summaryrefslogtreecommitdiff
path: root/src/pal
diff options
context:
space:
mode:
Diffstat (limited to 'src/pal')
-rw-r--r--src/pal/.gitmirrorall1
-rw-r--r--src/pal/CMakeLists.txt23
-rw-r--r--src/pal/automation/automation.py78
-rw-r--r--src/pal/automation/compile.py70
-rw-r--r--src/pal/automation/tests.py33
-rw-r--r--src/pal/automation/util.py97
-rw-r--r--src/pal/inc/mbusafecrt.h118
-rw-r--r--src/pal/inc/pal.h6956
-rw-r--r--src/pal/inc/pal_assert.h61
-rw-r--r--src/pal/inc/pal_char16.h57
-rw-r--r--src/pal/inc/pal_endian.h169
-rw-r--r--src/pal/inc/pal_error.h141
-rw-r--r--src/pal/inc/pal_mstypes.h732
-rw-r--r--src/pal/inc/pal_safecrt.h55
-rw-r--r--src/pal/inc/pal_unwind.h91
-rw-r--r--src/pal/inc/palprivate.h316
-rw-r--r--src/pal/inc/rt/accctrl.h13
-rw-r--r--src/pal/inc/rt/aclapi.h13
-rw-r--r--src/pal/inc/rt/assert.h13
-rw-r--r--src/pal/inc/rt/atl.h557
-rw-r--r--src/pal/inc/rt/atlcom.h13
-rw-r--r--src/pal/inc/rt/atlwin.h13
-rw-r--r--src/pal/inc/rt/commctrl.h13
-rw-r--r--src/pal/inc/rt/commdlg.h13
-rw-r--r--src/pal/inc/rt/common.ver33
-rw-r--r--src/pal/inc/rt/conio.h13
-rw-r--r--src/pal/inc/rt/cpp/ccombstr.h263
-rw-r--r--src/pal/inc/rt/cpp/cstdlib14
-rw-r--r--src/pal/inc/rt/cpp/cstring.h77
-rw-r--r--src/pal/inc/rt/cpp/ctype.h13
-rw-r--r--src/pal/inc/rt/cpp/fcntl.h13
-rw-r--r--src/pal/inc/rt/cpp/float.h13
-rw-r--r--src/pal/inc/rt/cpp/io.h13
-rw-r--r--src/pal/inc/rt/cpp/limits.h13
-rw-r--r--src/pal/inc/rt/cpp/malloc.h13
-rw-r--r--src/pal/inc/rt/cpp/math.h13
-rw-r--r--src/pal/inc/rt/cpp/memory.h13
-rw-r--r--src/pal/inc/rt/cpp/stdarg.h13
-rw-r--r--src/pal/inc/rt/cpp/stddef.h13
-rw-r--r--src/pal/inc/rt/cpp/stdint.h5
-rw-r--r--src/pal/inc/rt/cpp/stdio.h13
-rw-r--r--src/pal/inc/rt/cpp/stdlib.h13
-rw-r--r--src/pal/inc/rt/cpp/string.h13
-rw-r--r--src/pal/inc/rt/cpp/time.h13
-rw-r--r--src/pal/inc/rt/cpp/wchar.h13
-rw-r--r--src/pal/inc/rt/crtdbg.h13
-rw-r--r--src/pal/inc/rt/dbghelp.h37
-rw-r--r--src/pal/inc/rt/eh.h5
-rw-r--r--src/pal/inc/rt/emmintrin.h5
-rw-r--r--src/pal/inc/rt/errorrep.h5
-rw-r--r--src/pal/inc/rt/guiddef.h26
-rw-r--r--src/pal/inc/rt/hstring.h5
-rw-r--r--src/pal/inc/rt/htmlhelp.h13
-rw-r--r--src/pal/inc/rt/imagehlp.h64
-rw-r--r--src/pal/inc/rt/intrin.h5
-rw-r--r--src/pal/inc/rt/intsafe.h1616
-rw-r--r--src/pal/inc/rt/mbstring.h13
-rw-r--r--src/pal/inc/rt/new.h13
-rw-r--r--src/pal/inc/rt/no_sal2.h534
-rw-r--r--src/pal/inc/rt/ntimage.h1874
-rw-r--r--src/pal/inc/rt/oaidl.h111
-rw-r--r--src/pal/inc/rt/objbase.h9
-rw-r--r--src/pal/inc/rt/objidl.h293
-rw-r--r--src/pal/inc/rt/ocidl.h13
-rw-r--r--src/pal/inc/rt/ole2.h12
-rw-r--r--src/pal/inc/rt/oleauto.h161
-rw-r--r--src/pal/inc/rt/olectl.h13
-rw-r--r--src/pal/inc/rt/oleidl.h13
-rw-r--r--src/pal/inc/rt/palrt.h1805
-rw-r--r--src/pal/inc/rt/poppack.h39
-rw-r--r--src/pal/inc/rt/process.h13
-rw-r--r--src/pal/inc/rt/psapi.h5
-rw-r--r--src/pal/inc/rt/pshpack1.h38
-rw-r--r--src/pal/inc/rt/pshpack2.h37
-rw-r--r--src/pal/inc/rt/pshpack4.h38
-rw-r--r--src/pal/inc/rt/pshpack8.h38
-rw-r--r--src/pal/inc/rt/pshpck16.h38
-rw-r--r--src/pal/inc/rt/richedit.h13
-rw-r--r--src/pal/inc/rt/rpc.h34
-rw-r--r--src/pal/inc/rt/rpcndr.h20
-rw-r--r--src/pal/inc/rt/safecrt.h3381
-rw-r--r--src/pal/inc/rt/sal.h2957
-rw-r--r--src/pal/inc/rt/servprov.h32
-rw-r--r--src/pal/inc/rt/share.h5
-rw-r--r--src/pal/inc/rt/shellapi.h13
-rw-r--r--src/pal/inc/rt/shlobj.h13
-rw-r--r--src/pal/inc/rt/shlwapi.h13
-rw-r--r--src/pal/inc/rt/specstrings.h536
-rw-r--r--src/pal/inc/rt/specstrings_adt.h58
-rw-r--r--src/pal/inc/rt/specstrings_strict.h1190
-rw-r--r--src/pal/inc/rt/specstrings_undef.h464
-rw-r--r--src/pal/inc/rt/sscli_version.h33
-rw-r--r--src/pal/inc/rt/symcrypt.h13
-rw-r--r--src/pal/inc/rt/tchar.h5
-rw-r--r--src/pal/inc/rt/tlhelp32.h13
-rw-r--r--src/pal/inc/rt/unknwn.h66
-rw-r--r--src/pal/inc/rt/urlmon.h13
-rw-r--r--src/pal/inc/rt/verrsrc.h13
-rw-r--r--src/pal/inc/rt/vsassert.h98
-rw-r--r--src/pal/inc/rt/winapifamily.h40
-rw-r--r--src/pal/inc/rt/winbase.h13
-rw-r--r--src/pal/inc/rt/wincrypt.h13
-rw-r--r--src/pal/inc/rt/windef.h13
-rw-r--r--src/pal/inc/rt/windows.h13
-rw-r--r--src/pal/inc/rt/winerror.h13
-rw-r--r--src/pal/inc/rt/wininet.h13
-rw-r--r--src/pal/inc/rt/winnls.h13
-rw-r--r--src/pal/inc/rt/winnt.h13
-rw-r--r--src/pal/inc/rt/winresrc.h15
-rw-r--r--src/pal/inc/rt/winternl.h13
-rw-r--r--src/pal/inc/rt/winuser.h13
-rw-r--r--src/pal/inc/rt/winver.h30
-rw-r--r--src/pal/inc/rt/wtsapi32.h13
-rw-r--r--src/pal/inc/rt/xmmintrin.h5
-rw-r--r--src/pal/inc/strsafe.h6265
-rw-r--r--src/pal/inc/unixasmmacros.inc37
-rw-r--r--src/pal/inc/unixasmmacrosamd64.inc355
-rw-r--r--src/pal/inc/unixasmmacrosarm.inc268
-rw-r--r--src/pal/inc/unixasmmacrosarm64.inc318
-rw-r--r--src/pal/prebuilt/corerror/makecorerror.bat27
-rw-r--r--src/pal/prebuilt/corerror/mscorurt.rc1083
-rw-r--r--src/pal/prebuilt/corerror/readme.txt7
-rw-r--r--src/pal/prebuilt/idl/clrdata_i.c91
-rw-r--r--src/pal/prebuilt/idl/clrinternal_i.c79
-rw-r--r--src/pal/prebuilt/idl/clrprivappxhosting_i.c76
-rw-r--r--src/pal/prebuilt/idl/clrprivbinding_i.c100
-rw-r--r--src/pal/prebuilt/idl/clrprivhosting_i.c79
-rw-r--r--src/pal/prebuilt/idl/clrprivruntimebinders_i.c79
-rw-r--r--src/pal/prebuilt/idl/cordebug_i.c451
-rw-r--r--src/pal/prebuilt/idl/corprof_i.c134
-rw-r--r--src/pal/prebuilt/idl/corpub_i.c94
-rw-r--r--src/pal/prebuilt/idl/corsym_i.c175
-rw-r--r--src/pal/prebuilt/idl/fusionpriv_i.c121
-rw-r--r--src/pal/prebuilt/idl/gchost_i.c73
-rw-r--r--src/pal/prebuilt/idl/ivalidator_i.c76
-rw-r--r--src/pal/prebuilt/idl/ivehandler_i.c79
-rw-r--r--src/pal/prebuilt/idl/mscorsvc_i.c142
-rw-r--r--src/pal/prebuilt/idl/sospriv_i.c100
-rw-r--r--src/pal/prebuilt/idl/tlbimpexp_i.c82
-rw-r--r--src/pal/prebuilt/idl/xclrdata_i.c142
-rw-r--r--src/pal/prebuilt/idl/xcordebug_i.c75
-rw-r--r--src/pal/prebuilt/inc/CMakeLists.txt6
-rw-r--r--src/pal/prebuilt/inc/asm_version.h22
-rw-r--r--src/pal/prebuilt/inc/buildnumber.h34
-rw-r--r--src/pal/prebuilt/inc/clrdata.h1146
-rw-r--r--src/pal/prebuilt/inc/clrinternal.h847
-rw-r--r--src/pal/prebuilt/inc/clrprivbinding.h1124
-rw-r--r--src/pal/prebuilt/inc/clrprivhosting.h236
-rw-r--r--src/pal/prebuilt/inc/clrprivruntimebinders.h107
-rw-r--r--src/pal/prebuilt/inc/cordebug.h17660
-rw-r--r--src/pal/prebuilt/inc/corerror.h1250
-rw-r--r--src/pal/prebuilt/inc/corprof.h12049
-rw-r--r--src/pal/prebuilt/inc/corpub.h821
-rw-r--r--src/pal/prebuilt/inc/corsym.h5706
-rw-r--r--src/pal/prebuilt/inc/fusion.h407
-rw-r--r--src/pal/prebuilt/inc/fusionpriv.h2919
-rw-r--r--src/pal/prebuilt/inc/fxver.h203
-rw-r--r--src/pal/prebuilt/inc/fxver.rc106
-rw-r--r--src/pal/prebuilt/inc/fxverstrings.h17
-rw-r--r--src/pal/prebuilt/inc/gchost.h166
-rw-r--r--src/pal/prebuilt/inc/ivalidator.h334
-rw-r--r--src/pal/prebuilt/inc/ivehandler.h220
-rw-r--r--src/pal/prebuilt/inc/metahost.h1767
-rw-r--r--src/pal/prebuilt/inc/mscoree.h2929
-rw-r--r--src/pal/prebuilt/inc/mscorsvc.h2824
-rw-r--r--src/pal/prebuilt/inc/ndpversion.h4
-rw-r--r--src/pal/prebuilt/inc/ndpversion_generated.h15
-rw-r--r--src/pal/prebuilt/inc/product_version.h113
-rw-r--r--src/pal/prebuilt/inc/readme.txt1
-rw-r--r--src/pal/prebuilt/inc/sospriv.h2199
-rw-r--r--src/pal/prebuilt/inc/version.h17
-rw-r--r--src/pal/prebuilt/inc/xclrdata.h7730
-rw-r--r--src/pal/prebuilt/inc/xcordebug.h259
-rw-r--r--src/pal/src/.tpattributes1
-rw-r--r--src/pal/src/CMakeLists.txt311
-rw-r--r--src/pal/src/arch/arm/asmconstants.h61
-rw-r--r--src/pal/src/arch/arm/context2.S174
-rw-r--r--src/pal/src/arch/arm/debugbreak.S14
-rw-r--r--src/pal/src/arch/arm/exceptionhelper.S30
-rw-r--r--src/pal/src/arch/arm/processor.cpp42
-rw-r--r--src/pal/src/arch/arm64/context2.S300
-rw-r--r--src/pal/src/arch/arm64/debugbreak.S11
-rw-r--r--src/pal/src/arch/arm64/exceptionhelper.S9
-rw-r--r--src/pal/src/arch/arm64/processor.cpp41
-rw-r--r--src/pal/src/arch/i386/activationhandlerwrapper.S30
-rw-r--r--src/pal/src/arch/i386/asmconstants.h106
-rw-r--r--src/pal/src/arch/i386/context.S21
-rw-r--r--src/pal/src/arch/i386/context2.S259
-rw-r--r--src/pal/src/arch/i386/debugbreak.S12
-rw-r--r--src/pal/src/arch/i386/dispatchexceptionwrapper.S51
-rw-r--r--src/pal/src/arch/i386/exceptionhelper.S42
-rw-r--r--src/pal/src/arch/i386/optimizedtls.cpp237
-rw-r--r--src/pal/src/arch/i386/processor.cpp44
-rw-r--r--src/pal/src/build_tools/mdtool_dummy7
-rw-r--r--src/pal/src/build_tools/mdtool_gcc.in43
-rw-r--r--src/pal/src/config.h.in155
-rw-r--r--src/pal/src/configure.cmake1281
-rw-r--r--src/pal/src/cruntime/file.cpp954
-rw-r--r--src/pal/src/cruntime/filecrt.cpp571
-rw-r--r--src/pal/src/cruntime/lstr.cpp316
-rw-r--r--src/pal/src/cruntime/malloc.cpp116
-rw-r--r--src/pal/src/cruntime/math.cpp424
-rw-r--r--src/pal/src/cruntime/mbstring.cpp257
-rw-r--r--src/pal/src/cruntime/misc.cpp314
-rw-r--r--src/pal/src/cruntime/misctls.cpp399
-rw-r--r--src/pal/src/cruntime/path.cpp596
-rw-r--r--src/pal/src/cruntime/printf.cpp1758
-rw-r--r--src/pal/src/cruntime/printfcpp.cpp2556
-rw-r--r--src/pal/src/cruntime/silent_printf.cpp990
-rw-r--r--src/pal/src/cruntime/string.cpp348
-rw-r--r--src/pal/src/cruntime/stringtls.cpp78
-rw-r--r--src/pal/src/cruntime/thread.cpp52
-rw-r--r--src/pal/src/cruntime/wchar.cpp1885
-rw-r--r--src/pal/src/cruntime/wchartls.cpp127
-rw-r--r--src/pal/src/debug/debug.cpp1844
-rw-r--r--src/pal/src/examples/CMakeLists.txt18
-rw-r--r--src/pal/src/examples/example1.c49
-rw-r--r--src/pal/src/exception/machexception.cpp1612
-rw-r--r--src/pal/src/exception/machexception.h48
-rw-r--r--src/pal/src/exception/machmessage.cpp1383
-rw-r--r--src/pal/src/exception/machmessage.h441
-rw-r--r--src/pal/src/exception/seh-unwind.cpp737
-rw-r--r--src/pal/src/exception/seh.cpp431
-rw-r--r--src/pal/src/exception/signal.cpp705
-rw-r--r--src/pal/src/exception/signal.hpp59
-rw-r--r--src/pal/src/file/directory.cpp725
-rw-r--r--src/pal/src/file/disk.cpp180
-rw-r--r--src/pal/src/file/file.cpp4900
-rw-r--r--src/pal/src/file/filetime.cpp788
-rw-r--r--src/pal/src/file/find.cpp999
-rw-r--r--src/pal/src/file/path.cpp1624
-rw-r--r--src/pal/src/file/shmfilelockmgr.cpp1032
-rw-r--r--src/pal/src/file/shmfilelockmgr.hpp185
-rw-r--r--src/pal/src/handlemgr/handleapi.cpp338
-rw-r--r--src/pal/src/handlemgr/handlemgr.cpp327
-rw-r--r--src/pal/src/include/pal/cert.hpp33
-rw-r--r--src/pal/src/include/pal/context.h641
-rw-r--r--src/pal/src/include/pal/corunix.hpp1359
-rw-r--r--src/pal/src/include/pal/corunix.inl55
-rw-r--r--src/pal/src/include/pal/critsect.h45
-rw-r--r--src/pal/src/include/pal/cruntime.h247
-rw-r--r--src/pal/src/include/pal/cs.hpp54
-rw-r--r--src/pal/src/include/pal/dbgmsg.h628
-rw-r--r--src/pal/src/include/pal/debug.h86
-rw-r--r--src/pal/src/include/pal/dtraceprotocol.h39
-rw-r--r--src/pal/src/include/pal/environ.h78
-rw-r--r--src/pal/src/include/pal/event.hpp69
-rw-r--r--src/pal/src/include/pal/fakepoll.h68
-rw-r--r--src/pal/src/include/pal/file.h304
-rw-r--r--src/pal/src/include/pal/file.hpp365
-rw-r--r--src/pal/src/include/pal/filetime.h80
-rw-r--r--src/pal/src/include/pal/handleapi.hpp48
-rw-r--r--src/pal/src/include/pal/handlemgr.hpp180
-rw-r--r--src/pal/src/include/pal/identity.hpp57
-rw-r--r--src/pal/src/include/pal/init.h111
-rw-r--r--src/pal/src/include/pal/list.h141
-rw-r--r--src/pal/src/include/pal/locale.h75
-rw-r--r--src/pal/src/include/pal/malloc.hpp152
-rw-r--r--src/pal/src/include/pal/map.h52
-rw-r--r--src/pal/src/include/pal/map.hpp209
-rw-r--r--src/pal/src/include/pal/misc.h83
-rw-r--r--src/pal/src/include/pal/module.h203
-rw-r--r--src/pal/src/include/pal/modulename.h39
-rw-r--r--src/pal/src/include/pal/mutex.hpp191
-rw-r--r--src/pal/src/include/pal/palinternal.h696
-rw-r--r--src/pal/src/include/pal/perftrace.h70
-rw-r--r--src/pal/src/include/pal/printfcpp.hpp133
-rw-r--r--src/pal/src/include/pal/process.h162
-rw-r--r--src/pal/src/include/pal/procobj.hpp125
-rw-r--r--src/pal/src/include/pal/seh.hpp185
-rw-r--r--src/pal/src/include/pal/semaphore.hpp74
-rw-r--r--src/pal/src/include/pal/sharedmemory.h268
-rw-r--r--src/pal/src/include/pal/sharedmemory.inl53
-rw-r--r--src/pal/src/include/pal/shm.hpp83
-rw-r--r--src/pal/src/include/pal/shmemory.h331
-rw-r--r--src/pal/src/include/pal/stackstring.hpp239
-rw-r--r--src/pal/src/include/pal/synchcache.hpp397
-rw-r--r--src/pal/src/include/pal/synchobjects.hpp216
-rw-r--r--src/pal/src/include/pal/thread.hpp838
-rw-r--r--src/pal/src/include/pal/threadinfo.hpp89
-rw-r--r--src/pal/src/include/pal/threadsusp.hpp382
-rw-r--r--src/pal/src/include/pal/tls.hpp65
-rw-r--r--src/pal/src/include/pal/unicode_data.h69
-rw-r--r--src/pal/src/include/pal/utf8.h53
-rw-r--r--src/pal/src/include/pal/utils.h157
-rw-r--r--src/pal/src/include/pal/virtual.h208
-rw-r--r--src/pal/src/init/pal.cpp1480
-rw-r--r--src/pal/src/init/sxs.cpp322
-rw-r--r--src/pal/src/loader/module.cpp1771
-rw-r--r--src/pal/src/loader/modulename.cpp207
-rw-r--r--src/pal/src/locale/UnicodeData.txt12860
-rw-r--r--src/pal/src/locale/unicode.cpp1026
-rw-r--r--src/pal/src/locale/unicode_data.cpp1852
-rw-r--r--src/pal/src/locale/utf8.cpp2904
-rw-r--r--src/pal/src/map/common.cpp66
-rw-r--r--src/pal/src/map/common.h43
-rw-r--r--src/pal/src/map/map.cpp2749
-rw-r--r--src/pal/src/map/virtual.cpp2064
-rw-r--r--src/pal/src/memory/heap.cpp389
-rw-r--r--src/pal/src/memory/local.cpp141
-rw-r--r--src/pal/src/misc/dbgmsg.cpp968
-rw-r--r--src/pal/src/misc/environ.cpp1096
-rw-r--r--src/pal/src/misc/error.cpp126
-rw-r--r--src/pal/src/misc/errorstrings.cpp172
-rw-r--r--src/pal/src/misc/errorstrings.h10
-rw-r--r--src/pal/src/misc/eventlog.cpp423
-rw-r--r--src/pal/src/misc/fmtmessage.cpp701
-rw-r--r--src/pal/src/misc/identity.cpp410
-rw-r--r--src/pal/src/misc/miscpalapi.cpp381
-rw-r--r--src/pal/src/misc/msgbox.cpp416
-rw-r--r--src/pal/src/misc/perftrace.cpp1522
-rw-r--r--src/pal/src/misc/strutil.cpp96
-rw-r--r--src/pal/src/misc/sysinfo.cpp363
-rw-r--r--src/pal/src/misc/time.cpp396
-rw-r--r--src/pal/src/misc/tracepointprovider.cpp109
-rw-r--r--src/pal/src/misc/utils.cpp320
-rw-r--r--src/pal/src/misc/version.cpp119
-rw-r--r--src/pal/src/objmgr/palobjbase.cpp359
-rw-r--r--src/pal/src/objmgr/palobjbase.hpp191
-rw-r--r--src/pal/src/objmgr/shmobject.cpp1471
-rw-r--r--src/pal/src/objmgr/shmobject.hpp391
-rw-r--r--src/pal/src/objmgr/shmobjectmanager.cpp1567
-rw-r--r--src/pal/src/objmgr/shmobjectmanager.hpp167
-rw-r--r--src/pal/src/poll/fakepoll.cpp133
-rw-r--r--src/pal/src/safecrt/cruntime.h98
-rw-r--r--src/pal/src/safecrt/input.inl1314
-rw-r--r--src/pal/src/safecrt/internal.h1097
-rw-r--r--src/pal/src/safecrt/internal_securecrt.h292
-rw-r--r--src/pal/src/safecrt/makepath_s.c31
-rw-r--r--src/pal/src/safecrt/mbusafecrt.c254
-rw-r--r--src/pal/src/safecrt/mbusafecrt_internal.h88
-rw-r--r--src/pal/src/safecrt/memcpy_s.c82
-rw-r--r--src/pal/src/safecrt/memmove_s.c69
-rw-r--r--src/pal/src/safecrt/output.inl1624
-rw-r--r--src/pal/src/safecrt/safecrt_input_s.c46
-rw-r--r--src/pal/src/safecrt/safecrt_output_l.c1467
-rw-r--r--src/pal/src/safecrt/safecrt_output_s.c46
-rw-r--r--src/pal/src/safecrt/safecrt_winput_s.c55
-rw-r--r--src/pal/src/safecrt/safecrt_woutput_s.c59
-rw-r--r--src/pal/src/safecrt/snprintf.c18
-rw-r--r--src/pal/src/safecrt/splitpath_s.c31
-rw-r--r--src/pal/src/safecrt/sprintf.c98
-rw-r--r--src/pal/src/safecrt/sscanf.c249
-rw-r--r--src/pal/src/safecrt/strcat_s.c33
-rw-r--r--src/pal/src/safecrt/strcpy_s.c29
-rw-r--r--src/pal/src/safecrt/strlen_s.c58
-rw-r--r--src/pal/src/safecrt/strncat_s.c31
-rw-r--r--src/pal/src/safecrt/strncpy_s.c30
-rw-r--r--src/pal/src/safecrt/strtok_s.c27
-rw-r--r--src/pal/src/safecrt/swprintf.c120
-rw-r--r--src/pal/src/safecrt/tcscat_s.inl51
-rw-r--r--src/pal/src/safecrt/tcscpy_s.inl39
-rw-r--r--src/pal/src/safecrt/tcsncat_s.inl81
-rw-r--r--src/pal/src/safecrt/tcsncpy_s.inl71
-rw-r--r--src/pal/src/safecrt/tcstok_s.inl71
-rw-r--r--src/pal/src/safecrt/tmakepath_s.inl116
-rw-r--r--src/pal/src/safecrt/tsplitpath_s.inl280
-rw-r--r--src/pal/src/safecrt/vsprintf.c268
-rw-r--r--src/pal/src/safecrt/vswprint.c282
-rw-r--r--src/pal/src/safecrt/wcscat_s.c36
-rw-r--r--src/pal/src/safecrt/wcscpy_s.c33
-rw-r--r--src/pal/src/safecrt/wcslen_s.c58
-rw-r--r--src/pal/src/safecrt/wcsncat_s.c35
-rw-r--r--src/pal/src/safecrt/wcsncpy_s.c34
-rw-r--r--src/pal/src/safecrt/wcstok_s.c27
-rw-r--r--src/pal/src/safecrt/wmakepath_s.c30
-rw-r--r--src/pal/src/safecrt/wsplitpath_s.c30
-rw-r--r--src/pal/src/safecrt/xtoa_s.c29
-rw-r--r--src/pal/src/safecrt/xtow_s.c28
-rw-r--r--src/pal/src/safecrt/xtox_s.inl450
-rw-r--r--src/pal/src/sharedmemory/sharedmemory.cpp1136
-rw-r--r--src/pal/src/shmemory/shmemory.cpp1734
-rw-r--r--src/pal/src/sync/cs.cpp1603
-rw-r--r--src/pal/src/synchmgr/synchcontrollers.cpp1976
-rw-r--r--src/pal/src/synchmgr/synchmanager.cpp4556
-rw-r--r--src/pal/src/synchmgr/synchmanager.hpp1022
-rw-r--r--src/pal/src/synchmgr/wait.cpp711
-rw-r--r--src/pal/src/synchobj/event.cpp589
-rw-r--r--src/pal/src/synchobj/mutex.cpp1584
-rw-r--r--src/pal/src/synchobj/semaphore.cpp680
-rw-r--r--src/pal/src/thread/context.cpp1360
-rw-r--r--src/pal/src/thread/process.cpp4615
-rw-r--r--src/pal/src/thread/procprivate.hpp78
-rw-r--r--src/pal/src/thread/thread.cpp2871
-rw-r--r--src/pal/src/thread/threadsusp.cpp1046
-rw-r--r--src/pal/src/thread/tls.cpp226
-rw-r--r--src/pal/tests/CMakeLists.txt32
-rw-r--r--src/pal/tests/palsuite/CMakeLists.txt24
-rw-r--r--src/pal/tests/palsuite/DisabledTests.txt123
-rw-r--r--src/pal/tests/palsuite/README.txt140
-rw-r--r--src/pal/tests/palsuite/c_runtime/CMakeLists.txt162
-rw-r--r--src/pal/tests/palsuite/c_runtime/__iscsym/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/__iscsym/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/__iscsym/test1/__iscsym.c93
-rw-r--r--src/pal/tests/palsuite/c_runtime/__iscsym/test1/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/_alloca/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/_alloca/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_alloca/test1/test1.c62
-rw-r--r--src/pal/tests/palsuite/c_runtime/_alloca/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/c_runtime/_ecvt/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/_ecvt/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_ecvt/test1/test1.c135
-rw-r--r--src/pal/tests/palsuite/c_runtime/_ecvt/test1/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/_fdopen/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/_fdopen/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_fdopen/test1/test1.c112
-rw-r--r--src/pal/tests/palsuite/c_runtime/_fdopen/test1/testinfo.dat23
-rw-r--r--src/pal/tests/palsuite/c_runtime/_finite/CMakeLists.txt3
-rw-r--r--src/pal/tests/palsuite/c_runtime/_finite/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_finite/test1/test1.c119
-rw-r--r--src/pal/tests/palsuite/c_runtime/_finite/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/c_runtime/_fullpath/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/_fullpath/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_fullpath/test1/test1.c181
-rw-r--r--src/pal/tests/palsuite/c_runtime/_fullpath/test1/testinfo.dat23
-rw-r--r--src/pal/tests/palsuite/c_runtime/_gcvt/CMakeLists.txt5
-rw-r--r--src/pal/tests/palsuite/c_runtime/_gcvt/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_gcvt/test1/_gcvt.c58
-rw-r--r--src/pal/tests/palsuite/c_runtime/_gcvt/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/c_runtime/_gcvt/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_gcvt/test2/test2.c83
-rw-r--r--src/pal/tests/palsuite/c_runtime/_gcvt/test2/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/c_runtime/_getw/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/_getw/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_getw/test1/test.datbin0 -> 28 bytes
-rw-r--r--src/pal/tests/palsuite/c_runtime/_getw/test1/test1.c96
-rw-r--r--src/pal/tests/palsuite/c_runtime/_getw/test1/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/c_runtime/_isnan/CMakeLists.txt3
-rw-r--r--src/pal/tests/palsuite/c_runtime/_isnan/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_isnan/test1/test1.c115
-rw-r--r--src/pal/tests/palsuite/c_runtime/_isnan/test1/testinfo.dat16
-rw-r--r--src/pal/tests/palsuite/c_runtime/_itow/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/_itow/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_itow/test1/test1.c102
-rw-r--r--src/pal/tests/palsuite/c_runtime/_itow/test1/testinfo.dat18
-rw-r--r--src/pal/tests/palsuite/c_runtime/_makepath/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/_makepath/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_makepath/test1/test1.c65
-rw-r--r--src/pal/tests/palsuite/c_runtime/_makepath/test1/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/_mbsdec/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/_mbsdec/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_mbsdec/test1/test1.c77
-rw-r--r--src/pal/tests/palsuite/c_runtime/_mbsdec/test1/testinfo.dat18
-rw-r--r--src/pal/tests/palsuite/c_runtime/_mbsinc/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/_mbsinc/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_mbsinc/test1/test1.c62
-rw-r--r--src/pal/tests/palsuite/c_runtime/_mbsinc/test1/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/c_runtime/_mbslen/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/_mbslen/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_mbslen/test1/test1.c66
-rw-r--r--src/pal/tests/palsuite/c_runtime/_mbslen/test1/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/c_runtime/_mbsninc/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/_mbsninc/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_mbsninc/test1/test1.c65
-rw-r--r--src/pal/tests/palsuite/c_runtime/_mbsninc/test1/testinfo.dat17
-rw-r--r--src/pal/tests/palsuite/c_runtime/_open_osfhandle/CMakeLists.txt5
-rw-r--r--src/pal/tests/palsuite/c_runtime/_open_osfhandle/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_open_osfhandle/test1/test1.c132
-rw-r--r--src/pal/tests/palsuite/c_runtime/_open_osfhandle/test1/testinfo.dat17
-rw-r--r--src/pal/tests/palsuite/c_runtime/_open_osfhandle/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_open_osfhandle/test2/test2.c86
-rw-r--r--src/pal/tests/palsuite/c_runtime/_open_osfhandle/test2/testinfo.dat16
-rw-r--r--src/pal/tests/palsuite/c_runtime/_putenv/CMakeLists.txt7
-rw-r--r--src/pal/tests/palsuite/c_runtime/_putenv/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_putenv/test1/test1.c99
-rw-r--r--src/pal/tests/palsuite/c_runtime/_putenv/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/c_runtime/_putenv/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_putenv/test2/test2.c76
-rw-r--r--src/pal/tests/palsuite/c_runtime/_putenv/test2/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/c_runtime/_putenv/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_putenv/test3/test3.c102
-rw-r--r--src/pal/tests/palsuite/c_runtime/_putenv/test3/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/_putenv/test4/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_putenv/test4/test4.c75
-rw-r--r--src/pal/tests/palsuite/c_runtime/_putenv/test4/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/_putw/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/_putw/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_putw/test1/test1.c112
-rw-r--r--src/pal/tests/palsuite/c_runtime/_putw/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/c_runtime/_rotl/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/_rotl/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_rotl/test1/test1.cpp55
-rw-r--r--src/pal/tests/palsuite/c_runtime/_rotl/test1/testinfo.dat17
-rw-r--r--src/pal/tests/palsuite/c_runtime/_rotr/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/_rotr/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_rotr/test1/test1.cpp60
-rw-r--r--src/pal/tests/palsuite/c_runtime/_rotr/test1/testinfo.dat17
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snprintf/CMakeLists.txt22
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snprintf/_snprintf.h194
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snprintf/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snprintf/test1/test1.c58
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snprintf/test1/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snprintf/test10/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snprintf/test10/test10.c55
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snprintf/test10/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snprintf/test11/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snprintf/test11/test11.c54
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snprintf/test11/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snprintf/test12/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snprintf/test12/test12.c55
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snprintf/test12/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snprintf/test13/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snprintf/test13/test13.c55
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snprintf/test13/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snprintf/test14/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snprintf/test14/test14.c57
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snprintf/test14/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snprintf/test15/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snprintf/test15/test15.c56
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snprintf/test15/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snprintf/test16/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snprintf/test16/test16.c52
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snprintf/test16/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snprintf/test17/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snprintf/test17/test17.c53
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snprintf/test17/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snprintf/test18/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snprintf/test18/test18.c53
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snprintf/test18/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snprintf/test19/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snprintf/test19/test19.c76
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snprintf/test19/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snprintf/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snprintf/test2/test2.c44
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snprintf/test2/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snprintf/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snprintf/test3/test3.c45
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snprintf/test3/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snprintf/test4/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snprintf/test4/test4.c69
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snprintf/test4/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snprintf/test5/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snprintf/test5/test5.c61
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snprintf/test5/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snprintf/test6/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snprintf/test6/test6.c47
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snprintf/test6/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snprintf/test7/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snprintf/test7/test7.c47
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snprintf/test7/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snprintf/test8/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snprintf/test8/test8.c56
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snprintf/test8/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snprintf/test9/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snprintf/test9/test9.c55
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snprintf/test9/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snwprintf/CMakeLists.txt22
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snwprintf/_snwprintf.h199
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snwprintf/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snwprintf/test1/test1.c62
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snwprintf/test1/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snwprintf/test10/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snwprintf/test10/test10.c54
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snwprintf/test10/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snwprintf/test11/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snwprintf/test11/test11.c54
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snwprintf/test11/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snwprintf/test12/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snwprintf/test12/test12.c54
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snwprintf/test12/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snwprintf/test13/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snwprintf/test13/test13.c54
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snwprintf/test13/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snwprintf/test14/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snwprintf/test14/test14.c66
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snwprintf/test14/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snwprintf/test15/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snwprintf/test15/test15.c67
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snwprintf/test15/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snwprintf/test16/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snwprintf/test16/test16.c65
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snwprintf/test16/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snwprintf/test17/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snwprintf/test17/test17.c68
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snwprintf/test17/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snwprintf/test18/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snwprintf/test18/test18.c69
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snwprintf/test18/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snwprintf/test19/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snwprintf/test19/test19.c90
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snwprintf/test19/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snwprintf/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snwprintf/test2/test2.c44
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snwprintf/test2/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snwprintf/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snwprintf/test3/test3.c44
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snwprintf/test3/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snwprintf/test4/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snwprintf/test4/test4.c71
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snwprintf/test4/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snwprintf/test5/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snwprintf/test5/test5.c63
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snwprintf/test5/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snwprintf/test6/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snwprintf/test6/test6.c46
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snwprintf/test6/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snwprintf/test7/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snwprintf/test7/test7.c46
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snwprintf/test7/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snwprintf/test8/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snwprintf/test8/test8.c53
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snwprintf/test8/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snwprintf/test9/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snwprintf/test9/test9.c53
-rw-r--r--src/pal/tests/palsuite/c_runtime/_snwprintf/test9/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/_splitpath/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/_splitpath/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_splitpath/test1/test1.c108
-rw-r--r--src/pal/tests/palsuite/c_runtime/_splitpath/test1/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/c_runtime/_stricmp/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/_stricmp/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_stricmp/test1/test1.c70
-rw-r--r--src/pal/tests/palsuite/c_runtime/_stricmp/test1/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/c_runtime/_strlwr/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/_strlwr/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_strlwr/test1/test1.c42
-rw-r--r--src/pal/tests/palsuite/c_runtime/_strlwr/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/c_runtime/_strnicmp/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/_strnicmp/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_strnicmp/test1/test1.c85
-rw-r--r--src/pal/tests/palsuite/c_runtime/_strnicmp/test1/testinfo.dat18
-rw-r--r--src/pal/tests/palsuite/c_runtime/_swab/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/_swab/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_swab/test1/test1.c45
-rw-r--r--src/pal/tests/palsuite/c_runtime/_swab/test1/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnprintf/CMakeLists.txt22
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnprintf/_vsnprintf.h124
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnprintf/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnprintf/test1/test1.c55
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnprintf/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnprintf/test10/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnprintf/test10/test10.c50
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnprintf/test10/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnprintf/test11/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnprintf/test11/test11.c50
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnprintf/test11/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnprintf/test12/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnprintf/test12/test12.c52
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnprintf/test12/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnprintf/test13/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnprintf/test13/test13.c52
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnprintf/test13/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnprintf/test14/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnprintf/test14/test14.c50
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnprintf/test14/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnprintf/test15/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnprintf/test15/test15.c49
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnprintf/test15/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnprintf/test16/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnprintf/test16/test16.c49
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnprintf/test16/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnprintf/test17/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnprintf/test17/test17.c50
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnprintf/test17/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnprintf/test18/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnprintf/test18/test18.c50
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnprintf/test18/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnprintf/test19/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnprintf/test19/test19.c103
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnprintf/test19/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnprintf/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnprintf/test2/test2.c44
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnprintf/test2/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnprintf/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnprintf/test3/test3.c43
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnprintf/test3/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnprintf/test4/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnprintf/test4/test4.c98
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnprintf/test4/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnprintf/test5/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnprintf/test5/test5.c78
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnprintf/test5/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnprintf/test6/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnprintf/test6/test6.c44
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnprintf/test6/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnprintf/test7/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnprintf/test7/test7.c44
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnprintf/test7/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnprintf/test8/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnprintf/test8/test8.c52
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnprintf/test8/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnprintf/test9/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnprintf/test9/test9.c51
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnprintf/test9/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnwprintf/CMakeLists.txt22
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnwprintf/_vsnwprintf.h133
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnwprintf/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnwprintf/test1/test1.c60
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnwprintf/test1/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnwprintf/test10/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnwprintf/test10/test10.c50
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnwprintf/test10/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnwprintf/test11/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnwprintf/test11/test11.c50
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnwprintf/test11/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnwprintf/test12/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnwprintf/test12/test12.c50
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnwprintf/test12/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnwprintf/test13/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnwprintf/test13/test13.c50
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnwprintf/test13/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnwprintf/test14/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnwprintf/test14/test14.c63
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnwprintf/test14/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnwprintf/test15/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnwprintf/test15/test15.c64
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnwprintf/test15/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnwprintf/test16/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnwprintf/test16/test16.c63
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnwprintf/test16/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnwprintf/test17/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnwprintf/test17/test17.c65
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnwprintf/test17/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnwprintf/test18/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnwprintf/test18/test18.c65
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnwprintf/test18/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnwprintf/test19/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnwprintf/test19/test19.c139
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnwprintf/test19/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnwprintf/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnwprintf/test2/test2.c40
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnwprintf/test2/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnwprintf/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnwprintf/test3/test3.c40
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnwprintf/test3/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnwprintf/test4/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnwprintf/test4/test4.c121
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnwprintf/test4/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnwprintf/test5/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnwprintf/test5/test5.c81
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnwprintf/test5/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnwprintf/test6/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnwprintf/test6/test6.c43
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnwprintf/test6/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnwprintf/test7/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnwprintf/test7/test7.c43
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnwprintf/test7/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnwprintf/test8/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnwprintf/test8/test8.c49
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnwprintf/test8/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnwprintf/test9/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnwprintf/test9/test9.c49
-rw-r--r--src/pal/tests/palsuite/c_runtime/_vsnwprintf/test9/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/_wcsicmp/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/_wcsicmp/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_wcsicmp/test1/test1.c68
-rw-r--r--src/pal/tests/palsuite/c_runtime/_wcsicmp/test1/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/_wcslwr/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/_wcslwr/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_wcslwr/test1/test1.c50
-rw-r--r--src/pal/tests/palsuite/c_runtime/_wcslwr/test1/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/_wcsnicmp/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/_wcsnicmp/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_wcsnicmp/test1/test1.c95
-rw-r--r--src/pal/tests/palsuite/c_runtime/_wcsnicmp/test1/testinfo.dat18
-rw-r--r--src/pal/tests/palsuite/c_runtime/_wfopen/CMakeLists.txt10
-rw-r--r--src/pal/tests/palsuite/c_runtime/_wfopen/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_wfopen/test1/test1.c79
-rw-r--r--src/pal/tests/palsuite/c_runtime/_wfopen/test1/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/c_runtime/_wfopen/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_wfopen/test2/test2.c68
-rw-r--r--src/pal/tests/palsuite/c_runtime/_wfopen/test2/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/c_runtime/_wfopen/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_wfopen/test3/test3.c70
-rw-r--r--src/pal/tests/palsuite/c_runtime/_wfopen/test3/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/c_runtime/_wfopen/test4/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_wfopen/test4/test4.c87
-rw-r--r--src/pal/tests/palsuite/c_runtime/_wfopen/test4/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/c_runtime/_wfopen/test5/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_wfopen/test5/test5.c82
-rw-r--r--src/pal/tests/palsuite/c_runtime/_wfopen/test5/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/c_runtime/_wfopen/test6/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_wfopen/test6/test6.c152
-rw-r--r--src/pal/tests/palsuite/c_runtime/_wfopen/test6/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/c_runtime/_wfopen/test7/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_wfopen/test7/test7.c119
-rw-r--r--src/pal/tests/palsuite/c_runtime/_wfopen/test7/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/c_runtime/_wmakepath/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/_wmakepath/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_wmakepath/test1/test1.c76
-rw-r--r--src/pal/tests/palsuite/c_runtime/_wmakepath/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/c_runtime/_wsplitpath/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/_wsplitpath/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_wsplitpath/test1/test1.c151
-rw-r--r--src/pal/tests/palsuite/c_runtime/_wsplitpath/test1/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/c_runtime/_wtoi/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/_wtoi/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/_wtoi/test1/test1.c79
-rw-r--r--src/pal/tests/palsuite/c_runtime/_wtoi/test1/testinfo.dat17
-rw-r--r--src/pal/tests/palsuite/c_runtime/abs/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/abs/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/abs/test1/abs.c54
-rw-r--r--src/pal/tests/palsuite/c_runtime/abs/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/c_runtime/acos/CMakeLists.txt3
-rw-r--r--src/pal/tests/palsuite/c_runtime/acos/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/acos/test1/test1.c130
-rw-r--r--src/pal/tests/palsuite/c_runtime/acos/test1/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/asin/CMakeLists.txt3
-rw-r--r--src/pal/tests/palsuite/c_runtime/asin/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/asin/test1/test1.c146
-rw-r--r--src/pal/tests/palsuite/c_runtime/asin/test1/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/atan/CMakeLists.txt3
-rw-r--r--src/pal/tests/palsuite/c_runtime/atan/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/atan/test1/test1.c128
-rw-r--r--src/pal/tests/palsuite/c_runtime/atan/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/c_runtime/atan2/CMakeLists.txt3
-rw-r--r--src/pal/tests/palsuite/c_runtime/atan2/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/atan2/test1/test1.c148
-rw-r--r--src/pal/tests/palsuite/c_runtime/atan2/test1/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/atof/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/atof/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/atof/test1/test1.c75
-rw-r--r--src/pal/tests/palsuite/c_runtime/atof/test1/testinfo.dat16
-rw-r--r--src/pal/tests/palsuite/c_runtime/atoi/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/atoi/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/atoi/test1/test1.c86
-rw-r--r--src/pal/tests/palsuite/c_runtime/atoi/test1/testinfo.dat17
-rw-r--r--src/pal/tests/palsuite/c_runtime/atol/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/atol/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/atol/test1/test1.c88
-rw-r--r--src/pal/tests/palsuite/c_runtime/atol/test1/testinfo.dat17
-rw-r--r--src/pal/tests/palsuite/c_runtime/bsearch/CMakeLists.txt5
-rw-r--r--src/pal/tests/palsuite/c_runtime/bsearch/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/bsearch/test1/test1.c48
-rw-r--r--src/pal/tests/palsuite/c_runtime/bsearch/test1/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/bsearch/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/bsearch/test2/test2.c57
-rw-r--r--src/pal/tests/palsuite/c_runtime/bsearch/test2/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/ceil/CMakeLists.txt3
-rw-r--r--src/pal/tests/palsuite/c_runtime/ceil/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/ceil/test1/test1.c132
-rw-r--r--src/pal/tests/palsuite/c_runtime/ceil/test1/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/cos/CMakeLists.txt3
-rw-r--r--src/pal/tests/palsuite/c_runtime/cos/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/cos/test1/test1.c131
-rw-r--r--src/pal/tests/palsuite/c_runtime/cos/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/c_runtime/cosh/CMakeLists.txt3
-rw-r--r--src/pal/tests/palsuite/c_runtime/cosh/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/cosh/test1/test1.c130
-rw-r--r--src/pal/tests/palsuite/c_runtime/cosh/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/c_runtime/ctime/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/ctime/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/ctime/test1/test1.c154
-rw-r--r--src/pal/tests/palsuite/c_runtime/ctime/test1/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/c_runtime/errno/CMakeLists.txt5
-rw-r--r--src/pal/tests/palsuite/c_runtime/errno/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/errno/test1/test1.c43
-rw-r--r--src/pal/tests/palsuite/c_runtime/errno/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/c_runtime/errno/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/errno/test2/test2.c76
-rw-r--r--src/pal/tests/palsuite/c_runtime/errno/test2/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/exit/CMakeLists.txt5
-rw-r--r--src/pal/tests/palsuite/c_runtime/exit/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/exit/test1/test1.c37
-rw-r--r--src/pal/tests/palsuite/c_runtime/exit/test1/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/exit/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/exit/test2/test2.c38
-rw-r--r--src/pal/tests/palsuite/c_runtime/exit/test2/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/c_runtime/exp/CMakeLists.txt3
-rw-r--r--src/pal/tests/palsuite/c_runtime/exp/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/exp/test1/test1.c138
-rw-r--r--src/pal/tests/palsuite/c_runtime/exp/test1/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/fabs/CMakeLists.txt3
-rw-r--r--src/pal/tests/palsuite/c_runtime/fabs/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/fabs/test1/test1.c130
-rw-r--r--src/pal/tests/palsuite/c_runtime/fabs/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/c_runtime/fabsf/CMakeLists.txt3
-rw-r--r--src/pal/tests/palsuite/c_runtime/fabsf/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/fabsf/test1/test1.c130
-rw-r--r--src/pal/tests/palsuite/c_runtime/fabsf/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/c_runtime/fclose/CMakeLists.txt5
-rw-r--r--src/pal/tests/palsuite/c_runtime/fclose/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/fclose/test1/test1.c79
-rw-r--r--src/pal/tests/palsuite/c_runtime/fclose/test1/testinfo.dat18
-rw-r--r--src/pal/tests/palsuite/c_runtime/fclose/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/fclose/test2/test2.c77
-rw-r--r--src/pal/tests/palsuite/c_runtime/fclose/test2/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/c_runtime/feof/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/feof/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/feof/test1/test1.c88
-rw-r--r--src/pal/tests/palsuite/c_runtime/feof/test1/testfile1
-rw-r--r--src/pal/tests/palsuite/c_runtime/feof/test1/testinfo.dat16
-rw-r--r--src/pal/tests/palsuite/c_runtime/ferror/CMakeLists.txt5
-rw-r--r--src/pal/tests/palsuite/c_runtime/ferror/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/ferror/test1/test1.c74
-rw-r--r--src/pal/tests/palsuite/c_runtime/ferror/test1/testfile1
-rw-r--r--src/pal/tests/palsuite/c_runtime/ferror/test1/testinfo.dat16
-rw-r--r--src/pal/tests/palsuite/c_runtime/ferror/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/ferror/test2/test2.c69
-rw-r--r--src/pal/tests/palsuite/c_runtime/ferror/test2/testfile1
-rw-r--r--src/pal/tests/palsuite/c_runtime/ferror/test2/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/c_runtime/fflush/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/fflush/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/fflush/test1/test1.c80
-rw-r--r--src/pal/tests/palsuite/c_runtime/fflush/test1/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/c_runtime/fgets/CMakeLists.txt6
-rw-r--r--src/pal/tests/palsuite/c_runtime/fgets/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/fgets/test1/test1.c102
-rw-r--r--src/pal/tests/palsuite/c_runtime/fgets/test1/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/c_runtime/fgets/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/fgets/test2/test2.c97
-rw-r--r--src/pal/tests/palsuite/c_runtime/fgets/test2/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/fgets/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/fgets/test3/test3.c73
-rw-r--r--src/pal/tests/palsuite/c_runtime/fgets/test3/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/floor/CMakeLists.txt3
-rw-r--r--src/pal/tests/palsuite/c_runtime/floor/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/floor/test1/test1.c132
-rw-r--r--src/pal/tests/palsuite/c_runtime/floor/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/c_runtime/fmod/CMakeLists.txt3
-rw-r--r--src/pal/tests/palsuite/c_runtime/fmod/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/fmod/test1/test1.c157
-rw-r--r--src/pal/tests/palsuite/c_runtime/fmod/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/c_runtime/fmodf/CMakeLists.txt3
-rw-r--r--src/pal/tests/palsuite/c_runtime/fmodf/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/fmodf/test1/test1.c156
-rw-r--r--src/pal/tests/palsuite/c_runtime/fmodf/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/c_runtime/fopen/CMakeLists.txt10
-rw-r--r--src/pal/tests/palsuite/c_runtime/fopen/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/fopen/test1/test1.c82
-rw-r--r--src/pal/tests/palsuite/c_runtime/fopen/test1/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/c_runtime/fopen/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/fopen/test2/test2.c65
-rw-r--r--src/pal/tests/palsuite/c_runtime/fopen/test2/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/c_runtime/fopen/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/fopen/test3/test3.c66
-rw-r--r--src/pal/tests/palsuite/c_runtime/fopen/test3/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/c_runtime/fopen/test4/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/fopen/test4/test4.c82
-rw-r--r--src/pal/tests/palsuite/c_runtime/fopen/test4/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/c_runtime/fopen/test5/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/fopen/test5/test5.c78
-rw-r--r--src/pal/tests/palsuite/c_runtime/fopen/test5/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/c_runtime/fopen/test6/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/fopen/test6/test6.c131
-rw-r--r--src/pal/tests/palsuite/c_runtime/fopen/test6/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/c_runtime/fopen/test7/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/fopen/test7/test7.c117
-rw-r--r--src/pal/tests/palsuite/c_runtime/fopen/test7/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/c_runtime/fprintf/CMakeLists.txt22
-rw-r--r--src/pal/tests/palsuite/c_runtime/fprintf/fprintf.h177
-rw-r--r--src/pal/tests/palsuite/c_runtime/fprintf/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/fprintf/test1/test1.c80
-rw-r--r--src/pal/tests/palsuite/c_runtime/fprintf/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/c_runtime/fprintf/test10/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/fprintf/test10/test10.c49
-rw-r--r--src/pal/tests/palsuite/c_runtime/fprintf/test10/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/c_runtime/fprintf/test11/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/fprintf/test11/test11.c49
-rw-r--r--src/pal/tests/palsuite/c_runtime/fprintf/test11/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/c_runtime/fprintf/test12/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/fprintf/test12/test12.c50
-rw-r--r--src/pal/tests/palsuite/c_runtime/fprintf/test12/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/c_runtime/fprintf/test13/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/fprintf/test13/test13.c50
-rw-r--r--src/pal/tests/palsuite/c_runtime/fprintf/test13/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/c_runtime/fprintf/test14/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/fprintf/test14/test14.c49
-rw-r--r--src/pal/tests/palsuite/c_runtime/fprintf/test14/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/fprintf/test15/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/fprintf/test15/test15.c49
-rw-r--r--src/pal/tests/palsuite/c_runtime/fprintf/test15/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/fprintf/test16/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/fprintf/test16/test16.c48
-rw-r--r--src/pal/tests/palsuite/c_runtime/fprintf/test16/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/c_runtime/fprintf/test17/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/fprintf/test17/test17.c49
-rw-r--r--src/pal/tests/palsuite/c_runtime/fprintf/test17/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/c_runtime/fprintf/test18/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/fprintf/test18/test18.c49
-rw-r--r--src/pal/tests/palsuite/c_runtime/fprintf/test18/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/c_runtime/fprintf/test19/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/fprintf/test19/test19.c153
-rw-r--r--src/pal/tests/palsuite/c_runtime/fprintf/test19/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/c_runtime/fprintf/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/fprintf/test2/test2.c43
-rw-r--r--src/pal/tests/palsuite/c_runtime/fprintf/test2/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/c_runtime/fprintf/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/fprintf/test3/test3.c43
-rw-r--r--src/pal/tests/palsuite/c_runtime/fprintf/test3/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/c_runtime/fprintf/test4/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/fprintf/test4/test4.c110
-rw-r--r--src/pal/tests/palsuite/c_runtime/fprintf/test4/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/c_runtime/fprintf/test5/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/fprintf/test5/test5.c131
-rw-r--r--src/pal/tests/palsuite/c_runtime/fprintf/test5/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/c_runtime/fprintf/test6/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/fprintf/test6/test6.c46
-rw-r--r--src/pal/tests/palsuite/c_runtime/fprintf/test6/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/c_runtime/fprintf/test7/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/fprintf/test7/test7.c44
-rw-r--r--src/pal/tests/palsuite/c_runtime/fprintf/test7/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/c_runtime/fprintf/test8/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/fprintf/test8/test8.c49
-rw-r--r--src/pal/tests/palsuite/c_runtime/fprintf/test8/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/c_runtime/fprintf/test9/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/fprintf/test9/test9.c49
-rw-r--r--src/pal/tests/palsuite/c_runtime/fprintf/test9/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/c_runtime/fputs/CMakeLists.txt5
-rw-r--r--src/pal/tests/palsuite/c_runtime/fputs/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/fputs/test1/test1.c100
-rw-r--r--src/pal/tests/palsuite/c_runtime/fputs/test1/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/fputs/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/fputs/test2/test2.c88
-rw-r--r--src/pal/tests/palsuite/c_runtime/fputs/test2/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/c_runtime/fread/CMakeLists.txt6
-rw-r--r--src/pal/tests/palsuite/c_runtime/fread/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/fread/test1/test1.c135
-rw-r--r--src/pal/tests/palsuite/c_runtime/fread/test1/testfile1
-rw-r--r--src/pal/tests/palsuite/c_runtime/fread/test1/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/c_runtime/fread/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/fread/test2/test2.c143
-rw-r--r--src/pal/tests/palsuite/c_runtime/fread/test2/testfile1
-rw-r--r--src/pal/tests/palsuite/c_runtime/fread/test2/testinfo.dat16
-rw-r--r--src/pal/tests/palsuite/c_runtime/fread/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/fread/test3/test3.c131
-rw-r--r--src/pal/tests/palsuite/c_runtime/fread/test3/testfile1
-rw-r--r--src/pal/tests/palsuite/c_runtime/fread/test3/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/c_runtime/free/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/free/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/free/test1/test1.c62
-rw-r--r--src/pal/tests/palsuite/c_runtime/free/test1/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/fseek/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/fseek/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/fseek/test1/test1.c193
-rw-r--r--src/pal/tests/palsuite/c_runtime/fseek/test1/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/c_runtime/ftell/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/ftell/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/ftell/test1/ftell.c145
-rw-r--r--src/pal/tests/palsuite/c_runtime/ftell/test1/testfile.txt1
-rw-r--r--src/pal/tests/palsuite/c_runtime/ftell/test1/testinfo.dat16
-rw-r--r--src/pal/tests/palsuite/c_runtime/fwprintf/CMakeLists.txt22
-rw-r--r--src/pal/tests/palsuite/c_runtime/fwprintf/fwprintf.h453
-rw-r--r--src/pal/tests/palsuite/c_runtime/fwprintf/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/fwprintf/test1/test1.c71
-rw-r--r--src/pal/tests/palsuite/c_runtime/fwprintf/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/c_runtime/fwprintf/test10/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/fwprintf/test10/test10.c51
-rw-r--r--src/pal/tests/palsuite/c_runtime/fwprintf/test10/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/c_runtime/fwprintf/test11/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/fwprintf/test11/test11.c51
-rw-r--r--src/pal/tests/palsuite/c_runtime/fwprintf/test11/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/c_runtime/fwprintf/test12/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/fwprintf/test12/test12.c52
-rw-r--r--src/pal/tests/palsuite/c_runtime/fwprintf/test12/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/c_runtime/fwprintf/test13/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/fwprintf/test13/test13.c52
-rw-r--r--src/pal/tests/palsuite/c_runtime/fwprintf/test13/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/c_runtime/fwprintf/test14/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/fwprintf/test14/test14.c66
-rw-r--r--src/pal/tests/palsuite/c_runtime/fwprintf/test14/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/fwprintf/test15/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/fwprintf/test15/test15.c66
-rw-r--r--src/pal/tests/palsuite/c_runtime/fwprintf/test15/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/fwprintf/test16/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/fwprintf/test16/test16.c65
-rw-r--r--src/pal/tests/palsuite/c_runtime/fwprintf/test16/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/c_runtime/fwprintf/test17/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/fwprintf/test17/test17.c51
-rw-r--r--src/pal/tests/palsuite/c_runtime/fwprintf/test17/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/c_runtime/fwprintf/test18/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/fwprintf/test18/test18.c51
-rw-r--r--src/pal/tests/palsuite/c_runtime/fwprintf/test18/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/c_runtime/fwprintf/test19/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/fwprintf/test19/test19.c81
-rw-r--r--src/pal/tests/palsuite/c_runtime/fwprintf/test19/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/c_runtime/fwprintf/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/fwprintf/test2/test2.c45
-rw-r--r--src/pal/tests/palsuite/c_runtime/fwprintf/test2/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/c_runtime/fwprintf/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/fwprintf/test3/test3.c45
-rw-r--r--src/pal/tests/palsuite/c_runtime/fwprintf/test3/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/c_runtime/fwprintf/test4/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/fwprintf/test4/test4.c85
-rw-r--r--src/pal/tests/palsuite/c_runtime/fwprintf/test4/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/c_runtime/fwprintf/test5/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/fwprintf/test5/test5.c63
-rw-r--r--src/pal/tests/palsuite/c_runtime/fwprintf/test5/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/c_runtime/fwprintf/test6/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/fwprintf/test6/test6.c48
-rw-r--r--src/pal/tests/palsuite/c_runtime/fwprintf/test6/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/c_runtime/fwprintf/test7/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/fwprintf/test7/test7.c47
-rw-r--r--src/pal/tests/palsuite/c_runtime/fwprintf/test7/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/c_runtime/fwprintf/test8/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/fwprintf/test8/test8.c51
-rw-r--r--src/pal/tests/palsuite/c_runtime/fwprintf/test8/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/c_runtime/fwprintf/test9/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/fwprintf/test9/test9.c51
-rw-r--r--src/pal/tests/palsuite/c_runtime/fwprintf/test9/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/c_runtime/fwrite/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/fwrite/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/fwrite/test1/test1.c104
-rw-r--r--src/pal/tests/palsuite/c_runtime/fwrite/test1/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/getc/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/getc/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/getc/test1/getc.c152
-rw-r--r--src/pal/tests/palsuite/c_runtime/getc/test1/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/getenv/CMakeLists.txt6
-rw-r--r--src/pal/tests/palsuite/c_runtime/getenv/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/getenv/test1/test1.c78
-rw-r--r--src/pal/tests/palsuite/c_runtime/getenv/test1/testinfo.dat16
-rw-r--r--src/pal/tests/palsuite/c_runtime/getenv/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/getenv/test2/test2.c101
-rw-r--r--src/pal/tests/palsuite/c_runtime/getenv/test2/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/getenv/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/getenv/test3/test3.c75
-rw-r--r--src/pal/tests/palsuite/c_runtime/getenv/test3/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/isalnum/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/isalnum/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/isalnum/test1/test1.c88
-rw-r--r--src/pal/tests/palsuite/c_runtime/isalnum/test1/testinfo.dat19
-rw-r--r--src/pal/tests/palsuite/c_runtime/isalpha/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/isalpha/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/isalpha/test1/test1.c86
-rw-r--r--src/pal/tests/palsuite/c_runtime/isalpha/test1/testinfo.dat19
-rw-r--r--src/pal/tests/palsuite/c_runtime/isdigit/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/isdigit/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/isdigit/test1/test1.c47
-rw-r--r--src/pal/tests/palsuite/c_runtime/isdigit/test1/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/islower/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/islower/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/islower/test1/test1.c85
-rw-r--r--src/pal/tests/palsuite/c_runtime/islower/test1/testinfo.dat19
-rw-r--r--src/pal/tests/palsuite/c_runtime/isprint/CMakeLists.txt5
-rw-r--r--src/pal/tests/palsuite/c_runtime/isprint/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/isprint/test1/isprint.c42
-rw-r--r--src/pal/tests/palsuite/c_runtime/isprint/test1/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/isprint/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/isprint/test2/test2.c59
-rw-r--r--src/pal/tests/palsuite/c_runtime/isprint/test2/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/c_runtime/isspace/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/isspace/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/isspace/test1/test1.c82
-rw-r--r--src/pal/tests/palsuite/c_runtime/isspace/test1/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/c_runtime/isupper/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/isupper/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/isupper/test1/test1.c88
-rw-r--r--src/pal/tests/palsuite/c_runtime/isupper/test1/testinfo.dat19
-rw-r--r--src/pal/tests/palsuite/c_runtime/iswdigit/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/iswdigit/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/iswdigit/test1/test1.c69
-rw-r--r--src/pal/tests/palsuite/c_runtime/iswdigit/test1/testinfo.dat19
-rw-r--r--src/pal/tests/palsuite/c_runtime/iswprint/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/iswprint/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/iswprint/test1/test1.c59
-rw-r--r--src/pal/tests/palsuite/c_runtime/iswprint/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/c_runtime/iswspace/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/iswspace/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/iswspace/test1/test1.c78
-rw-r--r--src/pal/tests/palsuite/c_runtime/iswspace/test1/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/iswupper/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/iswupper/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/iswupper/test1/test1.c91
-rw-r--r--src/pal/tests/palsuite/c_runtime/iswupper/test1/testinfo.dat19
-rw-r--r--src/pal/tests/palsuite/c_runtime/iswxdigit/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/iswxdigit/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/iswxdigit/test1/test1.c61
-rw-r--r--src/pal/tests/palsuite/c_runtime/iswxdigit/test1/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/isxdigit/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/isxdigit/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/isxdigit/test1/test1.c58
-rw-r--r--src/pal/tests/palsuite/c_runtime/isxdigit/test1/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/c_runtime/labs/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/labs/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/labs/test1/test1.c65
-rw-r--r--src/pal/tests/palsuite/c_runtime/labs/test1/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/llabs/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/llabs/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/llabs/test1/test1.c65
-rw-r--r--src/pal/tests/palsuite/c_runtime/llabs/test1/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/localtime/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/localtime/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/localtime/test1/test1.c69
-rw-r--r--src/pal/tests/palsuite/c_runtime/localtime/test1/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/c_runtime/log/CMakeLists.txt3
-rw-r--r--src/pal/tests/palsuite/c_runtime/log/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/log/test1/test1.c140
-rw-r--r--src/pal/tests/palsuite/c_runtime/log/test1/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/log10/CMakeLists.txt3
-rw-r--r--src/pal/tests/palsuite/c_runtime/log10/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/log10/test1/test1.c146
-rw-r--r--src/pal/tests/palsuite/c_runtime/log10/test1/testinfo.dat17
-rw-r--r--src/pal/tests/palsuite/c_runtime/malloc/CMakeLists.txt5
-rw-r--r--src/pal/tests/palsuite/c_runtime/malloc/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/malloc/test1/test1.c52
-rw-r--r--src/pal/tests/palsuite/c_runtime/malloc/test1/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/malloc/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/malloc/test2/test2.c41
-rw-r--r--src/pal/tests/palsuite/c_runtime/malloc/test2/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/memchr/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/memchr/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/memchr/test1/test1.c122
-rw-r--r--src/pal/tests/palsuite/c_runtime/memchr/test1/testinfo.dat19
-rw-r--r--src/pal/tests/palsuite/c_runtime/memcmp/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/memcmp/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/memcmp/test1/test1.c57
-rw-r--r--src/pal/tests/palsuite/c_runtime/memcmp/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/c_runtime/memcpy/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/memcpy/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/memcpy/test1/test1.c87
-rw-r--r--src/pal/tests/palsuite/c_runtime/memcpy/test1/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/memmove/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/memmove/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/memmove/test1/test1.c116
-rw-r--r--src/pal/tests/palsuite/c_runtime/memmove/test1/testinfo.dat19
-rw-r--r--src/pal/tests/palsuite/c_runtime/memset/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/memset/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/memset/test1/test1.c60
-rw-r--r--src/pal/tests/palsuite/c_runtime/memset/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/c_runtime/modf/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/modf/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/modf/test1/test1.c136
-rw-r--r--src/pal/tests/palsuite/c_runtime/modf/test1/testinfo.dat16
-rw-r--r--src/pal/tests/palsuite/c_runtime/modff/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/modff/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/modff/test1/test1.c135
-rw-r--r--src/pal/tests/palsuite/c_runtime/modff/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/c_runtime/pow/CMakeLists.txt3
-rw-r--r--src/pal/tests/palsuite/c_runtime/pow/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/pow/test1/test1.c230
-rw-r--r--src/pal/tests/palsuite/c_runtime/pow/test1/testinfo.dat17
-rw-r--r--src/pal/tests/palsuite/c_runtime/printf/CMakeLists.txt22
-rw-r--r--src/pal/tests/palsuite/c_runtime/printf/printf.h182
-rw-r--r--src/pal/tests/palsuite/c_runtime/printf/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/printf/test1/test1.c43
-rw-r--r--src/pal/tests/palsuite/c_runtime/printf/test1/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/printf/test10/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/printf/test10/test10.c52
-rw-r--r--src/pal/tests/palsuite/c_runtime/printf/test10/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/printf/test11/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/printf/test11/test11.c51
-rw-r--r--src/pal/tests/palsuite/c_runtime/printf/test11/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/printf/test12/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/printf/test12/test12.c53
-rw-r--r--src/pal/tests/palsuite/c_runtime/printf/test12/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/printf/test13/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/printf/test13/test13.c54
-rw-r--r--src/pal/tests/palsuite/c_runtime/printf/test13/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/printf/test14/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/printf/test14/test14.c54
-rw-r--r--src/pal/tests/palsuite/c_runtime/printf/test14/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/printf/test15/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/printf/test15/test15.c54
-rw-r--r--src/pal/tests/palsuite/c_runtime/printf/test15/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/printf/test16/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/printf/test16/test16.c50
-rw-r--r--src/pal/tests/palsuite/c_runtime/printf/test16/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/printf/test17/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/printf/test17/test17.c52
-rw-r--r--src/pal/tests/palsuite/c_runtime/printf/test17/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/printf/test18/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/printf/test18/test18.c51
-rw-r--r--src/pal/tests/palsuite/c_runtime/printf/test18/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/printf/test19/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/printf/test19/test19.c76
-rw-r--r--src/pal/tests/palsuite/c_runtime/printf/test19/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/printf/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/printf/test2/test2.c45
-rw-r--r--src/pal/tests/palsuite/c_runtime/printf/test2/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/printf/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/printf/test3/test3.c45
-rw-r--r--src/pal/tests/palsuite/c_runtime/printf/test3/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/printf/test4/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/printf/test4/test4.c66
-rw-r--r--src/pal/tests/palsuite/c_runtime/printf/test4/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/printf/test5/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/printf/test5/test5.c60
-rw-r--r--src/pal/tests/palsuite/c_runtime/printf/test5/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/printf/test6/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/printf/test6/test6.c48
-rw-r--r--src/pal/tests/palsuite/c_runtime/printf/test6/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/printf/test7/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/printf/test7/test7.c47
-rw-r--r--src/pal/tests/palsuite/c_runtime/printf/test7/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/printf/test8/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/printf/test8/test8.c53
-rw-r--r--src/pal/tests/palsuite/c_runtime/printf/test8/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/printf/test9/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/printf/test9/test9.c53
-rw-r--r--src/pal/tests/palsuite/c_runtime/printf/test9/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/qsort/CMakeLists.txt5
-rw-r--r--src/pal/tests/palsuite/c_runtime/qsort/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/qsort/test1/test1.c48
-rw-r--r--src/pal/tests/palsuite/c_runtime/qsort/test1/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/qsort/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/qsort/test2/test2.c49
-rw-r--r--src/pal/tests/palsuite/c_runtime/qsort/test2/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/rand_srand/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/rand_srand/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/rand_srand/test1/test1.c100
-rw-r--r--src/pal/tests/palsuite/c_runtime/rand_srand/test1/testinfo.dat16
-rw-r--r--src/pal/tests/palsuite/c_runtime/realloc/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/realloc/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/realloc/test1/test1.c66
-rw-r--r--src/pal/tests/palsuite/c_runtime/realloc/test1/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/sin/CMakeLists.txt3
-rw-r--r--src/pal/tests/palsuite/c_runtime/sin/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/sin/test1/test1.c131
-rw-r--r--src/pal/tests/palsuite/c_runtime/sin/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/c_runtime/sinh/CMakeLists.txt3
-rw-r--r--src/pal/tests/palsuite/c_runtime/sinh/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/sinh/test1/test1.c130
-rw-r--r--src/pal/tests/palsuite/c_runtime/sinh/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/c_runtime/sprintf/CMakeLists.txt22
-rw-r--r--src/pal/tests/palsuite/c_runtime/sprintf/sprintf.h195
-rw-r--r--src/pal/tests/palsuite/c_runtime/sprintf/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/sprintf/test1/test1.c45
-rw-r--r--src/pal/tests/palsuite/c_runtime/sprintf/test1/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/sprintf/test10/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/sprintf/test10/test10.c55
-rw-r--r--src/pal/tests/palsuite/c_runtime/sprintf/test10/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/sprintf/test11/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/sprintf/test11/test11.c55
-rw-r--r--src/pal/tests/palsuite/c_runtime/sprintf/test11/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/sprintf/test12/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/sprintf/test12/test12.c56
-rw-r--r--src/pal/tests/palsuite/c_runtime/sprintf/test12/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/sprintf/test13/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/sprintf/test13/test13.c56
-rw-r--r--src/pal/tests/palsuite/c_runtime/sprintf/test13/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/sprintf/test14/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/sprintf/test14/test14.c53
-rw-r--r--src/pal/tests/palsuite/c_runtime/sprintf/test14/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/sprintf/test15/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/sprintf/test15/test15.c53
-rw-r--r--src/pal/tests/palsuite/c_runtime/sprintf/test15/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/sprintf/test16/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/sprintf/test16/test16.c52
-rw-r--r--src/pal/tests/palsuite/c_runtime/sprintf/test16/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/sprintf/test17/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/sprintf/test17/test17.c54
-rw-r--r--src/pal/tests/palsuite/c_runtime/sprintf/test17/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/sprintf/test18/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/sprintf/test18/test18.c53
-rw-r--r--src/pal/tests/palsuite/c_runtime/sprintf/test18/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/sprintf/test19/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/sprintf/test19/test19.c78
-rw-r--r--src/pal/tests/palsuite/c_runtime/sprintf/test19/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/sprintf/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/sprintf/test2/test2.c47
-rw-r--r--src/pal/tests/palsuite/c_runtime/sprintf/test2/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/sprintf/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/sprintf/test3/test3.c47
-rw-r--r--src/pal/tests/palsuite/c_runtime/sprintf/test3/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/sprintf/test4/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/sprintf/test4/test4.c69
-rw-r--r--src/pal/tests/palsuite/c_runtime/sprintf/test4/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/sprintf/test5/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/sprintf/test5/test5.c62
-rw-r--r--src/pal/tests/palsuite/c_runtime/sprintf/test5/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/sprintf/test6/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/sprintf/test6/test6.c50
-rw-r--r--src/pal/tests/palsuite/c_runtime/sprintf/test6/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/sprintf/test7/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/sprintf/test7/test7.c49
-rw-r--r--src/pal/tests/palsuite/c_runtime/sprintf/test7/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/sprintf/test8/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/sprintf/test8/test8.c55
-rw-r--r--src/pal/tests/palsuite/c_runtime/sprintf/test8/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/sprintf/test9/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/sprintf/test9/test9.c55
-rw-r--r--src/pal/tests/palsuite/c_runtime/sprintf/test9/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/sqrt/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/sqrt/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/sqrt/test1/test1.c123
-rw-r--r--src/pal/tests/palsuite/c_runtime/sqrt/test1/testinfo.dat17
-rw-r--r--src/pal/tests/palsuite/c_runtime/sscanf/CMakeLists.txt20
-rw-r--r--src/pal/tests/palsuite/c_runtime/sscanf/sscanf.h246
-rw-r--r--src/pal/tests/palsuite/c_runtime/sscanf/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/sscanf/test1/test1.c53
-rw-r--r--src/pal/tests/palsuite/c_runtime/sscanf/test1/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/sscanf/test10/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/sscanf/test10/test10.c37
-rw-r--r--src/pal/tests/palsuite/c_runtime/sscanf/test10/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/sscanf/test11/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/sscanf/test11/test11.c36
-rw-r--r--src/pal/tests/palsuite/c_runtime/sscanf/test11/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/sscanf/test12/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/sscanf/test12/test12.c35
-rw-r--r--src/pal/tests/palsuite/c_runtime/sscanf/test12/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/sscanf/test13/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/sscanf/test13/test13.c37
-rw-r--r--src/pal/tests/palsuite/c_runtime/sscanf/test13/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/sscanf/test14/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/sscanf/test14/test14.c36
-rw-r--r--src/pal/tests/palsuite/c_runtime/sscanf/test14/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/sscanf/test15/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/sscanf/test15/test15.c36
-rw-r--r--src/pal/tests/palsuite/c_runtime/sscanf/test15/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/sscanf/test16/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/sscanf/test16/test16.c37
-rw-r--r--src/pal/tests/palsuite/c_runtime/sscanf/test16/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/sscanf/test17/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/sscanf/test17/test17.c37
-rw-r--r--src/pal/tests/palsuite/c_runtime/sscanf/test17/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/sscanf/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/sscanf/test2/test2.c44
-rw-r--r--src/pal/tests/palsuite/c_runtime/sscanf/test2/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/sscanf/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/sscanf/test3/test3.c35
-rw-r--r--src/pal/tests/palsuite/c_runtime/sscanf/test3/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/sscanf/test4/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/sscanf/test4/test4.c44
-rw-r--r--src/pal/tests/palsuite/c_runtime/sscanf/test4/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/sscanf/test5/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/sscanf/test5/test5.c43
-rw-r--r--src/pal/tests/palsuite/c_runtime/sscanf/test5/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/sscanf/test6/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/sscanf/test6/test6.c43
-rw-r--r--src/pal/tests/palsuite/c_runtime/sscanf/test6/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/sscanf/test7/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/sscanf/test7/test7.c43
-rw-r--r--src/pal/tests/palsuite/c_runtime/sscanf/test7/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/sscanf/test8/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/sscanf/test8/test8.c43
-rw-r--r--src/pal/tests/palsuite/c_runtime/sscanf/test8/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/sscanf/test9/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/sscanf/test9/test9.c38
-rw-r--r--src/pal/tests/palsuite/c_runtime/sscanf/test9/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/strcat/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/strcat/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/strcat/test1/test1.c66
-rw-r--r--src/pal/tests/palsuite/c_runtime/strcat/test1/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/c_runtime/strchr/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/strchr/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/strchr/test1/test1.c86
-rw-r--r--src/pal/tests/palsuite/c_runtime/strchr/test1/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/c_runtime/strcmp/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/strcmp/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/strcmp/test1/test1.c73
-rw-r--r--src/pal/tests/palsuite/c_runtime/strcmp/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/c_runtime/strcpy/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/strcpy/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/strcpy/test1/test1.c51
-rw-r--r--src/pal/tests/palsuite/c_runtime/strcpy/test1/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/strcspn/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/strcspn/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/strcspn/test1/test1.c59
-rw-r--r--src/pal/tests/palsuite/c_runtime/strcspn/test1/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/c_runtime/strlen/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/strlen/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/strlen/test1/test1.c33
-rw-r--r--src/pal/tests/palsuite/c_runtime/strlen/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/c_runtime/strncat/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/strncat/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/strncat/test1/test1.c77
-rw-r--r--src/pal/tests/palsuite/c_runtime/strncat/test1/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/strncmp/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/strncmp/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/strncmp/test1/test1.c80
-rw-r--r--src/pal/tests/palsuite/c_runtime/strncmp/test1/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/strncpy/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/strncpy/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/strncpy/test1/test1.c85
-rw-r--r--src/pal/tests/palsuite/c_runtime/strncpy/test1/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/c_runtime/strpbrk/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/strpbrk/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/strpbrk/test1/test1.c85
-rw-r--r--src/pal/tests/palsuite/c_runtime/strpbrk/test1/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/strrchr/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/strrchr/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/strrchr/test1/test1.c55
-rw-r--r--src/pal/tests/palsuite/c_runtime/strrchr/test1/testinfo.dat16
-rw-r--r--src/pal/tests/palsuite/c_runtime/strspn/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/strspn/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/strspn/test1/test1.c60
-rw-r--r--src/pal/tests/palsuite/c_runtime/strspn/test1/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/c_runtime/strstr/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/strstr/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/strstr/test1/test1.c83
-rw-r--r--src/pal/tests/palsuite/c_runtime/strstr/test1/testinfo.dat16
-rw-r--r--src/pal/tests/palsuite/c_runtime/strtod/CMakeLists.txt5
-rw-r--r--src/pal/tests/palsuite/c_runtime/strtod/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/strtod/test1/test1.c93
-rw-r--r--src/pal/tests/palsuite/c_runtime/strtod/test1/testinfo.dat17
-rw-r--r--src/pal/tests/palsuite/c_runtime/strtod/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/strtod/test2/test2.c65
-rw-r--r--src/pal/tests/palsuite/c_runtime/strtod/test2/testinfo.dat16
-rw-r--r--src/pal/tests/palsuite/c_runtime/strtok/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/strtok/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/strtok/test1/test1.c78
-rw-r--r--src/pal/tests/palsuite/c_runtime/strtok/test1/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/strtoul/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/strtoul/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/strtoul/test1/test1.c73
-rw-r--r--src/pal/tests/palsuite/c_runtime/strtoul/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/c_runtime/swprintf/CMakeLists.txt22
-rw-r--r--src/pal/tests/palsuite/c_runtime/swprintf/swprintf.h202
-rw-r--r--src/pal/tests/palsuite/c_runtime/swprintf/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/swprintf/test1/test1.c44
-rw-r--r--src/pal/tests/palsuite/c_runtime/swprintf/test1/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/swprintf/test10/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/swprintf/test10/test10.c55
-rw-r--r--src/pal/tests/palsuite/c_runtime/swprintf/test10/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/swprintf/test11/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/swprintf/test11/test11.c55
-rw-r--r--src/pal/tests/palsuite/c_runtime/swprintf/test11/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/swprintf/test12/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/swprintf/test12/test12.c56
-rw-r--r--src/pal/tests/palsuite/c_runtime/swprintf/test12/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/swprintf/test13/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/swprintf/test13/test13.c55
-rw-r--r--src/pal/tests/palsuite/c_runtime/swprintf/test13/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/swprintf/test14/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/swprintf/test14/test14.c67
-rw-r--r--src/pal/tests/palsuite/c_runtime/swprintf/test14/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/swprintf/test15/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/swprintf/test15/test15.c67
-rw-r--r--src/pal/tests/palsuite/c_runtime/swprintf/test15/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/swprintf/test16/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/swprintf/test16/test16.c67
-rw-r--r--src/pal/tests/palsuite/c_runtime/swprintf/test16/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/swprintf/test17/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/swprintf/test17/test17.c69
-rw-r--r--src/pal/tests/palsuite/c_runtime/swprintf/test17/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/swprintf/test18/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/swprintf/test18/test18.c69
-rw-r--r--src/pal/tests/palsuite/c_runtime/swprintf/test18/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/swprintf/test19/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/swprintf/test19/test19.c109
-rw-r--r--src/pal/tests/palsuite/c_runtime/swprintf/test19/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/swprintf/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/swprintf/test2/test2.c46
-rw-r--r--src/pal/tests/palsuite/c_runtime/swprintf/test2/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/swprintf/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/swprintf/test3/test3.c43
-rw-r--r--src/pal/tests/palsuite/c_runtime/swprintf/test3/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/swprintf/test4/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/swprintf/test4/test4.c71
-rw-r--r--src/pal/tests/palsuite/c_runtime/swprintf/test4/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/swprintf/test5/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/swprintf/test5/test5.c67
-rw-r--r--src/pal/tests/palsuite/c_runtime/swprintf/test5/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/swprintf/test6/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/swprintf/test6/test6.c47
-rw-r--r--src/pal/tests/palsuite/c_runtime/swprintf/test6/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/swprintf/test7/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/swprintf/test7/test7.c48
-rw-r--r--src/pal/tests/palsuite/c_runtime/swprintf/test7/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/swprintf/test8/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/swprintf/test8/test8.c55
-rw-r--r--src/pal/tests/palsuite/c_runtime/swprintf/test8/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/swprintf/test9/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/swprintf/test9/test9.c55
-rw-r--r--src/pal/tests/palsuite/c_runtime/swprintf/test9/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/swscanf/CMakeLists.txt20
-rw-r--r--src/pal/tests/palsuite/c_runtime/swscanf/swscanf.h262
-rw-r--r--src/pal/tests/palsuite/c_runtime/swscanf/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/swscanf/test1/test1.c53
-rw-r--r--src/pal/tests/palsuite/c_runtime/swscanf/test1/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/swscanf/test10/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/swscanf/test10/test10.c36
-rw-r--r--src/pal/tests/palsuite/c_runtime/swscanf/test10/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/swscanf/test11/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/swscanf/test11/test11.c35
-rw-r--r--src/pal/tests/palsuite/c_runtime/swscanf/test11/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/swscanf/test12/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/swscanf/test12/test12.c35
-rw-r--r--src/pal/tests/palsuite/c_runtime/swscanf/test12/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/swscanf/test13/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/swscanf/test13/test13.c37
-rw-r--r--src/pal/tests/palsuite/c_runtime/swscanf/test13/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/swscanf/test14/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/swscanf/test14/test14.c38
-rw-r--r--src/pal/tests/palsuite/c_runtime/swscanf/test14/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/swscanf/test15/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/swscanf/test15/test15.c37
-rw-r--r--src/pal/tests/palsuite/c_runtime/swscanf/test15/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/swscanf/test16/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/swscanf/test16/test16.c37
-rw-r--r--src/pal/tests/palsuite/c_runtime/swscanf/test16/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/swscanf/test17/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/swscanf/test17/test17.c37
-rw-r--r--src/pal/tests/palsuite/c_runtime/swscanf/test17/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/swscanf/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/swscanf/test2/test2.c43
-rw-r--r--src/pal/tests/palsuite/c_runtime/swscanf/test2/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/swscanf/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/swscanf/test3/test3.c36
-rw-r--r--src/pal/tests/palsuite/c_runtime/swscanf/test3/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/swscanf/test4/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/swscanf/test4/test4.c44
-rw-r--r--src/pal/tests/palsuite/c_runtime/swscanf/test4/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/swscanf/test5/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/swscanf/test5/test5.c44
-rw-r--r--src/pal/tests/palsuite/c_runtime/swscanf/test5/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/swscanf/test6/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/swscanf/test6/test6.c44
-rw-r--r--src/pal/tests/palsuite/c_runtime/swscanf/test6/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/swscanf/test7/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/swscanf/test7/test7.c44
-rw-r--r--src/pal/tests/palsuite/c_runtime/swscanf/test7/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/swscanf/test8/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/swscanf/test8/test8.c44
-rw-r--r--src/pal/tests/palsuite/c_runtime/swscanf/test8/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/swscanf/test9/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/swscanf/test9/test9.c37
-rw-r--r--src/pal/tests/palsuite/c_runtime/swscanf/test9/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/tan/CMakeLists.txt3
-rw-r--r--src/pal/tests/palsuite/c_runtime/tan/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/tan/test1/test1.c137
-rw-r--r--src/pal/tests/palsuite/c_runtime/tan/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/c_runtime/tanh/CMakeLists.txt3
-rw-r--r--src/pal/tests/palsuite/c_runtime/tanh/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/tanh/test1/test1.c130
-rw-r--r--src/pal/tests/palsuite/c_runtime/tanh/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/c_runtime/time/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/time/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/time/test1/test1.c51
-rw-r--r--src/pal/tests/palsuite/c_runtime/time/test1/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/tolower/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/tolower/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/tolower/test1/test1.c79
-rw-r--r--src/pal/tests/palsuite/c_runtime/tolower/test1/testinfo.dat19
-rw-r--r--src/pal/tests/palsuite/c_runtime/toupper/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/toupper/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/toupper/test1/test1.c64
-rw-r--r--src/pal/tests/palsuite/c_runtime/toupper/test1/testinfo.dat19
-rw-r--r--src/pal/tests/palsuite/c_runtime/towlower/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/towlower/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/towlower/test1/test1.c79
-rw-r--r--src/pal/tests/palsuite/c_runtime/towlower/test1/testinfo.dat19
-rw-r--r--src/pal/tests/palsuite/c_runtime/towupper/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/towupper/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/towupper/test1/test1.c65
-rw-r--r--src/pal/tests/palsuite/c_runtime/towupper/test1/testinfo.dat19
-rw-r--r--src/pal/tests/palsuite/c_runtime/ungetc/CMakeLists.txt5
-rw-r--r--src/pal/tests/palsuite/c_runtime/ungetc/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/ungetc/test1/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/ungetc/test1/ungetc.c130
-rw-r--r--src/pal/tests/palsuite/c_runtime/ungetc/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/ungetc/test2/test2.txt1
-rw-r--r--src/pal/tests/palsuite/c_runtime/ungetc/test2/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/ungetc/test2/ungetc.c188
-rw-r--r--src/pal/tests/palsuite/c_runtime/vfprintf/CMakeLists.txt22
-rw-r--r--src/pal/tests/palsuite/c_runtime/vfprintf/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/vfprintf/test1/test1.c68
-rw-r--r--src/pal/tests/palsuite/c_runtime/vfprintf/test1/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/vfprintf/test10/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/vfprintf/test10/test10.c52
-rw-r--r--src/pal/tests/palsuite/c_runtime/vfprintf/test10/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/vfprintf/test11/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/vfprintf/test11/test11.c51
-rw-r--r--src/pal/tests/palsuite/c_runtime/vfprintf/test11/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/vfprintf/test12/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/vfprintf/test12/test12.c53
-rw-r--r--src/pal/tests/palsuite/c_runtime/vfprintf/test12/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/vfprintf/test13/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/vfprintf/test13/test13.c54
-rw-r--r--src/pal/tests/palsuite/c_runtime/vfprintf/test13/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/vfprintf/test14/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/vfprintf/test14/test14.c54
-rw-r--r--src/pal/tests/palsuite/c_runtime/vfprintf/test14/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/vfprintf/test15/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/vfprintf/test15/test15.c54
-rw-r--r--src/pal/tests/palsuite/c_runtime/vfprintf/test15/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/vfprintf/test16/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/vfprintf/test16/test16.c50
-rw-r--r--src/pal/tests/palsuite/c_runtime/vfprintf/test16/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/vfprintf/test17/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/vfprintf/test17/test17.c52
-rw-r--r--src/pal/tests/palsuite/c_runtime/vfprintf/test17/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/vfprintf/test18/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/vfprintf/test18/test18.c51
-rw-r--r--src/pal/tests/palsuite/c_runtime/vfprintf/test18/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/vfprintf/test19/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/vfprintf/test19/test19.c76
-rw-r--r--src/pal/tests/palsuite/c_runtime/vfprintf/test19/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/vfprintf/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/vfprintf/test2/test2.c45
-rw-r--r--src/pal/tests/palsuite/c_runtime/vfprintf/test2/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/vfprintf/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/vfprintf/test3/test3.c45
-rw-r--r--src/pal/tests/palsuite/c_runtime/vfprintf/test3/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/vfprintf/test4/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/vfprintf/test4/test4.c70
-rw-r--r--src/pal/tests/palsuite/c_runtime/vfprintf/test4/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/vfprintf/test5/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/vfprintf/test5/test5.c60
-rw-r--r--src/pal/tests/palsuite/c_runtime/vfprintf/test5/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/vfprintf/test6/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/vfprintf/test6/test6.c48
-rw-r--r--src/pal/tests/palsuite/c_runtime/vfprintf/test6/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/vfprintf/test7/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/vfprintf/test7/test7.c47
-rw-r--r--src/pal/tests/palsuite/c_runtime/vfprintf/test7/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/vfprintf/test8/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/vfprintf/test8/test8.c53
-rw-r--r--src/pal/tests/palsuite/c_runtime/vfprintf/test8/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/vfprintf/test9/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/vfprintf/test9/test9.c53
-rw-r--r--src/pal/tests/palsuite/c_runtime/vfprintf/test9/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/vfprintf/vfprintf.h463
-rw-r--r--src/pal/tests/palsuite/c_runtime/vprintf/CMakeLists.txt23
-rw-r--r--src/pal/tests/palsuite/c_runtime/vprintf/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/vprintf/test1/test1.c43
-rw-r--r--src/pal/tests/palsuite/c_runtime/vprintf/test1/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/vprintf/test10/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/vprintf/test10/test10.c52
-rw-r--r--src/pal/tests/palsuite/c_runtime/vprintf/test10/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/vprintf/test11/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/vprintf/test11/test11.c51
-rw-r--r--src/pal/tests/palsuite/c_runtime/vprintf/test11/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/vprintf/test12/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/vprintf/test12/test12.c53
-rw-r--r--src/pal/tests/palsuite/c_runtime/vprintf/test12/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/vprintf/test13/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/vprintf/test13/test13.c54
-rw-r--r--src/pal/tests/palsuite/c_runtime/vprintf/test13/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/vprintf/test14/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/vprintf/test14/test14.c54
-rw-r--r--src/pal/tests/palsuite/c_runtime/vprintf/test14/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/vprintf/test15/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/vprintf/test15/test15.c54
-rw-r--r--src/pal/tests/palsuite/c_runtime/vprintf/test15/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/vprintf/test16/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/vprintf/test16/test16.c50
-rw-r--r--src/pal/tests/palsuite/c_runtime/vprintf/test16/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/vprintf/test17/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/vprintf/test17/test17.c52
-rw-r--r--src/pal/tests/palsuite/c_runtime/vprintf/test17/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/vprintf/test18/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/vprintf/test18/test18.c51
-rw-r--r--src/pal/tests/palsuite/c_runtime/vprintf/test18/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/vprintf/test19/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/vprintf/test19/test19.c76
-rw-r--r--src/pal/tests/palsuite/c_runtime/vprintf/test19/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/vprintf/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/vprintf/test2/test2.c45
-rw-r--r--src/pal/tests/palsuite/c_runtime/vprintf/test2/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/vprintf/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/vprintf/test3/test3.c45
-rw-r--r--src/pal/tests/palsuite/c_runtime/vprintf/test3/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/vprintf/test4/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/vprintf/test4/test4.c70
-rw-r--r--src/pal/tests/palsuite/c_runtime/vprintf/test4/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/vprintf/test5/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/vprintf/test5/test5.c60
-rw-r--r--src/pal/tests/palsuite/c_runtime/vprintf/test5/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/vprintf/test6/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/vprintf/test6/test6.c48
-rw-r--r--src/pal/tests/palsuite/c_runtime/vprintf/test6/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/vprintf/test7/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/vprintf/test7/test7.c47
-rw-r--r--src/pal/tests/palsuite/c_runtime/vprintf/test7/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/vprintf/test8/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/vprintf/test8/test8.c53
-rw-r--r--src/pal/tests/palsuite/c_runtime/vprintf/test8/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/vprintf/test9/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/vprintf/test9/test9.c53
-rw-r--r--src/pal/tests/palsuite/c_runtime/vprintf/test9/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/vprintf/vprintf.h193
-rw-r--r--src/pal/tests/palsuite/c_runtime/vsprintf/CMakeLists.txt22
-rw-r--r--src/pal/tests/palsuite/c_runtime/vsprintf/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/vsprintf/test1/test1.c55
-rw-r--r--src/pal/tests/palsuite/c_runtime/vsprintf/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/c_runtime/vsprintf/test10/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/vsprintf/test10/test10.c50
-rw-r--r--src/pal/tests/palsuite/c_runtime/vsprintf/test10/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/vsprintf/test11/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/vsprintf/test11/test11.c50
-rw-r--r--src/pal/tests/palsuite/c_runtime/vsprintf/test11/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/vsprintf/test12/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/vsprintf/test12/test12.c52
-rw-r--r--src/pal/tests/palsuite/c_runtime/vsprintf/test12/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/vsprintf/test13/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/vsprintf/test13/test13.c52
-rw-r--r--src/pal/tests/palsuite/c_runtime/vsprintf/test13/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/vsprintf/test14/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/vsprintf/test14/test14.c50
-rw-r--r--src/pal/tests/palsuite/c_runtime/vsprintf/test14/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/vsprintf/test15/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/vsprintf/test15/test15.c64
-rw-r--r--src/pal/tests/palsuite/c_runtime/vsprintf/test15/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/vsprintf/test16/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/vsprintf/test16/test16.c49
-rw-r--r--src/pal/tests/palsuite/c_runtime/vsprintf/test16/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/vsprintf/test17/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/vsprintf/test17/test17.c50
-rw-r--r--src/pal/tests/palsuite/c_runtime/vsprintf/test17/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/vsprintf/test18/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/vsprintf/test18/test18.c50
-rw-r--r--src/pal/tests/palsuite/c_runtime/vsprintf/test18/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/vsprintf/test19/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/vsprintf/test19/test19.c67
-rw-r--r--src/pal/tests/palsuite/c_runtime/vsprintf/test19/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/vsprintf/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/vsprintf/test2/test2.c42
-rw-r--r--src/pal/tests/palsuite/c_runtime/vsprintf/test2/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/vsprintf/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/vsprintf/test3/test3.c43
-rw-r--r--src/pal/tests/palsuite/c_runtime/vsprintf/test3/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/vsprintf/test4/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/vsprintf/test4/test4.c72
-rw-r--r--src/pal/tests/palsuite/c_runtime/vsprintf/test4/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/vsprintf/test5/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/vsprintf/test5/test5.c43
-rw-r--r--src/pal/tests/palsuite/c_runtime/vsprintf/test5/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/vsprintf/test6/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/vsprintf/test6/test6.c44
-rw-r--r--src/pal/tests/palsuite/c_runtime/vsprintf/test6/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/vsprintf/test7/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/vsprintf/test7/test7.c44
-rw-r--r--src/pal/tests/palsuite/c_runtime/vsprintf/test7/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/vsprintf/test8/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/vsprintf/test8/test8.c52
-rw-r--r--src/pal/tests/palsuite/c_runtime/vsprintf/test8/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/vsprintf/test9/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/vsprintf/test9/test9.c51
-rw-r--r--src/pal/tests/palsuite/c_runtime/vsprintf/test9/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/vsprintf/vsprintf.h218
-rw-r--r--src/pal/tests/palsuite/c_runtime/vswprintf/CMakeLists.txt22
-rw-r--r--src/pal/tests/palsuite/c_runtime/vswprintf/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/vswprintf/test1/test1.c41
-rw-r--r--src/pal/tests/palsuite/c_runtime/vswprintf/test1/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/vswprintf/test10/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/vswprintf/test10/test10.c48
-rw-r--r--src/pal/tests/palsuite/c_runtime/vswprintf/test10/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/vswprintf/test11/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/vswprintf/test11/test11.c48
-rw-r--r--src/pal/tests/palsuite/c_runtime/vswprintf/test11/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/vswprintf/test12/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/vswprintf/test12/test12.c48
-rw-r--r--src/pal/tests/palsuite/c_runtime/vswprintf/test12/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/vswprintf/test13/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/vswprintf/test13/test13.c48
-rw-r--r--src/pal/tests/palsuite/c_runtime/vswprintf/test13/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/vswprintf/test14/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/vswprintf/test14/test14.c61
-rw-r--r--src/pal/tests/palsuite/c_runtime/vswprintf/test14/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/vswprintf/test15/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/vswprintf/test15/test15.c62
-rw-r--r--src/pal/tests/palsuite/c_runtime/vswprintf/test15/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/vswprintf/test16/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/vswprintf/test16/test16.c61
-rw-r--r--src/pal/tests/palsuite/c_runtime/vswprintf/test16/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/vswprintf/test17/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/vswprintf/test17/test17.c63
-rw-r--r--src/pal/tests/palsuite/c_runtime/vswprintf/test17/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/vswprintf/test18/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/vswprintf/test18/test18.c63
-rw-r--r--src/pal/tests/palsuite/c_runtime/vswprintf/test18/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/vswprintf/test19/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/vswprintf/test19/test19.c137
-rw-r--r--src/pal/tests/palsuite/c_runtime/vswprintf/test19/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/vswprintf/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/vswprintf/test2/test2.c40
-rw-r--r--src/pal/tests/palsuite/c_runtime/vswprintf/test2/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/vswprintf/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/vswprintf/test3/test3.c40
-rw-r--r--src/pal/tests/palsuite/c_runtime/vswprintf/test3/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/vswprintf/test4/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/vswprintf/test4/test4.c118
-rw-r--r--src/pal/tests/palsuite/c_runtime/vswprintf/test4/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/vswprintf/test5/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/vswprintf/test5/test5.c79
-rw-r--r--src/pal/tests/palsuite/c_runtime/vswprintf/test5/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/vswprintf/test6/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/vswprintf/test6/test6.c41
-rw-r--r--src/pal/tests/palsuite/c_runtime/vswprintf/test6/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/vswprintf/test7/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/vswprintf/test7/test7.c41
-rw-r--r--src/pal/tests/palsuite/c_runtime/vswprintf/test7/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/vswprintf/test8/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/vswprintf/test8/test8.c47
-rw-r--r--src/pal/tests/palsuite/c_runtime/vswprintf/test8/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/vswprintf/test9/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/vswprintf/test9/test9.c47
-rw-r--r--src/pal/tests/palsuite/c_runtime/vswprintf/test9/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/vswprintf/vswprintf.h132
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcscat/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcscat/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcscat/test1/test1.c71
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcscat/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcschr/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcschr/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcschr/test1/test1.c51
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcschr/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcscmp/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcscmp/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcscmp/test1/test1.c57
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcscmp/test1/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcscpy/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcscpy/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcscpy/test1/test1.c47
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcscpy/test1/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcslen/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcslen/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcslen/test1/test1.c49
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcslen/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcsncat/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcsncat/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcsncat/test1/test1.c77
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcsncat/test1/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcsncmp/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcsncmp/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcsncmp/test1/test1.c73
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcsncmp/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcsncpy/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcsncpy/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcsncpy/test1/test1.c84
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcsncpy/test1/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcspbrk/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcspbrk/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcspbrk/test1/test1.c61
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcspbrk/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcsrchr/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcsrchr/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcsrchr/test1/test1.c50
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcsrchr/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcsstr/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcsstr/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcsstr/test1/test1.c62
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcsstr/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcstod/CMakeLists.txt5
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcstod/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcstod/test1/test1.c79
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcstod/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcstod/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcstod/test2/test2.c59
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcstod/test2/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcstok/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcstok/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcstok/test1/test1.c114
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcstok/test1/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcstol/CMakeLists.txt9
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcstol/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcstol/test1/test1.c53
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcstol/test1/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcstol/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcstol/test2/test2.c53
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcstol/test2/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcstol/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcstol/test3/test3.c52
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcstol/test3/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcstol/test4/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcstol/test4/test4.c77
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcstol/test4/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcstol/test5/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcstol/test5/test5.c76
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcstol/test5/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcstol/test6/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcstol/test6/test6.c86
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcstol/test6/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcstoul/CMakeLists.txt9
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcstoul/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcstoul/test1/test1.c49
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcstoul/test1/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcstoul/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcstoul/test2/test2.c49
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcstoul/test2/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcstoul/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcstoul/test3/test3.c49
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcstoul/test3/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcstoul/test4/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcstoul/test4/test4.c52
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcstoul/test4/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcstoul/test5/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcstoul/test5/test5.c69
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcstoul/test5/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcstoul/test6/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcstoul/test6/test6.c83
-rw-r--r--src/pal/tests/palsuite/c_runtime/wcstoul/test6/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/wprintf/CMakeLists.txt5
-rw-r--r--src/pal/tests/palsuite/c_runtime/wprintf/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/wprintf/test1/test1.c47
-rw-r--r--src/pal/tests/palsuite/c_runtime/wprintf/test1/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/wprintf/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/c_runtime/wprintf/test2/test2.c45
-rw-r--r--src/pal/tests/palsuite/c_runtime/wprintf/test2/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/c_runtime/wprintf/wprintf.h171
-rw-r--r--src/pal/tests/palsuite/common/ResultBuffer.cpp69
-rw-r--r--src/pal/tests/palsuite/common/ResultBuffer.h43
-rw-r--r--src/pal/tests/palsuite/common/ResultTime.h103
-rw-r--r--src/pal/tests/palsuite/common/pal_stdclib.h24
-rw-r--r--src/pal/tests/palsuite/common/palsuite.h182
-rw-r--r--src/pal/tests/palsuite/composite/CMakeLists.txt7
-rw-r--r--src/pal/tests/palsuite/composite/object_management/CMakeLists.txt6
-rw-r--r--src/pal/tests/palsuite/composite/object_management/event/CMakeLists.txt5
-rw-r--r--src/pal/tests/palsuite/composite/object_management/event/nonshared/CMakeLists.txt21
-rw-r--r--src/pal/tests/palsuite/composite/object_management/event/nonshared/event.c358
-rw-r--r--src/pal/tests/palsuite/composite/object_management/event/nonshared/main.c228
-rw-r--r--src/pal/tests/palsuite/composite/object_management/event/shared/CMakeLists.txt21
-rw-r--r--src/pal/tests/palsuite/composite/object_management/event/shared/event.c373
-rw-r--r--src/pal/tests/palsuite/composite/object_management/event/shared/main.c265
-rw-r--r--src/pal/tests/palsuite/composite/object_management/mutex/CMakeLists.txt5
-rw-r--r--src/pal/tests/palsuite/composite/object_management/mutex/nonshared/CMakeLists.txt21
-rw-r--r--src/pal/tests/palsuite/composite/object_management/mutex/nonshared/main.c230
-rw-r--r--src/pal/tests/palsuite/composite/object_management/mutex/nonshared/mutex.c340
-rw-r--r--src/pal/tests/palsuite/composite/object_management/mutex/shared/CMakeLists.txt21
-rw-r--r--src/pal/tests/palsuite/composite/object_management/mutex/shared/main.c265
-rw-r--r--src/pal/tests/palsuite/composite/object_management/mutex/shared/mutex.c354
-rw-r--r--src/pal/tests/palsuite/composite/object_management/readme.txt29
-rw-r--r--src/pal/tests/palsuite/composite/object_management/semaphore/CMakeLists.txt5
-rw-r--r--src/pal/tests/palsuite/composite/object_management/semaphore/nonshared/CMakeLists.txt21
-rw-r--r--src/pal/tests/palsuite/composite/object_management/semaphore/nonshared/main.c228
-rw-r--r--src/pal/tests/palsuite/composite/object_management/semaphore/nonshared/semaphore.c342
-rw-r--r--src/pal/tests/palsuite/composite/object_management/semaphore/shared/CMakeLists.txt21
-rw-r--r--src/pal/tests/palsuite/composite/object_management/semaphore/shared/main.c278
-rw-r--r--src/pal/tests/palsuite/composite/object_management/semaphore/shared/semaphore.c351
-rw-r--r--src/pal/tests/palsuite/composite/synchronization/CMakeLists.txt6
-rw-r--r--src/pal/tests/palsuite/composite/synchronization/criticalsection/CMakeLists.txt20
-rw-r--r--src/pal/tests/palsuite/composite/synchronization/criticalsection/criticalsection.c418
-rw-r--r--src/pal/tests/palsuite/composite/synchronization/criticalsection/mainWrapper.c255
-rw-r--r--src/pal/tests/palsuite/composite/synchronization/criticalsection/readme.txt11
-rw-r--r--src/pal/tests/palsuite/composite/synchronization/nativecriticalsection/CMakeLists.txt21
-rw-r--r--src/pal/tests/palsuite/composite/synchronization/nativecriticalsection/mtx_critsect.cpp111
-rw-r--r--src/pal/tests/palsuite/composite/synchronization/nativecriticalsection/mtx_critsect.h51
-rw-r--r--src/pal/tests/palsuite/composite/synchronization/nativecriticalsection/pal_composite_native_cs.c471
-rw-r--r--src/pal/tests/palsuite/composite/synchronization/nativecriticalsection/readme.txt19
-rw-r--r--src/pal/tests/palsuite/composite/synchronization/nativecriticalsection/resultbuffer.cpp69
-rw-r--r--src/pal/tests/palsuite/composite/synchronization/nativecriticalsection/resultbuffer.h43
-rw-r--r--src/pal/tests/palsuite/composite/synchronization/nativecs_interlocked/CMakeLists.txt22
-rw-r--r--src/pal/tests/palsuite/composite/synchronization/nativecs_interlocked/hpitinterlock.s168
-rw-r--r--src/pal/tests/palsuite/composite/synchronization/nativecs_interlocked/interlocked.cpp27
-rw-r--r--src/pal/tests/palsuite/composite/synchronization/nativecs_interlocked/makefile70
-rw-r--r--src/pal/tests/palsuite/composite/synchronization/nativecs_interlocked/mtx_critsect.cpp112
-rw-r--r--src/pal/tests/palsuite/composite/synchronization/nativecs_interlocked/mtx_critsect.h67
-rw-r--r--src/pal/tests/palsuite/composite/synchronization/nativecs_interlocked/notes.txt15
-rw-r--r--src/pal/tests/palsuite/composite/synchronization/nativecs_interlocked/pal_composite_native_cs.c475
-rw-r--r--src/pal/tests/palsuite/composite/synchronization/nativecs_interlocked/readme.txt39
-rw-r--r--src/pal/tests/palsuite/composite/synchronization/nativecs_interlocked/resultbuffer.cpp69
-rw-r--r--src/pal/tests/palsuite/composite/synchronization/nativecs_interlocked/resultbuffer.h43
-rw-r--r--src/pal/tests/palsuite/composite/synchronization/nativecs_interlocked/sparcinterloc.s73
-rw-r--r--src/pal/tests/palsuite/composite/threading/CMakeLists.txt5
-rw-r--r--src/pal/tests/palsuite/composite/threading/threadsuspension/CMakeLists.txt20
-rw-r--r--src/pal/tests/palsuite/composite/threading/threadsuspension/mainWrapper.c274
-rw-r--r--src/pal/tests/palsuite/composite/threading/threadsuspension/readme.txt11
-rw-r--r--src/pal/tests/palsuite/composite/threading/threadsuspension/samplefile.dat5124
-rw-r--r--src/pal/tests/palsuite/composite/threading/threadsuspension/threadsuspension.c907
-rw-r--r--src/pal/tests/palsuite/composite/threading/threadsuspension_switchthread/CMakeLists.txt20
-rw-r--r--src/pal/tests/palsuite/composite/threading/threadsuspension_switchthread/mainWrapper.c274
-rw-r--r--src/pal/tests/palsuite/composite/threading/threadsuspension_switchthread/readme.txt11
-rw-r--r--src/pal/tests/palsuite/composite/threading/threadsuspension_switchthread/samplefile.dat5124
-rw-r--r--src/pal/tests/palsuite/composite/threading/threadsuspension_switchthread/threadsuspension.c914
-rw-r--r--src/pal/tests/palsuite/composite/wfmo/CMakeLists.txt21
-rw-r--r--src/pal/tests/palsuite/composite/wfmo/main.c239
-rw-r--r--src/pal/tests/palsuite/composite/wfmo/mutex.c365
-rw-r--r--src/pal/tests/palsuite/composite/wfmo/readme.txt22
-rw-r--r--src/pal/tests/palsuite/debug_api/CMakeLists.txt9
-rw-r--r--src/pal/tests/palsuite/debug_api/DebugBreak/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/debug_api/DebugBreak/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/debug_api/DebugBreak/test1/test1.c47
-rw-r--r--src/pal/tests/palsuite/debug_api/DebugBreak/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/debug_api/OutputDebugStringA/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/debug_api/OutputDebugStringA/test1/CMakeLists.txt38
-rw-r--r--src/pal/tests/palsuite/debug_api/OutputDebugStringA/test1/helper.c35
-rw-r--r--src/pal/tests/palsuite/debug_api/OutputDebugStringA/test1/test1.c94
-rw-r--r--src/pal/tests/palsuite/debug_api/OutputDebugStringA/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/debug_api/OutputDebugStringW/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/debug_api/OutputDebugStringW/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/debug_api/OutputDebugStringW/test1/test1.c41
-rw-r--r--src/pal/tests/palsuite/debug_api/OutputDebugStringW/test1/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/debug_api/WriteProcessMemory/CMakeLists.txt6
-rw-r--r--src/pal/tests/palsuite/debug_api/WriteProcessMemory/test1/CMakeLists.txt36
-rw-r--r--src/pal/tests/palsuite/debug_api/WriteProcessMemory/test1/commonconsts.h46
-rw-r--r--src/pal/tests/palsuite/debug_api/WriteProcessMemory/test1/helper.c243
-rw-r--r--src/pal/tests/palsuite/debug_api/WriteProcessMemory/test1/test1.c189
-rw-r--r--src/pal/tests/palsuite/debug_api/WriteProcessMemory/test1/testinfo.dat16
-rw-r--r--src/pal/tests/palsuite/debug_api/WriteProcessMemory/test3/CMakeLists.txt36
-rw-r--r--src/pal/tests/palsuite/debug_api/WriteProcessMemory/test3/commonconsts.h50
-rw-r--r--src/pal/tests/palsuite/debug_api/WriteProcessMemory/test3/helper.c256
-rw-r--r--src/pal/tests/palsuite/debug_api/WriteProcessMemory/test3/test3.c205
-rw-r--r--src/pal/tests/palsuite/debug_api/WriteProcessMemory/test3/testinfo.dat17
-rw-r--r--src/pal/tests/palsuite/debug_api/WriteProcessMemory/test4/CMakeLists.txt36
-rw-r--r--src/pal/tests/palsuite/debug_api/WriteProcessMemory/test4/helper.c67
-rw-r--r--src/pal/tests/palsuite/debug_api/WriteProcessMemory/test4/test4.c124
-rw-r--r--src/pal/tests/palsuite/debug_api/WriteProcessMemory/test4/testinfo.dat17
-rw-r--r--src/pal/tests/palsuite/exception_handling/CMakeLists.txt13
-rw-r--r--src/pal/tests/palsuite/exception_handling/PAL_EXCEPT_FILTER/CMakeLists.txt6
-rw-r--r--src/pal/tests/palsuite/exception_handling/PAL_EXCEPT_FILTER/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/exception_handling/PAL_EXCEPT_FILTER/test1/PAL_EXCEPT_FILTER.c118
-rw-r--r--src/pal/tests/palsuite/exception_handling/PAL_EXCEPT_FILTER/test1/testinfo.dat16
-rw-r--r--src/pal/tests/palsuite/exception_handling/PAL_EXCEPT_FILTER/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/exception_handling/PAL_EXCEPT_FILTER/test2/pal_except_filter.c154
-rw-r--r--src/pal/tests/palsuite/exception_handling/PAL_EXCEPT_FILTER/test2/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/exception_handling/PAL_EXCEPT_FILTER/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/exception_handling/PAL_EXCEPT_FILTER/test3/pal_except_filter.c206
-rw-r--r--src/pal/tests/palsuite/exception_handling/PAL_EXCEPT_FILTER/test3/testinfo.dat19
-rw-r--r--src/pal/tests/palsuite/exception_handling/PAL_EXCEPT_FILTER_EX/CMakeLists.txt6
-rw-r--r--src/pal/tests/palsuite/exception_handling/PAL_EXCEPT_FILTER_EX/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/exception_handling/PAL_EXCEPT_FILTER_EX/test1/PAL_EXCEPT_FILTER_EX.c197
-rw-r--r--src/pal/tests/palsuite/exception_handling/PAL_EXCEPT_FILTER_EX/test1/testinfo.dat18
-rw-r--r--src/pal/tests/palsuite/exception_handling/PAL_EXCEPT_FILTER_EX/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/exception_handling/PAL_EXCEPT_FILTER_EX/test2/pal_except_filter_ex.c142
-rw-r--r--src/pal/tests/palsuite/exception_handling/PAL_EXCEPT_FILTER_EX/test2/testinfo.dat17
-rw-r--r--src/pal/tests/palsuite/exception_handling/PAL_EXCEPT_FILTER_EX/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/exception_handling/PAL_EXCEPT_FILTER_EX/test3/pal_except_filter.c208
-rw-r--r--src/pal/tests/palsuite/exception_handling/PAL_EXCEPT_FILTER_EX/test3/testinfo.dat18
-rw-r--r--src/pal/tests/palsuite/exception_handling/PAL_TRY_EXCEPT/CMakeLists.txt5
-rw-r--r--src/pal/tests/palsuite/exception_handling/PAL_TRY_EXCEPT/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/exception_handling/PAL_TRY_EXCEPT/test1/PAL_TRY_EXCEPT.c82
-rw-r--r--src/pal/tests/palsuite/exception_handling/PAL_TRY_EXCEPT/test1/testinfo.dat16
-rw-r--r--src/pal/tests/palsuite/exception_handling/PAL_TRY_EXCEPT/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/exception_handling/PAL_TRY_EXCEPT/test2/PAL_TRY_EXCEPT.c68
-rw-r--r--src/pal/tests/palsuite/exception_handling/PAL_TRY_EXCEPT/test2/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/exception_handling/PAL_TRY_EXCEPT_EX/CMakeLists.txt6
-rw-r--r--src/pal/tests/palsuite/exception_handling/PAL_TRY_EXCEPT_EX/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/exception_handling/PAL_TRY_EXCEPT_EX/test1/PAL_TRY_EXCEPT_EX.c133
-rw-r--r--src/pal/tests/palsuite/exception_handling/PAL_TRY_EXCEPT_EX/test1/testinfo.dat16
-rw-r--r--src/pal/tests/palsuite/exception_handling/PAL_TRY_EXCEPT_EX/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/exception_handling/PAL_TRY_EXCEPT_EX/test2/PAL_TRY_EXCEPT_EX.c123
-rw-r--r--src/pal/tests/palsuite/exception_handling/PAL_TRY_EXCEPT_EX/test2/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/exception_handling/PAL_TRY_EXCEPT_EX/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/exception_handling/PAL_TRY_EXCEPT_EX/test3/PAL_TRY_EXCEPT_EX.c130
-rw-r--r--src/pal/tests/palsuite/exception_handling/PAL_TRY_EXCEPT_EX/test3/testinfo.dat16
-rw-r--r--src/pal/tests/palsuite/exception_handling/PAL_TRY_LEAVE_FINALLY/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/exception_handling/PAL_TRY_LEAVE_FINALLY/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/exception_handling/PAL_TRY_LEAVE_FINALLY/test1/PAL_TRY_LEAVE_FINALLY.c77
-rw-r--r--src/pal/tests/palsuite/exception_handling/PAL_TRY_LEAVE_FINALLY/test1/testinfo.dat17
-rw-r--r--src/pal/tests/palsuite/exception_handling/RaiseException/CMakeLists.txt6
-rw-r--r--src/pal/tests/palsuite/exception_handling/RaiseException/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/exception_handling/RaiseException/test1/test1.cpp130
-rw-r--r--src/pal/tests/palsuite/exception_handling/RaiseException/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/exception_handling/RaiseException/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/exception_handling/RaiseException/test2/test2.cpp224
-rw-r--r--src/pal/tests/palsuite/exception_handling/RaiseException/test2/testinfo.dat28
-rw-r--r--src/pal/tests/palsuite/exception_handling/RaiseException/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/exception_handling/RaiseException/test3/test.cpp115
-rw-r--r--src/pal/tests/palsuite/exception_handling/RaiseException/test3/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/exception_handling/SetUnhandledExceptionFilter/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/exception_handling/SetUnhandledExceptionFilter/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/exception_handling/SetUnhandledExceptionFilter/test1/test1.c82
-rw-r--r--src/pal/tests/palsuite/exception_handling/SetUnhandledExceptionFilter/test1/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/exception_handling/pal_except/CMakeLists.txt10
-rw-r--r--src/pal/tests/palsuite/exception_handling/pal_except/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/exception_handling/pal_except/test1/test1.c67
-rw-r--r--src/pal/tests/palsuite/exception_handling/pal_except/test1/testinfo.dat23
-rw-r--r--src/pal/tests/palsuite/exception_handling/pal_except/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/exception_handling/pal_except/test2/test2.c111
-rw-r--r--src/pal/tests/palsuite/exception_handling/pal_except/test2/testinfo.dat25
-rw-r--r--src/pal/tests/palsuite/exception_handling/pal_except/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/exception_handling/pal_except/test3/test3.c120
-rw-r--r--src/pal/tests/palsuite/exception_handling/pal_except/test3/testinfo.dat27
-rw-r--r--src/pal/tests/palsuite/exception_handling/pal_except/test4/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/exception_handling/pal_except/test4/test4.c105
-rw-r--r--src/pal/tests/palsuite/exception_handling/pal_except/test4/testinfo.dat27
-rw-r--r--src/pal/tests/palsuite/exception_handling/pal_except/test5/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/exception_handling/pal_except/test5/test5.c112
-rw-r--r--src/pal/tests/palsuite/exception_handling/pal_except/test5/testinfo.dat27
-rw-r--r--src/pal/tests/palsuite/exception_handling/pal_except/test6/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/exception_handling/pal_except/test6/test6.c160
-rw-r--r--src/pal/tests/palsuite/exception_handling/pal_except/test6/testinfo.dat25
-rw-r--r--src/pal/tests/palsuite/exception_handling/pal_except/test7/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/exception_handling/pal_except/test7/test7.c67
-rw-r--r--src/pal/tests/palsuite/exception_handling/pal_except/test7/testinfo.dat24
-rw-r--r--src/pal/tests/palsuite/exception_handling/pal_finally/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/exception_handling/pal_finally/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/exception_handling/pal_finally/test1/pal_finally.c302
-rw-r--r--src/pal/tests/palsuite/exception_handling/pal_finally/test1/testinfo.dat19
-rw-r--r--src/pal/tests/palsuite/exception_handling/pal_sxs/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/exception_handling/pal_sxs/test1/CMakeLists.txt97
-rw-r--r--src/pal/tests/palsuite/exception_handling/pal_sxs/test1/dlltest1.cpp75
-rw-r--r--src/pal/tests/palsuite/exception_handling/pal_sxs/test1/dlltest1.src3
-rw-r--r--src/pal/tests/palsuite/exception_handling/pal_sxs/test1/dlltest2.cpp75
-rw-r--r--src/pal/tests/palsuite/exception_handling/pal_sxs/test1/dlltest2.src3
-rw-r--r--src/pal/tests/palsuite/exception_handling/pal_sxs/test1/exceptionsxs.cpp117
-rw-r--r--src/pal/tests/palsuite/exception_handling/pal_sxs/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/file_io/AreFileApisANSI/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/file_io/AreFileApisANSI/test1/AreFileApisANSI.c40
-rw-r--r--src/pal/tests/palsuite/file_io/AreFileApisANSI/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/AreFileApisANSI/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/file_io/CMakeLists.txt61
-rw-r--r--src/pal/tests/palsuite/file_io/CompareFileTime/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/file_io/CompareFileTime/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/CompareFileTime/test1/CompareFileTime.c68
-rw-r--r--src/pal/tests/palsuite/file_io/CompareFileTime/test1/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/file_io/CopyFileA/CMakeLists.txt7
-rw-r--r--src/pal/tests/palsuite/file_io/CopyFileA/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/CopyFileA/test1/CopyFileA.c159
-rw-r--r--src/pal/tests/palsuite/file_io/CopyFileA/test1/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/file_io/CopyFileA/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/CopyFileA/test2/test2.c120
-rw-r--r--src/pal/tests/palsuite/file_io/CopyFileA/test2/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/file_io/CopyFileA/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/CopyFileA/test3/test3.c141
-rw-r--r--src/pal/tests/palsuite/file_io/CopyFileA/test3/testinfo.dat16
-rw-r--r--src/pal/tests/palsuite/file_io/CopyFileA/test4/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/CopyFileA/test4/test4.c180
-rw-r--r--src/pal/tests/palsuite/file_io/CopyFileA/test4/testinfo.dat16
-rw-r--r--src/pal/tests/palsuite/file_io/CopyFileW/CMakeLists.txt6
-rw-r--r--src/pal/tests/palsuite/file_io/CopyFileW/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/CopyFileW/test1/CopyFileW.c155
-rw-r--r--src/pal/tests/palsuite/file_io/CopyFileW/test1/ExpectedResults.txt1
-rw-r--r--src/pal/tests/palsuite/file_io/CopyFileW/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/file_io/CopyFileW/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/CopyFileW/test2/test2.c124
-rw-r--r--src/pal/tests/palsuite/file_io/CopyFileW/test2/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/file_io/CopyFileW/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/CopyFileW/test3/test3.c196
-rw-r--r--src/pal/tests/palsuite/file_io/CopyFileW/test3/testinfo.dat16
-rw-r--r--src/pal/tests/palsuite/file_io/CreateDirectoryA/CMakeLists.txt5
-rw-r--r--src/pal/tests/palsuite/file_io/CreateDirectoryA/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/CreateDirectoryA/test1/CreateDirectoryA.c296
-rw-r--r--src/pal/tests/palsuite/file_io/CreateDirectoryA/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/file_io/CreateDirectoryA/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/CreateDirectoryA/test2/createdirectorya.c335
-rw-r--r--src/pal/tests/palsuite/file_io/CreateDirectoryA/test2/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/file_io/CreateDirectoryW/CMakeLists.txt5
-rw-r--r--src/pal/tests/palsuite/file_io/CreateDirectoryW/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/CreateDirectoryW/test1/CreateDirectoryW.c347
-rw-r--r--src/pal/tests/palsuite/file_io/CreateDirectoryW/test1/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/file_io/CreateDirectoryW/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/CreateDirectoryW/test2/createdirectoryw.c345
-rw-r--r--src/pal/tests/palsuite/file_io/CreateDirectoryW/test2/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/file_io/CreateFileA/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/file_io/CreateFileA/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/CreateFileA/test1/CreateFileA.c145
-rw-r--r--src/pal/tests/palsuite/file_io/CreateFileA/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/file_io/CreateFileA/test1/winoutput1
-rw-r--r--src/pal/tests/palsuite/file_io/CreateFileW/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/file_io/CreateFileW/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/CreateFileW/test1/CreateFileW.c152
-rw-r--r--src/pal/tests/palsuite/file_io/CreateFileW/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/file_io/CreateFileW/test1/winoutput1
-rw-r--r--src/pal/tests/palsuite/file_io/DeleteFileA/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/file_io/DeleteFileA/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/DeleteFileA/test1/DeleteFileA.cpp182
-rw-r--r--src/pal/tests/palsuite/file_io/DeleteFileA/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/file_io/DeleteFileW/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/file_io/DeleteFileW/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/DeleteFileW/test1/DeleteFileW.c164
-rw-r--r--src/pal/tests/palsuite/file_io/DeleteFileW/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/file_io/FILECanonicalizePath/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/FILECanonicalizePath/FILECanonicalizePath.c83
-rw-r--r--src/pal/tests/palsuite/file_io/FILECanonicalizePath/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/file_io/FileTimeToDosDateTime/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/file_io/FileTimeToDosDateTime/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/FileTimeToDosDateTime/test1/test1.c116
-rw-r--r--src/pal/tests/palsuite/file_io/FileTimeToDosDateTime/test1/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/file_io/FindClose/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/file_io/FindClose/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/FindClose/test1/FindClose.c275
-rw-r--r--src/pal/tests/palsuite/file_io/FindClose/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/file_io/FindFirstFileA/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/file_io/FindFirstFileA/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/FindFirstFileA/test1/FindFirstFileA.c206
-rw-r--r--src/pal/tests/palsuite/file_io/FindFirstFileA/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/file_io/FindFirstFileW/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/file_io/FindFirstFileW/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/FindFirstFileW/test1/FindFirstFileW.c212
-rw-r--r--src/pal/tests/palsuite/file_io/FindFirstFileW/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/file_io/FindNextFileA/CMakeLists.txt5
-rw-r--r--src/pal/tests/palsuite/file_io/FindNextFileA/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/FindNextFileA/test1/FindNextFileA.c243
-rw-r--r--src/pal/tests/palsuite/file_io/FindNextFileA/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/file_io/FindNextFileA/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/FindNextFileA/test2/findnextfilea.c107
-rw-r--r--src/pal/tests/palsuite/file_io/FindNextFileA/test2/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/file_io/FindNextFileW/CMakeLists.txt5
-rw-r--r--src/pal/tests/palsuite/file_io/FindNextFileW/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/FindNextFileW/test1/FindNextFileW.c249
-rw-r--r--src/pal/tests/palsuite/file_io/FindNextFileW/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/file_io/FindNextFileW/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/FindNextFileW/test2/findnextfilew.c107
-rw-r--r--src/pal/tests/palsuite/file_io/FindNextFileW/test2/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/file_io/FlushFileBuffers/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/file_io/FlushFileBuffers/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/FlushFileBuffers/test1/FlushFileBuffers.c130
-rw-r--r--src/pal/tests/palsuite/file_io/FlushFileBuffers/test1/testinfo.dat17
-rw-r--r--src/pal/tests/palsuite/file_io/GetConsoleCP/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/file_io/GetConsoleCP/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/GetConsoleCP/test1/GetConsoleCP.c35
-rw-r--r--src/pal/tests/palsuite/file_io/GetConsoleCP/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/file_io/GetConsoleOutputCP/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/file_io/GetConsoleOutputCP/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/GetConsoleOutputCP/test1/GetConsoleOutputCP.c35
-rw-r--r--src/pal/tests/palsuite/file_io/GetConsoleOutputCP/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/file_io/GetCurrentDirectoryA/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/file_io/GetCurrentDirectoryA/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/GetCurrentDirectoryA/test1/GetCurrentDirectoryA.c97
-rw-r--r--src/pal/tests/palsuite/file_io/GetCurrentDirectoryA/test1/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/file_io/GetCurrentDirectoryW/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/file_io/GetCurrentDirectoryW/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/GetCurrentDirectoryW/test1/GetCurrentDirectoryW.c106
-rw-r--r--src/pal/tests/palsuite/file_io/GetCurrentDirectoryW/test1/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/file_io/GetDiskFreeSpaceW/CMakeLists.txt5
-rw-r--r--src/pal/tests/palsuite/file_io/GetDiskFreeSpaceW/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/GetDiskFreeSpaceW/test1/GetDiskFreeSpaceW.c94
-rw-r--r--src/pal/tests/palsuite/file_io/GetDiskFreeSpaceW/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/file_io/GetDiskFreeSpaceW/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/GetDiskFreeSpaceW/test2/getdiskfreespacew.c65
-rw-r--r--src/pal/tests/palsuite/file_io/GetDiskFreeSpaceW/test2/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileAttributesA/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileAttributesA/test1/.hidden_directory/CMakeLists.txt2
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileAttributesA/test1/.hidden_directory/keepme1
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileAttributesA/test1/.hidden_file1
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileAttributesA/test1/.hidden_ro_directory/CMakeLists.txt2
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileAttributesA/test1/.hidden_ro_directory/keepme1
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileAttributesA/test1/.hidden_ro_file1
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileAttributesA/test1/CMakeLists.txt26
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileAttributesA/test1/GetFileAttributesA.c340
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileAttributesA/test1/no_directory/CMakeLists.txt2
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileAttributesA/test1/no_directory/keepme1
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileAttributesA/test1/no_file1
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileAttributesA/test1/normal_test_directory/CMakeLists.txt2
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileAttributesA/test1/normal_test_directory/keepme1
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileAttributesA/test1/normal_test_file6
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileAttributesA/test1/ro_test_directory/CMakeLists.txt2
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileAttributesA/test1/ro_test_directory/keepme1
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileAttributesA/test1/ro_test_file6
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileAttributesA/test1/rw_directory/CMakeLists.txt2
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileAttributesA/test1/rw_directory/keepme1
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileAttributesA/test1/rw_file1
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileAttributesA/test1/testinfo.dat20
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileAttributesExW/CMakeLists.txt5
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileAttributesExW/test1/.hidden_directory/CMakeLists.txt2
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileAttributesExW/test1/.hidden_directory/anchor.txt2
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileAttributesExW/test1/.hidden_file1
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileAttributesExW/test1/CMakeLists.txt23
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileAttributesExW/test1/normal_test_directory/CMakeLists.txt2
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileAttributesExW/test1/normal_test_directory/keepme1
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileAttributesExW/test1/normal_test_file6
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileAttributesExW/test1/ro_test_directory/CMakeLists.txt2
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileAttributesExW/test1/ro_test_directory/keepme1
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileAttributesExW/test1/ro_test_file6
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileAttributesExW/test1/test1.c227
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileAttributesExW/test1/testinfo.dat16
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileAttributesExW/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileAttributesExW/test2/test2.c170
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileAttributesExW/test2/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileAttributesW/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileAttributesW/test1/.hidden_directory/CMakeLists.txt2
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileAttributesW/test1/.hidden_directory/keepme1
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileAttributesW/test1/.hidden_file1
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileAttributesW/test1/.hidden_ro_directory/CMakeLists.txt2
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileAttributesW/test1/.hidden_ro_directory/keepme1
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileAttributesW/test1/.hidden_ro_file1
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileAttributesW/test1/CMakeLists.txt26
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileAttributesW/test1/GetFileAttributesW.c345
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileAttributesW/test1/no_directory/CMakeLists.txt2
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileAttributesW/test1/no_directory/keepme1
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileAttributesW/test1/no_file1
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileAttributesW/test1/normal_test_directory/CMakeLists.txt2
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileAttributesW/test1/normal_test_directory/keepme1
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileAttributesW/test1/normal_test_file6
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileAttributesW/test1/ro_test_directory/CMakeLists.txt2
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileAttributesW/test1/ro_test_directory/keepme1
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileAttributesW/test1/ro_test_file6
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileAttributesW/test1/rw_file1
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileAttributesW/test1/rw_test_directory/CMakeLists.txt2
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileAttributesW/test1/rw_test_directory/keepme1
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileAttributesW/test1/testinfo.dat20
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileSize/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileSize/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileSize/test1/GetFileSize.c173
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileSize/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileSizeEx/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileSizeEx/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileSizeEx/test1/GetFileSizeEx.c173
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileSizeEx/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileTime/CMakeLists.txt10
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileTime/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileTime/test1/GetFileTime.c180
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileTime/test1/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileTime/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileTime/test2/GetFileTime.c195
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileTime/test2/testinfo.dat16
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileTime/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileTime/test3/GetFileTime.c142
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileTime/test3/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileTime/test4/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileTime/test4/GetFileTime.c98
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileTime/test4/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileTime/test5/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileTime/test5/getfiletime.c224
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileTime/test5/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileTime/test6/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileTime/test6/getfiletime.c281
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileTime/test6/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileTime/test7/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileTime/test7/getfiletime.c279
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileTime/test7/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileType/CMakeLists.txt6
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileType/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileType/test1/GetFileType.c76
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileType/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileType/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileType/test2/getfiletype.c95
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileType/test2/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileType/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileType/test3/getfiletype.c72
-rw-r--r--src/pal/tests/palsuite/file_io/GetFileType/test3/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/file_io/GetFullPathNameA/CMakeLists.txt7
-rw-r--r--src/pal/tests/palsuite/file_io/GetFullPathNameA/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/GetFullPathNameA/test1/GetFullPathNameA.c122
-rw-r--r--src/pal/tests/palsuite/file_io/GetFullPathNameA/test1/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/file_io/GetFullPathNameA/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/GetFullPathNameA/test2/test2.c143
-rw-r--r--src/pal/tests/palsuite/file_io/GetFullPathNameA/test2/testinfo.dat18
-rw-r--r--src/pal/tests/palsuite/file_io/GetFullPathNameA/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/GetFullPathNameA/test3/test3.c241
-rw-r--r--src/pal/tests/palsuite/file_io/GetFullPathNameA/test3/testinfo.dat19
-rw-r--r--src/pal/tests/palsuite/file_io/GetFullPathNameA/test4/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/GetFullPathNameA/test4/test4.c203
-rw-r--r--src/pal/tests/palsuite/file_io/GetFullPathNameA/test4/testinfo.dat19
-rw-r--r--src/pal/tests/palsuite/file_io/GetFullPathNameW/CMakeLists.txt7
-rw-r--r--src/pal/tests/palsuite/file_io/GetFullPathNameW/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/GetFullPathNameW/test1/GetFullPathNameW.c157
-rw-r--r--src/pal/tests/palsuite/file_io/GetFullPathNameW/test1/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/file_io/GetFullPathNameW/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/GetFullPathNameW/test2/test2.c159
-rw-r--r--src/pal/tests/palsuite/file_io/GetFullPathNameW/test2/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/file_io/GetFullPathNameW/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/GetFullPathNameW/test3/test3.c240
-rw-r--r--src/pal/tests/palsuite/file_io/GetFullPathNameW/test3/testinfo.dat19
-rw-r--r--src/pal/tests/palsuite/file_io/GetFullPathNameW/test4/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/GetFullPathNameW/test4/test4.c201
-rw-r--r--src/pal/tests/palsuite/file_io/GetFullPathNameW/test4/testinfo.dat19
-rw-r--r--src/pal/tests/palsuite/file_io/GetLongPathNameW/CMakeLists.txt5
-rw-r--r--src/pal/tests/palsuite/file_io/GetLongPathNameW/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/GetLongPathNameW/test1/GetLongPathNameW.c280
-rw-r--r--src/pal/tests/palsuite/file_io/GetLongPathNameW/test1/testinfo.dat16
-rw-r--r--src/pal/tests/palsuite/file_io/GetLongPathNameW/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/GetLongPathNameW/test2/getlongpathnamew.c266
-rw-r--r--src/pal/tests/palsuite/file_io/GetLongPathNameW/test2/testinfo.dat16
-rw-r--r--src/pal/tests/palsuite/file_io/GetStdHandle/CMakeLists.txt5
-rw-r--r--src/pal/tests/palsuite/file_io/GetStdHandle/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/GetStdHandle/test1/GetStdHandle.c132
-rw-r--r--src/pal/tests/palsuite/file_io/GetStdHandle/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/file_io/GetStdHandle/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/GetStdHandle/test2/GetStdHandle.c79
-rw-r--r--src/pal/tests/palsuite/file_io/GetStdHandle/test2/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/file_io/GetSystemTime/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/file_io/GetSystemTime/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/GetSystemTime/test1/test.c124
-rw-r--r--src/pal/tests/palsuite/file_io/GetSystemTime/test1/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/file_io/GetSystemTimeAsFileTime/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/file_io/GetSystemTimeAsFileTime/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/GetSystemTimeAsFileTime/test1/GetSystemTimeAsFileTime.c86
-rw-r--r--src/pal/tests/palsuite/file_io/GetSystemTimeAsFileTime/test1/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/file_io/GetTempFileNameA/CMakeLists.txt6
-rw-r--r--src/pal/tests/palsuite/file_io/GetTempFileNameA/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/GetTempFileNameA/test1/GetTempFileNameA.c125
-rw-r--r--src/pal/tests/palsuite/file_io/GetTempFileNameA/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/file_io/GetTempFileNameA/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/GetTempFileNameA/test2/GetTempFileNameA.c80
-rw-r--r--src/pal/tests/palsuite/file_io/GetTempFileNameA/test2/testinfo.dat17
-rw-r--r--src/pal/tests/palsuite/file_io/GetTempFileNameA/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/GetTempFileNameA/test3/gettempfilenamea.c159
-rw-r--r--src/pal/tests/palsuite/file_io/GetTempFileNameA/test3/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/file_io/GetTempFileNameW/CMakeLists.txt6
-rw-r--r--src/pal/tests/palsuite/file_io/GetTempFileNameW/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/GetTempFileNameW/test1/GetTempFileNameW.c129
-rw-r--r--src/pal/tests/palsuite/file_io/GetTempFileNameW/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/file_io/GetTempFileNameW/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/GetTempFileNameW/test2/GetTempFileNameW.c84
-rw-r--r--src/pal/tests/palsuite/file_io/GetTempFileNameW/test2/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/file_io/GetTempFileNameW/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/GetTempFileNameW/test3/gettempfilenamew.c161
-rw-r--r--src/pal/tests/palsuite/file_io/GetTempFileNameW/test3/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/file_io/GetTempPathW/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/file_io/GetTempPathW/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/GetTempPathW/test1/GetTempPathW.c103
-rw-r--r--src/pal/tests/palsuite/file_io/GetTempPathW/test1/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/file_io/MoveFileA/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/file_io/MoveFileA/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/MoveFileA/test1/ExpectedResults.txt1
-rw-r--r--src/pal/tests/palsuite/file_io/MoveFileA/test1/MoveFileA.c469
-rw-r--r--src/pal/tests/palsuite/file_io/MoveFileA/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/file_io/MoveFileExA/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/file_io/MoveFileExA/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/MoveFileExA/test1/ExpectedResults.txt1
-rw-r--r--src/pal/tests/palsuite/file_io/MoveFileExA/test1/MoveFileExA.c360
-rw-r--r--src/pal/tests/palsuite/file_io/MoveFileExA/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/file_io/MoveFileExW/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/file_io/MoveFileExW/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/MoveFileExW/test1/ExpectedResults.txt1
-rw-r--r--src/pal/tests/palsuite/file_io/MoveFileExW/test1/MoveFileExW.c431
-rw-r--r--src/pal/tests/palsuite/file_io/MoveFileExW/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/file_io/MoveFileW/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/file_io/MoveFileW/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/MoveFileW/test1/ExpectedResults.txt1
-rw-r--r--src/pal/tests/palsuite/file_io/MoveFileW/test1/MoveFileW.c478
-rw-r--r--src/pal/tests/palsuite/file_io/MoveFileW/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/file_io/ReadFile/CMakeLists.txt7
-rw-r--r--src/pal/tests/palsuite/file_io/ReadFile/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/ReadFile/test1/NonReadableFile.txt1
-rw-r--r--src/pal/tests/palsuite/file_io/ReadFile/test1/ReadFile.c82
-rw-r--r--src/pal/tests/palsuite/file_io/ReadFile/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/file_io/ReadFile/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/ReadFile/test2/ReadFile.c198
-rw-r--r--src/pal/tests/palsuite/file_io/ReadFile/test2/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/file_io/ReadFile/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/ReadFile/test3/ReadFile.c184
-rw-r--r--src/pal/tests/palsuite/file_io/ReadFile/test3/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/file_io/ReadFile/test4/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/ReadFile/test4/readfile.c147
-rw-r--r--src/pal/tests/palsuite/file_io/ReadFile/test4/testinfo.dat17
-rw-r--r--src/pal/tests/palsuite/file_io/RemoveDirectoryA/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/file_io/RemoveDirectoryA/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/RemoveDirectoryA/test1/RemoveDirectoryA.cpp315
-rw-r--r--src/pal/tests/palsuite/file_io/RemoveDirectoryA/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/file_io/RemoveDirectoryW/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/file_io/RemoveDirectoryW/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/RemoveDirectoryW/test1/RemoveDirectoryW.c282
-rw-r--r--src/pal/tests/palsuite/file_io/RemoveDirectoryW/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/file_io/SearchPathA/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/file_io/SearchPathA/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/SearchPathA/test1/SearchPathA.c144
-rw-r--r--src/pal/tests/palsuite/file_io/SearchPathA/test1/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/file_io/SearchPathW/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/file_io/SearchPathW/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/SearchPathW/test1/SearchPathW.c198
-rw-r--r--src/pal/tests/palsuite/file_io/SearchPathW/test1/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/file_io/SetCurrentDirectoryA/CMakeLists.txt6
-rw-r--r--src/pal/tests/palsuite/file_io/SetCurrentDirectoryA/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/SetCurrentDirectoryA/test1/SetCurrentDirectoryA.c215
-rw-r--r--src/pal/tests/palsuite/file_io/SetCurrentDirectoryA/test1/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/file_io/SetCurrentDirectoryA/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/SetCurrentDirectoryA/test2/setcurrentdirectorya.c142
-rw-r--r--src/pal/tests/palsuite/file_io/SetCurrentDirectoryA/test2/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/file_io/SetCurrentDirectoryA/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/SetCurrentDirectoryA/test3/setcurrentdirectorya.c56
-rw-r--r--src/pal/tests/palsuite/file_io/SetCurrentDirectoryA/test3/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/file_io/SetCurrentDirectoryW/CMakeLists.txt6
-rw-r--r--src/pal/tests/palsuite/file_io/SetCurrentDirectoryW/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/SetCurrentDirectoryW/test1/SetCurrentDirectoryW.c178
-rw-r--r--src/pal/tests/palsuite/file_io/SetCurrentDirectoryW/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/file_io/SetCurrentDirectoryW/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/SetCurrentDirectoryW/test2/setcurrentdirectoryw.c147
-rw-r--r--src/pal/tests/palsuite/file_io/SetCurrentDirectoryW/test2/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/file_io/SetCurrentDirectoryW/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/SetCurrentDirectoryW/test3/setcurrentdirectoryw.c64
-rw-r--r--src/pal/tests/palsuite/file_io/SetCurrentDirectoryW/test3/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/file_io/SetEndOfFile/CMakeLists.txt8
-rw-r--r--src/pal/tests/palsuite/file_io/SetEndOfFile/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/SetEndOfFile/test1/SetEndOfFile.c85
-rw-r--r--src/pal/tests/palsuite/file_io/SetEndOfFile/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/file_io/SetEndOfFile/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/SetEndOfFile/test2/SetEndOfFile.c154
-rw-r--r--src/pal/tests/palsuite/file_io/SetEndOfFile/test2/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/file_io/SetEndOfFile/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/SetEndOfFile/test3/SetEndOfFile.c109
-rw-r--r--src/pal/tests/palsuite/file_io/SetEndOfFile/test3/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/file_io/SetEndOfFile/test4/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/SetEndOfFile/test4/setendoffile.c138
-rw-r--r--src/pal/tests/palsuite/file_io/SetEndOfFile/test4/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/file_io/SetEndOfFile/test5/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/SetEndOfFile/test5/test5.c183
-rw-r--r--src/pal/tests/palsuite/file_io/SetEndOfFile/test5/testinfo.dat16
-rw-r--r--src/pal/tests/palsuite/file_io/SetFileAttributesA/CMakeLists.txt7
-rw-r--r--src/pal/tests/palsuite/file_io/SetFileAttributesA/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/SetFileAttributesA/test1/SetFileAttributesA.c168
-rw-r--r--src/pal/tests/palsuite/file_io/SetFileAttributesA/test1/test_file1
-rw-r--r--src/pal/tests/palsuite/file_io/SetFileAttributesA/test1/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/file_io/SetFileAttributesA/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/SetFileAttributesA/test2/SetFileAttributesA.c114
-rw-r--r--src/pal/tests/palsuite/file_io/SetFileAttributesA/test2/test_file1
-rw-r--r--src/pal/tests/palsuite/file_io/SetFileAttributesA/test2/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/file_io/SetFileAttributesA/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/SetFileAttributesA/test3/SetFileAttributesA.c48
-rw-r--r--src/pal/tests/palsuite/file_io/SetFileAttributesA/test3/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/file_io/SetFileAttributesA/test4/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/SetFileAttributesA/test4/SetFileAttributesA.c128
-rw-r--r--src/pal/tests/palsuite/file_io/SetFileAttributesA/test4/test_file1
-rw-r--r--src/pal/tests/palsuite/file_io/SetFileAttributesA/test4/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/file_io/SetFileAttributesW/CMakeLists.txt7
-rw-r--r--src/pal/tests/palsuite/file_io/SetFileAttributesW/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/SetFileAttributesW/test1/SetFileAttributesW.c167
-rw-r--r--src/pal/tests/palsuite/file_io/SetFileAttributesW/test1/test_file1
-rw-r--r--src/pal/tests/palsuite/file_io/SetFileAttributesW/test1/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/file_io/SetFileAttributesW/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/SetFileAttributesW/test2/SetFileAttributesW.c121
-rw-r--r--src/pal/tests/palsuite/file_io/SetFileAttributesW/test2/test_file1
-rw-r--r--src/pal/tests/palsuite/file_io/SetFileAttributesW/test2/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/file_io/SetFileAttributesW/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/SetFileAttributesW/test3/SetFileAttributesW.c57
-rw-r--r--src/pal/tests/palsuite/file_io/SetFileAttributesW/test3/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/file_io/SetFileAttributesW/test4/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/SetFileAttributesW/test4/SetFileAttributesW.c133
-rw-r--r--src/pal/tests/palsuite/file_io/SetFileAttributesW/test4/test_file1
-rw-r--r--src/pal/tests/palsuite/file_io/SetFileAttributesW/test4/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/file_io/SetFilePointer/CMakeLists.txt10
-rw-r--r--src/pal/tests/palsuite/file_io/SetFilePointer/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/SetFilePointer/test1/SetFilePointer.c123
-rw-r--r--src/pal/tests/palsuite/file_io/SetFilePointer/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/file_io/SetFilePointer/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/SetFilePointer/test2/SetFilePointer.c356
-rw-r--r--src/pal/tests/palsuite/file_io/SetFilePointer/test2/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/file_io/SetFilePointer/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/SetFilePointer/test3/SetFilePointer.c350
-rw-r--r--src/pal/tests/palsuite/file_io/SetFilePointer/test3/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/file_io/SetFilePointer/test4/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/SetFilePointer/test4/SetFilePointer.c242
-rw-r--r--src/pal/tests/palsuite/file_io/SetFilePointer/test4/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/file_io/SetFilePointer/test5/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/SetFilePointer/test5/SetFilePointer.c182
-rw-r--r--src/pal/tests/palsuite/file_io/SetFilePointer/test5/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/file_io/SetFilePointer/test6/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/SetFilePointer/test6/SetFilePointer.c213
-rw-r--r--src/pal/tests/palsuite/file_io/SetFilePointer/test6/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/file_io/SetFilePointer/test7/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/SetFilePointer/test7/SetFilePointer.c213
-rw-r--r--src/pal/tests/palsuite/file_io/SetFilePointer/test7/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/file_io/SetFileTime/CMakeLists.txt7
-rw-r--r--src/pal/tests/palsuite/file_io/SetFileTime/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/SetFileTime/test1/SetFileTime.c129
-rw-r--r--src/pal/tests/palsuite/file_io/SetFileTime/test1/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/file_io/SetFileTime/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/SetFileTime/test2/SetFileTime.c101
-rw-r--r--src/pal/tests/palsuite/file_io/SetFileTime/test2/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/file_io/SetFileTime/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/SetFileTime/test3/SetFileTime.c66
-rw-r--r--src/pal/tests/palsuite/file_io/SetFileTime/test3/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/file_io/SetFileTime/test4/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/SetFileTime/test4/SetFileTime.c108
-rw-r--r--src/pal/tests/palsuite/file_io/SetFileTime/test4/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/file_io/WriteFile/CMakeLists.txt8
-rw-r--r--src/pal/tests/palsuite/file_io/WriteFile/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/WriteFile/test1/WriteFile.c114
-rw-r--r--src/pal/tests/palsuite/file_io/WriteFile/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/file_io/WriteFile/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/WriteFile/test2/Results.txt1
-rw-r--r--src/pal/tests/palsuite/file_io/WriteFile/test2/WriteFile.c109
-rw-r--r--src/pal/tests/palsuite/file_io/WriteFile/test2/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/file_io/WriteFile/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/WriteFile/test3/WriteFile.c136
-rw-r--r--src/pal/tests/palsuite/file_io/WriteFile/test3/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/file_io/WriteFile/test4/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/WriteFile/test4/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/file_io/WriteFile/test4/writefile.c155
-rw-r--r--src/pal/tests/palsuite/file_io/WriteFile/test5/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/WriteFile/test5/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/file_io/WriteFile/test5/writefile.c117
-rw-r--r--src/pal/tests/palsuite/file_io/errorpathnotfound/CMakeLists.txt7
-rw-r--r--src/pal/tests/palsuite/file_io/errorpathnotfound/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/errorpathnotfound/test1/test1.c783
-rw-r--r--src/pal/tests/palsuite/file_io/errorpathnotfound/test1/testinfo.dat31
-rw-r--r--src/pal/tests/palsuite/file_io/errorpathnotfound/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/errorpathnotfound/test2/test2.c785
-rw-r--r--src/pal/tests/palsuite/file_io/errorpathnotfound/test2/testinfo.dat34
-rw-r--r--src/pal/tests/palsuite/file_io/errorpathnotfound/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/errorpathnotfound/test3/test3.c244
-rw-r--r--src/pal/tests/palsuite/file_io/errorpathnotfound/test3/testinfo.dat30
-rw-r--r--src/pal/tests/palsuite/file_io/errorpathnotfound/test4/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/errorpathnotfound/test4/test4.c351
-rw-r--r--src/pal/tests/palsuite/file_io/errorpathnotfound/test4/testinfo.dat34
-rw-r--r--src/pal/tests/palsuite/file_io/gettemppatha/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/file_io/gettemppatha/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/file_io/gettemppatha/test1/gettemppatha.c103
-rw-r--r--src/pal/tests/palsuite/file_io/gettemppatha/test1/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/CMakeLists.txt28
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/CMakeLists.txt11
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test1/CreateFileMapping.c173
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test3/CreateFileMapping.c155
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test3/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test4/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test4/CreateFileMapping.c181
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test4/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test5/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test5/CreateFileMapping.c193
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test5/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test6/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test6/CreateFileMapping.c164
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test6/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test7/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test7/createfilemapping.c164
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test7/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test8/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test8/createfilemapping.c79
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test8/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test9/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test9/createfilemapping.c150
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test9/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/CMakeLists.txt16
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/CreateFileMapping_neg1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/CreateFileMapping_neg1/CreateFileMapping_neg.c93
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/CreateFileMapping_neg1/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test1/CreateFileMappingW.c174
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test2/CreateFileMappingW.c124
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test3/CreateFileMappingW.c156
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test3/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test4/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test4/CreateFileMappingW.c182
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test4/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test5/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test5/CreateFileMappingW.c194
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test5/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test6/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test6/CreateFileMappingW.c165
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test6/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test7/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test7/createfilemapping.c165
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test7/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test8/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test8/createfilemapping.c82
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test8/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test9/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test9/createfilemapping.c151
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test9/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/FreeLibrary/CMakeLists.txt5
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/FreeLibrary/test1/CMakeLists.txt20
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/FreeLibrary/test1/FreeLibrary.c128
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/FreeLibrary/test1/dlltest.c32
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/FreeLibrary/test1/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/FreeLibrary/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/FreeLibrary/test2/test2.c52
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/FreeLibrary/test2/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/FreeLibraryAndExitThread/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/FreeLibraryAndExitThread/test1/CMakeLists.txt20
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/FreeLibraryAndExitThread/test1/dlltest.c32
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/FreeLibraryAndExitThread/test1/test1.c183
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/FreeLibraryAndExitThread/test1/testinfo.dat17
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/GetModuleFileNameA/CMakeLists.txt5
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/GetModuleFileNameA/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/GetModuleFileNameA/test1/GetModuleFileNameA.c92
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/GetModuleFileNameA/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/GetModuleFileNameA/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/GetModuleFileNameA/test2/GetModuleFileNameA.c49
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/GetModuleFileNameA/test2/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/GetModuleFileNameW/CMakeLists.txt5
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/GetModuleFileNameW/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/GetModuleFileNameW/test1/GetModuleFileNameW.c112
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/GetModuleFileNameW/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/GetModuleFileNameW/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/GetModuleFileNameW/test2/GetModuleFileNameW.c57
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/GetModuleFileNameW/test2/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/GetProcAddress/CMakeLists.txt5
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/GetProcAddress/test1/CMakeLists.txt20
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/GetProcAddress/test1/test1.c111
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/GetProcAddress/test1/testinfo.dat19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/GetProcAddress/test1/testlib.c33
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/GetProcAddress/test2/CMakeLists.txt20
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/GetProcAddress/test2/test2.c152
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/GetProcAddress/test2/testinfo.dat18
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/GetProcAddress/test2/testlib.c33
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/GetProcessHeap/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/GetProcessHeap/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/GetProcessHeap/test1/GetProcessHeap.c39
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/GetProcessHeap/test1/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/HeapAlloc/CMakeLists.txt6
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/HeapAlloc/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/HeapAlloc/test1/HeapAlloc.c100
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/HeapAlloc/test1/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/HeapAlloc/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/HeapAlloc/test2/HeapAlloc.c59
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/HeapAlloc/test2/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/HeapAlloc/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/HeapAlloc/test3/HeapAlloc.c62
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/HeapAlloc/test3/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/HeapFree/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/HeapFree/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/HeapFree/test1/HeapFree.c62
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/HeapFree/test1/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/HeapReAlloc/CMakeLists.txt8
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/HeapReAlloc/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/HeapReAlloc/test1/test1.c72
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/HeapReAlloc/test1/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/HeapReAlloc/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/HeapReAlloc/test2/test2.c79
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/HeapReAlloc/test2/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/HeapReAlloc/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/HeapReAlloc/test3/test3.c78
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/HeapReAlloc/test3/testinfo.dat16
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/HeapReAlloc/test4/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/HeapReAlloc/test4/test4.c80
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/HeapReAlloc/test4/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/HeapReAlloc/test5/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/HeapReAlloc/test5/test5.c69
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/HeapReAlloc/test5/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/LocalAlloc/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/LocalAlloc/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/LocalAlloc/test1/LocalAlloc.c49
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/LocalAlloc/test1/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/LocalFree/CMakeLists.txt5
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/LocalFree/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/LocalFree/test1/LocalFree.c49
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/LocalFree/test1/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/LocalFree/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/LocalFree/test2/LocalFree.c39
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/LocalFree/test2/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/LockFile/CMakeLists.txt10
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/LockFile/LockFile.h152
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/LockFile/test1/CMakeLists.txt36
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/LockFile/test1/helper.c86
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/LockFile/test1/test1.c140
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/LockFile/test1/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/LockFile/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/LockFile/test2/test2.c94
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/LockFile/test2/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/LockFile/test3/CMakeLists.txt36
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/LockFile/test3/helper.c102
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/LockFile/test3/test3.c71
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/LockFile/test3/testinfo.dat16
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/LockFile/test4/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/LockFile/test4/test4.c231
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/LockFile/test4/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/LockFile/test5/CMakeLists.txt36
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/LockFile/test5/helper.c122
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/LockFile/test5/test5.c161
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/LockFile/test5/testinfo.dat17
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/LockFile/test6/CMakeLists.txt36
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/LockFile/test6/helper.c71
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/LockFile/test6/test6.c146
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/LockFile/test6/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/LockFile/test7/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/LockFile/test7/test7.c135
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/LockFile/test7/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/MapViewOfFile/CMakeLists.txt9
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/MapViewOfFile/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/MapViewOfFile/test1/MapViewOfFile.c226
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/MapViewOfFile/test1/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/MapViewOfFile/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/MapViewOfFile/test2/MapViewOfFile.c203
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/MapViewOfFile/test2/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/MapViewOfFile/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/MapViewOfFile/test3/MapViewOfFile.c209
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/MapViewOfFile/test3/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/MapViewOfFile/test4/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/MapViewOfFile/test4/mapviewoffile.c166
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/MapViewOfFile/test4/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/MapViewOfFile/test5/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/MapViewOfFile/test5/mapviewoffile.c131
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/MapViewOfFile/test5/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/MapViewOfFile/test6/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/MapViewOfFile/test6/mapviewoffile.c85
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/MapViewOfFile/test6/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingA/CMakeLists.txt6
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingA/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingA/test1/OpenFileMappingA.c157
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingA/test1/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingA/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingA/test2/OpenFileMappingA.c214
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingA/test2/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingA/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingA/test3/OpenFileMappingA.c217
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingA/test3/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingW/CMakeLists.txt6
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingW/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingW/test1/OpenFileMappingW.c155
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingW/test1/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingW/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingW/test2/OpenFileMappingW.c217
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingW/test2/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingW/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingW/test3/OpenFileMappingW.c210
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingW/test3/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/ReadProcessMemory/CMakeLists.txt6
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/ReadProcessMemory/ReadProcessMemory_neg1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/ReadProcessMemory/ReadProcessMemory_neg1/ReadProcessMemory_neg.c127
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/ReadProcessMemory/ReadProcessMemory_neg1/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/ReadProcessMemory/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/ReadProcessMemory/test1/ReadProcessMemory.c126
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/ReadProcessMemory/test1/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/ReadProcessMemory/test2/CMakeLists.txt36
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/ReadProcessMemory/test2/commonconsts.h48
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/ReadProcessMemory/test2/helper.c249
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/ReadProcessMemory/test2/test2.c258
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/ReadProcessMemory/test2/testinfo.dat18
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/RtlMoveMemory/CMakeLists.txt7
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/RtlMoveMemory/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/RtlMoveMemory/test1/test1.c56
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/RtlMoveMemory/test1/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/RtlMoveMemory/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/RtlMoveMemory/test3/test3.c72
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/RtlMoveMemory/test3/testinfo.dat17
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/RtlMoveMemory/test4/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/RtlMoveMemory/test4/test4.c76
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/RtlMoveMemory/test4/testinfo.dat18
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/RtlMoveMemory/test5/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/RtlMoveMemory/test5/test5.c63
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/RtlMoveMemory/test5/testinfo.dat18
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/UnlockFile/CMakeLists.txt7
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/UnlockFile/UnlockFile.h112
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/UnlockFile/test1/CMakeLists.txt36
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/UnlockFile/test1/helper.c92
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/UnlockFile/test1/test1.c154
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/UnlockFile/test1/testinfo.dat17
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/UnlockFile/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/UnlockFile/test2/test2.c154
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/UnlockFile/test2/testinfo.dat16
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/UnlockFile/test3/CMakeLists.txt36
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/UnlockFile/test3/helper.c103
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/UnlockFile/test3/test3.c142
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/UnlockFile/test3/testinfo.dat17
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/UnlockFile/test4/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/UnlockFile/test4/test4.c187
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/UnlockFile/test4/testinfo.dat16
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/UnmapViewOfFile/CMakeLists.txt5
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/UnmapViewOfFile/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/UnmapViewOfFile/test1/UnmapViewOfFile.c184
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/UnmapViewOfFile/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/UnmapViewOfFile/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/UnmapViewOfFile/test2/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/UnmapViewOfFile/test2/unmapviewoffile.c42
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/CMakeLists.txt24
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test1/VirtualAlloc.c50
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test10/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test10/VirtualAlloc.c48
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test10/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test11/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test11/VirtualAlloc.c49
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test11/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test12/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test12/VirtualAlloc.c48
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test12/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test13/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test13/VirtualAlloc.c48
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test13/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test14/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test14/VirtualAlloc.c48
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test14/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test15/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test15/VirtualAlloc.c48
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test15/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test16/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test16/VirtualAlloc.c48
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test16/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test17/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test17/VirtualAlloc.c49
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test17/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test18/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test18/VirtualAlloc.c49
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test18/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test19/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test19/VirtualAlloc.c51
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test19/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test2/VirtualAlloc.c49
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test2/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test20/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test20/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test20/virtualalloc.c50
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test21/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test21/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test21/virtualalloc.c54
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test3/VirtualAlloc.c48
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test3/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test4/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test4/VirtualAlloc.c49
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test4/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test5/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test5/VirtualAlloc.c50
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test5/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test6/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test6/VirtualAlloc.c48
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test6/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test7/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test7/VirtualAlloc.c53
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test7/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test8/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test8/VirtualAlloc.c48
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test8/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test9/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test9/VirtualAlloc.c48
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test9/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualFree/CMakeLists.txt6
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualFree/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualFree/test1/VirtualFree.c48
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualFree/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualFree/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualFree/test2/VirtualFree.c54
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualFree/test2/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualFree/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualFree/test3/VirtualFree.c53
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualFree/test3/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualProtect/CMakeLists.txt9
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualProtect/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualProtect/test1/VirtualProtect.c69
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualProtect/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualProtect/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualProtect/test2/VirtualProtect.c69
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualProtect/test2/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualProtect/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualProtect/test3/VirtualProtect.c69
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualProtect/test3/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualProtect/test4/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualProtect/test4/VirtualProtect.c68
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualProtect/test4/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualProtect/test6/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualProtect/test6/VirtualProtect.c68
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualProtect/test6/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualProtect/test7/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualProtect/test7/VirtualProtect.c69
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualProtect/test7/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualQuery/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualQuery/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualQuery/test1/VirtualQuery.c68
-rw-r--r--src/pal/tests/palsuite/filemapping_memmgt/VirtualQuery/test1/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/loader/CMakeLists.txt5
-rw-r--r--src/pal/tests/palsuite/loader/LoadLibraryA/CMakeLists.txt8
-rw-r--r--src/pal/tests/palsuite/loader/LoadLibraryA/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/loader/LoadLibraryA/test1/LoadLibraryA.c53
-rw-r--r--src/pal/tests/palsuite/loader/LoadLibraryA/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/loader/LoadLibraryA/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/loader/LoadLibraryA/test2/LoadLibraryA.c52
-rw-r--r--src/pal/tests/palsuite/loader/LoadLibraryA/test2/MyModule.c19
-rw-r--r--src/pal/tests/palsuite/loader/LoadLibraryA/test2/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/loader/LoadLibraryA/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/loader/LoadLibraryA/test3/loadlibrarya.c40
-rw-r--r--src/pal/tests/palsuite/loader/LoadLibraryA/test3/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/loader/LoadLibraryA/test5/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/loader/LoadLibraryA/test5/loadlibrarya.c67
-rw-r--r--src/pal/tests/palsuite/loader/LoadLibraryA/test5/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/loader/LoadLibraryA/test6/CMakeLists.txt36
-rw-r--r--src/pal/tests/palsuite/loader/LoadLibraryA/test6/dlltest.c72
-rw-r--r--src/pal/tests/palsuite/loader/LoadLibraryA/test6/loadlibrarya.c172
-rw-r--r--src/pal/tests/palsuite/loader/LoadLibraryA/test6/testinfo.dat17
-rw-r--r--src/pal/tests/palsuite/loader/LoadLibraryA/test7/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/loader/LoadLibraryA/test7/LoadLibraryA.c83
-rw-r--r--src/pal/tests/palsuite/loader/LoadLibraryA/test7/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/loader/LoadLibraryA/test8/CMakeLists.txt36
-rw-r--r--src/pal/tests/palsuite/loader/LoadLibraryA/test8/dlltest.c72
-rw-r--r--src/pal/tests/palsuite/loader/LoadLibraryA/test8/loadlibrarya.c235
-rw-r--r--src/pal/tests/palsuite/loader/LoadLibraryA/test8/testinfo.dat17
-rw-r--r--src/pal/tests/palsuite/loader/LoadLibraryW/CMakeLists.txt7
-rw-r--r--src/pal/tests/palsuite/loader/LoadLibraryW/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/loader/LoadLibraryW/test1/LoadLibraryW.c62
-rw-r--r--src/pal/tests/palsuite/loader/LoadLibraryW/test1/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/loader/LoadLibraryW/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/loader/LoadLibraryW/test2/loadlibraryw.c62
-rw-r--r--src/pal/tests/palsuite/loader/LoadLibraryW/test2/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/loader/LoadLibraryW/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/loader/LoadLibraryW/test3/loadlibraryw.c41
-rw-r--r--src/pal/tests/palsuite/loader/LoadLibraryW/test3/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/loader/LoadLibraryW/test5/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/loader/LoadLibraryW/test5/loadlibraryw.c71
-rw-r--r--src/pal/tests/palsuite/loader/LoadLibraryW/test5/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/locale_info/CMakeLists.txt26
-rw-r--r--src/pal/tests/palsuite/locale_info/CompareStringA/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/locale_info/CompareStringA/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/locale_info/CompareStringA/test1/test1.c99
-rw-r--r--src/pal/tests/palsuite/locale_info/CompareStringA/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/locale_info/CompareStringW/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/locale_info/CompareStringW/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/locale_info/CompareStringW/test1/test1.c99
-rw-r--r--src/pal/tests/palsuite/locale_info/CompareStringW/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/locale_info/GetACP/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/locale_info/GetACP/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/locale_info/GetACP/test1/test1.c42
-rw-r--r--src/pal/tests/palsuite/locale_info/GetACP/test1/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/locale_info/GetCPInfo/CMakeLists.txt6
-rw-r--r--src/pal/tests/palsuite/locale_info/GetCPInfo/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/locale_info/GetCPInfo/test1/test1.c54
-rw-r--r--src/pal/tests/palsuite/locale_info/GetCPInfo/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/locale_info/GetCPInfo/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/locale_info/GetCPInfo/test2/test2.c60
-rw-r--r--src/pal/tests/palsuite/locale_info/GetCPInfo/test2/testinfo.dat9
-rw-r--r--src/pal/tests/palsuite/locale_info/GetCPInfo/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/locale_info/GetCPInfo/test3/test3.c41
-rw-r--r--src/pal/tests/palsuite/locale_info/GetCPInfo/test3/testinfo.dat8
-rw-r--r--src/pal/tests/palsuite/locale_info/GetLocaleInfoW/CMakeLists.txt5
-rw-r--r--src/pal/tests/palsuite/locale_info/GetLocaleInfoW/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/locale_info/GetLocaleInfoW/test1/test1.c89
-rw-r--r--src/pal/tests/palsuite/locale_info/GetLocaleInfoW/test1/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/locale_info/GetLocaleInfoW/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/locale_info/GetLocaleInfoW/test2/test2.c51
-rw-r--r--src/pal/tests/palsuite/locale_info/GetLocaleInfoW/test2/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/locale_info/GetStringTypeExW/CMakeLists.txt5
-rw-r--r--src/pal/tests/palsuite/locale_info/GetStringTypeExW/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/locale_info/GetStringTypeExW/test1/test1.c54
-rw-r--r--src/pal/tests/palsuite/locale_info/GetStringTypeExW/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/locale_info/GetStringTypeExW/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/locale_info/GetStringTypeExW/test2/test2.c78
-rw-r--r--src/pal/tests/palsuite/locale_info/GetStringTypeExW/test2/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/locale_info/GetSystemDefaultLangID/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/locale_info/GetSystemDefaultLangID/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/locale_info/GetSystemDefaultLangID/test1/test1.c59
-rw-r--r--src/pal/tests/palsuite/locale_info/GetSystemDefaultLangID/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/locale_info/GetThreadLocale/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/locale_info/GetThreadLocale/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/locale_info/GetThreadLocale/test1/test1.c36
-rw-r--r--src/pal/tests/palsuite/locale_info/GetThreadLocale/test1/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/locale_info/GetTimeZoneInformation/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/locale_info/GetTimeZoneInformation/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/locale_info/GetTimeZoneInformation/test1/test1.c73
-rw-r--r--src/pal/tests/palsuite/locale_info/GetTimeZoneInformation/test1/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/locale_info/GetUserDefaultLCID/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/locale_info/GetUserDefaultLCID/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/locale_info/GetUserDefaultLCID/test1/test1.c52
-rw-r--r--src/pal/tests/palsuite/locale_info/GetUserDefaultLCID/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/locale_info/GetUserDefaultLangID/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/locale_info/GetUserDefaultLangID/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/locale_info/GetUserDefaultLangID/test1/test1.c60
-rw-r--r--src/pal/tests/palsuite/locale_info/GetUserDefaultLangID/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/locale_info/IsDBCSLeadByte/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/locale_info/IsDBCSLeadByte/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/locale_info/IsDBCSLeadByte/test1/test1.c64
-rw-r--r--src/pal/tests/palsuite/locale_info/IsDBCSLeadByte/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/locale_info/IsDBCSLeadByteEx/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/locale_info/IsDBCSLeadByteEx/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/locale_info/IsDBCSLeadByteEx/test1/test1.c72
-rw-r--r--src/pal/tests/palsuite/locale_info/IsDBCSLeadByteEx/test1/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/locale_info/IsValidCodePage/CMakeLists.txt5
-rw-r--r--src/pal/tests/palsuite/locale_info/IsValidCodePage/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/locale_info/IsValidCodePage/test1/test1.c50
-rw-r--r--src/pal/tests/palsuite/locale_info/IsValidCodePage/test1/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/locale_info/IsValidCodePage/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/locale_info/IsValidCodePage/test2/test2.c51
-rw-r--r--src/pal/tests/palsuite/locale_info/IsValidCodePage/test2/testinfo.dat8
-rw-r--r--src/pal/tests/palsuite/locale_info/IsValidLocale/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/locale_info/IsValidLocale/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/locale_info/IsValidLocale/test1/test1.c76
-rw-r--r--src/pal/tests/palsuite/locale_info/IsValidLocale/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/locale_info/MultiByteToWideChar/CMakeLists.txt6
-rw-r--r--src/pal/tests/palsuite/locale_info/MultiByteToWideChar/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/locale_info/MultiByteToWideChar/test1/test1.c81
-rw-r--r--src/pal/tests/palsuite/locale_info/MultiByteToWideChar/test1/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/locale_info/MultiByteToWideChar/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/locale_info/MultiByteToWideChar/test2/test2.c68
-rw-r--r--src/pal/tests/palsuite/locale_info/MultiByteToWideChar/test2/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/locale_info/MultiByteToWideChar/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/locale_info/MultiByteToWideChar/test3/test3.c73
-rw-r--r--src/pal/tests/palsuite/locale_info/MultiByteToWideChar/test3/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/locale_info/MultiByteToWideChar/test4/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/locale_info/MultiByteToWideChar/test4/test4.c230
-rw-r--r--src/pal/tests/palsuite/locale_info/MultiByteToWideChar/test4/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/locale_info/SetThreadLocale/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/locale_info/SetThreadLocale/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/locale_info/SetThreadLocale/test1/test1.c50
-rw-r--r--src/pal/tests/palsuite/locale_info/SetThreadLocale/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/locale_info/WideCharToMultiByte/CMakeLists.txt7
-rw-r--r--src/pal/tests/palsuite/locale_info/WideCharToMultiByte/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/locale_info/WideCharToMultiByte/test1/test1.c102
-rw-r--r--src/pal/tests/palsuite/locale_info/WideCharToMultiByte/test1/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/locale_info/WideCharToMultiByte/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/locale_info/WideCharToMultiByte/test2/test2.c88
-rw-r--r--src/pal/tests/palsuite/locale_info/WideCharToMultiByte/test2/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/locale_info/WideCharToMultiByte/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/locale_info/WideCharToMultiByte/test3/test3.c100
-rw-r--r--src/pal/tests/palsuite/locale_info/WideCharToMultiByte/test3/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/locale_info/WideCharToMultiByte/test4/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/locale_info/WideCharToMultiByte/test4/test4.c131
-rw-r--r--src/pal/tests/palsuite/locale_info/WideCharToMultiByte/test4/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/locale_info/WideCharToMultiByte/test5/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/locale_info/WideCharToMultiByte/test5/test5.c154
-rw-r--r--src/pal/tests/palsuite/locale_info/WideCharToMultiByte/test5/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/manual-inspect.dat17
-rw-r--r--src/pal/tests/palsuite/manual-unautomatable.dat35
-rw-r--r--src/pal/tests/palsuite/miscellaneous/CMakeLists.txt44
-rw-r--r--src/pal/tests/palsuite/miscellaneous/CharNextA/CMakeLists.txt5
-rw-r--r--src/pal/tests/palsuite/miscellaneous/CharNextA/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/CharNextA/test1/test.c62
-rw-r--r--src/pal/tests/palsuite/miscellaneous/CharNextA/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/miscellaneous/CharNextA/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/CharNextA/test2/test.c67
-rw-r--r--src/pal/tests/palsuite/miscellaneous/CharNextA/test2/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/miscellaneous/CharNextExA/CMakeLists.txt5
-rw-r--r--src/pal/tests/palsuite/miscellaneous/CharNextExA/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/CharNextExA/test1/test.c63
-rw-r--r--src/pal/tests/palsuite/miscellaneous/CharNextExA/test1/testinfo.dat16
-rw-r--r--src/pal/tests/palsuite/miscellaneous/CharNextExA/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/CharNextExA/test2/test.c66
-rw-r--r--src/pal/tests/palsuite/miscellaneous/CharNextExA/test2/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/miscellaneous/CloseHandle/CMakeLists.txt5
-rw-r--r--src/pal/tests/palsuite/miscellaneous/CloseHandle/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/CloseHandle/test1/test.c64
-rw-r--r--src/pal/tests/palsuite/miscellaneous/CloseHandle/test1/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/miscellaneous/CloseHandle/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/CloseHandle/test2/test.c46
-rw-r--r--src/pal/tests/palsuite/miscellaneous/CloseHandle/test2/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/miscellaneous/CreatePipe/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/miscellaneous/CreatePipe/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/CreatePipe/test1/test1.c113
-rw-r--r--src/pal/tests/palsuite/miscellaneous/CreatePipe/test1/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/miscellaneous/FlushInstructionCache/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/miscellaneous/FlushInstructionCache/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/FlushInstructionCache/test1/test1.c66
-rw-r--r--src/pal/tests/palsuite/miscellaneous/FlushInstructionCache/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/miscellaneous/FormatMessageW/CMakeLists.txt9
-rw-r--r--src/pal/tests/palsuite/miscellaneous/FormatMessageW/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/FormatMessageW/test1/test.c63
-rw-r--r--src/pal/tests/palsuite/miscellaneous/FormatMessageW/test1/testinfo.dat16
-rw-r--r--src/pal/tests/palsuite/miscellaneous/FormatMessageW/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/FormatMessageW/test2/test.c581
-rw-r--r--src/pal/tests/palsuite/miscellaneous/FormatMessageW/test2/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/miscellaneous/FormatMessageW/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/FormatMessageW/test3/test.c85
-rw-r--r--src/pal/tests/palsuite/miscellaneous/FormatMessageW/test3/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/miscellaneous/FormatMessageW/test4/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/FormatMessageW/test4/test.c77
-rw-r--r--src/pal/tests/palsuite/miscellaneous/FormatMessageW/test4/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/miscellaneous/FormatMessageW/test5/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/FormatMessageW/test5/test.c76
-rw-r--r--src/pal/tests/palsuite/miscellaneous/FormatMessageW/test5/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/miscellaneous/FormatMessageW/test6/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/FormatMessageW/test6/test.c78
-rw-r--r--src/pal/tests/palsuite/miscellaneous/FormatMessageW/test6/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/miscellaneous/FreeEnvironmentStringsW/CMakeLists.txt5
-rw-r--r--src/pal/tests/palsuite/miscellaneous/FreeEnvironmentStringsW/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/FreeEnvironmentStringsW/test1/test.c53
-rw-r--r--src/pal/tests/palsuite/miscellaneous/FreeEnvironmentStringsW/test1/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/miscellaneous/FreeEnvironmentStringsW/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/FreeEnvironmentStringsW/test2/test.c71
-rw-r--r--src/pal/tests/palsuite/miscellaneous/FreeEnvironmentStringsW/test2/testinfo.dat16
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetCalendarInfoW/CMakeLists.txt5
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetCalendarInfoW/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetCalendarInfoW/test1/GetCalendarInfoW.c57
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetCalendarInfoW/test1/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetCalendarInfoW/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetCalendarInfoW/test2/GetCalendarInfoW.c79
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetCalendarInfoW/test2/testinfo.dat11
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetCommandLineW/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetCommandLineW/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetCommandLineW/test1/test.c71
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetCommandLineW/test1/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetComputerNameW/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetComputerNameW/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetComputerNameW/test1/test.c53
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetComputerNameW/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetDateFormatW/CMakeLists.txt6
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetDateFormatW/GetDateFormatW_neg1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetDateFormatW/GetDateFormatW_neg1/GetDateFormatW_neg.c85
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetDateFormatW/GetDateFormatW_neg1/testinfo.dat8
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetDateFormatW/GetDateFormatW_neg2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetDateFormatW/GetDateFormatW_neg2/GetDateFormatW_neg.c98
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetDateFormatW/GetDateFormatW_neg2/testinfo.dat9
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetDateFormatW/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetDateFormatW/test1/GetDateFormatW.c100
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetDateFormatW/test1/testinfo.dat9
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetEnvironmentStringsW/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetEnvironmentStringsW/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetEnvironmentStringsW/test1/test.c81
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetEnvironmentStringsW/test1/testinfo.dat16
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableA/CMakeLists.txt9
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableA/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableA/test1/test.c84
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableA/test1/testinfo.dat16
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableA/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableA/test2/test.c56
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableA/test2/testinfo.dat16
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableA/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableA/test3/test.c67
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableA/test3/testinfo.dat16
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableA/test4/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableA/test4/test.c75
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableA/test4/testinfo.dat16
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableA/test5/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableA/test5/test5.c145
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableA/test5/testinfo.dat17
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableA/test6/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableA/test6/test6.c99
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableA/test6/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableW/CMakeLists.txt9
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableW/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableW/test1/test.c79
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableW/test1/testinfo.dat16
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableW/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableW/test2/test.c56
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableW/test2/testinfo.dat16
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableW/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableW/test3/test.c71
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableW/test3/testinfo.dat16
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableW/test4/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableW/test4/test.c63
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableW/test4/testinfo.dat16
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableW/test5/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableW/test5/test5.c144
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableW/test5/testinfo.dat17
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableW/test6/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableW/test6/test6.c99
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableW/test6/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetLastError/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetLastError/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetLastError/test1/test.c63
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetLastError/test1/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetSystemInfo/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetSystemInfo/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetSystemInfo/test1/test.c70
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetSystemInfo/test1/testinfo.dat16
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetTickCount/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetTickCount/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetTickCount/test1/test.c58
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetTickCount/test1/testinfo.dat16
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetUserNameW/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetUserNameW/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetUserNameW/test1/test.c52
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetUserNameW/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetVersionExA/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetVersionExA/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetVersionExA/test1/test.c83
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetVersionExA/test1/testinfo.dat16
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetVersionExW/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetVersionExW/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetVersionExW/test1/test.c88
-rw-r--r--src/pal/tests/palsuite/miscellaneous/GetVersionExW/test1/testinfo.dat16
-rw-r--r--src/pal/tests/palsuite/miscellaneous/InterLockedExchangeAdd/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/miscellaneous/InterLockedExchangeAdd/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/InterLockedExchangeAdd/test1/test.cpp102
-rw-r--r--src/pal/tests/palsuite/miscellaneous/InterlockedBit/CMakeLists.txt5
-rw-r--r--src/pal/tests/palsuite/miscellaneous/InterlockedBit/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/InterlockedBit/test1/test.cpp77
-rw-r--r--src/pal/tests/palsuite/miscellaneous/InterlockedBit/test1/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/miscellaneous/InterlockedBit/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/InterlockedBit/test2/test.cpp77
-rw-r--r--src/pal/tests/palsuite/miscellaneous/InterlockedBit/test2/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/miscellaneous/InterlockedCompareExchange/CMakeLists.txt5
-rw-r--r--src/pal/tests/palsuite/miscellaneous/InterlockedCompareExchange/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/InterlockedCompareExchange/test1/test.cpp100
-rw-r--r--src/pal/tests/palsuite/miscellaneous/InterlockedCompareExchange/test1/testinfo.dat16
-rw-r--r--src/pal/tests/palsuite/miscellaneous/InterlockedCompareExchange/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/InterlockedCompareExchange/test2/test.cpp168
-rw-r--r--src/pal/tests/palsuite/miscellaneous/InterlockedCompareExchange64/CMakeLists.txt5
-rw-r--r--src/pal/tests/palsuite/miscellaneous/InterlockedCompareExchange64/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/InterlockedCompareExchange64/test1/test.cpp122
-rw-r--r--src/pal/tests/palsuite/miscellaneous/InterlockedCompareExchange64/test1/testinfo.dat16
-rw-r--r--src/pal/tests/palsuite/miscellaneous/InterlockedCompareExchange64/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/InterlockedCompareExchange64/test2/test.cpp104
-rw-r--r--src/pal/tests/palsuite/miscellaneous/InterlockedCompareExchangePointer/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/miscellaneous/InterlockedCompareExchangePointer/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/InterlockedCompareExchangePointer/test1/test.cpp80
-rw-r--r--src/pal/tests/palsuite/miscellaneous/InterlockedCompareExchangePointer/test1/testinfo.dat16
-rw-r--r--src/pal/tests/palsuite/miscellaneous/InterlockedDecrement/CMakeLists.txt5
-rw-r--r--src/pal/tests/palsuite/miscellaneous/InterlockedDecrement/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/InterlockedDecrement/test1/test.cpp60
-rw-r--r--src/pal/tests/palsuite/miscellaneous/InterlockedDecrement/test1/testinfo.dat16
-rw-r--r--src/pal/tests/palsuite/miscellaneous/InterlockedDecrement/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/InterlockedDecrement/test2/test.cpp94
-rw-r--r--src/pal/tests/palsuite/miscellaneous/InterlockedDecrement64/CMakeLists.txt5
-rw-r--r--src/pal/tests/palsuite/miscellaneous/InterlockedDecrement64/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/InterlockedDecrement64/test1/test.cpp77
-rw-r--r--src/pal/tests/palsuite/miscellaneous/InterlockedDecrement64/test1/testinfo.dat16
-rw-r--r--src/pal/tests/palsuite/miscellaneous/InterlockedDecrement64/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/InterlockedDecrement64/test2/test.cpp99
-rw-r--r--src/pal/tests/palsuite/miscellaneous/InterlockedExchange/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/miscellaneous/InterlockedExchange/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/InterlockedExchange/test1/test.cpp69
-rw-r--r--src/pal/tests/palsuite/miscellaneous/InterlockedExchange/test1/testinfo.dat16
-rw-r--r--src/pal/tests/palsuite/miscellaneous/InterlockedExchange64/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/miscellaneous/InterlockedExchange64/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/InterlockedExchange64/test1/test.cpp85
-rw-r--r--src/pal/tests/palsuite/miscellaneous/InterlockedExchange64/test1/testinfo.dat16
-rw-r--r--src/pal/tests/palsuite/miscellaneous/InterlockedExchangePointer/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/miscellaneous/InterlockedExchangePointer/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/InterlockedExchangePointer/test1/InterlockedExchangePointer.cpp64
-rw-r--r--src/pal/tests/palsuite/miscellaneous/InterlockedExchangePointer/test1/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/miscellaneous/InterlockedIncrement/CMakeLists.txt5
-rw-r--r--src/pal/tests/palsuite/miscellaneous/InterlockedIncrement/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/InterlockedIncrement/test1/test.cpp62
-rw-r--r--src/pal/tests/palsuite/miscellaneous/InterlockedIncrement/test1/testinfo.dat16
-rw-r--r--src/pal/tests/palsuite/miscellaneous/InterlockedIncrement/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/InterlockedIncrement/test2/test.cpp95
-rw-r--r--src/pal/tests/palsuite/miscellaneous/InterlockedIncrement64/CMakeLists.txt5
-rw-r--r--src/pal/tests/palsuite/miscellaneous/InterlockedIncrement64/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/InterlockedIncrement64/test1/test.cpp77
-rw-r--r--src/pal/tests/palsuite/miscellaneous/InterlockedIncrement64/test1/testinfo.dat16
-rw-r--r--src/pal/tests/palsuite/miscellaneous/InterlockedIncrement64/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/InterlockedIncrement64/test2/test.cpp101
-rw-r--r--src/pal/tests/palsuite/miscellaneous/IsBadCodePtr/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/miscellaneous/IsBadCodePtr/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/IsBadCodePtr/test1/test1.c60
-rw-r--r--src/pal/tests/palsuite/miscellaneous/IsBadCodePtr/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/miscellaneous/IsBadReadPtr/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/miscellaneous/IsBadReadPtr/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/IsBadReadPtr/test1/test.c138
-rw-r--r--src/pal/tests/palsuite/miscellaneous/IsBadReadPtr/test1/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/miscellaneous/IsBadWritePtr/CMakeLists.txt6
-rw-r--r--src/pal/tests/palsuite/miscellaneous/IsBadWritePtr/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/IsBadWritePtr/test1/test.c81
-rw-r--r--src/pal/tests/palsuite/miscellaneous/IsBadWritePtr/test1/testinfo.dat16
-rw-r--r--src/pal/tests/palsuite/miscellaneous/IsBadWritePtr/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/IsBadWritePtr/test2/test2.c128
-rw-r--r--src/pal/tests/palsuite/miscellaneous/IsBadWritePtr/test2/testinfo.dat19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/IsBadWritePtr/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/IsBadWritePtr/test3/test3.c58
-rw-r--r--src/pal/tests/palsuite/miscellaneous/IsBadWritePtr/test3/testinfo.dat17
-rw-r--r--src/pal/tests/palsuite/miscellaneous/MessageBoxW/CMakeLists.txt5
-rw-r--r--src/pal/tests/palsuite/miscellaneous/MessageBoxW/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/MessageBoxW/test1/test.c81
-rw-r--r--src/pal/tests/palsuite/miscellaneous/MessageBoxW/test1/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/miscellaneous/MessageBoxW/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/MessageBoxW/test2/test.c76
-rw-r--r--src/pal/tests/palsuite/miscellaneous/MessageBoxW/test2/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableA/CMakeLists.txt7
-rw-r--r--src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableA/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableA/test1/test1.c168
-rw-r--r--src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableA/test1/testinfo.dat19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableA/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableA/test2/test2.c85
-rw-r--r--src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableA/test2/testinfo.dat19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableA/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableA/test3/test3.c144
-rw-r--r--src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableA/test3/testinfo.dat18
-rw-r--r--src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableA/test4/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableA/test4/test4.c100
-rw-r--r--src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableA/test4/testinfo.dat18
-rw-r--r--src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableW/CMakeLists.txt7
-rw-r--r--src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableW/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableW/test1/test.c142
-rw-r--r--src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableW/test1/testinfo.dat18
-rw-r--r--src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableW/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableW/test2/test.c88
-rw-r--r--src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableW/test2/testinfo.dat18
-rw-r--r--src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableW/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableW/test3/test3.c143
-rw-r--r--src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableW/test3/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableW/test4/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableW/test4/test4.c99
-rw-r--r--src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableW/test4/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/miscellaneous/SetLastError/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/miscellaneous/SetLastError/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/SetLastError/test1/test.c59
-rw-r--r--src/pal/tests/palsuite/miscellaneous/SetLastError/test1/testinfo.dat16
-rw-r--r--src/pal/tests/palsuite/miscellaneous/_i64tow/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/miscellaneous/_i64tow/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/_i64tow/test1/test1.c76
-rw-r--r--src/pal/tests/palsuite/miscellaneous/_i64tow/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/miscellaneous/_ui64tow/CMakeLists.txt5
-rw-r--r--src/pal/tests/palsuite/miscellaneous/_ui64tow/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/_ui64tow/test1/_ui64tow.c101
-rw-r--r--src/pal/tests/palsuite/miscellaneous/_ui64tow/test1/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/miscellaneous/_ui64tow/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/_ui64tow/test2/_ui64tow.c88
-rw-r--r--src/pal/tests/palsuite/miscellaneous/_ui64tow/test2/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/miscellaneous/lstrcatW/CMakeLists.txt7
-rw-r--r--src/pal/tests/palsuite/miscellaneous/lstrcatW/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/lstrcatW/test1/test.c59
-rw-r--r--src/pal/tests/palsuite/miscellaneous/lstrcatW/test1/testinfo.dat16
-rw-r--r--src/pal/tests/palsuite/miscellaneous/lstrcatW/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/lstrcatW/test2/test2.c53
-rw-r--r--src/pal/tests/palsuite/miscellaneous/lstrcatW/test2/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/miscellaneous/lstrcatW/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/lstrcatW/test3/test3.c46
-rw-r--r--src/pal/tests/palsuite/miscellaneous/lstrcatW/test3/testinfo.dat26
-rw-r--r--src/pal/tests/palsuite/miscellaneous/lstrcatW/test4/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/lstrcatW/test4/test4.c101
-rw-r--r--src/pal/tests/palsuite/miscellaneous/lstrcatW/test4/testinfo.dat28
-rw-r--r--src/pal/tests/palsuite/miscellaneous/lstrcpyW/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/miscellaneous/lstrcpyW/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/lstrcpyW/test1/test.c66
-rw-r--r--src/pal/tests/palsuite/miscellaneous/lstrcpyW/test1/testinfo.dat16
-rw-r--r--src/pal/tests/palsuite/miscellaneous/lstrcpynW/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/miscellaneous/lstrcpynW/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/lstrcpynW/test1/test.c73
-rw-r--r--src/pal/tests/palsuite/miscellaneous/lstrcpynW/test1/testinfo.dat16
-rw-r--r--src/pal/tests/palsuite/miscellaneous/lstrlenA/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/miscellaneous/lstrlenA/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/lstrlenA/test1/test.c49
-rw-r--r--src/pal/tests/palsuite/miscellaneous/lstrlenA/test1/testinfo.dat16
-rw-r--r--src/pal/tests/palsuite/miscellaneous/lstrlenW/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/miscellaneous/lstrlenW/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/lstrlenW/test1/test.c51
-rw-r--r--src/pal/tests/palsuite/miscellaneous/lstrlenW/test1/testinfo.dat16
-rw-r--r--src/pal/tests/palsuite/miscellaneous/queryperformancecounter/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/miscellaneous/queryperformancecounter/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/queryperformancecounter/test1/test1.c107
-rw-r--r--src/pal/tests/palsuite/miscellaneous/queryperformancecounter/test1/testinfo.dat11
-rw-r--r--src/pal/tests/palsuite/miscellaneous/queryperformancefrequency/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/miscellaneous/queryperformancefrequency/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/queryperformancefrequency/test1/test1.c59
-rw-r--r--src/pal/tests/palsuite/miscellaneous/queryperformancefrequency/test1/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/miscellaneous/wsprintfA/CMakeLists.txt13
-rw-r--r--src/pal/tests/palsuite/miscellaneous/wsprintfA/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/wsprintfA/test1/test.c58
-rw-r--r--src/pal/tests/palsuite/miscellaneous/wsprintfA/test1/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/miscellaneous/wsprintfA/test11/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/wsprintfA/test11/test.c128
-rw-r--r--src/pal/tests/palsuite/miscellaneous/wsprintfA/test11/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/miscellaneous/wsprintfA/test12/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/wsprintfA/test12/test.c119
-rw-r--r--src/pal/tests/palsuite/miscellaneous/wsprintfA/test12/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/miscellaneous/wsprintfA/test13/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/wsprintfA/test13/test.c120
-rw-r--r--src/pal/tests/palsuite/miscellaneous/wsprintfA/test13/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/miscellaneous/wsprintfA/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/wsprintfA/test2/test.c123
-rw-r--r--src/pal/tests/palsuite/miscellaneous/wsprintfA/test2/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/miscellaneous/wsprintfA/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/wsprintfA/test3/test.c121
-rw-r--r--src/pal/tests/palsuite/miscellaneous/wsprintfA/test3/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/miscellaneous/wsprintfA/test6/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/wsprintfA/test6/test.c114
-rw-r--r--src/pal/tests/palsuite/miscellaneous/wsprintfA/test6/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/miscellaneous/wsprintfA/test7/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/wsprintfA/test7/test.c112
-rw-r--r--src/pal/tests/palsuite/miscellaneous/wsprintfA/test7/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/miscellaneous/wsprintfA/test8/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/wsprintfA/test8/test.c120
-rw-r--r--src/pal/tests/palsuite/miscellaneous/wsprintfA/test8/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/miscellaneous/wsprintfA/test9/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/wsprintfA/test9/test.c122
-rw-r--r--src/pal/tests/palsuite/miscellaneous/wsprintfA/test9/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/miscellaneous/wsprintfW/CMakeLists.txt13
-rw-r--r--src/pal/tests/palsuite/miscellaneous/wsprintfW/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/wsprintfW/test1/test.c64
-rw-r--r--src/pal/tests/palsuite/miscellaneous/wsprintfW/test1/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/miscellaneous/wsprintfW/test11/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/wsprintfW/test11/test.c139
-rw-r--r--src/pal/tests/palsuite/miscellaneous/wsprintfW/test11/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/miscellaneous/wsprintfW/test12/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/wsprintfW/test12/test.c128
-rw-r--r--src/pal/tests/palsuite/miscellaneous/wsprintfW/test12/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/miscellaneous/wsprintfW/test13/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/wsprintfW/test13/test.c126
-rw-r--r--src/pal/tests/palsuite/miscellaneous/wsprintfW/test13/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/miscellaneous/wsprintfW/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/wsprintfW/test2/test.c108
-rw-r--r--src/pal/tests/palsuite/miscellaneous/wsprintfW/test2/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/miscellaneous/wsprintfW/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/wsprintfW/test3/test.c127
-rw-r--r--src/pal/tests/palsuite/miscellaneous/wsprintfW/test3/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/miscellaneous/wsprintfW/test6/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/wsprintfW/test6/test.c115
-rw-r--r--src/pal/tests/palsuite/miscellaneous/wsprintfW/test6/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/miscellaneous/wsprintfW/test7/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/wsprintfW/test7/test.c117
-rw-r--r--src/pal/tests/palsuite/miscellaneous/wsprintfW/test7/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/miscellaneous/wsprintfW/test8/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/wsprintfW/test8/test.c128
-rw-r--r--src/pal/tests/palsuite/miscellaneous/wsprintfW/test8/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/miscellaneous/wsprintfW/test9/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/miscellaneous/wsprintfW/test9/test.c128
-rw-r--r--src/pal/tests/palsuite/miscellaneous/wsprintfW/test9/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/pal_specific/CMakeLists.txt13
-rw-r--r--src/pal/tests/palsuite/pal_specific/PAL_GetPALDirectoryW/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/pal_specific/PAL_GetPALDirectoryW/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/pal_specific/PAL_GetPALDirectoryW/test1/PAL_GetPALDirectoryW.c78
-rw-r--r--src/pal/tests/palsuite/pal_specific/PAL_GetPALDirectoryW/test1/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/pal_specific/PAL_GetUserTempDirectoryW/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/pal_specific/PAL_GetUserTempDirectoryW/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/pal_specific/PAL_GetUserTempDirectoryW/test1/PAL_GetUserTempDirectoryW.c58
-rw-r--r--src/pal/tests/palsuite/pal_specific/PAL_GetUserTempDirectoryW/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/pal_specific/PAL_Initialize_Terminate/CMakeLists.txt5
-rw-r--r--src/pal/tests/palsuite/pal_specific/PAL_Initialize_Terminate/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/pal_specific/PAL_Initialize_Terminate/test1/PAL_Initialize_Terminate.c33
-rw-r--r--src/pal/tests/palsuite/pal_specific/PAL_Initialize_Terminate/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/pal_specific/PAL_Initialize_Terminate/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/pal_specific/PAL_Initialize_Terminate/test2/pal_initialize_twice.c41
-rw-r--r--src/pal/tests/palsuite/pal_specific/PAL_Initialize_Terminate/test2/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/pal_specific/PAL_RegisterLibraryW_UnregisterLibraryW/CMakeLists.txt5
-rw-r--r--src/pal/tests/palsuite/pal_specific/PAL_RegisterLibraryW_UnregisterLibraryW/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/pal_specific/PAL_RegisterLibraryW_UnregisterLibraryW/test1/PAL_RegisterLibraryW_UnregisterLibraryW.c64
-rw-r--r--src/pal/tests/palsuite/pal_specific/PAL_RegisterLibraryW_UnregisterLibraryW/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/pal_specific/PAL_RegisterLibraryW_UnregisterLibraryW/test2_neg/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/pal_specific/PAL_RegisterLibraryW_UnregisterLibraryW/test2_neg/reg_unreg_libraryw_neg.c62
-rw-r--r--src/pal/tests/palsuite/pal_specific/PAL_RegisterLibraryW_UnregisterLibraryW/test2_neg/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/pal_specific/PAL_errno/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/pal_specific/PAL_errno/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/pal_specific/PAL_errno/test1/PAL_errno.c53
-rw-r--r--src/pal/tests/palsuite/pal_specific/PAL_errno/test1/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/pal_specific/PAL_get_stderr/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/pal_specific/PAL_get_stderr/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/pal_specific/PAL_get_stderr/test1/PAL_get_stderr.c52
-rw-r--r--src/pal/tests/palsuite/pal_specific/PAL_get_stderr/test1/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/pal_specific/PAL_get_stdin/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/pal_specific/PAL_get_stdin/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/pal_specific/PAL_get_stdin/test1/PAL_get_stdin.c68
-rw-r--r--src/pal/tests/palsuite/pal_specific/PAL_get_stdin/test1/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/pal_specific/PAL_get_stdout/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/pal_specific/PAL_get_stdout/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/pal_specific/PAL_get_stdout/test1/PAL_get_stdout.c52
-rw-r--r--src/pal/tests/palsuite/pal_specific/PAL_get_stdout/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/pal_specific/pal_entrypoint/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/pal_specific/pal_entrypoint/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/pal_specific/pal_entrypoint/test1/pal_entrypoint.c54
-rw-r--r--src/pal/tests/palsuite/pal_specific/pal_entrypoint/test1/palstartup.h49
-rw-r--r--src/pal/tests/palsuite/pal_specific/pal_entrypoint/test1/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/pal_specific/pal_initializedebug/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/pal_specific/pal_initializedebug/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/pal_specific/pal_initializedebug/test1/pal_initializedebug.c36
-rw-r--r--src/pal/tests/palsuite/pal_specific/pal_initializedebug/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/paltestlist.txt808
-rw-r--r--src/pal/tests/palsuite/paltestlist_to_be_reviewed.txt201
-rw-r--r--src/pal/tests/palsuite/palverify.dat889
-rwxr-xr-xsrc/pal/tests/palsuite/runpaltests.sh213
-rw-r--r--src/pal/tests/palsuite/samples/CMakeLists.txt5
-rw-r--r--src/pal/tests/palsuite/samples/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/samples/test1/test.c41
-rw-r--r--src/pal/tests/palsuite/samples/test1/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/samples/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/samples/test2/test.c48
-rw-r--r--src/pal/tests/palsuite/samples/test2/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/smoketest.script100
-rw-r--r--src/pal/tests/palsuite/tests-manual.dat12
-rw-r--r--src/pal/tests/palsuite/threading/CMakeLists.txt44
-rw-r--r--src/pal/tests/palsuite/threading/CreateEventA/CMakeLists.txt6
-rw-r--r--src/pal/tests/palsuite/threading/CreateEventA/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/CreateEventA/test1/test1.c95
-rw-r--r--src/pal/tests/palsuite/threading/CreateEventA/test1/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/threading/CreateEventA/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/CreateEventA/test2/test2.c84
-rw-r--r--src/pal/tests/palsuite/threading/CreateEventA/test2/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/threading/CreateEventA/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/CreateEventA/test3/test3.c219
-rw-r--r--src/pal/tests/palsuite/threading/CreateEventA/test3/testinfo.dat16
-rw-r--r--src/pal/tests/palsuite/threading/CreateEventW/CMakeLists.txt6
-rw-r--r--src/pal/tests/palsuite/threading/CreateEventW/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/CreateEventW/test1/test1.c93
-rw-r--r--src/pal/tests/palsuite/threading/CreateEventW/test1/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/threading/CreateEventW/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/CreateEventW/test2/test2.c85
-rw-r--r--src/pal/tests/palsuite/threading/CreateEventW/test2/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/threading/CreateEventW/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/CreateEventW/test3/test3.c233
-rw-r--r--src/pal/tests/palsuite/threading/CreateEventW/test3/testinfo.dat16
-rw-r--r--src/pal/tests/palsuite/threading/CreateMutexA_ReleaseMutex/CMakeLists.txt5
-rw-r--r--src/pal/tests/palsuite/threading/CreateMutexA_ReleaseMutex/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/CreateMutexA_ReleaseMutex/test1/CreateMutexA.c345
-rw-r--r--src/pal/tests/palsuite/threading/CreateMutexA_ReleaseMutex/test1/testinfo.dat33
-rw-r--r--src/pal/tests/palsuite/threading/CreateMutexA_ReleaseMutex/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/CreateMutexA_ReleaseMutex/test2/CreateMutexA.c331
-rw-r--r--src/pal/tests/palsuite/threading/CreateMutexA_ReleaseMutex/test2/testinfo.dat24
-rw-r--r--src/pal/tests/palsuite/threading/CreateMutexW_ReleaseMutex/CMakeLists.txt5
-rw-r--r--src/pal/tests/palsuite/threading/CreateMutexW_ReleaseMutex/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/CreateMutexW_ReleaseMutex/test1/CreateMutexW.c345
-rw-r--r--src/pal/tests/palsuite/threading/CreateMutexW_ReleaseMutex/test1/testinfo.dat33
-rw-r--r--src/pal/tests/palsuite/threading/CreateMutexW_ReleaseMutex/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/CreateMutexW_ReleaseMutex/test2/CreateMutexW.c340
-rw-r--r--src/pal/tests/palsuite/threading/CreateMutexW_ReleaseMutex/test2/testinfo.dat24
-rw-r--r--src/pal/tests/palsuite/threading/CreateProcessA/CMakeLists.txt5
-rw-r--r--src/pal/tests/palsuite/threading/CreateProcessA/test1/CMakeLists.txt36
-rw-r--r--src/pal/tests/palsuite/threading/CreateProcessA/test1/childProcess.c131
-rw-r--r--src/pal/tests/palsuite/threading/CreateProcessA/test1/parentProcess.c201
-rw-r--r--src/pal/tests/palsuite/threading/CreateProcessA/test1/testinfo.dat17
-rw-r--r--src/pal/tests/palsuite/threading/CreateProcessA/test2/CMakeLists.txt36
-rw-r--r--src/pal/tests/palsuite/threading/CreateProcessA/test2/childprocess.c69
-rw-r--r--src/pal/tests/palsuite/threading/CreateProcessA/test2/parentprocess.c243
-rw-r--r--src/pal/tests/palsuite/threading/CreateProcessA/test2/test2.h72
-rw-r--r--src/pal/tests/palsuite/threading/CreateProcessA/test2/testinfo.dat20
-rw-r--r--src/pal/tests/palsuite/threading/CreateProcessW/CMakeLists.txt5
-rw-r--r--src/pal/tests/palsuite/threading/CreateProcessW/test1/CMakeLists.txt36
-rw-r--r--src/pal/tests/palsuite/threading/CreateProcessW/test1/childProcess.c150
-rw-r--r--src/pal/tests/palsuite/threading/CreateProcessW/test1/parentProcess.c210
-rw-r--r--src/pal/tests/palsuite/threading/CreateProcessW/test1/testinfo.dat17
-rw-r--r--src/pal/tests/palsuite/threading/CreateProcessW/test2/CMakeLists.txt36
-rw-r--r--src/pal/tests/palsuite/threading/CreateProcessW/test2/childprocess.c78
-rw-r--r--src/pal/tests/palsuite/threading/CreateProcessW/test2/parentprocess.c245
-rw-r--r--src/pal/tests/palsuite/threading/CreateProcessW/test2/test2.h31
-rw-r--r--src/pal/tests/palsuite/threading/CreateProcessW/test2/testinfo.dat20
-rw-r--r--src/pal/tests/palsuite/threading/CreateSemaphoreA_ReleaseSemaphore/CMakeLists.txt6
-rw-r--r--src/pal/tests/palsuite/threading/CreateSemaphoreA_ReleaseSemaphore/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/CreateSemaphoreA_ReleaseSemaphore/test1/CreateSemaphore.c322
-rw-r--r--src/pal/tests/palsuite/threading/CreateSemaphoreA_ReleaseSemaphore/test1/testinfo.dat18
-rw-r--r--src/pal/tests/palsuite/threading/CreateSemaphoreA_ReleaseSemaphore/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/CreateSemaphoreA_ReleaseSemaphore/test2/CreateSemaphore.c313
-rw-r--r--src/pal/tests/palsuite/threading/CreateSemaphoreA_ReleaseSemaphore/test2/testinfo.dat18
-rw-r--r--src/pal/tests/palsuite/threading/CreateSemaphoreA_ReleaseSemaphore/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/CreateSemaphoreA_ReleaseSemaphore/test3/createsemaphore.c200
-rw-r--r--src/pal/tests/palsuite/threading/CreateSemaphoreA_ReleaseSemaphore/test3/testinfo.dat20
-rw-r--r--src/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/CMakeLists.txt6
-rw-r--r--src/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/test1/CreateSemaphore.c323
-rw-r--r--src/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/test1/testinfo.dat18
-rw-r--r--src/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/test2/CreateSemaphore.c314
-rw-r--r--src/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/test2/testinfo.dat18
-rw-r--r--src/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/test3/createsemaphore.c201
-rw-r--r--src/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/test3/testinfo.dat20
-rw-r--r--src/pal/tests/palsuite/threading/CreateThread/CMakeLists.txt6
-rw-r--r--src/pal/tests/palsuite/threading/CreateThread/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/CreateThread/test1/test1.c119
-rw-r--r--src/pal/tests/palsuite/threading/CreateThread/test1/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/threading/CreateThread/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/CreateThread/test2/test2.c184
-rw-r--r--src/pal/tests/palsuite/threading/CreateThread/test2/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/threading/CreateThread/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/CreateThread/test3/test3.c101
-rw-r--r--src/pal/tests/palsuite/threading/CreateThread/test3/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/threading/CriticalSectionFunctions/CMakeLists.txt11
-rw-r--r--src/pal/tests/palsuite/threading/CriticalSectionFunctions/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/CriticalSectionFunctions/test1/InitializeCriticalSection.c235
-rw-r--r--src/pal/tests/palsuite/threading/CriticalSectionFunctions/test1/testinfo.dat21
-rw-r--r--src/pal/tests/palsuite/threading/CriticalSectionFunctions/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/CriticalSectionFunctions/test2/test2.c226
-rw-r--r--src/pal/tests/palsuite/threading/CriticalSectionFunctions/test2/testinfo.dat18
-rw-r--r--src/pal/tests/palsuite/threading/CriticalSectionFunctions/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/CriticalSectionFunctions/test3/test3.c376
-rw-r--r--src/pal/tests/palsuite/threading/CriticalSectionFunctions/test3/testinfo.dat29
-rw-r--r--src/pal/tests/palsuite/threading/CriticalSectionFunctions/test4/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/CriticalSectionFunctions/test4/test4.c241
-rw-r--r--src/pal/tests/palsuite/threading/CriticalSectionFunctions/test4/testinfo.dat17
-rw-r--r--src/pal/tests/palsuite/threading/CriticalSectionFunctions/test5/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/CriticalSectionFunctions/test5/test5.c187
-rw-r--r--src/pal/tests/palsuite/threading/CriticalSectionFunctions/test5/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/threading/CriticalSectionFunctions/test6/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/CriticalSectionFunctions/test6/test6.c190
-rw-r--r--src/pal/tests/palsuite/threading/CriticalSectionFunctions/test6/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/threading/CriticalSectionFunctions/test7/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/CriticalSectionFunctions/test7/test7.c188
-rw-r--r--src/pal/tests/palsuite/threading/CriticalSectionFunctions/test7/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/threading/CriticalSectionFunctions/test8/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/CriticalSectionFunctions/test8/test8.c217
-rw-r--r--src/pal/tests/palsuite/threading/CriticalSectionFunctions/test8/thistest.dat2
-rw-r--r--src/pal/tests/palsuite/threading/DisableThreadLibraryCalls/test1/test1.c145
-rw-r--r--src/pal/tests/palsuite/threading/DisableThreadLibraryCalls/test1/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/threading/DisableThreadLibraryCalls/test1/testlib.c47
-rw-r--r--src/pal/tests/palsuite/threading/DisableThreadLibraryCalls/test2/dllmain1.c66
-rw-r--r--src/pal/tests/palsuite/threading/DisableThreadLibraryCalls/test2/dllmain2.c66
-rw-r--r--src/pal/tests/palsuite/threading/DisableThreadLibraryCalls/test2/test2.c237
-rw-r--r--src/pal/tests/palsuite/threading/DisableThreadLibraryCalls/test2/testinfo.dat18
-rw-r--r--src/pal/tests/palsuite/threading/DuplicateHandle/CMakeLists.txt15
-rw-r--r--src/pal/tests/palsuite/threading/DuplicateHandle/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/DuplicateHandle/test1/test1.c152
-rw-r--r--src/pal/tests/palsuite/threading/DuplicateHandle/test1/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/threading/DuplicateHandle/test10/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/DuplicateHandle/test10/test10.c239
-rw-r--r--src/pal/tests/palsuite/threading/DuplicateHandle/test10/testinfo.dat17
-rw-r--r--src/pal/tests/palsuite/threading/DuplicateHandle/test11/CMakeLists.txt36
-rw-r--r--src/pal/tests/palsuite/threading/DuplicateHandle/test11/childprocess.c74
-rw-r--r--src/pal/tests/palsuite/threading/DuplicateHandle/test11/myexitcode.h13
-rw-r--r--src/pal/tests/palsuite/threading/DuplicateHandle/test11/test11.c364
-rw-r--r--src/pal/tests/palsuite/threading/DuplicateHandle/test11/testinfo.dat19
-rw-r--r--src/pal/tests/palsuite/threading/DuplicateHandle/test12/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/DuplicateHandle/test12/test12.c129
-rw-r--r--src/pal/tests/palsuite/threading/DuplicateHandle/test12/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/threading/DuplicateHandle/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/DuplicateHandle/test2/test2.c96
-rw-r--r--src/pal/tests/palsuite/threading/DuplicateHandle/test2/testinfo.dat17
-rw-r--r--src/pal/tests/palsuite/threading/DuplicateHandle/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/DuplicateHandle/test3/test3.c123
-rw-r--r--src/pal/tests/palsuite/threading/DuplicateHandle/test3/testinfo.dat17
-rw-r--r--src/pal/tests/palsuite/threading/DuplicateHandle/test4/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/DuplicateHandle/test4/test4.c239
-rw-r--r--src/pal/tests/palsuite/threading/DuplicateHandle/test4/testinfo.dat19
-rw-r--r--src/pal/tests/palsuite/threading/DuplicateHandle/test5/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/DuplicateHandle/test5/test5.c145
-rw-r--r--src/pal/tests/palsuite/threading/DuplicateHandle/test5/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/threading/DuplicateHandle/test6/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/DuplicateHandle/test6/test6.c146
-rw-r--r--src/pal/tests/palsuite/threading/DuplicateHandle/test6/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/threading/DuplicateHandle/test7/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/DuplicateHandle/test7/test7.c149
-rw-r--r--src/pal/tests/palsuite/threading/DuplicateHandle/test7/testinfo.dat16
-rw-r--r--src/pal/tests/palsuite/threading/DuplicateHandle/test8/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/DuplicateHandle/test8/test8.c164
-rw-r--r--src/pal/tests/palsuite/threading/DuplicateHandle/test8/testinfo.dat16
-rw-r--r--src/pal/tests/palsuite/threading/DuplicateHandle/test9/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/DuplicateHandle/test9/test9.c127
-rw-r--r--src/pal/tests/palsuite/threading/DuplicateHandle/test9/testinfo.dat17
-rw-r--r--src/pal/tests/palsuite/threading/ExitProcess/CMakeLists.txt6
-rw-r--r--src/pal/tests/palsuite/threading/ExitProcess/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/ExitProcess/test1/ExitProcess.c32
-rw-r--r--src/pal/tests/palsuite/threading/ExitProcess/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/threading/ExitProcess/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/ExitProcess/test2/test2.c30
-rw-r--r--src/pal/tests/palsuite/threading/ExitProcess/test2/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/threading/ExitProcess/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/ExitProcess/test3/test3.c40
-rw-r--r--src/pal/tests/palsuite/threading/ExitProcess/test3/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/threading/ExitThread/CMakeLists.txt5
-rw-r--r--src/pal/tests/palsuite/threading/ExitThread/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/ExitThread/test1/test1.c114
-rw-r--r--src/pal/tests/palsuite/threading/ExitThread/test1/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/threading/ExitThread/test2/CMakeLists.txt36
-rw-r--r--src/pal/tests/palsuite/threading/ExitThread/test2/childprocess.c41
-rw-r--r--src/pal/tests/palsuite/threading/ExitThread/test2/myexitcode.h14
-rw-r--r--src/pal/tests/palsuite/threading/ExitThread/test2/test2.c168
-rw-r--r--src/pal/tests/palsuite/threading/ExitThread/test2/testinfo.dat19
-rw-r--r--src/pal/tests/palsuite/threading/ExitThread/test3/dllmain.c65
-rw-r--r--src/pal/tests/palsuite/threading/ExitThread/test3/test3.c162
-rw-r--r--src/pal/tests/palsuite/threading/ExitThread/test3/testinfo.dat16
-rw-r--r--src/pal/tests/palsuite/threading/GetCurrentProcess/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/threading/GetCurrentProcess/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/GetCurrentProcess/test1/process.c40
-rw-r--r--src/pal/tests/palsuite/threading/GetCurrentProcess/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/threading/GetCurrentProcessId/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/threading/GetCurrentProcessId/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/GetCurrentProcessId/test1/processId.c41
-rw-r--r--src/pal/tests/palsuite/threading/GetCurrentProcessId/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/threading/GetCurrentThread/CMakeLists.txt5
-rw-r--r--src/pal/tests/palsuite/threading/GetCurrentThread/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/GetCurrentThread/test1/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/threading/GetCurrentThread/test1/thread.c93
-rw-r--r--src/pal/tests/palsuite/threading/GetCurrentThread/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/GetCurrentThread/test2/test2.c144
-rw-r--r--src/pal/tests/palsuite/threading/GetCurrentThread/test2/testinfo.dat18
-rw-r--r--src/pal/tests/palsuite/threading/GetCurrentThreadId/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/threading/GetCurrentThreadId/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/GetCurrentThreadId/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/threading/GetCurrentThreadId/test1/threadId.c82
-rw-r--r--src/pal/tests/palsuite/threading/GetExitCodeProcess/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/threading/GetExitCodeProcess/test1/CMakeLists.txt36
-rw-r--r--src/pal/tests/palsuite/threading/GetExitCodeProcess/test1/childProcess.c31
-rw-r--r--src/pal/tests/palsuite/threading/GetExitCodeProcess/test1/myexitcode.h14
-rw-r--r--src/pal/tests/palsuite/threading/GetExitCodeProcess/test1/test1.c163
-rw-r--r--src/pal/tests/palsuite/threading/GetExitCodeProcess/test1/testinfo.dat16
-rw-r--r--src/pal/tests/palsuite/threading/GetProcessTimes/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/threading/GetProcessTimes/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/GetProcessTimes/test2/test2.c122
-rw-r--r--src/pal/tests/palsuite/threading/GetProcessTimes/test2/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/threading/GetThreadTimes/CMakeLists.txt3
-rw-r--r--src/pal/tests/palsuite/threading/GetThreadTimes/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/GetThreadTimes/test1/test1.c102
-rw-r--r--src/pal/tests/palsuite/threading/NamedMutex/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/threading/NamedMutex/test1/CMakeLists.txt20
-rw-r--r--src/pal/tests/palsuite/threading/NamedMutex/test1/namedmutex.cpp1058
-rw-r--r--src/pal/tests/palsuite/threading/NamedMutex/test1/nopal.cpp65
-rw-r--r--src/pal/tests/palsuite/threading/NamedMutex/test1/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/threading/OpenEventW/CMakeLists.txt8
-rw-r--r--src/pal/tests/palsuite/threading/OpenEventW/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/OpenEventW/test1/test1.c134
-rw-r--r--src/pal/tests/palsuite/threading/OpenEventW/test1/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/threading/OpenEventW/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/OpenEventW/test2/test2.c194
-rw-r--r--src/pal/tests/palsuite/threading/OpenEventW/test2/testinfo.dat17
-rw-r--r--src/pal/tests/palsuite/threading/OpenEventW/test3/CMakeLists.txt36
-rw-r--r--src/pal/tests/palsuite/threading/OpenEventW/test3/childprocess.c81
-rw-r--r--src/pal/tests/palsuite/threading/OpenEventW/test3/test3.c187
-rw-r--r--src/pal/tests/palsuite/threading/OpenEventW/test3/testinfo.dat21
-rw-r--r--src/pal/tests/palsuite/threading/OpenEventW/test4/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/OpenEventW/test4/test4.c112
-rw-r--r--src/pal/tests/palsuite/threading/OpenEventW/test4/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/threading/OpenEventW/test5/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/OpenEventW/test5/test5.c197
-rw-r--r--src/pal/tests/palsuite/threading/OpenEventW/test5/testinfo.dat19
-rw-r--r--src/pal/tests/palsuite/threading/OpenProcess/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/threading/OpenProcess/test1/CMakeLists.txt36
-rw-r--r--src/pal/tests/palsuite/threading/OpenProcess/test1/childProcess.c75
-rw-r--r--src/pal/tests/palsuite/threading/OpenProcess/test1/myexitcode.h14
-rw-r--r--src/pal/tests/palsuite/threading/OpenProcess/test1/test1.c282
-rw-r--r--src/pal/tests/palsuite/threading/OpenProcess/test1/testinfo.dat19
-rw-r--r--src/pal/tests/palsuite/threading/QueryThreadCycleTime/CMakeLists.txt3
-rw-r--r--src/pal/tests/palsuite/threading/QueryThreadCycleTime/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/QueryThreadCycleTime/test1/test1.c98
-rw-r--r--src/pal/tests/palsuite/threading/QueueUserAPC/CMakeLists.txt10
-rw-r--r--src/pal/tests/palsuite/threading/QueueUserAPC/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/QueueUserAPC/test1/test1.c313
-rw-r--r--src/pal/tests/palsuite/threading/QueueUserAPC/test1/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/threading/QueueUserAPC/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/QueueUserAPC/test2/test2.c224
-rw-r--r--src/pal/tests/palsuite/threading/QueueUserAPC/test2/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/threading/QueueUserAPC/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/QueueUserAPC/test3/test3.c33
-rw-r--r--src/pal/tests/palsuite/threading/QueueUserAPC/test3/testinfo.dat12
-rw-r--r--src/pal/tests/palsuite/threading/QueueUserAPC/test4/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/QueueUserAPC/test4/test4.c72
-rw-r--r--src/pal/tests/palsuite/threading/QueueUserAPC/test4/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/threading/QueueUserAPC/test5/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/QueueUserAPC/test5/test5.c200
-rw-r--r--src/pal/tests/palsuite/threading/QueueUserAPC/test5/testinfo.dat20
-rw-r--r--src/pal/tests/palsuite/threading/QueueUserAPC/test6/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/QueueUserAPC/test6/test6.c129
-rw-r--r--src/pal/tests/palsuite/threading/QueueUserAPC/test6/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/threading/QueueUserAPC/test7/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/QueueUserAPC/test7/test7.c253
-rw-r--r--src/pal/tests/palsuite/threading/QueueUserAPC/test7/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/threading/ReleaseMutex/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/threading/ReleaseMutex/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/ReleaseMutex/test3/ReleaseMutex.c103
-rw-r--r--src/pal/tests/palsuite/threading/ReleaseMutex/test3/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/threading/ResetEvent/CMakeLists.txt7
-rw-r--r--src/pal/tests/palsuite/threading/ResetEvent/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/ResetEvent/test1/test1.c99
-rw-r--r--src/pal/tests/palsuite/threading/ResetEvent/test1/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/threading/ResetEvent/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/ResetEvent/test2/test2.c89
-rw-r--r--src/pal/tests/palsuite/threading/ResetEvent/test2/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/threading/ResetEvent/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/ResetEvent/test3/test3.c86
-rw-r--r--src/pal/tests/palsuite/threading/ResetEvent/test3/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/threading/ResetEvent/test4/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/ResetEvent/test4/test4.c161
-rw-r--r--src/pal/tests/palsuite/threading/ResetEvent/test4/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/threading/ResumeThread/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/threading/ResumeThread/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/ResumeThread/test1/test1.c141
-rw-r--r--src/pal/tests/palsuite/threading/ResumeThread/test1/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/threading/SetErrorMode/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/threading/SetErrorMode/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/SetErrorMode/test1/test1.c50
-rw-r--r--src/pal/tests/palsuite/threading/SetErrorMode/test1/testinfo.dat16
-rw-r--r--src/pal/tests/palsuite/threading/SetEvent/CMakeLists.txt7
-rw-r--r--src/pal/tests/palsuite/threading/SetEvent/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/SetEvent/test1/test1.c94
-rw-r--r--src/pal/tests/palsuite/threading/SetEvent/test1/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/threading/SetEvent/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/SetEvent/test2/test2.c125
-rw-r--r--src/pal/tests/palsuite/threading/SetEvent/test2/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/threading/SetEvent/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/SetEvent/test3/test3.c85
-rw-r--r--src/pal/tests/palsuite/threading/SetEvent/test3/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/threading/SetEvent/test4/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/SetEvent/test4/test4.c161
-rw-r--r--src/pal/tests/palsuite/threading/SetEvent/test4/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/threading/Sleep/CMakeLists.txt5
-rw-r--r--src/pal/tests/palsuite/threading/Sleep/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/Sleep/test1/Sleep.c80
-rw-r--r--src/pal/tests/palsuite/threading/Sleep/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/threading/Sleep/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/Sleep/test2/sleep.c73
-rw-r--r--src/pal/tests/palsuite/threading/Sleep/test2/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/threading/SleepEx/CMakeLists.txt5
-rw-r--r--src/pal/tests/palsuite/threading/SleepEx/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/SleepEx/test1/test1.c89
-rw-r--r--src/pal/tests/palsuite/threading/SleepEx/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/threading/SleepEx/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/SleepEx/test2/test2.c183
-rw-r--r--src/pal/tests/palsuite/threading/SleepEx/test2/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/threading/SwitchToThread/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/threading/SwitchToThread/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/SwitchToThread/test1/test1.c97
-rw-r--r--src/pal/tests/palsuite/threading/SwitchToThread/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/threading/TLS/CMakeLists.txt9
-rw-r--r--src/pal/tests/palsuite/threading/TLS/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/TLS/test1/TLS.c182
-rw-r--r--src/pal/tests/palsuite/threading/TLS/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/threading/TLS/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/TLS/test2/TLS.c66
-rw-r--r--src/pal/tests/palsuite/threading/TLS/test2/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/threading/TLS/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/TLS/test3/TLS.c90
-rw-r--r--src/pal/tests/palsuite/threading/TLS/test3/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/threading/TLS/test4/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/TLS/test4/test4.c137
-rw-r--r--src/pal/tests/palsuite/threading/TLS/test4/testinfo.dat15
-rw-r--r--src/pal/tests/palsuite/threading/TLS/test5/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/TLS/test5/test5.c108
-rw-r--r--src/pal/tests/palsuite/threading/TLS/test5/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/threading/TLS/test6_optimizedtls/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/TLS/test6_optimizedtls/test.c190
-rw-r--r--src/pal/tests/palsuite/threading/TLS/test6_optimizedtls/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/threading/TerminateProcess/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/threading/TerminateProcess/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/TerminateProcess/test1/TerminateProcess.c41
-rw-r--r--src/pal/tests/palsuite/threading/TerminateProcess/test1/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/threading/ThreadPriority/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/threading/ThreadPriority/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/ThreadPriority/test1/ThreadPriority.c83
-rw-r--r--src/pal/tests/palsuite/threading/ThreadPriority/test1/testinfo.dat17
-rw-r--r--src/pal/tests/palsuite/threading/WaitForMultipleObjects/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/threading/WaitForMultipleObjects/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/WaitForMultipleObjects/test1/test1.c224
-rw-r--r--src/pal/tests/palsuite/threading/WaitForMultipleObjects/test1/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/CMakeLists.txt9
-rw-r--r--src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test1/test1.c226
-rw-r--r--src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test1/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test2/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test2/test2.c188
-rw-r--r--src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test2/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test3/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test3/test3.c106
-rw-r--r--src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test3/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test4/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test4/test4.c101
-rw-r--r--src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test4/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test5/CMakeLists.txt36
-rw-r--r--src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test5/commonconsts.h42
-rw-r--r--src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test5/helper.c122
-rw-r--r--src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test5/test5.c506
-rw-r--r--src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test5/testinfo.dat18
-rw-r--r--src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test6/CMakeLists.txt36
-rw-r--r--src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test6/child6.c211
-rw-r--r--src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test6/test6.c709
-rw-r--r--src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test6/thistest.dat2
-rw-r--r--src/pal/tests/palsuite/threading/WaitForSingleObject/CMakeLists.txt11
-rw-r--r--src/pal/tests/palsuite/threading/WaitForSingleObject/WFSOExMutexTest/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/WaitForSingleObject/WFSOExMutexTest/WFSOExMutexTest.c214
-rw-r--r--src/pal/tests/palsuite/threading/WaitForSingleObject/WFSOExSemaphoreTest/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/WaitForSingleObject/WFSOExSemaphoreTest/WFSOExSemaphoreTest.c184
-rw-r--r--src/pal/tests/palsuite/threading/WaitForSingleObject/WFSOExThreadTest/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/WaitForSingleObject/WFSOExThreadTest/WFSOExThreadTest.c204
-rw-r--r--src/pal/tests/palsuite/threading/WaitForSingleObject/WFSOMutexTest/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/WaitForSingleObject/WFSOMutexTest/WFSOMutexTest.c184
-rw-r--r--src/pal/tests/palsuite/threading/WaitForSingleObject/WFSOProcessTest/CMakeLists.txt36
-rw-r--r--src/pal/tests/palsuite/threading/WaitForSingleObject/WFSOProcessTest/ChildProcess.c50
-rw-r--r--src/pal/tests/palsuite/threading/WaitForSingleObject/WFSOProcessTest/WFSOProcessTest.c119
-rw-r--r--src/pal/tests/palsuite/threading/WaitForSingleObject/WFSOSemaphoreTest/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/WaitForSingleObject/WFSOSemaphoreTest/WFSOSemaphoreTest.c183
-rw-r--r--src/pal/tests/palsuite/threading/WaitForSingleObject/WFSOThreadTest/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/WaitForSingleObject/WFSOThreadTest/WFSOThreadTest.c179
-rw-r--r--src/pal/tests/palsuite/threading/WaitForSingleObject/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/WaitForSingleObject/test1/test1.c121
-rw-r--r--src/pal/tests/palsuite/threading/WaitForSingleObject/test1/testinfo.dat14
-rw-r--r--src/pal/tests/palsuite/threading/YieldProcessor/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/threading/YieldProcessor/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/YieldProcessor/test1/test1.c92
-rw-r--r--src/pal/tests/palsuite/threading/YieldProcessor/test1/testinfo.dat13
-rw-r--r--src/pal/tests/palsuite/threading/releasesemaphore/CMakeLists.txt4
-rw-r--r--src/pal/tests/palsuite/threading/releasesemaphore/test1/CMakeLists.txt19
-rw-r--r--src/pal/tests/palsuite/threading/releasesemaphore/test1/test.c68
-rw-r--r--src/pal/tests/palsuite/threading/releasesemaphore/test1/testinfo.dat15
-rw-r--r--src/pal/tools/clang-compiler-override.txt20
-rwxr-xr-xsrc/pal/tools/gen-buildsys-clang.sh154
-rw-r--r--src/pal/tools/gen-buildsys-win.bat54
-rw-r--r--src/pal/tools/gen-dactable-rva.sh1
-rwxr-xr-xsrc/pal/tools/preptests.sh69
-rw-r--r--src/pal/tools/probe-win.ps160
-rwxr-xr-xsrc/pal/tools/setup-ubuntuvm.sh27
-rwxr-xr-xsrc/pal/tools/smarty.sh26
-rw-r--r--src/pal/tools/windows-compiler-override.txt16
3984 files changed, 389911 insertions, 0 deletions
diff --git a/src/pal/.gitmirrorall b/src/pal/.gitmirrorall
new file mode 100644
index 0000000000..9ee5c57b99
--- /dev/null
+++ b/src/pal/.gitmirrorall
@@ -0,0 +1 @@
+This folder will be mirrored by the Git-TFS Mirror recursively. \ No newline at end of file
diff --git a/src/pal/CMakeLists.txt b/src/pal/CMakeLists.txt
new file mode 100644
index 0000000000..cb8b05586c
--- /dev/null
+++ b/src/pal/CMakeLists.txt
@@ -0,0 +1,23 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+project(COREPAL)
+
+if (WIN32)
+ set(FEATURE_EVENT_TRACE 1)
+endif()
+if(CLR_CMAKE_PLATFORM_LINUX AND CLR_CMAKE_PLATFORM_ARCH_AMD64)
+ set(FEATURE_EVENT_TRACE 1)
+endif()
+
+include_directories(${COREPAL_SOURCE_DIR}/inc)
+include_directories(${COREPAL_SOURCE_DIR}/src)
+include_directories(${COREPAL_SOURCE_DIR}/../inc)
+
+add_compile_options(-fexceptions)
+
+add_subdirectory(src)
+
+if(CLR_CMAKE_BUILD_TESTS)
+ add_subdirectory(tests)
+endif(CLR_CMAKE_BUILD_TESTS)
+
diff --git a/src/pal/automation/automation.py b/src/pal/automation/automation.py
new file mode 100644
index 0000000000..d8ddaa9117
--- /dev/null
+++ b/src/pal/automation/automation.py
@@ -0,0 +1,78 @@
+import logging as log
+import sys
+import getopt
+import os
+import subprocess
+import shutil
+import compile
+import tests
+import util
+
+target = ""
+arch = ""
+platform = ""
+workspace = ""
+fullbuilddirpath = ""
+cleanUp = True
+
+def ParseArgs(argv):
+ global target
+ global platform
+ global arch
+ global cleanUp
+
+ returncode,target,platform,arch,cleanUp = util.ParseArgs(argv)
+ return returncode
+
+def Initialize():
+ global workspace
+ workspace = util.Initialize(platform)
+ return 0
+
+def SetupDirectories():
+ global fullbuilddirpath
+ fullbuilddirpath = util.SetupDirectories(target, arch, platform)
+
+ return 0
+
+def CopyBinaries():
+ print "\n==================================================\n"
+ print "Stub for copying binaries"
+ print "\n==================================================\n"
+
+ return 0
+
+def main(argv):
+ returncode = ParseArgs(argv)
+ if returncode != 0:
+ return returncode
+
+ returncode += Initialize()
+ if returncode != 0:
+ return returncode
+
+ returncode += SetupDirectories()
+ if returncode != 0:
+ return returncode
+
+ returncode += compile.Compile(workspace, target, platform, arch)
+ if returncode != 0:
+ return returncode
+
+ returncode += CopyBinaries()
+ if returncode != 0:
+ return returncode
+
+ returncode += tests.RunTests(platform, fullbuilddirpath, workspace)
+ if returncode != 0:
+ return returncode
+
+ return returncode
+
+if __name__ == "__main__":
+ returncode = main(sys.argv[1:])
+
+ util.Cleanup(cleanUp,workspace)
+
+ sys.exit(returncode)
+
diff --git a/src/pal/automation/compile.py b/src/pal/automation/compile.py
new file mode 100644
index 0000000000..bb9d1b88ac
--- /dev/null
+++ b/src/pal/automation/compile.py
@@ -0,0 +1,70 @@
+import logging as log
+import sys
+import getopt
+import os
+import subprocess
+import shutil
+
+def RunCMake(workspace, target, platform):
+ # run CMake
+ print "\n==================================================\n"
+
+ returncode = 0
+ if platform == "windows":
+ print "Running: vcvarsall.bat x86_amd64 && " + workspace + "\ProjectK\NDP\clr\src\pal\\tools\gen-buildsys-win.bat " + workspace + "\ProjectK\NDP\clr"
+ print "\n==================================================\n"
+ sys.stdout.flush()
+ returncode = subprocess.call(["vcvarsall.bat", "x86_amd64", "&&", workspace + "\ProjectK\NDP\clr\src\pal\\tools\gen-buildsys-win.bat", workspace + "\ProjectK\NDP\clr"])
+ elif platform == "linux":
+ print "Running: " + workspace + "/ProjectK/NDP/clr/src/pal/tools/gen-buildsys-clang.sh " + workspace + "/ProjectK/NDP/clr DEBUG"
+ print "\n==================================================\n"
+ sys.stdout.flush()
+ returncode = subprocess.call(workspace + "/ProjectK/NDP/clr/src/pal/tools/gen-buildsys-clang.sh " + workspace + "/ProjectK/NDP/clr " + target, shell=True)
+
+ if returncode != 0:
+ print "ERROR: cmake failed with exit code " + str(returncode)
+
+ return returncode
+
+def RunBuild(target, platform, arch):
+ if platform == "windows":
+ return RunMsBuild(target, arch)
+ elif platform == "linux":
+ return RunMake()
+
+def RunMsBuild(target, arch):
+ # run MsBuild
+ print "\n==================================================\n"
+ print "Running: vcvarsall.bat x86_amd64 && msbuild CoreCLR.sln /p:Configuration=" + target + " /p:Platform=" + arch
+ print "\n==================================================\n"
+ sys.stdout.flush()
+
+ returncode = subprocess.call(["vcvarsall.bat","x86_amd64","&&","msbuild","CoreCLR.sln","/p:Configuration=" + target,"/p:Platform=" + arch])
+
+ if returncode != 0:
+ print "ERROR: vcvarsall.bat failed with exit code " + str(returncode)
+
+ return returncode
+
+def RunMake():
+ print "\n==================================================\n"
+ print "Running: make"
+ print "\n==================================================\n"
+ sys.stdout.flush()
+ returncode = subprocess.call(["make"])
+
+ if returncode != 0:
+ print "ERROR: make failed with exit code " + str(returncode)
+
+ return returncode
+
+def Compile(workspace, target, platform, arch):
+ returncode = RunCMake(workspace, target, platform)
+ if returncode != 0:
+ return returncode
+
+ returncode += RunBuild(target, platform, arch)
+ if returncode != 0:
+ return returncode
+
+ return returncode
diff --git a/src/pal/automation/tests.py b/src/pal/automation/tests.py
new file mode 100644
index 0000000000..e48e84fd1d
--- /dev/null
+++ b/src/pal/automation/tests.py
@@ -0,0 +1,33 @@
+import sys
+import getopt
+import os
+import subprocess
+import shutil
+import logging as log
+
+def RunPalTests(fullbuilddirpath, workspace):
+ print "\n==================================================\n"
+ print "Running PAL Tests."
+ print "\n==================================================\n"
+
+ print "Running: " + workspace + "/ProjectK/NDP/clr/src/pal/tests/palsuite/runpaltests.sh " + fullbuilddirpath + " " + fullbuilddirpath + "/PalTestOutput"
+ print "\n==================================================\n"
+ sys.stdout.flush()
+ returncode = subprocess.call(workspace + "/ProjectK/NDP/clr/src/pal/tests/palsuite/runpaltests.sh " + fullbuilddirpath + " " + fullbuilddirpath + "/PalTestOutput", shell=True)
+
+ if returncode != 0:
+ print "ERROR: there were errors failed with exit code " + str(returncode)
+
+ return returncode
+
+
+def RunTests(platform, fullbuilddirpath, workspace):
+ returncode = 0
+
+ if platform == "linux":
+ # Execute PAL tests
+ returncode = RunPalTests(fullbuilddirpath, workspace)
+
+ return returncode
+
+
diff --git a/src/pal/automation/util.py b/src/pal/automation/util.py
new file mode 100644
index 0000000000..790cbc4dbf
--- /dev/null
+++ b/src/pal/automation/util.py
@@ -0,0 +1,97 @@
+import sys
+import getopt
+import os
+import subprocess
+import shutil
+import logging as log
+
+def Initialize(platform):
+ print "Initializing Workspace"
+ global workspace
+ workspace = os.environ['WORKSPACE']
+ if platform == "windows":
+ # Jenkins puts quotes in the path, which is wrong. Remove quotes.
+ os.environ['PATH'] = os.environ['PATH'].replace('"','')
+
+ return workspace
+
+def ParseArgs(argv):
+ print "Parsing arguments for compile"
+ try:
+ opts, args = getopt.getopt(argv, "t:p:a:v", ["target=", "platform=", "arch=", "verbose","noclean"])
+ except getopt.GetoptError:
+ print "ERROR: \n\t usage: python compile.py --target <target> --platform <windows|linux> --arch <arch> [--verbose] [--noclean]"
+ return 2,"","","",True
+
+ verbose = False
+ cleanUp = True
+
+ acceptedPlatforms = ['windows','linux']
+
+ for opt, arg in opts:
+ if opt in ("-t", "--target"):
+ target = arg
+ elif opt in ("-p", "--platform"):
+ if arg.lower() not in acceptedPlatforms:
+ print "ERROR: " + arg + "not an accepted platform. Use windows or linux."
+ sys.exit(2)
+ platform = arg.lower()
+ elif opt in ("-a", "--arch"):
+ arch = arg
+ elif opt in ("-v", "--verbose"):
+ verbose = True
+ elif opt in ("-c", "--noclean"):
+ cleanUp = False
+
+ if verbose:
+ log.basicConfig(format="%(levelname)s: %(message)s", level=log.DEBUG)
+ log.info("In verbose mode.")
+ else:
+ log.basicConfig(format="%(levelname)s: %(message)s")
+
+ if target == "" or platform == "" or arch == "":
+ # must specify target, project and arch
+ log.error("Must specify target, project and arch")
+ return 2,"","","",True
+
+ return 0,target,platform,arch,cleanUp
+
+def SetupDirectories(target, arch, platform):
+ log.info("Setting up directories")
+
+ global rootdir
+ global builddir
+ global fullBuildDirPath
+
+ rootdir = "build"
+ if not os.path.isdir(rootdir):
+ os.mkdir(rootdir)
+ os.chdir(rootdir)
+
+ builddir = "build-" + platform
+
+ if platform == "windows":
+ builddir = builddir + "-" + arch + "-" + target
+
+ if os.path.isdir(builddir):
+ shutil.rmtree(builddir)
+ os.mkdir(builddir)
+ os.chdir(builddir)
+
+ fullbuilddirpath = workspace + "/" + rootdir + "/" + builddir
+
+ return fullbuilddirpath
+
+def Cleanup(cleanUp,workspace):
+ print "\n==================================================\n"
+ print "Cleaning Up."
+ print "\n==================================================\n"
+
+ if cleanUp:
+ os.chdir(workspace + "/" + rootdir)
+ shutil.rmtree(builddir)
+ os.chdir("..")
+ shutil.rmtree(rootdir)
+
+ log.shutdown()
+ return 0
diff --git a/src/pal/inc/mbusafecrt.h b/src/pal/inc/mbusafecrt.h
new file mode 100644
index 0000000000..c25676c499
--- /dev/null
+++ b/src/pal/inc/mbusafecrt.h
@@ -0,0 +1,118 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+* mbusafecrt.h - public declarations for SafeCRT lib
+*
+
+*
+* Purpose:
+* This file contains the public declarations SafeCRT
+* functions ported to MacOS. These are the safe versions of
+* functions standard functions banned by SWI
+*
+
+****/
+
+/* shields! */
+
+#ifndef MBUSAFECRT_H
+#define MBUSAFECRT_H
+
+//#include <wchar.h>
+
+/* MacOS does not define a specifc type for errnos, but SafeCRT does */
+typedef int errno_t;
+
+/* errno value that specific to SafeCRT */
+#define STRUNCATE 80
+
+// define the return value for success
+#define SAFECRT_SUCCESS 0
+
+/*
+ * Sizes for buffers used by the _makepath() and _splitpath() functions.
+ * note that the sizes include space for 0-terminator
+ */
+//#define _MAX_PATH 260 /* max. length of full pathname */
+//#define _MAX_DRIVE 3 /* max. length of drive component */
+//#define _MAX_DIR 256 /* max. length of path component */
+//#define _MAX_FNAME 256 /* max. length of file name component */
+//#define _MAX_EXT 256 /* max. length of extension component */
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+typedef void ( *tSafeCRT_AssertFuncPtr )( const char* inExpression, const char* inComment, const char* inFile, const unsigned long inLineNum );
+void MBUSafeCRTSetAssertFunc( tSafeCRT_AssertFuncPtr inAssertFuncPtr );
+
+extern errno_t strcat_s( char* ioDest, size_t inDestBufferSize, const char* inSrc );
+extern errno_t wcscat_s( WCHAR* ioDest, size_t inDestBufferSize, const WCHAR* inSrc );
+
+extern errno_t strncat_s( char* ioDest, size_t inDestBufferSize, const char* inSrc, size_t inCount );
+extern errno_t wcsncat_s( WCHAR* ioDest, size_t inDestBufferSize, const WCHAR* inSrc, size_t inCount );
+
+extern errno_t strcpy_s( char* outDest, size_t inDestBufferSize, const char* inSrc );
+extern errno_t wcscpy_s( WCHAR* outDest, size_t inDestBufferSize, const WCHAR* inSrc );
+
+extern errno_t strncpy_s( char* outDest, size_t inDestBufferSize, const char* inSrc, size_t inCount );
+extern errno_t wcsncpy_s( WCHAR* outDest, size_t inDestBufferSize, const WCHAR* inSrc, size_t inCount );
+
+extern char* strtok_s( char* inString, const char* inControl, char** ioContext );
+extern WCHAR* wcstok_s( WCHAR* inString, const WCHAR* inControl, WCHAR** ioContext );
+
+// strnlen is not required unless the source string is completely untrusted (e.g. anonymous input on a website)
+#ifndef SUPPRESS_STRNLEN
+ extern size_t strnlen( const char* inString, size_t inMaxSize );
+ extern size_t wcsnlen( const WCHAR* inString, size_t inMaxSize );
+#endif
+
+extern errno_t _itoa_s( int inValue, char* outBuffer, size_t inDestBufferSize, int inRadix );
+extern errno_t _itow_s( int inValue, WCHAR* outBuffer, size_t inDestBufferSize, int inRadix );
+
+extern errno_t _ltoa_s( long inValue, char* outBuffer, size_t inDestBufferSize, int inRadix );
+extern errno_t _ltow_s( long inValue, WCHAR* outBuffer, size_t inDestBufferSize, int inRadix );
+
+extern errno_t _ultoa_s( unsigned long inValue, char* outBuffer, size_t inDestBufferSize, int inRadix );
+extern errno_t _ultow_s( unsigned long inValue, WCHAR* outBuffer, size_t inDestBufferSize, int inRadix );
+
+extern errno_t _i64toa_s( long long inValue, char* outBuffer, size_t inDestBufferSize, int inRadix );
+extern errno_t _i64tow_s( long long inValue, WCHAR* outBuffer, size_t inDestBufferSize, int inRadix );
+
+extern errno_t _ui64toa_s( unsigned long long inValue, char* outBuffer, size_t inDestBufferSize, int inRadix );
+extern errno_t _ui64tow_s( unsigned long long inValue, WCHAR* outBuffer, size_t inDestBufferSize, int inRadix );
+
+extern errno_t _makepath_s( char* outDest, size_t inDestBufferSize, const char* inDrive, const char* inDirectory, const char* inFilename, const char* inExtension );
+extern errno_t _wmakepath_s( WCHAR* outDest, size_t inDestBufferSize, const WCHAR* inDrive, const WCHAR* inDirectory, const WCHAR* inFilename, const WCHAR* inExtension );
+
+extern errno_t _splitpath_s( const char* inPath, char* outDrive, size_t inDriveSize, char* outDirectory, size_t inDirectorySize, char* outFilename, size_t inFilenameSize, char* outExtension, size_t inExtensionSize );
+extern errno_t _wsplitpath_s( const WCHAR* inPath, WCHAR* outDrive, size_t inDriveSize, WCHAR* outDirectory, size_t inDirectorySize, WCHAR* outFilename, size_t inFilenameSize, WCHAR* outExtension, size_t inExtensionSize );
+
+extern int sprintf_s( char *string, size_t sizeInBytes, const char *format, ... );
+extern int swprintf_s( WCHAR *string, size_t sizeInWords, const WCHAR *format, ... );
+
+extern int _snprintf_s( char *string, size_t sizeInBytes, size_t count, const char *format, ... );
+extern int _snwprintf_s( WCHAR *string, size_t sizeInWords, size_t count, const WCHAR *format, ... );
+
+extern int _vsprintf_s( char* string, size_t sizeInBytes, const char* format, va_list arglist );
+extern int _vsnprintf_s( char* string, size_t sizeInBytes, size_t count, const char* format, va_list arglist );
+
+extern int _vswprintf_s( WCHAR* string, size_t sizeInWords, const WCHAR* format, va_list arglist );
+extern int _vsnwprintf_s( WCHAR* string, size_t sizeInWords, size_t count, const WCHAR* format, va_list arglist );
+
+extern int sscanf_s( const char *string, const char *format, ... );
+extern int swscanf_s( const WCHAR *string, const WCHAR *format, ... );
+
+extern int _snscanf_s( const char *string, size_t count, const char *format, ... );
+extern int _snwscanf_s( const WCHAR *string, size_t count, const WCHAR *format, ... );
+
+extern errno_t memcpy_s( void * dst, size_t sizeInBytes, const void * src, size_t count );
+extern errno_t memmove_s( void * dst, size_t sizeInBytes, const void * src, size_t count );
+
+#ifdef __cplusplus
+ }
+#endif
+
+#endif /* MBUSAFECRT_H */
diff --git a/src/pal/inc/pal.h b/src/pal/inc/pal.h
new file mode 100644
index 0000000000..260528285e
--- /dev/null
+++ b/src/pal/inc/pal.h
@@ -0,0 +1,6956 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+Module Name:
+
+ pal.h
+
+Abstract:
+
+ Rotor Platform Adaptation Layer (PAL) header file. This file
+ defines all types and API calls required by the Rotor port of
+ the Microsoft Common Language Runtime.
+
+ Defines which control the behavior of this include file:
+ UNICODE - define it to set the Ansi/Unicode neutral names to
+ be the ...W names. Otherwise the neutral names default
+ to be the ...A names.
+ PAL_IMPLEMENTATION - define it when implementing the PAL. Otherwise
+ leave it undefined when consuming the PAL.
+
+ Note: some fields in structs have been renamed from the original
+ SDK documentation names, with _PAL_Undefined appended. This leaves
+ the structure layout identical to its Win32 version, but prevents
+ PAL consumers from inadvertently referencing undefined fields.
+
+ If you want to add a PAL_ wrapper function to a native function in
+ here, you also need to edit palinternal.h and win32pal.h.
+
+
+
+--*/
+
+#ifndef __PAL_H__
+#define __PAL_H__
+
+#ifdef PAL_STDCPP_COMPAT
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined (PLATFORM_UNIX)
+// 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)
+#define W(str) u##str
+
+// Undefine the QUOTE_MACRO_L helper and redefine it in terms of u.
+// The reason that we do this is that quote macro is defined in ndp\common\inc,
+// not inside of coreclr sources.
+
+#define QUOTE_MACRO_L(x) QUOTE_MACRO_u(x)
+#define QUOTE_MACRO_u_HELPER(x) u###x
+#define QUOTE_MACRO_u(x) QUOTE_MACRO_u_HELPER(x)
+
+#endif
+
+#include <pal_char16.h>
+#include <pal_error.h>
+#include <pal_mstypes.h>
+
+/******************* Processor-specific glue *****************************/
+
+#ifndef _MSC_VER
+
+#if defined(__i686__) && !defined(_M_IX86)
+#define _M_IX86 600
+#elif defined(__i586__) && !defined(_M_IX86)
+#define _M_IX86 500
+#elif defined(__i486__) && !defined(_M_IX86)
+#define _M_IX86 400
+#elif defined(__i386__) && !defined(_M_IX86)
+#define _M_IX86 300
+#elif defined(__ppc__) && !defined(_M_PPC)
+#define _M_PPC 100
+#elif defined(_AIX) && defined(_POWER) && !defined(_M_PPC)
+#define _M_PPC 100
+#elif defined(__sparc__) && !defined(_M_SPARC)
+#define _M_SPARC 100
+#elif defined(__hppa__) && !defined(_M_PARISC)
+#define _M_PARISC 100
+#elif defined(__ia64__) && !defined(_M_IA64)
+#define _M_IA64 64100
+#elif defined(__x86_64__) && !defined(_M_AMD64)
+#define _M_AMD64 100
+#elif defined(__arm__) && !defined(_M_ARM)
+#define _M_ARM 7
+#elif defined(__aarch64__) && !defined(_M_ARM64)
+#define _M_ARM64 1
+#endif
+
+#if defined(_M_IX86) && !defined(_X86_)
+#define _X86_
+#elif defined(_M_ALPHA) && !defined(_ALPHA_)
+#define _ALPHA_
+#elif defined(_M_PPC) && !defined(_PPC_)
+#define _PPC_
+#elif defined(_M_SPARC) && !defined(_SPARC_)
+#define _SPARC_
+#elif defined(_M_PARISC) && !defined(_PARISC_)
+#define _PARISC_
+#elif defined(_M_MRX000) && !defined(_MIPS_)
+#define _MIPS_
+#elif defined(_M_M68K) && !defined(_68K_)
+#define _68K_
+#elif defined(_M_IA64) && !defined(_IA64_)
+#define _IA64_
+#elif defined(_M_AMD64) && !defined(_AMD64_)
+#define _AMD64_
+#elif defined(_M_ARM) && !defined(_ARM_)
+#define _ARM_
+#elif defined(_M_ARM64) && !defined(_ARM64_)
+#define _ARM64_
+#endif
+
+#endif // !_MSC_VER
+
+/******************* ABI-specific glue *******************************/
+
+#if defined(_PPC_) || defined(_PPC64_) || defined(_SPARC_) || defined(_PARISC_) || defined(_IA64_)
+#define BIGENDIAN 1
+#endif
+
+#ifdef __APPLE__
+// Both PowerPC, i386 and x86_64 on Mac OS X use 16-byte alignment.
+#define STACK_ALIGN_BITS 4
+#define STACK_ALIGN_REQ (1 << STACK_ALIGN_BITS)
+#endif
+
+#define MAX_PATH 260
+#define _MAX_PATH 260
+#define _MAX_DRIVE 3 /* max. length of drive component */
+#define _MAX_DIR 256 /* max. length of path component */
+#define _MAX_FNAME 256 /* max. length of file name component */
+#define _MAX_EXT 256 /* max. length of extension component */
+
+// In some Win32 APIs MAX_PATH is used for file names (even though 256 is the normal file system limit)
+// use _MAX_PATH_FNAME to indicate these cases
+#define MAX_PATH_FNAME MAX_PATH
+#define MAX_LONGPATH 1024 /* max. length of full pathname */
+
+#define MAXSHORT 0x7fff
+#define MAXLONG 0x7fffffff
+#define MAXCHAR 0x7f
+#define MAXDWORD 0xffffffff
+
+// Sorting IDs.
+//
+// Note that the named locale APIs (eg CompareStringExEx) are recommended.
+//
+
+#define LANG_CHINESE 0x04
+#define LANG_ENGLISH 0x09
+#define LANG_JAPANESE 0x11
+#define LANG_KOREAN 0x12
+#define LANG_THAI 0x1e
+
+/******************* Compiler-specific glue *******************************/
+
+#ifndef _MSC_VER
+#if defined(CORECLR)
+// Define this if the underlying platform supports true 2-pass EH.
+// At the same time, this enables running several PAL instances
+// side-by-side.
+#define FEATURE_PAL_SXS 1
+#endif // CORECLR
+#endif // !_MSC_VER
+
+#if defined(_MSC_VER) || defined(__llvm__)
+#define DECLSPEC_ALIGN(x) __declspec(align(x))
+#else
+#define DECLSPEC_ALIGN(x)
+#endif
+
+#define DECLSPEC_NORETURN PAL_NORETURN
+
+#if !defined(_MSC_VER) || defined(SOURCE_FORMATTING)
+#define __assume(x) (void)0
+#define __annotation(x)
+#endif //!MSC_VER
+
+#ifdef _MSC_VER
+
+#if defined(_M_MRX000) || defined(_M_ALPHA) || defined(_M_PPC) || defined(_M_IA64)
+#define UNALIGNED __unaligned
+#else
+#define UNALIGNED
+#endif
+
+#else // _MSC_VER
+
+#define UNALIGNED
+
+#endif // _MSC_VER
+
+#ifndef FORCEINLINE
+#if _MSC_VER < 1200
+#define FORCEINLINE inline
+#else
+#define FORCEINLINE __forceinline
+#endif
+#endif
+
+#ifndef PAL_STDCPP_COMPAT
+
+#ifdef _M_ALPHA
+
+typedef struct {
+ char *a0; /* pointer to first homed integer argument */
+ int offset; /* byte offset of next parameter */
+} va_list;
+
+#define va_start(list, v) __builtin_va_start(list, v, 1)
+#define va_end(list)
+
+#elif __GNUC__
+
+#if defined(_AIX)
+
+typedef __builtin_va_list __gnuc_va_list;
+typedef __builtin_va_list va_list;
+#define va_start(v,l) __builtin_va_start(v,l)
+#define va_end __builtin_va_end
+#define va_arg __builtin_va_arg
+
+#else // _AIX
+
+#if __GNUC__ == 2
+typedef void * va_list;
+#else
+typedef __builtin_va_list va_list;
+#endif // __GNUC__
+
+/* We should consider if the va_arg definition here is actually necessary.
+ Could we use the standard va_arg definition? */
+
+#if __GNUC__ == 2
+#if defined(_SPARC_) || defined(_PARISC_) // ToDo: is this the right thing for PARISC?
+#define va_start(list, v) (__builtin_next_arg(v), list = (char *) __builtin_saveregs())
+#define __va_rounded_size(TYPE) \
+ (((sizeof (TYPE) + sizeof (int) - 1) / sizeof (int)) * sizeof (int))
+#define __record_type_class 12
+#define __real_type_class 8
+#define va_arg(pvar,TYPE) \
+__extension__ \
+(*({((__builtin_classify_type (*(TYPE*) 0) >= __record_type_class \
+ || (__builtin_classify_type (*(TYPE*) 0) == __real_type_class \
+ && sizeof (TYPE) == 16)) \
+ ? ((pvar) = (char *)(pvar) + __va_rounded_size (TYPE *), \
+ *(TYPE **) (void *) ((char *)(pvar) - __va_rounded_size (TYPE *))) \
+ : __va_rounded_size (TYPE) == 8 \
+ ? ({ union {char __d[sizeof (TYPE)]; int __i[2];} __u; \
+ __u.__i[0] = ((int *) (void *) (pvar))[0]; \
+ __u.__i[1] = ((int *) (void *) (pvar))[1]; \
+ (pvar) = (char *)(pvar) + 8; \
+ (TYPE *) (void *) __u.__d; }) \
+ : ((pvar) = (char *)(pvar) + __va_rounded_size (TYPE), \
+ ((TYPE *) (void *) ((char *)(pvar) - __va_rounded_size (TYPE)))));}))
+#else // _SPARC_ or _PARISC_
+// GCC 2.95.3 on non-SPARC
+#define __va_size(type) (((sizeof(type) + sizeof(int) - 1) / sizeof(int)) * sizeof(int))
+#define va_start(list, v) ((list) = (va_list) __builtin_next_arg(v))
+#define va_arg(ap, type) (*(type *)((ap) += __va_size(type), (ap) - __va_size(type)))
+#endif // _SPARC_ or _PARISC_
+#else // __GNUC__ == 2
+#define va_start __builtin_va_start
+#define va_arg __builtin_va_arg
+#endif // __GNUC__ == 2
+
+#define va_copy __builtin_va_copy
+#define va_end __builtin_va_end
+
+#endif // _AIX
+
+#define VOID void
+
+#define PUB __attribute__((visibility("default")))
+
+#else // __GNUC__
+
+typedef char * va_list;
+
+#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
+
+#if _MSC_VER >= 1400
+
+#ifdef __cplusplus
+#define _ADDRESSOF(v) ( &reinterpret_cast<const char &>(v) )
+#else
+#define _ADDRESSOF(v) ( &(v) )
+#endif
+
+#define _crt_va_start(ap,v) ( ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v) )
+#define _crt_va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
+#define _crt_va_end(ap) ( ap = (va_list)0 )
+
+#define va_start _crt_va_start
+#define va_arg _crt_va_arg
+#define va_end _crt_va_end
+
+#else // _MSC_VER
+
+#define va_start(ap,v) (ap = (va_list) (&(v)) + _INTSIZEOF(v))
+#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
+#define va_end(ap)
+
+#endif // _MSC_VER
+
+#define va_copy(dest,src) (dest = src)
+
+#endif // __GNUC__
+
+#endif // !PAL_STDCPP_COMPAT
+
+/******************* PAL-Specific Entrypoints *****************************/
+
+#define IsDebuggerPresent PAL_IsDebuggerPresent
+
+PALIMPORT
+BOOL
+PALAPI
+PAL_IsDebuggerPresent();
+
+#define MAXIMUM_SUSPEND_COUNT MAXCHAR
+
+#define CHAR_BIT 8
+
+#define SCHAR_MIN (-128)
+#define SCHAR_MAX 127
+#define UCHAR_MAX 0xff
+
+#define SHRT_MIN (-32768)
+#define SHRT_MAX 32767
+#define USHRT_MAX 0xffff
+
+#define INT_MIN (-2147483647 - 1)
+#define INT_MAX 2147483647
+#define UINT_MAX 0xffffffff
+
+#define LONG_MIN (-2147483647L - 1)
+#define LONG_MAX 2147483647L
+#define ULONG_MAX 0xffffffffUL
+
+#define FLT_MAX 3.402823466e+38F
+#define DBL_MAX 1.7976931348623157e+308
+
+/* minimum signed 64 bit value */
+#define _I64_MIN (I64(-9223372036854775807) - 1)
+/* maximum signed 64 bit value */
+#define _I64_MAX I64(9223372036854775807)
+/* maximum unsigned 64 bit value */
+#define _UI64_MAX UI64(0xffffffffffffffff)
+
+#define _I8_MAX SCHAR_MAX
+#define _I8_MIN SCHAR_MIN
+#define _I16_MAX SHRT_MAX
+#define _I16_MIN SHRT_MIN
+#define _I32_MAX INT_MAX
+#define _I32_MIN INT_MIN
+#define _UI8_MAX UCHAR_MAX
+#define _UI8_MIN UCHAR_MIN
+#define _UI16_MAX USHRT_MAX
+#define _UI16_MIN USHRT_MIN
+#define _UI32_MAX UINT_MAX
+#define _UI32_MIN UINT_MIN
+
+#ifdef PAL_STDCPP_COMPAT
+#undef NULL
+#endif
+
+#ifndef NULL
+#if defined(__cplusplus)
+#define NULL 0
+#else
+#define NULL ((void *)0)
+#endif
+#endif
+
+#if defined(PAL_STDCPP_COMPAT) && !defined(__cplusplus)
+#define nullptr NULL
+#endif // defined(PAL_STDCPP_COMPAT) && !defined(__cplusplus)
+
+#ifndef PAL_STDCPP_COMPAT
+
+#if _WIN64 || _MSC_VER >= 1400
+typedef __int64 time_t;
+#else
+typedef long time_t;
+#endif
+#define _TIME_T_DEFINED
+#endif // !PAL_STDCPP_COMPAT
+
+#if ENABLE_DOWNLEVEL_FOR_NLS
+#define MAKELCID(lgid, srtid) ((DWORD)((((DWORD)((WORD )(srtid))) << 16) | \
+ ((DWORD)((WORD )(lgid)))))
+#define LANGIDFROMLCID(lcid) ((WORD)(lcid))
+#define SORTIDFROMLCID(lcid) ((WORD)((((DWORD)(lcid)) >> 16) & 0xf))
+
+#define LANG_NEUTRAL 0x00
+#define LANG_INVARIANT 0x7f
+#define SUBLANG_NEUTRAL 0x00 // language neutral
+#define SUBLANG_DEFAULT 0x01 // user default
+#define SORT_DEFAULT 0x0 // sorting default
+#define SUBLANG_SYS_DEFAULT 0x02 // system default
+
+#define MAKELANGID(p, s) ((((WORD )(s)) << 10) | (WORD )(p))
+#define PRIMARYLANGID(lgid) ((WORD )(lgid) & 0x3ff)
+#define SUBLANGID(lgid) ((WORD )(lgid) >> 10)
+
+#define LANG_SYSTEM_DEFAULT (MAKELANGID(LANG_NEUTRAL, SUBLANG_SYS_DEFAULT))
+#define LANG_USER_DEFAULT (MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT))
+#define LOCALE_SYSTEM_DEFAULT (MAKELCID(LANG_SYSTEM_DEFAULT, SORT_DEFAULT))
+#define LOCALE_USER_DEFAULT (MAKELCID(LANG_USER_DEFAULT, SORT_DEFAULT))
+#define LOCALE_NEUTRAL (MAKELCID(MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), SORT_DEFAULT))
+#define LOCALE_US_ENGLISH (MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT))
+#define LOCALE_INVARIANT (MAKELCID(MAKELANGID(LANG_INVARIANT, SUBLANG_NEUTRAL), SORT_DEFAULT))
+
+#define SUBLANG_ENGLISH_US 0x01
+#define SUBLANG_CHINESE_TRADITIONAL 0x01 /* Chinese (Traditional) */
+
+#endif // ENABLE_DOWNLEVEL_FOR_NLS
+
+
+#define CT_CTYPE1 0x00000001 /* ctype 1 information */
+#define CT_CTYPE2 0x00000002 /* ctype 2 information */
+#define CT_CTYPE3 0x00000004 /* ctype 3 information */
+#define C1_UPPER 0x0001 /* upper case */
+#define C1_LOWER 0x0002 /* lower case */
+#define C1_DIGIT 0x0004 /* decimal digits */
+#define C1_SPACE 0x0008 /* spacing characters */
+#define C1_PUNCT 0x0010 /* punctuation characters */
+#define C1_CNTRL 0x0020 /* control characters */
+#define C1_BLANK 0x0040 /* blank characters */
+#define C1_XDIGIT 0x0080 /* other digits */
+#define C1_ALPHA 0x0100 /* any linguistic character */
+#define C2_LEFTTORIGHT 0x0001 /* left to right */
+#define C2_RIGHTTOLEFT 0x0002 /* right to left */
+#define C2_EUROPENUMBER 0x0003 /* European number, digit */
+#define C2_EUROPESEPARATOR 0x0004 /* European numeric separator */
+#define C2_EUROPETERMINATOR 0x0005 /* European numeric terminator */
+#define C2_ARABICNUMBER 0x0006 /* Arabic number */
+#define C2_COMMONSEPARATOR 0x0007 /* common numeric separator */
+#define C2_BLOCKSEPARATOR 0x0008 /* block separator */
+#define C2_SEGMENTSEPARATOR 0x0009 /* segment separator */
+#define C2_WHITESPACE 0x000A /* white space */
+#define C2_OTHERNEUTRAL 0x000B /* other neutrals */
+#define C2_NOTAPPLICABLE 0x0000 /* no implicit directionality */
+#define C3_NONSPACING 0x0001 /* nonspacing character */
+#define C3_DIACRITIC 0x0002 /* diacritic mark */
+#define C3_VOWELMARK 0x0004 /* vowel mark */
+#define C3_SYMBOL 0x0008 /* symbols */
+#define C3_KATAKANA 0x0010 /* katakana character */
+#define C3_HIRAGANA 0x0020 /* hiragana character */
+#define C3_HALFWIDTH 0x0040 /* half width character */
+#define C3_FULLWIDTH 0x0080 /* full width character */
+#define C3_IDEOGRAPH 0x0100 /* ideographic character */
+#define C3_KASHIDA 0x0200 /* Arabic kashida character */
+#define C3_LEXICAL 0x0400 /* lexical character */
+#define C3_ALPHA 0x8000 /* any ling. char (C1_ALPHA) */
+#define C3_NOTAPPLICABLE 0x0000 /* ctype 3 is not applicable */
+
+#define DLL_PROCESS_ATTACH 1
+#define DLL_THREAD_ATTACH 2
+#define DLL_THREAD_DETACH 3
+#define DLL_PROCESS_DETACH 0
+
+#define PAL_INITIALIZE_NONE 0x00
+#define PAL_INITIALIZE_SYNC_THREAD 0x01
+#define PAL_INITIALIZE_EXEC_ALLOCATOR 0x02
+#define PAL_INITIALIZE_STD_HANDLES 0x04
+#define PAL_INITIALIZE_REGISTER_SIGTERM_HANDLER 0x08
+#define PAL_INITIALIZE_DEBUGGER_EXCEPTIONS 0x10
+
+// PAL_Initialize() flags
+#define PAL_INITIALIZE (PAL_INITIALIZE_SYNC_THREAD | PAL_INITIALIZE_STD_HANDLES)
+
+// PAL_InitializeDLL() flags - don't start any of the helper threads
+#define PAL_INITIALIZE_DLL PAL_INITIALIZE_NONE
+
+// PAL_InitializeCoreCLR() flags
+#define PAL_INITIALIZE_CORECLR (PAL_INITIALIZE | PAL_INITIALIZE_EXEC_ALLOCATOR | PAL_INITIALIZE_REGISTER_SIGTERM_HANDLER | PAL_INITIALIZE_DEBUGGER_EXCEPTIONS)
+
+typedef DWORD (PALAPI *PTHREAD_START_ROUTINE)(LPVOID lpThreadParameter);
+typedef PTHREAD_START_ROUTINE LPTHREAD_START_ROUTINE;
+
+/******************* PAL-Specific Entrypoints *****************************/
+
+PALIMPORT
+int
+PALAPI
+PAL_Initialize(
+ int argc,
+ const char * const argv[]);
+
+PALIMPORT
+int
+PALAPI
+PAL_InitializeDLL();
+
+PALIMPORT
+DWORD
+PALAPI
+PAL_InitializeCoreCLR(
+ const char *szExePath);
+
+PALIMPORT
+DWORD_PTR
+PALAPI
+PAL_EntryPoint(
+ IN LPTHREAD_START_ROUTINE lpStartAddress,
+ IN LPVOID lpParameter);
+
+/// <summary>
+/// This function shuts down PAL WITHOUT exiting the current process.
+/// </summary>
+PALIMPORT
+void
+PALAPI
+PAL_Shutdown(
+ void);
+
+/// <summary>
+/// This function shuts down PAL and exits the current process.
+/// </summary>
+PALIMPORT
+void
+PALAPI
+PAL_Terminate(
+ void);
+
+/// <summary>
+/// This function shuts down PAL and exits the current process with
+/// the specified exit code.
+/// </summary>
+PALIMPORT
+void
+PALAPI
+PAL_TerminateEx(
+ int exitCode);
+
+typedef VOID (*PSHUTDOWN_CALLBACK)(void);
+
+PALIMPORT
+VOID
+PALAPI
+PAL_SetShutdownCallback(
+ IN PSHUTDOWN_CALLBACK callback);
+
+typedef VOID (*PPAL_STARTUP_CALLBACK)(
+ char *modulePath,
+ HMODULE hModule,
+ PVOID parameter);
+
+PALIMPORT
+DWORD
+PALAPI
+PAL_RegisterForRuntimeStartup(
+ IN DWORD dwProcessId,
+ IN PPAL_STARTUP_CALLBACK pfnCallback,
+ IN PVOID parameter,
+ OUT PVOID *ppUnregisterToken);
+
+PALIMPORT
+DWORD
+PALAPI
+PAL_UnregisterForRuntimeStartup(
+ IN PVOID pUnregisterToken);
+
+PALIMPORT
+BOOL
+PALAPI
+PAL_NotifyRuntimeStarted();
+
+static const int MAX_DEBUGGER_TRANSPORT_PIPE_NAME_LENGTH = 64;
+
+PALIMPORT
+void
+PALAPI
+PAL_GetTransportPipeName(char *name, DWORD id, const char *suffix);
+
+PALIMPORT
+void
+PALAPI
+PAL_InitializeDebug(
+ void);
+
+PALIMPORT
+HINSTANCE
+PALAPI
+PAL_RegisterModule(
+ IN LPCSTR lpLibFileName);
+
+PALIMPORT
+VOID
+PALAPI
+PAL_UnregisterModule(
+ IN HINSTANCE hInstance);
+
+PALIMPORT
+BOOL
+PALAPI
+PAL_GetPALDirectoryW(
+ OUT LPWSTR lpDirectoryName,
+ IN OUT UINT* cchDirectoryName);
+#ifdef UNICODE
+#define PAL_GetPALDirectory PAL_GetPALDirectoryW
+#else
+#define PAL_GetPALDirectory PAL_GetPALDirectoryA
+#endif
+
+PALIMPORT
+BOOL
+PALAPI
+PAL_Random(
+ IN BOOL bStrong,
+ IN OUT LPVOID lpBuffer,
+ IN DWORD dwLength);
+
+#ifdef PLATFORM_UNIX
+
+PALIMPORT
+DWORD
+PALAPI
+PAL_CreateExecWatchpoint(
+ HANDLE hThread,
+ PVOID pvInstruction
+ );
+
+PALIMPORT
+DWORD
+PALAPI
+PAL_DeleteExecWatchpoint(
+ HANDLE hThread,
+ PVOID pvInstruction
+ );
+
+#endif
+
+
+/******************* winuser.h Entrypoints *******************************/
+
+PALIMPORT
+LPSTR
+PALAPI
+CharNextA(
+ IN LPCSTR lpsz);
+
+PALIMPORT
+LPSTR
+PALAPI
+CharNextExA(
+ IN WORD CodePage,
+ IN LPCSTR lpCurrentChar,
+ IN DWORD dwFlags);
+
+#ifndef UNICODE
+#define CharNext CharNextA
+#define CharNextEx CharNextExA
+#endif
+
+
+PALIMPORT
+int
+PALAPIV
+wsprintfA(
+ OUT LPSTR,
+ IN LPCSTR,
+ ...);
+
+PALIMPORT
+int
+PALAPIV
+wsprintfW(
+ OUT LPWSTR,
+ IN LPCWSTR,
+ ...);
+
+#ifdef UNICODE
+#define wsprintf wsprintfW
+#else
+#define wsprintf wsprintfA
+#endif
+
+#define MB_OK 0x00000000L
+#define MB_OKCANCEL 0x00000001L
+#define MB_ABORTRETRYIGNORE 0x00000002L
+#define MB_YESNO 0x00000004L
+#define MB_RETRYCANCEL 0x00000005L
+
+#define MB_ICONHAND 0x00000010L
+#define MB_ICONQUESTION 0x00000020L
+#define MB_ICONEXCLAMATION 0x00000030L
+#define MB_ICONASTERISK 0x00000040L
+
+#define MB_ICONINFORMATION MB_ICONASTERISK
+#define MB_ICONSTOP MB_ICONHAND
+#define MB_ICONERROR MB_ICONHAND
+
+#define MB_DEFBUTTON1 0x00000000L
+#define MB_DEFBUTTON2 0x00000100L
+#define MB_DEFBUTTON3 0x00000200L
+
+#define MB_SYSTEMMODAL 0x00001000L
+#define MB_TASKMODAL 0x00002000L
+#define MB_SETFOREGROUND 0x00010000L
+#define MB_TOPMOST 0x00040000L
+
+#define MB_NOFOCUS 0x00008000L
+#define MB_SETFOREGROUND 0x00010000L
+#define MB_DEFAULT_DESKTOP_ONLY 0x00020000L
+
+// Note: this is the NT 4.0 and greater value.
+#define MB_SERVICE_NOTIFICATION 0x00200000L
+
+#define MB_TYPEMASK 0x0000000FL
+#define MB_ICONMASK 0x000000F0L
+#define MB_DEFMASK 0x00000F00L
+
+#define IDOK 1
+#define IDCANCEL 2
+#define IDABORT 3
+#define IDRETRY 4
+#define IDIGNORE 5
+#define IDYES 6
+#define IDNO 7
+
+
+PALIMPORT
+int
+PALAPI
+MessageBoxW(
+ IN LPVOID hWnd, // NOTE: diff from winuser.h
+ IN LPCWSTR lpText,
+ IN LPCWSTR lpCaption,
+ IN UINT uType);
+
+
+#ifdef UNICODE
+#define MessageBox MessageBoxW
+#else
+#define MessageBox MessageBoxA
+#endif
+
+/***************** wincon.h Entrypoints **********************************/
+
+#define CTRL_C_EVENT 0
+#define CTRL_BREAK_EVENT 1
+#define CTRL_CLOSE_EVENT 2
+// 3 is reserved!
+// 4 is reserved!
+#define CTRL_LOGOFF_EVENT 5
+#define CTRL_SHUTDOWN_EVENT 6
+
+typedef
+BOOL
+(PALAPI *PHANDLER_ROUTINE)(
+ DWORD CtrlType
+ );
+
+#ifndef CORECLR
+PALIMPORT
+BOOL
+PALAPI
+GenerateConsoleCtrlEvent(
+ IN DWORD dwCtrlEvent,
+ IN DWORD dwProcessGroupId
+ );
+#endif // !CORECLR
+
+//end wincon.h Entrypoints
+
+// From win32.h
+#ifndef _CRTIMP
+#ifdef __llvm__
+#define _CRTIMP
+#else // __llvm__
+#define _CRTIMP __declspec(dllimport)
+#endif // __llvm__
+#endif // _CRTIMP
+
+/******************* winbase.h Entrypoints and defines ************************/
+PALIMPORT
+BOOL
+PALAPI
+AreFileApisANSI(
+ VOID);
+
+typedef struct _SECURITY_ATTRIBUTES {
+ DWORD nLength;
+ LPVOID lpSecurityDescriptor;
+ BOOL bInheritHandle;
+} SECURITY_ATTRIBUTES, *PSECURITY_ATTRIBUTES, *LPSECURITY_ATTRIBUTES;
+
+#define _SH_DENYWR 0x20 /* deny write mode */
+
+#define FILE_READ_DATA ( 0x0001 ) // file & pipe
+#define FILE_APPEND_DATA ( 0x0004 ) // file
+
+#define GENERIC_READ (0x80000000L)
+#define GENERIC_WRITE (0x40000000L)
+
+#define FILE_SHARE_READ 0x00000001
+#define FILE_SHARE_WRITE 0x00000002
+#define FILE_SHARE_DELETE 0x00000004
+
+#define CREATE_NEW 1
+#define CREATE_ALWAYS 2
+#define OPEN_EXISTING 3
+#define OPEN_ALWAYS 4
+#define TRUNCATE_EXISTING 5
+
+#define FILE_ATTRIBUTE_READONLY 0x00000001
+#define FILE_ATTRIBUTE_HIDDEN 0x00000002
+#define FILE_ATTRIBUTE_SYSTEM 0x00000004
+#define FILE_ATTRIBUTE_DIRECTORY 0x00000010
+#define FILE_ATTRIBUTE_ARCHIVE 0x00000020
+#define FILE_ATTRIBUTE_DEVICE 0x00000040
+#define FILE_ATTRIBUTE_NORMAL 0x00000080
+
+#define FILE_FLAG_WRITE_THROUGH 0x80000000
+#define FILE_FLAG_NO_BUFFERING 0x20000000
+#define FILE_FLAG_RANDOM_ACCESS 0x10000000
+#define FILE_FLAG_SEQUENTIAL_SCAN 0x08000000
+#define FILE_FLAG_BACKUP_SEMANTICS 0x02000000
+
+#define FILE_BEGIN 0
+#define FILE_CURRENT 1
+#define FILE_END 2
+
+#define STILL_ACTIVE (0x00000103L)
+
+#define INVALID_SET_FILE_POINTER ((DWORD)-1)
+
+
+PALIMPORT
+HANDLE
+PALAPI
+CreateFileW(
+ IN LPCWSTR lpFileName,
+ IN DWORD dwDesiredAccess,
+ IN DWORD dwShareMode,
+ IN LPSECURITY_ATTRIBUTES lpSecurityAttributes,
+ IN DWORD dwCreationDisposition,
+ IN DWORD dwFlagsAndAttributes,
+ IN HANDLE hTemplateFile);
+
+#ifdef UNICODE
+#define CreateFile CreateFileW
+#else
+#define CreateFile CreateFileA
+#endif
+
+PALIMPORT
+BOOL
+PALAPI
+LockFile(
+ IN HANDLE hFile,
+ IN DWORD dwFileOffsetLow,
+ IN DWORD dwFileOffsetHigh,
+ IN DWORD nNumberOfBytesToLockLow,
+ IN DWORD nNumberOfBytesToLockHigh
+ );
+
+PALIMPORT
+BOOL
+PALAPI
+UnlockFile(
+ IN HANDLE hFile,
+ IN DWORD dwFileOffsetLow,
+ IN DWORD dwFileOffsetHigh,
+ IN DWORD nNumberOfBytesToUnlockLow,
+ IN DWORD nNumberOfBytesToUnlockHigh
+ );
+
+
+PALIMPORT
+DWORD
+PALAPI
+SearchPathW(
+ IN LPCWSTR lpPath,
+ IN LPCWSTR lpFileName,
+ IN LPCWSTR lpExtension,
+ IN DWORD nBufferLength,
+ OUT LPWSTR lpBuffer,
+ OUT LPWSTR *lpFilePart
+ );
+#ifdef UNICODE
+#define SearchPath SearchPathW
+#else
+#define SearchPath SearchPathA
+#endif // !UNICODE
+
+
+
+PALIMPORT
+BOOL
+PALAPI
+CopyFileW(
+ IN LPCWSTR lpExistingFileName,
+ IN LPCWSTR lpNewFileName,
+ IN BOOL bFailIfExists);
+
+#ifdef UNICODE
+#define CopyFile CopyFileW
+#else
+#define CopyFile CopyFileA
+#endif
+
+
+PALIMPORT
+BOOL
+PALAPI
+DeleteFileW(
+ IN LPCWSTR lpFileName);
+
+#ifdef UNICODE
+#define DeleteFile DeleteFileW
+#else
+#define DeleteFile DeleteFileA
+#endif
+
+
+
+PALIMPORT
+BOOL
+PALAPI
+MoveFileW(
+ IN LPCWSTR lpExistingFileName,
+ IN LPCWSTR lpNewFileName);
+
+#ifdef UNICODE
+#define MoveFile MoveFileW
+#else
+#define MoveFile MoveFileA
+#endif
+
+#define MOVEFILE_REPLACE_EXISTING 0x00000001
+#define MOVEFILE_COPY_ALLOWED 0x00000002
+
+
+PALIMPORT
+BOOL
+PALAPI
+MoveFileExW(
+ IN LPCWSTR lpExistingFileName,
+ IN LPCWSTR lpNewFileName,
+ IN DWORD dwFlags);
+
+#ifdef UNICODE
+#define MoveFileEx MoveFileExW
+#else
+#define MoveFileEx MoveFileExA
+#endif
+
+PALIMPORT
+BOOL
+PALAPI
+CreateDirectoryW(
+ IN LPCWSTR lpPathName,
+ IN LPSECURITY_ATTRIBUTES lpSecurityAttributes);
+
+#ifdef UNICODE
+#define CreateDirectory CreateDirectoryW
+#else
+#define CreateDirectory CreateDirectoryA
+#endif
+
+PALIMPORT
+BOOL
+PALAPI
+RemoveDirectoryW(
+ IN LPCWSTR lpPathName);
+
+#ifdef UNICODE
+#define RemoveDirectory RemoveDirectoryW
+#else
+#define RemoveDirectory RemoveDirectoryA
+#endif
+
+typedef struct _BY_HANDLE_FILE_INFORMATION {
+ DWORD dwFileAttributes;
+ FILETIME ftCreationTime;
+ FILETIME ftLastAccessTime;
+ FILETIME ftLastWriteTime;
+ DWORD dwVolumeSerialNumber;
+ DWORD nFileSizeHigh;
+ DWORD nFileSizeLow;
+ DWORD nNumberOfLinks;
+ DWORD nFileIndexHigh;
+ DWORD nFileIndexLow;
+} BY_HANDLE_FILE_INFORMATION, *PBY_HANDLE_FILE_INFORMATION, *LPBY_HANDLE_FILE_INFORMATION;
+
+typedef struct _WIN32_FIND_DATAA {
+ DWORD dwFileAttributes;
+ FILETIME ftCreationTime;
+ FILETIME ftLastAccessTime;
+ FILETIME ftLastWriteTime;
+ DWORD nFileSizeHigh;
+ DWORD nFileSizeLow;
+ DWORD dwReserved0;
+ DWORD dwReserved1;
+ CHAR cFileName[ MAX_PATH_FNAME ];
+ CHAR cAlternateFileName[ 14 ];
+} WIN32_FIND_DATAA, *PWIN32_FIND_DATAA, *LPWIN32_FIND_DATAA;
+
+typedef struct _WIN32_FIND_DATAW {
+ DWORD dwFileAttributes;
+ FILETIME ftCreationTime;
+ FILETIME ftLastAccessTime;
+ FILETIME ftLastWriteTime;
+ DWORD nFileSizeHigh;
+ DWORD nFileSizeLow;
+ DWORD dwReserved0;
+ DWORD dwReserved1;
+ WCHAR cFileName[ MAX_PATH_FNAME ];
+ WCHAR cAlternateFileName[ 14 ];
+} WIN32_FIND_DATAW, *PWIN32_FIND_DATAW, *LPWIN32_FIND_DATAW;
+
+#ifdef UNICODE
+typedef WIN32_FIND_DATAW WIN32_FIND_DATA;
+typedef PWIN32_FIND_DATAW PWIN32_FIND_DATA;
+typedef LPWIN32_FIND_DATAW LPWIN32_FIND_DATA;
+#else
+typedef WIN32_FIND_DATAA WIN32_FIND_DATA;
+typedef PWIN32_FIND_DATAA PWIN32_FIND_DATA;
+typedef LPWIN32_FIND_DATAA LPWIN32_FIND_DATA;
+#endif
+
+PALIMPORT
+HANDLE
+PALAPI
+FindFirstFileW(
+ IN LPCWSTR lpFileName,
+ OUT LPWIN32_FIND_DATAW lpFindFileData);
+
+#ifdef UNICODE
+#define FindFirstFile FindFirstFileW
+#else
+#define FindFirstFile FindFirstFileA
+#endif
+
+PALIMPORT
+BOOL
+PALAPI
+FindNextFileW(
+ IN HANDLE hFindFile,
+ OUT LPWIN32_FIND_DATAW lpFindFileData);
+
+#ifdef UNICODE
+#define FindNextFile FindNextFileW
+#else
+#define FindNextFile FindNextFileA
+#endif
+
+PALIMPORT
+BOOL
+PALAPI
+FindClose(
+ IN OUT HANDLE hFindFile);
+
+PALIMPORT
+DWORD
+PALAPI
+GetFileAttributesW(
+ IN LPCWSTR lpFileName);
+
+#ifdef UNICODE
+#define GetFileAttributes GetFileAttributesW
+#else
+#define GetFileAttributes GetFileAttributesA
+#endif
+
+typedef enum _GET_FILEEX_INFO_LEVELS {
+ GetFileExInfoStandard
+} GET_FILEEX_INFO_LEVELS;
+
+typedef enum _FINDEX_INFO_LEVELS {
+ FindExInfoStandard,
+ FindExInfoBasic,
+ FindExInfoMaxInfoLevel
+} FINDEX_INFO_LEVELS;
+
+typedef enum _FINDEX_SEARCH_OPS {
+ FindExSearchNameMatch,
+ FindExSearchLimitToDirectories,
+ FindExSearchLimitToDevices,
+ FindExSearchMaxSearchOp
+} FINDEX_SEARCH_OPS;
+
+typedef struct _WIN32_FILE_ATTRIBUTE_DATA {
+ DWORD dwFileAttributes;
+ FILETIME ftCreationTime;
+ FILETIME ftLastAccessTime;
+ FILETIME ftLastWriteTime;
+ DWORD nFileSizeHigh;
+ DWORD nFileSizeLow;
+} WIN32_FILE_ATTRIBUTE_DATA, *LPWIN32_FILE_ATTRIBUTE_DATA;
+
+PALIMPORT
+BOOL
+PALAPI
+GetFileAttributesExW(
+ IN LPCWSTR lpFileName,
+ IN GET_FILEEX_INFO_LEVELS fInfoLevelId,
+ OUT LPVOID lpFileInformation);
+
+#ifdef UNICODE
+#define GetFileAttributesEx GetFileAttributesExW
+#endif
+
+PALIMPORT
+BOOL
+PALAPI
+SetFileAttributesW(
+ IN LPCWSTR lpFileName,
+ IN DWORD dwFileAttributes);
+
+#ifdef UNICODE
+#define SetFileAttributes SetFileAttributesW
+#else
+#define SetFileAttributes SetFileAttributesA
+#endif
+
+typedef LPVOID LPOVERLAPPED; // diff from winbase.h
+
+PALIMPORT
+BOOL
+PALAPI
+WriteFile(
+ IN HANDLE hFile,
+ IN LPCVOID lpBuffer,
+ IN DWORD nNumberOfBytesToWrite,
+ OUT LPDWORD lpNumberOfBytesWritten,
+ IN LPOVERLAPPED lpOverlapped);
+
+PALIMPORT
+BOOL
+PALAPI
+ReadFile(
+ IN HANDLE hFile,
+ OUT LPVOID lpBuffer,
+ IN DWORD nNumberOfBytesToRead,
+ OUT LPDWORD lpNumberOfBytesRead,
+ IN LPOVERLAPPED lpOverlapped);
+
+#define STD_INPUT_HANDLE ((DWORD)-10)
+#define STD_OUTPUT_HANDLE ((DWORD)-11)
+#define STD_ERROR_HANDLE ((DWORD)-12)
+
+PALIMPORT
+HANDLE
+PALAPI
+GetStdHandle(
+ IN DWORD nStdHandle);
+
+PALIMPORT
+BOOL
+PALAPI
+SetEndOfFile(
+ IN HANDLE hFile);
+
+PALIMPORT
+DWORD
+PALAPI
+SetFilePointer(
+ IN HANDLE hFile,
+ IN LONG lDistanceToMove,
+ IN PLONG lpDistanceToMoveHigh,
+ IN DWORD dwMoveMethod);
+
+PALIMPORT
+BOOL
+PALAPI
+SetFilePointerEx(
+ IN HANDLE hFile,
+ IN LARGE_INTEGER liDistanceToMove,
+ OUT PLARGE_INTEGER lpNewFilePointer,
+ IN DWORD dwMoveMethod);
+
+PALIMPORT
+DWORD
+PALAPI
+GetFileSize(
+ IN HANDLE hFile,
+ OUT LPDWORD lpFileSizeHigh);
+
+PALIMPORT
+BOOL
+PALAPI GetFileSizeEx(
+ IN HANDLE hFile,
+ OUT PLARGE_INTEGER lpFileSize);
+
+PALIMPORT
+BOOL
+PALAPI
+GetFileInformationByHandle(
+ IN HANDLE hFile,
+ OUT BY_HANDLE_FILE_INFORMATION* lpFileInformation);
+
+PALIMPORT
+LONG
+PALAPI
+CompareFileTime(
+ IN CONST FILETIME *lpFileTime1,
+ IN CONST FILETIME *lpFileTime2);
+
+PALIMPORT
+BOOL
+PALAPI
+SetFileTime(
+ IN HANDLE hFile,
+ IN CONST FILETIME *lpCreationTime,
+ IN CONST FILETIME *lpLastAccessTime,
+ IN CONST FILETIME *lpLastWriteTime);
+
+PALIMPORT
+BOOL
+PALAPI
+GetFileTime(
+ IN HANDLE hFile,
+ OUT LPFILETIME lpCreationTime,
+ OUT LPFILETIME lpLastAccessTime,
+ OUT LPFILETIME lpLastWriteTime);
+
+PALIMPORT
+VOID
+PALAPI
+GetSystemTimeAsFileTime(
+ OUT LPFILETIME lpSystemTimeAsFileTime);
+
+typedef struct _SYSTEMTIME {
+ WORD wYear;
+ WORD wMonth;
+ WORD wDayOfWeek;
+ WORD wDay;
+ WORD wHour;
+ WORD wMinute;
+ WORD wSecond;
+ WORD wMilliseconds;
+} SYSTEMTIME, *PSYSTEMTIME, *LPSYSTEMTIME;
+
+PALIMPORT
+VOID
+PALAPI
+GetSystemTime(
+ OUT LPSYSTEMTIME lpSystemTime);
+
+PALIMPORT
+BOOL
+PALAPI
+FileTimeToSystemTime(
+ IN CONST FILETIME *lpFileTime,
+ OUT LPSYSTEMTIME lpSystemTime);
+
+PALIMPORT
+BOOL
+PALAPI
+FileTimeToDosDateTime(
+ IN CONST FILETIME *lpFileTime,
+ OUT LPWORD lpFatDate,
+ OUT LPWORD lpFatTime
+ );
+
+
+
+PALIMPORT
+BOOL
+PALAPI
+FlushFileBuffers(
+ IN HANDLE hFile);
+
+#define FILE_TYPE_UNKNOWN 0x0000
+#define FILE_TYPE_DISK 0x0001
+#define FILE_TYPE_CHAR 0x0002
+#define FILE_TYPE_PIPE 0x0003
+#define FILE_TYPE_REMOTE 0x8000
+
+PALIMPORT
+DWORD
+PALAPI
+GetFileType(
+ IN HANDLE hFile);
+
+PALIMPORT
+UINT
+PALAPI
+GetConsoleCP(
+ VOID);
+
+PALIMPORT
+UINT
+PALAPI
+GetConsoleOutputCP(
+ VOID);
+
+PALIMPORT
+DWORD
+PALAPI
+GetFullPathNameW(
+ IN LPCWSTR lpFileName,
+ IN DWORD nBufferLength,
+ OUT LPWSTR lpBuffer,
+ OUT LPWSTR *lpFilePart);
+
+#ifdef UNICODE
+#define GetFullPathName GetFullPathNameW
+#else
+#define GetFullPathName GetFullPathNameA
+#endif
+
+PALIMPORT
+DWORD
+PALAPI
+GetLongPathNameW(
+ IN LPCWSTR lpszShortPath,
+ OUT LPWSTR lpszLongPath,
+ IN DWORD cchBuffer);
+
+#ifdef UNICODE
+#define GetLongPathName GetLongPathNameW
+#endif
+
+PALIMPORT
+DWORD
+PALAPI
+GetShortPathNameW(
+ IN LPCWSTR lpszLongPath,
+ OUT LPWSTR lpszShortPath,
+ IN DWORD cchBuffer);
+
+#ifdef UNICODE
+#define GetShortPathName GetShortPathNameW
+#endif
+
+
+PALIMPORT
+UINT
+PALAPI
+GetTempFileNameW(
+ IN LPCWSTR lpPathName,
+ IN LPCWSTR lpPrefixString,
+ IN UINT uUnique,
+ OUT LPWSTR lpTempFileName);
+
+#ifdef UNICODE
+#define GetTempFileName GetTempFileNameW
+#else
+#define GetTempFileName GetTempFileNameA
+#endif
+
+PALIMPORT
+DWORD
+PALAPI
+GetTempPathW(
+ IN DWORD nBufferLength,
+ OUT LPWSTR lpBuffer);
+
+#ifdef UNICODE
+#define GetTempPath GetTempPathW
+#else
+#define GetTempPath GetTempPathA
+#endif
+
+PALIMPORT
+DWORD
+PALAPI
+GetCurrentDirectoryW(
+ IN DWORD nBufferLength,
+ OUT LPWSTR lpBuffer);
+
+#ifdef UNICODE
+#define GetCurrentDirectory GetCurrentDirectoryW
+#else
+#define GetCurrentDirectory GetCurrentDirectoryA
+#endif
+
+PALIMPORT
+BOOL
+PALAPI
+SetCurrentDirectoryW(
+ IN LPCWSTR lpPathName);
+
+
+#ifdef UNICODE
+#define SetCurrentDirectory SetCurrentDirectoryW
+#else
+#define SetCurrentDirectory SetCurrentDirectoryA
+#endif
+
+// maximum length of the NETBIOS name (not including NULL)
+#define MAX_COMPUTERNAME_LENGTH 15
+
+// maximum length of the username (not including NULL)
+#define UNLEN 256
+
+PALIMPORT
+BOOL
+PALAPI
+GetUserNameW(
+ OUT LPWSTR lpBuffer, // address of name buffer
+ IN OUT LPDWORD nSize ); // address of size of name buffer
+
+PALIMPORT
+BOOL
+PALAPI
+GetComputerNameW(
+ OUT LPWSTR lpBuffer, // address of name buffer
+ IN OUT LPDWORD nSize); // address of size of name buffer
+
+#ifdef UNICODE
+#define GetUserName GetUserNameW
+#define GetComputerName GetComputerNameW
+#endif // UNICODE
+
+PALIMPORT
+HANDLE
+PALAPI
+CreateSemaphoreW(
+ IN LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,
+ IN LONG lInitialCount,
+ IN LONG lMaximumCount,
+ IN LPCWSTR lpName);
+
+PALIMPORT
+HANDLE
+PALAPI
+CreateSemaphoreExW(
+ IN LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,
+ IN LONG lInitialCount,
+ IN LONG lMaximumCount,
+ IN LPCWSTR lpName,
+ IN /*_Reserved_*/ DWORD dwFlags,
+ IN DWORD dwDesiredAccess);
+
+PALIMPORT
+HANDLE
+PALAPI
+OpenSemaphoreW(
+ IN DWORD dwDesiredAccess,
+ IN BOOL bInheritHandle,
+ IN LPCWSTR lpName);
+
+#ifdef UNICODE
+#define CreateSemaphore CreateSemaphoreW
+#define CreateSemaphoreEx CreateSemaphoreExW
+#else
+#define CreateSemaphore CreateSemaphoreA
+#define CreateSemaphoreEx CreateSemaphoreExA
+#endif
+
+PALIMPORT
+BOOL
+PALAPI
+ReleaseSemaphore(
+ IN HANDLE hSemaphore,
+ IN LONG lReleaseCount,
+ OUT LPLONG lpPreviousCount);
+
+PALIMPORT
+HANDLE
+PALAPI
+CreateEventW(
+ IN LPSECURITY_ATTRIBUTES lpEventAttributes,
+ IN BOOL bManualReset,
+ IN BOOL bInitialState,
+ IN LPCWSTR lpName);
+
+#ifdef UNICODE
+#define CreateEvent CreateEventW
+#else
+#define CreateEvent CreateEventA
+#endif
+
+PALIMPORT
+BOOL
+PALAPI
+SetEvent(
+ IN HANDLE hEvent);
+
+PALIMPORT
+BOOL
+PALAPI
+ResetEvent(
+ IN HANDLE hEvent);
+
+PALIMPORT
+HANDLE
+PALAPI
+OpenEventW(
+ IN DWORD dwDesiredAccess,
+ IN BOOL bInheritHandle,
+ IN LPCWSTR lpName);
+
+#ifdef UNICODE
+#define OpenEvent OpenEventW
+#endif
+
+PALIMPORT
+HANDLE
+PALAPI
+CreateMutexW(
+ IN LPSECURITY_ATTRIBUTES lpMutexAttributes,
+ IN BOOL bInitialOwner,
+ IN LPCWSTR lpName);
+
+#ifdef UNICODE
+#define CreateMutex CreateMutexW
+#else
+#define CreateMutex CreateMutexA
+#endif
+
+PALIMPORT
+HANDLE
+PALAPI
+OpenMutexW(
+ IN DWORD dwDesiredAccess,
+ IN BOOL bInheritHandle,
+ IN LPCWSTR lpName);
+
+
+#ifdef UNICODE
+#define OpenMutex OpenMutexW
+#else
+#define OpenMutex OpenMutexA
+#endif // UNICODE
+
+PALIMPORT
+BOOL
+PALAPI
+ReleaseMutex(
+ IN HANDLE hMutex);
+
+PALIMPORT
+DWORD
+PALAPI
+GetCurrentProcessId(
+ VOID);
+
+PALIMPORT
+DWORD
+PALAPI
+GetCurrentSessionId(
+ VOID);
+
+PALIMPORT
+HANDLE
+PALAPI
+GetCurrentProcess(
+ VOID);
+
+PALIMPORT
+DWORD
+PALAPI
+GetCurrentThreadId(
+ VOID);
+
+// To work around multiply-defined symbols in the Carbon framework.
+#define GetCurrentThread PAL_GetCurrentThread
+PALIMPORT
+HANDLE
+PALAPI
+GetCurrentThread(
+ VOID);
+
+
+#define STARTF_USESTDHANDLES 0x00000100
+
+typedef struct _STARTUPINFOW {
+ DWORD cb;
+ LPWSTR lpReserved_PAL_Undefined;
+ LPWSTR lpDesktop_PAL_Undefined;
+ LPWSTR lpTitle_PAL_Undefined;
+ DWORD dwX_PAL_Undefined;
+ DWORD dwY_PAL_Undefined;
+ DWORD dwXSize_PAL_Undefined;
+ DWORD dwYSize_PAL_Undefined;
+ DWORD dwXCountChars_PAL_Undefined;
+ DWORD dwYCountChars_PAL_Undefined;
+ DWORD dwFillAttribute_PAL_Undefined;
+ DWORD dwFlags;
+ WORD wShowWindow_PAL_Undefined;
+ WORD cbReserved2_PAL_Undefined;
+ LPBYTE lpReserved2_PAL_Undefined;
+ HANDLE hStdInput;
+ HANDLE hStdOutput;
+ HANDLE hStdError;
+} STARTUPINFOW, *LPSTARTUPINFOW;
+
+typedef struct _STARTUPINFOA {
+ DWORD cb;
+ LPSTR lpReserved_PAL_Undefined;
+ LPSTR lpDesktop_PAL_Undefined;
+ LPSTR lpTitle_PAL_Undefined;
+ DWORD dwX_PAL_Undefined;
+ DWORD dwY_PAL_Undefined;
+ DWORD dwXSize_PAL_Undefined;
+ DWORD dwYSize_PAL_Undefined;
+ DWORD dwXCountChars_PAL_Undefined;
+ DWORD dwYCountChars_PAL_Undefined;
+ DWORD dwFillAttribute_PAL_Undefined;
+ DWORD dwFlags;
+ WORD wShowWindow_PAL_Undefined;
+ WORD cbReserved2_PAL_Undefined;
+ LPBYTE lpReserved2_PAL_Undefined;
+ HANDLE hStdInput;
+ HANDLE hStdOutput;
+ HANDLE hStdError;
+} STARTUPINFOA, *LPSTARTUPINFOA;
+
+#ifdef UNICODE
+typedef STARTUPINFOW STARTUPINFO;
+typedef LPSTARTUPINFOW LPSTARTUPINFO;
+#else
+typedef STARTUPINFOA STARTUPINFO;
+typedef LPSTARTUPINFOW LPSTARTUPINFO;
+#endif
+
+#define CREATE_NEW_CONSOLE 0x00000010
+
+#define NORMAL_PRIORITY_CLASS 0x00000020
+
+typedef struct _PROCESS_INFORMATION {
+ HANDLE hProcess;
+ HANDLE hThread;
+ DWORD dwProcessId;
+ DWORD dwThreadId_PAL_Undefined;
+} PROCESS_INFORMATION, *PPROCESS_INFORMATION, *LPPROCESS_INFORMATION;
+
+PALIMPORT
+BOOL
+PALAPI
+CreateProcessW(
+ IN LPCWSTR lpApplicationName,
+ IN LPWSTR lpCommandLine,
+ IN LPSECURITY_ATTRIBUTES lpProcessAttributes,
+ IN LPSECURITY_ATTRIBUTES lpThreadAttributes,
+ IN BOOL bInheritHandles,
+ IN DWORD dwCreationFlags,
+ IN LPVOID lpEnvironment,
+ IN LPCWSTR lpCurrentDirectory,
+ IN LPSTARTUPINFOW lpStartupInfo,
+ OUT LPPROCESS_INFORMATION lpProcessInformation);
+
+#ifdef UNICODE
+#define CreateProcess CreateProcessW
+#else
+#define CreateProcess CreateProcessA
+#endif
+
+PALIMPORT
+PAL_NORETURN
+VOID
+PALAPI
+ExitProcess(
+ IN UINT uExitCode);
+
+PALIMPORT
+BOOL
+PALAPI
+TerminateProcess(
+ IN HANDLE hProcess,
+ IN UINT uExitCode);
+
+PALIMPORT
+BOOL
+PALAPI
+GetExitCodeProcess(
+ IN HANDLE hProcess,
+ IN LPDWORD lpExitCode);
+
+PALIMPORT
+BOOL
+PALAPI
+GetProcessTimes(
+ IN HANDLE hProcess,
+ OUT LPFILETIME lpCreationTime,
+ OUT LPFILETIME lpExitTime,
+ OUT LPFILETIME lpKernelTime,
+ OUT LPFILETIME lpUserTime);
+
+#define MAXIMUM_WAIT_OBJECTS 64
+#define WAIT_OBJECT_0 0
+#define WAIT_ABANDONED 0x00000080
+#define WAIT_ABANDONED_0 0x00000080
+#define WAIT_TIMEOUT 258
+#define WAIT_FAILED ((DWORD)0xFFFFFFFF)
+
+#define INFINITE 0xFFFFFFFF // Infinite timeout
+
+PALIMPORT
+DWORD
+PALAPI
+WaitForSingleObject(
+ IN HANDLE hHandle,
+ IN DWORD dwMilliseconds);
+
+PALIMPORT
+DWORD
+PALAPI
+WaitForSingleObjectEx(
+ IN HANDLE hHandle,
+ IN DWORD dwMilliseconds,
+ IN BOOL bAlertable);
+
+PALIMPORT
+DWORD
+PALAPI
+WaitForMultipleObjects(
+ IN DWORD nCount,
+ IN CONST HANDLE *lpHandles,
+ IN BOOL bWaitAll,
+ IN DWORD dwMilliseconds);
+
+PALIMPORT
+DWORD
+PALAPI
+WaitForMultipleObjectsEx(
+ IN DWORD nCount,
+ IN CONST HANDLE *lpHandles,
+ IN BOOL bWaitAll,
+ IN DWORD dwMilliseconds,
+ IN BOOL bAlertable);
+
+PALIMPORT
+RHANDLE
+PALAPI
+PAL_LocalHandleToRemote(
+ IN HANDLE hLocal);
+
+PALIMPORT
+HANDLE
+PALAPI
+PAL_RemoteHandleToLocal(
+ IN RHANDLE hRemote);
+
+
+#define DUPLICATE_CLOSE_SOURCE 0x00000001
+#define DUPLICATE_SAME_ACCESS 0x00000002
+
+PALIMPORT
+BOOL
+PALAPI
+DuplicateHandle(
+ IN HANDLE hSourceProcessHandle,
+ IN HANDLE hSourceHandle,
+ IN HANDLE hTargetProcessHandle,
+ OUT LPHANDLE lpTargetHandle,
+ IN DWORD dwDesiredAccess,
+ IN BOOL bInheritHandle,
+ IN DWORD dwOptions);
+
+PALIMPORT
+VOID
+PALAPI
+Sleep(
+ IN DWORD dwMilliseconds);
+
+PALIMPORT
+DWORD
+PALAPI
+SleepEx(
+ IN DWORD dwMilliseconds,
+ IN BOOL bAlertable);
+
+PALIMPORT
+BOOL
+PALAPI
+SwitchToThread(
+ VOID);
+
+#define DEBUG_PROCESS 0x00000001
+#define DEBUG_ONLY_THIS_PROCESS 0x00000002
+#define CREATE_SUSPENDED 0x00000004
+#define STACK_SIZE_PARAM_IS_A_RESERVATION 0x00010000
+
+PALIMPORT
+HANDLE
+PALAPI
+CreateThread(
+ IN LPSECURITY_ATTRIBUTES lpThreadAttributes,
+ IN DWORD dwStackSize,
+ IN LPTHREAD_START_ROUTINE lpStartAddress,
+ IN LPVOID lpParameter,
+ IN DWORD dwCreationFlags,
+ OUT LPDWORD lpThreadId);
+
+PALIMPORT
+PAL_NORETURN
+VOID
+PALAPI
+ExitThread(
+ IN DWORD dwExitCode);
+
+PALIMPORT
+BOOL
+PALAPI
+GetExitCodeThread(
+ IN HANDLE hThread,
+ IN LPDWORD lpExitCode);
+
+PALIMPORT
+DWORD
+PALAPI
+ResumeThread(
+ IN HANDLE hThread);
+
+typedef VOID (PALAPI *PAPCFUNC)(ULONG_PTR dwParam);
+
+PALIMPORT
+DWORD
+PALAPI
+QueueUserAPC(
+ IN PAPCFUNC pfnAPC,
+ IN HANDLE hThread,
+ IN ULONG_PTR dwData);
+
+#ifdef _X86_
+
+//
+// ***********************************************************************************
+//
+// NOTE: These context definitions are replicated in ndp/clr/src/debug/inc/DbgTargetContext.h (for the
+// purposes manipulating contexts from different platforms during remote debugging). Be sure to keep those
+// definitions in sync if you make any changes here.
+//
+// ***********************************************************************************
+//
+
+#define SIZE_OF_80387_REGISTERS 80
+
+#define CONTEXT_i386 0x00010000
+#define CONTEXT_CONTROL (CONTEXT_i386 | 0x00000001L) // SS:SP, CS:IP, FLAGS, BP
+#define CONTEXT_INTEGER (CONTEXT_i386 | 0x00000002L) // AX, BX, CX, DX, SI, DI
+#define CONTEXT_SEGMENTS (CONTEXT_i386 | 0x00000004L)
+#define CONTEXT_FLOATING_POINT (CONTEXT_i386 | 0x00000008L) // 387 state
+#define CONTEXT_DEBUG_REGISTERS (CONTEXT_i386 | 0x00000010L)
+
+#define CONTEXT_FULL (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS)
+#define CONTEXT_EXTENDED_REGISTERS (CONTEXT_i386 | 0x00000020L)
+#define CONTEXT_ALL (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS | CONTEXT_FLOATING_POINT | CONTEXT_DEBUG_REGISTERS | CONTEXT_EXTENDED_REGISTERS)
+
+#define MAXIMUM_SUPPORTED_EXTENSION 512
+
+typedef struct _FLOATING_SAVE_AREA {
+ DWORD ControlWord;
+ DWORD StatusWord;
+ DWORD TagWord;
+ DWORD ErrorOffset;
+ DWORD ErrorSelector;
+ DWORD DataOffset;
+ DWORD DataSelector;
+ BYTE RegisterArea[SIZE_OF_80387_REGISTERS];
+ DWORD Cr0NpxState;
+} FLOATING_SAVE_AREA;
+
+typedef FLOATING_SAVE_AREA *PFLOATING_SAVE_AREA;
+
+typedef struct _CONTEXT {
+ ULONG ContextFlags;
+
+ ULONG Dr0_PAL_Undefined;
+ ULONG Dr1_PAL_Undefined;
+ ULONG Dr2_PAL_Undefined;
+ ULONG Dr3_PAL_Undefined;
+ ULONG Dr6_PAL_Undefined;
+ ULONG Dr7_PAL_Undefined;
+
+ FLOATING_SAVE_AREA FloatSave;
+
+ ULONG SegGs_PAL_Undefined;
+ ULONG SegFs_PAL_Undefined;
+ ULONG SegEs_PAL_Undefined;
+ ULONG SegDs_PAL_Undefined;
+
+ ULONG Edi;
+ ULONG Esi;
+ ULONG Ebx;
+ ULONG Edx;
+ ULONG Ecx;
+ ULONG Eax;
+
+ ULONG Ebp;
+ ULONG Eip;
+ ULONG SegCs;
+ ULONG EFlags;
+ ULONG Esp;
+ ULONG SegSs;
+
+ UCHAR ExtendedRegisters[MAXIMUM_SUPPORTED_EXTENSION];
+
+} CONTEXT, *PCONTEXT, *LPCONTEXT;
+
+// To support saving and loading xmm register context we need to know the offset in the ExtendedRegisters
+// section at which they are stored. This has been determined experimentally since I have found no
+// documentation thus far but it corresponds to the offset we'd expect if a fxsave instruction was used to
+// store the regular FP state along with the XMM registers at the start of the extended registers section.
+// Technically the offset doesn't really matter if no code in the PAL or runtime knows what the offset should
+// be either (as long as we're consistent across GetThreadContext() and SetThreadContext() and we don't
+// support any other values in the ExtendedRegisters) but we might as well be as accurate as we can.
+#define CONTEXT_EXREG_XMM_OFFSET 160
+
+#elif defined(_PPC_)
+
+//
+// ***********************************************************************************
+//
+// NOTE: These context definitions are replicated in ndp/clr/src/debug/inc/DbgTargetContext.h (for the
+// purposes manipulating contexts from different platforms during remote debugging). Be sure to keep those
+// definitions in sync if you make any changes here.
+//
+// ***********************************************************************************
+//
+
+#define CONTEXT_CONTROL 0x00000001L
+#define CONTEXT_FLOATING_POINT 0x00000002L
+#define CONTEXT_INTEGER 0x00000004L
+
+#define CONTEXT_FULL (CONTEXT_CONTROL | CONTEXT_FLOATING_POINT | CONTEXT_INTEGER)
+#define CONTEXT_ALL CONTEXT_FULL
+
+typedef struct _CONTEXT {
+
+ //
+ // This section is specified/returned if the ContextFlags word contains
+ // the flag CONTEXT_FLOATING_POINT.
+ //
+
+ double Fpr0; // Floating registers 0..31
+ double Fpr1;
+ double Fpr2;
+ double Fpr3;
+ double Fpr4;
+ double Fpr5;
+ double Fpr6;
+ double Fpr7;
+ double Fpr8;
+ double Fpr9;
+ double Fpr10;
+ double Fpr11;
+ double Fpr12;
+ double Fpr13;
+ double Fpr14;
+ double Fpr15;
+ double Fpr16;
+ double Fpr17;
+ double Fpr18;
+ double Fpr19;
+ double Fpr20;
+ double Fpr21;
+ double Fpr22;
+ double Fpr23;
+ double Fpr24;
+ double Fpr25;
+ double Fpr26;
+ double Fpr27;
+ double Fpr28;
+ double Fpr29;
+ double Fpr30;
+ double Fpr31;
+ double Fpscr; // Floating point status/control reg
+
+ //
+ // This section is specified/returned if the ContextFlags word contains
+ // the flag CONTEXT_INTEGER.
+ //
+
+ ULONG Gpr0; // General registers 0..31
+ ULONG Gpr1; // StackPointer
+ ULONG Gpr2;
+ ULONG Gpr3;
+ ULONG Gpr4;
+ ULONG Gpr5;
+ ULONG Gpr6;
+ ULONG Gpr7;
+ ULONG Gpr8;
+ ULONG Gpr9;
+ ULONG Gpr10;
+ ULONG Gpr11;
+ ULONG Gpr12;
+ ULONG Gpr13;
+ ULONG Gpr14;
+ ULONG Gpr15;
+ ULONG Gpr16;
+ ULONG Gpr17;
+ ULONG Gpr18;
+ ULONG Gpr19;
+ ULONG Gpr20;
+ ULONG Gpr21;
+ ULONG Gpr22;
+ ULONG Gpr23;
+ ULONG Gpr24;
+ ULONG Gpr25;
+ ULONG Gpr26;
+ ULONG Gpr27;
+ ULONG Gpr28;
+ ULONG Gpr29;
+ ULONG Gpr30;
+ ULONG Gpr31;
+
+ ULONG Cr; // Condition register
+ ULONG Xer; // Fixed point exception register
+
+ //
+ // This section is specified/returned if the ContextFlags word contains
+ // the flag CONTEXT_CONTROL.
+ //
+
+ ULONG Msr; // Machine status register
+ ULONG Iar; // Instruction address register
+ ULONG Lr; // Link register
+ ULONG Ctr; // Count register
+
+ //
+ // The flags values within this flag control the contents of
+ // a CONTEXT record.
+ //
+ // If the context record is used as an input parameter, then
+ // for each portion of the context record controlled by a flag
+ // whose value is set, it is assumed that that portion of the
+ // context record contains valid context. If the context record
+ // is being used to modify a thread's context, then only that
+ // portion of the threads context will be modified.
+ //
+ // If the context record is used as an IN OUT parameter to capture
+ // the context of a thread, then only those portions of the thread's
+ // context corresponding to set flags will be returned.
+ //
+ // The context record is never used as an OUT only parameter.
+ //
+
+ ULONG ContextFlags;
+
+ ULONG Fill[3]; // Pad out to multiple of 16 bytes
+
+ //
+ // This section is specified/returned if CONTEXT_DEBUG_REGISTERS is
+ // set in ContextFlags. Note that CONTEXT_DEBUG_REGISTERS is NOT
+ // included in CONTEXT_FULL.
+ //
+ ULONG Dr0; // Breakpoint Register 1
+ ULONG Dr1; // Breakpoint Register 2
+ ULONG Dr2; // Breakpoint Register 3
+ ULONG Dr3; // Breakpoint Register 4
+ ULONG Dr4; // Breakpoint Register 5
+ ULONG Dr5; // Breakpoint Register 6
+ ULONG Dr6; // Debug Status Register
+ ULONG Dr7; // Debug Control Register
+
+} CONTEXT, *PCONTEXT, *LPCONTEXT;
+
+#elif defined(_SPARC_)
+
+#define CONTEXT_CONTROL 0x00000001L
+#define CONTEXT_FLOATING_POINT 0x00000002L
+#define CONTEXT_INTEGER 0x00000004L
+
+#define COUNT_FLOATING_REGISTER 32
+#define COUNT_DOUBLE_REGISTER 16
+#define CONTEXT_FULL (CONTEXT_CONTROL | CONTEXT_FLOATING_POINT | CONTEXT_INTEGER)
+#define CONTEXT_ALL CONTEXT_FULL
+
+typedef struct _CONTEXT {
+ //
+ // This section is specified/returned if the ContextFlags word contains
+ // the flag CONTEXT_INTEGER.
+ //
+ ULONG g0;
+ ULONG g1;
+ ULONG g2;
+ ULONG g3;
+ ULONG g4;
+ ULONG g5;
+ ULONG g6;
+ ULONG g7;
+ ULONG o0;
+ ULONG o1;
+ ULONG o2;
+ ULONG o3;
+ ULONG o4;
+ ULONG o5;
+ ULONG sp;
+ ULONG o7;
+ ULONG l0;
+ ULONG l1;
+ ULONG l2;
+ ULONG l3;
+ ULONG l4;
+ ULONG l5;
+ ULONG l6;
+ ULONG l7;
+ ULONG i0;
+ ULONG i1;
+ ULONG i2;
+ ULONG i3;
+ ULONG i4;
+ ULONG i5;
+ ULONG fp;
+ ULONG i7;
+
+ ULONG y;
+
+ //
+ // This section is specified/returned if the ContextFlags word contains
+ // the flag CONTEXT_CONTROL.
+ //
+#if defined(__sparcv9)
+ ULONG ccr;
+#else
+ ULONG psr;
+#endif
+ ULONG pc; // program counter
+ ULONG npc; // next address to be executed
+
+ ULONG ContextFlags;
+
+ //
+ // This section is specified/returned if the ContextFlags word contains
+ // the flag CONTEXT_FLOATING_POINT.
+ //
+ ULONGLONG fsr;
+ union {
+ float f[COUNT_FLOATING_REGISTER];
+ double d[COUNT_DOUBLE_REGISTER];
+ } fprs;
+
+} CONTEXT, *PCONTEXT, *LPCONTEXT;
+
+#elif defined(_PARISC_)
+
+// ToDo: Get this correct for PARISC architecture
+#define CONTEXT_CONTROL 0x00000001L
+#define CONTEXT_FLOATING_POINT 0x00000002L
+#define CONTEXT_INTEGER 0x00000004L
+
+#define COUNT_FLOATING_REGISTER 32
+#define COUNT_DOUBLE_REGISTER 16
+#define CONTEXT_FULL (CONTEXT_CONTROL | CONTEXT_FLOATING_POINT | CONTEXT_INTEGER)
+#define CONTEXT_ALL CONTEXT_FULL
+
+typedef struct _CONTEXT {
+ //
+ // This section is specified/returned if the ContextFlags word contains
+ // the flag CONTEXT_INTEGER.
+ //
+ ULONG g0;
+ ULONG g1;
+ ULONG g2;
+ ULONG g3;
+ ULONG g4;
+ ULONG g5;
+ ULONG g6;
+ ULONG g7;
+ ULONG o0;
+ ULONG o1;
+ ULONG o2;
+ ULONG o3;
+ ULONG o4;
+ ULONG o5;
+ ULONG sp;
+ ULONG o7;
+ ULONG l0;
+ ULONG l1;
+ ULONG l2;
+ ULONG l3;
+ ULONG l4;
+ ULONG l5;
+ ULONG l6;
+ ULONG l7;
+ ULONG i0;
+ ULONG i1;
+ ULONG i2;
+ ULONG i3;
+ ULONG i4;
+ ULONG i5;
+ ULONG fp;
+ ULONG i7;
+
+ ULONG y;
+
+ //
+ // This section is specified/returned if the ContextFlags word contains
+ // the flag CONTEXT_CONTROL.
+ //
+ ULONG psr;
+ ULONG pc; // program counter
+ ULONG npc; // next address to be executed
+
+ ULONG ContextFlags;
+
+ //
+ // This section is specified/returned if the ContextFlags word contains
+ // the flag CONTEXT_FLOATING_POINT.
+ //
+ ULONGLONG fsr;
+ union {
+ float f[COUNT_FLOATING_REGISTER];
+ double d[COUNT_DOUBLE_REGISTER];
+ } fprs;
+
+} CONTEXT, *PCONTEXT, *LPCONTEXT;
+
+#elif defined(_IA64_)
+
+// copied from winnt.h
+typedef struct _FLOAT128 {
+ __int64 LowPart;
+ __int64 HighPart;
+} FLOAT128;
+
+typedef FLOAT128 *PFLOAT128;
+
+// begin_ntddk begin_nthal
+
+//
+// The following flags control the contents of the CONTEXT structure.
+//
+
+#if !defined(RC_INVOKED)
+
+#define CONTEXT_IA64 0x00080000
+
+#define CONTEXT_CONTROL (CONTEXT_IA64 | 0x00000001L)
+#define CONTEXT_LOWER_FLOATING_POINT (CONTEXT_IA64 | 0x00000002L)
+#define CONTEXT_HIGHER_FLOATING_POINT (CONTEXT_IA64 | 0x00000004L)
+#define CONTEXT_INTEGER (CONTEXT_IA64 | 0x00000008L)
+#define CONTEXT_DEBUG (CONTEXT_IA64 | 0x00000010L)
+#define CONTEXT_IA32_CONTROL (CONTEXT_IA64 | 0x00000020L) // Includes StIPSR
+
+
+#define CONTEXT_FLOATING_POINT (CONTEXT_LOWER_FLOATING_POINT | CONTEXT_HIGHER_FLOATING_POINT)
+#define CONTEXT_FULL (CONTEXT_CONTROL | CONTEXT_FLOATING_POINT | CONTEXT_INTEGER | CONTEXT_IA32_CONTROL)
+#define CONTEXT_ALL (CONTEXT_CONTROL | CONTEXT_FLOATING_POINT | CONTEXT_INTEGER | CONTEXT_DEBUG | CONTEXT_IA32_CONTROL)
+
+#define CONTEXT_EXCEPTION_ACTIVE 0x8000000
+#define CONTEXT_SERVICE_ACTIVE 0x10000000
+#define CONTEXT_EXCEPTION_REQUEST 0x40000000
+#define CONTEXT_EXCEPTION_REPORTING 0x80000000
+
+#endif // !defined(RC_INVOKED)
+
+//
+// Context Frame
+//
+// This frame has a several purposes: 1) it is used as an argument to
+// NtContinue, 2) it is used to construct a call frame for APC delivery,
+// 3) it is used to construct a call frame for exception dispatching
+// in user mode, 4) it is used in the user level thread creation
+// routines, and 5) it is used to to pass thread state to debuggers.
+//
+// N.B. Because this record is used as a call frame, it must be EXACTLY
+// a multiple of 16 bytes in length and aligned on a 16-byte boundary.
+//
+
+typedef struct _CONTEXT {
+
+ //
+ // The flags values within this flag control the contents of
+ // a CONTEXT record.
+ //
+ // If the context record is used as an input parameter, then
+ // for each portion of the context record controlled by a flag
+ // whose value is set, it is assumed that that portion of the
+ // context record contains valid context. If the context record
+ // is being used to modify a thread's context, then only that
+ // portion of the threads context will be modified.
+ //
+ // If the context record is used as an IN OUT parameter to capture
+ // the context of a thread, then only those portions of the thread's
+ // context corresponding to set flags will be returned.
+ //
+ // The context record is never used as an OUT only parameter.
+ //
+
+ DWORD ContextFlags;
+ DWORD Fill1[3]; // for alignment of following on 16-byte boundary
+
+ //
+ // This section is specified/returned if the ContextFlags word contains
+ // the flag CONTEXT_DEBUG.
+ //
+ // N.B. CONTEXT_DEBUG is *not* part of CONTEXT_FULL.
+ //
+
+ ULONGLONG DbI0;
+ ULONGLONG DbI1;
+ ULONGLONG DbI2;
+ ULONGLONG DbI3;
+ ULONGLONG DbI4;
+ ULONGLONG DbI5;
+ ULONGLONG DbI6;
+ ULONGLONG DbI7;
+
+ ULONGLONG DbD0;
+ ULONGLONG DbD1;
+ ULONGLONG DbD2;
+ ULONGLONG DbD3;
+ ULONGLONG DbD4;
+ ULONGLONG DbD5;
+ ULONGLONG DbD6;
+ ULONGLONG DbD7;
+
+ //
+ // This section is specified/returned if the ContextFlags word contains
+ // the flag CONTEXT_LOWER_FLOATING_POINT.
+ //
+
+ FLOAT128 FltS0;
+ FLOAT128 FltS1;
+ FLOAT128 FltS2;
+ FLOAT128 FltS3;
+ FLOAT128 FltT0;
+ FLOAT128 FltT1;
+ FLOAT128 FltT2;
+ FLOAT128 FltT3;
+ FLOAT128 FltT4;
+ FLOAT128 FltT5;
+ FLOAT128 FltT6;
+ FLOAT128 FltT7;
+ FLOAT128 FltT8;
+ FLOAT128 FltT9;
+
+ //
+ // This section is specified/returned if the ContextFlags word contains
+ // the flag CONTEXT_HIGHER_FLOATING_POINT.
+ //
+
+ FLOAT128 FltS4;
+ FLOAT128 FltS5;
+ FLOAT128 FltS6;
+ FLOAT128 FltS7;
+ FLOAT128 FltS8;
+ FLOAT128 FltS9;
+ FLOAT128 FltS10;
+ FLOAT128 FltS11;
+ FLOAT128 FltS12;
+ FLOAT128 FltS13;
+ FLOAT128 FltS14;
+ FLOAT128 FltS15;
+ FLOAT128 FltS16;
+ FLOAT128 FltS17;
+ FLOAT128 FltS18;
+ FLOAT128 FltS19;
+
+ FLOAT128 FltF32;
+ FLOAT128 FltF33;
+ FLOAT128 FltF34;
+ FLOAT128 FltF35;
+ FLOAT128 FltF36;
+ FLOAT128 FltF37;
+ FLOAT128 FltF38;
+ FLOAT128 FltF39;
+
+ FLOAT128 FltF40;
+ FLOAT128 FltF41;
+ FLOAT128 FltF42;
+ FLOAT128 FltF43;
+ FLOAT128 FltF44;
+ FLOAT128 FltF45;
+ FLOAT128 FltF46;
+ FLOAT128 FltF47;
+ FLOAT128 FltF48;
+ FLOAT128 FltF49;
+
+ FLOAT128 FltF50;
+ FLOAT128 FltF51;
+ FLOAT128 FltF52;
+ FLOAT128 FltF53;
+ FLOAT128 FltF54;
+ FLOAT128 FltF55;
+ FLOAT128 FltF56;
+ FLOAT128 FltF57;
+ FLOAT128 FltF58;
+ FLOAT128 FltF59;
+
+ FLOAT128 FltF60;
+ FLOAT128 FltF61;
+ FLOAT128 FltF62;
+ FLOAT128 FltF63;
+ FLOAT128 FltF64;
+ FLOAT128 FltF65;
+ FLOAT128 FltF66;
+ FLOAT128 FltF67;
+ FLOAT128 FltF68;
+ FLOAT128 FltF69;
+
+ FLOAT128 FltF70;
+ FLOAT128 FltF71;
+ FLOAT128 FltF72;
+ FLOAT128 FltF73;
+ FLOAT128 FltF74;
+ FLOAT128 FltF75;
+ FLOAT128 FltF76;
+ FLOAT128 FltF77;
+ FLOAT128 FltF78;
+ FLOAT128 FltF79;
+
+ FLOAT128 FltF80;
+ FLOAT128 FltF81;
+ FLOAT128 FltF82;
+ FLOAT128 FltF83;
+ FLOAT128 FltF84;
+ FLOAT128 FltF85;
+ FLOAT128 FltF86;
+ FLOAT128 FltF87;
+ FLOAT128 FltF88;
+ FLOAT128 FltF89;
+
+ FLOAT128 FltF90;
+ FLOAT128 FltF91;
+ FLOAT128 FltF92;
+ FLOAT128 FltF93;
+ FLOAT128 FltF94;
+ FLOAT128 FltF95;
+ FLOAT128 FltF96;
+ FLOAT128 FltF97;
+ FLOAT128 FltF98;
+ FLOAT128 FltF99;
+
+ FLOAT128 FltF100;
+ FLOAT128 FltF101;
+ FLOAT128 FltF102;
+ FLOAT128 FltF103;
+ FLOAT128 FltF104;
+ FLOAT128 FltF105;
+ FLOAT128 FltF106;
+ FLOAT128 FltF107;
+ FLOAT128 FltF108;
+ FLOAT128 FltF109;
+
+ FLOAT128 FltF110;
+ FLOAT128 FltF111;
+ FLOAT128 FltF112;
+ FLOAT128 FltF113;
+ FLOAT128 FltF114;
+ FLOAT128 FltF115;
+ FLOAT128 FltF116;
+ FLOAT128 FltF117;
+ FLOAT128 FltF118;
+ FLOAT128 FltF119;
+
+ FLOAT128 FltF120;
+ FLOAT128 FltF121;
+ FLOAT128 FltF122;
+ FLOAT128 FltF123;
+ FLOAT128 FltF124;
+ FLOAT128 FltF125;
+ FLOAT128 FltF126;
+ FLOAT128 FltF127;
+
+ //
+ // This section is specified/returned if the ContextFlags word contains
+ // the flag CONTEXT_LOWER_FLOATING_POINT | CONTEXT_HIGHER_FLOATING_POINT | CONTEXT_CONTROL.
+ //
+
+ ULONGLONG StFPSR; // FP status
+
+ //
+ // This section is specified/returned if the ContextFlags word contains
+ // the flag CONTEXT_INTEGER.
+ //
+ // N.B. The registers gp, sp, rp are part of the control context
+ //
+
+ ULONGLONG IntGp; // r1, volatile
+ ULONGLONG IntT0; // r2-r3, volatile
+ ULONGLONG IntT1; //
+ ULONGLONG IntS0; // r4-r7, preserved
+ ULONGLONG IntS1;
+ ULONGLONG IntS2;
+ ULONGLONG IntS3;
+ ULONGLONG IntV0; // r8, volatile
+ ULONGLONG IntT2; // r9-r11, volatile
+ ULONGLONG IntT3;
+ ULONGLONG IntT4;
+ ULONGLONG IntSp; // stack pointer (r12), special
+ ULONGLONG IntTeb; // teb (r13), special
+ ULONGLONG IntT5; // r14-r31, volatile
+ ULONGLONG IntT6;
+ ULONGLONG IntT7;
+ ULONGLONG IntT8;
+ ULONGLONG IntT9;
+ ULONGLONG IntT10;
+ ULONGLONG IntT11;
+ ULONGLONG IntT12;
+ ULONGLONG IntT13;
+ ULONGLONG IntT14;
+ ULONGLONG IntT15;
+ ULONGLONG IntT16;
+ ULONGLONG IntT17;
+ ULONGLONG IntT18;
+ ULONGLONG IntT19;
+ ULONGLONG IntT20;
+ ULONGLONG IntT21;
+ ULONGLONG IntT22;
+
+ ULONGLONG IntNats; // Nat bits for r1-r31
+ // r1-r31 in bits 1 thru 31.
+ ULONGLONG Preds; // predicates, preserved
+
+ ULONGLONG BrRp; // return pointer, b0, preserved
+ ULONGLONG BrS0; // b1-b5, preserved
+ ULONGLONG BrS1;
+ ULONGLONG BrS2;
+ ULONGLONG BrS3;
+ ULONGLONG BrS4;
+ ULONGLONG BrT0; // b6-b7, volatile
+ ULONGLONG BrT1;
+
+ //
+ // This section is specified/returned if the ContextFlags word contains
+ // the flag CONTEXT_CONTROL.
+ //
+
+ // Other application registers
+ ULONGLONG ApUNAT; // User Nat collection register, preserved
+ ULONGLONG ApLC; // Loop counter register, preserved
+ ULONGLONG ApEC; // Epilog counter register, preserved
+ ULONGLONG ApCCV; // CMPXCHG value register, volatile
+ ULONGLONG ApDCR; // Default control register (TBD)
+
+ // Register stack info
+ ULONGLONG RsPFS; // Previous function state, preserved
+ ULONGLONG RsBSP; // Backing store pointer, preserved
+ ULONGLONG RsBSPSTORE;
+ ULONGLONG RsRSC; // RSE configuration, volatile
+ ULONGLONG RsRNAT; // RSE Nat collection register, preserved
+
+ // Trap Status Information
+ ULONGLONG StIPSR; // Interruption Processor Status
+ ULONGLONG StIIP; // Interruption IP
+ ULONGLONG StIFS; // Interruption Function State
+
+ // iA32 related control registers
+ ULONGLONG StFCR; // copy of Ar21
+ ULONGLONG Eflag; // Eflag copy of Ar24
+ ULONGLONG SegCSD; // iA32 CSDescriptor (Ar25)
+ ULONGLONG SegSSD; // iA32 SSDescriptor (Ar26)
+ ULONGLONG Cflag; // Cr0+Cr4 copy of Ar27
+ ULONGLONG StFSR; // x86 FP status (copy of AR28)
+ ULONGLONG StFIR; // x86 FP status (copy of AR29)
+ ULONGLONG StFDR; // x86 FP status (copy of AR30)
+
+ ULONGLONG UNUSEDPACK; // added to pack StFDR to 16-bytes
+
+} CONTEXT, *PCONTEXT, *LPCONTEXT;
+#elif defined(_AMD64_)
+// copied from winnt.h
+
+#define CONTEXT_AMD64 0x100000
+
+#define CONTEXT_CONTROL (CONTEXT_AMD64 | 0x1L)
+#define CONTEXT_INTEGER (CONTEXT_AMD64 | 0x2L)
+#define CONTEXT_SEGMENTS (CONTEXT_AMD64 | 0x4L)
+#define CONTEXT_FLOATING_POINT (CONTEXT_AMD64 | 0x8L)
+#define CONTEXT_DEBUG_REGISTERS (CONTEXT_AMD64 | 0x10L)
+
+#define CONTEXT_FULL (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT)
+
+#define CONTEXT_ALL (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS | CONTEXT_FLOATING_POINT | CONTEXT_DEBUG_REGISTERS)
+
+#define CONTEXT_XSTATE (CONTEXT_AMD64 | 0x40L)
+
+#define CONTEXT_EXCEPTION_ACTIVE 0x8000000
+#define CONTEXT_SERVICE_ACTIVE 0x10000000
+#define CONTEXT_EXCEPTION_REQUEST 0x40000000
+#define CONTEXT_EXCEPTION_REPORTING 0x80000000
+
+typedef struct DECLSPEC_ALIGN(16) _M128A {
+ ULONGLONG Low;
+ LONGLONG High;
+} M128A, *PM128A;
+
+typedef struct _XMM_SAVE_AREA32 {
+ WORD ControlWord;
+ WORD StatusWord;
+ BYTE TagWord;
+ BYTE Reserved1;
+ WORD ErrorOpcode;
+ DWORD ErrorOffset;
+ WORD ErrorSelector;
+ WORD Reserved2;
+ DWORD DataOffset;
+ WORD DataSelector;
+ WORD Reserved3;
+ DWORD MxCsr;
+ DWORD MxCsr_Mask;
+ M128A FloatRegisters[8];
+ M128A XmmRegisters[16];
+ BYTE Reserved4[96];
+} XMM_SAVE_AREA32, *PXMM_SAVE_AREA32;
+
+#define LEGACY_SAVE_AREA_LENGTH sizeof(XMM_SAVE_AREA32)
+
+//
+// Context Frame
+//
+// This frame has a several purposes: 1) it is used as an argument to
+// NtContinue, 2) is is used to constuct a call frame for APC delivery,
+// and 3) it is used in the user level thread creation routines.
+//
+//
+// The flags field within this record controls the contents of a CONTEXT
+// record.
+//
+// If the context record is used as an input parameter, then for each
+// portion of the context record controlled by a flag whose value is
+// set, it is assumed that that portion of the context record contains
+// valid context. If the context record is being used to modify a threads
+// context, then only that portion of the threads context is modified.
+//
+// If the context record is used as an output parameter to capture the
+// context of a thread, then only those portions of the thread's context
+// corresponding to set flags will be returned.
+//
+// CONTEXT_CONTROL specifies SegSs, Rsp, SegCs, Rip, and EFlags.
+//
+// CONTEXT_INTEGER specifies Rax, Rcx, Rdx, Rbx, Rbp, Rsi, Rdi, and R8-R15.
+//
+// CONTEXT_SEGMENTS specifies SegDs, SegEs, SegFs, and SegGs.
+//
+// CONTEXT_DEBUG_REGISTERS specifies Dr0-Dr3 and Dr6-Dr7.
+//
+// CONTEXT_MMX_REGISTERS specifies the floating point and extended registers
+// Mm0/St0-Mm7/St7 and Xmm0-Xmm15).
+//
+
+typedef struct DECLSPEC_ALIGN(16) _CONTEXT {
+
+ //
+ // Register parameter home addresses.
+ //
+ // N.B. These fields are for convience - they could be used to extend the
+ // context record in the future.
+ //
+
+ DWORD64 P1Home;
+ DWORD64 P2Home;
+ DWORD64 P3Home;
+ DWORD64 P4Home;
+ DWORD64 P5Home;
+ DWORD64 P6Home;
+
+ //
+ // Control flags.
+ //
+
+ DWORD ContextFlags;
+ DWORD MxCsr;
+
+ //
+ // Segment Registers and processor flags.
+ //
+
+ WORD SegCs;
+ WORD SegDs;
+ WORD SegEs;
+ WORD SegFs;
+ WORD SegGs;
+ WORD SegSs;
+ DWORD EFlags;
+
+ //
+ // Debug registers
+ //
+
+ DWORD64 Dr0;
+ DWORD64 Dr1;
+ DWORD64 Dr2;
+ DWORD64 Dr3;
+ DWORD64 Dr6;
+ DWORD64 Dr7;
+
+ //
+ // Integer registers.
+ //
+
+ DWORD64 Rax;
+ DWORD64 Rcx;
+ DWORD64 Rdx;
+ DWORD64 Rbx;
+ DWORD64 Rsp;
+ DWORD64 Rbp;
+ DWORD64 Rsi;
+ DWORD64 Rdi;
+ DWORD64 R8;
+ DWORD64 R9;
+ DWORD64 R10;
+ DWORD64 R11;
+ DWORD64 R12;
+ DWORD64 R13;
+ DWORD64 R14;
+ DWORD64 R15;
+
+ //
+ // Program counter.
+ //
+
+ DWORD64 Rip;
+
+ //
+ // Floating point state.
+ //
+
+ union {
+ XMM_SAVE_AREA32 FltSave;
+ struct {
+ M128A Header[2];
+ M128A Legacy[8];
+ M128A Xmm0;
+ M128A Xmm1;
+ M128A Xmm2;
+ M128A Xmm3;
+ M128A Xmm4;
+ M128A Xmm5;
+ M128A Xmm6;
+ M128A Xmm7;
+ M128A Xmm8;
+ M128A Xmm9;
+ M128A Xmm10;
+ M128A Xmm11;
+ M128A Xmm12;
+ M128A Xmm13;
+ M128A Xmm14;
+ M128A Xmm15;
+ };
+ };
+
+ //
+ // Vector registers.
+ //
+
+ M128A VectorRegister[26];
+ DWORD64 VectorControl;
+
+ //
+ // Special debug control registers.
+ //
+
+ DWORD64 DebugControl;
+ DWORD64 LastBranchToRip;
+ DWORD64 LastBranchFromRip;
+ DWORD64 LastExceptionToRip;
+ DWORD64 LastExceptionFromRip;
+} CONTEXT, *PCONTEXT, *LPCONTEXT;
+
+//
+// Nonvolatile context pointer record.
+//
+
+typedef struct _KNONVOLATILE_CONTEXT_POINTERS {
+ union {
+ PM128A FloatingContext[16];
+ struct {
+ PM128A Xmm0;
+ PM128A Xmm1;
+ PM128A Xmm2;
+ PM128A Xmm3;
+ PM128A Xmm4;
+ PM128A Xmm5;
+ PM128A Xmm6;
+ PM128A Xmm7;
+ PM128A Xmm8;
+ PM128A Xmm9;
+ PM128A Xmm10;
+ PM128A Xmm11;
+ PM128A Xmm12;
+ PM128A Xmm13;
+ PM128A Xmm14;
+ PM128A Xmm15;
+ } ;
+ } ;
+
+ union {
+ PDWORD64 IntegerContext[16];
+ struct {
+ PDWORD64 Rax;
+ PDWORD64 Rcx;
+ PDWORD64 Rdx;
+ PDWORD64 Rbx;
+ PDWORD64 Rsp;
+ PDWORD64 Rbp;
+ PDWORD64 Rsi;
+ PDWORD64 Rdi;
+ PDWORD64 R8;
+ PDWORD64 R9;
+ PDWORD64 R10;
+ PDWORD64 R11;
+ PDWORD64 R12;
+ PDWORD64 R13;
+ PDWORD64 R14;
+ PDWORD64 R15;
+ } ;
+ } ;
+
+} KNONVOLATILE_CONTEXT_POINTERS, *PKNONVOLATILE_CONTEXT_POINTERS;
+
+#elif defined(_ARM_)
+
+#define CONTEXT_ARM 0x00200000L
+
+// end_wx86
+
+#define CONTEXT_CONTROL (CONTEXT_ARM | 0x1L)
+#define CONTEXT_INTEGER (CONTEXT_ARM | 0x2L)
+#define CONTEXT_FLOATING_POINT (CONTEXT_ARM | 0x4L)
+#define CONTEXT_DEBUG_REGISTERS (CONTEXT_ARM | 0x8L)
+
+#define CONTEXT_FULL (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT)
+
+#define CONTEXT_ALL (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT | CONTEXT_DEBUG_REGISTERS)
+
+#define CONTEXT_EXCEPTION_ACTIVE 0x8000000L
+#define CONTEXT_SERVICE_ACTIVE 0x10000000L
+#define CONTEXT_EXCEPTION_REQUEST 0x40000000L
+#define CONTEXT_EXCEPTION_REPORTING 0x80000000L
+
+//
+// This flag is set by the unwinder if it has unwound to a call
+// site, and cleared whenever it unwinds through a trap frame.
+// It is used by language-specific exception handlers to help
+// differentiate exception scopes during dispatching.
+//
+
+#define CONTEXT_UNWOUND_TO_CALL 0x20000000
+
+//
+// Specify the number of breakpoints and watchpoints that the OS
+// will track. Architecturally, ARM supports up to 16. In practice,
+// however, almost no one implements more than 4 of each.
+//
+
+#define ARM_MAX_BREAKPOINTS 8
+#define ARM_MAX_WATCHPOINTS 1
+
+typedef struct _NEON128 {
+ ULONGLONG Low;
+ LONGLONG High;
+} NEON128, *PNEON128;
+
+//
+// Context Frame
+//
+// This frame has a several purposes: 1) it is used as an argument to
+// NtContinue, 2) it is used to constuct a call frame for APC delivery,
+// and 3) it is used in the user level thread creation routines.
+//
+//
+// The flags field within this record controls the contents of a CONTEXT
+// record.
+//
+// If the context record is used as an input parameter, then for each
+// portion of the context record controlled by a flag whose value is
+// set, it is assumed that that portion of the context record contains
+// valid context. If the context record is being used to modify a threads
+// context, then only that portion of the threads context is modified.
+//
+// If the context record is used as an output parameter to capture the
+// context of a thread, then only those portions of the thread's context
+// corresponding to set flags will be returned.
+//
+// CONTEXT_CONTROL specifies Sp, Lr, Pc, and Cpsr
+//
+// CONTEXT_INTEGER specifies R0-R12
+//
+// CONTEXT_FLOATING_POINT specifies Q0-Q15 / D0-D31 / S0-S31
+//
+// CONTEXT_DEBUG_REGISTERS specifies up to 16 of DBGBVR, DBGBCR, DBGWVR,
+// DBGWCR.
+//
+
+typedef struct DECLSPEC_ALIGN(8) _CONTEXT {
+
+ //
+ // Control flags.
+ //
+
+ DWORD ContextFlags;
+
+ //
+ // Integer registers
+ //
+
+ DWORD R0;
+ DWORD R1;
+ DWORD R2;
+ DWORD R3;
+ DWORD R4;
+ DWORD R5;
+ DWORD R6;
+ DWORD R7;
+ DWORD R8;
+ DWORD R9;
+ DWORD R10;
+ DWORD R11;
+ DWORD R12;
+
+ //
+ // Control Registers
+ //
+
+ DWORD Sp;
+ DWORD Lr;
+ DWORD Pc;
+ DWORD Cpsr;
+
+ //
+ // Floating Point/NEON Registers
+ //
+
+ DWORD Fpscr;
+ DWORD Padding;
+ union {
+ NEON128 Q[16];
+ ULONGLONG D[32];
+ DWORD S[32];
+ };
+
+ //
+ // Debug registers
+ //
+
+ DWORD Bvr[ARM_MAX_BREAKPOINTS];
+ DWORD Bcr[ARM_MAX_BREAKPOINTS];
+ DWORD Wvr[ARM_MAX_WATCHPOINTS];
+ DWORD Wcr[ARM_MAX_WATCHPOINTS];
+
+ DWORD Padding2[2];
+
+} CONTEXT, *PCONTEXT, *LPCONTEXT;
+
+//
+// Nonvolatile context pointer record.
+//
+
+typedef struct _KNONVOLATILE_CONTEXT_POINTERS {
+
+ PDWORD R4;
+ PDWORD R5;
+ PDWORD R6;
+ PDWORD R7;
+ PDWORD R8;
+ PDWORD R9;
+ PDWORD R10;
+ PDWORD R11;
+ PDWORD Lr;
+
+ PULONGLONG D8;
+ PULONGLONG D9;
+ PULONGLONG D10;
+ PULONGLONG D11;
+ PULONGLONG D12;
+ PULONGLONG D13;
+ PULONGLONG D14;
+ PULONGLONG D15;
+
+} KNONVOLATILE_CONTEXT_POINTERS, *PKNONVOLATILE_CONTEXT_POINTERS;
+
+typedef struct _IMAGE_ARM_RUNTIME_FUNCTION_ENTRY {
+ DWORD BeginAddress;
+ DWORD EndAddress;
+ union {
+ DWORD UnwindData;
+ struct {
+ DWORD Flag : 2;
+ DWORD FunctionLength : 11;
+ DWORD Ret : 2;
+ DWORD H : 1;
+ DWORD Reg : 3;
+ DWORD R : 1;
+ DWORD L : 1;
+ DWORD C : 1;
+ DWORD StackAdjust : 10;
+ };
+ };
+} IMAGE_ARM_RUNTIME_FUNCTION_ENTRY, * PIMAGE_ARM_RUNTIME_FUNCTION_ENTRY;
+
+#elif defined(_ARM64_)
+
+#define CONTEXT_ARM64 0x00400000L
+
+#define CONTEXT_CONTROL (CONTEXT_ARM64 | 0x1L)
+#define CONTEXT_INTEGER (CONTEXT_ARM64 | 0x2L)
+#define CONTEXT_FLOATING_POINT (CONTEXT_ARM64 | 0x4L)
+#define CONTEXT_DEBUG_REGISTERS (CONTEXT_ARM64 | 0x8L)
+
+#define CONTEXT_FULL (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT)
+
+#define CONTEXT_ALL (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT | CONTEXT_DEBUG_REGISTERS)
+
+#define CONTEXT_EXCEPTION_ACTIVE 0x8000000L
+#define CONTEXT_SERVICE_ACTIVE 0x10000000L
+#define CONTEXT_EXCEPTION_REQUEST 0x40000000L
+#define CONTEXT_EXCEPTION_REPORTING 0x80000000L
+
+//
+// This flag is set by the unwinder if it has unwound to a call
+// site, and cleared whenever it unwinds through a trap frame.
+// It is used by language-specific exception handlers to help
+// differentiate exception scopes during dispatching.
+//
+
+#define CONTEXT_UNWOUND_TO_CALL 0x20000000
+
+//
+// Define initial Cpsr/Fpscr value
+//
+
+#define INITIAL_CPSR 0x10
+#define INITIAL_FPSCR 0
+
+// begin_ntoshvp
+
+//
+// Specify the number of breakpoints and watchpoints that the OS
+// will track. Architecturally, ARM64 supports up to 16. In practice,
+// however, almost no one implements more than 4 of each.
+//
+
+#define ARM64_MAX_BREAKPOINTS 8
+#define ARM64_MAX_WATCHPOINTS 2
+
+//
+// Context Frame
+//
+// This frame has a several purposes: 1) it is used as an argument to
+// NtContinue, 2) it is used to constuct a call frame for APC delivery,
+// and 3) it is used in the user level thread creation routines.
+//
+//
+// The flags field within this record controls the contents of a CONTEXT
+// record.
+//
+// If the context record is used as an input parameter, then for each
+// portion of the context record controlled by a flag whose value is
+// set, it is assumed that that portion of the context record contains
+// valid context. If the context record is being used to modify a threads
+// context, then only that portion of the threads context is modified.
+//
+// If the context record is used as an output parameter to capture the
+// context of a thread, then only those portions of the thread's context
+// corresponding to set flags will be returned.
+//
+// CONTEXT_CONTROL specifies Sp, Lr, Pc, and Cpsr
+//
+// CONTEXT_INTEGER specifies R0-R12
+//
+// CONTEXT_FLOATING_POINT specifies Q0-Q15 / D0-D31 / S0-S31
+//
+// CONTEXT_DEBUG_REGISTERS specifies up to 16 of DBGBVR, DBGBCR, DBGWVR,
+// DBGWCR.
+//
+
+typedef struct _NEON128 {
+ ULONGLONG Low;
+ LONGLONG High;
+} NEON128, *PNEON128;
+
+typedef struct DECLSPEC_ALIGN(16) _CONTEXT {
+
+ //
+ // Control flags.
+ //
+
+ /* +0x000 */ DWORD ContextFlags;
+
+ //
+ // Integer registers
+ //
+
+ /* +0x004 */ DWORD Cpsr; // NZVF + DAIF + CurrentEL + SPSel
+ /* +0x008 */ union {
+ struct {
+ DWORD64 X0;
+ DWORD64 X1;
+ DWORD64 X2;
+ DWORD64 X3;
+ DWORD64 X4;
+ DWORD64 X5;
+ DWORD64 X6;
+ DWORD64 X7;
+ DWORD64 X8;
+ DWORD64 X9;
+ DWORD64 X10;
+ DWORD64 X11;
+ DWORD64 X12;
+ DWORD64 X13;
+ DWORD64 X14;
+ DWORD64 X15;
+ DWORD64 X16;
+ DWORD64 X17;
+ DWORD64 X18;
+ DWORD64 X19;
+ DWORD64 X20;
+ DWORD64 X21;
+ DWORD64 X22;
+ DWORD64 X23;
+ DWORD64 X24;
+ DWORD64 X25;
+ DWORD64 X26;
+ DWORD64 X27;
+ DWORD64 X28;
+ };
+ DWORD64 X[29];
+ };
+ /* +0x0f0 */ DWORD64 Fp;
+ /* +0x0f8 */ DWORD64 Lr;
+ /* +0x100 */ DWORD64 Sp;
+ /* +0x108 */ DWORD64 Pc;
+
+ //
+ // Floating Point/NEON Registers
+ //
+
+ /* +0x110 */ NEON128 V[32];
+ /* +0x310 */ DWORD Fpcr;
+ /* +0x314 */ DWORD Fpsr;
+
+ //
+ // Debug registers
+ //
+
+ /* +0x318 */ DWORD Bcr[ARM64_MAX_BREAKPOINTS];
+ /* +0x338 */ DWORD64 Bvr[ARM64_MAX_BREAKPOINTS];
+ /* +0x378 */ DWORD Wcr[ARM64_MAX_WATCHPOINTS];
+ /* +0x380 */ DWORD64 Wvr[ARM64_MAX_WATCHPOINTS];
+ /* +0x390 */
+
+} CONTEXT, *PCONTEXT, *LPCONTEXT;
+
+//
+// Nonvolatile context pointer record.
+//
+
+typedef struct _KNONVOLATILE_CONTEXT_POINTERS {
+
+ PDWORD64 X19;
+ PDWORD64 X20;
+ PDWORD64 X21;
+ PDWORD64 X22;
+ PDWORD64 X23;
+ PDWORD64 X24;
+ PDWORD64 X25;
+ PDWORD64 X26;
+ PDWORD64 X27;
+ PDWORD64 X28;
+ PDWORD64 Fp;
+ PDWORD64 Lr;
+
+ PDWORD64 D8;
+ PDWORD64 D9;
+ PDWORD64 D10;
+ PDWORD64 D11;
+ PDWORD64 D12;
+ PDWORD64 D13;
+ PDWORD64 D14;
+ PDWORD64 D15;
+
+} KNONVOLATILE_CONTEXT_POINTERS, *PKNONVOLATILE_CONTEXT_POINTERS;
+
+#else
+#error Unknown architecture for defining CONTEXT.
+#endif
+
+
+PALIMPORT
+BOOL
+PALAPI
+GetThreadContext(
+ IN HANDLE hThread,
+ IN OUT LPCONTEXT lpContext);
+
+PALIMPORT
+BOOL
+PALAPI
+SetThreadContext(
+ IN HANDLE hThread,
+ IN CONST CONTEXT *lpContext);
+
+#define THREAD_BASE_PRIORITY_LOWRT 15
+#define THREAD_BASE_PRIORITY_MAX 2
+#define THREAD_BASE_PRIORITY_MIN (-2)
+#define THREAD_BASE_PRIORITY_IDLE (-15)
+
+#define THREAD_PRIORITY_LOWEST THREAD_BASE_PRIORITY_MIN
+#define THREAD_PRIORITY_BELOW_NORMAL (THREAD_PRIORITY_LOWEST+1)
+#define THREAD_PRIORITY_NORMAL 0
+#define THREAD_PRIORITY_HIGHEST THREAD_BASE_PRIORITY_MAX
+#define THREAD_PRIORITY_ABOVE_NORMAL (THREAD_PRIORITY_HIGHEST-1)
+#define THREAD_PRIORITY_ERROR_RETURN (MAXLONG)
+
+#define THREAD_PRIORITY_TIME_CRITICAL THREAD_BASE_PRIORITY_LOWRT
+#define THREAD_PRIORITY_IDLE THREAD_BASE_PRIORITY_IDLE
+
+PALIMPORT
+int
+PALAPI
+GetThreadPriority(
+ IN HANDLE hThread);
+
+PALIMPORT
+BOOL
+PALAPI
+SetThreadPriority(
+ IN HANDLE hThread,
+ IN int nPriority);
+
+PALIMPORT
+BOOL
+PALAPI
+GetThreadTimes(
+ IN HANDLE hThread,
+ OUT LPFILETIME lpCreationTime,
+ OUT LPFILETIME lpExitTime,
+ OUT LPFILETIME lpKernelTime,
+ OUT LPFILETIME lpUserTime);
+
+#define TLS_OUT_OF_INDEXES ((DWORD)0xFFFFFFFF)
+
+PALIMPORT
+DWORD
+PALAPI
+TlsAlloc(
+ VOID);
+
+PALIMPORT
+LPVOID
+PALAPI
+TlsGetValue(
+ IN DWORD dwTlsIndex);
+
+PALIMPORT
+BOOL
+PALAPI
+TlsSetValue(
+ IN DWORD dwTlsIndex,
+ IN LPVOID lpTlsValue);
+
+PALIMPORT
+BOOL
+PALAPI
+TlsFree(
+ IN DWORD dwTlsIndex);
+
+PALIMPORT
+void *
+PALAPI
+PAL_GetStackBase();
+
+PALIMPORT
+void *
+PALAPI
+PAL_GetStackLimit();
+
+PALIMPORT
+DWORD
+PALAPI
+PAL_GetLogicalCpuCountFromOS();
+
+PALIMPORT
+size_t
+PALAPI
+PAL_GetLogicalProcessorCacheSizeFromOS();
+
+typedef BOOL (*ReadMemoryWordCallback)(SIZE_T address, SIZE_T *value);
+
+PALIMPORT BOOL PALAPI PAL_VirtualUnwind(CONTEXT *context, KNONVOLATILE_CONTEXT_POINTERS *contextPointers);
+
+PALIMPORT BOOL PALAPI PAL_VirtualUnwindOutOfProc(CONTEXT *context,
+ KNONVOLATILE_CONTEXT_POINTERS *contextPointers,
+ DWORD pid,
+ ReadMemoryWordCallback readMemCallback);
+
+#define GetLogicalProcessorCacheSizeFromOS PAL_GetLogicalProcessorCacheSizeFromOS
+
+#ifdef PLATFORM_UNIX
+
+/* PAL_CS_NATIVE_DATA_SIZE is defined as sizeof(PAL_CRITICAL_SECTION_NATIVE_DATA) */
+
+#if defined(_AIX)
+#define PAL_CS_NATIVE_DATA_SIZE 100
+#elif defined(__APPLE__) && defined(__i386__)
+#define PAL_CS_NATIVE_DATA_SIZE 76
+#elif defined(__APPLE__) && defined(__x86_64__)
+#define PAL_CS_NATIVE_DATA_SIZE 120
+#elif defined(__FreeBSD__) && defined(_X86_)
+#define PAL_CS_NATIVE_DATA_SIZE 12
+#elif defined(__FreeBSD__) && defined(__x86_64__)
+#define PAL_CS_NATIVE_DATA_SIZE 24
+#elif defined(__hpux__) && (defined(__hppa__) || defined (__ia64__))
+#define PAL_CS_NATIVE_DATA_SIZE 148
+#elif defined(__linux__) && defined(_ARM_)
+#define PAL_CS_NATIVE_DATA_SIZE 80
+#elif defined(__linux__) && defined(_ARM64_)
+#define PAL_CS_NATIVE_DATA_SIZE 116
+#elif defined(__linux__) && defined(__x86_64__)
+#define PAL_CS_NATIVE_DATA_SIZE 96
+#elif defined(__NetBSD__) && defined(__amd64__)
+#define PAL_CS_NATIVE_DATA_SIZE 96
+#elif defined(__NetBSD__) && defined(__earm__)
+#define PAL_CS_NATIVE_DATA_SIZE 56
+#elif defined(__NetBSD__) && defined(__hppa__)
+#define PAL_CS_NATIVE_DATA_SIZE 92
+#elif defined(__NetBSD__) && defined(__i386__)
+#define PAL_CS_NATIVE_DATA_SIZE 56
+#elif defined(__NetBSD__) && defined(__mips__)
+#define PAL_CS_NATIVE_DATA_SIZE 56
+#elif defined(__NetBSD__) && (defined(__sparc__) && !defined(__sparc64__))
+#define PAL_CS_NATIVE_DATA_SIZE 56
+#elif defined(__NetBSD__) && defined(__sparc64__)
+#define PAL_CS_NATIVE_DATA_SIZE 92
+#elif defined(__sun__)
+#define PAL_CS_NATIVE_DATA_SIZE 48
+#else
+#warning
+#error PAL_CS_NATIVE_DATA_SIZE is not defined for this architecture
+#endif
+
+#endif // PLATFORM_UNIX
+
+//
+typedef struct _CRITICAL_SECTION {
+ PVOID DebugInfo;
+ LONG LockCount;
+ LONG RecursionCount;
+ HANDLE OwningThread;
+ HANDLE LockSemaphore;
+ ULONG_PTR SpinCount;
+
+#ifdef PLATFORM_UNIX
+ BOOL bInternal;
+ volatile DWORD dwInitState;
+ union CSNativeDataStorage
+ {
+ BYTE rgNativeDataStorage[PAL_CS_NATIVE_DATA_SIZE];
+ VOID * pvAlign; // make sure the storage is machine-pointer-size aligned
+ } csnds;
+#endif // PLATFORM_UNIX
+} CRITICAL_SECTION, *PCRITICAL_SECTION, *LPCRITICAL_SECTION;
+
+PALIMPORT VOID PALAPI EnterCriticalSection(IN OUT LPCRITICAL_SECTION lpCriticalSection);
+PALIMPORT VOID PALAPI LeaveCriticalSection(IN OUT LPCRITICAL_SECTION lpCriticalSection);
+PALIMPORT VOID PALAPI InitializeCriticalSection(OUT LPCRITICAL_SECTION lpCriticalSection);
+PALIMPORT BOOL PALAPI InitializeCriticalSectionEx(LPCRITICAL_SECTION lpCriticalSection, DWORD dwSpinCount, DWORD Flags);
+PALIMPORT VOID PALAPI DeleteCriticalSection(IN OUT LPCRITICAL_SECTION lpCriticalSection);
+PALIMPORT BOOL PALAPI TryEnterCriticalSection(IN OUT LPCRITICAL_SECTION lpCriticalSection);
+
+#define SEM_FAILCRITICALERRORS 0x0001
+#define SEM_NOOPENFILEERRORBOX 0x8000
+
+PALIMPORT
+UINT
+PALAPI
+SetErrorMode(
+ IN UINT uMode);
+
+#define PAGE_NOACCESS 0x01
+#define PAGE_READONLY 0x02
+#define PAGE_READWRITE 0x04
+#define PAGE_WRITECOPY 0x08
+#define PAGE_EXECUTE 0x10
+#define PAGE_EXECUTE_READ 0x20
+#define PAGE_EXECUTE_READWRITE 0x40
+#define PAGE_EXECUTE_WRITECOPY 0x80
+#define MEM_COMMIT 0x1000
+#define MEM_RESERVE 0x2000
+#define MEM_DECOMMIT 0x4000
+#define MEM_RELEASE 0x8000
+#define MEM_RESET 0x80000
+#define MEM_FREE 0x10000
+#define MEM_PRIVATE 0x20000
+#define MEM_MAPPED 0x40000
+#define MEM_TOP_DOWN 0x100000
+#define MEM_WRITE_WATCH 0x200000
+#define MEM_RESERVE_EXECUTABLE 0x40000000 // reserve memory using executable memory allocator
+
+PALIMPORT
+HANDLE
+PALAPI
+CreateFileMappingW(
+ IN HANDLE hFile,
+ IN LPSECURITY_ATTRIBUTES lpFileMappingAttributes,
+ IN DWORD flProtect,
+ IN DWORD dwMaxmimumSizeHigh,
+ IN DWORD dwMaximumSizeLow,
+ IN LPCWSTR lpName);
+
+#ifdef UNICODE
+#define CreateFileMapping CreateFileMappingW
+#else
+#define CreateFileMapping CreateFileMappingA
+#endif
+
+#define SECTION_QUERY 0x0001
+#define SECTION_MAP_WRITE 0x0002
+#define SECTION_MAP_READ 0x0004
+#define SECTION_ALL_ACCESS (SECTION_MAP_READ | SECTION_MAP_WRITE) // diff from winnt.h
+
+#define FILE_MAP_WRITE SECTION_MAP_WRITE
+#define FILE_MAP_READ SECTION_MAP_READ
+#define FILE_MAP_ALL_ACCESS SECTION_ALL_ACCESS
+#define FILE_MAP_COPY SECTION_QUERY
+
+PALIMPORT
+HANDLE
+PALAPI
+OpenFileMappingW(
+ IN DWORD dwDesiredAccess,
+ IN BOOL bInheritHandle,
+ IN LPCWSTR lpName);
+
+#ifdef UNICODE
+#define OpenFileMapping OpenFileMappingW
+#else
+#define OpenFileMapping OpenFileMappingA
+#endif
+
+PALIMPORT
+LPVOID
+PALAPI
+MapViewOfFile(
+ IN HANDLE hFileMappingObject,
+ IN DWORD dwDesiredAccess,
+ IN DWORD dwFileOffsetHigh,
+ IN DWORD dwFileOffsetLow,
+ IN SIZE_T dwNumberOfBytesToMap);
+
+PALIMPORT
+LPVOID
+PALAPI
+MapViewOfFileEx(
+ IN HANDLE hFileMappingObject,
+ IN DWORD dwDesiredAccess,
+ IN DWORD dwFileOffsetHigh,
+ IN DWORD dwFileOffsetLow,
+ IN SIZE_T dwNumberOfBytesToMap,
+ IN LPVOID lpBaseAddress);
+
+PALIMPORT
+BOOL
+PALAPI
+FlushViewOfFile(
+ IN LPVOID lpBaseAddress,
+ IN SIZE_T dwNumberOfBytesToFlush);
+
+PALIMPORT
+BOOL
+PALAPI
+UnmapViewOfFile(
+ IN LPCVOID lpBaseAddress);
+
+
+PALIMPORT
+HMODULE
+PALAPI
+LoadLibraryW(
+ IN LPCWSTR lpLibFileName);
+
+PALIMPORT
+HMODULE
+PALAPI
+LoadLibraryExW(
+ IN LPCWSTR lpLibFileName,
+ IN /*Reserved*/ HANDLE hFile,
+ IN DWORD dwFlags);
+
+PALIMPORT
+void *
+PALAPI
+PAL_LoadLibraryDirect(
+ IN LPCWSTR lpLibFileName);
+
+PALIMPORT
+HMODULE
+PALAPI
+PAL_RegisterLibraryDirect(
+ IN void *dl_handle,
+ IN LPCWSTR lpLibFileName);
+
+/*++
+Function:
+ PAL_LOADLoadPEFile
+
+Abstract
+ Loads a PE file into memory. Properly maps all of the sections in the PE file. Returns a pointer to the
+ loaded base.
+
+Parameters:
+ IN hFile - The file to load
+
+Return value:
+ A valid base address if successful.
+ 0 if failure
+--*/
+void *
+PALAPI
+PAL_LOADLoadPEFile(HANDLE hFile);
+
+/*++
+ PAL_LOADUnloadPEFile
+
+ Unload a PE file that was loaded by PAL_LOADLoadPEFile().
+
+Parameters:
+ IN ptr - the file pointer returned by PAL_LOADLoadPEFile()
+
+Return value:
+ TRUE - success
+ FALSE - failure (incorrect ptr, etc.)
+--*/
+BOOL
+PALAPI
+PAL_LOADUnloadPEFile(void * ptr);
+
+#ifdef UNICODE
+#define LoadLibrary LoadLibraryW
+#define LoadLibraryEx LoadLibraryExW
+#else
+#define LoadLibrary LoadLibraryA
+#define LoadLibraryEx LoadLibraryExA
+#endif
+
+typedef INT_PTR (PALAPI *FARPROC)();
+
+PALIMPORT
+FARPROC
+PALAPI
+GetProcAddress(
+ IN HMODULE hModule,
+ IN LPCSTR lpProcName);
+
+PALIMPORT
+BOOL
+PALAPI
+FreeLibrary(
+ IN OUT HMODULE hLibModule);
+
+PALIMPORT
+PAL_NORETURN
+VOID
+PALAPI
+FreeLibraryAndExitThread(
+ IN HMODULE hLibModule,
+ IN DWORD dwExitCode);
+
+PALIMPORT
+BOOL
+PALAPI
+DisableThreadLibraryCalls(
+ IN HMODULE hLibModule);
+
+PALIMPORT
+DWORD
+PALAPI
+GetModuleFileNameW(
+ IN HMODULE hModule,
+ OUT LPWSTR lpFileName,
+ IN DWORD nSize);
+
+#ifdef UNICODE
+#define GetModuleFileName GetModuleFileNameW
+#else
+#define GetModuleFileName GetModuleFileNameA
+#endif
+
+PALIMPORT
+DWORD
+PALAPI
+GetModuleFileNameExW(
+ IN HANDLE hProcess,
+ IN HMODULE hModule,
+ OUT LPWSTR lpFilename,
+ IN DWORD nSize
+ );
+
+#ifdef UNICODE
+#define GetModuleFileNameEx GetModuleFileNameExW
+#endif
+
+// Get base address of the module containing a given symbol
+PALAPI
+LPCVOID
+PAL_GetSymbolModuleBase(void *symbol);
+
+PALIMPORT
+LPVOID
+PALAPI
+VirtualAlloc(
+ IN LPVOID lpAddress,
+ IN SIZE_T dwSize,
+ IN DWORD flAllocationType,
+ IN DWORD flProtect);
+
+PALIMPORT
+BOOL
+PALAPI
+VirtualFree(
+ IN LPVOID lpAddress,
+ IN SIZE_T dwSize,
+ IN DWORD dwFreeType);
+
+PALIMPORT
+BOOL
+PALAPI
+VirtualProtect(
+ IN LPVOID lpAddress,
+ IN SIZE_T dwSize,
+ IN DWORD flNewProtect,
+ OUT PDWORD lpflOldProtect);
+
+typedef struct _MEMORYSTATUSEX {
+ DWORD dwLength;
+ DWORD dwMemoryLoad;
+ DWORDLONG ullTotalPhys;
+ DWORDLONG ullAvailPhys;
+ DWORDLONG ullTotalPageFile;
+ DWORDLONG ullAvailPageFile;
+ DWORDLONG ullTotalVirtual;
+ DWORDLONG ullAvailVirtual;
+ DWORDLONG ullAvailExtendedVirtual;
+} MEMORYSTATUSEX, *LPMEMORYSTATUSEX;
+
+PALIMPORT
+BOOL
+PALAPI
+GlobalMemoryStatusEx(
+ IN OUT LPMEMORYSTATUSEX lpBuffer);
+
+typedef struct _MEMORY_BASIC_INFORMATION {
+ PVOID BaseAddress;
+ PVOID AllocationBase_PAL_Undefined;
+ DWORD AllocationProtect;
+ SIZE_T RegionSize;
+ DWORD State;
+ DWORD Protect;
+ DWORD Type;
+} MEMORY_BASIC_INFORMATION, *PMEMORY_BASIC_INFORMATION;
+
+PALIMPORT
+SIZE_T
+PALAPI
+VirtualQuery(
+ IN LPCVOID lpAddress,
+ OUT PMEMORY_BASIC_INFORMATION lpBuffer,
+ IN SIZE_T dwLength);
+
+PALIMPORT
+BOOL
+PALAPI
+ReadProcessMemory(
+ IN HANDLE hProcess,
+ IN LPCVOID lpBaseAddress,
+ OUT LPVOID lpBuffer,
+ IN SIZE_T nSize,
+ OUT SIZE_T * lpNumberOfBytesRead);
+
+PALIMPORT
+VOID
+PALAPI
+RtlMoveMemory(
+ IN PVOID Destination,
+ IN CONST VOID *Source,
+ IN SIZE_T Length);
+
+PALIMPORT
+VOID
+PALAPI
+RtlZeroMemory(
+ IN PVOID Destination,
+ IN SIZE_T Length);
+
+#define MoveMemory memmove
+#define CopyMemory memcpy
+#define FillMemory(Destination,Length,Fill) memset((Destination),(Fill),(Length))
+#define ZeroMemory(Destination,Length) memset((Destination),0,(Length))
+
+
+PALIMPORT
+HANDLE
+PALAPI
+GetProcessHeap(
+ VOID);
+
+#define HEAP_ZERO_MEMORY 0x00000008
+
+PALIMPORT
+HANDLE
+PALAPI
+HeapCreate(
+ IN DWORD flOptions,
+ IN SIZE_T dwInitialSize,
+ IN SIZE_T dwMaximumSize);
+
+PALIMPORT
+LPVOID
+PALAPI
+HeapAlloc(
+ IN HANDLE hHeap,
+ IN DWORD dwFlags,
+ IN SIZE_T dwBytes);
+
+PALIMPORT
+LPVOID
+PALAPI
+HeapReAlloc(
+ IN HANDLE hHeap,
+ IN DWORD dwFlags,
+ IN LPVOID lpMem,
+ IN SIZE_T dwBytes
+ );
+
+PALIMPORT
+BOOL
+PALAPI
+HeapFree(
+ IN HANDLE hHeap,
+ IN DWORD dwFlags,
+ IN LPVOID lpMem);
+
+typedef enum _HEAP_INFORMATION_CLASS {
+ HeapCompatibilityInformation,
+ HeapEnableTerminationOnCorruption
+} HEAP_INFORMATION_CLASS;
+
+PALIMPORT
+BOOL
+PALAPI
+HeapSetInformation(
+ IN OPTIONAL HANDLE HeapHandle,
+ IN HEAP_INFORMATION_CLASS HeapInformationClass,
+ IN PVOID HeapInformation,
+ IN SIZE_T HeapInformationLength);
+
+#define LMEM_FIXED 0x0000
+#define LMEM_MOVEABLE 0x0002
+#define LMEM_ZEROINIT 0x0040
+#define LPTR (LMEM_FIXED | LMEM_ZEROINIT)
+
+PALIMPORT
+HLOCAL
+PALAPI
+LocalAlloc(
+ IN UINT uFlags,
+ IN SIZE_T uBytes);
+
+PALIMPORT
+HLOCAL
+PALAPI
+LocalReAlloc(
+ IN HLOCAL hMem,
+ IN SIZE_T uBytes,
+ IN UINT uFlags);
+
+PALIMPORT
+HLOCAL
+PALAPI
+LocalFree(
+ IN HLOCAL hMem);
+
+PALIMPORT
+BOOL
+PALAPI
+FlushInstructionCache(
+ IN HANDLE hProcess,
+ IN LPCVOID lpBaseAddress,
+ IN SIZE_T dwSize);
+
+#if ENABLE_DOWNLEVEL_FOR_NLS
+
+PALIMPORT
+BOOL
+PALAPI
+GetStringTypeExW(
+ IN LCID Locale,
+ IN DWORD dwInfoType,
+ IN LPCWSTR lpSrcStr,
+ IN int cchSrc,
+ OUT LPWORD lpCharType);
+
+#ifdef UNICODE
+#define GetStringTypeEx GetStringTypeExW
+#endif
+
+#endif // ENABLE_DOWNLEVEL_FOR_NLS
+
+
+#define NORM_IGNORECASE 0x00000001 // ignore case
+#define NORM_IGNOREWIDTH 0x00020000 // ignore width
+
+#define NORM_LINGUISTIC_CASING 0x08000000 // use linguistic rules for casing
+
+#ifdef __APPLE__
+#define NORM_IGNORENONSPACE 0x00000002 // ignore nonspacing chars
+#define NORM_IGNORESYMBOLS 0x00000004 // ignore symbols
+#define NORM_IGNOREKANATYPE 0x00010000 // ignore kanatype
+#define SORT_STRINGSORT 0x00001000 // use string sort method
+#endif // __APPLE__
+
+
+typedef struct nlsversioninfo {
+ DWORD dwNLSVersionInfoSize;
+ DWORD dwNLSVersion;
+ DWORD dwDefinedVersion;
+} NLSVERSIONINFO, *LPNLSVERSIONINFO;
+
+#define CSTR_LESS_THAN 1
+#define CSTR_EQUAL 2
+#define CSTR_GREATER_THAN 3
+
+#if ENABLE_DOWNLEVEL_FOR_NLS
+
+
+PALIMPORT
+int
+PALAPI
+CompareStringW(
+ IN LCID Locale,
+ IN DWORD dwCmpFlags,
+ IN LPCWSTR lpString1,
+ IN int cchCount1,
+ IN LPCWSTR lpString2,
+ IN int cchCount2);
+
+#endif // ENABLE_DOWNLEVEL_FOR_NLS
+
+
+PALIMPORT
+int
+PALAPI
+CompareStringEx(
+ IN LPCWSTR lpLocaleName,
+ IN DWORD dwCmpFlags,
+ IN LPCWSTR lpString1,
+ IN int cchCount1,
+ IN LPCWSTR lpString2,
+ IN int cchCount2,
+ IN LPNLSVERSIONINFO lpVersionInformation,
+ IN LPVOID lpReserved,
+ IN LPARAM lParam);
+
+
+#ifdef UNICODE
+#define CompareString CompareStringW
+#endif
+
+#define MAX_LEADBYTES 12
+#define MAX_DEFAULTCHAR 2
+
+PALIMPORT
+UINT
+PALAPI
+GetACP(void);
+
+typedef struct _cpinfo {
+ UINT MaxCharSize;
+ BYTE DefaultChar[MAX_DEFAULTCHAR];
+ BYTE LeadByte[MAX_LEADBYTES];
+} CPINFO, *LPCPINFO;
+
+PALIMPORT
+BOOL
+PALAPI
+GetCPInfo(
+ IN UINT CodePage,
+ OUT LPCPINFO lpCPInfo);
+
+PALIMPORT
+BOOL
+PALAPI
+IsDBCSLeadByteEx(
+ IN UINT CodePage,
+ IN BYTE TestChar);
+
+PALIMPORT
+BOOL
+PALAPI
+IsDBCSLeadByte(
+ IN BYTE TestChar);
+
+PALIMPORT
+BOOL
+PALAPI
+IsValidCodePage(
+ IN UINT CodePage);
+
+
+#define MB_PRECOMPOSED 0x00000001
+#define MB_ERR_INVALID_CHARS 0x00000008
+
+PALIMPORT
+int
+PALAPI
+MultiByteToWideChar(
+ IN UINT CodePage,
+ IN DWORD dwFlags,
+ IN LPCSTR lpMultiByteStr,
+ IN int cbMultiByte,
+ OUT LPWSTR lpWideCharStr,
+ IN int cchWideChar);
+
+#define WC_NO_BEST_FIT_CHARS 0x00000400
+
+PALIMPORT
+int
+PALAPI
+WideCharToMultiByte(
+ IN UINT CodePage,
+ IN DWORD dwFlags,
+ IN LPCWSTR lpWideCharStr,
+ IN int cchWideChar,
+ OUT LPSTR lpMultiByteStr,
+ IN int cbMultyByte,
+ IN LPCSTR lpDefaultChar,
+ OUT LPBOOL lpUsedDefaultChar);
+
+#if ENABLE_DOWNLEVEL_FOR_NLS
+
+PALIMPORT
+LANGID
+PALAPI
+GetSystemDefaultLangID(
+ void);
+
+PALIMPORT
+LANGID
+PALAPI
+GetUserDefaultLangID(
+ void);
+
+PALIMPORT
+BOOL
+PALAPI
+SetThreadLocale(
+ IN LCID Locale);
+
+PALIMPORT
+LCID
+PALAPI
+GetThreadLocale(
+ void);
+
+#endif //ENABLE_DOWNLEVEL_FOR_NLS
+
+//
+// Locale Types.
+//
+// These types are used for the GetLocaleInfo NLS API routine.
+//
+
+#ifdef __APPLE__
+
+//
+// The following LCTypes may be used in combination with any other LCTypes.
+//
+// LOCALE_NOUSEROVERRIDE is also used in GetTimeFormat and
+// GetDateFormat.
+//
+// LOCALE_RETURN_NUMBER will return the result from GetLocaleInfo as a
+// number instead of a string. This flag is only valid for the LCTypes
+// beginning with LOCALE_I.
+//
+#define LOCALE_NOUSEROVERRIDE 0x80000000 /* do not use user overrides */
+#define LOCALE_RETURN_NUMBER 0x20000000 /* return number instead of string */
+#define LOCALE_RETURN_GENITIVE_NAMES 0x10000000 //Flag to return the Genitive forms of month names
+
+#define LOCALE_SLOCALIZEDDISPLAYNAME 0x00000002 // localized name of locale, eg "German (Germany)" in UI language
+#define LOCALE_SENGLISHDISPLAYNAME 0x00000072 // Display name (language + country usually) in English, eg "German (Germany)"
+#define LOCALE_SNATIVEDISPLAYNAME 0x00000073 // Display name in native locale language, eg "Deutsch (Deutschland)
+
+#define LOCALE_SLOCALIZEDLANGUAGENAME 0x0000006f // Language Display Name for a language, eg "German" in UI language
+#define LOCALE_SENGLISHLANGUAGENAME 0x00001001 // English name of language, eg "German"
+#define LOCALE_SNATIVELANGUAGENAME 0x00000004 // native name of language, eg "Deutsch"
+
+#define LOCALE_SLOCALIZEDCOUNTRYNAME 0x00000006 // localized name of country, eg "Germany" in UI language
+#define LOCALE_SENGLISHCOUNTRYNAME 0x00001002 // English name of country, eg "Germany"
+#define LOCALE_SNATIVECOUNTRYNAME 0x00000008 // native name of country, eg "Deutschland"
+
+//
+// The following LCTypes are mutually exclusive in that they may NOT
+// be used in combination with each other.
+//
+#define LOCALE_ILANGUAGE 0x00000001 /* language id */
+#define LOCALE_SLANGUAGE 0x00000002 /* localized name of language */
+#define LOCALE_SENGLANGUAGE 0x00001001 /* English name of language */
+#define LOCALE_SABBREVLANGNAME 0x00000003 /* abbreviated language name */
+#define LOCALE_SNATIVELANGNAME 0x00000004 /* native name of language */
+#define LOCALE_ICOUNTRY 0x00000005 /* country code */
+#define LOCALE_SCOUNTRY 0x00000006 /* localized name of country */
+
+#define LOCALE_SENGCOUNTRY 0x00001002 /* English name of country */
+#define LOCALE_SABBREVCTRYNAME 0x00000007 /* abbreviated country name */
+#define LOCALE_SNATIVECTRYNAME 0x00000008 /* native name of country */
+
+#define LOCALE_SLIST 0x0000000C /* list item separator */
+#define LOCALE_IMEASURE 0x0000000D /* 0 = metric, 1 = US */
+
+#define LOCALE_SDECIMAL 0x0000000E /* decimal separator */
+#define LOCALE_STHOUSAND 0x0000000F /* thousand separator */
+#define LOCALE_SGROUPING 0x00000010 /* digit grouping */
+#define LOCALE_IDIGITS 0x00000011 /* number of fractional digits */
+#define LOCALE_ILZERO 0x00000012 /* leading zeros for decimal */
+#define LOCALE_INEGNUMBER 0x00001010 /* negative number mode */
+#define LOCALE_SNATIVEDIGITS 0x00000013 /* native ascii 0-9 */
+
+#define LOCALE_SCURRENCY 0x00000014 /* local monetary symbol */
+#define LOCALE_SINTLSYMBOL 0x00000015 /* intl monetary symbol */
+#define LOCALE_SMONDECIMALSEP 0x00000016 /* monetary decimal separator */
+#define LOCALE_SMONTHOUSANDSEP 0x00000017 /* monetary thousand separator */
+#define LOCALE_SMONGROUPING 0x00000018 /* monetary grouping */
+#define LOCALE_ICURRDIGITS 0x00000019 /* # local monetary digits */
+#define LOCALE_IINTLCURRDIGITS 0x0000001A /* # intl monetary digits */
+#define LOCALE_ICURRENCY 0x0000001B /* positive currency mode */
+#define LOCALE_INEGCURR 0x0000001C /* negative currency mode */
+
+#define LOCALE_SSHORTDATE 0x0000001F /* short date format string */
+#define LOCALE_SLONGDATE 0x00000020 /* long date format string */
+#define LOCALE_STIMEFORMAT 0x00001003 /* time format string */
+#define LOCALE_S1159 0x00000028 /* AM designator */
+#define LOCALE_S2359 0x00000029 /* PM designator */
+
+#define LOCALE_ICALENDARTYPE 0x00001009 /* type of calendar specifier */
+#define LOCALE_IFIRSTDAYOFWEEK 0x0000100C /* first day of week specifier */
+#define LOCALE_IFIRSTWEEKOFYEAR 0x0000100D /* first week of year specifier */
+
+#define LOCALE_SDAYNAME1 0x0000002A /* long name for Monday */
+#define LOCALE_SDAYNAME2 0x0000002B /* long name for Tuesday */
+#define LOCALE_SDAYNAME3 0x0000002C /* long name for Wednesday */
+#define LOCALE_SDAYNAME4 0x0000002D /* long name for Thursday */
+#define LOCALE_SDAYNAME5 0x0000002E /* long name for Friday */
+#define LOCALE_SDAYNAME6 0x0000002F /* long name for Saturday */
+#define LOCALE_SDAYNAME7 0x00000030 /* long name for Sunday */
+#define LOCALE_SABBREVDAYNAME1 0x00000031 /* abbreviated name for Monday */
+#define LOCALE_SABBREVDAYNAME2 0x00000032 /* abbreviated name for Tuesday */
+#define LOCALE_SABBREVDAYNAME3 0x00000033 /* abbreviated name for Wednesday */
+#define LOCALE_SABBREVDAYNAME4 0x00000034 /* abbreviated name for Thursday */
+#define LOCALE_SABBREVDAYNAME5 0x00000035 /* abbreviated name for Friday */
+#define LOCALE_SABBREVDAYNAME6 0x00000036 /* abbreviated name for Saturday */
+#define LOCALE_SABBREVDAYNAME7 0x00000037 /* abbreviated name for Sunday */
+#define LOCALE_SMONTHNAME1 0x00000038 /* long name for January */
+#define LOCALE_SMONTHNAME2 0x00000039 /* long name for February */
+#define LOCALE_SMONTHNAME3 0x0000003A /* long name for March */
+#define LOCALE_SMONTHNAME4 0x0000003B /* long name for April */
+#define LOCALE_SMONTHNAME5 0x0000003C /* long name for May */
+#define LOCALE_SMONTHNAME6 0x0000003D /* long name for June */
+#define LOCALE_SMONTHNAME7 0x0000003E /* long name for July */
+#define LOCALE_SMONTHNAME8 0x0000003F /* long name for August */
+#define LOCALE_SMONTHNAME9 0x00000040 /* long name for September */
+#define LOCALE_SMONTHNAME10 0x00000041 /* long name for October */
+#define LOCALE_SMONTHNAME11 0x00000042 /* long name for November */
+#define LOCALE_SMONTHNAME12 0x00000043 /* long name for December */
+#define LOCALE_SMONTHNAME13 0x0000100E /* long name for 13th month (if exists) */
+#define LOCALE_SABBREVMONTHNAME1 0x00000044 /* abbreviated name for January */
+#define LOCALE_SABBREVMONTHNAME2 0x00000045 /* abbreviated name for February */
+#define LOCALE_SABBREVMONTHNAME3 0x00000046 /* abbreviated name for March */
+#define LOCALE_SABBREVMONTHNAME4 0x00000047 /* abbreviated name for April */
+#define LOCALE_SABBREVMONTHNAME5 0x00000048 /* abbreviated name for May */
+#define LOCALE_SABBREVMONTHNAME6 0x00000049 /* abbreviated name for June */
+#define LOCALE_SABBREVMONTHNAME7 0x0000004A /* abbreviated name for July */
+#define LOCALE_SABBREVMONTHNAME8 0x0000004B /* abbreviated name for August */
+#define LOCALE_SABBREVMONTHNAME9 0x0000004C /* abbreviated name for September */
+#define LOCALE_SABBREVMONTHNAME10 0x0000004D /* abbreviated name for October */
+#define LOCALE_SABBREVMONTHNAME11 0x0000004E /* abbreviated name for November */
+#define LOCALE_SABBREVMONTHNAME12 0x0000004F /* abbreviated name for December */
+#define LOCALE_SABBREVMONTHNAME13 0x0000100F /* abbreviated name for 13th month (if exists) */
+
+#define LOCALE_SPOSITIVESIGN 0x00000050 /* positive sign */
+#define LOCALE_SNEGATIVESIGN 0x00000051 /* negative sign */
+
+#define LOCALE_FONTSIGNATURE 0x00000058 /* font signature */
+#define LOCALE_SISO639LANGNAME 0x00000059 /* ISO abbreviated language name */
+#define LOCALE_SISO3166CTRYNAME 0x0000005A /* ISO abbreviated country name */
+
+#define LOCALE_SENGCURRNAME 0x00001007 /* english name of currency */
+#define LOCALE_SNATIVECURRNAME 0x00001008 /* native name of currency */
+#define LOCALE_SYEARMONTH 0x00001006 /* year month format string */
+#define LOCALE_IDIGITSUBSTITUTION 0x00001014 /* 0 = context, 1 = none, 2 = national */
+
+#define LOCALE_SNAME 0x0000005C /* locale name <language>[-<Script>][-<REGION>[_<sort order>]] */
+#define LOCALE_SDURATION 0x0000005d /* time duration format */
+#define LOCALE_SKEYBOARDSTOINSTALL 0x0000005e /* (windows only) keyboards to install */
+#define LOCALE_SSHORTESTDAYNAME1 0x00000060 /* Shortest day name for Monday */
+#define LOCALE_SSHORTESTDAYNAME2 0x00000061 /* Shortest day name for Tuesday */
+#define LOCALE_SSHORTESTDAYNAME3 0x00000062 /* Shortest day name for Wednesday */
+#define LOCALE_SSHORTESTDAYNAME4 0x00000063 /* Shortest day name for Thursday */
+#define LOCALE_SSHORTESTDAYNAME5 0x00000064 /* Shortest day name for Friday */
+#define LOCALE_SSHORTESTDAYNAME6 0x00000065 /* Shortest day name for Saturday */
+#define LOCALE_SSHORTESTDAYNAME7 0x00000066 /* Shortest day name for Sunday */
+#define LOCALE_SISO639LANGNAME2 0x00000067 /* 3 character ISO abbreviated language name */
+#define LOCALE_SISO3166CTRYNAME2 0x00000068 /* 3 character ISO country name */
+#define LOCALE_SNAN 0x00000069 /* Not a Number */
+#define LOCALE_SPOSINFINITY 0x0000006a /* + Infinity */
+#define LOCALE_SNEGINFINITY 0x0000006b /* - Infinity */
+#define LOCALE_SSCRIPTS 0x0000006c /* Typical scripts in the locale */
+#define LOCALE_SPARENT 0x0000006d /* Fallback name for resources */
+#define LOCALE_SCONSOLEFALLBACKNAME 0x0000006e /* Fallback name for within the console */
+#define LOCALE_SLANGDISPLAYNAME 0x0000006f /* Language Display Name for a language */
+#define LOCALE_IREADINGLAYOUT 0x00000070 // Returns one of the following 4 reading layout values:
+ // 0 - Left to right (eg en-US)
+ // 1 - Right to left (eg arabic locales)
+ // 2 - Vertical top to bottom with columns to the left and also left to right (ja-JP locales)
+ // 3 - Vertical top to bottom with columns proceeding to the right
+#define LOCALE_INEUTRAL 0x00000071 // Returns 0 for specific cultures, 1 for neutral cultures.
+#define LOCALE_INEGATIVEPERCENT 0x00000074 // Returns 0-11 for the negative percent format
+#define LOCALE_IPOSITIVEPERCENT 0x00000075 // Returns 0-3 for the positive percent formatIPOSITIVEPERCENT
+#define LOCALE_SPERCENT 0x00000076 // Returns the percent symbol
+#define LOCALE_SPERMILLE 0x00000077 // Returns the permille (U+2030) symbol
+#define LOCALE_SMONTHDAY 0x00000078 // Returns the preferred month/day format
+#define LOCALE_SSHORTTIME 0x00000079 // Returns the preferred short time format (ie: no seconds, just h:mm)
+#define LOCALE_SOPENTYPELANGUAGETAG 0x0000007a // Open type language tag, eg: "latn" or "dflt"
+#define LOCALE_SSORTLOCALE 0x0000007b // Name of locale to use for sorting/collation/casing behavior.
+
+#define LCMAP_LINGUISTIC_CASING 0x01000000 /* Use linguistic casing */
+
+#define CAL_RETURN_GENITIVE_NAMES LOCALE_RETURN_GENITIVE_NAMES // return genitive forms of month names
+
+#define CAL_SSHORTESTDAYNAME1 0x00000031
+#define CAL_SSHORTESTDAYNAME2 0x00000032
+#define CAL_SSHORTESTDAYNAME3 0x00000033
+#define CAL_SSHORTESTDAYNAME4 0x00000034
+#define CAL_SSHORTESTDAYNAME5 0x00000035
+#define CAL_SSHORTESTDAYNAME6 0x00000036
+#define CAL_SSHORTESTDAYNAME7 0x00000037
+
+#define CAL_SMONTHDAY 0x00000038 // Month/day pattern (reserve for potential inclusion in a future version)
+#define CAL_SERASTRING 0x00000004 // era name for IYearOffsetRanges, eg A.D.
+#define CAL_SABBREVERASTRING 0x00000039 // Abbreviated era string (eg: AD)
+
+#define CAL_SSHORTDATE 0x00000005 /* short date format string */
+#define CAL_SLONGDATE 0x00000006 /* long date format string */
+#define CAL_SDAYNAME1 0x00000007 /* native name for Monday */
+#define CAL_SDAYNAME2 0x00000008 /* native name for Tuesday */
+#define CAL_SDAYNAME3 0x00000009 /* native name for Wednesday */
+#define CAL_SDAYNAME4 0x0000000a /* native name for Thursday */
+#define CAL_SDAYNAME5 0x0000000b /* native name for Friday */
+#define CAL_SDAYNAME6 0x0000000c /* native name for Saturday */
+#define CAL_SDAYNAME7 0x0000000d /* native name for Sunday */
+#define CAL_SABBREVDAYNAME1 0x0000000e /* abbreviated name for Monday */
+#define CAL_SABBREVDAYNAME2 0x0000000f /* abbreviated name for Tuesday */
+#define CAL_SABBREVDAYNAME3 0x00000010 /* abbreviated name for Wednesday */
+#define CAL_SABBREVDAYNAME4 0x00000011 /* abbreviated name for Thursday */
+#define CAL_SABBREVDAYNAME5 0x00000012 /* abbreviated name for Friday */
+#define CAL_SABBREVDAYNAME6 0x00000013 /* abbreviated name for Saturday */
+#define CAL_SABBREVDAYNAME7 0x00000014 /* abbreviated name for Sunday */
+#define CAL_SMONTHNAME1 0x00000015 /* native name for January */
+#define CAL_SMONTHNAME2 0x00000016 /* native name for February */
+#define CAL_SMONTHNAME3 0x00000017 /* native name for March */
+#define CAL_SMONTHNAME4 0x00000018 /* native name for April */
+#define CAL_SMONTHNAME5 0x00000019 /* native name for May */
+#define CAL_SMONTHNAME6 0x0000001a /* native name for June */
+#define CAL_SMONTHNAME7 0x0000001b /* native name for July */
+#define CAL_SMONTHNAME8 0x0000001c /* native name for August */
+#define CAL_SMONTHNAME9 0x0000001d /* native name for September */
+#define CAL_SMONTHNAME10 0x0000001e /* native name for October */
+#define CAL_SMONTHNAME11 0x0000001f /* native name for November */
+#define CAL_SMONTHNAME12 0x00000020 /* native name for December */
+#define CAL_SMONTHNAME13 0x00000021 /* native name for 13th month (if any) */
+#define CAL_SABBREVMONTHNAME1 0x00000022 /* abbreviated name for January */
+#define CAL_SABBREVMONTHNAME2 0x00000023 /* abbreviated name for February */
+#define CAL_SABBREVMONTHNAME3 0x00000024 /* abbreviated name for March */
+#define CAL_SABBREVMONTHNAME4 0x00000025 /* abbreviated name for April */
+#define CAL_SABBREVMONTHNAME5 0x00000026 /* abbreviated name for May */
+#define CAL_SABBREVMONTHNAME6 0x00000027 /* abbreviated name for June */
+#define CAL_SABBREVMONTHNAME7 0x00000028 /* abbreviated name for July */
+#define CAL_SABBREVMONTHNAME8 0x00000029 /* abbreviated name for August */
+#define CAL_SABBREVMONTHNAME9 0x0000002a /* abbreviated name for September */
+#define CAL_SABBREVMONTHNAME10 0x0000002b /* abbreviated name for October */
+#define CAL_SABBREVMONTHNAME11 0x0000002c /* abbreviated name for November */
+#define CAL_SABBREVMONTHNAME12 0x0000002d /* abbreviated name for December */
+#define CAL_SABBREVMONTHNAME13 0x0000002e /* abbreviated name for 13th month (if any) */
+#define CAL_SYEARMONTH 0x0000002f /* year month format string */
+
+
+#else // __APPLE__
+
+#define LOCALE_SDECIMAL 0x0000000E /* decimal separator */
+#define LOCALE_STHOUSAND 0x0000000F /* thousand separator */
+#define LOCALE_ILZERO 0x00000012 /* leading zeros for decimal */
+#define LOCALE_SCURRENCY 0x00000014 /* local monetary symbol */
+#define LOCALE_SMONDECIMALSEP 0x00000016 /* monetary decimal separator */
+#define LOCALE_SMONTHOUSANDSEP 0x00000017 /* monetary thousand separator */
+
+#endif // __APPLE__
+
+
+#if ENABLE_DOWNLEVEL_FOR_NLS
+
+PALIMPORT
+int
+PALAPI
+GetLocaleInfoW(
+ IN LCID Locale,
+ IN LCTYPE LCType,
+ OUT LPWSTR lpLCData,
+ IN int cchData);
+
+#endif // ENABLE_DOWNLEVEL_FOR_NLS
+
+PALIMPORT
+int
+PALAPI
+GetLocaleInfoEx(
+ IN LPCWSTR lpLocaleName,
+ IN LCTYPE LCType,
+ OUT LPWSTR lpLCData,
+ IN int cchData);
+
+
+PALIMPORT
+int
+PALAPI
+CompareStringOrdinal(
+ IN LPCWSTR lpString1,
+ IN int cchCount1,
+ IN LPCWSTR lpString2,
+ IN int cchCount2,
+ IN BOOL bIgnoreCase);
+
+typedef struct _nlsversioninfoex {
+ DWORD dwNLSVersionInfoSize;
+ DWORD dwNLSVersion;
+ DWORD dwDefinedVersion;
+ DWORD dwEffectiveId;
+ GUID guidCustomVersion;
+ } NLSVERSIONINFOEX, *LPNLSVERSIONINFOEX;
+
+PALIMPORT
+int
+PALAPI
+FindNLSStringEx(
+ IN LPCWSTR lpLocaleName,
+ IN DWORD dwFindNLSStringFlags,
+ IN LPCWSTR lpStringSource,
+ IN int cchSource,
+ IN LPCWSTR lpStringValue,
+ IN int cchValue,
+ OUT LPINT pcchFound,
+ IN LPNLSVERSIONINFOEX lpVersionInformation,
+ IN LPVOID lpReserved,
+ IN LPARAM lParam );
+
+typedef enum {
+ COMPARE_STRING = 0x0001,
+} NLS_FUNCTION;
+
+PALIMPORT
+BOOL
+PALAPI
+IsNLSDefinedString(
+ IN NLS_FUNCTION Function,
+ IN DWORD dwFlags,
+ IN LPNLSVERSIONINFOEX lpVersionInfo,
+ IN LPCWSTR lpString,
+ IN int cchStr );
+
+
+PALIMPORT
+int
+PALAPI
+ResolveLocaleName(
+ IN LPCWSTR lpNameToResolve,
+ OUT LPWSTR lpLocaleName,
+ IN int cchLocaleName );
+
+PALIMPORT
+BOOL
+PALAPI
+GetThreadPreferredUILanguages(
+ IN DWORD dwFlags,
+ OUT PULONG pulNumLanguages,
+ OUT PWSTR pwszLanguagesBuffer,
+ IN OUT PULONG pcchLanguagesBuffer);
+
+
+PALIMPORT
+int
+PALAPI
+GetSystemDefaultLocaleName(
+ OUT LPWSTR lpLocaleName,
+ IN int cchLocaleName);
+
+#ifdef UNICODE
+#define GetLocaleInfo GetLocaleInfoW
+#endif
+
+#if ENABLE_DOWNLEVEL_FOR_NLS
+PALIMPORT
+LCID
+PALAPI
+GetUserDefaultLCID(
+ void);
+#endif
+
+
+PALIMPORT
+int
+PALAPI
+GetUserDefaultLocaleName(
+ OUT LPWSTR lpLocaleName,
+ IN int cchLocaleName);
+
+
+#define LCID_INSTALLED 0x00000001 // installed locale ids
+#define LCID_SUPPORTED 0x00000002 // supported locale ids
+#ifdef __APPLE__
+#define LCID_ALTERNATE_SORTS 0x00000004 // alternate sort locale ids
+#endif // __APPLE__
+
+#if ENABLE_DOWNLEVEL_FOR_NLS
+PALIMPORT
+BOOL
+PALAPI
+IsValidLocale(
+ IN LCID Locale,
+ IN DWORD dwFlags);
+#endif // ENABLE_DOWNLEVEL_FOR_NLS
+
+
+typedef DWORD CALID;
+typedef DWORD CALTYPE;
+
+#define CAL_ITWODIGITYEARMAX 0x00000030 // two digit year max
+#define CAL_RETURN_NUMBER 0x20000000 // return number instead of string
+
+#define CAL_GREGORIAN 1 // Gregorian (localized) calendar
+#define CAL_GREGORIAN_US 2 // Gregorian (U.S.) calendar
+#define CAL_JAPAN 3 // Japanese Emperor Era calendar
+#define CAL_TAIWAN 4 // Taiwan Era calendar
+#define CAL_KOREA 5 // Korean Tangun Era calendar
+#define CAL_HIJRI 6 // Hijri (Arabic Lunar) calendar
+#define CAL_THAI 7 // Thai calendar
+#define CAL_HEBREW 8 // Hebrew (Lunar) calendar
+#define CAL_GREGORIAN_ME_FRENCH 9 // Gregorian Middle East French calendar
+#define CAL_GREGORIAN_ARABIC 10 // Gregorian Arabic calendar
+#define CAL_GREGORIAN_XLIT_ENGLISH 11 // Gregorian Transliterated English calendar
+#define CAL_GREGORIAN_XLIT_FRENCH 12 // Gregorian Transliterated French calendar
+#define CAL_JULIAN 13
+
+#if ENABLE_DOWNLEVEL_FOR_NLS
+PALIMPORT
+int
+PALAPI
+GetCalendarInfoW(
+ IN LCID Locale,
+ IN CALID Calendar,
+ IN CALTYPE CalType,
+ OUT LPWSTR lpCalData,
+ IN int cchData,
+ OUT LPDWORD lpValue);
+
+#ifdef UNICODE
+#define GetCalendarInfo GetCalendarInfoW
+#endif
+
+#endif // ENABLE_DOWNLEVEL_FOR_NLS
+
+
+PALIMPORT
+int
+PALAPI
+GetCalendarInfoEx(
+ IN LPCWSTR lpLocaleName,
+ IN CALID Calendar,
+ IN LPCWSTR lpReserved,
+ IN CALTYPE CalType,
+ OUT LPWSTR lpCalData,
+ IN int cchData,
+ OUT LPDWORD lpValue);
+
+#if ENABLE_DOWNLEVEL_FOR_NLS
+typedef BOOL (CALLBACK* LOCALE_ENUMPROCW)(LPWSTR);
+
+PALIMPORT
+BOOL
+PALAPI
+EnumSystemLocalesW(
+ IN LOCALE_ENUMPROCW lpLocaleEnumProc,
+ IN DWORD dwFlags);
+#endif // ENABLE_DOWNLEVEL_FOR_NLS
+
+#define DATE_SHORTDATE 0x00000001 // use short date picture
+#define DATE_LONGDATE 0x00000002 // use long date picture
+#define DATE_YEARMONTH 0x00000008 // use year month picture
+
+typedef BOOL (CALLBACK* DATEFMT_ENUMPROCEXW)(LPWSTR, CALID);
+
+#if ENABLE_DOWNLEVEL_FOR_NLS
+
+PALIMPORT
+BOOL
+PALAPI
+EnumDateFormatsExW(
+ IN DATEFMT_ENUMPROCEXW lpDateFmtEnumProcEx,
+ IN LCID Locale,
+ IN DWORD dwFlags);
+
+#else // ENABLE_DOWNLEVEL_FOR_NLS
+
+typedef BOOL (CALLBACK* DATEFMT_ENUMPROCEXEXW)(LPWSTR, CALID, LPARAM);
+
+PALIMPORT
+BOOL
+PALAPI
+EnumDateFormatsExEx(
+ IN DATEFMT_ENUMPROCEXEXW lpDateFmtEnumProcEx,
+ IN LPCWSTR lpLocaleName,
+ IN DWORD dwFlags,
+ IN LPARAM lParam);
+
+#endif // ENABLE_DOWNLEVEL_FOR_NLS
+
+typedef BOOL (CALLBACK* TIMEFMT_ENUMPROCW)(LPWSTR);
+
+#if ENABLE_DOWNLEVEL_FOR_NLS
+
+PALIMPORT
+BOOL
+PALAPI
+EnumTimeFormatsW(
+ IN TIMEFMT_ENUMPROCW lpTimeFmtEnumProc,
+ IN LCID Locale,
+ IN DWORD dwFlags);
+
+#else // ENABLE_DOWNLEVEL_FOR_NLS
+
+typedef BOOL (CALLBACK* TIMEFMT_ENUMPROCEXW)(LPWSTR, LPARAM);
+
+PALIMPORT
+BOOL
+PALAPI
+EnumTimeFormatsEx(
+ IN TIMEFMT_ENUMPROCEXW lpTimeFmtEnumProc,
+ IN LPCWSTR lpLocaleName,
+ IN DWORD dwFlags,
+ IN LPARAM lParam);
+
+#endif // ENABLE_DOWNLEVEL_FOR_NLS
+
+#define ENUM_ALL_CALENDARS 0xffffffff // enumerate all calendars
+#define CAL_ICALINTVALUE 0x00000001 // calendar type
+#define CAL_NOUSEROVERRIDE LOCALE_NOUSEROVERRIDE // do not use user overrides
+#define CAL_SCALNAME 0x00000002 // native name of calendar
+
+typedef BOOL (CALLBACK* CALINFO_ENUMPROCEXW)(LPWSTR,CALID);
+
+#if ENABLE_DOWNLEVEL_FOR_NLS
+
+PALIMPORT
+BOOL
+PALAPI
+EnumCalendarInfoExW(
+ IN CALINFO_ENUMPROCEXW lpCalInfoEnumProc,
+ IN LCID Locale,
+ IN CALID Calendar,
+ IN CALTYPE CalType);
+
+#else // ENABLE_DOWNLEVEL_FOR_NLS
+
+typedef BOOL (CALLBACK* CALINFO_ENUMPROCEXEXW)(LPWSTR, CALID, LPWSTR, LPARAM);
+
+PALIMPORT
+BOOL
+PALAPI
+EnumCalendarInfoExEx(
+ IN CALINFO_ENUMPROCEXEXW lpCalInfoEnumProc,
+ IN LPCWSTR lpLocaleName,
+ IN CALID Calendar,
+ IN LPCWSTR lpReserved,
+ IN CALTYPE CalType,
+ IN LPARAM lParam);
+
+#endif // ENABLE_DOWNLEVEL_FOR_NLS
+
+#define LCMAP_LOWERCASE 0x00000100
+#define LCMAP_UPPERCASE 0x00000200
+
+#if ENABLE_DOWNLEVEL_FOR_NLS
+
+PALIMPORT
+int
+PALAPI
+LCMapStringW(
+ IN LCID Locale,
+ IN DWORD dwMapFlags,
+ IN LPCWSTR lpSrcStr,
+ IN int cchSrc,
+ OUT LPWSTR lpDestStr,
+ IN int cchDest);
+
+#ifdef UNICODE
+#define LCMapString LCMapStringW
+#endif
+
+
+#endif // ENABLE_DOWNLEVEL_FOR_NLS
+
+
+PALIMPORT
+int
+PALAPI
+LCMapStringEx(
+ IN LPCWSTR lpLocaleName,
+ IN DWORD dwMapFlags,
+ IN LPCWSTR lpSrcStr,
+ IN int cchSrc,
+ OUT LPWSTR lpDestStr,
+ IN int cchDest,
+ IN LPNLSVERSIONINFO lpVersionInformation,
+ IN LPVOID lpReserved,
+ IN LPARAM lParam );
+
+PALIMPORT
+int
+PALAPI
+PAL_LCMapCharW(
+ IN LPCWSTR lpLocaleName,
+ IN DWORD dwMapFlags,
+ IN WCHAR srcChar,
+ OUT WCHAR *destChar,
+ LPNLSVERSIONINFO lpVersionInformation,
+ LPVOID lpReserved,
+ LPARAM lParam );
+
+PALIMPORT
+int
+PALAPI
+PAL_NormalizeStringExW(
+ IN LPCWSTR lpLocaleName,
+ IN DWORD dwMapFlags,
+ IN LPCWSTR lpSrcStr,
+ IN int cchSrc,
+ OUT LPWSTR lpDestStr,
+ IN int cchDest);
+
+PALIMPORT
+int
+PALAPI
+PAL_ParseDateW(
+ IN LPCWSTR lpLocaleName,
+ IN LPCWSTR lpFormat,
+ IN LPCWSTR lpString,
+ OUT LPSYSTEMTIME lpTime);
+
+PALIMPORT
+int
+PALAPI
+PAL_GetCalendar(
+ IN LPCWSTR lpLocaleName,
+ OUT CALID* pCalendar);
+
+#define GEOID_NOT_AVAILABLE -1
+
+// "a number", might represent different types
+typedef struct PALNUMBER__* PALNUMBER;
+
+// return NULL on OOM
+PALIMPORT PALNUMBER PALAPI PAL_DoubleToNumber(double);
+PALIMPORT PALNUMBER PALAPI PAL_Int64ToNumber(INT64);
+PALIMPORT PALNUMBER PALAPI PAL_UInt64ToNumber(UINT64);
+PALIMPORT PALNUMBER PALAPI PAL_IntToNumber(int);
+PALIMPORT PALNUMBER PALAPI PAL_UIntToNumber(unsigned int);
+
+PALIMPORT void PALAPI PAL_ReleaseNumber(PALNUMBER);
+
+
+// return string length if Buffer is NULL or the result fits in cchBuffer, otherwise -1
+PALIMPORT int PALAPI PAL_FormatScientific(LPCWSTR sLocale, LPWSTR pBuffer, SIZE_T cchBuffer, PALNUMBER number, int nMinDigits, int nMaxDigits,
+ LPCWSTR sExponent, LPCWSTR sNumberDecimal, LPCWSTR sPositive, LPCWSTR sNegative, LPCWSTR sZero);
+
+PALIMPORT int PALAPI PAL_FormatCurrency(LPCWSTR sLocale, LPWSTR pBuffer, SIZE_T cchBuffer, PALNUMBER number, int nMinDigits, int nMaxDigits, int iNegativeFormat, int iPositiveFormat,
+ int iPrimaryGroup, int iSecondaryGroup, LPCWSTR sCurrencyDecimal, LPCWSTR sCurrencyGroup, LPCWSTR sNegative, LPCWSTR sCurrency, LPCWSTR sZero);
+
+PALIMPORT int PALAPI PAL_FormatPercent(LPCWSTR sLocale, LPWSTR pBuffer, SIZE_T cchBuffer, PALNUMBER number, int nMinDigits, int nMaxDigits,int iNegativeFormat, int iPositiveFormat,
+ int iPrimaryGroup, int iSecondaryGroup, LPCWSTR sPercentDecimal, LPCWSTR sPercentGroup, LPCWSTR sNegative, LPCWSTR sPercent, LPCWSTR sZero);
+
+PALIMPORT int PALAPI PAL_FormatDecimal(LPCWSTR sLocale, LPWSTR pBuffer, SIZE_T cchBuffer, PALNUMBER number, int nMinDigits, int nMaxDigits, int iNegativeFormat,
+ int iPrimaryGroup, int iSecondaryGroup, LPCWSTR sDecimal, LPCWSTR sGroup, LPCWSTR sNegative, LPCWSTR sZero);
+
+
+#define DATE_USE_ALT_CALENDAR 0x00000004
+
+#if ENABLE_DOWNLEVEL_FOR_NLS
+
+PALIMPORT
+int
+PALAPI
+GetDateFormatW(
+ IN LCID Locale,
+ IN DWORD dwFlags,
+ IN CONST SYSTEMTIME *lpDate,
+ IN LPCWSTR lpFormat,
+ OUT LPWSTR lpDateStr,
+ IN int cchDate);
+
+#else
+
+PALIMPORT
+int
+PALAPI
+GetDateFormatEx(
+ IN LPCWSTR Locale,
+ IN DWORD dwFlags,
+ IN CONST SYSTEMTIME *lpDate,
+ IN LPCWSTR lpFormat,
+ OUT LPWSTR lpDateStr,
+ IN int cchDate,
+ IN LPCWSTR lpCalendar);
+
+
+#endif // ENABLE_DOWNLEVEL_FOR_NLS
+
+PALIMPORT
+int
+PALAPI
+GetDateFormatEx(
+ IN LPCWSTR lpLocaleName,
+ IN DWORD dwFlags,
+ IN CONST SYSTEMTIME *lpDate,
+ IN LPCWSTR lpFormat,
+ OUT LPWSTR lpDateStr,
+ IN int cchDate,
+ LPCWSTR lpCalendar);
+
+
+#ifdef UNICODE
+#define GetDateFormat GetDateFormatW
+#endif
+
+
+PALIMPORT
+int
+PALAPI
+PAL_GetResourceString(
+ IN LPCSTR lpDomain,
+ IN LPCSTR lpResourceStr,
+ OUT LPWSTR lpWideCharStr,
+ IN int cchWideChar);
+
+PALIMPORT
+BOOL
+PALAPI
+PAL_BindResources(IN LPCSTR lpDomain);
+
+#define EXCEPTION_NONCONTINUABLE 0x1
+#define EXCEPTION_UNWINDING 0x2
+
+#ifdef FEATURE_PAL_SXS
+
+#define EXCEPTION_EXIT_UNWIND 0x4 // Exit unwind is in progress (not used by PAL SEH)
+#define EXCEPTION_NESTED_CALL 0x10 // Nested exception handler call
+#define EXCEPTION_TARGET_UNWIND 0x20 // Target unwind in progress
+#define EXCEPTION_COLLIDED_UNWIND 0x40 // Collided exception handler call
+#define EXCEPTION_SKIP_VEH 0x200
+
+#define EXCEPTION_UNWIND (EXCEPTION_UNWINDING | EXCEPTION_EXIT_UNWIND | \
+ EXCEPTION_TARGET_UNWIND | EXCEPTION_COLLIDED_UNWIND)
+
+#define IS_DISPATCHING(Flag) ((Flag & EXCEPTION_UNWIND) == 0)
+#define IS_UNWINDING(Flag) ((Flag & EXCEPTION_UNWIND) != 0)
+#define IS_TARGET_UNWIND(Flag) (Flag & EXCEPTION_TARGET_UNWIND)
+
+#endif // FEATURE_PAL_SXS
+
+#define EXCEPTION_IS_SIGNAL 0x100
+
+#define EXCEPTION_MAXIMUM_PARAMETERS 15
+
+// Index in the ExceptionInformation array where we will keep the reference
+// to the native exception that needs to be deleted when dispatching
+// exception in managed code.
+#define NATIVE_EXCEPTION_ASYNC_SLOT (EXCEPTION_MAXIMUM_PARAMETERS-1)
+
+typedef struct _EXCEPTION_RECORD {
+ DWORD ExceptionCode;
+ DWORD ExceptionFlags;
+ struct _EXCEPTION_RECORD *ExceptionRecord;
+ PVOID ExceptionAddress;
+ DWORD NumberParameters;
+ ULONG_PTR ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS];
+} EXCEPTION_RECORD, *PEXCEPTION_RECORD;
+
+typedef struct _EXCEPTION_POINTERS {
+ PEXCEPTION_RECORD ExceptionRecord;
+ PCONTEXT ContextRecord;
+} EXCEPTION_POINTERS, *PEXCEPTION_POINTERS, *LPEXCEPTION_POINTERS;
+
+#ifdef FEATURE_PAL_SXS
+
+typedef LONG EXCEPTION_DISPOSITION;
+
+enum {
+ ExceptionContinueExecution,
+ ExceptionContinueSearch,
+ ExceptionNestedException,
+ ExceptionCollidedUnwind,
+};
+
+#endif // FEATURE_PAL_SXS
+
+//
+// A function table entry is generated for each frame function.
+//
+typedef struct _RUNTIME_FUNCTION {
+ DWORD BeginAddress;
+ DWORD EndAddress;
+ DWORD UnwindData;
+} RUNTIME_FUNCTION, *PRUNTIME_FUNCTION;
+
+PALIMPORT
+BOOL
+PALAPI
+WriteProcessMemory(IN HANDLE hProcess,
+ IN LPVOID lpBaseAddress,
+ IN LPCVOID lpBuffer,
+ IN SIZE_T nSize,
+ OUT SIZE_T * lpNumberOfBytesWritten);
+
+#define STANDARD_RIGHTS_REQUIRED (0x000F0000L)
+#define SYNCHRONIZE (0x00100000L)
+#define READ_CONTROL (0x00020000L)
+
+#define EVENT_MODIFY_STATE (0x0002)
+#define EVENT_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | \
+ 0x3)
+
+#define MUTANT_QUERY_STATE (0x0001)
+#define MUTANT_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | \
+ MUTANT_QUERY_STATE)
+#define MUTEX_ALL_ACCESS MUTANT_ALL_ACCESS
+
+#define SEMAPHORE_MODIFY_STATE (0x0002)
+#define SEMAPHORE_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | \
+ 0x3)
+
+#define PROCESS_TERMINATE (0x0001)
+#define PROCESS_CREATE_THREAD (0x0002)
+#define PROCESS_SET_SESSIONID (0x0004)
+#define PROCESS_VM_OPERATION (0x0008)
+#define PROCESS_VM_READ (0x0010)
+#define PROCESS_VM_WRITE (0x0020)
+#define PROCESS_DUP_HANDLE (0x0040)
+#define PROCESS_CREATE_PROCESS (0x0080)
+#define PROCESS_SET_QUOTA (0x0100)
+#define PROCESS_SET_INFORMATION (0x0200)
+#define PROCESS_QUERY_INFORMATION (0x0400)
+#define PROCESS_SUSPEND_RESUME (0x0800)
+#define PROCESS_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | \
+ 0xFFF)
+
+PALIMPORT
+HANDLE
+PALAPI
+OpenProcess(
+ IN DWORD dwDesiredAccess, /* PROCESS_DUP_HANDLE or PROCESS_ALL_ACCESS */
+ IN BOOL bInheritHandle,
+ IN DWORD dwProcessId
+ );
+
+PALIMPORT
+BOOL
+PALAPI
+EnumProcessModules(
+ IN HANDLE hProcess,
+ OUT HMODULE *lphModule,
+ IN DWORD cb,
+ OUT LPDWORD lpcbNeeded
+ );
+
+PALIMPORT
+VOID
+PALAPI
+OutputDebugStringA(
+ IN LPCSTR lpOutputString);
+
+PALIMPORT
+VOID
+PALAPI
+OutputDebugStringW(
+ IN LPCWSTR lpOutputStrig);
+
+#ifdef UNICODE
+#define OutputDebugString OutputDebugStringW
+#else
+#define OutputDebugString OutputDebugStringA
+#endif
+
+PALIMPORT
+VOID
+PALAPI
+DebugBreak(
+ VOID);
+
+PALIMPORT
+LPWSTR
+PALAPI
+lstrcatW(
+ IN OUT LPWSTR lpString1,
+ IN LPCWSTR lpString2);
+
+#ifdef UNICODE
+#define lstrcat lstrcatW
+#endif
+
+PALIMPORT
+LPWSTR
+PALAPI
+lstrcpyW(
+ OUT LPWSTR lpString1,
+ IN LPCWSTR lpString2);
+
+#ifdef UNICODE
+#define lstrcpy lstrcpyW
+#endif
+
+PALIMPORT
+int
+PALAPI
+lstrlenA(
+ IN LPCSTR lpString);
+
+PALIMPORT
+int
+PALAPI
+lstrlenW(
+ IN LPCWSTR lpString);
+
+#ifdef UNICODE
+#define lstrlen lstrlenW
+#else
+#define lstrlen lstrlenA
+#endif
+
+PALIMPORT
+LPWSTR
+PALAPI
+lstrcpynW(
+ OUT LPWSTR lpString1,
+ IN LPCWSTR lpString2,
+ IN int iMaxLength);
+
+#ifdef UNICODE
+#define lstrcpyn lstrcpynW
+#endif
+
+
+PALIMPORT
+DWORD
+PALAPI
+GetEnvironmentVariableW(
+ IN LPCWSTR lpName,
+ OUT LPWSTR lpBuffer,
+ IN DWORD nSize);
+
+#ifdef UNICODE
+#define GetEnvironmentVariable GetEnvironmentVariableW
+#else
+#define GetEnvironmentVariable GetEnvironmentVariableA
+#endif
+
+PALIMPORT
+BOOL
+PALAPI
+SetEnvironmentVariableW(
+ IN LPCWSTR lpName,
+ IN LPCWSTR lpValue);
+
+#ifdef UNICODE
+#define SetEnvironmentVariable SetEnvironmentVariableW
+#else
+#define SetEnvironmentVariable SetEnvironmentVariableA
+#endif
+
+PALIMPORT
+LPWSTR
+PALAPI
+GetEnvironmentStringsW(
+ VOID);
+
+#ifdef UNICODE
+#define GetEnvironmentStrings GetEnvironmentStringsW
+#else
+#define GetEnvironmentStrings GetEnvironmentStringsA
+#endif
+
+PALIMPORT
+BOOL
+PALAPI
+FreeEnvironmentStringsW(
+ IN LPWSTR);
+
+#ifdef UNICODE
+#define FreeEnvironmentStrings FreeEnvironmentStringsW
+#else
+#define FreeEnvironmentStrings FreeEnvironmentStringsA
+#endif
+
+PALIMPORT
+BOOL
+PALAPI
+CloseHandle(
+ IN OUT HANDLE hObject);
+
+PALIMPORT
+VOID
+PALAPI
+RaiseException(
+ IN DWORD dwExceptionCode,
+ IN DWORD dwExceptionFlags,
+ IN DWORD nNumberOfArguments,
+ IN CONST ULONG_PTR *lpArguments);
+
+#ifdef FEATURE_PAL_SXS
+PALIMPORT
+PAL_NORETURN
+VOID
+PALAPI
+PAL_RaiseException(
+ IN PEXCEPTION_POINTERS ExceptionPointers);
+#endif // FEATURE_PAL_SXS
+
+PALIMPORT
+DWORD
+PALAPI
+GetTickCount(
+ VOID);
+
+PALIMPORT
+ULONGLONG
+PALAPI
+GetTickCount64();
+
+PALIMPORT
+BOOL
+PALAPI
+QueryPerformanceCounter(
+ OUT LARGE_INTEGER *lpPerformanceCount
+ );
+
+PALIMPORT
+BOOL
+PALAPI
+QueryPerformanceFrequency(
+ OUT LARGE_INTEGER *lpFrequency
+ );
+
+PALIMPORT
+BOOL
+PALAPI
+QueryThreadCycleTime(
+ IN HANDLE ThreadHandle,
+ OUT PULONG64 CycleTime);
+
+#ifndef FEATURE_PAL_SXS
+
+typedef LONG (PALAPI *PTOP_LEVEL_EXCEPTION_FILTER)(
+ struct _EXCEPTION_POINTERS *ExceptionInfo);
+typedef PTOP_LEVEL_EXCEPTION_FILTER LPTOP_LEVEL_EXCEPTION_FILTER;
+
+PALIMPORT
+LPTOP_LEVEL_EXCEPTION_FILTER
+PALAPI
+SetUnhandledExceptionFilter(
+ IN LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter);
+
+#else // FEATURE_PAL_SXS
+
+typedef EXCEPTION_DISPOSITION (PALAPI *PVECTORED_EXCEPTION_HANDLER)(
+ struct _EXCEPTION_POINTERS *ExceptionPointers);
+
+#endif // FEATURE_PAL_SXS
+
+// Define BitScanForward64 and BitScanForward
+// Per MSDN, BitScanForward64 will search the mask data from LSB to MSB for a set bit.
+// If one is found, its bit position is returned in the out PDWORD argument and 1 is returned.
+// Otherwise, 0 is returned.
+//
+// On GCC, the equivalent function is __builtin_ffsl. It returns 1+index of the least
+// significant set bit, or 0 if if mask is zero.
+//
+// The same is true for BitScanForward, except that the GCC function is __builtin_ffs.
+EXTERN_C
+PALIMPORT
+inline
+unsigned char
+PALAPI
+BitScanForward(
+ IN OUT PDWORD Index,
+ IN UINT qwMask)
+{
+ unsigned char bRet = FALSE;
+ int iIndex = __builtin_ffsl(qwMask);
+ if (iIndex != 0)
+ {
+ // Set the Index after deducting unity
+ *Index = (DWORD)(iIndex - 1);
+ bRet = TRUE;
+ }
+
+ return bRet;
+}
+
+EXTERN_C
+PALIMPORT
+inline
+unsigned char
+PALAPI
+BitScanForward64(
+ IN OUT PDWORD Index,
+ IN UINT64 qwMask)
+{
+ unsigned char bRet = FALSE;
+ int iIndex = __builtin_ffsl(qwMask);
+ if (iIndex != 0)
+ {
+ // Set the Index after deducting unity
+ *Index = (DWORD)(iIndex - 1);
+ bRet = TRUE;
+ }
+
+ return bRet;
+}
+
+/*++
+Function:
+InterlockedIncrement
+
+The InterlockedIncrement function increments (increases by one) the
+value of the specified variable and checks the resulting value. The
+function prevents more than one thread from using the same variable
+simultaneously.
+
+Parameters
+
+lpAddend
+[in/out] Pointer to the variable to increment.
+
+Return Values
+
+The return value is the resulting incremented value.
+
+--*/
+EXTERN_C
+PALIMPORT
+inline
+LONG
+PALAPI
+InterlockedIncrement(
+ IN OUT LONG volatile *lpAddend)
+{
+ return __sync_add_and_fetch(lpAddend, (LONG)1);
+}
+
+EXTERN_C
+PALIMPORT
+inline
+LONGLONG
+PALAPI
+InterlockedIncrement64(
+ IN OUT LONGLONG volatile *lpAddend)
+{
+ return __sync_add_and_fetch(lpAddend, (LONGLONG)1);
+}
+
+/*++
+Function:
+InterlockedDecrement
+
+The InterlockedDecrement function decrements (decreases by one) the
+value of the specified variable and checks the resulting value. The
+function prevents more than one thread from using the same variable
+simultaneously.
+
+Parameters
+
+lpAddend
+[in/out] Pointer to the variable to decrement.
+
+Return Values
+
+The return value is the resulting decremented value.
+
+--*/
+EXTERN_C
+PALIMPORT
+inline
+LONG
+PALAPI
+InterlockedDecrement(
+ IN OUT LONG volatile *lpAddend)
+{
+ return __sync_sub_and_fetch(lpAddend, (LONG)1);
+}
+
+EXTERN_C
+PALIMPORT
+inline
+LONGLONG
+PALAPI
+InterlockedDecrement64(
+ IN OUT LONGLONG volatile *lpAddend)
+{
+ return __sync_sub_and_fetch(lpAddend, (LONGLONG)1);
+}
+
+/*++
+Function:
+InterlockedExchange
+
+The InterlockedExchange function atomically exchanges a pair of
+values. The function prevents more than one thread from using the same
+variable simultaneously.
+
+Parameters
+
+Target
+[in/out] Pointer to the value to exchange. The function sets
+this variable to Value, and returns its prior value.
+Value
+[in] Specifies a new value for the variable pointed to by Target.
+
+Return Values
+
+The function returns the initial value pointed to by Target.
+
+--*/
+EXTERN_C
+PALIMPORT
+inline
+LONG
+PALAPI
+InterlockedExchange(
+ IN OUT LONG volatile *Target,
+ IN LONG Value)
+{
+ return __sync_swap(Target, Value);
+}
+
+EXTERN_C
+PALIMPORT
+inline
+LONGLONG
+PALAPI
+InterlockedExchange64(
+ IN OUT LONGLONG volatile *Target,
+ IN LONGLONG Value)
+{
+ return __sync_swap(Target, Value);
+}
+
+/*++
+Function:
+InterlockedCompareExchange
+
+The InterlockedCompareExchange function performs an atomic comparison
+of the specified values and exchanges the values, based on the outcome
+of the comparison. The function prevents more than one thread from
+using the same variable simultaneously.
+
+If you are exchanging pointer values, this function has been
+superseded by the InterlockedCompareExchangePointer function.
+
+Parameters
+
+Destination [in/out] Specifies the address of the destination value. The sign is ignored.
+Exchange [in] Specifies the exchange value. The sign is ignored.
+Comperand [in] Specifies the value to compare to Destination. The sign is ignored.
+
+Return Values
+
+The return value is the initial value of the destination.
+
+--*/
+EXTERN_C
+PALIMPORT
+inline
+LONG
+PALAPI
+InterlockedCompareExchange(
+ IN OUT LONG volatile *Destination,
+ IN LONG Exchange,
+ IN LONG Comperand)
+{
+ return __sync_val_compare_and_swap(
+ Destination, /* The pointer to a variable whose value is to be compared with. */
+ Comperand, /* The value to be compared */
+ Exchange /* The value to be stored */);
+}
+
+EXTERN_C
+PALIMPORT
+inline
+LONG
+PALAPI
+InterlockedCompareExchangeAcquire(
+ IN OUT LONG volatile *Destination,
+ IN LONG Exchange,
+ IN LONG Comperand)
+{
+ // TODO: implement the version with only the acquire semantics
+ return __sync_val_compare_and_swap(
+ Destination, /* The pointer to a variable whose value is to be compared with. */
+ Comperand, /* The value to be compared */
+ Exchange /* The value to be stored */);
+}
+
+EXTERN_C
+PALIMPORT
+inline
+LONG
+PALAPI
+InterlockedCompareExchangeRelease(
+ IN OUT LONG volatile *Destination,
+ IN LONG Exchange,
+ IN LONG Comperand)
+{
+ // TODO: implement the version with only the release semantics
+ return __sync_val_compare_and_swap(
+ Destination, /* The pointer to a variable whose value is to be compared with. */
+ Comperand, /* The value to be compared */
+ Exchange /* The value to be stored */);
+}
+
+// See the 32-bit variant in interlock2.s
+EXTERN_C
+PALIMPORT
+inline
+LONGLONG
+PALAPI
+InterlockedCompareExchange64(
+ IN OUT LONGLONG volatile *Destination,
+ IN LONGLONG Exchange,
+ IN LONGLONG Comperand)
+{
+ return __sync_val_compare_and_swap(
+ Destination, /* The pointer to a variable whose value is to be compared with. */
+ Comperand, /* The value to be compared */
+ Exchange /* The value to be stored */);
+}
+
+/*++
+Function:
+InterlockedExchangeAdd
+
+The InterlockedExchangeAdd function atomically adds the value of 'Value'
+to the variable that 'Addend' points to.
+
+Parameters
+
+lpAddend
+[in/out] Pointer to the variable to to added.
+
+Return Values
+
+The return value is the original value that 'Addend' pointed to.
+
+--*/
+EXTERN_C
+PALIMPORT
+inline
+LONG
+PALAPI
+InterlockedExchangeAdd(
+ IN OUT LONG volatile *Addend,
+ IN LONG Value)
+{
+ return __sync_fetch_and_add(Addend, Value);
+}
+
+EXTERN_C
+PALIMPORT
+inline
+LONGLONG
+PALAPI
+InterlockedExchangeAdd64(
+ IN OUT LONGLONG volatile *Addend,
+ IN LONGLONG Value)
+{
+ return __sync_fetch_and_add(Addend, Value);
+}
+
+EXTERN_C
+PALIMPORT
+inline
+LONG
+PALAPI
+InterlockedAnd(
+ IN OUT LONG volatile *Destination,
+ IN LONG Value)
+{
+ return __sync_fetch_and_and(Destination, Value);
+}
+
+EXTERN_C
+PALIMPORT
+inline
+LONG
+PALAPI
+InterlockedOr(
+ IN OUT LONG volatile *Destination,
+ IN LONG Value)
+{
+ return __sync_fetch_and_or(Destination, Value);
+}
+
+EXTERN_C
+PALIMPORT
+inline
+UCHAR
+PALAPI
+InterlockedBitTestAndReset(
+ IN OUT LONG volatile *Base,
+ IN LONG Bit)
+{
+ return (InterlockedAnd(Base, ~(1 << Bit)) & (1 << Bit)) != 0;
+}
+
+EXTERN_C
+PALIMPORT
+inline
+UCHAR
+PALAPI
+InterlockedBitTestAndSet(
+ IN OUT LONG volatile *Base,
+ IN LONG Bit)
+{
+ return (InterlockedOr(Base, (1 << Bit)) & (1 << Bit)) != 0;
+}
+
+#if defined(BIT64)
+#define InterlockedExchangePointer(Target, Value) \
+ ((PVOID)InterlockedExchange64((PLONG64)(Target), (LONGLONG)(Value)))
+
+#define InterlockedCompareExchangePointer(Destination, ExChange, Comperand) \
+ ((PVOID)InterlockedCompareExchange64((PLONG64)(Destination), (LONGLONG)(ExChange), (LONGLONG)(Comperand)))
+#else
+#define InterlockedExchangePointer(Target, Value) \
+ ((PVOID)(UINT_PTR)InterlockedExchange((PLONG)(UINT_PTR)(Target), (LONG)(UINT_PTR)(Value)))
+
+#define InterlockedCompareExchangePointer(Destination, ExChange, Comperand) \
+ ((PVOID)(UINT_PTR)InterlockedCompareExchange((PLONG)(UINT_PTR)(Destination), (LONG)(UINT_PTR)(ExChange), (LONG)(UINT_PTR)(Comperand)))
+#endif
+
+/*++
+Function:
+MemoryBarrier
+
+The MemoryBarrier function creates a full memory barrier.
+
+--*/
+EXTERN_C
+PALIMPORT
+inline
+VOID
+PALAPI
+MemoryBarrier(
+ VOID)
+{
+ __sync_synchronize();
+}
+
+PALIMPORT
+VOID
+PALAPI
+YieldProcessor(
+ VOID);
+
+PALIMPORT
+DWORD
+PALAPI
+GetCurrentProcessorNumber();
+
+/*++
+Function:
+PAL_HasGetCurrentProcessorNumber
+
+Checks if GetCurrentProcessorNumber is available in the current environment
+
+--*/
+PALIMPORT
+BOOL
+PALAPI
+PAL_HasGetCurrentProcessorNumber();
+
+#define FORMAT_MESSAGE_ALLOCATE_BUFFER 0x00000100
+#define FORMAT_MESSAGE_IGNORE_INSERTS 0x00000200
+#define FORMAT_MESSAGE_FROM_STRING 0x00000400
+#define FORMAT_MESSAGE_FROM_SYSTEM 0x00001000
+#define FORMAT_MESSAGE_ARGUMENT_ARRAY 0x00002000
+#define FORMAT_MESSAGE_MAX_WIDTH_MASK 0x000000FF
+
+PALIMPORT
+DWORD
+PALAPI
+FormatMessageW(
+ IN DWORD dwFlags,
+ IN LPCVOID lpSource,
+ IN DWORD dwMessageId,
+ IN DWORD dwLanguageId,
+ OUT LPWSTR lpBffer,
+ IN DWORD nSize,
+ IN va_list *Arguments);
+
+#ifdef UNICODE
+#define FormatMessage FormatMessageW
+#endif
+
+
+PALIMPORT
+DWORD
+PALAPI
+GetLastError(
+ VOID);
+
+PALIMPORT
+VOID
+PALAPI
+SetLastError(
+ IN DWORD dwErrCode);
+
+PALIMPORT
+LPWSTR
+PALAPI
+GetCommandLineW(
+ VOID);
+
+#ifdef UNICODE
+#define GetCommandLine GetCommandLineW
+#endif
+
+PALIMPORT
+VOID
+PALAPI
+RtlRestoreContext(
+ IN PCONTEXT ContextRecord,
+ IN PEXCEPTION_RECORD ExceptionRecord
+);
+
+PALIMPORT
+VOID
+PALAPI
+RtlCaptureContext(
+ OUT PCONTEXT ContextRecord
+);
+
+PALIMPORT
+UINT
+PALAPI
+GetWriteWatch(
+ IN DWORD dwFlags,
+ IN PVOID lpBaseAddress,
+ IN SIZE_T dwRegionSize,
+ OUT PVOID *lpAddresses,
+ IN OUT PULONG_PTR lpdwCount,
+ OUT PULONG lpdwGranularity
+);
+
+PALIMPORT
+UINT
+PALAPI
+ResetWriteWatch(
+ IN LPVOID lpBaseAddress,
+ IN SIZE_T dwRegionSize
+);
+
+PALIMPORT
+VOID
+PALAPI
+FlushProcessWriteBuffers();
+
+typedef void (*PAL_ActivationFunction)(CONTEXT *context);
+typedef BOOL (*PAL_SafeActivationCheckFunction)(SIZE_T ip, BOOL checkingCurrentThread);
+
+PALIMPORT
+VOID
+PALAPI
+PAL_SetActivationFunction(
+ IN PAL_ActivationFunction pActivationFunction,
+ IN PAL_SafeActivationCheckFunction pSafeActivationCheckFunction);
+
+PALIMPORT
+BOOL
+PALAPI
+PAL_InjectActivation(
+ IN HANDLE hThread
+);
+
+#define VER_PLATFORM_WIN32_WINDOWS 1
+#define VER_PLATFORM_WIN32_NT 2
+#define VER_PLATFORM_UNIX 10
+#define VER_PLATFORM_MACOSX 11
+
+typedef struct _OSVERSIONINFOA {
+ DWORD dwOSVersionInfoSize;
+ DWORD dwMajorVersion;
+ DWORD dwMinorVersion;
+ DWORD dwBuildNumber;
+ DWORD dwPlatformId;
+ CHAR szCSDVersion[ 128 ];
+} OSVERSIONINFOA, *POSVERSIONINFOA, *LPOSVERSIONINFOA;
+
+typedef struct _OSVERSIONINFOW {
+ DWORD dwOSVersionInfoSize;
+ DWORD dwMajorVersion;
+ DWORD dwMinorVersion;
+ DWORD dwBuildNumber;
+ DWORD dwPlatformId;
+ WCHAR szCSDVersion[ 128 ];
+} OSVERSIONINFOW, *POSVERSIONINFOW, *LPOSVERSIONINFOW;
+
+#ifdef UNICODE
+typedef OSVERSIONINFOW OSVERSIONINFO;
+typedef POSVERSIONINFOW POSVERSIONINFO;
+typedef LPOSVERSIONINFOW LPOSVERSIONINFO;
+#else
+typedef OSVERSIONINFOA OSVERSIONINFO;
+typedef POSVERSIONINFOA POSVERSIONINFO;
+typedef LPOSVERSIONINFOA LPOSVERSIONINFO;
+#endif
+
+typedef struct _OSVERSIONINFOEXA {
+ DWORD dwOSVersionInfoSize;
+ DWORD dwMajorVersion;
+ DWORD dwMinorVersion;
+ DWORD dwBuildNumber;
+ DWORD dwPlatformId;
+ CHAR szCSDVersion[ 128 ];
+ WORD wServicePackMajor;
+ WORD wServicePackMinor;
+ WORD wSuiteMask;
+ BYTE wProductType;
+ BYTE wReserved;
+} OSVERSIONINFOEXA, *POSVERSIONINFOEXA, *LPOSVERSIONINFOEXA;
+
+typedef struct _OSVERSIONINFOEXW {
+ DWORD dwOSVersionInfoSize;
+ DWORD dwMajorVersion;
+ DWORD dwMinorVersion;
+ DWORD dwBuildNumber;
+ DWORD dwPlatformId;
+ WCHAR szCSDVersion[ 128 ];
+ WORD wServicePackMajor;
+ WORD wServicePackMinor;
+ WORD wSuiteMask;
+ BYTE wProductType;
+ BYTE wReserved;
+} OSVERSIONINFOEXW, *POSVERSIONINFOEXW, *LPOSVERSIONINFOEXW;
+
+#ifdef UNICODE
+typedef OSVERSIONINFOEXW OSVERSIONINFOEX;
+typedef POSVERSIONINFOEXW POSVERSIONINFOEX;
+typedef LPOSVERSIONINFOEXW LPOSVERSIONINFOEX;
+#else
+typedef OSVERSIONINFOEXA OSVERSIONINFOEX;
+typedef POSVERSIONINFOEXA POSVERSIONINFOEX;
+typedef LPOSVERSIONINFOEXA LPOSVERSIONINFOEX;
+#endif
+
+PALIMPORT
+BOOL
+PALAPI
+GetVersionExW(
+ IN OUT LPOSVERSIONINFOW lpVersionInformation);
+
+#ifdef UNICODE
+#define GetVersionEx GetVersionExW
+#else
+#define GetVersionEx GetVersionExA
+#endif
+
+#define IMAGE_FILE_MACHINE_I386 0x014c
+#define IMAGE_FILE_MACHINE_ARM64 0xAA64 // ARM64 Little-Endian
+
+typedef struct _SYSTEM_INFO {
+ WORD wProcessorArchitecture_PAL_Undefined;
+ WORD wReserved_PAL_Undefined; // NOTE: diff from winbase.h - no obsolete dwOemId union
+ DWORD dwPageSize;
+ LPVOID lpMinimumApplicationAddress;
+ LPVOID lpMaximumApplicationAddress;
+ DWORD_PTR dwActiveProcessorMask_PAL_Undefined;
+ DWORD dwNumberOfProcessors;
+ DWORD dwProcessorType_PAL_Undefined;
+ DWORD dwAllocationGranularity;
+ WORD wProcessorLevel_PAL_Undefined;
+ WORD wProcessorRevision_PAL_Undefined;
+} SYSTEM_INFO, *LPSYSTEM_INFO;
+
+PALIMPORT
+VOID
+PALAPI
+GetSystemInfo(
+ OUT LPSYSTEM_INFO lpSystemInfo);
+
+PALIMPORT
+BOOL
+PALAPI
+GetDiskFreeSpaceW(
+ LPCWSTR lpDirectoryName,
+ LPDWORD lpSectorsPerCluster,
+ LPDWORD lpBytesPerSector,
+ LPDWORD lpNumberOfFreeClusters,
+ LPDWORD lpTotalNumberOfClusters);
+
+#ifdef UNICODE
+#define GetDiskFreeSpace GetDiskFreeSpaceW
+#endif
+
+PALIMPORT
+BOOL
+PALAPI
+CreatePipe(
+ OUT PHANDLE hReadPipe,
+ OUT PHANDLE hWritePipe,
+ IN LPSECURITY_ATTRIBUTES lpPipeAttributes,
+ IN DWORD nSize
+ );
+
+PALIMPORT
+BOOL
+PALAPI
+DeregisterEventSource (
+ IN HANDLE hEventLog
+ );
+
+PALIMPORT
+HANDLE
+PALAPI
+RegisterEventSourceA (
+ IN OPTIONAL LPCSTR lpUNCServerName,
+ IN LPCSTR lpSourceName
+ );
+PALIMPORT
+HANDLE
+PALAPI
+RegisterEventSourceW (
+ IN OPTIONAL LPCWSTR lpUNCServerName,
+ IN LPCWSTR lpSourceName
+ );
+#ifdef UNICODE
+#define RegisterEventSource RegisterEventSourceW
+#else
+#define RegisterEventSource RegisterEventSourceA
+#endif // !UNICODE
+
+//
+// The types of events that can be logged.
+//
+#define EVENTLOG_SUCCESS 0x0000
+#define EVENTLOG_ERROR_TYPE 0x0001
+#define EVENTLOG_WARNING_TYPE 0x0002
+#define EVENTLOG_INFORMATION_TYPE 0x0004
+#define EVENTLOG_AUDIT_SUCCESS 0x0008
+#define EVENTLOG_AUDIT_FAILURE 0x0010
+
+PALIMPORT
+BOOL
+PALAPI
+ReportEventA (
+ IN HANDLE hEventLog,
+ IN WORD wType,
+ IN WORD wCategory,
+ IN DWORD dwEventID,
+ IN OPTIONAL PSID lpUserSid,
+ IN WORD wNumStrings,
+ IN DWORD dwDataSize,
+ IN OPTIONAL LPCSTR *lpStrings,
+ IN OPTIONAL LPVOID lpRawData
+ );
+PALIMPORT
+BOOL
+PALAPI
+ReportEventW (
+ IN HANDLE hEventLog,
+ IN WORD wType,
+ IN WORD wCategory,
+ IN DWORD dwEventID,
+ IN OPTIONAL PSID lpUserSid,
+ IN WORD wNumStrings,
+ IN DWORD dwDataSize,
+ IN OPTIONAL LPCWSTR *lpStrings,
+ IN OPTIONAL LPVOID lpRawData
+ );
+#ifdef UNICODE
+#define ReportEvent ReportEventW
+#else
+#define ReportEvent ReportEventA
+#endif // !UNICODE
+
+PALIMPORT
+HRESULT
+PALAPI
+CoCreateGuid(OUT GUID * pguid);
+
+#if defined FEATURE_PAL_ANSI
+#include "palprivate.h"
+#endif //FEATURE_PAL_ANSI
+/******************* C Runtime Entrypoints *******************************/
+
+/* Some C runtime functions needs to be reimplemented by the PAL.
+ To avoid name collisions, those functions have been renamed using
+ defines */
+#ifdef PLATFORM_UNIX
+#ifndef PAL_STDCPP_COMPAT
+#define exit PAL_exit
+#define atexit PAL_atexit
+#define printf PAL_printf
+#define vprintf PAL_vprintf
+#define wprintf PAL_wprintf
+#define sprintf PAL_sprintf
+#define swprintf PAL_swprintf
+#define sscanf PAL_sscanf
+#define wcsspn PAL_wcsspn
+#define wcstod PAL_wcstod
+#define wcstol PAL_wcstol
+#define wcstoul PAL_wcstoul
+#define wcscat PAL_wcscat
+#define wcscpy PAL_wcscpy
+#define wcslen PAL_wcslen
+#define wcsncmp PAL_wcsncmp
+#define wcschr PAL_wcschr
+#define wcsrchr PAL_wcsrchr
+#define wcsstr PAL_wcsstr
+#define swscanf PAL_swscanf
+#define wcspbrk PAL_wcspbrk
+#define wcscmp PAL_wcscmp
+#define wcsncat PAL_wcsncat
+#define wcsncpy PAL_wcsncpy
+#define wcstok PAL_wcstok
+#define wcscspn PAL_wcscspn
+#define iswprint PAL_iswprint
+#define iswalpha PAL_iswalpha
+#define iswdigit PAL_iswdigit
+#define iswspace PAL_iswspace
+#define iswupper PAL_iswupper
+#define iswxdigit PAL_iswxdigit
+#define towlower PAL_towlower
+#define towupper PAL_towupper
+#define vsprintf PAL_vsprintf
+#define vswprintf PAL_vswprintf
+#define realloc PAL_realloc
+#define fopen PAL_fopen
+#define strtok PAL_strtok
+#define strtoul PAL_strtoul
+#define fprintf PAL_fprintf
+#define fwprintf PAL_fwprintf
+#define vfprintf PAL_vfprintf
+#define vfwprintf PAL_vfwprintf
+#define ctime PAL_ctime
+#define localtime PAL_localtime
+#define mktime PAL_mktime
+#define rand PAL_rand
+#define time PAL_time
+#define getenv PAL_getenv
+#define fgets PAL_fgets
+#define fgetws PAL_fgetws
+#define fputc PAL_fputc
+#define putchar PAL_putchar
+#define qsort PAL_qsort
+#define bsearch PAL_bsearch
+#define ferror PAL_ferror
+#define fread PAL_fread
+#define fwrite PAL_fwrite
+#define feof PAL_feof
+#define ftell PAL_ftell
+#define fclose PAL_fclose
+#define setbuf PAL_setbuf
+#define fflush PAL_fflush
+#define fputs PAL_fputs
+#define fseek PAL_fseek
+#define fgetpos PAL_fgetpos
+#define fsetpos PAL_fsetpos
+#define getc PAL_getc
+#define fgetc PAL_getc // not a typo
+#define ungetc PAL_ungetc
+#define setvbuf PAL_setvbuf
+#define atol PAL_atol
+#define labs PAL_labs
+#define acos PAL_acos
+#define asin PAL_asin
+#define atan2 PAL_atan2
+#define exp PAL_exp
+#define log PAL_log
+#define log10 PAL_log10
+#define pow PAL_pow
+#define malloc PAL_malloc
+#define free PAL_free
+#define mkstemp PAL_mkstemp
+#define rename PAL_rename
+#define _strdup PAL__strdup
+#define _getcwd PAL__getcwd
+#define _open PAL__open
+#define _close PAL__close
+#define _wcstoui64 PAL__wcstoui64
+#define _flushall PAL__flushall
+#define _vsnprintf PAL__vsnprintf
+
+#ifdef _AMD64_
+#define _mm_getcsr PAL__mm_getcsr
+#define _mm_setcsr PAL__mm_setcsr
+#endif // _AMD64_
+
+#endif // !PAL_STDCPP_COMPAT
+#endif // PLATFORM_UNIX
+
+#ifndef _CONST_RETURN
+#ifdef __cplusplus
+#define _CONST_RETURN const
+#define _CRT_CONST_CORRECT_OVERLOADS
+#else
+#define _CONST_RETURN
+#endif
+#endif
+
+/* For backwards compatibility */
+#define _WConst_return _CONST_RETURN
+
+#define EOF (-1)
+
+typedef int errno_t;
+
+#ifndef PAL_STDCPP_COMPAT
+
+typedef struct {
+ int quot;
+ int rem;
+} div_t;
+
+PALIMPORT div_t div(int numer, int denom);
+
+#if defined(_DEBUG)
+
+/*++
+Function:
+PAL_memcpy
+
+Overlapping buffer-safe version of memcpy.
+See MSDN doc for memcpy
+--*/
+EXTERN_C
+PALIMPORT
+void *PAL_memcpy (void *dest, const void *src, size_t count);
+
+PALIMPORT void * __cdecl memcpy(void *, const void *, size_t);
+
+#define memcpy PAL_memcpy
+#define IS_PAL_memcpy 1
+#define TEST_PAL_DEFERRED(def) IS_##def
+#define IS_REDEFINED_IN_PAL(def) TEST_PAL_DEFERRED(def)
+#else //defined(_DEBUG)
+PALIMPORT void * __cdecl memcpy(void *, const void *, size_t);
+#endif //defined(_DEBUG)
+PALIMPORT int __cdecl memcmp(const void *, const void *, size_t);
+PALIMPORT void * __cdecl memset(void *, int, size_t);
+PALIMPORT void * __cdecl memmove(void *, const void *, size_t);
+PALIMPORT void * __cdecl memchr(const void *, int, size_t);
+PALIMPORT long long int __cdecl atoll(const char *);
+PALIMPORT size_t __cdecl strlen(const char *);
+PALIMPORT int __cdecl strcmp(const char*, const char *);
+PALIMPORT int __cdecl strncmp(const char*, const char *, size_t);
+PALIMPORT int __cdecl _strnicmp(const char *, const char *, size_t);
+PALIMPORT char * __cdecl strcat(char *, const char *);
+PALIMPORT char * __cdecl strncat(char *, const char *, size_t);
+PALIMPORT char * __cdecl strcpy(char *, const char *);
+PALIMPORT char * __cdecl strncpy(char *, const char *, size_t);
+PALIMPORT char * __cdecl strchr(const char *, int);
+PALIMPORT char * __cdecl strrchr(const char *, int);
+PALIMPORT char * __cdecl strpbrk(const char *, const char *);
+PALIMPORT char * __cdecl strstr(const char *, const char *);
+PALIMPORT char * __cdecl strtok(char *, const char *);
+PALIMPORT size_t __cdecl strspn(const char *, const char *);
+PALIMPORT size_t __cdecl strcspn(const char *, const char *);
+PALIMPORT int __cdecl sprintf(char *, const char *, ...);
+PALIMPORT int __cdecl vsprintf(char *, const char *, va_list);
+PALIMPORT int __cdecl sscanf(const char *, const char *, ...);
+PALIMPORT int __cdecl atoi(const char *);
+PALIMPORT LONG __cdecl atol(const char *);
+PALIMPORT ULONG __cdecl strtoul(const char *, char **, int);
+PALIMPORT double __cdecl atof(const char *);
+PALIMPORT double __cdecl strtod(const char *, char **);
+PALIMPORT int __cdecl isprint(int);
+PALIMPORT int __cdecl isspace(int);
+PALIMPORT int __cdecl isalpha(int);
+PALIMPORT int __cdecl isalnum(int);
+PALIMPORT int __cdecl isdigit(int);
+PALIMPORT int __cdecl isxdigit(int);
+PALIMPORT int __cdecl isupper(int);
+PALIMPORT int __cdecl islower(int);
+PALIMPORT int __cdecl tolower(int);
+PALIMPORT int __cdecl toupper(int);
+
+#endif // PAL_STDCPP_COMPAT
+
+PALIMPORT errno_t __cdecl memcpy_s(void *, size_t, const void *, size_t);
+PALIMPORT errno_t __cdecl memmove_s(void *, size_t, const void *, size_t);
+PALIMPORT char * __cdecl _strlwr(char *);
+PALIMPORT int __cdecl _stricmp(const char *, const char *);
+PALIMPORT int __cdecl _snprintf(char *, size_t, const char *, ...);
+PALIMPORT char * __cdecl _gcvt_s(char *, int, double, int);
+PALIMPORT char * __cdecl _ecvt(double, int, int *, int *);
+PALIMPORT int __cdecl __iscsym(int);
+PALIMPORT size_t __cdecl _mbslen(const unsigned char *);
+PALIMPORT unsigned char * __cdecl _mbsinc(const unsigned char *);
+PALIMPORT unsigned char * __cdecl _mbsninc(const unsigned char *, size_t);
+PALIMPORT unsigned char * __cdecl _mbsdec(const unsigned char *, const unsigned char *);
+PALIMPORT int __cdecl _wcsicmp(const WCHAR *, const WCHAR*);
+PALIMPORT int __cdecl _wcsnicmp(const WCHAR *, const WCHAR *, size_t);
+PALIMPORT int __cdecl _vsnprintf(char *, size_t, const char *, va_list);
+PALIMPORT int __cdecl _vsnwprintf(WCHAR *, size_t, const WCHAR *, va_list);
+PALIMPORT WCHAR * __cdecl _itow(int, WCHAR *, int);
+
+PALIMPORT size_t __cdecl PAL_wcslen(const WCHAR *);
+PALIMPORT int __cdecl PAL_wcscmp(const WCHAR*, const WCHAR*);
+PALIMPORT int __cdecl PAL_wcsncmp(const WCHAR *, const WCHAR *, size_t);
+PALIMPORT WCHAR * __cdecl PAL_wcscat(WCHAR *, const WCHAR *);
+PALIMPORT WCHAR * __cdecl PAL_wcsncat(WCHAR *, const WCHAR *, size_t);
+PALIMPORT WCHAR * __cdecl PAL_wcscpy(WCHAR *, const WCHAR *);
+PALIMPORT WCHAR * __cdecl PAL_wcsncpy(WCHAR *, const WCHAR *, size_t);
+PALIMPORT const WCHAR * __cdecl PAL_wcschr(const WCHAR *, WCHAR);
+PALIMPORT const WCHAR * __cdecl PAL_wcsrchr(const WCHAR *, WCHAR);
+PALIMPORT WCHAR _WConst_return * __cdecl PAL_wcspbrk(const WCHAR *, const WCHAR *);
+PALIMPORT WCHAR _WConst_return * __cdecl PAL_wcsstr(const WCHAR *, const WCHAR *);
+PALIMPORT WCHAR * __cdecl PAL_wcstok(WCHAR *, const WCHAR *);
+PALIMPORT size_t __cdecl PAL_wcscspn(const WCHAR *, const WCHAR *);
+PALIMPORT int __cdecl PAL_swprintf(WCHAR *, const WCHAR *, ...);
+PALIMPORT int __cdecl PAL_vswprintf(WCHAR *, const WCHAR *, va_list);
+PALIMPORT int __cdecl PAL__vsnprintf(LPSTR Buffer, size_t Count, LPCSTR Format, va_list ap);
+PALIMPORT int __cdecl _snwprintf(WCHAR *, size_t, const WCHAR *, ...);
+PALIMPORT int __cdecl PAL_swscanf(const WCHAR *, const WCHAR *, ...);
+PALIMPORT LONG __cdecl PAL_wcstol(const WCHAR *, WCHAR **, int);
+PALIMPORT ULONG __cdecl PAL_wcstoul(const WCHAR *, WCHAR **, int);
+PALIMPORT size_t __cdecl PAL_wcsspn (const WCHAR *, const WCHAR *);
+PALIMPORT double __cdecl PAL_wcstod(const WCHAR *, WCHAR **);
+PALIMPORT int __cdecl PAL_iswalpha(WCHAR);
+PALIMPORT int __cdecl PAL_iswprint(WCHAR);
+PALIMPORT int __cdecl PAL_iswupper(WCHAR);
+PALIMPORT int __cdecl PAL_iswspace(WCHAR);
+PALIMPORT int __cdecl PAL_iswdigit(WCHAR);
+PALIMPORT int __cdecl PAL_iswxdigit(WCHAR);
+PALIMPORT WCHAR __cdecl PAL_towlower(WCHAR);
+PALIMPORT WCHAR __cdecl PAL_towupper(WCHAR);
+
+PALIMPORT WCHAR * __cdecl _wcslwr(WCHAR *);
+PALIMPORT ULONGLONG _wcstoui64(const WCHAR *, WCHAR **, int);
+PALIMPORT WCHAR * __cdecl _i64tow(__int64, WCHAR *, int);
+PALIMPORT WCHAR * __cdecl _ui64tow(unsigned __int64, WCHAR *, int);
+PALIMPORT int __cdecl _wtoi(const WCHAR *);
+
+#ifdef __cplusplus
+extern "C++" {
+inline WCHAR *PAL_wcschr(WCHAR *_S, WCHAR _C)
+ {return ((WCHAR *)PAL_wcschr((const WCHAR *)_S, _C)); }
+inline WCHAR *PAL_wcsrchr(WCHAR *_S, WCHAR _C)
+ {return ((WCHAR *)PAL_wcsrchr((const WCHAR *)_S, _C)); }
+inline WCHAR *PAL_wcspbrk(WCHAR *_S, const WCHAR *_P)
+ {return ((WCHAR *)PAL_wcspbrk((const WCHAR *)_S, _P)); }
+inline WCHAR *PAL_wcsstr(WCHAR *_S, const WCHAR *_P)
+ {return ((WCHAR *)PAL_wcsstr((const WCHAR *)_S, _P)); }
+}
+#endif
+
+/*++
+Function:
+_rotl
+
+See MSDN doc.
+--*/
+EXTERN_C
+PALIMPORT
+inline
+unsigned int __cdecl _rotl(unsigned int value, int shift)
+{
+ unsigned int retval = 0;
+
+ shift &= 0x1f;
+ retval = (value << shift) | (value >> (sizeof(int) * CHAR_BIT - shift));
+ return retval;
+}
+
+// On 64 bit unix, make the long an int.
+#ifdef BIT64
+#define _lrotl _rotl
+#endif // BIT64
+
+/*++
+Function:
+_rotr
+
+See MSDN doc.
+--*/
+EXTERN_C
+PALIMPORT
+inline
+unsigned int __cdecl _rotr(unsigned int value, int shift)
+{
+ unsigned int retval;
+
+ shift &= 0x1f;
+ retval = (value >> shift) | (value << (sizeof(int) * CHAR_BIT - shift));
+ return retval;
+}
+
+PALIMPORT int __cdecl abs(int);
+#ifndef PAL_STDCPP_COMPAT
+PALIMPORT LONG __cdecl labs(LONG);
+#endif // !PAL_STDCPP_COMPAT
+// clang complains if this is declared with __int64
+PALIMPORT long long __cdecl llabs(long long);
+
+PALIMPORT int __cdecl _finite(double);
+PALIMPORT int __cdecl _isnan(double);
+PALIMPORT double __cdecl _copysign(double, double);
+PALIMPORT double __cdecl acos(double);
+PALIMPORT double __cdecl asin(double);
+PALIMPORT double __cdecl atan(double);
+PALIMPORT double __cdecl atan2(double, double);
+PALIMPORT double __cdecl ceil(double);
+PALIMPORT double __cdecl cos(double);
+PALIMPORT double __cdecl cosh(double);
+PALIMPORT double __cdecl exp(double);
+PALIMPORT double __cdecl fabs(double);
+PALIMPORT double __cdecl floor(double);
+PALIMPORT double __cdecl fmod(double, double);
+PALIMPORT double __cdecl log(double);
+PALIMPORT double __cdecl log10(double);
+PALIMPORT double __cdecl modf(double, double*);
+PALIMPORT double __cdecl pow(double, double);
+PALIMPORT double __cdecl sin(double);
+PALIMPORT double __cdecl sinh(double);
+PALIMPORT double __cdecl sqrt(double);
+PALIMPORT double __cdecl tan(double);
+PALIMPORT double __cdecl tanh(double);
+
+PALIMPORT float __cdecl fabsf(float);
+PALIMPORT float __cdecl fmodf(float, float);
+PALIMPORT float __cdecl modff(float, float*);
+
+#ifndef PAL_STDCPP_COMPAT
+
+#ifdef __cplusplus
+extern "C++" {
+
+inline __int64 abs(__int64 _X) {
+ return llabs(_X);
+}
+
+}
+#endif
+
+PALIMPORT void * __cdecl malloc(size_t);
+PALIMPORT void __cdecl free(void *);
+PALIMPORT void * __cdecl realloc(void *, size_t);
+PALIMPORT char * __cdecl _strdup(const char *);
+
+#if defined(_MSC_VER)
+#define alloca _alloca
+#elif defined(PLATFORM_UNIX)
+#define _alloca alloca
+#else
+// MingW
+#define _alloca __builtin_alloca
+#define alloca __builtin_alloca
+#endif //_MSC_VER
+
+#if defined(__GNUC__) && defined(PLATFORM_UNIX)
+#define alloca __builtin_alloca
+#endif // __GNUC__
+
+#define max(a, b) (((a) > (b)) ? (a) : (b))
+#define min(a, b) (((a) < (b)) ? (a) : (b))
+
+#endif // !PAL_STDCPP_COMPAT
+
+PALIMPORT PAL_NORETURN void __cdecl exit(int);
+int __cdecl atexit(void (__cdecl *function)(void));
+
+PALIMPORT void __cdecl qsort(void *, size_t, size_t, int (__cdecl *)(const void *, const void *));
+PALIMPORT void * __cdecl bsearch(const void *, const void *, size_t, size_t,
+int (__cdecl *)(const void *, const void *));
+
+PALIMPORT void __cdecl _splitpath(const char *, char *, char *, char *, char *);
+PALIMPORT void __cdecl _wsplitpath(const WCHAR *, WCHAR *, WCHAR *, WCHAR *, WCHAR *);
+PALIMPORT void __cdecl _makepath(char *, const char *, const char *, const char *, const char *);
+PALIMPORT void __cdecl _wmakepath(WCHAR *, const WCHAR *, const WCHAR *, const WCHAR *, const WCHAR *);
+PALIMPORT char * __cdecl _fullpath(char *, const char *, size_t);
+
+PALIMPORT void __cdecl _swab(char *, char *, int);
+
+#ifndef PAL_STDCPP_COMPAT
+PALIMPORT time_t __cdecl time(time_t *);
+
+struct tm {
+ int tm_sec; /* seconds after the minute - [0,59] */
+ int tm_min; /* minutes after the hour - [0,59] */
+ int tm_hour; /* hours since midnight - [0,23] */
+ int tm_mday; /* day of the month - [1,31] */
+ int tm_mon; /* months since January - [0,11] */
+ int tm_year; /* years since 1900 */
+ int tm_wday; /* days since Sunday - [0,6] */
+ int tm_yday; /* days since January 1 - [0,365] */
+ int tm_isdst; /* daylight savings time flag */
+ };
+
+PALIMPORT struct tm * __cdecl localtime(const time_t *);
+PALIMPORT time_t __cdecl mktime(struct tm *);
+PALIMPORT char * __cdecl ctime(const time_t *);
+#endif // !PAL_STDCPP_COMPAT
+
+PALIMPORT int __cdecl _open_osfhandle(INT_PTR, int);
+PALIMPORT int __cdecl _close(int);
+PALIMPORT int __cdecl _flushall();
+
+#ifdef PAL_STDCPP_COMPAT
+
+struct _PAL_FILE;
+typedef struct _PAL_FILE PAL_FILE;
+
+#else // PAL_STDCPP_COMPAT
+
+struct _FILE;
+typedef struct _FILE FILE;
+typedef struct _FILE PAL_FILE;
+
+#define SEEK_SET 0
+#define SEEK_CUR 1
+#define SEEK_END 2
+
+/* Locale categories */
+#define LC_ALL 0
+#define LC_COLLATE 1
+#define LC_CTYPE 2
+#define LC_MONETARY 3
+#define LC_NUMERIC 4
+#define LC_TIME 5
+
+#define _IOFBF 0 /* setvbuf should set fully buffered */
+#define _IOLBF 1 /* setvbuf should set line buffered */
+#define _IONBF 2 /* setvbuf should set unbuffered */
+
+#endif // PAL_STDCPP_COMPAT
+
+PALIMPORT int __cdecl PAL_fclose(PAL_FILE *);
+PALIMPORT void __cdecl PAL_setbuf(PAL_FILE *, char*);
+PALIMPORT int __cdecl PAL_fflush(PAL_FILE *);
+PALIMPORT size_t __cdecl PAL_fwrite(const void *, size_t, size_t, PAL_FILE *);
+PALIMPORT size_t __cdecl PAL_fread(void *, size_t, size_t, PAL_FILE *);
+PALIMPORT char * __cdecl PAL_fgets(char *, int, PAL_FILE *);
+PALIMPORT int __cdecl PAL_fputs(const char *, PAL_FILE *);
+PALIMPORT int __cdecl PAL_fputc(int c, PAL_FILE *stream);
+PALIMPORT int __cdecl PAL_putchar(int c);
+PALIMPORT int __cdecl PAL_fprintf(PAL_FILE *, const char *, ...);
+PALIMPORT int __cdecl PAL_vfprintf(PAL_FILE *, const char *, va_list);
+PALIMPORT int __cdecl PAL_fseek(PAL_FILE *, LONG, int);
+PALIMPORT LONG __cdecl PAL_ftell(PAL_FILE *);
+PALIMPORT int __cdecl PAL_feof(PAL_FILE *);
+PALIMPORT int __cdecl PAL_ferror(PAL_FILE *);
+PALIMPORT PAL_FILE * __cdecl PAL_fopen(const char *, const char *);
+PALIMPORT int __cdecl PAL_getc(PAL_FILE *stream);
+PALIMPORT int __cdecl PAL_fgetc(PAL_FILE *stream);
+PALIMPORT int __cdecl PAL_ungetc(int c, PAL_FILE *stream);
+PALIMPORT int __cdecl PAL_setvbuf(PAL_FILE *stream, char *, int, size_t);
+PALIMPORT WCHAR * __cdecl PAL_fgetws(WCHAR *, int, PAL_FILE *);
+PALIMPORT int __cdecl PAL_fwprintf(PAL_FILE *, const WCHAR *, ...);
+PALIMPORT int __cdecl PAL_vfwprintf(PAL_FILE *, const WCHAR *, va_list);
+PALIMPORT int __cdecl PAL_wprintf(const WCHAR*, ...);
+
+PALIMPORT int __cdecl _getw(PAL_FILE *);
+PALIMPORT int __cdecl _putw(int, PAL_FILE *);
+PALIMPORT PAL_FILE * __cdecl _fdopen(int, const char *);
+PALIMPORT PAL_FILE * __cdecl _wfopen(const WCHAR *, const WCHAR *);
+PALIMPORT PAL_FILE * __cdecl _wfsopen(const WCHAR *, const WCHAR *, int);
+
+/* Maximum value that can be returned by the rand function. */
+
+#ifndef PAL_STDCPP_COMPAT
+#define RAND_MAX 0x7fff
+#endif // !PAL_STDCPP_COMPAT
+
+PALIMPORT int __cdecl rand(void);
+PALIMPORT void __cdecl srand(unsigned int);
+
+PALIMPORT int __cdecl printf(const char *, ...);
+PALIMPORT int __cdecl vprintf(const char *, va_list);
+
+#ifdef _MSC_VER
+#define PAL_get_caller _MSC_VER
+#else
+#define PAL_get_caller 0
+#endif
+
+PALIMPORT PAL_FILE * __cdecl PAL_get_stdout(int caller);
+PALIMPORT PAL_FILE * __cdecl PAL_get_stdin(int caller);
+PALIMPORT PAL_FILE * __cdecl PAL_get_stderr(int caller);
+PALIMPORT int * __cdecl PAL_errno(int caller);
+
+#ifdef PAL_STDCPP_COMPAT
+#define PAL_stdout (PAL_get_stdout(PAL_get_caller))
+#define PAL_stdin (PAL_get_stdin(PAL_get_caller))
+#define PAL_stderr (PAL_get_stderr(PAL_get_caller))
+#define PAL_errno (*PAL_errno(PAL_get_caller))
+#else // PAL_STDCPP_COMPAT
+#define stdout (PAL_get_stdout(PAL_get_caller))
+#define stdin (PAL_get_stdin(PAL_get_caller))
+#define stderr (PAL_get_stderr(PAL_get_caller))
+#define errno (*PAL_errno(PAL_get_caller))
+#endif // PAL_STDCPP_COMPAT
+
+PALIMPORT char * __cdecl getenv(const char *);
+PALIMPORT int __cdecl _putenv(const char *);
+
+#define ERANGE 34
+
+/******************* PAL-specific I/O completion port *****************/
+
+typedef struct _PAL_IOCP_CPU_INFORMATION {
+ union {
+ FILETIME ftLastRecordedIdleTime;
+ FILETIME ftLastRecordedCurrentTime;
+ } LastRecordedTime;
+ FILETIME ftLastRecordedKernelTime;
+ FILETIME ftLastRecordedUserTime;
+} PAL_IOCP_CPU_INFORMATION;
+
+PALIMPORT
+INT
+PALAPI
+PAL_GetCPUBusyTime(
+ IN OUT PAL_IOCP_CPU_INFORMATION *lpPrevCPUInfo);
+
+/****************PAL Perf functions for PInvoke*********************/
+#if PAL_PERF
+PALIMPORT
+VOID
+PALAPI
+PAL_EnableProcessProfile(VOID);
+
+PALIMPORT
+VOID
+PALAPI
+PAL_DisableProcessProfile(VOID);
+
+PALIMPORT
+BOOL
+PALAPI
+PAL_IsProcessProfileEnabled(VOID);
+
+PALIMPORT
+INT64
+PALAPI
+PAL_GetCpuTickCount(VOID);
+#endif // PAL_PERF
+
+/******************* PAL functions for SIMD extensions *****************/
+
+PALIMPORT
+unsigned int _mm_getcsr(void);
+
+PALIMPORT
+void _mm_setcsr(unsigned int i);
+
+/******************* PAL side-by-side support ************************/
+
+#ifdef FEATURE_PAL_SXS
+//
+// Some versions of the PAL support several PALs side-by-side
+// in the process. To avoid those PALs interfering with one
+// another, they need to be told by clients when they are active
+// and when they are not.
+//
+
+// To avoid performance problems incurred by swapping thread
+// exception ports every time we leave the PAL, there's also
+// the concept of entering/leaving the PAL at its top boundary
+// (entering down/leaving up) or at the bottom boundary
+// (leaving down/entering up).
+
+typedef enum _PAL_Boundary {
+ PAL_BoundaryTop, // closer to main()
+ PAL_BoundaryBottom, // closer to execution
+ PAL_BoundaryEH, // out-of-band during EH
+
+ PAL_BoundaryMax = PAL_BoundaryEH
+} PAL_Boundary;
+
+// This function needs to be called on a thread when it enters
+// a region of code that depends on this instance of the PAL
+// in the process, and the current thread may or may not be
+// known to the PAL. This function can fail (for something else
+// than an internal error) if this is the first time that the
+// current thread entered this PAL. Note that PAL_Initialize
+// implies a call to this function. Does not modify LastError.
+PALIMPORT
+DWORD
+PALAPI
+PAL_Enter(PAL_Boundary boundary);
+
+// Returns TRUE if we this thread has already entered the PAL,
+// returns FALSE if we have not entered the PAL.
+PALIMPORT
+BOOL
+PALAPI
+PAL_HasEntered();
+
+// Equivalent to PAL_Enter(PAL_BoundaryTop) and is for stub
+// code generation use.
+PALIMPORT
+DWORD
+PALAPI
+PAL_EnterTop();
+
+// This function needs to be called on a thread when it enters
+// a region of code that depends on this instance of the PAL
+// in the process, and the current thread is already known to
+// the PAL. Does not modify LastError.
+PALIMPORT
+VOID
+PALAPI
+PAL_Reenter(PAL_Boundary boundary);
+
+// This function needs to be called on a thread when it enters
+// a region of code that depends on this instance of the PAL
+// in the process, and it is unknown whether the current thread
+// is already running in the PAL. Returns TRUE if and only if
+// the thread was not running in the PAL previously. Does not
+// modify LastError.
+PALIMPORT
+BOOL
+PALAPI
+PAL_ReenterForEH(VOID);
+
+// This function needs to be called on a thread when it leaves
+// a region of code that depends on this instance of the PAL
+// in the process. Does not modify LastError.
+PALIMPORT
+VOID
+PALAPI
+PAL_Leave(PAL_Boundary boundary);
+
+// This function is equivalent to PAL_Leave(PAL_BoundaryBottom)
+// and is available to limit the creation of stub code.
+PALIMPORT
+VOID
+PALAPI
+PAL_LeaveBottom();
+
+// This function is equivalent to PAL_Leave(PAL_BoundaryTop)
+// and is available to limit the creation of stub code.
+PALIMPORT
+VOID
+PALAPI
+PAL_LeaveTop();
+
+#ifdef __cplusplus
+//
+// A holder to enter the PAL for a specific region of code.
+// Previously, we must have been executing outside the PAL
+// (unless fEnter is set to FALSE).
+//
+class PAL_EnterHolder
+{
+private:
+ BOOL m_fEntered;
+ DWORD m_palError;
+public:
+ PAL_EnterHolder(BOOL fEnter = TRUE) : m_palError(ERROR_SUCCESS)
+ {
+ if (fEnter)
+ {
+ m_palError = PAL_Enter(PAL_BoundaryTop);
+ m_fEntered = m_palError == ERROR_SUCCESS;
+ }
+ else
+ {
+ m_fEntered = FALSE;
+ }
+ }
+
+ ~PAL_EnterHolder()
+ {
+ if (m_fEntered)
+ {
+ PAL_Leave(PAL_BoundaryTop);
+ }
+ }
+
+ DWORD GetError()
+ {
+ return m_palError;
+ }
+
+ void SuppressRelease()
+ {
+ // Used to avoid calling PAL_Leave() when
+ // another code path will explicitly do so.
+ m_fEntered = FALSE;
+ }
+};
+
+class PAL_LeaveHolder
+{
+public:
+ PAL_LeaveHolder()
+ {
+ PAL_Leave(PAL_BoundaryBottom);
+ }
+
+ ~PAL_LeaveHolder()
+ {
+ PAL_Reenter(PAL_BoundaryBottom);
+ }
+};
+#endif // __cplusplus
+
+#else // FEATURE_PAL_SXS
+
+#define PAL_Enter(boundary) ERROR_SUCCESS
+#define PAL_Reenter(boundary)
+#define PAL_Leave(boundary)
+
+#ifdef __cplusplus
+class PAL_EnterHolder {
+public:
+ // using constructor to suppress the "unused variable" warnings
+ PAL_EnterHolder() {}
+};
+class PAL_LeaveHolder {
+public:
+ // using constructor to suppress the "unused variable" warnings
+ PAL_LeaveHolder() {}
+};
+#endif // __cplusplus
+
+#endif // FEATURE_PAL_SXS
+
+#ifdef __cplusplus
+
+#include "pal_unwind.h"
+
+PALIMPORT
+VOID
+PALAPI
+PAL_FreeExceptionRecords(
+ IN EXCEPTION_RECORD *exceptionRecord,
+ IN CONTEXT *contextRecord);
+
+#define EXCEPTION_CONTINUE_SEARCH 0
+#define EXCEPTION_EXECUTE_HANDLER 1
+#define EXCEPTION_CONTINUE_EXECUTION -1
+
+struct PAL_SEHException
+{
+private:
+ static const SIZE_T NoTargetFrameSp = SIZE_MAX;
+
+ void Move(PAL_SEHException& ex)
+ {
+ ExceptionPointers.ExceptionRecord = ex.ExceptionPointers.ExceptionRecord;
+ ExceptionPointers.ContextRecord = ex.ExceptionPointers.ContextRecord;
+ TargetFrameSp = ex.TargetFrameSp;
+
+ ex.Clear();
+ }
+
+ void FreeRecords()
+ {
+ if (ExceptionPointers.ExceptionRecord != NULL)
+ {
+ PAL_FreeExceptionRecords(ExceptionPointers.ExceptionRecord, ExceptionPointers.ContextRecord);
+ ExceptionPointers.ExceptionRecord = NULL;
+ ExceptionPointers.ContextRecord = NULL;
+ }
+ }
+
+public:
+ EXCEPTION_POINTERS ExceptionPointers;
+ // Target frame stack pointer set before the 2nd pass.
+ SIZE_T TargetFrameSp;
+
+ PAL_SEHException(EXCEPTION_RECORD *pExceptionRecord, CONTEXT *pContextRecord)
+ {
+ ExceptionPointers.ExceptionRecord = pExceptionRecord;
+ ExceptionPointers.ContextRecord = pContextRecord;
+ TargetFrameSp = NoTargetFrameSp;
+ }
+
+ PAL_SEHException()
+ {
+ Clear();
+ }
+
+ // The copy constructor and copy assignment operators are deleted so that the PAL_SEHException
+ // can never be copied, only moved. This enables simple lifetime management of the exception and
+ // context records, since there is always just one PAL_SEHException instance referring to the same records.
+ PAL_SEHException(const PAL_SEHException& ex) = delete;
+ PAL_SEHException& operator=(const PAL_SEHException& ex) = delete;
+
+ PAL_SEHException(PAL_SEHException&& ex)
+ {
+ Move(ex);
+ }
+
+ PAL_SEHException& operator=(PAL_SEHException&& ex)
+ {
+ FreeRecords();
+ Move(ex);
+ return *this;
+ }
+
+ ~PAL_SEHException()
+ {
+ FreeRecords();
+ }
+
+ void Clear()
+ {
+ ExceptionPointers.ExceptionRecord = NULL;
+ ExceptionPointers.ContextRecord = NULL;
+ TargetFrameSp = NoTargetFrameSp;
+ }
+
+ CONTEXT* GetContextRecord()
+ {
+ return ExceptionPointers.ContextRecord;
+ }
+
+ EXCEPTION_RECORD* GetExceptionRecord()
+ {
+ return ExceptionPointers.ExceptionRecord;
+ }
+
+ bool IsFirstPass()
+ {
+ return (TargetFrameSp == NoTargetFrameSp);
+ }
+
+ void SecondPassDone()
+ {
+ TargetFrameSp = NoTargetFrameSp;
+ }
+};
+
+typedef BOOL (PALAPI *PHARDWARE_EXCEPTION_HANDLER)(PAL_SEHException* ex);
+typedef BOOL (PALAPI *PHARDWARE_EXCEPTION_SAFETY_CHECK_FUNCTION)(PCONTEXT contextRecord, PEXCEPTION_RECORD exceptionRecord);
+typedef VOID (PALAPI *PTERMINATION_REQUEST_HANDLER)();
+typedef DWORD (PALAPI *PGET_GCMARKER_EXCEPTION_CODE)(LPVOID ip);
+
+PALIMPORT
+VOID
+PALAPI
+PAL_SetHardwareExceptionHandler(
+ IN PHARDWARE_EXCEPTION_HANDLER exceptionHandler,
+ IN PHARDWARE_EXCEPTION_SAFETY_CHECK_FUNCTION exceptionCheckFunction);
+
+PALIMPORT
+VOID
+PALAPI
+PAL_SetGetGcMarkerExceptionCode(
+ IN PGET_GCMARKER_EXCEPTION_CODE getGcMarkerExceptionCode);
+
+PALIMPORT
+VOID
+PALAPI
+PAL_ThrowExceptionFromContext(
+ IN CONTEXT* context,
+ IN PAL_SEHException* ex);
+
+PALIMPORT
+VOID
+PALAPI
+PAL_SetTerminationRequestHandler(
+ IN PTERMINATION_REQUEST_HANDLER terminationRequestHandler);
+
+//
+// This holder is used to indicate that a hardware
+// exception should be raised as a C++ exception
+// to better emulate SEH on the xplat platforms.
+//
+class CatchHardwareExceptionHolder
+{
+public:
+ CatchHardwareExceptionHolder();
+
+ ~CatchHardwareExceptionHolder();
+
+ static bool IsEnabled();
+};
+
+//
+// NOTE: Catching hardware exceptions are only enabled in the DAC and SOS
+// builds. A hardware exception in coreclr code will fail fast/terminate
+// the process.
+//
+#ifdef FEATURE_ENABLE_HARDWARE_EXCEPTIONS
+#define HardwareExceptionHolder CatchHardwareExceptionHolder __catchHardwareException;
+#else
+#define HardwareExceptionHolder
+#endif // FEATURE_ENABLE_HARDWARE_EXCEPTIONS
+
+#ifdef FEATURE_PAL_SXS
+
+extern "C++" {
+
+//
+// This is the base class of native exception holder used to provide
+// the filter function to the exception dispatcher. This allows the
+// filter to be called during the first pass to better emulate SEH
+// the xplat platforms that only have C++ exception support.
+//
+class NativeExceptionHolderBase
+{
+ // Save the address of the holder head so the destructor
+ // doesn't have access the slow (on Linux) TLS value again.
+ NativeExceptionHolderBase **m_head;
+
+ // The next holder on the stack
+ NativeExceptionHolderBase *m_next;
+
+protected:
+ NativeExceptionHolderBase();
+
+ ~NativeExceptionHolderBase();
+
+public:
+ // Calls the holder's filter handler.
+ virtual EXCEPTION_DISPOSITION InvokeFilter(PAL_SEHException& ex) = 0;
+
+ // Adds the holder to the "stack" of holders. This is done explicitly instead
+ // of in the constructor was to avoid the mess of move constructors combined
+ // with return value optimization (in CreateHolder).
+ void Push();
+
+ // Given the currentHolder and locals stack range find the next holder starting with this one
+ // To find the first holder, pass nullptr as the currentHolder.
+ static NativeExceptionHolderBase *FindNextHolder(NativeExceptionHolderBase *currentHolder, void *frameLowAddress, void *frameHighAddress);
+};
+
+//
+// This is the second part of the native exception filter holder. It is
+// templated because the lambda used to wrap the exception filter is a
+// unknown type.
+//
+template<class FilterType>
+class NativeExceptionHolder : public NativeExceptionHolderBase
+{
+ FilterType* m_exceptionFilter;
+
+public:
+ NativeExceptionHolder(FilterType* exceptionFilter)
+ : NativeExceptionHolderBase()
+ {
+ m_exceptionFilter = exceptionFilter;
+ }
+
+ virtual EXCEPTION_DISPOSITION InvokeFilter(PAL_SEHException& ex)
+ {
+ return (*m_exceptionFilter)(ex);
+ }
+};
+
+//
+// This is a native exception holder that is used when the catch catches
+// all exceptions.
+//
+class NativeExceptionHolderCatchAll : public NativeExceptionHolderBase
+{
+
+public:
+ NativeExceptionHolderCatchAll()
+ : NativeExceptionHolderBase()
+ {
+ }
+
+ virtual EXCEPTION_DISPOSITION InvokeFilter(PAL_SEHException& ex)
+ {
+ return EXCEPTION_EXECUTE_HANDLER;
+ }
+};
+
+// This is a native exception holder that doesn't catch any exceptions.
+class NativeExceptionHolderNoCatch : public NativeExceptionHolderBase
+{
+
+public:
+ NativeExceptionHolderNoCatch()
+ : NativeExceptionHolderBase()
+ {
+ }
+
+ virtual EXCEPTION_DISPOSITION InvokeFilter(PAL_SEHException& ex)
+ {
+ return EXCEPTION_CONTINUE_SEARCH;
+ }
+};
+
+//
+// This factory class for the native exception holder is necessary because
+// templated functions don't need the explicit type parameter and can infer
+// the template type from the parameter.
+//
+class NativeExceptionHolderFactory
+{
+public:
+ template<class FilterType>
+ static NativeExceptionHolder<FilterType> CreateHolder(FilterType* exceptionFilter)
+ {
+ return NativeExceptionHolder<FilterType>(exceptionFilter);
+ }
+};
+
+// Start of a try block for exceptions raised by RaiseException
+#define PAL_TRY(__ParamType, __paramDef, __paramRef) \
+{ \
+ __ParamType __param = __paramRef; \
+ auto tryBlock = [](__ParamType __paramDef) \
+ {
+
+// Start of an exception handler. If an exception raised by the RaiseException
+// occurs in the try block and the disposition is EXCEPTION_EXECUTE_HANDLER,
+// the handler code is executed. If the disposition is EXCEPTION_CONTINUE_SEARCH,
+// the exception is rethrown. The EXCEPTION_CONTINUE_EXECUTION disposition is
+// not supported.
+#define PAL_EXCEPT(dispositionExpression) \
+ }; \
+ const bool isFinally = false; \
+ auto finallyBlock = []() {}; \
+ EXCEPTION_DISPOSITION disposition = EXCEPTION_CONTINUE_EXECUTION; \
+ auto exceptionFilter = [&disposition, &__param](PAL_SEHException& ex) \
+ { \
+ disposition = dispositionExpression; \
+ _ASSERTE(disposition != EXCEPTION_CONTINUE_EXECUTION); \
+ return disposition; \
+ }; \
+ try \
+ { \
+ HardwareExceptionHolder \
+ auto __exceptionHolder = NativeExceptionHolderFactory::CreateHolder(&exceptionFilter); \
+ __exceptionHolder.Push(); \
+ tryBlock(__param); \
+ } \
+ catch (PAL_SEHException& ex) \
+ { \
+ if (disposition == EXCEPTION_CONTINUE_EXECUTION) \
+ { \
+ exceptionFilter(ex); \
+ } \
+ if (disposition == EXCEPTION_CONTINUE_SEARCH) \
+ { \
+ throw; \
+ } \
+ ex.SecondPassDone();
+
+// Start of an exception handler. It works the same way as the PAL_EXCEPT except
+// that the disposition is obtained by calling the specified filter.
+#define PAL_EXCEPT_FILTER(filter) PAL_EXCEPT(filter(&ex.ExceptionPointers, __param))
+
+// Start of a finally block. The finally block is executed both when the try block
+// finishes or when an exception is raised using the RaiseException in it.
+#define PAL_FINALLY \
+ }; \
+ const bool isFinally = true; \
+ auto finallyBlock = [&]() \
+ {
+
+// End of an except or a finally block.
+#define PAL_ENDTRY \
+ }; \
+ if (isFinally) \
+ { \
+ try \
+ { \
+ tryBlock(__param); \
+ } \
+ catch (...) \
+ { \
+ finallyBlock(); \
+ throw; \
+ } \
+ finallyBlock(); \
+ } \
+}
+
+} // extern "C++"
+
+#endif // FEATURE_PAL_SXS
+
+#define PAL_CPP_THROW(type, obj) { throw obj; }
+#define PAL_CPP_RETHROW { throw; }
+#define PAL_CPP_TRY try { HardwareExceptionHolder
+#define PAL_CPP_CATCH_EXCEPTION(ident) } catch (Exception *ident) { PAL_Reenter(PAL_BoundaryBottom);
+#define PAL_CPP_CATCH_EXCEPTION_NOARG } catch (Exception *) { PAL_Reenter(PAL_BoundaryBottom);
+#define PAL_CPP_CATCH_DERIVED(type, ident) } catch (type *ident) { PAL_Reenter(PAL_BoundaryBottom);
+#define PAL_CPP_CATCH_ALL } catch (...) { \
+ PAL_Reenter(PAL_BoundaryBottom); \
+ try { throw; } \
+ catch (PAL_SEHException& ex) { ex.SecondPassDone(); } \
+ catch (...) {}
+
+#define PAL_CPP_ENDTRY }
+
+#ifdef _MSC_VER
+#pragma warning(disable:4611) // interaction between '_setjmp' and C++ object destruction is non-portable
+#endif
+
+#ifdef FEATURE_PAL_SXS
+
+#define PAL_TRY_FOR_DLLMAIN(ParamType, paramDef, paramRef, _reason) PAL_TRY(ParamType, paramDef, paramRef)
+
+#else // FEATURE_PAL_SXS
+
+#define PAL_TRY(ParamType, paramDef, paramRef) \
+ { \
+ ParamType __param = paramRef; \
+ ParamType paramDef; paramDef = __param; \
+ try { \
+ HardwareExceptionHolder
+
+#define PAL_TRY_FOR_DLLMAIN(ParamType, paramDef, paramRef, _reason) \
+ { \
+ ParamType __param = paramRef; \
+ ParamType paramDef; paramDef = __param; \
+ try { \
+ HardwareExceptionHolder
+
+#define PAL_ENDTRY \
+ } \
+ }
+
+#endif // FEATURE_PAL_SXS
+
+#endif // __cplusplus
+
+// Platform-specific library naming
+//
+#ifdef PLATFORM_UNIX
+#ifdef __APPLE__
+#define MAKEDLLNAME_W(name) u"lib" name u".dylib"
+#define MAKEDLLNAME_A(name) "lib" name ".dylib"
+#elif defined(_AIX)
+#define MAKEDLLNAME_W(name) L"lib" name L".a"
+#define MAKEDLLNAME_A(name) "lib" name ".a"
+#elif defined(__hppa__) || defined(_IA64_)
+#define MAKEDLLNAME_W(name) L"lib" name L".sl"
+#define MAKEDLLNAME_A(name) "lib" name ".sl"
+#else
+#define MAKEDLLNAME_W(name) u"lib" name u".so"
+#define MAKEDLLNAME_A(name) "lib" name ".so"
+#endif
+#else
+#define MAKEDLLNAME_W(name) name L".dll"
+#define MAKEDLLNAME_A(name) name ".dll"
+#endif
+
+#ifdef UNICODE
+#define MAKEDLLNAME(x) MAKEDLLNAME_W(x)
+#else
+#define MAKEDLLNAME(x) MAKEDLLNAME_A(x)
+#endif
+
+#define PAL_SHLIB_PREFIX "lib"
+
+#if __APPLE__
+#define PAL_SHLIB_SUFFIX ".dylib"
+#elif _AIX
+#define PAL_SHLIB_SUFFIX ".a"
+#elif _HPUX_
+#define PAL_SHLIB_SUFFIX ".sl"
+#else
+#define PAL_SHLIB_SUFFIX ".so"
+#endif
+
+#define DBG_EXCEPTION_HANDLED ((DWORD )0x00010001L)
+#define DBG_CONTINUE ((DWORD )0x00010002L)
+#define DBG_EXCEPTION_NOT_HANDLED ((DWORD )0x80010001L)
+
+#define DBG_TERMINATE_THREAD ((DWORD )0x40010003L)
+#define DBG_TERMINATE_PROCESS ((DWORD )0x40010004L)
+#define DBG_CONTROL_C ((DWORD )0x40010005L)
+#define DBG_RIPEXCEPTION ((DWORD )0x40010007L)
+#define DBG_CONTROL_BREAK ((DWORD )0x40010008L)
+#define DBG_COMMAND_EXCEPTION ((DWORD )0x40010009L)
+
+#define STATUS_USER_APC ((DWORD )0x000000C0L)
+#define STATUS_GUARD_PAGE_VIOLATION ((DWORD )0x80000001L)
+#define STATUS_DATATYPE_MISALIGNMENT ((DWORD )0x80000002L)
+#define STATUS_BREAKPOINT ((DWORD )0x80000003L)
+#define STATUS_SINGLE_STEP ((DWORD )0x80000004L)
+#define STATUS_LONGJUMP ((DWORD )0x80000026L)
+#define STATUS_UNWIND_CONSOLIDATE ((DWORD )0x80000029L)
+#define STATUS_ACCESS_VIOLATION ((DWORD )0xC0000005L)
+#define STATUS_IN_PAGE_ERROR ((DWORD )0xC0000006L)
+#define STATUS_INVALID_HANDLE ((DWORD )0xC0000008L)
+#define STATUS_NO_MEMORY ((DWORD )0xC0000017L)
+#define STATUS_ILLEGAL_INSTRUCTION ((DWORD )0xC000001DL)
+#define STATUS_NONCONTINUABLE_EXCEPTION ((DWORD )0xC0000025L)
+#define STATUS_INVALID_DISPOSITION ((DWORD )0xC0000026L)
+#define STATUS_ARRAY_BOUNDS_EXCEEDED ((DWORD )0xC000008CL)
+#define STATUS_FLOAT_DENORMAL_OPERAND ((DWORD )0xC000008DL)
+#define STATUS_FLOAT_DIVIDE_BY_ZERO ((DWORD )0xC000008EL)
+#define STATUS_FLOAT_INEXACT_RESULT ((DWORD )0xC000008FL)
+#define STATUS_FLOAT_INVALID_OPERATION ((DWORD )0xC0000090L)
+#define STATUS_FLOAT_OVERFLOW ((DWORD )0xC0000091L)
+#define STATUS_FLOAT_STACK_CHECK ((DWORD )0xC0000092L)
+#define STATUS_FLOAT_UNDERFLOW ((DWORD )0xC0000093L)
+#define STATUS_INTEGER_DIVIDE_BY_ZERO ((DWORD )0xC0000094L)
+#define STATUS_INTEGER_OVERFLOW ((DWORD )0xC0000095L)
+#define STATUS_PRIVILEGED_INSTRUCTION ((DWORD )0xC0000096L)
+#define STATUS_STACK_OVERFLOW ((DWORD )0xC00000FDL)
+#define STATUS_CONTROL_C_EXIT ((DWORD )0xC000013AL)
+
+#define WAIT_IO_COMPLETION STATUS_USER_APC
+
+#define EXCEPTION_ACCESS_VIOLATION STATUS_ACCESS_VIOLATION
+#define EXCEPTION_DATATYPE_MISALIGNMENT STATUS_DATATYPE_MISALIGNMENT
+#define EXCEPTION_BREAKPOINT STATUS_BREAKPOINT
+#define EXCEPTION_SINGLE_STEP STATUS_SINGLE_STEP
+#define EXCEPTION_ARRAY_BOUNDS_EXCEEDED STATUS_ARRAY_BOUNDS_EXCEEDED
+#define EXCEPTION_FLT_DENORMAL_OPERAND STATUS_FLOAT_DENORMAL_OPERAND
+#define EXCEPTION_FLT_DIVIDE_BY_ZERO STATUS_FLOAT_DIVIDE_BY_ZERO
+#define EXCEPTION_FLT_INEXACT_RESULT STATUS_FLOAT_INEXACT_RESULT
+#define EXCEPTION_FLT_INVALID_OPERATION STATUS_FLOAT_INVALID_OPERATION
+#define EXCEPTION_FLT_OVERFLOW STATUS_FLOAT_OVERFLOW
+#define EXCEPTION_FLT_STACK_CHECK STATUS_FLOAT_STACK_CHECK
+#define EXCEPTION_FLT_UNDERFLOW STATUS_FLOAT_UNDERFLOW
+#define EXCEPTION_INT_DIVIDE_BY_ZERO STATUS_INTEGER_DIVIDE_BY_ZERO
+#define EXCEPTION_INT_OVERFLOW STATUS_INTEGER_OVERFLOW
+#define EXCEPTION_PRIV_INSTRUCTION STATUS_PRIVILEGED_INSTRUCTION
+#define EXCEPTION_IN_PAGE_ERROR STATUS_IN_PAGE_ERROR
+#define EXCEPTION_ILLEGAL_INSTRUCTION STATUS_ILLEGAL_INSTRUCTION
+#define EXCEPTION_NONCONTINUABLE_EXCEPTION STATUS_NONCONTINUABLE_EXCEPTION
+#define EXCEPTION_STACK_OVERFLOW STATUS_STACK_OVERFLOW
+#define EXCEPTION_INVALID_DISPOSITION STATUS_INVALID_DISPOSITION
+#define EXCEPTION_GUARD_PAGE STATUS_GUARD_PAGE_VIOLATION
+#define EXCEPTION_INVALID_HANDLE STATUS_INVALID_HANDLE
+
+#define CONTROL_C_EXIT STATUS_CONTROL_C_EXIT
+
+/* These are from the <FCNTL.H> file in windows.
+ They are needed for _open_osfhandle.*/
+#define _O_RDONLY 0x0000
+#define _O_APPEND 0x0008
+#define _O_TEXT 0x4000
+#define _O_BINARY 0x8000
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __PAL_H__
diff --git a/src/pal/inc/pal_assert.h b/src/pal/inc/pal_assert.h
new file mode 100644
index 0000000000..67ab24f527
--- /dev/null
+++ b/src/pal/inc/pal_assert.h
@@ -0,0 +1,61 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+
+
+--*/
+
+#ifndef __PAL_ASSERT_H__
+#define __PAL_ASSERT_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+//
+// C_ASSERT() can be used to perform many compile-time assertions:
+// type sizes, field offsets, etc.
+//
+#define C_ASSERT(e) static_assert(e, #e)
+
+//
+// CPP_ASSERT() can be used within a class definition, to perform a
+// compile-time assertion involving private names within the class.
+//
+#define CPP_ASSERT(n, e) static_assert(e, #e)
+
+#endif // __cplusplus
+
+#if defined(_DEBUG)
+#define _ASSERTE(e) do { \
+ if (!(e)) { \
+ fprintf (stderr, \
+ "ASSERT FAILED\n" \
+ "\tExpression: %s\n" \
+ "\tLocation: line %d in %s\n" \
+ "\tFunction: %s\n" \
+ "\tProcess: %d\n", \
+ #e, __LINE__, __FILE__, __FUNCTION__, \
+ GetCurrentProcessId()); \
+ DebugBreak(); \
+ } \
+ }while (0)
+#else // !DEBUG
+#define _ASSERTE(e) ((void)0)
+#endif
+
+#ifndef assert
+#define assert(e) _ASSERTE(e)
+#endif // assert
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __PAL_ASSERT_H__
diff --git a/src/pal/inc/pal_char16.h b/src/pal/inc/pal_char16.h
new file mode 100644
index 0000000000..b118e98e31
--- /dev/null
+++ b/src/pal/inc/pal_char16.h
@@ -0,0 +1,57 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ pal_char16.h
+
+Abstract:
+
+This file is used to define the wchar_t type as a 16-bit type on Unix.
+
+
+
+--*/
+
+// The unix compilers use a 32-bit wchar_t, so we must make a 16 bit wchar_t.
+// The windows compilers, gcc and MSVC, both define a 16 bit wchar_t.
+
+// Note : wchar_t is a built-in type in C++, gcc/llvm ignores any attempts to
+// typedef it. Using the preprocessor here, we make sure gcc sees
+// __wchar_16_cpp__ instead of wchar_t. This is apparently not necessary under
+// vc++, for whom wchar_t is already a typedef instead of a built-in.
+
+#ifndef PAL_STDCPP_COMPAT
+#if defined (PLATFORM_UNIX) && defined(__GNUC__)
+#undef wchar_t
+#undef __WCHAR_TYPE__
+#define __WCHAR_TYPE__ __wchar_16_cpp__
+#define wchar_t __wchar_16_cpp__
+#endif // PLATFORM_UNIX
+
+// Set up the wchar_t type (which got preprocessed to __wchar_16_cpp__).
+// In C++11, the standard gives us char16_t, which is what we want (and matches types with u"")
+// In C, this doesn't exist, so use unsigned short.
+
+#if !defined(_WCHAR_T_DEFINED) || !defined(_MSC_VER)
+#if defined (PLATFORM_UNIX)
+#if defined(__cplusplus)
+#undef __WCHAR_TYPE__
+#define __WCHAR_TYPE__ char16_t
+typedef char16_t wchar_t;
+#else
+#undef __WCHAR_TYPE__
+#define __WCHAR_TYPE__ unsigned short
+typedef unsigned short wchar_t;
+#endif // __cplusplus
+#endif // PLATFORM_UNIX
+#ifndef _WCHAR_T_DEFINED
+#define _WCHAR_T_DEFINED
+#endif // !_WCHAR_T_DEFINED
+#endif // !_WCHAR_T_DEFINED || !_MSC_VER
+#endif // !PAL_STDCPP_COMPAT
diff --git a/src/pal/inc/pal_endian.h b/src/pal/inc/pal_endian.h
new file mode 100644
index 0000000000..50b9e76765
--- /dev/null
+++ b/src/pal/inc/pal_endian.h
@@ -0,0 +1,169 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+
+
+--*/
+
+#ifndef __PAL_ENDIAN_H__
+#define __PAL_ENDIAN_H__
+
+#ifdef __cplusplus
+extern "C++" {
+inline UINT16 SWAP16(UINT16 x)
+{
+ return (x >> 8) | (x << 8);
+}
+
+inline UINT32 SWAP32(UINT32 x)
+{
+ return (x >> 24) |
+ ((x >> 8) & 0x0000FF00L) |
+ ((x & 0x0000FF00L) << 8) |
+ (x << 24);
+}
+
+}
+#endif // __cplusplus
+
+#if BIGENDIAN
+#ifdef __cplusplus
+extern "C++" {
+inline UINT16 VAL16(UINT16 x)
+{
+ return SWAP16(x);
+}
+
+inline UINT32 VAL32(UINT32 x)
+{
+ return SWAP32(x);
+}
+
+inline UINT64 VAL64(UINT64 x)
+{
+ return ((UINT64)VAL32(x) << 32) | VAL32(x >> 32);
+}
+
+inline void SwapString(WCHAR *szString)
+{
+ unsigned i;
+ for (i = 0; szString[i] != L'\0'; i++)
+ {
+ szString[i] = VAL16(szString[i]);
+ }
+}
+
+inline void SwapStringLength(WCHAR *szString, ULONG StringLength)
+{
+ unsigned i;
+ for (i = 0; i < StringLength; i++)
+ {
+ szString[i] = VAL16(szString[i]);
+ }
+}
+
+inline void SwapGuid(GUID *pGuid)
+{
+ pGuid->Data1 = VAL32(pGuid->Data1);
+ pGuid->Data2 = VAL16(pGuid->Data2);
+ pGuid->Data3 = VAL16(pGuid->Data3);
+}
+};
+#else // __cplusplus
+/* C Version of VAL functionality. Swap functions omitted for lack of use in C code */
+#define VAL16(x) (((x) >> 8) | ((x) << 8))
+#define VAL32(y) (((y) >> 24) | (((y) >> 8) & 0x0000FF00L) | (((y) & 0x0000FF00L) << 8) | ((y) << 24))
+#define VAL64(z) (((UINT64)VAL32(z) << 32) | VAL32((z) >> 32))
+#endif // __cplusplus
+
+#else // !BIGENDIAN
+
+#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 BIT64
+#define VALPTR(x) VAL64(x)
+#else
+#define VALPTR(x) VAL32(x)
+#endif
+
+#ifdef _ARM_
+#define LOG2_PTRSIZE 2
+#define ALIGN_ACCESS ((1<<LOG2_PTRSIZE)-1)
+#endif
+
+#if defined(ALIGN_ACCESS) && !defined(_MSC_VER)
+#ifdef __cplusplus
+extern "C++" {
+// Get Unaligned values from a potentially unaligned object
+inline UINT16 GET_UNALIGNED_16(const void *pObject)
+{
+ UINT16 temp;
+ memcpy(&temp, pObject, sizeof(temp));
+ return temp;
+}
+inline UINT32 GET_UNALIGNED_32(const void *pObject)
+{
+ UINT32 temp;
+ memcpy(&temp, pObject, sizeof(temp));
+ return temp;
+}
+inline UINT64 GET_UNALIGNED_64(const void *pObject)
+{
+ UINT64 temp;
+ memcpy(&temp, pObject, sizeof(temp));
+ return temp;
+}
+
+// Set Value on an potentially unaligned object
+inline void SET_UNALIGNED_16(void *pObject, UINT16 Value)
+{
+ memcpy(pObject, &Value, sizeof(UINT16));
+}
+inline void SET_UNALIGNED_32(void *pObject, UINT32 Value)
+{
+ memcpy(pObject, &Value, sizeof(UINT32));
+}
+inline void SET_UNALIGNED_64(void *pObject, UINT64 Value)
+{
+ memcpy(pObject, &Value, sizeof(UINT64));
+}
+}
+#endif // __cplusplus
+
+#else // defined(ALIGN_ACCESS) && !defined(_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)
+
+#endif // defined(ALIGN_ACCESS) && !defined(_MSC_VER)
+
+// 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 // __PAL_ENDIAN_H__
diff --git a/src/pal/inc/pal_error.h b/src/pal/inc/pal_error.h
new file mode 100644
index 0000000000..eb35d91419
--- /dev/null
+++ b/src/pal/inc/pal_error.h
@@ -0,0 +1,141 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+
+
+--*/
+
+#ifndef __PAL_ERROR_H__
+#define __PAL_ERROR_H__
+
+/******************* error codes *****************************************/
+/* STARTERRORCODES - do not remove this marker, it is consumed by the palsatellite tool */
+
+#define ERROR_SUCCESS 0L
+#define ERROR_INVALID_FUNCTION 1L
+#define ERROR_FILE_NOT_FOUND 2L
+#define ERROR_PATH_NOT_FOUND 3L
+#define ERROR_TOO_MANY_OPEN_FILES 4L
+#define ERROR_ACCESS_DENIED 5L
+#define ERROR_INVALID_HANDLE 6L
+#define ERROR_NOT_ENOUGH_MEMORY 8L
+#define ERROR_BAD_ENVIRONMENT 10L
+#define ERROR_BAD_FORMAT 11L
+#define ERROR_INVALID_ACCESS 12L
+#define ERROR_INVALID_DATA 13L
+#define ERROR_OUTOFMEMORY 14L
+#define ERROR_INVALID_DRIVE 15L
+#define ERROR_NO_MORE_FILES 18L
+#define ERROR_WRITE_PROTECT 19L
+#define ERROR_NOT_READY 21L
+#define ERROR_BAD_COMMAND 22L
+
+#define ERROR_BAD_LENGTH 24L
+#define ERROR_WRITE_FAULT 29L
+#define ERROR_READ_FAULT 30L
+#define ERROR_GEN_FAILURE 31L
+#define ERROR_SHARING_VIOLATION 32L
+#define ERROR_LOCK_VIOLATION 33L
+#define ERROR_SHARING_BUFFER_EXCEEDED 36L
+#define ERROR_HANDLE_EOF 38L
+#define ERROR_HANDLE_DISK_FULL 39L
+#define ERROR_NOT_SUPPORTED 50L
+#define ERROR_DUP_NAME 52L
+#define ERROR_BAD_NETPATH 53L
+#define ERROR_DEV_NOT_EXIST 55L
+#define ERROR_BAD_NET_NAME 67L
+#define ERROR_FILE_EXISTS 80L
+#define ERROR_CANNOT_MAKE 82L
+#define ERROR_INVALID_PARAMETER 87L
+#define ERROR_NET_WRITE_FAULT 88L
+#define ERROR_TOO_MANY_SEMAPHORES 100L
+#define ERROR_DRIVE_LOCKED 108L
+#define ERROR_BROKEN_PIPE 109L
+#define ERROR_OPEN_FAILED 110L
+#define ERROR_BUFFER_OVERFLOW 111L
+#define ERROR_DISK_FULL 112L
+#define ERROR_CALL_NOT_IMPLEMENTED 120L
+#define ERROR_SEM_TIMEOUT 121L
+#define ERROR_INSUFFICIENT_BUFFER 122L
+#define ERROR_INVALID_NAME 123L
+#define ERROR_MOD_NOT_FOUND 126L
+#define ERROR_PROC_NOT_FOUND 127L
+#define ERROR_WAIT_NO_CHILDREN 128L
+#define ERROR_NEGATIVE_SEEK 131L
+#define ERROR_SEEK_ON_DEVICE 132L
+#define ERROR_DIR_NOT_EMPTY 145L
+#define ERROR_SIGNAL_REFUSED 156L
+#define ERROR_NOT_LOCKED 158L
+#define ERROR_BAD_PATHNAME 161L
+#define ERROR_BUSY 170L
+
+#define ERROR_INVALID_ORDINAL 182L
+#define ERROR_ALREADY_EXISTS 183L
+#define ERROR_INVALID_EXE_SIGNATURE 191L
+#define ERROR_EXE_MARKED_INVALID 192L
+#define ERROR_BAD_EXE_FORMAT 193L
+#define ERROR_ENVVAR_NOT_FOUND 203L
+#define ERROR_FILENAME_EXCED_RANGE 206L
+#define ERROR_PIPE_BUSY 231L
+#define ERROR_NO_DATA 232L
+#define ERROR_MORE_DATA 234L
+#define ERROR_NO_MORE_ITEMS 259L
+#define ERROR_DIRECTORY 267L
+#define ERROR_NOT_OWNER 288L
+#define ERROR_PARTIAL_COPY 299L
+#define ERROR_INVALID_ADDRESS 487L
+#define ERROR_ARITHMETIC_OVERFLOW 534L
+#define ERROR_OPERATION_ABORTED 995L
+#define ERROR_IO_INCOMPLETE 996L
+#define ERROR_IO_PENDING 997L
+#define ERROR_NOACCESS 998L
+#define ERROR_STACK_OVERFLOW 1001L
+#define ERROR_INVALID_FLAGS 1004L
+#define ERROR_UNRECOGNIZED_VOLUME 1005L
+#define ERROR_FILE_INVALID 1006L
+#define ERROR_PROCESS_ABORTED 1067L
+#define ERROR_NO_UNICODE_TRANSLATION 1113L
+#define ERROR_DLL_INIT_FAILED 1114L
+#define ERROR_IO_DEVICE 1117L
+#define ERROR_DISK_OPERATION_FAILED 1127L
+#define ERROR_POSSIBLE_DEADLOCK 1131L
+#define ERROR_TOO_MANY_LINKS 1142L
+
+#define ERROR_INVALID_DLL 1154L
+#define ERROR_DLL_NOT_FOUND 1157L
+#define ERROR_NOT_FOUND 1168L
+#define ERROR_CANCELLED 1223L
+#define ERROR_NOT_AUTHENTICATED 1244L
+
+#define ERROR_INTERNAL_ERROR 1359L
+#define ERROR_FILE_CORRUPT 1392L
+#define ERROR_DISK_CORRUPT 1393L
+#define ERROR_WRONG_TARGET_NAME 1396L
+#define ERROR_NO_SYSTEM_RESOURCES 1450L
+#define ERROR_COMMITMENT_LIMIT 1455L
+#define ERROR_TIMEOUT 1460L
+#define ERROR_EVENTLOG_FILE_CORRUPT 1500L
+#define ERROR_LOG_FILE_FULL 1502L
+#define ERROR_UNSUPPORTED_TYPE 1630L
+
+#define RPC_S_INVALID_VERS_OPTION 1756L
+
+#define ERROR_RESOURCE_DATA_NOT_FOUND 1812L
+#define ERROR_RESOURCE_LANG_NOT_FOUND 1815L
+#define ERROR_TAG_NOT_PRESENT 2013L
+
+#define CRYPT_E_NO_MATCH 0x80092009
+
+/* ENDERRORCODES - do not remove this marker, it is consumed by the palsatellite tool */
+
+/******************* error code aliases **************************************/
+
+#define NOERROR 0
+#define NO_ERROR 0L
+
+#endif // __PAL_ERROR_H__
diff --git a/src/pal/inc/pal_mstypes.h b/src/pal/inc/pal_mstypes.h
new file mode 100644
index 0000000000..df17767747
--- /dev/null
+++ b/src/pal/inc/pal_mstypes.h
@@ -0,0 +1,732 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+
+
+--*/
+
+////////////////////////////////////////////////////////////////////////
+// Extensions to the usual posix header files
+////////////////////////////////////////////////////////////////////////
+
+#ifndef __PAL_MSTYPES_H__
+#define __PAL_MSTYPES_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+////////////////////////////////////////////////////////////////////////
+// calling convention stuff
+////////////////////////////////////////////////////////////////////////
+
+
+#ifdef __cplusplus
+#define EXTERN_C extern "C"
+#else
+#define EXTERN_C
+#endif // __cplusplus
+
+#ifndef _MSC_VER
+
+// Note: Win32-hosted GCC predefines __stdcall and __cdecl, but Unix-
+// hosted GCC does not.
+
+#ifdef __i386__
+
+#if !defined(__stdcall)
+#define __stdcall __attribute__((stdcall))
+#endif
+#if !defined(_stdcall)
+#define _stdcall __stdcall
+#endif
+
+#if !defined(__cdecl)
+#define __cdecl __attribute__((cdecl))
+#endif
+#if !defined(_cdecl)
+#define _cdecl __cdecl
+#endif
+#if !defined(CDECL)
+#define CDECL __cdecl
+#endif
+
+#ifndef PAL_STDCPP_COMPAT
+#undef __fastcall
+#define __fastcall __stdcall
+#undef _fastcall
+#define _fastcall __fastcall
+#endif // PAL_STDCPP_COMPAT
+
+#else // !defined(__i386__)
+
+#define __stdcall
+#define _stdcall
+#define __cdecl
+#define _cdecl
+#define CDECL
+
+// On ARM __fastcall is ignored and causes a compile error
+#if !defined(PAL_STDCPP_COMPAT) || defined(__arm__)
+# undef __fastcall
+# undef _fastcall
+# define __fastcall
+# define _fastcall
+#endif // !defined(PAL_STDCPP_COMPAT) || defined(__arm__)
+
+#endif // !defined(__i386__)
+
+#define CALLBACK __stdcall
+
+#if !defined(_declspec)
+#define _declspec(e) __declspec(e)
+#endif
+
+#if defined(_VAC_) && defined(__cplusplus)
+#define __inline inline
+#endif
+
+#define __forceinline inline
+
+#endif // !_MSC_VER
+
+#ifdef _MSC_VER
+
+#if defined(PAL_IMPLEMENTATION)
+#define PALIMPORT
+#else
+#define PALIMPORT __declspec(dllimport)
+#endif
+#define PAL_NORETURN __declspec(noreturn)
+
+#else
+
+#define PALIMPORT
+#define PAL_NORETURN __attribute__((noreturn))
+
+#endif
+
+#define PALAPI __stdcall
+#define PALAPIV __cdecl
+
+////////////////////////////////////////////////////////////////////////
+// Type attribute stuff
+////////////////////////////////////////////////////////////////////////
+
+#define CONST const
+#define IN
+#define OUT
+#define OPTIONAL
+#define FAR
+
+#ifdef UNICODE
+#define __TEXT(x) L##x
+#else
+#define __TEXT(x) x
+#endif
+#define TEXT(x) __TEXT(x)
+
+////////////////////////////////////////////////////////////////////////
+// Some special values
+////////////////////////////////////////////////////////////////////////
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+////////////////////////////////////////////////////////////////////////
+// Misc. type helpers
+////////////////////////////////////////////////////////////////////////
+
+#ifdef _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.
+#define I64_HELPER(x) x ## i64
+#define I64(x) I64_HELPER(x)
+
+#define UI64_HELPER(x) x ## ui64
+#define UI64(x) UI64_HELPER(x)
+
+#else // _MSC_VER
+
+// 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.
+#define I64_HELPER(x) x ## LL
+#define I64(x) I64_HELPER(x)
+
+#define UI64_HELPER(x) x ## ULL
+#define UI64(x) UI64_HELPER(x)
+
+#endif // _MSC_VER
+
+////////////////////////////////////////////////////////////////////////
+// Misc. types
+////////////////////////////////////////////////////////////////////////
+
+#ifndef _MSC_VER
+
+// A bunch of source files (e.g. most of the ndp tree) include pal.h
+// but are written to be LLP64, not LP64. (LP64 => long = 64 bits
+// LLP64 => longs = 32 bits, long long = 64 bits)
+//
+// To handle this difference, we #define long to be int (and thus 32 bits) when
+// compiling those files. (See the bottom of this file or search for
+// #define long to see where we do this.)
+//
+// But this fix is more complicated than it seems, because we also use the
+// preprocessor to #define __int64 to long for LP64 architectures (__int64
+// isn't a builtin in gcc). We don't want __int64 to be an int (by cascading
+// macro rules). So we play this little trick below where we add
+// __cppmungestrip before "long", which is what we're really #defining __int64
+// to. The preprocessor sees __cppmungestriplong as something different than
+// long, so it doesn't replace it with int. The during the cppmunge phase, we
+// remove the __cppmungestrip part, leaving long for the compiler to see.
+//
+// Note that we can't just use a typedef to define __int64 as long before
+// #defining long because typedefed types can't be signedness-agnostic (i.e.
+// they must be either signed or unsigned) and we want to be able to use
+// __int64 as though it were intrinsic
+
+#ifdef BIT64
+#define __int64 long
+#else // BIT64
+#define __int64 long long
+#endif // BIT64
+
+#define __int32 int
+#define __int16 short int
+#define __int8 char // assumes char is signed
+
+#endif // _MSC_VER
+
+#ifndef PAL_STDCPP_COMPAT
+// Defined in gnu's types.h. For non PAL_IMPLEMENTATION system
+// includes are not included, so we need to define them.
+#ifndef PAL_IMPLEMENTATION
+typedef __int64 int64_t;
+typedef unsigned __int64 uint64_t;
+typedef __int32 int32_t;
+typedef unsigned __int32 uint32_t;
+typedef __int16 int16_t;
+typedef unsigned __int16 uint16_t;
+typedef __int8 int8_t;
+typedef unsigned __int8 uint8_t;
+#endif // PAL_IMPLEMENTATION
+
+#ifndef _MSC_VER
+
+#if _WIN64
+typedef long double LONG_DOUBLE;
+#endif
+
+#endif // _MSC_VER
+#endif // !PAL_STDCPP_COMPAT
+
+typedef void VOID;
+
+#ifndef PLATFORM_UNIX
+typedef long LONG;
+typedef unsigned long ULONG;
+#else
+typedef int LONG; // NOTE: diff from windows.h, for LP64 compat
+typedef unsigned int ULONG; // NOTE: diff from windows.h, for LP64 compat
+#endif
+
+typedef __int64 LONGLONG;
+typedef unsigned __int64 ULONGLONG;
+typedef ULONGLONG DWORD64;
+typedef DWORD64 *PDWORD64;
+typedef LONGLONG *PLONG64;
+typedef ULONGLONG *PULONG64;
+typedef ULONGLONG *PULONGLONG;
+typedef ULONG *PULONG;
+typedef short SHORT;
+typedef SHORT *PSHORT;
+typedef unsigned short USHORT;
+typedef USHORT *PUSHORT;
+typedef unsigned char UCHAR;
+typedef UCHAR *PUCHAR;
+typedef char *PSZ;
+typedef ULONGLONG DWORDLONG;
+
+#ifndef PLATFORM_UNIX
+typedef unsigned long DWORD;
+#else
+typedef unsigned int DWORD; // NOTE: diff from windows.h, for LP64 compat
+#endif
+
+typedef unsigned int DWORD32, *PDWORD32;
+
+typedef int BOOL;
+typedef unsigned char BYTE;
+typedef unsigned short WORD;
+typedef float FLOAT;
+typedef double DOUBLE;
+typedef BOOL *PBOOL;
+typedef BOOL *LPBOOL;
+typedef BYTE *PBYTE;
+typedef BYTE *LPBYTE;
+typedef const BYTE *LPCBYTE;
+typedef int *PINT;
+typedef int *LPINT;
+typedef WORD *PWORD;
+typedef WORD *LPWORD;
+typedef LONG *LPLONG;
+typedef LPLONG PLONG;
+typedef DWORD *PDWORD;
+typedef DWORD *LPDWORD;
+typedef void *PVOID;
+typedef void *LPVOID;
+typedef CONST void *LPCVOID;
+typedef int INT;
+typedef unsigned int UINT;
+typedef unsigned int *PUINT;
+typedef BYTE BOOLEAN;
+typedef BOOLEAN *PBOOLEAN;
+
+typedef unsigned __int8 UINT8;
+typedef signed __int8 INT8;
+typedef unsigned __int16 UINT16;
+typedef signed __int16 INT16;
+typedef unsigned __int32 UINT32, *PUINT32;
+typedef signed __int32 INT32, *PINT32;
+typedef unsigned __int64 UINT64, *PUINT64;
+typedef signed __int64 INT64, *PINT64;
+
+typedef unsigned __int32 ULONG32, *PULONG32;
+typedef signed __int32 LONG32, *PLONG32;
+typedef unsigned __int64 ULONG64;
+typedef signed __int64 LONG64;
+
+#if defined(_X86_) && _MSC_VER >= 1300
+#define _W64 __w64
+#else
+#define _W64
+#endif
+
+#ifdef BIT64
+
+#define _atoi64 (__int64)atoll
+
+typedef __int64 INT_PTR, *PINT_PTR;
+typedef unsigned __int64 UINT_PTR, *PUINT_PTR;
+typedef __int64 LONG_PTR, *PLONG_PTR;
+typedef unsigned __int64 ULONG_PTR, *PULONG_PTR;
+typedef unsigned __int64 DWORD_PTR, *PDWORD_PTR;
+
+/* maximum signed 64 bit value */
+#define LONG_PTR_MAX I64(9223372036854775807)
+/* maximum unsigned 64 bit value */
+#define ULONG_PTR_MAX UI64(0xffffffffffffffff)
+
+#ifndef SIZE_MAX
+#define SIZE_MAX _UI64_MAX
+#endif
+
+#define __int3264 __int64
+
+#if !defined(BIT64)
+__inline
+unsigned long
+HandleToULong(
+ const void *h
+ )
+{
+ return((unsigned long) (ULONG_PTR) h );
+}
+
+__inline
+long
+HandleToLong(
+ const void *h
+ )
+{
+ return((long) (LONG_PTR) h );
+}
+
+__inline
+void *
+ULongToHandle(
+ const unsigned long h
+ )
+{
+ return((void *) (UINT_PTR) h );
+}
+
+
+__inline
+void *
+LongToHandle(
+ const long h
+ )
+{
+ return((void *) (INT_PTR) h );
+}
+
+
+__inline
+unsigned long
+PtrToUlong(
+ const void *p
+ )
+{
+ return((unsigned long) (ULONG_PTR) p );
+}
+
+__inline
+unsigned int
+PtrToUint(
+ const void *p
+ )
+{
+ return((unsigned int) (UINT_PTR) p );
+}
+
+__inline
+unsigned short
+PtrToUshort(
+ const void *p
+ )
+{
+ return((unsigned short) (unsigned long) (ULONG_PTR) p );
+}
+
+__inline
+long
+PtrToLong(
+ const void *p
+ )
+{
+ return((long) (LONG_PTR) p );
+}
+
+__inline
+int
+PtrToInt(
+ const void *p
+ )
+{
+ return((int) (INT_PTR) p );
+}
+
+__inline
+short
+PtrToShort(
+ const void *p
+ )
+{
+ return((short) (long) (LONG_PTR) p );
+}
+
+__inline
+void *
+IntToPtr(
+ const int i
+ )
+// Caution: IntToPtr() sign-extends the int value.
+{
+ return( (void *)(INT_PTR)i );
+}
+
+__inline
+void *
+UIntToPtr(
+ const unsigned int ui
+ )
+// Caution: UIntToPtr() zero-extends the unsigned int value.
+{
+ return( (void *)(UINT_PTR)ui );
+}
+
+__inline
+void *
+LongToPtr(
+ const long l
+ )
+// Caution: LongToPtr() sign-extends the long value.
+{
+ return( (void *)(LONG_PTR)l );
+}
+
+__inline
+void *
+ULongToPtr(
+ const unsigned long ul
+ )
+// Caution: ULongToPtr() zero-extends the unsigned long value.
+{
+ return( (void *)(ULONG_PTR)ul );
+}
+
+__inline
+void *
+ShortToPtr(
+ const short s
+ )
+// Caution: ShortToPtr() sign-extends the short value.
+{
+ return( (void *)(INT_PTR)s );
+}
+
+__inline
+void *
+UShortToPtr(
+ const unsigned short us
+ )
+// Caution: UShortToPtr() zero-extends the unsigned short value.
+{
+ return( (void *)(UINT_PTR)us );
+}
+
+#else // !defined(BIT64)
+#define HandleToULong( h ) ((ULONG)(ULONG_PTR)(h) )
+#define HandleToLong( h ) ((LONG)(LONG_PTR) (h) )
+#define ULongToHandle( ul ) ((HANDLE)(ULONG_PTR) (ul) )
+#define LongToHandle( h ) ((HANDLE)(LONG_PTR) (h) )
+#define PtrToUlong( p ) ((ULONG)(ULONG_PTR) (p) )
+#define PtrToLong( p ) ((LONG)(LONG_PTR) (p) )
+#define PtrToUint( p ) ((UINT)(UINT_PTR) (p) )
+#define PtrToInt( p ) ((INT)(INT_PTR) (p) )
+#define PtrToUshort( p ) ((unsigned short)(ULONG_PTR)(p) )
+#define PtrToShort( p ) ((short)(LONG_PTR)(p) )
+#define IntToPtr( i ) ((VOID *)(INT_PTR)((int)(i)))
+#define UIntToPtr( ui ) ((VOID *)(UINT_PTR)((unsigned int)(ui)))
+#define LongToPtr( l ) ((VOID *)(LONG_PTR)((long)(l)))
+#define ULongToPtr( ul ) ((VOID *)(ULONG_PTR)((unsigned long)(ul)))
+#define ShortToPtr( s ) ((VOID *)(INT_PTR)((short)(s)))
+#define UShortToPtr( us ) ((VOID *)(UINT_PTR)((unsigned short)(s)))
+#endif // !defined(BIT64)
+
+
+
+#else
+
+typedef _W64 __int32 INT_PTR;
+typedef _W64 unsigned __int32 UINT_PTR;
+
+typedef _W64 __int32 LONG_PTR;
+typedef _W64 unsigned __int32 ULONG_PTR, *PULONG_PTR;
+typedef _W64 unsigned __int32 DWORD_PTR, *PDWORD_PTR;
+
+/* maximum signed 32 bit value */
+#define LONG_PTR_MAX 2147483647L
+/* maximum unsigned 32 bit value */
+#define ULONG_PTR_MAX 0xffffffffUL
+
+#ifndef SIZE_MAX
+#define SIZE_MAX UINT_MAX
+#endif
+
+#define __int3264 __int32
+
+#define HandleToULong( h ) ((ULONG)(ULONG_PTR)(h) )
+#define HandleToLong( h ) ((LONG)(LONG_PTR) (h) )
+#define ULongToHandle( ul ) ((HANDLE)(ULONG_PTR) (ul) )
+#define LongToHandle( h ) ((HANDLE)(LONG_PTR) (h) )
+#define PtrToUlong( p ) ((ULONG)(ULONG_PTR) (p) )
+#define PtrToLong( p ) ((LONG)(LONG_PTR) (p) )
+#define PtrToUint( p ) ((UINT)(UINT_PTR) (p) )
+#define PtrToInt( p ) ((INT)(INT_PTR) (p) )
+#define PtrToUshort( p ) ((unsigned short)(ULONG_PTR)(p) )
+#define PtrToShort( p ) ((short)(LONG_PTR)(p) )
+#define IntToPtr( i ) ((VOID *)(INT_PTR)((int)i))
+#define UIntToPtr( ui ) ((VOID *)(UINT_PTR)((unsigned int)ui))
+#define LongToPtr( l ) ((VOID *)(LONG_PTR)((long)l))
+#define ULongToPtr( ul ) ((VOID *)(ULONG_PTR)((unsigned long)ul))
+#define ShortToPtr( s ) ((VOID *)(INT_PTR)((short)s))
+#define UShortToPtr( us ) ((VOID *)(UINT_PTR)((unsigned short)s))
+
+#endif
+
+#define HandleToUlong(h) HandleToULong(h)
+#define UlongToHandle(ul) ULongToHandle(ul)
+#define UlongToPtr(ul) ULongToPtr(ul)
+#define UintToPtr(ui) UIntToPtr(ui)
+
+typedef ULONG_PTR SIZE_T, *PSIZE_T;
+typedef LONG_PTR SSIZE_T, *PSSIZE_T;
+
+#ifndef SIZE_T_MAX
+#define SIZE_T_MAX ULONG_PTR_MAX
+#endif // SIZE_T_MAX
+
+#ifndef SSIZE_T_MAX
+#define SSIZE_T_MAX LONG_PTR_MAX
+#endif
+
+#ifndef SSIZE_T_MIN
+#define SSIZE_T_MIN I64(-9223372036854775808)
+#endif
+
+#ifndef PAL_STDCPP_COMPAT
+#if defined(__APPLE_CC__) || defined(__linux__)
+#ifdef BIT64
+typedef unsigned long size_t;
+typedef long ptrdiff_t;
+#else // !BIT64
+typedef unsigned int size_t;
+typedef int ptrdiff_t;
+#endif // !BIT64
+#else
+typedef ULONG_PTR size_t;
+typedef LONG_PTR ptrdiff_t;
+#endif
+#endif // !PAL_STDCPP_COMPAT
+#define _SIZE_T_DEFINED
+
+typedef LONG_PTR LPARAM;
+
+#define _PTRDIFF_T_DEFINED
+#ifdef _MINGW_
+// We need to define _PTRDIFF_T to make sure ptrdiff_t doesn't get defined
+// again by system headers - but only for MinGW.
+#define _PTRDIFF_T
+#endif
+
+#ifdef PAL_STDCPP_COMPAT
+
+#ifdef BIT64
+typedef unsigned long int uintptr_t;
+#else // !BIT64
+typedef unsigned int uintptr_t;
+#endif // !BIT64
+
+typedef char16_t WCHAR;
+
+#else // PAL_STDCPP_COMPAT
+
+typedef wchar_t WCHAR;
+#if defined(__linux__)
+#ifdef BIT64
+typedef long int intptr_t;
+typedef unsigned long int uintptr_t;
+#else // !BIT64
+typedef int intptr_t;
+typedef unsigned int uintptr_t;
+#endif // !BIT64
+#else
+typedef INT_PTR intptr_t;
+typedef UINT_PTR uintptr_t;
+#endif
+
+#endif // PAL_STDCPP_COMPAT
+
+#define _INTPTR_T_DEFINED
+#define _UINTPTR_T_DEFINED
+
+typedef DWORD LCID;
+typedef PDWORD PLCID;
+typedef WORD LANGID;
+
+typedef DWORD LCTYPE;
+
+typedef WCHAR *PWCHAR;
+typedef WCHAR *LPWCH, *PWCH;
+typedef CONST WCHAR *LPCWCH, *PCWCH;
+typedef WCHAR *NWPSTR;
+typedef WCHAR *LPWSTR, *PWSTR;
+
+typedef CONST WCHAR *LPCWSTR, *PCWSTR;
+
+typedef char CHAR;
+typedef CHAR *PCHAR;
+typedef CHAR *LPCH, *PCH;
+typedef CONST CHAR *LPCCH, *PCCH;
+typedef CHAR *NPSTR;
+typedef CHAR *LPSTR, *PSTR;
+typedef CONST CHAR *LPCSTR, *PCSTR;
+
+#ifdef UNICODE
+typedef WCHAR TCHAR;
+typedef WCHAR _TCHAR;
+#else
+typedef CHAR TCHAR;
+typedef CHAR _TCHAR;
+#endif
+typedef TCHAR *PTCHAR;
+typedef TCHAR *LPTSTR, *PTSTR;
+typedef CONST TCHAR *LPCTSTR;
+
+#define MAKEWORD(a, b) ((WORD)(((BYTE)((DWORD_PTR)(a) & 0xff)) | ((WORD)((BYTE)((DWORD_PTR)(b) & 0xff))) << 8))
+#define MAKELONG(a, b) ((LONG)(((WORD)((DWORD_PTR)(a) & 0xffff)) | ((DWORD)((WORD)((DWORD_PTR)(b) & 0xffff))) << 16))
+#define LOWORD(l) ((WORD)((DWORD_PTR)(l) & 0xffff))
+#define HIWORD(l) ((WORD)((DWORD_PTR)(l) >> 16))
+#define LOBYTE(w) ((BYTE)((DWORD_PTR)(w) & 0xff))
+#define HIBYTE(w) ((BYTE)((DWORD_PTR)(w) >> 8))
+
+typedef VOID *HANDLE;
+typedef HANDLE HWND;
+typedef struct __PAL_RemoteHandle__ { HANDLE h; } *RHANDLE;
+typedef HANDLE *PHANDLE;
+typedef HANDLE *LPHANDLE;
+#define INVALID_HANDLE_VALUE ((VOID *)(-1))
+#define INVALID_FILE_SIZE ((DWORD)0xFFFFFFFF)
+#define INVALID_FILE_ATTRIBUTES ((DWORD) -1)
+typedef HANDLE HMODULE;
+typedef HANDLE HINSTANCE;
+typedef HANDLE HGLOBAL;
+typedef HANDLE HLOCAL;
+typedef HANDLE HRSRC;
+
+typedef LONG HRESULT;
+typedef LONG NTSTATUS;
+
+typedef union _LARGE_INTEGER {
+ struct {
+#if BIGENDIAN
+ LONG HighPart;
+ DWORD LowPart;
+#else
+ DWORD LowPart;
+ LONG HighPart;
+#endif
+ } u;
+ LONGLONG QuadPart;
+} LARGE_INTEGER, *PLARGE_INTEGER;
+
+#ifndef GUID_DEFINED
+typedef struct _GUID {
+ ULONG Data1; // NOTE: diff from Win32, for LP64
+ USHORT Data2;
+ USHORT Data3;
+ UCHAR Data4[ 8 ];
+} GUID;
+typedef const GUID *LPCGUID;
+#define GUID_DEFINED
+#endif // !GUID_DEFINED
+
+typedef struct _FILETIME {
+ DWORD dwLowDateTime;
+ DWORD dwHighDateTime;
+} FILETIME, *PFILETIME, *LPFILETIME;
+
+/* Code Page Default Values */
+#define CP_ACP 0 /* default to ANSI code page */
+#define CP_OEMCP 1 /* default to OEM code page */
+#define CP_MACCP 2 /* default to MAC code page */
+#define CP_THREAD_ACP 3 /* current thread's ANSI code page */
+#define CP_WINUNICODE 1200
+#define CP_UNICODE 1200 /* Unicode */
+#define CP_UNICODESWAP 1201 /* Unicode Big-Endian */
+#define CP_UTF7 65000 /* UTF-7 translation */
+#define CP_UTF8 65001 /* UTF-8 translation */
+
+typedef PVOID PSID;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __PAL_MSTYPES_H__
diff --git a/src/pal/inc/pal_safecrt.h b/src/pal/inc/pal_safecrt.h
new file mode 100644
index 0000000000..d9e76cd783
--- /dev/null
+++ b/src/pal/inc/pal_safecrt.h
@@ -0,0 +1,55 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ pal_safecrt.h
+
+Abstract:
+
+Wrapper for including SafeCRT for Mac build of CoreCLR
+
+
+
+--*/
+
+#ifndef _PAL_SAFECRT_H_
+#define _PAL_SAFECRT_H_
+
+#define _CRT_ALTERNATIVE_INLINES
+#define _SAFECRT_NO_INCLUDES 1
+
+#if !defined (_SAFECRT_USE_INLINES)
+#define _SAFECRT_USE_INLINES 0
+#endif
+
+#if !defined (_SAFECRT_IMPL)
+#define _SAFECRT_IMPL 0
+#endif
+
+#define _SAFECRT_SET_ERRNO 0
+#define _SAFECRT_DEFINE_MBS_FUNCTIONS 0
+#define _SAFECRT_DEFINE_TCS_MACROS 1
+//#define _SAFECRT_INVALID_PARAMETER(message) WARN(message "\n")
+
+#if defined (SAFECRT_IN_PAL)
+
+#define DUMMY_memset void * __cdecl memset(void *, int, size_t);
+
+#endif
+
+// Include the safecrt implementation
+#include "../../palrt/inc/safecrt.h"
+
+#if defined(SAFECRT_IN_PAL)
+
+#define DUMMY_memset
+
+#endif
+
+#endif // _PAL_SAFECRT_H_
diff --git a/src/pal/inc/pal_unwind.h b/src/pal/inc/pal_unwind.h
new file mode 100644
index 0000000000..2931488e3b
--- /dev/null
+++ b/src/pal/inc/pal_unwind.h
@@ -0,0 +1,91 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+//
+// Definition of the Unwind API functions.
+// Taken from the ABI documentation.
+//
+
+
+
+#ifndef __PAL_UNWIND_H__
+#define __PAL_UNWIND_H__
+
+#if FEATURE_PAL_SXS
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif // __cplusplus
+
+ //
+ // Exception Handling ABI Level I: Base ABI
+ //
+
+ typedef enum
+ {
+ _URC_NO_REASON = 0,
+ _URC_FOREIGN_EXCEPTION_CAUGHT = 1,
+ _URC_FATAL_PHASE2_ERROR = 2,
+ _URC_FATAL_PHASE1_ERROR = 3,
+ _URC_NORMAL_STOP = 4,
+ _URC_END_OF_STACK = 5,
+ _URC_HANDLER_FOUND = 6,
+ _URC_INSTALL_CONTEXT = 7,
+ _URC_CONTINUE_UNWIND = 8,
+ } _Unwind_Reason_Code;
+
+ typedef enum
+ {
+ _UA_SEARCH_PHASE = 1,
+ _UA_CLEANUP_PHASE = 2,
+ _UA_HANDLER_FRAME = 4,
+ _UA_FORCE_UNWIND = 8,
+ } _Unwind_Action;
+ #define _UA_PHASE_MASK (_UA_SEARCH_PHASE|_UA_CLEANUP_PHASE)
+
+ struct _Unwind_Context;
+
+ void *_Unwind_GetIP(struct _Unwind_Context *context);
+ void _Unwind_SetIP(struct _Unwind_Context *context, void *new_value);
+ void *_Unwind_GetCFA(struct _Unwind_Context *context);
+ void *_Unwind_GetGR(struct _Unwind_Context *context, int index);
+ void _Unwind_SetGR(struct _Unwind_Context *context, int index, void *new_value);
+
+ struct _Unwind_Exception;
+
+ typedef void (*_Unwind_Exception_Cleanup_Fn)(
+ _Unwind_Reason_Code urc,
+ struct _Unwind_Exception *exception_object);
+
+ struct _Unwind_Exception
+ {
+ ULONG64 exception_class;
+ _Unwind_Exception_Cleanup_Fn exception_cleanup;
+ UINT_PTR private_1;
+ UINT_PTR private_2;
+ } __attribute__((aligned));
+
+ void _Unwind_DeleteException(struct _Unwind_Exception *exception_object);
+
+ typedef _Unwind_Reason_Code (*_Unwind_Trace_Fn)(struct _Unwind_Context *context, void *pvParam);
+ _Unwind_Reason_Code _Unwind_Backtrace(_Unwind_Trace_Fn pfnTrace, void *pvParam);
+
+ _Unwind_Reason_Code _Unwind_RaiseException(struct _Unwind_Exception *exception_object);
+ __attribute__((noreturn)) void _Unwind_Resume(struct _Unwind_Exception *exception_object);
+
+ //
+ // Exception Handling ABI Level II: C++ ABI
+ //
+
+ void *__cxa_begin_catch(void *exceptionObject);
+ void __cxa_end_catch();
+
+#ifdef __cplusplus
+};
+#endif // __cplusplus
+
+#endif // FEATURE_PAL_SXS
+
+#endif // __PAL_UNWIND_H__
diff --git a/src/pal/inc/palprivate.h b/src/pal/inc/palprivate.h
new file mode 100644
index 0000000000..2677dd6bdd
--- /dev/null
+++ b/src/pal/inc/palprivate.h
@@ -0,0 +1,316 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#ifndef __PAL_PRIVATE_H__
+#define __PAL_PRIVATE_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+PALIMPORT
+int
+PALAPI
+MessageBoxA(
+ IN LPVOID hWnd, // NOTE: diff from winuser.h
+ IN LPCSTR lpText,
+ IN LPCSTR lpCaption,
+ IN UINT uType);
+
+
+PALIMPORT
+HANDLE
+PALAPI
+CreateFileA(
+ IN LPCSTR lpFileName,
+ IN DWORD dwDesiredAccess,
+ IN DWORD dwShareMode,
+ IN LPSECURITY_ATTRIBUTES lpSecurityAttributes,
+ IN DWORD dwCreationDisposition,
+ IN DWORD dwFlagsAndAttributes,
+ IN HANDLE hTemplateFile);
+
+PALIMPORT
+DWORD
+PALAPI
+SearchPathA(
+ IN LPCSTR lpPath,
+ IN LPCSTR lpFileName,
+ IN LPCSTR lpExtension,
+ IN DWORD nBufferLength,
+ OUT LPSTR lpBuffer,
+ OUT LPSTR *lpFilePart
+ );
+
+PALIMPORT
+BOOL
+PALAPI
+CopyFileA(
+ IN LPCSTR lpExistingFileName,
+ IN LPCSTR lpNewFileName,
+ IN BOOL bFailIfExists);
+
+
+PALIMPORT
+BOOL
+PALAPI
+DeleteFileA(
+ IN LPCSTR lpFileName);
+
+PALIMPORT
+BOOL
+PALAPI
+MoveFileA(
+ IN LPCSTR lpExistingFileName,
+ IN LPCSTR lpNewFileName);
+
+PALIMPORT
+BOOL
+PALAPI
+MoveFileExA(
+ IN LPCSTR lpExistingFileName,
+ IN LPCSTR lpNewFileName,
+ IN DWORD dwFlags);
+
+PALIMPORT
+BOOL
+PALAPI
+CreateDirectoryA(
+ IN LPCSTR lpPathName,
+ IN LPSECURITY_ATTRIBUTES lpSecurityAttributes);
+
+PALIMPORT
+HANDLE
+PALAPI
+FindFirstFileA(
+ IN LPCSTR lpFileName,
+ OUT LPWIN32_FIND_DATAA lpFindFileData);
+
+PALIMPORT
+BOOL
+PALAPI
+FindNextFileA(
+ IN HANDLE hFindFile,
+ OUT LPWIN32_FIND_DATAA lpFindFileData);
+
+PALIMPORT
+DWORD
+PALAPI
+GetFileAttributesA(
+ IN LPCSTR lpFileName);
+
+PALIMPORT
+BOOL
+PALAPI
+SetFileAttributesA(
+ IN LPCSTR lpFileName,
+ IN DWORD dwFileAttributes);
+
+PALIMPORT
+DWORD
+PALAPI
+GetFullPathNameA(
+ IN LPCSTR lpFileName,
+ IN DWORD nBufferLength,
+ OUT LPSTR lpBuffer,
+ OUT LPSTR *lpFilePart);
+
+PALIMPORT
+UINT
+PALAPI
+GetTempFileNameA(
+ IN LPCSTR lpPathName,
+ IN LPCSTR lpPrefixString,
+ IN UINT uUnique,
+ OUT LPSTR lpTempFileName);
+
+PALIMPORT
+DWORD
+PALAPI
+GetTempPathA(
+ IN DWORD nBufferLength,
+ OUT LPSTR lpBuffer);
+
+PALIMPORT
+DWORD
+PALAPI
+GetCurrentDirectoryA(
+ IN DWORD nBufferLength,
+ OUT LPSTR lpBuffer);
+
+PALIMPORT
+BOOL
+PALAPI
+SetCurrentDirectoryA(
+ IN LPCSTR lpPathName);
+
+PALIMPORT
+HANDLE
+PALAPI
+CreateSemaphoreA(
+ IN LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,
+ IN LONG lInitialCount,
+ IN LONG lMaximumCount,
+ IN LPCSTR lpName);
+
+PALIMPORT
+HANDLE
+PALAPI
+CreateSemaphoreExA(
+ IN LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,
+ IN LONG lInitialCount,
+ IN LONG lMaximumCount,
+ IN LPCSTR lpName,
+ IN /*_Reserved_*/ DWORD dwFlags,
+ IN DWORD dwDesiredAccess);
+
+PALIMPORT
+HANDLE
+PALAPI
+CreateEventA(
+ IN LPSECURITY_ATTRIBUTES lpEventAttributes,
+ IN BOOL bManualReset,
+ IN BOOL bInitialState,
+ IN LPCSTR lpName);
+
+PALIMPORT
+HANDLE
+PALAPI
+CreateMutexA(
+ IN LPSECURITY_ATTRIBUTES lpMutexAttributes,
+ IN BOOL bInitialOwner,
+ IN LPCSTR lpName);
+
+PALIMPORT
+HANDLE
+PALAPI
+OpenMutexA(
+ IN DWORD dwDesiredAccess,
+ IN BOOL bInheritHandle,
+ IN LPCSTR lpName);
+
+PALIMPORT
+BOOL
+PALAPI
+CreateProcessA(
+ IN LPCSTR lpApplicationName,
+ IN LPSTR lpCommandLine,
+ IN LPSECURITY_ATTRIBUTES lpProcessAttributes,
+ IN LPSECURITY_ATTRIBUTES lpThreadAttributes,
+ IN BOOL bInheritHandles,
+ IN DWORD dwCreationFlags,
+ IN LPVOID lpEnvironment,
+ IN LPCSTR lpCurrentDirectory,
+ IN LPSTARTUPINFOA lpStartupInfo,
+ OUT LPPROCESS_INFORMATION lpProcessInformation);
+
+PALIMPORT
+HANDLE
+PALAPI
+CreateFileMappingA(
+ IN HANDLE hFile,
+ IN LPSECURITY_ATTRIBUTES lpFileMappingAttributes,
+ IN DWORD flProtect,
+ IN DWORD dwMaximumSizeHigh,
+ IN DWORD dwMaximumSizeLow,
+ IN LPCSTR lpName);
+
+PALIMPORT
+HANDLE
+PALAPI
+OpenFileMappingA(
+ IN DWORD dwDesiredAccess,
+ IN BOOL bInheritHandle,
+ IN LPCSTR lpName);
+
+PALIMPORT
+HMODULE
+PALAPI
+LoadLibraryA(
+ IN LPCSTR lpLibFileName);
+
+PALIMPORT
+HMODULE
+PALAPI
+LoadLibraryExA(
+ IN LPCSTR lpLibFileName,
+ IN /*Reserved*/ HANDLE hFile,
+ IN DWORD dwFlags);
+
+PALIMPORT
+DWORD
+PALAPI
+GetModuleFileNameA(
+ IN HMODULE hModule,
+ OUT LPSTR lpFileName,
+ IN DWORD nSize);
+
+#if ENABLE_DOWNLEVEL_FOR_NLS
+
+
+PALIMPORT
+int
+PALAPI
+CompareStringA(
+ IN LCID Locale,
+ IN DWORD dwCmpFlags,
+ IN LPCSTR lpString1,
+ IN int cchCount1,
+ IN LPCSTR lpString2,
+ IN int cchCount2);
+
+#endif // ENABLE_DOWNLEVEL_FOR_NLS
+
+
+PALIMPORT
+LPSTR
+PALAPI
+GetEnvironmentStringsA(
+ VOID);
+
+PALIMPORT
+BOOL
+PALAPI
+SetEnvironmentVariableA(
+ IN LPCSTR lpName,
+ IN LPCSTR lpValue);
+
+PALIMPORT
+DWORD
+PALAPI
+GetEnvironmentVariableA(
+ IN LPCSTR lpName,
+ OUT LPSTR lpBuffer,
+ IN DWORD nSize);
+
+PALIMPORT
+BOOL
+PALAPI
+FreeEnvironmentStringsA(
+ IN LPSTR);
+
+PALIMPORT
+BOOL
+PALAPI
+GetVersionExA(
+ IN OUT LPOSVERSIONINFOA lpVersionInformation);
+
+PALIMPORT
+BOOL
+PALAPI
+RemoveDirectoryA(
+ IN LPCSTR lpPathName);
+
+PALIMPORT
+BOOL
+PALAPI
+PAL_GetPALDirectoryA(
+ OUT LPSTR lpDirectoryName,
+ IN UINT* cchDirectoryName);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif// __PAL_PRIVATE_H__
diff --git a/src/pal/inc/rt/accctrl.h b/src/pal/inc/rt/accctrl.h
new file mode 100644
index 0000000000..6670eaca23
--- /dev/null
+++ b/src/pal/inc/rt/accctrl.h
@@ -0,0 +1,13 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+//
+// ===========================================================================
+// File: accctl.h
+//
+// ===========================================================================
+// dummy accctl.h for PAL
+
+#include "palrt.h"
diff --git a/src/pal/inc/rt/aclapi.h b/src/pal/inc/rt/aclapi.h
new file mode 100644
index 0000000000..3cad8e48ae
--- /dev/null
+++ b/src/pal/inc/rt/aclapi.h
@@ -0,0 +1,13 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+//
+// ===========================================================================
+// File: aclapi.h
+//
+// ===========================================================================
+// dummy aclapi.h for PAL
+
+#include "palrt.h"
diff --git a/src/pal/inc/rt/assert.h b/src/pal/inc/rt/assert.h
new file mode 100644
index 0000000000..b0c8ecd3be
--- /dev/null
+++ b/src/pal/inc/rt/assert.h
@@ -0,0 +1,13 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+//
+// ===========================================================================
+// File: assert.h
+//
+// ===========================================================================
+// dummy assert.h for PAL
+
+#include "palrt.h"
diff --git a/src/pal/inc/rt/atl.h b/src/pal/inc/rt/atl.h
new file mode 100644
index 0000000000..9f95fc7248
--- /dev/null
+++ b/src/pal/inc/rt/atl.h
@@ -0,0 +1,557 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+//
+// ===========================================================================
+// File: atl.h
+//
+// ===========================================================================
+
+#ifndef __ATL_H__
+#define __ATL_H__
+
+#include "ole2.h"
+/////////////////////////////////////////////////////////////////////////////
+// COM Smart pointers
+
+template <class T>
+class _NoAddRefReleaseOnCComPtr : public T
+{
+ private:
+ STDMETHOD_(ULONG, AddRef)()=0;
+ STDMETHOD_(ULONG, Release)()=0;
+};
+
+//CComPtrBase provides the basis for all other smart pointers
+//The other smartpointers add their own constructors and operators
+template <class T>
+class CComPtrBase
+{
+protected:
+ CComPtrBase()
+ {
+ p = NULL;
+ }
+ CComPtrBase(int nNull)
+ {
+ (void)nNull;
+ p = NULL;
+ }
+ CComPtrBase(T* lp)
+ {
+ p = lp;
+ if (p != NULL)
+ p->AddRef();
+ }
+public:
+ typedef T _PtrClass;
+ ~CComPtrBase()
+ {
+ if (p)
+ p->Release();
+ }
+ operator T*() const
+ {
+ return p;
+ }
+ T& operator*() const
+ {
+ return *p;
+ }
+ T** operator&()
+ {
+ return &p;
+ }
+ _NoAddRefReleaseOnCComPtr<T>* operator->() const
+ {
+ return (_NoAddRefReleaseOnCComPtr<T>*)p;
+ }
+ bool operator!() const
+ {
+ return (p == NULL);
+ }
+ bool operator<(T* pT) const
+ {
+ return p < pT;
+ }
+ bool operator==(T* pT) const
+ {
+ return p == pT;
+ }
+
+ // Release the interface and set to NULL
+ void Release()
+ {
+ T* pTemp = p;
+ if (pTemp)
+ {
+ p = NULL;
+ pTemp->Release();
+ }
+ }
+ // Attach to an existing interface (does not AddRef)
+ void Attach(T* p2)
+ {
+ if (p)
+ p->Release();
+ p = p2;
+ }
+ // Detach the interface (does not Release)
+ T* Detach()
+ {
+ T* pt = p;
+ p = NULL;
+ return pt;
+ }
+ HRESULT CopyTo(T** ppT)
+ {
+ if (ppT == NULL)
+ return E_POINTER;
+ *ppT = p;
+ if (p)
+ p->AddRef();
+ return S_OK;
+ }
+
+ T* p;
+};
+
+template <class T>
+class CComPtr : public CComPtrBase<T>
+{
+public:
+ CComPtr()
+ {
+ }
+ CComPtr(int nNull) :
+ CComPtrBase<T>(nNull)
+ {
+ }
+ CComPtr(T* lp) :
+ CComPtrBase<T>(lp)
+
+ {
+ }
+ CComPtr(const CComPtr<T>& lp) :
+ CComPtrBase<T>(lp.p)
+ {
+ }
+ T* operator=(T* lp)
+ {
+ return static_cast<T*>(AtlComPtrAssign((IUnknown**)&this->p, lp));
+ }
+ T* operator=(const CComPtr<T>& lp)
+ {
+ return static_cast<T*>(AtlComPtrAssign((IUnknown**)&this->p, lp));
+ }
+};
+
+#define IUNKNOWN_METHODS \
+private: ULONG m_dwRef; \
+public: \
+ virtual ULONG STDMETHODCALLTYPE AddRef( void) { \
+ return (ULONG)InterlockedIncrement((LONG*)&m_dwRef); } \
+ virtual ULONG STDMETHODCALLTYPE Release( void) { \
+ ULONG new_ref = (ULONG)InterlockedDecrement((LONG*)&m_dwRef); \
+ if (new_ref == 0) { delete this; return 0; } return new_ref; } \
+
+
+#define BEGIN_COM_MAP(t) \
+ HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject) \
+ { \
+ if (ppvObject == NULL) \
+ { \
+ return E_POINTER; \
+ }
+
+#define COM_INTERFACE_ENTRY(i) \
+ if (riid == IID_##i) \
+ { \
+ *ppvObject = (i*)this; \
+ this->AddRef(); \
+ return S_OK; \
+ }
+
+#define END_COM_MAP() \
+ return E_NOINTERFACE; \
+ } \
+ virtual ULONG STDMETHODCALLTYPE AddRef( void) = 0; \
+ virtual ULONG STDMETHODCALLTYPE Release( void) = 0;
+
+
+
+template <const IID* piid>
+class ISupportErrorInfoImpl : public ISupportErrorInfo
+{
+public:
+ STDMETHOD(InterfaceSupportsErrorInfo)(REFIID riid)
+ {
+ return (riid == *piid) ? S_OK : S_FALSE;
+ }
+};
+
+inline IUnknown* AtlComPtrAssign(IUnknown** pp, IUnknown* lp)
+{
+ if (lp != NULL)
+ lp->AddRef();
+ if (*pp)
+ (*pp)->Release();
+ *pp = lp;
+ return lp;
+}
+
+inline IUnknown* AtlComQIPtrAssign(IUnknown** pp, IUnknown* lp, REFIID riid)
+{
+ IUnknown* pTemp = *pp;
+ *pp = NULL;
+ if (lp != NULL)
+ lp->QueryInterface(riid, (void**)pp);
+ if (pTemp)
+ pTemp->Release();
+ return *pp;
+}
+
+
+class CComMultiThreadModelNoCS
+{
+public:
+ static ULONG WINAPI Increment(LONG *p) {return InterlockedIncrement(p);}
+ static ULONG WINAPI Decrement(LONG *p) {return InterlockedDecrement(p);}
+};
+
+//Base is the user's class that derives from CComObjectRoot and whatever
+//interfaces the user wants to support on the object
+template <class Base>
+class CComObject : public Base
+{
+public:
+ typedef Base _BaseClass;
+
+ // Set refcount to -(LONG_MAX/2) to protect destruction and
+ // also catch mismatched Release in debug builds
+ ~CComObject()
+ {
+ this->m_dwRef = -(LONG_MAX/2);
+ }
+ //If InternalAddRef or InternalRelease is undefined then your class
+ //doesn't derive from CComObjectRoot
+ STDMETHOD_(ULONG, AddRef)() {return this->InternalAddRef();}
+ STDMETHOD_(ULONG, Release)()
+ {
+ ULONG l = this->InternalRelease();
+ if (l == 0)
+ delete this;
+ return l;
+ }
+
+ static HRESULT WINAPI CreateInstance(CComObject<Base>** pp);
+};
+
+template <class Base>
+HRESULT WINAPI CComObject<Base>::CreateInstance(CComObject<Base>** pp)
+{
+ ATLASSERT(pp != NULL);
+ if (pp == NULL)
+ return E_POINTER;
+ *pp = NULL;
+
+ HRESULT hRes = E_OUTOFMEMORY;
+ CComObject<Base>* p = NULL;
+ p = new CComObject<Base>();
+ if (p != NULL)
+ {
+ hRes = NOERROR;
+ }
+ *pp = p;
+ return hRes;
+}
+
+
+// the functions in this class don't need to be virtual because
+// they are called from CComObject
+class CComObjectRootBase
+{
+public:
+ CComObjectRootBase()
+ {
+ m_dwRef = 0L;
+ }
+public:
+ LONG m_dwRef;
+}; // CComObjectRootBase
+
+template <class ThreadModel>
+class CComObjectRootEx : public CComObjectRootBase
+{
+public:
+ typedef ThreadModel _ThreadModel;
+
+ ULONG InternalAddRef()
+ {
+ ATLASSERT(m_dwRef != -1L);
+ return _ThreadModel::Increment(&m_dwRef);
+ }
+ ULONG InternalRelease()
+ {
+#ifdef _DEBUG
+ LONG nRef = _ThreadModel::Decrement(&m_dwRef);
+ if (nRef < -(LONG_MAX / 2))
+ {
+ ATLASSERT(0);
+ }
+ return nRef;
+#else
+ return _ThreadModel::Decrement(&m_dwRef);
+#endif
+ }
+}; // CComObjectRootEx
+
+typedef CComMultiThreadModelNoCS CComObjectThreadModel;
+
+typedef CComObjectRootEx<CComObjectThreadModel> CComObjectRoot;
+
+// dummy definitions for the ATL COM goo
+#define DECLARE_NO_REGISTRY()
+
+#define BEGIN_OBJECT_MAP(x) static const int x = 0;
+#define OBJECT_ENTRY(clsid, class)
+#define END_OBJECT_MAP()
+
+template <class T, const CLSID* pclsid>
+class CComCoClass {
+};
+
+class CComModule {
+public:
+ HINSTANCE m_hInst;
+ HINSTANCE m_hInstResource;
+
+ HRESULT Init(int objmap, HINSTANCE h)
+ {
+ m_hInst = h;
+ return S_OK;
+ }
+
+ void Term()
+ {
+ m_hInst = NULL;
+ m_hInstResource = NULL;
+ }
+
+ HINSTANCE GetModuleInstance()
+ {
+ return m_hInst;
+ }
+
+ HINSTANCE GetResourceInstance()
+ {
+ return m_hInstResource;
+ }
+};
+
+template <class E>
+class CAtlArray
+{
+private:
+ E * m_pData; // Elements of the array.
+ size_t m_nSize; // Number of valid elements in the array.
+ size_t m_nMaxSize; // Total number of elements m_pData buffer can hold.
+
+ // Call the constructors for the nElements elements starting from pBeggingElement
+ void CallConstructors( E* pBeginningElement, size_t nElements )
+ {
+ for( size_t iElement = 0; iElement < nElements; iElement++ )
+ {
+ ::new( this->pElements+iElement ) E;
+ }
+ }
+
+ // Call the destructor for the nElements elements starting from pBeggingElement
+ void CallDestructors( E* pBeginningElement, size_t nElements )
+ {
+ ATLASSERT(nElements == 0 ||
+ pBeginningElement + (nElements-1) < m_pData + m_nSize // Should not go beyond the valid element range.
+ );
+
+ for( size_t iElement = 0; iElement < nElements; iElement++ )
+ {
+ pBeginningElement[iElement].~E();
+#ifdef DEBUG
+ // Put some garbage there.
+ // It would be 0xcccccccc if the element is a pointer. For easy debugging.
+ memset(&pBeginningElement[iElement], 0xcc, sizeof(E));
+#endif
+ }
+ }
+
+
+public:
+ CAtlArray() : m_pData(NULL), m_nSize(0), m_nMaxSize(0) {}
+ ~CAtlArray() { RemoveAll(); }
+
+ size_t GetCount() const
+ {
+ return m_nSize;
+ }
+
+ bool IsEmpty()
+ {
+ return m_nSize == 0;
+ }
+
+ void RemoveAll()
+ {
+ if (m_pData)
+ {
+ CallDestructors( m_pData, m_nSize );
+ free( m_pData );
+ m_pData = NULL;
+ m_nSize = 0;
+ m_nMaxSize = 0;
+ }
+
+ ATLASSERT(m_pData == NULL);
+ ATLASSERT(m_nSize == 0);
+ ATLASSERT(m_nMaxSize == 0);
+ }
+
+ E& GetAt( size_t iElement )
+ {
+ ATLASSERT(iElement < m_nSize);
+ if (iElement >= m_nSize)
+ AtlThrow(E_INVALIDARG);
+ return (m_pData[iElement]);
+ }
+
+ E& operator[]( size_t iElement )
+ {
+ return GetAt(iElement);
+ }
+
+ E* GetData()
+ {
+ return (m_pData);
+ }
+
+ void SetCount( size_t nNewSize )
+ {
+ if ( nNewSize == 0 )
+ {
+ RemoveAll();
+ }
+ else
+ if ( nNewSize <= m_nSize )
+ {
+ CallDestructors( m_pData+nNewSize, m_nSize-nNewSize );
+ m_nSize = nNewSize;
+ }
+ else
+ if ( nNewSize > m_nSize )
+ {
+ bool bSuccess = GrowBuffer( nNewSize );
+ if( !bSuccess )
+ {
+ AtlThrow( E_OUTOFMEMORY );
+ }
+
+ CallDestructors( m_pData+m_nSize, nNewSize-m_nSize );
+ m_nSize = nNewSize;
+ }
+ }
+
+ bool GrowBuffer( size_t nNewMaxSize )
+ {
+ if( nNewMaxSize > m_nMaxSize )
+ {
+ E* pNewData = static_cast< E* >( malloc( nNewMaxSize*sizeof( E ) ) );
+ if( pNewData == NULL )
+ {
+ return false;
+ }
+
+ // Ok, allocation succeeded.
+
+ if (m_pData == NULL)
+ {
+ // First time allocation. Simply return the newly allocated buffer.
+ goto DoneNewBuffer;
+
+ }
+
+ // copy new data from old
+ memmove( pNewData, m_pData, m_nSize*sizeof( E ));
+
+ // get rid of old stuff
+ // (note: no need to call the destructors, because the elements are still alive
+ // in the new array.)
+ free( m_pData );
+
+DoneNewBuffer:
+ m_pData = pNewData;
+ m_nMaxSize = nNewMaxSize;
+ }
+
+ return true;
+ }
+
+ size_t Add( E element )
+ {
+ size_t iElement = m_nSize;
+
+ if( iElement >= m_nMaxSize )
+ {
+ size_t nNewMaxSize = m_nMaxSize * 2;
+ nNewMaxSize = (nNewMaxSize >= 16)?nNewMaxSize:16; // Let's allocate at least 16 elements.
+ if (nNewMaxSize < m_nMaxSize)
+ AtlThrow( E_OUTOFMEMORY ); // Integer overflow
+
+ if (iElement >= nNewMaxSize)
+ {
+ nNewMaxSize = iElement + 1;
+ if (nNewMaxSize<iElement)
+ AtlThrow( E_OUTOFMEMORY ); // Integer overflow
+ }
+
+ bool bSuccess = GrowBuffer( nNewMaxSize );
+ if( !bSuccess )
+ {
+ AtlThrow( E_OUTOFMEMORY );
+ }
+ }
+
+ ATLASSERT(m_pData);
+ ATLASSERT(iElement < m_nMaxSize);
+ new( m_pData+iElement ) E( element );
+
+ m_nSize++;
+
+ return( iElement );
+ }
+
+ // Remove "nElements" elements starting from the element at index "iElement"
+ void RemoveAt( size_t iElement, size_t nElements = 1 )
+ {
+ ATLASSERT( (iElement+nElements) <= m_nSize );
+
+ if( (iElement+nElements) > m_nSize )
+ AtlThrow(E_INVALIDARG);
+
+ // just remove a range
+ size_t nMoveCount = m_nSize-(iElement+nElements);
+ CallDestructors( m_pData+iElement, nElements );
+ if( nMoveCount > 0 )
+ {
+ memmove_s( m_pData+iElement,
+ nMoveCount * sizeof( E ),
+ m_pData+(iElement+nElements),
+ nMoveCount * sizeof( E )
+ );
+ }
+ m_nSize -= nElements;
+ }
+
+}; // CAtlArray
+
+#endif // __ATL_H__
diff --git a/src/pal/inc/rt/atlcom.h b/src/pal/inc/rt/atlcom.h
new file mode 100644
index 0000000000..f7d96a177c
--- /dev/null
+++ b/src/pal/inc/rt/atlcom.h
@@ -0,0 +1,13 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+//
+// ===========================================================================
+// File: atlcom.h
+//
+// ===========================================================================
+// dummy atlcom.h for PAL
+
+#include "atl.h"
diff --git a/src/pal/inc/rt/atlwin.h b/src/pal/inc/rt/atlwin.h
new file mode 100644
index 0000000000..0d63430b46
--- /dev/null
+++ b/src/pal/inc/rt/atlwin.h
@@ -0,0 +1,13 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+//
+// ===========================================================================
+// File: atlwin.h
+//
+// ===========================================================================
+// dummy atlwin.h for PAL
+
+#include "atlwin.h"
diff --git a/src/pal/inc/rt/commctrl.h b/src/pal/inc/rt/commctrl.h
new file mode 100644
index 0000000000..f7065dc25e
--- /dev/null
+++ b/src/pal/inc/rt/commctrl.h
@@ -0,0 +1,13 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+//
+// ===========================================================================
+// File: commctrl.h
+//
+// ===========================================================================
+// dummy commctrl.h for PAL
+
+#include "palrt.h"
diff --git a/src/pal/inc/rt/commdlg.h b/src/pal/inc/rt/commdlg.h
new file mode 100644
index 0000000000..0ef590d2a5
--- /dev/null
+++ b/src/pal/inc/rt/commdlg.h
@@ -0,0 +1,13 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+//
+// ===========================================================================
+// File: commdlg.h
+//
+// ===========================================================================
+// dummy commdlg.h for PAL
+
+#include "palrt.h"
diff --git a/src/pal/inc/rt/common.ver b/src/pal/inc/rt/common.ver
new file mode 100644
index 0000000000..9007a3de2d
--- /dev/null
+++ b/src/pal/inc/rt/common.ver
@@ -0,0 +1,33 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#include "fxver.h"
+
+VS_VERSION_INFO VERSIONINFO
+
+FILEVERSION VER_FILEVERSION
+PRODUCTVERSION VER_PRODUCTVERSION
+FILEFLAGSMASK VER_FILEFLAGSMASK
+FILEFLAGS VER_FILEFLAGS
+FILEOS VER_FILEOS
+FILETYPE VER_FILETYPE
+FILESUBTYPE VER_FILESUBTYPE
+
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK VER_VERSION_UNICODE_LANG
+ BEGIN
+ VALUE "CompanyName", VER_COMPANYNAME_STR
+ VALUE "LegalCopyright", VER_LEGALCOPYRIGHT_STR
+ VALUE "FileVersion", VER_FILEVERSION_STR
+ VALUE "FileDescription", "Rotor File"
+ END
+ END
+
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", VER_VERSION_TRANSLATION
+ END
+END
diff --git a/src/pal/inc/rt/conio.h b/src/pal/inc/rt/conio.h
new file mode 100644
index 0000000000..955a9298b8
--- /dev/null
+++ b/src/pal/inc/rt/conio.h
@@ -0,0 +1,13 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+//
+// ===========================================================================
+// File: conio.h
+//
+// ===========================================================================
+// dummy conio.h for PAL
+
+#include "palrt.h"
diff --git a/src/pal/inc/rt/cpp/ccombstr.h b/src/pal/inc/rt/cpp/ccombstr.h
new file mode 100644
index 0000000000..999be9e706
--- /dev/null
+++ b/src/pal/inc/rt/cpp/ccombstr.h
@@ -0,0 +1,263 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+//
+// ===========================================================================
+// File: CComBSTR.h
+//
+// ===========================================================================
+
+/*++
+
+Abstract:
+
+ Stripped down and modified version of CComBSTR
+
+--*/
+
+#ifndef __CCOMBSTR_H__
+#define __CCOMBSTR_H__
+
+#ifdef __cplusplus
+
+#ifndef AtlThrow
+#define AtlThrow(a) RaiseException(STATUS_NO_MEMORY,EXCEPTION_NONCONTINUABLE,0,nullptr);
+#endif
+#ifndef ATLASSERT
+#define ATLASSERT(a) _ASSERTE(a)
+#endif
+#define MAX_SATELLITESTRING 1024
+
+#include <safemath.h>
+
+class CComBSTR
+{
+public:
+ BSTR m_str;
+ CComBSTR()
+ {
+ m_str = nullptr;
+ }
+ CComBSTR(int nSize)
+ {
+ if (nSize == 0)
+ m_str = nullptr;
+ else
+ {
+ m_str = ::SysAllocStringLen(nullptr, nSize);
+ if (m_str == nullptr)
+ AtlThrow(E_OUTOFMEMORY);
+ }
+ }
+ CComBSTR(int nSize, LPCOLESTR sz)
+ {
+ if (nSize == 0)
+ m_str = nullptr;
+ else
+ {
+ m_str = ::SysAllocStringLen(sz, nSize);
+ if (m_str == nullptr)
+ AtlThrow(E_OUTOFMEMORY);
+ }
+ }
+ CComBSTR(LPCOLESTR pSrc)
+ {
+ if (pSrc == nullptr)
+ m_str = nullptr;
+ else
+ {
+ m_str = ::SysAllocString(pSrc);
+ if (m_str == nullptr)
+ AtlThrow(E_OUTOFMEMORY);
+ }
+ }
+
+ CComBSTR(const CComBSTR& src)
+ {
+ m_str = src.Copy();
+ if (!!src && m_str == nullptr)
+ AtlThrow(E_OUTOFMEMORY);
+
+ }
+
+ CComBSTR& operator=(const CComBSTR& src)
+ {
+ if (m_str != src.m_str)
+ {
+ ::SysFreeString(m_str);
+ m_str = src.Copy();
+ if (!!src && m_str == nullptr)
+ AtlThrow(E_OUTOFMEMORY);
+ }
+ return *this;
+ }
+
+ CComBSTR& operator=(LPCOLESTR pSrc)
+ {
+ if (pSrc != m_str)
+ {
+ ::SysFreeString(m_str);
+ if (pSrc != nullptr)
+ {
+ m_str = ::SysAllocString(pSrc);
+ if (m_str == nullptr)
+ AtlThrow(E_OUTOFMEMORY);
+ }
+ else
+ m_str = nullptr;
+ }
+ return *this;
+ }
+
+ ~CComBSTR()
+ {
+ ::SysFreeString(m_str);
+ }
+ unsigned int ByteLength() const
+ {
+ return (m_str == nullptr)? 0 : SysStringByteLen(m_str);
+ }
+ unsigned int Length() const
+ {
+ return (m_str == nullptr)? 0 : SysStringLen(m_str);
+ }
+ operator BSTR() const
+ {
+ return m_str;
+ }
+ BSTR* operator&()
+ {
+ return &m_str;
+ }
+ BSTR Copy() const
+ {
+ if (m_str == nullptr)
+ return nullptr;
+ return ::SysAllocStringLen(m_str, SysStringLen(m_str));
+ }
+ HRESULT CopyTo(BSTR* pbstr)
+ {
+ ATLASSERT(pbstr != nullptr);
+ if (pbstr == nullptr)
+ return E_POINTER;
+ *pbstr = Copy();
+ if ((*pbstr == nullptr) && (m_str != nullptr))
+ return E_OUTOFMEMORY;
+ return S_OK;
+ }
+ // copy BSTR to VARIANT
+ HRESULT CopyTo(VARIANT *pvarDest)
+ {
+ ATLASSERT(pvarDest != nullptr);
+ HRESULT hRes = E_POINTER;
+ if (pvarDest != nullptr)
+ {
+ V_VT (pvarDest) = VT_BSTR;
+ V_BSTR (pvarDest) = Copy();
+ if (V_BSTR (pvarDest) == nullptr && m_str != nullptr)
+ hRes = E_OUTOFMEMORY;
+ else
+ hRes = S_OK;
+ }
+ return hRes;
+ }
+
+ void Attach(BSTR src)
+ {
+ if (m_str != src)
+ {
+ ::SysFreeString(m_str);
+ m_str = src;
+ }
+ }
+ BSTR Detach()
+ {
+ BSTR s = m_str;
+ m_str = nullptr;
+ return s;
+ }
+ void Empty()
+ {
+ ::SysFreeString(m_str);
+ m_str = nullptr;
+ }
+ HRESULT Append(LPCOLESTR lpsz)
+ {
+ return Append(lpsz, UINT(lstrlenW(lpsz)));
+ }
+
+ HRESULT Append(LPCOLESTR lpsz, int nLen)
+ {
+ if (lpsz == nullptr || (m_str != nullptr && nLen == 0))
+ return S_OK;
+ if (nLen < 0)
+ return E_INVALIDARG;
+ int n1 = Length();
+
+ // Check for overflow
+ size_t newSize;
+ if (!ClrSafeInt<size_t>::addition(n1, nLen, newSize))
+ return E_INVALIDARG;
+
+ BSTR b;
+ b = ::SysAllocStringLen(nullptr, newSize);
+ if (b == nullptr)
+ return E_OUTOFMEMORY;
+ memcpy(b, m_str, n1*sizeof(OLECHAR));
+ memcpy(b+n1, lpsz, nLen*sizeof(OLECHAR));
+ b[n1+nLen] = 0;
+ SysFreeString(m_str);
+ m_str = b;
+ return S_OK;
+ }
+
+ HRESULT AssignBSTR(const BSTR bstrSrc)
+ {
+ HRESULT hr = S_OK;
+ if (m_str != bstrSrc)
+ {
+ ::SysFreeString(m_str);
+ if (bstrSrc != nullptr)
+ {
+ m_str = SysAllocStringLen(bstrSrc, SysStringLen(bstrSrc));
+ if (m_str == nullptr)
+ hr = E_OUTOFMEMORY;
+ }
+ else
+ m_str = nullptr;
+ }
+
+ return hr;
+ }
+
+ bool LoadString(HSATELLITE hInst, UINT nID)
+ {
+ ::SysFreeString(m_str);
+ m_str = nullptr;
+ WCHAR SatelliteString[MAX_SATELLITESTRING];
+ if (PAL_LoadSatelliteStringW(hInst, nID, SatelliteString, MAX_SATELLITESTRING))
+ {
+ m_str = SysAllocString(SatelliteString);
+ }
+ return m_str != nullptr;
+ }
+
+ bool LoadString(PVOID hInst, UINT nID)
+ {
+ return LoadString ((HSATELLITE)hInst, nID);
+ }
+
+ CComBSTR& operator+=(LPCOLESTR pszSrc)
+ {
+ HRESULT hr;
+ hr = Append(pszSrc);
+ if (FAILED(hr))
+ AtlThrow(hr);
+ return *this;
+ }
+
+};
+#endif // __cplusplus
+#endif // __CCOMBSTR_H__
diff --git a/src/pal/inc/rt/cpp/cstdlib b/src/pal/inc/rt/cpp/cstdlib
new file mode 100644
index 0000000000..74d998901a
--- /dev/null
+++ b/src/pal/inc/rt/cpp/cstdlib
@@ -0,0 +1,14 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+//
+// <OWNER>clrosdev</OWNER>
+//
+// ===========================================================================
+// File: cstdlib
+//
+// ===========================================================================
+// dummy cstdlib for PAL
+
+#include "palrt.h"
diff --git a/src/pal/inc/rt/cpp/cstring.h b/src/pal/inc/rt/cpp/cstring.h
new file mode 100644
index 0000000000..483a005ca6
--- /dev/null
+++ b/src/pal/inc/rt/cpp/cstring.h
@@ -0,0 +1,77 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+//
+
+#ifndef __CSTRING_H__
+#define __CSTRING_H__
+
+#ifdef __cplusplus
+
+#ifndef AtlThrow
+#define AtlThrow(a) RaiseException(STATUS_NO_MEMORY,EXCEPTION_NONCONTINUABLE,0,nullptr);
+#endif
+#ifndef ATLASSERT
+#define ATLASSERT(a) _ASSERTE(a)
+#endif
+
+#include "ccombstr.h"
+
+class CStringW : public CComBSTR
+{
+public:
+ CStringW() {
+ }
+
+ CStringW(int nSize, LPCOLESTR sz) :
+ CComBSTR (nSize, sz)
+ {
+ }
+
+
+ CStringW(LPCOLESTR pSrc) :
+ CComBSTR(pSrc)
+ {
+ }
+
+ CStringW(const CStringW& src) :
+ CComBSTR(src)
+ {
+ }
+
+ CStringW (LPCSTR pSrc) :
+ CComBSTR()
+ {
+ // Intentionaly create us as empty string, later
+ // we will overwrite ourselves with the
+ // converted string.
+ int cchSize;
+ cchSize = MultiByteToWideChar(CP_ACP, 0, pSrc, -1, nullptr, 0);
+ if (cchSize == 0)
+ {
+ AtlThrow(E_OUTOFMEMORY);
+ }
+
+ CComBSTR bstr(cchSize);
+ // No convert the string
+ // (Note that (BSTR)bstr will return a pointer to the
+ // allocated WCHAR buffer - done by the CComBSTR constructor)
+ if (MultiByteToWideChar(CP_ACP, 0, pSrc, -1, (WCHAR *)((BSTR)bstr), cchSize) == 0)
+ {
+ AtlThrow(E_OUTOFMEMORY);
+ }
+
+ // And now assign this new bstr to us
+ // The following is a trick how to avoid copying the string
+ Attach(bstr.Detach());
+ }
+
+ ~CStringW() {
+ }
+};
+
+#endif // __cplusplus
+
+#endif // __CSTRING_H__
diff --git a/src/pal/inc/rt/cpp/ctype.h b/src/pal/inc/rt/cpp/ctype.h
new file mode 100644
index 0000000000..2cd945662a
--- /dev/null
+++ b/src/pal/inc/rt/cpp/ctype.h
@@ -0,0 +1,13 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+//
+// ===========================================================================
+// File: ctype.h
+//
+// ===========================================================================
+// dummy ctype.h for PAL
+
+#include "palrt.h"
diff --git a/src/pal/inc/rt/cpp/fcntl.h b/src/pal/inc/rt/cpp/fcntl.h
new file mode 100644
index 0000000000..4acf456686
--- /dev/null
+++ b/src/pal/inc/rt/cpp/fcntl.h
@@ -0,0 +1,13 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+//
+// ===========================================================================
+// File: fcntl.h
+//
+// ===========================================================================
+// dummy fcntl.h for PAL
+
+#include "palrt.h"
diff --git a/src/pal/inc/rt/cpp/float.h b/src/pal/inc/rt/cpp/float.h
new file mode 100644
index 0000000000..87705eef73
--- /dev/null
+++ b/src/pal/inc/rt/cpp/float.h
@@ -0,0 +1,13 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+//
+// ===========================================================================
+// File: float.h
+//
+// ===========================================================================
+// dummy float.h for PAL
+
+#include "palrt.h"
diff --git a/src/pal/inc/rt/cpp/io.h b/src/pal/inc/rt/cpp/io.h
new file mode 100644
index 0000000000..d742d1c190
--- /dev/null
+++ b/src/pal/inc/rt/cpp/io.h
@@ -0,0 +1,13 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+//
+// ===========================================================================
+// File: io.h
+//
+// ===========================================================================
+// dummy io.h for PAL
+
+#include "palrt.h"
diff --git a/src/pal/inc/rt/cpp/limits.h b/src/pal/inc/rt/cpp/limits.h
new file mode 100644
index 0000000000..21b6d47fd8
--- /dev/null
+++ b/src/pal/inc/rt/cpp/limits.h
@@ -0,0 +1,13 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+//
+// ===========================================================================
+// File: limits.h
+//
+// ===========================================================================
+// dummy limits.h for PAL
+
+#include "palrt.h"
diff --git a/src/pal/inc/rt/cpp/malloc.h b/src/pal/inc/rt/cpp/malloc.h
new file mode 100644
index 0000000000..a9ecc1af93
--- /dev/null
+++ b/src/pal/inc/rt/cpp/malloc.h
@@ -0,0 +1,13 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+//
+// ===========================================================================
+// File: malloc.h
+//
+// ===========================================================================
+// dummy malloc.h for PAL
+
+#include "palrt.h"
diff --git a/src/pal/inc/rt/cpp/math.h b/src/pal/inc/rt/cpp/math.h
new file mode 100644
index 0000000000..07dbfa3b50
--- /dev/null
+++ b/src/pal/inc/rt/cpp/math.h
@@ -0,0 +1,13 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+//
+// ===========================================================================
+// File: math.h
+//
+// ===========================================================================
+// dummy math.h for PAL
+
+#include "palrt.h"
diff --git a/src/pal/inc/rt/cpp/memory.h b/src/pal/inc/rt/cpp/memory.h
new file mode 100644
index 0000000000..8257d710c3
--- /dev/null
+++ b/src/pal/inc/rt/cpp/memory.h
@@ -0,0 +1,13 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+//
+// ===========================================================================
+// File: memory.h
+//
+// ===========================================================================
+// dummy memory.h for PAL
+
+#include "palrt.h"
diff --git a/src/pal/inc/rt/cpp/stdarg.h b/src/pal/inc/rt/cpp/stdarg.h
new file mode 100644
index 0000000000..22517d04a8
--- /dev/null
+++ b/src/pal/inc/rt/cpp/stdarg.h
@@ -0,0 +1,13 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+//
+// ===========================================================================
+// File: stdarg.h
+//
+// ===========================================================================
+// dummy stdarg.h for PAL
+
+#include "palrt.h"
diff --git a/src/pal/inc/rt/cpp/stddef.h b/src/pal/inc/rt/cpp/stddef.h
new file mode 100644
index 0000000000..1725893869
--- /dev/null
+++ b/src/pal/inc/rt/cpp/stddef.h
@@ -0,0 +1,13 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+//
+// ===========================================================================
+// File: stddef.h
+//
+// ===========================================================================
+// dummy stddef.h for PAL
+
+#include "palrt.h"
diff --git a/src/pal/inc/rt/cpp/stdint.h b/src/pal/inc/rt/cpp/stdint.h
new file mode 100644
index 0000000000..5401fabc13
--- /dev/null
+++ b/src/pal/inc/rt/cpp/stdint.h
@@ -0,0 +1,5 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#include "palrt.h"
diff --git a/src/pal/inc/rt/cpp/stdio.h b/src/pal/inc/rt/cpp/stdio.h
new file mode 100644
index 0000000000..35ed76156c
--- /dev/null
+++ b/src/pal/inc/rt/cpp/stdio.h
@@ -0,0 +1,13 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+//
+// ===========================================================================
+// File: stdio.h
+//
+// ===========================================================================
+// dummy stdio.h for PAL
+
+#include "palrt.h"
diff --git a/src/pal/inc/rt/cpp/stdlib.h b/src/pal/inc/rt/cpp/stdlib.h
new file mode 100644
index 0000000000..68e0a40ab4
--- /dev/null
+++ b/src/pal/inc/rt/cpp/stdlib.h
@@ -0,0 +1,13 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+//
+// ===========================================================================
+// File: stdlib.h
+//
+// ===========================================================================
+// dummy stdlib.h for PAL
+
+#include "palrt.h"
diff --git a/src/pal/inc/rt/cpp/string.h b/src/pal/inc/rt/cpp/string.h
new file mode 100644
index 0000000000..804513265f
--- /dev/null
+++ b/src/pal/inc/rt/cpp/string.h
@@ -0,0 +1,13 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+//
+// ===========================================================================
+// File: string.h
+//
+// ===========================================================================
+// dummy string.h for PAL
+
+#include "palrt.h"
diff --git a/src/pal/inc/rt/cpp/time.h b/src/pal/inc/rt/cpp/time.h
new file mode 100644
index 0000000000..d6f487ed64
--- /dev/null
+++ b/src/pal/inc/rt/cpp/time.h
@@ -0,0 +1,13 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+//
+// ===========================================================================
+// File: time.h
+//
+// ===========================================================================
+// dummy time.h for PAL
+
+#include "palrt.h"
diff --git a/src/pal/inc/rt/cpp/wchar.h b/src/pal/inc/rt/cpp/wchar.h
new file mode 100644
index 0000000000..af00ca0133
--- /dev/null
+++ b/src/pal/inc/rt/cpp/wchar.h
@@ -0,0 +1,13 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+//
+// ===========================================================================
+// File: wchar.h
+//
+// ===========================================================================
+// dummy wchar.h for PAL
+
+#include "palrt.h"
diff --git a/src/pal/inc/rt/crtdbg.h b/src/pal/inc/rt/crtdbg.h
new file mode 100644
index 0000000000..e94bb3260c
--- /dev/null
+++ b/src/pal/inc/rt/crtdbg.h
@@ -0,0 +1,13 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+//
+// ===========================================================================
+// File: crtdbg.h
+//
+// ===========================================================================
+// dummy crtdbg.h for PAL
+
+#include "palrt.h"
diff --git a/src/pal/inc/rt/dbghelp.h b/src/pal/inc/rt/dbghelp.h
new file mode 100644
index 0000000000..7d9cd334e9
--- /dev/null
+++ b/src/pal/inc/rt/dbghelp.h
@@ -0,0 +1,37 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++ BUILD Version: 0000 Increment this if a change has global effects
+
+
+
+Module Name:
+
+ dbghelp.h
+
+Abstract:
+
+ This module defines the prototypes and constants required for the image
+ help routines.
+
+ Contains debugging support routines that are redistributable.
+
+Revision History:
+
+--*/
+
+#ifndef _DBGHELP_
+#define _DBGHELP_
+
+#if _MSC_VER > 1020
+#pragma once
+#endif
+
+//
+// options that are set/returned by SymSetOptions() & SymGetOptions()
+// these are used as a mask
+//
+#define SYMOPT_LOAD_LINES 0x00000010
+
+#endif // _DBGHELP_
diff --git a/src/pal/inc/rt/eh.h b/src/pal/inc/rt/eh.h
new file mode 100644
index 0000000000..5401fabc13
--- /dev/null
+++ b/src/pal/inc/rt/eh.h
@@ -0,0 +1,5 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#include "palrt.h"
diff --git a/src/pal/inc/rt/emmintrin.h b/src/pal/inc/rt/emmintrin.h
new file mode 100644
index 0000000000..5401fabc13
--- /dev/null
+++ b/src/pal/inc/rt/emmintrin.h
@@ -0,0 +1,5 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#include "palrt.h"
diff --git a/src/pal/inc/rt/errorrep.h b/src/pal/inc/rt/errorrep.h
new file mode 100644
index 0000000000..5401fabc13
--- /dev/null
+++ b/src/pal/inc/rt/errorrep.h
@@ -0,0 +1,5 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#include "palrt.h"
diff --git a/src/pal/inc/rt/guiddef.h b/src/pal/inc/rt/guiddef.h
new file mode 100644
index 0000000000..12e51c8fc6
--- /dev/null
+++ b/src/pal/inc/rt/guiddef.h
@@ -0,0 +1,26 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+//
+// ===========================================================================
+// File: guiddef.h
+//
+// ===========================================================================
+// simplified guiddef.h for PAL
+
+#include "palrt.h"
+
+#ifdef DEFINE_GUID
+#undef DEFINE_GUID
+#endif
+
+#ifdef INITGUID
+#define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
+ EXTERN_C const GUID DECLSPEC_SELECTANY name \
+ = { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }
+#else
+#define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
+ EXTERN_C const GUID FAR name
+#endif // INITGUID
diff --git a/src/pal/inc/rt/hstring.h b/src/pal/inc/rt/hstring.h
new file mode 100644
index 0000000000..5401fabc13
--- /dev/null
+++ b/src/pal/inc/rt/hstring.h
@@ -0,0 +1,5 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#include "palrt.h"
diff --git a/src/pal/inc/rt/htmlhelp.h b/src/pal/inc/rt/htmlhelp.h
new file mode 100644
index 0000000000..6ae044a897
--- /dev/null
+++ b/src/pal/inc/rt/htmlhelp.h
@@ -0,0 +1,13 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+//
+// ===========================================================================
+// File: htmlhelp.h
+//
+// ===========================================================================
+// dummy htmlhelp.h for PAL
+
+#include "palrt.h"
diff --git a/src/pal/inc/rt/imagehlp.h b/src/pal/inc/rt/imagehlp.h
new file mode 100644
index 0000000000..07824e49aa
--- /dev/null
+++ b/src/pal/inc/rt/imagehlp.h
@@ -0,0 +1,64 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ imagehlp.h
+
+Abstract:
+
+ This module defines the prototypes and constants required for the image
+ help routines.
+
+
+
+
+--*/
+
+#ifndef _IMAGEHLP_
+#define _IMAGEHLP_
+
+#if _MSC_VER > 1020
+#pragma once
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define IMAGEAPI __stdcall
+
+PIMAGE_NT_HEADERS
+IMAGEAPI
+CheckSumMappedFile (
+ PVOID BaseAddress,
+ DWORD FileLength,
+ PDWORD HeaderSum,
+ PDWORD CheckSum
+ );
+
+PIMAGE_NT_HEADERS
+IMAGEAPI
+ImageNtHeader (
+ IN PVOID Base
+ );
+
+PVOID
+IMAGEAPI
+ImageRvaToVa(
+ IN PIMAGE_NT_HEADERS NtHeaders,
+ IN PVOID Base,
+ IN ULONG Rva,
+ IN OUT PIMAGE_SECTION_HEADER *LastRvaSection
+ );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // _IMAGEHLP_
diff --git a/src/pal/inc/rt/intrin.h b/src/pal/inc/rt/intrin.h
new file mode 100644
index 0000000000..5401fabc13
--- /dev/null
+++ b/src/pal/inc/rt/intrin.h
@@ -0,0 +1,5 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#include "palrt.h"
diff --git a/src/pal/inc/rt/intsafe.h b/src/pal/inc/rt/intsafe.h
new file mode 100644
index 0000000000..2ab2cf1550
--- /dev/null
+++ b/src/pal/inc/rt/intsafe.h
@@ -0,0 +1,1616 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/******************************************************************
+* *
+* intsafe.h -- This module defines helper functions to prevent *
+* integer overflow issues. *
+* *
+* *
+******************************************************************/
+#ifndef _INTSAFE_H_INCLUDED_
+#define _INTSAFE_H_INCLUDED_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif
+
+#include <specstrings.h> // for IN, etc.
+
+
+#if defined(_AMD64_)
+#ifdef __cplusplus
+extern "C" {
+#endif
+#define UnsignedMultiply128 _umul128
+ULONG64
+UnsignedMultiply128 (
+ IN ULONG64 Multiplier,
+ IN ULONG64 Multiplicand,
+ OUT ULONG64 *HighProduct
+ );
+#ifdef _MSC_VER
+#pragma intrinsic(_umul128)
+#endif // _MSC_VER
+#ifdef __cplusplus
+}
+#endif
+#endif // _AMD64_
+
+#ifndef FEATURE_PAL
+
+#ifdef _WIN64
+typedef unsigned __int64 size_t;
+typedef unsigned __int64 UINT_PTR;
+typedef unsigned __int64 ULONG_PTR;
+typedef unsigned __int64 DWORD_PTR;
+typedef unsigned __int64 SIZE_T;
+#else
+typedef __w64 unsigned int size_t;
+typedef __w64 unsigned int UINT_PTR;
+typedef __w64 unsigned long ULONG_PTR;
+typedef __w64 unsigned long DWORD_PTR;
+typedef __w64 unsigned long SIZE_T;
+#endif
+typedef char CHAR;
+typedef int INT;
+typedef long LONG;
+typedef unsigned char UCHAR;
+typedef unsigned short USHORT;
+typedef unsigned short WORD;
+typedef unsigned int UINT;
+typedef unsigned long ULONG;
+typedef unsigned long DWORD;
+typedef unsigned __int64 ULONGLONG;
+
+
+typedef LONG HRESULT;
+
+#ifndef SUCCEEDED
+#define SUCCEEDED(hr) (((HRESULT)(hr)) >= 0)
+#endif
+
+#ifndef FAILED
+#define FAILED(hr) (((HRESULT)(hr)) < 0)
+#endif
+
+#define S_OK ((HRESULT)0x00000000L)
+
+#endif // !FEATURE_PAL
+
+#define INTSAFE_E_ARITHMETIC_OVERFLOW ((HRESULT)0x80070216L) // 0x216 = 534 = ERROR_ARITHMETIC_OVERFLOW
+
+#ifndef LOWORD
+#define LOWORD(l) ((WORD)(((DWORD_PTR)(l)) & 0xffff))
+#endif
+
+#ifndef HIWORD
+#define HIWORD(l) ((WORD)(((DWORD_PTR)(l)) >> 16))
+#endif
+
+#define HIDWORD(_qw) ((ULONG)((_qw) >> 32))
+#define LODWORD(_qw) ((ULONG)(_qw))
+
+#if defined(MIDL_PASS) || defined(RC_INVOKED) || defined(_M_CEE_PURE) \
+ || defined(_68K_) || defined(_MPPC_) || defined(_PPC_) \
+ || defined(_M_IA64) || defined(_M_AMD64) || defined(__ARM_ARCH)
+
+#ifndef UInt32x32To64
+#define UInt32x32To64(a, b) ((unsigned __int64)((ULONG)(a)) * (unsigned __int64)((ULONG)(b)))
+#endif
+
+#elif defined(_M_IX86)
+
+#ifndef UInt32x32To64
+#define UInt32x32To64(a, b) (unsigned __int64)((unsigned __int64)(ULONG)(a) * (ULONG)(b))
+#endif
+
+#else
+
+#error Must define a target architecture.
+
+#endif
+
+#define INT_MAX 2147483647
+#define LONG_MAX 2147483647L
+#define USHRT_MAX 0xffff
+#define UINT_MAX 0xffffffff
+#define ULONG_MAX 0xffffffffUL
+#define DWORD_MAX 0xffffffffUL
+
+//
+// It is common for -1 to be used as an error value for various types
+//
+#define USHORT_ERROR (0xffff)
+#define INT_ERROR (-1)
+#define LONG_ERROR (-1L)
+#define UINT_ERROR (0xffffffff)
+#define ULONG_ERROR (0xffffffffUL)
+#ifdef _MSC_VER
+#define ULONGLONG_ERROR (0xffffffffffffffffui64)
+#define HIDWORD_MASK (0xffffffff00000000ui64)
+#else // _MSC_VER
+#define ULONGLONG_ERROR (0xffffffffffffffffULL)
+#define HIDWORD_MASK (0xffffffff00000000ULL)
+#endif // _MSC_VER
+#ifdef _WIN64
+#define SIZET_ERROR ULONGLONG_ERROR
+#else
+#define SIZET_ERROR ULONG_ERROR
+#endif
+
+//
+// We make some assumptions about the sizes of various types. Let's be
+// explicit about those assumptions and check them.
+//
+C_ASSERT(sizeof(unsigned short) == 2);
+C_ASSERT(sizeof(unsigned int) == 4);
+C_ASSERT(sizeof(ULONG) == 4);
+
+//
+// INT -> signed char conversion
+//
+__inline
+HRESULT
+IntToSignedChar(
+ IN INT iOperand,
+ OUT signed char* pch)
+{
+ HRESULT hr = INTSAFE_E_ARITHMETIC_OVERFLOW;
+ *pch = 0;
+
+ if ((iOperand >= -128) && (iOperand <= 127))
+ {
+ *pch = (signed char)iOperand;
+ hr = S_OK;
+ }
+
+ return hr;
+}
+
+//
+// INT -> UCHAR conversion
+//
+__inline
+HRESULT
+IntToUChar(
+ IN INT iOperand,
+ OUT UCHAR* pch)
+{
+ HRESULT hr = INTSAFE_E_ARITHMETIC_OVERFLOW;
+ *pch = 0;
+
+ if ((iOperand >= 0) && (iOperand <= 255))
+ {
+ *pch = (UCHAR)iOperand;
+ hr = S_OK;
+ }
+
+ return hr;
+}
+
+//
+// LONG -> UCHAR conversion
+//
+__inline
+HRESULT
+LongToUChar(
+ IN LONG lOperand,
+ OUT UCHAR* pch)
+{
+ HRESULT hr = INTSAFE_E_ARITHMETIC_OVERFLOW;
+ *pch = 0;
+
+ if ((lOperand >= 0) && (lOperand <= 255))
+ {
+ *pch = (UCHAR)lOperand;
+ hr = S_OK;
+ }
+
+ return hr;
+}
+
+//
+// __inline is not sufficient. __forceinline is necessary.
+// If the function is not inlined and you link .objs compiled with different compiler switches,
+// you get one or the other function arbitrarily chosen.
+//
+// INT -> CHAR conversion
+//
+__forceinline
+HRESULT
+IntToChar(
+ IN INT iOperand,
+ OUT CHAR* pch)
+{
+#ifdef _CHAR_UNSIGNED
+ return IntToUChar(iOperand, (UCHAR*)pch);
+#else
+ return IntToSignedChar(iOperand, (signed char*)pch);
+#endif
+}
+
+//
+// INT -> USHORT conversion
+//
+__inline
+HRESULT
+IntToUShort(
+ IN INT iOperand,
+ OUT USHORT* pusResult)
+{
+ HRESULT hr = INTSAFE_E_ARITHMETIC_OVERFLOW;
+ *pusResult = USHORT_ERROR;
+
+ if ((iOperand >= 0) && (iOperand <= USHRT_MAX))
+ {
+ *pusResult = (USHORT)iOperand;
+ hr = S_OK;
+ }
+
+ return hr;
+}
+
+//
+// INT -> UINT conversion
+//
+__inline
+HRESULT
+IntToUInt(
+ IN INT iOperand,
+ OUT UINT* puResult)
+{
+ HRESULT hr = INTSAFE_E_ARITHMETIC_OVERFLOW;
+ *puResult = UINT_ERROR;
+
+ if (iOperand >= 0)
+ {
+ *puResult = (UINT)iOperand;
+ hr = S_OK;
+ }
+
+ return hr;
+}
+
+//
+// INT -> ULONG conversion
+//
+__inline
+HRESULT
+IntToULong(
+ IN INT iOperand,
+ OUT ULONG* pulResult)
+{
+ HRESULT hr = INTSAFE_E_ARITHMETIC_OVERFLOW;
+ *pulResult = ULONG_ERROR;
+
+ if (iOperand >= 0)
+ {
+ *pulResult = (ULONG)iOperand;
+ hr = S_OK;
+ }
+
+ return hr;
+}
+
+//
+// INT -> ULONGLONG conversion
+//
+__inline
+HRESULT
+IntToULongLong(
+ IN INT iOperand,
+ OUT ULONGLONG* pullResult)
+{
+ HRESULT hr = INTSAFE_E_ARITHMETIC_OVERFLOW;
+ *pullResult = ULONG_ERROR;
+
+ if (iOperand >= 0)
+ {
+ *pullResult = (ULONGLONG)iOperand;
+ hr = S_OK;
+ }
+
+ return hr;
+}
+
+//
+// UINT -> signed char conversion
+//
+__inline
+HRESULT
+UIntToSignedChar(
+ IN UINT uOperand,
+ OUT signed char* pch)
+{
+ HRESULT hr = INTSAFE_E_ARITHMETIC_OVERFLOW;
+ *pch = 0;
+
+ if (uOperand <= 127)
+ {
+ *pch = (signed char)uOperand;
+ hr = S_OK;
+ }
+
+ return hr;
+}
+
+//
+// UINT -> UCHAR conversion
+//
+__inline
+HRESULT
+UIntToUChar(
+ IN UINT uOperand,
+ OUT UCHAR* pch)
+{
+ HRESULT hr = INTSAFE_E_ARITHMETIC_OVERFLOW;
+ *pch = 0;
+
+ if (uOperand <= 255)
+ {
+ *pch = (UCHAR)uOperand;
+ hr = S_OK;
+ }
+
+ return hr;
+}
+
+//
+// UINT -> BYTE conversion
+//
+#define UIntToByte UIntToUChar
+
+//
+// __inline is not sufficient. __forceinline is necessary.
+// If the function is not inlined and you link .objs compiled with different compiler switches,
+// you get one or the other function arbitrarily chosen.
+//
+// UINT -> CHAR conversion
+//
+__forceinline
+HRESULT
+UIntToChar(
+ IN UINT uOperand,
+ OUT CHAR* pch)
+{
+#ifdef _CHAR_UNSIGNED
+ return UIntToUChar(uOperand, (UCHAR*)pch);
+#else
+ return UIntToSignedChar(uOperand, (signed char*)pch);
+#endif // _CHAR_UNSIGNED
+}
+
+//
+// UINT -> INT conversion
+//
+__inline
+HRESULT
+UIntToInt(
+ IN UINT uOperand,
+ OUT INT* piResult)
+{
+ HRESULT hr = INTSAFE_E_ARITHMETIC_OVERFLOW;
+ *piResult = INT_ERROR;
+
+ if (uOperand <= INT_MAX)
+ {
+ *piResult = (INT)uOperand;
+ hr = S_OK;
+ }
+
+ return hr;
+}
+
+//
+// UINT -> LONG conversion
+//
+__inline
+HRESULT
+UIntToLong(
+ IN UINT Operand,
+ OUT LONG* Result)
+{
+ if (Operand <= LONG_MAX)
+ {
+ *Result = (LONG)Operand;
+ return S_OK;
+ }
+ else
+ {
+ *Result = LONG_ERROR;
+ return INTSAFE_E_ARITHMETIC_OVERFLOW;
+ }
+}
+
+//
+// UINT -> ULONG conversion
+//
+__inline
+HRESULT
+UIntToULong(
+ IN UINT uOperand,
+ OUT ULONG* pulResult)
+{
+ *pulResult = (ULONG)uOperand;
+
+ return S_OK;
+}
+
+//
+// ULONG -> UCHAR conversion
+//
+__inline
+HRESULT
+ULongToSignedChar(
+ IN ULONG ulOperand,
+ OUT signed char* pch)
+{
+ HRESULT hr = INTSAFE_E_ARITHMETIC_OVERFLOW;
+ *pch = 0;
+
+ if (ulOperand <= 127)
+ {
+ *pch = (signed char)ulOperand;
+ hr = S_OK;
+ }
+
+ return hr;
+}
+
+//
+// ULONG -> UCHAR conversion
+//
+__inline
+HRESULT
+ULongToUChar(
+ IN ULONG ulOperand,
+ OUT unsigned char* pch)
+{
+ HRESULT hr = INTSAFE_E_ARITHMETIC_OVERFLOW;
+ *pch = 0;
+
+ if (ulOperand <= 255)
+ {
+ *pch = (unsigned char)ulOperand;
+ hr = S_OK;
+ }
+
+ return hr;
+}
+
+//
+// __inline is not sufficient. __forceinline is necessary.
+// If the function is not inlined and you link .objs compiled with different compiler switches,
+// you get one or the other function arbitrarily chosen.
+//
+// ULONG -> CHAR conversion
+//
+__forceinline
+HRESULT
+ULongToChar(
+ IN ULONG ulOperand,
+ OUT CHAR* pch)
+{
+#ifdef _CHAR_UNSIGNED
+ return ULongToUChar(ulOperand, (unsigned char*)pch);
+#else
+ return ULongToSignedChar(ulOperand, (signed char*)pch);
+#endif // _CHAR_UNSIGNED
+}
+
+//
+// ULONG -> USHORT conversion
+//
+__inline
+HRESULT
+ULongToUShort(
+ IN ULONG ulOperand,
+ OUT USHORT* pusResult)
+{
+ HRESULT hr = INTSAFE_E_ARITHMETIC_OVERFLOW;
+ *pusResult = USHORT_ERROR;
+
+ if (ulOperand <= USHRT_MAX)
+ {
+ *pusResult = (USHORT)ulOperand;
+ hr = S_OK;
+ }
+
+ return hr;
+}
+
+//
+// ULONG -> INT conversion
+//
+__inline
+HRESULT
+ULongToInt(
+ IN ULONG ulOperand,
+ OUT INT* piResult)
+{
+ if (ulOperand <= INT_MAX)
+ {
+ *piResult = (INT)ulOperand;
+ return S_OK;
+ }
+ else
+ {
+ *piResult = INT_ERROR;
+ return INTSAFE_E_ARITHMETIC_OVERFLOW;
+ }
+}
+
+//
+// ULONG -> UINT conversion
+//
+__inline
+HRESULT
+ULongToUInt(
+ IN ULONG ulOperand,
+ OUT UINT* puResult)
+{
+ *puResult = (UINT)ulOperand;
+
+ return S_OK;
+}
+
+//
+// ULONG -> LONG conversion
+//
+__inline
+HRESULT
+ULongToLong(
+ IN ULONG Operand,
+ OUT LONG* Result)
+{
+ if (Operand <= LONG_MAX)
+ {
+ *Result = (LONG)Operand;
+ return S_OK;
+ }
+ else
+ {
+ *Result = LONG_ERROR;
+ return INTSAFE_E_ARITHMETIC_OVERFLOW;
+ }
+}
+
+//
+// ULONGLONG -> INT conversion
+//
+__inline
+HRESULT
+ULongLongToInt(
+ IN ULONGLONG ullOperand,
+ OUT INT* piResult)
+{
+ if (ullOperand <= INT_MAX)
+ {
+ *piResult = (INT)ullOperand;
+ return S_OK;
+ }
+ else
+ {
+ *piResult = INT_ERROR;
+ return INTSAFE_E_ARITHMETIC_OVERFLOW;
+ }
+}
+
+//
+// ULONGLONG -> LONG conversion
+//
+__inline
+HRESULT
+ULongLongToLong(
+ IN ULONGLONG Operand,
+ OUT LONG* Result)
+{
+ if (Operand <= LONG_MAX)
+ {
+ *Result = (LONG)Operand;
+ return S_OK;
+ }
+ else
+ {
+ *Result = LONG_ERROR;
+ return INTSAFE_E_ARITHMETIC_OVERFLOW;
+ }
+}
+
+//
+// UINT -> USHORT conversion
+//
+__inline
+HRESULT
+UIntToUShort(
+ IN UINT uOperand,
+ OUT USHORT* pusResult)
+{
+ HRESULT hr = INTSAFE_E_ARITHMETIC_OVERFLOW;
+ *pusResult = USHORT_ERROR;
+
+ if (uOperand <= USHRT_MAX)
+ {
+ *pusResult = (USHORT)uOperand;
+ hr = S_OK;
+ }
+
+ return hr;
+}
+
+//
+// ULONGLONG -> USHORT conversion
+//
+__inline
+HRESULT
+ULongLongToUShort(
+ IN ULONGLONG ullOperand,
+ OUT USHORT* pusResult)
+{
+ HRESULT hr = INTSAFE_E_ARITHMETIC_OVERFLOW;
+ USHORT usResult = USHORT_ERROR;
+
+ if (ullOperand <= USHRT_MAX)
+ {
+ usResult = (USHORT)ullOperand;
+ hr = S_OK;
+ }
+ *pusResult = usResult;
+
+ return hr;
+}
+
+//
+// ULONGLONG -> ULONG conversion
+//
+__inline
+HRESULT
+ULongLongToULong(
+ IN ULONGLONG ullOperand,
+ OUT ULONG* pulResult)
+{
+ HRESULT hr = INTSAFE_E_ARITHMETIC_OVERFLOW;
+ *pulResult = ULONG_ERROR;
+
+ if (ullOperand <= ULONG_MAX)
+ {
+ *pulResult = (ULONG)ullOperand;
+ hr = S_OK;
+ }
+
+ return hr;
+}
+
+//
+// UINT_PTR -> ULONG conversion
+// ULONG_PTR -> ULONG conversion
+//
+#ifdef _WIN64
+
+#define UIntPtrToULong ULongLongToULong
+#define ULongPtrToULong ULongLongToULong
+
+#else
+
+__inline
+HRESULT
+UIntPtrToULong(
+ IN UINT_PTR Operand,
+ OUT ULONG* pResult)
+{
+ *pResult = (ULONG)Operand;
+ return S_OK;
+}
+
+__inline
+HRESULT
+ULongPtrToULong(
+ IN ULONG_PTR Operand,
+ OUT ULONG* pResult)
+{
+ *pResult = (ULONG)Operand;
+ return S_OK;
+}
+
+#endif
+
+//
+// ULONGLONG -> UINT conversion
+//
+__inline
+HRESULT
+ULongLongToUInt(
+ IN ULONGLONG ullOperand,
+ OUT UINT* puResult)
+{
+ HRESULT hr = INTSAFE_E_ARITHMETIC_OVERFLOW;
+ *puResult = UINT_ERROR;
+
+ if (ullOperand <= UINT_MAX)
+ {
+ *puResult = (UINT)ullOperand;
+ hr = S_OK;
+ }
+
+ return hr;
+}
+
+//
+// UINT_PTR -> UINT conversion
+// ULONG_PTR -> UINT conversion
+//
+#ifdef _WIN64
+
+#define UIntPtrToUInt ULongLongToUInt
+#define ULongPtrToUInt ULongLongToUInt
+
+#else
+
+__inline
+HRESULT
+UIntPtrToUInt(
+ IN UINT_PTR Operand,
+ OUT UINT* pResult)
+{
+ *pResult = (UINT)Operand;
+ return S_OK;
+}
+
+__inline
+HRESULT
+ULongPtrToUInt(
+ IN ULONG_PTR Operand,
+ OUT UINT* pResult)
+{
+ *pResult = (UINT)Operand;
+ return S_OK;
+}
+
+#endif
+
+//
+// * -> BYTE conversion (BYTE is always unsigned char)
+//
+#define IntToByte IntToUChar
+#define UIntToByte UIntToUChar
+#define LongToByte LongToUChar
+#define ULongToByte ULongToUChar
+
+//
+// * -> WORD conversion (WORD is always unsigned short)
+//
+#define IntToWord IntToUShort
+#define LongToWord LongToUShort
+#define LongLongToWord LongLongToUShort
+#define UIntToWord UIntToUShort
+#define ULongToWord ULongToUShort
+#define ULongLongToWord ULongLongToUShort
+#define UIntPtrToWord UIntPtrToUShort
+#define ULongPtrToWord ULongPtrToUShort
+#define SizeTToWord SizeTToUShort
+#define SIZETToWord SIZETToUShort
+
+//
+// WORD -> * conversion (WORD is always unsigned short)
+//
+#define WordToUChar UShortToUChar
+#define WordToByte UShortToByte
+#define WordToChar UShortToChar
+#define WordToSignedChar UShortToSignedChar
+#define WordToInt UShortToInt
+#define WordToLong UShortToLong
+#define WordToLongLong UShortToLongLong
+#define WordToIntPtr UShortToIntPtr
+#define WordToLongPtr UShortToLongPtr
+
+//
+// * -> DWORD conversion (DWORD is always ULONG)
+//
+#define CharToDWord CharToULong
+#define SignedCharToDWord SignedCharToULong
+#define ShortToDWord ShortToULong
+#define IntToDWord IntToULong
+#define LongToDWord LongToULong
+#define LongLongToDWord LongLongToULong
+#define UIntToDWord UIntToULong
+#define ULongLongToDWord ULongLongToULong
+#define IntPtrToDWord IntPtrToULong
+#define LongPtrToDWord LongPtrToULong
+#define UIntPtrToDWord UIntPtrToULong
+#define ULongPtrToDWord ULongPtrToULong
+#define SizeTToDWord SizeTToULong
+#define SIZETToDWord SIZETToULong
+
+//
+// DWORD -> * conversion (DWORD is always ULONG)
+//
+#define DWordToChar ULongToChar
+#define DWordToUChar ULongToUChar
+#define DWordToByte ULongToByte
+#define DWordToSignedChar ULongToSignedChar
+#define DWordToUShort ULongToUShort
+#define DWordToUInt ULongToUInt
+#define DWordToInt ULongToInt
+#define DWordToLong ULongToLong
+#define DWordToLongLong ULongToLongLong
+#define DWordToIntPtr ULongToIntPtr
+#define DWordToLongPtr ULongToLongPtr
+
+
+//
+// * -> UINT_PTR conversion (UINT_PTR is UINT on Win32, ULONGLONG on Win64)
+//
+#ifdef _WIN64
+#define CharToUIntPtr CharToULongLong
+#define SignedCharToUIntPtr SignedCharToULongLong
+#define ShortToUIntPtr ShortToULongLong
+#define IntToUIntPtr IntToULongLong
+#define LongToUIntPtr LongToULongLong
+#define LongLongToUIntPtr LongLongToULongLong
+#define IntPtrToUIntPtr IntPtrToULongLong
+#define LongPtrToUIntPtr LongPtrToULongLong
+#else
+#define CharToUIntPtr CharToUInt
+#define SignedCharToUIntPtr SignedCharToUInt
+#define ShortToUIntPtr ShortToUInt
+
+__inline
+HRESULT
+IntToUIntPtr(
+ IN INT iOperand,
+ OUT UINT_PTR* puResult)
+{
+ return IntToUInt(iOperand, (UINT*)puResult);
+}
+
+#define LongToUIntPtr LongToUInt
+#define LongLongToUIntPtr LongLongToUInt
+
+#define IntPtrToUIntPtr IntPtrToUInt
+#define LongPtrToUIntPtr LongPtrToUInt
+#endif
+
+__inline
+HRESULT
+ULongLongToUIntPtr(
+ IN ULONGLONG ullOperand,
+ OUT UINT_PTR* puResult)
+{
+#ifdef _WIN64
+ *puResult = ullOperand;
+ return S_OK;
+#else
+ return ULongLongToUInt(ullOperand, (UINT*)puResult);
+#endif
+}
+
+
+//
+// UINT_PTR -> * conversion (UINT_PTR is UINT on Win32, ULONGLONG on Win64)
+//
+#ifdef _WIN64
+#define UIntPtrToUShort ULongLongToUShort
+#define UIntPtrToInt ULongLongToInt
+#define UIntPtrToLong ULongLongToLong
+#define UIntPtrToLongLong ULongLongToLongLong
+#define UIntPtrToIntPtr ULongLongToIntPtr
+#define UIntPtrToLongPtr ULongLongToLongPtr
+#else
+
+__inline
+HRESULT
+UIntPtrToUShort(
+ IN UINT_PTR uOperand,
+ OUT USHORT* pusResult)
+{
+ return UIntToUShort((UINT)uOperand, pusResult);
+}
+
+__inline
+HRESULT
+UIntPtrToInt(
+ IN UINT_PTR uOperand,
+ OUT INT* piResult)
+{
+ return UIntToInt((UINT)uOperand, piResult);
+}
+
+__inline
+HRESULT
+UIntPtrToLong(
+ IN UINT_PTR Operand,
+ OUT LONG* Result)
+{
+ return UIntToLong((UINT)Operand, Result);
+}
+
+#define UIntPtrToLongLong UIntToLongLong
+#define UIntPtrToIntPtr UIntToIntPtr
+#define UIntPtrToLongPtr UIntToLongPtr
+#endif
+
+
+//
+// * -> ULONG_PTR conversion (ULONG_PTR is ULONG on Win32, ULONGLONG on Win64)
+//
+#ifdef _WIN64
+#define CharToULongPtr CharToULongLong
+#define SignedCharToULongPtr SignedCharToULongLong
+#define ShortToULongPtr ShortToULongLong
+#define IntToULongPtr IntToULongLong
+#define LongToULongPtr LongToULongLong
+#define LongLongToULongPtr LongLongToULongLong
+#define IntPtrToULongPtr IntPtrToULongLong
+#define LongPtrToULongPtr LongPtrToULongLong
+#else
+#define CharToULongPtr CharToULong
+#define SignedCharToULongPtr SignedCharToULong
+#define ShortToULongPtr ShortToULong
+
+__inline
+HRESULT
+IntToULongPtr(
+ IN INT iOperand,
+ OUT ULONG_PTR* pulResult)
+{
+ return IntToULong(iOperand, (ULONG*)pulResult);
+}
+
+#define LongToULongPtr LongToULong
+#define LongLongToULongPtr LongLongToULong
+
+#define IntPtrToULongPtr IntPtrToULong
+#define LongPtrToULongPtr LongPtrToULong
+#endif
+
+__inline
+HRESULT
+ULongLongToULongPtr(
+ IN ULONGLONG ullOperand,
+ OUT ULONG_PTR* pulResult)
+{
+#ifdef _WIN64
+ *pulResult = ullOperand;
+ return S_OK;
+#else
+ return ULongLongToULong(ullOperand, (ULONG*)pulResult);
+#endif
+}
+
+
+//
+// ULONG_PTR -> * conversion (ULONG_PTR is ULONG on Win32, ULONGLONG on Win64)
+//
+#ifdef _WIN64
+#define ULongPtrToUShort ULongLongToUShort
+#define ULongPtrToInt ULongLongToInt
+#define ULongPtrToLong ULongLongToLong
+#define ULongPtrToLongLong ULongLongToLongLong
+#define ULongPtrToIntPtr ULongLongToIntPtr
+#define ULongPtrToLongPtr ULongLongToLongPtr
+#else
+
+__inline
+HRESULT
+ULongPtrToUShort(
+ IN ULONG_PTR ulOperand,
+ OUT USHORT* pusResult)
+{
+ return ULongToUShort((ULONG)ulOperand, pusResult);
+}
+
+__inline
+HRESULT
+ULongPtrToInt(
+ IN ULONG_PTR ulOperand,
+ OUT INT* piResult)
+{
+ return ULongToInt((ULONG)ulOperand, piResult);
+}
+
+__inline
+HRESULT
+ULongPtrToLong(
+ IN ULONG_PTR Operand,
+ OUT LONG* Result)
+{
+ return ULongToLong((ULONG)Operand, Result);
+}
+
+#define ULongPtrToLongLong ULongToLongLong
+#define ULongPtrToIntPtr ULongToIntPtr
+#define ULongPtrToLongPtr ULongToLongPtr
+#endif
+
+//
+// * -> size_t conversion (size_t is always UINT_PTR)
+//
+#define CharToSizeT CharToUIntPtr
+#define SignedCharToSizeT SignedCharToUIntPtr
+#define ShortToSizeT ShortToUIntPtr
+#define IntToSizeT IntToUIntPtr
+#define LongToSizeT LongToUIntPtr
+#define LongLongToSizeT LongLongToUIntPtr
+#define ULongLongToSizeT ULongLongToUIntPtr
+#define IntPtrToSizeT IntPtrToUIntPtr
+#define LongPtrToSizeT LongPtrToUIntPtr
+
+//
+// size_t -> * conversion (size_t is always UINT_PTR)
+//
+#define SizeTToUShort UIntPtrToUShort
+#define SizeTToUInt UIntPtrToUInt
+#define SizeTToULong UIntPtrToULong
+#define SizeTToInt UIntPtrToInt
+#define SizeTToLong UIntPtrToLong
+#define SizeTToLongLong UIntPtrToLongLong
+#define SizeTToIntPtr UIntPtrToIntPtr
+#define SizeTToLongPtr UIntPtrToLongPtr
+
+//
+// * -> SIZE_T conversion (SIZE_T is always ULONG_PTR)
+//
+#define CharToSIZET CharToULongPtr
+#define SignedCharToSIZET SignedCharToULongPtr
+#define ShortToSIZET ShortToULongPtr
+#define IntToSIZET IntToULongPtr
+#define LongToSIZET LongToULongPtr
+#define LongLongToSIZET LongLongToULongPtr
+#define IntPtrToSIZET IntPtrToULongPtr
+#define LongPtrToSIZET LongPtrToULongPtr
+#define ULongLongToSIZET ULongLongToULongPtr
+
+//
+// SIZE_T -> * conversion (SIZE_T is always ULONG_PTR)
+//
+#define SIZETToUShort ULongPtrToUShort
+#define SIZETToUInt ULongPtrToUInt
+#define SIZETToULong ULongPtrToULong
+#define SIZETToUIntPtr ULongPtrToUIntPtr
+#define SIZETToULongPtr ULongPtrToULongPtr
+#define SIZETToInt ULongPtrToInt
+#define SIZETToLong ULongPtrToLong
+#define SIZETToLongLong ULongPtrToLongLong
+#define SIZETToIntPtr ULongPtrToIntPtr
+#define SIZETToLongPtr ULongPtrToLongPtr
+
+//
+// * -> DWORD_PTR conversion (DWORD_PTR is always ULONG_PTR)
+//
+#define CharToDWordPtr CharToULongPtr
+#define SignedCharToDWordPtr SignedCharToULongPtr
+#define ShortToDWordPtr ShortToULongPtr
+#define IntToDWordPtr IntToULongPtr
+#define LongToDWordPtr LongToULongPtr
+#define LongLongToDWordPtr LongLongToULongPtr
+#define ULongLongToDWordPtr ULongLongToULongPtr
+#define IntPtrToDWordPtr IntPtrToULongPtr
+#define LongPtrToDWordPtr LongPtrToULongPtr
+
+//
+// DWORD_PTR -> * conversion (DWORD_PTR is always ULONG_PTR)
+//
+#define DWordPtrToUShort ULongPtrToUShort
+#define DWordPtrToUInt ULongPtrToUInt
+#define DWordPtrToULong ULongPtrToULong
+#define DWordPtrToDWord ULongPtrToDWord
+#define DWordPtrToInt ULongPtrToInt
+#define DWordPtrToLong ULongPtrToLong
+#define DWordPtrToLongLong ULongPtrToLongLong
+#define DWordPtrToIntPtr ULongPtrToIntPtr
+#define DWordPtrToLongPtr ULongPtrToLongPtr
+
+//
+// USHORT addition
+//
+__inline
+HRESULT
+UShortAdd(
+ IN USHORT usAugend,
+ IN USHORT usAddend,
+ OUT USHORT* pusResult)
+{
+ HRESULT hr = INTSAFE_E_ARITHMETIC_OVERFLOW;
+ *pusResult = USHORT_ERROR;
+
+ if (((USHORT)(usAugend + usAddend)) >= usAugend)
+ {
+ *pusResult = (usAugend + usAddend);
+ hr = S_OK;
+ }
+
+ return hr;
+}
+
+//
+// WORD addtition
+//
+#define WordAdd UShortAdd
+
+//
+// UINT addition
+//
+__inline
+HRESULT
+UIntAdd(
+ IN UINT uAugend,
+ IN UINT uAddend,
+ OUT UINT* puResult)
+{
+ HRESULT hr = INTSAFE_E_ARITHMETIC_OVERFLOW;
+ *puResult = UINT_ERROR;
+
+ if ((uAugend + uAddend) >= uAugend)
+ {
+ *puResult = (uAugend + uAddend);
+ hr = S_OK;
+ }
+
+ return hr;
+}
+
+//
+// UINT_PTR addition
+//
+#define UIntPtrAdd SizeTAdd
+
+//
+// ULONG addition
+//
+__inline
+HRESULT
+ULongAdd(
+ IN ULONG ulAugend,
+ IN ULONG ulAddend,
+ OUT ULONG* pulResult)
+{
+ HRESULT hr = INTSAFE_E_ARITHMETIC_OVERFLOW;
+ *pulResult = ULONG_ERROR;
+
+ if ((ulAugend + ulAddend) >= ulAugend)
+ {
+ *pulResult = (ulAugend + ulAddend);
+ hr = S_OK;
+ }
+
+ return hr;
+}
+
+//
+// ULONG_PTR addition
+//
+#ifdef _WIN64
+#define ULongPtrAdd ULongLongAdd
+#else
+__inline
+HRESULT
+ULongPtrAdd(
+ IN ULONG_PTR ulAugend,
+ IN ULONG_PTR ulAddend,
+ OUT ULONG_PTR* pulResult)
+{
+ return ULongAdd((ULONG)ulAugend, (ULONG)ulAddend, (ULONG*)pulResult);
+}
+#endif // _WIN64
+
+//
+// DWORD addition
+//
+#define DWordAdd ULongAdd
+
+//
+// DWORD_PTR addition
+//
+#define DWordPtrAdd ULongPtrAdd
+
+//
+// size_t addition
+//
+__inline
+HRESULT
+SizeTAdd(
+ IN size_t Augend,
+ IN size_t Addend,
+ OUT size_t* pResult)
+{
+ HRESULT hr = INTSAFE_E_ARITHMETIC_OVERFLOW;
+ *pResult = SIZET_ERROR;
+
+ if ((Augend + Addend) >= Augend)
+ {
+ *pResult = (Augend + Addend);
+ hr = S_OK;
+ }
+
+ return hr;
+}
+
+//
+// SIZE_T addition
+//
+#define SIZETAdd ULongPtrAdd
+
+//
+// ULONGLONG addition
+//
+__inline
+HRESULT
+ULongLongAdd(
+ IN ULONGLONG ullAugend,
+ IN ULONGLONG ullAddend,
+ OUT ULONGLONG* pullResult)
+{
+ HRESULT hr = INTSAFE_E_ARITHMETIC_OVERFLOW;
+ *pullResult = ULONGLONG_ERROR;
+
+ if ((ullAugend + ullAddend) >= ullAugend)
+ {
+ *pullResult = (ullAugend + ullAddend);
+ hr = S_OK;
+ }
+
+ return hr;
+}
+
+//
+// USHORT subtraction
+//
+__inline
+HRESULT
+UShortSub(
+ IN USHORT usMinuend,
+ IN USHORT usSubtrahend,
+ OUT USHORT* pusResult)
+{
+ HRESULT hr = INTSAFE_E_ARITHMETIC_OVERFLOW;
+ *pusResult = USHORT_ERROR;
+
+ if (usMinuend >= usSubtrahend)
+ {
+ *pusResult = (usMinuend - usSubtrahend);
+ hr = S_OK;
+ }
+
+ return hr;
+}
+
+//
+// WORD subtraction
+//
+#define WordSub UShortSub
+
+
+//
+// UINT subtraction
+//
+__inline
+HRESULT
+UIntSub(
+ IN UINT uMinuend,
+ IN UINT uSubtrahend,
+ OUT UINT* puResult)
+{
+ HRESULT hr = INTSAFE_E_ARITHMETIC_OVERFLOW;
+ *puResult = UINT_ERROR;
+
+ if (uMinuend >= uSubtrahend)
+ {
+ *puResult = (uMinuend - uSubtrahend);
+ hr = S_OK;
+ }
+
+ return hr;
+}
+
+//
+// UINT_PTR subtraction
+//
+#define UIntPtrSub SizeTSub
+
+//
+// ULONG subtraction
+//
+__inline
+HRESULT
+ULongSub(
+ IN ULONG ulMinuend,
+ IN ULONG ulSubtrahend,
+ OUT ULONG* pulResult)
+{
+ HRESULT hr = INTSAFE_E_ARITHMETIC_OVERFLOW;
+ *pulResult = ULONG_ERROR;
+
+ if (ulMinuend >= ulSubtrahend)
+ {
+ *pulResult = (ulMinuend - ulSubtrahend);
+ hr = S_OK;
+ }
+
+ return hr;
+}
+
+//
+// ULONG_PTR subtraction
+//
+#ifdef _WIN64
+#define ULongPtrSub ULongLongSub
+#else
+__inline
+HRESULT
+ULongPtrSub(
+ IN ULONG_PTR ulMinuend,
+ IN ULONG_PTR ulSubtrahend,
+ OUT ULONG_PTR* pulResult)
+{
+ return ULongSub((ULONG)ulMinuend, (ULONG)ulSubtrahend, (ULONG*)pulResult);
+}
+#endif // _WIN64
+
+
+//
+// DWORD subtraction
+//
+#define DWordSub ULongSub
+
+//
+// DWORD_PTR subtraction
+//
+#define DWordPtrSub ULongPtrSub
+
+//
+// size_t subtraction
+//
+__inline
+HRESULT
+SizeTSub(
+ IN size_t Minuend,
+ IN size_t Subtrahend,
+ OUT size_t* pResult)
+{
+ HRESULT hr = INTSAFE_E_ARITHMETIC_OVERFLOW;
+ *pResult = SIZET_ERROR;
+
+ if (Minuend >= Subtrahend)
+ {
+ *pResult = (Minuend - Subtrahend);
+ hr = S_OK;
+ }
+
+ return hr;
+}
+
+//
+// SIZE_T subtraction
+//
+#define SIZETSub ULongPtrSub
+
+//
+// ULONGLONG subtraction
+//
+__inline
+HRESULT
+ULongLongSub(
+ IN ULONGLONG ullMinuend,
+ IN ULONGLONG ullSubtrahend,
+ OUT ULONGLONG* pullResult)
+{
+ HRESULT hr = INTSAFE_E_ARITHMETIC_OVERFLOW;
+ *pullResult = ULONGLONG_ERROR;
+
+ if (ullMinuend >= ullSubtrahend)
+ {
+ *pullResult = (ullMinuend - ullSubtrahend);
+ hr = S_OK;
+ }
+
+ return hr;
+}
+
+//
+// USHORT multiplication
+//
+__inline
+HRESULT
+UShortMult(
+ IN USHORT usMultiplicand,
+ IN USHORT usMultiplier,
+ OUT USHORT* pusResult)
+{
+ ULONG ulResult = ((ULONG)usMultiplicand) * (ULONG)usMultiplier;
+
+ return ULongToUShort(ulResult, pusResult);
+}
+
+//
+// WORD multiplication
+//
+#define WordMult UShortMult
+
+//
+// UINT multiplication
+//
+__inline
+HRESULT
+UIntMult(
+ IN UINT uMultiplicand,
+ IN UINT uMultiplier,
+ OUT UINT* puResult)
+{
+ ULONGLONG ull64Result = UInt32x32To64(uMultiplicand, uMultiplier);
+
+ return ULongLongToUInt(ull64Result, puResult);
+}
+
+//
+// UINT_PTR multiplication
+//
+#ifdef _WIN64
+#define UIntPtrMult ULongLongMult
+#else
+__inline
+HRESULT
+UIntPtrMult(
+ IN UINT_PTR ulMultiplicand,
+ IN UINT_PTR ulMultiplier,
+ OUT UINT_PTR* pulResult)
+{
+ return UIntMult((UINT)ulMultiplicand, (UINT)ulMultiplier, (UINT*)pulResult);
+}
+#endif // _WIN64
+
+//
+// ULONG multiplication
+//
+__inline
+HRESULT
+ULongMult(
+ IN ULONG ulMultiplicand,
+ IN ULONG ulMultiplier,
+ OUT ULONG* pulResult)
+{
+ ULONGLONG ull64Result = UInt32x32To64(ulMultiplicand, ulMultiplier);
+
+ return ULongLongToULong(ull64Result, pulResult);
+}
+
+//
+// ULONG_PTR multiplication
+//
+#ifdef _WIN64
+#define ULongPtrMult ULongLongMult
+#else
+__inline
+HRESULT
+ULongPtrMult(
+ IN ULONG_PTR ulMultiplicand,
+ IN ULONG_PTR ulMultiplier,
+ OUT ULONG_PTR* pulResult)
+{
+ return ULongMult((ULONG)ulMultiplicand, (ULONG)ulMultiplier, (ULONG*)pulResult);
+}
+#endif // _WIN64
+
+
+//
+// DWORD multiplication
+//
+#define DWordMult ULongMult
+
+//
+// DWORD_PTR multiplication
+//
+#define DWordPtrMult ULongPtrMult
+
+//
+// size_t multiplication
+//
+#define SizeTMult UIntPtrMult
+
+//
+// SIZE_T multiplication
+//
+#define SIZETMult ULongPtrMult
+
+//
+// ULONGLONG multiplication
+//
+__inline
+HRESULT
+ULongLongMult(
+ IN ULONGLONG ullMultiplicand,
+ IN ULONGLONG ullMultiplier,
+ OUT ULONGLONG* pullResult)
+{
+ HRESULT hr = INTSAFE_E_ARITHMETIC_OVERFLOW;
+#ifdef _AMD64_
+ ULONGLONG u64ResultHigh;
+ ULONGLONG u64ResultLow;
+
+ *pullResult = ULONGLONG_ERROR;
+
+ u64ResultLow = UnsignedMultiply128(ullMultiplicand, ullMultiplier, &u64ResultHigh);
+ if (u64ResultHigh == 0)
+ {
+ *pullResult = u64ResultLow;
+ hr = S_OK;
+ }
+#else
+ // 64x64 into 128 is like 32.32 x 32.32.
+ //
+ // a.b * c.d = a*(c.d) + .b*(c.d) = a*c + a*.d + .b*c + .b*.d
+ // back in non-decimal notation where A=a*2^32 and C=c*2^32:
+ // A*C + A*d + b*C + b*d
+ // So there are four components to add together.
+ // result = (a*c*2^64) + (a*d*2^32) + (b*c*2^32) + (b*d)
+ //
+ // a * c must be 0 or there would be bits in the high 64-bits
+ // a * d must be less than 2^32 or there would be bits in the high 64-bits
+ // b * c must be less than 2^32 or there would be bits in the high 64-bits
+ // then there must be no overflow of the resulting values summed up.
+
+ ULONG dw_a;
+ ULONG dw_b;
+ ULONG dw_c;
+ ULONG dw_d;
+ ULONGLONG ad = 0;
+ ULONGLONG bc = 0;
+ ULONGLONG bd = 0;
+ ULONGLONG ullResult = 0;
+
+ *pullResult = ULONGLONG_ERROR;
+
+ dw_a = (ULONG)(ullMultiplicand >> 32);
+ dw_c = (ULONG)(ullMultiplier >> 32);
+
+ // common case -- if high dwords are both zero, no chance for overflow
+ if ((dw_a == 0) && (dw_c == 0))
+ {
+ dw_b = (DWORD)ullMultiplicand;
+ dw_d = (DWORD)ullMultiplier;
+
+ *pullResult = (((ULONGLONG)dw_b) * (ULONGLONG)dw_d);
+ hr = S_OK;
+ }
+ else
+ {
+ // a * c must be 0 or there would be bits set in the high 64-bits
+ if ((dw_a == 0) ||
+ (dw_c == 0))
+ {
+ dw_d = (DWORD)ullMultiplier;
+
+ // a * d must be less than 2^32 or there would be bits set in the high 64-bits
+ ad = (((ULONGLONG)dw_a) * (ULONGLONG)dw_d);
+ if ((ad & HIDWORD_MASK) == 0)
+ {
+ dw_b = (DWORD)ullMultiplicand;
+
+ // b * c must be less than 2^32 or there would be bits set in the high 64-bits
+ bc = (((ULONGLONG)dw_b) * (ULONGLONG)dw_c);
+ if ((bc & HIDWORD_MASK) == 0)
+ {
+ // now sum them all up checking for overflow.
+ // shifting is safe because we already checked for overflow above
+ if (SUCCEEDED(ULongLongAdd(bc << 32, ad << 32, &ullResult)))
+ {
+ // b * d
+ bd = (((ULONGLONG)dw_b) * (ULONGLONG)dw_d);
+
+ if (SUCCEEDED(ULongLongAdd(ullResult, bd, &ullResult)))
+ {
+ *pullResult = ullResult;
+ hr = S_OK;
+ }
+ }
+ }
+ }
+ }
+ }
+#endif // _AMD64_
+
+ return hr;
+}
+
+#endif // _INTSAFE_H_INCLUDED_
diff --git a/src/pal/inc/rt/mbstring.h b/src/pal/inc/rt/mbstring.h
new file mode 100644
index 0000000000..bf9ceb66f4
--- /dev/null
+++ b/src/pal/inc/rt/mbstring.h
@@ -0,0 +1,13 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+//
+// ===========================================================================
+// File: mbstring.h
+//
+// ===========================================================================
+// dummy mbstring.h for PAL
+
+#include "palrt.h"
diff --git a/src/pal/inc/rt/new.h b/src/pal/inc/rt/new.h
new file mode 100644
index 0000000000..b9932d7505
--- /dev/null
+++ b/src/pal/inc/rt/new.h
@@ -0,0 +1,13 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+//
+// ===========================================================================
+// File: new.h
+//
+// ===========================================================================
+// dummy new.h for PAL
+
+#include "palrt.h"
diff --git a/src/pal/inc/rt/no_sal2.h b/src/pal/inc/rt/no_sal2.h
new file mode 100644
index 0000000000..d2a97a4138
--- /dev/null
+++ b/src/pal/inc/rt/no_sal2.h
@@ -0,0 +1,534 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+
+/***
+* no_sal2.h - renders the SAL annotations for documenting APIs harmless.
+*
+
+*
+*Purpose:
+* sal.h provides a set of SAL2 annotations to describe how a function uses its
+* parameters - the assumptions it makes about them, and the guarantees it makes
+* upon finishing. This file redefines all those annotation macros to be harmless.
+* It is designed for use in down-level build environments where the tooling may
+* be unhappy with the standard SAL2 macro definitions.
+*
+* [Public]
+*
+
+*
+****/
+
+#ifndef _NO_SAL_2_H_
+#define _NO_SAL_2_H_
+
+#undef _When_
+#define _When_(c,a)
+#undef _At_
+#define _At_(t,a)
+#undef _At_buffer_
+#define _At_buffer_(t,i,c,a)
+#undef _Group_
+#define _Group_(a)
+#undef _Pre_
+#define _Pre_
+#undef _Post_
+#define _Post_
+#undef _Deref_
+#define _Deref_
+#undef _Null_
+#define _Null_
+#undef _Notnull_
+#define _Notnull_
+#undef _Maybenull_
+#define _Maybenull_
+#undef _Const_
+#define _Const_
+#undef _Check_return_
+#define _Check_return_
+#undef _Must_inspect_result_
+#define _Must_inspect_result_
+#undef _Pre_satisfies_
+#define _Pre_satisfies_(e)
+#undef _Post_satisfies_
+#define _Post_satisfies_(e)
+#undef _Writable_elements_
+#define _Writable_elements_(s)
+#undef _Writable_bytes_
+#define _Writable_bytes_(s)
+#undef _Readable_elements_
+#define _Readable_elements_(s)
+#undef _Readable_bytes_
+#define _Readable_bytes_(s)
+#undef _Null_terminated_
+#define _Null_terminated_
+#undef _NullNull_terminated_
+#define _NullNull_terminated_
+#undef _Valid_
+#define _Valid_
+#undef _Notvalid_
+#define _Notvalid_
+#undef _Success_
+#define _Success_(c)
+#undef _Return_type_success_
+#define _Return_type_success_(c)
+#undef _On_failure_
+#define _On_failure_(a)
+#undef _Always_
+#define _Always_(a)
+#undef _Use_decl_annotations_
+#define _Use_decl_annotations_
+#undef _Pre_defensive_
+#define _Pre_defensive_
+#undef _Post_defensive_
+#define _Post_defensive_
+#undef _Pre_unknown_
+#define _Pre_unknown_
+#undef _Acquires_lock_
+#define _Acquires_lock_(e)
+#undef _Releases_lock_
+#define _Releases_lock_(e)
+#undef _Requires_lock_held_
+#define _Requires_lock_held_(e)
+#undef _Requires_lock_not_held_
+#define _Requires_lock_not_held_(e)
+#undef _Requires_no_locks_held_
+#define _Requires_no_locks_held_
+#undef _Guarded_by_
+#define _Guarded_by_(e)
+#undef _Write_guarded_by_
+#define _Write_guarded_by_(e)
+#undef _Interlocked_
+#define _Interlocked_
+#undef _Post_same_lock_
+#define _Post_same_lock_(e1,e2)
+#undef _Benign_race_begin_
+#define _Benign_race_begin_
+#undef _Benign_race_end_
+#define _Benign_race_end_
+#undef _No_competing_thread_
+#define _No_competing_thread_
+#undef _No_competing_thread_begin_
+#define _No_competing_thread_begin_
+#undef _No_competing_thread_end_
+#define _No_competing_thread_end_
+#undef _Acquires_shared_lock_
+#define _Acquires_shared_lock_(e)
+#undef _Releases_shared_lock_
+#define _Releases_shared_lock_(e)
+#undef _Requires_shared_lock_held_
+#define _Requires_shared_lock_held_(e)
+#undef _Acquires_exclusive_lock_
+#define _Acquires_exclusive_lock_(e)
+#undef _Releases_exclusive_lock_
+#define _Releases_exclusive_lock_(e)
+#undef _Requires_exclusive_lock_held_
+#define _Requires_exclusive_lock_held_(e)
+#undef _Has_lock_kind_
+#define _Has_lock_kind_(n)
+#undef _Create_lock_level_
+#define _Create_lock_level_(n)
+#undef _Has_lock_level_
+#define _Has_lock_level_(n)
+#undef _Lock_level_order_
+#define _Lock_level_order_(n1,n2)
+#undef _Analysis_assume_lock_acquired_
+#define _Analysis_assume_lock_acquired_(e)
+#undef _Analysis_assume_lock_released_
+#define _Analysis_assume_lock_released_(e)
+#undef _Analysis_assume_lock_held_
+#define _Analysis_assume_lock_held_(e)
+#undef _Analysis_assume_lock_not_held_
+#define _Analysis_assume_lock_not_held_(e)
+#undef _Analysis_assume_same_lock_
+#define _Analysis_assume_same_lock_(e)
+#undef _In_
+#define _In_
+#undef _Out_
+#define _Out_
+#undef _Inout_
+#define _Inout_
+#undef _In_z_
+#define _In_z_
+#undef _Inout_z_
+#define _Inout_z_
+#undef _In_reads_
+#define _In_reads_(s)
+#undef _In_reads_bytes_
+#define _In_reads_bytes_(s)
+#undef _In_reads_z_
+#define _In_reads_z_(s)
+#undef _In_reads_or_z_
+#define _In_reads_or_z_(s)
+#undef _Out_writes_
+#define _Out_writes_(s)
+#undef _Out_writes_bytes_
+#define _Out_writes_bytes_(s)
+#undef _Out_writes_z_
+#define _Out_writes_z_(s)
+#undef _Inout_updates_
+#define _Inout_updates_(s)
+#undef _Inout_updates_bytes_
+#define _Inout_updates_bytes_(s)
+#undef _Inout_updates_z_
+#define _Inout_updates_z_(s)
+#undef _Out_writes_to_
+#define _Out_writes_to_(s,c)
+#undef _Out_writes_bytes_to_
+#define _Out_writes_bytes_to_(s,c)
+#undef _Out_writes_all_
+#define _Out_writes_all_(s)
+#undef _Out_writes_bytes_all_
+#define _Out_writes_bytes_all_(s)
+#undef _Inout_updates_to_
+#define _Inout_updates_to_(s,c)
+#undef _Inout_updates_bytes_to_
+#define _Inout_updates_bytes_to_(s,c)
+#undef _Inout_updates_all_
+#define _Inout_updates_all_(s)
+#undef _Inout_updates_bytes_all_
+#define _Inout_updates_bytes_all_(s)
+#undef _In_reads_to_ptr_
+#define _In_reads_to_ptr_(p)
+#undef _In_reads_to_ptr_z_
+#define _In_reads_to_ptr_z_(p)
+#undef _Out_writes_to_ptr_
+#define _Out_writes_to_ptr_(p)
+#undef _Out_writes_to_ptr_z_
+#define _Out_writes_to_ptr_z_(p)
+#undef _In_opt_
+#define _In_opt_
+#undef _Out_opt_
+#define _Out_opt_
+#undef _Inout_opt_
+#define _Inout_opt_
+#undef _In_opt_z_
+#define _In_opt_z_
+#undef _Inout_opt_z_
+#define _Inout_opt_z_
+#undef _In_reads_opt_
+#define _In_reads_opt_(s)
+#undef _In_reads_bytes_opt_
+#define _In_reads_bytes_opt_(s)
+#undef _Out_writes_opt_
+#define _Out_writes_opt_(s)
+#undef _Out_writes_bytes_opt_
+#define _Out_writes_bytes_opt_(s)
+#undef _Out_writes_opt_z_
+#define _Out_writes_opt_z_(s)
+#undef _Inout_updates_opt_
+#define _Inout_updates_opt_(s)
+#undef _Inout_updates_bytes_opt_
+#define _Inout_updates_bytes_opt_(s)
+#undef _Inout_updates_opt_z_
+#define _Inout_updates_opt_z_(s)
+#undef _Out_writes_to_opt_
+#define _Out_writes_to_opt_(s,c)
+#undef _Out_writes_bytes_to_opt_
+#define _Out_writes_bytes_to_opt_(s,c)
+#undef _Out_writes_all_opt_
+#define _Out_writes_all_opt_(s)
+#undef _Out_writes_bytes_all_opt_
+#define _Out_writes_bytes_all_opt_(s)
+#undef _Inout_updates_to_opt_
+#define _Inout_updates_to_opt_(s,c)
+#undef _Inout_updates_bytes_to_opt_
+#define _Inout_updates_bytes_to_opt_(s,c)
+#undef _Inout_updates_all_opt_
+#define _Inout_updates_all_opt_(s)
+#undef _Inout_updates_bytes_all_opt_
+#define _Inout_updates_bytes_all_opt_(s)
+#undef _In_reads_to_ptr_opt_
+#define _In_reads_to_ptr_opt_(p)
+#undef _In_reads_to_ptr_opt_z_
+#define _In_reads_to_ptr_opt_z_(p)
+#undef _Out_writes_to_ptr_opt_
+#define _Out_writes_to_ptr_opt_(p)
+#undef _Out_writes_to_ptr_opt_z_
+#define _Out_writes_to_ptr_opt_z_(p)
+#undef _Outptr_
+#define _Outptr_
+#undef _Outptr_opt_
+#define _Outptr_opt_
+#undef _Outptr_result_maybenull_
+#define _Outptr_result_maybenull_
+#undef _Outptr_opt_result_maybenull_
+#define _Outptr_opt_result_maybenull_
+#undef _Outptr_z_
+#define _Outptr_z_
+#undef _Outptr_opt_z_
+#define _Outptr_opt_z_
+#undef _Outptr_result_maybenull_z_
+#define _Outptr_result_maybenull_z_
+#undef _Outptr_opt_result_maybenull_z_
+#define _Outptr_opt_result_maybenull_z_
+#undef _COM_Outptr_
+#define _COM_Outptr_
+#undef _COM_Outptr_opt_
+#define _COM_Outptr_opt_
+#undef _COM_Outptr_result_maybenull_
+#define _COM_Outptr_result_maybenull_
+#undef _COM_Outptr_opt_result_maybenull_
+#define _COM_Outptr_opt_result_maybenull_
+#undef _Outptr_result_buffer_
+#define _Outptr_result_buffer_(s)
+#undef _Outptr_result_bytebuffer_
+#define _Outptr_result_bytebuffer_(s)
+#undef _Outptr_opt_result_buffer_
+#define _Outptr_opt_result_buffer_(s)
+#undef _Outptr_opt_result_bytebuffer_
+#define _Outptr_opt_result_bytebuffer_(s)
+#undef _Outptr_result_buffer_to_
+#define _Outptr_result_buffer_to_(s,c)
+#undef _Outptr_result_bytebuffer_to_
+#define _Outptr_result_bytebuffer_to_(s,c)
+#undef _Outptr_opt_result_buffer_to_
+#define _Outptr_opt_result_buffer_to_(s,c)
+#undef _Outptr_opt_result_bytebuffer_to_
+#define _Outptr_opt_result_bytebuffer_to_(s,c)
+#undef _Ret_
+#define _Ret_
+#undef _Ret_valid_
+#define _Ret_valid_
+#undef _Ret_z_
+#define _Ret_z_
+#undef _Ret_writes_
+#define _Ret_writes_(s)
+#undef _Ret_writes_bytes_
+#define _Ret_writes_bytes_(s)
+#undef _Ret_writes_z_
+#define _Ret_writes_z_(s)
+#undef _Ret_writes_to_
+#define _Ret_writes_to_(s,c)
+#undef _Ret_writes_bytes_to_
+#define _Ret_writes_bytes_to_(s,c)
+#undef _Ret_writes_maybenull_
+#define _Ret_writes_maybenull_(s)
+#undef _Ret_writes_bytes_maybenull_
+#define _Ret_writes_bytes_maybenull_(s)
+#undef _Ret_writes_to_maybenull_
+#define _Ret_writes_to_maybenull_(s,c)
+#undef _Ret_writes_bytes_to_maybenull_
+#define _Ret_writes_bytes_to_maybenull_(s,c)
+#undef _Ret_writes_maybenull_z_
+#define _Ret_writes_maybenull_z_(s)
+#undef _Ret_maybenull_
+#define _Ret_maybenull_
+#undef _Ret_maybenull_z_
+#define _Ret_maybenull_z_
+#undef _Field_size_
+#define _Field_size_(s)
+#undef _Field_size_opt_
+#define _Field_size_opt_(s)
+#undef _Field_size_bytes_
+#define _Field_size_bytes_(s)
+#undef _Field_size_bytes_opt_
+#define _Field_size_bytes_opt_(s)
+#undef _Field_size_part_
+#define _Field_size_part_(s,c)
+#undef _Field_size_part_opt_
+#define _Field_size_part_opt_(s,c)
+#undef _Field_size_bytes_part_
+#define _Field_size_bytes_part_(s,c)
+#undef _Field_size_bytes_part_opt_
+#define _Field_size_bytes_part_opt_(s,c)
+#undef _Field_size_full_
+#define _Field_size_full_(s)
+#undef _Field_size_full_opt_
+#define _Field_size_full_opt_(s)
+#undef _Field_size_bytes_full_
+#define _Field_size_bytes_full_(s)
+#undef _Field_size_bytes_full_opt_
+#define _Field_size_bytes_full_opt_(s)
+#undef _Printf_format_string_
+#define _Printf_format_string_
+#undef _Scanf_format_string_
+#define _Scanf_format_string_
+#undef _Scanf_s_format_string_
+#define _Scanf_s_format_string_
+#undef _Printf_format_string_params_
+#define _Printf_format_string_params_(x)
+#undef _Scanf_format_string_params_
+#define _Scanf_format_string_params_(x)
+#undef _Scanf_s_format_string_params_
+#define _Scanf_s_format_string_params_(x)
+#undef _In_range_
+#define _In_range_(l,h)
+#undef _Out_range_
+#define _Out_range_(l,h)
+#undef _Ret_range_
+#define _Ret_range_(l,h)
+#undef _Deref_in_range_
+#define _Deref_in_range_(l,h)
+#undef _Deref_out_range_
+#define _Deref_out_range_(l,h)
+#undef _Deref_inout_range_
+#define _Deref_inout_range_(l,h)
+#undef _Field_range_
+#define _Field_range_(l,h)
+#undef _Pre_equal_to_
+#define _Pre_equal_to_(e)
+#undef _Post_equal_to_
+#define _Post_equal_to_(e)
+#undef _Struct_size_bytes_
+#define _Struct_size_bytes_(s)
+#undef _Analysis_assume_
+#define _Analysis_assume_
+#undef _Analysis_mode_
+#define _Analysis_mode_(m)
+#undef _Analysis_noreturn_
+#define _Analysis_noreturn_
+#undef _Raises_SEH_exception_
+#define _Raises_SEH_exception_
+#undef _Maybe_raises_SEH_exception_
+#define _Maybe_raises_SEH_exception_
+#undef _Function_class_
+#define _Function_class_(n)
+#undef _Literal_
+#define _Literal_
+#undef _Notliteral_
+#define _Notliteral_
+#undef _Enum_is_bitflag_
+#define _Enum_is_bitflag_
+#undef _Strict_type_match_
+#define _Strict_type_match_
+#undef _Points_to_data_
+#define _Points_to_data_
+#undef _Interlocked_operand_
+#define _Interlocked_operand_
+#undef _IRQL_raises_
+#define _IRQL_raises_(i)
+#undef _IRQL_requires_
+#define _IRQL_requires_(i)
+#undef _IRQL_requires_max_
+#define _IRQL_requires_max_(i)
+#undef _IRQL_requires_min_
+#define _IRQL_requires_min_(i)
+#undef _IRQL_saves_
+#define _IRQL_saves_
+#undef _IRQL_saves_global_
+#define _IRQL_saves_global_(k,s)
+#undef _IRQL_restores_
+#define _IRQL_restores_
+#undef _IRQL_restores_global_
+#define _IRQL_restores_global_(k,s)
+#undef _IRQL_always_function_min_
+#define _IRQL_always_function_min_(i)
+#undef _IRQL_always_function_max_
+#define _IRQL_always_function_max_(i)
+#undef _IRQL_requires_same_
+#define _IRQL_requires_same_
+#undef _IRQL_uses_cancel_
+#define _IRQL_uses_cancel_
+#undef _IRQL_is_cancel_
+#define _IRQL_is_cancel_
+#undef _Kernel_float_saved_
+#define _Kernel_float_saved_
+#undef _Kernel_float_restored_
+#define _Kernel_float_restored_
+#undef _Kernel_float_used_
+#define _Kernel_float_used_
+#undef _Kernel_acquires_resource_
+#define _Kernel_acquires_resource_(k)
+#undef _Kernel_releases_resource_
+#define _Kernel_releases_resource_(k)
+#undef _Kernel_requires_resource_held_
+#define _Kernel_requires_resource_held_(k)
+#undef _Kernel_requires_resource_not_held_
+#define _Kernel_requires_resource_not_held_(k)
+#undef _Kernel_clear_do_init_
+#define _Kernel_clear_do_init_(yn)
+#undef _Kernel_IoGetDmaAdapter_
+#define _Kernel_IoGetDmaAdapter_
+#undef _Outref_
+#define _Outref_
+#undef _Outref_result_maybenull_
+#define _Outref_result_maybenull_
+#undef _Outref_result_buffer_
+#define _Outref_result_buffer_(s)
+#undef _Outref_result_bytebuffer_
+#define _Outref_result_bytebuffer_(s)
+#undef _Outref_result_buffer_to_
+#define _Outref_result_buffer_to_(s,c)
+#undef _Outref_result_bytebuffer_to_
+#define _Outref_result_bytebuffer_to_(s,c)
+#undef _Outref_result_buffer_all_
+#define _Outref_result_buffer_all_(s)
+#undef _Outref_result_bytebuffer_all_
+#define _Outref_result_bytebuffer_all_(s)
+#undef _Outref_result_buffer_maybenull_
+#define _Outref_result_buffer_maybenull_(s)
+#undef _Outref_result_bytebuffer_maybenull_
+#define _Outref_result_bytebuffer_maybenull_(s)
+#undef _Outref_result_buffer_to_maybenull_
+#define _Outref_result_buffer_to_maybenull_(s,c)
+#undef _Outref_result_bytebuffer_to_maybenull_
+#define _Outref_result_bytebuffer_to_maybenull_(s,c)
+#undef _Outref_result_buffer_all_maybenull_
+#define _Outref_result_buffer_all_maybenull_(s)
+#undef _Outref_result_bytebuffer_all_maybenull_
+#define _Outref_result_bytebuffer_all_maybenull_(s)
+#undef _In_defensive_
+#define _In_defensive_(a)
+#undef _Out_defensive_
+#define _Out_defensive_(a)
+#undef _Inout_defensive_
+#define _Inout_defensive_(a)
+#undef _Outptr_result_nullonfailure_
+#define _Outptr_result_nullonfailure_
+#undef _Outptr_opt_result_nullonfailure_
+#define _Outptr_opt_result_nullonfailure_
+#undef _Outref_result_nullonfailure_
+#define _Outref_result_nullonfailure_
+#undef _Result_nullonfailure_
+#define _Result_nullonfailure_
+#undef _Result_zeroonfailure_
+#define _Result_zeroonfailure_
+#undef _Acquires_nonreentrant_lock_
+#define _Acquires_nonreentrant_lock_(e)
+#undef _Releases_nonreentrant_lock_
+#define _Releases_nonreentrant_lock_(e)
+#undef _Reserved_
+#define _Reserved_ _Pre_equal_to_(0) _Pre_ _Null_
+#undef _Pre_z_
+#define _Pre_z_ _Pre_ _Null_terminated_
+#undef _Post_z_
+#define _Post_z_ _Post_ _Null_terminated_
+#undef _Prepost_z_
+#define _Prepost_z_ _Pre_z_ _Post_z_
+#undef _Pre_null_
+#define _Pre_null_ _Pre_ _Null_
+#undef _Pre_maybenull_
+#define _Pre_maybenull_ _Pre_ _Maybenull_
+#undef _Pre_notnull_
+#define _Pre_notnull_ _Pre_ _Notnull_
+#undef _Pre_valid_
+#define _Pre_valid_ _Pre_notnull_ _Pre_ _Valid_
+#undef _Pre_opt_valid_
+#define _Pre_opt_valid_ _Pre_maybenull_ _Pre_ _Valid_
+#undef _Post_valid_
+#define _Post_valid_ _Post_ _Valid_
+#undef _Post_invalid_
+#define _Post_invalid_ _Post_ _Deref_ _Notvalid_
+#undef _Post_ptr_invalid_
+#define _Post_ptr_invalid_ _Post_ _Notvalid_
+#undef _Pre_readable_size_
+#define _Pre_readable_size_(s) _Pre_ _Readable_elements_(s) _Pre_ _Valid_
+#undef _Pre_writable_size_
+#define _Pre_writable_size_(s) _Pre_ _Writable_elements_(s)
+#undef _Pre_readable_byte_size_
+#define _Pre_readable_byte_size_(s) _Pre_ _Readable_bytes_(s) _Pre_ _Valid_
+#undef _Pre_writable_byte_size_
+#define _Pre_writable_byte_size_(s) _Pre_ _Writable_bytes_(s)
+#undef _Post_readable_size_
+#define _Post_readable_size_(s) _Post_ _Readable_elements_(s) _Post_ _Valid_
+#undef _Post_writable_size_
+#define _Post_writable_size_(s) _Post_ _Writable_elements_(s)
+#undef _Post_readable_byte_size_
+#define _Post_readable_byte_size_(s) _Post_ _Readable_bytes_(s) _Post_ _Valid_
+#undef _Post_writable_byte_size_
+#define _Post_writable_byte_size_(s) _Post_ _Writable_bytes_(s)
+
+#endif /* _NO_SAL_2_H_ */
diff --git a/src/pal/inc/rt/ntimage.h b/src/pal/inc/rt/ntimage.h
new file mode 100644
index 0000000000..7d98b567e3
--- /dev/null
+++ b/src/pal/inc/rt/ntimage.h
@@ -0,0 +1,1874 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+//
+// ===========================================================================
+// File: ntimage.h
+//
+// ===========================================================================
+
+//
+//Abstract:
+//
+// This is the include file that describes all image structures.
+//
+//Author:
+//
+//
+//
+//Revision History:
+//
+
+
+#ifndef _NTIMAGE_
+#define _NTIMAGE_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif
+
+//
+// Define the linker version number.
+
+#define IMAGE_MAJOR_LINKER_VERSION 2
+
+// begin_winnt
+
+
+//
+// Image Format
+//
+
+
+#ifndef _MAC
+
+#include "pshpack4.h" // 4 byte packing is the default
+
+#define IMAGE_DOS_SIGNATURE 0x5A4D // MZ
+#define IMAGE_OS2_SIGNATURE 0x454E // NE
+#define IMAGE_OS2_SIGNATURE_LE 0x454C // LE
+#define IMAGE_VXD_SIGNATURE 0x454C // LE
+#define IMAGE_NT_SIGNATURE 0x00004550 // PE00
+
+#include "pshpack2.h" // 16 bit headers are 2 byte packed
+
+#else
+
+#include "pshpack1.h"
+
+#define IMAGE_DOS_SIGNATURE 0x4D5A // MZ
+#define IMAGE_OS2_SIGNATURE 0x4E45 // NE
+#define IMAGE_OS2_SIGNATURE_LE 0x4C45 // LE
+#define IMAGE_NT_SIGNATURE 0x50450000 // PE00
+#endif
+
+typedef struct _IMAGE_DOS_HEADER { // DOS .EXE header
+ USHORT e_magic; // Magic number
+ USHORT e_cblp; // Bytes on last page of file
+ USHORT e_cp; // Pages in file
+ USHORT e_crlc; // Relocations
+ USHORT e_cparhdr; // Size of header in paragraphs
+ USHORT e_minalloc; // Minimum extra paragraphs needed
+ USHORT e_maxalloc; // Maximum extra paragraphs needed
+ USHORT e_ss; // Initial (relative) SS value
+ USHORT e_sp; // Initial SP value
+ USHORT e_csum; // Checksum
+ USHORT e_ip; // Initial IP value
+ USHORT e_cs; // Initial (relative) CS value
+ USHORT e_lfarlc; // File address of relocation table
+ USHORT e_ovno; // Overlay number
+ USHORT e_res[4]; // Reserved words
+ USHORT e_oemid; // OEM identifier (for e_oeminfo)
+ USHORT e_oeminfo; // OEM information; e_oemid specific
+ USHORT e_res2[10]; // Reserved words
+ LONG e_lfanew; // File address of new exe header
+ } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
+
+typedef struct _IMAGE_OS2_HEADER { // OS/2 .EXE header
+ USHORT ne_magic; // Magic number
+ CHAR ne_ver; // Version number
+ CHAR ne_rev; // Revision number
+ USHORT ne_enttab; // Offset of Entry Table
+ USHORT ne_cbenttab; // Number of bytes in Entry Table
+ LONG ne_crc; // Checksum of whole file
+ USHORT ne_flags; // Flag word
+ USHORT ne_autodata; // Automatic data segment number
+ USHORT ne_heap; // Initial heap allocation
+ USHORT ne_stack; // Initial stack allocation
+ LONG ne_csip; // Initial CS:IP setting
+ LONG ne_sssp; // Initial SS:SP setting
+ USHORT ne_cseg; // Count of file segments
+ USHORT ne_cmod; // Entries in Module Reference Table
+ USHORT ne_cbnrestab; // Size of non-resident name table
+ USHORT ne_segtab; // Offset of Segment Table
+ USHORT ne_rsrctab; // Offset of Resource Table
+ USHORT ne_restab; // Offset of resident name table
+ USHORT ne_modtab; // Offset of Module Reference Table
+ USHORT ne_imptab; // Offset of Imported Names Table
+ LONG ne_nrestab; // Offset of Non-resident Names Table
+ USHORT ne_cmovent; // Count of movable entries
+ USHORT ne_align; // Segment alignment shift count
+ USHORT ne_cres; // Count of resource segments
+ UCHAR ne_exetyp; // Target Operating system
+ UCHAR ne_flagsothers; // Other .EXE flags
+ USHORT ne_pretthunks; // offset to return thunks
+ USHORT ne_psegrefbytes; // offset to segment ref. bytes
+ USHORT ne_swaparea; // Minimum code swap area size
+ USHORT ne_expver; // Expected Windows version number
+ } IMAGE_OS2_HEADER, *PIMAGE_OS2_HEADER;
+
+typedef struct _IMAGE_VXD_HEADER { // Windows VXD header
+ USHORT e32_magic; // Magic number
+ UCHAR e32_border; // The byte ordering for the VXD
+ UCHAR e32_worder; // The word ordering for the VXD
+ ULONG e32_level; // The EXE format level for now = 0
+ USHORT e32_cpu; // The CPU type
+ USHORT e32_os; // The OS type
+ ULONG e32_ver; // Module version
+ ULONG e32_mflags; // Module flags
+ ULONG e32_mpages; // Module # pages
+ ULONG e32_startobj; // Object # for instruction pointer
+ ULONG e32_eip; // Extended instruction pointer
+ ULONG e32_stackobj; // Object # for stack pointer
+ ULONG e32_esp; // Extended stack pointer
+ ULONG e32_pagesize; // VXD page size
+ ULONG e32_lastpagesize; // Last page size in VXD
+ ULONG e32_fixupsize; // Fixup section size
+ ULONG e32_fixupsum; // Fixup section checksum
+ ULONG e32_ldrsize; // Loader section size
+ ULONG e32_ldrsum; // Loader section checksum
+ ULONG e32_objtab; // Object table offset
+ ULONG e32_objcnt; // Number of objects in module
+ ULONG e32_objmap; // Object page map offset
+ ULONG e32_itermap; // Object iterated data map offset
+ ULONG e32_rsrctab; // Offset of Resource Table
+ ULONG e32_rsrccnt; // Number of resource entries
+ ULONG e32_restab; // Offset of resident name table
+ ULONG e32_enttab; // Offset of Entry Table
+ ULONG e32_dirtab; // Offset of Module Directive Table
+ ULONG e32_dircnt; // Number of module directives
+ ULONG e32_fpagetab; // Offset of Fixup Page Table
+ ULONG e32_frectab; // Offset of Fixup Record Table
+ ULONG e32_impmod; // Offset of Import Module Name Table
+ ULONG e32_impmodcnt; // Number of entries in Import Module Name Table
+ ULONG e32_impproc; // Offset of Import Procedure Name Table
+ ULONG e32_pagesum; // Offset of Per-Page Checksum Table
+ ULONG e32_datapage; // Offset of Enumerated Data Pages
+ ULONG e32_preload; // Number of preload pages
+ ULONG e32_nrestab; // Offset of Non-resident Names Table
+ ULONG e32_cbnrestab; // Size of Non-resident Name Table
+ ULONG e32_nressum; // Non-resident Name Table Checksum
+ ULONG e32_autodata; // Object # for automatic data object
+ ULONG e32_debuginfo; // Offset of the debugging information
+ ULONG e32_debuglen; // The length of the debugging info. in bytes
+ ULONG e32_instpreload; // Number of instance pages in preload section of VXD file
+ ULONG e32_instdemand; // Number of instance pages in demand load section of VXD file
+ ULONG e32_heapsize; // Size of heap - for 16-bit apps
+ UCHAR e32_res3[12]; // Reserved words
+ ULONG e32_winresoff;
+ ULONG e32_winreslen;
+ USHORT e32_devid; // Device ID for VxD
+ USHORT e32_ddkver; // DDK version for VxD
+ } IMAGE_VXD_HEADER, *PIMAGE_VXD_HEADER;
+
+#ifndef _MAC
+#include "poppack.h" // Back to 4 byte packing
+#endif
+
+//
+// File header format.
+//
+
+typedef struct _IMAGE_FILE_HEADER {
+ USHORT Machine;
+ USHORT NumberOfSections;
+ ULONG TimeDateStamp;
+ ULONG PointerToSymbolTable;
+ ULONG NumberOfSymbols;
+ USHORT SizeOfOptionalHeader;
+ USHORT Characteristics;
+} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
+
+#define IMAGE_SIZEOF_FILE_HEADER 20
+
+
+#define IMAGE_FILE_RELOCS_STRIPPED 0x0001 // Relocation info stripped from file.
+#define IMAGE_FILE_EXECUTABLE_IMAGE 0x0002 // File is executable (i.e. no unresolved externel references).
+#define IMAGE_FILE_LINE_NUMS_STRIPPED 0x0004 // Line nunbers stripped from file.
+#define IMAGE_FILE_LOCAL_SYMS_STRIPPED 0x0008 // Local symbols stripped from file.
+#define IMAGE_FILE_AGGRESIVE_WS_TRIM 0x0010 // Agressively trim working set
+#define IMAGE_FILE_LARGE_ADDRESS_AWARE 0x0020 // App can handle >2gb addresses
+#define IMAGE_FILE_BYTES_REVERSED_LO 0x0080 // Bytes of machine word are reversed.
+#define IMAGE_FILE_32BIT_MACHINE 0x0100 // 32 bit word machine.
+#define IMAGE_FILE_DEBUG_STRIPPED 0x0200 // Debugging info stripped from file in .DBG file
+#define IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP 0x0400 // If Image is on removable media, copy and run from the swap file.
+#define IMAGE_FILE_NET_RUN_FROM_SWAP 0x0800 // If Image is on Net, copy and run from the swap file.
+#define IMAGE_FILE_SYSTEM 0x1000 // System File.
+#define IMAGE_FILE_DLL 0x2000 // File is a DLL.
+#define IMAGE_FILE_UP_SYSTEM_ONLY 0x4000 // File should only be run on a UP machine
+#define IMAGE_FILE_BYTES_REVERSED_HI 0x8000 // Bytes of machine word are reversed.
+
+#define IMAGE_FILE_MACHINE_UNKNOWN 0
+#define IMAGE_FILE_MACHINE_I386 0x014c // Intel 386.
+#define IMAGE_FILE_MACHINE_R3000 0x0162 // MIPS little-endian, 0x160 big-endian
+#define IMAGE_FILE_MACHINE_R4000 0x0166 // MIPS little-endian
+#define IMAGE_FILE_MACHINE_R10000 0x0168 // MIPS little-endian
+#define IMAGE_FILE_MACHINE_WCEMIPSV2 0x0169 // MIPS little-endian WCE v2
+#define IMAGE_FILE_MACHINE_ALPHA 0x0184 // Alpha_AXP
+#define IMAGE_FILE_MACHINE_SH3 0x01a2 // SH3 little-endian
+#define IMAGE_FILE_MACHINE_SH3DSP 0x01a3
+#define IMAGE_FILE_MACHINE_SH3E 0x01a4 // SH3E little-endian
+#define IMAGE_FILE_MACHINE_SH4 0x01a6 // SH4 little-endian
+#define IMAGE_FILE_MACHINE_SH5 0x01a8 // SH5
+#define IMAGE_FILE_MACHINE_ARM 0x01c0 // ARM Little-Endian
+#define IMAGE_FILE_MACHINE_THUMB 0x01c2
+#define IMAGE_FILE_MACHINE_ARMNT 0x01c4 // ARM Thumb-2 Little-Endian
+#define IMAGE_FILE_MACHINE_AM33 0x01d3
+#define IMAGE_FILE_MACHINE_POWERPC 0x01F0 // IBM PowerPC Little-Endian
+#define IMAGE_FILE_MACHINE_POWERPCFP 0x01f1
+#define IMAGE_FILE_MACHINE_IA64 0x0200 // Intel 64
+#define IMAGE_FILE_MACHINE_MIPS16 0x0266 // MIPS
+#define IMAGE_FILE_MACHINE_ALPHA64 0x0284 // ALPHA64
+#define IMAGE_FILE_MACHINE_MIPSFPU 0x0366 // MIPS
+#define IMAGE_FILE_MACHINE_MIPSFPU16 0x0466 // MIPS
+#define IMAGE_FILE_MACHINE_AXP64 IMAGE_FILE_MACHINE_ALPHA64
+#define IMAGE_FILE_MACHINE_TRICORE 0x0520 // Infineon
+#define IMAGE_FILE_MACHINE_CEF 0x0CEF
+#define IMAGE_FILE_MACHINE_EBC 0x0EBC // EFI Byte Code
+#define IMAGE_FILE_MACHINE_AMD64 0x8664 // AMD64 (K8)
+#define IMAGE_FILE_MACHINE_M32R 0x9041 // M32R little-endian
+#define IMAGE_FILE_MACHINE_CEE 0xC0EE
+
+//
+// Directory format.
+//
+
+typedef struct _IMAGE_DATA_DIRECTORY {
+ ULONG VirtualAddress;
+ ULONG Size;
+} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
+
+#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16
+
+//
+// Optional header format.
+//
+
+typedef struct _IMAGE_OPTIONAL_HEADER {
+ //
+ // Standard fields.
+ //
+
+ USHORT Magic;
+ UCHAR MajorLinkerVersion;
+ UCHAR MinorLinkerVersion;
+ ULONG SizeOfCode;
+ ULONG SizeOfInitializedData;
+ ULONG SizeOfUninitializedData;
+ ULONG AddressOfEntryPoint;
+ ULONG BaseOfCode;
+ ULONG BaseOfData;
+
+ //
+ // NT additional fields.
+ //
+
+ ULONG ImageBase;
+ ULONG SectionAlignment;
+ ULONG FileAlignment;
+ USHORT MajorOperatingSystemVersion;
+ USHORT MinorOperatingSystemVersion;
+ USHORT MajorImageVersion;
+ USHORT MinorImageVersion;
+ USHORT MajorSubsystemVersion;
+ USHORT MinorSubsystemVersion;
+ ULONG Win32VersionValue;
+ ULONG SizeOfImage;
+ ULONG SizeOfHeaders;
+ ULONG CheckSum;
+ USHORT Subsystem;
+ USHORT DllCharacteristics;
+ ULONG SizeOfStackReserve;
+ ULONG SizeOfStackCommit;
+ ULONG SizeOfHeapReserve;
+ ULONG SizeOfHeapCommit;
+ ULONG LoaderFlags;
+ ULONG NumberOfRvaAndSizes;
+ IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
+} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;
+
+typedef struct _IMAGE_ROM_OPTIONAL_HEADER {
+ USHORT Magic;
+ UCHAR MajorLinkerVersion;
+ UCHAR MinorLinkerVersion;
+ ULONG SizeOfCode;
+ ULONG SizeOfInitializedData;
+ ULONG SizeOfUninitializedData;
+ ULONG AddressOfEntryPoint;
+ ULONG BaseOfCode;
+ ULONG BaseOfData;
+ ULONG BaseOfBss;
+ ULONG GprMask;
+ ULONG CprMask[4];
+ ULONG GpValue;
+} IMAGE_ROM_OPTIONAL_HEADER, *PIMAGE_ROM_OPTIONAL_HEADER;
+
+typedef struct _IMAGE_OPTIONAL_HEADER64 {
+ USHORT Magic;
+ UCHAR MajorLinkerVersion;
+ UCHAR MinorLinkerVersion;
+ ULONG SizeOfCode;
+ ULONG SizeOfInitializedData;
+ ULONG SizeOfUninitializedData;
+ ULONG AddressOfEntryPoint;
+ ULONG BaseOfCode;
+ ULONGLONG ImageBase;
+ ULONG SectionAlignment;
+ ULONG FileAlignment;
+ USHORT MajorOperatingSystemVersion;
+ USHORT MinorOperatingSystemVersion;
+ USHORT MajorImageVersion;
+ USHORT MinorImageVersion;
+ USHORT MajorSubsystemVersion;
+ USHORT MinorSubsystemVersion;
+ ULONG Win32VersionValue;
+ ULONG SizeOfImage;
+ ULONG SizeOfHeaders;
+ ULONG CheckSum;
+ USHORT Subsystem;
+ USHORT DllCharacteristics;
+ ULONGLONG SizeOfStackReserve;
+ ULONGLONG SizeOfStackCommit;
+ ULONGLONG SizeOfHeapReserve;
+ ULONGLONG SizeOfHeapCommit;
+ ULONG LoaderFlags;
+ ULONG NumberOfRvaAndSizes;
+ IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
+} IMAGE_OPTIONAL_HEADER64, *PIMAGE_OPTIONAL_HEADER64;
+
+#define IMAGE_SIZEOF_ROM_OPTIONAL_HEADER 56
+#define IMAGE_SIZEOF_STD_OPTIONAL_HEADER 28
+#define IMAGE_SIZEOF_NT_OPTIONAL32_HEADER 224
+#define IMAGE_SIZEOF_NT_OPTIONAL64_HEADER 240
+
+#define IMAGE_NT_OPTIONAL_HDR32_MAGIC 0x10b
+#define IMAGE_NT_OPTIONAL_HDR64_MAGIC 0x20b
+#define IMAGE_ROM_OPTIONAL_HDR_MAGIC 0x107
+
+#ifdef _WIN64
+typedef IMAGE_OPTIONAL_HEADER64 IMAGE_OPTIONAL_HEADER;
+typedef PIMAGE_OPTIONAL_HEADER64 PIMAGE_OPTIONAL_HEADER;
+#define IMAGE_SIZEOF_NT_OPTIONAL_HEADER IMAGE_SIZEOF_NT_OPTIONAL64_HEADER
+#define IMAGE_NT_OPTIONAL_HDR_MAGIC IMAGE_NT_OPTIONAL_HDR64_MAGIC
+#else
+typedef IMAGE_OPTIONAL_HEADER32 IMAGE_OPTIONAL_HEADER;
+typedef PIMAGE_OPTIONAL_HEADER32 PIMAGE_OPTIONAL_HEADER;
+#define IMAGE_SIZEOF_NT_OPTIONAL_HEADER IMAGE_SIZEOF_NT_OPTIONAL32_HEADER
+#define IMAGE_NT_OPTIONAL_HDR_MAGIC IMAGE_NT_OPTIONAL_HDR32_MAGIC
+#endif
+
+typedef struct _IMAGE_NT_HEADERS64 {
+ ULONG Signature;
+ IMAGE_FILE_HEADER FileHeader;
+ IMAGE_OPTIONAL_HEADER64 OptionalHeader;
+} IMAGE_NT_HEADERS64, *PIMAGE_NT_HEADERS64;
+
+typedef struct _IMAGE_NT_HEADERS {
+ ULONG Signature;
+ IMAGE_FILE_HEADER FileHeader;
+ IMAGE_OPTIONAL_HEADER32 OptionalHeader;
+} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;
+
+typedef struct _IMAGE_ROM_HEADERS {
+ IMAGE_FILE_HEADER FileHeader;
+ IMAGE_ROM_OPTIONAL_HEADER OptionalHeader;
+} IMAGE_ROM_HEADERS, *PIMAGE_ROM_HEADERS;
+
+#ifdef _WIN64
+typedef IMAGE_NT_HEADERS64 IMAGE_NT_HEADERS;
+typedef PIMAGE_NT_HEADERS64 PIMAGE_NT_HEADERS;
+#else
+typedef IMAGE_NT_HEADERS32 IMAGE_NT_HEADERS;
+typedef PIMAGE_NT_HEADERS32 PIMAGE_NT_HEADERS;
+#endif
+
+// IMAGE_FIRST_SECTION doesn't need 32/64 versions since the file header is the same either way.
+
+#define IMAGE_FIRST_SECTION( ntheader ) ((PIMAGE_SECTION_HEADER) \
+ ((ULONG_PTR)ntheader + \
+ FIELD_OFFSET( IMAGE_NT_HEADERS, OptionalHeader ) + \
+ VAL16(((PIMAGE_NT_HEADERS)(ntheader))->FileHeader.SizeOfOptionalHeader) \
+ ))
+
+// Subsystem Values
+
+#define IMAGE_SUBSYSTEM_UNKNOWN 0 // Unknown subsystem.
+#define IMAGE_SUBSYSTEM_NATIVE 1 // Image doesn't require a subsystem.
+#define IMAGE_SUBSYSTEM_WINDOWS_GUI 2 // Image runs in the Windows GUI subsystem.
+#define IMAGE_SUBSYSTEM_WINDOWS_CUI 3 // Image runs in the Windows character subsystem.
+// end_winnt
+// reserved 4 // Old Windows CE subsystem.
+// begin_winnt
+#define IMAGE_SUBSYSTEM_OS2_CUI 5 // image runs in the OS/2 character subsystem.
+#define IMAGE_SUBSYSTEM_POSIX_CUI 7 // image runs in the Posix character subsystem.
+#define IMAGE_SUBSYSTEM_NATIVE_WINDOWS 8 // image is a native Win9x driver.
+#define IMAGE_SUBSYSTEM_WINDOWS_CE_GUI 9 // Image runs in the Windows CE subsystem.
+#define IMAGE_SUBSYSTEM_EFI_APPLICATION 10 //
+#define IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER 11 //
+#define IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER 12 //
+#define IMAGE_SUBSYSTEM_EFI_ROM 13
+#define IMAGE_SUBSYSTEM_XBOX 14
+
+// DllCharacteristics Entries
+
+// IMAGE_LIBRARY_PROCESS_INIT 0x0001 // Reserved.
+// IMAGE_LIBRARY_PROCESS_TERM 0x0002 // Reserved.
+// IMAGE_LIBRARY_THREAD_INIT 0x0004 // Reserved.
+// IMAGE_LIBRARY_THREAD_TERM 0x0008 // Reserved.
+#define IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA 0x0020 // Image can handle a high entropy 64-bit virtual address space.
+#define IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE 0x0040 // DLL can move
+#define IMAGE_DLLCHARACTERISTICS_NX_COMPAT 0x0100 // Image ix NX compatible
+#define IMAGE_DLLCHARACTERISTICS_NO_SEH 0x0400 // Image does not use SEH. No SE handler may reside in this image
+#define IMAGE_DLLCHARACTERISTICS_NO_BIND 0x0800 // Do not bind this image.
+#define IMAGE_DLLCHARACTERISTICS_APPCONTAINER 0x1000 // Image should execute in an AppContainer
+#define IMAGE_DLLCHARACTERISTICS_WDM_DRIVER 0x2000 // Driver uses WDM model
+// 0x4000 // Reserved.
+#define IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE 0x8000
+// end_winnt
+#define IMAGE_DLLCHARACTERISTICS_X86_THUNK 0x1000 // Image is a Wx86 Thunk DLL
+// Note: The Borland linker sets IMAGE_LIBRARY_xxx flags in DllCharacteristics
+
+// LoaderFlags Values
+
+#define IMAGE_LOADER_FLAGS_COMPLUS 0x00000001 // COM+ image
+#define IMAGE_LOADER_FLAGS_SYSTEM_GLOBAL 0x01000000 // Global subsections apply across TS sessions.
+
+// begin_winnt
+
+// Directory Entries
+
+#define IMAGE_DIRECTORY_ENTRY_EXPORT 0 // Export Directory
+#define IMAGE_DIRECTORY_ENTRY_IMPORT 1 // Import Directory
+#define IMAGE_DIRECTORY_ENTRY_RESOURCE 2 // Resource Directory
+#define IMAGE_DIRECTORY_ENTRY_EXCEPTION 3 // Exception Directory
+#define IMAGE_DIRECTORY_ENTRY_SECURITY 4 // Security Directory
+#define IMAGE_DIRECTORY_ENTRY_BASERELOC 5 // Base Relocation Table
+#define IMAGE_DIRECTORY_ENTRY_DEBUG 6 // Debug Directory
+// IMAGE_DIRECTORY_ENTRY_COPYRIGHT 7 // (X86 usage)
+#define IMAGE_DIRECTORY_ENTRY_ARCHITECTURE 7 // Architecture Specific Data
+#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8 // RVA of GP
+#define IMAGE_DIRECTORY_ENTRY_TLS 9 // TLS Directory
+#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10 // Load Configuration Directory
+#define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT 11 // Bound Import Directory in headers
+#define IMAGE_DIRECTORY_ENTRY_IAT 12 // Import Address Table
+#define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 13 // Delay Load Import Descriptors
+#define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14 // COM Runtime descriptor
+
+#ifdef _MSC_VER
+//
+// Non-COFF Object file header
+//
+
+typedef struct ANON_OBJECT_HEADER {
+ USHORT Sig1; // Must be IMAGE_FILE_MACHINE_UNKNOWN
+ USHORT Sig2; // Must be 0xffff
+ USHORT Version; // >= 1 (implies the CLSID field is present)
+ USHORT Machine;
+ ULONG TimeDateStamp;
+ CLSID ClassID; // Used to invoke CoCreateInstance
+ ULONG SizeOfData; // Size of data that follows the header
+} ANON_OBJECT_HEADER;
+#endif
+
+//
+// Section header format.
+//
+
+#define IMAGE_SIZEOF_SHORT_NAME 8
+
+typedef struct _IMAGE_SECTION_HEADER {
+ UCHAR Name[IMAGE_SIZEOF_SHORT_NAME];
+ union {
+ ULONG PhysicalAddress;
+ ULONG VirtualSize;
+ } Misc;
+ ULONG VirtualAddress;
+ ULONG SizeOfRawData;
+ ULONG PointerToRawData;
+ ULONG PointerToRelocations;
+ ULONG PointerToLinenumbers;
+ USHORT NumberOfRelocations;
+ USHORT NumberOfLinenumbers;
+ ULONG Characteristics;
+} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;
+
+#define IMAGE_SIZEOF_SECTION_HEADER 40
+
+//
+// Section characteristics.
+//
+// IMAGE_SCN_TYPE_REG 0x00000000 // Reserved.
+// IMAGE_SCN_TYPE_DSECT 0x00000001 // Reserved.
+// IMAGE_SCN_TYPE_NOLOAD 0x00000002 // Reserved.
+// IMAGE_SCN_TYPE_GROUP 0x00000004 // Reserved.
+#define IMAGE_SCN_TYPE_NO_PAD 0x00000008 // Reserved.
+// IMAGE_SCN_TYPE_COPY 0x00000010 // Reserved.
+
+#define IMAGE_SCN_CNT_CODE 0x00000020 // Section contains code.
+#define IMAGE_SCN_CNT_INITIALIZED_DATA 0x00000040 // Section contains initialized data.
+#define IMAGE_SCN_CNT_UNINITIALIZED_DATA 0x00000080 // Section contains uninitialized data.
+
+#define IMAGE_SCN_LNK_OTHER 0x00000100 // Reserved.
+#define IMAGE_SCN_LNK_INFO 0x00000200 // Section contains comments or some other type of information.
+// IMAGE_SCN_TYPE_OVER 0x00000400 // Reserved.
+#define IMAGE_SCN_LNK_REMOVE 0x00000800 // Section contents will not become part of image.
+#define IMAGE_SCN_LNK_COMDAT 0x00001000 // Section contents comdat.
+// 0x00002000 // Reserved.
+// IMAGE_SCN_MEM_PROTECTED - Obsolete 0x00004000
+#define IMAGE_SCN_NO_DEFER_SPEC_EXC 0x00004000 // Reset speculative exceptions handling bits in the TLB entries for this section.
+#define IMAGE_SCN_GPREL 0x00008000 // Section content can be accessed relative to GP
+#define IMAGE_SCN_MEM_FARDATA 0x00008000
+// IMAGE_SCN_MEM_SYSHEAP - Obsolete 0x00010000
+#define IMAGE_SCN_MEM_PURGEABLE 0x00020000
+#define IMAGE_SCN_MEM_16BIT 0x00020000
+#define IMAGE_SCN_MEM_LOCKED 0x00040000
+#define IMAGE_SCN_MEM_PRELOAD 0x00080000
+
+#define IMAGE_SCN_ALIGN_1BYTES 0x00100000 //
+#define IMAGE_SCN_ALIGN_2BYTES 0x00200000 //
+#define IMAGE_SCN_ALIGN_4BYTES 0x00300000 //
+#define IMAGE_SCN_ALIGN_8BYTES 0x00400000 //
+#define IMAGE_SCN_ALIGN_16BYTES 0x00500000 // Default alignment if no others are specified.
+#define IMAGE_SCN_ALIGN_32BYTES 0x00600000 //
+#define IMAGE_SCN_ALIGN_64BYTES 0x00700000 //
+#define IMAGE_SCN_ALIGN_128BYTES 0x00800000 //
+#define IMAGE_SCN_ALIGN_256BYTES 0x00900000 //
+#define IMAGE_SCN_ALIGN_512BYTES 0x00A00000 //
+#define IMAGE_SCN_ALIGN_1024BYTES 0x00B00000 //
+#define IMAGE_SCN_ALIGN_2048BYTES 0x00C00000 //
+#define IMAGE_SCN_ALIGN_4096BYTES 0x00D00000 //
+#define IMAGE_SCN_ALIGN_8192BYTES 0x00E00000 //
+// Unused 0x00F00000
+#define IMAGE_SCN_ALIGN_MASK 0x00F00000
+
+#define IMAGE_SCN_LNK_NRELOC_OVFL 0x01000000 // Section contains extended relocations.
+#define IMAGE_SCN_MEM_DISCARDABLE 0x02000000 // Section can be discarded.
+#define IMAGE_SCN_MEM_NOT_CACHED 0x04000000 // Section is not cachable.
+#define IMAGE_SCN_MEM_NOT_PAGED 0x08000000 // Section is not pageable.
+#define IMAGE_SCN_MEM_SHARED 0x10000000 // Section is shareable.
+#define IMAGE_SCN_MEM_EXECUTE 0x20000000 // Section is executable.
+#define IMAGE_SCN_MEM_READ 0x40000000 // Section is readable.
+#define IMAGE_SCN_MEM_WRITE 0x80000000 // Section is writeable.
+
+//
+// TLS Chaacteristic Flags
+//
+#define IMAGE_SCN_SCALE_INDEX 0x00000001 // Tls index is scaled
+
+#ifndef _MAC
+#include "pshpack2.h" // Symbols, relocs, and linenumbers are 2 byte packed
+#endif
+
+//
+// Symbol format.
+//
+
+typedef struct _IMAGE_SYMBOL {
+ union {
+ UCHAR ShortName[8];
+ struct {
+ ULONG Short; // if 0, use LongName
+ ULONG Long; // offset into string table
+ } Name;
+ ULONG LongName[2]; // PUCHAR[2]
+ } N;
+ ULONG Value;
+ SHORT SectionNumber;
+ USHORT Type;
+ UCHAR StorageClass;
+ UCHAR NumberOfAuxSymbols;
+} IMAGE_SYMBOL;
+typedef IMAGE_SYMBOL UNALIGNED *PIMAGE_SYMBOL;
+
+
+#define IMAGE_SIZEOF_SYMBOL 18
+
+//
+// Section values.
+//
+// Symbols have a section number of the section in which they are
+// defined. Otherwise, section numbers have the following meanings:
+//
+
+#define IMAGE_SYM_UNDEFINED (SHORT)0 // Symbol is undefined or is common.
+#define IMAGE_SYM_ABSOLUTE (SHORT)-1 // Symbol is an absolute value.
+#define IMAGE_SYM_DEBUG (SHORT)-2 // Symbol is a special debug item.
+#define IMAGE_SYM_SECTION_MAX 0xFEFF // Values 0xFF00-0xFFFF are special
+
+//
+// Type (fundamental) values.
+//
+
+#define IMAGE_SYM_TYPE_NULL 0x0000 // no type.
+#define IMAGE_SYM_TYPE_VOID 0x0001 //
+#define IMAGE_SYM_TYPE_CHAR 0x0002 // type character.
+#define IMAGE_SYM_TYPE_SHORT 0x0003 // type short integer.
+#define IMAGE_SYM_TYPE_INT 0x0004 //
+#define IMAGE_SYM_TYPE_LONG 0x0005 //
+#define IMAGE_SYM_TYPE_FLOAT 0x0006 //
+#define IMAGE_SYM_TYPE_DOUBLE 0x0007 //
+#define IMAGE_SYM_TYPE_STRUCT 0x0008 //
+#define IMAGE_SYM_TYPE_UNION 0x0009 //
+#define IMAGE_SYM_TYPE_ENUM 0x000A // enumeration.
+#define IMAGE_SYM_TYPE_MOE 0x000B // member of enumeration.
+#define IMAGE_SYM_TYPE_UCHAR 0x000C //
+#define IMAGE_SYM_TYPE_USHORT 0x000D //
+#define IMAGE_SYM_TYPE_UINT 0x000E //
+#define IMAGE_SYM_TYPE_ULONG 0x000F //
+#define IMAGE_SYM_TYPE_PCODE 0x8000 //
+//
+// Type (derived) values.
+//
+
+#define IMAGE_SYM_DTYPE_NULL 0 // no derived type.
+#define IMAGE_SYM_DTYPE_POINTER 1 // pointer.
+#define IMAGE_SYM_DTYPE_FUNCTION 2 // function.
+#define IMAGE_SYM_DTYPE_ARRAY 3 // array.
+
+//
+// Storage classes.
+//
+#define IMAGE_SYM_CLASS_END_OF_FUNCTION (UCHAR)-1
+#define IMAGE_SYM_CLASS_NULL 0x0000
+#define IMAGE_SYM_CLASS_AUTOMATIC 0x0001
+#define IMAGE_SYM_CLASS_EXTERNAL 0x0002
+#define IMAGE_SYM_CLASS_STATIC 0x0003
+#define IMAGE_SYM_CLASS_REGISTER 0x0004
+#define IMAGE_SYM_CLASS_EXTERNAL_DEF 0x0005
+#define IMAGE_SYM_CLASS_LABEL 0x0006
+#define IMAGE_SYM_CLASS_UNDEFINED_LABEL 0x0007
+#define IMAGE_SYM_CLASS_MEMBER_OF_STRUCT 0x0008
+#define IMAGE_SYM_CLASS_ARGUMENT 0x0009
+#define IMAGE_SYM_CLASS_STRUCT_TAG 0x000A
+#define IMAGE_SYM_CLASS_MEMBER_OF_UNION 0x000B
+#define IMAGE_SYM_CLASS_UNION_TAG 0x000C
+#define IMAGE_SYM_CLASS_TYPE_DEFINITION 0x000D
+#define IMAGE_SYM_CLASS_UNDEFINED_STATIC 0x000E
+#define IMAGE_SYM_CLASS_ENUM_TAG 0x000F
+#define IMAGE_SYM_CLASS_MEMBER_OF_ENUM 0x0010
+#define IMAGE_SYM_CLASS_REGISTER_PARAM 0x0011
+#define IMAGE_SYM_CLASS_BIT_FIELD 0x0012
+
+#define IMAGE_SYM_CLASS_FAR_EXTERNAL 0x0044 //
+
+#define IMAGE_SYM_CLASS_BLOCK 0x0064
+#define IMAGE_SYM_CLASS_FUNCTION 0x0065
+#define IMAGE_SYM_CLASS_END_OF_STRUCT 0x0066
+#define IMAGE_SYM_CLASS_FILE 0x0067
+// new
+#define IMAGE_SYM_CLASS_SECTION 0x0068
+#define IMAGE_SYM_CLASS_WEAK_EXTERNAL 0x0069
+
+#define IMAGE_SYM_CLASS_CLR_TOKEN 0x006B
+
+// type packing constants
+
+#define N_BTMASK 0x000F
+#define N_TMASK 0x0030
+#define N_TMASK1 0x00C0
+#define N_TMASK2 0x00F0
+#define N_BTSHFT 4
+#define N_TSHIFT 2
+// MACROS
+
+// Basic Type of x
+#define BTYPE(x) ((x) & N_BTMASK)
+
+// Is x a pointer?
+#ifndef ISPTR
+#define ISPTR(x) (((x) & N_TMASK) == (IMAGE_SYM_DTYPE_POINTER << N_BTSHFT))
+#endif
+
+// Is x a function?
+#ifndef ISFCN
+#define ISFCN(x) (((x) & N_TMASK) == (IMAGE_SYM_DTYPE_FUNCTION << N_BTSHFT))
+#endif
+
+// Is x an array?
+
+#ifndef ISARY
+#define ISARY(x) (((x) & N_TMASK) == (IMAGE_SYM_DTYPE_ARRAY << N_BTSHFT))
+#endif
+
+// Is x a structure, union, or enumeration TAG?
+#ifndef ISTAG
+#define ISTAG(x) ((x)==IMAGE_SYM_CLASS_STRUCT_TAG || (x)==IMAGE_SYM_CLASS_UNION_TAG || (x)==IMAGE_SYM_CLASS_ENUM_TAG)
+#endif
+
+#ifndef INCREF
+#define INCREF(x) ((((x)&~N_BTMASK)<<N_TSHIFT)|(IMAGE_SYM_DTYPE_POINTER<<N_BTSHFT)|((x)&N_BTMASK))
+#endif
+#ifndef DECREF
+#define DECREF(x) ((((x)>>N_TSHIFT)&~N_BTMASK)|((x)&N_BTMASK))
+#endif
+
+//
+// Auxiliary entry format.
+//
+
+typedef union _IMAGE_AUX_SYMBOL {
+ struct {
+ ULONG TagIndex; // struct, union, or enum tag index
+ union {
+ struct {
+ USHORT Linenumber; // declaration line number
+ USHORT Size; // size of struct, union, or enum
+ } LnSz;
+ ULONG TotalSize;
+ } Misc;
+ union {
+ struct { // if ISFCN, tag, or .bb
+ ULONG PointerToLinenumber;
+ ULONG PointerToNextFunction;
+ } Function;
+ struct { // if ISARY, up to 4 dimen.
+ USHORT Dimension[4];
+ } Array;
+ } FcnAry;
+ USHORT TvIndex; // tv index
+ } Sym;
+ struct {
+ UCHAR Name[IMAGE_SIZEOF_SYMBOL];
+ } File;
+ struct {
+ ULONG Length; // section length
+ USHORT NumberOfRelocations; // number of relocation entries
+ USHORT NumberOfLinenumbers; // number of line numbers
+ ULONG CheckSum; // checksum for communal
+ SHORT Number; // section number to associate with
+ UCHAR Selection; // communal selection type
+ } Section;
+} IMAGE_AUX_SYMBOL;
+typedef IMAGE_AUX_SYMBOL UNALIGNED *PIMAGE_AUX_SYMBOL;
+
+#define IMAGE_SIZEOF_AUX_SYMBOL 18
+
+typedef enum IMAGE_AUX_SYMBOL_TYPE {
+ IMAGE_AUX_SYMBOL_TYPE_TOKEN_DEF = 1,
+} IMAGE_AUX_SYMBOL_TYPE;
+
+#include "pshpack2.h"
+
+typedef struct IMAGE_AUX_SYMBOL_TOKEN_DEF {
+ UCHAR bAuxType; // IMAGE_AUX_SYMBOL_TYPE
+ UCHAR bReserved; // Must be 0
+ ULONG SymbolTableIndex;
+ UCHAR rgbReserved[12]; // Must be 0
+} IMAGE_AUX_SYMBOL_TOKEN_DEF;
+
+typedef IMAGE_AUX_SYMBOL_TOKEN_DEF UNALIGNED *PIMAGE_AUX_SYMBOL_TOKEN_DEF;
+
+#include "poppack.h"
+
+//
+// Communal selection types.
+//
+
+#define IMAGE_COMDAT_SELECT_NODUPLICATES 1
+#define IMAGE_COMDAT_SELECT_ANY 2
+#define IMAGE_COMDAT_SELECT_SAME_SIZE 3
+#define IMAGE_COMDAT_SELECT_EXACT_MATCH 4
+#define IMAGE_COMDAT_SELECT_ASSOCIATIVE 5
+#define IMAGE_COMDAT_SELECT_LARGEST 6
+#define IMAGE_COMDAT_SELECT_NEWEST 7
+
+#define IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY 1
+#define IMAGE_WEAK_EXTERN_SEARCH_LIBRARY 2
+#define IMAGE_WEAK_EXTERN_SEARCH_ALIAS 3
+
+//
+// Relocation format.
+//
+
+typedef struct _IMAGE_RELOCATION {
+ union {
+ ULONG VirtualAddress;
+ ULONG RelocCount; // Set to the real count when IMAGE_SCN_LNK_NRELOC_OVFL is set
+ };
+ ULONG SymbolTableIndex;
+ USHORT Type;
+} IMAGE_RELOCATION;
+typedef IMAGE_RELOCATION UNALIGNED *PIMAGE_RELOCATION;
+
+#define IMAGE_SIZEOF_RELOCATION 10
+
+//
+// I386 relocation types.
+//
+#define IMAGE_REL_I386_ABSOLUTE 0x0000 // Reference is absolute, no relocation is necessary
+#define IMAGE_REL_I386_DIR16 0x0001 // Direct 16-bit reference to the symbols virtual address
+#define IMAGE_REL_I386_REL16 0x0002 // PC-relative 16-bit reference to the symbols virtual address
+#define IMAGE_REL_I386_DIR32 0x0006 // Direct 32-bit reference to the symbols virtual address
+#define IMAGE_REL_I386_DIR32NB 0x0007 // Direct 32-bit reference to the symbols virtual address, base not included
+#define IMAGE_REL_I386_SEG12 0x0009 // Direct 16-bit reference to the segment-selector bits of a 32-bit virtual address
+#define IMAGE_REL_I386_SECTION 0x000A
+#define IMAGE_REL_I386_SECREL 0x000B
+#define IMAGE_REL_I386_TOKEN 0x000C // clr token
+#define IMAGE_REL_I386_SECREL7 0x000D // 7 bit offset from base of section containing target
+#define IMAGE_REL_I386_REL32 0x0014 // PC-relative 32-bit reference to the symbols virtual address
+
+//
+// MIPS relocation types.
+//
+#define IMAGE_REL_MIPS_ABSOLUTE 0x0000 // Reference is absolute, no relocation is necessary
+#define IMAGE_REL_MIPS_REFHALF 0x0001
+#define IMAGE_REL_MIPS_REFWORD 0x0002
+#define IMAGE_REL_MIPS_JMPADDR 0x0003
+#define IMAGE_REL_MIPS_REFHI 0x0004
+#define IMAGE_REL_MIPS_REFLO 0x0005
+#define IMAGE_REL_MIPS_GPREL 0x0006
+#define IMAGE_REL_MIPS_LITERAL 0x0007
+#define IMAGE_REL_MIPS_SECTION 0x000A
+#define IMAGE_REL_MIPS_SECREL 0x000B
+#define IMAGE_REL_MIPS_SECRELLO 0x000C // Low 16-bit section relative referemce (used for >32k TLS)
+#define IMAGE_REL_MIPS_SECRELHI 0x000D // High 16-bit section relative reference (used for >32k TLS)
+#define IMAGE_REL_MIPS_TOKEN 0x000E // clr token
+#define IMAGE_REL_MIPS_JMPADDR16 0x0010
+#define IMAGE_REL_MIPS_REFWORDNB 0x0022
+#define IMAGE_REL_MIPS_PAIR 0x0025
+
+//
+// Alpha Relocation types.
+//
+#define IMAGE_REL_ALPHA_ABSOLUTE 0x0000
+#define IMAGE_REL_ALPHA_REFLONG 0x0001
+#define IMAGE_REL_ALPHA_REFQUAD 0x0002
+#define IMAGE_REL_ALPHA_GPREL32 0x0003
+#define IMAGE_REL_ALPHA_LITERAL 0x0004
+#define IMAGE_REL_ALPHA_LITUSE 0x0005
+#define IMAGE_REL_ALPHA_GPDISP 0x0006
+#define IMAGE_REL_ALPHA_BRADDR 0x0007
+#define IMAGE_REL_ALPHA_HINT 0x0008
+#define IMAGE_REL_ALPHA_INLINE_REFLONG 0x0009
+#define IMAGE_REL_ALPHA_REFHI 0x000A
+#define IMAGE_REL_ALPHA_REFLO 0x000B
+#define IMAGE_REL_ALPHA_PAIR 0x000C
+#define IMAGE_REL_ALPHA_MATCH 0x000D
+#define IMAGE_REL_ALPHA_SECTION 0x000E
+#define IMAGE_REL_ALPHA_SECREL 0x000F
+#define IMAGE_REL_ALPHA_REFLONGNB 0x0010
+#define IMAGE_REL_ALPHA_SECRELLO 0x0011 // Low 16-bit section relative reference
+#define IMAGE_REL_ALPHA_SECRELHI 0x0012 // High 16-bit section relative reference
+#define IMAGE_REL_ALPHA_REFQ3 0x0013 // High 16 bits of 48 bit reference
+#define IMAGE_REL_ALPHA_REFQ2 0x0014 // Middle 16 bits of 48 bit reference
+#define IMAGE_REL_ALPHA_REFQ1 0x0015 // Low 16 bits of 48 bit reference
+#define IMAGE_REL_ALPHA_GPRELLO 0x0016 // Low 16-bit GP relative reference
+#define IMAGE_REL_ALPHA_GPRELHI 0x0017 // High 16-bit GP relative reference
+
+//
+// IBM PowerPC relocation types.
+//
+#define IMAGE_REL_PPC_ABSOLUTE 0x0000 // NOP
+#define IMAGE_REL_PPC_ADDR64 0x0001 // 64-bit address
+#define IMAGE_REL_PPC_ADDR32 0x0002 // 32-bit address
+#define IMAGE_REL_PPC_ADDR24 0x0003 // 26-bit address, shifted left 2 (branch absolute)
+#define IMAGE_REL_PPC_ADDR16 0x0004 // 16-bit address
+#define IMAGE_REL_PPC_ADDR14 0x0005 // 16-bit address, shifted left 2 (load doubleword)
+#define IMAGE_REL_PPC_REL24 0x0006 // 26-bit PC-relative offset, shifted left 2 (branch relative)
+#define IMAGE_REL_PPC_REL14 0x0007 // 16-bit PC-relative offset, shifted left 2 (br cond relative)
+#define IMAGE_REL_PPC_TOCREL16 0x0008 // 16-bit offset from TOC base
+#define IMAGE_REL_PPC_TOCREL14 0x0009 // 16-bit offset from TOC base, shifted left 2 (load doubleword)
+
+#define IMAGE_REL_PPC_ADDR32NB 0x000A // 32-bit addr w/o image base
+#define IMAGE_REL_PPC_SECREL 0x000B // va of containing section (as in an image sectionhdr)
+#define IMAGE_REL_PPC_SECTION 0x000C // sectionheader number
+#define IMAGE_REL_PPC_IFGLUE 0x000D // substitute TOC restore instruction iff symbol is glue code
+#define IMAGE_REL_PPC_IMGLUE 0x000E // symbol is glue code; virtual address is TOC restore instruction
+#define IMAGE_REL_PPC_SECREL16 0x000F // va of containing section (limited to 16 bits)
+#define IMAGE_REL_PPC_REFHI 0x0010
+#define IMAGE_REL_PPC_REFLO 0x0011
+#define IMAGE_REL_PPC_PAIR 0x0012
+#define IMAGE_REL_PPC_SECRELLO 0x0013 // Low 16-bit section relative reference (used for >32k TLS)
+#define IMAGE_REL_PPC_SECRELHI 0x0014 // High 16-bit section relative reference (used for >32k TLS)
+#define IMAGE_REL_PPC_GPREL 0x0015
+#define IMAGE_REL_PPC_TOKEN 0x0016 // clr token
+
+#define IMAGE_REL_PPC_TYPEMASK 0x00FF // mask to isolate above values in IMAGE_RELOCATION.Type
+
+// Flag bits in IMAGE_RELOCATION.TYPE
+
+#define IMAGE_REL_PPC_NEG 0x0100 // subtract reloc value rather than adding it
+#define IMAGE_REL_PPC_BRTAKEN 0x0200 // fix branch prediction bit to predict branch taken
+#define IMAGE_REL_PPC_BRNTAKEN 0x0400 // fix branch prediction bit to predict branch not taken
+#define IMAGE_REL_PPC_TOCDEFN 0x0800 // toc slot defined in file (or, data in toc)
+
+//
+// Hitachi SH3 relocation types.
+//
+#define IMAGE_REL_SH3_ABSOLUTE 0x0000 // No relocation
+#define IMAGE_REL_SH3_DIRECT16 0x0001 // 16 bit direct
+#define IMAGE_REL_SH3_DIRECT32 0x0002 // 32 bit direct
+#define IMAGE_REL_SH3_DIRECT8 0x0003 // 8 bit direct, -128..255
+#define IMAGE_REL_SH3_DIRECT8_WORD 0x0004 // 8 bit direct .W (0 ext.)
+#define IMAGE_REL_SH3_DIRECT8_LONG 0x0005 // 8 bit direct .L (0 ext.)
+#define IMAGE_REL_SH3_DIRECT4 0x0006 // 4 bit direct (0 ext.)
+#define IMAGE_REL_SH3_DIRECT4_WORD 0x0007 // 4 bit direct .W (0 ext.)
+#define IMAGE_REL_SH3_DIRECT4_LONG 0x0008 // 4 bit direct .L (0 ext.)
+#define IMAGE_REL_SH3_PCREL8_WORD 0x0009 // 8 bit PC relative .W
+#define IMAGE_REL_SH3_PCREL8_LONG 0x000A // 8 bit PC relative .L
+#define IMAGE_REL_SH3_PCREL12_WORD 0x000B // 12 LSB PC relative .W
+#define IMAGE_REL_SH3_STARTOF_SECTION 0x000C // Start of EXE section
+#define IMAGE_REL_SH3_SIZEOF_SECTION 0x000D // Size of EXE section
+#define IMAGE_REL_SH3_SECTION 0x000E // Section table index
+#define IMAGE_REL_SH3_SECREL 0x000F // Offset within section
+#define IMAGE_REL_SH3_DIRECT32_NB 0x0010 // 32 bit direct not based
+#define IMAGE_REL_SH3_GPREL4_LONG 0x0011 // GP-relative addressing
+#define IMAGE_REL_SH3_TOKEN 0x0012 // clr token
+
+#define IMAGE_REL_ARM_ABSOLUTE 0x0000 // No relocation required
+#define IMAGE_REL_ARM_ADDR32 0x0001 // 32 bit address
+#define IMAGE_REL_ARM_ADDR32NB 0x0002 // 32 bit address w/o image base
+#define IMAGE_REL_ARM_BRANCH24 0x0003 // 24 bit offset << 2 & sign ext.
+#define IMAGE_REL_ARM_BRANCH11 0x0004 // Thumb: 2 11 bit offsets
+#define IMAGE_REL_ARM_TOKEN 0x0005 // clr token
+#define IMAGE_REL_ARM_GPREL12 0x0006 // GP-relative addressing (ARM)
+#define IMAGE_REL_ARM_GPREL7 0x0007 // GP-relative addressing (Thumb)
+#define IMAGE_REL_ARM_BLX24 0x0008
+#define IMAGE_REL_ARM_BLX11 0x0009
+#define IMAGE_REL_ARM_SECTION 0x000E // Section table index
+#define IMAGE_REL_ARM_SECREL 0x000F // Offset within section
+
+//
+// ARM64 relocation types
+//
+#define IMAGE_REL_ARM64_ABSOLUTE 0x0000
+#define IMAGE_REL_ARM64_ADDR32 0x0001
+#define IMAGE_REL_ARM64_ADDR32NB 0x0002
+#define IMAGE_REL_ARM64_BRANCH26 0x0003
+#define IMAGE_REL_ARM64_PAGEBASE_REL21 0x0004
+#define IMAGE_REL_ARM64_REL21 0x0005
+#define IMAGE_REL_ARM64_PAGEOFFSET_12A 0x0006
+#define IMAGE_REL_ARM64_PAGEOFFSET_12L 0x0007
+#define IMAGE_REL_ARM64_SECREL 0x0008
+#define IMAGE_REL_ARM64_SECREL_LOW12A 0x0009
+#define IMAGE_REL_ARM64_SECREL_HIGH12A 0x000A
+#define IMAGE_REL_ARM64_SECREL_LOW12L 0x000B
+#define IMAGE_REL_ARM64_TOKEN 0x000C
+#define IMAGE_REL_ARM64_SECTION 0x000D
+#define IMAGE_REL_ARM64_ADDR64 0x000E
+
+#define IMAGE_REL_AM_ABSOLUTE 0x0000
+#define IMAGE_REL_AM_ADDR32 0x0001
+#define IMAGE_REL_AM_ADDR32NB 0x0002
+#define IMAGE_REL_AM_CALL32 0x0003
+#define IMAGE_REL_AM_FUNCINFO 0x0004
+#define IMAGE_REL_AM_REL32_1 0x0005
+#define IMAGE_REL_AM_REL32_2 0x0006
+#define IMAGE_REL_AM_SECREL 0x0007
+#define IMAGE_REL_AM_SECTION 0x0008
+#define IMAGE_REL_AM_TOKEN 0x0009
+
+//
+// X86-64 relocations
+//
+#define IMAGE_REL_AMD64_ABSOLUTE 0x0000 // Reference is absolute, no relocation is necessary
+#define IMAGE_REL_AMD64_ADDR64 0x0001 // 64-bit address (VA).
+#define IMAGE_REL_AMD64_ADDR32 0x0002 // 32-bit address (VA).
+#define IMAGE_REL_AMD64_ADDR32NB 0x0003 // 32-bit address w/o image base (RVA).
+#define IMAGE_REL_AMD64_REL32 0x0004 // 32-bit relative address from byte following reloc
+#define IMAGE_REL_AMD64_REL32_1 0x0005 // 32-bit relative address from byte distance 1 from reloc
+#define IMAGE_REL_AMD64_REL32_2 0x0006 // 32-bit relative address from byte distance 2 from reloc
+#define IMAGE_REL_AMD64_REL32_3 0x0007 // 32-bit relative address from byte distance 3 from reloc
+#define IMAGE_REL_AMD64_REL32_4 0x0008 // 32-bit relative address from byte distance 4 from reloc
+#define IMAGE_REL_AMD64_REL32_5 0x0009 // 32-bit relative address from byte distance 5 from reloc
+#define IMAGE_REL_AMD64_SECTION 0x000A // Section index
+#define IMAGE_REL_AMD64_SECREL 0x000B // 32 bit offset from base of section containing target
+#define IMAGE_REL_AMD64_SECREL7 0x000C // 7 bit unsigned offset from base of section containing target
+#define IMAGE_REL_AMD64_TOKEN 0x000D // 32 bit metadata token
+
+//
+// IA64 relocation types.
+//
+#define IMAGE_REL_IA64_ABSOLUTE 0x0000
+#define IMAGE_REL_IA64_IMM14 0x0001
+#define IMAGE_REL_IA64_IMM22 0x0002
+#define IMAGE_REL_IA64_IMM64 0x0003
+#define IMAGE_REL_IA64_DIR32 0x0004
+#define IMAGE_REL_IA64_DIR64 0x0005
+#define IMAGE_REL_IA64_PCREL21B 0x0006
+#define IMAGE_REL_IA64_PCREL21M 0x0007
+#define IMAGE_REL_IA64_PCREL21F 0x0008
+#define IMAGE_REL_IA64_GPREL22 0x0009
+#define IMAGE_REL_IA64_LTOFF22 0x000A
+#define IMAGE_REL_IA64_SECTION 0x000B
+#define IMAGE_REL_IA64_SECREL22 0x000C
+#define IMAGE_REL_IA64_SECREL64I 0x000D
+#define IMAGE_REL_IA64_SECREL32 0x000E
+//
+#define IMAGE_REL_IA64_DIR32NB 0x0010
+#define IMAGE_REL_IA64_SREL14 0x0011
+#define IMAGE_REL_IA64_SREL22 0x0012
+#define IMAGE_REL_IA64_SREL32 0x0013
+#define IMAGE_REL_IA64_UREL32 0x0014
+#define IMAGE_REL_IA64_PCREL60X 0x0015 // This is always a BRL and never converted
+#define IMAGE_REL_IA64_PCREL60B 0x0016 // If possible, convert to MBB bundle with NOP.B in slot 1
+#define IMAGE_REL_IA64_PCREL60F 0x0017 // If possible, convert to MFB bundle with NOP.F in slot 1
+#define IMAGE_REL_IA64_PCREL60I 0x0018 // If possible, convert to MIB bundle with NOP.I in slot 1
+#define IMAGE_REL_IA64_PCREL60M 0x0019 // If possible, convert to MMB bundle with NOP.M in slot 1
+#define IMAGE_REL_IA64_IMMGPREL64 0x001A
+#define IMAGE_REL_IA64_TOKEN 0x001B // clr token
+#define IMAGE_REL_IA64_GPREL32 0x001C
+#define IMAGE_REL_IA64_ADDEND 0x001F
+
+//
+// CEF relocation types.
+//
+#define IMAGE_REL_CEF_ABSOLUTE 0x0000 // Reference is absolute, no relocation is necessary
+#define IMAGE_REL_CEF_ADDR32 0x0001 // 32-bit address (VA).
+#define IMAGE_REL_CEF_ADDR64 0x0002 // 64-bit address (VA).
+#define IMAGE_REL_CEF_ADDR32NB 0x0003 // 32-bit address w/o image base (RVA).
+#define IMAGE_REL_CEF_SECTION 0x0004 // Section index
+#define IMAGE_REL_CEF_SECREL 0x0005 // 32 bit offset from base of section containing target
+#define IMAGE_REL_CEF_TOKEN 0x0006 // 32 bit metadata token
+
+//
+// clr relocation types.
+//
+#define IMAGE_REL_CEE_ABSOLUTE 0x0000 // Reference is absolute, no relocation is necessary
+#define IMAGE_REL_CEE_ADDR32 0x0001 // 32-bit address (VA).
+#define IMAGE_REL_CEE_ADDR64 0x0002 // 64-bit address (VA).
+#define IMAGE_REL_CEE_ADDR32NB 0x0003 // 32-bit address w/o image base (RVA).
+#define IMAGE_REL_CEE_SECTION 0x0004 // Section index
+#define IMAGE_REL_CEE_SECREL 0x0005 // 32 bit offset from base of section containing target
+#define IMAGE_REL_CEE_TOKEN 0x0006 // 32 bit metadata token
+
+
+#define IMAGE_REL_M32R_ABSOLUTE 0x0000 // No relocation required
+#define IMAGE_REL_M32R_ADDR32 0x0001 // 32 bit address
+#define IMAGE_REL_M32R_ADDR32NB 0x0002 // 32 bit address w/o image base
+#define IMAGE_REL_M32R_ADDR24 0x0003 // 24 bit address
+#define IMAGE_REL_M32R_GPREL16 0x0004 // GP relative addressing
+#define IMAGE_REL_M32R_PCREL24 0x0005 // 24 bit offset << 2 & sign ext.
+#define IMAGE_REL_M32R_PCREL16 0x0006 // 16 bit offset << 2 & sign ext.
+#define IMAGE_REL_M32R_PCREL8 0x0007 // 8 bit offset << 2 & sign ext.
+#define IMAGE_REL_M32R_REFHALF 0x0008 // 16 MSBs
+#define IMAGE_REL_M32R_REFHI 0x0009 // 16 MSBs; adj for LSB sign ext.
+#define IMAGE_REL_M32R_REFLO 0x000A // 16 LSBs
+#define IMAGE_REL_M32R_PAIR 0x000B // Link HI and LO
+#define IMAGE_REL_M32R_SECTION 0x000C // Section table index
+#define IMAGE_REL_M32R_SECREL32 0x000D // 32 bit section relative reference
+#define IMAGE_REL_M32R_TOKEN 0x000E // clr token
+
+
+#define EXT_IMM64(Value, Address, Size, InstPos, ValPos) /* Intel-IA64-Filler */ \
+ Value |= (((ULONGLONG)((*(Address) >> InstPos) & (((ULONGLONG)1 << Size) - 1))) << ValPos) // Intel-IA64-Filler
+
+#define INS_IMM64(Value, Address, Size, InstPos, ValPos) /* Intel-IA64-Filler */\
+ *(PULONG)Address = (*(PULONG)Address & ~(((1 << Size) - 1) << InstPos)) | /* Intel-IA64-Filler */\
+ ((ULONG)((((ULONGLONG)Value >> ValPos) & (((ULONGLONG)1 << Size) - 1))) << InstPos) // Intel-IA64-Filler
+
+#define EMARCH_ENC_I17_IMM7B_INST_WORD_X 3 // Intel-IA64-Filler
+#define EMARCH_ENC_I17_IMM7B_SIZE_X 7 // Intel-IA64-Filler
+#define EMARCH_ENC_I17_IMM7B_INST_WORD_POS_X 4 // Intel-IA64-Filler
+#define EMARCH_ENC_I17_IMM7B_VAL_POS_X 0 // Intel-IA64-Filler
+
+#define EMARCH_ENC_I17_IMM9D_INST_WORD_X 3 // Intel-IA64-Filler
+#define EMARCH_ENC_I17_IMM9D_SIZE_X 9 // Intel-IA64-Filler
+#define EMARCH_ENC_I17_IMM9D_INST_WORD_POS_X 18 // Intel-IA64-Filler
+#define EMARCH_ENC_I17_IMM9D_VAL_POS_X 7 // Intel-IA64-Filler
+
+#define EMARCH_ENC_I17_IMM5C_INST_WORD_X 3 // Intel-IA64-Filler
+#define EMARCH_ENC_I17_IMM5C_SIZE_X 5 // Intel-IA64-Filler
+#define EMARCH_ENC_I17_IMM5C_INST_WORD_POS_X 13 // Intel-IA64-Filler
+#define EMARCH_ENC_I17_IMM5C_VAL_POS_X 16 // Intel-IA64-Filler
+
+#define EMARCH_ENC_I17_IC_INST_WORD_X 3 // Intel-IA64-Filler
+#define EMARCH_ENC_I17_IC_SIZE_X 1 // Intel-IA64-Filler
+#define EMARCH_ENC_I17_IC_INST_WORD_POS_X 12 // Intel-IA64-Filler
+#define EMARCH_ENC_I17_IC_VAL_POS_X 21 // Intel-IA64-Filler
+
+#define EMARCH_ENC_I17_IMM41a_INST_WORD_X 1 // Intel-IA64-Filler
+#define EMARCH_ENC_I17_IMM41a_SIZE_X 10 // Intel-IA64-Filler
+#define EMARCH_ENC_I17_IMM41a_INST_WORD_POS_X 14 // Intel-IA64-Filler
+#define EMARCH_ENC_I17_IMM41a_VAL_POS_X 22 // Intel-IA64-Filler
+
+#define EMARCH_ENC_I17_IMM41b_INST_WORD_X 1 // Intel-IA64-Filler
+#define EMARCH_ENC_I17_IMM41b_SIZE_X 8 // Intel-IA64-Filler
+#define EMARCH_ENC_I17_IMM41b_INST_WORD_POS_X 24 // Intel-IA64-Filler
+#define EMARCH_ENC_I17_IMM41b_VAL_POS_X 32 // Intel-IA64-Filler
+
+#define EMARCH_ENC_I17_IMM41c_INST_WORD_X 2 // Intel-IA64-Filler
+#define EMARCH_ENC_I17_IMM41c_SIZE_X 23 // Intel-IA64-Filler
+#define EMARCH_ENC_I17_IMM41c_INST_WORD_POS_X 0 // Intel-IA64-Filler
+#define EMARCH_ENC_I17_IMM41c_VAL_POS_X 40 // Intel-IA64-Filler
+
+#define EMARCH_ENC_I17_SIGN_INST_WORD_X 3 // Intel-IA64-Filler
+#define EMARCH_ENC_I17_SIGN_SIZE_X 1 // Intel-IA64-Filler
+#define EMARCH_ENC_I17_SIGN_INST_WORD_POS_X 27 // Intel-IA64-Filler
+#define EMARCH_ENC_I17_SIGN_VAL_POS_X 63 // Intel-IA64-Filler
+
+
+//
+// Line number format.
+//
+
+typedef struct _IMAGE_LINENUMBER {
+ union {
+ ULONG SymbolTableIndex; // Symbol table index of function name if Linenumber is 0.
+ ULONG VirtualAddress; // Virtual address of line number.
+ } Type;
+ USHORT Linenumber; // Line number.
+} IMAGE_LINENUMBER;
+typedef IMAGE_LINENUMBER UNALIGNED *PIMAGE_LINENUMBER;
+
+#define IMAGE_SIZEOF_LINENUMBER 6
+
+#ifndef _MAC
+#include "poppack.h" // Back to 4 byte packing
+#endif
+
+//
+// Based relocation format.
+//
+
+typedef struct _IMAGE_BASE_RELOCATION {
+ ULONG VirtualAddress;
+ ULONG SizeOfBlock;
+// USHORT TypeOffset[1];
+} IMAGE_BASE_RELOCATION;
+typedef IMAGE_BASE_RELOCATION UNALIGNED * PIMAGE_BASE_RELOCATION;
+
+#define IMAGE_SIZEOF_BASE_RELOCATION 8
+
+//
+// Based relocation types.
+//
+
+#define IMAGE_REL_BASED_ABSOLUTE 0
+#define IMAGE_REL_BASED_HIGH 1
+#define IMAGE_REL_BASED_LOW 2
+#define IMAGE_REL_BASED_HIGHLOW 3
+#define IMAGE_REL_BASED_HIGHADJ 4
+#define IMAGE_REL_BASED_MACHINE_SPECIFIC_5 5
+#define IMAGE_REL_BASED_RESERVED 6
+#define IMAGE_REL_BASED_MACHINE_SPECIFIC_7 7
+#define IMAGE_REL_BASED_MACHINE_SPECIFIC_8 8
+#define IMAGE_REL_BASED_MACHINE_SPECIFIC_9 9
+#define IMAGE_REL_BASED_DIR64 10
+
+//
+// Platform-specific based relocation types.
+//
+
+#define IMAGE_REL_BASED_IA64_IMM64 9
+
+#define IMAGE_REL_BASED_MIPS_JMPADDR 5
+#define IMAGE_REL_BASED_MIPS_JMPADDR16 9
+
+#define IMAGE_REL_BASED_ARM_MOV32 5
+#define IMAGE_REL_BASED_THUMB_MOV32 7
+
+//
+// Archive format.
+//
+
+#define IMAGE_ARCHIVE_START_SIZE 8
+#define IMAGE_ARCHIVE_START "!<arch>\n"
+#define IMAGE_ARCHIVE_END "`\n"
+#define IMAGE_ARCHIVE_PAD "\n"
+#define IMAGE_ARCHIVE_LINKER_MEMBER "/ "
+#define IMAGE_ARCHIVE_LONGNAMES_MEMBER "// "
+
+typedef struct _IMAGE_ARCHIVE_MEMBER_HEADER {
+ UCHAR Name[16]; // File member name - `/' terminated.
+ UCHAR Date[12]; // File member date - decimal.
+ UCHAR UserID[6]; // File member user id - decimal.
+ UCHAR GroupID[6]; // File member group id - decimal.
+ UCHAR Mode[8]; // File member mode - octal.
+ UCHAR Size[10]; // File member size - decimal.
+ UCHAR EndHeader[2]; // String to end header.
+} IMAGE_ARCHIVE_MEMBER_HEADER, *PIMAGE_ARCHIVE_MEMBER_HEADER;
+
+#define IMAGE_SIZEOF_ARCHIVE_MEMBER_HDR 60
+
+//
+// DLL support.
+//
+
+//
+// Export Format
+//
+
+typedef struct _IMAGE_EXPORT_DIRECTORY {
+ ULONG Characteristics;
+ ULONG TimeDateStamp;
+ USHORT MajorVersion;
+ USHORT MinorVersion;
+ ULONG Name;
+ ULONG Base;
+ ULONG NumberOfFunctions;
+ ULONG NumberOfNames;
+ ULONG AddressOfFunctions; // RVA from base of image
+ ULONG AddressOfNames; // RVA from base of image
+ ULONG AddressOfNameOrdinals; // RVA from base of image
+} IMAGE_EXPORT_DIRECTORY, *PIMAGE_EXPORT_DIRECTORY;
+
+//
+// Import Format
+//
+
+typedef struct _IMAGE_IMPORT_BY_NAME {
+ USHORT Hint;
+ UCHAR Name[1];
+} IMAGE_IMPORT_BY_NAME, *PIMAGE_IMPORT_BY_NAME;
+
+#include "pshpack8.h" // Use align 8 for the 64-bit IAT.
+
+typedef struct _IMAGE_THUNK_DATA64 {
+ union {
+ ULONGLONG ForwarderString; // PUCHAR
+ ULONGLONG Function; // PULONG
+ ULONGLONG Ordinal;
+ ULONGLONG AddressOfData; // PIMAGE_IMPORT_BY_NAME
+ } u1;
+} IMAGE_THUNK_DATA64;
+typedef IMAGE_THUNK_DATA64 * PIMAGE_THUNK_DATA64;
+
+#include "poppack.h" // Back to 4 byte packing
+
+typedef struct _IMAGE_THUNK_DATA32 {
+ union {
+ ULONG ForwarderString; // PUCHAR
+ ULONG Function; // PULONG
+ ULONG Ordinal;
+ ULONG AddressOfData; // PIMAGE_IMPORT_BY_NAME
+ } u1;
+} IMAGE_THUNK_DATA32;
+typedef IMAGE_THUNK_DATA32 * PIMAGE_THUNK_DATA32;
+
+#define IMAGE_ORDINAL_FLAG64 0x8000000000000000
+#define IMAGE_ORDINAL_FLAG32 0x80000000
+#define IMAGE_ORDINAL64(Ordinal) (Ordinal & 0xffff)
+#define IMAGE_ORDINAL32(Ordinal) (Ordinal & 0xffff)
+#define IMAGE_SNAP_BY_ORDINAL64(Ordinal) ((Ordinal & IMAGE_ORDINAL_FLAG64) != 0)
+#define IMAGE_SNAP_BY_ORDINAL32(Ordinal) ((Ordinal & IMAGE_ORDINAL_FLAG32) != 0)
+
+//
+// Thread Local Storage
+//
+
+#ifdef _MSC_VER
+typedef VOID
+(NTAPI *PIMAGE_TLS_CALLBACK) (
+ PVOID DllHandle,
+ ULONG Reason,
+ PVOID Reserved
+ );
+#endif
+
+typedef struct _IMAGE_TLS_DIRECTORY64 {
+ ULONGLONG StartAddressOfRawData;
+ ULONGLONG EndAddressOfRawData;
+ ULONGLONG AddressOfIndex; // PULONG
+ ULONGLONG AddressOfCallBacks; // PIMAGE_TLS_CALLBACK *;
+ ULONG SizeOfZeroFill;
+ ULONG Characteristics;
+} IMAGE_TLS_DIRECTORY64;
+typedef IMAGE_TLS_DIRECTORY64 * PIMAGE_TLS_DIRECTORY64;
+
+typedef struct _IMAGE_TLS_DIRECTORY32 {
+ ULONG StartAddressOfRawData;
+ ULONG EndAddressOfRawData;
+ ULONG AddressOfIndex; // PULONG
+ ULONG AddressOfCallBacks; // PIMAGE_TLS_CALLBACK *
+ ULONG SizeOfZeroFill;
+ ULONG Characteristics;
+} IMAGE_TLS_DIRECTORY32;
+typedef IMAGE_TLS_DIRECTORY32 * PIMAGE_TLS_DIRECTORY32;
+
+#ifdef _WIN64
+#define IMAGE_ORDINAL_FLAG IMAGE_ORDINAL_FLAG64
+#define IMAGE_ORDINAL(Ordinal) IMAGE_ORDINAL64(Ordinal)
+typedef IMAGE_THUNK_DATA64 IMAGE_THUNK_DATA;
+typedef PIMAGE_THUNK_DATA64 PIMAGE_THUNK_DATA;
+#define IMAGE_SNAP_BY_ORDINAL(Ordinal) IMAGE_SNAP_BY_ORDINAL64(Ordinal)
+typedef IMAGE_TLS_DIRECTORY64 IMAGE_TLS_DIRECTORY;
+typedef PIMAGE_TLS_DIRECTORY64 PIMAGE_TLS_DIRECTORY;
+#else
+#define IMAGE_ORDINAL_FLAG IMAGE_ORDINAL_FLAG32
+#define IMAGE_ORDINAL(Ordinal) IMAGE_ORDINAL32(Ordinal)
+typedef IMAGE_THUNK_DATA32 IMAGE_THUNK_DATA;
+typedef PIMAGE_THUNK_DATA32 PIMAGE_THUNK_DATA;
+#define IMAGE_SNAP_BY_ORDINAL(Ordinal) IMAGE_SNAP_BY_ORDINAL32(Ordinal)
+typedef IMAGE_TLS_DIRECTORY32 IMAGE_TLS_DIRECTORY;
+typedef PIMAGE_TLS_DIRECTORY32 PIMAGE_TLS_DIRECTORY;
+#endif
+
+typedef struct _IMAGE_IMPORT_DESCRIPTOR {
+ union {
+ ULONG Characteristics; // 0 for terminating null import descriptor
+ ULONG OriginalFirstThunk; // RVA to original unbound IAT (PIMAGE_THUNK_DATA)
+ } u;
+ ULONG TimeDateStamp; // 0 if not bound,
+ // -1 if bound, and real date\time stamp
+ // in IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT (new BIND)
+ // O.W. date/time stamp of DLL bound to (Old BIND)
+
+ ULONG ForwarderChain; // -1 if no forwarders
+ ULONG Name;
+ ULONG FirstThunk; // RVA to IAT (if bound this IAT has actual addresses)
+} IMAGE_IMPORT_DESCRIPTOR;
+typedef IMAGE_IMPORT_DESCRIPTOR UNALIGNED *PIMAGE_IMPORT_DESCRIPTOR;
+
+//
+// New format import descriptors pointed to by DataDirectory[ IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT ]
+//
+
+typedef struct _IMAGE_BOUND_IMPORT_DESCRIPTOR {
+ ULONG TimeDateStamp;
+ USHORT OffsetModuleName;
+ USHORT NumberOfModuleForwarderRefs;
+// Array of zero or more IMAGE_BOUND_FORWARDER_REF follows
+} IMAGE_BOUND_IMPORT_DESCRIPTOR, *PIMAGE_BOUND_IMPORT_DESCRIPTOR;
+
+typedef struct _IMAGE_BOUND_FORWARDER_REF {
+ ULONG TimeDateStamp;
+ USHORT OffsetModuleName;
+ USHORT Reserved;
+} IMAGE_BOUND_FORWARDER_REF, *PIMAGE_BOUND_FORWARDER_REF;
+
+//
+// Resource Format.
+//
+
+//
+// Resource directory consists of two counts, following by a variable length
+// array of directory entries. The first count is the number of entries at
+// beginning of the array that have actual names associated with each entry.
+// The entries are in ascending order, case insensitive strings. The second
+// count is the number of entries that immediately follow the named entries.
+// This second count identifies the number of entries that have 16-bit integer
+// Ids as their name. These entries are also sorted in ascending order.
+//
+// This structure allows fast lookup by either name or number, but for any
+// given resource entry only one form of lookup is supported, not both.
+// This is consistant with the syntax of the .RC file and the .RES file.
+//
+
+typedef struct _IMAGE_RESOURCE_DIRECTORY {
+ ULONG Characteristics;
+ ULONG TimeDateStamp;
+ USHORT MajorVersion;
+ USHORT MinorVersion;
+ USHORT NumberOfNamedEntries;
+ USHORT NumberOfIdEntries;
+// IMAGE_RESOURCE_DIRECTORY_ENTRY DirectoryEntries[];
+} IMAGE_RESOURCE_DIRECTORY, *PIMAGE_RESOURCE_DIRECTORY;
+
+#define IMAGE_RESOURCE_NAME_IS_STRING 0x80000000
+#define IMAGE_RESOURCE_DATA_IS_DIRECTORY 0x80000000
+//
+// Each directory contains the 32-bit Name of the entry and an offset,
+// relative to the beginning of the resource directory of the data associated
+// with this directory entry. If the name of the entry is an actual text
+// string instead of an integer Id, then the high order bit of the name field
+// is set to one and the low order 31-bits are an offset, relative to the
+// beginning of the resource directory of the string, which is of type
+// IMAGE_RESOURCE_DIRECTORY_STRING. Otherwise the high bit is clear and the
+// low-order 16-bits are the integer Id that identify this resource directory
+// entry. If the directory entry is yet another resource directory (i.e. a
+// subdirectory), then the high order bit of the offset field will be
+// set to indicate this. Otherwise the high bit is clear and the offset
+// field points to a resource data entry.
+//
+
+typedef struct _IMAGE_RESOURCE_DIRECTORY_ENTRY {
+ union {
+ struct {
+ ULONG NameOffset:31;
+ ULONG NameIsString:1;
+ };
+ ULONG Name;
+ USHORT Id;
+ };
+ union {
+ ULONG OffsetToData;
+ struct {
+ ULONG OffsetToDirectory:31;
+ ULONG DataIsDirectory:1;
+ };
+ };
+} IMAGE_RESOURCE_DIRECTORY_ENTRY, *PIMAGE_RESOURCE_DIRECTORY_ENTRY;
+
+//
+// For resource directory entries that have actual string names, the Name
+// field of the directory entry points to an object of the following type.
+// All of these string objects are stored together after the last resource
+// directory entry and before the first resource data object. This minimizes
+// the impact of these variable length objects on the alignment of the fixed
+// size directory entry objects.
+//
+
+typedef struct _IMAGE_RESOURCE_DIRECTORY_STRING {
+ USHORT Length;
+ CHAR NameString[ 1 ];
+} IMAGE_RESOURCE_DIRECTORY_STRING, *PIMAGE_RESOURCE_DIRECTORY_STRING;
+
+
+typedef struct _IMAGE_RESOURCE_DIR_STRING_U {
+ USHORT Length;
+ WCHAR NameString[ 1 ];
+} IMAGE_RESOURCE_DIR_STRING_U, *PIMAGE_RESOURCE_DIR_STRING_U;
+
+
+//
+// Each resource data entry describes a leaf node in the resource directory
+// tree. It contains an offset, relative to the beginning of the resource
+// directory of the data for the resource, a size field that gives the number
+// of bytes of data at that offset, a CodePage that should be used when
+// decoding code point values within the resource data. Typically for new
+// applications the code page would be the unicode code page.
+//
+
+typedef struct _IMAGE_RESOURCE_DATA_ENTRY {
+ ULONG OffsetToData;
+ ULONG Size;
+ ULONG CodePage;
+ ULONG Reserved;
+} IMAGE_RESOURCE_DATA_ENTRY, *PIMAGE_RESOURCE_DATA_ENTRY;
+
+//
+// Load Configuration Directory Entry
+//
+
+typedef struct {
+ ULONG Characteristics;
+ ULONG TimeDateStamp;
+ USHORT MajorVersion;
+ USHORT MinorVersion;
+ ULONG GlobalFlagsClear;
+ ULONG GlobalFlagsSet;
+ ULONG CriticalSectionDefaultTimeout;
+ ULONG DeCommitFreeBlockThreshold;
+ ULONG DeCommitTotalFreeThreshold;
+ ULONG LockPrefixTable; // VA
+ ULONG MaximumAllocationSize;
+ ULONG VirtualMemoryThreshold;
+ ULONG ProcessHeapFlags;
+ ULONG ProcessAffinityMask;
+ USHORT CSDVersion;
+ USHORT Reserved1;
+ ULONG EditList; // VA
+ ULONG Reserved[ 1 ];
+} IMAGE_LOAD_CONFIG_DIRECTORY32, *PIMAGE_LOAD_CONFIG_DIRECTORY32;
+
+typedef struct {
+ ULONG Characteristics;
+ ULONG TimeDateStamp;
+ USHORT MajorVersion;
+ USHORT MinorVersion;
+ ULONG GlobalFlagsClear;
+ ULONG GlobalFlagsSet;
+ ULONG CriticalSectionDefaultTimeout;
+ ULONGLONG DeCommitFreeBlockThreshold;
+ ULONGLONG DeCommitTotalFreeThreshold;
+ ULONGLONG LockPrefixTable; // VA
+ ULONGLONG MaximumAllocationSize;
+ ULONGLONG VirtualMemoryThreshold;
+ ULONGLONG ProcessAffinityMask;
+ ULONG ProcessHeapFlags;
+ USHORT CSDVersion;
+ USHORT Reserved1;
+ ULONGLONG EditList; // VA
+ ULONG Reserved[ 2 ];
+} IMAGE_LOAD_CONFIG_DIRECTORY64, *PIMAGE_LOAD_CONFIG_DIRECTORY64;
+
+#ifdef _WIN64
+typedef IMAGE_LOAD_CONFIG_DIRECTORY64 IMAGE_LOAD_CONFIG_DIRECTORY;
+typedef PIMAGE_LOAD_CONFIG_DIRECTORY64 PIMAGE_LOAD_CONFIG_DIRECTORY;
+#else
+typedef IMAGE_LOAD_CONFIG_DIRECTORY32 IMAGE_LOAD_CONFIG_DIRECTORY;
+typedef PIMAGE_LOAD_CONFIG_DIRECTORY32 PIMAGE_LOAD_CONFIG_DIRECTORY;
+#endif
+
+//
+// WIN CE Exception table format
+//
+
+//
+// Function table entry format. Function table is pointed to by the
+// IMAGE_DIRECTORY_ENTRY_EXCEPTION directory entry.
+//
+
+typedef struct _IMAGE_CE_RUNTIME_FUNCTION_ENTRY {
+ ULONG FuncStart;
+ ULONG PrologLen : 8;
+ ULONG FuncLen : 22;
+ ULONG ThirtyTwoBit : 1;
+ ULONG ExceptionFlag : 1;
+} IMAGE_CE_RUNTIME_FUNCTION_ENTRY, * PIMAGE_CE_RUNTIME_FUNCTION_ENTRY;
+
+typedef struct _IMAGE_ALPHA64_RUNTIME_FUNCTION_ENTRY {
+ ULONGLONG BeginAddress;
+ ULONGLONG EndAddress;
+ ULONGLONG ExceptionHandler;
+ ULONGLONG HandlerData;
+ ULONGLONG PrologEndAddress;
+} IMAGE_ALPHA64_RUNTIME_FUNCTION_ENTRY, *PIMAGE_ALPHA64_RUNTIME_FUNCTION_ENTRY;
+
+typedef struct _IMAGE_ALPHA_RUNTIME_FUNCTION_ENTRY {
+ ULONG BeginAddress;
+ ULONG EndAddress;
+ ULONG ExceptionHandler;
+ ULONG HandlerData;
+ ULONG PrologEndAddress;
+} IMAGE_ALPHA_RUNTIME_FUNCTION_ENTRY, *PIMAGE_ALPHA_RUNTIME_FUNCTION_ENTRY;
+
+typedef struct _IMAGE_RUNTIME_FUNCTION_ENTRY {
+ ULONG BeginAddress;
+ ULONG EndAddress;
+ ULONG UnwindInfoAddress;
+} _IMAGE_RUNTIME_FUNCTION_ENTRY, *_PIMAGE_RUNTIME_FUNCTION_ENTRY;
+
+typedef _IMAGE_RUNTIME_FUNCTION_ENTRY IMAGE_IA64_RUNTIME_FUNCTION_ENTRY;
+typedef _PIMAGE_RUNTIME_FUNCTION_ENTRY PIMAGE_IA64_RUNTIME_FUNCTION_ENTRY;
+
+#if defined(_AXP64_)
+
+typedef IMAGE_ALPHA64_RUNTIME_FUNCTION_ENTRY IMAGE_AXP64_RUNTIME_FUNCTION_ENTRY;
+typedef PIMAGE_ALPHA64_RUNTIME_FUNCTION_ENTRY PIMAGE_AXP64_RUNTIME_FUNCTION_ENTRY;
+typedef IMAGE_ALPHA64_RUNTIME_FUNCTION_ENTRY IMAGE_RUNTIME_FUNCTION_ENTRY;
+typedef PIMAGE_ALPHA64_RUNTIME_FUNCTION_ENTRY PIMAGE_RUNTIME_FUNCTION_ENTRY;
+
+#elif defined(_ALPHA_)
+
+typedef IMAGE_ALPHA_RUNTIME_FUNCTION_ENTRY IMAGE_RUNTIME_FUNCTION_ENTRY;
+typedef PIMAGE_ALPHA_RUNTIME_FUNCTION_ENTRY PIMAGE_RUNTIME_FUNCTION_ENTRY;
+
+#else
+
+typedef _IMAGE_RUNTIME_FUNCTION_ENTRY IMAGE_RUNTIME_FUNCTION_ENTRY;
+typedef _PIMAGE_RUNTIME_FUNCTION_ENTRY PIMAGE_RUNTIME_FUNCTION_ENTRY;
+
+#endif
+
+//
+// Debug Format
+//
+
+typedef struct _IMAGE_DEBUG_DIRECTORY {
+ ULONG Characteristics;
+ ULONG TimeDateStamp;
+ USHORT MajorVersion;
+ USHORT MinorVersion;
+ ULONG Type;
+ ULONG SizeOfData;
+ ULONG AddressOfRawData;
+ ULONG PointerToRawData;
+} IMAGE_DEBUG_DIRECTORY, *PIMAGE_DEBUG_DIRECTORY;
+
+#define IMAGE_DEBUG_TYPE_UNKNOWN 0
+#define IMAGE_DEBUG_TYPE_COFF 1
+#define IMAGE_DEBUG_TYPE_CODEVIEW 2
+#define IMAGE_DEBUG_TYPE_FPO 3
+#define IMAGE_DEBUG_TYPE_MISC 4
+#define IMAGE_DEBUG_TYPE_EXCEPTION 5
+#define IMAGE_DEBUG_TYPE_FIXUP 6
+#define IMAGE_DEBUG_TYPE_OMAP_TO_SRC 7
+#define IMAGE_DEBUG_TYPE_OMAP_FROM_SRC 8
+#define IMAGE_DEBUG_TYPE_BORLAND 9
+#define IMAGE_DEBUG_TYPE_RESERVED10 10
+#define IMAGE_DEBUG_TYPE_CLSID 11
+
+// end_winnt
+
+//
+
+// begin_winnt
+
+typedef struct _IMAGE_COFF_SYMBOLS_HEADER {
+ ULONG NumberOfSymbols;
+ ULONG LvaToFirstSymbol;
+ ULONG NumberOfLinenumbers;
+ ULONG LvaToFirstLinenumber;
+ ULONG RvaToFirstByteOfCode;
+ ULONG RvaToLastByteOfCode;
+ ULONG RvaToFirstByteOfData;
+ ULONG RvaToLastByteOfData;
+} IMAGE_COFF_SYMBOLS_HEADER, *PIMAGE_COFF_SYMBOLS_HEADER;
+
+#define FRAME_FPO 0
+#define FRAME_TRAP 1
+#define FRAME_TSS 2
+#define FRAME_NONFPO 3
+
+typedef struct _FPO_DATA {
+ ULONG ulOffStart; // offset 1st byte of function code
+ ULONG cbProcSize; // # bytes in function
+ ULONG cdwLocals; // # bytes in locals/4
+ USHORT cdwParams; // # bytes in params/4
+ USHORT cbProlog : 8; // # bytes in prolog
+ USHORT cbRegs : 3; // # regs saved
+ USHORT fHasSEH : 1; // TRUE if SEH in func
+ USHORT fUseBP : 1; // TRUE if EBP has been allocated
+ USHORT reserved : 1; // reserved for future use
+ USHORT cbFrame : 2; // frame type
+} FPO_DATA, *PFPO_DATA;
+#define SIZEOF_RFPO_DATA 16
+
+
+#define IMAGE_DEBUG_MISC_EXENAME 1
+
+typedef struct _IMAGE_DEBUG_MISC {
+ ULONG DataType; // type of misc data, see defines
+ ULONG Length; // total length of record, rounded to four
+ // byte multiple.
+ BOOLEAN Unicode; // TRUE if data is unicode string
+ UCHAR Reserved[ 3 ];
+ UCHAR Data[ 1 ]; // Actual data
+} IMAGE_DEBUG_MISC, *PIMAGE_DEBUG_MISC;
+
+
+//
+// Function table extracted from MIPS/ALPHA/IA64 images. Does not contain
+// information needed only for runtime support. Just those fields for
+// each entry needed by a debugger.
+//
+
+typedef struct _IMAGE_FUNCTION_ENTRY {
+ ULONG StartingAddress;
+ ULONG EndingAddress;
+ ULONG EndOfPrologue;
+} IMAGE_FUNCTION_ENTRY, *PIMAGE_FUNCTION_ENTRY;
+
+typedef struct _IMAGE_FUNCTION_ENTRY64 {
+ ULONGLONG StartingAddress;
+ ULONGLONG EndingAddress;
+ union {
+ ULONGLONG EndOfPrologue;
+ ULONGLONG UnwindInfoAddress;
+ } u;
+} IMAGE_FUNCTION_ENTRY64, *PIMAGE_FUNCTION_ENTRY64;
+
+//
+// Debugging information can be stripped from an image file and placed
+// in a separate .DBG file, whose file name part is the same as the
+// image file name part (e.g. symbols for CMD.EXE could be stripped
+// and placed in CMD.DBG). This is indicated by the IMAGE_FILE_DEBUG_STRIPPED
+// flag in the Characteristics field of the file header. The beginning of
+// the .DBG file contains the following structure which captures certain
+// information from the image file. This allows a debug to proceed even if
+// the original image file is not accessable. This header is followed by
+// zero of more IMAGE_SECTION_HEADER structures, followed by zero or more
+// IMAGE_DEBUG_DIRECTORY structures. The latter structures and those in
+// the image file contain file offsets relative to the beginning of the
+// .DBG file.
+//
+// If symbols have been stripped from an image, the IMAGE_DEBUG_MISC structure
+// is left in the image file, but not mapped. This allows a debugger to
+// compute the name of the .DBG file, from the name of the image in the
+// IMAGE_DEBUG_MISC structure.
+//
+
+typedef struct _IMAGE_SEPARATE_DEBUG_HEADER {
+ USHORT Signature;
+ USHORT Flags;
+ USHORT Machine;
+ USHORT Characteristics;
+ ULONG TimeDateStamp;
+ ULONG CheckSum;
+ ULONG ImageBase;
+ ULONG SizeOfImage;
+ ULONG NumberOfSections;
+ ULONG ExportedNamesSize;
+ ULONG DebugDirectorySize;
+ ULONG SectionAlignment;
+ ULONG Reserved[2];
+} IMAGE_SEPARATE_DEBUG_HEADER, *PIMAGE_SEPARATE_DEBUG_HEADER;
+
+typedef struct _NON_PAGED_DEBUG_INFO {
+ USHORT Signature;
+ USHORT Flags;
+ ULONG Size;
+ USHORT Machine;
+ USHORT Characteristics;
+ ULONG TimeDateStamp;
+ ULONG CheckSum;
+ ULONG SizeOfImage;
+ ULONGLONG ImageBase;
+ //DebugDirectorySize
+ //IMAGE_DEBUG_DIRECTORY
+} NON_PAGED_DEBUG_INFO, *PNON_PAGED_DEBUG_INFO;
+
+#ifndef _MAC
+#define IMAGE_SEPARATE_DEBUG_SIGNATURE 0x4944
+#define NON_PAGED_DEBUG_SIGNATURE 0x494E
+#else
+#define IMAGE_SEPARATE_DEBUG_SIGNATURE 0x4449 // DI
+#define NON_PAGED_DEBUG_SIGNATURE 0x4E49 // NI
+#endif
+
+#define IMAGE_SEPARATE_DEBUG_FLAGS_MASK 0x8000
+#define IMAGE_SEPARATE_DEBUG_MISMATCH 0x8000 // when DBG was updated, the
+ // old checksum didn't match.
+
+//
+// The .arch section is made up of headers, each describing an amask position/value
+// pointing to an array of IMAGE_ARCHITECTURE_ENTRY's. Each "array" (both the header
+// and entry arrays) are terminiated by a quadword of 0xffffffffL.
+//
+// NOTE: There may be quadwords of 0 sprinkled around and must be skipped.
+//
+
+typedef struct _ImageArchitectureHeader {
+ unsigned int AmaskValue: 1; // 1 -> code section depends on mask bit
+ // 0 -> new instruction depends on mask bit
+ int :7; // MBZ
+ unsigned int AmaskShift: 8; // Amask bit in question for this fixup
+ int :16; // MBZ
+ ULONG FirstEntryRVA; // RVA into .arch section to array of ARCHITECTURE_ENTRY's
+} IMAGE_ARCHITECTURE_HEADER, *PIMAGE_ARCHITECTURE_HEADER;
+
+typedef struct _ImageArchitectureEntry {
+ ULONG FixupInstRVA; // RVA of instruction to fixup
+ ULONG NewInst; // fixup instruction (see alphaops.h)
+} IMAGE_ARCHITECTURE_ENTRY, *PIMAGE_ARCHITECTURE_ENTRY;
+
+#include "poppack.h" // Back to the initial value
+
+// The following structure defines the new import object. Note the values of the first two fields,
+// which must be set as stated in order to differentiate old and new import members.
+// Following this structure, the linker emits two null-terminated strings used to recreate the
+// import at the time of use. The first string is the import's name, the second is the dll's name.
+
+#define IMPORT_OBJECT_HDR_SIG2 0xffff
+
+typedef struct IMPORT_OBJECT_HEADER {
+ USHORT Sig1; // Must be IMAGE_FILE_MACHINE_UNKNOWN
+ USHORT Sig2; // Must be IMPORT_OBJECT_HDR_SIG2.
+ USHORT Version;
+ USHORT Machine;
+ ULONG TimeDateStamp; // Time/date stamp
+ ULONG SizeOfData; // particularly useful for incremental links
+
+ union {
+ USHORT Ordinal; // if grf & IMPORT_OBJECT_ORDINAL
+ USHORT Hint;
+ } u;
+
+ USHORT Type : 2; // IMPORT_TYPE
+ USHORT NameType : 3; // IMPORT_NAME_TYPE
+ USHORT Reserved : 11; // Reserved. Must be zero.
+} IMPORT_OBJECT_HEADER;
+
+typedef enum IMPORT_OBJECT_TYPE
+{
+ IMPORT_OBJECT_CODE = 0,
+ IMPORT_OBJECT_DATA = 1,
+ IMPORT_OBJECT_CONST = 2,
+} IMPORT_OBJECT_TYPE;
+
+typedef enum IMPORT_OBJECT_NAME_TYPE
+{
+ IMPORT_OBJECT_ORDINAL = 0, // Import by ordinal
+ IMPORT_OBJECT_NAME = 1, // Import name == public symbol name.
+ IMPORT_OBJECT_NAME_NO_PREFIX = 2, // Import name == public symbol name skipping leading ?, @, or optionally _.
+ IMPORT_OBJECT_NAME_UNDECORATE = 3, // Import name == public symbol name skipping leading ?, @, or optionally _
+ // and truncating at first @
+} IMPORT_OBJECT_NAME_TYPE;
+
+// end_winnt
+
+// The structure is used by the NT loader for clr URT support. It
+// is a duplicate of the definition in corhdr.h.
+
+// begin_winnt
+
+#ifndef __IMAGE_COR20_HEADER_DEFINED__
+#define __IMAGE_COR20_HEADER_DEFINED__
+
+typedef enum ReplacesCorHdrNumericDefines
+{
+// COM+ Header entry point flags.
+ COMIMAGE_FLAGS_ILONLY =0x00000001,
+ COMIMAGE_FLAGS_32BITREQUIRED =0x00000002,
+ COMIMAGE_FLAGS_IL_LIBRARY =0x00000004,
+ COMIMAGE_FLAGS_STRONGNAMESIGNED =0x00000008,
+ COMIMAGE_FLAGS_NATIVE_ENTRYPOINT =0x00000010,
+ COMIMAGE_FLAGS_TRACKDEBUGDATA =0x00010000,
+
+// Version flags for image.
+ COR_VERSION_MAJOR_V2 =2,
+ COR_VERSION_MAJOR =COR_VERSION_MAJOR_V2,
+ COR_VERSION_MINOR =0,
+ COR_DELETED_NAME_LENGTH =8,
+ COR_VTABLEGAP_NAME_LENGTH =8,
+
+// Maximum size of a NativeType descriptor.
+ NATIVE_TYPE_MAX_CB =1,
+ COR_ILMETHOD_SECT_SMALL_MAX_DATASIZE=0xFF,
+
+// #defines for the MIH FLAGS
+ IMAGE_COR_MIH_METHODRVA =0x01,
+ IMAGE_COR_MIH_EHRVA =0x02,
+ IMAGE_COR_MIH_BASICBLOCK =0x08,
+
+// V-table constants
+ COR_VTABLE_32BIT =0x01, // V-table slots are 32-bits in size.
+ COR_VTABLE_64BIT =0x02, // V-table slots are 64-bits in size.
+ COR_VTABLE_FROM_UNMANAGED =0x04, // If set, transition from unmanaged.
+ COR_VTABLE_CALL_MOST_DERIVED =0x10, // Call most derived method described by
+
+// EATJ constants
+ IMAGE_COR_EATJ_THUNK_SIZE =32, // Size of a jump thunk reserved range.
+
+// Max name lengths
+ //<TODO> Change to unlimited name lengths. </TODO>
+ MAX_CLASS_NAME =1024,
+ MAX_PACKAGE_NAME =1024,
+} ReplacesCorHdrNumericDefines;
+
+// COM+ 2.0 header structure.
+typedef struct IMAGE_COR20_HEADER
+{
+ // Header versioning
+ ULONG cb;
+ USHORT MajorRuntimeVersion;
+ USHORT MinorRuntimeVersion;
+
+ // Symbol table and startup information
+ IMAGE_DATA_DIRECTORY MetaData;
+ ULONG Flags;
+
+ // If COMIMAGE_FLAGS_NATIVE_ENTRYPOINT is not set, EntryPointToken represents a managed entrypoint.
+ // If COMIMAGE_FLAGS_NATIVE_ENTRYPOINT is set, EntryPointRVA represents an RVA to a native entrypoint.
+ union {
+ ULONG EntryPointToken;
+ ULONG EntryPointRVA;
+ };
+
+ // Binding information
+ IMAGE_DATA_DIRECTORY Resources;
+ IMAGE_DATA_DIRECTORY StrongNameSignature;
+
+ // Regular fixup and binding information
+ IMAGE_DATA_DIRECTORY CodeManagerTable;
+ IMAGE_DATA_DIRECTORY VTableFixups;
+ IMAGE_DATA_DIRECTORY ExportAddressTableJumps;
+
+ // Precompiled image info (internal use only - set to zero)
+ IMAGE_DATA_DIRECTORY ManagedNativeHeader;
+
+} IMAGE_COR20_HEADER, *PIMAGE_COR20_HEADER;
+
+#endif // __IMAGE_COR20_HEADER_DEFINED__
+
+//
+// End Image Format
+//
+
+// end_winnt
+
+#endif // _NTIMAGE_
diff --git a/src/pal/inc/rt/oaidl.h b/src/pal/inc/rt/oaidl.h
new file mode 100644
index 0000000000..f5c9aa155d
--- /dev/null
+++ b/src/pal/inc/rt/oaidl.h
@@ -0,0 +1,111 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+//
+// ===========================================================================
+// File: oaidl.h
+//
+// ===========================================================================
+
+#ifndef __OAIDL_H__
+#define __OAIDL_H__
+
+#include "rpc.h"
+#include "rpcndr.h"
+
+#include "unknwn.h"
+
+typedef struct tagEXCEPINFO {
+ WORD wCode;
+ WORD wReserved;
+ BSTR bstrSource;
+ BSTR bstrDescription;
+ BSTR bstrHelpFile;
+ DWORD dwHelpContext;
+ PVOID pvReserved;
+ HRESULT (__stdcall *pfnDeferredFillIn)(struct tagEXCEPINFO *);
+ SCODE scode;
+} EXCEPINFO, * LPEXCEPINFO;
+
+typedef interface IErrorInfo IErrorInfo;
+typedef /* [unique] */ IErrorInfo *LPERRORINFO;
+
+EXTERN_C const IID IID_IErrorInfo;
+
+ interface
+ IErrorInfo : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetGUID(
+ /* [out] */ GUID *pGUID) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetSource(
+ /* [out] */ BSTR *pBstrSource) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetDescription(
+ /* [out] */ BSTR *pBstrDescription) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetHelpFile(
+ /* [out] */ BSTR *pBstrHelpFile) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetHelpContext(
+ /* [out] */ DWORD *pdwHelpContext) = 0;
+
+ };
+
+typedef interface ICreateErrorInfo ICreateErrorInfo;
+
+EXTERN_C const IID IID_ICreateErrorInfo;
+
+typedef /* [unique] */ ICreateErrorInfo *LPCREATEERRORINFO;
+
+ interface
+ ICreateErrorInfo : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE SetGUID(
+ /* [in] */ REFGUID rguid) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetSource(
+ /* [in] */ LPOLESTR szSource) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetDescription(
+ /* [in] */ LPOLESTR szDescription) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetHelpFile(
+ /* [in] */ LPOLESTR szHelpFile) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetHelpContext(
+ /* [in] */ DWORD dwHelpContext) = 0;
+
+ };
+
+STDAPI
+SetErrorInfo(ULONG dwReserved, IErrorInfo FAR* perrinfo);
+
+STDAPI
+GetErrorInfo(ULONG dwReserved, IErrorInfo FAR* FAR* pperrinfo);
+
+STDAPI
+CreateErrorInfo(ICreateErrorInfo FAR* FAR* pperrinfo);
+
+
+typedef interface ISupportErrorInfo ISupportErrorInfo;
+
+typedef /* [unique] */ ISupportErrorInfo *LPSUPPORTERRORINFO;
+
+EXTERN_C const IID IID_ISupportErrorInfo;
+
+
+ interface
+ ISupportErrorInfo : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE InterfaceSupportsErrorInfo(
+ /* [in] */ REFIID riid) = 0;
+
+ };
+
+#endif //__OAIDL_H__
diff --git a/src/pal/inc/rt/objbase.h b/src/pal/inc/rt/objbase.h
new file mode 100644
index 0000000000..6b2693272a
--- /dev/null
+++ b/src/pal/inc/rt/objbase.h
@@ -0,0 +1,9 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+//
+// dummy objbase.h for PAL
+
+#include "palrt.h"
diff --git a/src/pal/inc/rt/objidl.h b/src/pal/inc/rt/objidl.h
new file mode 100644
index 0000000000..4586a557cf
--- /dev/null
+++ b/src/pal/inc/rt/objidl.h
@@ -0,0 +1,293 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+//
+// ===========================================================================
+// File: objidl.h
+//
+// ===========================================================================
+// simplified objidl.h for PAL
+
+#include "rpc.h"
+#include "rpcndr.h"
+
+#include "unknwn.h"
+
+#ifndef __IEnumUnknown_INTERFACE_DEFINED__
+#define __IEnumUnknown_INTERFACE_DEFINED__
+
+// 00000100-0000-0000-C000-000000000046
+EXTERN_C const IID IID_IEnumUnknown;
+
+interface IEnumUnknown : public IUnknown
+{
+public:
+ virtual /* [local] */ HRESULT STDMETHODCALLTYPE Next(
+ /* [annotation][in] */
+ _In_ ULONG celt,
+ /* [annotation][out] */
+ _Out_writes_to_(celt,*pceltFetched) IUnknown **rgelt,
+ /* [annotation][out] */
+ _Out_opt_ ULONG *pceltFetched) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Skip(
+ /* [in] */ ULONG celt) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Reset( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Clone(
+ /* [out] */ __RPC__deref_out_opt IEnumUnknown **ppenum) = 0;
+
+};
+
+#endif /* __IEnumUnknown_INTERFACE_DEFINED__ */
+
+#ifndef __ISequentialStream_INTERFACE_DEFINED__
+#define __ISequentialStream_INTERFACE_DEFINED__
+
+// 0c733a30-2a1c-11ce-ade5-00aa0044773d
+EXTERN_C const IID IID_ISequentialStream;
+
+interface ISequentialStream : public IUnknown
+{
+public:
+ virtual /* [local] */ HRESULT STDMETHODCALLTYPE Read(
+ /* [length_is][size_is][out] */ void *pv,
+ /* [in] */ ULONG cb,
+ /* [out] */ ULONG *pcbRead) = 0;
+
+ virtual /* [local] */ HRESULT STDMETHODCALLTYPE Write(
+ /* [size_is][in] */ const void *pv,
+ /* [in] */ ULONG cb,
+ /* [out] */ ULONG *pcbWritten) = 0;
+
+};
+
+#endif // __ISequentialStream_INTERFACE_DEFINED__
+
+
+#ifndef __IStream_INTERFACE_DEFINED__
+#define __IStream_INTERFACE_DEFINED__
+
+typedef struct tagSTATSTG
+ {
+ LPOLESTR pwcsName;
+ DWORD type;
+ ULARGE_INTEGER cbSize;
+ FILETIME mtime;
+ FILETIME ctime;
+ FILETIME atime;
+ DWORD grfMode;
+ DWORD grfLocksSupported;
+ CLSID clsid;
+ DWORD grfStateBits;
+ DWORD reserved;
+ } STATSTG;
+
+typedef
+enum tagSTGTY
+ { STGTY_STORAGE = 1,
+ STGTY_STREAM = 2,
+ STGTY_LOCKBYTES = 3,
+ STGTY_PROPERTY = 4
+ } STGTY;
+
+typedef
+enum tagSTREAM_SEEK
+ { STREAM_SEEK_SET = 0,
+ STREAM_SEEK_CUR = 1,
+ STREAM_SEEK_END = 2
+ } STREAM_SEEK;
+
+typedef
+enum tagLOCKTYPE
+ { LOCK_WRITE = 1,
+ LOCK_EXCLUSIVE = 2,
+ LOCK_ONLYONCE = 4
+ } LOCKTYPE;
+
+typedef
+enum tagSTATFLAG
+ { STATFLAG_DEFAULT = 0,
+ STATFLAG_NONAME = 1,
+ STATFLAG_NOOPEN = 2
+ } STATFLAG;
+
+// 0000000c-0000-0000-C000-000000000046
+EXTERN_C const IID IID_IStream;
+
+interface DECLSPEC_UUID("0000000c-0000-0000-C000-000000000046")
+IStream : public ISequentialStream
+{
+public:
+ virtual /* [local] */ HRESULT STDMETHODCALLTYPE Seek(
+ /* [in] */ LARGE_INTEGER dlibMove,
+ /* [in] */ DWORD dwOrigin,
+ /* [out] */ ULARGE_INTEGER *plibNewPosition) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetSize(
+ /* [in] */ ULARGE_INTEGER libNewSize) = 0;
+
+ virtual /* [local] */ HRESULT STDMETHODCALLTYPE CopyTo(
+ /* [unique][in] */ IStream *pstm,
+ /* [in] */ ULARGE_INTEGER cb,
+ /* [out] */ ULARGE_INTEGER *pcbRead,
+ /* [out] */ ULARGE_INTEGER *pcbWritten) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Commit(
+ /* [in] */ DWORD grfCommitFlags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Revert( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE LockRegion(
+ /* [in] */ ULARGE_INTEGER libOffset,
+ /* [in] */ ULARGE_INTEGER cb,
+ /* [in] */ DWORD dwLockType) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE UnlockRegion(
+ /* [in] */ ULARGE_INTEGER libOffset,
+ /* [in] */ ULARGE_INTEGER cb,
+ /* [in] */ DWORD dwLockType) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Stat(
+ /* [out] */ STATSTG *pstatstg,
+ /* [in] */ DWORD grfStatFlag) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Clone(
+ /* [out] */ IStream **ppstm) = 0;
+
+};
+
+#endif // __IStream_INTERFACE_DEFINED__
+
+
+#ifndef __IStorage_INTERFACE_DEFINED__
+#define __IStorage_INTERFACE_DEFINED__
+
+typedef OLECHAR **SNB;
+
+interface IEnumSTATSTG;
+
+// 0000000b-0000-0000-C000-000000000046
+
+interface IStorage : public IUnknown
+{
+public:
+ virtual HRESULT STDMETHODCALLTYPE CreateStream(
+ /* [string][in] */ const OLECHAR *pwcsName,
+ /* [in] */ DWORD grfMode,
+ /* [in] */ DWORD reserved1,
+ /* [in] */ DWORD reserved2,
+ /* [out] */ IStream **ppstm) = 0;
+
+ virtual /* [local] */ HRESULT STDMETHODCALLTYPE OpenStream(
+ /* [string][in] */ const OLECHAR *pwcsName,
+ /* [unique][in] */ void *reserved1,
+ /* [in] */ DWORD grfMode,
+ /* [in] */ DWORD reserved2,
+ /* [out] */ IStream **ppstm) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE CreateStorage(
+ /* [string][in] */ const OLECHAR *pwcsName,
+ /* [in] */ DWORD grfMode,
+ /* [in] */ DWORD reserved1,
+ /* [in] */ DWORD reserved2,
+ /* [out] */ IStorage **ppstg) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE OpenStorage(
+ /* [string][unique][in] */ const OLECHAR *pwcsName,
+ /* [unique][in] */ IStorage *pstgPriority,
+ /* [in] */ DWORD grfMode,
+ /* [unique][in] */ SNB snbExclude,
+ /* [in] */ DWORD reserved,
+ /* [out] */ IStorage **ppstg) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE CopyTo(
+ /* [in] */ DWORD ciidExclude,
+ /* [size_is][unique][in] */ const IID *rgiidExclude,
+ /* [unique][in] */ SNB snbExclude,
+ /* [unique][in] */ IStorage *pstgDest) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE MoveElementTo(
+ /* [string][in] */ const OLECHAR *pwcsName,
+ /* [unique][in] */ IStorage *pstgDest,
+ /* [string][in] */ const OLECHAR *pwcsNewName,
+ /* [in] */ DWORD grfFlags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Commit(
+ /* [in] */ DWORD grfCommitFlags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Revert( void) = 0;
+
+ virtual /* [local] */ HRESULT STDMETHODCALLTYPE EnumElements(
+ /* [in] */ DWORD reserved1,
+ /* [size_is][unique][in] */ void *reserved2,
+ /* [in] */ DWORD reserved3,
+ /* [out] */ IEnumSTATSTG **ppenum) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE DestroyElement(
+ /* [string][in] */ const OLECHAR *pwcsName) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE RenameElement(
+ /* [string][in] */ const OLECHAR *pwcsOldName,
+ /* [string][in] */ const OLECHAR *pwcsNewName) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetElementTimes(
+ /* [string][unique][in] */ const OLECHAR *pwcsName,
+ /* [unique][in] */ const FILETIME *pctime,
+ /* [unique][in] */ const FILETIME *patime,
+ /* [unique][in] */ const FILETIME *pmtime) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetClass(
+ /* [in] */ REFCLSID clsid) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetStateBits(
+ /* [in] */ DWORD grfStateBits,
+ /* [in] */ DWORD grfMask) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Stat(
+ /* [out] */ STATSTG *pstatstg,
+ /* [in] */ DWORD grfStatFlag) = 0;
+
+};
+
+#endif // __IStorage_INTERFACE_DEFINED__
+
+
+#ifndef __IMalloc_INTERFACE_DEFINED__
+#define __IMalloc_INTERFACE_DEFINED__
+
+/* interface IMalloc */
+/* [uuid][object][local] */
+
+// 0000001d-0000-0000-C000-000000000046
+EXTERN_C const IID IID_IMalloc;
+
+interface IMalloc : public IUnknown
+{
+public:
+ virtual void *STDMETHODCALLTYPE Alloc(
+ /* [in] */ SIZE_T cb) = 0;
+
+ virtual void *STDMETHODCALLTYPE Realloc(
+ /* [in] */ void *pv,
+ /* [in] */ SIZE_T cb) = 0;
+
+ virtual void STDMETHODCALLTYPE Free(
+ /* [in] */ void *pv) = 0;
+
+ virtual SIZE_T STDMETHODCALLTYPE GetSize(
+ /* [in] */ void *pv) = 0;
+
+ virtual int STDMETHODCALLTYPE DidAlloc(
+ void *pv) = 0;
+
+ virtual void STDMETHODCALLTYPE HeapMinimize( void) = 0;
+
+};
+
+typedef /* [unique] */ IMalloc *LPMALLOC;
+
+#endif // __IMalloc_INTERFACE_DEFINED__
diff --git a/src/pal/inc/rt/ocidl.h b/src/pal/inc/rt/ocidl.h
new file mode 100644
index 0000000000..ab6272e758
--- /dev/null
+++ b/src/pal/inc/rt/ocidl.h
@@ -0,0 +1,13 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+//
+// ===========================================================================
+// File: ocidl.h
+//
+// ===========================================================================
+// dummy ocidl.h for PAL
+
+#include "palrt.h"
diff --git a/src/pal/inc/rt/ole2.h b/src/pal/inc/rt/ole2.h
new file mode 100644
index 0000000000..36a057fcf9
--- /dev/null
+++ b/src/pal/inc/rt/ole2.h
@@ -0,0 +1,12 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+//
+// dummy ole2.h for PAL
+
+#include "objidl.h"
+#include "servprov.h"
+#include "oaidl.h"
+
diff --git a/src/pal/inc/rt/oleauto.h b/src/pal/inc/rt/oleauto.h
new file mode 100644
index 0000000000..a8499f96d5
--- /dev/null
+++ b/src/pal/inc/rt/oleauto.h
@@ -0,0 +1,161 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+//
+// ===========================================================================
+// File: oleauto.h
+//
+// ===========================================================================
+// simplified oleauto.h for PAL
+
+#ifndef _OLEAUTO_H_
+#define _OLEAUTO_H_
+#include "oaidl.h"
+
+#ifndef BEGIN_INTERFACE
+#define BEGIN_INTERFACE
+#define END_INTERFACE
+#endif
+
+// OleAut's VT_CY and VT_DECIMAL declarations required by System.Decimal and System.Currency
+
+typedef struct {
+ INT cDig;
+ ULONG dwInFlags;
+ ULONG dwOutFlags;
+ INT cchUsed;
+ INT nBaseShift;
+ INT nPwr10;
+} NUMPARSE;
+
+#define NUMPRS_STD 0x1FFF
+
+/* flags used by both dwInFlags and dwOutFlags:
+ */
+#define NUMPRS_LEADING_WHITE 0x0001
+#define NUMPRS_TRAILING_WHITE 0x0002
+#define NUMPRS_LEADING_PLUS 0x0004
+#define NUMPRS_TRAILING_PLUS 0x0008
+#define NUMPRS_LEADING_MINUS 0x0010
+#define NUMPRS_TRAILING_MINUS 0x0020
+#define NUMPRS_HEX_OCT 0x0040
+#define NUMPRS_PARENS 0x0080
+#define NUMPRS_DECIMAL 0x0100
+#define NUMPRS_THOUSANDS 0x0200
+#define NUMPRS_CURRENCY 0x0400
+#define NUMPRS_EXPONENT 0x0800
+#define NUMPRS_USE_ALL 0x1000
+
+/* flags used by dwOutFlags only:
+ */
+#define NUMPRS_NEG 0x10000
+#define NUMPRS_INEXACT 0x20000
+/* flags used by VarNumFromParseNum to indicate acceptable result types:
+ */
+#define VTBIT_I1 (1 << VT_I1)
+#define VTBIT_UI1 (1 << VT_UI1)
+#define VTBIT_I2 (1 << VT_I2)
+#define VTBIT_UI2 (1 << VT_UI2)
+#define VTBIT_I4 (1 << VT_I4)
+#define VTBIT_UI4 (1 << VT_UI4)
+#define VTBIT_I8 (1 << VT_I8)
+#define VTBIT_UI8 (1 << VT_UI8)
+#define VTBIT_R4 (1 << VT_R4)
+#define VTBIT_R8 (1 << VT_R8)
+#define VTBIT_CY (1 << VT_CY)
+#define VTBIT_DECIMAL (1 << VT_DECIMAL)
+
+#define LOCALE_NOUSEROVERRIDE 0x80000000 /* OR in to avoid user override */
+/*
+ * Use NLS functions to format date, currency, time, and number.
+ */
+#ifndef LOCALE_USE_NLS
+#define LOCALE_USE_NLS 0x10000000
+#endif
+
+// Compare results for VarDecCmp. These are returned as a SUCCESS HResult.
+// Subtracting one gives the usual values of -1 for Less Than,
+// 0 for Equal To, +1 for Greater Than.
+//
+#define VARCMP_LT 0
+#define VARCMP_EQ 1
+#define VARCMP_GT 2
+#define VARCMP_NULL 3
+
+#ifdef ENABLE_DOWNLEVEL_FOR_NLS
+STDAPI VarParseNumFromStr(OLECHAR * strIn, LCID lcid, ULONG dwFlags,
+ NUMPARSE * pnumprs, BYTE * rgbDig);
+
+STDAPI VarNumFromParseNum(NUMPARSE * pnumprs, BYTE * rgbDig,
+ ULONG dwVtBits, VARIANT * pvar);
+#endif
+
+STDAPI VariantChangeType(VARIANTARG * pvargDest,
+ VARIANTARG * pvarSrc, USHORT wFlags, VARTYPE vt);
+
+STDAPI VarCyFromR4(FLOAT fltIn, CY * pcyOut);
+STDAPI VarCyFromR8(DOUBLE dblIn, CY * pcyOut);
+STDAPI VarCyFromDec(DECIMAL *pdecIn, CY *pcyOut);
+STDAPI VarCyAdd(CY cyLeft, CY cyRight, LPCY pcyResult);
+STDAPI VarCySub(CY cyLeft, CY cyRight, LPCY pcyResult);
+STDAPI VarCyMul(CY cyLeft, CY cyRight, LPCY pcyResult);
+STDAPI VarCyInt(CY cyIn, LPCY pcyResult);
+STDAPI VarCyRound(CY cyIn, INT cDecimals, LPCY pcyResult);
+STDAPI VarCyFix(CY cyIn, LPCY pcyResult);
+
+STDAPI VarR8FromCy(CY cyIn, DOUBLE * pdblOut);
+STDAPI VarR4FromCy(CY cyIn, FLOAT * pfltOut);
+
+#ifdef ENABLE_DOWNLEVEL_FOR_NLS
+STDAPI VarBstrFromCy(CY cyIn, LCID lcid, ULONG dwFlags, BSTR * pbstrOut);
+STDAPI VarBstrFromUI1(BYTE bVal, LCID lcid, ULONG dwFlags, BSTR * pbstrOut);
+STDAPI VarBstrFromI2(SHORT iVal, LCID lcid, ULONG dwFlags, BSTR * pbstrOut);
+STDAPI VarBstrFromI4(LONG lIn, LCID lcid, ULONG dwFlags, BSTR * pbstrOut);
+STDAPI VarBstrFromI8(LONG64 i64In, LCID lcid, ULONG dwFlags, BSTR FAR* pbstrOut);
+STDAPI VarBstrFromR4(FLOAT fltIn, LCID lcid, ULONG dwFlags, BSTR * pbstrOut);
+STDAPI VarBstrFromR8(DOUBLE dblIn, LCID lcid, ULONG dwFlags, BSTR * pbstrOut);
+STDAPI VarBstrFromI1(CHAR cIn, LCID lcid, ULONG dwFlags, BSTR *pbstrOut);
+STDAPI VarBstrFromUI2(USHORT uiIn, LCID lcid, ULONG dwFlags, BSTR *pbstrOut);
+STDAPI VarBstrFromUI4(ULONG ulIn, LCID lcid, ULONG dwFlags, BSTR *pbstrOut);
+STDAPI VarBstrFromUI8(ULONG64 ui64In, LCID lcid, ULONG dwFlags, BSTR FAR* pbstrOut);
+STDAPI VarBstrFromDec(DECIMAL *pdecIn, LCID lcid, ULONG dwFlags, BSTR *pbstrOut);
+#endif
+
+STDAPI VarDecFromR4(FLOAT fltIn, DECIMAL *pdecOut);
+STDAPI VarDecFromR8(DOUBLE dblIn, DECIMAL *pdecOut);
+STDAPI VarDecFromCy(CY cyIn, DECIMAL *pdecOut);
+STDAPI VarDecAdd(LPDECIMAL pdecLeft, LPDECIMAL pdecRight, LPDECIMAL pdecResult);
+STDAPI VarDecSub(LPDECIMAL pdecLeft, LPDECIMAL pdecRight, LPDECIMAL pdecResult);
+STDAPI VarDecMul(LPDECIMAL pdecLeft, LPDECIMAL pdecRight, LPDECIMAL pdecResult);
+STDAPI VarDecDiv(LPDECIMAL pdecLeft, LPDECIMAL pdecRight, LPDECIMAL pdecResult);
+STDAPI VarDecCmp(LPDECIMAL pdecLeft, LPDECIMAL pdecRight);
+STDAPI VarDecInt(LPDECIMAL pdecIn, LPDECIMAL pdecResult);
+STDAPI VarDecRound(LPDECIMAL pdecIn, INT cDecimals, LPDECIMAL pdecResult);
+STDAPI VarDecFix(LPDECIMAL pdecIn, LPDECIMAL pdecResult);
+STDAPI VarDecNeg(LPDECIMAL pdecIn, LPDECIMAL pdecResult);
+STDAPI VarDecFromI4(LONG I4in, DECIMAL *pdecOut);
+STDAPI VarDecFromUI4(ULONG UI4in, DECIMAL *pdecOut);
+
+STDAPI VarI1FromDec(DECIMAL *pdecIn, CHAR *pI1In);
+STDAPI VarUI1FromDec(DECIMAL *pdecIn, BYTE *pUI1In);
+STDAPI VarI2FromDec(DECIMAL *pdecIn, SHORT *pI2In);
+STDAPI VarUI2FromDec(DECIMAL *pdecIn, USHORT *pUI2In);
+STDAPI VarI4FromDec(DECIMAL *pdecIn, LONG *pI4In);
+STDAPI VarUI4FromDec(DECIMAL *pdecIn, ULONG *pUI4In);
+STDAPI VarR8FromDec(DECIMAL *pdecIn, DOUBLE *pdblOut);
+STDAPI VarR4FromDec(DECIMAL *pdecIn, FLOAT *pfltOut);
+
+#ifdef ENABLE_DOWNLEVEL_FOR_NLS
+STDAPI VarR8FromStr(OLECHAR *strin, LCID lcid, ULONG dwFlags, DOUBLE *pdblOut);
+#endif
+
+STDAPI VarI1FromR8(DOUBLE dblIn, CHAR *pcOut);
+STDAPI VarI2FromR8(DOUBLE dblIn, SHORT * psOut);
+STDAPI VarI4FromR8(DOUBLE dblIn, LONG * plOut);
+STDAPI VarUI1FromR8(DOUBLE dblIn, BYTE * pbOut);
+STDAPI VarUI2FromR8(DOUBLE dblIn, USHORT *puiOut);
+STDAPI VarUI4FromR8(DOUBLE dblIn, ULONG *pulOut);
+
+#endif // _OLEAUTO_H_
diff --git a/src/pal/inc/rt/olectl.h b/src/pal/inc/rt/olectl.h
new file mode 100644
index 0000000000..94b093f017
--- /dev/null
+++ b/src/pal/inc/rt/olectl.h
@@ -0,0 +1,13 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+//
+// ===========================================================================
+// File: olectl.h
+//
+// ===========================================================================
+// dummy olectl.h for PAL
+
+#include "palrt.h"
diff --git a/src/pal/inc/rt/oleidl.h b/src/pal/inc/rt/oleidl.h
new file mode 100644
index 0000000000..301692ea75
--- /dev/null
+++ b/src/pal/inc/rt/oleidl.h
@@ -0,0 +1,13 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+//
+// ===========================================================================
+// File: oleidl.h
+//
+// ===========================================================================
+// simplified oleidl.h for PAL
+
+#include "palrt.h"
diff --git a/src/pal/inc/rt/palrt.h b/src/pal/inc/rt/palrt.h
new file mode 100644
index 0000000000..336a13f529
--- /dev/null
+++ b/src/pal/inc/rt/palrt.h
@@ -0,0 +1,1805 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+//
+// ===========================================================================
+// File: palrt.h
+//
+// ===========================================================================
+
+/*++
+
+
+Abstract:
+
+ Rotor runtime functions. These are functions which are ordinarily
+ implemented as part of the Win32 API set, but for Rotor, are
+ implemented as a runtime library on top of the PAL.
+
+Author:
+
+
+
+Revision History:
+
+--*/
+
+#ifndef __PALRT_H__
+#define __PALRT_H__
+
+/******************* HRESULTs *********************************************/
+
+#ifdef RC_INVOKED
+#define _HRESULT_TYPEDEF_(_sc) _sc
+#else // RC_INVOKED
+#define _HRESULT_TYPEDEF_(_sc) ((HRESULT)_sc)
+#endif // RC_INVOKED
+
+#define S_OK _HRESULT_TYPEDEF_(0x00000000L)
+#define S_FALSE _HRESULT_TYPEDEF_(0x00000001L)
+
+#define E_NOTIMPL _HRESULT_TYPEDEF_(0x80004001L)
+#define E_NOINTERFACE _HRESULT_TYPEDEF_(0x80004002L)
+#define E_UNEXPECTED _HRESULT_TYPEDEF_(0x8000FFFFL)
+#define E_OUTOFMEMORY _HRESULT_TYPEDEF_(0x8007000EL)
+#define E_INVALIDARG _HRESULT_TYPEDEF_(0x80070057L)
+#define E_POINTER _HRESULT_TYPEDEF_(0x80004003L)
+#define E_HANDLE _HRESULT_TYPEDEF_(0x80070006L)
+#define E_ABORT _HRESULT_TYPEDEF_(0x80004004L)
+#define E_FAIL _HRESULT_TYPEDEF_(0x80004005L)
+#define E_ACCESSDENIED _HRESULT_TYPEDEF_(0x80070005L)
+#define E_PENDING _HRESULT_TYPEDEF_(0x8000000AL)
+
+#define DISP_E_PARAMNOTFOUND _HRESULT_TYPEDEF_(0x80020004L)
+#define DISP_E_TYPEMISMATCH _HRESULT_TYPEDEF_(0x80020005L)
+#define DISP_E_BADVARTYPE _HRESULT_TYPEDEF_(0x80020008L)
+#define DISP_E_OVERFLOW _HRESULT_TYPEDEF_(0x8002000AL)
+#define DISP_E_DIVBYZERO _HRESULT_TYPEDEF_(0x80020012L)
+
+#define CLASS_E_CLASSNOTAVAILABLE _HRESULT_TYPEDEF_(0x80040111L)
+#define CLASS_E_NOAGGREGATION _HRESULT_TYPEDEF_(0x80040110L)
+
+#define CO_E_CLASSSTRING _HRESULT_TYPEDEF_(0x800401F3L)
+
+#define URL_E_INVALID_SYNTAX _HRESULT_TYPEDEF_(0x80041001L)
+#define MK_E_SYNTAX _HRESULT_TYPEDEF_(0x800401E4L)
+
+#define STG_E_INVALIDFUNCTION _HRESULT_TYPEDEF_(0x80030001L)
+#define STG_E_FILENOTFOUND _HRESULT_TYPEDEF_(0x80030002L)
+#define STG_E_PATHNOTFOUND _HRESULT_TYPEDEF_(0x80030003L)
+#define STG_E_WRITEFAULT _HRESULT_TYPEDEF_(0x8003001DL)
+#define STG_E_FILEALREADYEXISTS _HRESULT_TYPEDEF_(0x80030050L)
+#define STG_E_ABNORMALAPIEXIT _HRESULT_TYPEDEF_(0x800300FAL)
+
+#define NTE_BAD_UID _HRESULT_TYPEDEF_(0x80090001L)
+#define NTE_BAD_HASH _HRESULT_TYPEDEF_(0x80090002L)
+#define NTE_BAD_KEY _HRESULT_TYPEDEF_(0x80090003L)
+#define NTE_BAD_LEN _HRESULT_TYPEDEF_(0x80090004L)
+#define NTE_BAD_DATA _HRESULT_TYPEDEF_(0x80090005L)
+#define NTE_BAD_SIGNATURE _HRESULT_TYPEDEF_(0x80090006L)
+#define NTE_BAD_VER _HRESULT_TYPEDEF_(0x80090007L)
+#define NTE_BAD_ALGID _HRESULT_TYPEDEF_(0x80090008L)
+#define NTE_BAD_FLAGS _HRESULT_TYPEDEF_(0x80090009L)
+#define NTE_BAD_TYPE _HRESULT_TYPEDEF_(0x8009000AL)
+#define NTE_BAD_KEY_STATE _HRESULT_TYPEDEF_(0x8009000BL)
+#define NTE_BAD_HASH_STATE _HRESULT_TYPEDEF_(0x8009000CL)
+#define NTE_NO_KEY _HRESULT_TYPEDEF_(0x8009000DL)
+#define NTE_NO_MEMORY _HRESULT_TYPEDEF_(0x8009000EL)
+#define NTE_SIGNATURE_FILE_BAD _HRESULT_TYPEDEF_(0x8009001CL)
+#define NTE_FAIL _HRESULT_TYPEDEF_(0x80090020L)
+
+#define CRYPT_E_HASH_VALUE _HRESULT_TYPEDEF_(0x80091007L)
+
+#define TYPE_E_SIZETOOBIG _HRESULT_TYPEDEF_(0x800288C5L)
+#define TYPE_E_DUPLICATEID _HRESULT_TYPEDEF_(0x800288C6L)
+
+#define STD_CTL_SCODE(n) MAKE_SCODE(SEVERITY_ERROR, FACILITY_CONTROL, n)
+#define CTL_E_OVERFLOW STD_CTL_SCODE(6)
+#define CTL_E_OUTOFMEMORY STD_CTL_SCODE(7)
+#define CTL_E_DIVISIONBYZERO STD_CTL_SCODE(11)
+#define CTL_E_OUTOFSTACKSPACE STD_CTL_SCODE(28)
+#define CTL_E_FILENOTFOUND STD_CTL_SCODE(53)
+#define CTL_E_DEVICEIOERROR STD_CTL_SCODE(57)
+#define CTL_E_PERMISSIONDENIED STD_CTL_SCODE(70)
+#define CTL_E_PATHFILEACCESSERROR STD_CTL_SCODE(75)
+#define CTL_E_PATHNOTFOUND STD_CTL_SCODE(76)
+
+#define INET_E_CANNOT_CONNECT _HRESULT_TYPEDEF_(0x800C0004L)
+#define INET_E_RESOURCE_NOT_FOUND _HRESULT_TYPEDEF_(0x800C0005L)
+#define INET_E_OBJECT_NOT_FOUND _HRESULT_TYPEDEF_(0x800C0006L)
+#define INET_E_DATA_NOT_AVAILABLE _HRESULT_TYPEDEF_(0x800C0007L)
+#define INET_E_DOWNLOAD_FAILURE _HRESULT_TYPEDEF_(0x800C0008L)
+#define INET_E_CONNECTION_TIMEOUT _HRESULT_TYPEDEF_(0x800C000BL)
+#define INET_E_UNKNOWN_PROTOCOL _HRESULT_TYPEDEF_(0x800C000DL)
+
+#define DBG_PRINTEXCEPTION_C _HRESULT_TYPEDEF_(0x40010006L)
+
+/********************** errorrep.h ****************************************/
+
+typedef enum tagEFaultRepRetVal
+{
+ frrvOk = 0,
+ frrvOkManifest,
+ frrvOkQueued,
+ frrvErr,
+ frrvErrNoDW,
+ frrvErrTimeout,
+ frrvLaunchDebugger,
+ frrvOkHeadless,
+ frrvErrAnotherInstance
+} EFaultRepRetVal;
+
+/**************************************************************************/
+
+#ifndef RC_INVOKED
+
+#include "pal.h"
+
+#ifndef PAL_STDCPP_COMPAT
+#ifdef __cplusplus
+#ifndef __PLACEMENT_NEW_INLINE
+#define __PLACEMENT_NEW_INLINE
+inline void *__cdecl operator new(size_t, void *_P)
+{
+ return (_P);
+}
+#endif // __PLACEMENT_NEW_INLINE
+#endif // __cplusplus
+#endif // !PAL_STDCPP_COMPAT
+
+#include <pal_assert.h>
+
+#if defined(_DEBUG)
+#define ROTOR_PAL_CTOR_TEST_BODY(TESTNAME) \
+ class TESTNAME ## _CTOR_TEST { \
+ public: \
+ class HelperClass { \
+ public: \
+ HelperClass(const char *String) { \
+ _ASSERTE (m_s == NULL); \
+ m_s = String; \
+ } \
+ \
+ void Validate (const char *String) { \
+ _ASSERTE (m_s); \
+ _ASSERTE (m_s == String); \
+ _ASSERTE (!strncmp ( \
+ m_s, \
+ String, \
+ 1000)); \
+ } \
+ \
+ private: \
+ const char *m_s; \
+ }; \
+ \
+ TESTNAME ## _CTOR_TEST() { \
+ _ASSERTE (m_This == NULL); \
+ m_This = this; \
+ } \
+ \
+ void Validate () { \
+ _ASSERTE (m_This == this); \
+ m_String.Validate(#TESTNAME "_CTOR_TEST"); \
+ } \
+ \
+ private: \
+ void *m_This; \
+ static HelperClass m_String; \
+ }; \
+ \
+ static TESTNAME ## _CTOR_TEST \
+ g_ ## TESTNAME ## _CTOR_TEST; \
+ TESTNAME ## _CTOR_TEST::HelperClass \
+ TESTNAME ## _CTOR_TEST::m_String(#TESTNAME "_CTOR_TEST");
+
+#define ROTOR_PAL_CTOR_TEST_RUN(TESTNAME) \
+ g_ ## TESTNAME ##_CTOR_TEST.Validate()
+
+#else // DEBUG
+
+#define ROTOR_PAL_CTOR_TEST_BODY(TESTNAME)
+#define ROTOR_PAL_CTOR_TEST_RUN(TESTNAME) do {} while (0)
+
+#endif // DEBUG
+
+#define NTAPI __stdcall
+#define WINAPI __stdcall
+#define CALLBACK __stdcall
+#define NTSYSAPI
+
+#define _WINNT_
+
+// C++ standard, 18.1.5 - offsetof requires a POD (plain old data) struct or
+// union. Since offsetof is a macro, gcc doesn't actually check for improper
+// use of offsetof, it keys off of the -> from NULL (which is also invalid for
+// non-POD types by 18.1.5)
+//
+// As we have numerous examples of this behavior in our codebase,
+// making an offsetof which doesn't use 0.
+
+// PAL_safe_offsetof is a version of offsetof that protects against an
+// overridden operator&
+
+#if defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 5 || __GNUC__ > 3)
+#define FIELD_OFFSET(type, field) __builtin_offsetof(type, field)
+#ifndef offsetof
+#define offsetof(type, field) __builtin_offsetof(type, field)
+#endif
+#define PAL_safe_offsetof(type, field) __builtin_offsetof(type, field)
+#else
+#define FIELD_OFFSET(type, field) (((LONG)(LONG_PTR)&(((type *)64)->field)) - 64)
+#ifndef offsetof
+#define offsetof(s,m) ((size_t)((ptrdiff_t)&(((s *)64)->m)) - 64)
+#endif
+#define PAL_safe_offsetof(s,m) ((size_t)((ptrdiff_t)&(char&)(((s *)64)->m))-64)
+#endif
+
+#define CONTAINING_RECORD(address, type, field) \
+ ((type *)((LONG_PTR)(address) - FIELD_OFFSET(type, field)))
+
+#define ARGUMENT_PRESENT(ArgumentPointer) (\
+ (CHAR *)(ArgumentPointer) != (CHAR *)(NULL) )
+
+#if defined(_WIN64) || defined(_M_ALPHA)
+#define MAX_NATURAL_ALIGNMENT sizeof(ULONGLONG)
+#else
+#define MAX_NATURAL_ALIGNMENT sizeof(ULONG)
+#endif
+
+#define DECLARE_HANDLE(name) struct name##__ { int unused; }; typedef struct name##__ *name
+
+#ifndef COM_NO_WINDOWS_H
+#define COM_NO_WINDOWS_H
+#endif
+
+#define interface struct
+
+#define STDMETHODCALLTYPE __stdcall
+#define STDMETHODVCALLTYPE __cdecl
+
+#define STDAPICALLTYPE __stdcall
+#define STDAPIVCALLTYPE __cdecl
+
+#define STDMETHODIMP HRESULT STDMETHODCALLTYPE
+#define STDMETHODIMP_(type) type STDMETHODCALLTYPE
+
+#define STDMETHODIMPV HRESULT STDMETHODVCALLTYPE
+#define STDMETHODIMPV_(type) type STDMETHODVCALLTYPE
+
+#define STDMETHOD(method) virtual HRESULT STDMETHODCALLTYPE method
+#define STDMETHOD_(type,method) virtual type STDMETHODCALLTYPE method
+
+#define STDMETHODV(method) virtual HRESULT STDMETHODVCALLTYPE method
+#define STDMETHODV_(type,method) virtual type STDMETHODVCALLTYPE method
+
+#define STDAPI EXTERN_C HRESULT STDAPICALLTYPE
+#define STDAPI_(type) EXTERN_C type STDAPICALLTYPE
+
+#define STDAPIV EXTERN_C HRESULT STDAPIVCALLTYPE
+#define STDAPIV_(type) EXTERN_C type STDAPIVCALLTYPE
+
+#define PURE = 0
+#define THIS_
+#define THIS void
+
+#ifndef _DECLSPEC_DEFINED_
+#define _DECLSPEC_DEFINED_
+
+#if defined(_MSC_VER)
+#define DECLSPEC_NOVTABLE __declspec(novtable)
+#define DECLSPEC_IMPORT __declspec(dllimport)
+#define DECLSPEC_SELECTANY __declspec(selectany)
+#elif defined(__GNUC__)
+#define DECLSPEC_NOVTABLE
+#define DECLSPEC_IMPORT
+#define DECLSPEC_SELECTANY __attribute__((weak))
+#else
+#define DECLSPEC_NOVTABLE
+#define DECLSPEC_IMPORT
+#define DECLSPEC_SELECTANY
+#endif
+
+#endif // !_DECLSPEC_DEFINED_
+
+#define DECLARE_INTERFACE(iface) interface DECLSPEC_NOVTABLE iface
+#define DECLARE_INTERFACE_(iface, baseiface) interface DECLSPEC_NOVTABLE iface : public baseiface
+
+#ifdef __cplusplus
+#define REFGUID const GUID &
+#else
+#define REFGUID const GUID *
+#endif
+
+EXTERN_C const GUID GUID_NULL;
+
+typedef GUID *LPGUID;
+typedef const GUID FAR *LPCGUID;
+
+#ifdef __cplusplus
+extern "C++" {
+#if !defined _SYS_GUID_OPERATOR_EQ_ && !defined _NO_SYS_GUID_OPERATOR_EQ_
+#define _SYS_GUID_OPERATOR_EQ_
+inline int IsEqualGUID(REFGUID rguid1, REFGUID rguid2)
+ { return !memcmp(&rguid1, &rguid2, sizeof(GUID)); }
+inline int operator==(REFGUID guidOne, REFGUID guidOther)
+ { return IsEqualGUID(guidOne,guidOther); }
+inline int operator!=(REFGUID guidOne, REFGUID guidOther)
+ { return !IsEqualGUID(guidOne,guidOther); }
+#endif
+};
+#endif // __cplusplus
+
+#define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
+ EXTERN_C const GUID FAR name
+
+typedef GUID IID;
+#ifdef __cplusplus
+#define REFIID const IID &
+#else
+#define REFIID const IID *
+#endif
+#define IID_NULL GUID_NULL
+#define IsEqualIID(riid1, riid2) IsEqualGUID(riid1, riid2)
+
+#define __IID_DEFINED__
+
+typedef GUID CLSID;
+#define CLSID_DEFINED
+#ifdef __cplusplus
+#define REFCLSID const CLSID &
+#else
+#define REFCLSID const CLSID *
+#endif
+#define CLSID_NULL GUID_NULL
+#define IsEqualCLSID(rclsid1, rclsid2) IsEqualGUID(rclsid1, rclsid2)
+typedef CLSID *LPCLSID;
+
+typedef UINT_PTR WPARAM;
+typedef LONG_PTR LRESULT;
+
+typedef LONG SCODE;
+
+
+typedef union _ULARGE_INTEGER {
+ struct {
+#if BIGENDIAN
+ DWORD HighPart;
+ DWORD LowPart;
+#else
+ DWORD LowPart;
+ DWORD HighPart;
+#endif
+ }
+#ifndef PAL_STDCPP_COMPAT
+ u
+#endif // PAL_STDCPP_COMPAT
+ ;
+ ULONGLONG QuadPart;
+} ULARGE_INTEGER, *PULARGE_INTEGER;
+
+/******************* HRESULT types ****************************************/
+
+#define FACILITY_WINDOWS 8
+#define FACILITY_URT 19
+#define FACILITY_UMI 22
+#define FACILITY_SXS 23
+#define FACILITY_STORAGE 3
+#define FACILITY_SSPI 9
+#define FACILITY_SCARD 16
+#define FACILITY_SETUPAPI 15
+#define FACILITY_SECURITY 9
+#define FACILITY_RPC 1
+#define FACILITY_WIN32 7
+#define FACILITY_CONTROL 10
+#define FACILITY_NULL 0
+#define FACILITY_MSMQ 14
+#define FACILITY_MEDIASERVER 13
+#define FACILITY_INTERNET 12
+#define FACILITY_ITF 4
+#define FACILITY_DPLAY 21
+#define FACILITY_DISPATCH 2
+#define FACILITY_COMPLUS 17
+#define FACILITY_CERT 11
+#define FACILITY_ACS 20
+#define FACILITY_AAF 18
+
+#define NO_ERROR 0L
+
+#define SEVERITY_SUCCESS 0
+#define SEVERITY_ERROR 1
+
+#define SUCCEEDED(Status) ((HRESULT)(Status) >= 0)
+#define FAILED(Status) ((HRESULT)(Status)<0)
+#define IS_ERROR(Status) ((ULONG)(Status) >> 31 == SEVERITY_ERROR) // diff from win32
+#define HRESULT_CODE(hr) ((hr) & 0xFFFF)
+#define SCODE_CODE(sc) ((sc) & 0xFFFF)
+#define HRESULT_FACILITY(hr) (((hr) >> 16) & 0x1fff)
+#define SCODE_FACILITY(sc) (((sc) >> 16) & 0x1fff)
+#define HRESULT_SEVERITY(hr) (((hr) >> 31) & 0x1)
+#define SCODE_SEVERITY(sc) (((sc) >> 31) & 0x1)
+
+// both macros diff from Win32
+#define MAKE_HRESULT(sev,fac,code) \
+ ((HRESULT) (((ULONG)(sev)<<31) | ((ULONG)(fac)<<16) | ((ULONG)(code))) )
+#define MAKE_SCODE(sev,fac,code) \
+ ((SCODE) (((ULONG)(sev)<<31) | ((ULONG)(fac)<<16) | ((LONG)(code))) )
+
+#define FACILITY_NT_BIT 0x10000000
+#define HRESULT_FROM_WIN32(x) ((HRESULT)(x) <= 0 ? ((HRESULT)(x)) : ((HRESULT) (((x) & 0x0000FFFF) | (FACILITY_WIN32 << 16) | 0x80000000)))
+#define __HRESULT_FROM_WIN32(x) HRESULT_FROM_WIN32(x)
+
+#define HRESULT_FROM_NT(x) ((HRESULT) ((x) | FACILITY_NT_BIT))
+
+/******************* OLE, BSTR, VARIANT *************************/
+
+STDAPI_(LPVOID) CoTaskMemAlloc(SIZE_T cb);
+STDAPI_(LPVOID) CoTaskMemRealloc(LPVOID pv, SIZE_T cb);
+STDAPI_(void) CoTaskMemFree(LPVOID pv);
+
+typedef SHORT VARIANT_BOOL;
+#define VARIANT_TRUE ((VARIANT_BOOL)-1)
+#define VARIANT_FALSE ((VARIANT_BOOL)0)
+
+typedef WCHAR OLECHAR;
+typedef OLECHAR* LPOLESTR;
+typedef const OLECHAR* LPCOLESTR;
+
+typedef WCHAR *BSTR;
+
+STDAPI_(BSTR) SysAllocString(const OLECHAR*);
+STDAPI_(BSTR) SysAllocStringLen(const OLECHAR*, UINT);
+STDAPI_(BSTR) SysAllocStringByteLen(const char *, UINT);
+STDAPI_(void) SysFreeString(BSTR);
+STDAPI_(UINT) SysStringLen(BSTR);
+STDAPI_(UINT) SysStringByteLen(BSTR);
+
+typedef double DATE;
+
+typedef union tagCY {
+ struct {
+#if BIGENDIAN
+ LONG Hi;
+ ULONG Lo;
+#else
+ ULONG Lo;
+ LONG Hi;
+#endif
+ } u;
+ LONGLONG int64;
+} CY, *LPCY;
+
+typedef CY CURRENCY;
+
+typedef struct tagDEC {
+ // Decimal.cs treats the first two shorts as one long
+ // And they seriable the data so we need to little endian
+ // seriliazation
+ // The wReserved overlaps with Variant's vt member
+#if BIGENDIAN
+ union {
+ struct {
+ BYTE sign;
+ BYTE scale;
+ } u;
+ USHORT signscale;
+ } u;
+ USHORT wReserved;
+#else
+ USHORT wReserved;
+ union {
+ struct {
+ BYTE scale;
+ BYTE sign;
+ } u;
+ USHORT signscale;
+ } u;
+#endif
+ ULONG Hi32;
+ union {
+ struct {
+ ULONG Lo32;
+ ULONG Mid32;
+ } v;
+ ULONGLONG Lo64;
+ } v;
+} DECIMAL, *LPDECIMAL;
+
+#define DECIMAL_NEG ((BYTE)0x80)
+#define DECIMAL_SCALE(dec) ((dec).u.u.scale)
+#define DECIMAL_SIGN(dec) ((dec).u.u.sign)
+#define DECIMAL_SIGNSCALE(dec) ((dec).u.signscale)
+#define DECIMAL_LO32(dec) ((dec).v.v.Lo32)
+#define DECIMAL_MID32(dec) ((dec).v.v.Mid32)
+#define DECIMAL_HI32(dec) ((dec).Hi32)
+#define DECIMAL_LO64_GET(dec) ((dec).v.Lo64)
+#define DECIMAL_LO64_SET(dec,value) {(dec).v.Lo64 = value; }
+
+#define DECIMAL_SETZERO(dec) {DECIMAL_LO32(dec) = 0; DECIMAL_MID32(dec) = 0; DECIMAL_HI32(dec) = 0; DECIMAL_SIGNSCALE(dec) = 0;}
+
+typedef struct tagBLOB {
+ ULONG cbSize;
+ BYTE *pBlobData;
+} BLOB, *LPBLOB;
+
+interface IStream;
+interface IRecordInfo;
+
+typedef unsigned short VARTYPE;
+
+enum VARENUM {
+ VT_EMPTY = 0,
+ VT_NULL = 1,
+ VT_I2 = 2,
+ VT_I4 = 3,
+ VT_R4 = 4,
+ VT_R8 = 5,
+ VT_CY = 6,
+ VT_DATE = 7,
+ VT_BSTR = 8,
+ VT_DISPATCH = 9,
+ VT_ERROR = 10,
+ VT_BOOL = 11,
+ VT_VARIANT = 12,
+ VT_UNKNOWN = 13,
+ VT_DECIMAL = 14,
+ VT_I1 = 16,
+ VT_UI1 = 17,
+ VT_UI2 = 18,
+ VT_UI4 = 19,
+ VT_I8 = 20,
+ VT_UI8 = 21,
+ VT_INT = 22,
+ VT_UINT = 23,
+ VT_VOID = 24,
+ VT_HRESULT = 25,
+ VT_PTR = 26,
+ VT_SAFEARRAY = 27,
+ VT_CARRAY = 28,
+ VT_USERDEFINED = 29,
+ VT_LPSTR = 30,
+ VT_LPWSTR = 31,
+ VT_RECORD = 36,
+ VT_INT_PTR = 37,
+ VT_UINT_PTR = 38,
+
+ VT_FILETIME = 64,
+ VT_BLOB = 65,
+ VT_STREAM = 66,
+ VT_STORAGE = 67,
+ VT_STREAMED_OBJECT = 68,
+ VT_STORED_OBJECT = 69,
+ VT_BLOB_OBJECT = 70,
+ VT_CF = 71,
+ VT_CLSID = 72,
+
+ VT_VECTOR = 0x1000,
+ VT_ARRAY = 0x2000,
+ VT_BYREF = 0x4000,
+ VT_TYPEMASK = 0xfff,
+};
+
+typedef struct tagVARIANT VARIANT, *LPVARIANT;
+typedef struct tagSAFEARRAY SAFEARRAY;
+
+struct tagVARIANT
+ {
+ union
+ {
+ struct
+ {
+#if BIGENDIAN
+ // We need to make sure vt overlaps with DECIMAL's wReserved.
+ // See the DECIMAL type for details.
+ WORD wReserved1;
+ VARTYPE vt;
+#else
+ VARTYPE vt;
+ WORD wReserved1;
+#endif
+ WORD wReserved2;
+ WORD wReserved3;
+ union
+ {
+ LONGLONG llVal;
+ LONG lVal;
+ BYTE bVal;
+ SHORT iVal;
+ FLOAT fltVal;
+ DOUBLE dblVal;
+ VARIANT_BOOL boolVal;
+ SCODE scode;
+ CY cyVal;
+ DATE date;
+ BSTR bstrVal;
+ interface IUnknown *punkVal;
+ interface IDispatch *pdispVal;
+ SAFEARRAY *parray;
+ BYTE *pbVal;
+ SHORT *piVal;
+ LONG *plVal;
+ LONGLONG *pllVal;
+ FLOAT *pfltVal;
+ DOUBLE *pdblVal;
+ VARIANT_BOOL *pboolVal;
+ SCODE *pscode;
+ CY *pcyVal;
+ DATE *pdate;
+ BSTR *pbstrVal;
+ interface IUnknown **ppunkVal;
+ VARIANT *pvarVal;
+ PVOID byref;
+ CHAR cVal;
+ USHORT uiVal;
+ ULONG ulVal;
+ ULONGLONG ullVal;
+ INT intVal;
+ UINT uintVal;
+ DECIMAL *pdecVal;
+ CHAR *pcVal;
+ USHORT *puiVal;
+ ULONG *pulVal;
+ ULONGLONG *pullVal;
+ INT *pintVal;
+ UINT *puintVal;
+ struct __tagBRECORD
+ {
+ PVOID pvRecord;
+ interface IRecordInfo *pRecInfo;
+ } brecVal;
+ } n3;
+ } n2;
+ DECIMAL decVal;
+ } n1;
+ };
+
+typedef VARIANT VARIANTARG, *LPVARIANTARG;
+
+STDAPI_(void) VariantInit(VARIANT * pvarg);
+STDAPI_(HRESULT) VariantClear(VARIANT * pvarg);
+
+#define V_VT(X) ((X)->n1.n2.vt)
+#define V_UNION(X, Y) ((X)->n1.n2.n3.Y)
+#define V_RECORDINFO(X) ((X)->n1.n2.n3.brecVal.pRecInfo)
+#define V_RECORD(X) ((X)->n1.n2.n3.brecVal.pvRecord)
+
+#define V_UI1(X) V_UNION(X, bVal)
+#define V_UI1REF(X) V_UNION(X, pbVal)
+#define V_I2(X) V_UNION(X, iVal)
+#define V_I2REF(X) V_UNION(X, piVal)
+#define V_I4(X) V_UNION(X, lVal)
+#define V_I4REF(X) V_UNION(X, plVal)
+#define V_I8(X) V_UNION(X, llVal)
+#define V_I8REF(X) V_UNION(X, pllVal)
+#define V_R4(X) V_UNION(X, fltVal)
+#define V_R4REF(X) V_UNION(X, pfltVal)
+#define V_R8(X) V_UNION(X, dblVal)
+#define V_R8REF(X) V_UNION(X, pdblVal)
+#define V_I1(X) V_UNION(X, cVal)
+#define V_I1REF(X) V_UNION(X, pcVal)
+#define V_UI2(X) V_UNION(X, uiVal)
+#define V_UI2REF(X) V_UNION(X, puiVal)
+#define V_UI4(X) V_UNION(X, ulVal)
+#define V_UI4REF(X) V_UNION(X, pulVal)
+#define V_UI8(X) V_UNION(X, ullVal)
+#define V_UI8REF(X) V_UNION(X, pullVal)
+#define V_INT(X) V_UNION(X, intVal)
+#define V_INTREF(X) V_UNION(X, pintVal)
+#define V_UINT(X) V_UNION(X, uintVal)
+#define V_UINTREF(X) V_UNION(X, puintVal)
+#define V_ARRAY(X) V_UNION(X, parray)
+
+#ifdef _WIN64
+#define V_INT_PTR(X) V_UNION(X, llVal)
+#define V_UINT_PTR(X) V_UNION(X, ullVal)
+#define V_INT_PTRREF(X) V_UNION(X, pllVal)
+#define V_UINT_PTRREF(X) V_UNION(X, pullVal)
+#else
+#define V_INT_PTR(X) V_UNION(X, lVal)
+#define V_UINT_PTR(X) V_UNION(X, ulVal)
+#define V_INT_PTRREF(X) V_UNION(X, plVal)
+#define V_UINT_PTRREF(X) V_UNION(X, pulVal)
+#endif
+
+#define V_CY(X) V_UNION(X, cyVal)
+#define V_CYREF(X) V_UNION(X, pcyVal)
+#define V_DATE(X) V_UNION(X, date)
+#define V_DATEREF(X) V_UNION(X, pdate)
+#define V_BSTR(X) V_UNION(X, bstrVal)
+#define V_BSTRREF(X) V_UNION(X, pbstrVal)
+#define V_UNKNOWN(X) V_UNION(X, punkVal)
+#define V_UNKNOWNREF(X) V_UNION(X, ppunkVal)
+#define V_VARIANTREF(X) V_UNION(X, pvarVal)
+#define V_DISPATCH(X) V_UNION(X, pdispVal)
+#define V_ERROR(X) V_UNION(X, scode)
+#define V_ERRORREF(X) V_UNION(X, pscode)
+#define V_BOOL(X) V_UNION(X, boolVal)
+#define V_BOOLREF(X) V_UNION(X, pboolVal)
+#define V_BYREF(X) V_UNION(X, byref)
+
+#define V_DECIMAL(X) ((X)->n1.decVal)
+#define V_DECIMALREF(X) V_UNION(X, pdecVal)
+
+#define V_ISBYREF(X) (V_VT(X)&VT_BYREF)
+
+STDAPI CreateStreamOnHGlobal(PVOID hGlobal, BOOL fDeleteOnRelease, interface IStream** ppstm);
+
+#define STGM_DIRECT 0x00000000L
+
+#define STGM_READ 0x00000000L
+#define STGM_WRITE 0x00000001L
+#define STGM_READWRITE 0x00000002L
+
+#define STGM_SHARE_DENY_NONE 0x00000040L
+#define STGM_SHARE_DENY_READ 0x00000030L
+#define STGM_SHARE_DENY_WRITE 0x00000020L
+#define STGM_SHARE_EXCLUSIVE 0x00000010L
+
+#define STGM_DELETEONRELEASE 0x04000000L
+
+#define STGM_CREATE 0x00001000L
+#define STGM_CONVERT 0x00020000L
+#define STGM_FAILIFTHERE 0x00000000L
+
+#define STGM_NOSNAPSHOT 0x00200000L
+
+STDAPI IIDFromString(LPOLESTR lpsz, IID* lpiid);
+STDAPI_(int) StringFromGUID2(REFGUID rguid, LPOLESTR lpsz, int cchMax);
+
+/******************* CRYPT **************************************/
+
+#define PUBLICKEYBLOB 0x6
+
+//
+// Algorithm IDs and Flags
+//
+#define GET_ALG_CLASS(x) (x & (7 << 13))
+#define GET_ALG_TYPE(x) (x & (15 << 9))
+#define GET_ALG_SID(x) (x & (511))
+
+typedef unsigned int ALG_ID;
+
+// Algorithm classes
+#define ALG_CLASS_SIGNATURE (1 << 13)
+#define ALG_CLASS_HASH (4 << 13)
+
+// Algorithm types
+#define ALG_TYPE_ANY (0)
+
+// Hash sub ids
+#define ALG_SID_SHA1 4
+
+// algorithm identifier definitions
+#define CALG_SHA1 (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA1)
+
+/******************* NLS ****************************************/
+
+typedef
+enum tagMIMECONTF {
+ MIMECONTF_MAILNEWS = 0x1,
+ MIMECONTF_BROWSER = 0x2,
+ MIMECONTF_MINIMAL = 0x4,
+ MIMECONTF_IMPORT = 0x8,
+ MIMECONTF_SAVABLE_MAILNEWS = 0x100,
+ MIMECONTF_SAVABLE_BROWSER = 0x200,
+ MIMECONTF_EXPORT = 0x400,
+ MIMECONTF_PRIVCONVERTER = 0x10000,
+ MIMECONTF_VALID = 0x20000,
+ MIMECONTF_VALID_NLS = 0x40000,
+ MIMECONTF_MIME_IE4 = 0x10000000,
+ MIMECONTF_MIME_LATEST = 0x20000000,
+ MIMECONTF_MIME_REGISTRY = 0x40000000
+ } MIMECONTF;
+
+#define LCMAP_LOWERCASE 0x00000100
+#define LCMAP_UPPERCASE 0x00000200
+#define LCMAP_SORTKEY 0x00000400
+#define LCMAP_BYTEREV 0x00000800
+
+#define LCMAP_HIRAGANA 0x00100000
+#define LCMAP_KATAKANA 0x00200000
+#define LCMAP_HALFWIDTH 0x00400000
+#define LCMAP_FULLWIDTH 0x00800000
+
+#define LCMAP_LINGUISTIC_CASING 0x01000000
+
+// 8 characters for language
+// 8 characters for region
+// 64 characters for suffix (script)
+// 2 characters for '-' separators
+// 2 characters for prefix like "i-" or "x-"
+// 1 null termination
+#define LOCALE_NAME_MAX_LENGTH 85
+
+#define LOCALE_SCOUNTRY 0x00000006
+#define LOCALE_SENGCOUNTRY 0x00001002
+
+#define LOCALE_SLANGUAGE 0x00000002
+#define LOCALE_SENGLANGUAGE 0x00001001
+
+#define LOCALE_SDATE 0x0000001D
+#define LOCALE_STIME 0x0000001E
+
+#define CSTR_LESS_THAN 1
+#define CSTR_EQUAL 2
+#define CSTR_GREATER_THAN 3
+
+#define NORM_IGNORENONSPACE 0x00000002
+
+#define WC_COMPOSITECHECK 0x00000000 // NOTE: diff from winnls.h
+
+/******************* shlwapi ************************************/
+
+// note: diff in NULL handing and calling convetion
+#define StrCpyW PAL_wcscpy
+#define StrCpyNW lstrcpynW // note: can't be wcsncpy!
+#define StrCatW PAL_wcscat
+#define StrChrW (WCHAR*)PAL_wcschr
+#define StrCmpW PAL_wcscmp
+#define StrCmpIW _wcsicmp
+#define StrCmpNW PAL_wcsncmp
+#define StrCmpNIW _wcsnicmp
+
+STDAPI_(LPWSTR) StrNCatW(LPWSTR lpFront, LPCWSTR lpBack, int cchMax);
+STDAPI_(int) StrToIntW(LPCWSTR lpSrc);
+STDAPI_(LPWSTR) StrStrIW(LPCWSTR lpFirst, LPCWSTR lpSrch);
+STDAPI_(LPWSTR) StrRChrW(LPCWSTR lpStart, LPCWSTR lpEnd, WCHAR wMatch);
+STDAPI_(LPWSTR) StrCatBuffW(LPWSTR pszDest, LPCWSTR pszSrc, int cchDestBuffSize);
+
+#define lstrcmpW PAL_wcscmp
+#define lstrcmpiW _wcsicmp
+#define wnsprintfW _snwprintf // note: not 100% compatible (wsprintf should be subset of sprintf...)
+#define wvnsprintfW _vsnwprintf // note: not 100% compatible (wsprintf should be subset of sprintf...)
+
+#ifdef UNICODE
+#define StrCpy StrCpyW
+#define StrCpyN StrCpyNW
+#define StrCat StrCatW
+#define StrNCat StrNCatW
+#define StrChr StrChrW
+#define StrCmp StrCmpW
+#define StrCmpN StrCmpNW
+#define StrCmpI StrCmpIW
+#define StrCmpNI StrCmpNIW
+
+#define StrToInt StrToIntW
+#define StrStrI StrStrIW
+#define StrRChr StrRChrW
+#define StrCatBuff StrCatBuffW
+
+#define lstrcmp lstrcmpW
+#define lstrcmpi lstrcmpiW
+#define wnsprintf wnsprintfW
+#endif
+
+
+#ifdef __cplusplus
+/*
+ Safe CRT functions are not available (yet) on all platforms, so we use our own implementations from safecrt.h.
+*/
+#define _CRT_ALTERNATIVE_INLINES
+#define _SAFECRT_NO_INCLUDES 1
+#define _SAFECRT_USE_INLINES 1
+#define _SAFECRT_SET_ERRNO 0
+#define _SAFECRT_DEFINE_MBS_FUNCTIONS 0
+#define _SAFECRT_DEFINE_TCS_MACROS 1
+/*
+#define _SAFECRT__ISMBBLEAD(_Character) 0
+#define _SAFECRT__MBSDEC(_String, _Current) (_Current - 1)
+*/
+#include "safecrt.h"
+#include "specstrings.h"
+
+/*
+The wrappers below are simple implementations that may not be as robust as complete functions in the Secure CRT library.
+Remember to fix the errcode defintion in safecrt.h.
+*/
+
+#define _wcslwr_s _wcslwr_unsafe
+#define _snwprintf_s _snwprintf_unsafe
+#define _vsnwprintf_s _vsnwprintf_unsafe
+#define _snprintf_s _snprintf_unsafe
+#define _vsnprintf_s _vsnprintf_unsafe
+#define swscanf_s swscanf
+#define sscanf_s sscanf
+
+#define _wfopen_s _wfopen_unsafe
+#define fopen_s _fopen_unsafe
+
+#define _strlwr_s _strlwr_unsafe
+
+#define _vscprintf _vscprintf_unsafe
+#define _vscwprintf _vscwprintf_unsafe
+
+#define sprintf_s _snprintf
+#define swprintf_s _snwprintf
+#define vsprintf_s _vsnprintf
+#define vswprintf_s _vsnwprintf
+
+extern "C++" {
+
+#include <safemath.h>
+
+inline errno_t __cdecl _wcslwr_unsafe(WCHAR *str, size_t sz)
+{
+ size_t fullSize;
+ if(!ClrSafeInt<size_t>::multiply(sz, sizeof(WCHAR), fullSize))
+ return 1;
+ WCHAR *copy = (WCHAR *)malloc(fullSize);
+ if(copy == nullptr)
+ return 1;
+
+ errno_t retCode = wcscpy_s(copy, sz, str);
+ if(retCode) {
+ free(copy);
+ return 1;
+ }
+
+ _wcslwr(copy);
+ wcscpy_s(str, sz, copy);
+ free(copy);
+
+ return 0;
+}
+inline errno_t __cdecl _strlwr_unsafe(char *str, size_t sz)
+{
+ char *copy = (char *)malloc(sz);
+ if(copy == nullptr)
+ return 1;
+
+ errno_t retCode = strcpy_s(copy, sz, str);
+ if(retCode) {
+ free(copy);
+ return 1;
+ }
+
+ _strlwr(copy);
+ strcpy_s(str, sz, copy);
+ free(copy);
+
+ return 0;
+}
+
+inline int __cdecl _vscprintf_unsafe(const char *_Format, va_list _ArgList)
+{
+ int guess = 10;
+
+ for (;;)
+ {
+ char *buf = (char *)malloc(guess * sizeof(char));
+ if(buf == nullptr)
+ return 0;
+
+ int ret = _vsnprintf(buf, guess, _Format, _ArgList);
+ free(buf);
+
+ if ((ret != -1) && (ret < guess))
+ return ret;
+
+ guess *= 2;
+ }
+}
+
+inline int __cdecl _vscwprintf_unsafe(const WCHAR *_Format, va_list _ArgList)
+{
+ int guess = 256;
+
+ for (;;)
+ {
+ WCHAR *buf = (WCHAR *)malloc(guess * sizeof(WCHAR));
+ if (buf == nullptr)
+ return 0;
+
+ va_list apcopy;
+ va_copy(apcopy, _ArgList);
+ int ret = _vsnwprintf(buf, guess, _Format, apcopy);
+ free(buf);
+ va_end(apcopy);
+
+ if ((ret != -1) && (ret < guess))
+ return ret;
+
+ guess *= 2;
+ }
+}
+
+inline int __cdecl _vsnwprintf_unsafe(WCHAR *_Dst, size_t _SizeInWords, size_t _Count, const WCHAR *_Format, va_list _ArgList)
+{
+ if (_Count == _TRUNCATE) _Count = _SizeInWords - 1;
+ int ret = _vsnwprintf(_Dst, _Count, _Format, _ArgList);
+ _Dst[_SizeInWords - 1] = L'\0';
+ if (ret < 0 && errno == 0)
+ {
+ errno = ERANGE;
+ }
+ return ret;
+}
+
+inline int __cdecl _snwprintf_unsafe(WCHAR *_Dst, size_t _SizeInWords, size_t _Count, const WCHAR *_Format, ...)
+{
+ int ret;
+ va_list _ArgList;
+ va_start(_ArgList, _Format);
+ ret = _vsnwprintf_unsafe(_Dst, _SizeInWords, _Count, _Format, _ArgList);
+ va_end(_ArgList);
+ return ret;
+}
+
+inline int __cdecl _vsnprintf_unsafe(char *_Dst, size_t _SizeInWords, size_t _Count, const char *_Format, va_list _ArgList)
+{
+ if (_Count == _TRUNCATE) _Count = _SizeInWords - 1;
+ int ret = _vsnprintf(_Dst, _Count, _Format, _ArgList);
+ _Dst[_SizeInWords - 1] = L'\0';
+ if (ret < 0 && errno == 0)
+ {
+ errno = ERANGE;
+ }
+ return ret;
+}
+
+inline int __cdecl _snprintf_unsafe(char *_Dst, size_t _SizeInWords, size_t _Count, const char *_Format, ...)
+{
+ int ret;
+ va_list _ArgList;
+ va_start(_ArgList, _Format);
+ ret = _vsnprintf_unsafe(_Dst, _SizeInWords, _Count, _Format, _ArgList);
+ va_end(_ArgList);
+ return ret;
+}
+
+inline errno_t __cdecl _wfopen_unsafe(PAL_FILE * *ff, const WCHAR *fileName, const WCHAR *mode)
+{
+ PAL_FILE *result = _wfopen(fileName, mode);
+ if(result == 0) {
+ return 1;
+ } else {
+ *ff = result;
+ return 0;
+ }
+}
+
+inline errno_t __cdecl _fopen_unsafe(PAL_FILE * *ff, const char *fileName, const char *mode)
+{
+ PAL_FILE *result = PAL_fopen(fileName, mode);
+ if(result == 0) {
+ return 1;
+ } else {
+ *ff = result;
+ return 0;
+ }
+}
+
+/* _itow_s */
+_SAFECRT__EXTERN_C
+errno_t __cdecl _itow_s(int _Value, WCHAR *_Dst, size_t _SizeInWords, int _Radix);
+
+#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS
+template <size_t _SizeInWords>
+inline
+errno_t __cdecl _itow_s(int _Value, WCHAR (&_Dst)[_SizeInWords], int _Radix)
+{
+ return _itow_s(_Value, _Dst, _SizeInWords, _Radix);
+}
+#endif
+
+#if _SAFECRT_USE_INLINES
+
+__inline
+errno_t __cdecl _itow_s(int _Value, WCHAR *_Dst, size_t _SizeInWords, int _Radix)
+{
+ /* validation section */
+ _SAFECRT__VALIDATE_STRING(_Dst, _SizeInWords);
+
+ /* TODO: do not write past buffer size */
+ _itow(_Value, _Dst, _Radix);
+ return 0;
+}
+
+#endif
+
+/* _i64tow_s */
+_SAFECRT__EXTERN_C
+errno_t __cdecl _i64tow_s(__int64 _Value, WCHAR *_Dst, size_t _SizeInWords, int _Radix);
+
+#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS
+template <size_t _SizeInWords>
+inline
+errno_t __cdecl _i64tow_s(__int64 _Value, WCHAR (&_Dst)[_SizeInWords], int _Radix)
+{
+ return _i64tow_s(_Value, _Dst, _SizeInWords, _Radix);
+}
+#endif
+
+#if _SAFECRT_USE_INLINES
+
+__inline
+errno_t __cdecl _i64tow_s(__int64 _Value, WCHAR *_Dst, size_t _SizeInWords, int _Radix)
+{
+ /* validation section */
+ _SAFECRT__VALIDATE_STRING(_Dst, _SizeInWords);
+
+ /* TODO: do not write past buffer size */
+ _i64tow(_Value, _Dst, _Radix);
+ return 0;
+}
+
+#endif
+
+/* getenv_s */
+/*
+ * _ReturnValue indicates if the variable has been found and size needed
+ */
+_SAFECRT__EXTERN_C
+errno_t __cdecl getenv_s(size_t *_ReturnValue, char *_Dst, size_t _SizeInWords, const char *_Name);
+
+#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS
+template <size_t _SizeInWords>
+inline
+errno_t __cdecl getenv_s(size_t *_ReturnValue, char *_Dst, size_t _SizeInWords, const char *_Name)
+{
+ return getenv_s(_ReturnValue, _Dst, _SizeInWords, _Name);
+}
+#endif
+
+#if _SAFECRT_USE_INLINES
+
+__inline
+errno_t __cdecl getenv_s(size_t *_ReturnValue, char *_Dst, size_t _SizeInWords, const char *_Name)
+{
+ char *szFound;
+
+ /* validation section */
+ _SAFECRT__VALIDATE_STRING(_Dst, _SizeInWords);
+
+ szFound = getenv(_Name);
+ if (szFound == nullptr)
+ {
+ *_ReturnValue = 0;
+ return 0;
+ }
+ *_ReturnValue = strlen(szFound) + 1;
+ return strcpy_s(_Dst, _SizeInWords, szFound);
+}
+
+#endif
+
+}
+#endif /* __cplusplus */
+
+
+STDAPI_(BOOL) PathAppendW(LPWSTR pszPath, LPCWSTR pszMore);
+STDAPI_(int) PathCommonPrefixW(LPCWSTR pszFile1, LPCWSTR pszFile2, LPWSTR pszPath);
+PALIMPORT LPWSTR PALAPI PathFindFileNameW(LPCWSTR pPath);
+STDAPI_(int) PathGetDriveNumberW(LPCWSTR lpsz);
+STDAPI_(BOOL) PathIsRelativeW(LPCWSTR lpszPath);
+STDAPI_(BOOL) PathIsUNCW(LPCWSTR pszPath);
+STDAPI_(LPWSTR) PathAddBackslashW(LPWSTR lpszPath);
+STDAPI_(LPWSTR) PathRemoveBackslashW(LPWSTR lpszPath);
+STDAPI_(void) PathRemoveExtensionW(LPWSTR pszPath);
+STDAPI_(LPWSTR) PathCombineW(LPWSTR lpszDest, LPCWSTR lpszDir, LPCWSTR lpszFile);
+STDAPI_(BOOL) PathCanonicalizeW(LPWSTR lpszDst, LPCWSTR lpszSrc);
+STDAPI_(BOOL) PathRelativePathToW(LPWSTR pszPath, LPCWSTR pszFrom, DWORD dwAttrFrom, LPCWSTR pszTo, DWORD dwAttrTo);
+STDAPI_(BOOL) PathRenameExtensionW(LPWSTR pszPath, LPCWSTR pszExt);
+STDAPI_(BOOL) PathRemoveFileSpecW(LPWSTR pFile);
+STDAPI_(void) PathStripPathW (LPWSTR pszPath);
+
+STDAPI PathCreateFromUrlW(LPCWSTR pszUrl, LPWSTR pszPath, LPDWORD pcchPath, DWORD dwFlags);
+STDAPI_(BOOL) PathIsURLW(LPCWSTR pszPath);
+
+
+#define URL_UNESCAPE 0x10000000
+#define URL_ESCAPE_PERCENT 0x00001000
+
+typedef enum {
+ URLIS_FILEURL = 3,
+} URLIS;
+
+typedef enum {
+ URL_PART_SCHEME = 1,
+ URL_PART_HOSTNAME = 2,
+} URL_PART;
+
+STDAPI UrlCanonicalizeW(LPCWSTR pszUrl, LPWSTR pszCanonicalized, LPDWORD pcchCanonicalized, DWORD dwFlags);
+STDAPI UrlCombineW(LPCWSTR pszBase, LPCWSTR pszRelative, LPWSTR pszCombined, LPDWORD pcchCombined, DWORD dwFlags);
+STDAPI UrlEscapeW(LPCWSTR pszUrl, LPWSTR pszEscaped, LPDWORD pcchEscaped, DWORD dwFlags);
+STDAPI UrlUnescapeW(LPWSTR pszURL, LPWSTR pszUnescaped, LPDWORD pcchUnescaped, DWORD dwFlags);
+STDAPI_(BOOL) UrlIsW(LPCWSTR pszUrl, URLIS dwUrlIs);
+STDAPI UrlGetPartW(LPCWSTR pszIn, LPWSTR pszOut, LPDWORD pcchOut, DWORD dwPart, DWORD dwFlags);
+
+#ifdef UNICODE
+#define PathAppend PathAppendW
+#define PathCommonPrefix PathCommonPrefixW
+#define PathFindFileName PathFindFileNameW
+#define PathIsRelative PathIsRelativeW
+#define PathGetDriveNumber PathGetDriveNumberW
+#define PathIsUNC PathIsUNCW
+#define PathAddBackslash PathAddBackslashW
+#define PathRemoveBackslash PathRemoveBackslashW
+#define PathRemoveExtension PathRemoveExtensionW
+#define PathCombine PathCombineW
+#define PathSkipRoot PathSkipRootW
+#define PathFindExtension PathFindExtensionW
+#define PathCanonicalize PathCanonicalizeW
+#define PathRelativePathTo PathRelativePathToW
+#define PathRemoveFileSpec PathRemoveFileSpecW
+#define PathRenameExtension PathRenameExtensionW
+#define PathStripPath PathStripPathW
+
+#define PathCreateFromUrl PathCreateFromUrlW
+#define PathIsURL PathIsURLW
+
+#define UrlCanonicalize UrlCanonicalizeW
+#define UrlCombine UrlCombineW
+#define UrlEscape UrlEscapeW
+#define UrlUnescape UrlUnescapeW
+#define UrlIs UrlIsW
+#define UrlGetPart UrlGetPartW
+
+#endif // UNICODE
+
+/******************* misc ***************************************/
+
+#ifdef __cplusplus
+namespace std
+{
+ typedef decltype(nullptr) nullptr_t;
+}
+
+template< class T >
+typename std::remove_reference<T>::type&& move( T&& t );
+#endif // __cplusplus
+
+#define __RPC__out
+#define __RPC__in
+#define __RPC__deref_out_opt
+#define __RPC__in_opt
+#define __RPC__inout_xcount(x)
+#define __RPC__in_ecount_full(x)
+#define __RPC__out_ecount_part(x, y)
+#define __RPC__in_xcount(x)
+#define __RPC__inout
+#define __RPC__deref_out_ecount_full_opt(x)
+
+typedef DWORD OLE_COLOR;
+
+typedef union __m128i {
+ __int8 m128i_i8[16];
+ __int16 m128i_i16[8];
+ __int32 m128i_i32[4];
+ __int64 m128i_i64[2];
+ unsigned __int8 m128i_u8[16];
+ unsigned __int16 m128i_u16[8];
+ unsigned __int32 m128i_u32[4];
+ unsigned __int64 m128i_u64[2];
+} __m128i;
+
+#define PF_COMPARE_EXCHANGE_DOUBLE 2
+
+typedef VOID (NTAPI * WAITORTIMERCALLBACKFUNC) (PVOID, BOOLEAN );
+
+typedef HANDLE HWND;
+
+#define IS_TEXT_UNICODE_SIGNATURE 0x0008
+#define IS_TEXT_UNICODE_UNICODE_MASK 0x000F
+
+BOOL IsTextUnicode(CONST VOID* lpv, int iSize, LPINT lpiResult);
+
+typedef struct _LIST_ENTRY {
+ struct _LIST_ENTRY *Flink;
+ struct _LIST_ENTRY *Blink;
+} LIST_ENTRY, *PLIST_ENTRY;
+
+typedef VOID (__stdcall *WAITORTIMERCALLBACK)(PVOID, BOOLEAN);
+
+// 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 UNREFERENCED_PARAMETER(P) (void)(P)
+
+#ifdef BIT64
+#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
+
+#ifdef _TARGET_AMD64_
+#define RUNTIME_FUNCTION_INDIRECT 0x1
+#endif
+
+#define _ReturnAddress() __builtin_return_address(0)
+
+#ifdef PLATFORM_UNIX
+#define DIRECTORY_SEPARATOR_CHAR_A '/'
+#define DIRECTORY_SEPARATOR_CHAR_W W('/')
+#define DIRECTORY_SEPARATOR_STR_A "/"
+#define DIRECTORY_SEPARATOR_STR_W W("/")
+#define PATH_SEPARATOR_CHAR_W W(':')
+#define PATH_SEPARATOR_STR_W W(":")
+#define VOLUME_SEPARATOR_CHAR_W W('/')
+#else // PLATFORM_UNIX
+#define DIRECTORY_SEPARATOR_CHAR_A '\\'
+#define DIRECTORY_SEPARATOR_CHAR_W W('\\')
+#define DIRECTORY_SEPARATOR_STR_A "\\"
+#define DIRECTORY_SEPARATOR_STR_W W("\\")
+#define PATH_SEPARATOR_CHAR_W W(';')
+#define PATH_SEPARATOR_STR_W W(";")
+#define VOLUME_SEPARATOR_CHAR_W W(':')
+#endif // PLATFORM_UNIX
+
+#ifndef IMAGE_IMPORT_DESC_FIELD
+#define IMAGE_IMPORT_DESC_FIELD(img, f) ((img).u.f)
+#endif
+
+#ifndef IMAGE_COR20_HEADER_FIELD
+#define IMAGE_COR20_HEADER_FIELD(obj, f) ((obj).f)
+#endif
+
+// copied from winnt.h
+#define PROCESSOR_ARCHITECTURE_INTEL 0
+#define PROCESSOR_ARCHITECTURE_MIPS 1
+#define PROCESSOR_ARCHITECTURE_ALPHA 2
+#define PROCESSOR_ARCHITECTURE_PPC 3
+#define PROCESSOR_ARCHITECTURE_SHX 4
+#define PROCESSOR_ARCHITECTURE_ARM 5
+#define PROCESSOR_ARCHITECTURE_IA64 6
+#define PROCESSOR_ARCHITECTURE_ALPHA64 7
+#define PROCESSOR_ARCHITECTURE_MSIL 8
+#define PROCESSOR_ARCHITECTURE_AMD64 9
+#define PROCESSOR_ARCHITECTURE_IA32_ON_WIN64 10
+#define PROCESSOR_ARCHITECTURE_NEUTRAL 11
+#define PROCESSOR_ARCHITECTURE_ARM64 12
+
+#define PROCESSOR_ARCHITECTURE_UNKNOWN 0xFFFF
+
+//
+// JIT Debugging Info. This structure is defined to have constant size in
+// both the emulated and native environment.
+//
+
+typedef struct _JIT_DEBUG_INFO {
+ DWORD dwSize;
+ DWORD dwProcessorArchitecture;
+ DWORD dwThreadID;
+ DWORD dwReserved0;
+ ULONG64 lpExceptionAddress;
+ ULONG64 lpExceptionRecord;
+ ULONG64 lpContextRecord;
+} JIT_DEBUG_INFO, *LPJIT_DEBUG_INFO;
+
+typedef JIT_DEBUG_INFO JIT_DEBUG_INFO32, *LPJIT_DEBUG_INFO32;
+typedef JIT_DEBUG_INFO JIT_DEBUG_INFO64, *LPJIT_DEBUG_INFO64;
+
+/******************* resources ***************************************/
+
+#define MAKEINTRESOURCEW(i) ((LPWSTR)((ULONG_PTR)((WORD)(i))))
+#define RT_RCDATA MAKEINTRESOURCE(10)
+#define RT_VERSION MAKEINTRESOURCE(16)
+
+/******************* SAFEARRAY ************************/
+
+#define FADF_VARIANT ( 0x800 )
+
+typedef struct tagSAFEARRAYBOUND
+ {
+ ULONG cElements;
+ LONG lLbound;
+ } SAFEARRAYBOUND;
+
+typedef struct tagSAFEARRAYBOUND *LPSAFEARRAYBOUND;
+
+typedef struct tagSAFEARRAY
+ {
+ USHORT cDims;
+ USHORT fFeatures;
+ ULONG cbElements;
+ ULONG cLocks;
+ PVOID pvData;
+ SAFEARRAYBOUND rgsabound[ 1 ];
+ } SAFEARRAY;
+
+typedef SAFEARRAY *LPSAFEARRAY;
+
+
+STDAPI_(SAFEARRAY *) SafeArrayCreateVector(VARTYPE vt, LONG lLbound, ULONG cElements);
+STDAPI_(UINT) SafeArrayGetDim(SAFEARRAY * psa);
+STDAPI SafeArrayGetElement(SAFEARRAY * psa, LONG * rgIndices, void * pv);
+STDAPI SafeArrayGetLBound(SAFEARRAY * psa, UINT nDim, LONG * plLbound);
+STDAPI SafeArrayGetUBound(SAFEARRAY * psa, UINT nDim, LONG * plUbound);
+STDAPI SafeArrayGetVartype(SAFEARRAY * psa, VARTYPE * pvt);
+STDAPI SafeArrayPutElement(SAFEARRAY * psa, LONG * rgIndices, void * pv);
+STDAPI SafeArrayDestroy(SAFEARRAY * psa);
+
+EXTERN_C void * _stdcall _lfind(const void *, const void *, unsigned int *, unsigned int,
+ int (__cdecl *)(const void *, const void *));
+
+
+/*<TODO>****************** clean this up ***********************</TODO>*/
+
+
+interface IDispatch;
+interface ITypeInfo;
+interface ITypeLib;
+interface IMoniker;
+
+typedef VOID (WINAPI *LPOVERLAPPED_COMPLETION_ROUTINE)(
+ DWORD dwErrorCode,
+ DWORD dwNumberOfBytesTransfered,
+ LPVOID lpOverlapped);
+
+//
+// Debug APIs
+//
+#define EXCEPTION_DEBUG_EVENT 1
+#define CREATE_THREAD_DEBUG_EVENT 2
+#define CREATE_PROCESS_DEBUG_EVENT 3
+#define EXIT_THREAD_DEBUG_EVENT 4
+#define EXIT_PROCESS_DEBUG_EVENT 5
+#define LOAD_DLL_DEBUG_EVENT 6
+#define UNLOAD_DLL_DEBUG_EVENT 7
+#define OUTPUT_DEBUG_STRING_EVENT 8
+#define RIP_EVENT 9
+
+typedef struct _EXCEPTION_DEBUG_INFO {
+ EXCEPTION_RECORD ExceptionRecord;
+ DWORD dwFirstChance;
+} EXCEPTION_DEBUG_INFO, *LPEXCEPTION_DEBUG_INFO;
+
+typedef struct _CREATE_THREAD_DEBUG_INFO {
+ HANDLE hThread;
+ LPVOID lpThreadLocalBase;
+ LPTHREAD_START_ROUTINE lpStartAddress;
+} CREATE_THREAD_DEBUG_INFO, *LPCREATE_THREAD_DEBUG_INFO;
+
+typedef struct _CREATE_PROCESS_DEBUG_INFO {
+ HANDLE hFile;
+ HANDLE hProcess;
+ HANDLE hThread;
+ LPVOID lpBaseOfImage;
+ DWORD dwDebugInfoFileOffset;
+ DWORD nDebugInfoSize;
+ LPVOID lpThreadLocalBase;
+ LPTHREAD_START_ROUTINE lpStartAddress;
+ LPVOID lpImageName;
+ WORD fUnicode;
+} CREATE_PROCESS_DEBUG_INFO, *LPCREATE_PROCESS_DEBUG_INFO;
+
+typedef struct _EXIT_THREAD_DEBUG_INFO {
+ DWORD dwExitCode;
+} EXIT_THREAD_DEBUG_INFO, *LPEXIT_THREAD_DEBUG_INFO;
+
+typedef struct _EXIT_PROCESS_DEBUG_INFO {
+ DWORD dwExitCode;
+} EXIT_PROCESS_DEBUG_INFO, *LPEXIT_PROCESS_DEBUG_INFO;
+
+typedef struct _LOAD_DLL_DEBUG_INFO {
+ HANDLE hFile;
+ LPVOID lpBaseOfDll;
+ DWORD dwDebugInfoFileOffset;
+ DWORD nDebugInfoSize;
+ LPVOID lpImageName;
+ WORD fUnicode;
+} LOAD_DLL_DEBUG_INFO, *LPLOAD_DLL_DEBUG_INFO;
+
+typedef struct _UNLOAD_DLL_DEBUG_INFO {
+ LPVOID lpBaseOfDll;
+} UNLOAD_DLL_DEBUG_INFO, *LPUNLOAD_DLL_DEBUG_INFO;
+
+typedef struct _OUTPUT_DEBUG_STRING_INFO {
+ LPSTR lpDebugStringData;
+ WORD fUnicode;
+ WORD nDebugStringLength;
+} OUTPUT_DEBUG_STRING_INFO, *LPOUTPUT_DEBUG_STRING_INFO;
+
+typedef struct _RIP_INFO {
+ DWORD dwError;
+ DWORD dwType;
+} RIP_INFO, *LPRIP_INFO;
+
+typedef struct _DEBUG_EVENT {
+ DWORD dwDebugEventCode;
+ DWORD dwProcessId;
+ DWORD dwThreadId;
+ union {
+ EXCEPTION_DEBUG_INFO Exception;
+ CREATE_THREAD_DEBUG_INFO CreateThread;
+ CREATE_PROCESS_DEBUG_INFO CreateProcessInfo;
+ EXIT_THREAD_DEBUG_INFO ExitThread;
+ EXIT_PROCESS_DEBUG_INFO ExitProcess;
+ LOAD_DLL_DEBUG_INFO LoadDll;
+ UNLOAD_DLL_DEBUG_INFO UnloadDll;
+ OUTPUT_DEBUG_STRING_INFO DebugString;
+ RIP_INFO RipInfo;
+ } u;
+} DEBUG_EVENT, *LPDEBUG_EVENT;
+
+//
+// Define dynamic function table entry.
+//
+
+typedef
+PRUNTIME_FUNCTION
+GET_RUNTIME_FUNCTION_CALLBACK (
+ DWORD64 ControlPc,
+ PVOID Context
+ );
+typedef GET_RUNTIME_FUNCTION_CALLBACK *PGET_RUNTIME_FUNCTION_CALLBACK;
+
+typedef
+DWORD
+OUT_OF_PROCESS_FUNCTION_TABLE_CALLBACK (
+ HANDLE Process,
+ PVOID TableAddress,
+ PDWORD Entries,
+ PRUNTIME_FUNCTION* Functions
+ );
+typedef OUT_OF_PROCESS_FUNCTION_TABLE_CALLBACK *POUT_OF_PROCESS_FUNCTION_TABLE_CALLBACK;
+
+#define OUT_OF_PROCESS_FUNCTION_TABLE_CALLBACK_EXPORT_NAME \
+ "OutOfProcessFunctionTableCallback"
+
+#if defined(FEATURE_PAL_SXS)
+
+// #if !defined(_TARGET_MAC64)
+// typedef LONG (*PEXCEPTION_ROUTINE)(
+ // IN PEXCEPTION_POINTERS pExceptionPointers,
+ // IN LPVOID lpvParam);
+
+// #define DISPATCHER_CONTEXT LPVOID
+
+// #else // defined(_TARGET_MAC64)
+
+//
+// Define unwind history table structure.
+//
+
+#define UNWIND_HISTORY_TABLE_SIZE 12
+
+typedef struct _UNWIND_HISTORY_TABLE_ENTRY {
+ DWORD64 ImageBase;
+ PRUNTIME_FUNCTION FunctionEntry;
+} UNWIND_HISTORY_TABLE_ENTRY, *PUNWIND_HISTORY_TABLE_ENTRY;
+
+typedef struct _UNWIND_HISTORY_TABLE {
+ DWORD Count;
+ BYTE LocalHint;
+ BYTE GlobalHint;
+ BYTE Search;
+ BYTE Once;
+ DWORD64 LowAddress;
+ DWORD64 HighAddress;
+ UNWIND_HISTORY_TABLE_ENTRY Entry[UNWIND_HISTORY_TABLE_SIZE];
+} UNWIND_HISTORY_TABLE, *PUNWIND_HISTORY_TABLE;
+
+typedef
+EXCEPTION_DISPOSITION
+(*PEXCEPTION_ROUTINE) (
+ PEXCEPTION_RECORD ExceptionRecord,
+ ULONG64 EstablisherFrame,
+ PCONTEXT ContextRecord,
+ PVOID DispatcherContext
+ );
+
+#if defined(_ARM_)
+
+typedef struct _DISPATCHER_CONTEXT {
+ DWORD ControlPc;
+ DWORD ImageBase;
+ PRUNTIME_FUNCTION FunctionEntry;
+ DWORD EstablisherFrame;
+ DWORD TargetPc;
+ PCONTEXT ContextRecord;
+ PEXCEPTION_ROUTINE LanguageHandler;
+ PVOID HandlerData;
+ PUNWIND_HISTORY_TABLE HistoryTable;
+ DWORD ScopeIndex;
+ BOOLEAN ControlPcIsUnwound;
+ PBYTE NonVolatileRegisters;
+ DWORD Reserved;
+} DISPATCHER_CONTEXT, *PDISPATCHER_CONTEXT;
+
+#elif defined(_ARM64_)
+
+typedef struct _DISPATCHER_CONTEXT {
+ ULONG64 ControlPc;
+ ULONG64 ImageBase;
+ PRUNTIME_FUNCTION FunctionEntry;
+ ULONG64 EstablisherFrame;
+ ULONG64 TargetPc;
+ PCONTEXT ContextRecord;
+ PEXCEPTION_ROUTINE LanguageHandler;
+ PVOID HandlerData;
+ PUNWIND_HISTORY_TABLE HistoryTable;
+ ULONG64 ScopeIndex;
+ BOOLEAN ControlPcIsUnwound;
+ PBYTE NonVolatileRegisters;
+ ULONG64 Reserved;
+} DISPATCHER_CONTEXT, *PDISPATCHER_CONTEXT;
+
+#else
+
+typedef struct _DISPATCHER_CONTEXT {
+ ULONG64 ControlPc;
+ ULONG64 ImageBase;
+ PRUNTIME_FUNCTION FunctionEntry;
+ ULONG64 EstablisherFrame;
+ ULONG64 TargetIp;
+ PCONTEXT ContextRecord;
+ PEXCEPTION_ROUTINE LanguageHandler;
+ PVOID HandlerData;
+ PUNWIND_HISTORY_TABLE HistoryTable;
+} DISPATCHER_CONTEXT, *PDISPATCHER_CONTEXT;
+
+#endif
+
+// #endif // !defined(_TARGET_MAC64)
+
+typedef DISPATCHER_CONTEXT *PDISPATCHER_CONTEXT;
+
+#define ExceptionContinueSearch EXCEPTION_CONTINUE_SEARCH
+#define ExceptionStackUnwind EXCEPTION_EXECUTE_HANDLER
+#define ExceptionContinueExecution EXCEPTION_CONTINUE_EXECUTION
+
+#endif // FEATURE_PAL_SXS
+
+typedef struct _EXCEPTION_REGISTRATION_RECORD EXCEPTION_REGISTRATION_RECORD;
+typedef EXCEPTION_REGISTRATION_RECORD *PEXCEPTION_REGISTRATION_RECORD;
+
+typedef LPVOID HKEY;
+typedef LPVOID PACL;
+typedef LPVOID LPBC;
+typedef LPVOID PSECURITY_DESCRIPTOR;
+
+typedef struct _EXCEPTION_RECORD64 {
+ DWORD ExceptionCode;
+ ULONG ExceptionFlags;
+ ULONG64 ExceptionRecord;
+ ULONG64 ExceptionAddress;
+ ULONG NumberParameters;
+ ULONG __unusedAlignment;
+ ULONG64 ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS];
+} EXCEPTION_RECORD64, *PEXCEPTION_RECORD64;
+
+typedef LONG (WINAPI *PTOP_LEVEL_EXCEPTION_FILTER)(
+ IN struct _EXCEPTION_POINTERS *ExceptionInfo
+ );
+typedef PTOP_LEVEL_EXCEPTION_FILTER LPTOP_LEVEL_EXCEPTION_FILTER;
+
+/******************* ntdef ************************************/
+
+#ifndef ANYSIZE_ARRAY
+#define ANYSIZE_ARRAY 1 // winnt
+#endif
+
+/******************* winnt ************************************/
+
+typedef struct LIST_ENTRY32 {
+ ULONG Flink;
+ ULONG Blink;
+} LIST_ENTRY32;
+typedef LIST_ENTRY32 *PLIST_ENTRY32;
+
+typedef struct LIST_ENTRY64 {
+ ULONGLONG Flink;
+ ULONGLONG Blink;
+} LIST_ENTRY64;
+typedef LIST_ENTRY64 *PLIST_ENTRY64;
+
+/******************** PAL RT APIs *******************************/
+
+typedef struct _HSATELLITE *HSATELLITE;
+
+EXTERN_C HSATELLITE PALAPI PAL_LoadSatelliteResourceW(LPCWSTR SatelliteResourceFileName);
+EXTERN_C HSATELLITE PALAPI PAL_LoadSatelliteResourceA(LPCSTR SatelliteResourceFileName);
+EXTERN_C BOOL PALAPI PAL_FreeSatelliteResource(HSATELLITE SatelliteResource);
+EXTERN_C UINT PALAPI PAL_LoadSatelliteStringW(HSATELLITE SatelliteResource,
+ UINT uID,
+ LPWSTR lpBuffer,
+ UINT nBufferMax);
+EXTERN_C UINT PALAPI PAL_LoadSatelliteStringA(HSATELLITE SatelliteResource,
+ UINT uID,
+ LPSTR lpBuffer,
+ UINT nBufferMax);
+
+EXTERN_C HRESULT PALAPI PAL_CoCreateInstance(REFCLSID rclsid,
+ REFIID riid,
+ void **ppv);
+
+// So we can have CoCreateInstance in most of the code base,
+// instead of spreading around of if'def FEATURE_PALs for PAL_CoCreateInstance.
+#define CoCreateInstance(rclsid, pUnkOuter, dwClsContext, riid, ppv) PAL_CoCreateInstance(rclsid, riid, ppv)
+
+/************** verrsrc.h ************************************/
+
+/* ----- VS_VERSION.dwFileFlags ----- */
+#define VS_FF_DEBUG 0x00000001L
+#define VS_FF_PRERELEASE 0x00000002L
+#define VS_FF_PATCHED 0x00000004L
+#define VS_FF_PRIVATEBUILD 0x00000008L
+#define VS_FF_INFOINFERRED 0x00000010L
+#define VS_FF_SPECIALBUILD 0x00000020L
+
+/* ----- Types and structures ----- */
+typedef struct tagVS_FIXEDFILEINFO
+{
+ DWORD dwSignature; /* e.g. 0xfeef04bd */
+ DWORD dwStrucVersion; /* e.g. 0x00000042 = "0.42" */
+ DWORD dwFileVersionMS; /* e.g. 0x00030075 = "3.75" */
+ DWORD dwFileVersionLS; /* e.g. 0x00000031 = "0.31" */
+ DWORD dwProductVersionMS; /* e.g. 0x00030010 = "3.10" */
+ DWORD dwProductVersionLS; /* e.g. 0x00000031 = "0.31" */
+ DWORD dwFileFlagsMask; /* = 0x3F for version "0.42" */
+ DWORD dwFileFlags; /* e.g. VFF_DEBUG | VFF_PRERELEASE */
+ DWORD dwFileOS; /* e.g. VOS_DOS_WINDOWS16 */
+ DWORD dwFileType; /* e.g. VFT_DRIVER */
+ DWORD dwFileSubtype; /* e.g. VFT2_DRV_KEYBOARD */
+ DWORD dwFileDateMS; /* e.g. 0 */
+ DWORD dwFileDateLS; /* e.g. 0 */
+} VS_FIXEDFILEINFO;
+
+/************** Byte swapping & unaligned access ******************/
+
+#include <pal_endian.h>
+
+/******************** external includes *************************/
+
+#include "ntimage.h"
+#ifndef PAL_STDCPP_COMPAT
+#include "cpp/ccombstr.h"
+#include "cpp/cstring.h"
+#endif // !PAL_STDCPP_COMPAT
+#include "sscli_version.h"
+
+#endif // RC_INVOKED
+
+#endif // __PALRT_H__
diff --git a/src/pal/inc/rt/poppack.h b/src/pal/inc/rt/poppack.h
new file mode 100644
index 0000000000..ef4e86b63f
--- /dev/null
+++ b/src/pal/inc/rt/poppack.h
@@ -0,0 +1,39 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+//
+// ===========================================================================
+// File: poppack.h
+//
+// ===========================================================================
+/*
+Abstract:
+
+ This file turns packing of structures off. (That is, it enables
+ automatic alignment of structure fields.) An include file is needed
+ because various compilers do this in different ways.
+
+ poppack.h is the complement to pshpack?.h. An inclusion of poppack.h
+ MUST ALWAYS be preceded by an inclusion of one of pshpack?.h, in one-to-one
+ correspondence.
+
+ For Microsoft compatible compilers, this file uses the pop option
+ to the pack pragma so that it can restore the previous saved by the
+ pshpack?.h include file.
+
+*/
+
+#if ! (defined(lint) || defined(RC_INVOKED))
+#if ( _MSC_VER >= 800 && !defined(_M_I86)) || defined(_PUSHPOP_SUPPORTED)
+#pragma warning(disable:4103)
+#if !(defined( MIDL_PASS )) || defined( __midl )
+#pragma pack(pop)
+#else
+#pragma pack()
+#endif
+#else
+#pragma pack()
+#endif
+#endif // ! (defined(lint) || defined(RC_INVOKED))
diff --git a/src/pal/inc/rt/process.h b/src/pal/inc/rt/process.h
new file mode 100644
index 0000000000..4dcfbe88bd
--- /dev/null
+++ b/src/pal/inc/rt/process.h
@@ -0,0 +1,13 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+//
+// ===========================================================================
+// File: process.h
+//
+// ===========================================================================
+// dummy process.h for PAL
+
+#include "palrt.h"
diff --git a/src/pal/inc/rt/psapi.h b/src/pal/inc/rt/psapi.h
new file mode 100644
index 0000000000..5401fabc13
--- /dev/null
+++ b/src/pal/inc/rt/psapi.h
@@ -0,0 +1,5 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#include "palrt.h"
diff --git a/src/pal/inc/rt/pshpack1.h b/src/pal/inc/rt/pshpack1.h
new file mode 100644
index 0000000000..f53472d720
--- /dev/null
+++ b/src/pal/inc/rt/pshpack1.h
@@ -0,0 +1,38 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+//
+// ===========================================================================
+// File: pshpack1.h
+//
+// ===========================================================================
+
+/*++
+
+Abstract:
+
+ This file turns 1 byte packing of structures on. (That is, it disables
+ automatic alignment of structure fields.) An include file is needed
+ because various compilers do this in different ways. For Microsoft
+ compatible compilers, this files uses the push option to the pack pragma
+ so that the poppack.h include file can restore the previous packing
+ reliably.
+
+ The file poppack.h is the complement to this file.
+
+--*/
+
+#if ! (defined(lint) || defined(RC_INVOKED))
+#if ( _MSC_VER >= 800 && !defined(_M_I86)) || defined(_PUSHPOP_SUPPORTED)
+#pragma warning(disable:4103)
+#if !(defined( MIDL_PASS )) || defined( __midl )
+#pragma pack(push,1)
+#else
+#pragma pack(1)
+#endif
+#else
+#pragma pack(1)
+#endif
+#endif // ! (defined(lint) || defined(RC_INVOKED))
diff --git a/src/pal/inc/rt/pshpack2.h b/src/pal/inc/rt/pshpack2.h
new file mode 100644
index 0000000000..bbeffac9ca
--- /dev/null
+++ b/src/pal/inc/rt/pshpack2.h
@@ -0,0 +1,37 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+//
+// ===========================================================================
+// File: pshpack2.h
+//
+// ===========================================================================
+/*++
+
+Abstract:
+
+ This file turns 2 byte packing of structures on. (That is, it disables
+ automatic alignment of structure fields.) An include file is needed
+ because various compilers do this in different ways. For Microsoft
+ compatible compilers, this files uses the push option to the pack pragma
+ so that the poppack.h include file can restore the previous packing
+ reliably.
+
+ The file poppack.h is the complement to this file.
+
+--*/
+
+#if ! (defined(lint) || defined(RC_INVOKED))
+#if ( _MSC_VER >= 800 && !defined(_M_I86)) || defined(_PUSHPOP_SUPPORTED)
+#pragma warning(disable:4103)
+#if !(defined( MIDL_PASS )) || defined( __midl )
+#pragma pack(push,2)
+#else
+#pragma pack(2)
+#endif
+#else
+#pragma pack(2)
+#endif
+#endif // ! (defined(lint) || defined(RC_INVOKED))
diff --git a/src/pal/inc/rt/pshpack4.h b/src/pal/inc/rt/pshpack4.h
new file mode 100644
index 0000000000..4431c9d393
--- /dev/null
+++ b/src/pal/inc/rt/pshpack4.h
@@ -0,0 +1,38 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+//
+// ===========================================================================
+// File: pshpack4.h
+//
+// ===========================================================================
+
+/*++
+
+Abstract:
+
+ This file turns 4 byte packing of structures on. (That is, it disables
+ automatic alignment of structure fields.) An include file is needed
+ because various compilers do this in different ways. For Microsoft
+ compatible compilers, this files uses the push option to the pack pragma
+ so that the poppack.h include file can restore the previous packing
+ reliably.
+
+ The file poppack.h is the complement to this file.
+
+--*/
+
+#if ! (defined(lint) || defined(RC_INVOKED))
+#if ( _MSC_VER >= 800 && !defined(_M_I86)) || defined(_PUSHPOP_SUPPORTED)
+#pragma warning(disable:4103)
+#if !(defined( MIDL_PASS )) || defined( __midl )
+#pragma pack(push,4)
+#else
+#pragma pack(4)
+#endif
+#else
+#pragma pack(4)
+#endif
+#endif // ! (defined(lint) || defined(RC_INVOKED))
diff --git a/src/pal/inc/rt/pshpack8.h b/src/pal/inc/rt/pshpack8.h
new file mode 100644
index 0000000000..b1377d3e00
--- /dev/null
+++ b/src/pal/inc/rt/pshpack8.h
@@ -0,0 +1,38 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+//
+// ===========================================================================
+// File: pshpack8.h
+//
+// ===========================================================================
+
+/*++
+
+Abstract:
+
+ This file turns 8 byte packing of structures on. (That is, it disables
+ automatic alignment of structure fields.) An include file is needed
+ because various compilers do this in different ways. For Microsoft
+ compatible compilers, this files uses the push option to the pack pragma
+ so that the poppack.h include file can restore the previous packing
+ reliably.
+
+ The file poppack.h is the complement to this file.
+
+--*/
+
+#if ! (defined(lint) || defined(RC_INVOKED))
+#if ( _MSC_VER >= 800 && !defined(_M_I86)) || defined(_PUSHPOP_SUPPORTED)
+#pragma warning(disable:4103)
+#if !(defined( MIDL_PASS )) || defined( __midl )
+#pragma pack(push,8)
+#else
+#pragma pack(8)
+#endif
+#else
+#pragma pack(8)
+#endif
+#endif // ! (defined(lint) || defined(RC_INVOKED))
diff --git a/src/pal/inc/rt/pshpck16.h b/src/pal/inc/rt/pshpck16.h
new file mode 100644
index 0000000000..bb4a0e1228
--- /dev/null
+++ b/src/pal/inc/rt/pshpck16.h
@@ -0,0 +1,38 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+//
+// ===========================================================================
+// File: pshpck16.h
+//
+// ===========================================================================
+
+/*++
+
+Abstract:
+
+ This file turns 16 byte packing of structures on. (That is, it disables
+ automatic alignment of structure fields.) An include file is needed
+ because various compilers do this in different ways. For Microsoft
+ compatible compilers, this files uses the push option to the pack pragma
+ so that the poppack.h include file can restore the previous packing
+ reliably.
+
+ The file poppack.h is the complement to this file.
+
+--*/
+
+#if ! (defined(lint) || defined(RC_INVOKED))
+#if ( _MSC_VER >= 800 && !defined(_M_I86)) || defined(_PUSHPOP_SUPPORTED)
+#pragma warning(disable:4103)
+#if !(defined( MIDL_PASS )) || defined( __midl )
+#pragma pack(push,16)
+#else
+#pragma pack(16)
+#endif
+#else
+#pragma pack(16)
+#endif
+#endif // ! (defined(lint) || defined(RC_INVOKED))
diff --git a/src/pal/inc/rt/richedit.h b/src/pal/inc/rt/richedit.h
new file mode 100644
index 0000000000..c3c5849669
--- /dev/null
+++ b/src/pal/inc/rt/richedit.h
@@ -0,0 +1,13 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+//
+// ===========================================================================
+// File: richedit.h
+//
+// ===========================================================================
+// dummy richedit.h for PAL
+
+#include "palrt.h"
diff --git a/src/pal/inc/rt/rpc.h b/src/pal/inc/rt/rpc.h
new file mode 100644
index 0000000000..e63e617da1
--- /dev/null
+++ b/src/pal/inc/rt/rpc.h
@@ -0,0 +1,34 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+//
+// ===========================================================================
+// File: rpc.h
+//
+// ===========================================================================
+// dummy rpc.h for PAL
+
+#ifndef __RPC_H__
+#define __RPC_H__
+
+#include "palrt.h"
+
+#define __RPC_STUB
+#define __RPC_USER
+#define __RPC_FAR
+
+#define DECLSPEC_UUID(x) __declspec(uuid(x))
+#define MIDL_INTERFACE(x) struct DECLSPEC_UUID(x) DECLSPEC_NOVTABLE
+
+#define EXTERN_GUID(itf,l1,s1,s2,c1,c2,c3,c4,c5,c6,c7,c8) \
+ EXTERN_C const IID DECLSPEC_SELECTANY itf = {l1,s1,s2,{c1,c2,c3,c4,c5,c6,c7,c8}}
+
+interface IRpcStubBuffer;
+interface IRpcChannelBuffer;
+
+typedef void* PRPC_MESSAGE;
+typedef void* RPC_IF_HANDLE;
+
+#endif // __RPC_H__
diff --git a/src/pal/inc/rt/rpcndr.h b/src/pal/inc/rt/rpcndr.h
new file mode 100644
index 0000000000..bf67d4cd57
--- /dev/null
+++ b/src/pal/inc/rt/rpcndr.h
@@ -0,0 +1,20 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+//
+// ===========================================================================
+// File: rpcndr.h
+//
+// ===========================================================================
+// dummy rpcndr.h for PAL
+
+#ifndef __RPCNDR_H__
+#define __RPCNDR_H__
+
+#ifndef __RPCNDR_H_VERSION__
+#define __RPCNDR_H_VERSION__
+#endif
+
+#endif // __RPCNDR_H__
diff --git a/src/pal/inc/rt/safecrt.h b/src/pal/inc/rt/safecrt.h
new file mode 100644
index 0000000000..6b95e28dfb
--- /dev/null
+++ b/src/pal/inc/rt/safecrt.h
@@ -0,0 +1,3381 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+//
+/***
+*safecrt.h - secure crt downlevel for windows build
+*
+*Purpose:
+* This file contains a subset of the Secure CRT. It is meant to
+* be used in the Windows source tree.
+*
+****/
+
+/* #pragma once */
+
+/* guard against other includes */
+#if !defined(_CRT_ALTERNATIVE_INLINES)
+#error "_CRT_ALTERNATIVE_INLINES needs to be defined to use safecrt.h. This will make sure the safecrt functions are not declared in the standard headers."
+#endif
+
+#if defined(_CRT_ALTERNATIVE_IMPORTED)
+#error "_CRT_ALTERNATIVE_IMPORTED is defined. This means some files were included with _CRT_ALTERNATIVE_INLINES undefined."
+#endif
+
+#if !defined(_INC_SAFECRT)
+#define _INC_SAFECRT
+
+#if !defined(_SAFECRT_NO_INCLUDES)
+#include <stdarg.h> /* for va_start, etc. */
+#endif
+
+/* _SAFECRT switches */
+#if !defined(_SAFECRT_USE_INLINES)
+#define _SAFECRT_USE_INLINES 0
+#endif
+
+#if !defined(_SAFECRT_SET_ERRNO)
+#define _SAFECRT_SET_ERRNO 1
+#endif
+
+#if !defined(_SAFECRT_DEFINE_TCS_MACROS)
+#define _SAFECRT_DEFINE_TCS_MACROS 0
+#endif
+
+#if !defined(_SAFECRT_DEFINE_MBS_FUNCTIONS)
+#define _SAFECRT_DEFINE_MBS_FUNCTIONS 1
+#endif
+
+#if !defined(_SAFECRT_USE_CPP_OVERLOADS)
+#define _SAFECRT_USE_CPP_OVERLOADS 0
+#endif
+
+#if !defined(_SAFECRT_FILL_BUFFER)
+#if defined(_DEBUG)
+#define _SAFECRT_FILL_BUFFER 1
+#else
+#define _SAFECRT_FILL_BUFFER 0
+#endif
+#endif
+
+#if !defined(_SAFECRT_FILL_BUFFER_PATTERN)
+#define _SAFECRT_FILL_BUFFER_PATTERN 0xFD
+#endif
+
+#if !defined(_SAFECRT_INVALID_PARAMETER_DEBUG_INFO)
+#define _SAFECRT_INVALID_PARAMETER_DEBUG_INFO 0
+#endif
+
+#if !defined(_SAFECRT_IMPL) && defined (_SAFECRT_USE_INLINES)
+#define _SAFECRT__INLINE __inline
+#else
+#define _SAFECRT__INLINE
+#endif
+
+/* additional includes */
+#if _SAFECRT_USE_INLINES && !defined(_SAFECRT_NO_INCLUDES)
+#include <stdlib.h> /* for _MAX_DRIVE */
+#include <string.h> /* for memset */
+#include <windows.h> /* for NTSTATUS, RaiseException */
+#if _SAFECRT_SET_ERRNO
+#include <errno.h>
+#endif
+#if _SAFECRT_DEFINE_MBS_FUNCTIONS
+#include <mbctype.h>
+#endif
+#endif
+
+/* NULL */
+#if !defined(NULL)
+#if !defined(__cplusplus)
+#define NULL 0
+#else
+#define NULL ((void *)0)
+#endif
+#endif
+
+/* WCHAR */
+#if defined (SAFECRT_INCLUDE_REDEFINES)
+#if !defined(_WCHAR_T_DEFINED)
+typedef unsigned short WCHAR;
+#define _WCHAR_T_DEFINED
+#endif
+#endif
+
+/* _W64 */
+#if !defined(_W64)
+#if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300
+#define _W64 __w64
+#else
+#define _W64
+#endif
+#endif
+
+/* size_t */
+#if defined (SAFECRT_INCLUDE_REDEFINES)
+#if !defined(_SIZE_T_DEFINED)
+#if defined(_WIN64)
+typedef unsigned __int64 size_t;
+#else
+typedef _W64 unsigned int size_t;
+#endif
+#define _SIZE_T_DEFINED
+#endif
+#endif
+
+/* uintptr_t */
+#if !defined(_UINTPTR_T_DEFINED)
+#if defined(_WIN64)
+typedef unsigned __int64 uintptr_t;
+#else
+typedef _W64 unsigned int uintptr_t;
+#endif
+#define _UINTPTR_T_DEFINED
+#endif
+
+#if defined(_MSC_VER) || (defined(__GNUC__) && (__GNUC__ >= 3))
+#define SAFECRT_DEPRECATED __declspec(deprecated)
+#else
+#define SAFECRT_DEPRECATED
+#endif
+
+/* errno_t */
+#if !defined(_ERRCODE_DEFINED)
+#define _ERRCODE_DEFINED
+/* errcode is deprecated in favor or errno_t, which is part of the standard proposal */
+SAFECRT_DEPRECATED typedef int errcode;
+typedef int errno_t; /* standard */
+#endif
+
+/* error codes */
+#if !defined(_SECURECRT_ERRCODE_VALUES_DEFINED)
+#define _SECURECRT_ERRCODE_VALUES_DEFINED
+#if !defined(EINVAL)
+#define EINVAL 22
+#endif
+#if !defined(ERANGE)
+#define ERANGE 34
+#endif
+#if !defined(EILSEQ)
+#define EILSEQ 42
+#endif
+#if !defined(STRUNCATE)
+#define STRUNCATE 80
+#endif
+#endif
+
+/* _TRUNCATE */
+#if !defined(_TRUNCATE)
+#define _TRUNCATE ((size_t)-1)
+#endif
+
+/* _SAFECRT_AUTOMATICALLY_REPLACED_CALL */
+#if !defined(_SAFECRT_AUTOMATICALLY_REPLACED_CALL)
+#define _SAFECRT_AUTOMATICALLY_REPLACED_CALL(v) (v)
+#endif
+
+/* internal macros */
+#if _SAFECRT_USE_INLINES
+#define _SAFECRT__EXTERN_C
+#else
+#if defined(__cplusplus)
+#define _SAFECRT__EXTERN_C extern "C"
+#else
+#define _SAFECRT__EXTERN_C extern
+#endif
+#endif /* _SAFECRT_USE_INLINES */
+
+#if !defined(_SAFECRT_IMPL)
+
+#define _SAFECRT__STR2WSTR(str) L##str
+
+#define _SAFECRT__STR2WSTR2(str) _SAFECRT__STR2WSTR(str)
+
+#if !defined(__FILEW__)
+#define __FILEW__ _SAFECRT__STR2WSTR2(__FILE__)
+#endif
+
+#if !defined(__FUNCTIONW__)
+#define __FUNCTIONW__ _SAFECRT__STR2WSTR2(__FUNCTION__)
+#endif
+
+#endif
+
+/* validation macros */
+#if !defined(_SAFECRT_INVALID_PARAMETER)
+#if _SAFECRT_INVALID_PARAMETER_DEBUG_INFO
+#define _SAFECRT_INVALID_PARAMETER(message) _invalid_parameter(message, __FUNCTIONW__, __FILEW__, __LINE__, 0)
+#else
+#define _SAFECRT_INVALID_PARAMETER(message) _invalid_parameter(nullptr, nullptr, nullptr, 0, 0)
+#endif
+#endif
+
+#if !defined(_SAFECRT__SET_ERRNO)
+#if _SAFECRT_SET_ERRNO
+#define _SAFECRT__SET_ERRNO(_ErrorCode) errno = (_ErrorCode)
+#else
+#define _SAFECRT__SET_ERRNO(_ErrorCode)
+#endif
+#endif
+
+#if !defined(_SAFECRT__RETURN_ERROR)
+#define _SAFECRT__RETURN_ERROR(_Msg, _Ret) \
+ _SAFECRT__SET_ERRNO(EINVAL); \
+ _SAFECRT_INVALID_PARAMETER(_Msg); \
+ return _Ret
+#endif
+
+#if !defined(_SAFECRT__VALIDATE_STRING_ERROR)
+#define _SAFECRT__VALIDATE_STRING_ERROR(_String, _Size, _Ret) \
+ if ((_String) == nullptr || (_Size) == 0) \
+ { \
+ _SAFECRT__SET_ERRNO(EINVAL); \
+ _SAFECRT_INVALID_PARAMETER(L"String " _SAFECRT__STR2WSTR(#_String) L" is invalid"); \
+ return _Ret; \
+ }
+#endif
+
+#if !defined(_SAFECRT__VALIDATE_STRING)
+#define _SAFECRT__VALIDATE_STRING(_String, _Size) _SAFECRT__VALIDATE_STRING_ERROR(_String, _Size, EINVAL)
+#endif
+
+#if !defined(_SAFECRT__VALIDATE_POINTER_ERROR_RETURN)
+#define _SAFECRT__VALIDATE_POINTER_ERROR_RETURN(_Pointer, _ErrorCode, _Ret) \
+ if ((_Pointer) == nullptr) \
+ { \
+ _SAFECRT__SET_ERRNO(_ErrorCode); \
+ _SAFECRT_INVALID_PARAMETER(L"Pointer " _SAFECRT__STR2WSTR(#_Pointer) L" is invalid"); \
+ return _Ret; \
+ }
+#endif
+
+#if !defined(_SAFECRT__VALIDATE_POINTER_ERROR)
+#define _SAFECRT__VALIDATE_POINTER_ERROR(_Pointer, _Ret) \
+ _SAFECRT__VALIDATE_POINTER_ERROR_RETURN(_Pointer, EINVAL, _Ret)
+#endif
+
+#if !defined(_SAFECRT__VALIDATE_POINTER)
+#define _SAFECRT__VALIDATE_POINTER(_Pointer) \
+ _SAFECRT__VALIDATE_POINTER_ERROR(_Pointer, EINVAL)
+#endif
+
+#if !defined(_SAFECRT__VALIDATE_POINTER_RESET_STRING_ERROR)
+#define _SAFECRT__VALIDATE_POINTER_RESET_STRING_ERROR(_Pointer, _String, _Size, _Ret) \
+ if ((_Pointer) == nullptr) \
+ { \
+ _SAFECRT__SET_ERRNO(EINVAL); \
+ _SAFECRT__RESET_STRING(_String, _Size); \
+ _SAFECRT_INVALID_PARAMETER(L"Pointer " _SAFECRT__STR2WSTR(#_Pointer) L" is invalid"); \
+ return _Ret; \
+ }
+#endif
+
+#if !defined(_SAFECRT__VALIDATE_POINTER_RESET_STRING)
+#define _SAFECRT__VALIDATE_POINTER_RESET_STRING(_Pointer, _String, _Size) \
+ _SAFECRT__VALIDATE_POINTER_RESET_STRING_ERROR(_Pointer, _String, _Size, EINVAL)
+#endif
+
+#if !defined(_SAFECRT__VALIDATE_CONDITION_ERROR_RETURN)
+#define _SAFECRT__VALIDATE_CONDITION_ERROR_RETURN(_Condition, _ErrorCode, _Ret) \
+ if (!(_Condition)) \
+ { \
+ _SAFECRT__SET_ERRNO(_ErrorCode); \
+ _SAFECRT_INVALID_PARAMETER(_SAFECRT__STR2WSTR(#_Condition)); \
+ return _Ret; \
+ }
+#endif
+
+#if !defined(_SAFECRT__VALIDATE_CONDITION_ERROR)
+#define _SAFECRT__VALIDATE_CONDITION_ERROR(_Condition, _Ret) \
+ _SAFECRT__VALIDATE_CONDITION_ERROR_RETURN(_Condition, EINVAL, _Ret)
+#endif
+
+/* if _SAFECRT_FILL_BUFFER is on, fill the interval [_Offset, _Size) with _SAFECRT_FILL_BUFFER_PATTERN;
+ * assume that the string has been validated with _SAFECRT__VALIDATE_STRING
+ */
+#if !defined(_SAFECRT__FILL_STRING)
+#if _SAFECRT_FILL_BUFFER
+#define _SAFECRT__FILL_STRING(_String, _Size, _Offset) \
+ if ((size_t)(_Offset) < (_Size)) \
+ { \
+ memset((_String) + (_Offset), _SAFECRT_FILL_BUFFER_PATTERN, ((_Size) - (_Offset)) * sizeof(*(_String))); \
+ }
+#else
+#define _SAFECRT__FILL_STRING(_String, _Size, _Offset)
+#endif
+#endif
+
+/* if _SAFECRT_FILL_BUFFER is on, set the byte to _SAFECRT_FILL_BUFFER_PATTERN
+ */
+#if !defined(_SAFECRT__FILL_BYTE)
+#if _SAFECRT_FILL_BUFFER
+#define _SAFECRT__FILL_BYTE(_Position) \
+ (_Position) = _SAFECRT_FILL_BUFFER_PATTERN
+#else
+#define _SAFECRT__FILL_BYTE(_Position)
+#endif
+#endif
+
+/* put a null terminator at the beginning of the string and then calls _SAFECRT__FILL_STRING;
+ * assume that the string has been validated with _SAFECRT__VALIDATE_STRING
+ */
+#if !defined(_SAFECRT__RESET_STRING)
+#define _SAFECRT__RESET_STRING(_String, _Size) \
+ *(_String) = 0; \
+ _SAFECRT__FILL_STRING(_String, _Size, 1);
+#endif
+
+#if !defined(_SAFECRT__RETURN_BUFFER_TOO_SMALL_ERROR)
+#define _SAFECRT__RETURN_BUFFER_TOO_SMALL_ERROR(_String, _Size, _Ret) \
+ _SAFECRT__SET_ERRNO(ERANGE); \
+ _SAFECRT_INVALID_PARAMETER(L"Buffer " _SAFECRT__STR2WSTR(#_String) L" is too small"); \
+ return _Ret;
+#endif
+
+#if !defined(_SAFECRT__RETURN_BUFFER_TOO_SMALL)
+#define _SAFECRT__RETURN_BUFFER_TOO_SMALL(_String, _Size) \
+ _SAFECRT__RETURN_BUFFER_TOO_SMALL_ERROR(_String, _Size, ERANGE)
+#endif
+
+#if !defined(_SAFECRT__RETURN_DEST_NOT_NULL_TERMINATED)
+#define _SAFECRT__RETURN_DEST_NOT_NULL_TERMINATED(_String, _Size) \
+ _SAFECRT__SET_ERRNO(EINVAL); \
+ _SAFECRT_INVALID_PARAMETER(L"String " _SAFECRT__STR2WSTR(#_String) L" is not terminated"); \
+ return EINVAL;
+#endif
+
+#if !defined(_SAFECRT__RETURN_EINVAL)
+#define _SAFECRT__RETURN_EINVAL \
+ _SAFECRT__SET_ERRNO(EINVAL); \
+ _SAFECRT_INVALID_PARAMETER(L"Invalid parameter"); \
+ return EINVAL;
+#endif
+
+/* MBCS handling: change these definitions if you do not need to support mbcs strings */
+#if !defined(_SAFECRT__ISMBBLEAD)
+#define _SAFECRT__ISMBBLEAD(_Character) \
+ _ismbblead(_Character)
+#endif
+
+#if !defined(_SAFECRT__MBSDEC)
+#define _SAFECRT__MBSDEC(_String, _Current) \
+ _mbsdec(_String, _Current)
+#endif
+
+_SAFECRT__EXTERN_C
+void __cdecl _invalid_parameter(const WCHAR *_Message, const WCHAR *_FunctionName, const WCHAR *_FileName, unsigned int _LineNumber, uintptr_t _Reserved);
+
+#if (_SAFECRT_USE_INLINES || _SAFECRT_IMPL) && !defined(_SAFECRT_DO_NOT_DEFINE_INVALID_PARAMETER)
+
+#ifndef STATUS_INVALID_PARAMETER
+#if defined (SAFECRT_INCLUDE_REDEFINES)
+typedef LONG NTSTATUS;
+#endif
+#define STATUS_INVALID_PARAMETER ((NTSTATUS)0xC000000DL)
+#endif
+
+_SAFECRT__INLINE
+void __cdecl _invalid_parameter(const WCHAR *_Message, const WCHAR *_FunctionName, const WCHAR *_FileName, unsigned int _LineNumber, uintptr_t _Reserved)
+{
+#ifdef _MSC_VER
+ (_Message);
+ (_FunctionName);
+ (_FileName);
+ (_LineNumber);
+ (_Reserved);
+#endif
+ /* invoke Watson */
+ RaiseException((DWORD)STATUS_INVALID_PARAMETER, 0, 0, nullptr);
+}
+
+#endif
+
+//#if !defined(_SAFECRT_IMPL)
+
+#if _SAFECRT_DEFINE_TCS_MACROS
+
+/* _tcs macros */
+#if !defined(_UNICODE) && !defined(UNICODE) && !defined(_MBCS)
+
+#define _tcscpy_s strcpy_s
+#define _tcsncpy_s strncpy_s
+#define _tcscat_s strcat_s
+#define _tcsncat_s strncat_s
+#define _tcsset_s _strset_s
+#define _tcsnset_s _strnset_s
+#define _tcstok_s strtok_s
+#define _tmakepath_s _makepath_s
+#define _tsplitpath_s _splitpath_s
+#define _stprintf_s sprintf_s
+#define _vstprintf_s vsprintf_s
+#define _sntprintf_s _snprintf_s
+#define _vsntprintf_s _vsnprintf_s
+#define _tscanf_s scanf_s
+#define _tsscanf_s sscanf_s
+#define _tsnscanf_s _snscanf_s
+
+#elif defined(_UNICODE) || defined(UNICODE)
+
+#define _tcscpy_s wcscpy_s
+#define _tcsncpy_s wcsncpy_s
+#define _tcscat_s wcscat_s
+#define _tcsncat_s wcsncat_s
+#define _tcsset_s _wcsset_s
+#define _tcsnset_s _wcsnset_s
+#define _tcstok_s wcstok_s
+#define _tmakepath_s _wmakepath_s
+#define _tsplitpath_s _wsplitpath_s
+#define _stprintf_s swprintf_s
+#define _vstprintf_s vswprintf_s
+#define _sntprintf_s _snwprintf_s
+#define _vsntprintf_s _vsnwprintf_s
+#define _tscanf_s wscanf_s
+#define _tsscanf_s swscanf_s
+#define _tsnscanf_s _swnscanf_s
+
+#elif defined(_MBCS)
+
+#define _tcscpy_s _mbscpy_s
+#define _tcsncpy_s _mbsnbcpy_s
+#define _tcscat_s _mbscat_s
+#define _tcsncat_s _mbsnbcat_s
+#define _tcsset_s _mbsset_s
+#define _tcsnset_s _mbsnbset_s
+#define _tcstok_s _mbstok_s
+#define _tmakepath_s _makepath_s
+#define _tsplitpath_s _splitpath_s
+#define _stprintf_s sprintf_s
+#define _vstprintf_s vsprintf_s
+#define _sntprintf_s _snprintf_s
+#define _vsntprintf_s _vsnprintf_s
+#define _tscanf_s scanf_s
+#define _tsscanf_s sscanf_s
+#define _tsnscanf_s _snscanf_s
+
+#else
+
+#error We should not get here...
+
+#endif
+
+#endif /* _SAFECRT_DEFINE_TCS_MACROS */
+
+/* strcpy_s */
+/*
+ * strcpy_s, wcscpy_s copy string _Src into _Dst;
+ * will call _SAFECRT_INVALID_PARAMETER if string _Src does not fit into _Dst
+ */
+
+
+_SAFECRT__EXTERN_C
+errno_t __cdecl strcpy_s(char *_Dst, size_t _SizeInBytes, const char *_Src);
+
+#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS
+template <size_t _SizeInBytes>
+inline
+errno_t __cdecl strcpy_s(char (&_Dst)[_SizeInBytes], const char *_Src)
+{
+ return strcpy_s(_Dst, _SizeInBytes, _Src);
+}
+#endif
+
+
+#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL
+
+
+_SAFECRT__INLINE
+errno_t __cdecl strcpy_s(char *_Dst, size_t _SizeInBytes, const char *_Src)
+{
+
+ char *p;
+ size_t available;
+
+ /* validation section */
+ _SAFECRT__VALIDATE_STRING(_Dst, _SizeInBytes);
+ _SAFECRT__VALIDATE_POINTER_RESET_STRING(_Src, _Dst, _SizeInBytes);
+
+ p = _Dst;
+ available = _SizeInBytes;
+ while ((*p++ = *_Src++) != 0 && --available > 0)
+ {
+ }
+
+ if (available == 0)
+ {
+ _SAFECRT__RESET_STRING(_Dst, _SizeInBytes);
+ _SAFECRT__RETURN_BUFFER_TOO_SMALL(_Dst, _SizeInBytes);
+ }
+
+ _SAFECRT__FILL_STRING(_Dst, _SizeInBytes, _SizeInBytes - available + 1);
+ return 0;
+}
+
+#endif
+
+/* wcscpy_s */
+_SAFECRT__EXTERN_C
+errno_t __cdecl wcscpy_s(WCHAR *_Dst, size_t _SizeInWords, const WCHAR *_Src);
+
+#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS
+template <size_t _SizeInWords>
+inline
+errno_t __cdecl wcscpy_s(WCHAR (&_Dst)[_SizeInWords], const WCHAR *_Src)
+{
+ return wcscpy_s(_Dst, _SizeInWords, _Src);
+}
+#endif
+
+#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL
+
+_SAFECRT__INLINE
+errno_t __cdecl wcscpy_s(WCHAR *_Dst, size_t _SizeInWords, const WCHAR *_Src)
+{
+ WCHAR *p;
+ size_t available;
+
+ /* validation section */
+ _SAFECRT__VALIDATE_STRING(_Dst, _SizeInWords);
+ _SAFECRT__VALIDATE_POINTER_RESET_STRING(_Src, _Dst, _SizeInWords);
+
+ p = _Dst;
+ available = _SizeInWords;
+ while ((*p++ = *_Src++) != 0 && --available > 0)
+ {
+ }
+
+ if (available == 0)
+ {
+ _SAFECRT__RESET_STRING(_Dst, _SizeInWords);
+ _SAFECRT__RETURN_BUFFER_TOO_SMALL(_Dst, _SizeInWords);
+ }
+ _SAFECRT__FILL_STRING(_Dst, _SizeInWords, _SizeInWords - available + 1);
+ return 0;
+}
+
+#endif
+
+/* _mbscpy_s */
+#if _SAFECRT_DEFINE_MBS_FUNCTIONS
+
+_SAFECRT__EXTERN_C
+errno_t __cdecl _mbscpy_s(unsigned char *_Dst, size_t _SizeInBytes, const unsigned char *_Src);
+
+#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS
+template <size_t _SizeInBytes>
+inline
+errno_t __cdecl _mbscpy_s(unsigned char (&_Dst)[_SizeInBytes], const unsigned char *_Src)
+{
+ return _mbscpy_s(_Dst, _SizeInBytes, _Src);
+}
+#endif
+
+#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL
+
+_SAFECRT__INLINE
+errno_t __cdecl _mbscpy_s(unsigned char *_Dst, size_t _SizeInBytes, const unsigned char *_Src)
+{
+ unsigned char *p;
+ size_t available;
+
+ /* validation section */
+ _SAFECRT__VALIDATE_STRING(_Dst, _SizeInBytes);
+ _SAFECRT__VALIDATE_POINTER_RESET_STRING(_Src, _Dst, _SizeInBytes);
+
+ p = _Dst;
+ available = _SizeInBytes;
+ while ((*p++ = *_Src++) != 0 && --available > 0)
+ {
+ }
+
+ if (available == 0)
+ {
+ if (*_Src == 0 && _SAFECRT__ISMBBLEAD(p[-1]))
+ {
+ /* the source string ended with a lead byte: we remove it */
+ p[-1] = 0;
+ return 0;
+ }
+ _SAFECRT__RESET_STRING(_Dst, _SizeInBytes);
+ _SAFECRT__RETURN_BUFFER_TOO_SMALL(_Dst, _SizeInBytes);
+ }
+ if (available < _SizeInBytes && _SAFECRT__ISMBBLEAD(p[-2]))
+ {
+ /* the source string ended with a lead byte: we remove it */
+ p[-2] = 0;
+ available++;
+ }
+ _SAFECRT__FILL_STRING(_Dst, _SizeInBytes, _SizeInBytes - available + 1);
+ return 0;
+}
+
+#endif
+
+#endif /* _SAFECRT_DEFINE_MBS_FUNCTIONS */
+
+/* strncpy_s */
+/*
+ * strncpy_s, wcsncpy_s copy at max _Count characters from string _Src into _Dst;
+ * string _Dst will always be null-terminated;
+ * will call _SAFECRT_INVALID_PARAMETER if there is not enough space in _Dst;
+ * if _Count == _TRUNCATE, we will copy as many characters as we can from _Src into _Dst, and
+ * return STRUNCATE if _Src does not entirely fit into _Dst (we will not call _SAFECRT_INVALID_PARAMETER);
+ * if _Count == 0, then (_Dst == nullptr && _SizeInBytes == 0) is allowed
+ */
+_SAFECRT__EXTERN_C
+errno_t __cdecl strncpy_s(char *_Dst, size_t _SizeInBytes, const char *_Src, size_t _Count);
+
+#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS
+template <size_t _SizeInBytes>
+inline
+errno_t __cdecl strncpy_s(char (&_Dst)[_SizeInBytes], const char *_Src, size_t _Count)
+{
+ return strncpy_s(_Dst, _SizeInBytes, _Src, _Count);
+}
+#endif
+
+#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL
+
+_SAFECRT__INLINE
+errno_t __cdecl strncpy_s(char *_Dst, size_t _SizeInBytes, const char *_Src, size_t _Count)
+{
+ char *p;
+ size_t available;
+
+ if (_Count == 0 && _Dst == nullptr && _SizeInBytes == 0)
+ {
+ /* this case is allowed; nothing to do */
+ return 0;
+ }
+
+ /* validation section */
+ _SAFECRT__VALIDATE_STRING(_Dst, _SizeInBytes);
+ if (_Count == 0)
+ {
+ /* notice that the source string pointer can be nullptr in this case */
+ _SAFECRT__RESET_STRING(_Dst, _SizeInBytes);
+ return 0;
+ }
+ _SAFECRT__VALIDATE_POINTER_RESET_STRING(_Src, _Dst, _SizeInBytes);
+
+ p = _Dst;
+ available = _SizeInBytes;
+ if (_Count == _TRUNCATE)
+ {
+ while ((*p++ = *_Src++) != 0 && --available > 0)
+ {
+ }
+ }
+ else
+ {
+ while ((*p++ = *_Src++) != 0 && --available > 0 && --_Count > 0)
+ {
+ }
+ if (_Count == 0)
+ {
+ *p = 0;
+ }
+ }
+
+ if (available == 0)
+ {
+ if (_Count == _TRUNCATE)
+ {
+ _Dst[_SizeInBytes - 1] = 0;
+ return STRUNCATE;
+ }
+ _SAFECRT__RESET_STRING(_Dst, _SizeInBytes);
+ _SAFECRT__RETURN_BUFFER_TOO_SMALL(_Dst, _SizeInBytes);
+ }
+ _SAFECRT__FILL_STRING(_Dst, _SizeInBytes, _SizeInBytes - available + 1);
+ return 0;
+}
+
+#endif
+
+/* wcsncpy_s */
+_SAFECRT__EXTERN_C
+errno_t __cdecl wcsncpy_s(WCHAR *_Dst, size_t _SizeInWords, const WCHAR *_Src, size_t _Count);
+
+#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS
+template <size_t _SizeInWords>
+inline
+errno_t __cdecl wcsncpy_s(WCHAR (&_Dst)[_SizeInWords], const WCHAR *_Src, size_t _Count)
+{
+ return wcsncpy_s(_Dst, _SizeInWords, _Src, _Count);
+}
+#endif
+
+#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL
+
+_SAFECRT__INLINE
+errno_t __cdecl wcsncpy_s(WCHAR *_Dst, size_t _SizeInWords, const WCHAR *_Src, size_t _Count)
+{
+ WCHAR *p;
+ size_t available;
+
+ if (_Count == 0 && _Dst == nullptr && _SizeInWords == 0)
+ {
+ /* this case is allowed; nothing to do */
+ return 0;
+ }
+
+ /* validation section */
+ _SAFECRT__VALIDATE_STRING(_Dst, _SizeInWords);
+ if (_Count == 0)
+ {
+ /* notice that the source string pointer can be nullptr in this case */
+ _SAFECRT__RESET_STRING(_Dst, _SizeInWords);
+ return 0;
+ }
+ _SAFECRT__VALIDATE_POINTER_RESET_STRING(_Src, _Dst, _SizeInWords);
+
+ p = _Dst;
+ available = _SizeInWords;
+ if (_Count == _TRUNCATE)
+ {
+ while ((*p++ = *_Src++) != 0 && --available > 0)
+ {
+ }
+ }
+ else
+ {
+ while ((*p++ = *_Src++) != 0 && --available > 0 && --_Count > 0)
+ {
+ }
+ if (_Count == 0)
+ {
+ *p = 0;
+ }
+ }
+
+ if (available == 0)
+ {
+ if (_Count == _TRUNCATE)
+ {
+ _Dst[_SizeInWords - 1] = 0;
+ return STRUNCATE;
+ }
+ _SAFECRT__RESET_STRING(_Dst, _SizeInWords);
+ _SAFECRT__RETURN_BUFFER_TOO_SMALL(_Dst, _SizeInWords);
+ }
+ _SAFECRT__FILL_STRING(_Dst, _SizeInWords, _SizeInWords - available + 1);
+ return 0;
+}
+
+#endif
+
+/* _mbsnbcpy_s */
+#if _SAFECRT_DEFINE_MBS_FUNCTIONS
+
+_SAFECRT__EXTERN_C
+errno_t __cdecl _mbsnbcpy_s(unsigned char *_Dst, size_t _SizeInBytes, const unsigned char *_Src, size_t _CountInBytes);
+
+#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS
+template <size_t _SizeInBytes>
+inline
+errno_t __cdecl _mbsnbcpy_s(unsigned char (&_Dst)[_SizeInBytes], const unsigned char *_Src, size_t _CountInBytes)
+{
+ return _mbsnbcpy_s(_Dst, _SizeInBytes, _Src, _CountInBytes);
+}
+#endif
+
+#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL
+
+_SAFECRT__INLINE
+errno_t __cdecl _mbsnbcpy_s(unsigned char *_Dst, size_t _SizeInBytes, const unsigned char *_Src, size_t _CountInBytes)
+{
+ unsigned char *p;
+ size_t available;
+
+ if (_CountInBytes == 0 && _Dst == nullptr && _SizeInBytes == 0)
+ {
+ /* this case is allowed; nothing to do */
+ return 0;
+ }
+
+ /* validation section */
+ _SAFECRT__VALIDATE_STRING(_Dst, _SizeInBytes);
+ if (_CountInBytes == 0)
+ {
+ /* notice that the source string pointer can be nullptr in this case */
+ _SAFECRT__RESET_STRING(_Dst, _SizeInBytes);
+ return 0;
+ }
+ _SAFECRT__VALIDATE_POINTER_RESET_STRING(_Src, _Dst, _SizeInBytes);
+
+ p = _Dst;
+ available = _SizeInBytes;
+ if (_CountInBytes == _TRUNCATE)
+ {
+ while ((*p++ = *_Src++) != 0 && --available > 0)
+ {
+ }
+ }
+ else
+ {
+ while ((*p++ = *_Src++) != 0 && --available > 0 && --_CountInBytes > 0)
+ {
+ }
+ if (_CountInBytes == 0)
+ {
+ *p++ = 0;
+ }
+ }
+
+ if (available == 0)
+ {
+ if ((*_Src == 0 || _CountInBytes == 1) && _SAFECRT__ISMBBLEAD(p[-1]))
+ {
+ /* the source string ended with a lead byte: we remove it */
+ p[-1] = 0;
+ return 0;
+ }
+ if (_CountInBytes == _TRUNCATE)
+ {
+ if (_SizeInBytes > 1 && _SAFECRT__ISMBBLEAD(_Dst[_SizeInBytes - 2]))
+ {
+ _Dst[_SizeInBytes - 2] = 0;
+ _SAFECRT__FILL_BYTE(_Dst[_SizeInBytes - 1]);
+ }
+ else
+ {
+ _Dst[_SizeInBytes - 1] = 0;
+ }
+ return STRUNCATE;
+ }
+ _SAFECRT__RESET_STRING(_Dst, _SizeInBytes);
+ _SAFECRT__RETURN_BUFFER_TOO_SMALL(_Dst, _SizeInBytes);
+ }
+ if (available < _SizeInBytes && _SAFECRT__ISMBBLEAD(p[-2]))
+ {
+ /* the source string ended with a lead byte: we remove it */
+ p[-2] = 0;
+ available++;
+ }
+ _SAFECRT__FILL_STRING(_Dst, _SizeInBytes, _SizeInBytes - available + 1);
+ return 0;
+}
+
+#endif
+
+#endif /* _SAFECRT_DEFINE_MBS_FUNCTIONS */
+
+/* _mbsncpy_s */
+#if _SAFECRT_DEFINE_MBS_FUNCTIONS
+
+_SAFECRT__EXTERN_C
+errno_t __cdecl _mbsncpy_s(unsigned char *_Dst, size_t _SizeInBytes, const unsigned char *_Src, size_t _CountInChars);
+
+#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS
+template <size_t _SizeInBytes>
+inline
+errno_t __cdecl _mbsncpy_s(unsigned char (&_Dst)[_SizeInBytes], const unsigned char *_Src, size_t _CountInChars)
+{
+ return _mbsncpy_s(_Dst, _SizeInBytes, _Src, _CountInChars);
+}
+#endif
+
+#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL
+
+_SAFECRT__INLINE
+errno_t __cdecl _mbsncpy_s(unsigned char *_Dst, size_t _SizeInBytes, const unsigned char *_Src, size_t _CountInChars)
+{
+ unsigned char *p;
+ size_t available;
+
+ if (_CountInChars == 0 && _Dst == nullptr && _SizeInBytes == 0)
+ {
+ /* this case is allowed; nothing to do */
+ return 0;
+ }
+
+ /* validation section */
+ _SAFECRT__VALIDATE_STRING(_Dst, _SizeInBytes);
+ if (_CountInChars == 0)
+ {
+ /* notice that the source string pointer can be nullptr in this case */
+ _SAFECRT__RESET_STRING(_Dst, _SizeInBytes);
+ return 0;
+ }
+ _SAFECRT__VALIDATE_POINTER_RESET_STRING(_Src, _Dst, _SizeInBytes);
+
+ p = _Dst;
+ available = _SizeInBytes;
+ if (_CountInChars == _TRUNCATE)
+ {
+ while ((*p++ = *_Src++) != 0 && --available > 0)
+ {
+ }
+ }
+ else
+ {
+ do
+ {
+ if (_SAFECRT__ISMBBLEAD(*_Src))
+ {
+ if (_Src[1] == 0)
+ {
+ /* the source string ended with a lead byte: we remove it */
+ *p = 0;
+ break;
+ }
+ if (available <= 2)
+ {
+ /* not enough space */
+ available = 0;
+ break;
+ }
+ *p++ = *_Src++;
+ *p++ = *_Src++;
+ available -= 2;
+ }
+ else
+ {
+ if ((*p++ = *_Src++) == 0 || --available == 0)
+ {
+ break;
+ }
+ }
+ }
+ while (--_CountInChars > 0);
+ if (_CountInChars == 0)
+ {
+ *p++ = 0;
+ }
+ }
+
+ if (available == 0)
+ {
+ if (_CountInChars == _TRUNCATE)
+ {
+ if (_SizeInBytes > 1 && _SAFECRT__ISMBBLEAD(_Dst[_SizeInBytes - 2]))
+ {
+ _Dst[_SizeInBytes - 2] = 0;
+ _SAFECRT__FILL_BYTE(_Dst[_SizeInBytes - 1]);
+ }
+ else
+ {
+ _Dst[_SizeInBytes - 1] = 0;
+ }
+ return STRUNCATE;
+ }
+ _SAFECRT__RESET_STRING(_Dst, _SizeInBytes);
+ _SAFECRT__RETURN_BUFFER_TOO_SMALL(_Dst, _SizeInBytes);
+ }
+ _SAFECRT__FILL_STRING(_Dst, _SizeInBytes, _SizeInBytes - available + 1);
+ return 0;
+}
+
+#endif
+
+#endif /* _SAFECRT_DEFINE_MBS_FUNCTIONS */
+
+/* strcat_s */
+/*
+ * strcat_s, wcscat_s append string _Src to _Dst;
+ * will call _SAFECRT_INVALID_PARAMETER if there is not enough space in _Dst
+ */
+_SAFECRT__EXTERN_C
+errno_t __cdecl strcat_s(char *_Dst, size_t _SizeInBytes, const char *_Src);
+
+#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS
+template <size_t _SizeInBytes>
+inline
+errno_t __cdecl strcat_s(char (&_Dst)[_SizeInBytes], const char *_Src)
+{
+ return strcat_s(_Dst, _SizeInBytes, _Src);
+}
+#endif
+
+#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL
+
+_SAFECRT__INLINE
+errno_t __cdecl strcat_s(char *_Dst, size_t _SizeInBytes, const char *_Src)
+{
+ char *p;
+ size_t available;
+
+ /* validation section */
+ _SAFECRT__VALIDATE_STRING(_Dst, _SizeInBytes);
+ _SAFECRT__VALIDATE_POINTER_RESET_STRING(_Src, _Dst, _SizeInBytes);
+
+ p = _Dst;
+ available = _SizeInBytes;
+ while (available > 0 && *p != 0)
+ {
+ p++;
+ available--;
+ }
+
+ if (available == 0)
+ {
+ _SAFECRT__RESET_STRING(_Dst, _SizeInBytes);
+ _SAFECRT__RETURN_DEST_NOT_NULL_TERMINATED(_Dst, _SizeInBytes);
+ }
+
+ while ((*p++ = *_Src++) != 0 && --available > 0)
+ {
+ }
+
+ if (available == 0)
+ {
+ _SAFECRT__RESET_STRING(_Dst, _SizeInBytes);
+ _SAFECRT__RETURN_BUFFER_TOO_SMALL(_Dst, _SizeInBytes);
+ }
+ _SAFECRT__FILL_STRING(_Dst, _SizeInBytes, _SizeInBytes - available + 1);
+ return 0;
+}
+
+#endif
+
+/* wcscat_s */
+_SAFECRT__EXTERN_C
+errno_t __cdecl wcscat_s(WCHAR *_Dst, size_t _SizeInWords, const WCHAR *_Src);
+
+#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS
+template <size_t _SizeInWords>
+inline
+errno_t __cdecl wcscat_s(WCHAR (&_Dst)[_SizeInWords], const WCHAR *_Src)
+{
+ return wcscat_s(_Dst, _SizeInWords, _Src);
+}
+#endif
+
+#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL
+
+_SAFECRT__INLINE
+errno_t __cdecl wcscat_s(WCHAR *_Dst, size_t _SizeInWords, const WCHAR *_Src)
+{
+ WCHAR *p;
+ size_t available;
+
+ /* validation section */
+ _SAFECRT__VALIDATE_STRING(_Dst, _SizeInWords);
+ _SAFECRT__VALIDATE_POINTER_RESET_STRING(_Src, _Dst, _SizeInWords);
+
+ p = _Dst;
+ available = _SizeInWords;
+ while (available > 0 && *p != 0)
+ {
+ p++;
+ available--;
+ }
+
+ if (available == 0)
+ {
+ _SAFECRT__RESET_STRING(_Dst, _SizeInWords);
+ _SAFECRT__RETURN_DEST_NOT_NULL_TERMINATED(_Dst, _SizeInWords);
+ }
+
+ while ((*p++ = *_Src++) != 0 && --available > 0)
+ {
+ }
+
+ if (available == 0)
+ {
+ _SAFECRT__RESET_STRING(_Dst, _SizeInWords);
+ _SAFECRT__RETURN_BUFFER_TOO_SMALL(_Dst, _SizeInWords);
+ }
+ _SAFECRT__FILL_STRING(_Dst, _SizeInWords, _SizeInWords - available + 1);
+ return 0;
+}
+
+#endif
+
+/* _mbscat_s */
+#if _SAFECRT_DEFINE_MBS_FUNCTIONS
+
+_SAFECRT__EXTERN_C
+errno_t __cdecl _mbscat_s(unsigned char *_Dst, size_t _SizeInBytes, const unsigned char *_Src);
+
+#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS
+template <size_t _SizeInBytes>
+inline
+errno_t __cdecl _mbscat_s(unsigned char (&_Dst)[_SizeInBytes], const unsigned char *_Src)
+{
+ return _mbscat_s(_Dst, _SizeInBytes, _Src);
+}
+#endif
+
+#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL
+
+_SAFECRT__INLINE
+errno_t __cdecl _mbscat_s(unsigned char *_Dst, size_t _SizeInBytes, const unsigned char *_Src)
+{
+ unsigned char *p;
+ size_t available;
+
+ /* validation section */
+ _SAFECRT__VALIDATE_STRING(_Dst, _SizeInBytes);
+ _SAFECRT__VALIDATE_POINTER_RESET_STRING(_Src, _Dst, _SizeInBytes);
+
+ p = _Dst;
+ available = _SizeInBytes;
+ while (available > 0 && *p != 0)
+ {
+ p++;
+ available--;
+ }
+
+ if (available == 0)
+ {
+ if (*p == 0 && _SAFECRT__ISMBBLEAD(p[-1]))
+ {
+ /* the original string ended with a lead byte: we remove it */
+ p--;
+ *p = 0;
+ available = 1;
+ }
+ else
+ {
+ _SAFECRT__RESET_STRING(_Dst, _SizeInBytes);
+ _SAFECRT__RETURN_DEST_NOT_NULL_TERMINATED(_Dst, _SizeInBytes);
+ }
+ }
+ if (available < _SizeInBytes && _SAFECRT__ISMBBLEAD(p[-1]))
+ {
+ /* the original string ended with a lead byte: we remove it */
+ p--;
+ *p = 0;
+ available++;
+ }
+
+ while ((*p++ = *_Src++) != 0 && --available > 0)
+ {
+ }
+
+ if (available == 0)
+ {
+ if (*_Src == 0 && _SAFECRT__ISMBBLEAD(p[-1]))
+ {
+ /* the source string ended with a lead byte: we remove it */
+ p[-1] = 0;
+ return 0;
+ }
+ _SAFECRT__RESET_STRING(_Dst, _SizeInBytes);
+ _SAFECRT__RETURN_BUFFER_TOO_SMALL(_Dst, _SizeInBytes);
+ }
+ if (available < _SizeInBytes && _SAFECRT__ISMBBLEAD(p[-2]))
+ {
+ /* the source string ended with a lead byte: we remove it */
+ p[-2] = 0;
+ available++;
+ }
+ _SAFECRT__FILL_STRING(_Dst, _SizeInBytes, _SizeInBytes - available + 1);
+ return 0;
+}
+
+#endif
+
+#endif /* _SAFECRT_DEFINE_MBS_FUNCTIONS */
+
+/* strncat_s */
+/*
+ * strncat_s, wcsncat_s append at max _Count characters from string _Src to _Dst;
+ * string _Dst will always be null-terminated;
+ * will call _SAFECRT_INVALID_PARAMETER if there is not enough space in _Dst;
+ * if _Count == _TRUNCATE, we will append as many characters as we can from _Src to _Dst, and
+ * return STRUNCATE if _Src does not entirely fit into _Dst (we will not call _SAFECRT_INVALID_PARAMETER);
+ * if _Count == 0, then (_Dst == nullptr && _SizeInBytes == 0) is allowed
+ */
+_SAFECRT__EXTERN_C
+errno_t __cdecl strncat_s(char *_Dst, size_t _SizeInBytes, const char *_Src, size_t _Count);
+
+#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS
+template <size_t _SizeInBytes>
+inline
+errno_t __cdecl strncat_s(char (&_Dst)[_SizeInBytes], const char *_Src, size_t _Count)
+{
+ return strncat_s(_Dst, _SizeInBytes, _Src, _Count);
+}
+#endif
+
+#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL
+
+_SAFECRT__INLINE
+errno_t __cdecl strncat_s(char *_Dst, size_t _SizeInBytes, const char *_Src, size_t _Count)
+{
+ char *p;
+ size_t available;
+ if (_Count == 0 && _Dst == nullptr && _SizeInBytes == 0)
+ {
+ /* this case is allowed; nothing to do */
+ return 0;
+ }
+ /* validation section */
+ _SAFECRT__VALIDATE_STRING(_Dst, _SizeInBytes);
+ if (_Count != 0)
+ {
+ _SAFECRT__VALIDATE_POINTER_RESET_STRING(_Src, _Dst, _SizeInBytes);
+ }
+
+ p = _Dst;
+ available = _SizeInBytes;
+ while (available > 0 && *p != 0)
+ {
+ p++;
+ available--;
+ }
+
+ if (available == 0)
+ {
+ _SAFECRT__RESET_STRING(_Dst, _SizeInBytes);
+ _SAFECRT__RETURN_DEST_NOT_NULL_TERMINATED(_Dst, _SizeInBytes);
+ }
+
+ if (_Count == _TRUNCATE)
+ {
+ while ((*p++ = *_Src++) != 0 && --available > 0)
+ {
+ }
+ }
+ else
+ {
+ while (_Count > 0 && (*p++ = *_Src++) != 0 && --available > 0)
+ {
+ _Count--;
+ }
+ if (_Count == 0)
+ {
+ *p = 0;
+ }
+ }
+
+ if (available == 0)
+ {
+ if (_Count == _TRUNCATE)
+ {
+ _Dst[_SizeInBytes - 1] = 0;
+ return STRUNCATE;
+ }
+ _SAFECRT__RESET_STRING(_Dst, _SizeInBytes);
+ _SAFECRT__RETURN_BUFFER_TOO_SMALL(_Dst, _SizeInBytes);
+ }
+ _SAFECRT__FILL_STRING(_Dst, _SizeInBytes, _SizeInBytes - available + 1);
+ return 0;
+}
+
+#endif
+
+/* wcsncat_s */
+_SAFECRT__EXTERN_C
+errno_t __cdecl wcsncat_s(WCHAR *_Dst, size_t _SizeInWords, const WCHAR *_Src, size_t _Count);
+
+#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS
+template <size_t _SizeInWords>
+inline
+errno_t __cdecl wcsncat_s(WCHAR (&_Dst)[_SizeInWords], const WCHAR *_Src, size_t _Count)
+{
+ return wcsncat_s(_Dst, _SizeInWords, _Src, _Count);
+}
+#endif
+
+#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL
+
+_SAFECRT__INLINE
+errno_t __cdecl wcsncat_s(WCHAR *_Dst, size_t _SizeInWords, const WCHAR *_Src, size_t _Count)
+{
+ WCHAR *p;
+ size_t available;
+ if (_Count == 0 && _Dst == nullptr && _SizeInWords == 0)
+ {
+ /* this case is allowed; nothing to do */
+ return 0;
+ }
+ /* validation section */
+ _SAFECRT__VALIDATE_STRING(_Dst, _SizeInWords);
+ if (_Count != 0)
+ {
+ _SAFECRT__VALIDATE_POINTER_RESET_STRING(_Src, _Dst, _SizeInWords);
+ }
+
+ p = _Dst;
+ available = _SizeInWords;
+ while (available > 0 && *p != 0)
+ {
+ p++;
+ available--;
+ }
+
+ if (available == 0)
+ {
+ _SAFECRT__RESET_STRING(_Dst, _SizeInWords);
+ _SAFECRT__RETURN_DEST_NOT_NULL_TERMINATED(_Dst, _SizeInWords);
+ }
+
+ if (_Count == _TRUNCATE)
+ {
+ while ((*p++ = *_Src++) != 0 && --available > 0)
+ {
+ }
+ }
+ else
+ {
+ while (_Count > 0 && (*p++ = *_Src++) != 0 && --available > 0)
+ {
+ _Count--;
+ }
+ if (_Count == 0)
+ {
+ *p = 0;
+ }
+ }
+
+ if (available == 0)
+ {
+ if (_Count == _TRUNCATE)
+ {
+ _Dst[_SizeInWords - 1] = 0;
+ return STRUNCATE;
+ }
+ _SAFECRT__RESET_STRING(_Dst, _SizeInWords);
+ _SAFECRT__RETURN_BUFFER_TOO_SMALL(_Dst, _SizeInWords);
+ }
+ _SAFECRT__FILL_STRING(_Dst, _SizeInWords, _SizeInWords - available + 1);
+ return 0;
+}
+
+#endif
+
+/* _mbsnbcat_s */
+#if _SAFECRT_DEFINE_MBS_FUNCTIONS
+
+_SAFECRT__EXTERN_C
+errno_t __cdecl _mbsnbcat_s(unsigned char *_Dst, size_t _SizeInBytes, const unsigned char *_Src, size_t _CountInBytes);
+
+#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS
+template <size_t _SizeInBytes>
+inline
+errno_t __cdecl _mbsnbcat_s(unsigned char (&_Dst)[_SizeInBytes], const unsigned char *_Src, size_t _CountInBytes)
+{
+ return _mbsnbcat_s(_Dst, _SizeInBytes, _Src, size_t _CountInBytes);
+}
+#endif
+
+#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL
+
+_SAFECRT__INLINE
+errno_t __cdecl _mbsnbcat_s(unsigned char *_Dst, size_t _SizeInBytes, const unsigned char *_Src, size_t _CountInBytes)
+{
+ unsigned char *p;
+ size_t available;
+ if (_CountInBytes == 0 && _Dst == nullptr && _SizeInBytes == 0)
+ {
+ /* this case is allowed; nothing to do */
+ return 0;
+ }
+ /* validation section */
+ _SAFECRT__VALIDATE_STRING(_Dst, _SizeInBytes);
+ if (_CountInBytes != 0)
+ {
+ _SAFECRT__VALIDATE_POINTER_RESET_STRING(_Src, _Dst, _SizeInBytes);
+ }
+
+ p = _Dst;
+ available = _SizeInBytes;
+ while (available > 0 && *p != 0)
+ {
+ p++;
+ available--;
+ }
+
+ if (available == 0)
+ {
+ if (*p == 0 && _SAFECRT__ISMBBLEAD(p[-1]))
+ {
+ /* the original string ended with a lead byte: we remove it */
+ p--;
+ *p = 0;
+ available = 1;
+ }
+ else
+ {
+ _SAFECRT__RESET_STRING(_Dst, _SizeInBytes);
+ _SAFECRT__RETURN_DEST_NOT_NULL_TERMINATED(_Dst, _SizeInBytes);
+ }
+ }
+ if (available < _SizeInBytes && _SAFECRT__ISMBBLEAD(p[-1]))
+ {
+ /* the original string ended with a lead byte: we remove it */
+ p--;
+ *p = 0;
+ available++;
+ }
+
+ if (_CountInBytes == _TRUNCATE)
+ {
+ while ((*p++ = *_Src++) != 0 && --available > 0)
+ {
+ }
+ }
+ else
+ {
+ while (_CountInBytes > 0 && (*p++ = *_Src++) != 0 && --available > 0)
+ {
+ _CountInBytes--;
+ }
+ if (_CountInBytes == 0)
+ {
+ *p++ = 0;
+ }
+ }
+
+ if (available == 0)
+ {
+ if ((*_Src == 0 || _CountInBytes == 1) && _SAFECRT__ISMBBLEAD(p[-1]))
+ {
+ /* the source string ended with a lead byte: we remove it */
+ p[-1] = 0;
+ return 0;
+ }
+ if (_CountInBytes == _TRUNCATE)
+ {
+ if (_SizeInBytes > 1 && _SAFECRT__ISMBBLEAD(_Dst[_SizeInBytes - 2]))
+ {
+ _Dst[_SizeInBytes - 2] = 0;
+ _SAFECRT__FILL_BYTE(_Dst[_SizeInBytes - 1]);
+ }
+ else
+ {
+ _Dst[_SizeInBytes - 1] = 0;
+ }
+ return STRUNCATE;
+ }
+ _SAFECRT__RESET_STRING(_Dst, _SizeInBytes);
+ _SAFECRT__RETURN_BUFFER_TOO_SMALL(_Dst, _SizeInBytes);
+ }
+ if (available < _SizeInBytes && _SAFECRT__ISMBBLEAD(p[-2]))
+ {
+ /* the source string ended with a lead byte: we remove it */
+ p[-2] = 0;
+ available++;
+ }
+ _SAFECRT__FILL_STRING(_Dst, _SizeInBytes, _SizeInBytes - available + 1);
+ return 0;
+}
+
+#endif
+
+#endif /* _SAFECRT_DEFINE_MBS_FUNCTIONS */
+
+/* _mbsncat_s */
+#if _SAFECRT_DEFINE_MBS_FUNCTIONS
+
+_SAFECRT__EXTERN_C
+errno_t __cdecl _mbsncat_s(unsigned char *_Dst, size_t _SizeInBytes, const unsigned char *_Src, size_t _CountInChars);
+
+#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS
+template <size_t _SizeInBytes>
+inline
+errno_t __cdecl _mbsncat_s(unsigned char (&_Dst)[_SizeInBytes], const unsigned char *_Src, size_t _CountInChars)
+{
+ return _mbsncat_s(_Dst, _SizeInBytes, _Src, size_t _CountInChars);
+}
+#endif
+
+#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL
+
+_SAFECRT__INLINE
+errno_t __cdecl _mbsncat_s(unsigned char *_Dst, size_t _SizeInBytes, const unsigned char *_Src, size_t _CountInChars)
+{
+ unsigned char *p;
+ size_t available;
+ if (_CountInChars == 0 && _Dst == nullptr && _SizeInBytes == 0)
+ {
+ /* this case is allowed; nothing to do */
+ return 0;
+ }
+ /* validation section */
+ _SAFECRT__VALIDATE_STRING(_Dst, _SizeInBytes);
+ if (_CountInChars != 0)
+ {
+ _SAFECRT__VALIDATE_POINTER_RESET_STRING(_Src, _Dst, _SizeInBytes);
+ }
+
+ p = _Dst;
+ available = _SizeInBytes;
+ while (available > 0 && *p != 0)
+ {
+ p++;
+ available--;
+ }
+
+ if (available == 0)
+ {
+ if (*p == 0 && _SAFECRT__ISMBBLEAD(p[-1]))
+ {
+ /* the original string ended with a lead byte: we remove it */
+ p--;
+ *p = 0;
+ available = 1;
+ }
+ else
+ {
+ _SAFECRT__RESET_STRING(_Dst, _SizeInBytes);
+ _SAFECRT__RETURN_DEST_NOT_NULL_TERMINATED(_Dst, _SizeInBytes);
+ }
+ }
+ if (available < _SizeInBytes && _SAFECRT__ISMBBLEAD(p[-1]))
+ {
+ /* the original string ended with a lead byte: we remove it */
+ p--;
+ *p = 0;
+ available++;
+ }
+
+ if (_CountInChars == _TRUNCATE)
+ {
+ while ((*p++ = *_Src++) != 0 && --available > 0)
+ {
+ }
+ }
+ else
+ {
+ while (_CountInChars > 0)
+ {
+ if (_SAFECRT__ISMBBLEAD(*_Src))
+ {
+ if (_Src[1] == 0)
+ {
+ /* the source string ended with a lead byte: we remove it */
+ *p = 0;
+ break;
+ }
+ if (available <= 2)
+ {
+ /* not enough space */
+ available = 0;
+ break;
+ }
+ *p++ = *_Src++;
+ *p++ = *_Src++;
+ available -= 2;
+ }
+ else
+ {
+ if ((*p++ = *_Src++) == 0 || --available == 0)
+ {
+ break;
+ }
+ }
+ _CountInChars--;
+ }
+ if (_CountInChars == 0)
+ {
+ *p++ = 0;
+ }
+ }
+
+ if (available == 0)
+ {
+ if (_CountInChars == _TRUNCATE)
+ {
+ if (_SizeInBytes > 1 && _SAFECRT__ISMBBLEAD(_Dst[_SizeInBytes - 2]))
+ {
+ _Dst[_SizeInBytes - 2] = 0;
+ _SAFECRT__FILL_BYTE(_Dst[_SizeInBytes - 1]);
+ }
+ else
+ {
+ _Dst[_SizeInBytes - 1] = 0;
+ }
+ return STRUNCATE;
+ }
+ _SAFECRT__RESET_STRING(_Dst, _SizeInBytes);
+ _SAFECRT__RETURN_BUFFER_TOO_SMALL(_Dst, _SizeInBytes);
+ }
+ _SAFECRT__FILL_STRING(_Dst, _SizeInBytes, _SizeInBytes - available + 1);
+ return 0;
+}
+
+#endif
+
+#endif /* _SAFECRT_DEFINE_MBS_FUNCTIONS */
+
+/* _strset_s */
+/*
+ * _strset_s, _wcsset_s ;
+ * will call _SAFECRT_INVALID_PARAMETER if _Dst is not null terminated.
+ */
+_SAFECRT__EXTERN_C
+errno_t __cdecl _strset_s(char *_Dst, size_t _SizeInBytes, int _Value);
+
+#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS
+template <size_t _SizeInBytes>
+inline
+errno_t __cdecl _strset_s(char (&_Dst)[_SizeInBytes], int _Value)
+{
+ return _strset_s(_Dst, _SizeInBytes, _Value);
+}
+#endif
+
+#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL
+
+_SAFECRT__INLINE
+errno_t __cdecl _strset_s(char *_Dst, size_t _SizeInBytes, int _Value)
+{
+ char *p;
+ size_t available;
+
+ /* validation section */
+ _SAFECRT__VALIDATE_STRING(_Dst, _SizeInBytes);
+
+ p = _Dst;
+ available = _SizeInBytes;
+ while (*p != 0 && --available > 0)
+ {
+ *p++ = (char)_Value;
+ }
+
+ if (available == 0)
+ {
+ _SAFECRT__RESET_STRING(_Dst, _SizeInBytes);
+ _SAFECRT__RETURN_DEST_NOT_NULL_TERMINATED(_Dst, _SizeInBytes);
+ }
+ _SAFECRT__FILL_STRING(_Dst, _SizeInBytes, _SizeInBytes - available + 1);
+ return 0;
+}
+
+#endif
+
+/* _wcsset_s */
+_SAFECRT__EXTERN_C
+errno_t __cdecl _wcsset_s(WCHAR *_Dst, size_t _SizeInWords, WCHAR _Value);
+
+#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS
+template <size_t _SizeInWords>
+inline
+errno_t __cdecl _wcsset_s(WCHAR (&_Dst)[_SizeInWords], WCHAR _Value)
+{
+ return _wcsset_s(_Dst, _SizeInWords, _Value);
+}
+#endif
+
+#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL
+
+_SAFECRT__INLINE
+errno_t __cdecl _wcsset_s(WCHAR *_Dst, size_t _SizeInWords, WCHAR _Value)
+{
+ WCHAR *p;
+ size_t available;
+
+ /* validation section */
+ _SAFECRT__VALIDATE_STRING(_Dst, _SizeInWords);
+
+ p = _Dst;
+ available = _SizeInWords;
+ while (*p != 0 && --available > 0)
+ {
+ *p++ = (WCHAR)_Value;
+ }
+
+ if (available == 0)
+ {
+ _SAFECRT__RESET_STRING(_Dst, _SizeInWords);
+ _SAFECRT__RETURN_DEST_NOT_NULL_TERMINATED(_Dst, _SizeInWords);
+ }
+ _SAFECRT__FILL_STRING(_Dst, _SizeInWords, _SizeInWords - available + 1);
+ return 0;
+}
+
+#endif
+
+/* _mbsset_s */
+#if _SAFECRT_DEFINE_MBS_FUNCTIONS
+
+_SAFECRT__EXTERN_C
+errno_t __cdecl _mbsset_s(unsigned char *_Dst, size_t _SizeInBytes, unsigned int _Value);
+
+#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS
+template <size_t _SizeInBytes>
+inline
+errno_t __cdecl _mbsset_s(unsigned char (&_Dst)[_SizeInBytes], unsigned int _Value)
+{
+ return _mbsset_s(_Dst, _SizeInBytes, _Value);
+}
+#endif
+
+#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL
+
+_SAFECRT__INLINE
+errno_t __cdecl _mbsset_s(unsigned char *_Dst, size_t _SizeInBytes, unsigned int _Value)
+{
+ int mbcs_error = 0;
+ unsigned char *p;
+ size_t available;
+ unsigned char highval, lowval;
+
+ /* validation section */
+ _SAFECRT__VALIDATE_STRING(_Dst, _SizeInBytes);
+
+ p = _Dst;
+ available = _SizeInBytes;
+ highval = (unsigned char)(_Value >> 8);
+ lowval = (unsigned char)(_Value & 0x00ff);
+ if (highval != 0)
+ {
+ if (_SAFECRT__ISMBBLEAD(highval) && lowval != 0)
+ {
+ while (*p != 0 && --available > 0)
+ {
+ if (p[1] == 0)
+ {
+ /* do not orphan leadbyte */
+ *p++ = ' ';
+ break;
+ }
+ *p++ = highval;
+ if (--available == 0)
+ {
+ break;
+ }
+ *p++ = lowval;
+ }
+ }
+ else
+ {
+ mbcs_error = 1;
+ highval = 0;
+ lowval = ' ';
+ }
+ }
+ else
+ {
+ if (_SAFECRT__ISMBBLEAD(lowval))
+ {
+ mbcs_error = 1;
+ lowval = ' ';
+ }
+ }
+ if (highval == 0)
+ {
+ while (*p != 0 && --available > 0)
+ {
+ *p++ = lowval;
+ }
+ }
+
+ if (available == 0)
+ {
+ _SAFECRT__RESET_STRING(_Dst, _SizeInBytes);
+ _SAFECRT__RETURN_DEST_NOT_NULL_TERMINATED(_Dst, _SizeInBytes);
+ }
+ _SAFECRT__FILL_STRING(_Dst, _SizeInBytes, _SizeInBytes - available + 1);
+ if (mbcs_error)
+ {
+ _SAFECRT__SET_ERRNO(EILSEQ); return EILSEQ;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+#endif
+
+#endif /* _SAFECRT_DEFINE_MBS_FUNCTIONS */
+
+/* _strnset_s */
+/*
+ * _strnset_s, _wcsnset_s ;
+ * will call _SAFECRT_INVALID_PARAMETER if _Dst is not null terminated.
+ */
+_SAFECRT__EXTERN_C
+errno_t __cdecl _strnset_s(char *_Dst, size_t _SizeInBytes, int _Value, size_t _Count);
+
+#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS
+template <size_t _SizeInBytes>
+inline
+errno_t __cdecl _strnset_s(char (&_Dst)[_SizeInBytes], int _Value, size_t _Count)
+{
+ return _strnset_s(_Dst, _SizeInBytes, _Value, _Count);
+}
+#endif
+
+#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL
+
+_SAFECRT__INLINE
+errno_t __cdecl _strnset_s(char *_Dst, size_t _SizeInBytes, int _Value, size_t _Count)
+{
+ char *p;
+ size_t available;
+
+ /* validation section */
+ if (_Count == 0 && _Dst == nullptr && _SizeInBytes == 0)
+ {
+ /* this case is allowed; nothing to do */
+ return 0;
+ }
+ _SAFECRT__VALIDATE_STRING(_Dst, _SizeInBytes);
+
+ p = _Dst;
+ available = _SizeInBytes;
+ while (*p != 0 && _Count > 0 && --available > 0)
+ {
+ *p++ = (char)_Value;
+ --_Count;
+ }
+
+ if (available == 0)
+ {
+ _SAFECRT__RESET_STRING(_Dst, _SizeInBytes);
+ _SAFECRT__RETURN_DEST_NOT_NULL_TERMINATED(_Dst, _SizeInBytes);
+ }
+ if (_Count == 0)
+ {
+ *p = 0;
+ }
+ _SAFECRT__FILL_STRING(_Dst, _SizeInBytes, _SizeInBytes - available + 1);
+ return 0;
+}
+
+#endif
+
+/* _wcsnset_s */
+_SAFECRT__EXTERN_C
+errno_t __cdecl _wcsnset_s(WCHAR *_Dst, size_t _SizeInWords, WCHAR _Value, size_t _Count);
+
+#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS
+template <size_t _SizeInWords>
+inline
+errno_t __cdecl _wcsnset_s(WCHAR (&_Dst)[_SizeInWords], WCHAR _Value, size_t _Count)
+{
+ return _wcsnset_s(_Dst, _SizeInWords, _Value, _Count);
+}
+#endif
+
+#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL
+
+_SAFECRT__INLINE
+errno_t __cdecl _wcsnset_s(WCHAR *_Dst, size_t _SizeInWords, WCHAR _Value, size_t _Count)
+{
+ WCHAR *p;
+ size_t available;
+
+ /* validation section */
+ if (_Count == 0 && _Dst == nullptr && _SizeInWords == 0)
+ {
+ /* this case is allowed; nothing to do */
+ return 0;
+ }
+ _SAFECRT__VALIDATE_STRING(_Dst, _SizeInWords);
+
+ p = _Dst;
+ available = _SizeInWords;
+ while (*p != 0 && _Count > 0 && --available > 0)
+ {
+ *p++ = (WCHAR)_Value;
+ --_Count;
+ }
+
+ if (available == 0)
+ {
+ _SAFECRT__RESET_STRING(_Dst, _SizeInWords);
+ _SAFECRT__RETURN_DEST_NOT_NULL_TERMINATED(_Dst, _SizeInWords);
+ }
+ if (_Count == 0)
+ {
+ *p = 0;
+ }
+ _SAFECRT__FILL_STRING(_Dst, _SizeInWords, _SizeInWords - available + 1);
+ return 0;
+}
+
+#endif
+
+/* _mbsnbset_s */
+#if _SAFECRT_DEFINE_MBS_FUNCTIONS
+
+_SAFECRT__EXTERN_C
+errno_t __cdecl _mbsnbset_s(unsigned char *_Dst, size_t _SizeInBytes, unsigned int _Value, size_t _CountInBytes);
+
+#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS
+template <size_t _SizeInBytes>
+inline
+errno_t __cdecl _mbsnbset_s(unsigned char (&_Dst)[_SizeInBytes], unsigned int _Value, size_t _CountInBytes)
+{
+ return _mbsnbset_s(_Dst, _SizeInBytes, _Value, _CountInBytes);
+}
+#endif
+
+#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL
+
+_SAFECRT__INLINE
+errno_t __cdecl _mbsnbset_s(unsigned char *_Dst, size_t _SizeInBytes, unsigned int _Value, size_t _CountInBytes)
+{
+ int mbcs_error = 0;
+ unsigned char *p;
+ size_t available;
+ unsigned char highval, lowval;
+
+ /* validation section */
+ if (_CountInBytes == 0 && _Dst == nullptr && _SizeInBytes == 0)
+ {
+ /* this case is allowed; nothing to do */
+ return 0;
+ }
+ _SAFECRT__VALIDATE_STRING(_Dst, _SizeInBytes);
+
+ p = _Dst;
+ available = _SizeInBytes;
+ highval = (unsigned char)(_Value >> 8);
+ lowval = (unsigned char)(_Value & 0x00ff);
+ if (highval != 0)
+ {
+ if (_SAFECRT__ISMBBLEAD(highval) && lowval != 0)
+ {
+ while (*p != 0 && _CountInBytes > 0 && --available > 0)
+ {
+ if (_CountInBytes == 1 || p[1] == 0)
+ {
+ /* do not orphan leadbyte */
+ *p++ = ' ';
+ --_CountInBytes;
+ break;
+ }
+ *p++ = highval;
+ if (--available == 0)
+ {
+ break;
+ }
+ *p++ = lowval;
+ _CountInBytes -= 2;
+ }
+ }
+ else
+ {
+ mbcs_error = 1;
+ highval = 0;
+ lowval = ' ';
+ }
+ }
+ else
+ {
+ if (_SAFECRT__ISMBBLEAD(lowval))
+ {
+ mbcs_error = 1;
+ lowval = ' ';
+ }
+ }
+ if (highval == 0)
+ {
+ while (*p != 0 && available > 0 && _CountInBytes > 0)
+ {
+ *p++ = lowval;
+ --available;
+ --_CountInBytes;
+ }
+ }
+ if (available == 0)
+ {
+ _SAFECRT__RESET_STRING(_Dst, _SizeInBytes);
+ _SAFECRT__RETURN_DEST_NOT_NULL_TERMINATED(_Dst, _SizeInBytes);
+ }
+ if (_CountInBytes == 0)
+ {
+ *p = 0;
+ }
+ _SAFECRT__FILL_STRING(_Dst, _SizeInBytes, _SizeInBytes - available + 1);
+ if (mbcs_error)
+ {
+ _SAFECRT__SET_ERRNO(EILSEQ); return EILSEQ;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+#endif
+
+#endif /* _SAFECRT_DEFINE_MBS_FUNCTIONS */
+
+/* _mbsnset_s */
+#if _SAFECRT_DEFINE_MBS_FUNCTIONS
+
+_SAFECRT__EXTERN_C
+errno_t __cdecl _mbsnset_s(unsigned char *_Dst, size_t _SizeInBytes, unsigned int _Value, size_t _CountInChars);
+
+#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS
+template <size_t _SizeInBytes>
+inline
+errno_t __cdecl _mbsnset_s(unsigned char (&_Dst)[_SizeInBytes], unsigned int _Value, size_t _CountInChars)
+{
+ return _mbsnset_s(_Dst, _SizeInBytes, _Value, _CountInChars);
+}
+#endif
+
+#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL
+
+_SAFECRT__INLINE
+errno_t __cdecl _mbsnset_s(unsigned char *_Dst, size_t _SizeInBytes, unsigned int _Value, size_t _CountInChars)
+{
+ int mbcs_error = 0;
+ unsigned char *p;
+ size_t available;
+ unsigned char highval, lowval;
+
+ /* validation section */
+ if (_CountInChars == 0 && _Dst == nullptr && _SizeInBytes == 0)
+ {
+ /* this case is allowed; nothing to do */
+ return 0;
+ }
+ _SAFECRT__VALIDATE_STRING(_Dst, _SizeInBytes);
+
+ p = _Dst;
+ available = _SizeInBytes;
+ highval = (unsigned char)(_Value >> 8);
+ lowval = (unsigned char)(_Value & 0x00ff);
+ if (highval != 0)
+ {
+ if (_SAFECRT__ISMBBLEAD(highval) && lowval != 0)
+ {
+ while (*p != 0 && _CountInChars > 0 && --available > 0)
+ {
+ if (p[1] == 0)
+ {
+ /* do not orphan leadbyte */
+ *p++ = ' ';
+ break;
+ }
+ *p++ = highval;
+ if (--available == 0)
+ {
+ break;
+ }
+ *p++ = lowval;
+ --_CountInChars;
+ }
+ }
+ else
+ {
+ mbcs_error = 1;
+ highval = 0;
+ lowval = ' ';
+ }
+ }
+ else
+ {
+ if (_SAFECRT__ISMBBLEAD(lowval))
+ {
+ mbcs_error = 1;
+ lowval = ' ';
+ }
+ }
+ if (highval == 0)
+ {
+ while (*p != 0 && available > 0 && _CountInChars > 0)
+ {
+ *p++ = lowval;
+ --available;
+ --_CountInChars;
+ }
+ }
+ if (available == 0)
+ {
+ _SAFECRT__RESET_STRING(_Dst, _SizeInBytes);
+ _SAFECRT__RETURN_DEST_NOT_NULL_TERMINATED(_Dst, _SizeInBytes);
+ }
+ if (_CountInChars == 0)
+ {
+ *p = 0;
+ }
+ _SAFECRT__FILL_STRING(_Dst, _SizeInBytes, _SizeInBytes - available + 1);
+ if (mbcs_error)
+ {
+ _SAFECRT__SET_ERRNO(EILSEQ); return EILSEQ;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+#endif
+
+#endif /* _SAFECRT_DEFINE_MBS_FUNCTIONS */
+
+/* _mbccpy_s */
+#if _SAFECRT_DEFINE_MBS_FUNCTIONS
+
+_SAFECRT__EXTERN_C
+errno_t __cdecl _mbccpy_s(unsigned char *_Dst, size_t _SizeInBytes, int *_PCopied, const unsigned char *_Src);
+
+#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS
+template <size_t _SizeInBytes>
+inline
+errno_t __cdecl _mbccpy_s(unsigned char (&_Dst)[_SizeInBytes], int *_PCopied, const unsigned char *_Src)
+{
+ return _mbccpy_s(_Dst, _SizeInBytes, _PCopied, _Src);
+}
+#endif
+
+#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL
+
+_SAFECRT__INLINE
+errno_t __cdecl _mbccpy_s(unsigned char *_Dst, size_t _SizeInBytes, int *_PCopied, const unsigned char *_Src)
+{
+ /* validation section */
+ if (_PCopied != nullptr) { *_PCopied = 0; };
+ _SAFECRT__VALIDATE_STRING(_Dst, _SizeInBytes);
+ if (_Src == nullptr)
+ {
+ *_Dst = '\0';
+ _SAFECRT__RETURN_EINVAL;
+ }
+
+ /* copy */
+ if (_SAFECRT__ISMBBLEAD(*_Src))
+ {
+ if (_Src[1] == '\0')
+ {
+ /* the source string contained a lead byte followed by the null terminator:
+ we copy only the null terminator and return EILSEQ to indicate the
+ malformed char */
+ *_Dst = '\0';
+ if (_PCopied != nullptr) { *_PCopied = 1; };
+ _SAFECRT__SET_ERRNO(EILSEQ); return EILSEQ;
+ }
+ if (_SizeInBytes < 2)
+ {
+ *_Dst = '\0';
+ _SAFECRT__RETURN_BUFFER_TOO_SMALL(_Dst, _SizeInBytes);
+ }
+ *_Dst++ = *_Src++;
+ *_Dst = *_Src;
+ if (_PCopied != nullptr) { *_PCopied = 2; };
+ }
+ else
+ {
+ *_Dst = *_Src;
+ if (_PCopied != nullptr) { *_PCopied = 1; };
+ }
+
+ return 0;
+}
+#endif
+
+#endif /* _SAFECRT_DEFINE_MBS_FUNCTIONS */
+
+/* strtok_s */
+/*
+ * strtok_s, wcstok_s ;
+ * uses _Context to keep track of the position in the string.
+ */
+_SAFECRT__EXTERN_C
+char * __cdecl strtok_s(char *_String, const char *_Control, char **_Context);
+
+#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL
+
+_SAFECRT__INLINE
+char * __cdecl strtok_s(char *_String, const char *_Control, char **_Context)
+{
+ unsigned char *str;
+ const unsigned char *ctl = (const unsigned char *)_Control;
+ unsigned char map[32];
+ int count;
+
+ /* validation section */
+ _SAFECRT__VALIDATE_POINTER_ERROR_RETURN(_Context, EINVAL, nullptr);
+ _SAFECRT__VALIDATE_POINTER_ERROR_RETURN(_Control, EINVAL, nullptr);
+ _SAFECRT__VALIDATE_CONDITION_ERROR_RETURN(_String != nullptr || *_Context != nullptr, EINVAL, nullptr);
+
+ /* Clear control map */
+ for (count = 0; count < 32; count++)
+ {
+ map[count] = 0;
+ }
+
+ /* Set bits in delimiter table */
+ do {
+ map[*ctl >> 3] |= (1 << (*ctl & 7));
+ } while (*ctl++);
+
+ /* If string is nullptr, set str to the saved
+ * pointer (i.e., continue breaking tokens out of the string
+ * from the last strtok call) */
+ if (_String != nullptr)
+ {
+ str = (unsigned char *)_String;
+ }
+ else
+ {
+ str = (unsigned char *)*_Context;
+ }
+
+ /* Find beginning of token (skip over leading delimiters). Note that
+ * there is no token iff this loop sets str to point to the terminal
+ * null (*str == 0) */
+ while ((map[*str >> 3] & (1 << (*str & 7))) && *str != 0)
+ {
+ str++;
+ }
+
+ _String = (char *)str;
+
+ /* Find the end of the token. If it is not the end of the string,
+ * put a null there. */
+ for ( ; *str != 0 ; str++ )
+ {
+ if (map[*str >> 3] & (1 << (*str & 7)))
+ {
+ *str++ = 0;
+ break;
+ }
+ }
+
+ /* Update context */
+ *_Context = (char *)str;
+
+ /* Determine if a token has been found. */
+ if (_String == (char *)str)
+ {
+ return nullptr;
+ }
+ else
+ {
+ return _String;
+ }
+}
+#endif
+
+/* wcstok_s */
+_SAFECRT__EXTERN_C
+WCHAR * __cdecl wcstok_s(WCHAR *_String, const WCHAR *_Control, WCHAR **_Context);
+
+#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL
+
+_SAFECRT__INLINE
+WCHAR * __cdecl wcstok_s(WCHAR *_String, const WCHAR *_Control, WCHAR **_Context)
+{
+ WCHAR *token;
+ const WCHAR *ctl;
+
+ /* validation section */
+ _SAFECRT__VALIDATE_POINTER_ERROR_RETURN(_Context, EINVAL, nullptr);
+ _SAFECRT__VALIDATE_POINTER_ERROR_RETURN(_Control, EINVAL, nullptr);
+ _SAFECRT__VALIDATE_CONDITION_ERROR_RETURN(_String != nullptr || *_Context != nullptr, EINVAL, nullptr);
+
+ /* If string==nullptr, continue with previous string */
+ if (!_String)
+ {
+ _String = *_Context;
+ }
+
+ /* Find beginning of token (skip over leading delimiters). Note that
+ * there is no token iff this loop sets string to point to the terminal null. */
+ for ( ; *_String != 0 ; _String++)
+ {
+ for (ctl = _Control; *ctl != 0 && *ctl != *_String; ctl++)
+ ;
+ if (*ctl == 0)
+ {
+ break;
+ }
+ }
+
+ token = _String;
+
+ /* Find the end of the token. If it is not the end of the string,
+ * put a null there. */
+ for ( ; *_String != 0 ; _String++)
+ {
+ for (ctl = _Control; *ctl != 0 && *ctl != *_String; ctl++)
+ ;
+ if (*ctl != 0)
+ {
+ *_String++ = 0;
+ break;
+ }
+ }
+
+ /* Update the context */
+ *_Context = _String;
+
+ /* Determine if a token has been found. */
+ if (token == _String)
+ {
+ return nullptr;
+ }
+ else
+ {
+ return token;
+ }
+}
+#endif
+
+/* _mbstok_s */
+#if _SAFECRT_DEFINE_MBS_FUNCTIONS
+
+_SAFECRT__EXTERN_C
+unsigned char * __cdecl _mbstok_s(unsigned char *_String, const unsigned char *_Control, unsigned char **_Context);
+
+#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL
+
+_SAFECRT__INLINE
+unsigned char * __cdecl _mbstok_s(unsigned char *_String, const unsigned char *_Control, unsigned char **_Context)
+{
+ unsigned char *token;
+ const unsigned char *ctl;
+ int dbc;
+
+ /* validation section */
+ _SAFECRT__VALIDATE_POINTER_ERROR_RETURN(_Context, EINVAL, nullptr);
+ _SAFECRT__VALIDATE_POINTER_ERROR_RETURN(_Control, EINVAL, nullptr);
+ _SAFECRT__VALIDATE_CONDITION_ERROR_RETURN(_String != nullptr || *_Context != nullptr, EINVAL, nullptr);
+
+ /* If string==nullptr, continue with previous string */
+ if (!_String)
+ {
+ _String = *_Context;
+ }
+
+ /* Find beginning of token (skip over leading delimiters). Note that
+ * there is no token iff this loop sets string to point to the terminal null. */
+ for ( ; *_String != 0; _String++)
+ {
+ for (ctl = _Control; *ctl != 0; ctl++)
+ {
+ if (_SAFECRT__ISMBBLEAD(*ctl))
+ {
+ if (*ctl == *_String && (ctl[1] == 0 || ctl[1] == _String[1]))
+ {
+ break;
+ }
+ ctl++;
+ }
+ else
+ {
+ if (*ctl == *_String)
+ {
+ break;
+ }
+ }
+ }
+ if (*ctl == 0)
+ {
+ break;
+ }
+ if (_SAFECRT__ISMBBLEAD(*_String))
+ {
+ _String++;
+ if (*_String == 0)
+ {
+ break;
+ }
+ }
+ }
+
+ token = _String;
+
+ /* Find the end of the token. If it is not the end of the string,
+ * put a null there. */
+ for ( ; *_String != 0; _String++)
+ {
+ for (ctl = _Control, dbc = 0; *ctl != 0; ctl++)
+ {
+ if (_SAFECRT__ISMBBLEAD(*ctl))
+ {
+ if (*ctl == *_String && (ctl[1] == 0 || ctl[1] == _String[1]))
+ {
+ dbc = 1;
+ break;
+ }
+ ctl++;
+ }
+ else
+ {
+ if (*ctl == *_String)
+ {
+ break;
+ }
+ }
+ }
+ if (*ctl != 0)
+ {
+ *_String++ = 0;
+ if (dbc && ctl[1] != 0)
+ {
+ *_String++ = 0;
+ }
+ break;
+ }
+ if (_SAFECRT__ISMBBLEAD(*_String))
+ {
+ _String++;
+ if (*_String == 0)
+ {
+ break;
+ }
+ }
+ }
+
+ /* Update the context */
+ *_Context = _String;
+
+ /* Determine if a token has been found. */
+ if (token == _String)
+ {
+ return nullptr;
+ }
+ else
+ {
+ return token;
+ }
+}
+#endif
+
+#endif /* _SAFECRT_DEFINE_MBS_FUNCTIONS */
+
+#ifndef PAL_STDCPP_COMPAT
+/* strnlen */
+/*
+ * strnlen, wcsnlen ;
+ * returns inMaxSize if the null character is not found.
+ */
+_SAFECRT__EXTERN_C
+size_t __cdecl strnlen(const char* inString, size_t inMaxSize);
+
+#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL
+
+_SAFECRT__INLINE
+size_t __cdecl strnlen(const char* inString, size_t inMaxSize)
+{
+ size_t n;
+
+ /* Note that we do not check if s == nullptr, because we do not
+ * return errno_t...
+ */
+
+ for (n = 0; n < inMaxSize && *inString; n++, inString++)
+ ;
+
+ return n;
+}
+
+#endif
+
+/* wcsnlen */
+_SAFECRT__EXTERN_C
+size_t __cdecl wcsnlen(const WCHAR *inString, size_t inMaxSize);
+
+#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL
+
+_SAFECRT__INLINE
+size_t __cdecl wcsnlen(const WCHAR *inString, size_t inMaxSize)
+{
+ size_t n;
+
+ /* Note that we do not check if s == nullptr, because we do not
+ * return errno_t...
+ */
+
+ for (n = 0; n < inMaxSize && *inString; n++, inString++)
+ ;
+
+ return n;
+}
+
+#endif
+#endif // PAL_STDCPP_COMPAT
+
+/* _makepath_s */
+/*
+ * _makepath_s, _wmakepath_s build up a path starting from the specified components;
+ * will call _SAFECRT_INVALID_PARAMETER if there is not enough space in _Dst;
+ * any of _Drive, _Dir, _Filename and _Ext can be nullptr
+ */
+_SAFECRT__EXTERN_C
+errno_t __cdecl _makepath_s(char *_Dst, size_t _SizeInBytes, const char *_Drive, const char *_Dir, const char *_Filename, const char *_Ext);
+
+#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS
+template <size_t _SizeInBytes>
+inline
+errno_t __cdecl _makepath_s(char (&_Dst)[_SizeInBytes], const char *_Drive, const char *_Dir, const char *_Filename, const char *_Ext)
+{
+ return _makepath_s(_Dst, _SizeInBytes, _Drive, _Dir, _Filename, _Ext);
+}
+#endif
+
+#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL
+
+_SAFECRT__INLINE
+errno_t __cdecl _makepath_s(char *_Dst, size_t _SizeInBytes, const char *_Drive, const char *_Dir, const char *_Filename, const char *_Ext)
+{
+ size_t written;
+ const char *p;
+ char *d;
+
+ /* validation section */
+ _SAFECRT__VALIDATE_STRING(_Dst, _SizeInBytes);
+
+ /* copy drive */
+ written = 0;
+ d = _Dst;
+ if (_Drive != nullptr && *_Drive != 0)
+ {
+ written += 2;
+ if(written >= _SizeInBytes)
+ {
+ goto error_return;
+ }
+ *d++ = *_Drive;
+ *d++ = ':';
+ }
+
+ /* copy dir */
+ p = _Dir;
+ if (p != nullptr && *p != 0)
+ {
+ do {
+ if(++written >= _SizeInBytes)
+ {
+ goto error_return;
+ }
+ *d++ = *p++;
+ } while (*p != 0);
+
+ p = (const char *)_SAFECRT__MBSDEC((const unsigned char *)_Dir, (const unsigned char *)p);
+ if (*p != '/' && *p != '\\')
+ {
+ if(++written >= _SizeInBytes)
+ {
+ goto error_return;
+ }
+ *d++ = '\\';
+ }
+ }
+
+ /* copy fname */
+ p = _Filename;
+ if (p != nullptr)
+ {
+ while (*p != 0)
+ {
+ if(++written >= _SizeInBytes)
+ {
+ goto error_return;
+ }
+ *d++ = *p++;
+ }
+ }
+
+ /* copy extension; check to see if a '.' needs to be inserted */
+ p = _Ext;
+ if (p != nullptr)
+ {
+ if (*p != 0 && *p != '.')
+ {
+ if(++written >= _SizeInBytes)
+ {
+ goto error_return;
+ }
+ *d++ = '.';
+ }
+ while (*p != 0)
+ {
+ if(++written >= _SizeInBytes)
+ {
+ goto error_return;
+ }
+ *d++ = *p++;
+ }
+ }
+
+ if(++written > _SizeInBytes)
+ {
+ goto error_return;
+ }
+ *d = 0;
+ _SAFECRT__FILL_STRING(_Dst, _SizeInBytes, written);
+ return 0;
+
+error_return:
+ _SAFECRT__RESET_STRING(_Dst, _SizeInBytes);
+ _SAFECRT__RETURN_BUFFER_TOO_SMALL(_Dst, _SizeInBytes);
+ /* should never happen, but compiler can't tell */
+ return EINVAL;
+}
+#endif
+
+/* _wmakepath_s */
+_SAFECRT__EXTERN_C
+errno_t __cdecl _wmakepath_s(WCHAR *_Dst, size_t _SizeInWords, const WCHAR *_Drive, const WCHAR *_Dir, const WCHAR *_Filename, const WCHAR *_Ext);
+
+#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS
+template <size_t _SizeInWords>
+inline
+errno_t __cdecl _wmakepath_s(WCHAR (&_Dst)[_SizeInWords], const WCHAR *_Drive, const WCHAR *_Dir, const WCHAR *_Filename, const WCHAR *_Ext)
+{
+ return _wmakepath_s(_Dst, _SizeInWords, _Drive, _Dir, _Filename, _Ext);
+}
+#endif
+
+#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL
+
+_SAFECRT__INLINE
+errno_t __cdecl _wmakepath_s(WCHAR *_Dst, size_t _SizeInWords, const WCHAR *_Drive, const WCHAR *_Dir, const WCHAR *_Filename, const WCHAR *_Ext)
+{
+ size_t written;
+ const WCHAR *p;
+ WCHAR *d;
+
+ /* validation section */
+ _SAFECRT__VALIDATE_STRING(_Dst, _SizeInWords);
+
+ /* copy drive */
+ written = 0;
+ d = _Dst;
+ if (_Drive != nullptr && *_Drive != 0)
+ {
+ written += 2;
+ if(written >= _SizeInWords)
+ {
+ goto error_return;
+ }
+ *d++ = *_Drive;
+ *d++ = L':';
+ }
+
+ /* copy dir */
+ p = _Dir;
+ if (p != nullptr && *p != 0)
+ {
+ do {
+ if(++written >= _SizeInWords)
+ {
+ goto error_return;
+ }
+ *d++ = *p++;
+ } while (*p != 0);
+
+ p = p - 1;
+ if (*p != L'/' && *p != L'\\')
+ {
+ if(++written >= _SizeInWords)
+ {
+ goto error_return;
+ }
+ *d++ = L'\\';
+ }
+ }
+
+ /* copy fname */
+ p = _Filename;
+ if (p != nullptr)
+ {
+ while (*p != 0)
+ {
+ if(++written >= _SizeInWords)
+ {
+ goto error_return;
+ }
+ *d++ = *p++;
+ }
+ }
+
+ /* copy extension; check to see if a '.' needs to be inserted */
+ p = _Ext;
+ if (p != nullptr)
+ {
+ if (*p != 0 && *p != L'.')
+ {
+ if(++written >= _SizeInWords)
+ {
+ goto error_return;
+ }
+ *d++ = L'.';
+ }
+ while (*p != 0)
+ {
+ if(++written >= _SizeInWords)
+ {
+ goto error_return;
+ }
+ *d++ = *p++;
+ }
+ }
+
+ if(++written > _SizeInWords)
+ {
+ goto error_return;
+ }
+ *d = 0;
+ _SAFECRT__FILL_STRING(_Dst, _SizeInWords, written);
+ return 0;
+
+error_return:
+ _SAFECRT__RESET_STRING(_Dst, _SizeInWords);
+ _SAFECRT__RETURN_BUFFER_TOO_SMALL(_Dst, _SizeInWords);
+ /* should never happen, but compiler can't tell */
+ return EINVAL;
+}
+#endif
+
+/* _splitpath_s */
+/*
+ * _splitpath_s, _wsplitpath_s decompose a path into the specified components;
+ * will call _SAFECRT_INVALID_PARAMETER if there is not enough space in
+ * any of _Drive, _Dir, _Filename and _Ext;
+ * any of _Drive, _Dir, _Filename and _Ext can be nullptr, but the correspondent size must
+ * be set to 0, e.g. (_Drive == nullptr && _DriveSize == 0) is allowed, but
+ * (_Drive == nullptr && _DriveSize != 0) is considered an invalid parameter
+ */
+_SAFECRT__EXTERN_C
+errno_t __cdecl _splitpath_s(
+ const char *_Path,
+ char *_Drive, size_t _DriveSize,
+ char *_Dir, size_t _DirSize,
+ char *_Filename, size_t _FilenameSize,
+ char *_Ext, size_t _ExtSize
+);
+
+/* no C++ overload for _splitpath_s */
+
+#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL
+
+_SAFECRT__INLINE
+errno_t __cdecl _splitpath_s(
+ const char *_Path,
+ char *_Drive, size_t _DriveSize,
+ char *_Dir, size_t _DirSize,
+ char *_Filename, size_t _FilenameSize,
+ char *_Ext, size_t _ExtSize
+)
+{
+ const char *tmp;
+ const char *last_slash;
+ const char *dot;
+ int drive_set = 0;
+ size_t length = 0;
+ int bEinval = 0;
+
+ /* validation section */
+ _SAFECRT__VALIDATE_POINTER(_Path);
+ if ((_Drive == nullptr && _DriveSize != 0) || (_Drive != nullptr && _DriveSize == 0))
+ {
+ goto error_einval;
+ }
+ if ((_Dir == nullptr && _DirSize != 0) || (_Dir != nullptr && _DirSize == 0))
+ {
+ goto error_einval;
+ }
+ if ((_Filename == nullptr && _FilenameSize != 0) || (_Filename != nullptr && _FilenameSize == 0))
+ {
+ goto error_einval;
+ }
+ if ((_Ext == nullptr && _ExtSize != 0) || (_Ext != nullptr && _ExtSize == 0))
+ {
+ goto error_einval;
+ }
+
+ /* check if _Path begins with the longpath prefix */
+ if (_Path[0] == '\\' && _Path[1] == '\\' && _Path[2] == '?' && _Path[3] == '\\')
+ {
+ _Path += 4;
+ }
+
+ /* extract drive letter and ':', if any */
+ if (!drive_set)
+ {
+ size_t skip = _MAX_DRIVE - 2;
+ tmp = _Path;
+ while (skip > 0 && *tmp != 0)
+ {
+ skip--;
+ tmp++;
+ }
+ if (*tmp == ':')
+ {
+ if (_Drive != nullptr)
+ {
+ if (_DriveSize < _MAX_DRIVE)
+ {
+ goto error_erange;
+ }
+ strncpy_s(_Drive, _DriveSize, _Path, _MAX_DRIVE - 1);
+ }
+ _Path = tmp + 1;
+ }
+ else
+ {
+ if (_Drive != nullptr)
+ {
+ _SAFECRT__RESET_STRING(_Drive, _DriveSize);
+ }
+ }
+ }
+
+ /* extract path string, if any. _Path now points to the first character
+ * of the path, if any, or the filename or extension, if no path was
+ * specified. Scan ahead for the last occurence, if any, of a '/' or
+ * '\' path separator character. If none is found, there is no path.
+ * We will also note the last '.' character found, if any, to aid in
+ * handling the extension.
+ */
+ last_slash = nullptr;
+ dot = nullptr;
+ tmp = _Path;
+ for (; *tmp != 0; ++tmp)
+ {
+#if _SAFECRT_DEFINE_MBS_FUNCTIONS
+#pragma warning(push)
+#pragma warning(disable:4127)
+ if (_SAFECRT__ISMBBLEAD(*tmp))
+#pragma warning(pop)
+#else
+ if (0)
+#endif
+ {
+ tmp++;
+ }
+ else
+ {
+ if (*tmp == '/' || *tmp == '\\')
+ {
+ /* point to one beyond for later copy */
+ last_slash = tmp + 1;
+ }
+ else if (*tmp == '.')
+ {
+ dot = tmp;
+ }
+ }
+ }
+
+ if (last_slash != nullptr)
+ {
+ /* found a path - copy up through last_slash or max characters
+ * allowed, whichever is smaller
+ */
+ if (_Dir != nullptr) {
+ length = (size_t)(last_slash - _Path);
+ if (_DirSize <= length)
+ {
+ goto error_erange;
+ }
+ strncpy_s(_Dir, _DirSize, _Path, length);
+ }
+ _Path = last_slash;
+ }
+ else
+ {
+ /* there is no path */
+ if (_Dir != nullptr)
+ {
+ _SAFECRT__RESET_STRING(_Dir, _DirSize);
+ }
+ }
+
+ /* extract file name and extension, if any. Path now points to the
+ * first character of the file name, if any, or the extension if no
+ * file name was given. Dot points to the '.' beginning the extension,
+ * if any.
+ */
+ if (dot != nullptr && (dot >= _Path))
+ {
+ /* found the marker for an extension - copy the file name up to the '.' */
+ if (_Filename)
+ {
+ length = (size_t)(dot - _Path);
+ if (_FilenameSize <= length)
+ {
+ goto error_erange;
+ }
+ strncpy_s(_Filename, _FilenameSize, _Path, length);
+ }
+ /* now we can get the extension - remember that tmp still points
+ * to the terminating nullptr character of path.
+ */
+ if (_Ext)
+ {
+ length = (size_t)(tmp - dot);
+ if (_ExtSize <= length)
+ {
+ goto error_erange;
+ }
+ strncpy_s(_Ext, _ExtSize, dot, length);
+ }
+ }
+ else
+ {
+ /* found no extension, give empty extension and copy rest of
+ * string into fname.
+ */
+ if (_Filename)
+ {
+ length = (size_t)(tmp - _Path);
+ if (_FilenameSize <= length)
+ {
+ goto error_erange;
+ }
+ strncpy_s(_Filename, _FilenameSize, _Path, length);
+ }
+ if (_Ext)
+ {
+ _SAFECRT__RESET_STRING(_Ext, _ExtSize);
+ }
+ }
+
+ return 0;
+
+error_einval:
+ bEinval = 1;
+
+error_erange:
+ if (_Drive != nullptr && _DriveSize > 0)
+ {
+ _SAFECRT__RESET_STRING(_Drive, _DriveSize);
+ }
+ if (_Dir != nullptr && _DirSize > 0)
+ {
+ _SAFECRT__RESET_STRING(_Dir, _DirSize);
+ }
+ if (_Filename != nullptr && _FilenameSize > 0)
+ {
+ _SAFECRT__RESET_STRING(_Filename, _FilenameSize);
+ }
+ if (_Ext != nullptr && _ExtSize > 0)
+ {
+ _SAFECRT__RESET_STRING(_Ext, _ExtSize);
+ }
+
+ if (bEinval)
+ {
+ _SAFECRT__RETURN_EINVAL;
+ }
+
+ _SAFECRT__RETURN_BUFFER_TOO_SMALL(_Strings, _StringSizes);
+ /* should never happen, but compiler can't tell */
+ return EINVAL;
+}
+#endif
+
+/* _wsplitpath_s */
+_SAFECRT__EXTERN_C
+errno_t __cdecl _wsplitpath_s(
+ const WCHAR *_Path,
+ WCHAR *_Drive, size_t _DriveSize,
+ WCHAR *_Dir, size_t _DirSize,
+ WCHAR *_Filename, size_t _FilenameSize,
+ WCHAR *_Ext, size_t _ExtSize
+);
+
+/* no C++ overload for _wsplitpath_s */
+
+#if _SAFECRT_USE_INLINES || _SAFECRT_IMPL
+
+_SAFECRT__INLINE
+errno_t __cdecl _wsplitpath_s(
+ const WCHAR *_Path,
+ WCHAR *_Drive, size_t _DriveSize,
+ WCHAR *_Dir, size_t _DirSize,
+ WCHAR *_Filename, size_t _FilenameSize,
+ WCHAR *_Ext, size_t _ExtSize
+)
+{
+ const WCHAR *tmp;
+ const WCHAR *last_slash;
+ const WCHAR *dot;
+ int drive_set = 0;
+ size_t length = 0;
+ int bEinval = 0;
+
+ /* validation section */
+ _SAFECRT__VALIDATE_POINTER(_Path);
+ if ((_Drive == nullptr && _DriveSize != 0) || (_Drive != nullptr && _DriveSize == 0))
+ {
+ goto error_einval;
+ }
+ if ((_Dir == nullptr && _DirSize != 0) || (_Dir != nullptr && _DirSize == 0))
+ {
+ goto error_einval;
+ }
+ if ((_Filename == nullptr && _FilenameSize != 0) || (_Filename != nullptr && _FilenameSize == 0))
+ {
+ goto error_einval;
+ }
+ if ((_Ext == nullptr && _ExtSize != 0) || (_Ext != nullptr && _ExtSize == 0))
+ {
+ goto error_einval;
+ }
+
+ /* check if _Path begins with the longpath prefix */
+ if (_Path[0] == L'\\' && _Path[1] == L'\\' && _Path[2] == L'?' && _Path[3] == L'\\')
+ {
+ _Path += 4;
+ }
+
+ /* extract drive letter and ':', if any */
+ if (!drive_set)
+ {
+ size_t skip = _MAX_DRIVE - 2;
+ tmp = _Path;
+ while (skip > 0 && *tmp != 0)
+ {
+ skip--;
+ tmp++;
+ }
+ if (*tmp == L':')
+ {
+ if (_Drive != nullptr)
+ {
+ if (_DriveSize < _MAX_DRIVE)
+ {
+ goto error_erange;
+ }
+ wcsncpy_s(_Drive, _DriveSize, _Path, _MAX_DRIVE - 1);
+ }
+ _Path = tmp + 1;
+ }
+ else
+ {
+ if (_Drive != nullptr)
+ {
+ _SAFECRT__RESET_STRING(_Drive, _DriveSize);
+ }
+ }
+ }
+
+ /* extract path string, if any. _Path now points to the first character
+ * of the path, if any, or the filename or extension, if no path was
+ * specified. Scan ahead for the last occurence, if any, of a '/' or
+ * '\' path separator character. If none is found, there is no path.
+ * We will also note the last '.' character found, if any, to aid in
+ * handling the extension.
+ */
+ last_slash = nullptr;
+ dot = nullptr;
+ tmp = _Path;
+ for (; *tmp != 0; ++tmp)
+ {
+ {
+ if (*tmp == L'/' || *tmp == L'\\')
+ {
+ /* point to one beyond for later copy */
+ last_slash = tmp + 1;
+ }
+ else if (*tmp == L'.')
+ {
+ dot = tmp;
+ }
+ }
+ }
+
+ if (last_slash != nullptr)
+ {
+ /* found a path - copy up through last_slash or max characters
+ * allowed, whichever is smaller
+ */
+ if (_Dir != nullptr) {
+ length = (size_t)(last_slash - _Path);
+ if (_DirSize <= length)
+ {
+ goto error_erange;
+ }
+ wcsncpy_s(_Dir, _DirSize, _Path, length);
+ }
+ _Path = last_slash;
+ }
+ else
+ {
+ /* there is no path */
+ if (_Dir != nullptr)
+ {
+ _SAFECRT__RESET_STRING(_Dir, _DirSize);
+ }
+ }
+
+ /* extract file name and extension, if any. Path now points to the
+ * first character of the file name, if any, or the extension if no
+ * file name was given. Dot points to the '.' beginning the extension,
+ * if any.
+ */
+ if (dot != nullptr && (dot >= _Path))
+ {
+ /* found the marker for an extension - copy the file name up to the '.' */
+ if (_Filename)
+ {
+ length = (size_t)(dot - _Path);
+ if (_FilenameSize <= length)
+ {
+ goto error_erange;
+ }
+ wcsncpy_s(_Filename, _FilenameSize, _Path, length);
+ }
+ /* now we can get the extension - remember that tmp still points
+ * to the terminating nullptr character of path.
+ */
+ if (_Ext)
+ {
+ length = (size_t)(tmp - dot);
+ if (_ExtSize <= length)
+ {
+ goto error_erange;
+ }
+ wcsncpy_s(_Ext, _ExtSize, dot, length);
+ }
+ }
+ else
+ {
+ /* found no extension, give empty extension and copy rest of
+ * string into fname.
+ */
+ if (_Filename)
+ {
+ length = (size_t)(tmp - _Path);
+ if (_FilenameSize <= length)
+ {
+ goto error_erange;
+ }
+ wcsncpy_s(_Filename, _FilenameSize, _Path, length);
+ }
+ if (_Ext)
+ {
+ _SAFECRT__RESET_STRING(_Ext, _ExtSize);
+ }
+ }
+
+ return 0;
+
+error_einval:
+ bEinval = 1;
+
+error_erange:
+ if (_Drive != nullptr && _DriveSize > 0)
+ {
+ _SAFECRT__RESET_STRING(_Drive, _DriveSize);
+ }
+ if (_Dir != nullptr && _DirSize > 0)
+ {
+ _SAFECRT__RESET_STRING(_Dir, _DirSize);
+ }
+ if (_Filename != nullptr && _FilenameSize > 0)
+ {
+ _SAFECRT__RESET_STRING(_Filename, _FilenameSize);
+ }
+ if (_Ext != nullptr && _ExtSize > 0)
+ {
+ _SAFECRT__RESET_STRING(_Ext, _ExtSize);
+ }
+
+ if (bEinval)
+ {
+ _SAFECRT__RETURN_EINVAL;
+ }
+
+ _SAFECRT__RETURN_BUFFER_TOO_SMALL(_Strings, _StringSizes);
+ /* should never happen, but compiler can't tell */
+ return EINVAL;
+}
+#endif
+
+/* sprintf_s, vsprintf_s */
+/*
+ * sprintf_s, swprintf_s, vsprintf_s, vswprintf_s format a string and copy it into _Dst;
+ * need safecrt.lib and msvcrt.dll;
+ * will call _SAFECRT_INVALID_PARAMETER if there is not enough space in _Dst;
+ * will call _SAFECRT_INVALID_PARAMETER if the format string is malformed;
+ * the %n format type is not allowed;
+ * return the length of string _Dst;
+ * return a negative number if something goes wrong with mbcs conversions (we will not call _SAFECRT_INVALID_PARAMETER);
+ * _SizeInBytes/_SizeInWords must be <= (INT_MAX / sizeof(char/WCHAR));
+ * cannot be used without safecrt.lib
+ */
+_SAFECRT__EXTERN_C
+int __cdecl sprintf_s(char *_Dst, size_t _SizeInBytes, const char *_Format, ...);
+_SAFECRT__EXTERN_C
+int __cdecl vsprintf_s(char *_Dst, size_t _SizeInBytes, const char *_Format, va_list _ArgList);
+
+#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS
+template <size_t _SizeInBytes>
+inline
+int __cdecl sprintf_s(char (&_Dst)[_SizeInBytes], const char *_Format, ...)
+{
+ int ret;
+ va_list _ArgList;
+ va_start(_ArgList, _Format);
+ ret = vsprintf_s(_Dst, _SizeInBytes, _Format, _ArgList);
+ va_end(_ArgList);
+ return ret;
+}
+
+template <size_t _SizeInBytes>
+inline
+int __cdecl vsprintf_s(char (&_Dst)[_SizeInBytes], const char *_Format, va_list _ArgList)
+{
+ return vsprintf_s(_Dst, _SizeInBytes, _Format, _ArgList);
+}
+#endif
+
+/* no inline version of sprintf_s, vsprintf_s */
+
+/* swprintf_s, vswprintf_s */
+_SAFECRT__EXTERN_C
+int __cdecl swprintf_s(WCHAR *_Dst, size_t _SizeInWords, const WCHAR *_Format, ...);
+_SAFECRT__EXTERN_C
+int __cdecl vswprintf_s(WCHAR *_Dst, size_t _SizeInWords, const WCHAR *_Format, va_list _ArgList);
+
+#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS
+template <size_t _SizeInWords>
+inline
+int __cdecl swprintf_s(char (&_Dst)[_SizeInWords], const char *_Format, ...)
+{
+ int ret;
+ va_list _ArgList;
+ va_start(_ArgList, _Format);
+ ret = vswprintf_s(_Dst, _SizeInWords, _Format, _ArgList);
+ va_end(_ArgList);
+ return ret;
+}
+
+template <size_t _SizeInWords>
+inline
+int __cdecl vswprintf_s(char (&_Dst)[_SizeInWords], const char *_Format, va_list _ArgList)
+{
+ return vswprintf_s(_Dst, _SizeInWords, _Format, _ArgList);
+}
+#endif
+
+/* no inline version of swprintf_s, vswprintf_s */
+
+/* _snprintf_s, _vsnprintf_s */
+/*
+ * _snprintf_s, _snwprintf_s, _vsnprintf_s, _vsnwprintf_s format a string and copy at max _Count characters into _Dst;
+ * need safecrt.lib and msvcrt.dll;
+ * string _Dst will always be null-terminated;
+ * will call _SAFECRT_INVALID_PARAMETER if there is not enough space in _Dst;
+ * will call _SAFECRT_INVALID_PARAMETER if the format string is malformed;
+ * the %n format type is not allowed;
+ * return the length of string _Dst;
+ * return a negative number if something goes wrong with mbcs conversions (we will not call _SAFECRT_INVALID_PARAMETER);
+ * _SizeInBytes/_SizeInWords must be <= (INT_MAX / sizeof(char/WCHAR));
+ * cannot be used without safecrt.lib;
+ * if _Count == _TRUNCATE, we will copy into _Dst as many characters as we can, and
+ * return -1 if the formatted string does not entirely fit into _Dst (we will not call _SAFECRT_INVALID_PARAMETER);
+ * if _Count == 0, then (_Dst == nullptr && _SizeInBytes == 0) is allowed
+ */
+_SAFECRT__EXTERN_C
+int __cdecl _snprintf_s(char *_Dst, size_t _SizeInBytes, size_t _Count, const char *_Format, ...);
+_SAFECRT__EXTERN_C
+int __cdecl _vsnprintf_s(char *_Dst, size_t _SizeInBytes, size_t _Count, const char *_Format, va_list _ArgList);
+
+#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS
+template <size_t _SizeInBytes>
+inline
+int __cdecl _snprintf_s(char (&_Dst)[_SizeInBytes], size_t _Count, const char *_Format, ...)
+{
+ int ret;
+ va_list _ArgList;
+ va_start(_ArgList, _Format);
+ ret = _vsnprintf_s(_Dst, _SizeInBytes, _Count, _Format, _ArgList);
+ va_end(_ArgList);
+ return ret;
+}
+
+template <size_t _SizeInBytes>
+inline
+int __cdecl _vsnprintf_s(char (&_Dst)[_SizeInBytes], size_t _Count, const char *_Format, va_list _ArgList)
+{
+ return _vsnprintf_s(_Dst, _SizeInBytes, _Count, _Format, _ArgList);
+}
+#endif
+
+/* no inline version of _snprintf_s, _vsnprintf_s */
+
+/* _snwprintf_s, _vsnwprintf_s */
+_SAFECRT__EXTERN_C
+int __cdecl _snwprintf_s(WCHAR *_Dst, size_t _SizeInWords, size_t _Count, const WCHAR *_Format, ...);
+_SAFECRT__EXTERN_C
+int __cdecl _vsnwprintf_s(WCHAR *_Dst, size_t _SizeInWords, size_t _Count, const WCHAR *_Format, va_list _ArgList);
+
+#if defined(__cplusplus) && _SAFECRT_USE_CPP_OVERLOADS
+template <size_t _SizeInWords>
+inline
+int __cdecl _snwprintf_s(char (&_Dst)[_SizeInWords], size_t _Count, const char *_Format, ...)
+{
+ int ret;
+ va_list _ArgList;
+ va_start(_ArgList, _Format);
+ ret = _vsnwprintf_s(_Dst, _SizeInWords, _Count, _Format, _ArgList);
+ va_end(_ArgList);
+ return ret;
+}
+
+template <size_t _SizeInWords>
+inline
+int __cdecl _vsnwprintf_s(char (&_Dst)[_SizeInWords], size_t _Count, const char *_Format, va_list _ArgList)
+{
+ return _vsnwprintf_s(_Dst, _SizeInWords, _Count, _Format, _ArgList);
+}
+#endif
+
+/* no inline version of _snwprintf_s, _vsnwprintf_s */
+
+/* scanf_s */
+/*
+ * read formatted data from the standard input stream;
+ * need safecrt.lib and msvcrt.dll;
+ * will call _SAFECRT_INVALID_PARAMETER if the format string is malformed;
+ * for format types %s, %S, %[, %c and %C, in the argument list the buffer pointer
+ * need to be followed by the size of the buffer, e.g.:
+ * #define BUFFSIZE 100
+ * char buff[BUFFSIZE];
+ * scanf_s("%s", buff, BUFFSIZE);
+ * as scanf, returns the number of fields successfully converted and assigned;
+ * if a buffer field is too small, scanf set the buffer to the empty string and returns.
+ * do not support floating-point, for now
+ */
+_SAFECRT__EXTERN_C
+int __cdecl scanf_s(const char *_Format, ...);
+
+/* no C++ overload for scanf_s */
+
+/* no inline version of scanf_s */
+
+/* wscanf_s */
+_SAFECRT__EXTERN_C
+int __cdecl wscanf_s(const WCHAR *_Format, ...);
+
+/* no C++ overload for wscanf_s */
+
+/* no inline version of wscanf_s */
+
+/* sscanf_s */
+_SAFECRT__EXTERN_C
+int __cdecl sscanf_s(const char *_String, const char *_Format, ...);
+
+/* no C++ overload for sscanf_s */
+
+/* no inline version of sscanf_s */
+
+/* swscanf_s */
+_SAFECRT__EXTERN_C
+int __cdecl swscanf_s(const WCHAR *_String, const WCHAR *_Format, ...);
+
+/* no C++ overload for swscanf_s */
+
+/* no inline version of swscanf_s */
+
+/* _snscanf_s */
+_SAFECRT__EXTERN_C
+int __cdecl _snscanf_s(const char *_String, size_t _Count, const char *_Format, ...);
+
+/* no C++ overload for snscanf_s */
+
+/* no inline version of snscanf_s */
+
+/* _swnscanf_s */
+_SAFECRT__EXTERN_C
+int __cdecl _swnscanf_s(const WCHAR *_String, size_t _Count, const WCHAR *_Format, ...);
+
+/* no C++ overload for _swnscanf_s */
+
+/* no inline version of _swnscanf_s */
+
+//#endif /* ndef _SAFECRT_IMPL */
+
+#endif /* _INC_SAFECRT */
diff --git a/src/pal/inc/rt/sal.h b/src/pal/inc/rt/sal.h
new file mode 100644
index 0000000000..0e3eaaa388
--- /dev/null
+++ b/src/pal/inc/rt/sal.h
@@ -0,0 +1,2957 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*sal.h - markers for documenting the semantics of APIs
+*
+
+*
+*Purpose:
+* sal.h provides a set of annotations to describe how a function uses its
+* parameters - the assumptions it makes about them, and the guarantees it makes
+* upon finishing.
+****/
+#pragma once
+
+/*==========================================================================
+
+ The comments in this file are intended to give basic understanding of
+ the usage of SAL, the Microsoft Source Code Annotation Language.
+ For more details, please see http://go.microsoft.com/fwlink/?LinkID=242134
+
+ The macros are defined in 3 layers, plus the structural set:
+
+ _In_/_Out_/_Ret_ Layer:
+ ----------------------
+ This layer provides the highest abstraction and its macros should be used
+ in most cases. These macros typically start with:
+ _In_ : input parameter to a function, unmodified by called function
+ _Out_ : output parameter, written to by called function, pointed-to
+ location not expected to be initialized prior to call
+ _Outptr_ : like _Out_ when returned variable is a pointer type
+ (so param is pointer-to-pointer type). Called function
+ provides/allocated space.
+ _Outref_ : like _Outptr_, except param is reference-to-pointer type.
+ _Inout_ : inout parameter, read from and potentially modified by
+ called function.
+ _Ret_ : for return values
+ _Field_ : class/struct field invariants
+ For common usage, this class of SAL provides the most concise annotations.
+ Note that _In_/_Out_/_Inout_/_Outptr_ annotations are designed to be used
+ with a parameter target. Using them with _At_ to specify non-parameter
+ targets may yield unexpected results.
+
+ This layer also includes a number of other properties that can be specified
+ to extend the ability of code analysis, most notably:
+ -- Designating parameters as format strings for printf/scanf/scanf_s
+ -- Requesting stricter type checking for C enum parameters
+
+ _Pre_/_Post_ Layer:
+ ------------------
+ The macros of this layer only should be used when there is no suitable macro
+ in the _In_/_Out_ layer. Its macros start with _Pre_ or _Post_.
+ This layer provides the most flexibility for annotations.
+
+ Implementation Abstraction Layer:
+ --------------------------------
+ Macros from this layer should never be used directly. The layer only exists
+ to hide the implementation of the annotation macros.
+
+ Structural Layer:
+ ----------------
+ These annotations, like _At_ and _When_, are used with annotations from
+ any of the other layers as modifiers, indicating exactly when and where
+ the annotations apply.
+
+
+ Common syntactic conventions:
+ ----------------------------
+
+ Usage:
+ -----
+ _In_, _Out_, _Inout_, _Pre_, _Post_, are for formal parameters.
+ _Ret_, _Deref_ret_ must be used for return values.
+
+ Nullness:
+ --------
+ If the parameter can be NULL as a precondition to the function, the
+ annotation contains _opt. If the macro does not contain '_opt' the
+ parameter cannot be NULL.
+
+ If an out/inout parameter returns a null pointer as a postcondition, this is
+ indicated by _Ret_maybenull_ or _result_maybenull_. If the macro is not
+ of this form, then the result will not be NULL as a postcondition.
+ _Outptr_ - output value is not NULL
+ _Outptr_result_maybenull_ - output value might be NULL
+
+ String Type:
+ -----------
+ _z: NullTerminated string
+ for _In_ parameters the buffer must have the specified stringtype before the call
+ for _Out_ parameters the buffer must have the specified stringtype after the call
+ for _Inout_ parameters both conditions apply
+
+ Extent Syntax:
+ -------------
+ Buffer sizes are expressed as element counts, unless the macro explicitly
+ contains _byte_ or _bytes_. Some annotations specify two buffer sizes, in
+ which case the second is used to indicate how much of the buffer is valid
+ as a postcondition. This table outlines the precondition buffer allocation
+ size, precondition number of valid elements, postcondition allocation size,
+ and postcondition number of valid elements for representative buffer size
+ annotations:
+ Pre | Pre | Post | Post
+ alloc | valid | alloc | valid
+ Annotation elems | elems | elems | elems
+ ---------- ------------------------------------
+ _In_reads_(s) s | s | s | s
+ _Inout_updates_(s) s | s | s | s
+ _Inout_updates_to_(s,c) s | s | s | c
+ _Out_writes_(s) s | 0 | s | s
+ _Out_writes_to_(s,c) s | 0 | s | c
+ _Outptr_result_buffer_(s) ? | ? | s | s
+ _Outptr_result_buffer_to_(s,c) ? | ? | s | c
+
+ For the _Outptr_ annotations, the buffer in question is at one level of
+ dereference. The called function is responsible for supplying the buffer.
+
+ Success and failure:
+ -------------------
+ The SAL concept of success allows functions to define expressions that can
+ be tested by the caller, which if it evaluates to non-zero, indicates the
+ function succeeded, which means that its postconditions are guaranteed to
+ hold. Otherwise, if the expression evaluates to zero, the function is
+ considered to have failed, and the postconditions are not guaranteed.
+
+ The success criteria can be specified with the _Success_(expr) annotation:
+ _Success_(return != FALSE) BOOL
+ PathCanonicalizeA(_Out_writes_(MAX_PATH) LPSTR pszBuf, LPCSTR pszPath) :
+ pszBuf is only guaranteed to be NULL-terminated when TRUE is returned,
+ and FALSE indiates failure. In common practice, callers check for zero
+ vs. non-zero returns, so it is preferable to express the success
+ criteria in terms of zero/non-zero, not checked for exactly TRUE.
+
+ Functions can specify that some postconditions will still hold, even when
+ the function fails, using _On_failure_(anno-list), or postconditions that
+ hold regardless of success or failure using _Always_(anno-list).
+
+ The annotation _Return_type_success_(expr) may be used with a typedef to
+ give a default _Success_ criteria to all functions returning that type.
+ This is the case for common Windows API status types, including
+ HRESULT and NTSTATUS. This may be overridden on a per-function basis by
+ specifying a _Success_ annotation locally.
+
+============================================================================*/
+
+#define __ATTR_SAL
+
+#ifndef _SAL_VERSION /*IFSTRIP=IGN*/
+#define _SAL_VERSION 20
+#endif
+
+#ifdef _PREFAST_ // [
+
+// choose attribute or __declspec implementation
+#ifndef _USE_DECLSPECS_FOR_SAL // [
+#define _USE_DECLSPECS_FOR_SAL 1
+#endif // ]
+
+#if _USE_DECLSPECS_FOR_SAL // [
+#undef _USE_ATTRIBUTES_FOR_SAL
+#define _USE_ATTRIBUTES_FOR_SAL 0
+#elif !defined(_USE_ATTRIBUTES_FOR_SAL) // ][
+#if _MSC_VER >= 1400 /*IFSTRIP=IGN*/ // [
+#define _USE_ATTRIBUTES_FOR_SAL 1
+#else // ][
+#define _USE_ATTRIBUTES_FOR_SAL 0
+#endif // ]
+#endif // ]
+
+
+#if !_USE_DECLSPECS_FOR_SAL // [
+#if !_USE_ATTRIBUTES_FOR_SAL // [
+#if _MSC_VER >= 1400 /*IFSTRIP=IGN*/ // [
+#undef _USE_ATTRIBUTES_FOR_SAL
+#define _USE_ATTRIBUTES_FOR_SAL 1
+#else // ][
+#undef _USE_DECLSPECS_FOR_SAL
+#define _USE_DECLSPECS_FOR_SAL 1
+#endif // ]
+#endif // ]
+#endif // ]
+
+#else
+
+// Disable expansion of SAL macros in non-Prefast mode to
+// improve compiler throughput.
+#ifndef _USE_DECLSPECS_FOR_SAL // [
+#define _USE_DECLSPECS_FOR_SAL 0
+#endif // ]
+#ifndef _USE_ATTRIBUTES_FOR_SAL // [
+#define _USE_ATTRIBUTES_FOR_SAL 0
+#endif // ]
+
+#endif // ]
+
+// safeguard for MIDL and RC builds
+#if _USE_DECLSPECS_FOR_SAL && ( defined( MIDL_PASS ) || defined(__midl) || defined(RC_INVOKED) || !defined(_PREFAST_) ) /*IFSTRIP=IGN*/ // [
+#undef _USE_DECLSPECS_FOR_SAL
+#define _USE_DECLSPECS_FOR_SAL 0
+#endif // ]
+#if _USE_ATTRIBUTES_FOR_SAL && ( !defined(_MSC_EXTENSIONS) || defined( MIDL_PASS ) || defined(__midl) || defined(RC_INVOKED) ) /*IFSTRIP=IGN*/ // [
+#undef _USE_ATTRIBUTES_FOR_SAL
+#define _USE_ATTRIBUTES_FOR_SAL 0
+#endif // ]
+
+#if _USE_DECLSPECS_FOR_SAL || _USE_ATTRIBUTES_FOR_SAL
+
+// Special enum type for Y/N/M
+enum __SAL_YesNo {_SAL_notpresent, _SAL_no, _SAL_maybe, _SAL_yes, _SAL_default};
+
+#endif
+
+#if defined(BUILD_WINDOWS) && !_USE_ATTRIBUTES_FOR_SAL /*IFSTRIP=IGN*/
+#define _SAL1_Source_(Name, args, annotes) _SA_annotes3(SAL_name, #Name, "", "1") _GrouP_(annotes _SAL_nop_impl_)
+#define _SAL1_1_Source_(Name, args, annotes) _SA_annotes3(SAL_name, #Name, "", "1.1") _GrouP_(annotes _SAL_nop_impl_)
+#define _SAL1_2_Source_(Name, args, annotes) _SA_annotes3(SAL_name, #Name, "", "1.2") _GrouP_(annotes _SAL_nop_impl_)
+#define _SAL2_Source_(Name, args, annotes) _SA_annotes3(SAL_name, #Name, "", "2") _GrouP_(annotes _SAL_nop_impl_)
+#else
+#define _SAL1_Source_(Name, args, annotes) _SA_annotes3(SAL_name, #Name, "", "1") _Group_(annotes _SAL_nop_impl_)
+#define _SAL1_1_Source_(Name, args, annotes) _SA_annotes3(SAL_name, #Name, "", "1.1") _Group_(annotes _SAL_nop_impl_)
+#define _SAL1_2_Source_(Name, args, annotes) _SA_annotes3(SAL_name, #Name, "", "1.2") _Group_(annotes _SAL_nop_impl_)
+#define _SAL2_Source_(Name, args, annotes) _SA_annotes3(SAL_name, #Name, "", "2") _Group_(annotes _SAL_nop_impl_)
+#endif
+
+//============================================================================
+// Structural SAL:
+// These annotations modify the use of other annotations. They may
+// express the annotation target (i.e. what parameter/field the annotation
+// applies to) or the condition under which the annotation is applicable.
+//============================================================================
+
+// _At_(target, annos) specifies that the annotations listed in 'annos' is to
+// be applied to 'target' rather than to the identifier which is the current
+// lexical target.
+#define _At_(target, annos) _At_impl_(target, annos _SAL_nop_impl_)
+
+// _At_buffer_(target, iter, bound, annos) is similar to _At_, except that
+// target names a buffer, and each annotation in annos is applied to each
+// element of target up to bound, with the variable named in iter usable
+// by the annotations to refer to relevant offsets within target.
+#define _At_buffer_(target, iter, bound, annos) _At_buffer_impl_(target, iter, bound, annos _SAL_nop_impl_)
+
+// _When_(expr, annos) specifies that the annotations listed in 'annos' only
+// apply when 'expr' evaluates to non-zero.
+#define _When_(expr, annos) _When_impl_(expr, annos _SAL_nop_impl_)
+#define _Group_(annos) _Group_impl_(annos _SAL_nop_impl_)
+#define _GrouP_(annos) _GrouP_impl_(annos _SAL_nop_impl_)
+
+// <expr> indicates whether normal post conditions apply to a function
+#define _Success_(expr) _SAL2_Source_(_Success_, (expr), _Success_impl_(expr))
+
+// <expr> indicates whether post conditions apply to a function returning
+// the type that this annotation is applied to
+#define _Return_type_success_(expr) _SAL2_Source_(_Return_type_success_, (expr), _Success_impl_(expr))
+
+// Establish postconditions that apply only if the function does not succeed
+#define _On_failure_(annos) _On_failure_impl_(annos _SAL_nop_impl_)
+
+// Establish postconditions that apply in both success and failure cases.
+// Only applicable with functions that have _Success_ or _Return_type_succss_.
+#define _Always_(annos) _Always_impl_(annos _SAL_nop_impl_)
+
+// Usable on a function defintion. Asserts that a function declaration is
+// in scope, and its annotations are to be used. There are no other annotations
+// allowed on the function definition.
+#define _Use_decl_annotations_ _Use_decl_anno_impl_
+
+// _Notref_ may precede a _Deref_ or "real" annotation, and removes one
+// level of dereference if the parameter is a C++ reference (&). If the
+// net deref on a "real" annotation is negative, it is simply discarded.
+#define _Notref_ _Notref_impl_
+
+// Annotations for defensive programming styles.
+#define _Pre_defensive_ _SA_annotes0(SAL_pre_defensive)
+#define _Post_defensive_ _SA_annotes0(SAL_post_defensive)
+
+#define _In_defensive_(annotes) _Pre_defensive_ _Group_(annotes)
+#define _Out_defensive_(annotes) _Post_defensive_ _Group_(annotes)
+#define _Inout_defensive_(annotes) _Pre_defensive_ _Post_defensive_ _Group_(annotes)
+
+//============================================================================
+// _In_\_Out_ Layer:
+//============================================================================
+
+// Reserved pointer parameters, must always be NULL.
+#define _Reserved_ _SAL2_Source_(_Reserved_, (), _Pre1_impl_(__null_impl))
+
+// _Const_ allows specification that any namable memory location is considered
+// readonly for a given call.
+#define _Const_ _SAL2_Source_(_Const_, (), _Pre1_impl_(__readaccess_impl_notref))
+
+
+// Input parameters --------------------------
+
+// _In_ - Annotations for parameters where data is passed into the function, but not modified.
+// _In_ by itself can be used with non-pointer types (although it is redundant).
+
+// e.g. void SetPoint( _In_ const POINT* pPT );
+#define _In_ _SAL2_Source_(_In_, (), _Pre1_impl_(__notnull_impl_notref) _Pre_valid_impl_ _Deref_pre1_impl_(__readaccess_impl_notref))
+#define _In_opt_ _SAL2_Source_(_In_opt_, (), _Pre1_impl_(__maybenull_impl_notref) _Pre_valid_impl_ _Deref_pre_readonly_)
+
+// nullterminated 'in' parameters.
+// e.g. void CopyStr( _In_z_ const char* szFrom, _Out_z_cap_(cchTo) char* szTo, size_t cchTo );
+#define _In_z_ _SAL2_Source_(_In_z_, (), _In_ _Pre1_impl_(__zterm_impl))
+#define _In_opt_z_ _SAL2_Source_(_In_opt_z_, (), _In_opt_ _Pre1_impl_(__zterm_impl))
+
+
+// 'input' buffers with given size
+
+#define _In_reads_(size) _SAL2_Source_(_In_reads_, (size), _Pre_count_(size) _Deref_pre_readonly_)
+#define _In_reads_opt_(size) _SAL2_Source_(_In_reads_opt_, (size), _Pre_opt_count_(size) _Deref_pre_readonly_)
+#define _In_reads_bytes_(size) _SAL2_Source_(_In_reads_bytes_, (size), _Pre_bytecount_(size) _Deref_pre_readonly_)
+#define _In_reads_bytes_opt_(size) _SAL2_Source_(_In_reads_bytes_opt_, (size), _Pre_opt_bytecount_(size) _Deref_pre_readonly_)
+#define _In_reads_z_(size) _SAL2_Source_(_In_reads_z_, (size), _In_reads_(size) _Pre_z_)
+#define _In_reads_opt_z_(size) _SAL2_Source_(_In_reads_opt_z_, (size), _Pre_opt_count_(size) _Deref_pre_readonly_ _Pre_opt_z_)
+#define _In_reads_or_z_(size) _SAL2_Source_(_In_reads_or_z_, (size), _In_ _When_(_String_length_(_Curr_) < (size), _Pre_z_) _When_(_String_length_(_Curr_) >= (size), _Pre1_impl_(__count_impl(size))))
+#define _In_reads_or_z_opt_(size) _SAL2_Source_(_In_reads_or_z_opt_, (size), _In_opt_ _When_(_String_length_(_Curr_) < (size), _Pre_z_) _When_(_String_length_(_Curr_) >= (size), _Pre1_impl_(__count_impl(size))))
+
+
+// 'input' buffers valid to the given end pointer
+
+#define _In_reads_to_ptr_(ptr) _SAL2_Source_(_In_reads_to_ptr_, (ptr), _Pre_ptrdiff_count_(ptr) _Deref_pre_readonly_)
+#define _In_reads_to_ptr_opt_(ptr) _SAL2_Source_(_In_reads_to_ptr_opt_, (ptr), _Pre_opt_ptrdiff_count_(ptr) _Deref_pre_readonly_)
+#define _In_reads_to_ptr_z_(ptr) _SAL2_Source_(_In_reads_to_ptr_z_, (ptr), _In_reads_to_ptr_(ptr) _Pre_z_)
+#define _In_reads_to_ptr_opt_z_(ptr) _SAL2_Source_(_In_reads_to_ptr_opt_z_, (ptr), _Pre_opt_ptrdiff_count_(ptr) _Deref_pre_readonly_ _Pre_opt_z_)
+
+
+
+// Output parameters --------------------------
+
+// _Out_ - Annotations for pointer or reference parameters where data passed back to the caller.
+// These are mostly used where the pointer/reference is to a non-pointer type.
+// _Outptr_/_Outref) (see below) are typically used to return pointers via parameters.
+
+// e.g. void GetPoint( _Out_ POINT* pPT );
+#define _Out_ _SAL2_Source_(_Out_, (), _Out_impl_)
+#define _Out_opt_ _SAL2_Source_(_Out_opt_, (), _Out_opt_impl_)
+
+#define _Out_writes_(size) _SAL2_Source_(_Out_writes_, (size), _Pre_cap_(size) _Post_valid_impl_)
+#define _Out_writes_opt_(size) _SAL2_Source_(_Out_writes_opt_, (size), _Pre_opt_cap_(size) _Post_valid_impl_)
+#define _Out_writes_bytes_(size) _SAL2_Source_(_Out_writes_bytes_, (size), _Pre_bytecap_(size) _Post_valid_impl_)
+#define _Out_writes_bytes_opt_(size) _SAL2_Source_(_Out_writes_bytes_opt_, (size), _Pre_opt_bytecap_(size) _Post_valid_impl_)
+#define _Out_writes_z_(size) _SAL2_Source_(_Out_writes_z_, (size), _Pre_cap_(size) _Post_valid_impl_ _Post_z_)
+#define _Out_writes_opt_z_(size) _SAL2_Source_(_Out_writes_opt_z_, (size), _Pre_opt_cap_(size) _Post_valid_impl_ _Post_z_)
+
+#define _Out_writes_to_(size,count) _SAL2_Source_(_Out_writes_to_, (size,count), _Pre_cap_(size) _Post_valid_impl_ _Post_count_(count))
+#define _Out_writes_to_opt_(size,count) _SAL2_Source_(_Out_writes_to_opt_, (size,count), _Pre_opt_cap_(size) _Post_valid_impl_ _Post_count_(count))
+#define _Out_writes_all_(size) _SAL2_Source_(_Out_writes_all_, (size), _Out_writes_to_(_Old_(size), _Old_(size)))
+#define _Out_writes_all_opt_(size) _SAL2_Source_(_Out_writes_all_opt_, (size), _Out_writes_to_opt_(_Old_(size), _Old_(size)))
+
+#define _Out_writes_bytes_to_(size,count) _SAL2_Source_(_Out_writes_bytes_to_, (size,count), _Pre_bytecap_(size) _Post_valid_impl_ _Post_bytecount_(count))
+#define _Out_writes_bytes_to_opt_(size,count) _SAL2_Source_(_Out_writes_bytes_to_opt_, (size,count), _Pre_opt_bytecap_(size) _Post_valid_impl_ _Post_bytecount_(count))
+#define _Out_writes_bytes_all_(size) _SAL2_Source_(_Out_writes_bytes_all_, (size), _Out_writes_bytes_to_(_Old_(size), _Old_(size)))
+#define _Out_writes_bytes_all_opt_(size) _SAL2_Source_(_Out_writes_bytes_all_opt_, (size), _Out_writes_bytes_to_opt_(_Old_(size), _Old_(size)))
+
+#define _Out_writes_to_ptr_(ptr) _SAL2_Source_(_Out_writes_to_ptr_, (ptr), _Pre_ptrdiff_cap_(ptr) _Post_valid_impl_)
+#define _Out_writes_to_ptr_opt_(ptr) _SAL2_Source_(_Out_writes_to_ptr_opt_, (ptr), _Pre_opt_ptrdiff_cap_(ptr) _Post_valid_impl_)
+#define _Out_writes_to_ptr_z_(ptr) _SAL2_Source_(_Out_writes_to_ptr_z_, (ptr), _Pre_ptrdiff_cap_(ptr) _Post_valid_impl_ Post_z_)
+#define _Out_writes_to_ptr_opt_z_(ptr) _SAL2_Source_(_Out_writes_to_ptr_opt_z_, (ptr), _Pre_opt_ptrdiff_cap_(ptr) _Post_valid_impl_ Post_z_)
+
+
+// Inout parameters ----------------------------
+
+// _Inout_ - Annotations for pointer or reference parameters where data is passed in and
+// potentially modified.
+// void ModifyPoint( _Inout_ POINT* pPT );
+// void ModifyPointByRef( _Inout_ POINT& pPT );
+
+#define _Inout_ _SAL2_Source_(_Inout_, (), _Prepost_valid_)
+#define _Inout_opt_ _SAL2_Source_(_Inout_opt_, (), _Prepost_opt_valid_)
+
+// For modifying string buffers
+// void toupper( _Inout_z_ char* sz );
+#define _Inout_z_ _SAL2_Source_(_Inout_z_, (), _Prepost_z_)
+#define _Inout_opt_z_ _SAL2_Source_(_Inout_opt_z_, (), _Prepost_opt_z_)
+
+// For modifying buffers with explicit element size
+#define _Inout_updates_(size) _SAL2_Source_(_Inout_updates_, (size), _Pre_cap_(size) _Pre_valid_impl_ _Post_valid_impl_)
+#define _Inout_updates_opt_(size) _SAL2_Source_(_Inout_updates_opt_, (size), _Pre_opt_cap_(size) _Pre_valid_impl_ _Post_valid_impl_)
+#define _Inout_updates_z_(size) _SAL2_Source_(_Inout_updates_z_, (size), _Pre_cap_(size) _Pre_valid_impl_ _Post_valid_impl_ _Pre1_impl_(__zterm_impl) _Post1_impl_(__zterm_impl))
+#define _Inout_updates_opt_z_(size) _SAL2_Source_(_Inout_updates_opt_z_, (size), _Pre_opt_cap_(size) _Pre_valid_impl_ _Post_valid_impl_ _Pre1_impl_(__zterm_impl) _Post1_impl_(__zterm_impl))
+
+#define _Inout_updates_to_(size,count) _SAL2_Source_(_Inout_updates_to_, (size,count), _Out_writes_to_(size,count) _Pre_valid_impl_ _Pre1_impl_(__count_impl(count)))
+#define _Inout_updates_to_opt_(size,count) _SAL2_Source_(_Inout_updates_to_opt_, (size,count), _Out_writes_to_opt_(size,count) _Pre_valid_impl_ _Pre1_impl_(__count_impl(count)))
+
+#define _Inout_updates_all_(size) _SAL2_Source_(_Inout_updates_all_, (size), _Inout_updates_to_(_Old_(size), _Old_(size)))
+#define _Inout_updates_all_opt_(size) _SAL2_Source_(_Inout_updates_all_opt_, (size), _Inout_updates_to_opt_(_Old_(size), _Old_(size)))
+
+// For modifying buffers with explicit byte size
+#define _Inout_updates_bytes_(size) _SAL2_Source_(_Inout_updates_bytes_, (size), _Pre_bytecap_(size) _Pre_valid_impl_ _Post_valid_impl_)
+#define _Inout_updates_bytes_opt_(size) _SAL2_Source_(_Inout_updates_bytes_opt_, (size), _Pre_opt_bytecap_(size) _Pre_valid_impl_ _Post_valid_impl_)
+
+#define _Inout_updates_bytes_to_(size,count) _SAL2_Source_(_Inout_updates_bytes_to_, (size,count), _Out_writes_bytes_to_(size,count) _Pre_valid_impl_ _Pre1_impl_(__bytecount_impl(count)))
+#define _Inout_updates_bytes_to_opt_(size,count) _SAL2_Source_(_Inout_updates_bytes_to_opt_, (size,count), _Out_writes_bytes_to_opt_(size,count) _Pre_valid_impl_ _Pre1_impl_(__bytecount_impl(count)))
+
+#define _Inout_updates_bytes_all_(size) _SAL2_Source_(_Inout_updates_bytes_all_, (size), _Inout_updates_bytes_to_(_Old_(size), _Old_(size)))
+#define _Inout_updates_bytes_all_opt_(size) _SAL2_Source_(_Inout_updates_bytes_all_opt_, (size), _Inout_updates_bytes_to_opt_(_Old_(size), _Old_(size)))
+
+
+// Pointer to pointer parameters -------------------------
+
+// _Outptr_ - Annotations for output params returning pointers
+// These describe parameters where the called function provides the buffer:
+// HRESULT SHStrDupW(_In_ LPCWSTR psz, _Outptr_ LPWSTR *ppwsz);
+// The caller passes the address of an LPWSTR variable as ppwsz, and SHStrDupW allocates
+// and initializes memory and returns the pointer to the new LPWSTR in *ppwsz.
+//
+// _Outptr_opt_ - describes parameters that are allowed to be NULL.
+// _Outptr_*_result_maybenull_ - describes parameters where the called function might return NULL to the caller.
+//
+// Example:
+// void MyFunc(_Outptr_opt_ int **ppData1, _Outptr_result_maybenull_ int **ppData2);
+// Callers:
+// MyFunc(NULL, NULL); // error: parameter 2, ppData2, should not be NULL
+// MyFunc(&pData1, &pData2); // ok: both non-NULL
+// if (*pData1 == *pData2) ... // error: pData2 might be NULL after call
+
+#define _Outptr_ _SAL2_Source_(_Outptr_, (), _Out_impl_ _Deref_post2_impl_(__notnull_impl_notref, __count_impl(1)))
+#define _Outptr_result_maybenull_ _SAL2_Source_(_Outptr_result_maybenull_, (), _Out_impl_ _Deref_post2_impl_(__maybenull_impl_notref, __count_impl(1)))
+#define _Outptr_opt_ _SAL2_Source_(_Outptr_opt_, (), _Out_opt_impl_ _Deref_post2_impl_(__notnull_impl_notref, __count_impl(1)))
+#define _Outptr_opt_result_maybenull_ _SAL2_Source_(_Outptr_opt_result_maybenull_, (), _Out_opt_impl_ _Deref_post2_impl_(__maybenull_impl_notref, __count_impl(1)))
+
+// Annotations for _Outptr_ parameters returning pointers to null terminated strings.
+
+#define _Outptr_result_z_ _SAL2_Source_(_Outptr_result_z_, (), _Out_impl_ _Deref_post_z_)
+#define _Outptr_opt_result_z_ _SAL2_Source_(_Outptr_opt_result_z_, (), _Out_opt_impl_ _Deref_post_z_)
+#define _Outptr_result_maybenull_z_ _SAL2_Source_(_Outptr_result_maybenull_z_, (), _Out_impl_ _Deref_post_opt_z_)
+#define _Outptr_opt_result_maybenull_z_ _SAL2_Source_(_Outptr_opt_result_maybenull_z_, (), _Out_opt_impl_ _Deref_post_opt_z_)
+
+// Annotations for _Outptr_ parameters where the output pointer is set to NULL if the function fails.
+
+#define _Outptr_result_nullonfailure_ _SAL2_Source_(_Outptr_result_nullonfailure_, (), _Outptr_ _On_failure_(_Deref_post_null_))
+#define _Outptr_opt_result_nullonfailure_ _SAL2_Source_(_Outptr_opt_result_nullonfailure_, (), _Outptr_opt_ _On_failure_(_Deref_post_null_))
+
+// Annotations for _Outptr_ parameters which return a pointer to a ref-counted COM object,
+// following the COM convention of setting the output to NULL on failure.
+// The current implementation is identical to _Outptr_result_nullonfailure_.
+// For pointers to types that are not COM objects, _Outptr_result_nullonfailure_ is preferred.
+
+#define _COM_Outptr_ _SAL2_Source_(_COM_Outptr_, (), _Outptr_ _On_failure_(_Deref_post_null_))
+#define _COM_Outptr_result_maybenull_ _SAL2_Source_(_COM_Outptr_result_maybenull_, (), _Outptr_result_maybenull_ _On_failure_(_Deref_post_null_))
+#define _COM_Outptr_opt_ _SAL2_Source_(_COM_Outptr_opt_, (), _Outptr_opt_ _On_failure_(_Deref_post_null_))
+#define _COM_Outptr_opt_result_maybenull_ _SAL2_Source_(_COM_Outptr_opt_result_maybenull_, (), _Outptr_opt_result_maybenull_ _On_failure_(_Deref_post_null_))
+
+// Annotations for _Outptr_ parameters returning a pointer to buffer with a specified number of elements/bytes
+
+#define _Outptr_result_buffer_(size) _SAL2_Source_(_Outptr_result_buffer_, (size), _Out_impl_ _Deref_post2_impl_(__notnull_impl_notref, __cap_impl(size)))
+#define _Outptr_opt_result_buffer_(size) _SAL2_Source_(_Outptr_opt_result_buffer_, (size), _Out_opt_impl_ _Deref_post2_impl_(__notnull_impl_notref, __cap_impl(size)))
+#define _Outptr_result_buffer_to_(size, count) _SAL2_Source_(_Outptr_result_buffer_to_, (size, count), _Out_impl_ _Deref_post3_impl_(__notnull_impl_notref, __cap_impl(size), __count_impl(count)))
+#define _Outptr_opt_result_buffer_to_(size, count) _SAL2_Source_(_Outptr_opt_result_buffer_to_, (size, count), _Out_opt_impl_ _Deref_post3_impl_(__notnull_impl_notref, __cap_impl(size), __count_impl(count)))
+
+#define _Outptr_result_buffer_all_(size) _SAL2_Source_(_Outptr_result_buffer_all_, (size), _Out_impl_ _Deref_post2_impl_(__notnull_impl_notref, __count_impl(size)))
+#define _Outptr_opt_result_buffer_all_(size) _SAL2_Source_(_Outptr_opt_result_buffer_all_, (size), _Out_opt_impl_ _Deref_post2_impl_(__notnull_impl_notref, __count_impl(size)))
+
+#define _Outptr_result_buffer_maybenull_(size) _SAL2_Source_(_Outptr_result_buffer_maybenull_, (size), _Out_impl_ _Deref_post2_impl_(__maybenull_impl_notref, __cap_impl(size)))
+#define _Outptr_opt_result_buffer_maybenull_(size) _SAL2_Source_(_Outptr_opt_result_buffer_maybenull_, (size), _Out_opt_impl_ _Deref_post2_impl_(__maybenull_impl_notref, __cap_impl(size)))
+#define _Outptr_result_buffer_to_maybenull_(size, count) _SAL2_Source_(_Outptr_result_buffer_to_maybenull_, (size, count), _Out_impl_ _Deref_post3_impl_(__maybenull_impl_notref, __cap_impl(size), __count_impl(count)))
+#define _Outptr_opt_result_buffer_to_maybenull_(size, count) _SAL2_Source_(_Outptr_opt_result_buffer_to_maybenull_, (size, count), _Out_opt_impl_ _Deref_post3_impl_(__maybenull_impl_notref, __cap_impl(size), __count_impl(count)))
+
+#define _Outptr_result_buffer_all_maybenull_(size) _SAL2_Source_(_Outptr_result_buffer_all_maybenull_, (size), _Out_impl_ _Deref_post2_impl_(__maybenull_impl_notref, __count_impl(size)))
+#define _Outptr_opt_result_buffer_all_maybenull_(size) _SAL2_Source_(_Outptr_opt_result_buffer_all_maybenull_, (size), _Out_opt_impl_ _Deref_post2_impl_(__maybenull_impl_notref, __count_impl(size)))
+
+#define _Outptr_result_bytebuffer_(size) _SAL2_Source_(_Outptr_result_bytebuffer_, (size), _Out_impl_ _Deref_post2_impl_(__notnull_impl_notref, __bytecap_impl(size)))
+#define _Outptr_opt_result_bytebuffer_(size) _SAL2_Source_(_Outptr_opt_result_bytebuffer_, (size), _Out_opt_impl_ _Deref_post2_impl_(__notnull_impl_notref, __bytecap_impl(size)))
+#define _Outptr_result_bytebuffer_to_(size, count) _SAL2_Source_(_Outptr_result_bytebuffer_to_, (size, count), _Out_impl_ _Deref_post3_impl_(__notnull_impl_notref, __bytecap_impl(size), __bytecount_impl(count)))
+#define _Outptr_opt_result_bytebuffer_to_(size, count) _SAL2_Source_(_Outptr_opt_result_bytebuffer_to_, (size, count), _Out_opt_impl_ _Deref_post3_impl_(__notnull_impl_notref, __bytecap_impl(size), __bytecount_impl(count)))
+
+#define _Outptr_result_bytebuffer_all_(size) _SAL2_Source_(_Outptr_result_bytebuffer_all_, (size), _Out_impl_ _Deref_post2_impl_(__notnull_impl_notref, __bytecount_impl(size)))
+#define _Outptr_opt_result_bytebuffer_all_(size) _SAL2_Source_(_Outptr_opt_result_bytebuffer_all_, (size), _Out_opt_impl_ _Deref_post2_impl_(__notnull_impl_notref, __bytecount_impl(size)))
+
+#define _Outptr_result_bytebuffer_maybenull_(size) _SAL2_Source_(_Outptr_result_bytebuffer_maybenull_, (size), _Out_impl_ _Deref_post2_impl_(__maybenull_impl_notref, __bytecap_impl(size)))
+#define _Outptr_opt_result_bytebuffer_maybenull_(size) _SAL2_Source_(_Outptr_opt_result_bytebuffer_maybenull_, (size), _Out_opt_impl_ _Deref_post2_impl_(__maybenull_impl_notref, __bytecap_impl(size)))
+#define _Outptr_result_bytebuffer_to_maybenull_(size, count) _SAL2_Source_(_Outptr_result_bytebuffer_to_maybenull_, (size, count), _Out_impl_ _Deref_post3_impl_(__maybenull_impl_notref, __bytecap_impl(size), __bytecount_impl(count)))
+#define _Outptr_opt_result_bytebuffer_to_maybenull_(size, count) _SAL2_Source_(_Outptr_opt_result_bytebuffer_to_maybenull_, (size, count), _Out_opt_impl_ _Deref_post3_impl_(__maybenull_impl_notref, __bytecap_impl(size), __bytecount_impl(count)))
+
+#define _Outptr_result_bytebuffer_all_maybenull_(size) _SAL2_Source_(_Outptr_result_bytebuffer_all_maybenull_, (size), _Out_impl_ _Deref_post2_impl_(__maybenull_impl_notref, __bytecount_impl(size)))
+#define _Outptr_opt_result_bytebuffer_all_maybenull_(size) _SAL2_Source_(_Outptr_opt_result_bytebuffer_all_maybenull_, (size), _Out_opt_impl_ _Deref_post2_impl_(__maybenull_impl_notref, __bytecount_impl(size)))
+
+// Annotations for output reference to pointer parameters.
+
+#define _Outref_ _SAL2_Source_(_Outref_, (), _Out_impl_ _Post_notnull_)
+#define _Outref_result_maybenull_ _SAL2_Source_(_Outref_result_maybenull_, (), _Pre2_impl_(__notnull_impl_notref, __cap_c_one_notref_impl) _Post_maybenull_ _Post_valid_impl_)
+
+#define _Outref_result_buffer_(size) _SAL2_Source_(_Outref_result_buffer_, (size), _Outref_ _Post1_impl_(__cap_impl(size)))
+#define _Outref_result_bytebuffer_(size) _SAL2_Source_(_Outref_result_bytebuffer_, (size), _Outref_ _Post1_impl_(__bytecap_impl(size)))
+#define _Outref_result_buffer_to_(size, count) _SAL2_Source_(_Outref_result_buffer_to_, (size, count), _Outref_result_buffer_(size) _Post1_impl_(__count_impl(count)))
+#define _Outref_result_bytebuffer_to_(size, count) _SAL2_Source_(_Outref_result_bytebuffer_to_, (size, count), _Outref_result_bytebuffer_(size) _Post1_impl_(__bytecount_impl(count)))
+#define _Outref_result_buffer_all_(size) _SAL2_Source_(_Outref_result_buffer_all_, (size), _Outref_result_buffer_to_(size, _Old_(size)))
+#define _Outref_result_bytebuffer_all_(size) _SAL2_Source_(_Outref_result_bytebuffer_all_, (size), _Outref_result_bytebuffer_to_(size, _Old_(size)))
+
+#define _Outref_result_buffer_maybenull_(size) _SAL2_Source_(_Outref_result_buffer_maybenull_, (size), _Outref_result_maybenull_ _Post1_impl_(__cap_impl(size)))
+#define _Outref_result_bytebuffer_maybenull_(size) _SAL2_Source_(_Outref_result_bytebuffer_maybenull_, (size), _Outref_result_maybenull_ _Post1_impl_(__bytecap_impl(size)))
+#define _Outref_result_buffer_to_maybenull_(size, count) _SAL2_Source_(_Outref_result_buffer_to_maybenull_, (size, count), _Outref_result_buffer_maybenull_(size) _Post1_impl_(__count_impl(count)))
+#define _Outref_result_bytebuffer_to_maybenull_(size, count) _SAL2_Source_(_Outref_result_bytebuffer_to_maybenull_, (size, count), _Outref_result_bytebuffer_maybenull_(size) _Post1_impl_(__bytecount_impl(count)))
+#define _Outref_result_buffer_all_maybenull_(size) _SAL2_Source_(_Outref_result_buffer_all_maybenull_, (size), _Outref_result_buffer_to_maybenull_(size, _Old_(size)))
+#define _Outref_result_bytebuffer_all_maybenull_(size) _SAL2_Source_(_Outref_result_bytebuffer_all_maybenull_, (size), _Outref_result_bytebuffer_to_maybenull_(size, _Old_(size)))
+
+// Annotations for output reference to pointer parameters that guarantee
+// that the pointer is set to NULL on failure.
+#define _Outref_result_nullonfailure_ _SAL2_Source_(_Outref_result_nullonfailure_, (), _Outref_ _On_failure_(_Post_null_))
+
+// Generic annotations to set output value of a by-pointer or by-reference parameter to null/zero on failure.
+#define _Result_nullonfailure_ _SAL2_Source_(_Result_nullonfailure_, (), _On_failure_(_Notref_impl_ _Deref_impl_ _Post_null_))
+#define _Result_zeroonfailure_ _SAL2_Source_(_Result_zeroonfailure_, (), _On_failure_(_Notref_impl_ _Deref_impl_ _Out_range_(==, 0)))
+
+
+// return values -------------------------------
+
+//
+// _Ret_ annotations
+//
+// describing conditions that hold for return values after the call
+
+// e.g. _Ret_z_ CString::operator const WCHAR*() const throw();
+#define _Ret_z_ _SAL2_Source_(_Ret_z_, (), _Ret2_impl_(__notnull_impl, __zterm_impl) _Ret_valid_impl_)
+#define _Ret_maybenull_z_ _SAL2_Source_(_Ret_maybenull_z_, (), _Ret2_impl_(__maybenull_impl,__zterm_impl) _Ret_valid_impl_)
+
+// used with allocated but not yet initialized objects
+#define _Ret_notnull_ _SAL2_Source_(_Ret_notnull_, (), _Ret1_impl_(__notnull_impl))
+#define _Ret_maybenull_ _SAL2_Source_(_Ret_maybenull_, (), _Ret1_impl_(__maybenull_impl))
+#define _Ret_null_ _SAL2_Source_(_Ret_null_, (), _Ret1_impl_(__null_impl))
+
+// used with allocated and initialized objects
+// returns single valid object
+#define _Ret_valid_ _SAL2_Source_(_Ret_valid_, (), _Ret1_impl_(__notnull_impl_notref) _Ret_valid_impl_)
+
+// returns pointer to initialized buffer of specified size
+#define _Ret_writes_(size) _SAL2_Source_(_Ret_writes_, (size), _Ret2_impl_(__notnull_impl, __count_impl(size)) _Ret_valid_impl_)
+#define _Ret_writes_z_(size) _SAL2_Source_(_Ret_writes_z_, (size), _Ret3_impl_(__notnull_impl, __count_impl(size), __zterm_impl) _Ret_valid_impl_)
+#define _Ret_writes_bytes_(size) _SAL2_Source_(_Ret_writes_bytes_, (size), _Ret2_impl_(__notnull_impl, __bytecount_impl(size)) _Ret_valid_impl_)
+#define _Ret_writes_maybenull_(size) _SAL2_Source_(_Ret_writes_maybenull_, (size), _Ret2_impl_(__maybenull_impl,__count_impl(size)) _Ret_valid_impl_)
+#define _Ret_writes_maybenull_z_(size) _SAL2_Source_(_Ret_writes_maybenull_z_, (size), _Ret3_impl_(__maybenull_impl,__count_impl(size),__zterm_impl) _Ret_valid_impl_)
+#define _Ret_writes_bytes_maybenull_(size) _SAL2_Source_(_Ret_writes_bytes_maybenull_, (size), _Ret2_impl_(__maybenull_impl,__bytecount_impl(size)) _Ret_valid_impl_)
+
+// returns pointer to partially initialized buffer, with total size 'size' and initialized size 'count'
+#define _Ret_writes_to_(size,count) _SAL2_Source_(_Ret_writes_to_, (size,count), _Ret3_impl_(__notnull_impl, __cap_impl(size), __count_impl(count)) _Ret_valid_impl_)
+#define _Ret_writes_bytes_to_(size,count) _SAL2_Source_(_Ret_writes_bytes_to_, (size,count), _Ret3_impl_(__notnull_impl, __bytecap_impl(size), __bytecount_impl(count)) _Ret_valid_impl_)
+#define _Ret_writes_to_maybenull_(size,count) _SAL2_Source_(_Ret_writes_to_maybenull_, (size,count), _Ret3_impl_(__maybenull_impl, __cap_impl(size), __count_impl(count)) _Ret_valid_impl_)
+#define _Ret_writes_bytes_to_maybenull_(size,count) _SAL2_Source_(_Ret_writes_bytes_to_maybenull_, (size,count), _Ret3_impl_(__maybenull_impl, __bytecap_impl(size), __bytecount_impl(count)) _Ret_valid_impl_)
+
+
+// Annotations for strict type checking
+#define _Points_to_data_ _SAL2_Source_(_Points_to_data_, (), _Pre_ _Points_to_data_impl_)
+#define _Literal_ _SAL2_Source_(_Literal_, (), _Pre_ _Literal_impl_)
+#define _Notliteral_ _SAL2_Source_(_Notliteral_, (), _Pre_ _Notliteral_impl_)
+
+// Check the return value of a function e.g. _Check_return_ ErrorCode Foo();
+#define _Check_return_ _SAL2_Source_(_Check_return_, (), _Check_return_impl_)
+#define _Must_inspect_result_ _SAL2_Source_(_Must_inspect_result_, (), _Must_inspect_impl_ _Check_return_impl_)
+
+// e.g. MyPrintF( _Printf_format_string_ const WCHAR* wzFormat, ... );
+#define _Printf_format_string_ _SAL2_Source_(_Printf_format_string_, (), _Printf_format_string_impl_)
+#define _Scanf_format_string_ _SAL2_Source_(_Scanf_format_string_, (), _Scanf_format_string_impl_)
+#define _Scanf_s_format_string_ _SAL2_Source_(_Scanf_s_format_string_, (), _Scanf_s_format_string_impl_)
+
+#define _Format_string_impl_(kind,where) _SA_annotes2(SAL_IsFormatString2, kind, where)
+#define _Printf_format_string_params_(x) _SAL2_Source_(_Printf_format_string_params_, (x), _Format_string_impl_("printf", x))
+#define _Scanf_format_string_params_(x) _SAL2_Source_(_Scanf_format_string_params_, (x), _Format_string_impl_("scanf", x))
+#define _Scanf_s_format_string_params_(x) _SAL2_Source_(_Scanf_s_format_string_params_, (x), _Format_string_impl_("scanf_s", x))
+
+// annotations to express value of integral or pointer parameter
+#define _In_range_(lb,ub) _SAL2_Source_(_In_range_, (lb,ub), _In_range_impl_(lb,ub))
+#define _Out_range_(lb,ub) _SAL2_Source_(_Out_range_, (lb,ub), _Out_range_impl_(lb,ub))
+#define _Ret_range_(lb,ub) _SAL2_Source_(_Ret_range_, (lb,ub), _Ret_range_impl_(lb,ub))
+#define _Deref_in_range_(lb,ub) _SAL2_Source_(_Deref_in_range_, (lb,ub), _Deref_in_range_impl_(lb,ub))
+#define _Deref_out_range_(lb,ub) _SAL2_Source_(_Deref_out_range_, (lb,ub), _Deref_out_range_impl_(lb,ub))
+#define _Deref_ret_range_(lb,ub) _SAL2_Source_(_Deref_ret_range_, (lb,ub), _Deref_ret_range_impl_(lb,ub))
+#define _Pre_equal_to_(expr) _SAL2_Source_(_Pre_equal_to_, (expr), _In_range_(==, expr))
+#define _Post_equal_to_(expr) _SAL2_Source_(_Post_equal_to_, (expr), _Out_range_(==, expr))
+
+// annotation to express that a value (usually a field of a mutable class)
+// is not changed by a function call
+#define _Unchanged_(e) _SAL2_Source_(_Unchanged_, (e), _At_(e, _Post_equal_to_(_Old_(e)) _Const_))
+
+// Annotations to allow expressing generalized pre and post conditions.
+// 'cond' may be any valid SAL expression that is considered to be true as a precondition
+// or postcondition (respsectively).
+#define _Pre_satisfies_(cond) _SAL2_Source_(_Pre_satisfies_, (cond), _Pre_satisfies_impl_(cond))
+#define _Post_satisfies_(cond) _SAL2_Source_(_Post_satisfies_, (cond), _Post_satisfies_impl_(cond))
+
+// Annotations to express struct, class and field invariants
+#define _Struct_size_bytes_(size) _SAL2_Source_(_Struct_size_bytes_, (size), _Writable_bytes_(size))
+
+#define _Field_size_(size) _SAL2_Source_(_Field_size_, (size), _Notnull_ _Writable_elements_(size))
+#define _Field_size_opt_(size) _SAL2_Source_(_Field_size_opt_, (size), _Maybenull_ _Writable_elements_(size))
+#define _Field_size_part_(size, count) _SAL2_Source_(_Field_size_part_, (size, count), _Notnull_ _Writable_elements_(size) _Readable_elements_(count))
+#define _Field_size_part_opt_(size, count) _SAL2_Source_(_Field_size_part_opt_, (size, count), _Maybenull_ _Writable_elements_(size) _Readable_elements_(count))
+#define _Field_size_full_(size) _SAL2_Source_(_Field_size_full_, (size), _Field_size_part_(size, size))
+#define _Field_size_full_opt_(size) _SAL2_Source_(_Field_size_full_opt_, (size), _Field_size_part_opt_(size, size))
+
+#define _Field_size_bytes_(size) _SAL2_Source_(_Field_size_bytes_, (size), _Notnull_ _Writable_bytes_(size))
+#define _Field_size_bytes_opt_(size) _SAL2_Source_(_Field_size_bytes_opt_, (size), _Maybenull_ _Writable_bytes_(size))
+#define _Field_size_bytes_part_(size, count) _SAL2_Source_(_Field_size_bytes_part_, (size, count), _Notnull_ _Writable_bytes_(size) _Readable_bytes_(count))
+#define _Field_size_bytes_part_opt_(size, count) _SAL2_Source_(_Field_size_bytes_part_opt_, (size, count), _Maybenull_ _Writable_bytes_(size) _Readable_bytes_(count))
+#define _Field_size_bytes_full_(size) _SAL2_Source_(_Field_size_bytes_full_, (size), _Field_size_bytes_part_(size, size))
+#define _Field_size_bytes_full_opt_(size) _SAL2_Source_(_Field_size_bytes_full_opt_, (size), _Field_size_bytes_part_opt_(size, size))
+
+#define _Field_z_ _SAL2_Source_(_Field_z_, (), _Null_terminated_)
+
+#define _Field_range_(min,max) _SAL2_Source_(_Field_range_, (min,max), _Field_range_impl_(min,max))
+
+//============================================================================
+// _Pre_\_Post_ Layer:
+//============================================================================
+
+//
+// Raw Pre/Post for declaring custom pre/post conditions
+//
+
+#define _Pre_ _Pre_impl_
+#define _Post_ _Post_impl_
+
+//
+// Validity property
+//
+
+#define _Valid_ _Valid_impl_
+#define _Notvalid_ _Notvalid_impl_
+#define _Maybevalid_ _Maybevalid_impl_
+
+//
+// Buffer size properties
+//
+
+// Expressing buffer sizes without specifying pre or post condition
+#define _Readable_bytes_(size) _SAL2_Source_(_Readable_bytes_, (size), _Readable_bytes_impl_(size))
+#define _Readable_elements_(size) _SAL2_Source_(_Readable_elements_, (size), _Readable_elements_impl_(size))
+#define _Writable_bytes_(size) _SAL2_Source_(_Writable_bytes_, (size), _Writable_bytes_impl_(size))
+#define _Writable_elements_(size) _SAL2_Source_(_Writable_elements_, (size), _Writable_elements_impl_(size))
+
+#define _Null_terminated_ _SAL2_Source_(_Null_terminated_, (), _Null_terminated_impl_)
+#define _NullNull_terminated_ _SAL2_Source_(_NullNull_terminated_, (), _NullNull_terminated_impl_)
+
+// Expressing buffer size as pre or post condition
+#define _Pre_readable_size_(size) _SAL2_Source_(_Pre_readable_size_, (size), _Pre1_impl_(__count_impl(size)) _Pre_valid_impl_)
+#define _Pre_writable_size_(size) _SAL2_Source_(_Pre_writable_size_, (size), _Pre1_impl_(__cap_impl(size)))
+#define _Pre_readable_byte_size_(size) _SAL2_Source_(_Pre_readable_byte_size_, (size), _Pre1_impl_(__bytecount_impl(size)) _Pre_valid_impl_)
+#define _Pre_writable_byte_size_(size) _SAL2_Source_(_Pre_writable_byte_size_, (size), _Pre1_impl_(__bytecap_impl(size)))
+
+#define _Post_readable_size_(size) _SAL2_Source_(_Post_readable_size_, (size), _Post1_impl_(__count_impl(size)) _Post_valid_impl_)
+#define _Post_writable_size_(size) _SAL2_Source_(_Post_writable_size_, (size), _Post1_impl_(__cap_impl(size)))
+#define _Post_readable_byte_size_(size) _SAL2_Source_(_Post_readable_byte_size_, (size), _Post1_impl_(__bytecount_impl(size)) _Post_valid_impl_)
+#define _Post_writable_byte_size_(size) _SAL2_Source_(_Post_writable_byte_size_, (size), _Post1_impl_(__bytecap_impl(size)))
+
+//
+// Pointer null-ness properties
+//
+#define _Null_ _Null_impl_
+#define _Notnull_ _Notnull_impl_
+#define _Maybenull_ _Maybenull_impl_
+
+//
+// _Pre_ annotations ---
+//
+// describing conditions that must be met before the call of the function
+
+// e.g. int strlen( _Pre_z_ const char* sz );
+// buffer is a zero terminated string
+#define _Pre_z_ _SAL2_Source_(_Pre_z_, (), _Pre1_impl_(__zterm_impl) _Pre_valid_impl_)
+
+// valid size unknown or indicated by type (e.g.:LPSTR)
+#define _Pre_valid_ _SAL2_Source_(_Pre_valid_, (), _Pre1_impl_(__notnull_impl_notref) _Pre_valid_impl_)
+#define _Pre_opt_valid_ _SAL2_Source_(_Pre_opt_valid_, (), _Pre1_impl_(__maybenull_impl_notref) _Pre_valid_impl_)
+
+#define _Pre_invalid_ _SAL2_Source_(_Pre_invalid_, (), _Deref_pre1_impl_(__notvalid_impl))
+
+// Overrides recursive valid when some field is not yet initialized when using _Inout_
+#define _Pre_unknown_ _SAL2_Source_(_Pre_unknown_, (), _Pre1_impl_(__maybevalid_impl))
+
+// used with allocated but not yet initialized objects
+#define _Pre_notnull_ _SAL2_Source_(_Pre_notnull_, (), _Pre1_impl_(__notnull_impl_notref))
+#define _Pre_maybenull_ _SAL2_Source_(_Pre_maybenull_, (), _Pre1_impl_(__maybenull_impl_notref))
+#define _Pre_null_ _SAL2_Source_(_Pre_null_, (), _Pre1_impl_(__null_impl_notref))
+
+//
+// _Post_ annotations ---
+//
+// describing conditions that hold after the function call
+
+// void CopyStr( _In_z_ const char* szFrom, _Pre_cap_(cch) _Post_z_ char* szFrom, size_t cchFrom );
+// buffer will be a zero-terminated string after the call
+#define _Post_z_ _SAL2_Source_(_Post_z_, (), _Post1_impl_(__zterm_impl) _Post_valid_impl_)
+
+// e.g. HRESULT InitStruct( _Post_valid_ Struct* pobj );
+#define _Post_valid_ _SAL2_Source_(_Post_valid_, (), _Post_valid_impl_)
+#define _Post_invalid_ _SAL2_Source_(_Post_invalid_, (), _Deref_post1_impl_(__notvalid_impl))
+
+// e.g. void free( _Post_ptr_invalid_ void* pv );
+#define _Post_ptr_invalid_ _SAL2_Source_(_Post_ptr_invalid_, (), _Post1_impl_(__notvalid_impl))
+
+// e.g. void ThrowExceptionIfNull( _Post_notnull_ const void* pv );
+#define _Post_notnull_ _SAL2_Source_(_Post_notnull_, (), _Post1_impl_(__notnull_impl))
+
+// e.g. HRESULT GetObject(_Outptr_ _On_failure_(_At_(*p, _Post_null_)) T **p);
+#define _Post_null_ _SAL2_Source_(_Post_null_, (), _Post1_impl_(__null_impl))
+
+#define _Post_maybenull_ _SAL2_Source_(_Post_maybenull_, (), _Post1_impl_(__maybenull_impl))
+
+#define _Prepost_z_ _SAL2_Source_(_Prepost_z_, (), _Pre_z_ _Post_z_)
+
+
+// #pragma region Input Buffer SAL 1 compatibility macros
+
+/*==========================================================================
+
+ This section contains definitions for macros defined for VS2010 and earlier.
+ Usage of these macros is still supported, but the SAL 2 macros defined above
+ are recommended instead. This comment block is retained to assist in
+ understanding SAL that still uses the older syntax.
+
+ The macros are defined in 3 layers:
+
+ _In_\_Out_ Layer:
+ ----------------
+ This layer provides the highest abstraction and its macros should be used
+ in most cases. Its macros start with _In_, _Out_ or _Inout_. For the
+ typical case they provide the most concise annotations.
+
+ _Pre_\_Post_ Layer:
+ ------------------
+ The macros of this layer only should be used when there is no suitable macro
+ in the _In_\_Out_ layer. Its macros start with _Pre_, _Post_, _Ret_,
+ _Deref_pre_ _Deref_post_ and _Deref_ret_. This layer provides the most
+ flexibility for annotations.
+
+ Implementation Abstraction Layer:
+ --------------------------------
+ Macros from this layer should never be used directly. The layer only exists
+ to hide the implementation of the annotation macros.
+
+
+ Annotation Syntax:
+ |--------------|----------|----------------|-----------------------------|
+ | Usage | Nullness | ZeroTerminated | Extent |
+ |--------------|----------|----------------|-----------------------------|
+ | _In_ | <> | <> | <> |
+ | _Out_ | opt_ | z_ | [byte]cap_[c_|x_]( size ) |
+ | _Inout_ | | | [byte]count_[c_|x_]( size ) |
+ | _Deref_out_ | | | ptrdiff_cap_( ptr ) |
+ |--------------| | | ptrdiff_count_( ptr ) |
+ | _Ret_ | | | |
+ | _Deref_ret_ | | | |
+ |--------------| | | |
+ | _Pre_ | | | |
+ | _Post_ | | | |
+ | _Deref_pre_ | | | |
+ | _Deref_post_ | | | |
+ |--------------|----------|----------------|-----------------------------|
+
+ Usage:
+ -----
+ _In_, _Out_, _Inout_, _Pre_, _Post_, _Deref_pre_, _Deref_post_ are for
+ formal parameters.
+ _Ret_, _Deref_ret_ must be used for return values.
+
+ Nullness:
+ --------
+ If the pointer can be NULL the annotation contains _opt. If the macro
+ does not contain '_opt' the pointer may not be NULL.
+
+ String Type:
+ -----------
+ _z: NullTerminated string
+ for _In_ parameters the buffer must have the specified stringtype before the call
+ for _Out_ parameters the buffer must have the specified stringtype after the call
+ for _Inout_ parameters both conditions apply
+
+ Extent Syntax:
+ |------|---------------|---------------|
+ | Unit | Writ\Readable | Argument Type |
+ |------|---------------|---------------|
+ | <> | cap_ | <> |
+ | byte | count_ | c_ |
+ | | | x_ |
+ |------|---------------|---------------|
+
+ 'cap' (capacity) describes the writable size of the buffer and is typically used
+ with _Out_. The default unit is elements. Use 'bytecap' if the size is given in bytes
+ 'count' describes the readable size of the buffer and is typically used with _In_.
+ The default unit is elements. Use 'bytecount' if the size is given in bytes.
+
+ Argument syntax for cap_, bytecap_, count_, bytecount_:
+ (<parameter>|return)[+n] e.g. cch, return, cb+2
+
+ If the buffer size is a constant expression use the c_ postfix.
+ E.g. cap_c_(20), count_c_(MAX_PATH), bytecount_c_(16)
+
+ If the buffer size is given by a limiting pointer use the ptrdiff_ versions
+ of the macros.
+
+ If the buffer size is neither a parameter nor a constant expression use the x_
+ postfix. e.g. bytecount_x_(num*size) x_ annotations accept any arbitrary string.
+ No analysis can be done for x_ annotations but they at least tell the tool that
+ the buffer has some sort of extent description. x_ annotations might be supported
+ by future compiler versions.
+
+============================================================================*/
+
+// e.g. void SetCharRange( _In_count_(cch) const char* rgch, size_t cch )
+// valid buffer extent described by another parameter
+#define _In_count_(size) _SAL1_1_Source_(_In_count_, (size), _Pre_count_(size) _Deref_pre_readonly_)
+#define _In_opt_count_(size) _SAL1_1_Source_(_In_opt_count_, (size), _Pre_opt_count_(size) _Deref_pre_readonly_)
+#define _In_bytecount_(size) _SAL1_1_Source_(_In_bytecount_, (size), _Pre_bytecount_(size) _Deref_pre_readonly_)
+#define _In_opt_bytecount_(size) _SAL1_1_Source_(_In_opt_bytecount_, (size), _Pre_opt_bytecount_(size) _Deref_pre_readonly_)
+
+// valid buffer extent described by a constant extression
+#define _In_count_c_(size) _SAL1_1_Source_(_In_count_c_, (size), _Pre_count_c_(size) _Deref_pre_readonly_)
+#define _In_opt_count_c_(size) _SAL1_1_Source_(_In_opt_count_c_, (size), _Pre_opt_count_c_(size) _Deref_pre_readonly_)
+#define _In_bytecount_c_(size) _SAL1_1_Source_(_In_bytecount_c_, (size), _Pre_bytecount_c_(size) _Deref_pre_readonly_)
+#define _In_opt_bytecount_c_(size) _SAL1_1_Source_(_In_opt_bytecount_c_, (size), _Pre_opt_bytecount_c_(size) _Deref_pre_readonly_)
+
+// nullterminated 'input' buffers with given size
+
+// e.g. void SetCharRange( _In_count_(cch) const char* rgch, size_t cch )
+// nullterminated valid buffer extent described by another parameter
+#define _In_z_count_(size) _SAL1_1_Source_(_In_z_count_, (size), _Pre_z_ _Pre_count_(size) _Deref_pre_readonly_)
+#define _In_opt_z_count_(size) _SAL1_1_Source_(_In_opt_z_count_, (size), _Pre_opt_z_ _Pre_opt_count_(size) _Deref_pre_readonly_)
+#define _In_z_bytecount_(size) _SAL1_1_Source_(_In_z_bytecount_, (size), _Pre_z_ _Pre_bytecount_(size) _Deref_pre_readonly_)
+#define _In_opt_z_bytecount_(size) _SAL1_1_Source_(_In_opt_z_bytecount_, (size), _Pre_opt_z_ _Pre_opt_bytecount_(size) _Deref_pre_readonly_)
+
+// nullterminated valid buffer extent described by a constant extression
+#define _In_z_count_c_(size) _SAL1_1_Source_(_In_z_count_c_, (size), _Pre_z_ _Pre_count_c_(size) _Deref_pre_readonly_)
+#define _In_opt_z_count_c_(size) _SAL1_1_Source_(_In_opt_z_count_c_, (size), _Pre_opt_z_ _Pre_opt_count_c_(size) _Deref_pre_readonly_)
+#define _In_z_bytecount_c_(size) _SAL1_1_Source_(_In_z_bytecount_c_, (size), _Pre_z_ _Pre_bytecount_c_(size) _Deref_pre_readonly_)
+#define _In_opt_z_bytecount_c_(size) _SAL1_1_Source_(_In_opt_z_bytecount_c_, (size), _Pre_opt_z_ _Pre_opt_bytecount_c_(size) _Deref_pre_readonly_)
+
+// buffer capacity is described by another pointer
+// e.g. void Foo( _In_ptrdiff_count_(pchMax) const char* pch, const char* pchMax ) { while pch < pchMax ) pch++; }
+#define _In_ptrdiff_count_(size) _SAL1_1_Source_(_In_ptrdiff_count_, (size), _Pre_ptrdiff_count_(size) _Deref_pre_readonly_)
+#define _In_opt_ptrdiff_count_(size) _SAL1_1_Source_(_In_opt_ptrdiff_count_, (size), _Pre_opt_ptrdiff_count_(size) _Deref_pre_readonly_)
+
+// 'x' version for complex expressions that are not supported by the current compiler version
+// e.g. void Set3ColMatrix( _In_count_x_(3*cRows) const Elem* matrix, int cRows );
+#define _In_count_x_(size) _SAL1_1_Source_(_In_count_x_, (size), _Pre_count_x_(size) _Deref_pre_readonly_)
+#define _In_opt_count_x_(size) _SAL1_1_Source_(_In_opt_count_x_, (size), _Pre_opt_count_x_(size) _Deref_pre_readonly_)
+#define _In_bytecount_x_(size) _SAL1_1_Source_(_In_bytecount_x_, (size), _Pre_bytecount_x_(size) _Deref_pre_readonly_)
+#define _In_opt_bytecount_x_(size) _SAL1_1_Source_(_In_opt_bytecount_x_, (size), _Pre_opt_bytecount_x_(size) _Deref_pre_readonly_)
+
+
+// 'out' with buffer size
+// e.g. void GetIndeces( _Out_cap_(cIndeces) int* rgIndeces, size_t cIndices );
+// buffer capacity is described by another parameter
+#define _Out_cap_(size) _SAL1_1_Source_(_Out_cap_, (size), _Pre_cap_(size) _Post_valid_impl_)
+#define _Out_opt_cap_(size) _SAL1_1_Source_(_Out_opt_cap_, (size), _Pre_opt_cap_(size) _Post_valid_impl_)
+#define _Out_bytecap_(size) _SAL1_1_Source_(_Out_bytecap_, (size), _Pre_bytecap_(size) _Post_valid_impl_)
+#define _Out_opt_bytecap_(size) _SAL1_1_Source_(_Out_opt_bytecap_, (size), _Pre_opt_bytecap_(size) _Post_valid_impl_)
+
+// buffer capacity is described by a constant expression
+#define _Out_cap_c_(size) _SAL1_1_Source_(_Out_cap_c_, (size), _Pre_cap_c_(size) _Post_valid_impl_)
+#define _Out_opt_cap_c_(size) _SAL1_1_Source_(_Out_opt_cap_c_, (size), _Pre_opt_cap_c_(size) _Post_valid_impl_)
+#define _Out_bytecap_c_(size) _SAL1_1_Source_(_Out_bytecap_c_, (size), _Pre_bytecap_c_(size) _Post_valid_impl_)
+#define _Out_opt_bytecap_c_(size) _SAL1_1_Source_(_Out_opt_bytecap_c_, (size), _Pre_opt_bytecap_c_(size) _Post_valid_impl_)
+
+// buffer capacity is described by another parameter multiplied by a constant expression
+#define _Out_cap_m_(mult,size) _SAL1_1_Source_(_Out_cap_m_, (mult,size), _Pre_cap_m_(mult,size) _Post_valid_impl_)
+#define _Out_opt_cap_m_(mult,size) _SAL1_1_Source_(_Out_opt_cap_m_, (mult,size), _Pre_opt_cap_m_(mult,size) _Post_valid_impl_)
+#define _Out_z_cap_m_(mult,size) _SAL1_1_Source_(_Out_z_cap_m_, (mult,size), _Pre_cap_m_(mult,size) _Post_valid_impl_ _Post_z_)
+#define _Out_opt_z_cap_m_(mult,size) _SAL1_1_Source_(_Out_opt_z_cap_m_, (mult,size), _Pre_opt_cap_m_(mult,size) _Post_valid_impl_ _Post_z_)
+
+// buffer capacity is described by another pointer
+// e.g. void Foo( _Out_ptrdiff_cap_(pchMax) char* pch, const char* pchMax ) { while pch < pchMax ) pch++; }
+#define _Out_ptrdiff_cap_(size) _SAL1_1_Source_(_Out_ptrdiff_cap_, (size), _Pre_ptrdiff_cap_(size) _Post_valid_impl_)
+#define _Out_opt_ptrdiff_cap_(size) _SAL1_1_Source_(_Out_opt_ptrdiff_cap_, (size), _Pre_opt_ptrdiff_cap_(size) _Post_valid_impl_)
+
+// buffer capacity is described by a complex expression
+#define _Out_cap_x_(size) _SAL1_1_Source_(_Out_cap_x_, (size), _Pre_cap_x_(size) _Post_valid_impl_)
+#define _Out_opt_cap_x_(size) _SAL1_1_Source_(_Out_opt_cap_x_, (size), _Pre_opt_cap_x_(size) _Post_valid_impl_)
+#define _Out_bytecap_x_(size) _SAL1_1_Source_(_Out_bytecap_x_, (size), _Pre_bytecap_x_(size) _Post_valid_impl_)
+#define _Out_opt_bytecap_x_(size) _SAL1_1_Source_(_Out_opt_bytecap_x_, (size), _Pre_opt_bytecap_x_(size) _Post_valid_impl_)
+
+// a zero terminated string is filled into a buffer of given capacity
+// e.g. void CopyStr( _In_z_ const char* szFrom, _Out_z_cap_(cchTo) char* szTo, size_t cchTo );
+// buffer capacity is described by another parameter
+#define _Out_z_cap_(size) _SAL1_1_Source_(_Out_z_cap_, (size), _Pre_cap_(size) _Post_valid_impl_ _Post_z_)
+#define _Out_opt_z_cap_(size) _SAL1_1_Source_(_Out_opt_z_cap_, (size), _Pre_opt_cap_(size) _Post_valid_impl_ _Post_z_)
+#define _Out_z_bytecap_(size) _SAL1_1_Source_(_Out_z_bytecap_, (size), _Pre_bytecap_(size) _Post_valid_impl_ _Post_z_)
+#define _Out_opt_z_bytecap_(size) _SAL1_1_Source_(_Out_opt_z_bytecap_, (size), _Pre_opt_bytecap_(size) _Post_valid_impl_ _Post_z_)
+
+// buffer capacity is described by a constant expression
+#define _Out_z_cap_c_(size) _SAL1_1_Source_(_Out_z_cap_c_, (size), _Pre_cap_c_(size) _Post_valid_impl_ _Post_z_)
+#define _Out_opt_z_cap_c_(size) _SAL1_1_Source_(_Out_opt_z_cap_c_, (size), _Pre_opt_cap_c_(size) _Post_valid_impl_ _Post_z_)
+#define _Out_z_bytecap_c_(size) _SAL1_1_Source_(_Out_z_bytecap_c_, (size), _Pre_bytecap_c_(size) _Post_valid_impl_ _Post_z_)
+#define _Out_opt_z_bytecap_c_(size) _SAL1_1_Source_(_Out_opt_z_bytecap_c_, (size), _Pre_opt_bytecap_c_(size) _Post_valid_impl_ _Post_z_)
+
+// buffer capacity is described by a complex expression
+#define _Out_z_cap_x_(size) _SAL1_1_Source_(_Out_z_cap_x_, (size), _Pre_cap_x_(size) _Post_valid_impl_ _Post_z_)
+#define _Out_opt_z_cap_x_(size) _SAL1_1_Source_(_Out_opt_z_cap_x_, (size), _Pre_opt_cap_x_(size) _Post_valid_impl_ _Post_z_)
+#define _Out_z_bytecap_x_(size) _SAL1_1_Source_(_Out_z_bytecap_x_, (size), _Pre_bytecap_x_(size) _Post_valid_impl_ _Post_z_)
+#define _Out_opt_z_bytecap_x_(size) _SAL1_1_Source_(_Out_opt_z_bytecap_x_, (size), _Pre_opt_bytecap_x_(size) _Post_valid_impl_ _Post_z_)
+
+// a zero terminated string is filled into a buffer of given capacity
+// e.g. size_t CopyCharRange( _In_count_(cchFrom) const char* rgchFrom, size_t cchFrom, _Out_cap_post_count_(cchTo,return)) char* rgchTo, size_t cchTo );
+#define _Out_cap_post_count_(cap,count) _SAL1_1_Source_(_Out_cap_post_count_, (cap,count), _Pre_cap_(cap) _Post_valid_impl_ _Post_count_(count))
+#define _Out_opt_cap_post_count_(cap,count) _SAL1_1_Source_(_Out_opt_cap_post_count_, (cap,count), _Pre_opt_cap_(cap) _Post_valid_impl_ _Post_count_(count))
+#define _Out_bytecap_post_bytecount_(cap,count) _SAL1_1_Source_(_Out_bytecap_post_bytecount_, (cap,count), _Pre_bytecap_(cap) _Post_valid_impl_ _Post_bytecount_(count))
+#define _Out_opt_bytecap_post_bytecount_(cap,count) _SAL1_1_Source_(_Out_opt_bytecap_post_bytecount_, (cap,count), _Pre_opt_bytecap_(cap) _Post_valid_impl_ _Post_bytecount_(count))
+
+// a zero terminated string is filled into a buffer of given capacity
+// e.g. size_t CopyStr( _In_z_ const char* szFrom, _Out_z_cap_post_count_(cchTo,return+1) char* szTo, size_t cchTo );
+#define _Out_z_cap_post_count_(cap,count) _SAL1_1_Source_(_Out_z_cap_post_count_, (cap,count), _Pre_cap_(cap) _Post_valid_impl_ _Post_z_count_(count))
+#define _Out_opt_z_cap_post_count_(cap,count) _SAL1_1_Source_(_Out_opt_z_cap_post_count_, (cap,count), _Pre_opt_cap_(cap) _Post_valid_impl_ _Post_z_count_(count))
+#define _Out_z_bytecap_post_bytecount_(cap,count) _SAL1_1_Source_(_Out_z_bytecap_post_bytecount_, (cap,count), _Pre_bytecap_(cap) _Post_valid_impl_ _Post_z_bytecount_(count))
+#define _Out_opt_z_bytecap_post_bytecount_(cap,count) _SAL1_1_Source_(_Out_opt_z_bytecap_post_bytecount_, (cap,count), _Pre_opt_bytecap_(cap) _Post_valid_impl_ _Post_z_bytecount_(count))
+
+// only use with dereferenced arguments e.g. '*pcch'
+#define _Out_capcount_(capcount) _SAL1_1_Source_(_Out_capcount_, (capcount), _Pre_cap_(capcount) _Post_valid_impl_ _Post_count_(capcount))
+#define _Out_opt_capcount_(capcount) _SAL1_1_Source_(_Out_opt_capcount_, (capcount), _Pre_opt_cap_(capcount) _Post_valid_impl_ _Post_count_(capcount))
+#define _Out_bytecapcount_(capcount) _SAL1_1_Source_(_Out_bytecapcount_, (capcount), _Pre_bytecap_(capcount) _Post_valid_impl_ _Post_bytecount_(capcount))
+#define _Out_opt_bytecapcount_(capcount) _SAL1_1_Source_(_Out_opt_bytecapcount_, (capcount), _Pre_opt_bytecap_(capcount) _Post_valid_impl_ _Post_bytecount_(capcount))
+
+#define _Out_capcount_x_(capcount) _SAL1_1_Source_(_Out_capcount_x_, (capcount), _Pre_cap_x_(capcount) _Post_valid_impl_ _Post_count_x_(capcount))
+#define _Out_opt_capcount_x_(capcount) _SAL1_1_Source_(_Out_opt_capcount_x_, (capcount), _Pre_opt_cap_x_(capcount) _Post_valid_impl_ _Post_count_x_(capcount))
+#define _Out_bytecapcount_x_(capcount) _SAL1_1_Source_(_Out_bytecapcount_x_, (capcount), _Pre_bytecap_x_(capcount) _Post_valid_impl_ _Post_bytecount_x_(capcount))
+#define _Out_opt_bytecapcount_x_(capcount) _SAL1_1_Source_(_Out_opt_bytecapcount_x_, (capcount), _Pre_opt_bytecap_x_(capcount) _Post_valid_impl_ _Post_bytecount_x_(capcount))
+
+// e.g. GetString( _Out_z_capcount_(*pLen+1) char* sz, size_t* pLen );
+#define _Out_z_capcount_(capcount) _SAL1_1_Source_(_Out_z_capcount_, (capcount), _Pre_cap_(capcount) _Post_valid_impl_ _Post_z_count_(capcount))
+#define _Out_opt_z_capcount_(capcount) _SAL1_1_Source_(_Out_opt_z_capcount_, (capcount), _Pre_opt_cap_(capcount) _Post_valid_impl_ _Post_z_count_(capcount))
+#define _Out_z_bytecapcount_(capcount) _SAL1_1_Source_(_Out_z_bytecapcount_, (capcount), _Pre_bytecap_(capcount) _Post_valid_impl_ _Post_z_bytecount_(capcount))
+#define _Out_opt_z_bytecapcount_(capcount) _SAL1_1_Source_(_Out_opt_z_bytecapcount_, (capcount), _Pre_opt_bytecap_(capcount) _Post_valid_impl_ _Post_z_bytecount_(capcount))
+
+
+// 'inout' buffers with initialized elements before and after the call
+// e.g. void ModifyIndices( _Inout_count_(cIndices) int* rgIndeces, size_t cIndices );
+#define _Inout_count_(size) _SAL1_1_Source_(_Inout_count_, (size), _Prepost_count_(size))
+#define _Inout_opt_count_(size) _SAL1_1_Source_(_Inout_opt_count_, (size), _Prepost_opt_count_(size))
+#define _Inout_bytecount_(size) _SAL1_1_Source_(_Inout_bytecount_, (size), _Prepost_bytecount_(size))
+#define _Inout_opt_bytecount_(size) _SAL1_1_Source_(_Inout_opt_bytecount_, (size), _Prepost_opt_bytecount_(size))
+
+#define _Inout_count_c_(size) _SAL1_1_Source_(_Inout_count_c_, (size), _Prepost_count_c_(size))
+#define _Inout_opt_count_c_(size) _SAL1_1_Source_(_Inout_opt_count_c_, (size), _Prepost_opt_count_c_(size))
+#define _Inout_bytecount_c_(size) _SAL1_1_Source_(_Inout_bytecount_c_, (size), _Prepost_bytecount_c_(size))
+#define _Inout_opt_bytecount_c_(size) _SAL1_1_Source_(_Inout_opt_bytecount_c_, (size), _Prepost_opt_bytecount_c_(size))
+
+// nullterminated 'inout' buffers with initialized elements before and after the call
+// e.g. void ModifyIndices( _Inout_count_(cIndices) int* rgIndeces, size_t cIndices );
+#define _Inout_z_count_(size) _SAL1_1_Source_(_Inout_z_count_, (size), _Prepost_z_ _Prepost_count_(size))
+#define _Inout_opt_z_count_(size) _SAL1_1_Source_(_Inout_opt_z_count_, (size), _Prepost_z_ _Prepost_opt_count_(size))
+#define _Inout_z_bytecount_(size) _SAL1_1_Source_(_Inout_z_bytecount_, (size), _Prepost_z_ _Prepost_bytecount_(size))
+#define _Inout_opt_z_bytecount_(size) _SAL1_1_Source_(_Inout_opt_z_bytecount_, (size), _Prepost_z_ _Prepost_opt_bytecount_(size))
+
+#define _Inout_z_count_c_(size) _SAL1_1_Source_(_Inout_z_count_c_, (size), _Prepost_z_ _Prepost_count_c_(size))
+#define _Inout_opt_z_count_c_(size) _SAL1_1_Source_(_Inout_opt_z_count_c_, (size), _Prepost_z_ _Prepost_opt_count_c_(size))
+#define _Inout_z_bytecount_c_(size) _SAL1_1_Source_(_Inout_z_bytecount_c_, (size), _Prepost_z_ _Prepost_bytecount_c_(size))
+#define _Inout_opt_z_bytecount_c_(size) _SAL1_1_Source_(_Inout_opt_z_bytecount_c_, (size), _Prepost_z_ _Prepost_opt_bytecount_c_(size))
+
+#define _Inout_ptrdiff_count_(size) _SAL1_1_Source_(_Inout_ptrdiff_count_, (size), _Pre_ptrdiff_count_(size))
+#define _Inout_opt_ptrdiff_count_(size) _SAL1_1_Source_(_Inout_opt_ptrdiff_count_, (size), _Pre_opt_ptrdiff_count_(size))
+
+#define _Inout_count_x_(size) _SAL1_1_Source_(_Inout_count_x_, (size), _Prepost_count_x_(size))
+#define _Inout_opt_count_x_(size) _SAL1_1_Source_(_Inout_opt_count_x_, (size), _Prepost_opt_count_x_(size))
+#define _Inout_bytecount_x_(size) _SAL1_1_Source_(_Inout_bytecount_x_, (size), _Prepost_bytecount_x_(size))
+#define _Inout_opt_bytecount_x_(size) _SAL1_1_Source_(_Inout_opt_bytecount_x_, (size), _Prepost_opt_bytecount_x_(size))
+
+// e.g. void AppendToLPSTR( _In_ LPCSTR szFrom, _Inout_cap_(cchTo) LPSTR* szTo, size_t cchTo );
+#define _Inout_cap_(size) _SAL1_1_Source_(_Inout_cap_, (size), _Pre_valid_cap_(size) _Post_valid_)
+#define _Inout_opt_cap_(size) _SAL1_1_Source_(_Inout_opt_cap_, (size), _Pre_opt_valid_cap_(size) _Post_valid_)
+#define _Inout_bytecap_(size) _SAL1_1_Source_(_Inout_bytecap_, (size), _Pre_valid_bytecap_(size) _Post_valid_)
+#define _Inout_opt_bytecap_(size) _SAL1_1_Source_(_Inout_opt_bytecap_, (size), _Pre_opt_valid_bytecap_(size) _Post_valid_)
+
+#define _Inout_cap_c_(size) _SAL1_1_Source_(_Inout_cap_c_, (size), _Pre_valid_cap_c_(size) _Post_valid_)
+#define _Inout_opt_cap_c_(size) _SAL1_1_Source_(_Inout_opt_cap_c_, (size), _Pre_opt_valid_cap_c_(size) _Post_valid_)
+#define _Inout_bytecap_c_(size) _SAL1_1_Source_(_Inout_bytecap_c_, (size), _Pre_valid_bytecap_c_(size) _Post_valid_)
+#define _Inout_opt_bytecap_c_(size) _SAL1_1_Source_(_Inout_opt_bytecap_c_, (size), _Pre_opt_valid_bytecap_c_(size) _Post_valid_)
+
+#define _Inout_cap_x_(size) _SAL1_1_Source_(_Inout_cap_x_, (size), _Pre_valid_cap_x_(size) _Post_valid_)
+#define _Inout_opt_cap_x_(size) _SAL1_1_Source_(_Inout_opt_cap_x_, (size), _Pre_opt_valid_cap_x_(size) _Post_valid_)
+#define _Inout_bytecap_x_(size) _SAL1_1_Source_(_Inout_bytecap_x_, (size), _Pre_valid_bytecap_x_(size) _Post_valid_)
+#define _Inout_opt_bytecap_x_(size) _SAL1_1_Source_(_Inout_opt_bytecap_x_, (size), _Pre_opt_valid_bytecap_x_(size) _Post_valid_)
+
+// inout string buffers with writable size
+// e.g. void AppendStr( _In_z_ const char* szFrom, _Inout_z_cap_(cchTo) char* szTo, size_t cchTo );
+#define _Inout_z_cap_(size) _SAL1_1_Source_(_Inout_z_cap_, (size), _Pre_z_cap_(size) _Post_z_)
+#define _Inout_opt_z_cap_(size) _SAL1_1_Source_(_Inout_opt_z_cap_, (size), _Pre_opt_z_cap_(size) _Post_z_)
+#define _Inout_z_bytecap_(size) _SAL1_1_Source_(_Inout_z_bytecap_, (size), _Pre_z_bytecap_(size) _Post_z_)
+#define _Inout_opt_z_bytecap_(size) _SAL1_1_Source_(_Inout_opt_z_bytecap_, (size), _Pre_opt_z_bytecap_(size) _Post_z_)
+
+#define _Inout_z_cap_c_(size) _SAL1_1_Source_(_Inout_z_cap_c_, (size), _Pre_z_cap_c_(size) _Post_z_)
+#define _Inout_opt_z_cap_c_(size) _SAL1_1_Source_(_Inout_opt_z_cap_c_, (size), _Pre_opt_z_cap_c_(size) _Post_z_)
+#define _Inout_z_bytecap_c_(size) _SAL1_1_Source_(_Inout_z_bytecap_c_, (size), _Pre_z_bytecap_c_(size) _Post_z_)
+#define _Inout_opt_z_bytecap_c_(size) _SAL1_1_Source_(_Inout_opt_z_bytecap_c_, (size), _Pre_opt_z_bytecap_c_(size) _Post_z_)
+
+#define _Inout_z_cap_x_(size) _SAL1_1_Source_(_Inout_z_cap_x_, (size), _Pre_z_cap_x_(size) _Post_z_)
+#define _Inout_opt_z_cap_x_(size) _SAL1_1_Source_(_Inout_opt_z_cap_x_, (size), _Pre_opt_z_cap_x_(size) _Post_z_)
+#define _Inout_z_bytecap_x_(size) _SAL1_1_Source_(_Inout_z_bytecap_x_, (size), _Pre_z_bytecap_x_(size) _Post_z_)
+#define _Inout_opt_z_bytecap_x_(size) _SAL1_1_Source_(_Inout_opt_z_bytecap_x_, (size), _Pre_opt_z_bytecap_x_(size) _Post_z_)
+
+
+// returning pointers to valid objects
+#define _Ret_ _SAL1_1_Source_(_Ret_, (), _Ret_valid_)
+#define _Ret_opt_ _SAL1_1_Source_(_Ret_opt_, (), _Ret_opt_valid_)
+
+// annotations to express 'boundedness' of integral value parameter
+#define _In_bound_ _SAL1_1_Source_(_In_bound_, (), _In_bound_impl_)
+#define _Out_bound_ _SAL1_1_Source_(_Out_bound_, (), _Out_bound_impl_)
+#define _Ret_bound_ _SAL1_1_Source_(_Ret_bound_, (), _Ret_bound_impl_)
+#define _Deref_in_bound_ _SAL1_1_Source_(_Deref_in_bound_, (), _Deref_in_bound_impl_)
+#define _Deref_out_bound_ _SAL1_1_Source_(_Deref_out_bound_, (), _Deref_out_bound_impl_)
+#define _Deref_inout_bound_ _SAL1_1_Source_(_Deref_inout_bound_, (), _Deref_in_bound_ _Deref_out_bound_)
+#define _Deref_ret_bound_ _SAL1_1_Source_(_Deref_ret_bound_, (), _Deref_ret_bound_impl_)
+
+// e.g. HRESULT HrCreatePoint( _Deref_out_opt_ POINT** ppPT );
+#define _Deref_out_ _SAL1_1_Source_(_Deref_out_, (), _Out_ _Deref_post_valid_)
+#define _Deref_out_opt_ _SAL1_1_Source_(_Deref_out_opt_, (), _Out_ _Deref_post_opt_valid_)
+#define _Deref_opt_out_ _SAL1_1_Source_(_Deref_opt_out_, (), _Out_opt_ _Deref_post_valid_)
+#define _Deref_opt_out_opt_ _SAL1_1_Source_(_Deref_opt_out_opt_, (), _Out_opt_ _Deref_post_opt_valid_)
+
+// e.g. void CloneString( _In_z_ const WCHAR* wzFrom, _Deref_out_z_ WCHAR** pWzTo );
+#define _Deref_out_z_ _SAL1_1_Source_(_Deref_out_z_, (), _Out_ _Deref_post_z_)
+#define _Deref_out_opt_z_ _SAL1_1_Source_(_Deref_out_opt_z_, (), _Out_ _Deref_post_opt_z_)
+#define _Deref_opt_out_z_ _SAL1_1_Source_(_Deref_opt_out_z_, (), _Out_opt_ _Deref_post_z_)
+#define _Deref_opt_out_opt_z_ _SAL1_1_Source_(_Deref_opt_out_opt_z_, (), _Out_opt_ _Deref_post_opt_z_)
+
+//
+// _Deref_pre_ ---
+//
+// describing conditions for array elements of dereferenced pointer parameters that must be met before the call
+
+// e.g. void SaveStringArray( _In_count_(cStrings) _Deref_pre_z_ const WCHAR* const rgpwch[] );
+#define _Deref_pre_z_ _SAL1_1_Source_(_Deref_pre_z_, (), _Deref_pre1_impl_(__notnull_impl_notref) _Deref_pre1_impl_(__zterm_impl) _Pre_valid_impl_)
+#define _Deref_pre_opt_z_ _SAL1_1_Source_(_Deref_pre_opt_z_, (), _Deref_pre1_impl_(__maybenull_impl_notref) _Deref_pre1_impl_(__zterm_impl) _Pre_valid_impl_)
+
+// e.g. void FillInArrayOfStr32( _In_count_(cStrings) _Deref_pre_cap_c_(32) _Deref_post_z_ WCHAR* const rgpwch[] );
+// buffer capacity is described by another parameter
+#define _Deref_pre_cap_(size) _SAL1_1_Source_(_Deref_pre_cap_, (size), _Deref_pre1_impl_(__notnull_impl_notref) _Deref_pre1_impl_(__cap_impl(size)))
+#define _Deref_pre_opt_cap_(size) _SAL1_1_Source_(_Deref_pre_opt_cap_, (size), _Deref_pre1_impl_(__maybenull_impl_notref) _Deref_pre1_impl_(__cap_impl(size)))
+#define _Deref_pre_bytecap_(size) _SAL1_1_Source_(_Deref_pre_bytecap_, (size), _Deref_pre1_impl_(__notnull_impl_notref) _Deref_pre1_impl_(__bytecap_impl(size)))
+#define _Deref_pre_opt_bytecap_(size) _SAL1_1_Source_(_Deref_pre_opt_bytecap_, (size), _Deref_pre1_impl_(__maybenull_impl_notref) _Deref_pre1_impl_(__bytecap_impl(size)))
+
+// buffer capacity is described by a constant expression
+#define _Deref_pre_cap_c_(size) _SAL1_1_Source_(_Deref_pre_cap_c_, (size), _Deref_pre1_impl_(__notnull_impl_notref) _Deref_pre1_impl_(__cap_c_impl(size)))
+#define _Deref_pre_opt_cap_c_(size) _SAL1_1_Source_(_Deref_pre_opt_cap_c_, (size), _Deref_pre1_impl_(__maybenull_impl_notref) _Deref_pre1_impl_(__cap_c_impl(size)))
+#define _Deref_pre_bytecap_c_(size) _SAL1_1_Source_(_Deref_pre_bytecap_c_, (size), _Deref_pre1_impl_(__notnull_impl_notref) _Deref_pre1_impl_(__bytecap_c_impl(size)))
+#define _Deref_pre_opt_bytecap_c_(size) _SAL1_1_Source_(_Deref_pre_opt_bytecap_c_, (size), _Deref_pre1_impl_(__maybenull_impl_notref) _Deref_pre1_impl_(__bytecap_c_impl(size)))
+
+// buffer capacity is described by a complex condition
+#define _Deref_pre_cap_x_(size) _SAL1_1_Source_(_Deref_pre_cap_x_, (size), _Deref_pre1_impl_(__notnull_impl_notref) _Deref_pre1_impl_(__cap_x_impl(size)))
+#define _Deref_pre_opt_cap_x_(size) _SAL1_1_Source_(_Deref_pre_opt_cap_x_, (size), _Deref_pre1_impl_(__maybenull_impl_notref) _Deref_pre1_impl_(__cap_x_impl(size)))
+#define _Deref_pre_bytecap_x_(size) _SAL1_1_Source_(_Deref_pre_bytecap_x_, (size), _Deref_pre1_impl_(__notnull_impl_notref) _Deref_pre1_impl_(__bytecap_x_impl(size)))
+#define _Deref_pre_opt_bytecap_x_(size) _SAL1_1_Source_(_Deref_pre_opt_bytecap_x_, (size), _Deref_pre1_impl_(__maybenull_impl_notref) _Deref_pre1_impl_(__bytecap_x_impl(size)))
+
+// convenience macros for nullterminated buffers with given capacity
+#define _Deref_pre_z_cap_(size) _SAL1_1_Source_(_Deref_pre_z_cap_, (size), _Deref_pre1_impl_(__notnull_impl_notref) _Deref_pre2_impl_(__zterm_impl,__cap_impl(size)) _Pre_valid_impl_)
+#define _Deref_pre_opt_z_cap_(size) _SAL1_1_Source_(_Deref_pre_opt_z_cap_, (size), _Deref_pre1_impl_(__maybenull_impl_notref) _Deref_pre2_impl_(__zterm_impl,__cap_impl(size)) _Pre_valid_impl_)
+#define _Deref_pre_z_bytecap_(size) _SAL1_1_Source_(_Deref_pre_z_bytecap_, (size), _Deref_pre1_impl_(__notnull_impl_notref) _Deref_pre2_impl_(__zterm_impl,__bytecap_impl(size)) _Pre_valid_impl_)
+#define _Deref_pre_opt_z_bytecap_(size) _SAL1_1_Source_(_Deref_pre_opt_z_bytecap_, (size), _Deref_pre1_impl_(__maybenull_impl_notref) _Deref_pre2_impl_(__zterm_impl,__bytecap_impl(size)) _Pre_valid_impl_)
+
+#define _Deref_pre_z_cap_c_(size) _SAL1_1_Source_(_Deref_pre_z_cap_c_, (size), _Deref_pre1_impl_(__notnull_impl_notref) _Deref_pre2_impl_(__zterm_impl,__cap_c_impl(size)) _Pre_valid_impl_)
+#define _Deref_pre_opt_z_cap_c_(size) _SAL1_1_Source_(_Deref_pre_opt_z_cap_c_, (size), _Deref_pre1_impl_(__maybenull_impl_notref) _Deref_pre2_impl_(__zterm_impl,__cap_c_impl(size)) _Pre_valid_impl_)
+#define _Deref_pre_z_bytecap_c_(size) _SAL1_1_Source_(_Deref_pre_z_bytecap_c_, (size), _Deref_pre1_impl_(__notnull_impl_notref) _Deref_pre2_impl_(__zterm_impl,__bytecap_c_impl(size)) _Pre_valid_impl_)
+#define _Deref_pre_opt_z_bytecap_c_(size) _SAL1_1_Source_(_Deref_pre_opt_z_bytecap_c_, (size), _Deref_pre1_impl_(__maybenull_impl_notref) _Deref_pre2_impl_(__zterm_impl,__bytecap_c_impl(size)) _Pre_valid_impl_)
+
+#define _Deref_pre_z_cap_x_(size) _SAL1_1_Source_(_Deref_pre_z_cap_x_, (size), _Deref_pre1_impl_(__notnull_impl_notref) _Deref_pre2_impl_(__zterm_impl,__cap_x_impl(size)) _Pre_valid_impl_)
+#define _Deref_pre_opt_z_cap_x_(size) _SAL1_1_Source_(_Deref_pre_opt_z_cap_x_, (size), _Deref_pre1_impl_(__maybenull_impl_notref) _Deref_pre2_impl_(__zterm_impl,__cap_x_impl(size)) _Pre_valid_impl_)
+#define _Deref_pre_z_bytecap_x_(size) _SAL1_1_Source_(_Deref_pre_z_bytecap_x_, (size), _Deref_pre1_impl_(__notnull_impl_notref) _Deref_pre2_impl_(__zterm_impl,__bytecap_x_impl(size)) _Pre_valid_impl_)
+#define _Deref_pre_opt_z_bytecap_x_(size) _SAL1_1_Source_(_Deref_pre_opt_z_bytecap_x_, (size), _Deref_pre1_impl_(__maybenull_impl_notref) _Deref_pre2_impl_(__zterm_impl,__bytecap_x_impl(size)) _Pre_valid_impl_)
+
+// known capacity and valid but unknown readable extent
+#define _Deref_pre_valid_cap_(size) _SAL1_1_Source_(_Deref_pre_valid_cap_, (size), _Deref_pre1_impl_(__notnull_impl_notref) _Deref_pre1_impl_(__cap_impl(size)) _Pre_valid_impl_)
+#define _Deref_pre_opt_valid_cap_(size) _SAL1_1_Source_(_Deref_pre_opt_valid_cap_, (size), _Deref_pre1_impl_(__maybenull_impl_notref) _Deref_pre1_impl_(__cap_impl(size)) _Pre_valid_impl_)
+#define _Deref_pre_valid_bytecap_(size) _SAL1_1_Source_(_Deref_pre_valid_bytecap_, (size), _Deref_pre1_impl_(__notnull_impl_notref) _Deref_pre1_impl_(__bytecap_impl(size)) _Pre_valid_impl_)
+#define _Deref_pre_opt_valid_bytecap_(size) _SAL1_1_Source_(_Deref_pre_opt_valid_bytecap_, (size), _Deref_pre1_impl_(__maybenull_impl_notref) _Deref_pre1_impl_(__bytecap_impl(size)) _Pre_valid_impl_)
+
+#define _Deref_pre_valid_cap_c_(size) _SAL1_1_Source_(_Deref_pre_valid_cap_c_, (size), _Deref_pre1_impl_(__notnull_impl_notref) _Deref_pre1_impl_(__cap_c_impl(size)) _Pre_valid_impl_)
+#define _Deref_pre_opt_valid_cap_c_(size) _SAL1_1_Source_(_Deref_pre_opt_valid_cap_c_, (size), _Deref_pre1_impl_(__maybenull_impl_notref) _Deref_pre1_impl_(__cap_c_impl(size)) _Pre_valid_impl_)
+#define _Deref_pre_valid_bytecap_c_(size) _SAL1_1_Source_(_Deref_pre_valid_bytecap_c_, (size), _Deref_pre1_impl_(__notnull_impl_notref) _Deref_pre1_impl_(__bytecap_c_impl(size)) _Pre_valid_impl_)
+#define _Deref_pre_opt_valid_bytecap_c_(size) _SAL1_1_Source_(_Deref_pre_opt_valid_bytecap_c_, (size), _Deref_pre1_impl_(__maybenull_impl_notref) _Deref_pre1_impl_(__bytecap_c_impl(size)) _Pre_valid_impl_)
+
+#define _Deref_pre_valid_cap_x_(size) _SAL1_1_Source_(_Deref_pre_valid_cap_x_, (size), _Deref_pre1_impl_(__notnull_impl_notref) _Deref_pre1_impl_(__cap_x_impl(size)) _Pre_valid_impl_)
+#define _Deref_pre_opt_valid_cap_x_(size) _SAL1_1_Source_(_Deref_pre_opt_valid_cap_x_, (size), _Deref_pre1_impl_(__maybenull_impl_notref) _Deref_pre1_impl_(__cap_x_impl(size)) _Pre_valid_impl_)
+#define _Deref_pre_valid_bytecap_x_(size) _SAL1_1_Source_(_Deref_pre_valid_bytecap_x_, (size), _Deref_pre1_impl_(__notnull_impl_notref) _Deref_pre1_impl_(__bytecap_x_impl(size)) _Pre_valid_impl_)
+#define _Deref_pre_opt_valid_bytecap_x_(size) _SAL1_1_Source_(_Deref_pre_opt_valid_bytecap_x_, (size), _Deref_pre1_impl_(__maybenull_impl_notref) _Deref_pre1_impl_(__bytecap_x_impl(size)) _Pre_valid_impl_)
+
+// e.g. void SaveMatrix( _In_count_(n) _Deref_pre_count_(n) const Elem** matrix, size_t n );
+// valid buffer extent is described by another parameter
+#define _Deref_pre_count_(size) _SAL1_1_Source_(_Deref_pre_count_, (size), _Deref_pre1_impl_(__notnull_impl_notref) _Deref_pre1_impl_(__count_impl(size)) _Pre_valid_impl_)
+#define _Deref_pre_opt_count_(size) _SAL1_1_Source_(_Deref_pre_opt_count_, (size), _Deref_pre1_impl_(__maybenull_impl_notref) _Deref_pre1_impl_(__count_impl(size)) _Pre_valid_impl_)
+#define _Deref_pre_bytecount_(size) _SAL1_1_Source_(_Deref_pre_bytecount_, (size), _Deref_pre1_impl_(__notnull_impl_notref) _Deref_pre1_impl_(__bytecount_impl(size)) _Pre_valid_impl_)
+#define _Deref_pre_opt_bytecount_(size) _SAL1_1_Source_(_Deref_pre_opt_bytecount_, (size), _Deref_pre1_impl_(__maybenull_impl_notref) _Deref_pre1_impl_(__bytecount_impl(size)) _Pre_valid_impl_)
+
+// valid buffer extent is described by a constant expression
+#define _Deref_pre_count_c_(size) _SAL1_1_Source_(_Deref_pre_count_c_, (size), _Deref_pre1_impl_(__notnull_impl_notref) _Deref_pre1_impl_(__count_c_impl(size)) _Pre_valid_impl_)
+#define _Deref_pre_opt_count_c_(size) _SAL1_1_Source_(_Deref_pre_opt_count_c_, (size), _Deref_pre1_impl_(__maybenull_impl_notref) _Deref_pre1_impl_(__count_c_impl(size)) _Pre_valid_impl_)
+#define _Deref_pre_bytecount_c_(size) _SAL1_1_Source_(_Deref_pre_bytecount_c_, (size), _Deref_pre1_impl_(__notnull_impl_notref) _Deref_pre1_impl_(__bytecount_c_impl(size)) _Pre_valid_impl_)
+#define _Deref_pre_opt_bytecount_c_(size) _SAL1_1_Source_(_Deref_pre_opt_bytecount_c_, (size), _Deref_pre1_impl_(__maybenull_impl_notref) _Deref_pre1_impl_(__bytecount_c_impl(size)) _Pre_valid_impl_)
+
+// valid buffer extent is described by a complex expression
+#define _Deref_pre_count_x_(size) _SAL1_1_Source_(_Deref_pre_count_x_, (size), _Deref_pre1_impl_(__notnull_impl_notref) _Deref_pre1_impl_(__count_x_impl(size)) _Pre_valid_impl_)
+#define _Deref_pre_opt_count_x_(size) _SAL1_1_Source_(_Deref_pre_opt_count_x_, (size), _Deref_pre1_impl_(__maybenull_impl_notref) _Deref_pre1_impl_(__count_x_impl(size)) _Pre_valid_impl_)
+#define _Deref_pre_bytecount_x_(size) _SAL1_1_Source_(_Deref_pre_bytecount_x_, (size), _Deref_pre1_impl_(__notnull_impl_notref) _Deref_pre1_impl_(__bytecount_x_impl(size)) _Pre_valid_impl_)
+#define _Deref_pre_opt_bytecount_x_(size) _SAL1_1_Source_(_Deref_pre_opt_bytecount_x_, (size), _Deref_pre1_impl_(__maybenull_impl_notref) _Deref_pre1_impl_(__bytecount_x_impl(size)) _Pre_valid_impl_)
+
+// e.g. void PrintStringArray( _In_count_(cElems) _Deref_pre_valid_ LPCSTR rgStr[], size_t cElems );
+#define _Deref_pre_valid_ _SAL1_1_Source_(_Deref_pre_valid_, (), _Deref_pre1_impl_(__notnull_impl_notref) _Pre_valid_impl_)
+#define _Deref_pre_opt_valid_ _SAL1_1_Source_(_Deref_pre_opt_valid_, (), _Deref_pre1_impl_(__maybenull_impl_notref) _Pre_valid_impl_)
+#define _Deref_pre_invalid_ _SAL1_1_Source_(_Deref_pre_invalid_, (), _Deref_pre1_impl_(__notvalid_impl))
+
+#define _Deref_pre_notnull_ _SAL1_1_Source_(_Deref_pre_notnull_, (), _Deref_pre1_impl_(__notnull_impl_notref))
+#define _Deref_pre_maybenull_ _SAL1_1_Source_(_Deref_pre_maybenull_, (), _Deref_pre1_impl_(__maybenull_impl_notref))
+#define _Deref_pre_null_ _SAL1_1_Source_(_Deref_pre_null_, (), _Deref_pre1_impl_(__null_impl_notref))
+
+// restrict access rights
+#define _Deref_pre_readonly_ _SAL1_1_Source_(_Deref_pre_readonly_, (), _Deref_pre1_impl_(__readaccess_impl_notref))
+#define _Deref_pre_writeonly_ _SAL1_1_Source_(_Deref_pre_writeonly_, (), _Deref_pre1_impl_(__writeaccess_impl_notref))
+
+//
+// _Deref_post_ ---
+//
+// describing conditions for array elements or dereferenced pointer parameters that hold after the call
+
+// e.g. void CloneString( _In_z_ const Wchar_t* wzIn _Out_ _Deref_post_z_ WCHAR** pWzOut );
+#define _Deref_post_z_ _SAL1_1_Source_(_Deref_post_z_, (), _Deref_post1_impl_(__notnull_impl_notref) _Deref_post1_impl_(__zterm_impl) _Post_valid_impl_)
+#define _Deref_post_opt_z_ _SAL1_1_Source_(_Deref_post_opt_z_, (), _Deref_post1_impl_(__maybenull_impl_notref) _Deref_post1_impl_(__zterm_impl) _Post_valid_impl_)
+
+// e.g. HRESULT HrAllocateMemory( size_t cb, _Out_ _Deref_post_bytecap_(cb) void** ppv );
+// buffer capacity is described by another parameter
+#define _Deref_post_cap_(size) _SAL1_1_Source_(_Deref_post_cap_, (size), _Deref_post1_impl_(__notnull_impl_notref) _Deref_post1_impl_(__cap_impl(size)))
+#define _Deref_post_opt_cap_(size) _SAL1_1_Source_(_Deref_post_opt_cap_, (size), _Deref_post1_impl_(__maybenull_impl_notref) _Deref_post1_impl_(__cap_impl(size)))
+#define _Deref_post_bytecap_(size) _SAL1_1_Source_(_Deref_post_bytecap_, (size), _Deref_post1_impl_(__notnull_impl_notref) _Deref_post1_impl_(__bytecap_impl(size)))
+#define _Deref_post_opt_bytecap_(size) _SAL1_1_Source_(_Deref_post_opt_bytecap_, (size), _Deref_post1_impl_(__maybenull_impl_notref) _Deref_post1_impl_(__bytecap_impl(size)))
+
+// buffer capacity is described by a constant expression
+#define _Deref_post_cap_c_(size) _SAL1_1_Source_(_Deref_post_cap_c_, (size), _Deref_post1_impl_(__notnull_impl_notref) _Deref_post1_impl_(__cap_c_impl(size)))
+#define _Deref_post_opt_cap_c_(size) _SAL1_1_Source_(_Deref_post_opt_cap_c_, (size), _Deref_post1_impl_(__maybenull_impl_notref) _Deref_post1_impl_(__cap_c_impl(size)))
+#define _Deref_post_bytecap_c_(size) _SAL1_1_Source_(_Deref_post_bytecap_c_, (size), _Deref_post1_impl_(__notnull_impl_notref) _Deref_post1_impl_(__bytecap_c_impl(size)))
+#define _Deref_post_opt_bytecap_c_(size) _SAL1_1_Source_(_Deref_post_opt_bytecap_c_, (size), _Deref_post1_impl_(__maybenull_impl_notref) _Deref_post1_impl_(__bytecap_c_impl(size)))
+
+// buffer capacity is described by a complex expression
+#define _Deref_post_cap_x_(size) _SAL1_1_Source_(_Deref_post_cap_x_, (size), _Deref_post1_impl_(__notnull_impl_notref) _Deref_post1_impl_(__cap_x_impl(size)))
+#define _Deref_post_opt_cap_x_(size) _SAL1_1_Source_(_Deref_post_opt_cap_x_, (size), _Deref_post1_impl_(__maybenull_impl_notref) _Deref_post1_impl_(__cap_x_impl(size)))
+#define _Deref_post_bytecap_x_(size) _SAL1_1_Source_(_Deref_post_bytecap_x_, (size), _Deref_post1_impl_(__notnull_impl_notref) _Deref_post1_impl_(__bytecap_x_impl(size)))
+#define _Deref_post_opt_bytecap_x_(size) _SAL1_1_Source_(_Deref_post_opt_bytecap_x_, (size), _Deref_post1_impl_(__maybenull_impl_notref) _Deref_post1_impl_(__bytecap_x_impl(size)))
+
+// convenience macros for nullterminated buffers with given capacity
+#define _Deref_post_z_cap_(size) _SAL1_1_Source_(_Deref_post_z_cap_, (size), _Deref_post1_impl_(__notnull_impl_notref) _Deref_post2_impl_(__zterm_impl,__cap_impl(size)) _Post_valid_impl_)
+#define _Deref_post_opt_z_cap_(size) _SAL1_1_Source_(_Deref_post_opt_z_cap_, (size), _Deref_post1_impl_(__maybenull_impl_notref) _Deref_post2_impl_(__zterm_impl,__cap_impl(size)) _Post_valid_impl_)
+#define _Deref_post_z_bytecap_(size) _SAL1_1_Source_(_Deref_post_z_bytecap_, (size), _Deref_post1_impl_(__notnull_impl_notref) _Deref_post2_impl_(__zterm_impl,__bytecap_impl(size)) _Post_valid_impl_)
+#define _Deref_post_opt_z_bytecap_(size) _SAL1_1_Source_(_Deref_post_opt_z_bytecap_, (size), _Deref_post1_impl_(__maybenull_impl_notref) _Deref_post2_impl_(__zterm_impl,__bytecap_impl(size)) _Post_valid_impl_)
+
+#define _Deref_post_z_cap_c_(size) _SAL1_1_Source_(_Deref_post_z_cap_c_, (size), _Deref_post1_impl_(__notnull_impl_notref) _Deref_post2_impl_(__zterm_impl,__cap_c_impl(size)) _Post_valid_impl_)
+#define _Deref_post_opt_z_cap_c_(size) _SAL1_1_Source_(_Deref_post_opt_z_cap_c_, (size), _Deref_post1_impl_(__maybenull_impl_notref) _Deref_post2_impl_(__zterm_impl,__cap_c_impl(size)) _Post_valid_impl_)
+#define _Deref_post_z_bytecap_c_(size) _SAL1_1_Source_(_Deref_post_z_bytecap_c_, (size), _Deref_post1_impl_(__notnull_impl_notref) _Deref_post2_impl_(__zterm_impl,__bytecap_c_impl(size)) _Post_valid_impl_)
+#define _Deref_post_opt_z_bytecap_c_(size) _SAL1_1_Source_(_Deref_post_opt_z_bytecap_c_, (size), _Deref_post1_impl_(__maybenull_impl_notref) _Deref_post2_impl_(__zterm_impl,__bytecap_c_impl(size)) _Post_valid_impl_)
+
+#define _Deref_post_z_cap_x_(size) _SAL1_1_Source_(_Deref_post_z_cap_x_, (size), _Deref_post1_impl_(__notnull_impl_notref) _Deref_post2_impl_(__zterm_impl,__cap_x_impl(size)) _Post_valid_impl_)
+#define _Deref_post_opt_z_cap_x_(size) _SAL1_1_Source_(_Deref_post_opt_z_cap_x_, (size), _Deref_post1_impl_(__maybenull_impl_notref) _Deref_post2_impl_(__zterm_impl,__cap_x_impl(size)) _Post_valid_impl_)
+#define _Deref_post_z_bytecap_x_(size) _SAL1_1_Source_(_Deref_post_z_bytecap_x_, (size), _Deref_post1_impl_(__notnull_impl_notref) _Deref_post2_impl_(__zterm_impl,__bytecap_x_impl(size)) _Post_valid_impl_)
+#define _Deref_post_opt_z_bytecap_x_(size) _SAL1_1_Source_(_Deref_post_opt_z_bytecap_x_, (size), _Deref_post1_impl_(__maybenull_impl_notref) _Deref_post2_impl_(__zterm_impl,__bytecap_x_impl(size)) _Post_valid_impl_)
+
+// known capacity and valid but unknown readable extent
+#define _Deref_post_valid_cap_(size) _SAL1_1_Source_(_Deref_post_valid_cap_, (size), _Deref_post1_impl_(__notnull_impl_notref) _Deref_post1_impl_(__cap_impl(size)) _Post_valid_impl_)
+#define _Deref_post_opt_valid_cap_(size) _SAL1_1_Source_(_Deref_post_opt_valid_cap_, (size), _Deref_post1_impl_(__maybenull_impl_notref) _Deref_post1_impl_(__cap_impl(size)) _Post_valid_impl_)
+#define _Deref_post_valid_bytecap_(size) _SAL1_1_Source_(_Deref_post_valid_bytecap_, (size), _Deref_post1_impl_(__notnull_impl_notref) _Deref_post1_impl_(__bytecap_impl(size)) _Post_valid_impl_)
+#define _Deref_post_opt_valid_bytecap_(size) _SAL1_1_Source_(_Deref_post_opt_valid_bytecap_, (size), _Deref_post1_impl_(__maybenull_impl_notref) _Deref_post1_impl_(__bytecap_impl(size)) _Post_valid_impl_)
+
+#define _Deref_post_valid_cap_c_(size) _SAL1_1_Source_(_Deref_post_valid_cap_c_, (size), _Deref_post1_impl_(__notnull_impl_notref) _Deref_post1_impl_(__cap_c_impl(size)) _Post_valid_impl_)
+#define _Deref_post_opt_valid_cap_c_(size) _SAL1_1_Source_(_Deref_post_opt_valid_cap_c_, (size), _Deref_post1_impl_(__maybenull_impl_notref) _Deref_post1_impl_(__cap_c_impl(size)) _Post_valid_impl_)
+#define _Deref_post_valid_bytecap_c_(size) _SAL1_1_Source_(_Deref_post_valid_bytecap_c_, (size), _Deref_post1_impl_(__notnull_impl_notref) _Deref_post1_impl_(__bytecap_c_impl(size)) _Post_valid_impl_)
+#define _Deref_post_opt_valid_bytecap_c_(size) _SAL1_1_Source_(_Deref_post_opt_valid_bytecap_c_, (size), _Deref_post1_impl_(__maybenull_impl_notref) _Deref_post1_impl_(__bytecap_c_impl(size)) _Post_valid_impl_)
+
+#define _Deref_post_valid_cap_x_(size) _SAL1_1_Source_(_Deref_post_valid_cap_x_, (size), _Deref_post1_impl_(__notnull_impl_notref) _Deref_post1_impl_(__cap_x_impl(size)) _Post_valid_impl_)
+#define _Deref_post_opt_valid_cap_x_(size) _SAL1_1_Source_(_Deref_post_opt_valid_cap_x_, (size), _Deref_post1_impl_(__maybenull_impl_notref) _Deref_post1_impl_(__cap_x_impl(size)) _Post_valid_impl_)
+#define _Deref_post_valid_bytecap_x_(size) _SAL1_1_Source_(_Deref_post_valid_bytecap_x_, (size), _Deref_post1_impl_(__notnull_impl_notref) _Deref_post1_impl_(__bytecap_x_impl(size)) _Post_valid_impl_)
+#define _Deref_post_opt_valid_bytecap_x_(size) _SAL1_1_Source_(_Deref_post_opt_valid_bytecap_x_, (size), _Deref_post1_impl_(__maybenull_impl_notref) _Deref_post1_impl_(__bytecap_x_impl(size)) _Post_valid_impl_)
+
+// e.g. HRESULT HrAllocateZeroInitializedMemory( size_t cb, _Out_ _Deref_post_bytecount_(cb) void** ppv );
+// valid buffer extent is described by another parameter
+#define _Deref_post_count_(size) _SAL1_1_Source_(_Deref_post_count_, (size), _Deref_post1_impl_(__notnull_impl_notref) _Deref_post1_impl_(__count_impl(size)) _Post_valid_impl_)
+#define _Deref_post_opt_count_(size) _SAL1_1_Source_(_Deref_post_opt_count_, (size), _Deref_post1_impl_(__maybenull_impl_notref) _Deref_post1_impl_(__count_impl(size)) _Post_valid_impl_)
+#define _Deref_post_bytecount_(size) _SAL1_1_Source_(_Deref_post_bytecount_, (size), _Deref_post1_impl_(__notnull_impl_notref) _Deref_post1_impl_(__bytecount_impl(size)) _Post_valid_impl_)
+#define _Deref_post_opt_bytecount_(size) _SAL1_1_Source_(_Deref_post_opt_bytecount_, (size), _Deref_post1_impl_(__maybenull_impl_notref) _Deref_post1_impl_(__bytecount_impl(size)) _Post_valid_impl_)
+
+// buffer capacity is described by a constant expression
+#define _Deref_post_count_c_(size) _SAL1_1_Source_(_Deref_post_count_c_, (size), _Deref_post1_impl_(__notnull_impl_notref) _Deref_post1_impl_(__count_c_impl(size)) _Post_valid_impl_)
+#define _Deref_post_opt_count_c_(size) _SAL1_1_Source_(_Deref_post_opt_count_c_, (size), _Deref_post1_impl_(__maybenull_impl_notref) _Deref_post1_impl_(__count_c_impl(size)) _Post_valid_impl_)
+#define _Deref_post_bytecount_c_(size) _SAL1_1_Source_(_Deref_post_bytecount_c_, (size), _Deref_post1_impl_(__notnull_impl_notref) _Deref_post1_impl_(__bytecount_c_impl(size)) _Post_valid_impl_)
+#define _Deref_post_opt_bytecount_c_(size) _SAL1_1_Source_(_Deref_post_opt_bytecount_c_, (size), _Deref_post1_impl_(__maybenull_impl_notref) _Deref_post1_impl_(__bytecount_c_impl(size)) _Post_valid_impl_)
+
+// buffer capacity is described by a complex expression
+#define _Deref_post_count_x_(size) _SAL1_1_Source_(_Deref_post_count_x_, (size), _Deref_post1_impl_(__notnull_impl_notref) _Deref_post1_impl_(__count_x_impl(size)) _Post_valid_impl_)
+#define _Deref_post_opt_count_x_(size) _SAL1_1_Source_(_Deref_post_opt_count_x_, (size), _Deref_post1_impl_(__maybenull_impl_notref) _Deref_post1_impl_(__count_x_impl(size)) _Post_valid_impl_)
+#define _Deref_post_bytecount_x_(size) _SAL1_1_Source_(_Deref_post_bytecount_x_, (size), _Deref_post1_impl_(__notnull_impl_notref) _Deref_post1_impl_(__bytecount_x_impl(size)) _Post_valid_impl_)
+#define _Deref_post_opt_bytecount_x_(size) _SAL1_1_Source_(_Deref_post_opt_bytecount_x_, (size), _Deref_post1_impl_(__maybenull_impl_notref) _Deref_post1_impl_(__bytecount_x_impl(size)) _Post_valid_impl_)
+
+// e.g. void GetStrings( _Out_count_(cElems) _Deref_post_valid_ LPSTR const rgStr[], size_t cElems );
+#define _Deref_post_valid_ _SAL1_1_Source_(_Deref_post_valid_, (), _Deref_post1_impl_(__notnull_impl_notref) _Post_valid_impl_)
+#define _Deref_post_opt_valid_ _SAL1_1_Source_(_Deref_post_opt_valid_, (), _Deref_post1_impl_(__maybenull_impl_notref) _Post_valid_impl_)
+
+#define _Deref_post_notnull_ _SAL1_1_Source_(_Deref_post_notnull_, (), _Deref_post1_impl_(__notnull_impl_notref))
+#define _Deref_post_maybenull_ _SAL1_1_Source_(_Deref_post_maybenull_, (), _Deref_post1_impl_(__maybenull_impl_notref))
+#define _Deref_post_null_ _SAL1_1_Source_(_Deref_post_null_, (), _Deref_post1_impl_(__null_impl_notref))
+
+//
+// _Deref_ret_ ---
+//
+
+#define _Deref_ret_z_ _SAL1_1_Source_(_Deref_ret_z_, (), _Deref_ret1_impl_(__notnull_impl_notref) _Deref_ret1_impl_(__zterm_impl))
+#define _Deref_ret_opt_z_ _SAL1_1_Source_(_Deref_ret_opt_z_, (), _Deref_ret1_impl_(__maybenull_impl_notref) _Ret1_impl_(__zterm_impl))
+
+//
+// special _Deref_ ---
+//
+#define _Deref2_pre_readonly_ _SAL1_1_Source_(_Deref2_pre_readonly_, (), _Deref2_pre1_impl_(__readaccess_impl_notref))
+
+//
+// _Ret_ ---
+//
+
+// e.g. _Ret_opt_valid_ LPSTR void* CloneSTR( _Pre_valid_ LPSTR src );
+#define _Ret_opt_valid_ _SAL1_1_Source_(_Ret_opt_valid_, (), _Ret1_impl_(__maybenull_impl_notref) _Ret_valid_impl_)
+#define _Ret_opt_z_ _SAL1_1_Source_(_Ret_opt_z_, (), _Ret2_impl_(__maybenull_impl,__zterm_impl) _Ret_valid_impl_)
+
+// e.g. _Ret_opt_bytecap_(cb) void* AllocateMemory( size_t cb );
+// Buffer capacity is described by another parameter
+#define _Ret_cap_(size) _SAL1_1_Source_(_Ret_cap_, (size), _Ret1_impl_(__notnull_impl_notref) _Ret1_impl_(__cap_impl(size)))
+#define _Ret_opt_cap_(size) _SAL1_1_Source_(_Ret_opt_cap_, (size), _Ret1_impl_(__maybenull_impl_notref) _Ret1_impl_(__cap_impl(size)))
+#define _Ret_bytecap_(size) _SAL1_1_Source_(_Ret_bytecap_, (size), _Ret1_impl_(__notnull_impl_notref) _Ret1_impl_(__bytecap_impl(size)))
+#define _Ret_opt_bytecap_(size) _SAL1_1_Source_(_Ret_opt_bytecap_, (size), _Ret1_impl_(__maybenull_impl_notref) _Ret1_impl_(__bytecap_impl(size)))
+
+// Buffer capacity is described by a constant expression
+#define _Ret_cap_c_(size) _SAL1_1_Source_(_Ret_cap_c_, (size), _Ret1_impl_(__notnull_impl_notref) _Ret1_impl_(__cap_c_impl(size)))
+#define _Ret_opt_cap_c_(size) _SAL1_1_Source_(_Ret_opt_cap_c_, (size), _Ret1_impl_(__maybenull_impl_notref) _Ret1_impl_(__cap_c_impl(size)))
+#define _Ret_bytecap_c_(size) _SAL1_1_Source_(_Ret_bytecap_c_, (size), _Ret1_impl_(__notnull_impl_notref) _Ret1_impl_(__bytecap_c_impl(size)))
+#define _Ret_opt_bytecap_c_(size) _SAL1_1_Source_(_Ret_opt_bytecap_c_, (size), _Ret1_impl_(__maybenull_impl_notref) _Ret1_impl_(__bytecap_c_impl(size)))
+
+// Buffer capacity is described by a complex condition
+#define _Ret_cap_x_(size) _SAL1_1_Source_(_Ret_cap_x_, (size), _Ret1_impl_(__notnull_impl_notref) _Ret1_impl_(__cap_x_impl(size)))
+#define _Ret_opt_cap_x_(size) _SAL1_1_Source_(_Ret_opt_cap_x_, (size), _Ret1_impl_(__maybenull_impl_notref) _Ret1_impl_(__cap_x_impl(size)))
+#define _Ret_bytecap_x_(size) _SAL1_1_Source_(_Ret_bytecap_x_, (size), _Ret1_impl_(__notnull_impl_notref) _Ret1_impl_(__bytecap_x_impl(size)))
+#define _Ret_opt_bytecap_x_(size) _SAL1_1_Source_(_Ret_opt_bytecap_x_, (size), _Ret1_impl_(__maybenull_impl_notref) _Ret1_impl_(__bytecap_x_impl(size)))
+
+// return value is nullterminated and capacity is given by another parameter
+#define _Ret_z_cap_(size) _SAL1_1_Source_(_Ret_z_cap_, (size), _Ret1_impl_(__notnull_impl_notref) _Ret2_impl_(__zterm_impl,__cap_impl(size)) _Ret_valid_impl_)
+#define _Ret_opt_z_cap_(size) _SAL1_1_Source_(_Ret_opt_z_cap_, (size), _Ret1_impl_(__maybenull_impl_notref) _Ret2_impl_(__zterm_impl,__cap_impl(size)) _Ret_valid_impl_)
+#define _Ret_z_bytecap_(size) _SAL1_1_Source_(_Ret_z_bytecap_, (size), _Ret1_impl_(__notnull_impl_notref) _Ret2_impl_(__zterm_impl,__bytecap_impl(size)) _Ret_valid_impl_)
+#define _Ret_opt_z_bytecap_(size) _SAL1_1_Source_(_Ret_opt_z_bytecap_, (size), _Ret1_impl_(__maybenull_impl_notref) _Ret2_impl_(__zterm_impl,__bytecap_impl(size)) _Ret_valid_impl_)
+
+// e.g. _Ret_opt_bytecount_(cb) void* AllocateZeroInitializedMemory( size_t cb );
+// Valid Buffer extent is described by another parameter
+#define _Ret_count_(size) _SAL1_1_Source_(_Ret_count_, (size), _Ret1_impl_(__notnull_impl_notref) _Ret1_impl_(__count_impl(size)) _Ret_valid_impl_)
+#define _Ret_opt_count_(size) _SAL1_1_Source_(_Ret_opt_count_, (size), _Ret1_impl_(__maybenull_impl_notref) _Ret1_impl_(__count_impl(size)) _Ret_valid_impl_)
+#define _Ret_bytecount_(size) _SAL1_1_Source_(_Ret_bytecount_, (size), _Ret1_impl_(__notnull_impl_notref) _Ret1_impl_(__bytecount_impl(size)) _Ret_valid_impl_)
+#define _Ret_opt_bytecount_(size) _SAL1_1_Source_(_Ret_opt_bytecount_, (size), _Ret1_impl_(__maybenull_impl_notref) _Ret1_impl_(__bytecount_impl(size)) _Ret_valid_impl_)
+
+// Valid Buffer extent is described by a constant expression
+#define _Ret_count_c_(size) _SAL1_1_Source_(_Ret_count_c_, (size), _Ret1_impl_(__notnull_impl_notref) _Ret1_impl_(__count_c_impl(size)) _Ret_valid_impl_)
+#define _Ret_opt_count_c_(size) _SAL1_1_Source_(_Ret_opt_count_c_, (size), _Ret1_impl_(__maybenull_impl_notref) _Ret1_impl_(__count_c_impl(size)) _Ret_valid_impl_)
+#define _Ret_bytecount_c_(size) _SAL1_1_Source_(_Ret_bytecount_c_, (size), _Ret1_impl_(__notnull_impl_notref) _Ret1_impl_(__bytecount_c_impl(size)) _Ret_valid_impl_)
+#define _Ret_opt_bytecount_c_(size) _SAL1_1_Source_(_Ret_opt_bytecount_c_, (size), _Ret1_impl_(__maybenull_impl_notref) _Ret1_impl_(__bytecount_c_impl(size)) _Ret_valid_impl_)
+
+// Valid Buffer extent is described by a complex expression
+#define _Ret_count_x_(size) _SAL1_1_Source_(_Ret_count_x_, (size), _Ret1_impl_(__notnull_impl_notref) _Ret1_impl_(__count_x_impl(size)) _Ret_valid_impl_)
+#define _Ret_opt_count_x_(size) _SAL1_1_Source_(_Ret_opt_count_x_, (size), _Ret1_impl_(__maybenull_impl_notref) _Ret1_impl_(__count_x_impl(size)) _Ret_valid_impl_)
+#define _Ret_bytecount_x_(size) _SAL1_1_Source_(_Ret_bytecount_x_, (size), _Ret1_impl_(__notnull_impl_notref) _Ret1_impl_(__bytecount_x_impl(size)) _Ret_valid_impl_)
+#define _Ret_opt_bytecount_x_(size) _SAL1_1_Source_(_Ret_opt_bytecount_x_, (size), _Ret1_impl_(__maybenull_impl_notref) _Ret1_impl_(__bytecount_x_impl(size)) _Ret_valid_impl_)
+
+// return value is nullterminated and length is given by another parameter
+#define _Ret_z_count_(size) _SAL1_1_Source_(_Ret_z_count_, (size), _Ret1_impl_(__notnull_impl_notref) _Ret2_impl_(__zterm_impl,__count_impl(size)) _Ret_valid_impl_)
+#define _Ret_opt_z_count_(size) _SAL1_1_Source_(_Ret_opt_z_count_, (size), _Ret1_impl_(__maybenull_impl_notref) _Ret2_impl_(__zterm_impl,__count_impl(size)) _Ret_valid_impl_)
+#define _Ret_z_bytecount_(size) _SAL1_1_Source_(_Ret_z_bytecount_, (size), _Ret1_impl_(__notnull_impl_notref) _Ret2_impl_(__zterm_impl,__bytecount_impl(size)) _Ret_valid_impl_)
+#define _Ret_opt_z_bytecount_(size) _SAL1_1_Source_(_Ret_opt_z_bytecount_, (size), _Ret1_impl_(__maybenull_impl_notref) _Ret2_impl_(__zterm_impl,__bytecount_impl(size)) _Ret_valid_impl_)
+
+
+// _Pre_ annotations ---
+#define _Pre_opt_z_ _SAL1_1_Source_(_Pre_opt_z_, (), _Pre1_impl_(__maybenull_impl_notref) _Pre1_impl_(__zterm_impl) _Pre_valid_impl_)
+
+// restrict access rights
+#define _Pre_readonly_ _SAL1_1_Source_(_Pre_readonly_, (), _Pre1_impl_(__readaccess_impl_notref))
+#define _Pre_writeonly_ _SAL1_1_Source_(_Pre_writeonly_, (), _Pre1_impl_(__writeaccess_impl_notref))
+
+// e.g. void FreeMemory( _Pre_bytecap_(cb) _Post_ptr_invalid_ void* pv, size_t cb );
+// buffer capacity described by another parameter
+#define _Pre_cap_(size) _SAL1_1_Source_(_Pre_cap_, (size), _Pre1_impl_(__notnull_impl_notref) _Pre1_impl_(__cap_impl(size)))
+#define _Pre_opt_cap_(size) _SAL1_1_Source_(_Pre_opt_cap_, (size), _Pre1_impl_(__maybenull_impl_notref) _Pre1_impl_(__cap_impl(size)))
+#define _Pre_bytecap_(size) _SAL1_1_Source_(_Pre_bytecap_, (size), _Pre1_impl_(__notnull_impl_notref) _Pre1_impl_(__bytecap_impl(size)))
+#define _Pre_opt_bytecap_(size) _SAL1_1_Source_(_Pre_opt_bytecap_, (size), _Pre1_impl_(__maybenull_impl_notref) _Pre1_impl_(__bytecap_impl(size)))
+
+// buffer capacity described by a constant expression
+#define _Pre_cap_c_(size) _SAL1_1_Source_(_Pre_cap_c_, (size), _Pre1_impl_(__notnull_impl_notref) _Pre1_impl_(__cap_c_impl(size)))
+#define _Pre_opt_cap_c_(size) _SAL1_1_Source_(_Pre_opt_cap_c_, (size), _Pre1_impl_(__maybenull_impl_notref) _Pre1_impl_(__cap_c_impl(size)))
+#define _Pre_bytecap_c_(size) _SAL1_1_Source_(_Pre_bytecap_c_, (size), _Pre1_impl_(__notnull_impl_notref) _Pre1_impl_(__bytecap_c_impl(size)))
+#define _Pre_opt_bytecap_c_(size) _SAL1_1_Source_(_Pre_opt_bytecap_c_, (size), _Pre1_impl_(__maybenull_impl_notref) _Pre1_impl_(__bytecap_c_impl(size)))
+#define _Pre_cap_c_one_ _SAL1_1_Source_(_Pre_cap_c_one_, (), _Pre1_impl_(__notnull_impl_notref) _Pre1_impl_(__cap_c_one_notref_impl))
+#define _Pre_opt_cap_c_one_ _SAL1_1_Source_(_Pre_opt_cap_c_one_, (), _Pre1_impl_(__maybenull_impl_notref) _Pre1_impl_(__cap_c_one_notref_impl))
+
+// buffer capacity is described by another parameter multiplied by a constant expression
+#define _Pre_cap_m_(mult,size) _SAL1_1_Source_(_Pre_cap_m_, (mult,size), _Pre1_impl_(__notnull_impl_notref) _Pre1_impl_(__mult_impl(mult,size)))
+#define _Pre_opt_cap_m_(mult,size) _SAL1_1_Source_(_Pre_opt_cap_m_, (mult,size), _Pre1_impl_(__maybenull_impl_notref) _Pre1_impl_(__mult_impl(mult,size)))
+
+// buffer capacity described by size of other buffer, only used by dangerous legacy APIs
+// e.g. int strcpy(_Pre_cap_for_(src) char* dst, const char* src);
+#define _Pre_cap_for_(param) _SAL1_1_Source_(_Pre_cap_for_, (param), _Pre1_impl_(__notnull_impl_notref) _Pre1_impl_(__cap_for_impl(param)))
+#define _Pre_opt_cap_for_(param) _SAL1_1_Source_(_Pre_opt_cap_for_, (param), _Pre1_impl_(__maybenull_impl_notref) _Pre1_impl_(__cap_for_impl(param)))
+
+// buffer capacity described by a complex condition
+#define _Pre_cap_x_(size) _SAL1_1_Source_(_Pre_cap_x_, (size), _Pre1_impl_(__notnull_impl_notref) _Pre1_impl_(__cap_x_impl(size)))
+#define _Pre_opt_cap_x_(size) _SAL1_1_Source_(_Pre_opt_cap_x_, (size), _Pre1_impl_(__maybenull_impl_notref) _Pre1_impl_(__cap_x_impl(size)))
+#define _Pre_bytecap_x_(size) _SAL1_1_Source_(_Pre_bytecap_x_, (size), _Pre1_impl_(__notnull_impl_notref) _Pre1_impl_(__bytecap_x_impl(size)))
+#define _Pre_opt_bytecap_x_(size) _SAL1_1_Source_(_Pre_opt_bytecap_x_, (size), _Pre1_impl_(__maybenull_impl_notref) _Pre1_impl_(__bytecap_x_impl(size)))
+
+// buffer capacity described by the difference to another pointer parameter
+#define _Pre_ptrdiff_cap_(ptr) _SAL1_1_Source_(_Pre_ptrdiff_cap_, (ptr), _Pre1_impl_(__notnull_impl_notref) _Pre1_impl_(__cap_x_impl(__ptrdiff(ptr))))
+#define _Pre_opt_ptrdiff_cap_(ptr) _SAL1_1_Source_(_Pre_opt_ptrdiff_cap_, (ptr), _Pre1_impl_(__maybenull_impl_notref) _Pre1_impl_(__cap_x_impl(__ptrdiff(ptr))))
+
+// e.g. void AppendStr( _Pre_z_ const char* szFrom, _Pre_z_cap_(cchTo) _Post_z_ char* szTo, size_t cchTo );
+#define _Pre_z_cap_(size) _SAL1_1_Source_(_Pre_z_cap_, (size), _Pre1_impl_(__notnull_impl_notref) _Pre2_impl_(__zterm_impl,__cap_impl(size)) _Pre_valid_impl_)
+#define _Pre_opt_z_cap_(size) _SAL1_1_Source_(_Pre_opt_z_cap_, (size), _Pre1_impl_(__maybenull_impl_notref) _Pre2_impl_(__zterm_impl,__cap_impl(size)) _Pre_valid_impl_)
+#define _Pre_z_bytecap_(size) _SAL1_1_Source_(_Pre_z_bytecap_, (size), _Pre1_impl_(__notnull_impl_notref) _Pre2_impl_(__zterm_impl,__bytecap_impl(size)) _Pre_valid_impl_)
+#define _Pre_opt_z_bytecap_(size) _SAL1_1_Source_(_Pre_opt_z_bytecap_, (size), _Pre1_impl_(__maybenull_impl_notref) _Pre2_impl_(__zterm_impl,__bytecap_impl(size)) _Pre_valid_impl_)
+
+#define _Pre_z_cap_c_(size) _SAL1_1_Source_(_Pre_z_cap_c_, (size), _Pre1_impl_(__notnull_impl_notref) _Pre2_impl_(__zterm_impl,__cap_c_impl(size)) _Pre_valid_impl_)
+#define _Pre_opt_z_cap_c_(size) _SAL1_1_Source_(_Pre_opt_z_cap_c_, (size), _Pre1_impl_(__maybenull_impl_notref) _Pre2_impl_(__zterm_impl,__cap_c_impl(size)) _Pre_valid_impl_)
+#define _Pre_z_bytecap_c_(size) _SAL1_1_Source_(_Pre_z_bytecap_c_, (size), _Pre1_impl_(__notnull_impl_notref) _Pre2_impl_(__zterm_impl,__bytecap_c_impl(size)) _Pre_valid_impl_)
+#define _Pre_opt_z_bytecap_c_(size) _SAL1_1_Source_(_Pre_opt_z_bytecap_c_, (size), _Pre1_impl_(__maybenull_impl_notref) _Pre2_impl_(__zterm_impl,__bytecap_c_impl(size)) _Pre_valid_impl_)
+
+#define _Pre_z_cap_x_(size) _SAL1_1_Source_(_Pre_z_cap_x_, (size), _Pre1_impl_(__notnull_impl_notref) _Pre2_impl_(__zterm_impl,__cap_x_impl(size)) _Pre_valid_impl_)
+#define _Pre_opt_z_cap_x_(size) _SAL1_1_Source_(_Pre_opt_z_cap_x_, (size), _Pre1_impl_(__maybenull_impl_notref) _Pre2_impl_(__zterm_impl,__cap_x_impl(size)) _Pre_valid_impl_)
+#define _Pre_z_bytecap_x_(size) _SAL1_1_Source_(_Pre_z_bytecap_x_, (size), _Pre1_impl_(__notnull_impl_notref) _Pre2_impl_(__zterm_impl,__bytecap_x_impl(size)) _Pre_valid_impl_)
+#define _Pre_opt_z_bytecap_x_(size) _SAL1_1_Source_(_Pre_opt_z_bytecap_x_, (size), _Pre1_impl_(__maybenull_impl_notref) _Pre2_impl_(__zterm_impl,__bytecap_x_impl(size)) _Pre_valid_impl_)
+
+// known capacity and valid but unknown readable extent
+#define _Pre_valid_cap_(size) _SAL1_1_Source_(_Pre_valid_cap_, (size), _Pre1_impl_(__notnull_impl_notref) _Pre1_impl_(__cap_impl(size)) _Pre_valid_impl_)
+#define _Pre_opt_valid_cap_(size) _SAL1_1_Source_(_Pre_opt_valid_cap_, (size), _Pre1_impl_(__maybenull_impl_notref) _Pre1_impl_(__cap_impl(size)) _Pre_valid_impl_)
+#define _Pre_valid_bytecap_(size) _SAL1_1_Source_(_Pre_valid_bytecap_, (size), _Pre1_impl_(__notnull_impl_notref) _Pre1_impl_(__bytecap_impl(size)) _Pre_valid_impl_)
+#define _Pre_opt_valid_bytecap_(size) _SAL1_1_Source_(_Pre_opt_valid_bytecap_, (size), _Pre1_impl_(__maybenull_impl_notref) _Pre1_impl_(__bytecap_impl(size)) _Pre_valid_impl_)
+
+#define _Pre_valid_cap_c_(size) _SAL1_1_Source_(_Pre_valid_cap_c_, (size), _Pre1_impl_(__notnull_impl_notref) _Pre1_impl_(__cap_c_impl(size)) _Pre_valid_impl_)
+#define _Pre_opt_valid_cap_c_(size) _SAL1_1_Source_(_Pre_opt_valid_cap_c_, (size), _Pre1_impl_(__maybenull_impl_notref) _Pre1_impl_(__cap_c_impl(size)) _Pre_valid_impl_)
+#define _Pre_valid_bytecap_c_(size) _SAL1_1_Source_(_Pre_valid_bytecap_c_, (size), _Pre1_impl_(__notnull_impl_notref) _Pre1_impl_(__bytecap_c_impl(size)) _Pre_valid_impl_)
+#define _Pre_opt_valid_bytecap_c_(size) _SAL1_1_Source_(_Pre_opt_valid_bytecap_c_, (size), _Pre1_impl_(__maybenull_impl_notref) _Pre1_impl_(__bytecap_c_impl(size)) _Pre_valid_impl_)
+
+#define _Pre_valid_cap_x_(size) _SAL1_1_Source_(_Pre_valid_cap_x_, (size), _Pre1_impl_(__notnull_impl_notref) _Pre1_impl_(__cap_x_impl(size)) _Pre_valid_impl_)
+#define _Pre_opt_valid_cap_x_(size) _SAL1_1_Source_(_Pre_opt_valid_cap_x_, (size), _Pre1_impl_(__maybenull_impl_notref) _Pre1_impl_(__cap_x_impl(size)) _Pre_valid_impl_)
+#define _Pre_valid_bytecap_x_(size) _SAL1_1_Source_(_Pre_valid_bytecap_x_, (size), _Pre1_impl_(__notnull_impl_notref) _Pre1_impl_(__bytecap_x_impl(size)) _Pre_valid_impl_)
+#define _Pre_opt_valid_bytecap_x_(size) _SAL1_1_Source_(_Pre_opt_valid_bytecap_x_, (size), _Pre1_impl_(__maybenull_impl_notref) _Pre1_impl_(__bytecap_x_impl(size)) _Pre_valid_impl_)
+
+// e.g. void AppendCharRange( _Pre_count_(cchFrom) const char* rgFrom, size_t cchFrom, _Out_z_cap_(cchTo) char* szTo, size_t cchTo );
+// Valid buffer extent described by another parameter
+#define _Pre_count_(size) _SAL1_1_Source_(_Pre_count_, (size), _Pre1_impl_(__notnull_impl_notref) _Pre1_impl_(__count_impl(size)) _Pre_valid_impl_)
+#define _Pre_opt_count_(size) _SAL1_1_Source_(_Pre_opt_count_, (size), _Pre1_impl_(__maybenull_impl_notref) _Pre1_impl_(__count_impl(size)) _Pre_valid_impl_)
+#define _Pre_bytecount_(size) _SAL1_1_Source_(_Pre_bytecount_, (size), _Pre1_impl_(__notnull_impl_notref) _Pre1_impl_(__bytecount_impl(size)) _Pre_valid_impl_)
+#define _Pre_opt_bytecount_(size) _SAL1_1_Source_(_Pre_opt_bytecount_, (size), _Pre1_impl_(__maybenull_impl_notref) _Pre1_impl_(__bytecount_impl(size)) _Pre_valid_impl_)
+
+// Valid buffer extent described by a constant expression
+#define _Pre_count_c_(size) _SAL1_1_Source_(_Pre_count_c_, (size), _Pre1_impl_(__notnull_impl_notref) _Pre1_impl_(__count_c_impl(size)) _Pre_valid_impl_)
+#define _Pre_opt_count_c_(size) _SAL1_1_Source_(_Pre_opt_count_c_, (size), _Pre1_impl_(__maybenull_impl_notref) _Pre1_impl_(__count_c_impl(size)) _Pre_valid_impl_)
+#define _Pre_bytecount_c_(size) _SAL1_1_Source_(_Pre_bytecount_c_, (size), _Pre1_impl_(__notnull_impl_notref) _Pre1_impl_(__bytecount_c_impl(size)) _Pre_valid_impl_)
+#define _Pre_opt_bytecount_c_(size) _SAL1_1_Source_(_Pre_opt_bytecount_c_, (size), _Pre1_impl_(__maybenull_impl_notref) _Pre1_impl_(__bytecount_c_impl(size)) _Pre_valid_impl_)
+
+// Valid buffer extent described by a complex expression
+#define _Pre_count_x_(size) _SAL1_1_Source_(_Pre_count_x_, (size), _Pre1_impl_(__notnull_impl_notref) _Pre1_impl_(__count_x_impl(size)) _Pre_valid_impl_)
+#define _Pre_opt_count_x_(size) _SAL1_1_Source_(_Pre_opt_count_x_, (size), _Pre1_impl_(__maybenull_impl_notref) _Pre1_impl_(__count_x_impl(size)) _Pre_valid_impl_)
+#define _Pre_bytecount_x_(size) _SAL1_1_Source_(_Pre_bytecount_x_, (size), _Pre1_impl_(__notnull_impl_notref) _Pre1_impl_(__bytecount_x_impl(size)) _Pre_valid_impl_)
+#define _Pre_opt_bytecount_x_(size) _SAL1_1_Source_(_Pre_opt_bytecount_x_, (size), _Pre1_impl_(__maybenull_impl_notref) _Pre1_impl_(__bytecount_x_impl(size)) _Pre_valid_impl_)
+
+// Valid buffer extent described by the difference to another pointer parameter
+#define _Pre_ptrdiff_count_(ptr) _SAL1_1_Source_(_Pre_ptrdiff_count_, (ptr), _Pre1_impl_(__notnull_impl_notref) _Pre1_impl_(__count_x_impl(__ptrdiff(ptr))) _Pre_valid_impl_)
+#define _Pre_opt_ptrdiff_count_(ptr) _SAL1_1_Source_(_Pre_opt_ptrdiff_count_, (ptr), _Pre1_impl_(__maybenull_impl_notref) _Pre1_impl_(__count_x_impl(__ptrdiff(ptr))) _Pre_valid_impl_)
+
+
+// char * strncpy(_Out_cap_(_Count) _Post_maybez_ char * _Dest, _In_z_ const char * _Source, _In_ size_t _Count)
+// buffer maybe zero-terminated after the call
+#define _Post_maybez_ _SAL1_1_Source_(_Post_maybez_, (), _Post1_impl_(__maybezterm_impl))
+
+// e.g. SIZE_T HeapSize( _In_ HANDLE hHeap, DWORD dwFlags, _Pre_notnull_ _Post_bytecap_(return) LPCVOID lpMem );
+#define _Post_cap_(size) _SAL1_1_Source_(_Post_cap_, (size), _Post1_impl_(__cap_impl(size)))
+#define _Post_bytecap_(size) _SAL1_1_Source_(_Post_bytecap_, (size), _Post1_impl_(__bytecap_impl(size)))
+
+// e.g. int strlen( _In_z_ _Post_count_(return+1) const char* sz );
+#define _Post_count_(size) _SAL1_1_Source_(_Post_count_, (size), _Post1_impl_(__count_impl(size)) _Post_valid_impl_)
+#define _Post_bytecount_(size) _SAL1_1_Source_(_Post_bytecount_, (size), _Post1_impl_(__bytecount_impl(size)) _Post_valid_impl_)
+#define _Post_count_c_(size) _SAL1_1_Source_(_Post_count_c_, (size), _Post1_impl_(__count_c_impl(size)) _Post_valid_impl_)
+#define _Post_bytecount_c_(size) _SAL1_1_Source_(_Post_bytecount_c_, (size), _Post1_impl_(__bytecount_c_impl(size)) _Post_valid_impl_)
+#define _Post_count_x_(size) _SAL1_1_Source_(_Post_count_x_, (size), _Post1_impl_(__count_x_impl(size)) _Post_valid_impl_)
+#define _Post_bytecount_x_(size) _SAL1_1_Source_(_Post_bytecount_x_, (size), _Post1_impl_(__bytecount_x_impl(size)) _Post_valid_impl_)
+
+// e.g. size_t CopyStr( _In_z_ const char* szFrom, _Pre_cap_(cch) _Post_z_count_(return+1) char* szFrom, size_t cchFrom );
+#define _Post_z_count_(size) _SAL1_1_Source_(_Post_z_count_, (size), _Post2_impl_(__zterm_impl,__count_impl(size)) _Post_valid_impl_)
+#define _Post_z_bytecount_(size) _SAL1_1_Source_(_Post_z_bytecount_, (size), _Post2_impl_(__zterm_impl,__bytecount_impl(size)) _Post_valid_impl_)
+#define _Post_z_count_c_(size) _SAL1_1_Source_(_Post_z_count_c_, (size), _Post2_impl_(__zterm_impl,__count_c_impl(size)) _Post_valid_impl_)
+#define _Post_z_bytecount_c_(size) _SAL1_1_Source_(_Post_z_bytecount_c_, (size), _Post2_impl_(__zterm_impl,__bytecount_c_impl(size)) _Post_valid_impl_)
+#define _Post_z_count_x_(size) _SAL1_1_Source_(_Post_z_count_x_, (size), _Post2_impl_(__zterm_impl,__count_x_impl(size)) _Post_valid_impl_)
+#define _Post_z_bytecount_x_(size) _SAL1_1_Source_(_Post_z_bytecount_x_, (size), _Post2_impl_(__zterm_impl,__bytecount_x_impl(size)) _Post_valid_impl_)
+
+//
+// _Prepost_ ---
+//
+// describing conditions that hold before and after the function call
+
+#define _Prepost_opt_z_ _SAL1_1_Source_(_Prepost_opt_z_, (), _Pre_opt_z_ _Post_z_)
+
+#define _Prepost_count_(size) _SAL1_1_Source_(_Prepost_count_, (size), _Pre_count_(size) _Post_count_(size))
+#define _Prepost_opt_count_(size) _SAL1_1_Source_(_Prepost_opt_count_, (size), _Pre_opt_count_(size) _Post_count_(size))
+#define _Prepost_bytecount_(size) _SAL1_1_Source_(_Prepost_bytecount_, (size), _Pre_bytecount_(size) _Post_bytecount_(size))
+#define _Prepost_opt_bytecount_(size) _SAL1_1_Source_(_Prepost_opt_bytecount_, (size), _Pre_opt_bytecount_(size) _Post_bytecount_(size))
+#define _Prepost_count_c_(size) _SAL1_1_Source_(_Prepost_count_c_, (size), _Pre_count_c_(size) _Post_count_c_(size))
+#define _Prepost_opt_count_c_(size) _SAL1_1_Source_(_Prepost_opt_count_c_, (size), _Pre_opt_count_c_(size) _Post_count_c_(size))
+#define _Prepost_bytecount_c_(size) _SAL1_1_Source_(_Prepost_bytecount_c_, (size), _Pre_bytecount_c_(size) _Post_bytecount_c_(size))
+#define _Prepost_opt_bytecount_c_(size) _SAL1_1_Source_(_Prepost_opt_bytecount_c_, (size), _Pre_opt_bytecount_c_(size) _Post_bytecount_c_(size))
+#define _Prepost_count_x_(size) _SAL1_1_Source_(_Prepost_count_x_, (size), _Pre_count_x_(size) _Post_count_x_(size))
+#define _Prepost_opt_count_x_(size) _SAL1_1_Source_(_Prepost_opt_count_x_, (size), _Pre_opt_count_x_(size) _Post_count_x_(size))
+#define _Prepost_bytecount_x_(size) _SAL1_1_Source_(_Prepost_bytecount_x_, (size), _Pre_bytecount_x_(size) _Post_bytecount_x_(size))
+#define _Prepost_opt_bytecount_x_(size) _SAL1_1_Source_(_Prepost_opt_bytecount_x_, (size), _Pre_opt_bytecount_x_(size) _Post_bytecount_x_(size))
+
+#define _Prepost_valid_ _SAL1_1_Source_(_Prepost_valid_, (), _Pre_valid_ _Post_valid_)
+#define _Prepost_opt_valid_ _SAL1_1_Source_(_Prepost_opt_valid_, (), _Pre_opt_valid_ _Post_valid_)
+
+//
+// _Deref_<both> ---
+//
+// short version for _Deref_pre_<ann> _Deref_post_<ann>
+// describing conditions for array elements or dereferenced pointer parameters that hold before and after the call
+
+#define _Deref_prepost_z_ _SAL1_1_Source_(_Deref_prepost_z_, (), _Deref_pre_z_ _Deref_post_z_)
+#define _Deref_prepost_opt_z_ _SAL1_1_Source_(_Deref_prepost_opt_z_, (), _Deref_pre_opt_z_ _Deref_post_opt_z_)
+
+#define _Deref_prepost_cap_(size) _SAL1_1_Source_(_Deref_prepost_cap_, (size), _Deref_pre_cap_(size) _Deref_post_cap_(size))
+#define _Deref_prepost_opt_cap_(size) _SAL1_1_Source_(_Deref_prepost_opt_cap_, (size), _Deref_pre_opt_cap_(size) _Deref_post_opt_cap_(size))
+#define _Deref_prepost_bytecap_(size) _SAL1_1_Source_(_Deref_prepost_bytecap_, (size), _Deref_pre_bytecap_(size) _Deref_post_bytecap_(size))
+#define _Deref_prepost_opt_bytecap_(size) _SAL1_1_Source_(_Deref_prepost_opt_bytecap_, (size), _Deref_pre_opt_bytecap_(size) _Deref_post_opt_bytecap_(size))
+
+#define _Deref_prepost_cap_x_(size) _SAL1_1_Source_(_Deref_prepost_cap_x_, (size), _Deref_pre_cap_x_(size) _Deref_post_cap_x_(size))
+#define _Deref_prepost_opt_cap_x_(size) _SAL1_1_Source_(_Deref_prepost_opt_cap_x_, (size), _Deref_pre_opt_cap_x_(size) _Deref_post_opt_cap_x_(size))
+#define _Deref_prepost_bytecap_x_(size) _SAL1_1_Source_(_Deref_prepost_bytecap_x_, (size), _Deref_pre_bytecap_x_(size) _Deref_post_bytecap_x_(size))
+#define _Deref_prepost_opt_bytecap_x_(size) _SAL1_1_Source_(_Deref_prepost_opt_bytecap_x_, (size), _Deref_pre_opt_bytecap_x_(size) _Deref_post_opt_bytecap_x_(size))
+
+#define _Deref_prepost_z_cap_(size) _SAL1_1_Source_(_Deref_prepost_z_cap_, (size), _Deref_pre_z_cap_(size) _Deref_post_z_cap_(size))
+#define _Deref_prepost_opt_z_cap_(size) _SAL1_1_Source_(_Deref_prepost_opt_z_cap_, (size), _Deref_pre_opt_z_cap_(size) _Deref_post_opt_z_cap_(size))
+#define _Deref_prepost_z_bytecap_(size) _SAL1_1_Source_(_Deref_prepost_z_bytecap_, (size), _Deref_pre_z_bytecap_(size) _Deref_post_z_bytecap_(size))
+#define _Deref_prepost_opt_z_bytecap_(size) _SAL1_1_Source_(_Deref_prepost_opt_z_bytecap_, (size), _Deref_pre_opt_z_bytecap_(size) _Deref_post_opt_z_bytecap_(size))
+
+#define _Deref_prepost_valid_cap_(size) _SAL1_1_Source_(_Deref_prepost_valid_cap_, (size), _Deref_pre_valid_cap_(size) _Deref_post_valid_cap_(size))
+#define _Deref_prepost_opt_valid_cap_(size) _SAL1_1_Source_(_Deref_prepost_opt_valid_cap_, (size), _Deref_pre_opt_valid_cap_(size) _Deref_post_opt_valid_cap_(size))
+#define _Deref_prepost_valid_bytecap_(size) _SAL1_1_Source_(_Deref_prepost_valid_bytecap_, (size), _Deref_pre_valid_bytecap_(size) _Deref_post_valid_bytecap_(size))
+#define _Deref_prepost_opt_valid_bytecap_(size) _SAL1_1_Source_(_Deref_prepost_opt_valid_bytecap_, (size), _Deref_pre_opt_valid_bytecap_(size) _Deref_post_opt_valid_bytecap_(size))
+
+#define _Deref_prepost_valid_cap_x_(size) _SAL1_1_Source_(_Deref_prepost_valid_cap_x_, (size), _Deref_pre_valid_cap_x_(size) _Deref_post_valid_cap_x_(size))
+#define _Deref_prepost_opt_valid_cap_x_(size) _SAL1_1_Source_(_Deref_prepost_opt_valid_cap_x_, (size), _Deref_pre_opt_valid_cap_x_(size) _Deref_post_opt_valid_cap_x_(size))
+#define _Deref_prepost_valid_bytecap_x_(size) _SAL1_1_Source_(_Deref_prepost_valid_bytecap_x_, (size), _Deref_pre_valid_bytecap_x_(size) _Deref_post_valid_bytecap_x_(size))
+#define _Deref_prepost_opt_valid_bytecap_x_(size) _SAL1_1_Source_(_Deref_prepost_opt_valid_bytecap_x_, (size), _Deref_pre_opt_valid_bytecap_x_(size) _Deref_post_opt_valid_bytecap_x_(size))
+
+#define _Deref_prepost_count_(size) _SAL1_1_Source_(_Deref_prepost_count_, (size), _Deref_pre_count_(size) _Deref_post_count_(size))
+#define _Deref_prepost_opt_count_(size) _SAL1_1_Source_(_Deref_prepost_opt_count_, (size), _Deref_pre_opt_count_(size) _Deref_post_opt_count_(size))
+#define _Deref_prepost_bytecount_(size) _SAL1_1_Source_(_Deref_prepost_bytecount_, (size), _Deref_pre_bytecount_(size) _Deref_post_bytecount_(size))
+#define _Deref_prepost_opt_bytecount_(size) _SAL1_1_Source_(_Deref_prepost_opt_bytecount_, (size), _Deref_pre_opt_bytecount_(size) _Deref_post_opt_bytecount_(size))
+
+#define _Deref_prepost_count_x_(size) _SAL1_1_Source_(_Deref_prepost_count_x_, (size), _Deref_pre_count_x_(size) _Deref_post_count_x_(size))
+#define _Deref_prepost_opt_count_x_(size) _SAL1_1_Source_(_Deref_prepost_opt_count_x_, (size), _Deref_pre_opt_count_x_(size) _Deref_post_opt_count_x_(size))
+#define _Deref_prepost_bytecount_x_(size) _SAL1_1_Source_(_Deref_prepost_bytecount_x_, (size), _Deref_pre_bytecount_x_(size) _Deref_post_bytecount_x_(size))
+#define _Deref_prepost_opt_bytecount_x_(size) _SAL1_1_Source_(_Deref_prepost_opt_bytecount_x_, (size), _Deref_pre_opt_bytecount_x_(size) _Deref_post_opt_bytecount_x_(size))
+
+#define _Deref_prepost_valid_ _SAL1_1_Source_(_Deref_prepost_valid_, (), _Deref_pre_valid_ _Deref_post_valid_)
+#define _Deref_prepost_opt_valid_ _SAL1_1_Source_(_Deref_prepost_opt_valid_, (), _Deref_pre_opt_valid_ _Deref_post_opt_valid_)
+
+//
+// _Deref_<miscellaneous>
+//
+// used with references to arrays
+
+#define _Deref_out_z_cap_c_(size) _SAL1_1_Source_(_Deref_out_z_cap_c_, (size), _Deref_pre_cap_c_(size) _Deref_post_z_)
+#define _Deref_inout_z_cap_c_(size) _SAL1_1_Source_(_Deref_inout_z_cap_c_, (size), _Deref_pre_z_cap_c_(size) _Deref_post_z_)
+#define _Deref_out_z_bytecap_c_(size) _SAL1_1_Source_(_Deref_out_z_bytecap_c_, (size), _Deref_pre_bytecap_c_(size) _Deref_post_z_)
+#define _Deref_inout_z_bytecap_c_(size) _SAL1_1_Source_(_Deref_inout_z_bytecap_c_, (size), _Deref_pre_z_bytecap_c_(size) _Deref_post_z_)
+#define _Deref_inout_z_ _SAL1_1_Source_(_Deref_inout_z_, (), _Deref_prepost_z_)
+
+// #pragma endregion Input Buffer SAL 1 compatibility macros
+
+
+//============================================================================
+// Implementation Layer:
+//============================================================================
+
+
+// Naming conventions:
+// A symbol the begins with _SA_ is for the machinery of creating any
+// annotations; many of those come from sourceannotations.h in the case
+// of attributes.
+
+// A symbol that ends with _impl is the very lowest level macro. It is
+// not required to be a legal standalone annotation, and in the case
+// of attribute annotations, usually is not. (In the case of some declspec
+// annotations, it might be, but it should not be assumed so.) Those
+// symols will be used in the _PreN..., _PostN... and _RetN... annotations
+// to build up more complete annotations.
+
+// A symbol ending in _impl_ is reserved to the implementation as well,
+// but it does form a complete annotation; usually they are used to build
+// up even higher level annotations.
+
+
+#if _USE_ATTRIBUTES_FOR_SAL || _USE_DECLSPECS_FOR_SAL // [
+// Sharable "_impl" macros: these can be shared between the various annotation
+// forms but are part of the implementation of the macros. These are collected
+// here to assure that only necessary differences in the annotations
+// exist.
+
+#define _Always_impl_(annos) _Group_(annos _SAL_nop_impl_) _On_failure_impl_(annos _SAL_nop_impl_)
+#define _Bound_impl_ _SA_annotes0(SAL_bound)
+#define _Field_range_impl_(min,max) _Range_impl_(min,max)
+#define _Literal_impl_ _SA_annotes1(SAL_constant, __yes)
+#define _Maybenull_impl_ _SA_annotes1(SAL_null, __maybe)
+#define _Maybevalid_impl_ _SA_annotes1(SAL_valid, __maybe)
+#define _Must_inspect_impl_ _Post_impl_ _SA_annotes0(SAL_mustInspect)
+#define _Notliteral_impl_ _SA_annotes1(SAL_constant, __no)
+#define _Notnull_impl_ _SA_annotes1(SAL_null, __no)
+#define _Notvalid_impl_ _SA_annotes1(SAL_valid, __no)
+#define _NullNull_terminated_impl_ _Group_(_SA_annotes1(SAL_nullTerminated, __yes) _SA_annotes1(SAL_readableTo,inexpressibleCount("NullNull terminated string")))
+#define _Null_impl_ _SA_annotes1(SAL_null, __yes)
+#define _Null_terminated_impl_ _SA_annotes1(SAL_nullTerminated, __yes)
+#define _Out_impl_ _Pre1_impl_(__notnull_impl_notref) _Pre1_impl_(__cap_c_one_notref_impl) _Post_valid_impl_
+#define _Out_opt_impl_ _Pre1_impl_(__maybenull_impl_notref) _Pre1_impl_(__cap_c_one_notref_impl) _Post_valid_impl_
+#define _Points_to_data_impl_ _At_(*_Curr_, _SA_annotes1(SAL_mayBePointer, __no))
+#define _Post_satisfies_impl_(cond) _Post_impl_ _Satisfies_impl_(cond)
+#define _Post_valid_impl_ _Post1_impl_(__valid_impl)
+#define _Pre_satisfies_impl_(cond) _Pre_impl_ _Satisfies_impl_(cond)
+#define _Pre_valid_impl_ _Pre1_impl_(__valid_impl)
+#define _Range_impl_(min,max) _SA_annotes2(SAL_range, min, max)
+#define _Readable_bytes_impl_(size) _SA_annotes1(SAL_readableTo, byteCount(size))
+#define _Readable_elements_impl_(size) _SA_annotes1(SAL_readableTo, elementCount(size))
+#define _Ret_valid_impl_ _Ret1_impl_(__valid_impl)
+#define _Satisfies_impl_(cond) _SA_annotes1(SAL_satisfies, cond)
+#define _Valid_impl_ _SA_annotes1(SAL_valid, __yes)
+#define _Writable_bytes_impl_(size) _SA_annotes1(SAL_writableTo, byteCount(size))
+#define _Writable_elements_impl_(size) _SA_annotes1(SAL_writableTo, elementCount(size))
+
+#define _In_range_impl_(min,max) _Pre_impl_ _Range_impl_(min,max)
+#define _Out_range_impl_(min,max) _Post_impl_ _Range_impl_(min,max)
+#define _Ret_range_impl_(min,max) _Post_impl_ _Range_impl_(min,max)
+#define _Deref_in_range_impl_(min,max) _Deref_pre_impl_ _Range_impl_(min,max)
+#define _Deref_out_range_impl_(min,max) _Deref_post_impl_ _Range_impl_(min,max)
+#define _Deref_ret_range_impl_(min,max) _Deref_post_impl_ _Range_impl_(min,max)
+
+#define _Deref_pre_impl_ _Pre_impl_ _Notref_impl_ _Deref_impl_
+#define _Deref_post_impl_ _Post_impl_ _Notref_impl_ _Deref_impl_
+
+// The following are for the implementation machinery, and are not
+// suitable for annotating general code.
+// We're tying to phase this out, someday. The parser quotes the param.
+#define __AuToQuOtE _SA_annotes0(SAL_AuToQuOtE)
+
+// Normally the parser does some simple type checking of annotation params,
+// defer that check to the plugin.
+#define __deferTypecheck _SA_annotes0(SAL_deferTypecheck)
+
+#define _SA_SPECSTRIZE( x ) #x
+#define _SAL_nop_impl_ /* nothing */
+#define __nop_impl(x) x
+#endif
+
+
+#if _USE_ATTRIBUTES_FOR_SAL // [
+
+// Using attributes for sal
+
+#include "codeanalysis\sourceannotations.h"
+
+
+#define _SA_annotes0(n) [SAL_annotes(Name=#n)]
+#define _SA_annotes1(n,pp1) [SAL_annotes(Name=#n, p1=_SA_SPECSTRIZE(pp1))]
+#define _SA_annotes2(n,pp1,pp2) [SAL_annotes(Name=#n, p1=_SA_SPECSTRIZE(pp1), p2=_SA_SPECSTRIZE(pp2))]
+#define _SA_annotes3(n,pp1,pp2,pp3) [SAL_annotes(Name=#n, p1=_SA_SPECSTRIZE(pp1), p2=_SA_SPECSTRIZE(pp2), p3=_SA_SPECSTRIZE(pp3))]
+
+#define _Pre_impl_ [SAL_pre]
+#define _Post_impl_ [SAL_post]
+#define _Deref_impl_ [SAL_deref]
+#define _Notref_impl_ [SAL_notref]
+
+
+// Declare a function to be an annotation or primop (respectively).
+// Done this way so that they don't appear in the regular compiler's
+// namespace.
+#define __ANNOTATION(fun) _SA_annotes0(SAL_annotation) void __SA_##fun;
+#define __PRIMOP(type, fun) _SA_annotes0(SAL_primop) type __SA_##fun;
+#define __QUALIFIER(fun) _SA_annotes0(SAL_qualifier) void __SA_##fun;
+
+// Benign declspec needed here for WindowsPREfast
+#define __In_impl_ [SA_Pre(Valid=SA_Yes)] [SA_Pre(Deref=1, Notref=1, Access=SA_Read)] __declspec("SAL_pre SAL_valid")
+
+#elif _USE_DECLSPECS_FOR_SAL // ][
+
+// Using declspecs for sal
+
+#define _SA_annotes0(n) __declspec(#n)
+#define _SA_annotes1(n,pp1) __declspec(#n "(" _SA_SPECSTRIZE(pp1) ")" )
+#define _SA_annotes2(n,pp1,pp2) __declspec(#n "(" _SA_SPECSTRIZE(pp1) "," _SA_SPECSTRIZE(pp2) ")")
+#define _SA_annotes3(n,pp1,pp2,pp3) __declspec(#n "(" _SA_SPECSTRIZE(pp1) "," _SA_SPECSTRIZE(pp2) "," _SA_SPECSTRIZE(pp3) ")")
+
+#define _Pre_impl_ _SA_annotes0(SAL_pre)
+#define _Post_impl_ _SA_annotes0(SAL_post)
+#define _Deref_impl_ _SA_annotes0(SAL_deref)
+#define _Notref_impl_ _SA_annotes0(SAL_notref)
+
+// Declare a function to be an annotation or primop (respectively).
+// Done this way so that they don't appear in the regular compiler's
+// namespace.
+#define __ANNOTATION(fun) _SA_annotes0(SAL_annotation) void __SA_##fun
+
+#define __PRIMOP(type, fun) _SA_annotes0(SAL_primop) type __SA_##fun
+
+#define __QUALIFIER(fun) _SA_annotes0(SAL_qualifier) void __SA_##fun;
+
+#define __In_impl_ _Pre_impl_ _SA_annotes0(SAL_valid) _Pre_impl_ _Deref_impl_ _Notref_impl_ _SA_annotes0(SAL_readonly)
+
+#else // ][
+
+// Using "nothing" for sal
+
+#define _SA_annotes0(n)
+#define _SA_annotes1(n,pp1)
+#define _SA_annotes2(n,pp1,pp2)
+#define _SA_annotes3(n,pp1,pp2,pp3)
+
+#define __ANNOTATION(fun)
+#define __PRIMOP(type, fun)
+#define __QUALIFIER(type, fun)
+
+#endif // ]
+
+#if _USE_ATTRIBUTES_FOR_SAL || _USE_DECLSPECS_FOR_SAL // [
+
+// Declare annotations that need to be declared.
+__ANNOTATION(SAL_useHeader(void));
+__ANNOTATION(SAL_bound(void));
+__ANNOTATION(SAL_allocator(void)); //??? resolve with PFD
+__ANNOTATION(SAL_file_parser(__AuToQuOtE __In_impl_ char *, __In_impl_ char *));
+__ANNOTATION(SAL_source_code_content(__In_impl_ char *));
+__ANNOTATION(SAL_analysisHint(__AuToQuOtE __In_impl_ char *));
+__ANNOTATION(SAL_untrusted_data_source(__AuToQuOtE __In_impl_ char *));
+__ANNOTATION(SAL_untrusted_data_source_this(__AuToQuOtE __In_impl_ char *));
+__ANNOTATION(SAL_validated(__AuToQuOtE __In_impl_ char *));
+__ANNOTATION(SAL_validated_this(__AuToQuOtE __In_impl_ char *));
+__ANNOTATION(SAL_encoded(void));
+__ANNOTATION(SAL_adt(__AuToQuOtE __In_impl_ char *, __AuToQuOtE __In_impl_ char *));
+__ANNOTATION(SAL_add_adt_property(__AuToQuOtE __In_impl_ char *, __AuToQuOtE __In_impl_ char *));
+__ANNOTATION(SAL_remove_adt_property(__AuToQuOtE __In_impl_ char *, __AuToQuOtE __In_impl_ char *));
+__ANNOTATION(SAL_transfer_adt_property_from(__AuToQuOtE __In_impl_ char *));
+__ANNOTATION(SAL_post_type(__AuToQuOtE __In_impl_ char *));
+__ANNOTATION(SAL_volatile(void));
+__ANNOTATION(SAL_nonvolatile(void));
+__ANNOTATION(SAL_entrypoint(__AuToQuOtE __In_impl_ char *, __AuToQuOtE __In_impl_ char *));
+__ANNOTATION(SAL_blocksOn(__In_impl_ void*));
+__ANNOTATION(SAL_mustInspect(void));
+
+// Only appears in model files, but needs to be declared.
+__ANNOTATION(SAL_TypeName(__AuToQuOtE __In_impl_ char *));
+
+// To be declared well-known soon.
+__ANNOTATION(SAL_interlocked(void);)
+
+#pragma warning (suppress: 28227 28241)
+__ANNOTATION(SAL_name(__In_impl_ char *, __In_impl_ char *, __In_impl_ char *);)
+
+__PRIMOP(char *, _Macro_value_(__In_impl_ char *));
+__PRIMOP(int, _Macro_defined_(__In_impl_ char *));
+__PRIMOP(char *, _Strstr_(__In_impl_ char *, __In_impl_ char *));
+
+#endif // ]
+
+#if _USE_ATTRIBUTES_FOR_SAL // [
+
+#define _Check_return_impl_ [SA_Post(MustCheck=SA_Yes)]
+
+#define _Success_impl_(expr) [SA_Success(Condition=#expr)]
+#define _On_failure_impl_(annos) [SAL_context(p1="SAL_failed")] _Group_(_Post_impl_ _Group_(annos _SAL_nop_impl_))
+
+#define _Printf_format_string_impl_ [SA_FormatString(Style="printf")]
+#define _Scanf_format_string_impl_ [SA_FormatString(Style="scanf")]
+#define _Scanf_s_format_string_impl_ [SA_FormatString(Style="scanf_s")]
+
+#define _In_bound_impl_ [SA_PreBound(Deref=0)]
+#define _Out_bound_impl_ [SA_PostBound(Deref=0)]
+#define _Ret_bound_impl_ [SA_PostBound(Deref=0)]
+#define _Deref_in_bound_impl_ [SA_PreBound(Deref=1)]
+#define _Deref_out_bound_impl_ [SA_PostBound(Deref=1)]
+#define _Deref_ret_bound_impl_ [SA_PostBound(Deref=1)]
+
+#define __valid_impl Valid=SA_Yes
+#define __maybevalid_impl Valid=SA_Maybe
+#define __notvalid_impl Valid=SA_No
+
+#define __null_impl Null=SA_Yes
+#define __maybenull_impl Null=SA_Maybe
+#define __notnull_impl Null=SA_No
+
+#define __null_impl_notref Null=SA_Yes,Notref=1
+#define __maybenull_impl_notref Null=SA_Maybe,Notref=1
+#define __notnull_impl_notref Null=SA_No,Notref=1
+
+#define __zterm_impl NullTerminated=SA_Yes
+#define __maybezterm_impl NullTerminated=SA_Maybe
+#define __maybzterm_impl NullTerminated=SA_Maybe
+#define __notzterm_impl NullTerminated=SA_No
+
+#define __readaccess_impl Access=SA_Read
+#define __writeaccess_impl Access=SA_Write
+#define __allaccess_impl Access=SA_ReadWrite
+
+#define __readaccess_impl_notref Access=SA_Read,Notref=1
+#define __writeaccess_impl_notref Access=SA_Write,Notref=1
+#define __allaccess_impl_notref Access=SA_ReadWrite,Notref=1
+
+#if _MSC_VER >= 1610 /*IFSTRIP=IGN*/ // [
+
+// For SAL2, we need to expect general expressions.
+
+#define __cap_impl(size) WritableElements="\n"#size
+#define __bytecap_impl(size) WritableBytes="\n"#size
+#define __bytecount_impl(size) ValidBytes="\n"#size
+#define __count_impl(size) ValidElements="\n"#size
+
+#else // ][
+
+#define __cap_impl(size) WritableElements=#size
+#define __bytecap_impl(size) WritableBytes=#size
+#define __bytecount_impl(size) ValidBytes=#size
+#define __count_impl(size) ValidElements=#size
+
+#endif // ]
+
+#define __cap_c_impl(size) WritableElementsConst=size
+#define __cap_c_one_notref_impl WritableElementsConst=1,Notref=1
+#define __cap_for_impl(param) WritableElementsLength=#param
+#define __cap_x_impl(size) WritableElements="\n@"#size
+
+#define __bytecap_c_impl(size) WritableBytesConst=size
+#define __bytecap_x_impl(size) WritableBytes="\n@"#size
+
+#define __mult_impl(mult,size) __cap_impl((mult)*(size))
+
+#define __count_c_impl(size) ValidElementsConst=size
+#define __count_x_impl(size) ValidElements="\n@"#size
+
+#define __bytecount_c_impl(size) ValidBytesConst=size
+#define __bytecount_x_impl(size) ValidBytes="\n@"#size
+
+
+#define _At_impl_(target, annos) [SAL_at(p1=#target)] _Group_(annos)
+#define _At_buffer_impl_(target, iter, bound, annos) [SAL_at_buffer(p1=#target, p2=#iter, p3=#bound)] _Group_(annos)
+#define _When_impl_(expr, annos) [SAL_when(p1=#expr)] _Group_(annos)
+
+#define _Group_impl_(annos) [SAL_begin] annos [SAL_end]
+#define _GrouP_impl_(annos) [SAL_BEGIN] annos [SAL_END]
+
+#define _Use_decl_anno_impl_ _SA_annotes0(SAL_useHeader) // this is a special case!
+
+#define _Pre1_impl_(p1) [SA_Pre(p1)]
+#define _Pre2_impl_(p1,p2) [SA_Pre(p1,p2)]
+#define _Pre3_impl_(p1,p2,p3) [SA_Pre(p1,p2,p3)]
+
+#define _Post1_impl_(p1) [SA_Post(p1)]
+#define _Post2_impl_(p1,p2) [SA_Post(p1,p2)]
+#define _Post3_impl_(p1,p2,p3) [SA_Post(p1,p2,p3)]
+
+#define _Ret1_impl_(p1) [SA_Post(p1)]
+#define _Ret2_impl_(p1,p2) [SA_Post(p1,p2)]
+#define _Ret3_impl_(p1,p2,p3) [SA_Post(p1,p2,p3)]
+
+#define _Deref_pre1_impl_(p1) [SA_Pre(Deref=1,p1)]
+#define _Deref_pre2_impl_(p1,p2) [SA_Pre(Deref=1,p1,p2)]
+#define _Deref_pre3_impl_(p1,p2,p3) [SA_Pre(Deref=1,p1,p2,p3)]
+
+
+#define _Deref_post1_impl_(p1) [SA_Post(Deref=1,p1)]
+#define _Deref_post2_impl_(p1,p2) [SA_Post(Deref=1,p1,p2)]
+#define _Deref_post3_impl_(p1,p2,p3) [SA_Post(Deref=1,p1,p2,p3)]
+
+#define _Deref_ret1_impl_(p1) [SA_Post(Deref=1,p1)]
+#define _Deref_ret2_impl_(p1,p2) [SA_Post(Deref=1,p1,p2)]
+#define _Deref_ret3_impl_(p1,p2,p3) [SA_Post(Deref=1,p1,p2,p3)]
+
+#define _Deref2_pre1_impl_(p1) [SA_Pre(Deref=2,Notref=1,p1)]
+#define _Deref2_post1_impl_(p1) [SA_Post(Deref=2,Notref=1,p1)]
+#define _Deref2_ret1_impl_(p1) [SA_Post(Deref=2,Notref=1,p1)]
+
+// Obsolete -- may be needed for transition to attributes.
+#define __inner_typefix(ctype) [SAL_typefix(p1=_SA_SPECSTRIZE(ctype))]
+#define __inner_exceptthat [SAL_except]
+
+
+#elif _USE_DECLSPECS_FOR_SAL // ][
+
+#define _Check_return_impl_ __post _SA_annotes0(SAL_checkReturn)
+
+#define _Success_impl_(expr) _SA_annotes1(SAL_success, expr)
+#define _On_failure_impl_(annos) _SA_annotes1(SAL_context, SAL_failed) _Group_(_Post_impl_ _Group_(_SAL_nop_impl_ annos))
+
+#define _Printf_format_string_impl_ _SA_annotes1(SAL_IsFormatString, "printf")
+#define _Scanf_format_string_impl_ _SA_annotes1(SAL_IsFormatString, "scanf")
+#define _Scanf_s_format_string_impl_ _SA_annotes1(SAL_IsFormatString, "scanf_s")
+
+#define _In_bound_impl_ _Pre_impl_ _Bound_impl_
+#define _Out_bound_impl_ _Post_impl_ _Bound_impl_
+#define _Ret_bound_impl_ _Post_impl_ _Bound_impl_
+#define _Deref_in_bound_impl_ _Deref_pre_impl_ _Bound_impl_
+#define _Deref_out_bound_impl_ _Deref_post_impl_ _Bound_impl_
+#define _Deref_ret_bound_impl_ _Deref_post_impl_ _Bound_impl_
+
+
+#define __null_impl _SA_annotes0(SAL_null) // _SA_annotes1(SAL_null, __yes)
+#define __notnull_impl _SA_annotes0(SAL_notnull) // _SA_annotes1(SAL_null, __no)
+#define __maybenull_impl _SA_annotes0(SAL_maybenull) // _SA_annotes1(SAL_null, __maybe)
+
+#define __valid_impl _SA_annotes0(SAL_valid) // _SA_annotes1(SAL_valid, __yes)
+#define __notvalid_impl _SA_annotes0(SAL_notvalid) // _SA_annotes1(SAL_valid, __no)
+#define __maybevalid_impl _SA_annotes0(SAL_maybevalid) // _SA_annotes1(SAL_valid, __maybe)
+
+#define __null_impl_notref _Notref_ _Null_impl_
+#define __maybenull_impl_notref _Notref_ _Maybenull_impl_
+#define __notnull_impl_notref _Notref_ _Notnull_impl_
+
+#define __zterm_impl _SA_annotes1(SAL_nullTerminated, __yes)
+#define __maybezterm_impl _SA_annotes1(SAL_nullTerminated, __maybe)
+#define __maybzterm_impl _SA_annotes1(SAL_nullTerminated, __maybe)
+#define __notzterm_impl _SA_annotes1(SAL_nullTerminated, __no)
+
+#define __readaccess_impl _SA_annotes1(SAL_access, 0x1)
+#define __writeaccess_impl _SA_annotes1(SAL_access, 0x2)
+#define __allaccess_impl _SA_annotes1(SAL_access, 0x3)
+
+#define __readaccess_impl_notref _Notref_ _SA_annotes1(SAL_access, 0x1)
+#define __writeaccess_impl_notref _Notref_ _SA_annotes1(SAL_access, 0x2)
+#define __allaccess_impl_notref _Notref_ _SA_annotes1(SAL_access, 0x3)
+
+#define __cap_impl(size) _SA_annotes1(SAL_writableTo,elementCount(size))
+#define __cap_c_impl(size) _SA_annotes1(SAL_writableTo,elementCount(size))
+#define __cap_c_one_notref_impl _Notref_ _SA_annotes1(SAL_writableTo,elementCount(1))
+#define __cap_for_impl(param) _SA_annotes1(SAL_writableTo,inexpressibleCount(sizeof(param)))
+#define __cap_x_impl(size) _SA_annotes1(SAL_writableTo,inexpressibleCount(#size))
+
+#define __bytecap_impl(size) _SA_annotes1(SAL_writableTo,byteCount(size))
+#define __bytecap_c_impl(size) _SA_annotes1(SAL_writableTo,byteCount(size))
+#define __bytecap_x_impl(size) _SA_annotes1(SAL_writableTo,inexpressibleCount(#size))
+
+#define __mult_impl(mult,size) _SA_annotes1(SAL_writableTo,(mult)*(size))
+
+#define __count_impl(size) _SA_annotes1(SAL_readableTo,elementCount(size))
+#define __count_c_impl(size) _SA_annotes1(SAL_readableTo,elementCount(size))
+#define __count_x_impl(size) _SA_annotes1(SAL_readableTo,inexpressibleCount(#size))
+
+#define __bytecount_impl(size) _SA_annotes1(SAL_readableTo,byteCount(size))
+#define __bytecount_c_impl(size) _SA_annotes1(SAL_readableTo,byteCount(size))
+#define __bytecount_x_impl(size) _SA_annotes1(SAL_readableTo,inexpressibleCount(#size))
+
+#define _At_impl_(target, annos) _SA_annotes0(SAL_at(target)) _Group_(annos)
+#define _At_buffer_impl_(target, iter, bound, annos) _SA_annotes3(SAL_at_buffer, target, iter, bound) _Group_(annos)
+#define _Group_impl_(annos) _SA_annotes0(SAL_begin) annos _SA_annotes0(SAL_end)
+#define _GrouP_impl_(annos) _SA_annotes0(SAL_BEGIN) annos _SA_annotes0(SAL_END)
+#define _When_impl_(expr, annos) _SA_annotes0(SAL_when(expr)) _Group_(annos)
+
+#define _Use_decl_anno_impl_ __declspec("SAL_useHeader()") // this is a special case!
+
+#define _Pre1_impl_(p1) _Pre_impl_ p1
+#define _Pre2_impl_(p1,p2) _Pre_impl_ p1 _Pre_impl_ p2
+#define _Pre3_impl_(p1,p2,p3) _Pre_impl_ p1 _Pre_impl_ p2 _Pre_impl_ p3
+
+#define _Post1_impl_(p1) _Post_impl_ p1
+#define _Post2_impl_(p1,p2) _Post_impl_ p1 _Post_impl_ p2
+#define _Post3_impl_(p1,p2,p3) _Post_impl_ p1 _Post_impl_ p2 _Post_impl_ p3
+
+#define _Ret1_impl_(p1) _Post_impl_ p1
+#define _Ret2_impl_(p1,p2) _Post_impl_ p1 _Post_impl_ p2
+#define _Ret3_impl_(p1,p2,p3) _Post_impl_ p1 _Post_impl_ p2 _Post_impl_ p3
+
+#define _Deref_pre1_impl_(p1) _Deref_pre_impl_ p1
+#define _Deref_pre2_impl_(p1,p2) _Deref_pre_impl_ p1 _Deref_pre_impl_ p2
+#define _Deref_pre3_impl_(p1,p2,p3) _Deref_pre_impl_ p1 _Deref_pre_impl_ p2 _Deref_pre_impl_ p3
+
+#define _Deref_post1_impl_(p1) _Deref_post_impl_ p1
+#define _Deref_post2_impl_(p1,p2) _Deref_post_impl_ p1 _Deref_post_impl_ p2
+#define _Deref_post3_impl_(p1,p2,p3) _Deref_post_impl_ p1 _Deref_post_impl_ p2 _Deref_post_impl_ p3
+
+#define _Deref_ret1_impl_(p1) _Deref_post_impl_ p1
+#define _Deref_ret2_impl_(p1,p2) _Deref_post_impl_ p1 _Deref_post_impl_ p2
+#define _Deref_ret3_impl_(p1,p2,p3) _Deref_post_impl_ p1 _Deref_post_impl_ p2 _Deref_post_impl_ p3
+
+#define _Deref2_pre1_impl_(p1) _Deref_pre_impl_ _Notref_impl_ _Deref_impl_ p1
+#define _Deref2_post1_impl_(p1) _Deref_post_impl_ _Notref_impl_ _Deref_impl_ p1
+#define _Deref2_ret1_impl_(p1) _Deref_post_impl_ _Notref_impl_ _Deref_impl_ p1
+
+#define __inner_typefix(ctype) _SA_annotes1(SAL_typefix, ctype)
+#define __inner_exceptthat _SA_annotes0(SAL_except)
+
+#elif defined(_MSC_EXTENSIONS) && !defined( MIDL_PASS ) && !defined(__midl) && !defined(RC_INVOKED) && defined(_PFT_VER) && _MSC_VER >= 1400 /*IFSTRIP=IGN*/ // ][
+
+// minimum attribute expansion for foreground build
+
+#pragma push_macro( "SA" )
+#pragma push_macro( "REPEATABLE" )
+
+#ifdef __cplusplus // [
+#define SA( id ) id
+#define REPEATABLE [repeatable]
+#else // !__cplusplus // ][
+#define SA( id ) SA_##id
+#define REPEATABLE
+#endif // !__cplusplus // ]
+
+REPEATABLE
+[source_annotation_attribute( SA( Parameter ) )]
+struct __P_impl
+{
+#ifdef __cplusplus // [
+ __P_impl();
+#endif // ]
+ int __d_;
+};
+typedef struct __P_impl __P_impl;
+
+REPEATABLE
+[source_annotation_attribute( SA( ReturnValue ) )]
+struct __R_impl
+{
+#ifdef __cplusplus // [
+ __R_impl();
+#endif // ]
+ int __d_;
+};
+typedef struct __R_impl __R_impl;
+
+[source_annotation_attribute( SA( Method ) )]
+struct __M_
+{
+#ifdef __cplusplus // [
+ __M_();
+#endif // ]
+ int __d_;
+};
+typedef struct __M_ __M_;
+
+[source_annotation_attribute( SA( All ) )]
+struct __A_
+{
+#ifdef __cplusplus // [
+ __A_();
+#endif // ]
+ int __d_;
+};
+typedef struct __A_ __A_;
+
+[source_annotation_attribute( SA( Field ) )]
+struct __F_
+{
+#ifdef __cplusplus // [
+ __F_();
+#endif // ]
+ int __d_;
+};
+typedef struct __F_ __F_;
+
+#pragma pop_macro( "REPEATABLE" )
+#pragma pop_macro( "SA" )
+
+
+#define _SAL_nop_impl_
+
+#define _At_impl_(target, annos) [__A_(__d_=0)]
+#define _At_buffer_impl_(target, iter, bound, annos) [__A_(__d_=0)]
+#define _When_impl_(expr, annos) annos
+#define _Group_impl_(annos) annos
+#define _GrouP_impl_(annos) annos
+#define _Use_decl_anno_impl_ [__M_(__d_=0)]
+
+#define _Points_to_data_impl_ [__P_impl(__d_=0)]
+#define _Literal_impl_ [__P_impl(__d_=0)]
+#define _Notliteral_impl_ [__P_impl(__d_=0)]
+
+#define _Pre_valid_impl_ [__P_impl(__d_=0)]
+#define _Post_valid_impl_ [__P_impl(__d_=0)]
+#define _Ret_valid_impl_ [__R_impl(__d_=0)]
+
+#define _Check_return_impl_ [__R_impl(__d_=0)]
+#define _Must_inspect_impl_ [__R_impl(__d_=0)]
+
+#define _Success_impl_(expr) [__M_(__d_=0)]
+#define _On_failure_impl_(expr) [__M_(__d_=0)]
+#define _Always_impl_(expr) [__M_(__d_=0)]
+
+#define _Printf_format_string_impl_ [__P_impl(__d_=0)]
+#define _Scanf_format_string_impl_ [__P_impl(__d_=0)]
+#define _Scanf_s_format_string_impl_ [__P_impl(__d_=0)]
+
+#define _Raises_SEH_exception_impl_ [__M_(__d_=0)]
+#define _Maybe_raises_SEH_exception_impl_ [__M_(__d_=0)]
+
+#define _In_bound_impl_ [__P_impl(__d_=0)]
+#define _Out_bound_impl_ [__P_impl(__d_=0)]
+#define _Ret_bound_impl_ [__R_impl(__d_=0)]
+#define _Deref_in_bound_impl_ [__P_impl(__d_=0)]
+#define _Deref_out_bound_impl_ [__P_impl(__d_=0)]
+#define _Deref_ret_bound_impl_ [__R_impl(__d_=0)]
+
+#define _Range_impl_(min,max) [__P_impl(__d_=0)]
+#define _In_range_impl_(min,max) [__P_impl(__d_=0)]
+#define _Out_range_impl_(min,max) [__P_impl(__d_=0)]
+#define _Ret_range_impl_(min,max) [__R_impl(__d_=0)]
+#define _Deref_in_range_impl_(min,max) [__P_impl(__d_=0)]
+#define _Deref_out_range_impl_(min,max) [__P_impl(__d_=0)]
+#define _Deref_ret_range_impl_(min,max) [__R_impl(__d_=0)]
+
+#define _Field_range_impl_(min,max) [__F_(__d_=0)]
+
+#define _Pre_satisfies_impl_(cond) [__A_(__d_=0)]
+#define _Post_satisfies_impl_(cond) [__A_(__d_=0)]
+#define _Satisfies_impl_(cond) [__A_(__d_=0)]
+
+#define _Null_impl_ [__A_(__d_=0)]
+#define _Notnull_impl_ [__A_(__d_=0)]
+#define _Maybenull_impl_ [__A_(__d_=0)]
+
+#define _Valid_impl_ [__A_(__d_=0)]
+#define _Notvalid_impl_ [__A_(__d_=0)]
+#define _Maybevalid_impl_ [__A_(__d_=0)]
+
+#define _Readable_bytes_impl_(size) [__A_(__d_=0)]
+#define _Readable_elements_impl_(size) [__A_(__d_=0)]
+#define _Writable_bytes_impl_(size) [__A_(__d_=0)]
+#define _Writable_elements_impl_(size) [__A_(__d_=0)]
+
+#define _Null_terminated_impl_ [__A_(__d_=0)]
+#define _NullNull_terminated_impl_ [__A_(__d_=0)]
+
+#define _Pre_impl_ [__P_impl(__d_=0)]
+#define _Pre1_impl_(p1) [__P_impl(__d_=0)]
+#define _Pre2_impl_(p1,p2) [__P_impl(__d_=0)]
+#define _Pre3_impl_(p1,p2,p3) [__P_impl(__d_=0)]
+
+#define _Post_impl_ [__P_impl(__d_=0)]
+#define _Post1_impl_(p1) [__P_impl(__d_=0)]
+#define _Post2_impl_(p1,p2) [__P_impl(__d_=0)]
+#define _Post3_impl_(p1,p2,p3) [__P_impl(__d_=0)]
+
+#define _Ret1_impl_(p1) [__R_impl(__d_=0)]
+#define _Ret2_impl_(p1,p2) [__R_impl(__d_=0)]
+#define _Ret3_impl_(p1,p2,p3) [__R_impl(__d_=0)]
+
+#define _Deref_pre1_impl_(p1) [__P_impl(__d_=0)]
+#define _Deref_pre2_impl_(p1,p2) [__P_impl(__d_=0)]
+#define _Deref_pre3_impl_(p1,p2,p3) [__P_impl(__d_=0)]
+
+#define _Deref_post1_impl_(p1) [__P_impl(__d_=0)]
+#define _Deref_post2_impl_(p1,p2) [__P_impl(__d_=0)]
+#define _Deref_post3_impl_(p1,p2,p3) [__P_impl(__d_=0)]
+
+#define _Deref_ret1_impl_(p1) [__R_impl(__d_=0)]
+#define _Deref_ret2_impl_(p1,p2) [__R_impl(__d_=0)]
+#define _Deref_ret3_impl_(p1,p2,p3) [__R_impl(__d_=0)]
+
+#define _Deref2_pre1_impl_(p1) //[__P_impl(__d_=0)]
+#define _Deref2_post1_impl_(p1) //[__P_impl(__d_=0)]
+#define _Deref2_ret1_impl_(p1) //[__P_impl(__d_=0)]
+
+#else // ][
+
+
+#define _SAL_nop_impl_ X
+
+#define _At_impl_(target, annos)
+#define _When_impl_(expr, annos)
+#define _Group_impl_(annos)
+#define _GrouP_impl_(annos)
+#define _At_buffer_impl_(target, iter, bound, annos)
+#define _Use_decl_anno_impl_
+#define _Points_to_data_impl_
+#define _Literal_impl_
+#define _Notliteral_impl_
+#define _Notref_impl_
+
+#define _Pre_valid_impl_
+#define _Post_valid_impl_
+#define _Ret_valid_impl_
+
+#define _Check_return_impl_
+#define _Must_inspect_impl_
+
+#define _Success_impl_(expr)
+#define _On_failure_impl_(annos)
+#define _Always_impl_(annos)
+
+#define _Printf_format_string_impl_
+#define _Scanf_format_string_impl_
+#define _Scanf_s_format_string_impl_
+
+#define _In_bound_impl_
+#define _Out_bound_impl_
+#define _Ret_bound_impl_
+#define _Deref_in_bound_impl_
+#define _Deref_out_bound_impl_
+#define _Deref_ret_bound_impl_
+
+#define _Range_impl_(min,max)
+#define _In_range_impl_(min,max)
+#define _Out_range_impl_(min,max)
+#define _Ret_range_impl_(min,max)
+#define _Deref_in_range_impl_(min,max)
+#define _Deref_out_range_impl_(min,max)
+#define _Deref_ret_range_impl_(min,max)
+
+#define _Satisfies_impl_(expr)
+#define _Pre_satisfies_impl_(expr)
+#define _Post_satisfies_impl_(expr)
+
+#define _Null_impl_
+#define _Notnull_impl_
+#define _Maybenull_impl_
+
+#define _Valid_impl_
+#define _Notvalid_impl_
+#define _Maybevalid_impl_
+
+#define _Field_range_impl_(min,max)
+
+#define _Pre_impl_
+#define _Pre1_impl_(p1)
+#define _Pre2_impl_(p1,p2)
+#define _Pre3_impl_(p1,p2,p3)
+
+#define _Post_impl_
+#define _Post1_impl_(p1)
+#define _Post2_impl_(p1,p2)
+#define _Post3_impl_(p1,p2,p3)
+
+#define _Ret1_impl_(p1)
+#define _Ret2_impl_(p1,p2)
+#define _Ret3_impl_(p1,p2,p3)
+
+#define _Deref_pre1_impl_(p1)
+#define _Deref_pre2_impl_(p1,p2)
+#define _Deref_pre3_impl_(p1,p2,p3)
+
+#define _Deref_post1_impl_(p1)
+#define _Deref_post2_impl_(p1,p2)
+#define _Deref_post3_impl_(p1,p2,p3)
+
+#define _Deref_ret1_impl_(p1)
+#define _Deref_ret2_impl_(p1,p2)
+#define _Deref_ret3_impl_(p1,p2,p3)
+
+#define _Deref2_pre1_impl_(p1)
+#define _Deref2_post1_impl_(p1)
+#define _Deref2_ret1_impl_(p1)
+
+#define _Readable_bytes_impl_(size)
+#define _Readable_elements_impl_(size)
+#define _Writable_bytes_impl_(size)
+#define _Writable_elements_impl_(size)
+
+#define _Null_terminated_impl_
+#define _NullNull_terminated_impl_
+
+// Obsolete -- may be needed for transition to attributes.
+#define __inner_typefix(ctype)
+#define __inner_exceptthat
+
+#endif // ]
+
+// This section contains the deprecated annotations
+
+/*
+ -------------------------------------------------------------------------------
+ Introduction
+
+ sal.h provides a set of annotations to describe how a function uses its
+ parameters - the assumptions it makes about them, and the guarantees it makes
+ upon finishing.
+
+ Annotations may be placed before either a function parameter's type or its return
+ type, and describe the function's behavior regarding the parameter or return value.
+ There are two classes of annotations: buffer annotations and advanced annotations.
+ Buffer annotations describe how functions use their pointer parameters, and
+ advanced annotations either describe complex/unusual buffer behavior, or provide
+ additional information about a parameter that is not otherwise expressible.
+
+ -------------------------------------------------------------------------------
+ Buffer Annotations
+
+ The most important annotations in sal.h provide a consistent way to annotate
+ buffer parameters or return values for a function. Each of these annotations describes
+ a single buffer (which could be a string, a fixed-length or variable-length array,
+ or just a pointer) that the function interacts with: where it is, how large it is,
+ how much is initialized, and what the function does with it.
+
+ The appropriate macro for a given buffer can be constructed using the table below.
+ Just pick the appropriate values from each category, and combine them together
+ with a leading underscore. Some combinations of values do not make sense as buffer
+ annotations. Only meaningful annotations can be added to your code; for a list of
+ these, see the buffer annotation definitions section.
+
+ Only a single buffer annotation should be used for each parameter.
+
+ |------------|------------|---------|--------|----------|----------|---------------|
+ | Level | Usage | Size | Output | NullTerm | Optional | Parameters |
+ |------------|------------|---------|--------|----------|----------|---------------|
+ | <> | <> | <> | <> | _z | <> | <> |
+ | _deref | _in | _ecount | _full | _nz | _opt | (size) |
+ | _deref_opt | _out | _bcount | _part | | | (size,length) |
+ | | _inout | | | | | |
+ | | | | | | | |
+ |------------|------------|---------|--------|----------|----------|---------------|
+
+ Level: Describes the buffer pointer's level of indirection from the parameter or
+ return value 'p'.
+
+ <> : p is the buffer pointer.
+ _deref : *p is the buffer pointer. p must not be NULL.
+ _deref_opt : *p may be the buffer pointer. p may be NULL, in which case the rest of
+ the annotation is ignored.
+
+ Usage: Describes how the function uses the buffer.
+
+ <> : The buffer is not accessed. If used on the return value or with _deref, the
+ function will provide the buffer, and it will be uninitialized at exit.
+ Otherwise, the caller must provide the buffer. This should only be used
+ for alloc and free functions.
+ _in : The function will only read from the buffer. The caller must provide the
+ buffer and initialize it. Cannot be used with _deref.
+ _out : The function will only write to the buffer. If used on the return value or
+ with _deref, the function will provide the buffer and initialize it.
+ Otherwise, the caller must provide the buffer, and the function will
+ initialize it.
+ _inout : The function may freely read from and write to the buffer. The caller must
+ provide the buffer and initialize it. If used with _deref, the buffer may
+ be reallocated by the function.
+
+ Size: Describes the total size of the buffer. This may be less than the space actually
+ allocated for the buffer, in which case it describes the accessible amount.
+
+ <> : No buffer size is given. If the type specifies the buffer size (such as
+ with LPSTR and LPWSTR), that amount is used. Otherwise, the buffer is one
+ element long. Must be used with _in, _out, or _inout.
+ _ecount : The buffer size is an explicit element count.
+ _bcount : The buffer size is an explicit byte count.
+
+ Output: Describes how much of the buffer will be initialized by the function. For
+ _inout buffers, this also describes how much is initialized at entry. Omit this
+ category for _in buffers; they must be fully initialized by the caller.
+
+ <> : The type specifies how much is initialized. For instance, a function initializing
+ an LPWSTR must NULL-terminate the string.
+ _full : The function initializes the entire buffer.
+ _part : The function initializes part of the buffer, and explicitly indicates how much.
+
+ NullTerm: States if the present of a '\0' marks the end of valid elements in the buffer.
+ _z : A '\0' indicated the end of the buffer
+ _nz : The buffer may not be null terminated and a '\0' does not indicate the end of the
+ buffer.
+ Optional: Describes if the buffer itself is optional.
+
+ <> : The pointer to the buffer must not be NULL.
+ _opt : The pointer to the buffer might be NULL. It will be checked before being dereferenced.
+
+ Parameters: Gives explicit counts for the size and length of the buffer.
+
+ <> : There is no explicit count. Use when neither _ecount nor _bcount is used.
+ (size) : Only the buffer's total size is given. Use with _ecount or _bcount but not _part.
+ (size,length) : The buffer's total size and initialized length are given. Use with _ecount_part
+ and _bcount_part.
+
+ -------------------------------------------------------------------------------
+ Buffer Annotation Examples
+
+ LWSTDAPI_(BOOL) StrToIntExA(
+ __in LPCSTR pszString,
+ DWORD dwFlags,
+ __out int *piRet -- A pointer whose dereference will be filled in.
+ );
+
+ void MyPaintingFunction(
+ __in HWND hwndControl, -- An initialized read-only parameter.
+ __in_opt HDC hdcOptional, -- An initialized read-only parameter that might be NULL.
+ __inout IPropertyStore *ppsStore -- An initialized parameter that may be freely used
+ -- and modified.
+ );
+
+ LWSTDAPI_(BOOL) PathCompactPathExA(
+ __out_ecount(cchMax) LPSTR pszOut, -- A string buffer with cch elements that will
+ -- be NULL terminated on exit.
+ __in LPCSTR pszSrc,
+ UINT cchMax,
+ DWORD dwFlags
+ );
+
+ HRESULT SHLocalAllocBytes(
+ size_t cb,
+ __deref_bcount(cb) T **ppv -- A pointer whose dereference will be set to an
+ -- uninitialized buffer with cb bytes.
+ );
+
+ __inout_bcount_full(cb) : A buffer with cb elements that is fully initialized at
+ entry and exit, and may be written to by this function.
+
+ __out_ecount_part(count, *countOut) : A buffer with count elements that will be
+ partially initialized by this function. The function indicates how much it
+ initialized by setting *countOut.
+
+ -------------------------------------------------------------------------------
+ Advanced Annotations
+
+ Advanced annotations describe behavior that is not expressible with the regular
+ buffer macros. These may be used either to annotate buffer parameters that involve
+ complex or conditional behavior, or to enrich existing annotations with additional
+ information.
+
+ __success(expr) f :
+ <expr> indicates whether function f succeeded or not. If <expr> is true at exit,
+ all the function's guarantees (as given by other annotations) must hold. If <expr>
+ is false at exit, the caller should not expect any of the function's guarantees
+ to hold. If not used, the function must always satisfy its guarantees. Added
+ automatically to functions that indicate success in standard ways, such as by
+ returning an HRESULT.
+
+ __nullterminated p :
+ Pointer p is a buffer that may be read or written up to and including the first
+ NULL character or pointer. May be used on typedefs, which marks valid (properly
+ initialized) instances of that type as being NULL-terminated.
+
+ __nullnullterminated p :
+ Pointer p is a buffer that may be read or written up to and including the first
+ sequence of two NULL characters or pointers. May be used on typedefs, which marks
+ valid instances of that type as being double-NULL terminated.
+
+ __reserved v :
+ Value v must be 0/NULL, reserved for future use.
+
+ __checkReturn v :
+ Return value v must not be ignored by callers of this function.
+
+ __typefix(ctype) v :
+ Value v should be treated as an instance of ctype, rather than its declared type.
+
+ __override f :
+ Specify C#-style 'override' behaviour for overriding virtual methods.
+
+ __callback f :
+ Function f can be used as a function pointer.
+
+ __format_string p :
+ Pointer p is a string that contains % markers in the style of printf.
+
+ __blocksOn(resource) f :
+ Function f blocks on the resource 'resource'.
+
+ __fallthrough :
+ Annotates switch statement labels where fall-through is desired, to distinguish
+ from forgotten break statements.
+
+ -------------------------------------------------------------------------------
+ Advanced Annotation Examples
+
+ __success(return != FALSE) LWSTDAPI_(BOOL)
+ PathCanonicalizeA(__out_ecount(MAX_PATH) LPSTR pszBuf, LPCSTR pszPath) :
+ pszBuf is only guaranteed to be NULL-terminated when TRUE is returned.
+
+ typedef __nullterminated WCHAR* LPWSTR : Initialized LPWSTRs are NULL-terminated strings.
+
+ __out_ecount(cch) __typefix(LPWSTR) void *psz : psz is a buffer parameter which will be
+ a NULL-terminated WCHAR string at exit, and which initially contains cch WCHARs.
+
+ -------------------------------------------------------------------------------
+*/
+
+#define __specstrings
+
+#ifdef __cplusplus // [
+#ifndef __nothrow // [
+# define __nothrow __declspec(nothrow)
+#endif // ]
+extern "C" {
+#else // ][
+#ifndef __nothrow // [
+# define __nothrow
+#endif // ]
+#endif /* #ifdef __cplusplus */ // ]
+
+
+/*
+ -------------------------------------------------------------------------------
+ Helper Macro Definitions
+
+ These express behavior common to many of the high-level annotations.
+ DO NOT USE THESE IN YOUR CODE.
+ -------------------------------------------------------------------------------
+*/
+
+/*
+ The helper annotations are only understood by the compiler version used by
+ various defect detection tools. When the regular compiler is running, they
+ are defined into nothing, and do not affect the compiled code.
+*/
+
+#if !defined(__midl) && defined(_PREFAST_) // [
+
+ /*
+ In the primitive "SAL_*" annotations "SAL" stands for Standard
+ Annotation Language. These "SAL_*" annotations are the
+ primitives the compiler understands and high-level MACROs
+ will decompose into these primivates.
+ */
+
+ #define _SA_SPECSTRIZE( x ) #x
+
+ /*
+ __null p
+ __notnull p
+ __maybenull p
+
+ Annotates a pointer p. States that pointer p is null. Commonly used
+ in the negated form __notnull or the possibly null form __maybenull.
+ */
+
+#ifndef PAL_STDCPP_COMPAT
+ #define __null _Null_impl_
+ #define __notnull _Notnull_impl_
+ #define __maybenull _Maybenull_impl_
+#endif // !PAL_STDCPP_COMPAT
+
+ /*
+ __readonly l
+ __notreadonly l
+ __mabyereadonly l
+
+ Annotates a location l. States that location l is not modified after
+ this point. If the annotation is placed on the precondition state of
+ a function, the restriction only applies until the postcondition state
+ of the function. __maybereadonly states that the annotated location
+ may be modified, whereas __notreadonly states that a location must be
+ modified.
+ */
+
+ #define __readonly _Pre1_impl_(__readaccess_impl)
+ #define __notreadonly _Pre1_impl_(__allaccess_impl)
+ #define __maybereadonly _Pre1_impl_(__readaccess_impl)
+
+ /*
+ __valid v
+ __notvalid v
+ __maybevalid v
+
+ Annotates any value v. States that the value satisfies all properties of
+ valid values of its type. For example, for a string buffer, valid means
+ that the buffer pointer is either NULL or points to a NULL-terminated string.
+ */
+
+ #define __valid _Valid_impl_
+ #define __notvalid _Notvalid_impl_
+ #define __maybevalid _Maybevalid_impl_
+
+ /*
+ __readableTo(extent) p
+
+ Annotates a buffer pointer p. If the buffer can be read, extent describes
+ how much of the buffer is readable. For a reader of the buffer, this is
+ an explicit permission to read up to that amount, rather than a restriction to
+ read only up to it.
+ */
+
+ #define __readableTo(extent) _SA_annotes1(SAL_readableTo, extent)
+
+ /*
+
+ __elem_readableTo(size)
+
+ Annotates a buffer pointer p as being readable to size elements.
+ */
+
+ #define __elem_readableTo(size) _SA_annotes1(SAL_readableTo, elementCount( size ))
+
+ /*
+ __byte_readableTo(size)
+
+ Annotates a buffer pointer p as being readable to size bytes.
+ */
+ #define __byte_readableTo(size) _SA_annotes1(SAL_readableTo, byteCount(size))
+
+ /*
+ __writableTo(extent) p
+
+ Annotates a buffer pointer p. If the buffer can be modified, extent
+ describes how much of the buffer is writable (usually the allocation
+ size). For a writer of the buffer, this is an explicit permission to
+ write up to that amount, rather than a restriction to write only up to it.
+ */
+ #define __writableTo(size) _SA_annotes1(SAL_writableTo, size)
+
+ /*
+ __elem_writableTo(size)
+
+ Annotates a buffer pointer p as being writable to size elements.
+ */
+ #define __elem_writableTo(size) _SA_annotes1(SAL_writableTo, elementCount( size ))
+
+ /*
+ __byte_writableTo(size)
+
+ Annotates a buffer pointer p as being writable to size bytes.
+ */
+ #define __byte_writableTo(size) _SA_annotes1(SAL_writableTo, byteCount( size))
+
+ /*
+ __deref p
+
+ Annotates a pointer p. The next annotation applies one dereference down
+ in the type. If readableTo(p, size) then the next annotation applies to
+ all elements *(p+i) for which i satisfies the size. If p is a pointer
+ to a struct, the next annotation applies to all fields of the struct.
+ */
+ #define __deref _Deref_impl_
+
+ /*
+ __pre __next_annotation
+
+ The next annotation applies in the precondition state
+ */
+ #define __pre _Pre_impl_
+
+ /*
+ __post __next_annotation
+
+ The next annotation applies in the postcondition state
+ */
+ #define __post _Post_impl_
+
+ /*
+ __precond(<expr>)
+
+ When <expr> is true, the next annotation applies in the precondition state
+ (currently not enabled)
+ */
+ #define __precond(expr) __pre
+
+ /*
+ __postcond(<expr>)
+
+ When <expr> is true, the next annotation applies in the postcondition state
+ (currently not enabled)
+ */
+ #define __postcond(expr) __post
+
+ /*
+ __exceptthat
+
+ Given a set of annotations Q containing __exceptthat maybeP, the effect of
+ the except clause is to erase any P or notP annotations (explicit or
+ implied) within Q at the same level of dereferencing that the except
+ clause appears, and to replace it with maybeP.
+
+ Example 1: __valid __pre_except_maybenull on a pointer p means that the
+ pointer may be null, and is otherwise valid, thus overriding
+ the implicit notnull annotation implied by __valid on
+ pointers.
+
+ Example 2: __valid __deref __pre_except_maybenull on an int **p means
+ that p is not null (implied by valid), but the elements
+ pointed to by p could be null, and are otherwise valid.
+ */
+ #define __exceptthat __inner_exceptthat
+
+ /*
+ _refparam
+
+ Added to all out parameter macros to indicate that they are all reference
+ parameters.
+ */
+ #define __refparam _Notref_ __deref __notreadonly
+
+ /*
+ __inner_*
+
+ Helper macros that directly correspond to certain high-level annotations.
+
+ */
+
+ /*
+ Macros to classify the entrypoints and indicate their category.
+
+ Pre-defined control point categories include: RPC, LPC, DeviceDriver, UserToKernel, ISAPI, COM.
+
+ */
+ #define __inner_control_entrypoint(category) _SA_annotes2(SAL_entrypoint, controlEntry, category)
+
+
+ /*
+ Pre-defined data entry point categories include: Registry, File, Network.
+ */
+ #define __inner_data_entrypoint(category) _SA_annotes2(SAL_entrypoint, dataEntry, category)
+
+ #define __inner_override _SA_annotes0(__override)
+ #define __inner_callback _SA_annotes0(__callback)
+ #define __inner_blocksOn(resource) _SA_annotes1(SAL_blocksOn, resource)
+ #define __inner_fallthrough_dec __inline __nothrow void __FallThrough() {}
+ #define __inner_fallthrough __FallThrough();
+
+ #define __post_except_maybenull __post __inner_exceptthat _Maybenull_impl_
+ #define __pre_except_maybenull __pre __inner_exceptthat _Maybenull_impl_
+
+ #define __post_deref_except_maybenull __post __deref __inner_exceptthat _Maybenull_impl_
+ #define __pre_deref_except_maybenull __pre __deref __inner_exceptthat _Maybenull_impl_
+
+ #define __inexpressible_readableTo(size) _Readable_elements_impl_(_Inexpressible_(size))
+ #define __inexpressible_writableTo(size) _Writable_elements_impl_(_Inexpressible_(size))
+
+
+#else // ][
+#ifndef PAL_STDCPP_COMPAT
+ #define __null
+ #define __notnull
+#endif // !PAL_STDCPP_COMPAT
+ #define __maybenull
+ #define __readonly
+ #define __notreadonly
+ #define __maybereadonly
+ #define __valid
+ #define __notvalid
+ #define __maybevalid
+ #define __readableTo(extent)
+ #define __elem_readableTo(size)
+ #define __byte_readableTo(size)
+ #define __writableTo(size)
+ #define __elem_writableTo(size)
+ #define __byte_writableTo(size)
+ #define __deref
+ #define __pre
+ #define __post
+ #define __precond(expr)
+ #define __postcond(expr)
+ #define __exceptthat
+ #define __inner_override
+ #define __inner_callback
+ #define __inner_blocksOn(resource)
+ #define __inner_fallthrough_dec
+ #define __inner_fallthrough
+ #define __refparam
+ #define __inner_control_entrypoint(category)
+ #define __inner_data_entrypoint(category)
+
+ #define __post_except_maybenull
+ #define __pre_except_maybenull
+ #define __post_deref_except_maybenull
+ #define __pre_deref_except_maybenull
+
+ #define __inexpressible_readableTo(size)
+ #define __inexpressible_writableTo(size)
+
+#endif /* #if !defined(__midl) && defined(_PREFAST_) */ // ]
+
+/*
+-------------------------------------------------------------------------------
+Buffer Annotation Definitions
+
+Any of these may be used to directly annotate functions, but only one should
+be used for each parameter. To determine which annotation to use for a given
+buffer, use the table in the buffer annotations section.
+-------------------------------------------------------------------------------
+*/
+
+// These macros conflict with c++ headers.
+#ifndef PAL_STDCPP_COMPAT
+#define __in _SAL1_Source_(__in, (), _In_)
+#define __out _SAL1_Source_(__out, (), _Out_)
+#endif // !PAL_STDCPP_COMPAT
+
+#define __ecount(size) _SAL1_Source_(__ecount, (size), __notnull __elem_writableTo(size))
+#define __bcount(size) _SAL1_Source_(__bcount, (size), __notnull __byte_writableTo(size))
+#define __in_ecount(size) _SAL1_Source_(__in_ecount, (size), _In_reads_(size))
+#define __in_bcount(size) _SAL1_Source_(__in_bcount, (size), _In_reads_bytes_(size))
+#define __in_z _SAL1_Source_(__in_z, (), _In_z_)
+#define __in_ecount_z(size) _SAL1_Source_(__in_ecount_z, (size), _In_reads_z_(size))
+#define __in_bcount_z(size) _SAL1_Source_(__in_bcount_z, (size), __in_bcount(size) __pre __nullterminated)
+#define __in_nz _SAL1_Source_(__in_nz, (), __in)
+#define __in_ecount_nz(size) _SAL1_Source_(__in_ecount_nz, (size), __in_ecount(size))
+#define __in_bcount_nz(size) _SAL1_Source_(__in_bcount_nz, (size), __in_bcount(size))
+#define __out_ecount(size) _SAL1_Source_(__out_ecount, (size), _Out_writes_(size))
+#define __out_bcount(size) _SAL1_Source_(__out_bcount, (size), _Out_writes_bytes_(size))
+#define __out_ecount_part(size,length) _SAL1_Source_(__out_ecount_part, (size,length), _Out_writes_to_(size,length))
+#define __out_bcount_part(size,length) _SAL1_Source_(__out_bcount_part, (size,length), _Out_writes_bytes_to_(size,length))
+#define __out_ecount_full(size) _SAL1_Source_(__out_ecount_full, (size), _Out_writes_all_(size))
+#define __out_bcount_full(size) _SAL1_Source_(__out_bcount_full, (size), _Out_writes_bytes_all_(size))
+#define __out_z _SAL1_Source_(__out_z, (), __post __valid __refparam __post __nullterminated)
+#define __out_z_opt _SAL1_Source_(__out_z_opt, (), __post __valid __refparam __post __nullterminated __pre_except_maybenull)
+#define __out_ecount_z(size) _SAL1_Source_(__out_ecount_z, (size), __ecount(size) __post __valid __refparam __post __nullterminated)
+#define __out_bcount_z(size) _SAL1_Source_(__out_bcount_z, (size), __bcount(size) __post __valid __refparam __post __nullterminated)
+#define __out_ecount_part_z(size,length) _SAL1_Source_(__out_ecount_part_z, (size,length), __out_ecount_part(size,length) __post __nullterminated)
+#define __out_bcount_part_z(size,length) _SAL1_Source_(__out_bcount_part_z, (size,length), __out_bcount_part(size,length) __post __nullterminated)
+#define __out_ecount_full_z(size) _SAL1_Source_(__out_ecount_full_z, (size), __out_ecount_full(size) __post __nullterminated)
+#define __out_bcount_full_z(size) _SAL1_Source_(__out_bcount_full_z, (size), __out_bcount_full(size) __post __nullterminated)
+#define __out_nz _SAL1_Source_(__out_nz, (), __post __valid __refparam)
+#define __out_nz_opt _SAL1_Source_(__out_nz_opt, (), __post __valid __refparam __post_except_maybenull_)
+#define __out_ecount_nz(size) _SAL1_Source_(__out_ecount_nz, (size), __ecount(size) __post __valid __refparam)
+#define __out_bcount_nz(size) _SAL1_Source_(__out_bcount_nz, (size), __bcount(size) __post __valid __refparam)
+#define __inout _SAL1_Source_(__inout, (), _Inout_)
+#define __inout_ecount(size) _SAL1_Source_(__inout_ecount, (size), _Inout_updates_(size))
+#define __inout_bcount(size) _SAL1_Source_(__inout_bcount, (size), _Inout_updates_bytes_(size))
+#define __inout_ecount_part(size,length) _SAL1_Source_(__inout_ecount_part, (size,length), _Inout_updates_to_(size,length))
+#define __inout_bcount_part(size,length) _SAL1_Source_(__inout_bcount_part, (size,length), _Inout_updates_bytes_to_(size,length))
+#define __inout_ecount_full(size) _SAL1_Source_(__inout_ecount_full, (size), _Inout_updates_all_(size))
+#define __inout_bcount_full(size) _SAL1_Source_(__inout_bcount_full, (size), _Inout_updates_bytes_all_(size))
+#define __inout_z _SAL1_Source_(__inout_z, (), _Inout_z_)
+#define __inout_ecount_z(size) _SAL1_Source_(__inout_ecount_z, (size), _Inout_updates_z_(size))
+#define __inout_bcount_z(size) _SAL1_Source_(__inout_bcount_z, (size), __inout_bcount(size) __pre __nullterminated __post __nullterminated)
+#define __inout_nz _SAL1_Source_(__inout_nz, (), __inout)
+#define __inout_ecount_nz(size) _SAL1_Source_(__inout_ecount_nz, (size), __inout_ecount(size))
+#define __inout_bcount_nz(size) _SAL1_Source_(__inout_bcount_nz, (size), __inout_bcount(size))
+#define __ecount_opt(size) _SAL1_Source_(__ecount_opt, (size), __ecount(size) __pre_except_maybenull)
+#define __bcount_opt(size) _SAL1_Source_(__bcount_opt, (size), __bcount(size) __pre_except_maybenull)
+#define __in_opt _SAL1_Source_(__in_opt, (), _In_opt_)
+#define __in_ecount_opt(size) _SAL1_Source_(__in_ecount_opt, (size), _In_reads_opt_(size))
+#define __in_bcount_opt(size) _SAL1_Source_(__in_bcount_opt, (size), _In_reads_bytes_opt_(size))
+#define __in_z_opt _SAL1_Source_(__in_z_opt, (), _In_opt_z_)
+#define __in_ecount_z_opt(size) _SAL1_Source_(__in_ecount_z_opt, (size), __in_ecount_opt(size) __pre __nullterminated)
+#define __in_bcount_z_opt(size) _SAL1_Source_(__in_bcount_z_opt, (size), __in_bcount_opt(size) __pre __nullterminated)
+#define __in_nz_opt _SAL1_Source_(__in_nz_opt, (), __in_opt)
+#define __in_ecount_nz_opt(size) _SAL1_Source_(__in_ecount_nz_opt, (size), __in_ecount_opt(size))
+#define __in_bcount_nz_opt(size) _SAL1_Source_(__in_bcount_nz_opt, (size), __in_bcount_opt(size))
+#define __out_opt _SAL1_Source_(__out_opt, (), _Out_opt_)
+#define __out_ecount_opt(size) _SAL1_Source_(__out_ecount_opt, (size), _Out_writes_opt_(size))
+#define __out_bcount_opt(size) _SAL1_Source_(__out_bcount_opt, (size), _Out_writes_bytes_opt_(size))
+#define __out_ecount_part_opt(size,length) _SAL1_Source_(__out_ecount_part_opt, (size,length), __out_ecount_part(size,length) __pre_except_maybenull)
+#define __out_bcount_part_opt(size,length) _SAL1_Source_(__out_bcount_part_opt, (size,length), __out_bcount_part(size,length) __pre_except_maybenull)
+#define __out_ecount_full_opt(size) _SAL1_Source_(__out_ecount_full_opt, (size), __out_ecount_full(size) __pre_except_maybenull)
+#define __out_bcount_full_opt(size) _SAL1_Source_(__out_bcount_full_opt, (size), __out_bcount_full(size) __pre_except_maybenull)
+#define __out_ecount_z_opt(size) _SAL1_Source_(__out_ecount_z_opt, (size), __out_ecount_opt(size) __post __nullterminated)
+#define __out_bcount_z_opt(size) _SAL1_Source_(__out_bcount_z_opt, (size), __out_bcount_opt(size) __post __nullterminated)
+#define __out_ecount_part_z_opt(size,length) _SAL1_Source_(__out_ecount_part_z_opt, (size,length), __out_ecount_part_opt(size,length) __post __nullterminated)
+#define __out_bcount_part_z_opt(size,length) _SAL1_Source_(__out_bcount_part_z_opt, (size,length), __out_bcount_part_opt(size,length) __post __nullterminated)
+#define __out_ecount_full_z_opt(size) _SAL1_Source_(__out_ecount_full_z_opt, (size), __out_ecount_full_opt(size) __post __nullterminated)
+#define __out_bcount_full_z_opt(size) _SAL1_Source_(__out_bcount_full_z_opt, (size), __out_bcount_full_opt(size) __post __nullterminated)
+#define __out_ecount_nz_opt(size) _SAL1_Source_(__out_ecount_nz_opt, (size), __out_ecount_opt(size) __post __nullterminated)
+#define __out_bcount_nz_opt(size) _SAL1_Source_(__out_bcount_nz_opt, (size), __out_bcount_opt(size) __post __nullterminated)
+#define __inout_opt _SAL1_Source_(__inout_opt, (), _Inout_opt_)
+#define __inout_ecount_opt(size) _SAL1_Source_(__inout_ecount_opt, (size), __inout_ecount(size) __pre_except_maybenull)
+#define __inout_bcount_opt(size) _SAL1_Source_(__inout_bcount_opt, (size), __inout_bcount(size) __pre_except_maybenull)
+#define __inout_ecount_part_opt(size,length) _SAL1_Source_(__inout_ecount_part_opt, (size,length), __inout_ecount_part(size,length) __pre_except_maybenull)
+#define __inout_bcount_part_opt(size,length) _SAL1_Source_(__inout_bcount_part_opt, (size,length), __inout_bcount_part(size,length) __pre_except_maybenull)
+#define __inout_ecount_full_opt(size) _SAL1_Source_(__inout_ecount_full_opt, (size), __inout_ecount_full(size) __pre_except_maybenull)
+#define __inout_bcount_full_opt(size) _SAL1_Source_(__inout_bcount_full_opt, (size), __inout_bcount_full(size) __pre_except_maybenull)
+#define __inout_z_opt _SAL1_Source_(__inout_z_opt, (), __inout_opt __pre __nullterminated __post __nullterminated)
+#define __inout_ecount_z_opt(size) _SAL1_Source_(__inout_ecount_z_opt, (size), __inout_ecount_opt(size) __pre __nullterminated __post __nullterminated)
+#define __inout_ecount_z_opt(size) _SAL1_Source_(__inout_ecount_z_opt, (size), __inout_ecount_opt(size) __pre __nullterminated __post __nullterminated)
+#define __inout_bcount_z_opt(size) _SAL1_Source_(__inout_bcount_z_opt, (size), __inout_bcount_opt(size))
+#define __inout_nz_opt _SAL1_Source_(__inout_nz_opt, (), __inout_opt)
+#define __inout_ecount_nz_opt(size) _SAL1_Source_(__inout_ecount_nz_opt, (size), __inout_ecount_opt(size))
+#define __inout_bcount_nz_opt(size) _SAL1_Source_(__inout_bcount_nz_opt, (size), __inout_bcount_opt(size))
+#define __deref_ecount(size) _SAL1_Source_(__deref_ecount, (size), _Notref_ __ecount(1) __post _Notref_ __elem_readableTo(1) __post _Notref_ __deref _Notref_ __notnull __post __deref __elem_writableTo(size))
+#define __deref_bcount(size) _SAL1_Source_(__deref_bcount, (size), _Notref_ __ecount(1) __post _Notref_ __elem_readableTo(1) __post _Notref_ __deref _Notref_ __notnull __post __deref __byte_writableTo(size))
+#define __deref_out _SAL1_Source_(__deref_out, (), _Outptr_)
+#define __deref_out_ecount(size) _SAL1_Source_(__deref_out_ecount, (size), _Outptr_result_buffer_(size))
+#define __deref_out_bcount(size) _SAL1_Source_(__deref_out_bcount, (size), _Outptr_result_bytebuffer_(size))
+#define __deref_out_ecount_part(size,length) _SAL1_Source_(__deref_out_ecount_part, (size,length), _Outptr_result_buffer_to_(size,length))
+#define __deref_out_bcount_part(size,length) _SAL1_Source_(__deref_out_bcount_part, (size,length), _Outptr_result_bytebuffer_to_(size,length))
+#define __deref_out_ecount_full(size) _SAL1_Source_(__deref_out_ecount_full, (size), __deref_out_ecount_part(size,size))
+#define __deref_out_bcount_full(size) _SAL1_Source_(__deref_out_bcount_full, (size), __deref_out_bcount_part(size,size))
+#define __deref_out_z _SAL1_Source_(__deref_out_z, (), _Outptr_result_z_)
+#define __deref_out_ecount_z(size) _SAL1_Source_(__deref_out_ecount_z, (size), __deref_out_ecount(size) __post __deref __nullterminated)
+#define __deref_out_bcount_z(size) _SAL1_Source_(__deref_out_bcount_z, (size), __deref_out_bcount(size) __post __deref __nullterminated)
+#define __deref_out_nz _SAL1_Source_(__deref_out_nz, (), __deref_out)
+#define __deref_out_ecount_nz(size) _SAL1_Source_(__deref_out_ecount_nz, (size), __deref_out_ecount(size))
+#define __deref_out_bcount_nz(size) _SAL1_Source_(__deref_out_bcount_nz, (size), __deref_out_ecount(size))
+#define __deref_inout _SAL1_Source_(__deref_inout, (), _Notref_ __notnull _Notref_ __elem_readableTo(1) __pre __deref __valid __post _Notref_ __deref __valid __refparam)
+#define __deref_inout_z _SAL1_Source_(__deref_inout_z, (), __deref_inout __pre __deref __nullterminated __post _Notref_ __deref __nullterminated)
+#define __deref_inout_ecount(size) _SAL1_Source_(__deref_inout_ecount, (size), __deref_inout __pre __deref __elem_writableTo(size) __post _Notref_ __deref __elem_writableTo(size))
+#define __deref_inout_bcount(size) _SAL1_Source_(__deref_inout_bcount, (size), __deref_inout __pre __deref __byte_writableTo(size) __post _Notref_ __deref __byte_writableTo(size))
+#define __deref_inout_ecount_part(size,length) _SAL1_Source_(__deref_inout_ecount_part, (size,length), __deref_inout_ecount(size) __pre __deref __elem_readableTo(length) __post __deref __elem_readableTo(length))
+#define __deref_inout_bcount_part(size,length) _SAL1_Source_(__deref_inout_bcount_part, (size,length), __deref_inout_bcount(size) __pre __deref __byte_readableTo(length) __post __deref __byte_readableTo(length))
+#define __deref_inout_ecount_full(size) _SAL1_Source_(__deref_inout_ecount_full, (size), __deref_inout_ecount_part(size,size))
+#define __deref_inout_bcount_full(size) _SAL1_Source_(__deref_inout_bcount_full, (size), __deref_inout_bcount_part(size,size))
+#define __deref_inout_ecount_z(size) _SAL1_Source_(__deref_inout_ecount_z, (size), __deref_inout_ecount(size) __pre __deref __nullterminated __post __deref __nullterminated)
+#define __deref_inout_bcount_z(size) _SAL1_Source_(__deref_inout_bcount_z, (size), __deref_inout_bcount(size) __pre __deref __nullterminated __post __deref __nullterminated)
+#define __deref_inout_nz _SAL1_Source_(__deref_inout_nz, (), __deref_inout)
+#define __deref_inout_ecount_nz(size) _SAL1_Source_(__deref_inout_ecount_nz, (size), __deref_inout_ecount(size))
+#define __deref_inout_bcount_nz(size) _SAL1_Source_(__deref_inout_bcount_nz, (size), __deref_inout_ecount(size))
+#define __deref_ecount_opt(size) _SAL1_Source_(__deref_ecount_opt, (size), __deref_ecount(size) __post_deref_except_maybenull)
+#define __deref_bcount_opt(size) _SAL1_Source_(__deref_bcount_opt, (size), __deref_bcount(size) __post_deref_except_maybenull)
+#define __deref_out_opt _SAL1_Source_(__deref_out_opt, (), __deref_out __post_deref_except_maybenull)
+#define __deref_out_ecount_opt(size) _SAL1_Source_(__deref_out_ecount_opt, (size), __deref_out_ecount(size) __post_deref_except_maybenull)
+#define __deref_out_bcount_opt(size) _SAL1_Source_(__deref_out_bcount_opt, (size), __deref_out_bcount(size) __post_deref_except_maybenull)
+#define __deref_out_ecount_part_opt(size,length) _SAL1_Source_(__deref_out_ecount_part_opt, (size,length), __deref_out_ecount_part(size,length) __post_deref_except_maybenull)
+#define __deref_out_bcount_part_opt(size,length) _SAL1_Source_(__deref_out_bcount_part_opt, (size,length), __deref_out_bcount_part(size,length) __post_deref_except_maybenull)
+#define __deref_out_ecount_full_opt(size) _SAL1_Source_(__deref_out_ecount_full_opt, (size), __deref_out_ecount_full(size) __post_deref_except_maybenull)
+#define __deref_out_bcount_full_opt(size) _SAL1_Source_(__deref_out_bcount_full_opt, (size), __deref_out_bcount_full(size) __post_deref_except_maybenull)
+#define __deref_out_z_opt _SAL1_Source_(__deref_out_z_opt, (), _Outptr_result_maybenull_z_)
+#define __deref_out_ecount_z_opt(size) _SAL1_Source_(__deref_out_ecount_z_opt, (size), __deref_out_ecount_opt(size) __post __deref __nullterminated)
+#define __deref_out_bcount_z_opt(size) _SAL1_Source_(__deref_out_bcount_z_opt, (size), __deref_out_bcount_opt(size) __post __deref __nullterminated)
+#define __deref_out_nz_opt _SAL1_Source_(__deref_out_nz_opt, (), __deref_out_opt)
+#define __deref_out_ecount_nz_opt(size) _SAL1_Source_(__deref_out_ecount_nz_opt, (size), __deref_out_ecount_opt(size))
+#define __deref_out_bcount_nz_opt(size) _SAL1_Source_(__deref_out_bcount_nz_opt, (size), __deref_out_bcount_opt(size))
+#define __deref_inout_opt _SAL1_Source_(__deref_inout_opt, (), __deref_inout __pre_deref_except_maybenull __post_deref_except_maybenull)
+#define __deref_inout_ecount_opt(size) _SAL1_Source_(__deref_inout_ecount_opt, (size), __deref_inout_ecount(size) __pre_deref_except_maybenull __post_deref_except_maybenull)
+#define __deref_inout_bcount_opt(size) _SAL1_Source_(__deref_inout_bcount_opt, (size), __deref_inout_bcount(size) __pre_deref_except_maybenull __post_deref_except_maybenull)
+#define __deref_inout_ecount_part_opt(size,length) _SAL1_Source_(__deref_inout_ecount_part_opt, (size,length), __deref_inout_ecount_part(size,length) __pre_deref_except_maybenull __post_deref_except_maybenull)
+#define __deref_inout_bcount_part_opt(size,length) _SAL1_Source_(__deref_inout_bcount_part_opt, (size,length), __deref_inout_bcount_part(size,length) __pre_deref_except_maybenull __post_deref_except_maybenull)
+#define __deref_inout_ecount_full_opt(size) _SAL1_Source_(__deref_inout_ecount_full_opt, (size), __deref_inout_ecount_full(size) __pre_deref_except_maybenull __post_deref_except_maybenull)
+#define __deref_inout_bcount_full_opt(size) _SAL1_Source_(__deref_inout_bcount_full_opt, (size), __deref_inout_bcount_full(size) __pre_deref_except_maybenull __post_deref_except_maybenull)
+#define __deref_inout_z_opt _SAL1_Source_(__deref_inout_z_opt, (), __deref_inout_opt __pre __deref __nullterminated __post __deref __nullterminated)
+#define __deref_inout_ecount_z_opt(size) _SAL1_Source_(__deref_inout_ecount_z_opt, (size), __deref_inout_ecount_opt(size) __pre __deref __nullterminated __post __deref __nullterminated)
+#define __deref_inout_bcount_z_opt(size) _SAL1_Source_(__deref_inout_bcount_z_opt, (size), __deref_inout_bcount_opt(size) __pre __deref __nullterminated __post __deref __nullterminated)
+#define __deref_inout_nz_opt _SAL1_Source_(__deref_inout_nz_opt, (), __deref_inout_opt)
+#define __deref_inout_ecount_nz_opt(size) _SAL1_Source_(__deref_inout_ecount_nz_opt, (size), __deref_inout_ecount_opt(size))
+#define __deref_inout_bcount_nz_opt(size) _SAL1_Source_(__deref_inout_bcount_nz_opt, (size), __deref_inout_bcount_opt(size))
+#define __deref_opt_ecount(size) _SAL1_Source_(__deref_opt_ecount, (size), __deref_ecount(size) __pre_except_maybenull)
+#define __deref_opt_bcount(size) _SAL1_Source_(__deref_opt_bcount, (size), __deref_bcount(size) __pre_except_maybenull)
+#define __deref_opt_out _SAL1_Source_(__deref_opt_out, (), _Outptr_opt_)
+#define __deref_opt_out_z _SAL1_Source_(__deref_opt_out_z, (), _Outptr_opt_result_z_)
+#define __deref_opt_out_ecount(size) _SAL1_Source_(__deref_opt_out_ecount, (size), __deref_out_ecount(size) __pre_except_maybenull)
+#define __deref_opt_out_bcount(size) _SAL1_Source_(__deref_opt_out_bcount, (size), __deref_out_bcount(size) __pre_except_maybenull)
+#define __deref_opt_out_ecount_part(size,length) _SAL1_Source_(__deref_opt_out_ecount_part, (size,length), __deref_out_ecount_part(size,length) __pre_except_maybenull)
+#define __deref_opt_out_bcount_part(size,length) _SAL1_Source_(__deref_opt_out_bcount_part, (size,length), __deref_out_bcount_part(size,length) __pre_except_maybenull)
+#define __deref_opt_out_ecount_full(size) _SAL1_Source_(__deref_opt_out_ecount_full, (size), __deref_out_ecount_full(size) __pre_except_maybenull)
+#define __deref_opt_out_bcount_full(size) _SAL1_Source_(__deref_opt_out_bcount_full, (size), __deref_out_bcount_full(size) __pre_except_maybenull)
+#define __deref_opt_inout _SAL1_Source_(__deref_opt_inout, (), _Inout_opt_)
+#define __deref_opt_inout_ecount(size) _SAL1_Source_(__deref_opt_inout_ecount, (size), __deref_inout_ecount(size) __pre_except_maybenull)
+#define __deref_opt_inout_bcount(size) _SAL1_Source_(__deref_opt_inout_bcount, (size), __deref_inout_bcount(size) __pre_except_maybenull)
+#define __deref_opt_inout_ecount_part(size,length) _SAL1_Source_(__deref_opt_inout_ecount_part, (size,length), __deref_inout_ecount_part(size,length) __pre_except_maybenull)
+#define __deref_opt_inout_bcount_part(size,length) _SAL1_Source_(__deref_opt_inout_bcount_part, (size,length), __deref_inout_bcount_part(size,length) __pre_except_maybenull)
+#define __deref_opt_inout_ecount_full(size) _SAL1_Source_(__deref_opt_inout_ecount_full, (size), __deref_inout_ecount_full(size) __pre_except_maybenull)
+#define __deref_opt_inout_bcount_full(size) _SAL1_Source_(__deref_opt_inout_bcount_full, (size), __deref_inout_bcount_full(size) __pre_except_maybenull)
+#define __deref_opt_inout_z _SAL1_Source_(__deref_opt_inout_z, (), __deref_opt_inout __pre __deref __nullterminated __post __deref __nullterminated)
+#define __deref_opt_inout_ecount_z(size) _SAL1_Source_(__deref_opt_inout_ecount_z, (size), __deref_opt_inout_ecount(size) __pre __deref __nullterminated __post __deref __nullterminated)
+#define __deref_opt_inout_bcount_z(size) _SAL1_Source_(__deref_opt_inout_bcount_z, (size), __deref_opt_inout_bcount(size) __pre __deref __nullterminated __post __deref __nullterminated)
+#define __deref_opt_inout_nz _SAL1_Source_(__deref_opt_inout_nz, (), __deref_opt_inout)
+#define __deref_opt_inout_ecount_nz(size) _SAL1_Source_(__deref_opt_inout_ecount_nz, (size), __deref_opt_inout_ecount(size))
+#define __deref_opt_inout_bcount_nz(size) _SAL1_Source_(__deref_opt_inout_bcount_nz, (size), __deref_opt_inout_bcount(size))
+#define __deref_opt_ecount_opt(size) _SAL1_Source_(__deref_opt_ecount_opt, (size), __deref_ecount_opt(size) __pre_except_maybenull)
+#define __deref_opt_bcount_opt(size) _SAL1_Source_(__deref_opt_bcount_opt, (size), __deref_bcount_opt(size) __pre_except_maybenull)
+#define __deref_opt_out_opt _SAL1_Source_(__deref_opt_out_opt, (), _Outptr_opt_result_maybenull_)
+#define __deref_opt_out_ecount_opt(size) _SAL1_Source_(__deref_opt_out_ecount_opt, (size), __deref_out_ecount_opt(size) __pre_except_maybenull)
+#define __deref_opt_out_bcount_opt(size) _SAL1_Source_(__deref_opt_out_bcount_opt, (size), __deref_out_bcount_opt(size) __pre_except_maybenull)
+#define __deref_opt_out_ecount_part_opt(size,length) _SAL1_Source_(__deref_opt_out_ecount_part_opt, (size,length), __deref_out_ecount_part_opt(size,length) __pre_except_maybenull)
+#define __deref_opt_out_bcount_part_opt(size,length) _SAL1_Source_(__deref_opt_out_bcount_part_opt, (size,length), __deref_out_bcount_part_opt(size,length) __pre_except_maybenull)
+#define __deref_opt_out_ecount_full_opt(size) _SAL1_Source_(__deref_opt_out_ecount_full_opt, (size), __deref_out_ecount_full_opt(size) __pre_except_maybenull)
+#define __deref_opt_out_bcount_full_opt(size) _SAL1_Source_(__deref_opt_out_bcount_full_opt, (size), __deref_out_bcount_full_opt(size) __pre_except_maybenull)
+#define __deref_opt_out_z_opt _SAL1_Source_(__deref_opt_out_z_opt, (), __post __deref __valid __refparam __pre_except_maybenull __pre_deref_except_maybenull __post_deref_except_maybenull __post __deref __nullterminated)
+#define __deref_opt_out_ecount_z_opt(size) _SAL1_Source_(__deref_opt_out_ecount_z_opt, (size), __deref_opt_out_ecount_opt(size) __post __deref __nullterminated)
+#define __deref_opt_out_bcount_z_opt(size) _SAL1_Source_(__deref_opt_out_bcount_z_opt, (size), __deref_opt_out_bcount_opt(size) __post __deref __nullterminated)
+#define __deref_opt_out_nz_opt _SAL1_Source_(__deref_opt_out_nz_opt, (), __deref_opt_out_opt)
+#define __deref_opt_out_ecount_nz_opt(size) _SAL1_Source_(__deref_opt_out_ecount_nz_opt, (size), __deref_opt_out_ecount_opt(size))
+#define __deref_opt_out_bcount_nz_opt(size) _SAL1_Source_(__deref_opt_out_bcount_nz_opt, (size), __deref_opt_out_bcount_opt(size))
+#define __deref_opt_inout_opt _SAL1_Source_(__deref_opt_inout_opt, (), __deref_inout_opt __pre_except_maybenull)
+#define __deref_opt_inout_ecount_opt(size) _SAL1_Source_(__deref_opt_inout_ecount_opt, (size), __deref_inout_ecount_opt(size) __pre_except_maybenull)
+#define __deref_opt_inout_bcount_opt(size) _SAL1_Source_(__deref_opt_inout_bcount_opt, (size), __deref_inout_bcount_opt(size) __pre_except_maybenull)
+#define __deref_opt_inout_ecount_part_opt(size,length) _SAL1_Source_(__deref_opt_inout_ecount_part_opt, (size,length), __deref_inout_ecount_part_opt(size,length) __pre_except_maybenull)
+#define __deref_opt_inout_bcount_part_opt(size,length) _SAL1_Source_(__deref_opt_inout_bcount_part_opt, (size,length), __deref_inout_bcount_part_opt(size,length) __pre_except_maybenull)
+#define __deref_opt_inout_ecount_full_opt(size) _SAL1_Source_(__deref_opt_inout_ecount_full_opt, (size), __deref_inout_ecount_full_opt(size) __pre_except_maybenull)
+#define __deref_opt_inout_bcount_full_opt(size) _SAL1_Source_(__deref_opt_inout_bcount_full_opt, (size), __deref_inout_bcount_full_opt(size) __pre_except_maybenull)
+#define __deref_opt_inout_z_opt _SAL1_Source_(__deref_opt_inout_z_opt, (), __deref_opt_inout_opt __pre __deref __nullterminated __post __deref __nullterminated)
+#define __deref_opt_inout_ecount_z_opt(size) _SAL1_Source_(__deref_opt_inout_ecount_z_opt, (size), __deref_opt_inout_ecount_opt(size) __pre __deref __nullterminated __post __deref __nullterminated)
+#define __deref_opt_inout_bcount_z_opt(size) _SAL1_Source_(__deref_opt_inout_bcount_z_opt, (size), __deref_opt_inout_bcount_opt(size) __pre __deref __nullterminated __post __deref __nullterminated)
+#define __deref_opt_inout_nz_opt _SAL1_Source_(__deref_opt_inout_nz_opt, (), __deref_opt_inout_opt)
+#define __deref_opt_inout_ecount_nz_opt(size) _SAL1_Source_(__deref_opt_inout_ecount_nz_opt, (size), __deref_opt_inout_ecount_opt(size))
+#define __deref_opt_inout_bcount_nz_opt(size) _SAL1_Source_(__deref_opt_inout_bcount_nz_opt, (size), __deref_opt_inout_bcount_opt(size))
+
+/*
+-------------------------------------------------------------------------------
+Advanced Annotation Definitions
+
+Any of these may be used to directly annotate functions, and may be used in
+combination with each other or with regular buffer macros. For an explanation
+of each annotation, see the advanced annotations section.
+-------------------------------------------------------------------------------
+*/
+
+#define __success(expr) _Success_(expr)
+#define __nullterminated _Null_terminated_
+#define __nullnullterminated
+#define __reserved _SAL1_Source_(__reserved, (), _Reserved_)
+#define __checkReturn _SAL1_Source_(__checkReturn, (), _Check_return_)
+#define __typefix(ctype) _SAL1_Source_(__typefix, (ctype), __inner_typefix(ctype))
+#define __override __inner_override
+#define __callback __inner_callback
+#define __format_string _Printf_format_string_
+#define __blocksOn(resource) __inner_blocksOn(resource)
+#define __control_entrypoint(category) __inner_control_entrypoint(category)
+#define __data_entrypoint(category) __inner_data_entrypoint(category)
+#define __useHeader _Use_decl_anno_impl_
+#define __on_failure(annotes) _On_failure_impl_(annotes _SAL_nop_impl_)
+
+#ifndef __fallthrough // [
+ __inner_fallthrough_dec
+ #define __fallthrough __inner_fallthrough
+#endif // ]
+
+#ifndef __analysis_assume // [
+#ifdef _PREFAST_ // [
+#define __analysis_assume(expr) __assume(expr)
+#else // ][
+#define __analysis_assume(expr)
+#endif // ]
+#endif // ]
+
+#ifndef _Analysis_assume_ // [
+#ifdef _PREFAST_ // [
+#define _Analysis_assume_(expr) __assume(expr)
+#else // ][
+#define _Analysis_assume_(expr)
+#endif // ]
+#endif // ]
+
+#define _Analysis_noreturn_ _SAL2_Source_(_Analysis_noreturn_, (), _SA_annotes0(SAL_terminates))
+
+#ifdef _PREFAST_ // [
+__inline __nothrow
+void __AnalysisAssumeNullterminated(_Post_ __nullterminated void *p);
+
+#define _Analysis_assume_nullterminated_(x) __AnalysisAssumeNullterminated(x)
+#else // ][
+#define _Analysis_assume_nullterminated_(x)
+#endif // ]
+
+//
+// Set the analysis mode (global flags to analysis).
+// They take effect at the point of declaration; use at global scope
+// as a declaration.
+//
+
+// Synthesize a unique symbol.
+#define ___MKID(x, y) x ## y
+#define __MKID(x, y) ___MKID(x, y)
+#define __GENSYM(x) __MKID(x, __COUNTER__)
+
+__ANNOTATION(SAL_analysisMode(__AuToQuOtE __In_impl_ char *mode);)
+
+#define _Analysis_mode_impl_(mode) _SA_annotes1(SAL_analysisMode, #mode)
+
+#define _Analysis_mode_(mode) \
+ typedef _Analysis_mode_impl_(mode) int \
+ __GENSYM(__prefast_analysis_mode_flag);
+
+// The following are predefined:
+// _Analysis_operator_new_throw_ (operator new throws)
+// _Analysis_operator_new_null_ (operator new returns null)
+// _Analysis_operator_new_never_fails_ (operator new never fails)
+//
+
+// Function class annotations.
+__ANNOTATION(SAL_functionClassNew(__In_impl_ char*);)
+__PRIMOP(int, _In_function_class_(__In_impl_ char*);)
+#define _In_function_class_(x) _In_function_class_(#x)
+
+#define _Function_class_(x) _SA_annotes1(SAL_functionClassNew, #x)
+
+/*
+ * interlocked operand used in interlocked instructions
+ */
+//#define _Interlocked_operand_ _Pre_ _SA_annotes0(SAL_interlocked)
+
+#define _Enum_is_bitflag_ _SA_annotes0(SAL_enumIsBitflag)
+#define _Strict_type_match_ _SA_annotes0(SAL_strictType2)
+
+#define _Maybe_raises_SEH_exception_ _Pre_ _SA_annotes1(SAL_inTry,__yes)
+#define _Raises_SEH_exception_ _Group_(_Maybe_raises_SEH_exception_ _Analysis_noreturn_)
+
+#ifdef __cplusplus // [
+}
+#endif // ]
+
+// Rotor doesn't need concurrency sal.
+// #include <ConcurrencySal.h>
+
diff --git a/src/pal/inc/rt/servprov.h b/src/pal/inc/rt/servprov.h
new file mode 100644
index 0000000000..4dfffb1298
--- /dev/null
+++ b/src/pal/inc/rt/servprov.h
@@ -0,0 +1,32 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+//
+// ===========================================================================
+// File: servprov.h
+//
+// ===========================================================================
+// simplified servprov.h for PAL
+
+#include "rpc.h"
+#include "rpcndr.h"
+
+#include "unknwn.h"
+
+#ifndef __IServiceProvider_INTERFACE_DEFINED__
+#define __IServiceProvider_INTERFACE_DEFINED__
+
+// 6d5140c1-7436-11ce-8034-00aa006009fa
+EXTERN_C const IID IID_IServiceProvider;
+
+interface IServiceProvider : public IUnknown
+{
+ virtual /* [local] */ HRESULT STDMETHODCALLTYPE QueryService(
+ /* [in] */ REFGUID guidService,
+ /* [in] */ REFIID riid,
+ /* [out] */ void **ppvObject) = 0;
+};
+
+#endif // __IServiceProvider_INTERFACE_DEFINED__
diff --git a/src/pal/inc/rt/share.h b/src/pal/inc/rt/share.h
new file mode 100644
index 0000000000..5401fabc13
--- /dev/null
+++ b/src/pal/inc/rt/share.h
@@ -0,0 +1,5 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#include "palrt.h"
diff --git a/src/pal/inc/rt/shellapi.h b/src/pal/inc/rt/shellapi.h
new file mode 100644
index 0000000000..5c20f4f847
--- /dev/null
+++ b/src/pal/inc/rt/shellapi.h
@@ -0,0 +1,13 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+//
+// ===========================================================================
+// File: shellapi.h
+//
+// ===========================================================================
+// dummy shellapi.h for PAL
+
+#include "palrt.h"
diff --git a/src/pal/inc/rt/shlobj.h b/src/pal/inc/rt/shlobj.h
new file mode 100644
index 0000000000..ba60876db4
--- /dev/null
+++ b/src/pal/inc/rt/shlobj.h
@@ -0,0 +1,13 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+//
+// ===========================================================================
+// File: shlobj.h
+//
+// ===========================================================================
+// dummy shlobj.h for PAL
+
+#include "palrt.h"
diff --git a/src/pal/inc/rt/shlwapi.h b/src/pal/inc/rt/shlwapi.h
new file mode 100644
index 0000000000..d284fd690f
--- /dev/null
+++ b/src/pal/inc/rt/shlwapi.h
@@ -0,0 +1,13 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+//
+// ===========================================================================
+// File: shlwapi.h
+//
+// ===========================================================================
+// dummy shlwapi.h for PAL
+
+#include "palrt.h"
diff --git a/src/pal/inc/rt/specstrings.h b/src/pal/inc/rt/specstrings.h
new file mode 100644
index 0000000000..214d4190de
--- /dev/null
+++ b/src/pal/inc/rt/specstrings.h
@@ -0,0 +1,536 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+
+//
+#ifndef SPECSTRINGS_H
+#define SPECSTRINGS_H
+
+/***
+*specstrings.h - support for markers for documenting the semantics of APIs
+*
+
+*
+* [Public]
+****/
+
+/*************************************************************************
+* See specstrings_strict.h for documentation of all user visible macros.
+*************************************************************************/
+
+#if _MSC_VER
+#pragma once
+#endif
+
+#if !defined(_SAL_VERSION_SAL2)
+
+ #if defined(__BUILDMACHINE__) || defined(_USE_SAL2_ONLY)
+ #define _SAL_VERSION_SAL2(_A) SAL_2_Clean_Violation_using ## _A
+ #else
+ #define _SAL_VERSION_SAL2(_A)
+ #endif
+
+ #ifdef _USE_SAL2_ONLY
+ #define _SAL2_STRICT
+ #define _SAL_VERSION_CHECK(_A) _SAL_VERSION_SAL2(_A)
+ #else
+ #define _SAL_VERSION_CHECK(_A)
+ #endif
+
+ #ifndef SAL_VERSION_CHECK
+ #define SAL_VERSION_CHECK(_A) _SAL_VERSION_CHECK(_A)
+ #define SAL_VERSION_SAL2(_A) _SAL_VERSION_SAL2(_A)
+ #endif
+
+#endif
+
+#include <sal.h>
+
+#ifndef __SAL_H_FULL_VER
+#define __SAL_H_FULL_VER 140050727
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* version specific fixes to bring sal.h upto date */
+#if __SAL_H_FULL_VER <= 140050727
+
+#if !defined(__midl) && defined(_PREFAST_) && _MSC_VER >= 1000 // [
+
+/* Missing from RTM sal.h */
+#define __inner_bound _SA_annotes0(SAL_bound)
+#define __inner_range(lb,ub) _SA_annotes2(SAL_range,lb,ub)
+#define __inner_assume_bound_dec __inline __nothrow void __AssumeBoundInt(_Post_ __inner_bound int i) {i;}
+#define __inner_assume_bound(i) __AssumeBoundInt(i);
+#define __inner_allocator _SA_annotes0(SAL_allocator)
+
+#define __static_context(ctx, annotes) \
+ _SA_annotes1(SAL_context,ctx) _Group_(__nop_impl(annotes))
+
+#define __failure(x) __static_context(SAL_return_convention, \
+ _SA_annotes1(SAL_failure,x))
+
+__ANNOTATION(SAL_valueUndefined());
+#define __valueUndefined _SA_annotes0(SAL_valueUndefined)
+
+enum __SAL_failureKind{__failureUnspecified = 0, __failureUndefined = 1};
+
+__ANNOTATION(SAL_failureDefault(enum __SAL_failureKind));
+#define __failureDefault(kind) __static_context(SAL_return_convention, \
+ _SA_annotes1(SAL_failureDefault,kind))
+
+#else // ][
+
+#define __inner_bound
+#define __inner_range(lb,ub)
+#define __inner_assume_bound_dec
+#define __inner_assume_bound(i)
+#define __inner_allocator
+
+#define __static_context(ctx, annotes)
+#define __failure(x)
+#define __valueUndefined
+#define __failureDefault(x)
+
+#endif // ]
+
+#define __xcount(size) __notnull __inexpressible_writableTo(size)
+#define __in_xcount(size) __in _Pre_ __inexpressible_readableTo(size)
+#define __out_xcount(size) __xcount(size) _Post_ __valid __refparam
+#define __out_xcount_part(size,length) __out_xcount(size) _Post_ __inexpressible_readableTo(length)
+#define __out_xcount_full(size) __out_xcount_part(size,size)
+#define __inout_xcount(size) __out_xcount(size) _Pre_ __valid
+#define __inout_xcount_part(size,length) __out_xcount_part(size,length) _Pre_ __valid _Pre_ __inexpressible_readableTo(length)
+#define __inout_xcount_full(size) __inout_xcount_part(size,size)
+#define __xcount_opt(size) __xcount(size) __exceptthat __maybenull
+#define __in_xcount_opt(size) __in_xcount(size) __exceptthat __maybenull
+#define __out_xcount_opt(size) __out_xcount(size) __exceptthat __maybenull
+#define __out_xcount_part_opt(size,length) __out_xcount_part(size,length) __exceptthat __maybenull
+#define __out_xcount_full_opt(size) __out_xcount_full(size) __exceptthat __maybenull
+#define __inout_xcount_opt(size) __inout_xcount(size) __exceptthat __maybenull
+#define __inout_xcount_part_opt(size,length) __inout_xcount_part(size,length) __exceptthat __maybenull
+#define __inout_xcount_full_opt(size) __inout_xcount_full(size) __exceptthat __maybenull
+#define __deref_xcount(size) __ecount(1) _Post_ __elem_readableTo(1) _Post_ __deref __notnull _Post_ __deref __inexpressible_writableTo(size)
+#define __deref_in __in _Pre_ __deref __deref __readonly
+#define __deref_in_ecount(size) __deref_in _Pre_ __deref __elem_readableTo(size)
+#define __deref_in_bcount(size) __deref_in _Pre_ __deref __byte_readableTo(size)
+#define __deref_in_xcount(size) __deref_in _Pre_ __deref __inexpressible_readableTo(size)
+#define __deref_out_xcount(size) __deref_xcount(size) _Post_ __deref __valid __refparam
+#define __deref_out_xcount_part(size,length) __deref_out_xcount(size) _Post_ __deref __inexpressible_readableTo(length)
+#define __deref_out_xcount_full(size) __deref_out_xcount_part(size,size)
+#define __deref_out_xcount(size) __deref_xcount(size) _Post_ __deref __valid __refparam
+#define __inout_xcount_opt(size) __inout_xcount(size) __exceptthat __maybenull
+#define __inout_xcount_part_opt(size,length) __inout_xcount_part(size,length) __exceptthat __maybenull
+#define __inout_xcount_full_opt(size) __inout_xcount_full(size) __exceptthat __maybenull
+#define __deref_xcount(size) __ecount(1) _Post_ __elem_readableTo(1) _Post_ __deref __notnull _Post_ __deref __inexpressible_writableTo(size)
+#define __deref_in __in _Pre_ __deref __deref __readonly
+#define __deref_in_ecount(size) __deref_in _Pre_ __deref __elem_readableTo(size)
+#define __deref_in_bcount(size) __deref_in _Pre_ __deref __byte_readableTo(size)
+#define __deref_in_xcount(size) __deref_in _Pre_ __deref __inexpressible_readableTo(size)
+#define __deref_out_xcount(size) __deref_xcount(size) _Post_ __deref __valid __refparam
+#define __deref_out_xcount_part(size,length) __deref_out_xcount(size) _Post_ __deref __inexpressible_readableTo(length)
+#define __deref_out_xcount_full(size) __deref_out_xcount_part(size,size)
+#define __deref_out_xcount(size) __deref_xcount(size) _Post_ __deref __valid __refparam
+#define __deref_inout_xcount(size) __deref_inout _Pre_ __deref __inexpressible_writableTo(size) _Post_ __deref __inexpressible_writableTo(size)
+#define __deref_inout_xcount_part(size,length) __deref_inout_xcount(size) _Pre_ __deref __inexpressible_readableTo(length) _Post_ __deref __inexpressible_readableTo(length)
+#define __deref_inout_xcount_full(size) __deref_inout_xcount_part(size,size)
+#define __deref_xcount_opt(size) __deref_xcount(size) _Post_ __deref __exceptthat __maybenull
+#define __deref_in_opt __deref_in _Pre_ __deref __exceptthat __maybenull
+#define __deref_in_opt_out __deref_inout _Pre_ __deref __exceptthat __maybenull _Post_ __deref __notnull
+#define __deref_in_ecount_opt(size) __deref_in_ecount(size) _Pre_ __deref __exceptthat __maybenull
+#define __deref_in_bcount_opt(size) __deref_in_bcount(size) _Pre_ __deref __exceptthat __maybenull
+#define __deref_in_xcount_opt(size) __deref_in_xcount(size) _Pre_ __deref __exceptthat __maybenull
+#define __deref_out_xcount_opt(size) __deref_out_xcount(size) _Post_ __deref __exceptthat __maybenull
+#define __deref_out_xcount_part_opt(size,length) __deref_out_xcount_part(size,length) _Post_ __deref __exceptthat __maybenull
+#define __deref_out_xcount_full_opt(size) __deref_out_xcount_full(size) _Post_ __deref __exceptthat __maybenull
+#define __deref_inout_xcount_opt(size) __deref_inout_xcount(size) _Pre_ __deref __exceptthat __maybenull _Post_ __deref __exceptthat __maybenull
+#define __deref_inout_xcount_part_opt(size,length) __deref_inout_xcount_part(size,length) _Pre_ __deref __exceptthat __maybenull _Post_ __deref __exceptthat __maybenull
+#define __deref_inout_xcount_full_opt(size) __deref_inout_xcount_full(size) _Pre_ __deref __exceptthat __maybenull _Post_ __deref __exceptthat __maybenull
+#define __deref_opt_xcount(size) __deref_xcount(size) __exceptthat __maybenull
+#define __deref_opt_in __deref_in __exceptthat __maybenull
+#define __deref_opt_in_ecount(size) __deref_in_ecount(size) __exceptthat __maybenull
+#define __deref_opt_in_bcount(size) __deref_in_bcount(size) __exceptthat __maybenull
+#define __deref_opt_in_xcount(size) __deref_in_xcount(size) __exceptthat __maybenull
+#define __deref_opt_out_xcount(size) __deref_out_xcount(size) __exceptthat __maybenull
+#define __deref_opt_out_xcount_part(size,length) __deref_out_xcount_part(size,length) __exceptthat __maybenull
+#define __deref_opt_out_xcount_full(size) __deref_out_xcount_full(size) __exceptthat __maybenull
+#define __deref_opt_inout_xcount(size) __deref_inout_xcount(size) __exceptthat __maybenull
+#define __deref_opt_inout_xcount_part(size,length) __deref_inout_xcount_part(size,length) __exceptthat __maybenull
+#define __deref_opt_inout_xcount_full(size) __deref_inout_xcount_full(size) __exceptthat __maybenull
+#define __deref_opt_xcount_opt(size) __deref_xcount_opt(size) __exceptthat __maybenull
+#define __deref_opt_in_opt __deref_in_opt __exceptthat __maybenull
+#define __deref_opt_in_ecount_opt(size) __deref_in_ecount_opt(size) __exceptthat __maybenull
+#define __deref_opt_in_bcount_opt(size) __deref_in_bcount_opt(size) __exceptthat __maybenull
+#define __deref_opt_in_xcount_opt(size) __deref_in_xcount_opt(size) __exceptthat __maybenull
+#define __deref_opt_out_xcount_opt(size) __deref_out_xcount_opt(size) __exceptthat __maybenull
+#define __deref_opt_out_xcount_part_opt(size,length) __deref_out_xcount_part_opt(size,length) __exceptthat __maybenull
+#define __deref_opt_out_xcount_full_opt(size) __deref_out_xcount_full_opt(size) __exceptthat __maybenull
+#define __deref_opt_inout_xcount_opt(size) __deref_inout_xcount_opt(size) __exceptthat __maybenull
+#define __deref_opt_inout_xcount_part_opt(size,length) __deref_inout_xcount_part_opt(size,length) __exceptthat __maybenull
+#define __deref_opt_inout_xcount_full_opt(size) __deref_inout_xcount_full_opt(size) __exceptthat __maybenull
+
+#define __deref_in_ecount_iterator(size, incr) __inout _Pre_ __deref __elem_readableTo(size) __deref_out_range(==, _Old_(*_Curr_) + incr)
+#define __deref_out_ecount_iterator(size, incr) __inout _Pre_ __deref __elem_writableTo(size) __deref_out_range(==, _Old_(*_Curr_) + incr)
+#define __deref_inout_ecount_iterator(size, incr) __inout _Pre_ __deref __elem_readableTo(size) _Pre_ __deref __elem_writableTo(size) __deref_out_range(==, _Old_(*_Curr_) + incr)
+
+#define __post_bcount(size) _Post_ __byte_writableTo(size)
+#define __post_ecount(size) _Post_ __elem_writableTo(size)
+
+#define __deref_realloc_bcount(insize, outsize) __inout _Pre_ __deref __byte_readableTo(insize) _Post_ __deref __byte_writableTo(outsize)
+
+/* __in_ecount_or_z(c) specifies semantics like strncmp, where a string
+ * parameter is either null terminated, or valid up to c elements.
+ */
+#define __in_ecount_or_z(c) _When_(_String_length_(_Curr_) < (c), __in_z) \
+ _When_(_String_length_(_Curr_) >= (c), __in_ecount(c))
+
+
+/* Provide default definition to be overridden when needed */
+#define __post_nullnullterminated
+
+/* Must protect redfinitions of macros to workaround rc.exe issues. */
+#ifndef RC_INVOKED
+
+#undef __nullnullterminated
+#define __nullnullterminated __inexpressible_readableTo("string terminated by two nulls") __nullterminated
+
+#undef __post_nullnullterminated
+#define __post_nullnullterminated _Post_ __inexpressible_readableTo("string terminated by two nulls") _Post_ __nullterminated
+
+#endif
+#endif //__SAL_H_FULL_VER <= 140050727
+
+/************************************************************************
+ New extensions to sal.h follow here.
+*************************************************************************/
+
+#if (_MSC_VER >= 1000) && !defined(__midl) && defined(_PREFAST_)
+
+#define __file_parser(typ) _SA_annotes2(SAL_file_parser,"function",typ)
+#define __file_parser_class(typ) _SA_annotes2(SAL_file_parser,"class",typ)
+#define __file_parser_library(typ) extern int _SA_annotes2(SAL_file_parser, "library", typ) __iSALFileParserLibrary##typ;
+#define __source_code_content(typ) extern int _SA_annotes1(SAL_source_code_content, typ) __iSAL_Source_Code_Content##typ;
+#define __class_code_content(typ) _SA_annotes1(SAL_class_code_content, typ)
+#define __analysis_assert(e) __assume(e)
+#define __analysis_hint(hint) _SA_annotes1(SAL_analysisHint, hint)
+// For "breakpoint": doesn't return as far as analysis is concerned.
+#define __analysis_noreturn __declspec(noreturn)
+/* Internal defintions */
+#define __inner_data_source(src_raw) _SA_annotes1(SAL_untrusted_data_source,src_raw)
+#define __inner_this_data_source(src_raw) _SA_annotes1(SAL_untrusted_data_source_this,src_raw)
+#define __inner_out_validated(typ_raw) _Post_ _SA_annotes1(SAL_validated,typ_raw)
+#define __inner_this_out_validated(typ_raw) _SA_annotes1(SAL_validated_this,typ_raw)
+#define __inner_assume_validated_dec __inline __nothrow void __AssumeValidated(__inner_out_validated("BY_DESIGN") const void *p) {p;}
+#define __inner_assume_validated(p) __AssumeValidated(p)
+#define __inner_transfer(formal) _SA_annotes1(SAL_transfer_adt_property_from,formal)
+#define __inner_encoded _SA_annotes0(SAL_encoded)
+
+#if defined(_MSC_EXTENSIONS) || defined(_PREFAST_) || defined(OACR)
+#define __inner_adt_prop(adt,prop) _SA_annotes2(SAL_adt, adt,prop)
+#define __inner_adt_add_prop(adt,prop) _SA_annotes2(SAL_add_adt_property,adt,prop)
+#define __inner_adt_remove_prop(adt,prop) _SA_annotes2(SAL_remove_adt_property,adt,prop)
+#define __inner_adt_transfer_prop(arg) _SA_annotes1(SAL_transfer_adt_property_from,arg)
+#define __inner_adt_type_props(typ) _SA_annotes1(SAL_post_type,typ)
+#define __inner_volatile _SA_annotes0(SAL_volatile)
+#define __inner_nonvolatile _SA_annotes0(SAL_nonvolatile)
+#define __inner_possibly_notnullterminated _SA_annotes1(SAL_nullTerminated,__maybe)
+#define __inner_analysis_assume_nullterminated_dec __inline __nothrow void __AnalysisAssumeNullterminated(_Post_ __nullterminated void *p) {*(char*)p=0;}
+#define __inner_analysis_assume_nullterminated(x) __AnalysisAssumeNullterminated(x);
+#endif
+
+#else
+
+#define __file_parser(typ)
+#define __file_parser_class(typ)
+#define __file_parser_library(typ)
+#define __source_code_content(typ)
+#define __class_code_content(typ)
+#define __analysis_assert(e)
+#define __analysis_hint(hint)
+#define __analysis_noreturn
+/* Internal defintions */
+#define __inner_data_source(src_raw)
+#define __inner_this_data_source(src_raw)
+#define __inner_out_validated(typ_raw)
+#define __inner_this_out_validated(typ_raw)
+#define __inner_assume_validated_dec
+#define __inner_assume_validated(p)
+#define __inner_transfer(formal)
+#define __inner_encoded
+#define __inner_adt_prop(adt,prop)
+#define __inner_adt_add_prop(adt,prop)
+#define __inner_adt_remove_prop(adt,prop)
+#define __inner_adt_transfer_prop(arg)
+#define __inner_adt_type_props(typ)
+#define __inner_volatile
+#define __inner_nonvolatile
+#define __inner_possibly_notnullterminated
+#define __inner_analysis_assume_nullterminated_dec
+#define __inner_analysis_assume_nullterminated(x)
+
+#endif // #if (_MSC_VER >= 1000) && !defined(__midl) && defined(_PREFAST_)
+
+#define __field_ecount(size) __notnull __elem_writableTo(size)
+#define __field_bcount(size) __notnull __byte_writableTo(size)
+#define __field_xcount(size) __notnull __inexpressible_writableTo(size)
+
+#define __field_ecount_opt(size) __maybenull __elem_writableTo(size)
+#define __field_bcount_opt(size) __maybenull __byte_writableTo(size)
+#define __field_xcount_opt(size) __maybenull __inexpressible_writableTo(size)
+
+#define __field_ecount_part(size,init) __notnull __elem_writableTo(size) __elem_readableTo(init)
+#define __field_bcount_part(size,init) __notnull __byte_writableTo(size) __byte_readableTo(init)
+#define __field_xcount_part(size,init) __notnull __inexpressible_writableTo(size) __inexpressible_readableTo(init)
+
+#define __field_ecount_part_opt(size,init) __maybenull __elem_writableTo(size) __elem_readableTo(init)
+#define __field_bcount_part_opt(size,init) __maybenull __byte_writableTo(size) __byte_readableTo(init)
+#define __field_xcount_part_opt(size,init) __maybenull __inexpressible_writableTo(size) __inexpressible_readableTo(init)
+
+#define __field_ecount_full(size) __field_ecount_part(size,size)
+#define __field_bcount_full(size) __field_bcount_part(size,size)
+#define __field_xcount_full(size) __field_xcount_part(size,size)
+
+#define __field_ecount_full_opt(size) __field_ecount_part_opt(size,size)
+#define __field_bcount_full_opt(size) __field_bcount_part_opt(size,size)
+#define __field_xcount_full_opt(size) __field_xcount_part_opt(size,size)
+
+#define __field_nullterminated __nullterminated
+
+#define __struct_bcount(size) __byte_writableTo(size)
+#define __struct_xcount(size) __inexpressible_writableTo(size)
+
+#define __out_awcount(expr,size) _Pre_ __notnull \
+ __byte_writableTo((expr) ? (size) : (size) * 2) \
+ _Post_ __valid __refparam
+#define __in_awcount(expr,size) _Pre_ __valid \
+ _Pre_ _Notref_ __deref __readonly \
+ __byte_readableTo((expr) ? (size) : (size) * 2)
+#define __post_invalid _Post_ __notvalid
+/* integer related macros */
+#define __allocator __inner_allocator
+#ifndef PAL_STDCPP_COMPAT
+#define __deallocate(kind) _Pre_ __notnull __post_invalid
+#define __deallocate_opt(kind) _Pre_ __maybenull __post_invalid
+#endif
+#define __bound __inner_bound
+#define __range(lb,ub) __inner_range(lb,ub)
+#define __in_bound _Pre_ __inner_bound
+#define __out_bound _Post_ __inner_bound
+#define __deref_out_bound _Post_ __deref __inner_bound
+#define __in_range(lb,ub) _Pre_ __inner_range(lb,ub)
+#define __out_range(lb,ub) _Post_ __inner_range(lb,ub)
+#define __deref_in_range(lb,ub) _Pre_ __deref __inner_range(lb,ub)
+#define __deref_out_range(lb,ub) _Post_ __deref __inner_range(lb,ub)
+#define __deref_inout_range(lb,ub) __deref_in_range(lb,ub) __deref_out_range(lb,ub)
+#define __field_range(lb,ub) __range(lb,ub)
+#define __field_data_source(src_sym) __inner_data_source(#src_sym)
+
+#define __range_max(a,b) __range(==, a > b ? a : b)
+#define __range_min(a,b) __range(==, a < b ? a : b)
+
+
+/* Penetration review macros */
+#define __in_data_source(src_sym) _Pre_ __inner_data_source(#src_sym)
+#define __out_data_source(src_sym) _Post_ __inner_data_source(#src_sym)
+#define __out_validated(typ_sym) __inner_out_validated(#typ_sym)
+#define __this_out_data_source(src_sym) __inner_this_data_source(#src_sym)
+#define __this_out_validated(typ_sym) __inner_this_out_validated(#typ_sym)
+#define __transfer(formal) _Post_ __inner_transfer(formal)
+#define __rpc_entry __inner_control_entrypoint(RPC)
+#define __kernel_entry __inner_control_entrypoint(UserToKernel)
+#define __gdi_entry __inner_control_entrypoint(GDI)
+#define __encoded_pointer __inner_encoded
+#define __encoded_array __inner_encoded
+#define __field_encoded_pointer __inner_encoded
+#define __field_encoded_array __inner_encoded
+#if defined(_MSC_EXTENSIONS) || defined(_PREFAST_) || defined(OACR)
+#define __type_has_adt_prop(adt,prop) __inner_adt_prop(adt,prop)
+#define __out_has_adt_prop(adt,prop) _Post_ __inner_adt_add_prop(adt,prop)
+#define __out_not_has_adt_prop(adt,prop) _Post_ __inner_adt_remove_prop(adt,prop)
+#define __out_transfer_adt_prop(arg) _Post_ __inner_adt_transfer_prop(arg)
+#define __out_has_type_adt_props(typ) _Post_ __inner_adt_type_props(typ)
+
+/* useful PFD related macros */
+#define __possibly_notnullterminated __inner_possibly_notnullterminated
+
+/* Windows Internal */
+#define __volatile __inner_volatile
+#define __nonvolatile __inner_nonvolatile
+#else
+#define __out_has_type_adt_props(typ) /* nothing */
+#endif
+#define __deref_volatile __deref __volatile
+#define __deref_nonvolatile __deref __nonvolatile
+
+/* declare stub functions for macros */
+__inner_assume_validated_dec
+__inner_assume_bound_dec
+__inner_analysis_assume_nullterminated_dec
+#define __analysis_assume_nullterminated(x) __inner_analysis_assume_nullterminated(x)
+#define __assume_validated(p) __inner_assume_validated(p)
+#define __assume_bound(i) __inner_assume_bound(i)
+
+
+/**************************************************************************
+* SAL 2 extensions for Windows-specific APIs.
+***************************************************************************/
+
+// Annotation for parameters that are not used in any way by the function.
+// Unlike _Reserved_, an _Unreferenced_parameter_ pointer need not be NULL.
+#ifndef _Unreferenced_parameter_
+#define _Unreferenced_parameter_ _Const_
+#endif
+
+// Pointer parameters that are freed by the function, and thus the pointed-to
+// memory should not be used after return.
+#ifndef _Frees_ptr_
+#define _Frees_ptr_ _Pre_notnull_ _Post_ptr_invalid_
+#endif
+#ifndef _Frees_ptr_opt_
+#define _Frees_ptr_opt_ _Pre_maybenull_ _Post_ptr_invalid_
+#endif
+
+// NLS APIs allow strings to be specified either by an element count or
+// null termination. Unlike _In_reads_or_z_, this is not whichever comes
+// first, but based on whether the size is negative or not.
+#define _In_NLS_string_(size) _When_((size) < 0, _In_z_) \
+ _When_((size) >= 0, _In_reads_(size))
+
+
+// Minifilter CompletionContext parameters on the pre-operation callback
+// default to NULL. For return type FLT_PREOP_SUCCESS_WITH_CALLBACK or
+// FLT_PREOP_SYNCHRONIZE, it may be set to NULL or a valid pointer. For all
+// other returns, it must be NULL.
+#define _Flt_CompletionContext_Outptr_ \
+ _Outptr_result_maybenull_ _Pre_valid_ \
+ _At_(*_Curr_, _Pre_null_ \
+ _When_(return != FLT_PREOP_SUCCESS_WITH_CALLBACK && return != FLT_PREOP_SYNCHRONIZE, _Post_null_))
+
+// Minifilter ConnectionCookie parameters on the port connect notify callback
+// default to NULL. On successful return, it may be set to NULL or non-NULL,
+// but it must be NULL on failure.
+#define _Flt_ConnectionCookie_Outptr_ \
+ _Outptr_result_maybenull_ _Pre_valid_ \
+ _At_(*_Curr_, _Pre_null_ _On_failure_(_Post_null_))
+
+
+//
+// A common pattern is to pass an "_Inout_ PCHAR* ppBuf" of size "_Inout_ DWORD* pSize"
+// to a function that writes to **pBuf, incrementing *ppBuf to point to one
+// past the last written byte. Thus the length of the write is
+// (*ppBuf - Old(*ppBuf)). The size of the remaining unwritten capacity
+// is written to *pSize.
+//
+// This pattern is frequently used when progressively filling a
+// large buffer in chunks
+// (e.g. when reading from a network interface in a driver).
+//
+// It is expected that these supplementary annotations would be used inside an
+// _At_, like so:
+//
+// _At_(*ppBuf, _Writes_and_advances_ptr_(*pBufSize))
+// HRESULT WriteChunkOfData(_Inout_ PCHAR* ppBuf, _Inout_ DWORD* pBufSize);
+//
+#ifndef _Writes_and_advances_ptr_
+#define _Writes_and_advances_ptr_(size) \
+ _At_((void*)_Curr_, _Inout_) \
+ _At_(_Curr_, \
+ _Pre_writable_size_(size) \
+ _Post_writable_size_(size) \
+ _Post_satisfies_(_Curr_ - _Old_(_Curr_) == size)) \
+ _At_(_Old_(_Curr_), \
+ _Post_readable_size_(_Old_(size) - size))
+#endif
+
+#ifndef _Writes_bytes_and_advances_ptr_
+#define _Writes_bytes_and_advances_ptr_(size) \
+ _At_((void*)_Curr_, _Inout_) \
+ _At_(_Curr_, \
+ _Pre_writable_byte_size_(size) \
+ _Post_writable_byte_size_(size) \
+ _Post_satisfies_(((char*)_Curr_) - ((void*)_Old_(_Curr_)) == size)) \
+ _At_(_Old_(_Curr_), \
+ _Post_readable_byte_size_(_Old_(size) - size))
+#endif
+
+//
+// Gets the current error code (as returned by GetLastError()), and stores
+// in _Curr_ as a postcondition. This is currently approximated by assuming
+// that GetLastError() always returns a failed error code. This is not a
+// completely accurate approximation, but reasonable.
+//
+#define _Post_equals_last_error_ _Post_satisfies_(_Curr_ != 0)
+
+#ifdef __cplusplus
+}
+#endif
+
+#ifdef _PREFIX_
+/**************************************************************************
+* Defintion of __pfx_assume and __pfx_assert. Thse should be the only
+* defintions of these functions.
+***************************************************************************/
+#if __cplusplus
+extern "C" void __pfx_assert(bool, const char *);
+extern "C" void __pfx_assume(bool, const char *);
+#else
+void __pfx_assert(int, const char *);
+void __pfx_assume(int, const char *);
+#endif
+/**************************************************************************
+* Redefintion of __analysis_assume and __analysis_assert for PREFIX build
+**************************************************************************/
+#undef __analysis_assume
+#undef __analysis_assert
+#define __analysis_assume(e) (__pfx_assume(e,"pfx_assume"),__assume(e));
+#define __analysis_assert(e) (__pfx_assert(e,"pfx_assert"),__assume(e));
+#endif /* ifdef _PREFIX_ */
+
+/**************************************************************************
+* This include should always be the last thing in this file.
+* Must avoid redfinitions of macros to workaround rc.exe issues.
+***************************************************************************/
+#if !(defined(RC_INVOKED) || defined(SORTPP_PASS))
+#include <specstrings_strict.h>
+#endif /* if !(defined(RC_INVOKED) || defined(SORTPP_PASS)) */
+
+/*
+ If no SAL 2 appears to have been defined (_Outptr_ is a representative choice)
+ then we must be operating in a downlevel build environment (such as VS10).
+ We also test against the compiler version to identify a downlevel environment,
+ as VS11 is the minimum required for SAL 2 support.
+
+ If we are operating in a downlevel build environment (such as VS10)
+ we need to undefine the following symbols before including driverspecs.h
+ or we will end up referencing SAL 2 implementation symbols and cause
+ build failures.
+*/
+#if (!defined(_Outptr_) || _MSC_VER <= 1600) && !( defined( MIDL_PASS ) || defined(__midl) || defined(RC_INVOKED) ) /*IFSTRIP=IGN*/
+#undef __ANNOTATION
+#define __ANNOTATION(fun) /* fun */
+#undef __PRIMOP
+#define __PRIMOP(type, fun)
+#endif /* !defined(_Outptr_) || _MSC_VER <= 1600 */
+
+// ROTOR doesn't need driverspecs.h
+// #include <driverspecs.h>
+
+/*
+ If no SAL 2 appears to have been defined (_Outptr_ is a representative choice)
+ then we must be operating in a downlevel build environment (such as VS10).
+ We also test against the compiler version to identify a downlevel environment,
+ as VS11 is the minimum required for SAL 2 support.
+
+ If we are in a downlevel environment, we can go ahead and include no_sal2.h
+ to make all of SAL 2 no-ops to ensure no build failures.
+*/
+#if (!defined(_Outptr_) || _MSC_VER <= 1600) && !( defined( MIDL_PASS ) || defined(__midl) || defined(RC_INVOKED) ) && !( defined( _SDV_ ) ) /*IFSTRIP=IGN*/
+#include <no_sal2.h>
+#endif /* !defined(_Outptr_) || _MSC_VER <= 1600 */
+
+#endif /* #ifndef SPECSTRINGS_H */
+
+
diff --git a/src/pal/inc/rt/specstrings_adt.h b/src/pal/inc/rt/specstrings_adt.h
new file mode 100644
index 0000000000..b3b949273a
--- /dev/null
+++ b/src/pal/inc/rt/specstrings_adt.h
@@ -0,0 +1,58 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+//
+
+//
+#pragma once
+/*************************************************************************
+* DEFINITIONS OF NEW TYPES
+*************************************************************************/
+#if !defined(__midl)
+#define __$compname_props \
+ __type_has_adt_prop(compname,nullterminated) \
+ __type_has_adt_prop(compname,valid_schars) \
+ __type_has_adt_prop(compname,correct_len) \
+ __nullterminated
+#if defined(UNICODE) || defined(_UNICODE)
+#define __$TCHAR unsigned short
+#else
+#define __$TCHAR char
+#endif
+// DEVDIV: Windows SDK Vista RTM update: Ignore C4956 warning when compiling with /clr:safe flag
+#ifdef _MSC_VER
+#pragma warning( disable : 4956 )
+#endif // _MSC_VER
+typedef __$compname_props char* ValidCompNameA;
+typedef __$compname_props unsigned short* ValidCompNameW;
+typedef __$compname_props const unsigned short* ConstValidCompNameW;
+typedef __$compname_props __$TCHAR* SAL_ValidCompNameT;
+typedef __$compname_props const __$TCHAR* SAL_ConstValidCompNameT;
+#ifdef _MSC_VER
+#pragma warning(default:4956)
+#endif // _MSC_VER
+#undef __$compname_props
+#undef __$TCHAR
+#endif
+
+/*************************************************************************
+* DEFINITIONS OF INLINE FUNCTIONS FOR CASTING TO THE NEW TYPES : USER
+*************************************************************************/
+#if (_MSC_VER >= 1000) && !defined(__midl) && defined(_PREFAST_)
+#ifdef __cplusplus
+extern "C" {
+#endif
+void __inline __nothrow __SAL_ValidCompNameA(__out_has_type_adt_props(ValidCompNameA) const void *expr) { expr;}
+void __inline __nothrow __SAL_ValidCompNameW(__out_has_type_adt_props(ValidCompNameW) const void *expr) { expr;}
+#ifdef __cplusplus
+}
+#endif
+#define __assume_ValidCompNameA(expr) __SAL_ValidCompNameA(expr)
+#define __assume_ValidCompNameW(expr) __SAL_ValidCompNameW(expr)
+#else
+#define __assume_ValidCompNameA(expr)
+#define __assume_ValidCompNameW(expr)
+#endif
+
+
diff --git a/src/pal/inc/rt/specstrings_strict.h b/src/pal/inc/rt/specstrings_strict.h
new file mode 100644
index 0000000000..514106eedf
--- /dev/null
+++ b/src/pal/inc/rt/specstrings_strict.h
@@ -0,0 +1,1190 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*************************************************************************
+* This file documents all the macros approved for use in windows source
+* code. It includes some experimental macros which should only be used by
+* experts.
+*
+* DO NOT include this file directly. This file is include after
+* specstrings.h. So we can undefine every possible old definition including
+* private internal macros people should not be using, as well as macros from
+* sal.h. Macros are redefined here in a way to cause syntax errors when used
+* incorrectly during a normal build when specstrings.h is included and
+* __SPECSTRINGS_STRICT_LEVEL is defined.
+*
+* There are several levels of strictness, each level includes the behavior of
+* all previous levels.
+*
+* 0 - Disable strict checking
+* 1 - Break on unapproved macros and misuse of statement
+* macros such as __fallthrough (default)
+* 2 - Deprecated some old macros that should not be used
+* 3 - Use VS 2005 Source Annotation to make sure every macro
+* is used in the right context. For example placing __in on a return
+* parameter will result in an error.
+*
+
+*
+************************************************************************/
+#ifndef __SPECSTRINGS_STRICT_LEVEL
+#define __SPECSTRINGS_STRICT_LEVEL 1
+#endif
+/************************************************************************
+* Introduction
+*
+* specstrings.h provides a set of annotations to describe how a function uses
+* its parameters - the assumptions it makes about them, and the guarantees it
+* makes upon finishing.
+*
+* Annotations must be placed before a function parameter's type or its return
+* type. There are two basic classes of common annotations buffer annotations
+* and advanced annotations. Buffer annotations describe how functions use
+* their pointer parameters, and advanced annotations either describe
+* complex/unusual buffer behavior, or provide additional information about a
+* parameter that is not otherwise expressible.
+*
+* Buffer Annotations
+*
+* The most important annotations in SpecStrings.h provide a consistent way to
+* annotate buffer parameters or return values for a function. Each of these
+* annotations describes a single buffer (which could be a string, a
+* fixed-length or variable-length array, or just a pointer) that the function
+* interacts with: where it is, how large it is, how much is initialized, and
+* what the function does with it.
+*
+* The appropriate macro for a given buffer can be constructed using the table
+* below. Just pick the appropriate values from each category, and combine
+* them together with a leading underscore. Some combinations of values do not
+* make sense as buffer annotations. Only meaningful annotations can be added
+* to your code; for a list of these, see the buffer annotation definitions
+* section.
+*
+* Only a single buffer annotation should be used for each parameter.
+*
+* |------------|------------|---------|--------|----------|---------------|
+* | Level | Usage | Size | Output | Optional | Parameters |
+* |------------|------------|---------|--------|----------|---------------|
+* | <> | <> | <> | <> | <> | <> |
+* | _deref | _in | _ecount | _full | _opt | (size) |
+* | _deref_opt | _out | _bcount | _part | | (size,length) |
+* | | _inout | | | | |
+* | | | | | | |
+* |------------|------------|---------|--------|----------|---------------|
+*
+* Note: "<>" represents the empty string.
+*
+* Level: Describes the buffer pointer's level of indirection from the
+* parameter or return value 'p'.
+*
+* <> : p is the buffer pointer.
+* _deref : *p is the buffer pointer. p must not be NULL.
+* _deref_opt : *p may be the buffer pointer. p may be NULL, in which case the
+* rest of the annotation is ignored.
+*
+* Usage: Describes how the function uses the buffer.
+*
+* <> : The buffer is not accessed. If used on the return value or with
+* _deref, the function will provide the buffer, and it will be uninitialized
+* at exit. Otherwise, the caller must provide the buffer. This should only
+* be used for alloc and free functions.
+*
+* _in : The function will only read from the buffer. The caller must provide
+* the buffer and initialize it.
+*
+* _out : The function will only write to the buffer. If used on the return
+* value or with _deref, the function will provide the buffer and initialize
+* it. Otherwise, the caller must provide the buffer, and the function will
+* initialize it.
+*
+* _inout : The function may freely read from and write to the buffer. The
+* caller must provide the buffer and initialize it. If used with _deref, the
+* buffer may be reallocated by the function.
+*
+* Size: Describes the total size of the buffer. This may be less than the
+* space actually allocated for the buffer, in which case it describes the
+* accessible amount.
+*
+* <> : No buffer size is given. If the type specifies the buffer size (such
+* as with LPSTR and LPWSTR), that amount is used. Otherwise, the buffer is
+* one element long. Must be used with _in, _out, or _inout.
+*
+* _ecount : The buffer size is an explicit element count.
+*
+* _bcount : The buffer size is an explicit byte count.
+*
+* Output: Describes how much of the buffer will be initialized by the
+* function. For _inout buffers, this also describes how much is initialized
+* at entry. Omit this category for _in buffers; they must be fully
+* initialized by the caller.
+*
+* <> : The type specifies how much is initialized. For instance, a function
+* initializing an LPWSTR must NULL-terminate the string.
+*
+* _full : The function initializes the entire buffer.
+*
+* _part : The function initializes part of the buffer, and explicitly
+* indicates how much.
+*
+* Optional: Describes if the buffer itself is optional.
+*
+* <> : The pointer to the buffer must not be NULL.
+*
+* _opt : The pointer to the buffer might be NULL. It will be checked before
+* being dereferenced.
+*
+* Parameters: Gives explicit counts for the size and length of the buffer.
+*
+* <> : There is no explicit count. Use when neither _ecount nor _bcount is
+* used.
+*
+* (size) : Only the buffer's total size is given. Use with _ecount or _bcount
+* but not _part.
+*
+* (size,length) : The buffer's total size and initialized length are
+* given. Use with _ecount_part and _bcount_part.
+*
+* ----------------------------------------------------------------------------
+* Buffer Annotation Examples
+*
+* LWSTDAPI_(BOOL) StrToIntExA(
+* LPCSTR pszString, // No annotation required, const implies __in.
+* DWORD dwFlags,
+* __out int *piRet // A pointer whose dereference will be filled in.
+* );
+*
+* void MyPaintingFunction(
+* __in HWND hwndControl, // An initialized read-only parameter.
+* __in_opt HDC hdcOptional, // An initialized read-only parameter that
+* // might be NULL.
+* __inout IPropertyStore *ppsStore // An initialized parameter that
+* // may be freely used and modified.
+* );
+*
+* LWSTDAPI_(BOOL) PathCompactPathExA(
+* __out_ecount(cchMax) LPSTR pszOut, // A string buffer with cch elements
+* // that will be '\0' terminated
+* // on exit.
+* LPCSTR pszSrc, // No annotation required,
+* // const implies __in.
+* UINT cchMax,
+* DWORD dwFlags
+* );
+*
+* HRESULT SHLocalAllocBytes(
+* size_t cb,
+* __deref_bcount(cb) T **ppv // A pointer whose dereference will be set
+* // to an uninitialized buffer with cb bytes.
+* );
+*
+* __inout_bcount_full(cb) : A buffer with cb elements that is fully
+* initialized at entry and exit, and may be written to by this function.
+*
+* __out_ecount_part(count, *countOut) : A buffer with count elements that
+* will be partially initialized by this function. The function indicates how
+* much it initialized by setting *countOut.
+*
+************************************************************************/
+
+#if (_MSC_VER >= 1400) && !defined(__midl) && !defined(_PREFAST_) && (__SPECSTRINGS_STRICT_LEVEL > 0)
+#pragma once
+#include <specstrings_undef.h>
+#define __ecount(size) _SAL_VERSION_CHECK(__ecount)
+#define __bcount(size) _SAL_VERSION_CHECK(__bcount)
+#define __xcount(size) _SAL_VERSION_CHECK(__xcount)
+#define __in _SAL_VERSION_CHECK(__in)
+#define __in_ecount(size) _SAL_VERSION_CHECK(__in_ecount)
+#define __in_bcount(size) _SAL_VERSION_CHECK(__in_bcount)
+#define __in_xcount(size) _SAL_VERSION_CHECK(__in_xcount)
+#define __in_z _SAL_VERSION_CHECK(__in_z)
+#define __in_ecount_z(size) _SAL_VERSION_CHECK(__in_ecount_z)
+#define __in_bcount_z(size) _SAL_VERSION_CHECK(__in_bcount_z)
+#define __out _SAL_VERSION_CHECK(__out)
+#define __out_ecount(size) _SAL_VERSION_CHECK(__out_ecount)
+#define __out_bcount(size) _SAL_VERSION_CHECK(__out_bcount)
+#define __out_xcount(size) _SAL_VERSION_CHECK(__out_xcount)
+#define __out_ecount_part(size,len) _SAL_VERSION_CHECK(__out_ecount_part)
+#define __out_bcount_part(size,len) _SAL_VERSION_CHECK(__out_bcount_part)
+#define __out_xcount_part(size,len) _SAL_VERSION_CHECK(__out_xcount_part)
+#define __out_ecount_full(size) _SAL_VERSION_CHECK(__out_ecount_full)
+#define __out_bcount_full(size) _SAL_VERSION_CHECK(__out_bcount_full)
+#define __out_xcount_full(size) _SAL_VERSION_CHECK(__out_xcount_full)
+#define __out_z _SAL_VERSION_CHECK(__out_z)
+#define __out_ecount_z(size) _SAL_VERSION_CHECK(__out_ecount_z)
+#define __out_bcount_z(size) _SAL_VERSION_CHECK(__out_bcount_z)
+#define __inout _SAL_VERSION_CHECK(__inout)
+#define __inout_ecount(size) _SAL_VERSION_CHECK(__inout_ecount)
+#define __inout_bcount(size) _SAL_VERSION_CHECK(__inout_bcount)
+#define __inout_xcount(size) _SAL_VERSION_CHECK(__inout_xcount)
+#define __inout_ecount_part(size,len) _SAL_VERSION_CHECK(__inout_ecount_part)
+#define __inout_bcount_part(size,len) _SAL_VERSION_CHECK(__inout_bcount_part)
+#define __inout_xcount_part(size,len) _SAL_VERSION_CHECK(__inout_xcount_part)
+#define __inout_ecount_full(size) _SAL_VERSION_CHECK(__inout_ecount_full)
+#define __inout_bcount_full(size) _SAL_VERSION_CHECK(__inout_bcount_full)
+#define __inout_xcount_full(size) _SAL_VERSION_CHECK(__inout_xcount_full)
+#define __inout_z __allowed(on_parameter)
+#define __inout_ecount_z(size) __allowed(on_parameter)
+#define __inout_bcount_z(size) __allowed(on_parameter)
+#define __ecount_opt(size) __allowed(on_parameter)
+#define __bcount_opt(size) __allowed(on_parameter)
+#define __xcount_opt(size) __allowed(on_parameter)
+#define __in_opt _SAL_VERSION_CHECK(__in_opt)
+#define __in_ecount_opt(size) _SAL_VERSION_CHECK(__in_ecount_opt)
+#define __in_bcount_opt(size) _SAL_VERSION_CHECK(__in_bcount_opt)
+#define __in_z_opt __allowed(on_parameter)
+#define __in_ecount_z_opt(size) __allowed(on_parameter)
+#define __in_bcount_z_opt(size) __allowed(on_parameter)
+#define __in_xcount_opt(size) __allowed(on_parameter)
+#define __out_opt _SAL_VERSION_CHECK(__out_opt)
+#define __out_ecount_opt(size) _SAL_VERSION_CHECK(__out_ecount_opt)
+#define __out_bcount_opt(size) _SAL_VERSION_CHECK(__out_bcount_opt)
+#define __out_xcount_opt(size) __allowed(on_parameter)
+#define __out_ecount_part_opt(size,len) __allowed(on_parameter)
+#define __out_bcount_part_opt(size,len) __allowed(on_parameter)
+#define __out_xcount_part_opt(size,len) __allowed(on_parameter)
+#define __out_ecount_full_opt(size) __allowed(on_parameter)
+#define __out_bcount_full_opt(size) __allowed(on_parameter)
+#define __out_xcount_full_opt(size) __allowed(on_parameter)
+#define __out_ecount_z_opt(size) __allowed(on_parameter)
+#define __out_bcount_z_opt(size) __allowed(on_parameter)
+#define __inout_opt _SAL_VERSION_CHECK(__inout_opt)
+#define __inout_ecount_opt(size) _SAL_VERSION_CHECK(__inout_ecount_opt)
+#define __inout_bcount_opt(size) _SAL_VERSION_CHECK(__inout_bcount_opt)
+#define __inout_xcount_opt(size) _SAL_VERSION_CHECK(__inout_xcount_opt)
+#define __inout_ecount_part_opt(size,len) _SAL_VERSION_CHECK(__inout_ecount_part_opt)
+#define __inout_bcount_part_opt(size,len) _SAL_VERSION_CHECK(__inout_bcount_part_opt)
+#define __inout_xcount_part_opt(size,len) _SAL_VERSION_CHECK(__inout_xcount_part_opt)
+#define __inout_ecount_full_opt(size) _SAL_VERSION_CHECK(__inout_ecount_full_opt)
+#define __inout_bcount_full_opt(size) _SAL_VERSION_CHECK(__inout_bcount_full_opt)
+#define __inout_xcount_full_opt(size) _SAL_VERSION_CHECK(__inout_xcount_full_opt)
+#define __inout_z_opt __allowed(on_parameter)
+#define __inout_ecount_z_opt(size) __allowed(on_parameter)
+#define __inout_ecount_z_opt(size) __allowed(on_parameter)
+#define __inout_bcount_z_opt(size) __allowed(on_parameter)
+#define __deref_ecount(size) __allowed(on_parameter)
+#define __deref_bcount(size) __allowed(on_parameter)
+#define __deref_xcount(size) __allowed(on_parameter)
+#define __deref_in _SAL_VERSION_CHECK(__deref_in)
+#define __deref_in_ecount(size) _SAL_VERSION_CHECK(__deref_in_ecount)
+#define __deref_in_bcount(size) _SAL_VERSION_CHECK(__deref_in_bcount)
+#define __deref_in_xcount(size) _SAL_VERSION_CHECK(__deref_in_xcount)
+#define __deref_out _SAL_VERSION_CHECK(__deref_out)
+#define __deref_out_ecount(size) _SAL_VERSION_CHECK(__deref_out_ecount)
+#define __deref_out_bcount(size) _SAL_VERSION_CHECK(__deref_out_bcount)
+#define __deref_out_xcount(size) _SAL_VERSION_CHECK(__deref_out_xcount)
+#define __deref_out_ecount_part(size,len) _SAL_VERSION_CHECK(__deref_out_ecount_part)
+#define __deref_out_bcount_part(size,len) _SAL_VERSION_CHECK(__deref_out_bcount_part)
+#define __deref_out_xcount_part(size,len) _SAL_VERSION_CHECK(__deref_out_xcount_part)
+#define __deref_out_ecount_full(size) _SAL_VERSION_CHECK(__deref_out_ecount_full)
+#define __deref_out_bcount_full(size) _SAL_VERSION_CHECK(__deref_out_bcount_full)
+#define __deref_out_xcount_full(size) _SAL_VERSION_CHECK(__deref_out_xcount_full)
+#define __deref_out_z __allowed(on_parameter)
+#define __deref_out_ecount_z(size) __allowed(on_parameter)
+#define __deref_out_bcount_z(size) __allowed(on_parameter)
+#define __deref_inout _SAL_VERSION_CHECK(__deref_inout)
+#define __deref_inout_ecount(size) _SAL_VERSION_CHECK(__deref_inout_ecount)
+#define __deref_inout_bcount(size) _SAL_VERSION_CHECK(__deref_inout_bcount)
+#define __deref_inout_xcount(size) _SAL_VERSION_CHECK(__deref_inout_xcount)
+#define __deref_inout_ecount_part(size,len) __allowed(on_parameter)
+#define __deref_inout_bcount_part(size,len) __allowed(on_parameter)
+#define __deref_inout_xcount_part(size,len) __allowed(on_parameter)
+#define __deref_inout_ecount_full(size) __allowed(on_parameter)
+#define __deref_inout_bcount_full(size) __allowed(on_parameter)
+#define __deref_inout_xcount_full(size) __allowed(on_parameter)
+#define __deref_inout_z __allowed(on_parameter)
+#define __deref_inout_ecount_z(size) __allowed(on_parameter)
+#define __deref_inout_bcount_z(size) __allowed(on_parameter)
+#define __deref_ecount_opt(size) __allowed(on_parameter)
+#define __deref_bcount_opt(size) __allowed(on_parameter)
+#define __deref_xcount_opt(size) __allowed(on_parameter)
+#define __deref_in_opt __allowed(on_parameter)
+#define __deref_in_opt_out __allowed(on_parameter)
+#define __deref_in_ecount_opt(size) __allowed(on_parameter)
+#define __deref_in_bcount_opt(size) __allowed(on_parameter)
+#define __deref_in_xcount_opt(size) __allowed(on_parameter)
+#define __deref_out_opt _SAL_VERSION_CHECK(__deref_out_opt)
+#define __deref_out_ecount_opt(size) _SAL_VERSION_CHECK(__deref_out_ecount_opt)
+#define __deref_out_bcount_opt(size) _SAL_VERSION_CHECK(__deref_out_bcount_opt)
+#define __deref_out_xcount_opt(size) _SAL_VERSION_CHECK(__deref_out_xcount_opt)
+#define __deref_out_ecount_part_opt(size,len) _SAL_VERSION_CHECK(__deref_out_ecount_part_opt)
+#define __deref_out_bcount_part_opt(size,len) _SAL_VERSION_CHECK(__deref_out_bcount_part_opt)
+#define __deref_out_xcount_part_opt(size,len) _SAL_VERSION_CHECK(__deref_out_xcount_part_opt)
+#define __deref_out_ecount_full_opt(size) _SAL_VERSION_CHECK(__deref_out_ecount_full_opt)
+#define __deref_out_bcount_full_opt(size) _SAL_VERSION_CHECK(__deref_out_bcount_full_opt)
+#define __deref_out_xcount_full_opt(size) _SAL_VERSION_CHECK(__deref_out_xcount_full_opt)
+#define __deref_out_z_opt __allowed(on_parameter)
+#define __deref_out_ecount_z_opt(size) __allowed(on_parameter)
+#define __deref_out_bcount_z_opt(size) __allowed(on_parameter)
+#define __deref_inout_opt __allowed(on_parameter)
+#define __deref_inout_ecount_opt(size) __allowed(on_parameter)
+#define __deref_inout_bcount_opt(size) __allowed(on_parameter)
+#define __deref_inout_xcount_opt(size) __allowed(on_parameter)
+#define __deref_inout_ecount_part_opt(size,len) __allowed(on_parameter)
+#define __deref_inout_bcount_part_opt(size,len) __allowed(on_parameter)
+#define __deref_inout_xcount_part_opt(size,len) __allowed(on_parameter)
+#define __deref_inout_ecount_full_opt(size) __allowed(on_parameter)
+#define __deref_inout_bcount_full_opt(size) __allowed(on_parameter)
+#define __deref_inout_xcount_full_opt(size) __allowed(on_parameter)
+#define __deref_inout_z_opt __allowed(on_parameter)
+#define __deref_inout_ecount_z_opt(size) __allowed(on_parameter)
+#define __deref_inout_bcount_z_opt(size) __allowed(on_parameter)
+#define __deref_opt_ecount(size) __allowed(on_parameter)
+#define __deref_opt_bcount(size) __allowed(on_parameter)
+#define __deref_opt_xcount(size) __allowed(on_parameter)
+#define __deref_opt_in __allowed(on_parameter)
+#define __deref_opt_in_ecount(size) __allowed(on_parameter)
+#define __deref_opt_in_bcount(size) __allowed(on_parameter)
+#define __deref_opt_in_xcount(size) __allowed(on_parameter)
+#define __deref_opt_out _SAL_VERSION_CHECK(__deref_opt_out)
+#define __deref_opt_out_ecount(size) _SAL_VERSION_CHECK(__deref_opt_out_ecount)
+#define __deref_opt_out_bcount(size) _SAL_VERSION_CHECK(__deref_opt_out_bcount)
+#define __deref_opt_out_xcount(size) _SAL_VERSION_CHECK(__deref_opt_out_xcount)
+#define __deref_opt_out_ecount_part(size,len) __allowed(on_parameter)
+#define __deref_opt_out_bcount_part(size,len) __allowed(on_parameter)
+#define __deref_opt_out_xcount_part(size,len) __allowed(on_parameter)
+#define __deref_opt_out_ecount_full(size) __allowed(on_parameter)
+#define __deref_opt_out_bcount_full(size) __allowed(on_parameter)
+#define __deref_opt_out_xcount_full(size) __allowed(on_parameter)
+#define __deref_opt_inout __allowed(on_parameter)
+#define __deref_opt_inout_ecount(size) __allowed(on_parameter)
+#define __deref_opt_inout_bcount(size) __allowed(on_parameter)
+#define __deref_opt_inout_xcount(size) __allowed(on_parameter)
+#define __deref_opt_inout_ecount_part(size,len) __allowed(on_parameter)
+#define __deref_opt_inout_bcount_part(size,len) __allowed(on_parameter)
+#define __deref_opt_inout_xcount_part(size,len) __allowed(on_parameter)
+#define __deref_opt_inout_ecount_full(size) __allowed(on_parameter)
+#define __deref_opt_inout_bcount_full(size) __allowed(on_parameter)
+#define __deref_opt_inout_xcount_full(size) __allowed(on_parameter)
+#define __deref_opt_inout_z __allowed(on_parameter)
+#define __deref_opt_inout_ecount_z(size) __allowed(on_parameter)
+#define __deref_opt_inout_bcount_z(size) __allowed(on_parameter)
+#define __deref_opt_ecount_opt(size) __allowed(on_parameter)
+#define __deref_opt_bcount_opt(size) __allowed(on_parameter)
+#define __deref_opt_xcount_opt(size) __allowed(on_parameter)
+#define __deref_opt_in_opt __allowed(on_parameter)
+#define __deref_opt_in_ecount_opt(size) __allowed(on_parameter)
+#define __deref_opt_in_bcount_opt(size) __allowed(on_parameter)
+#define __deref_opt_in_xcount_opt(size) __allowed(on_parameter)
+#define __deref_opt_out_opt __allowed(on_parameter)
+#define __deref_opt_out_ecount_opt(size) __allowed(on_parameter)
+#define __deref_opt_out_bcount_opt(size) __allowed(on_parameter)
+#define __deref_opt_out_xcount_opt(size) __allowed(on_parameter)
+#define __deref_opt_out_ecount_part_opt(size,len) __allowed(on_parameter)
+#define __deref_opt_out_bcount_part_opt(size,len) __allowed(on_parameter)
+#define __deref_opt_out_xcount_part_opt(size,len) __allowed(on_parameter)
+#define __deref_opt_out_ecount_full_opt(size) __allowed(on_parameter)
+#define __deref_opt_out_bcount_full_opt(size) __allowed(on_parameter)
+#define __deref_opt_out_xcount_full_opt(size) __allowed(on_parameter)
+#define __deref_opt_out_z_opt __allowed(on_parameter)
+#define __deref_opt_out_ecount_z_opt(size) __allowed(on_parameter)
+#define __deref_opt_out_bcount_z_opt(size) __allowed(on_parameter)
+#define __deref_opt_inout_opt __allowed(on_parameter)
+#define __deref_opt_inout_ecount_opt(size) __allowed(on_parameter)
+#define __deref_opt_inout_bcount_opt(size) __allowed(on_parameter)
+#define __deref_opt_inout_xcount_opt(size) __allowed(on_parameter)
+#define __deref_opt_inout_ecount_part_opt(size,len) __allowed(on_parameter)
+#define __deref_opt_inout_bcount_part_opt(size,len) __allowed(on_parameter)
+#define __deref_opt_inout_xcount_part_opt(size,len) __allowed(on_parameter)
+#define __deref_opt_inout_ecount_full_opt(size) __allowed(on_parameter)
+#define __deref_opt_inout_bcount_full_opt(size) __allowed(on_parameter)
+#define __deref_opt_inout_xcount_full_opt(size) __allowed(on_parameter)
+#define __deref_opt_inout_z_opt __allowed(on_parameter)
+#define __deref_opt_inout_ecount_z_opt(size) __allowed(on_parameter)
+#define __deref_opt_inout_bcount_z_opt(size) __allowed(on_parameter)
+#define __deref_in_ecount_iterator(size,incr) __allowed(on_parameter)
+#define __deref_out_ecount_iterator(size,incr) __allowed(on_parameter)
+#define __deref_inout_ecount_iterator(size,incr) __allowed(on_parameter)
+#define __deref_realloc_bcount(insize,outsize) __allowed(on_parameter)
+
+/************************************************************************
+* SAL 2 _Ouptr_ family of annotations
+************************************************************************/
+
+#define _Outptr_ __allowed(on_parameter)
+#define _Outptr_result_maybenull_ __allowed(on_parameter)
+#define _Outptr_opt_ __allowed(on_parameter)
+#define _Outptr_opt_result_maybenull_ __allowed(on_parameter)
+#define _Outptr_result_z_ __allowed(on_parameter)
+#define _Outptr_opt_result_z_ __allowed(on_parameter)
+#define _Outptr_result_maybenull_z_ __allowed(on_parameter)
+#define _Outptr_opt_result_maybenull_z_ __allowed(on_parameter)
+#define _Outptr_result_nullonfailure_ __allowed(on_parameter)
+#define _Outptr_opt_result_nullonfailure_ __allowed(on_parameter)
+#define _COM_Outptr_ __allowed(on_parameter)
+#define _COM_Outptr_result_maybenull_ __allowed(on_parameter)
+#define _COM_Outptr_opt_ __allowed(on_parameter)
+#define _COM_Outptr_opt_result_maybenull_ __allowed(on_parameter)
+#define _Outptr_result_buffer_(size) __allowed(on_parameter)
+#define _Outptr_opt_result_buffer_(size) __allowed(on_parameter)
+#define _Outptr_result_buffer_to_(size, count) __allowed(on_parameter)
+#define _Outptr_opt_result_buffer_to_(size, count) __allowed(on_parameter)
+#define _Outptr_result_buffer_all_(size) __allowed(on_parameter)
+#define _Outptr_opt_result_buffer_all_(size) __allowed(on_parameter)
+#define _Outptr_result_buffer_maybenull_(size) __allowed(on_parameter)
+#define _Outptr_opt_result_buffer_maybenull_(size) __allowed(on_parameter)
+#define _Outptr_result_buffer_to_maybenull_(size, count) __allowed(on_parameter)
+#define _Outptr_opt_result_buffer_to_maybenull_(size, count) __allowed(on_parameter)
+#define _Outptr_result_buffer_all_maybenull_(size) __allowed(on_parameter)
+#define _Outptr_opt_result_buffer_all_maybenull_(size) __allowed(on_parameter)
+#define _Outptr_result_bytebuffer_(size) __allowed(on_parameter)
+#define _Outptr_opt_result_bytebuffer_(size) __allowed(on_parameter)
+#define _Outptr_result_bytebuffer_to_(size, count) __allowed(on_parameter)
+#define _Outptr_opt_result_bytebuffer_to_(size, count) __allowed(on_parameter)
+#define _Outptr_result_bytebuffer_all_(size) __allowed(on_parameter)
+#define _Outptr_opt_result_bytebuffer_all_(size) __allowed(on_parameter)
+#define _Outptr_result_bytebuffer_maybenull_(size) __allowed(on_parameter)
+#define _Outptr_opt_result_bytebuffer_maybenull_(size) __allowed(on_parameter)
+#define _Outptr_result_bytebuffer_to_maybenull_(size, count) __allowed(on_parameter)
+#define _Outptr_opt_result_bytebuffer_to_maybenull_(size, count) __allowed(on_parameter)
+#define _Outptr_result_bytebuffer_all_maybenull_(size) __allowed(on_parameter)
+#define _Outptr_opt_result_bytebuffer_all_maybenull_(size) __allowed(on_parameter)
+
+/************************************************************************
+* Orcas SAL
+************************************************************************/
+#define _Deref_out_ _SAL_VERSION_CHECK(_Deref_out_)
+#define _Deref_out_opt_ _SAL_VERSION_CHECK(_Deref_out_opt_)
+#define _Deref_opt_out_ _SAL_VERSION_CHECK(_Deref_opt_out_)
+#define _Deref_opt_out_opt_ _SAL_VERSION_CHECK(_Deref_opt_out_opt_)
+#define _In_count_(size) _SAL_VERSION_CHECK(_In_count_)
+#define _In_opt_count_(size) _SAL_VERSION_CHECK(_In_opt_count_)
+#define _In_bytecount_(size) _SAL_VERSION_CHECK(_In_bytecount_)
+#define _In_opt_bytecount_(size) _SAL_VERSION_CHECK(_In_opt_bytecount_)
+#define _Out_cap_(size) _SAL_VERSION_CHECK(_Out_cap_)
+#define _Out_opt_cap_(size) _SAL_VERSION_CHECK(_Out_opt_cap_)
+#define _Out_bytecap_(size) _SAL_VERSION_CHECK(_Out_bytecap_)
+#define _Out_opt_bytecap_(size) _SAL_VERSION_CHECK(_Out_opt_bytecap_)
+#define _Deref_post_count_(size) _SAL_VERSION_CHECK(_Deref_post_count_)
+#define _Deref_post_opt_count_(size) _SAL_VERSION_CHECK(_Deref_post_opt_count_)
+#define _Deref_post_bytecount_(size) _SAL_VERSION_CHECK(_Deref_post_bytecount_)
+#define _Deref_post_opt_bytecount_(size) _SAL_VERSION_CHECK(_Deref_post_opt_bytecount_)
+#define _Deref_post_cap_(size) _SAL_VERSION_CHECK(_Deref_post_cap_)
+#define _Deref_post_opt_cap_(size) _SAL_VERSION_CHECK(_Deref_post_opt_cap_)
+#define _Deref_post_bytecap_(size) _SAL_VERSION_CHECK(_Deref_post_bytecap_)
+#define _Deref_post_opt_bytecap_(size) _SAL_VERSION_CHECK(_Deref_post_opt_bytecap_)
+
+/************************************************************************
+* Advanced Annotations
+*
+* Advanced annotations describe behavior that is not expressible with the
+* regular buffer macros. These may be used either to annotate buffer
+* parameters that involve complex or conditional behavior, or to enrich
+* existing annotations with additional information.
+*
+* _At_(expr, annotes) : annotation list annotes applies to target 'expr'
+*
+* _When_(expr, annotes) : annotation list annotes applies when 'expr' is true
+*
+* __success(expr) T f() : <expr> indicates whether function f succeeded or
+* not. If <expr> is true at exit, all the function's guarantees (as given
+* by other annotations) must hold. If <expr> is false at exit, the caller
+* should not expect any of the function's guarantees to hold. If not used,
+* the function must always satisfy its guarantees. Added automatically to
+* functions that indicate success in standard ways, such as by returning an
+* HRESULT.
+*
+* __out_awcount(expr, size) T *p : Pointer p is a buffer whose size may be
+* given in either bytes or elements. If <expr> is true, this acts like
+* __out_bcount. If <expr> is false, this acts like __out_ecount. This
+* should only be used to annotate old APIs.
+*
+* __in_awcount(expr, size) T* p : Pointer p is a buffer whose size may be given
+* in either bytes or elements. If <expr> is true, this acts like
+* __in_bcount. If <expr> is false, this acts like __in_ecount. This should
+* only be used to annotate old APIs.
+*
+* __nullterminated T* p : Pointer p is a buffer that may be read or written
+* up to and including the first '\0' character or pointer. May be used on
+* typedefs, which marks valid (properly initialized) instances of that type
+* as being null-terminated.
+*
+* __nullnullterminated T* p : Pointer p is a buffer that may be read or
+* written up to and including the first sequence of two '\0' characters or
+* pointers. May be used on typedefs, which marks valid instances of that
+* type as being double-null terminated.
+*
+* __reserved T v : Value v must be 0/NULL, reserved for future use.
+*
+* __checkReturn T f(); : Return value of f must not be ignored by callers
+* of this function.
+*
+* __typefix(ctype) T v : Value v should be treated as an instance of ctype,
+* rather than its declared type when considering validity.
+*
+* __override T f(); : Specify C#-style 'override' behaviour for overriding
+* virtual methods.
+*
+* __callback T f(); : Function f can be used as a function pointer.
+*
+* __format_string T p : Pointer p is a string that contains % markers in
+* the style of printf.
+*
+* __blocksOn(resource) f(); : Function f blocks on the resource 'resource'.
+*
+* __fallthrough : Annotates switch statement labels where fall-through is
+* desired, to distinguish from forgotten break statements.
+*
+* __range(low_bnd, up_bnd) int f(): The return from the function "f" must
+* be in the inclusive numeric range [low_bnd, up_bnd].
+*
+* __in_range(low_bnd, up_bnd) int i : Precondition that integer i must be
+* in the inclusive numeric range [low_bnd, up_bnd].
+*
+* __out_range(low_bnd, up_bnd) int i : Postcondition that integer i must be
+* in the inclusive numeric range [low_bnd, up_bnd].
+*
+* __deref_in_range(low_bnd, up_bnd) int* pi : Precondition that integer *pi
+* must be in the inclusive numeric range [low_bnd, up_bnd].
+*
+* __deref_out_range(low_bnd, up_bnd) int* pi : Postcondition that integer
+* *pi must be in the inclusive numeric range [low_bnd, up_bnd].
+*
+* __deref_inout_range(low_bnd, up_bnd) int* pi : Invariant that the integer
+* *pi must be in the inclusive numeric range [low_bnd, up_bnd].
+*
+* The first argument of a range macro may also be a C relational operator
+* (<,>,!=, ==, <=, >=).
+*
+* __range(rel_op, j) int f(): Postcondition that "f() rel_op j" must be
+* true. Note that j may be a expression known only at runtime.
+*
+* __in_range(rel_op, j) int i : Precondition that "i rel_op j" must be
+* true. Note that j may be a expression known only at runtime.
+*
+* __out_range(rel_op, j) int i : Postcondition that integer "i rel_op j"
+* must be true. Note that j may be a expression known only at runtime.
+*
+* __deref_in_range(rel_op, j) int *pi : Precondition that "*pi rel_op j"
+* must be true. Note that j may be a expression known only at runtime.
+*
+* __deref_out_range(rel_op, j) int *pi : Postcondition that "*pi rel_op j"
+* must be true. Note that j may be a expression known only at runtime.
+*
+* __deref_inout_range(rel_op, j) int *pi : Invariant that "*pi rel_op j"
+* must be true. Note that j may be a expression known only at runtime.
+*
+* __range_max(a, b) int f(): Postcondition f acts as 'max', returns larger
+* of a and b. Note that a and b may be expressions known only at runtime.
+*
+* __range_min(a, b) int f(): Postcondition f acts as 'min', returns smaller
+* of a and b. Note that a and b may be expressions known only at runtime.
+*
+* __in_bound int i : Precondition that integer i must be bound, but the
+* exact range can't be specified at compile time. __in_range should be
+* used if the range can be explicitly stated.
+*
+* __out_bound int i : Postcondition that integer i must be bound, but the
+* exact range can't be specified at compile time. __out_range should be
+* used if the range can be explicitly stated.
+*
+* __deref_out_bound int pi : Postcondition that integer *pi must be bound,
+* but the exact range can't be specified at compile time.
+* __deref_out_range should be used if the range can be explicitly stated.
+*
+* __assume_bound(expr); : Assume that the expression is bound to some known
+* range. This can be used to suppress integer overflow warnings on integral
+* expressions that are known to be bound due to reasons not explicit in the
+* code. Use as a statement in the body of a function.
+*
+* __analysis_assume_nulltermianted(expr); : Assume that the expression is
+* a null terminated buffer. Use this to suppress tool noise specific to
+* nulltermination warnings, and capture deeper invariants tools can not
+* discover.
+*
+* __allocator void f(): Function allocates memory using an integral size
+* argument
+*
+* void myfree(__deallocate(Mem) void *p) : Memory is freed, no longer usable
+* upon return, and p may not be null.
+*
+* void myfree(__deallocate_opt(Mem) void *p) : Memory is freed, no longer
+* usable upon return, and p may be null.
+*
+* void free(__post_invalid void* x): Mark memory as untouchable when
+* function returns.
+*
+* ----------------------------------------------------------------------------
+* Advanced Annotation Examples
+*
+* __success(return == TRUE) LWSTDAPI_(BOOL)
+* PathCanonicalizeA(__out_ecount(MAX_PATH) LPSTR pszBuf, LPCSTR pszPath);
+* // pszBuf is only guaranteed to be null-terminated when TRUE is returned.
+*
+* // Initialized LPWSTRs are null-terminated strings.
+* typedef __nullterminated WCHAR* LPWSTR;
+*
+* __out_ecount(cch) __typefix(LPWSTR) void *psz;
+* // psz is a buffer parameter which will be a null-terminated WCHAR string
+* // at exit, and which initially contains cch WCHARs.
+*
+************************************************************************/
+#define _At_(expr, annotes) __allowed(on_parameter_or_return)
+#define _When_(expr, annotes) __allowed(on_parameter_or_return)
+#define __success(expr) _SAL_VERSION_CHECK(__success)
+#define __out_awcount(expr,size) __allowed(on_parameter)
+#define __in_awcount(expr,size) __allowed(on_parameter)
+#define __nullterminated _SAL_VERSION_CHECK(__nullterminated)
+#define __nullnullterminated _SAL_VERSION_CHECK(__nullnullterminated)
+#define __reserved _SAL_VERSION_CHECK(__reserved)
+#define __checkReturn _SAL_VERSION_CHECK(__checkReturn)
+#define __typefix(ctype) __allowed(on_parameter_or_return)
+#define __override __allowed(on_function)
+#define __callback __allowed(on_function)
+#define __format_string __allowed(on_parameter_or_return)
+#define __blocksOn(resource) __allowed(on_function)
+#define __fallthrough __allowed(as_statement)
+#define __range(lb,ub) __allowed(on_return)
+#define __in_range(lb,ub) _SAL_VERSION_CHECK(__in_range)
+#define __out_range(lb,ub) _SAL_VERSION_CHECK(__out_range)
+#define __deref_in_range(lb,ub) __allowed(on_parameter)
+#define __deref_out_range(lb,ub) _SAL_VERSION_CHECK(__deref_out_range)
+#define __deref_inout_range(lb,ub) __allowed(on_parameter)
+#define __field_range(lb,ub) _SAL_VERSION_CHECK(__field_range)
+#define __range_max(a,b) __allowed(on_return)
+#define __range_min(a,b) __allowed(on_return)
+#define __bound __allowed(on_return)
+#define __in_bound __allowed(on_parameter)
+#define __out_bound __allowed(on_parameter)
+#define __deref_out_bound __allowed(on_parameter)
+#define __assume_bound(i) __allowed(as_statement_with_arg(i))
+#define __analysis_assume_nullterminated(x) \
+ __allowed(as_statement_with_arg(x))
+#define __allocator __allowed(on_function)
+#define __deallocate(kind) __allowed(on_parameter)
+#define __deallocate_opt(kind) __allowed(on_parameter)
+#define __post_invalid __allowed(on_parameter_or_return)
+#define __post_nullnullterminated \
+ __allowed(on_parameter_or_return)
+/***************************************************************************
+* Expert Macros
+***************************************************************************/
+#define __null __allowed(on_typedecl)
+#define __notnull __allowed(on_typedecl)
+#define __maybenull __allowed(on_typedecl)
+#define __exceptthat __allowed(on_typedecl)
+/***************************************************************************
+* Macros to classify fields of structures.
+* Structure Annotations
+*
+* The buffer annotations are a convenient way of describing
+* relationships between buffers and their size on a function by
+* function basis. Very often struct or class data members have similar
+* invariants, which can be expressed directly on the type.
+*
+* Similar to our buffer annotations we can summarize all the various
+* structure annotations by one choosing an element from each column of
+* this table to build a composite annotation.
+*
+* +--------------------------------------------------+
+* | Selector | Units | Size/Init | Optional |
+* |----------+---------+------------------+----------|
+* | __field | _ecount | (size) | empty |
+* |----------+---------+------------------+----------|
+* | __struct | _bcount | _full(size) | _opt |
+* |----------+---------+------------------+----------|
+* | | _xcount | _part(size,init) | |
+* +--------------------------------------------------+
+*
+* Note that empty represents the empty string. Sometime arguments need
+* to be "floated" to the left to give us a valid annotation name. For
+* example the naive combination __field_ecount(size)_opt is actually
+* written as __field_ecount_opt(size). Not all possible combinations
+* are currently supported or sensible. See specstrings_strict.h for
+* the currently supported set. Those that are supported are documented
+* below.
+*
+*Summary of Elements
+*
+* Selector
+*
+* __field
+* The annotation should only be placed in front
+* of data members of structures and classes. The
+* data members are pointers to a block of data.
+* The annotations describe properties about the
+* size of the block of data. This can be used for
+*
+* __struct
+* The annotation should only be placed at the
+* beginning of the definition of a structure or
+* class. These annotations are used when a struct
+* or class is used as a "header" that is
+* allocated inline with a block of data and there
+* is no apparent field that represents the tail
+* end of the structure.
+*
+* Units
+*
+* _ecount
+* All size and initialization values are in terms
+* of elements of the appropriate type
+*
+* _bcount
+* All size and initialization values are in terms
+* of raw byte sizes.
+*
+* _xcount
+* The size or initialization values cannot be
+* properly expressed as a simple byte or element
+* count, and instead a place holder is used to
+* document the relationship.
+*
+* Size/Init
+* All the size/init expressions can contain references to
+* other fields in the struct or class.
+*
+* (size)
+* The size of the buffer is determined by the
+* expression size. Unless, the type of the buffer
+* provides more information nothing is know about
+* how much of this data is initialized. For
+* example, if the data member happens to be a
+* string type such as LPSTR. It is assumed that
+* the data is initialized to the first '\0'.
+*
+* _full(size)
+* The size of the buffer is determined by the
+* expression size and all the data in the buffer
+* is guaranteed to be initialized.
+*
+* _part(size,init)
+* The size of the buffer is determined by the
+* expression size and all the data in the buffer
+* is guaranteed to be initialized up to init
+* elements or bytes.
+*
+* Optional
+*
+* empty
+* The pointer to the block of memory is never
+* NULL
+*
+* _opt
+* The pointer to the block of memory is may be
+* NULL
+*
+*
+* // Basic Usage of Struct Annotations
+* #include <stdio.h>
+* #include <stdlib.h>
+* struct buf_s {
+* int sz;
+* __field_bcount_full(sz)
+* char *buf;
+* };
+* void InitBuf(__out struct *buf_s b,int sz) {
+* b->buf = calloc(sz,sizeof(char));
+* b->sz = sz;
+* }
+* void WriteBuf(__in FILE *fp,__in struct *buf_s b) {
+* fwrite(b->buf,b->sz,sizeof(char),fp);
+* }
+* void ReadBuf(__in FILE *fp,__inout struct *buf_s b) {
+* fread(b->buf,b->sz,sizeof(char),fp);
+* }
+*
+*
+*
+* // Inline Allocated Buffer
+* struct buf_s {
+* int sz;
+* __field_bcount(sz)
+* char buf[1];
+* };
+* void WriteBuf(__in FILE *fp,__in struct *buf_s b) {
+* fwrite(&(b->buf),b->sz,sizeof(char),fp);
+* }
+* void ReadBuf(__in FILE *fp,__inout struct *buf_s b) {
+* fread(&(b->buf),b->sz,sizeof(char),fp);
+* }
+*
+*
+*
+* // Embedded Header Structure
+* __struct_bcount(sz)
+* struct buf_s {
+* int sz;
+* };
+* void WriteBuf(__in FILE *fp,__in struct *buf_s b) {
+* fwrite(&b,b->sz,sizeof(char),fp);
+* }
+* void ReadBuf(__in FILE *fp,__inout struct *buf_s b) {
+* fread(&b,b->sz,sizeof(char),fp);
+* }
+*
+*
+****************************************************************************/
+#define __field_ecount(size) _SAL_VERSION_CHECK(__field_ecount)
+#define __field_bcount(size) _SAL_VERSION_CHECK(__field_bcount)
+#define __field_xcount(size) __allowed(on_field)
+#define __field_ecount_opt(size) __allowed(on_field)
+#define __field_bcount_opt(size) __allowed(on_field)
+#define __field_xcount_opt(size) __allowed(on_field)
+#define __field_ecount_part(size,init) __allowed(on_field)
+#define __field_bcount_part(size,init) __allowed(on_field)
+#define __field_xcount_part(size,init) __allowed(on_field)
+#define __field_ecount_part_opt(size,init) __allowed(on_field)
+#define __field_bcount_part_opt(size,init) __allowed(on_field)
+#define __field_xcount_part_opt(size,init) __allowed(on_field)
+#define __field_ecount_full(size) __allowed(on_field)
+#define __field_bcount_full(size) __allowed(on_field)
+#define __field_xcount_full(size) __allowed(on_field)
+#define __field_ecount_full_opt(size) __allowed(on_field)
+#define __field_bcount_full_opt(size) __allowed(on_field)
+#define __field_xcount_full_opt(size) __allowed(on_field)
+#define __field_nullterminated __allowed(on_field)
+#define __struct_bcount(size) __allowed(on_struct)
+#define __struct_xcount(size) __allowed(on_struct)
+
+/***************************************************************************
+* Macros to classify the entrypoints and indicate their category.
+*
+* Pre-defined control point categories include: RPC, KERNEL, GDI.
+*
+* Pre-defined control point macros include:
+* __rpc_entry, __kernel_entry, __gdi_entry.
+***************************************************************************/
+#define __control_entrypoint(category) __allowed(on_function)
+#define __rpc_entry __allowed(on_function)
+#define __kernel_entry __allowed(on_function)
+#define __gdi_entry __allowed(on_function)
+
+/***************************************************************************
+* Macros to track untrusted data and their validation. The list of untrusted
+* sources include:
+*
+* FILE - File reading stream or API
+* NETWORK - Socket readers
+* INTERNET - WinInet and WinHttp readers
+* USER_REGISTRY - HKCU portions of the registry
+* USER_MODE - Parameters to kernel entry points
+* RPC - Parameters to RPC entry points
+* DRIVER - Device driver
+***************************************************************************/
+#define __in_data_source(src_sym) __allowed(on_parameter)
+#define __out_data_source(src_sym) __allowed(on_parameter)
+#define __field_data_source(src_sym) __allowed(on_field)
+#define __this_out_data_source(src_syn) __allowed(on_function)
+
+/**************************************************************************
+* Macros to tag file parsing code. Predefined formats include:
+* PNG - Portable Network Graphics
+* JPEG - Joint Photographic Experts Group
+* BMP - Bitmap
+* RC_BMP - Resource bitmap
+* WMF - Windows Metafile
+* EMF - Windows Enhanced Metafile
+* GIF - Graphics Interchange Format
+* MIME_TYPE - MIME type from header tokens
+* MAIL_MONIKER - MAIL information refered by URL moniker
+* HTML - HyperText Markup Language
+* WMPHOTO - Windows media photo
+* OE_VCARD - Outlook Express virtual card
+* OE_CONTACT - Outlook Express contact
+* MIDI - Musical Instrument Digital Interface
+* LDIF - LDAP Data Interchange Format
+* AVI - Audio Visual Interchange
+* ACM - Audio Compression Manager
+**************************************************************************/
+#define __out_validated(filetype_sym) __allowed(on_parameter)
+#define __this_out_validated(filetype_sym) __allowed(on_function)
+#define __file_parser(filetype_sym) __allowed(on_function)
+#define __file_parser_class(filetype_sym) __allowed(on_struct)
+#define __file_parser_library(filetype_sym) __allowed(as_global_decl)
+
+/***************************************************************************
+* Macros to track the code content in the file. The type of code
+* contents currently tracked:
+*
+* NDIS_DRIVER - NDIS Device driver
+***************************************************************************/
+#define __source_code_content(codetype_sym) __allowed(as_global_decl)
+
+/***************************************************************************
+* Macros to track the code content in the class. The type of code
+* contents currently tracked:
+*
+* DCOM - Class implementing DCOM
+***************************************************************************/
+#define __class_code_content(codetype_sym) __allowed(on_struct)
+
+/*************************************************************************
+* Macros to tag encoded function pointers
+**************************************************************************/
+#define __encoded_pointer
+#define __encoded_array
+#define __field_encoded_pointer __allowed(on_field)
+#define __field_encoded_array __allowed(on_field)
+
+#define __transfer(formal) __allowed(on_parameter_or_return)
+#define __assume_validated(exp) __allowed(as_statement_with_arg(exp))
+
+/*************************************************************************
+* __analysis_assume(expr) : Expert macro use only when directed. Use this to
+* tell static analysis tools like PREfix and PREfast about a non-coded
+* assumption that you wish the tools to assume. The assumption will be
+* understood by those tools. By default there is no dynamic checking or
+* static checking of the assumption in any build.
+*
+* To obtain dynamic checking wrap this macro in your local version of a debug
+* assert.
+* Please do not put function calls in the expression because this is not
+* supported by all tools:
+* __analysis_assume(GetObject () != NULL); // DO NOT DO THIS
+*
+*************************************************************************/
+#define __analysis_assume(expr) __allowed(as_statement_with_arg(expr))
+#define __analysis_assert(expr) __allowed(as_statement_with_arg(expr))
+
+/*************************************************************************
+* __analysis_hint(hint_sym) : Expert macro use only when
+* directed. Use this to influence certain analysis heuristics
+* used by the tools. These hints do not describe the semantics
+* of functions but simply direct the tools to act in a certain
+* way.
+*
+* Current hints that are supported are:
+*
+* INLINE - inline this function during analysis overrides any
+* default heuristics
+* NOINLINE - do not inline this function during analysis overrides
+* and default heuristics
+*************************************************************************/
+#define __analysis_hint(hint) __allowed(on_function)
+
+/*************************************************************************
+* Macros to encode abstract properties of values. Used by SALadt.h
+*************************************************************************/
+#define __type_has_adt_prop(adt,prop) __allowed(on_typdecl)
+#define __out_has_adt_prop(adt,prop) __allowed(on_parameter)
+#define __out_not_has_adt_prop(adt,prop) __allowed(on_parameter)
+#define __out_transfer_adt_prop(arg) __allowed(on_parameter)
+#define __out_has_type_adt_props(typ) __allowed(on_parameter)
+
+/*************************************************************************
+* Macros used by Prefast for Drivers
+*
+* __possibly_notnullterminated :
+*
+* Used for return values of parameters or functions that do not
+* guarantee nulltermination in all cases.
+*
+*************************************************************************/
+#define __possibly_notnullterminated __allowed(on_parameter_or_return)
+
+/*************************************************************************
+* Advanced macros
+*
+* __volatile
+* The __volatile annotation identifies a global variable or
+* structure field that:
+* 1) is not declared volatile;
+* 2) is accessed concurrently by multiple threads.
+*
+* The __deref_volatile annotation identifies a global variable
+* or structure field that stores a pointer to some data that:
+* 1) is not declared volatile;
+* 2) is accessed concurrently by multiple threads.
+*
+* Prefast uses these annotations to find patterns of code that
+* may result in unexpected re-fetching of the global variable
+* into a local variable.
+*
+* We also provide two complimentary annotations __nonvolatile
+* and __deref_nonvolatile that could be used to suppress Prefast
+*
+* re-fetching warnings on variables that are known either:
+* 1) not to be in danger of being re-fetched or,
+* 2) not to lead to incorrect results if they are re-fetched
+*
+*************************************************************************/
+#define __volatile __allowed(on_global_or_field)
+#define __deref_volatile __allowed(on_global_or_field)
+#define __nonvolatile __allowed(on_global_or_field)
+#define __deref_nonvolatile __allowed(on_global_or_field)
+
+/*************************************************************************
+* Macros deprecated with strict level greater then 1.
+**************************************************************************/
+#if (__SPECSTRINGS_STRICT_LEVEL > 1)
+/* Must come before macro defintions */
+#pragma deprecated(__in_nz)
+#pragma deprecated(__in_ecount_nz)
+#pragma deprecated(__in_bcount_nz)
+#pragma deprecated(__out_nz)
+#pragma deprecated(__out_nz_opt)
+#pragma deprecated(__out_ecount_nz)
+#pragma deprecated(__out_bcount_nz)
+#pragma deprecated(__inout_nz)
+#pragma deprecated(__inout_ecount_nz)
+#pragma deprecated(__inout_bcount_nz)
+#pragma deprecated(__in_nz_opt)
+#pragma deprecated(__in_ecount_nz_opt)
+#pragma deprecated(__in_bcount_nz_opt)
+#pragma deprecated(__out_ecount_nz_opt)
+#pragma deprecated(__out_bcount_nz_opt)
+#pragma deprecated(__inout_nz_opt)
+#pragma deprecated(__inout_ecount_nz_opt)
+#pragma deprecated(__inout_bcount_nz_opt)
+#pragma deprecated(__deref_out_nz)
+#pragma deprecated(__deref_out_ecount_nz)
+#pragma deprecated(__deref_out_bcount_nz)
+#pragma deprecated(__deref_inout_nz)
+#pragma deprecated(__deref_inout_ecount_nz)
+#pragma deprecated(__deref_inout_bcount_nz)
+#pragma deprecated(__deref_out_nz_opt)
+#pragma deprecated(__deref_out_ecount_nz_opt)
+#pragma deprecated(__deref_out_bcount_nz_opt)
+#pragma deprecated(__deref_inout_nz_opt)
+#pragma deprecated(__deref_inout_ecount_nz_opt)
+#pragma deprecated(__deref_inout_bcount_nz_opt)
+#pragma deprecated(__deref_opt_inout_nz)
+#pragma deprecated(__deref_opt_inout_ecount_nz)
+#pragma deprecated(__deref_opt_inout_bcount_nz)
+#pragma deprecated(__deref_opt_out_nz_opt)
+#pragma deprecated(__deref_opt_out_ecount_nz_opt)
+#pragma deprecated(__deref_opt_out_bcount_nz_opt)
+#pragma deprecated(__deref_opt_inout_nz_opt)
+#pragma deprecated(__deref_opt_inout_ecount_nz_opt)
+#pragma deprecated(__deref_opt_inout_bcount_nz_opt)
+#pragma deprecated(__deref)
+#pragma deprecated(__pre)
+#pragma deprecated(__post)
+#pragma deprecated(__readableTo)
+#pragma deprecated(__writableTo)
+#pragma deprecated(__maybevalid)
+#pragma deprecated(__data_entrypoint)
+#pragma deprecated(__inexpressible_readableTo)
+#pragma deprecated(__readonly)
+#pragma deprecated(__byte_writableTo)
+#pragma deprecated(__byte_readableTo)
+#pragma deprecated(__elem_readableTo)
+#pragma deprecated(__elem_writableTo)
+#pragma deprecated(__valid)
+#pragma deprecated(__notvalid)
+#pragma deprecated(__refparam)
+#pragma deprecated(__precond)
+#endif
+/* Define soon to be deprecated macros to nops. */
+#define __in_nz
+#define __in_ecount_nz(size)
+#define __in_bcount_nz(size)
+#define __out_nz
+#define __out_nz_opt
+#define __out_ecount_nz(size)
+#define __out_bcount_nz(size)
+#define __inout_nz
+#define __inout_ecount_nz(size)
+#define __inout_bcount_nz(size)
+#define __in_nz_opt
+#define __in_ecount_nz_opt(size)
+#define __in_bcount_nz_opt(size)
+#define __out_ecount_nz_opt(size)
+#define __out_bcount_nz_opt(size)
+#define __inout_nz_opt
+#define __inout_ecount_nz_opt(size)
+#define __inout_bcount_nz_opt(size)
+#define __deref_out_nz
+#define __deref_out_ecount_nz(size)
+#define __deref_out_bcount_nz(size)
+#define __deref_inout_nz
+#define __deref_inout_ecount_nz(size)
+#define __deref_inout_bcount_nz(size)
+#define __deref_out_nz_opt
+#define __deref_out_ecount_nz_opt(size)
+#define __deref_out_bcount_nz_opt(size)
+#define __deref_inout_nz_opt
+#define __deref_inout_ecount_nz_opt(size)
+#define __deref_inout_bcount_nz_opt(size)
+#define __deref_opt_inout_nz
+#define __deref_opt_inout_ecount_nz(size)
+#define __deref_opt_inout_bcount_nz(size)
+#define __deref_opt_out_nz_opt
+#define __deref_opt_out_ecount_nz_opt(size)
+#define __deref_opt_out_bcount_nz_opt(size)
+#define __deref_opt_inout_nz_opt
+#define __deref_opt_inout_ecount_nz_opt(size)
+#define __deref_opt_inout_bcount_nz_opt(size)
+#define __deref
+#define __pre
+#define __post
+#define __readableTo(count)
+#define __writableTo(count)
+#define __maybevalid
+#define __inexpressible_readableTo(string)
+#define __data_entrypoint(category)
+#define __readonly
+#define __byte_writableTo(count)
+#define __byte_readableTo(count)
+#define __elem_readableTo(count)
+#define __elem_writableTo(count)
+#define __valid
+#define __notvalid
+#define __refparam
+#define __precond(condition)
+
+/*************************************************************************
+* Definitions to force a compile error when macros are used improperly.
+* Relies on VS 2005 source annotations.
+*************************************************************************/
+#if !defined(_MSC_EXTENSIONS) && !defined(_PREFAST_) && !defined(OACR)
+#define __allowed(p) /* nothing */
+#else
+#define __allowed(p) __$allowed_##p
+#define __$allowed_as_global_decl /* empty */
+#define __$allowed_as_statement_with_arg(x) \
+ __pragma(warning(push)) __pragma(warning(disable : 4548)) \
+ do {__noop(x);} while((0,0) __pragma(warning(pop)) )
+#define __$allowed_as_statement __$allowed_as_statement_with_arg(1)
+
+/**************************************************************************
+* This should go away. It's only for __success which we should split into.
+* __success and __typdecl_sucess
+***************************************************************************/
+#define __$allowed_on_function_or_typedecl /* empty */
+#if (__SPECSTRINGS_STRICT_LEVEL == 1) || (__SPECSTRINGS_STRICT_LEVEL == 2)
+#define __$allowed_on_typedecl /* empty */
+#define __$allowed_on_return /* empty */
+#define __$allowed_on_parameter /* empty */
+#define __$allowed_on_function /* empty */
+#define __$allowed_on_struct /* empty */
+#define __$allowed_on_field /* empty */
+#define __$allowed_on_parameter_or_return /* empty */
+#define __$allowed_on_global_or_field /* empty */
+#elif __SPECSTRINGS_STRICT_LEVEL == 3
+#define __$allowed_on_typedecl /* empty */
+/* Define dummy source attributes. Still needs more testing */
+#define __$allowed_on_return [returnvalue: OnReturnOnly]
+#define __$allowed_on_parameter [OnParameterOnly]
+#define __$allowed_on_function [method: OnFunctionOnly]
+#define __$allowed_on_struct [OnStructOnly]
+#define __$allowed_on_field [OnFieldOnly]
+#define __$allowed_on_parameter_or_return [OnParameterOrReturnOnly]
+#define __$allowed_on_global_or_field /* empty */
+#pragma push_macro( "DECL_SA" )
+#pragma push_macro( "SA" )
+#ifdef __cplusplus
+#define SA(x) x
+#define DECL_SA(name,loc) \
+ [repeatable] \
+ [source_annotation_attribute( loc )] \
+ struct name##Attribute { name##Attribute(); const char* ignored; };
+#else
+#define SA(x) SA_##x
+#define DECL_SA(name,loc) \
+ [source_annotation_attribute( loc )] \
+ struct name { const char* ignored; };\
+ typedef struct name name;
+#endif /* #endif __cplusplus */
+DECL_SA(OnParameterOnly,SA(Parameter));
+DECL_SA(OnReturnOnly,SA(ReturnValue));
+DECL_SA(OnFunctionOnly,SA(Method));
+DECL_SA(OnStructOnly,SA(Struct));
+DECL_SA(OnFieldOnly,SA(Field));
+DECL_SA(OnParameterOrReturnOnly,SA(Parameter) | SA(ReturnValue));
+#pragma pop_macro( "SA" )
+#pragma pop_macro( "DECL_SA" )
+#endif
+#endif
+#endif
diff --git a/src/pal/inc/rt/specstrings_undef.h b/src/pal/inc/rt/specstrings_undef.h
new file mode 100644
index 0000000000..b462dc2e25
--- /dev/null
+++ b/src/pal/inc/rt/specstrings_undef.h
@@ -0,0 +1,464 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*
+
+*/
+
+#ifndef PAL_STDCPP_COMPAT
+#undef __in
+#undef __out
+#endif // !PAL_STDCPP_COMPAT
+
+#undef _At_
+#undef _Deref_out_
+#undef _Deref_out_opt_
+#undef _Deref_opt_out_
+#undef _Deref_opt_out_opt_
+#undef _Deref_post_cap_
+#undef _Deref_post_opt_cap_
+#undef _Deref_post_bytecap_
+#undef _Deref_post_opt_bytecap_
+#undef _Deref_post_count_
+#undef _Deref_post_opt_count_
+#undef _Deref_post_bytecount_
+#undef _Deref_post_opt_bytecount_
+#undef _In_count_
+#undef _In_opt_count_
+#undef _In_bytecount_
+#undef _In_opt_bytecount_
+#undef _Out_cap_
+#undef _Out_opt_cap_
+#undef _Out_bytecap_
+#undef _Out_opt_bytecap_
+#undef _Outptr_
+#undef _Outptr_result_maybenull_
+#undef _Outptr_opt_
+#undef _Outptr_opt_result_maybenull_
+#undef _Outptr_result_z_
+#undef _Outptr_opt_result_z_
+#undef _Outptr_result_maybenull_z_
+#undef _Outptr_opt_result_maybenull_z_
+#undef _Outptr_result_nullonfailure_
+#undef _Outptr_opt_result_nullonfailure_
+#undef _COM_Outptr_
+#undef _COM_Outptr_result_maybenull_
+#undef _COM_Outptr_opt_
+#undef _COM_Outptr_opt_result_maybenull_
+#undef _Outptr_result_buffer_
+#undef _Outptr_opt_result_buffer_
+#undef _Outptr_result_buffer_to_
+#undef _Outptr_opt_result_buffer_to_
+#undef _Outptr_result_buffer_all_
+#undef _Outptr_opt_result_buffer_all_
+#undef _Outptr_result_buffer_maybenull_
+#undef _Outptr_opt_result_buffer_maybenull_
+#undef _Outptr_result_buffer_to_maybenull_
+#undef _Outptr_opt_result_buffer_to_maybenull_
+#undef _Outptr_result_buffer_all_maybenull_
+#undef _Outptr_opt_result_buffer_all_maybenull_
+#undef _Outptr_result_bytebuffer_
+#undef _Outptr_opt_result_bytebuffer_
+#undef _Outptr_result_bytebuffer_to_
+#undef _Outptr_opt_result_bytebuffer_to_
+#undef _Outptr_result_bytebuffer_all_
+#undef _Outptr_opt_result_bytebuffer_all_
+#undef _Outptr_result_bytebuffer_maybenull_
+#undef _Outptr_opt_result_bytebuffer_maybenull_
+#undef _Outptr_result_bytebuffer_to_maybenull_
+#undef _Outptr_opt_result_bytebuffer_to_maybenull_
+#undef _Outptr_result_bytebuffer_all_maybenull_
+#undef _Outptr_opt_result_bytebuffer_all_maybenull_
+#undef _When_
+#undef __allocator
+#undef __analysis_assert
+#undef __analysis_assume
+#undef __analysis_assume_nullterminated
+#undef __analysis_hint
+#undef __assume_bound
+#undef __assume_validated
+#undef __bcount
+#undef __bcount_opt
+#undef __blocksOn
+#undef __bound
+#undef __byte_readableTo
+#undef __byte_writableTo
+#undef __callback
+#undef __checkReturn
+#undef __class_code_content
+#undef __control_entrypoint
+#undef __data_entrypoint
+#undef __deallocate
+#undef __deallocate_opt
+#undef __deref
+#undef __deref_bcount
+#undef __deref_bcount_opt
+#undef __deref_ecount
+#undef __deref_ecount_opt
+#undef __deref_in
+#undef __deref_in_bcount
+#undef __deref_in_bcount_opt
+#undef __deref_in_ecount
+#undef __deref_in_ecount_opt
+#undef __deref_in_ecount_iterator
+#undef __deref_in_opt
+#undef __deref_in_opt_out
+#undef __deref_in_range
+#undef __deref_in_xcount
+#undef __deref_in_xcount_opt
+#undef __deref_inout
+#undef __deref_inout_bcount
+#undef __deref_inout_bcount_full
+#undef __deref_inout_bcount_full_opt
+#undef __deref_inout_bcount_nz
+#undef __deref_inout_bcount_nz_opt
+#undef __deref_inout_bcount_opt
+#undef __deref_inout_bcount_part
+#undef __deref_inout_bcount_part_opt
+#undef __deref_inout_bcount_z
+#undef __deref_inout_bcount_z_opt
+#undef __deref_inout_ecount
+#undef __deref_inout_ecount_full
+#undef __deref_inout_ecount_full_opt
+#undef __deref_inout_ecount_nz
+#undef __deref_inout_ecount_nz_opt
+#undef __deref_inout_ecount_opt
+#undef __deref_inout_ecount_part
+#undef __deref_inout_ecount_part_opt
+#undef __deref_inout_ecount_z
+#undef __deref_inout_ecount_z_opt
+#undef __deref_inout_ecount_iterator
+#undef __deref_inout_nz
+#undef __deref_inout_nz_opt
+#undef __deref_inout_opt
+#undef __deref_inout_range
+#undef __deref_inout_xcount
+#undef __deref_inout_xcount_full
+#undef __deref_inout_xcount_full_opt
+#undef __deref_inout_xcount_opt
+#undef __deref_inout_xcount_part
+#undef __deref_inout_xcount_part_opt
+#undef __deref_inout_z
+#undef __deref_inout_z_opt
+#undef __deref_nonvolatile
+#undef __deref_opt_bcount
+#undef __deref_opt_bcount_opt
+#undef __deref_opt_ecount
+#undef __deref_opt_ecount_opt
+#undef __deref_opt_in
+#undef __deref_opt_in_bcount
+#undef __deref_opt_in_bcount_opt
+#undef __deref_opt_in_ecount
+#undef __deref_opt_in_ecount_opt
+#undef __deref_opt_in_opt
+#undef __deref_opt_in_xcount
+#undef __deref_opt_in_xcount_opt
+#undef __deref_opt_inout
+#undef __deref_opt_inout_bcount
+#undef __deref_opt_inout_bcount_full
+#undef __deref_opt_inout_bcount_full_opt
+#undef __deref_opt_inout_bcount_nz
+#undef __deref_opt_inout_bcount_nz_opt
+#undef __deref_opt_inout_bcount_opt
+#undef __deref_opt_inout_bcount_part
+#undef __deref_opt_inout_bcount_part_opt
+#undef __deref_opt_inout_bcount_z
+#undef __deref_opt_inout_bcount_z_opt
+#undef __deref_opt_inout_ecount
+#undef __deref_opt_inout_ecount_full
+#undef __deref_opt_inout_ecount_full_opt
+#undef __deref_opt_inout_ecount_nz
+#undef __deref_opt_inout_ecount_nz_opt
+#undef __deref_opt_inout_ecount_opt
+#undef __deref_opt_inout_ecount_part
+#undef __deref_opt_inout_ecount_part_opt
+#undef __deref_opt_inout_ecount_z
+#undef __deref_opt_inout_ecount_z_opt
+#undef __deref_opt_inout_nz
+#undef __deref_opt_inout_nz_opt
+#undef __deref_opt_inout_opt
+#undef __deref_opt_inout_xcount
+#undef __deref_opt_inout_xcount_full
+#undef __deref_opt_inout_xcount_full_opt
+#undef __deref_opt_inout_xcount_opt
+#undef __deref_opt_inout_xcount_part
+#undef __deref_opt_inout_xcount_part_opt
+#undef __deref_opt_inout_z
+#undef __deref_opt_inout_z_opt
+#undef __deref_opt_out
+#undef __deref_opt_out_bcount
+#undef __deref_opt_out_bcount_full
+#undef __deref_opt_out_bcount_full_opt
+#undef __deref_opt_out_bcount_nz_opt
+#undef __deref_opt_out_bcount_opt
+#undef __deref_opt_out_bcount_part
+#undef __deref_opt_out_bcount_part_opt
+#undef __deref_opt_out_bcount_z_opt
+#undef __deref_opt_out_ecount
+#undef __deref_opt_out_ecount_full
+#undef __deref_opt_out_ecount_full_opt
+#undef __deref_opt_out_ecount_nz_opt
+#undef __deref_opt_out_ecount_opt
+#undef __deref_opt_out_ecount_part
+#undef __deref_opt_out_ecount_part_opt
+#undef __deref_opt_out_ecount_z_opt
+#undef __deref_opt_out_nz_opt
+#undef __deref_opt_out_opt
+#undef __deref_opt_out_xcount
+#undef __deref_opt_out_xcount_full
+#undef __deref_opt_out_xcount_full_opt
+#undef __deref_opt_out_xcount_opt
+#undef __deref_opt_out_xcount_part
+#undef __deref_opt_out_xcount_part_opt
+#undef __deref_opt_out_z_opt
+#undef __deref_opt_xcount
+#undef __deref_opt_xcount_opt
+#undef __deref_out
+#undef __deref_out_bcount
+#undef __deref_out_bcount_full
+#undef __deref_out_bcount_full_opt
+#undef __deref_out_bcount_nz
+#undef __deref_out_bcount_nz_opt
+#undef __deref_out_bcount_opt
+#undef __deref_out_bcount_part
+#undef __deref_out_bcount_part_opt
+#undef __deref_out_bcount_z
+#undef __deref_out_bcount_z_opt
+#undef __deref_out_bound
+#undef __deref_out_ecount
+#undef __deref_out_ecount_full
+#undef __deref_out_ecount_full_opt
+#undef __deref_out_ecount_iterator
+#undef __deref_out_ecount_nz
+#undef __deref_out_ecount_nz_opt
+#undef __deref_out_ecount_opt
+#undef __deref_out_ecount_part
+#undef __deref_out_ecount_part_opt
+#undef __deref_out_ecount_z
+#undef __deref_out_ecount_z_opt
+#undef __deref_out_nz
+#undef __deref_out_nz_opt
+#undef __deref_out_opt
+#undef __deref_out_range
+#undef __deref_out_range
+#undef __deref_out_xcount
+#undef __deref_out_xcount
+#undef __deref_out_xcount_full
+#undef __deref_out_xcount_full_opt
+#undef __deref_out_xcount_opt
+#undef __deref_out_xcount_part
+#undef __deref_out_xcount_part_opt
+#undef __deref_out_z
+#undef __deref_out_z_opt
+#undef __deref_realloc_bcount
+#undef __deref_volatile
+#undef __deref_xcount
+#undef __deref_xcount_opt
+#undef __ecount
+#undef __ecount_opt
+#undef __elem_readableTo
+#undef __elem_writableTo
+#undef __encoded_array
+#undef __encoded_pointer
+#undef __exceptthat
+#undef __fallthrough
+#undef __field_bcount
+#undef __field_bcount_full
+#undef __field_bcount_full_opt
+#undef __field_bcount_opt
+#undef __field_bcount_part
+#undef __field_bcount_part_opt
+#undef __field_data_source
+#undef __field_ecount
+#undef __field_ecount_full
+#undef __field_ecount_full_opt
+#undef __field_ecount_opt
+#undef __field_ecount_part
+#undef __field_ecount_part_opt
+#undef __field_encoded_array
+#undef __field_encoded_pointer
+#undef __field_nullterminated
+#undef __field_range
+#undef __field_xcount
+#undef __field_xcount_full
+#undef __field_xcount_full_opt
+#undef __field_xcount_opt
+#undef __field_xcount_part
+#undef __field_xcount_part_opt
+#undef __file_parser
+#undef __file_parser_class
+#undef __file_parser_library
+#undef __format_string
+#undef __format_string
+#undef __gdi_entry
+#undef __in_awcount
+#undef __in_bcount
+#undef __in_bcount_nz
+#undef __in_bcount_nz_opt
+#undef __in_bcount_opt
+#undef __in_bcount_z
+#undef __in_bcount_z_opt
+#undef __in_bound
+#undef __in_data_source
+#undef __in_ecount
+#undef __in_ecount_nz
+#undef __in_ecount_nz_opt
+#undef __in_ecount_opt
+#undef __in_ecount_z
+#undef __in_ecount_z_opt
+#undef __in_nz
+#undef __in_nz_opt
+#undef __in_opt
+#undef __in_range
+#undef __in_xcount
+#undef __in_xcount_opt
+#undef __in_z
+#undef __in_z_opt
+#undef __inexpressible_readableTo
+#undef __inexpressible_writableTo
+#undef __inner_adt_add_prop
+#undef __inner_adt_prop
+#undef __inner_adt_remove_prop
+#undef __inner_adt_transfer_prop
+#undef __inner_adt_type_props
+#undef __inner_analysis_assume_nulltermianted_dec
+#undef __inner_analysis_assume_nullterminated
+#undef __inner_assume_bound
+#undef __inner_assume_bound_dec
+#undef __inner_assume_validated
+#undef __inner_assume_validated_dec
+#undef __inner_blocksOn
+#undef __inner_bound
+#undef __inner_callback
+#undef __inner_checkReturn
+#undef __inner_compname_props
+#undef __inner_control_entrypoint
+#undef __inner_data_entrypoint
+#undef __inner_data_source
+#undef __inner_encoded
+#undef __inner_fallthrough
+#undef __inner_fallthrough_dec
+#undef __inner_nonvolatile
+#undef __inner_out_validated
+#undef __inner_override
+#undef __inner_possibly_notnullterminated
+#undef __inner_range
+#undef __inner_success
+#undef __inner_transfer
+#undef __inner_typefix
+#undef __inner_volatile
+#undef __inout
+#undef __inout_bcount
+#undef __inout_bcount_full
+#undef __inout_bcount_full_opt
+#undef __inout_bcount_nz
+#undef __inout_bcount_nz_opt
+#undef __inout_bcount_opt
+#undef __inout_bcount_part
+#undef __inout_bcount_part_opt
+#undef __inout_bcount_z
+#undef __inout_bcount_z_opt
+#undef __inout_ecount
+#undef __inout_ecount_full
+#undef __inout_ecount_full_opt
+#undef __inout_ecount_nz
+#undef __inout_ecount_nz_opt
+#undef __inout_ecount_opt
+#undef __inout_ecount_part
+#undef __inout_ecount_part_opt
+#undef __inout_ecount_z
+#undef __inout_ecount_z_opt
+#undef __inout_ecount_z_opt
+#undef __inout_nz
+#undef __inout_nz_opt
+#undef __inout_opt
+#undef __inout_xcount
+#undef __inout_xcount_full
+#undef __inout_xcount_full_opt
+#undef __inout_xcount_opt
+#undef __inout_xcount_part
+#undef __inout_xcount_part_opt
+#undef __inout_z
+#undef __inout_z_opt
+#undef __kernel_entry
+#undef __maybenull
+#undef __maybereadonly
+#undef __maybevalid
+#undef __range_max
+#undef __range_min
+#undef __nonvolatile
+#undef __notnull
+#undef __notreadonly
+#undef __notvalid
+#undef __null
+#undef __nullnullterminated
+#undef __nullterminated
+#undef __out_awcount
+#undef __out_bcount
+#undef __out_bcount_full
+#undef __out_bcount_full_opt
+#undef __out_bcount_nz
+#undef __out_bcount_nz_opt
+#undef __out_bcount_opt
+#undef __out_bcount_part
+#undef __out_bcount_part_opt
+#undef __out_bcount_z
+#undef __out_bcount_z_opt
+#undef __out_bound
+#undef __out_data_source
+#undef __out_ecount
+#undef __out_ecount_full
+#undef __out_ecount_full_opt
+#undef __out_ecount_nz
+#undef __out_ecount_nz_opt
+#undef __out_ecount_opt
+#undef __out_ecount_part
+#undef __out_ecount_part_opt
+#undef __out_ecount_z
+#undef __out_ecount_z_opt
+#undef __out_has_adt_prop
+#undef __out_has_type_adt_props
+#undef __out_not_has_adt_prop
+#undef __out_nz
+#undef __out_nz_opt
+#undef __out_opt
+#undef __out_range
+#undef __out_transfer_adt_prop
+#undef __out_validated
+#undef __out_xcount
+#undef __out_xcount_full
+#undef __out_xcount_full_opt
+#undef __out_xcount_opt
+#undef __out_xcount_part
+#undef __out_xcount_part_opt
+#undef __out_z
+#undef __override
+#undef __possibly_notnullterminated
+#undef __post
+#undef __post_invalid
+#undef __postcond
+#undef __post_nullnullterminated
+#undef __pre
+#undef __precond
+#undef __range
+#undef __readableTo
+#undef __readonly
+#undef __refparam
+#undef __reserved
+#undef __rpc_entry
+#undef __source_code_content
+#undef __struct_bcount
+#undef __struct_xcount
+#undef __success
+#undef __this_out_data_source
+#undef __this_out_validated
+#undef __transfer
+#undef __type_has_adt_prop
+#undef __typefix
+#undef __valid
+#undef __volatile
+#undef __writableTo
+#undef __xcount
+#undef __xcount_opt
+
diff --git a/src/pal/inc/rt/sscli_version.h b/src/pal/inc/rt/sscli_version.h
new file mode 100644
index 0000000000..3b31f4e6a5
--- /dev/null
+++ b/src/pal/inc/rt/sscli_version.h
@@ -0,0 +1,33 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+//
+// ===========================================================================
+// File: sscli_version.h
+//
+// ===========================================================================
+
+
+#ifndef __SSCLI_VERSION_H__
+#define __SSCLI_VERSION_H__
+
+#ifndef __RC_STRINGIZE__
+#define __RC_STRINGIZE__AUX(x) #x
+#define __RC_STRINGIZE__(x) __RC_STRINGIZE__AUX(x)
+#endif
+
+#ifndef __RC_STRINGIZE_WSZ__
+#define __RC_STRINGIZE_WSZ__AUX(x) L###x
+#define __RC_STRINGIZE_WSZ__(x) __RC_STRINGIZE_WSZ__AUX(x)
+#endif
+
+#define SSCLI_VERSION_MAJOR 2
+#define SSCLI_VERSION_MINOR 0
+#define SSCLI_VERSION_RELEASE 0001
+
+#define SSCLI_VERSION_STR __RC_STRINGIZE__(SSCLI_VERSION_MAJOR) "." __RC_STRINGIZE__(SSCLI_VERSION_MINOR) "." __RC_STRINGIZE__(SSCLI_VERSION_RELEASE)
+
+#define SSCLI_VERSION_STRW __RC_STRINGIZE_WSZ__(SSCLI_VERSION_MAJOR) L"." __RC_STRINGIZE_WSZ__(SSCLI_VERSION_MINOR) L"." __RC_STRINGIZE_WSZ__(SSCLI_VERSION_RELEASE)
+#endif // __SSCLI_VERSION_H__
diff --git a/src/pal/inc/rt/symcrypt.h b/src/pal/inc/rt/symcrypt.h
new file mode 100644
index 0000000000..33c24b2899
--- /dev/null
+++ b/src/pal/inc/rt/symcrypt.h
@@ -0,0 +1,13 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+//
+// ===========================================================================
+// File: symcrypt.h
+//
+// ===========================================================================
+// dummy symcrypt.h for PAL
+
+#include "palrt.h"
diff --git a/src/pal/inc/rt/tchar.h b/src/pal/inc/rt/tchar.h
new file mode 100644
index 0000000000..5401fabc13
--- /dev/null
+++ b/src/pal/inc/rt/tchar.h
@@ -0,0 +1,5 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#include "palrt.h"
diff --git a/src/pal/inc/rt/tlhelp32.h b/src/pal/inc/rt/tlhelp32.h
new file mode 100644
index 0000000000..721590d302
--- /dev/null
+++ b/src/pal/inc/rt/tlhelp32.h
@@ -0,0 +1,13 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+//
+// ===========================================================================
+// File: tlhelp32.h
+//
+// ===========================================================================
+// dummy tlhelp32.h for PAL
+
+#include "palrt.h"
diff --git a/src/pal/inc/rt/unknwn.h b/src/pal/inc/rt/unknwn.h
new file mode 100644
index 0000000000..1397cdbec9
--- /dev/null
+++ b/src/pal/inc/rt/unknwn.h
@@ -0,0 +1,66 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+//
+// ===========================================================================
+// File: unknwn.h
+//
+// ===========================================================================
+// simplified unknwn.h for PAL
+
+#include "rpc.h"
+#include "rpcndr.h"
+
+#ifndef __IUnknown_INTERFACE_DEFINED__
+#define __IUnknown_INTERFACE_DEFINED__
+
+typedef interface IUnknown IUnknown;
+
+typedef /* [unique] */ IUnknown *LPUNKNOWN;
+
+// 00000000-0000-0000-C000-000000000046
+EXTERN_C const IID IID_IUnknown;
+
+MIDL_INTERFACE("00000000-0000-0000-C000-000000000046")
+IUnknown
+{
+ virtual HRESULT STDMETHODCALLTYPE QueryInterface(
+ REFIID riid,
+ void **ppvObject) = 0;
+
+ virtual ULONG STDMETHODCALLTYPE AddRef( void) = 0;
+
+ virtual ULONG STDMETHODCALLTYPE Release( void) = 0;
+
+ template<class Q>
+ HRESULT
+ STDMETHODCALLTYPE
+ QueryInterface(Q** pp)
+ {
+ return QueryInterface(__uuidof(Q), (void **)pp);
+ }
+};
+
+#endif // __IUnknown_INTERFACE_DEFINED__
+
+#ifndef __IClassFactory_INTERFACE_DEFINED__
+#define __IClassFactory_INTERFACE_DEFINED__
+
+// 00000001-0000-0000-C000-000000000046
+EXTERN_C const IID IID_IClassFactory;
+
+MIDL_INTERFACE("00000001-0000-0000-C000-000000000046")
+IClassFactory : public IUnknown
+{
+ virtual HRESULT STDMETHODCALLTYPE CreateInstance(
+ IUnknown *pUnkOuter,
+ REFIID riid,
+ void **ppvObject) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE LockServer(
+ BOOL fLock) = 0;
+};
+
+#endif // __IClassFactory_INTERFACE_DEFINED__
diff --git a/src/pal/inc/rt/urlmon.h b/src/pal/inc/rt/urlmon.h
new file mode 100644
index 0000000000..827ad0d6ee
--- /dev/null
+++ b/src/pal/inc/rt/urlmon.h
@@ -0,0 +1,13 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+//
+// ===========================================================================
+// File: urlmon.h
+//
+// ===========================================================================
+// dummy urlmon.h for PAL
+
+#include "palrt.h"
diff --git a/src/pal/inc/rt/verrsrc.h b/src/pal/inc/rt/verrsrc.h
new file mode 100644
index 0000000000..78a53cf886
--- /dev/null
+++ b/src/pal/inc/rt/verrsrc.h
@@ -0,0 +1,13 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+//
+// ===========================================================================
+// File: verrsrc.h
+//
+// ===========================================================================
+// dummy verrsrc.h for PAL
+
+#include "palrt.h"
diff --git a/src/pal/inc/rt/vsassert.h b/src/pal/inc/rt/vsassert.h
new file mode 100644
index 0000000000..1f16cf1be7
--- /dev/null
+++ b/src/pal/inc/rt/vsassert.h
@@ -0,0 +1,98 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+//
+
+// This is a simple implementation of what's in vsassert.h in vscommon, since
+// we don't want to pull in the entire vsassert library.
+
+#ifndef __VSASSERT_H__
+#define __VSASSERT_H__
+
+#ifndef FEATURE_PAL
+#error "FEATURE_PAL must be defined for this file"
+#else // FEATURE_PAL
+
+#define VSASSERT(e, szMsg) \
+do { \
+ if (!(e)) { \
+ PAL_fprintf (stderr, \
+ "ASSERT FAILED:\n" \
+ "\tExpression: %s\n" \
+ "\tLocation: line %d in %s\n" \
+ "\tFunction: %s\n" \
+ "\tMessage: %s\n", \
+ #e, __LINE__, __FILE__, __FUNCTION__, szMsg); \
+ DebugBreak(); \
+ } \
+} while (0)
+
+#define VSFAIL(szMsg) VSASSERT(0, szMsg)
+#define VSIMPLIES(fHypothesis, fConclusion, szMsg) VSASSERT(!(fHypothesis) || (fConclusion), szMsg)
+#define VSVERIFY(fTest, szMsg) VSASSERT((fTest), (szMsg))
+
+#undef VSAlloc
+#undef VSAllocZero
+#undef VSRealloc
+#undef VSReallocZero
+#undef VSFree
+#undef VSSize
+#undef VsDebAlloc
+#undef VsDebRealloc
+#undef VsDebSafeRealloc
+#undef VsDebFree
+#undef VsDebHeapSize
+
+#undef VsDebHeapCreate
+#undef VsDebHeapDestroy
+
+#undef VsDebugInitialize
+#undef VsDebugTerminate
+
+// NOTE: These have changed to use the HeapAlloc family (as opposed to
+// LocalAlloc family) because of HeapReAlloc's behavior (a block may move to
+// satisfy a realloc request, as opposed to LocalReAlloc's behavior of simply
+// failing).
+
+#define VSAlloc(cb) HeapAlloc(GetProcessHeap(), 0, cb)
+#define VSAllocZero(cb) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cb)
+#define VSRealloc(pv, cb) HeapReAlloc(GetProcessHeap(), 0, pv, cb)
+#define VSReallocZero(pv,cb) Rotors_pal_doesnt_have_vsrealloczero
+#define VSFree(pv) HeapFree(GetProcessHeap(), 0, pv)
+#define VSSize(pv) Rotors_pal_doesnt_have_heapsize
+
+#define VsDebAlloc(flags,cb) VSAlloc(cb)
+#define VsDebRealloc(pv,flags,cb) VSRealloc(pv,cb)
+#define VsDebSafeRealloc(pv,flags,cb) Rotors_pal_doenst_have_saferealloc
+#define VsDebFree(pv) VSFree(pv)
+#define VsDebHeapSize(heap, pv) VSSize(pv)
+
+#define VsDebHeapCreate(flags, name) Rotor_doesnt_have_heapcreate
+#define VsDebHeapDestroy(heap, fLeakCheck) Rotor_doesnt_have_heapdestroy
+
+#define VsDebugAllocInternal(hheap,dwFlags,cb,pszFile,uLine,dwInst,pszExtra) \
+ HeapAlloc(GetProcessHeap(), dwFlags, cb)
+
+#define DEFAULT_HEAP 0
+#define INSTANCE_GLOBAL 0
+
+#define VsDebugInitialize() do {} while (0)
+#define VsDebugTerminate() do {} while (0)
+
+
+// Debug switches
+//
+#define DEFINE_SWITCH(NAME, PACKAGE, DESC) VSDEFINE_SWITCH(NAME, PACKAGE, DESC)
+#define EXTERN_SWITCH(NAME) VSEXTERN_SWITCH(NAME)
+#define FSWITCH(NAME) VSFSWITCH(NAME)
+
+#define VSDEFINE_SWITCH(NAME, PACKAGE, DESC)
+#define VSEXTERN_SWITCH(NAME)
+#define VSFSWITCH(NAME) FALSE
+
+#define VsIgnoreAllocs(f)
+
+#endif // FEATURE_PAL
+#endif // __VSASSERT_H__
diff --git a/src/pal/inc/rt/winapifamily.h b/src/pal/inc/rt/winapifamily.h
new file mode 100644
index 0000000000..234a07bb0b
--- /dev/null
+++ b/src/pal/inc/rt/winapifamily.h
@@ -0,0 +1,40 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+//
+// ===========================================================================
+// File: windows.h
+//
+// ===========================================================================
+// dummy winapifamily.h for PAL
+
+#ifndef _INC_WINAPIFAMILY
+#define _INC_WINAPIFAMILY
+
+//
+// Windows APIs can be placed in a partition represented by one of the below bits. The
+// WINAPI_FAMILY value determines which partitions are available to the client code.
+//
+
+#define WINAPI_PARTITION_DESKTOP 0x00000001
+#define WINAPI_PARTITION_APP 0x00000002
+
+// A family may be defined as the union of multiple families. WINAPI_FAMILY should be set
+// to one of these values.
+#define WINAPI_FAMILY_APP WINAPI_PARTITION_APP
+#define WINAPI_FAMILY_DESKTOP_APP (WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_APP)
+
+// Provide a default for WINAPI_FAMILY if needed.
+#ifndef WINAPI_FAMILY
+#define WINAPI_FAMILY WINAPI_FAMILY_DESKTOP_APP
+#endif
+
+// Macro to determine if a partition is enabled
+#define WINAPI_FAMILY_PARTITION(Partition) ((WINAPI_FAMILY & Partition) == Partition)
+
+// Macro to determine if only one partition is enabled from a set
+#define WINAPI_FAMILY_ONE_PARTITION(PartitionSet, Partition) ((WINAPI_FAMILY & PartitionSet) == Partition)
+
+#endif
diff --git a/src/pal/inc/rt/winbase.h b/src/pal/inc/rt/winbase.h
new file mode 100644
index 0000000000..af9de7c63f
--- /dev/null
+++ b/src/pal/inc/rt/winbase.h
@@ -0,0 +1,13 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+//
+// ===========================================================================
+// File: winbase.h
+//
+// ===========================================================================
+// dummy winbase.h for PAL
+
+#include "palrt.h"
diff --git a/src/pal/inc/rt/wincrypt.h b/src/pal/inc/rt/wincrypt.h
new file mode 100644
index 0000000000..71caa7d07d
--- /dev/null
+++ b/src/pal/inc/rt/wincrypt.h
@@ -0,0 +1,13 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+//
+// ===========================================================================
+// File: wincrypt.h
+//
+// ===========================================================================
+// dummy wincrypt.h for PAL
+
+#include "palrt.h"
diff --git a/src/pal/inc/rt/windef.h b/src/pal/inc/rt/windef.h
new file mode 100644
index 0000000000..2ab50f256f
--- /dev/null
+++ b/src/pal/inc/rt/windef.h
@@ -0,0 +1,13 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+//
+// ===========================================================================
+// File: windef.h
+//
+// ===========================================================================
+// dummy windef.h for PAL
+
+#include "palrt.h"
diff --git a/src/pal/inc/rt/windows.h b/src/pal/inc/rt/windows.h
new file mode 100644
index 0000000000..802fde15e9
--- /dev/null
+++ b/src/pal/inc/rt/windows.h
@@ -0,0 +1,13 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+//
+// ===========================================================================
+// File: windows.h
+//
+// ===========================================================================
+// dummy windows.h for PAL
+
+#include "palrt.h"
diff --git a/src/pal/inc/rt/winerror.h b/src/pal/inc/rt/winerror.h
new file mode 100644
index 0000000000..e8eeed9ced
--- /dev/null
+++ b/src/pal/inc/rt/winerror.h
@@ -0,0 +1,13 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+//
+// ===========================================================================
+// File: winerror.h
+//
+// ===========================================================================
+// dummy winerror.h for PAL
+
+#include "palrt.h"
diff --git a/src/pal/inc/rt/wininet.h b/src/pal/inc/rt/wininet.h
new file mode 100644
index 0000000000..e41482fc32
--- /dev/null
+++ b/src/pal/inc/rt/wininet.h
@@ -0,0 +1,13 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+//
+// ===========================================================================
+// File: wininet.h
+//
+// ===========================================================================
+// dummy wininet.h for PAL
+
+#include "palrt.h"
diff --git a/src/pal/inc/rt/winnls.h b/src/pal/inc/rt/winnls.h
new file mode 100644
index 0000000000..57bb2415d5
--- /dev/null
+++ b/src/pal/inc/rt/winnls.h
@@ -0,0 +1,13 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+//
+// ===========================================================================
+// File: winnls.h
+//
+// ===========================================================================
+// dummy winnls.h for PAL
+
+#include "palrt.h"
diff --git a/src/pal/inc/rt/winnt.h b/src/pal/inc/rt/winnt.h
new file mode 100644
index 0000000000..600338ce2e
--- /dev/null
+++ b/src/pal/inc/rt/winnt.h
@@ -0,0 +1,13 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+//
+// ===========================================================================
+// File: winnt.h
+//
+// ===========================================================================
+// dummy winnt.h for PAL
+
+#include "palrt.h"
diff --git a/src/pal/inc/rt/winresrc.h b/src/pal/inc/rt/winresrc.h
new file mode 100644
index 0000000000..b8d92706ad
--- /dev/null
+++ b/src/pal/inc/rt/winresrc.h
@@ -0,0 +1,15 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+//
+// ===========================================================================
+// File: winresrc.h
+//
+// ===========================================================================
+// winresrc.h for PAL
+// Included in .rc files.
+
+#include "winver.h"
+#include "palrt.h"
diff --git a/src/pal/inc/rt/winternl.h b/src/pal/inc/rt/winternl.h
new file mode 100644
index 0000000000..476e40de0c
--- /dev/null
+++ b/src/pal/inc/rt/winternl.h
@@ -0,0 +1,13 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+//
+// ===========================================================================
+// File: winternl.h
+//
+// ===========================================================================
+// dummy winternl.h for PAL
+
+#include "palrt.h"
diff --git a/src/pal/inc/rt/winuser.h b/src/pal/inc/rt/winuser.h
new file mode 100644
index 0000000000..fc19f9a55d
--- /dev/null
+++ b/src/pal/inc/rt/winuser.h
@@ -0,0 +1,13 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+//
+// ===========================================================================
+// File: winuser.h
+//
+// ===========================================================================
+// dummy winuser.h for PAL
+
+#include "palrt.h"
diff --git a/src/pal/inc/rt/winver.h b/src/pal/inc/rt/winver.h
new file mode 100644
index 0000000000..b315280ef7
--- /dev/null
+++ b/src/pal/inc/rt/winver.h
@@ -0,0 +1,30 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+//
+// ===========================================================================
+// File: winver.h
+//
+// ===========================================================================
+// winver.h for PAL
+// Included in .rc files.
+
+#define VS_VERSION_INFO 1
+#define VS_FFI_FILEFLAGSMASK 0x0000003FL
+
+#define VS_FF_DEBUG 0x00000001L
+#define VS_FF_PRERELEASE 0x00000002L
+#define VS_FF_PATCHED 0x00000004L
+#define VS_FF_PRIVATEBUILD 0x00000008L
+#define VS_FF_INFOINFERRED 0x00000010L
+#define VS_FF_SPECIALBUILD 0x00000020L
+
+#define VFT_UNKNOWN 0x00000000L
+#define VFT_APP 0x00000001L
+#define VFT_DLL 0x00000002L
+
+#define VFT2_UNKNOWN 0x00000000L
+
+#define VOS__WINDOWS32 0x00000004L
diff --git a/src/pal/inc/rt/wtsapi32.h b/src/pal/inc/rt/wtsapi32.h
new file mode 100644
index 0000000000..0e41b15abf
--- /dev/null
+++ b/src/pal/inc/rt/wtsapi32.h
@@ -0,0 +1,13 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+//
+// ===========================================================================
+// File: wtsapi32.h
+//
+// ===========================================================================
+// dummy wtsapi32.h for PAL
+
+#include "palrt.h"
diff --git a/src/pal/inc/rt/xmmintrin.h b/src/pal/inc/rt/xmmintrin.h
new file mode 100644
index 0000000000..5401fabc13
--- /dev/null
+++ b/src/pal/inc/rt/xmmintrin.h
@@ -0,0 +1,5 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#include "palrt.h"
diff --git a/src/pal/inc/strsafe.h b/src/pal/inc/strsafe.h
new file mode 100644
index 0000000000..5a9f0edd43
--- /dev/null
+++ b/src/pal/inc/strsafe.h
@@ -0,0 +1,6265 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+
+
+--*/
+
+/******************************************************************
+* *
+* strsafe.h -- This module defines safer C library string *
+* routine replacements. These are meant to make C *
+* a bit more safe in reference to security and *
+* robustness *
+* *
+******************************************************************/
+#ifndef _STRSAFE_H_INCLUDED_
+#define _STRSAFE_H_INCLUDED_
+#ifdef _MSC_VER
+#pragma once
+#endif
+
+#if defined(PLATFORM_UNIX) && !defined (FEATURE_PAL)
+#define _NATIVE_WCHAR_T_DEFINED
+#endif // defined(PLATFORM_UNIX) && !defined (FEATURE_PAL)
+
+#if defined(PLATFORM_UNIX) && !defined (FEATURE_PAL)
+#define _vsnprintf vsnprintf
+#endif // defined(PLATFORM_UNIX) && !defined (FEATURE_PAL)
+
+#include <stdio.h> // for _vsnprintf, _vsnwprintf, getc, getwc
+#include <string.h> // for memset
+#include <stdarg.h> // for va_start, etc.
+
+#ifndef _SIZE_T_DEFINED
+#ifdef _WIN64
+typedef unsigned __int64 size_t;
+#else
+typedef __w64 unsigned int size_t;
+#endif // !_WIN64
+#define _SIZE_T_DEFINED
+#endif // !_SIZE_T_DEFINED
+
+#if !defined(_WCHAR_T_DEFINED) && !defined(_NATIVE_WCHAR_T_DEFINED)
+#error Unexpected define.
+typedef char16_t WCHAR;
+#define _WCHAR_T_DEFINED
+#endif
+
+#ifndef FEATURE_PAL
+#ifndef _HRESULT_DEFINED
+#define _HRESULT_DEFINED
+typedef LONG HRESULT;
+#endif // !_HRESULT_DEFINED
+#endif // !FEATURE_PAL
+
+#ifndef SUCCEEDED
+#define SUCCEEDED(hr) ((HRESULT)(hr) >= 0)
+#endif
+
+#ifndef FAILED
+#define FAILED(hr) ((HRESULT)(hr) < 0)
+#endif
+
+#ifndef S_OK
+#define S_OK ((HRESULT)0x00000000L)
+#endif
+
+#ifdef __cplusplus
+#define _STRSAFE_EXTERN_C extern "C"
+#else
+#define _STRSAFE_EXTERN_C extern
+#endif
+
+// If you do not want to use these functions inline (and instead want to link w/ strsafe.lib), then
+// #define STRSAFE_LIB before including this header file.
+#if defined(STRSAFE_LIB)
+#define STRSAFEAPI _STRSAFE_EXTERN_C HRESULT __stdcall
+#pragma comment(lib, "strsafe.lib")
+#elif defined(STRSAFE_LIB_IMPL)
+#define STRSAFEAPI _STRSAFE_EXTERN_C HRESULT __stdcall
+#else
+#define STRSAFEAPI __inline HRESULT __stdcall
+#define STRSAFE_INLINE
+#endif
+
+// Some functions always run inline because they use stdin and we want to avoid building multiple
+// versions of strsafe lib depending on if you use msvcrt, libcmt, etc.
+#define STRSAFE_INLINE_API __inline HRESULT __stdcall
+
+// The user can request no "Cb" or no "Cch" fuctions, but not both!
+#if defined(STRSAFE_NO_CB_FUNCTIONS) && defined(STRSAFE_NO_CCH_FUNCTIONS)
+#error cannot specify both STRSAFE_NO_CB_FUNCTIONS and STRSAFE_NO_CCH_FUNCTIONS !!
+#endif
+
+// This should only be defined when we are building strsafe.lib
+#ifdef STRSAFE_LIB_IMPL
+#define STRSAFE_INLINE
+#endif
+
+
+#define STRSAFE_MAX_CCH 2147483647 // max # of characters we support (same as INT_MAX)
+
+// STRSAFE error return codes
+//
+#define STRSAFE_E_INSUFFICIENT_BUFFER ((HRESULT)0x8007007AL) // 0x7A = 122L = ERROR_INSUFFICIENT_BUFFER
+#define STRSAFE_E_INVALID_PARAMETER ((HRESULT)0x80070057L) // 0x57 = 87L = ERROR_INVALID_PARAMETER
+#define STRSAFE_E_END_OF_FILE ((HRESULT)0x80070026L) // 0x26 = 38L = ERROR_HANDLE_EOF
+
+// Flags for controling the Ex functions
+//
+// STRSAFE_FILL_BYTE(0xFF) 0x000000FF // bottom byte specifies fill pattern
+#define STRSAFE_IGNORE_NULLS 0x00000100 // treat null as TEXT("") -- don't fault on NULL buffers
+#define STRSAFE_FILL_BEHIND_NULL 0x00000200 // fill in extra space behind the null terminator
+#define STRSAFE_FILL_ON_FAILURE 0x00000400 // on failure, overwrite pszDest with fill pattern and null terminate it
+#define STRSAFE_NULL_ON_FAILURE 0x00000800 // on failure, set *pszDest = TEXT('\0')
+#define STRSAFE_NO_TRUNCATION 0x00001000 // instead of returning a truncated result, copy/append nothing to pszDest and null terminate it
+
+#define STRSAFE_VALID_FLAGS (0x000000FF | STRSAFE_IGNORE_NULLS | STRSAFE_FILL_BEHIND_NULL | STRSAFE_FILL_ON_FAILURE | STRSAFE_NULL_ON_FAILURE | STRSAFE_NO_TRUNCATION)
+
+// helper macro to set the fill character and specify buffer filling
+#define STRSAFE_FILL_BYTE(x) ((unsigned long)((x & 0x000000FF) | STRSAFE_FILL_BEHIND_NULL))
+#define STRSAFE_FAILURE_BYTE(x) ((unsigned long)((x & 0x000000FF) | STRSAFE_FILL_ON_FAILURE))
+
+#define STRSAFE_GET_FILL_PATTERN(dwFlags) ((int)(dwFlags & 0x000000FF))
+
+// prototypes for the worker functions
+#ifdef STRSAFE_INLINE
+STRSAFEAPI StringCopyWorkerA(char* pszDest, size_t cchDest, const char* pszSrc);
+STRSAFEAPI StringCopyWorkerW(WCHAR* pszDest, size_t cchDest, const WCHAR* pszSrc);
+STRSAFEAPI StringCopyExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, const char* pszSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
+STRSAFEAPI StringCopyExWorkerW(WCHAR* pszDest, size_t cchDest, size_t cbDest, const WCHAR* pszSrc, WCHAR** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
+STRSAFEAPI StringCopyNWorkerA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchSrc);
+STRSAFEAPI StringCopyNWorkerW(WCHAR* pszDest, size_t cchDest, const WCHAR* pszSrc, size_t cchSrc);
+STRSAFEAPI StringCopyNExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, const char* pszSrc, size_t cchSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
+STRSAFEAPI StringCopyNExWorkerW(WCHAR* pszDest, size_t cchDest, size_t cbDest, const WCHAR* pszSrc, size_t cchSrc, WCHAR** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
+STRSAFEAPI StringCatWorkerA(char* pszDest, size_t cchDest, const char* pszSrc);
+STRSAFEAPI StringCatWorkerW(WCHAR* pszDest, size_t cchDest, const WCHAR* pszSrc);
+STRSAFEAPI StringCatExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, const char* pszSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
+STRSAFEAPI StringCatExWorkerW(WCHAR* pszDest, size_t cchDest, size_t cbDest, const WCHAR* pszSrc, WCHAR** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
+STRSAFEAPI StringCatNWorkerA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchMaxAppend);
+STRSAFEAPI StringCatNWorkerW(WCHAR* pszDest, size_t cchDest, const WCHAR* pszSrc, size_t cchMaxAppend);
+STRSAFEAPI StringCatNExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, const char* pszSrc, size_t cchMaxAppend, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
+STRSAFEAPI StringCatNExWorkerW(WCHAR* pszDest, size_t cchDest, size_t cbDest, const WCHAR* pszSrc, size_t cchMaxAppend, WCHAR** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
+STRSAFEAPI StringVPrintfWorkerA(char* pszDest, size_t cchDest, const char* pszFormat, va_list argList);
+STRSAFEAPI StringVPrintfWorkerW(WCHAR* pszDest, size_t cchDest, const WCHAR* pszFormat, va_list argList);
+STRSAFEAPI StringVPrintfExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const char* pszFormat, va_list argList);
+STRSAFEAPI StringVPrintfExWorkerW(WCHAR* pszDest, size_t cchDest, size_t cbDest, WCHAR** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const WCHAR* pszFormat, va_list argList);
+STRSAFEAPI StringLengthWorkerA(const char* psz, size_t cchMax, size_t* pcch);
+STRSAFEAPI StringLengthWorkerW(const WCHAR* psz, size_t cchMax, size_t* pcch);
+#endif // STRSAFE_INLINE
+
+#ifndef STRSAFE_LIB_IMPL
+#ifndef FEATURE_PAL
+// these functions are always inline
+STRSAFE_INLINE_API StringGetsExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
+STRSAFE_INLINE_API StringGetsExWorkerW(WCHAR* pszDest, size_t cchDest, size_t cbDest, WCHAR** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
+#endif // !FEATURE_PAL
+#endif
+
+#ifndef STRSAFE_NO_CCH_FUNCTIONS
+/*++
+
+STDAPI StringCchCopy(LPTSTR pszDest,
+ size_t cchDest,
+ LPCTSTR pszSrc);
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'strcpy'.
+ The size of the destination buffer (in characters) is a parameter and
+ this function will not write past the end of this buffer and it will
+ ALWAYS null terminate the destination buffer (unless it is zero length).
+
+ This routine is not a replacement for strncpy. That function will pad the
+ destination string with extra null termination characters if the count is
+ greater than the length of the source string, and it will fail to null
+ terminate the destination string if the source string length is greater
+ than or equal to the count. You can not blindly use this instead of strncpy:
+ it is common for code to use it to "patch" strings and you would introduce
+ errors if the code started null terminating in the middle of the string.
+
+ This function returns a hresult, and not a pointer. It returns a S_OK
+ if the string was copied without truncation and null terminated, otherwise
+ it will return a failure code. In failure cases as much of pszSrc will be
+ copied to pszDest as possible, and pszDest will be null terminated.
+
+Arguments:
+
+ pszDest - destination string
+
+ cchDest - size of destination buffer in characters.
+ length must be = (_tcslen(src) + 1) to hold all of the
+ source including the null terminator
+
+ pszSrc - source string which must be null terminated
+
+Notes:
+ Behavior is undefined if source and destination strings overlap.
+
+ pszDest and pszSrc should not be NULL. See StringCchCopyEx if you require
+ the handling of NULL values.
+
+Return Value:
+
+ S_OK - if there was source data and it was all copied and the
+ resultant dest string was null terminated
+
+ failure - you can use the macro HRESULT_CODE() to get a win32 error
+ code for all hresult falure cases
+
+ STRSAFE_E_INSUFFICIENT_BUFFER /
+ HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
+ - this return value is an indication that the copy operation
+ failed due to insufficient space. When this error occurs,
+ the destination buffer is modified to contain a truncated
+ version of the ideal result and is null terminated. This
+ is useful for situations where truncation is ok
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function.
+
+--*/
+
+STRSAFEAPI StringCchCopyA(char* pszDest, size_t cchDest, const char* pszSrc);
+STRSAFEAPI StringCchCopyW(WCHAR* pszDest, size_t cchDest, const WCHAR* pszSrc);
+#ifdef UNICODE
+#define StringCchCopy StringCchCopyW
+#else
+#define StringCchCopy StringCchCopyA
+#endif // !UNICODE
+
+#ifdef STRSAFE_INLINE
+STRSAFEAPI StringCchCopyA(char* pszDest, size_t cchDest, const char* pszSrc)
+{
+ HRESULT hr;
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringCopyWorkerA(pszDest, cchDest, pszSrc);
+ }
+
+ return hr;
+}
+
+#if defined(FEATURE_PAL) || !defined(PLATFORM_UNIX)
+STRSAFEAPI StringCchCopyW(WCHAR* pszDest, size_t cchDest, const WCHAR* pszSrc)
+{
+ HRESULT hr;
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringCopyWorkerW(pszDest, cchDest, pszSrc);
+ }
+
+ return hr;
+}
+#endif // FEATURE_PAL || !PLATFORM_UNIX
+#endif // STRSAFE_INLINE
+#endif // !STRSAFE_NO_CCH_FUNCTIONS
+
+
+#ifndef STRSAFE_NO_CB_FUNCTIONS
+/*++
+
+STDAPI StringCbCopy(LPTSTR pszDest,
+ size_t cbDest,
+ LPCTSTR pszSrc);
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'strcpy'.
+ The size of the destination buffer (in bytes) is a parameter and this
+ function will not write past the end of this buffer and it will ALWAYS
+ null terminate the destination buffer (unless it is zero length).
+
+ This routine is not a replacement for strncpy. That function will pad the
+ destination string with extra null termination characters if the count is
+ greater than the length of the source string, and it will fail to null
+ terminate the destination string if the source string length is greater
+ than or equal to the count. You can not blindly use this instead of strncpy:
+ it is common for code to use it to "patch" strings and you would introduce
+ errors if the code started null terminating in the middle of the string.
+
+ This function returns a hresult, and not a pointer. It returns a S_OK
+ if the string was copied without truncation and null terminated, otherwise
+ it will return a failure code. In failure cases as much of pszSrc will be
+ copied to pszDest as possible, and pszDest will be null terminated.
+
+Arguments:
+
+ pszDest - destination string
+
+ cbDest - size of destination buffer in bytes.
+ length must be = ((_tcslen(src) + 1) * sizeof(TCHAR)) to
+ hold all of the source including the null terminator
+
+ pszSrc - source string which must be null terminated
+
+Notes:
+ Behavior is undefined if source and destination strings overlap.
+
+ pszDest and pszSrc should not be NULL. See StringCbCopyEx if you require
+ the handling of NULL values.
+
+Return Value:
+
+ S_OK - if there was source data and it was all copied and the
+ resultant dest string was null terminated
+
+ failure - you can use the macro HRESULT_CODE() to get a win32 error
+ code for all hresult falure cases
+
+ STRSAFE_E_INSUFFICIENT_BUFFER /
+ HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
+ - this return value is an indication that the copy operation
+ failed due to insufficient space. When this error occurs,
+ the destination buffer is modified to contain a truncated
+ version of the ideal result and is null terminated. This
+ is useful for situations where truncation is ok
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function.
+
+--*/
+
+STRSAFEAPI StringCbCopyA(char* pszDest, size_t cbDest, const char* pszSrc);
+STRSAFEAPI StringCbCopyW(WCHAR* pszDest, size_t cbDest, const WCHAR* pszSrc);
+#ifdef UNICODE
+#define StringCbCopy StringCbCopyW
+#else
+#define StringCbCopy StringCbCopyA
+#endif // !UNICODE
+
+#ifdef STRSAFE_INLINE
+STRSAFEAPI StringCbCopyA(char* pszDest, size_t cbDest, const char* pszSrc)
+{
+ HRESULT hr;
+ size_t cchDest;
+
+ // convert to count of characters
+ cchDest = cbDest / sizeof(char);
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringCopyWorkerA(pszDest, cchDest, pszSrc);
+ }
+
+ return hr;
+}
+
+#if defined(FEATURE_PAL) || !defined(PLATFORM_UNIX)
+STRSAFEAPI StringCbCopyW(WCHAR* pszDest, size_t cbDest, const WCHAR* pszSrc)
+{
+ HRESULT hr;
+ size_t cchDest;
+
+ // convert to count of characters
+ cchDest = cbDest / sizeof(WCHAR);
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringCopyWorkerW(pszDest, cchDest, pszSrc);
+ }
+
+ return hr;
+}
+#endif // FEATURE_PAL || !PLATFORM_UNIX
+#endif // STRSAFE_INLINE
+#endif // !STRSAFE_NO_CB_FUNCTIONS
+
+
+#ifndef STRSAFE_NO_CCH_FUNCTIONS
+/*++
+
+STDAPI StringCchCopyEx(TCHAR pszDest,
+ size_t cchDest,
+ LPCTSTR pszSrc,
+ LPTSTR* ppszDestEnd,
+ size_t* pcchRemaining,
+ DWORD dwFlags);
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'strcpy' with
+ some additional parameters. In addition to functionality provided by
+ StringCchCopy, this routine also returns a pointer to the end of the
+ destination string and the number of characters left in the destination string
+ including the null terminator. The flags parameter allows additional controls.
+
+Arguments:
+
+ pszDest - destination string
+
+ cchDest - size of destination buffer in characters.
+ length must be = (_tcslen(pszSrc) + 1) to hold all of
+ the source including the null terminator
+
+ pszSrc - source string which must be null terminated
+
+ ppszDestEnd - if ppszDestEnd is non-null, the function will return a
+ pointer to the end of the destination string. If the
+ function copied any data, the result will point to the
+ null termination character
+
+ pcchRemaining - if pcchRemaining is non-null, the function will return the
+ number of characters left in the destination string,
+ including the null terminator
+
+ dwFlags - controls some details of the string copy:
+
+ STRSAFE_FILL_BEHIND_NULL
+ if the function succeeds, the low byte of dwFlags will be
+ used to fill the uninitialize part of destination buffer
+ behind the null terminator
+
+ STRSAFE_IGNORE_NULLS
+ treat NULL string pointers like empty strings (TEXT("")).
+ this flag is useful for emulating functions like lstrcpy
+
+ STRSAFE_FILL_ON_FAILURE
+ if the function fails, the low byte of dwFlags will be
+ used to fill all of the destination buffer, and it will
+ be null terminated. This will overwrite any truncated
+ string returned when the failure is
+ STRSAFE_E_INSUFFICIENT_BUFFER
+
+ STRSAFE_NO_TRUNCATION /
+ STRSAFE_NULL_ON_FAILURE
+ if the function fails, the destination buffer will be set
+ to the empty string. This will overwrite any truncated string
+ returned when the failure is STRSAFE_E_INSUFFICIENT_BUFFER.
+
+Notes:
+ Behavior is undefined if source and destination strings overlap.
+
+ pszDest and pszSrc should not be NULL unless the STRSAFE_IGNORE_NULLS flag
+ is specified. If STRSAFE_IGNORE_NULLS is passed, both pszDest and pszSrc
+ may be NULL. An error may still be returned even though NULLS are ignored
+ due to insufficient space.
+
+Return Value:
+
+ S_OK - if there was source data and it was all copied and the
+ resultant dest string was null terminated
+
+ failure - you can use the macro HRESULT_CODE() to get a win32 error
+ code for all falure cases
+
+ STRSAFE_E_INSUFFICIENT_BUFFER /
+ HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
+ - this return value is an indication that the copy operation
+ failed due to insufficient space. When this error occurs,
+ the destination buffer is modified to contain a truncated
+ version of the ideal result and is null terminated. This
+ is useful for situations where truncation is ok.
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function
+
+--*/
+
+STRSAFEAPI StringCchCopyExA(char* pszDest, size_t cchDest, const char* pszSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
+STRSAFEAPI StringCchCopyExW(WCHAR* pszDest, size_t cchDest, const WCHAR* pszSrc, WCHAR** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
+#ifdef UNICODE
+#define StringCchCopyEx StringCchCopyExW
+#else
+#define StringCchCopyEx StringCchCopyExA
+#endif // !UNICODE
+
+#ifdef STRSAFE_INLINE
+STRSAFEAPI StringCchCopyExA(char* pszDest, size_t cchDest, const char* pszSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
+{
+ HRESULT hr;
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ size_t cbDest;
+
+ // safe to multiply cchDest * sizeof(char) since cchDest < STRSAFE_MAX_CCH and sizeof(char) is 1
+ cbDest = cchDest * sizeof(char);
+
+ hr = StringCopyExWorkerA(pszDest, cchDest, cbDest, pszSrc, ppszDestEnd, pcchRemaining, dwFlags);
+ }
+
+ return hr;
+}
+
+#if defined(FEATURE_PAL) || !defined(PLATFORM_UNIX)
+STRSAFEAPI StringCchCopyExW(WCHAR* pszDest, size_t cchDest, const WCHAR* pszSrc, WCHAR** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
+{
+ HRESULT hr;
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ size_t cbDest;
+
+ // safe to multiply cchDest * sizeof(WCHAR) since cchDest < STRSAFE_MAX_CCH and sizeof(WCHAR) is 2
+ cbDest = cchDest * sizeof(WCHAR);
+
+ hr = StringCopyExWorkerW(pszDest, cchDest, cbDest, pszSrc, ppszDestEnd, pcchRemaining, dwFlags);
+ }
+
+ return hr;
+}
+#endif // FEATURE_PAL || !PLATFORM_UNIX
+#endif // STRSAFE_INLINE
+#endif // !STRSAFE_NO_CCH_FUNCTIONS
+
+
+#ifndef STRSAFE_NO_CB_FUNCTIONS
+/*++
+
+STDAPI StringCbCopyEx(TCHAR pszDest,
+ size_t cbDest,
+ LPCTSTR pszSrc,
+ LPTSTR* ppszDestEnd,
+ size_t* pcbRemaining,
+ DWORD dwFlags);
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'strcpy' with
+ some additional parameters. In addition to functionality provided by
+ StringCbCopy, this routine also returns a pointer to the end of the
+ destination string and the number of bytes left in the destination string
+ including the null terminator. The flags parameter allows additional controls.
+
+Arguments:
+
+ pszDest - destination string
+
+ cbDest - size of destination buffer in bytes.
+ length must be ((_tcslen(pszSrc) + 1) * sizeof(TCHAR)) to
+ hold all of the source including the null terminator
+
+ pszSrc - source string which must be null terminated
+
+ ppszDestEnd - if ppszDestEnd is non-null, the function will return a
+ pointer to the end of the destination string. If the
+ function copied any data, the result will point to the
+ null termination character
+
+ pcbRemaining - pcbRemaining is non-null,the function will return the
+ number of bytes left in the destination string,
+ including the null terminator
+
+ dwFlags - controls some details of the string copy:
+
+ STRSAFE_FILL_BEHIND_NULL
+ if the function succeeds, the low byte of dwFlags will be
+ used to fill the uninitialize part of destination buffer
+ behind the null terminator
+
+ STRSAFE_IGNORE_NULLS
+ treat NULL string pointers like empty strings (TEXT("")).
+ this flag is useful for emulating functions like lstrcpy
+
+ STRSAFE_FILL_ON_FAILURE
+ if the function fails, the low byte of dwFlags will be
+ used to fill all of the destination buffer, and it will
+ be null terminated. This will overwrite any truncated
+ string returned when the failure is
+ STRSAFE_E_INSUFFICIENT_BUFFER
+
+ STRSAFE_NO_TRUNCATION /
+ STRSAFE_NULL_ON_FAILURE
+ if the function fails, the destination buffer will be set
+ to the empty string. This will overwrite any truncated string
+ returned when the failure is STRSAFE_E_INSUFFICIENT_BUFFER.
+
+Notes:
+ Behavior is undefined if source and destination strings overlap.
+
+ pszDest and pszSrc should not be NULL unless the STRSAFE_IGNORE_NULLS flag
+ is specified. If STRSAFE_IGNORE_NULLS is passed, both pszDest and pszSrc
+ may be NULL. An error may still be returned even though NULLS are ignored
+ due to insufficient space.
+
+Return Value:
+
+ S_OK - if there was source data and it was all copied and the
+ resultant dest string was null terminated
+
+ failure - you can use the macro HRESULT_CODE() to get a win32 error
+ code for all falure cases
+
+ STRSAFE_E_INSUFFICIENT_BUFFER /
+ HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
+ - this return value is an indication that the copy operation
+ failed due to insufficient space. When this error occurs,
+ the destination buffer is modified to contain a truncated
+ version of the ideal result and is null terminated. This
+ is useful for situations where truncation is ok.
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function
+
+--*/
+
+STRSAFEAPI StringCbCopyExA(char* pszDest, size_t cbDest, const char* pszSrc, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags);
+STRSAFEAPI StringCbCopyExW(WCHAR* pszDest, size_t cbDest, const WCHAR* pszSrc, WCHAR** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags);
+#ifdef UNICODE
+#define StringCbCopyEx StringCbCopyExW
+#else
+#define StringCbCopyEx StringCbCopyExA
+#endif // !UNICODE
+
+#ifdef STRSAFE_INLINE
+STRSAFEAPI StringCbCopyExA(char* pszDest, size_t cbDest, const char* pszSrc, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags)
+{
+ HRESULT hr;
+ size_t cchDest;
+ size_t cchRemaining = 0;
+
+ cchDest = cbDest / sizeof(char);
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringCopyExWorkerA(pszDest, cchDest, cbDest, pszSrc, ppszDestEnd, &cchRemaining, dwFlags);
+ }
+
+ if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
+ {
+ if (pcbRemaining)
+ {
+ // safe to multiply cchRemaining * sizeof(char) since cchRemaining < STRSAFE_MAX_CCH and sizeof(char) is 1
+ *pcbRemaining = (cchRemaining * sizeof(char)) + (cbDest % sizeof(char));
+ }
+ }
+
+ return hr;
+}
+
+#if defined(FEATURE_PAL) || !defined(PLATFORM_UNIX)
+STRSAFEAPI StringCbCopyExW(WCHAR* pszDest, size_t cbDest, const WCHAR* pszSrc, WCHAR** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags)
+{
+ HRESULT hr;
+ size_t cchDest;
+ size_t cchRemaining = 0;
+
+ cchDest = cbDest / sizeof(WCHAR);
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringCopyExWorkerW(pszDest, cchDest, cbDest, pszSrc, ppszDestEnd, &cchRemaining, dwFlags);
+ }
+
+ if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
+ {
+ if (pcbRemaining)
+ {
+ // safe to multiply cchRemaining * sizeof(WCHAR) since cchRemaining < STRSAFE_MAX_CCH and sizeof(WCHAR) is 2
+ *pcbRemaining = (cchRemaining * sizeof(WCHAR)) + (cbDest % sizeof(WCHAR));
+ }
+ }
+
+ return hr;
+}
+#endif // FEATURE_PAL || !PLATFORM_UNIX
+#endif // STRSAFE_INLINE
+#endif // !STRSAFE_NO_CB_FUNCTIONS
+
+
+#ifndef STRSAFE_NO_CCH_FUNCTIONS
+/*++
+
+STDAPI StringCchCopyN(LPTSTR pszDest,
+ size_t cchDest,
+ LPCTSTR pszSrc,
+ size_t cchSrc);
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'strncpy'.
+ The size of the destination buffer (in characters) is a parameter and
+ this function will not write past the end of this buffer and it will
+ ALWAYS null terminate the destination buffer (unless it is zero length).
+
+ This routine is meant as a replacement for strncpy, but it does behave
+ differently. This function will not pad the destination buffer with extra
+ null termination characters if cchSrc is greater than the length of pszSrc.
+
+ This function returns a hresult, and not a pointer. It returns a S_OK
+ if the entire string or the first cchSrc characters were copied without
+ truncation and the resultant destination string was null terminated, otherwise
+ it will return a failure code. In failure cases as much of pszSrc will be
+ copied to pszDest as possible, and pszDest will be null terminated.
+
+Arguments:
+
+ pszDest - destination string
+
+ cchDest - size of destination buffer in characters.
+ length must be = (_tcslen(src) + 1) to hold all of the
+ source including the null terminator
+
+ pszSrc - source string
+
+ cchSrc - maximum number of characters to copy from source string
+
+Notes:
+ Behavior is undefined if source and destination strings overlap.
+
+ pszDest and pszSrc should not be NULL. See StringCchCopyNEx if you require
+ the handling of NULL values.
+
+Return Value:
+
+ S_OK - if there was source data and it was all copied and the
+ resultant dest string was null terminated
+
+ failure - you can use the macro HRESULT_CODE() to get a win32 error
+ code for all hresult falure cases
+
+ STRSAFE_E_INSUFFICIENT_BUFFER /
+ HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
+ - this return value is an indication that the copy operation
+ failed due to insufficient space. When this error occurs,
+ the destination buffer is modified to contain a truncated
+ version of the ideal result and is null terminated. This
+ is useful for situations where truncation is ok
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function.
+
+--*/
+
+STRSAFEAPI StringCchCopyNA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchSrc);
+STRSAFEAPI StringCchCopyNW(WCHAR* pszDest, size_t cchDest, const WCHAR* pszSrc, size_t cchSrc);
+#ifdef UNICODE
+#define StringCchCopyN StringCchCopyNW
+#else
+#define StringCchCopyN StringCchCopyNA
+#endif // !UNICODE
+
+#ifdef STRSAFE_INLINE
+STRSAFEAPI StringCchCopyNA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchSrc)
+{
+ HRESULT hr;
+
+ if ((cchDest > STRSAFE_MAX_CCH) ||
+ (cchSrc > STRSAFE_MAX_CCH))
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringCopyNWorkerA(pszDest, cchDest, pszSrc, cchSrc);
+ }
+
+ return hr;
+}
+
+#if defined(FEATURE_PAL) || !defined(PLATFORM_UNIX)
+STRSAFEAPI StringCchCopyNW(WCHAR* pszDest, size_t cchDest, const WCHAR* pszSrc, size_t cchSrc)
+{
+ HRESULT hr;
+
+ if ((cchDest > STRSAFE_MAX_CCH) ||
+ (cchSrc > STRSAFE_MAX_CCH))
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringCopyNWorkerW(pszDest, cchDest, pszSrc, cchSrc);
+ }
+
+ return hr;
+}
+#endif // FEATURE_PAL || !PLATFORM_UNIX
+#endif // STRSAFE_INLINE
+#endif // !STRSAFE_NO_CCH_FUNCTIONS
+
+
+#ifndef STRSAFE_NO_CB_FUNCTIONS
+/*++
+
+STDAPI StringCbCopyN(LPTSTR pszDest,
+ size_t cbDest,
+ LPCTSTR pszSrc,
+ size_t cbSrc);
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'strncpy'.
+ The size of the destination buffer (in bytes) is a parameter and this
+ function will not write past the end of this buffer and it will ALWAYS
+ null terminate the destination buffer (unless it is zero length).
+
+ This routine is meant as a replacement for strncpy, but it does behave
+ differently. This function will not pad the destination buffer with extra
+ null termination characters if cbSrc is greater than the size of pszSrc.
+
+ This function returns a hresult, and not a pointer. It returns a S_OK
+ if the entire string or the first cbSrc characters were copied without
+ truncation and the resultant destination string was null terminated, otherwise
+ it will return a failure code. In failure cases as much of pszSrc will be
+ copied to pszDest as possible, and pszDest will be null terminated.
+
+Arguments:
+
+ pszDest - destination string
+
+ cbDest - size of destination buffer in bytes.
+ length must be = ((_tcslen(src) + 1) * sizeof(TCHAR)) to
+ hold all of the source including the null terminator
+
+ pszSrc - source string
+
+ cbSrc - maximum number of bytes to copy from source string
+
+Notes:
+ Behavior is undefined if source and destination strings overlap.
+
+ pszDest and pszSrc should not be NULL. See StringCbCopyEx if you require
+ the handling of NULL values.
+
+Return Value:
+
+ S_OK - if there was source data and it was all copied and the
+ resultant dest string was null terminated
+
+ failure - you can use the macro HRESULT_CODE() to get a win32 error
+ code for all hresult falure cases
+
+ STRSAFE_E_INSUFFICIENT_BUFFER /
+ HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
+ - this return value is an indication that the copy operation
+ failed due to insufficient space. When this error occurs,
+ the destination buffer is modified to contain a truncated
+ version of the ideal result and is null terminated. This
+ is useful for situations where truncation is ok
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function.
+
+--*/
+
+STRSAFEAPI StringCbCopyNA(char* pszDest, size_t cbDest, const char* pszSrc, size_t cbSrc);
+STRSAFEAPI StringCbCopyNW(WCHAR* pszDest, size_t cbDest, const WCHAR* pszSrc, size_t cbSrc);
+#ifdef UNICODE
+#define StringCbCopyN StringCbCopyNW
+#else
+#define StringCbCopyN StringCbCopyNA
+#endif // !UNICODE
+
+#ifdef STRSAFE_INLINE
+STRSAFEAPI StringCbCopyNA(char* pszDest, size_t cbDest, const char* pszSrc, size_t cbSrc)
+{
+ HRESULT hr;
+ size_t cchDest;
+ size_t cchSrc;
+
+ // convert to count of characters
+ cchDest = cbDest / sizeof(char);
+ cchSrc = cbSrc / sizeof(char);
+
+ if ((cchDest > STRSAFE_MAX_CCH) ||
+ (cchSrc > STRSAFE_MAX_CCH))
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringCopyNWorkerA(pszDest, cchDest, pszSrc, cchSrc);
+ }
+
+ return hr;
+}
+
+#if defined(FEATURE_PAL) || !defined(PLATFORM_UNIX)
+STRSAFEAPI StringCbCopyNW(WCHAR* pszDest, size_t cbDest, const WCHAR* pszSrc, size_t cbSrc)
+{
+ HRESULT hr;
+ size_t cchDest;
+ size_t cchSrc;
+
+ // convert to count of characters
+ cchDest = cbDest / sizeof(WCHAR);
+ cchSrc = cbSrc / sizeof(WCHAR);
+
+ if ((cchDest > STRSAFE_MAX_CCH) ||
+ (cchSrc > STRSAFE_MAX_CCH))
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringCopyNWorkerW(pszDest, cchDest, pszSrc, cchSrc);
+ }
+
+ return hr;
+}
+#endif // FEATURE_PAL || !PLATFORM_UNIX
+#endif // STRSAFE_INLINE
+#endif // !STRSAFE_NO_CB_FUNCTIONS
+
+
+#ifndef STRSAFE_NO_CCH_FUNCTIONS
+/*++
+
+STDAPI StringCchCopyNEx(TCHAR pszDest,
+ size_t cchDest,
+ LPCTSTR pszSrc,
+ size_t cchSrc,
+ LPTSTR* ppszDestEnd,
+ size_t* pcchRemaining,
+ DWORD dwFlags);
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'strncpy' with
+ some additional parameters. In addition to functionality provided by
+ StringCchCopyN, this routine also returns a pointer to the end of the
+ destination string and the number of characters left in the destination
+ string including the null terminator. The flags parameter allows
+ additional controls.
+
+ This routine is meant as a replacement for strncpy, but it does behave
+ differently. This function will not pad the destination buffer with extra
+ null termination characters if cchSrc is greater than the length of pszSrc.
+
+Arguments:
+
+ pszDest - destination string
+
+ cchDest - size of destination buffer in characters.
+ length must be = (_tcslen(pszSrc) + 1) to hold all of
+ the source including the null terminator
+
+ pszSrc - source string
+
+ cchSrc - maximum number of characters to copy from the source
+ string
+
+ ppszDestEnd - if ppszDestEnd is non-null, the function will return a
+ pointer to the end of the destination string. If the
+ function copied any data, the result will point to the
+ null termination character
+
+ pcchRemaining - if pcchRemaining is non-null, the function will return the
+ number of characters left in the destination string,
+ including the null terminator
+
+ dwFlags - controls some details of the string copy:
+
+ STRSAFE_FILL_BEHIND_NULL
+ if the function succeeds, the low byte of dwFlags will be
+ used to fill the uninitialize part of destination buffer
+ behind the null terminator
+
+ STRSAFE_IGNORE_NULLS
+ treat NULL string pointers like empty strings (TEXT("")).
+ this flag is useful for emulating functions like lstrcpy
+
+ STRSAFE_FILL_ON_FAILURE
+ if the function fails, the low byte of dwFlags will be
+ used to fill all of the destination buffer, and it will
+ be null terminated. This will overwrite any truncated
+ string returned when the failure is
+ STRSAFE_E_INSUFFICIENT_BUFFER
+
+ STRSAFE_NO_TRUNCATION /
+ STRSAFE_NULL_ON_FAILURE
+ if the function fails, the destination buffer will be set
+ to the empty string. This will overwrite any truncated string
+ returned when the failure is STRSAFE_E_INSUFFICIENT_BUFFER.
+
+Notes:
+ Behavior is undefined if source and destination strings overlap.
+
+ pszDest and pszSrc should not be NULL unless the STRSAFE_IGNORE_NULLS flag
+ is specified. If STRSAFE_IGNORE_NULLS is passed, both pszDest and pszSrc
+ may be NULL. An error may still be returned even though NULLS are ignored
+ due to insufficient space.
+
+Return Value:
+
+ S_OK - if there was source data and it was all copied and the
+ resultant dest string was null terminated
+
+ failure - you can use the macro HRESULT_CODE() to get a win32 error
+ code for all falure cases
+
+ STRSAFE_E_INSUFFICIENT_BUFFER /
+ HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
+ - this return value is an indication that the copy operation
+ failed due to insufficient space. When this error occurs,
+ the destination buffer is modified to contain a truncated
+ version of the ideal result and is null terminated. This
+ is useful for situations where truncation is ok.
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function
+
+--*/
+
+STRSAFEAPI StringCchCopyNExA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
+STRSAFEAPI StringCchCopyNExW(WCHAR* pszDest, size_t cchDest, const WCHAR* pszSrc, size_t cchSrc, WCHAR** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
+#ifdef UNICODE
+#define StringCchCopyNEx StringCchCopyNExW
+#else
+#define StringCchCopyNEx StringCchCopyNExA
+#endif // !UNICODE
+
+#ifdef STRSAFE_INLINE
+STRSAFEAPI StringCchCopyNExA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
+{
+ HRESULT hr;
+
+ if ((cchDest > STRSAFE_MAX_CCH) ||
+ (cchSrc > STRSAFE_MAX_CCH))
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ size_t cbDest;
+
+ // safe to multiply cchDest * sizeof(char) since cchDest < STRSAFE_MAX_CCH and sizeof(char) is 1
+ cbDest = cchDest * sizeof(char);
+
+ hr = StringCopyNExWorkerA(pszDest, cchDest, cbDest, pszSrc, cchSrc, ppszDestEnd, pcchRemaining, dwFlags);
+ }
+
+ return hr;
+}
+
+#if defined(FEATURE_PAL) || !defined(PLATFORM_UNIX)
+STRSAFEAPI StringCchCopyNExW(WCHAR* pszDest, size_t cchDest, const WCHAR* pszSrc, size_t cchSrc, WCHAR** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
+{
+ HRESULT hr;
+
+ if ((cchDest > STRSAFE_MAX_CCH) ||
+ (cchSrc > STRSAFE_MAX_CCH))
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ size_t cbDest;
+
+ // safe to multiply cchDest * sizeof(WCHAR) since cchDest < STRSAFE_MAX_CCH and sizeof(WCHAR) is 2
+ cbDest = cchDest * sizeof(WCHAR);
+
+ hr = StringCopyNExWorkerW(pszDest, cchDest, cbDest, pszSrc, cchSrc, ppszDestEnd, pcchRemaining, dwFlags);
+ }
+
+ return hr;
+}
+#endif // FEATURE_PAL || !PLATFORM_UNIX
+#endif // STRSAFE_INLINE
+#endif // !STRSAFE_NO_CCH_FUNCTIONS
+
+
+#ifndef STRSAFE_NO_CB_FUNCTIONS
+/*++
+
+STDAPI StringCbCopyNEx(TCHAR pszDest,
+ size_t cbDest,
+ LPCTSTR pszSrc,
+ size_t cbSrc,
+ LPTSTR* ppszDestEnd,
+ size_t* pcbRemaining,
+ DWORD dwFlags);
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'strncpy' with
+ some additional parameters. In addition to functionality provided by
+ StringCbCopyN, this routine also returns a pointer to the end of the
+ destination string and the number of bytes left in the destination string
+ including the null terminator. The flags parameter allows additional controls.
+
+ This routine is meant as a replacement for strncpy, but it does behave
+ differently. This function will not pad the destination buffer with extra
+ null termination characters if cbSrc is greater than the size of pszSrc.
+
+Arguments:
+
+ pszDest - destination string
+
+ cbDest - size of destination buffer in bytes.
+ length must be ((_tcslen(pszSrc) + 1) * sizeof(TCHAR)) to
+ hold all of the source including the null terminator
+
+ pszSrc - source string
+
+ cbSrc - maximum number of bytes to copy from source string
+
+ ppszDestEnd - if ppszDestEnd is non-null, the function will return a
+ pointer to the end of the destination string. If the
+ function copied any data, the result will point to the
+ null termination character
+
+ pcbRemaining - pcbRemaining is non-null,the function will return the
+ number of bytes left in the destination string,
+ including the null terminator
+
+ dwFlags - controls some details of the string copy:
+
+ STRSAFE_FILL_BEHIND_NULL
+ if the function succeeds, the low byte of dwFlags will be
+ used to fill the uninitialize part of destination buffer
+ behind the null terminator
+
+ STRSAFE_IGNORE_NULLS
+ treat NULL string pointers like empty strings (TEXT("")).
+ this flag is useful for emulating functions like lstrcpy
+
+ STRSAFE_FILL_ON_FAILURE
+ if the function fails, the low byte of dwFlags will be
+ used to fill all of the destination buffer, and it will
+ be null terminated. This will overwrite any truncated
+ string returned when the failure is
+ STRSAFE_E_INSUFFICIENT_BUFFER
+
+ STRSAFE_NO_TRUNCATION /
+ STRSAFE_NULL_ON_FAILURE
+ if the function fails, the destination buffer will be set
+ to the empty string. This will overwrite any truncated string
+ returned when the failure is STRSAFE_E_INSUFFICIENT_BUFFER.
+
+Notes:
+ Behavior is undefined if source and destination strings overlap.
+
+ pszDest and pszSrc should not be NULL unless the STRSAFE_IGNORE_NULLS flag
+ is specified. If STRSAFE_IGNORE_NULLS is passed, both pszDest and pszSrc
+ may be NULL. An error may still be returned even though NULLS are ignored
+ due to insufficient space.
+
+Return Value:
+
+ S_OK - if there was source data and it was all copied and the
+ resultant dest string was null terminated
+
+ failure - you can use the macro HRESULT_CODE() to get a win32 error
+ code for all falure cases
+
+ STRSAFE_E_INSUFFICIENT_BUFFER /
+ HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
+ - this return value is an indication that the copy operation
+ failed due to insufficient space. When this error occurs,
+ the destination buffer is modified to contain a truncated
+ version of the ideal result and is null terminated. This
+ is useful for situations where truncation is ok.
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function
+
+--*/
+
+STRSAFEAPI StringCbCopyNExA(char* pszDest, size_t cbDest, const char* pszSrc, size_t cbSrc, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags);
+STRSAFEAPI StringCbCopyNExW(WCHAR* pszDest, size_t cbDest, const WCHAR* pszSrc, size_t cbSrc, WCHAR** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags);
+#ifdef UNICODE
+#define StringCbCopyNEx StringCbCopyNExW
+#else
+#define StringCbCopyNEx StringCbCopyNExA
+#endif // !UNICODE
+
+
+#ifdef STRSAFE_INLINE
+STRSAFEAPI StringCbCopyNExA(char* pszDest, size_t cbDest, const char* pszSrc, size_t cbSrc, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags)
+{
+ HRESULT hr;
+ size_t cchDest;
+ size_t cchSrc;
+ size_t cchRemaining = 0;
+
+ cchDest = cbDest / sizeof(char);
+ cchSrc = cbSrc / sizeof(char);
+
+ if ((cchDest > STRSAFE_MAX_CCH) ||
+ (cchSrc > STRSAFE_MAX_CCH))
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringCopyNExWorkerA(pszDest, cchDest, cbDest, pszSrc, cchSrc, ppszDestEnd, &cchRemaining, dwFlags);
+ }
+
+ if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
+ {
+ if (pcbRemaining)
+ {
+ // safe to multiply cchRemaining * sizeof(char) since cchRemaining < STRSAFE_MAX_CCH and sizeof(char) is 1
+ *pcbRemaining = (cchRemaining * sizeof(char)) + (cbDest % sizeof(char));
+ }
+ }
+
+ return hr;
+}
+
+#if defined(FEATURE_PAL) || !defined(PLATFORM_UNIX)
+STRSAFEAPI StringCbCopyNExW(WCHAR* pszDest, size_t cbDest, const WCHAR* pszSrc, size_t cbSrc, WCHAR** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags)
+{
+ HRESULT hr;
+ size_t cchDest;
+ size_t cchSrc;
+ size_t cchRemaining = 0;
+
+ cchDest = cbDest / sizeof(WCHAR);
+ cchSrc = cbSrc / sizeof(WCHAR);
+
+ if ((cchDest > STRSAFE_MAX_CCH) ||
+ (cchSrc > STRSAFE_MAX_CCH))
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringCopyNExWorkerW(pszDest, cchDest, cbDest, pszSrc, cchSrc, ppszDestEnd, &cchRemaining, dwFlags);
+ }
+
+ if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
+ {
+ if (pcbRemaining)
+ {
+ // safe to multiply cchRemaining * sizeof(WCHAR) since cchRemaining < STRSAFE_MAX_CCH and sizeof(WCHAR) is 2
+ *pcbRemaining = (cchRemaining * sizeof(WCHAR)) + (cbDest % sizeof(WCHAR));
+ }
+ }
+
+ return hr;
+}
+#endif // FEATURE_PAL || !PLATFORM_UNIX
+#endif // STRSAFE_INLINE
+#endif // !STRSAFE_NO_CB_FUNCTIONS
+
+
+#ifndef STRSAFE_NO_CCH_FUNCTIONS
+/*++
+
+STDAPI StringCchCat(LPTSTR pszDest,
+ size_t cchDest,
+ LPCTSTR pszSrc);
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'strcat'.
+ The size of the destination buffer (in characters) is a parameter and this
+ function will not write past the end of this buffer and it will ALWAYS
+ null terminate the destination buffer (unless it is zero length).
+
+ This function returns a hresult, and not a pointer. It returns a S_OK
+ if the string was concatenated without truncation and null terminated, otherwise
+ it will return a failure code. In failure cases as much of pszSrc will be
+ appended to pszDest as possible, and pszDest will be null terminated.
+
+Arguments:
+
+ pszDest - destination string which must be null terminated
+
+ cchDest - size of destination buffer in characters.
+ length must be = (_tcslen(pszDest) + _tcslen(pszSrc) + 1)
+ to hold all of the combine string plus the null
+ terminator
+
+ pszSrc - source string which must be null terminated
+
+Notes:
+ Behavior is undefined if source and destination strings overlap.
+
+ pszDest and pszSrc should not be NULL. See StringCchCatEx if you require
+ the handling of NULL values.
+
+Return Value:
+
+ S_OK - if there was source data and it was all concatenated and the
+ resultant dest string was null terminated
+
+ failure - you can use the macro HRESULT_CODE() to get a win32 error
+ code for all falure cases
+
+ STRSAFE_E_INSUFFICIENT_BUFFER /
+ HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
+ - this return value is an indication that the operation
+ failed due to insufficient space. When this error occurs,
+ the destination buffer is modified to contain a truncated
+ version of the ideal result and is null terminated. This
+ is useful for situations where truncation is ok.
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function
+
+--*/
+
+STRSAFEAPI StringCchCatA(char* pszDest, size_t cchDest, const char* pszSrc);
+STRSAFEAPI StringCchCatW(WCHAR* pszDest, size_t cchDest, const WCHAR* pszSrc);
+#ifdef UNICODE
+#define StringCchCat StringCchCatW
+#else
+#define StringCchCat StringCchCatA
+#endif // !UNICODE
+
+#ifdef STRSAFE_INLINE
+STRSAFEAPI StringCchCatA(char* pszDest, size_t cchDest, const char* pszSrc)
+{
+ HRESULT hr;
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringCatWorkerA(pszDest, cchDest, pszSrc);
+ }
+
+ return hr;
+}
+
+#if defined(FEATURE_PAL) || !defined(PLATFORM_UNIX)
+STRSAFEAPI StringCchCatW(WCHAR* pszDest, size_t cchDest, const WCHAR* pszSrc)
+{
+ HRESULT hr;
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringCatWorkerW(pszDest, cchDest, pszSrc);
+ }
+
+ return hr;
+}
+#endif // FEATURE_PAL || !PLATFORM_UNIX
+#endif // STRSAFE_INLINE
+#endif // !STRSAFE_NO_CCH_FUNCTIONS
+
+
+#ifndef STRSAFE_NO_CB_FUNCTIONS
+/*++
+
+STDAPI StringCbCat(LPTSTR pszDest,
+ size_t cbDest,
+ LPCTSTR pszSrc);
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'strcat'.
+ The size of the destination buffer (in bytes) is a parameter and this
+ function will not write past the end of this buffer and it will ALWAYS
+ null terminate the destination buffer (unless it is zero length).
+
+ This function returns a hresult, and not a pointer. It returns a S_OK
+ if the string was concatenated without truncation and null terminated, otherwise
+ it will return a failure code. In failure cases as much of pszSrc will be
+ appended to pszDest as possible, and pszDest will be null terminated.
+
+Arguments:
+
+ pszDest - destination string which must be null terminated
+
+ cbDest - size of destination buffer in bytes.
+ length must be = ((_tcslen(pszDest) + _tcslen(pszSrc) + 1) * sizeof(TCHAR)
+ to hold all of the combine string plus the null
+ terminator
+
+ pszSrc - source string which must be null terminated
+
+Notes:
+ Behavior is undefined if source and destination strings overlap.
+
+ pszDest and pszSrc should not be NULL. See StringCbCatEx if you require
+ the handling of NULL values.
+
+Return Value:
+
+ S_OK - if there was source data and it was all concatenated and the
+ resultant dest string was null terminated
+
+ failure - you can use the macro HRESULT_CODE() to get a win32 error
+ code for all falure cases
+
+ STRSAFE_E_INSUFFICIENT_BUFFER /
+ HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
+ - this return value is an indication that the operation
+ failed due to insufficient space. When this error occurs,
+ the destination buffer is modified to contain a truncated
+ version of the ideal result and is null terminated. This
+ is useful for situations where truncation is ok.
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function
+
+--*/
+
+STRSAFEAPI StringCbCatA(char* pszDest, size_t cbDest, const char* pszSrc);
+STRSAFEAPI StringCbCatW(WCHAR* pszDest, size_t cbDest, const WCHAR* pszSrc);
+#ifdef UNICODE
+#define StringCbCat StringCbCatW
+#else
+#define StringCbCat StringCbCatA
+#endif // !UNICODE
+
+#ifdef STRSAFE_INLINE
+STRSAFEAPI StringCbCatA(char* pszDest, size_t cbDest, const char* pszSrc)
+{
+ HRESULT hr;
+ size_t cchDest;
+
+ cchDest = cbDest / sizeof(char);
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringCatWorkerA(pszDest, cchDest, pszSrc);
+ }
+
+ return hr;
+}
+
+#if defined(FEATURE_PAL) || !defined(PLATFORM_UNIX)
+STRSAFEAPI StringCbCatW(WCHAR* pszDest, size_t cbDest, const WCHAR* pszSrc)
+{
+ HRESULT hr;
+ size_t cchDest;
+
+ cchDest = cbDest / sizeof(WCHAR);
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringCatWorkerW(pszDest, cchDest, pszSrc);
+ }
+
+ return hr;
+}
+#endif // FEATURE_PAL || !PLATFORM_UNIX
+#endif // STRSAFE_INLINE
+#endif // !STRSAFE_NO_CB_FUNCTIONS
+
+
+#ifndef STRSAFE_NO_CCH_FUNCTIONS
+/*++
+
+STDAPI StringCchCatEx(LPTSTR pszDest,
+ size_t cchDest,
+ LPCTSTR pszSrc,
+ LPTSTR* ppszDestEnd,
+ size_t* pcchRemaining,
+ DWORD dwFlags);
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'strcat' with
+ some additional parameters. In addition to functionality provided by
+ StringCchCat, this routine also returns a pointer to the end of the
+ destination string and the number of characters left in the destination string
+ including the null terminator. The flags parameter allows additional controls.
+
+Arguments:
+
+ pszDest - destination string which must be null terminated
+
+ cchDest - size of destination buffer in characters
+ length must be (_tcslen(pszDest) + _tcslen(pszSrc) + 1)
+ to hold all of the combine string plus the null
+ terminator.
+
+ pszSrc - source string which must be null terminated
+
+ ppszDestEnd - if ppszDestEnd is non-null, the function will return a
+ pointer to the end of the destination string. If the
+ function appended any data, the result will point to the
+ null termination character
+
+ pcchRemaining - if pcchRemaining is non-null, the function will return the
+ number of characters left in the destination string,
+ including the null terminator
+
+ dwFlags - controls some details of the string copy:
+
+ STRSAFE_FILL_BEHIND_NULL
+ if the function succeeds, the low byte of dwFlags will be
+ used to fill the uninitialize part of destination buffer
+ behind the null terminator
+
+ STRSAFE_IGNORE_NULLS
+ treat NULL string pointers like empty strings (TEXT("")).
+ this flag is useful for emulating functions like lstrcat
+
+ STRSAFE_FILL_ON_FAILURE
+ if the function fails, the low byte of dwFlags will be
+ used to fill all of the destination buffer, and it will
+ be null terminated. This will overwrite any pre-existing
+ or truncated string
+
+ STRSAFE_NULL_ON_FAILURE
+ if the function fails, the destination buffer will be set
+ to the empty string. This will overwrite any pre-existing or
+ truncated string
+
+ STRSAFE_NO_TRUNCATION
+ if the function returns STRSAFE_E_INSUFFICIENT_BUFFER, pszDest
+ will not contain a truncated string, it will remain unchanged.
+
+Notes:
+ Behavior is undefined if source and destination strings overlap.
+
+ pszDest and pszSrc should not be NULL unless the STRSAFE_IGNORE_NULLS flag
+ is specified. If STRSAFE_IGNORE_NULLS is passed, both pszDest and pszSrc
+ may be NULL. An error may still be returned even though NULLS are ignored
+ due to insufficient space.
+
+Return Value:
+
+ S_OK - if there was source data and it was all concatenated and the
+ resultant dest string was null terminated
+
+ failure - you can use the macro HRESULT_CODE() to get a win32 error
+ code for all falure cases
+
+ STRSAFE_E_INSUFFICIENT_BUFFER /
+ HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
+ - this return value is an indication that the operation
+ failed due to insufficient space. When this error occurs,
+ the destination buffer is modified to contain a truncated
+ version of the ideal result and is null terminated. This
+ is useful for situations where truncation is ok.
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function
+
+--*/
+
+STRSAFEAPI StringCchCatExA(char* pszDest, size_t cchDest, const char* pszSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
+STRSAFEAPI StringCchCatExW(WCHAR* pszDest, size_t cchDest, const WCHAR* pszSrc, WCHAR** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
+#ifdef UNICODE
+#define StringCchCatEx StringCchCatExW
+#else
+#define StringCchCatEx StringCchCatExA
+#endif // !UNICODE
+
+#ifdef STRSAFE_INLINE
+STRSAFEAPI StringCchCatExA(char* pszDest, size_t cchDest, const char* pszSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
+{
+ HRESULT hr;
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ size_t cbDest;
+
+ // safe to multiply cchDest * sizeof(char) since cchDest < STRSAFE_MAX_CCH and sizeof(char) is 1
+ cbDest = cchDest * sizeof(char);
+
+ hr = StringCatExWorkerA(pszDest, cchDest, cbDest, pszSrc, ppszDestEnd, pcchRemaining, dwFlags);
+ }
+
+ return hr;
+}
+
+#if defined(FEATURE_PAL) || !defined(PLATFORM_UNIX)
+STRSAFEAPI StringCchCatExW(WCHAR* pszDest, size_t cchDest, const WCHAR* pszSrc, WCHAR** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
+{
+ HRESULT hr;
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ size_t cbDest;
+
+ // safe to multiply cchDest * sizeof(WCHAR) since cchDest < STRSAFE_MAX_CCH and sizeof(WCHAR) is 2
+ cbDest = cchDest * sizeof(WCHAR);
+
+ hr = StringCatExWorkerW(pszDest, cchDest, cbDest, pszSrc, ppszDestEnd, pcchRemaining, dwFlags);
+ }
+
+ return hr;
+}
+#endif // FEATURE_PAL || !PLATFORM_UNIX
+#endif // STRSAFE_INLINE
+#endif // !STRSAFE_NO_CCH_FUNCTIONS
+
+
+#ifndef STRSAFE_NO_CB_FUNCTIONS
+/*++
+
+STDAPI StringCbCatEx(LPTSTR pszDest,
+ size_t cbDest,
+ LPCTSTR pszSrc,
+ LPTSTR* ppszDestEnd,
+ size_t* pcbRemaining,
+ DWORD dwFlags);
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'strcat' with
+ some additional parameters. In addition to functionality provided by
+ StringCbCat, this routine also returns a pointer to the end of the
+ destination string and the number of bytes left in the destination string
+ including the null terminator. The flags parameter allows additional controls.
+
+Arguments:
+
+ pszDest - destination string which must be null terminated
+
+ cbDest - size of destination buffer in bytes.
+ length must be ((_tcslen(pszDest) + _tcslen(pszSrc) + 1) * sizeof(TCHAR)
+ to hold all of the combine string plus the null
+ terminator.
+
+ pszSrc - source string which must be null terminated
+
+ ppszDestEnd - if ppszDestEnd is non-null, the function will return a
+ pointer to the end of the destination string. If the
+ function appended any data, the result will point to the
+ null termination character
+
+ pcbRemaining - if pcbRemaining is non-null, the function will return
+ the number of bytes left in the destination string,
+ including the null terminator
+
+ dwFlags - controls some details of the string copy:
+
+ STRSAFE_FILL_BEHIND_NULL
+ if the function succeeds, the low byte of dwFlags will be
+ used to fill the uninitialize part of destination buffer
+ behind the null terminator
+
+ STRSAFE_IGNORE_NULLS
+ treat NULL string pointers like empty strings (TEXT("")).
+ this flag is useful for emulating functions like lstrcat
+
+ STRSAFE_FILL_ON_FAILURE
+ if the function fails, the low byte of dwFlags will be
+ used to fill all of the destination buffer, and it will
+ be null terminated. This will overwrite any pre-existing
+ or truncated string
+
+ STRSAFE_NULL_ON_FAILURE
+ if the function fails, the destination buffer will be set
+ to the empty string. This will overwrite any pre-existing or
+ truncated string
+
+ STRSAFE_NO_TRUNCATION
+ if the function returns STRSAFE_E_INSUFFICIENT_BUFFER, pszDest
+ will not contain a truncated string, it will remain unchanged.
+
+Notes:
+ Behavior is undefined if source and destination strings overlap.
+
+ pszDest and pszSrc should not be NULL unless the STRSAFE_IGNORE_NULLS flag
+ is specified. If STRSAFE_IGNORE_NULLS is passed, both pszDest and pszSrc
+ may be NULL. An error may still be returned even though NULLS are ignored
+ due to insufficient space.
+
+Return Value:
+
+ S_OK - if there was source data and it was all concatenated and the
+ resultant dest string was null terminated
+
+ failure - you can use the macro HRESULT_CODE() to get a win32 error
+ code for all falure cases
+
+ STRSAFE_E_INSUFFICIENT_BUFFER /
+ HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
+ - this return value is an indication that the operation
+ failed due to insufficient space. When this error occurs,
+ the destination buffer is modified to contain a truncated
+ version of the ideal result and is null terminated. This
+ is useful for situations where truncation is ok.
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function
+
+--*/
+
+STRSAFEAPI StringCbCatExA(char* pszDest, size_t cbDest, const char* pszSrc, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags);
+STRSAFEAPI StringCbCatExW(WCHAR* pszDest, size_t cbDest, const WCHAR* pszSrc, WCHAR** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags);
+#ifdef UNICODE
+#define StringCbCatEx StringCbCatExW
+#else
+#define StringCbCatEx StringCbCatExA
+#endif // !UNICODE
+
+#ifdef STRSAFE_INLINE
+STRSAFEAPI StringCbCatExA(char* pszDest, size_t cbDest, const char* pszSrc, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags)
+{
+ HRESULT hr;
+ size_t cchDest;
+ size_t cchRemaining = 0;
+
+ cchDest = cbDest / sizeof(char);
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringCatExWorkerA(pszDest, cchDest, cbDest, pszSrc, ppszDestEnd, &cchRemaining, dwFlags);
+ }
+
+ if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
+ {
+ if (pcbRemaining)
+ {
+ // safe to multiply cchRemaining * sizeof(char) since cchRemaining < STRSAFE_MAX_CCH and sizeof(char) is 1
+ *pcbRemaining = (cchRemaining * sizeof(char)) + (cbDest % sizeof(char));
+ }
+ }
+
+ return hr;
+}
+
+#if defined(FEATURE_PAL) || !defined(PLATFORM_UNIX)
+STRSAFEAPI StringCbCatExW(WCHAR* pszDest, size_t cbDest, const WCHAR* pszSrc, WCHAR** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags)
+{
+ HRESULT hr;
+ size_t cchDest;
+ size_t cchRemaining = 0;
+
+ cchDest = cbDest / sizeof(WCHAR);
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringCatExWorkerW(pszDest, cchDest, cbDest, pszSrc, ppszDestEnd, &cchRemaining, dwFlags);
+ }
+
+ if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
+ {
+ if (pcbRemaining)
+ {
+ // safe to multiply cchRemaining * sizeof(WCHAR) since cchRemaining < STRSAFE_MAX_CCH and sizeof(WCHAR) is 2
+ *pcbRemaining = (cchRemaining * sizeof(WCHAR)) + (cbDest % sizeof(WCHAR));
+ }
+ }
+
+ return hr;
+}
+#endif // FEATURE_PAL || !PLATFORM_UNIX
+#endif // STRSAFE_INLINE
+#endif // !STRSAFE_NO_CB_FUNCTIONS
+
+
+#ifndef STRSAFE_NO_CCH_FUNCTIONS
+/*++
+
+STDAPI StringCchCatN(LPTSTR pszDest,
+ size_t cchDest,
+ LPCTSTR pszSrc,
+ size_t cchMaxAppend);
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'strncat'.
+ The size of the destination buffer (in characters) is a parameter as well as
+ the maximum number of characters to append, excluding the null terminator.
+ This function will not write past the end of the destination buffer and it will
+ ALWAYS null terminate pszDest (unless it is zero length).
+
+ This function returns a hresult, and not a pointer. It returns a S_OK
+ if all of pszSrc or the first cchMaxAppend characters were appended to the
+ destination string and it was null terminated, otherwise it will return a
+ failure code. In failure cases as much of pszSrc will be appended to pszDest
+ as possible, and pszDest will be null terminated.
+
+Arguments:
+
+ pszDest - destination string which must be null terminated
+
+ cchDest - size of destination buffer in characters.
+ length must be (_tcslen(pszDest) + min(cchMaxAppend, _tcslen(pszSrc)) + 1)
+ to hold all of the combine string plus the null
+ terminator.
+
+ pszSrc - source string
+
+ cchMaxAppend - maximum number of characters to append
+
+Notes:
+ Behavior is undefined if source and destination strings overlap.
+
+ pszDest and pszSrc should not be NULL. See StringCchCatNEx if you require
+ the handling of NULL values.
+
+Return Value:
+
+ S_OK - if all of pszSrc or the first cchMaxAppend characters were
+ concatenated to pszDest and the resultant dest string was
+ null terminated
+
+ failure - you can use the macro HRESULT_CODE() to get a win32 error
+ code for all falure cases
+
+ STRSAFE_E_INSUFFICIENT_BUFFER /
+ HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
+ - this return value is an indication that the operation
+ failed due to insufficient space. When this error occurs,
+ the destination buffer is modified to contain a truncated
+ version of the ideal result and is null terminated. This
+ is useful for situations where truncation is ok.
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function
+
+--*/
+
+STRSAFEAPI StringCchCatNA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchMaxAppend);
+STRSAFEAPI StringCchCatNW(WCHAR* pszDest, size_t cchDest, const WCHAR* pszSrc, size_t cchMaxAppend);
+#ifdef UNICODE
+#define StringCchCatN StringCchCatNW
+#else
+#define StringCchCatN StringCchCatNA
+#endif // !UNICODE
+
+#ifdef STRSAFE_INLINE
+STRSAFEAPI StringCchCatNA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchMaxAppend)
+{
+ HRESULT hr;
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringCatNWorkerA(pszDest, cchDest, pszSrc, cchMaxAppend);
+ }
+
+ return hr;
+}
+
+#if defined(FEATURE_PAL) || !defined(PLATFORM_UNIX)
+STRSAFEAPI StringCchCatNW(WCHAR* pszDest, size_t cchDest, const WCHAR* pszSrc, size_t cchMaxAppend)
+{
+ HRESULT hr;
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringCatNWorkerW(pszDest, cchDest, pszSrc, cchMaxAppend);
+ }
+
+ return hr;
+}
+#endif // FEATURE_PAL || !PLATFORM_UNIX
+#endif // STRSAFE_INLINE
+#endif // !STRSAFE_NO_CCH_FUNCTIONS
+
+
+#ifndef STRSAFE_NO_CB_FUNCTIONS
+/*++
+
+STDAPI StringCbCatN(LPTSTR pszDest,
+ size_t cbDest,
+ LPCTSTR pszSrc,
+ size_t cbMaxAppend);
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'strncat'.
+ The size of the destination buffer (in bytes) is a parameter as well as
+ the maximum number of bytes to append, excluding the null terminator.
+ This function will not write past the end of the destination buffer and it will
+ ALWAYS null terminate pszDest (unless it is zero length).
+
+ This function returns a hresult, and not a pointer. It returns a S_OK
+ if all of pszSrc or the first cbMaxAppend bytes were appended to the
+ destination string and it was null terminated, otherwise it will return a
+ failure code. In failure cases as much of pszSrc will be appended to pszDest
+ as possible, and pszDest will be null terminated.
+
+Arguments:
+
+ pszDest - destination string which must be null terminated
+
+ cbDest - size of destination buffer in bytes.
+ length must be ((_tcslen(pszDest) + min(cbMaxAppend / sizeof(TCHAR), _tcslen(pszSrc)) + 1) * sizeof(TCHAR)
+ to hold all of the combine string plus the null
+ terminator.
+
+ pszSrc - source string
+
+ cbMaxAppend - maximum number of bytes to append
+
+Notes:
+ Behavior is undefined if source and destination strings overlap.
+
+ pszDest and pszSrc should not be NULL. See StringCbCatNEx if you require
+ the handling of NULL values.
+
+Return Value:
+
+ S_OK - if all of pszSrc or the first cbMaxAppend bytes were
+ concatenated to pszDest and the resultant dest string was
+ null terminated
+
+ failure - you can use the macro HRESULT_CODE() to get a win32 error
+ code for all falure cases
+
+ STRSAFE_E_INSUFFICIENT_BUFFER /
+ HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
+ - this return value is an indication that the operation
+ failed due to insufficient space. When this error occurs,
+ the destination buffer is modified to contain a truncated
+ version of the ideal result and is null terminated. This
+ is useful for situations where truncation is ok.
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function
+
+--*/
+
+STRSAFEAPI StringCbCatNA(char* pszDest, size_t cbDest, const char* pszSrc, size_t cbMaxAppend);
+STRSAFEAPI StringCbCatNW(WCHAR* pszDest, size_t cbDest, const WCHAR* pszSrc, size_t cbMaxAppend);
+#ifdef UNICODE
+#define StringCbCatN StringCbCatNW
+#else
+#define StringCbCatN StringCbCatNA
+#endif // !UNICODE
+
+#ifdef STRSAFE_INLINE
+STRSAFEAPI StringCbCatNA(char* pszDest, size_t cbDest, const char* pszSrc, size_t cbMaxAppend)
+{
+ HRESULT hr;
+ size_t cchDest;
+
+ cchDest = cbDest / sizeof(char);
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ size_t cchMaxAppend;
+
+ cchMaxAppend = cbMaxAppend / sizeof(char);
+
+ hr = StringCatNWorkerA(pszDest, cchDest, pszSrc, cchMaxAppend);
+ }
+
+ return hr;
+}
+
+#if defined(FEATURE_PAL) || !defined(PLATFORM_UNIX)
+STRSAFEAPI StringCbCatNW(WCHAR* pszDest, size_t cbDest, const WCHAR* pszSrc, size_t cbMaxAppend)
+{
+ HRESULT hr;
+ size_t cchDest;
+
+ cchDest = cbDest / sizeof(WCHAR);
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ size_t cchMaxAppend;
+
+ cchMaxAppend = cbMaxAppend / sizeof(WCHAR);
+
+ hr = StringCatNWorkerW(pszDest, cchDest, pszSrc, cchMaxAppend);
+ }
+
+ return hr;
+}
+#endif // FEATURE_PAL || !PLATFORM_UNIX
+#endif // STRSAFE_INLINE
+#endif // !STRSAFE_NO_CB_FUNCTIONS
+
+
+#ifndef STRSAFE_NO_CCH_FUNCTIONS
+/*++
+
+STDAPI StringCchCatNEx(LPTSTR pszDest,
+ size_t cchDest,
+ LPCTSTR pszSrc,
+ size_t cchMaxAppend,
+ LPTSTR* ppszDestEnd,
+ size_t* pcchRemaining,
+ DWORD dwFlags);
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'strncat', with
+ some additional parameters. In addition to functionality provided by
+ StringCchCatN, this routine also returns a pointer to the end of the
+ destination string and the number of characters left in the destination string
+ including the null terminator. The flags parameter allows additional controls.
+
+Arguments:
+
+ pszDest - destination string which must be null terminated
+
+ cchDest - size of destination buffer in characters.
+ length must be (_tcslen(pszDest) + min(cchMaxAppend, _tcslen(pszSrc)) + 1)
+ to hold all of the combine string plus the null
+ terminator.
+
+ pszSrc - source string
+
+ cchMaxAppend - maximum number of characters to append
+
+ ppszDestEnd - if ppszDestEnd is non-null, the function will return a
+ pointer to the end of the destination string. If the
+ function appended any data, the result will point to the
+ null termination character
+
+ pcchRemaining - if pcchRemaining is non-null, the function will return the
+ number of characters left in the destination string,
+ including the null terminator
+
+ dwFlags - controls some details of the string copy:
+
+ STRSAFE_FILL_BEHIND_NULL
+ if the function succeeds, the low byte of dwFlags will be
+ used to fill the uninitialize part of destination buffer
+ behind the null terminator
+
+ STRSAFE_IGNORE_NULLS
+ treat NULL string pointers like empty strings (TEXT(""))
+
+ STRSAFE_FILL_ON_FAILURE
+ if the function fails, the low byte of dwFlags will be
+ used to fill all of the destination buffer, and it will
+ be null terminated. This will overwrite any pre-existing
+ or truncated string
+
+ STRSAFE_NULL_ON_FAILURE
+ if the function fails, the destination buffer will be set
+ to the empty string. This will overwrite any pre-existing or
+ truncated string
+
+ STRSAFE_NO_TRUNCATION
+ if the function returns STRSAFE_E_INSUFFICIENT_BUFFER, pszDest
+ will not contain a truncated string, it will remain unchanged.
+
+Notes:
+ Behavior is undefined if source and destination strings overlap.
+
+ pszDest and pszSrc should not be NULL unless the STRSAFE_IGNORE_NULLS flag
+ is specified. If STRSAFE_IGNORE_NULLS is passed, both pszDest and pszSrc
+ may be NULL. An error may still be returned even though NULLS are ignored
+ due to insufficient space.
+
+Return Value:
+
+ S_OK - if all of pszSrc or the first cchMaxAppend characters were
+ concatenated to pszDest and the resultant dest string was
+ null terminated
+
+ failure - you can use the macro HRESULT_CODE() to get a win32 error
+ code for all falure cases
+
+ STRSAFE_E_INSUFFICIENT_BUFFER /
+ HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
+ - this return value is an indication that the operation
+ failed due to insufficient space. When this error occurs,
+ the destination buffer is modified to contain a truncated
+ version of the ideal result and is null terminated. This
+ is useful for situations where truncation is ok.
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function
+
+--*/
+
+STRSAFEAPI StringCchCatNExA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchMaxAppend, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
+STRSAFEAPI StringCchCatNExW(WCHAR* pszDest, size_t cchDest, const WCHAR* pszSrc, size_t cchMaxAppend, WCHAR** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
+#ifdef UNICODE
+#define StringCchCatNEx StringCchCatNExW
+#else
+#define StringCchCatNEx StringCchCatNExA
+#endif // !UNICODE
+
+#ifdef STRSAFE_INLINE
+STRSAFEAPI StringCchCatNExA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchMaxAppend, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
+{
+ HRESULT hr;
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ size_t cbDest;
+
+ // safe to multiply cchDest * sizeof(char) since cchDest < STRSAFE_MAX_CCH and sizeof(char) is 1
+ cbDest = cchDest * sizeof(char);
+
+ hr = StringCatNExWorkerA(pszDest, cchDest, cbDest, pszSrc, cchMaxAppend, ppszDestEnd, pcchRemaining, dwFlags);
+ }
+
+ return hr;
+}
+
+#if defined(FEATURE_PAL) || !defined(PLATFORM_UNIX)
+STRSAFEAPI StringCchCatNExW(WCHAR* pszDest, size_t cchDest, const WCHAR* pszSrc, size_t cchMaxAppend, WCHAR** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
+{
+ HRESULT hr;
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ size_t cbDest;
+
+ // safe to multiply cchDest * sizeof(WCHAR) since cchDest < STRSAFE_MAX_CCH and sizeof(WCHAR) is 2
+ cbDest = cchDest * sizeof(WCHAR);
+
+ hr = StringCatNExWorkerW(pszDest, cchDest, cbDest, pszSrc, cchMaxAppend, ppszDestEnd, pcchRemaining, dwFlags);
+ }
+
+ return hr;
+}
+#endif // FEATURE_PAL || !PLATFORM_UNIX
+#endif // STRSAFE_INLINE
+#endif // !STRSAFE_NO_CCH_FUNCTIONS
+
+
+#ifndef STRSAFE_NO_CB_FUNCTIONS
+/*++
+
+STDAPI StringCbCatNEx(LPTSTR pszDest,
+ size_t cbDest,
+ LPCTSTR pszSrc,
+ size_t cbMaxAppend
+ LPTSTR* ppszDestEnd,
+ size_t* pcchRemaining,
+ DWORD dwFlags);
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'strncat', with
+ some additional parameters. In addition to functionality provided by
+ StringCbCatN, this routine also returns a pointer to the end of the
+ destination string and the number of bytes left in the destination string
+ including the null terminator. The flags parameter allows additional controls.
+
+Arguments:
+
+ pszDest - destination string which must be null terminated
+
+ cbDest - size of destination buffer in bytes.
+ length must be ((_tcslen(pszDest) + min(cbMaxAppend / sizeof(TCHAR), _tcslen(pszSrc)) + 1) * sizeof(TCHAR)
+ to hold all of the combine string plus the null
+ terminator.
+
+ pszSrc - source string
+
+ cbMaxAppend - maximum number of bytes to append
+
+ ppszDestEnd - if ppszDestEnd is non-null, the function will return a
+ pointer to the end of the destination string. If the
+ function appended any data, the result will point to the
+ null termination character
+
+ pcbRemaining - if pcbRemaining is non-null, the function will return the
+ number of bytes left in the destination string,
+ including the null terminator
+
+ dwFlags - controls some details of the string copy:
+
+ STRSAFE_FILL_BEHIND_NULL
+ if the function succeeds, the low byte of dwFlags will be
+ used to fill the uninitialize part of destination buffer
+ behind the null terminator
+
+ STRSAFE_IGNORE_NULLS
+ treat NULL string pointers like empty strings (TEXT(""))
+
+ STRSAFE_FILL_ON_FAILURE
+ if the function fails, the low byte of dwFlags will be
+ used to fill all of the destination buffer, and it will
+ be null terminated. This will overwrite any pre-existing
+ or truncated string
+
+ STRSAFE_NULL_ON_FAILURE
+ if the function fails, the destination buffer will be set
+ to the empty string. This will overwrite any pre-existing or
+ truncated string
+
+ STRSAFE_NO_TRUNCATION
+ if the function returns STRSAFE_E_INSUFFICIENT_BUFFER, pszDest
+ will not contain a truncated string, it will remain unchanged.
+
+Notes:
+ Behavior is undefined if source and destination strings overlap.
+
+ pszDest and pszSrc should not be NULL unless the STRSAFE_IGNORE_NULLS flag
+ is specified. If STRSAFE_IGNORE_NULLS is passed, both pszDest and pszSrc
+ may be NULL. An error may still be returned even though NULLS are ignored
+ due to insufficient space.
+
+Return Value:
+
+ S_OK - if all of pszSrc or the first cbMaxAppend bytes were
+ concatenated to pszDest and the resultant dest string was
+ null terminated
+
+ failure - you can use the macro HRESULT_CODE() to get a win32 error
+ code for all falure cases
+
+ STRSAFE_E_INSUFFICIENT_BUFFER /
+ HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
+ - this return value is an indication that the operation
+ failed due to insufficient space. When this error occurs,
+ the destination buffer is modified to contain a truncated
+ version of the ideal result and is null terminated. This
+ is useful for situations where truncation is ok.
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function
+
+--*/
+
+STRSAFEAPI StringCbCatNExA(char* pszDest, size_t cbDest, const char* pszSrc, size_t cbMaxAppend, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags);
+STRSAFEAPI StringCbCatNExW(WCHAR* pszDest, size_t cbDest, const WCHAR* pszSrc, size_t cbMaxAppend, WCHAR** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags);
+#ifdef UNICODE
+#define StringCbCatNEx StringCbCatNExW
+#else
+#define StringCbCatNEx StringCbCatNExA
+#endif // !UNICODE
+
+#ifdef STRSAFE_INLINE
+STRSAFEAPI StringCbCatNExA(char* pszDest, size_t cbDest, const char* pszSrc, size_t cbMaxAppend, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags)
+{
+ HRESULT hr;
+ size_t cchDest;
+ size_t cchRemaining = 0;
+
+ cchDest = cbDest / sizeof(char);
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ size_t cchMaxAppend;
+
+ cchMaxAppend = cbMaxAppend / sizeof(char);
+
+ hr = StringCatNExWorkerA(pszDest, cchDest, cbDest, pszSrc, cchMaxAppend, ppszDestEnd, &cchRemaining, dwFlags);
+ }
+
+ if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
+ {
+ if (pcbRemaining)
+ {
+ // safe to multiply cchRemaining * sizeof(char) since cchRemaining < STRSAFE_MAX_CCH and sizeof(char) is 1
+ *pcbRemaining = (cchRemaining * sizeof(char)) + (cbDest % sizeof(char));
+ }
+ }
+
+ return hr;
+}
+
+#if defined(FEATURE_PAL) || !defined(PLATFORM_UNIX)
+STRSAFEAPI StringCbCatNExW(WCHAR* pszDest, size_t cbDest, const WCHAR* pszSrc, size_t cbMaxAppend, WCHAR** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags)
+{
+ HRESULT hr;
+ size_t cchDest;
+ size_t cchRemaining = 0;
+
+ cchDest = cbDest / sizeof(WCHAR);
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ size_t cchMaxAppend;
+
+ cchMaxAppend = cbMaxAppend / sizeof(WCHAR);
+
+ hr = StringCatNExWorkerW(pszDest, cchDest, cbDest, pszSrc, cchMaxAppend, ppszDestEnd, &cchRemaining, dwFlags);
+ }
+
+ if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
+ {
+ if (pcbRemaining)
+ {
+ // safe to multiply cchRemaining * sizeof(WCHAR) since cchRemaining < STRSAFE_MAX_CCH and sizeof(WCHAR) is 2
+ *pcbRemaining = (cchRemaining * sizeof(WCHAR)) + (cbDest % sizeof(WCHAR));
+ }
+ }
+
+ return hr;
+}
+#endif // FEATURE_PAL || !PLATFORM_UNIX
+#endif // STRSAFE_INLINE
+#endif // !STRSAFE_NO_CB_FUNCTIONS
+
+
+#ifndef STRSAFE_NO_CCH_FUNCTIONS
+/*++
+
+STDAPI StringCchVPrintf(LPTSTR pszDest,
+ size_t cchDest,
+ LPCTSTR pszFormat,
+ va_list argList);
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'vsprintf'.
+ The size of the destination buffer (in characters) is a parameter and
+ this function will not write past the end of this buffer and it will
+ ALWAYS null terminate the destination buffer (unless it is zero length).
+
+ This function returns a hresult, and not a pointer. It returns a S_OK
+ if the string was printed without truncation and null terminated, otherwise
+ it will return a failure code. In failure cases it will return a truncated
+ version of the ideal result.
+
+Arguments:
+
+ pszDest - destination string
+
+ cchDest - size of destination buffer in characters
+ length must be sufficient to hold the resulting formatted
+ string, including the null terminator.
+
+ pszFormat - format string which must be null terminated
+
+ argList - va_list from the variable arguments according to the
+ stdarg.h convention
+
+Notes:
+ Behavior is undefined if destination, format strings or any arguments
+ strings overlap.
+
+ pszDest and pszFormat should not be NULL. See StringCchVPrintfEx if you
+ require the handling of NULL values.
+
+Return Value:
+
+ S_OK - if there was sufficient space in the dest buffer for
+ the resultant string and it was null terminated.
+
+ failure - you can use the macro HRESULT_CODE() to get a win32 error
+ code for all falure cases
+
+ STRSAFE_E_INSUFFICIENT_BUFFER /
+ HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
+ - this return value is an indication that the print operation
+ failed due to insufficient space. When this error occurs,
+ the destination buffer is modified to contain a truncated
+ version of the ideal result and is null terminated. This
+ is useful for situations where truncation is ok.
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function
+
+--*/
+
+STRSAFEAPI StringCchVPrintfA(char* pszDest, size_t cchDest, const char* pszFormat, va_list argList);
+STRSAFEAPI StringCchVPrintfW(WCHAR* pszDest, size_t cchDest, const WCHAR* pszFormat, va_list argList);
+#ifdef UNICODE
+#define StringCchVPrintf StringCchVPrintfW
+#else
+#define StringCchVPrintf StringCchVPrintfA
+#endif // !UNICODE
+
+#ifdef STRSAFE_INLINE
+STRSAFEAPI StringCchVPrintfA(char* pszDest, size_t cchDest, const char* pszFormat, va_list argList)
+{
+ HRESULT hr;
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringVPrintfWorkerA(pszDest, cchDest, pszFormat, argList);
+ }
+
+ return hr;
+}
+
+#if defined(FEATURE_PAL) || !defined(PLATFORM_UNIX)
+STRSAFEAPI StringCchVPrintfW(WCHAR* pszDest, size_t cchDest, const WCHAR* pszFormat, va_list argList)
+{
+ HRESULT hr;
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringVPrintfWorkerW(pszDest, cchDest, pszFormat, argList);
+ }
+
+ return hr;
+}
+#endif // FEATURE_PAL || !PLATFORM_UNIX
+#endif // STRSAFE_INLINE
+#endif // !STRSAFE_NO_CCH_FUNCTIONS
+
+
+#ifndef STRSAFE_NO_CB_FUNCTIONS
+/*++
+
+STDAPI StringCbVPrintf(LPTSTR pszDest,
+ size_t cbDest,
+ LPCTSTR pszFormat,
+ va_list argList);
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'vsprintf'.
+ The size of the destination buffer (in bytes) is a parameter and
+ this function will not write past the end of this buffer and it will
+ ALWAYS null terminate the destination buffer (unless it is zero length).
+
+ This function returns a hresult, and not a pointer. It returns a S_OK
+ if the string was printed without truncation and null terminated, otherwise
+ it will return a failure code. In failure cases it will return a truncated
+ version of the ideal result.
+
+Arguments:
+
+ pszDest - destination string
+
+ cbDest - size of destination buffer in bytes
+ length must be sufficient to hold the resulting formatted
+ string, including the null terminator.
+
+ pszFormat - format string which must be null terminated
+
+ argList - va_list from the variable arguments according to the
+ stdarg.h convention
+
+Notes:
+ Behavior is undefined if destination, format strings or any arguments
+ strings overlap.
+
+ pszDest and pszFormat should not be NULL. See StringCbVPrintfEx if you
+ require the handling of NULL values.
+
+
+Return Value:
+
+ S_OK - if there was sufficient space in the dest buffer for
+ the resultant string and it was null terminated.
+
+ failure - you can use the macro HRESULT_CODE() to get a win32 error
+ code for all falure cases
+
+ STRSAFE_E_INSUFFICIENT_BUFFER /
+ HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
+ - this return value is an indication that the print operation
+ failed due to insufficient space. When this error occurs,
+ the destination buffer is modified to contain a truncated
+ version of the ideal result and is null terminated. This
+ is useful for situations where truncation is ok.
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function
+
+--*/
+
+STRSAFEAPI StringCbVPrintfA(char* pszDest, size_t cbDest, const char* pszFormat, va_list argList);
+STRSAFEAPI StringCbVPrintfW(WCHAR* pszDest, size_t cbDest, const WCHAR* pszFormat, va_list argList);
+#ifdef UNICODE
+#define StringCbVPrintf StringCbVPrintfW
+#else
+#define StringCbVPrintf StringCbVPrintfA
+#endif // !UNICODE
+
+#ifdef STRSAFE_INLINE
+STRSAFEAPI StringCbVPrintfA(char* pszDest, size_t cbDest, const char* pszFormat, va_list argList)
+{
+ HRESULT hr;
+ size_t cchDest;
+
+ cchDest = cbDest / sizeof(char);
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringVPrintfWorkerA(pszDest, cchDest, pszFormat, argList);
+ }
+
+ return hr;
+}
+
+#if defined(FEATURE_PAL) || !defined(PLATFORM_UNIX)
+STRSAFEAPI StringCbVPrintfW(WCHAR* pszDest, size_t cbDest, const WCHAR* pszFormat, va_list argList)
+{
+ HRESULT hr;
+ size_t cchDest;
+
+ cchDest = cbDest / sizeof(WCHAR);
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringVPrintfWorkerW(pszDest, cchDest, pszFormat, argList);
+ }
+
+ return hr;
+}
+#endif // FEATURE_PAL || !PLATFORM_UNIX
+#endif // STRSAFE_INLINE
+#endif // !STRSAFE_NO_CB_FUNCTIONS
+
+
+#ifndef STRSAFE_NO_CCH_FUNCTIONS
+/*++
+
+STDAPI StringCchPrintf(LPTSTR pszDest,
+ size_t cchDest,
+ LPCTSTR pszFormat,
+ ...);
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'sprintf'.
+ The size of the destination buffer (in characters) is a parameter and
+ this function will not write past the end of this buffer and it will
+ ALWAYS null terminate the destination buffer (unless it is zero length).
+
+ This function returns a hresult, and not a pointer. It returns a S_OK
+ if the string was printed without truncation and null terminated, otherwise
+ it will return a failure code. In failure cases it will return a truncated
+ version of the ideal result.
+
+Arguments:
+
+ pszDest - destination string
+
+ cchDest - size of destination buffer in characters
+ length must be sufficient to hold the resulting formatted
+ string, including the null terminator.
+
+ pszFormat - format string which must be null terminated
+
+ ... - additional parameters to be formatted according to
+ the format string
+
+Notes:
+ Behavior is undefined if destination, format strings or any arguments
+ strings overlap.
+
+ pszDest and pszFormat should not be NULL. See StringCchPrintfEx if you
+ require the handling of NULL values.
+
+Return Value:
+
+ S_OK - if there was sufficient space in the dest buffer for
+ the resultant string and it was null terminated.
+
+ failure - you can use the macro HRESULT_CODE() to get a win32 error
+ code for all falure cases
+
+ STRSAFE_E_INSUFFICIENT_BUFFER /
+ HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
+ - this return value is an indication that the print operation
+ failed due to insufficient space. When this error occurs,
+ the destination buffer is modified to contain a truncated
+ version of the ideal result and is null terminated. This
+ is useful for situations where truncation is ok.
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function
+
+--*/
+
+STRSAFEAPI StringCchPrintfA(char* pszDest, size_t cchDest, const char* pszFormat, ...);
+STRSAFEAPI StringCchPrintfW(WCHAR* pszDest, size_t cchDest, const WCHAR* pszFormat, ...);
+#ifdef UNICODE
+#define StringCchPrintf StringCchPrintfW
+#else
+#define StringCchPrintf StringCchPrintfA
+#endif // !UNICODE
+
+#ifdef STRSAFE_INLINE
+STRSAFEAPI StringCchPrintfA(char* pszDest, size_t cchDest, const char* pszFormat, ...)
+{
+ HRESULT hr;
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ va_list argList;
+
+ va_start(argList, pszFormat);
+
+ hr = StringVPrintfWorkerA(pszDest, cchDest, pszFormat, argList);
+
+ va_end(argList);
+ }
+
+ return hr;
+}
+
+#if defined(FEATURE_PAL) || !defined(PLATFORM_UNIX)
+STRSAFEAPI StringCchPrintfW(WCHAR* pszDest, size_t cchDest, const WCHAR* pszFormat, ...)
+{
+ HRESULT hr;
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ va_list argList;
+
+ va_start(argList, pszFormat);
+
+ hr = StringVPrintfWorkerW(pszDest, cchDest, pszFormat, argList);
+
+ va_end(argList);
+ }
+
+ return hr;
+}
+#endif // FEATURE_PAL || !PLATFORM_UNIX
+#endif // STRSAFE_INLINE
+#endif // !STRSAFE_NO_CCH_FUNCTIONS
+
+
+#ifndef STRSAFE_NO_CB_FUNCTIONS
+/*++
+
+STDAPI StringCbPrintf(LPTSTR pszDest,
+ size_t cbDest,
+ LPCTSTR pszFormat,
+ ...);
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'sprintf'.
+ The size of the destination buffer (in bytes) is a parameter and
+ this function will not write past the end of this buffer and it will
+ ALWAYS null terminate the destination buffer (unless it is zero length).
+
+ This function returns a hresult, and not a pointer. It returns a S_OK
+ if the string was printed without truncation and null terminated, otherwise
+ it will return a failure code. In failure cases it will return a truncated
+ version of the ideal result.
+
+Arguments:
+
+ pszDest - destination string
+
+ cbDest - size of destination buffer in bytes
+ length must be sufficient to hold the resulting formatted
+ string, including the null terminator.
+
+ pszFormat - format string which must be null terminated
+
+ ... - additional parameters to be formatted according to
+ the format string
+
+Notes:
+ Behavior is undefined if destination, format strings or any arguments
+ strings overlap.
+
+ pszDest and pszFormat should not be NULL. See StringCbPrintfEx if you
+ require the handling of NULL values.
+
+
+Return Value:
+
+ S_OK - if there was sufficient space in the dest buffer for
+ the resultant string and it was null terminated.
+
+ failure - you can use the macro HRESULT_CODE() to get a win32 error
+ code for all falure cases
+
+ STRSAFE_E_INSUFFICIENT_BUFFER /
+ HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
+ - this return value is an indication that the print operation
+ failed due to insufficient space. When this error occurs,
+ the destination buffer is modified to contain a truncated
+ version of the ideal result and is null terminated. This
+ is useful for situations where truncation is ok.
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function
+
+--*/
+
+STRSAFEAPI StringCbPrintfA(char* pszDest, size_t cbDest, const char* pszFormat, ...);
+STRSAFEAPI StringCbPrintfW(WCHAR* pszDest, size_t cbDest, const WCHAR* pszFormat, ...);
+#ifdef UNICODE
+#define StringCbPrintf StringCbPrintfW
+#else
+#define StringCbPrintf StringCbPrintfA
+#endif // !UNICODE
+
+#ifdef STRSAFE_INLINE
+STRSAFEAPI StringCbPrintfA(char* pszDest, size_t cbDest, const char* pszFormat, ...)
+{
+ HRESULT hr;
+ size_t cchDest;
+
+ cchDest = cbDest / sizeof(char);
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ va_list argList;
+
+ va_start(argList, pszFormat);
+
+ hr = StringVPrintfWorkerA(pszDest, cchDest, pszFormat, argList);
+
+ va_end(argList);
+ }
+
+ return hr;
+}
+
+#if defined(FEATURE_PAL) || !defined(PLATFORM_UNIX)
+STRSAFEAPI StringCbPrintfW(WCHAR* pszDest, size_t cbDest, const WCHAR* pszFormat, ...)
+{
+ HRESULT hr;
+ size_t cchDest;
+
+ cchDest = cbDest / sizeof(WCHAR);
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ va_list argList;
+
+ va_start(argList, pszFormat);
+
+ hr = StringVPrintfWorkerW(pszDest, cchDest, pszFormat, argList);
+
+ va_end(argList);
+ }
+
+ return hr;
+}
+#endif // FEATURE_PAL || !PLATFORM_UNIX
+#endif // STRSAFE_INLINE
+#endif // !STRSAFE_NO_CB_FUNCTIONS
+
+
+#ifndef STRSAFE_NO_CCH_FUNCTIONS
+/*++
+
+STDAPI StringCchPrintfEx(LPTSTR pszDest,
+ size_t cchDest,
+ LPTSTR* ppszDestEnd,
+ size_t* pcchRemaining,
+ DWORD dwFlags,
+ LPCTSTR pszFormat,
+ ...);
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'sprintf' with
+ some additional parameters. In addition to functionality provided by
+ StringCchPrintf, this routine also returns a pointer to the end of the
+ destination string and the number of characters left in the destination string
+ including the null terminator. The flags parameter allows additional controls.
+
+Arguments:
+
+ pszDest - destination string
+
+ cchDest - size of destination buffer in characters.
+ length must be sufficient to contain the resulting
+ formatted string plus the null terminator.
+
+ ppszDestEnd - if ppszDestEnd is non-null, the function will return a
+ pointer to the end of the destination string. If the
+ function printed any data, the result will point to the
+ null termination character
+
+ pcchRemaining - if pcchRemaining is non-null, the function will return
+ the number of characters left in the destination string,
+ including the null terminator
+
+ dwFlags - controls some details of the string copy:
+
+ STRSAFE_FILL_BEHIND_NULL
+ if the function succeeds, the low byte of dwFlags will be
+ used to fill the uninitialize part of destination buffer
+ behind the null terminator
+
+ STRSAFE_IGNORE_NULLS
+ treat NULL string pointers like empty strings (TEXT(""))
+
+ STRSAFE_FILL_ON_FAILURE
+ if the function fails, the low byte of dwFlags will be
+ used to fill all of the destination buffer, and it will
+ be null terminated. This will overwrite any truncated
+ string returned when the failure is
+ STRSAFE_E_INSUFFICIENT_BUFFER
+
+ STRSAFE_NO_TRUNCATION /
+ STRSAFE_NULL_ON_FAILURE
+ if the function fails, the destination buffer will be set
+ to the empty string. This will overwrite any truncated string
+ returned when the failure is STRSAFE_E_INSUFFICIENT_BUFFER.
+
+ pszFormat - format string which must be null terminated
+
+ ... - additional parameters to be formatted according to
+ the format string
+
+Notes:
+ Behavior is undefined if destination, format strings or any arguments
+ strings overlap.
+
+ pszDest and pszFormat should not be NULL unless the STRSAFE_IGNORE_NULLS
+ flag is specified. If STRSAFE_IGNORE_NULLS is passed, both pszDest and
+ pszFormat may be NULL. An error may still be returned even though NULLS
+ are ignored due to insufficient space.
+
+Return Value:
+
+ S_OK - if there was source data and it was all concatenated and the
+ resultant dest string was null terminated
+
+ failure - you can use the macro HRESULT_CODE() to get a win32 error
+ code for all falure cases
+
+ STRSAFE_E_INSUFFICIENT_BUFFER /
+ HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
+ - this return value is an indication that the print operation
+ failed due to insufficient space. When this error occurs,
+ the destination buffer is modified to contain a truncated
+ version of the ideal result and is null terminated. This
+ is useful for situations where truncation is ok.
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function
+
+--*/
+
+STRSAFEAPI StringCchPrintfExA(char* pszDest, size_t cchDest, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const char* pszFormat, ...);
+STRSAFEAPI StringCchPrintfExW(WCHAR* pszDest, size_t cchDest, WCHAR** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const WCHAR* pszFormat, ...);
+#ifdef UNICODE
+#define StringCchPrintfEx StringCchPrintfExW
+#else
+#define StringCchPrintfEx StringCchPrintfExA
+#endif // !UNICODE
+
+#ifdef STRSAFE_INLINE
+STRSAFEAPI StringCchPrintfExA(char* pszDest, size_t cchDest, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const char* pszFormat, ...)
+{
+ HRESULT hr;
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ size_t cbDest;
+ va_list argList;
+
+ // safe to multiply cchDest * sizeof(char) since cchDest < STRSAFE_MAX_CCH and sizeof(char) is 1
+ cbDest = cchDest * sizeof(char);
+ va_start(argList, pszFormat);
+
+ hr = StringVPrintfExWorkerA(pszDest, cchDest, cbDest, ppszDestEnd, pcchRemaining, dwFlags, pszFormat, argList);
+
+ va_end(argList);
+ }
+
+ return hr;
+}
+
+#if defined(FEATURE_PAL) || !defined(PLATFORM_UNIX)
+STRSAFEAPI StringCchPrintfExW(WCHAR* pszDest, size_t cchDest, WCHAR** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const WCHAR* pszFormat, ...)
+{
+ HRESULT hr;
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ size_t cbDest;
+ va_list argList;
+
+ // safe to multiply cchDest * sizeof(WCHAR) since cchDest < STRSAFE_MAX_CCH and sizeof(WCHAR) is 2
+ cbDest = cchDest * sizeof(WCHAR);
+ va_start(argList, pszFormat);
+
+ hr = StringVPrintfExWorkerW(pszDest, cchDest, cbDest, ppszDestEnd, pcchRemaining, dwFlags, pszFormat, argList);
+
+ va_end(argList);
+ }
+
+ return hr;
+}
+#endif // FEATURE_PAL || !PLATFORM_UNIX
+#endif // STRSAFE_INLINE
+#endif // !STRSAFE_NO_CCH_FUNCTIONS
+
+
+#ifndef STRSAFE_NO_CB_FUNCTIONS
+/*++
+
+STDAPI StringCbPrintfEx(LPTSTR pszDest,
+ size_t cbDest,
+ LPTSTR* ppszDestEnd,
+ size_t* pcbRemaining,
+ DWORD dwFlags,
+ LPCTSTR pszFormat,
+ ...);
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'sprintf' with
+ some additional parameters. In addition to functionality provided by
+ StringCbPrintf, this routine also returns a pointer to the end of the
+ destination string and the number of bytes left in the destination string
+ including the null terminator. The flags parameter allows additional controls.
+
+Arguments:
+
+ pszDest - destination string
+
+ cbDest - size of destination buffer in bytes.
+ length must be sufficient to contain the resulting
+ formatted string plus the null terminator.
+
+ ppszDestEnd - if ppszDestEnd is non-null, the function will return a
+ pointer to the end of the destination string. If the
+ function printed any data, the result will point to the
+ null termination character
+
+ pcbRemaining - if pcbRemaining is non-null, the function will return
+ the number of bytes left in the destination string,
+ including the null terminator
+
+ dwFlags - controls some details of the string copy:
+
+ STRSAFE_FILL_BEHIND_NULL
+ if the function succeeds, the low byte of dwFlags will be
+ used to fill the uninitialize part of destination buffer
+ behind the null terminator
+
+ STRSAFE_IGNORE_NULLS
+ treat NULL string pointers like empty strings (TEXT(""))
+
+ STRSAFE_FILL_ON_FAILURE
+ if the function fails, the low byte of dwFlags will be
+ used to fill all of the destination buffer, and it will
+ be null terminated. This will overwrite any truncated
+ string returned when the failure is
+ STRSAFE_E_INSUFFICIENT_BUFFER
+
+ STRSAFE_NO_TRUNCATION /
+ STRSAFE_NULL_ON_FAILURE
+ if the function fails, the destination buffer will be set
+ to the empty string. This will overwrite any truncated string
+ returned when the failure is STRSAFE_E_INSUFFICIENT_BUFFER.
+
+ pszFormat - format string which must be null terminated
+
+ ... - additional parameters to be formatted according to
+ the format string
+
+Notes:
+ Behavior is undefined if destination, format strings or any arguments
+ strings overlap.
+
+ pszDest and pszFormat should not be NULL unless the STRSAFE_IGNORE_NULLS
+ flag is specified. If STRSAFE_IGNORE_NULLS is passed, both pszDest and
+ pszFormat may be NULL. An error may still be returned even though NULLS
+ are ignored due to insufficient space.
+
+Return Value:
+
+ S_OK - if there was source data and it was all concatenated and the
+ resultant dest string was null terminated
+
+ failure - you can use the macro HRESULT_CODE() to get a win32 error
+ code for all falure cases
+
+ STRSAFE_E_INSUFFICIENT_BUFFER /
+ HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
+ - this return value is an indication that the print operation
+ failed due to insufficient space. When this error occurs,
+ the destination buffer is modified to contain a truncated
+ version of the ideal result and is null terminated. This
+ is useful for situations where truncation is ok.
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function
+
+--*/
+
+STRSAFEAPI StringCbPrintfExA(char* pszDest, size_t cbDest, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags, const char* pszFormat, ...);
+STRSAFEAPI StringCbPrintfExW(WCHAR* pszDest, size_t cbDest, WCHAR** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags, const WCHAR* pszFormat, ...);
+#ifdef UNICODE
+#define StringCbPrintfEx StringCbPrintfExW
+#else
+#define StringCbPrintfEx StringCbPrintfExA
+#endif // !UNICODE
+
+#ifdef STRSAFE_INLINE
+STRSAFEAPI StringCbPrintfExA(char* pszDest, size_t cbDest, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags, const char* pszFormat, ...)
+{
+ HRESULT hr;
+ size_t cchDest;
+ size_t cchRemaining = 0;
+
+ cchDest = cbDest / sizeof(char);
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ va_list argList;
+
+ va_start(argList, pszFormat);
+
+ hr = StringVPrintfExWorkerA(pszDest, cchDest, cbDest, ppszDestEnd, &cchRemaining, dwFlags, pszFormat, argList);
+
+ va_end(argList);
+ }
+
+ if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
+ {
+ if (pcbRemaining)
+ {
+ // safe to multiply cchRemaining * sizeof(char) since cchRemaining < STRSAFE_MAX_CCH and sizeof(char) is 1
+ *pcbRemaining = (cchRemaining * sizeof(char)) + (cbDest % sizeof(char));
+ }
+ }
+
+ return hr;
+}
+
+#if defined(FEATURE_PAL) || !defined(PLATFORM_UNIX)
+STRSAFEAPI StringCbPrintfExW(WCHAR* pszDest, size_t cbDest, WCHAR** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags, const WCHAR* pszFormat, ...)
+{
+ HRESULT hr;
+ size_t cchDest;
+ size_t cchRemaining = 0;
+
+ cchDest = cbDest / sizeof(WCHAR);
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ va_list argList;
+
+ va_start(argList, pszFormat);
+
+ hr = StringVPrintfExWorkerW(pszDest, cchDest, cbDest, ppszDestEnd, &cchRemaining, dwFlags, pszFormat, argList);
+
+ va_end(argList);
+ }
+
+ if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
+ {
+ if (pcbRemaining)
+ {
+ // safe to multiply cchRemaining * sizeof(WCHAR) since cchRemaining < STRSAFE_MAX_CCH and sizeof(WCHAR) is 2
+ *pcbRemaining = (cchRemaining * sizeof(WCHAR)) + (cbDest % sizeof(WCHAR));
+ }
+ }
+
+ return hr;
+}
+#endif // FEATURE_PAL || !PLATFORM_UNIX
+#endif // STRSAFE_INLINE
+#endif // !STRSAFE_NO_CB_FUNCTIONS
+
+
+#ifndef STRSAFE_NO_CCH_FUNCTIONS
+/*++
+
+STDAPI StringCchVPrintfEx(LPTSTR pszDest,
+ size_t cchDest,
+ LPTSTR* ppszDestEnd,
+ size_t* pcchRemaining,
+ DWORD dwFlags,
+ LPCTSTR pszFormat,
+ va_list argList);
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'vsprintf' with
+ some additional parameters. In addition to functionality provided by
+ StringCchVPrintf, this routine also returns a pointer to the end of the
+ destination string and the number of characters left in the destination string
+ including the null terminator. The flags parameter allows additional controls.
+
+Arguments:
+
+ pszDest - destination string
+
+ cchDest - size of destination buffer in characters.
+ length must be sufficient to contain the resulting
+ formatted string plus the null terminator.
+
+ ppszDestEnd - if ppszDestEnd is non-null, the function will return a
+ pointer to the end of the destination string. If the
+ function printed any data, the result will point to the
+ null termination character
+
+ pcchRemaining - if pcchRemaining is non-null, the function will return
+ the number of characters left in the destination string,
+ including the null terminator
+
+ dwFlags - controls some details of the string copy:
+
+ STRSAFE_FILL_BEHIND_NULL
+ if the function succeeds, the low byte of dwFlags will be
+ used to fill the uninitialize part of destination buffer
+ behind the null terminator
+
+ STRSAFE_IGNORE_NULLS
+ treat NULL string pointers like empty strings (TEXT(""))
+
+ STRSAFE_FILL_ON_FAILURE
+ if the function fails, the low byte of dwFlags will be
+ used to fill all of the destination buffer, and it will
+ be null terminated. This will overwrite any truncated
+ string returned when the failure is
+ STRSAFE_E_INSUFFICIENT_BUFFER
+
+ STRSAFE_NO_TRUNCATION /
+ STRSAFE_NULL_ON_FAILURE
+ if the function fails, the destination buffer will be set
+ to the empty string. This will overwrite any truncated string
+ returned when the failure is STRSAFE_E_INSUFFICIENT_BUFFER.
+
+ pszFormat - format string which must be null terminated
+
+ argList - va_list from the variable arguments according to the
+ stdarg.h convention
+
+Notes:
+ Behavior is undefined if destination, format strings or any arguments
+ strings overlap.
+
+ pszDest and pszFormat should not be NULL unless the STRSAFE_IGNORE_NULLS
+ flag is specified. If STRSAFE_IGNORE_NULLS is passed, both pszDest and
+ pszFormat may be NULL. An error may still be returned even though NULLS
+ are ignored due to insufficient space.
+
+Return Value:
+
+ S_OK - if there was source data and it was all concatenated and the
+ resultant dest string was null terminated
+
+ failure - you can use the macro HRESULT_CODE() to get a win32 error
+ code for all falure cases
+
+ STRSAFE_E_INSUFFICIENT_BUFFER /
+ HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
+ - this return value is an indication that the print operation
+ failed due to insufficient space. When this error occurs,
+ the destination buffer is modified to contain a truncated
+ version of the ideal result and is null terminated. This
+ is useful for situations where truncation is ok.
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function
+
+--*/
+
+STRSAFEAPI StringCchVPrintfExA(char* pszDest, size_t cchDest, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const char* pszFormat, va_list argList);
+STRSAFEAPI StringCchVPrintfExW(WCHAR* pszDest, size_t cchDest, WCHAR** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const WCHAR* pszFormat, va_list argList);
+#ifdef UNICODE
+#define StringCchVPrintfEx StringCchVPrintfExW
+#else
+#define StringCchVPrintfEx StringCchVPrintfExA
+#endif // !UNICODE
+
+#ifdef STRSAFE_INLINE
+STRSAFEAPI StringCchVPrintfExA(char* pszDest, size_t cchDest, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const char* pszFormat, va_list argList)
+{
+ HRESULT hr;
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ size_t cbDest;
+
+ // safe to multiply cchDest * sizeof(char) since cchDest < STRSAFE_MAX_CCH and sizeof(char) is 1
+ cbDest = cchDest * sizeof(char);
+
+ hr = StringVPrintfExWorkerA(pszDest, cchDest, cbDest, ppszDestEnd, pcchRemaining, dwFlags, pszFormat, argList);
+ }
+
+ return hr;
+}
+
+#if defined(FEATURE_PAL) || !defined(PLATFORM_UNIX)
+STRSAFEAPI StringCchVPrintfExW(WCHAR* pszDest, size_t cchDest, WCHAR** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const WCHAR* pszFormat, va_list argList)
+{
+ HRESULT hr;
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ size_t cbDest;
+
+ // safe to multiply cchDest * sizeof(WCHAR) since cchDest < STRSAFE_MAX_CCH and sizeof(WCHAR) is 2
+ cbDest = cchDest * sizeof(WCHAR);
+
+ hr = StringVPrintfExWorkerW(pszDest, cchDest, cbDest, ppszDestEnd, pcchRemaining, dwFlags, pszFormat, argList);
+ }
+
+ return hr;
+}
+#endif // FEATURE_PAL || !PLATFORM_UNIX
+#endif // STRSAFE_INLINE
+#endif // !STRSAFE_NO_CCH_FUNCTIONS
+
+
+#ifndef STRSAFE_NO_CB_FUNCTIONS
+/*++
+
+STDAPI StringCbVPrintfEx(LPTSTR pszDest,
+ size_t cbDest,
+ LPTSTR* ppszDestEnd,
+ size_t* pcbRemaining,
+ DWORD dwFlags,
+ LPCTSTR pszFormat,
+ va_list argList);
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'vsprintf' with
+ some additional parameters. In addition to functionality provided by
+ StringCbVPrintf, this routine also returns a pointer to the end of the
+ destination string and the number of characters left in the destination string
+ including the null terminator. The flags parameter allows additional controls.
+
+Arguments:
+
+ pszDest - destination string
+
+ cbDest - size of destination buffer in bytes.
+ length must be sufficient to contain the resulting
+ formatted string plus the null terminator.
+
+ ppszDestEnd - if ppszDestEnd is non-null, the function will return
+ a pointer to the end of the destination string. If the
+ function printed any data, the result will point to the
+ null termination character
+
+ pcbRemaining - if pcbRemaining is non-null, the function will return
+ the number of bytes left in the destination string,
+ including the null terminator
+
+ dwFlags - controls some details of the string copy:
+
+ STRSAFE_FILL_BEHIND_NULL
+ if the function succeeds, the low byte of dwFlags will be
+ used to fill the uninitialize part of destination buffer
+ behind the null terminator
+
+ STRSAFE_IGNORE_NULLS
+ treat NULL string pointers like empty strings (TEXT(""))
+
+ STRSAFE_FILL_ON_FAILURE
+ if the function fails, the low byte of dwFlags will be
+ used to fill all of the destination buffer, and it will
+ be null terminated. This will overwrite any truncated
+ string returned when the failure is
+ STRSAFE_E_INSUFFICIENT_BUFFER
+
+ STRSAFE_NO_TRUNCATION /
+ STRSAFE_NULL_ON_FAILURE
+ if the function fails, the destination buffer will be set
+ to the empty string. This will overwrite any truncated string
+ returned when the failure is STRSAFE_E_INSUFFICIENT_BUFFER.
+
+ pszFormat - format string which must be null terminated
+
+ argList - va_list from the variable arguments according to the
+ stdarg.h convention
+
+Notes:
+ Behavior is undefined if destination, format strings or any arguments
+ strings overlap.
+
+ pszDest and pszFormat should not be NULL unless the STRSAFE_IGNORE_NULLS
+ flag is specified. If STRSAFE_IGNORE_NULLS is passed, both pszDest and
+ pszFormat may be NULL. An error may still be returned even though NULLS
+ are ignored due to insufficient space.
+
+Return Value:
+
+ S_OK - if there was source data and it was all concatenated and the
+ resultant dest string was null terminated
+
+ failure - you can use the macro HRESULT_CODE() to get a win32 error
+ code for all falure cases
+
+ STRSAFE_E_INSUFFICIENT_BUFFER /
+ HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
+ - this return value is an indication that the print operation
+ failed due to insufficient space. When this error occurs,
+ the destination buffer is modified to contain a truncated
+ version of the ideal result and is null terminated. This
+ is useful for situations where truncation is ok.
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function
+
+--*/
+
+STRSAFEAPI StringCbVPrintfExA(char* pszDest, size_t cbDest, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags, const char* pszFormat, va_list argList);
+STRSAFEAPI StringCbVPrintfExW(WCHAR* pszDest, size_t cbDest, WCHAR** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags, const WCHAR* pszFormat, va_list argList);
+#ifdef UNICODE
+#define StringCbVPrintfEx StringCbVPrintfExW
+#else
+#define StringCbVPrintfEx StringCbVPrintfExA
+#endif // !UNICODE
+
+#ifdef STRSAFE_INLINE
+STRSAFEAPI StringCbVPrintfExA(char* pszDest, size_t cbDest, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags, const char* pszFormat, va_list argList)
+{
+ HRESULT hr;
+ size_t cchDest;
+ size_t cchRemaining = 0;
+
+ cchDest = cbDest / sizeof(char);
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringVPrintfExWorkerA(pszDest, cchDest, cbDest, ppszDestEnd, &cchRemaining, dwFlags, pszFormat, argList);
+ }
+
+ if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
+ {
+ if (pcbRemaining)
+ {
+ // safe to multiply cchRemaining * sizeof(char) since cchRemaining < STRSAFE_MAX_CCH and sizeof(char) is 1
+ *pcbRemaining = (cchRemaining * sizeof(char)) + (cbDest % sizeof(char));
+ }
+ }
+
+ return hr;
+}
+
+#if defined(FEATURE_PAL) || !defined(PLATFORM_UNIX)
+STRSAFEAPI StringCbVPrintfExW(WCHAR* pszDest, size_t cbDest, WCHAR** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags, const WCHAR* pszFormat, va_list argList)
+{
+ HRESULT hr;
+ size_t cchDest;
+ size_t cchRemaining = 0;
+
+ cchDest = cbDest / sizeof(WCHAR);
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringVPrintfExWorkerW(pszDest, cchDest, cbDest, ppszDestEnd, &cchRemaining, dwFlags, pszFormat, argList);
+ }
+
+ if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
+ {
+ if (pcbRemaining)
+ {
+ // safe to multiply cchRemaining * sizeof(WCHAR) since cchRemaining < STRSAFE_MAX_CCH and sizeof(WCHAR) is 2
+ *pcbRemaining = (cchRemaining * sizeof(WCHAR)) + (cbDest % sizeof(WCHAR));
+ }
+ }
+
+ return hr;
+}
+#endif // FEATURE_PAL || !PLATFORM_UNIX
+#endif // STRSAFE_INLINE
+#endif // !STRSAFE_NO_CB_FUNCTIONS
+
+
+#ifndef STRSAFE_NO_CCH_FUNCTIONS
+/*++
+
+STDAPI StringCchGets(LPTSTR pszDest,
+ size_t cchDest);
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'gets'.
+ The size of the destination buffer (in characters) is a parameter and
+ this function will not write past the end of this buffer and it will
+ ALWAYS null terminate the destination buffer (unless it is zero length).
+
+ This routine is not a replacement for fgets. That function does not replace
+ newline characters with a null terminator.
+
+ This function returns a hresult, and not a pointer. It returns a S_OK
+ if any characters were read from stdin and copied to pszDest and pszDest was
+ null terminated, otherwise it will return a failure code.
+
+Arguments:
+
+ pszDest - destination string
+
+ cchDest - size of destination buffer in characters.
+
+Notes:
+ pszDest should not be NULL. See StringCchGetsEx if you require the handling
+ of NULL values.
+
+ cchDest must be > 1 for this function to succeed.
+
+Return Value:
+
+ S_OK - data was read from stdin and copied, and the resultant dest
+ string was null terminated
+
+ failure - you can use the macro HRESULT_CODE() to get a win32 error
+ code for all hresult falure cases
+
+ STRSAFE_E_END_OF_FILE
+ - this return value indicates an error or end-of-file condition,
+ use feof or ferror to determine which one has occurred.
+
+ STRSAFE_E_INSUFFICIENT_BUFFER /
+ HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
+ - this return value is an indication that there was insufficient
+ space in the destination buffer to copy any data
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function.
+
+--*/
+
+#ifndef FEATURE_PAL
+#ifndef STRSAFE_LIB_IMPL
+STRSAFE_INLINE_API StringCchGetsA(char* pszDest, size_t cchDest);
+STRSAFE_INLINE_API StringCchGetsW(WCHAR* pszDest, size_t cchDest);
+#ifdef UNICODE
+#define StringCchGets StringCchGetsW
+#else
+#define StringCchGets StringCchGetsA
+#endif // !UNICODE
+
+STRSAFE_INLINE_API StringCchGetsA(char* pszDest, size_t cchDest)
+{
+ HRESULT hr;
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ size_t cbDest;
+
+ // safe to multiply cchDest * sizeof(char) since cchDest < STRSAFE_MAX_CCH and sizeof(char) is 1
+ cbDest = cchDest * sizeof(char);
+
+ hr = StringGetsExWorkerA(pszDest, cchDest, cbDest, NULL, NULL, 0);
+ }
+
+ return hr;
+}
+
+#if defined(FEATURE_PAL) || !defined(PLATFORM_UNIX)
+STRSAFE_INLINE_API StringCchGetsW(WCHAR* pszDest, size_t cchDest)
+{
+ HRESULT hr;
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ size_t cbDest;
+
+ // safe to multiply cchDest * sizeof(WCHAR) since cchDest < STRSAFE_MAX_CCH and sizeof(WCHAR) is 2
+ cbDest = cchDest * sizeof(WCHAR);
+
+ hr = StringGetsExWorkerW(pszDest, cchDest, cbDest, NULL, NULL, 0);
+ }
+
+ return hr;
+}
+#endif // FEATURE_PAL || !PLATFORM_UNIX
+#endif // !STRSAFE_NO_CCH_FUNCTIONS
+#endif // !STRSAFE_LIB_IMPL
+#endif // !FEATURE_PAL
+
+#ifndef STRSAFE_NO_CB_FUNCTIONS
+/*++
+
+STDAPI StringCbGets(LPTSTR pszDest,
+ size_t cbDest);
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'gets'.
+ The size of the destination buffer (in bytes) is a parameter and
+ this function will not write past the end of this buffer and it will
+ ALWAYS null terminate the destination buffer (unless it is zero length).
+
+ This routine is not a replacement for fgets. That function does not replace
+ newline characters with a null terminator.
+
+ This function returns a hresult, and not a pointer. It returns a S_OK
+ if any characters were read from stdin and copied to pszDest and pszDest was
+ null terminated, otherwise it will return a failure code.
+
+Arguments:
+
+ pszDest - destination string
+
+ cbDest - size of destination buffer in bytes.
+
+Notes:
+ pszDest should not be NULL. See StringCbGetsEx if you require the handling
+ of NULL values.
+
+ cbDest must be > sizeof(TCHAR) for this function to succeed.
+
+Return Value:
+
+ S_OK - data was read from stdin and copied, and the resultant dest
+ string was null terminated
+
+ failure - you can use the macro HRESULT_CODE() to get a win32 error
+ code for all hresult falure cases
+
+ STRSAFE_E_END_OF_FILE
+ - this return value indicates an error or end-of-file condition,
+ use feof or ferror to determine which one has occurred.
+
+ STRSAFE_E_INSUFFICIENT_BUFFER /
+ HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
+ - this return value is an indication that there was insufficient
+ space in the destination buffer to copy any data
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function.
+
+--*/
+
+#ifndef FEATURE_PAL
+#ifndef STRSAFE_LIB_IMPL
+STRSAFE_INLINE_API StringCbGetsA(char* pszDest, size_t cbDest);
+STRSAFE_INLINE_API StringCbGetsW(WCHAR* pszDest, size_t cbDest);
+#ifdef UNICODE
+#define StringCbGets StringCbGetsW
+#else
+#define StringCbGets StringCbGetsA
+#endif // !UNICODE
+
+STRSAFE_INLINE_API StringCbGetsA(char* pszDest, size_t cbDest)
+{
+ HRESULT hr;
+ size_t cchDest;
+
+ // convert to count of characters
+ cchDest = cbDest / sizeof(char);
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringGetsExWorkerA(pszDest, cchDest, cbDest, NULL, NULL, 0);
+ }
+
+ return hr;
+}
+
+#if defined(FEATURE_PAL) || !defined(PLATFORM_UNIX)
+STRSAFE_INLINE_API StringCbGetsW(WCHAR* pszDest, size_t cbDest)
+{
+ HRESULT hr;
+ size_t cchDest;
+
+ // convert to count of characters
+ cchDest = cbDest / sizeof(WCHAR);
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringGetsExWorkerW(pszDest, cchDest, cbDest, NULL, NULL, 0);
+ }
+
+ return hr;
+}
+#endif // FEATURE_PAL || !PLATFORM_UNIX
+#endif // !STRSAFE_NO_CB_FUNCTIONS
+#endif // !STRSAFE_LIB_IMPL
+#endif // !FEATURE_PAL
+
+#ifndef STRSAFE_NO_CCH_FUNCTIONS
+/*++
+
+STDAPI StringCchGetsEx(LPTSTR pszDest,
+ size_t cchDest,
+ LPTSTR* ppszDestEnd,
+ size_t* pcchRemaining,
+ DWORD dwFlags);
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'gets' with
+ some additional parameters. In addition to functionality provided by
+ StringCchGets, this routine also returns a pointer to the end of the
+ destination string and the number of characters left in the destination string
+ including the null terminator. The flags parameter allows additional controls.
+
+Arguments:
+
+ pszDest - destination string
+
+ cchDest - size of destination buffer in characters.
+
+ ppszDestEnd - if ppszDestEnd is non-null, the function will return a
+ pointer to the end of the destination string. If the
+ function copied any data, the result will point to the
+ null termination character
+
+ pcchRemaining - if pcchRemaining is non-null, the function will return the
+ number of characters left in the destination string,
+ including the null terminator
+
+ dwFlags - controls some details of the string copy:
+
+ STRSAFE_FILL_BEHIND_NULL
+ if the function succeeds, the low byte of dwFlags will be
+ used to fill the uninitialize part of destination buffer
+ behind the null terminator
+
+ STRSAFE_IGNORE_NULLS
+ treat NULL string pointers like empty strings (TEXT("")).
+
+ STRSAFE_FILL_ON_FAILURE
+ if the function fails, the low byte of dwFlags will be
+ used to fill all of the destination buffer, and it will
+ be null terminated.
+
+ STRSAFE_NO_TRUNCATION /
+ STRSAFE_NULL_ON_FAILURE
+ if the function fails, the destination buffer will be set
+ to the empty string.
+
+Notes:
+ pszDest should not be NULL unless the STRSAFE_IGNORE_NULLS flag is specified.
+ If STRSAFE_IGNORE_NULLS is passed and pszDest is NULL, an error may still be
+ returned even though NULLS are ignored
+
+ cchDest must be > 1 for this function to succeed.
+
+Return Value:
+
+ S_OK - data was read from stdin and copied, and the resultant dest
+ string was null terminated
+
+ failure - you can use the macro HRESULT_CODE() to get a win32 error
+ code for all hresult falure cases
+
+ STRSAFE_E_END_OF_FILE
+ - this return value indicates an error or end-of-file condition,
+ use feof or ferror to determine which one has occurred.
+
+ STRSAFE_E_INSUFFICIENT_BUFFER /
+ HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
+ - this return value is an indication that there was insufficient
+ space in the destination buffer to copy any data
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function.
+
+--*/
+
+#ifndef FEATURE_PAL
+#ifndef STRSAFE_LIB_IMPL
+STRSAFE_INLINE_API StringCchGetsExA(char* pszDest, size_t cchDest, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
+STRSAFE_INLINE_API StringCchGetsExW(WCHAR* pszDest, size_t cchDest, WCHAR** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
+#ifdef UNICODE
+#define StringCchGetsEx StringCchGetsExW
+#else
+#define StringCchGetsEx StringCchGetsExA
+#endif // !UNICODE
+
+STRSAFE_INLINE_API StringCchGetsExA(char* pszDest, size_t cchDest, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
+{
+ HRESULT hr;
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ size_t cbDest;
+
+ // safe to multiply cchDest * sizeof(char) since cchDest < STRSAFE_MAX_CCH and sizeof(char) is 1
+ cbDest = cchDest * sizeof(char);
+
+ hr = StringGetsExWorkerA(pszDest, cchDest, cbDest, ppszDestEnd, pcchRemaining, dwFlags);
+ }
+
+ return hr;
+}
+
+#if defined(FEATURE_PAL) || !defined(PLATFORM_UNIX)
+STRSAFE_INLINE_API StringCchGetsExW(WCHAR* pszDest, size_t cchDest, WCHAR** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
+{
+ HRESULT hr;
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ size_t cbDest;
+
+ // safe to multiply cchDest * sizeof(WCHAR) since cchDest < STRSAFE_MAX_CCH and sizeof(WCHAR) is 2
+ cbDest = cchDest * sizeof(WCHAR);
+
+ hr = StringGetsExWorkerW(pszDest, cchDest, cbDest, ppszDestEnd, pcchRemaining, dwFlags);
+ }
+
+ return hr;
+}
+#endif // FEATURE_PAL || !PLATFORM_UNIX
+#endif // !STRSAFE_NO_CCH_FUNCTIONS
+#endif // !STRSAFE_LIB_IMPL
+#endif // !FEATURE_PAL
+
+#ifndef STRSAFE_NO_CB_FUNCTIONS
+/*++
+
+STDAPI StringCbGetsEx(LPTSTR pszDest,
+ size_t cbDest,
+ LPTSTR* ppszDestEnd,
+ size_t* pcbRemaining,
+ DWORD dwFlags);
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'gets' with
+ some additional parameters. In addition to functionality provided by
+ StringCbGets, this routine also returns a pointer to the end of the
+ destination string and the number of characters left in the destination string
+ including the null terminator. The flags parameter allows additional controls.
+
+Arguments:
+
+ pszDest - destination string
+
+ cbDest - size of destination buffer in bytes.
+
+ ppszDestEnd - if ppszDestEnd is non-null, the function will return a
+ pointer to the end of the destination string. If the
+ function copied any data, the result will point to the
+ null termination character
+
+ pcbRemaining - if pbRemaining is non-null, the function will return the
+ number of bytes left in the destination string,
+ including the null terminator
+
+ dwFlags - controls some details of the string copy:
+
+ STRSAFE_FILL_BEHIND_NULL
+ if the function succeeds, the low byte of dwFlags will be
+ used to fill the uninitialize part of destination buffer
+ behind the null terminator
+
+ STRSAFE_IGNORE_NULLS
+ treat NULL string pointers like empty strings (TEXT("")).
+
+ STRSAFE_FILL_ON_FAILURE
+ if the function fails, the low byte of dwFlags will be
+ used to fill all of the destination buffer, and it will
+ be null terminated.
+
+ STRSAFE_NO_TRUNCATION /
+ STRSAFE_NULL_ON_FAILURE
+ if the function fails, the destination buffer will be set
+ to the empty string.
+
+Notes:
+ pszDest should not be NULL unless the STRSAFE_IGNORE_NULLS flag is specified.
+ If STRSAFE_IGNORE_NULLS is passed and pszDest is NULL, an error may still be
+ returned even though NULLS are ignored
+
+ cbDest must be > sizeof(TCHAR) for this function to succeed
+
+Return Value:
+
+ S_OK - data was read from stdin and copied, and the resultant dest
+ string was null terminated
+
+ failure - you can use the macro HRESULT_CODE() to get a win32 error
+ code for all hresult falure cases
+
+ STRSAFE_E_END_OF_FILE
+ - this return value indicates an error or end-of-file condition,
+ use feof or ferror to determine which one has occurred.
+
+ STRSAFE_E_INSUFFICIENT_BUFFER /
+ HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
+ - this return value is an indication that there was insufficient
+ space in the destination buffer to copy any data
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function.
+
+--*/
+
+#ifndef FEATURE_PAL
+#ifndef STRSAFE_LIB_IMPL
+STRSAFE_INLINE_API StringCbGetsExA(char* pszDest, size_t cbDest, char** ppszDestEnd, size_t* pbRemaining, unsigned long dwFlags);
+STRSAFE_INLINE_API StringCbGetsExW(WCHAR* pszDest, size_t cbDest, WCHAR** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags);
+#ifdef UNICODE
+#define StringCbGetsEx StringCbGetsExW
+#else
+#define StringCbGetsEx StringCbGetsExA
+#endif // !UNICODE
+
+STRSAFE_INLINE_API StringCbGetsExA(char* pszDest, size_t cbDest, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags)
+{
+ HRESULT hr;
+ size_t cchDest;
+ size_t cchRemaining = 0;
+
+ cchDest = cbDest / sizeof(char);
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringGetsExWorkerA(pszDest, cchDest, cbDest, ppszDestEnd, &cchRemaining, dwFlags);
+ }
+
+ if (SUCCEEDED(hr) ||
+ (hr == STRSAFE_E_INSUFFICIENT_BUFFER) ||
+ (hr == STRSAFE_E_END_OF_FILE))
+ {
+ if (pcbRemaining)
+ {
+ // safe to multiply cchRemaining * sizeof(char) since cchRemaining < STRSAFE_MAX_CCH and sizeof(char) is 1
+ *pcbRemaining = (cchRemaining * sizeof(char)) + (cbDest % sizeof(char));
+ }
+ }
+
+ return hr;
+}
+
+#if defined(FEATURE_PAL) || !defined(PLATFORM_UNIX)
+STRSAFE_INLINE_API StringCbGetsExW(WCHAR* pszDest, size_t cbDest, WCHAR** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags)
+{
+ HRESULT hr;
+ size_t cchDest;
+ size_t cchRemaining = 0;
+
+ cchDest = cbDest / sizeof(WCHAR);
+
+ if (cchDest > STRSAFE_MAX_CCH)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringGetsExWorkerW(pszDest, cchDest, cbDest, ppszDestEnd, &cchRemaining, dwFlags);
+ }
+
+ if (SUCCEEDED(hr) ||
+ (hr == STRSAFE_E_INSUFFICIENT_BUFFER) ||
+ (hr == STRSAFE_E_END_OF_FILE))
+ {
+ if (pcbRemaining)
+ {
+ // safe to multiply cchRemaining * sizeof(WCHAR) since cchRemaining < STRSAFE_MAX_CCH and sizeof(WCHAR) is 2
+ *pcbRemaining = (cchRemaining * sizeof(WCHAR)) + (cbDest % sizeof(WCHAR));
+ }
+ }
+
+ return hr;
+}
+#endif // FEATURE_PAL || !PLATFORM_UNIX
+#endif // !STRSAFE_NO_CB_FUNCTIONS
+#endif // !STRSAFE_LIB_IMPL
+#endif // !FEATURE_PAL
+
+#ifndef STRSAFE_NO_CCH_FUNCTIONS
+/*++
+
+STDAPI StringCchLength(LPCTSTR psz,
+ size_t cchMax,
+ size_t* pcch);
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'strlen'.
+ It is used to make sure a string is not larger than a given length, and
+ it optionally returns the current length in characters not including
+ the null terminator.
+
+ This function returns a hresult, and not a pointer. It returns a S_OK
+ if the string is non-null and the length including the null terminator is
+ less than or equal to cchMax characters.
+
+Arguments:
+
+ psz - string to check the length of
+
+ cchMax - maximum number of characters including the null terminator
+ that psz is allowed to contain
+
+ pcch - if the function succeeds and pcch is non-null, the current length
+ in characters of psz excluding the null terminator will be returned.
+ This out parameter is equivalent to the return value of strlen(psz)
+
+Notes:
+ psz can be null but the function will fail
+
+ cchMax should be greater than zero or the function will fail
+
+Return Value:
+
+ S_OK - psz is non-null and the length including the null terminator is
+ less than or equal to cchMax characters
+
+ failure - you can use the macro HRESULT_CODE() to get a win32 error
+ code for all hresult falure cases
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function.
+
+--*/
+
+STRSAFEAPI StringCchLengthA(const char* psz, size_t cchMax, size_t* pcch);
+STRSAFEAPI StringCchLengthW(const WCHAR* psz, size_t cchMax, size_t* pcch);
+#ifdef UNICODE
+#define StringCchLength StringCchLengthW
+#else
+#define StringCchLength StringCchLengthA
+#endif // !UNICODE
+
+#ifdef STRSAFE_INLINE
+STRSAFEAPI StringCchLengthA(const char* psz, size_t cchMax, size_t* pcch)
+{
+ HRESULT hr;
+
+ if ((psz == NULL) || (cchMax > STRSAFE_MAX_CCH))
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringLengthWorkerA(psz, cchMax, pcch);
+ }
+
+ return hr;
+}
+
+#if defined(FEATURE_PAL) || !defined(PLATFORM_UNIX)
+STRSAFEAPI StringCchLengthW(const WCHAR* psz, size_t cchMax, size_t* pcch)
+{
+ HRESULT hr;
+
+ if ((psz == NULL) || (cchMax > STRSAFE_MAX_CCH))
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringLengthWorkerW(psz, cchMax, pcch);
+ }
+
+ return hr;
+}
+#endif // FEATURE_PAL || !PLATFORM_UNIX
+#endif // STRSAFE_INLINE
+#endif // !STRSAFE_NO_CCH_FUNCTIONS
+
+
+#ifndef STRSAFE_NO_CB_FUNCTIONS
+/*++
+
+STDAPI StringCbLength(LPCTSTR psz,
+ size_t cbMax,
+ size_t* pcb);
+
+Routine Description:
+
+ This routine is a safer version of the C built-in function 'strlen'.
+ It is used to make sure a string is not larger than a given length, and
+ it optionally returns the current length in bytes not including
+ the null terminator.
+
+ This function returns a hresult, and not a pointer. It returns a S_OK
+ if the string is non-null and the length including the null terminator is
+ less than or equal to cbMax bytes.
+
+Arguments:
+
+ psz - string to check the length of
+
+ cbMax - maximum number of bytes including the null terminator
+ that psz is allowed to contain
+
+ pcb - if the function succeeds and pcb is non-null, the current length
+ in bytes of psz excluding the null terminator will be returned.
+ This out parameter is equivalent to the return value of strlen(psz) * sizeof(TCHAR)
+
+Notes:
+ psz can be null but the function will fail
+
+ cbMax should be greater than or equal to sizeof(TCHAR) or the function will fail
+
+Return Value:
+
+ S_OK - psz is non-null and the length including the null terminator is
+ less than or equal to cbMax bytes
+
+ failure - you can use the macro HRESULT_CODE() to get a win32 error
+ code for all hresult falure cases
+
+ It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
+ return value of this function.
+
+--*/
+
+STRSAFEAPI StringCbLengthA(const char* psz, size_t cchMax, size_t* pcch);
+STRSAFEAPI StringCbLengthW(const WCHAR* psz, size_t cchMax, size_t* pcch);
+#ifdef UNICODE
+#define StringCbLength StringCbLengthW
+#else
+#define StringCbLength StringCbLengthA
+#endif // !UNICODE
+
+#ifdef STRSAFE_INLINE
+STRSAFEAPI StringCbLengthA(const char* psz, size_t cbMax, size_t* pcb)
+{
+ HRESULT hr;
+ size_t cchMax;
+ size_t cch = 0;
+
+ cchMax = cbMax / sizeof(char);
+
+ if ((psz == NULL) || (cchMax > STRSAFE_MAX_CCH))
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringLengthWorkerA(psz, cchMax, &cch);
+ }
+
+ if (SUCCEEDED(hr) && pcb)
+ {
+ // safe to multiply cch * sizeof(char) since cch < STRSAFE_MAX_CCH and sizeof(char) is 1
+ *pcb = cch * sizeof(char);
+ }
+
+ return hr;
+}
+
+#if defined(FEATURE_PAL) || !defined(PLATFORM_UNIX)
+STRSAFEAPI StringCbLengthW(const WCHAR* psz, size_t cbMax, size_t* pcb)
+{
+ HRESULT hr;
+ size_t cchMax;
+ size_t cch = 0;
+
+ cchMax = cbMax / sizeof(WCHAR);
+
+ if ((psz == NULL) || (cchMax > STRSAFE_MAX_CCH))
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = StringLengthWorkerW(psz, cchMax, &cch);
+ }
+
+ if (SUCCEEDED(hr) && pcb)
+ {
+ // safe to multiply cch * sizeof(WCHAR) since cch < STRSAFE_MAX_CCH and sizeof(WCHAR) is 2
+ *pcb = cch * sizeof(WCHAR);
+ }
+
+ return hr;
+}
+#endif // FEATURE_PAL || !PLATFORM_UNIX
+#endif // STRSAFE_INLINE
+#endif // !STRSAFE_NO_CB_FUNCTIONS
+
+
+// these are the worker functions that actually do the work
+#ifdef STRSAFE_INLINE
+STRSAFEAPI StringCopyWorkerA(char* pszDest, size_t cchDest, const char* pszSrc)
+{
+ HRESULT hr = S_OK;
+
+ if (cchDest == 0)
+ {
+ // can not null terminate a zero-byte dest buffer
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ while (cchDest && (*pszSrc != '\0'))
+ {
+ *pszDest++ = *pszSrc++;
+ cchDest--;
+ }
+
+ if (cchDest == 0)
+ {
+ // we are going to truncate pszDest
+ pszDest--;
+ hr = STRSAFE_E_INSUFFICIENT_BUFFER;
+ }
+
+ *pszDest= '\0';
+ }
+
+ return hr;
+}
+
+#if defined(FEATURE_PAL) || !defined(PLATFORM_UNIX)
+STRSAFEAPI StringCopyWorkerW(WCHAR* pszDest, size_t cchDest, const WCHAR* pszSrc)
+{
+ HRESULT hr = S_OK;
+
+ if (cchDest == 0)
+ {
+ // can not null terminate a zero-byte dest buffer
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ while (cchDest && (*pszSrc != L'\0'))
+ {
+ *pszDest++ = *pszSrc++;
+ cchDest--;
+ }
+
+ if (cchDest == 0)
+ {
+ // we are going to truncate pszDest
+ pszDest--;
+ hr = STRSAFE_E_INSUFFICIENT_BUFFER;
+ }
+
+ *pszDest= L'\0';
+ }
+
+ return hr;
+}
+#endif // FEATURE_PAL || !PLATFORM_UNIX
+
+STRSAFEAPI StringCopyExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, const char* pszSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
+{
+ HRESULT hr = S_OK;
+ char* pszDestEnd = pszDest;
+ size_t cchRemaining = 0;
+
+ // ASSERT(cbDest == (cchDest * sizeof(char)) ||
+ // cbDest == (cchDest * sizeof(char)) + (cbDest % sizeof(char)));
+
+ // only accept valid flags
+ if (dwFlags & (~STRSAFE_VALID_FLAGS))
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ if (dwFlags & STRSAFE_IGNORE_NULLS)
+ {
+ if (pszDest == NULL)
+ {
+ if ((cchDest != 0) || (cbDest != 0))
+ {
+ // NULL pszDest and non-zero cchDest/cbDest is invalid
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ }
+
+ if (pszSrc == NULL)
+ {
+ pszSrc = "";
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ if (cchDest == 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = 0;
+
+ // only fail if there was actually src data to copy
+ if (*pszSrc != '\0')
+ {
+ if (pszDest == NULL)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = STRSAFE_E_INSUFFICIENT_BUFFER;
+ }
+ }
+ }
+ else
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+
+ while (cchRemaining && (*pszSrc != '\0'))
+ {
+ *pszDestEnd++= *pszSrc++;
+ cchRemaining--;
+ }
+
+ if (cchRemaining > 0)
+ {
+ if (dwFlags & STRSAFE_FILL_BEHIND_NULL)
+ {
+ memset(pszDestEnd + 1, STRSAFE_GET_FILL_PATTERN(dwFlags), ((cchRemaining - 1) * sizeof(char)) + (cbDest % sizeof(char)));
+ }
+ }
+ else
+ {
+ // we are going to truncate pszDest
+ pszDestEnd--;
+ cchRemaining++;
+
+ hr = STRSAFE_E_INSUFFICIENT_BUFFER;
+ }
+
+ *pszDestEnd = '\0';
+ }
+ }
+ }
+
+ if (FAILED(hr))
+ {
+ if (pszDest)
+ {
+ if (dwFlags & STRSAFE_FILL_ON_FAILURE)
+ {
+ memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest);
+
+ if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+ }
+ else if (cchDest > 0)
+ {
+ pszDestEnd = pszDest + cchDest - 1;
+ cchRemaining = 1;
+
+ // null terminate the end of the string
+ *pszDestEnd = '\0';
+ }
+ }
+
+ if (dwFlags & (STRSAFE_NULL_ON_FAILURE | STRSAFE_NO_TRUNCATION))
+ {
+ if (cchDest > 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+
+ // null terminate the beginning of the string
+ *pszDestEnd = '\0';
+ }
+ }
+ }
+ }
+
+ if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
+ {
+ if (ppszDestEnd)
+ {
+ *ppszDestEnd = pszDestEnd;
+ }
+
+ if (pcchRemaining)
+ {
+ *pcchRemaining = cchRemaining;
+ }
+ }
+
+ return hr;
+}
+
+#if defined(FEATURE_PAL) || !defined(PLATFORM_UNIX)
+STRSAFEAPI StringCopyExWorkerW(WCHAR* pszDest, size_t cchDest, size_t cbDest, const WCHAR* pszSrc, WCHAR** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
+{
+ HRESULT hr = S_OK;
+ WCHAR* pszDestEnd = pszDest;
+ size_t cchRemaining = 0;
+
+ // ASSERT(cbDest == (cchDest * sizeof(WCHAR)) ||
+ // cbDest == (cchDest * sizeof(WCHAR)) + (cbDest % sizeof(WCHAR)));
+
+ // only accept valid flags
+ if (dwFlags & (~STRSAFE_VALID_FLAGS))
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ if (dwFlags & STRSAFE_IGNORE_NULLS)
+ {
+ if (pszDest == NULL)
+ {
+ if ((cchDest != 0) || (cbDest != 0))
+ {
+ // NULL pszDest and non-zero cchDest/cbDest is invalid
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ }
+
+ if (pszSrc == NULL)
+ {
+ pszSrc = u"";
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ if (cchDest == 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = 0;
+
+ // only fail if there was actually src data to copy
+ if (*pszSrc != u'\0')
+ {
+ if (pszDest == NULL)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = STRSAFE_E_INSUFFICIENT_BUFFER;
+ }
+ }
+ }
+ else
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+
+ while (cchRemaining && (*pszSrc != u'\0'))
+ {
+ *pszDestEnd++= *pszSrc++;
+ cchRemaining--;
+ }
+
+ if (cchRemaining > 0)
+ {
+ if (dwFlags & STRSAFE_FILL_BEHIND_NULL)
+ {
+ memset(pszDestEnd + 1, STRSAFE_GET_FILL_PATTERN(dwFlags), ((cchRemaining - 1) * sizeof(WCHAR)) + (cbDest % sizeof(WCHAR)));
+ }
+ }
+ else
+ {
+ // we are going to truncate pszDest
+ pszDestEnd--;
+ cchRemaining++;
+
+ hr = STRSAFE_E_INSUFFICIENT_BUFFER;
+ }
+
+ *pszDestEnd = u'\0';
+ }
+ }
+ }
+
+ if (FAILED(hr))
+ {
+ if (pszDest)
+ {
+ if (dwFlags & STRSAFE_FILL_ON_FAILURE)
+ {
+ memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest);
+
+ if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+ }
+ else if (cchDest > 0)
+ {
+ pszDestEnd = pszDest + cchDest - 1;
+ cchRemaining = 1;
+
+ // null terminate the end of the string
+ *pszDestEnd = L'\0';
+ }
+ }
+
+ if (dwFlags & (STRSAFE_NULL_ON_FAILURE | STRSAFE_NO_TRUNCATION))
+ {
+ if (cchDest > 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+
+ // null terminate the beginning of the string
+ *pszDestEnd = L'\0';
+ }
+ }
+ }
+ }
+
+ if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
+ {
+ if (ppszDestEnd)
+ {
+ *ppszDestEnd = pszDestEnd;
+ }
+
+ if (pcchRemaining)
+ {
+ *pcchRemaining = cchRemaining;
+ }
+ }
+
+ return hr;
+}
+#endif // FEATURE_PAL || !PLATFORM_UNIX
+
+STRSAFEAPI StringCopyNWorkerA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchSrc)
+{
+ HRESULT hr = S_OK;
+
+ if (cchDest == 0)
+ {
+ // can not null terminate a zero-byte dest buffer
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ while (cchDest && cchSrc && (*pszSrc != '\0'))
+ {
+ *pszDest++= *pszSrc++;
+ cchDest--;
+ cchSrc--;
+ }
+
+ if (cchDest == 0)
+ {
+ // we are going to truncate pszDest
+ pszDest--;
+ hr = STRSAFE_E_INSUFFICIENT_BUFFER;
+ }
+
+ *pszDest= '\0';
+ }
+
+ return hr;
+}
+
+#if defined(FEATURE_PAL) || !defined(PLATFORM_UNIX)
+STRSAFEAPI StringCopyNWorkerW(WCHAR* pszDest, size_t cchDest, const WCHAR* pszSrc, size_t cchSrc)
+{
+ HRESULT hr = S_OK;
+
+ if (cchDest == 0)
+ {
+ // can not null terminate a zero-byte dest buffer
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ while (cchDest && cchSrc && (*pszSrc != L'\0'))
+ {
+ *pszDest++= *pszSrc++;
+ cchDest--;
+ cchSrc--;
+ }
+
+ if (cchDest == 0)
+ {
+ // we are going to truncate pszDest
+ pszDest--;
+ hr = STRSAFE_E_INSUFFICIENT_BUFFER;
+ }
+
+ *pszDest= L'\0';
+ }
+
+ return hr;
+}
+#endif // FEATURE_PAL || !PLATFORM_UNIX
+
+STRSAFEAPI StringCopyNExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, const char* pszSrc, size_t cchSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
+{
+ HRESULT hr = S_OK;
+ char* pszDestEnd = pszDest;
+ size_t cchRemaining = 0;
+
+ // ASSERT(cbDest == (cchDest * sizeof(char)) ||
+ // cbDest == (cchDest * sizeof(char)) + (cbDest % sizeof(char)));
+
+ // only accept valid flags
+ if (dwFlags & (~STRSAFE_VALID_FLAGS))
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ if (dwFlags & STRSAFE_IGNORE_NULLS)
+ {
+ if (pszDest == NULL)
+ {
+ if ((cchDest != 0) || (cbDest != 0))
+ {
+ // NULL pszDest and non-zero cchDest/cbDest is invalid
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ }
+
+ if (pszSrc == NULL)
+ {
+ pszSrc = "";
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ if (cchDest == 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = 0;
+
+ // only fail if there was actually src data to copy
+ if (*pszSrc != '\0')
+ {
+ if (pszDest == NULL)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = STRSAFE_E_INSUFFICIENT_BUFFER;
+ }
+ }
+ }
+ else
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+
+ while (cchRemaining && cchSrc && (*pszSrc != '\0'))
+ {
+ *pszDestEnd++= *pszSrc++;
+ cchRemaining--;
+ cchSrc--;
+ }
+
+ if (cchRemaining > 0)
+ {
+ if (dwFlags & STRSAFE_FILL_BEHIND_NULL)
+ {
+ memset(pszDestEnd + 1, STRSAFE_GET_FILL_PATTERN(dwFlags), ((cchRemaining - 1) * sizeof(char)) + (cbDest % sizeof(char)));
+ }
+ }
+ else
+ {
+ // we are going to truncate pszDest
+ pszDestEnd--;
+ cchRemaining++;
+
+ hr = STRSAFE_E_INSUFFICIENT_BUFFER;
+ }
+
+ *pszDestEnd = '\0';
+ }
+ }
+ }
+
+ if (FAILED(hr))
+ {
+ if (pszDest)
+ {
+ if (dwFlags & STRSAFE_FILL_ON_FAILURE)
+ {
+ memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest);
+
+ if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+ }
+ else if (cchDest > 0)
+ {
+ pszDestEnd = pszDest + cchDest - 1;
+ cchRemaining = 1;
+
+ // null terminate the end of the string
+ *pszDestEnd = '\0';
+ }
+ }
+
+ if (dwFlags & (STRSAFE_NULL_ON_FAILURE | STRSAFE_NO_TRUNCATION))
+ {
+ if (cchDest > 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+
+ // null terminate the beginning of the string
+ *pszDestEnd = '\0';
+ }
+ }
+ }
+ }
+
+ if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
+ {
+ if (ppszDestEnd)
+ {
+ *ppszDestEnd = pszDestEnd;
+ }
+
+ if (pcchRemaining)
+ {
+ *pcchRemaining = cchRemaining;
+ }
+ }
+
+ return hr;
+}
+
+#if defined(FEATURE_PAL) || !defined(PLATFORM_UNIX)
+STRSAFEAPI StringCopyNExWorkerW(WCHAR* pszDest, size_t cchDest, size_t cbDest, const WCHAR* pszSrc, size_t cchSrc, WCHAR** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
+{
+ HRESULT hr = S_OK;
+ WCHAR* pszDestEnd = pszDest;
+ size_t cchRemaining = 0;
+
+ // ASSERT(cbDest == (cchDest * sizeof(WCHAR)) ||
+ // cbDest == (cchDest * sizeof(WCHAR)) + (cbDest % sizeof(WCHAR)));
+
+ // only accept valid flags
+ if (dwFlags & (~STRSAFE_VALID_FLAGS))
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ if (dwFlags & STRSAFE_IGNORE_NULLS)
+ {
+ if (pszDest == NULL)
+ {
+ if ((cchDest != 0) || (cbDest != 0))
+ {
+ // NULL pszDest and non-zero cchDest/cbDest is invalid
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ }
+
+ if (pszSrc == NULL)
+ {
+ pszSrc = u"";
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ if (cchDest == 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = 0;
+
+ // only fail if there was actually src data to copy
+ if (*pszSrc != L'\0')
+ {
+ if (pszDest == NULL)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = STRSAFE_E_INSUFFICIENT_BUFFER;
+ }
+ }
+ }
+ else
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+
+ while (cchRemaining && cchSrc && (*pszSrc != L'\0'))
+ {
+ *pszDestEnd++= *pszSrc++;
+ cchRemaining--;
+ cchSrc--;
+ }
+
+ if (cchRemaining > 0)
+ {
+ if (dwFlags & STRSAFE_FILL_BEHIND_NULL)
+ {
+ memset(pszDestEnd + 1, STRSAFE_GET_FILL_PATTERN(dwFlags), ((cchRemaining - 1) * sizeof(WCHAR)) + (cbDest % sizeof(WCHAR)));
+ }
+ }
+ else
+ {
+ // we are going to truncate pszDest
+ pszDestEnd--;
+ cchRemaining++;
+
+ hr = STRSAFE_E_INSUFFICIENT_BUFFER;
+ }
+
+ *pszDestEnd = L'\0';
+ }
+ }
+ }
+
+ if (FAILED(hr))
+ {
+ if (pszDest)
+ {
+ if (dwFlags & STRSAFE_FILL_ON_FAILURE)
+ {
+ memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest);
+
+ if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+ }
+ else if (cchDest > 0)
+ {
+ pszDestEnd = pszDest + cchDest - 1;
+ cchRemaining = 1;
+
+ // null terminate the end of the string
+ *pszDestEnd = L'\0';
+ }
+ }
+
+ if (dwFlags & (STRSAFE_NULL_ON_FAILURE | STRSAFE_NO_TRUNCATION))
+ {
+ if (cchDest > 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+
+ // null terminate the beginning of the string
+ *pszDestEnd = L'\0';
+ }
+ }
+ }
+ }
+
+ if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
+ {
+ if (ppszDestEnd)
+ {
+ *ppszDestEnd = pszDestEnd;
+ }
+
+ if (pcchRemaining)
+ {
+ *pcchRemaining = cchRemaining;
+ }
+ }
+
+ return hr;
+}
+#endif // FEATURE_PAL || !PLATFORM_UNIX
+
+STRSAFEAPI StringCatWorkerA(char* pszDest, size_t cchDest, const char* pszSrc)
+{
+ HRESULT hr;
+ size_t cchDestCurrent;
+
+ hr = StringLengthWorkerA(pszDest, cchDest, &cchDestCurrent);
+
+ if (SUCCEEDED(hr))
+ {
+ hr = StringCopyWorkerA(pszDest + cchDestCurrent,
+ cchDest - cchDestCurrent,
+ pszSrc);
+ }
+
+ return hr;
+}
+
+#if defined(FEATURE_PAL) || !defined(PLATFORM_UNIX)
+STRSAFEAPI StringCatWorkerW(WCHAR* pszDest, size_t cchDest, const WCHAR* pszSrc)
+{
+ HRESULT hr;
+ size_t cchDestCurrent;
+
+ hr = StringLengthWorkerW(pszDest, cchDest, &cchDestCurrent);
+
+ if (SUCCEEDED(hr))
+ {
+ hr = StringCopyWorkerW(pszDest + cchDestCurrent,
+ cchDest - cchDestCurrent,
+ pszSrc);
+ }
+
+ return hr;
+}
+#endif // FEATURE_PAL || !PLATFORM_UNIX
+
+STRSAFEAPI StringCatExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, const char* pszSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
+{
+ HRESULT hr = S_OK;
+ char* pszDestEnd = pszDest;
+ size_t cchRemaining = 0;
+
+ // ASSERT(cbDest == (cchDest * sizeof(char)) ||
+ // cbDest == (cchDest * sizeof(char)) + (cbDest % sizeof(char)));
+
+ // only accept valid flags
+ if (dwFlags & (~STRSAFE_VALID_FLAGS))
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ size_t cchDestCurrent;
+
+ if (dwFlags & STRSAFE_IGNORE_NULLS)
+ {
+ if (pszDest == NULL)
+ {
+ if ((cchDest == 0) && (cbDest == 0))
+ {
+ cchDestCurrent = 0;
+ }
+ else
+ {
+ // NULL pszDest and non-zero cchDest/cbDest is invalid
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ }
+ else
+ {
+ hr = StringLengthWorkerA(pszDest, cchDest, &cchDestCurrent);
+
+ if (SUCCEEDED(hr))
+ {
+ pszDestEnd = pszDest + cchDestCurrent;
+ cchRemaining = cchDest - cchDestCurrent;
+ }
+ }
+
+ if (pszSrc == NULL)
+ {
+ pszSrc = "";
+ }
+ }
+ else
+ {
+ hr = StringLengthWorkerA(pszDest, cchDest, &cchDestCurrent);
+
+ if (SUCCEEDED(hr))
+ {
+ pszDestEnd = pszDest + cchDestCurrent;
+ cchRemaining = cchDest - cchDestCurrent;
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ if (cchDest == 0)
+ {
+ // only fail if there was actually src data to append
+ if (*pszSrc != '\0')
+ {
+ if (pszDest == NULL)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = STRSAFE_E_INSUFFICIENT_BUFFER;
+ }
+ }
+ }
+ else
+ {
+ // we handle the STRSAFE_FILL_ON_FAILURE and STRSAFE_NULL_ON_FAILURE cases below, so do not pass
+ // those flags through
+ hr = StringCopyExWorkerA(pszDestEnd,
+ cchRemaining,
+ (cchRemaining * sizeof(char)) + (cbDest % sizeof(char)),
+ pszSrc,
+ &pszDestEnd,
+ &cchRemaining,
+ dwFlags & (~(STRSAFE_FILL_ON_FAILURE | STRSAFE_NULL_ON_FAILURE)));
+ }
+ }
+ }
+
+ if (FAILED(hr))
+ {
+ if (pszDest)
+ {
+ // STRSAFE_NO_TRUNCATION is taken care of by StringCopyExWorkerA()
+
+ if (dwFlags & STRSAFE_FILL_ON_FAILURE)
+ {
+ memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest);
+
+ if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+ }
+ else
+ if (cchDest > 0)
+ {
+ pszDestEnd = pszDest + cchDest - 1;
+ cchRemaining = 1;
+
+ // null terminate the end of the string
+ *pszDestEnd = '\0';
+ }
+ }
+
+ if (dwFlags & STRSAFE_NULL_ON_FAILURE)
+ {
+ if (cchDest > 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+
+ // null terminate the beginning of the string
+ *pszDestEnd = '\0';
+ }
+ }
+ }
+ }
+
+ if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
+ {
+ if (ppszDestEnd)
+ {
+ *ppszDestEnd = pszDestEnd;
+ }
+
+ if (pcchRemaining)
+ {
+ *pcchRemaining = cchRemaining;
+ }
+ }
+
+ return hr;
+}
+
+#if defined(FEATURE_PAL) || !defined(PLATFORM_UNIX)
+STRSAFEAPI StringCatExWorkerW(WCHAR* pszDest, size_t cchDest, size_t cbDest, const WCHAR* pszSrc, WCHAR** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
+{
+ HRESULT hr = S_OK;
+ WCHAR* pszDestEnd = pszDest;
+ size_t cchRemaining = 0;
+
+ // ASSERT(cbDest == (cchDest * sizeof(WCHAR)) ||
+ // cbDest == (cchDest * sizeof(WCHAR)) + (cbDest % sizeof(WCHAR)));
+
+ // only accept valid flags
+ if (dwFlags & (~STRSAFE_VALID_FLAGS))
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ size_t cchDestCurrent;
+
+ if (dwFlags & STRSAFE_IGNORE_NULLS)
+ {
+ if (pszDest == NULL)
+ {
+ if ((cchDest == 0) && (cbDest == 0))
+ {
+ cchDestCurrent = 0;
+ }
+ else
+ {
+ // NULL pszDest and non-zero cchDest/cbDest is invalid
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ }
+ else
+ {
+ hr = StringLengthWorkerW(pszDest, cchDest, &cchDestCurrent);
+
+ if (SUCCEEDED(hr))
+ {
+ pszDestEnd = pszDest + cchDestCurrent;
+ cchRemaining = cchDest - cchDestCurrent;
+ }
+ }
+
+ if (pszSrc == NULL)
+ {
+ pszSrc = u"";
+ }
+ }
+ else
+ {
+ hr = StringLengthWorkerW(pszDest, cchDest, &cchDestCurrent);
+
+ if (SUCCEEDED(hr))
+ {
+ pszDestEnd = pszDest + cchDestCurrent;
+ cchRemaining = cchDest - cchDestCurrent;
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ if (cchDest == 0)
+ {
+ // only fail if there was actually src data to append
+ if (*pszSrc != L'\0')
+ {
+ if (pszDest == NULL)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = STRSAFE_E_INSUFFICIENT_BUFFER;
+ }
+ }
+ }
+ else
+ {
+ // we handle the STRSAFE_FILL_ON_FAILURE and STRSAFE_NULL_ON_FAILURE cases below, so do not pass
+ // those flags through
+ hr = StringCopyExWorkerW(pszDestEnd,
+ cchRemaining,
+ (cchRemaining * sizeof(WCHAR)) + (cbDest % sizeof(WCHAR)),
+ pszSrc,
+ &pszDestEnd,
+ &cchRemaining,
+ dwFlags & (~(STRSAFE_FILL_ON_FAILURE | STRSAFE_NULL_ON_FAILURE)));
+ }
+ }
+ }
+
+ if (FAILED(hr))
+ {
+ if (pszDest)
+ {
+ // STRSAFE_NO_TRUNCATION is taken care of by StringCopyExWorkerW()
+
+ if (dwFlags & STRSAFE_FILL_ON_FAILURE)
+ {
+ memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest);
+
+ if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+ }
+ else if (cchDest > 0)
+ {
+ pszDestEnd = pszDest + cchDest - 1;
+ cchRemaining = 1;
+
+ // null terminate the end of the string
+ *pszDestEnd = L'\0';
+ }
+ }
+
+ if (dwFlags & STRSAFE_NULL_ON_FAILURE)
+ {
+ if (cchDest > 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+
+ // null terminate the beginning of the string
+ *pszDestEnd = L'\0';
+ }
+ }
+ }
+ }
+
+ if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
+ {
+ if (ppszDestEnd)
+ {
+ *ppszDestEnd = pszDestEnd;
+ }
+
+ if (pcchRemaining)
+ {
+ *pcchRemaining = cchRemaining;
+ }
+ }
+
+ return hr;
+}
+#endif // FEATURE_PAL || !PLATFORM_UNIX
+
+STRSAFEAPI StringCatNWorkerA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchMaxAppend)
+{
+ HRESULT hr;
+ size_t cchDestCurrent;
+
+ hr = StringLengthWorkerA(pszDest, cchDest, &cchDestCurrent);
+
+ if (SUCCEEDED(hr))
+ {
+ hr = StringCopyNWorkerA(pszDest + cchDestCurrent,
+ cchDest - cchDestCurrent,
+ pszSrc,
+ cchMaxAppend);
+ }
+
+ return hr;
+}
+
+#if defined(FEATURE_PAL) || !defined(PLATFORM_UNIX)
+STRSAFEAPI StringCatNWorkerW(WCHAR* pszDest, size_t cchDest, const WCHAR* pszSrc, size_t cchMaxAppend)
+{
+ HRESULT hr;
+ size_t cchDestCurrent;
+
+ hr = StringLengthWorkerW(pszDest, cchDest, &cchDestCurrent);
+
+ if (SUCCEEDED(hr))
+ {
+ hr = StringCopyNWorkerW(pszDest + cchDestCurrent,
+ cchDest - cchDestCurrent,
+ pszSrc,
+ cchMaxAppend);
+ }
+
+ return hr;
+}
+#endif // FEATURE_PAL || !PLATFORM_UNIX
+
+STRSAFEAPI StringCatNExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, const char* pszSrc, size_t cchMaxAppend, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
+{
+ HRESULT hr = S_OK;
+ char* pszDestEnd = pszDest;
+ size_t cchRemaining = 0;
+ size_t cchDestCurrent = 0;
+
+ // ASSERT(cbDest == (cchDest * sizeof(char)) ||
+ // cbDest == (cchDest * sizeof(char)) + (cbDest % sizeof(char)));
+
+ // only accept valid flags
+ if (dwFlags & (~STRSAFE_VALID_FLAGS))
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ if (dwFlags & STRSAFE_IGNORE_NULLS)
+ {
+ if (pszDest == NULL)
+ {
+ if ((cchDest == 0) && (cbDest == 0))
+ {
+ cchDestCurrent = 0;
+ }
+ else
+ {
+ // NULL pszDest and non-zero cchDest/cbDest is invalid
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ }
+ else
+ {
+ hr = StringLengthWorkerA(pszDest, cchDest, &cchDestCurrent);
+
+ if (SUCCEEDED(hr))
+ {
+ pszDestEnd = pszDest + cchDestCurrent;
+ cchRemaining = cchDest - cchDestCurrent;
+ }
+ }
+
+ if (pszSrc == NULL)
+ {
+ pszSrc = "";
+ }
+ }
+ else
+ {
+ hr = StringLengthWorkerA(pszDest, cchDest, &cchDestCurrent);
+
+ if (SUCCEEDED(hr))
+ {
+ pszDestEnd = pszDest + cchDestCurrent;
+ cchRemaining = cchDest - cchDestCurrent;
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ if (cchDest == 0)
+ {
+ // only fail if there was actually src data to append
+ if (*pszSrc != '\0')
+ {
+ if (pszDest == NULL)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = STRSAFE_E_INSUFFICIENT_BUFFER;
+ }
+ }
+ }
+ else
+ {
+ // we handle the STRSAFE_FILL_ON_FAILURE and STRSAFE_NULL_ON_FAILURE cases below, so do not pass
+ // those flags through
+ hr = StringCopyNExWorkerA(pszDestEnd,
+ cchRemaining,
+ (cchRemaining * sizeof(char)) + (cbDest % sizeof(char)),
+ pszSrc,
+ cchMaxAppend,
+ &pszDestEnd,
+ &cchRemaining,
+ dwFlags & (~(STRSAFE_FILL_ON_FAILURE | STRSAFE_NULL_ON_FAILURE)));
+ }
+ }
+ }
+
+ if (FAILED(hr))
+ {
+ if (pszDest)
+ {
+ // STRSAFE_NO_TRUNCATION is taken care of by StringCopyNExWorkerA()
+
+ if (dwFlags & STRSAFE_FILL_ON_FAILURE)
+ {
+ memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest);
+
+ if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+ }
+ else if (cchDest > 0)
+ {
+ pszDestEnd = pszDest + cchDest - 1;
+ cchRemaining = 1;
+
+ // null terminate the end of the string
+ *pszDestEnd = '\0';
+ }
+ }
+
+ if (dwFlags & (STRSAFE_NULL_ON_FAILURE))
+ {
+ if (cchDest > 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+
+ // null terminate the beginning of the string
+ *pszDestEnd = '\0';
+ }
+ }
+ }
+ }
+
+ if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
+ {
+ if (ppszDestEnd)
+ {
+ *ppszDestEnd = pszDestEnd;
+ }
+
+ if (pcchRemaining)
+ {
+ *pcchRemaining = cchRemaining;
+ }
+ }
+
+ return hr;
+}
+
+#if defined(FEATURE_PAL) || !defined(PLATFORM_UNIX)
+STRSAFEAPI StringCatNExWorkerW(WCHAR* pszDest, size_t cchDest, size_t cbDest, const WCHAR* pszSrc, size_t cchMaxAppend, WCHAR** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
+{
+ HRESULT hr = S_OK;
+ WCHAR* pszDestEnd = pszDest;
+ size_t cchRemaining = 0;
+ size_t cchDestCurrent = 0;
+
+
+ // ASSERT(cbDest == (cchDest * sizeof(WCHAR)) ||
+ // cbDest == (cchDest * sizeof(WCHAR)) + (cbDest % sizeof(WCHAR)));
+
+ // only accept valid flags
+ if (dwFlags & (~STRSAFE_VALID_FLAGS))
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ if (dwFlags & STRSAFE_IGNORE_NULLS)
+ {
+ if (pszDest == NULL)
+ {
+ if ((cchDest == 0) && (cbDest == 0))
+ {
+ cchDestCurrent = 0;
+ }
+ else
+ {
+ // NULL pszDest and non-zero cchDest/cbDest is invalid
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ }
+ else
+ {
+ hr = StringLengthWorkerW(pszDest, cchDest, &cchDestCurrent);
+
+ if (SUCCEEDED(hr))
+ {
+ pszDestEnd = pszDest + cchDestCurrent;
+ cchRemaining = cchDest - cchDestCurrent;
+ }
+ }
+
+ if (pszSrc == NULL)
+ {
+ pszSrc = u"";
+ }
+ }
+ else
+ {
+ hr = StringLengthWorkerW(pszDest, cchDest, &cchDestCurrent);
+
+ if (SUCCEEDED(hr))
+ {
+ pszDestEnd = pszDest + cchDestCurrent;
+ cchRemaining = cchDest - cchDestCurrent;
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ if (cchDest == 0)
+ {
+ // only fail if there was actually src data to append
+ if (*pszSrc != L'\0')
+ {
+ if (pszDest == NULL)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = STRSAFE_E_INSUFFICIENT_BUFFER;
+ }
+ }
+ }
+ else
+ {
+ // we handle the STRSAFE_FILL_ON_FAILURE and STRSAFE_NULL_ON_FAILURE cases below, so do not pass
+ // those flags through
+ hr = StringCopyNExWorkerW(pszDestEnd,
+ cchRemaining,
+ (cchRemaining * sizeof(WCHAR)) + (cbDest % sizeof(WCHAR)),
+ pszSrc,
+ cchMaxAppend,
+ &pszDestEnd,
+ &cchRemaining,
+ dwFlags & (~(STRSAFE_FILL_ON_FAILURE | STRSAFE_NULL_ON_FAILURE)));
+ }
+ }
+ }
+
+ if (FAILED(hr))
+ {
+ if (pszDest)
+ {
+ // STRSAFE_NO_TRUNCATION is taken care of by StringCopyNExWorkerW()
+
+ if (dwFlags & STRSAFE_FILL_ON_FAILURE)
+ {
+ memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest);
+
+ if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+ }
+ else if (cchDest > 0)
+ {
+ pszDestEnd = pszDest + cchDest - 1;
+ cchRemaining = 1;
+
+ // null terminate the end of the string
+ *pszDestEnd = L'\0';
+ }
+ }
+
+ if (dwFlags & (STRSAFE_NULL_ON_FAILURE))
+ {
+ if (cchDest > 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+
+ // null terminate the beginning of the string
+ *pszDestEnd = L'\0';
+ }
+ }
+ }
+ }
+
+ if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
+ {
+ if (ppszDestEnd)
+ {
+ *ppszDestEnd = pszDestEnd;
+ }
+
+ if (pcchRemaining)
+ {
+ *pcchRemaining = cchRemaining;
+ }
+ }
+
+ return hr;
+}
+#endif // FEATURE_PAL || !PLATFORM_UNIX
+
+STRSAFEAPI StringVPrintfWorkerA(char* pszDest, size_t cchDest, const char* pszFormat, va_list argList)
+{
+ HRESULT hr = S_OK;
+
+ if (cchDest == 0)
+ {
+ // can not null terminate a zero-byte dest buffer
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ int iRet;
+ size_t cchMax;
+
+ // leave the last space for the null terminator
+ cchMax = cchDest - 1;
+
+ iRet = _vsnprintf(pszDest, cchMax, pszFormat, argList);
+ // ASSERT((iRet < 0) || (((size_t)iRet) <= cchMax));
+
+ if ((iRet < 0) || (((size_t)iRet) > cchMax))
+ {
+ // need to null terminate the string
+ pszDest += cchMax;
+ *pszDest = '\0';
+
+ // we have truncated pszDest
+ hr = STRSAFE_E_INSUFFICIENT_BUFFER;
+ }
+ else if (((size_t)iRet) == cchMax)
+ {
+ // need to null terminate the string
+ pszDest += cchMax;
+ *pszDest = '\0';
+ }
+ }
+
+ return hr;
+}
+
+#if defined(FEATURE_PAL) || !defined(PLATFORM_UNIX)
+STRSAFEAPI StringVPrintfWorkerW(WCHAR* pszDest, size_t cchDest, const WCHAR* pszFormat, va_list argList)
+{
+ HRESULT hr = S_OK;
+
+ if (cchDest == 0)
+ {
+ // can not null terminate a zero-byte dest buffer
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ int iRet;
+ size_t cchMax;
+
+ // leave the last space for the null terminator
+ cchMax = cchDest - 1;
+
+ iRet = _vsnwprintf(pszDest, cchMax, pszFormat, argList);
+ // ASSERT((iRet < 0) || (((size_t)iRet) <= cchMax));
+
+ if ((iRet < 0) || (((size_t)iRet) > cchMax))
+ {
+ // need to null terminate the string
+ pszDest += cchMax;
+ *pszDest = L'\0';
+
+ // we have truncated pszDest
+ hr = STRSAFE_E_INSUFFICIENT_BUFFER;
+ }
+ else if (((size_t)iRet) == cchMax)
+ {
+ // need to null terminate the string
+ pszDest += cchMax;
+ *pszDest = L'\0';
+ }
+ }
+
+ return hr;
+}
+#endif // FEATURE_PAL || !PLATFORM_UNIX
+
+STRSAFEAPI StringVPrintfExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const char* pszFormat, va_list argList)
+{
+ HRESULT hr = S_OK;
+ char* pszDestEnd = pszDest;
+ size_t cchRemaining = 0;
+
+ // ASSERT(cbDest == (cchDest * sizeof(char)) ||
+ // cbDest == (cchDest * sizeof(char)) + (cbDest % sizeof(char)));
+
+ // only accept valid flags
+ if (dwFlags & (~STRSAFE_VALID_FLAGS))
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ if (dwFlags & STRSAFE_IGNORE_NULLS)
+ {
+ if (pszDest == NULL)
+ {
+ if ((cchDest != 0) || (cbDest != 0))
+ {
+ // NULL pszDest and non-zero cchDest/cbDest is invalid
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ }
+
+ if (pszFormat == NULL)
+ {
+ pszFormat = "";
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ if (cchDest == 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = 0;
+
+ // only fail if there was actually a non-empty format string
+ if (*pszFormat != '\0')
+ {
+ if (pszDest == NULL)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = STRSAFE_E_INSUFFICIENT_BUFFER;
+ }
+ }
+ }
+ else
+ {
+ int iRet;
+ size_t cchMax;
+
+ // leave the last space for the null terminator
+ cchMax = cchDest - 1;
+
+ iRet = _vsnprintf(pszDest, cchMax, pszFormat, argList);
+ // ASSERT((iRet < 0) || (((size_t)iRet) <= cchMax));
+
+ if ((iRet < 0) || (((size_t)iRet) > cchMax))
+ {
+ // we have truncated pszDest
+ pszDestEnd = pszDest + cchMax;
+ cchRemaining = 1;
+
+ // need to null terminate the string
+ *pszDestEnd = '\0';
+
+ hr = STRSAFE_E_INSUFFICIENT_BUFFER;
+ }
+ else if (((size_t)iRet) == cchMax)
+ {
+ // string fit perfectly
+ pszDestEnd = pszDest + cchMax;
+ cchRemaining = 1;
+
+ // need to null terminate the string
+ *pszDestEnd = '\0';
+ }
+ else if (((size_t)iRet) < cchMax)
+ {
+ // there is extra room
+ pszDestEnd = pszDest + iRet;
+ cchRemaining = cchDest - iRet;
+
+ if (dwFlags & STRSAFE_FILL_BEHIND_NULL)
+ {
+ memset(pszDestEnd + 1, STRSAFE_GET_FILL_PATTERN(dwFlags), ((cchRemaining - 1) * sizeof(char)) + (cbDest % sizeof(char)));
+ }
+ }
+ }
+ }
+ }
+
+ if (FAILED(hr))
+ {
+ if (pszDest)
+ {
+ if (dwFlags & STRSAFE_FILL_ON_FAILURE)
+ {
+ memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest);
+
+ if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+ }
+ else if (cchDest > 0)
+ {
+ pszDestEnd = pszDest + cchDest - 1;
+ cchRemaining = 1;
+
+ // null terminate the end of the string
+ *pszDestEnd = '\0';
+ }
+ }
+
+ if (dwFlags & (STRSAFE_NULL_ON_FAILURE | STRSAFE_NO_TRUNCATION))
+ {
+ if (cchDest > 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+
+ // null terminate the beginning of the string
+ *pszDestEnd = '\0';
+ }
+ }
+ }
+ }
+
+ if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
+ {
+ if (ppszDestEnd)
+ {
+ *ppszDestEnd = pszDestEnd;
+ }
+
+ if (pcchRemaining)
+ {
+ *pcchRemaining = cchRemaining;
+ }
+ }
+
+ return hr;
+}
+
+#if defined(FEATURE_PAL) || !defined(PLATFORM_UNIX)
+STRSAFEAPI StringVPrintfExWorkerW(WCHAR* pszDest, size_t cchDest, size_t cbDest, WCHAR** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const WCHAR* pszFormat, va_list argList)
+{
+ HRESULT hr = S_OK;
+ WCHAR* pszDestEnd = pszDest;
+ size_t cchRemaining = 0;
+
+ // ASSERT(cbDest == (cchDest * sizeof(WCHAR)) ||
+ // cbDest == (cchDest * sizeof(WCHAR)) + (cbDest % sizeof(WCHAR)));
+
+ // only accept valid flags
+ if (dwFlags & (~STRSAFE_VALID_FLAGS))
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ if (dwFlags & STRSAFE_IGNORE_NULLS)
+ {
+ if (pszDest == NULL)
+ {
+ if ((cchDest != 0) || (cbDest != 0))
+ {
+ // NULL pszDest and non-zero cchDest/cbDest is invalid
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ }
+
+ if (pszFormat == NULL)
+ {
+ pszFormat = u"";
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ if (cchDest == 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = 0;
+
+ // only fail if there was actually a non-empty format string
+ if (*pszFormat != L'\0')
+ {
+ if (pszDest == NULL)
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ hr = STRSAFE_E_INSUFFICIENT_BUFFER;
+ }
+ }
+ }
+ else
+ {
+ int iRet;
+ size_t cchMax;
+
+ // leave the last space for the null terminator
+ cchMax = cchDest - 1;
+
+ iRet = _vsnwprintf(pszDest, cchMax, pszFormat, argList);
+ // ASSERT((iRet < 0) || (((size_t)iRet) <= cchMax));
+
+ if ((iRet < 0) || (((size_t)iRet) > cchMax))
+ {
+ // we have truncated pszDest
+ pszDestEnd = pszDest + cchMax;
+ cchRemaining = 1;
+
+ // need to null terminate the string
+ *pszDestEnd = L'\0';
+
+ hr = STRSAFE_E_INSUFFICIENT_BUFFER;
+ }
+ else if (((size_t)iRet) == cchMax)
+ {
+ // string fit perfectly
+ pszDestEnd = pszDest + cchMax;
+ cchRemaining = 1;
+
+ // need to null terminate the string
+ *pszDestEnd = L'\0';
+ }
+ else if (((size_t)iRet) < cchMax)
+ {
+ // there is extra room
+ pszDestEnd = pszDest + iRet;
+ cchRemaining = cchDest - iRet;
+
+ if (dwFlags & STRSAFE_FILL_BEHIND_NULL)
+ {
+ memset(pszDestEnd + 1, STRSAFE_GET_FILL_PATTERN(dwFlags), ((cchRemaining - 1) * sizeof(WCHAR)) + (cbDest % sizeof(WCHAR)));
+ }
+ }
+ }
+ }
+ }
+
+ if (FAILED(hr))
+ {
+ if (pszDest)
+ {
+ if (dwFlags & STRSAFE_FILL_ON_FAILURE)
+ {
+ memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest);
+
+ if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+ }
+ else if (cchDest > 0)
+ {
+ pszDestEnd = pszDest + cchDest - 1;
+ cchRemaining = 1;
+
+ // null terminate the end of the string
+ *pszDestEnd = L'\0';
+ }
+ }
+
+ if (dwFlags & (STRSAFE_NULL_ON_FAILURE | STRSAFE_NO_TRUNCATION))
+ {
+ if (cchDest > 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+
+ // null terminate the beginning of the string
+ *pszDestEnd = L'\0';
+ }
+ }
+ }
+ }
+
+ if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
+ {
+ if (ppszDestEnd)
+ {
+ *ppszDestEnd = pszDestEnd;
+ }
+
+ if (pcchRemaining)
+ {
+ *pcchRemaining = cchRemaining;
+ }
+ }
+
+ return hr;
+}
+#endif // FEATURE_PAL || !PLATFORM_UNIX
+
+STRSAFEAPI StringLengthWorkerA(const char* psz, size_t cchMax, size_t* pcch)
+{
+ HRESULT hr = S_OK;
+ size_t cchMaxPrev = cchMax;
+
+ while (cchMax && (*psz != '\0'))
+ {
+ psz++;
+ cchMax--;
+ }
+
+ if (cchMax == 0)
+ {
+ // the string is longer than cchMax
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+
+ if (SUCCEEDED(hr) && pcch)
+ {
+ *pcch = cchMaxPrev - cchMax;
+ }
+
+ return hr;
+}
+
+#if defined(FEATURE_PAL) || !defined(PLATFORM_UNIX)
+STRSAFEAPI StringLengthWorkerW(const WCHAR* psz, size_t cchMax, size_t* pcch)
+{
+ HRESULT hr = S_OK;
+ size_t cchMaxPrev = cchMax;
+
+ while (cchMax && (*psz != L'\0'))
+ {
+ psz++;
+ cchMax--;
+ }
+
+ if (cchMax == 0)
+ {
+ // the string is longer than cchMax
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+
+ if (SUCCEEDED(hr) && pcch)
+ {
+ *pcch = cchMaxPrev - cchMax;
+ }
+
+ return hr;
+}
+#endif // FEATURE_PAL || !PLATFORM_UNIX
+#endif // STRSAFE_INLINE
+
+#ifndef STRSAFE_LIB_IMPL
+#ifndef FEATURE_PAL
+STRSAFE_INLINE_API StringGetsExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
+{
+ HRESULT hr = S_OK;
+ char* pszDestEnd = pszDest;
+ size_t cchRemaining = 0;
+
+ // ASSERT(cbDest == (cchDest * sizeof(char)) ||
+ // cbDest == (cchDest * sizeof(char)) + (cbDest % sizeof(char)));
+
+ // only accept valid flags
+ if (dwFlags & (~STRSAFE_VALID_FLAGS))
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ if (dwFlags & STRSAFE_IGNORE_NULLS)
+ {
+ if (pszDest == NULL)
+ {
+ if ((cchDest != 0) || (cbDest != 0))
+ {
+ // NULL pszDest and non-zero cchDest/cbDest is invalid
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ if (cchDest <= 1)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+
+ if (cchDest == 1)
+ {
+ *pszDestEnd = '\0';
+ }
+
+ hr = STRSAFE_E_INSUFFICIENT_BUFFER;
+ }
+ else
+ {
+ char ch;
+
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+
+ while ((cchRemaining > 1) && (ch = (char)getc(stdin)) != '\n')
+ {
+ if (ch == EOF)
+ {
+ if (pszDestEnd == pszDest)
+ {
+ // we failed to read anything from stdin
+ hr = STRSAFE_E_END_OF_FILE;
+ }
+ break;
+ }
+
+ *pszDestEnd = ch;
+
+ pszDestEnd++;
+ cchRemaining--;
+ }
+
+ if (cchRemaining > 0)
+ {
+ // there is extra room
+ if (dwFlags & STRSAFE_FILL_BEHIND_NULL)
+ {
+ memset(pszDestEnd + 1, STRSAFE_GET_FILL_PATTERN(dwFlags), ((cchRemaining - 1) * sizeof(char)) + (cbDest % sizeof(char)));
+ }
+ }
+
+ *pszDestEnd = '\0';
+ }
+ }
+ }
+
+ if (FAILED(hr))
+ {
+ if (pszDest)
+ {
+ if (dwFlags & STRSAFE_FILL_ON_FAILURE)
+ {
+ memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest);
+
+ if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+ }
+ else if (cchDest > 0)
+ {
+ pszDestEnd = pszDest + cchDest - 1;
+ cchRemaining = 1;
+
+ // null terminate the end of the string
+ *pszDestEnd = '\0';
+ }
+ }
+
+ if (dwFlags & (STRSAFE_NULL_ON_FAILURE | STRSAFE_NO_TRUNCATION))
+ {
+ if (cchDest > 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+
+ // null terminate the beginning of the string
+ *pszDestEnd = '\0';
+ }
+ }
+ }
+ }
+
+ if (SUCCEEDED(hr) ||
+ (hr == STRSAFE_E_INSUFFICIENT_BUFFER) ||
+ (hr == STRSAFE_E_END_OF_FILE))
+ {
+ if (ppszDestEnd)
+ {
+ *ppszDestEnd = pszDestEnd;
+ }
+
+ if (pcchRemaining)
+ {
+ *pcchRemaining = cchRemaining;
+ }
+ }
+
+ return hr;
+}
+
+#if defined(FEATURE_PAL) || !defined(PLATFORM_UNIX)
+STRSAFE_INLINE_API StringGetsExWorkerW(WCHAR* pszDest, size_t cchDest, size_t cbDest, WCHAR** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
+{
+ HRESULT hr = S_OK;
+ WCHAR* pszDestEnd = pszDest;
+ size_t cchRemaining = 0;
+
+ // ASSERT(cbDest == (cchDest * sizeof(char)) ||
+ // cbDest == (cchDest * sizeof(char)) + (cbDest % sizeof(char)));
+
+ // only accept valid flags
+ if (dwFlags & (~STRSAFE_VALID_FLAGS))
+ {
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ else
+ {
+ if (dwFlags & STRSAFE_IGNORE_NULLS)
+ {
+ if (pszDest == NULL)
+ {
+ if ((cchDest != 0) || (cbDest != 0))
+ {
+ // NULL pszDest and non-zero cchDest/cbDest is invalid
+ hr = STRSAFE_E_INVALID_PARAMETER;
+ }
+ }
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ if (cchDest <= 1)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+
+ if (cchDest == 1)
+ {
+ *pszDestEnd = L'\0';
+ }
+
+ hr = STRSAFE_E_INSUFFICIENT_BUFFER;
+ }
+ else
+ {
+ WCHAR ch;
+
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+
+ while ((cchRemaining > 1) && (ch = (WCHAR)getwc(stdin)) != L'\n')
+ {
+ if (ch == EOF)
+ {
+ if (pszDestEnd == pszDest)
+ {
+ // we failed to read anything from stdin
+ hr = STRSAFE_E_END_OF_FILE;
+ }
+ break;
+ }
+
+ *pszDestEnd = ch;
+
+ pszDestEnd++;
+ cchRemaining--;
+ }
+
+ if (cchRemaining > 0)
+ {
+ // there is extra room
+ if (dwFlags & STRSAFE_FILL_BEHIND_NULL)
+ {
+ memset(pszDestEnd + 1, STRSAFE_GET_FILL_PATTERN(dwFlags), ((cchRemaining - 1) * sizeof(WCHAR)) + (cbDest % sizeof(WCHAR)));
+ }
+ }
+
+ *pszDestEnd = L'\0';
+ }
+ }
+ }
+
+ if (FAILED(hr))
+ {
+ if (pszDest)
+ {
+ if (dwFlags & STRSAFE_FILL_ON_FAILURE)
+ {
+ memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest);
+
+ if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+ }
+ else if (cchDest > 0)
+ {
+ pszDestEnd = pszDest + cchDest - 1;
+ cchRemaining = 1;
+
+ // null terminate the end of the string
+ *pszDestEnd = L'\0';
+ }
+ }
+
+ if (dwFlags & (STRSAFE_NULL_ON_FAILURE | STRSAFE_NO_TRUNCATION))
+ {
+ if (cchDest > 0)
+ {
+ pszDestEnd = pszDest;
+ cchRemaining = cchDest;
+
+ // null terminate the beginning of the string
+ *pszDestEnd = L'\0';
+ }
+ }
+ }
+ }
+
+ if (SUCCEEDED(hr) ||
+ (hr == STRSAFE_E_INSUFFICIENT_BUFFER) ||
+ (hr == STRSAFE_E_END_OF_FILE))
+ {
+ if (ppszDestEnd)
+ {
+ *ppszDestEnd = pszDestEnd;
+ }
+
+ if (pcchRemaining)
+ {
+ *pcchRemaining = cchRemaining;
+ }
+ }
+
+ return hr;
+}
+#endif // FEATURE_PAL || !PLATFORM_UNIX
+#endif // !FEATURE_PAL
+#endif // !STRSAFE_LIB_IMPL
+
+#endif // _STRSAFE_H_INCLUDED_
diff --git a/src/pal/inc/unixasmmacros.inc b/src/pal/inc/unixasmmacros.inc
new file mode 100644
index 0000000000..7186645b34
--- /dev/null
+++ b/src/pal/inc/unixasmmacros.inc
@@ -0,0 +1,37 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#define INVALIDGCVALUE 0CCCCCCCDh
+
+#if defined(__APPLE__)
+#define C_FUNC(name) _##name
+#define EXTERNAL_C_FUNC(name) C_FUNC(name)
+#define LOCAL_LABEL(name) L##name
+#else
+#define C_FUNC(name) name
+#define EXTERNAL_C_FUNC(name) C_FUNC(name)@plt
+#define LOCAL_LABEL(name) .L##name
+#endif
+
+#if defined(__APPLE__)
+#define C_PLTFUNC(name) _##name
+#else
+#define C_PLTFUNC(name) name@PLT
+#endif
+
+
+.macro END_PROLOGUE
+.endm
+
+.macro SETALIAS New, Old
+ .equiv \New, \Old
+.endm
+
+#if defined(_AMD64_)
+#include "unixasmmacrosamd64.inc"
+#elif defined(_ARM_)
+#include "unixasmmacrosarm.inc"
+#elif defined(_ARM64_)
+#include "unixasmmacrosarm64.inc"
+#endif
diff --git a/src/pal/inc/unixasmmacrosamd64.inc b/src/pal/inc/unixasmmacrosamd64.inc
new file mode 100644
index 0000000000..f221b4406b
--- /dev/null
+++ b/src/pal/inc/unixasmmacrosamd64.inc
@@ -0,0 +1,355 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+.macro NESTED_ENTRY Name, Section, Handler
+ LEAF_ENTRY \Name, \Section
+ .ifnc \Handler, NoHandler
+#if defined(__APPLE__)
+ .cfi_personality 0x9b, C_FUNC(\Handler) // 0x9b == DW_EH_PE_indirect | DW_EH_PE_pcrel | DW_EH_PE_sdata4
+#else
+ .cfi_personality 0, C_FUNC(\Handler) // 0 == DW_EH_PE_absptr
+#endif
+ .endif
+.endm
+
+.macro NESTED_END Name, Section
+ LEAF_END \Name, \Section
+#if defined(__APPLE__)
+ .set LOCAL_LABEL(\Name\()_Size), . - C_FUNC(\Name)
+ .section __LD,__compact_unwind,regular,debug
+ .quad C_FUNC(\Name)
+ .long LOCAL_LABEL(\Name\()_Size)
+ .long 0x04000000 # DWARF
+ .quad 0
+ .quad 0
+#endif
+.endm
+
+.macro PATCH_LABEL Name
+ .global C_FUNC(\Name)
+C_FUNC(\Name):
+.endm
+
+.macro LEAF_ENTRY Name, Section
+ .global C_FUNC(\Name)
+#if defined(__APPLE__)
+ .text
+#else
+ .type \Name, %function
+#endif
+C_FUNC(\Name):
+ .cfi_startproc
+.endm
+
+.macro LEAF_END Name, Section
+#if !defined(__APPLE__)
+ .size \Name, .-\Name
+#endif
+ .cfi_endproc
+.endm
+
+.macro LEAF_END_MARKED Name, Section
+C_FUNC(\Name\()_End):
+ .global C_FUNC(\Name\()_End)
+ LEAF_END \Name, \Section
+.endm
+
+.macro NOP_3_BYTE
+ nop dword ptr [rax]
+.endm
+
+.macro NOP_2_BYTE
+ xchg ax, ax
+.endm
+
+.macro REPRET
+ .byte 0xf3
+ .byte 0xc3
+.endm
+
+.macro TAILJMP_RAX
+ .byte 0x48
+ .byte 0xFF
+ .byte 0xE0
+.endm
+
+.macro PREPARE_EXTERNAL_VAR Name, HelperReg
+ mov \HelperReg, [rip + C_FUNC(\Name)@GOTPCREL]
+.endm
+
+.macro push_nonvol_reg Register
+ push \Register
+ .cfi_adjust_cfa_offset 8
+ .cfi_rel_offset \Register, 0
+.endm
+
+.macro pop_nonvol_reg Register
+ pop \Register
+ .cfi_adjust_cfa_offset -8
+ .cfi_restore \Register
+.endm
+
+.macro alloc_stack Size
+.att_syntax
+ lea -(\Size)(%rsp), %rsp
+.intel_syntax noprefix
+ .cfi_adjust_cfa_offset \Size
+.endm
+
+.macro free_stack Size
+.att_syntax
+ lea \Size(%rsp), %rsp
+.intel_syntax noprefix
+ .cfi_adjust_cfa_offset -\Size
+.endm
+
+.macro set_cfa_register Reg, Offset
+ .cfi_def_cfa_register \Reg
+ .cfi_def_cfa_offset \Offset
+.endm
+
+.macro save_reg_postrsp Reg, Offset
+ __Offset = \Offset
+ mov qword ptr [rsp + __Offset], \Reg
+ .cfi_rel_offset \Reg, __Offset
+.endm
+
+.macro restore_reg Reg, Offset
+ __Offset = \Offset
+ mov \Reg, [rsp + __Offset]
+ .cfi_restore \Reg
+.endm
+
+.macro save_xmm128_postrsp Reg, Offset
+ __Offset = \Offset
+ movdqa xmmword ptr [rsp + __Offset], \Reg
+ // NOTE: We cannot use ".cfi_rel_offset \Reg, __Offset" here,
+ // the xmm registers are not supported by the libunwind
+.endm
+
+.macro restore_xmm128 Reg, ofs
+ __Offset = \ofs
+ movdqa \Reg, xmmword ptr [rsp + __Offset]
+ // NOTE: We cannot use ".cfi_restore \Reg" here,
+ // the xmm registers are not supported by the libunwind
+
+.endm
+
+.macro PUSH_CALLEE_SAVED_REGISTERS
+
+ push_register rbp
+ push_register rbx
+ push_register r15
+ push_register r14
+ push_register r13
+ push_register r12
+
+.endm
+
+.macro POP_CALLEE_SAVED_REGISTERS
+
+ pop_nonvol_reg r12
+ pop_nonvol_reg r13
+ pop_nonvol_reg r14
+ pop_nonvol_reg r15
+ pop_nonvol_reg rbx
+ pop_nonvol_reg rbp
+
+.endm
+
+.macro push_register Reg
+ push \Reg
+ .cfi_adjust_cfa_offset 8
+.endm
+
+.macro push_eflags
+ pushfq
+ .cfi_adjust_cfa_offset 8
+.endm
+
+.macro push_argument_register Reg
+ push_register \Reg
+.endm
+
+.macro PUSH_ARGUMENT_REGISTERS
+
+ push_argument_register r9
+ push_argument_register r8
+ push_argument_register rcx
+ push_argument_register rdx
+ push_argument_register rsi
+ push_argument_register rdi
+
+.endm
+
+.macro pop_register Reg
+ pop \Reg
+ .cfi_adjust_cfa_offset -8
+.endm
+
+.macro pop_eflags
+ popfq
+ .cfi_adjust_cfa_offset -8
+.endm
+
+.macro pop_argument_register Reg
+ pop_register \Reg
+.endm
+
+.macro POP_ARGUMENT_REGISTERS
+
+ pop_argument_register rdi
+ pop_argument_register rsi
+ pop_argument_register rdx
+ pop_argument_register rcx
+ pop_argument_register r8
+ pop_argument_register r9
+
+.endm
+
+.macro SAVE_FLOAT_ARGUMENT_REGISTERS ofs
+
+ save_xmm128_postrsp xmm0, \ofs
+ save_xmm128_postrsp xmm1, \ofs + 0x10
+ save_xmm128_postrsp xmm2, \ofs + 0x20
+ save_xmm128_postrsp xmm3, \ofs + 0x30
+ save_xmm128_postrsp xmm4, \ofs + 0x40
+ save_xmm128_postrsp xmm5, \ofs + 0x50
+ save_xmm128_postrsp xmm6, \ofs + 0x60
+ save_xmm128_postrsp xmm7, \ofs + 0x70
+
+.endm
+
+.macro RESTORE_FLOAT_ARGUMENT_REGISTERS ofs
+
+ restore_xmm128 xmm0, \ofs
+ restore_xmm128 xmm1, \ofs + 0x10
+ restore_xmm128 xmm2, \ofs + 0x20
+ restore_xmm128 xmm3, \ofs + 0x30
+ restore_xmm128 xmm4, \ofs + 0x40
+ restore_xmm128 xmm5, \ofs + 0x50
+ restore_xmm128 xmm6, \ofs + 0x60
+ restore_xmm128 xmm7, \ofs + 0x70
+
+.endm
+
+// Stack layout:
+//
+// (stack parameters)
+// ...
+// return address
+// CalleeSavedRegisters::rbp
+// CalleeSavedRegisters::rbx
+// CalleeSavedRegisters::r15
+// CalleeSavedRegisters::r14
+// CalleeSavedRegisters::r13
+// CalleeSavedRegisters::r12
+// ArgumentRegisters::r9
+// ArgumentRegisters::r8
+// ArgumentRegisters::rcx
+// ArgumentRegisters::rdx
+// ArgumentRegisters::rsi
+// ArgumentRegisters::rdi <- __PWTB_StackAlloc, __PWTB_TransitionBlock
+// padding to align xmm save area
+// xmm7
+// xmm6
+// xmm5
+// xmm4
+// xmm3
+// xmm2
+// xmm1
+// xmm0 <- __PWTB_FloatArgumentRegisters
+// extra locals + padding to qword align
+.macro PROLOG_WITH_TRANSITION_BLOCK extraLocals = 0, stackAllocOnEntry = 0, stackAllocSpill1, stackAllocSpill2, stackAllocSpill3
+
+ set_cfa_register rsp, 8
+
+ __PWTB_FloatArgumentRegisters = \extraLocals
+
+ .if ((__PWTB_FloatArgumentRegisters % 16) != 0)
+ __PWTB_FloatArgumentRegisters = __PWTB_FloatArgumentRegisters + 8
+ .endif
+
+ __PWTB_StackAlloc = __PWTB_FloatArgumentRegisters + 8 * 16 + 8 // 8 floating point registers
+ __PWTB_TransitionBlock = __PWTB_StackAlloc
+
+ .if \stackAllocOnEntry >= 4*8
+ .error "Max supported stackAllocOnEntry is 3*8"
+ .endif
+
+ .if \stackAllocOnEntry > 0
+ .cfi_adjust_cfa_offset \stackAllocOnEntry
+ .endif
+
+ // PUSH_CALLEE_SAVED_REGISTERS expanded here
+
+ .if \stackAllocOnEntry < 8
+ push_nonvol_reg rbp
+ mov rbp, rsp
+ .endif
+
+ .if \stackAllocOnEntry < 2*8
+ push_nonvol_reg rbx
+ .endif
+
+ .if \stackAllocOnEntry < 3*8
+ push_nonvol_reg r15
+ .endif
+
+ push_nonvol_reg r14
+ push_nonvol_reg r13
+ push_nonvol_reg r12
+
+ // ArgumentRegisters
+ PUSH_ARGUMENT_REGISTERS
+
+ .if \stackAllocOnEntry >= 3*8
+ mov \stackAllocSpill3, [rsp + 0x48]
+ save_reg_postrsp r15, 0x48
+ .endif
+
+ .if \stackAllocOnEntry >= 2*8
+ mov \stackAllocSpill2, [rsp + 0x50]
+ save_reg_postrsp rbx, 0x50
+ .endif
+
+ .if \stackAllocOnEntry >= 8
+ mov \stackAllocSpill1, [rsp + 0x58]
+ save_reg_postrsp rbp, 0x58
+ lea rbp, [rsp + 0x58]
+ .endif
+
+ alloc_stack __PWTB_StackAlloc
+ SAVE_FLOAT_ARGUMENT_REGISTERS __PWTB_FloatArgumentRegisters
+
+ END_PROLOGUE
+
+.endm
+
+.macro EPILOG_WITH_TRANSITION_BLOCK_RETURN
+
+ free_stack __PWTB_StackAlloc
+ POP_ARGUMENT_REGISTERS
+ POP_CALLEE_SAVED_REGISTERS
+ ret
+
+.endm
+
+.macro EPILOG_WITH_TRANSITION_BLOCK_TAILCALL
+
+ RESTORE_FLOAT_ARGUMENT_REGISTERS __PWTB_FloatArgumentRegisters
+ free_stack __PWTB_StackAlloc
+ POP_ARGUMENT_REGISTERS
+ POP_CALLEE_SAVED_REGISTERS
+
+.endm
+
+.macro RESET_FRAME_WITH_RBP
+
+ mov rsp, rbp
+ set_cfa_register rsp, 16
+ pop_nonvol_reg rbp
+ .cfi_same_value rbp
+
+.endm
diff --git a/src/pal/inc/unixasmmacrosarm.inc b/src/pal/inc/unixasmmacrosarm.inc
new file mode 100644
index 0000000000..14b0b4160e
--- /dev/null
+++ b/src/pal/inc/unixasmmacrosarm.inc
@@ -0,0 +1,268 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+.macro LEAF_ENTRY Name, Section
+ .thumb_func
+ .global C_FUNC(\Name)
+ .type \Name, %function
+C_FUNC(\Name):
+ .fnstart
+.endm
+
+.macro NESTED_ENTRY Name, Section, Handler
+ LEAF_ENTRY \Name, \Section
+ .ifnc \Handler, NoHandler
+ .personality C_FUNC(\Handler)
+ .endif
+.endm
+
+.macro NESTED_END Name, Section
+ LEAF_END \Name, \Section
+.endm
+
+.macro NESTED_END_MARKED Name, Section
+ LEAF_END_MARKED \Name, \Section
+.endm
+
+.macro PATCH_LABEL Name
+ .thumb_func
+ .global C_FUNC(\Name)
+C_FUNC(\Name):
+.endm
+
+.macro LEAF_END Name, Section
+ .size \Name, .-\Name
+ .fnend
+.endm
+
+.macro LEAF_END_MARKED Name, Section
+ .thumb_func
+ .global C_FUNC(\Name\()_End)
+C_FUNC(\Name\()_End):
+ LEAF_END \Name, \Section
+.endm
+
+.macro PREPARE_EXTERNAL_VAR Name, HelperReg
+ ldr \HelperReg, [pc, #C_FUNC(\Name)@GOTPCREL]
+.endm
+
+.macro push_nonvol_reg Register
+ push \Register
+ .save \Register
+.endm
+
+.macro pop_nonvol_reg Register
+ pop \Register
+.endm
+
+.macro vpush_nonvol_reg Register
+ vpush \Register
+ .vsave \Register
+.endm
+
+.macro vpop_nonvol_reg Register
+ vpop \Register
+.endm
+
+.macro alloc_stack Size
+ sub sp, sp, (\Size)
+ .pad #(\Size)
+.endm
+
+.macro free_stack Size
+ add sp, sp, (\Size)
+ .pad #-(\Size)
+.endm
+
+.macro POP_CALLEE_SAVED_REGISTERS
+ pop_nonvol_reg "{r4-r11, lr}"
+.endm
+
+.macro PUSH_CALLEE_SAVED_REGISTERS
+ push_nonvol_reg "{r4-r11, lr}"
+.endm
+
+.macro push_register Reg
+ push \Reg
+.endm
+
+.macro push_argument_register Reg
+ push_register \Reg
+.endm
+
+.macro PUSH_ARGUMENT_REGISTERS
+ push {r0-r3}
+ .save {r0-r3}
+.endm
+
+.macro pop_register Reg
+ pop \Reg
+.endm
+
+.macro pop_argument_register Reg
+ pop_register \Reg
+.endm
+
+.macro POP_ARGUMENT_REGISTERS
+ pop {r0-r3}
+.endm
+
+// Stack layout:
+//
+// (stack parameters)
+// ...
+// ArgumentRegisters::r3
+// ArgumentRegisters::r2
+// ArgumentRegisters::r1
+// ArgumentRegisters::r0
+// CalleeSavedRegisters::lr
+// CalleeSavedRegisters::r11
+// CalleeSavedRegisters::r10
+// CalleeSavedRegisters::r9
+// CalleeSavedRegisters::r8
+// CalleeSavedRegisters::r7 <- r7
+// CalleeSavedRegisters::r6
+// CalleeSavedRegisters::r5
+// CalleeSavedRegisters::r4 <- __PWTB_StackAlloc, __PWTB_TransitionBlock
+// padding to align float save area
+// d7
+// d6
+// d5
+// d4
+// d3
+// d2
+// d1
+// d0 <- __PWTB_FloatArgumentRegisters
+.macro PROLOG_WITH_TRANSITION_BLOCK extraLocals = 0, saveFpArgs = 1, pushArgRegs = 0
+
+ __PWTB_FloatArgumentRegisters = \extraLocals
+ __PWTB_SaveFPArgs = \saveFpArgs
+
+ .if (__PWTB_SaveFPArgs == 1)
+ .if ((__PWTB_FloatArgumentRegisters % 8) != 0)
+ __PWTB_FloatArgumentRegisters = __PWTB_FloatArgumentRegisters + 4
+ .endif
+
+ __PWTB_TransitionBlock = __PWTB_FloatArgumentRegisters + 8 * 8 + 4 // 8 floating point registers + padding
+ .else
+ .if ((__PWTB_FloatArgumentRegisters % 8) == 0)
+ __PWTB_FloatArgumentRegisters = __PWTB_FloatArgumentRegisters + 4
+ .endif
+
+ __PWTB_TransitionBlock = __PWTB_FloatArgumentRegisters
+ .endif
+
+ __PWTB_StackAlloc = __PWTB_TransitionBlock
+
+ .ifnc \pushArgRegs, DoNotPushArgRegs
+ PUSH_ARGUMENT_REGISTERS
+ .endif
+
+ PUSH_CALLEE_SAVED_REGISTERS
+ PROLOG_STACK_SAVE_OFFSET r7, #12
+ // let r7 point the saved r7 in the stack (clang FP style)
+
+ alloc_stack __PWTB_StackAlloc
+
+ .if (__PWTB_SaveFPArgs == 1)
+ add r6, sp, #(__PWTB_FloatArgumentRegisters)
+ vstm r6, {d0-d7}
+ .endif
+
+ CHECK_STACK_ALIGNMENT
+
+ END_PROLOGUE
+
+.endm
+
+.macro EPILOG_WITH_TRANSITION_BLOCK_RETURN
+
+ free_stack __PWTB_StackAlloc
+ POP_CALLEE_SAVED_REGISTERS
+ free_stack 16
+ bx lr
+
+.endm
+
+.macro EPILOG_WITH_TRANSITION_BLOCK_TAILCALL
+
+ .if (__PWTB_SaveFPArgs == 1)
+ add r6, sp, #(__PWTB_FloatArgumentRegisters)
+ vldm r6, {d0-d7}
+ .endif
+
+ free_stack __PWTB_StackAlloc
+ POP_CALLEE_SAVED_REGISTERS
+ POP_ARGUMENT_REGISTERS
+
+.endm
+
+.macro EMIT_BREAKPOINT
+ .inst.w 0xde01
+.endm
+
+.macro PROLOG_PUSH RegList
+ push_nonvol_reg "\RegList"
+.endm
+
+.macro PROLOG_VPUSH RegList
+ vpush_nonvol_reg "\RegList"
+.endm
+
+.macro PROLOG_STACK_SAVE Register
+ .setfp \Register, sp
+ mov \Register, sp
+.endm
+
+.macro PROLOG_STACK_SAVE_OFFSET Register, Offset
+ .setfp \Register, sp, \Offset
+ add \Register, sp, \Offset
+.endm
+
+.macro EPILOG_STACK_FREE Size
+ add sp, sp, \Size
+.endm
+
+.macro EPILOG_STACK_RESTORE Register
+ mov sp, \Register
+.endm
+
+.macro EPILOG_STACK_RESTORE_OFFSET Register, Offset
+ sub sp, \Register, \Offset
+.endm
+
+.macro EPILOG_BRANCH Target
+ b \Target
+.endm
+
+.macro EPILOG_BRANCH_REG reg
+ bx \reg
+.endm
+
+.macro EPILOG_POP RegList
+ pop_nonvol_reg "\RegList"
+.endm
+
+.macro EPILOG_VPOP RegList
+ vpop_nonvol_reg "\RegList"
+.endm
+
+//-----------------------------------------------------------------------------
+// Macro used to check (in debug builds only) whether the stack is 64-bit aligned (a requirement before calling
+// out into C++/OS code). Invoke this directly after your prolog (if the stack frame size is fixed) or directly
+// before a call (if you have a frame pointer and a dynamic stack). A breakpoint will be invoked if the stack
+// is misaligned.
+//
+.macro CHECK_STACK_ALIGNMENT
+
+#ifdef _DEBUG
+ push {r0}
+ add r0, sp, #4
+ tst r0, #7
+ pop {r0}
+ beq 0f
+ EMIT_BREAKPOINT
+0:
+#endif
+.endm
diff --git a/src/pal/inc/unixasmmacrosarm64.inc b/src/pal/inc/unixasmmacrosarm64.inc
new file mode 100644
index 0000000000..ae60db4d35
--- /dev/null
+++ b/src/pal/inc/unixasmmacrosarm64.inc
@@ -0,0 +1,318 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+.macro NESTED_ENTRY Name, Section, Handler
+ LEAF_ENTRY \Name, \Section
+ .ifnc \Handler, NoHandler
+ .cfi_personality 0, C_FUNC(\Handler) // 0 == DW_EH_PE_absptr
+ .endif
+.endm
+
+.macro NESTED_END Name, Section
+ LEAF_END \Name, \Section
+.endm
+
+.macro PATCH_LABEL Name
+ .global C_FUNC(\Name)
+C_FUNC(\Name):
+.endm
+
+.macro LEAF_ENTRY Name, Section
+ .global C_FUNC(\Name)
+ .type \Name, %function
+C_FUNC(\Name):
+ .cfi_startproc
+.endm
+
+.macro LEAF_END Name, Section
+ .size \Name, .-\Name
+ .cfi_endproc
+.endm
+
+.macro LEAF_END_MARKED Name, Section
+ .global C_FUNC(\Name\()_End)
+C_FUNC(\Name\()_End):
+ LEAF_END \Name, \Section
+.endm
+
+.macro PREPARE_EXTERNAL_VAR Name, HelperReg
+ ldr \HelperReg, [pc, #C_FUNC(\Name)@GOTPCREL]
+.endm
+
+.macro PROLOG_STACK_ALLOC Size
+ sub sp, sp, \Size
+ .cfi_adjust_cfa_offset \Size
+.endm
+
+.macro EPILOG_STACK_FREE Size
+ add sp, sp, \Size
+.endm
+
+.macro EPILOG_STACK_RESTORE
+ mov sp, fp
+.endm
+
+.macro PROLOG_SAVE_REG reg, ofs
+ str \reg, [sp, \ofs]
+.endm
+
+.macro PROLOG_SAVE_REG_PAIR reg1, reg2, ofs
+ stp \reg1, \reg2, [sp, \ofs]
+ .ifc \reg1, fp
+ mov fp, sp
+ .endif
+.endm
+
+.macro PROLOG_SAVE_REG_PAIR_INDEXED reg1, reg2, ofs
+ stp \reg1, \reg2, [sp, \ofs]!
+ .ifc \reg1, fp
+ mov fp, sp
+ .endif
+.endm
+
+.macro EPILOG_RESTORE_REG reg, ofs
+ ldr \reg, [sp, \ofs]
+.endm
+
+.macro EPILOG_RESTORE_REG_PAIR reg1, reg2, ofs
+ ldp \reg1, \reg2, [sp, \ofs]
+.endm
+
+.macro EPILOG_RESTORE_REG_PAIR_INDEXED reg1, reg2, ofs
+ ldp \reg1, \reg2, [sp], \ofs
+.endm
+
+.macro EPILOG_RETURN
+ ret
+.endm
+
+.macro EMIT_BREAKPOINT
+ brk #0
+.endm
+
+//-----------------------------------------------------------------------------
+// Define the prolog for a TransitionFrame-based method. This macro should be called first in the method and
+// comprises the entire prolog (i.e. don't modify SP after calling this).The locals must be 8 byte aligned
+//
+// Stack layout:
+//
+// (stack parameters)
+// ...
+// fp
+// lr
+// CalleeSavedRegisters::x28
+// CalleeSavedRegisters::x27
+// CalleeSavedRegisters::x26
+// CalleeSavedRegisters::x25
+// CalleeSavedRegisters::x24
+// CalleeSavedRegisters::x23
+// CalleeSavedRegisters::x22
+// CalleeSavedRegisters::x21
+// CalleeSavedRegisters::x20
+// CalleeSavedRegisters::x19
+// CalleeSavedRegisters::x30 (Lr)
+// CalleeSavedRegisters::x29 (Fp)
+// ArgumentRegisters::x7
+// ArgumentRegisters::x6
+// ArgumentRegisters::x5
+// ArgumentRegisters::x4
+// ArgumentRegisters::x3
+// ArgumentRegisters::x2
+// ArgumentRegisters::x1
+// ArgumentRegisters::x0
+// FloatRegisters::d7
+// FloatRegisters::d6
+// FloatRegisters::d5
+// FloatRegisters::d4
+// FloatRegisters::d3
+// FloatRegisters::d2
+// FloatRegisters::d1
+// FloatRegisters::d0
+.macro PROLOG_WITH_TRANSITION_BLOCK extraLocals = 0, SaveFPArgs = 1
+
+ __PWTB_FloatArgumentRegisters = \extraLocals
+
+ .if ((__PWTB_FloatArgumentRegisters % 16) != 0)
+ __PWTB_FloatArgumentRegisters = __PWTB_FloatArgumentRegisters + 8
+ .endif
+
+ __PWTB_TransitionBlock = __PWTB_FloatArgumentRegisters
+
+ .if \SaveFPArgs > 0
+ __PWTB_TransitionBlock = __PWTB_TransitionBlock + SIZEOF__FloatArgumentRegisters
+ .endif
+
+ __PWTB_StackAlloc = __PWTB_TransitionBlock
+ __PWTB_ArgumentRegisters = __PWTB_StackAlloc + 96
+
+ PROLOG_SAVE_REG_PAIR_INDEXED fp, lr, #-160
+ // Spill callee saved registers
+ PROLOG_SAVE_REG_PAIR x19, x20, #16
+ PROLOG_SAVE_REG_PAIR x21, x22, #32
+ PROLOG_SAVE_REG_PAIR x23, x24, #48
+ PROLOG_SAVE_REG_PAIR x25, x26, #64
+ PROLOG_SAVE_REG_PAIR x27, x28, #80
+
+ // Allocate space for the rest of the frame
+ PROLOG_STACK_ALLOC __PWTB_StackAlloc
+
+ // Spill argument registers.
+ SAVE_ARGUMENT_REGISTERS sp, __PWTB_ArgumentRegisters
+
+ .if \SaveFPArgs > 0
+ SAVE_FLOAT_ARGUMENT_REGISTERS sp, \extraLocals
+ .endif
+
+.endm
+
+//-----------------------------------------------------------------------------
+// The Following sets of SAVE_*_REGISTERS expect the memory to be reserved and
+// base address to be passed in $reg
+//
+
+// Reserve 64 bytes of memory before calling SAVE_ARGUMENT_REGISTERS
+.macro SAVE_ARGUMENT_REGISTERS reg, ofs
+
+ stp x0, x1, [\reg, #(\ofs)]
+ stp x2, x3, [\reg, #(\ofs + 16)]
+ stp x4, x5, [\reg, #(\ofs + 32)]
+ stp x6, x7, [\reg, #(\ofs + 48)]
+
+.endm
+
+// Reserve 64 bytes of memory before calling SAVE_FLOAT_ARGUMENT_REGISTERS
+.macro SAVE_FLOAT_ARGUMENT_REGISTERS reg, ofs
+
+ stp d0, d1, [\reg, #(\ofs)]
+ stp d2, d3, [\reg, #(\ofs + 16)]
+ stp d4, d5, [\reg, #(\ofs + 32)]
+ stp d6, d7, [\reg, #(\ofs + 48)]
+
+.endm
+
+.macro RESTORE_ARGUMENT_REGISTERS reg, ofs
+
+ ldp x0, x1, [\reg, #(\ofs)]
+ ldp x2, x3, [\reg, #(\ofs + 16)]
+ ldp x4, x5, [\reg, #(\ofs + 32)]
+ ldp x6, x7, [\reg, #(\ofs + 48)]
+
+.endm
+
+.macro RESTORE_FLOAT_ARGUMENT_REGISTERS reg, ofs
+
+ ldp d0, d1, [\reg, #(\ofs)]
+ ldp d2, d3, [\reg, #(\ofs + 16)]
+ ldp d4, d5, [\reg, #(\ofs + 32)]
+ ldp d6, d7, [\reg, #(\ofs + 48)]
+
+.endm
+
+.macro EPILOG_BRANCH_REG reg
+
+ br \reg
+
+.endm
+
+//-----------------------------------------------------------------------------
+// Provides a matching epilog to PROLOG_WITH_TRANSITION_BLOCK and ends by preparing for tail-calling.
+// Since this is a tail call argument registers are restored.
+//
+.macro EPILOG_WITH_TRANSITION_BLOCK_TAILCALL extraLocals = 0, SaveFPArgs =1
+
+ __PWTB_FloatArgumentRegisters = \extraLocals
+
+ .if ((__PWTB_FloatArgumentRegisters % 16) != 0)
+ __PWTB_FloatArgumentRegisters = __PWTB_FloatArgumentRegisters + 8
+ .endif
+
+ __PWTB_TransitionBlock = __PWTB_FloatArgumentRegisters
+
+ .if \SaveFPArgs > 0
+ __PWTB_TransitionBlock = __PWTB_TransitionBlock + SIZEOF__FloatArgumentRegisters
+ .endif
+
+ __PWTB_StackAlloc = __PWTB_TransitionBlock
+ __PWTB_ArgumentRegisters = __PWTB_StackAlloc + 96
+
+ .if \SaveFPArgs > 0
+ RESTORE_FLOAT_ARGUMENT_REGISTERS sp, __PWTB_FloatArgumentRegisters
+ .endif
+
+ RESTORE_ARGUMENT_REGISTERS sp, __PWTB_ArgumentRegisters
+ EPILOG_STACK_FREE __PWTB_StackAlloc
+
+ EPILOG_RESTORE_REG_PAIR x19, x20, #16
+ EPILOG_RESTORE_REG_PAIR x21, x22, #32
+ EPILOG_RESTORE_REG_PAIR x23, x24, #48
+ EPILOG_RESTORE_REG_PAIR x25, x26, #64
+ EPILOG_RESTORE_REG_PAIR x27, x28, #80
+ EPILOG_RESTORE_REG_PAIR_INDEXED fp, lr, #160
+
+.endm
+
+// ------------------------------------------------------------------
+// Macro to generate Redirection Stubs
+//
+// $reason : reason for redirection
+// Eg. GCThreadControl
+// NOTE: If you edit this macro, make sure you update GetCONTEXTFromRedirectedStubStackFrame.
+// This function is used by both the personality routine and the debugger to retrieve the original CONTEXT.
+.macro GenerateRedirectedHandledJITCaseStub reason
+
+#if NOTYET
+ GBLS __RedirectionStubFuncName
+ GBLS __RedirectionStubEndFuncName
+ GBLS __RedirectionFuncName
+__RedirectionStubFuncName SETS "RedirectedHandledJITCaseFor":CC:"$reason":CC:"_Stub"
+__RedirectionStubEndFuncName SETS "RedirectedHandledJITCaseFor":CC:"$reason":CC:"_StubEnd"
+__RedirectionFuncName SETS "|?RedirectedHandledJITCaseFor":CC:"$reason":CC:"@Thread@@CAXXZ|"
+
+ IMPORT $__RedirectionFuncName
+
+ NESTED_ENTRY $__RedirectionStubFuncName
+ PROLOG_SAVE_REG_PAIR fp, lr, #-16
+ sub sp, sp, #16 // stack slot for CONTEXT * and padding
+
+ //REDIRECTSTUB_SP_OFFSET_CONTEXT is defined in asmconstants.h and is used in GetCONTEXTFromRedirectedStubStackFrame
+ //If CONTEXT is not saved at 0 offset from SP it must be changed as well.
+ ASSERT REDIRECTSTUB_SP_OFFSET_CONTEXT == 0
+
+ // Stack alignment. This check is necessary as this function can be
+ // entered before complete execution of the prolog of another function.
+ and x8, fp, #15
+ sub sp, sp, x8
+
+
+ //
+ // Save a copy of the redirect CONTEXT*.
+ // This is needed for the debugger to unwind the stack.
+ //
+ bl GetCurrentSavedRedirectContext
+ str x0, [sp]
+
+ //
+ // Fetch the interrupted pc and save it as our return address.
+ //
+ ldr x1, [x0, #CONTEXT_Pc]
+ str x1, [fp, #8]
+
+ //
+ // Call target, which will do whatever we needed to do in the context
+ // of the target thread, and will RtlRestoreContext when it is done.
+ //
+ bl $__RedirectionFuncName
+
+ EMIT_BREAKPOINT // Unreachable
+
+// Put a label here to tell the debugger where the end of this function is.
+$__RedirectionStubEndFuncName
+ EXPORT $__RedirectionStubEndFuncName
+
+ NESTED_END
+#else
+ EMIT_BREAKPOINT
+#endif
+
+.endm
diff --git a/src/pal/prebuilt/corerror/makecorerror.bat b/src/pal/prebuilt/corerror/makecorerror.bat
new file mode 100644
index 0000000000..f9b964f569
--- /dev/null
+++ b/src/pal/prebuilt/corerror/makecorerror.bat
@@ -0,0 +1,27 @@
+@if "%_echo%"=="" echo off
+REM Licensed to the .NET Foundation under one or more agreements.
+REM The .NET Foundation licenses this file to you under the MIT license.
+REM See the LICENSE file in the project root for more information.
+setlocal
+
+if "%_NTROOT%" == "" goto LUsage
+
+set MANAGED_TOOLS_PATH=%MANAGED_TOOLS_ROOT%\%MANAGED_TOOLS_VERSION%
+set CORERROR_PATH=%_NTROOT%\ndp\clr\src\inc
+
+%MANAGED_TOOLS_PATH%\genheaders.exe %CORERROR_PATH%\corerror.xml ..\inc\corerror.h mscorurt.rc
+
+goto LExit
+
+:LUsage
+
+echo.
+echo makecorerror.bat
+echo.
+echo Builds corerror.h for PALRT
+echo.
+echo Should be run inside razzle environment, depends on %%_NTROOT%% environment variable.
+echo.
+
+:LExit
+
diff --git a/src/pal/prebuilt/corerror/mscorurt.rc b/src/pal/prebuilt/corerror/mscorurt.rc
new file mode 100644
index 0000000000..28da8f91ce
--- /dev/null
+++ b/src/pal/prebuilt/corerror/mscorurt.rc
@@ -0,0 +1,1083 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+STRINGTABLE DISCARDABLE
+BEGIN
+ MSG_FOR_URT_HR(CORDBG_S_AT_END_OF_STACK) "The stack walk has reached the end of the stack. There are no more frames to walk."
+ MSG_FOR_URT_HR(CEE_E_ENTRYPOINT) "Invalid entrypoint information."
+ MSG_FOR_URT_HR(CEE_E_CVTRES_NOT_FOUND) "cvtres.exe not found."
+ MSG_FOR_URT_HR(MSEE_E_LOADLIBFAILED) "Failed to delayload a library."
+ MSG_FOR_URT_HR(MSEE_E_GETPROCFAILED) "Failed to get dll entrypoint."
+ MSG_FOR_URT_HR(MSEE_E_MULTCOPIESLOADED) "Multiple copies of mscoree.dll have been loaded into the same process."
+ MSG_FOR_URT_HR(COR_E_TYPEUNLOADED) "Type has been unloaded."
+ MSG_FOR_URT_HR(COR_E_APPDOMAINUNLOADED) "Attempted to access an unloaded appdomain."
+ MSG_FOR_URT_HR(COR_E_CANNOTUNLOADAPPDOMAIN) "Error while unloading appdomain."
+ MSG_FOR_URT_HR(MSEE_E_ASSEMBLYLOADINPROGRESS) "Assembly is still being loaded."
+ MSG_FOR_URT_HR(MSEE_E_CANNOTCREATEAPPDOMAIN) "Attempt to create appdomain failed."
+ MSG_FOR_URT_HR(COR_E_ASSEMBLYEXPECTED) "The module was expected to contain an assembly manifest."
+ MSG_FOR_URT_HR(COR_E_FIXUPSINEXE) "Attempt to load an unverifiable executable with fixups (IAT with more than 2 sections or a TLS section.)"
+ MSG_FOR_URT_HR(COR_E_NO_LOADLIBRARY_ALLOWED) "Attempt to LoadLibrary a managed image in an improper way (only assemblies with EAT area allowed)."
+ MSG_FOR_URT_HR(COR_E_NEWER_RUNTIME) "This assembly is built by a runtime newer than the currently loaded runtime and cannot be loaded."
+ MSG_FOR_URT_HR(COR_E_CANNOT_SET_POLICY) "Cannot set security policy under MultiDomain after non-GAC assemblies have been loaded in appdomain."
+ MSG_FOR_URT_HR(COR_E_CANNOT_SPECIFY_EVIDENCE) "Cannot specify assembly evidence under MultiDomain after non-GAC assemblies with default evidence have been loaded in appdomain."
+ MSG_FOR_URT_HR(COR_E_MULTIMODULEASSEMBLIESDIALLOWED) "The module cannot be loaded because only single file assemblies are supported."
+ MSG_FOR_URT_HR(HOST_E_DEADLOCK) "Host detected a deadlock on a blocking operation."
+ MSG_FOR_URT_HR(HOST_E_INTERRUPTED) "Host interrupted a wait."
+ MSG_FOR_URT_HR(HOST_E_INVALIDOPERATION) "Invalid operation."
+ MSG_FOR_URT_HR(HOST_E_CLRNOTAVAILABLE) "CLR has been disabled due to unrecoverable error."
+ MSG_FOR_URT_HR(HOST_E_TIMEOUT) "A wait has timed out."
+ MSG_FOR_URT_HR(HOST_E_NOT_OWNER) "The leave operation has been attempted on a synchronization primitive that is not owned by the current thread."
+ MSG_FOR_URT_HR(HOST_E_ABANDONED) "An event has been abandoned."
+ MSG_FOR_URT_HR(HOST_E_EXITPROCESS_THREADABORT) "Process exited due to ThreadAbort escalation."
+ MSG_FOR_URT_HR(HOST_E_EXITPROCESS_ADUNLOAD) "Process exited due to AD Unload escalation."
+ MSG_FOR_URT_HR(HOST_E_EXITPROCESS_TIMEOUT) "Process exited due to Timeout escalation."
+ MSG_FOR_URT_HR(HOST_E_EXITPROCESS_OUTOFMEMORY) "Process exited due to OutOfMemory escalation."
+ MSG_FOR_URT_HR(HOST_E_EXITPROCESS_STACKOVERFLOW) "Process exited due to StackOverflow escalation."
+ MSG_FOR_URT_HR(COR_E_MODULE_HASH_CHECK_FAILED) "The check of the module's hash failed."
+ MSG_FOR_URT_HR(FUSION_E_REF_DEF_MISMATCH) "The located assembly's manifest definition does not match the assembly reference."
+ MSG_FOR_URT_HR(FUSION_E_INVALID_PRIVATE_ASM_LOCATION) "The private assembly was located outside the appbase directory."
+ MSG_FOR_URT_HR(FUSION_E_ASM_MODULE_MISSING) "A module specified in the manifest was not found."
+ MSG_FOR_URT_HR(FUSION_E_UNEXPECTED_MODULE_FOUND) "Modules which are not in the manifest were streamed in."
+ MSG_FOR_URT_HR(FUSION_E_PRIVATE_ASM_DISALLOWED) "A strongly-named assembly is required."
+ MSG_FOR_URT_HR(FUSION_E_SIGNATURE_CHECK_FAILED) "Strong name signature could not be verified. The assembly may have been tampered with, or it was delay signed but not fully signed with the correct private key."
+ MSG_FOR_URT_HR(FUSION_E_DATABASE_ERROR) "An unexpected error was encountered in the Assembly Cache database."
+ MSG_FOR_URT_HR(FUSION_E_INVALID_NAME) "The given assembly name or codebase was invalid."
+ MSG_FOR_URT_HR(FUSION_E_CODE_DOWNLOAD_DISABLED) "HTTP download of assemblies has been disabled for this appdomain."
+ MSG_FOR_URT_HR(FUSION_E_UNINSTALL_DISALLOWED) "Uninstall of given assembly is not allowed."
+ MSG_FOR_URT_HR(CLR_E_APP_CONFIG_NOT_ALLOWED_IN_APPX_PROCESS) "Application configuration file not allowed in AppX process."
+ MSG_FOR_URT_HR(FUSION_E_HOST_GAC_ASM_MISMATCH) "Assembly in host store has a different signature than assembly in GAC."
+ MSG_FOR_URT_HR(FUSION_E_LOADFROM_BLOCKED) "LoadFrom(), LoadFile(), Load(byte[]) and LoadModule() have been disabled by the host."
+ MSG_FOR_URT_HR(FUSION_E_CACHEFILE_FAILED) "Failed to add file to AppDomain cache."
+ MSG_FOR_URT_HR(FUSION_E_APP_DOMAIN_LOCKED) "The requested assembly version conflicts with what is already bound in the app domain or specified in the manifest."
+ MSG_FOR_URT_HR(FUSION_E_CONFIGURATION_ERROR) "The requested assembly name was neither found in the GAC nor in the manifest or the manifest's specified location is wrong."
+ MSG_FOR_URT_HR(FUSION_E_MANIFEST_PARSE_ERROR) "Unexpected error while parsing the specified manifest."
+ MSG_FOR_URT_HR(FUSION_E_INVALID_ASSEMBLY_REFERENCE) "The given assembly name is invalid because a processor architecture is specified."
+ MSG_FOR_URT_HR(COR_E_ASSEMBLY_NOT_EXPECTED) "The module was expected to not contain an assembly manifest."
+ MSG_FOR_URT_HR(COR_E_LOADING_REFERENCE_ASSEMBLY) "Reference assemblies should not be loaded for execution. They can only be loaded in the Reflection-only loader context."
+ MSG_FOR_URT_HR(COR_E_NI_AND_RUNTIME_VERSION_MISMATCH) "The native image could not be loaded, because it was generated for use by a different version of the runtime."
+ MSG_FOR_URT_HR(COR_E_LOADING_WINMD_REFERENCE_ASSEMBLY) "Contract Windows Runtime assemblies cannot be loaded for execution. Make sure your application only contains non-contract Windows Runtime assemblies."
+ MSG_FOR_URT_HR(CLDB_E_FILE_BADREAD) "Error occurred during a read."
+ MSG_FOR_URT_HR(CLDB_E_FILE_BADWRITE) "Error occurred during a write."
+ MSG_FOR_URT_HR(CLDB_E_FILE_READONLY) "File is read only."
+ MSG_FOR_URT_HR(CLDB_E_NAME_ERROR) "Ill-formed name."
+ MSG_FOR_URT_HR(CLDB_E_TRUNCATION) "Data value was truncated."
+ MSG_FOR_URT_HR(CLDB_E_FILE_OLDVER) "Old version error."
+ MSG_FOR_URT_HR(CLDB_E_RELOCATED) "A shared memory open failed to open at the originally assigned memory address."
+ MSG_FOR_URT_HR(CLDB_E_SMDUPLICATE) "Create of shared memory failed. A memory mapping of the same name already exists."
+ MSG_FOR_URT_HR(CLDB_E_NO_DATA) "No .CLB data in the memory or stream."
+ MSG_FOR_URT_HR(CLDB_E_READONLY) "Database is read only."
+ MSG_FOR_URT_HR(CLDB_E_INCOMPATIBLE) "Importing scope is not compatible with the emitting scope."
+ MSG_FOR_URT_HR(CLDB_E_FILE_CORRUPT) "File is corrupt."
+ MSG_FOR_URT_HR(CLDB_E_SCHEMA_VERNOTFOUND) "Required version of schema not found."
+ MSG_FOR_URT_HR(CLDB_E_BADUPDATEMODE) "Cannot open a incrementally build scope for full update."
+ MSG_FOR_URT_HR(CLDB_E_INDEX_NONULLKEYS) "Null value not allowed in unique index or primary key."
+ MSG_FOR_URT_HR(CLDB_E_INDEX_DUPLICATE) "Index has been duplicated."
+ MSG_FOR_URT_HR(CLDB_E_INDEX_BADTYPE) "The columns data type is not allowed in an index."
+ MSG_FOR_URT_HR(CLDB_E_INDEX_NOTFOUND) "Index not found."
+ MSG_FOR_URT_HR(CLDB_E_RECORD_NOTFOUND) "Record not found on lookup."
+ MSG_FOR_URT_HR(CLDB_E_RECORD_OVERFLOW) "Too many records were returned for criteria."
+ MSG_FOR_URT_HR(CLDB_E_RECORD_DUPLICATE) "Record is a duplicate."
+ MSG_FOR_URT_HR(CLDB_E_RECORD_PKREQUIRED) "Primary key value is required."
+ MSG_FOR_URT_HR(CLDB_E_RECORD_DELETED) "Record is valid but deleted."
+ MSG_FOR_URT_HR(CLDB_E_RECORD_OUTOFORDER) "Record is emitted out of order."
+ MSG_FOR_URT_HR(CLDB_E_COLUMN_OVERFLOW) "Data too large."
+ MSG_FOR_URT_HR(CLDB_E_COLUMN_READONLY) "Column cannot be changed."
+ MSG_FOR_URT_HR(CLDB_E_COLUMN_SPECIALCOL) "Too many RID or primary key columns, 1 is max."
+ MSG_FOR_URT_HR(CLDB_E_COLUMN_PKNONULLS) "Primary key column may not allow the null value."
+ MSG_FOR_URT_HR(CLDB_E_TABLE_CANTDROP) "Attempted auto-drop of table while open."
+ MSG_FOR_URT_HR(CLDB_E_OBJECT_NOTFOUND) "Object not found in the database."
+ MSG_FOR_URT_HR(CLDB_E_OBJECT_COLNOTFOUND) "Column not found."
+ MSG_FOR_URT_HR(CLDB_E_VECTOR_BADINDEX) "Invalid index."
+ MSG_FOR_URT_HR(CLDB_E_TOO_BIG) "A blob or string was too big."
+ MSG_FOR_URT_HR(META_E_INVALID_TOKEN_TYPE) "A token of the wrong type passed to a metadata function."
+ MSG_FOR_URT_HR(TLBX_E_INVALID_TYPEINFO) "Typelib import: Invalid type, not converted."
+ MSG_FOR_URT_HR(TLBX_E_INVALID_TYPEINFO_UNNAMED) "Typelib import: Invalid type, not converted - name unknown."
+ MSG_FOR_URT_HR(TLBX_E_CTX_NESTED) "Typelib export: TLBX_E_CTX_NESTED"
+ MSG_FOR_URT_HR(TLBX_E_ERROR_MESSAGE) "Typelib export: General error. See IError info for more information."
+ MSG_FOR_URT_HR(TLBX_E_CANT_SAVE) "Typelib export: SaveAllChanges() failed."
+ MSG_FOR_URT_HR(TLBX_W_LIBNOTREGISTERED) "Typelib export: Type library is not registered."
+ MSG_FOR_URT_HR(TLBX_E_CANTLOADLIBRARY) "Typelib export: Type library could not be loaded."
+ MSG_FOR_URT_HR(TLBX_E_BAD_VT_TYPE) "Typelib import: Invalid vartype, not converted."
+ MSG_FOR_URT_HR(TLBX_E_NO_MSCOREE_TLB) "Typelib export: Could not load mscoree.tlb."
+ MSG_FOR_URT_HR(TLBX_E_BAD_MSCOREE_TLB) "Typelib export: Could not get a required typeinfo from mscoree.tlb."
+ MSG_FOR_URT_HR(TLBX_E_TLB_EXCEPTION) "Typelib import: Fault reading a typelib."
+ MSG_FOR_URT_HR(TLBX_E_MULTIPLE_LCIDS) "Typelib import: Multiple [lcid] parameters on a method."
+ MSG_FOR_URT_HR(TLBX_E_AMBIGUOUS_RETURN) "Typelib import: Duplicate or ambiguous return types."
+ MSG_FOR_URT_HR(TLBX_E_DUPLICATE_TYPE_NAME) "Typelib import: Duplicate name (due to user-defined name)."
+ MSG_FOR_URT_HR(TLBX_I_NONSEQUENTIALSTRUCT) "Typelib export: Cannot convert non-sequential structs."
+ MSG_FOR_URT_HR(TLBX_I_RESOLVEREFFAILED) "Typelib import: The resolve ref call failed."
+ MSG_FOR_URT_HR(TLBX_E_ASANY) "Typelib export: Encountered AsAny - ignored."
+ MSG_FOR_URT_HR(TLBX_E_INVALIDLCIDPARAM) "Typelib export: Encountered an [lcid] attribute set to an invalid parameter."
+ MSG_FOR_URT_HR(TLBX_E_LCIDONDISPONLYITF) "Typelib export: Encountered an [lcid] attribute on a pure dispatch interface."
+ MSG_FOR_URT_HR(TLBX_E_NONPUBLIC_FIELD) "Typelib export: Non-public field in public struct."
+ MSG_FOR_URT_HR(TLBX_E_BAD_NAMES) "Typelib export: Bad names list."
+ MSG_FOR_URT_HR(TLBX_E_GENERICINST_SIGNATURE) "TypeLib export: generic type instance in signature."
+ MSG_FOR_URT_HR(TLBX_E_GENERICPAR_SIGNATURE) "TypeLib export: generic type parameter in signature."
+ MSG_FOR_URT_HR(META_E_DUPLICATE) "Attempted to define an object that already exists."
+ MSG_FOR_URT_HR(META_E_GUID_REQUIRED) "A guid was not provided where one was required."
+ MSG_FOR_URT_HR(META_E_TYPEDEF_MISMATCH) "Merge: an import typedef matched ns.name, but not version and guid."
+ MSG_FOR_URT_HR(META_E_MERGE_COLLISION) "Merge: conflict between import and emit."
+ MSG_FOR_URT_HR(TLBX_E_NO_SAFEHANDLE_ARRAYS) "TypeLib export: Detected array of SafeHandles."
+ MSG_FOR_URT_HR(META_E_METHD_NOT_FOUND) "Merge: Class already in emit scope, but member not found."
+ MSG_FOR_URT_HR(META_E_FIELD_NOT_FOUND) "Merge: Class already in emit scope, but member not found."
+ MSG_FOR_URT_HR(META_E_PARAM_MISMATCH) "Merge: Parameter information mismatched."
+ MSG_FOR_URT_HR(META_E_BADMETADATA) "Merge: Inconsistency in meta data import scope."
+ MSG_FOR_URT_HR(META_E_INTFCEIMPL_NOT_FOUND) "Merge: Class already in emit scope, but interfaceimpl not found."
+ MSG_FOR_URT_HR(TLBX_E_NO_CRITICALHANDLE_ARRAYS) "TypeLib export: Detected array of CriticalHandles."
+ MSG_FOR_URT_HR(META_E_CLASS_LAYOUT_INCONSISTENT) "Merge: Duplicate classes have inconsistent class layout information."
+ MSG_FOR_URT_HR(META_E_FIELD_MARSHAL_NOT_FOUND) "Merge: Field is duplicated but no matching FieldMarshal information."
+ MSG_FOR_URT_HR(META_E_EVENT_NOT_FOUND) "Merge: Method is duplicated but no matching event info."
+ MSG_FOR_URT_HR(META_E_PROP_NOT_FOUND) "Merge: Method is duplicated but no matching property info."
+ MSG_FOR_URT_HR(META_E_BAD_SIGNATURE) "Bad binary signature."
+ MSG_FOR_URT_HR(META_E_BAD_INPUT_PARAMETER) "Bad input parameters."
+ MSG_FOR_URT_HR(META_E_METHDIMPL_INCONSISTENT) "Merge: duplicated methods have inconsistent ImplFlags."
+ MSG_FOR_URT_HR(META_E_MD_INCONSISTENCY) "Merge: Inconsistency in meta data."
+ MSG_FOR_URT_HR(META_E_CANNOTRESOLVETYPEREF) "Cannot resolve typeref."
+ MSG_FOR_URT_HR(META_E_STRINGSPACE_FULL) "No logical space left to create more user strings."
+ MSG_FOR_URT_HR(META_E_UNEXPECTED_REMAP) "Unexpected TokenRemap."
+ MSG_FOR_URT_HR(META_E_HAS_UNMARKALL) "Unmark all has been called already."
+ MSG_FOR_URT_HR(META_E_MUST_CALL_UNMARKALL) "Must call UnmarkAll first before marking."
+ MSG_FOR_URT_HR(META_E_GENERICPARAM_INCONSISTENT) "Merge: duplicated types or methods have inconsistent GenericParams."
+ MSG_FOR_URT_HR(META_E_EVENT_COUNTS) "Merge: different event counts in import and emit scopes."
+ MSG_FOR_URT_HR(META_E_PROPERTY_COUNTS) "Merge: different property counts in import and emit scopes."
+ MSG_FOR_URT_HR(META_E_TYPEDEF_MISSING) "Merge: An input scope has a TypeRef which does not have a matching TypeDef."
+ MSG_FOR_URT_HR(TLBX_E_CANT_LOAD_MODULE) "TypeLib export: cannot open the module to export."
+ MSG_FOR_URT_HR(TLBX_E_CANT_LOAD_CLASS) "TypeLib export: cannot load a class."
+ MSG_FOR_URT_HR(TLBX_E_NULL_MODULE) "TypeLib export: the hModule of a loaded class is 0; cannot export it."
+ MSG_FOR_URT_HR(TLBX_E_NO_CLSID_KEY) "TypeLib export: no CLSID or Interface subkey to HKCR."
+ MSG_FOR_URT_HR(TLBX_E_CIRCULAR_EXPORT) "TypeLib export: attempted to export an Assembly imported from a TLB."
+ MSG_FOR_URT_HR(TLBX_E_CIRCULAR_IMPORT) "TypeLib import: attempted to import a TLB exported from an Assembly."
+ MSG_FOR_URT_HR(TLBX_E_BAD_NATIVETYPE) "TypeLib export: bad Native type in method signature."
+ MSG_FOR_URT_HR(TLBX_E_BAD_VTABLE) "TypeLib import: non-increasing vtable (duplicate slots)."
+ MSG_FOR_URT_HR(TLBX_E_CRM_NON_STATIC) "TypeLib export: the COM register method is non static."
+ MSG_FOR_URT_HR(TLBX_E_CRM_INVALID_SIG) "TypeLib export: the specified COM register method does not have the correct signature."
+ MSG_FOR_URT_HR(TLBX_E_CLASS_LOAD_EXCEPTION) "TypeLib export: cannot load CLR type."
+ MSG_FOR_URT_HR(TLBX_E_UNKNOWN_SIGNATURE) "TypeLib export: unknown element in signature."
+ MSG_FOR_URT_HR(TLBX_E_REFERENCED_TYPELIB) "TypeLib import: reference to an external typelib."
+ MSG_FOR_URT_HR(TLBX_E_INVALID_NAMESPACE) "TypeLib import: an imported typelib has an invalid namespace name."
+ MSG_FOR_URT_HR(TLBX_E_LAYOUT_ERROR) "Typelib export: an error on Layout()"
+ MSG_FOR_URT_HR(TLBX_E_NOTIUNKNOWN) "Typelib import: Interface not derived from IUnknown."
+ MSG_FOR_URT_HR(TLBX_E_NONVISIBLEVALUECLASS) "Typelib export: Non COM visible value type in method signature."
+ MSG_FOR_URT_HR(TLBX_E_LPTSTR_NOT_ALLOWED) "Typelib export: Types which contain the native type NATIVE_TYPE_LPTSTR are not allowed to be exported to COM."
+ MSG_FOR_URT_HR(TLBX_E_AUTO_CS_NOT_ALLOWED) "Typelib export: Types with a charset of auto are not allowed to be exported to COM."
+ MSG_FOR_URT_HR(TLBX_E_ENUM_VALUE_INVALID) "Typelib export: The enum value is not legal for a typelib."
+ MSG_FOR_URT_HR(TLBX_E_DUPLICATE_IID) "Typelib export: Duplicate IID."
+ MSG_FOR_URT_HR(TLBX_E_NO_NESTED_ARRAYS) "Typelib export: detected nested arrays."
+ MSG_FOR_URT_HR(TLBX_E_PARAM_ERROR_NAMED) "Typelib import: parameter type could not be converted."
+ MSG_FOR_URT_HR(TLBX_E_PARAM_ERROR_UNNAMED) "Typelib import: parameter type could not be converted - parameter name unknown."
+ MSG_FOR_URT_HR(TLBX_E_AGNOST_SIGNATURE) "TypeLib export: size agnostic element in signature."
+ MSG_FOR_URT_HR(TLBX_E_CONVERT_FAIL) "TypeLib export: exporter failed."
+ MSG_FOR_URT_HR(TLBX_W_DUAL_NOT_DISPATCH) "Typelib import: [dual] interface not derived from IDispatch."
+ MSG_FOR_URT_HR(TLBX_E_BAD_SIGNATURE) "Typelib export: bad signature."
+ MSG_FOR_URT_HR(TLBX_E_ARRAY_NEEDS_NT_FIXED) "Typelib export: non-fixed or non-safearray array in struct."
+ MSG_FOR_URT_HR(TLBX_E_CLASS_NEEDS_NT_INTF) "Typelib export: non-interface class in struct."
+ MSG_FOR_URT_HR(META_E_CA_INVALID_TARGET) "Known custom attribute on invalid target."
+ MSG_FOR_URT_HR(META_E_CA_INVALID_VALUE) "Known custom attribute had invalid value."
+ MSG_FOR_URT_HR(META_E_CA_INVALID_BLOB) "Known custom attribute blob has bad format."
+ MSG_FOR_URT_HR(META_E_CA_REPEATED_ARG) "Known custom attribute blob has repeated named argument."
+ MSG_FOR_URT_HR(META_E_CA_UNKNOWN_ARGUMENT) "Known custom attribute named argument not recognized."
+ MSG_FOR_URT_HR(META_E_CA_VARIANT_NYI) "Known attribute named argument does not support variant."
+ MSG_FOR_URT_HR(META_E_CA_ARRAY_NYI) "Known attribute named argument does not support array."
+ MSG_FOR_URT_HR(META_E_CA_UNEXPECTED_TYPE) "Known attribute parser found unexpected type."
+ MSG_FOR_URT_HR(META_E_CA_INVALID_ARGTYPE) "Known attribute parser only handles fields, not properties."
+ MSG_FOR_URT_HR(META_E_CA_INVALID_ARG_FOR_TYPE) "Known attribute parser found an argument that is invalid for the object it is applied to."
+ MSG_FOR_URT_HR(META_E_CA_INVALID_UUID) "The format of the UUID was invalid."
+ MSG_FOR_URT_HR(META_E_CA_INVALID_MARSHALAS_FIELDS) "The MarshalAs attribute has fields set that are not valid for the specified unmanaged type."
+ MSG_FOR_URT_HR(META_E_CA_NT_FIELDONLY) "The specified unmanaged type is only valid on fields."
+ MSG_FOR_URT_HR(META_E_CA_NEGATIVE_PARAMINDEX) "The parameter index cannot be negative."
+ MSG_FOR_URT_HR(META_E_CA_NEGATIVE_MULTIPLIER) "The multiplier cannot be negative."
+ MSG_FOR_URT_HR(META_E_CA_NEGATIVE_CONSTSIZE) "The constant size cannot be negative."
+ MSG_FOR_URT_HR(META_E_CA_FIXEDSTR_SIZE_REQUIRED) "A fixed string requires a size."
+ MSG_FOR_URT_HR(META_E_CA_CUSTMARSH_TYPE_REQUIRED) "A custom marshaler requires the custom marshaler type."
+ MSG_FOR_URT_HR(META_E_CA_FILENAME_REQUIRED) "A DllImport attribute requires a filename."
+ MSG_FOR_URT_HR(TLBX_W_NO_PROPS_IN_EVENTS) "TypeLib import: Detected properties in a source dispinterface."
+ MSG_FOR_URT_HR(META_E_NOT_IN_ENC_MODE) "SaveDelta was called without being in EnC mode."
+ MSG_FOR_URT_HR(META_E_METHOD_COUNTS) "Merge: different method counts in import and emit scopes."
+ MSG_FOR_URT_HR(META_E_FIELD_COUNTS) "Merge: different field counts in import and emit scopes."
+ MSG_FOR_URT_HR(META_E_PARAM_COUNTS) "Merge: different parameter counts in import and emit scopes."
+ MSG_FOR_URT_HR(TLBX_E_TYPED_REF) "TypeLib export: Exporting a TypedReference."
+ MSG_FOR_URT_HR(TLBX_E_BITNESS_MISMATCH) "TypeLib export: bitness of assembly does not match bitness of output type library."
+ MSG_FOR_URT_HR(META_E_CA_BAD_FRIENDS_ARGS) "InternalsVisibleTo can't have a version, culture, or processor architecture."
+ MSG_FOR_URT_HR(VLDTR_E_RID_OUTOFRANGE) "Rid is out of range."
+ MSG_FOR_URT_HR(VLDTR_E_CDTKN_OUTOFRANGE) "Coded token type is out of range."
+ MSG_FOR_URT_HR(VLDTR_E_CDRID_OUTOFRANGE) "Coded rid is out of range."
+ MSG_FOR_URT_HR(VLDTR_E_STRING_INVALID) "String offset is invalid."
+ MSG_FOR_URT_HR(VLDTR_E_GUID_INVALID) "GUID offset is invalid."
+ MSG_FOR_URT_HR(VLDTR_E_BLOB_INVALID) "Blob offset if invalid."
+ MSG_FOR_URT_HR(VLDTR_E_MOD_MULTI) "Multiple module records found."
+ MSG_FOR_URT_HR(VLDTR_E_MOD_NULLMVID) "Module has null MVID."
+ MSG_FOR_URT_HR(VLDTR_E_TR_NAMENULL) "TypeRef name is NULL."
+ MSG_FOR_URT_HR(VLDTR_E_TR_DUP) "TypeRef has a duplicate."
+ MSG_FOR_URT_HR(VLDTR_E_TD_NAMENULL) "TypeDef name is NULL."
+ MSG_FOR_URT_HR(VLDTR_E_TD_DUPNAME) "TypeDef has a duplicate based on name+namespace."
+ MSG_FOR_URT_HR(VLDTR_E_TD_DUPGUID) "TypeDef has a duplicate based on GUID."
+ MSG_FOR_URT_HR(VLDTR_E_TD_NOTIFACEOBJEXTNULL) "TypeDef that is not an Interface and not System.Object extends nil parent."
+ MSG_FOR_URT_HR(VLDTR_E_TD_OBJEXTENDSNONNULL) "System.Object extends a non-nil parent."
+ MSG_FOR_URT_HR(VLDTR_E_TD_EXTENDSSEALED) "TypeDef extends sealed class."
+ MSG_FOR_URT_HR(VLDTR_E_TD_DLTNORTSPCL) "TypeDef is Deleted but not marked with RTSpecialName."
+ MSG_FOR_URT_HR(VLDTR_E_TD_RTSPCLNOTDLT) "TypeDef is marked RTSpecialName, but is not a Deleted record."
+ MSG_FOR_URT_HR(VLDTR_E_MI_DECLPRIV) "MethodImpl's Decl is private."
+ MSG_FOR_URT_HR(VLDTR_E_AS_BADNAME) "Assembly [Ref] name has path and/or extension."
+ MSG_FOR_URT_HR(VLDTR_E_FILE_SYSNAME) "File has a system name (con, com, aux, etc.)."
+ MSG_FOR_URT_HR(VLDTR_E_MI_BODYSTATIC) "MethodImpl's body is static."
+ MSG_FOR_URT_HR(VLDTR_E_TD_IFACENOTABS) "TypeDef is marked Interface but not Abstract."
+ MSG_FOR_URT_HR(VLDTR_E_TD_IFACEPARNOTNIL) "TypeDef is marked Interface but parent is not Nil."
+ MSG_FOR_URT_HR(VLDTR_E_TD_IFACEGUIDNULL) "TypeDef is marked Interface but GUID is NULL."
+ MSG_FOR_URT_HR(VLDTR_E_MI_DECLFINAL) "TMethodImpl's Decl is final."
+ MSG_FOR_URT_HR(VLDTR_E_TD_VTNOTSEAL) "TypeDef is marked ValueType but not marked Sealed."
+ MSG_FOR_URT_HR(VLDTR_E_PD_BADFLAGS) "Parameter has extra bits in flags."
+ MSG_FOR_URT_HR(VLDTR_E_IFACE_DUP) "InterfaceImpl has a duplicate."
+ MSG_FOR_URT_HR(VLDTR_E_MR_NAMENULL) "MemberRef name is NULL."
+ MSG_FOR_URT_HR(VLDTR_E_MR_VTBLNAME) "MemberRef has an invalid name, _VtblGap*."
+ MSG_FOR_URT_HR(VLDTR_E_MR_DELNAME) "MemberRef has an invalid name, _Deleted*."
+ MSG_FOR_URT_HR(VLDTR_E_MR_PARNIL) "MemberRef parent Nil in a PE file."
+ MSG_FOR_URT_HR(VLDTR_E_MR_BADCALLINGCONV) "MemberRef has invalid calling convention."
+ MSG_FOR_URT_HR(VLDTR_E_MR_NOTVARARG) "MemberRef has Method parent but calling convention is not VARARG."
+ MSG_FOR_URT_HR(VLDTR_E_MR_NAMEDIFF) "MemberRef name different from parent MethodDef."
+ MSG_FOR_URT_HR(VLDTR_E_MR_SIGDIFF) "MemberRef signature different from parent MethodDef."
+ MSG_FOR_URT_HR(VLDTR_E_MR_DUP) "MemberRef has a duplicate."
+ MSG_FOR_URT_HR(VLDTR_E_CL_TDAUTO) "ClassLayout parent TypeDef is marked AutoLayout."
+ MSG_FOR_URT_HR(VLDTR_E_CL_BADPCKSZ) "ClassLayout has bad PackingSize."
+ MSG_FOR_URT_HR(VLDTR_E_CL_DUP) "ClassLayout has a duplicate."
+ MSG_FOR_URT_HR(VLDTR_E_FL_BADOFFSET) "FieldLayout2 has bad offset."
+ MSG_FOR_URT_HR(VLDTR_E_FL_TDNIL) "FieldLayout2 has field with nil parent."
+ MSG_FOR_URT_HR(VLDTR_E_FL_NOCL) "FieldLayout2 has no ClassLayout record."
+ MSG_FOR_URT_HR(VLDTR_E_FL_TDNOTEXPLCT) "FieldLayout2 parent TypeDef is not marked with ExplicitLayout."
+ MSG_FOR_URT_HR(VLDTR_E_FL_FLDSTATIC) "FieldLayout2 has field marked Static."
+ MSG_FOR_URT_HR(VLDTR_E_FL_DUP) "FieldLayout2 has a duplicate."
+ MSG_FOR_URT_HR(VLDTR_E_MODREF_NAMENULL) "ModuleRef name is NULL."
+ MSG_FOR_URT_HR(VLDTR_E_MODREF_DUP) "ModuleRef has a duplicate."
+ MSG_FOR_URT_HR(VLDTR_E_TR_BADSCOPE) "TypeRef has a bad resolution scope."
+ MSG_FOR_URT_HR(VLDTR_E_TD_NESTEDNOENCL) "TypeDef marked nested has no encloser."
+ MSG_FOR_URT_HR(VLDTR_E_TD_EXTTRRES) "TypeDef extends a TypeRef which resolves to a TypeDef in the same module."
+ MSG_FOR_URT_HR(VLDTR_E_SIGNULL) "Signature specified is zero-sized."
+ MSG_FOR_URT_HR(VLDTR_E_SIGNODATA) "Signature does not have enough data at specified byte."
+ MSG_FOR_URT_HR(VLDTR_E_MD_BADCALLINGCONV) "Method signature has invalid calling convention."
+ MSG_FOR_URT_HR(VLDTR_E_MD_THISSTATIC) "Method is marked static but has HASTHIS/EXPLICITTHIS set on the calling convention."
+ MSG_FOR_URT_HR(VLDTR_E_MD_NOTTHISNOTSTATIC) "Method is not marked static but is not HASTHIS or EXPLICITTHIS."
+ MSG_FOR_URT_HR(VLDTR_E_MD_NOARGCNT) "Method signature is missing the argument count."
+ MSG_FOR_URT_HR(VLDTR_E_SIG_MISSELTYPE) "Signature missing element type."
+ MSG_FOR_URT_HR(VLDTR_E_SIG_MISSTKN) "Signature missing token."
+ MSG_FOR_URT_HR(VLDTR_E_SIG_TKNBAD) "Signature has bad token."
+ MSG_FOR_URT_HR(VLDTR_E_SIG_MISSFPTR) "Signature is missing function pointer."
+ MSG_FOR_URT_HR(VLDTR_E_SIG_MISSFPTRARGCNT) "Signature has function pointer missing argument count."
+ MSG_FOR_URT_HR(VLDTR_E_SIG_MISSRANK) "Signature is missing rank specification."
+ MSG_FOR_URT_HR(VLDTR_E_SIG_MISSNSIZE) "Signature is missing count of sized dimensions."
+ MSG_FOR_URT_HR(VLDTR_E_SIG_MISSSIZE) "Signature is missing size of dimension."
+ MSG_FOR_URT_HR(VLDTR_E_SIG_MISSNLBND) "Signature is missing count of lower bounds."
+ MSG_FOR_URT_HR(VLDTR_E_SIG_MISSLBND) "Signature is missing a lower bound."
+ MSG_FOR_URT_HR(VLDTR_E_SIG_BADELTYPE) "Signature has bad element type."
+ MSG_FOR_URT_HR(VLDTR_E_SIG_MISSVASIZE) "Signature has value array missing size."
+ MSG_FOR_URT_HR(VLDTR_E_FD_BADCALLINGCONV) "Field signature has invalid calling convention."
+ MSG_FOR_URT_HR(VLDTR_E_MD_NAMENULL) "Method name is NULL."
+ MSG_FOR_URT_HR(VLDTR_E_MD_PARNIL) "Method has parent NIL."
+ MSG_FOR_URT_HR(VLDTR_E_MD_DUP) "Method has a duplicate."
+ MSG_FOR_URT_HR(VLDTR_E_FD_NAMENULL) "Field name is NULL."
+ MSG_FOR_URT_HR(VLDTR_E_FD_PARNIL) "Field parent is Nil."
+ MSG_FOR_URT_HR(VLDTR_E_FD_DUP) "Field has a duplicate."
+ MSG_FOR_URT_HR(VLDTR_E_AS_MULTI) "Multiple Assembly records found."
+ MSG_FOR_URT_HR(VLDTR_E_AS_NAMENULL) "Assembly name is NULL."
+ MSG_FOR_URT_HR(VLDTR_E_SIG_TOKTYPEMISMATCH) "E_T_VALUETYPE<class token> or E_T_CLASS<vtype token>."
+ MSG_FOR_URT_HR(VLDTR_E_CL_TDINTF) "Class layout on an Interface."
+ MSG_FOR_URT_HR(VLDTR_E_ASOS_OSPLTFRMIDINVAL) "AssemblyOS platform ID invalid."
+ MSG_FOR_URT_HR(VLDTR_E_AR_NAMENULL) "AssemblyRef name is NULL."
+ MSG_FOR_URT_HR(VLDTR_E_TD_ENCLNOTNESTED) "TypeDef not nested has encloser."
+ MSG_FOR_URT_HR(VLDTR_E_AROS_OSPLTFRMIDINVAL) "AssemblyRefOS has invalid platform ID."
+ MSG_FOR_URT_HR(VLDTR_E_FILE_NAMENULL) "File name is NULL."
+ MSG_FOR_URT_HR(VLDTR_E_CT_NAMENULL) "ExportedType name is NULL."
+ MSG_FOR_URT_HR(VLDTR_E_TD_EXTENDSCHILD) "TypeDef extends its own child."
+ MSG_FOR_URT_HR(VLDTR_E_MAR_NAMENULL) "ManifestResource name is NULL."
+ MSG_FOR_URT_HR(VLDTR_E_FILE_DUP) "File has a duplicate."
+ MSG_FOR_URT_HR(VLDTR_E_FILE_NAMEFULLQLFD) "File name is fully qualified."
+ MSG_FOR_URT_HR(VLDTR_E_CT_DUP) "ExportedType has a duplicate."
+ MSG_FOR_URT_HR(VLDTR_E_MAR_DUP) "ManifestResource has a duplicate."
+ MSG_FOR_URT_HR(VLDTR_E_MAR_NOTPUBPRIV) "ManifestResource is neither Public nor Private."
+ MSG_FOR_URT_HR(VLDTR_E_TD_ENUMNOVALUE) "Enum has no value__ field."
+ MSG_FOR_URT_HR(VLDTR_E_TD_ENUMVALSTATIC) "Enum's value__ field is static."
+ MSG_FOR_URT_HR(VLDTR_E_TD_ENUMVALNOTSN) "Enum's value__ field is not SpecialName."
+ MSG_FOR_URT_HR(VLDTR_E_TD_ENUMFLDNOTST) "Enum's field is not static."
+ MSG_FOR_URT_HR(VLDTR_E_TD_ENUMFLDNOTLIT) "Enum's field is not literal."
+ MSG_FOR_URT_HR(VLDTR_E_TD_ENUMNOLITFLDS) "Enum has no literal fields."
+ MSG_FOR_URT_HR(VLDTR_E_TD_ENUMFLDSIGMISMATCH) "Enum's field signature does not match value__ signature."
+ MSG_FOR_URT_HR(VLDTR_E_TD_ENUMVALNOT1ST) "Enum's value__ field is not first."
+ MSG_FOR_URT_HR(VLDTR_E_FD_NOTVALUERTSN) "Field is RTSpecialName but name is not value__."
+ MSG_FOR_URT_HR(VLDTR_E_FD_VALUEPARNOTENUM) "Field value__ in not Enum class."
+ MSG_FOR_URT_HR(VLDTR_E_FD_INSTINIFACE) "Instance field in interface."
+ MSG_FOR_URT_HR(VLDTR_E_FD_NOTPUBINIFACE) "Non-public field in interface."
+ MSG_FOR_URT_HR(VLDTR_E_FMD_GLOBALNOTPUBPRIVSC) "Global field or method is neither Public nor PrivateScope."
+ MSG_FOR_URT_HR(VLDTR_E_FMD_GLOBALNOTSTATIC) "Global field or method is not static."
+ MSG_FOR_URT_HR(VLDTR_E_FD_GLOBALNORVA) "Global field has no RVA."
+ MSG_FOR_URT_HR(VLDTR_E_MD_CTORZERORVA) ".ctor or .cctor has zero RVA."
+ MSG_FOR_URT_HR(VLDTR_E_FD_MARKEDNOMARSHAL) "Field is marked marshaled but has no marshaling record."
+ MSG_FOR_URT_HR(VLDTR_E_FD_MARSHALNOTMARKED) "Field has marshaling record but is not marked marshaled."
+ MSG_FOR_URT_HR(VLDTR_E_FD_MARKEDNODEFLT) "Field is marked HasDefault but has no const value."
+ MSG_FOR_URT_HR(VLDTR_E_FD_DEFLTNOTMARKED) "Field has const value record but is not marked HasDefault."
+ MSG_FOR_URT_HR(VLDTR_E_FMD_MARKEDNOSECUR) "Field or method is marked HasSecurity but has no security record."
+ MSG_FOR_URT_HR(VLDTR_E_FMD_SECURNOTMARKED) "Field or method has security record but is not marked HasSecurity."
+ MSG_FOR_URT_HR(VLDTR_E_FMD_PINVOKENOTSTATIC) "Field or method is PInvoke but is not marked Static."
+ MSG_FOR_URT_HR(VLDTR_E_FMD_MARKEDNOPINVOKE) "Field or method is marked PInvoke but has no ImplMap."
+ MSG_FOR_URT_HR(VLDTR_E_FMD_PINVOKENOTMARKED) "Field or method has ImplMap but is not marked PInvoke."
+ MSG_FOR_URT_HR(VLDTR_E_FMD_BADIMPLMAP) "Field or method has invalid ImplMap."
+ MSG_FOR_URT_HR(VLDTR_E_IMAP_BADMODREF) "ImplMap has invalid ModuleRef."
+ MSG_FOR_URT_HR(VLDTR_E_IMAP_BADMEMBER) "ImplMap has invalid MemberForwarded."
+ MSG_FOR_URT_HR(VLDTR_E_IMAP_BADIMPORTNAME) "ImplMap has invalid ImportName."
+ MSG_FOR_URT_HR(VLDTR_E_IMAP_BADCALLCONV) "ImplMap has invalid call conv."
+ MSG_FOR_URT_HR(VLDTR_E_FMD_BADACCESSFLAG) "Field or method has invalid access flag."
+ MSG_FOR_URT_HR(VLDTR_E_FD_INITONLYANDLITERAL) "Field is InitOnly and Literal."
+ MSG_FOR_URT_HR(VLDTR_E_FD_LITERALNOTSTATIC) "Field is Literal but not Static."
+ MSG_FOR_URT_HR(VLDTR_E_FMD_RTSNNOTSN) "Field or method is RTSpec.Name but not Spec.Name."
+ MSG_FOR_URT_HR(VLDTR_E_MD_ABSTPARNOTABST) "Method is abstract, parent is not."
+ MSG_FOR_URT_HR(VLDTR_E_MD_NOTSTATABSTININTF) "Method not static or abstract in interface."
+ MSG_FOR_URT_HR(VLDTR_E_MD_NOTPUBININTF) "Method not public in interface."
+ MSG_FOR_URT_HR(VLDTR_E_MD_CTORININTF) ".ctor in interface."
+ MSG_FOR_URT_HR(VLDTR_E_MD_GLOBALCTORCCTOR) "global .ctor or .cctor."
+ MSG_FOR_URT_HR(VLDTR_E_MD_CTORSTATIC) "static .ctor."
+ MSG_FOR_URT_HR(VLDTR_E_MD_CTORNOTSNRTSN) ".ctor or .cctor not marked SpecialName or RTSpecialName."
+ MSG_FOR_URT_HR(VLDTR_E_MD_CTORVIRT) "virtual .ctor or .cctor."
+ MSG_FOR_URT_HR(VLDTR_E_MD_CTORABST) "abstract .ctor or .cctor."
+ MSG_FOR_URT_HR(VLDTR_E_MD_CCTORNOTSTATIC) "instance .cctor."
+ MSG_FOR_URT_HR(VLDTR_E_MD_ZERORVA) "RVA set to zero, but method not abstract or pinvoke or runtime, or reverse."
+ MSG_FOR_URT_HR(VLDTR_E_MD_FINNOTVIRT) "Method is final and not virtual."
+ MSG_FOR_URT_HR(VLDTR_E_MD_STATANDFINORVIRT) "Method is static and final or virtual."
+ MSG_FOR_URT_HR(VLDTR_E_MD_ABSTANDFINAL) "Method is abstract and final."
+ MSG_FOR_URT_HR(VLDTR_E_MD_ABSTANDIMPL) "Method is abstract and implemented."
+ MSG_FOR_URT_HR(VLDTR_E_MD_ABSTANDPINVOKE) "Method is abstract and pinvoke."
+ MSG_FOR_URT_HR(VLDTR_E_MD_ABSTNOTVIRT) "Method is abstract and not virtual."
+ MSG_FOR_URT_HR(VLDTR_E_MD_NOTABSTNOTIMPL) "Method is not abstract and not implemented."
+ MSG_FOR_URT_HR(VLDTR_E_MD_NOTABSTBADFLAGSRVA) "Method is not abstract and not (non-zero RVA or PInvoke or runtime)."
+ MSG_FOR_URT_HR(VLDTR_E_MD_PRIVSCOPENORVA) "Method is PrivateScope and has RVA set to zero."
+ MSG_FOR_URT_HR(VLDTR_E_MD_GLOBALABSTORVIRT) "Global method is abstract or virtual."
+ MSG_FOR_URT_HR(VLDTR_E_SIG_LONGFORM) "Signature uses long form."
+ MSG_FOR_URT_HR(VLDTR_E_MD_MULTIPLESEMANTICS) "Method has multiple semantics (warning)."
+ MSG_FOR_URT_HR(VLDTR_E_MD_INVALIDSEMANTICS) "Method has invalid semantics (not event or property.)"
+ MSG_FOR_URT_HR(VLDTR_E_MD_SEMANTICSNOTEXIST) "Method has semantics association that does not exist."
+ MSG_FOR_URT_HR(VLDTR_E_MI_DECLNOTVIRT) "MethodImpl's Decl is not virtual."
+ MSG_FOR_URT_HR(VLDTR_E_FMD_GLOBALITEM) "Global field or method (warning, CLS)."
+ MSG_FOR_URT_HR(VLDTR_E_MD_MULTSEMANTICFLAGS) "Method has multiple semantic flags set."
+ MSG_FOR_URT_HR(VLDTR_E_MD_NOSEMANTICFLAGS) "Method has no semantic flags set."
+ MSG_FOR_URT_HR(VLDTR_E_FD_FLDINIFACE) "Field in Interface (warning, CLS)."
+ MSG_FOR_URT_HR(VLDTR_E_AS_HASHALGID) "Unrecognized Hash Alg ID (warning)."
+ MSG_FOR_URT_HR(VLDTR_E_AS_PROCID) "Unrecognized Processor ID in Assembly(warning)."
+ MSG_FOR_URT_HR(VLDTR_E_AR_PROCID) "Unrecognized Processor ID in AssemblyRef(warning)."
+ MSG_FOR_URT_HR(VLDTR_E_CN_PARENTRANGE) "Constant: parent token out of range."
+ MSG_FOR_URT_HR(VLDTR_E_AS_BADFLAGS) "Invalid flags in Assembly."
+ MSG_FOR_URT_HR(VLDTR_E_TR_HASTYPEDEF) "There is TypeDef with same name as TypeRef (warning)."
+ MSG_FOR_URT_HR(VLDTR_E_IFACE_BADIMPL) "In InterfaceImpl, the implementing token is not TypeDef."
+ MSG_FOR_URT_HR(VLDTR_E_IFACE_BADIFACE) "In InterfaceImpl, the implemented token is not TypeDef or TypeRef."
+ MSG_FOR_URT_HR(VLDTR_E_TD_SECURNOTMARKED) "TypeDef has security record but it is not marked HasSecurity."
+ MSG_FOR_URT_HR(VLDTR_E_TD_MARKEDNOSECUR) "TypeDef marked HasSecurity but has no security record."
+ MSG_FOR_URT_HR(VLDTR_E_MD_CCTORHASARGS) ".cctor has arguments."
+ MSG_FOR_URT_HR(VLDTR_E_CT_BADIMPL) "ExportedType has invalid Implementation."
+ MSG_FOR_URT_HR(VLDTR_E_MI_ALIENBODY) "MethodImpl has body from other class."
+ MSG_FOR_URT_HR(VLDTR_E_MD_CCTORCALLCONV) ".cctor has invalid calling convention."
+ MSG_FOR_URT_HR(VLDTR_E_MI_BADCLASS) "MethodImpl has invalid Class token."
+ MSG_FOR_URT_HR(VLDTR_E_MI_CLASSISINTF) "MethodImpl declared in Interface."
+ MSG_FOR_URT_HR(VLDTR_E_MI_BADDECL) "MethodImpl has invalid MethodDeclaration token."
+ MSG_FOR_URT_HR(VLDTR_E_MI_BADBODY) "MethodImpl has invalid MethodBody token."
+ MSG_FOR_URT_HR(VLDTR_E_MI_DUP) "MethodImpl has duplicate."
+ MSG_FOR_URT_HR(VLDTR_E_FD_BADPARENT) "Bad field parent."
+ MSG_FOR_URT_HR(VLDTR_E_MD_PARAMOUTOFSEQ) "Parameter out of sequence (warning)."
+ MSG_FOR_URT_HR(VLDTR_E_MD_PARASEQTOOBIG) "Parameter's sequence number exceeds number of arguments."
+ MSG_FOR_URT_HR(VLDTR_E_MD_PARMMARKEDNOMARSHAL) "Parameter marked HasMarshal, has no marshaling info."
+ MSG_FOR_URT_HR(VLDTR_E_MD_PARMMARSHALNOTMARKED) "Parameter has marshaling info, not marked HasMarshal."
+ MSG_FOR_URT_HR(VLDTR_E_MD_PARMMARKEDNODEFLT) "Parameter marked HasDefault, has no const value."
+ MSG_FOR_URT_HR(VLDTR_E_MD_PARMDEFLTNOTMARKED) "Parameter has const value, not marked HasDefault."
+ MSG_FOR_URT_HR(VLDTR_E_PR_BADSCOPE) "Property has invalid scope."
+ MSG_FOR_URT_HR(VLDTR_E_PR_NONAME) "Property has no name."
+ MSG_FOR_URT_HR(VLDTR_E_PR_NOSIG) "Property has no signature."
+ MSG_FOR_URT_HR(VLDTR_E_PR_DUP) "Property has a duplicate."
+ MSG_FOR_URT_HR(VLDTR_E_PR_BADCALLINGCONV) "Property has bad calling convention."
+ MSG_FOR_URT_HR(VLDTR_E_PR_MARKEDNODEFLT) "Property marked HasDefault, has no const value."
+ MSG_FOR_URT_HR(VLDTR_E_PR_DEFLTNOTMARKED) "Property has const value, not marked HasDefault."
+ MSG_FOR_URT_HR(VLDTR_E_PR_BADSEMANTICS) "Property has method that is neither a Setter nor a Getter."
+ MSG_FOR_URT_HR(VLDTR_E_PR_BADMETHOD) "Property has method with invalid token."
+ MSG_FOR_URT_HR(VLDTR_E_PR_ALIENMETHOD) "Property has method from another class."
+ MSG_FOR_URT_HR(VLDTR_E_CN_BLOBNOTNULL) "Const has non-null blob when it should not."
+ MSG_FOR_URT_HR(VLDTR_E_CN_BLOBNULL) "Const has null value blob."
+ MSG_FOR_URT_HR(VLDTR_E_EV_BADSCOPE) "Event has invalid scope."
+ MSG_FOR_URT_HR(VLDTR_E_EV_NONAME) "Event has no name."
+ MSG_FOR_URT_HR(VLDTR_E_EV_DUP) "Event has a duplicate."
+ MSG_FOR_URT_HR(VLDTR_E_EV_BADEVTYPE) "Event has invalid EventType."
+ MSG_FOR_URT_HR(VLDTR_E_EV_EVTYPENOTCLASS) "Event's EventType is not a class."
+ MSG_FOR_URT_HR(VLDTR_E_EV_BADSEMANTICS) "Event has method not (AddOn,RemoveOn,Fire,Other)."
+ MSG_FOR_URT_HR(VLDTR_E_EV_BADMETHOD) "Event has method with invalid token."
+ MSG_FOR_URT_HR(VLDTR_E_EV_ALIENMETHOD) "Event has method from another class."
+ MSG_FOR_URT_HR(VLDTR_E_EV_NOADDON) "Event has no AddOn method."
+ MSG_FOR_URT_HR(VLDTR_E_EV_NOREMOVEON) "Event has no RemoveOn method."
+ MSG_FOR_URT_HR(VLDTR_E_CT_DUPTDNAME) "ExportedType has same name as TypeDef."
+ MSG_FOR_URT_HR(VLDTR_E_MAR_BADOFFSET) "MRes refers to non-PE file with non-zero offset."
+ MSG_FOR_URT_HR(VLDTR_E_DS_BADOWNER) "Declarative security has invalid owner token."
+ MSG_FOR_URT_HR(VLDTR_E_DS_BADFLAGS) "Declarative security has invalid action flags."
+ MSG_FOR_URT_HR(VLDTR_E_DS_NOBLOB) "Declarative security has no permission blob."
+ MSG_FOR_URT_HR(VLDTR_E_MAR_BADIMPL) "Manifest resource has invalid Implementation."
+ MSG_FOR_URT_HR(VLDTR_E_MR_VARARGCALLINGCONV) "MemberRef has VARARG calling conv. (CLS warning)."
+ MSG_FOR_URT_HR(VLDTR_E_MD_CTORNOTVOID) ".ctor or .cctor returns something other than void."
+ MSG_FOR_URT_HR(VLDTR_E_EV_FIRENOTVOID) "Fire method returns something other than void."
+ MSG_FOR_URT_HR(VLDTR_E_AS_BADLOCALE) "Invalid locale."
+ MSG_FOR_URT_HR(VLDTR_E_CN_PARENTTYPE) "Constant has parent of invalid type."
+ MSG_FOR_URT_HR(VLDTR_E_SIG_SENTINMETHODDEF) "E_T_SENTINEL in MethodDef signature."
+ MSG_FOR_URT_HR(VLDTR_E_SIG_SENTMUSTVARARG) "E_T_SENTINEL <=> VARARG."
+ MSG_FOR_URT_HR(VLDTR_E_SIG_MULTSENTINELS) "Multiple E_T_SENTINELs."
+ MSG_FOR_URT_HR(VLDTR_E_SIG_LASTSENTINEL) "E_T_SENTINEL not followed by type."
+ MSG_FOR_URT_HR(VLDTR_E_SIG_MISSARG) "Signature missing argument."
+ MSG_FOR_URT_HR(VLDTR_E_SIG_BYREFINFIELD) "Field of ByRef type."
+ MSG_FOR_URT_HR(VLDTR_E_MD_SYNCMETHODINVTYPE) "Synchronized method in value class."
+ MSG_FOR_URT_HR(VLDTR_E_TD_NAMETOOLONG) "TypeDef name too long."
+ MSG_FOR_URT_HR(VLDTR_E_AS_PROCDUP) "Duplicate Assembly Processor."
+ MSG_FOR_URT_HR(VLDTR_E_ASOS_DUP) "Duplicate Assembly OS (ID+ver.major+ver.minor)."
+ MSG_FOR_URT_HR(VLDTR_E_MAR_BADFLAGS) "Manifest Resource has bad flags."
+ MSG_FOR_URT_HR(VLDTR_E_CT_NOTYPEDEFID) "ExportedType has nil TypeDefId."
+ MSG_FOR_URT_HR(VLDTR_E_FILE_BADFLAGS) "File has bad flags."
+ MSG_FOR_URT_HR(VLDTR_E_FILE_NULLHASH) "File has no hash blob."
+ MSG_FOR_URT_HR(VLDTR_E_MOD_NONAME) "Module has no name."
+ MSG_FOR_URT_HR(VLDTR_E_MOD_NAMEFULLQLFD) "Module has fully-qualified name."
+ MSG_FOR_URT_HR(VLDTR_E_TD_RTSPCLNOTSPCL) "TypeDef is tdRTSpecialName but not tdSpecialName."
+ MSG_FOR_URT_HR(VLDTR_E_TD_EXTENDSIFACE) "TypeDef extends interface."
+ MSG_FOR_URT_HR(VLDTR_E_MD_CTORPINVOKE) ".ctor or .cctor is PInvokeImpl."
+ MSG_FOR_URT_HR(VLDTR_E_TD_SYSENUMNOTCLASS) "System.Enum is not a class."
+ MSG_FOR_URT_HR(VLDTR_E_TD_SYSENUMNOTEXTVTYPE) "System.Enum extends not System.ValueType."
+ MSG_FOR_URT_HR(VLDTR_E_MI_SIGMISMATCH) "MethodImpl's Decl and Body signatures mismatch."
+ MSG_FOR_URT_HR(VLDTR_E_TD_ENUMHASMETHODS) "TypeDef extends System.Enum but has methods."
+ MSG_FOR_URT_HR(VLDTR_E_TD_ENUMIMPLIFACE) "TypeDef extends System.Enum but implements an interface."
+ MSG_FOR_URT_HR(VLDTR_E_TD_ENUMHASPROP) "TypeDef extends System.Enum but has a property."
+ MSG_FOR_URT_HR(VLDTR_E_TD_ENUMHASEVENT) "TypeDef extends System.Enum but has an event."
+ MSG_FOR_URT_HR(VLDTR_E_TD_BADMETHODLST) "TypeDef has MethodList > Nmethods+1."
+ MSG_FOR_URT_HR(VLDTR_E_TD_BADFIELDLST) "TypeDef has FieldList > Nfields+1."
+ MSG_FOR_URT_HR(VLDTR_E_CN_BADTYPE) "Constant has wrong type."
+ MSG_FOR_URT_HR(VLDTR_E_TD_ENUMNOINSTFLD) "Enum has no instance fields."
+ MSG_FOR_URT_HR(VLDTR_E_TD_ENUMMULINSTFLD) "Enum has multiple instance fields."
+ MSG_FOR_URT_HR(VLDTR_E_INTERRUPTED) "Validator has been interrupted by the VEHandler."
+ MSG_FOR_URT_HR(VLDTR_E_NOTINIT) "Validator failed to initialize correctly."
+ MSG_FOR_URT_HR(CORDBG_E_UNRECOVERABLE_ERROR) "Unrecoverable API error."
+ MSG_FOR_URT_HR(CORDBG_E_PROCESS_TERMINATED) "Process was terminated."
+ MSG_FOR_URT_HR(CORDBG_E_PROCESS_NOT_SYNCHRONIZED) "Process not synchronized."
+ MSG_FOR_URT_HR(CORDBG_E_CLASS_NOT_LOADED) "A class is not loaded."
+ MSG_FOR_URT_HR(CORDBG_E_IL_VAR_NOT_AVAILABLE) "An IL variable is not available at the current native IP."
+ MSG_FOR_URT_HR(CORDBG_E_BAD_REFERENCE_VALUE) "A reference value was found to be bad during dereferencing."
+ MSG_FOR_URT_HR(CORDBG_E_FIELD_NOT_AVAILABLE) "A field in a class is not available, because the runtime optimized it away."
+ MSG_FOR_URT_HR(CORDBG_E_NON_NATIVE_FRAME) "'Native-frame-only' operation on non-native frame."
+ MSG_FOR_URT_HR(CORDBG_E_NONCONTINUABLE_EXCEPTION) "Cannot Continue on non-continuable exception."
+ MSG_FOR_URT_HR(CORDBG_E_CODE_NOT_AVAILABLE) "The code is currently unavailable."
+ MSG_FOR_URT_HR(CORDBG_E_FUNCTION_NOT_IL) "Attempt to get a ICorDebugFunction for a function that is not IL."
+ MSG_FOR_URT_HR(CORDBG_E_CANT_SET_IP_INTO_FINALLY) "SetIP is not possible because SetIP would move EIP from outside of an exception handling finally clause to a point inside of one."
+ MSG_FOR_URT_HR(CORDBG_E_CANT_SET_IP_OUT_OF_FINALLY) "SetIP is not possible because it would move EIP from within an exception handling finally clause to a point outside of one."
+ MSG_FOR_URT_HR(CORDBG_E_CANT_SET_IP_INTO_CATCH) "SetIP is not possible, because SetIP would move EIP from outside of an exception handling catch clause to a point inside of one."
+ MSG_FOR_URT_HR(CORDBG_E_SET_IP_NOT_ALLOWED_ON_NONLEAF_FRAME) "SetIP cannot be done on any frame except the leaf frame."
+ MSG_FOR_URT_HR(CORDBG_E_SET_IP_IMPOSSIBLE) "SetIP is not allowed."
+ MSG_FOR_URT_HR(CORDBG_E_FUNC_EVAL_BAD_START_POINT) "Func eval cannot work. Bad starting point."
+ MSG_FOR_URT_HR(CORDBG_E_INVALID_OBJECT) "This object value is no longer valid."
+ MSG_FOR_URT_HR(CORDBG_E_FUNC_EVAL_NOT_COMPLETE) "CordbEval::GetResult called before func eval has finished."
+ MSG_FOR_URT_HR(CORDBG_E_INPROC_NOT_IMPL) "The in-process version of the debugging API does not support this function."
+ MSG_FOR_URT_HR(CORDBG_E_STATIC_VAR_NOT_AVAILABLE) "A static variable is not available because it has not been initialized yet."
+ MSG_FOR_URT_HR(CORDBG_E_OBJECT_IS_NOT_COPYABLE_VALUE_CLASS) "Cannot copy a VC with object refs in it."
+ MSG_FOR_URT_HR(CORDBG_E_CANT_SETIP_INTO_OR_OUT_OF_FILTER) "SetIP cannot leave or enter a filter."
+ MSG_FOR_URT_HR(CORDBG_E_CANT_CHANGE_JIT_SETTING_FOR_ZAP_MODULE) "JIT settings for ZAP modules cannot be changed."
+ MSG_FOR_URT_HR(CORDBG_E_CANT_SET_IP_OUT_OF_FINALLY_ON_WIN64) "SetIP is not possible because it would move EIP from within a finally clause to a point outside of one on WIN64 platforms."
+ MSG_FOR_URT_HR(CORDBG_E_CANT_SET_IP_OUT_OF_CATCH_ON_WIN64) "SetIP is not possible because it would move EIP from within a catch clause to a point outside of one on WIN64 platforms."
+ MSG_FOR_URT_HR(CORDBG_E_REMOTE_CONNECTION_CONN_RESET) "The remote device closed the connection."
+ MSG_FOR_URT_HR(CORDBG_E_REMOTE_CONNECTION_KEEP_ALIVE) "The connection was closed due to a keep-alive failure."
+ MSG_FOR_URT_HR(CORDBG_E_REMOTE_CONNECTION_FATAL_ERROR) "Generic error that the device connection has been broken with no chance for recovery."
+ MSG_FOR_URT_HR(CORDBG_E_CANT_SET_TO_JMC) "Cannot use JMC on this code (likely wrong JIT settings)."
+ MSG_FOR_URT_HR(CORDBG_E_NO_CONTEXT_FOR_INTERNAL_FRAME) "Internal frame markers have no associated context."
+ MSG_FOR_URT_HR(CORDBG_E_NOT_CHILD_FRAME) "The current frame is not a child frame."
+ MSG_FOR_URT_HR(CORDBG_E_NON_MATCHING_CONTEXT) "The provided CONTEXT does not match the specified thread."
+ MSG_FOR_URT_HR(CORDBG_E_PAST_END_OF_STACK) "The stackwalker is now past the end of stack. No information is available."
+ MSG_FOR_URT_HR(CORDBG_E_FUNC_EVAL_CANNOT_UPDATE_REGISTER_IN_NONLEAF_FRAME) "Func eval cannot update a variable stored in a register on a non-leaf frame. The most likely cause is that such a variable is passed as a ref/out argument."
+ MSG_FOR_URT_HR(CORDBG_E_BAD_THREAD_STATE) "The state of the thread is invalid."
+ MSG_FOR_URT_HR(CORDBG_E_DEBUGGER_ALREADY_ATTACHED) "This process has already been attached."
+ MSG_FOR_URT_HR(CORDBG_E_SUPERFLOUS_CONTINUE) "Returned from a call to Continue that was not matched with a stopping event."
+ MSG_FOR_URT_HR(CORDBG_E_SET_VALUE_NOT_ALLOWED_ON_NONLEAF_FRAME) "Cannot perfrom SetValue on non-leaf frames."
+ MSG_FOR_URT_HR(CORDBG_E_ENC_EH_MAX_NESTING_LEVEL_CANT_INCREASE) "When doing Edit and Continue, some JITs do not allow increasing the maximum level to which exception handling can be nested."
+ MSG_FOR_URT_HR(CORDBG_E_ENC_MODULE_NOT_ENC_ENABLED) "Tried to do Edit and Continue on a module that was not started in Edit and Continue mode."
+ MSG_FOR_URT_HR(CORDBG_E_SET_IP_NOT_ALLOWED_ON_EXCEPTION) "SetIP cannot be done on any exception."
+ MSG_FOR_URT_HR(CORDBG_E_VARIABLE_IS_ACTUALLY_LITERAL) "The 'variable' does not exist because it is a literal optimized away by the compiler."
+ MSG_FOR_URT_HR(CORDBG_E_PROCESS_DETACHED) "Process has been detached."
+ MSG_FOR_URT_HR(CORDBG_E_ENC_METHOD_SIG_CHANGED) "Not allowed to change the signature of an existing method."
+ MSG_FOR_URT_HR(CORDBG_E_ENC_METHOD_NO_LOCAL_SIG) "Cannot get the local signature for the method."
+ MSG_FOR_URT_HR(CORDBG_E_ENC_CANT_ADD_FIELD_TO_VALUE_OR_LAYOUT_CLASS) "Adding a field to a value or layout class is prohibited."
+ MSG_FOR_URT_HR(CORDBG_E_ENC_CANT_CHANGE_FIELD) "Cannot change field after adding."
+ MSG_FOR_URT_HR(CORDBG_E_ENC_CANT_ADD_NON_PRIVATE_MEMBER) "Only support addition of private members."
+ MSG_FOR_URT_HR(CORDBG_E_FIELD_NOT_STATIC) "GetStaticFieldValue called on a non-static field."
+ MSG_FOR_URT_HR(CORDBG_E_FIELD_NOT_INSTANCE) "Returned if someone tries to call GetStaticFieldValue on a non-instance field."
+ MSG_FOR_URT_HR(CORDBG_E_ENC_ZAPPED_WITHOUT_ENC) "If a zap file was created without the Edit and Continue flag set, then we cannot do Edit and Continue on it, no matter what."
+ MSG_FOR_URT_HR(CORDBG_E_ENC_BAD_METHOD_INFO) "Lacking information about method."
+ MSG_FOR_URT_HR(CORDBG_E_ENC_JIT_CANT_UPDATE) "The JIT is unable to update the method."
+ MSG_FOR_URT_HR(CORDBG_E_ENC_MISSING_CLASS) "An internal structure about the class is missing."
+ MSG_FOR_URT_HR(CORDBG_E_ENC_INTERNAL_ERROR) "Internal Runtime Error while doing Edit-and-Continue."
+ MSG_FOR_URT_HR(CORDBG_E_ENC_HANGING_FIELD) "The field was added via Edit and Continue after the class was loaded."
+ MSG_FOR_URT_HR(CORDBG_E_MODULE_NOT_LOADED) "Module not loaded."
+ MSG_FOR_URT_HR(CORDBG_E_ENC_CANT_CHANGE_SUPERCLASS) "Not allowed to change base class."
+ MSG_FOR_URT_HR(CORDBG_E_UNABLE_TO_SET_BREAKPOINT) "Cannot set a breakpoint here."
+ MSG_FOR_URT_HR(CORDBG_E_DEBUGGING_NOT_POSSIBLE) "Debugging is not possible due to an incompatibility within the CLR implementation."
+ MSG_FOR_URT_HR(CORDBG_E_KERNEL_DEBUGGER_ENABLED) "A kernel debugger is enabled on the system. User-mode debugging will trap to the kernel debugger."
+ MSG_FOR_URT_HR(CORDBG_E_KERNEL_DEBUGGER_PRESENT) "A kernel debugger is present on the system. User-mode debugging will trap to the kernel debugger."
+ MSG_FOR_URT_HR(CORDBG_E_HELPER_THREAD_DEAD) "The debugger's internal helper thread is dead."
+ MSG_FOR_URT_HR(CORDBG_E_INTERFACE_INHERITANCE_CANT_CHANGE) "Not allowed to change interface inheritance."
+ MSG_FOR_URT_HR(CORDBG_E_INCOMPATIBLE_PROTOCOL) "The debugger's protocol is incompatible with the debuggee."
+ MSG_FOR_URT_HR(CORDBG_E_TOO_MANY_PROCESSES) "The debugger can only handle a finite number of debuggees."
+ MSG_FOR_URT_HR(CORDBG_E_INTEROP_NOT_SUPPORTED) "Interop debugging is not supported."
+ MSG_FOR_URT_HR(CORDBG_E_NO_REMAP_BREAKPIONT) "Cannot call RemapFunction until have received RemapBreakpoint."
+ MSG_FOR_URT_HR(CORDBG_E_OBJECT_NEUTERED) "Object is in a zombie state."
+ MSG_FOR_URT_HR(CORPROF_E_FUNCTION_NOT_COMPILED) "Function not yet compiled."
+ MSG_FOR_URT_HR(CORPROF_E_DATAINCOMPLETE) "The ID is not fully loaded/defined yet."
+ MSG_FOR_URT_HR(CORPROF_E_NOT_REJITABLE_METHODS) "The Module is not configured for updateable methods."
+ MSG_FOR_URT_HR(CORPROF_E_CANNOT_UPDATE_METHOD) "The Method could not be updated for re-JIT."
+ MSG_FOR_URT_HR(CORPROF_E_FUNCTION_NOT_IL) "The Method has no associated IL."
+ MSG_FOR_URT_HR(CORPROF_E_NOT_MANAGED_THREAD) "The thread has never run managed code before."
+ MSG_FOR_URT_HR(CORPROF_E_CALL_ONLY_FROM_INIT) "The function may only be called during profiler initialization."
+ MSG_FOR_URT_HR(CORPROF_E_INPROC_NOT_ENABLED) "In-process debugging must be enabled during initialization."
+ MSG_FOR_URT_HR(CORPROF_E_JITMAPS_NOT_ENABLED) "Cannot get a JIT map becuase they are not enabled."
+ MSG_FOR_URT_HR(CORPROF_E_INPROC_ALREADY_BEGUN) "BeginInprocDebugging already called."
+ MSG_FOR_URT_HR(CORPROF_E_INPROC_NOT_AVAILABLE) "In-process debugging not allowed at this point."
+ MSG_FOR_URT_HR(CORPROF_E_NOT_YET_AVAILABLE) "Requested information is not yet available."
+ MSG_FOR_URT_HR(CORPROF_E_TYPE_IS_PARAMETERIZED) "The given type is a generic and cannot be used with this method."
+ MSG_FOR_URT_HR(CORPROF_E_FUNCTION_IS_PARAMETERIZED) "The given function is a generic and cannot be used with this method."
+ MSG_FOR_URT_HR(SECURITY_E_XML_TO_ASN_ENCODING) "Failed to convert XML to ASN."
+ MSG_FOR_URT_HR(SECURITY_E_INCOMPATIBLE_SHARE) "Loading this assembly would produce a different grant set from other instances."
+ MSG_FOR_URT_HR(SECURITY_E_UNVERIFIABLE) "Unverifiable code failed policy check."
+ MSG_FOR_URT_HR(SECURITY_E_INCOMPATIBLE_EVIDENCE) "Assembly already loaded without additional security evidence."
+ MSG_FOR_URT_HR(CORSEC_E_DECODE_SET) "Failure decoding permission set."
+ MSG_FOR_URT_HR(CORSEC_E_ENCODE_SET) "Failure encoding permission set."
+ MSG_FOR_URT_HR(CORSEC_E_UNSUPPORTED_FORMAT) "Unrecognized encoding format."
+ MSG_FOR_URT_HR(CORSEC_E_CRYPTOAPI_CALL_FAILED) "StrongName APIs not supported on system."
+ MSG_FOR_URT_HR(CORSEC_E_NO_SUITABLE_CSP) "StrongName APIs could not locate a matching CSP."
+ MSG_FOR_URT_HR(CORSEC_E_INVALID_ATTR) "Invalid security custom attribute."
+ MSG_FOR_URT_HR(CORSEC_E_POLICY_EXCEPTION) "PolicyException thrown."
+ MSG_FOR_URT_HR(CORSEC_E_MIN_GRANT_FAIL) "Failed to grant minimum permission requests."
+ MSG_FOR_URT_HR(CORSEC_E_NO_EXEC_PERM) "Failed to grant permission to execute."
+ MSG_FOR_URT_HR(CORSEC_E_XMLSYNTAX) "XML Syntax error."
+ MSG_FOR_URT_HR(CORSEC_E_INVALID_STRONGNAME) "Strong name validation failed."
+ MSG_FOR_URT_HR(CORSEC_E_MISSING_STRONGNAME) "Assembly is not strong named."
+ MSG_FOR_URT_HR(CORSEC_E_CONTAINER_NOT_FOUND) "Strong name key container not found."
+ MSG_FOR_URT_HR(CORSEC_E_INVALID_IMAGE_FORMAT) "Invalid assembly file format."
+ MSG_FOR_URT_HR(CORSEC_E_INVALID_PUBLICKEY) "Invalid assembly public key."
+ MSG_FOR_URT_HR(CORSEC_E_SIGNATURE_MISMATCH) "Signature size mismatch."
+ MSG_FOR_URT_HR(SN_E_PUBLICKEY_MISMATCH) "Public key of assembly did not match signing public key."
+ MSG_FOR_URT_HR(CORSEC_E_INVALID_SIGNATUREKEY) "Invalid signature public key specified in AssemblySignatureKeyAttribute."
+ MSG_FOR_URT_HR(CORSEC_E_INVALID_COUNTERSIGNATURE) "Invalid countersignature specified in AssemblySignatureKeyAttribute."
+ MSG_FOR_URT_HR(CORSEC_E_CRYPTO) "Failure during Cryptographic operation."
+ MSG_FOR_URT_HR(CORSEC_E_CRYPTO_UNEX_OPER) "Unexpected Cryptographic operation."
+ MSG_FOR_URT_HR(CORSECATTR_E_BAD_ATTRIBUTE) "Generic problem with a custom attribute."
+ MSG_FOR_URT_HR(CORSECATTR_E_MISSING_CONSTRUCTOR) "Missing a required constructor."
+ MSG_FOR_URT_HR(CORSECATTR_E_FAILED_TO_CREATE_PERM) "Unable to create a permission for this attribute."
+ MSG_FOR_URT_HR(CORSECATTR_E_BAD_ACTION_ASM) "SecurityAction type invalid on assembly."
+ MSG_FOR_URT_HR(CORSECATTR_E_BAD_ACTION_OTHER) "SecurityAction type invalid on types and methods."
+ MSG_FOR_URT_HR(CORSECATTR_E_BAD_PARENT) "Security custom attribute attached to invalid parent."
+ MSG_FOR_URT_HR(CORSECATTR_E_TRUNCATED) "Bad custom attribute serialized blob."
+ MSG_FOR_URT_HR(CORSECATTR_E_BAD_VERSION) "Bad custom attribute serialized blob version."
+ MSG_FOR_URT_HR(CORSECATTR_E_BAD_ACTION) "Invalid security action code."
+ MSG_FOR_URT_HR(CORSECATTR_E_NO_SELF_REF) "CA reference to CA definition in same assembly."
+ MSG_FOR_URT_HR(CORSECATTR_E_BAD_NONCAS) "Use of non-CAS permission with invalid action."
+ MSG_FOR_URT_HR(CORSECATTR_E_ASSEMBLY_LOAD_FAILED) "Failed to load assembly containing CA (or required CA type)."
+ MSG_FOR_URT_HR(CORSECATTR_E_ASSEMBLY_LOAD_FAILED_EX) "Failed to load assembly containing CA (or required CA type)."
+ MSG_FOR_URT_HR(CORSECATTR_E_TYPE_LOAD_FAILED) "Failed to load CA type (or required CA type)."
+ MSG_FOR_URT_HR(CORSECATTR_E_TYPE_LOAD_FAILED_EX) "Failed to load CA type (or required CA type)."
+ MSG_FOR_URT_HR(CORSECATTR_E_ABSTRACT) "CA type is abstract."
+ MSG_FOR_URT_HR(CORSECATTR_E_UNSUPPORTED_TYPE) "Security custom attributes do not support array or Type fields and properties."
+ MSG_FOR_URT_HR(CORSECATTR_E_UNSUPPORTED_ENUM_TYPE) "Unsupported base type for enum field or property."
+ MSG_FOR_URT_HR(CORSECATTR_E_NO_FIELD) "Could not find a CA field."
+ MSG_FOR_URT_HR(CORSECATTR_E_NO_PROPERTY) "Could not find a CA property."
+ MSG_FOR_URT_HR(CORSECATTR_E_EXCEPTION) "Unexpected exception."
+ MSG_FOR_URT_HR(CORSECATTR_E_EXCEPTION_HR) "Unexpected exception."
+ MSG_FOR_URT_HR(ISS_E_ISOSTORE) "IsolatedStorage operation failed."
+ MSG_FOR_URT_HR(ISS_E_OPEN_STORE_FILE) "Unable to open the store."
+ MSG_FOR_URT_HR(ISS_E_OPEN_FILE_MAPPING) "Unable to create store file mapping."
+ MSG_FOR_URT_HR(ISS_E_MAP_VIEW_OF_FILE) "Unable to map the store file."
+ MSG_FOR_URT_HR(ISS_E_GET_FILE_SIZE) "Unable to determine store file size."
+ MSG_FOR_URT_HR(ISS_E_CREATE_MUTEX) "Unable to create mutex."
+ MSG_FOR_URT_HR(ISS_E_LOCK_FAILED) "Unable to lock the store."
+ MSG_FOR_URT_HR(ISS_E_FILE_WRITE) "File Write failed."
+ MSG_FOR_URT_HR(ISS_E_SET_FILE_POINTER) "Cannot set file pointer."
+ MSG_FOR_URT_HR(ISS_E_CREATE_DIR) "Unable to create the store directory."
+ MSG_FOR_URT_HR(ISS_E_STORE_NOT_OPEN) "Store must be open for this operation."
+ MSG_FOR_URT_HR(ISS_E_CORRUPTED_STORE_FILE) "Store file is corrupt."
+ MSG_FOR_URT_HR(ISS_E_STORE_VERSION) "Store version is not supported."
+ MSG_FOR_URT_HR(ISS_E_FILE_NOT_MAPPED) "Store file is not mapped."
+ MSG_FOR_URT_HR(ISS_E_BLOCK_SIZE_TOO_SMALL) "Block size is too small."
+ MSG_FOR_URT_HR(ISS_E_ALLOC_TOO_LARGE) "Allocation size is too large."
+ MSG_FOR_URT_HR(ISS_E_USAGE_WILL_EXCEED_QUOTA) "Allowed quota is fully used."
+ MSG_FOR_URT_HR(ISS_E_TABLE_ROW_NOT_FOUND) "Row not found."
+ MSG_FOR_URT_HR(ISS_E_DEPRECATE) "Unable to deprecate old store."
+ MSG_FOR_URT_HR(ISS_E_CALLER) "Unable to determine the caller."
+ MSG_FOR_URT_HR(ISS_E_PATH_LENGTH) "Path length is too long."
+ MSG_FOR_URT_HR(ISS_E_MACHINE) "Machine Store is not supported."
+ MSG_FOR_URT_HR(ISS_E_MACHINE_DACL) "The DACL for the machine store is incorrect or could not be created."
+ MSG_FOR_URT_HR(COR_E_EXCEPTION) "General Exception"
+ MSG_FOR_URT_HR(COR_E_SYSTEM) "System.Exception"
+ MSG_FOR_URT_HR(COR_E_ARGUMENTOUTOFRANGE) "An argument was out of its legal range."
+ MSG_FOR_URT_HR(COR_E_ARRAYTYPEMISMATCH) "Attempted to store an object of the wrong type in an array."
+ MSG_FOR_URT_HR(COR_E_CONTEXTMARSHAL) "Attempted to marshal an object across a context boundary."
+ MSG_FOR_URT_HR(COR_E_TIMEOUT) "Operation timed out."
+ MSG_FOR_URT_HR(COR_E_EXECUTIONENGINE) "Internal CLR error."
+ MSG_FOR_URT_HR(COR_E_FIELDACCESS) "Access to this field is denied."
+ MSG_FOR_URT_HR(COR_E_INDEXOUTOFRANGE) "Array subscript out of range."
+ MSG_FOR_URT_HR(COR_E_INVALIDOPERATION) "An operation is not legal in the current state."
+ MSG_FOR_URT_HR(COR_E_SECURITY) "An error relating to security occurred."
+ MSG_FOR_URT_HR(COR_E_REMOTING) "An error relating to remoting occurred."
+ MSG_FOR_URT_HR(COR_E_SERIALIZATION) "An error relating to serialization occurred."
+ MSG_FOR_URT_HR(COR_E_VERIFICATION) "A verification failure has occurred."
+ MSG_FOR_URT_HR(COR_E_SERVER) "An error relating to remoting occurred."
+ MSG_FOR_URT_HR(COR_E_SERVICEDCOMPONENT) "An error relating to ServicedComponent occurred."
+ MSG_FOR_URT_HR(COR_E_METHODACCESS) "Access to this method is denied."
+ MSG_FOR_URT_HR(COR_E_MISSINGFIELD) "Field does not exist."
+ MSG_FOR_URT_HR(COR_E_MISSINGMEMBER) "Member does not exist."
+ MSG_FOR_URT_HR(COR_E_MISSINGMETHOD) "Method does not exist."
+ MSG_FOR_URT_HR(COR_E_MULTICASTNOTSUPPORTED) "Attempt to combine delegates that are not multicast."
+ MSG_FOR_URT_HR(COR_E_NOTSUPPORTED) "Operation is not supported."
+ MSG_FOR_URT_HR(COR_E_OVERFLOW) "Arithmetic, casting or conversion operation overflowed or underflowed."
+ MSG_FOR_URT_HR(COR_E_RANK) "An array has the wrong number of dimensions for a particular operation."
+ MSG_FOR_URT_HR(COR_E_SYNCHRONIZATIONLOCK) "This operation must be called from a synchronized block."
+ MSG_FOR_URT_HR(COR_E_THREADINTERRUPTED) "Thread was interrupted from a waiting state."
+ MSG_FOR_URT_HR(COR_E_MEMBERACCESS) "Access to this member is denied."
+ MSG_FOR_URT_HR(COR_E_THREADSTATE) "Thread is in an invalid state for this operation."
+ MSG_FOR_URT_HR(COR_E_THREADSTOP) "Thread is stopping."
+ MSG_FOR_URT_HR(COR_E_TYPELOAD) "Could not find or load a type."
+ MSG_FOR_URT_HR(COR_E_ENTRYPOINTNOTFOUND) "Could not find the specified DllImport entrypoint."
+ MSG_FOR_URT_HR(COR_E_DLLNOTFOUND) "Could not find the specified DllImport Dll."
+ MSG_FOR_URT_HR(COR_E_INVALIDCOMOBJECT) "An invalid __ComObject has been used."
+ MSG_FOR_URT_HR(COR_E_NOTFINITENUMBER) "Not a Number."
+ MSG_FOR_URT_HR(COR_E_DUPLICATEWAITOBJECT) "An object appears more than once in the wait objects array."
+ MSG_FOR_URT_HR(COR_E_SEMAPHOREFULL) "Reached maximum count for semaphore."
+ MSG_FOR_URT_HR(COR_E_WAITHANDLECANNOTBEOPENED) "No semaphore of the given name exists."
+ MSG_FOR_URT_HR(COR_E_ABANDONEDMUTEX) "The wait completed due to an abandoned mutex."
+ MSG_FOR_URT_HR(COR_E_THREADABORTED) "Thread has aborted."
+ MSG_FOR_URT_HR(COR_E_INVALIDOLEVARIANTTYPE) "OLE Variant has an invalid type."
+ MSG_FOR_URT_HR(COR_E_MISSINGMANIFESTRESOURCE) "An expected resource in the assembly manifest was missing."
+ MSG_FOR_URT_HR(COR_E_SAFEARRAYTYPEMISMATCH) "A mismatch has occurred between the runtime type of the array and the sub type recorded in the metadata."
+ MSG_FOR_URT_HR(COR_E_TYPEINITIALIZATION) "Uncaught exception during type initialization."
+ MSG_FOR_URT_HR(COR_E_MARSHALDIRECTIVE) "Invalid marshaling directives."
+ MSG_FOR_URT_HR(COR_E_MISSINGSATELLITEASSEMBLY) "An expected satellite assembly containing the ultimate fallback resources for a given culture was not found or could not be loaded."
+ MSG_FOR_URT_HR(COR_E_FORMAT) "The format of one argument does not meet the contract of the method."
+ MSG_FOR_URT_HR(COR_E_SAFEARRAYRANKMISMATCH) "A mismatch has occurred between the runtime rank of the array and the rank recorded in the metadata."
+ MSG_FOR_URT_HR(COR_E_PLATFORMNOTSUPPORTED) "Operation is not supported on this platform."
+ MSG_FOR_URT_HR(COR_E_INVALIDPROGRAM) "Invalid IL or CLR metadata."
+ MSG_FOR_URT_HR(COR_E_OPERATIONCANCELED) "The operation was cancelled."
+ MSG_FOR_URT_HR(COR_E_DEVICESNOTSUPPORTED) "Devices not supported."
+ MSG_FOR_URT_HR(COR_E_DATAMISALIGNED) "A datatype misalignment was detected in a load or store instruction."
+ MSG_FOR_URT_HR(COR_E_CODECONTRACTFAILED) "A managed code contract (ie, precondition, postcondition, invariant, or assert) failed."
+ MSG_FOR_URT_HR(COR_E_TYPEACCESS) "Access to this type is denied."
+ MSG_FOR_URT_HR(COR_E_ACCESSING_CCW) "Fail to access a CCW because the corresponding managed object is already collected."
+ MSG_FOR_URT_HR(COR_E_MAXMETHODSIZE) "A method in this assembly is greater than the maximum allowed method size."
+ MSG_FOR_URT_HR(COR_E_KEYNOTFOUND) "The given key was not present in the dictionary."
+ MSG_FOR_URT_HR(COR_E_INSUFFICIENTEXECUTIONSTACK) "Insufficient stack to continue executing the program safely. This can happen from having too many functions on the call stack or function on the stack using too much stack space."
+ MSG_FOR_URT_HR(COR_E_APPLICATION) "Application exception"
+ MSG_FOR_URT_HR(COR_E_INVALIDFILTERCRITERIA) "The given filter criteria does not match the filter content."
+ MSG_FOR_URT_HR(COR_E_REFLECTIONTYPELOAD) "Could not find or load a specific class that was requested through Reflection."
+ MSG_FOR_URT_HR(COR_E_TARGET) "Attempt to invoke non-static method with a null Object."
+ MSG_FOR_URT_HR(COR_E_TARGETINVOCATION) "Uncaught exception thrown by method called through Reflection."
+ MSG_FOR_URT_HR(COR_E_CUSTOMATTRIBUTEFORMAT) "Custom attribute has invalid format."
+ MSG_FOR_URT_HR(COR_E_IO) "Error during managed I/O."
+ MSG_FOR_URT_HR(COR_E_FILELOAD) "Could not find or load a specific file."
+ MSG_FOR_URT_HR(COR_E_OBJECTDISPOSED) "The object has already been disposed."
+ MSG_FOR_URT_HR(COR_E_FAILFAST) "Runtime operation halted by call to System.Environment.FailFast()."
+ MSG_FOR_URT_HR(COR_E_HOSTPROTECTION) "The host has forbidden this operation."
+ MSG_FOR_URT_HR(COR_E_ILLEGAL_REENTRANCY) "Attempted to call into managed code when executing inside a low level extensibility point."
+ MSG_FOR_URT_HR(CLR_E_SHIM_RUNTIMELOAD) "Failed to load the runtime."
+ MSG_FOR_URT_HR(CLR_E_SHIM_RUNTIMEEXPORT) "Failed to find a required export in the runtime."
+ MSG_FOR_URT_HR(CLR_E_SHIM_INSTALLROOT) "Install root is not defined."
+ MSG_FOR_URT_HR(CLR_E_SHIM_INSTALLCOMP) "Expected component of the runtime is not available."
+ MSG_FOR_URT_HR(CLR_E_SHIM_LEGACYRUNTIMEALREADYBOUND) "A runtime has already been bound for legacy activation policy use."
+ MSG_FOR_URT_HR(CLR_E_SHIM_SHUTDOWNINPROGRESS) "The operation is invalid because the process may be shutting down."
+ MSG_FOR_URT_HR(VER_E_UNKNOWN_OPCODE) "Unknown opcode."
+ MSG_FOR_URT_HR(VER_E_SIG_CALLCONV) "Unknown calling convention."
+ MSG_FOR_URT_HR(VER_E_SIG_ELEMTYPE) "Unknown ELEMENT_TYPE."
+ MSG_FOR_URT_HR(VER_E_RET_SIG) "[return sig]"
+ MSG_FOR_URT_HR(VER_E_FIELD_SIG) "[field sig]"
+ MSG_FOR_URT_HR(VER_E_OPEN_DLGT_PROT_ACC) "Protected method access through an open instance delegate is not verifiable."
+ MSG_FOR_URT_HR(VER_E_INTERNAL) "Internal error."
+ MSG_FOR_URT_HR(VER_E_STACK_TOO_LARGE) "Stack is too large."
+ MSG_FOR_URT_HR(VER_E_ARRAY_NAME_LONG) "Array name is too long."
+ MSG_FOR_URT_HR(VER_E_FALLTHRU) "fall through end of the method without returning"
+ MSG_FOR_URT_HR(VER_E_TRY_GTEQ_END) "try start >= try end"
+ MSG_FOR_URT_HR(VER_E_TRYEND_GT_CS) "try end > code size"
+ MSG_FOR_URT_HR(VER_E_HND_GTEQ_END) "handler start >= handler end"
+ MSG_FOR_URT_HR(VER_E_HNDEND_GT_CS) "handler end > code size"
+ MSG_FOR_URT_HR(VER_E_TRY_START) "Try starts in the middle of an instruction."
+ MSG_FOR_URT_HR(VER_E_HND_START) "Handler starts in the middle of an instruction."
+ MSG_FOR_URT_HR(VER_E_TRY_OVERLAP) "Try block overlap with another block."
+ MSG_FOR_URT_HR(VER_E_TRY_EQ_HND_FIL) "Try and filter/handler blocks are equivalent."
+ MSG_FOR_URT_HR(VER_E_TRY_SHARE_FIN_FAL) "Shared try has finally or fault handler."
+ MSG_FOR_URT_HR(VER_E_HND_OVERLAP) "Handler block overlaps with another block."
+ MSG_FOR_URT_HR(VER_E_HND_EQ) "Handler block is the same as another block."
+ MSG_FOR_URT_HR(VER_E_FIL_OVERLAP) "Filter block overlaps with another block."
+ MSG_FOR_URT_HR(VER_E_FIL_EQ) "Filter block is the same as another block."
+ MSG_FOR_URT_HR(VER_E_FIL_CONT_TRY) "Filter contains try."
+ MSG_FOR_URT_HR(VER_E_FIL_CONT_HND) "Filter contains handler."
+ MSG_FOR_URT_HR(VER_E_FIL_CONT_FIL) "Nested filters."
+ MSG_FOR_URT_HR(VER_E_FIL_GTEQ_CS) "filter >= code size"
+ MSG_FOR_URT_HR(VER_E_FIL_START) "Filter starts in the middle of an instruction."
+ MSG_FOR_URT_HR(VER_E_FALLTHRU_EXCEP) "fallthru the end of an exception block"
+ MSG_FOR_URT_HR(VER_E_FALLTHRU_INTO_HND) "fallthru into an exception handler"
+ MSG_FOR_URT_HR(VER_E_FALLTHRU_INTO_FIL) "fallthru into an exception filter"
+ MSG_FOR_URT_HR(VER_E_LEAVE) "Leave from outside a try or catch block."
+ MSG_FOR_URT_HR(VER_E_RETHROW) "Rethrow from outside a catch handler."
+ MSG_FOR_URT_HR(VER_E_ENDFINALLY) "Endfinally from outside a finally handler"
+ MSG_FOR_URT_HR(VER_E_ENDFILTER) "Endfilter from outside an exception filter block"
+ MSG_FOR_URT_HR(VER_E_ENDFILTER_MISSING) "Missing Endfilter."
+ MSG_FOR_URT_HR(VER_E_BR_INTO_TRY) "Branch into try block."
+ MSG_FOR_URT_HR(VER_E_BR_INTO_HND) "Branch into exception handler block."
+ MSG_FOR_URT_HR(VER_E_BR_INTO_FIL) "Branch into exception filter block."
+ MSG_FOR_URT_HR(VER_E_BR_OUTOF_TRY) "Branch out of try block."
+ MSG_FOR_URT_HR(VER_E_BR_OUTOF_HND) "Branch out of exception handler block."
+ MSG_FOR_URT_HR(VER_E_BR_OUTOF_FIL) "Branch out of exception filter block."
+ MSG_FOR_URT_HR(VER_E_BR_OUTOF_FIN) "Branch out of finally block."
+ MSG_FOR_URT_HR(VER_E_RET_FROM_TRY) "Return out of try block."
+ MSG_FOR_URT_HR(VER_E_RET_FROM_HND) "Return out of exception handler block."
+ MSG_FOR_URT_HR(VER_E_RET_FROM_FIL) "Return out of exception filter block."
+ MSG_FOR_URT_HR(VER_E_BAD_JMP_TARGET) "jmp / exception into the middle of an instruction."
+ MSG_FOR_URT_HR(VER_E_PATH_LOC) "Non-compatible types depending on path."
+ MSG_FOR_URT_HR(VER_E_PATH_THIS) "Init state for this differs depending on path."
+ MSG_FOR_URT_HR(VER_E_PATH_STACK) "Non-compatible types on stack depending on path."
+ MSG_FOR_URT_HR(VER_E_PATH_STACK_DEPTH) "Stack depth differs depending on path."
+ MSG_FOR_URT_HR(VER_E_THIS) "Instance variable (this) missing."
+ MSG_FOR_URT_HR(VER_E_THIS_UNINIT_EXCEP) "Uninitialized this on entering a try block."
+ MSG_FOR_URT_HR(VER_E_THIS_UNINIT_STORE) "Store into this when it is uninitialized."
+ MSG_FOR_URT_HR(VER_E_THIS_UNINIT_RET) "Return from .ctor when this is uninitialized."
+ MSG_FOR_URT_HR(VER_E_THIS_UNINIT_V_RET) "Return from .ctor before all fields are initialized."
+ MSG_FOR_URT_HR(VER_E_THIS_UNINIT_BR) "Branch back when this is uninitialized."
+ MSG_FOR_URT_HR(VER_E_LDFTN_CTOR) "ldftn and ldvirtftn not allowed on .ctor."
+ MSG_FOR_URT_HR(VER_E_STACK_NOT_EQ) "Non-compatible types on the stack."
+ MSG_FOR_URT_HR(VER_E_STACK_UNEXPECTED) "Unexpected type on the stack."
+ MSG_FOR_URT_HR(VER_E_STACK_EXCEPTION) "Missing stack slot for exception."
+ MSG_FOR_URT_HR(VER_E_STACK_OVERFLOW) "Stack overflow."
+ MSG_FOR_URT_HR(VER_E_STACK_UNDERFLOW) "Stack underflow."
+ MSG_FOR_URT_HR(VER_E_STACK_EMPTY) "Stack empty."
+ MSG_FOR_URT_HR(VER_E_STACK_UNINIT) "Uninitialized item on stack."
+ MSG_FOR_URT_HR(VER_E_STACK_I_I4_I8) "Expected I, I4, or I8 on the stack."
+ MSG_FOR_URT_HR(VER_E_STACK_R_R4_R8) "Expected R, R4, or R8 on the stack."
+ MSG_FOR_URT_HR(VER_E_STACK_NO_R_I8) "unexpected R, R4, R8, or I8 on the stack."
+ MSG_FOR_URT_HR(VER_E_STACK_NUMERIC) "Expected numeric type on the stack."
+ MSG_FOR_URT_HR(VER_E_STACK_OBJREF) "Expected an ObjRef on the stack."
+ MSG_FOR_URT_HR(VER_E_STACK_P_OBJREF) "Expected address of an ObjRef on the stack."
+ MSG_FOR_URT_HR(VER_E_STACK_BYREF) "Expected ByRef on the stack."
+ MSG_FOR_URT_HR(VER_E_STACK_METHOD) "Expected pointer to function on the stack."
+ MSG_FOR_URT_HR(VER_E_STACK_ARRAY_SD) "Expected single dimension array on the stack."
+ MSG_FOR_URT_HR(VER_E_STACK_VALCLASS) "Expected value type instance on the stack."
+ MSG_FOR_URT_HR(VER_E_STACK_P_VALCLASS) "Expected address of value type on the stack."
+ MSG_FOR_URT_HR(VER_E_STACK_NO_VALCLASS) "Unexpected value type instance on the stack."
+ MSG_FOR_URT_HR(VER_E_LOC_DEAD) "Local variable is unusable at this point."
+ MSG_FOR_URT_HR(VER_E_LOC_NUM) "Unrecognized local variable number."
+ MSG_FOR_URT_HR(VER_E_ARG_NUM) "Unrecognized argument number."
+ MSG_FOR_URT_HR(VER_E_TOKEN_RESOLVE) "Unable to resolve token."
+ MSG_FOR_URT_HR(VER_E_TOKEN_TYPE) "Unable to resolve type of the token."
+ MSG_FOR_URT_HR(VER_E_TOKEN_TYPE_MEMBER) "Expected memberRef, memberDef or methodSpec token."
+ MSG_FOR_URT_HR(VER_E_TOKEN_TYPE_FIELD) "Expected memberRef or fieldDef token."
+ MSG_FOR_URT_HR(VER_E_TOKEN_TYPE_SIG) "Expected signature token."
+ MSG_FOR_URT_HR(VER_E_UNVERIFIABLE) "Instruction cannot be verified."
+ MSG_FOR_URT_HR(VER_E_LDSTR_OPERAND) "Operand does not point to a valid string ref."
+ MSG_FOR_URT_HR(VER_E_RET_PTR_TO_STACK) "Return type is ByRef, TypedReference, ArgHandle, or ArgIterator."
+ MSG_FOR_URT_HR(VER_E_RET_VOID) "Stack must be empty on return from a void function."
+ MSG_FOR_URT_HR(VER_E_RET_MISSING) "Return value missing on the stack."
+ MSG_FOR_URT_HR(VER_E_RET_EMPTY) "Stack must contain only the return value."
+ MSG_FOR_URT_HR(VER_E_RET_UNINIT) "Return uninitialized data."
+ MSG_FOR_URT_HR(VER_E_ARRAY_ACCESS) "Illegal array access."
+ MSG_FOR_URT_HR(VER_E_ARRAY_V_STORE) "Store non Object type into Object array."
+ MSG_FOR_URT_HR(VER_E_ARRAY_SD) "Expected single dimension array."
+ MSG_FOR_URT_HR(VER_E_ARRAY_SD_PTR) "Expected single dimension array of pointer types."
+ MSG_FOR_URT_HR(VER_E_ARRAY_FIELD) "Array field access is denied."
+ MSG_FOR_URT_HR(VER_E_ARGLIST) "Allowed only in vararg methods."
+ MSG_FOR_URT_HR(VER_E_VALCLASS) "Value type expected."
+ MSG_FOR_URT_HR(VER_E_METHOD_ACCESS) "Method is not visible."
+ MSG_FOR_URT_HR(VER_E_FIELD_ACCESS) "Field is not visible."
+ MSG_FOR_URT_HR(VER_E_DEAD) "Item is unusable at this point."
+ MSG_FOR_URT_HR(VER_E_FIELD_STATIC) "Expected static field."
+ MSG_FOR_URT_HR(VER_E_FIELD_NO_STATIC) "Expected non-static field."
+ MSG_FOR_URT_HR(VER_E_ADDR) "Address of not allowed for this item."
+ MSG_FOR_URT_HR(VER_E_ADDR_BYREF) "Address of not allowed for ByRef."
+ MSG_FOR_URT_HR(VER_E_ADDR_LITERAL) "Address of not allowed for literal field."
+ MSG_FOR_URT_HR(VER_E_INITONLY) "Cannot change initonly field outside its .ctor."
+ MSG_FOR_URT_HR(VER_E_THROW) "Cannot throw this object."
+ MSG_FOR_URT_HR(VER_E_CALLVIRT_VALCLASS) "Callvirt on a value type method."
+ MSG_FOR_URT_HR(VER_E_CALL_SIG) "Call signature mismatch."
+ MSG_FOR_URT_HR(VER_E_CALL_STATIC) "Static function expected."
+ MSG_FOR_URT_HR(VER_E_CTOR) ".ctor expected."
+ MSG_FOR_URT_HR(VER_E_CTOR_VIRT) "Cannot use callvirt on .ctor."
+ MSG_FOR_URT_HR(VER_E_CTOR_OR_SUPER) "Only super::ctor or typeof(this)::ctor allowed here."
+ MSG_FOR_URT_HR(VER_E_CTOR_MUL_INIT) "Possible call to .ctor more than once."
+ MSG_FOR_URT_HR(VER_E_SIG) "Unrecognized signature."
+ MSG_FOR_URT_HR(VER_E_SIG_ARRAY) "Cannot resolve Array type."
+ MSG_FOR_URT_HR(VER_E_SIG_ARRAY_PTR) "Array of ELEMENT_TYPE_PTR."
+ MSG_FOR_URT_HR(VER_E_SIG_ARRAY_BYREF) "Array of ELEMENT_TYPE_BYREF or ELEMENT_TYPE_TYPEDBYREF."
+ MSG_FOR_URT_HR(VER_E_SIG_ELEM_PTR) "ELEMENT_TYPE_PTR cannot be verified."
+ MSG_FOR_URT_HR(VER_E_SIG_VARARG) "Unexpected vararg."
+ MSG_FOR_URT_HR(VER_E_SIG_VOID) "Unexpected Void."
+ MSG_FOR_URT_HR(VER_E_SIG_BYREF_BYREF) "ByRef of ByRef"
+ MSG_FOR_URT_HR(VER_E_CODE_SIZE_ZERO) "Code size is zero."
+ MSG_FOR_URT_HR(VER_E_BAD_VARARG) "Unrecognized use of vararg."
+ MSG_FOR_URT_HR(VER_E_TAIL_CALL) "Missing call, callvirt or calli."
+ MSG_FOR_URT_HR(VER_E_TAIL_BYREF) "Cannot pass ByRef to a tail call."
+ MSG_FOR_URT_HR(VER_E_TAIL_RET) "Missing ret."
+ MSG_FOR_URT_HR(VER_E_TAIL_RET_VOID) "Void ret type expected for tail call."
+ MSG_FOR_URT_HR(VER_E_TAIL_RET_TYPE) "Tail call return type not compatible."
+ MSG_FOR_URT_HR(VER_E_TAIL_STACK_EMPTY) "Stack not empty after tail call."
+ MSG_FOR_URT_HR(VER_E_METHOD_END) "Method ends in the middle of an instruction."
+ MSG_FOR_URT_HR(VER_E_BAD_BRANCH) "Branch out of the method."
+ MSG_FOR_URT_HR(VER_E_FIN_OVERLAP) "Finally handler blocks overlap."
+ MSG_FOR_URT_HR(VER_E_LEXICAL_NESTING) "Lexical nesting."
+ MSG_FOR_URT_HR(VER_E_VOLATILE) "Missing ldsfld, stsfld, ldind, stind, ldfld, stfld, ldobj, stobj, initblk or cpblk."
+ MSG_FOR_URT_HR(VER_E_UNALIGNED) "Missing ldind, stind, ldfld, stfld, ldobj, stobj, initblk or cpblk."
+ MSG_FOR_URT_HR(VER_E_INNERMOST_FIRST) "Innermost exception blocks should be declared first."
+ MSG_FOR_URT_HR(VER_E_CALLI_VIRTUAL) "Calli not allowed on virtual methods."
+ MSG_FOR_URT_HR(VER_E_CALL_ABSTRACT) "Call not allowed on abstract methods."
+ MSG_FOR_URT_HR(VER_E_STACK_UNEXP_ARRAY) "Unexpected array type on the stack."
+ MSG_FOR_URT_HR(VER_E_NOT_IN_GC_HEAP) "Value type with NotInGCHeap attribute being created on the GC heap."
+ MSG_FOR_URT_HR(VER_E_TRY_N_EMPTY_STACK) "Attempt to enter a try block with nonempty stack."
+ MSG_FOR_URT_HR(VER_E_DLGT_CTOR) "Unrecognized arguments for delegate .ctor."
+ MSG_FOR_URT_HR(VER_E_DLGT_BB) "Delegate .ctor not allowed at the start of a basic block when the function pointer argument is a virtual method."
+ MSG_FOR_URT_HR(VER_E_DLGT_PATTERN) "Dup, ldvirtftn, newobj delegate::.ctor() pattern expected (in the same basic block)."
+ MSG_FOR_URT_HR(VER_E_DLGT_LDFTN) "Ldftn or ldvirtftn instruction required before call to a delegate .ctor."
+ MSG_FOR_URT_HR(VER_E_FTN_ABSTRACT) "Attempt to load address of an abstract method."
+ MSG_FOR_URT_HR(VER_E_SIG_C_VC) "ELEMENT_TYPE_CLASS ValueClass in signature."
+ MSG_FOR_URT_HR(VER_E_SIG_VC_C) "ELEMENT_TYPE_VALUETYPE non-ValueClass in signature."
+ MSG_FOR_URT_HR(VER_E_BOX_PTR_TO_STACK) "Box operation on TypedReference, ArgHandle, or ArgIterator."
+ MSG_FOR_URT_HR(VER_E_SIG_BYREF_TB_AH) "ByRef of TypedReference, ArgHandle, or ArgIterator."
+ MSG_FOR_URT_HR(VER_E_SIG_ARRAY_TB_AH) "Array of TypedReference, ArgHandle, or ArgIterator."
+ MSG_FOR_URT_HR(VER_E_ENDFILTER_STACK) "Stack not empty when leaving an exception filter."
+ MSG_FOR_URT_HR(VER_E_DLGT_SIG_I) "Unrecognized delegate .ctor signature; expected I."
+ MSG_FOR_URT_HR(VER_E_DLGT_SIG_O) "Unrecognized delegate .ctor signature; expected Object."
+ MSG_FOR_URT_HR(VER_E_RA_PTR_TO_STACK) "Mkrefany on TypedReference, ArgHandle, or ArgIterator."
+ MSG_FOR_URT_HR(VER_E_CATCH_VALUE_TYPE) "Value type not allowed as catch type."
+ MSG_FOR_URT_HR(VER_E_CATCH_BYREF) "ByRef not allowed as catch type."
+ MSG_FOR_URT_HR(VER_E_FIL_PRECEED_HND) "filter block should immediately precede handler block"
+ MSG_FOR_URT_HR(VER_E_LDVIRTFTN_STATIC) "ldvirtftn on static"
+ MSG_FOR_URT_HR(VER_E_CALLVIRT_STATIC) "callvirt on static"
+ MSG_FOR_URT_HR(VER_E_INITLOCALS) "initlocals must be set for verifiable methods with one or more local variables."
+ MSG_FOR_URT_HR(VER_E_BR_TO_EXCEPTION) "branch or leave to the beginning of a catch/filter handler"
+ MSG_FOR_URT_HR(VER_E_CALL_CTOR) "Call to .ctor only allowed to initialize this pointer from within a .ctor. Try newobj."
+ MSG_FOR_URT_HR(VER_E_VALCLASS_OBJREF_VAR) "Value type, ObjRef type or variable type expected."
+ MSG_FOR_URT_HR(VER_E_STACK_P_VALCLASS_OBJREF_VAR) "Expected address of value type, ObjRef type or variable type on the stack."
+ MSG_FOR_URT_HR(VER_E_SIG_VAR_PARAM) "Unrecognized type parameter of enclosing class."
+ MSG_FOR_URT_HR(VER_E_SIG_MVAR_PARAM) "Unrecognized type parameter of enclosing method."
+ MSG_FOR_URT_HR(VER_E_SIG_VAR_ARG) "Unrecognized type argument of referenced class instantiation."
+ MSG_FOR_URT_HR(VER_E_SIG_MVAR_ARG) "Unrecognized type argument of referenced method instantiation."
+ MSG_FOR_URT_HR(VER_E_SIG_GENERICINST) "Cannot resolve generic type."
+ MSG_FOR_URT_HR(VER_E_SIG_METHOD_INST) "Method instantiation contains non boxable type arguments."
+ MSG_FOR_URT_HR(VER_E_SIG_METHOD_PARENT_INST) "Method parent instantiation contains non boxable type arguments."
+ MSG_FOR_URT_HR(VER_E_SIG_FIELD_PARENT_INST) "Field parent instantiation contains non boxable type arguments."
+ MSG_FOR_URT_HR(VER_E_CALLCONV_NOT_GENERICINST) "Unrecognized calling convention for an instantiated generic method."
+ MSG_FOR_URT_HR(VER_E_TOKEN_BAD_METHOD_SPEC) "Unrecognized generic method in method instantiation."
+ MSG_FOR_URT_HR(VER_E_BAD_READONLY_PREFIX) "Missing ldelema or call following readonly. prefix."
+ MSG_FOR_URT_HR(VER_E_BAD_CONSTRAINED_PREFIX) "Missing callvirt following constrained. prefix."
+ MSG_FOR_URT_HR(VER_E_CIRCULAR_VAR_CONSTRAINTS) "Method parent has circular class type parameter constraints."
+ MSG_FOR_URT_HR(VER_E_CIRCULAR_MVAR_CONSTRAINTS) "Method has circular method type parameter constraints."
+ MSG_FOR_URT_HR(VER_E_UNSATISFIED_METHOD_INST) "Method instantiation has unsatisfied method type parameter constraints."
+ MSG_FOR_URT_HR(VER_E_UNSATISFIED_METHOD_PARENT_INST) "Method parent instantiation has unsatisfied class type parameter constraints."
+ MSG_FOR_URT_HR(VER_E_UNSATISFIED_FIELD_PARENT_INST) "Field parent instantiation has unsatisfied class type parameter constraints."
+ MSG_FOR_URT_HR(VER_E_UNSATISFIED_BOX_OPERAND) "Type operand of box instruction has unsatisfied class type parameter constraints."
+ MSG_FOR_URT_HR(VER_E_CONSTRAINED_CALL_WITH_NON_BYREF_THIS) "The 'this' argument to a constrained call must have ByRef type."
+ MSG_FOR_URT_HR(VER_E_CONSTRAINED_OF_NON_VARIABLE_TYPE) "The operand to a constrained prefix instruction must be a type parameter."
+ MSG_FOR_URT_HR(VER_E_READONLY_UNEXPECTED_CALLEE) "The readonly prefix may only be applied to calls to array methods returning ByRefs."
+ MSG_FOR_URT_HR(VER_E_READONLY_ILLEGAL_WRITE) "Illegal write to readonly ByRef."
+ MSG_FOR_URT_HR(VER_E_READONLY_IN_MKREFANY) "A readonly ByRef cannot be used with mkrefany."
+ MSG_FOR_URT_HR(VER_E_UNALIGNED_ALIGNMENT) "Alignment specified for 'unaligned' prefix must be 1, 2, or 4."
+ MSG_FOR_URT_HR(VER_E_TAILCALL_INSIDE_EH) "The tail.call (or calli or callvirt) instruction cannot be used to transfer control out of a try, filter, catch, or finally block."
+ MSG_FOR_URT_HR(VER_E_BACKWARD_BRANCH) "Stack height at all points must be determinable in a single forward scan of IL."
+ MSG_FOR_URT_HR(VER_E_CALL_TO_VTYPE_BASE) "Call to base type of valuetype."
+ MSG_FOR_URT_HR(VER_E_NEWOBJ_OF_ABSTRACT_CLASS) "Cannot construct an instance of abstract class."
+ MSG_FOR_URT_HR(VER_E_UNMANAGED_POINTER) "Unmanaged pointers are not a verifiable type."
+ MSG_FOR_URT_HR(VER_E_LDFTN_NON_FINAL_VIRTUAL) "Cannot LDFTN a non-final virtual method."
+ MSG_FOR_URT_HR(VER_E_FIELD_OVERLAP) "Accessing type with overlapping fields."
+ MSG_FOR_URT_HR(VER_E_THIS_MISMATCH) "The 'this' parameter to the call must be the calling method's 'this' parameter."
+ MSG_FOR_URT_HR(VER_E_STACK_I_I4) "Expected I4 on the stack."
+ MSG_FOR_URT_HR(VER_E_BAD_PE) "Unverifiable PE Header/native stub."
+ MSG_FOR_URT_HR(VER_E_BAD_MD) "Unrecognized metadata, unable to verify IL."
+ MSG_FOR_URT_HR(VER_E_BAD_APPDOMAIN) "Unrecognized appdomain pointer."
+ MSG_FOR_URT_HR(VER_E_TYPELOAD) "Type load failed."
+ MSG_FOR_URT_HR(VER_E_PE_LOAD) "Module load failed."
+ MSG_FOR_URT_HR(VER_E_WRITE_RVA_STATIC) "Cannot modify an imaged based (RVA) static"
+ MSG_FOR_URT_HR(VER_E_INITIALIZE_ARRAY_MISSING_TOKEN) "Ldtoken instruction required before call to System.Runtime.CompilerServices.InitializeArray."
+ MSG_FOR_URT_HR(VLDTR_E_IFACE_NOTIFACE) "Interface in InterfaceImpl is not marked tdInterface."
+ MSG_FOR_URT_HR(VLDTR_E_FD_RVAHASNORVA) "Field marked fdHasFieldRVA but has no RVA record."
+ MSG_FOR_URT_HR(VLDTR_E_FD_RVAHASZERORVA) "Field marked fdHasFieldRVA has RVA set to zero."
+ MSG_FOR_URT_HR(VLDTR_E_MD_RVAANDIMPLMAP) "Method has both non-zero RVA and ImplMap."
+ MSG_FOR_URT_HR(VLDTR_E_TD_EXTRAFLAGS) "TypeDef has extraneous bits in flags."
+ MSG_FOR_URT_HR(VLDTR_E_TD_EXTENDSITSELF) "TypeDef extends itself."
+ MSG_FOR_URT_HR(VLDTR_E_TD_SYSVTNOTEXTOBJ) "System.ValueType does not extend System.Object."
+ MSG_FOR_URT_HR(VLDTR_E_TD_EXTTYPESPEC) "Class extends TypeSpec (warning)."
+ MSG_FOR_URT_HR(VLDTR_E_TD_VTNOSIZE) "Value Class has zero size."
+ MSG_FOR_URT_HR(VLDTR_E_TD_IFACESEALED) "Interface is sealed."
+ MSG_FOR_URT_HR(VLDTR_E_NC_BADNESTED) "Bad 'nested' token in NestedClass."
+ MSG_FOR_URT_HR(VLDTR_E_NC_BADENCLOSER) "Bad 'enclosing' token in NestedClass."
+ MSG_FOR_URT_HR(VLDTR_E_NC_DUP) "Duplicate NestedClass record."
+ MSG_FOR_URT_HR(VLDTR_E_NC_DUPENCLOSER) "Duplicate NestedClass with different encloser."
+ MSG_FOR_URT_HR(VLDTR_E_FRVA_ZERORVA) "RVA set to zero in FieldRVA record."
+ MSG_FOR_URT_HR(VLDTR_E_FRVA_BADFIELD) "Invalid field token in FieldRVA record."
+ MSG_FOR_URT_HR(VLDTR_E_FRVA_DUPRVA) "Duplicate RVA in FieldRVA record."
+ MSG_FOR_URT_HR(VLDTR_E_FRVA_DUPFIELD) "Duplicate field in FieldRVA record."
+ MSG_FOR_URT_HR(VLDTR_E_EP_BADTOKEN) "Bad token as entry point in CLR header."
+ MSG_FOR_URT_HR(VLDTR_E_EP_INSTANCE) "Entry point in CLR header is a token of instance method."
+ MSG_FOR_URT_HR(VLDTR_E_TD_ENUMFLDBADTYPE) "Enum has non-integral underlying type."
+ MSG_FOR_URT_HR(VLDTR_E_MD_BADRVA) "Method has bogus RVA."
+ MSG_FOR_URT_HR(VLDTR_E_FD_LITERALNODEFAULT) "Literal field has no const value."
+ MSG_FOR_URT_HR(VLDTR_E_IFACE_METHNOTIMPL) "Class implementing an interface does not implement one of methods."
+ MSG_FOR_URT_HR(VLDTR_E_CA_BADPARENT) "CA has invalid owner."
+ MSG_FOR_URT_HR(VLDTR_E_CA_BADTYPE) "CA has invalid type."
+ MSG_FOR_URT_HR(VLDTR_E_CA_NOTCTOR) "CA type is not .ctor."
+ MSG_FOR_URT_HR(VLDTR_E_CA_BADSIG) "CA type has bad signature."
+ MSG_FOR_URT_HR(VLDTR_E_CA_NOSIG) "CA type has no signature."
+ MSG_FOR_URT_HR(VLDTR_E_CA_BADPROLOG) "CA blob has bad prolog (not 0x01 0x00)."
+ MSG_FOR_URT_HR(VLDTR_E_MD_BADLOCALSIGTOK) "Method has invalid LocalSig token."
+ MSG_FOR_URT_HR(VLDTR_E_MD_BADHEADER) "Method has invalid header."
+ MSG_FOR_URT_HR(VLDTR_E_EP_TOOMANYARGS) "Entry point has more than one argument."
+ MSG_FOR_URT_HR(VLDTR_E_EP_BADRET) "Entry point has bad return type."
+ MSG_FOR_URT_HR(VLDTR_E_EP_BADARG) "Entry point has bad argument."
+ MSG_FOR_URT_HR(VLDTR_E_SIG_BADVOID) "Illegal 'void' in signature."
+ MSG_FOR_URT_HR(VLDTR_E_IFACE_METHMULTIMPL) "Multiple implementation of method."
+ MSG_FOR_URT_HR(VLDTR_E_GP_NAMENULL) "GenericParam name is NULL."
+ MSG_FOR_URT_HR(VLDTR_E_GP_OWNERNIL) "GenericParam has nil owner."
+ MSG_FOR_URT_HR(VLDTR_E_GP_DUPNAME) "GenericParam has duplicate by owner and name."
+ MSG_FOR_URT_HR(VLDTR_E_GP_DUPNUMBER) "GenericParam has duplicate by owner and number."
+ MSG_FOR_URT_HR(VLDTR_E_GP_NONSEQ_BY_OWNER) "GenericParam is non sequential by owner."
+ MSG_FOR_URT_HR(VLDTR_E_GP_NONSEQ_BY_NUMBER) "GenericParam is non sequential by number."
+ MSG_FOR_URT_HR(VLDTR_E_GP_UNEXPECTED_OWNER_FOR_VARIANT_VAR) "GenericParam has variance but its owner is not an interface or delegate."
+ MSG_FOR_URT_HR(VLDTR_E_GP_ILLEGAL_VARIANT_MVAR) "GenericParam is a method type parameter and must be non-variant."
+ MSG_FOR_URT_HR(VLDTR_E_GP_ILLEGAL_VARIANCE_FLAGS) "GenericParam has illegal value for variance flags."
+ MSG_FOR_URT_HR(VLDTR_E_GP_REFANDVALUETYPE) "GenericParam has incompatible special constraints reference type and valuetype."
+ MSG_FOR_URT_HR(VLDTR_E_GPC_OWNERNIL) "GenericParamConstraint has nil owner."
+ MSG_FOR_URT_HR(VLDTR_E_GPC_DUP) "GenericParamConstraint has duplicate by owner and constraint."
+ MSG_FOR_URT_HR(VLDTR_E_GPC_NONCONTIGUOUS) "GenericParamConstraint is non-contiguous with preceeding constraints for same owner."
+ MSG_FOR_URT_HR(VLDTR_E_MS_METHODNIL) "MethodSpec has nil method."
+ MSG_FOR_URT_HR(VLDTR_E_MS_DUP) "MethodSpec has duplicate based on method and instantiation."
+ MSG_FOR_URT_HR(VLDTR_E_MS_BADCALLINGCONV) "MethodSpec signature has invalid calling convention."
+ MSG_FOR_URT_HR(VLDTR_E_MS_MISSARITY) "MethodSpec signature is missing arity specification."
+ MSG_FOR_URT_HR(VLDTR_E_MS_MISSARG) "MethodSpec signature is missing type argument."
+ MSG_FOR_URT_HR(VLDTR_E_MS_ARITYMISMATCH) "MethodSpec arity of generic method and instantiation do not match."
+ MSG_FOR_URT_HR(VLDTR_E_MS_METHODNOTGENERIC) "MethodSpec method is not generic."
+ MSG_FOR_URT_HR(VLDTR_E_SIG_MISSARITY) "Signature missing arity of instantiated generic type."
+ MSG_FOR_URT_HR(VLDTR_E_SIG_ARITYMISMATCH) "Signature has generic type of arity instantiated at different arity."
+ MSG_FOR_URT_HR(VLDTR_E_MD_GENERIC_CCTOR) "Method cannot be both generic and a class constructor."
+ MSG_FOR_URT_HR(VLDTR_E_MD_GENERIC_CTOR) "Method cannot be both generic and an instance constructor."
+ MSG_FOR_URT_HR(VLDTR_E_MD_GENERIC_IMPORT) "Method cannot be both generic and defined on an imported type."
+ MSG_FOR_URT_HR(VLDTR_E_MD_GENERIC_BADCALLCONV) "Method cannot be both generic and have non-default calling convention."
+ MSG_FOR_URT_HR(VLDTR_E_EP_GENERIC_METHOD) "Entry point in CLR header is the token for a generic method."
+ MSG_FOR_URT_HR(VLDTR_E_MD_MISSARITY) "Method signature is generic but is missing its arity."
+ MSG_FOR_URT_HR(VLDTR_E_MD_ARITYZERO) "Method signature is generic but its arity is zero."
+ MSG_FOR_URT_HR(VLDTR_E_SIG_ARITYZERO) "Signature has generic type instantiated at arity 0."
+ MSG_FOR_URT_HR(VLDTR_E_MS_ARITYZERO) "MethodSpec signature has arity 0."
+ MSG_FOR_URT_HR(VLDTR_E_MD_GPMISMATCH) "MethodDef signature has arity n but owns m GenericParams."
+ MSG_FOR_URT_HR(VLDTR_E_EP_GENERIC_TYPE) "Entry point in CLR header is the token for a method in a generic type."
+ MSG_FOR_URT_HR(VLDTR_E_MI_DECLNOTGENERIC) "MethodImpl overrides non-generic method with generic method."
+ MSG_FOR_URT_HR(VLDTR_E_MI_IMPLNOTGENERIC) "MethodImpl overrides non-generic method with generic method."
+ MSG_FOR_URT_HR(VLDTR_E_MI_ARITYMISMATCH) "MethodImpl overrides generic method of arity n with generic method of arity m."
+ MSG_FOR_URT_HR(VLDTR_E_TD_EXTBADTYPESPEC) "TypeDef extends a TypeSpec that is not an instantiated type."
+ MSG_FOR_URT_HR(VLDTR_E_SIG_BYREFINST) "Signature has type instantiated at ByRef at offset i."
+ MSG_FOR_URT_HR(VLDTR_E_MS_BYREFINST) "Signature has type instantiated at ByRef at offset i."
+ MSG_FOR_URT_HR(VLDTR_E_TS_EMPTY) "TypeSpec has empty signature."
+ MSG_FOR_URT_HR(VLDTR_E_TS_HASSENTINALS) "TypeSpec has signature containing one or more sentinels."
+ MSG_FOR_URT_HR(VLDTR_E_TD_GENERICHASEXPLAYOUT) "TypeDef is generic but has explicit layout."
+ MSG_FOR_URT_HR(VLDTR_E_SIG_BADTOKTYPE) "Signature has token following ELEMENT_TYPE_CLASS (_VALUETYPE) that is not a TypeDef or TypeRef."
+ MSG_FOR_URT_HR(VLDTR_E_IFACE_METHNOTIMPLTHISMOD) "Warning: Class does not implement interface method in this module."
+ MSG_FOR_URT_HR(TLBX_E_CIRCULAR_EXPORT2) "TypeLib export: attempted to export an Assembly imported from a TLB."
+ MSG_FOR_URT_HR(CORDBG_E_THREAD_NOT_SCHEDULED) "Thread is not scheduled. Thus we may not have OSThreadId, handle, or context."
+ MSG_FOR_URT_HR(CORDBG_E_HANDLE_HAS_BEEN_DISPOSED) "Handle has been disposed."
+ MSG_FOR_URT_HR(CORDBG_E_NONINTERCEPTABLE_EXCEPTION) "Cannot intercept this exception."
+ MSG_FOR_URT_HR(CORDBG_E_CANT_UNWIND_ABOVE_CALLBACK) "When intercepting an exception, cannot intercept above the current frame."
+ MSG_FOR_URT_HR(CORDBG_E_INTERCEPT_FRAME_ALREADY_SET) "The intercept frame for this exception has already been set."
+ MSG_FOR_URT_HR(CORDBG_E_NO_NATIVE_PATCH_AT_ADDR) "There is no native patch at the given address."
+ MSG_FOR_URT_HR(CORDBG_E_MUST_BE_INTEROP_DEBUGGING) "This API is only allowed when interop debugging."
+ MSG_FOR_URT_HR(CORDBG_E_NATIVE_PATCH_ALREADY_AT_ADDR) "There is already a native patch at the address."
+ MSG_FOR_URT_HR(CORDBG_E_TIMEOUT) "A wait timed out, likely an indication of deadlock."
+ MSG_FOR_URT_HR(CORDBG_E_CANT_CALL_ON_THIS_THREAD) "Cannot use the API on this thread."
+ MSG_FOR_URT_HR(CORDBG_E_ENC_INFOLESS_METHOD) "Method was not JIT'd in EnC mode."
+ MSG_FOR_URT_HR(CORDBG_E_ENC_NESTED_HANLDERS) "Frame cannot be updated due to change in max nesting of handlers."
+ MSG_FOR_URT_HR(CORDBG_E_ENC_IN_FUNCLET) "Method is in a callable handler/filter. Cannot increase stack."
+ MSG_FOR_URT_HR(CORDBG_E_ENC_LOCALLOC) "Frame cannot be updated due to localloc."
+ MSG_FOR_URT_HR(CORDBG_E_ENC_EDIT_NOT_SUPPORTED) "Attempt to perform unsupported edit."
+ MSG_FOR_URT_HR(CORDBG_E_FEABORT_DELAYED_UNTIL_THREAD_RESUMED) "Attempt to func eval abort on a suspended thread."
+ MSG_FOR_URT_HR(CORDBG_E_NOTREADY) "The LS is not in a good spot to perform the requested operation."
+ MSG_FOR_URT_HR(CORDBG_E_CANNOT_RESOLVE_ASSEMBLY) "We failed to resolve assembly given an AssemblyRef token. Assembly may be not loaded yet or not a valid token."
+ MSG_FOR_URT_HR(CORDBG_E_MUST_BE_IN_LOAD_MODULE) "Must be in context of LoadModule callback to perform requested operation."
+ MSG_FOR_URT_HR(CORDBG_E_CANNOT_BE_ON_ATTACH) "Requested operation cannot be performed during an attach operation."
+ MSG_FOR_URT_HR(CORDBG_E_NGEN_NOT_SUPPORTED) "NGEN must be supported to perform the requested operation."
+ MSG_FOR_URT_HR(CORDBG_E_ILLEGAL_SHUTDOWN_ORDER) "Trying to shutdown out of order."
+ MSG_FOR_URT_HR(CORDBG_E_CANNOT_DEBUG_FIBER_PROCESS) "Debugging fiber mode managed process is not supported."
+ MSG_FOR_URT_HR(CORDBG_E_MUST_BE_IN_CREATE_PROCESS) "Must be in context of CreateProcess callback to perform requested operation."
+ MSG_FOR_URT_HR(CORDBG_E_DETACH_FAILED_OUTSTANDING_EVALS) "All outstanding func-evals have not completed, detaching is not allowed at this time."
+ MSG_FOR_URT_HR(CORDBG_E_DETACH_FAILED_OUTSTANDING_STEPPERS) "All outstanding steppers have not been closed, detaching is not allowed at this time."
+ MSG_FOR_URT_HR(CORDBG_E_CANT_INTEROP_STEP_OUT) "Cannot have an ICorDebugStepper do a native step-out."
+ MSG_FOR_URT_HR(CORDBG_E_DETACH_FAILED_OUTSTANDING_BREAKPOINTS) "All outstanding breakpoints have not been closed, detaching is not allowed at this time."
+ MSG_FOR_URT_HR(CORDBG_E_ILLEGAL_IN_STACK_OVERFLOW) "The operation is illegal because of a stack overflow."
+ MSG_FOR_URT_HR(CORDBG_E_ILLEGAL_AT_GC_UNSAFE_POINT) "The operation failed because it is a GC unsafe point."
+ MSG_FOR_URT_HR(CORDBG_E_ILLEGAL_IN_PROLOG) "The operation failed because the thread is in the prolog."
+ MSG_FOR_URT_HR(CORDBG_E_ILLEGAL_IN_NATIVE_CODE) "The operation failed because the thread is in native code."
+ MSG_FOR_URT_HR(CORDBG_E_ILLEGAL_IN_OPTIMIZED_CODE) "The operation failed because the thread is in optimized code."
+ MSG_FOR_URT_HR(CORDBG_E_MINIDUMP_UNSUPPORTED) "The information requested is not supported by minidumps."
+ MSG_FOR_URT_HR(CORDBG_E_APPDOMAIN_MISMATCH) "A supplied object or type belongs to the wrong AppDomain."
+ MSG_FOR_URT_HR(CORDBG_E_CONTEXT_UNVAILABLE) "The thread's context is not available."
+ MSG_FOR_URT_HR(CORDBG_E_UNCOMPATIBLE_PLATFORMS) "The operation failed because debuggee and debugger are on incompatible platforms."
+ MSG_FOR_URT_HR(CORDBG_E_DEBUGGING_DISABLED) "The operation failed because the debugging has been disabled"
+ MSG_FOR_URT_HR(CORDBG_E_DETACH_FAILED_ON_ENC) "Detach is illegal after an Edit and Continue on a module."
+ MSG_FOR_URT_HR(CORDBG_E_CURRENT_EXCEPTION_IS_OUTSIDE_CURRENT_EXECUTION_SCOPE) "Cannot intercept the current exception at the specified frame."
+ MSG_FOR_URT_HR(CORDBG_E_HELPER_MAY_DEADLOCK) "The debugger helper thread cannot obtain the locks it needs to perform this operation."
+ MSG_FOR_URT_HR(CORDBG_E_MISSING_METADATA) "The operation failed because the debugger could not get the metadata."
+ MSG_FOR_URT_HR(CORDBG_E_TARGET_INCONSISTENT) "The debuggee is in a corrupt state."
+ MSG_FOR_URT_HR(CORDBG_E_DETACH_FAILED_OUTSTANDING_TARGET_RESOURCES) "Detach failed because there are outstanding resources in the target."
+ MSG_FOR_URT_HR(CORDBG_E_TARGET_READONLY) "The debuggee is read-only."
+ MSG_FOR_URT_HR(CORDBG_E_MISMATCHED_CORWKS_AND_DACWKS_DLLS) "The version of clr.dll in the target does not match the one mscordacwks.dll was built for."
+ MSG_FOR_URT_HR(CORDBG_E_MODULE_LOADED_FROM_DISK) "Symbols are not supplied for modules loaded from disk."
+ MSG_FOR_URT_HR(CORDBG_E_SYMBOLS_NOT_AVAILABLE) "The application did not supply symbols when it loaded or created this module, or they are not yet available."
+ MSG_FOR_URT_HR(CORDBG_E_DEBUG_COMPONENT_MISSING) "A debug component is not installed."
+ MSG_FOR_URT_HR(CORDBG_E_REMOTE_MISMATCHED_CERTS) "Connection authentication failed due to mismatched certificates."
+ MSG_FOR_URT_HR(CORDBG_E_REMOTE_NETWORK_FAILURE) "Connection failed due to a miscellaneous network error."
+ MSG_FOR_URT_HR(CORDBG_E_REMOTE_NO_LISTENER) "Connection failed due to no endpoint at remote machine (no proxy configured?)."
+ MSG_FOR_URT_HR(CORDBG_E_REMOTE_UNKNOWN_TARGET) "Connection failed due to inability to locate remote machine."
+ MSG_FOR_URT_HR(CORDBG_E_REMOTE_INVALID_CONFIG) "Local debugger configuration was missing or invalid."
+ MSG_FOR_URT_HR(CORDBG_E_REMOTE_MISMATCHED_PROTOCOLS) "Connection failed due to protocol version mismatch between local and remote components."
+ MSG_FOR_URT_HR(CORDBG_E_LIBRARY_PROVIDER_ERROR) "The ICLRDebuggingLibraryProvider callback returned an error or did not provide a valid handle."
+ MSG_FOR_URT_HR(CORDBG_E_NOT_CLR) "The module at the base address indicated was not recognized as a CLR"
+ MSG_FOR_URT_HR(CORDBG_E_MISSING_DATA_TARGET_INTERFACE) "The provided data target does not implement the required interfaces for this version of the runtime"
+ MSG_FOR_URT_HR(CORDBG_E_UNSUPPORTED_DEBUGGING_MODEL) "This debugging model is unsupported by the specified runtime"
+ MSG_FOR_URT_HR(CORDBG_E_UNSUPPORTED_FORWARD_COMPAT) "The debugger is not designed to support the version of the CLR the debuggee is using."
+ MSG_FOR_URT_HR(CORDBG_E_UNSUPPORTED_VERSION_STRUCT) "The version struct has an unrecognized value for wStructVersion"
+ MSG_FOR_URT_HR(CORDBG_E_READVIRTUAL_FAILURE) "A call into a ReadVirtual implementation returned failure"
+ MSG_FOR_URT_HR(CORDBG_E_VALUE_POINTS_TO_FUNCTION) "The Debugging API doesn't support dereferencing function pointers."
+ MSG_FOR_URT_HR(CORDBG_E_CORRUPT_OBJECT) "The address provided does not point to a valid managed object."
+ MSG_FOR_URT_HR(CORDBG_E_GC_STRUCTURES_INVALID) "The GC heap structures are not in a valid state for traversal."
+ MSG_FOR_URT_HR(CORDBG_E_INVALID_OPCODE) "The specified IL offset or opcode is not supported for this operation."
+ MSG_FOR_URT_HR(CORDBG_E_UNSUPPORTED) "The specified action is unsupported by this version of the runtime."
+ MSG_FOR_URT_HR(CORDBG_E_MISSING_DEBUGGER_EXPORTS) "The debuggee memory space does not have the expected debugging export table."
+ MSG_FOR_URT_HR(CORDBG_E_DATA_TARGET_ERROR) "Failure when calling a data target method."
+ MSG_FOR_URT_HR(CORDBG_E_CODE_HAS_NO_METADATA) "Couldn't find metadata for the given executable code."
+ MSG_FOR_URT_HR(CORDBG_E_CODE_UNRECOGNIZED) "Given executable code is not managed."
+ MSG_FOR_URT_HR(CORDBG_E_NO_IMAGE_AVAILABLE) "Couldn't find a native image."
+ MSG_FOR_URT_HR(CORDBG_E_TYPE_NOT_FOUND) "The type doesn't exist in the given module."
+ MSG_FOR_URT_HR(CORDBG_E_VTABLE_HAS_NO_METADATA) "Couldn't find metadata for the given vtable."
+ MSG_FOR_URT_HR(CORDBG_E_NO_GENERIC_INFO) "Couldn't find any generics information."
+ MSG_FOR_URT_HR(PEFMT_E_NO_CONTENTS) "File is empty."
+ MSG_FOR_URT_HR(PEFMT_E_NO_NTHEADERS) "File has no NT headers."
+ MSG_FOR_URT_HR(PEFMT_E_64BIT) "File is PE32+."
+ MSG_FOR_URT_HR(PEFMT_E_NO_CORHEADER) "File has no COR header."
+ MSG_FOR_URT_HR(PEFMT_E_NOT_ILONLY) "Flag IL_ONLY not set."
+ MSG_FOR_URT_HR(PEFMT_E_IMPORT_DLLS) "Bad import DLLs."
+ MSG_FOR_URT_HR(PEFMT_E_EXE_NOENTRYPOINT) "EXE file has no mgd entry point."
+ MSG_FOR_URT_HR(PEFMT_E_BASE_RELOCS) "Bad base relocations."
+ MSG_FOR_URT_HR(PEFMT_E_ENTRYPOINT) "Bad managed entry point."
+ MSG_FOR_URT_HR(PEFMT_E_ZERO_SIZEOFCODE) "OptHeader.SizeOfCode is set to zero."
+ MSG_FOR_URT_HR(PEFMT_E_BAD_CORHEADER) "File has invalid COR header."
+ MSG_FOR_URT_HR(PEFMT_E_32BIT) "File is PE32"
+ MSG_FOR_URT_HR(CLR_OPTSVC_E_CONTROLLER_INTERRUPT) "The operation was interrupted by the CLR Optimization Service controller."
+ MSG_FOR_URT_HR(NGEN_FAILED_GET_DEPENDENCIES) "Failed to get dependencies for assembly."
+ MSG_FOR_URT_HR(NGEN_FAILED_NATIVE_IMAGE_DELETE) "Failed to delete native image."
+ MSG_FOR_URT_HR(NGEN_E_TOO_MANY_INTERFACES) "Module contains too many interfaces to successfully compile all methods."
+ MSG_FOR_URT_HR(NGEN_E_OLDER_RUNTIME) "Requested runtime does not support side-by-side NGen."
+ MSG_FOR_URT_HR(NGEN_E_WORKER_UNEXPECTED_EXIT) "Worker exited unexpectedly during startup"
+ MSG_FOR_URT_HR(NGEN_E_WORKER_UNEXPECTED_SYNC) "Failed to synchronize with worker during startup"
+ MSG_FOR_URT_HR(NGEN_E_SYS_ASM_NI_MISSING) "NGen cannot proceed because Mscorlib.dll does not have a native image"
+ MSG_FOR_URT_HR(NGEN_E_EXE_MACHINE_TYPE_MISMATCH) "The image file is not compatible with the version of Ngen you're running. Use 32bit Ngen for 32bit assemblies, and 64bit Ngen for 64bit assemblies."
+ MSG_FOR_URT_HR(NGEN_E_ASSEMBLY_EXCLUSION_FILE_PARSE_ERROR) "There was an error parsing the NGen assembly exclusion Xml file."
+ MSG_FOR_URT_HR(NGEN_E_HARDBOUND_DEPENDENCY_MISSING) "A hardbound dependent native image is missing."
+ MSG_FOR_URT_HR(NGEN_E_NOT_RUNNING_IN_EXPECTED_PACKAGE) "NGen is not running in expected package."
+ MSG_FOR_URT_HR(NGEN_E_FILE_NOT_ASSEMBLY) "The image being compiled is not a .NET assembly"
+ MSG_FOR_URT_HR(CLR_E_BIND_ASSEMBLY_VERSION_TOO_LOW) "The bound assembly has a version that is lower than that of the request."
+ MSG_FOR_URT_HR(CLR_E_BIND_ASSEMBLY_PUBLIC_KEY_MISMATCH) "The assembly version has a public key token that does not match that of the request."
+ MSG_FOR_URT_HR(CLR_E_BIND_IMAGE_UNAVAILABLE) "The requested image was not found or is unavailable."
+ MSG_FOR_URT_HR(CLR_E_BIND_UNRECOGNIZED_IDENTITY_FORMAT) "The provided identity format is not recognized."
+ MSG_FOR_URT_HR(CLR_E_BIND_ASSEMBLY_NOT_FOUND) "A binding for the specified assembly name was not found."
+ MSG_FOR_URT_HR(CLR_E_BIND_TYPE_NOT_FOUND) "A binding for the specified type name was not found."
+ MSG_FOR_URT_HR(CLR_E_BIND_SYS_ASM_NI_MISSING) "Could not use native image because Mscorlib.dll is missing a native image"
+ MSG_FOR_URT_HR(CLR_E_BIND_NI_SECURITY_FAILURE) "Native image was generated in a different trust level than present at runtime"
+ MSG_FOR_URT_HR(CLR_E_BIND_NI_DEP_IDENTITY_MISMATCH) "Native image identity mismatch with respect to its dependencies"
+ MSG_FOR_URT_HR(CLR_E_GC_OOM) "Failfast due to an OOM during a GC"
+ MSG_FOR_URT_HR(COR_E_BADIMAGEFORMAT) "The format of a DLL or executable being loaded is invalid."
+END
diff --git a/src/pal/prebuilt/corerror/readme.txt b/src/pal/prebuilt/corerror/readme.txt
new file mode 100644
index 0000000000..a21a724909
--- /dev/null
+++ b/src/pal/prebuilt/corerror/readme.txt
@@ -0,0 +1,7 @@
+Steps to generate corerror.h for the Unix:
+
+Open Razzle window
+tf edit ..\inc\corerror.h
+tf edit mscorurt.rc
+makecorerror.bat
+tf undo any files that didn't get modified \ No newline at end of file
diff --git a/src/pal/prebuilt/idl/clrdata_i.c b/src/pal/prebuilt/idl/clrdata_i.c
new file mode 100644
index 0000000000..bb9616a9f8
--- /dev/null
+++ b/src/pal/prebuilt/idl/clrdata_i.c
@@ -0,0 +1,91 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+
+
+/* this ALWAYS GENERATED file contains the IIDs and CLSIDs */
+
+/* link this file in with the server and any clients */
+
+
+ /* File created by MIDL compiler version 8.00.0603 */
+/* @@MIDL_FILE_HEADING( ) */
+
+#pragma warning( disable: 4049 ) /* more than 64k source lines */
+
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+
+#include <rpc.h>
+#include <rpcndr.h>
+
+#ifdef _MIDL_USE_GUIDDEF_
+
+#ifndef INITGUID
+#define INITGUID
+#include <guiddef.h>
+#undef INITGUID
+#else
+#include <guiddef.h>
+#endif
+
+#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
+ DEFINE_GUID(name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8)
+
+#else // !_MIDL_USE_GUIDDEF_
+
+#ifndef __IID_DEFINED__
+#define __IID_DEFINED__
+
+typedef struct _IID
+{
+ unsigned long x;
+ unsigned short s1;
+ unsigned short s2;
+ unsigned char c[8];
+} IID;
+
+#endif // __IID_DEFINED__
+
+#ifndef CLSID_DEFINED
+#define CLSID_DEFINED
+typedef IID CLSID;
+#endif // CLSID_DEFINED
+
+#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
+ const type name = {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}}
+
+#endif !_MIDL_USE_GUIDDEF_
+
+MIDL_DEFINE_GUID(IID, IID_ICLRDataTarget,0x3E11CCEE,0xD08B,0x43e5,0xAF,0x01,0x32,0x71,0x7A,0x64,0xDA,0x03);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICLRDataTarget2,0x6d05fae3,0x189c,0x4630,0xa6,0xdc,0x1c,0x25,0x1e,0x1c,0x01,0xab);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICLRDataTarget3,0xa5664f95,0x0af4,0x4a1b,0x96,0x0e,0x2f,0x33,0x46,0xb4,0x21,0x4c);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICLRMetadataLocator,0xaa8fa804,0xbc05,0x4642,0xb2,0xc5,0xc3,0x53,0xed,0x22,0xfc,0x63);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICLRDataEnumMemoryRegionsCallback,0xBCDD6908,0xBA2D,0x4ec5,0x96,0xCF,0xDF,0x4D,0x5C,0xDC,0xB4,0xA4);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICLRDataEnumMemoryRegionsCallback2,0x3721A26F,0x8B91,0x4D98,0xA3,0x88,0xDB,0x17,0xB3,0x56,0xFA,0xDB);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICLRDataEnumMemoryRegions,0x471c35b4,0x7c2f,0x4ef0,0xa9,0x45,0x00,0xf8,0xc3,0x80,0x56,0xf1);
+
+#undef MIDL_DEFINE_GUID
+
+#ifdef __cplusplus
+}
+#endif
+
+
+
diff --git a/src/pal/prebuilt/idl/clrinternal_i.c b/src/pal/prebuilt/idl/clrinternal_i.c
new file mode 100644
index 0000000000..58a16672cf
--- /dev/null
+++ b/src/pal/prebuilt/idl/clrinternal_i.c
@@ -0,0 +1,79 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+
+
+/* this ALWAYS GENERATED file contains the IIDs and CLSIDs */
+
+/* link this file in with the server and any clients */
+
+
+ /* File created by MIDL compiler version 8.00.0603 */
+/* @@MIDL_FILE_HEADING( ) */
+
+#pragma warning( disable: 4049 ) /* more than 64k source lines */
+
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+
+#include <rpc.h>
+#include <rpcndr.h>
+
+#ifdef _MIDL_USE_GUIDDEF_
+
+#ifndef INITGUID
+#define INITGUID
+#include <guiddef.h>
+#undef INITGUID
+#else
+#include <guiddef.h>
+#endif
+
+#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
+ DEFINE_GUID(name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8)
+
+#else // !_MIDL_USE_GUIDDEF_
+
+#ifndef __IID_DEFINED__
+#define __IID_DEFINED__
+
+typedef struct _IID
+{
+ unsigned long x;
+ unsigned short s1;
+ unsigned short s2;
+ unsigned char c[8];
+} IID;
+
+#endif // __IID_DEFINED__
+
+#ifndef CLSID_DEFINED
+#define CLSID_DEFINED
+typedef IID CLSID;
+#endif // CLSID_DEFINED
+
+#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
+ const type name = {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}}
+
+#endif !_MIDL_USE_GUIDDEF_
+
+MIDL_DEFINE_GUID(IID, IID_IExecutionEngine,0x7AF02DAC,0x2A33,0x494b,0xA0,0x9F,0x25,0xE0,0x0A,0x93,0xC6,0xF8);
+
+
+MIDL_DEFINE_GUID(IID, IID_IEEMemoryManager,0x17713B61,0xB59F,0x4e13,0xBA,0xAF,0x91,0x62,0x3D,0xC8,0xAD,0xC0);
+
+
+MIDL_DEFINE_GUID(IID, IID_IPrivateManagedExceptionReporting,0xAD76A023,0x332D,0x4298,0x80,0x01,0x07,0xAA,0x93,0x50,0xDC,0xA4);
+
+#undef MIDL_DEFINE_GUID
+
+#ifdef __cplusplus
+}
+#endif
+
+
+
diff --git a/src/pal/prebuilt/idl/clrprivappxhosting_i.c b/src/pal/prebuilt/idl/clrprivappxhosting_i.c
new file mode 100644
index 0000000000..c46d033d1a
--- /dev/null
+++ b/src/pal/prebuilt/idl/clrprivappxhosting_i.c
@@ -0,0 +1,76 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+
+
+/* this ALWAYS GENERATED file contains the IIDs and CLSIDs */
+
+/* link this file in with the server and any clients */
+
+
+ /* File created by MIDL compiler version 8.00.0603 */
+/* @@MIDL_FILE_HEADING( ) */
+
+#pragma warning( disable: 4049 ) /* more than 64k source lines */
+
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+
+#include <rpc.h>
+#include <rpcndr.h>
+
+#ifdef _MIDL_USE_GUIDDEF_
+
+#ifndef INITGUID
+#define INITGUID
+#include <guiddef.h>
+#undef INITGUID
+#else
+#include <guiddef.h>
+#endif
+
+#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
+ DEFINE_GUID(name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8)
+
+#else // !_MIDL_USE_GUIDDEF_
+
+#ifndef __IID_DEFINED__
+#define __IID_DEFINED__
+
+typedef struct _IID
+{
+ unsigned long x;
+ unsigned short s1;
+ unsigned short s2;
+ unsigned char c[8];
+} IID;
+
+#endif // __IID_DEFINED__
+
+#ifndef CLSID_DEFINED
+#define CLSID_DEFINED
+typedef IID CLSID;
+#endif // CLSID_DEFINED
+
+#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
+ const type name = {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}}
+
+#endif !_MIDL_USE_GUIDDEF_
+
+MIDL_DEFINE_GUID(IID, IID_ICLRPrivAppXRuntime,0x6D2DF5A4,0xFA3A,0x4481,0x8B,0xA0,0x04,0x22,0xFD,0x21,0x72,0x0F);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICLRPrivAppXDomain,0x6633398E,0x823D,0x4361,0xB3,0x0E,0x82,0x40,0x43,0xBD,0x46,0x86);
+
+#undef MIDL_DEFINE_GUID
+
+#ifdef __cplusplus
+}
+#endif
+
+
+
diff --git a/src/pal/prebuilt/idl/clrprivbinding_i.c b/src/pal/prebuilt/idl/clrprivbinding_i.c
new file mode 100644
index 0000000000..ee08cc3583
--- /dev/null
+++ b/src/pal/prebuilt/idl/clrprivbinding_i.c
@@ -0,0 +1,100 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+
+
+/* this ALWAYS GENERATED file contains the IIDs and CLSIDs */
+
+/* link this file in with the server and any clients */
+
+
+ /* File created by MIDL compiler version 8.00.0603 */
+/* @@MIDL_FILE_HEADING( ) */
+
+#pragma warning( disable: 4049 ) /* more than 64k source lines */
+
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+
+#include <rpc.h>
+#include <rpcndr.h>
+
+#ifdef _MIDL_USE_GUIDDEF_
+
+#ifndef INITGUID
+#define INITGUID
+#include <guiddef.h>
+#undef INITGUID
+#else
+#include <guiddef.h>
+#endif
+
+#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
+ DEFINE_GUID(name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8)
+
+#else // !_MIDL_USE_GUIDDEF_
+
+#ifndef __IID_DEFINED__
+#define __IID_DEFINED__
+
+typedef struct _IID
+{
+ unsigned long x;
+ unsigned short s1;
+ unsigned short s2;
+ unsigned char c[8];
+} IID;
+
+#endif // __IID_DEFINED__
+
+#ifndef CLSID_DEFINED
+#define CLSID_DEFINED
+typedef IID CLSID;
+#endif // CLSID_DEFINED
+
+#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
+ const type name = {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}}
+
+#endif !_MIDL_USE_GUIDDEF_
+
+MIDL_DEFINE_GUID(IID, IID_ICLRPrivBinder,0x2601F621,0xE462,0x404C,0xB2,0x99,0x3E,0x1D,0xE7,0x2F,0x85,0x42);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICLRPrivAssembly,0x2601F621,0xE462,0x404C,0xB2,0x99,0x3E,0x1D,0xE7,0x2F,0x85,0x43);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICLRPrivResource,0x2601F621,0xE462,0x404C,0xB2,0x99,0x3E,0x1D,0xE7,0x2F,0x85,0x47);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICLRPrivResourcePath,0x2601F621,0xE462,0x404C,0xB2,0x99,0x3E,0x1D,0xE7,0x2F,0x85,0x44);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICLRPrivResourceStream,0x2601F621,0xE462,0x404C,0xB2,0x99,0x3E,0x1D,0xE7,0x2F,0x85,0x45);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICLRPrivResourceHMODULE,0x2601F621,0xE462,0x404C,0xB2,0x99,0x3E,0x1D,0xE7,0x2F,0x85,0x46);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICLRPrivResourceAssembly,0x8d2d3cc9,0x1249,0x4ad4,0x97,0x7d,0xb7,0x72,0xbd,0x4e,0x8a,0x94);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICLRPrivAssemblyInfo,0x5653946E,0x800B,0x48B7,0x8B,0x09,0xB1,0xB8,0x79,0xB5,0x4F,0x68);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICLRPrivAssemblyID_WinRT,0x4372D277,0x9906,0x4FED,0xBF,0x53,0x30,0xC0,0xB4,0x01,0x08,0x96);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICLRPrivWinRtTypeBinder,0x6DE2A085,0xEFF4,0x4078,0x9F,0x60,0xB9,0xD3,0x66,0x73,0x63,0x98);
+
+#undef MIDL_DEFINE_GUID
+
+#ifdef __cplusplus
+}
+#endif
+
+
+
diff --git a/src/pal/prebuilt/idl/clrprivhosting_i.c b/src/pal/prebuilt/idl/clrprivhosting_i.c
new file mode 100644
index 0000000000..07a40b290e
--- /dev/null
+++ b/src/pal/prebuilt/idl/clrprivhosting_i.c
@@ -0,0 +1,79 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+
+
+/* this ALWAYS GENERATED file contains the IIDs and CLSIDs */
+
+/* link this file in with the server and any clients */
+
+
+ /* File created by MIDL compiler version 8.00.0603 */
+/* @@MIDL_FILE_HEADING( ) */
+
+#pragma warning( disable: 4049 ) /* more than 64k source lines */
+
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+
+#include <rpc.h>
+#include <rpcndr.h>
+
+#ifdef _MIDL_USE_GUIDDEF_
+
+#ifndef INITGUID
+#define INITGUID
+#include <guiddef.h>
+#undef INITGUID
+#else
+#include <guiddef.h>
+#endif
+
+#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
+ DEFINE_GUID(name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8)
+
+#else // !_MIDL_USE_GUIDDEF_
+
+#ifndef __IID_DEFINED__
+#define __IID_DEFINED__
+
+typedef struct _IID
+{
+ unsigned long x;
+ unsigned short s1;
+ unsigned short s2;
+ unsigned char c[8];
+} IID;
+
+#endif // __IID_DEFINED__
+
+#ifndef CLSID_DEFINED
+#define CLSID_DEFINED
+typedef IID CLSID;
+#endif // CLSID_DEFINED
+
+#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
+ const type name = {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}}
+
+#endif !_MIDL_USE_GUIDDEF_
+
+MIDL_DEFINE_GUID(IID, LIBID_CLRPrivHosting,0xEDA73987,0xE6C0,0x42BF,0xA6,0xB7,0x07,0x3F,0x7B,0x24,0xD8,0xC7);
+
+
+MIDL_DEFINE_GUID(CLSID, CLSID_CLRPrivRuntime,0xBC1B53A8,0xDCBC,0x43B2,0xBB,0x17,0x1E,0x40,0x61,0x44,0x7A,0xE8);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICLRPrivRuntime,0xBC1B53A8,0xDCBC,0x43B2,0xBB,0x17,0x1E,0x40,0x61,0x44,0x7A,0xE9);
+
+#undef MIDL_DEFINE_GUID
+
+#ifdef __cplusplus
+}
+#endif
+
+
+
diff --git a/src/pal/prebuilt/idl/clrprivruntimebinders_i.c b/src/pal/prebuilt/idl/clrprivruntimebinders_i.c
new file mode 100644
index 0000000000..0fe4a180df
--- /dev/null
+++ b/src/pal/prebuilt/idl/clrprivruntimebinders_i.c
@@ -0,0 +1,79 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+
+
+/* this ALWAYS GENERATED file contains the IIDs and CLSIDs */
+
+/* link this file in with the server and any clients */
+
+
+ /* File created by MIDL compiler version 8.00.0603 */
+/* @@MIDL_FILE_HEADING( ) */
+
+#pragma warning( disable: 4049 ) /* more than 64k source lines */
+
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+
+#include <rpc.h>
+#include <rpcndr.h>
+
+#ifdef _MIDL_USE_GUIDDEF_
+
+#ifndef INITGUID
+#define INITGUID
+#include <guiddef.h>
+#undef INITGUID
+#else
+#include <guiddef.h>
+#endif
+
+#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
+ DEFINE_GUID(name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8)
+
+#else // !_MIDL_USE_GUIDDEF_
+
+#ifndef __IID_DEFINED__
+#define __IID_DEFINED__
+
+typedef struct _IID
+{
+ unsigned long x;
+ unsigned short s1;
+ unsigned short s2;
+ unsigned char c[8];
+} IID;
+
+#endif // __IID_DEFINED__
+
+#ifndef CLSID_DEFINED
+#define CLSID_DEFINED
+typedef IID CLSID;
+#endif // CLSID_DEFINED
+
+#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
+ const type name = {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}}
+
+#endif !_MIDL_USE_GUIDDEF_
+
+MIDL_DEFINE_GUID(IID, LIBID_CLRPrivRuntimeBinders,0xEA6A2170,0x8F6A,0x4007,0x87,0xA9,0x02,0x42,0x9F,0x61,0x59,0x58);
+
+
+MIDL_DEFINE_GUID(CLSID, CLSID_CLRPrivAppXBinder,0xE990F732,0x2D0A,0x48AC,0x87,0xFC,0xEF,0x12,0xB6,0x18,0x98,0x1A);
+
+
+MIDL_DEFINE_GUID(CLSID, CLSID_CLRPrivFusionBinder,0xE990F732,0x2D0A,0x48AC,0x87,0xFC,0xEF,0x12,0xB6,0x18,0x98,0x1C);
+
+#undef MIDL_DEFINE_GUID
+
+#ifdef __cplusplus
+}
+#endif
+
+
+
diff --git a/src/pal/prebuilt/idl/cordebug_i.c b/src/pal/prebuilt/idl/cordebug_i.c
new file mode 100644
index 0000000000..e3c8d2edcb
--- /dev/null
+++ b/src/pal/prebuilt/idl/cordebug_i.c
@@ -0,0 +1,451 @@
+
+
+/* this ALWAYS GENERATED file contains the IIDs and CLSIDs */
+
+/* link this file in with the server and any clients */
+
+
+ /* File created by MIDL compiler version 8.00.0613 */
+/* at Mon Jan 18 19:14:07 2038
+ */
+/* Compiler settings for C:/ssd/coreclr/src/inc/cordebug.idl:
+ Oicf, W1, Zp8, env=Win32 (32b run), target_arch=X86 8.00.0613
+ protocol : dce , ms_ext, c_ext, robust
+ error checks: allocation ref bounds_check enum stub_data
+ VC __declspec() decoration level:
+ __declspec(uuid()), __declspec(selectany), __declspec(novtable)
+ DECLSPEC_UUID(), MIDL_INTERFACE()
+*/
+/* @@MIDL_FILE_HEADING( ) */
+
+#pragma warning( disable: 4049 ) /* more than 64k source lines */
+
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+
+#include <rpc.h>
+#include <rpcndr.h>
+
+#ifdef _MIDL_USE_GUIDDEF_
+
+#ifndef INITGUID
+#define INITGUID
+#include <guiddef.h>
+#undef INITGUID
+#else
+#include <guiddef.h>
+#endif
+
+#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
+ DEFINE_GUID(name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8)
+
+#else // !_MIDL_USE_GUIDDEF_
+
+#ifndef __IID_DEFINED__
+#define __IID_DEFINED__
+
+typedef struct _IID
+{
+ unsigned long x;
+ unsigned short s1;
+ unsigned short s2;
+ unsigned char c[8];
+} IID;
+
+#endif // __IID_DEFINED__
+
+#ifndef CLSID_DEFINED
+#define CLSID_DEFINED
+typedef IID CLSID;
+#endif // CLSID_DEFINED
+
+#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
+ const type name = {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}}
+
+#endif !_MIDL_USE_GUIDDEF_
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugDataTarget,0xFE06DC28,0x49FB,0x4636,0xA4,0xA3,0xE8,0x0D,0xB4,0xAE,0x11,0x6C);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugStaticFieldSymbol,0xCBF9DA63,0xF68D,0x4BBB,0xA2,0x1C,0x15,0xA4,0x5E,0xAA,0xDF,0x5B);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugInstanceFieldSymbol,0xA074096B,0x3ADC,0x4485,0x81,0xDA,0x68,0xC7,0xA4,0xEA,0x52,0xDB);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugVariableSymbol,0x707E8932,0x1163,0x48D9,0x8A,0x93,0xF5,0xB1,0xF4,0x80,0xFB,0xB7);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugMemoryBuffer,0x677888B3,0xD160,0x4B8C,0xA7,0x3B,0xD7,0x9E,0x6A,0xAA,0x1D,0x13);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugMergedAssemblyRecord,0xFAA8637B,0x3BBE,0x4671,0x8E,0x26,0x3B,0x59,0x87,0x5B,0x92,0x2A);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugSymbolProvider,0x3948A999,0xFD8A,0x4C38,0xA7,0x08,0x8A,0x71,0xE9,0xB0,0x4D,0xBB);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugSymbolProvider2,0xF9801807,0x4764,0x4330,0x9E,0x67,0x4F,0x68,0x50,0x94,0x16,0x5E);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugVirtualUnwinder,0xF69126B7,0xC787,0x4F6B,0xAE,0x96,0xA5,0x69,0x78,0x6F,0xC6,0x70);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugDataTarget2,0x2eb364da,0x605b,0x4e8d,0xb3,0x33,0x33,0x94,0xc4,0x82,0x8d,0x41);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugLoadedModule,0x817F343A,0x6630,0x4578,0x96,0xC5,0xD1,0x1B,0xC0,0xEC,0x5E,0xE2);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugDataTarget3,0xD05E60C3,0x848C,0x4E7D,0x89,0x4E,0x62,0x33,0x20,0xFF,0x6A,0xFA);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugDataTarget4,0xE799DC06,0xE099,0x4713,0xBD,0xD9,0x90,0x6D,0x3C,0xC0,0x2C,0xF2);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugMutableDataTarget,0xA1B8A756,0x3CB6,0x4CCB,0x97,0x9F,0x3D,0xF9,0x99,0x67,0x3A,0x59);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugMetaDataLocator,0x7cef8ba9,0x2ef7,0x42bf,0x97,0x3f,0x41,0x71,0x47,0x4f,0x87,0xd9);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugManagedCallback,0x3d6f5f60,0x7538,0x11d3,0x8d,0x5b,0x00,0x10,0x4b,0x35,0xe7,0xef);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugManagedCallback3,0x264EA0FC,0x2591,0x49AA,0x86,0x8E,0x83,0x5E,0x65,0x15,0x32,0x3F);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugManagedCallback2,0x250E5EEA,0xDB5C,0x4C76,0xB6,0xF3,0x8C,0x46,0xF1,0x2E,0x32,0x03);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugUnmanagedCallback,0x5263E909,0x8CB5,0x11d3,0xBD,0x2F,0x00,0x00,0xF8,0x08,0x49,0xBD);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebug,0x3d6f5f61,0x7538,0x11d3,0x8d,0x5b,0x00,0x10,0x4b,0x35,0xe7,0xef);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugRemoteTarget,0xC3ED8383,0x5A49,0x4cf5,0xB4,0xB7,0x01,0x86,0x4D,0x9E,0x58,0x2D);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugRemote,0xD5EBB8E2,0x7BBE,0x4c1d,0x98,0xA6,0xA3,0xC0,0x4C,0xBD,0xEF,0x64);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebug2,0xECCCCF2E,0xB286,0x4b3e,0xA9,0x83,0x86,0x0A,0x87,0x93,0xD1,0x05);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugController,0x3d6f5f62,0x7538,0x11d3,0x8d,0x5b,0x00,0x10,0x4b,0x35,0xe7,0xef);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugAppDomain,0x3d6f5f63,0x7538,0x11d3,0x8d,0x5b,0x00,0x10,0x4b,0x35,0xe7,0xef);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugAppDomain2,0x096E81D5,0xECDA,0x4202,0x83,0xF5,0xC6,0x59,0x80,0xA9,0xEF,0x75);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugEnum,0xCC7BCB01,0x8A68,0x11d2,0x98,0x3C,0x00,0x00,0xF8,0x08,0x34,0x2D);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugGuidToTypeEnum,0x6164D242,0x1015,0x4BD6,0x8C,0xBE,0xD0,0xDB,0xD4,0xB8,0x27,0x5A);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugAppDomain3,0x8CB96A16,0xB588,0x42E2,0xB7,0x1C,0xDD,0x84,0x9F,0xC2,0xEC,0xCC);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugAppDomain4,0xFB99CC40,0x83BE,0x4724,0xAB,0x3B,0x76,0x8E,0x79,0x6E,0xBA,0xC2);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugAssembly,0xdf59507c,0xd47a,0x459e,0xbc,0xe2,0x64,0x27,0xea,0xc8,0xfd,0x06);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugAssembly2,0x426d1f9e,0x6dd4,0x44c8,0xae,0xc7,0x26,0xcd,0xba,0xf4,0xe3,0x98);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugAssembly3,0x76361AB2,0x8C86,0x4FE9,0x96,0xF2,0xF7,0x3D,0x88,0x43,0x57,0x0A);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugHeapEnum,0x76D7DAB8,0xD044,0x11DF,0x9A,0x15,0x7E,0x29,0xDF,0xD7,0x20,0x85);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugHeapSegmentEnum,0xA2FA0F8E,0xD045,0x11DF,0xAC,0x8E,0xCE,0x2A,0xDF,0xD7,0x20,0x85);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugGCReferenceEnum,0x7F3C24D3,0x7E1D,0x4245,0xAC,0x3A,0xF7,0x2F,0x88,0x59,0xC8,0x0C);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugProcess,0x3d6f5f64,0x7538,0x11d3,0x8d,0x5b,0x00,0x10,0x4b,0x35,0xe7,0xef);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugProcess2,0xAD1B3588,0x0EF0,0x4744,0xA4,0x96,0xAA,0x09,0xA9,0xF8,0x03,0x71);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugProcess3,0x2EE06488,0xC0D4,0x42B1,0xB2,0x6D,0xF3,0x79,0x5E,0xF6,0x06,0xFB);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugProcess5,0x21e9d9c0,0xfcb8,0x11df,0x8c,0xff,0x08,0x00,0x20,0x0c,0x9a,0x66);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugDebugEvent,0x41BD395D,0xDE99,0x48F1,0xBF,0x7A,0xCC,0x0F,0x44,0xA6,0xD2,0x81);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugProcess6,0x11588775,0x7205,0x4CEB,0xA4,0x1A,0x93,0x75,0x3C,0x31,0x53,0xE9);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugProcess7,0x9B2C54E4,0x119F,0x4D6F,0xB4,0x02,0x52,0x76,0x03,0x26,0x6D,0x69);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugProcess8,0x2E6F28C1,0x85EB,0x4141,0x80,0xAD,0x0A,0x90,0x94,0x4B,0x96,0x39);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugModuleDebugEvent,0x51A15E8D,0x9FFF,0x4864,0x9B,0x87,0xF4,0xFB,0xDE,0xA7,0x47,0xA2);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugExceptionDebugEvent,0xAF79EC94,0x4752,0x419C,0xA6,0x26,0x5F,0xB1,0xCC,0x1A,0x5A,0xB7);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugBreakpoint,0xCC7BCAE8,0x8A68,0x11d2,0x98,0x3C,0x00,0x00,0xF8,0x08,0x34,0x2D);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugFunctionBreakpoint,0xCC7BCAE9,0x8A68,0x11d2,0x98,0x3C,0x00,0x00,0xF8,0x08,0x34,0x2D);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugModuleBreakpoint,0xCC7BCAEA,0x8A68,0x11d2,0x98,0x3C,0x00,0x00,0xF8,0x08,0x34,0x2D);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugValueBreakpoint,0xCC7BCAEB,0x8A68,0x11d2,0x98,0x3C,0x00,0x00,0xF8,0x08,0x34,0x2D);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugStepper,0xCC7BCAEC,0x8A68,0x11d2,0x98,0x3C,0x00,0x00,0xF8,0x08,0x34,0x2D);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugStepper2,0xC5B6E9C3,0xE7D1,0x4a8e,0x87,0x3B,0x7F,0x04,0x7F,0x07,0x06,0xF7);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugRegisterSet,0xCC7BCB0B,0x8A68,0x11d2,0x98,0x3C,0x00,0x00,0xF8,0x08,0x34,0x2D);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugRegisterSet2,0x6DC7BA3F,0x89BA,0x4459,0x9E,0xC1,0x9D,0x60,0x93,0x7B,0x46,0x8D);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugThread,0x938c6d66,0x7fb6,0x4f69,0xb3,0x89,0x42,0x5b,0x89,0x87,0x32,0x9b);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugThread2,0x2BD956D9,0x7B07,0x4bef,0x8A,0x98,0x12,0xAA,0x86,0x24,0x17,0xC5);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugThread3,0xF8544EC3,0x5E4E,0x46c7,0x8D,0x3E,0xA5,0x2B,0x84,0x05,0xB1,0xF5);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugThread4,0x1A1F204B,0x1C66,0x4637,0x82,0x3F,0x3E,0xE6,0xC7,0x44,0xA6,0x9C);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugStackWalk,0xA0647DE9,0x55DE,0x4816,0x92,0x9C,0x38,0x52,0x71,0xC6,0x4C,0xF7);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugChain,0xCC7BCAEE,0x8A68,0x11d2,0x98,0x3C,0x00,0x00,0xF8,0x08,0x34,0x2D);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugFrame,0xCC7BCAEF,0x8A68,0x11d2,0x98,0x3C,0x00,0x00,0xF8,0x08,0x34,0x2D);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugInternalFrame,0xB92CC7F7,0x9D2D,0x45c4,0xBC,0x2B,0x62,0x1F,0xCC,0x9D,0xFB,0xF4);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugInternalFrame2,0xC0815BDC,0xCFAB,0x447e,0xA7,0x79,0xC1,0x16,0xB4,0x54,0xEB,0x5B);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugILFrame,0x03E26311,0x4F76,0x11d3,0x88,0xC6,0x00,0x60,0x97,0x94,0x54,0x18);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugILFrame2,0x5D88A994,0x6C30,0x479b,0x89,0x0F,0xBC,0xEF,0x88,0xB1,0x29,0xA5);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugILFrame3,0x9A9E2ED6,0x04DF,0x4FE0,0xBB,0x50,0xCA,0xB6,0x41,0x26,0xAD,0x24);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugILFrame4,0xAD914A30,0xC6D1,0x4AC5,0x9C,0x5E,0x57,0x7F,0x3B,0xAA,0x8A,0x45);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugNativeFrame,0x03E26314,0x4F76,0x11d3,0x88,0xC6,0x00,0x60,0x97,0x94,0x54,0x18);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugNativeFrame2,0x35389FF1,0x3684,0x4c55,0xA2,0xEE,0x21,0x0F,0x26,0xC6,0x0E,0x5E);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugModule3,0x86F012BF,0xFF15,0x4372,0xBD,0x30,0xB6,0xF1,0x1C,0xAA,0xE1,0xDD);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugRuntimeUnwindableFrame,0x879CAC0A,0x4A53,0x4668,0xB8,0xE3,0xCB,0x84,0x73,0xCB,0x18,0x7F);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugModule,0xdba2d8c1,0xe5c5,0x4069,0x8c,0x13,0x10,0xa7,0xc6,0xab,0xf4,0x3d);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugModule2,0x7FCC5FB5,0x49C0,0x41de,0x99,0x38,0x3B,0x88,0xB5,0xB9,0xAD,0xD7);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugFunction,0xCC7BCAF3,0x8A68,0x11d2,0x98,0x3C,0x00,0x00,0xF8,0x08,0x34,0x2D);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugFunction2,0xEF0C490B,0x94C3,0x4e4d,0xB6,0x29,0xDD,0xC1,0x34,0xC5,0x32,0xD8);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugFunction3,0x09B70F28,0xE465,0x482D,0x99,0xE0,0x81,0xA1,0x65,0xEB,0x05,0x32);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugCode,0xCC7BCAF4,0x8A68,0x11d2,0x98,0x3C,0x00,0x00,0xF8,0x08,0x34,0x2D);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugCode2,0x5F696509,0x452F,0x4436,0xA3,0xFE,0x4D,0x11,0xFE,0x7E,0x23,0x47);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugCode3,0xD13D3E88,0xE1F2,0x4020,0xAA,0x1D,0x3D,0x16,0x2D,0xCB,0xE9,0x66);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugILCode,0x598D46C2,0xC877,0x42A7,0x89,0xD2,0x3D,0x0C,0x7F,0x1C,0x12,0x64);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugILCode2,0x46586093,0xD3F5,0x4DB6,0xAC,0xDB,0x95,0x5B,0xCE,0x22,0x8C,0x15);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugClass,0xCC7BCAF5,0x8A68,0x11d2,0x98,0x3C,0x00,0x00,0xF8,0x08,0x34,0x2D);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugClass2,0xB008EA8D,0x7AB1,0x43f7,0xBB,0x20,0xFB,0xB5,0xA0,0x40,0x38,0xAE);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugEval,0xCC7BCAF6,0x8A68,0x11d2,0x98,0x3C,0x00,0x00,0xF8,0x08,0x34,0x2D);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugEval2,0xFB0D9CE7,0xBE66,0x4683,0x9D,0x32,0xA4,0x2A,0x04,0xE2,0xFD,0x91);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugValue,0xCC7BCAF7,0x8A68,0x11d2,0x98,0x3C,0x00,0x00,0xF8,0x08,0x34,0x2D);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugValue2,0x5E0B54E7,0xD88A,0x4626,0x94,0x20,0xA6,0x91,0xE0,0xA7,0x8B,0x49);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugValue3,0x565005FC,0x0F8A,0x4F3E,0x9E,0xDB,0x83,0x10,0x2B,0x15,0x65,0x95);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugGenericValue,0xCC7BCAF8,0x8A68,0x11d2,0x98,0x3C,0x00,0x00,0xF8,0x08,0x34,0x2D);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugReferenceValue,0xCC7BCAF9,0x8A68,0x11d2,0x98,0x3C,0x00,0x00,0xF8,0x08,0x34,0x2D);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugHeapValue,0xCC7BCAFA,0x8A68,0x11d2,0x98,0x3C,0x00,0x00,0xF8,0x08,0x34,0x2D);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugHeapValue2,0xE3AC4D6C,0x9CB7,0x43e6,0x96,0xCC,0xB2,0x15,0x40,0xE5,0x08,0x3C);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugHeapValue3,0xA69ACAD8,0x2374,0x46e9,0x9F,0xF8,0xB1,0xF1,0x41,0x20,0xD2,0x96);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugObjectValue,0x18AD3D6E,0xB7D2,0x11d2,0xBD,0x04,0x00,0x00,0xF8,0x08,0x49,0xBD);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugObjectValue2,0x49E4A320,0x4A9B,0x4eca,0xB1,0x05,0x22,0x9F,0xB7,0xD5,0x00,0x9F);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugBoxValue,0xCC7BCAFC,0x8A68,0x11d2,0x98,0x3C,0x00,0x00,0xF8,0x08,0x34,0x2D);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugStringValue,0xCC7BCAFD,0x8A68,0x11d2,0x98,0x3C,0x00,0x00,0xF8,0x08,0x34,0x2D);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugArrayValue,0x0405B0DF,0xA660,0x11d2,0xBD,0x02,0x00,0x00,0xF8,0x08,0x49,0xBD);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugHandleValue,0x029596E8,0x276B,0x46a1,0x98,0x21,0x73,0x2E,0x96,0xBB,0xB0,0x0B);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugContext,0xCC7BCB00,0x8A68,0x11d2,0x98,0x3C,0x00,0x00,0xF8,0x08,0x34,0x2D);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugComObjectValue,0x5F69C5E5,0x3E12,0x42DF,0xB3,0x71,0xF9,0xD7,0x61,0xD6,0xEE,0x24);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugObjectEnum,0xCC7BCB02,0x8A68,0x11d2,0x98,0x3C,0x00,0x00,0xF8,0x08,0x34,0x2D);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugBreakpointEnum,0xCC7BCB03,0x8A68,0x11d2,0x98,0x3C,0x00,0x00,0xF8,0x08,0x34,0x2D);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugStepperEnum,0xCC7BCB04,0x8A68,0x11d2,0x98,0x3C,0x00,0x00,0xF8,0x08,0x34,0x2D);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugProcessEnum,0xCC7BCB05,0x8A68,0x11d2,0x98,0x3C,0x00,0x00,0xF8,0x08,0x34,0x2D);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugThreadEnum,0xCC7BCB06,0x8A68,0x11d2,0x98,0x3C,0x00,0x00,0xF8,0x08,0x34,0x2D);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugFrameEnum,0xCC7BCB07,0x8A68,0x11d2,0x98,0x3C,0x00,0x00,0xF8,0x08,0x34,0x2D);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugChainEnum,0xCC7BCB08,0x8A68,0x11d2,0x98,0x3C,0x00,0x00,0xF8,0x08,0x34,0x2D);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugModuleEnum,0xCC7BCB09,0x8A68,0x11d2,0x98,0x3C,0x00,0x00,0xF8,0x08,0x34,0x2D);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugValueEnum,0xCC7BCB0A,0x8A68,0x11d2,0x98,0x3C,0x00,0x00,0xF8,0x08,0x34,0x2D);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugCodeEnum,0x55E96461,0x9645,0x45e4,0xA2,0xFF,0x03,0x67,0x87,0x7A,0xBC,0xDE);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugTypeEnum,0x10F27499,0x9DF2,0x43ce,0x83,0x33,0xA3,0x21,0xD7,0xC9,0x9C,0xB4);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugType,0xD613F0BB,0xACE1,0x4c19,0xBD,0x72,0xE4,0xC0,0x8D,0x5D,0xA7,0xF5);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugErrorInfoEnum,0xF0E18809,0x72B5,0x11d2,0x97,0x6F,0x00,0xA0,0xC9,0xB4,0xD5,0x0C);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugAppDomainEnum,0x63ca1b24,0x4359,0x4883,0xbd,0x57,0x13,0xf8,0x15,0xf5,0x87,0x44);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugAssemblyEnum,0x4a2a1ec9,0x85ec,0x4bfb,0x9f,0x15,0xa8,0x9f,0xdf,0xe0,0xfe,0x83);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugBlockingObjectEnum,0x976A6278,0x134A,0x4a81,0x81,0xA3,0x8F,0x27,0x79,0x43,0xF4,0xC3);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugMDA,0xCC726F2F,0x1DB7,0x459b,0xB0,0xEC,0x05,0xF0,0x1D,0x84,0x1B,0x42);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugEditAndContinueErrorInfo,0x8D600D41,0xF4F6,0x4cb3,0xB7,0xEC,0x7B,0xD1,0x64,0x94,0x40,0x36);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugEditAndContinueSnapshot,0x6DC3FA01,0xD7CB,0x11d2,0x8A,0x95,0x00,0x80,0xC7,0x92,0xE5,0xD8);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugExceptionObjectCallStackEnum,0xED775530,0x4DC4,0x41F7,0x86,0xD0,0x9E,0x2D,0xEF,0x7D,0xFC,0x66);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugExceptionObjectValue,0xAE4CA65D,0x59DD,0x42A2,0x83,0xA5,0x57,0xE8,0xA0,0x8D,0x87,0x19);
+
+
+MIDL_DEFINE_GUID(IID, LIBID_CORDBLib,0x53D13620,0xF417,0x11d1,0x97,0x62,0xA6,0x38,0x26,0xA4,0xF2,0x55);
+
+
+MIDL_DEFINE_GUID(CLSID, CLSID_CorDebug,0x6fef44d0,0x39e7,0x4c77,0xbe,0x8e,0xc9,0xf8,0xcf,0x98,0x86,0x30);
+
+
+MIDL_DEFINE_GUID(CLSID, CLSID_EmbeddedCLRCorDebug,0x211f1254,0xbc7e,0x4af5,0xb9,0xaa,0x06,0x73,0x08,0xd8,0x3d,0xd1);
+
+#undef MIDL_DEFINE_GUID
+
+#ifdef __cplusplus
+}
+#endif
+
+
+
diff --git a/src/pal/prebuilt/idl/corprof_i.c b/src/pal/prebuilt/idl/corprof_i.c
new file mode 100644
index 0000000000..4686c76d54
--- /dev/null
+++ b/src/pal/prebuilt/idl/corprof_i.c
@@ -0,0 +1,134 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/* this ALWAYS GENERATED file contains the IIDs and CLSIDs */
+
+/* link this file in with the server and any clients */
+
+
+ /* File created by MIDL compiler version 8.00.0603 */
+/* @@MIDL_FILE_HEADING( ) */
+
+#pragma warning( disable: 4049 ) /* more than 64k source lines */
+
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+
+#include <rpc.h>
+#include <rpcndr.h>
+
+#ifdef _MIDL_USE_GUIDDEF_
+
+#ifndef INITGUID
+#define INITGUID
+#include <guiddef.h>
+#undef INITGUID
+#else
+#include <guiddef.h>
+#endif
+
+#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
+ DEFINE_GUID(name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8)
+
+#else // !_MIDL_USE_GUIDDEF_
+
+#ifndef __IID_DEFINED__
+#define __IID_DEFINED__
+
+typedef struct _IID
+{
+ unsigned long x;
+ unsigned short s1;
+ unsigned short s2;
+ unsigned char c[8];
+} IID;
+
+#endif // __IID_DEFINED__
+
+#ifndef CLSID_DEFINED
+#define CLSID_DEFINED
+typedef IID CLSID;
+#endif // CLSID_DEFINED
+
+#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
+ const type name = {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}}
+
+#endif !_MIDL_USE_GUIDDEF_
+
+MIDL_DEFINE_GUID(IID, IID_ICorProfilerCallback,0x176FBED1,0xA55C,0x4796,0x98,0xCA,0xA9,0xDA,0x0E,0xF8,0x83,0xE7);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorProfilerCallback2,0x8A8CC829,0xCCF2,0x49fe,0xBB,0xAE,0x0F,0x02,0x22,0x28,0x07,0x1A);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorProfilerCallback3,0x4FD2ED52,0x7731,0x4b8d,0x94,0x69,0x03,0xD2,0xCC,0x30,0x86,0xC5);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorProfilerCallback4,0x7B63B2E3,0x107D,0x4d48,0xB2,0xF6,0xF6,0x1E,0x22,0x94,0x70,0xD2);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorProfilerCallback5,0x8DFBA405,0x8C9F,0x45F8,0xBF,0xFA,0x83,0xB1,0x4C,0xEF,0x78,0xB5);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorProfilerCallback6,0xFC13DF4B,0x4448,0x4F4F,0x95,0x0C,0xBA,0x8D,0x19,0xD0,0x0C,0x36);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorProfilerCallback7,0xF76A2DBA,0x1D52,0x4539,0x86,0x6C,0x2A,0xA5,0x18,0xF9,0xEF,0xC3);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorProfilerInfo,0x28B5557D,0x3F3F,0x48b4,0x90,0xB2,0x5F,0x9E,0xEA,0x2F,0x6C,0x48);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorProfilerInfo2,0xCC0935CD,0xA518,0x487d,0xB0,0xBB,0xA9,0x32,0x14,0xE6,0x54,0x78);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorProfilerInfo3,0xB555ED4F,0x452A,0x4E54,0x8B,0x39,0xB5,0x36,0x0B,0xAD,0x32,0xA0);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorProfilerObjectEnum,0x2C6269BD,0x2D13,0x4321,0xAE,0x12,0x66,0x86,0x36,0x5F,0xD6,0xAF);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorProfilerFunctionEnum,0xFF71301A,0xB994,0x429D,0xA1,0x0B,0xB3,0x45,0xA6,0x52,0x80,0xEF);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorProfilerModuleEnum,0xb0266d75,0x2081,0x4493,0xaf,0x7f,0x02,0x8b,0xa3,0x4d,0xb8,0x91);
+
+
+MIDL_DEFINE_GUID(IID, IID_IMethodMalloc,0xA0EFB28B,0x6EE2,0x4d7b,0xB9,0x83,0xA7,0x5E,0xF7,0xBE,0xED,0xB8);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorProfilerFunctionControl,0xF0963021,0xE1EA,0x4732,0x85,0x81,0xE0,0x1B,0x0B,0xD3,0xC0,0xC6);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorProfilerInfo4,0x0d8fdcaa,0x6257,0x47bf,0xb1,0xbf,0x94,0xda,0xc8,0x84,0x66,0xee);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorProfilerInfo5,0x07602928,0xCE38,0x4B83,0x81,0xE7,0x74,0xAD,0xAF,0x78,0x12,0x14);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorProfilerInfo6,0xF30A070D,0xBFFB,0x46A7,0xB1,0xD8,0x87,0x81,0xEF,0x7B,0x69,0x8A);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorProfilerInfo7,0x9AEECC0D,0x63E0,0x4187,0x8C,0x00,0xE3,0x12,0xF5,0x03,0xF6,0x63);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorProfilerMethodEnum,0xFCCEE788,0x0088,0x454B,0xA8,0x11,0xC9,0x9F,0x29,0x8D,0x19,0x42);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorProfilerThreadEnum,0x571194f7,0x25ed,0x419f,0xaa,0x8b,0x70,0x16,0xb3,0x15,0x97,0x01);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorProfilerAssemblyReferenceProvider,0x66A78C24,0x2EEF,0x4F65,0xB4,0x5F,0xDD,0x1D,0x80,0x38,0xBF,0x3C);
+
+#undef MIDL_DEFINE_GUID
+
+#ifdef __cplusplus
+}
+#endif
+
+
+
diff --git a/src/pal/prebuilt/idl/corpub_i.c b/src/pal/prebuilt/idl/corpub_i.c
new file mode 100644
index 0000000000..982f89724e
--- /dev/null
+++ b/src/pal/prebuilt/idl/corpub_i.c
@@ -0,0 +1,94 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+
+
+/* this ALWAYS GENERATED file contains the IIDs and CLSIDs */
+
+/* link this file in with the server and any clients */
+
+
+ /* File created by MIDL compiler version 8.00.0603 */
+/* @@MIDL_FILE_HEADING( ) */
+
+#pragma warning( disable: 4049 ) /* more than 64k source lines */
+
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+
+#include <rpc.h>
+#include <rpcndr.h>
+
+#ifdef _MIDL_USE_GUIDDEF_
+
+#ifndef INITGUID
+#define INITGUID
+#include <guiddef.h>
+#undef INITGUID
+#else
+#include <guiddef.h>
+#endif
+
+#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
+ DEFINE_GUID(name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8)
+
+#else // !_MIDL_USE_GUIDDEF_
+
+#ifndef __IID_DEFINED__
+#define __IID_DEFINED__
+
+typedef struct _IID
+{
+ unsigned long x;
+ unsigned short s1;
+ unsigned short s2;
+ unsigned char c[8];
+} IID;
+
+#endif // __IID_DEFINED__
+
+#ifndef CLSID_DEFINED
+#define CLSID_DEFINED
+typedef IID CLSID;
+#endif // CLSID_DEFINED
+
+#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
+ const type name = {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}}
+
+#endif !_MIDL_USE_GUIDDEF_
+
+MIDL_DEFINE_GUID(IID, LIBID_CorpubProcessLib,0xe97ca460,0x657d,0x11d3,0x8d,0x5b,0x00,0x10,0x4b,0x35,0xe7,0xef);
+
+
+MIDL_DEFINE_GUID(CLSID, CLSID_CorpubPublish,0x047a9a40,0x657e,0x11d3,0x8d,0x5b,0x00,0x10,0x4b,0x35,0xe7,0xef);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorPublish,0x9613A0E7,0x5A68,0x11d3,0x8F,0x84,0x00,0xA0,0xC9,0xB4,0xD5,0x0C);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorPublishEnum,0xC0B22967,0x5A69,0x11d3,0x8F,0x84,0x00,0xA0,0xC9,0xB4,0xD5,0x0C);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorPublishProcess,0x18D87AF1,0x5A6A,0x11d3,0x8F,0x84,0x00,0xA0,0xC9,0xB4,0xD5,0x0C);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorPublishAppDomain,0xD6315C8F,0x5A6A,0x11d3,0x8F,0x84,0x00,0xA0,0xC9,0xB4,0xD5,0x0C);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorPublishProcessEnum,0xA37FBD41,0x5A69,0x11d3,0x8F,0x84,0x00,0xA0,0xC9,0xB4,0xD5,0x0C);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorPublishAppDomainEnum,0x9F0C98F5,0x5A6A,0x11d3,0x8F,0x84,0x00,0xA0,0xC9,0xB4,0xD5,0x0C);
+
+#undef MIDL_DEFINE_GUID
+
+#ifdef __cplusplus
+}
+#endif
+
+
+
diff --git a/src/pal/prebuilt/idl/corsym_i.c b/src/pal/prebuilt/idl/corsym_i.c
new file mode 100644
index 0000000000..7ef9242315
--- /dev/null
+++ b/src/pal/prebuilt/idl/corsym_i.c
@@ -0,0 +1,175 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+
+
+/* this ALWAYS GENERATED file contains the IIDs and CLSIDs */
+
+/* link this file in with the server and any clients */
+
+
+ /* File created by MIDL compiler version 8.00.0603 */
+/* @@MIDL_FILE_HEADING( ) */
+
+#pragma warning( disable: 4049 ) /* more than 64k source lines */
+
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+
+#include <rpc.h>
+#include <rpcndr.h>
+
+#ifdef _MIDL_USE_GUIDDEF_
+
+#ifndef INITGUID
+#define INITGUID
+#include <guiddef.h>
+#undef INITGUID
+#else
+#include <guiddef.h>
+#endif
+
+#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
+ DEFINE_GUID(name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8)
+
+#else // !_MIDL_USE_GUIDDEF_
+
+#ifndef __IID_DEFINED__
+#define __IID_DEFINED__
+
+typedef struct _IID
+{
+ unsigned long x;
+ unsigned short s1;
+ unsigned short s2;
+ unsigned char c[8];
+} IID;
+
+#endif // __IID_DEFINED__
+
+#ifndef CLSID_DEFINED
+#define CLSID_DEFINED
+typedef IID CLSID;
+#endif // CLSID_DEFINED
+
+#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
+ const type name = {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}}
+
+#endif !_MIDL_USE_GUIDDEF_
+
+MIDL_DEFINE_GUID(IID, LIBID_CorSymLib,0x7E348441,0x7E1F,0x380E,0xA0,0xF6,0x22,0x66,0x8F,0x0F,0x9E,0x4B);
+
+
+MIDL_DEFINE_GUID(CLSID, CLSID_CorSymWriter_deprecated,0x108296C1,0x281E,0x11d3,0xBD,0x22,0x00,0x00,0xF8,0x08,0x49,0xBD);
+
+
+MIDL_DEFINE_GUID(CLSID, CLSID_CorSymReader_deprecated,0x108296C2,0x281E,0x11d3,0xBD,0x22,0x00,0x00,0xF8,0x08,0x49,0xBD);
+
+
+MIDL_DEFINE_GUID(CLSID, CLSID_CorSymBinder_deprecated,0xAA544D41,0x28CB,0x11d3,0xBD,0x22,0x00,0x00,0xF8,0x08,0x49,0xBD);
+
+
+MIDL_DEFINE_GUID(CLSID, CLSID_CorSymWriter_SxS,0x0AE2DEB0,0xF901,0x478b,0xBB,0x9F,0x88,0x1E,0xE8,0x06,0x67,0x88);
+
+
+MIDL_DEFINE_GUID(CLSID, CLSID_CorSymReader_SxS,0x0A3976C5,0x4529,0x4ef8,0xB0,0xB0,0x42,0xEE,0xD3,0x70,0x82,0xCD);
+
+
+MIDL_DEFINE_GUID(CLSID, CLSID_CorSymBinder_SxS,0x0A29FF9E,0x7F9C,0x4437,0x8B,0x11,0xF4,0x24,0x49,0x1E,0x39,0x31);
+
+
+MIDL_DEFINE_GUID(IID, IID_ISymUnmanagedBinder,0xAA544D42,0x28CB,0x11d3,0xBD,0x22,0x00,0x00,0xF8,0x08,0x49,0xBD);
+
+
+MIDL_DEFINE_GUID(IID, IID_ISymUnmanagedBinder2,0xACCEE350,0x89AF,0x4ccb,0x8B,0x40,0x1C,0x2C,0x4C,0x6F,0x94,0x34);
+
+
+MIDL_DEFINE_GUID(IID, IID_ISymUnmanagedBinder3,0x28AD3D43,0xB601,0x4d26,0x8A,0x1B,0x25,0xF9,0x16,0x5A,0xF9,0xD7);
+
+
+MIDL_DEFINE_GUID(IID, IID_ISymUnmanagedDispose,0x969708D2,0x05E5,0x4861,0xA3,0xB0,0x96,0xE4,0x73,0xCD,0xF6,0x3F);
+
+
+MIDL_DEFINE_GUID(IID, IID_ISymUnmanagedDocument,0x40DE4037,0x7C81,0x3E1E,0xB0,0x22,0xAE,0x1A,0xBF,0xF2,0xCA,0x08);
+
+
+MIDL_DEFINE_GUID(IID, IID_ISymUnmanagedDocumentWriter,0xB01FAFEB,0xC450,0x3A4D,0xBE,0xEC,0xB4,0xCE,0xEC,0x01,0xE0,0x06);
+
+
+MIDL_DEFINE_GUID(IID, IID_ISymUnmanagedMethod,0xB62B923C,0xB500,0x3158,0xA5,0x43,0x24,0xF3,0x07,0xA8,0xB7,0xE1);
+
+
+MIDL_DEFINE_GUID(IID, IID_ISymENCUnmanagedMethod,0x85E891DA,0xA631,0x4c76,0xAC,0xA2,0xA4,0x4A,0x39,0xC4,0x6B,0x8C);
+
+
+MIDL_DEFINE_GUID(IID, IID_ISymUnmanagedNamespace,0x0DFF7289,0x54F8,0x11d3,0xBD,0x28,0x00,0x00,0xF8,0x08,0x49,0xBD);
+
+
+MIDL_DEFINE_GUID(IID, IID_ISymUnmanagedReader,0xB4CE6286,0x2A6B,0x3712,0xA3,0xB7,0x1E,0xE1,0xDA,0xD4,0x67,0xB5);
+
+
+MIDL_DEFINE_GUID(IID, IID_ISymUnmanagedSourceServerModule,0x997DD0CC,0xA76F,0x4c82,0x8D,0x79,0xEA,0x87,0x55,0x9D,0x27,0xAD);
+
+
+MIDL_DEFINE_GUID(IID, IID_ISymUnmanagedENCUpdate,0xE502D2DD,0x8671,0x4338,0x8F,0x2A,0xFC,0x08,0x22,0x96,0x28,0xC4);
+
+
+MIDL_DEFINE_GUID(IID, IID_ISymUnmanagedReaderSymbolSearchInfo,0x20D9645D,0x03CD,0x4e34,0x9C,0x11,0x98,0x48,0xA5,0xB0,0x84,0xF1);
+
+
+MIDL_DEFINE_GUID(IID, IID_ISymUnmanagedScope,0x68005D0F,0xB8E0,0x3B01,0x84,0xD5,0xA1,0x1A,0x94,0x15,0x49,0x42);
+
+
+MIDL_DEFINE_GUID(IID, IID_ISymUnmanagedConstant,0x48B25ED8,0x5BAD,0x41bc,0x9C,0xEE,0xCD,0x62,0xFA,0xBC,0x74,0xE9);
+
+
+MIDL_DEFINE_GUID(IID, IID_ISymUnmanagedScope2,0xAE932FBA,0x3FD8,0x4dba,0x82,0x32,0x30,0xA2,0x30,0x9B,0x02,0xDB);
+
+
+MIDL_DEFINE_GUID(IID, IID_ISymUnmanagedVariable,0x9F60EEBE,0x2D9A,0x3F7C,0xBF,0x58,0x80,0xBC,0x99,0x1C,0x60,0xBB);
+
+
+MIDL_DEFINE_GUID(IID, IID_ISymUnmanagedSymbolSearchInfo,0xF8B3534A,0xA46B,0x4980,0xB5,0x20,0xBE,0xC4,0xAC,0xEA,0xBA,0x8F);
+
+
+MIDL_DEFINE_GUID(IID, IID_ISymUnmanagedWriter,0xED14AA72,0x78E2,0x4884,0x84,0xE2,0x33,0x42,0x93,0xAE,0x52,0x14);
+
+
+MIDL_DEFINE_GUID(IID, IID_ISymUnmanagedWriter2,0x0B97726E,0x9E6D,0x4f05,0x9A,0x26,0x42,0x40,0x22,0x09,0x3C,0xAA);
+
+
+MIDL_DEFINE_GUID(IID, IID_ISymUnmanagedWriter3,0x12F1E02C,0x1E05,0x4B0E,0x94,0x68,0xEB,0xC9,0xD1,0xBB,0x04,0x0F);
+
+
+MIDL_DEFINE_GUID(IID, IID_ISymUnmanagedWriter4,0xBC7E3F53,0xF458,0x4C23,0x9D,0xBD,0xA1,0x89,0xE6,0xE9,0x65,0x94);
+
+
+MIDL_DEFINE_GUID(IID, IID_ISymUnmanagedWriter5,0xDCF7780D,0xBDE9,0x45DF,0xAC,0xFE,0x21,0x73,0x1A,0x32,0x00,0x0C);
+
+
+MIDL_DEFINE_GUID(IID, IID_ISymUnmanagedReader2,0xA09E53B2,0x2A57,0x4cca,0x8F,0x63,0xB8,0x4F,0x7C,0x35,0xD4,0xAA);
+
+
+MIDL_DEFINE_GUID(IID, IID_ISymNGenWriter,0xd682fd12,0x43de,0x411c,0x81,0x1b,0xbe,0x84,0x04,0xce,0xa1,0x26);
+
+
+MIDL_DEFINE_GUID(IID, IID_ISymNGenWriter2,0xB029E51B,0x4C55,0x4fe2,0xB9,0x93,0x9F,0x7B,0xC1,0xF1,0x0D,0xB4);
+
+
+MIDL_DEFINE_GUID(IID, IID_ISymUnmanagedAsyncMethodPropertiesWriter,0xFC073774,0x1739,0x4232,0xBD,0x56,0xA0,0x27,0x29,0x4B,0xEC,0x15);
+
+
+MIDL_DEFINE_GUID(IID, IID_ISymUnmanagedAsyncMethod,0xB20D55B3,0x532E,0x4906,0x87,0xE7,0x25,0xBD,0x57,0x34,0xAB,0xD2);
+
+#undef MIDL_DEFINE_GUID
+
+#ifdef __cplusplus
+}
+#endif
+
+
+
diff --git a/src/pal/prebuilt/idl/fusionpriv_i.c b/src/pal/prebuilt/idl/fusionpriv_i.c
new file mode 100644
index 0000000000..ece9622114
--- /dev/null
+++ b/src/pal/prebuilt/idl/fusionpriv_i.c
@@ -0,0 +1,121 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+
+
+/* this ALWAYS GENERATED file contains the IIDs and CLSIDs */
+
+/* link this file in with the server and any clients */
+
+
+ /* File created by MIDL compiler version 8.00.0603 */
+/* @@MIDL_FILE_HEADING( ) */
+
+#pragma warning( disable: 4049 ) /* more than 64k source lines */
+
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+
+#include <rpc.h>
+#include <rpcndr.h>
+
+#ifdef _MIDL_USE_GUIDDEF_
+
+#ifndef INITGUID
+#define INITGUID
+#include <guiddef.h>
+#undef INITGUID
+#else
+#include <guiddef.h>
+#endif
+
+#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
+ DEFINE_GUID(name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8)
+
+#else // !_MIDL_USE_GUIDDEF_
+
+#ifndef __IID_DEFINED__
+#define __IID_DEFINED__
+
+typedef struct _IID
+{
+ unsigned long x;
+ unsigned short s1;
+ unsigned short s2;
+ unsigned char c[8];
+} IID;
+
+#endif // __IID_DEFINED__
+
+#ifndef CLSID_DEFINED
+#define CLSID_DEFINED
+typedef IID CLSID;
+#endif // CLSID_DEFINED
+
+#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
+ const type name = {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}}
+
+#endif !_MIDL_USE_GUIDDEF_
+
+MIDL_DEFINE_GUID(IID, IID_IHistoryAssembly,0xe6096a07,0xe188,0x4a49,0x8d,0x50,0x2a,0x01,0x72,0xa0,0xd2,0x05);
+
+
+MIDL_DEFINE_GUID(IID, IID_IHistoryReader,0x1d23df4d,0xa1e2,0x4b8b,0x93,0xd6,0x6e,0xa3,0xdc,0x28,0x5a,0x54);
+
+
+MIDL_DEFINE_GUID(IID, IID_IFusionBindLog,0x67E9F87D,0x8B8A,0x4a90,0x9D,0x3E,0x85,0xED,0x5B,0x2D,0xCC,0x83);
+
+
+MIDL_DEFINE_GUID(IID, IID_IAssemblyManifestImport,0xde9a68ba,0x0fa2,0x11d3,0x94,0xaa,0x00,0xc0,0x4f,0xc3,0x08,0xff);
+
+
+MIDL_DEFINE_GUID(IID, IID_IApplicationContext,0x7c23ff90,0x33af,0x11d3,0x95,0xda,0x00,0xa0,0x24,0xa8,0x5b,0x51);
+
+
+MIDL_DEFINE_GUID(IID, IID_IAssemblyNameBinder,0x56972d9d,0x0f6c,0x47de,0xa0,0x38,0xe8,0x2d,0x5d,0xe3,0xa7,0x77);
+
+
+MIDL_DEFINE_GUID(IID, IID_IAssembly,0xff08d7d4,0x04c2,0x11d3,0x94,0xaa,0x00,0xc0,0x4f,0xc3,0x08,0xff);
+
+
+MIDL_DEFINE_GUID(IID, IID_IAssemblyBindingClosureEnumerator,0xb3f1e4ed,0xcb09,0x4b85,0x9a,0x1b,0x68,0x09,0x58,0x2f,0x1e,0xbc);
+
+
+MIDL_DEFINE_GUID(IID, IID_IAssemblyBindingClosure,0x415c226a,0xe513,0x41ba,0x96,0x51,0x9c,0x48,0xe9,0x7a,0xa5,0xde);
+
+
+MIDL_DEFINE_GUID(IID, IID_IAssemblyBindSink,0xaf0bc960,0x0b9a,0x11d3,0x95,0xca,0x00,0xa0,0x24,0xa8,0x5b,0x51);
+
+
+MIDL_DEFINE_GUID(IID, IID_IAssemblyBinding,0xcfe52a80,0x12bd,0x11d3,0x95,0xca,0x00,0xa0,0x24,0xa8,0x5b,0x51);
+
+
+MIDL_DEFINE_GUID(IID, IID_IAssemblyModuleImport,0xda0cd4b0,0x1117,0x11d3,0x95,0xca,0x00,0xa0,0x24,0xa8,0x5b,0x51);
+
+
+MIDL_DEFINE_GUID(IID, IID_IAssemblyScavenger,0x21b8916c,0xf28e,0x11d2,0xa4,0x73,0x00,0xcc,0xff,0x8e,0xf4,0x48);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICodebaseList,0xD8FB9BD6,0x3969,0x11d3,0xB4,0xAF,0x00,0xC0,0x4F,0x8E,0xCB,0x26);
+
+
+MIDL_DEFINE_GUID(IID, IID_IDownloadMgr,0x0A6F16F8,0xACD7,0x11d3,0xB4,0xED,0x00,0xC0,0x4F,0x8E,0xCB,0x26);
+
+
+MIDL_DEFINE_GUID(IID, IID_IHostAssembly,0x711f7c2d,0x8234,0x4505,0xb0,0x2f,0x75,0x54,0xf4,0x6c,0xbf,0x29);
+
+
+MIDL_DEFINE_GUID(IID, IID_IHostAssemblyModuleImport,0xb6f2729d,0x6c0f,0x4944,0xb6,0x92,0xe5,0xa2,0xce,0x2c,0x6e,0x7a);
+
+#undef MIDL_DEFINE_GUID
+
+#ifdef __cplusplus
+}
+#endif
+
+
+
diff --git a/src/pal/prebuilt/idl/gchost_i.c b/src/pal/prebuilt/idl/gchost_i.c
new file mode 100644
index 0000000000..32ecfbe9d5
--- /dev/null
+++ b/src/pal/prebuilt/idl/gchost_i.c
@@ -0,0 +1,73 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+
+
+/* this ALWAYS GENERATED file contains the IIDs and CLSIDs */
+
+/* link this file in with the server and any clients */
+
+
+ /* File created by MIDL compiler version 8.00.0603 */
+/* @@MIDL_FILE_HEADING( ) */
+
+#pragma warning( disable: 4049 ) /* more than 64k source lines */
+
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+
+#include <rpc.h>
+#include <rpcndr.h>
+
+#ifdef _MIDL_USE_GUIDDEF_
+
+#ifndef INITGUID
+#define INITGUID
+#include <guiddef.h>
+#undef INITGUID
+#else
+#include <guiddef.h>
+#endif
+
+#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
+ DEFINE_GUID(name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8)
+
+#else // !_MIDL_USE_GUIDDEF_
+
+#ifndef __IID_DEFINED__
+#define __IID_DEFINED__
+
+typedef struct _IID
+{
+ unsigned long x;
+ unsigned short s1;
+ unsigned short s2;
+ unsigned char c[8];
+} IID;
+
+#endif // __IID_DEFINED__
+
+#ifndef CLSID_DEFINED
+#define CLSID_DEFINED
+typedef IID CLSID;
+#endif // CLSID_DEFINED
+
+#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
+ const type name = {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}}
+
+#endif !_MIDL_USE_GUIDDEF_
+
+MIDL_DEFINE_GUID(IID, IID_IDummyDoNotUse,0xF9423916,0x2A35,0x4f03,0x9E,0xE9,0xDD,0xAF,0xA3,0xC8,0xAE,0xE0);
+
+#undef MIDL_DEFINE_GUID
+
+#ifdef __cplusplus
+}
+#endif
+
+
+
diff --git a/src/pal/prebuilt/idl/ivalidator_i.c b/src/pal/prebuilt/idl/ivalidator_i.c
new file mode 100644
index 0000000000..0edbec448a
--- /dev/null
+++ b/src/pal/prebuilt/idl/ivalidator_i.c
@@ -0,0 +1,76 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+
+
+/* this ALWAYS GENERATED file contains the IIDs and CLSIDs */
+
+/* link this file in with the server and any clients */
+
+
+ /* File created by MIDL compiler version 8.00.0603 */
+/* @@MIDL_FILE_HEADING( ) */
+
+#pragma warning( disable: 4049 ) /* more than 64k source lines */
+
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+
+#include <rpc.h>
+#include <rpcndr.h>
+
+#ifdef _MIDL_USE_GUIDDEF_
+
+#ifndef INITGUID
+#define INITGUID
+#include <guiddef.h>
+#undef INITGUID
+#else
+#include <guiddef.h>
+#endif
+
+#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
+ DEFINE_GUID(name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8)
+
+#else // !_MIDL_USE_GUIDDEF_
+
+#ifndef __IID_DEFINED__
+#define __IID_DEFINED__
+
+typedef struct _IID
+{
+ unsigned long x;
+ unsigned short s1;
+ unsigned short s2;
+ unsigned char c[8];
+} IID;
+
+#endif // __IID_DEFINED__
+
+#ifndef CLSID_DEFINED
+#define CLSID_DEFINED
+typedef IID CLSID;
+#endif // CLSID_DEFINED
+
+#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
+ const type name = {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}}
+
+#endif !_MIDL_USE_GUIDDEF_
+
+MIDL_DEFINE_GUID(IID, IID_IValidator,0x63DF8730,0xDC81,0x4062,0x84,0xA2,0x1F,0xF9,0x43,0xF5,0x9F,0xAC);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICLRValidator,0x63DF8730,0xDC81,0x4062,0x84,0xA2,0x1F,0xF9,0x43,0xF5,0x9F,0xDD);
+
+#undef MIDL_DEFINE_GUID
+
+#ifdef __cplusplus
+}
+#endif
+
+
+
diff --git a/src/pal/prebuilt/idl/ivehandler_i.c b/src/pal/prebuilt/idl/ivehandler_i.c
new file mode 100644
index 0000000000..44d0b961bb
--- /dev/null
+++ b/src/pal/prebuilt/idl/ivehandler_i.c
@@ -0,0 +1,79 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+
+
+/* this ALWAYS GENERATED file contains the IIDs and CLSIDs */
+
+/* link this file in with the server and any clients */
+
+
+ /* File created by MIDL compiler version 8.00.0603 */
+/* @@MIDL_FILE_HEADING( ) */
+
+#pragma warning( disable: 4049 ) /* more than 64k source lines */
+
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+
+#include <rpc.h>
+#include <rpcndr.h>
+
+#ifdef _MIDL_USE_GUIDDEF_
+
+#ifndef INITGUID
+#define INITGUID
+#include <guiddef.h>
+#undef INITGUID
+#else
+#include <guiddef.h>
+#endif
+
+#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
+ DEFINE_GUID(name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8)
+
+#else // !_MIDL_USE_GUIDDEF_
+
+#ifndef __IID_DEFINED__
+#define __IID_DEFINED__
+
+typedef struct _IID
+{
+ unsigned long x;
+ unsigned short s1;
+ unsigned short s2;
+ unsigned char c[8];
+} IID;
+
+#endif // __IID_DEFINED__
+
+#ifndef CLSID_DEFINED
+#define CLSID_DEFINED
+typedef IID CLSID;
+#endif // CLSID_DEFINED
+
+#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
+ const type name = {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}}
+
+#endif !_MIDL_USE_GUIDDEF_
+
+MIDL_DEFINE_GUID(IID, LIBID_VEHandlerLib,0x856CA1B0,0x7DAB,0x11d3,0xAC,0xEC,0x00,0xC0,0x4F,0x86,0xC3,0x09);
+
+
+MIDL_DEFINE_GUID(CLSID, CLSID_VEHandlerClass,0x856CA1B1,0x7DAB,0x11d3,0xAC,0xEC,0x00,0xC0,0x4F,0x86,0xC3,0x09);
+
+
+MIDL_DEFINE_GUID(IID, IID_IVEHandler,0x856CA1B2,0x7DAB,0x11d3,0xAC,0xEC,0x00,0xC0,0x4F,0x86,0xC3,0x09);
+
+#undef MIDL_DEFINE_GUID
+
+#ifdef __cplusplus
+}
+#endif
+
+
+
diff --git a/src/pal/prebuilt/idl/mscorsvc_i.c b/src/pal/prebuilt/idl/mscorsvc_i.c
new file mode 100644
index 0000000000..05d04e58a6
--- /dev/null
+++ b/src/pal/prebuilt/idl/mscorsvc_i.c
@@ -0,0 +1,142 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+
+
+/* this ALWAYS GENERATED file contains the IIDs and CLSIDs */
+
+/* link this file in with the server and any clients */
+
+
+ /* File created by MIDL compiler version 8.00.0603 */
+/* @@MIDL_FILE_HEADING( ) */
+
+#pragma warning( disable: 4049 ) /* more than 64k source lines */
+
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+
+#include <rpc.h>
+#include <rpcndr.h>
+
+#ifdef _MIDL_USE_GUIDDEF_
+
+#ifndef INITGUID
+#define INITGUID
+#include <guiddef.h>
+#undef INITGUID
+#else
+#include <guiddef.h>
+#endif
+
+#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
+ DEFINE_GUID(name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8)
+
+#else // !_MIDL_USE_GUIDDEF_
+
+#ifndef __IID_DEFINED__
+#define __IID_DEFINED__
+
+typedef struct _IID
+{
+ unsigned long x;
+ unsigned short s1;
+ unsigned short s2;
+ unsigned char c[8];
+} IID;
+
+#endif // __IID_DEFINED__
+
+#ifndef CLSID_DEFINED
+#define CLSID_DEFINED
+typedef IID CLSID;
+#endif // CLSID_DEFINED
+
+#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
+ const type name = {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}}
+
+#endif !_MIDL_USE_GUIDDEF_
+
+MIDL_DEFINE_GUID(IID, LIBID_mscorsvc,0xd69cca64,0x16f7,0x485c,0x8c,0xf1,0x67,0x06,0x3e,0x44,0xf0,0xc3);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorSvcDependencies,0xddb34005,0x9ba3,0x4025,0x95,0x54,0xf0,0x0a,0x2d,0xf5,0xdb,0xf5);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorSvcWorker,0xd1047bc2,0x67c0,0x400c,0xa9,0x4c,0xe6,0x44,0x46,0xa6,0x7f,0xbe);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorSvcWorker2,0xf3358a7d,0x0061,0x4776,0x88,0x0e,0xa2,0xf2,0x1b,0x9e,0xf9,0x3e);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorSvcWorker3,0xDC516615,0x47BE,0x477e,0x8B,0x55,0xC5,0xAB,0xE0,0xD7,0x6B,0x8F);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorSvcSetPrivateAttributes,0xb18e0b40,0xc089,0x4350,0x83,0x28,0x06,0x6c,0x66,0x8b,0xcc,0xc2);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorSvcRepository,0xd5346658,0xb5fd,0x4353,0x96,0x47,0x07,0xad,0x47,0x83,0xd5,0xa0);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorSvcAppX,0x5c814791,0x559e,0x4f7f,0x83,0xce,0x18,0x4a,0x4c,0xcb,0xae,0x24);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorSvcLogger,0xd189ff1a,0xe266,0x4f13,0x96,0x37,0x4b,0x95,0x22,0x27,0x9f,0xfc);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorSvcPooledWorker,0x0631e7e2,0x6046,0x4fde,0x8b,0x6d,0xa0,0x9b,0x64,0xfd,0xa6,0xf3);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorSvcBindToWorker,0x5c6fb596,0x4828,0x4ed5,0xb9,0xdd,0x29,0x3d,0xad,0x73,0x6f,0xb5);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorSvc,0x3eef5ff0,0x3680,0x4f20,0x8a,0x8f,0x90,0x51,0xac,0xa6,0x6b,0x22);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICompileProgressNotification,0x01c10030,0x6c81,0x4671,0xbd,0x51,0x14,0xb1,0x84,0xc6,0x73,0xb2);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICompileProgressNotification2,0x98E5BDE2,0xE9A0,0x4ADE,0x9C,0xB2,0x6C,0xD0,0x6F,0xDB,0x1A,0x85);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorSvcInstaller,0x0523feee,0xeb0e,0x4857,0xb2,0xaa,0xdb,0x78,0x75,0x21,0xd0,0x77);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorSvcAdvancedInstaller,0x0871fb80,0x3ea0,0x47cc,0x9b,0x51,0xd9,0x2e,0x2a,0xee,0x75,0xdb);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorSvcOptimizer,0x94af0ec4,0xc10d,0x45d4,0xa6,0x25,0xd6,0x8d,0x1b,0x02,0xa3,0x96);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorSvcOptimizer2,0xee3b09c2,0x0110,0x4b6e,0xa7,0x3f,0xa3,0xd6,0x56,0x2f,0x98,0xab);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorSvcOptimizer3,0x6EED164F,0x61EE,0x4a07,0xAB,0xE8,0x67,0x0F,0x92,0xB4,0xB7,0xA9);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorSvcManager,0x8f416a48,0xd663,0x4a7e,0x97,0x32,0xfb,0xca,0x3f,0xc4,0x6e,0xa8);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorSvcManager2,0x29626056,0x8031,0x441b,0xaf,0xfa,0x7a,0x82,0x48,0x00,0x58,0xb3);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorSvcSetLegacyServiceBehavior,0x35e5d609,0xec3d,0x4fc2,0x9b,0xa2,0x5f,0x99,0xe4,0x2f,0xf4,0x2f);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorSvcSetTaskBootTriggerState,0x115466A4,0x7005,0x4CA3,0x97,0x1F,0x01,0xF0,0xA2,0xC8,0xEF,0x09);
+
+
+MIDL_DEFINE_GUID(IID, IID_ICorSvcSetTaskDelayStartTriggerState,0x261DD1E3,0xF07E,0x4B8D,0xB5,0x4E,0xF2,0x68,0x89,0x41,0x36,0x26);
+
+#undef MIDL_DEFINE_GUID
+
+#ifdef __cplusplus
+}
+#endif
+
+
+
diff --git a/src/pal/prebuilt/idl/sospriv_i.c b/src/pal/prebuilt/idl/sospriv_i.c
new file mode 100644
index 0000000000..7fee909ca3
--- /dev/null
+++ b/src/pal/prebuilt/idl/sospriv_i.c
@@ -0,0 +1,100 @@
+
+
+/* this ALWAYS GENERATED file contains the IIDs and CLSIDs */
+
+/* link this file in with the server and any clients */
+
+
+ /* File created by MIDL compiler version 8.00.0613 */
+/* at Mon Jan 18 19:14:07 2038
+ */
+/* Compiler settings for C:/ssd/coreclr/src/inc/sospriv.idl:
+ Oicf, W1, Zp8, env=Win32 (32b run), target_arch=X86 8.00.0613
+ protocol : dce , ms_ext, c_ext, robust
+ error checks: allocation ref bounds_check enum stub_data
+ VC __declspec() decoration level:
+ __declspec(uuid()), __declspec(selectany), __declspec(novtable)
+ DECLSPEC_UUID(), MIDL_INTERFACE()
+*/
+/* @@MIDL_FILE_HEADING( ) */
+
+#pragma warning( disable: 4049 ) /* more than 64k source lines */
+
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+
+#include <rpc.h>
+#include <rpcndr.h>
+
+#ifdef _MIDL_USE_GUIDDEF_
+
+#ifndef INITGUID
+#define INITGUID
+#include <guiddef.h>
+#undef INITGUID
+#else
+#include <guiddef.h>
+#endif
+
+#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
+ DEFINE_GUID(name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8)
+
+#else // !_MIDL_USE_GUIDDEF_
+
+#ifndef __IID_DEFINED__
+#define __IID_DEFINED__
+
+typedef struct _IID
+{
+ unsigned long x;
+ unsigned short s1;
+ unsigned short s2;
+ unsigned char c[8];
+} IID;
+
+#endif // __IID_DEFINED__
+
+#ifndef CLSID_DEFINED
+#define CLSID_DEFINED
+typedef IID CLSID;
+#endif // CLSID_DEFINED
+
+#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
+ const type name = {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}}
+
+#endif !_MIDL_USE_GUIDDEF_
+
+MIDL_DEFINE_GUID(IID, IID_ISOSEnum,0x286CA186,0xE763,0x4F61,0x97,0x60,0x48,0x7D,0x43,0xAE,0x43,0x41);
+
+
+MIDL_DEFINE_GUID(IID, IID_ISOSHandleEnum,0x3E269830,0x4A2B,0x4301,0x8E,0xE2,0xD6,0x80,0x5B,0x29,0xB2,0xFA);
+
+
+MIDL_DEFINE_GUID(IID, IID_ISOSStackRefErrorEnum,0x774F4E1B,0xFB7B,0x491B,0x97,0x6D,0xA8,0x13,0x0F,0xE3,0x55,0xE9);
+
+
+MIDL_DEFINE_GUID(IID, IID_ISOSStackRefEnum,0x8FA642BD,0x9F10,0x4799,0x9A,0xA3,0x51,0x2A,0xE7,0x8C,0x77,0xEE);
+
+
+MIDL_DEFINE_GUID(IID, IID_ISOSDacInterface,0x436f00f2,0xb42a,0x4b9f,0x87,0x0c,0xe7,0x3d,0xb6,0x6a,0xe9,0x30);
+
+
+MIDL_DEFINE_GUID(IID, IID_ISOSDacInterface2,0xA16026EC,0x96F4,0x40BA,0x87,0xFB,0x55,0x75,0x98,0x6F,0xB7,0xAF);
+
+
+MIDL_DEFINE_GUID(IID, IID_ISOSDacInterface3,0xB08C5CDC,0xFD8A,0x49C5,0xAB,0x38,0x5F,0xEE,0xF3,0x52,0x35,0xB4);
+
+
+MIDL_DEFINE_GUID(IID, IID_ISOSDacInterface4,0x74B9D34C,0xA612,0x4B07,0x93,0xDD,0x54,0x62,0x17,0x8F,0xCE,0x11);
+
+#undef MIDL_DEFINE_GUID
+
+#ifdef __cplusplus
+}
+#endif
+
+
+
diff --git a/src/pal/prebuilt/idl/tlbimpexp_i.c b/src/pal/prebuilt/idl/tlbimpexp_i.c
new file mode 100644
index 0000000000..0eb2791fa3
--- /dev/null
+++ b/src/pal/prebuilt/idl/tlbimpexp_i.c
@@ -0,0 +1,82 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+
+
+/* this ALWAYS GENERATED file contains the IIDs and CLSIDs */
+
+/* link this file in with the server and any clients */
+
+
+ /* File created by MIDL compiler version 8.00.0603 */
+/* @@MIDL_FILE_HEADING( ) */
+
+#pragma warning( disable: 4049 ) /* more than 64k source lines */
+
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+
+#include <rpc.h>
+#include <rpcndr.h>
+
+#ifdef _MIDL_USE_GUIDDEF_
+
+#ifndef INITGUID
+#define INITGUID
+#include <guiddef.h>
+#undef INITGUID
+#else
+#include <guiddef.h>
+#endif
+
+#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
+ DEFINE_GUID(name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8)
+
+#else // !_MIDL_USE_GUIDDEF_
+
+#ifndef __IID_DEFINED__
+#define __IID_DEFINED__
+
+typedef struct _IID
+{
+ unsigned long x;
+ unsigned short s1;
+ unsigned short s2;
+ unsigned char c[8];
+} IID;
+
+#endif // __IID_DEFINED__
+
+#ifndef CLSID_DEFINED
+#define CLSID_DEFINED
+typedef IID CLSID;
+#endif // CLSID_DEFINED
+
+#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
+ const type name = {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}}
+
+#endif !_MIDL_USE_GUIDDEF_
+
+MIDL_DEFINE_GUID(IID, LIBID_TlbImpLib,0x20BC1825,0x06F0,0x11d2,0x8C,0xF4,0x00,0xA0,0xC9,0xB0,0xA0,0x63);
+
+
+MIDL_DEFINE_GUID(IID, IID_ITypeLibImporterNotifySink,0xF1C3BF76,0xC3E4,0x11D3,0x88,0xE7,0x00,0x90,0x27,0x54,0xC4,0x3A);
+
+
+MIDL_DEFINE_GUID(IID, IID_ITypeLibExporterNotifySink,0xF1C3BF77,0xC3E4,0x11D3,0x88,0xE7,0x00,0x90,0x27,0x54,0xC4,0x3A);
+
+
+MIDL_DEFINE_GUID(IID, IID_ITypeLibExporterNameProvider,0xFA1F3615,0xACB9,0x486d,0x9E,0xAC,0x1B,0xEF,0x87,0xE3,0x6B,0x09);
+
+#undef MIDL_DEFINE_GUID
+
+#ifdef __cplusplus
+}
+#endif
+
+
+
diff --git a/src/pal/prebuilt/idl/xclrdata_i.c b/src/pal/prebuilt/idl/xclrdata_i.c
new file mode 100644
index 0000000000..6dd642da4c
--- /dev/null
+++ b/src/pal/prebuilt/idl/xclrdata_i.c
@@ -0,0 +1,142 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+
+
+/* this ALWAYS GENERATED file contains the IIDs and CLSIDs */
+
+/* link this file in with the server and any clients */
+
+
+ /* File created by MIDL compiler version 8.00.0603 */
+/* @@MIDL_FILE_HEADING( ) */
+
+#pragma warning( disable: 4049 ) /* more than 64k source lines */
+
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+
+#include <rpc.h>
+#include <rpcndr.h>
+
+#ifdef _MIDL_USE_GUIDDEF_
+
+#ifndef INITGUID
+#define INITGUID
+#include <guiddef.h>
+#undef INITGUID
+#else
+#include <guiddef.h>
+#endif
+
+#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
+ DEFINE_GUID(name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8)
+
+#else // !_MIDL_USE_GUIDDEF_
+
+#ifndef __IID_DEFINED__
+#define __IID_DEFINED__
+
+typedef struct _IID
+{
+ unsigned long x;
+ unsigned short s1;
+ unsigned short s2;
+ unsigned char c[8];
+} IID;
+
+#endif // __IID_DEFINED__
+
+#ifndef CLSID_DEFINED
+#define CLSID_DEFINED
+typedef IID CLSID;
+#endif // CLSID_DEFINED
+
+#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
+ const type name = {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}}
+
+#endif !_MIDL_USE_GUIDDEF_
+
+MIDL_DEFINE_GUID(IID, IID_IXCLRDataTarget3,0x59d9b5e1,0x4a6f,0x4531,0x84,0xc3,0x51,0xd1,0x2d,0xa2,0x2f,0xd4);
+
+
+MIDL_DEFINE_GUID(IID, IID_IXCLRLibrarySupport,0xE5F3039D,0x2C0C,0x4230,0xA6,0x9E,0x12,0xAF,0x1C,0x3E,0x56,0x3C);
+
+
+MIDL_DEFINE_GUID(IID, IID_IXCLRDisassemblySupport,0x1F0F7134,0xD3F3,0x47DE,0x8E,0x9B,0xC2,0xFD,0x35,0x8A,0x29,0x36);
+
+
+MIDL_DEFINE_GUID(IID, IID_IXCLRDataDisplay,0xA3C1704A,0x4559,0x4a67,0x8D,0x28,0xE8,0xF4,0xFE,0x3B,0x3F,0x62);
+
+
+MIDL_DEFINE_GUID(IID, IID_IXCLRDataProcess,0x5c552ab6,0xfc09,0x4cb3,0x8e,0x36,0x22,0xfa,0x03,0xc7,0x98,0xb7);
+
+
+MIDL_DEFINE_GUID(IID, IID_IXCLRDataProcess2,0x5c552ab6,0xfc09,0x4cb3,0x8e,0x36,0x22,0xfa,0x03,0xc7,0x98,0xb8);
+
+
+MIDL_DEFINE_GUID(IID, IID_IXCLRDataAppDomain,0x7CA04601,0xC702,0x4670,0xA6,0x3C,0xFA,0x44,0xF7,0xDA,0x7B,0xD5);
+
+
+MIDL_DEFINE_GUID(IID, IID_IXCLRDataAssembly,0x2FA17588,0x43C2,0x46ab,0x9B,0x51,0xC8,0xF0,0x1E,0x39,0xC9,0xAC);
+
+
+MIDL_DEFINE_GUID(IID, IID_IXCLRDataModule,0x88E32849,0x0A0A,0x4cb0,0x90,0x22,0x7C,0xD2,0xE9,0xE1,0x39,0xE2);
+
+
+MIDL_DEFINE_GUID(IID, IID_IXCLRDataModule2,0x34625881,0x7EB3,0x4524,0x81,0x7B,0x8D,0xB9,0xD0,0x64,0xC7,0x60);
+
+
+MIDL_DEFINE_GUID(IID, IID_IXCLRDataTypeDefinition,0x4675666C,0xC275,0x45b8,0x9F,0x6C,0xAB,0x16,0x5D,0x5C,0x1E,0x09);
+
+
+MIDL_DEFINE_GUID(IID, IID_IXCLRDataTypeInstance,0x4D078D91,0x9CB3,0x4b0d,0x97,0xAC,0x28,0xC8,0xA5,0xA8,0x25,0x97);
+
+
+MIDL_DEFINE_GUID(IID, IID_IXCLRDataMethodDefinition,0xAAF60008,0xFB2C,0x420b,0x8F,0xB1,0x42,0xD2,0x44,0xA5,0x4A,0x97);
+
+
+MIDL_DEFINE_GUID(IID, IID_IXCLRDataMethodInstance,0xECD73800,0x22CA,0x4b0d,0xAB,0x55,0xE9,0xBA,0x7E,0x63,0x18,0xA5);
+
+
+MIDL_DEFINE_GUID(IID, IID_IXCLRDataTask,0xA5B0BEEA,0xEC62,0x4618,0x80,0x12,0xA2,0x4F,0xFC,0x23,0x93,0x4C);
+
+
+MIDL_DEFINE_GUID(IID, IID_IXCLRDataStackWalk,0xE59D8D22,0xADA7,0x49a2,0x89,0xB5,0xA4,0x15,0xAF,0xCF,0xC9,0x5F);
+
+
+MIDL_DEFINE_GUID(IID, IID_IXCLRDataFrame,0x271498C2,0x4085,0x4766,0xBC,0x3A,0x7F,0x8E,0xD1,0x88,0xA1,0x73);
+
+
+MIDL_DEFINE_GUID(IID, IID_IXCLRDataFrame2,0x1C4D9A4B,0x702D,0x4CF6,0xB2,0x90,0x1D,0xB6,0xF4,0x30,0x50,0xD0);
+
+
+MIDL_DEFINE_GUID(IID, IID_IXCLRDataExceptionState,0x75DA9E4C,0xBD33,0x43C8,0x8F,0x5C,0x96,0xE8,0xA5,0x24,0x1F,0x57);
+
+
+MIDL_DEFINE_GUID(IID, IID_IXCLRDataValue,0x96EC93C7,0x1000,0x4e93,0x89,0x91,0x98,0xD8,0x76,0x6E,0x66,0x66);
+
+
+MIDL_DEFINE_GUID(IID, IID_IXCLRDataExceptionNotification,0x2D95A079,0x42A1,0x4837,0x81,0x8F,0x0B,0x97,0xD7,0x04,0x8E,0x0E);
+
+
+MIDL_DEFINE_GUID(IID, IID_IXCLRDataExceptionNotification2,0x31201a94,0x4337,0x49b7,0xae,0xf7,0x0c,0x75,0x50,0x54,0x09,0x1f);
+
+
+MIDL_DEFINE_GUID(IID, IID_IXCLRDataExceptionNotification3,0x31201a94,0x4337,0x49b7,0xae,0xf7,0x0c,0x75,0x50,0x54,0x09,0x20);
+
+
+MIDL_DEFINE_GUID(IID, IID_IXCLRDataExceptionNotification4,0xC25E926E,0x5F09,0x4AA2,0xBB,0xAD,0xB7,0xFC,0x7F,0x10,0xCF,0xD7);
+
+#undef MIDL_DEFINE_GUID
+
+#ifdef __cplusplus
+}
+#endif
+
+
+
diff --git a/src/pal/prebuilt/idl/xcordebug_i.c b/src/pal/prebuilt/idl/xcordebug_i.c
new file mode 100644
index 0000000000..ffafd17c34
--- /dev/null
+++ b/src/pal/prebuilt/idl/xcordebug_i.c
@@ -0,0 +1,75 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+
+
+/* this ALWAYS GENERATED file contains the IIDs and CLSIDs */
+
+/* link this file in with the server and any clients */
+
+
+ /* File created by MIDL compiler version 8.00.0603 */
+/* @@MIDL_FILE_HEADING( ) */
+
+#pragma warning( disable: 4049 ) /* more than 64k source lines */
+
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+
+#include <rpc.h>
+#include <rpcndr.h>
+
+#ifdef _MIDL_USE_GUIDDEF_
+
+#ifndef INITGUID
+#define INITGUID
+#include <guiddef.h>
+#undef INITGUID
+#else
+#include <guiddef.h>
+#endif
+
+#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
+ DEFINE_GUID(name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8)
+
+#else // !_MIDL_USE_GUIDDEF_
+
+#ifndef __IID_DEFINED__
+#define __IID_DEFINED__
+
+typedef struct _IID
+{
+ unsigned long x;
+ unsigned short s1;
+ unsigned short s2;
+ unsigned char c[8];
+} IID;
+
+#endif // __IID_DEFINED__
+
+#ifndef CLSID_DEFINED
+#define CLSID_DEFINED
+typedef IID CLSID;
+#endif // CLSID_DEFINED
+
+#define MIDL_DEFINE_GUID(type,name,l,w1,w2,b1,b2,b3,b4,b5,b6,b7,b8) \
+ const type name = {l,w1,w2,{b1,b2,b3,b4,b5,b6,b7,b8}}
+
+#endif !_MIDL_USE_GUIDDEF_
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugProcess4,0xE930C679,0x78AF,0x4953,0x8A,0xB7,0xB0,0xAA,0xBF,0x0F,0x9F,0x80);
+
+MIDL_DEFINE_GUID(IID, IID_ICorDebugLegacyNetCFHostCallbackInvoker_PrivateWindowsPhoneOnly,0x34B27FB0,0xA318,0x450D,0xA0,0xDD,0x11,0xB7,0x0B,0x21,0xF4,0x1D);
+
+#undef MIDL_DEFINE_GUID
+
+#ifdef __cplusplus
+}
+#endif
+
+
+
diff --git a/src/pal/prebuilt/inc/CMakeLists.txt b/src/pal/prebuilt/inc/CMakeLists.txt
new file mode 100644
index 0000000000..ae9892bb77
--- /dev/null
+++ b/src/pal/prebuilt/inc/CMakeLists.txt
@@ -0,0 +1,6 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+project(COREPAL)
+
+_install (FILES corerror.h corprof.h DESTINATION inc)
+
diff --git a/src/pal/prebuilt/inc/asm_version.h b/src/pal/prebuilt/inc/asm_version.h
new file mode 100644
index 0000000000..977c8dd188
--- /dev/null
+++ b/src/pal/prebuilt/inc/asm_version.h
@@ -0,0 +1,22 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+#if defined(SILVERLIGHT) || defined(FEATURE_CORECLR)
+#if defined(FEATURE_CORESYSTEM)
+#define asm_rmj 4
+#define asm_rmm 0
+#define asm_rup 0
+#define asm_rpt 0
+#else
+#define asm_rmj 5
+#define asm_rmm 0
+#define asm_rup 5
+#define asm_rpt 0
+#endif
+#else
+#define asm_rmj 4
+#define asm_rmm 0
+#define asm_rup 0
+#define asm_rpt 0
+#endif
+
diff --git a/src/pal/prebuilt/inc/buildnumber.h b/src/pal/prebuilt/inc/buildnumber.h
new file mode 100644
index 0000000000..63472cd45c
--- /dev/null
+++ b/src/pal/prebuilt/inc/buildnumber.h
@@ -0,0 +1,34 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#if 0
+/**** Generated Based on d:\ProjectK\src\InternalApis\Version\buildnumber.settings.targets
+Bizarely enough, you can't put comments in this file (without the #if) -
+because ndp\clr\src\Tools\applaunch preprocesses it into a perl script *****/
+#endif
+#define ProjectNMajorVersion 1
+#define ProjectNMinorVersion 0
+#define ProjectNMajorVersion_A "1"
+#define ProjectNMinorVersion_A "0"
+#define BuildNumberMajor 22220
+#define BuildNumberMinor 0
+#define BuildNumberMajor_A "22220"
+#define BuildNumberMinor_A "00"
+#define BuildNumbers_A "22220.00"
+#define BuildNumbers_T TEXT("22220.00")
+
+#define NDPBuildNumberMajor 22220
+#define NDPBuildNumberMinor 0
+#define NDPBuildNumbers_A "22220.00"
+#define NDPBuildNumbers_T TEXT("22220.00")
+
+#define NDPFileVersionMinor 5
+#define NDPFileVersionBuild 22220
+#define NDPFileVersionRevision 0
+
+#define NDPFileVersionMinor_A "5"
+#define NDPFileVersionBuild_A "22220"
+#define NDPFileVersionRevision_A "00"
+#define PROJECTN_VER_FILEVERSION_STR ProjectNMajorVersion_A "." NDPFileVersionMinor_A "." NDPFileVersionBuild_A "." NDPFileVersionRevision_A
+#define PROJECTN_VER_LEGALCOPYRIGHT_LOGO_STR "Copyright (c) Microsoft Corporation. All rights reserved."
diff --git a/src/pal/prebuilt/inc/clrdata.h b/src/pal/prebuilt/inc/clrdata.h
new file mode 100644
index 0000000000..5d3a764dfb
--- /dev/null
+++ b/src/pal/prebuilt/inc/clrdata.h
@@ -0,0 +1,1146 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+
+
+/* this ALWAYS GENERATED file contains the definitions for the interfaces */
+
+
+ /* File created by MIDL compiler version 8.00.0603 */
+/* @@MIDL_FILE_HEADING( ) */
+
+#pragma warning( disable: 4049 ) /* more than 64k source lines */
+
+
+/* verify that the <rpcndr.h> version is high enough to compile this file*/
+#ifndef __REQUIRED_RPCNDR_H_VERSION__
+#define __REQUIRED_RPCNDR_H_VERSION__ 475
+#endif
+
+#include "rpc.h"
+#include "rpcndr.h"
+
+#ifndef __RPCNDR_H_VERSION__
+#error this stub requires an updated version of <rpcndr.h>
+#endif // __RPCNDR_H_VERSION__
+
+#ifndef COM_NO_WINDOWS_H
+#include "windows.h"
+#include "ole2.h"
+#endif /*COM_NO_WINDOWS_H*/
+
+#ifndef __clrdata_h__
+#define __clrdata_h__
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+/* Forward Declarations */
+
+#ifndef __ICLRDataTarget_FWD_DEFINED__
+#define __ICLRDataTarget_FWD_DEFINED__
+typedef interface ICLRDataTarget ICLRDataTarget;
+
+#endif /* __ICLRDataTarget_FWD_DEFINED__ */
+
+
+#ifndef __ICLRDataTarget2_FWD_DEFINED__
+#define __ICLRDataTarget2_FWD_DEFINED__
+typedef interface ICLRDataTarget2 ICLRDataTarget2;
+
+#endif /* __ICLRDataTarget2_FWD_DEFINED__ */
+
+
+#ifndef __ICLRDataTarget3_FWD_DEFINED__
+#define __ICLRDataTarget3_FWD_DEFINED__
+typedef interface ICLRDataTarget3 ICLRDataTarget3;
+
+#endif /* __ICLRDataTarget3_FWD_DEFINED__ */
+
+
+#ifndef __ICLRMetadataLocator_FWD_DEFINED__
+#define __ICLRMetadataLocator_FWD_DEFINED__
+typedef interface ICLRMetadataLocator ICLRMetadataLocator;
+
+#endif /* __ICLRMetadataLocator_FWD_DEFINED__ */
+
+
+#ifndef __ICLRDataEnumMemoryRegionsCallback_FWD_DEFINED__
+#define __ICLRDataEnumMemoryRegionsCallback_FWD_DEFINED__
+typedef interface ICLRDataEnumMemoryRegionsCallback ICLRDataEnumMemoryRegionsCallback;
+
+#endif /* __ICLRDataEnumMemoryRegionsCallback_FWD_DEFINED__ */
+
+
+#ifndef __ICLRDataEnumMemoryRegionsCallback2_FWD_DEFINED__
+#define __ICLRDataEnumMemoryRegionsCallback2_FWD_DEFINED__
+typedef interface ICLRDataEnumMemoryRegionsCallback2 ICLRDataEnumMemoryRegionsCallback2;
+
+#endif /* __ICLRDataEnumMemoryRegionsCallback2_FWD_DEFINED__ */
+
+
+#ifndef __ICLRDataEnumMemoryRegions_FWD_DEFINED__
+#define __ICLRDataEnumMemoryRegions_FWD_DEFINED__
+typedef interface ICLRDataEnumMemoryRegions ICLRDataEnumMemoryRegions;
+
+#endif /* __ICLRDataEnumMemoryRegions_FWD_DEFINED__ */
+
+
+/* header files for imported files */
+#include "unknwn.h"
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+
+/* interface __MIDL_itf_clrdata_0000_0000 */
+/* [local] */
+
+
+
+
+
+
+
+typedef ULONG64 CLRDATA_ADDRESS;
+
+STDAPI CLRDataCreateInstance(REFIID iid, ICLRDataTarget* target, void** iface);
+typedef HRESULT (STDAPICALLTYPE* PFN_CLRDataCreateInstance)(REFIID iid, ICLRDataTarget* target, void** iface);
+
+
+extern RPC_IF_HANDLE __MIDL_itf_clrdata_0000_0000_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_clrdata_0000_0000_v0_0_s_ifspec;
+
+#ifndef __ICLRDataTarget_INTERFACE_DEFINED__
+#define __ICLRDataTarget_INTERFACE_DEFINED__
+
+/* interface ICLRDataTarget */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICLRDataTarget;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("3E11CCEE-D08B-43e5-AF01-32717A64DA03")
+ ICLRDataTarget : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetMachineType(
+ /* [out] */ ULONG32 *machineType) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetPointerSize(
+ /* [out] */ ULONG32 *pointerSize) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetImageBase(
+ /* [string][in] */ LPCWSTR imagePath,
+ /* [out] */ CLRDATA_ADDRESS *baseAddress) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ReadVirtual(
+ /* [in] */ CLRDATA_ADDRESS address,
+ /* [length_is][size_is][out] */ BYTE *buffer,
+ /* [in] */ ULONG32 bytesRequested,
+ /* [out] */ ULONG32 *bytesRead) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE WriteVirtual(
+ /* [in] */ CLRDATA_ADDRESS address,
+ /* [size_is][in] */ BYTE *buffer,
+ /* [in] */ ULONG32 bytesRequested,
+ /* [out] */ ULONG32 *bytesWritten) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetTLSValue(
+ /* [in] */ ULONG32 threadID,
+ /* [in] */ ULONG32 index,
+ /* [out] */ CLRDATA_ADDRESS *value) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetTLSValue(
+ /* [in] */ ULONG32 threadID,
+ /* [in] */ ULONG32 index,
+ /* [in] */ CLRDATA_ADDRESS value) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetCurrentThreadID(
+ /* [out] */ ULONG32 *threadID) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetThreadContext(
+ /* [in] */ ULONG32 threadID,
+ /* [in] */ ULONG32 contextFlags,
+ /* [in] */ ULONG32 contextSize,
+ /* [size_is][out] */ BYTE *context) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetThreadContext(
+ /* [in] */ ULONG32 threadID,
+ /* [in] */ ULONG32 contextSize,
+ /* [size_is][in] */ BYTE *context) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Request(
+ /* [in] */ ULONG32 reqCode,
+ /* [in] */ ULONG32 inBufferSize,
+ /* [size_is][in] */ BYTE *inBuffer,
+ /* [in] */ ULONG32 outBufferSize,
+ /* [size_is][out] */ BYTE *outBuffer) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICLRDataTargetVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICLRDataTarget * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICLRDataTarget * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICLRDataTarget * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetMachineType )(
+ ICLRDataTarget * This,
+ /* [out] */ ULONG32 *machineType);
+
+ HRESULT ( STDMETHODCALLTYPE *GetPointerSize )(
+ ICLRDataTarget * This,
+ /* [out] */ ULONG32 *pointerSize);
+
+ HRESULT ( STDMETHODCALLTYPE *GetImageBase )(
+ ICLRDataTarget * This,
+ /* [string][in] */ LPCWSTR imagePath,
+ /* [out] */ CLRDATA_ADDRESS *baseAddress);
+
+ HRESULT ( STDMETHODCALLTYPE *ReadVirtual )(
+ ICLRDataTarget * This,
+ /* [in] */ CLRDATA_ADDRESS address,
+ /* [length_is][size_is][out] */ BYTE *buffer,
+ /* [in] */ ULONG32 bytesRequested,
+ /* [out] */ ULONG32 *bytesRead);
+
+ HRESULT ( STDMETHODCALLTYPE *WriteVirtual )(
+ ICLRDataTarget * This,
+ /* [in] */ CLRDATA_ADDRESS address,
+ /* [size_is][in] */ BYTE *buffer,
+ /* [in] */ ULONG32 bytesRequested,
+ /* [out] */ ULONG32 *bytesWritten);
+
+ HRESULT ( STDMETHODCALLTYPE *GetTLSValue )(
+ ICLRDataTarget * This,
+ /* [in] */ ULONG32 threadID,
+ /* [in] */ ULONG32 index,
+ /* [out] */ CLRDATA_ADDRESS *value);
+
+ HRESULT ( STDMETHODCALLTYPE *SetTLSValue )(
+ ICLRDataTarget * This,
+ /* [in] */ ULONG32 threadID,
+ /* [in] */ ULONG32 index,
+ /* [in] */ CLRDATA_ADDRESS value);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCurrentThreadID )(
+ ICLRDataTarget * This,
+ /* [out] */ ULONG32 *threadID);
+
+ HRESULT ( STDMETHODCALLTYPE *GetThreadContext )(
+ ICLRDataTarget * This,
+ /* [in] */ ULONG32 threadID,
+ /* [in] */ ULONG32 contextFlags,
+ /* [in] */ ULONG32 contextSize,
+ /* [size_is][out] */ BYTE *context);
+
+ HRESULT ( STDMETHODCALLTYPE *SetThreadContext )(
+ ICLRDataTarget * This,
+ /* [in] */ ULONG32 threadID,
+ /* [in] */ ULONG32 contextSize,
+ /* [size_is][in] */ BYTE *context);
+
+ HRESULT ( STDMETHODCALLTYPE *Request )(
+ ICLRDataTarget * This,
+ /* [in] */ ULONG32 reqCode,
+ /* [in] */ ULONG32 inBufferSize,
+ /* [size_is][in] */ BYTE *inBuffer,
+ /* [in] */ ULONG32 outBufferSize,
+ /* [size_is][out] */ BYTE *outBuffer);
+
+ END_INTERFACE
+ } ICLRDataTargetVtbl;
+
+ interface ICLRDataTarget
+ {
+ CONST_VTBL struct ICLRDataTargetVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICLRDataTarget_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICLRDataTarget_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICLRDataTarget_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICLRDataTarget_GetMachineType(This,machineType) \
+ ( (This)->lpVtbl -> GetMachineType(This,machineType) )
+
+#define ICLRDataTarget_GetPointerSize(This,pointerSize) \
+ ( (This)->lpVtbl -> GetPointerSize(This,pointerSize) )
+
+#define ICLRDataTarget_GetImageBase(This,imagePath,baseAddress) \
+ ( (This)->lpVtbl -> GetImageBase(This,imagePath,baseAddress) )
+
+#define ICLRDataTarget_ReadVirtual(This,address,buffer,bytesRequested,bytesRead) \
+ ( (This)->lpVtbl -> ReadVirtual(This,address,buffer,bytesRequested,bytesRead) )
+
+#define ICLRDataTarget_WriteVirtual(This,address,buffer,bytesRequested,bytesWritten) \
+ ( (This)->lpVtbl -> WriteVirtual(This,address,buffer,bytesRequested,bytesWritten) )
+
+#define ICLRDataTarget_GetTLSValue(This,threadID,index,value) \
+ ( (This)->lpVtbl -> GetTLSValue(This,threadID,index,value) )
+
+#define ICLRDataTarget_SetTLSValue(This,threadID,index,value) \
+ ( (This)->lpVtbl -> SetTLSValue(This,threadID,index,value) )
+
+#define ICLRDataTarget_GetCurrentThreadID(This,threadID) \
+ ( (This)->lpVtbl -> GetCurrentThreadID(This,threadID) )
+
+#define ICLRDataTarget_GetThreadContext(This,threadID,contextFlags,contextSize,context) \
+ ( (This)->lpVtbl -> GetThreadContext(This,threadID,contextFlags,contextSize,context) )
+
+#define ICLRDataTarget_SetThreadContext(This,threadID,contextSize,context) \
+ ( (This)->lpVtbl -> SetThreadContext(This,threadID,contextSize,context) )
+
+#define ICLRDataTarget_Request(This,reqCode,inBufferSize,inBuffer,outBufferSize,outBuffer) \
+ ( (This)->lpVtbl -> Request(This,reqCode,inBufferSize,inBuffer,outBufferSize,outBuffer) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICLRDataTarget_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICLRDataTarget2_INTERFACE_DEFINED__
+#define __ICLRDataTarget2_INTERFACE_DEFINED__
+
+/* interface ICLRDataTarget2 */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICLRDataTarget2;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("6d05fae3-189c-4630-a6dc-1c251e1c01ab")
+ ICLRDataTarget2 : public ICLRDataTarget
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE AllocVirtual(
+ /* [in] */ CLRDATA_ADDRESS addr,
+ /* [in] */ ULONG32 size,
+ /* [in] */ ULONG32 typeFlags,
+ /* [in] */ ULONG32 protectFlags,
+ /* [out] */ CLRDATA_ADDRESS *virt) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE FreeVirtual(
+ /* [in] */ CLRDATA_ADDRESS addr,
+ /* [in] */ ULONG32 size,
+ /* [in] */ ULONG32 typeFlags) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICLRDataTarget2Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICLRDataTarget2 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICLRDataTarget2 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICLRDataTarget2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetMachineType )(
+ ICLRDataTarget2 * This,
+ /* [out] */ ULONG32 *machineType);
+
+ HRESULT ( STDMETHODCALLTYPE *GetPointerSize )(
+ ICLRDataTarget2 * This,
+ /* [out] */ ULONG32 *pointerSize);
+
+ HRESULT ( STDMETHODCALLTYPE *GetImageBase )(
+ ICLRDataTarget2 * This,
+ /* [string][in] */ LPCWSTR imagePath,
+ /* [out] */ CLRDATA_ADDRESS *baseAddress);
+
+ HRESULT ( STDMETHODCALLTYPE *ReadVirtual )(
+ ICLRDataTarget2 * This,
+ /* [in] */ CLRDATA_ADDRESS address,
+ /* [length_is][size_is][out] */ BYTE *buffer,
+ /* [in] */ ULONG32 bytesRequested,
+ /* [out] */ ULONG32 *bytesRead);
+
+ HRESULT ( STDMETHODCALLTYPE *WriteVirtual )(
+ ICLRDataTarget2 * This,
+ /* [in] */ CLRDATA_ADDRESS address,
+ /* [size_is][in] */ BYTE *buffer,
+ /* [in] */ ULONG32 bytesRequested,
+ /* [out] */ ULONG32 *bytesWritten);
+
+ HRESULT ( STDMETHODCALLTYPE *GetTLSValue )(
+ ICLRDataTarget2 * This,
+ /* [in] */ ULONG32 threadID,
+ /* [in] */ ULONG32 index,
+ /* [out] */ CLRDATA_ADDRESS *value);
+
+ HRESULT ( STDMETHODCALLTYPE *SetTLSValue )(
+ ICLRDataTarget2 * This,
+ /* [in] */ ULONG32 threadID,
+ /* [in] */ ULONG32 index,
+ /* [in] */ CLRDATA_ADDRESS value);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCurrentThreadID )(
+ ICLRDataTarget2 * This,
+ /* [out] */ ULONG32 *threadID);
+
+ HRESULT ( STDMETHODCALLTYPE *GetThreadContext )(
+ ICLRDataTarget2 * This,
+ /* [in] */ ULONG32 threadID,
+ /* [in] */ ULONG32 contextFlags,
+ /* [in] */ ULONG32 contextSize,
+ /* [size_is][out] */ BYTE *context);
+
+ HRESULT ( STDMETHODCALLTYPE *SetThreadContext )(
+ ICLRDataTarget2 * This,
+ /* [in] */ ULONG32 threadID,
+ /* [in] */ ULONG32 contextSize,
+ /* [size_is][in] */ BYTE *context);
+
+ HRESULT ( STDMETHODCALLTYPE *Request )(
+ ICLRDataTarget2 * This,
+ /* [in] */ ULONG32 reqCode,
+ /* [in] */ ULONG32 inBufferSize,
+ /* [size_is][in] */ BYTE *inBuffer,
+ /* [in] */ ULONG32 outBufferSize,
+ /* [size_is][out] */ BYTE *outBuffer);
+
+ HRESULT ( STDMETHODCALLTYPE *AllocVirtual )(
+ ICLRDataTarget2 * This,
+ /* [in] */ CLRDATA_ADDRESS addr,
+ /* [in] */ ULONG32 size,
+ /* [in] */ ULONG32 typeFlags,
+ /* [in] */ ULONG32 protectFlags,
+ /* [out] */ CLRDATA_ADDRESS *virt);
+
+ HRESULT ( STDMETHODCALLTYPE *FreeVirtual )(
+ ICLRDataTarget2 * This,
+ /* [in] */ CLRDATA_ADDRESS addr,
+ /* [in] */ ULONG32 size,
+ /* [in] */ ULONG32 typeFlags);
+
+ END_INTERFACE
+ } ICLRDataTarget2Vtbl;
+
+ interface ICLRDataTarget2
+ {
+ CONST_VTBL struct ICLRDataTarget2Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICLRDataTarget2_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICLRDataTarget2_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICLRDataTarget2_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICLRDataTarget2_GetMachineType(This,machineType) \
+ ( (This)->lpVtbl -> GetMachineType(This,machineType) )
+
+#define ICLRDataTarget2_GetPointerSize(This,pointerSize) \
+ ( (This)->lpVtbl -> GetPointerSize(This,pointerSize) )
+
+#define ICLRDataTarget2_GetImageBase(This,imagePath,baseAddress) \
+ ( (This)->lpVtbl -> GetImageBase(This,imagePath,baseAddress) )
+
+#define ICLRDataTarget2_ReadVirtual(This,address,buffer,bytesRequested,bytesRead) \
+ ( (This)->lpVtbl -> ReadVirtual(This,address,buffer,bytesRequested,bytesRead) )
+
+#define ICLRDataTarget2_WriteVirtual(This,address,buffer,bytesRequested,bytesWritten) \
+ ( (This)->lpVtbl -> WriteVirtual(This,address,buffer,bytesRequested,bytesWritten) )
+
+#define ICLRDataTarget2_GetTLSValue(This,threadID,index,value) \
+ ( (This)->lpVtbl -> GetTLSValue(This,threadID,index,value) )
+
+#define ICLRDataTarget2_SetTLSValue(This,threadID,index,value) \
+ ( (This)->lpVtbl -> SetTLSValue(This,threadID,index,value) )
+
+#define ICLRDataTarget2_GetCurrentThreadID(This,threadID) \
+ ( (This)->lpVtbl -> GetCurrentThreadID(This,threadID) )
+
+#define ICLRDataTarget2_GetThreadContext(This,threadID,contextFlags,contextSize,context) \
+ ( (This)->lpVtbl -> GetThreadContext(This,threadID,contextFlags,contextSize,context) )
+
+#define ICLRDataTarget2_SetThreadContext(This,threadID,contextSize,context) \
+ ( (This)->lpVtbl -> SetThreadContext(This,threadID,contextSize,context) )
+
+#define ICLRDataTarget2_Request(This,reqCode,inBufferSize,inBuffer,outBufferSize,outBuffer) \
+ ( (This)->lpVtbl -> Request(This,reqCode,inBufferSize,inBuffer,outBufferSize,outBuffer) )
+
+
+#define ICLRDataTarget2_AllocVirtual(This,addr,size,typeFlags,protectFlags,virt) \
+ ( (This)->lpVtbl -> AllocVirtual(This,addr,size,typeFlags,protectFlags,virt) )
+
+#define ICLRDataTarget2_FreeVirtual(This,addr,size,typeFlags) \
+ ( (This)->lpVtbl -> FreeVirtual(This,addr,size,typeFlags) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICLRDataTarget2_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICLRDataTarget3_INTERFACE_DEFINED__
+#define __ICLRDataTarget3_INTERFACE_DEFINED__
+
+/* interface ICLRDataTarget3 */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICLRDataTarget3;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("a5664f95-0af4-4a1b-960e-2f3346b4214c")
+ ICLRDataTarget3 : public ICLRDataTarget2
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetExceptionRecord(
+ /* [in] */ ULONG32 bufferSize,
+ /* [out] */ ULONG32 *bufferUsed,
+ /* [size_is][out] */ BYTE *buffer) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetExceptionContextRecord(
+ /* [in] */ ULONG32 bufferSize,
+ /* [out] */ ULONG32 *bufferUsed,
+ /* [size_is][out] */ BYTE *buffer) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetExceptionThreadID(
+ /* [out] */ ULONG32 *threadID) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICLRDataTarget3Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICLRDataTarget3 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICLRDataTarget3 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICLRDataTarget3 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetMachineType )(
+ ICLRDataTarget3 * This,
+ /* [out] */ ULONG32 *machineType);
+
+ HRESULT ( STDMETHODCALLTYPE *GetPointerSize )(
+ ICLRDataTarget3 * This,
+ /* [out] */ ULONG32 *pointerSize);
+
+ HRESULT ( STDMETHODCALLTYPE *GetImageBase )(
+ ICLRDataTarget3 * This,
+ /* [string][in] */ LPCWSTR imagePath,
+ /* [out] */ CLRDATA_ADDRESS *baseAddress);
+
+ HRESULT ( STDMETHODCALLTYPE *ReadVirtual )(
+ ICLRDataTarget3 * This,
+ /* [in] */ CLRDATA_ADDRESS address,
+ /* [length_is][size_is][out] */ BYTE *buffer,
+ /* [in] */ ULONG32 bytesRequested,
+ /* [out] */ ULONG32 *bytesRead);
+
+ HRESULT ( STDMETHODCALLTYPE *WriteVirtual )(
+ ICLRDataTarget3 * This,
+ /* [in] */ CLRDATA_ADDRESS address,
+ /* [size_is][in] */ BYTE *buffer,
+ /* [in] */ ULONG32 bytesRequested,
+ /* [out] */ ULONG32 *bytesWritten);
+
+ HRESULT ( STDMETHODCALLTYPE *GetTLSValue )(
+ ICLRDataTarget3 * This,
+ /* [in] */ ULONG32 threadID,
+ /* [in] */ ULONG32 index,
+ /* [out] */ CLRDATA_ADDRESS *value);
+
+ HRESULT ( STDMETHODCALLTYPE *SetTLSValue )(
+ ICLRDataTarget3 * This,
+ /* [in] */ ULONG32 threadID,
+ /* [in] */ ULONG32 index,
+ /* [in] */ CLRDATA_ADDRESS value);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCurrentThreadID )(
+ ICLRDataTarget3 * This,
+ /* [out] */ ULONG32 *threadID);
+
+ HRESULT ( STDMETHODCALLTYPE *GetThreadContext )(
+ ICLRDataTarget3 * This,
+ /* [in] */ ULONG32 threadID,
+ /* [in] */ ULONG32 contextFlags,
+ /* [in] */ ULONG32 contextSize,
+ /* [size_is][out] */ BYTE *context);
+
+ HRESULT ( STDMETHODCALLTYPE *SetThreadContext )(
+ ICLRDataTarget3 * This,
+ /* [in] */ ULONG32 threadID,
+ /* [in] */ ULONG32 contextSize,
+ /* [size_is][in] */ BYTE *context);
+
+ HRESULT ( STDMETHODCALLTYPE *Request )(
+ ICLRDataTarget3 * This,
+ /* [in] */ ULONG32 reqCode,
+ /* [in] */ ULONG32 inBufferSize,
+ /* [size_is][in] */ BYTE *inBuffer,
+ /* [in] */ ULONG32 outBufferSize,
+ /* [size_is][out] */ BYTE *outBuffer);
+
+ HRESULT ( STDMETHODCALLTYPE *AllocVirtual )(
+ ICLRDataTarget3 * This,
+ /* [in] */ CLRDATA_ADDRESS addr,
+ /* [in] */ ULONG32 size,
+ /* [in] */ ULONG32 typeFlags,
+ /* [in] */ ULONG32 protectFlags,
+ /* [out] */ CLRDATA_ADDRESS *virt);
+
+ HRESULT ( STDMETHODCALLTYPE *FreeVirtual )(
+ ICLRDataTarget3 * This,
+ /* [in] */ CLRDATA_ADDRESS addr,
+ /* [in] */ ULONG32 size,
+ /* [in] */ ULONG32 typeFlags);
+
+ HRESULT ( STDMETHODCALLTYPE *GetExceptionRecord )(
+ ICLRDataTarget3 * This,
+ /* [in] */ ULONG32 bufferSize,
+ /* [out] */ ULONG32 *bufferUsed,
+ /* [size_is][out] */ BYTE *buffer);
+
+ HRESULT ( STDMETHODCALLTYPE *GetExceptionContextRecord )(
+ ICLRDataTarget3 * This,
+ /* [in] */ ULONG32 bufferSize,
+ /* [out] */ ULONG32 *bufferUsed,
+ /* [size_is][out] */ BYTE *buffer);
+
+ HRESULT ( STDMETHODCALLTYPE *GetExceptionThreadID )(
+ ICLRDataTarget3 * This,
+ /* [out] */ ULONG32 *threadID);
+
+ END_INTERFACE
+ } ICLRDataTarget3Vtbl;
+
+ interface ICLRDataTarget3
+ {
+ CONST_VTBL struct ICLRDataTarget3Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICLRDataTarget3_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICLRDataTarget3_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICLRDataTarget3_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICLRDataTarget3_GetMachineType(This,machineType) \
+ ( (This)->lpVtbl -> GetMachineType(This,machineType) )
+
+#define ICLRDataTarget3_GetPointerSize(This,pointerSize) \
+ ( (This)->lpVtbl -> GetPointerSize(This,pointerSize) )
+
+#define ICLRDataTarget3_GetImageBase(This,imagePath,baseAddress) \
+ ( (This)->lpVtbl -> GetImageBase(This,imagePath,baseAddress) )
+
+#define ICLRDataTarget3_ReadVirtual(This,address,buffer,bytesRequested,bytesRead) \
+ ( (This)->lpVtbl -> ReadVirtual(This,address,buffer,bytesRequested,bytesRead) )
+
+#define ICLRDataTarget3_WriteVirtual(This,address,buffer,bytesRequested,bytesWritten) \
+ ( (This)->lpVtbl -> WriteVirtual(This,address,buffer,bytesRequested,bytesWritten) )
+
+#define ICLRDataTarget3_GetTLSValue(This,threadID,index,value) \
+ ( (This)->lpVtbl -> GetTLSValue(This,threadID,index,value) )
+
+#define ICLRDataTarget3_SetTLSValue(This,threadID,index,value) \
+ ( (This)->lpVtbl -> SetTLSValue(This,threadID,index,value) )
+
+#define ICLRDataTarget3_GetCurrentThreadID(This,threadID) \
+ ( (This)->lpVtbl -> GetCurrentThreadID(This,threadID) )
+
+#define ICLRDataTarget3_GetThreadContext(This,threadID,contextFlags,contextSize,context) \
+ ( (This)->lpVtbl -> GetThreadContext(This,threadID,contextFlags,contextSize,context) )
+
+#define ICLRDataTarget3_SetThreadContext(This,threadID,contextSize,context) \
+ ( (This)->lpVtbl -> SetThreadContext(This,threadID,contextSize,context) )
+
+#define ICLRDataTarget3_Request(This,reqCode,inBufferSize,inBuffer,outBufferSize,outBuffer) \
+ ( (This)->lpVtbl -> Request(This,reqCode,inBufferSize,inBuffer,outBufferSize,outBuffer) )
+
+
+#define ICLRDataTarget3_AllocVirtual(This,addr,size,typeFlags,protectFlags,virt) \
+ ( (This)->lpVtbl -> AllocVirtual(This,addr,size,typeFlags,protectFlags,virt) )
+
+#define ICLRDataTarget3_FreeVirtual(This,addr,size,typeFlags) \
+ ( (This)->lpVtbl -> FreeVirtual(This,addr,size,typeFlags) )
+
+
+#define ICLRDataTarget3_GetExceptionRecord(This,bufferSize,bufferUsed,buffer) \
+ ( (This)->lpVtbl -> GetExceptionRecord(This,bufferSize,bufferUsed,buffer) )
+
+#define ICLRDataTarget3_GetExceptionContextRecord(This,bufferSize,bufferUsed,buffer) \
+ ( (This)->lpVtbl -> GetExceptionContextRecord(This,bufferSize,bufferUsed,buffer) )
+
+#define ICLRDataTarget3_GetExceptionThreadID(This,threadID) \
+ ( (This)->lpVtbl -> GetExceptionThreadID(This,threadID) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICLRDataTarget3_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICLRMetadataLocator_INTERFACE_DEFINED__
+#define __ICLRMetadataLocator_INTERFACE_DEFINED__
+
+/* interface ICLRMetadataLocator */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICLRMetadataLocator;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("aa8fa804-bc05-4642-b2c5-c353ed22fc63")
+ ICLRMetadataLocator : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetMetadata(
+ /* [in] */ LPCWSTR imagePath,
+ /* [in] */ ULONG32 imageTimestamp,
+ /* [in] */ ULONG32 imageSize,
+ /* [in] */ GUID *mvid,
+ /* [in] */ ULONG32 mdRva,
+ /* [in] */ ULONG32 flags,
+ /* [in] */ ULONG32 bufferSize,
+ /* [length_is][size_is][out] */ BYTE *buffer,
+ /* [out] */ ULONG32 *dataSize) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICLRMetadataLocatorVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICLRMetadataLocator * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICLRMetadataLocator * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICLRMetadataLocator * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetMetadata )(
+ ICLRMetadataLocator * This,
+ /* [in] */ LPCWSTR imagePath,
+ /* [in] */ ULONG32 imageTimestamp,
+ /* [in] */ ULONG32 imageSize,
+ /* [in] */ GUID *mvid,
+ /* [in] */ ULONG32 mdRva,
+ /* [in] */ ULONG32 flags,
+ /* [in] */ ULONG32 bufferSize,
+ /* [length_is][size_is][out] */ BYTE *buffer,
+ /* [out] */ ULONG32 *dataSize);
+
+ END_INTERFACE
+ } ICLRMetadataLocatorVtbl;
+
+ interface ICLRMetadataLocator
+ {
+ CONST_VTBL struct ICLRMetadataLocatorVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICLRMetadataLocator_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICLRMetadataLocator_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICLRMetadataLocator_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICLRMetadataLocator_GetMetadata(This,imagePath,imageTimestamp,imageSize,mvid,mdRva,flags,bufferSize,buffer,dataSize) \
+ ( (This)->lpVtbl -> GetMetadata(This,imagePath,imageTimestamp,imageSize,mvid,mdRva,flags,bufferSize,buffer,dataSize) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICLRMetadataLocator_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICLRDataEnumMemoryRegionsCallback_INTERFACE_DEFINED__
+#define __ICLRDataEnumMemoryRegionsCallback_INTERFACE_DEFINED__
+
+/* interface ICLRDataEnumMemoryRegionsCallback */
+/* [uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICLRDataEnumMemoryRegionsCallback;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("BCDD6908-BA2D-4ec5-96CF-DF4D5CDCB4A4")
+ ICLRDataEnumMemoryRegionsCallback : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE EnumMemoryRegion(
+ /* [in] */ CLRDATA_ADDRESS address,
+ /* [in] */ ULONG32 size) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICLRDataEnumMemoryRegionsCallbackVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICLRDataEnumMemoryRegionsCallback * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICLRDataEnumMemoryRegionsCallback * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICLRDataEnumMemoryRegionsCallback * This);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumMemoryRegion )(
+ ICLRDataEnumMemoryRegionsCallback * This,
+ /* [in] */ CLRDATA_ADDRESS address,
+ /* [in] */ ULONG32 size);
+
+ END_INTERFACE
+ } ICLRDataEnumMemoryRegionsCallbackVtbl;
+
+ interface ICLRDataEnumMemoryRegionsCallback
+ {
+ CONST_VTBL struct ICLRDataEnumMemoryRegionsCallbackVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICLRDataEnumMemoryRegionsCallback_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICLRDataEnumMemoryRegionsCallback_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICLRDataEnumMemoryRegionsCallback_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICLRDataEnumMemoryRegionsCallback_EnumMemoryRegion(This,address,size) \
+ ( (This)->lpVtbl -> EnumMemoryRegion(This,address,size) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICLRDataEnumMemoryRegionsCallback_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICLRDataEnumMemoryRegionsCallback2_INTERFACE_DEFINED__
+#define __ICLRDataEnumMemoryRegionsCallback2_INTERFACE_DEFINED__
+
+/* interface ICLRDataEnumMemoryRegionsCallback2 */
+/* [uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICLRDataEnumMemoryRegionsCallback2;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("3721A26F-8B91-4D98-A388-DB17B356FADB")
+ ICLRDataEnumMemoryRegionsCallback2 : public ICLRDataEnumMemoryRegionsCallback
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE UpdateMemoryRegion(
+ /* [in] */ CLRDATA_ADDRESS address,
+ /* [in] */ ULONG32 bufferSize,
+ /* [size_is][in] */ BYTE *buffer) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICLRDataEnumMemoryRegionsCallback2Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICLRDataEnumMemoryRegionsCallback2 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICLRDataEnumMemoryRegionsCallback2 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICLRDataEnumMemoryRegionsCallback2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumMemoryRegion )(
+ ICLRDataEnumMemoryRegionsCallback2 * This,
+ /* [in] */ CLRDATA_ADDRESS address,
+ /* [in] */ ULONG32 size);
+
+ HRESULT ( STDMETHODCALLTYPE *UpdateMemoryRegion )(
+ ICLRDataEnumMemoryRegionsCallback2 * This,
+ /* [in] */ CLRDATA_ADDRESS address,
+ /* [in] */ ULONG32 bufferSize,
+ /* [size_is][in] */ BYTE *buffer);
+
+ END_INTERFACE
+ } ICLRDataEnumMemoryRegionsCallback2Vtbl;
+
+ interface ICLRDataEnumMemoryRegionsCallback2
+ {
+ CONST_VTBL struct ICLRDataEnumMemoryRegionsCallback2Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICLRDataEnumMemoryRegionsCallback2_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICLRDataEnumMemoryRegionsCallback2_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICLRDataEnumMemoryRegionsCallback2_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICLRDataEnumMemoryRegionsCallback2_EnumMemoryRegion(This,address,size) \
+ ( (This)->lpVtbl -> EnumMemoryRegion(This,address,size) )
+
+
+#define ICLRDataEnumMemoryRegionsCallback2_UpdateMemoryRegion(This,address,bufferSize,buffer) \
+ ( (This)->lpVtbl -> UpdateMemoryRegion(This,address,bufferSize,buffer) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICLRDataEnumMemoryRegionsCallback2_INTERFACE_DEFINED__ */
+
+
+/* interface __MIDL_itf_clrdata_0000_0006 */
+/* [local] */
+
+typedef
+enum CLRDataEnumMemoryFlags
+ {
+ CLRDATA_ENUM_MEM_DEFAULT = 0,
+ CLRDATA_ENUM_MEM_MINI = CLRDATA_ENUM_MEM_DEFAULT,
+ CLRDATA_ENUM_MEM_HEAP = 0x1,
+ CLRDATA_ENUM_MEM_TRIAGE = 0x2
+ } CLRDataEnumMemoryFlags;
+
+
+
+extern RPC_IF_HANDLE __MIDL_itf_clrdata_0000_0006_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_clrdata_0000_0006_v0_0_s_ifspec;
+
+#ifndef __ICLRDataEnumMemoryRegions_INTERFACE_DEFINED__
+#define __ICLRDataEnumMemoryRegions_INTERFACE_DEFINED__
+
+/* interface ICLRDataEnumMemoryRegions */
+/* [uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICLRDataEnumMemoryRegions;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("471c35b4-7c2f-4ef0-a945-00f8c38056f1")
+ ICLRDataEnumMemoryRegions : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE EnumMemoryRegions(
+ /* [in] */ ICLRDataEnumMemoryRegionsCallback *callback,
+ /* [in] */ ULONG32 miniDumpFlags,
+ /* [in] */ CLRDataEnumMemoryFlags clrFlags) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICLRDataEnumMemoryRegionsVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICLRDataEnumMemoryRegions * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICLRDataEnumMemoryRegions * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICLRDataEnumMemoryRegions * This);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumMemoryRegions )(
+ ICLRDataEnumMemoryRegions * This,
+ /* [in] */ ICLRDataEnumMemoryRegionsCallback *callback,
+ /* [in] */ ULONG32 miniDumpFlags,
+ /* [in] */ CLRDataEnumMemoryFlags clrFlags);
+
+ END_INTERFACE
+ } ICLRDataEnumMemoryRegionsVtbl;
+
+ interface ICLRDataEnumMemoryRegions
+ {
+ CONST_VTBL struct ICLRDataEnumMemoryRegionsVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICLRDataEnumMemoryRegions_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICLRDataEnumMemoryRegions_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICLRDataEnumMemoryRegions_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICLRDataEnumMemoryRegions_EnumMemoryRegions(This,callback,miniDumpFlags,clrFlags) \
+ ( (This)->lpVtbl -> EnumMemoryRegions(This,callback,miniDumpFlags,clrFlags) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICLRDataEnumMemoryRegions_INTERFACE_DEFINED__ */
+
+
+/* Additional Prototypes for ALL interfaces */
+
+/* end of Additional Prototypes */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+
diff --git a/src/pal/prebuilt/inc/clrinternal.h b/src/pal/prebuilt/inc/clrinternal.h
new file mode 100644
index 0000000000..673ae68470
--- /dev/null
+++ b/src/pal/prebuilt/inc/clrinternal.h
@@ -0,0 +1,847 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+
+
+/* this ALWAYS GENERATED file contains the definitions for the interfaces */
+
+
+ /* File created by MIDL compiler version 8.00.0603 */
+/* @@MIDL_FILE_HEADING( ) */
+
+#pragma warning( disable: 4049 ) /* more than 64k source lines */
+
+
+/* verify that the <rpcndr.h> version is high enough to compile this file*/
+#ifndef __REQUIRED_RPCNDR_H_VERSION__
+#define __REQUIRED_RPCNDR_H_VERSION__ 475
+#endif
+
+#include "rpc.h"
+#include "rpcndr.h"
+
+#ifndef __RPCNDR_H_VERSION__
+#error this stub requires an updated version of <rpcndr.h>
+#endif // __RPCNDR_H_VERSION__
+
+#ifndef COM_NO_WINDOWS_H
+#include "windows.h"
+#include "ole2.h"
+#endif /*COM_NO_WINDOWS_H*/
+
+#ifndef __clrinternal_h__
+#define __clrinternal_h__
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+/* Forward Declarations */
+
+#ifndef __IExecutionEngine_FWD_DEFINED__
+#define __IExecutionEngine_FWD_DEFINED__
+typedef interface IExecutionEngine IExecutionEngine;
+
+#endif /* __IExecutionEngine_FWD_DEFINED__ */
+
+
+#ifndef __IEEMemoryManager_FWD_DEFINED__
+#define __IEEMemoryManager_FWD_DEFINED__
+typedef interface IEEMemoryManager IEEMemoryManager;
+
+#endif /* __IEEMemoryManager_FWD_DEFINED__ */
+
+
+#ifndef __IPrivateManagedExceptionReporting_FWD_DEFINED__
+#define __IPrivateManagedExceptionReporting_FWD_DEFINED__
+typedef interface IPrivateManagedExceptionReporting IPrivateManagedExceptionReporting;
+
+#endif /* __IPrivateManagedExceptionReporting_FWD_DEFINED__ */
+
+
+/* header files for imported files */
+#include "unknwn.h"
+#include "mscoree.h"
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+
+/* interface __MIDL_itf_clrinternal_0000_0000 */
+/* [local] */
+
+#if 0
+typedef struct _OSVERSIONINFOA
+ {
+ DWORD dwOSVersionInfoSize;
+ DWORD dwMajorVersion;
+ DWORD dwMinorVersion;
+ DWORD dwBuildNumber;
+ DWORD dwPlatformId;
+ CHAR szCSDVersion[ 128 ];
+ } OSVERSIONINFOA;
+
+typedef struct _OSVERSIONINFOA *POSVERSIONINFOA;
+
+typedef struct _OSVERSIONINFOA *LPOSVERSIONINFOA;
+
+typedef struct _OSVERSIONINFOW
+ {
+ DWORD dwOSVersionInfoSize;
+ DWORD dwMajorVersion;
+ DWORD dwMinorVersion;
+ DWORD dwBuildNumber;
+ DWORD dwPlatformId;
+ WCHAR szCSDVersion[ 128 ];
+ } OSVERSIONINFOW;
+
+typedef struct _OSVERSIONINFOW *POSVERSIONINFOW;
+
+typedef struct _OSVERSIONINFOW *LPOSVERSIONINFOW;
+
+typedef struct _OSVERSIONINFOW RTL_OSVERSIONINFOW;
+
+typedef struct _OSVERSIONINFOW *PRTL_OSVERSIONINFOW;
+
+typedef OSVERSIONINFOA OSVERSIONINFO;
+
+typedef POSVERSIONINFOA POSVERSIONINFO;
+
+typedef LPOSVERSIONINFOA LPOSVERSIONINFO;
+
+#endif
+EXTERN_GUID(IID_IExecutionEngine, 0x7AF02DAC, 0x2A33, 0x494b, 0xA0, 0x9F, 0x25, 0xE0, 0x0A, 0x93, 0xC6, 0xF8);
+EXTERN_GUID(IID_IEEMemoryManager, 0x17713b61, 0xb59f, 0x4e13, 0xba, 0xaf, 0x91, 0x62, 0x3d, 0xc8, 0xad, 0xc0);
+EXTERN_GUID(CLR_ID_V4_DESKTOP, 0x267f3989, 0xd786, 0x4b9a, 0x9a, 0xf6, 0xd1, 0x9e, 0x42, 0xd5, 0x57, 0xec);
+EXTERN_GUID(CLR_ID_CORECLR, 0x8CB8E075, 0x0A91, 0x408E, 0x92, 0x28, 0xD6, 0x6E, 0x00, 0xA3, 0xBF, 0xF6 );
+EXTERN_GUID(CLR_ID_PHONE_CLR, 0xE7237E9C, 0x31C0, 0x488C, 0xAD, 0x48, 0x32, 0x4D, 0x3E, 0x7E, 0xD9, 0x2A);
+EXTERN_GUID(CLR_ID_ONECORE_CLR, 0xb1ee760d, 0x6c4a, 0x4533, 0xba, 0x41, 0x6f, 0x4f, 0x66, 0x1f, 0xab, 0xaf);
+EXTERN_GUID(IID_IPrivateManagedExceptionReporting, 0xad76a023, 0x332d, 0x4298, 0x80, 0x01, 0x07, 0xaa, 0x93, 0x50, 0xdc, 0xa4);
+typedef void *CRITSEC_COOKIE;
+
+typedef void *EVENT_COOKIE;
+
+typedef void *SEMAPHORE_COOKIE;
+
+typedef void *MUTEX_COOKIE;
+
+typedef /* [public][public] */
+enum __MIDL___MIDL_itf_clrinternal_0000_0000_0001
+ {
+ CRST_DEFAULT = 0,
+ CRST_REENTRANCY = 0x1,
+ CRST_UNSAFE_SAMELEVEL = 0x2,
+ CRST_UNSAFE_COOPGC = 0x4,
+ CRST_UNSAFE_ANYMODE = 0x8,
+ CRST_DEBUGGER_THREAD = 0x10,
+ CRST_HOST_BREAKABLE = 0x20,
+ CRST_TAKEN_DURING_SHUTDOWN = 0x80,
+ CRST_GC_NOTRIGGER_WHEN_TAKEN = 0x100,
+ CRST_DEBUG_ONLY_CHECK_FORBID_SUSPEND_THREAD = 0x200
+ } CrstFlags;
+
+typedef VOID ( __stdcall *PTLS_CALLBACK_FUNCTION )(
+ PVOID __MIDL____MIDL_itf_clrinternal_0000_00000000);
+
+
+
+extern RPC_IF_HANDLE __MIDL_itf_clrinternal_0000_0000_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_clrinternal_0000_0000_v0_0_s_ifspec;
+
+#ifndef __IExecutionEngine_INTERFACE_DEFINED__
+#define __IExecutionEngine_INTERFACE_DEFINED__
+
+/* interface IExecutionEngine */
+/* [object][local][unique][helpstring][uuid] */
+
+
+EXTERN_C const IID IID_IExecutionEngine;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("7AF02DAC-2A33-494b-A09F-25E00A93C6F8")
+ IExecutionEngine : public IUnknown
+ {
+ public:
+ virtual void STDMETHODCALLTYPE TLS_AssociateCallback(
+ /* [in] */ DWORD slot,
+ /* [in] */ PTLS_CALLBACK_FUNCTION callback) = 0;
+
+ virtual PVOID *STDMETHODCALLTYPE TLS_GetDataBlock( void) = 0;
+
+ virtual PVOID STDMETHODCALLTYPE TLS_GetValue(
+ /* [in] */ DWORD slot) = 0;
+
+ virtual BOOL STDMETHODCALLTYPE TLS_CheckValue(
+ /* [in] */ DWORD slot,
+ /* [out] */ PVOID *pValue) = 0;
+
+ virtual void STDMETHODCALLTYPE TLS_SetValue(
+ /* [in] */ DWORD slot,
+ /* [in] */ PVOID pData) = 0;
+
+ virtual void STDMETHODCALLTYPE TLS_ThreadDetaching( void) = 0;
+
+ virtual CRITSEC_COOKIE STDMETHODCALLTYPE CreateLock(
+ /* [in] */ LPCSTR szTag,
+ /* [in] */ LPCSTR level,
+ /* [in] */ CrstFlags flags) = 0;
+
+ virtual void STDMETHODCALLTYPE DestroyLock(
+ /* [in] */ CRITSEC_COOKIE lock) = 0;
+
+ virtual void STDMETHODCALLTYPE AcquireLock(
+ /* [in] */ CRITSEC_COOKIE lock) = 0;
+
+ virtual void STDMETHODCALLTYPE ReleaseLock(
+ /* [in] */ CRITSEC_COOKIE lock) = 0;
+
+ virtual EVENT_COOKIE STDMETHODCALLTYPE CreateAutoEvent(
+ /* [in] */ BOOL bInitialState) = 0;
+
+ virtual EVENT_COOKIE STDMETHODCALLTYPE CreateManualEvent(
+ /* [in] */ BOOL bInitialState) = 0;
+
+ virtual void STDMETHODCALLTYPE CloseEvent(
+ /* [in] */ EVENT_COOKIE event) = 0;
+
+ virtual BOOL STDMETHODCALLTYPE ClrSetEvent(
+ /* [in] */ EVENT_COOKIE event) = 0;
+
+ virtual BOOL STDMETHODCALLTYPE ClrResetEvent(
+ /* [in] */ EVENT_COOKIE event) = 0;
+
+ virtual DWORD STDMETHODCALLTYPE WaitForEvent(
+ /* [in] */ EVENT_COOKIE event,
+ /* [in] */ DWORD dwMilliseconds,
+ /* [in] */ BOOL bAlertable) = 0;
+
+ virtual DWORD STDMETHODCALLTYPE WaitForSingleObject(
+ /* [in] */ HANDLE handle,
+ /* [in] */ DWORD dwMilliseconds) = 0;
+
+ virtual SEMAPHORE_COOKIE STDMETHODCALLTYPE ClrCreateSemaphore(
+ /* [in] */ DWORD dwInitial,
+ /* [in] */ DWORD dwMax) = 0;
+
+ virtual void STDMETHODCALLTYPE ClrCloseSemaphore(
+ /* [in] */ SEMAPHORE_COOKIE semaphore) = 0;
+
+ virtual DWORD STDMETHODCALLTYPE ClrWaitForSemaphore(
+ /* [in] */ SEMAPHORE_COOKIE semaphore,
+ /* [in] */ DWORD dwMilliseconds,
+ /* [in] */ BOOL bAlertable) = 0;
+
+ virtual BOOL STDMETHODCALLTYPE ClrReleaseSemaphore(
+ /* [in] */ SEMAPHORE_COOKIE semaphore,
+ /* [in] */ LONG lReleaseCount,
+ /* [in] */ LONG *lpPreviousCount) = 0;
+
+ virtual MUTEX_COOKIE STDMETHODCALLTYPE ClrCreateMutex(
+ /* [in] */ LPSECURITY_ATTRIBUTES lpMutexAttributes,
+ /* [in] */ BOOL bInitialOwner,
+ /* [in] */ LPCTSTR lpName) = 0;
+
+ virtual DWORD STDMETHODCALLTYPE ClrWaitForMutex(
+ /* [in] */ MUTEX_COOKIE mutex,
+ /* [in] */ DWORD dwMilliseconds,
+ /* [in] */ BOOL bAlertable) = 0;
+
+ virtual BOOL STDMETHODCALLTYPE ClrReleaseMutex(
+ /* [in] */ MUTEX_COOKIE mutex) = 0;
+
+ virtual void STDMETHODCALLTYPE ClrCloseMutex(
+ /* [in] */ MUTEX_COOKIE mutex) = 0;
+
+ virtual DWORD STDMETHODCALLTYPE ClrSleepEx(
+ /* [in] */ DWORD dwMilliseconds,
+ /* [in] */ BOOL bAlertable) = 0;
+
+ virtual BOOL STDMETHODCALLTYPE ClrAllocationDisallowed( void) = 0;
+
+ virtual void STDMETHODCALLTYPE GetLastThrownObjectExceptionFromThread(
+ /* [out] */ void **ppvException) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IExecutionEngineVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IExecutionEngine * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IExecutionEngine * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IExecutionEngine * This);
+
+ void ( STDMETHODCALLTYPE *TLS_AssociateCallback )(
+ IExecutionEngine * This,
+ /* [in] */ DWORD slot,
+ /* [in] */ PTLS_CALLBACK_FUNCTION callback);
+
+ PVOID *( STDMETHODCALLTYPE *TLS_GetDataBlock )(
+ IExecutionEngine * This);
+
+ PVOID ( STDMETHODCALLTYPE *TLS_GetValue )(
+ IExecutionEngine * This,
+ /* [in] */ DWORD slot);
+
+ BOOL ( STDMETHODCALLTYPE *TLS_CheckValue )(
+ IExecutionEngine * This,
+ /* [in] */ DWORD slot,
+ /* [out] */ PVOID *pValue);
+
+ void ( STDMETHODCALLTYPE *TLS_SetValue )(
+ IExecutionEngine * This,
+ /* [in] */ DWORD slot,
+ /* [in] */ PVOID pData);
+
+ void ( STDMETHODCALLTYPE *TLS_ThreadDetaching )(
+ IExecutionEngine * This);
+
+ CRITSEC_COOKIE ( STDMETHODCALLTYPE *CreateLock )(
+ IExecutionEngine * This,
+ /* [in] */ LPCSTR szTag,
+ /* [in] */ LPCSTR level,
+ /* [in] */ CrstFlags flags);
+
+ void ( STDMETHODCALLTYPE *DestroyLock )(
+ IExecutionEngine * This,
+ /* [in] */ CRITSEC_COOKIE lock);
+
+ void ( STDMETHODCALLTYPE *AcquireLock )(
+ IExecutionEngine * This,
+ /* [in] */ CRITSEC_COOKIE lock);
+
+ void ( STDMETHODCALLTYPE *ReleaseLock )(
+ IExecutionEngine * This,
+ /* [in] */ CRITSEC_COOKIE lock);
+
+ EVENT_COOKIE ( STDMETHODCALLTYPE *CreateAutoEvent )(
+ IExecutionEngine * This,
+ /* [in] */ BOOL bInitialState);
+
+ EVENT_COOKIE ( STDMETHODCALLTYPE *CreateManualEvent )(
+ IExecutionEngine * This,
+ /* [in] */ BOOL bInitialState);
+
+ void ( STDMETHODCALLTYPE *CloseEvent )(
+ IExecutionEngine * This,
+ /* [in] */ EVENT_COOKIE event);
+
+ BOOL ( STDMETHODCALLTYPE *ClrSetEvent )(
+ IExecutionEngine * This,
+ /* [in] */ EVENT_COOKIE event);
+
+ BOOL ( STDMETHODCALLTYPE *ClrResetEvent )(
+ IExecutionEngine * This,
+ /* [in] */ EVENT_COOKIE event);
+
+ DWORD ( STDMETHODCALLTYPE *WaitForEvent )(
+ IExecutionEngine * This,
+ /* [in] */ EVENT_COOKIE event,
+ /* [in] */ DWORD dwMilliseconds,
+ /* [in] */ BOOL bAlertable);
+
+ DWORD ( STDMETHODCALLTYPE *WaitForSingleObject )(
+ IExecutionEngine * This,
+ /* [in] */ HANDLE handle,
+ /* [in] */ DWORD dwMilliseconds);
+
+ SEMAPHORE_COOKIE ( STDMETHODCALLTYPE *ClrCreateSemaphore )(
+ IExecutionEngine * This,
+ /* [in] */ DWORD dwInitial,
+ /* [in] */ DWORD dwMax);
+
+ void ( STDMETHODCALLTYPE *ClrCloseSemaphore )(
+ IExecutionEngine * This,
+ /* [in] */ SEMAPHORE_COOKIE semaphore);
+
+ DWORD ( STDMETHODCALLTYPE *ClrWaitForSemaphore )(
+ IExecutionEngine * This,
+ /* [in] */ SEMAPHORE_COOKIE semaphore,
+ /* [in] */ DWORD dwMilliseconds,
+ /* [in] */ BOOL bAlertable);
+
+ BOOL ( STDMETHODCALLTYPE *ClrReleaseSemaphore )(
+ IExecutionEngine * This,
+ /* [in] */ SEMAPHORE_COOKIE semaphore,
+ /* [in] */ LONG lReleaseCount,
+ /* [in] */ LONG *lpPreviousCount);
+
+ MUTEX_COOKIE ( STDMETHODCALLTYPE *ClrCreateMutex )(
+ IExecutionEngine * This,
+ /* [in] */ LPSECURITY_ATTRIBUTES lpMutexAttributes,
+ /* [in] */ BOOL bInitialOwner,
+ /* [in] */ LPCTSTR lpName);
+
+ DWORD ( STDMETHODCALLTYPE *ClrWaitForMutex )(
+ IExecutionEngine * This,
+ /* [in] */ MUTEX_COOKIE mutex,
+ /* [in] */ DWORD dwMilliseconds,
+ /* [in] */ BOOL bAlertable);
+
+ BOOL ( STDMETHODCALLTYPE *ClrReleaseMutex )(
+ IExecutionEngine * This,
+ /* [in] */ MUTEX_COOKIE mutex);
+
+ void ( STDMETHODCALLTYPE *ClrCloseMutex )(
+ IExecutionEngine * This,
+ /* [in] */ MUTEX_COOKIE mutex);
+
+ DWORD ( STDMETHODCALLTYPE *ClrSleepEx )(
+ IExecutionEngine * This,
+ /* [in] */ DWORD dwMilliseconds,
+ /* [in] */ BOOL bAlertable);
+
+ BOOL ( STDMETHODCALLTYPE *ClrAllocationDisallowed )(
+ IExecutionEngine * This);
+
+ void ( STDMETHODCALLTYPE *GetLastThrownObjectExceptionFromThread )(
+ IExecutionEngine * This,
+ /* [out] */ void **ppvException);
+
+ END_INTERFACE
+ } IExecutionEngineVtbl;
+
+ interface IExecutionEngine
+ {
+ CONST_VTBL struct IExecutionEngineVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IExecutionEngine_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IExecutionEngine_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IExecutionEngine_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IExecutionEngine_TLS_AssociateCallback(This,slot,callback) \
+ ( (This)->lpVtbl -> TLS_AssociateCallback(This,slot,callback) )
+
+#define IExecutionEngine_TLS_GetDataBlock(This) \
+ ( (This)->lpVtbl -> TLS_GetDataBlock(This) )
+
+#define IExecutionEngine_TLS_GetValue(This,slot) \
+ ( (This)->lpVtbl -> TLS_GetValue(This,slot) )
+
+#define IExecutionEngine_TLS_CheckValue(This,slot,pValue) \
+ ( (This)->lpVtbl -> TLS_CheckValue(This,slot,pValue) )
+
+#define IExecutionEngine_TLS_SetValue(This,slot,pData) \
+ ( (This)->lpVtbl -> TLS_SetValue(This,slot,pData) )
+
+#define IExecutionEngine_TLS_ThreadDetaching(This) \
+ ( (This)->lpVtbl -> TLS_ThreadDetaching(This) )
+
+#define IExecutionEngine_CreateLock(This,szTag,level,flags) \
+ ( (This)->lpVtbl -> CreateLock(This,szTag,level,flags) )
+
+#define IExecutionEngine_DestroyLock(This,lock) \
+ ( (This)->lpVtbl -> DestroyLock(This,lock) )
+
+#define IExecutionEngine_AcquireLock(This,lock) \
+ ( (This)->lpVtbl -> AcquireLock(This,lock) )
+
+#define IExecutionEngine_ReleaseLock(This,lock) \
+ ( (This)->lpVtbl -> ReleaseLock(This,lock) )
+
+#define IExecutionEngine_CreateAutoEvent(This,bInitialState) \
+ ( (This)->lpVtbl -> CreateAutoEvent(This,bInitialState) )
+
+#define IExecutionEngine_CreateManualEvent(This,bInitialState) \
+ ( (This)->lpVtbl -> CreateManualEvent(This,bInitialState) )
+
+#define IExecutionEngine_CloseEvent(This,event) \
+ ( (This)->lpVtbl -> CloseEvent(This,event) )
+
+#define IExecutionEngine_ClrSetEvent(This,event) \
+ ( (This)->lpVtbl -> ClrSetEvent(This,event) )
+
+#define IExecutionEngine_ClrResetEvent(This,event) \
+ ( (This)->lpVtbl -> ClrResetEvent(This,event) )
+
+#define IExecutionEngine_WaitForEvent(This,event,dwMilliseconds,bAlertable) \
+ ( (This)->lpVtbl -> WaitForEvent(This,event,dwMilliseconds,bAlertable) )
+
+#define IExecutionEngine_WaitForSingleObject(This,handle,dwMilliseconds) \
+ ( (This)->lpVtbl -> WaitForSingleObject(This,handle,dwMilliseconds) )
+
+#define IExecutionEngine_ClrCreateSemaphore(This,dwInitial,dwMax) \
+ ( (This)->lpVtbl -> ClrCreateSemaphore(This,dwInitial,dwMax) )
+
+#define IExecutionEngine_ClrCloseSemaphore(This,semaphore) \
+ ( (This)->lpVtbl -> ClrCloseSemaphore(This,semaphore) )
+
+#define IExecutionEngine_ClrWaitForSemaphore(This,semaphore,dwMilliseconds,bAlertable) \
+ ( (This)->lpVtbl -> ClrWaitForSemaphore(This,semaphore,dwMilliseconds,bAlertable) )
+
+#define IExecutionEngine_ClrReleaseSemaphore(This,semaphore,lReleaseCount,lpPreviousCount) \
+ ( (This)->lpVtbl -> ClrReleaseSemaphore(This,semaphore,lReleaseCount,lpPreviousCount) )
+
+#define IExecutionEngine_ClrCreateMutex(This,lpMutexAttributes,bInitialOwner,lpName) \
+ ( (This)->lpVtbl -> ClrCreateMutex(This,lpMutexAttributes,bInitialOwner,lpName) )
+
+#define IExecutionEngine_ClrWaitForMutex(This,mutex,dwMilliseconds,bAlertable) \
+ ( (This)->lpVtbl -> ClrWaitForMutex(This,mutex,dwMilliseconds,bAlertable) )
+
+#define IExecutionEngine_ClrReleaseMutex(This,mutex) \
+ ( (This)->lpVtbl -> ClrReleaseMutex(This,mutex) )
+
+#define IExecutionEngine_ClrCloseMutex(This,mutex) \
+ ( (This)->lpVtbl -> ClrCloseMutex(This,mutex) )
+
+#define IExecutionEngine_ClrSleepEx(This,dwMilliseconds,bAlertable) \
+ ( (This)->lpVtbl -> ClrSleepEx(This,dwMilliseconds,bAlertable) )
+
+#define IExecutionEngine_ClrAllocationDisallowed(This) \
+ ( (This)->lpVtbl -> ClrAllocationDisallowed(This) )
+
+#define IExecutionEngine_GetLastThrownObjectExceptionFromThread(This,ppvException) \
+ ( (This)->lpVtbl -> GetLastThrownObjectExceptionFromThread(This,ppvException) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IExecutionEngine_INTERFACE_DEFINED__ */
+
+
+/* interface __MIDL_itf_clrinternal_0000_0001 */
+/* [local] */
+
+#if !defined(_WINNT_) && !defined(_NTMMAPI_)
+typedef void *PMEMORY_BASIC_INFORMATION;
+
+#endif
+
+
+extern RPC_IF_HANDLE __MIDL_itf_clrinternal_0000_0001_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_clrinternal_0000_0001_v0_0_s_ifspec;
+
+#ifndef __IEEMemoryManager_INTERFACE_DEFINED__
+#define __IEEMemoryManager_INTERFACE_DEFINED__
+
+/* interface IEEMemoryManager */
+/* [object][local][unique][helpstring][uuid] */
+
+
+EXTERN_C const IID IID_IEEMemoryManager;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("17713B61-B59F-4e13-BAAF-91623DC8ADC0")
+ IEEMemoryManager : public IUnknown
+ {
+ public:
+ virtual LPVOID STDMETHODCALLTYPE ClrVirtualAlloc(
+ /* [in] */ LPVOID lpAddress,
+ /* [in] */ SIZE_T dwSize,
+ /* [in] */ DWORD flAllocationType,
+ /* [in] */ DWORD flProtect) = 0;
+
+ virtual BOOL STDMETHODCALLTYPE ClrVirtualFree(
+ /* [in] */ LPVOID lpAddress,
+ /* [in] */ SIZE_T dwSize,
+ /* [in] */ DWORD dwFreeType) = 0;
+
+ virtual SIZE_T STDMETHODCALLTYPE ClrVirtualQuery(
+ /* [in] */ const void *lpAddress,
+ /* [in] */ PMEMORY_BASIC_INFORMATION lpBuffer,
+ /* [in] */ SIZE_T dwLength) = 0;
+
+ virtual BOOL STDMETHODCALLTYPE ClrVirtualProtect(
+ /* [in] */ LPVOID lpAddress,
+ /* [in] */ SIZE_T dwSize,
+ /* [in] */ DWORD flNewProtect,
+ /* [in] */ DWORD *lpflOldProtect) = 0;
+
+ virtual HANDLE STDMETHODCALLTYPE ClrGetProcessHeap( void) = 0;
+
+ virtual HANDLE STDMETHODCALLTYPE ClrHeapCreate(
+ /* [in] */ DWORD flOptions,
+ /* [in] */ SIZE_T dwInitialSize,
+ /* [in] */ SIZE_T dwMaximumSize) = 0;
+
+ virtual BOOL STDMETHODCALLTYPE ClrHeapDestroy(
+ /* [in] */ HANDLE hHeap) = 0;
+
+ virtual LPVOID STDMETHODCALLTYPE ClrHeapAlloc(
+ /* [in] */ HANDLE hHeap,
+ /* [in] */ DWORD dwFlags,
+ /* [in] */ SIZE_T dwBytes) = 0;
+
+ virtual BOOL STDMETHODCALLTYPE ClrHeapFree(
+ /* [in] */ HANDLE hHeap,
+ /* [in] */ DWORD dwFlags,
+ /* [in] */ LPVOID lpMem) = 0;
+
+ virtual BOOL STDMETHODCALLTYPE ClrHeapValidate(
+ /* [in] */ HANDLE hHeap,
+ /* [in] */ DWORD dwFlags,
+ /* [in] */ const void *lpMem) = 0;
+
+ virtual HANDLE STDMETHODCALLTYPE ClrGetProcessExecutableHeap( void) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IEEMemoryManagerVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IEEMemoryManager * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IEEMemoryManager * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IEEMemoryManager * This);
+
+ LPVOID ( STDMETHODCALLTYPE *ClrVirtualAlloc )(
+ IEEMemoryManager * This,
+ /* [in] */ LPVOID lpAddress,
+ /* [in] */ SIZE_T dwSize,
+ /* [in] */ DWORD flAllocationType,
+ /* [in] */ DWORD flProtect);
+
+ BOOL ( STDMETHODCALLTYPE *ClrVirtualFree )(
+ IEEMemoryManager * This,
+ /* [in] */ LPVOID lpAddress,
+ /* [in] */ SIZE_T dwSize,
+ /* [in] */ DWORD dwFreeType);
+
+ SIZE_T ( STDMETHODCALLTYPE *ClrVirtualQuery )(
+ IEEMemoryManager * This,
+ /* [in] */ const void *lpAddress,
+ /* [in] */ PMEMORY_BASIC_INFORMATION lpBuffer,
+ /* [in] */ SIZE_T dwLength);
+
+ BOOL ( STDMETHODCALLTYPE *ClrVirtualProtect )(
+ IEEMemoryManager * This,
+ /* [in] */ LPVOID lpAddress,
+ /* [in] */ SIZE_T dwSize,
+ /* [in] */ DWORD flNewProtect,
+ /* [in] */ DWORD *lpflOldProtect);
+
+ HANDLE ( STDMETHODCALLTYPE *ClrGetProcessHeap )(
+ IEEMemoryManager * This);
+
+ HANDLE ( STDMETHODCALLTYPE *ClrHeapCreate )(
+ IEEMemoryManager * This,
+ /* [in] */ DWORD flOptions,
+ /* [in] */ SIZE_T dwInitialSize,
+ /* [in] */ SIZE_T dwMaximumSize);
+
+ BOOL ( STDMETHODCALLTYPE *ClrHeapDestroy )(
+ IEEMemoryManager * This,
+ /* [in] */ HANDLE hHeap);
+
+ LPVOID ( STDMETHODCALLTYPE *ClrHeapAlloc )(
+ IEEMemoryManager * This,
+ /* [in] */ HANDLE hHeap,
+ /* [in] */ DWORD dwFlags,
+ /* [in] */ SIZE_T dwBytes);
+
+ BOOL ( STDMETHODCALLTYPE *ClrHeapFree )(
+ IEEMemoryManager * This,
+ /* [in] */ HANDLE hHeap,
+ /* [in] */ DWORD dwFlags,
+ /* [in] */ LPVOID lpMem);
+
+ BOOL ( STDMETHODCALLTYPE *ClrHeapValidate )(
+ IEEMemoryManager * This,
+ /* [in] */ HANDLE hHeap,
+ /* [in] */ DWORD dwFlags,
+ /* [in] */ const void *lpMem);
+
+ HANDLE ( STDMETHODCALLTYPE *ClrGetProcessExecutableHeap )(
+ IEEMemoryManager * This);
+
+ END_INTERFACE
+ } IEEMemoryManagerVtbl;
+
+ interface IEEMemoryManager
+ {
+ CONST_VTBL struct IEEMemoryManagerVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IEEMemoryManager_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IEEMemoryManager_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IEEMemoryManager_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IEEMemoryManager_ClrVirtualAlloc(This,lpAddress,dwSize,flAllocationType,flProtect) \
+ ( (This)->lpVtbl -> ClrVirtualAlloc(This,lpAddress,dwSize,flAllocationType,flProtect) )
+
+#define IEEMemoryManager_ClrVirtualFree(This,lpAddress,dwSize,dwFreeType) \
+ ( (This)->lpVtbl -> ClrVirtualFree(This,lpAddress,dwSize,dwFreeType) )
+
+#define IEEMemoryManager_ClrVirtualQuery(This,lpAddress,lpBuffer,dwLength) \
+ ( (This)->lpVtbl -> ClrVirtualQuery(This,lpAddress,lpBuffer,dwLength) )
+
+#define IEEMemoryManager_ClrVirtualProtect(This,lpAddress,dwSize,flNewProtect,lpflOldProtect) \
+ ( (This)->lpVtbl -> ClrVirtualProtect(This,lpAddress,dwSize,flNewProtect,lpflOldProtect) )
+
+#define IEEMemoryManager_ClrGetProcessHeap(This) \
+ ( (This)->lpVtbl -> ClrGetProcessHeap(This) )
+
+#define IEEMemoryManager_ClrHeapCreate(This,flOptions,dwInitialSize,dwMaximumSize) \
+ ( (This)->lpVtbl -> ClrHeapCreate(This,flOptions,dwInitialSize,dwMaximumSize) )
+
+#define IEEMemoryManager_ClrHeapDestroy(This,hHeap) \
+ ( (This)->lpVtbl -> ClrHeapDestroy(This,hHeap) )
+
+#define IEEMemoryManager_ClrHeapAlloc(This,hHeap,dwFlags,dwBytes) \
+ ( (This)->lpVtbl -> ClrHeapAlloc(This,hHeap,dwFlags,dwBytes) )
+
+#define IEEMemoryManager_ClrHeapFree(This,hHeap,dwFlags,lpMem) \
+ ( (This)->lpVtbl -> ClrHeapFree(This,hHeap,dwFlags,lpMem) )
+
+#define IEEMemoryManager_ClrHeapValidate(This,hHeap,dwFlags,lpMem) \
+ ( (This)->lpVtbl -> ClrHeapValidate(This,hHeap,dwFlags,lpMem) )
+
+#define IEEMemoryManager_ClrGetProcessExecutableHeap(This) \
+ ( (This)->lpVtbl -> ClrGetProcessExecutableHeap(This) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IEEMemoryManager_INTERFACE_DEFINED__ */
+
+
+#ifndef __IPrivateManagedExceptionReporting_INTERFACE_DEFINED__
+#define __IPrivateManagedExceptionReporting_INTERFACE_DEFINED__
+
+/* interface IPrivateManagedExceptionReporting */
+/* [object][local][unique][helpstring][uuid] */
+
+
+EXTERN_C const IID IID_IPrivateManagedExceptionReporting;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("AD76A023-332D-4298-8001-07AA9350DCA4")
+ IPrivateManagedExceptionReporting : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetBucketParametersForCurrentException(
+ /* [out] */ BucketParameters *pParams) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IPrivateManagedExceptionReportingVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IPrivateManagedExceptionReporting * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IPrivateManagedExceptionReporting * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IPrivateManagedExceptionReporting * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetBucketParametersForCurrentException )(
+ IPrivateManagedExceptionReporting * This,
+ /* [out] */ BucketParameters *pParams);
+
+ END_INTERFACE
+ } IPrivateManagedExceptionReportingVtbl;
+
+ interface IPrivateManagedExceptionReporting
+ {
+ CONST_VTBL struct IPrivateManagedExceptionReportingVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IPrivateManagedExceptionReporting_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IPrivateManagedExceptionReporting_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IPrivateManagedExceptionReporting_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IPrivateManagedExceptionReporting_GetBucketParametersForCurrentException(This,pParams) \
+ ( (This)->lpVtbl -> GetBucketParametersForCurrentException(This,pParams) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IPrivateManagedExceptionReporting_INTERFACE_DEFINED__ */
+
+
+/* Additional Prototypes for ALL interfaces */
+
+/* end of Additional Prototypes */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+
diff --git a/src/pal/prebuilt/inc/clrprivbinding.h b/src/pal/prebuilt/inc/clrprivbinding.h
new file mode 100644
index 0000000000..4d3d36d05f
--- /dev/null
+++ b/src/pal/prebuilt/inc/clrprivbinding.h
@@ -0,0 +1,1124 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+
+
+/* this ALWAYS GENERATED file contains the definitions for the interfaces */
+
+
+ /* File created by MIDL compiler version 8.00.0603 */
+/* @@MIDL_FILE_HEADING( ) */
+
+#pragma warning( disable: 4049 ) /* more than 64k source lines */
+
+
+/* verify that the <rpcndr.h> version is high enough to compile this file*/
+#ifndef __REQUIRED_RPCNDR_H_VERSION__
+#define __REQUIRED_RPCNDR_H_VERSION__ 475
+#endif
+
+#include "rpc.h"
+#include "rpcndr.h"
+
+#ifndef __RPCNDR_H_VERSION__
+#error this stub requires an updated version of <rpcndr.h>
+#endif // __RPCNDR_H_VERSION__
+
+#ifndef COM_NO_WINDOWS_H
+#include "windows.h"
+#include "ole2.h"
+#endif /*COM_NO_WINDOWS_H*/
+
+#ifndef __CLRPrivBinding_h__
+#define __CLRPrivBinding_h__
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+/* Forward Declarations */
+
+#ifndef __ICLRPrivBinder_FWD_DEFINED__
+#define __ICLRPrivBinder_FWD_DEFINED__
+typedef interface ICLRPrivBinder ICLRPrivBinder;
+
+#endif /* __ICLRPrivBinder_FWD_DEFINED__ */
+
+
+#ifndef __ICLRPrivAssembly_FWD_DEFINED__
+#define __ICLRPrivAssembly_FWD_DEFINED__
+typedef interface ICLRPrivAssembly ICLRPrivAssembly;
+
+#endif /* __ICLRPrivAssembly_FWD_DEFINED__ */
+
+
+#ifndef __ICLRPrivResource_FWD_DEFINED__
+#define __ICLRPrivResource_FWD_DEFINED__
+typedef interface ICLRPrivResource ICLRPrivResource;
+
+#endif /* __ICLRPrivResource_FWD_DEFINED__ */
+
+
+#ifndef __ICLRPrivResourcePath_FWD_DEFINED__
+#define __ICLRPrivResourcePath_FWD_DEFINED__
+typedef interface ICLRPrivResourcePath ICLRPrivResourcePath;
+
+#endif /* __ICLRPrivResourcePath_FWD_DEFINED__ */
+
+
+#ifndef __ICLRPrivResourceStream_FWD_DEFINED__
+#define __ICLRPrivResourceStream_FWD_DEFINED__
+typedef interface ICLRPrivResourceStream ICLRPrivResourceStream;
+
+#endif /* __ICLRPrivResourceStream_FWD_DEFINED__ */
+
+
+#ifndef __ICLRPrivResourceHMODULE_FWD_DEFINED__
+#define __ICLRPrivResourceHMODULE_FWD_DEFINED__
+typedef interface ICLRPrivResourceHMODULE ICLRPrivResourceHMODULE;
+
+#endif /* __ICLRPrivResourceHMODULE_FWD_DEFINED__ */
+
+
+#ifndef __ICLRPrivResourceAssembly_FWD_DEFINED__
+#define __ICLRPrivResourceAssembly_FWD_DEFINED__
+typedef interface ICLRPrivResourceAssembly ICLRPrivResourceAssembly;
+
+#endif /* __ICLRPrivResourceAssembly_FWD_DEFINED__ */
+
+
+#ifndef __ICLRPrivAssemblyInfo_FWD_DEFINED__
+#define __ICLRPrivAssemblyInfo_FWD_DEFINED__
+typedef interface ICLRPrivAssemblyInfo ICLRPrivAssemblyInfo;
+
+#endif /* __ICLRPrivAssemblyInfo_FWD_DEFINED__ */
+
+
+#ifndef __ICLRPrivAssemblyID_WinRT_FWD_DEFINED__
+#define __ICLRPrivAssemblyID_WinRT_FWD_DEFINED__
+typedef interface ICLRPrivAssemblyID_WinRT ICLRPrivAssemblyID_WinRT;
+
+#endif /* __ICLRPrivAssemblyID_WinRT_FWD_DEFINED__ */
+
+
+#ifndef __ICLRPrivWinRtTypeBinder_FWD_DEFINED__
+#define __ICLRPrivWinRtTypeBinder_FWD_DEFINED__
+typedef interface ICLRPrivWinRtTypeBinder ICLRPrivWinRtTypeBinder;
+
+#endif /* __ICLRPrivWinRtTypeBinder_FWD_DEFINED__ */
+
+
+/* header files for imported files */
+#include "unknwn.h"
+#include "objidl.h"
+#include "fusion.h"
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+
+/* interface __MIDL_itf_CLRPrivBinding_0000_0000 */
+/* [local] */
+
+
+
+
+
+
+
+
+typedef LPCSTR LPCUTF8;
+
+
+
+extern RPC_IF_HANDLE __MIDL_itf_CLRPrivBinding_0000_0000_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_CLRPrivBinding_0000_0000_v0_0_s_ifspec;
+
+#ifndef __ICLRPrivBinder_INTERFACE_DEFINED__
+#define __ICLRPrivBinder_INTERFACE_DEFINED__
+
+/* interface ICLRPrivBinder */
+/* [object][local][version][uuid] */
+
+
+EXTERN_C const IID IID_ICLRPrivBinder;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("2601F621-E462-404C-B299-3E1DE72F8542")
+ ICLRPrivBinder : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE BindAssemblyByName(
+ /* [in] */ IAssemblyName *pAssemblyName,
+ /* [retval][out] */ ICLRPrivAssembly **ppAssembly) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE VerifyBind(
+ /* [in] */ IAssemblyName *AssemblyName,
+ /* [in] */ ICLRPrivAssembly *pAssembly,
+ /* [in] */ ICLRPrivAssemblyInfo *pAssemblyInfo) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetBinderFlags(
+ /* [retval][out] */ DWORD *pBinderFlags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetBinderID(
+ /* [retval][out] */ UINT_PTR *pBinderId) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE FindAssemblyBySpec(
+ /* [in] */ LPVOID pvAppDomain,
+ /* [in] */ LPVOID pvAssemblySpec,
+ /* [out] */ HRESULT *pResult,
+ /* [out] */ ICLRPrivAssembly **ppAssembly) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICLRPrivBinderVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICLRPrivBinder * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICLRPrivBinder * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICLRPrivBinder * This);
+
+ HRESULT ( STDMETHODCALLTYPE *BindAssemblyByName )(
+ ICLRPrivBinder * This,
+ /* [in] */ IAssemblyName *pAssemblyName,
+ /* [retval][out] */ ICLRPrivAssembly **ppAssembly);
+
+ HRESULT ( STDMETHODCALLTYPE *VerifyBind )(
+ ICLRPrivBinder * This,
+ /* [in] */ IAssemblyName *AssemblyName,
+ /* [in] */ ICLRPrivAssembly *pAssembly,
+ /* [in] */ ICLRPrivAssemblyInfo *pAssemblyInfo);
+
+ HRESULT ( STDMETHODCALLTYPE *GetBinderFlags )(
+ ICLRPrivBinder * This,
+ /* [retval][out] */ DWORD *pBinderFlags);
+
+ HRESULT ( STDMETHODCALLTYPE *GetBinderID )(
+ ICLRPrivBinder * This,
+ /* [retval][out] */ UINT_PTR *pBinderId);
+
+ HRESULT ( STDMETHODCALLTYPE *FindAssemblyBySpec )(
+ ICLRPrivBinder * This,
+ /* [in] */ LPVOID pvAppDomain,
+ /* [in] */ LPVOID pvAssemblySpec,
+ /* [out] */ HRESULT *pResult,
+ /* [out] */ ICLRPrivAssembly **ppAssembly);
+
+ END_INTERFACE
+ } ICLRPrivBinderVtbl;
+
+ interface ICLRPrivBinder
+ {
+ CONST_VTBL struct ICLRPrivBinderVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICLRPrivBinder_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICLRPrivBinder_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICLRPrivBinder_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICLRPrivBinder_BindAssemblyByName(This,pAssemblyName,ppAssembly) \
+ ( (This)->lpVtbl -> BindAssemblyByName(This,pAssemblyName,ppAssembly) )
+
+#define ICLRPrivBinder_VerifyBind(This,AssemblyName,pAssembly,pAssemblyInfo) \
+ ( (This)->lpVtbl -> VerifyBind(This,AssemblyName,pAssembly,pAssemblyInfo) )
+
+#define ICLRPrivBinder_GetBinderFlags(This,pBinderFlags) \
+ ( (This)->lpVtbl -> GetBinderFlags(This,pBinderFlags) )
+
+#define ICLRPrivBinder_GetBinderID(This,pBinderId) \
+ ( (This)->lpVtbl -> GetBinderID(This,pBinderId) )
+
+#define ICLRPrivBinder_FindAssemblyBySpec(This,pvAppDomain,pvAssemblySpec,pResult,ppAssembly) \
+ ( (This)->lpVtbl -> FindAssemblyBySpec(This,pvAppDomain,pvAssemblySpec,pResult,ppAssembly) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICLRPrivBinder_INTERFACE_DEFINED__ */
+
+
+/* interface __MIDL_itf_CLRPrivBinding_0000_0001 */
+/* [local] */
+
+
+enum CLR_PRIV_BINDER_FLAGS
+ {
+ BINDER_NONE = 0,
+ BINDER_DESIGNER_BINDING_CONTEXT = 0x1,
+ BINDER_FINDASSEMBLYBYSPEC_REQUIRES_EXACT_MATCH = 0x2
+ } ;
+
+enum ASSEMBLY_IMAGE_TYPES
+ {
+ ASSEMBLY_IMAGE_TYPE_IL = 0x1,
+ ASSEMBLY_IMAGE_TYPE_NATIVE = 0x2,
+ ASSEMBLY_IMAGE_TYPE_DEFAULT = 0x3,
+ ASSEMBLY_IMAGE_TYPE_ASSEMBLY = 0x4
+ } ;
+
+
+extern RPC_IF_HANDLE __MIDL_itf_CLRPrivBinding_0000_0001_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_CLRPrivBinding_0000_0001_v0_0_s_ifspec;
+
+#ifndef __ICLRPrivAssembly_INTERFACE_DEFINED__
+#define __ICLRPrivAssembly_INTERFACE_DEFINED__
+
+/* interface ICLRPrivAssembly */
+/* [object][local][version][uuid] */
+
+
+EXTERN_C const IID IID_ICLRPrivAssembly;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("2601F621-E462-404C-B299-3E1DE72F8543")
+ ICLRPrivAssembly : public ICLRPrivBinder
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE IsShareable(
+ /* [retval][out] */ BOOL *pbIsShareable) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetAvailableImageTypes(
+ /* [retval][out] */ LPDWORD pdwImageTypes) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetImageResource(
+ /* [in] */ DWORD dwImageType,
+ /* [out] */ DWORD *pdwImageType,
+ /* [retval][out] */ ICLRPrivResource **ppIResource) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICLRPrivAssemblyVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICLRPrivAssembly * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICLRPrivAssembly * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICLRPrivAssembly * This);
+
+ HRESULT ( STDMETHODCALLTYPE *BindAssemblyByName )(
+ ICLRPrivAssembly * This,
+ /* [in] */ IAssemblyName *pAssemblyName,
+ /* [retval][out] */ ICLRPrivAssembly **ppAssembly);
+
+ HRESULT ( STDMETHODCALLTYPE *VerifyBind )(
+ ICLRPrivAssembly * This,
+ /* [in] */ IAssemblyName *AssemblyName,
+ /* [in] */ ICLRPrivAssembly *pAssembly,
+ /* [in] */ ICLRPrivAssemblyInfo *pAssemblyInfo);
+
+ HRESULT ( STDMETHODCALLTYPE *GetBinderFlags )(
+ ICLRPrivAssembly * This,
+ /* [retval][out] */ DWORD *pBinderFlags);
+
+ HRESULT ( STDMETHODCALLTYPE *GetBinderID )(
+ ICLRPrivAssembly * This,
+ /* [retval][out] */ UINT_PTR *pBinderId);
+
+ HRESULT ( STDMETHODCALLTYPE *FindAssemblyBySpec )(
+ ICLRPrivAssembly * This,
+ /* [in] */ LPVOID pvAppDomain,
+ /* [in] */ LPVOID pvAssemblySpec,
+ /* [out] */ HRESULT *pResult,
+ /* [out] */ ICLRPrivAssembly **ppAssembly);
+
+ HRESULT ( STDMETHODCALLTYPE *IsShareable )(
+ ICLRPrivAssembly * This,
+ /* [retval][out] */ BOOL *pbIsShareable);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAvailableImageTypes )(
+ ICLRPrivAssembly * This,
+ /* [retval][out] */ LPDWORD pdwImageTypes);
+
+ HRESULT ( STDMETHODCALLTYPE *GetImageResource )(
+ ICLRPrivAssembly * This,
+ /* [in] */ DWORD dwImageType,
+ /* [out] */ DWORD *pdwImageType,
+ /* [retval][out] */ ICLRPrivResource **ppIResource);
+
+ END_INTERFACE
+ } ICLRPrivAssemblyVtbl;
+
+ interface ICLRPrivAssembly
+ {
+ CONST_VTBL struct ICLRPrivAssemblyVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICLRPrivAssembly_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICLRPrivAssembly_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICLRPrivAssembly_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICLRPrivAssembly_BindAssemblyByName(This,pAssemblyName,ppAssembly) \
+ ( (This)->lpVtbl -> BindAssemblyByName(This,pAssemblyName,ppAssembly) )
+
+#define ICLRPrivAssembly_VerifyBind(This,AssemblyName,pAssembly,pAssemblyInfo) \
+ ( (This)->lpVtbl -> VerifyBind(This,AssemblyName,pAssembly,pAssemblyInfo) )
+
+#define ICLRPrivAssembly_GetBinderFlags(This,pBinderFlags) \
+ ( (This)->lpVtbl -> GetBinderFlags(This,pBinderFlags) )
+
+#define ICLRPrivAssembly_GetBinderID(This,pBinderId) \
+ ( (This)->lpVtbl -> GetBinderID(This,pBinderId) )
+
+#define ICLRPrivAssembly_FindAssemblyBySpec(This,pvAppDomain,pvAssemblySpec,pResult,ppAssembly) \
+ ( (This)->lpVtbl -> FindAssemblyBySpec(This,pvAppDomain,pvAssemblySpec,pResult,ppAssembly) )
+
+
+#define ICLRPrivAssembly_IsShareable(This,pbIsShareable) \
+ ( (This)->lpVtbl -> IsShareable(This,pbIsShareable) )
+
+#define ICLRPrivAssembly_GetAvailableImageTypes(This,pdwImageTypes) \
+ ( (This)->lpVtbl -> GetAvailableImageTypes(This,pdwImageTypes) )
+
+#define ICLRPrivAssembly_GetImageResource(This,dwImageType,pdwImageType,ppIResource) \
+ ( (This)->lpVtbl -> GetImageResource(This,dwImageType,pdwImageType,ppIResource) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICLRPrivAssembly_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICLRPrivResource_INTERFACE_DEFINED__
+#define __ICLRPrivResource_INTERFACE_DEFINED__
+
+/* interface ICLRPrivResource */
+/* [object][local][version][uuid] */
+
+
+EXTERN_C const IID IID_ICLRPrivResource;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("2601F621-E462-404C-B299-3E1DE72F8547")
+ ICLRPrivResource : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetResourceType(
+ /* [retval][out] */ IID *pIID) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICLRPrivResourceVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICLRPrivResource * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICLRPrivResource * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICLRPrivResource * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetResourceType )(
+ ICLRPrivResource * This,
+ /* [retval][out] */ IID *pIID);
+
+ END_INTERFACE
+ } ICLRPrivResourceVtbl;
+
+ interface ICLRPrivResource
+ {
+ CONST_VTBL struct ICLRPrivResourceVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICLRPrivResource_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICLRPrivResource_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICLRPrivResource_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICLRPrivResource_GetResourceType(This,pIID) \
+ ( (This)->lpVtbl -> GetResourceType(This,pIID) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICLRPrivResource_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICLRPrivResourcePath_INTERFACE_DEFINED__
+#define __ICLRPrivResourcePath_INTERFACE_DEFINED__
+
+/* interface ICLRPrivResourcePath */
+/* [object][local][version][uuid] */
+
+
+EXTERN_C const IID IID_ICLRPrivResourcePath;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("2601F621-E462-404C-B299-3E1DE72F8544")
+ ICLRPrivResourcePath : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetPath(
+ /* [in] */ DWORD cchBuffer,
+ /* [out] */ LPDWORD pcchBuffer,
+ /* [optional][string][length_is][size_is][out] */ LPWSTR wzBuffer) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICLRPrivResourcePathVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICLRPrivResourcePath * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICLRPrivResourcePath * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICLRPrivResourcePath * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetPath )(
+ ICLRPrivResourcePath * This,
+ /* [in] */ DWORD cchBuffer,
+ /* [out] */ LPDWORD pcchBuffer,
+ /* [optional][string][length_is][size_is][out] */ LPWSTR wzBuffer);
+
+ END_INTERFACE
+ } ICLRPrivResourcePathVtbl;
+
+ interface ICLRPrivResourcePath
+ {
+ CONST_VTBL struct ICLRPrivResourcePathVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICLRPrivResourcePath_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICLRPrivResourcePath_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICLRPrivResourcePath_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICLRPrivResourcePath_GetPath(This,cchBuffer,pcchBuffer,wzBuffer) \
+ ( (This)->lpVtbl -> GetPath(This,cchBuffer,pcchBuffer,wzBuffer) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICLRPrivResourcePath_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICLRPrivResourceStream_INTERFACE_DEFINED__
+#define __ICLRPrivResourceStream_INTERFACE_DEFINED__
+
+/* interface ICLRPrivResourceStream */
+/* [object][local][version][uuid] */
+
+
+EXTERN_C const IID IID_ICLRPrivResourceStream;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("2601F621-E462-404C-B299-3E1DE72F8545")
+ ICLRPrivResourceStream : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetStream(
+ /* [in] */ REFIID riid,
+ /* [retval][iid_is][out] */ LPVOID *ppvStream) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICLRPrivResourceStreamVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICLRPrivResourceStream * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICLRPrivResourceStream * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICLRPrivResourceStream * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetStream )(
+ ICLRPrivResourceStream * This,
+ /* [in] */ REFIID riid,
+ /* [retval][iid_is][out] */ LPVOID *ppvStream);
+
+ END_INTERFACE
+ } ICLRPrivResourceStreamVtbl;
+
+ interface ICLRPrivResourceStream
+ {
+ CONST_VTBL struct ICLRPrivResourceStreamVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICLRPrivResourceStream_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICLRPrivResourceStream_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICLRPrivResourceStream_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICLRPrivResourceStream_GetStream(This,riid,ppvStream) \
+ ( (This)->lpVtbl -> GetStream(This,riid,ppvStream) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICLRPrivResourceStream_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICLRPrivResourceHMODULE_INTERFACE_DEFINED__
+#define __ICLRPrivResourceHMODULE_INTERFACE_DEFINED__
+
+/* interface ICLRPrivResourceHMODULE */
+/* [object][local][version][uuid] */
+
+
+EXTERN_C const IID IID_ICLRPrivResourceHMODULE;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("2601F621-E462-404C-B299-3E1DE72F8546")
+ ICLRPrivResourceHMODULE : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetHMODULE(
+ /* [retval][out] */ HMODULE *phModule) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICLRPrivResourceHMODULEVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICLRPrivResourceHMODULE * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICLRPrivResourceHMODULE * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICLRPrivResourceHMODULE * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetHMODULE )(
+ ICLRPrivResourceHMODULE * This,
+ /* [retval][out] */ HMODULE *phModule);
+
+ END_INTERFACE
+ } ICLRPrivResourceHMODULEVtbl;
+
+ interface ICLRPrivResourceHMODULE
+ {
+ CONST_VTBL struct ICLRPrivResourceHMODULEVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICLRPrivResourceHMODULE_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICLRPrivResourceHMODULE_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICLRPrivResourceHMODULE_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICLRPrivResourceHMODULE_GetHMODULE(This,phModule) \
+ ( (This)->lpVtbl -> GetHMODULE(This,phModule) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICLRPrivResourceHMODULE_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICLRPrivResourceAssembly_INTERFACE_DEFINED__
+#define __ICLRPrivResourceAssembly_INTERFACE_DEFINED__
+
+/* interface ICLRPrivResourceAssembly */
+/* [object][local][version][uuid] */
+
+
+EXTERN_C const IID IID_ICLRPrivResourceAssembly;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("8d2d3cc9-1249-4ad4-977d-b772bd4e8a94")
+ ICLRPrivResourceAssembly : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetAssembly(
+ /* [retval][out] */ LPVOID *pAssembly) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICLRPrivResourceAssemblyVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICLRPrivResourceAssembly * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICLRPrivResourceAssembly * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICLRPrivResourceAssembly * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAssembly )(
+ ICLRPrivResourceAssembly * This,
+ /* [retval][out] */ LPVOID *pAssembly);
+
+ END_INTERFACE
+ } ICLRPrivResourceAssemblyVtbl;
+
+ interface ICLRPrivResourceAssembly
+ {
+ CONST_VTBL struct ICLRPrivResourceAssemblyVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICLRPrivResourceAssembly_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICLRPrivResourceAssembly_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICLRPrivResourceAssembly_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICLRPrivResourceAssembly_GetAssembly(This,pAssembly) \
+ ( (This)->lpVtbl -> GetAssembly(This,pAssembly) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICLRPrivResourceAssembly_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICLRPrivAssemblyInfo_INTERFACE_DEFINED__
+#define __ICLRPrivAssemblyInfo_INTERFACE_DEFINED__
+
+/* interface ICLRPrivAssemblyInfo */
+/* [object][local][version][uuid] */
+
+
+EXTERN_C const IID IID_ICLRPrivAssemblyInfo;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("5653946E-800B-48B7-8B09-B1B879B54F68")
+ ICLRPrivAssemblyInfo : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetAssemblyName(
+ /* [in] */ DWORD cchBuffer,
+ /* [out] */ LPDWORD pcchBuffer,
+ /* [optional][string][out] */ LPWSTR wzBuffer) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetAssemblyVersion(
+ /* [out] */ USHORT *pMajor,
+ /* [out] */ USHORT *pMinor,
+ /* [out] */ USHORT *pBuild,
+ /* [out] */ USHORT *pRevision) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetAssemblyPublicKey(
+ /* [in] */ DWORD cbBuffer,
+ /* [out] */ LPDWORD pcbBuffer,
+ /* [optional][length_is][size_is][out] */ BYTE *pbBuffer) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICLRPrivAssemblyInfoVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICLRPrivAssemblyInfo * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICLRPrivAssemblyInfo * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICLRPrivAssemblyInfo * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAssemblyName )(
+ ICLRPrivAssemblyInfo * This,
+ /* [in] */ DWORD cchBuffer,
+ /* [out] */ LPDWORD pcchBuffer,
+ /* [optional][string][out] */ LPWSTR wzBuffer);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAssemblyVersion )(
+ ICLRPrivAssemblyInfo * This,
+ /* [out] */ USHORT *pMajor,
+ /* [out] */ USHORT *pMinor,
+ /* [out] */ USHORT *pBuild,
+ /* [out] */ USHORT *pRevision);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAssemblyPublicKey )(
+ ICLRPrivAssemblyInfo * This,
+ /* [in] */ DWORD cbBuffer,
+ /* [out] */ LPDWORD pcbBuffer,
+ /* [optional][length_is][size_is][out] */ BYTE *pbBuffer);
+
+ END_INTERFACE
+ } ICLRPrivAssemblyInfoVtbl;
+
+ interface ICLRPrivAssemblyInfo
+ {
+ CONST_VTBL struct ICLRPrivAssemblyInfoVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICLRPrivAssemblyInfo_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICLRPrivAssemblyInfo_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICLRPrivAssemblyInfo_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICLRPrivAssemblyInfo_GetAssemblyName(This,cchBuffer,pcchBuffer,wzBuffer) \
+ ( (This)->lpVtbl -> GetAssemblyName(This,cchBuffer,pcchBuffer,wzBuffer) )
+
+#define ICLRPrivAssemblyInfo_GetAssemblyVersion(This,pMajor,pMinor,pBuild,pRevision) \
+ ( (This)->lpVtbl -> GetAssemblyVersion(This,pMajor,pMinor,pBuild,pRevision) )
+
+#define ICLRPrivAssemblyInfo_GetAssemblyPublicKey(This,cbBuffer,pcbBuffer,pbBuffer) \
+ ( (This)->lpVtbl -> GetAssemblyPublicKey(This,cbBuffer,pcbBuffer,pbBuffer) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICLRPrivAssemblyInfo_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICLRPrivAssemblyID_WinRT_INTERFACE_DEFINED__
+#define __ICLRPrivAssemblyID_WinRT_INTERFACE_DEFINED__
+
+/* interface ICLRPrivAssemblyID_WinRT */
+/* [object][local][version][uuid] */
+
+
+EXTERN_C const IID IID_ICLRPrivAssemblyID_WinRT;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("4372D277-9906-4FED-BF53-30C0B4010896")
+ ICLRPrivAssemblyID_WinRT : public IUnknown
+ {
+ public:
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICLRPrivAssemblyID_WinRTVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICLRPrivAssemblyID_WinRT * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICLRPrivAssemblyID_WinRT * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICLRPrivAssemblyID_WinRT * This);
+
+ END_INTERFACE
+ } ICLRPrivAssemblyID_WinRTVtbl;
+
+ interface ICLRPrivAssemblyID_WinRT
+ {
+ CONST_VTBL struct ICLRPrivAssemblyID_WinRTVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICLRPrivAssemblyID_WinRT_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICLRPrivAssemblyID_WinRT_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICLRPrivAssemblyID_WinRT_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICLRPrivAssemblyID_WinRT_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICLRPrivWinRtTypeBinder_INTERFACE_DEFINED__
+#define __ICLRPrivWinRtTypeBinder_INTERFACE_DEFINED__
+
+/* interface ICLRPrivWinRtTypeBinder */
+/* [object][local][version][uuid] */
+
+
+EXTERN_C const IID IID_ICLRPrivWinRtTypeBinder;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("6DE2A085-EFF4-4078-9F60-B9D366736398")
+ ICLRPrivWinRtTypeBinder : public IUnknown
+ {
+ public:
+ virtual void *STDMETHODCALLTYPE FindAssemblyForWinRtTypeIfLoaded(
+ void *pAppDomain,
+ LPCUTF8 szNamespace,
+ LPCUTF8 szClassName) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICLRPrivWinRtTypeBinderVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICLRPrivWinRtTypeBinder * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICLRPrivWinRtTypeBinder * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICLRPrivWinRtTypeBinder * This);
+
+ void *( STDMETHODCALLTYPE *FindAssemblyForWinRtTypeIfLoaded )(
+ ICLRPrivWinRtTypeBinder * This,
+ void *pAppDomain,
+ LPCUTF8 szNamespace,
+ LPCUTF8 szClassName);
+
+ END_INTERFACE
+ } ICLRPrivWinRtTypeBinderVtbl;
+
+ interface ICLRPrivWinRtTypeBinder
+ {
+ CONST_VTBL struct ICLRPrivWinRtTypeBinderVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICLRPrivWinRtTypeBinder_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICLRPrivWinRtTypeBinder_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICLRPrivWinRtTypeBinder_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICLRPrivWinRtTypeBinder_FindAssemblyForWinRtTypeIfLoaded(This,pAppDomain,szNamespace,szClassName) \
+ ( (This)->lpVtbl -> FindAssemblyForWinRtTypeIfLoaded(This,pAppDomain,szNamespace,szClassName) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICLRPrivWinRtTypeBinder_INTERFACE_DEFINED__ */
+
+
+/* Additional Prototypes for ALL interfaces */
+
+/* end of Additional Prototypes */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+
diff --git a/src/pal/prebuilt/inc/clrprivhosting.h b/src/pal/prebuilt/inc/clrprivhosting.h
new file mode 100644
index 0000000000..c0c3fd36b6
--- /dev/null
+++ b/src/pal/prebuilt/inc/clrprivhosting.h
@@ -0,0 +1,236 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+
+
+/* this ALWAYS GENERATED file contains the definitions for the interfaces */
+
+
+ /* File created by MIDL compiler version 8.00.0603 */
+/* @@MIDL_FILE_HEADING( ) */
+
+#pragma warning( disable: 4049 ) /* more than 64k source lines */
+
+
+/* verify that the <rpcndr.h> version is high enough to compile this file*/
+#ifndef __REQUIRED_RPCNDR_H_VERSION__
+#define __REQUIRED_RPCNDR_H_VERSION__ 475
+#endif
+
+#include "rpc.h"
+#include "rpcndr.h"
+
+#ifndef __RPCNDR_H_VERSION__
+#error this stub requires an updated version of <rpcndr.h>
+#endif // __RPCNDR_H_VERSION__
+
+#ifndef COM_NO_WINDOWS_H
+#include "windows.h"
+#include "ole2.h"
+#endif /*COM_NO_WINDOWS_H*/
+
+#ifndef __CLRPrivHosting_h__
+#define __CLRPrivHosting_h__
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+/* Forward Declarations */
+
+#ifndef __CLRPrivRuntime_FWD_DEFINED__
+#define __CLRPrivRuntime_FWD_DEFINED__
+
+#ifdef __cplusplus
+typedef class CLRPrivRuntime CLRPrivRuntime;
+#else
+typedef struct CLRPrivRuntime CLRPrivRuntime;
+#endif /* __cplusplus */
+
+#endif /* __CLRPrivRuntime_FWD_DEFINED__ */
+
+
+#ifndef __ICLRPrivRuntime_FWD_DEFINED__
+#define __ICLRPrivRuntime_FWD_DEFINED__
+typedef interface ICLRPrivRuntime ICLRPrivRuntime;
+
+#endif /* __ICLRPrivRuntime_FWD_DEFINED__ */
+
+
+/* header files for imported files */
+#include "unknwn.h"
+#include "clrprivbinding.h"
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+
+/* interface __MIDL_itf_CLRPrivHosting_0000_0000 */
+/* [local] */
+
+
+
+
+extern RPC_IF_HANDLE __MIDL_itf_CLRPrivHosting_0000_0000_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_CLRPrivHosting_0000_0000_v0_0_s_ifspec;
+
+
+#ifndef __CLRPrivHosting_LIBRARY_DEFINED__
+#define __CLRPrivHosting_LIBRARY_DEFINED__
+
+/* library CLRPrivHosting */
+/* [uuid] */
+
+
+EXTERN_C const IID LIBID_CLRPrivHosting;
+
+EXTERN_C const CLSID CLSID_CLRPrivRuntime;
+
+#ifdef __cplusplus
+
+class DECLSPEC_UUID("BC1B53A8-DCBC-43B2-BB17-1E4061447AE8")
+CLRPrivRuntime;
+#endif
+#endif /* __CLRPrivHosting_LIBRARY_DEFINED__ */
+
+#ifndef __ICLRPrivRuntime_INTERFACE_DEFINED__
+#define __ICLRPrivRuntime_INTERFACE_DEFINED__
+
+/* interface ICLRPrivRuntime */
+/* [object][local][version][uuid] */
+
+
+EXTERN_C const IID IID_ICLRPrivRuntime;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("BC1B53A8-DCBC-43B2-BB17-1E4061447AE9")
+ ICLRPrivRuntime : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetInterface(
+ /* [in] */ REFCLSID rclsid,
+ /* [in] */ REFIID riid,
+ /* [retval][iid_is][out] */ LPVOID *ppUnk) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE CreateAppDomain(
+ /* [string][in] */ LPCWSTR pwzFriendlyName,
+ /* [in] */ ICLRPrivBinder *pBinder,
+ /* [retval][out] */ LPDWORD pdwAppDomainId) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE CreateDelegate(
+ /* [in] */ DWORD appDomainID,
+ /* [string][in] */ LPCWSTR wszAssemblyName,
+ /* [string][in] */ LPCWSTR wszClassName,
+ /* [string][in] */ LPCWSTR wszMethodName,
+ /* [retval][out] */ LPVOID *ppvDelegate) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ExecuteMain(
+ /* [in] */ ICLRPrivBinder *pBinder,
+ /* [retval][out] */ int *pRetVal) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICLRPrivRuntimeVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICLRPrivRuntime * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICLRPrivRuntime * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICLRPrivRuntime * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetInterface )(
+ ICLRPrivRuntime * This,
+ /* [in] */ REFCLSID rclsid,
+ /* [in] */ REFIID riid,
+ /* [retval][iid_is][out] */ LPVOID *ppUnk);
+
+ HRESULT ( STDMETHODCALLTYPE *CreateAppDomain )(
+ ICLRPrivRuntime * This,
+ /* [string][in] */ LPCWSTR pwzFriendlyName,
+ /* [in] */ ICLRPrivBinder *pBinder,
+ /* [retval][out] */ LPDWORD pdwAppDomainId);
+
+ HRESULT ( STDMETHODCALLTYPE *CreateDelegate )(
+ ICLRPrivRuntime * This,
+ /* [in] */ DWORD appDomainID,
+ /* [string][in] */ LPCWSTR wszAssemblyName,
+ /* [string][in] */ LPCWSTR wszClassName,
+ /* [string][in] */ LPCWSTR wszMethodName,
+ /* [retval][out] */ LPVOID *ppvDelegate);
+
+ HRESULT ( STDMETHODCALLTYPE *ExecuteMain )(
+ ICLRPrivRuntime * This,
+ /* [in] */ ICLRPrivBinder *pBinder,
+ /* [retval][out] */ int *pRetVal);
+
+ END_INTERFACE
+ } ICLRPrivRuntimeVtbl;
+
+ interface ICLRPrivRuntime
+ {
+ CONST_VTBL struct ICLRPrivRuntimeVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICLRPrivRuntime_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICLRPrivRuntime_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICLRPrivRuntime_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICLRPrivRuntime_GetInterface(This,rclsid,riid,ppUnk) \
+ ( (This)->lpVtbl -> GetInterface(This,rclsid,riid,ppUnk) )
+
+#define ICLRPrivRuntime_CreateAppDomain(This,pwzFriendlyName,pBinder,pdwAppDomainId) \
+ ( (This)->lpVtbl -> CreateAppDomain(This,pwzFriendlyName,pBinder,pdwAppDomainId) )
+
+#define ICLRPrivRuntime_CreateDelegate(This,appDomainID,wszAssemblyName,wszClassName,wszMethodName,ppvDelegate) \
+ ( (This)->lpVtbl -> CreateDelegate(This,appDomainID,wszAssemblyName,wszClassName,wszMethodName,ppvDelegate) )
+
+#define ICLRPrivRuntime_ExecuteMain(This,pBinder,pRetVal) \
+ ( (This)->lpVtbl -> ExecuteMain(This,pBinder,pRetVal) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICLRPrivRuntime_INTERFACE_DEFINED__ */
+
+
+/* Additional Prototypes for ALL interfaces */
+
+/* end of Additional Prototypes */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+
diff --git a/src/pal/prebuilt/inc/clrprivruntimebinders.h b/src/pal/prebuilt/inc/clrprivruntimebinders.h
new file mode 100644
index 0000000000..dc4324a5c6
--- /dev/null
+++ b/src/pal/prebuilt/inc/clrprivruntimebinders.h
@@ -0,0 +1,107 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+
+
+/* this ALWAYS GENERATED file contains the definitions for the interfaces */
+
+
+ /* File created by MIDL compiler version 8.00.0603 */
+/* @@MIDL_FILE_HEADING( ) */
+
+#pragma warning( disable: 4049 ) /* more than 64k source lines */
+
+
+/* verify that the <rpcndr.h> version is high enough to compile this file*/
+#ifndef __REQUIRED_RPCNDR_H_VERSION__
+#define __REQUIRED_RPCNDR_H_VERSION__ 475
+#endif
+
+#include "rpc.h"
+#include "rpcndr.h"
+
+#ifndef __RPCNDR_H_VERSION__
+#error this stub requires an updated version of <rpcndr.h>
+#endif // __RPCNDR_H_VERSION__
+
+
+#ifndef __CLRPrivRuntimeBinders_h__
+#define __CLRPrivRuntimeBinders_h__
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+/* Forward Declarations */
+
+#ifndef __CLRPrivAppXBinder_FWD_DEFINED__
+#define __CLRPrivAppXBinder_FWD_DEFINED__
+
+#ifdef __cplusplus
+typedef class CLRPrivAppXBinder CLRPrivAppXBinder;
+#else
+typedef struct CLRPrivAppXBinder CLRPrivAppXBinder;
+#endif /* __cplusplus */
+
+#endif /* __CLRPrivAppXBinder_FWD_DEFINED__ */
+
+
+#ifndef __CLRPrivFusionBinder_FWD_DEFINED__
+#define __CLRPrivFusionBinder_FWD_DEFINED__
+
+#ifdef __cplusplus
+typedef class CLRPrivFusionBinder CLRPrivFusionBinder;
+#else
+typedef struct CLRPrivFusionBinder CLRPrivFusionBinder;
+#endif /* __cplusplus */
+
+#endif /* __CLRPrivFusionBinder_FWD_DEFINED__ */
+
+
+/* header files for imported files */
+#include "clrprivbinding.h"
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+
+
+#ifndef __CLRPrivRuntimeBinders_LIBRARY_DEFINED__
+#define __CLRPrivRuntimeBinders_LIBRARY_DEFINED__
+
+/* library CLRPrivRuntimeBinders */
+/* [uuid] */
+
+
+EXTERN_C const IID LIBID_CLRPrivRuntimeBinders;
+
+EXTERN_C const CLSID CLSID_CLRPrivAppXBinder;
+
+#ifdef __cplusplus
+
+class DECLSPEC_UUID("E990F732-2D0A-48AC-87FC-EF12B618981A")
+CLRPrivAppXBinder;
+#endif
+
+EXTERN_C const CLSID CLSID_CLRPrivFusionBinder;
+
+#ifdef __cplusplus
+
+class DECLSPEC_UUID("E990F732-2D0A-48AC-87FC-EF12B618981C")
+CLRPrivFusionBinder;
+#endif
+#endif /* __CLRPrivRuntimeBinders_LIBRARY_DEFINED__ */
+
+/* Additional Prototypes for ALL interfaces */
+
+/* end of Additional Prototypes */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+
diff --git a/src/pal/prebuilt/inc/cordebug.h b/src/pal/prebuilt/inc/cordebug.h
new file mode 100644
index 0000000000..a5a5cf2e8a
--- /dev/null
+++ b/src/pal/prebuilt/inc/cordebug.h
@@ -0,0 +1,17660 @@
+
+
+/* this ALWAYS GENERATED file contains the definitions for the interfaces */
+
+
+ /* File created by MIDL compiler version 8.00.0603 */
+/* at Fri Jul 15 18:01:08 2016
+ */
+/* Compiler settings for E:/git/coreclr/src/inc/cordebug.idl:
+ Oicf, W1, Zp8, env=Win32 (32b run), target_arch=X86 8.00.0603
+ protocol : dce , ms_ext, c_ext, robust
+ error checks: allocation ref bounds_check enum stub_data
+ VC __declspec() decoration level:
+ __declspec(uuid()), __declspec(selectany), __declspec(novtable)
+ DECLSPEC_UUID(), MIDL_INTERFACE()
+*/
+/* @@MIDL_FILE_HEADING( ) */
+
+#pragma warning( disable: 4049 ) /* more than 64k source lines */
+
+
+/* verify that the <rpcndr.h> version is high enough to compile this file*/
+#ifndef __REQUIRED_RPCNDR_H_VERSION__
+#define __REQUIRED_RPCNDR_H_VERSION__ 475
+#endif
+
+#include "rpc.h"
+#include "rpcndr.h"
+
+#ifndef __RPCNDR_H_VERSION__
+#error this stub requires an updated version of <rpcndr.h>
+#endif // __RPCNDR_H_VERSION__
+
+#ifndef COM_NO_WINDOWS_H
+#include "windows.h"
+#include "ole2.h"
+#endif /*COM_NO_WINDOWS_H*/
+
+#ifndef __cordebug_h__
+#define __cordebug_h__
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+/* Forward Declarations */
+
+#ifndef __ICorDebugDataTarget_FWD_DEFINED__
+#define __ICorDebugDataTarget_FWD_DEFINED__
+typedef interface ICorDebugDataTarget ICorDebugDataTarget;
+
+#endif /* __ICorDebugDataTarget_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugStaticFieldSymbol_FWD_DEFINED__
+#define __ICorDebugStaticFieldSymbol_FWD_DEFINED__
+typedef interface ICorDebugStaticFieldSymbol ICorDebugStaticFieldSymbol;
+
+#endif /* __ICorDebugStaticFieldSymbol_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugInstanceFieldSymbol_FWD_DEFINED__
+#define __ICorDebugInstanceFieldSymbol_FWD_DEFINED__
+typedef interface ICorDebugInstanceFieldSymbol ICorDebugInstanceFieldSymbol;
+
+#endif /* __ICorDebugInstanceFieldSymbol_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugVariableSymbol_FWD_DEFINED__
+#define __ICorDebugVariableSymbol_FWD_DEFINED__
+typedef interface ICorDebugVariableSymbol ICorDebugVariableSymbol;
+
+#endif /* __ICorDebugVariableSymbol_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugMemoryBuffer_FWD_DEFINED__
+#define __ICorDebugMemoryBuffer_FWD_DEFINED__
+typedef interface ICorDebugMemoryBuffer ICorDebugMemoryBuffer;
+
+#endif /* __ICorDebugMemoryBuffer_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugMergedAssemblyRecord_FWD_DEFINED__
+#define __ICorDebugMergedAssemblyRecord_FWD_DEFINED__
+typedef interface ICorDebugMergedAssemblyRecord ICorDebugMergedAssemblyRecord;
+
+#endif /* __ICorDebugMergedAssemblyRecord_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugSymbolProvider_FWD_DEFINED__
+#define __ICorDebugSymbolProvider_FWD_DEFINED__
+typedef interface ICorDebugSymbolProvider ICorDebugSymbolProvider;
+
+#endif /* __ICorDebugSymbolProvider_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugSymbolProvider2_FWD_DEFINED__
+#define __ICorDebugSymbolProvider2_FWD_DEFINED__
+typedef interface ICorDebugSymbolProvider2 ICorDebugSymbolProvider2;
+
+#endif /* __ICorDebugSymbolProvider2_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugVirtualUnwinder_FWD_DEFINED__
+#define __ICorDebugVirtualUnwinder_FWD_DEFINED__
+typedef interface ICorDebugVirtualUnwinder ICorDebugVirtualUnwinder;
+
+#endif /* __ICorDebugVirtualUnwinder_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugDataTarget2_FWD_DEFINED__
+#define __ICorDebugDataTarget2_FWD_DEFINED__
+typedef interface ICorDebugDataTarget2 ICorDebugDataTarget2;
+
+#endif /* __ICorDebugDataTarget2_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugLoadedModule_FWD_DEFINED__
+#define __ICorDebugLoadedModule_FWD_DEFINED__
+typedef interface ICorDebugLoadedModule ICorDebugLoadedModule;
+
+#endif /* __ICorDebugLoadedModule_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugDataTarget3_FWD_DEFINED__
+#define __ICorDebugDataTarget3_FWD_DEFINED__
+typedef interface ICorDebugDataTarget3 ICorDebugDataTarget3;
+
+#endif /* __ICorDebugDataTarget3_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugDataTarget4_FWD_DEFINED__
+#define __ICorDebugDataTarget4_FWD_DEFINED__
+typedef interface ICorDebugDataTarget4 ICorDebugDataTarget4;
+
+#endif /* __ICorDebugDataTarget4_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugMutableDataTarget_FWD_DEFINED__
+#define __ICorDebugMutableDataTarget_FWD_DEFINED__
+typedef interface ICorDebugMutableDataTarget ICorDebugMutableDataTarget;
+
+#endif /* __ICorDebugMutableDataTarget_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugMetaDataLocator_FWD_DEFINED__
+#define __ICorDebugMetaDataLocator_FWD_DEFINED__
+typedef interface ICorDebugMetaDataLocator ICorDebugMetaDataLocator;
+
+#endif /* __ICorDebugMetaDataLocator_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugManagedCallback_FWD_DEFINED__
+#define __ICorDebugManagedCallback_FWD_DEFINED__
+typedef interface ICorDebugManagedCallback ICorDebugManagedCallback;
+
+#endif /* __ICorDebugManagedCallback_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugManagedCallback3_FWD_DEFINED__
+#define __ICorDebugManagedCallback3_FWD_DEFINED__
+typedef interface ICorDebugManagedCallback3 ICorDebugManagedCallback3;
+
+#endif /* __ICorDebugManagedCallback3_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugManagedCallback2_FWD_DEFINED__
+#define __ICorDebugManagedCallback2_FWD_DEFINED__
+typedef interface ICorDebugManagedCallback2 ICorDebugManagedCallback2;
+
+#endif /* __ICorDebugManagedCallback2_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugUnmanagedCallback_FWD_DEFINED__
+#define __ICorDebugUnmanagedCallback_FWD_DEFINED__
+typedef interface ICorDebugUnmanagedCallback ICorDebugUnmanagedCallback;
+
+#endif /* __ICorDebugUnmanagedCallback_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebug_FWD_DEFINED__
+#define __ICorDebug_FWD_DEFINED__
+typedef interface ICorDebug ICorDebug;
+
+#endif /* __ICorDebug_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugRemoteTarget_FWD_DEFINED__
+#define __ICorDebugRemoteTarget_FWD_DEFINED__
+typedef interface ICorDebugRemoteTarget ICorDebugRemoteTarget;
+
+#endif /* __ICorDebugRemoteTarget_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugRemote_FWD_DEFINED__
+#define __ICorDebugRemote_FWD_DEFINED__
+typedef interface ICorDebugRemote ICorDebugRemote;
+
+#endif /* __ICorDebugRemote_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebug2_FWD_DEFINED__
+#define __ICorDebug2_FWD_DEFINED__
+typedef interface ICorDebug2 ICorDebug2;
+
+#endif /* __ICorDebug2_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugController_FWD_DEFINED__
+#define __ICorDebugController_FWD_DEFINED__
+typedef interface ICorDebugController ICorDebugController;
+
+#endif /* __ICorDebugController_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugAppDomain_FWD_DEFINED__
+#define __ICorDebugAppDomain_FWD_DEFINED__
+typedef interface ICorDebugAppDomain ICorDebugAppDomain;
+
+#endif /* __ICorDebugAppDomain_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugAppDomain2_FWD_DEFINED__
+#define __ICorDebugAppDomain2_FWD_DEFINED__
+typedef interface ICorDebugAppDomain2 ICorDebugAppDomain2;
+
+#endif /* __ICorDebugAppDomain2_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugEnum_FWD_DEFINED__
+#define __ICorDebugEnum_FWD_DEFINED__
+typedef interface ICorDebugEnum ICorDebugEnum;
+
+#endif /* __ICorDebugEnum_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugGuidToTypeEnum_FWD_DEFINED__
+#define __ICorDebugGuidToTypeEnum_FWD_DEFINED__
+typedef interface ICorDebugGuidToTypeEnum ICorDebugGuidToTypeEnum;
+
+#endif /* __ICorDebugGuidToTypeEnum_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugAppDomain3_FWD_DEFINED__
+#define __ICorDebugAppDomain3_FWD_DEFINED__
+typedef interface ICorDebugAppDomain3 ICorDebugAppDomain3;
+
+#endif /* __ICorDebugAppDomain3_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugAppDomain4_FWD_DEFINED__
+#define __ICorDebugAppDomain4_FWD_DEFINED__
+typedef interface ICorDebugAppDomain4 ICorDebugAppDomain4;
+
+#endif /* __ICorDebugAppDomain4_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugAssembly_FWD_DEFINED__
+#define __ICorDebugAssembly_FWD_DEFINED__
+typedef interface ICorDebugAssembly ICorDebugAssembly;
+
+#endif /* __ICorDebugAssembly_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugAssembly2_FWD_DEFINED__
+#define __ICorDebugAssembly2_FWD_DEFINED__
+typedef interface ICorDebugAssembly2 ICorDebugAssembly2;
+
+#endif /* __ICorDebugAssembly2_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugAssembly3_FWD_DEFINED__
+#define __ICorDebugAssembly3_FWD_DEFINED__
+typedef interface ICorDebugAssembly3 ICorDebugAssembly3;
+
+#endif /* __ICorDebugAssembly3_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugHeapEnum_FWD_DEFINED__
+#define __ICorDebugHeapEnum_FWD_DEFINED__
+typedef interface ICorDebugHeapEnum ICorDebugHeapEnum;
+
+#endif /* __ICorDebugHeapEnum_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugHeapSegmentEnum_FWD_DEFINED__
+#define __ICorDebugHeapSegmentEnum_FWD_DEFINED__
+typedef interface ICorDebugHeapSegmentEnum ICorDebugHeapSegmentEnum;
+
+#endif /* __ICorDebugHeapSegmentEnum_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugGCReferenceEnum_FWD_DEFINED__
+#define __ICorDebugGCReferenceEnum_FWD_DEFINED__
+typedef interface ICorDebugGCReferenceEnum ICorDebugGCReferenceEnum;
+
+#endif /* __ICorDebugGCReferenceEnum_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugProcess_FWD_DEFINED__
+#define __ICorDebugProcess_FWD_DEFINED__
+typedef interface ICorDebugProcess ICorDebugProcess;
+
+#endif /* __ICorDebugProcess_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugProcess2_FWD_DEFINED__
+#define __ICorDebugProcess2_FWD_DEFINED__
+typedef interface ICorDebugProcess2 ICorDebugProcess2;
+
+#endif /* __ICorDebugProcess2_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugProcess3_FWD_DEFINED__
+#define __ICorDebugProcess3_FWD_DEFINED__
+typedef interface ICorDebugProcess3 ICorDebugProcess3;
+
+#endif /* __ICorDebugProcess3_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugProcess5_FWD_DEFINED__
+#define __ICorDebugProcess5_FWD_DEFINED__
+typedef interface ICorDebugProcess5 ICorDebugProcess5;
+
+#endif /* __ICorDebugProcess5_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugDebugEvent_FWD_DEFINED__
+#define __ICorDebugDebugEvent_FWD_DEFINED__
+typedef interface ICorDebugDebugEvent ICorDebugDebugEvent;
+
+#endif /* __ICorDebugDebugEvent_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugProcess6_FWD_DEFINED__
+#define __ICorDebugProcess6_FWD_DEFINED__
+typedef interface ICorDebugProcess6 ICorDebugProcess6;
+
+#endif /* __ICorDebugProcess6_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugProcess7_FWD_DEFINED__
+#define __ICorDebugProcess7_FWD_DEFINED__
+typedef interface ICorDebugProcess7 ICorDebugProcess7;
+
+#endif /* __ICorDebugProcess7_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugProcess8_FWD_DEFINED__
+#define __ICorDebugProcess8_FWD_DEFINED__
+typedef interface ICorDebugProcess8 ICorDebugProcess8;
+
+#endif /* __ICorDebugProcess8_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugModuleDebugEvent_FWD_DEFINED__
+#define __ICorDebugModuleDebugEvent_FWD_DEFINED__
+typedef interface ICorDebugModuleDebugEvent ICorDebugModuleDebugEvent;
+
+#endif /* __ICorDebugModuleDebugEvent_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugExceptionDebugEvent_FWD_DEFINED__
+#define __ICorDebugExceptionDebugEvent_FWD_DEFINED__
+typedef interface ICorDebugExceptionDebugEvent ICorDebugExceptionDebugEvent;
+
+#endif /* __ICorDebugExceptionDebugEvent_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugBreakpoint_FWD_DEFINED__
+#define __ICorDebugBreakpoint_FWD_DEFINED__
+typedef interface ICorDebugBreakpoint ICorDebugBreakpoint;
+
+#endif /* __ICorDebugBreakpoint_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugFunctionBreakpoint_FWD_DEFINED__
+#define __ICorDebugFunctionBreakpoint_FWD_DEFINED__
+typedef interface ICorDebugFunctionBreakpoint ICorDebugFunctionBreakpoint;
+
+#endif /* __ICorDebugFunctionBreakpoint_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugModuleBreakpoint_FWD_DEFINED__
+#define __ICorDebugModuleBreakpoint_FWD_DEFINED__
+typedef interface ICorDebugModuleBreakpoint ICorDebugModuleBreakpoint;
+
+#endif /* __ICorDebugModuleBreakpoint_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugValueBreakpoint_FWD_DEFINED__
+#define __ICorDebugValueBreakpoint_FWD_DEFINED__
+typedef interface ICorDebugValueBreakpoint ICorDebugValueBreakpoint;
+
+#endif /* __ICorDebugValueBreakpoint_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugStepper_FWD_DEFINED__
+#define __ICorDebugStepper_FWD_DEFINED__
+typedef interface ICorDebugStepper ICorDebugStepper;
+
+#endif /* __ICorDebugStepper_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugStepper2_FWD_DEFINED__
+#define __ICorDebugStepper2_FWD_DEFINED__
+typedef interface ICorDebugStepper2 ICorDebugStepper2;
+
+#endif /* __ICorDebugStepper2_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugRegisterSet_FWD_DEFINED__
+#define __ICorDebugRegisterSet_FWD_DEFINED__
+typedef interface ICorDebugRegisterSet ICorDebugRegisterSet;
+
+#endif /* __ICorDebugRegisterSet_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugRegisterSet2_FWD_DEFINED__
+#define __ICorDebugRegisterSet2_FWD_DEFINED__
+typedef interface ICorDebugRegisterSet2 ICorDebugRegisterSet2;
+
+#endif /* __ICorDebugRegisterSet2_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugThread_FWD_DEFINED__
+#define __ICorDebugThread_FWD_DEFINED__
+typedef interface ICorDebugThread ICorDebugThread;
+
+#endif /* __ICorDebugThread_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugThread2_FWD_DEFINED__
+#define __ICorDebugThread2_FWD_DEFINED__
+typedef interface ICorDebugThread2 ICorDebugThread2;
+
+#endif /* __ICorDebugThread2_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugThread3_FWD_DEFINED__
+#define __ICorDebugThread3_FWD_DEFINED__
+typedef interface ICorDebugThread3 ICorDebugThread3;
+
+#endif /* __ICorDebugThread3_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugThread4_FWD_DEFINED__
+#define __ICorDebugThread4_FWD_DEFINED__
+typedef interface ICorDebugThread4 ICorDebugThread4;
+
+#endif /* __ICorDebugThread4_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugStackWalk_FWD_DEFINED__
+#define __ICorDebugStackWalk_FWD_DEFINED__
+typedef interface ICorDebugStackWalk ICorDebugStackWalk;
+
+#endif /* __ICorDebugStackWalk_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugChain_FWD_DEFINED__
+#define __ICorDebugChain_FWD_DEFINED__
+typedef interface ICorDebugChain ICorDebugChain;
+
+#endif /* __ICorDebugChain_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugFrame_FWD_DEFINED__
+#define __ICorDebugFrame_FWD_DEFINED__
+typedef interface ICorDebugFrame ICorDebugFrame;
+
+#endif /* __ICorDebugFrame_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugInternalFrame_FWD_DEFINED__
+#define __ICorDebugInternalFrame_FWD_DEFINED__
+typedef interface ICorDebugInternalFrame ICorDebugInternalFrame;
+
+#endif /* __ICorDebugInternalFrame_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugInternalFrame2_FWD_DEFINED__
+#define __ICorDebugInternalFrame2_FWD_DEFINED__
+typedef interface ICorDebugInternalFrame2 ICorDebugInternalFrame2;
+
+#endif /* __ICorDebugInternalFrame2_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugILFrame_FWD_DEFINED__
+#define __ICorDebugILFrame_FWD_DEFINED__
+typedef interface ICorDebugILFrame ICorDebugILFrame;
+
+#endif /* __ICorDebugILFrame_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugILFrame2_FWD_DEFINED__
+#define __ICorDebugILFrame2_FWD_DEFINED__
+typedef interface ICorDebugILFrame2 ICorDebugILFrame2;
+
+#endif /* __ICorDebugILFrame2_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugILFrame3_FWD_DEFINED__
+#define __ICorDebugILFrame3_FWD_DEFINED__
+typedef interface ICorDebugILFrame3 ICorDebugILFrame3;
+
+#endif /* __ICorDebugILFrame3_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugILFrame4_FWD_DEFINED__
+#define __ICorDebugILFrame4_FWD_DEFINED__
+typedef interface ICorDebugILFrame4 ICorDebugILFrame4;
+
+#endif /* __ICorDebugILFrame4_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugNativeFrame_FWD_DEFINED__
+#define __ICorDebugNativeFrame_FWD_DEFINED__
+typedef interface ICorDebugNativeFrame ICorDebugNativeFrame;
+
+#endif /* __ICorDebugNativeFrame_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugNativeFrame2_FWD_DEFINED__
+#define __ICorDebugNativeFrame2_FWD_DEFINED__
+typedef interface ICorDebugNativeFrame2 ICorDebugNativeFrame2;
+
+#endif /* __ICorDebugNativeFrame2_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugModule3_FWD_DEFINED__
+#define __ICorDebugModule3_FWD_DEFINED__
+typedef interface ICorDebugModule3 ICorDebugModule3;
+
+#endif /* __ICorDebugModule3_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugRuntimeUnwindableFrame_FWD_DEFINED__
+#define __ICorDebugRuntimeUnwindableFrame_FWD_DEFINED__
+typedef interface ICorDebugRuntimeUnwindableFrame ICorDebugRuntimeUnwindableFrame;
+
+#endif /* __ICorDebugRuntimeUnwindableFrame_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugModule_FWD_DEFINED__
+#define __ICorDebugModule_FWD_DEFINED__
+typedef interface ICorDebugModule ICorDebugModule;
+
+#endif /* __ICorDebugModule_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugModule2_FWD_DEFINED__
+#define __ICorDebugModule2_FWD_DEFINED__
+typedef interface ICorDebugModule2 ICorDebugModule2;
+
+#endif /* __ICorDebugModule2_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugFunction_FWD_DEFINED__
+#define __ICorDebugFunction_FWD_DEFINED__
+typedef interface ICorDebugFunction ICorDebugFunction;
+
+#endif /* __ICorDebugFunction_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugFunction2_FWD_DEFINED__
+#define __ICorDebugFunction2_FWD_DEFINED__
+typedef interface ICorDebugFunction2 ICorDebugFunction2;
+
+#endif /* __ICorDebugFunction2_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugFunction3_FWD_DEFINED__
+#define __ICorDebugFunction3_FWD_DEFINED__
+typedef interface ICorDebugFunction3 ICorDebugFunction3;
+
+#endif /* __ICorDebugFunction3_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugCode_FWD_DEFINED__
+#define __ICorDebugCode_FWD_DEFINED__
+typedef interface ICorDebugCode ICorDebugCode;
+
+#endif /* __ICorDebugCode_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugCode2_FWD_DEFINED__
+#define __ICorDebugCode2_FWD_DEFINED__
+typedef interface ICorDebugCode2 ICorDebugCode2;
+
+#endif /* __ICorDebugCode2_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugCode3_FWD_DEFINED__
+#define __ICorDebugCode3_FWD_DEFINED__
+typedef interface ICorDebugCode3 ICorDebugCode3;
+
+#endif /* __ICorDebugCode3_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugILCode_FWD_DEFINED__
+#define __ICorDebugILCode_FWD_DEFINED__
+typedef interface ICorDebugILCode ICorDebugILCode;
+
+#endif /* __ICorDebugILCode_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugILCode2_FWD_DEFINED__
+#define __ICorDebugILCode2_FWD_DEFINED__
+typedef interface ICorDebugILCode2 ICorDebugILCode2;
+
+#endif /* __ICorDebugILCode2_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugClass_FWD_DEFINED__
+#define __ICorDebugClass_FWD_DEFINED__
+typedef interface ICorDebugClass ICorDebugClass;
+
+#endif /* __ICorDebugClass_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugClass2_FWD_DEFINED__
+#define __ICorDebugClass2_FWD_DEFINED__
+typedef interface ICorDebugClass2 ICorDebugClass2;
+
+#endif /* __ICorDebugClass2_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugEval_FWD_DEFINED__
+#define __ICorDebugEval_FWD_DEFINED__
+typedef interface ICorDebugEval ICorDebugEval;
+
+#endif /* __ICorDebugEval_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugEval2_FWD_DEFINED__
+#define __ICorDebugEval2_FWD_DEFINED__
+typedef interface ICorDebugEval2 ICorDebugEval2;
+
+#endif /* __ICorDebugEval2_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugValue_FWD_DEFINED__
+#define __ICorDebugValue_FWD_DEFINED__
+typedef interface ICorDebugValue ICorDebugValue;
+
+#endif /* __ICorDebugValue_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugValue2_FWD_DEFINED__
+#define __ICorDebugValue2_FWD_DEFINED__
+typedef interface ICorDebugValue2 ICorDebugValue2;
+
+#endif /* __ICorDebugValue2_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugValue3_FWD_DEFINED__
+#define __ICorDebugValue3_FWD_DEFINED__
+typedef interface ICorDebugValue3 ICorDebugValue3;
+
+#endif /* __ICorDebugValue3_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugGenericValue_FWD_DEFINED__
+#define __ICorDebugGenericValue_FWD_DEFINED__
+typedef interface ICorDebugGenericValue ICorDebugGenericValue;
+
+#endif /* __ICorDebugGenericValue_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugReferenceValue_FWD_DEFINED__
+#define __ICorDebugReferenceValue_FWD_DEFINED__
+typedef interface ICorDebugReferenceValue ICorDebugReferenceValue;
+
+#endif /* __ICorDebugReferenceValue_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugHeapValue_FWD_DEFINED__
+#define __ICorDebugHeapValue_FWD_DEFINED__
+typedef interface ICorDebugHeapValue ICorDebugHeapValue;
+
+#endif /* __ICorDebugHeapValue_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugHeapValue2_FWD_DEFINED__
+#define __ICorDebugHeapValue2_FWD_DEFINED__
+typedef interface ICorDebugHeapValue2 ICorDebugHeapValue2;
+
+#endif /* __ICorDebugHeapValue2_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugHeapValue3_FWD_DEFINED__
+#define __ICorDebugHeapValue3_FWD_DEFINED__
+typedef interface ICorDebugHeapValue3 ICorDebugHeapValue3;
+
+#endif /* __ICorDebugHeapValue3_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugObjectValue_FWD_DEFINED__
+#define __ICorDebugObjectValue_FWD_DEFINED__
+typedef interface ICorDebugObjectValue ICorDebugObjectValue;
+
+#endif /* __ICorDebugObjectValue_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugObjectValue2_FWD_DEFINED__
+#define __ICorDebugObjectValue2_FWD_DEFINED__
+typedef interface ICorDebugObjectValue2 ICorDebugObjectValue2;
+
+#endif /* __ICorDebugObjectValue2_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugBoxValue_FWD_DEFINED__
+#define __ICorDebugBoxValue_FWD_DEFINED__
+typedef interface ICorDebugBoxValue ICorDebugBoxValue;
+
+#endif /* __ICorDebugBoxValue_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugStringValue_FWD_DEFINED__
+#define __ICorDebugStringValue_FWD_DEFINED__
+typedef interface ICorDebugStringValue ICorDebugStringValue;
+
+#endif /* __ICorDebugStringValue_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugArrayValue_FWD_DEFINED__
+#define __ICorDebugArrayValue_FWD_DEFINED__
+typedef interface ICorDebugArrayValue ICorDebugArrayValue;
+
+#endif /* __ICorDebugArrayValue_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugHandleValue_FWD_DEFINED__
+#define __ICorDebugHandleValue_FWD_DEFINED__
+typedef interface ICorDebugHandleValue ICorDebugHandleValue;
+
+#endif /* __ICorDebugHandleValue_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugContext_FWD_DEFINED__
+#define __ICorDebugContext_FWD_DEFINED__
+typedef interface ICorDebugContext ICorDebugContext;
+
+#endif /* __ICorDebugContext_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugComObjectValue_FWD_DEFINED__
+#define __ICorDebugComObjectValue_FWD_DEFINED__
+typedef interface ICorDebugComObjectValue ICorDebugComObjectValue;
+
+#endif /* __ICorDebugComObjectValue_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugObjectEnum_FWD_DEFINED__
+#define __ICorDebugObjectEnum_FWD_DEFINED__
+typedef interface ICorDebugObjectEnum ICorDebugObjectEnum;
+
+#endif /* __ICorDebugObjectEnum_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugBreakpointEnum_FWD_DEFINED__
+#define __ICorDebugBreakpointEnum_FWD_DEFINED__
+typedef interface ICorDebugBreakpointEnum ICorDebugBreakpointEnum;
+
+#endif /* __ICorDebugBreakpointEnum_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugStepperEnum_FWD_DEFINED__
+#define __ICorDebugStepperEnum_FWD_DEFINED__
+typedef interface ICorDebugStepperEnum ICorDebugStepperEnum;
+
+#endif /* __ICorDebugStepperEnum_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugProcessEnum_FWD_DEFINED__
+#define __ICorDebugProcessEnum_FWD_DEFINED__
+typedef interface ICorDebugProcessEnum ICorDebugProcessEnum;
+
+#endif /* __ICorDebugProcessEnum_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugThreadEnum_FWD_DEFINED__
+#define __ICorDebugThreadEnum_FWD_DEFINED__
+typedef interface ICorDebugThreadEnum ICorDebugThreadEnum;
+
+#endif /* __ICorDebugThreadEnum_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugFrameEnum_FWD_DEFINED__
+#define __ICorDebugFrameEnum_FWD_DEFINED__
+typedef interface ICorDebugFrameEnum ICorDebugFrameEnum;
+
+#endif /* __ICorDebugFrameEnum_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugChainEnum_FWD_DEFINED__
+#define __ICorDebugChainEnum_FWD_DEFINED__
+typedef interface ICorDebugChainEnum ICorDebugChainEnum;
+
+#endif /* __ICorDebugChainEnum_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugModuleEnum_FWD_DEFINED__
+#define __ICorDebugModuleEnum_FWD_DEFINED__
+typedef interface ICorDebugModuleEnum ICorDebugModuleEnum;
+
+#endif /* __ICorDebugModuleEnum_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugValueEnum_FWD_DEFINED__
+#define __ICorDebugValueEnum_FWD_DEFINED__
+typedef interface ICorDebugValueEnum ICorDebugValueEnum;
+
+#endif /* __ICorDebugValueEnum_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugCodeEnum_FWD_DEFINED__
+#define __ICorDebugCodeEnum_FWD_DEFINED__
+typedef interface ICorDebugCodeEnum ICorDebugCodeEnum;
+
+#endif /* __ICorDebugCodeEnum_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugTypeEnum_FWD_DEFINED__
+#define __ICorDebugTypeEnum_FWD_DEFINED__
+typedef interface ICorDebugTypeEnum ICorDebugTypeEnum;
+
+#endif /* __ICorDebugTypeEnum_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugType_FWD_DEFINED__
+#define __ICorDebugType_FWD_DEFINED__
+typedef interface ICorDebugType ICorDebugType;
+
+#endif /* __ICorDebugType_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugErrorInfoEnum_FWD_DEFINED__
+#define __ICorDebugErrorInfoEnum_FWD_DEFINED__
+typedef interface ICorDebugErrorInfoEnum ICorDebugErrorInfoEnum;
+
+#endif /* __ICorDebugErrorInfoEnum_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugAppDomainEnum_FWD_DEFINED__
+#define __ICorDebugAppDomainEnum_FWD_DEFINED__
+typedef interface ICorDebugAppDomainEnum ICorDebugAppDomainEnum;
+
+#endif /* __ICorDebugAppDomainEnum_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugAssemblyEnum_FWD_DEFINED__
+#define __ICorDebugAssemblyEnum_FWD_DEFINED__
+typedef interface ICorDebugAssemblyEnum ICorDebugAssemblyEnum;
+
+#endif /* __ICorDebugAssemblyEnum_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugBlockingObjectEnum_FWD_DEFINED__
+#define __ICorDebugBlockingObjectEnum_FWD_DEFINED__
+typedef interface ICorDebugBlockingObjectEnum ICorDebugBlockingObjectEnum;
+
+#endif /* __ICorDebugBlockingObjectEnum_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugMDA_FWD_DEFINED__
+#define __ICorDebugMDA_FWD_DEFINED__
+typedef interface ICorDebugMDA ICorDebugMDA;
+
+#endif /* __ICorDebugMDA_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugEditAndContinueErrorInfo_FWD_DEFINED__
+#define __ICorDebugEditAndContinueErrorInfo_FWD_DEFINED__
+typedef interface ICorDebugEditAndContinueErrorInfo ICorDebugEditAndContinueErrorInfo;
+
+#endif /* __ICorDebugEditAndContinueErrorInfo_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugEditAndContinueSnapshot_FWD_DEFINED__
+#define __ICorDebugEditAndContinueSnapshot_FWD_DEFINED__
+typedef interface ICorDebugEditAndContinueSnapshot ICorDebugEditAndContinueSnapshot;
+
+#endif /* __ICorDebugEditAndContinueSnapshot_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugExceptionObjectCallStackEnum_FWD_DEFINED__
+#define __ICorDebugExceptionObjectCallStackEnum_FWD_DEFINED__
+typedef interface ICorDebugExceptionObjectCallStackEnum ICorDebugExceptionObjectCallStackEnum;
+
+#endif /* __ICorDebugExceptionObjectCallStackEnum_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugExceptionObjectValue_FWD_DEFINED__
+#define __ICorDebugExceptionObjectValue_FWD_DEFINED__
+typedef interface ICorDebugExceptionObjectValue ICorDebugExceptionObjectValue;
+
+#endif /* __ICorDebugExceptionObjectValue_FWD_DEFINED__ */
+
+
+#ifndef __CorDebug_FWD_DEFINED__
+#define __CorDebug_FWD_DEFINED__
+
+#ifdef __cplusplus
+typedef class CorDebug CorDebug;
+#else
+typedef struct CorDebug CorDebug;
+#endif /* __cplusplus */
+
+#endif /* __CorDebug_FWD_DEFINED__ */
+
+
+#ifndef __EmbeddedCLRCorDebug_FWD_DEFINED__
+#define __EmbeddedCLRCorDebug_FWD_DEFINED__
+
+#ifdef __cplusplus
+typedef class EmbeddedCLRCorDebug EmbeddedCLRCorDebug;
+#else
+typedef struct EmbeddedCLRCorDebug EmbeddedCLRCorDebug;
+#endif /* __cplusplus */
+
+#endif /* __EmbeddedCLRCorDebug_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugValue_FWD_DEFINED__
+#define __ICorDebugValue_FWD_DEFINED__
+typedef interface ICorDebugValue ICorDebugValue;
+
+#endif /* __ICorDebugValue_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugReferenceValue_FWD_DEFINED__
+#define __ICorDebugReferenceValue_FWD_DEFINED__
+typedef interface ICorDebugReferenceValue ICorDebugReferenceValue;
+
+#endif /* __ICorDebugReferenceValue_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugHeapValue_FWD_DEFINED__
+#define __ICorDebugHeapValue_FWD_DEFINED__
+typedef interface ICorDebugHeapValue ICorDebugHeapValue;
+
+#endif /* __ICorDebugHeapValue_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugStringValue_FWD_DEFINED__
+#define __ICorDebugStringValue_FWD_DEFINED__
+typedef interface ICorDebugStringValue ICorDebugStringValue;
+
+#endif /* __ICorDebugStringValue_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugGenericValue_FWD_DEFINED__
+#define __ICorDebugGenericValue_FWD_DEFINED__
+typedef interface ICorDebugGenericValue ICorDebugGenericValue;
+
+#endif /* __ICorDebugGenericValue_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugBoxValue_FWD_DEFINED__
+#define __ICorDebugBoxValue_FWD_DEFINED__
+typedef interface ICorDebugBoxValue ICorDebugBoxValue;
+
+#endif /* __ICorDebugBoxValue_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugArrayValue_FWD_DEFINED__
+#define __ICorDebugArrayValue_FWD_DEFINED__
+typedef interface ICorDebugArrayValue ICorDebugArrayValue;
+
+#endif /* __ICorDebugArrayValue_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugFrame_FWD_DEFINED__
+#define __ICorDebugFrame_FWD_DEFINED__
+typedef interface ICorDebugFrame ICorDebugFrame;
+
+#endif /* __ICorDebugFrame_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugILFrame_FWD_DEFINED__
+#define __ICorDebugILFrame_FWD_DEFINED__
+typedef interface ICorDebugILFrame ICorDebugILFrame;
+
+#endif /* __ICorDebugILFrame_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugInternalFrame_FWD_DEFINED__
+#define __ICorDebugInternalFrame_FWD_DEFINED__
+typedef interface ICorDebugInternalFrame ICorDebugInternalFrame;
+
+#endif /* __ICorDebugInternalFrame_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugInternalFrame2_FWD_DEFINED__
+#define __ICorDebugInternalFrame2_FWD_DEFINED__
+typedef interface ICorDebugInternalFrame2 ICorDebugInternalFrame2;
+
+#endif /* __ICorDebugInternalFrame2_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugNativeFrame_FWD_DEFINED__
+#define __ICorDebugNativeFrame_FWD_DEFINED__
+typedef interface ICorDebugNativeFrame ICorDebugNativeFrame;
+
+#endif /* __ICorDebugNativeFrame_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugNativeFrame2_FWD_DEFINED__
+#define __ICorDebugNativeFrame2_FWD_DEFINED__
+typedef interface ICorDebugNativeFrame2 ICorDebugNativeFrame2;
+
+#endif /* __ICorDebugNativeFrame2_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugRuntimeUnwindableFrame_FWD_DEFINED__
+#define __ICorDebugRuntimeUnwindableFrame_FWD_DEFINED__
+typedef interface ICorDebugRuntimeUnwindableFrame ICorDebugRuntimeUnwindableFrame;
+
+#endif /* __ICorDebugRuntimeUnwindableFrame_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugManagedCallback2_FWD_DEFINED__
+#define __ICorDebugManagedCallback2_FWD_DEFINED__
+typedef interface ICorDebugManagedCallback2 ICorDebugManagedCallback2;
+
+#endif /* __ICorDebugManagedCallback2_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugAppDomain2_FWD_DEFINED__
+#define __ICorDebugAppDomain2_FWD_DEFINED__
+typedef interface ICorDebugAppDomain2 ICorDebugAppDomain2;
+
+#endif /* __ICorDebugAppDomain2_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugAppDomain3_FWD_DEFINED__
+#define __ICorDebugAppDomain3_FWD_DEFINED__
+typedef interface ICorDebugAppDomain3 ICorDebugAppDomain3;
+
+#endif /* __ICorDebugAppDomain3_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugAssembly2_FWD_DEFINED__
+#define __ICorDebugAssembly2_FWD_DEFINED__
+typedef interface ICorDebugAssembly2 ICorDebugAssembly2;
+
+#endif /* __ICorDebugAssembly2_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugProcess2_FWD_DEFINED__
+#define __ICorDebugProcess2_FWD_DEFINED__
+typedef interface ICorDebugProcess2 ICorDebugProcess2;
+
+#endif /* __ICorDebugProcess2_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugStepper2_FWD_DEFINED__
+#define __ICorDebugStepper2_FWD_DEFINED__
+typedef interface ICorDebugStepper2 ICorDebugStepper2;
+
+#endif /* __ICorDebugStepper2_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugThread2_FWD_DEFINED__
+#define __ICorDebugThread2_FWD_DEFINED__
+typedef interface ICorDebugThread2 ICorDebugThread2;
+
+#endif /* __ICorDebugThread2_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugThread3_FWD_DEFINED__
+#define __ICorDebugThread3_FWD_DEFINED__
+typedef interface ICorDebugThread3 ICorDebugThread3;
+
+#endif /* __ICorDebugThread3_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugILFrame2_FWD_DEFINED__
+#define __ICorDebugILFrame2_FWD_DEFINED__
+typedef interface ICorDebugILFrame2 ICorDebugILFrame2;
+
+#endif /* __ICorDebugILFrame2_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugModule2_FWD_DEFINED__
+#define __ICorDebugModule2_FWD_DEFINED__
+typedef interface ICorDebugModule2 ICorDebugModule2;
+
+#endif /* __ICorDebugModule2_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugFunction2_FWD_DEFINED__
+#define __ICorDebugFunction2_FWD_DEFINED__
+typedef interface ICorDebugFunction2 ICorDebugFunction2;
+
+#endif /* __ICorDebugFunction2_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugClass2_FWD_DEFINED__
+#define __ICorDebugClass2_FWD_DEFINED__
+typedef interface ICorDebugClass2 ICorDebugClass2;
+
+#endif /* __ICorDebugClass2_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugEval2_FWD_DEFINED__
+#define __ICorDebugEval2_FWD_DEFINED__
+typedef interface ICorDebugEval2 ICorDebugEval2;
+
+#endif /* __ICorDebugEval2_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugValue2_FWD_DEFINED__
+#define __ICorDebugValue2_FWD_DEFINED__
+typedef interface ICorDebugValue2 ICorDebugValue2;
+
+#endif /* __ICorDebugValue2_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugObjectValue2_FWD_DEFINED__
+#define __ICorDebugObjectValue2_FWD_DEFINED__
+typedef interface ICorDebugObjectValue2 ICorDebugObjectValue2;
+
+#endif /* __ICorDebugObjectValue2_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugHandleValue_FWD_DEFINED__
+#define __ICorDebugHandleValue_FWD_DEFINED__
+typedef interface ICorDebugHandleValue ICorDebugHandleValue;
+
+#endif /* __ICorDebugHandleValue_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugHeapValue2_FWD_DEFINED__
+#define __ICorDebugHeapValue2_FWD_DEFINED__
+typedef interface ICorDebugHeapValue2 ICorDebugHeapValue2;
+
+#endif /* __ICorDebugHeapValue2_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugComObjectValue_FWD_DEFINED__
+#define __ICorDebugComObjectValue_FWD_DEFINED__
+typedef interface ICorDebugComObjectValue ICorDebugComObjectValue;
+
+#endif /* __ICorDebugComObjectValue_FWD_DEFINED__ */
+
+
+#ifndef __ICorDebugModule3_FWD_DEFINED__
+#define __ICorDebugModule3_FWD_DEFINED__
+typedef interface ICorDebugModule3 ICorDebugModule3;
+
+#endif /* __ICorDebugModule3_FWD_DEFINED__ */
+
+
+/* header files for imported files */
+#include "unknwn.h"
+#include "objidl.h"
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+
+/* interface __MIDL_itf_cordebug_0000_0000 */
+/* [local] */
+
+#if 0
+typedef UINT32 mdToken;
+
+typedef mdToken mdModule;
+
+typedef SIZE_T mdScope;
+
+typedef mdToken mdTypeDef;
+
+typedef mdToken mdSourceFile;
+
+typedef mdToken mdMemberRef;
+
+typedef mdToken mdMethodDef;
+
+typedef mdToken mdFieldDef;
+
+typedef mdToken mdSignature;
+
+typedef ULONG CorElementType;
+
+typedef SIZE_T PCCOR_SIGNATURE;
+
+typedef SIZE_T LPDEBUG_EVENT;
+
+typedef SIZE_T LPSTARTUPINFOW;
+
+typedef SIZE_T LPPROCESS_INFORMATION;
+
+typedef const void *LPCVOID;
+
+#endif
+typedef /* [wire_marshal] */ void *HPROCESS;
+
+typedef /* [wire_marshal] */ void *HTHREAD;
+
+typedef UINT64 TASKID;
+
+typedef DWORD CONNID;
+
+#ifndef _COR_IL_MAP
+#define _COR_IL_MAP
+typedef struct _COR_IL_MAP
+ {
+ ULONG32 oldOffset;
+ ULONG32 newOffset;
+ BOOL fAccurate;
+ } COR_IL_MAP;
+
+#endif //_COR_IL_MAP
+#ifndef _COR_DEBUG_IL_TO_NATIVE_MAP_
+#define _COR_DEBUG_IL_TO_NATIVE_MAP_
+typedef
+enum CorDebugIlToNativeMappingTypes
+ {
+ NO_MAPPING = -1,
+ PROLOG = -2,
+ EPILOG = -3
+ } CorDebugIlToNativeMappingTypes;
+
+typedef struct COR_DEBUG_IL_TO_NATIVE_MAP
+ {
+ ULONG32 ilOffset;
+ ULONG32 nativeStartOffset;
+ ULONG32 nativeEndOffset;
+ } COR_DEBUG_IL_TO_NATIVE_MAP;
+
+#endif // _COR_DEBUG_IL_TO_NATIVE_MAP_
+#define REMOTE_DEBUGGING_DLL_ENTRY L"Software\\Microsoft\\.NETFramework\\Debugger\\ActivateRemoteDebugging"
+typedef
+enum CorDebugJITCompilerFlags
+ {
+ CORDEBUG_JIT_DEFAULT = 0x1,
+ CORDEBUG_JIT_DISABLE_OPTIMIZATION = 0x3,
+ CORDEBUG_JIT_ENABLE_ENC = 0x7
+ } CorDebugJITCompilerFlags;
+
+typedef
+enum CorDebugJITCompilerFlagsDecprecated
+ {
+ CORDEBUG_JIT_TRACK_DEBUG_INFO = 0x1
+ } CorDebugJITCompilerFlagsDeprecated;
+
+typedef
+enum CorDebugNGENPolicy
+ {
+ DISABLE_LOCAL_NIC = 1
+ } CorDebugNGENPolicy;
+
+#pragma warning(push)
+#pragma warning(disable:28718)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#pragma warning(pop)
+typedef ULONG64 CORDB_ADDRESS;
+
+typedef ULONG64 CORDB_REGISTER;
+
+typedef DWORD CORDB_CONTINUE_STATUS;
+
+typedef
+enum CorDebugBlockingReason
+ {
+ BLOCKING_NONE = 0,
+ BLOCKING_MONITOR_CRITICAL_SECTION = 0x1,
+ BLOCKING_MONITOR_EVENT = 0x2
+ } CorDebugBlockingReason;
+
+typedef struct CorDebugBlockingObject
+ {
+ ICorDebugValue *pBlockingObject;
+ DWORD dwTimeout;
+ CorDebugBlockingReason blockingReason;
+ } CorDebugBlockingObject;
+
+typedef struct CorDebugExceptionObjectStackFrame
+ {
+ ICorDebugModule *pModule;
+ CORDB_ADDRESS ip;
+ mdMethodDef methodDef;
+ BOOL isLastForeignExceptionFrame;
+ } CorDebugExceptionObjectStackFrame;
+
+typedef struct CorDebugGuidToTypeMapping
+ {
+ GUID iid;
+ ICorDebugType *pType;
+ } CorDebugGuidToTypeMapping;
+
+
+
+extern RPC_IF_HANDLE __MIDL_itf_cordebug_0000_0000_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_cordebug_0000_0000_v0_0_s_ifspec;
+
+#ifndef __ICorDebugDataTarget_INTERFACE_DEFINED__
+#define __ICorDebugDataTarget_INTERFACE_DEFINED__
+
+/* interface ICorDebugDataTarget */
+/* [unique][uuid][local][object] */
+
+typedef
+enum CorDebugPlatform
+ {
+ CORDB_PLATFORM_WINDOWS_X86 = 0,
+ CORDB_PLATFORM_WINDOWS_AMD64 = ( CORDB_PLATFORM_WINDOWS_X86 + 1 ) ,
+ CORDB_PLATFORM_WINDOWS_IA64 = ( CORDB_PLATFORM_WINDOWS_AMD64 + 1 ) ,
+ CORDB_PLATFORM_MAC_PPC = ( CORDB_PLATFORM_WINDOWS_IA64 + 1 ) ,
+ CORDB_PLATFORM_MAC_X86 = ( CORDB_PLATFORM_MAC_PPC + 1 ) ,
+ CORDB_PLATFORM_WINDOWS_ARM = ( CORDB_PLATFORM_MAC_X86 + 1 ) ,
+ CORDB_PLATFORM_MAC_AMD64 = ( CORDB_PLATFORM_WINDOWS_ARM + 1 ) ,
+ CORDB_PLATFORM_WINDOWS_ARM64 = ( CORDB_PLATFORM_MAC_AMD64 + 1 ) ,
+ CORDB_PLATFORM_POSIX_AMD64 = ( CORDB_PLATFORM_WINDOWS_ARM64 + 1 ) ,
+ CORDB_PLATFORM_POSIX_X86 = ( CORDB_PLATFORM_POSIX_AMD64 + 1 ) ,
+ CORDB_PLATFORM_POSIX_ARM = ( CORDB_PLATFORM_POSIX_X86 + 1 ) ,
+ CORDB_PLATFORM_POSIX_ARM64 = ( CORDB_PLATFORM_POSIX_ARM + 1 )
+ } CorDebugPlatform;
+
+
+EXTERN_C const IID IID_ICorDebugDataTarget;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("FE06DC28-49FB-4636-A4A3-E80DB4AE116C")
+ ICorDebugDataTarget : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetPlatform(
+ /* [out] */ CorDebugPlatform *pTargetPlatform) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ReadVirtual(
+ /* [in] */ CORDB_ADDRESS address,
+ /* [length_is][size_is][out] */ BYTE *pBuffer,
+ /* [in] */ ULONG32 bytesRequested,
+ /* [out] */ ULONG32 *pBytesRead) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetThreadContext(
+ /* [in] */ DWORD dwThreadID,
+ /* [in] */ ULONG32 contextFlags,
+ /* [in] */ ULONG32 contextSize,
+ /* [size_is][out] */ BYTE *pContext) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugDataTargetVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugDataTarget * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugDataTarget * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugDataTarget * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetPlatform )(
+ ICorDebugDataTarget * This,
+ /* [out] */ CorDebugPlatform *pTargetPlatform);
+
+ HRESULT ( STDMETHODCALLTYPE *ReadVirtual )(
+ ICorDebugDataTarget * This,
+ /* [in] */ CORDB_ADDRESS address,
+ /* [length_is][size_is][out] */ BYTE *pBuffer,
+ /* [in] */ ULONG32 bytesRequested,
+ /* [out] */ ULONG32 *pBytesRead);
+
+ HRESULT ( STDMETHODCALLTYPE *GetThreadContext )(
+ ICorDebugDataTarget * This,
+ /* [in] */ DWORD dwThreadID,
+ /* [in] */ ULONG32 contextFlags,
+ /* [in] */ ULONG32 contextSize,
+ /* [size_is][out] */ BYTE *pContext);
+
+ END_INTERFACE
+ } ICorDebugDataTargetVtbl;
+
+ interface ICorDebugDataTarget
+ {
+ CONST_VTBL struct ICorDebugDataTargetVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugDataTarget_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugDataTarget_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugDataTarget_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugDataTarget_GetPlatform(This,pTargetPlatform) \
+ ( (This)->lpVtbl -> GetPlatform(This,pTargetPlatform) )
+
+#define ICorDebugDataTarget_ReadVirtual(This,address,pBuffer,bytesRequested,pBytesRead) \
+ ( (This)->lpVtbl -> ReadVirtual(This,address,pBuffer,bytesRequested,pBytesRead) )
+
+#define ICorDebugDataTarget_GetThreadContext(This,dwThreadID,contextFlags,contextSize,pContext) \
+ ( (This)->lpVtbl -> GetThreadContext(This,dwThreadID,contextFlags,contextSize,pContext) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugDataTarget_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugStaticFieldSymbol_INTERFACE_DEFINED__
+#define __ICorDebugStaticFieldSymbol_INTERFACE_DEFINED__
+
+/* interface ICorDebugStaticFieldSymbol */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugStaticFieldSymbol;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("CBF9DA63-F68D-4BBB-A21C-15A45EAADF5B")
+ ICorDebugStaticFieldSymbol : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetName(
+ /* [in] */ ULONG32 cchName,
+ /* [out] */ ULONG32 *pcchName,
+ /* [length_is][size_is][out] */ WCHAR szName[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetSize(
+ /* [out] */ ULONG32 *pcbSize) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetAddress(
+ /* [out] */ CORDB_ADDRESS *pRVA) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugStaticFieldSymbolVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugStaticFieldSymbol * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugStaticFieldSymbol * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugStaticFieldSymbol * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetName )(
+ ICorDebugStaticFieldSymbol * This,
+ /* [in] */ ULONG32 cchName,
+ /* [out] */ ULONG32 *pcchName,
+ /* [length_is][size_is][out] */ WCHAR szName[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetSize )(
+ ICorDebugStaticFieldSymbol * This,
+ /* [out] */ ULONG32 *pcbSize);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAddress )(
+ ICorDebugStaticFieldSymbol * This,
+ /* [out] */ CORDB_ADDRESS *pRVA);
+
+ END_INTERFACE
+ } ICorDebugStaticFieldSymbolVtbl;
+
+ interface ICorDebugStaticFieldSymbol
+ {
+ CONST_VTBL struct ICorDebugStaticFieldSymbolVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugStaticFieldSymbol_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugStaticFieldSymbol_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugStaticFieldSymbol_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugStaticFieldSymbol_GetName(This,cchName,pcchName,szName) \
+ ( (This)->lpVtbl -> GetName(This,cchName,pcchName,szName) )
+
+#define ICorDebugStaticFieldSymbol_GetSize(This,pcbSize) \
+ ( (This)->lpVtbl -> GetSize(This,pcbSize) )
+
+#define ICorDebugStaticFieldSymbol_GetAddress(This,pRVA) \
+ ( (This)->lpVtbl -> GetAddress(This,pRVA) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugStaticFieldSymbol_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugInstanceFieldSymbol_INTERFACE_DEFINED__
+#define __ICorDebugInstanceFieldSymbol_INTERFACE_DEFINED__
+
+/* interface ICorDebugInstanceFieldSymbol */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugInstanceFieldSymbol;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("A074096B-3ADC-4485-81DA-68C7A4EA52DB")
+ ICorDebugInstanceFieldSymbol : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetName(
+ /* [in] */ ULONG32 cchName,
+ /* [out] */ ULONG32 *pcchName,
+ /* [length_is][size_is][out] */ WCHAR szName[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetSize(
+ /* [out] */ ULONG32 *pcbSize) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetOffset(
+ /* [out] */ ULONG32 *pcbOffset) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugInstanceFieldSymbolVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugInstanceFieldSymbol * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugInstanceFieldSymbol * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugInstanceFieldSymbol * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetName )(
+ ICorDebugInstanceFieldSymbol * This,
+ /* [in] */ ULONG32 cchName,
+ /* [out] */ ULONG32 *pcchName,
+ /* [length_is][size_is][out] */ WCHAR szName[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetSize )(
+ ICorDebugInstanceFieldSymbol * This,
+ /* [out] */ ULONG32 *pcbSize);
+
+ HRESULT ( STDMETHODCALLTYPE *GetOffset )(
+ ICorDebugInstanceFieldSymbol * This,
+ /* [out] */ ULONG32 *pcbOffset);
+
+ END_INTERFACE
+ } ICorDebugInstanceFieldSymbolVtbl;
+
+ interface ICorDebugInstanceFieldSymbol
+ {
+ CONST_VTBL struct ICorDebugInstanceFieldSymbolVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugInstanceFieldSymbol_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugInstanceFieldSymbol_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugInstanceFieldSymbol_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugInstanceFieldSymbol_GetName(This,cchName,pcchName,szName) \
+ ( (This)->lpVtbl -> GetName(This,cchName,pcchName,szName) )
+
+#define ICorDebugInstanceFieldSymbol_GetSize(This,pcbSize) \
+ ( (This)->lpVtbl -> GetSize(This,pcbSize) )
+
+#define ICorDebugInstanceFieldSymbol_GetOffset(This,pcbOffset) \
+ ( (This)->lpVtbl -> GetOffset(This,pcbOffset) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugInstanceFieldSymbol_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugVariableSymbol_INTERFACE_DEFINED__
+#define __ICorDebugVariableSymbol_INTERFACE_DEFINED__
+
+/* interface ICorDebugVariableSymbol */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugVariableSymbol;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("707E8932-1163-48D9-8A93-F5B1F480FBB7")
+ ICorDebugVariableSymbol : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetName(
+ /* [in] */ ULONG32 cchName,
+ /* [out] */ ULONG32 *pcchName,
+ /* [length_is][size_is][out] */ WCHAR szName[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetSize(
+ /* [out] */ ULONG32 *pcbValue) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetValue(
+ /* [in] */ ULONG32 offset,
+ /* [in] */ ULONG32 cbContext,
+ /* [size_is][in] */ BYTE context[ ],
+ /* [in] */ ULONG32 cbValue,
+ /* [out] */ ULONG32 *pcbValue,
+ /* [length_is][size_is][out] */ BYTE pValue[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetValue(
+ /* [in] */ ULONG32 offset,
+ /* [in] */ DWORD threadID,
+ /* [in] */ ULONG32 cbContext,
+ /* [size_is][in] */ BYTE context[ ],
+ /* [in] */ ULONG32 cbValue,
+ /* [size_is][in] */ BYTE pValue[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetSlotIndex(
+ /* [out] */ ULONG32 *pSlotIndex) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugVariableSymbolVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugVariableSymbol * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugVariableSymbol * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugVariableSymbol * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetName )(
+ ICorDebugVariableSymbol * This,
+ /* [in] */ ULONG32 cchName,
+ /* [out] */ ULONG32 *pcchName,
+ /* [length_is][size_is][out] */ WCHAR szName[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetSize )(
+ ICorDebugVariableSymbol * This,
+ /* [out] */ ULONG32 *pcbValue);
+
+ HRESULT ( STDMETHODCALLTYPE *GetValue )(
+ ICorDebugVariableSymbol * This,
+ /* [in] */ ULONG32 offset,
+ /* [in] */ ULONG32 cbContext,
+ /* [size_is][in] */ BYTE context[ ],
+ /* [in] */ ULONG32 cbValue,
+ /* [out] */ ULONG32 *pcbValue,
+ /* [length_is][size_is][out] */ BYTE pValue[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *SetValue )(
+ ICorDebugVariableSymbol * This,
+ /* [in] */ ULONG32 offset,
+ /* [in] */ DWORD threadID,
+ /* [in] */ ULONG32 cbContext,
+ /* [size_is][in] */ BYTE context[ ],
+ /* [in] */ ULONG32 cbValue,
+ /* [size_is][in] */ BYTE pValue[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetSlotIndex )(
+ ICorDebugVariableSymbol * This,
+ /* [out] */ ULONG32 *pSlotIndex);
+
+ END_INTERFACE
+ } ICorDebugVariableSymbolVtbl;
+
+ interface ICorDebugVariableSymbol
+ {
+ CONST_VTBL struct ICorDebugVariableSymbolVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugVariableSymbol_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugVariableSymbol_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugVariableSymbol_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugVariableSymbol_GetName(This,cchName,pcchName,szName) \
+ ( (This)->lpVtbl -> GetName(This,cchName,pcchName,szName) )
+
+#define ICorDebugVariableSymbol_GetSize(This,pcbValue) \
+ ( (This)->lpVtbl -> GetSize(This,pcbValue) )
+
+#define ICorDebugVariableSymbol_GetValue(This,offset,cbContext,context,cbValue,pcbValue,pValue) \
+ ( (This)->lpVtbl -> GetValue(This,offset,cbContext,context,cbValue,pcbValue,pValue) )
+
+#define ICorDebugVariableSymbol_SetValue(This,offset,threadID,cbContext,context,cbValue,pValue) \
+ ( (This)->lpVtbl -> SetValue(This,offset,threadID,cbContext,context,cbValue,pValue) )
+
+#define ICorDebugVariableSymbol_GetSlotIndex(This,pSlotIndex) \
+ ( (This)->lpVtbl -> GetSlotIndex(This,pSlotIndex) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugVariableSymbol_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugMemoryBuffer_INTERFACE_DEFINED__
+#define __ICorDebugMemoryBuffer_INTERFACE_DEFINED__
+
+/* interface ICorDebugMemoryBuffer */
+/* [unique][local][uuid][object] */
+
+
+EXTERN_C const IID IID_ICorDebugMemoryBuffer;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("677888B3-D160-4B8C-A73B-D79E6AAA1D13")
+ ICorDebugMemoryBuffer : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetStartAddress(
+ /* [out] */ LPCVOID *address) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetSize(
+ /* [out] */ ULONG32 *pcbBufferLength) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugMemoryBufferVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugMemoryBuffer * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugMemoryBuffer * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugMemoryBuffer * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetStartAddress )(
+ ICorDebugMemoryBuffer * This,
+ /* [out] */ LPCVOID *address);
+
+ HRESULT ( STDMETHODCALLTYPE *GetSize )(
+ ICorDebugMemoryBuffer * This,
+ /* [out] */ ULONG32 *pcbBufferLength);
+
+ END_INTERFACE
+ } ICorDebugMemoryBufferVtbl;
+
+ interface ICorDebugMemoryBuffer
+ {
+ CONST_VTBL struct ICorDebugMemoryBufferVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugMemoryBuffer_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugMemoryBuffer_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugMemoryBuffer_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugMemoryBuffer_GetStartAddress(This,address) \
+ ( (This)->lpVtbl -> GetStartAddress(This,address) )
+
+#define ICorDebugMemoryBuffer_GetSize(This,pcbBufferLength) \
+ ( (This)->lpVtbl -> GetSize(This,pcbBufferLength) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugMemoryBuffer_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugMergedAssemblyRecord_INTERFACE_DEFINED__
+#define __ICorDebugMergedAssemblyRecord_INTERFACE_DEFINED__
+
+/* interface ICorDebugMergedAssemblyRecord */
+/* [unique][local][uuid][object] */
+
+
+EXTERN_C const IID IID_ICorDebugMergedAssemblyRecord;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("FAA8637B-3BBE-4671-8E26-3B59875B922A")
+ ICorDebugMergedAssemblyRecord : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetSimpleName(
+ /* [in] */ ULONG32 cchName,
+ /* [out] */ ULONG32 *pcchName,
+ /* [length_is][size_is][out] */ WCHAR szName[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetVersion(
+ /* [out] */ USHORT *pMajor,
+ /* [out] */ USHORT *pMinor,
+ /* [out] */ USHORT *pBuild,
+ /* [out] */ USHORT *pRevision) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetCulture(
+ /* [in] */ ULONG32 cchCulture,
+ /* [out] */ ULONG32 *pcchCulture,
+ /* [length_is][size_is][out] */ WCHAR szCulture[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetPublicKey(
+ /* [in] */ ULONG32 cbPublicKey,
+ /* [out] */ ULONG32 *pcbPublicKey,
+ /* [length_is][size_is][out] */ BYTE pbPublicKey[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetPublicKeyToken(
+ /* [in] */ ULONG32 cbPublicKeyToken,
+ /* [out] */ ULONG32 *pcbPublicKeyToken,
+ /* [length_is][size_is][out] */ BYTE pbPublicKeyToken[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetIndex(
+ /* [out] */ ULONG32 *pIndex) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugMergedAssemblyRecordVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugMergedAssemblyRecord * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugMergedAssemblyRecord * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugMergedAssemblyRecord * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetSimpleName )(
+ ICorDebugMergedAssemblyRecord * This,
+ /* [in] */ ULONG32 cchName,
+ /* [out] */ ULONG32 *pcchName,
+ /* [length_is][size_is][out] */ WCHAR szName[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetVersion )(
+ ICorDebugMergedAssemblyRecord * This,
+ /* [out] */ USHORT *pMajor,
+ /* [out] */ USHORT *pMinor,
+ /* [out] */ USHORT *pBuild,
+ /* [out] */ USHORT *pRevision);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCulture )(
+ ICorDebugMergedAssemblyRecord * This,
+ /* [in] */ ULONG32 cchCulture,
+ /* [out] */ ULONG32 *pcchCulture,
+ /* [length_is][size_is][out] */ WCHAR szCulture[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetPublicKey )(
+ ICorDebugMergedAssemblyRecord * This,
+ /* [in] */ ULONG32 cbPublicKey,
+ /* [out] */ ULONG32 *pcbPublicKey,
+ /* [length_is][size_is][out] */ BYTE pbPublicKey[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetPublicKeyToken )(
+ ICorDebugMergedAssemblyRecord * This,
+ /* [in] */ ULONG32 cbPublicKeyToken,
+ /* [out] */ ULONG32 *pcbPublicKeyToken,
+ /* [length_is][size_is][out] */ BYTE pbPublicKeyToken[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetIndex )(
+ ICorDebugMergedAssemblyRecord * This,
+ /* [out] */ ULONG32 *pIndex);
+
+ END_INTERFACE
+ } ICorDebugMergedAssemblyRecordVtbl;
+
+ interface ICorDebugMergedAssemblyRecord
+ {
+ CONST_VTBL struct ICorDebugMergedAssemblyRecordVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugMergedAssemblyRecord_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugMergedAssemblyRecord_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugMergedAssemblyRecord_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugMergedAssemblyRecord_GetSimpleName(This,cchName,pcchName,szName) \
+ ( (This)->lpVtbl -> GetSimpleName(This,cchName,pcchName,szName) )
+
+#define ICorDebugMergedAssemblyRecord_GetVersion(This,pMajor,pMinor,pBuild,pRevision) \
+ ( (This)->lpVtbl -> GetVersion(This,pMajor,pMinor,pBuild,pRevision) )
+
+#define ICorDebugMergedAssemblyRecord_GetCulture(This,cchCulture,pcchCulture,szCulture) \
+ ( (This)->lpVtbl -> GetCulture(This,cchCulture,pcchCulture,szCulture) )
+
+#define ICorDebugMergedAssemblyRecord_GetPublicKey(This,cbPublicKey,pcbPublicKey,pbPublicKey) \
+ ( (This)->lpVtbl -> GetPublicKey(This,cbPublicKey,pcbPublicKey,pbPublicKey) )
+
+#define ICorDebugMergedAssemblyRecord_GetPublicKeyToken(This,cbPublicKeyToken,pcbPublicKeyToken,pbPublicKeyToken) \
+ ( (This)->lpVtbl -> GetPublicKeyToken(This,cbPublicKeyToken,pcbPublicKeyToken,pbPublicKeyToken) )
+
+#define ICorDebugMergedAssemblyRecord_GetIndex(This,pIndex) \
+ ( (This)->lpVtbl -> GetIndex(This,pIndex) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugMergedAssemblyRecord_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugSymbolProvider_INTERFACE_DEFINED__
+#define __ICorDebugSymbolProvider_INTERFACE_DEFINED__
+
+/* interface ICorDebugSymbolProvider */
+/* [unique][local][uuid][object] */
+
+
+EXTERN_C const IID IID_ICorDebugSymbolProvider;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("3948A999-FD8A-4C38-A708-8A71E9B04DBB")
+ ICorDebugSymbolProvider : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetStaticFieldSymbols(
+ /* [in] */ ULONG32 cbSignature,
+ /* [size_is][in] */ BYTE typeSig[ ],
+ /* [in] */ ULONG32 cRequestedSymbols,
+ /* [out] */ ULONG32 *pcFetchedSymbols,
+ /* [length_is][size_is][out] */ ICorDebugStaticFieldSymbol *pSymbols[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetInstanceFieldSymbols(
+ /* [in] */ ULONG32 cbSignature,
+ /* [size_is][in] */ BYTE typeSig[ ],
+ /* [in] */ ULONG32 cRequestedSymbols,
+ /* [out] */ ULONG32 *pcFetchedSymbols,
+ /* [length_is][size_is][out] */ ICorDebugInstanceFieldSymbol *pSymbols[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetMethodLocalSymbols(
+ /* [in] */ ULONG32 nativeRVA,
+ /* [in] */ ULONG32 cRequestedSymbols,
+ /* [out] */ ULONG32 *pcFetchedSymbols,
+ /* [length_is][size_is][out] */ ICorDebugVariableSymbol *pSymbols[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetMethodParameterSymbols(
+ /* [in] */ ULONG32 nativeRVA,
+ /* [in] */ ULONG32 cRequestedSymbols,
+ /* [out] */ ULONG32 *pcFetchedSymbols,
+ /* [length_is][size_is][out] */ ICorDebugVariableSymbol *pSymbols[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetMergedAssemblyRecords(
+ /* [in] */ ULONG32 cRequestedRecords,
+ /* [out] */ ULONG32 *pcFetchedRecords,
+ /* [length_is][size_is][out] */ ICorDebugMergedAssemblyRecord *pRecords[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetMethodProps(
+ /* [in] */ ULONG32 codeRva,
+ /* [out] */ mdToken *pMethodToken,
+ /* [out] */ ULONG32 *pcGenericParams,
+ /* [in] */ ULONG32 cbSignature,
+ /* [out] */ ULONG32 *pcbSignature,
+ /* [length_is][size_is][out] */ BYTE signature[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetTypeProps(
+ /* [in] */ ULONG32 vtableRva,
+ /* [in] */ ULONG32 cbSignature,
+ /* [out] */ ULONG32 *pcbSignature,
+ /* [length_is][size_is][out] */ BYTE signature[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetCodeRange(
+ /* [in] */ ULONG32 codeRva,
+ /* [out] */ ULONG32 *pCodeStartAddress,
+ ULONG32 *pCodeSize) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetAssemblyImageBytes(
+ /* [in] */ CORDB_ADDRESS rva,
+ /* [in] */ ULONG32 length,
+ /* [out] */ ICorDebugMemoryBuffer **ppMemoryBuffer) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetObjectSize(
+ /* [in] */ ULONG32 cbSignature,
+ /* [size_is][in] */ BYTE typeSig[ ],
+ /* [out] */ ULONG32 *pObjectSize) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetAssemblyImageMetadata(
+ /* [out] */ ICorDebugMemoryBuffer **ppMemoryBuffer) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugSymbolProviderVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugSymbolProvider * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugSymbolProvider * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugSymbolProvider * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetStaticFieldSymbols )(
+ ICorDebugSymbolProvider * This,
+ /* [in] */ ULONG32 cbSignature,
+ /* [size_is][in] */ BYTE typeSig[ ],
+ /* [in] */ ULONG32 cRequestedSymbols,
+ /* [out] */ ULONG32 *pcFetchedSymbols,
+ /* [length_is][size_is][out] */ ICorDebugStaticFieldSymbol *pSymbols[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetInstanceFieldSymbols )(
+ ICorDebugSymbolProvider * This,
+ /* [in] */ ULONG32 cbSignature,
+ /* [size_is][in] */ BYTE typeSig[ ],
+ /* [in] */ ULONG32 cRequestedSymbols,
+ /* [out] */ ULONG32 *pcFetchedSymbols,
+ /* [length_is][size_is][out] */ ICorDebugInstanceFieldSymbol *pSymbols[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetMethodLocalSymbols )(
+ ICorDebugSymbolProvider * This,
+ /* [in] */ ULONG32 nativeRVA,
+ /* [in] */ ULONG32 cRequestedSymbols,
+ /* [out] */ ULONG32 *pcFetchedSymbols,
+ /* [length_is][size_is][out] */ ICorDebugVariableSymbol *pSymbols[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetMethodParameterSymbols )(
+ ICorDebugSymbolProvider * This,
+ /* [in] */ ULONG32 nativeRVA,
+ /* [in] */ ULONG32 cRequestedSymbols,
+ /* [out] */ ULONG32 *pcFetchedSymbols,
+ /* [length_is][size_is][out] */ ICorDebugVariableSymbol *pSymbols[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetMergedAssemblyRecords )(
+ ICorDebugSymbolProvider * This,
+ /* [in] */ ULONG32 cRequestedRecords,
+ /* [out] */ ULONG32 *pcFetchedRecords,
+ /* [length_is][size_is][out] */ ICorDebugMergedAssemblyRecord *pRecords[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetMethodProps )(
+ ICorDebugSymbolProvider * This,
+ /* [in] */ ULONG32 codeRva,
+ /* [out] */ mdToken *pMethodToken,
+ /* [out] */ ULONG32 *pcGenericParams,
+ /* [in] */ ULONG32 cbSignature,
+ /* [out] */ ULONG32 *pcbSignature,
+ /* [length_is][size_is][out] */ BYTE signature[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetTypeProps )(
+ ICorDebugSymbolProvider * This,
+ /* [in] */ ULONG32 vtableRva,
+ /* [in] */ ULONG32 cbSignature,
+ /* [out] */ ULONG32 *pcbSignature,
+ /* [length_is][size_is][out] */ BYTE signature[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCodeRange )(
+ ICorDebugSymbolProvider * This,
+ /* [in] */ ULONG32 codeRva,
+ /* [out] */ ULONG32 *pCodeStartAddress,
+ ULONG32 *pCodeSize);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAssemblyImageBytes )(
+ ICorDebugSymbolProvider * This,
+ /* [in] */ CORDB_ADDRESS rva,
+ /* [in] */ ULONG32 length,
+ /* [out] */ ICorDebugMemoryBuffer **ppMemoryBuffer);
+
+ HRESULT ( STDMETHODCALLTYPE *GetObjectSize )(
+ ICorDebugSymbolProvider * This,
+ /* [in] */ ULONG32 cbSignature,
+ /* [size_is][in] */ BYTE typeSig[ ],
+ /* [out] */ ULONG32 *pObjectSize);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAssemblyImageMetadata )(
+ ICorDebugSymbolProvider * This,
+ /* [out] */ ICorDebugMemoryBuffer **ppMemoryBuffer);
+
+ END_INTERFACE
+ } ICorDebugSymbolProviderVtbl;
+
+ interface ICorDebugSymbolProvider
+ {
+ CONST_VTBL struct ICorDebugSymbolProviderVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugSymbolProvider_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugSymbolProvider_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugSymbolProvider_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugSymbolProvider_GetStaticFieldSymbols(This,cbSignature,typeSig,cRequestedSymbols,pcFetchedSymbols,pSymbols) \
+ ( (This)->lpVtbl -> GetStaticFieldSymbols(This,cbSignature,typeSig,cRequestedSymbols,pcFetchedSymbols,pSymbols) )
+
+#define ICorDebugSymbolProvider_GetInstanceFieldSymbols(This,cbSignature,typeSig,cRequestedSymbols,pcFetchedSymbols,pSymbols) \
+ ( (This)->lpVtbl -> GetInstanceFieldSymbols(This,cbSignature,typeSig,cRequestedSymbols,pcFetchedSymbols,pSymbols) )
+
+#define ICorDebugSymbolProvider_GetMethodLocalSymbols(This,nativeRVA,cRequestedSymbols,pcFetchedSymbols,pSymbols) \
+ ( (This)->lpVtbl -> GetMethodLocalSymbols(This,nativeRVA,cRequestedSymbols,pcFetchedSymbols,pSymbols) )
+
+#define ICorDebugSymbolProvider_GetMethodParameterSymbols(This,nativeRVA,cRequestedSymbols,pcFetchedSymbols,pSymbols) \
+ ( (This)->lpVtbl -> GetMethodParameterSymbols(This,nativeRVA,cRequestedSymbols,pcFetchedSymbols,pSymbols) )
+
+#define ICorDebugSymbolProvider_GetMergedAssemblyRecords(This,cRequestedRecords,pcFetchedRecords,pRecords) \
+ ( (This)->lpVtbl -> GetMergedAssemblyRecords(This,cRequestedRecords,pcFetchedRecords,pRecords) )
+
+#define ICorDebugSymbolProvider_GetMethodProps(This,codeRva,pMethodToken,pcGenericParams,cbSignature,pcbSignature,signature) \
+ ( (This)->lpVtbl -> GetMethodProps(This,codeRva,pMethodToken,pcGenericParams,cbSignature,pcbSignature,signature) )
+
+#define ICorDebugSymbolProvider_GetTypeProps(This,vtableRva,cbSignature,pcbSignature,signature) \
+ ( (This)->lpVtbl -> GetTypeProps(This,vtableRva,cbSignature,pcbSignature,signature) )
+
+#define ICorDebugSymbolProvider_GetCodeRange(This,codeRva,pCodeStartAddress,pCodeSize) \
+ ( (This)->lpVtbl -> GetCodeRange(This,codeRva,pCodeStartAddress,pCodeSize) )
+
+#define ICorDebugSymbolProvider_GetAssemblyImageBytes(This,rva,length,ppMemoryBuffer) \
+ ( (This)->lpVtbl -> GetAssemblyImageBytes(This,rva,length,ppMemoryBuffer) )
+
+#define ICorDebugSymbolProvider_GetObjectSize(This,cbSignature,typeSig,pObjectSize) \
+ ( (This)->lpVtbl -> GetObjectSize(This,cbSignature,typeSig,pObjectSize) )
+
+#define ICorDebugSymbolProvider_GetAssemblyImageMetadata(This,ppMemoryBuffer) \
+ ( (This)->lpVtbl -> GetAssemblyImageMetadata(This,ppMemoryBuffer) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugSymbolProvider_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugSymbolProvider2_INTERFACE_DEFINED__
+#define __ICorDebugSymbolProvider2_INTERFACE_DEFINED__
+
+/* interface ICorDebugSymbolProvider2 */
+/* [unique][local][uuid][object] */
+
+
+EXTERN_C const IID IID_ICorDebugSymbolProvider2;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("F9801807-4764-4330-9E67-4F685094165E")
+ ICorDebugSymbolProvider2 : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetGenericDictionaryInfo(
+ /* [out] */ ICorDebugMemoryBuffer **ppMemoryBuffer) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetFrameProps(
+ /* [in] */ ULONG32 codeRva,
+ /* [out] */ ULONG32 *pCodeStartRva,
+ /* [out] */ ULONG32 *pParentFrameStartRva) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugSymbolProvider2Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugSymbolProvider2 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugSymbolProvider2 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugSymbolProvider2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetGenericDictionaryInfo )(
+ ICorDebugSymbolProvider2 * This,
+ /* [out] */ ICorDebugMemoryBuffer **ppMemoryBuffer);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFrameProps )(
+ ICorDebugSymbolProvider2 * This,
+ /* [in] */ ULONG32 codeRva,
+ /* [out] */ ULONG32 *pCodeStartRva,
+ /* [out] */ ULONG32 *pParentFrameStartRva);
+
+ END_INTERFACE
+ } ICorDebugSymbolProvider2Vtbl;
+
+ interface ICorDebugSymbolProvider2
+ {
+ CONST_VTBL struct ICorDebugSymbolProvider2Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugSymbolProvider2_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugSymbolProvider2_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugSymbolProvider2_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugSymbolProvider2_GetGenericDictionaryInfo(This,ppMemoryBuffer) \
+ ( (This)->lpVtbl -> GetGenericDictionaryInfo(This,ppMemoryBuffer) )
+
+#define ICorDebugSymbolProvider2_GetFrameProps(This,codeRva,pCodeStartRva,pParentFrameStartRva) \
+ ( (This)->lpVtbl -> GetFrameProps(This,codeRva,pCodeStartRva,pParentFrameStartRva) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugSymbolProvider2_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugVirtualUnwinder_INTERFACE_DEFINED__
+#define __ICorDebugVirtualUnwinder_INTERFACE_DEFINED__
+
+/* interface ICorDebugVirtualUnwinder */
+/* [unique][local][uuid][object] */
+
+
+EXTERN_C const IID IID_ICorDebugVirtualUnwinder;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("F69126B7-C787-4F6B-AE96-A569786FC670")
+ ICorDebugVirtualUnwinder : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetContext(
+ /* [in] */ ULONG32 contextFlags,
+ /* [in] */ ULONG32 cbContextBuf,
+ /* [out] */ ULONG32 *contextSize,
+ /* [size_is][out] */ BYTE contextBuf[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Next( void) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugVirtualUnwinderVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugVirtualUnwinder * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugVirtualUnwinder * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugVirtualUnwinder * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetContext )(
+ ICorDebugVirtualUnwinder * This,
+ /* [in] */ ULONG32 contextFlags,
+ /* [in] */ ULONG32 cbContextBuf,
+ /* [out] */ ULONG32 *contextSize,
+ /* [size_is][out] */ BYTE contextBuf[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *Next )(
+ ICorDebugVirtualUnwinder * This);
+
+ END_INTERFACE
+ } ICorDebugVirtualUnwinderVtbl;
+
+ interface ICorDebugVirtualUnwinder
+ {
+ CONST_VTBL struct ICorDebugVirtualUnwinderVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugVirtualUnwinder_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugVirtualUnwinder_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugVirtualUnwinder_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugVirtualUnwinder_GetContext(This,contextFlags,cbContextBuf,contextSize,contextBuf) \
+ ( (This)->lpVtbl -> GetContext(This,contextFlags,cbContextBuf,contextSize,contextBuf) )
+
+#define ICorDebugVirtualUnwinder_Next(This) \
+ ( (This)->lpVtbl -> Next(This) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugVirtualUnwinder_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugDataTarget2_INTERFACE_DEFINED__
+#define __ICorDebugDataTarget2_INTERFACE_DEFINED__
+
+/* interface ICorDebugDataTarget2 */
+/* [unique][local][uuid][object] */
+
+
+EXTERN_C const IID IID_ICorDebugDataTarget2;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("2eb364da-605b-4e8d-b333-3394c4828d41")
+ ICorDebugDataTarget2 : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetImageFromPointer(
+ /* [in] */ CORDB_ADDRESS addr,
+ /* [out] */ CORDB_ADDRESS *pImageBase,
+ /* [out] */ ULONG32 *pSize) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetImageLocation(
+ /* [in] */ CORDB_ADDRESS baseAddress,
+ /* [in] */ ULONG32 cchName,
+ /* [out] */ ULONG32 *pcchName,
+ /* [length_is][size_is][out] */ WCHAR szName[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetSymbolProviderForImage(
+ /* [in] */ CORDB_ADDRESS imageBaseAddress,
+ /* [out] */ ICorDebugSymbolProvider **ppSymProvider) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnumerateThreadIDs(
+ /* [in] */ ULONG32 cThreadIds,
+ /* [out] */ ULONG32 *pcThreadIds,
+ /* [length_is][size_is][out] */ ULONG32 pThreadIds[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE CreateVirtualUnwinder(
+ /* [in] */ DWORD nativeThreadID,
+ /* [in] */ ULONG32 contextFlags,
+ /* [in] */ ULONG32 cbContext,
+ /* [size_is][in] */ BYTE initialContext[ ],
+ /* [out] */ ICorDebugVirtualUnwinder **ppUnwinder) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugDataTarget2Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugDataTarget2 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugDataTarget2 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugDataTarget2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetImageFromPointer )(
+ ICorDebugDataTarget2 * This,
+ /* [in] */ CORDB_ADDRESS addr,
+ /* [out] */ CORDB_ADDRESS *pImageBase,
+ /* [out] */ ULONG32 *pSize);
+
+ HRESULT ( STDMETHODCALLTYPE *GetImageLocation )(
+ ICorDebugDataTarget2 * This,
+ /* [in] */ CORDB_ADDRESS baseAddress,
+ /* [in] */ ULONG32 cchName,
+ /* [out] */ ULONG32 *pcchName,
+ /* [length_is][size_is][out] */ WCHAR szName[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetSymbolProviderForImage )(
+ ICorDebugDataTarget2 * This,
+ /* [in] */ CORDB_ADDRESS imageBaseAddress,
+ /* [out] */ ICorDebugSymbolProvider **ppSymProvider);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumerateThreadIDs )(
+ ICorDebugDataTarget2 * This,
+ /* [in] */ ULONG32 cThreadIds,
+ /* [out] */ ULONG32 *pcThreadIds,
+ /* [length_is][size_is][out] */ ULONG32 pThreadIds[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *CreateVirtualUnwinder )(
+ ICorDebugDataTarget2 * This,
+ /* [in] */ DWORD nativeThreadID,
+ /* [in] */ ULONG32 contextFlags,
+ /* [in] */ ULONG32 cbContext,
+ /* [size_is][in] */ BYTE initialContext[ ],
+ /* [out] */ ICorDebugVirtualUnwinder **ppUnwinder);
+
+ END_INTERFACE
+ } ICorDebugDataTarget2Vtbl;
+
+ interface ICorDebugDataTarget2
+ {
+ CONST_VTBL struct ICorDebugDataTarget2Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugDataTarget2_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugDataTarget2_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugDataTarget2_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugDataTarget2_GetImageFromPointer(This,addr,pImageBase,pSize) \
+ ( (This)->lpVtbl -> GetImageFromPointer(This,addr,pImageBase,pSize) )
+
+#define ICorDebugDataTarget2_GetImageLocation(This,baseAddress,cchName,pcchName,szName) \
+ ( (This)->lpVtbl -> GetImageLocation(This,baseAddress,cchName,pcchName,szName) )
+
+#define ICorDebugDataTarget2_GetSymbolProviderForImage(This,imageBaseAddress,ppSymProvider) \
+ ( (This)->lpVtbl -> GetSymbolProviderForImage(This,imageBaseAddress,ppSymProvider) )
+
+#define ICorDebugDataTarget2_EnumerateThreadIDs(This,cThreadIds,pcThreadIds,pThreadIds) \
+ ( (This)->lpVtbl -> EnumerateThreadIDs(This,cThreadIds,pcThreadIds,pThreadIds) )
+
+#define ICorDebugDataTarget2_CreateVirtualUnwinder(This,nativeThreadID,contextFlags,cbContext,initialContext,ppUnwinder) \
+ ( (This)->lpVtbl -> CreateVirtualUnwinder(This,nativeThreadID,contextFlags,cbContext,initialContext,ppUnwinder) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugDataTarget2_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugLoadedModule_INTERFACE_DEFINED__
+#define __ICorDebugLoadedModule_INTERFACE_DEFINED__
+
+/* interface ICorDebugLoadedModule */
+/* [unique][local][uuid][object] */
+
+
+EXTERN_C const IID IID_ICorDebugLoadedModule;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("817F343A-6630-4578-96C5-D11BC0EC5EE2")
+ ICorDebugLoadedModule : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetBaseAddress(
+ /* [out] */ CORDB_ADDRESS *pAddress) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetName(
+ /* [in] */ ULONG32 cchName,
+ /* [out] */ ULONG32 *pcchName,
+ /* [length_is][size_is][out] */ WCHAR szName[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetSize(
+ /* [out] */ ULONG32 *pcBytes) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugLoadedModuleVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugLoadedModule * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugLoadedModule * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugLoadedModule * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetBaseAddress )(
+ ICorDebugLoadedModule * This,
+ /* [out] */ CORDB_ADDRESS *pAddress);
+
+ HRESULT ( STDMETHODCALLTYPE *GetName )(
+ ICorDebugLoadedModule * This,
+ /* [in] */ ULONG32 cchName,
+ /* [out] */ ULONG32 *pcchName,
+ /* [length_is][size_is][out] */ WCHAR szName[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetSize )(
+ ICorDebugLoadedModule * This,
+ /* [out] */ ULONG32 *pcBytes);
+
+ END_INTERFACE
+ } ICorDebugLoadedModuleVtbl;
+
+ interface ICorDebugLoadedModule
+ {
+ CONST_VTBL struct ICorDebugLoadedModuleVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugLoadedModule_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugLoadedModule_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugLoadedModule_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugLoadedModule_GetBaseAddress(This,pAddress) \
+ ( (This)->lpVtbl -> GetBaseAddress(This,pAddress) )
+
+#define ICorDebugLoadedModule_GetName(This,cchName,pcchName,szName) \
+ ( (This)->lpVtbl -> GetName(This,cchName,pcchName,szName) )
+
+#define ICorDebugLoadedModule_GetSize(This,pcBytes) \
+ ( (This)->lpVtbl -> GetSize(This,pcBytes) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugLoadedModule_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugDataTarget3_INTERFACE_DEFINED__
+#define __ICorDebugDataTarget3_INTERFACE_DEFINED__
+
+/* interface ICorDebugDataTarget3 */
+/* [unique][local][uuid][object] */
+
+
+EXTERN_C const IID IID_ICorDebugDataTarget3;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("D05E60C3-848C-4E7D-894E-623320FF6AFA")
+ ICorDebugDataTarget3 : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetLoadedModules(
+ /* [in] */ ULONG32 cRequestedModules,
+ /* [out] */ ULONG32 *pcFetchedModules,
+ /* [length_is][size_is][out] */ ICorDebugLoadedModule *pLoadedModules[ ]) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugDataTarget3Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugDataTarget3 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugDataTarget3 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugDataTarget3 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetLoadedModules )(
+ ICorDebugDataTarget3 * This,
+ /* [in] */ ULONG32 cRequestedModules,
+ /* [out] */ ULONG32 *pcFetchedModules,
+ /* [length_is][size_is][out] */ ICorDebugLoadedModule *pLoadedModules[ ]);
+
+ END_INTERFACE
+ } ICorDebugDataTarget3Vtbl;
+
+ interface ICorDebugDataTarget3
+ {
+ CONST_VTBL struct ICorDebugDataTarget3Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugDataTarget3_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugDataTarget3_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugDataTarget3_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugDataTarget3_GetLoadedModules(This,cRequestedModules,pcFetchedModules,pLoadedModules) \
+ ( (This)->lpVtbl -> GetLoadedModules(This,cRequestedModules,pcFetchedModules,pLoadedModules) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugDataTarget3_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugDataTarget4_INTERFACE_DEFINED__
+#define __ICorDebugDataTarget4_INTERFACE_DEFINED__
+
+/* interface ICorDebugDataTarget4 */
+/* [unique][local][uuid][object] */
+
+
+EXTERN_C const IID IID_ICorDebugDataTarget4;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("E799DC06-E099-4713-BDD9-906D3CC02CF2")
+ ICorDebugDataTarget4 : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE VirtualUnwind(
+ /* [in] */ DWORD threadId,
+ /* [in] */ ULONG32 contextSize,
+ /* [size_is][out][in] */ BYTE *context) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugDataTarget4Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugDataTarget4 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugDataTarget4 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugDataTarget4 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *VirtualUnwind )(
+ ICorDebugDataTarget4 * This,
+ /* [in] */ DWORD threadId,
+ /* [in] */ ULONG32 contextSize,
+ /* [size_is][out][in] */ BYTE *context);
+
+ END_INTERFACE
+ } ICorDebugDataTarget4Vtbl;
+
+ interface ICorDebugDataTarget4
+ {
+ CONST_VTBL struct ICorDebugDataTarget4Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugDataTarget4_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugDataTarget4_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugDataTarget4_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugDataTarget4_VirtualUnwind(This,threadId,contextSize,context) \
+ ( (This)->lpVtbl -> VirtualUnwind(This,threadId,contextSize,context) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugDataTarget4_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugMutableDataTarget_INTERFACE_DEFINED__
+#define __ICorDebugMutableDataTarget_INTERFACE_DEFINED__
+
+/* interface ICorDebugMutableDataTarget */
+/* [unique][local][uuid][object] */
+
+
+EXTERN_C const IID IID_ICorDebugMutableDataTarget;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("A1B8A756-3CB6-4CCB-979F-3DF999673A59")
+ ICorDebugMutableDataTarget : public ICorDebugDataTarget
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE WriteVirtual(
+ /* [in] */ CORDB_ADDRESS address,
+ /* [size_is][in] */ const BYTE *pBuffer,
+ /* [in] */ ULONG32 bytesRequested) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetThreadContext(
+ /* [in] */ DWORD dwThreadID,
+ /* [in] */ ULONG32 contextSize,
+ /* [size_is][in] */ const BYTE *pContext) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ContinueStatusChanged(
+ /* [in] */ DWORD dwThreadId,
+ /* [in] */ CORDB_CONTINUE_STATUS continueStatus) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugMutableDataTargetVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugMutableDataTarget * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugMutableDataTarget * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugMutableDataTarget * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetPlatform )(
+ ICorDebugMutableDataTarget * This,
+ /* [out] */ CorDebugPlatform *pTargetPlatform);
+
+ HRESULT ( STDMETHODCALLTYPE *ReadVirtual )(
+ ICorDebugMutableDataTarget * This,
+ /* [in] */ CORDB_ADDRESS address,
+ /* [length_is][size_is][out] */ BYTE *pBuffer,
+ /* [in] */ ULONG32 bytesRequested,
+ /* [out] */ ULONG32 *pBytesRead);
+
+ HRESULT ( STDMETHODCALLTYPE *GetThreadContext )(
+ ICorDebugMutableDataTarget * This,
+ /* [in] */ DWORD dwThreadID,
+ /* [in] */ ULONG32 contextFlags,
+ /* [in] */ ULONG32 contextSize,
+ /* [size_is][out] */ BYTE *pContext);
+
+ HRESULT ( STDMETHODCALLTYPE *WriteVirtual )(
+ ICorDebugMutableDataTarget * This,
+ /* [in] */ CORDB_ADDRESS address,
+ /* [size_is][in] */ const BYTE *pBuffer,
+ /* [in] */ ULONG32 bytesRequested);
+
+ HRESULT ( STDMETHODCALLTYPE *SetThreadContext )(
+ ICorDebugMutableDataTarget * This,
+ /* [in] */ DWORD dwThreadID,
+ /* [in] */ ULONG32 contextSize,
+ /* [size_is][in] */ const BYTE *pContext);
+
+ HRESULT ( STDMETHODCALLTYPE *ContinueStatusChanged )(
+ ICorDebugMutableDataTarget * This,
+ /* [in] */ DWORD dwThreadId,
+ /* [in] */ CORDB_CONTINUE_STATUS continueStatus);
+
+ END_INTERFACE
+ } ICorDebugMutableDataTargetVtbl;
+
+ interface ICorDebugMutableDataTarget
+ {
+ CONST_VTBL struct ICorDebugMutableDataTargetVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugMutableDataTarget_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugMutableDataTarget_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugMutableDataTarget_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugMutableDataTarget_GetPlatform(This,pTargetPlatform) \
+ ( (This)->lpVtbl -> GetPlatform(This,pTargetPlatform) )
+
+#define ICorDebugMutableDataTarget_ReadVirtual(This,address,pBuffer,bytesRequested,pBytesRead) \
+ ( (This)->lpVtbl -> ReadVirtual(This,address,pBuffer,bytesRequested,pBytesRead) )
+
+#define ICorDebugMutableDataTarget_GetThreadContext(This,dwThreadID,contextFlags,contextSize,pContext) \
+ ( (This)->lpVtbl -> GetThreadContext(This,dwThreadID,contextFlags,contextSize,pContext) )
+
+
+#define ICorDebugMutableDataTarget_WriteVirtual(This,address,pBuffer,bytesRequested) \
+ ( (This)->lpVtbl -> WriteVirtual(This,address,pBuffer,bytesRequested) )
+
+#define ICorDebugMutableDataTarget_SetThreadContext(This,dwThreadID,contextSize,pContext) \
+ ( (This)->lpVtbl -> SetThreadContext(This,dwThreadID,contextSize,pContext) )
+
+#define ICorDebugMutableDataTarget_ContinueStatusChanged(This,dwThreadId,continueStatus) \
+ ( (This)->lpVtbl -> ContinueStatusChanged(This,dwThreadId,continueStatus) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugMutableDataTarget_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugMetaDataLocator_INTERFACE_DEFINED__
+#define __ICorDebugMetaDataLocator_INTERFACE_DEFINED__
+
+/* interface ICorDebugMetaDataLocator */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugMetaDataLocator;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("7cef8ba9-2ef7-42bf-973f-4171474f87d9")
+ ICorDebugMetaDataLocator : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetMetaData(
+ /* [in] */ LPCWSTR wszImagePath,
+ /* [in] */ DWORD dwImageTimeStamp,
+ /* [in] */ DWORD dwImageSize,
+ /* [in] */ ULONG32 cchPathBuffer,
+ /* [annotation][out] */
+ _Out_ ULONG32 *pcchPathBuffer,
+ /* [annotation][length_is][size_is][out] */
+ _Out_writes_to_(cchPathBuffer, *pcchPathBuffer) WCHAR wszPathBuffer[ ]) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugMetaDataLocatorVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugMetaDataLocator * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugMetaDataLocator * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugMetaDataLocator * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetMetaData )(
+ ICorDebugMetaDataLocator * This,
+ /* [in] */ LPCWSTR wszImagePath,
+ /* [in] */ DWORD dwImageTimeStamp,
+ /* [in] */ DWORD dwImageSize,
+ /* [in] */ ULONG32 cchPathBuffer,
+ /* [annotation][out] */
+ _Out_ ULONG32 *pcchPathBuffer,
+ /* [annotation][length_is][size_is][out] */
+ _Out_writes_to_(cchPathBuffer, *pcchPathBuffer) WCHAR wszPathBuffer[ ]);
+
+ END_INTERFACE
+ } ICorDebugMetaDataLocatorVtbl;
+
+ interface ICorDebugMetaDataLocator
+ {
+ CONST_VTBL struct ICorDebugMetaDataLocatorVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugMetaDataLocator_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugMetaDataLocator_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugMetaDataLocator_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugMetaDataLocator_GetMetaData(This,wszImagePath,dwImageTimeStamp,dwImageSize,cchPathBuffer,pcchPathBuffer,wszPathBuffer) \
+ ( (This)->lpVtbl -> GetMetaData(This,wszImagePath,dwImageTimeStamp,dwImageSize,cchPathBuffer,pcchPathBuffer,wszPathBuffer) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugMetaDataLocator_INTERFACE_DEFINED__ */
+
+
+/* interface __MIDL_itf_cordebug_0000_0015 */
+/* [local] */
+
+#pragma warning(push)
+#pragma warning(disable:28718)
+
+
+extern RPC_IF_HANDLE __MIDL_itf_cordebug_0000_0015_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_cordebug_0000_0015_v0_0_s_ifspec;
+
+#ifndef __ICorDebugManagedCallback_INTERFACE_DEFINED__
+#define __ICorDebugManagedCallback_INTERFACE_DEFINED__
+
+/* interface ICorDebugManagedCallback */
+/* [unique][uuid][local][object] */
+
+typedef
+enum CorDebugStepReason
+ {
+ STEP_NORMAL = 0,
+ STEP_RETURN = ( STEP_NORMAL + 1 ) ,
+ STEP_CALL = ( STEP_RETURN + 1 ) ,
+ STEP_EXCEPTION_FILTER = ( STEP_CALL + 1 ) ,
+ STEP_EXCEPTION_HANDLER = ( STEP_EXCEPTION_FILTER + 1 ) ,
+ STEP_INTERCEPT = ( STEP_EXCEPTION_HANDLER + 1 ) ,
+ STEP_EXIT = ( STEP_INTERCEPT + 1 )
+ } CorDebugStepReason;
+
+typedef
+enum LoggingLevelEnum
+ {
+ LTraceLevel0 = 0,
+ LTraceLevel1 = ( LTraceLevel0 + 1 ) ,
+ LTraceLevel2 = ( LTraceLevel1 + 1 ) ,
+ LTraceLevel3 = ( LTraceLevel2 + 1 ) ,
+ LTraceLevel4 = ( LTraceLevel3 + 1 ) ,
+ LStatusLevel0 = 20,
+ LStatusLevel1 = ( LStatusLevel0 + 1 ) ,
+ LStatusLevel2 = ( LStatusLevel1 + 1 ) ,
+ LStatusLevel3 = ( LStatusLevel2 + 1 ) ,
+ LStatusLevel4 = ( LStatusLevel3 + 1 ) ,
+ LWarningLevel = 40,
+ LErrorLevel = 50,
+ LPanicLevel = 100
+ } LoggingLevelEnum;
+
+typedef
+enum LogSwitchCallReason
+ {
+ SWITCH_CREATE = 0,
+ SWITCH_MODIFY = ( SWITCH_CREATE + 1 ) ,
+ SWITCH_DELETE = ( SWITCH_MODIFY + 1 )
+ } LogSwitchCallReason;
+
+
+EXTERN_C const IID IID_ICorDebugManagedCallback;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("3d6f5f60-7538-11d3-8d5b-00104b35e7ef")
+ ICorDebugManagedCallback : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE Breakpoint(
+ /* [in] */ ICorDebugAppDomain *pAppDomain,
+ /* [in] */ ICorDebugThread *pThread,
+ /* [in] */ ICorDebugBreakpoint *pBreakpoint) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StepComplete(
+ /* [in] */ ICorDebugAppDomain *pAppDomain,
+ /* [in] */ ICorDebugThread *pThread,
+ /* [in] */ ICorDebugStepper *pStepper,
+ /* [in] */ CorDebugStepReason reason) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Break(
+ /* [in] */ ICorDebugAppDomain *pAppDomain,
+ /* [in] */ ICorDebugThread *thread) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Exception(
+ /* [in] */ ICorDebugAppDomain *pAppDomain,
+ /* [in] */ ICorDebugThread *pThread,
+ /* [in] */ BOOL unhandled) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EvalComplete(
+ /* [in] */ ICorDebugAppDomain *pAppDomain,
+ /* [in] */ ICorDebugThread *pThread,
+ /* [in] */ ICorDebugEval *pEval) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EvalException(
+ /* [in] */ ICorDebugAppDomain *pAppDomain,
+ /* [in] */ ICorDebugThread *pThread,
+ /* [in] */ ICorDebugEval *pEval) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE CreateProcess(
+ /* [in] */ ICorDebugProcess *pProcess) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ExitProcess(
+ /* [in] */ ICorDebugProcess *pProcess) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE CreateThread(
+ /* [in] */ ICorDebugAppDomain *pAppDomain,
+ /* [in] */ ICorDebugThread *thread) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ExitThread(
+ /* [in] */ ICorDebugAppDomain *pAppDomain,
+ /* [in] */ ICorDebugThread *thread) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE LoadModule(
+ /* [in] */ ICorDebugAppDomain *pAppDomain,
+ /* [in] */ ICorDebugModule *pModule) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE UnloadModule(
+ /* [in] */ ICorDebugAppDomain *pAppDomain,
+ /* [in] */ ICorDebugModule *pModule) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE LoadClass(
+ /* [in] */ ICorDebugAppDomain *pAppDomain,
+ /* [in] */ ICorDebugClass *c) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE UnloadClass(
+ /* [in] */ ICorDebugAppDomain *pAppDomain,
+ /* [in] */ ICorDebugClass *c) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE DebuggerError(
+ /* [in] */ ICorDebugProcess *pProcess,
+ /* [in] */ HRESULT errorHR,
+ /* [in] */ DWORD errorCode) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE LogMessage(
+ /* [in] */ ICorDebugAppDomain *pAppDomain,
+ /* [in] */ ICorDebugThread *pThread,
+ /* [in] */ LONG lLevel,
+ /* [in] */ WCHAR *pLogSwitchName,
+ /* [in] */ WCHAR *pMessage) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE LogSwitch(
+ /* [in] */ ICorDebugAppDomain *pAppDomain,
+ /* [in] */ ICorDebugThread *pThread,
+ /* [in] */ LONG lLevel,
+ /* [in] */ ULONG ulReason,
+ /* [in] */ WCHAR *pLogSwitchName,
+ /* [in] */ WCHAR *pParentName) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE CreateAppDomain(
+ /* [in] */ ICorDebugProcess *pProcess,
+ /* [in] */ ICorDebugAppDomain *pAppDomain) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ExitAppDomain(
+ /* [in] */ ICorDebugProcess *pProcess,
+ /* [in] */ ICorDebugAppDomain *pAppDomain) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE LoadAssembly(
+ /* [in] */ ICorDebugAppDomain *pAppDomain,
+ /* [in] */ ICorDebugAssembly *pAssembly) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE UnloadAssembly(
+ /* [in] */ ICorDebugAppDomain *pAppDomain,
+ /* [in] */ ICorDebugAssembly *pAssembly) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ControlCTrap(
+ /* [in] */ ICorDebugProcess *pProcess) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE NameChange(
+ /* [in] */ ICorDebugAppDomain *pAppDomain,
+ /* [in] */ ICorDebugThread *pThread) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE UpdateModuleSymbols(
+ /* [in] */ ICorDebugAppDomain *pAppDomain,
+ /* [in] */ ICorDebugModule *pModule,
+ /* [in] */ IStream *pSymbolStream) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EditAndContinueRemap(
+ /* [in] */ ICorDebugAppDomain *pAppDomain,
+ /* [in] */ ICorDebugThread *pThread,
+ /* [in] */ ICorDebugFunction *pFunction,
+ /* [in] */ BOOL fAccurate) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE BreakpointSetError(
+ /* [in] */ ICorDebugAppDomain *pAppDomain,
+ /* [in] */ ICorDebugThread *pThread,
+ /* [in] */ ICorDebugBreakpoint *pBreakpoint,
+ /* [in] */ DWORD dwError) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugManagedCallbackVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugManagedCallback * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugManagedCallback * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugManagedCallback * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Breakpoint )(
+ ICorDebugManagedCallback * This,
+ /* [in] */ ICorDebugAppDomain *pAppDomain,
+ /* [in] */ ICorDebugThread *pThread,
+ /* [in] */ ICorDebugBreakpoint *pBreakpoint);
+
+ HRESULT ( STDMETHODCALLTYPE *StepComplete )(
+ ICorDebugManagedCallback * This,
+ /* [in] */ ICorDebugAppDomain *pAppDomain,
+ /* [in] */ ICorDebugThread *pThread,
+ /* [in] */ ICorDebugStepper *pStepper,
+ /* [in] */ CorDebugStepReason reason);
+
+ HRESULT ( STDMETHODCALLTYPE *Break )(
+ ICorDebugManagedCallback * This,
+ /* [in] */ ICorDebugAppDomain *pAppDomain,
+ /* [in] */ ICorDebugThread *thread);
+
+ HRESULT ( STDMETHODCALLTYPE *Exception )(
+ ICorDebugManagedCallback * This,
+ /* [in] */ ICorDebugAppDomain *pAppDomain,
+ /* [in] */ ICorDebugThread *pThread,
+ /* [in] */ BOOL unhandled);
+
+ HRESULT ( STDMETHODCALLTYPE *EvalComplete )(
+ ICorDebugManagedCallback * This,
+ /* [in] */ ICorDebugAppDomain *pAppDomain,
+ /* [in] */ ICorDebugThread *pThread,
+ /* [in] */ ICorDebugEval *pEval);
+
+ HRESULT ( STDMETHODCALLTYPE *EvalException )(
+ ICorDebugManagedCallback * This,
+ /* [in] */ ICorDebugAppDomain *pAppDomain,
+ /* [in] */ ICorDebugThread *pThread,
+ /* [in] */ ICorDebugEval *pEval);
+
+ HRESULT ( STDMETHODCALLTYPE *CreateProcess )(
+ ICorDebugManagedCallback * This,
+ /* [in] */ ICorDebugProcess *pProcess);
+
+ HRESULT ( STDMETHODCALLTYPE *ExitProcess )(
+ ICorDebugManagedCallback * This,
+ /* [in] */ ICorDebugProcess *pProcess);
+
+ HRESULT ( STDMETHODCALLTYPE *CreateThread )(
+ ICorDebugManagedCallback * This,
+ /* [in] */ ICorDebugAppDomain *pAppDomain,
+ /* [in] */ ICorDebugThread *thread);
+
+ HRESULT ( STDMETHODCALLTYPE *ExitThread )(
+ ICorDebugManagedCallback * This,
+ /* [in] */ ICorDebugAppDomain *pAppDomain,
+ /* [in] */ ICorDebugThread *thread);
+
+ HRESULT ( STDMETHODCALLTYPE *LoadModule )(
+ ICorDebugManagedCallback * This,
+ /* [in] */ ICorDebugAppDomain *pAppDomain,
+ /* [in] */ ICorDebugModule *pModule);
+
+ HRESULT ( STDMETHODCALLTYPE *UnloadModule )(
+ ICorDebugManagedCallback * This,
+ /* [in] */ ICorDebugAppDomain *pAppDomain,
+ /* [in] */ ICorDebugModule *pModule);
+
+ HRESULT ( STDMETHODCALLTYPE *LoadClass )(
+ ICorDebugManagedCallback * This,
+ /* [in] */ ICorDebugAppDomain *pAppDomain,
+ /* [in] */ ICorDebugClass *c);
+
+ HRESULT ( STDMETHODCALLTYPE *UnloadClass )(
+ ICorDebugManagedCallback * This,
+ /* [in] */ ICorDebugAppDomain *pAppDomain,
+ /* [in] */ ICorDebugClass *c);
+
+ HRESULT ( STDMETHODCALLTYPE *DebuggerError )(
+ ICorDebugManagedCallback * This,
+ /* [in] */ ICorDebugProcess *pProcess,
+ /* [in] */ HRESULT errorHR,
+ /* [in] */ DWORD errorCode);
+
+ HRESULT ( STDMETHODCALLTYPE *LogMessage )(
+ ICorDebugManagedCallback * This,
+ /* [in] */ ICorDebugAppDomain *pAppDomain,
+ /* [in] */ ICorDebugThread *pThread,
+ /* [in] */ LONG lLevel,
+ /* [in] */ WCHAR *pLogSwitchName,
+ /* [in] */ WCHAR *pMessage);
+
+ HRESULT ( STDMETHODCALLTYPE *LogSwitch )(
+ ICorDebugManagedCallback * This,
+ /* [in] */ ICorDebugAppDomain *pAppDomain,
+ /* [in] */ ICorDebugThread *pThread,
+ /* [in] */ LONG lLevel,
+ /* [in] */ ULONG ulReason,
+ /* [in] */ WCHAR *pLogSwitchName,
+ /* [in] */ WCHAR *pParentName);
+
+ HRESULT ( STDMETHODCALLTYPE *CreateAppDomain )(
+ ICorDebugManagedCallback * This,
+ /* [in] */ ICorDebugProcess *pProcess,
+ /* [in] */ ICorDebugAppDomain *pAppDomain);
+
+ HRESULT ( STDMETHODCALLTYPE *ExitAppDomain )(
+ ICorDebugManagedCallback * This,
+ /* [in] */ ICorDebugProcess *pProcess,
+ /* [in] */ ICorDebugAppDomain *pAppDomain);
+
+ HRESULT ( STDMETHODCALLTYPE *LoadAssembly )(
+ ICorDebugManagedCallback * This,
+ /* [in] */ ICorDebugAppDomain *pAppDomain,
+ /* [in] */ ICorDebugAssembly *pAssembly);
+
+ HRESULT ( STDMETHODCALLTYPE *UnloadAssembly )(
+ ICorDebugManagedCallback * This,
+ /* [in] */ ICorDebugAppDomain *pAppDomain,
+ /* [in] */ ICorDebugAssembly *pAssembly);
+
+ HRESULT ( STDMETHODCALLTYPE *ControlCTrap )(
+ ICorDebugManagedCallback * This,
+ /* [in] */ ICorDebugProcess *pProcess);
+
+ HRESULT ( STDMETHODCALLTYPE *NameChange )(
+ ICorDebugManagedCallback * This,
+ /* [in] */ ICorDebugAppDomain *pAppDomain,
+ /* [in] */ ICorDebugThread *pThread);
+
+ HRESULT ( STDMETHODCALLTYPE *UpdateModuleSymbols )(
+ ICorDebugManagedCallback * This,
+ /* [in] */ ICorDebugAppDomain *pAppDomain,
+ /* [in] */ ICorDebugModule *pModule,
+ /* [in] */ IStream *pSymbolStream);
+
+ HRESULT ( STDMETHODCALLTYPE *EditAndContinueRemap )(
+ ICorDebugManagedCallback * This,
+ /* [in] */ ICorDebugAppDomain *pAppDomain,
+ /* [in] */ ICorDebugThread *pThread,
+ /* [in] */ ICorDebugFunction *pFunction,
+ /* [in] */ BOOL fAccurate);
+
+ HRESULT ( STDMETHODCALLTYPE *BreakpointSetError )(
+ ICorDebugManagedCallback * This,
+ /* [in] */ ICorDebugAppDomain *pAppDomain,
+ /* [in] */ ICorDebugThread *pThread,
+ /* [in] */ ICorDebugBreakpoint *pBreakpoint,
+ /* [in] */ DWORD dwError);
+
+ END_INTERFACE
+ } ICorDebugManagedCallbackVtbl;
+
+ interface ICorDebugManagedCallback
+ {
+ CONST_VTBL struct ICorDebugManagedCallbackVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugManagedCallback_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugManagedCallback_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugManagedCallback_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugManagedCallback_Breakpoint(This,pAppDomain,pThread,pBreakpoint) \
+ ( (This)->lpVtbl -> Breakpoint(This,pAppDomain,pThread,pBreakpoint) )
+
+#define ICorDebugManagedCallback_StepComplete(This,pAppDomain,pThread,pStepper,reason) \
+ ( (This)->lpVtbl -> StepComplete(This,pAppDomain,pThread,pStepper,reason) )
+
+#define ICorDebugManagedCallback_Break(This,pAppDomain,thread) \
+ ( (This)->lpVtbl -> Break(This,pAppDomain,thread) )
+
+#define ICorDebugManagedCallback_Exception(This,pAppDomain,pThread,unhandled) \
+ ( (This)->lpVtbl -> Exception(This,pAppDomain,pThread,unhandled) )
+
+#define ICorDebugManagedCallback_EvalComplete(This,pAppDomain,pThread,pEval) \
+ ( (This)->lpVtbl -> EvalComplete(This,pAppDomain,pThread,pEval) )
+
+#define ICorDebugManagedCallback_EvalException(This,pAppDomain,pThread,pEval) \
+ ( (This)->lpVtbl -> EvalException(This,pAppDomain,pThread,pEval) )
+
+#define ICorDebugManagedCallback_CreateProcess(This,pProcess) \
+ ( (This)->lpVtbl -> CreateProcess(This,pProcess) )
+
+#define ICorDebugManagedCallback_ExitProcess(This,pProcess) \
+ ( (This)->lpVtbl -> ExitProcess(This,pProcess) )
+
+#define ICorDebugManagedCallback_CreateThread(This,pAppDomain,thread) \
+ ( (This)->lpVtbl -> CreateThread(This,pAppDomain,thread) )
+
+#define ICorDebugManagedCallback_ExitThread(This,pAppDomain,thread) \
+ ( (This)->lpVtbl -> ExitThread(This,pAppDomain,thread) )
+
+#define ICorDebugManagedCallback_LoadModule(This,pAppDomain,pModule) \
+ ( (This)->lpVtbl -> LoadModule(This,pAppDomain,pModule) )
+
+#define ICorDebugManagedCallback_UnloadModule(This,pAppDomain,pModule) \
+ ( (This)->lpVtbl -> UnloadModule(This,pAppDomain,pModule) )
+
+#define ICorDebugManagedCallback_LoadClass(This,pAppDomain,c) \
+ ( (This)->lpVtbl -> LoadClass(This,pAppDomain,c) )
+
+#define ICorDebugManagedCallback_UnloadClass(This,pAppDomain,c) \
+ ( (This)->lpVtbl -> UnloadClass(This,pAppDomain,c) )
+
+#define ICorDebugManagedCallback_DebuggerError(This,pProcess,errorHR,errorCode) \
+ ( (This)->lpVtbl -> DebuggerError(This,pProcess,errorHR,errorCode) )
+
+#define ICorDebugManagedCallback_LogMessage(This,pAppDomain,pThread,lLevel,pLogSwitchName,pMessage) \
+ ( (This)->lpVtbl -> LogMessage(This,pAppDomain,pThread,lLevel,pLogSwitchName,pMessage) )
+
+#define ICorDebugManagedCallback_LogSwitch(This,pAppDomain,pThread,lLevel,ulReason,pLogSwitchName,pParentName) \
+ ( (This)->lpVtbl -> LogSwitch(This,pAppDomain,pThread,lLevel,ulReason,pLogSwitchName,pParentName) )
+
+#define ICorDebugManagedCallback_CreateAppDomain(This,pProcess,pAppDomain) \
+ ( (This)->lpVtbl -> CreateAppDomain(This,pProcess,pAppDomain) )
+
+#define ICorDebugManagedCallback_ExitAppDomain(This,pProcess,pAppDomain) \
+ ( (This)->lpVtbl -> ExitAppDomain(This,pProcess,pAppDomain) )
+
+#define ICorDebugManagedCallback_LoadAssembly(This,pAppDomain,pAssembly) \
+ ( (This)->lpVtbl -> LoadAssembly(This,pAppDomain,pAssembly) )
+
+#define ICorDebugManagedCallback_UnloadAssembly(This,pAppDomain,pAssembly) \
+ ( (This)->lpVtbl -> UnloadAssembly(This,pAppDomain,pAssembly) )
+
+#define ICorDebugManagedCallback_ControlCTrap(This,pProcess) \
+ ( (This)->lpVtbl -> ControlCTrap(This,pProcess) )
+
+#define ICorDebugManagedCallback_NameChange(This,pAppDomain,pThread) \
+ ( (This)->lpVtbl -> NameChange(This,pAppDomain,pThread) )
+
+#define ICorDebugManagedCallback_UpdateModuleSymbols(This,pAppDomain,pModule,pSymbolStream) \
+ ( (This)->lpVtbl -> UpdateModuleSymbols(This,pAppDomain,pModule,pSymbolStream) )
+
+#define ICorDebugManagedCallback_EditAndContinueRemap(This,pAppDomain,pThread,pFunction,fAccurate) \
+ ( (This)->lpVtbl -> EditAndContinueRemap(This,pAppDomain,pThread,pFunction,fAccurate) )
+
+#define ICorDebugManagedCallback_BreakpointSetError(This,pAppDomain,pThread,pBreakpoint,dwError) \
+ ( (This)->lpVtbl -> BreakpointSetError(This,pAppDomain,pThread,pBreakpoint,dwError) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugManagedCallback_INTERFACE_DEFINED__ */
+
+
+/* interface __MIDL_itf_cordebug_0000_0016 */
+/* [local] */
+
+#pragma warning(pop)
+#pragma warning(push)
+
+
+extern RPC_IF_HANDLE __MIDL_itf_cordebug_0000_0016_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_cordebug_0000_0016_v0_0_s_ifspec;
+
+#ifndef __ICorDebugManagedCallback3_INTERFACE_DEFINED__
+#define __ICorDebugManagedCallback3_INTERFACE_DEFINED__
+
+/* interface ICorDebugManagedCallback3 */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugManagedCallback3;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("264EA0FC-2591-49AA-868E-835E6515323F")
+ ICorDebugManagedCallback3 : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE CustomNotification(
+ /* [in] */ ICorDebugThread *pThread,
+ /* [in] */ ICorDebugAppDomain *pAppDomain) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugManagedCallback3Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugManagedCallback3 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugManagedCallback3 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugManagedCallback3 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *CustomNotification )(
+ ICorDebugManagedCallback3 * This,
+ /* [in] */ ICorDebugThread *pThread,
+ /* [in] */ ICorDebugAppDomain *pAppDomain);
+
+ END_INTERFACE
+ } ICorDebugManagedCallback3Vtbl;
+
+ interface ICorDebugManagedCallback3
+ {
+ CONST_VTBL struct ICorDebugManagedCallback3Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugManagedCallback3_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugManagedCallback3_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugManagedCallback3_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugManagedCallback3_CustomNotification(This,pThread,pAppDomain) \
+ ( (This)->lpVtbl -> CustomNotification(This,pThread,pAppDomain) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugManagedCallback3_INTERFACE_DEFINED__ */
+
+
+/* interface __MIDL_itf_cordebug_0000_0017 */
+/* [local] */
+
+#pragma warning(disable:28718)
+
+
+extern RPC_IF_HANDLE __MIDL_itf_cordebug_0000_0017_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_cordebug_0000_0017_v0_0_s_ifspec;
+
+#ifndef __ICorDebugManagedCallback2_INTERFACE_DEFINED__
+#define __ICorDebugManagedCallback2_INTERFACE_DEFINED__
+
+/* interface ICorDebugManagedCallback2 */
+/* [unique][uuid][local][object] */
+
+typedef
+enum CorDebugExceptionCallbackType
+ {
+ DEBUG_EXCEPTION_FIRST_CHANCE = 1,
+ DEBUG_EXCEPTION_USER_FIRST_CHANCE = 2,
+ DEBUG_EXCEPTION_CATCH_HANDLER_FOUND = 3,
+ DEBUG_EXCEPTION_UNHANDLED = 4
+ } CorDebugExceptionCallbackType;
+
+typedef
+enum CorDebugExceptionFlags
+ {
+ DEBUG_EXCEPTION_NONE = 0,
+ DEBUG_EXCEPTION_CAN_BE_INTERCEPTED = 0x1
+ } CorDebugExceptionFlags;
+
+typedef
+enum CorDebugExceptionUnwindCallbackType
+ {
+ DEBUG_EXCEPTION_UNWIND_BEGIN = 1,
+ DEBUG_EXCEPTION_INTERCEPTED = 2
+ } CorDebugExceptionUnwindCallbackType;
+
+
+EXTERN_C const IID IID_ICorDebugManagedCallback2;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("250E5EEA-DB5C-4C76-B6F3-8C46F12E3203")
+ ICorDebugManagedCallback2 : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE FunctionRemapOpportunity(
+ /* [in] */ ICorDebugAppDomain *pAppDomain,
+ /* [in] */ ICorDebugThread *pThread,
+ /* [in] */ ICorDebugFunction *pOldFunction,
+ /* [in] */ ICorDebugFunction *pNewFunction,
+ /* [in] */ ULONG32 oldILOffset) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE CreateConnection(
+ /* [in] */ ICorDebugProcess *pProcess,
+ /* [in] */ CONNID dwConnectionId,
+ /* [in] */ WCHAR *pConnName) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ChangeConnection(
+ /* [in] */ ICorDebugProcess *pProcess,
+ /* [in] */ CONNID dwConnectionId) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE DestroyConnection(
+ /* [in] */ ICorDebugProcess *pProcess,
+ /* [in] */ CONNID dwConnectionId) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Exception(
+ /* [in] */ ICorDebugAppDomain *pAppDomain,
+ /* [in] */ ICorDebugThread *pThread,
+ /* [in] */ ICorDebugFrame *pFrame,
+ /* [in] */ ULONG32 nOffset,
+ /* [in] */ CorDebugExceptionCallbackType dwEventType,
+ /* [in] */ DWORD dwFlags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ExceptionUnwind(
+ /* [in] */ ICorDebugAppDomain *pAppDomain,
+ /* [in] */ ICorDebugThread *pThread,
+ /* [in] */ CorDebugExceptionUnwindCallbackType dwEventType,
+ /* [in] */ DWORD dwFlags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE FunctionRemapComplete(
+ /* [in] */ ICorDebugAppDomain *pAppDomain,
+ /* [in] */ ICorDebugThread *pThread,
+ /* [in] */ ICorDebugFunction *pFunction) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE MDANotification(
+ /* [in] */ ICorDebugController *pController,
+ /* [in] */ ICorDebugThread *pThread,
+ /* [in] */ ICorDebugMDA *pMDA) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugManagedCallback2Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugManagedCallback2 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugManagedCallback2 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugManagedCallback2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *FunctionRemapOpportunity )(
+ ICorDebugManagedCallback2 * This,
+ /* [in] */ ICorDebugAppDomain *pAppDomain,
+ /* [in] */ ICorDebugThread *pThread,
+ /* [in] */ ICorDebugFunction *pOldFunction,
+ /* [in] */ ICorDebugFunction *pNewFunction,
+ /* [in] */ ULONG32 oldILOffset);
+
+ HRESULT ( STDMETHODCALLTYPE *CreateConnection )(
+ ICorDebugManagedCallback2 * This,
+ /* [in] */ ICorDebugProcess *pProcess,
+ /* [in] */ CONNID dwConnectionId,
+ /* [in] */ WCHAR *pConnName);
+
+ HRESULT ( STDMETHODCALLTYPE *ChangeConnection )(
+ ICorDebugManagedCallback2 * This,
+ /* [in] */ ICorDebugProcess *pProcess,
+ /* [in] */ CONNID dwConnectionId);
+
+ HRESULT ( STDMETHODCALLTYPE *DestroyConnection )(
+ ICorDebugManagedCallback2 * This,
+ /* [in] */ ICorDebugProcess *pProcess,
+ /* [in] */ CONNID dwConnectionId);
+
+ HRESULT ( STDMETHODCALLTYPE *Exception )(
+ ICorDebugManagedCallback2 * This,
+ /* [in] */ ICorDebugAppDomain *pAppDomain,
+ /* [in] */ ICorDebugThread *pThread,
+ /* [in] */ ICorDebugFrame *pFrame,
+ /* [in] */ ULONG32 nOffset,
+ /* [in] */ CorDebugExceptionCallbackType dwEventType,
+ /* [in] */ DWORD dwFlags);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionUnwind )(
+ ICorDebugManagedCallback2 * This,
+ /* [in] */ ICorDebugAppDomain *pAppDomain,
+ /* [in] */ ICorDebugThread *pThread,
+ /* [in] */ CorDebugExceptionUnwindCallbackType dwEventType,
+ /* [in] */ DWORD dwFlags);
+
+ HRESULT ( STDMETHODCALLTYPE *FunctionRemapComplete )(
+ ICorDebugManagedCallback2 * This,
+ /* [in] */ ICorDebugAppDomain *pAppDomain,
+ /* [in] */ ICorDebugThread *pThread,
+ /* [in] */ ICorDebugFunction *pFunction);
+
+ HRESULT ( STDMETHODCALLTYPE *MDANotification )(
+ ICorDebugManagedCallback2 * This,
+ /* [in] */ ICorDebugController *pController,
+ /* [in] */ ICorDebugThread *pThread,
+ /* [in] */ ICorDebugMDA *pMDA);
+
+ END_INTERFACE
+ } ICorDebugManagedCallback2Vtbl;
+
+ interface ICorDebugManagedCallback2
+ {
+ CONST_VTBL struct ICorDebugManagedCallback2Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugManagedCallback2_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugManagedCallback2_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugManagedCallback2_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugManagedCallback2_FunctionRemapOpportunity(This,pAppDomain,pThread,pOldFunction,pNewFunction,oldILOffset) \
+ ( (This)->lpVtbl -> FunctionRemapOpportunity(This,pAppDomain,pThread,pOldFunction,pNewFunction,oldILOffset) )
+
+#define ICorDebugManagedCallback2_CreateConnection(This,pProcess,dwConnectionId,pConnName) \
+ ( (This)->lpVtbl -> CreateConnection(This,pProcess,dwConnectionId,pConnName) )
+
+#define ICorDebugManagedCallback2_ChangeConnection(This,pProcess,dwConnectionId) \
+ ( (This)->lpVtbl -> ChangeConnection(This,pProcess,dwConnectionId) )
+
+#define ICorDebugManagedCallback2_DestroyConnection(This,pProcess,dwConnectionId) \
+ ( (This)->lpVtbl -> DestroyConnection(This,pProcess,dwConnectionId) )
+
+#define ICorDebugManagedCallback2_Exception(This,pAppDomain,pThread,pFrame,nOffset,dwEventType,dwFlags) \
+ ( (This)->lpVtbl -> Exception(This,pAppDomain,pThread,pFrame,nOffset,dwEventType,dwFlags) )
+
+#define ICorDebugManagedCallback2_ExceptionUnwind(This,pAppDomain,pThread,dwEventType,dwFlags) \
+ ( (This)->lpVtbl -> ExceptionUnwind(This,pAppDomain,pThread,dwEventType,dwFlags) )
+
+#define ICorDebugManagedCallback2_FunctionRemapComplete(This,pAppDomain,pThread,pFunction) \
+ ( (This)->lpVtbl -> FunctionRemapComplete(This,pAppDomain,pThread,pFunction) )
+
+#define ICorDebugManagedCallback2_MDANotification(This,pController,pThread,pMDA) \
+ ( (This)->lpVtbl -> MDANotification(This,pController,pThread,pMDA) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugManagedCallback2_INTERFACE_DEFINED__ */
+
+
+/* interface __MIDL_itf_cordebug_0000_0018 */
+/* [local] */
+
+#pragma warning(pop)
+
+
+extern RPC_IF_HANDLE __MIDL_itf_cordebug_0000_0018_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_cordebug_0000_0018_v0_0_s_ifspec;
+
+#ifndef __ICorDebugUnmanagedCallback_INTERFACE_DEFINED__
+#define __ICorDebugUnmanagedCallback_INTERFACE_DEFINED__
+
+/* interface ICorDebugUnmanagedCallback */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugUnmanagedCallback;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("5263E909-8CB5-11d3-BD2F-0000F80849BD")
+ ICorDebugUnmanagedCallback : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE DebugEvent(
+ /* [in] */ LPDEBUG_EVENT pDebugEvent,
+ /* [in] */ BOOL fOutOfBand) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugUnmanagedCallbackVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugUnmanagedCallback * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugUnmanagedCallback * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugUnmanagedCallback * This);
+
+ HRESULT ( STDMETHODCALLTYPE *DebugEvent )(
+ ICorDebugUnmanagedCallback * This,
+ /* [in] */ LPDEBUG_EVENT pDebugEvent,
+ /* [in] */ BOOL fOutOfBand);
+
+ END_INTERFACE
+ } ICorDebugUnmanagedCallbackVtbl;
+
+ interface ICorDebugUnmanagedCallback
+ {
+ CONST_VTBL struct ICorDebugUnmanagedCallbackVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugUnmanagedCallback_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugUnmanagedCallback_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugUnmanagedCallback_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugUnmanagedCallback_DebugEvent(This,pDebugEvent,fOutOfBand) \
+ ( (This)->lpVtbl -> DebugEvent(This,pDebugEvent,fOutOfBand) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugUnmanagedCallback_INTERFACE_DEFINED__ */
+
+
+/* interface __MIDL_itf_cordebug_0000_0019 */
+/* [local] */
+
+typedef
+enum CorDebugCreateProcessFlags
+ {
+ DEBUG_NO_SPECIAL_OPTIONS = 0
+ } CorDebugCreateProcessFlags;
+
+typedef
+enum CorDebugHandleType
+ {
+ HANDLE_STRONG = 1,
+ HANDLE_WEAK_TRACK_RESURRECTION = 2
+ } CorDebugHandleType;
+
+#pragma warning(push)
+#pragma warning(disable:28718)
+
+
+extern RPC_IF_HANDLE __MIDL_itf_cordebug_0000_0019_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_cordebug_0000_0019_v0_0_s_ifspec;
+
+#ifndef __ICorDebug_INTERFACE_DEFINED__
+#define __ICorDebug_INTERFACE_DEFINED__
+
+/* interface ICorDebug */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebug;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("3d6f5f61-7538-11d3-8d5b-00104b35e7ef")
+ ICorDebug : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE Initialize( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Terminate( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetManagedHandler(
+ /* [in] */ ICorDebugManagedCallback *pCallback) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetUnmanagedHandler(
+ /* [in] */ ICorDebugUnmanagedCallback *pCallback) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE CreateProcess(
+ /* [in] */ LPCWSTR lpApplicationName,
+ /* [in] */ LPWSTR lpCommandLine,
+ /* [in] */ LPSECURITY_ATTRIBUTES lpProcessAttributes,
+ /* [in] */ LPSECURITY_ATTRIBUTES lpThreadAttributes,
+ /* [in] */ BOOL bInheritHandles,
+ /* [in] */ DWORD dwCreationFlags,
+ /* [in] */ PVOID lpEnvironment,
+ /* [in] */ LPCWSTR lpCurrentDirectory,
+ /* [in] */ LPSTARTUPINFOW lpStartupInfo,
+ /* [in] */ LPPROCESS_INFORMATION lpProcessInformation,
+ /* [in] */ CorDebugCreateProcessFlags debuggingFlags,
+ /* [out] */ ICorDebugProcess **ppProcess) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE DebugActiveProcess(
+ /* [in] */ DWORD id,
+ /* [in] */ BOOL win32Attach,
+ /* [out] */ ICorDebugProcess **ppProcess) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnumerateProcesses(
+ /* [out] */ ICorDebugProcessEnum **ppProcess) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetProcess(
+ /* [in] */ DWORD dwProcessId,
+ /* [out] */ ICorDebugProcess **ppProcess) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE CanLaunchOrAttach(
+ /* [in] */ DWORD dwProcessId,
+ /* [in] */ BOOL win32DebuggingEnabled) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebug * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebug * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebug * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Initialize )(
+ ICorDebug * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Terminate )(
+ ICorDebug * This);
+
+ HRESULT ( STDMETHODCALLTYPE *SetManagedHandler )(
+ ICorDebug * This,
+ /* [in] */ ICorDebugManagedCallback *pCallback);
+
+ HRESULT ( STDMETHODCALLTYPE *SetUnmanagedHandler )(
+ ICorDebug * This,
+ /* [in] */ ICorDebugUnmanagedCallback *pCallback);
+
+ HRESULT ( STDMETHODCALLTYPE *CreateProcess )(
+ ICorDebug * This,
+ /* [in] */ LPCWSTR lpApplicationName,
+ /* [in] */ LPWSTR lpCommandLine,
+ /* [in] */ LPSECURITY_ATTRIBUTES lpProcessAttributes,
+ /* [in] */ LPSECURITY_ATTRIBUTES lpThreadAttributes,
+ /* [in] */ BOOL bInheritHandles,
+ /* [in] */ DWORD dwCreationFlags,
+ /* [in] */ PVOID lpEnvironment,
+ /* [in] */ LPCWSTR lpCurrentDirectory,
+ /* [in] */ LPSTARTUPINFOW lpStartupInfo,
+ /* [in] */ LPPROCESS_INFORMATION lpProcessInformation,
+ /* [in] */ CorDebugCreateProcessFlags debuggingFlags,
+ /* [out] */ ICorDebugProcess **ppProcess);
+
+ HRESULT ( STDMETHODCALLTYPE *DebugActiveProcess )(
+ ICorDebug * This,
+ /* [in] */ DWORD id,
+ /* [in] */ BOOL win32Attach,
+ /* [out] */ ICorDebugProcess **ppProcess);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumerateProcesses )(
+ ICorDebug * This,
+ /* [out] */ ICorDebugProcessEnum **ppProcess);
+
+ HRESULT ( STDMETHODCALLTYPE *GetProcess )(
+ ICorDebug * This,
+ /* [in] */ DWORD dwProcessId,
+ /* [out] */ ICorDebugProcess **ppProcess);
+
+ HRESULT ( STDMETHODCALLTYPE *CanLaunchOrAttach )(
+ ICorDebug * This,
+ /* [in] */ DWORD dwProcessId,
+ /* [in] */ BOOL win32DebuggingEnabled);
+
+ END_INTERFACE
+ } ICorDebugVtbl;
+
+ interface ICorDebug
+ {
+ CONST_VTBL struct ICorDebugVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebug_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebug_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebug_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebug_Initialize(This) \
+ ( (This)->lpVtbl -> Initialize(This) )
+
+#define ICorDebug_Terminate(This) \
+ ( (This)->lpVtbl -> Terminate(This) )
+
+#define ICorDebug_SetManagedHandler(This,pCallback) \
+ ( (This)->lpVtbl -> SetManagedHandler(This,pCallback) )
+
+#define ICorDebug_SetUnmanagedHandler(This,pCallback) \
+ ( (This)->lpVtbl -> SetUnmanagedHandler(This,pCallback) )
+
+#define ICorDebug_CreateProcess(This,lpApplicationName,lpCommandLine,lpProcessAttributes,lpThreadAttributes,bInheritHandles,dwCreationFlags,lpEnvironment,lpCurrentDirectory,lpStartupInfo,lpProcessInformation,debuggingFlags,ppProcess) \
+ ( (This)->lpVtbl -> CreateProcess(This,lpApplicationName,lpCommandLine,lpProcessAttributes,lpThreadAttributes,bInheritHandles,dwCreationFlags,lpEnvironment,lpCurrentDirectory,lpStartupInfo,lpProcessInformation,debuggingFlags,ppProcess) )
+
+#define ICorDebug_DebugActiveProcess(This,id,win32Attach,ppProcess) \
+ ( (This)->lpVtbl -> DebugActiveProcess(This,id,win32Attach,ppProcess) )
+
+#define ICorDebug_EnumerateProcesses(This,ppProcess) \
+ ( (This)->lpVtbl -> EnumerateProcesses(This,ppProcess) )
+
+#define ICorDebug_GetProcess(This,dwProcessId,ppProcess) \
+ ( (This)->lpVtbl -> GetProcess(This,dwProcessId,ppProcess) )
+
+#define ICorDebug_CanLaunchOrAttach(This,dwProcessId,win32DebuggingEnabled) \
+ ( (This)->lpVtbl -> CanLaunchOrAttach(This,dwProcessId,win32DebuggingEnabled) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebug_INTERFACE_DEFINED__ */
+
+
+/* interface __MIDL_itf_cordebug_0000_0020 */
+/* [local] */
+
+#pragma warning(pop)
+
+
+extern RPC_IF_HANDLE __MIDL_itf_cordebug_0000_0020_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_cordebug_0000_0020_v0_0_s_ifspec;
+
+#ifndef __ICorDebugRemoteTarget_INTERFACE_DEFINED__
+#define __ICorDebugRemoteTarget_INTERFACE_DEFINED__
+
+/* interface ICorDebugRemoteTarget */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugRemoteTarget;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("C3ED8383-5A49-4cf5-B4B7-01864D9E582D")
+ ICorDebugRemoteTarget : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetHostName(
+ /* [in] */ ULONG32 cchHostName,
+ /* [annotation][out] */
+ _Out_ ULONG32 *pcchHostName,
+ /* [annotation][length_is][size_is][out] */
+ _Out_writes_to_opt_(cchHostName, *pcchHostName) WCHAR szHostName[ ]) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugRemoteTargetVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugRemoteTarget * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugRemoteTarget * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugRemoteTarget * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetHostName )(
+ ICorDebugRemoteTarget * This,
+ /* [in] */ ULONG32 cchHostName,
+ /* [annotation][out] */
+ _Out_ ULONG32 *pcchHostName,
+ /* [annotation][length_is][size_is][out] */
+ _Out_writes_to_opt_(cchHostName, *pcchHostName) WCHAR szHostName[ ]);
+
+ END_INTERFACE
+ } ICorDebugRemoteTargetVtbl;
+
+ interface ICorDebugRemoteTarget
+ {
+ CONST_VTBL struct ICorDebugRemoteTargetVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugRemoteTarget_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugRemoteTarget_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugRemoteTarget_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugRemoteTarget_GetHostName(This,cchHostName,pcchHostName,szHostName) \
+ ( (This)->lpVtbl -> GetHostName(This,cchHostName,pcchHostName,szHostName) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugRemoteTarget_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugRemote_INTERFACE_DEFINED__
+#define __ICorDebugRemote_INTERFACE_DEFINED__
+
+/* interface ICorDebugRemote */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugRemote;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("D5EBB8E2-7BBE-4c1d-98A6-A3C04CBDEF64")
+ ICorDebugRemote : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE CreateProcessEx(
+ /* [in] */ ICorDebugRemoteTarget *pRemoteTarget,
+ /* [in] */ LPCWSTR lpApplicationName,
+ /* [annotation][in] */
+ _In_ LPWSTR lpCommandLine,
+ /* [in] */ LPSECURITY_ATTRIBUTES lpProcessAttributes,
+ /* [in] */ LPSECURITY_ATTRIBUTES lpThreadAttributes,
+ /* [in] */ BOOL bInheritHandles,
+ /* [in] */ DWORD dwCreationFlags,
+ /* [in] */ PVOID lpEnvironment,
+ /* [in] */ LPCWSTR lpCurrentDirectory,
+ /* [in] */ LPSTARTUPINFOW lpStartupInfo,
+ /* [in] */ LPPROCESS_INFORMATION lpProcessInformation,
+ /* [in] */ CorDebugCreateProcessFlags debuggingFlags,
+ /* [out] */ ICorDebugProcess **ppProcess) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE DebugActiveProcessEx(
+ /* [in] */ ICorDebugRemoteTarget *pRemoteTarget,
+ /* [in] */ DWORD dwProcessId,
+ /* [in] */ BOOL fWin32Attach,
+ /* [out] */ ICorDebugProcess **ppProcess) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugRemoteVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugRemote * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugRemote * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugRemote * This);
+
+ HRESULT ( STDMETHODCALLTYPE *CreateProcessEx )(
+ ICorDebugRemote * This,
+ /* [in] */ ICorDebugRemoteTarget *pRemoteTarget,
+ /* [in] */ LPCWSTR lpApplicationName,
+ /* [annotation][in] */
+ _In_ LPWSTR lpCommandLine,
+ /* [in] */ LPSECURITY_ATTRIBUTES lpProcessAttributes,
+ /* [in] */ LPSECURITY_ATTRIBUTES lpThreadAttributes,
+ /* [in] */ BOOL bInheritHandles,
+ /* [in] */ DWORD dwCreationFlags,
+ /* [in] */ PVOID lpEnvironment,
+ /* [in] */ LPCWSTR lpCurrentDirectory,
+ /* [in] */ LPSTARTUPINFOW lpStartupInfo,
+ /* [in] */ LPPROCESS_INFORMATION lpProcessInformation,
+ /* [in] */ CorDebugCreateProcessFlags debuggingFlags,
+ /* [out] */ ICorDebugProcess **ppProcess);
+
+ HRESULT ( STDMETHODCALLTYPE *DebugActiveProcessEx )(
+ ICorDebugRemote * This,
+ /* [in] */ ICorDebugRemoteTarget *pRemoteTarget,
+ /* [in] */ DWORD dwProcessId,
+ /* [in] */ BOOL fWin32Attach,
+ /* [out] */ ICorDebugProcess **ppProcess);
+
+ END_INTERFACE
+ } ICorDebugRemoteVtbl;
+
+ interface ICorDebugRemote
+ {
+ CONST_VTBL struct ICorDebugRemoteVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugRemote_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugRemote_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugRemote_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugRemote_CreateProcessEx(This,pRemoteTarget,lpApplicationName,lpCommandLine,lpProcessAttributes,lpThreadAttributes,bInheritHandles,dwCreationFlags,lpEnvironment,lpCurrentDirectory,lpStartupInfo,lpProcessInformation,debuggingFlags,ppProcess) \
+ ( (This)->lpVtbl -> CreateProcessEx(This,pRemoteTarget,lpApplicationName,lpCommandLine,lpProcessAttributes,lpThreadAttributes,bInheritHandles,dwCreationFlags,lpEnvironment,lpCurrentDirectory,lpStartupInfo,lpProcessInformation,debuggingFlags,ppProcess) )
+
+#define ICorDebugRemote_DebugActiveProcessEx(This,pRemoteTarget,dwProcessId,fWin32Attach,ppProcess) \
+ ( (This)->lpVtbl -> DebugActiveProcessEx(This,pRemoteTarget,dwProcessId,fWin32Attach,ppProcess) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugRemote_INTERFACE_DEFINED__ */
+
+
+/* interface __MIDL_itf_cordebug_0000_0022 */
+/* [local] */
+
+typedef struct _COR_VERSION
+ {
+ DWORD dwMajor;
+ DWORD dwMinor;
+ DWORD dwBuild;
+ DWORD dwSubBuild;
+ } COR_VERSION;
+
+
+
+extern RPC_IF_HANDLE __MIDL_itf_cordebug_0000_0022_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_cordebug_0000_0022_v0_0_s_ifspec;
+
+#ifndef __ICorDebug2_INTERFACE_DEFINED__
+#define __ICorDebug2_INTERFACE_DEFINED__
+
+/* interface ICorDebug2 */
+/* [unique][uuid][local][object] */
+
+typedef
+enum CorDebugInterfaceVersion
+ {
+ CorDebugInvalidVersion = 0,
+ CorDebugVersion_1_0 = ( CorDebugInvalidVersion + 1 ) ,
+ ver_ICorDebugManagedCallback = CorDebugVersion_1_0,
+ ver_ICorDebugUnmanagedCallback = CorDebugVersion_1_0,
+ ver_ICorDebug = CorDebugVersion_1_0,
+ ver_ICorDebugController = CorDebugVersion_1_0,
+ ver_ICorDebugAppDomain = CorDebugVersion_1_0,
+ ver_ICorDebugAssembly = CorDebugVersion_1_0,
+ ver_ICorDebugProcess = CorDebugVersion_1_0,
+ ver_ICorDebugBreakpoint = CorDebugVersion_1_0,
+ ver_ICorDebugFunctionBreakpoint = CorDebugVersion_1_0,
+ ver_ICorDebugModuleBreakpoint = CorDebugVersion_1_0,
+ ver_ICorDebugValueBreakpoint = CorDebugVersion_1_0,
+ ver_ICorDebugStepper = CorDebugVersion_1_0,
+ ver_ICorDebugRegisterSet = CorDebugVersion_1_0,
+ ver_ICorDebugThread = CorDebugVersion_1_0,
+ ver_ICorDebugChain = CorDebugVersion_1_0,
+ ver_ICorDebugFrame = CorDebugVersion_1_0,
+ ver_ICorDebugILFrame = CorDebugVersion_1_0,
+ ver_ICorDebugNativeFrame = CorDebugVersion_1_0,
+ ver_ICorDebugModule = CorDebugVersion_1_0,
+ ver_ICorDebugFunction = CorDebugVersion_1_0,
+ ver_ICorDebugCode = CorDebugVersion_1_0,
+ ver_ICorDebugClass = CorDebugVersion_1_0,
+ ver_ICorDebugEval = CorDebugVersion_1_0,
+ ver_ICorDebugValue = CorDebugVersion_1_0,
+ ver_ICorDebugGenericValue = CorDebugVersion_1_0,
+ ver_ICorDebugReferenceValue = CorDebugVersion_1_0,
+ ver_ICorDebugHeapValue = CorDebugVersion_1_0,
+ ver_ICorDebugObjectValue = CorDebugVersion_1_0,
+ ver_ICorDebugBoxValue = CorDebugVersion_1_0,
+ ver_ICorDebugStringValue = CorDebugVersion_1_0,
+ ver_ICorDebugArrayValue = CorDebugVersion_1_0,
+ ver_ICorDebugContext = CorDebugVersion_1_0,
+ ver_ICorDebugEnum = CorDebugVersion_1_0,
+ ver_ICorDebugObjectEnum = CorDebugVersion_1_0,
+ ver_ICorDebugBreakpointEnum = CorDebugVersion_1_0,
+ ver_ICorDebugStepperEnum = CorDebugVersion_1_0,
+ ver_ICorDebugProcessEnum = CorDebugVersion_1_0,
+ ver_ICorDebugThreadEnum = CorDebugVersion_1_0,
+ ver_ICorDebugFrameEnum = CorDebugVersion_1_0,
+ ver_ICorDebugChainEnum = CorDebugVersion_1_0,
+ ver_ICorDebugModuleEnum = CorDebugVersion_1_0,
+ ver_ICorDebugValueEnum = CorDebugVersion_1_0,
+ ver_ICorDebugCodeEnum = CorDebugVersion_1_0,
+ ver_ICorDebugTypeEnum = CorDebugVersion_1_0,
+ ver_ICorDebugErrorInfoEnum = CorDebugVersion_1_0,
+ ver_ICorDebugAppDomainEnum = CorDebugVersion_1_0,
+ ver_ICorDebugAssemblyEnum = CorDebugVersion_1_0,
+ ver_ICorDebugEditAndContinueErrorInfo = CorDebugVersion_1_0,
+ ver_ICorDebugEditAndContinueSnapshot = CorDebugVersion_1_0,
+ CorDebugVersion_1_1 = ( CorDebugVersion_1_0 + 1 ) ,
+ CorDebugVersion_2_0 = ( CorDebugVersion_1_1 + 1 ) ,
+ ver_ICorDebugManagedCallback2 = CorDebugVersion_2_0,
+ ver_ICorDebugAppDomain2 = CorDebugVersion_2_0,
+ ver_ICorDebugAssembly2 = CorDebugVersion_2_0,
+ ver_ICorDebugProcess2 = CorDebugVersion_2_0,
+ ver_ICorDebugStepper2 = CorDebugVersion_2_0,
+ ver_ICorDebugRegisterSet2 = CorDebugVersion_2_0,
+ ver_ICorDebugThread2 = CorDebugVersion_2_0,
+ ver_ICorDebugILFrame2 = CorDebugVersion_2_0,
+ ver_ICorDebugInternalFrame = CorDebugVersion_2_0,
+ ver_ICorDebugModule2 = CorDebugVersion_2_0,
+ ver_ICorDebugFunction2 = CorDebugVersion_2_0,
+ ver_ICorDebugCode2 = CorDebugVersion_2_0,
+ ver_ICorDebugClass2 = CorDebugVersion_2_0,
+ ver_ICorDebugValue2 = CorDebugVersion_2_0,
+ ver_ICorDebugEval2 = CorDebugVersion_2_0,
+ ver_ICorDebugObjectValue2 = CorDebugVersion_2_0,
+ CorDebugVersion_4_0 = ( CorDebugVersion_2_0 + 1 ) ,
+ ver_ICorDebugThread3 = CorDebugVersion_4_0,
+ ver_ICorDebugThread4 = CorDebugVersion_4_0,
+ ver_ICorDebugStackWalk = CorDebugVersion_4_0,
+ ver_ICorDebugNativeFrame2 = CorDebugVersion_4_0,
+ ver_ICorDebugInternalFrame2 = CorDebugVersion_4_0,
+ ver_ICorDebugRuntimeUnwindableFrame = CorDebugVersion_4_0,
+ ver_ICorDebugHeapValue3 = CorDebugVersion_4_0,
+ ver_ICorDebugBlockingObjectEnum = CorDebugVersion_4_0,
+ ver_ICorDebugValue3 = CorDebugVersion_4_0,
+ CorDebugVersion_4_5 = ( CorDebugVersion_4_0 + 1 ) ,
+ ver_ICorDebugComObjectValue = CorDebugVersion_4_5,
+ ver_ICorDebugAppDomain3 = CorDebugVersion_4_5,
+ ver_ICorDebugCode3 = CorDebugVersion_4_5,
+ ver_ICorDebugILFrame3 = CorDebugVersion_4_5,
+ CorDebugLatestVersion = CorDebugVersion_4_5
+ } CorDebugInterfaceVersion;
+
+
+EXTERN_C const IID IID_ICorDebug2;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("ECCCCF2E-B286-4b3e-A983-860A8793D105")
+ ICorDebug2 : public IUnknown
+ {
+ public:
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebug2Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebug2 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebug2 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebug2 * This);
+
+ END_INTERFACE
+ } ICorDebug2Vtbl;
+
+ interface ICorDebug2
+ {
+ CONST_VTBL struct ICorDebug2Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebug2_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebug2_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebug2_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebug2_INTERFACE_DEFINED__ */
+
+
+/* interface __MIDL_itf_cordebug_0000_0023 */
+/* [local] */
+
+typedef
+enum CorDebugThreadState
+ {
+ THREAD_RUN = 0,
+ THREAD_SUSPEND = ( THREAD_RUN + 1 )
+ } CorDebugThreadState;
+
+
+
+extern RPC_IF_HANDLE __MIDL_itf_cordebug_0000_0023_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_cordebug_0000_0023_v0_0_s_ifspec;
+
+#ifndef __ICorDebugController_INTERFACE_DEFINED__
+#define __ICorDebugController_INTERFACE_DEFINED__
+
+/* interface ICorDebugController */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugController;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("3d6f5f62-7538-11d3-8d5b-00104b35e7ef")
+ ICorDebugController : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE Stop(
+ /* [in] */ DWORD dwTimeoutIgnored) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Continue(
+ /* [in] */ BOOL fIsOutOfBand) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE IsRunning(
+ /* [out] */ BOOL *pbRunning) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE HasQueuedCallbacks(
+ /* [in] */ ICorDebugThread *pThread,
+ /* [out] */ BOOL *pbQueued) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnumerateThreads(
+ /* [out] */ ICorDebugThreadEnum **ppThreads) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetAllThreadsDebugState(
+ /* [in] */ CorDebugThreadState state,
+ /* [in] */ ICorDebugThread *pExceptThisThread) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Detach( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Terminate(
+ /* [in] */ UINT exitCode) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE CanCommitChanges(
+ /* [in] */ ULONG cSnapshots,
+ /* [size_is][in] */ ICorDebugEditAndContinueSnapshot *pSnapshots[ ],
+ /* [out] */ ICorDebugErrorInfoEnum **pError) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE CommitChanges(
+ /* [in] */ ULONG cSnapshots,
+ /* [size_is][in] */ ICorDebugEditAndContinueSnapshot *pSnapshots[ ],
+ /* [out] */ ICorDebugErrorInfoEnum **pError) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugControllerVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugController * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugController * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugController * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Stop )(
+ ICorDebugController * This,
+ /* [in] */ DWORD dwTimeoutIgnored);
+
+ HRESULT ( STDMETHODCALLTYPE *Continue )(
+ ICorDebugController * This,
+ /* [in] */ BOOL fIsOutOfBand);
+
+ HRESULT ( STDMETHODCALLTYPE *IsRunning )(
+ ICorDebugController * This,
+ /* [out] */ BOOL *pbRunning);
+
+ HRESULT ( STDMETHODCALLTYPE *HasQueuedCallbacks )(
+ ICorDebugController * This,
+ /* [in] */ ICorDebugThread *pThread,
+ /* [out] */ BOOL *pbQueued);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumerateThreads )(
+ ICorDebugController * This,
+ /* [out] */ ICorDebugThreadEnum **ppThreads);
+
+ HRESULT ( STDMETHODCALLTYPE *SetAllThreadsDebugState )(
+ ICorDebugController * This,
+ /* [in] */ CorDebugThreadState state,
+ /* [in] */ ICorDebugThread *pExceptThisThread);
+
+ HRESULT ( STDMETHODCALLTYPE *Detach )(
+ ICorDebugController * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Terminate )(
+ ICorDebugController * This,
+ /* [in] */ UINT exitCode);
+
+ HRESULT ( STDMETHODCALLTYPE *CanCommitChanges )(
+ ICorDebugController * This,
+ /* [in] */ ULONG cSnapshots,
+ /* [size_is][in] */ ICorDebugEditAndContinueSnapshot *pSnapshots[ ],
+ /* [out] */ ICorDebugErrorInfoEnum **pError);
+
+ HRESULT ( STDMETHODCALLTYPE *CommitChanges )(
+ ICorDebugController * This,
+ /* [in] */ ULONG cSnapshots,
+ /* [size_is][in] */ ICorDebugEditAndContinueSnapshot *pSnapshots[ ],
+ /* [out] */ ICorDebugErrorInfoEnum **pError);
+
+ END_INTERFACE
+ } ICorDebugControllerVtbl;
+
+ interface ICorDebugController
+ {
+ CONST_VTBL struct ICorDebugControllerVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugController_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugController_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugController_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugController_Stop(This,dwTimeoutIgnored) \
+ ( (This)->lpVtbl -> Stop(This,dwTimeoutIgnored) )
+
+#define ICorDebugController_Continue(This,fIsOutOfBand) \
+ ( (This)->lpVtbl -> Continue(This,fIsOutOfBand) )
+
+#define ICorDebugController_IsRunning(This,pbRunning) \
+ ( (This)->lpVtbl -> IsRunning(This,pbRunning) )
+
+#define ICorDebugController_HasQueuedCallbacks(This,pThread,pbQueued) \
+ ( (This)->lpVtbl -> HasQueuedCallbacks(This,pThread,pbQueued) )
+
+#define ICorDebugController_EnumerateThreads(This,ppThreads) \
+ ( (This)->lpVtbl -> EnumerateThreads(This,ppThreads) )
+
+#define ICorDebugController_SetAllThreadsDebugState(This,state,pExceptThisThread) \
+ ( (This)->lpVtbl -> SetAllThreadsDebugState(This,state,pExceptThisThread) )
+
+#define ICorDebugController_Detach(This) \
+ ( (This)->lpVtbl -> Detach(This) )
+
+#define ICorDebugController_Terminate(This,exitCode) \
+ ( (This)->lpVtbl -> Terminate(This,exitCode) )
+
+#define ICorDebugController_CanCommitChanges(This,cSnapshots,pSnapshots,pError) \
+ ( (This)->lpVtbl -> CanCommitChanges(This,cSnapshots,pSnapshots,pError) )
+
+#define ICorDebugController_CommitChanges(This,cSnapshots,pSnapshots,pError) \
+ ( (This)->lpVtbl -> CommitChanges(This,cSnapshots,pSnapshots,pError) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugController_INTERFACE_DEFINED__ */
+
+
+/* interface __MIDL_itf_cordebug_0000_0024 */
+/* [local] */
+
+#pragma warning(push)
+#pragma warning(disable:28718)
+
+
+extern RPC_IF_HANDLE __MIDL_itf_cordebug_0000_0024_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_cordebug_0000_0024_v0_0_s_ifspec;
+
+#ifndef __ICorDebugAppDomain_INTERFACE_DEFINED__
+#define __ICorDebugAppDomain_INTERFACE_DEFINED__
+
+/* interface ICorDebugAppDomain */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugAppDomain;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("3d6f5f63-7538-11d3-8d5b-00104b35e7ef")
+ ICorDebugAppDomain : public ICorDebugController
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetProcess(
+ /* [out] */ ICorDebugProcess **ppProcess) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnumerateAssemblies(
+ /* [out] */ ICorDebugAssemblyEnum **ppAssemblies) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetModuleFromMetaDataInterface(
+ /* [in] */ IUnknown *pIMetaData,
+ /* [out] */ ICorDebugModule **ppModule) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnumerateBreakpoints(
+ /* [out] */ ICorDebugBreakpointEnum **ppBreakpoints) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnumerateSteppers(
+ /* [out] */ ICorDebugStepperEnum **ppSteppers) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE IsAttached(
+ /* [out] */ BOOL *pbAttached) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetName(
+ /* [in] */ ULONG32 cchName,
+ /* [out] */ ULONG32 *pcchName,
+ /* [length_is][size_is][out] */ WCHAR szName[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetObject(
+ /* [out] */ ICorDebugValue **ppObject) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Attach( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetID(
+ /* [out] */ ULONG32 *pId) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugAppDomainVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugAppDomain * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugAppDomain * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugAppDomain * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Stop )(
+ ICorDebugAppDomain * This,
+ /* [in] */ DWORD dwTimeoutIgnored);
+
+ HRESULT ( STDMETHODCALLTYPE *Continue )(
+ ICorDebugAppDomain * This,
+ /* [in] */ BOOL fIsOutOfBand);
+
+ HRESULT ( STDMETHODCALLTYPE *IsRunning )(
+ ICorDebugAppDomain * This,
+ /* [out] */ BOOL *pbRunning);
+
+ HRESULT ( STDMETHODCALLTYPE *HasQueuedCallbacks )(
+ ICorDebugAppDomain * This,
+ /* [in] */ ICorDebugThread *pThread,
+ /* [out] */ BOOL *pbQueued);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumerateThreads )(
+ ICorDebugAppDomain * This,
+ /* [out] */ ICorDebugThreadEnum **ppThreads);
+
+ HRESULT ( STDMETHODCALLTYPE *SetAllThreadsDebugState )(
+ ICorDebugAppDomain * This,
+ /* [in] */ CorDebugThreadState state,
+ /* [in] */ ICorDebugThread *pExceptThisThread);
+
+ HRESULT ( STDMETHODCALLTYPE *Detach )(
+ ICorDebugAppDomain * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Terminate )(
+ ICorDebugAppDomain * This,
+ /* [in] */ UINT exitCode);
+
+ HRESULT ( STDMETHODCALLTYPE *CanCommitChanges )(
+ ICorDebugAppDomain * This,
+ /* [in] */ ULONG cSnapshots,
+ /* [size_is][in] */ ICorDebugEditAndContinueSnapshot *pSnapshots[ ],
+ /* [out] */ ICorDebugErrorInfoEnum **pError);
+
+ HRESULT ( STDMETHODCALLTYPE *CommitChanges )(
+ ICorDebugAppDomain * This,
+ /* [in] */ ULONG cSnapshots,
+ /* [size_is][in] */ ICorDebugEditAndContinueSnapshot *pSnapshots[ ],
+ /* [out] */ ICorDebugErrorInfoEnum **pError);
+
+ HRESULT ( STDMETHODCALLTYPE *GetProcess )(
+ ICorDebugAppDomain * This,
+ /* [out] */ ICorDebugProcess **ppProcess);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumerateAssemblies )(
+ ICorDebugAppDomain * This,
+ /* [out] */ ICorDebugAssemblyEnum **ppAssemblies);
+
+ HRESULT ( STDMETHODCALLTYPE *GetModuleFromMetaDataInterface )(
+ ICorDebugAppDomain * This,
+ /* [in] */ IUnknown *pIMetaData,
+ /* [out] */ ICorDebugModule **ppModule);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumerateBreakpoints )(
+ ICorDebugAppDomain * This,
+ /* [out] */ ICorDebugBreakpointEnum **ppBreakpoints);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumerateSteppers )(
+ ICorDebugAppDomain * This,
+ /* [out] */ ICorDebugStepperEnum **ppSteppers);
+
+ HRESULT ( STDMETHODCALLTYPE *IsAttached )(
+ ICorDebugAppDomain * This,
+ /* [out] */ BOOL *pbAttached);
+
+ HRESULT ( STDMETHODCALLTYPE *GetName )(
+ ICorDebugAppDomain * This,
+ /* [in] */ ULONG32 cchName,
+ /* [out] */ ULONG32 *pcchName,
+ /* [length_is][size_is][out] */ WCHAR szName[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetObject )(
+ ICorDebugAppDomain * This,
+ /* [out] */ ICorDebugValue **ppObject);
+
+ HRESULT ( STDMETHODCALLTYPE *Attach )(
+ ICorDebugAppDomain * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetID )(
+ ICorDebugAppDomain * This,
+ /* [out] */ ULONG32 *pId);
+
+ END_INTERFACE
+ } ICorDebugAppDomainVtbl;
+
+ interface ICorDebugAppDomain
+ {
+ CONST_VTBL struct ICorDebugAppDomainVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugAppDomain_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugAppDomain_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugAppDomain_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugAppDomain_Stop(This,dwTimeoutIgnored) \
+ ( (This)->lpVtbl -> Stop(This,dwTimeoutIgnored) )
+
+#define ICorDebugAppDomain_Continue(This,fIsOutOfBand) \
+ ( (This)->lpVtbl -> Continue(This,fIsOutOfBand) )
+
+#define ICorDebugAppDomain_IsRunning(This,pbRunning) \
+ ( (This)->lpVtbl -> IsRunning(This,pbRunning) )
+
+#define ICorDebugAppDomain_HasQueuedCallbacks(This,pThread,pbQueued) \
+ ( (This)->lpVtbl -> HasQueuedCallbacks(This,pThread,pbQueued) )
+
+#define ICorDebugAppDomain_EnumerateThreads(This,ppThreads) \
+ ( (This)->lpVtbl -> EnumerateThreads(This,ppThreads) )
+
+#define ICorDebugAppDomain_SetAllThreadsDebugState(This,state,pExceptThisThread) \
+ ( (This)->lpVtbl -> SetAllThreadsDebugState(This,state,pExceptThisThread) )
+
+#define ICorDebugAppDomain_Detach(This) \
+ ( (This)->lpVtbl -> Detach(This) )
+
+#define ICorDebugAppDomain_Terminate(This,exitCode) \
+ ( (This)->lpVtbl -> Terminate(This,exitCode) )
+
+#define ICorDebugAppDomain_CanCommitChanges(This,cSnapshots,pSnapshots,pError) \
+ ( (This)->lpVtbl -> CanCommitChanges(This,cSnapshots,pSnapshots,pError) )
+
+#define ICorDebugAppDomain_CommitChanges(This,cSnapshots,pSnapshots,pError) \
+ ( (This)->lpVtbl -> CommitChanges(This,cSnapshots,pSnapshots,pError) )
+
+
+#define ICorDebugAppDomain_GetProcess(This,ppProcess) \
+ ( (This)->lpVtbl -> GetProcess(This,ppProcess) )
+
+#define ICorDebugAppDomain_EnumerateAssemblies(This,ppAssemblies) \
+ ( (This)->lpVtbl -> EnumerateAssemblies(This,ppAssemblies) )
+
+#define ICorDebugAppDomain_GetModuleFromMetaDataInterface(This,pIMetaData,ppModule) \
+ ( (This)->lpVtbl -> GetModuleFromMetaDataInterface(This,pIMetaData,ppModule) )
+
+#define ICorDebugAppDomain_EnumerateBreakpoints(This,ppBreakpoints) \
+ ( (This)->lpVtbl -> EnumerateBreakpoints(This,ppBreakpoints) )
+
+#define ICorDebugAppDomain_EnumerateSteppers(This,ppSteppers) \
+ ( (This)->lpVtbl -> EnumerateSteppers(This,ppSteppers) )
+
+#define ICorDebugAppDomain_IsAttached(This,pbAttached) \
+ ( (This)->lpVtbl -> IsAttached(This,pbAttached) )
+
+#define ICorDebugAppDomain_GetName(This,cchName,pcchName,szName) \
+ ( (This)->lpVtbl -> GetName(This,cchName,pcchName,szName) )
+
+#define ICorDebugAppDomain_GetObject(This,ppObject) \
+ ( (This)->lpVtbl -> GetObject(This,ppObject) )
+
+#define ICorDebugAppDomain_Attach(This) \
+ ( (This)->lpVtbl -> Attach(This) )
+
+#define ICorDebugAppDomain_GetID(This,pId) \
+ ( (This)->lpVtbl -> GetID(This,pId) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugAppDomain_INTERFACE_DEFINED__ */
+
+
+/* interface __MIDL_itf_cordebug_0000_0025 */
+/* [local] */
+
+#pragma warning(pop)
+
+
+extern RPC_IF_HANDLE __MIDL_itf_cordebug_0000_0025_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_cordebug_0000_0025_v0_0_s_ifspec;
+
+#ifndef __ICorDebugAppDomain2_INTERFACE_DEFINED__
+#define __ICorDebugAppDomain2_INTERFACE_DEFINED__
+
+/* interface ICorDebugAppDomain2 */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugAppDomain2;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("096E81D5-ECDA-4202-83F5-C65980A9EF75")
+ ICorDebugAppDomain2 : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetArrayOrPointerType(
+ /* [in] */ CorElementType elementType,
+ /* [in] */ ULONG32 nRank,
+ /* [in] */ ICorDebugType *pTypeArg,
+ /* [out] */ ICorDebugType **ppType) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetFunctionPointerType(
+ /* [in] */ ULONG32 nTypeArgs,
+ /* [size_is][in] */ ICorDebugType *ppTypeArgs[ ],
+ /* [out] */ ICorDebugType **ppType) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugAppDomain2Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugAppDomain2 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugAppDomain2 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugAppDomain2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetArrayOrPointerType )(
+ ICorDebugAppDomain2 * This,
+ /* [in] */ CorElementType elementType,
+ /* [in] */ ULONG32 nRank,
+ /* [in] */ ICorDebugType *pTypeArg,
+ /* [out] */ ICorDebugType **ppType);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFunctionPointerType )(
+ ICorDebugAppDomain2 * This,
+ /* [in] */ ULONG32 nTypeArgs,
+ /* [size_is][in] */ ICorDebugType *ppTypeArgs[ ],
+ /* [out] */ ICorDebugType **ppType);
+
+ END_INTERFACE
+ } ICorDebugAppDomain2Vtbl;
+
+ interface ICorDebugAppDomain2
+ {
+ CONST_VTBL struct ICorDebugAppDomain2Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugAppDomain2_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugAppDomain2_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugAppDomain2_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugAppDomain2_GetArrayOrPointerType(This,elementType,nRank,pTypeArg,ppType) \
+ ( (This)->lpVtbl -> GetArrayOrPointerType(This,elementType,nRank,pTypeArg,ppType) )
+
+#define ICorDebugAppDomain2_GetFunctionPointerType(This,nTypeArgs,ppTypeArgs,ppType) \
+ ( (This)->lpVtbl -> GetFunctionPointerType(This,nTypeArgs,ppTypeArgs,ppType) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugAppDomain2_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugEnum_INTERFACE_DEFINED__
+#define __ICorDebugEnum_INTERFACE_DEFINED__
+
+/* interface ICorDebugEnum */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugEnum;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("CC7BCB01-8A68-11d2-983C-0000F808342D")
+ ICorDebugEnum : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE Skip(
+ /* [in] */ ULONG celt) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Reset( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Clone(
+ /* [out] */ ICorDebugEnum **ppEnum) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetCount(
+ /* [out] */ ULONG *pcelt) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugEnumVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugEnum * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugEnum * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugEnum * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Skip )(
+ ICorDebugEnum * This,
+ /* [in] */ ULONG celt);
+
+ HRESULT ( STDMETHODCALLTYPE *Reset )(
+ ICorDebugEnum * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Clone )(
+ ICorDebugEnum * This,
+ /* [out] */ ICorDebugEnum **ppEnum);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCount )(
+ ICorDebugEnum * This,
+ /* [out] */ ULONG *pcelt);
+
+ END_INTERFACE
+ } ICorDebugEnumVtbl;
+
+ interface ICorDebugEnum
+ {
+ CONST_VTBL struct ICorDebugEnumVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugEnum_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugEnum_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugEnum_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugEnum_Skip(This,celt) \
+ ( (This)->lpVtbl -> Skip(This,celt) )
+
+#define ICorDebugEnum_Reset(This) \
+ ( (This)->lpVtbl -> Reset(This) )
+
+#define ICorDebugEnum_Clone(This,ppEnum) \
+ ( (This)->lpVtbl -> Clone(This,ppEnum) )
+
+#define ICorDebugEnum_GetCount(This,pcelt) \
+ ( (This)->lpVtbl -> GetCount(This,pcelt) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugEnum_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugGuidToTypeEnum_INTERFACE_DEFINED__
+#define __ICorDebugGuidToTypeEnum_INTERFACE_DEFINED__
+
+/* interface ICorDebugGuidToTypeEnum */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugGuidToTypeEnum;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("6164D242-1015-4BD6-8CBE-D0DBD4B8275A")
+ ICorDebugGuidToTypeEnum : public ICorDebugEnum
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE Next(
+ /* [in] */ ULONG celt,
+ /* [length_is][size_is][out] */ CorDebugGuidToTypeMapping values[ ],
+ /* [out] */ ULONG *pceltFetched) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugGuidToTypeEnumVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugGuidToTypeEnum * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugGuidToTypeEnum * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugGuidToTypeEnum * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Skip )(
+ ICorDebugGuidToTypeEnum * This,
+ /* [in] */ ULONG celt);
+
+ HRESULT ( STDMETHODCALLTYPE *Reset )(
+ ICorDebugGuidToTypeEnum * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Clone )(
+ ICorDebugGuidToTypeEnum * This,
+ /* [out] */ ICorDebugEnum **ppEnum);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCount )(
+ ICorDebugGuidToTypeEnum * This,
+ /* [out] */ ULONG *pcelt);
+
+ HRESULT ( STDMETHODCALLTYPE *Next )(
+ ICorDebugGuidToTypeEnum * This,
+ /* [in] */ ULONG celt,
+ /* [length_is][size_is][out] */ CorDebugGuidToTypeMapping values[ ],
+ /* [out] */ ULONG *pceltFetched);
+
+ END_INTERFACE
+ } ICorDebugGuidToTypeEnumVtbl;
+
+ interface ICorDebugGuidToTypeEnum
+ {
+ CONST_VTBL struct ICorDebugGuidToTypeEnumVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugGuidToTypeEnum_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugGuidToTypeEnum_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugGuidToTypeEnum_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugGuidToTypeEnum_Skip(This,celt) \
+ ( (This)->lpVtbl -> Skip(This,celt) )
+
+#define ICorDebugGuidToTypeEnum_Reset(This) \
+ ( (This)->lpVtbl -> Reset(This) )
+
+#define ICorDebugGuidToTypeEnum_Clone(This,ppEnum) \
+ ( (This)->lpVtbl -> Clone(This,ppEnum) )
+
+#define ICorDebugGuidToTypeEnum_GetCount(This,pcelt) \
+ ( (This)->lpVtbl -> GetCount(This,pcelt) )
+
+
+#define ICorDebugGuidToTypeEnum_Next(This,celt,values,pceltFetched) \
+ ( (This)->lpVtbl -> Next(This,celt,values,pceltFetched) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugGuidToTypeEnum_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugAppDomain3_INTERFACE_DEFINED__
+#define __ICorDebugAppDomain3_INTERFACE_DEFINED__
+
+/* interface ICorDebugAppDomain3 */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugAppDomain3;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("8CB96A16-B588-42E2-B71C-DD849FC2ECCC")
+ ICorDebugAppDomain3 : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetCachedWinRTTypesForIIDs(
+ /* [in] */ ULONG32 cReqTypes,
+ /* [size_is][in] */ GUID *iidsToResolve,
+ /* [out] */ ICorDebugTypeEnum **ppTypesEnum) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetCachedWinRTTypes(
+ /* [out] */ ICorDebugGuidToTypeEnum **ppGuidToTypeEnum) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugAppDomain3Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugAppDomain3 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugAppDomain3 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugAppDomain3 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCachedWinRTTypesForIIDs )(
+ ICorDebugAppDomain3 * This,
+ /* [in] */ ULONG32 cReqTypes,
+ /* [size_is][in] */ GUID *iidsToResolve,
+ /* [out] */ ICorDebugTypeEnum **ppTypesEnum);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCachedWinRTTypes )(
+ ICorDebugAppDomain3 * This,
+ /* [out] */ ICorDebugGuidToTypeEnum **ppGuidToTypeEnum);
+
+ END_INTERFACE
+ } ICorDebugAppDomain3Vtbl;
+
+ interface ICorDebugAppDomain3
+ {
+ CONST_VTBL struct ICorDebugAppDomain3Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugAppDomain3_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugAppDomain3_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugAppDomain3_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugAppDomain3_GetCachedWinRTTypesForIIDs(This,cReqTypes,iidsToResolve,ppTypesEnum) \
+ ( (This)->lpVtbl -> GetCachedWinRTTypesForIIDs(This,cReqTypes,iidsToResolve,ppTypesEnum) )
+
+#define ICorDebugAppDomain3_GetCachedWinRTTypes(This,ppGuidToTypeEnum) \
+ ( (This)->lpVtbl -> GetCachedWinRTTypes(This,ppGuidToTypeEnum) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugAppDomain3_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugAppDomain4_INTERFACE_DEFINED__
+#define __ICorDebugAppDomain4_INTERFACE_DEFINED__
+
+/* interface ICorDebugAppDomain4 */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugAppDomain4;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("FB99CC40-83BE-4724-AB3B-768E796EBAC2")
+ ICorDebugAppDomain4 : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetObjectForCCW(
+ /* [in] */ CORDB_ADDRESS ccwPointer,
+ /* [out] */ ICorDebugValue **ppManagedObject) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugAppDomain4Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugAppDomain4 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugAppDomain4 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugAppDomain4 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetObjectForCCW )(
+ ICorDebugAppDomain4 * This,
+ /* [in] */ CORDB_ADDRESS ccwPointer,
+ /* [out] */ ICorDebugValue **ppManagedObject);
+
+ END_INTERFACE
+ } ICorDebugAppDomain4Vtbl;
+
+ interface ICorDebugAppDomain4
+ {
+ CONST_VTBL struct ICorDebugAppDomain4Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugAppDomain4_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugAppDomain4_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugAppDomain4_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugAppDomain4_GetObjectForCCW(This,ccwPointer,ppManagedObject) \
+ ( (This)->lpVtbl -> GetObjectForCCW(This,ccwPointer,ppManagedObject) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugAppDomain4_INTERFACE_DEFINED__ */
+
+
+/* interface __MIDL_itf_cordebug_0000_0029 */
+/* [local] */
+
+#pragma warning(push)
+#pragma warning(disable:28718)
+
+
+extern RPC_IF_HANDLE __MIDL_itf_cordebug_0000_0029_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_cordebug_0000_0029_v0_0_s_ifspec;
+
+#ifndef __ICorDebugAssembly_INTERFACE_DEFINED__
+#define __ICorDebugAssembly_INTERFACE_DEFINED__
+
+/* interface ICorDebugAssembly */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugAssembly;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("df59507c-d47a-459e-bce2-6427eac8fd06")
+ ICorDebugAssembly : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetProcess(
+ /* [out] */ ICorDebugProcess **ppProcess) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetAppDomain(
+ /* [out] */ ICorDebugAppDomain **ppAppDomain) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnumerateModules(
+ /* [out] */ ICorDebugModuleEnum **ppModules) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetCodeBase(
+ /* [in] */ ULONG32 cchName,
+ /* [out] */ ULONG32 *pcchName,
+ /* [length_is][size_is][out] */ WCHAR szName[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetName(
+ /* [in] */ ULONG32 cchName,
+ /* [out] */ ULONG32 *pcchName,
+ /* [length_is][size_is][out] */ WCHAR szName[ ]) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugAssemblyVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugAssembly * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugAssembly * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugAssembly * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetProcess )(
+ ICorDebugAssembly * This,
+ /* [out] */ ICorDebugProcess **ppProcess);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAppDomain )(
+ ICorDebugAssembly * This,
+ /* [out] */ ICorDebugAppDomain **ppAppDomain);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumerateModules )(
+ ICorDebugAssembly * This,
+ /* [out] */ ICorDebugModuleEnum **ppModules);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCodeBase )(
+ ICorDebugAssembly * This,
+ /* [in] */ ULONG32 cchName,
+ /* [out] */ ULONG32 *pcchName,
+ /* [length_is][size_is][out] */ WCHAR szName[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetName )(
+ ICorDebugAssembly * This,
+ /* [in] */ ULONG32 cchName,
+ /* [out] */ ULONG32 *pcchName,
+ /* [length_is][size_is][out] */ WCHAR szName[ ]);
+
+ END_INTERFACE
+ } ICorDebugAssemblyVtbl;
+
+ interface ICorDebugAssembly
+ {
+ CONST_VTBL struct ICorDebugAssemblyVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugAssembly_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugAssembly_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugAssembly_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugAssembly_GetProcess(This,ppProcess) \
+ ( (This)->lpVtbl -> GetProcess(This,ppProcess) )
+
+#define ICorDebugAssembly_GetAppDomain(This,ppAppDomain) \
+ ( (This)->lpVtbl -> GetAppDomain(This,ppAppDomain) )
+
+#define ICorDebugAssembly_EnumerateModules(This,ppModules) \
+ ( (This)->lpVtbl -> EnumerateModules(This,ppModules) )
+
+#define ICorDebugAssembly_GetCodeBase(This,cchName,pcchName,szName) \
+ ( (This)->lpVtbl -> GetCodeBase(This,cchName,pcchName,szName) )
+
+#define ICorDebugAssembly_GetName(This,cchName,pcchName,szName) \
+ ( (This)->lpVtbl -> GetName(This,cchName,pcchName,szName) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugAssembly_INTERFACE_DEFINED__ */
+
+
+/* interface __MIDL_itf_cordebug_0000_0030 */
+/* [local] */
+
+#pragma warning(pop)
+
+
+extern RPC_IF_HANDLE __MIDL_itf_cordebug_0000_0030_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_cordebug_0000_0030_v0_0_s_ifspec;
+
+#ifndef __ICorDebugAssembly2_INTERFACE_DEFINED__
+#define __ICorDebugAssembly2_INTERFACE_DEFINED__
+
+/* interface ICorDebugAssembly2 */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugAssembly2;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("426d1f9e-6dd4-44c8-aec7-26cdbaf4e398")
+ ICorDebugAssembly2 : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE IsFullyTrusted(
+ /* [out] */ BOOL *pbFullyTrusted) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugAssembly2Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugAssembly2 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugAssembly2 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugAssembly2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *IsFullyTrusted )(
+ ICorDebugAssembly2 * This,
+ /* [out] */ BOOL *pbFullyTrusted);
+
+ END_INTERFACE
+ } ICorDebugAssembly2Vtbl;
+
+ interface ICorDebugAssembly2
+ {
+ CONST_VTBL struct ICorDebugAssembly2Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugAssembly2_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugAssembly2_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugAssembly2_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugAssembly2_IsFullyTrusted(This,pbFullyTrusted) \
+ ( (This)->lpVtbl -> IsFullyTrusted(This,pbFullyTrusted) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugAssembly2_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugAssembly3_INTERFACE_DEFINED__
+#define __ICorDebugAssembly3_INTERFACE_DEFINED__
+
+/* interface ICorDebugAssembly3 */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugAssembly3;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("76361AB2-8C86-4FE9-96F2-F73D8843570A")
+ ICorDebugAssembly3 : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetContainerAssembly(
+ ICorDebugAssembly **ppAssembly) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnumerateContainedAssemblies(
+ ICorDebugAssemblyEnum **ppAssemblies) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugAssembly3Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugAssembly3 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugAssembly3 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugAssembly3 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetContainerAssembly )(
+ ICorDebugAssembly3 * This,
+ ICorDebugAssembly **ppAssembly);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumerateContainedAssemblies )(
+ ICorDebugAssembly3 * This,
+ ICorDebugAssemblyEnum **ppAssemblies);
+
+ END_INTERFACE
+ } ICorDebugAssembly3Vtbl;
+
+ interface ICorDebugAssembly3
+ {
+ CONST_VTBL struct ICorDebugAssembly3Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugAssembly3_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugAssembly3_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugAssembly3_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugAssembly3_GetContainerAssembly(This,ppAssembly) \
+ ( (This)->lpVtbl -> GetContainerAssembly(This,ppAssembly) )
+
+#define ICorDebugAssembly3_EnumerateContainedAssemblies(This,ppAssemblies) \
+ ( (This)->lpVtbl -> EnumerateContainedAssemblies(This,ppAssemblies) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugAssembly3_INTERFACE_DEFINED__ */
+
+
+/* interface __MIDL_itf_cordebug_0000_0032 */
+/* [local] */
+
+#ifndef _DEF_COR_TYPEID_
+#define _DEF_COR_TYPEID_
+typedef struct COR_TYPEID
+ {
+ UINT64 token1;
+ UINT64 token2;
+ } COR_TYPEID;
+
+#endif // _DEF_COR_TYPEID_
+typedef struct _COR_HEAPOBJECT
+ {
+ CORDB_ADDRESS address;
+ ULONG64 size;
+ COR_TYPEID type;
+ } COR_HEAPOBJECT;
+
+
+
+extern RPC_IF_HANDLE __MIDL_itf_cordebug_0000_0032_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_cordebug_0000_0032_v0_0_s_ifspec;
+
+#ifndef __ICorDebugHeapEnum_INTERFACE_DEFINED__
+#define __ICorDebugHeapEnum_INTERFACE_DEFINED__
+
+/* interface ICorDebugHeapEnum */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugHeapEnum;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("76D7DAB8-D044-11DF-9A15-7E29DFD72085")
+ ICorDebugHeapEnum : public ICorDebugEnum
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE Next(
+ /* [in] */ ULONG celt,
+ /* [length_is][size_is][out] */ COR_HEAPOBJECT objects[ ],
+ /* [out] */ ULONG *pceltFetched) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugHeapEnumVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugHeapEnum * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugHeapEnum * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugHeapEnum * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Skip )(
+ ICorDebugHeapEnum * This,
+ /* [in] */ ULONG celt);
+
+ HRESULT ( STDMETHODCALLTYPE *Reset )(
+ ICorDebugHeapEnum * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Clone )(
+ ICorDebugHeapEnum * This,
+ /* [out] */ ICorDebugEnum **ppEnum);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCount )(
+ ICorDebugHeapEnum * This,
+ /* [out] */ ULONG *pcelt);
+
+ HRESULT ( STDMETHODCALLTYPE *Next )(
+ ICorDebugHeapEnum * This,
+ /* [in] */ ULONG celt,
+ /* [length_is][size_is][out] */ COR_HEAPOBJECT objects[ ],
+ /* [out] */ ULONG *pceltFetched);
+
+ END_INTERFACE
+ } ICorDebugHeapEnumVtbl;
+
+ interface ICorDebugHeapEnum
+ {
+ CONST_VTBL struct ICorDebugHeapEnumVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugHeapEnum_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugHeapEnum_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugHeapEnum_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugHeapEnum_Skip(This,celt) \
+ ( (This)->lpVtbl -> Skip(This,celt) )
+
+#define ICorDebugHeapEnum_Reset(This) \
+ ( (This)->lpVtbl -> Reset(This) )
+
+#define ICorDebugHeapEnum_Clone(This,ppEnum) \
+ ( (This)->lpVtbl -> Clone(This,ppEnum) )
+
+#define ICorDebugHeapEnum_GetCount(This,pcelt) \
+ ( (This)->lpVtbl -> GetCount(This,pcelt) )
+
+
+#define ICorDebugHeapEnum_Next(This,celt,objects,pceltFetched) \
+ ( (This)->lpVtbl -> Next(This,celt,objects,pceltFetched) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugHeapEnum_INTERFACE_DEFINED__ */
+
+
+/* interface __MIDL_itf_cordebug_0000_0033 */
+/* [local] */
+
+typedef
+enum CorDebugGenerationTypes
+ {
+ CorDebug_Gen0 = 0,
+ CorDebug_Gen1 = 1,
+ CorDebug_Gen2 = 2,
+ CorDebug_LOH = 3
+ } CorDebugGenerationTypes;
+
+typedef struct _COR_SEGMENT
+ {
+ CORDB_ADDRESS start;
+ CORDB_ADDRESS end;
+ CorDebugGenerationTypes type;
+ ULONG heap;
+ } COR_SEGMENT;
+
+typedef
+enum CorDebugGCType
+ {
+ CorDebugWorkstationGC = 0,
+ CorDebugServerGC = ( CorDebugWorkstationGC + 1 )
+ } CorDebugGCType;
+
+typedef struct _COR_HEAPINFO
+ {
+ BOOL areGCStructuresValid;
+ DWORD pointerSize;
+ DWORD numHeaps;
+ BOOL concurrent;
+ CorDebugGCType gcType;
+ } COR_HEAPINFO;
+
+
+
+extern RPC_IF_HANDLE __MIDL_itf_cordebug_0000_0033_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_cordebug_0000_0033_v0_0_s_ifspec;
+
+#ifndef __ICorDebugHeapSegmentEnum_INTERFACE_DEFINED__
+#define __ICorDebugHeapSegmentEnum_INTERFACE_DEFINED__
+
+/* interface ICorDebugHeapSegmentEnum */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugHeapSegmentEnum;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("A2FA0F8E-D045-11DF-AC8E-CE2ADFD72085")
+ ICorDebugHeapSegmentEnum : public ICorDebugEnum
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE Next(
+ /* [in] */ ULONG celt,
+ /* [length_is][size_is][out] */ COR_SEGMENT segments[ ],
+ /* [out] */ ULONG *pceltFetched) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugHeapSegmentEnumVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugHeapSegmentEnum * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugHeapSegmentEnum * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugHeapSegmentEnum * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Skip )(
+ ICorDebugHeapSegmentEnum * This,
+ /* [in] */ ULONG celt);
+
+ HRESULT ( STDMETHODCALLTYPE *Reset )(
+ ICorDebugHeapSegmentEnum * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Clone )(
+ ICorDebugHeapSegmentEnum * This,
+ /* [out] */ ICorDebugEnum **ppEnum);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCount )(
+ ICorDebugHeapSegmentEnum * This,
+ /* [out] */ ULONG *pcelt);
+
+ HRESULT ( STDMETHODCALLTYPE *Next )(
+ ICorDebugHeapSegmentEnum * This,
+ /* [in] */ ULONG celt,
+ /* [length_is][size_is][out] */ COR_SEGMENT segments[ ],
+ /* [out] */ ULONG *pceltFetched);
+
+ END_INTERFACE
+ } ICorDebugHeapSegmentEnumVtbl;
+
+ interface ICorDebugHeapSegmentEnum
+ {
+ CONST_VTBL struct ICorDebugHeapSegmentEnumVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugHeapSegmentEnum_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugHeapSegmentEnum_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugHeapSegmentEnum_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugHeapSegmentEnum_Skip(This,celt) \
+ ( (This)->lpVtbl -> Skip(This,celt) )
+
+#define ICorDebugHeapSegmentEnum_Reset(This) \
+ ( (This)->lpVtbl -> Reset(This) )
+
+#define ICorDebugHeapSegmentEnum_Clone(This,ppEnum) \
+ ( (This)->lpVtbl -> Clone(This,ppEnum) )
+
+#define ICorDebugHeapSegmentEnum_GetCount(This,pcelt) \
+ ( (This)->lpVtbl -> GetCount(This,pcelt) )
+
+
+#define ICorDebugHeapSegmentEnum_Next(This,celt,segments,pceltFetched) \
+ ( (This)->lpVtbl -> Next(This,celt,segments,pceltFetched) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugHeapSegmentEnum_INTERFACE_DEFINED__ */
+
+
+/* interface __MIDL_itf_cordebug_0000_0034 */
+/* [local] */
+
+typedef
+enum CorGCReferenceType
+ {
+ CorHandleStrong = ( 1 << 0 ) ,
+ CorHandleStrongPinning = ( 1 << 1 ) ,
+ CorHandleWeakShort = ( 1 << 2 ) ,
+ CorHandleWeakLong = ( 1 << 3 ) ,
+ CorHandleWeakRefCount = ( 1 << 4 ) ,
+ CorHandleStrongRefCount = ( 1 << 5 ) ,
+ CorHandleStrongDependent = ( 1 << 6 ) ,
+ CorHandleStrongAsyncPinned = ( 1 << 7 ) ,
+ CorHandleStrongSizedByref = ( 1 << 8 ) ,
+ CorHandleWeakWinRT = ( 1 << 9 ) ,
+ CorReferenceStack = 0x80000001,
+ CorReferenceFinalizer = 80000002,
+ CorHandleStrongOnly = 0x1e3,
+ CorHandleWeakOnly = 0x21c,
+ CorHandleAll = 0x7fffffff
+ } CorGCReferenceType;
+
+#ifndef _DEF_COR_GC_REFERENCE_
+#define _DEF_COR_GC_REFERENCE_
+typedef struct COR_GC_REFERENCE
+ {
+ ICorDebugAppDomain *Domain;
+ ICorDebugValue *Location;
+ CorGCReferenceType Type;
+ UINT64 ExtraData;
+ } COR_GC_REFERENCE;
+
+#endif // _DEF_COR_GC_REFERENCE_
+
+
+extern RPC_IF_HANDLE __MIDL_itf_cordebug_0000_0034_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_cordebug_0000_0034_v0_0_s_ifspec;
+
+#ifndef __ICorDebugGCReferenceEnum_INTERFACE_DEFINED__
+#define __ICorDebugGCReferenceEnum_INTERFACE_DEFINED__
+
+/* interface ICorDebugGCReferenceEnum */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugGCReferenceEnum;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("7F3C24D3-7E1D-4245-AC3A-F72F8859C80C")
+ ICorDebugGCReferenceEnum : public ICorDebugEnum
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE Next(
+ /* [in] */ ULONG celt,
+ /* [length_is][size_is][out] */ COR_GC_REFERENCE roots[ ],
+ /* [out] */ ULONG *pceltFetched) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugGCReferenceEnumVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugGCReferenceEnum * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugGCReferenceEnum * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugGCReferenceEnum * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Skip )(
+ ICorDebugGCReferenceEnum * This,
+ /* [in] */ ULONG celt);
+
+ HRESULT ( STDMETHODCALLTYPE *Reset )(
+ ICorDebugGCReferenceEnum * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Clone )(
+ ICorDebugGCReferenceEnum * This,
+ /* [out] */ ICorDebugEnum **ppEnum);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCount )(
+ ICorDebugGCReferenceEnum * This,
+ /* [out] */ ULONG *pcelt);
+
+ HRESULT ( STDMETHODCALLTYPE *Next )(
+ ICorDebugGCReferenceEnum * This,
+ /* [in] */ ULONG celt,
+ /* [length_is][size_is][out] */ COR_GC_REFERENCE roots[ ],
+ /* [out] */ ULONG *pceltFetched);
+
+ END_INTERFACE
+ } ICorDebugGCReferenceEnumVtbl;
+
+ interface ICorDebugGCReferenceEnum
+ {
+ CONST_VTBL struct ICorDebugGCReferenceEnumVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugGCReferenceEnum_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugGCReferenceEnum_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugGCReferenceEnum_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugGCReferenceEnum_Skip(This,celt) \
+ ( (This)->lpVtbl -> Skip(This,celt) )
+
+#define ICorDebugGCReferenceEnum_Reset(This) \
+ ( (This)->lpVtbl -> Reset(This) )
+
+#define ICorDebugGCReferenceEnum_Clone(This,ppEnum) \
+ ( (This)->lpVtbl -> Clone(This,ppEnum) )
+
+#define ICorDebugGCReferenceEnum_GetCount(This,pcelt) \
+ ( (This)->lpVtbl -> GetCount(This,pcelt) )
+
+
+#define ICorDebugGCReferenceEnum_Next(This,celt,roots,pceltFetched) \
+ ( (This)->lpVtbl -> Next(This,celt,roots,pceltFetched) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugGCReferenceEnum_INTERFACE_DEFINED__ */
+
+
+/* interface __MIDL_itf_cordebug_0000_0035 */
+/* [local] */
+
+#ifndef _DEF_COR_ARRAY_LAYOUT_
+#define _DEF_COR_ARRAY_LAYOUT_
+typedef struct COR_ARRAY_LAYOUT
+ {
+ COR_TYPEID componentID;
+ CorElementType componentType;
+ ULONG32 firstElementOffset;
+ ULONG32 elementSize;
+ ULONG32 countOffset;
+ ULONG32 rankSize;
+ ULONG32 numRanks;
+ ULONG32 rankOffset;
+ } COR_ARRAY_LAYOUT;
+
+#endif // _DEF_COR_ARRAY_LAYOUT_
+#ifndef _DEF_COR_TYPE_LAYOUT_
+#define _DEF_COR_TYPE_LAYOUT_
+typedef struct COR_TYPE_LAYOUT
+ {
+ COR_TYPEID parentID;
+ ULONG32 objectSize;
+ ULONG32 numFields;
+ ULONG32 boxOffset;
+ CorElementType type;
+ } COR_TYPE_LAYOUT;
+
+#endif // _DEF_COR_TYPE_LAYOUT_
+#ifndef _DEF_COR_FIELD_
+#define _DEF_COR_FIELD_
+typedef struct COR_FIELD
+ {
+ mdFieldDef token;
+ ULONG32 offset;
+ COR_TYPEID id;
+ CorElementType fieldType;
+ } COR_FIELD;
+
+#endif // _DEF_COR_FIELD_
+#pragma warning(push)
+#pragma warning(disable:28718)
+
+
+extern RPC_IF_HANDLE __MIDL_itf_cordebug_0000_0035_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_cordebug_0000_0035_v0_0_s_ifspec;
+
+#ifndef __ICorDebugProcess_INTERFACE_DEFINED__
+#define __ICorDebugProcess_INTERFACE_DEFINED__
+
+/* interface ICorDebugProcess */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugProcess;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("3d6f5f64-7538-11d3-8d5b-00104b35e7ef")
+ ICorDebugProcess : public ICorDebugController
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetID(
+ /* [out] */ DWORD *pdwProcessId) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetHandle(
+ /* [out] */ HPROCESS *phProcessHandle) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetThread(
+ /* [in] */ DWORD dwThreadId,
+ /* [out] */ ICorDebugThread **ppThread) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnumerateObjects(
+ /* [out] */ ICorDebugObjectEnum **ppObjects) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE IsTransitionStub(
+ /* [in] */ CORDB_ADDRESS address,
+ /* [out] */ BOOL *pbTransitionStub) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE IsOSSuspended(
+ /* [in] */ DWORD threadID,
+ /* [out] */ BOOL *pbSuspended) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetThreadContext(
+ /* [in] */ DWORD threadID,
+ /* [in] */ ULONG32 contextSize,
+ /* [size_is][length_is][out][in] */ BYTE context[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetThreadContext(
+ /* [in] */ DWORD threadID,
+ /* [in] */ ULONG32 contextSize,
+ /* [size_is][length_is][in] */ BYTE context[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ReadMemory(
+ /* [in] */ CORDB_ADDRESS address,
+ /* [in] */ DWORD size,
+ /* [length_is][size_is][out] */ BYTE buffer[ ],
+ /* [out] */ SIZE_T *read) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE WriteMemory(
+ /* [in] */ CORDB_ADDRESS address,
+ /* [in] */ DWORD size,
+ /* [size_is][in] */ BYTE buffer[ ],
+ /* [out] */ SIZE_T *written) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ClearCurrentException(
+ /* [in] */ DWORD threadID) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnableLogMessages(
+ /* [in] */ BOOL fOnOff) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ModifyLogSwitch(
+ /* [annotation][in] */
+ _In_ WCHAR *pLogSwitchName,
+ /* [in] */ LONG lLevel) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnumerateAppDomains(
+ /* [out] */ ICorDebugAppDomainEnum **ppAppDomains) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetObject(
+ /* [out] */ ICorDebugValue **ppObject) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ThreadForFiberCookie(
+ /* [in] */ DWORD fiberCookie,
+ /* [out] */ ICorDebugThread **ppThread) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetHelperThreadID(
+ /* [out] */ DWORD *pThreadID) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugProcessVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugProcess * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugProcess * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugProcess * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Stop )(
+ ICorDebugProcess * This,
+ /* [in] */ DWORD dwTimeoutIgnored);
+
+ HRESULT ( STDMETHODCALLTYPE *Continue )(
+ ICorDebugProcess * This,
+ /* [in] */ BOOL fIsOutOfBand);
+
+ HRESULT ( STDMETHODCALLTYPE *IsRunning )(
+ ICorDebugProcess * This,
+ /* [out] */ BOOL *pbRunning);
+
+ HRESULT ( STDMETHODCALLTYPE *HasQueuedCallbacks )(
+ ICorDebugProcess * This,
+ /* [in] */ ICorDebugThread *pThread,
+ /* [out] */ BOOL *pbQueued);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumerateThreads )(
+ ICorDebugProcess * This,
+ /* [out] */ ICorDebugThreadEnum **ppThreads);
+
+ HRESULT ( STDMETHODCALLTYPE *SetAllThreadsDebugState )(
+ ICorDebugProcess * This,
+ /* [in] */ CorDebugThreadState state,
+ /* [in] */ ICorDebugThread *pExceptThisThread);
+
+ HRESULT ( STDMETHODCALLTYPE *Detach )(
+ ICorDebugProcess * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Terminate )(
+ ICorDebugProcess * This,
+ /* [in] */ UINT exitCode);
+
+ HRESULT ( STDMETHODCALLTYPE *CanCommitChanges )(
+ ICorDebugProcess * This,
+ /* [in] */ ULONG cSnapshots,
+ /* [size_is][in] */ ICorDebugEditAndContinueSnapshot *pSnapshots[ ],
+ /* [out] */ ICorDebugErrorInfoEnum **pError);
+
+ HRESULT ( STDMETHODCALLTYPE *CommitChanges )(
+ ICorDebugProcess * This,
+ /* [in] */ ULONG cSnapshots,
+ /* [size_is][in] */ ICorDebugEditAndContinueSnapshot *pSnapshots[ ],
+ /* [out] */ ICorDebugErrorInfoEnum **pError);
+
+ HRESULT ( STDMETHODCALLTYPE *GetID )(
+ ICorDebugProcess * This,
+ /* [out] */ DWORD *pdwProcessId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetHandle )(
+ ICorDebugProcess * This,
+ /* [out] */ HPROCESS *phProcessHandle);
+
+ HRESULT ( STDMETHODCALLTYPE *GetThread )(
+ ICorDebugProcess * This,
+ /* [in] */ DWORD dwThreadId,
+ /* [out] */ ICorDebugThread **ppThread);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumerateObjects )(
+ ICorDebugProcess * This,
+ /* [out] */ ICorDebugObjectEnum **ppObjects);
+
+ HRESULT ( STDMETHODCALLTYPE *IsTransitionStub )(
+ ICorDebugProcess * This,
+ /* [in] */ CORDB_ADDRESS address,
+ /* [out] */ BOOL *pbTransitionStub);
+
+ HRESULT ( STDMETHODCALLTYPE *IsOSSuspended )(
+ ICorDebugProcess * This,
+ /* [in] */ DWORD threadID,
+ /* [out] */ BOOL *pbSuspended);
+
+ HRESULT ( STDMETHODCALLTYPE *GetThreadContext )(
+ ICorDebugProcess * This,
+ /* [in] */ DWORD threadID,
+ /* [in] */ ULONG32 contextSize,
+ /* [size_is][length_is][out][in] */ BYTE context[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *SetThreadContext )(
+ ICorDebugProcess * This,
+ /* [in] */ DWORD threadID,
+ /* [in] */ ULONG32 contextSize,
+ /* [size_is][length_is][in] */ BYTE context[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *ReadMemory )(
+ ICorDebugProcess * This,
+ /* [in] */ CORDB_ADDRESS address,
+ /* [in] */ DWORD size,
+ /* [length_is][size_is][out] */ BYTE buffer[ ],
+ /* [out] */ SIZE_T *read);
+
+ HRESULT ( STDMETHODCALLTYPE *WriteMemory )(
+ ICorDebugProcess * This,
+ /* [in] */ CORDB_ADDRESS address,
+ /* [in] */ DWORD size,
+ /* [size_is][in] */ BYTE buffer[ ],
+ /* [out] */ SIZE_T *written);
+
+ HRESULT ( STDMETHODCALLTYPE *ClearCurrentException )(
+ ICorDebugProcess * This,
+ /* [in] */ DWORD threadID);
+
+ HRESULT ( STDMETHODCALLTYPE *EnableLogMessages )(
+ ICorDebugProcess * This,
+ /* [in] */ BOOL fOnOff);
+
+ HRESULT ( STDMETHODCALLTYPE *ModifyLogSwitch )(
+ ICorDebugProcess * This,
+ /* [annotation][in] */
+ _In_ WCHAR *pLogSwitchName,
+ /* [in] */ LONG lLevel);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumerateAppDomains )(
+ ICorDebugProcess * This,
+ /* [out] */ ICorDebugAppDomainEnum **ppAppDomains);
+
+ HRESULT ( STDMETHODCALLTYPE *GetObject )(
+ ICorDebugProcess * This,
+ /* [out] */ ICorDebugValue **ppObject);
+
+ HRESULT ( STDMETHODCALLTYPE *ThreadForFiberCookie )(
+ ICorDebugProcess * This,
+ /* [in] */ DWORD fiberCookie,
+ /* [out] */ ICorDebugThread **ppThread);
+
+ HRESULT ( STDMETHODCALLTYPE *GetHelperThreadID )(
+ ICorDebugProcess * This,
+ /* [out] */ DWORD *pThreadID);
+
+ END_INTERFACE
+ } ICorDebugProcessVtbl;
+
+ interface ICorDebugProcess
+ {
+ CONST_VTBL struct ICorDebugProcessVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugProcess_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugProcess_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugProcess_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugProcess_Stop(This,dwTimeoutIgnored) \
+ ( (This)->lpVtbl -> Stop(This,dwTimeoutIgnored) )
+
+#define ICorDebugProcess_Continue(This,fIsOutOfBand) \
+ ( (This)->lpVtbl -> Continue(This,fIsOutOfBand) )
+
+#define ICorDebugProcess_IsRunning(This,pbRunning) \
+ ( (This)->lpVtbl -> IsRunning(This,pbRunning) )
+
+#define ICorDebugProcess_HasQueuedCallbacks(This,pThread,pbQueued) \
+ ( (This)->lpVtbl -> HasQueuedCallbacks(This,pThread,pbQueued) )
+
+#define ICorDebugProcess_EnumerateThreads(This,ppThreads) \
+ ( (This)->lpVtbl -> EnumerateThreads(This,ppThreads) )
+
+#define ICorDebugProcess_SetAllThreadsDebugState(This,state,pExceptThisThread) \
+ ( (This)->lpVtbl -> SetAllThreadsDebugState(This,state,pExceptThisThread) )
+
+#define ICorDebugProcess_Detach(This) \
+ ( (This)->lpVtbl -> Detach(This) )
+
+#define ICorDebugProcess_Terminate(This,exitCode) \
+ ( (This)->lpVtbl -> Terminate(This,exitCode) )
+
+#define ICorDebugProcess_CanCommitChanges(This,cSnapshots,pSnapshots,pError) \
+ ( (This)->lpVtbl -> CanCommitChanges(This,cSnapshots,pSnapshots,pError) )
+
+#define ICorDebugProcess_CommitChanges(This,cSnapshots,pSnapshots,pError) \
+ ( (This)->lpVtbl -> CommitChanges(This,cSnapshots,pSnapshots,pError) )
+
+
+#define ICorDebugProcess_GetID(This,pdwProcessId) \
+ ( (This)->lpVtbl -> GetID(This,pdwProcessId) )
+
+#define ICorDebugProcess_GetHandle(This,phProcessHandle) \
+ ( (This)->lpVtbl -> GetHandle(This,phProcessHandle) )
+
+#define ICorDebugProcess_GetThread(This,dwThreadId,ppThread) \
+ ( (This)->lpVtbl -> GetThread(This,dwThreadId,ppThread) )
+
+#define ICorDebugProcess_EnumerateObjects(This,ppObjects) \
+ ( (This)->lpVtbl -> EnumerateObjects(This,ppObjects) )
+
+#define ICorDebugProcess_IsTransitionStub(This,address,pbTransitionStub) \
+ ( (This)->lpVtbl -> IsTransitionStub(This,address,pbTransitionStub) )
+
+#define ICorDebugProcess_IsOSSuspended(This,threadID,pbSuspended) \
+ ( (This)->lpVtbl -> IsOSSuspended(This,threadID,pbSuspended) )
+
+#define ICorDebugProcess_GetThreadContext(This,threadID,contextSize,context) \
+ ( (This)->lpVtbl -> GetThreadContext(This,threadID,contextSize,context) )
+
+#define ICorDebugProcess_SetThreadContext(This,threadID,contextSize,context) \
+ ( (This)->lpVtbl -> SetThreadContext(This,threadID,contextSize,context) )
+
+#define ICorDebugProcess_ReadMemory(This,address,size,buffer,read) \
+ ( (This)->lpVtbl -> ReadMemory(This,address,size,buffer,read) )
+
+#define ICorDebugProcess_WriteMemory(This,address,size,buffer,written) \
+ ( (This)->lpVtbl -> WriteMemory(This,address,size,buffer,written) )
+
+#define ICorDebugProcess_ClearCurrentException(This,threadID) \
+ ( (This)->lpVtbl -> ClearCurrentException(This,threadID) )
+
+#define ICorDebugProcess_EnableLogMessages(This,fOnOff) \
+ ( (This)->lpVtbl -> EnableLogMessages(This,fOnOff) )
+
+#define ICorDebugProcess_ModifyLogSwitch(This,pLogSwitchName,lLevel) \
+ ( (This)->lpVtbl -> ModifyLogSwitch(This,pLogSwitchName,lLevel) )
+
+#define ICorDebugProcess_EnumerateAppDomains(This,ppAppDomains) \
+ ( (This)->lpVtbl -> EnumerateAppDomains(This,ppAppDomains) )
+
+#define ICorDebugProcess_GetObject(This,ppObject) \
+ ( (This)->lpVtbl -> GetObject(This,ppObject) )
+
+#define ICorDebugProcess_ThreadForFiberCookie(This,fiberCookie,ppThread) \
+ ( (This)->lpVtbl -> ThreadForFiberCookie(This,fiberCookie,ppThread) )
+
+#define ICorDebugProcess_GetHelperThreadID(This,pThreadID) \
+ ( (This)->lpVtbl -> GetHelperThreadID(This,pThreadID) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugProcess_INTERFACE_DEFINED__ */
+
+
+/* interface __MIDL_itf_cordebug_0000_0036 */
+/* [local] */
+
+#pragma warning(pop)
+
+
+extern RPC_IF_HANDLE __MIDL_itf_cordebug_0000_0036_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_cordebug_0000_0036_v0_0_s_ifspec;
+
+#ifndef __ICorDebugProcess2_INTERFACE_DEFINED__
+#define __ICorDebugProcess2_INTERFACE_DEFINED__
+
+/* interface ICorDebugProcess2 */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugProcess2;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("AD1B3588-0EF0-4744-A496-AA09A9F80371")
+ ICorDebugProcess2 : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetThreadForTaskID(
+ /* [in] */ TASKID taskid,
+ /* [out] */ ICorDebugThread2 **ppThread) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetVersion(
+ /* [out] */ COR_VERSION *version) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetUnmanagedBreakpoint(
+ /* [in] */ CORDB_ADDRESS address,
+ /* [in] */ ULONG32 bufsize,
+ /* [length_is][size_is][out] */ BYTE buffer[ ],
+ /* [out] */ ULONG32 *bufLen) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ClearUnmanagedBreakpoint(
+ /* [in] */ CORDB_ADDRESS address) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetDesiredNGENCompilerFlags(
+ /* [in] */ DWORD pdwFlags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetDesiredNGENCompilerFlags(
+ /* [out] */ DWORD *pdwFlags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetReferenceValueFromGCHandle(
+ /* [in] */ UINT_PTR handle,
+ /* [out] */ ICorDebugReferenceValue **pOutValue) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugProcess2Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugProcess2 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugProcess2 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugProcess2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetThreadForTaskID )(
+ ICorDebugProcess2 * This,
+ /* [in] */ TASKID taskid,
+ /* [out] */ ICorDebugThread2 **ppThread);
+
+ HRESULT ( STDMETHODCALLTYPE *GetVersion )(
+ ICorDebugProcess2 * This,
+ /* [out] */ COR_VERSION *version);
+
+ HRESULT ( STDMETHODCALLTYPE *SetUnmanagedBreakpoint )(
+ ICorDebugProcess2 * This,
+ /* [in] */ CORDB_ADDRESS address,
+ /* [in] */ ULONG32 bufsize,
+ /* [length_is][size_is][out] */ BYTE buffer[ ],
+ /* [out] */ ULONG32 *bufLen);
+
+ HRESULT ( STDMETHODCALLTYPE *ClearUnmanagedBreakpoint )(
+ ICorDebugProcess2 * This,
+ /* [in] */ CORDB_ADDRESS address);
+
+ HRESULT ( STDMETHODCALLTYPE *SetDesiredNGENCompilerFlags )(
+ ICorDebugProcess2 * This,
+ /* [in] */ DWORD pdwFlags);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDesiredNGENCompilerFlags )(
+ ICorDebugProcess2 * This,
+ /* [out] */ DWORD *pdwFlags);
+
+ HRESULT ( STDMETHODCALLTYPE *GetReferenceValueFromGCHandle )(
+ ICorDebugProcess2 * This,
+ /* [in] */ UINT_PTR handle,
+ /* [out] */ ICorDebugReferenceValue **pOutValue);
+
+ END_INTERFACE
+ } ICorDebugProcess2Vtbl;
+
+ interface ICorDebugProcess2
+ {
+ CONST_VTBL struct ICorDebugProcess2Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugProcess2_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugProcess2_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugProcess2_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugProcess2_GetThreadForTaskID(This,taskid,ppThread) \
+ ( (This)->lpVtbl -> GetThreadForTaskID(This,taskid,ppThread) )
+
+#define ICorDebugProcess2_GetVersion(This,version) \
+ ( (This)->lpVtbl -> GetVersion(This,version) )
+
+#define ICorDebugProcess2_SetUnmanagedBreakpoint(This,address,bufsize,buffer,bufLen) \
+ ( (This)->lpVtbl -> SetUnmanagedBreakpoint(This,address,bufsize,buffer,bufLen) )
+
+#define ICorDebugProcess2_ClearUnmanagedBreakpoint(This,address) \
+ ( (This)->lpVtbl -> ClearUnmanagedBreakpoint(This,address) )
+
+#define ICorDebugProcess2_SetDesiredNGENCompilerFlags(This,pdwFlags) \
+ ( (This)->lpVtbl -> SetDesiredNGENCompilerFlags(This,pdwFlags) )
+
+#define ICorDebugProcess2_GetDesiredNGENCompilerFlags(This,pdwFlags) \
+ ( (This)->lpVtbl -> GetDesiredNGENCompilerFlags(This,pdwFlags) )
+
+#define ICorDebugProcess2_GetReferenceValueFromGCHandle(This,handle,pOutValue) \
+ ( (This)->lpVtbl -> GetReferenceValueFromGCHandle(This,handle,pOutValue) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugProcess2_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugProcess3_INTERFACE_DEFINED__
+#define __ICorDebugProcess3_INTERFACE_DEFINED__
+
+/* interface ICorDebugProcess3 */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugProcess3;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("2EE06488-C0D4-42B1-B26D-F3795EF606FB")
+ ICorDebugProcess3 : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE SetEnableCustomNotification(
+ ICorDebugClass *pClass,
+ BOOL fEnable) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugProcess3Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugProcess3 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugProcess3 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugProcess3 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *SetEnableCustomNotification )(
+ ICorDebugProcess3 * This,
+ ICorDebugClass *pClass,
+ BOOL fEnable);
+
+ END_INTERFACE
+ } ICorDebugProcess3Vtbl;
+
+ interface ICorDebugProcess3
+ {
+ CONST_VTBL struct ICorDebugProcess3Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugProcess3_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugProcess3_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugProcess3_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugProcess3_SetEnableCustomNotification(This,pClass,fEnable) \
+ ( (This)->lpVtbl -> SetEnableCustomNotification(This,pClass,fEnable) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugProcess3_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugProcess5_INTERFACE_DEFINED__
+#define __ICorDebugProcess5_INTERFACE_DEFINED__
+
+/* interface ICorDebugProcess5 */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugProcess5;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("21e9d9c0-fcb8-11df-8cff-0800200c9a66")
+ ICorDebugProcess5 : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetGCHeapInformation(
+ /* [out] */ COR_HEAPINFO *pHeapInfo) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnumerateHeap(
+ /* [out] */ ICorDebugHeapEnum **ppObjects) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnumerateHeapRegions(
+ /* [out] */ ICorDebugHeapSegmentEnum **ppRegions) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetObject(
+ /* [in] */ CORDB_ADDRESS addr,
+ /* [out] */ ICorDebugObjectValue **pObject) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnumerateGCReferences(
+ /* [in] */ BOOL enumerateWeakReferences,
+ /* [out] */ ICorDebugGCReferenceEnum **ppEnum) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnumerateHandles(
+ /* [in] */ CorGCReferenceType types,
+ /* [out] */ ICorDebugGCReferenceEnum **ppEnum) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetTypeID(
+ /* [in] */ CORDB_ADDRESS obj,
+ /* [out] */ COR_TYPEID *pId) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetTypeForTypeID(
+ /* [in] */ COR_TYPEID id,
+ /* [out] */ ICorDebugType **ppType) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetArrayLayout(
+ /* [in] */ COR_TYPEID id,
+ /* [out] */ COR_ARRAY_LAYOUT *pLayout) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetTypeLayout(
+ /* [in] */ COR_TYPEID id,
+ /* [out] */ COR_TYPE_LAYOUT *pLayout) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetTypeFields(
+ /* [in] */ COR_TYPEID id,
+ ULONG32 celt,
+ COR_FIELD fields[ ],
+ ULONG32 *pceltNeeded) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnableNGENPolicy(
+ /* [in] */ CorDebugNGENPolicy ePolicy) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugProcess5Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugProcess5 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugProcess5 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugProcess5 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetGCHeapInformation )(
+ ICorDebugProcess5 * This,
+ /* [out] */ COR_HEAPINFO *pHeapInfo);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumerateHeap )(
+ ICorDebugProcess5 * This,
+ /* [out] */ ICorDebugHeapEnum **ppObjects);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumerateHeapRegions )(
+ ICorDebugProcess5 * This,
+ /* [out] */ ICorDebugHeapSegmentEnum **ppRegions);
+
+ HRESULT ( STDMETHODCALLTYPE *GetObject )(
+ ICorDebugProcess5 * This,
+ /* [in] */ CORDB_ADDRESS addr,
+ /* [out] */ ICorDebugObjectValue **pObject);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumerateGCReferences )(
+ ICorDebugProcess5 * This,
+ /* [in] */ BOOL enumerateWeakReferences,
+ /* [out] */ ICorDebugGCReferenceEnum **ppEnum);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumerateHandles )(
+ ICorDebugProcess5 * This,
+ /* [in] */ CorGCReferenceType types,
+ /* [out] */ ICorDebugGCReferenceEnum **ppEnum);
+
+ HRESULT ( STDMETHODCALLTYPE *GetTypeID )(
+ ICorDebugProcess5 * This,
+ /* [in] */ CORDB_ADDRESS obj,
+ /* [out] */ COR_TYPEID *pId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetTypeForTypeID )(
+ ICorDebugProcess5 * This,
+ /* [in] */ COR_TYPEID id,
+ /* [out] */ ICorDebugType **ppType);
+
+ HRESULT ( STDMETHODCALLTYPE *GetArrayLayout )(
+ ICorDebugProcess5 * This,
+ /* [in] */ COR_TYPEID id,
+ /* [out] */ COR_ARRAY_LAYOUT *pLayout);
+
+ HRESULT ( STDMETHODCALLTYPE *GetTypeLayout )(
+ ICorDebugProcess5 * This,
+ /* [in] */ COR_TYPEID id,
+ /* [out] */ COR_TYPE_LAYOUT *pLayout);
+
+ HRESULT ( STDMETHODCALLTYPE *GetTypeFields )(
+ ICorDebugProcess5 * This,
+ /* [in] */ COR_TYPEID id,
+ ULONG32 celt,
+ COR_FIELD fields[ ],
+ ULONG32 *pceltNeeded);
+
+ HRESULT ( STDMETHODCALLTYPE *EnableNGENPolicy )(
+ ICorDebugProcess5 * This,
+ /* [in] */ CorDebugNGENPolicy ePolicy);
+
+ END_INTERFACE
+ } ICorDebugProcess5Vtbl;
+
+ interface ICorDebugProcess5
+ {
+ CONST_VTBL struct ICorDebugProcess5Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugProcess5_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugProcess5_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugProcess5_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugProcess5_GetGCHeapInformation(This,pHeapInfo) \
+ ( (This)->lpVtbl -> GetGCHeapInformation(This,pHeapInfo) )
+
+#define ICorDebugProcess5_EnumerateHeap(This,ppObjects) \
+ ( (This)->lpVtbl -> EnumerateHeap(This,ppObjects) )
+
+#define ICorDebugProcess5_EnumerateHeapRegions(This,ppRegions) \
+ ( (This)->lpVtbl -> EnumerateHeapRegions(This,ppRegions) )
+
+#define ICorDebugProcess5_GetObject(This,addr,pObject) \
+ ( (This)->lpVtbl -> GetObject(This,addr,pObject) )
+
+#define ICorDebugProcess5_EnumerateGCReferences(This,enumerateWeakReferences,ppEnum) \
+ ( (This)->lpVtbl -> EnumerateGCReferences(This,enumerateWeakReferences,ppEnum) )
+
+#define ICorDebugProcess5_EnumerateHandles(This,types,ppEnum) \
+ ( (This)->lpVtbl -> EnumerateHandles(This,types,ppEnum) )
+
+#define ICorDebugProcess5_GetTypeID(This,obj,pId) \
+ ( (This)->lpVtbl -> GetTypeID(This,obj,pId) )
+
+#define ICorDebugProcess5_GetTypeForTypeID(This,id,ppType) \
+ ( (This)->lpVtbl -> GetTypeForTypeID(This,id,ppType) )
+
+#define ICorDebugProcess5_GetArrayLayout(This,id,pLayout) \
+ ( (This)->lpVtbl -> GetArrayLayout(This,id,pLayout) )
+
+#define ICorDebugProcess5_GetTypeLayout(This,id,pLayout) \
+ ( (This)->lpVtbl -> GetTypeLayout(This,id,pLayout) )
+
+#define ICorDebugProcess5_GetTypeFields(This,id,celt,fields,pceltNeeded) \
+ ( (This)->lpVtbl -> GetTypeFields(This,id,celt,fields,pceltNeeded) )
+
+#define ICorDebugProcess5_EnableNGENPolicy(This,ePolicy) \
+ ( (This)->lpVtbl -> EnableNGENPolicy(This,ePolicy) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugProcess5_INTERFACE_DEFINED__ */
+
+
+/* interface __MIDL_itf_cordebug_0000_0039 */
+/* [local] */
+
+typedef
+enum CorDebugRecordFormat
+ {
+ FORMAT_WINDOWS_EXCEPTIONRECORD32 = 1,
+ FORMAT_WINDOWS_EXCEPTIONRECORD64 = 2
+ } CorDebugRecordFormat;
+
+typedef
+enum CorDebugDecodeEventFlagsWindows
+ {
+ IS_FIRST_CHANCE = 1
+ } CorDebugDecodeEventFlagsWindows;
+
+typedef
+enum CorDebugDebugEventKind
+ {
+ DEBUG_EVENT_KIND_MODULE_LOADED = 1,
+ DEBUG_EVENT_KIND_MODULE_UNLOADED = 2,
+ DEBUG_EVENT_KIND_MANAGED_EXCEPTION_FIRST_CHANCE = 3,
+ DEBUG_EVENT_KIND_MANAGED_EXCEPTION_USER_FIRST_CHANCE = 4,
+ DEBUG_EVENT_KIND_MANAGED_EXCEPTION_CATCH_HANDLER_FOUND = 5,
+ DEBUG_EVENT_KIND_MANAGED_EXCEPTION_UNHANDLED = 6
+ } CorDebugDebugEventKind;
+
+typedef
+enum CorDebugStateChange
+ {
+ PROCESS_RUNNING = 0x1,
+ FLUSH_ALL = 0x2
+ } CorDebugStateChange;
+
+
+
+extern RPC_IF_HANDLE __MIDL_itf_cordebug_0000_0039_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_cordebug_0000_0039_v0_0_s_ifspec;
+
+#ifndef __ICorDebugDebugEvent_INTERFACE_DEFINED__
+#define __ICorDebugDebugEvent_INTERFACE_DEFINED__
+
+/* interface ICorDebugDebugEvent */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugDebugEvent;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("41BD395D-DE99-48F1-BF7A-CC0F44A6D281")
+ ICorDebugDebugEvent : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetEventKind(
+ /* [out] */ CorDebugDebugEventKind *pDebugEventKind) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetThread(
+ /* [out] */ ICorDebugThread **ppThread) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugDebugEventVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugDebugEvent * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugDebugEvent * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugDebugEvent * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetEventKind )(
+ ICorDebugDebugEvent * This,
+ /* [out] */ CorDebugDebugEventKind *pDebugEventKind);
+
+ HRESULT ( STDMETHODCALLTYPE *GetThread )(
+ ICorDebugDebugEvent * This,
+ /* [out] */ ICorDebugThread **ppThread);
+
+ END_INTERFACE
+ } ICorDebugDebugEventVtbl;
+
+ interface ICorDebugDebugEvent
+ {
+ CONST_VTBL struct ICorDebugDebugEventVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugDebugEvent_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugDebugEvent_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugDebugEvent_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugDebugEvent_GetEventKind(This,pDebugEventKind) \
+ ( (This)->lpVtbl -> GetEventKind(This,pDebugEventKind) )
+
+#define ICorDebugDebugEvent_GetThread(This,ppThread) \
+ ( (This)->lpVtbl -> GetThread(This,ppThread) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugDebugEvent_INTERFACE_DEFINED__ */
+
+
+/* interface __MIDL_itf_cordebug_0000_0040 */
+/* [local] */
+
+typedef
+enum CorDebugCodeInvokeKind
+ {
+ CODE_INVOKE_KIND_NONE = 0,
+ CODE_INVOKE_KIND_RETURN = ( CODE_INVOKE_KIND_NONE + 1 ) ,
+ CODE_INVOKE_KIND_TAILCALL = ( CODE_INVOKE_KIND_RETURN + 1 )
+ } CorDebugCodeInvokeKind;
+
+typedef
+enum CorDebugCodeInvokePurpose
+ {
+ CODE_INVOKE_PURPOSE_NONE = 0,
+ CODE_INVOKE_PURPOSE_NATIVE_TO_MANAGED_TRANSITION = ( CODE_INVOKE_PURPOSE_NONE + 1 ) ,
+ CODE_INVOKE_PURPOSE_CLASS_INIT = ( CODE_INVOKE_PURPOSE_NATIVE_TO_MANAGED_TRANSITION + 1 ) ,
+ CODE_INVOKE_PURPOSE_INTERFACE_DISPATCH = ( CODE_INVOKE_PURPOSE_CLASS_INIT + 1 )
+ } CorDebugCodeInvokePurpose;
+
+
+
+extern RPC_IF_HANDLE __MIDL_itf_cordebug_0000_0040_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_cordebug_0000_0040_v0_0_s_ifspec;
+
+#ifndef __ICorDebugProcess6_INTERFACE_DEFINED__
+#define __ICorDebugProcess6_INTERFACE_DEFINED__
+
+/* interface ICorDebugProcess6 */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugProcess6;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("11588775-7205-4CEB-A41A-93753C3153E9")
+ ICorDebugProcess6 : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE DecodeEvent(
+ /* [size_is][length_is][in] */ const BYTE pRecord[ ],
+ /* [in] */ DWORD countBytes,
+ /* [in] */ CorDebugRecordFormat format,
+ /* [in] */ DWORD dwFlags,
+ /* [in] */ DWORD dwThreadId,
+ /* [out] */ ICorDebugDebugEvent **ppEvent) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ProcessStateChanged(
+ /* [in] */ CorDebugStateChange change) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetCode(
+ /* [in] */ CORDB_ADDRESS codeAddress,
+ /* [out] */ ICorDebugCode **ppCode) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnableVirtualModuleSplitting(
+ BOOL enableSplitting) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE MarkDebuggerAttached(
+ BOOL fIsAttached) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetExportStepInfo(
+ /* [in] */ LPCWSTR pszExportName,
+ /* [out] */ CorDebugCodeInvokeKind *pInvokeKind,
+ /* [out] */ CorDebugCodeInvokePurpose *pInvokePurpose) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugProcess6Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugProcess6 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugProcess6 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugProcess6 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *DecodeEvent )(
+ ICorDebugProcess6 * This,
+ /* [size_is][length_is][in] */ const BYTE pRecord[ ],
+ /* [in] */ DWORD countBytes,
+ /* [in] */ CorDebugRecordFormat format,
+ /* [in] */ DWORD dwFlags,
+ /* [in] */ DWORD dwThreadId,
+ /* [out] */ ICorDebugDebugEvent **ppEvent);
+
+ HRESULT ( STDMETHODCALLTYPE *ProcessStateChanged )(
+ ICorDebugProcess6 * This,
+ /* [in] */ CorDebugStateChange change);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCode )(
+ ICorDebugProcess6 * This,
+ /* [in] */ CORDB_ADDRESS codeAddress,
+ /* [out] */ ICorDebugCode **ppCode);
+
+ HRESULT ( STDMETHODCALLTYPE *EnableVirtualModuleSplitting )(
+ ICorDebugProcess6 * This,
+ BOOL enableSplitting);
+
+ HRESULT ( STDMETHODCALLTYPE *MarkDebuggerAttached )(
+ ICorDebugProcess6 * This,
+ BOOL fIsAttached);
+
+ HRESULT ( STDMETHODCALLTYPE *GetExportStepInfo )(
+ ICorDebugProcess6 * This,
+ /* [in] */ LPCWSTR pszExportName,
+ /* [out] */ CorDebugCodeInvokeKind *pInvokeKind,
+ /* [out] */ CorDebugCodeInvokePurpose *pInvokePurpose);
+
+ END_INTERFACE
+ } ICorDebugProcess6Vtbl;
+
+ interface ICorDebugProcess6
+ {
+ CONST_VTBL struct ICorDebugProcess6Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugProcess6_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugProcess6_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugProcess6_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugProcess6_DecodeEvent(This,pRecord,countBytes,format,dwFlags,dwThreadId,ppEvent) \
+ ( (This)->lpVtbl -> DecodeEvent(This,pRecord,countBytes,format,dwFlags,dwThreadId,ppEvent) )
+
+#define ICorDebugProcess6_ProcessStateChanged(This,change) \
+ ( (This)->lpVtbl -> ProcessStateChanged(This,change) )
+
+#define ICorDebugProcess6_GetCode(This,codeAddress,ppCode) \
+ ( (This)->lpVtbl -> GetCode(This,codeAddress,ppCode) )
+
+#define ICorDebugProcess6_EnableVirtualModuleSplitting(This,enableSplitting) \
+ ( (This)->lpVtbl -> EnableVirtualModuleSplitting(This,enableSplitting) )
+
+#define ICorDebugProcess6_MarkDebuggerAttached(This,fIsAttached) \
+ ( (This)->lpVtbl -> MarkDebuggerAttached(This,fIsAttached) )
+
+#define ICorDebugProcess6_GetExportStepInfo(This,pszExportName,pInvokeKind,pInvokePurpose) \
+ ( (This)->lpVtbl -> GetExportStepInfo(This,pszExportName,pInvokeKind,pInvokePurpose) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugProcess6_INTERFACE_DEFINED__ */
+
+
+/* interface __MIDL_itf_cordebug_0000_0041 */
+/* [local] */
+
+typedef
+enum WriteableMetadataUpdateMode
+ {
+ LegacyCompatPolicy = 0,
+ AlwaysShowUpdates = ( LegacyCompatPolicy + 1 )
+ } WriteableMetadataUpdateMode;
+
+
+
+extern RPC_IF_HANDLE __MIDL_itf_cordebug_0000_0041_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_cordebug_0000_0041_v0_0_s_ifspec;
+
+#ifndef __ICorDebugProcess7_INTERFACE_DEFINED__
+#define __ICorDebugProcess7_INTERFACE_DEFINED__
+
+/* interface ICorDebugProcess7 */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugProcess7;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("9B2C54E4-119F-4D6F-B402-527603266D69")
+ ICorDebugProcess7 : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE SetWriteableMetadataUpdateMode(
+ WriteableMetadataUpdateMode flags) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugProcess7Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugProcess7 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugProcess7 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugProcess7 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *SetWriteableMetadataUpdateMode )(
+ ICorDebugProcess7 * This,
+ WriteableMetadataUpdateMode flags);
+
+ END_INTERFACE
+ } ICorDebugProcess7Vtbl;
+
+ interface ICorDebugProcess7
+ {
+ CONST_VTBL struct ICorDebugProcess7Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugProcess7_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugProcess7_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugProcess7_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugProcess7_SetWriteableMetadataUpdateMode(This,flags) \
+ ( (This)->lpVtbl -> SetWriteableMetadataUpdateMode(This,flags) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugProcess7_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugProcess8_INTERFACE_DEFINED__
+#define __ICorDebugProcess8_INTERFACE_DEFINED__
+
+/* interface ICorDebugProcess8 */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugProcess8;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("2E6F28C1-85EB-4141-80AD-0A90944B9639")
+ ICorDebugProcess8 : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE EnableExceptionCallbacksOutsideOfMyCode(
+ /* [in] */ BOOL enableExceptionsOutsideOfJMC) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugProcess8Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugProcess8 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugProcess8 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugProcess8 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *EnableExceptionCallbacksOutsideOfMyCode )(
+ ICorDebugProcess8 * This,
+ /* [in] */ BOOL enableExceptionsOutsideOfJMC);
+
+ END_INTERFACE
+ } ICorDebugProcess8Vtbl;
+
+ interface ICorDebugProcess8
+ {
+ CONST_VTBL struct ICorDebugProcess8Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugProcess8_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugProcess8_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugProcess8_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugProcess8_EnableExceptionCallbacksOutsideOfMyCode(This,enableExceptionsOutsideOfJMC) \
+ ( (This)->lpVtbl -> EnableExceptionCallbacksOutsideOfMyCode(This,enableExceptionsOutsideOfJMC) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugProcess8_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugModuleDebugEvent_INTERFACE_DEFINED__
+#define __ICorDebugModuleDebugEvent_INTERFACE_DEFINED__
+
+/* interface ICorDebugModuleDebugEvent */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugModuleDebugEvent;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("51A15E8D-9FFF-4864-9B87-F4FBDEA747A2")
+ ICorDebugModuleDebugEvent : public ICorDebugDebugEvent
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetModule(
+ /* [out] */ ICorDebugModule **ppModule) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugModuleDebugEventVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugModuleDebugEvent * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugModuleDebugEvent * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugModuleDebugEvent * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetEventKind )(
+ ICorDebugModuleDebugEvent * This,
+ /* [out] */ CorDebugDebugEventKind *pDebugEventKind);
+
+ HRESULT ( STDMETHODCALLTYPE *GetThread )(
+ ICorDebugModuleDebugEvent * This,
+ /* [out] */ ICorDebugThread **ppThread);
+
+ HRESULT ( STDMETHODCALLTYPE *GetModule )(
+ ICorDebugModuleDebugEvent * This,
+ /* [out] */ ICorDebugModule **ppModule);
+
+ END_INTERFACE
+ } ICorDebugModuleDebugEventVtbl;
+
+ interface ICorDebugModuleDebugEvent
+ {
+ CONST_VTBL struct ICorDebugModuleDebugEventVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugModuleDebugEvent_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugModuleDebugEvent_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugModuleDebugEvent_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugModuleDebugEvent_GetEventKind(This,pDebugEventKind) \
+ ( (This)->lpVtbl -> GetEventKind(This,pDebugEventKind) )
+
+#define ICorDebugModuleDebugEvent_GetThread(This,ppThread) \
+ ( (This)->lpVtbl -> GetThread(This,ppThread) )
+
+
+#define ICorDebugModuleDebugEvent_GetModule(This,ppModule) \
+ ( (This)->lpVtbl -> GetModule(This,ppModule) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugModuleDebugEvent_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugExceptionDebugEvent_INTERFACE_DEFINED__
+#define __ICorDebugExceptionDebugEvent_INTERFACE_DEFINED__
+
+/* interface ICorDebugExceptionDebugEvent */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugExceptionDebugEvent;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("AF79EC94-4752-419C-A626-5FB1CC1A5AB7")
+ ICorDebugExceptionDebugEvent : public ICorDebugDebugEvent
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetStackPointer(
+ /* [out] */ CORDB_ADDRESS *pStackPointer) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetNativeIP(
+ /* [out] */ CORDB_ADDRESS *pIP) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetFlags(
+ /* [out] */ CorDebugExceptionFlags *pdwFlags) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugExceptionDebugEventVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugExceptionDebugEvent * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugExceptionDebugEvent * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugExceptionDebugEvent * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetEventKind )(
+ ICorDebugExceptionDebugEvent * This,
+ /* [out] */ CorDebugDebugEventKind *pDebugEventKind);
+
+ HRESULT ( STDMETHODCALLTYPE *GetThread )(
+ ICorDebugExceptionDebugEvent * This,
+ /* [out] */ ICorDebugThread **ppThread);
+
+ HRESULT ( STDMETHODCALLTYPE *GetStackPointer )(
+ ICorDebugExceptionDebugEvent * This,
+ /* [out] */ CORDB_ADDRESS *pStackPointer);
+
+ HRESULT ( STDMETHODCALLTYPE *GetNativeIP )(
+ ICorDebugExceptionDebugEvent * This,
+ /* [out] */ CORDB_ADDRESS *pIP);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFlags )(
+ ICorDebugExceptionDebugEvent * This,
+ /* [out] */ CorDebugExceptionFlags *pdwFlags);
+
+ END_INTERFACE
+ } ICorDebugExceptionDebugEventVtbl;
+
+ interface ICorDebugExceptionDebugEvent
+ {
+ CONST_VTBL struct ICorDebugExceptionDebugEventVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugExceptionDebugEvent_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugExceptionDebugEvent_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugExceptionDebugEvent_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugExceptionDebugEvent_GetEventKind(This,pDebugEventKind) \
+ ( (This)->lpVtbl -> GetEventKind(This,pDebugEventKind) )
+
+#define ICorDebugExceptionDebugEvent_GetThread(This,ppThread) \
+ ( (This)->lpVtbl -> GetThread(This,ppThread) )
+
+
+#define ICorDebugExceptionDebugEvent_GetStackPointer(This,pStackPointer) \
+ ( (This)->lpVtbl -> GetStackPointer(This,pStackPointer) )
+
+#define ICorDebugExceptionDebugEvent_GetNativeIP(This,pIP) \
+ ( (This)->lpVtbl -> GetNativeIP(This,pIP) )
+
+#define ICorDebugExceptionDebugEvent_GetFlags(This,pdwFlags) \
+ ( (This)->lpVtbl -> GetFlags(This,pdwFlags) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugExceptionDebugEvent_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugBreakpoint_INTERFACE_DEFINED__
+#define __ICorDebugBreakpoint_INTERFACE_DEFINED__
+
+/* interface ICorDebugBreakpoint */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugBreakpoint;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("CC7BCAE8-8A68-11d2-983C-0000F808342D")
+ ICorDebugBreakpoint : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE Activate(
+ /* [in] */ BOOL bActive) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE IsActive(
+ /* [out] */ BOOL *pbActive) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugBreakpointVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugBreakpoint * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugBreakpoint * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugBreakpoint * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Activate )(
+ ICorDebugBreakpoint * This,
+ /* [in] */ BOOL bActive);
+
+ HRESULT ( STDMETHODCALLTYPE *IsActive )(
+ ICorDebugBreakpoint * This,
+ /* [out] */ BOOL *pbActive);
+
+ END_INTERFACE
+ } ICorDebugBreakpointVtbl;
+
+ interface ICorDebugBreakpoint
+ {
+ CONST_VTBL struct ICorDebugBreakpointVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugBreakpoint_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugBreakpoint_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugBreakpoint_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugBreakpoint_Activate(This,bActive) \
+ ( (This)->lpVtbl -> Activate(This,bActive) )
+
+#define ICorDebugBreakpoint_IsActive(This,pbActive) \
+ ( (This)->lpVtbl -> IsActive(This,pbActive) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugBreakpoint_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugFunctionBreakpoint_INTERFACE_DEFINED__
+#define __ICorDebugFunctionBreakpoint_INTERFACE_DEFINED__
+
+/* interface ICorDebugFunctionBreakpoint */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugFunctionBreakpoint;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("CC7BCAE9-8A68-11d2-983C-0000F808342D")
+ ICorDebugFunctionBreakpoint : public ICorDebugBreakpoint
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetFunction(
+ /* [out] */ ICorDebugFunction **ppFunction) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetOffset(
+ /* [out] */ ULONG32 *pnOffset) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugFunctionBreakpointVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugFunctionBreakpoint * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugFunctionBreakpoint * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugFunctionBreakpoint * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Activate )(
+ ICorDebugFunctionBreakpoint * This,
+ /* [in] */ BOOL bActive);
+
+ HRESULT ( STDMETHODCALLTYPE *IsActive )(
+ ICorDebugFunctionBreakpoint * This,
+ /* [out] */ BOOL *pbActive);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFunction )(
+ ICorDebugFunctionBreakpoint * This,
+ /* [out] */ ICorDebugFunction **ppFunction);
+
+ HRESULT ( STDMETHODCALLTYPE *GetOffset )(
+ ICorDebugFunctionBreakpoint * This,
+ /* [out] */ ULONG32 *pnOffset);
+
+ END_INTERFACE
+ } ICorDebugFunctionBreakpointVtbl;
+
+ interface ICorDebugFunctionBreakpoint
+ {
+ CONST_VTBL struct ICorDebugFunctionBreakpointVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugFunctionBreakpoint_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugFunctionBreakpoint_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugFunctionBreakpoint_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugFunctionBreakpoint_Activate(This,bActive) \
+ ( (This)->lpVtbl -> Activate(This,bActive) )
+
+#define ICorDebugFunctionBreakpoint_IsActive(This,pbActive) \
+ ( (This)->lpVtbl -> IsActive(This,pbActive) )
+
+
+#define ICorDebugFunctionBreakpoint_GetFunction(This,ppFunction) \
+ ( (This)->lpVtbl -> GetFunction(This,ppFunction) )
+
+#define ICorDebugFunctionBreakpoint_GetOffset(This,pnOffset) \
+ ( (This)->lpVtbl -> GetOffset(This,pnOffset) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugFunctionBreakpoint_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugModuleBreakpoint_INTERFACE_DEFINED__
+#define __ICorDebugModuleBreakpoint_INTERFACE_DEFINED__
+
+/* interface ICorDebugModuleBreakpoint */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugModuleBreakpoint;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("CC7BCAEA-8A68-11d2-983C-0000F808342D")
+ ICorDebugModuleBreakpoint : public ICorDebugBreakpoint
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetModule(
+ /* [out] */ ICorDebugModule **ppModule) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugModuleBreakpointVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugModuleBreakpoint * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugModuleBreakpoint * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugModuleBreakpoint * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Activate )(
+ ICorDebugModuleBreakpoint * This,
+ /* [in] */ BOOL bActive);
+
+ HRESULT ( STDMETHODCALLTYPE *IsActive )(
+ ICorDebugModuleBreakpoint * This,
+ /* [out] */ BOOL *pbActive);
+
+ HRESULT ( STDMETHODCALLTYPE *GetModule )(
+ ICorDebugModuleBreakpoint * This,
+ /* [out] */ ICorDebugModule **ppModule);
+
+ END_INTERFACE
+ } ICorDebugModuleBreakpointVtbl;
+
+ interface ICorDebugModuleBreakpoint
+ {
+ CONST_VTBL struct ICorDebugModuleBreakpointVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugModuleBreakpoint_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugModuleBreakpoint_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugModuleBreakpoint_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugModuleBreakpoint_Activate(This,bActive) \
+ ( (This)->lpVtbl -> Activate(This,bActive) )
+
+#define ICorDebugModuleBreakpoint_IsActive(This,pbActive) \
+ ( (This)->lpVtbl -> IsActive(This,pbActive) )
+
+
+#define ICorDebugModuleBreakpoint_GetModule(This,ppModule) \
+ ( (This)->lpVtbl -> GetModule(This,ppModule) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugModuleBreakpoint_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugValueBreakpoint_INTERFACE_DEFINED__
+#define __ICorDebugValueBreakpoint_INTERFACE_DEFINED__
+
+/* interface ICorDebugValueBreakpoint */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugValueBreakpoint;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("CC7BCAEB-8A68-11d2-983C-0000F808342D")
+ ICorDebugValueBreakpoint : public ICorDebugBreakpoint
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetValue(
+ /* [out] */ ICorDebugValue **ppValue) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugValueBreakpointVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugValueBreakpoint * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugValueBreakpoint * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugValueBreakpoint * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Activate )(
+ ICorDebugValueBreakpoint * This,
+ /* [in] */ BOOL bActive);
+
+ HRESULT ( STDMETHODCALLTYPE *IsActive )(
+ ICorDebugValueBreakpoint * This,
+ /* [out] */ BOOL *pbActive);
+
+ HRESULT ( STDMETHODCALLTYPE *GetValue )(
+ ICorDebugValueBreakpoint * This,
+ /* [out] */ ICorDebugValue **ppValue);
+
+ END_INTERFACE
+ } ICorDebugValueBreakpointVtbl;
+
+ interface ICorDebugValueBreakpoint
+ {
+ CONST_VTBL struct ICorDebugValueBreakpointVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugValueBreakpoint_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugValueBreakpoint_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugValueBreakpoint_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugValueBreakpoint_Activate(This,bActive) \
+ ( (This)->lpVtbl -> Activate(This,bActive) )
+
+#define ICorDebugValueBreakpoint_IsActive(This,pbActive) \
+ ( (This)->lpVtbl -> IsActive(This,pbActive) )
+
+
+#define ICorDebugValueBreakpoint_GetValue(This,ppValue) \
+ ( (This)->lpVtbl -> GetValue(This,ppValue) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugValueBreakpoint_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugStepper_INTERFACE_DEFINED__
+#define __ICorDebugStepper_INTERFACE_DEFINED__
+
+/* interface ICorDebugStepper */
+/* [unique][uuid][local][object] */
+
+typedef
+enum CorDebugIntercept
+ {
+ INTERCEPT_NONE = 0,
+ INTERCEPT_CLASS_INIT = 0x1,
+ INTERCEPT_EXCEPTION_FILTER = 0x2,
+ INTERCEPT_SECURITY = 0x4,
+ INTERCEPT_CONTEXT_POLICY = 0x8,
+ INTERCEPT_INTERCEPTION = 0x10,
+ INTERCEPT_ALL = 0xffff
+ } CorDebugIntercept;
+
+typedef
+enum CorDebugUnmappedStop
+ {
+ STOP_NONE = 0,
+ STOP_PROLOG = 0x1,
+ STOP_EPILOG = 0x2,
+ STOP_NO_MAPPING_INFO = 0x4,
+ STOP_OTHER_UNMAPPED = 0x8,
+ STOP_UNMANAGED = 0x10,
+ STOP_ALL = 0xffff
+ } CorDebugUnmappedStop;
+
+typedef struct COR_DEBUG_STEP_RANGE
+ {
+ ULONG32 startOffset;
+ ULONG32 endOffset;
+ } COR_DEBUG_STEP_RANGE;
+
+
+EXTERN_C const IID IID_ICorDebugStepper;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("CC7BCAEC-8A68-11d2-983C-0000F808342D")
+ ICorDebugStepper : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE IsActive(
+ /* [out] */ BOOL *pbActive) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Deactivate( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetInterceptMask(
+ /* [in] */ CorDebugIntercept mask) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetUnmappedStopMask(
+ /* [in] */ CorDebugUnmappedStop mask) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Step(
+ /* [in] */ BOOL bStepIn) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StepRange(
+ /* [in] */ BOOL bStepIn,
+ /* [size_is][in] */ COR_DEBUG_STEP_RANGE ranges[ ],
+ /* [in] */ ULONG32 cRangeCount) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StepOut( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetRangeIL(
+ /* [in] */ BOOL bIL) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugStepperVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugStepper * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugStepper * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugStepper * This);
+
+ HRESULT ( STDMETHODCALLTYPE *IsActive )(
+ ICorDebugStepper * This,
+ /* [out] */ BOOL *pbActive);
+
+ HRESULT ( STDMETHODCALLTYPE *Deactivate )(
+ ICorDebugStepper * This);
+
+ HRESULT ( STDMETHODCALLTYPE *SetInterceptMask )(
+ ICorDebugStepper * This,
+ /* [in] */ CorDebugIntercept mask);
+
+ HRESULT ( STDMETHODCALLTYPE *SetUnmappedStopMask )(
+ ICorDebugStepper * This,
+ /* [in] */ CorDebugUnmappedStop mask);
+
+ HRESULT ( STDMETHODCALLTYPE *Step )(
+ ICorDebugStepper * This,
+ /* [in] */ BOOL bStepIn);
+
+ HRESULT ( STDMETHODCALLTYPE *StepRange )(
+ ICorDebugStepper * This,
+ /* [in] */ BOOL bStepIn,
+ /* [size_is][in] */ COR_DEBUG_STEP_RANGE ranges[ ],
+ /* [in] */ ULONG32 cRangeCount);
+
+ HRESULT ( STDMETHODCALLTYPE *StepOut )(
+ ICorDebugStepper * This);
+
+ HRESULT ( STDMETHODCALLTYPE *SetRangeIL )(
+ ICorDebugStepper * This,
+ /* [in] */ BOOL bIL);
+
+ END_INTERFACE
+ } ICorDebugStepperVtbl;
+
+ interface ICorDebugStepper
+ {
+ CONST_VTBL struct ICorDebugStepperVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugStepper_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugStepper_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugStepper_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugStepper_IsActive(This,pbActive) \
+ ( (This)->lpVtbl -> IsActive(This,pbActive) )
+
+#define ICorDebugStepper_Deactivate(This) \
+ ( (This)->lpVtbl -> Deactivate(This) )
+
+#define ICorDebugStepper_SetInterceptMask(This,mask) \
+ ( (This)->lpVtbl -> SetInterceptMask(This,mask) )
+
+#define ICorDebugStepper_SetUnmappedStopMask(This,mask) \
+ ( (This)->lpVtbl -> SetUnmappedStopMask(This,mask) )
+
+#define ICorDebugStepper_Step(This,bStepIn) \
+ ( (This)->lpVtbl -> Step(This,bStepIn) )
+
+#define ICorDebugStepper_StepRange(This,bStepIn,ranges,cRangeCount) \
+ ( (This)->lpVtbl -> StepRange(This,bStepIn,ranges,cRangeCount) )
+
+#define ICorDebugStepper_StepOut(This) \
+ ( (This)->lpVtbl -> StepOut(This) )
+
+#define ICorDebugStepper_SetRangeIL(This,bIL) \
+ ( (This)->lpVtbl -> SetRangeIL(This,bIL) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugStepper_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugStepper2_INTERFACE_DEFINED__
+#define __ICorDebugStepper2_INTERFACE_DEFINED__
+
+/* interface ICorDebugStepper2 */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugStepper2;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("C5B6E9C3-E7D1-4a8e-873B-7F047F0706F7")
+ ICorDebugStepper2 : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE SetJMC(
+ /* [in] */ BOOL fIsJMCStepper) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugStepper2Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugStepper2 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugStepper2 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugStepper2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *SetJMC )(
+ ICorDebugStepper2 * This,
+ /* [in] */ BOOL fIsJMCStepper);
+
+ END_INTERFACE
+ } ICorDebugStepper2Vtbl;
+
+ interface ICorDebugStepper2
+ {
+ CONST_VTBL struct ICorDebugStepper2Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugStepper2_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugStepper2_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugStepper2_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugStepper2_SetJMC(This,fIsJMCStepper) \
+ ( (This)->lpVtbl -> SetJMC(This,fIsJMCStepper) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugStepper2_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugRegisterSet_INTERFACE_DEFINED__
+#define __ICorDebugRegisterSet_INTERFACE_DEFINED__
+
+/* interface ICorDebugRegisterSet */
+/* [unique][uuid][local][object] */
+
+typedef
+enum CorDebugRegister
+ {
+ REGISTER_INSTRUCTION_POINTER = 0,
+ REGISTER_STACK_POINTER = ( REGISTER_INSTRUCTION_POINTER + 1 ) ,
+ REGISTER_FRAME_POINTER = ( REGISTER_STACK_POINTER + 1 ) ,
+ REGISTER_X86_EIP = 0,
+ REGISTER_X86_ESP = ( REGISTER_X86_EIP + 1 ) ,
+ REGISTER_X86_EBP = ( REGISTER_X86_ESP + 1 ) ,
+ REGISTER_X86_EAX = ( REGISTER_X86_EBP + 1 ) ,
+ REGISTER_X86_ECX = ( REGISTER_X86_EAX + 1 ) ,
+ REGISTER_X86_EDX = ( REGISTER_X86_ECX + 1 ) ,
+ REGISTER_X86_EBX = ( REGISTER_X86_EDX + 1 ) ,
+ REGISTER_X86_ESI = ( REGISTER_X86_EBX + 1 ) ,
+ REGISTER_X86_EDI = ( REGISTER_X86_ESI + 1 ) ,
+ REGISTER_X86_FPSTACK_0 = ( REGISTER_X86_EDI + 1 ) ,
+ REGISTER_X86_FPSTACK_1 = ( REGISTER_X86_FPSTACK_0 + 1 ) ,
+ REGISTER_X86_FPSTACK_2 = ( REGISTER_X86_FPSTACK_1 + 1 ) ,
+ REGISTER_X86_FPSTACK_3 = ( REGISTER_X86_FPSTACK_2 + 1 ) ,
+ REGISTER_X86_FPSTACK_4 = ( REGISTER_X86_FPSTACK_3 + 1 ) ,
+ REGISTER_X86_FPSTACK_5 = ( REGISTER_X86_FPSTACK_4 + 1 ) ,
+ REGISTER_X86_FPSTACK_6 = ( REGISTER_X86_FPSTACK_5 + 1 ) ,
+ REGISTER_X86_FPSTACK_7 = ( REGISTER_X86_FPSTACK_6 + 1 ) ,
+ REGISTER_AMD64_RIP = 0,
+ REGISTER_AMD64_RSP = ( REGISTER_AMD64_RIP + 1 ) ,
+ REGISTER_AMD64_RBP = ( REGISTER_AMD64_RSP + 1 ) ,
+ REGISTER_AMD64_RAX = ( REGISTER_AMD64_RBP + 1 ) ,
+ REGISTER_AMD64_RCX = ( REGISTER_AMD64_RAX + 1 ) ,
+ REGISTER_AMD64_RDX = ( REGISTER_AMD64_RCX + 1 ) ,
+ REGISTER_AMD64_RBX = ( REGISTER_AMD64_RDX + 1 ) ,
+ REGISTER_AMD64_RSI = ( REGISTER_AMD64_RBX + 1 ) ,
+ REGISTER_AMD64_RDI = ( REGISTER_AMD64_RSI + 1 ) ,
+ REGISTER_AMD64_R8 = ( REGISTER_AMD64_RDI + 1 ) ,
+ REGISTER_AMD64_R9 = ( REGISTER_AMD64_R8 + 1 ) ,
+ REGISTER_AMD64_R10 = ( REGISTER_AMD64_R9 + 1 ) ,
+ REGISTER_AMD64_R11 = ( REGISTER_AMD64_R10 + 1 ) ,
+ REGISTER_AMD64_R12 = ( REGISTER_AMD64_R11 + 1 ) ,
+ REGISTER_AMD64_R13 = ( REGISTER_AMD64_R12 + 1 ) ,
+ REGISTER_AMD64_R14 = ( REGISTER_AMD64_R13 + 1 ) ,
+ REGISTER_AMD64_R15 = ( REGISTER_AMD64_R14 + 1 ) ,
+ REGISTER_AMD64_XMM0 = ( REGISTER_AMD64_R15 + 1 ) ,
+ REGISTER_AMD64_XMM1 = ( REGISTER_AMD64_XMM0 + 1 ) ,
+ REGISTER_AMD64_XMM2 = ( REGISTER_AMD64_XMM1 + 1 ) ,
+ REGISTER_AMD64_XMM3 = ( REGISTER_AMD64_XMM2 + 1 ) ,
+ REGISTER_AMD64_XMM4 = ( REGISTER_AMD64_XMM3 + 1 ) ,
+ REGISTER_AMD64_XMM5 = ( REGISTER_AMD64_XMM4 + 1 ) ,
+ REGISTER_AMD64_XMM6 = ( REGISTER_AMD64_XMM5 + 1 ) ,
+ REGISTER_AMD64_XMM7 = ( REGISTER_AMD64_XMM6 + 1 ) ,
+ REGISTER_AMD64_XMM8 = ( REGISTER_AMD64_XMM7 + 1 ) ,
+ REGISTER_AMD64_XMM9 = ( REGISTER_AMD64_XMM8 + 1 ) ,
+ REGISTER_AMD64_XMM10 = ( REGISTER_AMD64_XMM9 + 1 ) ,
+ REGISTER_AMD64_XMM11 = ( REGISTER_AMD64_XMM10 + 1 ) ,
+ REGISTER_AMD64_XMM12 = ( REGISTER_AMD64_XMM11 + 1 ) ,
+ REGISTER_AMD64_XMM13 = ( REGISTER_AMD64_XMM12 + 1 ) ,
+ REGISTER_AMD64_XMM14 = ( REGISTER_AMD64_XMM13 + 1 ) ,
+ REGISTER_AMD64_XMM15 = ( REGISTER_AMD64_XMM14 + 1 ) ,
+ REGISTER_IA64_BSP = REGISTER_FRAME_POINTER,
+ REGISTER_IA64_R0 = ( REGISTER_IA64_BSP + 1 ) ,
+ REGISTER_IA64_F0 = ( REGISTER_IA64_R0 + 128 ) ,
+ REGISTER_ARM_PC = 0,
+ REGISTER_ARM_SP = ( REGISTER_ARM_PC + 1 ) ,
+ REGISTER_ARM_R0 = ( REGISTER_ARM_SP + 1 ) ,
+ REGISTER_ARM_R1 = ( REGISTER_ARM_R0 + 1 ) ,
+ REGISTER_ARM_R2 = ( REGISTER_ARM_R1 + 1 ) ,
+ REGISTER_ARM_R3 = ( REGISTER_ARM_R2 + 1 ) ,
+ REGISTER_ARM_R4 = ( REGISTER_ARM_R3 + 1 ) ,
+ REGISTER_ARM_R5 = ( REGISTER_ARM_R4 + 1 ) ,
+ REGISTER_ARM_R6 = ( REGISTER_ARM_R5 + 1 ) ,
+ REGISTER_ARM_R7 = ( REGISTER_ARM_R6 + 1 ) ,
+ REGISTER_ARM_R8 = ( REGISTER_ARM_R7 + 1 ) ,
+ REGISTER_ARM_R9 = ( REGISTER_ARM_R8 + 1 ) ,
+ REGISTER_ARM_R10 = ( REGISTER_ARM_R9 + 1 ) ,
+ REGISTER_ARM_R11 = ( REGISTER_ARM_R10 + 1 ) ,
+ REGISTER_ARM_R12 = ( REGISTER_ARM_R11 + 1 ) ,
+ REGISTER_ARM_LR = ( REGISTER_ARM_R12 + 1 ) ,
+ REGISTER_ARM64_PC = 0,
+ REGISTER_ARM64_SP = ( REGISTER_ARM64_PC + 1 ) ,
+ REGISTER_ARM64_FP = ( REGISTER_ARM64_SP + 1 ) ,
+ REGISTER_ARM64_X0 = ( REGISTER_ARM64_FP + 1 ) ,
+ REGISTER_ARM64_X1 = ( REGISTER_ARM64_X0 + 1 ) ,
+ REGISTER_ARM64_X2 = ( REGISTER_ARM64_X1 + 1 ) ,
+ REGISTER_ARM64_X3 = ( REGISTER_ARM64_X2 + 1 ) ,
+ REGISTER_ARM64_X4 = ( REGISTER_ARM64_X3 + 1 ) ,
+ REGISTER_ARM64_X5 = ( REGISTER_ARM64_X4 + 1 ) ,
+ REGISTER_ARM64_X6 = ( REGISTER_ARM64_X5 + 1 ) ,
+ REGISTER_ARM64_X7 = ( REGISTER_ARM64_X6 + 1 ) ,
+ REGISTER_ARM64_X8 = ( REGISTER_ARM64_X7 + 1 ) ,
+ REGISTER_ARM64_X9 = ( REGISTER_ARM64_X8 + 1 ) ,
+ REGISTER_ARM64_X10 = ( REGISTER_ARM64_X9 + 1 ) ,
+ REGISTER_ARM64_X11 = ( REGISTER_ARM64_X10 + 1 ) ,
+ REGISTER_ARM64_X12 = ( REGISTER_ARM64_X11 + 1 ) ,
+ REGISTER_ARM64_X13 = ( REGISTER_ARM64_X12 + 1 ) ,
+ REGISTER_ARM64_X14 = ( REGISTER_ARM64_X13 + 1 ) ,
+ REGISTER_ARM64_X15 = ( REGISTER_ARM64_X14 + 1 ) ,
+ REGISTER_ARM64_X16 = ( REGISTER_ARM64_X15 + 1 ) ,
+ REGISTER_ARM64_X17 = ( REGISTER_ARM64_X16 + 1 ) ,
+ REGISTER_ARM64_X18 = ( REGISTER_ARM64_X17 + 1 ) ,
+ REGISTER_ARM64_X19 = ( REGISTER_ARM64_X18 + 1 ) ,
+ REGISTER_ARM64_X20 = ( REGISTER_ARM64_X19 + 1 ) ,
+ REGISTER_ARM64_X21 = ( REGISTER_ARM64_X20 + 1 ) ,
+ REGISTER_ARM64_X22 = ( REGISTER_ARM64_X21 + 1 ) ,
+ REGISTER_ARM64_X23 = ( REGISTER_ARM64_X22 + 1 ) ,
+ REGISTER_ARM64_X24 = ( REGISTER_ARM64_X23 + 1 ) ,
+ REGISTER_ARM64_X25 = ( REGISTER_ARM64_X24 + 1 ) ,
+ REGISTER_ARM64_X26 = ( REGISTER_ARM64_X25 + 1 ) ,
+ REGISTER_ARM64_X27 = ( REGISTER_ARM64_X26 + 1 ) ,
+ REGISTER_ARM64_X28 = ( REGISTER_ARM64_X27 + 1 ) ,
+ REGISTER_ARM64_LR = ( REGISTER_ARM64_X28 + 1 ) ,
+ REGISTER_ARM64_V0 = ( REGISTER_ARM64_LR + 1 ) ,
+ REGISTER_ARM64_V1 = ( REGISTER_ARM64_V0 + 1 ) ,
+ REGISTER_ARM64_V2 = ( REGISTER_ARM64_V1 + 1 ) ,
+ REGISTER_ARM64_V3 = ( REGISTER_ARM64_V2 + 1 ) ,
+ REGISTER_ARM64_V4 = ( REGISTER_ARM64_V3 + 1 ) ,
+ REGISTER_ARM64_V5 = ( REGISTER_ARM64_V4 + 1 ) ,
+ REGISTER_ARM64_V6 = ( REGISTER_ARM64_V5 + 1 ) ,
+ REGISTER_ARM64_V7 = ( REGISTER_ARM64_V6 + 1 ) ,
+ REGISTER_ARM64_V8 = ( REGISTER_ARM64_V7 + 1 ) ,
+ REGISTER_ARM64_V9 = ( REGISTER_ARM64_V8 + 1 ) ,
+ REGISTER_ARM64_V10 = ( REGISTER_ARM64_V9 + 1 ) ,
+ REGISTER_ARM64_V11 = ( REGISTER_ARM64_V10 + 1 ) ,
+ REGISTER_ARM64_V12 = ( REGISTER_ARM64_V11 + 1 ) ,
+ REGISTER_ARM64_V13 = ( REGISTER_ARM64_V12 + 1 ) ,
+ REGISTER_ARM64_V14 = ( REGISTER_ARM64_V13 + 1 ) ,
+ REGISTER_ARM64_V15 = ( REGISTER_ARM64_V14 + 1 ) ,
+ REGISTER_ARM64_V16 = ( REGISTER_ARM64_V15 + 1 ) ,
+ REGISTER_ARM64_V17 = ( REGISTER_ARM64_V16 + 1 ) ,
+ REGISTER_ARM64_V18 = ( REGISTER_ARM64_V17 + 1 ) ,
+ REGISTER_ARM64_V19 = ( REGISTER_ARM64_V18 + 1 ) ,
+ REGISTER_ARM64_V20 = ( REGISTER_ARM64_V19 + 1 ) ,
+ REGISTER_ARM64_V21 = ( REGISTER_ARM64_V20 + 1 ) ,
+ REGISTER_ARM64_V22 = ( REGISTER_ARM64_V21 + 1 ) ,
+ REGISTER_ARM64_V23 = ( REGISTER_ARM64_V22 + 1 ) ,
+ REGISTER_ARM64_V24 = ( REGISTER_ARM64_V23 + 1 ) ,
+ REGISTER_ARM64_V25 = ( REGISTER_ARM64_V24 + 1 ) ,
+ REGISTER_ARM64_V26 = ( REGISTER_ARM64_V25 + 1 ) ,
+ REGISTER_ARM64_V27 = ( REGISTER_ARM64_V26 + 1 ) ,
+ REGISTER_ARM64_V28 = ( REGISTER_ARM64_V27 + 1 ) ,
+ REGISTER_ARM64_V29 = ( REGISTER_ARM64_V28 + 1 ) ,
+ REGISTER_ARM64_V30 = ( REGISTER_ARM64_V29 + 1 ) ,
+ REGISTER_ARM64_V31 = ( REGISTER_ARM64_V30 + 1 )
+ } CorDebugRegister;
+
+
+EXTERN_C const IID IID_ICorDebugRegisterSet;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("CC7BCB0B-8A68-11d2-983C-0000F808342D")
+ ICorDebugRegisterSet : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetRegistersAvailable(
+ /* [out] */ ULONG64 *pAvailable) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetRegisters(
+ /* [in] */ ULONG64 mask,
+ /* [in] */ ULONG32 regCount,
+ /* [length_is][size_is][out] */ CORDB_REGISTER regBuffer[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetRegisters(
+ /* [in] */ ULONG64 mask,
+ /* [in] */ ULONG32 regCount,
+ /* [size_is][in] */ CORDB_REGISTER regBuffer[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetThreadContext(
+ /* [in] */ ULONG32 contextSize,
+ /* [size_is][length_is][out][in] */ BYTE context[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetThreadContext(
+ /* [in] */ ULONG32 contextSize,
+ /* [size_is][length_is][in] */ BYTE context[ ]) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugRegisterSetVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugRegisterSet * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugRegisterSet * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugRegisterSet * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetRegistersAvailable )(
+ ICorDebugRegisterSet * This,
+ /* [out] */ ULONG64 *pAvailable);
+
+ HRESULT ( STDMETHODCALLTYPE *GetRegisters )(
+ ICorDebugRegisterSet * This,
+ /* [in] */ ULONG64 mask,
+ /* [in] */ ULONG32 regCount,
+ /* [length_is][size_is][out] */ CORDB_REGISTER regBuffer[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *SetRegisters )(
+ ICorDebugRegisterSet * This,
+ /* [in] */ ULONG64 mask,
+ /* [in] */ ULONG32 regCount,
+ /* [size_is][in] */ CORDB_REGISTER regBuffer[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetThreadContext )(
+ ICorDebugRegisterSet * This,
+ /* [in] */ ULONG32 contextSize,
+ /* [size_is][length_is][out][in] */ BYTE context[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *SetThreadContext )(
+ ICorDebugRegisterSet * This,
+ /* [in] */ ULONG32 contextSize,
+ /* [size_is][length_is][in] */ BYTE context[ ]);
+
+ END_INTERFACE
+ } ICorDebugRegisterSetVtbl;
+
+ interface ICorDebugRegisterSet
+ {
+ CONST_VTBL struct ICorDebugRegisterSetVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugRegisterSet_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugRegisterSet_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugRegisterSet_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugRegisterSet_GetRegistersAvailable(This,pAvailable) \
+ ( (This)->lpVtbl -> GetRegistersAvailable(This,pAvailable) )
+
+#define ICorDebugRegisterSet_GetRegisters(This,mask,regCount,regBuffer) \
+ ( (This)->lpVtbl -> GetRegisters(This,mask,regCount,regBuffer) )
+
+#define ICorDebugRegisterSet_SetRegisters(This,mask,regCount,regBuffer) \
+ ( (This)->lpVtbl -> SetRegisters(This,mask,regCount,regBuffer) )
+
+#define ICorDebugRegisterSet_GetThreadContext(This,contextSize,context) \
+ ( (This)->lpVtbl -> GetThreadContext(This,contextSize,context) )
+
+#define ICorDebugRegisterSet_SetThreadContext(This,contextSize,context) \
+ ( (This)->lpVtbl -> SetThreadContext(This,contextSize,context) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugRegisterSet_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugRegisterSet2_INTERFACE_DEFINED__
+#define __ICorDebugRegisterSet2_INTERFACE_DEFINED__
+
+/* interface ICorDebugRegisterSet2 */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugRegisterSet2;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("6DC7BA3F-89BA-4459-9EC1-9D60937B468D")
+ ICorDebugRegisterSet2 : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetRegistersAvailable(
+ /* [in] */ ULONG32 numChunks,
+ /* [size_is][out] */ BYTE availableRegChunks[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetRegisters(
+ /* [in] */ ULONG32 maskCount,
+ /* [size_is][in] */ BYTE mask[ ],
+ /* [in] */ ULONG32 regCount,
+ /* [size_is][out] */ CORDB_REGISTER regBuffer[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetRegisters(
+ /* [in] */ ULONG32 maskCount,
+ /* [size_is][in] */ BYTE mask[ ],
+ /* [in] */ ULONG32 regCount,
+ /* [size_is][in] */ CORDB_REGISTER regBuffer[ ]) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugRegisterSet2Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugRegisterSet2 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugRegisterSet2 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugRegisterSet2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetRegistersAvailable )(
+ ICorDebugRegisterSet2 * This,
+ /* [in] */ ULONG32 numChunks,
+ /* [size_is][out] */ BYTE availableRegChunks[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetRegisters )(
+ ICorDebugRegisterSet2 * This,
+ /* [in] */ ULONG32 maskCount,
+ /* [size_is][in] */ BYTE mask[ ],
+ /* [in] */ ULONG32 regCount,
+ /* [size_is][out] */ CORDB_REGISTER regBuffer[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *SetRegisters )(
+ ICorDebugRegisterSet2 * This,
+ /* [in] */ ULONG32 maskCount,
+ /* [size_is][in] */ BYTE mask[ ],
+ /* [in] */ ULONG32 regCount,
+ /* [size_is][in] */ CORDB_REGISTER regBuffer[ ]);
+
+ END_INTERFACE
+ } ICorDebugRegisterSet2Vtbl;
+
+ interface ICorDebugRegisterSet2
+ {
+ CONST_VTBL struct ICorDebugRegisterSet2Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugRegisterSet2_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugRegisterSet2_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugRegisterSet2_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugRegisterSet2_GetRegistersAvailable(This,numChunks,availableRegChunks) \
+ ( (This)->lpVtbl -> GetRegistersAvailable(This,numChunks,availableRegChunks) )
+
+#define ICorDebugRegisterSet2_GetRegisters(This,maskCount,mask,regCount,regBuffer) \
+ ( (This)->lpVtbl -> GetRegisters(This,maskCount,mask,regCount,regBuffer) )
+
+#define ICorDebugRegisterSet2_SetRegisters(This,maskCount,mask,regCount,regBuffer) \
+ ( (This)->lpVtbl -> SetRegisters(This,maskCount,mask,regCount,regBuffer) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugRegisterSet2_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugThread_INTERFACE_DEFINED__
+#define __ICorDebugThread_INTERFACE_DEFINED__
+
+/* interface ICorDebugThread */
+/* [unique][uuid][local][object] */
+
+typedef
+enum CorDebugUserState
+ {
+ USER_STOP_REQUESTED = 0x1,
+ USER_SUSPEND_REQUESTED = 0x2,
+ USER_BACKGROUND = 0x4,
+ USER_UNSTARTED = 0x8,
+ USER_STOPPED = 0x10,
+ USER_WAIT_SLEEP_JOIN = 0x20,
+ USER_SUSPENDED = 0x40,
+ USER_UNSAFE_POINT = 0x80,
+ USER_THREADPOOL = 0x100
+ } CorDebugUserState;
+
+
+EXTERN_C const IID IID_ICorDebugThread;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("938c6d66-7fb6-4f69-b389-425b8987329b")
+ ICorDebugThread : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetProcess(
+ /* [out] */ ICorDebugProcess **ppProcess) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetID(
+ /* [out] */ DWORD *pdwThreadId) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetHandle(
+ /* [out] */ HTHREAD *phThreadHandle) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetAppDomain(
+ /* [out] */ ICorDebugAppDomain **ppAppDomain) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetDebugState(
+ /* [in] */ CorDebugThreadState state) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetDebugState(
+ /* [out] */ CorDebugThreadState *pState) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetUserState(
+ /* [out] */ CorDebugUserState *pState) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetCurrentException(
+ /* [out] */ ICorDebugValue **ppExceptionObject) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ClearCurrentException( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE CreateStepper(
+ /* [out] */ ICorDebugStepper **ppStepper) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnumerateChains(
+ /* [out] */ ICorDebugChainEnum **ppChains) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetActiveChain(
+ /* [out] */ ICorDebugChain **ppChain) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetActiveFrame(
+ /* [out] */ ICorDebugFrame **ppFrame) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetRegisterSet(
+ /* [out] */ ICorDebugRegisterSet **ppRegisters) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE CreateEval(
+ /* [out] */ ICorDebugEval **ppEval) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetObject(
+ /* [out] */ ICorDebugValue **ppObject) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugThreadVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugThread * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugThread * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugThread * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetProcess )(
+ ICorDebugThread * This,
+ /* [out] */ ICorDebugProcess **ppProcess);
+
+ HRESULT ( STDMETHODCALLTYPE *GetID )(
+ ICorDebugThread * This,
+ /* [out] */ DWORD *pdwThreadId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetHandle )(
+ ICorDebugThread * This,
+ /* [out] */ HTHREAD *phThreadHandle);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAppDomain )(
+ ICorDebugThread * This,
+ /* [out] */ ICorDebugAppDomain **ppAppDomain);
+
+ HRESULT ( STDMETHODCALLTYPE *SetDebugState )(
+ ICorDebugThread * This,
+ /* [in] */ CorDebugThreadState state);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDebugState )(
+ ICorDebugThread * This,
+ /* [out] */ CorDebugThreadState *pState);
+
+ HRESULT ( STDMETHODCALLTYPE *GetUserState )(
+ ICorDebugThread * This,
+ /* [out] */ CorDebugUserState *pState);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCurrentException )(
+ ICorDebugThread * This,
+ /* [out] */ ICorDebugValue **ppExceptionObject);
+
+ HRESULT ( STDMETHODCALLTYPE *ClearCurrentException )(
+ ICorDebugThread * This);
+
+ HRESULT ( STDMETHODCALLTYPE *CreateStepper )(
+ ICorDebugThread * This,
+ /* [out] */ ICorDebugStepper **ppStepper);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumerateChains )(
+ ICorDebugThread * This,
+ /* [out] */ ICorDebugChainEnum **ppChains);
+
+ HRESULT ( STDMETHODCALLTYPE *GetActiveChain )(
+ ICorDebugThread * This,
+ /* [out] */ ICorDebugChain **ppChain);
+
+ HRESULT ( STDMETHODCALLTYPE *GetActiveFrame )(
+ ICorDebugThread * This,
+ /* [out] */ ICorDebugFrame **ppFrame);
+
+ HRESULT ( STDMETHODCALLTYPE *GetRegisterSet )(
+ ICorDebugThread * This,
+ /* [out] */ ICorDebugRegisterSet **ppRegisters);
+
+ HRESULT ( STDMETHODCALLTYPE *CreateEval )(
+ ICorDebugThread * This,
+ /* [out] */ ICorDebugEval **ppEval);
+
+ HRESULT ( STDMETHODCALLTYPE *GetObject )(
+ ICorDebugThread * This,
+ /* [out] */ ICorDebugValue **ppObject);
+
+ END_INTERFACE
+ } ICorDebugThreadVtbl;
+
+ interface ICorDebugThread
+ {
+ CONST_VTBL struct ICorDebugThreadVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugThread_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugThread_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugThread_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugThread_GetProcess(This,ppProcess) \
+ ( (This)->lpVtbl -> GetProcess(This,ppProcess) )
+
+#define ICorDebugThread_GetID(This,pdwThreadId) \
+ ( (This)->lpVtbl -> GetID(This,pdwThreadId) )
+
+#define ICorDebugThread_GetHandle(This,phThreadHandle) \
+ ( (This)->lpVtbl -> GetHandle(This,phThreadHandle) )
+
+#define ICorDebugThread_GetAppDomain(This,ppAppDomain) \
+ ( (This)->lpVtbl -> GetAppDomain(This,ppAppDomain) )
+
+#define ICorDebugThread_SetDebugState(This,state) \
+ ( (This)->lpVtbl -> SetDebugState(This,state) )
+
+#define ICorDebugThread_GetDebugState(This,pState) \
+ ( (This)->lpVtbl -> GetDebugState(This,pState) )
+
+#define ICorDebugThread_GetUserState(This,pState) \
+ ( (This)->lpVtbl -> GetUserState(This,pState) )
+
+#define ICorDebugThread_GetCurrentException(This,ppExceptionObject) \
+ ( (This)->lpVtbl -> GetCurrentException(This,ppExceptionObject) )
+
+#define ICorDebugThread_ClearCurrentException(This) \
+ ( (This)->lpVtbl -> ClearCurrentException(This) )
+
+#define ICorDebugThread_CreateStepper(This,ppStepper) \
+ ( (This)->lpVtbl -> CreateStepper(This,ppStepper) )
+
+#define ICorDebugThread_EnumerateChains(This,ppChains) \
+ ( (This)->lpVtbl -> EnumerateChains(This,ppChains) )
+
+#define ICorDebugThread_GetActiveChain(This,ppChain) \
+ ( (This)->lpVtbl -> GetActiveChain(This,ppChain) )
+
+#define ICorDebugThread_GetActiveFrame(This,ppFrame) \
+ ( (This)->lpVtbl -> GetActiveFrame(This,ppFrame) )
+
+#define ICorDebugThread_GetRegisterSet(This,ppRegisters) \
+ ( (This)->lpVtbl -> GetRegisterSet(This,ppRegisters) )
+
+#define ICorDebugThread_CreateEval(This,ppEval) \
+ ( (This)->lpVtbl -> CreateEval(This,ppEval) )
+
+#define ICorDebugThread_GetObject(This,ppObject) \
+ ( (This)->lpVtbl -> GetObject(This,ppObject) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugThread_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugThread2_INTERFACE_DEFINED__
+#define __ICorDebugThread2_INTERFACE_DEFINED__
+
+/* interface ICorDebugThread2 */
+/* [unique][uuid][local][object] */
+
+typedef struct _COR_ACTIVE_FUNCTION
+ {
+ ICorDebugAppDomain *pAppDomain;
+ ICorDebugModule *pModule;
+ ICorDebugFunction2 *pFunction;
+ ULONG32 ilOffset;
+ ULONG32 flags;
+ } COR_ACTIVE_FUNCTION;
+
+
+EXTERN_C const IID IID_ICorDebugThread2;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("2BD956D9-7B07-4bef-8A98-12AA862417C5")
+ ICorDebugThread2 : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetActiveFunctions(
+ /* [in] */ ULONG32 cFunctions,
+ /* [out] */ ULONG32 *pcFunctions,
+ /* [length_is][size_is][out][in] */ COR_ACTIVE_FUNCTION pFunctions[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetConnectionID(
+ /* [out] */ CONNID *pdwConnectionId) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetTaskID(
+ /* [out] */ TASKID *pTaskId) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetVolatileOSThreadID(
+ /* [out] */ DWORD *pdwTid) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE InterceptCurrentException(
+ /* [in] */ ICorDebugFrame *pFrame) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugThread2Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugThread2 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugThread2 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugThread2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetActiveFunctions )(
+ ICorDebugThread2 * This,
+ /* [in] */ ULONG32 cFunctions,
+ /* [out] */ ULONG32 *pcFunctions,
+ /* [length_is][size_is][out][in] */ COR_ACTIVE_FUNCTION pFunctions[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetConnectionID )(
+ ICorDebugThread2 * This,
+ /* [out] */ CONNID *pdwConnectionId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetTaskID )(
+ ICorDebugThread2 * This,
+ /* [out] */ TASKID *pTaskId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetVolatileOSThreadID )(
+ ICorDebugThread2 * This,
+ /* [out] */ DWORD *pdwTid);
+
+ HRESULT ( STDMETHODCALLTYPE *InterceptCurrentException )(
+ ICorDebugThread2 * This,
+ /* [in] */ ICorDebugFrame *pFrame);
+
+ END_INTERFACE
+ } ICorDebugThread2Vtbl;
+
+ interface ICorDebugThread2
+ {
+ CONST_VTBL struct ICorDebugThread2Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugThread2_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugThread2_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugThread2_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugThread2_GetActiveFunctions(This,cFunctions,pcFunctions,pFunctions) \
+ ( (This)->lpVtbl -> GetActiveFunctions(This,cFunctions,pcFunctions,pFunctions) )
+
+#define ICorDebugThread2_GetConnectionID(This,pdwConnectionId) \
+ ( (This)->lpVtbl -> GetConnectionID(This,pdwConnectionId) )
+
+#define ICorDebugThread2_GetTaskID(This,pTaskId) \
+ ( (This)->lpVtbl -> GetTaskID(This,pTaskId) )
+
+#define ICorDebugThread2_GetVolatileOSThreadID(This,pdwTid) \
+ ( (This)->lpVtbl -> GetVolatileOSThreadID(This,pdwTid) )
+
+#define ICorDebugThread2_InterceptCurrentException(This,pFrame) \
+ ( (This)->lpVtbl -> InterceptCurrentException(This,pFrame) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugThread2_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugThread3_INTERFACE_DEFINED__
+#define __ICorDebugThread3_INTERFACE_DEFINED__
+
+/* interface ICorDebugThread3 */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugThread3;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("F8544EC3-5E4E-46c7-8D3E-A52B8405B1F5")
+ ICorDebugThread3 : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE CreateStackWalk(
+ /* [out] */ ICorDebugStackWalk **ppStackWalk) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetActiveInternalFrames(
+ /* [in] */ ULONG32 cInternalFrames,
+ /* [out] */ ULONG32 *pcInternalFrames,
+ /* [length_is][size_is][out][in] */ ICorDebugInternalFrame2 *ppInternalFrames[ ]) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugThread3Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugThread3 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugThread3 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugThread3 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *CreateStackWalk )(
+ ICorDebugThread3 * This,
+ /* [out] */ ICorDebugStackWalk **ppStackWalk);
+
+ HRESULT ( STDMETHODCALLTYPE *GetActiveInternalFrames )(
+ ICorDebugThread3 * This,
+ /* [in] */ ULONG32 cInternalFrames,
+ /* [out] */ ULONG32 *pcInternalFrames,
+ /* [length_is][size_is][out][in] */ ICorDebugInternalFrame2 *ppInternalFrames[ ]);
+
+ END_INTERFACE
+ } ICorDebugThread3Vtbl;
+
+ interface ICorDebugThread3
+ {
+ CONST_VTBL struct ICorDebugThread3Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugThread3_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugThread3_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugThread3_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugThread3_CreateStackWalk(This,ppStackWalk) \
+ ( (This)->lpVtbl -> CreateStackWalk(This,ppStackWalk) )
+
+#define ICorDebugThread3_GetActiveInternalFrames(This,cInternalFrames,pcInternalFrames,ppInternalFrames) \
+ ( (This)->lpVtbl -> GetActiveInternalFrames(This,cInternalFrames,pcInternalFrames,ppInternalFrames) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugThread3_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugThread4_INTERFACE_DEFINED__
+#define __ICorDebugThread4_INTERFACE_DEFINED__
+
+/* interface ICorDebugThread4 */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugThread4;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("1A1F204B-1C66-4637-823F-3EE6C744A69C")
+ ICorDebugThread4 : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE HasUnhandledException( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetBlockingObjects(
+ /* [out] */ ICorDebugBlockingObjectEnum **ppBlockingObjectEnum) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetCurrentCustomDebuggerNotification(
+ /* [out] */ ICorDebugValue **ppNotificationObject) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugThread4Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugThread4 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugThread4 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugThread4 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *HasUnhandledException )(
+ ICorDebugThread4 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetBlockingObjects )(
+ ICorDebugThread4 * This,
+ /* [out] */ ICorDebugBlockingObjectEnum **ppBlockingObjectEnum);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCurrentCustomDebuggerNotification )(
+ ICorDebugThread4 * This,
+ /* [out] */ ICorDebugValue **ppNotificationObject);
+
+ END_INTERFACE
+ } ICorDebugThread4Vtbl;
+
+ interface ICorDebugThread4
+ {
+ CONST_VTBL struct ICorDebugThread4Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugThread4_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugThread4_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugThread4_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugThread4_HasUnhandledException(This) \
+ ( (This)->lpVtbl -> HasUnhandledException(This) )
+
+#define ICorDebugThread4_GetBlockingObjects(This,ppBlockingObjectEnum) \
+ ( (This)->lpVtbl -> GetBlockingObjects(This,ppBlockingObjectEnum) )
+
+#define ICorDebugThread4_GetCurrentCustomDebuggerNotification(This,ppNotificationObject) \
+ ( (This)->lpVtbl -> GetCurrentCustomDebuggerNotification(This,ppNotificationObject) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugThread4_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugStackWalk_INTERFACE_DEFINED__
+#define __ICorDebugStackWalk_INTERFACE_DEFINED__
+
+/* interface ICorDebugStackWalk */
+/* [unique][uuid][local][object] */
+
+typedef
+enum CorDebugSetContextFlag
+ {
+ SET_CONTEXT_FLAG_ACTIVE_FRAME = 0x1,
+ SET_CONTEXT_FLAG_UNWIND_FRAME = 0x2
+ } CorDebugSetContextFlag;
+
+
+EXTERN_C const IID IID_ICorDebugStackWalk;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("A0647DE9-55DE-4816-929C-385271C64CF7")
+ ICorDebugStackWalk : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetContext(
+ /* [in] */ ULONG32 contextFlags,
+ /* [in] */ ULONG32 contextBufSize,
+ /* [out] */ ULONG32 *contextSize,
+ /* [size_is][out] */ BYTE contextBuf[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetContext(
+ /* [in] */ CorDebugSetContextFlag flag,
+ /* [in] */ ULONG32 contextSize,
+ /* [size_is][in] */ BYTE context[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Next( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetFrame(
+ /* [out] */ ICorDebugFrame **pFrame) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugStackWalkVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugStackWalk * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugStackWalk * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugStackWalk * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetContext )(
+ ICorDebugStackWalk * This,
+ /* [in] */ ULONG32 contextFlags,
+ /* [in] */ ULONG32 contextBufSize,
+ /* [out] */ ULONG32 *contextSize,
+ /* [size_is][out] */ BYTE contextBuf[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *SetContext )(
+ ICorDebugStackWalk * This,
+ /* [in] */ CorDebugSetContextFlag flag,
+ /* [in] */ ULONG32 contextSize,
+ /* [size_is][in] */ BYTE context[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *Next )(
+ ICorDebugStackWalk * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFrame )(
+ ICorDebugStackWalk * This,
+ /* [out] */ ICorDebugFrame **pFrame);
+
+ END_INTERFACE
+ } ICorDebugStackWalkVtbl;
+
+ interface ICorDebugStackWalk
+ {
+ CONST_VTBL struct ICorDebugStackWalkVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugStackWalk_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugStackWalk_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugStackWalk_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugStackWalk_GetContext(This,contextFlags,contextBufSize,contextSize,contextBuf) \
+ ( (This)->lpVtbl -> GetContext(This,contextFlags,contextBufSize,contextSize,contextBuf) )
+
+#define ICorDebugStackWalk_SetContext(This,flag,contextSize,context) \
+ ( (This)->lpVtbl -> SetContext(This,flag,contextSize,context) )
+
+#define ICorDebugStackWalk_Next(This) \
+ ( (This)->lpVtbl -> Next(This) )
+
+#define ICorDebugStackWalk_GetFrame(This,pFrame) \
+ ( (This)->lpVtbl -> GetFrame(This,pFrame) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugStackWalk_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugChain_INTERFACE_DEFINED__
+#define __ICorDebugChain_INTERFACE_DEFINED__
+
+/* interface ICorDebugChain */
+/* [unique][uuid][local][object] */
+
+typedef
+enum CorDebugChainReason
+ {
+ CHAIN_NONE = 0,
+ CHAIN_CLASS_INIT = 0x1,
+ CHAIN_EXCEPTION_FILTER = 0x2,
+ CHAIN_SECURITY = 0x4,
+ CHAIN_CONTEXT_POLICY = 0x8,
+ CHAIN_INTERCEPTION = 0x10,
+ CHAIN_PROCESS_START = 0x20,
+ CHAIN_THREAD_START = 0x40,
+ CHAIN_ENTER_MANAGED = 0x80,
+ CHAIN_ENTER_UNMANAGED = 0x100,
+ CHAIN_DEBUGGER_EVAL = 0x200,
+ CHAIN_CONTEXT_SWITCH = 0x400,
+ CHAIN_FUNC_EVAL = 0x800
+ } CorDebugChainReason;
+
+
+EXTERN_C const IID IID_ICorDebugChain;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("CC7BCAEE-8A68-11d2-983C-0000F808342D")
+ ICorDebugChain : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetThread(
+ /* [out] */ ICorDebugThread **ppThread) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetStackRange(
+ /* [out] */ CORDB_ADDRESS *pStart,
+ /* [out] */ CORDB_ADDRESS *pEnd) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetContext(
+ /* [out] */ ICorDebugContext **ppContext) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetCaller(
+ /* [out] */ ICorDebugChain **ppChain) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetCallee(
+ /* [out] */ ICorDebugChain **ppChain) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetPrevious(
+ /* [out] */ ICorDebugChain **ppChain) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetNext(
+ /* [out] */ ICorDebugChain **ppChain) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE IsManaged(
+ /* [out] */ BOOL *pManaged) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnumerateFrames(
+ /* [out] */ ICorDebugFrameEnum **ppFrames) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetActiveFrame(
+ /* [out] */ ICorDebugFrame **ppFrame) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetRegisterSet(
+ /* [out] */ ICorDebugRegisterSet **ppRegisters) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetReason(
+ /* [out] */ CorDebugChainReason *pReason) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugChainVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugChain * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugChain * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugChain * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetThread )(
+ ICorDebugChain * This,
+ /* [out] */ ICorDebugThread **ppThread);
+
+ HRESULT ( STDMETHODCALLTYPE *GetStackRange )(
+ ICorDebugChain * This,
+ /* [out] */ CORDB_ADDRESS *pStart,
+ /* [out] */ CORDB_ADDRESS *pEnd);
+
+ HRESULT ( STDMETHODCALLTYPE *GetContext )(
+ ICorDebugChain * This,
+ /* [out] */ ICorDebugContext **ppContext);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCaller )(
+ ICorDebugChain * This,
+ /* [out] */ ICorDebugChain **ppChain);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCallee )(
+ ICorDebugChain * This,
+ /* [out] */ ICorDebugChain **ppChain);
+
+ HRESULT ( STDMETHODCALLTYPE *GetPrevious )(
+ ICorDebugChain * This,
+ /* [out] */ ICorDebugChain **ppChain);
+
+ HRESULT ( STDMETHODCALLTYPE *GetNext )(
+ ICorDebugChain * This,
+ /* [out] */ ICorDebugChain **ppChain);
+
+ HRESULT ( STDMETHODCALLTYPE *IsManaged )(
+ ICorDebugChain * This,
+ /* [out] */ BOOL *pManaged);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumerateFrames )(
+ ICorDebugChain * This,
+ /* [out] */ ICorDebugFrameEnum **ppFrames);
+
+ HRESULT ( STDMETHODCALLTYPE *GetActiveFrame )(
+ ICorDebugChain * This,
+ /* [out] */ ICorDebugFrame **ppFrame);
+
+ HRESULT ( STDMETHODCALLTYPE *GetRegisterSet )(
+ ICorDebugChain * This,
+ /* [out] */ ICorDebugRegisterSet **ppRegisters);
+
+ HRESULT ( STDMETHODCALLTYPE *GetReason )(
+ ICorDebugChain * This,
+ /* [out] */ CorDebugChainReason *pReason);
+
+ END_INTERFACE
+ } ICorDebugChainVtbl;
+
+ interface ICorDebugChain
+ {
+ CONST_VTBL struct ICorDebugChainVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugChain_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugChain_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugChain_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugChain_GetThread(This,ppThread) \
+ ( (This)->lpVtbl -> GetThread(This,ppThread) )
+
+#define ICorDebugChain_GetStackRange(This,pStart,pEnd) \
+ ( (This)->lpVtbl -> GetStackRange(This,pStart,pEnd) )
+
+#define ICorDebugChain_GetContext(This,ppContext) \
+ ( (This)->lpVtbl -> GetContext(This,ppContext) )
+
+#define ICorDebugChain_GetCaller(This,ppChain) \
+ ( (This)->lpVtbl -> GetCaller(This,ppChain) )
+
+#define ICorDebugChain_GetCallee(This,ppChain) \
+ ( (This)->lpVtbl -> GetCallee(This,ppChain) )
+
+#define ICorDebugChain_GetPrevious(This,ppChain) \
+ ( (This)->lpVtbl -> GetPrevious(This,ppChain) )
+
+#define ICorDebugChain_GetNext(This,ppChain) \
+ ( (This)->lpVtbl -> GetNext(This,ppChain) )
+
+#define ICorDebugChain_IsManaged(This,pManaged) \
+ ( (This)->lpVtbl -> IsManaged(This,pManaged) )
+
+#define ICorDebugChain_EnumerateFrames(This,ppFrames) \
+ ( (This)->lpVtbl -> EnumerateFrames(This,ppFrames) )
+
+#define ICorDebugChain_GetActiveFrame(This,ppFrame) \
+ ( (This)->lpVtbl -> GetActiveFrame(This,ppFrame) )
+
+#define ICorDebugChain_GetRegisterSet(This,ppRegisters) \
+ ( (This)->lpVtbl -> GetRegisterSet(This,ppRegisters) )
+
+#define ICorDebugChain_GetReason(This,pReason) \
+ ( (This)->lpVtbl -> GetReason(This,pReason) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugChain_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugFrame_INTERFACE_DEFINED__
+#define __ICorDebugFrame_INTERFACE_DEFINED__
+
+/* interface ICorDebugFrame */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugFrame;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("CC7BCAEF-8A68-11d2-983C-0000F808342D")
+ ICorDebugFrame : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetChain(
+ /* [out] */ ICorDebugChain **ppChain) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetCode(
+ /* [out] */ ICorDebugCode **ppCode) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetFunction(
+ /* [out] */ ICorDebugFunction **ppFunction) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetFunctionToken(
+ /* [out] */ mdMethodDef *pToken) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetStackRange(
+ /* [out] */ CORDB_ADDRESS *pStart,
+ /* [out] */ CORDB_ADDRESS *pEnd) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetCaller(
+ /* [out] */ ICorDebugFrame **ppFrame) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetCallee(
+ /* [out] */ ICorDebugFrame **ppFrame) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE CreateStepper(
+ /* [out] */ ICorDebugStepper **ppStepper) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugFrameVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugFrame * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugFrame * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugFrame * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetChain )(
+ ICorDebugFrame * This,
+ /* [out] */ ICorDebugChain **ppChain);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCode )(
+ ICorDebugFrame * This,
+ /* [out] */ ICorDebugCode **ppCode);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFunction )(
+ ICorDebugFrame * This,
+ /* [out] */ ICorDebugFunction **ppFunction);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFunctionToken )(
+ ICorDebugFrame * This,
+ /* [out] */ mdMethodDef *pToken);
+
+ HRESULT ( STDMETHODCALLTYPE *GetStackRange )(
+ ICorDebugFrame * This,
+ /* [out] */ CORDB_ADDRESS *pStart,
+ /* [out] */ CORDB_ADDRESS *pEnd);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCaller )(
+ ICorDebugFrame * This,
+ /* [out] */ ICorDebugFrame **ppFrame);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCallee )(
+ ICorDebugFrame * This,
+ /* [out] */ ICorDebugFrame **ppFrame);
+
+ HRESULT ( STDMETHODCALLTYPE *CreateStepper )(
+ ICorDebugFrame * This,
+ /* [out] */ ICorDebugStepper **ppStepper);
+
+ END_INTERFACE
+ } ICorDebugFrameVtbl;
+
+ interface ICorDebugFrame
+ {
+ CONST_VTBL struct ICorDebugFrameVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugFrame_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugFrame_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugFrame_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugFrame_GetChain(This,ppChain) \
+ ( (This)->lpVtbl -> GetChain(This,ppChain) )
+
+#define ICorDebugFrame_GetCode(This,ppCode) \
+ ( (This)->lpVtbl -> GetCode(This,ppCode) )
+
+#define ICorDebugFrame_GetFunction(This,ppFunction) \
+ ( (This)->lpVtbl -> GetFunction(This,ppFunction) )
+
+#define ICorDebugFrame_GetFunctionToken(This,pToken) \
+ ( (This)->lpVtbl -> GetFunctionToken(This,pToken) )
+
+#define ICorDebugFrame_GetStackRange(This,pStart,pEnd) \
+ ( (This)->lpVtbl -> GetStackRange(This,pStart,pEnd) )
+
+#define ICorDebugFrame_GetCaller(This,ppFrame) \
+ ( (This)->lpVtbl -> GetCaller(This,ppFrame) )
+
+#define ICorDebugFrame_GetCallee(This,ppFrame) \
+ ( (This)->lpVtbl -> GetCallee(This,ppFrame) )
+
+#define ICorDebugFrame_CreateStepper(This,ppStepper) \
+ ( (This)->lpVtbl -> CreateStepper(This,ppStepper) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugFrame_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugInternalFrame_INTERFACE_DEFINED__
+#define __ICorDebugInternalFrame_INTERFACE_DEFINED__
+
+/* interface ICorDebugInternalFrame */
+/* [unique][uuid][local][object] */
+
+typedef
+enum CorDebugInternalFrameType
+ {
+ STUBFRAME_NONE = 0,
+ STUBFRAME_M2U = 0x1,
+ STUBFRAME_U2M = 0x2,
+ STUBFRAME_APPDOMAIN_TRANSITION = 0x3,
+ STUBFRAME_LIGHTWEIGHT_FUNCTION = 0x4,
+ STUBFRAME_FUNC_EVAL = 0x5,
+ STUBFRAME_INTERNALCALL = 0x6,
+ STUBFRAME_CLASS_INIT = 0x7,
+ STUBFRAME_EXCEPTION = 0x8,
+ STUBFRAME_SECURITY = 0x9,
+ STUBFRAME_JIT_COMPILATION = 0xa
+ } CorDebugInternalFrameType;
+
+
+EXTERN_C const IID IID_ICorDebugInternalFrame;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("B92CC7F7-9D2D-45c4-BC2B-621FCC9DFBF4")
+ ICorDebugInternalFrame : public ICorDebugFrame
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetFrameType(
+ /* [out] */ CorDebugInternalFrameType *pType) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugInternalFrameVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugInternalFrame * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugInternalFrame * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugInternalFrame * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetChain )(
+ ICorDebugInternalFrame * This,
+ /* [out] */ ICorDebugChain **ppChain);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCode )(
+ ICorDebugInternalFrame * This,
+ /* [out] */ ICorDebugCode **ppCode);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFunction )(
+ ICorDebugInternalFrame * This,
+ /* [out] */ ICorDebugFunction **ppFunction);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFunctionToken )(
+ ICorDebugInternalFrame * This,
+ /* [out] */ mdMethodDef *pToken);
+
+ HRESULT ( STDMETHODCALLTYPE *GetStackRange )(
+ ICorDebugInternalFrame * This,
+ /* [out] */ CORDB_ADDRESS *pStart,
+ /* [out] */ CORDB_ADDRESS *pEnd);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCaller )(
+ ICorDebugInternalFrame * This,
+ /* [out] */ ICorDebugFrame **ppFrame);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCallee )(
+ ICorDebugInternalFrame * This,
+ /* [out] */ ICorDebugFrame **ppFrame);
+
+ HRESULT ( STDMETHODCALLTYPE *CreateStepper )(
+ ICorDebugInternalFrame * This,
+ /* [out] */ ICorDebugStepper **ppStepper);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFrameType )(
+ ICorDebugInternalFrame * This,
+ /* [out] */ CorDebugInternalFrameType *pType);
+
+ END_INTERFACE
+ } ICorDebugInternalFrameVtbl;
+
+ interface ICorDebugInternalFrame
+ {
+ CONST_VTBL struct ICorDebugInternalFrameVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugInternalFrame_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugInternalFrame_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugInternalFrame_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugInternalFrame_GetChain(This,ppChain) \
+ ( (This)->lpVtbl -> GetChain(This,ppChain) )
+
+#define ICorDebugInternalFrame_GetCode(This,ppCode) \
+ ( (This)->lpVtbl -> GetCode(This,ppCode) )
+
+#define ICorDebugInternalFrame_GetFunction(This,ppFunction) \
+ ( (This)->lpVtbl -> GetFunction(This,ppFunction) )
+
+#define ICorDebugInternalFrame_GetFunctionToken(This,pToken) \
+ ( (This)->lpVtbl -> GetFunctionToken(This,pToken) )
+
+#define ICorDebugInternalFrame_GetStackRange(This,pStart,pEnd) \
+ ( (This)->lpVtbl -> GetStackRange(This,pStart,pEnd) )
+
+#define ICorDebugInternalFrame_GetCaller(This,ppFrame) \
+ ( (This)->lpVtbl -> GetCaller(This,ppFrame) )
+
+#define ICorDebugInternalFrame_GetCallee(This,ppFrame) \
+ ( (This)->lpVtbl -> GetCallee(This,ppFrame) )
+
+#define ICorDebugInternalFrame_CreateStepper(This,ppStepper) \
+ ( (This)->lpVtbl -> CreateStepper(This,ppStepper) )
+
+
+#define ICorDebugInternalFrame_GetFrameType(This,pType) \
+ ( (This)->lpVtbl -> GetFrameType(This,pType) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugInternalFrame_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugInternalFrame2_INTERFACE_DEFINED__
+#define __ICorDebugInternalFrame2_INTERFACE_DEFINED__
+
+/* interface ICorDebugInternalFrame2 */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugInternalFrame2;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("C0815BDC-CFAB-447e-A779-C116B454EB5B")
+ ICorDebugInternalFrame2 : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetAddress(
+ /* [out] */ CORDB_ADDRESS *pAddress) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE IsCloserToLeaf(
+ /* [in] */ ICorDebugFrame *pFrameToCompare,
+ /* [out] */ BOOL *pIsCloser) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugInternalFrame2Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugInternalFrame2 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugInternalFrame2 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugInternalFrame2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAddress )(
+ ICorDebugInternalFrame2 * This,
+ /* [out] */ CORDB_ADDRESS *pAddress);
+
+ HRESULT ( STDMETHODCALLTYPE *IsCloserToLeaf )(
+ ICorDebugInternalFrame2 * This,
+ /* [in] */ ICorDebugFrame *pFrameToCompare,
+ /* [out] */ BOOL *pIsCloser);
+
+ END_INTERFACE
+ } ICorDebugInternalFrame2Vtbl;
+
+ interface ICorDebugInternalFrame2
+ {
+ CONST_VTBL struct ICorDebugInternalFrame2Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugInternalFrame2_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugInternalFrame2_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugInternalFrame2_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugInternalFrame2_GetAddress(This,pAddress) \
+ ( (This)->lpVtbl -> GetAddress(This,pAddress) )
+
+#define ICorDebugInternalFrame2_IsCloserToLeaf(This,pFrameToCompare,pIsCloser) \
+ ( (This)->lpVtbl -> IsCloserToLeaf(This,pFrameToCompare,pIsCloser) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugInternalFrame2_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugILFrame_INTERFACE_DEFINED__
+#define __ICorDebugILFrame_INTERFACE_DEFINED__
+
+/* interface ICorDebugILFrame */
+/* [unique][uuid][local][object] */
+
+typedef
+enum CorDebugMappingResult
+ {
+ MAPPING_PROLOG = 0x1,
+ MAPPING_EPILOG = 0x2,
+ MAPPING_NO_INFO = 0x4,
+ MAPPING_UNMAPPED_ADDRESS = 0x8,
+ MAPPING_EXACT = 0x10,
+ MAPPING_APPROXIMATE = 0x20
+ } CorDebugMappingResult;
+
+
+EXTERN_C const IID IID_ICorDebugILFrame;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("03E26311-4F76-11d3-88C6-006097945418")
+ ICorDebugILFrame : public ICorDebugFrame
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetIP(
+ /* [out] */ ULONG32 *pnOffset,
+ /* [out] */ CorDebugMappingResult *pMappingResult) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetIP(
+ /* [in] */ ULONG32 nOffset) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnumerateLocalVariables(
+ /* [out] */ ICorDebugValueEnum **ppValueEnum) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetLocalVariable(
+ /* [in] */ DWORD dwIndex,
+ /* [out] */ ICorDebugValue **ppValue) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnumerateArguments(
+ /* [out] */ ICorDebugValueEnum **ppValueEnum) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetArgument(
+ /* [in] */ DWORD dwIndex,
+ /* [out] */ ICorDebugValue **ppValue) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetStackDepth(
+ /* [out] */ ULONG32 *pDepth) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetStackValue(
+ /* [in] */ DWORD dwIndex,
+ /* [out] */ ICorDebugValue **ppValue) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE CanSetIP(
+ /* [in] */ ULONG32 nOffset) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugILFrameVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugILFrame * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugILFrame * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugILFrame * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetChain )(
+ ICorDebugILFrame * This,
+ /* [out] */ ICorDebugChain **ppChain);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCode )(
+ ICorDebugILFrame * This,
+ /* [out] */ ICorDebugCode **ppCode);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFunction )(
+ ICorDebugILFrame * This,
+ /* [out] */ ICorDebugFunction **ppFunction);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFunctionToken )(
+ ICorDebugILFrame * This,
+ /* [out] */ mdMethodDef *pToken);
+
+ HRESULT ( STDMETHODCALLTYPE *GetStackRange )(
+ ICorDebugILFrame * This,
+ /* [out] */ CORDB_ADDRESS *pStart,
+ /* [out] */ CORDB_ADDRESS *pEnd);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCaller )(
+ ICorDebugILFrame * This,
+ /* [out] */ ICorDebugFrame **ppFrame);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCallee )(
+ ICorDebugILFrame * This,
+ /* [out] */ ICorDebugFrame **ppFrame);
+
+ HRESULT ( STDMETHODCALLTYPE *CreateStepper )(
+ ICorDebugILFrame * This,
+ /* [out] */ ICorDebugStepper **ppStepper);
+
+ HRESULT ( STDMETHODCALLTYPE *GetIP )(
+ ICorDebugILFrame * This,
+ /* [out] */ ULONG32 *pnOffset,
+ /* [out] */ CorDebugMappingResult *pMappingResult);
+
+ HRESULT ( STDMETHODCALLTYPE *SetIP )(
+ ICorDebugILFrame * This,
+ /* [in] */ ULONG32 nOffset);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumerateLocalVariables )(
+ ICorDebugILFrame * This,
+ /* [out] */ ICorDebugValueEnum **ppValueEnum);
+
+ HRESULT ( STDMETHODCALLTYPE *GetLocalVariable )(
+ ICorDebugILFrame * This,
+ /* [in] */ DWORD dwIndex,
+ /* [out] */ ICorDebugValue **ppValue);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumerateArguments )(
+ ICorDebugILFrame * This,
+ /* [out] */ ICorDebugValueEnum **ppValueEnum);
+
+ HRESULT ( STDMETHODCALLTYPE *GetArgument )(
+ ICorDebugILFrame * This,
+ /* [in] */ DWORD dwIndex,
+ /* [out] */ ICorDebugValue **ppValue);
+
+ HRESULT ( STDMETHODCALLTYPE *GetStackDepth )(
+ ICorDebugILFrame * This,
+ /* [out] */ ULONG32 *pDepth);
+
+ HRESULT ( STDMETHODCALLTYPE *GetStackValue )(
+ ICorDebugILFrame * This,
+ /* [in] */ DWORD dwIndex,
+ /* [out] */ ICorDebugValue **ppValue);
+
+ HRESULT ( STDMETHODCALLTYPE *CanSetIP )(
+ ICorDebugILFrame * This,
+ /* [in] */ ULONG32 nOffset);
+
+ END_INTERFACE
+ } ICorDebugILFrameVtbl;
+
+ interface ICorDebugILFrame
+ {
+ CONST_VTBL struct ICorDebugILFrameVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugILFrame_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugILFrame_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugILFrame_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugILFrame_GetChain(This,ppChain) \
+ ( (This)->lpVtbl -> GetChain(This,ppChain) )
+
+#define ICorDebugILFrame_GetCode(This,ppCode) \
+ ( (This)->lpVtbl -> GetCode(This,ppCode) )
+
+#define ICorDebugILFrame_GetFunction(This,ppFunction) \
+ ( (This)->lpVtbl -> GetFunction(This,ppFunction) )
+
+#define ICorDebugILFrame_GetFunctionToken(This,pToken) \
+ ( (This)->lpVtbl -> GetFunctionToken(This,pToken) )
+
+#define ICorDebugILFrame_GetStackRange(This,pStart,pEnd) \
+ ( (This)->lpVtbl -> GetStackRange(This,pStart,pEnd) )
+
+#define ICorDebugILFrame_GetCaller(This,ppFrame) \
+ ( (This)->lpVtbl -> GetCaller(This,ppFrame) )
+
+#define ICorDebugILFrame_GetCallee(This,ppFrame) \
+ ( (This)->lpVtbl -> GetCallee(This,ppFrame) )
+
+#define ICorDebugILFrame_CreateStepper(This,ppStepper) \
+ ( (This)->lpVtbl -> CreateStepper(This,ppStepper) )
+
+
+#define ICorDebugILFrame_GetIP(This,pnOffset,pMappingResult) \
+ ( (This)->lpVtbl -> GetIP(This,pnOffset,pMappingResult) )
+
+#define ICorDebugILFrame_SetIP(This,nOffset) \
+ ( (This)->lpVtbl -> SetIP(This,nOffset) )
+
+#define ICorDebugILFrame_EnumerateLocalVariables(This,ppValueEnum) \
+ ( (This)->lpVtbl -> EnumerateLocalVariables(This,ppValueEnum) )
+
+#define ICorDebugILFrame_GetLocalVariable(This,dwIndex,ppValue) \
+ ( (This)->lpVtbl -> GetLocalVariable(This,dwIndex,ppValue) )
+
+#define ICorDebugILFrame_EnumerateArguments(This,ppValueEnum) \
+ ( (This)->lpVtbl -> EnumerateArguments(This,ppValueEnum) )
+
+#define ICorDebugILFrame_GetArgument(This,dwIndex,ppValue) \
+ ( (This)->lpVtbl -> GetArgument(This,dwIndex,ppValue) )
+
+#define ICorDebugILFrame_GetStackDepth(This,pDepth) \
+ ( (This)->lpVtbl -> GetStackDepth(This,pDepth) )
+
+#define ICorDebugILFrame_GetStackValue(This,dwIndex,ppValue) \
+ ( (This)->lpVtbl -> GetStackValue(This,dwIndex,ppValue) )
+
+#define ICorDebugILFrame_CanSetIP(This,nOffset) \
+ ( (This)->lpVtbl -> CanSetIP(This,nOffset) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugILFrame_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugILFrame2_INTERFACE_DEFINED__
+#define __ICorDebugILFrame2_INTERFACE_DEFINED__
+
+/* interface ICorDebugILFrame2 */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugILFrame2;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("5D88A994-6C30-479b-890F-BCEF88B129A5")
+ ICorDebugILFrame2 : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE RemapFunction(
+ /* [in] */ ULONG32 newILOffset) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnumerateTypeParameters(
+ /* [out] */ ICorDebugTypeEnum **ppTyParEnum) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugILFrame2Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugILFrame2 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugILFrame2 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugILFrame2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *RemapFunction )(
+ ICorDebugILFrame2 * This,
+ /* [in] */ ULONG32 newILOffset);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumerateTypeParameters )(
+ ICorDebugILFrame2 * This,
+ /* [out] */ ICorDebugTypeEnum **ppTyParEnum);
+
+ END_INTERFACE
+ } ICorDebugILFrame2Vtbl;
+
+ interface ICorDebugILFrame2
+ {
+ CONST_VTBL struct ICorDebugILFrame2Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugILFrame2_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugILFrame2_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugILFrame2_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugILFrame2_RemapFunction(This,newILOffset) \
+ ( (This)->lpVtbl -> RemapFunction(This,newILOffset) )
+
+#define ICorDebugILFrame2_EnumerateTypeParameters(This,ppTyParEnum) \
+ ( (This)->lpVtbl -> EnumerateTypeParameters(This,ppTyParEnum) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugILFrame2_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugILFrame3_INTERFACE_DEFINED__
+#define __ICorDebugILFrame3_INTERFACE_DEFINED__
+
+/* interface ICorDebugILFrame3 */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugILFrame3;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("9A9E2ED6-04DF-4FE0-BB50-CAB64126AD24")
+ ICorDebugILFrame3 : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetReturnValueForILOffset(
+ ULONG32 ILoffset,
+ /* [out] */ ICorDebugValue **ppReturnValue) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugILFrame3Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugILFrame3 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugILFrame3 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugILFrame3 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetReturnValueForILOffset )(
+ ICorDebugILFrame3 * This,
+ ULONG32 ILoffset,
+ /* [out] */ ICorDebugValue **ppReturnValue);
+
+ END_INTERFACE
+ } ICorDebugILFrame3Vtbl;
+
+ interface ICorDebugILFrame3
+ {
+ CONST_VTBL struct ICorDebugILFrame3Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugILFrame3_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugILFrame3_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugILFrame3_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugILFrame3_GetReturnValueForILOffset(This,ILoffset,ppReturnValue) \
+ ( (This)->lpVtbl -> GetReturnValueForILOffset(This,ILoffset,ppReturnValue) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugILFrame3_INTERFACE_DEFINED__ */
+
+
+/* interface __MIDL_itf_cordebug_0000_0065 */
+/* [local] */
+
+typedef
+enum ILCodeKind
+ {
+ ILCODE_ORIGINAL_IL = 0x1,
+ ILCODE_REJIT_IL = 0x2
+ } ILCodeKind;
+
+
+
+extern RPC_IF_HANDLE __MIDL_itf_cordebug_0000_0065_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_cordebug_0000_0065_v0_0_s_ifspec;
+
+#ifndef __ICorDebugILFrame4_INTERFACE_DEFINED__
+#define __ICorDebugILFrame4_INTERFACE_DEFINED__
+
+/* interface ICorDebugILFrame4 */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugILFrame4;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("AD914A30-C6D1-4AC5-9C5E-577F3BAA8A45")
+ ICorDebugILFrame4 : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE EnumerateLocalVariablesEx(
+ /* [in] */ ILCodeKind flags,
+ /* [out] */ ICorDebugValueEnum **ppValueEnum) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetLocalVariableEx(
+ /* [in] */ ILCodeKind flags,
+ /* [in] */ DWORD dwIndex,
+ /* [out] */ ICorDebugValue **ppValue) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetCodeEx(
+ /* [in] */ ILCodeKind flags,
+ /* [out] */ ICorDebugCode **ppCode) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugILFrame4Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugILFrame4 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugILFrame4 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugILFrame4 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumerateLocalVariablesEx )(
+ ICorDebugILFrame4 * This,
+ /* [in] */ ILCodeKind flags,
+ /* [out] */ ICorDebugValueEnum **ppValueEnum);
+
+ HRESULT ( STDMETHODCALLTYPE *GetLocalVariableEx )(
+ ICorDebugILFrame4 * This,
+ /* [in] */ ILCodeKind flags,
+ /* [in] */ DWORD dwIndex,
+ /* [out] */ ICorDebugValue **ppValue);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCodeEx )(
+ ICorDebugILFrame4 * This,
+ /* [in] */ ILCodeKind flags,
+ /* [out] */ ICorDebugCode **ppCode);
+
+ END_INTERFACE
+ } ICorDebugILFrame4Vtbl;
+
+ interface ICorDebugILFrame4
+ {
+ CONST_VTBL struct ICorDebugILFrame4Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugILFrame4_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugILFrame4_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugILFrame4_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugILFrame4_EnumerateLocalVariablesEx(This,flags,ppValueEnum) \
+ ( (This)->lpVtbl -> EnumerateLocalVariablesEx(This,flags,ppValueEnum) )
+
+#define ICorDebugILFrame4_GetLocalVariableEx(This,flags,dwIndex,ppValue) \
+ ( (This)->lpVtbl -> GetLocalVariableEx(This,flags,dwIndex,ppValue) )
+
+#define ICorDebugILFrame4_GetCodeEx(This,flags,ppCode) \
+ ( (This)->lpVtbl -> GetCodeEx(This,flags,ppCode) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugILFrame4_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugNativeFrame_INTERFACE_DEFINED__
+#define __ICorDebugNativeFrame_INTERFACE_DEFINED__
+
+/* interface ICorDebugNativeFrame */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugNativeFrame;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("03E26314-4F76-11d3-88C6-006097945418")
+ ICorDebugNativeFrame : public ICorDebugFrame
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetIP(
+ /* [out] */ ULONG32 *pnOffset) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetIP(
+ /* [in] */ ULONG32 nOffset) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetRegisterSet(
+ /* [out] */ ICorDebugRegisterSet **ppRegisters) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetLocalRegisterValue(
+ /* [in] */ CorDebugRegister reg,
+ /* [in] */ ULONG cbSigBlob,
+ /* [in] */ PCCOR_SIGNATURE pvSigBlob,
+ /* [out] */ ICorDebugValue **ppValue) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetLocalDoubleRegisterValue(
+ /* [in] */ CorDebugRegister highWordReg,
+ /* [in] */ CorDebugRegister lowWordReg,
+ /* [in] */ ULONG cbSigBlob,
+ /* [in] */ PCCOR_SIGNATURE pvSigBlob,
+ /* [out] */ ICorDebugValue **ppValue) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetLocalMemoryValue(
+ /* [in] */ CORDB_ADDRESS address,
+ /* [in] */ ULONG cbSigBlob,
+ /* [in] */ PCCOR_SIGNATURE pvSigBlob,
+ /* [out] */ ICorDebugValue **ppValue) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetLocalRegisterMemoryValue(
+ /* [in] */ CorDebugRegister highWordReg,
+ /* [in] */ CORDB_ADDRESS lowWordAddress,
+ /* [in] */ ULONG cbSigBlob,
+ /* [in] */ PCCOR_SIGNATURE pvSigBlob,
+ /* [out] */ ICorDebugValue **ppValue) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetLocalMemoryRegisterValue(
+ /* [in] */ CORDB_ADDRESS highWordAddress,
+ /* [in] */ CorDebugRegister lowWordRegister,
+ /* [in] */ ULONG cbSigBlob,
+ /* [in] */ PCCOR_SIGNATURE pvSigBlob,
+ /* [out] */ ICorDebugValue **ppValue) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE CanSetIP(
+ /* [in] */ ULONG32 nOffset) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugNativeFrameVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugNativeFrame * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugNativeFrame * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugNativeFrame * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetChain )(
+ ICorDebugNativeFrame * This,
+ /* [out] */ ICorDebugChain **ppChain);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCode )(
+ ICorDebugNativeFrame * This,
+ /* [out] */ ICorDebugCode **ppCode);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFunction )(
+ ICorDebugNativeFrame * This,
+ /* [out] */ ICorDebugFunction **ppFunction);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFunctionToken )(
+ ICorDebugNativeFrame * This,
+ /* [out] */ mdMethodDef *pToken);
+
+ HRESULT ( STDMETHODCALLTYPE *GetStackRange )(
+ ICorDebugNativeFrame * This,
+ /* [out] */ CORDB_ADDRESS *pStart,
+ /* [out] */ CORDB_ADDRESS *pEnd);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCaller )(
+ ICorDebugNativeFrame * This,
+ /* [out] */ ICorDebugFrame **ppFrame);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCallee )(
+ ICorDebugNativeFrame * This,
+ /* [out] */ ICorDebugFrame **ppFrame);
+
+ HRESULT ( STDMETHODCALLTYPE *CreateStepper )(
+ ICorDebugNativeFrame * This,
+ /* [out] */ ICorDebugStepper **ppStepper);
+
+ HRESULT ( STDMETHODCALLTYPE *GetIP )(
+ ICorDebugNativeFrame * This,
+ /* [out] */ ULONG32 *pnOffset);
+
+ HRESULT ( STDMETHODCALLTYPE *SetIP )(
+ ICorDebugNativeFrame * This,
+ /* [in] */ ULONG32 nOffset);
+
+ HRESULT ( STDMETHODCALLTYPE *GetRegisterSet )(
+ ICorDebugNativeFrame * This,
+ /* [out] */ ICorDebugRegisterSet **ppRegisters);
+
+ HRESULT ( STDMETHODCALLTYPE *GetLocalRegisterValue )(
+ ICorDebugNativeFrame * This,
+ /* [in] */ CorDebugRegister reg,
+ /* [in] */ ULONG cbSigBlob,
+ /* [in] */ PCCOR_SIGNATURE pvSigBlob,
+ /* [out] */ ICorDebugValue **ppValue);
+
+ HRESULT ( STDMETHODCALLTYPE *GetLocalDoubleRegisterValue )(
+ ICorDebugNativeFrame * This,
+ /* [in] */ CorDebugRegister highWordReg,
+ /* [in] */ CorDebugRegister lowWordReg,
+ /* [in] */ ULONG cbSigBlob,
+ /* [in] */ PCCOR_SIGNATURE pvSigBlob,
+ /* [out] */ ICorDebugValue **ppValue);
+
+ HRESULT ( STDMETHODCALLTYPE *GetLocalMemoryValue )(
+ ICorDebugNativeFrame * This,
+ /* [in] */ CORDB_ADDRESS address,
+ /* [in] */ ULONG cbSigBlob,
+ /* [in] */ PCCOR_SIGNATURE pvSigBlob,
+ /* [out] */ ICorDebugValue **ppValue);
+
+ HRESULT ( STDMETHODCALLTYPE *GetLocalRegisterMemoryValue )(
+ ICorDebugNativeFrame * This,
+ /* [in] */ CorDebugRegister highWordReg,
+ /* [in] */ CORDB_ADDRESS lowWordAddress,
+ /* [in] */ ULONG cbSigBlob,
+ /* [in] */ PCCOR_SIGNATURE pvSigBlob,
+ /* [out] */ ICorDebugValue **ppValue);
+
+ HRESULT ( STDMETHODCALLTYPE *GetLocalMemoryRegisterValue )(
+ ICorDebugNativeFrame * This,
+ /* [in] */ CORDB_ADDRESS highWordAddress,
+ /* [in] */ CorDebugRegister lowWordRegister,
+ /* [in] */ ULONG cbSigBlob,
+ /* [in] */ PCCOR_SIGNATURE pvSigBlob,
+ /* [out] */ ICorDebugValue **ppValue);
+
+ HRESULT ( STDMETHODCALLTYPE *CanSetIP )(
+ ICorDebugNativeFrame * This,
+ /* [in] */ ULONG32 nOffset);
+
+ END_INTERFACE
+ } ICorDebugNativeFrameVtbl;
+
+ interface ICorDebugNativeFrame
+ {
+ CONST_VTBL struct ICorDebugNativeFrameVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugNativeFrame_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugNativeFrame_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugNativeFrame_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugNativeFrame_GetChain(This,ppChain) \
+ ( (This)->lpVtbl -> GetChain(This,ppChain) )
+
+#define ICorDebugNativeFrame_GetCode(This,ppCode) \
+ ( (This)->lpVtbl -> GetCode(This,ppCode) )
+
+#define ICorDebugNativeFrame_GetFunction(This,ppFunction) \
+ ( (This)->lpVtbl -> GetFunction(This,ppFunction) )
+
+#define ICorDebugNativeFrame_GetFunctionToken(This,pToken) \
+ ( (This)->lpVtbl -> GetFunctionToken(This,pToken) )
+
+#define ICorDebugNativeFrame_GetStackRange(This,pStart,pEnd) \
+ ( (This)->lpVtbl -> GetStackRange(This,pStart,pEnd) )
+
+#define ICorDebugNativeFrame_GetCaller(This,ppFrame) \
+ ( (This)->lpVtbl -> GetCaller(This,ppFrame) )
+
+#define ICorDebugNativeFrame_GetCallee(This,ppFrame) \
+ ( (This)->lpVtbl -> GetCallee(This,ppFrame) )
+
+#define ICorDebugNativeFrame_CreateStepper(This,ppStepper) \
+ ( (This)->lpVtbl -> CreateStepper(This,ppStepper) )
+
+
+#define ICorDebugNativeFrame_GetIP(This,pnOffset) \
+ ( (This)->lpVtbl -> GetIP(This,pnOffset) )
+
+#define ICorDebugNativeFrame_SetIP(This,nOffset) \
+ ( (This)->lpVtbl -> SetIP(This,nOffset) )
+
+#define ICorDebugNativeFrame_GetRegisterSet(This,ppRegisters) \
+ ( (This)->lpVtbl -> GetRegisterSet(This,ppRegisters) )
+
+#define ICorDebugNativeFrame_GetLocalRegisterValue(This,reg,cbSigBlob,pvSigBlob,ppValue) \
+ ( (This)->lpVtbl -> GetLocalRegisterValue(This,reg,cbSigBlob,pvSigBlob,ppValue) )
+
+#define ICorDebugNativeFrame_GetLocalDoubleRegisterValue(This,highWordReg,lowWordReg,cbSigBlob,pvSigBlob,ppValue) \
+ ( (This)->lpVtbl -> GetLocalDoubleRegisterValue(This,highWordReg,lowWordReg,cbSigBlob,pvSigBlob,ppValue) )
+
+#define ICorDebugNativeFrame_GetLocalMemoryValue(This,address,cbSigBlob,pvSigBlob,ppValue) \
+ ( (This)->lpVtbl -> GetLocalMemoryValue(This,address,cbSigBlob,pvSigBlob,ppValue) )
+
+#define ICorDebugNativeFrame_GetLocalRegisterMemoryValue(This,highWordReg,lowWordAddress,cbSigBlob,pvSigBlob,ppValue) \
+ ( (This)->lpVtbl -> GetLocalRegisterMemoryValue(This,highWordReg,lowWordAddress,cbSigBlob,pvSigBlob,ppValue) )
+
+#define ICorDebugNativeFrame_GetLocalMemoryRegisterValue(This,highWordAddress,lowWordRegister,cbSigBlob,pvSigBlob,ppValue) \
+ ( (This)->lpVtbl -> GetLocalMemoryRegisterValue(This,highWordAddress,lowWordRegister,cbSigBlob,pvSigBlob,ppValue) )
+
+#define ICorDebugNativeFrame_CanSetIP(This,nOffset) \
+ ( (This)->lpVtbl -> CanSetIP(This,nOffset) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugNativeFrame_INTERFACE_DEFINED__ */
+
+
+/* interface __MIDL_itf_cordebug_0000_0067 */
+/* [local] */
+
+#pragma warning(push)
+#pragma warning(disable:28718)
+
+
+extern RPC_IF_HANDLE __MIDL_itf_cordebug_0000_0067_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_cordebug_0000_0067_v0_0_s_ifspec;
+
+#ifndef __ICorDebugNativeFrame2_INTERFACE_DEFINED__
+#define __ICorDebugNativeFrame2_INTERFACE_DEFINED__
+
+/* interface ICorDebugNativeFrame2 */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugNativeFrame2;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("35389FF1-3684-4c55-A2EE-210F26C60E5E")
+ ICorDebugNativeFrame2 : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE IsChild(
+ /* [out] */ BOOL *pIsChild) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE IsMatchingParentFrame(
+ /* [in] */ ICorDebugNativeFrame2 *pPotentialParentFrame,
+ /* [out] */ BOOL *pIsParent) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetStackParameterSize(
+ /* [out] */ ULONG32 *pSize) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugNativeFrame2Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugNativeFrame2 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugNativeFrame2 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugNativeFrame2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *IsChild )(
+ ICorDebugNativeFrame2 * This,
+ /* [out] */ BOOL *pIsChild);
+
+ HRESULT ( STDMETHODCALLTYPE *IsMatchingParentFrame )(
+ ICorDebugNativeFrame2 * This,
+ /* [in] */ ICorDebugNativeFrame2 *pPotentialParentFrame,
+ /* [out] */ BOOL *pIsParent);
+
+ HRESULT ( STDMETHODCALLTYPE *GetStackParameterSize )(
+ ICorDebugNativeFrame2 * This,
+ /* [out] */ ULONG32 *pSize);
+
+ END_INTERFACE
+ } ICorDebugNativeFrame2Vtbl;
+
+ interface ICorDebugNativeFrame2
+ {
+ CONST_VTBL struct ICorDebugNativeFrame2Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugNativeFrame2_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugNativeFrame2_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugNativeFrame2_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugNativeFrame2_IsChild(This,pIsChild) \
+ ( (This)->lpVtbl -> IsChild(This,pIsChild) )
+
+#define ICorDebugNativeFrame2_IsMatchingParentFrame(This,pPotentialParentFrame,pIsParent) \
+ ( (This)->lpVtbl -> IsMatchingParentFrame(This,pPotentialParentFrame,pIsParent) )
+
+#define ICorDebugNativeFrame2_GetStackParameterSize(This,pSize) \
+ ( (This)->lpVtbl -> GetStackParameterSize(This,pSize) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugNativeFrame2_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugModule3_INTERFACE_DEFINED__
+#define __ICorDebugModule3_INTERFACE_DEFINED__
+
+/* interface ICorDebugModule3 */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugModule3;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("86F012BF-FF15-4372-BD30-B6F11CAAE1DD")
+ ICorDebugModule3 : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE CreateReaderForInMemorySymbols(
+ /* [in] */ REFIID riid,
+ /* [iid_is][out] */ void **ppObj) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugModule3Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugModule3 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugModule3 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugModule3 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *CreateReaderForInMemorySymbols )(
+ ICorDebugModule3 * This,
+ /* [in] */ REFIID riid,
+ /* [iid_is][out] */ void **ppObj);
+
+ END_INTERFACE
+ } ICorDebugModule3Vtbl;
+
+ interface ICorDebugModule3
+ {
+ CONST_VTBL struct ICorDebugModule3Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugModule3_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugModule3_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugModule3_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugModule3_CreateReaderForInMemorySymbols(This,riid,ppObj) \
+ ( (This)->lpVtbl -> CreateReaderForInMemorySymbols(This,riid,ppObj) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugModule3_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugRuntimeUnwindableFrame_INTERFACE_DEFINED__
+#define __ICorDebugRuntimeUnwindableFrame_INTERFACE_DEFINED__
+
+/* interface ICorDebugRuntimeUnwindableFrame */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugRuntimeUnwindableFrame;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("879CAC0A-4A53-4668-B8E3-CB8473CB187F")
+ ICorDebugRuntimeUnwindableFrame : public ICorDebugFrame
+ {
+ public:
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugRuntimeUnwindableFrameVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugRuntimeUnwindableFrame * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugRuntimeUnwindableFrame * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugRuntimeUnwindableFrame * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetChain )(
+ ICorDebugRuntimeUnwindableFrame * This,
+ /* [out] */ ICorDebugChain **ppChain);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCode )(
+ ICorDebugRuntimeUnwindableFrame * This,
+ /* [out] */ ICorDebugCode **ppCode);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFunction )(
+ ICorDebugRuntimeUnwindableFrame * This,
+ /* [out] */ ICorDebugFunction **ppFunction);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFunctionToken )(
+ ICorDebugRuntimeUnwindableFrame * This,
+ /* [out] */ mdMethodDef *pToken);
+
+ HRESULT ( STDMETHODCALLTYPE *GetStackRange )(
+ ICorDebugRuntimeUnwindableFrame * This,
+ /* [out] */ CORDB_ADDRESS *pStart,
+ /* [out] */ CORDB_ADDRESS *pEnd);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCaller )(
+ ICorDebugRuntimeUnwindableFrame * This,
+ /* [out] */ ICorDebugFrame **ppFrame);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCallee )(
+ ICorDebugRuntimeUnwindableFrame * This,
+ /* [out] */ ICorDebugFrame **ppFrame);
+
+ HRESULT ( STDMETHODCALLTYPE *CreateStepper )(
+ ICorDebugRuntimeUnwindableFrame * This,
+ /* [out] */ ICorDebugStepper **ppStepper);
+
+ END_INTERFACE
+ } ICorDebugRuntimeUnwindableFrameVtbl;
+
+ interface ICorDebugRuntimeUnwindableFrame
+ {
+ CONST_VTBL struct ICorDebugRuntimeUnwindableFrameVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugRuntimeUnwindableFrame_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugRuntimeUnwindableFrame_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugRuntimeUnwindableFrame_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugRuntimeUnwindableFrame_GetChain(This,ppChain) \
+ ( (This)->lpVtbl -> GetChain(This,ppChain) )
+
+#define ICorDebugRuntimeUnwindableFrame_GetCode(This,ppCode) \
+ ( (This)->lpVtbl -> GetCode(This,ppCode) )
+
+#define ICorDebugRuntimeUnwindableFrame_GetFunction(This,ppFunction) \
+ ( (This)->lpVtbl -> GetFunction(This,ppFunction) )
+
+#define ICorDebugRuntimeUnwindableFrame_GetFunctionToken(This,pToken) \
+ ( (This)->lpVtbl -> GetFunctionToken(This,pToken) )
+
+#define ICorDebugRuntimeUnwindableFrame_GetStackRange(This,pStart,pEnd) \
+ ( (This)->lpVtbl -> GetStackRange(This,pStart,pEnd) )
+
+#define ICorDebugRuntimeUnwindableFrame_GetCaller(This,ppFrame) \
+ ( (This)->lpVtbl -> GetCaller(This,ppFrame) )
+
+#define ICorDebugRuntimeUnwindableFrame_GetCallee(This,ppFrame) \
+ ( (This)->lpVtbl -> GetCallee(This,ppFrame) )
+
+#define ICorDebugRuntimeUnwindableFrame_CreateStepper(This,ppStepper) \
+ ( (This)->lpVtbl -> CreateStepper(This,ppStepper) )
+
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugRuntimeUnwindableFrame_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugModule_INTERFACE_DEFINED__
+#define __ICorDebugModule_INTERFACE_DEFINED__
+
+/* interface ICorDebugModule */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugModule;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("dba2d8c1-e5c5-4069-8c13-10a7c6abf43d")
+ ICorDebugModule : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetProcess(
+ /* [out] */ ICorDebugProcess **ppProcess) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetBaseAddress(
+ /* [out] */ CORDB_ADDRESS *pAddress) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetAssembly(
+ /* [out] */ ICorDebugAssembly **ppAssembly) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetName(
+ /* [in] */ ULONG32 cchName,
+ /* [out] */ ULONG32 *pcchName,
+ /* [length_is][size_is][out] */ WCHAR szName[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnableJITDebugging(
+ /* [in] */ BOOL bTrackJITInfo,
+ /* [in] */ BOOL bAllowJitOpts) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnableClassLoadCallbacks(
+ /* [in] */ BOOL bClassLoadCallbacks) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetFunctionFromToken(
+ /* [in] */ mdMethodDef methodDef,
+ /* [out] */ ICorDebugFunction **ppFunction) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetFunctionFromRVA(
+ /* [in] */ CORDB_ADDRESS rva,
+ /* [out] */ ICorDebugFunction **ppFunction) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetClassFromToken(
+ /* [in] */ mdTypeDef typeDef,
+ /* [out] */ ICorDebugClass **ppClass) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE CreateBreakpoint(
+ /* [out] */ ICorDebugModuleBreakpoint **ppBreakpoint) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetEditAndContinueSnapshot(
+ /* [out] */ ICorDebugEditAndContinueSnapshot **ppEditAndContinueSnapshot) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetMetaDataInterface(
+ /* [in] */ REFIID riid,
+ /* [out] */ IUnknown **ppObj) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetToken(
+ /* [out] */ mdModule *pToken) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE IsDynamic(
+ /* [out] */ BOOL *pDynamic) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetGlobalVariableValue(
+ /* [in] */ mdFieldDef fieldDef,
+ /* [out] */ ICorDebugValue **ppValue) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetSize(
+ /* [out] */ ULONG32 *pcBytes) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE IsInMemory(
+ /* [out] */ BOOL *pInMemory) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugModuleVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugModule * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugModule * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugModule * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetProcess )(
+ ICorDebugModule * This,
+ /* [out] */ ICorDebugProcess **ppProcess);
+
+ HRESULT ( STDMETHODCALLTYPE *GetBaseAddress )(
+ ICorDebugModule * This,
+ /* [out] */ CORDB_ADDRESS *pAddress);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAssembly )(
+ ICorDebugModule * This,
+ /* [out] */ ICorDebugAssembly **ppAssembly);
+
+ HRESULT ( STDMETHODCALLTYPE *GetName )(
+ ICorDebugModule * This,
+ /* [in] */ ULONG32 cchName,
+ /* [out] */ ULONG32 *pcchName,
+ /* [length_is][size_is][out] */ WCHAR szName[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *EnableJITDebugging )(
+ ICorDebugModule * This,
+ /* [in] */ BOOL bTrackJITInfo,
+ /* [in] */ BOOL bAllowJitOpts);
+
+ HRESULT ( STDMETHODCALLTYPE *EnableClassLoadCallbacks )(
+ ICorDebugModule * This,
+ /* [in] */ BOOL bClassLoadCallbacks);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFunctionFromToken )(
+ ICorDebugModule * This,
+ /* [in] */ mdMethodDef methodDef,
+ /* [out] */ ICorDebugFunction **ppFunction);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFunctionFromRVA )(
+ ICorDebugModule * This,
+ /* [in] */ CORDB_ADDRESS rva,
+ /* [out] */ ICorDebugFunction **ppFunction);
+
+ HRESULT ( STDMETHODCALLTYPE *GetClassFromToken )(
+ ICorDebugModule * This,
+ /* [in] */ mdTypeDef typeDef,
+ /* [out] */ ICorDebugClass **ppClass);
+
+ HRESULT ( STDMETHODCALLTYPE *CreateBreakpoint )(
+ ICorDebugModule * This,
+ /* [out] */ ICorDebugModuleBreakpoint **ppBreakpoint);
+
+ HRESULT ( STDMETHODCALLTYPE *GetEditAndContinueSnapshot )(
+ ICorDebugModule * This,
+ /* [out] */ ICorDebugEditAndContinueSnapshot **ppEditAndContinueSnapshot);
+
+ HRESULT ( STDMETHODCALLTYPE *GetMetaDataInterface )(
+ ICorDebugModule * This,
+ /* [in] */ REFIID riid,
+ /* [out] */ IUnknown **ppObj);
+
+ HRESULT ( STDMETHODCALLTYPE *GetToken )(
+ ICorDebugModule * This,
+ /* [out] */ mdModule *pToken);
+
+ HRESULT ( STDMETHODCALLTYPE *IsDynamic )(
+ ICorDebugModule * This,
+ /* [out] */ BOOL *pDynamic);
+
+ HRESULT ( STDMETHODCALLTYPE *GetGlobalVariableValue )(
+ ICorDebugModule * This,
+ /* [in] */ mdFieldDef fieldDef,
+ /* [out] */ ICorDebugValue **ppValue);
+
+ HRESULT ( STDMETHODCALLTYPE *GetSize )(
+ ICorDebugModule * This,
+ /* [out] */ ULONG32 *pcBytes);
+
+ HRESULT ( STDMETHODCALLTYPE *IsInMemory )(
+ ICorDebugModule * This,
+ /* [out] */ BOOL *pInMemory);
+
+ END_INTERFACE
+ } ICorDebugModuleVtbl;
+
+ interface ICorDebugModule
+ {
+ CONST_VTBL struct ICorDebugModuleVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugModule_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugModule_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugModule_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugModule_GetProcess(This,ppProcess) \
+ ( (This)->lpVtbl -> GetProcess(This,ppProcess) )
+
+#define ICorDebugModule_GetBaseAddress(This,pAddress) \
+ ( (This)->lpVtbl -> GetBaseAddress(This,pAddress) )
+
+#define ICorDebugModule_GetAssembly(This,ppAssembly) \
+ ( (This)->lpVtbl -> GetAssembly(This,ppAssembly) )
+
+#define ICorDebugModule_GetName(This,cchName,pcchName,szName) \
+ ( (This)->lpVtbl -> GetName(This,cchName,pcchName,szName) )
+
+#define ICorDebugModule_EnableJITDebugging(This,bTrackJITInfo,bAllowJitOpts) \
+ ( (This)->lpVtbl -> EnableJITDebugging(This,bTrackJITInfo,bAllowJitOpts) )
+
+#define ICorDebugModule_EnableClassLoadCallbacks(This,bClassLoadCallbacks) \
+ ( (This)->lpVtbl -> EnableClassLoadCallbacks(This,bClassLoadCallbacks) )
+
+#define ICorDebugModule_GetFunctionFromToken(This,methodDef,ppFunction) \
+ ( (This)->lpVtbl -> GetFunctionFromToken(This,methodDef,ppFunction) )
+
+#define ICorDebugModule_GetFunctionFromRVA(This,rva,ppFunction) \
+ ( (This)->lpVtbl -> GetFunctionFromRVA(This,rva,ppFunction) )
+
+#define ICorDebugModule_GetClassFromToken(This,typeDef,ppClass) \
+ ( (This)->lpVtbl -> GetClassFromToken(This,typeDef,ppClass) )
+
+#define ICorDebugModule_CreateBreakpoint(This,ppBreakpoint) \
+ ( (This)->lpVtbl -> CreateBreakpoint(This,ppBreakpoint) )
+
+#define ICorDebugModule_GetEditAndContinueSnapshot(This,ppEditAndContinueSnapshot) \
+ ( (This)->lpVtbl -> GetEditAndContinueSnapshot(This,ppEditAndContinueSnapshot) )
+
+#define ICorDebugModule_GetMetaDataInterface(This,riid,ppObj) \
+ ( (This)->lpVtbl -> GetMetaDataInterface(This,riid,ppObj) )
+
+#define ICorDebugModule_GetToken(This,pToken) \
+ ( (This)->lpVtbl -> GetToken(This,pToken) )
+
+#define ICorDebugModule_IsDynamic(This,pDynamic) \
+ ( (This)->lpVtbl -> IsDynamic(This,pDynamic) )
+
+#define ICorDebugModule_GetGlobalVariableValue(This,fieldDef,ppValue) \
+ ( (This)->lpVtbl -> GetGlobalVariableValue(This,fieldDef,ppValue) )
+
+#define ICorDebugModule_GetSize(This,pcBytes) \
+ ( (This)->lpVtbl -> GetSize(This,pcBytes) )
+
+#define ICorDebugModule_IsInMemory(This,pInMemory) \
+ ( (This)->lpVtbl -> IsInMemory(This,pInMemory) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugModule_INTERFACE_DEFINED__ */
+
+
+/* interface __MIDL_itf_cordebug_0000_0071 */
+/* [local] */
+
+#pragma warning(pop)
+
+
+extern RPC_IF_HANDLE __MIDL_itf_cordebug_0000_0071_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_cordebug_0000_0071_v0_0_s_ifspec;
+
+#ifndef __ICorDebugModule2_INTERFACE_DEFINED__
+#define __ICorDebugModule2_INTERFACE_DEFINED__
+
+/* interface ICorDebugModule2 */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugModule2;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("7FCC5FB5-49C0-41de-9938-3B88B5B9ADD7")
+ ICorDebugModule2 : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE SetJMCStatus(
+ /* [in] */ BOOL bIsJustMyCode,
+ /* [in] */ ULONG32 cTokens,
+ /* [size_is][in] */ mdToken pTokens[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ApplyChanges(
+ /* [in] */ ULONG cbMetadata,
+ /* [size_is][in] */ BYTE pbMetadata[ ],
+ /* [in] */ ULONG cbIL,
+ /* [size_is][in] */ BYTE pbIL[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetJITCompilerFlags(
+ /* [in] */ DWORD dwFlags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetJITCompilerFlags(
+ /* [out] */ DWORD *pdwFlags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ResolveAssembly(
+ /* [in] */ mdToken tkAssemblyRef,
+ /* [out] */ ICorDebugAssembly **ppAssembly) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugModule2Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugModule2 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugModule2 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugModule2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *SetJMCStatus )(
+ ICorDebugModule2 * This,
+ /* [in] */ BOOL bIsJustMyCode,
+ /* [in] */ ULONG32 cTokens,
+ /* [size_is][in] */ mdToken pTokens[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *ApplyChanges )(
+ ICorDebugModule2 * This,
+ /* [in] */ ULONG cbMetadata,
+ /* [size_is][in] */ BYTE pbMetadata[ ],
+ /* [in] */ ULONG cbIL,
+ /* [size_is][in] */ BYTE pbIL[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *SetJITCompilerFlags )(
+ ICorDebugModule2 * This,
+ /* [in] */ DWORD dwFlags);
+
+ HRESULT ( STDMETHODCALLTYPE *GetJITCompilerFlags )(
+ ICorDebugModule2 * This,
+ /* [out] */ DWORD *pdwFlags);
+
+ HRESULT ( STDMETHODCALLTYPE *ResolveAssembly )(
+ ICorDebugModule2 * This,
+ /* [in] */ mdToken tkAssemblyRef,
+ /* [out] */ ICorDebugAssembly **ppAssembly);
+
+ END_INTERFACE
+ } ICorDebugModule2Vtbl;
+
+ interface ICorDebugModule2
+ {
+ CONST_VTBL struct ICorDebugModule2Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugModule2_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugModule2_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugModule2_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugModule2_SetJMCStatus(This,bIsJustMyCode,cTokens,pTokens) \
+ ( (This)->lpVtbl -> SetJMCStatus(This,bIsJustMyCode,cTokens,pTokens) )
+
+#define ICorDebugModule2_ApplyChanges(This,cbMetadata,pbMetadata,cbIL,pbIL) \
+ ( (This)->lpVtbl -> ApplyChanges(This,cbMetadata,pbMetadata,cbIL,pbIL) )
+
+#define ICorDebugModule2_SetJITCompilerFlags(This,dwFlags) \
+ ( (This)->lpVtbl -> SetJITCompilerFlags(This,dwFlags) )
+
+#define ICorDebugModule2_GetJITCompilerFlags(This,pdwFlags) \
+ ( (This)->lpVtbl -> GetJITCompilerFlags(This,pdwFlags) )
+
+#define ICorDebugModule2_ResolveAssembly(This,tkAssemblyRef,ppAssembly) \
+ ( (This)->lpVtbl -> ResolveAssembly(This,tkAssemblyRef,ppAssembly) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugModule2_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugFunction_INTERFACE_DEFINED__
+#define __ICorDebugFunction_INTERFACE_DEFINED__
+
+/* interface ICorDebugFunction */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugFunction;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("CC7BCAF3-8A68-11d2-983C-0000F808342D")
+ ICorDebugFunction : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetModule(
+ /* [out] */ ICorDebugModule **ppModule) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetClass(
+ /* [out] */ ICorDebugClass **ppClass) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetToken(
+ /* [out] */ mdMethodDef *pMethodDef) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetILCode(
+ /* [out] */ ICorDebugCode **ppCode) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetNativeCode(
+ /* [out] */ ICorDebugCode **ppCode) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE CreateBreakpoint(
+ /* [out] */ ICorDebugFunctionBreakpoint **ppBreakpoint) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetLocalVarSigToken(
+ /* [out] */ mdSignature *pmdSig) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetCurrentVersionNumber(
+ /* [out] */ ULONG32 *pnCurrentVersion) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugFunctionVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugFunction * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugFunction * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugFunction * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetModule )(
+ ICorDebugFunction * This,
+ /* [out] */ ICorDebugModule **ppModule);
+
+ HRESULT ( STDMETHODCALLTYPE *GetClass )(
+ ICorDebugFunction * This,
+ /* [out] */ ICorDebugClass **ppClass);
+
+ HRESULT ( STDMETHODCALLTYPE *GetToken )(
+ ICorDebugFunction * This,
+ /* [out] */ mdMethodDef *pMethodDef);
+
+ HRESULT ( STDMETHODCALLTYPE *GetILCode )(
+ ICorDebugFunction * This,
+ /* [out] */ ICorDebugCode **ppCode);
+
+ HRESULT ( STDMETHODCALLTYPE *GetNativeCode )(
+ ICorDebugFunction * This,
+ /* [out] */ ICorDebugCode **ppCode);
+
+ HRESULT ( STDMETHODCALLTYPE *CreateBreakpoint )(
+ ICorDebugFunction * This,
+ /* [out] */ ICorDebugFunctionBreakpoint **ppBreakpoint);
+
+ HRESULT ( STDMETHODCALLTYPE *GetLocalVarSigToken )(
+ ICorDebugFunction * This,
+ /* [out] */ mdSignature *pmdSig);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCurrentVersionNumber )(
+ ICorDebugFunction * This,
+ /* [out] */ ULONG32 *pnCurrentVersion);
+
+ END_INTERFACE
+ } ICorDebugFunctionVtbl;
+
+ interface ICorDebugFunction
+ {
+ CONST_VTBL struct ICorDebugFunctionVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugFunction_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugFunction_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugFunction_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugFunction_GetModule(This,ppModule) \
+ ( (This)->lpVtbl -> GetModule(This,ppModule) )
+
+#define ICorDebugFunction_GetClass(This,ppClass) \
+ ( (This)->lpVtbl -> GetClass(This,ppClass) )
+
+#define ICorDebugFunction_GetToken(This,pMethodDef) \
+ ( (This)->lpVtbl -> GetToken(This,pMethodDef) )
+
+#define ICorDebugFunction_GetILCode(This,ppCode) \
+ ( (This)->lpVtbl -> GetILCode(This,ppCode) )
+
+#define ICorDebugFunction_GetNativeCode(This,ppCode) \
+ ( (This)->lpVtbl -> GetNativeCode(This,ppCode) )
+
+#define ICorDebugFunction_CreateBreakpoint(This,ppBreakpoint) \
+ ( (This)->lpVtbl -> CreateBreakpoint(This,ppBreakpoint) )
+
+#define ICorDebugFunction_GetLocalVarSigToken(This,pmdSig) \
+ ( (This)->lpVtbl -> GetLocalVarSigToken(This,pmdSig) )
+
+#define ICorDebugFunction_GetCurrentVersionNumber(This,pnCurrentVersion) \
+ ( (This)->lpVtbl -> GetCurrentVersionNumber(This,pnCurrentVersion) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugFunction_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugFunction2_INTERFACE_DEFINED__
+#define __ICorDebugFunction2_INTERFACE_DEFINED__
+
+/* interface ICorDebugFunction2 */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugFunction2;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("EF0C490B-94C3-4e4d-B629-DDC134C532D8")
+ ICorDebugFunction2 : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE SetJMCStatus(
+ /* [in] */ BOOL bIsJustMyCode) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetJMCStatus(
+ /* [out] */ BOOL *pbIsJustMyCode) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnumerateNativeCode(
+ /* [out] */ ICorDebugCodeEnum **ppCodeEnum) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetVersionNumber(
+ /* [out] */ ULONG32 *pnVersion) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugFunction2Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugFunction2 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugFunction2 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugFunction2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *SetJMCStatus )(
+ ICorDebugFunction2 * This,
+ /* [in] */ BOOL bIsJustMyCode);
+
+ HRESULT ( STDMETHODCALLTYPE *GetJMCStatus )(
+ ICorDebugFunction2 * This,
+ /* [out] */ BOOL *pbIsJustMyCode);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumerateNativeCode )(
+ ICorDebugFunction2 * This,
+ /* [out] */ ICorDebugCodeEnum **ppCodeEnum);
+
+ HRESULT ( STDMETHODCALLTYPE *GetVersionNumber )(
+ ICorDebugFunction2 * This,
+ /* [out] */ ULONG32 *pnVersion);
+
+ END_INTERFACE
+ } ICorDebugFunction2Vtbl;
+
+ interface ICorDebugFunction2
+ {
+ CONST_VTBL struct ICorDebugFunction2Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugFunction2_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugFunction2_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugFunction2_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugFunction2_SetJMCStatus(This,bIsJustMyCode) \
+ ( (This)->lpVtbl -> SetJMCStatus(This,bIsJustMyCode) )
+
+#define ICorDebugFunction2_GetJMCStatus(This,pbIsJustMyCode) \
+ ( (This)->lpVtbl -> GetJMCStatus(This,pbIsJustMyCode) )
+
+#define ICorDebugFunction2_EnumerateNativeCode(This,ppCodeEnum) \
+ ( (This)->lpVtbl -> EnumerateNativeCode(This,ppCodeEnum) )
+
+#define ICorDebugFunction2_GetVersionNumber(This,pnVersion) \
+ ( (This)->lpVtbl -> GetVersionNumber(This,pnVersion) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugFunction2_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugFunction3_INTERFACE_DEFINED__
+#define __ICorDebugFunction3_INTERFACE_DEFINED__
+
+/* interface ICorDebugFunction3 */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugFunction3;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("09B70F28-E465-482D-99E0-81A165EB0532")
+ ICorDebugFunction3 : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetActiveReJitRequestILCode(
+ ICorDebugILCode **ppReJitedILCode) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugFunction3Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugFunction3 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugFunction3 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugFunction3 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetActiveReJitRequestILCode )(
+ ICorDebugFunction3 * This,
+ ICorDebugILCode **ppReJitedILCode);
+
+ END_INTERFACE
+ } ICorDebugFunction3Vtbl;
+
+ interface ICorDebugFunction3
+ {
+ CONST_VTBL struct ICorDebugFunction3Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugFunction3_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugFunction3_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugFunction3_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugFunction3_GetActiveReJitRequestILCode(This,ppReJitedILCode) \
+ ( (This)->lpVtbl -> GetActiveReJitRequestILCode(This,ppReJitedILCode) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugFunction3_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugCode_INTERFACE_DEFINED__
+#define __ICorDebugCode_INTERFACE_DEFINED__
+
+/* interface ICorDebugCode */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugCode;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("CC7BCAF4-8A68-11d2-983C-0000F808342D")
+ ICorDebugCode : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE IsIL(
+ /* [out] */ BOOL *pbIL) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetFunction(
+ /* [out] */ ICorDebugFunction **ppFunction) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetAddress(
+ /* [out] */ CORDB_ADDRESS *pStart) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetSize(
+ /* [out] */ ULONG32 *pcBytes) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE CreateBreakpoint(
+ /* [in] */ ULONG32 offset,
+ /* [out] */ ICorDebugFunctionBreakpoint **ppBreakpoint) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetCode(
+ /* [in] */ ULONG32 startOffset,
+ /* [in] */ ULONG32 endOffset,
+ /* [in] */ ULONG32 cBufferAlloc,
+ /* [length_is][size_is][out] */ BYTE buffer[ ],
+ /* [out] */ ULONG32 *pcBufferSize) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetVersionNumber(
+ /* [out] */ ULONG32 *nVersion) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetILToNativeMapping(
+ /* [in] */ ULONG32 cMap,
+ /* [out] */ ULONG32 *pcMap,
+ /* [length_is][size_is][out] */ COR_DEBUG_IL_TO_NATIVE_MAP map[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetEnCRemapSequencePoints(
+ /* [in] */ ULONG32 cMap,
+ /* [out] */ ULONG32 *pcMap,
+ /* [length_is][size_is][out] */ ULONG32 offsets[ ]) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugCodeVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugCode * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugCode * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugCode * This);
+
+ HRESULT ( STDMETHODCALLTYPE *IsIL )(
+ ICorDebugCode * This,
+ /* [out] */ BOOL *pbIL);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFunction )(
+ ICorDebugCode * This,
+ /* [out] */ ICorDebugFunction **ppFunction);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAddress )(
+ ICorDebugCode * This,
+ /* [out] */ CORDB_ADDRESS *pStart);
+
+ HRESULT ( STDMETHODCALLTYPE *GetSize )(
+ ICorDebugCode * This,
+ /* [out] */ ULONG32 *pcBytes);
+
+ HRESULT ( STDMETHODCALLTYPE *CreateBreakpoint )(
+ ICorDebugCode * This,
+ /* [in] */ ULONG32 offset,
+ /* [out] */ ICorDebugFunctionBreakpoint **ppBreakpoint);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCode )(
+ ICorDebugCode * This,
+ /* [in] */ ULONG32 startOffset,
+ /* [in] */ ULONG32 endOffset,
+ /* [in] */ ULONG32 cBufferAlloc,
+ /* [length_is][size_is][out] */ BYTE buffer[ ],
+ /* [out] */ ULONG32 *pcBufferSize);
+
+ HRESULT ( STDMETHODCALLTYPE *GetVersionNumber )(
+ ICorDebugCode * This,
+ /* [out] */ ULONG32 *nVersion);
+
+ HRESULT ( STDMETHODCALLTYPE *GetILToNativeMapping )(
+ ICorDebugCode * This,
+ /* [in] */ ULONG32 cMap,
+ /* [out] */ ULONG32 *pcMap,
+ /* [length_is][size_is][out] */ COR_DEBUG_IL_TO_NATIVE_MAP map[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetEnCRemapSequencePoints )(
+ ICorDebugCode * This,
+ /* [in] */ ULONG32 cMap,
+ /* [out] */ ULONG32 *pcMap,
+ /* [length_is][size_is][out] */ ULONG32 offsets[ ]);
+
+ END_INTERFACE
+ } ICorDebugCodeVtbl;
+
+ interface ICorDebugCode
+ {
+ CONST_VTBL struct ICorDebugCodeVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugCode_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugCode_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugCode_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugCode_IsIL(This,pbIL) \
+ ( (This)->lpVtbl -> IsIL(This,pbIL) )
+
+#define ICorDebugCode_GetFunction(This,ppFunction) \
+ ( (This)->lpVtbl -> GetFunction(This,ppFunction) )
+
+#define ICorDebugCode_GetAddress(This,pStart) \
+ ( (This)->lpVtbl -> GetAddress(This,pStart) )
+
+#define ICorDebugCode_GetSize(This,pcBytes) \
+ ( (This)->lpVtbl -> GetSize(This,pcBytes) )
+
+#define ICorDebugCode_CreateBreakpoint(This,offset,ppBreakpoint) \
+ ( (This)->lpVtbl -> CreateBreakpoint(This,offset,ppBreakpoint) )
+
+#define ICorDebugCode_GetCode(This,startOffset,endOffset,cBufferAlloc,buffer,pcBufferSize) \
+ ( (This)->lpVtbl -> GetCode(This,startOffset,endOffset,cBufferAlloc,buffer,pcBufferSize) )
+
+#define ICorDebugCode_GetVersionNumber(This,nVersion) \
+ ( (This)->lpVtbl -> GetVersionNumber(This,nVersion) )
+
+#define ICorDebugCode_GetILToNativeMapping(This,cMap,pcMap,map) \
+ ( (This)->lpVtbl -> GetILToNativeMapping(This,cMap,pcMap,map) )
+
+#define ICorDebugCode_GetEnCRemapSequencePoints(This,cMap,pcMap,offsets) \
+ ( (This)->lpVtbl -> GetEnCRemapSequencePoints(This,cMap,pcMap,offsets) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugCode_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugCode2_INTERFACE_DEFINED__
+#define __ICorDebugCode2_INTERFACE_DEFINED__
+
+/* interface ICorDebugCode2 */
+/* [unique][uuid][local][object] */
+
+typedef struct _CodeChunkInfo
+ {
+ CORDB_ADDRESS startAddr;
+ ULONG32 length;
+ } CodeChunkInfo;
+
+
+EXTERN_C const IID IID_ICorDebugCode2;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("5F696509-452F-4436-A3FE-4D11FE7E2347")
+ ICorDebugCode2 : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetCodeChunks(
+ /* [in] */ ULONG32 cbufSize,
+ /* [out] */ ULONG32 *pcnumChunks,
+ /* [length_is][size_is][out] */ CodeChunkInfo chunks[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetCompilerFlags(
+ /* [out] */ DWORD *pdwFlags) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugCode2Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugCode2 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugCode2 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugCode2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCodeChunks )(
+ ICorDebugCode2 * This,
+ /* [in] */ ULONG32 cbufSize,
+ /* [out] */ ULONG32 *pcnumChunks,
+ /* [length_is][size_is][out] */ CodeChunkInfo chunks[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCompilerFlags )(
+ ICorDebugCode2 * This,
+ /* [out] */ DWORD *pdwFlags);
+
+ END_INTERFACE
+ } ICorDebugCode2Vtbl;
+
+ interface ICorDebugCode2
+ {
+ CONST_VTBL struct ICorDebugCode2Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugCode2_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugCode2_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugCode2_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugCode2_GetCodeChunks(This,cbufSize,pcnumChunks,chunks) \
+ ( (This)->lpVtbl -> GetCodeChunks(This,cbufSize,pcnumChunks,chunks) )
+
+#define ICorDebugCode2_GetCompilerFlags(This,pdwFlags) \
+ ( (This)->lpVtbl -> GetCompilerFlags(This,pdwFlags) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugCode2_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugCode3_INTERFACE_DEFINED__
+#define __ICorDebugCode3_INTERFACE_DEFINED__
+
+/* interface ICorDebugCode3 */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugCode3;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("D13D3E88-E1F2-4020-AA1D-3D162DCBE966")
+ ICorDebugCode3 : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetReturnValueLiveOffset(
+ /* [in] */ ULONG32 ILoffset,
+ /* [in] */ ULONG32 bufferSize,
+ /* [out] */ ULONG32 *pFetched,
+ /* [length_is][size_is][out] */ ULONG32 pOffsets[ ]) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugCode3Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugCode3 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugCode3 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugCode3 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetReturnValueLiveOffset )(
+ ICorDebugCode3 * This,
+ /* [in] */ ULONG32 ILoffset,
+ /* [in] */ ULONG32 bufferSize,
+ /* [out] */ ULONG32 *pFetched,
+ /* [length_is][size_is][out] */ ULONG32 pOffsets[ ]);
+
+ END_INTERFACE
+ } ICorDebugCode3Vtbl;
+
+ interface ICorDebugCode3
+ {
+ CONST_VTBL struct ICorDebugCode3Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugCode3_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugCode3_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugCode3_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugCode3_GetReturnValueLiveOffset(This,ILoffset,bufferSize,pFetched,pOffsets) \
+ ( (This)->lpVtbl -> GetReturnValueLiveOffset(This,ILoffset,bufferSize,pFetched,pOffsets) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugCode3_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugILCode_INTERFACE_DEFINED__
+#define __ICorDebugILCode_INTERFACE_DEFINED__
+
+/* interface ICorDebugILCode */
+/* [unique][uuid][local][object] */
+
+typedef struct _CorDebugEHClause
+ {
+ ULONG32 Flags;
+ ULONG32 TryOffset;
+ ULONG32 TryLength;
+ ULONG32 HandlerOffset;
+ ULONG32 HandlerLength;
+ ULONG32 ClassToken;
+ ULONG32 FilterOffset;
+ } CorDebugEHClause;
+
+
+EXTERN_C const IID IID_ICorDebugILCode;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("598D46C2-C877-42A7-89D2-3D0C7F1C1264")
+ ICorDebugILCode : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetEHClauses(
+ /* [in] */ ULONG32 cClauses,
+ /* [out] */ ULONG32 *pcClauses,
+ /* [length_is][size_is][out] */ CorDebugEHClause clauses[ ]) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugILCodeVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugILCode * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugILCode * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugILCode * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetEHClauses )(
+ ICorDebugILCode * This,
+ /* [in] */ ULONG32 cClauses,
+ /* [out] */ ULONG32 *pcClauses,
+ /* [length_is][size_is][out] */ CorDebugEHClause clauses[ ]);
+
+ END_INTERFACE
+ } ICorDebugILCodeVtbl;
+
+ interface ICorDebugILCode
+ {
+ CONST_VTBL struct ICorDebugILCodeVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugILCode_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugILCode_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugILCode_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugILCode_GetEHClauses(This,cClauses,pcClauses,clauses) \
+ ( (This)->lpVtbl -> GetEHClauses(This,cClauses,pcClauses,clauses) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugILCode_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugILCode2_INTERFACE_DEFINED__
+#define __ICorDebugILCode2_INTERFACE_DEFINED__
+
+/* interface ICorDebugILCode2 */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugILCode2;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("46586093-D3F5-4DB6-ACDB-955BCE228C15")
+ ICorDebugILCode2 : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetLocalVarSigToken(
+ /* [out] */ mdSignature *pmdSig) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetInstrumentedILMap(
+ /* [in] */ ULONG32 cMap,
+ /* [out] */ ULONG32 *pcMap,
+ /* [length_is][size_is][out] */ COR_IL_MAP map[ ]) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugILCode2Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugILCode2 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugILCode2 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugILCode2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetLocalVarSigToken )(
+ ICorDebugILCode2 * This,
+ /* [out] */ mdSignature *pmdSig);
+
+ HRESULT ( STDMETHODCALLTYPE *GetInstrumentedILMap )(
+ ICorDebugILCode2 * This,
+ /* [in] */ ULONG32 cMap,
+ /* [out] */ ULONG32 *pcMap,
+ /* [length_is][size_is][out] */ COR_IL_MAP map[ ]);
+
+ END_INTERFACE
+ } ICorDebugILCode2Vtbl;
+
+ interface ICorDebugILCode2
+ {
+ CONST_VTBL struct ICorDebugILCode2Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugILCode2_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugILCode2_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugILCode2_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugILCode2_GetLocalVarSigToken(This,pmdSig) \
+ ( (This)->lpVtbl -> GetLocalVarSigToken(This,pmdSig) )
+
+#define ICorDebugILCode2_GetInstrumentedILMap(This,cMap,pcMap,map) \
+ ( (This)->lpVtbl -> GetInstrumentedILMap(This,cMap,pcMap,map) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugILCode2_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugClass_INTERFACE_DEFINED__
+#define __ICorDebugClass_INTERFACE_DEFINED__
+
+/* interface ICorDebugClass */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugClass;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("CC7BCAF5-8A68-11d2-983C-0000F808342D")
+ ICorDebugClass : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetModule(
+ /* [out] */ ICorDebugModule **pModule) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetToken(
+ /* [out] */ mdTypeDef *pTypeDef) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetStaticFieldValue(
+ /* [in] */ mdFieldDef fieldDef,
+ /* [in] */ ICorDebugFrame *pFrame,
+ /* [out] */ ICorDebugValue **ppValue) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugClassVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugClass * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugClass * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugClass * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetModule )(
+ ICorDebugClass * This,
+ /* [out] */ ICorDebugModule **pModule);
+
+ HRESULT ( STDMETHODCALLTYPE *GetToken )(
+ ICorDebugClass * This,
+ /* [out] */ mdTypeDef *pTypeDef);
+
+ HRESULT ( STDMETHODCALLTYPE *GetStaticFieldValue )(
+ ICorDebugClass * This,
+ /* [in] */ mdFieldDef fieldDef,
+ /* [in] */ ICorDebugFrame *pFrame,
+ /* [out] */ ICorDebugValue **ppValue);
+
+ END_INTERFACE
+ } ICorDebugClassVtbl;
+
+ interface ICorDebugClass
+ {
+ CONST_VTBL struct ICorDebugClassVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugClass_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugClass_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugClass_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugClass_GetModule(This,pModule) \
+ ( (This)->lpVtbl -> GetModule(This,pModule) )
+
+#define ICorDebugClass_GetToken(This,pTypeDef) \
+ ( (This)->lpVtbl -> GetToken(This,pTypeDef) )
+
+#define ICorDebugClass_GetStaticFieldValue(This,fieldDef,pFrame,ppValue) \
+ ( (This)->lpVtbl -> GetStaticFieldValue(This,fieldDef,pFrame,ppValue) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugClass_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugClass2_INTERFACE_DEFINED__
+#define __ICorDebugClass2_INTERFACE_DEFINED__
+
+/* interface ICorDebugClass2 */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugClass2;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("B008EA8D-7AB1-43f7-BB20-FBB5A04038AE")
+ ICorDebugClass2 : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetParameterizedType(
+ /* [in] */ CorElementType elementType,
+ /* [in] */ ULONG32 nTypeArgs,
+ /* [size_is][in] */ ICorDebugType *ppTypeArgs[ ],
+ /* [out] */ ICorDebugType **ppType) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetJMCStatus(
+ /* [in] */ BOOL bIsJustMyCode) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugClass2Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugClass2 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugClass2 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugClass2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetParameterizedType )(
+ ICorDebugClass2 * This,
+ /* [in] */ CorElementType elementType,
+ /* [in] */ ULONG32 nTypeArgs,
+ /* [size_is][in] */ ICorDebugType *ppTypeArgs[ ],
+ /* [out] */ ICorDebugType **ppType);
+
+ HRESULT ( STDMETHODCALLTYPE *SetJMCStatus )(
+ ICorDebugClass2 * This,
+ /* [in] */ BOOL bIsJustMyCode);
+
+ END_INTERFACE
+ } ICorDebugClass2Vtbl;
+
+ interface ICorDebugClass2
+ {
+ CONST_VTBL struct ICorDebugClass2Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugClass2_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugClass2_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugClass2_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugClass2_GetParameterizedType(This,elementType,nTypeArgs,ppTypeArgs,ppType) \
+ ( (This)->lpVtbl -> GetParameterizedType(This,elementType,nTypeArgs,ppTypeArgs,ppType) )
+
+#define ICorDebugClass2_SetJMCStatus(This,bIsJustMyCode) \
+ ( (This)->lpVtbl -> SetJMCStatus(This,bIsJustMyCode) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugClass2_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugEval_INTERFACE_DEFINED__
+#define __ICorDebugEval_INTERFACE_DEFINED__
+
+/* interface ICorDebugEval */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugEval;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("CC7BCAF6-8A68-11d2-983C-0000F808342D")
+ ICorDebugEval : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE CallFunction(
+ /* [in] */ ICorDebugFunction *pFunction,
+ /* [in] */ ULONG32 nArgs,
+ /* [size_is][in] */ ICorDebugValue *ppArgs[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE NewObject(
+ /* [in] */ ICorDebugFunction *pConstructor,
+ /* [in] */ ULONG32 nArgs,
+ /* [size_is][in] */ ICorDebugValue *ppArgs[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE NewObjectNoConstructor(
+ /* [in] */ ICorDebugClass *pClass) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE NewString(
+ /* [in] */ LPCWSTR string) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE NewArray(
+ /* [in] */ CorElementType elementType,
+ /* [in] */ ICorDebugClass *pElementClass,
+ /* [in] */ ULONG32 rank,
+ /* [size_is][in] */ ULONG32 dims[ ],
+ /* [size_is][in] */ ULONG32 lowBounds[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE IsActive(
+ /* [out] */ BOOL *pbActive) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Abort( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetResult(
+ /* [out] */ ICorDebugValue **ppResult) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetThread(
+ /* [out] */ ICorDebugThread **ppThread) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE CreateValue(
+ /* [in] */ CorElementType elementType,
+ /* [in] */ ICorDebugClass *pElementClass,
+ /* [out] */ ICorDebugValue **ppValue) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugEvalVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugEval * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugEval * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugEval * This);
+
+ HRESULT ( STDMETHODCALLTYPE *CallFunction )(
+ ICorDebugEval * This,
+ /* [in] */ ICorDebugFunction *pFunction,
+ /* [in] */ ULONG32 nArgs,
+ /* [size_is][in] */ ICorDebugValue *ppArgs[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *NewObject )(
+ ICorDebugEval * This,
+ /* [in] */ ICorDebugFunction *pConstructor,
+ /* [in] */ ULONG32 nArgs,
+ /* [size_is][in] */ ICorDebugValue *ppArgs[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *NewObjectNoConstructor )(
+ ICorDebugEval * This,
+ /* [in] */ ICorDebugClass *pClass);
+
+ HRESULT ( STDMETHODCALLTYPE *NewString )(
+ ICorDebugEval * This,
+ /* [in] */ LPCWSTR string);
+
+ HRESULT ( STDMETHODCALLTYPE *NewArray )(
+ ICorDebugEval * This,
+ /* [in] */ CorElementType elementType,
+ /* [in] */ ICorDebugClass *pElementClass,
+ /* [in] */ ULONG32 rank,
+ /* [size_is][in] */ ULONG32 dims[ ],
+ /* [size_is][in] */ ULONG32 lowBounds[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *IsActive )(
+ ICorDebugEval * This,
+ /* [out] */ BOOL *pbActive);
+
+ HRESULT ( STDMETHODCALLTYPE *Abort )(
+ ICorDebugEval * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetResult )(
+ ICorDebugEval * This,
+ /* [out] */ ICorDebugValue **ppResult);
+
+ HRESULT ( STDMETHODCALLTYPE *GetThread )(
+ ICorDebugEval * This,
+ /* [out] */ ICorDebugThread **ppThread);
+
+ HRESULT ( STDMETHODCALLTYPE *CreateValue )(
+ ICorDebugEval * This,
+ /* [in] */ CorElementType elementType,
+ /* [in] */ ICorDebugClass *pElementClass,
+ /* [out] */ ICorDebugValue **ppValue);
+
+ END_INTERFACE
+ } ICorDebugEvalVtbl;
+
+ interface ICorDebugEval
+ {
+ CONST_VTBL struct ICorDebugEvalVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugEval_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugEval_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugEval_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugEval_CallFunction(This,pFunction,nArgs,ppArgs) \
+ ( (This)->lpVtbl -> CallFunction(This,pFunction,nArgs,ppArgs) )
+
+#define ICorDebugEval_NewObject(This,pConstructor,nArgs,ppArgs) \
+ ( (This)->lpVtbl -> NewObject(This,pConstructor,nArgs,ppArgs) )
+
+#define ICorDebugEval_NewObjectNoConstructor(This,pClass) \
+ ( (This)->lpVtbl -> NewObjectNoConstructor(This,pClass) )
+
+#define ICorDebugEval_NewString(This,string) \
+ ( (This)->lpVtbl -> NewString(This,string) )
+
+#define ICorDebugEval_NewArray(This,elementType,pElementClass,rank,dims,lowBounds) \
+ ( (This)->lpVtbl -> NewArray(This,elementType,pElementClass,rank,dims,lowBounds) )
+
+#define ICorDebugEval_IsActive(This,pbActive) \
+ ( (This)->lpVtbl -> IsActive(This,pbActive) )
+
+#define ICorDebugEval_Abort(This) \
+ ( (This)->lpVtbl -> Abort(This) )
+
+#define ICorDebugEval_GetResult(This,ppResult) \
+ ( (This)->lpVtbl -> GetResult(This,ppResult) )
+
+#define ICorDebugEval_GetThread(This,ppThread) \
+ ( (This)->lpVtbl -> GetThread(This,ppThread) )
+
+#define ICorDebugEval_CreateValue(This,elementType,pElementClass,ppValue) \
+ ( (This)->lpVtbl -> CreateValue(This,elementType,pElementClass,ppValue) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugEval_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugEval2_INTERFACE_DEFINED__
+#define __ICorDebugEval2_INTERFACE_DEFINED__
+
+/* interface ICorDebugEval2 */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugEval2;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("FB0D9CE7-BE66-4683-9D32-A42A04E2FD91")
+ ICorDebugEval2 : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE CallParameterizedFunction(
+ /* [in] */ ICorDebugFunction *pFunction,
+ /* [in] */ ULONG32 nTypeArgs,
+ /* [size_is][in] */ ICorDebugType *ppTypeArgs[ ],
+ /* [in] */ ULONG32 nArgs,
+ /* [size_is][in] */ ICorDebugValue *ppArgs[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE CreateValueForType(
+ /* [in] */ ICorDebugType *pType,
+ /* [out] */ ICorDebugValue **ppValue) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE NewParameterizedObject(
+ /* [in] */ ICorDebugFunction *pConstructor,
+ /* [in] */ ULONG32 nTypeArgs,
+ /* [size_is][in] */ ICorDebugType *ppTypeArgs[ ],
+ /* [in] */ ULONG32 nArgs,
+ /* [size_is][in] */ ICorDebugValue *ppArgs[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE NewParameterizedObjectNoConstructor(
+ /* [in] */ ICorDebugClass *pClass,
+ /* [in] */ ULONG32 nTypeArgs,
+ /* [size_is][in] */ ICorDebugType *ppTypeArgs[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE NewParameterizedArray(
+ /* [in] */ ICorDebugType *pElementType,
+ /* [in] */ ULONG32 rank,
+ /* [size_is][in] */ ULONG32 dims[ ],
+ /* [size_is][in] */ ULONG32 lowBounds[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE NewStringWithLength(
+ /* [in] */ LPCWSTR string,
+ /* [in] */ UINT uiLength) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE RudeAbort( void) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugEval2Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugEval2 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugEval2 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugEval2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *CallParameterizedFunction )(
+ ICorDebugEval2 * This,
+ /* [in] */ ICorDebugFunction *pFunction,
+ /* [in] */ ULONG32 nTypeArgs,
+ /* [size_is][in] */ ICorDebugType *ppTypeArgs[ ],
+ /* [in] */ ULONG32 nArgs,
+ /* [size_is][in] */ ICorDebugValue *ppArgs[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *CreateValueForType )(
+ ICorDebugEval2 * This,
+ /* [in] */ ICorDebugType *pType,
+ /* [out] */ ICorDebugValue **ppValue);
+
+ HRESULT ( STDMETHODCALLTYPE *NewParameterizedObject )(
+ ICorDebugEval2 * This,
+ /* [in] */ ICorDebugFunction *pConstructor,
+ /* [in] */ ULONG32 nTypeArgs,
+ /* [size_is][in] */ ICorDebugType *ppTypeArgs[ ],
+ /* [in] */ ULONG32 nArgs,
+ /* [size_is][in] */ ICorDebugValue *ppArgs[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *NewParameterizedObjectNoConstructor )(
+ ICorDebugEval2 * This,
+ /* [in] */ ICorDebugClass *pClass,
+ /* [in] */ ULONG32 nTypeArgs,
+ /* [size_is][in] */ ICorDebugType *ppTypeArgs[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *NewParameterizedArray )(
+ ICorDebugEval2 * This,
+ /* [in] */ ICorDebugType *pElementType,
+ /* [in] */ ULONG32 rank,
+ /* [size_is][in] */ ULONG32 dims[ ],
+ /* [size_is][in] */ ULONG32 lowBounds[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *NewStringWithLength )(
+ ICorDebugEval2 * This,
+ /* [in] */ LPCWSTR string,
+ /* [in] */ UINT uiLength);
+
+ HRESULT ( STDMETHODCALLTYPE *RudeAbort )(
+ ICorDebugEval2 * This);
+
+ END_INTERFACE
+ } ICorDebugEval2Vtbl;
+
+ interface ICorDebugEval2
+ {
+ CONST_VTBL struct ICorDebugEval2Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugEval2_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugEval2_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugEval2_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugEval2_CallParameterizedFunction(This,pFunction,nTypeArgs,ppTypeArgs,nArgs,ppArgs) \
+ ( (This)->lpVtbl -> CallParameterizedFunction(This,pFunction,nTypeArgs,ppTypeArgs,nArgs,ppArgs) )
+
+#define ICorDebugEval2_CreateValueForType(This,pType,ppValue) \
+ ( (This)->lpVtbl -> CreateValueForType(This,pType,ppValue) )
+
+#define ICorDebugEval2_NewParameterizedObject(This,pConstructor,nTypeArgs,ppTypeArgs,nArgs,ppArgs) \
+ ( (This)->lpVtbl -> NewParameterizedObject(This,pConstructor,nTypeArgs,ppTypeArgs,nArgs,ppArgs) )
+
+#define ICorDebugEval2_NewParameterizedObjectNoConstructor(This,pClass,nTypeArgs,ppTypeArgs) \
+ ( (This)->lpVtbl -> NewParameterizedObjectNoConstructor(This,pClass,nTypeArgs,ppTypeArgs) )
+
+#define ICorDebugEval2_NewParameterizedArray(This,pElementType,rank,dims,lowBounds) \
+ ( (This)->lpVtbl -> NewParameterizedArray(This,pElementType,rank,dims,lowBounds) )
+
+#define ICorDebugEval2_NewStringWithLength(This,string,uiLength) \
+ ( (This)->lpVtbl -> NewStringWithLength(This,string,uiLength) )
+
+#define ICorDebugEval2_RudeAbort(This) \
+ ( (This)->lpVtbl -> RudeAbort(This) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugEval2_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugValue_INTERFACE_DEFINED__
+#define __ICorDebugValue_INTERFACE_DEFINED__
+
+/* interface ICorDebugValue */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugValue;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("CC7BCAF7-8A68-11d2-983C-0000F808342D")
+ ICorDebugValue : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetType(
+ /* [out] */ CorElementType *pType) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetSize(
+ /* [out] */ ULONG32 *pSize) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetAddress(
+ /* [out] */ CORDB_ADDRESS *pAddress) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE CreateBreakpoint(
+ /* [out] */ ICorDebugValueBreakpoint **ppBreakpoint) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugValueVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugValue * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugValue * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugValue * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetType )(
+ ICorDebugValue * This,
+ /* [out] */ CorElementType *pType);
+
+ HRESULT ( STDMETHODCALLTYPE *GetSize )(
+ ICorDebugValue * This,
+ /* [out] */ ULONG32 *pSize);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAddress )(
+ ICorDebugValue * This,
+ /* [out] */ CORDB_ADDRESS *pAddress);
+
+ HRESULT ( STDMETHODCALLTYPE *CreateBreakpoint )(
+ ICorDebugValue * This,
+ /* [out] */ ICorDebugValueBreakpoint **ppBreakpoint);
+
+ END_INTERFACE
+ } ICorDebugValueVtbl;
+
+ interface ICorDebugValue
+ {
+ CONST_VTBL struct ICorDebugValueVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugValue_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugValue_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugValue_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugValue_GetType(This,pType) \
+ ( (This)->lpVtbl -> GetType(This,pType) )
+
+#define ICorDebugValue_GetSize(This,pSize) \
+ ( (This)->lpVtbl -> GetSize(This,pSize) )
+
+#define ICorDebugValue_GetAddress(This,pAddress) \
+ ( (This)->lpVtbl -> GetAddress(This,pAddress) )
+
+#define ICorDebugValue_CreateBreakpoint(This,ppBreakpoint) \
+ ( (This)->lpVtbl -> CreateBreakpoint(This,ppBreakpoint) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugValue_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugValue2_INTERFACE_DEFINED__
+#define __ICorDebugValue2_INTERFACE_DEFINED__
+
+/* interface ICorDebugValue2 */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugValue2;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("5E0B54E7-D88A-4626-9420-A691E0A78B49")
+ ICorDebugValue2 : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetExactType(
+ /* [out] */ ICorDebugType **ppType) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugValue2Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugValue2 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugValue2 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugValue2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetExactType )(
+ ICorDebugValue2 * This,
+ /* [out] */ ICorDebugType **ppType);
+
+ END_INTERFACE
+ } ICorDebugValue2Vtbl;
+
+ interface ICorDebugValue2
+ {
+ CONST_VTBL struct ICorDebugValue2Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugValue2_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugValue2_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugValue2_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugValue2_GetExactType(This,ppType) \
+ ( (This)->lpVtbl -> GetExactType(This,ppType) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugValue2_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugValue3_INTERFACE_DEFINED__
+#define __ICorDebugValue3_INTERFACE_DEFINED__
+
+/* interface ICorDebugValue3 */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugValue3;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("565005FC-0F8A-4F3E-9EDB-83102B156595")
+ ICorDebugValue3 : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetSize64(
+ /* [out] */ ULONG64 *pSize) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugValue3Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugValue3 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugValue3 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugValue3 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetSize64 )(
+ ICorDebugValue3 * This,
+ /* [out] */ ULONG64 *pSize);
+
+ END_INTERFACE
+ } ICorDebugValue3Vtbl;
+
+ interface ICorDebugValue3
+ {
+ CONST_VTBL struct ICorDebugValue3Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugValue3_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugValue3_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugValue3_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugValue3_GetSize64(This,pSize) \
+ ( (This)->lpVtbl -> GetSize64(This,pSize) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugValue3_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugGenericValue_INTERFACE_DEFINED__
+#define __ICorDebugGenericValue_INTERFACE_DEFINED__
+
+/* interface ICorDebugGenericValue */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugGenericValue;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("CC7BCAF8-8A68-11d2-983C-0000F808342D")
+ ICorDebugGenericValue : public ICorDebugValue
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetValue(
+ /* [out] */ void *pTo) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetValue(
+ /* [in] */ void *pFrom) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugGenericValueVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugGenericValue * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugGenericValue * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugGenericValue * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetType )(
+ ICorDebugGenericValue * This,
+ /* [out] */ CorElementType *pType);
+
+ HRESULT ( STDMETHODCALLTYPE *GetSize )(
+ ICorDebugGenericValue * This,
+ /* [out] */ ULONG32 *pSize);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAddress )(
+ ICorDebugGenericValue * This,
+ /* [out] */ CORDB_ADDRESS *pAddress);
+
+ HRESULT ( STDMETHODCALLTYPE *CreateBreakpoint )(
+ ICorDebugGenericValue * This,
+ /* [out] */ ICorDebugValueBreakpoint **ppBreakpoint);
+
+ HRESULT ( STDMETHODCALLTYPE *GetValue )(
+ ICorDebugGenericValue * This,
+ /* [out] */ void *pTo);
+
+ HRESULT ( STDMETHODCALLTYPE *SetValue )(
+ ICorDebugGenericValue * This,
+ /* [in] */ void *pFrom);
+
+ END_INTERFACE
+ } ICorDebugGenericValueVtbl;
+
+ interface ICorDebugGenericValue
+ {
+ CONST_VTBL struct ICorDebugGenericValueVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugGenericValue_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugGenericValue_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugGenericValue_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugGenericValue_GetType(This,pType) \
+ ( (This)->lpVtbl -> GetType(This,pType) )
+
+#define ICorDebugGenericValue_GetSize(This,pSize) \
+ ( (This)->lpVtbl -> GetSize(This,pSize) )
+
+#define ICorDebugGenericValue_GetAddress(This,pAddress) \
+ ( (This)->lpVtbl -> GetAddress(This,pAddress) )
+
+#define ICorDebugGenericValue_CreateBreakpoint(This,ppBreakpoint) \
+ ( (This)->lpVtbl -> CreateBreakpoint(This,ppBreakpoint) )
+
+
+#define ICorDebugGenericValue_GetValue(This,pTo) \
+ ( (This)->lpVtbl -> GetValue(This,pTo) )
+
+#define ICorDebugGenericValue_SetValue(This,pFrom) \
+ ( (This)->lpVtbl -> SetValue(This,pFrom) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugGenericValue_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugReferenceValue_INTERFACE_DEFINED__
+#define __ICorDebugReferenceValue_INTERFACE_DEFINED__
+
+/* interface ICorDebugReferenceValue */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugReferenceValue;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("CC7BCAF9-8A68-11d2-983C-0000F808342D")
+ ICorDebugReferenceValue : public ICorDebugValue
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE IsNull(
+ /* [out] */ BOOL *pbNull) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetValue(
+ /* [out] */ CORDB_ADDRESS *pValue) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetValue(
+ /* [in] */ CORDB_ADDRESS value) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Dereference(
+ /* [out] */ ICorDebugValue **ppValue) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE DereferenceStrong(
+ /* [out] */ ICorDebugValue **ppValue) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugReferenceValueVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugReferenceValue * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugReferenceValue * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugReferenceValue * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetType )(
+ ICorDebugReferenceValue * This,
+ /* [out] */ CorElementType *pType);
+
+ HRESULT ( STDMETHODCALLTYPE *GetSize )(
+ ICorDebugReferenceValue * This,
+ /* [out] */ ULONG32 *pSize);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAddress )(
+ ICorDebugReferenceValue * This,
+ /* [out] */ CORDB_ADDRESS *pAddress);
+
+ HRESULT ( STDMETHODCALLTYPE *CreateBreakpoint )(
+ ICorDebugReferenceValue * This,
+ /* [out] */ ICorDebugValueBreakpoint **ppBreakpoint);
+
+ HRESULT ( STDMETHODCALLTYPE *IsNull )(
+ ICorDebugReferenceValue * This,
+ /* [out] */ BOOL *pbNull);
+
+ HRESULT ( STDMETHODCALLTYPE *GetValue )(
+ ICorDebugReferenceValue * This,
+ /* [out] */ CORDB_ADDRESS *pValue);
+
+ HRESULT ( STDMETHODCALLTYPE *SetValue )(
+ ICorDebugReferenceValue * This,
+ /* [in] */ CORDB_ADDRESS value);
+
+ HRESULT ( STDMETHODCALLTYPE *Dereference )(
+ ICorDebugReferenceValue * This,
+ /* [out] */ ICorDebugValue **ppValue);
+
+ HRESULT ( STDMETHODCALLTYPE *DereferenceStrong )(
+ ICorDebugReferenceValue * This,
+ /* [out] */ ICorDebugValue **ppValue);
+
+ END_INTERFACE
+ } ICorDebugReferenceValueVtbl;
+
+ interface ICorDebugReferenceValue
+ {
+ CONST_VTBL struct ICorDebugReferenceValueVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugReferenceValue_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugReferenceValue_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugReferenceValue_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugReferenceValue_GetType(This,pType) \
+ ( (This)->lpVtbl -> GetType(This,pType) )
+
+#define ICorDebugReferenceValue_GetSize(This,pSize) \
+ ( (This)->lpVtbl -> GetSize(This,pSize) )
+
+#define ICorDebugReferenceValue_GetAddress(This,pAddress) \
+ ( (This)->lpVtbl -> GetAddress(This,pAddress) )
+
+#define ICorDebugReferenceValue_CreateBreakpoint(This,ppBreakpoint) \
+ ( (This)->lpVtbl -> CreateBreakpoint(This,ppBreakpoint) )
+
+
+#define ICorDebugReferenceValue_IsNull(This,pbNull) \
+ ( (This)->lpVtbl -> IsNull(This,pbNull) )
+
+#define ICorDebugReferenceValue_GetValue(This,pValue) \
+ ( (This)->lpVtbl -> GetValue(This,pValue) )
+
+#define ICorDebugReferenceValue_SetValue(This,value) \
+ ( (This)->lpVtbl -> SetValue(This,value) )
+
+#define ICorDebugReferenceValue_Dereference(This,ppValue) \
+ ( (This)->lpVtbl -> Dereference(This,ppValue) )
+
+#define ICorDebugReferenceValue_DereferenceStrong(This,ppValue) \
+ ( (This)->lpVtbl -> DereferenceStrong(This,ppValue) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugReferenceValue_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugHeapValue_INTERFACE_DEFINED__
+#define __ICorDebugHeapValue_INTERFACE_DEFINED__
+
+/* interface ICorDebugHeapValue */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugHeapValue;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("CC7BCAFA-8A68-11d2-983C-0000F808342D")
+ ICorDebugHeapValue : public ICorDebugValue
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE IsValid(
+ /* [out] */ BOOL *pbValid) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE CreateRelocBreakpoint(
+ /* [out] */ ICorDebugValueBreakpoint **ppBreakpoint) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugHeapValueVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugHeapValue * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugHeapValue * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugHeapValue * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetType )(
+ ICorDebugHeapValue * This,
+ /* [out] */ CorElementType *pType);
+
+ HRESULT ( STDMETHODCALLTYPE *GetSize )(
+ ICorDebugHeapValue * This,
+ /* [out] */ ULONG32 *pSize);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAddress )(
+ ICorDebugHeapValue * This,
+ /* [out] */ CORDB_ADDRESS *pAddress);
+
+ HRESULT ( STDMETHODCALLTYPE *CreateBreakpoint )(
+ ICorDebugHeapValue * This,
+ /* [out] */ ICorDebugValueBreakpoint **ppBreakpoint);
+
+ HRESULT ( STDMETHODCALLTYPE *IsValid )(
+ ICorDebugHeapValue * This,
+ /* [out] */ BOOL *pbValid);
+
+ HRESULT ( STDMETHODCALLTYPE *CreateRelocBreakpoint )(
+ ICorDebugHeapValue * This,
+ /* [out] */ ICorDebugValueBreakpoint **ppBreakpoint);
+
+ END_INTERFACE
+ } ICorDebugHeapValueVtbl;
+
+ interface ICorDebugHeapValue
+ {
+ CONST_VTBL struct ICorDebugHeapValueVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugHeapValue_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugHeapValue_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugHeapValue_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugHeapValue_GetType(This,pType) \
+ ( (This)->lpVtbl -> GetType(This,pType) )
+
+#define ICorDebugHeapValue_GetSize(This,pSize) \
+ ( (This)->lpVtbl -> GetSize(This,pSize) )
+
+#define ICorDebugHeapValue_GetAddress(This,pAddress) \
+ ( (This)->lpVtbl -> GetAddress(This,pAddress) )
+
+#define ICorDebugHeapValue_CreateBreakpoint(This,ppBreakpoint) \
+ ( (This)->lpVtbl -> CreateBreakpoint(This,ppBreakpoint) )
+
+
+#define ICorDebugHeapValue_IsValid(This,pbValid) \
+ ( (This)->lpVtbl -> IsValid(This,pbValid) )
+
+#define ICorDebugHeapValue_CreateRelocBreakpoint(This,ppBreakpoint) \
+ ( (This)->lpVtbl -> CreateRelocBreakpoint(This,ppBreakpoint) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugHeapValue_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugHeapValue2_INTERFACE_DEFINED__
+#define __ICorDebugHeapValue2_INTERFACE_DEFINED__
+
+/* interface ICorDebugHeapValue2 */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugHeapValue2;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("E3AC4D6C-9CB7-43e6-96CC-B21540E5083C")
+ ICorDebugHeapValue2 : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE CreateHandle(
+ /* [in] */ CorDebugHandleType type,
+ /* [out] */ ICorDebugHandleValue **ppHandle) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugHeapValue2Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugHeapValue2 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugHeapValue2 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugHeapValue2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *CreateHandle )(
+ ICorDebugHeapValue2 * This,
+ /* [in] */ CorDebugHandleType type,
+ /* [out] */ ICorDebugHandleValue **ppHandle);
+
+ END_INTERFACE
+ } ICorDebugHeapValue2Vtbl;
+
+ interface ICorDebugHeapValue2
+ {
+ CONST_VTBL struct ICorDebugHeapValue2Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugHeapValue2_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugHeapValue2_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugHeapValue2_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugHeapValue2_CreateHandle(This,type,ppHandle) \
+ ( (This)->lpVtbl -> CreateHandle(This,type,ppHandle) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugHeapValue2_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugHeapValue3_INTERFACE_DEFINED__
+#define __ICorDebugHeapValue3_INTERFACE_DEFINED__
+
+/* interface ICorDebugHeapValue3 */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugHeapValue3;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("A69ACAD8-2374-46e9-9FF8-B1F14120D296")
+ ICorDebugHeapValue3 : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetThreadOwningMonitorLock(
+ /* [out] */ ICorDebugThread **ppThread,
+ /* [out] */ DWORD *pAcquisitionCount) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetMonitorEventWaitList(
+ /* [out] */ ICorDebugThreadEnum **ppThreadEnum) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugHeapValue3Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugHeapValue3 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugHeapValue3 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugHeapValue3 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetThreadOwningMonitorLock )(
+ ICorDebugHeapValue3 * This,
+ /* [out] */ ICorDebugThread **ppThread,
+ /* [out] */ DWORD *pAcquisitionCount);
+
+ HRESULT ( STDMETHODCALLTYPE *GetMonitorEventWaitList )(
+ ICorDebugHeapValue3 * This,
+ /* [out] */ ICorDebugThreadEnum **ppThreadEnum);
+
+ END_INTERFACE
+ } ICorDebugHeapValue3Vtbl;
+
+ interface ICorDebugHeapValue3
+ {
+ CONST_VTBL struct ICorDebugHeapValue3Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugHeapValue3_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugHeapValue3_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugHeapValue3_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugHeapValue3_GetThreadOwningMonitorLock(This,ppThread,pAcquisitionCount) \
+ ( (This)->lpVtbl -> GetThreadOwningMonitorLock(This,ppThread,pAcquisitionCount) )
+
+#define ICorDebugHeapValue3_GetMonitorEventWaitList(This,ppThreadEnum) \
+ ( (This)->lpVtbl -> GetMonitorEventWaitList(This,ppThreadEnum) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugHeapValue3_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugObjectValue_INTERFACE_DEFINED__
+#define __ICorDebugObjectValue_INTERFACE_DEFINED__
+
+/* interface ICorDebugObjectValue */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugObjectValue;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("18AD3D6E-B7D2-11d2-BD04-0000F80849BD")
+ ICorDebugObjectValue : public ICorDebugValue
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetClass(
+ /* [out] */ ICorDebugClass **ppClass) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetFieldValue(
+ /* [in] */ ICorDebugClass *pClass,
+ /* [in] */ mdFieldDef fieldDef,
+ /* [out] */ ICorDebugValue **ppValue) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetVirtualMethod(
+ /* [in] */ mdMemberRef memberRef,
+ /* [out] */ ICorDebugFunction **ppFunction) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetContext(
+ /* [out] */ ICorDebugContext **ppContext) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE IsValueClass(
+ /* [out] */ BOOL *pbIsValueClass) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetManagedCopy(
+ /* [out] */ IUnknown **ppObject) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetFromManagedCopy(
+ /* [in] */ IUnknown *pObject) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugObjectValueVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugObjectValue * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugObjectValue * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugObjectValue * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetType )(
+ ICorDebugObjectValue * This,
+ /* [out] */ CorElementType *pType);
+
+ HRESULT ( STDMETHODCALLTYPE *GetSize )(
+ ICorDebugObjectValue * This,
+ /* [out] */ ULONG32 *pSize);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAddress )(
+ ICorDebugObjectValue * This,
+ /* [out] */ CORDB_ADDRESS *pAddress);
+
+ HRESULT ( STDMETHODCALLTYPE *CreateBreakpoint )(
+ ICorDebugObjectValue * This,
+ /* [out] */ ICorDebugValueBreakpoint **ppBreakpoint);
+
+ HRESULT ( STDMETHODCALLTYPE *GetClass )(
+ ICorDebugObjectValue * This,
+ /* [out] */ ICorDebugClass **ppClass);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFieldValue )(
+ ICorDebugObjectValue * This,
+ /* [in] */ ICorDebugClass *pClass,
+ /* [in] */ mdFieldDef fieldDef,
+ /* [out] */ ICorDebugValue **ppValue);
+
+ HRESULT ( STDMETHODCALLTYPE *GetVirtualMethod )(
+ ICorDebugObjectValue * This,
+ /* [in] */ mdMemberRef memberRef,
+ /* [out] */ ICorDebugFunction **ppFunction);
+
+ HRESULT ( STDMETHODCALLTYPE *GetContext )(
+ ICorDebugObjectValue * This,
+ /* [out] */ ICorDebugContext **ppContext);
+
+ HRESULT ( STDMETHODCALLTYPE *IsValueClass )(
+ ICorDebugObjectValue * This,
+ /* [out] */ BOOL *pbIsValueClass);
+
+ HRESULT ( STDMETHODCALLTYPE *GetManagedCopy )(
+ ICorDebugObjectValue * This,
+ /* [out] */ IUnknown **ppObject);
+
+ HRESULT ( STDMETHODCALLTYPE *SetFromManagedCopy )(
+ ICorDebugObjectValue * This,
+ /* [in] */ IUnknown *pObject);
+
+ END_INTERFACE
+ } ICorDebugObjectValueVtbl;
+
+ interface ICorDebugObjectValue
+ {
+ CONST_VTBL struct ICorDebugObjectValueVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugObjectValue_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugObjectValue_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugObjectValue_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugObjectValue_GetType(This,pType) \
+ ( (This)->lpVtbl -> GetType(This,pType) )
+
+#define ICorDebugObjectValue_GetSize(This,pSize) \
+ ( (This)->lpVtbl -> GetSize(This,pSize) )
+
+#define ICorDebugObjectValue_GetAddress(This,pAddress) \
+ ( (This)->lpVtbl -> GetAddress(This,pAddress) )
+
+#define ICorDebugObjectValue_CreateBreakpoint(This,ppBreakpoint) \
+ ( (This)->lpVtbl -> CreateBreakpoint(This,ppBreakpoint) )
+
+
+#define ICorDebugObjectValue_GetClass(This,ppClass) \
+ ( (This)->lpVtbl -> GetClass(This,ppClass) )
+
+#define ICorDebugObjectValue_GetFieldValue(This,pClass,fieldDef,ppValue) \
+ ( (This)->lpVtbl -> GetFieldValue(This,pClass,fieldDef,ppValue) )
+
+#define ICorDebugObjectValue_GetVirtualMethod(This,memberRef,ppFunction) \
+ ( (This)->lpVtbl -> GetVirtualMethod(This,memberRef,ppFunction) )
+
+#define ICorDebugObjectValue_GetContext(This,ppContext) \
+ ( (This)->lpVtbl -> GetContext(This,ppContext) )
+
+#define ICorDebugObjectValue_IsValueClass(This,pbIsValueClass) \
+ ( (This)->lpVtbl -> IsValueClass(This,pbIsValueClass) )
+
+#define ICorDebugObjectValue_GetManagedCopy(This,ppObject) \
+ ( (This)->lpVtbl -> GetManagedCopy(This,ppObject) )
+
+#define ICorDebugObjectValue_SetFromManagedCopy(This,pObject) \
+ ( (This)->lpVtbl -> SetFromManagedCopy(This,pObject) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugObjectValue_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugObjectValue2_INTERFACE_DEFINED__
+#define __ICorDebugObjectValue2_INTERFACE_DEFINED__
+
+/* interface ICorDebugObjectValue2 */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugObjectValue2;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("49E4A320-4A9B-4eca-B105-229FB7D5009F")
+ ICorDebugObjectValue2 : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetVirtualMethodAndType(
+ /* [in] */ mdMemberRef memberRef,
+ /* [out] */ ICorDebugFunction **ppFunction,
+ /* [out] */ ICorDebugType **ppType) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugObjectValue2Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugObjectValue2 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugObjectValue2 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugObjectValue2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetVirtualMethodAndType )(
+ ICorDebugObjectValue2 * This,
+ /* [in] */ mdMemberRef memberRef,
+ /* [out] */ ICorDebugFunction **ppFunction,
+ /* [out] */ ICorDebugType **ppType);
+
+ END_INTERFACE
+ } ICorDebugObjectValue2Vtbl;
+
+ interface ICorDebugObjectValue2
+ {
+ CONST_VTBL struct ICorDebugObjectValue2Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugObjectValue2_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugObjectValue2_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugObjectValue2_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugObjectValue2_GetVirtualMethodAndType(This,memberRef,ppFunction,ppType) \
+ ( (This)->lpVtbl -> GetVirtualMethodAndType(This,memberRef,ppFunction,ppType) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugObjectValue2_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugBoxValue_INTERFACE_DEFINED__
+#define __ICorDebugBoxValue_INTERFACE_DEFINED__
+
+/* interface ICorDebugBoxValue */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugBoxValue;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("CC7BCAFC-8A68-11d2-983C-0000F808342D")
+ ICorDebugBoxValue : public ICorDebugHeapValue
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetObject(
+ /* [out] */ ICorDebugObjectValue **ppObject) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugBoxValueVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugBoxValue * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugBoxValue * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugBoxValue * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetType )(
+ ICorDebugBoxValue * This,
+ /* [out] */ CorElementType *pType);
+
+ HRESULT ( STDMETHODCALLTYPE *GetSize )(
+ ICorDebugBoxValue * This,
+ /* [out] */ ULONG32 *pSize);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAddress )(
+ ICorDebugBoxValue * This,
+ /* [out] */ CORDB_ADDRESS *pAddress);
+
+ HRESULT ( STDMETHODCALLTYPE *CreateBreakpoint )(
+ ICorDebugBoxValue * This,
+ /* [out] */ ICorDebugValueBreakpoint **ppBreakpoint);
+
+ HRESULT ( STDMETHODCALLTYPE *IsValid )(
+ ICorDebugBoxValue * This,
+ /* [out] */ BOOL *pbValid);
+
+ HRESULT ( STDMETHODCALLTYPE *CreateRelocBreakpoint )(
+ ICorDebugBoxValue * This,
+ /* [out] */ ICorDebugValueBreakpoint **ppBreakpoint);
+
+ HRESULT ( STDMETHODCALLTYPE *GetObject )(
+ ICorDebugBoxValue * This,
+ /* [out] */ ICorDebugObjectValue **ppObject);
+
+ END_INTERFACE
+ } ICorDebugBoxValueVtbl;
+
+ interface ICorDebugBoxValue
+ {
+ CONST_VTBL struct ICorDebugBoxValueVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugBoxValue_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugBoxValue_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugBoxValue_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugBoxValue_GetType(This,pType) \
+ ( (This)->lpVtbl -> GetType(This,pType) )
+
+#define ICorDebugBoxValue_GetSize(This,pSize) \
+ ( (This)->lpVtbl -> GetSize(This,pSize) )
+
+#define ICorDebugBoxValue_GetAddress(This,pAddress) \
+ ( (This)->lpVtbl -> GetAddress(This,pAddress) )
+
+#define ICorDebugBoxValue_CreateBreakpoint(This,ppBreakpoint) \
+ ( (This)->lpVtbl -> CreateBreakpoint(This,ppBreakpoint) )
+
+
+#define ICorDebugBoxValue_IsValid(This,pbValid) \
+ ( (This)->lpVtbl -> IsValid(This,pbValid) )
+
+#define ICorDebugBoxValue_CreateRelocBreakpoint(This,ppBreakpoint) \
+ ( (This)->lpVtbl -> CreateRelocBreakpoint(This,ppBreakpoint) )
+
+
+#define ICorDebugBoxValue_GetObject(This,ppObject) \
+ ( (This)->lpVtbl -> GetObject(This,ppObject) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugBoxValue_INTERFACE_DEFINED__ */
+
+
+/* interface __MIDL_itf_cordebug_0000_0095 */
+/* [local] */
+
+#pragma warning(push)
+#pragma warning(disable:28718)
+
+
+extern RPC_IF_HANDLE __MIDL_itf_cordebug_0000_0095_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_cordebug_0000_0095_v0_0_s_ifspec;
+
+#ifndef __ICorDebugStringValue_INTERFACE_DEFINED__
+#define __ICorDebugStringValue_INTERFACE_DEFINED__
+
+/* interface ICorDebugStringValue */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugStringValue;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("CC7BCAFD-8A68-11d2-983C-0000F808342D")
+ ICorDebugStringValue : public ICorDebugHeapValue
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetLength(
+ /* [out] */ ULONG32 *pcchString) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetString(
+ /* [in] */ ULONG32 cchString,
+ /* [out] */ ULONG32 *pcchString,
+ /* [length_is][size_is][out] */ WCHAR szString[ ]) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugStringValueVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugStringValue * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugStringValue * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugStringValue * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetType )(
+ ICorDebugStringValue * This,
+ /* [out] */ CorElementType *pType);
+
+ HRESULT ( STDMETHODCALLTYPE *GetSize )(
+ ICorDebugStringValue * This,
+ /* [out] */ ULONG32 *pSize);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAddress )(
+ ICorDebugStringValue * This,
+ /* [out] */ CORDB_ADDRESS *pAddress);
+
+ HRESULT ( STDMETHODCALLTYPE *CreateBreakpoint )(
+ ICorDebugStringValue * This,
+ /* [out] */ ICorDebugValueBreakpoint **ppBreakpoint);
+
+ HRESULT ( STDMETHODCALLTYPE *IsValid )(
+ ICorDebugStringValue * This,
+ /* [out] */ BOOL *pbValid);
+
+ HRESULT ( STDMETHODCALLTYPE *CreateRelocBreakpoint )(
+ ICorDebugStringValue * This,
+ /* [out] */ ICorDebugValueBreakpoint **ppBreakpoint);
+
+ HRESULT ( STDMETHODCALLTYPE *GetLength )(
+ ICorDebugStringValue * This,
+ /* [out] */ ULONG32 *pcchString);
+
+ HRESULT ( STDMETHODCALLTYPE *GetString )(
+ ICorDebugStringValue * This,
+ /* [in] */ ULONG32 cchString,
+ /* [out] */ ULONG32 *pcchString,
+ /* [length_is][size_is][out] */ WCHAR szString[ ]);
+
+ END_INTERFACE
+ } ICorDebugStringValueVtbl;
+
+ interface ICorDebugStringValue
+ {
+ CONST_VTBL struct ICorDebugStringValueVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugStringValue_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugStringValue_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugStringValue_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugStringValue_GetType(This,pType) \
+ ( (This)->lpVtbl -> GetType(This,pType) )
+
+#define ICorDebugStringValue_GetSize(This,pSize) \
+ ( (This)->lpVtbl -> GetSize(This,pSize) )
+
+#define ICorDebugStringValue_GetAddress(This,pAddress) \
+ ( (This)->lpVtbl -> GetAddress(This,pAddress) )
+
+#define ICorDebugStringValue_CreateBreakpoint(This,ppBreakpoint) \
+ ( (This)->lpVtbl -> CreateBreakpoint(This,ppBreakpoint) )
+
+
+#define ICorDebugStringValue_IsValid(This,pbValid) \
+ ( (This)->lpVtbl -> IsValid(This,pbValid) )
+
+#define ICorDebugStringValue_CreateRelocBreakpoint(This,ppBreakpoint) \
+ ( (This)->lpVtbl -> CreateRelocBreakpoint(This,ppBreakpoint) )
+
+
+#define ICorDebugStringValue_GetLength(This,pcchString) \
+ ( (This)->lpVtbl -> GetLength(This,pcchString) )
+
+#define ICorDebugStringValue_GetString(This,cchString,pcchString,szString) \
+ ( (This)->lpVtbl -> GetString(This,cchString,pcchString,szString) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugStringValue_INTERFACE_DEFINED__ */
+
+
+/* interface __MIDL_itf_cordebug_0000_0096 */
+/* [local] */
+
+#pragma warning(pop)
+
+
+extern RPC_IF_HANDLE __MIDL_itf_cordebug_0000_0096_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_cordebug_0000_0096_v0_0_s_ifspec;
+
+#ifndef __ICorDebugArrayValue_INTERFACE_DEFINED__
+#define __ICorDebugArrayValue_INTERFACE_DEFINED__
+
+/* interface ICorDebugArrayValue */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugArrayValue;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("0405B0DF-A660-11d2-BD02-0000F80849BD")
+ ICorDebugArrayValue : public ICorDebugHeapValue
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetElementType(
+ /* [out] */ CorElementType *pType) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetRank(
+ /* [out] */ ULONG32 *pnRank) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetCount(
+ /* [out] */ ULONG32 *pnCount) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetDimensions(
+ /* [in] */ ULONG32 cdim,
+ /* [length_is][size_is][out] */ ULONG32 dims[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE HasBaseIndicies(
+ /* [out] */ BOOL *pbHasBaseIndicies) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetBaseIndicies(
+ /* [in] */ ULONG32 cdim,
+ /* [length_is][size_is][out] */ ULONG32 indicies[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetElement(
+ /* [in] */ ULONG32 cdim,
+ /* [length_is][size_is][in] */ ULONG32 indices[ ],
+ /* [out] */ ICorDebugValue **ppValue) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetElementAtPosition(
+ /* [in] */ ULONG32 nPosition,
+ /* [out] */ ICorDebugValue **ppValue) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugArrayValueVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugArrayValue * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugArrayValue * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugArrayValue * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetType )(
+ ICorDebugArrayValue * This,
+ /* [out] */ CorElementType *pType);
+
+ HRESULT ( STDMETHODCALLTYPE *GetSize )(
+ ICorDebugArrayValue * This,
+ /* [out] */ ULONG32 *pSize);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAddress )(
+ ICorDebugArrayValue * This,
+ /* [out] */ CORDB_ADDRESS *pAddress);
+
+ HRESULT ( STDMETHODCALLTYPE *CreateBreakpoint )(
+ ICorDebugArrayValue * This,
+ /* [out] */ ICorDebugValueBreakpoint **ppBreakpoint);
+
+ HRESULT ( STDMETHODCALLTYPE *IsValid )(
+ ICorDebugArrayValue * This,
+ /* [out] */ BOOL *pbValid);
+
+ HRESULT ( STDMETHODCALLTYPE *CreateRelocBreakpoint )(
+ ICorDebugArrayValue * This,
+ /* [out] */ ICorDebugValueBreakpoint **ppBreakpoint);
+
+ HRESULT ( STDMETHODCALLTYPE *GetElementType )(
+ ICorDebugArrayValue * This,
+ /* [out] */ CorElementType *pType);
+
+ HRESULT ( STDMETHODCALLTYPE *GetRank )(
+ ICorDebugArrayValue * This,
+ /* [out] */ ULONG32 *pnRank);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCount )(
+ ICorDebugArrayValue * This,
+ /* [out] */ ULONG32 *pnCount);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDimensions )(
+ ICorDebugArrayValue * This,
+ /* [in] */ ULONG32 cdim,
+ /* [length_is][size_is][out] */ ULONG32 dims[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *HasBaseIndicies )(
+ ICorDebugArrayValue * This,
+ /* [out] */ BOOL *pbHasBaseIndicies);
+
+ HRESULT ( STDMETHODCALLTYPE *GetBaseIndicies )(
+ ICorDebugArrayValue * This,
+ /* [in] */ ULONG32 cdim,
+ /* [length_is][size_is][out] */ ULONG32 indicies[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetElement )(
+ ICorDebugArrayValue * This,
+ /* [in] */ ULONG32 cdim,
+ /* [length_is][size_is][in] */ ULONG32 indices[ ],
+ /* [out] */ ICorDebugValue **ppValue);
+
+ HRESULT ( STDMETHODCALLTYPE *GetElementAtPosition )(
+ ICorDebugArrayValue * This,
+ /* [in] */ ULONG32 nPosition,
+ /* [out] */ ICorDebugValue **ppValue);
+
+ END_INTERFACE
+ } ICorDebugArrayValueVtbl;
+
+ interface ICorDebugArrayValue
+ {
+ CONST_VTBL struct ICorDebugArrayValueVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugArrayValue_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugArrayValue_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugArrayValue_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugArrayValue_GetType(This,pType) \
+ ( (This)->lpVtbl -> GetType(This,pType) )
+
+#define ICorDebugArrayValue_GetSize(This,pSize) \
+ ( (This)->lpVtbl -> GetSize(This,pSize) )
+
+#define ICorDebugArrayValue_GetAddress(This,pAddress) \
+ ( (This)->lpVtbl -> GetAddress(This,pAddress) )
+
+#define ICorDebugArrayValue_CreateBreakpoint(This,ppBreakpoint) \
+ ( (This)->lpVtbl -> CreateBreakpoint(This,ppBreakpoint) )
+
+
+#define ICorDebugArrayValue_IsValid(This,pbValid) \
+ ( (This)->lpVtbl -> IsValid(This,pbValid) )
+
+#define ICorDebugArrayValue_CreateRelocBreakpoint(This,ppBreakpoint) \
+ ( (This)->lpVtbl -> CreateRelocBreakpoint(This,ppBreakpoint) )
+
+
+#define ICorDebugArrayValue_GetElementType(This,pType) \
+ ( (This)->lpVtbl -> GetElementType(This,pType) )
+
+#define ICorDebugArrayValue_GetRank(This,pnRank) \
+ ( (This)->lpVtbl -> GetRank(This,pnRank) )
+
+#define ICorDebugArrayValue_GetCount(This,pnCount) \
+ ( (This)->lpVtbl -> GetCount(This,pnCount) )
+
+#define ICorDebugArrayValue_GetDimensions(This,cdim,dims) \
+ ( (This)->lpVtbl -> GetDimensions(This,cdim,dims) )
+
+#define ICorDebugArrayValue_HasBaseIndicies(This,pbHasBaseIndicies) \
+ ( (This)->lpVtbl -> HasBaseIndicies(This,pbHasBaseIndicies) )
+
+#define ICorDebugArrayValue_GetBaseIndicies(This,cdim,indicies) \
+ ( (This)->lpVtbl -> GetBaseIndicies(This,cdim,indicies) )
+
+#define ICorDebugArrayValue_GetElement(This,cdim,indices,ppValue) \
+ ( (This)->lpVtbl -> GetElement(This,cdim,indices,ppValue) )
+
+#define ICorDebugArrayValue_GetElementAtPosition(This,nPosition,ppValue) \
+ ( (This)->lpVtbl -> GetElementAtPosition(This,nPosition,ppValue) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugArrayValue_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugHandleValue_INTERFACE_DEFINED__
+#define __ICorDebugHandleValue_INTERFACE_DEFINED__
+
+/* interface ICorDebugHandleValue */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugHandleValue;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("029596E8-276B-46a1-9821-732E96BBB00B")
+ ICorDebugHandleValue : public ICorDebugReferenceValue
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetHandleType(
+ /* [out] */ CorDebugHandleType *pType) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Dispose( void) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugHandleValueVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugHandleValue * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugHandleValue * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugHandleValue * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetType )(
+ ICorDebugHandleValue * This,
+ /* [out] */ CorElementType *pType);
+
+ HRESULT ( STDMETHODCALLTYPE *GetSize )(
+ ICorDebugHandleValue * This,
+ /* [out] */ ULONG32 *pSize);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAddress )(
+ ICorDebugHandleValue * This,
+ /* [out] */ CORDB_ADDRESS *pAddress);
+
+ HRESULT ( STDMETHODCALLTYPE *CreateBreakpoint )(
+ ICorDebugHandleValue * This,
+ /* [out] */ ICorDebugValueBreakpoint **ppBreakpoint);
+
+ HRESULT ( STDMETHODCALLTYPE *IsNull )(
+ ICorDebugHandleValue * This,
+ /* [out] */ BOOL *pbNull);
+
+ HRESULT ( STDMETHODCALLTYPE *GetValue )(
+ ICorDebugHandleValue * This,
+ /* [out] */ CORDB_ADDRESS *pValue);
+
+ HRESULT ( STDMETHODCALLTYPE *SetValue )(
+ ICorDebugHandleValue * This,
+ /* [in] */ CORDB_ADDRESS value);
+
+ HRESULT ( STDMETHODCALLTYPE *Dereference )(
+ ICorDebugHandleValue * This,
+ /* [out] */ ICorDebugValue **ppValue);
+
+ HRESULT ( STDMETHODCALLTYPE *DereferenceStrong )(
+ ICorDebugHandleValue * This,
+ /* [out] */ ICorDebugValue **ppValue);
+
+ HRESULT ( STDMETHODCALLTYPE *GetHandleType )(
+ ICorDebugHandleValue * This,
+ /* [out] */ CorDebugHandleType *pType);
+
+ HRESULT ( STDMETHODCALLTYPE *Dispose )(
+ ICorDebugHandleValue * This);
+
+ END_INTERFACE
+ } ICorDebugHandleValueVtbl;
+
+ interface ICorDebugHandleValue
+ {
+ CONST_VTBL struct ICorDebugHandleValueVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugHandleValue_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugHandleValue_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugHandleValue_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugHandleValue_GetType(This,pType) \
+ ( (This)->lpVtbl -> GetType(This,pType) )
+
+#define ICorDebugHandleValue_GetSize(This,pSize) \
+ ( (This)->lpVtbl -> GetSize(This,pSize) )
+
+#define ICorDebugHandleValue_GetAddress(This,pAddress) \
+ ( (This)->lpVtbl -> GetAddress(This,pAddress) )
+
+#define ICorDebugHandleValue_CreateBreakpoint(This,ppBreakpoint) \
+ ( (This)->lpVtbl -> CreateBreakpoint(This,ppBreakpoint) )
+
+
+#define ICorDebugHandleValue_IsNull(This,pbNull) \
+ ( (This)->lpVtbl -> IsNull(This,pbNull) )
+
+#define ICorDebugHandleValue_GetValue(This,pValue) \
+ ( (This)->lpVtbl -> GetValue(This,pValue) )
+
+#define ICorDebugHandleValue_SetValue(This,value) \
+ ( (This)->lpVtbl -> SetValue(This,value) )
+
+#define ICorDebugHandleValue_Dereference(This,ppValue) \
+ ( (This)->lpVtbl -> Dereference(This,ppValue) )
+
+#define ICorDebugHandleValue_DereferenceStrong(This,ppValue) \
+ ( (This)->lpVtbl -> DereferenceStrong(This,ppValue) )
+
+
+#define ICorDebugHandleValue_GetHandleType(This,pType) \
+ ( (This)->lpVtbl -> GetHandleType(This,pType) )
+
+#define ICorDebugHandleValue_Dispose(This) \
+ ( (This)->lpVtbl -> Dispose(This) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugHandleValue_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugContext_INTERFACE_DEFINED__
+#define __ICorDebugContext_INTERFACE_DEFINED__
+
+/* interface ICorDebugContext */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugContext;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("CC7BCB00-8A68-11d2-983C-0000F808342D")
+ ICorDebugContext : public ICorDebugObjectValue
+ {
+ public:
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugContextVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugContext * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugContext * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugContext * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetType )(
+ ICorDebugContext * This,
+ /* [out] */ CorElementType *pType);
+
+ HRESULT ( STDMETHODCALLTYPE *GetSize )(
+ ICorDebugContext * This,
+ /* [out] */ ULONG32 *pSize);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAddress )(
+ ICorDebugContext * This,
+ /* [out] */ CORDB_ADDRESS *pAddress);
+
+ HRESULT ( STDMETHODCALLTYPE *CreateBreakpoint )(
+ ICorDebugContext * This,
+ /* [out] */ ICorDebugValueBreakpoint **ppBreakpoint);
+
+ HRESULT ( STDMETHODCALLTYPE *GetClass )(
+ ICorDebugContext * This,
+ /* [out] */ ICorDebugClass **ppClass);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFieldValue )(
+ ICorDebugContext * This,
+ /* [in] */ ICorDebugClass *pClass,
+ /* [in] */ mdFieldDef fieldDef,
+ /* [out] */ ICorDebugValue **ppValue);
+
+ HRESULT ( STDMETHODCALLTYPE *GetVirtualMethod )(
+ ICorDebugContext * This,
+ /* [in] */ mdMemberRef memberRef,
+ /* [out] */ ICorDebugFunction **ppFunction);
+
+ HRESULT ( STDMETHODCALLTYPE *GetContext )(
+ ICorDebugContext * This,
+ /* [out] */ ICorDebugContext **ppContext);
+
+ HRESULT ( STDMETHODCALLTYPE *IsValueClass )(
+ ICorDebugContext * This,
+ /* [out] */ BOOL *pbIsValueClass);
+
+ HRESULT ( STDMETHODCALLTYPE *GetManagedCopy )(
+ ICorDebugContext * This,
+ /* [out] */ IUnknown **ppObject);
+
+ HRESULT ( STDMETHODCALLTYPE *SetFromManagedCopy )(
+ ICorDebugContext * This,
+ /* [in] */ IUnknown *pObject);
+
+ END_INTERFACE
+ } ICorDebugContextVtbl;
+
+ interface ICorDebugContext
+ {
+ CONST_VTBL struct ICorDebugContextVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugContext_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugContext_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugContext_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugContext_GetType(This,pType) \
+ ( (This)->lpVtbl -> GetType(This,pType) )
+
+#define ICorDebugContext_GetSize(This,pSize) \
+ ( (This)->lpVtbl -> GetSize(This,pSize) )
+
+#define ICorDebugContext_GetAddress(This,pAddress) \
+ ( (This)->lpVtbl -> GetAddress(This,pAddress) )
+
+#define ICorDebugContext_CreateBreakpoint(This,ppBreakpoint) \
+ ( (This)->lpVtbl -> CreateBreakpoint(This,ppBreakpoint) )
+
+
+#define ICorDebugContext_GetClass(This,ppClass) \
+ ( (This)->lpVtbl -> GetClass(This,ppClass) )
+
+#define ICorDebugContext_GetFieldValue(This,pClass,fieldDef,ppValue) \
+ ( (This)->lpVtbl -> GetFieldValue(This,pClass,fieldDef,ppValue) )
+
+#define ICorDebugContext_GetVirtualMethod(This,memberRef,ppFunction) \
+ ( (This)->lpVtbl -> GetVirtualMethod(This,memberRef,ppFunction) )
+
+#define ICorDebugContext_GetContext(This,ppContext) \
+ ( (This)->lpVtbl -> GetContext(This,ppContext) )
+
+#define ICorDebugContext_IsValueClass(This,pbIsValueClass) \
+ ( (This)->lpVtbl -> IsValueClass(This,pbIsValueClass) )
+
+#define ICorDebugContext_GetManagedCopy(This,ppObject) \
+ ( (This)->lpVtbl -> GetManagedCopy(This,ppObject) )
+
+#define ICorDebugContext_SetFromManagedCopy(This,pObject) \
+ ( (This)->lpVtbl -> SetFromManagedCopy(This,pObject) )
+
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugContext_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugComObjectValue_INTERFACE_DEFINED__
+#define __ICorDebugComObjectValue_INTERFACE_DEFINED__
+
+/* interface ICorDebugComObjectValue */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugComObjectValue;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("5F69C5E5-3E12-42DF-B371-F9D761D6EE24")
+ ICorDebugComObjectValue : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetCachedInterfaceTypes(
+ /* [in] */ BOOL bIInspectableOnly,
+ /* [out] */ ICorDebugTypeEnum **ppInterfacesEnum) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetCachedInterfacePointers(
+ /* [in] */ BOOL bIInspectableOnly,
+ /* [in] */ ULONG32 celt,
+ /* [out] */ ULONG32 *pcEltFetched,
+ /* [length_is][size_is][out] */ CORDB_ADDRESS *ptrs) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugComObjectValueVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugComObjectValue * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugComObjectValue * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugComObjectValue * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCachedInterfaceTypes )(
+ ICorDebugComObjectValue * This,
+ /* [in] */ BOOL bIInspectableOnly,
+ /* [out] */ ICorDebugTypeEnum **ppInterfacesEnum);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCachedInterfacePointers )(
+ ICorDebugComObjectValue * This,
+ /* [in] */ BOOL bIInspectableOnly,
+ /* [in] */ ULONG32 celt,
+ /* [out] */ ULONG32 *pcEltFetched,
+ /* [length_is][size_is][out] */ CORDB_ADDRESS *ptrs);
+
+ END_INTERFACE
+ } ICorDebugComObjectValueVtbl;
+
+ interface ICorDebugComObjectValue
+ {
+ CONST_VTBL struct ICorDebugComObjectValueVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugComObjectValue_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugComObjectValue_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugComObjectValue_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugComObjectValue_GetCachedInterfaceTypes(This,bIInspectableOnly,ppInterfacesEnum) \
+ ( (This)->lpVtbl -> GetCachedInterfaceTypes(This,bIInspectableOnly,ppInterfacesEnum) )
+
+#define ICorDebugComObjectValue_GetCachedInterfacePointers(This,bIInspectableOnly,celt,pcEltFetched,ptrs) \
+ ( (This)->lpVtbl -> GetCachedInterfacePointers(This,bIInspectableOnly,celt,pcEltFetched,ptrs) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugComObjectValue_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugObjectEnum_INTERFACE_DEFINED__
+#define __ICorDebugObjectEnum_INTERFACE_DEFINED__
+
+/* interface ICorDebugObjectEnum */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugObjectEnum;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("CC7BCB02-8A68-11d2-983C-0000F808342D")
+ ICorDebugObjectEnum : public ICorDebugEnum
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE Next(
+ /* [in] */ ULONG celt,
+ /* [length_is][size_is][out] */ CORDB_ADDRESS objects[ ],
+ /* [out] */ ULONG *pceltFetched) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugObjectEnumVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugObjectEnum * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugObjectEnum * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugObjectEnum * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Skip )(
+ ICorDebugObjectEnum * This,
+ /* [in] */ ULONG celt);
+
+ HRESULT ( STDMETHODCALLTYPE *Reset )(
+ ICorDebugObjectEnum * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Clone )(
+ ICorDebugObjectEnum * This,
+ /* [out] */ ICorDebugEnum **ppEnum);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCount )(
+ ICorDebugObjectEnum * This,
+ /* [out] */ ULONG *pcelt);
+
+ HRESULT ( STDMETHODCALLTYPE *Next )(
+ ICorDebugObjectEnum * This,
+ /* [in] */ ULONG celt,
+ /* [length_is][size_is][out] */ CORDB_ADDRESS objects[ ],
+ /* [out] */ ULONG *pceltFetched);
+
+ END_INTERFACE
+ } ICorDebugObjectEnumVtbl;
+
+ interface ICorDebugObjectEnum
+ {
+ CONST_VTBL struct ICorDebugObjectEnumVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugObjectEnum_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugObjectEnum_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugObjectEnum_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugObjectEnum_Skip(This,celt) \
+ ( (This)->lpVtbl -> Skip(This,celt) )
+
+#define ICorDebugObjectEnum_Reset(This) \
+ ( (This)->lpVtbl -> Reset(This) )
+
+#define ICorDebugObjectEnum_Clone(This,ppEnum) \
+ ( (This)->lpVtbl -> Clone(This,ppEnum) )
+
+#define ICorDebugObjectEnum_GetCount(This,pcelt) \
+ ( (This)->lpVtbl -> GetCount(This,pcelt) )
+
+
+#define ICorDebugObjectEnum_Next(This,celt,objects,pceltFetched) \
+ ( (This)->lpVtbl -> Next(This,celt,objects,pceltFetched) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugObjectEnum_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugBreakpointEnum_INTERFACE_DEFINED__
+#define __ICorDebugBreakpointEnum_INTERFACE_DEFINED__
+
+/* interface ICorDebugBreakpointEnum */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugBreakpointEnum;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("CC7BCB03-8A68-11d2-983C-0000F808342D")
+ ICorDebugBreakpointEnum : public ICorDebugEnum
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE Next(
+ /* [in] */ ULONG celt,
+ /* [length_is][size_is][out] */ ICorDebugBreakpoint *breakpoints[ ],
+ /* [out] */ ULONG *pceltFetched) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugBreakpointEnumVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugBreakpointEnum * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugBreakpointEnum * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugBreakpointEnum * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Skip )(
+ ICorDebugBreakpointEnum * This,
+ /* [in] */ ULONG celt);
+
+ HRESULT ( STDMETHODCALLTYPE *Reset )(
+ ICorDebugBreakpointEnum * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Clone )(
+ ICorDebugBreakpointEnum * This,
+ /* [out] */ ICorDebugEnum **ppEnum);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCount )(
+ ICorDebugBreakpointEnum * This,
+ /* [out] */ ULONG *pcelt);
+
+ HRESULT ( STDMETHODCALLTYPE *Next )(
+ ICorDebugBreakpointEnum * This,
+ /* [in] */ ULONG celt,
+ /* [length_is][size_is][out] */ ICorDebugBreakpoint *breakpoints[ ],
+ /* [out] */ ULONG *pceltFetched);
+
+ END_INTERFACE
+ } ICorDebugBreakpointEnumVtbl;
+
+ interface ICorDebugBreakpointEnum
+ {
+ CONST_VTBL struct ICorDebugBreakpointEnumVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugBreakpointEnum_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugBreakpointEnum_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugBreakpointEnum_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugBreakpointEnum_Skip(This,celt) \
+ ( (This)->lpVtbl -> Skip(This,celt) )
+
+#define ICorDebugBreakpointEnum_Reset(This) \
+ ( (This)->lpVtbl -> Reset(This) )
+
+#define ICorDebugBreakpointEnum_Clone(This,ppEnum) \
+ ( (This)->lpVtbl -> Clone(This,ppEnum) )
+
+#define ICorDebugBreakpointEnum_GetCount(This,pcelt) \
+ ( (This)->lpVtbl -> GetCount(This,pcelt) )
+
+
+#define ICorDebugBreakpointEnum_Next(This,celt,breakpoints,pceltFetched) \
+ ( (This)->lpVtbl -> Next(This,celt,breakpoints,pceltFetched) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugBreakpointEnum_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugStepperEnum_INTERFACE_DEFINED__
+#define __ICorDebugStepperEnum_INTERFACE_DEFINED__
+
+/* interface ICorDebugStepperEnum */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugStepperEnum;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("CC7BCB04-8A68-11d2-983C-0000F808342D")
+ ICorDebugStepperEnum : public ICorDebugEnum
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE Next(
+ /* [in] */ ULONG celt,
+ /* [length_is][size_is][out] */ ICorDebugStepper *steppers[ ],
+ /* [out] */ ULONG *pceltFetched) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugStepperEnumVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugStepperEnum * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugStepperEnum * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugStepperEnum * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Skip )(
+ ICorDebugStepperEnum * This,
+ /* [in] */ ULONG celt);
+
+ HRESULT ( STDMETHODCALLTYPE *Reset )(
+ ICorDebugStepperEnum * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Clone )(
+ ICorDebugStepperEnum * This,
+ /* [out] */ ICorDebugEnum **ppEnum);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCount )(
+ ICorDebugStepperEnum * This,
+ /* [out] */ ULONG *pcelt);
+
+ HRESULT ( STDMETHODCALLTYPE *Next )(
+ ICorDebugStepperEnum * This,
+ /* [in] */ ULONG celt,
+ /* [length_is][size_is][out] */ ICorDebugStepper *steppers[ ],
+ /* [out] */ ULONG *pceltFetched);
+
+ END_INTERFACE
+ } ICorDebugStepperEnumVtbl;
+
+ interface ICorDebugStepperEnum
+ {
+ CONST_VTBL struct ICorDebugStepperEnumVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugStepperEnum_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugStepperEnum_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugStepperEnum_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugStepperEnum_Skip(This,celt) \
+ ( (This)->lpVtbl -> Skip(This,celt) )
+
+#define ICorDebugStepperEnum_Reset(This) \
+ ( (This)->lpVtbl -> Reset(This) )
+
+#define ICorDebugStepperEnum_Clone(This,ppEnum) \
+ ( (This)->lpVtbl -> Clone(This,ppEnum) )
+
+#define ICorDebugStepperEnum_GetCount(This,pcelt) \
+ ( (This)->lpVtbl -> GetCount(This,pcelt) )
+
+
+#define ICorDebugStepperEnum_Next(This,celt,steppers,pceltFetched) \
+ ( (This)->lpVtbl -> Next(This,celt,steppers,pceltFetched) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugStepperEnum_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugProcessEnum_INTERFACE_DEFINED__
+#define __ICorDebugProcessEnum_INTERFACE_DEFINED__
+
+/* interface ICorDebugProcessEnum */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugProcessEnum;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("CC7BCB05-8A68-11d2-983C-0000F808342D")
+ ICorDebugProcessEnum : public ICorDebugEnum
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE Next(
+ /* [in] */ ULONG celt,
+ /* [length_is][size_is][out] */ ICorDebugProcess *processes[ ],
+ /* [out] */ ULONG *pceltFetched) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugProcessEnumVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugProcessEnum * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugProcessEnum * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugProcessEnum * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Skip )(
+ ICorDebugProcessEnum * This,
+ /* [in] */ ULONG celt);
+
+ HRESULT ( STDMETHODCALLTYPE *Reset )(
+ ICorDebugProcessEnum * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Clone )(
+ ICorDebugProcessEnum * This,
+ /* [out] */ ICorDebugEnum **ppEnum);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCount )(
+ ICorDebugProcessEnum * This,
+ /* [out] */ ULONG *pcelt);
+
+ HRESULT ( STDMETHODCALLTYPE *Next )(
+ ICorDebugProcessEnum * This,
+ /* [in] */ ULONG celt,
+ /* [length_is][size_is][out] */ ICorDebugProcess *processes[ ],
+ /* [out] */ ULONG *pceltFetched);
+
+ END_INTERFACE
+ } ICorDebugProcessEnumVtbl;
+
+ interface ICorDebugProcessEnum
+ {
+ CONST_VTBL struct ICorDebugProcessEnumVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugProcessEnum_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugProcessEnum_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugProcessEnum_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugProcessEnum_Skip(This,celt) \
+ ( (This)->lpVtbl -> Skip(This,celt) )
+
+#define ICorDebugProcessEnum_Reset(This) \
+ ( (This)->lpVtbl -> Reset(This) )
+
+#define ICorDebugProcessEnum_Clone(This,ppEnum) \
+ ( (This)->lpVtbl -> Clone(This,ppEnum) )
+
+#define ICorDebugProcessEnum_GetCount(This,pcelt) \
+ ( (This)->lpVtbl -> GetCount(This,pcelt) )
+
+
+#define ICorDebugProcessEnum_Next(This,celt,processes,pceltFetched) \
+ ( (This)->lpVtbl -> Next(This,celt,processes,pceltFetched) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugProcessEnum_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugThreadEnum_INTERFACE_DEFINED__
+#define __ICorDebugThreadEnum_INTERFACE_DEFINED__
+
+/* interface ICorDebugThreadEnum */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugThreadEnum;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("CC7BCB06-8A68-11d2-983C-0000F808342D")
+ ICorDebugThreadEnum : public ICorDebugEnum
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE Next(
+ /* [in] */ ULONG celt,
+ /* [length_is][size_is][out] */ ICorDebugThread *threads[ ],
+ /* [out] */ ULONG *pceltFetched) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugThreadEnumVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugThreadEnum * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugThreadEnum * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugThreadEnum * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Skip )(
+ ICorDebugThreadEnum * This,
+ /* [in] */ ULONG celt);
+
+ HRESULT ( STDMETHODCALLTYPE *Reset )(
+ ICorDebugThreadEnum * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Clone )(
+ ICorDebugThreadEnum * This,
+ /* [out] */ ICorDebugEnum **ppEnum);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCount )(
+ ICorDebugThreadEnum * This,
+ /* [out] */ ULONG *pcelt);
+
+ HRESULT ( STDMETHODCALLTYPE *Next )(
+ ICorDebugThreadEnum * This,
+ /* [in] */ ULONG celt,
+ /* [length_is][size_is][out] */ ICorDebugThread *threads[ ],
+ /* [out] */ ULONG *pceltFetched);
+
+ END_INTERFACE
+ } ICorDebugThreadEnumVtbl;
+
+ interface ICorDebugThreadEnum
+ {
+ CONST_VTBL struct ICorDebugThreadEnumVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugThreadEnum_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugThreadEnum_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugThreadEnum_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugThreadEnum_Skip(This,celt) \
+ ( (This)->lpVtbl -> Skip(This,celt) )
+
+#define ICorDebugThreadEnum_Reset(This) \
+ ( (This)->lpVtbl -> Reset(This) )
+
+#define ICorDebugThreadEnum_Clone(This,ppEnum) \
+ ( (This)->lpVtbl -> Clone(This,ppEnum) )
+
+#define ICorDebugThreadEnum_GetCount(This,pcelt) \
+ ( (This)->lpVtbl -> GetCount(This,pcelt) )
+
+
+#define ICorDebugThreadEnum_Next(This,celt,threads,pceltFetched) \
+ ( (This)->lpVtbl -> Next(This,celt,threads,pceltFetched) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugThreadEnum_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugFrameEnum_INTERFACE_DEFINED__
+#define __ICorDebugFrameEnum_INTERFACE_DEFINED__
+
+/* interface ICorDebugFrameEnum */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugFrameEnum;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("CC7BCB07-8A68-11d2-983C-0000F808342D")
+ ICorDebugFrameEnum : public ICorDebugEnum
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE Next(
+ /* [in] */ ULONG celt,
+ /* [length_is][size_is][out] */ ICorDebugFrame *frames[ ],
+ /* [out] */ ULONG *pceltFetched) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugFrameEnumVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugFrameEnum * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugFrameEnum * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugFrameEnum * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Skip )(
+ ICorDebugFrameEnum * This,
+ /* [in] */ ULONG celt);
+
+ HRESULT ( STDMETHODCALLTYPE *Reset )(
+ ICorDebugFrameEnum * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Clone )(
+ ICorDebugFrameEnum * This,
+ /* [out] */ ICorDebugEnum **ppEnum);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCount )(
+ ICorDebugFrameEnum * This,
+ /* [out] */ ULONG *pcelt);
+
+ HRESULT ( STDMETHODCALLTYPE *Next )(
+ ICorDebugFrameEnum * This,
+ /* [in] */ ULONG celt,
+ /* [length_is][size_is][out] */ ICorDebugFrame *frames[ ],
+ /* [out] */ ULONG *pceltFetched);
+
+ END_INTERFACE
+ } ICorDebugFrameEnumVtbl;
+
+ interface ICorDebugFrameEnum
+ {
+ CONST_VTBL struct ICorDebugFrameEnumVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugFrameEnum_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugFrameEnum_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugFrameEnum_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugFrameEnum_Skip(This,celt) \
+ ( (This)->lpVtbl -> Skip(This,celt) )
+
+#define ICorDebugFrameEnum_Reset(This) \
+ ( (This)->lpVtbl -> Reset(This) )
+
+#define ICorDebugFrameEnum_Clone(This,ppEnum) \
+ ( (This)->lpVtbl -> Clone(This,ppEnum) )
+
+#define ICorDebugFrameEnum_GetCount(This,pcelt) \
+ ( (This)->lpVtbl -> GetCount(This,pcelt) )
+
+
+#define ICorDebugFrameEnum_Next(This,celt,frames,pceltFetched) \
+ ( (This)->lpVtbl -> Next(This,celt,frames,pceltFetched) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugFrameEnum_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugChainEnum_INTERFACE_DEFINED__
+#define __ICorDebugChainEnum_INTERFACE_DEFINED__
+
+/* interface ICorDebugChainEnum */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugChainEnum;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("CC7BCB08-8A68-11d2-983C-0000F808342D")
+ ICorDebugChainEnum : public ICorDebugEnum
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE Next(
+ /* [in] */ ULONG celt,
+ /* [length_is][size_is][out] */ ICorDebugChain *chains[ ],
+ /* [out] */ ULONG *pceltFetched) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugChainEnumVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugChainEnum * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugChainEnum * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugChainEnum * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Skip )(
+ ICorDebugChainEnum * This,
+ /* [in] */ ULONG celt);
+
+ HRESULT ( STDMETHODCALLTYPE *Reset )(
+ ICorDebugChainEnum * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Clone )(
+ ICorDebugChainEnum * This,
+ /* [out] */ ICorDebugEnum **ppEnum);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCount )(
+ ICorDebugChainEnum * This,
+ /* [out] */ ULONG *pcelt);
+
+ HRESULT ( STDMETHODCALLTYPE *Next )(
+ ICorDebugChainEnum * This,
+ /* [in] */ ULONG celt,
+ /* [length_is][size_is][out] */ ICorDebugChain *chains[ ],
+ /* [out] */ ULONG *pceltFetched);
+
+ END_INTERFACE
+ } ICorDebugChainEnumVtbl;
+
+ interface ICorDebugChainEnum
+ {
+ CONST_VTBL struct ICorDebugChainEnumVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugChainEnum_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugChainEnum_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugChainEnum_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugChainEnum_Skip(This,celt) \
+ ( (This)->lpVtbl -> Skip(This,celt) )
+
+#define ICorDebugChainEnum_Reset(This) \
+ ( (This)->lpVtbl -> Reset(This) )
+
+#define ICorDebugChainEnum_Clone(This,ppEnum) \
+ ( (This)->lpVtbl -> Clone(This,ppEnum) )
+
+#define ICorDebugChainEnum_GetCount(This,pcelt) \
+ ( (This)->lpVtbl -> GetCount(This,pcelt) )
+
+
+#define ICorDebugChainEnum_Next(This,celt,chains,pceltFetched) \
+ ( (This)->lpVtbl -> Next(This,celt,chains,pceltFetched) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugChainEnum_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugModuleEnum_INTERFACE_DEFINED__
+#define __ICorDebugModuleEnum_INTERFACE_DEFINED__
+
+/* interface ICorDebugModuleEnum */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugModuleEnum;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("CC7BCB09-8A68-11d2-983C-0000F808342D")
+ ICorDebugModuleEnum : public ICorDebugEnum
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE Next(
+ /* [in] */ ULONG celt,
+ /* [length_is][size_is][out] */ ICorDebugModule *modules[ ],
+ /* [out] */ ULONG *pceltFetched) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugModuleEnumVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugModuleEnum * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugModuleEnum * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugModuleEnum * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Skip )(
+ ICorDebugModuleEnum * This,
+ /* [in] */ ULONG celt);
+
+ HRESULT ( STDMETHODCALLTYPE *Reset )(
+ ICorDebugModuleEnum * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Clone )(
+ ICorDebugModuleEnum * This,
+ /* [out] */ ICorDebugEnum **ppEnum);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCount )(
+ ICorDebugModuleEnum * This,
+ /* [out] */ ULONG *pcelt);
+
+ HRESULT ( STDMETHODCALLTYPE *Next )(
+ ICorDebugModuleEnum * This,
+ /* [in] */ ULONG celt,
+ /* [length_is][size_is][out] */ ICorDebugModule *modules[ ],
+ /* [out] */ ULONG *pceltFetched);
+
+ END_INTERFACE
+ } ICorDebugModuleEnumVtbl;
+
+ interface ICorDebugModuleEnum
+ {
+ CONST_VTBL struct ICorDebugModuleEnumVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugModuleEnum_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugModuleEnum_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugModuleEnum_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugModuleEnum_Skip(This,celt) \
+ ( (This)->lpVtbl -> Skip(This,celt) )
+
+#define ICorDebugModuleEnum_Reset(This) \
+ ( (This)->lpVtbl -> Reset(This) )
+
+#define ICorDebugModuleEnum_Clone(This,ppEnum) \
+ ( (This)->lpVtbl -> Clone(This,ppEnum) )
+
+#define ICorDebugModuleEnum_GetCount(This,pcelt) \
+ ( (This)->lpVtbl -> GetCount(This,pcelt) )
+
+
+#define ICorDebugModuleEnum_Next(This,celt,modules,pceltFetched) \
+ ( (This)->lpVtbl -> Next(This,celt,modules,pceltFetched) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugModuleEnum_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugValueEnum_INTERFACE_DEFINED__
+#define __ICorDebugValueEnum_INTERFACE_DEFINED__
+
+/* interface ICorDebugValueEnum */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugValueEnum;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("CC7BCB0A-8A68-11d2-983C-0000F808342D")
+ ICorDebugValueEnum : public ICorDebugEnum
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE Next(
+ /* [in] */ ULONG celt,
+ /* [length_is][size_is][out] */ ICorDebugValue *values[ ],
+ /* [out] */ ULONG *pceltFetched) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugValueEnumVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugValueEnum * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugValueEnum * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugValueEnum * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Skip )(
+ ICorDebugValueEnum * This,
+ /* [in] */ ULONG celt);
+
+ HRESULT ( STDMETHODCALLTYPE *Reset )(
+ ICorDebugValueEnum * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Clone )(
+ ICorDebugValueEnum * This,
+ /* [out] */ ICorDebugEnum **ppEnum);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCount )(
+ ICorDebugValueEnum * This,
+ /* [out] */ ULONG *pcelt);
+
+ HRESULT ( STDMETHODCALLTYPE *Next )(
+ ICorDebugValueEnum * This,
+ /* [in] */ ULONG celt,
+ /* [length_is][size_is][out] */ ICorDebugValue *values[ ],
+ /* [out] */ ULONG *pceltFetched);
+
+ END_INTERFACE
+ } ICorDebugValueEnumVtbl;
+
+ interface ICorDebugValueEnum
+ {
+ CONST_VTBL struct ICorDebugValueEnumVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugValueEnum_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugValueEnum_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugValueEnum_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugValueEnum_Skip(This,celt) \
+ ( (This)->lpVtbl -> Skip(This,celt) )
+
+#define ICorDebugValueEnum_Reset(This) \
+ ( (This)->lpVtbl -> Reset(This) )
+
+#define ICorDebugValueEnum_Clone(This,ppEnum) \
+ ( (This)->lpVtbl -> Clone(This,ppEnum) )
+
+#define ICorDebugValueEnum_GetCount(This,pcelt) \
+ ( (This)->lpVtbl -> GetCount(This,pcelt) )
+
+
+#define ICorDebugValueEnum_Next(This,celt,values,pceltFetched) \
+ ( (This)->lpVtbl -> Next(This,celt,values,pceltFetched) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugValueEnum_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugCodeEnum_INTERFACE_DEFINED__
+#define __ICorDebugCodeEnum_INTERFACE_DEFINED__
+
+/* interface ICorDebugCodeEnum */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugCodeEnum;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("55E96461-9645-45e4-A2FF-0367877ABCDE")
+ ICorDebugCodeEnum : public ICorDebugEnum
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE Next(
+ /* [in] */ ULONG celt,
+ /* [length_is][size_is][out] */ ICorDebugCode *values[ ],
+ /* [out] */ ULONG *pceltFetched) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugCodeEnumVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugCodeEnum * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugCodeEnum * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugCodeEnum * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Skip )(
+ ICorDebugCodeEnum * This,
+ /* [in] */ ULONG celt);
+
+ HRESULT ( STDMETHODCALLTYPE *Reset )(
+ ICorDebugCodeEnum * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Clone )(
+ ICorDebugCodeEnum * This,
+ /* [out] */ ICorDebugEnum **ppEnum);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCount )(
+ ICorDebugCodeEnum * This,
+ /* [out] */ ULONG *pcelt);
+
+ HRESULT ( STDMETHODCALLTYPE *Next )(
+ ICorDebugCodeEnum * This,
+ /* [in] */ ULONG celt,
+ /* [length_is][size_is][out] */ ICorDebugCode *values[ ],
+ /* [out] */ ULONG *pceltFetched);
+
+ END_INTERFACE
+ } ICorDebugCodeEnumVtbl;
+
+ interface ICorDebugCodeEnum
+ {
+ CONST_VTBL struct ICorDebugCodeEnumVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugCodeEnum_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugCodeEnum_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugCodeEnum_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugCodeEnum_Skip(This,celt) \
+ ( (This)->lpVtbl -> Skip(This,celt) )
+
+#define ICorDebugCodeEnum_Reset(This) \
+ ( (This)->lpVtbl -> Reset(This) )
+
+#define ICorDebugCodeEnum_Clone(This,ppEnum) \
+ ( (This)->lpVtbl -> Clone(This,ppEnum) )
+
+#define ICorDebugCodeEnum_GetCount(This,pcelt) \
+ ( (This)->lpVtbl -> GetCount(This,pcelt) )
+
+
+#define ICorDebugCodeEnum_Next(This,celt,values,pceltFetched) \
+ ( (This)->lpVtbl -> Next(This,celt,values,pceltFetched) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugCodeEnum_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugTypeEnum_INTERFACE_DEFINED__
+#define __ICorDebugTypeEnum_INTERFACE_DEFINED__
+
+/* interface ICorDebugTypeEnum */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugTypeEnum;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("10F27499-9DF2-43ce-8333-A321D7C99CB4")
+ ICorDebugTypeEnum : public ICorDebugEnum
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE Next(
+ /* [in] */ ULONG celt,
+ /* [length_is][size_is][out] */ ICorDebugType *values[ ],
+ /* [out] */ ULONG *pceltFetched) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugTypeEnumVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugTypeEnum * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugTypeEnum * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugTypeEnum * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Skip )(
+ ICorDebugTypeEnum * This,
+ /* [in] */ ULONG celt);
+
+ HRESULT ( STDMETHODCALLTYPE *Reset )(
+ ICorDebugTypeEnum * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Clone )(
+ ICorDebugTypeEnum * This,
+ /* [out] */ ICorDebugEnum **ppEnum);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCount )(
+ ICorDebugTypeEnum * This,
+ /* [out] */ ULONG *pcelt);
+
+ HRESULT ( STDMETHODCALLTYPE *Next )(
+ ICorDebugTypeEnum * This,
+ /* [in] */ ULONG celt,
+ /* [length_is][size_is][out] */ ICorDebugType *values[ ],
+ /* [out] */ ULONG *pceltFetched);
+
+ END_INTERFACE
+ } ICorDebugTypeEnumVtbl;
+
+ interface ICorDebugTypeEnum
+ {
+ CONST_VTBL struct ICorDebugTypeEnumVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugTypeEnum_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugTypeEnum_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugTypeEnum_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugTypeEnum_Skip(This,celt) \
+ ( (This)->lpVtbl -> Skip(This,celt) )
+
+#define ICorDebugTypeEnum_Reset(This) \
+ ( (This)->lpVtbl -> Reset(This) )
+
+#define ICorDebugTypeEnum_Clone(This,ppEnum) \
+ ( (This)->lpVtbl -> Clone(This,ppEnum) )
+
+#define ICorDebugTypeEnum_GetCount(This,pcelt) \
+ ( (This)->lpVtbl -> GetCount(This,pcelt) )
+
+
+#define ICorDebugTypeEnum_Next(This,celt,values,pceltFetched) \
+ ( (This)->lpVtbl -> Next(This,celt,values,pceltFetched) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugTypeEnum_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugType_INTERFACE_DEFINED__
+#define __ICorDebugType_INTERFACE_DEFINED__
+
+/* interface ICorDebugType */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugType;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("D613F0BB-ACE1-4c19-BD72-E4C08D5DA7F5")
+ ICorDebugType : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetType(
+ /* [out] */ CorElementType *ty) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetClass(
+ /* [out] */ ICorDebugClass **ppClass) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnumerateTypeParameters(
+ /* [out] */ ICorDebugTypeEnum **ppTyParEnum) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetFirstTypeParameter(
+ /* [out] */ ICorDebugType **value) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetBase(
+ /* [out] */ ICorDebugType **pBase) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetStaticFieldValue(
+ /* [in] */ mdFieldDef fieldDef,
+ /* [in] */ ICorDebugFrame *pFrame,
+ /* [out] */ ICorDebugValue **ppValue) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetRank(
+ /* [out] */ ULONG32 *pnRank) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugTypeVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugType * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugType * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugType * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetType )(
+ ICorDebugType * This,
+ /* [out] */ CorElementType *ty);
+
+ HRESULT ( STDMETHODCALLTYPE *GetClass )(
+ ICorDebugType * This,
+ /* [out] */ ICorDebugClass **ppClass);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumerateTypeParameters )(
+ ICorDebugType * This,
+ /* [out] */ ICorDebugTypeEnum **ppTyParEnum);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFirstTypeParameter )(
+ ICorDebugType * This,
+ /* [out] */ ICorDebugType **value);
+
+ HRESULT ( STDMETHODCALLTYPE *GetBase )(
+ ICorDebugType * This,
+ /* [out] */ ICorDebugType **pBase);
+
+ HRESULT ( STDMETHODCALLTYPE *GetStaticFieldValue )(
+ ICorDebugType * This,
+ /* [in] */ mdFieldDef fieldDef,
+ /* [in] */ ICorDebugFrame *pFrame,
+ /* [out] */ ICorDebugValue **ppValue);
+
+ HRESULT ( STDMETHODCALLTYPE *GetRank )(
+ ICorDebugType * This,
+ /* [out] */ ULONG32 *pnRank);
+
+ END_INTERFACE
+ } ICorDebugTypeVtbl;
+
+ interface ICorDebugType
+ {
+ CONST_VTBL struct ICorDebugTypeVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugType_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugType_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugType_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugType_GetType(This,ty) \
+ ( (This)->lpVtbl -> GetType(This,ty) )
+
+#define ICorDebugType_GetClass(This,ppClass) \
+ ( (This)->lpVtbl -> GetClass(This,ppClass) )
+
+#define ICorDebugType_EnumerateTypeParameters(This,ppTyParEnum) \
+ ( (This)->lpVtbl -> EnumerateTypeParameters(This,ppTyParEnum) )
+
+#define ICorDebugType_GetFirstTypeParameter(This,value) \
+ ( (This)->lpVtbl -> GetFirstTypeParameter(This,value) )
+
+#define ICorDebugType_GetBase(This,pBase) \
+ ( (This)->lpVtbl -> GetBase(This,pBase) )
+
+#define ICorDebugType_GetStaticFieldValue(This,fieldDef,pFrame,ppValue) \
+ ( (This)->lpVtbl -> GetStaticFieldValue(This,fieldDef,pFrame,ppValue) )
+
+#define ICorDebugType_GetRank(This,pnRank) \
+ ( (This)->lpVtbl -> GetRank(This,pnRank) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugType_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugErrorInfoEnum_INTERFACE_DEFINED__
+#define __ICorDebugErrorInfoEnum_INTERFACE_DEFINED__
+
+/* interface ICorDebugErrorInfoEnum */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugErrorInfoEnum;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("F0E18809-72B5-11d2-976F-00A0C9B4D50C")
+ ICorDebugErrorInfoEnum : public ICorDebugEnum
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE Next(
+ /* [in] */ ULONG celt,
+ /* [length_is][size_is][out] */ ICorDebugEditAndContinueErrorInfo *errors[ ],
+ /* [out] */ ULONG *pceltFetched) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugErrorInfoEnumVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugErrorInfoEnum * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugErrorInfoEnum * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugErrorInfoEnum * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Skip )(
+ ICorDebugErrorInfoEnum * This,
+ /* [in] */ ULONG celt);
+
+ HRESULT ( STDMETHODCALLTYPE *Reset )(
+ ICorDebugErrorInfoEnum * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Clone )(
+ ICorDebugErrorInfoEnum * This,
+ /* [out] */ ICorDebugEnum **ppEnum);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCount )(
+ ICorDebugErrorInfoEnum * This,
+ /* [out] */ ULONG *pcelt);
+
+ HRESULT ( STDMETHODCALLTYPE *Next )(
+ ICorDebugErrorInfoEnum * This,
+ /* [in] */ ULONG celt,
+ /* [length_is][size_is][out] */ ICorDebugEditAndContinueErrorInfo *errors[ ],
+ /* [out] */ ULONG *pceltFetched);
+
+ END_INTERFACE
+ } ICorDebugErrorInfoEnumVtbl;
+
+ interface ICorDebugErrorInfoEnum
+ {
+ CONST_VTBL struct ICorDebugErrorInfoEnumVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugErrorInfoEnum_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugErrorInfoEnum_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugErrorInfoEnum_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugErrorInfoEnum_Skip(This,celt) \
+ ( (This)->lpVtbl -> Skip(This,celt) )
+
+#define ICorDebugErrorInfoEnum_Reset(This) \
+ ( (This)->lpVtbl -> Reset(This) )
+
+#define ICorDebugErrorInfoEnum_Clone(This,ppEnum) \
+ ( (This)->lpVtbl -> Clone(This,ppEnum) )
+
+#define ICorDebugErrorInfoEnum_GetCount(This,pcelt) \
+ ( (This)->lpVtbl -> GetCount(This,pcelt) )
+
+
+#define ICorDebugErrorInfoEnum_Next(This,celt,errors,pceltFetched) \
+ ( (This)->lpVtbl -> Next(This,celt,errors,pceltFetched) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugErrorInfoEnum_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugAppDomainEnum_INTERFACE_DEFINED__
+#define __ICorDebugAppDomainEnum_INTERFACE_DEFINED__
+
+/* interface ICorDebugAppDomainEnum */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugAppDomainEnum;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("63ca1b24-4359-4883-bd57-13f815f58744")
+ ICorDebugAppDomainEnum : public ICorDebugEnum
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE Next(
+ /* [in] */ ULONG celt,
+ /* [length_is][size_is][out] */ ICorDebugAppDomain *values[ ],
+ /* [out] */ ULONG *pceltFetched) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugAppDomainEnumVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugAppDomainEnum * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugAppDomainEnum * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugAppDomainEnum * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Skip )(
+ ICorDebugAppDomainEnum * This,
+ /* [in] */ ULONG celt);
+
+ HRESULT ( STDMETHODCALLTYPE *Reset )(
+ ICorDebugAppDomainEnum * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Clone )(
+ ICorDebugAppDomainEnum * This,
+ /* [out] */ ICorDebugEnum **ppEnum);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCount )(
+ ICorDebugAppDomainEnum * This,
+ /* [out] */ ULONG *pcelt);
+
+ HRESULT ( STDMETHODCALLTYPE *Next )(
+ ICorDebugAppDomainEnum * This,
+ /* [in] */ ULONG celt,
+ /* [length_is][size_is][out] */ ICorDebugAppDomain *values[ ],
+ /* [out] */ ULONG *pceltFetched);
+
+ END_INTERFACE
+ } ICorDebugAppDomainEnumVtbl;
+
+ interface ICorDebugAppDomainEnum
+ {
+ CONST_VTBL struct ICorDebugAppDomainEnumVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugAppDomainEnum_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugAppDomainEnum_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugAppDomainEnum_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugAppDomainEnum_Skip(This,celt) \
+ ( (This)->lpVtbl -> Skip(This,celt) )
+
+#define ICorDebugAppDomainEnum_Reset(This) \
+ ( (This)->lpVtbl -> Reset(This) )
+
+#define ICorDebugAppDomainEnum_Clone(This,ppEnum) \
+ ( (This)->lpVtbl -> Clone(This,ppEnum) )
+
+#define ICorDebugAppDomainEnum_GetCount(This,pcelt) \
+ ( (This)->lpVtbl -> GetCount(This,pcelt) )
+
+
+#define ICorDebugAppDomainEnum_Next(This,celt,values,pceltFetched) \
+ ( (This)->lpVtbl -> Next(This,celt,values,pceltFetched) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugAppDomainEnum_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugAssemblyEnum_INTERFACE_DEFINED__
+#define __ICorDebugAssemblyEnum_INTERFACE_DEFINED__
+
+/* interface ICorDebugAssemblyEnum */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugAssemblyEnum;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("4a2a1ec9-85ec-4bfb-9f15-a89fdfe0fe83")
+ ICorDebugAssemblyEnum : public ICorDebugEnum
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE Next(
+ /* [in] */ ULONG celt,
+ /* [length_is][size_is][out] */ ICorDebugAssembly *values[ ],
+ /* [out] */ ULONG *pceltFetched) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugAssemblyEnumVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugAssemblyEnum * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugAssemblyEnum * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugAssemblyEnum * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Skip )(
+ ICorDebugAssemblyEnum * This,
+ /* [in] */ ULONG celt);
+
+ HRESULT ( STDMETHODCALLTYPE *Reset )(
+ ICorDebugAssemblyEnum * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Clone )(
+ ICorDebugAssemblyEnum * This,
+ /* [out] */ ICorDebugEnum **ppEnum);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCount )(
+ ICorDebugAssemblyEnum * This,
+ /* [out] */ ULONG *pcelt);
+
+ HRESULT ( STDMETHODCALLTYPE *Next )(
+ ICorDebugAssemblyEnum * This,
+ /* [in] */ ULONG celt,
+ /* [length_is][size_is][out] */ ICorDebugAssembly *values[ ],
+ /* [out] */ ULONG *pceltFetched);
+
+ END_INTERFACE
+ } ICorDebugAssemblyEnumVtbl;
+
+ interface ICorDebugAssemblyEnum
+ {
+ CONST_VTBL struct ICorDebugAssemblyEnumVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugAssemblyEnum_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugAssemblyEnum_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugAssemblyEnum_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugAssemblyEnum_Skip(This,celt) \
+ ( (This)->lpVtbl -> Skip(This,celt) )
+
+#define ICorDebugAssemblyEnum_Reset(This) \
+ ( (This)->lpVtbl -> Reset(This) )
+
+#define ICorDebugAssemblyEnum_Clone(This,ppEnum) \
+ ( (This)->lpVtbl -> Clone(This,ppEnum) )
+
+#define ICorDebugAssemblyEnum_GetCount(This,pcelt) \
+ ( (This)->lpVtbl -> GetCount(This,pcelt) )
+
+
+#define ICorDebugAssemblyEnum_Next(This,celt,values,pceltFetched) \
+ ( (This)->lpVtbl -> Next(This,celt,values,pceltFetched) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugAssemblyEnum_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugBlockingObjectEnum_INTERFACE_DEFINED__
+#define __ICorDebugBlockingObjectEnum_INTERFACE_DEFINED__
+
+/* interface ICorDebugBlockingObjectEnum */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugBlockingObjectEnum;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("976A6278-134A-4a81-81A3-8F277943F4C3")
+ ICorDebugBlockingObjectEnum : public ICorDebugEnum
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE Next(
+ /* [in] */ ULONG celt,
+ /* [length_is][size_is][out] */ CorDebugBlockingObject values[ ],
+ /* [out] */ ULONG *pceltFetched) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugBlockingObjectEnumVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugBlockingObjectEnum * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugBlockingObjectEnum * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugBlockingObjectEnum * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Skip )(
+ ICorDebugBlockingObjectEnum * This,
+ /* [in] */ ULONG celt);
+
+ HRESULT ( STDMETHODCALLTYPE *Reset )(
+ ICorDebugBlockingObjectEnum * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Clone )(
+ ICorDebugBlockingObjectEnum * This,
+ /* [out] */ ICorDebugEnum **ppEnum);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCount )(
+ ICorDebugBlockingObjectEnum * This,
+ /* [out] */ ULONG *pcelt);
+
+ HRESULT ( STDMETHODCALLTYPE *Next )(
+ ICorDebugBlockingObjectEnum * This,
+ /* [in] */ ULONG celt,
+ /* [length_is][size_is][out] */ CorDebugBlockingObject values[ ],
+ /* [out] */ ULONG *pceltFetched);
+
+ END_INTERFACE
+ } ICorDebugBlockingObjectEnumVtbl;
+
+ interface ICorDebugBlockingObjectEnum
+ {
+ CONST_VTBL struct ICorDebugBlockingObjectEnumVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugBlockingObjectEnum_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugBlockingObjectEnum_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugBlockingObjectEnum_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugBlockingObjectEnum_Skip(This,celt) \
+ ( (This)->lpVtbl -> Skip(This,celt) )
+
+#define ICorDebugBlockingObjectEnum_Reset(This) \
+ ( (This)->lpVtbl -> Reset(This) )
+
+#define ICorDebugBlockingObjectEnum_Clone(This,ppEnum) \
+ ( (This)->lpVtbl -> Clone(This,ppEnum) )
+
+#define ICorDebugBlockingObjectEnum_GetCount(This,pcelt) \
+ ( (This)->lpVtbl -> GetCount(This,pcelt) )
+
+
+#define ICorDebugBlockingObjectEnum_Next(This,celt,values,pceltFetched) \
+ ( (This)->lpVtbl -> Next(This,celt,values,pceltFetched) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugBlockingObjectEnum_INTERFACE_DEFINED__ */
+
+
+/* interface __MIDL_itf_cordebug_0000_0117 */
+/* [local] */
+
+#pragma warning(push)
+#pragma warning(disable:28718)
+
+
+extern RPC_IF_HANDLE __MIDL_itf_cordebug_0000_0117_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_cordebug_0000_0117_v0_0_s_ifspec;
+
+#ifndef __ICorDebugMDA_INTERFACE_DEFINED__
+#define __ICorDebugMDA_INTERFACE_DEFINED__
+
+/* interface ICorDebugMDA */
+/* [unique][uuid][local][object] */
+
+typedef
+enum CorDebugMDAFlags
+ {
+ MDA_FLAG_SLIP = 0x2
+ } CorDebugMDAFlags;
+
+
+EXTERN_C const IID IID_ICorDebugMDA;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("CC726F2F-1DB7-459b-B0EC-05F01D841B42")
+ ICorDebugMDA : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetName(
+ /* [in] */ ULONG32 cchName,
+ /* [out] */ ULONG32 *pcchName,
+ /* [length_is][size_is][out] */ WCHAR szName[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetDescription(
+ /* [in] */ ULONG32 cchName,
+ /* [out] */ ULONG32 *pcchName,
+ /* [length_is][size_is][out] */ WCHAR szName[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetXML(
+ /* [in] */ ULONG32 cchName,
+ /* [out] */ ULONG32 *pcchName,
+ /* [length_is][size_is][out] */ WCHAR szName[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetFlags(
+ /* [in] */ CorDebugMDAFlags *pFlags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetOSThreadId(
+ /* [out] */ DWORD *pOsTid) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugMDAVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugMDA * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugMDA * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugMDA * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetName )(
+ ICorDebugMDA * This,
+ /* [in] */ ULONG32 cchName,
+ /* [out] */ ULONG32 *pcchName,
+ /* [length_is][size_is][out] */ WCHAR szName[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDescription )(
+ ICorDebugMDA * This,
+ /* [in] */ ULONG32 cchName,
+ /* [out] */ ULONG32 *pcchName,
+ /* [length_is][size_is][out] */ WCHAR szName[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetXML )(
+ ICorDebugMDA * This,
+ /* [in] */ ULONG32 cchName,
+ /* [out] */ ULONG32 *pcchName,
+ /* [length_is][size_is][out] */ WCHAR szName[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFlags )(
+ ICorDebugMDA * This,
+ /* [in] */ CorDebugMDAFlags *pFlags);
+
+ HRESULT ( STDMETHODCALLTYPE *GetOSThreadId )(
+ ICorDebugMDA * This,
+ /* [out] */ DWORD *pOsTid);
+
+ END_INTERFACE
+ } ICorDebugMDAVtbl;
+
+ interface ICorDebugMDA
+ {
+ CONST_VTBL struct ICorDebugMDAVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugMDA_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugMDA_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugMDA_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugMDA_GetName(This,cchName,pcchName,szName) \
+ ( (This)->lpVtbl -> GetName(This,cchName,pcchName,szName) )
+
+#define ICorDebugMDA_GetDescription(This,cchName,pcchName,szName) \
+ ( (This)->lpVtbl -> GetDescription(This,cchName,pcchName,szName) )
+
+#define ICorDebugMDA_GetXML(This,cchName,pcchName,szName) \
+ ( (This)->lpVtbl -> GetXML(This,cchName,pcchName,szName) )
+
+#define ICorDebugMDA_GetFlags(This,pFlags) \
+ ( (This)->lpVtbl -> GetFlags(This,pFlags) )
+
+#define ICorDebugMDA_GetOSThreadId(This,pOsTid) \
+ ( (This)->lpVtbl -> GetOSThreadId(This,pOsTid) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugMDA_INTERFACE_DEFINED__ */
+
+
+/* interface __MIDL_itf_cordebug_0000_0118 */
+/* [local] */
+
+#pragma warning(pop)
+#pragma warning(push)
+#pragma warning(disable:28718)
+
+
+extern RPC_IF_HANDLE __MIDL_itf_cordebug_0000_0118_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_cordebug_0000_0118_v0_0_s_ifspec;
+
+#ifndef __ICorDebugEditAndContinueErrorInfo_INTERFACE_DEFINED__
+#define __ICorDebugEditAndContinueErrorInfo_INTERFACE_DEFINED__
+
+/* interface ICorDebugEditAndContinueErrorInfo */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugEditAndContinueErrorInfo;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("8D600D41-F4F6-4cb3-B7EC-7BD164944036")
+ ICorDebugEditAndContinueErrorInfo : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetModule(
+ /* [out] */ ICorDebugModule **ppModule) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetToken(
+ /* [out] */ mdToken *pToken) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetErrorCode(
+ /* [out] */ HRESULT *pHr) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetString(
+ /* [in] */ ULONG32 cchString,
+ /* [out] */ ULONG32 *pcchString,
+ /* [length_is][size_is][out] */ WCHAR szString[ ]) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugEditAndContinueErrorInfoVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugEditAndContinueErrorInfo * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugEditAndContinueErrorInfo * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugEditAndContinueErrorInfo * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetModule )(
+ ICorDebugEditAndContinueErrorInfo * This,
+ /* [out] */ ICorDebugModule **ppModule);
+
+ HRESULT ( STDMETHODCALLTYPE *GetToken )(
+ ICorDebugEditAndContinueErrorInfo * This,
+ /* [out] */ mdToken *pToken);
+
+ HRESULT ( STDMETHODCALLTYPE *GetErrorCode )(
+ ICorDebugEditAndContinueErrorInfo * This,
+ /* [out] */ HRESULT *pHr);
+
+ HRESULT ( STDMETHODCALLTYPE *GetString )(
+ ICorDebugEditAndContinueErrorInfo * This,
+ /* [in] */ ULONG32 cchString,
+ /* [out] */ ULONG32 *pcchString,
+ /* [length_is][size_is][out] */ WCHAR szString[ ]);
+
+ END_INTERFACE
+ } ICorDebugEditAndContinueErrorInfoVtbl;
+
+ interface ICorDebugEditAndContinueErrorInfo
+ {
+ CONST_VTBL struct ICorDebugEditAndContinueErrorInfoVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugEditAndContinueErrorInfo_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugEditAndContinueErrorInfo_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugEditAndContinueErrorInfo_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugEditAndContinueErrorInfo_GetModule(This,ppModule) \
+ ( (This)->lpVtbl -> GetModule(This,ppModule) )
+
+#define ICorDebugEditAndContinueErrorInfo_GetToken(This,pToken) \
+ ( (This)->lpVtbl -> GetToken(This,pToken) )
+
+#define ICorDebugEditAndContinueErrorInfo_GetErrorCode(This,pHr) \
+ ( (This)->lpVtbl -> GetErrorCode(This,pHr) )
+
+#define ICorDebugEditAndContinueErrorInfo_GetString(This,cchString,pcchString,szString) \
+ ( (This)->lpVtbl -> GetString(This,cchString,pcchString,szString) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugEditAndContinueErrorInfo_INTERFACE_DEFINED__ */
+
+
+/* interface __MIDL_itf_cordebug_0000_0119 */
+/* [local] */
+
+#pragma warning(pop)
+
+
+extern RPC_IF_HANDLE __MIDL_itf_cordebug_0000_0119_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_cordebug_0000_0119_v0_0_s_ifspec;
+
+#ifndef __ICorDebugEditAndContinueSnapshot_INTERFACE_DEFINED__
+#define __ICorDebugEditAndContinueSnapshot_INTERFACE_DEFINED__
+
+/* interface ICorDebugEditAndContinueSnapshot */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugEditAndContinueSnapshot;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("6DC3FA01-D7CB-11d2-8A95-0080C792E5D8")
+ ICorDebugEditAndContinueSnapshot : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE CopyMetaData(
+ /* [in] */ IStream *pIStream,
+ /* [out] */ GUID *pMvid) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetMvid(
+ /* [out] */ GUID *pMvid) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetRoDataRVA(
+ /* [out] */ ULONG32 *pRoDataRVA) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetRwDataRVA(
+ /* [out] */ ULONG32 *pRwDataRVA) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetPEBytes(
+ /* [in] */ IStream *pIStream) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetILMap(
+ /* [in] */ mdToken mdFunction,
+ /* [in] */ ULONG cMapSize,
+ /* [size_is][in] */ COR_IL_MAP map[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetPESymbolBytes(
+ /* [in] */ IStream *pIStream) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugEditAndContinueSnapshotVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugEditAndContinueSnapshot * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugEditAndContinueSnapshot * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugEditAndContinueSnapshot * This);
+
+ HRESULT ( STDMETHODCALLTYPE *CopyMetaData )(
+ ICorDebugEditAndContinueSnapshot * This,
+ /* [in] */ IStream *pIStream,
+ /* [out] */ GUID *pMvid);
+
+ HRESULT ( STDMETHODCALLTYPE *GetMvid )(
+ ICorDebugEditAndContinueSnapshot * This,
+ /* [out] */ GUID *pMvid);
+
+ HRESULT ( STDMETHODCALLTYPE *GetRoDataRVA )(
+ ICorDebugEditAndContinueSnapshot * This,
+ /* [out] */ ULONG32 *pRoDataRVA);
+
+ HRESULT ( STDMETHODCALLTYPE *GetRwDataRVA )(
+ ICorDebugEditAndContinueSnapshot * This,
+ /* [out] */ ULONG32 *pRwDataRVA);
+
+ HRESULT ( STDMETHODCALLTYPE *SetPEBytes )(
+ ICorDebugEditAndContinueSnapshot * This,
+ /* [in] */ IStream *pIStream);
+
+ HRESULT ( STDMETHODCALLTYPE *SetILMap )(
+ ICorDebugEditAndContinueSnapshot * This,
+ /* [in] */ mdToken mdFunction,
+ /* [in] */ ULONG cMapSize,
+ /* [size_is][in] */ COR_IL_MAP map[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *SetPESymbolBytes )(
+ ICorDebugEditAndContinueSnapshot * This,
+ /* [in] */ IStream *pIStream);
+
+ END_INTERFACE
+ } ICorDebugEditAndContinueSnapshotVtbl;
+
+ interface ICorDebugEditAndContinueSnapshot
+ {
+ CONST_VTBL struct ICorDebugEditAndContinueSnapshotVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugEditAndContinueSnapshot_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugEditAndContinueSnapshot_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugEditAndContinueSnapshot_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugEditAndContinueSnapshot_CopyMetaData(This,pIStream,pMvid) \
+ ( (This)->lpVtbl -> CopyMetaData(This,pIStream,pMvid) )
+
+#define ICorDebugEditAndContinueSnapshot_GetMvid(This,pMvid) \
+ ( (This)->lpVtbl -> GetMvid(This,pMvid) )
+
+#define ICorDebugEditAndContinueSnapshot_GetRoDataRVA(This,pRoDataRVA) \
+ ( (This)->lpVtbl -> GetRoDataRVA(This,pRoDataRVA) )
+
+#define ICorDebugEditAndContinueSnapshot_GetRwDataRVA(This,pRwDataRVA) \
+ ( (This)->lpVtbl -> GetRwDataRVA(This,pRwDataRVA) )
+
+#define ICorDebugEditAndContinueSnapshot_SetPEBytes(This,pIStream) \
+ ( (This)->lpVtbl -> SetPEBytes(This,pIStream) )
+
+#define ICorDebugEditAndContinueSnapshot_SetILMap(This,mdFunction,cMapSize,map) \
+ ( (This)->lpVtbl -> SetILMap(This,mdFunction,cMapSize,map) )
+
+#define ICorDebugEditAndContinueSnapshot_SetPESymbolBytes(This,pIStream) \
+ ( (This)->lpVtbl -> SetPESymbolBytes(This,pIStream) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugEditAndContinueSnapshot_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugExceptionObjectCallStackEnum_INTERFACE_DEFINED__
+#define __ICorDebugExceptionObjectCallStackEnum_INTERFACE_DEFINED__
+
+/* interface ICorDebugExceptionObjectCallStackEnum */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugExceptionObjectCallStackEnum;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("ED775530-4DC4-41F7-86D0-9E2DEF7DFC66")
+ ICorDebugExceptionObjectCallStackEnum : public ICorDebugEnum
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE Next(
+ /* [in] */ ULONG celt,
+ /* [length_is][size_is][out] */ CorDebugExceptionObjectStackFrame values[ ],
+ /* [out] */ ULONG *pceltFetched) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugExceptionObjectCallStackEnumVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugExceptionObjectCallStackEnum * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugExceptionObjectCallStackEnum * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugExceptionObjectCallStackEnum * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Skip )(
+ ICorDebugExceptionObjectCallStackEnum * This,
+ /* [in] */ ULONG celt);
+
+ HRESULT ( STDMETHODCALLTYPE *Reset )(
+ ICorDebugExceptionObjectCallStackEnum * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Clone )(
+ ICorDebugExceptionObjectCallStackEnum * This,
+ /* [out] */ ICorDebugEnum **ppEnum);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCount )(
+ ICorDebugExceptionObjectCallStackEnum * This,
+ /* [out] */ ULONG *pcelt);
+
+ HRESULT ( STDMETHODCALLTYPE *Next )(
+ ICorDebugExceptionObjectCallStackEnum * This,
+ /* [in] */ ULONG celt,
+ /* [length_is][size_is][out] */ CorDebugExceptionObjectStackFrame values[ ],
+ /* [out] */ ULONG *pceltFetched);
+
+ END_INTERFACE
+ } ICorDebugExceptionObjectCallStackEnumVtbl;
+
+ interface ICorDebugExceptionObjectCallStackEnum
+ {
+ CONST_VTBL struct ICorDebugExceptionObjectCallStackEnumVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugExceptionObjectCallStackEnum_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugExceptionObjectCallStackEnum_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugExceptionObjectCallStackEnum_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugExceptionObjectCallStackEnum_Skip(This,celt) \
+ ( (This)->lpVtbl -> Skip(This,celt) )
+
+#define ICorDebugExceptionObjectCallStackEnum_Reset(This) \
+ ( (This)->lpVtbl -> Reset(This) )
+
+#define ICorDebugExceptionObjectCallStackEnum_Clone(This,ppEnum) \
+ ( (This)->lpVtbl -> Clone(This,ppEnum) )
+
+#define ICorDebugExceptionObjectCallStackEnum_GetCount(This,pcelt) \
+ ( (This)->lpVtbl -> GetCount(This,pcelt) )
+
+
+#define ICorDebugExceptionObjectCallStackEnum_Next(This,celt,values,pceltFetched) \
+ ( (This)->lpVtbl -> Next(This,celt,values,pceltFetched) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugExceptionObjectCallStackEnum_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorDebugExceptionObjectValue_INTERFACE_DEFINED__
+#define __ICorDebugExceptionObjectValue_INTERFACE_DEFINED__
+
+/* interface ICorDebugExceptionObjectValue */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugExceptionObjectValue;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("AE4CA65D-59DD-42A2-83A5-57E8A08D8719")
+ ICorDebugExceptionObjectValue : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE EnumerateExceptionCallStack(
+ /* [out] */ ICorDebugExceptionObjectCallStackEnum **ppCallStackEnum) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugExceptionObjectValueVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugExceptionObjectValue * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugExceptionObjectValue * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugExceptionObjectValue * This);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumerateExceptionCallStack )(
+ ICorDebugExceptionObjectValue * This,
+ /* [out] */ ICorDebugExceptionObjectCallStackEnum **ppCallStackEnum);
+
+ END_INTERFACE
+ } ICorDebugExceptionObjectValueVtbl;
+
+ interface ICorDebugExceptionObjectValue
+ {
+ CONST_VTBL struct ICorDebugExceptionObjectValueVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugExceptionObjectValue_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugExceptionObjectValue_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugExceptionObjectValue_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugExceptionObjectValue_EnumerateExceptionCallStack(This,ppCallStackEnum) \
+ ( (This)->lpVtbl -> EnumerateExceptionCallStack(This,ppCallStackEnum) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugExceptionObjectValue_INTERFACE_DEFINED__ */
+
+
+
+#ifndef __CORDBLib_LIBRARY_DEFINED__
+#define __CORDBLib_LIBRARY_DEFINED__
+
+/* library CORDBLib */
+/* [helpstring][version][uuid] */
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+EXTERN_C const IID LIBID_CORDBLib;
+
+EXTERN_C const CLSID CLSID_CorDebug;
+
+#ifdef __cplusplus
+
+class DECLSPEC_UUID("6fef44d0-39e7-4c77-be8e-c9f8cf988630")
+CorDebug;
+#endif
+
+EXTERN_C const CLSID CLSID_EmbeddedCLRCorDebug;
+
+#ifdef __cplusplus
+
+class DECLSPEC_UUID("211f1254-bc7e-4af5-b9aa-067308d83dd1")
+EmbeddedCLRCorDebug;
+#endif
+#endif /* __CORDBLib_LIBRARY_DEFINED__ */
+
+/* Additional Prototypes for ALL interfaces */
+
+/* end of Additional Prototypes */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+
diff --git a/src/pal/prebuilt/inc/corerror.h b/src/pal/prebuilt/inc/corerror.h
new file mode 100644
index 0000000000..d4d4495297
--- /dev/null
+++ b/src/pal/prebuilt/inc/corerror.h
@@ -0,0 +1,1250 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#ifndef __COMMON_LANGUAGE_RUNTIME_HRESULTS__
+#define __COMMON_LANGUAGE_RUNTIME_HRESULTS__
+
+#include <winerror.h>
+
+
+//
+//This file is AutoGenerated -- Do Not Edit by hand!!!
+//
+//Add new HRESULTS along with their corresponding error messages to
+//corerror.xml
+//
+
+#ifndef FACILITY_URT
+#define FACILITY_URT 0x13
+#endif
+#ifndef EMAKEHR
+#define SMAKEHR(val) MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_URT, val)
+#define EMAKEHR(val) MAKE_HRESULT(SEVERITY_ERROR, FACILITY_URT, val)
+#endif
+
+#define CLDB_S_TRUNCATION SMAKEHR(0x1106)
+#define CLDB_S_NULL SMAKEHR(0x1109)
+#define CLDB_S_INDEX_TABLESCANREQUIRED SMAKEHR(0x1125)
+#define TLBX_I_TYPEINFO_IMPORTED SMAKEHR(0x116c)
+#define TLBX_I_PIA_REGISTERED_FOR_TLB SMAKEHR(0x116d)
+#define TLBX_I_AGNOSTIC_ASSEMBLY SMAKEHR(0x116e)
+#define TLBX_I_USEIUNKNOWN SMAKEHR(0x116f)
+#define TLBX_I_UNCONVERTABLE_ARGS SMAKEHR(0x1170)
+#define TLBX_I_UNCONVERTABLE_FIELD SMAKEHR(0x1171)
+#define TLBX_W_WARNING_MESSAGE SMAKEHR(0x1173)
+#define TLBX_W_ASSEMBLY_HAS_EMBEDDED_TLB SMAKEHR(0x1174)
+#define TLBX_W_CROSS_COMPILE_NO_REFS SMAKEHR(0x1175)
+#define TLBX_W_PURE_CROSS_COMPILE SMAKEHR(0x1176)
+#define TLBX_I_TYPE_EXPORTED SMAKEHR(0x1179)
+#define TLBX_I_DUPLICATE_DISPID SMAKEHR(0x117a)
+#define TLBX_I_REF_TYPE_AS_STRUCT SMAKEHR(0x117c)
+#define TLBX_I_GENERIC_TYPE SMAKEHR(0x117f)
+#define TLBX_W_NON_INTEGRAL_CA_TYPE SMAKEHR(0x1184)
+#define TLBX_W_IENUM_CA_ON_IUNK SMAKEHR(0x1185)
+#define META_S_PARAM_MISMATCH SMAKEHR(0x1189)
+#define META_S_DUPLICATE SMAKEHR(0x1197)
+#define TLBX_S_REFERENCED_TYPELIB SMAKEHR(0x11ac)
+#define TLBX_S_NOSTDINTERFACE SMAKEHR(0x11b3)
+#define TLBX_S_DUPLICATE_DISPID SMAKEHR(0x11b4)
+#define TLBX_W_ENUM_VALUE_TOOBIG SMAKEHR(0x11d5)
+#define TLBX_W_EXPORTING_AUTO_LAYOUT SMAKEHR(0x11d9)
+#define TLBX_W_DEFAULT_INTF_NOT_VISIBLE SMAKEHR(0x11db)
+#define TLBX_W_BAD_SAFEARRAYFIELD_NO_ELEMENTVT SMAKEHR(0x11de)
+#define TLBX_W_LAYOUTCLASS_AS_INTERFACE SMAKEHR(0x11df)
+#define TLBX_I_GENERIC_BASE_TYPE SMAKEHR(0x11e0)
+#define VLDTR_S_WRN SMAKEHR(0x1200)
+#define VLDTR_S_ERR SMAKEHR(0x1201)
+#define VLDTR_S_WRNERR SMAKEHR(0x1202)
+#define CORDBG_S_BAD_START_SEQUENCE_POINT SMAKEHR(0x130b)
+#define CORDBG_S_BAD_END_SEQUENCE_POINT SMAKEHR(0x130c)
+#define CORDBG_S_INSUFFICIENT_INFO_FOR_SET_IP SMAKEHR(0x130d)
+#define CORDBG_S_FUNC_EVAL_HAS_NO_RESULT SMAKEHR(0x1316)
+#define CORDBG_S_VALUE_POINTS_TO_VOID SMAKEHR(0x1317)
+#define CORDBG_S_FUNC_EVAL_ABORTED SMAKEHR(0x1319)
+#define CORDBG_S_AT_END_OF_STACK SMAKEHR(0x1324)
+#define CORDBG_S_NOT_ALL_BITS_SET SMAKEHR(0x1c13)
+#define CEE_E_ENTRYPOINT EMAKEHR(0x1000)
+#define CEE_E_CVTRES_NOT_FOUND EMAKEHR(0x1001)
+#define MSEE_E_LOADLIBFAILED EMAKEHR(0x1010)
+#define MSEE_E_GETPROCFAILED EMAKEHR(0x1011)
+#define MSEE_E_MULTCOPIESLOADED EMAKEHR(0x1012)
+#define COR_E_TYPEUNLOADED EMAKEHR(0x1013)
+#define COR_E_APPDOMAINUNLOADED EMAKEHR(0x1014)
+#define COR_E_CANNOTUNLOADAPPDOMAIN EMAKEHR(0x1015)
+#define MSEE_E_ASSEMBLYLOADINPROGRESS EMAKEHR(0x1016)
+#define MSEE_E_CANNOTCREATEAPPDOMAIN EMAKEHR(0x1017)
+#define COR_E_ASSEMBLYEXPECTED EMAKEHR(0x1018)
+#define COR_E_FIXUPSINEXE EMAKEHR(0x1019)
+#define COR_E_NO_LOADLIBRARY_ALLOWED EMAKEHR(0x101a)
+#define COR_E_NEWER_RUNTIME EMAKEHR(0x101b)
+#define COR_E_CANNOT_SET_POLICY EMAKEHR(0x101c)
+#define COR_E_CANNOT_SPECIFY_EVIDENCE EMAKEHR(0x101d)
+#define COR_E_MULTIMODULEASSEMBLIESDIALLOWED EMAKEHR(0x101e)
+#define HOST_E_DEADLOCK EMAKEHR(0x1020)
+#define HOST_E_INTERRUPTED EMAKEHR(0x1021)
+#define HOST_E_INVALIDOPERATION EMAKEHR(0x1022)
+#define HOST_E_CLRNOTAVAILABLE EMAKEHR(0x1023)
+#define HOST_E_TIMEOUT EMAKEHR(0x1024)
+#define HOST_E_NOT_OWNER EMAKEHR(0x1025)
+#define HOST_E_ABANDONED EMAKEHR(0x1026)
+#define HOST_E_EXITPROCESS_THREADABORT EMAKEHR(0x1027)
+#define HOST_E_EXITPROCESS_ADUNLOAD EMAKEHR(0x1028)
+#define HOST_E_EXITPROCESS_TIMEOUT EMAKEHR(0x1029)
+#define HOST_E_EXITPROCESS_OUTOFMEMORY EMAKEHR(0x102a)
+#define HOST_E_EXITPROCESS_STACKOVERFLOW EMAKEHR(0x102b)
+#define COR_E_MODULE_HASH_CHECK_FAILED EMAKEHR(0x1039)
+#define FUSION_E_REF_DEF_MISMATCH EMAKEHR(0x1040)
+#define FUSION_E_INVALID_PRIVATE_ASM_LOCATION EMAKEHR(0x1041)
+#define FUSION_E_ASM_MODULE_MISSING EMAKEHR(0x1042)
+#define FUSION_E_UNEXPECTED_MODULE_FOUND EMAKEHR(0x1043)
+#define FUSION_E_PRIVATE_ASM_DISALLOWED EMAKEHR(0x1044)
+#define FUSION_E_SIGNATURE_CHECK_FAILED EMAKEHR(0x1045)
+#define FUSION_E_DATABASE_ERROR EMAKEHR(0x1046)
+#define FUSION_E_INVALID_NAME EMAKEHR(0x1047)
+#define FUSION_E_CODE_DOWNLOAD_DISABLED EMAKEHR(0x1048)
+#define FUSION_E_UNINSTALL_DISALLOWED EMAKEHR(0x1049)
+#define CLR_E_APP_CONFIG_NOT_ALLOWED_IN_APPX_PROCESS EMAKEHR(0x104a)
+#define FUSION_E_HOST_GAC_ASM_MISMATCH EMAKEHR(0x1050)
+#define FUSION_E_LOADFROM_BLOCKED EMAKEHR(0x1051)
+#define FUSION_E_CACHEFILE_FAILED EMAKEHR(0x1052)
+#define FUSION_E_APP_DOMAIN_LOCKED EMAKEHR(0x1053)
+#define FUSION_E_CONFIGURATION_ERROR EMAKEHR(0x1054)
+#define FUSION_E_MANIFEST_PARSE_ERROR EMAKEHR(0x1055)
+#define FUSION_E_INVALID_ASSEMBLY_REFERENCE EMAKEHR(0x1056)
+#define COR_E_ASSEMBLY_NOT_EXPECTED EMAKEHR(0x1057)
+#define COR_E_LOADING_REFERENCE_ASSEMBLY EMAKEHR(0x1058)
+#define COR_E_NI_AND_RUNTIME_VERSION_MISMATCH EMAKEHR(0x1059)
+#define COR_E_LOADING_WINMD_REFERENCE_ASSEMBLY EMAKEHR(0x1069)
+#define CLDB_E_FILE_BADREAD EMAKEHR(0x1100)
+#define CLDB_E_FILE_BADWRITE EMAKEHR(0x1101)
+#define CLDB_E_FILE_READONLY EMAKEHR(0x1103)
+#define CLDB_E_NAME_ERROR EMAKEHR(0x1105)
+#define CLDB_E_TRUNCATION EMAKEHR(0x1106)
+#define CLDB_E_FILE_OLDVER EMAKEHR(0x1107)
+#define CLDB_E_RELOCATED EMAKEHR(0x1108)
+#define CLDB_E_SMDUPLICATE EMAKEHR(0x110a)
+#define CLDB_E_NO_DATA EMAKEHR(0x110b)
+#define CLDB_E_READONLY EMAKEHR(0x110c)
+#define CLDB_E_INCOMPATIBLE EMAKEHR(0x110d)
+#define CLDB_E_FILE_CORRUPT EMAKEHR(0x110e)
+#define CLDB_E_SCHEMA_VERNOTFOUND EMAKEHR(0x110f)
+#define CLDB_E_BADUPDATEMODE EMAKEHR(0x1110)
+#define CLDB_E_INDEX_NONULLKEYS EMAKEHR(0x1121)
+#define CLDB_E_INDEX_DUPLICATE EMAKEHR(0x1122)
+#define CLDB_E_INDEX_BADTYPE EMAKEHR(0x1123)
+#define CLDB_E_INDEX_NOTFOUND EMAKEHR(0x1124)
+#define CLDB_E_RECORD_NOTFOUND EMAKEHR(0x1130)
+#define CLDB_E_RECORD_OVERFLOW EMAKEHR(0x1131)
+#define CLDB_E_RECORD_DUPLICATE EMAKEHR(0x1132)
+#define CLDB_E_RECORD_PKREQUIRED EMAKEHR(0x1133)
+#define CLDB_E_RECORD_DELETED EMAKEHR(0x1134)
+#define CLDB_E_RECORD_OUTOFORDER EMAKEHR(0x1135)
+#define CLDB_E_COLUMN_OVERFLOW EMAKEHR(0x1140)
+#define CLDB_E_COLUMN_READONLY EMAKEHR(0x1141)
+#define CLDB_E_COLUMN_SPECIALCOL EMAKEHR(0x1142)
+#define CLDB_E_COLUMN_PKNONULLS EMAKEHR(0x1143)
+#define CLDB_E_TABLE_CANTDROP EMAKEHR(0x1150)
+#define CLDB_E_OBJECT_NOTFOUND EMAKEHR(0x1151)
+#define CLDB_E_OBJECT_COLNOTFOUND EMAKEHR(0x1152)
+#define CLDB_E_VECTOR_BADINDEX EMAKEHR(0x1153)
+#define CLDB_E_TOO_BIG EMAKEHR(0x1154)
+#define META_E_INVALID_TOKEN_TYPE EMAKEHR(0x115f)
+#define TLBX_E_INVALID_TYPEINFO EMAKEHR(0x1160)
+#define TLBX_E_INVALID_TYPEINFO_UNNAMED EMAKEHR(0x1161)
+#define TLBX_E_CTX_NESTED EMAKEHR(0x1162)
+#define TLBX_E_ERROR_MESSAGE EMAKEHR(0x1163)
+#define TLBX_E_CANT_SAVE EMAKEHR(0x1164)
+#define TLBX_W_LIBNOTREGISTERED EMAKEHR(0x1165)
+#define TLBX_E_CANTLOADLIBRARY EMAKEHR(0x1166)
+#define TLBX_E_BAD_VT_TYPE EMAKEHR(0x1167)
+#define TLBX_E_NO_MSCOREE_TLB EMAKEHR(0x1168)
+#define TLBX_E_BAD_MSCOREE_TLB EMAKEHR(0x1169)
+#define TLBX_E_TLB_EXCEPTION EMAKEHR(0x116a)
+#define TLBX_E_MULTIPLE_LCIDS EMAKEHR(0x116b)
+#define TLBX_E_AMBIGUOUS_RETURN EMAKEHR(0x116d)
+#define TLBX_E_DUPLICATE_TYPE_NAME EMAKEHR(0x116e)
+#define TLBX_I_NONSEQUENTIALSTRUCT EMAKEHR(0x1172)
+#define TLBX_I_RESOLVEREFFAILED EMAKEHR(0x1174)
+#define TLBX_E_ASANY EMAKEHR(0x1175)
+#define TLBX_E_INVALIDLCIDPARAM EMAKEHR(0x1176)
+#define TLBX_E_LCIDONDISPONLYITF EMAKEHR(0x1177)
+#define TLBX_E_NONPUBLIC_FIELD EMAKEHR(0x1178)
+#define TLBX_E_BAD_NAMES EMAKEHR(0x117b)
+#define TLBX_E_GENERICINST_SIGNATURE EMAKEHR(0x117d)
+#define TLBX_E_GENERICPAR_SIGNATURE EMAKEHR(0x117e)
+#define META_E_DUPLICATE EMAKEHR(0x1180)
+#define META_E_GUID_REQUIRED EMAKEHR(0x1181)
+#define META_E_TYPEDEF_MISMATCH EMAKEHR(0x1182)
+#define META_E_MERGE_COLLISION EMAKEHR(0x1183)
+#define TLBX_E_NO_SAFEHANDLE_ARRAYS EMAKEHR(0x1186)
+#define META_E_METHD_NOT_FOUND EMAKEHR(0x1187)
+#define META_E_FIELD_NOT_FOUND EMAKEHR(0x1188)
+#define META_E_PARAM_MISMATCH EMAKEHR(0x1189)
+#define META_E_BADMETADATA EMAKEHR(0x118a)
+#define META_E_INTFCEIMPL_NOT_FOUND EMAKEHR(0x118b)
+#define TLBX_E_NO_CRITICALHANDLE_ARRAYS EMAKEHR(0x118c)
+#define META_E_CLASS_LAYOUT_INCONSISTENT EMAKEHR(0x118d)
+#define META_E_FIELD_MARSHAL_NOT_FOUND EMAKEHR(0x118e)
+#define META_E_METHODSEM_NOT_FOUND EMAKEHR(0x118f)
+#define META_E_EVENT_NOT_FOUND EMAKEHR(0x1190)
+#define META_E_PROP_NOT_FOUND EMAKEHR(0x1191)
+#define META_E_BAD_SIGNATURE EMAKEHR(0x1192)
+#define META_E_BAD_INPUT_PARAMETER EMAKEHR(0x1193)
+#define META_E_METHDIMPL_INCONSISTENT EMAKEHR(0x1194)
+#define META_E_MD_INCONSISTENCY EMAKEHR(0x1195)
+#define META_E_CANNOTRESOLVETYPEREF EMAKEHR(0x1196)
+#define META_E_STRINGSPACE_FULL EMAKEHR(0x1198)
+#define META_E_UNEXPECTED_REMAP EMAKEHR(0x1199)
+#define META_E_HAS_UNMARKALL EMAKEHR(0x119a)
+#define META_E_MUST_CALL_UNMARKALL EMAKEHR(0x119b)
+#define META_E_GENERICPARAM_INCONSISTENT EMAKEHR(0x119c)
+#define META_E_EVENT_COUNTS EMAKEHR(0x119d)
+#define META_E_PROPERTY_COUNTS EMAKEHR(0x119e)
+#define META_E_TYPEDEF_MISSING EMAKEHR(0x119f)
+#define TLBX_E_CANT_LOAD_MODULE EMAKEHR(0x11a0)
+#define TLBX_E_CANT_LOAD_CLASS EMAKEHR(0x11a1)
+#define TLBX_E_NULL_MODULE EMAKEHR(0x11a2)
+#define TLBX_E_NO_CLSID_KEY EMAKEHR(0x11a3)
+#define TLBX_E_CIRCULAR_EXPORT EMAKEHR(0x11a4)
+#define TLBX_E_CIRCULAR_IMPORT EMAKEHR(0x11a5)
+#define TLBX_E_BAD_NATIVETYPE EMAKEHR(0x11a6)
+#define TLBX_E_BAD_VTABLE EMAKEHR(0x11a7)
+#define TLBX_E_CRM_NON_STATIC EMAKEHR(0x11a8)
+#define TLBX_E_CRM_INVALID_SIG EMAKEHR(0x11a9)
+#define TLBX_E_CLASS_LOAD_EXCEPTION EMAKEHR(0x11aa)
+#define TLBX_E_UNKNOWN_SIGNATURE EMAKEHR(0x11ab)
+#define TLBX_E_REFERENCED_TYPELIB EMAKEHR(0x11ac)
+#define TLBX_E_INVALID_NAMESPACE EMAKEHR(0x11ad)
+#define TLBX_E_LAYOUT_ERROR EMAKEHR(0x11ae)
+#define TLBX_E_NOTIUNKNOWN EMAKEHR(0x11af)
+#define TLBX_E_NONVISIBLEVALUECLASS EMAKEHR(0x11b0)
+#define TLBX_E_LPTSTR_NOT_ALLOWED EMAKEHR(0x11b1)
+#define TLBX_E_AUTO_CS_NOT_ALLOWED EMAKEHR(0x11b2)
+#define TLBX_E_ENUM_VALUE_INVALID EMAKEHR(0x11b5)
+#define TLBX_E_DUPLICATE_IID EMAKEHR(0x11b6)
+#define TLBX_E_NO_NESTED_ARRAYS EMAKEHR(0x11b7)
+#define TLBX_E_PARAM_ERROR_NAMED EMAKEHR(0x11b8)
+#define TLBX_E_PARAM_ERROR_UNNAMED EMAKEHR(0x11b9)
+#define TLBX_E_AGNOST_SIGNATURE EMAKEHR(0x11ba)
+#define TLBX_E_CONVERT_FAIL EMAKEHR(0x11bb)
+#define TLBX_W_DUAL_NOT_DISPATCH EMAKEHR(0x11bc)
+#define TLBX_E_BAD_SIGNATURE EMAKEHR(0x11bd)
+#define TLBX_E_ARRAY_NEEDS_NT_FIXED EMAKEHR(0x11be)
+#define TLBX_E_CLASS_NEEDS_NT_INTF EMAKEHR(0x11bf)
+#define META_E_CA_INVALID_TARGET EMAKEHR(0x11c0)
+#define META_E_CA_INVALID_VALUE EMAKEHR(0x11c1)
+#define META_E_CA_INVALID_BLOB EMAKEHR(0x11c2)
+#define META_E_CA_REPEATED_ARG EMAKEHR(0x11c3)
+#define META_E_CA_UNKNOWN_ARGUMENT EMAKEHR(0x11c4)
+#define META_E_CA_VARIANT_NYI EMAKEHR(0x11c5)
+#define META_E_CA_ARRAY_NYI EMAKEHR(0x11c6)
+#define META_E_CA_UNEXPECTED_TYPE EMAKEHR(0x11c7)
+#define META_E_CA_INVALID_ARGTYPE EMAKEHR(0x11c8)
+#define META_E_CA_INVALID_ARG_FOR_TYPE EMAKEHR(0x11c9)
+#define META_E_CA_INVALID_UUID EMAKEHR(0x11ca)
+#define META_E_CA_INVALID_MARSHALAS_FIELDS EMAKEHR(0x11cb)
+#define META_E_CA_NT_FIELDONLY EMAKEHR(0x11cc)
+#define META_E_CA_NEGATIVE_PARAMINDEX EMAKEHR(0x11cd)
+#define META_E_CA_NEGATIVE_MULTIPLIER EMAKEHR(0x11ce)
+#define META_E_CA_NEGATIVE_CONSTSIZE EMAKEHR(0x11cf)
+#define META_E_CA_FIXEDSTR_SIZE_REQUIRED EMAKEHR(0x11d0)
+#define META_E_CA_CUSTMARSH_TYPE_REQUIRED EMAKEHR(0x11d1)
+#define META_E_CA_FILENAME_REQUIRED EMAKEHR(0x11d2)
+#define TLBX_W_NO_PROPS_IN_EVENTS EMAKEHR(0x11d3)
+#define META_E_NOT_IN_ENC_MODE EMAKEHR(0x11d4)
+#define META_E_METHOD_COUNTS EMAKEHR(0x11d6)
+#define META_E_FIELD_COUNTS EMAKEHR(0x11d7)
+#define META_E_PARAM_COUNTS EMAKEHR(0x11d8)
+#define TLBX_E_TYPED_REF EMAKEHR(0x11da)
+#define TLBX_E_BITNESS_MISMATCH EMAKEHR(0x11e1)
+#define TLBX_E_EVENT_WITH_NEWENUM EMAKEHR(0x11e2)
+#define TLBX_E_PROPGET_WITHOUT_RETURN EMAKEHR(0x11e3)
+#define META_E_MISMATCHED_VISIBLITY EMAKEHR(0x11e4)
+#define META_E_CA_BAD_FRIENDS_ARGS EMAKEHR(0x11e5)
+#define META_E_CA_FRIENDS_SN_REQUIRED EMAKEHR(0x11e6)
+#define VLDTR_E_RID_OUTOFRANGE EMAKEHR(0x1203)
+#define VLDTR_E_CDTKN_OUTOFRANGE EMAKEHR(0x1204)
+#define VLDTR_E_CDRID_OUTOFRANGE EMAKEHR(0x1205)
+#define VLDTR_E_STRING_INVALID EMAKEHR(0x1206)
+#define VLDTR_E_GUID_INVALID EMAKEHR(0x1207)
+#define VLDTR_E_BLOB_INVALID EMAKEHR(0x1208)
+#define VLDTR_E_MOD_MULTI EMAKEHR(0x1209)
+#define VLDTR_E_MOD_NULLMVID EMAKEHR(0x120a)
+#define VLDTR_E_TR_NAMENULL EMAKEHR(0x120b)
+#define VLDTR_E_TR_DUP EMAKEHR(0x120c)
+#define VLDTR_E_TD_NAMENULL EMAKEHR(0x120d)
+#define VLDTR_E_TD_DUPNAME EMAKEHR(0x120e)
+#define VLDTR_E_TD_DUPGUID EMAKEHR(0x120f)
+#define VLDTR_E_TD_NOTIFACEOBJEXTNULL EMAKEHR(0x1210)
+#define VLDTR_E_TD_OBJEXTENDSNONNULL EMAKEHR(0x1211)
+#define VLDTR_E_TD_EXTENDSSEALED EMAKEHR(0x1212)
+#define VLDTR_E_TD_DLTNORTSPCL EMAKEHR(0x1213)
+#define VLDTR_E_TD_RTSPCLNOTDLT EMAKEHR(0x1214)
+#define VLDTR_E_MI_DECLPRIV EMAKEHR(0x1215)
+#define VLDTR_E_AS_BADNAME EMAKEHR(0x1216)
+#define VLDTR_E_FILE_SYSNAME EMAKEHR(0x1217)
+#define VLDTR_E_MI_BODYSTATIC EMAKEHR(0x1218)
+#define VLDTR_E_TD_IFACENOTABS EMAKEHR(0x1219)
+#define VLDTR_E_TD_IFACEPARNOTNIL EMAKEHR(0x121a)
+#define VLDTR_E_TD_IFACEGUIDNULL EMAKEHR(0x121b)
+#define VLDTR_E_MI_DECLFINAL EMAKEHR(0x121c)
+#define VLDTR_E_TD_VTNOTSEAL EMAKEHR(0x121d)
+#define VLDTR_E_PD_BADFLAGS EMAKEHR(0x121e)
+#define VLDTR_E_IFACE_DUP EMAKEHR(0x121f)
+#define VLDTR_E_MR_NAMENULL EMAKEHR(0x1220)
+#define VLDTR_E_MR_VTBLNAME EMAKEHR(0x1221)
+#define VLDTR_E_MR_DELNAME EMAKEHR(0x1222)
+#define VLDTR_E_MR_PARNIL EMAKEHR(0x1223)
+#define VLDTR_E_MR_BADCALLINGCONV EMAKEHR(0x1224)
+#define VLDTR_E_MR_NOTVARARG EMAKEHR(0x1225)
+#define VLDTR_E_MR_NAMEDIFF EMAKEHR(0x1226)
+#define VLDTR_E_MR_SIGDIFF EMAKEHR(0x1227)
+#define VLDTR_E_MR_DUP EMAKEHR(0x1228)
+#define VLDTR_E_CL_TDAUTO EMAKEHR(0x1229)
+#define VLDTR_E_CL_BADPCKSZ EMAKEHR(0x122a)
+#define VLDTR_E_CL_DUP EMAKEHR(0x122b)
+#define VLDTR_E_FL_BADOFFSET EMAKEHR(0x122c)
+#define VLDTR_E_FL_TDNIL EMAKEHR(0x122d)
+#define VLDTR_E_FL_NOCL EMAKEHR(0x122e)
+#define VLDTR_E_FL_TDNOTEXPLCT EMAKEHR(0x122f)
+#define VLDTR_E_FL_FLDSTATIC EMAKEHR(0x1230)
+#define VLDTR_E_FL_DUP EMAKEHR(0x1231)
+#define VLDTR_E_MODREF_NAMENULL EMAKEHR(0x1232)
+#define VLDTR_E_MODREF_DUP EMAKEHR(0x1233)
+#define VLDTR_E_TR_BADSCOPE EMAKEHR(0x1234)
+#define VLDTR_E_TD_NESTEDNOENCL EMAKEHR(0x1235)
+#define VLDTR_E_TD_EXTTRRES EMAKEHR(0x1236)
+#define VLDTR_E_SIGNULL EMAKEHR(0x1237)
+#define VLDTR_E_SIGNODATA EMAKEHR(0x1238)
+#define VLDTR_E_MD_BADCALLINGCONV EMAKEHR(0x1239)
+#define VLDTR_E_MD_THISSTATIC EMAKEHR(0x123a)
+#define VLDTR_E_MD_NOTTHISNOTSTATIC EMAKEHR(0x123b)
+#define VLDTR_E_MD_NOARGCNT EMAKEHR(0x123c)
+#define VLDTR_E_SIG_MISSELTYPE EMAKEHR(0x123d)
+#define VLDTR_E_SIG_MISSTKN EMAKEHR(0x123e)
+#define VLDTR_E_SIG_TKNBAD EMAKEHR(0x123f)
+#define VLDTR_E_SIG_MISSFPTR EMAKEHR(0x1240)
+#define VLDTR_E_SIG_MISSFPTRARGCNT EMAKEHR(0x1241)
+#define VLDTR_E_SIG_MISSRANK EMAKEHR(0x1242)
+#define VLDTR_E_SIG_MISSNSIZE EMAKEHR(0x1243)
+#define VLDTR_E_SIG_MISSSIZE EMAKEHR(0x1244)
+#define VLDTR_E_SIG_MISSNLBND EMAKEHR(0x1245)
+#define VLDTR_E_SIG_MISSLBND EMAKEHR(0x1246)
+#define VLDTR_E_SIG_BADELTYPE EMAKEHR(0x1247)
+#define VLDTR_E_SIG_MISSVASIZE EMAKEHR(0x1248)
+#define VLDTR_E_FD_BADCALLINGCONV EMAKEHR(0x1249)
+#define VLDTR_E_MD_NAMENULL EMAKEHR(0x124a)
+#define VLDTR_E_MD_PARNIL EMAKEHR(0x124b)
+#define VLDTR_E_MD_DUP EMAKEHR(0x124c)
+#define VLDTR_E_FD_NAMENULL EMAKEHR(0x124d)
+#define VLDTR_E_FD_PARNIL EMAKEHR(0x124e)
+#define VLDTR_E_FD_DUP EMAKEHR(0x124f)
+#define VLDTR_E_AS_MULTI EMAKEHR(0x1250)
+#define VLDTR_E_AS_NAMENULL EMAKEHR(0x1251)
+#define VLDTR_E_SIG_TOKTYPEMISMATCH EMAKEHR(0x1252)
+#define VLDTR_E_CL_TDINTF EMAKEHR(0x1253)
+#define VLDTR_E_ASOS_OSPLTFRMIDINVAL EMAKEHR(0x1254)
+#define VLDTR_E_AR_NAMENULL EMAKEHR(0x1255)
+#define VLDTR_E_TD_ENCLNOTNESTED EMAKEHR(0x1256)
+#define VLDTR_E_AROS_OSPLTFRMIDINVAL EMAKEHR(0x1257)
+#define VLDTR_E_FILE_NAMENULL EMAKEHR(0x1258)
+#define VLDTR_E_CT_NAMENULL EMAKEHR(0x1259)
+#define VLDTR_E_TD_EXTENDSCHILD EMAKEHR(0x125a)
+#define VLDTR_E_MAR_NAMENULL EMAKEHR(0x125b)
+#define VLDTR_E_FILE_DUP EMAKEHR(0x125c)
+#define VLDTR_E_FILE_NAMEFULLQLFD EMAKEHR(0x125d)
+#define VLDTR_E_CT_DUP EMAKEHR(0x125e)
+#define VLDTR_E_MAR_DUP EMAKEHR(0x125f)
+#define VLDTR_E_MAR_NOTPUBPRIV EMAKEHR(0x1260)
+#define VLDTR_E_TD_ENUMNOVALUE EMAKEHR(0x1261)
+#define VLDTR_E_TD_ENUMVALSTATIC EMAKEHR(0x1262)
+#define VLDTR_E_TD_ENUMVALNOTSN EMAKEHR(0x1263)
+#define VLDTR_E_TD_ENUMFLDNOTST EMAKEHR(0x1264)
+#define VLDTR_E_TD_ENUMFLDNOTLIT EMAKEHR(0x1265)
+#define VLDTR_E_TD_ENUMNOLITFLDS EMAKEHR(0x1266)
+#define VLDTR_E_TD_ENUMFLDSIGMISMATCH EMAKEHR(0x1267)
+#define VLDTR_E_TD_ENUMVALNOT1ST EMAKEHR(0x1268)
+#define VLDTR_E_FD_NOTVALUERTSN EMAKEHR(0x1269)
+#define VLDTR_E_FD_VALUEPARNOTENUM EMAKEHR(0x126a)
+#define VLDTR_E_FD_INSTINIFACE EMAKEHR(0x126b)
+#define VLDTR_E_FD_NOTPUBINIFACE EMAKEHR(0x126c)
+#define VLDTR_E_FMD_GLOBALNOTPUBPRIVSC EMAKEHR(0x126d)
+#define VLDTR_E_FMD_GLOBALNOTSTATIC EMAKEHR(0x126e)
+#define VLDTR_E_FD_GLOBALNORVA EMAKEHR(0x126f)
+#define VLDTR_E_MD_CTORZERORVA EMAKEHR(0x1270)
+#define VLDTR_E_FD_MARKEDNOMARSHAL EMAKEHR(0x1271)
+#define VLDTR_E_FD_MARSHALNOTMARKED EMAKEHR(0x1272)
+#define VLDTR_E_FD_MARKEDNODEFLT EMAKEHR(0x1273)
+#define VLDTR_E_FD_DEFLTNOTMARKED EMAKEHR(0x1274)
+#define VLDTR_E_FMD_MARKEDNOSECUR EMAKEHR(0x1275)
+#define VLDTR_E_FMD_SECURNOTMARKED EMAKEHR(0x1276)
+#define VLDTR_E_FMD_PINVOKENOTSTATIC EMAKEHR(0x1277)
+#define VLDTR_E_FMD_MARKEDNOPINVOKE EMAKEHR(0x1278)
+#define VLDTR_E_FMD_PINVOKENOTMARKED EMAKEHR(0x1279)
+#define VLDTR_E_FMD_BADIMPLMAP EMAKEHR(0x127a)
+#define VLDTR_E_IMAP_BADMODREF EMAKEHR(0x127b)
+#define VLDTR_E_IMAP_BADMEMBER EMAKEHR(0x127c)
+#define VLDTR_E_IMAP_BADIMPORTNAME EMAKEHR(0x127d)
+#define VLDTR_E_IMAP_BADCALLCONV EMAKEHR(0x127e)
+#define VLDTR_E_FMD_BADACCESSFLAG EMAKEHR(0x127f)
+#define VLDTR_E_FD_INITONLYANDLITERAL EMAKEHR(0x1280)
+#define VLDTR_E_FD_LITERALNOTSTATIC EMAKEHR(0x1281)
+#define VLDTR_E_FMD_RTSNNOTSN EMAKEHR(0x1282)
+#define VLDTR_E_MD_ABSTPARNOTABST EMAKEHR(0x1283)
+#define VLDTR_E_MD_NOTSTATABSTININTF EMAKEHR(0x1284)
+#define VLDTR_E_MD_NOTPUBININTF EMAKEHR(0x1285)
+#define VLDTR_E_MD_CTORININTF EMAKEHR(0x1286)
+#define VLDTR_E_MD_GLOBALCTORCCTOR EMAKEHR(0x1287)
+#define VLDTR_E_MD_CTORSTATIC EMAKEHR(0x1288)
+#define VLDTR_E_MD_CTORNOTSNRTSN EMAKEHR(0x1289)
+#define VLDTR_E_MD_CTORVIRT EMAKEHR(0x128a)
+#define VLDTR_E_MD_CTORABST EMAKEHR(0x128b)
+#define VLDTR_E_MD_CCTORNOTSTATIC EMAKEHR(0x128c)
+#define VLDTR_E_MD_ZERORVA EMAKEHR(0x128d)
+#define VLDTR_E_MD_FINNOTVIRT EMAKEHR(0x128e)
+#define VLDTR_E_MD_STATANDFINORVIRT EMAKEHR(0x128f)
+#define VLDTR_E_MD_ABSTANDFINAL EMAKEHR(0x1290)
+#define VLDTR_E_MD_ABSTANDIMPL EMAKEHR(0x1291)
+#define VLDTR_E_MD_ABSTANDPINVOKE EMAKEHR(0x1292)
+#define VLDTR_E_MD_ABSTNOTVIRT EMAKEHR(0x1293)
+#define VLDTR_E_MD_NOTABSTNOTIMPL EMAKEHR(0x1294)
+#define VLDTR_E_MD_NOTABSTBADFLAGSRVA EMAKEHR(0x1295)
+#define VLDTR_E_MD_PRIVSCOPENORVA EMAKEHR(0x1296)
+#define VLDTR_E_MD_GLOBALABSTORVIRT EMAKEHR(0x1297)
+#define VLDTR_E_SIG_LONGFORM EMAKEHR(0x1298)
+#define VLDTR_E_MD_MULTIPLESEMANTICS EMAKEHR(0x1299)
+#define VLDTR_E_MD_INVALIDSEMANTICS EMAKEHR(0x129a)
+#define VLDTR_E_MD_SEMANTICSNOTEXIST EMAKEHR(0x129b)
+#define VLDTR_E_MI_DECLNOTVIRT EMAKEHR(0x129c)
+#define VLDTR_E_FMD_GLOBALITEM EMAKEHR(0x129d)
+#define VLDTR_E_MD_MULTSEMANTICFLAGS EMAKEHR(0x129e)
+#define VLDTR_E_MD_NOSEMANTICFLAGS EMAKEHR(0x129f)
+#define VLDTR_E_FD_FLDINIFACE EMAKEHR(0x12a0)
+#define VLDTR_E_AS_HASHALGID EMAKEHR(0x12a1)
+#define VLDTR_E_AS_PROCID EMAKEHR(0x12a2)
+#define VLDTR_E_AR_PROCID EMAKEHR(0x12a3)
+#define VLDTR_E_CN_PARENTRANGE EMAKEHR(0x12a4)
+#define VLDTR_E_AS_BADFLAGS EMAKEHR(0x12a5)
+#define VLDTR_E_TR_HASTYPEDEF EMAKEHR(0x12a6)
+#define VLDTR_E_IFACE_BADIMPL EMAKEHR(0x12a7)
+#define VLDTR_E_IFACE_BADIFACE EMAKEHR(0x12a8)
+#define VLDTR_E_TD_SECURNOTMARKED EMAKEHR(0x12a9)
+#define VLDTR_E_TD_MARKEDNOSECUR EMAKEHR(0x12aa)
+#define VLDTR_E_MD_CCTORHASARGS EMAKEHR(0x12ab)
+#define VLDTR_E_CT_BADIMPL EMAKEHR(0x12ac)
+#define VLDTR_E_MI_ALIENBODY EMAKEHR(0x12ad)
+#define VLDTR_E_MD_CCTORCALLCONV EMAKEHR(0x12ae)
+#define VLDTR_E_MI_BADCLASS EMAKEHR(0x12af)
+#define VLDTR_E_MI_CLASSISINTF EMAKEHR(0x12b0)
+#define VLDTR_E_MI_BADDECL EMAKEHR(0x12b1)
+#define VLDTR_E_MI_BADBODY EMAKEHR(0x12b2)
+#define VLDTR_E_MI_DUP EMAKEHR(0x12b3)
+#define VLDTR_E_FD_BADPARENT EMAKEHR(0x12b4)
+#define VLDTR_E_MD_PARAMOUTOFSEQ EMAKEHR(0x12b5)
+#define VLDTR_E_MD_PARASEQTOOBIG EMAKEHR(0x12b6)
+#define VLDTR_E_MD_PARMMARKEDNOMARSHAL EMAKEHR(0x12b7)
+#define VLDTR_E_MD_PARMMARSHALNOTMARKED EMAKEHR(0x12b8)
+#define VLDTR_E_MD_PARMMARKEDNODEFLT EMAKEHR(0x12ba)
+#define VLDTR_E_MD_PARMDEFLTNOTMARKED EMAKEHR(0x12bb)
+#define VLDTR_E_PR_BADSCOPE EMAKEHR(0x12bc)
+#define VLDTR_E_PR_NONAME EMAKEHR(0x12bd)
+#define VLDTR_E_PR_NOSIG EMAKEHR(0x12be)
+#define VLDTR_E_PR_DUP EMAKEHR(0x12bf)
+#define VLDTR_E_PR_BADCALLINGCONV EMAKEHR(0x12c0)
+#define VLDTR_E_PR_MARKEDNODEFLT EMAKEHR(0x12c1)
+#define VLDTR_E_PR_DEFLTNOTMARKED EMAKEHR(0x12c2)
+#define VLDTR_E_PR_BADSEMANTICS EMAKEHR(0x12c3)
+#define VLDTR_E_PR_BADMETHOD EMAKEHR(0x12c4)
+#define VLDTR_E_PR_ALIENMETHOD EMAKEHR(0x12c5)
+#define VLDTR_E_CN_BLOBNOTNULL EMAKEHR(0x12c6)
+#define VLDTR_E_CN_BLOBNULL EMAKEHR(0x12c7)
+#define VLDTR_E_EV_BADSCOPE EMAKEHR(0x12c8)
+#define VLDTR_E_EV_NONAME EMAKEHR(0x12ca)
+#define VLDTR_E_EV_DUP EMAKEHR(0x12cb)
+#define VLDTR_E_EV_BADEVTYPE EMAKEHR(0x12cc)
+#define VLDTR_E_EV_EVTYPENOTCLASS EMAKEHR(0x12cd)
+#define VLDTR_E_EV_BADSEMANTICS EMAKEHR(0x12ce)
+#define VLDTR_E_EV_BADMETHOD EMAKEHR(0x12cf)
+#define VLDTR_E_EV_ALIENMETHOD EMAKEHR(0x12d0)
+#define VLDTR_E_EV_NOADDON EMAKEHR(0x12d1)
+#define VLDTR_E_EV_NOREMOVEON EMAKEHR(0x12d2)
+#define VLDTR_E_CT_DUPTDNAME EMAKEHR(0x12d3)
+#define VLDTR_E_MAR_BADOFFSET EMAKEHR(0x12d4)
+#define VLDTR_E_DS_BADOWNER EMAKEHR(0x12d5)
+#define VLDTR_E_DS_BADFLAGS EMAKEHR(0x12d6)
+#define VLDTR_E_DS_NOBLOB EMAKEHR(0x12d7)
+#define VLDTR_E_MAR_BADIMPL EMAKEHR(0x12d8)
+#define VLDTR_E_MR_VARARGCALLINGCONV EMAKEHR(0x12da)
+#define VLDTR_E_MD_CTORNOTVOID EMAKEHR(0x12db)
+#define VLDTR_E_EV_FIRENOTVOID EMAKEHR(0x12dc)
+#define VLDTR_E_AS_BADLOCALE EMAKEHR(0x12dd)
+#define VLDTR_E_CN_PARENTTYPE EMAKEHR(0x12de)
+#define VLDTR_E_SIG_SENTINMETHODDEF EMAKEHR(0x12df)
+#define VLDTR_E_SIG_SENTMUSTVARARG EMAKEHR(0x12e0)
+#define VLDTR_E_SIG_MULTSENTINELS EMAKEHR(0x12e1)
+#define VLDTR_E_SIG_LASTSENTINEL EMAKEHR(0x12e2)
+#define VLDTR_E_SIG_MISSARG EMAKEHR(0x12e3)
+#define VLDTR_E_SIG_BYREFINFIELD EMAKEHR(0x12e4)
+#define VLDTR_E_MD_SYNCMETHODINVTYPE EMAKEHR(0x12e5)
+#define VLDTR_E_TD_NAMETOOLONG EMAKEHR(0x12e6)
+#define VLDTR_E_AS_PROCDUP EMAKEHR(0x12e7)
+#define VLDTR_E_ASOS_DUP EMAKEHR(0x12e8)
+#define VLDTR_E_MAR_BADFLAGS EMAKEHR(0x12e9)
+#define VLDTR_E_CT_NOTYPEDEFID EMAKEHR(0x12ea)
+#define VLDTR_E_FILE_BADFLAGS EMAKEHR(0x12eb)
+#define VLDTR_E_FILE_NULLHASH EMAKEHR(0x12ec)
+#define VLDTR_E_MOD_NONAME EMAKEHR(0x12ed)
+#define VLDTR_E_MOD_NAMEFULLQLFD EMAKEHR(0x12ee)
+#define VLDTR_E_TD_RTSPCLNOTSPCL EMAKEHR(0x12ef)
+#define VLDTR_E_TD_EXTENDSIFACE EMAKEHR(0x12f0)
+#define VLDTR_E_MD_CTORPINVOKE EMAKEHR(0x12f1)
+#define VLDTR_E_TD_SYSENUMNOTCLASS EMAKEHR(0x12f2)
+#define VLDTR_E_TD_SYSENUMNOTEXTVTYPE EMAKEHR(0x12f3)
+#define VLDTR_E_MI_SIGMISMATCH EMAKEHR(0x12f4)
+#define VLDTR_E_TD_ENUMHASMETHODS EMAKEHR(0x12f5)
+#define VLDTR_E_TD_ENUMIMPLIFACE EMAKEHR(0x12f6)
+#define VLDTR_E_TD_ENUMHASPROP EMAKEHR(0x12f7)
+#define VLDTR_E_TD_ENUMHASEVENT EMAKEHR(0x12f8)
+#define VLDTR_E_TD_BADMETHODLST EMAKEHR(0x12f9)
+#define VLDTR_E_TD_BADFIELDLST EMAKEHR(0x12fa)
+#define VLDTR_E_CN_BADTYPE EMAKEHR(0x12fb)
+#define VLDTR_E_TD_ENUMNOINSTFLD EMAKEHR(0x12fc)
+#define VLDTR_E_TD_ENUMMULINSTFLD EMAKEHR(0x12fd)
+#define VLDTR_E_INTERRUPTED EMAKEHR(0x12fe)
+#define VLDTR_E_NOTINIT EMAKEHR(0x12ff)
+#define CORDBG_E_UNRECOVERABLE_ERROR EMAKEHR(0x1300)
+#define CORDBG_E_PROCESS_TERMINATED EMAKEHR(0x1301)
+#define CORDBG_E_PROCESS_NOT_SYNCHRONIZED EMAKEHR(0x1302)
+#define CORDBG_E_CLASS_NOT_LOADED EMAKEHR(0x1303)
+#define CORDBG_E_IL_VAR_NOT_AVAILABLE EMAKEHR(0x1304)
+#define CORDBG_E_BAD_REFERENCE_VALUE EMAKEHR(0x1305)
+#define CORDBG_E_FIELD_NOT_AVAILABLE EMAKEHR(0x1306)
+#define CORDBG_E_NON_NATIVE_FRAME EMAKEHR(0x1307)
+#define CORDBG_E_NONCONTINUABLE_EXCEPTION EMAKEHR(0x1308)
+#define CORDBG_E_CODE_NOT_AVAILABLE EMAKEHR(0x1309)
+#define CORDBG_E_FUNCTION_NOT_IL EMAKEHR(0x130a)
+#define CORDBG_E_CANT_SET_IP_INTO_FINALLY EMAKEHR(0x130e)
+#define CORDBG_E_CANT_SET_IP_OUT_OF_FINALLY EMAKEHR(0x130f)
+#define CORDBG_E_CANT_SET_IP_INTO_CATCH EMAKEHR(0x1310)
+#define CORDBG_E_SET_IP_NOT_ALLOWED_ON_NONLEAF_FRAME EMAKEHR(0x1311)
+#define CORDBG_E_SET_IP_IMPOSSIBLE EMAKEHR(0x1312)
+#define CORDBG_E_FUNC_EVAL_BAD_START_POINT EMAKEHR(0x1313)
+#define CORDBG_E_INVALID_OBJECT EMAKEHR(0x1314)
+#define CORDBG_E_FUNC_EVAL_NOT_COMPLETE EMAKEHR(0x1315)
+#define CORDBG_E_INPROC_NOT_IMPL EMAKEHR(0x1318)
+#define CORDBG_E_STATIC_VAR_NOT_AVAILABLE EMAKEHR(0x131a)
+#define CORDBG_E_OBJECT_IS_NOT_COPYABLE_VALUE_CLASS EMAKEHR(0x131b)
+#define CORDBG_E_CANT_SETIP_INTO_OR_OUT_OF_FILTER EMAKEHR(0x131c)
+#define CORDBG_E_CANT_CHANGE_JIT_SETTING_FOR_ZAP_MODULE EMAKEHR(0x131d)
+#define CORDBG_E_CANT_SET_IP_OUT_OF_FINALLY_ON_WIN64 EMAKEHR(0x131e)
+#define CORDBG_E_CANT_SET_IP_OUT_OF_CATCH_ON_WIN64 EMAKEHR(0x131f)
+#define CORDBG_E_REMOTE_CONNECTION_CONN_RESET EMAKEHR(0x1320)
+#define CORDBG_E_REMOTE_CONNECTION_KEEP_ALIVE EMAKEHR(0x1321)
+#define CORDBG_E_REMOTE_CONNECTION_FATAL_ERROR EMAKEHR(0x1322)
+#define CORDBG_E_CANT_SET_TO_JMC EMAKEHR(0x1323)
+#define CORDBG_E_NO_CONTEXT_FOR_INTERNAL_FRAME EMAKEHR(0x1325)
+#define CORDBG_E_NOT_CHILD_FRAME EMAKEHR(0x1326)
+#define CORDBG_E_NON_MATCHING_CONTEXT EMAKEHR(0x1327)
+#define CORDBG_E_PAST_END_OF_STACK EMAKEHR(0x1328)
+#define CORDBG_E_FUNC_EVAL_CANNOT_UPDATE_REGISTER_IN_NONLEAF_FRAME EMAKEHR(0x1329)
+#define CORDBG_E_BAD_THREAD_STATE EMAKEHR(0x132d)
+#define CORDBG_E_DEBUGGER_ALREADY_ATTACHED EMAKEHR(0x132e)
+#define CORDBG_E_SUPERFLOUS_CONTINUE EMAKEHR(0x132f)
+#define CORDBG_E_SET_VALUE_NOT_ALLOWED_ON_NONLEAF_FRAME EMAKEHR(0x1330)
+#define CORDBG_E_ENC_EH_MAX_NESTING_LEVEL_CANT_INCREASE EMAKEHR(0x1331)
+#define CORDBG_E_ENC_MODULE_NOT_ENC_ENABLED EMAKEHR(0x1332)
+#define CORDBG_E_SET_IP_NOT_ALLOWED_ON_EXCEPTION EMAKEHR(0x1333)
+#define CORDBG_E_VARIABLE_IS_ACTUALLY_LITERAL EMAKEHR(0x1334)
+#define CORDBG_E_PROCESS_DETACHED EMAKEHR(0x1335)
+#define CORDBG_E_ENC_METHOD_SIG_CHANGED EMAKEHR(0x1336)
+#define CORDBG_E_ENC_METHOD_NO_LOCAL_SIG EMAKEHR(0x1337)
+#define CORDBG_E_ENC_CANT_ADD_FIELD_TO_VALUE_OR_LAYOUT_CLASS EMAKEHR(0x1338)
+#define CORDBG_E_ENC_CANT_CHANGE_FIELD EMAKEHR(0x1339)
+#define CORDBG_E_ENC_CANT_ADD_NON_PRIVATE_MEMBER EMAKEHR(0x133a)
+#define CORDBG_E_FIELD_NOT_STATIC EMAKEHR(0x133b)
+#define CORDBG_E_FIELD_NOT_INSTANCE EMAKEHR(0x133c)
+#define CORDBG_E_ENC_ZAPPED_WITHOUT_ENC EMAKEHR(0x133d)
+#define CORDBG_E_ENC_BAD_METHOD_INFO EMAKEHR(0x133e)
+#define CORDBG_E_ENC_JIT_CANT_UPDATE EMAKEHR(0x133f)
+#define CORDBG_E_ENC_MISSING_CLASS EMAKEHR(0x1340)
+#define CORDBG_E_ENC_INTERNAL_ERROR EMAKEHR(0x1341)
+#define CORDBG_E_ENC_HANGING_FIELD EMAKEHR(0x1342)
+#define CORDBG_E_MODULE_NOT_LOADED EMAKEHR(0x1343)
+#define CORDBG_E_ENC_CANT_CHANGE_SUPERCLASS EMAKEHR(0x1344)
+#define CORDBG_E_UNABLE_TO_SET_BREAKPOINT EMAKEHR(0x1345)
+#define CORDBG_E_DEBUGGING_NOT_POSSIBLE EMAKEHR(0x1346)
+#define CORDBG_E_KERNEL_DEBUGGER_ENABLED EMAKEHR(0x1347)
+#define CORDBG_E_KERNEL_DEBUGGER_PRESENT EMAKEHR(0x1348)
+#define CORDBG_E_HELPER_THREAD_DEAD EMAKEHR(0x1349)
+#define CORDBG_E_INTERFACE_INHERITANCE_CANT_CHANGE EMAKEHR(0x134a)
+#define CORDBG_E_INCOMPATIBLE_PROTOCOL EMAKEHR(0x134b)
+#define CORDBG_E_TOO_MANY_PROCESSES EMAKEHR(0x134c)
+#define CORDBG_E_INTEROP_NOT_SUPPORTED EMAKEHR(0x134d)
+#define CORDBG_E_NO_REMAP_BREAKPIONT EMAKEHR(0x134e)
+#define CORDBG_E_OBJECT_NEUTERED EMAKEHR(0x134f)
+#define CORPROF_E_FUNCTION_NOT_COMPILED EMAKEHR(0x1350)
+#define CORPROF_E_DATAINCOMPLETE EMAKEHR(0x1351)
+#define CORPROF_E_NOT_REJITABLE_METHODS EMAKEHR(0x1352)
+#define CORPROF_E_CANNOT_UPDATE_METHOD EMAKEHR(0x1353)
+#define CORPROF_E_FUNCTION_NOT_IL EMAKEHR(0x1354)
+#define CORPROF_E_NOT_MANAGED_THREAD EMAKEHR(0x1355)
+#define CORPROF_E_CALL_ONLY_FROM_INIT EMAKEHR(0x1356)
+#define CORPROF_E_INPROC_NOT_ENABLED EMAKEHR(0x1357)
+#define CORPROF_E_JITMAPS_NOT_ENABLED EMAKEHR(0x1358)
+#define CORPROF_E_INPROC_ALREADY_BEGUN EMAKEHR(0x1359)
+#define CORPROF_E_INPROC_NOT_AVAILABLE EMAKEHR(0x135a)
+#define CORPROF_E_NOT_YET_AVAILABLE EMAKEHR(0x135b)
+#define CORPROF_E_TYPE_IS_PARAMETERIZED EMAKEHR(0x135c)
+#define CORPROF_E_FUNCTION_IS_PARAMETERIZED EMAKEHR(0x135d)
+#define CORPROF_E_STACKSNAPSHOT_INVALID_TGT_THREAD EMAKEHR(0x135e)
+#define CORPROF_E_STACKSNAPSHOT_UNMANAGED_CTX EMAKEHR(0x135f)
+#define CORPROF_E_STACKSNAPSHOT_UNSAFE EMAKEHR(0x1360)
+#define CORPROF_E_STACKSNAPSHOT_ABORTED EMAKEHR(0x1361)
+#define CORPROF_E_LITERALS_HAVE_NO_ADDRESS EMAKEHR(0x1362)
+#define CORPROF_E_UNSUPPORTED_CALL_SEQUENCE EMAKEHR(0x1363)
+#define CORPROF_E_ASYNCHRONOUS_UNSAFE EMAKEHR(0x1364)
+#define CORPROF_E_CLASSID_IS_ARRAY EMAKEHR(0x1365)
+#define CORPROF_E_CLASSID_IS_COMPOSITE EMAKEHR(0x1366)
+#define CORPROF_E_PROFILER_DETACHING EMAKEHR(0x1367)
+#define CORPROF_E_PROFILER_NOT_ATTACHABLE EMAKEHR(0x1368)
+#define CORPROF_E_UNRECOGNIZED_PIPE_MSG_FORMAT EMAKEHR(0x1369)
+#define CORPROF_E_PROFILER_ALREADY_ACTIVE EMAKEHR(0x136a)
+#define CORPROF_E_PROFILEE_INCOMPATIBLE_WITH_TRIGGER EMAKEHR(0x136b)
+#define CORPROF_E_IPC_FAILED EMAKEHR(0x136c)
+#define CORPROF_E_PROFILEE_PROCESS_NOT_FOUND EMAKEHR(0x136d)
+#define CORPROF_E_CALLBACK3_REQUIRED EMAKEHR(0x136e)
+#define CORPROF_E_UNSUPPORTED_FOR_ATTACHING_PROFILER EMAKEHR(0x136f)
+#define CORPROF_E_IRREVERSIBLE_INSTRUMENTATION_PRESENT EMAKEHR(0x1370)
+#define CORPROF_E_RUNTIME_UNINITIALIZED EMAKEHR(0x1371)
+#define CORPROF_E_IMMUTABLE_FLAGS_SET EMAKEHR(0x1372)
+#define CORPROF_E_PROFILER_NOT_YET_INITIALIZED EMAKEHR(0x1373)
+#define CORPROF_E_INCONSISTENT_WITH_FLAGS EMAKEHR(0x1374)
+#define CORPROF_E_PROFILER_CANCEL_ACTIVATION EMAKEHR(0x1375)
+#define CORPROF_E_CONCURRENT_GC_NOT_PROFILABLE EMAKEHR(0x1376)
+#define CORPROF_E_INCONSISTENT_FLAGS_WITH_HOST_PROTECTION_SETTING EMAKEHR(0x1377)
+#define CORPROF_E_DEBUGGING_DISABLED EMAKEHR(0x1378)
+#define CORPROF_E_TIMEOUT_WAITING_FOR_CONCURRENT_GC EMAKEHR(0x1379)
+#define CORPROF_E_MODULE_IS_DYNAMIC EMAKEHR(0x137a)
+#define CORPROF_E_CALLBACK4_REQUIRED EMAKEHR(0x137b)
+#define CORPROF_E_REJIT_NOT_ENABLED EMAKEHR(0x137c)
+#define CORPROF_E_ACTIVE_REJIT_REQUEST_NOT_FOUND EMAKEHR(0x137d)
+#define CORPROF_E_FUNCTION_IS_COLLECTIBLE EMAKEHR(0x137e)
+#define CORPROF_E_REJIT_REQUIRES_DISABLE_NGEN EMAKEHR(0x137f)
+#define CORPROF_E_CALLBACK6_REQUIRED EMAKEHR(0x1380)
+#define CORPROF_E_CALLBACK7_REQUIRED EMAKEHR(0x1382)
+#define SECURITY_E_XML_TO_ASN_ENCODING EMAKEHR(0x1400)
+#define SECURITY_E_INCOMPATIBLE_SHARE EMAKEHR(0x1401)
+#define SECURITY_E_UNVERIFIABLE EMAKEHR(0x1402)
+#define SECURITY_E_INCOMPATIBLE_EVIDENCE EMAKEHR(0x1403)
+#define CORSEC_E_DECODE_SET EMAKEHR(0x1410)
+#define CORSEC_E_ENCODE_SET EMAKEHR(0x1411)
+#define CORSEC_E_UNSUPPORTED_FORMAT EMAKEHR(0x1412)
+#define SN_CRYPTOAPI_CALL_FAILED EMAKEHR(0x1413)
+#define CORSEC_E_CRYPTOAPI_CALL_FAILED EMAKEHR(0x1413)
+#define SN_NO_SUITABLE_CSP EMAKEHR(0x1414)
+#define CORSEC_E_NO_SUITABLE_CSP EMAKEHR(0x1414)
+#define CORSEC_E_INVALID_ATTR EMAKEHR(0x1415)
+#define CORSEC_E_POLICY_EXCEPTION EMAKEHR(0x1416)
+#define CORSEC_E_MIN_GRANT_FAIL EMAKEHR(0x1417)
+#define CORSEC_E_NO_EXEC_PERM EMAKEHR(0x1418)
+#define CORSEC_E_XMLSYNTAX EMAKEHR(0x1419)
+#define CORSEC_E_INVALID_STRONGNAME EMAKEHR(0x141a)
+#define CORSEC_E_MISSING_STRONGNAME EMAKEHR(0x141b)
+#define CORSEC_E_CONTAINER_NOT_FOUND EMAKEHR(0x141c)
+#define CORSEC_E_INVALID_IMAGE_FORMAT EMAKEHR(0x141d)
+#define CORSEC_E_INVALID_PUBLICKEY EMAKEHR(0x141e)
+#define CORSEC_E_SIGNATURE_MISMATCH EMAKEHR(0x1420)
+#define SN_E_PUBLICKEY_MISMATCH EMAKEHR(0x1421)
+#define CORSEC_E_INVALID_SIGNATUREKEY EMAKEHR(0x1422)
+#define CORSEC_E_INVALID_COUNTERSIGNATURE EMAKEHR(0x1423)
+#define CORSEC_E_CRYPTO EMAKEHR(0x1430)
+#define CORSEC_E_CRYPTO_UNEX_OPER EMAKEHR(0x1431)
+#define CORSECATTR_E_BAD_ATTRIBUTE EMAKEHR(0x143a)
+#define CORSECATTR_E_MISSING_CONSTRUCTOR EMAKEHR(0x143b)
+#define CORSECATTR_E_FAILED_TO_CREATE_PERM EMAKEHR(0x143c)
+#define CORSECATTR_E_BAD_ACTION_ASM EMAKEHR(0x143d)
+#define CORSECATTR_E_BAD_ACTION_OTHER EMAKEHR(0x143e)
+#define CORSECATTR_E_BAD_PARENT EMAKEHR(0x143f)
+#define CORSECATTR_E_TRUNCATED EMAKEHR(0x1440)
+#define CORSECATTR_E_BAD_VERSION EMAKEHR(0x1441)
+#define CORSECATTR_E_BAD_ACTION EMAKEHR(0x1442)
+#define CORSECATTR_E_NO_SELF_REF EMAKEHR(0x1443)
+#define CORSECATTR_E_BAD_NONCAS EMAKEHR(0x1444)
+#define CORSECATTR_E_ASSEMBLY_LOAD_FAILED EMAKEHR(0x1445)
+#define CORSECATTR_E_ASSEMBLY_LOAD_FAILED_EX EMAKEHR(0x1446)
+#define CORSECATTR_E_TYPE_LOAD_FAILED EMAKEHR(0x1447)
+#define CORSECATTR_E_TYPE_LOAD_FAILED_EX EMAKEHR(0x1448)
+#define CORSECATTR_E_ABSTRACT EMAKEHR(0x1449)
+#define CORSECATTR_E_UNSUPPORTED_TYPE EMAKEHR(0x144a)
+#define CORSECATTR_E_UNSUPPORTED_ENUM_TYPE EMAKEHR(0x144b)
+#define CORSECATTR_E_NO_FIELD EMAKEHR(0x144c)
+#define CORSECATTR_E_NO_PROPERTY EMAKEHR(0x144d)
+#define CORSECATTR_E_EXCEPTION EMAKEHR(0x144e)
+#define CORSECATTR_E_EXCEPTION_HR EMAKEHR(0x144f)
+#define ISS_E_ISOSTORE_START EMAKEHR(0x1450)
+#define ISS_E_ISOSTORE EMAKEHR(0x1450)
+#define ISS_E_OPEN_STORE_FILE EMAKEHR(0x1460)
+#define ISS_E_OPEN_FILE_MAPPING EMAKEHR(0x1461)
+#define ISS_E_MAP_VIEW_OF_FILE EMAKEHR(0x1462)
+#define ISS_E_GET_FILE_SIZE EMAKEHR(0x1463)
+#define ISS_E_CREATE_MUTEX EMAKEHR(0x1464)
+#define ISS_E_LOCK_FAILED EMAKEHR(0x1465)
+#define ISS_E_FILE_WRITE EMAKEHR(0x1466)
+#define ISS_E_SET_FILE_POINTER EMAKEHR(0x1467)
+#define ISS_E_CREATE_DIR EMAKEHR(0x1468)
+#define ISS_E_STORE_NOT_OPEN EMAKEHR(0x1469)
+#define ISS_E_CORRUPTED_STORE_FILE EMAKEHR(0x1480)
+#define ISS_E_STORE_VERSION EMAKEHR(0x1481)
+#define ISS_E_FILE_NOT_MAPPED EMAKEHR(0x1482)
+#define ISS_E_BLOCK_SIZE_TOO_SMALL EMAKEHR(0x1483)
+#define ISS_E_ALLOC_TOO_LARGE EMAKEHR(0x1484)
+#define ISS_E_USAGE_WILL_EXCEED_QUOTA EMAKEHR(0x1485)
+#define ISS_E_TABLE_ROW_NOT_FOUND EMAKEHR(0x1486)
+#define ISS_E_DEPRECATE EMAKEHR(0x14a0)
+#define ISS_E_CALLER EMAKEHR(0x14a1)
+#define ISS_E_PATH_LENGTH EMAKEHR(0x14a2)
+#define ISS_E_MACHINE EMAKEHR(0x14a3)
+#define ISS_E_MACHINE_DACL EMAKEHR(0x14a4)
+#define ISS_E_ISOSTORE_END EMAKEHR(0x14ff)
+#define COR_E_EXCEPTION EMAKEHR(0x1500)
+#define COR_E_SYSTEM EMAKEHR(0x1501)
+#define COR_E_ARGUMENTOUTOFRANGE EMAKEHR(0x1502)
+#define COR_E_ARRAYTYPEMISMATCH EMAKEHR(0x1503)
+#define COR_E_CONTEXTMARSHAL EMAKEHR(0x1504)
+#define COR_E_TIMEOUT EMAKEHR(0x1505)
+#define COR_E_EXECUTIONENGINE EMAKEHR(0x1506)
+#define COR_E_FIELDACCESS EMAKEHR(0x1507)
+#define COR_E_INDEXOUTOFRANGE EMAKEHR(0x1508)
+#define COR_E_INVALIDOPERATION EMAKEHR(0x1509)
+#define COR_E_SECURITY EMAKEHR(0x150a)
+#define COR_E_REMOTING EMAKEHR(0x150b)
+#define COR_E_SERIALIZATION EMAKEHR(0x150c)
+#define COR_E_VERIFICATION EMAKEHR(0x150d)
+#define COR_E_SERVER EMAKEHR(0x150e)
+#define COR_E_SERVICEDCOMPONENT EMAKEHR(0x150f)
+#define COR_E_METHODACCESS EMAKEHR(0x1510)
+#define COR_E_MISSINGFIELD EMAKEHR(0x1511)
+#define COR_E_MISSINGMEMBER EMAKEHR(0x1512)
+#define COR_E_MISSINGMETHOD EMAKEHR(0x1513)
+#define COR_E_MULTICASTNOTSUPPORTED EMAKEHR(0x1514)
+#define COR_E_NOTSUPPORTED EMAKEHR(0x1515)
+#define COR_E_OVERFLOW EMAKEHR(0x1516)
+#define COR_E_RANK EMAKEHR(0x1517)
+#define COR_E_SYNCHRONIZATIONLOCK EMAKEHR(0x1518)
+#define COR_E_THREADINTERRUPTED EMAKEHR(0x1519)
+#define COR_E_MEMBERACCESS EMAKEHR(0x151a)
+#define COR_E_THREADSTATE EMAKEHR(0x1520)
+#define COR_E_THREADSTOP EMAKEHR(0x1521)
+#define COR_E_TYPELOAD EMAKEHR(0x1522)
+#define COR_E_ENTRYPOINTNOTFOUND EMAKEHR(0x1523)
+#define COR_E_DLLNOTFOUND EMAKEHR(0x1524)
+#define COR_E_THREADSTART EMAKEHR(0x1525)
+#define COR_E_INVALIDCOMOBJECT EMAKEHR(0x1527)
+#define COR_E_NOTFINITENUMBER EMAKEHR(0x1528)
+#define COR_E_DUPLICATEWAITOBJECT EMAKEHR(0x1529)
+#define COR_E_SEMAPHOREFULL EMAKEHR(0x152b)
+#define COR_E_WAITHANDLECANNOTBEOPENED EMAKEHR(0x152c)
+#define COR_E_ABANDONEDMUTEX EMAKEHR(0x152d)
+#define COR_E_THREADABORTED EMAKEHR(0x1530)
+#define COR_E_INVALIDOLEVARIANTTYPE EMAKEHR(0x1531)
+#define COR_E_MISSINGMANIFESTRESOURCE EMAKEHR(0x1532)
+#define COR_E_SAFEARRAYTYPEMISMATCH EMAKEHR(0x1533)
+#define COR_E_TYPEINITIALIZATION EMAKEHR(0x1534)
+#define COR_E_MARSHALDIRECTIVE EMAKEHR(0x1535)
+#define COR_E_MISSINGSATELLITEASSEMBLY EMAKEHR(0x1536)
+#define COR_E_FORMAT EMAKEHR(0x1537)
+#define COR_E_SAFEARRAYRANKMISMATCH EMAKEHR(0x1538)
+#define COR_E_PLATFORMNOTSUPPORTED EMAKEHR(0x1539)
+#define COR_E_INVALIDPROGRAM EMAKEHR(0x153a)
+#define COR_E_OPERATIONCANCELED EMAKEHR(0x153b)
+#define COR_E_INSUFFICIENTMEMORY EMAKEHR(0x153d)
+#define COR_E_RUNTIMEWRAPPED EMAKEHR(0x153e)
+#define COR_E_DEVICESNOTSUPPORTED EMAKEHR(0x1540)
+#define COR_E_DATAMISALIGNED EMAKEHR(0x1541)
+#define COR_E_CODECONTRACTFAILED EMAKEHR(0x1542)
+#define COR_E_TYPEACCESS EMAKEHR(0x1543)
+#define COR_E_ACCESSING_CCW EMAKEHR(0x1544)
+#define COR_E_MAXMETHODSIZE EMAKEHR(0x1545)
+#define COR_E_KEYNOTFOUND EMAKEHR(0x1577)
+#define COR_E_INSUFFICIENTEXECUTIONSTACK EMAKEHR(0x1578)
+#define COR_E_APPLICATION EMAKEHR(0x1600)
+#define COR_E_INVALIDFILTERCRITERIA EMAKEHR(0x1601)
+#define COR_E_REFLECTIONTYPELOAD EMAKEHR(0x1602)
+#define COR_E_TARGET EMAKEHR(0x1603)
+#define COR_E_TARGETINVOCATION EMAKEHR(0x1604)
+#define COR_E_CUSTOMATTRIBUTEFORMAT EMAKEHR(0x1605)
+#define COR_E_IO EMAKEHR(0x1620)
+#define COR_E_FILELOAD EMAKEHR(0x1621)
+#define COR_E_OBJECTDISPOSED EMAKEHR(0x1622)
+#define COR_E_FAILFAST EMAKEHR(0x1623)
+#define COR_E_HOSTPROTECTION EMAKEHR(0x1640)
+#define COR_E_ILLEGAL_REENTRANCY EMAKEHR(0x1641)
+#define CLR_E_SHIM_RUNTIMELOAD EMAKEHR(0x1700)
+#define CLR_E_SHIM_RUNTIMEEXPORT EMAKEHR(0x1701)
+#define CLR_E_SHIM_INSTALLROOT EMAKEHR(0x1702)
+#define CLR_E_SHIM_INSTALLCOMP EMAKEHR(0x1703)
+#define CLR_E_SHIM_LEGACYRUNTIMEALREADYBOUND EMAKEHR(0x1704)
+#define CLR_E_SHIM_SHUTDOWNINPROGRESS EMAKEHR(0x1705)
+#define VER_E_HRESULT EMAKEHR(0x1801)
+#define VER_E_OFFSET EMAKEHR(0x1802)
+#define VER_E_OPCODE EMAKEHR(0x1803)
+#define VER_E_OPERAND EMAKEHR(0x1804)
+#define VER_E_TOKEN EMAKEHR(0x1805)
+#define VER_E_EXCEPT EMAKEHR(0x1806)
+#define VER_E_STACK_SLOT EMAKEHR(0x1807)
+#define VER_E_LOC EMAKEHR(0x1808)
+#define VER_E_ARG EMAKEHR(0x1809)
+#define VER_E_FOUND EMAKEHR(0x180a)
+#define VER_E_EXPECTED EMAKEHR(0x180b)
+#define VER_E_LOC_BYNAME EMAKEHR(0x180c)
+#define VER_E_UNKNOWN_OPCODE EMAKEHR(0x1810)
+#define VER_E_SIG_CALLCONV EMAKEHR(0x1811)
+#define VER_E_SIG_ELEMTYPE EMAKEHR(0x1812)
+#define VER_E_RET_SIG EMAKEHR(0x1814)
+#define VER_E_FIELD_SIG EMAKEHR(0x1815)
+#define VER_E_OPEN_DLGT_PROT_ACC EMAKEHR(0x1816)
+#define VER_E_INTERNAL EMAKEHR(0x1818)
+#define VER_E_STACK_TOO_LARGE EMAKEHR(0x1819)
+#define VER_E_ARRAY_NAME_LONG EMAKEHR(0x181a)
+#define VER_E_FALLTHRU EMAKEHR(0x1820)
+#define VER_E_TRY_GTEQ_END EMAKEHR(0x1821)
+#define VER_E_TRYEND_GT_CS EMAKEHR(0x1822)
+#define VER_E_HND_GTEQ_END EMAKEHR(0x1823)
+#define VER_E_HNDEND_GT_CS EMAKEHR(0x1824)
+#define VER_E_FLT_GTEQ_CS EMAKEHR(0x1825)
+#define VER_E_TRY_START EMAKEHR(0x1826)
+#define VER_E_HND_START EMAKEHR(0x1827)
+#define VER_E_FLT_START EMAKEHR(0x1828)
+#define VER_E_TRY_OVERLAP EMAKEHR(0x1829)
+#define VER_E_TRY_EQ_HND_FIL EMAKEHR(0x182a)
+#define VER_E_TRY_SHARE_FIN_FAL EMAKEHR(0x182b)
+#define VER_E_HND_OVERLAP EMAKEHR(0x182c)
+#define VER_E_HND_EQ EMAKEHR(0x182d)
+#define VER_E_FIL_OVERLAP EMAKEHR(0x182e)
+#define VER_E_FIL_EQ EMAKEHR(0x182f)
+#define VER_E_FIL_CONT_TRY EMAKEHR(0x1830)
+#define VER_E_FIL_CONT_HND EMAKEHR(0x1831)
+#define VER_E_FIL_CONT_FIL EMAKEHR(0x1832)
+#define VER_E_FIL_GTEQ_CS EMAKEHR(0x1833)
+#define VER_E_FIL_START EMAKEHR(0x1834)
+#define VER_E_FALLTHRU_EXCEP EMAKEHR(0x1835)
+#define VER_E_FALLTHRU_INTO_HND EMAKEHR(0x1836)
+#define VER_E_FALLTHRU_INTO_FIL EMAKEHR(0x1837)
+#define VER_E_LEAVE EMAKEHR(0x1838)
+#define VER_E_RETHROW EMAKEHR(0x1839)
+#define VER_E_ENDFINALLY EMAKEHR(0x183a)
+#define VER_E_ENDFILTER EMAKEHR(0x183b)
+#define VER_E_ENDFILTER_MISSING EMAKEHR(0x183c)
+#define VER_E_BR_INTO_TRY EMAKEHR(0x183d)
+#define VER_E_BR_INTO_HND EMAKEHR(0x183e)
+#define VER_E_BR_INTO_FIL EMAKEHR(0x183f)
+#define VER_E_BR_OUTOF_TRY EMAKEHR(0x1840)
+#define VER_E_BR_OUTOF_HND EMAKEHR(0x1841)
+#define VER_E_BR_OUTOF_FIL EMAKEHR(0x1842)
+#define VER_E_BR_OUTOF_FIN EMAKEHR(0x1843)
+#define VER_E_RET_FROM_TRY EMAKEHR(0x1844)
+#define VER_E_RET_FROM_HND EMAKEHR(0x1845)
+#define VER_E_RET_FROM_FIL EMAKEHR(0x1846)
+#define VER_E_BAD_JMP_TARGET EMAKEHR(0x1847)
+#define VER_E_PATH_LOC EMAKEHR(0x1848)
+#define VER_E_PATH_THIS EMAKEHR(0x1849)
+#define VER_E_PATH_STACK EMAKEHR(0x184a)
+#define VER_E_PATH_STACK_DEPTH EMAKEHR(0x184b)
+#define VER_E_THIS EMAKEHR(0x184c)
+#define VER_E_THIS_UNINIT_EXCEP EMAKEHR(0x184d)
+#define VER_E_THIS_UNINIT_STORE EMAKEHR(0x184e)
+#define VER_E_THIS_UNINIT_RET EMAKEHR(0x184f)
+#define VER_E_THIS_UNINIT_V_RET EMAKEHR(0x1850)
+#define VER_E_THIS_UNINIT_BR EMAKEHR(0x1851)
+#define VER_E_LDFTN_CTOR EMAKEHR(0x1852)
+#define VER_E_STACK_NOT_EQ EMAKEHR(0x1853)
+#define VER_E_STACK_UNEXPECTED EMAKEHR(0x1854)
+#define VER_E_STACK_EXCEPTION EMAKEHR(0x1855)
+#define VER_E_STACK_OVERFLOW EMAKEHR(0x1856)
+#define VER_E_STACK_UNDERFLOW EMAKEHR(0x1857)
+#define VER_E_STACK_EMPTY EMAKEHR(0x1858)
+#define VER_E_STACK_UNINIT EMAKEHR(0x1859)
+#define VER_E_STACK_I_I4_I8 EMAKEHR(0x185a)
+#define VER_E_STACK_R_R4_R8 EMAKEHR(0x185b)
+#define VER_E_STACK_NO_R_I8 EMAKEHR(0x185c)
+#define VER_E_STACK_NUMERIC EMAKEHR(0x185d)
+#define VER_E_STACK_OBJREF EMAKEHR(0x185e)
+#define VER_E_STACK_P_OBJREF EMAKEHR(0x185f)
+#define VER_E_STACK_BYREF EMAKEHR(0x1860)
+#define VER_E_STACK_METHOD EMAKEHR(0x1861)
+#define VER_E_STACK_ARRAY_SD EMAKEHR(0x1862)
+#define VER_E_STACK_VALCLASS EMAKEHR(0x1863)
+#define VER_E_STACK_P_VALCLASS EMAKEHR(0x1864)
+#define VER_E_STACK_NO_VALCLASS EMAKEHR(0x1865)
+#define VER_E_LOC_DEAD EMAKEHR(0x1866)
+#define VER_E_LOC_NUM EMAKEHR(0x1867)
+#define VER_E_ARG_NUM EMAKEHR(0x1868)
+#define VER_E_TOKEN_RESOLVE EMAKEHR(0x1869)
+#define VER_E_TOKEN_TYPE EMAKEHR(0x186a)
+#define VER_E_TOKEN_TYPE_MEMBER EMAKEHR(0x186b)
+#define VER_E_TOKEN_TYPE_FIELD EMAKEHR(0x186c)
+#define VER_E_TOKEN_TYPE_SIG EMAKEHR(0x186d)
+#define VER_E_UNVERIFIABLE EMAKEHR(0x186e)
+#define VER_E_LDSTR_OPERAND EMAKEHR(0x186f)
+#define VER_E_RET_PTR_TO_STACK EMAKEHR(0x1870)
+#define VER_E_RET_VOID EMAKEHR(0x1871)
+#define VER_E_RET_MISSING EMAKEHR(0x1872)
+#define VER_E_RET_EMPTY EMAKEHR(0x1873)
+#define VER_E_RET_UNINIT EMAKEHR(0x1874)
+#define VER_E_ARRAY_ACCESS EMAKEHR(0x1875)
+#define VER_E_ARRAY_V_STORE EMAKEHR(0x1876)
+#define VER_E_ARRAY_SD EMAKEHR(0x1877)
+#define VER_E_ARRAY_SD_PTR EMAKEHR(0x1878)
+#define VER_E_ARRAY_FIELD EMAKEHR(0x1879)
+#define VER_E_ARGLIST EMAKEHR(0x187a)
+#define VER_E_VALCLASS EMAKEHR(0x187b)
+#define VER_E_METHOD_ACCESS EMAKEHR(0x187c)
+#define VER_E_FIELD_ACCESS EMAKEHR(0x187d)
+#define VER_E_DEAD EMAKEHR(0x187e)
+#define VER_E_FIELD_STATIC EMAKEHR(0x187f)
+#define VER_E_FIELD_NO_STATIC EMAKEHR(0x1880)
+#define VER_E_ADDR EMAKEHR(0x1881)
+#define VER_E_ADDR_BYREF EMAKEHR(0x1882)
+#define VER_E_ADDR_LITERAL EMAKEHR(0x1883)
+#define VER_E_INITONLY EMAKEHR(0x1884)
+#define VER_E_THROW EMAKEHR(0x1885)
+#define VER_E_CALLVIRT_VALCLASS EMAKEHR(0x1886)
+#define VER_E_CALL_SIG EMAKEHR(0x1887)
+#define VER_E_CALL_STATIC EMAKEHR(0x1888)
+#define VER_E_CTOR EMAKEHR(0x1889)
+#define VER_E_CTOR_VIRT EMAKEHR(0x188a)
+#define VER_E_CTOR_OR_SUPER EMAKEHR(0x188b)
+#define VER_E_CTOR_MUL_INIT EMAKEHR(0x188c)
+#define VER_E_SIG EMAKEHR(0x188d)
+#define VER_E_SIG_ARRAY EMAKEHR(0x188e)
+#define VER_E_SIG_ARRAY_PTR EMAKEHR(0x188f)
+#define VER_E_SIG_ARRAY_BYREF EMAKEHR(0x1890)
+#define VER_E_SIG_ELEM_PTR EMAKEHR(0x1891)
+#define VER_E_SIG_VARARG EMAKEHR(0x1892)
+#define VER_E_SIG_VOID EMAKEHR(0x1893)
+#define VER_E_SIG_BYREF_BYREF EMAKEHR(0x1894)
+#define VER_E_CODE_SIZE_ZERO EMAKEHR(0x1896)
+#define VER_E_BAD_VARARG EMAKEHR(0x1897)
+#define VER_E_TAIL_CALL EMAKEHR(0x1898)
+#define VER_E_TAIL_BYREF EMAKEHR(0x1899)
+#define VER_E_TAIL_RET EMAKEHR(0x189a)
+#define VER_E_TAIL_RET_VOID EMAKEHR(0x189b)
+#define VER_E_TAIL_RET_TYPE EMAKEHR(0x189c)
+#define VER_E_TAIL_STACK_EMPTY EMAKEHR(0x189d)
+#define VER_E_METHOD_END EMAKEHR(0x189e)
+#define VER_E_BAD_BRANCH EMAKEHR(0x189f)
+#define VER_E_FIN_OVERLAP EMAKEHR(0x18a0)
+#define VER_E_LEXICAL_NESTING EMAKEHR(0x18a1)
+#define VER_E_VOLATILE EMAKEHR(0x18a2)
+#define VER_E_UNALIGNED EMAKEHR(0x18a3)
+#define VER_E_INNERMOST_FIRST EMAKEHR(0x18a4)
+#define VER_E_CALLI_VIRTUAL EMAKEHR(0x18a5)
+#define VER_E_CALL_ABSTRACT EMAKEHR(0x18a6)
+#define VER_E_STACK_UNEXP_ARRAY EMAKEHR(0x18a7)
+#define VER_E_NOT_IN_GC_HEAP EMAKEHR(0x18a8)
+#define VER_E_TRY_N_EMPTY_STACK EMAKEHR(0x18a9)
+#define VER_E_DLGT_CTOR EMAKEHR(0x18aa)
+#define VER_E_DLGT_BB EMAKEHR(0x18ab)
+#define VER_E_DLGT_PATTERN EMAKEHR(0x18ac)
+#define VER_E_DLGT_LDFTN EMAKEHR(0x18ad)
+#define VER_E_FTN_ABSTRACT EMAKEHR(0x18ae)
+#define VER_E_SIG_C_VC EMAKEHR(0x18af)
+#define VER_E_SIG_VC_C EMAKEHR(0x18b0)
+#define VER_E_BOX_PTR_TO_STACK EMAKEHR(0x18b1)
+#define VER_E_SIG_BYREF_TB_AH EMAKEHR(0x18b2)
+#define VER_E_SIG_ARRAY_TB_AH EMAKEHR(0x18b3)
+#define VER_E_ENDFILTER_STACK EMAKEHR(0x18b4)
+#define VER_E_DLGT_SIG_I EMAKEHR(0x18b5)
+#define VER_E_DLGT_SIG_O EMAKEHR(0x18b6)
+#define VER_E_RA_PTR_TO_STACK EMAKEHR(0x18b7)
+#define VER_E_CATCH_VALUE_TYPE EMAKEHR(0x18b8)
+#define VER_E_CATCH_BYREF EMAKEHR(0x18b9)
+#define VER_E_FIL_PRECEED_HND EMAKEHR(0x18ba)
+#define VER_E_LDVIRTFTN_STATIC EMAKEHR(0x18bb)
+#define VER_E_CALLVIRT_STATIC EMAKEHR(0x18bc)
+#define VER_E_INITLOCALS EMAKEHR(0x18bd)
+#define VER_E_BR_TO_EXCEPTION EMAKEHR(0x18be)
+#define VER_E_CALL_CTOR EMAKEHR(0x18bf)
+#define VER_E_VALCLASS_OBJREF_VAR EMAKEHR(0x18c0)
+#define VER_E_STACK_P_VALCLASS_OBJREF_VAR EMAKEHR(0x18c1)
+#define VER_E_SIG_VAR_PARAM EMAKEHR(0x18c2)
+#define VER_E_SIG_MVAR_PARAM EMAKEHR(0x18c3)
+#define VER_E_SIG_VAR_ARG EMAKEHR(0x18c4)
+#define VER_E_SIG_MVAR_ARG EMAKEHR(0x18c5)
+#define VER_E_SIG_GENERICINST EMAKEHR(0x18c6)
+#define VER_E_SIG_METHOD_INST EMAKEHR(0x18c7)
+#define VER_E_SIG_METHOD_PARENT_INST EMAKEHR(0x18c8)
+#define VER_E_SIG_FIELD_PARENT_INST EMAKEHR(0x18c9)
+#define VER_E_CALLCONV_NOT_GENERICINST EMAKEHR(0x18ca)
+#define VER_E_TOKEN_BAD_METHOD_SPEC EMAKEHR(0x18cb)
+#define VER_E_BAD_READONLY_PREFIX EMAKEHR(0x18cc)
+#define VER_E_BAD_CONSTRAINED_PREFIX EMAKEHR(0x18cd)
+#define VER_E_CIRCULAR_VAR_CONSTRAINTS EMAKEHR(0x18ce)
+#define VER_E_CIRCULAR_MVAR_CONSTRAINTS EMAKEHR(0x18cf)
+#define VER_E_UNSATISFIED_METHOD_INST EMAKEHR(0x18d0)
+#define VER_E_UNSATISFIED_METHOD_PARENT_INST EMAKEHR(0x18d1)
+#define VER_E_UNSATISFIED_FIELD_PARENT_INST EMAKEHR(0x18d2)
+#define VER_E_UNSATISFIED_BOX_OPERAND EMAKEHR(0x18d3)
+#define VER_E_CONSTRAINED_CALL_WITH_NON_BYREF_THIS EMAKEHR(0x18d4)
+#define VER_E_CONSTRAINED_OF_NON_VARIABLE_TYPE EMAKEHR(0x18d5)
+#define VER_E_READONLY_UNEXPECTED_CALLEE EMAKEHR(0x18d6)
+#define VER_E_READONLY_ILLEGAL_WRITE EMAKEHR(0x18d7)
+#define VER_E_READONLY_IN_MKREFANY EMAKEHR(0x18d8)
+#define VER_E_UNALIGNED_ALIGNMENT EMAKEHR(0x18d9)
+#define VER_E_TAILCALL_INSIDE_EH EMAKEHR(0x18da)
+#define VER_E_BACKWARD_BRANCH EMAKEHR(0x18db)
+#define VER_E_CALL_TO_VTYPE_BASE EMAKEHR(0x18dc)
+#define VER_E_NEWOBJ_OF_ABSTRACT_CLASS EMAKEHR(0x18dd)
+#define VER_E_UNMANAGED_POINTER EMAKEHR(0x18de)
+#define VER_E_LDFTN_NON_FINAL_VIRTUAL EMAKEHR(0x18df)
+#define VER_E_FIELD_OVERLAP EMAKEHR(0x18e0)
+#define VER_E_THIS_MISMATCH EMAKEHR(0x18e1)
+#define VER_E_STACK_I_I4 EMAKEHR(0x18e2)
+#define VER_E_BAD_PE EMAKEHR(0x18f0)
+#define VER_E_BAD_MD EMAKEHR(0x18f1)
+#define VER_E_BAD_APPDOMAIN EMAKEHR(0x18f2)
+#define VER_E_TYPELOAD EMAKEHR(0x18f3)
+#define VER_E_PE_LOAD EMAKEHR(0x18f4)
+#define VER_E_WRITE_RVA_STATIC EMAKEHR(0x18f5)
+#define VER_E_INITIALIZE_ARRAY_MISSING_TOKEN EMAKEHR(0x18f6)
+#define COR_E_SqlException EMAKEHR(0x1904)
+#define COR_E_Data EMAKEHR(0x1920)
+#define COR_E_DataDeletedRowInaccessible EMAKEHR(0x1921)
+#define COR_E_DataDuplicateName EMAKEHR(0x1922)
+#define COR_E_DataInRowChangingEvent EMAKEHR(0x1923)
+#define COR_E_DataInvalidConstraint EMAKEHR(0x1924)
+#define COR_E_DataMissingPrimaryKey EMAKEHR(0x1925)
+#define COR_E_DataNoNullAllowed EMAKEHR(0x1926)
+#define COR_E_DataReadOnly EMAKEHR(0x1927)
+#define COR_E_DataRowNotInTable EMAKEHR(0x1928)
+#define COR_E_DataVersionNotFound EMAKEHR(0x1929)
+#define COR_E_DataConstraint EMAKEHR(0x192a)
+#define COR_E_StrongTyping EMAKEHR(0x192b)
+#define COR_E_SqlType EMAKEHR(0x1930)
+#define COR_E_SqlNullValue EMAKEHR(0x1931)
+#define COR_E_SqlTruncate EMAKEHR(0x1932)
+#define COR_E_AdapterMapping EMAKEHR(0x1933)
+#define COR_E_DataAdapter EMAKEHR(0x1934)
+#define COR_E_DBConcurrency EMAKEHR(0x1935)
+#define COR_E_OperationAborted EMAKEHR(0x1936)
+#define COR_E_InvalidUdt EMAKEHR(0x1937)
+#define COR_E_OdbcException EMAKEHR(0x1937)
+#define COR_E_OracleException EMAKEHR(0x1938)
+#define COR_E_Xml EMAKEHR(0x1940)
+#define COR_E_XmlSchema EMAKEHR(0x1941)
+#define COR_E_XmlXslt EMAKEHR(0x1942)
+#define COR_E_XmlXPath EMAKEHR(0x1943)
+#define COR_E_XmlQuery EMAKEHR(0x1944)
+#define VLDTR_E_IFACE_NOTIFACE EMAKEHR(0x1b00)
+#define VLDTR_E_FD_RVAHASNORVA EMAKEHR(0x1b01)
+#define VLDTR_E_FD_RVAHASZERORVA EMAKEHR(0x1b02)
+#define VLDTR_E_MD_RVAANDIMPLMAP EMAKEHR(0x1b03)
+#define VLDTR_E_TD_EXTRAFLAGS EMAKEHR(0x1b04)
+#define VLDTR_E_TD_EXTENDSITSELF EMAKEHR(0x1b05)
+#define VLDTR_E_TD_SYSVTNOTEXTOBJ EMAKEHR(0x1b06)
+#define VLDTR_E_TD_EXTTYPESPEC EMAKEHR(0x1b07)
+#define VLDTR_E_TD_VTNOSIZE EMAKEHR(0x1b09)
+#define VLDTR_E_TD_IFACESEALED EMAKEHR(0x1b0a)
+#define VLDTR_E_NC_BADNESTED EMAKEHR(0x1b0b)
+#define VLDTR_E_NC_BADENCLOSER EMAKEHR(0x1b0c)
+#define VLDTR_E_NC_DUP EMAKEHR(0x1b0d)
+#define VLDTR_E_NC_DUPENCLOSER EMAKEHR(0x1b0e)
+#define VLDTR_E_FRVA_ZERORVA EMAKEHR(0x1b0f)
+#define VLDTR_E_FRVA_BADFIELD EMAKEHR(0x1b10)
+#define VLDTR_E_FRVA_DUPRVA EMAKEHR(0x1b11)
+#define VLDTR_E_FRVA_DUPFIELD EMAKEHR(0x1b12)
+#define VLDTR_E_EP_BADTOKEN EMAKEHR(0x1b13)
+#define VLDTR_E_EP_INSTANCE EMAKEHR(0x1b14)
+#define VLDTR_E_TD_ENUMFLDBADTYPE EMAKEHR(0x1b15)
+#define VLDTR_E_MD_BADRVA EMAKEHR(0x1b16)
+#define VLDTR_E_FD_LITERALNODEFAULT EMAKEHR(0x1b17)
+#define VLDTR_E_IFACE_METHNOTIMPL EMAKEHR(0x1b18)
+#define VLDTR_E_CA_BADPARENT EMAKEHR(0x1b19)
+#define VLDTR_E_CA_BADTYPE EMAKEHR(0x1b1a)
+#define VLDTR_E_CA_NOTCTOR EMAKEHR(0x1b1b)
+#define VLDTR_E_CA_BADSIG EMAKEHR(0x1b1c)
+#define VLDTR_E_CA_NOSIG EMAKEHR(0x1b1d)
+#define VLDTR_E_CA_BADPROLOG EMAKEHR(0x1b1e)
+#define VLDTR_E_MD_BADLOCALSIGTOK EMAKEHR(0x1b1f)
+#define VLDTR_E_MD_BADHEADER EMAKEHR(0x1b20)
+#define VLDTR_E_EP_TOOMANYARGS EMAKEHR(0x1b21)
+#define VLDTR_E_EP_BADRET EMAKEHR(0x1b22)
+#define VLDTR_E_EP_BADARG EMAKEHR(0x1b23)
+#define VLDTR_E_SIG_BADVOID EMAKEHR(0x1b24)
+#define VLDTR_E_IFACE_METHMULTIMPL EMAKEHR(0x1b25)
+#define VLDTR_E_GP_NAMENULL EMAKEHR(0x1b26)
+#define VLDTR_E_GP_OWNERNIL EMAKEHR(0x1b27)
+#define VLDTR_E_GP_DUPNAME EMAKEHR(0x1b28)
+#define VLDTR_E_GP_DUPNUMBER EMAKEHR(0x1b29)
+#define VLDTR_E_GP_NONSEQ_BY_OWNER EMAKEHR(0x1b2a)
+#define VLDTR_E_GP_NONSEQ_BY_NUMBER EMAKEHR(0x1b2b)
+#define VLDTR_E_GP_UNEXPECTED_OWNER_FOR_VARIANT_VAR EMAKEHR(0x1b2c)
+#define VLDTR_E_GP_ILLEGAL_VARIANT_MVAR EMAKEHR(0x1b2d)
+#define VLDTR_E_GP_ILLEGAL_VARIANCE_FLAGS EMAKEHR(0x1b2e)
+#define VLDTR_E_GP_REFANDVALUETYPE EMAKEHR(0x1b2f)
+#define VLDTR_E_GPC_OWNERNIL EMAKEHR(0x1b30)
+#define VLDTR_E_GPC_DUP EMAKEHR(0x1b31)
+#define VLDTR_E_GPC_NONCONTIGUOUS EMAKEHR(0x1b32)
+#define VLDTR_E_MS_METHODNIL EMAKEHR(0x1b33)
+#define VLDTR_E_MS_DUP EMAKEHR(0x1b34)
+#define VLDTR_E_MS_BADCALLINGCONV EMAKEHR(0x1b35)
+#define VLDTR_E_MS_MISSARITY EMAKEHR(0x1b36)
+#define VLDTR_E_MS_MISSARG EMAKEHR(0x1b37)
+#define VLDTR_E_MS_ARITYMISMATCH EMAKEHR(0x1b38)
+#define VLDTR_E_MS_METHODNOTGENERIC EMAKEHR(0x1b39)
+#define VLDTR_E_SIG_MISSARITY EMAKEHR(0x1b3a)
+#define VLDTR_E_SIG_ARITYMISMATCH EMAKEHR(0x1b3b)
+#define VLDTR_E_MD_GENERIC_CCTOR EMAKEHR(0x1b3c)
+#define VLDTR_E_MD_GENERIC_CTOR EMAKEHR(0x1b3d)
+#define VLDTR_E_MD_GENERIC_IMPORT EMAKEHR(0x1b3e)
+#define VLDTR_E_MD_GENERIC_BADCALLCONV EMAKEHR(0x1b3f)
+#define VLDTR_E_EP_GENERIC_METHOD EMAKEHR(0x1b40)
+#define VLDTR_E_MD_MISSARITY EMAKEHR(0x1b41)
+#define VLDTR_E_MD_ARITYZERO EMAKEHR(0x1b42)
+#define VLDTR_E_SIG_ARITYZERO EMAKEHR(0x1b43)
+#define VLDTR_E_MS_ARITYZERO EMAKEHR(0x1b44)
+#define VLDTR_E_MD_GPMISMATCH EMAKEHR(0x1b45)
+#define VLDTR_E_EP_GENERIC_TYPE EMAKEHR(0x1b46)
+#define VLDTR_E_MI_DECLNOTGENERIC EMAKEHR(0x1b47)
+#define VLDTR_E_MI_IMPLNOTGENERIC EMAKEHR(0x1b48)
+#define VLDTR_E_MI_ARITYMISMATCH EMAKEHR(0x1b49)
+#define VLDTR_E_TD_EXTBADTYPESPEC EMAKEHR(0x1b4a)
+#define VLDTR_E_SIG_BYREFINST EMAKEHR(0x1b4b)
+#define VLDTR_E_MS_BYREFINST EMAKEHR(0x1b4c)
+#define VLDTR_E_TS_EMPTY EMAKEHR(0x1b4d)
+#define VLDTR_E_TS_HASSENTINALS EMAKEHR(0x1b4e)
+#define VLDTR_E_TD_GENERICHASEXPLAYOUT EMAKEHR(0x1b4f)
+#define VLDTR_E_SIG_BADTOKTYPE EMAKEHR(0x1b50)
+#define VLDTR_E_IFACE_METHNOTIMPLTHISMOD EMAKEHR(0x1b51)
+#define TLBX_E_CIRCULAR_EXPORT2 EMAKEHR(0x1b52)
+#define CORDBG_E_THREAD_NOT_SCHEDULED EMAKEHR(0x1c00)
+#define CORDBG_E_HANDLE_HAS_BEEN_DISPOSED EMAKEHR(0x1c01)
+#define CORDBG_E_NONINTERCEPTABLE_EXCEPTION EMAKEHR(0x1c02)
+#define CORDBG_E_CANT_UNWIND_ABOVE_CALLBACK EMAKEHR(0x1c03)
+#define CORDBG_E_INTERCEPT_FRAME_ALREADY_SET EMAKEHR(0x1c04)
+#define CORDBG_E_NO_NATIVE_PATCH_AT_ADDR EMAKEHR(0x1c05)
+#define CORDBG_E_MUST_BE_INTEROP_DEBUGGING EMAKEHR(0x1c06)
+#define CORDBG_E_NATIVE_PATCH_ALREADY_AT_ADDR EMAKEHR(0x1c07)
+#define CORDBG_E_TIMEOUT EMAKEHR(0x1c08)
+#define CORDBG_E_CANT_CALL_ON_THIS_THREAD EMAKEHR(0x1c09)
+#define CORDBG_E_ENC_INFOLESS_METHOD EMAKEHR(0x1c0a)
+#define CORDBG_E_ENC_NESTED_HANLDERS EMAKEHR(0x1c0b)
+#define CORDBG_E_ENC_IN_FUNCLET EMAKEHR(0x1c0c)
+#define CORDBG_E_ENC_LOCALLOC EMAKEHR(0x1c0d)
+#define CORDBG_E_ENC_EDIT_NOT_SUPPORTED EMAKEHR(0x1c0e)
+#define CORDBG_E_FEABORT_DELAYED_UNTIL_THREAD_RESUMED EMAKEHR(0x1c0f)
+#define CORDBG_E_NOTREADY EMAKEHR(0x1c10)
+#define CORDBG_E_CANNOT_RESOLVE_ASSEMBLY EMAKEHR(0x1c11)
+#define CORDBG_E_MUST_BE_IN_LOAD_MODULE EMAKEHR(0x1c12)
+#define CORDBG_E_CANNOT_BE_ON_ATTACH EMAKEHR(0x1c13)
+#define CORDBG_E_NGEN_NOT_SUPPORTED EMAKEHR(0x1c14)
+#define CORDBG_E_ILLEGAL_SHUTDOWN_ORDER EMAKEHR(0x1c15)
+#define CORDBG_E_CANNOT_DEBUG_FIBER_PROCESS EMAKEHR(0x1c16)
+#define CORDBG_E_MUST_BE_IN_CREATE_PROCESS EMAKEHR(0x1c17)
+#define CORDBG_E_DETACH_FAILED_OUTSTANDING_EVALS EMAKEHR(0x1c18)
+#define CORDBG_E_DETACH_FAILED_OUTSTANDING_STEPPERS EMAKEHR(0x1c19)
+#define CORDBG_E_CANT_INTEROP_STEP_OUT EMAKEHR(0x1c20)
+#define CORDBG_E_DETACH_FAILED_OUTSTANDING_BREAKPOINTS EMAKEHR(0x1c21)
+#define CORDBG_E_ILLEGAL_IN_STACK_OVERFLOW EMAKEHR(0x1c22)
+#define CORDBG_E_ILLEGAL_AT_GC_UNSAFE_POINT EMAKEHR(0x1c23)
+#define CORDBG_E_ILLEGAL_IN_PROLOG EMAKEHR(0x1c24)
+#define CORDBG_E_ILLEGAL_IN_NATIVE_CODE EMAKEHR(0x1c25)
+#define CORDBG_E_ILLEGAL_IN_OPTIMIZED_CODE EMAKEHR(0x1c26)
+#define CORDBG_E_MINIDUMP_UNSUPPORTED EMAKEHR(0x1c27)
+#define CORDBG_E_APPDOMAIN_MISMATCH EMAKEHR(0x1c28)
+#define CORDBG_E_CONTEXT_UNVAILABLE EMAKEHR(0x1c29)
+#define CORDBG_E_UNCOMPATIBLE_PLATFORMS EMAKEHR(0x1c30)
+#define CORDBG_E_DEBUGGING_DISABLED EMAKEHR(0x1c31)
+#define CORDBG_E_DETACH_FAILED_ON_ENC EMAKEHR(0x1c32)
+#define CORDBG_E_CURRENT_EXCEPTION_IS_OUTSIDE_CURRENT_EXECUTION_SCOPE EMAKEHR(0x1c33)
+#define CORDBG_E_HELPER_MAY_DEADLOCK EMAKEHR(0x1c34)
+#define CORDBG_E_MISSING_METADATA EMAKEHR(0x1c35)
+#define CORDBG_E_TARGET_INCONSISTENT EMAKEHR(0x1c36)
+#define CORDBG_E_DETACH_FAILED_OUTSTANDING_TARGET_RESOURCES EMAKEHR(0x1c37)
+#define CORDBG_E_TARGET_READONLY EMAKEHR(0x1c38)
+#define CORDBG_E_MISMATCHED_CORWKS_AND_DACWKS_DLLS EMAKEHR(0x1c39)
+#define CORDBG_E_MODULE_LOADED_FROM_DISK EMAKEHR(0x1c3a)
+#define CORDBG_E_SYMBOLS_NOT_AVAILABLE EMAKEHR(0x1c3b)
+#define CORDBG_E_DEBUG_COMPONENT_MISSING EMAKEHR(0x1c3c)
+#define CORDBG_E_REMOTE_MISMATCHED_CERTS EMAKEHR(0x1c3d)
+#define CORDBG_E_REMOTE_NETWORK_FAILURE EMAKEHR(0x1c3e)
+#define CORDBG_E_REMOTE_NO_LISTENER EMAKEHR(0x1c3f)
+#define CORDBG_E_REMOTE_UNKNOWN_TARGET EMAKEHR(0x1c40)
+#define CORDBG_E_REMOTE_INVALID_CONFIG EMAKEHR(0x1c41)
+#define CORDBG_E_REMOTE_MISMATCHED_PROTOCOLS EMAKEHR(0x1c42)
+#define CORDBG_E_LIBRARY_PROVIDER_ERROR EMAKEHR(0x1c43)
+#define CORDBG_E_NOT_CLR EMAKEHR(0x1c44)
+#define CORDBG_E_MISSING_DATA_TARGET_INTERFACE EMAKEHR(0x1c45)
+#define CORDBG_E_UNSUPPORTED_DEBUGGING_MODEL EMAKEHR(0x1c46)
+#define CORDBG_E_UNSUPPORTED_FORWARD_COMPAT EMAKEHR(0x1c47)
+#define CORDBG_E_UNSUPPORTED_VERSION_STRUCT EMAKEHR(0x1c48)
+#define CORDBG_E_READVIRTUAL_FAILURE EMAKEHR(0x1c49)
+#define CORDBG_E_VALUE_POINTS_TO_FUNCTION EMAKEHR(0x1c4a)
+#define CORDBG_E_CORRUPT_OBJECT EMAKEHR(0x1c4b)
+#define CORDBG_E_GC_STRUCTURES_INVALID EMAKEHR(0x1c4c)
+#define CORDBG_E_INVALID_OPCODE EMAKEHR(0x1c4d)
+#define CORDBG_E_UNSUPPORTED EMAKEHR(0x1c4e)
+#define CORDBG_E_MISSING_DEBUGGER_EXPORTS EMAKEHR(0x1c4f)
+#define CORDBG_E_DATA_TARGET_ERROR EMAKEHR(0x1c61)
+#define CORDBG_E_CODE_HAS_NO_METADATA EMAKEHR(0x1c62)
+#define CORDBG_E_CODE_UNRECOGNIZED EMAKEHR(0x1c63)
+#define CORDBG_E_NO_IMAGE_AVAILABLE EMAKEHR(0x1c64)
+#define CORDBG_E_TYPE_NOT_FOUND EMAKEHR(0x1c65)
+#define CORDBG_E_VTABLE_HAS_NO_METADATA EMAKEHR(0x1c66)
+#define CORDBG_E_NO_GENERIC_INFO EMAKEHR(0x1c67)
+#define PEFMT_E_NO_CONTENTS EMAKEHR(0x1d00)
+#define PEFMT_E_NO_NTHEADERS EMAKEHR(0x1d01)
+#define PEFMT_E_64BIT EMAKEHR(0x1d02)
+#define PEFMT_E_NO_CORHEADER EMAKEHR(0x1d03)
+#define PEFMT_E_NOT_ILONLY EMAKEHR(0x1d04)
+#define PEFMT_E_IMPORT_DLLS EMAKEHR(0x1d05)
+#define PEFMT_E_EXE_NOENTRYPOINT EMAKEHR(0x1d06)
+#define PEFMT_E_BASE_RELOCS EMAKEHR(0x1d07)
+#define PEFMT_E_ENTRYPOINT EMAKEHR(0x1d08)
+#define PEFMT_E_ZERO_SIZEOFCODE EMAKEHR(0x1d09)
+#define PEFMT_E_BAD_CORHEADER EMAKEHR(0x1d0a)
+#define PEFMT_E_32BIT EMAKEHR(0x1d0b)
+#define CLR_OPTSVC_E_CONTROLLER_INTERRUPT EMAKEHR(0x1e00)
+#define NGEN_FAILED_GET_DEPENDENCIES EMAKEHR(0x1f00)
+#define NGEN_FAILED_NATIVE_IMAGE_DELETE EMAKEHR(0x1f01)
+#define NGEN_E_TOO_MANY_INTERFACES EMAKEHR(0x1f02)
+#define NGEN_E_OLDER_RUNTIME EMAKEHR(0x1f03)
+#define NGEN_E_WORKER_UNEXPECTED_EXIT EMAKEHR(0x1f04)
+#define NGEN_E_WORKER_UNEXPECTED_SYNC EMAKEHR(0x1f05)
+#define NGEN_E_SYS_ASM_NI_MISSING EMAKEHR(0x1f06)
+#define NGEN_E_EXE_MACHINE_TYPE_MISMATCH EMAKEHR(0x1f07)
+#define NGEN_E_ASSEMBLY_EXCLUSION_FILE_PARSE_ERROR EMAKEHR(0x1f08)
+#define NGEN_E_HARDBOUND_DEPENDENCY_MISSING EMAKEHR(0x1f09)
+#define NGEN_E_NOT_RUNNING_IN_EXPECTED_PACKAGE EMAKEHR(0x1f0a)
+#define NGEN_E_FILE_NOT_ASSEMBLY EMAKEHR(0x1f0b)
+#define CLDB_E_INTERNALERROR EMAKEHR(0x1fff)
+#define CLR_E_BIND_ASSEMBLY_VERSION_TOO_LOW EMAKEHR(0x2000)
+#define CLR_E_BIND_ASSEMBLY_PUBLIC_KEY_MISMATCH EMAKEHR(0x2001)
+#define CLR_E_BIND_IMAGE_UNAVAILABLE EMAKEHR(0x2002)
+#define CLR_E_BIND_UNRECOGNIZED_IDENTITY_FORMAT EMAKEHR(0x2003)
+#define CLR_E_BIND_ASSEMBLY_NOT_FOUND EMAKEHR(0x2004)
+#define CLR_E_BIND_TYPE_NOT_FOUND EMAKEHR(0x2005)
+#define CLR_E_BIND_SYS_ASM_NI_MISSING EMAKEHR(0x2006)
+#define CLR_E_BIND_NI_SECURITY_FAILURE EMAKEHR(0x2007)
+#define CLR_E_BIND_NI_DEP_IDENTITY_MISMATCH EMAKEHR(0x2008)
+#define CLR_E_GC_OOM EMAKEHR(0x2009)
+#define COR_E_UNAUTHORIZEDACCESS E_ACCESSDENIED
+#define COR_E_ARGUMENT E_INVALIDARG
+#define COR_E_INVALIDCAST E_NOINTERFACE
+#define COR_E_OUTOFMEMORY E_OUTOFMEMORY
+#define COR_E_NULLREFERENCE E_POINTER
+#define COR_E_ARITHMETIC __HRESULT_FROM_WIN32(ERROR_ARITHMETIC_OVERFLOW)
+#define COR_E_BAD_PATHNAME __HRESULT_FROM_WIN32(ERROR_BAD_PATHNAME)
+#define COR_E_PATHTOOLONG __HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE)
+#define COR_E_FILENOTFOUND __HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)
+#define COR_E_ENDOFSTREAM __HRESULT_FROM_WIN32(ERROR_HANDLE_EOF)
+#define COR_E_DIRECTORYNOTFOUND __HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND)
+#define COR_E_STACKOVERFLOW __HRESULT_FROM_WIN32(ERROR_STACK_OVERFLOW)
+#define COR_E_AMBIGUOUSMATCH _HRESULT_TYPEDEF_(0x8000211DL)
+#define COR_E_TARGETPARAMCOUNT _HRESULT_TYPEDEF_(0x8002000EL)
+#define COR_E_DIVIDEBYZERO _HRESULT_TYPEDEF_(0x80020012L)
+#define COR_E_BADIMAGEFORMAT _HRESULT_TYPEDEF_(0x8007000BL)
+
+
+#endif // __COMMON_LANGUAGE_RUNTIME_HRESULTS__
diff --git a/src/pal/prebuilt/inc/corprof.h b/src/pal/prebuilt/inc/corprof.h
new file mode 100644
index 0000000000..70b7e77df2
--- /dev/null
+++ b/src/pal/prebuilt/inc/corprof.h
@@ -0,0 +1,12049 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/* this ALWAYS GENERATED file contains the definitions for the interfaces */
+
+
+ /* File created by MIDL compiler version 8.00.0603 */
+/* @@MIDL_FILE_HEADING( ) */
+
+#pragma warning( disable: 4049 ) /* more than 64k source lines */
+
+
+/* verify that the <rpcndr.h> version is high enough to compile this file*/
+#ifndef __REQUIRED_RPCNDR_H_VERSION__
+#define __REQUIRED_RPCNDR_H_VERSION__ 475
+#endif
+
+#include "rpc.h"
+#include "rpcndr.h"
+
+#ifndef __RPCNDR_H_VERSION__
+#error this stub requires an updated version of <rpcndr.h>
+#endif // __RPCNDR_H_VERSION__
+
+#ifndef COM_NO_WINDOWS_H
+#include "windows.h"
+#include "ole2.h"
+#endif /*COM_NO_WINDOWS_H*/
+
+#ifndef __corprof_h__
+#define __corprof_h__
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+/* Forward Declarations */
+
+#ifndef __ICorProfilerCallback_FWD_DEFINED__
+#define __ICorProfilerCallback_FWD_DEFINED__
+typedef interface ICorProfilerCallback ICorProfilerCallback;
+
+#endif /* __ICorProfilerCallback_FWD_DEFINED__ */
+
+
+#ifndef __ICorProfilerCallback2_FWD_DEFINED__
+#define __ICorProfilerCallback2_FWD_DEFINED__
+typedef interface ICorProfilerCallback2 ICorProfilerCallback2;
+
+#endif /* __ICorProfilerCallback2_FWD_DEFINED__ */
+
+
+#ifndef __ICorProfilerCallback3_FWD_DEFINED__
+#define __ICorProfilerCallback3_FWD_DEFINED__
+typedef interface ICorProfilerCallback3 ICorProfilerCallback3;
+
+#endif /* __ICorProfilerCallback3_FWD_DEFINED__ */
+
+
+#ifndef __ICorProfilerCallback4_FWD_DEFINED__
+#define __ICorProfilerCallback4_FWD_DEFINED__
+typedef interface ICorProfilerCallback4 ICorProfilerCallback4;
+
+#endif /* __ICorProfilerCallback4_FWD_DEFINED__ */
+
+
+#ifndef __ICorProfilerCallback5_FWD_DEFINED__
+#define __ICorProfilerCallback5_FWD_DEFINED__
+typedef interface ICorProfilerCallback5 ICorProfilerCallback5;
+
+#endif /* __ICorProfilerCallback5_FWD_DEFINED__ */
+
+
+#ifndef __ICorProfilerCallback6_FWD_DEFINED__
+#define __ICorProfilerCallback6_FWD_DEFINED__
+typedef interface ICorProfilerCallback6 ICorProfilerCallback6;
+
+#endif /* __ICorProfilerCallback6_FWD_DEFINED__ */
+
+
+#ifndef __ICorProfilerCallback7_FWD_DEFINED__
+#define __ICorProfilerCallback7_FWD_DEFINED__
+typedef interface ICorProfilerCallback7 ICorProfilerCallback7;
+
+#endif /* __ICorProfilerCallback7_FWD_DEFINED__ */
+
+
+#ifndef __ICorProfilerInfo_FWD_DEFINED__
+#define __ICorProfilerInfo_FWD_DEFINED__
+typedef interface ICorProfilerInfo ICorProfilerInfo;
+
+#endif /* __ICorProfilerInfo_FWD_DEFINED__ */
+
+
+#ifndef __ICorProfilerInfo2_FWD_DEFINED__
+#define __ICorProfilerInfo2_FWD_DEFINED__
+typedef interface ICorProfilerInfo2 ICorProfilerInfo2;
+
+#endif /* __ICorProfilerInfo2_FWD_DEFINED__ */
+
+
+#ifndef __ICorProfilerInfo3_FWD_DEFINED__
+#define __ICorProfilerInfo3_FWD_DEFINED__
+typedef interface ICorProfilerInfo3 ICorProfilerInfo3;
+
+#endif /* __ICorProfilerInfo3_FWD_DEFINED__ */
+
+
+#ifndef __ICorProfilerObjectEnum_FWD_DEFINED__
+#define __ICorProfilerObjectEnum_FWD_DEFINED__
+typedef interface ICorProfilerObjectEnum ICorProfilerObjectEnum;
+
+#endif /* __ICorProfilerObjectEnum_FWD_DEFINED__ */
+
+
+#ifndef __ICorProfilerFunctionEnum_FWD_DEFINED__
+#define __ICorProfilerFunctionEnum_FWD_DEFINED__
+typedef interface ICorProfilerFunctionEnum ICorProfilerFunctionEnum;
+
+#endif /* __ICorProfilerFunctionEnum_FWD_DEFINED__ */
+
+
+#ifndef __ICorProfilerModuleEnum_FWD_DEFINED__
+#define __ICorProfilerModuleEnum_FWD_DEFINED__
+typedef interface ICorProfilerModuleEnum ICorProfilerModuleEnum;
+
+#endif /* __ICorProfilerModuleEnum_FWD_DEFINED__ */
+
+
+#ifndef __IMethodMalloc_FWD_DEFINED__
+#define __IMethodMalloc_FWD_DEFINED__
+typedef interface IMethodMalloc IMethodMalloc;
+
+#endif /* __IMethodMalloc_FWD_DEFINED__ */
+
+
+#ifndef __ICorProfilerFunctionControl_FWD_DEFINED__
+#define __ICorProfilerFunctionControl_FWD_DEFINED__
+typedef interface ICorProfilerFunctionControl ICorProfilerFunctionControl;
+
+#endif /* __ICorProfilerFunctionControl_FWD_DEFINED__ */
+
+
+#ifndef __ICorProfilerInfo4_FWD_DEFINED__
+#define __ICorProfilerInfo4_FWD_DEFINED__
+typedef interface ICorProfilerInfo4 ICorProfilerInfo4;
+
+#endif /* __ICorProfilerInfo4_FWD_DEFINED__ */
+
+
+#ifndef __ICorProfilerInfo5_FWD_DEFINED__
+#define __ICorProfilerInfo5_FWD_DEFINED__
+typedef interface ICorProfilerInfo5 ICorProfilerInfo5;
+
+#endif /* __ICorProfilerInfo5_FWD_DEFINED__ */
+
+
+#ifndef __ICorProfilerInfo6_FWD_DEFINED__
+#define __ICorProfilerInfo6_FWD_DEFINED__
+typedef interface ICorProfilerInfo6 ICorProfilerInfo6;
+
+#endif /* __ICorProfilerInfo6_FWD_DEFINED__ */
+
+
+#ifndef __ICorProfilerInfo7_FWD_DEFINED__
+#define __ICorProfilerInfo7_FWD_DEFINED__
+typedef interface ICorProfilerInfo7 ICorProfilerInfo7;
+
+#endif /* __ICorProfilerInfo7_FWD_DEFINED__ */
+
+
+#ifndef __ICorProfilerMethodEnum_FWD_DEFINED__
+#define __ICorProfilerMethodEnum_FWD_DEFINED__
+typedef interface ICorProfilerMethodEnum ICorProfilerMethodEnum;
+
+#endif /* __ICorProfilerMethodEnum_FWD_DEFINED__ */
+
+
+#ifndef __ICorProfilerThreadEnum_FWD_DEFINED__
+#define __ICorProfilerThreadEnum_FWD_DEFINED__
+typedef interface ICorProfilerThreadEnum ICorProfilerThreadEnum;
+
+#endif /* __ICorProfilerThreadEnum_FWD_DEFINED__ */
+
+
+#ifndef __ICorProfilerAssemblyReferenceProvider_FWD_DEFINED__
+#define __ICorProfilerAssemblyReferenceProvider_FWD_DEFINED__
+typedef interface ICorProfilerAssemblyReferenceProvider ICorProfilerAssemblyReferenceProvider;
+
+#endif /* __ICorProfilerAssemblyReferenceProvider_FWD_DEFINED__ */
+
+
+/* header files for imported files */
+#include "unknwn.h"
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+
+/* interface __MIDL_itf_corprof_0000_0000 */
+/* [local] */
+
+#define CorDB_CONTROL_Profiling "Cor_Enable_Profiling"
+#define CorDB_CONTROL_ProfilingL L"Cor_Enable_Profiling"
+#if 0
+typedef LONG32 mdToken;
+
+typedef mdToken mdModule;
+
+typedef mdToken mdTypeDef;
+
+typedef mdToken mdMethodDef;
+
+typedef mdToken mdFieldDef;
+
+typedef ULONG CorElementType;
+
+
+typedef /* [public][public][public][public] */ struct __MIDL___MIDL_itf_corprof_0000_0000_0001
+ {
+ DWORD dwOSPlatformId;
+ DWORD dwOSMajorVersion;
+ DWORD dwOSMinorVersion;
+ } OSINFO;
+
+typedef /* [public][public][public] */ struct __MIDL___MIDL_itf_corprof_0000_0000_0002
+ {
+ USHORT usMajorVersion;
+ USHORT usMinorVersion;
+ USHORT usBuildNumber;
+ USHORT usRevisionNumber;
+ LPWSTR szLocale;
+ ULONG cbLocale;
+ DWORD *rProcessor;
+ ULONG ulProcessor;
+ OSINFO *rOS;
+ ULONG ulOS;
+ } ASSEMBLYMETADATA;
+
+#endif
+typedef const BYTE *LPCBYTE;
+
+typedef BYTE *LPBYTE;
+
+#ifndef _COR_IL_MAP
+#define _COR_IL_MAP
+typedef struct _COR_IL_MAP
+ {
+ ULONG32 oldOffset;
+ ULONG32 newOffset;
+ BOOL fAccurate;
+ } COR_IL_MAP;
+
+#endif //_COR_IL_MAP
+#ifndef _COR_DEBUG_IL_TO_NATIVE_MAP_
+#define _COR_DEBUG_IL_TO_NATIVE_MAP_
+typedef
+enum CorDebugIlToNativeMappingTypes
+ {
+ NO_MAPPING = -1,
+ PROLOG = -2,
+ EPILOG = -3
+ } CorDebugIlToNativeMappingTypes;
+
+typedef struct COR_DEBUG_IL_TO_NATIVE_MAP
+ {
+ ULONG32 ilOffset;
+ ULONG32 nativeStartOffset;
+ ULONG32 nativeEndOffset;
+ } COR_DEBUG_IL_TO_NATIVE_MAP;
+
+#endif // _COR_DEBUG_IL_TO_NATIVE_MAP_
+#ifndef _COR_FIELD_OFFSET_
+#define _COR_FIELD_OFFSET_
+typedef struct _COR_FIELD_OFFSET
+ {
+ mdFieldDef ridOfField;
+ ULONG ulOffset;
+ } COR_FIELD_OFFSET;
+
+#endif // _COR_FIELD_OFFSET_
+typedef UINT_PTR ProcessID;
+
+typedef UINT_PTR AssemblyID;
+
+typedef UINT_PTR AppDomainID;
+
+typedef UINT_PTR ModuleID;
+
+typedef UINT_PTR ClassID;
+
+typedef UINT_PTR ThreadID;
+
+typedef UINT_PTR ContextID;
+
+typedef UINT_PTR FunctionID;
+
+typedef UINT_PTR ObjectID;
+
+typedef UINT_PTR GCHandleID;
+
+typedef UINT_PTR COR_PRF_ELT_INFO;
+
+typedef UINT_PTR ReJITID;
+
+typedef /* [public][public][public][public][public][public][public][public][public][public][public][public][public] */ union __MIDL___MIDL_itf_corprof_0000_0000_0003
+ {
+ FunctionID functionID;
+ UINT_PTR clientID;
+ } FunctionIDOrClientID;
+
+typedef UINT_PTR __stdcall __stdcall FunctionIDMapper(
+ FunctionID funcId,
+ BOOL *pbHookFunction);
+
+typedef UINT_PTR __stdcall __stdcall FunctionIDMapper2(
+ FunctionID funcId,
+ void *clientData,
+ BOOL *pbHookFunction);
+
+typedef
+enum _COR_PRF_SNAPSHOT_INFO
+ {
+ COR_PRF_SNAPSHOT_DEFAULT = 0,
+ COR_PRF_SNAPSHOT_REGISTER_CONTEXT = 0x1,
+ COR_PRF_SNAPSHOT_X86_OPTIMIZED = 0x2
+ } COR_PRF_SNAPSHOT_INFO;
+
+typedef UINT_PTR COR_PRF_FRAME_INFO;
+
+typedef struct _COR_PRF_FUNCTION_ARGUMENT_RANGE
+ {
+ UINT_PTR startAddress;
+ ULONG length;
+ } COR_PRF_FUNCTION_ARGUMENT_RANGE;
+
+typedef struct _COR_PRF_FUNCTION_ARGUMENT_INFO
+ {
+ ULONG numRanges;
+ ULONG totalArgumentSize;
+ COR_PRF_FUNCTION_ARGUMENT_RANGE ranges[ 1 ];
+ } COR_PRF_FUNCTION_ARGUMENT_INFO;
+
+typedef struct _COR_PRF_CODE_INFO
+ {
+ UINT_PTR startAddress;
+ SIZE_T size;
+ } COR_PRF_CODE_INFO;
+
+typedef /* [public][public] */
+enum __MIDL___MIDL_itf_corprof_0000_0000_0004
+ {
+ COR_PRF_FIELD_NOT_A_STATIC = 0,
+ COR_PRF_FIELD_APP_DOMAIN_STATIC = 0x1,
+ COR_PRF_FIELD_THREAD_STATIC = 0x2,
+ COR_PRF_FIELD_CONTEXT_STATIC = 0x4,
+ COR_PRF_FIELD_RVA_STATIC = 0x8
+ } COR_PRF_STATIC_TYPE;
+
+typedef struct _COR_PRF_FUNCTION
+ {
+ FunctionID functionId;
+ ReJITID reJitId;
+ } COR_PRF_FUNCTION;
+
+typedef struct _COR_PRF_ASSEMBLY_REFERENCE_INFO
+ {
+ void *pbPublicKeyOrToken;
+ ULONG cbPublicKeyOrToken;
+ LPCWSTR szName;
+ ASSEMBLYMETADATA *pMetaData;
+ void *pbHashValue;
+ ULONG cbHashValue;
+ DWORD dwAssemblyRefFlags;
+ } COR_PRF_ASSEMBLY_REFERENCE_INFO;
+
+typedef struct _COR_PRF_METHOD
+ {
+ ModuleID moduleId;
+ mdMethodDef methodId;
+ } COR_PRF_METHOD;
+
+typedef void __stdcall __stdcall FunctionEnter(
+ FunctionID funcID);
+
+typedef void __stdcall __stdcall FunctionLeave(
+ FunctionID funcID);
+
+typedef void __stdcall __stdcall FunctionTailcall(
+ FunctionID funcID);
+
+typedef void __stdcall __stdcall FunctionEnter2(
+ FunctionID funcId,
+ UINT_PTR clientData,
+ COR_PRF_FRAME_INFO func,
+ COR_PRF_FUNCTION_ARGUMENT_INFO *argumentInfo);
+
+typedef void __stdcall __stdcall FunctionLeave2(
+ FunctionID funcId,
+ UINT_PTR clientData,
+ COR_PRF_FRAME_INFO func,
+ COR_PRF_FUNCTION_ARGUMENT_RANGE *retvalRange);
+
+typedef void __stdcall __stdcall FunctionTailcall2(
+ FunctionID funcId,
+ UINT_PTR clientData,
+ COR_PRF_FRAME_INFO func);
+
+typedef void __stdcall __stdcall FunctionEnter3(
+ FunctionIDOrClientID functionIDOrClientID);
+
+typedef void __stdcall __stdcall FunctionLeave3(
+ FunctionIDOrClientID functionIDOrClientID);
+
+typedef void __stdcall __stdcall FunctionTailcall3(
+ FunctionIDOrClientID functionIDOrClientID);
+
+typedef void __stdcall __stdcall FunctionEnter3WithInfo(
+ FunctionIDOrClientID functionIDOrClientID,
+ COR_PRF_ELT_INFO eltInfo);
+
+typedef void __stdcall __stdcall FunctionLeave3WithInfo(
+ FunctionIDOrClientID functionIDOrClientID,
+ COR_PRF_ELT_INFO eltInfo);
+
+typedef void __stdcall __stdcall FunctionTailcall3WithInfo(
+ FunctionIDOrClientID functionIDOrClientID,
+ COR_PRF_ELT_INFO eltInfo);
+
+typedef HRESULT __stdcall __stdcall StackSnapshotCallback(
+ FunctionID funcId,
+ UINT_PTR ip,
+ COR_PRF_FRAME_INFO frameInfo,
+ ULONG32 contextSize,
+ BYTE context[ ],
+ void *clientData);
+
+typedef /* [public] */
+enum __MIDL___MIDL_itf_corprof_0000_0000_0005
+ {
+ COR_PRF_MONITOR_NONE = 0,
+ COR_PRF_MONITOR_FUNCTION_UNLOADS = 0x1,
+ COR_PRF_MONITOR_CLASS_LOADS = 0x2,
+ COR_PRF_MONITOR_MODULE_LOADS = 0x4,
+ COR_PRF_MONITOR_ASSEMBLY_LOADS = 0x8,
+ COR_PRF_MONITOR_APPDOMAIN_LOADS = 0x10,
+ COR_PRF_MONITOR_JIT_COMPILATION = 0x20,
+ COR_PRF_MONITOR_EXCEPTIONS = 0x40,
+ COR_PRF_MONITOR_GC = 0x80,
+ COR_PRF_MONITOR_OBJECT_ALLOCATED = 0x100,
+ COR_PRF_MONITOR_THREADS = 0x200,
+ COR_PRF_MONITOR_REMOTING = 0x400,
+ COR_PRF_MONITOR_CODE_TRANSITIONS = 0x800,
+ COR_PRF_MONITOR_ENTERLEAVE = 0x1000,
+ COR_PRF_MONITOR_CCW = 0x2000,
+ COR_PRF_MONITOR_REMOTING_COOKIE = ( 0x4000 | COR_PRF_MONITOR_REMOTING ) ,
+ COR_PRF_MONITOR_REMOTING_ASYNC = ( 0x8000 | COR_PRF_MONITOR_REMOTING ) ,
+ COR_PRF_MONITOR_SUSPENDS = 0x10000,
+ COR_PRF_MONITOR_CACHE_SEARCHES = 0x20000,
+ COR_PRF_ENABLE_REJIT = 0x40000,
+ COR_PRF_ENABLE_INPROC_DEBUGGING = 0x80000,
+ COR_PRF_ENABLE_JIT_MAPS = 0x100000,
+ COR_PRF_DISABLE_INLINING = 0x200000,
+ COR_PRF_DISABLE_OPTIMIZATIONS = 0x400000,
+ COR_PRF_ENABLE_OBJECT_ALLOCATED = 0x800000,
+ COR_PRF_MONITOR_CLR_EXCEPTIONS = 0x1000000,
+ COR_PRF_MONITOR_ALL = 0x107ffff,
+ COR_PRF_ENABLE_FUNCTION_ARGS = 0x2000000,
+ COR_PRF_ENABLE_FUNCTION_RETVAL = 0x4000000,
+ COR_PRF_ENABLE_FRAME_INFO = 0x8000000,
+ COR_PRF_ENABLE_STACK_SNAPSHOT = 0x10000000,
+ COR_PRF_USE_PROFILE_IMAGES = 0x20000000,
+ COR_PRF_DISABLE_TRANSPARENCY_CHECKS_UNDER_FULL_TRUST = 0x40000000,
+ COR_PRF_DISABLE_ALL_NGEN_IMAGES = 0x80000000,
+ COR_PRF_ALL = 0x8fffffff,
+ COR_PRF_REQUIRE_PROFILE_IMAGE = ( ( COR_PRF_USE_PROFILE_IMAGES | COR_PRF_MONITOR_CODE_TRANSITIONS ) | COR_PRF_MONITOR_ENTERLEAVE ) ,
+ COR_PRF_ALLOWABLE_AFTER_ATTACH = ( ( ( ( ( ( ( ( ( COR_PRF_MONITOR_THREADS | COR_PRF_MONITOR_MODULE_LOADS ) | COR_PRF_MONITOR_ASSEMBLY_LOADS ) | COR_PRF_MONITOR_APPDOMAIN_LOADS ) | COR_PRF_ENABLE_STACK_SNAPSHOT ) | COR_PRF_MONITOR_GC ) | COR_PRF_MONITOR_SUSPENDS ) | COR_PRF_MONITOR_CLASS_LOADS ) | COR_PRF_MONITOR_EXCEPTIONS ) | COR_PRF_MONITOR_JIT_COMPILATION ) ,
+ COR_PRF_MONITOR_IMMUTABLE = ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( COR_PRF_MONITOR_CODE_TRANSITIONS | COR_PRF_MONITOR_REMOTING ) | COR_PRF_MONITOR_REMOTING_COOKIE ) | COR_PRF_MONITOR_REMOTING_ASYNC ) | COR_PRF_ENABLE_REJIT ) | COR_PRF_ENABLE_INPROC_DEBUGGING ) | COR_PRF_ENABLE_JIT_MAPS ) | COR_PRF_DISABLE_OPTIMIZATIONS ) | COR_PRF_DISABLE_INLINING ) | COR_PRF_ENABLE_OBJECT_ALLOCATED ) | COR_PRF_ENABLE_FUNCTION_ARGS ) | COR_PRF_ENABLE_FUNCTION_RETVAL ) | COR_PRF_ENABLE_FRAME_INFO ) | COR_PRF_USE_PROFILE_IMAGES ) | COR_PRF_DISABLE_TRANSPARENCY_CHECKS_UNDER_FULL_TRUST ) | COR_PRF_DISABLE_ALL_NGEN_IMAGES )
+ } COR_PRF_MONITOR;
+
+typedef /* [public] */
+enum __MIDL___MIDL_itf_corprof_0000_0000_0006
+ {
+ COR_PRF_HIGH_MONITOR_NONE = 0,
+ COR_PRF_HIGH_ADD_ASSEMBLY_REFERENCES = 0x1,
+ COR_PRF_HIGH_IN_MEMORY_SYMBOLS_UPDATED = 0x2,
+ COR_PRF_HIGH_REQUIRE_PROFILE_IMAGE = 0,
+ COR_PRF_HIGH_ALLOWABLE_AFTER_ATTACH = COR_PRF_HIGH_IN_MEMORY_SYMBOLS_UPDATED,
+ COR_PRF_HIGH_MONITOR_IMMUTABLE = 0
+ } COR_PRF_HIGH_MONITOR;
+
+typedef /* [public] */
+enum __MIDL___MIDL_itf_corprof_0000_0000_0007
+ {
+ PROFILER_PARENT_UNKNOWN = 0xfffffffd,
+ PROFILER_GLOBAL_CLASS = 0xfffffffe,
+ PROFILER_GLOBAL_MODULE = 0xffffffff
+ } COR_PRF_MISC;
+
+typedef /* [public][public] */
+enum __MIDL___MIDL_itf_corprof_0000_0000_0008
+ {
+ COR_PRF_CACHED_FUNCTION_FOUND = 0,
+ COR_PRF_CACHED_FUNCTION_NOT_FOUND = ( COR_PRF_CACHED_FUNCTION_FOUND + 1 )
+ } COR_PRF_JIT_CACHE;
+
+typedef /* [public][public][public] */
+enum __MIDL___MIDL_itf_corprof_0000_0000_0009
+ {
+ COR_PRF_TRANSITION_CALL = 0,
+ COR_PRF_TRANSITION_RETURN = ( COR_PRF_TRANSITION_CALL + 1 )
+ } COR_PRF_TRANSITION_REASON;
+
+typedef /* [public][public] */
+enum __MIDL___MIDL_itf_corprof_0000_0000_0010
+ {
+ COR_PRF_SUSPEND_OTHER = 0,
+ COR_PRF_SUSPEND_FOR_GC = 1,
+ COR_PRF_SUSPEND_FOR_APPDOMAIN_SHUTDOWN = 2,
+ COR_PRF_SUSPEND_FOR_CODE_PITCHING = 3,
+ COR_PRF_SUSPEND_FOR_SHUTDOWN = 4,
+ COR_PRF_SUSPEND_FOR_INPROC_DEBUGGER = 6,
+ COR_PRF_SUSPEND_FOR_GC_PREP = 7,
+ COR_PRF_SUSPEND_FOR_REJIT = 8
+ } COR_PRF_SUSPEND_REASON;
+
+typedef /* [public][public] */
+enum __MIDL___MIDL_itf_corprof_0000_0000_0011
+ {
+ COR_PRF_DESKTOP_CLR = 0x1,
+ COR_PRF_CORE_CLR = 0x2
+ } COR_PRF_RUNTIME_TYPE;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+extern RPC_IF_HANDLE __MIDL_itf_corprof_0000_0000_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_corprof_0000_0000_v0_0_s_ifspec;
+
+#ifndef __ICorProfilerCallback_INTERFACE_DEFINED__
+#define __ICorProfilerCallback_INTERFACE_DEFINED__
+
+/* interface ICorProfilerCallback */
+/* [local][unique][uuid][object] */
+
+
+EXTERN_C const IID IID_ICorProfilerCallback;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("176FBED1-A55C-4796-98CA-A9DA0EF883E7")
+ ICorProfilerCallback : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE Initialize(
+ /* [in] */ IUnknown *pICorProfilerInfoUnk) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Shutdown( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE AppDomainCreationStarted(
+ /* [in] */ AppDomainID appDomainId) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE AppDomainCreationFinished(
+ /* [in] */ AppDomainID appDomainId,
+ /* [in] */ HRESULT hrStatus) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE AppDomainShutdownStarted(
+ /* [in] */ AppDomainID appDomainId) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE AppDomainShutdownFinished(
+ /* [in] */ AppDomainID appDomainId,
+ /* [in] */ HRESULT hrStatus) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE AssemblyLoadStarted(
+ /* [in] */ AssemblyID assemblyId) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE AssemblyLoadFinished(
+ /* [in] */ AssemblyID assemblyId,
+ /* [in] */ HRESULT hrStatus) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE AssemblyUnloadStarted(
+ /* [in] */ AssemblyID assemblyId) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE AssemblyUnloadFinished(
+ /* [in] */ AssemblyID assemblyId,
+ /* [in] */ HRESULT hrStatus) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ModuleLoadStarted(
+ /* [in] */ ModuleID moduleId) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ModuleLoadFinished(
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ HRESULT hrStatus) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ModuleUnloadStarted(
+ /* [in] */ ModuleID moduleId) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ModuleUnloadFinished(
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ HRESULT hrStatus) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ModuleAttachedToAssembly(
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ AssemblyID AssemblyId) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ClassLoadStarted(
+ /* [in] */ ClassID classId) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ClassLoadFinished(
+ /* [in] */ ClassID classId,
+ /* [in] */ HRESULT hrStatus) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ClassUnloadStarted(
+ /* [in] */ ClassID classId) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ClassUnloadFinished(
+ /* [in] */ ClassID classId,
+ /* [in] */ HRESULT hrStatus) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE FunctionUnloadStarted(
+ /* [in] */ FunctionID functionId) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE JITCompilationStarted(
+ /* [in] */ FunctionID functionId,
+ /* [in] */ BOOL fIsSafeToBlock) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE JITCompilationFinished(
+ /* [in] */ FunctionID functionId,
+ /* [in] */ HRESULT hrStatus,
+ /* [in] */ BOOL fIsSafeToBlock) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE JITCachedFunctionSearchStarted(
+ /* [in] */ FunctionID functionId,
+ /* [out] */ BOOL *pbUseCachedFunction) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE JITCachedFunctionSearchFinished(
+ /* [in] */ FunctionID functionId,
+ /* [in] */ COR_PRF_JIT_CACHE result) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE JITFunctionPitched(
+ /* [in] */ FunctionID functionId) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE JITInlining(
+ /* [in] */ FunctionID callerId,
+ /* [in] */ FunctionID calleeId,
+ /* [out] */ BOOL *pfShouldInline) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ThreadCreated(
+ /* [in] */ ThreadID threadId) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ThreadDestroyed(
+ /* [in] */ ThreadID threadId) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ThreadAssignedToOSThread(
+ /* [in] */ ThreadID managedThreadId,
+ /* [in] */ DWORD osThreadId) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE RemotingClientInvocationStarted( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE RemotingClientSendingMessage(
+ /* [in] */ GUID *pCookie,
+ /* [in] */ BOOL fIsAsync) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE RemotingClientReceivingReply(
+ /* [in] */ GUID *pCookie,
+ /* [in] */ BOOL fIsAsync) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE RemotingClientInvocationFinished( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE RemotingServerReceivingMessage(
+ /* [in] */ GUID *pCookie,
+ /* [in] */ BOOL fIsAsync) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE RemotingServerInvocationStarted( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE RemotingServerInvocationReturned( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE RemotingServerSendingReply(
+ /* [in] */ GUID *pCookie,
+ /* [in] */ BOOL fIsAsync) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE UnmanagedToManagedTransition(
+ /* [in] */ FunctionID functionId,
+ /* [in] */ COR_PRF_TRANSITION_REASON reason) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ManagedToUnmanagedTransition(
+ /* [in] */ FunctionID functionId,
+ /* [in] */ COR_PRF_TRANSITION_REASON reason) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE RuntimeSuspendStarted(
+ /* [in] */ COR_PRF_SUSPEND_REASON suspendReason) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE RuntimeSuspendFinished( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE RuntimeSuspendAborted( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE RuntimeResumeStarted( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE RuntimeResumeFinished( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE RuntimeThreadSuspended(
+ /* [in] */ ThreadID threadId) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE RuntimeThreadResumed(
+ /* [in] */ ThreadID threadId) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE MovedReferences(
+ /* [in] */ ULONG cMovedObjectIDRanges,
+ /* [size_is][in] */ ObjectID oldObjectIDRangeStart[ ],
+ /* [size_is][in] */ ObjectID newObjectIDRangeStart[ ],
+ /* [size_is][in] */ ULONG cObjectIDRangeLength[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ObjectAllocated(
+ /* [in] */ ObjectID objectId,
+ /* [in] */ ClassID classId) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ObjectsAllocatedByClass(
+ /* [in] */ ULONG cClassCount,
+ /* [size_is][in] */ ClassID classIds[ ],
+ /* [size_is][in] */ ULONG cObjects[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ObjectReferences(
+ /* [in] */ ObjectID objectId,
+ /* [in] */ ClassID classId,
+ /* [in] */ ULONG cObjectRefs,
+ /* [size_is][in] */ ObjectID objectRefIds[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE RootReferences(
+ /* [in] */ ULONG cRootRefs,
+ /* [size_is][in] */ ObjectID rootRefIds[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ExceptionThrown(
+ /* [in] */ ObjectID thrownObjectId) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ExceptionSearchFunctionEnter(
+ /* [in] */ FunctionID functionId) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ExceptionSearchFunctionLeave( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ExceptionSearchFilterEnter(
+ /* [in] */ FunctionID functionId) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ExceptionSearchFilterLeave( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ExceptionSearchCatcherFound(
+ /* [in] */ FunctionID functionId) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ExceptionOSHandlerEnter(
+ /* [in] */ UINT_PTR __unused) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ExceptionOSHandlerLeave(
+ /* [in] */ UINT_PTR __unused) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ExceptionUnwindFunctionEnter(
+ /* [in] */ FunctionID functionId) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ExceptionUnwindFunctionLeave( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ExceptionUnwindFinallyEnter(
+ /* [in] */ FunctionID functionId) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ExceptionUnwindFinallyLeave( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ExceptionCatcherEnter(
+ /* [in] */ FunctionID functionId,
+ /* [in] */ ObjectID objectId) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ExceptionCatcherLeave( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE COMClassicVTableCreated(
+ /* [in] */ ClassID wrappedClassId,
+ /* [in] */ REFGUID implementedIID,
+ /* [in] */ void *pVTable,
+ /* [in] */ ULONG cSlots) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE COMClassicVTableDestroyed(
+ /* [in] */ ClassID wrappedClassId,
+ /* [in] */ REFGUID implementedIID,
+ /* [in] */ void *pVTable) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ExceptionCLRCatcherFound( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ExceptionCLRCatcherExecute( void) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorProfilerCallbackVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorProfilerCallback * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorProfilerCallback * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorProfilerCallback * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Initialize )(
+ ICorProfilerCallback * This,
+ /* [in] */ IUnknown *pICorProfilerInfoUnk);
+
+ HRESULT ( STDMETHODCALLTYPE *Shutdown )(
+ ICorProfilerCallback * This);
+
+ HRESULT ( STDMETHODCALLTYPE *AppDomainCreationStarted )(
+ ICorProfilerCallback * This,
+ /* [in] */ AppDomainID appDomainId);
+
+ HRESULT ( STDMETHODCALLTYPE *AppDomainCreationFinished )(
+ ICorProfilerCallback * This,
+ /* [in] */ AppDomainID appDomainId,
+ /* [in] */ HRESULT hrStatus);
+
+ HRESULT ( STDMETHODCALLTYPE *AppDomainShutdownStarted )(
+ ICorProfilerCallback * This,
+ /* [in] */ AppDomainID appDomainId);
+
+ HRESULT ( STDMETHODCALLTYPE *AppDomainShutdownFinished )(
+ ICorProfilerCallback * This,
+ /* [in] */ AppDomainID appDomainId,
+ /* [in] */ HRESULT hrStatus);
+
+ HRESULT ( STDMETHODCALLTYPE *AssemblyLoadStarted )(
+ ICorProfilerCallback * This,
+ /* [in] */ AssemblyID assemblyId);
+
+ HRESULT ( STDMETHODCALLTYPE *AssemblyLoadFinished )(
+ ICorProfilerCallback * This,
+ /* [in] */ AssemblyID assemblyId,
+ /* [in] */ HRESULT hrStatus);
+
+ HRESULT ( STDMETHODCALLTYPE *AssemblyUnloadStarted )(
+ ICorProfilerCallback * This,
+ /* [in] */ AssemblyID assemblyId);
+
+ HRESULT ( STDMETHODCALLTYPE *AssemblyUnloadFinished )(
+ ICorProfilerCallback * This,
+ /* [in] */ AssemblyID assemblyId,
+ /* [in] */ HRESULT hrStatus);
+
+ HRESULT ( STDMETHODCALLTYPE *ModuleLoadStarted )(
+ ICorProfilerCallback * This,
+ /* [in] */ ModuleID moduleId);
+
+ HRESULT ( STDMETHODCALLTYPE *ModuleLoadFinished )(
+ ICorProfilerCallback * This,
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ HRESULT hrStatus);
+
+ HRESULT ( STDMETHODCALLTYPE *ModuleUnloadStarted )(
+ ICorProfilerCallback * This,
+ /* [in] */ ModuleID moduleId);
+
+ HRESULT ( STDMETHODCALLTYPE *ModuleUnloadFinished )(
+ ICorProfilerCallback * This,
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ HRESULT hrStatus);
+
+ HRESULT ( STDMETHODCALLTYPE *ModuleAttachedToAssembly )(
+ ICorProfilerCallback * This,
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ AssemblyID AssemblyId);
+
+ HRESULT ( STDMETHODCALLTYPE *ClassLoadStarted )(
+ ICorProfilerCallback * This,
+ /* [in] */ ClassID classId);
+
+ HRESULT ( STDMETHODCALLTYPE *ClassLoadFinished )(
+ ICorProfilerCallback * This,
+ /* [in] */ ClassID classId,
+ /* [in] */ HRESULT hrStatus);
+
+ HRESULT ( STDMETHODCALLTYPE *ClassUnloadStarted )(
+ ICorProfilerCallback * This,
+ /* [in] */ ClassID classId);
+
+ HRESULT ( STDMETHODCALLTYPE *ClassUnloadFinished )(
+ ICorProfilerCallback * This,
+ /* [in] */ ClassID classId,
+ /* [in] */ HRESULT hrStatus);
+
+ HRESULT ( STDMETHODCALLTYPE *FunctionUnloadStarted )(
+ ICorProfilerCallback * This,
+ /* [in] */ FunctionID functionId);
+
+ HRESULT ( STDMETHODCALLTYPE *JITCompilationStarted )(
+ ICorProfilerCallback * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ BOOL fIsSafeToBlock);
+
+ HRESULT ( STDMETHODCALLTYPE *JITCompilationFinished )(
+ ICorProfilerCallback * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ HRESULT hrStatus,
+ /* [in] */ BOOL fIsSafeToBlock);
+
+ HRESULT ( STDMETHODCALLTYPE *JITCachedFunctionSearchStarted )(
+ ICorProfilerCallback * This,
+ /* [in] */ FunctionID functionId,
+ /* [out] */ BOOL *pbUseCachedFunction);
+
+ HRESULT ( STDMETHODCALLTYPE *JITCachedFunctionSearchFinished )(
+ ICorProfilerCallback * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ COR_PRF_JIT_CACHE result);
+
+ HRESULT ( STDMETHODCALLTYPE *JITFunctionPitched )(
+ ICorProfilerCallback * This,
+ /* [in] */ FunctionID functionId);
+
+ HRESULT ( STDMETHODCALLTYPE *JITInlining )(
+ ICorProfilerCallback * This,
+ /* [in] */ FunctionID callerId,
+ /* [in] */ FunctionID calleeId,
+ /* [out] */ BOOL *pfShouldInline);
+
+ HRESULT ( STDMETHODCALLTYPE *ThreadCreated )(
+ ICorProfilerCallback * This,
+ /* [in] */ ThreadID threadId);
+
+ HRESULT ( STDMETHODCALLTYPE *ThreadDestroyed )(
+ ICorProfilerCallback * This,
+ /* [in] */ ThreadID threadId);
+
+ HRESULT ( STDMETHODCALLTYPE *ThreadAssignedToOSThread )(
+ ICorProfilerCallback * This,
+ /* [in] */ ThreadID managedThreadId,
+ /* [in] */ DWORD osThreadId);
+
+ HRESULT ( STDMETHODCALLTYPE *RemotingClientInvocationStarted )(
+ ICorProfilerCallback * This);
+
+ HRESULT ( STDMETHODCALLTYPE *RemotingClientSendingMessage )(
+ ICorProfilerCallback * This,
+ /* [in] */ GUID *pCookie,
+ /* [in] */ BOOL fIsAsync);
+
+ HRESULT ( STDMETHODCALLTYPE *RemotingClientReceivingReply )(
+ ICorProfilerCallback * This,
+ /* [in] */ GUID *pCookie,
+ /* [in] */ BOOL fIsAsync);
+
+ HRESULT ( STDMETHODCALLTYPE *RemotingClientInvocationFinished )(
+ ICorProfilerCallback * This);
+
+ HRESULT ( STDMETHODCALLTYPE *RemotingServerReceivingMessage )(
+ ICorProfilerCallback * This,
+ /* [in] */ GUID *pCookie,
+ /* [in] */ BOOL fIsAsync);
+
+ HRESULT ( STDMETHODCALLTYPE *RemotingServerInvocationStarted )(
+ ICorProfilerCallback * This);
+
+ HRESULT ( STDMETHODCALLTYPE *RemotingServerInvocationReturned )(
+ ICorProfilerCallback * This);
+
+ HRESULT ( STDMETHODCALLTYPE *RemotingServerSendingReply )(
+ ICorProfilerCallback * This,
+ /* [in] */ GUID *pCookie,
+ /* [in] */ BOOL fIsAsync);
+
+ HRESULT ( STDMETHODCALLTYPE *UnmanagedToManagedTransition )(
+ ICorProfilerCallback * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ COR_PRF_TRANSITION_REASON reason);
+
+ HRESULT ( STDMETHODCALLTYPE *ManagedToUnmanagedTransition )(
+ ICorProfilerCallback * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ COR_PRF_TRANSITION_REASON reason);
+
+ HRESULT ( STDMETHODCALLTYPE *RuntimeSuspendStarted )(
+ ICorProfilerCallback * This,
+ /* [in] */ COR_PRF_SUSPEND_REASON suspendReason);
+
+ HRESULT ( STDMETHODCALLTYPE *RuntimeSuspendFinished )(
+ ICorProfilerCallback * This);
+
+ HRESULT ( STDMETHODCALLTYPE *RuntimeSuspendAborted )(
+ ICorProfilerCallback * This);
+
+ HRESULT ( STDMETHODCALLTYPE *RuntimeResumeStarted )(
+ ICorProfilerCallback * This);
+
+ HRESULT ( STDMETHODCALLTYPE *RuntimeResumeFinished )(
+ ICorProfilerCallback * This);
+
+ HRESULT ( STDMETHODCALLTYPE *RuntimeThreadSuspended )(
+ ICorProfilerCallback * This,
+ /* [in] */ ThreadID threadId);
+
+ HRESULT ( STDMETHODCALLTYPE *RuntimeThreadResumed )(
+ ICorProfilerCallback * This,
+ /* [in] */ ThreadID threadId);
+
+ HRESULT ( STDMETHODCALLTYPE *MovedReferences )(
+ ICorProfilerCallback * This,
+ /* [in] */ ULONG cMovedObjectIDRanges,
+ /* [size_is][in] */ ObjectID oldObjectIDRangeStart[ ],
+ /* [size_is][in] */ ObjectID newObjectIDRangeStart[ ],
+ /* [size_is][in] */ ULONG cObjectIDRangeLength[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *ObjectAllocated )(
+ ICorProfilerCallback * This,
+ /* [in] */ ObjectID objectId,
+ /* [in] */ ClassID classId);
+
+ HRESULT ( STDMETHODCALLTYPE *ObjectsAllocatedByClass )(
+ ICorProfilerCallback * This,
+ /* [in] */ ULONG cClassCount,
+ /* [size_is][in] */ ClassID classIds[ ],
+ /* [size_is][in] */ ULONG cObjects[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *ObjectReferences )(
+ ICorProfilerCallback * This,
+ /* [in] */ ObjectID objectId,
+ /* [in] */ ClassID classId,
+ /* [in] */ ULONG cObjectRefs,
+ /* [size_is][in] */ ObjectID objectRefIds[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *RootReferences )(
+ ICorProfilerCallback * This,
+ /* [in] */ ULONG cRootRefs,
+ /* [size_is][in] */ ObjectID rootRefIds[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionThrown )(
+ ICorProfilerCallback * This,
+ /* [in] */ ObjectID thrownObjectId);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionSearchFunctionEnter )(
+ ICorProfilerCallback * This,
+ /* [in] */ FunctionID functionId);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionSearchFunctionLeave )(
+ ICorProfilerCallback * This);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionSearchFilterEnter )(
+ ICorProfilerCallback * This,
+ /* [in] */ FunctionID functionId);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionSearchFilterLeave )(
+ ICorProfilerCallback * This);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionSearchCatcherFound )(
+ ICorProfilerCallback * This,
+ /* [in] */ FunctionID functionId);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionOSHandlerEnter )(
+ ICorProfilerCallback * This,
+ /* [in] */ UINT_PTR __unused);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionOSHandlerLeave )(
+ ICorProfilerCallback * This,
+ /* [in] */ UINT_PTR __unused);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionUnwindFunctionEnter )(
+ ICorProfilerCallback * This,
+ /* [in] */ FunctionID functionId);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionUnwindFunctionLeave )(
+ ICorProfilerCallback * This);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionUnwindFinallyEnter )(
+ ICorProfilerCallback * This,
+ /* [in] */ FunctionID functionId);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionUnwindFinallyLeave )(
+ ICorProfilerCallback * This);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionCatcherEnter )(
+ ICorProfilerCallback * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ ObjectID objectId);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionCatcherLeave )(
+ ICorProfilerCallback * This);
+
+ HRESULT ( STDMETHODCALLTYPE *COMClassicVTableCreated )(
+ ICorProfilerCallback * This,
+ /* [in] */ ClassID wrappedClassId,
+ /* [in] */ REFGUID implementedIID,
+ /* [in] */ void *pVTable,
+ /* [in] */ ULONG cSlots);
+
+ HRESULT ( STDMETHODCALLTYPE *COMClassicVTableDestroyed )(
+ ICorProfilerCallback * This,
+ /* [in] */ ClassID wrappedClassId,
+ /* [in] */ REFGUID implementedIID,
+ /* [in] */ void *pVTable);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionCLRCatcherFound )(
+ ICorProfilerCallback * This);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionCLRCatcherExecute )(
+ ICorProfilerCallback * This);
+
+ END_INTERFACE
+ } ICorProfilerCallbackVtbl;
+
+ interface ICorProfilerCallback
+ {
+ CONST_VTBL struct ICorProfilerCallbackVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorProfilerCallback_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorProfilerCallback_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorProfilerCallback_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorProfilerCallback_Initialize(This,pICorProfilerInfoUnk) \
+ ( (This)->lpVtbl -> Initialize(This,pICorProfilerInfoUnk) )
+
+#define ICorProfilerCallback_Shutdown(This) \
+ ( (This)->lpVtbl -> Shutdown(This) )
+
+#define ICorProfilerCallback_AppDomainCreationStarted(This,appDomainId) \
+ ( (This)->lpVtbl -> AppDomainCreationStarted(This,appDomainId) )
+
+#define ICorProfilerCallback_AppDomainCreationFinished(This,appDomainId,hrStatus) \
+ ( (This)->lpVtbl -> AppDomainCreationFinished(This,appDomainId,hrStatus) )
+
+#define ICorProfilerCallback_AppDomainShutdownStarted(This,appDomainId) \
+ ( (This)->lpVtbl -> AppDomainShutdownStarted(This,appDomainId) )
+
+#define ICorProfilerCallback_AppDomainShutdownFinished(This,appDomainId,hrStatus) \
+ ( (This)->lpVtbl -> AppDomainShutdownFinished(This,appDomainId,hrStatus) )
+
+#define ICorProfilerCallback_AssemblyLoadStarted(This,assemblyId) \
+ ( (This)->lpVtbl -> AssemblyLoadStarted(This,assemblyId) )
+
+#define ICorProfilerCallback_AssemblyLoadFinished(This,assemblyId,hrStatus) \
+ ( (This)->lpVtbl -> AssemblyLoadFinished(This,assemblyId,hrStatus) )
+
+#define ICorProfilerCallback_AssemblyUnloadStarted(This,assemblyId) \
+ ( (This)->lpVtbl -> AssemblyUnloadStarted(This,assemblyId) )
+
+#define ICorProfilerCallback_AssemblyUnloadFinished(This,assemblyId,hrStatus) \
+ ( (This)->lpVtbl -> AssemblyUnloadFinished(This,assemblyId,hrStatus) )
+
+#define ICorProfilerCallback_ModuleLoadStarted(This,moduleId) \
+ ( (This)->lpVtbl -> ModuleLoadStarted(This,moduleId) )
+
+#define ICorProfilerCallback_ModuleLoadFinished(This,moduleId,hrStatus) \
+ ( (This)->lpVtbl -> ModuleLoadFinished(This,moduleId,hrStatus) )
+
+#define ICorProfilerCallback_ModuleUnloadStarted(This,moduleId) \
+ ( (This)->lpVtbl -> ModuleUnloadStarted(This,moduleId) )
+
+#define ICorProfilerCallback_ModuleUnloadFinished(This,moduleId,hrStatus) \
+ ( (This)->lpVtbl -> ModuleUnloadFinished(This,moduleId,hrStatus) )
+
+#define ICorProfilerCallback_ModuleAttachedToAssembly(This,moduleId,AssemblyId) \
+ ( (This)->lpVtbl -> ModuleAttachedToAssembly(This,moduleId,AssemblyId) )
+
+#define ICorProfilerCallback_ClassLoadStarted(This,classId) \
+ ( (This)->lpVtbl -> ClassLoadStarted(This,classId) )
+
+#define ICorProfilerCallback_ClassLoadFinished(This,classId,hrStatus) \
+ ( (This)->lpVtbl -> ClassLoadFinished(This,classId,hrStatus) )
+
+#define ICorProfilerCallback_ClassUnloadStarted(This,classId) \
+ ( (This)->lpVtbl -> ClassUnloadStarted(This,classId) )
+
+#define ICorProfilerCallback_ClassUnloadFinished(This,classId,hrStatus) \
+ ( (This)->lpVtbl -> ClassUnloadFinished(This,classId,hrStatus) )
+
+#define ICorProfilerCallback_FunctionUnloadStarted(This,functionId) \
+ ( (This)->lpVtbl -> FunctionUnloadStarted(This,functionId) )
+
+#define ICorProfilerCallback_JITCompilationStarted(This,functionId,fIsSafeToBlock) \
+ ( (This)->lpVtbl -> JITCompilationStarted(This,functionId,fIsSafeToBlock) )
+
+#define ICorProfilerCallback_JITCompilationFinished(This,functionId,hrStatus,fIsSafeToBlock) \
+ ( (This)->lpVtbl -> JITCompilationFinished(This,functionId,hrStatus,fIsSafeToBlock) )
+
+#define ICorProfilerCallback_JITCachedFunctionSearchStarted(This,functionId,pbUseCachedFunction) \
+ ( (This)->lpVtbl -> JITCachedFunctionSearchStarted(This,functionId,pbUseCachedFunction) )
+
+#define ICorProfilerCallback_JITCachedFunctionSearchFinished(This,functionId,result) \
+ ( (This)->lpVtbl -> JITCachedFunctionSearchFinished(This,functionId,result) )
+
+#define ICorProfilerCallback_JITFunctionPitched(This,functionId) \
+ ( (This)->lpVtbl -> JITFunctionPitched(This,functionId) )
+
+#define ICorProfilerCallback_JITInlining(This,callerId,calleeId,pfShouldInline) \
+ ( (This)->lpVtbl -> JITInlining(This,callerId,calleeId,pfShouldInline) )
+
+#define ICorProfilerCallback_ThreadCreated(This,threadId) \
+ ( (This)->lpVtbl -> ThreadCreated(This,threadId) )
+
+#define ICorProfilerCallback_ThreadDestroyed(This,threadId) \
+ ( (This)->lpVtbl -> ThreadDestroyed(This,threadId) )
+
+#define ICorProfilerCallback_ThreadAssignedToOSThread(This,managedThreadId,osThreadId) \
+ ( (This)->lpVtbl -> ThreadAssignedToOSThread(This,managedThreadId,osThreadId) )
+
+#define ICorProfilerCallback_RemotingClientInvocationStarted(This) \
+ ( (This)->lpVtbl -> RemotingClientInvocationStarted(This) )
+
+#define ICorProfilerCallback_RemotingClientSendingMessage(This,pCookie,fIsAsync) \
+ ( (This)->lpVtbl -> RemotingClientSendingMessage(This,pCookie,fIsAsync) )
+
+#define ICorProfilerCallback_RemotingClientReceivingReply(This,pCookie,fIsAsync) \
+ ( (This)->lpVtbl -> RemotingClientReceivingReply(This,pCookie,fIsAsync) )
+
+#define ICorProfilerCallback_RemotingClientInvocationFinished(This) \
+ ( (This)->lpVtbl -> RemotingClientInvocationFinished(This) )
+
+#define ICorProfilerCallback_RemotingServerReceivingMessage(This,pCookie,fIsAsync) \
+ ( (This)->lpVtbl -> RemotingServerReceivingMessage(This,pCookie,fIsAsync) )
+
+#define ICorProfilerCallback_RemotingServerInvocationStarted(This) \
+ ( (This)->lpVtbl -> RemotingServerInvocationStarted(This) )
+
+#define ICorProfilerCallback_RemotingServerInvocationReturned(This) \
+ ( (This)->lpVtbl -> RemotingServerInvocationReturned(This) )
+
+#define ICorProfilerCallback_RemotingServerSendingReply(This,pCookie,fIsAsync) \
+ ( (This)->lpVtbl -> RemotingServerSendingReply(This,pCookie,fIsAsync) )
+
+#define ICorProfilerCallback_UnmanagedToManagedTransition(This,functionId,reason) \
+ ( (This)->lpVtbl -> UnmanagedToManagedTransition(This,functionId,reason) )
+
+#define ICorProfilerCallback_ManagedToUnmanagedTransition(This,functionId,reason) \
+ ( (This)->lpVtbl -> ManagedToUnmanagedTransition(This,functionId,reason) )
+
+#define ICorProfilerCallback_RuntimeSuspendStarted(This,suspendReason) \
+ ( (This)->lpVtbl -> RuntimeSuspendStarted(This,suspendReason) )
+
+#define ICorProfilerCallback_RuntimeSuspendFinished(This) \
+ ( (This)->lpVtbl -> RuntimeSuspendFinished(This) )
+
+#define ICorProfilerCallback_RuntimeSuspendAborted(This) \
+ ( (This)->lpVtbl -> RuntimeSuspendAborted(This) )
+
+#define ICorProfilerCallback_RuntimeResumeStarted(This) \
+ ( (This)->lpVtbl -> RuntimeResumeStarted(This) )
+
+#define ICorProfilerCallback_RuntimeResumeFinished(This) \
+ ( (This)->lpVtbl -> RuntimeResumeFinished(This) )
+
+#define ICorProfilerCallback_RuntimeThreadSuspended(This,threadId) \
+ ( (This)->lpVtbl -> RuntimeThreadSuspended(This,threadId) )
+
+#define ICorProfilerCallback_RuntimeThreadResumed(This,threadId) \
+ ( (This)->lpVtbl -> RuntimeThreadResumed(This,threadId) )
+
+#define ICorProfilerCallback_MovedReferences(This,cMovedObjectIDRanges,oldObjectIDRangeStart,newObjectIDRangeStart,cObjectIDRangeLength) \
+ ( (This)->lpVtbl -> MovedReferences(This,cMovedObjectIDRanges,oldObjectIDRangeStart,newObjectIDRangeStart,cObjectIDRangeLength) )
+
+#define ICorProfilerCallback_ObjectAllocated(This,objectId,classId) \
+ ( (This)->lpVtbl -> ObjectAllocated(This,objectId,classId) )
+
+#define ICorProfilerCallback_ObjectsAllocatedByClass(This,cClassCount,classIds,cObjects) \
+ ( (This)->lpVtbl -> ObjectsAllocatedByClass(This,cClassCount,classIds,cObjects) )
+
+#define ICorProfilerCallback_ObjectReferences(This,objectId,classId,cObjectRefs,objectRefIds) \
+ ( (This)->lpVtbl -> ObjectReferences(This,objectId,classId,cObjectRefs,objectRefIds) )
+
+#define ICorProfilerCallback_RootReferences(This,cRootRefs,rootRefIds) \
+ ( (This)->lpVtbl -> RootReferences(This,cRootRefs,rootRefIds) )
+
+#define ICorProfilerCallback_ExceptionThrown(This,thrownObjectId) \
+ ( (This)->lpVtbl -> ExceptionThrown(This,thrownObjectId) )
+
+#define ICorProfilerCallback_ExceptionSearchFunctionEnter(This,functionId) \
+ ( (This)->lpVtbl -> ExceptionSearchFunctionEnter(This,functionId) )
+
+#define ICorProfilerCallback_ExceptionSearchFunctionLeave(This) \
+ ( (This)->lpVtbl -> ExceptionSearchFunctionLeave(This) )
+
+#define ICorProfilerCallback_ExceptionSearchFilterEnter(This,functionId) \
+ ( (This)->lpVtbl -> ExceptionSearchFilterEnter(This,functionId) )
+
+#define ICorProfilerCallback_ExceptionSearchFilterLeave(This) \
+ ( (This)->lpVtbl -> ExceptionSearchFilterLeave(This) )
+
+#define ICorProfilerCallback_ExceptionSearchCatcherFound(This,functionId) \
+ ( (This)->lpVtbl -> ExceptionSearchCatcherFound(This,functionId) )
+
+#define ICorProfilerCallback_ExceptionOSHandlerEnter(This,__unused) \
+ ( (This)->lpVtbl -> ExceptionOSHandlerEnter(This,__unused) )
+
+#define ICorProfilerCallback_ExceptionOSHandlerLeave(This,__unused) \
+ ( (This)->lpVtbl -> ExceptionOSHandlerLeave(This,__unused) )
+
+#define ICorProfilerCallback_ExceptionUnwindFunctionEnter(This,functionId) \
+ ( (This)->lpVtbl -> ExceptionUnwindFunctionEnter(This,functionId) )
+
+#define ICorProfilerCallback_ExceptionUnwindFunctionLeave(This) \
+ ( (This)->lpVtbl -> ExceptionUnwindFunctionLeave(This) )
+
+#define ICorProfilerCallback_ExceptionUnwindFinallyEnter(This,functionId) \
+ ( (This)->lpVtbl -> ExceptionUnwindFinallyEnter(This,functionId) )
+
+#define ICorProfilerCallback_ExceptionUnwindFinallyLeave(This) \
+ ( (This)->lpVtbl -> ExceptionUnwindFinallyLeave(This) )
+
+#define ICorProfilerCallback_ExceptionCatcherEnter(This,functionId,objectId) \
+ ( (This)->lpVtbl -> ExceptionCatcherEnter(This,functionId,objectId) )
+
+#define ICorProfilerCallback_ExceptionCatcherLeave(This) \
+ ( (This)->lpVtbl -> ExceptionCatcherLeave(This) )
+
+#define ICorProfilerCallback_COMClassicVTableCreated(This,wrappedClassId,implementedIID,pVTable,cSlots) \
+ ( (This)->lpVtbl -> COMClassicVTableCreated(This,wrappedClassId,implementedIID,pVTable,cSlots) )
+
+#define ICorProfilerCallback_COMClassicVTableDestroyed(This,wrappedClassId,implementedIID,pVTable) \
+ ( (This)->lpVtbl -> COMClassicVTableDestroyed(This,wrappedClassId,implementedIID,pVTable) )
+
+#define ICorProfilerCallback_ExceptionCLRCatcherFound(This) \
+ ( (This)->lpVtbl -> ExceptionCLRCatcherFound(This) )
+
+#define ICorProfilerCallback_ExceptionCLRCatcherExecute(This) \
+ ( (This)->lpVtbl -> ExceptionCLRCatcherExecute(This) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorProfilerCallback_INTERFACE_DEFINED__ */
+
+
+/* interface __MIDL_itf_corprof_0000_0001 */
+/* [local] */
+
+typedef /* [public][public] */
+enum __MIDL___MIDL_itf_corprof_0000_0001_0001
+ {
+ COR_PRF_GC_ROOT_STACK = 1,
+ COR_PRF_GC_ROOT_FINALIZER = 2,
+ COR_PRF_GC_ROOT_HANDLE = 3,
+ COR_PRF_GC_ROOT_OTHER = 0
+ } COR_PRF_GC_ROOT_KIND;
+
+typedef /* [public][public] */
+enum __MIDL___MIDL_itf_corprof_0000_0001_0002
+ {
+ COR_PRF_GC_ROOT_PINNING = 0x1,
+ COR_PRF_GC_ROOT_WEAKREF = 0x2,
+ COR_PRF_GC_ROOT_INTERIOR = 0x4,
+ COR_PRF_GC_ROOT_REFCOUNTED = 0x8
+ } COR_PRF_GC_ROOT_FLAGS;
+
+typedef /* [public] */
+enum __MIDL___MIDL_itf_corprof_0000_0001_0003
+ {
+ COR_PRF_FINALIZER_CRITICAL = 0x1
+ } COR_PRF_FINALIZER_FLAGS;
+
+typedef /* [public][public][public][public] */
+enum __MIDL___MIDL_itf_corprof_0000_0001_0004
+ {
+ COR_PRF_GC_GEN_0 = 0,
+ COR_PRF_GC_GEN_1 = 1,
+ COR_PRF_GC_GEN_2 = 2,
+ COR_PRF_GC_LARGE_OBJECT_HEAP = 3
+ } COR_PRF_GC_GENERATION;
+
+typedef struct COR_PRF_GC_GENERATION_RANGE
+ {
+ COR_PRF_GC_GENERATION generation;
+ ObjectID rangeStart;
+ UINT_PTR rangeLength;
+ UINT_PTR rangeLengthReserved;
+ } COR_PRF_GC_GENERATION_RANGE;
+
+typedef /* [public][public][public] */
+enum __MIDL___MIDL_itf_corprof_0000_0001_0005
+ {
+ COR_PRF_CLAUSE_NONE = 0,
+ COR_PRF_CLAUSE_FILTER = 1,
+ COR_PRF_CLAUSE_CATCH = 2,
+ COR_PRF_CLAUSE_FINALLY = 3
+ } COR_PRF_CLAUSE_TYPE;
+
+typedef struct COR_PRF_EX_CLAUSE_INFO
+ {
+ COR_PRF_CLAUSE_TYPE clauseType;
+ UINT_PTR programCounter;
+ UINT_PTR framePointer;
+ UINT_PTR shadowStackPointer;
+ } COR_PRF_EX_CLAUSE_INFO;
+
+typedef /* [public][public] */
+enum __MIDL___MIDL_itf_corprof_0000_0001_0006
+ {
+ COR_PRF_GC_INDUCED = 1,
+ COR_PRF_GC_OTHER = 0
+ } COR_PRF_GC_REASON;
+
+typedef /* [public] */
+enum __MIDL___MIDL_itf_corprof_0000_0001_0007
+ {
+ COR_PRF_MODULE_DISK = 0x1,
+ COR_PRF_MODULE_NGEN = 0x2,
+ COR_PRF_MODULE_DYNAMIC = 0x4,
+ COR_PRF_MODULE_COLLECTIBLE = 0x8,
+ COR_PRF_MODULE_RESOURCE = 0x10,
+ COR_PRF_MODULE_FLAT_LAYOUT = 0x20,
+ COR_PRF_MODULE_WINDOWS_RUNTIME = 0x40
+ } COR_PRF_MODULE_FLAGS;
+
+
+
+extern RPC_IF_HANDLE __MIDL_itf_corprof_0000_0001_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_corprof_0000_0001_v0_0_s_ifspec;
+
+#ifndef __ICorProfilerCallback2_INTERFACE_DEFINED__
+#define __ICorProfilerCallback2_INTERFACE_DEFINED__
+
+/* interface ICorProfilerCallback2 */
+/* [local][unique][uuid][object] */
+
+
+EXTERN_C const IID IID_ICorProfilerCallback2;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("8A8CC829-CCF2-49fe-BBAE-0F022228071A")
+ ICorProfilerCallback2 : public ICorProfilerCallback
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE ThreadNameChanged(
+ /* [in] */ ThreadID threadId,
+ /* [in] */ ULONG cchName,
+ /* [annotation][in] */
+ _In_reads_opt_(cchName) WCHAR name[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GarbageCollectionStarted(
+ /* [in] */ int cGenerations,
+ /* [size_is][in] */ BOOL generationCollected[ ],
+ /* [in] */ COR_PRF_GC_REASON reason) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SurvivingReferences(
+ /* [in] */ ULONG cSurvivingObjectIDRanges,
+ /* [size_is][in] */ ObjectID objectIDRangeStart[ ],
+ /* [size_is][in] */ ULONG cObjectIDRangeLength[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GarbageCollectionFinished( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE FinalizeableObjectQueued(
+ /* [in] */ DWORD finalizerFlags,
+ /* [in] */ ObjectID objectID) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE RootReferences2(
+ /* [in] */ ULONG cRootRefs,
+ /* [size_is][in] */ ObjectID rootRefIds[ ],
+ /* [size_is][in] */ COR_PRF_GC_ROOT_KIND rootKinds[ ],
+ /* [size_is][in] */ COR_PRF_GC_ROOT_FLAGS rootFlags[ ],
+ /* [size_is][in] */ UINT_PTR rootIds[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE HandleCreated(
+ /* [in] */ GCHandleID handleId,
+ /* [in] */ ObjectID initialObjectId) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE HandleDestroyed(
+ /* [in] */ GCHandleID handleId) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorProfilerCallback2Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorProfilerCallback2 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorProfilerCallback2 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorProfilerCallback2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Initialize )(
+ ICorProfilerCallback2 * This,
+ /* [in] */ IUnknown *pICorProfilerInfoUnk);
+
+ HRESULT ( STDMETHODCALLTYPE *Shutdown )(
+ ICorProfilerCallback2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *AppDomainCreationStarted )(
+ ICorProfilerCallback2 * This,
+ /* [in] */ AppDomainID appDomainId);
+
+ HRESULT ( STDMETHODCALLTYPE *AppDomainCreationFinished )(
+ ICorProfilerCallback2 * This,
+ /* [in] */ AppDomainID appDomainId,
+ /* [in] */ HRESULT hrStatus);
+
+ HRESULT ( STDMETHODCALLTYPE *AppDomainShutdownStarted )(
+ ICorProfilerCallback2 * This,
+ /* [in] */ AppDomainID appDomainId);
+
+ HRESULT ( STDMETHODCALLTYPE *AppDomainShutdownFinished )(
+ ICorProfilerCallback2 * This,
+ /* [in] */ AppDomainID appDomainId,
+ /* [in] */ HRESULT hrStatus);
+
+ HRESULT ( STDMETHODCALLTYPE *AssemblyLoadStarted )(
+ ICorProfilerCallback2 * This,
+ /* [in] */ AssemblyID assemblyId);
+
+ HRESULT ( STDMETHODCALLTYPE *AssemblyLoadFinished )(
+ ICorProfilerCallback2 * This,
+ /* [in] */ AssemblyID assemblyId,
+ /* [in] */ HRESULT hrStatus);
+
+ HRESULT ( STDMETHODCALLTYPE *AssemblyUnloadStarted )(
+ ICorProfilerCallback2 * This,
+ /* [in] */ AssemblyID assemblyId);
+
+ HRESULT ( STDMETHODCALLTYPE *AssemblyUnloadFinished )(
+ ICorProfilerCallback2 * This,
+ /* [in] */ AssemblyID assemblyId,
+ /* [in] */ HRESULT hrStatus);
+
+ HRESULT ( STDMETHODCALLTYPE *ModuleLoadStarted )(
+ ICorProfilerCallback2 * This,
+ /* [in] */ ModuleID moduleId);
+
+ HRESULT ( STDMETHODCALLTYPE *ModuleLoadFinished )(
+ ICorProfilerCallback2 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ HRESULT hrStatus);
+
+ HRESULT ( STDMETHODCALLTYPE *ModuleUnloadStarted )(
+ ICorProfilerCallback2 * This,
+ /* [in] */ ModuleID moduleId);
+
+ HRESULT ( STDMETHODCALLTYPE *ModuleUnloadFinished )(
+ ICorProfilerCallback2 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ HRESULT hrStatus);
+
+ HRESULT ( STDMETHODCALLTYPE *ModuleAttachedToAssembly )(
+ ICorProfilerCallback2 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ AssemblyID AssemblyId);
+
+ HRESULT ( STDMETHODCALLTYPE *ClassLoadStarted )(
+ ICorProfilerCallback2 * This,
+ /* [in] */ ClassID classId);
+
+ HRESULT ( STDMETHODCALLTYPE *ClassLoadFinished )(
+ ICorProfilerCallback2 * This,
+ /* [in] */ ClassID classId,
+ /* [in] */ HRESULT hrStatus);
+
+ HRESULT ( STDMETHODCALLTYPE *ClassUnloadStarted )(
+ ICorProfilerCallback2 * This,
+ /* [in] */ ClassID classId);
+
+ HRESULT ( STDMETHODCALLTYPE *ClassUnloadFinished )(
+ ICorProfilerCallback2 * This,
+ /* [in] */ ClassID classId,
+ /* [in] */ HRESULT hrStatus);
+
+ HRESULT ( STDMETHODCALLTYPE *FunctionUnloadStarted )(
+ ICorProfilerCallback2 * This,
+ /* [in] */ FunctionID functionId);
+
+ HRESULT ( STDMETHODCALLTYPE *JITCompilationStarted )(
+ ICorProfilerCallback2 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ BOOL fIsSafeToBlock);
+
+ HRESULT ( STDMETHODCALLTYPE *JITCompilationFinished )(
+ ICorProfilerCallback2 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ HRESULT hrStatus,
+ /* [in] */ BOOL fIsSafeToBlock);
+
+ HRESULT ( STDMETHODCALLTYPE *JITCachedFunctionSearchStarted )(
+ ICorProfilerCallback2 * This,
+ /* [in] */ FunctionID functionId,
+ /* [out] */ BOOL *pbUseCachedFunction);
+
+ HRESULT ( STDMETHODCALLTYPE *JITCachedFunctionSearchFinished )(
+ ICorProfilerCallback2 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ COR_PRF_JIT_CACHE result);
+
+ HRESULT ( STDMETHODCALLTYPE *JITFunctionPitched )(
+ ICorProfilerCallback2 * This,
+ /* [in] */ FunctionID functionId);
+
+ HRESULT ( STDMETHODCALLTYPE *JITInlining )(
+ ICorProfilerCallback2 * This,
+ /* [in] */ FunctionID callerId,
+ /* [in] */ FunctionID calleeId,
+ /* [out] */ BOOL *pfShouldInline);
+
+ HRESULT ( STDMETHODCALLTYPE *ThreadCreated )(
+ ICorProfilerCallback2 * This,
+ /* [in] */ ThreadID threadId);
+
+ HRESULT ( STDMETHODCALLTYPE *ThreadDestroyed )(
+ ICorProfilerCallback2 * This,
+ /* [in] */ ThreadID threadId);
+
+ HRESULT ( STDMETHODCALLTYPE *ThreadAssignedToOSThread )(
+ ICorProfilerCallback2 * This,
+ /* [in] */ ThreadID managedThreadId,
+ /* [in] */ DWORD osThreadId);
+
+ HRESULT ( STDMETHODCALLTYPE *RemotingClientInvocationStarted )(
+ ICorProfilerCallback2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *RemotingClientSendingMessage )(
+ ICorProfilerCallback2 * This,
+ /* [in] */ GUID *pCookie,
+ /* [in] */ BOOL fIsAsync);
+
+ HRESULT ( STDMETHODCALLTYPE *RemotingClientReceivingReply )(
+ ICorProfilerCallback2 * This,
+ /* [in] */ GUID *pCookie,
+ /* [in] */ BOOL fIsAsync);
+
+ HRESULT ( STDMETHODCALLTYPE *RemotingClientInvocationFinished )(
+ ICorProfilerCallback2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *RemotingServerReceivingMessage )(
+ ICorProfilerCallback2 * This,
+ /* [in] */ GUID *pCookie,
+ /* [in] */ BOOL fIsAsync);
+
+ HRESULT ( STDMETHODCALLTYPE *RemotingServerInvocationStarted )(
+ ICorProfilerCallback2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *RemotingServerInvocationReturned )(
+ ICorProfilerCallback2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *RemotingServerSendingReply )(
+ ICorProfilerCallback2 * This,
+ /* [in] */ GUID *pCookie,
+ /* [in] */ BOOL fIsAsync);
+
+ HRESULT ( STDMETHODCALLTYPE *UnmanagedToManagedTransition )(
+ ICorProfilerCallback2 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ COR_PRF_TRANSITION_REASON reason);
+
+ HRESULT ( STDMETHODCALLTYPE *ManagedToUnmanagedTransition )(
+ ICorProfilerCallback2 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ COR_PRF_TRANSITION_REASON reason);
+
+ HRESULT ( STDMETHODCALLTYPE *RuntimeSuspendStarted )(
+ ICorProfilerCallback2 * This,
+ /* [in] */ COR_PRF_SUSPEND_REASON suspendReason);
+
+ HRESULT ( STDMETHODCALLTYPE *RuntimeSuspendFinished )(
+ ICorProfilerCallback2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *RuntimeSuspendAborted )(
+ ICorProfilerCallback2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *RuntimeResumeStarted )(
+ ICorProfilerCallback2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *RuntimeResumeFinished )(
+ ICorProfilerCallback2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *RuntimeThreadSuspended )(
+ ICorProfilerCallback2 * This,
+ /* [in] */ ThreadID threadId);
+
+ HRESULT ( STDMETHODCALLTYPE *RuntimeThreadResumed )(
+ ICorProfilerCallback2 * This,
+ /* [in] */ ThreadID threadId);
+
+ HRESULT ( STDMETHODCALLTYPE *MovedReferences )(
+ ICorProfilerCallback2 * This,
+ /* [in] */ ULONG cMovedObjectIDRanges,
+ /* [size_is][in] */ ObjectID oldObjectIDRangeStart[ ],
+ /* [size_is][in] */ ObjectID newObjectIDRangeStart[ ],
+ /* [size_is][in] */ ULONG cObjectIDRangeLength[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *ObjectAllocated )(
+ ICorProfilerCallback2 * This,
+ /* [in] */ ObjectID objectId,
+ /* [in] */ ClassID classId);
+
+ HRESULT ( STDMETHODCALLTYPE *ObjectsAllocatedByClass )(
+ ICorProfilerCallback2 * This,
+ /* [in] */ ULONG cClassCount,
+ /* [size_is][in] */ ClassID classIds[ ],
+ /* [size_is][in] */ ULONG cObjects[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *ObjectReferences )(
+ ICorProfilerCallback2 * This,
+ /* [in] */ ObjectID objectId,
+ /* [in] */ ClassID classId,
+ /* [in] */ ULONG cObjectRefs,
+ /* [size_is][in] */ ObjectID objectRefIds[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *RootReferences )(
+ ICorProfilerCallback2 * This,
+ /* [in] */ ULONG cRootRefs,
+ /* [size_is][in] */ ObjectID rootRefIds[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionThrown )(
+ ICorProfilerCallback2 * This,
+ /* [in] */ ObjectID thrownObjectId);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionSearchFunctionEnter )(
+ ICorProfilerCallback2 * This,
+ /* [in] */ FunctionID functionId);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionSearchFunctionLeave )(
+ ICorProfilerCallback2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionSearchFilterEnter )(
+ ICorProfilerCallback2 * This,
+ /* [in] */ FunctionID functionId);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionSearchFilterLeave )(
+ ICorProfilerCallback2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionSearchCatcherFound )(
+ ICorProfilerCallback2 * This,
+ /* [in] */ FunctionID functionId);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionOSHandlerEnter )(
+ ICorProfilerCallback2 * This,
+ /* [in] */ UINT_PTR __unused);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionOSHandlerLeave )(
+ ICorProfilerCallback2 * This,
+ /* [in] */ UINT_PTR __unused);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionUnwindFunctionEnter )(
+ ICorProfilerCallback2 * This,
+ /* [in] */ FunctionID functionId);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionUnwindFunctionLeave )(
+ ICorProfilerCallback2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionUnwindFinallyEnter )(
+ ICorProfilerCallback2 * This,
+ /* [in] */ FunctionID functionId);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionUnwindFinallyLeave )(
+ ICorProfilerCallback2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionCatcherEnter )(
+ ICorProfilerCallback2 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ ObjectID objectId);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionCatcherLeave )(
+ ICorProfilerCallback2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *COMClassicVTableCreated )(
+ ICorProfilerCallback2 * This,
+ /* [in] */ ClassID wrappedClassId,
+ /* [in] */ REFGUID implementedIID,
+ /* [in] */ void *pVTable,
+ /* [in] */ ULONG cSlots);
+
+ HRESULT ( STDMETHODCALLTYPE *COMClassicVTableDestroyed )(
+ ICorProfilerCallback2 * This,
+ /* [in] */ ClassID wrappedClassId,
+ /* [in] */ REFGUID implementedIID,
+ /* [in] */ void *pVTable);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionCLRCatcherFound )(
+ ICorProfilerCallback2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionCLRCatcherExecute )(
+ ICorProfilerCallback2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *ThreadNameChanged )(
+ ICorProfilerCallback2 * This,
+ /* [in] */ ThreadID threadId,
+ /* [in] */ ULONG cchName,
+ /* [annotation][in] */
+ _In_reads_opt_(cchName) WCHAR name[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GarbageCollectionStarted )(
+ ICorProfilerCallback2 * This,
+ /* [in] */ int cGenerations,
+ /* [size_is][in] */ BOOL generationCollected[ ],
+ /* [in] */ COR_PRF_GC_REASON reason);
+
+ HRESULT ( STDMETHODCALLTYPE *SurvivingReferences )(
+ ICorProfilerCallback2 * This,
+ /* [in] */ ULONG cSurvivingObjectIDRanges,
+ /* [size_is][in] */ ObjectID objectIDRangeStart[ ],
+ /* [size_is][in] */ ULONG cObjectIDRangeLength[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GarbageCollectionFinished )(
+ ICorProfilerCallback2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *FinalizeableObjectQueued )(
+ ICorProfilerCallback2 * This,
+ /* [in] */ DWORD finalizerFlags,
+ /* [in] */ ObjectID objectID);
+
+ HRESULT ( STDMETHODCALLTYPE *RootReferences2 )(
+ ICorProfilerCallback2 * This,
+ /* [in] */ ULONG cRootRefs,
+ /* [size_is][in] */ ObjectID rootRefIds[ ],
+ /* [size_is][in] */ COR_PRF_GC_ROOT_KIND rootKinds[ ],
+ /* [size_is][in] */ COR_PRF_GC_ROOT_FLAGS rootFlags[ ],
+ /* [size_is][in] */ UINT_PTR rootIds[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *HandleCreated )(
+ ICorProfilerCallback2 * This,
+ /* [in] */ GCHandleID handleId,
+ /* [in] */ ObjectID initialObjectId);
+
+ HRESULT ( STDMETHODCALLTYPE *HandleDestroyed )(
+ ICorProfilerCallback2 * This,
+ /* [in] */ GCHandleID handleId);
+
+ END_INTERFACE
+ } ICorProfilerCallback2Vtbl;
+
+ interface ICorProfilerCallback2
+ {
+ CONST_VTBL struct ICorProfilerCallback2Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorProfilerCallback2_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorProfilerCallback2_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorProfilerCallback2_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorProfilerCallback2_Initialize(This,pICorProfilerInfoUnk) \
+ ( (This)->lpVtbl -> Initialize(This,pICorProfilerInfoUnk) )
+
+#define ICorProfilerCallback2_Shutdown(This) \
+ ( (This)->lpVtbl -> Shutdown(This) )
+
+#define ICorProfilerCallback2_AppDomainCreationStarted(This,appDomainId) \
+ ( (This)->lpVtbl -> AppDomainCreationStarted(This,appDomainId) )
+
+#define ICorProfilerCallback2_AppDomainCreationFinished(This,appDomainId,hrStatus) \
+ ( (This)->lpVtbl -> AppDomainCreationFinished(This,appDomainId,hrStatus) )
+
+#define ICorProfilerCallback2_AppDomainShutdownStarted(This,appDomainId) \
+ ( (This)->lpVtbl -> AppDomainShutdownStarted(This,appDomainId) )
+
+#define ICorProfilerCallback2_AppDomainShutdownFinished(This,appDomainId,hrStatus) \
+ ( (This)->lpVtbl -> AppDomainShutdownFinished(This,appDomainId,hrStatus) )
+
+#define ICorProfilerCallback2_AssemblyLoadStarted(This,assemblyId) \
+ ( (This)->lpVtbl -> AssemblyLoadStarted(This,assemblyId) )
+
+#define ICorProfilerCallback2_AssemblyLoadFinished(This,assemblyId,hrStatus) \
+ ( (This)->lpVtbl -> AssemblyLoadFinished(This,assemblyId,hrStatus) )
+
+#define ICorProfilerCallback2_AssemblyUnloadStarted(This,assemblyId) \
+ ( (This)->lpVtbl -> AssemblyUnloadStarted(This,assemblyId) )
+
+#define ICorProfilerCallback2_AssemblyUnloadFinished(This,assemblyId,hrStatus) \
+ ( (This)->lpVtbl -> AssemblyUnloadFinished(This,assemblyId,hrStatus) )
+
+#define ICorProfilerCallback2_ModuleLoadStarted(This,moduleId) \
+ ( (This)->lpVtbl -> ModuleLoadStarted(This,moduleId) )
+
+#define ICorProfilerCallback2_ModuleLoadFinished(This,moduleId,hrStatus) \
+ ( (This)->lpVtbl -> ModuleLoadFinished(This,moduleId,hrStatus) )
+
+#define ICorProfilerCallback2_ModuleUnloadStarted(This,moduleId) \
+ ( (This)->lpVtbl -> ModuleUnloadStarted(This,moduleId) )
+
+#define ICorProfilerCallback2_ModuleUnloadFinished(This,moduleId,hrStatus) \
+ ( (This)->lpVtbl -> ModuleUnloadFinished(This,moduleId,hrStatus) )
+
+#define ICorProfilerCallback2_ModuleAttachedToAssembly(This,moduleId,AssemblyId) \
+ ( (This)->lpVtbl -> ModuleAttachedToAssembly(This,moduleId,AssemblyId) )
+
+#define ICorProfilerCallback2_ClassLoadStarted(This,classId) \
+ ( (This)->lpVtbl -> ClassLoadStarted(This,classId) )
+
+#define ICorProfilerCallback2_ClassLoadFinished(This,classId,hrStatus) \
+ ( (This)->lpVtbl -> ClassLoadFinished(This,classId,hrStatus) )
+
+#define ICorProfilerCallback2_ClassUnloadStarted(This,classId) \
+ ( (This)->lpVtbl -> ClassUnloadStarted(This,classId) )
+
+#define ICorProfilerCallback2_ClassUnloadFinished(This,classId,hrStatus) \
+ ( (This)->lpVtbl -> ClassUnloadFinished(This,classId,hrStatus) )
+
+#define ICorProfilerCallback2_FunctionUnloadStarted(This,functionId) \
+ ( (This)->lpVtbl -> FunctionUnloadStarted(This,functionId) )
+
+#define ICorProfilerCallback2_JITCompilationStarted(This,functionId,fIsSafeToBlock) \
+ ( (This)->lpVtbl -> JITCompilationStarted(This,functionId,fIsSafeToBlock) )
+
+#define ICorProfilerCallback2_JITCompilationFinished(This,functionId,hrStatus,fIsSafeToBlock) \
+ ( (This)->lpVtbl -> JITCompilationFinished(This,functionId,hrStatus,fIsSafeToBlock) )
+
+#define ICorProfilerCallback2_JITCachedFunctionSearchStarted(This,functionId,pbUseCachedFunction) \
+ ( (This)->lpVtbl -> JITCachedFunctionSearchStarted(This,functionId,pbUseCachedFunction) )
+
+#define ICorProfilerCallback2_JITCachedFunctionSearchFinished(This,functionId,result) \
+ ( (This)->lpVtbl -> JITCachedFunctionSearchFinished(This,functionId,result) )
+
+#define ICorProfilerCallback2_JITFunctionPitched(This,functionId) \
+ ( (This)->lpVtbl -> JITFunctionPitched(This,functionId) )
+
+#define ICorProfilerCallback2_JITInlining(This,callerId,calleeId,pfShouldInline) \
+ ( (This)->lpVtbl -> JITInlining(This,callerId,calleeId,pfShouldInline) )
+
+#define ICorProfilerCallback2_ThreadCreated(This,threadId) \
+ ( (This)->lpVtbl -> ThreadCreated(This,threadId) )
+
+#define ICorProfilerCallback2_ThreadDestroyed(This,threadId) \
+ ( (This)->lpVtbl -> ThreadDestroyed(This,threadId) )
+
+#define ICorProfilerCallback2_ThreadAssignedToOSThread(This,managedThreadId,osThreadId) \
+ ( (This)->lpVtbl -> ThreadAssignedToOSThread(This,managedThreadId,osThreadId) )
+
+#define ICorProfilerCallback2_RemotingClientInvocationStarted(This) \
+ ( (This)->lpVtbl -> RemotingClientInvocationStarted(This) )
+
+#define ICorProfilerCallback2_RemotingClientSendingMessage(This,pCookie,fIsAsync) \
+ ( (This)->lpVtbl -> RemotingClientSendingMessage(This,pCookie,fIsAsync) )
+
+#define ICorProfilerCallback2_RemotingClientReceivingReply(This,pCookie,fIsAsync) \
+ ( (This)->lpVtbl -> RemotingClientReceivingReply(This,pCookie,fIsAsync) )
+
+#define ICorProfilerCallback2_RemotingClientInvocationFinished(This) \
+ ( (This)->lpVtbl -> RemotingClientInvocationFinished(This) )
+
+#define ICorProfilerCallback2_RemotingServerReceivingMessage(This,pCookie,fIsAsync) \
+ ( (This)->lpVtbl -> RemotingServerReceivingMessage(This,pCookie,fIsAsync) )
+
+#define ICorProfilerCallback2_RemotingServerInvocationStarted(This) \
+ ( (This)->lpVtbl -> RemotingServerInvocationStarted(This) )
+
+#define ICorProfilerCallback2_RemotingServerInvocationReturned(This) \
+ ( (This)->lpVtbl -> RemotingServerInvocationReturned(This) )
+
+#define ICorProfilerCallback2_RemotingServerSendingReply(This,pCookie,fIsAsync) \
+ ( (This)->lpVtbl -> RemotingServerSendingReply(This,pCookie,fIsAsync) )
+
+#define ICorProfilerCallback2_UnmanagedToManagedTransition(This,functionId,reason) \
+ ( (This)->lpVtbl -> UnmanagedToManagedTransition(This,functionId,reason) )
+
+#define ICorProfilerCallback2_ManagedToUnmanagedTransition(This,functionId,reason) \
+ ( (This)->lpVtbl -> ManagedToUnmanagedTransition(This,functionId,reason) )
+
+#define ICorProfilerCallback2_RuntimeSuspendStarted(This,suspendReason) \
+ ( (This)->lpVtbl -> RuntimeSuspendStarted(This,suspendReason) )
+
+#define ICorProfilerCallback2_RuntimeSuspendFinished(This) \
+ ( (This)->lpVtbl -> RuntimeSuspendFinished(This) )
+
+#define ICorProfilerCallback2_RuntimeSuspendAborted(This) \
+ ( (This)->lpVtbl -> RuntimeSuspendAborted(This) )
+
+#define ICorProfilerCallback2_RuntimeResumeStarted(This) \
+ ( (This)->lpVtbl -> RuntimeResumeStarted(This) )
+
+#define ICorProfilerCallback2_RuntimeResumeFinished(This) \
+ ( (This)->lpVtbl -> RuntimeResumeFinished(This) )
+
+#define ICorProfilerCallback2_RuntimeThreadSuspended(This,threadId) \
+ ( (This)->lpVtbl -> RuntimeThreadSuspended(This,threadId) )
+
+#define ICorProfilerCallback2_RuntimeThreadResumed(This,threadId) \
+ ( (This)->lpVtbl -> RuntimeThreadResumed(This,threadId) )
+
+#define ICorProfilerCallback2_MovedReferences(This,cMovedObjectIDRanges,oldObjectIDRangeStart,newObjectIDRangeStart,cObjectIDRangeLength) \
+ ( (This)->lpVtbl -> MovedReferences(This,cMovedObjectIDRanges,oldObjectIDRangeStart,newObjectIDRangeStart,cObjectIDRangeLength) )
+
+#define ICorProfilerCallback2_ObjectAllocated(This,objectId,classId) \
+ ( (This)->lpVtbl -> ObjectAllocated(This,objectId,classId) )
+
+#define ICorProfilerCallback2_ObjectsAllocatedByClass(This,cClassCount,classIds,cObjects) \
+ ( (This)->lpVtbl -> ObjectsAllocatedByClass(This,cClassCount,classIds,cObjects) )
+
+#define ICorProfilerCallback2_ObjectReferences(This,objectId,classId,cObjectRefs,objectRefIds) \
+ ( (This)->lpVtbl -> ObjectReferences(This,objectId,classId,cObjectRefs,objectRefIds) )
+
+#define ICorProfilerCallback2_RootReferences(This,cRootRefs,rootRefIds) \
+ ( (This)->lpVtbl -> RootReferences(This,cRootRefs,rootRefIds) )
+
+#define ICorProfilerCallback2_ExceptionThrown(This,thrownObjectId) \
+ ( (This)->lpVtbl -> ExceptionThrown(This,thrownObjectId) )
+
+#define ICorProfilerCallback2_ExceptionSearchFunctionEnter(This,functionId) \
+ ( (This)->lpVtbl -> ExceptionSearchFunctionEnter(This,functionId) )
+
+#define ICorProfilerCallback2_ExceptionSearchFunctionLeave(This) \
+ ( (This)->lpVtbl -> ExceptionSearchFunctionLeave(This) )
+
+#define ICorProfilerCallback2_ExceptionSearchFilterEnter(This,functionId) \
+ ( (This)->lpVtbl -> ExceptionSearchFilterEnter(This,functionId) )
+
+#define ICorProfilerCallback2_ExceptionSearchFilterLeave(This) \
+ ( (This)->lpVtbl -> ExceptionSearchFilterLeave(This) )
+
+#define ICorProfilerCallback2_ExceptionSearchCatcherFound(This,functionId) \
+ ( (This)->lpVtbl -> ExceptionSearchCatcherFound(This,functionId) )
+
+#define ICorProfilerCallback2_ExceptionOSHandlerEnter(This,__unused) \
+ ( (This)->lpVtbl -> ExceptionOSHandlerEnter(This,__unused) )
+
+#define ICorProfilerCallback2_ExceptionOSHandlerLeave(This,__unused) \
+ ( (This)->lpVtbl -> ExceptionOSHandlerLeave(This,__unused) )
+
+#define ICorProfilerCallback2_ExceptionUnwindFunctionEnter(This,functionId) \
+ ( (This)->lpVtbl -> ExceptionUnwindFunctionEnter(This,functionId) )
+
+#define ICorProfilerCallback2_ExceptionUnwindFunctionLeave(This) \
+ ( (This)->lpVtbl -> ExceptionUnwindFunctionLeave(This) )
+
+#define ICorProfilerCallback2_ExceptionUnwindFinallyEnter(This,functionId) \
+ ( (This)->lpVtbl -> ExceptionUnwindFinallyEnter(This,functionId) )
+
+#define ICorProfilerCallback2_ExceptionUnwindFinallyLeave(This) \
+ ( (This)->lpVtbl -> ExceptionUnwindFinallyLeave(This) )
+
+#define ICorProfilerCallback2_ExceptionCatcherEnter(This,functionId,objectId) \
+ ( (This)->lpVtbl -> ExceptionCatcherEnter(This,functionId,objectId) )
+
+#define ICorProfilerCallback2_ExceptionCatcherLeave(This) \
+ ( (This)->lpVtbl -> ExceptionCatcherLeave(This) )
+
+#define ICorProfilerCallback2_COMClassicVTableCreated(This,wrappedClassId,implementedIID,pVTable,cSlots) \
+ ( (This)->lpVtbl -> COMClassicVTableCreated(This,wrappedClassId,implementedIID,pVTable,cSlots) )
+
+#define ICorProfilerCallback2_COMClassicVTableDestroyed(This,wrappedClassId,implementedIID,pVTable) \
+ ( (This)->lpVtbl -> COMClassicVTableDestroyed(This,wrappedClassId,implementedIID,pVTable) )
+
+#define ICorProfilerCallback2_ExceptionCLRCatcherFound(This) \
+ ( (This)->lpVtbl -> ExceptionCLRCatcherFound(This) )
+
+#define ICorProfilerCallback2_ExceptionCLRCatcherExecute(This) \
+ ( (This)->lpVtbl -> ExceptionCLRCatcherExecute(This) )
+
+
+#define ICorProfilerCallback2_ThreadNameChanged(This,threadId,cchName,name) \
+ ( (This)->lpVtbl -> ThreadNameChanged(This,threadId,cchName,name) )
+
+#define ICorProfilerCallback2_GarbageCollectionStarted(This,cGenerations,generationCollected,reason) \
+ ( (This)->lpVtbl -> GarbageCollectionStarted(This,cGenerations,generationCollected,reason) )
+
+#define ICorProfilerCallback2_SurvivingReferences(This,cSurvivingObjectIDRanges,objectIDRangeStart,cObjectIDRangeLength) \
+ ( (This)->lpVtbl -> SurvivingReferences(This,cSurvivingObjectIDRanges,objectIDRangeStart,cObjectIDRangeLength) )
+
+#define ICorProfilerCallback2_GarbageCollectionFinished(This) \
+ ( (This)->lpVtbl -> GarbageCollectionFinished(This) )
+
+#define ICorProfilerCallback2_FinalizeableObjectQueued(This,finalizerFlags,objectID) \
+ ( (This)->lpVtbl -> FinalizeableObjectQueued(This,finalizerFlags,objectID) )
+
+#define ICorProfilerCallback2_RootReferences2(This,cRootRefs,rootRefIds,rootKinds,rootFlags,rootIds) \
+ ( (This)->lpVtbl -> RootReferences2(This,cRootRefs,rootRefIds,rootKinds,rootFlags,rootIds) )
+
+#define ICorProfilerCallback2_HandleCreated(This,handleId,initialObjectId) \
+ ( (This)->lpVtbl -> HandleCreated(This,handleId,initialObjectId) )
+
+#define ICorProfilerCallback2_HandleDestroyed(This,handleId) \
+ ( (This)->lpVtbl -> HandleDestroyed(This,handleId) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorProfilerCallback2_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorProfilerCallback3_INTERFACE_DEFINED__
+#define __ICorProfilerCallback3_INTERFACE_DEFINED__
+
+/* interface ICorProfilerCallback3 */
+/* [local][unique][uuid][object] */
+
+
+EXTERN_C const IID IID_ICorProfilerCallback3;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("4FD2ED52-7731-4b8d-9469-03D2CC3086C5")
+ ICorProfilerCallback3 : public ICorProfilerCallback2
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE InitializeForAttach(
+ /* [in] */ IUnknown *pCorProfilerInfoUnk,
+ /* [in] */ void *pvClientData,
+ /* [in] */ UINT cbClientData) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ProfilerAttachComplete( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ProfilerDetachSucceeded( void) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorProfilerCallback3Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorProfilerCallback3 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorProfilerCallback3 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorProfilerCallback3 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Initialize )(
+ ICorProfilerCallback3 * This,
+ /* [in] */ IUnknown *pICorProfilerInfoUnk);
+
+ HRESULT ( STDMETHODCALLTYPE *Shutdown )(
+ ICorProfilerCallback3 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *AppDomainCreationStarted )(
+ ICorProfilerCallback3 * This,
+ /* [in] */ AppDomainID appDomainId);
+
+ HRESULT ( STDMETHODCALLTYPE *AppDomainCreationFinished )(
+ ICorProfilerCallback3 * This,
+ /* [in] */ AppDomainID appDomainId,
+ /* [in] */ HRESULT hrStatus);
+
+ HRESULT ( STDMETHODCALLTYPE *AppDomainShutdownStarted )(
+ ICorProfilerCallback3 * This,
+ /* [in] */ AppDomainID appDomainId);
+
+ HRESULT ( STDMETHODCALLTYPE *AppDomainShutdownFinished )(
+ ICorProfilerCallback3 * This,
+ /* [in] */ AppDomainID appDomainId,
+ /* [in] */ HRESULT hrStatus);
+
+ HRESULT ( STDMETHODCALLTYPE *AssemblyLoadStarted )(
+ ICorProfilerCallback3 * This,
+ /* [in] */ AssemblyID assemblyId);
+
+ HRESULT ( STDMETHODCALLTYPE *AssemblyLoadFinished )(
+ ICorProfilerCallback3 * This,
+ /* [in] */ AssemblyID assemblyId,
+ /* [in] */ HRESULT hrStatus);
+
+ HRESULT ( STDMETHODCALLTYPE *AssemblyUnloadStarted )(
+ ICorProfilerCallback3 * This,
+ /* [in] */ AssemblyID assemblyId);
+
+ HRESULT ( STDMETHODCALLTYPE *AssemblyUnloadFinished )(
+ ICorProfilerCallback3 * This,
+ /* [in] */ AssemblyID assemblyId,
+ /* [in] */ HRESULT hrStatus);
+
+ HRESULT ( STDMETHODCALLTYPE *ModuleLoadStarted )(
+ ICorProfilerCallback3 * This,
+ /* [in] */ ModuleID moduleId);
+
+ HRESULT ( STDMETHODCALLTYPE *ModuleLoadFinished )(
+ ICorProfilerCallback3 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ HRESULT hrStatus);
+
+ HRESULT ( STDMETHODCALLTYPE *ModuleUnloadStarted )(
+ ICorProfilerCallback3 * This,
+ /* [in] */ ModuleID moduleId);
+
+ HRESULT ( STDMETHODCALLTYPE *ModuleUnloadFinished )(
+ ICorProfilerCallback3 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ HRESULT hrStatus);
+
+ HRESULT ( STDMETHODCALLTYPE *ModuleAttachedToAssembly )(
+ ICorProfilerCallback3 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ AssemblyID AssemblyId);
+
+ HRESULT ( STDMETHODCALLTYPE *ClassLoadStarted )(
+ ICorProfilerCallback3 * This,
+ /* [in] */ ClassID classId);
+
+ HRESULT ( STDMETHODCALLTYPE *ClassLoadFinished )(
+ ICorProfilerCallback3 * This,
+ /* [in] */ ClassID classId,
+ /* [in] */ HRESULT hrStatus);
+
+ HRESULT ( STDMETHODCALLTYPE *ClassUnloadStarted )(
+ ICorProfilerCallback3 * This,
+ /* [in] */ ClassID classId);
+
+ HRESULT ( STDMETHODCALLTYPE *ClassUnloadFinished )(
+ ICorProfilerCallback3 * This,
+ /* [in] */ ClassID classId,
+ /* [in] */ HRESULT hrStatus);
+
+ HRESULT ( STDMETHODCALLTYPE *FunctionUnloadStarted )(
+ ICorProfilerCallback3 * This,
+ /* [in] */ FunctionID functionId);
+
+ HRESULT ( STDMETHODCALLTYPE *JITCompilationStarted )(
+ ICorProfilerCallback3 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ BOOL fIsSafeToBlock);
+
+ HRESULT ( STDMETHODCALLTYPE *JITCompilationFinished )(
+ ICorProfilerCallback3 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ HRESULT hrStatus,
+ /* [in] */ BOOL fIsSafeToBlock);
+
+ HRESULT ( STDMETHODCALLTYPE *JITCachedFunctionSearchStarted )(
+ ICorProfilerCallback3 * This,
+ /* [in] */ FunctionID functionId,
+ /* [out] */ BOOL *pbUseCachedFunction);
+
+ HRESULT ( STDMETHODCALLTYPE *JITCachedFunctionSearchFinished )(
+ ICorProfilerCallback3 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ COR_PRF_JIT_CACHE result);
+
+ HRESULT ( STDMETHODCALLTYPE *JITFunctionPitched )(
+ ICorProfilerCallback3 * This,
+ /* [in] */ FunctionID functionId);
+
+ HRESULT ( STDMETHODCALLTYPE *JITInlining )(
+ ICorProfilerCallback3 * This,
+ /* [in] */ FunctionID callerId,
+ /* [in] */ FunctionID calleeId,
+ /* [out] */ BOOL *pfShouldInline);
+
+ HRESULT ( STDMETHODCALLTYPE *ThreadCreated )(
+ ICorProfilerCallback3 * This,
+ /* [in] */ ThreadID threadId);
+
+ HRESULT ( STDMETHODCALLTYPE *ThreadDestroyed )(
+ ICorProfilerCallback3 * This,
+ /* [in] */ ThreadID threadId);
+
+ HRESULT ( STDMETHODCALLTYPE *ThreadAssignedToOSThread )(
+ ICorProfilerCallback3 * This,
+ /* [in] */ ThreadID managedThreadId,
+ /* [in] */ DWORD osThreadId);
+
+ HRESULT ( STDMETHODCALLTYPE *RemotingClientInvocationStarted )(
+ ICorProfilerCallback3 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *RemotingClientSendingMessage )(
+ ICorProfilerCallback3 * This,
+ /* [in] */ GUID *pCookie,
+ /* [in] */ BOOL fIsAsync);
+
+ HRESULT ( STDMETHODCALLTYPE *RemotingClientReceivingReply )(
+ ICorProfilerCallback3 * This,
+ /* [in] */ GUID *pCookie,
+ /* [in] */ BOOL fIsAsync);
+
+ HRESULT ( STDMETHODCALLTYPE *RemotingClientInvocationFinished )(
+ ICorProfilerCallback3 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *RemotingServerReceivingMessage )(
+ ICorProfilerCallback3 * This,
+ /* [in] */ GUID *pCookie,
+ /* [in] */ BOOL fIsAsync);
+
+ HRESULT ( STDMETHODCALLTYPE *RemotingServerInvocationStarted )(
+ ICorProfilerCallback3 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *RemotingServerInvocationReturned )(
+ ICorProfilerCallback3 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *RemotingServerSendingReply )(
+ ICorProfilerCallback3 * This,
+ /* [in] */ GUID *pCookie,
+ /* [in] */ BOOL fIsAsync);
+
+ HRESULT ( STDMETHODCALLTYPE *UnmanagedToManagedTransition )(
+ ICorProfilerCallback3 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ COR_PRF_TRANSITION_REASON reason);
+
+ HRESULT ( STDMETHODCALLTYPE *ManagedToUnmanagedTransition )(
+ ICorProfilerCallback3 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ COR_PRF_TRANSITION_REASON reason);
+
+ HRESULT ( STDMETHODCALLTYPE *RuntimeSuspendStarted )(
+ ICorProfilerCallback3 * This,
+ /* [in] */ COR_PRF_SUSPEND_REASON suspendReason);
+
+ HRESULT ( STDMETHODCALLTYPE *RuntimeSuspendFinished )(
+ ICorProfilerCallback3 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *RuntimeSuspendAborted )(
+ ICorProfilerCallback3 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *RuntimeResumeStarted )(
+ ICorProfilerCallback3 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *RuntimeResumeFinished )(
+ ICorProfilerCallback3 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *RuntimeThreadSuspended )(
+ ICorProfilerCallback3 * This,
+ /* [in] */ ThreadID threadId);
+
+ HRESULT ( STDMETHODCALLTYPE *RuntimeThreadResumed )(
+ ICorProfilerCallback3 * This,
+ /* [in] */ ThreadID threadId);
+
+ HRESULT ( STDMETHODCALLTYPE *MovedReferences )(
+ ICorProfilerCallback3 * This,
+ /* [in] */ ULONG cMovedObjectIDRanges,
+ /* [size_is][in] */ ObjectID oldObjectIDRangeStart[ ],
+ /* [size_is][in] */ ObjectID newObjectIDRangeStart[ ],
+ /* [size_is][in] */ ULONG cObjectIDRangeLength[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *ObjectAllocated )(
+ ICorProfilerCallback3 * This,
+ /* [in] */ ObjectID objectId,
+ /* [in] */ ClassID classId);
+
+ HRESULT ( STDMETHODCALLTYPE *ObjectsAllocatedByClass )(
+ ICorProfilerCallback3 * This,
+ /* [in] */ ULONG cClassCount,
+ /* [size_is][in] */ ClassID classIds[ ],
+ /* [size_is][in] */ ULONG cObjects[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *ObjectReferences )(
+ ICorProfilerCallback3 * This,
+ /* [in] */ ObjectID objectId,
+ /* [in] */ ClassID classId,
+ /* [in] */ ULONG cObjectRefs,
+ /* [size_is][in] */ ObjectID objectRefIds[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *RootReferences )(
+ ICorProfilerCallback3 * This,
+ /* [in] */ ULONG cRootRefs,
+ /* [size_is][in] */ ObjectID rootRefIds[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionThrown )(
+ ICorProfilerCallback3 * This,
+ /* [in] */ ObjectID thrownObjectId);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionSearchFunctionEnter )(
+ ICorProfilerCallback3 * This,
+ /* [in] */ FunctionID functionId);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionSearchFunctionLeave )(
+ ICorProfilerCallback3 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionSearchFilterEnter )(
+ ICorProfilerCallback3 * This,
+ /* [in] */ FunctionID functionId);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionSearchFilterLeave )(
+ ICorProfilerCallback3 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionSearchCatcherFound )(
+ ICorProfilerCallback3 * This,
+ /* [in] */ FunctionID functionId);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionOSHandlerEnter )(
+ ICorProfilerCallback3 * This,
+ /* [in] */ UINT_PTR __unused);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionOSHandlerLeave )(
+ ICorProfilerCallback3 * This,
+ /* [in] */ UINT_PTR __unused);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionUnwindFunctionEnter )(
+ ICorProfilerCallback3 * This,
+ /* [in] */ FunctionID functionId);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionUnwindFunctionLeave )(
+ ICorProfilerCallback3 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionUnwindFinallyEnter )(
+ ICorProfilerCallback3 * This,
+ /* [in] */ FunctionID functionId);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionUnwindFinallyLeave )(
+ ICorProfilerCallback3 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionCatcherEnter )(
+ ICorProfilerCallback3 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ ObjectID objectId);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionCatcherLeave )(
+ ICorProfilerCallback3 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *COMClassicVTableCreated )(
+ ICorProfilerCallback3 * This,
+ /* [in] */ ClassID wrappedClassId,
+ /* [in] */ REFGUID implementedIID,
+ /* [in] */ void *pVTable,
+ /* [in] */ ULONG cSlots);
+
+ HRESULT ( STDMETHODCALLTYPE *COMClassicVTableDestroyed )(
+ ICorProfilerCallback3 * This,
+ /* [in] */ ClassID wrappedClassId,
+ /* [in] */ REFGUID implementedIID,
+ /* [in] */ void *pVTable);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionCLRCatcherFound )(
+ ICorProfilerCallback3 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionCLRCatcherExecute )(
+ ICorProfilerCallback3 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *ThreadNameChanged )(
+ ICorProfilerCallback3 * This,
+ /* [in] */ ThreadID threadId,
+ /* [in] */ ULONG cchName,
+ /* [annotation][in] */
+ _In_reads_opt_(cchName) WCHAR name[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GarbageCollectionStarted )(
+ ICorProfilerCallback3 * This,
+ /* [in] */ int cGenerations,
+ /* [size_is][in] */ BOOL generationCollected[ ],
+ /* [in] */ COR_PRF_GC_REASON reason);
+
+ HRESULT ( STDMETHODCALLTYPE *SurvivingReferences )(
+ ICorProfilerCallback3 * This,
+ /* [in] */ ULONG cSurvivingObjectIDRanges,
+ /* [size_is][in] */ ObjectID objectIDRangeStart[ ],
+ /* [size_is][in] */ ULONG cObjectIDRangeLength[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GarbageCollectionFinished )(
+ ICorProfilerCallback3 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *FinalizeableObjectQueued )(
+ ICorProfilerCallback3 * This,
+ /* [in] */ DWORD finalizerFlags,
+ /* [in] */ ObjectID objectID);
+
+ HRESULT ( STDMETHODCALLTYPE *RootReferences2 )(
+ ICorProfilerCallback3 * This,
+ /* [in] */ ULONG cRootRefs,
+ /* [size_is][in] */ ObjectID rootRefIds[ ],
+ /* [size_is][in] */ COR_PRF_GC_ROOT_KIND rootKinds[ ],
+ /* [size_is][in] */ COR_PRF_GC_ROOT_FLAGS rootFlags[ ],
+ /* [size_is][in] */ UINT_PTR rootIds[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *HandleCreated )(
+ ICorProfilerCallback3 * This,
+ /* [in] */ GCHandleID handleId,
+ /* [in] */ ObjectID initialObjectId);
+
+ HRESULT ( STDMETHODCALLTYPE *HandleDestroyed )(
+ ICorProfilerCallback3 * This,
+ /* [in] */ GCHandleID handleId);
+
+ HRESULT ( STDMETHODCALLTYPE *InitializeForAttach )(
+ ICorProfilerCallback3 * This,
+ /* [in] */ IUnknown *pCorProfilerInfoUnk,
+ /* [in] */ void *pvClientData,
+ /* [in] */ UINT cbClientData);
+
+ HRESULT ( STDMETHODCALLTYPE *ProfilerAttachComplete )(
+ ICorProfilerCallback3 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *ProfilerDetachSucceeded )(
+ ICorProfilerCallback3 * This);
+
+ END_INTERFACE
+ } ICorProfilerCallback3Vtbl;
+
+ interface ICorProfilerCallback3
+ {
+ CONST_VTBL struct ICorProfilerCallback3Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorProfilerCallback3_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorProfilerCallback3_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorProfilerCallback3_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorProfilerCallback3_Initialize(This,pICorProfilerInfoUnk) \
+ ( (This)->lpVtbl -> Initialize(This,pICorProfilerInfoUnk) )
+
+#define ICorProfilerCallback3_Shutdown(This) \
+ ( (This)->lpVtbl -> Shutdown(This) )
+
+#define ICorProfilerCallback3_AppDomainCreationStarted(This,appDomainId) \
+ ( (This)->lpVtbl -> AppDomainCreationStarted(This,appDomainId) )
+
+#define ICorProfilerCallback3_AppDomainCreationFinished(This,appDomainId,hrStatus) \
+ ( (This)->lpVtbl -> AppDomainCreationFinished(This,appDomainId,hrStatus) )
+
+#define ICorProfilerCallback3_AppDomainShutdownStarted(This,appDomainId) \
+ ( (This)->lpVtbl -> AppDomainShutdownStarted(This,appDomainId) )
+
+#define ICorProfilerCallback3_AppDomainShutdownFinished(This,appDomainId,hrStatus) \
+ ( (This)->lpVtbl -> AppDomainShutdownFinished(This,appDomainId,hrStatus) )
+
+#define ICorProfilerCallback3_AssemblyLoadStarted(This,assemblyId) \
+ ( (This)->lpVtbl -> AssemblyLoadStarted(This,assemblyId) )
+
+#define ICorProfilerCallback3_AssemblyLoadFinished(This,assemblyId,hrStatus) \
+ ( (This)->lpVtbl -> AssemblyLoadFinished(This,assemblyId,hrStatus) )
+
+#define ICorProfilerCallback3_AssemblyUnloadStarted(This,assemblyId) \
+ ( (This)->lpVtbl -> AssemblyUnloadStarted(This,assemblyId) )
+
+#define ICorProfilerCallback3_AssemblyUnloadFinished(This,assemblyId,hrStatus) \
+ ( (This)->lpVtbl -> AssemblyUnloadFinished(This,assemblyId,hrStatus) )
+
+#define ICorProfilerCallback3_ModuleLoadStarted(This,moduleId) \
+ ( (This)->lpVtbl -> ModuleLoadStarted(This,moduleId) )
+
+#define ICorProfilerCallback3_ModuleLoadFinished(This,moduleId,hrStatus) \
+ ( (This)->lpVtbl -> ModuleLoadFinished(This,moduleId,hrStatus) )
+
+#define ICorProfilerCallback3_ModuleUnloadStarted(This,moduleId) \
+ ( (This)->lpVtbl -> ModuleUnloadStarted(This,moduleId) )
+
+#define ICorProfilerCallback3_ModuleUnloadFinished(This,moduleId,hrStatus) \
+ ( (This)->lpVtbl -> ModuleUnloadFinished(This,moduleId,hrStatus) )
+
+#define ICorProfilerCallback3_ModuleAttachedToAssembly(This,moduleId,AssemblyId) \
+ ( (This)->lpVtbl -> ModuleAttachedToAssembly(This,moduleId,AssemblyId) )
+
+#define ICorProfilerCallback3_ClassLoadStarted(This,classId) \
+ ( (This)->lpVtbl -> ClassLoadStarted(This,classId) )
+
+#define ICorProfilerCallback3_ClassLoadFinished(This,classId,hrStatus) \
+ ( (This)->lpVtbl -> ClassLoadFinished(This,classId,hrStatus) )
+
+#define ICorProfilerCallback3_ClassUnloadStarted(This,classId) \
+ ( (This)->lpVtbl -> ClassUnloadStarted(This,classId) )
+
+#define ICorProfilerCallback3_ClassUnloadFinished(This,classId,hrStatus) \
+ ( (This)->lpVtbl -> ClassUnloadFinished(This,classId,hrStatus) )
+
+#define ICorProfilerCallback3_FunctionUnloadStarted(This,functionId) \
+ ( (This)->lpVtbl -> FunctionUnloadStarted(This,functionId) )
+
+#define ICorProfilerCallback3_JITCompilationStarted(This,functionId,fIsSafeToBlock) \
+ ( (This)->lpVtbl -> JITCompilationStarted(This,functionId,fIsSafeToBlock) )
+
+#define ICorProfilerCallback3_JITCompilationFinished(This,functionId,hrStatus,fIsSafeToBlock) \
+ ( (This)->lpVtbl -> JITCompilationFinished(This,functionId,hrStatus,fIsSafeToBlock) )
+
+#define ICorProfilerCallback3_JITCachedFunctionSearchStarted(This,functionId,pbUseCachedFunction) \
+ ( (This)->lpVtbl -> JITCachedFunctionSearchStarted(This,functionId,pbUseCachedFunction) )
+
+#define ICorProfilerCallback3_JITCachedFunctionSearchFinished(This,functionId,result) \
+ ( (This)->lpVtbl -> JITCachedFunctionSearchFinished(This,functionId,result) )
+
+#define ICorProfilerCallback3_JITFunctionPitched(This,functionId) \
+ ( (This)->lpVtbl -> JITFunctionPitched(This,functionId) )
+
+#define ICorProfilerCallback3_JITInlining(This,callerId,calleeId,pfShouldInline) \
+ ( (This)->lpVtbl -> JITInlining(This,callerId,calleeId,pfShouldInline) )
+
+#define ICorProfilerCallback3_ThreadCreated(This,threadId) \
+ ( (This)->lpVtbl -> ThreadCreated(This,threadId) )
+
+#define ICorProfilerCallback3_ThreadDestroyed(This,threadId) \
+ ( (This)->lpVtbl -> ThreadDestroyed(This,threadId) )
+
+#define ICorProfilerCallback3_ThreadAssignedToOSThread(This,managedThreadId,osThreadId) \
+ ( (This)->lpVtbl -> ThreadAssignedToOSThread(This,managedThreadId,osThreadId) )
+
+#define ICorProfilerCallback3_RemotingClientInvocationStarted(This) \
+ ( (This)->lpVtbl -> RemotingClientInvocationStarted(This) )
+
+#define ICorProfilerCallback3_RemotingClientSendingMessage(This,pCookie,fIsAsync) \
+ ( (This)->lpVtbl -> RemotingClientSendingMessage(This,pCookie,fIsAsync) )
+
+#define ICorProfilerCallback3_RemotingClientReceivingReply(This,pCookie,fIsAsync) \
+ ( (This)->lpVtbl -> RemotingClientReceivingReply(This,pCookie,fIsAsync) )
+
+#define ICorProfilerCallback3_RemotingClientInvocationFinished(This) \
+ ( (This)->lpVtbl -> RemotingClientInvocationFinished(This) )
+
+#define ICorProfilerCallback3_RemotingServerReceivingMessage(This,pCookie,fIsAsync) \
+ ( (This)->lpVtbl -> RemotingServerReceivingMessage(This,pCookie,fIsAsync) )
+
+#define ICorProfilerCallback3_RemotingServerInvocationStarted(This) \
+ ( (This)->lpVtbl -> RemotingServerInvocationStarted(This) )
+
+#define ICorProfilerCallback3_RemotingServerInvocationReturned(This) \
+ ( (This)->lpVtbl -> RemotingServerInvocationReturned(This) )
+
+#define ICorProfilerCallback3_RemotingServerSendingReply(This,pCookie,fIsAsync) \
+ ( (This)->lpVtbl -> RemotingServerSendingReply(This,pCookie,fIsAsync) )
+
+#define ICorProfilerCallback3_UnmanagedToManagedTransition(This,functionId,reason) \
+ ( (This)->lpVtbl -> UnmanagedToManagedTransition(This,functionId,reason) )
+
+#define ICorProfilerCallback3_ManagedToUnmanagedTransition(This,functionId,reason) \
+ ( (This)->lpVtbl -> ManagedToUnmanagedTransition(This,functionId,reason) )
+
+#define ICorProfilerCallback3_RuntimeSuspendStarted(This,suspendReason) \
+ ( (This)->lpVtbl -> RuntimeSuspendStarted(This,suspendReason) )
+
+#define ICorProfilerCallback3_RuntimeSuspendFinished(This) \
+ ( (This)->lpVtbl -> RuntimeSuspendFinished(This) )
+
+#define ICorProfilerCallback3_RuntimeSuspendAborted(This) \
+ ( (This)->lpVtbl -> RuntimeSuspendAborted(This) )
+
+#define ICorProfilerCallback3_RuntimeResumeStarted(This) \
+ ( (This)->lpVtbl -> RuntimeResumeStarted(This) )
+
+#define ICorProfilerCallback3_RuntimeResumeFinished(This) \
+ ( (This)->lpVtbl -> RuntimeResumeFinished(This) )
+
+#define ICorProfilerCallback3_RuntimeThreadSuspended(This,threadId) \
+ ( (This)->lpVtbl -> RuntimeThreadSuspended(This,threadId) )
+
+#define ICorProfilerCallback3_RuntimeThreadResumed(This,threadId) \
+ ( (This)->lpVtbl -> RuntimeThreadResumed(This,threadId) )
+
+#define ICorProfilerCallback3_MovedReferences(This,cMovedObjectIDRanges,oldObjectIDRangeStart,newObjectIDRangeStart,cObjectIDRangeLength) \
+ ( (This)->lpVtbl -> MovedReferences(This,cMovedObjectIDRanges,oldObjectIDRangeStart,newObjectIDRangeStart,cObjectIDRangeLength) )
+
+#define ICorProfilerCallback3_ObjectAllocated(This,objectId,classId) \
+ ( (This)->lpVtbl -> ObjectAllocated(This,objectId,classId) )
+
+#define ICorProfilerCallback3_ObjectsAllocatedByClass(This,cClassCount,classIds,cObjects) \
+ ( (This)->lpVtbl -> ObjectsAllocatedByClass(This,cClassCount,classIds,cObjects) )
+
+#define ICorProfilerCallback3_ObjectReferences(This,objectId,classId,cObjectRefs,objectRefIds) \
+ ( (This)->lpVtbl -> ObjectReferences(This,objectId,classId,cObjectRefs,objectRefIds) )
+
+#define ICorProfilerCallback3_RootReferences(This,cRootRefs,rootRefIds) \
+ ( (This)->lpVtbl -> RootReferences(This,cRootRefs,rootRefIds) )
+
+#define ICorProfilerCallback3_ExceptionThrown(This,thrownObjectId) \
+ ( (This)->lpVtbl -> ExceptionThrown(This,thrownObjectId) )
+
+#define ICorProfilerCallback3_ExceptionSearchFunctionEnter(This,functionId) \
+ ( (This)->lpVtbl -> ExceptionSearchFunctionEnter(This,functionId) )
+
+#define ICorProfilerCallback3_ExceptionSearchFunctionLeave(This) \
+ ( (This)->lpVtbl -> ExceptionSearchFunctionLeave(This) )
+
+#define ICorProfilerCallback3_ExceptionSearchFilterEnter(This,functionId) \
+ ( (This)->lpVtbl -> ExceptionSearchFilterEnter(This,functionId) )
+
+#define ICorProfilerCallback3_ExceptionSearchFilterLeave(This) \
+ ( (This)->lpVtbl -> ExceptionSearchFilterLeave(This) )
+
+#define ICorProfilerCallback3_ExceptionSearchCatcherFound(This,functionId) \
+ ( (This)->lpVtbl -> ExceptionSearchCatcherFound(This,functionId) )
+
+#define ICorProfilerCallback3_ExceptionOSHandlerEnter(This,__unused) \
+ ( (This)->lpVtbl -> ExceptionOSHandlerEnter(This,__unused) )
+
+#define ICorProfilerCallback3_ExceptionOSHandlerLeave(This,__unused) \
+ ( (This)->lpVtbl -> ExceptionOSHandlerLeave(This,__unused) )
+
+#define ICorProfilerCallback3_ExceptionUnwindFunctionEnter(This,functionId) \
+ ( (This)->lpVtbl -> ExceptionUnwindFunctionEnter(This,functionId) )
+
+#define ICorProfilerCallback3_ExceptionUnwindFunctionLeave(This) \
+ ( (This)->lpVtbl -> ExceptionUnwindFunctionLeave(This) )
+
+#define ICorProfilerCallback3_ExceptionUnwindFinallyEnter(This,functionId) \
+ ( (This)->lpVtbl -> ExceptionUnwindFinallyEnter(This,functionId) )
+
+#define ICorProfilerCallback3_ExceptionUnwindFinallyLeave(This) \
+ ( (This)->lpVtbl -> ExceptionUnwindFinallyLeave(This) )
+
+#define ICorProfilerCallback3_ExceptionCatcherEnter(This,functionId,objectId) \
+ ( (This)->lpVtbl -> ExceptionCatcherEnter(This,functionId,objectId) )
+
+#define ICorProfilerCallback3_ExceptionCatcherLeave(This) \
+ ( (This)->lpVtbl -> ExceptionCatcherLeave(This) )
+
+#define ICorProfilerCallback3_COMClassicVTableCreated(This,wrappedClassId,implementedIID,pVTable,cSlots) \
+ ( (This)->lpVtbl -> COMClassicVTableCreated(This,wrappedClassId,implementedIID,pVTable,cSlots) )
+
+#define ICorProfilerCallback3_COMClassicVTableDestroyed(This,wrappedClassId,implementedIID,pVTable) \
+ ( (This)->lpVtbl -> COMClassicVTableDestroyed(This,wrappedClassId,implementedIID,pVTable) )
+
+#define ICorProfilerCallback3_ExceptionCLRCatcherFound(This) \
+ ( (This)->lpVtbl -> ExceptionCLRCatcherFound(This) )
+
+#define ICorProfilerCallback3_ExceptionCLRCatcherExecute(This) \
+ ( (This)->lpVtbl -> ExceptionCLRCatcherExecute(This) )
+
+
+#define ICorProfilerCallback3_ThreadNameChanged(This,threadId,cchName,name) \
+ ( (This)->lpVtbl -> ThreadNameChanged(This,threadId,cchName,name) )
+
+#define ICorProfilerCallback3_GarbageCollectionStarted(This,cGenerations,generationCollected,reason) \
+ ( (This)->lpVtbl -> GarbageCollectionStarted(This,cGenerations,generationCollected,reason) )
+
+#define ICorProfilerCallback3_SurvivingReferences(This,cSurvivingObjectIDRanges,objectIDRangeStart,cObjectIDRangeLength) \
+ ( (This)->lpVtbl -> SurvivingReferences(This,cSurvivingObjectIDRanges,objectIDRangeStart,cObjectIDRangeLength) )
+
+#define ICorProfilerCallback3_GarbageCollectionFinished(This) \
+ ( (This)->lpVtbl -> GarbageCollectionFinished(This) )
+
+#define ICorProfilerCallback3_FinalizeableObjectQueued(This,finalizerFlags,objectID) \
+ ( (This)->lpVtbl -> FinalizeableObjectQueued(This,finalizerFlags,objectID) )
+
+#define ICorProfilerCallback3_RootReferences2(This,cRootRefs,rootRefIds,rootKinds,rootFlags,rootIds) \
+ ( (This)->lpVtbl -> RootReferences2(This,cRootRefs,rootRefIds,rootKinds,rootFlags,rootIds) )
+
+#define ICorProfilerCallback3_HandleCreated(This,handleId,initialObjectId) \
+ ( (This)->lpVtbl -> HandleCreated(This,handleId,initialObjectId) )
+
+#define ICorProfilerCallback3_HandleDestroyed(This,handleId) \
+ ( (This)->lpVtbl -> HandleDestroyed(This,handleId) )
+
+
+#define ICorProfilerCallback3_InitializeForAttach(This,pCorProfilerInfoUnk,pvClientData,cbClientData) \
+ ( (This)->lpVtbl -> InitializeForAttach(This,pCorProfilerInfoUnk,pvClientData,cbClientData) )
+
+#define ICorProfilerCallback3_ProfilerAttachComplete(This) \
+ ( (This)->lpVtbl -> ProfilerAttachComplete(This) )
+
+#define ICorProfilerCallback3_ProfilerDetachSucceeded(This) \
+ ( (This)->lpVtbl -> ProfilerDetachSucceeded(This) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorProfilerCallback3_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorProfilerCallback4_INTERFACE_DEFINED__
+#define __ICorProfilerCallback4_INTERFACE_DEFINED__
+
+/* interface ICorProfilerCallback4 */
+/* [local][unique][uuid][object] */
+
+
+EXTERN_C const IID IID_ICorProfilerCallback4;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("7B63B2E3-107D-4d48-B2F6-F61E229470D2")
+ ICorProfilerCallback4 : public ICorProfilerCallback3
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE ReJITCompilationStarted(
+ /* [in] */ FunctionID functionId,
+ /* [in] */ ReJITID rejitId,
+ /* [in] */ BOOL fIsSafeToBlock) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetReJITParameters(
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ mdMethodDef methodId,
+ /* [in] */ ICorProfilerFunctionControl *pFunctionControl) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ReJITCompilationFinished(
+ /* [in] */ FunctionID functionId,
+ /* [in] */ ReJITID rejitId,
+ /* [in] */ HRESULT hrStatus,
+ /* [in] */ BOOL fIsSafeToBlock) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ReJITError(
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ mdMethodDef methodId,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ HRESULT hrStatus) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE MovedReferences2(
+ /* [in] */ ULONG cMovedObjectIDRanges,
+ /* [size_is][in] */ ObjectID oldObjectIDRangeStart[ ],
+ /* [size_is][in] */ ObjectID newObjectIDRangeStart[ ],
+ /* [size_is][in] */ SIZE_T cObjectIDRangeLength[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SurvivingReferences2(
+ /* [in] */ ULONG cSurvivingObjectIDRanges,
+ /* [size_is][in] */ ObjectID objectIDRangeStart[ ],
+ /* [size_is][in] */ SIZE_T cObjectIDRangeLength[ ]) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorProfilerCallback4Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorProfilerCallback4 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorProfilerCallback4 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorProfilerCallback4 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Initialize )(
+ ICorProfilerCallback4 * This,
+ /* [in] */ IUnknown *pICorProfilerInfoUnk);
+
+ HRESULT ( STDMETHODCALLTYPE *Shutdown )(
+ ICorProfilerCallback4 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *AppDomainCreationStarted )(
+ ICorProfilerCallback4 * This,
+ /* [in] */ AppDomainID appDomainId);
+
+ HRESULT ( STDMETHODCALLTYPE *AppDomainCreationFinished )(
+ ICorProfilerCallback4 * This,
+ /* [in] */ AppDomainID appDomainId,
+ /* [in] */ HRESULT hrStatus);
+
+ HRESULT ( STDMETHODCALLTYPE *AppDomainShutdownStarted )(
+ ICorProfilerCallback4 * This,
+ /* [in] */ AppDomainID appDomainId);
+
+ HRESULT ( STDMETHODCALLTYPE *AppDomainShutdownFinished )(
+ ICorProfilerCallback4 * This,
+ /* [in] */ AppDomainID appDomainId,
+ /* [in] */ HRESULT hrStatus);
+
+ HRESULT ( STDMETHODCALLTYPE *AssemblyLoadStarted )(
+ ICorProfilerCallback4 * This,
+ /* [in] */ AssemblyID assemblyId);
+
+ HRESULT ( STDMETHODCALLTYPE *AssemblyLoadFinished )(
+ ICorProfilerCallback4 * This,
+ /* [in] */ AssemblyID assemblyId,
+ /* [in] */ HRESULT hrStatus);
+
+ HRESULT ( STDMETHODCALLTYPE *AssemblyUnloadStarted )(
+ ICorProfilerCallback4 * This,
+ /* [in] */ AssemblyID assemblyId);
+
+ HRESULT ( STDMETHODCALLTYPE *AssemblyUnloadFinished )(
+ ICorProfilerCallback4 * This,
+ /* [in] */ AssemblyID assemblyId,
+ /* [in] */ HRESULT hrStatus);
+
+ HRESULT ( STDMETHODCALLTYPE *ModuleLoadStarted )(
+ ICorProfilerCallback4 * This,
+ /* [in] */ ModuleID moduleId);
+
+ HRESULT ( STDMETHODCALLTYPE *ModuleLoadFinished )(
+ ICorProfilerCallback4 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ HRESULT hrStatus);
+
+ HRESULT ( STDMETHODCALLTYPE *ModuleUnloadStarted )(
+ ICorProfilerCallback4 * This,
+ /* [in] */ ModuleID moduleId);
+
+ HRESULT ( STDMETHODCALLTYPE *ModuleUnloadFinished )(
+ ICorProfilerCallback4 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ HRESULT hrStatus);
+
+ HRESULT ( STDMETHODCALLTYPE *ModuleAttachedToAssembly )(
+ ICorProfilerCallback4 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ AssemblyID AssemblyId);
+
+ HRESULT ( STDMETHODCALLTYPE *ClassLoadStarted )(
+ ICorProfilerCallback4 * This,
+ /* [in] */ ClassID classId);
+
+ HRESULT ( STDMETHODCALLTYPE *ClassLoadFinished )(
+ ICorProfilerCallback4 * This,
+ /* [in] */ ClassID classId,
+ /* [in] */ HRESULT hrStatus);
+
+ HRESULT ( STDMETHODCALLTYPE *ClassUnloadStarted )(
+ ICorProfilerCallback4 * This,
+ /* [in] */ ClassID classId);
+
+ HRESULT ( STDMETHODCALLTYPE *ClassUnloadFinished )(
+ ICorProfilerCallback4 * This,
+ /* [in] */ ClassID classId,
+ /* [in] */ HRESULT hrStatus);
+
+ HRESULT ( STDMETHODCALLTYPE *FunctionUnloadStarted )(
+ ICorProfilerCallback4 * This,
+ /* [in] */ FunctionID functionId);
+
+ HRESULT ( STDMETHODCALLTYPE *JITCompilationStarted )(
+ ICorProfilerCallback4 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ BOOL fIsSafeToBlock);
+
+ HRESULT ( STDMETHODCALLTYPE *JITCompilationFinished )(
+ ICorProfilerCallback4 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ HRESULT hrStatus,
+ /* [in] */ BOOL fIsSafeToBlock);
+
+ HRESULT ( STDMETHODCALLTYPE *JITCachedFunctionSearchStarted )(
+ ICorProfilerCallback4 * This,
+ /* [in] */ FunctionID functionId,
+ /* [out] */ BOOL *pbUseCachedFunction);
+
+ HRESULT ( STDMETHODCALLTYPE *JITCachedFunctionSearchFinished )(
+ ICorProfilerCallback4 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ COR_PRF_JIT_CACHE result);
+
+ HRESULT ( STDMETHODCALLTYPE *JITFunctionPitched )(
+ ICorProfilerCallback4 * This,
+ /* [in] */ FunctionID functionId);
+
+ HRESULT ( STDMETHODCALLTYPE *JITInlining )(
+ ICorProfilerCallback4 * This,
+ /* [in] */ FunctionID callerId,
+ /* [in] */ FunctionID calleeId,
+ /* [out] */ BOOL *pfShouldInline);
+
+ HRESULT ( STDMETHODCALLTYPE *ThreadCreated )(
+ ICorProfilerCallback4 * This,
+ /* [in] */ ThreadID threadId);
+
+ HRESULT ( STDMETHODCALLTYPE *ThreadDestroyed )(
+ ICorProfilerCallback4 * This,
+ /* [in] */ ThreadID threadId);
+
+ HRESULT ( STDMETHODCALLTYPE *ThreadAssignedToOSThread )(
+ ICorProfilerCallback4 * This,
+ /* [in] */ ThreadID managedThreadId,
+ /* [in] */ DWORD osThreadId);
+
+ HRESULT ( STDMETHODCALLTYPE *RemotingClientInvocationStarted )(
+ ICorProfilerCallback4 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *RemotingClientSendingMessage )(
+ ICorProfilerCallback4 * This,
+ /* [in] */ GUID *pCookie,
+ /* [in] */ BOOL fIsAsync);
+
+ HRESULT ( STDMETHODCALLTYPE *RemotingClientReceivingReply )(
+ ICorProfilerCallback4 * This,
+ /* [in] */ GUID *pCookie,
+ /* [in] */ BOOL fIsAsync);
+
+ HRESULT ( STDMETHODCALLTYPE *RemotingClientInvocationFinished )(
+ ICorProfilerCallback4 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *RemotingServerReceivingMessage )(
+ ICorProfilerCallback4 * This,
+ /* [in] */ GUID *pCookie,
+ /* [in] */ BOOL fIsAsync);
+
+ HRESULT ( STDMETHODCALLTYPE *RemotingServerInvocationStarted )(
+ ICorProfilerCallback4 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *RemotingServerInvocationReturned )(
+ ICorProfilerCallback4 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *RemotingServerSendingReply )(
+ ICorProfilerCallback4 * This,
+ /* [in] */ GUID *pCookie,
+ /* [in] */ BOOL fIsAsync);
+
+ HRESULT ( STDMETHODCALLTYPE *UnmanagedToManagedTransition )(
+ ICorProfilerCallback4 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ COR_PRF_TRANSITION_REASON reason);
+
+ HRESULT ( STDMETHODCALLTYPE *ManagedToUnmanagedTransition )(
+ ICorProfilerCallback4 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ COR_PRF_TRANSITION_REASON reason);
+
+ HRESULT ( STDMETHODCALLTYPE *RuntimeSuspendStarted )(
+ ICorProfilerCallback4 * This,
+ /* [in] */ COR_PRF_SUSPEND_REASON suspendReason);
+
+ HRESULT ( STDMETHODCALLTYPE *RuntimeSuspendFinished )(
+ ICorProfilerCallback4 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *RuntimeSuspendAborted )(
+ ICorProfilerCallback4 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *RuntimeResumeStarted )(
+ ICorProfilerCallback4 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *RuntimeResumeFinished )(
+ ICorProfilerCallback4 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *RuntimeThreadSuspended )(
+ ICorProfilerCallback4 * This,
+ /* [in] */ ThreadID threadId);
+
+ HRESULT ( STDMETHODCALLTYPE *RuntimeThreadResumed )(
+ ICorProfilerCallback4 * This,
+ /* [in] */ ThreadID threadId);
+
+ HRESULT ( STDMETHODCALLTYPE *MovedReferences )(
+ ICorProfilerCallback4 * This,
+ /* [in] */ ULONG cMovedObjectIDRanges,
+ /* [size_is][in] */ ObjectID oldObjectIDRangeStart[ ],
+ /* [size_is][in] */ ObjectID newObjectIDRangeStart[ ],
+ /* [size_is][in] */ ULONG cObjectIDRangeLength[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *ObjectAllocated )(
+ ICorProfilerCallback4 * This,
+ /* [in] */ ObjectID objectId,
+ /* [in] */ ClassID classId);
+
+ HRESULT ( STDMETHODCALLTYPE *ObjectsAllocatedByClass )(
+ ICorProfilerCallback4 * This,
+ /* [in] */ ULONG cClassCount,
+ /* [size_is][in] */ ClassID classIds[ ],
+ /* [size_is][in] */ ULONG cObjects[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *ObjectReferences )(
+ ICorProfilerCallback4 * This,
+ /* [in] */ ObjectID objectId,
+ /* [in] */ ClassID classId,
+ /* [in] */ ULONG cObjectRefs,
+ /* [size_is][in] */ ObjectID objectRefIds[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *RootReferences )(
+ ICorProfilerCallback4 * This,
+ /* [in] */ ULONG cRootRefs,
+ /* [size_is][in] */ ObjectID rootRefIds[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionThrown )(
+ ICorProfilerCallback4 * This,
+ /* [in] */ ObjectID thrownObjectId);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionSearchFunctionEnter )(
+ ICorProfilerCallback4 * This,
+ /* [in] */ FunctionID functionId);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionSearchFunctionLeave )(
+ ICorProfilerCallback4 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionSearchFilterEnter )(
+ ICorProfilerCallback4 * This,
+ /* [in] */ FunctionID functionId);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionSearchFilterLeave )(
+ ICorProfilerCallback4 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionSearchCatcherFound )(
+ ICorProfilerCallback4 * This,
+ /* [in] */ FunctionID functionId);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionOSHandlerEnter )(
+ ICorProfilerCallback4 * This,
+ /* [in] */ UINT_PTR __unused);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionOSHandlerLeave )(
+ ICorProfilerCallback4 * This,
+ /* [in] */ UINT_PTR __unused);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionUnwindFunctionEnter )(
+ ICorProfilerCallback4 * This,
+ /* [in] */ FunctionID functionId);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionUnwindFunctionLeave )(
+ ICorProfilerCallback4 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionUnwindFinallyEnter )(
+ ICorProfilerCallback4 * This,
+ /* [in] */ FunctionID functionId);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionUnwindFinallyLeave )(
+ ICorProfilerCallback4 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionCatcherEnter )(
+ ICorProfilerCallback4 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ ObjectID objectId);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionCatcherLeave )(
+ ICorProfilerCallback4 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *COMClassicVTableCreated )(
+ ICorProfilerCallback4 * This,
+ /* [in] */ ClassID wrappedClassId,
+ /* [in] */ REFGUID implementedIID,
+ /* [in] */ void *pVTable,
+ /* [in] */ ULONG cSlots);
+
+ HRESULT ( STDMETHODCALLTYPE *COMClassicVTableDestroyed )(
+ ICorProfilerCallback4 * This,
+ /* [in] */ ClassID wrappedClassId,
+ /* [in] */ REFGUID implementedIID,
+ /* [in] */ void *pVTable);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionCLRCatcherFound )(
+ ICorProfilerCallback4 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionCLRCatcherExecute )(
+ ICorProfilerCallback4 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *ThreadNameChanged )(
+ ICorProfilerCallback4 * This,
+ /* [in] */ ThreadID threadId,
+ /* [in] */ ULONG cchName,
+ /* [annotation][in] */
+ _In_reads_opt_(cchName) WCHAR name[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GarbageCollectionStarted )(
+ ICorProfilerCallback4 * This,
+ /* [in] */ int cGenerations,
+ /* [size_is][in] */ BOOL generationCollected[ ],
+ /* [in] */ COR_PRF_GC_REASON reason);
+
+ HRESULT ( STDMETHODCALLTYPE *SurvivingReferences )(
+ ICorProfilerCallback4 * This,
+ /* [in] */ ULONG cSurvivingObjectIDRanges,
+ /* [size_is][in] */ ObjectID objectIDRangeStart[ ],
+ /* [size_is][in] */ ULONG cObjectIDRangeLength[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GarbageCollectionFinished )(
+ ICorProfilerCallback4 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *FinalizeableObjectQueued )(
+ ICorProfilerCallback4 * This,
+ /* [in] */ DWORD finalizerFlags,
+ /* [in] */ ObjectID objectID);
+
+ HRESULT ( STDMETHODCALLTYPE *RootReferences2 )(
+ ICorProfilerCallback4 * This,
+ /* [in] */ ULONG cRootRefs,
+ /* [size_is][in] */ ObjectID rootRefIds[ ],
+ /* [size_is][in] */ COR_PRF_GC_ROOT_KIND rootKinds[ ],
+ /* [size_is][in] */ COR_PRF_GC_ROOT_FLAGS rootFlags[ ],
+ /* [size_is][in] */ UINT_PTR rootIds[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *HandleCreated )(
+ ICorProfilerCallback4 * This,
+ /* [in] */ GCHandleID handleId,
+ /* [in] */ ObjectID initialObjectId);
+
+ HRESULT ( STDMETHODCALLTYPE *HandleDestroyed )(
+ ICorProfilerCallback4 * This,
+ /* [in] */ GCHandleID handleId);
+
+ HRESULT ( STDMETHODCALLTYPE *InitializeForAttach )(
+ ICorProfilerCallback4 * This,
+ /* [in] */ IUnknown *pCorProfilerInfoUnk,
+ /* [in] */ void *pvClientData,
+ /* [in] */ UINT cbClientData);
+
+ HRESULT ( STDMETHODCALLTYPE *ProfilerAttachComplete )(
+ ICorProfilerCallback4 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *ProfilerDetachSucceeded )(
+ ICorProfilerCallback4 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *ReJITCompilationStarted )(
+ ICorProfilerCallback4 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ ReJITID rejitId,
+ /* [in] */ BOOL fIsSafeToBlock);
+
+ HRESULT ( STDMETHODCALLTYPE *GetReJITParameters )(
+ ICorProfilerCallback4 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ mdMethodDef methodId,
+ /* [in] */ ICorProfilerFunctionControl *pFunctionControl);
+
+ HRESULT ( STDMETHODCALLTYPE *ReJITCompilationFinished )(
+ ICorProfilerCallback4 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ ReJITID rejitId,
+ /* [in] */ HRESULT hrStatus,
+ /* [in] */ BOOL fIsSafeToBlock);
+
+ HRESULT ( STDMETHODCALLTYPE *ReJITError )(
+ ICorProfilerCallback4 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ mdMethodDef methodId,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ HRESULT hrStatus);
+
+ HRESULT ( STDMETHODCALLTYPE *MovedReferences2 )(
+ ICorProfilerCallback4 * This,
+ /* [in] */ ULONG cMovedObjectIDRanges,
+ /* [size_is][in] */ ObjectID oldObjectIDRangeStart[ ],
+ /* [size_is][in] */ ObjectID newObjectIDRangeStart[ ],
+ /* [size_is][in] */ SIZE_T cObjectIDRangeLength[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *SurvivingReferences2 )(
+ ICorProfilerCallback4 * This,
+ /* [in] */ ULONG cSurvivingObjectIDRanges,
+ /* [size_is][in] */ ObjectID objectIDRangeStart[ ],
+ /* [size_is][in] */ SIZE_T cObjectIDRangeLength[ ]);
+
+ END_INTERFACE
+ } ICorProfilerCallback4Vtbl;
+
+ interface ICorProfilerCallback4
+ {
+ CONST_VTBL struct ICorProfilerCallback4Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorProfilerCallback4_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorProfilerCallback4_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorProfilerCallback4_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorProfilerCallback4_Initialize(This,pICorProfilerInfoUnk) \
+ ( (This)->lpVtbl -> Initialize(This,pICorProfilerInfoUnk) )
+
+#define ICorProfilerCallback4_Shutdown(This) \
+ ( (This)->lpVtbl -> Shutdown(This) )
+
+#define ICorProfilerCallback4_AppDomainCreationStarted(This,appDomainId) \
+ ( (This)->lpVtbl -> AppDomainCreationStarted(This,appDomainId) )
+
+#define ICorProfilerCallback4_AppDomainCreationFinished(This,appDomainId,hrStatus) \
+ ( (This)->lpVtbl -> AppDomainCreationFinished(This,appDomainId,hrStatus) )
+
+#define ICorProfilerCallback4_AppDomainShutdownStarted(This,appDomainId) \
+ ( (This)->lpVtbl -> AppDomainShutdownStarted(This,appDomainId) )
+
+#define ICorProfilerCallback4_AppDomainShutdownFinished(This,appDomainId,hrStatus) \
+ ( (This)->lpVtbl -> AppDomainShutdownFinished(This,appDomainId,hrStatus) )
+
+#define ICorProfilerCallback4_AssemblyLoadStarted(This,assemblyId) \
+ ( (This)->lpVtbl -> AssemblyLoadStarted(This,assemblyId) )
+
+#define ICorProfilerCallback4_AssemblyLoadFinished(This,assemblyId,hrStatus) \
+ ( (This)->lpVtbl -> AssemblyLoadFinished(This,assemblyId,hrStatus) )
+
+#define ICorProfilerCallback4_AssemblyUnloadStarted(This,assemblyId) \
+ ( (This)->lpVtbl -> AssemblyUnloadStarted(This,assemblyId) )
+
+#define ICorProfilerCallback4_AssemblyUnloadFinished(This,assemblyId,hrStatus) \
+ ( (This)->lpVtbl -> AssemblyUnloadFinished(This,assemblyId,hrStatus) )
+
+#define ICorProfilerCallback4_ModuleLoadStarted(This,moduleId) \
+ ( (This)->lpVtbl -> ModuleLoadStarted(This,moduleId) )
+
+#define ICorProfilerCallback4_ModuleLoadFinished(This,moduleId,hrStatus) \
+ ( (This)->lpVtbl -> ModuleLoadFinished(This,moduleId,hrStatus) )
+
+#define ICorProfilerCallback4_ModuleUnloadStarted(This,moduleId) \
+ ( (This)->lpVtbl -> ModuleUnloadStarted(This,moduleId) )
+
+#define ICorProfilerCallback4_ModuleUnloadFinished(This,moduleId,hrStatus) \
+ ( (This)->lpVtbl -> ModuleUnloadFinished(This,moduleId,hrStatus) )
+
+#define ICorProfilerCallback4_ModuleAttachedToAssembly(This,moduleId,AssemblyId) \
+ ( (This)->lpVtbl -> ModuleAttachedToAssembly(This,moduleId,AssemblyId) )
+
+#define ICorProfilerCallback4_ClassLoadStarted(This,classId) \
+ ( (This)->lpVtbl -> ClassLoadStarted(This,classId) )
+
+#define ICorProfilerCallback4_ClassLoadFinished(This,classId,hrStatus) \
+ ( (This)->lpVtbl -> ClassLoadFinished(This,classId,hrStatus) )
+
+#define ICorProfilerCallback4_ClassUnloadStarted(This,classId) \
+ ( (This)->lpVtbl -> ClassUnloadStarted(This,classId) )
+
+#define ICorProfilerCallback4_ClassUnloadFinished(This,classId,hrStatus) \
+ ( (This)->lpVtbl -> ClassUnloadFinished(This,classId,hrStatus) )
+
+#define ICorProfilerCallback4_FunctionUnloadStarted(This,functionId) \
+ ( (This)->lpVtbl -> FunctionUnloadStarted(This,functionId) )
+
+#define ICorProfilerCallback4_JITCompilationStarted(This,functionId,fIsSafeToBlock) \
+ ( (This)->lpVtbl -> JITCompilationStarted(This,functionId,fIsSafeToBlock) )
+
+#define ICorProfilerCallback4_JITCompilationFinished(This,functionId,hrStatus,fIsSafeToBlock) \
+ ( (This)->lpVtbl -> JITCompilationFinished(This,functionId,hrStatus,fIsSafeToBlock) )
+
+#define ICorProfilerCallback4_JITCachedFunctionSearchStarted(This,functionId,pbUseCachedFunction) \
+ ( (This)->lpVtbl -> JITCachedFunctionSearchStarted(This,functionId,pbUseCachedFunction) )
+
+#define ICorProfilerCallback4_JITCachedFunctionSearchFinished(This,functionId,result) \
+ ( (This)->lpVtbl -> JITCachedFunctionSearchFinished(This,functionId,result) )
+
+#define ICorProfilerCallback4_JITFunctionPitched(This,functionId) \
+ ( (This)->lpVtbl -> JITFunctionPitched(This,functionId) )
+
+#define ICorProfilerCallback4_JITInlining(This,callerId,calleeId,pfShouldInline) \
+ ( (This)->lpVtbl -> JITInlining(This,callerId,calleeId,pfShouldInline) )
+
+#define ICorProfilerCallback4_ThreadCreated(This,threadId) \
+ ( (This)->lpVtbl -> ThreadCreated(This,threadId) )
+
+#define ICorProfilerCallback4_ThreadDestroyed(This,threadId) \
+ ( (This)->lpVtbl -> ThreadDestroyed(This,threadId) )
+
+#define ICorProfilerCallback4_ThreadAssignedToOSThread(This,managedThreadId,osThreadId) \
+ ( (This)->lpVtbl -> ThreadAssignedToOSThread(This,managedThreadId,osThreadId) )
+
+#define ICorProfilerCallback4_RemotingClientInvocationStarted(This) \
+ ( (This)->lpVtbl -> RemotingClientInvocationStarted(This) )
+
+#define ICorProfilerCallback4_RemotingClientSendingMessage(This,pCookie,fIsAsync) \
+ ( (This)->lpVtbl -> RemotingClientSendingMessage(This,pCookie,fIsAsync) )
+
+#define ICorProfilerCallback4_RemotingClientReceivingReply(This,pCookie,fIsAsync) \
+ ( (This)->lpVtbl -> RemotingClientReceivingReply(This,pCookie,fIsAsync) )
+
+#define ICorProfilerCallback4_RemotingClientInvocationFinished(This) \
+ ( (This)->lpVtbl -> RemotingClientInvocationFinished(This) )
+
+#define ICorProfilerCallback4_RemotingServerReceivingMessage(This,pCookie,fIsAsync) \
+ ( (This)->lpVtbl -> RemotingServerReceivingMessage(This,pCookie,fIsAsync) )
+
+#define ICorProfilerCallback4_RemotingServerInvocationStarted(This) \
+ ( (This)->lpVtbl -> RemotingServerInvocationStarted(This) )
+
+#define ICorProfilerCallback4_RemotingServerInvocationReturned(This) \
+ ( (This)->lpVtbl -> RemotingServerInvocationReturned(This) )
+
+#define ICorProfilerCallback4_RemotingServerSendingReply(This,pCookie,fIsAsync) \
+ ( (This)->lpVtbl -> RemotingServerSendingReply(This,pCookie,fIsAsync) )
+
+#define ICorProfilerCallback4_UnmanagedToManagedTransition(This,functionId,reason) \
+ ( (This)->lpVtbl -> UnmanagedToManagedTransition(This,functionId,reason) )
+
+#define ICorProfilerCallback4_ManagedToUnmanagedTransition(This,functionId,reason) \
+ ( (This)->lpVtbl -> ManagedToUnmanagedTransition(This,functionId,reason) )
+
+#define ICorProfilerCallback4_RuntimeSuspendStarted(This,suspendReason) \
+ ( (This)->lpVtbl -> RuntimeSuspendStarted(This,suspendReason) )
+
+#define ICorProfilerCallback4_RuntimeSuspendFinished(This) \
+ ( (This)->lpVtbl -> RuntimeSuspendFinished(This) )
+
+#define ICorProfilerCallback4_RuntimeSuspendAborted(This) \
+ ( (This)->lpVtbl -> RuntimeSuspendAborted(This) )
+
+#define ICorProfilerCallback4_RuntimeResumeStarted(This) \
+ ( (This)->lpVtbl -> RuntimeResumeStarted(This) )
+
+#define ICorProfilerCallback4_RuntimeResumeFinished(This) \
+ ( (This)->lpVtbl -> RuntimeResumeFinished(This) )
+
+#define ICorProfilerCallback4_RuntimeThreadSuspended(This,threadId) \
+ ( (This)->lpVtbl -> RuntimeThreadSuspended(This,threadId) )
+
+#define ICorProfilerCallback4_RuntimeThreadResumed(This,threadId) \
+ ( (This)->lpVtbl -> RuntimeThreadResumed(This,threadId) )
+
+#define ICorProfilerCallback4_MovedReferences(This,cMovedObjectIDRanges,oldObjectIDRangeStart,newObjectIDRangeStart,cObjectIDRangeLength) \
+ ( (This)->lpVtbl -> MovedReferences(This,cMovedObjectIDRanges,oldObjectIDRangeStart,newObjectIDRangeStart,cObjectIDRangeLength) )
+
+#define ICorProfilerCallback4_ObjectAllocated(This,objectId,classId) \
+ ( (This)->lpVtbl -> ObjectAllocated(This,objectId,classId) )
+
+#define ICorProfilerCallback4_ObjectsAllocatedByClass(This,cClassCount,classIds,cObjects) \
+ ( (This)->lpVtbl -> ObjectsAllocatedByClass(This,cClassCount,classIds,cObjects) )
+
+#define ICorProfilerCallback4_ObjectReferences(This,objectId,classId,cObjectRefs,objectRefIds) \
+ ( (This)->lpVtbl -> ObjectReferences(This,objectId,classId,cObjectRefs,objectRefIds) )
+
+#define ICorProfilerCallback4_RootReferences(This,cRootRefs,rootRefIds) \
+ ( (This)->lpVtbl -> RootReferences(This,cRootRefs,rootRefIds) )
+
+#define ICorProfilerCallback4_ExceptionThrown(This,thrownObjectId) \
+ ( (This)->lpVtbl -> ExceptionThrown(This,thrownObjectId) )
+
+#define ICorProfilerCallback4_ExceptionSearchFunctionEnter(This,functionId) \
+ ( (This)->lpVtbl -> ExceptionSearchFunctionEnter(This,functionId) )
+
+#define ICorProfilerCallback4_ExceptionSearchFunctionLeave(This) \
+ ( (This)->lpVtbl -> ExceptionSearchFunctionLeave(This) )
+
+#define ICorProfilerCallback4_ExceptionSearchFilterEnter(This,functionId) \
+ ( (This)->lpVtbl -> ExceptionSearchFilterEnter(This,functionId) )
+
+#define ICorProfilerCallback4_ExceptionSearchFilterLeave(This) \
+ ( (This)->lpVtbl -> ExceptionSearchFilterLeave(This) )
+
+#define ICorProfilerCallback4_ExceptionSearchCatcherFound(This,functionId) \
+ ( (This)->lpVtbl -> ExceptionSearchCatcherFound(This,functionId) )
+
+#define ICorProfilerCallback4_ExceptionOSHandlerEnter(This,__unused) \
+ ( (This)->lpVtbl -> ExceptionOSHandlerEnter(This,__unused) )
+
+#define ICorProfilerCallback4_ExceptionOSHandlerLeave(This,__unused) \
+ ( (This)->lpVtbl -> ExceptionOSHandlerLeave(This,__unused) )
+
+#define ICorProfilerCallback4_ExceptionUnwindFunctionEnter(This,functionId) \
+ ( (This)->lpVtbl -> ExceptionUnwindFunctionEnter(This,functionId) )
+
+#define ICorProfilerCallback4_ExceptionUnwindFunctionLeave(This) \
+ ( (This)->lpVtbl -> ExceptionUnwindFunctionLeave(This) )
+
+#define ICorProfilerCallback4_ExceptionUnwindFinallyEnter(This,functionId) \
+ ( (This)->lpVtbl -> ExceptionUnwindFinallyEnter(This,functionId) )
+
+#define ICorProfilerCallback4_ExceptionUnwindFinallyLeave(This) \
+ ( (This)->lpVtbl -> ExceptionUnwindFinallyLeave(This) )
+
+#define ICorProfilerCallback4_ExceptionCatcherEnter(This,functionId,objectId) \
+ ( (This)->lpVtbl -> ExceptionCatcherEnter(This,functionId,objectId) )
+
+#define ICorProfilerCallback4_ExceptionCatcherLeave(This) \
+ ( (This)->lpVtbl -> ExceptionCatcherLeave(This) )
+
+#define ICorProfilerCallback4_COMClassicVTableCreated(This,wrappedClassId,implementedIID,pVTable,cSlots) \
+ ( (This)->lpVtbl -> COMClassicVTableCreated(This,wrappedClassId,implementedIID,pVTable,cSlots) )
+
+#define ICorProfilerCallback4_COMClassicVTableDestroyed(This,wrappedClassId,implementedIID,pVTable) \
+ ( (This)->lpVtbl -> COMClassicVTableDestroyed(This,wrappedClassId,implementedIID,pVTable) )
+
+#define ICorProfilerCallback4_ExceptionCLRCatcherFound(This) \
+ ( (This)->lpVtbl -> ExceptionCLRCatcherFound(This) )
+
+#define ICorProfilerCallback4_ExceptionCLRCatcherExecute(This) \
+ ( (This)->lpVtbl -> ExceptionCLRCatcherExecute(This) )
+
+
+#define ICorProfilerCallback4_ThreadNameChanged(This,threadId,cchName,name) \
+ ( (This)->lpVtbl -> ThreadNameChanged(This,threadId,cchName,name) )
+
+#define ICorProfilerCallback4_GarbageCollectionStarted(This,cGenerations,generationCollected,reason) \
+ ( (This)->lpVtbl -> GarbageCollectionStarted(This,cGenerations,generationCollected,reason) )
+
+#define ICorProfilerCallback4_SurvivingReferences(This,cSurvivingObjectIDRanges,objectIDRangeStart,cObjectIDRangeLength) \
+ ( (This)->lpVtbl -> SurvivingReferences(This,cSurvivingObjectIDRanges,objectIDRangeStart,cObjectIDRangeLength) )
+
+#define ICorProfilerCallback4_GarbageCollectionFinished(This) \
+ ( (This)->lpVtbl -> GarbageCollectionFinished(This) )
+
+#define ICorProfilerCallback4_FinalizeableObjectQueued(This,finalizerFlags,objectID) \
+ ( (This)->lpVtbl -> FinalizeableObjectQueued(This,finalizerFlags,objectID) )
+
+#define ICorProfilerCallback4_RootReferences2(This,cRootRefs,rootRefIds,rootKinds,rootFlags,rootIds) \
+ ( (This)->lpVtbl -> RootReferences2(This,cRootRefs,rootRefIds,rootKinds,rootFlags,rootIds) )
+
+#define ICorProfilerCallback4_HandleCreated(This,handleId,initialObjectId) \
+ ( (This)->lpVtbl -> HandleCreated(This,handleId,initialObjectId) )
+
+#define ICorProfilerCallback4_HandleDestroyed(This,handleId) \
+ ( (This)->lpVtbl -> HandleDestroyed(This,handleId) )
+
+
+#define ICorProfilerCallback4_InitializeForAttach(This,pCorProfilerInfoUnk,pvClientData,cbClientData) \
+ ( (This)->lpVtbl -> InitializeForAttach(This,pCorProfilerInfoUnk,pvClientData,cbClientData) )
+
+#define ICorProfilerCallback4_ProfilerAttachComplete(This) \
+ ( (This)->lpVtbl -> ProfilerAttachComplete(This) )
+
+#define ICorProfilerCallback4_ProfilerDetachSucceeded(This) \
+ ( (This)->lpVtbl -> ProfilerDetachSucceeded(This) )
+
+
+#define ICorProfilerCallback4_ReJITCompilationStarted(This,functionId,rejitId,fIsSafeToBlock) \
+ ( (This)->lpVtbl -> ReJITCompilationStarted(This,functionId,rejitId,fIsSafeToBlock) )
+
+#define ICorProfilerCallback4_GetReJITParameters(This,moduleId,methodId,pFunctionControl) \
+ ( (This)->lpVtbl -> GetReJITParameters(This,moduleId,methodId,pFunctionControl) )
+
+#define ICorProfilerCallback4_ReJITCompilationFinished(This,functionId,rejitId,hrStatus,fIsSafeToBlock) \
+ ( (This)->lpVtbl -> ReJITCompilationFinished(This,functionId,rejitId,hrStatus,fIsSafeToBlock) )
+
+#define ICorProfilerCallback4_ReJITError(This,moduleId,methodId,functionId,hrStatus) \
+ ( (This)->lpVtbl -> ReJITError(This,moduleId,methodId,functionId,hrStatus) )
+
+#define ICorProfilerCallback4_MovedReferences2(This,cMovedObjectIDRanges,oldObjectIDRangeStart,newObjectIDRangeStart,cObjectIDRangeLength) \
+ ( (This)->lpVtbl -> MovedReferences2(This,cMovedObjectIDRanges,oldObjectIDRangeStart,newObjectIDRangeStart,cObjectIDRangeLength) )
+
+#define ICorProfilerCallback4_SurvivingReferences2(This,cSurvivingObjectIDRanges,objectIDRangeStart,cObjectIDRangeLength) \
+ ( (This)->lpVtbl -> SurvivingReferences2(This,cSurvivingObjectIDRanges,objectIDRangeStart,cObjectIDRangeLength) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorProfilerCallback4_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorProfilerCallback5_INTERFACE_DEFINED__
+#define __ICorProfilerCallback5_INTERFACE_DEFINED__
+
+/* interface ICorProfilerCallback5 */
+/* [local][unique][uuid][object] */
+
+
+EXTERN_C const IID IID_ICorProfilerCallback5;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("8DFBA405-8C9F-45F8-BFFA-83B14CEF78B5")
+ ICorProfilerCallback5 : public ICorProfilerCallback4
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE ConditionalWeakTableElementReferences(
+ /* [in] */ ULONG cRootRefs,
+ /* [size_is][in] */ ObjectID keyRefIds[ ],
+ /* [size_is][in] */ ObjectID valueRefIds[ ],
+ /* [size_is][in] */ GCHandleID rootIds[ ]) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorProfilerCallback5Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorProfilerCallback5 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorProfilerCallback5 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorProfilerCallback5 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Initialize )(
+ ICorProfilerCallback5 * This,
+ /* [in] */ IUnknown *pICorProfilerInfoUnk);
+
+ HRESULT ( STDMETHODCALLTYPE *Shutdown )(
+ ICorProfilerCallback5 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *AppDomainCreationStarted )(
+ ICorProfilerCallback5 * This,
+ /* [in] */ AppDomainID appDomainId);
+
+ HRESULT ( STDMETHODCALLTYPE *AppDomainCreationFinished )(
+ ICorProfilerCallback5 * This,
+ /* [in] */ AppDomainID appDomainId,
+ /* [in] */ HRESULT hrStatus);
+
+ HRESULT ( STDMETHODCALLTYPE *AppDomainShutdownStarted )(
+ ICorProfilerCallback5 * This,
+ /* [in] */ AppDomainID appDomainId);
+
+ HRESULT ( STDMETHODCALLTYPE *AppDomainShutdownFinished )(
+ ICorProfilerCallback5 * This,
+ /* [in] */ AppDomainID appDomainId,
+ /* [in] */ HRESULT hrStatus);
+
+ HRESULT ( STDMETHODCALLTYPE *AssemblyLoadStarted )(
+ ICorProfilerCallback5 * This,
+ /* [in] */ AssemblyID assemblyId);
+
+ HRESULT ( STDMETHODCALLTYPE *AssemblyLoadFinished )(
+ ICorProfilerCallback5 * This,
+ /* [in] */ AssemblyID assemblyId,
+ /* [in] */ HRESULT hrStatus);
+
+ HRESULT ( STDMETHODCALLTYPE *AssemblyUnloadStarted )(
+ ICorProfilerCallback5 * This,
+ /* [in] */ AssemblyID assemblyId);
+
+ HRESULT ( STDMETHODCALLTYPE *AssemblyUnloadFinished )(
+ ICorProfilerCallback5 * This,
+ /* [in] */ AssemblyID assemblyId,
+ /* [in] */ HRESULT hrStatus);
+
+ HRESULT ( STDMETHODCALLTYPE *ModuleLoadStarted )(
+ ICorProfilerCallback5 * This,
+ /* [in] */ ModuleID moduleId);
+
+ HRESULT ( STDMETHODCALLTYPE *ModuleLoadFinished )(
+ ICorProfilerCallback5 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ HRESULT hrStatus);
+
+ HRESULT ( STDMETHODCALLTYPE *ModuleUnloadStarted )(
+ ICorProfilerCallback5 * This,
+ /* [in] */ ModuleID moduleId);
+
+ HRESULT ( STDMETHODCALLTYPE *ModuleUnloadFinished )(
+ ICorProfilerCallback5 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ HRESULT hrStatus);
+
+ HRESULT ( STDMETHODCALLTYPE *ModuleAttachedToAssembly )(
+ ICorProfilerCallback5 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ AssemblyID AssemblyId);
+
+ HRESULT ( STDMETHODCALLTYPE *ClassLoadStarted )(
+ ICorProfilerCallback5 * This,
+ /* [in] */ ClassID classId);
+
+ HRESULT ( STDMETHODCALLTYPE *ClassLoadFinished )(
+ ICorProfilerCallback5 * This,
+ /* [in] */ ClassID classId,
+ /* [in] */ HRESULT hrStatus);
+
+ HRESULT ( STDMETHODCALLTYPE *ClassUnloadStarted )(
+ ICorProfilerCallback5 * This,
+ /* [in] */ ClassID classId);
+
+ HRESULT ( STDMETHODCALLTYPE *ClassUnloadFinished )(
+ ICorProfilerCallback5 * This,
+ /* [in] */ ClassID classId,
+ /* [in] */ HRESULT hrStatus);
+
+ HRESULT ( STDMETHODCALLTYPE *FunctionUnloadStarted )(
+ ICorProfilerCallback5 * This,
+ /* [in] */ FunctionID functionId);
+
+ HRESULT ( STDMETHODCALLTYPE *JITCompilationStarted )(
+ ICorProfilerCallback5 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ BOOL fIsSafeToBlock);
+
+ HRESULT ( STDMETHODCALLTYPE *JITCompilationFinished )(
+ ICorProfilerCallback5 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ HRESULT hrStatus,
+ /* [in] */ BOOL fIsSafeToBlock);
+
+ HRESULT ( STDMETHODCALLTYPE *JITCachedFunctionSearchStarted )(
+ ICorProfilerCallback5 * This,
+ /* [in] */ FunctionID functionId,
+ /* [out] */ BOOL *pbUseCachedFunction);
+
+ HRESULT ( STDMETHODCALLTYPE *JITCachedFunctionSearchFinished )(
+ ICorProfilerCallback5 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ COR_PRF_JIT_CACHE result);
+
+ HRESULT ( STDMETHODCALLTYPE *JITFunctionPitched )(
+ ICorProfilerCallback5 * This,
+ /* [in] */ FunctionID functionId);
+
+ HRESULT ( STDMETHODCALLTYPE *JITInlining )(
+ ICorProfilerCallback5 * This,
+ /* [in] */ FunctionID callerId,
+ /* [in] */ FunctionID calleeId,
+ /* [out] */ BOOL *pfShouldInline);
+
+ HRESULT ( STDMETHODCALLTYPE *ThreadCreated )(
+ ICorProfilerCallback5 * This,
+ /* [in] */ ThreadID threadId);
+
+ HRESULT ( STDMETHODCALLTYPE *ThreadDestroyed )(
+ ICorProfilerCallback5 * This,
+ /* [in] */ ThreadID threadId);
+
+ HRESULT ( STDMETHODCALLTYPE *ThreadAssignedToOSThread )(
+ ICorProfilerCallback5 * This,
+ /* [in] */ ThreadID managedThreadId,
+ /* [in] */ DWORD osThreadId);
+
+ HRESULT ( STDMETHODCALLTYPE *RemotingClientInvocationStarted )(
+ ICorProfilerCallback5 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *RemotingClientSendingMessage )(
+ ICorProfilerCallback5 * This,
+ /* [in] */ GUID *pCookie,
+ /* [in] */ BOOL fIsAsync);
+
+ HRESULT ( STDMETHODCALLTYPE *RemotingClientReceivingReply )(
+ ICorProfilerCallback5 * This,
+ /* [in] */ GUID *pCookie,
+ /* [in] */ BOOL fIsAsync);
+
+ HRESULT ( STDMETHODCALLTYPE *RemotingClientInvocationFinished )(
+ ICorProfilerCallback5 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *RemotingServerReceivingMessage )(
+ ICorProfilerCallback5 * This,
+ /* [in] */ GUID *pCookie,
+ /* [in] */ BOOL fIsAsync);
+
+ HRESULT ( STDMETHODCALLTYPE *RemotingServerInvocationStarted )(
+ ICorProfilerCallback5 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *RemotingServerInvocationReturned )(
+ ICorProfilerCallback5 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *RemotingServerSendingReply )(
+ ICorProfilerCallback5 * This,
+ /* [in] */ GUID *pCookie,
+ /* [in] */ BOOL fIsAsync);
+
+ HRESULT ( STDMETHODCALLTYPE *UnmanagedToManagedTransition )(
+ ICorProfilerCallback5 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ COR_PRF_TRANSITION_REASON reason);
+
+ HRESULT ( STDMETHODCALLTYPE *ManagedToUnmanagedTransition )(
+ ICorProfilerCallback5 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ COR_PRF_TRANSITION_REASON reason);
+
+ HRESULT ( STDMETHODCALLTYPE *RuntimeSuspendStarted )(
+ ICorProfilerCallback5 * This,
+ /* [in] */ COR_PRF_SUSPEND_REASON suspendReason);
+
+ HRESULT ( STDMETHODCALLTYPE *RuntimeSuspendFinished )(
+ ICorProfilerCallback5 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *RuntimeSuspendAborted )(
+ ICorProfilerCallback5 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *RuntimeResumeStarted )(
+ ICorProfilerCallback5 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *RuntimeResumeFinished )(
+ ICorProfilerCallback5 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *RuntimeThreadSuspended )(
+ ICorProfilerCallback5 * This,
+ /* [in] */ ThreadID threadId);
+
+ HRESULT ( STDMETHODCALLTYPE *RuntimeThreadResumed )(
+ ICorProfilerCallback5 * This,
+ /* [in] */ ThreadID threadId);
+
+ HRESULT ( STDMETHODCALLTYPE *MovedReferences )(
+ ICorProfilerCallback5 * This,
+ /* [in] */ ULONG cMovedObjectIDRanges,
+ /* [size_is][in] */ ObjectID oldObjectIDRangeStart[ ],
+ /* [size_is][in] */ ObjectID newObjectIDRangeStart[ ],
+ /* [size_is][in] */ ULONG cObjectIDRangeLength[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *ObjectAllocated )(
+ ICorProfilerCallback5 * This,
+ /* [in] */ ObjectID objectId,
+ /* [in] */ ClassID classId);
+
+ HRESULT ( STDMETHODCALLTYPE *ObjectsAllocatedByClass )(
+ ICorProfilerCallback5 * This,
+ /* [in] */ ULONG cClassCount,
+ /* [size_is][in] */ ClassID classIds[ ],
+ /* [size_is][in] */ ULONG cObjects[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *ObjectReferences )(
+ ICorProfilerCallback5 * This,
+ /* [in] */ ObjectID objectId,
+ /* [in] */ ClassID classId,
+ /* [in] */ ULONG cObjectRefs,
+ /* [size_is][in] */ ObjectID objectRefIds[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *RootReferences )(
+ ICorProfilerCallback5 * This,
+ /* [in] */ ULONG cRootRefs,
+ /* [size_is][in] */ ObjectID rootRefIds[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionThrown )(
+ ICorProfilerCallback5 * This,
+ /* [in] */ ObjectID thrownObjectId);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionSearchFunctionEnter )(
+ ICorProfilerCallback5 * This,
+ /* [in] */ FunctionID functionId);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionSearchFunctionLeave )(
+ ICorProfilerCallback5 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionSearchFilterEnter )(
+ ICorProfilerCallback5 * This,
+ /* [in] */ FunctionID functionId);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionSearchFilterLeave )(
+ ICorProfilerCallback5 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionSearchCatcherFound )(
+ ICorProfilerCallback5 * This,
+ /* [in] */ FunctionID functionId);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionOSHandlerEnter )(
+ ICorProfilerCallback5 * This,
+ /* [in] */ UINT_PTR __unused);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionOSHandlerLeave )(
+ ICorProfilerCallback5 * This,
+ /* [in] */ UINT_PTR __unused);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionUnwindFunctionEnter )(
+ ICorProfilerCallback5 * This,
+ /* [in] */ FunctionID functionId);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionUnwindFunctionLeave )(
+ ICorProfilerCallback5 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionUnwindFinallyEnter )(
+ ICorProfilerCallback5 * This,
+ /* [in] */ FunctionID functionId);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionUnwindFinallyLeave )(
+ ICorProfilerCallback5 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionCatcherEnter )(
+ ICorProfilerCallback5 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ ObjectID objectId);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionCatcherLeave )(
+ ICorProfilerCallback5 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *COMClassicVTableCreated )(
+ ICorProfilerCallback5 * This,
+ /* [in] */ ClassID wrappedClassId,
+ /* [in] */ REFGUID implementedIID,
+ /* [in] */ void *pVTable,
+ /* [in] */ ULONG cSlots);
+
+ HRESULT ( STDMETHODCALLTYPE *COMClassicVTableDestroyed )(
+ ICorProfilerCallback5 * This,
+ /* [in] */ ClassID wrappedClassId,
+ /* [in] */ REFGUID implementedIID,
+ /* [in] */ void *pVTable);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionCLRCatcherFound )(
+ ICorProfilerCallback5 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionCLRCatcherExecute )(
+ ICorProfilerCallback5 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *ThreadNameChanged )(
+ ICorProfilerCallback5 * This,
+ /* [in] */ ThreadID threadId,
+ /* [in] */ ULONG cchName,
+ /* [annotation][in] */
+ _In_reads_opt_(cchName) WCHAR name[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GarbageCollectionStarted )(
+ ICorProfilerCallback5 * This,
+ /* [in] */ int cGenerations,
+ /* [size_is][in] */ BOOL generationCollected[ ],
+ /* [in] */ COR_PRF_GC_REASON reason);
+
+ HRESULT ( STDMETHODCALLTYPE *SurvivingReferences )(
+ ICorProfilerCallback5 * This,
+ /* [in] */ ULONG cSurvivingObjectIDRanges,
+ /* [size_is][in] */ ObjectID objectIDRangeStart[ ],
+ /* [size_is][in] */ ULONG cObjectIDRangeLength[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GarbageCollectionFinished )(
+ ICorProfilerCallback5 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *FinalizeableObjectQueued )(
+ ICorProfilerCallback5 * This,
+ /* [in] */ DWORD finalizerFlags,
+ /* [in] */ ObjectID objectID);
+
+ HRESULT ( STDMETHODCALLTYPE *RootReferences2 )(
+ ICorProfilerCallback5 * This,
+ /* [in] */ ULONG cRootRefs,
+ /* [size_is][in] */ ObjectID rootRefIds[ ],
+ /* [size_is][in] */ COR_PRF_GC_ROOT_KIND rootKinds[ ],
+ /* [size_is][in] */ COR_PRF_GC_ROOT_FLAGS rootFlags[ ],
+ /* [size_is][in] */ UINT_PTR rootIds[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *HandleCreated )(
+ ICorProfilerCallback5 * This,
+ /* [in] */ GCHandleID handleId,
+ /* [in] */ ObjectID initialObjectId);
+
+ HRESULT ( STDMETHODCALLTYPE *HandleDestroyed )(
+ ICorProfilerCallback5 * This,
+ /* [in] */ GCHandleID handleId);
+
+ HRESULT ( STDMETHODCALLTYPE *InitializeForAttach )(
+ ICorProfilerCallback5 * This,
+ /* [in] */ IUnknown *pCorProfilerInfoUnk,
+ /* [in] */ void *pvClientData,
+ /* [in] */ UINT cbClientData);
+
+ HRESULT ( STDMETHODCALLTYPE *ProfilerAttachComplete )(
+ ICorProfilerCallback5 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *ProfilerDetachSucceeded )(
+ ICorProfilerCallback5 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *ReJITCompilationStarted )(
+ ICorProfilerCallback5 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ ReJITID rejitId,
+ /* [in] */ BOOL fIsSafeToBlock);
+
+ HRESULT ( STDMETHODCALLTYPE *GetReJITParameters )(
+ ICorProfilerCallback5 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ mdMethodDef methodId,
+ /* [in] */ ICorProfilerFunctionControl *pFunctionControl);
+
+ HRESULT ( STDMETHODCALLTYPE *ReJITCompilationFinished )(
+ ICorProfilerCallback5 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ ReJITID rejitId,
+ /* [in] */ HRESULT hrStatus,
+ /* [in] */ BOOL fIsSafeToBlock);
+
+ HRESULT ( STDMETHODCALLTYPE *ReJITError )(
+ ICorProfilerCallback5 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ mdMethodDef methodId,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ HRESULT hrStatus);
+
+ HRESULT ( STDMETHODCALLTYPE *MovedReferences2 )(
+ ICorProfilerCallback5 * This,
+ /* [in] */ ULONG cMovedObjectIDRanges,
+ /* [size_is][in] */ ObjectID oldObjectIDRangeStart[ ],
+ /* [size_is][in] */ ObjectID newObjectIDRangeStart[ ],
+ /* [size_is][in] */ SIZE_T cObjectIDRangeLength[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *SurvivingReferences2 )(
+ ICorProfilerCallback5 * This,
+ /* [in] */ ULONG cSurvivingObjectIDRanges,
+ /* [size_is][in] */ ObjectID objectIDRangeStart[ ],
+ /* [size_is][in] */ SIZE_T cObjectIDRangeLength[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *ConditionalWeakTableElementReferences )(
+ ICorProfilerCallback5 * This,
+ /* [in] */ ULONG cRootRefs,
+ /* [size_is][in] */ ObjectID keyRefIds[ ],
+ /* [size_is][in] */ ObjectID valueRefIds[ ],
+ /* [size_is][in] */ GCHandleID rootIds[ ]);
+
+ END_INTERFACE
+ } ICorProfilerCallback5Vtbl;
+
+ interface ICorProfilerCallback5
+ {
+ CONST_VTBL struct ICorProfilerCallback5Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorProfilerCallback5_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorProfilerCallback5_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorProfilerCallback5_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorProfilerCallback5_Initialize(This,pICorProfilerInfoUnk) \
+ ( (This)->lpVtbl -> Initialize(This,pICorProfilerInfoUnk) )
+
+#define ICorProfilerCallback5_Shutdown(This) \
+ ( (This)->lpVtbl -> Shutdown(This) )
+
+#define ICorProfilerCallback5_AppDomainCreationStarted(This,appDomainId) \
+ ( (This)->lpVtbl -> AppDomainCreationStarted(This,appDomainId) )
+
+#define ICorProfilerCallback5_AppDomainCreationFinished(This,appDomainId,hrStatus) \
+ ( (This)->lpVtbl -> AppDomainCreationFinished(This,appDomainId,hrStatus) )
+
+#define ICorProfilerCallback5_AppDomainShutdownStarted(This,appDomainId) \
+ ( (This)->lpVtbl -> AppDomainShutdownStarted(This,appDomainId) )
+
+#define ICorProfilerCallback5_AppDomainShutdownFinished(This,appDomainId,hrStatus) \
+ ( (This)->lpVtbl -> AppDomainShutdownFinished(This,appDomainId,hrStatus) )
+
+#define ICorProfilerCallback5_AssemblyLoadStarted(This,assemblyId) \
+ ( (This)->lpVtbl -> AssemblyLoadStarted(This,assemblyId) )
+
+#define ICorProfilerCallback5_AssemblyLoadFinished(This,assemblyId,hrStatus) \
+ ( (This)->lpVtbl -> AssemblyLoadFinished(This,assemblyId,hrStatus) )
+
+#define ICorProfilerCallback5_AssemblyUnloadStarted(This,assemblyId) \
+ ( (This)->lpVtbl -> AssemblyUnloadStarted(This,assemblyId) )
+
+#define ICorProfilerCallback5_AssemblyUnloadFinished(This,assemblyId,hrStatus) \
+ ( (This)->lpVtbl -> AssemblyUnloadFinished(This,assemblyId,hrStatus) )
+
+#define ICorProfilerCallback5_ModuleLoadStarted(This,moduleId) \
+ ( (This)->lpVtbl -> ModuleLoadStarted(This,moduleId) )
+
+#define ICorProfilerCallback5_ModuleLoadFinished(This,moduleId,hrStatus) \
+ ( (This)->lpVtbl -> ModuleLoadFinished(This,moduleId,hrStatus) )
+
+#define ICorProfilerCallback5_ModuleUnloadStarted(This,moduleId) \
+ ( (This)->lpVtbl -> ModuleUnloadStarted(This,moduleId) )
+
+#define ICorProfilerCallback5_ModuleUnloadFinished(This,moduleId,hrStatus) \
+ ( (This)->lpVtbl -> ModuleUnloadFinished(This,moduleId,hrStatus) )
+
+#define ICorProfilerCallback5_ModuleAttachedToAssembly(This,moduleId,AssemblyId) \
+ ( (This)->lpVtbl -> ModuleAttachedToAssembly(This,moduleId,AssemblyId) )
+
+#define ICorProfilerCallback5_ClassLoadStarted(This,classId) \
+ ( (This)->lpVtbl -> ClassLoadStarted(This,classId) )
+
+#define ICorProfilerCallback5_ClassLoadFinished(This,classId,hrStatus) \
+ ( (This)->lpVtbl -> ClassLoadFinished(This,classId,hrStatus) )
+
+#define ICorProfilerCallback5_ClassUnloadStarted(This,classId) \
+ ( (This)->lpVtbl -> ClassUnloadStarted(This,classId) )
+
+#define ICorProfilerCallback5_ClassUnloadFinished(This,classId,hrStatus) \
+ ( (This)->lpVtbl -> ClassUnloadFinished(This,classId,hrStatus) )
+
+#define ICorProfilerCallback5_FunctionUnloadStarted(This,functionId) \
+ ( (This)->lpVtbl -> FunctionUnloadStarted(This,functionId) )
+
+#define ICorProfilerCallback5_JITCompilationStarted(This,functionId,fIsSafeToBlock) \
+ ( (This)->lpVtbl -> JITCompilationStarted(This,functionId,fIsSafeToBlock) )
+
+#define ICorProfilerCallback5_JITCompilationFinished(This,functionId,hrStatus,fIsSafeToBlock) \
+ ( (This)->lpVtbl -> JITCompilationFinished(This,functionId,hrStatus,fIsSafeToBlock) )
+
+#define ICorProfilerCallback5_JITCachedFunctionSearchStarted(This,functionId,pbUseCachedFunction) \
+ ( (This)->lpVtbl -> JITCachedFunctionSearchStarted(This,functionId,pbUseCachedFunction) )
+
+#define ICorProfilerCallback5_JITCachedFunctionSearchFinished(This,functionId,result) \
+ ( (This)->lpVtbl -> JITCachedFunctionSearchFinished(This,functionId,result) )
+
+#define ICorProfilerCallback5_JITFunctionPitched(This,functionId) \
+ ( (This)->lpVtbl -> JITFunctionPitched(This,functionId) )
+
+#define ICorProfilerCallback5_JITInlining(This,callerId,calleeId,pfShouldInline) \
+ ( (This)->lpVtbl -> JITInlining(This,callerId,calleeId,pfShouldInline) )
+
+#define ICorProfilerCallback5_ThreadCreated(This,threadId) \
+ ( (This)->lpVtbl -> ThreadCreated(This,threadId) )
+
+#define ICorProfilerCallback5_ThreadDestroyed(This,threadId) \
+ ( (This)->lpVtbl -> ThreadDestroyed(This,threadId) )
+
+#define ICorProfilerCallback5_ThreadAssignedToOSThread(This,managedThreadId,osThreadId) \
+ ( (This)->lpVtbl -> ThreadAssignedToOSThread(This,managedThreadId,osThreadId) )
+
+#define ICorProfilerCallback5_RemotingClientInvocationStarted(This) \
+ ( (This)->lpVtbl -> RemotingClientInvocationStarted(This) )
+
+#define ICorProfilerCallback5_RemotingClientSendingMessage(This,pCookie,fIsAsync) \
+ ( (This)->lpVtbl -> RemotingClientSendingMessage(This,pCookie,fIsAsync) )
+
+#define ICorProfilerCallback5_RemotingClientReceivingReply(This,pCookie,fIsAsync) \
+ ( (This)->lpVtbl -> RemotingClientReceivingReply(This,pCookie,fIsAsync) )
+
+#define ICorProfilerCallback5_RemotingClientInvocationFinished(This) \
+ ( (This)->lpVtbl -> RemotingClientInvocationFinished(This) )
+
+#define ICorProfilerCallback5_RemotingServerReceivingMessage(This,pCookie,fIsAsync) \
+ ( (This)->lpVtbl -> RemotingServerReceivingMessage(This,pCookie,fIsAsync) )
+
+#define ICorProfilerCallback5_RemotingServerInvocationStarted(This) \
+ ( (This)->lpVtbl -> RemotingServerInvocationStarted(This) )
+
+#define ICorProfilerCallback5_RemotingServerInvocationReturned(This) \
+ ( (This)->lpVtbl -> RemotingServerInvocationReturned(This) )
+
+#define ICorProfilerCallback5_RemotingServerSendingReply(This,pCookie,fIsAsync) \
+ ( (This)->lpVtbl -> RemotingServerSendingReply(This,pCookie,fIsAsync) )
+
+#define ICorProfilerCallback5_UnmanagedToManagedTransition(This,functionId,reason) \
+ ( (This)->lpVtbl -> UnmanagedToManagedTransition(This,functionId,reason) )
+
+#define ICorProfilerCallback5_ManagedToUnmanagedTransition(This,functionId,reason) \
+ ( (This)->lpVtbl -> ManagedToUnmanagedTransition(This,functionId,reason) )
+
+#define ICorProfilerCallback5_RuntimeSuspendStarted(This,suspendReason) \
+ ( (This)->lpVtbl -> RuntimeSuspendStarted(This,suspendReason) )
+
+#define ICorProfilerCallback5_RuntimeSuspendFinished(This) \
+ ( (This)->lpVtbl -> RuntimeSuspendFinished(This) )
+
+#define ICorProfilerCallback5_RuntimeSuspendAborted(This) \
+ ( (This)->lpVtbl -> RuntimeSuspendAborted(This) )
+
+#define ICorProfilerCallback5_RuntimeResumeStarted(This) \
+ ( (This)->lpVtbl -> RuntimeResumeStarted(This) )
+
+#define ICorProfilerCallback5_RuntimeResumeFinished(This) \
+ ( (This)->lpVtbl -> RuntimeResumeFinished(This) )
+
+#define ICorProfilerCallback5_RuntimeThreadSuspended(This,threadId) \
+ ( (This)->lpVtbl -> RuntimeThreadSuspended(This,threadId) )
+
+#define ICorProfilerCallback5_RuntimeThreadResumed(This,threadId) \
+ ( (This)->lpVtbl -> RuntimeThreadResumed(This,threadId) )
+
+#define ICorProfilerCallback5_MovedReferences(This,cMovedObjectIDRanges,oldObjectIDRangeStart,newObjectIDRangeStart,cObjectIDRangeLength) \
+ ( (This)->lpVtbl -> MovedReferences(This,cMovedObjectIDRanges,oldObjectIDRangeStart,newObjectIDRangeStart,cObjectIDRangeLength) )
+
+#define ICorProfilerCallback5_ObjectAllocated(This,objectId,classId) \
+ ( (This)->lpVtbl -> ObjectAllocated(This,objectId,classId) )
+
+#define ICorProfilerCallback5_ObjectsAllocatedByClass(This,cClassCount,classIds,cObjects) \
+ ( (This)->lpVtbl -> ObjectsAllocatedByClass(This,cClassCount,classIds,cObjects) )
+
+#define ICorProfilerCallback5_ObjectReferences(This,objectId,classId,cObjectRefs,objectRefIds) \
+ ( (This)->lpVtbl -> ObjectReferences(This,objectId,classId,cObjectRefs,objectRefIds) )
+
+#define ICorProfilerCallback5_RootReferences(This,cRootRefs,rootRefIds) \
+ ( (This)->lpVtbl -> RootReferences(This,cRootRefs,rootRefIds) )
+
+#define ICorProfilerCallback5_ExceptionThrown(This,thrownObjectId) \
+ ( (This)->lpVtbl -> ExceptionThrown(This,thrownObjectId) )
+
+#define ICorProfilerCallback5_ExceptionSearchFunctionEnter(This,functionId) \
+ ( (This)->lpVtbl -> ExceptionSearchFunctionEnter(This,functionId) )
+
+#define ICorProfilerCallback5_ExceptionSearchFunctionLeave(This) \
+ ( (This)->lpVtbl -> ExceptionSearchFunctionLeave(This) )
+
+#define ICorProfilerCallback5_ExceptionSearchFilterEnter(This,functionId) \
+ ( (This)->lpVtbl -> ExceptionSearchFilterEnter(This,functionId) )
+
+#define ICorProfilerCallback5_ExceptionSearchFilterLeave(This) \
+ ( (This)->lpVtbl -> ExceptionSearchFilterLeave(This) )
+
+#define ICorProfilerCallback5_ExceptionSearchCatcherFound(This,functionId) \
+ ( (This)->lpVtbl -> ExceptionSearchCatcherFound(This,functionId) )
+
+#define ICorProfilerCallback5_ExceptionOSHandlerEnter(This,__unused) \
+ ( (This)->lpVtbl -> ExceptionOSHandlerEnter(This,__unused) )
+
+#define ICorProfilerCallback5_ExceptionOSHandlerLeave(This,__unused) \
+ ( (This)->lpVtbl -> ExceptionOSHandlerLeave(This,__unused) )
+
+#define ICorProfilerCallback5_ExceptionUnwindFunctionEnter(This,functionId) \
+ ( (This)->lpVtbl -> ExceptionUnwindFunctionEnter(This,functionId) )
+
+#define ICorProfilerCallback5_ExceptionUnwindFunctionLeave(This) \
+ ( (This)->lpVtbl -> ExceptionUnwindFunctionLeave(This) )
+
+#define ICorProfilerCallback5_ExceptionUnwindFinallyEnter(This,functionId) \
+ ( (This)->lpVtbl -> ExceptionUnwindFinallyEnter(This,functionId) )
+
+#define ICorProfilerCallback5_ExceptionUnwindFinallyLeave(This) \
+ ( (This)->lpVtbl -> ExceptionUnwindFinallyLeave(This) )
+
+#define ICorProfilerCallback5_ExceptionCatcherEnter(This,functionId,objectId) \
+ ( (This)->lpVtbl -> ExceptionCatcherEnter(This,functionId,objectId) )
+
+#define ICorProfilerCallback5_ExceptionCatcherLeave(This) \
+ ( (This)->lpVtbl -> ExceptionCatcherLeave(This) )
+
+#define ICorProfilerCallback5_COMClassicVTableCreated(This,wrappedClassId,implementedIID,pVTable,cSlots) \
+ ( (This)->lpVtbl -> COMClassicVTableCreated(This,wrappedClassId,implementedIID,pVTable,cSlots) )
+
+#define ICorProfilerCallback5_COMClassicVTableDestroyed(This,wrappedClassId,implementedIID,pVTable) \
+ ( (This)->lpVtbl -> COMClassicVTableDestroyed(This,wrappedClassId,implementedIID,pVTable) )
+
+#define ICorProfilerCallback5_ExceptionCLRCatcherFound(This) \
+ ( (This)->lpVtbl -> ExceptionCLRCatcherFound(This) )
+
+#define ICorProfilerCallback5_ExceptionCLRCatcherExecute(This) \
+ ( (This)->lpVtbl -> ExceptionCLRCatcherExecute(This) )
+
+
+#define ICorProfilerCallback5_ThreadNameChanged(This,threadId,cchName,name) \
+ ( (This)->lpVtbl -> ThreadNameChanged(This,threadId,cchName,name) )
+
+#define ICorProfilerCallback5_GarbageCollectionStarted(This,cGenerations,generationCollected,reason) \
+ ( (This)->lpVtbl -> GarbageCollectionStarted(This,cGenerations,generationCollected,reason) )
+
+#define ICorProfilerCallback5_SurvivingReferences(This,cSurvivingObjectIDRanges,objectIDRangeStart,cObjectIDRangeLength) \
+ ( (This)->lpVtbl -> SurvivingReferences(This,cSurvivingObjectIDRanges,objectIDRangeStart,cObjectIDRangeLength) )
+
+#define ICorProfilerCallback5_GarbageCollectionFinished(This) \
+ ( (This)->lpVtbl -> GarbageCollectionFinished(This) )
+
+#define ICorProfilerCallback5_FinalizeableObjectQueued(This,finalizerFlags,objectID) \
+ ( (This)->lpVtbl -> FinalizeableObjectQueued(This,finalizerFlags,objectID) )
+
+#define ICorProfilerCallback5_RootReferences2(This,cRootRefs,rootRefIds,rootKinds,rootFlags,rootIds) \
+ ( (This)->lpVtbl -> RootReferences2(This,cRootRefs,rootRefIds,rootKinds,rootFlags,rootIds) )
+
+#define ICorProfilerCallback5_HandleCreated(This,handleId,initialObjectId) \
+ ( (This)->lpVtbl -> HandleCreated(This,handleId,initialObjectId) )
+
+#define ICorProfilerCallback5_HandleDestroyed(This,handleId) \
+ ( (This)->lpVtbl -> HandleDestroyed(This,handleId) )
+
+
+#define ICorProfilerCallback5_InitializeForAttach(This,pCorProfilerInfoUnk,pvClientData,cbClientData) \
+ ( (This)->lpVtbl -> InitializeForAttach(This,pCorProfilerInfoUnk,pvClientData,cbClientData) )
+
+#define ICorProfilerCallback5_ProfilerAttachComplete(This) \
+ ( (This)->lpVtbl -> ProfilerAttachComplete(This) )
+
+#define ICorProfilerCallback5_ProfilerDetachSucceeded(This) \
+ ( (This)->lpVtbl -> ProfilerDetachSucceeded(This) )
+
+
+#define ICorProfilerCallback5_ReJITCompilationStarted(This,functionId,rejitId,fIsSafeToBlock) \
+ ( (This)->lpVtbl -> ReJITCompilationStarted(This,functionId,rejitId,fIsSafeToBlock) )
+
+#define ICorProfilerCallback5_GetReJITParameters(This,moduleId,methodId,pFunctionControl) \
+ ( (This)->lpVtbl -> GetReJITParameters(This,moduleId,methodId,pFunctionControl) )
+
+#define ICorProfilerCallback5_ReJITCompilationFinished(This,functionId,rejitId,hrStatus,fIsSafeToBlock) \
+ ( (This)->lpVtbl -> ReJITCompilationFinished(This,functionId,rejitId,hrStatus,fIsSafeToBlock) )
+
+#define ICorProfilerCallback5_ReJITError(This,moduleId,methodId,functionId,hrStatus) \
+ ( (This)->lpVtbl -> ReJITError(This,moduleId,methodId,functionId,hrStatus) )
+
+#define ICorProfilerCallback5_MovedReferences2(This,cMovedObjectIDRanges,oldObjectIDRangeStart,newObjectIDRangeStart,cObjectIDRangeLength) \
+ ( (This)->lpVtbl -> MovedReferences2(This,cMovedObjectIDRanges,oldObjectIDRangeStart,newObjectIDRangeStart,cObjectIDRangeLength) )
+
+#define ICorProfilerCallback5_SurvivingReferences2(This,cSurvivingObjectIDRanges,objectIDRangeStart,cObjectIDRangeLength) \
+ ( (This)->lpVtbl -> SurvivingReferences2(This,cSurvivingObjectIDRanges,objectIDRangeStart,cObjectIDRangeLength) )
+
+
+#define ICorProfilerCallback5_ConditionalWeakTableElementReferences(This,cRootRefs,keyRefIds,valueRefIds,rootIds) \
+ ( (This)->lpVtbl -> ConditionalWeakTableElementReferences(This,cRootRefs,keyRefIds,valueRefIds,rootIds) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorProfilerCallback5_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorProfilerCallback6_INTERFACE_DEFINED__
+#define __ICorProfilerCallback6_INTERFACE_DEFINED__
+
+/* interface ICorProfilerCallback6 */
+/* [local][unique][uuid][object] */
+
+
+EXTERN_C const IID IID_ICorProfilerCallback6;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("FC13DF4B-4448-4F4F-950C-BA8D19D00C36")
+ ICorProfilerCallback6 : public ICorProfilerCallback5
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetAssemblyReferences(
+ /* [string][in] */ const WCHAR *wszAssemblyPath,
+ /* [in] */ ICorProfilerAssemblyReferenceProvider *pAsmRefProvider) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorProfilerCallback6Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorProfilerCallback6 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorProfilerCallback6 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorProfilerCallback6 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Initialize )(
+ ICorProfilerCallback6 * This,
+ /* [in] */ IUnknown *pICorProfilerInfoUnk);
+
+ HRESULT ( STDMETHODCALLTYPE *Shutdown )(
+ ICorProfilerCallback6 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *AppDomainCreationStarted )(
+ ICorProfilerCallback6 * This,
+ /* [in] */ AppDomainID appDomainId);
+
+ HRESULT ( STDMETHODCALLTYPE *AppDomainCreationFinished )(
+ ICorProfilerCallback6 * This,
+ /* [in] */ AppDomainID appDomainId,
+ /* [in] */ HRESULT hrStatus);
+
+ HRESULT ( STDMETHODCALLTYPE *AppDomainShutdownStarted )(
+ ICorProfilerCallback6 * This,
+ /* [in] */ AppDomainID appDomainId);
+
+ HRESULT ( STDMETHODCALLTYPE *AppDomainShutdownFinished )(
+ ICorProfilerCallback6 * This,
+ /* [in] */ AppDomainID appDomainId,
+ /* [in] */ HRESULT hrStatus);
+
+ HRESULT ( STDMETHODCALLTYPE *AssemblyLoadStarted )(
+ ICorProfilerCallback6 * This,
+ /* [in] */ AssemblyID assemblyId);
+
+ HRESULT ( STDMETHODCALLTYPE *AssemblyLoadFinished )(
+ ICorProfilerCallback6 * This,
+ /* [in] */ AssemblyID assemblyId,
+ /* [in] */ HRESULT hrStatus);
+
+ HRESULT ( STDMETHODCALLTYPE *AssemblyUnloadStarted )(
+ ICorProfilerCallback6 * This,
+ /* [in] */ AssemblyID assemblyId);
+
+ HRESULT ( STDMETHODCALLTYPE *AssemblyUnloadFinished )(
+ ICorProfilerCallback6 * This,
+ /* [in] */ AssemblyID assemblyId,
+ /* [in] */ HRESULT hrStatus);
+
+ HRESULT ( STDMETHODCALLTYPE *ModuleLoadStarted )(
+ ICorProfilerCallback6 * This,
+ /* [in] */ ModuleID moduleId);
+
+ HRESULT ( STDMETHODCALLTYPE *ModuleLoadFinished )(
+ ICorProfilerCallback6 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ HRESULT hrStatus);
+
+ HRESULT ( STDMETHODCALLTYPE *ModuleUnloadStarted )(
+ ICorProfilerCallback6 * This,
+ /* [in] */ ModuleID moduleId);
+
+ HRESULT ( STDMETHODCALLTYPE *ModuleUnloadFinished )(
+ ICorProfilerCallback6 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ HRESULT hrStatus);
+
+ HRESULT ( STDMETHODCALLTYPE *ModuleAttachedToAssembly )(
+ ICorProfilerCallback6 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ AssemblyID AssemblyId);
+
+ HRESULT ( STDMETHODCALLTYPE *ClassLoadStarted )(
+ ICorProfilerCallback6 * This,
+ /* [in] */ ClassID classId);
+
+ HRESULT ( STDMETHODCALLTYPE *ClassLoadFinished )(
+ ICorProfilerCallback6 * This,
+ /* [in] */ ClassID classId,
+ /* [in] */ HRESULT hrStatus);
+
+ HRESULT ( STDMETHODCALLTYPE *ClassUnloadStarted )(
+ ICorProfilerCallback6 * This,
+ /* [in] */ ClassID classId);
+
+ HRESULT ( STDMETHODCALLTYPE *ClassUnloadFinished )(
+ ICorProfilerCallback6 * This,
+ /* [in] */ ClassID classId,
+ /* [in] */ HRESULT hrStatus);
+
+ HRESULT ( STDMETHODCALLTYPE *FunctionUnloadStarted )(
+ ICorProfilerCallback6 * This,
+ /* [in] */ FunctionID functionId);
+
+ HRESULT ( STDMETHODCALLTYPE *JITCompilationStarted )(
+ ICorProfilerCallback6 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ BOOL fIsSafeToBlock);
+
+ HRESULT ( STDMETHODCALLTYPE *JITCompilationFinished )(
+ ICorProfilerCallback6 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ HRESULT hrStatus,
+ /* [in] */ BOOL fIsSafeToBlock);
+
+ HRESULT ( STDMETHODCALLTYPE *JITCachedFunctionSearchStarted )(
+ ICorProfilerCallback6 * This,
+ /* [in] */ FunctionID functionId,
+ /* [out] */ BOOL *pbUseCachedFunction);
+
+ HRESULT ( STDMETHODCALLTYPE *JITCachedFunctionSearchFinished )(
+ ICorProfilerCallback6 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ COR_PRF_JIT_CACHE result);
+
+ HRESULT ( STDMETHODCALLTYPE *JITFunctionPitched )(
+ ICorProfilerCallback6 * This,
+ /* [in] */ FunctionID functionId);
+
+ HRESULT ( STDMETHODCALLTYPE *JITInlining )(
+ ICorProfilerCallback6 * This,
+ /* [in] */ FunctionID callerId,
+ /* [in] */ FunctionID calleeId,
+ /* [out] */ BOOL *pfShouldInline);
+
+ HRESULT ( STDMETHODCALLTYPE *ThreadCreated )(
+ ICorProfilerCallback6 * This,
+ /* [in] */ ThreadID threadId);
+
+ HRESULT ( STDMETHODCALLTYPE *ThreadDestroyed )(
+ ICorProfilerCallback6 * This,
+ /* [in] */ ThreadID threadId);
+
+ HRESULT ( STDMETHODCALLTYPE *ThreadAssignedToOSThread )(
+ ICorProfilerCallback6 * This,
+ /* [in] */ ThreadID managedThreadId,
+ /* [in] */ DWORD osThreadId);
+
+ HRESULT ( STDMETHODCALLTYPE *RemotingClientInvocationStarted )(
+ ICorProfilerCallback6 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *RemotingClientSendingMessage )(
+ ICorProfilerCallback6 * This,
+ /* [in] */ GUID *pCookie,
+ /* [in] */ BOOL fIsAsync);
+
+ HRESULT ( STDMETHODCALLTYPE *RemotingClientReceivingReply )(
+ ICorProfilerCallback6 * This,
+ /* [in] */ GUID *pCookie,
+ /* [in] */ BOOL fIsAsync);
+
+ HRESULT ( STDMETHODCALLTYPE *RemotingClientInvocationFinished )(
+ ICorProfilerCallback6 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *RemotingServerReceivingMessage )(
+ ICorProfilerCallback6 * This,
+ /* [in] */ GUID *pCookie,
+ /* [in] */ BOOL fIsAsync);
+
+ HRESULT ( STDMETHODCALLTYPE *RemotingServerInvocationStarted )(
+ ICorProfilerCallback6 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *RemotingServerInvocationReturned )(
+ ICorProfilerCallback6 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *RemotingServerSendingReply )(
+ ICorProfilerCallback6 * This,
+ /* [in] */ GUID *pCookie,
+ /* [in] */ BOOL fIsAsync);
+
+ HRESULT ( STDMETHODCALLTYPE *UnmanagedToManagedTransition )(
+ ICorProfilerCallback6 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ COR_PRF_TRANSITION_REASON reason);
+
+ HRESULT ( STDMETHODCALLTYPE *ManagedToUnmanagedTransition )(
+ ICorProfilerCallback6 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ COR_PRF_TRANSITION_REASON reason);
+
+ HRESULT ( STDMETHODCALLTYPE *RuntimeSuspendStarted )(
+ ICorProfilerCallback6 * This,
+ /* [in] */ COR_PRF_SUSPEND_REASON suspendReason);
+
+ HRESULT ( STDMETHODCALLTYPE *RuntimeSuspendFinished )(
+ ICorProfilerCallback6 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *RuntimeSuspendAborted )(
+ ICorProfilerCallback6 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *RuntimeResumeStarted )(
+ ICorProfilerCallback6 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *RuntimeResumeFinished )(
+ ICorProfilerCallback6 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *RuntimeThreadSuspended )(
+ ICorProfilerCallback6 * This,
+ /* [in] */ ThreadID threadId);
+
+ HRESULT ( STDMETHODCALLTYPE *RuntimeThreadResumed )(
+ ICorProfilerCallback6 * This,
+ /* [in] */ ThreadID threadId);
+
+ HRESULT ( STDMETHODCALLTYPE *MovedReferences )(
+ ICorProfilerCallback6 * This,
+ /* [in] */ ULONG cMovedObjectIDRanges,
+ /* [size_is][in] */ ObjectID oldObjectIDRangeStart[ ],
+ /* [size_is][in] */ ObjectID newObjectIDRangeStart[ ],
+ /* [size_is][in] */ ULONG cObjectIDRangeLength[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *ObjectAllocated )(
+ ICorProfilerCallback6 * This,
+ /* [in] */ ObjectID objectId,
+ /* [in] */ ClassID classId);
+
+ HRESULT ( STDMETHODCALLTYPE *ObjectsAllocatedByClass )(
+ ICorProfilerCallback6 * This,
+ /* [in] */ ULONG cClassCount,
+ /* [size_is][in] */ ClassID classIds[ ],
+ /* [size_is][in] */ ULONG cObjects[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *ObjectReferences )(
+ ICorProfilerCallback6 * This,
+ /* [in] */ ObjectID objectId,
+ /* [in] */ ClassID classId,
+ /* [in] */ ULONG cObjectRefs,
+ /* [size_is][in] */ ObjectID objectRefIds[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *RootReferences )(
+ ICorProfilerCallback6 * This,
+ /* [in] */ ULONG cRootRefs,
+ /* [size_is][in] */ ObjectID rootRefIds[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionThrown )(
+ ICorProfilerCallback6 * This,
+ /* [in] */ ObjectID thrownObjectId);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionSearchFunctionEnter )(
+ ICorProfilerCallback6 * This,
+ /* [in] */ FunctionID functionId);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionSearchFunctionLeave )(
+ ICorProfilerCallback6 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionSearchFilterEnter )(
+ ICorProfilerCallback6 * This,
+ /* [in] */ FunctionID functionId);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionSearchFilterLeave )(
+ ICorProfilerCallback6 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionSearchCatcherFound )(
+ ICorProfilerCallback6 * This,
+ /* [in] */ FunctionID functionId);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionOSHandlerEnter )(
+ ICorProfilerCallback6 * This,
+ /* [in] */ UINT_PTR __unused);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionOSHandlerLeave )(
+ ICorProfilerCallback6 * This,
+ /* [in] */ UINT_PTR __unused);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionUnwindFunctionEnter )(
+ ICorProfilerCallback6 * This,
+ /* [in] */ FunctionID functionId);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionUnwindFunctionLeave )(
+ ICorProfilerCallback6 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionUnwindFinallyEnter )(
+ ICorProfilerCallback6 * This,
+ /* [in] */ FunctionID functionId);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionUnwindFinallyLeave )(
+ ICorProfilerCallback6 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionCatcherEnter )(
+ ICorProfilerCallback6 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ ObjectID objectId);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionCatcherLeave )(
+ ICorProfilerCallback6 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *COMClassicVTableCreated )(
+ ICorProfilerCallback6 * This,
+ /* [in] */ ClassID wrappedClassId,
+ /* [in] */ REFGUID implementedIID,
+ /* [in] */ void *pVTable,
+ /* [in] */ ULONG cSlots);
+
+ HRESULT ( STDMETHODCALLTYPE *COMClassicVTableDestroyed )(
+ ICorProfilerCallback6 * This,
+ /* [in] */ ClassID wrappedClassId,
+ /* [in] */ REFGUID implementedIID,
+ /* [in] */ void *pVTable);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionCLRCatcherFound )(
+ ICorProfilerCallback6 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionCLRCatcherExecute )(
+ ICorProfilerCallback6 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *ThreadNameChanged )(
+ ICorProfilerCallback6 * This,
+ /* [in] */ ThreadID threadId,
+ /* [in] */ ULONG cchName,
+ /* [annotation][in] */
+ _In_reads_opt_(cchName) WCHAR name[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GarbageCollectionStarted )(
+ ICorProfilerCallback6 * This,
+ /* [in] */ int cGenerations,
+ /* [size_is][in] */ BOOL generationCollected[ ],
+ /* [in] */ COR_PRF_GC_REASON reason);
+
+ HRESULT ( STDMETHODCALLTYPE *SurvivingReferences )(
+ ICorProfilerCallback6 * This,
+ /* [in] */ ULONG cSurvivingObjectIDRanges,
+ /* [size_is][in] */ ObjectID objectIDRangeStart[ ],
+ /* [size_is][in] */ ULONG cObjectIDRangeLength[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GarbageCollectionFinished )(
+ ICorProfilerCallback6 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *FinalizeableObjectQueued )(
+ ICorProfilerCallback6 * This,
+ /* [in] */ DWORD finalizerFlags,
+ /* [in] */ ObjectID objectID);
+
+ HRESULT ( STDMETHODCALLTYPE *RootReferences2 )(
+ ICorProfilerCallback6 * This,
+ /* [in] */ ULONG cRootRefs,
+ /* [size_is][in] */ ObjectID rootRefIds[ ],
+ /* [size_is][in] */ COR_PRF_GC_ROOT_KIND rootKinds[ ],
+ /* [size_is][in] */ COR_PRF_GC_ROOT_FLAGS rootFlags[ ],
+ /* [size_is][in] */ UINT_PTR rootIds[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *HandleCreated )(
+ ICorProfilerCallback6 * This,
+ /* [in] */ GCHandleID handleId,
+ /* [in] */ ObjectID initialObjectId);
+
+ HRESULT ( STDMETHODCALLTYPE *HandleDestroyed )(
+ ICorProfilerCallback6 * This,
+ /* [in] */ GCHandleID handleId);
+
+ HRESULT ( STDMETHODCALLTYPE *InitializeForAttach )(
+ ICorProfilerCallback6 * This,
+ /* [in] */ IUnknown *pCorProfilerInfoUnk,
+ /* [in] */ void *pvClientData,
+ /* [in] */ UINT cbClientData);
+
+ HRESULT ( STDMETHODCALLTYPE *ProfilerAttachComplete )(
+ ICorProfilerCallback6 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *ProfilerDetachSucceeded )(
+ ICorProfilerCallback6 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *ReJITCompilationStarted )(
+ ICorProfilerCallback6 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ ReJITID rejitId,
+ /* [in] */ BOOL fIsSafeToBlock);
+
+ HRESULT ( STDMETHODCALLTYPE *GetReJITParameters )(
+ ICorProfilerCallback6 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ mdMethodDef methodId,
+ /* [in] */ ICorProfilerFunctionControl *pFunctionControl);
+
+ HRESULT ( STDMETHODCALLTYPE *ReJITCompilationFinished )(
+ ICorProfilerCallback6 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ ReJITID rejitId,
+ /* [in] */ HRESULT hrStatus,
+ /* [in] */ BOOL fIsSafeToBlock);
+
+ HRESULT ( STDMETHODCALLTYPE *ReJITError )(
+ ICorProfilerCallback6 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ mdMethodDef methodId,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ HRESULT hrStatus);
+
+ HRESULT ( STDMETHODCALLTYPE *MovedReferences2 )(
+ ICorProfilerCallback6 * This,
+ /* [in] */ ULONG cMovedObjectIDRanges,
+ /* [size_is][in] */ ObjectID oldObjectIDRangeStart[ ],
+ /* [size_is][in] */ ObjectID newObjectIDRangeStart[ ],
+ /* [size_is][in] */ SIZE_T cObjectIDRangeLength[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *SurvivingReferences2 )(
+ ICorProfilerCallback6 * This,
+ /* [in] */ ULONG cSurvivingObjectIDRanges,
+ /* [size_is][in] */ ObjectID objectIDRangeStart[ ],
+ /* [size_is][in] */ SIZE_T cObjectIDRangeLength[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *ConditionalWeakTableElementReferences )(
+ ICorProfilerCallback6 * This,
+ /* [in] */ ULONG cRootRefs,
+ /* [size_is][in] */ ObjectID keyRefIds[ ],
+ /* [size_is][in] */ ObjectID valueRefIds[ ],
+ /* [size_is][in] */ GCHandleID rootIds[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAssemblyReferences )(
+ ICorProfilerCallback6 * This,
+ /* [string][in] */ const WCHAR *wszAssemblyPath,
+ /* [in] */ ICorProfilerAssemblyReferenceProvider *pAsmRefProvider);
+
+ END_INTERFACE
+ } ICorProfilerCallback6Vtbl;
+
+ interface ICorProfilerCallback6
+ {
+ CONST_VTBL struct ICorProfilerCallback6Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorProfilerCallback6_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorProfilerCallback6_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorProfilerCallback6_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorProfilerCallback6_Initialize(This,pICorProfilerInfoUnk) \
+ ( (This)->lpVtbl -> Initialize(This,pICorProfilerInfoUnk) )
+
+#define ICorProfilerCallback6_Shutdown(This) \
+ ( (This)->lpVtbl -> Shutdown(This) )
+
+#define ICorProfilerCallback6_AppDomainCreationStarted(This,appDomainId) \
+ ( (This)->lpVtbl -> AppDomainCreationStarted(This,appDomainId) )
+
+#define ICorProfilerCallback6_AppDomainCreationFinished(This,appDomainId,hrStatus) \
+ ( (This)->lpVtbl -> AppDomainCreationFinished(This,appDomainId,hrStatus) )
+
+#define ICorProfilerCallback6_AppDomainShutdownStarted(This,appDomainId) \
+ ( (This)->lpVtbl -> AppDomainShutdownStarted(This,appDomainId) )
+
+#define ICorProfilerCallback6_AppDomainShutdownFinished(This,appDomainId,hrStatus) \
+ ( (This)->lpVtbl -> AppDomainShutdownFinished(This,appDomainId,hrStatus) )
+
+#define ICorProfilerCallback6_AssemblyLoadStarted(This,assemblyId) \
+ ( (This)->lpVtbl -> AssemblyLoadStarted(This,assemblyId) )
+
+#define ICorProfilerCallback6_AssemblyLoadFinished(This,assemblyId,hrStatus) \
+ ( (This)->lpVtbl -> AssemblyLoadFinished(This,assemblyId,hrStatus) )
+
+#define ICorProfilerCallback6_AssemblyUnloadStarted(This,assemblyId) \
+ ( (This)->lpVtbl -> AssemblyUnloadStarted(This,assemblyId) )
+
+#define ICorProfilerCallback6_AssemblyUnloadFinished(This,assemblyId,hrStatus) \
+ ( (This)->lpVtbl -> AssemblyUnloadFinished(This,assemblyId,hrStatus) )
+
+#define ICorProfilerCallback6_ModuleLoadStarted(This,moduleId) \
+ ( (This)->lpVtbl -> ModuleLoadStarted(This,moduleId) )
+
+#define ICorProfilerCallback6_ModuleLoadFinished(This,moduleId,hrStatus) \
+ ( (This)->lpVtbl -> ModuleLoadFinished(This,moduleId,hrStatus) )
+
+#define ICorProfilerCallback6_ModuleUnloadStarted(This,moduleId) \
+ ( (This)->lpVtbl -> ModuleUnloadStarted(This,moduleId) )
+
+#define ICorProfilerCallback6_ModuleUnloadFinished(This,moduleId,hrStatus) \
+ ( (This)->lpVtbl -> ModuleUnloadFinished(This,moduleId,hrStatus) )
+
+#define ICorProfilerCallback6_ModuleAttachedToAssembly(This,moduleId,AssemblyId) \
+ ( (This)->lpVtbl -> ModuleAttachedToAssembly(This,moduleId,AssemblyId) )
+
+#define ICorProfilerCallback6_ClassLoadStarted(This,classId) \
+ ( (This)->lpVtbl -> ClassLoadStarted(This,classId) )
+
+#define ICorProfilerCallback6_ClassLoadFinished(This,classId,hrStatus) \
+ ( (This)->lpVtbl -> ClassLoadFinished(This,classId,hrStatus) )
+
+#define ICorProfilerCallback6_ClassUnloadStarted(This,classId) \
+ ( (This)->lpVtbl -> ClassUnloadStarted(This,classId) )
+
+#define ICorProfilerCallback6_ClassUnloadFinished(This,classId,hrStatus) \
+ ( (This)->lpVtbl -> ClassUnloadFinished(This,classId,hrStatus) )
+
+#define ICorProfilerCallback6_FunctionUnloadStarted(This,functionId) \
+ ( (This)->lpVtbl -> FunctionUnloadStarted(This,functionId) )
+
+#define ICorProfilerCallback6_JITCompilationStarted(This,functionId,fIsSafeToBlock) \
+ ( (This)->lpVtbl -> JITCompilationStarted(This,functionId,fIsSafeToBlock) )
+
+#define ICorProfilerCallback6_JITCompilationFinished(This,functionId,hrStatus,fIsSafeToBlock) \
+ ( (This)->lpVtbl -> JITCompilationFinished(This,functionId,hrStatus,fIsSafeToBlock) )
+
+#define ICorProfilerCallback6_JITCachedFunctionSearchStarted(This,functionId,pbUseCachedFunction) \
+ ( (This)->lpVtbl -> JITCachedFunctionSearchStarted(This,functionId,pbUseCachedFunction) )
+
+#define ICorProfilerCallback6_JITCachedFunctionSearchFinished(This,functionId,result) \
+ ( (This)->lpVtbl -> JITCachedFunctionSearchFinished(This,functionId,result) )
+
+#define ICorProfilerCallback6_JITFunctionPitched(This,functionId) \
+ ( (This)->lpVtbl -> JITFunctionPitched(This,functionId) )
+
+#define ICorProfilerCallback6_JITInlining(This,callerId,calleeId,pfShouldInline) \
+ ( (This)->lpVtbl -> JITInlining(This,callerId,calleeId,pfShouldInline) )
+
+#define ICorProfilerCallback6_ThreadCreated(This,threadId) \
+ ( (This)->lpVtbl -> ThreadCreated(This,threadId) )
+
+#define ICorProfilerCallback6_ThreadDestroyed(This,threadId) \
+ ( (This)->lpVtbl -> ThreadDestroyed(This,threadId) )
+
+#define ICorProfilerCallback6_ThreadAssignedToOSThread(This,managedThreadId,osThreadId) \
+ ( (This)->lpVtbl -> ThreadAssignedToOSThread(This,managedThreadId,osThreadId) )
+
+#define ICorProfilerCallback6_RemotingClientInvocationStarted(This) \
+ ( (This)->lpVtbl -> RemotingClientInvocationStarted(This) )
+
+#define ICorProfilerCallback6_RemotingClientSendingMessage(This,pCookie,fIsAsync) \
+ ( (This)->lpVtbl -> RemotingClientSendingMessage(This,pCookie,fIsAsync) )
+
+#define ICorProfilerCallback6_RemotingClientReceivingReply(This,pCookie,fIsAsync) \
+ ( (This)->lpVtbl -> RemotingClientReceivingReply(This,pCookie,fIsAsync) )
+
+#define ICorProfilerCallback6_RemotingClientInvocationFinished(This) \
+ ( (This)->lpVtbl -> RemotingClientInvocationFinished(This) )
+
+#define ICorProfilerCallback6_RemotingServerReceivingMessage(This,pCookie,fIsAsync) \
+ ( (This)->lpVtbl -> RemotingServerReceivingMessage(This,pCookie,fIsAsync) )
+
+#define ICorProfilerCallback6_RemotingServerInvocationStarted(This) \
+ ( (This)->lpVtbl -> RemotingServerInvocationStarted(This) )
+
+#define ICorProfilerCallback6_RemotingServerInvocationReturned(This) \
+ ( (This)->lpVtbl -> RemotingServerInvocationReturned(This) )
+
+#define ICorProfilerCallback6_RemotingServerSendingReply(This,pCookie,fIsAsync) \
+ ( (This)->lpVtbl -> RemotingServerSendingReply(This,pCookie,fIsAsync) )
+
+#define ICorProfilerCallback6_UnmanagedToManagedTransition(This,functionId,reason) \
+ ( (This)->lpVtbl -> UnmanagedToManagedTransition(This,functionId,reason) )
+
+#define ICorProfilerCallback6_ManagedToUnmanagedTransition(This,functionId,reason) \
+ ( (This)->lpVtbl -> ManagedToUnmanagedTransition(This,functionId,reason) )
+
+#define ICorProfilerCallback6_RuntimeSuspendStarted(This,suspendReason) \
+ ( (This)->lpVtbl -> RuntimeSuspendStarted(This,suspendReason) )
+
+#define ICorProfilerCallback6_RuntimeSuspendFinished(This) \
+ ( (This)->lpVtbl -> RuntimeSuspendFinished(This) )
+
+#define ICorProfilerCallback6_RuntimeSuspendAborted(This) \
+ ( (This)->lpVtbl -> RuntimeSuspendAborted(This) )
+
+#define ICorProfilerCallback6_RuntimeResumeStarted(This) \
+ ( (This)->lpVtbl -> RuntimeResumeStarted(This) )
+
+#define ICorProfilerCallback6_RuntimeResumeFinished(This) \
+ ( (This)->lpVtbl -> RuntimeResumeFinished(This) )
+
+#define ICorProfilerCallback6_RuntimeThreadSuspended(This,threadId) \
+ ( (This)->lpVtbl -> RuntimeThreadSuspended(This,threadId) )
+
+#define ICorProfilerCallback6_RuntimeThreadResumed(This,threadId) \
+ ( (This)->lpVtbl -> RuntimeThreadResumed(This,threadId) )
+
+#define ICorProfilerCallback6_MovedReferences(This,cMovedObjectIDRanges,oldObjectIDRangeStart,newObjectIDRangeStart,cObjectIDRangeLength) \
+ ( (This)->lpVtbl -> MovedReferences(This,cMovedObjectIDRanges,oldObjectIDRangeStart,newObjectIDRangeStart,cObjectIDRangeLength) )
+
+#define ICorProfilerCallback6_ObjectAllocated(This,objectId,classId) \
+ ( (This)->lpVtbl -> ObjectAllocated(This,objectId,classId) )
+
+#define ICorProfilerCallback6_ObjectsAllocatedByClass(This,cClassCount,classIds,cObjects) \
+ ( (This)->lpVtbl -> ObjectsAllocatedByClass(This,cClassCount,classIds,cObjects) )
+
+#define ICorProfilerCallback6_ObjectReferences(This,objectId,classId,cObjectRefs,objectRefIds) \
+ ( (This)->lpVtbl -> ObjectReferences(This,objectId,classId,cObjectRefs,objectRefIds) )
+
+#define ICorProfilerCallback6_RootReferences(This,cRootRefs,rootRefIds) \
+ ( (This)->lpVtbl -> RootReferences(This,cRootRefs,rootRefIds) )
+
+#define ICorProfilerCallback6_ExceptionThrown(This,thrownObjectId) \
+ ( (This)->lpVtbl -> ExceptionThrown(This,thrownObjectId) )
+
+#define ICorProfilerCallback6_ExceptionSearchFunctionEnter(This,functionId) \
+ ( (This)->lpVtbl -> ExceptionSearchFunctionEnter(This,functionId) )
+
+#define ICorProfilerCallback6_ExceptionSearchFunctionLeave(This) \
+ ( (This)->lpVtbl -> ExceptionSearchFunctionLeave(This) )
+
+#define ICorProfilerCallback6_ExceptionSearchFilterEnter(This,functionId) \
+ ( (This)->lpVtbl -> ExceptionSearchFilterEnter(This,functionId) )
+
+#define ICorProfilerCallback6_ExceptionSearchFilterLeave(This) \
+ ( (This)->lpVtbl -> ExceptionSearchFilterLeave(This) )
+
+#define ICorProfilerCallback6_ExceptionSearchCatcherFound(This,functionId) \
+ ( (This)->lpVtbl -> ExceptionSearchCatcherFound(This,functionId) )
+
+#define ICorProfilerCallback6_ExceptionOSHandlerEnter(This,__unused) \
+ ( (This)->lpVtbl -> ExceptionOSHandlerEnter(This,__unused) )
+
+#define ICorProfilerCallback6_ExceptionOSHandlerLeave(This,__unused) \
+ ( (This)->lpVtbl -> ExceptionOSHandlerLeave(This,__unused) )
+
+#define ICorProfilerCallback6_ExceptionUnwindFunctionEnter(This,functionId) \
+ ( (This)->lpVtbl -> ExceptionUnwindFunctionEnter(This,functionId) )
+
+#define ICorProfilerCallback6_ExceptionUnwindFunctionLeave(This) \
+ ( (This)->lpVtbl -> ExceptionUnwindFunctionLeave(This) )
+
+#define ICorProfilerCallback6_ExceptionUnwindFinallyEnter(This,functionId) \
+ ( (This)->lpVtbl -> ExceptionUnwindFinallyEnter(This,functionId) )
+
+#define ICorProfilerCallback6_ExceptionUnwindFinallyLeave(This) \
+ ( (This)->lpVtbl -> ExceptionUnwindFinallyLeave(This) )
+
+#define ICorProfilerCallback6_ExceptionCatcherEnter(This,functionId,objectId) \
+ ( (This)->lpVtbl -> ExceptionCatcherEnter(This,functionId,objectId) )
+
+#define ICorProfilerCallback6_ExceptionCatcherLeave(This) \
+ ( (This)->lpVtbl -> ExceptionCatcherLeave(This) )
+
+#define ICorProfilerCallback6_COMClassicVTableCreated(This,wrappedClassId,implementedIID,pVTable,cSlots) \
+ ( (This)->lpVtbl -> COMClassicVTableCreated(This,wrappedClassId,implementedIID,pVTable,cSlots) )
+
+#define ICorProfilerCallback6_COMClassicVTableDestroyed(This,wrappedClassId,implementedIID,pVTable) \
+ ( (This)->lpVtbl -> COMClassicVTableDestroyed(This,wrappedClassId,implementedIID,pVTable) )
+
+#define ICorProfilerCallback6_ExceptionCLRCatcherFound(This) \
+ ( (This)->lpVtbl -> ExceptionCLRCatcherFound(This) )
+
+#define ICorProfilerCallback6_ExceptionCLRCatcherExecute(This) \
+ ( (This)->lpVtbl -> ExceptionCLRCatcherExecute(This) )
+
+
+#define ICorProfilerCallback6_ThreadNameChanged(This,threadId,cchName,name) \
+ ( (This)->lpVtbl -> ThreadNameChanged(This,threadId,cchName,name) )
+
+#define ICorProfilerCallback6_GarbageCollectionStarted(This,cGenerations,generationCollected,reason) \
+ ( (This)->lpVtbl -> GarbageCollectionStarted(This,cGenerations,generationCollected,reason) )
+
+#define ICorProfilerCallback6_SurvivingReferences(This,cSurvivingObjectIDRanges,objectIDRangeStart,cObjectIDRangeLength) \
+ ( (This)->lpVtbl -> SurvivingReferences(This,cSurvivingObjectIDRanges,objectIDRangeStart,cObjectIDRangeLength) )
+
+#define ICorProfilerCallback6_GarbageCollectionFinished(This) \
+ ( (This)->lpVtbl -> GarbageCollectionFinished(This) )
+
+#define ICorProfilerCallback6_FinalizeableObjectQueued(This,finalizerFlags,objectID) \
+ ( (This)->lpVtbl -> FinalizeableObjectQueued(This,finalizerFlags,objectID) )
+
+#define ICorProfilerCallback6_RootReferences2(This,cRootRefs,rootRefIds,rootKinds,rootFlags,rootIds) \
+ ( (This)->lpVtbl -> RootReferences2(This,cRootRefs,rootRefIds,rootKinds,rootFlags,rootIds) )
+
+#define ICorProfilerCallback6_HandleCreated(This,handleId,initialObjectId) \
+ ( (This)->lpVtbl -> HandleCreated(This,handleId,initialObjectId) )
+
+#define ICorProfilerCallback6_HandleDestroyed(This,handleId) \
+ ( (This)->lpVtbl -> HandleDestroyed(This,handleId) )
+
+
+#define ICorProfilerCallback6_InitializeForAttach(This,pCorProfilerInfoUnk,pvClientData,cbClientData) \
+ ( (This)->lpVtbl -> InitializeForAttach(This,pCorProfilerInfoUnk,pvClientData,cbClientData) )
+
+#define ICorProfilerCallback6_ProfilerAttachComplete(This) \
+ ( (This)->lpVtbl -> ProfilerAttachComplete(This) )
+
+#define ICorProfilerCallback6_ProfilerDetachSucceeded(This) \
+ ( (This)->lpVtbl -> ProfilerDetachSucceeded(This) )
+
+
+#define ICorProfilerCallback6_ReJITCompilationStarted(This,functionId,rejitId,fIsSafeToBlock) \
+ ( (This)->lpVtbl -> ReJITCompilationStarted(This,functionId,rejitId,fIsSafeToBlock) )
+
+#define ICorProfilerCallback6_GetReJITParameters(This,moduleId,methodId,pFunctionControl) \
+ ( (This)->lpVtbl -> GetReJITParameters(This,moduleId,methodId,pFunctionControl) )
+
+#define ICorProfilerCallback6_ReJITCompilationFinished(This,functionId,rejitId,hrStatus,fIsSafeToBlock) \
+ ( (This)->lpVtbl -> ReJITCompilationFinished(This,functionId,rejitId,hrStatus,fIsSafeToBlock) )
+
+#define ICorProfilerCallback6_ReJITError(This,moduleId,methodId,functionId,hrStatus) \
+ ( (This)->lpVtbl -> ReJITError(This,moduleId,methodId,functionId,hrStatus) )
+
+#define ICorProfilerCallback6_MovedReferences2(This,cMovedObjectIDRanges,oldObjectIDRangeStart,newObjectIDRangeStart,cObjectIDRangeLength) \
+ ( (This)->lpVtbl -> MovedReferences2(This,cMovedObjectIDRanges,oldObjectIDRangeStart,newObjectIDRangeStart,cObjectIDRangeLength) )
+
+#define ICorProfilerCallback6_SurvivingReferences2(This,cSurvivingObjectIDRanges,objectIDRangeStart,cObjectIDRangeLength) \
+ ( (This)->lpVtbl -> SurvivingReferences2(This,cSurvivingObjectIDRanges,objectIDRangeStart,cObjectIDRangeLength) )
+
+
+#define ICorProfilerCallback6_ConditionalWeakTableElementReferences(This,cRootRefs,keyRefIds,valueRefIds,rootIds) \
+ ( (This)->lpVtbl -> ConditionalWeakTableElementReferences(This,cRootRefs,keyRefIds,valueRefIds,rootIds) )
+
+
+#define ICorProfilerCallback6_GetAssemblyReferences(This,wszAssemblyPath,pAsmRefProvider) \
+ ( (This)->lpVtbl -> GetAssemblyReferences(This,wszAssemblyPath,pAsmRefProvider) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorProfilerCallback6_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorProfilerCallback7_INTERFACE_DEFINED__
+#define __ICorProfilerCallback7_INTERFACE_DEFINED__
+
+/* interface ICorProfilerCallback7 */
+/* [local][unique][uuid][object] */
+
+
+EXTERN_C const IID IID_ICorProfilerCallback7;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("F76A2DBA-1D52-4539-866C-2AA518F9EFC3")
+ ICorProfilerCallback7 : public ICorProfilerCallback6
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE ModuleInMemorySymbolsUpdated(
+ ModuleID moduleId) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorProfilerCallback7Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorProfilerCallback7 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorProfilerCallback7 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorProfilerCallback7 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Initialize )(
+ ICorProfilerCallback7 * This,
+ /* [in] */ IUnknown *pICorProfilerInfoUnk);
+
+ HRESULT ( STDMETHODCALLTYPE *Shutdown )(
+ ICorProfilerCallback7 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *AppDomainCreationStarted )(
+ ICorProfilerCallback7 * This,
+ /* [in] */ AppDomainID appDomainId);
+
+ HRESULT ( STDMETHODCALLTYPE *AppDomainCreationFinished )(
+ ICorProfilerCallback7 * This,
+ /* [in] */ AppDomainID appDomainId,
+ /* [in] */ HRESULT hrStatus);
+
+ HRESULT ( STDMETHODCALLTYPE *AppDomainShutdownStarted )(
+ ICorProfilerCallback7 * This,
+ /* [in] */ AppDomainID appDomainId);
+
+ HRESULT ( STDMETHODCALLTYPE *AppDomainShutdownFinished )(
+ ICorProfilerCallback7 * This,
+ /* [in] */ AppDomainID appDomainId,
+ /* [in] */ HRESULT hrStatus);
+
+ HRESULT ( STDMETHODCALLTYPE *AssemblyLoadStarted )(
+ ICorProfilerCallback7 * This,
+ /* [in] */ AssemblyID assemblyId);
+
+ HRESULT ( STDMETHODCALLTYPE *AssemblyLoadFinished )(
+ ICorProfilerCallback7 * This,
+ /* [in] */ AssemblyID assemblyId,
+ /* [in] */ HRESULT hrStatus);
+
+ HRESULT ( STDMETHODCALLTYPE *AssemblyUnloadStarted )(
+ ICorProfilerCallback7 * This,
+ /* [in] */ AssemblyID assemblyId);
+
+ HRESULT ( STDMETHODCALLTYPE *AssemblyUnloadFinished )(
+ ICorProfilerCallback7 * This,
+ /* [in] */ AssemblyID assemblyId,
+ /* [in] */ HRESULT hrStatus);
+
+ HRESULT ( STDMETHODCALLTYPE *ModuleLoadStarted )(
+ ICorProfilerCallback7 * This,
+ /* [in] */ ModuleID moduleId);
+
+ HRESULT ( STDMETHODCALLTYPE *ModuleLoadFinished )(
+ ICorProfilerCallback7 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ HRESULT hrStatus);
+
+ HRESULT ( STDMETHODCALLTYPE *ModuleUnloadStarted )(
+ ICorProfilerCallback7 * This,
+ /* [in] */ ModuleID moduleId);
+
+ HRESULT ( STDMETHODCALLTYPE *ModuleUnloadFinished )(
+ ICorProfilerCallback7 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ HRESULT hrStatus);
+
+ HRESULT ( STDMETHODCALLTYPE *ModuleAttachedToAssembly )(
+ ICorProfilerCallback7 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ AssemblyID AssemblyId);
+
+ HRESULT ( STDMETHODCALLTYPE *ClassLoadStarted )(
+ ICorProfilerCallback7 * This,
+ /* [in] */ ClassID classId);
+
+ HRESULT ( STDMETHODCALLTYPE *ClassLoadFinished )(
+ ICorProfilerCallback7 * This,
+ /* [in] */ ClassID classId,
+ /* [in] */ HRESULT hrStatus);
+
+ HRESULT ( STDMETHODCALLTYPE *ClassUnloadStarted )(
+ ICorProfilerCallback7 * This,
+ /* [in] */ ClassID classId);
+
+ HRESULT ( STDMETHODCALLTYPE *ClassUnloadFinished )(
+ ICorProfilerCallback7 * This,
+ /* [in] */ ClassID classId,
+ /* [in] */ HRESULT hrStatus);
+
+ HRESULT ( STDMETHODCALLTYPE *FunctionUnloadStarted )(
+ ICorProfilerCallback7 * This,
+ /* [in] */ FunctionID functionId);
+
+ HRESULT ( STDMETHODCALLTYPE *JITCompilationStarted )(
+ ICorProfilerCallback7 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ BOOL fIsSafeToBlock);
+
+ HRESULT ( STDMETHODCALLTYPE *JITCompilationFinished )(
+ ICorProfilerCallback7 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ HRESULT hrStatus,
+ /* [in] */ BOOL fIsSafeToBlock);
+
+ HRESULT ( STDMETHODCALLTYPE *JITCachedFunctionSearchStarted )(
+ ICorProfilerCallback7 * This,
+ /* [in] */ FunctionID functionId,
+ /* [out] */ BOOL *pbUseCachedFunction);
+
+ HRESULT ( STDMETHODCALLTYPE *JITCachedFunctionSearchFinished )(
+ ICorProfilerCallback7 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ COR_PRF_JIT_CACHE result);
+
+ HRESULT ( STDMETHODCALLTYPE *JITFunctionPitched )(
+ ICorProfilerCallback7 * This,
+ /* [in] */ FunctionID functionId);
+
+ HRESULT ( STDMETHODCALLTYPE *JITInlining )(
+ ICorProfilerCallback7 * This,
+ /* [in] */ FunctionID callerId,
+ /* [in] */ FunctionID calleeId,
+ /* [out] */ BOOL *pfShouldInline);
+
+ HRESULT ( STDMETHODCALLTYPE *ThreadCreated )(
+ ICorProfilerCallback7 * This,
+ /* [in] */ ThreadID threadId);
+
+ HRESULT ( STDMETHODCALLTYPE *ThreadDestroyed )(
+ ICorProfilerCallback7 * This,
+ /* [in] */ ThreadID threadId);
+
+ HRESULT ( STDMETHODCALLTYPE *ThreadAssignedToOSThread )(
+ ICorProfilerCallback7 * This,
+ /* [in] */ ThreadID managedThreadId,
+ /* [in] */ DWORD osThreadId);
+
+ HRESULT ( STDMETHODCALLTYPE *RemotingClientInvocationStarted )(
+ ICorProfilerCallback7 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *RemotingClientSendingMessage )(
+ ICorProfilerCallback7 * This,
+ /* [in] */ GUID *pCookie,
+ /* [in] */ BOOL fIsAsync);
+
+ HRESULT ( STDMETHODCALLTYPE *RemotingClientReceivingReply )(
+ ICorProfilerCallback7 * This,
+ /* [in] */ GUID *pCookie,
+ /* [in] */ BOOL fIsAsync);
+
+ HRESULT ( STDMETHODCALLTYPE *RemotingClientInvocationFinished )(
+ ICorProfilerCallback7 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *RemotingServerReceivingMessage )(
+ ICorProfilerCallback7 * This,
+ /* [in] */ GUID *pCookie,
+ /* [in] */ BOOL fIsAsync);
+
+ HRESULT ( STDMETHODCALLTYPE *RemotingServerInvocationStarted )(
+ ICorProfilerCallback7 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *RemotingServerInvocationReturned )(
+ ICorProfilerCallback7 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *RemotingServerSendingReply )(
+ ICorProfilerCallback7 * This,
+ /* [in] */ GUID *pCookie,
+ /* [in] */ BOOL fIsAsync);
+
+ HRESULT ( STDMETHODCALLTYPE *UnmanagedToManagedTransition )(
+ ICorProfilerCallback7 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ COR_PRF_TRANSITION_REASON reason);
+
+ HRESULT ( STDMETHODCALLTYPE *ManagedToUnmanagedTransition )(
+ ICorProfilerCallback7 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ COR_PRF_TRANSITION_REASON reason);
+
+ HRESULT ( STDMETHODCALLTYPE *RuntimeSuspendStarted )(
+ ICorProfilerCallback7 * This,
+ /* [in] */ COR_PRF_SUSPEND_REASON suspendReason);
+
+ HRESULT ( STDMETHODCALLTYPE *RuntimeSuspendFinished )(
+ ICorProfilerCallback7 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *RuntimeSuspendAborted )(
+ ICorProfilerCallback7 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *RuntimeResumeStarted )(
+ ICorProfilerCallback7 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *RuntimeResumeFinished )(
+ ICorProfilerCallback7 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *RuntimeThreadSuspended )(
+ ICorProfilerCallback7 * This,
+ /* [in] */ ThreadID threadId);
+
+ HRESULT ( STDMETHODCALLTYPE *RuntimeThreadResumed )(
+ ICorProfilerCallback7 * This,
+ /* [in] */ ThreadID threadId);
+
+ HRESULT ( STDMETHODCALLTYPE *MovedReferences )(
+ ICorProfilerCallback7 * This,
+ /* [in] */ ULONG cMovedObjectIDRanges,
+ /* [size_is][in] */ ObjectID oldObjectIDRangeStart[ ],
+ /* [size_is][in] */ ObjectID newObjectIDRangeStart[ ],
+ /* [size_is][in] */ ULONG cObjectIDRangeLength[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *ObjectAllocated )(
+ ICorProfilerCallback7 * This,
+ /* [in] */ ObjectID objectId,
+ /* [in] */ ClassID classId);
+
+ HRESULT ( STDMETHODCALLTYPE *ObjectsAllocatedByClass )(
+ ICorProfilerCallback7 * This,
+ /* [in] */ ULONG cClassCount,
+ /* [size_is][in] */ ClassID classIds[ ],
+ /* [size_is][in] */ ULONG cObjects[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *ObjectReferences )(
+ ICorProfilerCallback7 * This,
+ /* [in] */ ObjectID objectId,
+ /* [in] */ ClassID classId,
+ /* [in] */ ULONG cObjectRefs,
+ /* [size_is][in] */ ObjectID objectRefIds[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *RootReferences )(
+ ICorProfilerCallback7 * This,
+ /* [in] */ ULONG cRootRefs,
+ /* [size_is][in] */ ObjectID rootRefIds[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionThrown )(
+ ICorProfilerCallback7 * This,
+ /* [in] */ ObjectID thrownObjectId);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionSearchFunctionEnter )(
+ ICorProfilerCallback7 * This,
+ /* [in] */ FunctionID functionId);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionSearchFunctionLeave )(
+ ICorProfilerCallback7 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionSearchFilterEnter )(
+ ICorProfilerCallback7 * This,
+ /* [in] */ FunctionID functionId);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionSearchFilterLeave )(
+ ICorProfilerCallback7 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionSearchCatcherFound )(
+ ICorProfilerCallback7 * This,
+ /* [in] */ FunctionID functionId);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionOSHandlerEnter )(
+ ICorProfilerCallback7 * This,
+ /* [in] */ UINT_PTR __unused);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionOSHandlerLeave )(
+ ICorProfilerCallback7 * This,
+ /* [in] */ UINT_PTR __unused);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionUnwindFunctionEnter )(
+ ICorProfilerCallback7 * This,
+ /* [in] */ FunctionID functionId);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionUnwindFunctionLeave )(
+ ICorProfilerCallback7 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionUnwindFinallyEnter )(
+ ICorProfilerCallback7 * This,
+ /* [in] */ FunctionID functionId);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionUnwindFinallyLeave )(
+ ICorProfilerCallback7 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionCatcherEnter )(
+ ICorProfilerCallback7 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ ObjectID objectId);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionCatcherLeave )(
+ ICorProfilerCallback7 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *COMClassicVTableCreated )(
+ ICorProfilerCallback7 * This,
+ /* [in] */ ClassID wrappedClassId,
+ /* [in] */ REFGUID implementedIID,
+ /* [in] */ void *pVTable,
+ /* [in] */ ULONG cSlots);
+
+ HRESULT ( STDMETHODCALLTYPE *COMClassicVTableDestroyed )(
+ ICorProfilerCallback7 * This,
+ /* [in] */ ClassID wrappedClassId,
+ /* [in] */ REFGUID implementedIID,
+ /* [in] */ void *pVTable);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionCLRCatcherFound )(
+ ICorProfilerCallback7 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionCLRCatcherExecute )(
+ ICorProfilerCallback7 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *ThreadNameChanged )(
+ ICorProfilerCallback7 * This,
+ /* [in] */ ThreadID threadId,
+ /* [in] */ ULONG cchName,
+ /* [annotation][in] */
+ _In_reads_opt_(cchName) WCHAR name[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GarbageCollectionStarted )(
+ ICorProfilerCallback7 * This,
+ /* [in] */ int cGenerations,
+ /* [size_is][in] */ BOOL generationCollected[ ],
+ /* [in] */ COR_PRF_GC_REASON reason);
+
+ HRESULT ( STDMETHODCALLTYPE *SurvivingReferences )(
+ ICorProfilerCallback7 * This,
+ /* [in] */ ULONG cSurvivingObjectIDRanges,
+ /* [size_is][in] */ ObjectID objectIDRangeStart[ ],
+ /* [size_is][in] */ ULONG cObjectIDRangeLength[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GarbageCollectionFinished )(
+ ICorProfilerCallback7 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *FinalizeableObjectQueued )(
+ ICorProfilerCallback7 * This,
+ /* [in] */ DWORD finalizerFlags,
+ /* [in] */ ObjectID objectID);
+
+ HRESULT ( STDMETHODCALLTYPE *RootReferences2 )(
+ ICorProfilerCallback7 * This,
+ /* [in] */ ULONG cRootRefs,
+ /* [size_is][in] */ ObjectID rootRefIds[ ],
+ /* [size_is][in] */ COR_PRF_GC_ROOT_KIND rootKinds[ ],
+ /* [size_is][in] */ COR_PRF_GC_ROOT_FLAGS rootFlags[ ],
+ /* [size_is][in] */ UINT_PTR rootIds[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *HandleCreated )(
+ ICorProfilerCallback7 * This,
+ /* [in] */ GCHandleID handleId,
+ /* [in] */ ObjectID initialObjectId);
+
+ HRESULT ( STDMETHODCALLTYPE *HandleDestroyed )(
+ ICorProfilerCallback7 * This,
+ /* [in] */ GCHandleID handleId);
+
+ HRESULT ( STDMETHODCALLTYPE *InitializeForAttach )(
+ ICorProfilerCallback7 * This,
+ /* [in] */ IUnknown *pCorProfilerInfoUnk,
+ /* [in] */ void *pvClientData,
+ /* [in] */ UINT cbClientData);
+
+ HRESULT ( STDMETHODCALLTYPE *ProfilerAttachComplete )(
+ ICorProfilerCallback7 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *ProfilerDetachSucceeded )(
+ ICorProfilerCallback7 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *ReJITCompilationStarted )(
+ ICorProfilerCallback7 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ ReJITID rejitId,
+ /* [in] */ BOOL fIsSafeToBlock);
+
+ HRESULT ( STDMETHODCALLTYPE *GetReJITParameters )(
+ ICorProfilerCallback7 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ mdMethodDef methodId,
+ /* [in] */ ICorProfilerFunctionControl *pFunctionControl);
+
+ HRESULT ( STDMETHODCALLTYPE *ReJITCompilationFinished )(
+ ICorProfilerCallback7 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ ReJITID rejitId,
+ /* [in] */ HRESULT hrStatus,
+ /* [in] */ BOOL fIsSafeToBlock);
+
+ HRESULT ( STDMETHODCALLTYPE *ReJITError )(
+ ICorProfilerCallback7 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ mdMethodDef methodId,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ HRESULT hrStatus);
+
+ HRESULT ( STDMETHODCALLTYPE *MovedReferences2 )(
+ ICorProfilerCallback7 * This,
+ /* [in] */ ULONG cMovedObjectIDRanges,
+ /* [size_is][in] */ ObjectID oldObjectIDRangeStart[ ],
+ /* [size_is][in] */ ObjectID newObjectIDRangeStart[ ],
+ /* [size_is][in] */ SIZE_T cObjectIDRangeLength[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *SurvivingReferences2 )(
+ ICorProfilerCallback7 * This,
+ /* [in] */ ULONG cSurvivingObjectIDRanges,
+ /* [size_is][in] */ ObjectID objectIDRangeStart[ ],
+ /* [size_is][in] */ SIZE_T cObjectIDRangeLength[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *ConditionalWeakTableElementReferences )(
+ ICorProfilerCallback7 * This,
+ /* [in] */ ULONG cRootRefs,
+ /* [size_is][in] */ ObjectID keyRefIds[ ],
+ /* [size_is][in] */ ObjectID valueRefIds[ ],
+ /* [size_is][in] */ GCHandleID rootIds[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAssemblyReferences )(
+ ICorProfilerCallback7 * This,
+ /* [string][in] */ const WCHAR *wszAssemblyPath,
+ /* [in] */ ICorProfilerAssemblyReferenceProvider *pAsmRefProvider);
+
+ HRESULT ( STDMETHODCALLTYPE *ModuleInMemorySymbolsUpdated )(
+ ICorProfilerCallback7 * This,
+ ModuleID moduleId);
+
+ END_INTERFACE
+ } ICorProfilerCallback7Vtbl;
+
+ interface ICorProfilerCallback7
+ {
+ CONST_VTBL struct ICorProfilerCallback7Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorProfilerCallback7_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorProfilerCallback7_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorProfilerCallback7_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorProfilerCallback7_Initialize(This,pICorProfilerInfoUnk) \
+ ( (This)->lpVtbl -> Initialize(This,pICorProfilerInfoUnk) )
+
+#define ICorProfilerCallback7_Shutdown(This) \
+ ( (This)->lpVtbl -> Shutdown(This) )
+
+#define ICorProfilerCallback7_AppDomainCreationStarted(This,appDomainId) \
+ ( (This)->lpVtbl -> AppDomainCreationStarted(This,appDomainId) )
+
+#define ICorProfilerCallback7_AppDomainCreationFinished(This,appDomainId,hrStatus) \
+ ( (This)->lpVtbl -> AppDomainCreationFinished(This,appDomainId,hrStatus) )
+
+#define ICorProfilerCallback7_AppDomainShutdownStarted(This,appDomainId) \
+ ( (This)->lpVtbl -> AppDomainShutdownStarted(This,appDomainId) )
+
+#define ICorProfilerCallback7_AppDomainShutdownFinished(This,appDomainId,hrStatus) \
+ ( (This)->lpVtbl -> AppDomainShutdownFinished(This,appDomainId,hrStatus) )
+
+#define ICorProfilerCallback7_AssemblyLoadStarted(This,assemblyId) \
+ ( (This)->lpVtbl -> AssemblyLoadStarted(This,assemblyId) )
+
+#define ICorProfilerCallback7_AssemblyLoadFinished(This,assemblyId,hrStatus) \
+ ( (This)->lpVtbl -> AssemblyLoadFinished(This,assemblyId,hrStatus) )
+
+#define ICorProfilerCallback7_AssemblyUnloadStarted(This,assemblyId) \
+ ( (This)->lpVtbl -> AssemblyUnloadStarted(This,assemblyId) )
+
+#define ICorProfilerCallback7_AssemblyUnloadFinished(This,assemblyId,hrStatus) \
+ ( (This)->lpVtbl -> AssemblyUnloadFinished(This,assemblyId,hrStatus) )
+
+#define ICorProfilerCallback7_ModuleLoadStarted(This,moduleId) \
+ ( (This)->lpVtbl -> ModuleLoadStarted(This,moduleId) )
+
+#define ICorProfilerCallback7_ModuleLoadFinished(This,moduleId,hrStatus) \
+ ( (This)->lpVtbl -> ModuleLoadFinished(This,moduleId,hrStatus) )
+
+#define ICorProfilerCallback7_ModuleUnloadStarted(This,moduleId) \
+ ( (This)->lpVtbl -> ModuleUnloadStarted(This,moduleId) )
+
+#define ICorProfilerCallback7_ModuleUnloadFinished(This,moduleId,hrStatus) \
+ ( (This)->lpVtbl -> ModuleUnloadFinished(This,moduleId,hrStatus) )
+
+#define ICorProfilerCallback7_ModuleAttachedToAssembly(This,moduleId,AssemblyId) \
+ ( (This)->lpVtbl -> ModuleAttachedToAssembly(This,moduleId,AssemblyId) )
+
+#define ICorProfilerCallback7_ClassLoadStarted(This,classId) \
+ ( (This)->lpVtbl -> ClassLoadStarted(This,classId) )
+
+#define ICorProfilerCallback7_ClassLoadFinished(This,classId,hrStatus) \
+ ( (This)->lpVtbl -> ClassLoadFinished(This,classId,hrStatus) )
+
+#define ICorProfilerCallback7_ClassUnloadStarted(This,classId) \
+ ( (This)->lpVtbl -> ClassUnloadStarted(This,classId) )
+
+#define ICorProfilerCallback7_ClassUnloadFinished(This,classId,hrStatus) \
+ ( (This)->lpVtbl -> ClassUnloadFinished(This,classId,hrStatus) )
+
+#define ICorProfilerCallback7_FunctionUnloadStarted(This,functionId) \
+ ( (This)->lpVtbl -> FunctionUnloadStarted(This,functionId) )
+
+#define ICorProfilerCallback7_JITCompilationStarted(This,functionId,fIsSafeToBlock) \
+ ( (This)->lpVtbl -> JITCompilationStarted(This,functionId,fIsSafeToBlock) )
+
+#define ICorProfilerCallback7_JITCompilationFinished(This,functionId,hrStatus,fIsSafeToBlock) \
+ ( (This)->lpVtbl -> JITCompilationFinished(This,functionId,hrStatus,fIsSafeToBlock) )
+
+#define ICorProfilerCallback7_JITCachedFunctionSearchStarted(This,functionId,pbUseCachedFunction) \
+ ( (This)->lpVtbl -> JITCachedFunctionSearchStarted(This,functionId,pbUseCachedFunction) )
+
+#define ICorProfilerCallback7_JITCachedFunctionSearchFinished(This,functionId,result) \
+ ( (This)->lpVtbl -> JITCachedFunctionSearchFinished(This,functionId,result) )
+
+#define ICorProfilerCallback7_JITFunctionPitched(This,functionId) \
+ ( (This)->lpVtbl -> JITFunctionPitched(This,functionId) )
+
+#define ICorProfilerCallback7_JITInlining(This,callerId,calleeId,pfShouldInline) \
+ ( (This)->lpVtbl -> JITInlining(This,callerId,calleeId,pfShouldInline) )
+
+#define ICorProfilerCallback7_ThreadCreated(This,threadId) \
+ ( (This)->lpVtbl -> ThreadCreated(This,threadId) )
+
+#define ICorProfilerCallback7_ThreadDestroyed(This,threadId) \
+ ( (This)->lpVtbl -> ThreadDestroyed(This,threadId) )
+
+#define ICorProfilerCallback7_ThreadAssignedToOSThread(This,managedThreadId,osThreadId) \
+ ( (This)->lpVtbl -> ThreadAssignedToOSThread(This,managedThreadId,osThreadId) )
+
+#define ICorProfilerCallback7_RemotingClientInvocationStarted(This) \
+ ( (This)->lpVtbl -> RemotingClientInvocationStarted(This) )
+
+#define ICorProfilerCallback7_RemotingClientSendingMessage(This,pCookie,fIsAsync) \
+ ( (This)->lpVtbl -> RemotingClientSendingMessage(This,pCookie,fIsAsync) )
+
+#define ICorProfilerCallback7_RemotingClientReceivingReply(This,pCookie,fIsAsync) \
+ ( (This)->lpVtbl -> RemotingClientReceivingReply(This,pCookie,fIsAsync) )
+
+#define ICorProfilerCallback7_RemotingClientInvocationFinished(This) \
+ ( (This)->lpVtbl -> RemotingClientInvocationFinished(This) )
+
+#define ICorProfilerCallback7_RemotingServerReceivingMessage(This,pCookie,fIsAsync) \
+ ( (This)->lpVtbl -> RemotingServerReceivingMessage(This,pCookie,fIsAsync) )
+
+#define ICorProfilerCallback7_RemotingServerInvocationStarted(This) \
+ ( (This)->lpVtbl -> RemotingServerInvocationStarted(This) )
+
+#define ICorProfilerCallback7_RemotingServerInvocationReturned(This) \
+ ( (This)->lpVtbl -> RemotingServerInvocationReturned(This) )
+
+#define ICorProfilerCallback7_RemotingServerSendingReply(This,pCookie,fIsAsync) \
+ ( (This)->lpVtbl -> RemotingServerSendingReply(This,pCookie,fIsAsync) )
+
+#define ICorProfilerCallback7_UnmanagedToManagedTransition(This,functionId,reason) \
+ ( (This)->lpVtbl -> UnmanagedToManagedTransition(This,functionId,reason) )
+
+#define ICorProfilerCallback7_ManagedToUnmanagedTransition(This,functionId,reason) \
+ ( (This)->lpVtbl -> ManagedToUnmanagedTransition(This,functionId,reason) )
+
+#define ICorProfilerCallback7_RuntimeSuspendStarted(This,suspendReason) \
+ ( (This)->lpVtbl -> RuntimeSuspendStarted(This,suspendReason) )
+
+#define ICorProfilerCallback7_RuntimeSuspendFinished(This) \
+ ( (This)->lpVtbl -> RuntimeSuspendFinished(This) )
+
+#define ICorProfilerCallback7_RuntimeSuspendAborted(This) \
+ ( (This)->lpVtbl -> RuntimeSuspendAborted(This) )
+
+#define ICorProfilerCallback7_RuntimeResumeStarted(This) \
+ ( (This)->lpVtbl -> RuntimeResumeStarted(This) )
+
+#define ICorProfilerCallback7_RuntimeResumeFinished(This) \
+ ( (This)->lpVtbl -> RuntimeResumeFinished(This) )
+
+#define ICorProfilerCallback7_RuntimeThreadSuspended(This,threadId) \
+ ( (This)->lpVtbl -> RuntimeThreadSuspended(This,threadId) )
+
+#define ICorProfilerCallback7_RuntimeThreadResumed(This,threadId) \
+ ( (This)->lpVtbl -> RuntimeThreadResumed(This,threadId) )
+
+#define ICorProfilerCallback7_MovedReferences(This,cMovedObjectIDRanges,oldObjectIDRangeStart,newObjectIDRangeStart,cObjectIDRangeLength) \
+ ( (This)->lpVtbl -> MovedReferences(This,cMovedObjectIDRanges,oldObjectIDRangeStart,newObjectIDRangeStart,cObjectIDRangeLength) )
+
+#define ICorProfilerCallback7_ObjectAllocated(This,objectId,classId) \
+ ( (This)->lpVtbl -> ObjectAllocated(This,objectId,classId) )
+
+#define ICorProfilerCallback7_ObjectsAllocatedByClass(This,cClassCount,classIds,cObjects) \
+ ( (This)->lpVtbl -> ObjectsAllocatedByClass(This,cClassCount,classIds,cObjects) )
+
+#define ICorProfilerCallback7_ObjectReferences(This,objectId,classId,cObjectRefs,objectRefIds) \
+ ( (This)->lpVtbl -> ObjectReferences(This,objectId,classId,cObjectRefs,objectRefIds) )
+
+#define ICorProfilerCallback7_RootReferences(This,cRootRefs,rootRefIds) \
+ ( (This)->lpVtbl -> RootReferences(This,cRootRefs,rootRefIds) )
+
+#define ICorProfilerCallback7_ExceptionThrown(This,thrownObjectId) \
+ ( (This)->lpVtbl -> ExceptionThrown(This,thrownObjectId) )
+
+#define ICorProfilerCallback7_ExceptionSearchFunctionEnter(This,functionId) \
+ ( (This)->lpVtbl -> ExceptionSearchFunctionEnter(This,functionId) )
+
+#define ICorProfilerCallback7_ExceptionSearchFunctionLeave(This) \
+ ( (This)->lpVtbl -> ExceptionSearchFunctionLeave(This) )
+
+#define ICorProfilerCallback7_ExceptionSearchFilterEnter(This,functionId) \
+ ( (This)->lpVtbl -> ExceptionSearchFilterEnter(This,functionId) )
+
+#define ICorProfilerCallback7_ExceptionSearchFilterLeave(This) \
+ ( (This)->lpVtbl -> ExceptionSearchFilterLeave(This) )
+
+#define ICorProfilerCallback7_ExceptionSearchCatcherFound(This,functionId) \
+ ( (This)->lpVtbl -> ExceptionSearchCatcherFound(This,functionId) )
+
+#define ICorProfilerCallback7_ExceptionOSHandlerEnter(This,__unused) \
+ ( (This)->lpVtbl -> ExceptionOSHandlerEnter(This,__unused) )
+
+#define ICorProfilerCallback7_ExceptionOSHandlerLeave(This,__unused) \
+ ( (This)->lpVtbl -> ExceptionOSHandlerLeave(This,__unused) )
+
+#define ICorProfilerCallback7_ExceptionUnwindFunctionEnter(This,functionId) \
+ ( (This)->lpVtbl -> ExceptionUnwindFunctionEnter(This,functionId) )
+
+#define ICorProfilerCallback7_ExceptionUnwindFunctionLeave(This) \
+ ( (This)->lpVtbl -> ExceptionUnwindFunctionLeave(This) )
+
+#define ICorProfilerCallback7_ExceptionUnwindFinallyEnter(This,functionId) \
+ ( (This)->lpVtbl -> ExceptionUnwindFinallyEnter(This,functionId) )
+
+#define ICorProfilerCallback7_ExceptionUnwindFinallyLeave(This) \
+ ( (This)->lpVtbl -> ExceptionUnwindFinallyLeave(This) )
+
+#define ICorProfilerCallback7_ExceptionCatcherEnter(This,functionId,objectId) \
+ ( (This)->lpVtbl -> ExceptionCatcherEnter(This,functionId,objectId) )
+
+#define ICorProfilerCallback7_ExceptionCatcherLeave(This) \
+ ( (This)->lpVtbl -> ExceptionCatcherLeave(This) )
+
+#define ICorProfilerCallback7_COMClassicVTableCreated(This,wrappedClassId,implementedIID,pVTable,cSlots) \
+ ( (This)->lpVtbl -> COMClassicVTableCreated(This,wrappedClassId,implementedIID,pVTable,cSlots) )
+
+#define ICorProfilerCallback7_COMClassicVTableDestroyed(This,wrappedClassId,implementedIID,pVTable) \
+ ( (This)->lpVtbl -> COMClassicVTableDestroyed(This,wrappedClassId,implementedIID,pVTable) )
+
+#define ICorProfilerCallback7_ExceptionCLRCatcherFound(This) \
+ ( (This)->lpVtbl -> ExceptionCLRCatcherFound(This) )
+
+#define ICorProfilerCallback7_ExceptionCLRCatcherExecute(This) \
+ ( (This)->lpVtbl -> ExceptionCLRCatcherExecute(This) )
+
+
+#define ICorProfilerCallback7_ThreadNameChanged(This,threadId,cchName,name) \
+ ( (This)->lpVtbl -> ThreadNameChanged(This,threadId,cchName,name) )
+
+#define ICorProfilerCallback7_GarbageCollectionStarted(This,cGenerations,generationCollected,reason) \
+ ( (This)->lpVtbl -> GarbageCollectionStarted(This,cGenerations,generationCollected,reason) )
+
+#define ICorProfilerCallback7_SurvivingReferences(This,cSurvivingObjectIDRanges,objectIDRangeStart,cObjectIDRangeLength) \
+ ( (This)->lpVtbl -> SurvivingReferences(This,cSurvivingObjectIDRanges,objectIDRangeStart,cObjectIDRangeLength) )
+
+#define ICorProfilerCallback7_GarbageCollectionFinished(This) \
+ ( (This)->lpVtbl -> GarbageCollectionFinished(This) )
+
+#define ICorProfilerCallback7_FinalizeableObjectQueued(This,finalizerFlags,objectID) \
+ ( (This)->lpVtbl -> FinalizeableObjectQueued(This,finalizerFlags,objectID) )
+
+#define ICorProfilerCallback7_RootReferences2(This,cRootRefs,rootRefIds,rootKinds,rootFlags,rootIds) \
+ ( (This)->lpVtbl -> RootReferences2(This,cRootRefs,rootRefIds,rootKinds,rootFlags,rootIds) )
+
+#define ICorProfilerCallback7_HandleCreated(This,handleId,initialObjectId) \
+ ( (This)->lpVtbl -> HandleCreated(This,handleId,initialObjectId) )
+
+#define ICorProfilerCallback7_HandleDestroyed(This,handleId) \
+ ( (This)->lpVtbl -> HandleDestroyed(This,handleId) )
+
+
+#define ICorProfilerCallback7_InitializeForAttach(This,pCorProfilerInfoUnk,pvClientData,cbClientData) \
+ ( (This)->lpVtbl -> InitializeForAttach(This,pCorProfilerInfoUnk,pvClientData,cbClientData) )
+
+#define ICorProfilerCallback7_ProfilerAttachComplete(This) \
+ ( (This)->lpVtbl -> ProfilerAttachComplete(This) )
+
+#define ICorProfilerCallback7_ProfilerDetachSucceeded(This) \
+ ( (This)->lpVtbl -> ProfilerDetachSucceeded(This) )
+
+
+#define ICorProfilerCallback7_ReJITCompilationStarted(This,functionId,rejitId,fIsSafeToBlock) \
+ ( (This)->lpVtbl -> ReJITCompilationStarted(This,functionId,rejitId,fIsSafeToBlock) )
+
+#define ICorProfilerCallback7_GetReJITParameters(This,moduleId,methodId,pFunctionControl) \
+ ( (This)->lpVtbl -> GetReJITParameters(This,moduleId,methodId,pFunctionControl) )
+
+#define ICorProfilerCallback7_ReJITCompilationFinished(This,functionId,rejitId,hrStatus,fIsSafeToBlock) \
+ ( (This)->lpVtbl -> ReJITCompilationFinished(This,functionId,rejitId,hrStatus,fIsSafeToBlock) )
+
+#define ICorProfilerCallback7_ReJITError(This,moduleId,methodId,functionId,hrStatus) \
+ ( (This)->lpVtbl -> ReJITError(This,moduleId,methodId,functionId,hrStatus) )
+
+#define ICorProfilerCallback7_MovedReferences2(This,cMovedObjectIDRanges,oldObjectIDRangeStart,newObjectIDRangeStart,cObjectIDRangeLength) \
+ ( (This)->lpVtbl -> MovedReferences2(This,cMovedObjectIDRanges,oldObjectIDRangeStart,newObjectIDRangeStart,cObjectIDRangeLength) )
+
+#define ICorProfilerCallback7_SurvivingReferences2(This,cSurvivingObjectIDRanges,objectIDRangeStart,cObjectIDRangeLength) \
+ ( (This)->lpVtbl -> SurvivingReferences2(This,cSurvivingObjectIDRanges,objectIDRangeStart,cObjectIDRangeLength) )
+
+
+#define ICorProfilerCallback7_ConditionalWeakTableElementReferences(This,cRootRefs,keyRefIds,valueRefIds,rootIds) \
+ ( (This)->lpVtbl -> ConditionalWeakTableElementReferences(This,cRootRefs,keyRefIds,valueRefIds,rootIds) )
+
+
+#define ICorProfilerCallback7_GetAssemblyReferences(This,wszAssemblyPath,pAsmRefProvider) \
+ ( (This)->lpVtbl -> GetAssemblyReferences(This,wszAssemblyPath,pAsmRefProvider) )
+
+
+#define ICorProfilerCallback7_ModuleInMemorySymbolsUpdated(This,moduleId) \
+ ( (This)->lpVtbl -> ModuleInMemorySymbolsUpdated(This,moduleId) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorProfilerCallback7_INTERFACE_DEFINED__ */
+
+
+/* interface __MIDL_itf_corprof_0000_0007 */
+/* [local] */
+
+typedef /* [public] */
+enum __MIDL___MIDL_itf_corprof_0000_0007_0001
+ {
+ COR_PRF_CODEGEN_DISABLE_INLINING = 0x1,
+ COR_PRF_CODEGEN_DISABLE_ALL_OPTIMIZATIONS = 0x2
+ } COR_PRF_CODEGEN_FLAGS;
+
+
+
+extern RPC_IF_HANDLE __MIDL_itf_corprof_0000_0007_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_corprof_0000_0007_v0_0_s_ifspec;
+
+#ifndef __ICorProfilerInfo_INTERFACE_DEFINED__
+#define __ICorProfilerInfo_INTERFACE_DEFINED__
+
+/* interface ICorProfilerInfo */
+/* [local][unique][uuid][object] */
+
+
+EXTERN_C const IID IID_ICorProfilerInfo;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("28B5557D-3F3F-48b4-90B2-5F9EEA2F6C48")
+ ICorProfilerInfo : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetClassFromObject(
+ /* [in] */ ObjectID objectId,
+ /* [out] */ ClassID *pClassId) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetClassFromToken(
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ mdTypeDef typeDef,
+ /* [out] */ ClassID *pClassId) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetCodeInfo(
+ /* [in] */ FunctionID functionId,
+ /* [out] */ LPCBYTE *pStart,
+ /* [out] */ ULONG *pcSize) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetEventMask(
+ /* [out] */ DWORD *pdwEvents) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetFunctionFromIP(
+ /* [in] */ LPCBYTE ip,
+ /* [out] */ FunctionID *pFunctionId) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetFunctionFromToken(
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ mdToken token,
+ /* [out] */ FunctionID *pFunctionId) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetHandleFromThread(
+ /* [in] */ ThreadID threadId,
+ /* [out] */ HANDLE *phThread) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetObjectSize(
+ /* [in] */ ObjectID objectId,
+ /* [out] */ ULONG *pcSize) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE IsArrayClass(
+ /* [in] */ ClassID classId,
+ /* [out] */ CorElementType *pBaseElemType,
+ /* [out] */ ClassID *pBaseClassId,
+ /* [out] */ ULONG *pcRank) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetThreadInfo(
+ /* [in] */ ThreadID threadId,
+ /* [out] */ DWORD *pdwWin32ThreadId) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetCurrentThreadID(
+ /* [out] */ ThreadID *pThreadId) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetClassIDInfo(
+ /* [in] */ ClassID classId,
+ /* [out] */ ModuleID *pModuleId,
+ /* [out] */ mdTypeDef *pTypeDefToken) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetFunctionInfo(
+ /* [in] */ FunctionID functionId,
+ /* [out] */ ClassID *pClassId,
+ /* [out] */ ModuleID *pModuleId,
+ /* [out] */ mdToken *pToken) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetEventMask(
+ /* [in] */ DWORD dwEvents) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetEnterLeaveFunctionHooks(
+ /* [in] */ FunctionEnter *pFuncEnter,
+ /* [in] */ FunctionLeave *pFuncLeave,
+ /* [in] */ FunctionTailcall *pFuncTailcall) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetFunctionIDMapper(
+ /* [in] */ FunctionIDMapper *pFunc) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetTokenAndMetaDataFromFunction(
+ /* [in] */ FunctionID functionId,
+ /* [in] */ REFIID riid,
+ /* [out] */ IUnknown **ppImport,
+ /* [out] */ mdToken *pToken) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetModuleInfo(
+ /* [in] */ ModuleID moduleId,
+ /* [out] */ LPCBYTE *ppBaseLoadAddress,
+ /* [in] */ ULONG cchName,
+ /* [out] */ ULONG *pcchName,
+ /* [annotation][out] */
+ _Out_writes_to_(cchName, *pcchName) WCHAR szName[ ],
+ /* [out] */ AssemblyID *pAssemblyId) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetModuleMetaData(
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ DWORD dwOpenFlags,
+ /* [in] */ REFIID riid,
+ /* [out] */ IUnknown **ppOut) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetILFunctionBody(
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ mdMethodDef methodId,
+ /* [out] */ LPCBYTE *ppMethodHeader,
+ /* [out] */ ULONG *pcbMethodSize) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetILFunctionBodyAllocator(
+ /* [in] */ ModuleID moduleId,
+ /* [out] */ IMethodMalloc **ppMalloc) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetILFunctionBody(
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ mdMethodDef methodid,
+ /* [in] */ LPCBYTE pbNewILMethodHeader) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetAppDomainInfo(
+ /* [in] */ AppDomainID appDomainId,
+ /* [in] */ ULONG cchName,
+ /* [out] */ ULONG *pcchName,
+ /* [annotation][out] */
+ _Out_writes_to_(cchName, *pcchName) WCHAR szName[ ],
+ /* [out] */ ProcessID *pProcessId) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetAssemblyInfo(
+ /* [in] */ AssemblyID assemblyId,
+ /* [in] */ ULONG cchName,
+ /* [out] */ ULONG *pcchName,
+ /* [annotation][out] */
+ _Out_writes_to_(cchName, *pcchName) WCHAR szName[ ],
+ /* [out] */ AppDomainID *pAppDomainId,
+ /* [out] */ ModuleID *pModuleId) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetFunctionReJIT(
+ /* [in] */ FunctionID functionId) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ForceGC( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetILInstrumentedCodeMap(
+ /* [in] */ FunctionID functionId,
+ /* [in] */ BOOL fStartJit,
+ /* [in] */ ULONG cILMapEntries,
+ /* [size_is][in] */ COR_IL_MAP rgILMapEntries[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetInprocInspectionInterface(
+ /* [out] */ IUnknown **ppicd) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetInprocInspectionIThisThread(
+ /* [out] */ IUnknown **ppicd) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetThreadContext(
+ /* [in] */ ThreadID threadId,
+ /* [out] */ ContextID *pContextId) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE BeginInprocDebugging(
+ /* [in] */ BOOL fThisThreadOnly,
+ /* [out] */ DWORD *pdwProfilerContext) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EndInprocDebugging(
+ /* [in] */ DWORD dwProfilerContext) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetILToNativeMapping(
+ /* [in] */ FunctionID functionId,
+ /* [in] */ ULONG32 cMap,
+ /* [out] */ ULONG32 *pcMap,
+ /* [length_is][size_is][out] */ COR_DEBUG_IL_TO_NATIVE_MAP map[ ]) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorProfilerInfoVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorProfilerInfo * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorProfilerInfo * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorProfilerInfo * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetClassFromObject )(
+ ICorProfilerInfo * This,
+ /* [in] */ ObjectID objectId,
+ /* [out] */ ClassID *pClassId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetClassFromToken )(
+ ICorProfilerInfo * This,
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ mdTypeDef typeDef,
+ /* [out] */ ClassID *pClassId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCodeInfo )(
+ ICorProfilerInfo * This,
+ /* [in] */ FunctionID functionId,
+ /* [out] */ LPCBYTE *pStart,
+ /* [out] */ ULONG *pcSize);
+
+ HRESULT ( STDMETHODCALLTYPE *GetEventMask )(
+ ICorProfilerInfo * This,
+ /* [out] */ DWORD *pdwEvents);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFunctionFromIP )(
+ ICorProfilerInfo * This,
+ /* [in] */ LPCBYTE ip,
+ /* [out] */ FunctionID *pFunctionId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFunctionFromToken )(
+ ICorProfilerInfo * This,
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ mdToken token,
+ /* [out] */ FunctionID *pFunctionId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetHandleFromThread )(
+ ICorProfilerInfo * This,
+ /* [in] */ ThreadID threadId,
+ /* [out] */ HANDLE *phThread);
+
+ HRESULT ( STDMETHODCALLTYPE *GetObjectSize )(
+ ICorProfilerInfo * This,
+ /* [in] */ ObjectID objectId,
+ /* [out] */ ULONG *pcSize);
+
+ HRESULT ( STDMETHODCALLTYPE *IsArrayClass )(
+ ICorProfilerInfo * This,
+ /* [in] */ ClassID classId,
+ /* [out] */ CorElementType *pBaseElemType,
+ /* [out] */ ClassID *pBaseClassId,
+ /* [out] */ ULONG *pcRank);
+
+ HRESULT ( STDMETHODCALLTYPE *GetThreadInfo )(
+ ICorProfilerInfo * This,
+ /* [in] */ ThreadID threadId,
+ /* [out] */ DWORD *pdwWin32ThreadId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCurrentThreadID )(
+ ICorProfilerInfo * This,
+ /* [out] */ ThreadID *pThreadId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetClassIDInfo )(
+ ICorProfilerInfo * This,
+ /* [in] */ ClassID classId,
+ /* [out] */ ModuleID *pModuleId,
+ /* [out] */ mdTypeDef *pTypeDefToken);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFunctionInfo )(
+ ICorProfilerInfo * This,
+ /* [in] */ FunctionID functionId,
+ /* [out] */ ClassID *pClassId,
+ /* [out] */ ModuleID *pModuleId,
+ /* [out] */ mdToken *pToken);
+
+ HRESULT ( STDMETHODCALLTYPE *SetEventMask )(
+ ICorProfilerInfo * This,
+ /* [in] */ DWORD dwEvents);
+
+ HRESULT ( STDMETHODCALLTYPE *SetEnterLeaveFunctionHooks )(
+ ICorProfilerInfo * This,
+ /* [in] */ FunctionEnter *pFuncEnter,
+ /* [in] */ FunctionLeave *pFuncLeave,
+ /* [in] */ FunctionTailcall *pFuncTailcall);
+
+ HRESULT ( STDMETHODCALLTYPE *SetFunctionIDMapper )(
+ ICorProfilerInfo * This,
+ /* [in] */ FunctionIDMapper *pFunc);
+
+ HRESULT ( STDMETHODCALLTYPE *GetTokenAndMetaDataFromFunction )(
+ ICorProfilerInfo * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ REFIID riid,
+ /* [out] */ IUnknown **ppImport,
+ /* [out] */ mdToken *pToken);
+
+ HRESULT ( STDMETHODCALLTYPE *GetModuleInfo )(
+ ICorProfilerInfo * This,
+ /* [in] */ ModuleID moduleId,
+ /* [out] */ LPCBYTE *ppBaseLoadAddress,
+ /* [in] */ ULONG cchName,
+ /* [out] */ ULONG *pcchName,
+ /* [annotation][out] */
+ _Out_writes_to_(cchName, *pcchName) WCHAR szName[ ],
+ /* [out] */ AssemblyID *pAssemblyId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetModuleMetaData )(
+ ICorProfilerInfo * This,
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ DWORD dwOpenFlags,
+ /* [in] */ REFIID riid,
+ /* [out] */ IUnknown **ppOut);
+
+ HRESULT ( STDMETHODCALLTYPE *GetILFunctionBody )(
+ ICorProfilerInfo * This,
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ mdMethodDef methodId,
+ /* [out] */ LPCBYTE *ppMethodHeader,
+ /* [out] */ ULONG *pcbMethodSize);
+
+ HRESULT ( STDMETHODCALLTYPE *GetILFunctionBodyAllocator )(
+ ICorProfilerInfo * This,
+ /* [in] */ ModuleID moduleId,
+ /* [out] */ IMethodMalloc **ppMalloc);
+
+ HRESULT ( STDMETHODCALLTYPE *SetILFunctionBody )(
+ ICorProfilerInfo * This,
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ mdMethodDef methodid,
+ /* [in] */ LPCBYTE pbNewILMethodHeader);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAppDomainInfo )(
+ ICorProfilerInfo * This,
+ /* [in] */ AppDomainID appDomainId,
+ /* [in] */ ULONG cchName,
+ /* [out] */ ULONG *pcchName,
+ /* [annotation][out] */
+ _Out_writes_to_(cchName, *pcchName) WCHAR szName[ ],
+ /* [out] */ ProcessID *pProcessId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAssemblyInfo )(
+ ICorProfilerInfo * This,
+ /* [in] */ AssemblyID assemblyId,
+ /* [in] */ ULONG cchName,
+ /* [out] */ ULONG *pcchName,
+ /* [annotation][out] */
+ _Out_writes_to_(cchName, *pcchName) WCHAR szName[ ],
+ /* [out] */ AppDomainID *pAppDomainId,
+ /* [out] */ ModuleID *pModuleId);
+
+ HRESULT ( STDMETHODCALLTYPE *SetFunctionReJIT )(
+ ICorProfilerInfo * This,
+ /* [in] */ FunctionID functionId);
+
+ HRESULT ( STDMETHODCALLTYPE *ForceGC )(
+ ICorProfilerInfo * This);
+
+ HRESULT ( STDMETHODCALLTYPE *SetILInstrumentedCodeMap )(
+ ICorProfilerInfo * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ BOOL fStartJit,
+ /* [in] */ ULONG cILMapEntries,
+ /* [size_is][in] */ COR_IL_MAP rgILMapEntries[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetInprocInspectionInterface )(
+ ICorProfilerInfo * This,
+ /* [out] */ IUnknown **ppicd);
+
+ HRESULT ( STDMETHODCALLTYPE *GetInprocInspectionIThisThread )(
+ ICorProfilerInfo * This,
+ /* [out] */ IUnknown **ppicd);
+
+ HRESULT ( STDMETHODCALLTYPE *GetThreadContext )(
+ ICorProfilerInfo * This,
+ /* [in] */ ThreadID threadId,
+ /* [out] */ ContextID *pContextId);
+
+ HRESULT ( STDMETHODCALLTYPE *BeginInprocDebugging )(
+ ICorProfilerInfo * This,
+ /* [in] */ BOOL fThisThreadOnly,
+ /* [out] */ DWORD *pdwProfilerContext);
+
+ HRESULT ( STDMETHODCALLTYPE *EndInprocDebugging )(
+ ICorProfilerInfo * This,
+ /* [in] */ DWORD dwProfilerContext);
+
+ HRESULT ( STDMETHODCALLTYPE *GetILToNativeMapping )(
+ ICorProfilerInfo * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ ULONG32 cMap,
+ /* [out] */ ULONG32 *pcMap,
+ /* [length_is][size_is][out] */ COR_DEBUG_IL_TO_NATIVE_MAP map[ ]);
+
+ END_INTERFACE
+ } ICorProfilerInfoVtbl;
+
+ interface ICorProfilerInfo
+ {
+ CONST_VTBL struct ICorProfilerInfoVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorProfilerInfo_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorProfilerInfo_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorProfilerInfo_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorProfilerInfo_GetClassFromObject(This,objectId,pClassId) \
+ ( (This)->lpVtbl -> GetClassFromObject(This,objectId,pClassId) )
+
+#define ICorProfilerInfo_GetClassFromToken(This,moduleId,typeDef,pClassId) \
+ ( (This)->lpVtbl -> GetClassFromToken(This,moduleId,typeDef,pClassId) )
+
+#define ICorProfilerInfo_GetCodeInfo(This,functionId,pStart,pcSize) \
+ ( (This)->lpVtbl -> GetCodeInfo(This,functionId,pStart,pcSize) )
+
+#define ICorProfilerInfo_GetEventMask(This,pdwEvents) \
+ ( (This)->lpVtbl -> GetEventMask(This,pdwEvents) )
+
+#define ICorProfilerInfo_GetFunctionFromIP(This,ip,pFunctionId) \
+ ( (This)->lpVtbl -> GetFunctionFromIP(This,ip,pFunctionId) )
+
+#define ICorProfilerInfo_GetFunctionFromToken(This,moduleId,token,pFunctionId) \
+ ( (This)->lpVtbl -> GetFunctionFromToken(This,moduleId,token,pFunctionId) )
+
+#define ICorProfilerInfo_GetHandleFromThread(This,threadId,phThread) \
+ ( (This)->lpVtbl -> GetHandleFromThread(This,threadId,phThread) )
+
+#define ICorProfilerInfo_GetObjectSize(This,objectId,pcSize) \
+ ( (This)->lpVtbl -> GetObjectSize(This,objectId,pcSize) )
+
+#define ICorProfilerInfo_IsArrayClass(This,classId,pBaseElemType,pBaseClassId,pcRank) \
+ ( (This)->lpVtbl -> IsArrayClass(This,classId,pBaseElemType,pBaseClassId,pcRank) )
+
+#define ICorProfilerInfo_GetThreadInfo(This,threadId,pdwWin32ThreadId) \
+ ( (This)->lpVtbl -> GetThreadInfo(This,threadId,pdwWin32ThreadId) )
+
+#define ICorProfilerInfo_GetCurrentThreadID(This,pThreadId) \
+ ( (This)->lpVtbl -> GetCurrentThreadID(This,pThreadId) )
+
+#define ICorProfilerInfo_GetClassIDInfo(This,classId,pModuleId,pTypeDefToken) \
+ ( (This)->lpVtbl -> GetClassIDInfo(This,classId,pModuleId,pTypeDefToken) )
+
+#define ICorProfilerInfo_GetFunctionInfo(This,functionId,pClassId,pModuleId,pToken) \
+ ( (This)->lpVtbl -> GetFunctionInfo(This,functionId,pClassId,pModuleId,pToken) )
+
+#define ICorProfilerInfo_SetEventMask(This,dwEvents) \
+ ( (This)->lpVtbl -> SetEventMask(This,dwEvents) )
+
+#define ICorProfilerInfo_SetEnterLeaveFunctionHooks(This,pFuncEnter,pFuncLeave,pFuncTailcall) \
+ ( (This)->lpVtbl -> SetEnterLeaveFunctionHooks(This,pFuncEnter,pFuncLeave,pFuncTailcall) )
+
+#define ICorProfilerInfo_SetFunctionIDMapper(This,pFunc) \
+ ( (This)->lpVtbl -> SetFunctionIDMapper(This,pFunc) )
+
+#define ICorProfilerInfo_GetTokenAndMetaDataFromFunction(This,functionId,riid,ppImport,pToken) \
+ ( (This)->lpVtbl -> GetTokenAndMetaDataFromFunction(This,functionId,riid,ppImport,pToken) )
+
+#define ICorProfilerInfo_GetModuleInfo(This,moduleId,ppBaseLoadAddress,cchName,pcchName,szName,pAssemblyId) \
+ ( (This)->lpVtbl -> GetModuleInfo(This,moduleId,ppBaseLoadAddress,cchName,pcchName,szName,pAssemblyId) )
+
+#define ICorProfilerInfo_GetModuleMetaData(This,moduleId,dwOpenFlags,riid,ppOut) \
+ ( (This)->lpVtbl -> GetModuleMetaData(This,moduleId,dwOpenFlags,riid,ppOut) )
+
+#define ICorProfilerInfo_GetILFunctionBody(This,moduleId,methodId,ppMethodHeader,pcbMethodSize) \
+ ( (This)->lpVtbl -> GetILFunctionBody(This,moduleId,methodId,ppMethodHeader,pcbMethodSize) )
+
+#define ICorProfilerInfo_GetILFunctionBodyAllocator(This,moduleId,ppMalloc) \
+ ( (This)->lpVtbl -> GetILFunctionBodyAllocator(This,moduleId,ppMalloc) )
+
+#define ICorProfilerInfo_SetILFunctionBody(This,moduleId,methodid,pbNewILMethodHeader) \
+ ( (This)->lpVtbl -> SetILFunctionBody(This,moduleId,methodid,pbNewILMethodHeader) )
+
+#define ICorProfilerInfo_GetAppDomainInfo(This,appDomainId,cchName,pcchName,szName,pProcessId) \
+ ( (This)->lpVtbl -> GetAppDomainInfo(This,appDomainId,cchName,pcchName,szName,pProcessId) )
+
+#define ICorProfilerInfo_GetAssemblyInfo(This,assemblyId,cchName,pcchName,szName,pAppDomainId,pModuleId) \
+ ( (This)->lpVtbl -> GetAssemblyInfo(This,assemblyId,cchName,pcchName,szName,pAppDomainId,pModuleId) )
+
+#define ICorProfilerInfo_SetFunctionReJIT(This,functionId) \
+ ( (This)->lpVtbl -> SetFunctionReJIT(This,functionId) )
+
+#define ICorProfilerInfo_ForceGC(This) \
+ ( (This)->lpVtbl -> ForceGC(This) )
+
+#define ICorProfilerInfo_SetILInstrumentedCodeMap(This,functionId,fStartJit,cILMapEntries,rgILMapEntries) \
+ ( (This)->lpVtbl -> SetILInstrumentedCodeMap(This,functionId,fStartJit,cILMapEntries,rgILMapEntries) )
+
+#define ICorProfilerInfo_GetInprocInspectionInterface(This,ppicd) \
+ ( (This)->lpVtbl -> GetInprocInspectionInterface(This,ppicd) )
+
+#define ICorProfilerInfo_GetInprocInspectionIThisThread(This,ppicd) \
+ ( (This)->lpVtbl -> GetInprocInspectionIThisThread(This,ppicd) )
+
+#define ICorProfilerInfo_GetThreadContext(This,threadId,pContextId) \
+ ( (This)->lpVtbl -> GetThreadContext(This,threadId,pContextId) )
+
+#define ICorProfilerInfo_BeginInprocDebugging(This,fThisThreadOnly,pdwProfilerContext) \
+ ( (This)->lpVtbl -> BeginInprocDebugging(This,fThisThreadOnly,pdwProfilerContext) )
+
+#define ICorProfilerInfo_EndInprocDebugging(This,dwProfilerContext) \
+ ( (This)->lpVtbl -> EndInprocDebugging(This,dwProfilerContext) )
+
+#define ICorProfilerInfo_GetILToNativeMapping(This,functionId,cMap,pcMap,map) \
+ ( (This)->lpVtbl -> GetILToNativeMapping(This,functionId,cMap,pcMap,map) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorProfilerInfo_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorProfilerInfo2_INTERFACE_DEFINED__
+#define __ICorProfilerInfo2_INTERFACE_DEFINED__
+
+/* interface ICorProfilerInfo2 */
+/* [local][unique][uuid][object] */
+
+
+EXTERN_C const IID IID_ICorProfilerInfo2;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("CC0935CD-A518-487d-B0BB-A93214E65478")
+ ICorProfilerInfo2 : public ICorProfilerInfo
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE DoStackSnapshot(
+ /* [in] */ ThreadID thread,
+ /* [in] */ StackSnapshotCallback *callback,
+ /* [in] */ ULONG32 infoFlags,
+ /* [in] */ void *clientData,
+ /* [size_is][in] */ BYTE context[ ],
+ /* [in] */ ULONG32 contextSize) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetEnterLeaveFunctionHooks2(
+ /* [in] */ FunctionEnter2 *pFuncEnter,
+ /* [in] */ FunctionLeave2 *pFuncLeave,
+ /* [in] */ FunctionTailcall2 *pFuncTailcall) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetFunctionInfo2(
+ /* [in] */ FunctionID funcId,
+ /* [in] */ COR_PRF_FRAME_INFO frameInfo,
+ /* [out] */ ClassID *pClassId,
+ /* [out] */ ModuleID *pModuleId,
+ /* [out] */ mdToken *pToken,
+ /* [in] */ ULONG32 cTypeArgs,
+ /* [out] */ ULONG32 *pcTypeArgs,
+ /* [out] */ ClassID typeArgs[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetStringLayout(
+ /* [out] */ ULONG *pBufferLengthOffset,
+ /* [out] */ ULONG *pStringLengthOffset,
+ /* [out] */ ULONG *pBufferOffset) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetClassLayout(
+ /* [in] */ ClassID classID,
+ /* [out][in] */ COR_FIELD_OFFSET rFieldOffset[ ],
+ /* [in] */ ULONG cFieldOffset,
+ /* [out] */ ULONG *pcFieldOffset,
+ /* [out] */ ULONG *pulClassSize) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetClassIDInfo2(
+ /* [in] */ ClassID classId,
+ /* [out] */ ModuleID *pModuleId,
+ /* [out] */ mdTypeDef *pTypeDefToken,
+ /* [out] */ ClassID *pParentClassId,
+ /* [in] */ ULONG32 cNumTypeArgs,
+ /* [out] */ ULONG32 *pcNumTypeArgs,
+ /* [out] */ ClassID typeArgs[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetCodeInfo2(
+ /* [in] */ FunctionID functionID,
+ /* [in] */ ULONG32 cCodeInfos,
+ /* [out] */ ULONG32 *pcCodeInfos,
+ /* [length_is][size_is][out] */ COR_PRF_CODE_INFO codeInfos[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetClassFromTokenAndTypeArgs(
+ /* [in] */ ModuleID moduleID,
+ /* [in] */ mdTypeDef typeDef,
+ /* [in] */ ULONG32 cTypeArgs,
+ /* [size_is][in] */ ClassID typeArgs[ ],
+ /* [out] */ ClassID *pClassID) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetFunctionFromTokenAndTypeArgs(
+ /* [in] */ ModuleID moduleID,
+ /* [in] */ mdMethodDef funcDef,
+ /* [in] */ ClassID classId,
+ /* [in] */ ULONG32 cTypeArgs,
+ /* [size_is][in] */ ClassID typeArgs[ ],
+ /* [out] */ FunctionID *pFunctionID) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnumModuleFrozenObjects(
+ /* [in] */ ModuleID moduleID,
+ /* [out] */ ICorProfilerObjectEnum **ppEnum) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetArrayObjectInfo(
+ /* [in] */ ObjectID objectId,
+ /* [in] */ ULONG32 cDimensions,
+ /* [size_is][out] */ ULONG32 pDimensionSizes[ ],
+ /* [size_is][out] */ int pDimensionLowerBounds[ ],
+ /* [out] */ BYTE **ppData) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetBoxClassLayout(
+ /* [in] */ ClassID classId,
+ /* [out] */ ULONG32 *pBufferOffset) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetThreadAppDomain(
+ /* [in] */ ThreadID threadId,
+ /* [out] */ AppDomainID *pAppDomainId) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetRVAStaticAddress(
+ /* [in] */ ClassID classId,
+ /* [in] */ mdFieldDef fieldToken,
+ /* [out] */ void **ppAddress) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetAppDomainStaticAddress(
+ /* [in] */ ClassID classId,
+ /* [in] */ mdFieldDef fieldToken,
+ /* [in] */ AppDomainID appDomainId,
+ /* [out] */ void **ppAddress) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetThreadStaticAddress(
+ /* [in] */ ClassID classId,
+ /* [in] */ mdFieldDef fieldToken,
+ /* [in] */ ThreadID threadId,
+ /* [out] */ void **ppAddress) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetContextStaticAddress(
+ /* [in] */ ClassID classId,
+ /* [in] */ mdFieldDef fieldToken,
+ /* [in] */ ContextID contextId,
+ /* [out] */ void **ppAddress) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetStaticFieldInfo(
+ /* [in] */ ClassID classId,
+ /* [in] */ mdFieldDef fieldToken,
+ /* [out] */ COR_PRF_STATIC_TYPE *pFieldInfo) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetGenerationBounds(
+ /* [in] */ ULONG cObjectRanges,
+ /* [out] */ ULONG *pcObjectRanges,
+ /* [length_is][size_is][out] */ COR_PRF_GC_GENERATION_RANGE ranges[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetObjectGeneration(
+ /* [in] */ ObjectID objectId,
+ /* [out] */ COR_PRF_GC_GENERATION_RANGE *range) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetNotifiedExceptionClauseInfo(
+ /* [out] */ COR_PRF_EX_CLAUSE_INFO *pinfo) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorProfilerInfo2Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorProfilerInfo2 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorProfilerInfo2 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorProfilerInfo2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetClassFromObject )(
+ ICorProfilerInfo2 * This,
+ /* [in] */ ObjectID objectId,
+ /* [out] */ ClassID *pClassId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetClassFromToken )(
+ ICorProfilerInfo2 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ mdTypeDef typeDef,
+ /* [out] */ ClassID *pClassId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCodeInfo )(
+ ICorProfilerInfo2 * This,
+ /* [in] */ FunctionID functionId,
+ /* [out] */ LPCBYTE *pStart,
+ /* [out] */ ULONG *pcSize);
+
+ HRESULT ( STDMETHODCALLTYPE *GetEventMask )(
+ ICorProfilerInfo2 * This,
+ /* [out] */ DWORD *pdwEvents);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFunctionFromIP )(
+ ICorProfilerInfo2 * This,
+ /* [in] */ LPCBYTE ip,
+ /* [out] */ FunctionID *pFunctionId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFunctionFromToken )(
+ ICorProfilerInfo2 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ mdToken token,
+ /* [out] */ FunctionID *pFunctionId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetHandleFromThread )(
+ ICorProfilerInfo2 * This,
+ /* [in] */ ThreadID threadId,
+ /* [out] */ HANDLE *phThread);
+
+ HRESULT ( STDMETHODCALLTYPE *GetObjectSize )(
+ ICorProfilerInfo2 * This,
+ /* [in] */ ObjectID objectId,
+ /* [out] */ ULONG *pcSize);
+
+ HRESULT ( STDMETHODCALLTYPE *IsArrayClass )(
+ ICorProfilerInfo2 * This,
+ /* [in] */ ClassID classId,
+ /* [out] */ CorElementType *pBaseElemType,
+ /* [out] */ ClassID *pBaseClassId,
+ /* [out] */ ULONG *pcRank);
+
+ HRESULT ( STDMETHODCALLTYPE *GetThreadInfo )(
+ ICorProfilerInfo2 * This,
+ /* [in] */ ThreadID threadId,
+ /* [out] */ DWORD *pdwWin32ThreadId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCurrentThreadID )(
+ ICorProfilerInfo2 * This,
+ /* [out] */ ThreadID *pThreadId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetClassIDInfo )(
+ ICorProfilerInfo2 * This,
+ /* [in] */ ClassID classId,
+ /* [out] */ ModuleID *pModuleId,
+ /* [out] */ mdTypeDef *pTypeDefToken);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFunctionInfo )(
+ ICorProfilerInfo2 * This,
+ /* [in] */ FunctionID functionId,
+ /* [out] */ ClassID *pClassId,
+ /* [out] */ ModuleID *pModuleId,
+ /* [out] */ mdToken *pToken);
+
+ HRESULT ( STDMETHODCALLTYPE *SetEventMask )(
+ ICorProfilerInfo2 * This,
+ /* [in] */ DWORD dwEvents);
+
+ HRESULT ( STDMETHODCALLTYPE *SetEnterLeaveFunctionHooks )(
+ ICorProfilerInfo2 * This,
+ /* [in] */ FunctionEnter *pFuncEnter,
+ /* [in] */ FunctionLeave *pFuncLeave,
+ /* [in] */ FunctionTailcall *pFuncTailcall);
+
+ HRESULT ( STDMETHODCALLTYPE *SetFunctionIDMapper )(
+ ICorProfilerInfo2 * This,
+ /* [in] */ FunctionIDMapper *pFunc);
+
+ HRESULT ( STDMETHODCALLTYPE *GetTokenAndMetaDataFromFunction )(
+ ICorProfilerInfo2 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ REFIID riid,
+ /* [out] */ IUnknown **ppImport,
+ /* [out] */ mdToken *pToken);
+
+ HRESULT ( STDMETHODCALLTYPE *GetModuleInfo )(
+ ICorProfilerInfo2 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [out] */ LPCBYTE *ppBaseLoadAddress,
+ /* [in] */ ULONG cchName,
+ /* [out] */ ULONG *pcchName,
+ /* [annotation][out] */
+ _Out_writes_to_(cchName, *pcchName) WCHAR szName[ ],
+ /* [out] */ AssemblyID *pAssemblyId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetModuleMetaData )(
+ ICorProfilerInfo2 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ DWORD dwOpenFlags,
+ /* [in] */ REFIID riid,
+ /* [out] */ IUnknown **ppOut);
+
+ HRESULT ( STDMETHODCALLTYPE *GetILFunctionBody )(
+ ICorProfilerInfo2 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ mdMethodDef methodId,
+ /* [out] */ LPCBYTE *ppMethodHeader,
+ /* [out] */ ULONG *pcbMethodSize);
+
+ HRESULT ( STDMETHODCALLTYPE *GetILFunctionBodyAllocator )(
+ ICorProfilerInfo2 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [out] */ IMethodMalloc **ppMalloc);
+
+ HRESULT ( STDMETHODCALLTYPE *SetILFunctionBody )(
+ ICorProfilerInfo2 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ mdMethodDef methodid,
+ /* [in] */ LPCBYTE pbNewILMethodHeader);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAppDomainInfo )(
+ ICorProfilerInfo2 * This,
+ /* [in] */ AppDomainID appDomainId,
+ /* [in] */ ULONG cchName,
+ /* [out] */ ULONG *pcchName,
+ /* [annotation][out] */
+ _Out_writes_to_(cchName, *pcchName) WCHAR szName[ ],
+ /* [out] */ ProcessID *pProcessId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAssemblyInfo )(
+ ICorProfilerInfo2 * This,
+ /* [in] */ AssemblyID assemblyId,
+ /* [in] */ ULONG cchName,
+ /* [out] */ ULONG *pcchName,
+ /* [annotation][out] */
+ _Out_writes_to_(cchName, *pcchName) WCHAR szName[ ],
+ /* [out] */ AppDomainID *pAppDomainId,
+ /* [out] */ ModuleID *pModuleId);
+
+ HRESULT ( STDMETHODCALLTYPE *SetFunctionReJIT )(
+ ICorProfilerInfo2 * This,
+ /* [in] */ FunctionID functionId);
+
+ HRESULT ( STDMETHODCALLTYPE *ForceGC )(
+ ICorProfilerInfo2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *SetILInstrumentedCodeMap )(
+ ICorProfilerInfo2 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ BOOL fStartJit,
+ /* [in] */ ULONG cILMapEntries,
+ /* [size_is][in] */ COR_IL_MAP rgILMapEntries[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetInprocInspectionInterface )(
+ ICorProfilerInfo2 * This,
+ /* [out] */ IUnknown **ppicd);
+
+ HRESULT ( STDMETHODCALLTYPE *GetInprocInspectionIThisThread )(
+ ICorProfilerInfo2 * This,
+ /* [out] */ IUnknown **ppicd);
+
+ HRESULT ( STDMETHODCALLTYPE *GetThreadContext )(
+ ICorProfilerInfo2 * This,
+ /* [in] */ ThreadID threadId,
+ /* [out] */ ContextID *pContextId);
+
+ HRESULT ( STDMETHODCALLTYPE *BeginInprocDebugging )(
+ ICorProfilerInfo2 * This,
+ /* [in] */ BOOL fThisThreadOnly,
+ /* [out] */ DWORD *pdwProfilerContext);
+
+ HRESULT ( STDMETHODCALLTYPE *EndInprocDebugging )(
+ ICorProfilerInfo2 * This,
+ /* [in] */ DWORD dwProfilerContext);
+
+ HRESULT ( STDMETHODCALLTYPE *GetILToNativeMapping )(
+ ICorProfilerInfo2 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ ULONG32 cMap,
+ /* [out] */ ULONG32 *pcMap,
+ /* [length_is][size_is][out] */ COR_DEBUG_IL_TO_NATIVE_MAP map[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *DoStackSnapshot )(
+ ICorProfilerInfo2 * This,
+ /* [in] */ ThreadID thread,
+ /* [in] */ StackSnapshotCallback *callback,
+ /* [in] */ ULONG32 infoFlags,
+ /* [in] */ void *clientData,
+ /* [size_is][in] */ BYTE context[ ],
+ /* [in] */ ULONG32 contextSize);
+
+ HRESULT ( STDMETHODCALLTYPE *SetEnterLeaveFunctionHooks2 )(
+ ICorProfilerInfo2 * This,
+ /* [in] */ FunctionEnter2 *pFuncEnter,
+ /* [in] */ FunctionLeave2 *pFuncLeave,
+ /* [in] */ FunctionTailcall2 *pFuncTailcall);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFunctionInfo2 )(
+ ICorProfilerInfo2 * This,
+ /* [in] */ FunctionID funcId,
+ /* [in] */ COR_PRF_FRAME_INFO frameInfo,
+ /* [out] */ ClassID *pClassId,
+ /* [out] */ ModuleID *pModuleId,
+ /* [out] */ mdToken *pToken,
+ /* [in] */ ULONG32 cTypeArgs,
+ /* [out] */ ULONG32 *pcTypeArgs,
+ /* [out] */ ClassID typeArgs[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetStringLayout )(
+ ICorProfilerInfo2 * This,
+ /* [out] */ ULONG *pBufferLengthOffset,
+ /* [out] */ ULONG *pStringLengthOffset,
+ /* [out] */ ULONG *pBufferOffset);
+
+ HRESULT ( STDMETHODCALLTYPE *GetClassLayout )(
+ ICorProfilerInfo2 * This,
+ /* [in] */ ClassID classID,
+ /* [out][in] */ COR_FIELD_OFFSET rFieldOffset[ ],
+ /* [in] */ ULONG cFieldOffset,
+ /* [out] */ ULONG *pcFieldOffset,
+ /* [out] */ ULONG *pulClassSize);
+
+ HRESULT ( STDMETHODCALLTYPE *GetClassIDInfo2 )(
+ ICorProfilerInfo2 * This,
+ /* [in] */ ClassID classId,
+ /* [out] */ ModuleID *pModuleId,
+ /* [out] */ mdTypeDef *pTypeDefToken,
+ /* [out] */ ClassID *pParentClassId,
+ /* [in] */ ULONG32 cNumTypeArgs,
+ /* [out] */ ULONG32 *pcNumTypeArgs,
+ /* [out] */ ClassID typeArgs[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCodeInfo2 )(
+ ICorProfilerInfo2 * This,
+ /* [in] */ FunctionID functionID,
+ /* [in] */ ULONG32 cCodeInfos,
+ /* [out] */ ULONG32 *pcCodeInfos,
+ /* [length_is][size_is][out] */ COR_PRF_CODE_INFO codeInfos[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetClassFromTokenAndTypeArgs )(
+ ICorProfilerInfo2 * This,
+ /* [in] */ ModuleID moduleID,
+ /* [in] */ mdTypeDef typeDef,
+ /* [in] */ ULONG32 cTypeArgs,
+ /* [size_is][in] */ ClassID typeArgs[ ],
+ /* [out] */ ClassID *pClassID);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFunctionFromTokenAndTypeArgs )(
+ ICorProfilerInfo2 * This,
+ /* [in] */ ModuleID moduleID,
+ /* [in] */ mdMethodDef funcDef,
+ /* [in] */ ClassID classId,
+ /* [in] */ ULONG32 cTypeArgs,
+ /* [size_is][in] */ ClassID typeArgs[ ],
+ /* [out] */ FunctionID *pFunctionID);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumModuleFrozenObjects )(
+ ICorProfilerInfo2 * This,
+ /* [in] */ ModuleID moduleID,
+ /* [out] */ ICorProfilerObjectEnum **ppEnum);
+
+ HRESULT ( STDMETHODCALLTYPE *GetArrayObjectInfo )(
+ ICorProfilerInfo2 * This,
+ /* [in] */ ObjectID objectId,
+ /* [in] */ ULONG32 cDimensions,
+ /* [size_is][out] */ ULONG32 pDimensionSizes[ ],
+ /* [size_is][out] */ int pDimensionLowerBounds[ ],
+ /* [out] */ BYTE **ppData);
+
+ HRESULT ( STDMETHODCALLTYPE *GetBoxClassLayout )(
+ ICorProfilerInfo2 * This,
+ /* [in] */ ClassID classId,
+ /* [out] */ ULONG32 *pBufferOffset);
+
+ HRESULT ( STDMETHODCALLTYPE *GetThreadAppDomain )(
+ ICorProfilerInfo2 * This,
+ /* [in] */ ThreadID threadId,
+ /* [out] */ AppDomainID *pAppDomainId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetRVAStaticAddress )(
+ ICorProfilerInfo2 * This,
+ /* [in] */ ClassID classId,
+ /* [in] */ mdFieldDef fieldToken,
+ /* [out] */ void **ppAddress);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAppDomainStaticAddress )(
+ ICorProfilerInfo2 * This,
+ /* [in] */ ClassID classId,
+ /* [in] */ mdFieldDef fieldToken,
+ /* [in] */ AppDomainID appDomainId,
+ /* [out] */ void **ppAddress);
+
+ HRESULT ( STDMETHODCALLTYPE *GetThreadStaticAddress )(
+ ICorProfilerInfo2 * This,
+ /* [in] */ ClassID classId,
+ /* [in] */ mdFieldDef fieldToken,
+ /* [in] */ ThreadID threadId,
+ /* [out] */ void **ppAddress);
+
+ HRESULT ( STDMETHODCALLTYPE *GetContextStaticAddress )(
+ ICorProfilerInfo2 * This,
+ /* [in] */ ClassID classId,
+ /* [in] */ mdFieldDef fieldToken,
+ /* [in] */ ContextID contextId,
+ /* [out] */ void **ppAddress);
+
+ HRESULT ( STDMETHODCALLTYPE *GetStaticFieldInfo )(
+ ICorProfilerInfo2 * This,
+ /* [in] */ ClassID classId,
+ /* [in] */ mdFieldDef fieldToken,
+ /* [out] */ COR_PRF_STATIC_TYPE *pFieldInfo);
+
+ HRESULT ( STDMETHODCALLTYPE *GetGenerationBounds )(
+ ICorProfilerInfo2 * This,
+ /* [in] */ ULONG cObjectRanges,
+ /* [out] */ ULONG *pcObjectRanges,
+ /* [length_is][size_is][out] */ COR_PRF_GC_GENERATION_RANGE ranges[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetObjectGeneration )(
+ ICorProfilerInfo2 * This,
+ /* [in] */ ObjectID objectId,
+ /* [out] */ COR_PRF_GC_GENERATION_RANGE *range);
+
+ HRESULT ( STDMETHODCALLTYPE *GetNotifiedExceptionClauseInfo )(
+ ICorProfilerInfo2 * This,
+ /* [out] */ COR_PRF_EX_CLAUSE_INFO *pinfo);
+
+ END_INTERFACE
+ } ICorProfilerInfo2Vtbl;
+
+ interface ICorProfilerInfo2
+ {
+ CONST_VTBL struct ICorProfilerInfo2Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorProfilerInfo2_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorProfilerInfo2_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorProfilerInfo2_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorProfilerInfo2_GetClassFromObject(This,objectId,pClassId) \
+ ( (This)->lpVtbl -> GetClassFromObject(This,objectId,pClassId) )
+
+#define ICorProfilerInfo2_GetClassFromToken(This,moduleId,typeDef,pClassId) \
+ ( (This)->lpVtbl -> GetClassFromToken(This,moduleId,typeDef,pClassId) )
+
+#define ICorProfilerInfo2_GetCodeInfo(This,functionId,pStart,pcSize) \
+ ( (This)->lpVtbl -> GetCodeInfo(This,functionId,pStart,pcSize) )
+
+#define ICorProfilerInfo2_GetEventMask(This,pdwEvents) \
+ ( (This)->lpVtbl -> GetEventMask(This,pdwEvents) )
+
+#define ICorProfilerInfo2_GetFunctionFromIP(This,ip,pFunctionId) \
+ ( (This)->lpVtbl -> GetFunctionFromIP(This,ip,pFunctionId) )
+
+#define ICorProfilerInfo2_GetFunctionFromToken(This,moduleId,token,pFunctionId) \
+ ( (This)->lpVtbl -> GetFunctionFromToken(This,moduleId,token,pFunctionId) )
+
+#define ICorProfilerInfo2_GetHandleFromThread(This,threadId,phThread) \
+ ( (This)->lpVtbl -> GetHandleFromThread(This,threadId,phThread) )
+
+#define ICorProfilerInfo2_GetObjectSize(This,objectId,pcSize) \
+ ( (This)->lpVtbl -> GetObjectSize(This,objectId,pcSize) )
+
+#define ICorProfilerInfo2_IsArrayClass(This,classId,pBaseElemType,pBaseClassId,pcRank) \
+ ( (This)->lpVtbl -> IsArrayClass(This,classId,pBaseElemType,pBaseClassId,pcRank) )
+
+#define ICorProfilerInfo2_GetThreadInfo(This,threadId,pdwWin32ThreadId) \
+ ( (This)->lpVtbl -> GetThreadInfo(This,threadId,pdwWin32ThreadId) )
+
+#define ICorProfilerInfo2_GetCurrentThreadID(This,pThreadId) \
+ ( (This)->lpVtbl -> GetCurrentThreadID(This,pThreadId) )
+
+#define ICorProfilerInfo2_GetClassIDInfo(This,classId,pModuleId,pTypeDefToken) \
+ ( (This)->lpVtbl -> GetClassIDInfo(This,classId,pModuleId,pTypeDefToken) )
+
+#define ICorProfilerInfo2_GetFunctionInfo(This,functionId,pClassId,pModuleId,pToken) \
+ ( (This)->lpVtbl -> GetFunctionInfo(This,functionId,pClassId,pModuleId,pToken) )
+
+#define ICorProfilerInfo2_SetEventMask(This,dwEvents) \
+ ( (This)->lpVtbl -> SetEventMask(This,dwEvents) )
+
+#define ICorProfilerInfo2_SetEnterLeaveFunctionHooks(This,pFuncEnter,pFuncLeave,pFuncTailcall) \
+ ( (This)->lpVtbl -> SetEnterLeaveFunctionHooks(This,pFuncEnter,pFuncLeave,pFuncTailcall) )
+
+#define ICorProfilerInfo2_SetFunctionIDMapper(This,pFunc) \
+ ( (This)->lpVtbl -> SetFunctionIDMapper(This,pFunc) )
+
+#define ICorProfilerInfo2_GetTokenAndMetaDataFromFunction(This,functionId,riid,ppImport,pToken) \
+ ( (This)->lpVtbl -> GetTokenAndMetaDataFromFunction(This,functionId,riid,ppImport,pToken) )
+
+#define ICorProfilerInfo2_GetModuleInfo(This,moduleId,ppBaseLoadAddress,cchName,pcchName,szName,pAssemblyId) \
+ ( (This)->lpVtbl -> GetModuleInfo(This,moduleId,ppBaseLoadAddress,cchName,pcchName,szName,pAssemblyId) )
+
+#define ICorProfilerInfo2_GetModuleMetaData(This,moduleId,dwOpenFlags,riid,ppOut) \
+ ( (This)->lpVtbl -> GetModuleMetaData(This,moduleId,dwOpenFlags,riid,ppOut) )
+
+#define ICorProfilerInfo2_GetILFunctionBody(This,moduleId,methodId,ppMethodHeader,pcbMethodSize) \
+ ( (This)->lpVtbl -> GetILFunctionBody(This,moduleId,methodId,ppMethodHeader,pcbMethodSize) )
+
+#define ICorProfilerInfo2_GetILFunctionBodyAllocator(This,moduleId,ppMalloc) \
+ ( (This)->lpVtbl -> GetILFunctionBodyAllocator(This,moduleId,ppMalloc) )
+
+#define ICorProfilerInfo2_SetILFunctionBody(This,moduleId,methodid,pbNewILMethodHeader) \
+ ( (This)->lpVtbl -> SetILFunctionBody(This,moduleId,methodid,pbNewILMethodHeader) )
+
+#define ICorProfilerInfo2_GetAppDomainInfo(This,appDomainId,cchName,pcchName,szName,pProcessId) \
+ ( (This)->lpVtbl -> GetAppDomainInfo(This,appDomainId,cchName,pcchName,szName,pProcessId) )
+
+#define ICorProfilerInfo2_GetAssemblyInfo(This,assemblyId,cchName,pcchName,szName,pAppDomainId,pModuleId) \
+ ( (This)->lpVtbl -> GetAssemblyInfo(This,assemblyId,cchName,pcchName,szName,pAppDomainId,pModuleId) )
+
+#define ICorProfilerInfo2_SetFunctionReJIT(This,functionId) \
+ ( (This)->lpVtbl -> SetFunctionReJIT(This,functionId) )
+
+#define ICorProfilerInfo2_ForceGC(This) \
+ ( (This)->lpVtbl -> ForceGC(This) )
+
+#define ICorProfilerInfo2_SetILInstrumentedCodeMap(This,functionId,fStartJit,cILMapEntries,rgILMapEntries) \
+ ( (This)->lpVtbl -> SetILInstrumentedCodeMap(This,functionId,fStartJit,cILMapEntries,rgILMapEntries) )
+
+#define ICorProfilerInfo2_GetInprocInspectionInterface(This,ppicd) \
+ ( (This)->lpVtbl -> GetInprocInspectionInterface(This,ppicd) )
+
+#define ICorProfilerInfo2_GetInprocInspectionIThisThread(This,ppicd) \
+ ( (This)->lpVtbl -> GetInprocInspectionIThisThread(This,ppicd) )
+
+#define ICorProfilerInfo2_GetThreadContext(This,threadId,pContextId) \
+ ( (This)->lpVtbl -> GetThreadContext(This,threadId,pContextId) )
+
+#define ICorProfilerInfo2_BeginInprocDebugging(This,fThisThreadOnly,pdwProfilerContext) \
+ ( (This)->lpVtbl -> BeginInprocDebugging(This,fThisThreadOnly,pdwProfilerContext) )
+
+#define ICorProfilerInfo2_EndInprocDebugging(This,dwProfilerContext) \
+ ( (This)->lpVtbl -> EndInprocDebugging(This,dwProfilerContext) )
+
+#define ICorProfilerInfo2_GetILToNativeMapping(This,functionId,cMap,pcMap,map) \
+ ( (This)->lpVtbl -> GetILToNativeMapping(This,functionId,cMap,pcMap,map) )
+
+
+#define ICorProfilerInfo2_DoStackSnapshot(This,thread,callback,infoFlags,clientData,context,contextSize) \
+ ( (This)->lpVtbl -> DoStackSnapshot(This,thread,callback,infoFlags,clientData,context,contextSize) )
+
+#define ICorProfilerInfo2_SetEnterLeaveFunctionHooks2(This,pFuncEnter,pFuncLeave,pFuncTailcall) \
+ ( (This)->lpVtbl -> SetEnterLeaveFunctionHooks2(This,pFuncEnter,pFuncLeave,pFuncTailcall) )
+
+#define ICorProfilerInfo2_GetFunctionInfo2(This,funcId,frameInfo,pClassId,pModuleId,pToken,cTypeArgs,pcTypeArgs,typeArgs) \
+ ( (This)->lpVtbl -> GetFunctionInfo2(This,funcId,frameInfo,pClassId,pModuleId,pToken,cTypeArgs,pcTypeArgs,typeArgs) )
+
+#define ICorProfilerInfo2_GetStringLayout(This,pBufferLengthOffset,pStringLengthOffset,pBufferOffset) \
+ ( (This)->lpVtbl -> GetStringLayout(This,pBufferLengthOffset,pStringLengthOffset,pBufferOffset) )
+
+#define ICorProfilerInfo2_GetClassLayout(This,classID,rFieldOffset,cFieldOffset,pcFieldOffset,pulClassSize) \
+ ( (This)->lpVtbl -> GetClassLayout(This,classID,rFieldOffset,cFieldOffset,pcFieldOffset,pulClassSize) )
+
+#define ICorProfilerInfo2_GetClassIDInfo2(This,classId,pModuleId,pTypeDefToken,pParentClassId,cNumTypeArgs,pcNumTypeArgs,typeArgs) \
+ ( (This)->lpVtbl -> GetClassIDInfo2(This,classId,pModuleId,pTypeDefToken,pParentClassId,cNumTypeArgs,pcNumTypeArgs,typeArgs) )
+
+#define ICorProfilerInfo2_GetCodeInfo2(This,functionID,cCodeInfos,pcCodeInfos,codeInfos) \
+ ( (This)->lpVtbl -> GetCodeInfo2(This,functionID,cCodeInfos,pcCodeInfos,codeInfos) )
+
+#define ICorProfilerInfo2_GetClassFromTokenAndTypeArgs(This,moduleID,typeDef,cTypeArgs,typeArgs,pClassID) \
+ ( (This)->lpVtbl -> GetClassFromTokenAndTypeArgs(This,moduleID,typeDef,cTypeArgs,typeArgs,pClassID) )
+
+#define ICorProfilerInfo2_GetFunctionFromTokenAndTypeArgs(This,moduleID,funcDef,classId,cTypeArgs,typeArgs,pFunctionID) \
+ ( (This)->lpVtbl -> GetFunctionFromTokenAndTypeArgs(This,moduleID,funcDef,classId,cTypeArgs,typeArgs,pFunctionID) )
+
+#define ICorProfilerInfo2_EnumModuleFrozenObjects(This,moduleID,ppEnum) \
+ ( (This)->lpVtbl -> EnumModuleFrozenObjects(This,moduleID,ppEnum) )
+
+#define ICorProfilerInfo2_GetArrayObjectInfo(This,objectId,cDimensions,pDimensionSizes,pDimensionLowerBounds,ppData) \
+ ( (This)->lpVtbl -> GetArrayObjectInfo(This,objectId,cDimensions,pDimensionSizes,pDimensionLowerBounds,ppData) )
+
+#define ICorProfilerInfo2_GetBoxClassLayout(This,classId,pBufferOffset) \
+ ( (This)->lpVtbl -> GetBoxClassLayout(This,classId,pBufferOffset) )
+
+#define ICorProfilerInfo2_GetThreadAppDomain(This,threadId,pAppDomainId) \
+ ( (This)->lpVtbl -> GetThreadAppDomain(This,threadId,pAppDomainId) )
+
+#define ICorProfilerInfo2_GetRVAStaticAddress(This,classId,fieldToken,ppAddress) \
+ ( (This)->lpVtbl -> GetRVAStaticAddress(This,classId,fieldToken,ppAddress) )
+
+#define ICorProfilerInfo2_GetAppDomainStaticAddress(This,classId,fieldToken,appDomainId,ppAddress) \
+ ( (This)->lpVtbl -> GetAppDomainStaticAddress(This,classId,fieldToken,appDomainId,ppAddress) )
+
+#define ICorProfilerInfo2_GetThreadStaticAddress(This,classId,fieldToken,threadId,ppAddress) \
+ ( (This)->lpVtbl -> GetThreadStaticAddress(This,classId,fieldToken,threadId,ppAddress) )
+
+#define ICorProfilerInfo2_GetContextStaticAddress(This,classId,fieldToken,contextId,ppAddress) \
+ ( (This)->lpVtbl -> GetContextStaticAddress(This,classId,fieldToken,contextId,ppAddress) )
+
+#define ICorProfilerInfo2_GetStaticFieldInfo(This,classId,fieldToken,pFieldInfo) \
+ ( (This)->lpVtbl -> GetStaticFieldInfo(This,classId,fieldToken,pFieldInfo) )
+
+#define ICorProfilerInfo2_GetGenerationBounds(This,cObjectRanges,pcObjectRanges,ranges) \
+ ( (This)->lpVtbl -> GetGenerationBounds(This,cObjectRanges,pcObjectRanges,ranges) )
+
+#define ICorProfilerInfo2_GetObjectGeneration(This,objectId,range) \
+ ( (This)->lpVtbl -> GetObjectGeneration(This,objectId,range) )
+
+#define ICorProfilerInfo2_GetNotifiedExceptionClauseInfo(This,pinfo) \
+ ( (This)->lpVtbl -> GetNotifiedExceptionClauseInfo(This,pinfo) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorProfilerInfo2_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorProfilerInfo3_INTERFACE_DEFINED__
+#define __ICorProfilerInfo3_INTERFACE_DEFINED__
+
+/* interface ICorProfilerInfo3 */
+/* [local][unique][uuid][object] */
+
+
+EXTERN_C const IID IID_ICorProfilerInfo3;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("B555ED4F-452A-4E54-8B39-B5360BAD32A0")
+ ICorProfilerInfo3 : public ICorProfilerInfo2
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE EnumJITedFunctions(
+ /* [out] */ ICorProfilerFunctionEnum **ppEnum) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE RequestProfilerDetach(
+ /* [in] */ DWORD dwExpectedCompletionMilliseconds) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetFunctionIDMapper2(
+ /* [in] */ FunctionIDMapper2 *pFunc,
+ /* [in] */ void *clientData) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetStringLayout2(
+ /* [out] */ ULONG *pStringLengthOffset,
+ /* [out] */ ULONG *pBufferOffset) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetEnterLeaveFunctionHooks3(
+ /* [in] */ FunctionEnter3 *pFuncEnter3,
+ /* [in] */ FunctionLeave3 *pFuncLeave3,
+ /* [in] */ FunctionTailcall3 *pFuncTailcall3) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetEnterLeaveFunctionHooks3WithInfo(
+ /* [in] */ FunctionEnter3WithInfo *pFuncEnter3WithInfo,
+ /* [in] */ FunctionLeave3WithInfo *pFuncLeave3WithInfo,
+ /* [in] */ FunctionTailcall3WithInfo *pFuncTailcall3WithInfo) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetFunctionEnter3Info(
+ /* [in] */ FunctionID functionId,
+ /* [in] */ COR_PRF_ELT_INFO eltInfo,
+ /* [out] */ COR_PRF_FRAME_INFO *pFrameInfo,
+ /* [out][in] */ ULONG *pcbArgumentInfo,
+ /* [size_is][out] */ COR_PRF_FUNCTION_ARGUMENT_INFO *pArgumentInfo) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetFunctionLeave3Info(
+ /* [in] */ FunctionID functionId,
+ /* [in] */ COR_PRF_ELT_INFO eltInfo,
+ /* [out] */ COR_PRF_FRAME_INFO *pFrameInfo,
+ /* [out] */ COR_PRF_FUNCTION_ARGUMENT_RANGE *pRetvalRange) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetFunctionTailcall3Info(
+ /* [in] */ FunctionID functionId,
+ /* [in] */ COR_PRF_ELT_INFO eltInfo,
+ /* [out] */ COR_PRF_FRAME_INFO *pFrameInfo) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnumModules(
+ /* [out] */ ICorProfilerModuleEnum **ppEnum) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetRuntimeInformation(
+ /* [out] */ USHORT *pClrInstanceId,
+ /* [out] */ COR_PRF_RUNTIME_TYPE *pRuntimeType,
+ /* [out] */ USHORT *pMajorVersion,
+ /* [out] */ USHORT *pMinorVersion,
+ /* [out] */ USHORT *pBuildNumber,
+ /* [out] */ USHORT *pQFEVersion,
+ /* [in] */ ULONG cchVersionString,
+ /* [out] */ ULONG *pcchVersionString,
+ /* [annotation][out] */
+ _Out_writes_to_(cchVersionString, *pcchVersionString) WCHAR szVersionString[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetThreadStaticAddress2(
+ /* [in] */ ClassID classId,
+ /* [in] */ mdFieldDef fieldToken,
+ /* [in] */ AppDomainID appDomainId,
+ /* [in] */ ThreadID threadId,
+ /* [out] */ void **ppAddress) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetAppDomainsContainingModule(
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ ULONG32 cAppDomainIds,
+ /* [out] */ ULONG32 *pcAppDomainIds,
+ /* [length_is][size_is][out] */ AppDomainID appDomainIds[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetModuleInfo2(
+ /* [in] */ ModuleID moduleId,
+ /* [out] */ LPCBYTE *ppBaseLoadAddress,
+ /* [in] */ ULONG cchName,
+ /* [out] */ ULONG *pcchName,
+ /* [annotation][out] */
+ _Out_writes_to_(cchName, *pcchName) WCHAR szName[ ],
+ /* [out] */ AssemblyID *pAssemblyId,
+ /* [out] */ DWORD *pdwModuleFlags) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorProfilerInfo3Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorProfilerInfo3 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorProfilerInfo3 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorProfilerInfo3 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetClassFromObject )(
+ ICorProfilerInfo3 * This,
+ /* [in] */ ObjectID objectId,
+ /* [out] */ ClassID *pClassId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetClassFromToken )(
+ ICorProfilerInfo3 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ mdTypeDef typeDef,
+ /* [out] */ ClassID *pClassId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCodeInfo )(
+ ICorProfilerInfo3 * This,
+ /* [in] */ FunctionID functionId,
+ /* [out] */ LPCBYTE *pStart,
+ /* [out] */ ULONG *pcSize);
+
+ HRESULT ( STDMETHODCALLTYPE *GetEventMask )(
+ ICorProfilerInfo3 * This,
+ /* [out] */ DWORD *pdwEvents);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFunctionFromIP )(
+ ICorProfilerInfo3 * This,
+ /* [in] */ LPCBYTE ip,
+ /* [out] */ FunctionID *pFunctionId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFunctionFromToken )(
+ ICorProfilerInfo3 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ mdToken token,
+ /* [out] */ FunctionID *pFunctionId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetHandleFromThread )(
+ ICorProfilerInfo3 * This,
+ /* [in] */ ThreadID threadId,
+ /* [out] */ HANDLE *phThread);
+
+ HRESULT ( STDMETHODCALLTYPE *GetObjectSize )(
+ ICorProfilerInfo3 * This,
+ /* [in] */ ObjectID objectId,
+ /* [out] */ ULONG *pcSize);
+
+ HRESULT ( STDMETHODCALLTYPE *IsArrayClass )(
+ ICorProfilerInfo3 * This,
+ /* [in] */ ClassID classId,
+ /* [out] */ CorElementType *pBaseElemType,
+ /* [out] */ ClassID *pBaseClassId,
+ /* [out] */ ULONG *pcRank);
+
+ HRESULT ( STDMETHODCALLTYPE *GetThreadInfo )(
+ ICorProfilerInfo3 * This,
+ /* [in] */ ThreadID threadId,
+ /* [out] */ DWORD *pdwWin32ThreadId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCurrentThreadID )(
+ ICorProfilerInfo3 * This,
+ /* [out] */ ThreadID *pThreadId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetClassIDInfo )(
+ ICorProfilerInfo3 * This,
+ /* [in] */ ClassID classId,
+ /* [out] */ ModuleID *pModuleId,
+ /* [out] */ mdTypeDef *pTypeDefToken);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFunctionInfo )(
+ ICorProfilerInfo3 * This,
+ /* [in] */ FunctionID functionId,
+ /* [out] */ ClassID *pClassId,
+ /* [out] */ ModuleID *pModuleId,
+ /* [out] */ mdToken *pToken);
+
+ HRESULT ( STDMETHODCALLTYPE *SetEventMask )(
+ ICorProfilerInfo3 * This,
+ /* [in] */ DWORD dwEvents);
+
+ HRESULT ( STDMETHODCALLTYPE *SetEnterLeaveFunctionHooks )(
+ ICorProfilerInfo3 * This,
+ /* [in] */ FunctionEnter *pFuncEnter,
+ /* [in] */ FunctionLeave *pFuncLeave,
+ /* [in] */ FunctionTailcall *pFuncTailcall);
+
+ HRESULT ( STDMETHODCALLTYPE *SetFunctionIDMapper )(
+ ICorProfilerInfo3 * This,
+ /* [in] */ FunctionIDMapper *pFunc);
+
+ HRESULT ( STDMETHODCALLTYPE *GetTokenAndMetaDataFromFunction )(
+ ICorProfilerInfo3 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ REFIID riid,
+ /* [out] */ IUnknown **ppImport,
+ /* [out] */ mdToken *pToken);
+
+ HRESULT ( STDMETHODCALLTYPE *GetModuleInfo )(
+ ICorProfilerInfo3 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [out] */ LPCBYTE *ppBaseLoadAddress,
+ /* [in] */ ULONG cchName,
+ /* [out] */ ULONG *pcchName,
+ /* [annotation][out] */
+ _Out_writes_to_(cchName, *pcchName) WCHAR szName[ ],
+ /* [out] */ AssemblyID *pAssemblyId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetModuleMetaData )(
+ ICorProfilerInfo3 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ DWORD dwOpenFlags,
+ /* [in] */ REFIID riid,
+ /* [out] */ IUnknown **ppOut);
+
+ HRESULT ( STDMETHODCALLTYPE *GetILFunctionBody )(
+ ICorProfilerInfo3 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ mdMethodDef methodId,
+ /* [out] */ LPCBYTE *ppMethodHeader,
+ /* [out] */ ULONG *pcbMethodSize);
+
+ HRESULT ( STDMETHODCALLTYPE *GetILFunctionBodyAllocator )(
+ ICorProfilerInfo3 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [out] */ IMethodMalloc **ppMalloc);
+
+ HRESULT ( STDMETHODCALLTYPE *SetILFunctionBody )(
+ ICorProfilerInfo3 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ mdMethodDef methodid,
+ /* [in] */ LPCBYTE pbNewILMethodHeader);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAppDomainInfo )(
+ ICorProfilerInfo3 * This,
+ /* [in] */ AppDomainID appDomainId,
+ /* [in] */ ULONG cchName,
+ /* [out] */ ULONG *pcchName,
+ /* [annotation][out] */
+ _Out_writes_to_(cchName, *pcchName) WCHAR szName[ ],
+ /* [out] */ ProcessID *pProcessId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAssemblyInfo )(
+ ICorProfilerInfo3 * This,
+ /* [in] */ AssemblyID assemblyId,
+ /* [in] */ ULONG cchName,
+ /* [out] */ ULONG *pcchName,
+ /* [annotation][out] */
+ _Out_writes_to_(cchName, *pcchName) WCHAR szName[ ],
+ /* [out] */ AppDomainID *pAppDomainId,
+ /* [out] */ ModuleID *pModuleId);
+
+ HRESULT ( STDMETHODCALLTYPE *SetFunctionReJIT )(
+ ICorProfilerInfo3 * This,
+ /* [in] */ FunctionID functionId);
+
+ HRESULT ( STDMETHODCALLTYPE *ForceGC )(
+ ICorProfilerInfo3 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *SetILInstrumentedCodeMap )(
+ ICorProfilerInfo3 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ BOOL fStartJit,
+ /* [in] */ ULONG cILMapEntries,
+ /* [size_is][in] */ COR_IL_MAP rgILMapEntries[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetInprocInspectionInterface )(
+ ICorProfilerInfo3 * This,
+ /* [out] */ IUnknown **ppicd);
+
+ HRESULT ( STDMETHODCALLTYPE *GetInprocInspectionIThisThread )(
+ ICorProfilerInfo3 * This,
+ /* [out] */ IUnknown **ppicd);
+
+ HRESULT ( STDMETHODCALLTYPE *GetThreadContext )(
+ ICorProfilerInfo3 * This,
+ /* [in] */ ThreadID threadId,
+ /* [out] */ ContextID *pContextId);
+
+ HRESULT ( STDMETHODCALLTYPE *BeginInprocDebugging )(
+ ICorProfilerInfo3 * This,
+ /* [in] */ BOOL fThisThreadOnly,
+ /* [out] */ DWORD *pdwProfilerContext);
+
+ HRESULT ( STDMETHODCALLTYPE *EndInprocDebugging )(
+ ICorProfilerInfo3 * This,
+ /* [in] */ DWORD dwProfilerContext);
+
+ HRESULT ( STDMETHODCALLTYPE *GetILToNativeMapping )(
+ ICorProfilerInfo3 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ ULONG32 cMap,
+ /* [out] */ ULONG32 *pcMap,
+ /* [length_is][size_is][out] */ COR_DEBUG_IL_TO_NATIVE_MAP map[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *DoStackSnapshot )(
+ ICorProfilerInfo3 * This,
+ /* [in] */ ThreadID thread,
+ /* [in] */ StackSnapshotCallback *callback,
+ /* [in] */ ULONG32 infoFlags,
+ /* [in] */ void *clientData,
+ /* [size_is][in] */ BYTE context[ ],
+ /* [in] */ ULONG32 contextSize);
+
+ HRESULT ( STDMETHODCALLTYPE *SetEnterLeaveFunctionHooks2 )(
+ ICorProfilerInfo3 * This,
+ /* [in] */ FunctionEnter2 *pFuncEnter,
+ /* [in] */ FunctionLeave2 *pFuncLeave,
+ /* [in] */ FunctionTailcall2 *pFuncTailcall);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFunctionInfo2 )(
+ ICorProfilerInfo3 * This,
+ /* [in] */ FunctionID funcId,
+ /* [in] */ COR_PRF_FRAME_INFO frameInfo,
+ /* [out] */ ClassID *pClassId,
+ /* [out] */ ModuleID *pModuleId,
+ /* [out] */ mdToken *pToken,
+ /* [in] */ ULONG32 cTypeArgs,
+ /* [out] */ ULONG32 *pcTypeArgs,
+ /* [out] */ ClassID typeArgs[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetStringLayout )(
+ ICorProfilerInfo3 * This,
+ /* [out] */ ULONG *pBufferLengthOffset,
+ /* [out] */ ULONG *pStringLengthOffset,
+ /* [out] */ ULONG *pBufferOffset);
+
+ HRESULT ( STDMETHODCALLTYPE *GetClassLayout )(
+ ICorProfilerInfo3 * This,
+ /* [in] */ ClassID classID,
+ /* [out][in] */ COR_FIELD_OFFSET rFieldOffset[ ],
+ /* [in] */ ULONG cFieldOffset,
+ /* [out] */ ULONG *pcFieldOffset,
+ /* [out] */ ULONG *pulClassSize);
+
+ HRESULT ( STDMETHODCALLTYPE *GetClassIDInfo2 )(
+ ICorProfilerInfo3 * This,
+ /* [in] */ ClassID classId,
+ /* [out] */ ModuleID *pModuleId,
+ /* [out] */ mdTypeDef *pTypeDefToken,
+ /* [out] */ ClassID *pParentClassId,
+ /* [in] */ ULONG32 cNumTypeArgs,
+ /* [out] */ ULONG32 *pcNumTypeArgs,
+ /* [out] */ ClassID typeArgs[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCodeInfo2 )(
+ ICorProfilerInfo3 * This,
+ /* [in] */ FunctionID functionID,
+ /* [in] */ ULONG32 cCodeInfos,
+ /* [out] */ ULONG32 *pcCodeInfos,
+ /* [length_is][size_is][out] */ COR_PRF_CODE_INFO codeInfos[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetClassFromTokenAndTypeArgs )(
+ ICorProfilerInfo3 * This,
+ /* [in] */ ModuleID moduleID,
+ /* [in] */ mdTypeDef typeDef,
+ /* [in] */ ULONG32 cTypeArgs,
+ /* [size_is][in] */ ClassID typeArgs[ ],
+ /* [out] */ ClassID *pClassID);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFunctionFromTokenAndTypeArgs )(
+ ICorProfilerInfo3 * This,
+ /* [in] */ ModuleID moduleID,
+ /* [in] */ mdMethodDef funcDef,
+ /* [in] */ ClassID classId,
+ /* [in] */ ULONG32 cTypeArgs,
+ /* [size_is][in] */ ClassID typeArgs[ ],
+ /* [out] */ FunctionID *pFunctionID);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumModuleFrozenObjects )(
+ ICorProfilerInfo3 * This,
+ /* [in] */ ModuleID moduleID,
+ /* [out] */ ICorProfilerObjectEnum **ppEnum);
+
+ HRESULT ( STDMETHODCALLTYPE *GetArrayObjectInfo )(
+ ICorProfilerInfo3 * This,
+ /* [in] */ ObjectID objectId,
+ /* [in] */ ULONG32 cDimensions,
+ /* [size_is][out] */ ULONG32 pDimensionSizes[ ],
+ /* [size_is][out] */ int pDimensionLowerBounds[ ],
+ /* [out] */ BYTE **ppData);
+
+ HRESULT ( STDMETHODCALLTYPE *GetBoxClassLayout )(
+ ICorProfilerInfo3 * This,
+ /* [in] */ ClassID classId,
+ /* [out] */ ULONG32 *pBufferOffset);
+
+ HRESULT ( STDMETHODCALLTYPE *GetThreadAppDomain )(
+ ICorProfilerInfo3 * This,
+ /* [in] */ ThreadID threadId,
+ /* [out] */ AppDomainID *pAppDomainId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetRVAStaticAddress )(
+ ICorProfilerInfo3 * This,
+ /* [in] */ ClassID classId,
+ /* [in] */ mdFieldDef fieldToken,
+ /* [out] */ void **ppAddress);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAppDomainStaticAddress )(
+ ICorProfilerInfo3 * This,
+ /* [in] */ ClassID classId,
+ /* [in] */ mdFieldDef fieldToken,
+ /* [in] */ AppDomainID appDomainId,
+ /* [out] */ void **ppAddress);
+
+ HRESULT ( STDMETHODCALLTYPE *GetThreadStaticAddress )(
+ ICorProfilerInfo3 * This,
+ /* [in] */ ClassID classId,
+ /* [in] */ mdFieldDef fieldToken,
+ /* [in] */ ThreadID threadId,
+ /* [out] */ void **ppAddress);
+
+ HRESULT ( STDMETHODCALLTYPE *GetContextStaticAddress )(
+ ICorProfilerInfo3 * This,
+ /* [in] */ ClassID classId,
+ /* [in] */ mdFieldDef fieldToken,
+ /* [in] */ ContextID contextId,
+ /* [out] */ void **ppAddress);
+
+ HRESULT ( STDMETHODCALLTYPE *GetStaticFieldInfo )(
+ ICorProfilerInfo3 * This,
+ /* [in] */ ClassID classId,
+ /* [in] */ mdFieldDef fieldToken,
+ /* [out] */ COR_PRF_STATIC_TYPE *pFieldInfo);
+
+ HRESULT ( STDMETHODCALLTYPE *GetGenerationBounds )(
+ ICorProfilerInfo3 * This,
+ /* [in] */ ULONG cObjectRanges,
+ /* [out] */ ULONG *pcObjectRanges,
+ /* [length_is][size_is][out] */ COR_PRF_GC_GENERATION_RANGE ranges[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetObjectGeneration )(
+ ICorProfilerInfo3 * This,
+ /* [in] */ ObjectID objectId,
+ /* [out] */ COR_PRF_GC_GENERATION_RANGE *range);
+
+ HRESULT ( STDMETHODCALLTYPE *GetNotifiedExceptionClauseInfo )(
+ ICorProfilerInfo3 * This,
+ /* [out] */ COR_PRF_EX_CLAUSE_INFO *pinfo);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumJITedFunctions )(
+ ICorProfilerInfo3 * This,
+ /* [out] */ ICorProfilerFunctionEnum **ppEnum);
+
+ HRESULT ( STDMETHODCALLTYPE *RequestProfilerDetach )(
+ ICorProfilerInfo3 * This,
+ /* [in] */ DWORD dwExpectedCompletionMilliseconds);
+
+ HRESULT ( STDMETHODCALLTYPE *SetFunctionIDMapper2 )(
+ ICorProfilerInfo3 * This,
+ /* [in] */ FunctionIDMapper2 *pFunc,
+ /* [in] */ void *clientData);
+
+ HRESULT ( STDMETHODCALLTYPE *GetStringLayout2 )(
+ ICorProfilerInfo3 * This,
+ /* [out] */ ULONG *pStringLengthOffset,
+ /* [out] */ ULONG *pBufferOffset);
+
+ HRESULT ( STDMETHODCALLTYPE *SetEnterLeaveFunctionHooks3 )(
+ ICorProfilerInfo3 * This,
+ /* [in] */ FunctionEnter3 *pFuncEnter3,
+ /* [in] */ FunctionLeave3 *pFuncLeave3,
+ /* [in] */ FunctionTailcall3 *pFuncTailcall3);
+
+ HRESULT ( STDMETHODCALLTYPE *SetEnterLeaveFunctionHooks3WithInfo )(
+ ICorProfilerInfo3 * This,
+ /* [in] */ FunctionEnter3WithInfo *pFuncEnter3WithInfo,
+ /* [in] */ FunctionLeave3WithInfo *pFuncLeave3WithInfo,
+ /* [in] */ FunctionTailcall3WithInfo *pFuncTailcall3WithInfo);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFunctionEnter3Info )(
+ ICorProfilerInfo3 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ COR_PRF_ELT_INFO eltInfo,
+ /* [out] */ COR_PRF_FRAME_INFO *pFrameInfo,
+ /* [out][in] */ ULONG *pcbArgumentInfo,
+ /* [size_is][out] */ COR_PRF_FUNCTION_ARGUMENT_INFO *pArgumentInfo);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFunctionLeave3Info )(
+ ICorProfilerInfo3 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ COR_PRF_ELT_INFO eltInfo,
+ /* [out] */ COR_PRF_FRAME_INFO *pFrameInfo,
+ /* [out] */ COR_PRF_FUNCTION_ARGUMENT_RANGE *pRetvalRange);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFunctionTailcall3Info )(
+ ICorProfilerInfo3 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ COR_PRF_ELT_INFO eltInfo,
+ /* [out] */ COR_PRF_FRAME_INFO *pFrameInfo);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumModules )(
+ ICorProfilerInfo3 * This,
+ /* [out] */ ICorProfilerModuleEnum **ppEnum);
+
+ HRESULT ( STDMETHODCALLTYPE *GetRuntimeInformation )(
+ ICorProfilerInfo3 * This,
+ /* [out] */ USHORT *pClrInstanceId,
+ /* [out] */ COR_PRF_RUNTIME_TYPE *pRuntimeType,
+ /* [out] */ USHORT *pMajorVersion,
+ /* [out] */ USHORT *pMinorVersion,
+ /* [out] */ USHORT *pBuildNumber,
+ /* [out] */ USHORT *pQFEVersion,
+ /* [in] */ ULONG cchVersionString,
+ /* [out] */ ULONG *pcchVersionString,
+ /* [annotation][out] */
+ _Out_writes_to_(cchVersionString, *pcchVersionString) WCHAR szVersionString[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetThreadStaticAddress2 )(
+ ICorProfilerInfo3 * This,
+ /* [in] */ ClassID classId,
+ /* [in] */ mdFieldDef fieldToken,
+ /* [in] */ AppDomainID appDomainId,
+ /* [in] */ ThreadID threadId,
+ /* [out] */ void **ppAddress);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAppDomainsContainingModule )(
+ ICorProfilerInfo3 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ ULONG32 cAppDomainIds,
+ /* [out] */ ULONG32 *pcAppDomainIds,
+ /* [length_is][size_is][out] */ AppDomainID appDomainIds[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetModuleInfo2 )(
+ ICorProfilerInfo3 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [out] */ LPCBYTE *ppBaseLoadAddress,
+ /* [in] */ ULONG cchName,
+ /* [out] */ ULONG *pcchName,
+ /* [annotation][out] */
+ _Out_writes_to_(cchName, *pcchName) WCHAR szName[ ],
+ /* [out] */ AssemblyID *pAssemblyId,
+ /* [out] */ DWORD *pdwModuleFlags);
+
+ END_INTERFACE
+ } ICorProfilerInfo3Vtbl;
+
+ interface ICorProfilerInfo3
+ {
+ CONST_VTBL struct ICorProfilerInfo3Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorProfilerInfo3_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorProfilerInfo3_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorProfilerInfo3_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorProfilerInfo3_GetClassFromObject(This,objectId,pClassId) \
+ ( (This)->lpVtbl -> GetClassFromObject(This,objectId,pClassId) )
+
+#define ICorProfilerInfo3_GetClassFromToken(This,moduleId,typeDef,pClassId) \
+ ( (This)->lpVtbl -> GetClassFromToken(This,moduleId,typeDef,pClassId) )
+
+#define ICorProfilerInfo3_GetCodeInfo(This,functionId,pStart,pcSize) \
+ ( (This)->lpVtbl -> GetCodeInfo(This,functionId,pStart,pcSize) )
+
+#define ICorProfilerInfo3_GetEventMask(This,pdwEvents) \
+ ( (This)->lpVtbl -> GetEventMask(This,pdwEvents) )
+
+#define ICorProfilerInfo3_GetFunctionFromIP(This,ip,pFunctionId) \
+ ( (This)->lpVtbl -> GetFunctionFromIP(This,ip,pFunctionId) )
+
+#define ICorProfilerInfo3_GetFunctionFromToken(This,moduleId,token,pFunctionId) \
+ ( (This)->lpVtbl -> GetFunctionFromToken(This,moduleId,token,pFunctionId) )
+
+#define ICorProfilerInfo3_GetHandleFromThread(This,threadId,phThread) \
+ ( (This)->lpVtbl -> GetHandleFromThread(This,threadId,phThread) )
+
+#define ICorProfilerInfo3_GetObjectSize(This,objectId,pcSize) \
+ ( (This)->lpVtbl -> GetObjectSize(This,objectId,pcSize) )
+
+#define ICorProfilerInfo3_IsArrayClass(This,classId,pBaseElemType,pBaseClassId,pcRank) \
+ ( (This)->lpVtbl -> IsArrayClass(This,classId,pBaseElemType,pBaseClassId,pcRank) )
+
+#define ICorProfilerInfo3_GetThreadInfo(This,threadId,pdwWin32ThreadId) \
+ ( (This)->lpVtbl -> GetThreadInfo(This,threadId,pdwWin32ThreadId) )
+
+#define ICorProfilerInfo3_GetCurrentThreadID(This,pThreadId) \
+ ( (This)->lpVtbl -> GetCurrentThreadID(This,pThreadId) )
+
+#define ICorProfilerInfo3_GetClassIDInfo(This,classId,pModuleId,pTypeDefToken) \
+ ( (This)->lpVtbl -> GetClassIDInfo(This,classId,pModuleId,pTypeDefToken) )
+
+#define ICorProfilerInfo3_GetFunctionInfo(This,functionId,pClassId,pModuleId,pToken) \
+ ( (This)->lpVtbl -> GetFunctionInfo(This,functionId,pClassId,pModuleId,pToken) )
+
+#define ICorProfilerInfo3_SetEventMask(This,dwEvents) \
+ ( (This)->lpVtbl -> SetEventMask(This,dwEvents) )
+
+#define ICorProfilerInfo3_SetEnterLeaveFunctionHooks(This,pFuncEnter,pFuncLeave,pFuncTailcall) \
+ ( (This)->lpVtbl -> SetEnterLeaveFunctionHooks(This,pFuncEnter,pFuncLeave,pFuncTailcall) )
+
+#define ICorProfilerInfo3_SetFunctionIDMapper(This,pFunc) \
+ ( (This)->lpVtbl -> SetFunctionIDMapper(This,pFunc) )
+
+#define ICorProfilerInfo3_GetTokenAndMetaDataFromFunction(This,functionId,riid,ppImport,pToken) \
+ ( (This)->lpVtbl -> GetTokenAndMetaDataFromFunction(This,functionId,riid,ppImport,pToken) )
+
+#define ICorProfilerInfo3_GetModuleInfo(This,moduleId,ppBaseLoadAddress,cchName,pcchName,szName,pAssemblyId) \
+ ( (This)->lpVtbl -> GetModuleInfo(This,moduleId,ppBaseLoadAddress,cchName,pcchName,szName,pAssemblyId) )
+
+#define ICorProfilerInfo3_GetModuleMetaData(This,moduleId,dwOpenFlags,riid,ppOut) \
+ ( (This)->lpVtbl -> GetModuleMetaData(This,moduleId,dwOpenFlags,riid,ppOut) )
+
+#define ICorProfilerInfo3_GetILFunctionBody(This,moduleId,methodId,ppMethodHeader,pcbMethodSize) \
+ ( (This)->lpVtbl -> GetILFunctionBody(This,moduleId,methodId,ppMethodHeader,pcbMethodSize) )
+
+#define ICorProfilerInfo3_GetILFunctionBodyAllocator(This,moduleId,ppMalloc) \
+ ( (This)->lpVtbl -> GetILFunctionBodyAllocator(This,moduleId,ppMalloc) )
+
+#define ICorProfilerInfo3_SetILFunctionBody(This,moduleId,methodid,pbNewILMethodHeader) \
+ ( (This)->lpVtbl -> SetILFunctionBody(This,moduleId,methodid,pbNewILMethodHeader) )
+
+#define ICorProfilerInfo3_GetAppDomainInfo(This,appDomainId,cchName,pcchName,szName,pProcessId) \
+ ( (This)->lpVtbl -> GetAppDomainInfo(This,appDomainId,cchName,pcchName,szName,pProcessId) )
+
+#define ICorProfilerInfo3_GetAssemblyInfo(This,assemblyId,cchName,pcchName,szName,pAppDomainId,pModuleId) \
+ ( (This)->lpVtbl -> GetAssemblyInfo(This,assemblyId,cchName,pcchName,szName,pAppDomainId,pModuleId) )
+
+#define ICorProfilerInfo3_SetFunctionReJIT(This,functionId) \
+ ( (This)->lpVtbl -> SetFunctionReJIT(This,functionId) )
+
+#define ICorProfilerInfo3_ForceGC(This) \
+ ( (This)->lpVtbl -> ForceGC(This) )
+
+#define ICorProfilerInfo3_SetILInstrumentedCodeMap(This,functionId,fStartJit,cILMapEntries,rgILMapEntries) \
+ ( (This)->lpVtbl -> SetILInstrumentedCodeMap(This,functionId,fStartJit,cILMapEntries,rgILMapEntries) )
+
+#define ICorProfilerInfo3_GetInprocInspectionInterface(This,ppicd) \
+ ( (This)->lpVtbl -> GetInprocInspectionInterface(This,ppicd) )
+
+#define ICorProfilerInfo3_GetInprocInspectionIThisThread(This,ppicd) \
+ ( (This)->lpVtbl -> GetInprocInspectionIThisThread(This,ppicd) )
+
+#define ICorProfilerInfo3_GetThreadContext(This,threadId,pContextId) \
+ ( (This)->lpVtbl -> GetThreadContext(This,threadId,pContextId) )
+
+#define ICorProfilerInfo3_BeginInprocDebugging(This,fThisThreadOnly,pdwProfilerContext) \
+ ( (This)->lpVtbl -> BeginInprocDebugging(This,fThisThreadOnly,pdwProfilerContext) )
+
+#define ICorProfilerInfo3_EndInprocDebugging(This,dwProfilerContext) \
+ ( (This)->lpVtbl -> EndInprocDebugging(This,dwProfilerContext) )
+
+#define ICorProfilerInfo3_GetILToNativeMapping(This,functionId,cMap,pcMap,map) \
+ ( (This)->lpVtbl -> GetILToNativeMapping(This,functionId,cMap,pcMap,map) )
+
+
+#define ICorProfilerInfo3_DoStackSnapshot(This,thread,callback,infoFlags,clientData,context,contextSize) \
+ ( (This)->lpVtbl -> DoStackSnapshot(This,thread,callback,infoFlags,clientData,context,contextSize) )
+
+#define ICorProfilerInfo3_SetEnterLeaveFunctionHooks2(This,pFuncEnter,pFuncLeave,pFuncTailcall) \
+ ( (This)->lpVtbl -> SetEnterLeaveFunctionHooks2(This,pFuncEnter,pFuncLeave,pFuncTailcall) )
+
+#define ICorProfilerInfo3_GetFunctionInfo2(This,funcId,frameInfo,pClassId,pModuleId,pToken,cTypeArgs,pcTypeArgs,typeArgs) \
+ ( (This)->lpVtbl -> GetFunctionInfo2(This,funcId,frameInfo,pClassId,pModuleId,pToken,cTypeArgs,pcTypeArgs,typeArgs) )
+
+#define ICorProfilerInfo3_GetStringLayout(This,pBufferLengthOffset,pStringLengthOffset,pBufferOffset) \
+ ( (This)->lpVtbl -> GetStringLayout(This,pBufferLengthOffset,pStringLengthOffset,pBufferOffset) )
+
+#define ICorProfilerInfo3_GetClassLayout(This,classID,rFieldOffset,cFieldOffset,pcFieldOffset,pulClassSize) \
+ ( (This)->lpVtbl -> GetClassLayout(This,classID,rFieldOffset,cFieldOffset,pcFieldOffset,pulClassSize) )
+
+#define ICorProfilerInfo3_GetClassIDInfo2(This,classId,pModuleId,pTypeDefToken,pParentClassId,cNumTypeArgs,pcNumTypeArgs,typeArgs) \
+ ( (This)->lpVtbl -> GetClassIDInfo2(This,classId,pModuleId,pTypeDefToken,pParentClassId,cNumTypeArgs,pcNumTypeArgs,typeArgs) )
+
+#define ICorProfilerInfo3_GetCodeInfo2(This,functionID,cCodeInfos,pcCodeInfos,codeInfos) \
+ ( (This)->lpVtbl -> GetCodeInfo2(This,functionID,cCodeInfos,pcCodeInfos,codeInfos) )
+
+#define ICorProfilerInfo3_GetClassFromTokenAndTypeArgs(This,moduleID,typeDef,cTypeArgs,typeArgs,pClassID) \
+ ( (This)->lpVtbl -> GetClassFromTokenAndTypeArgs(This,moduleID,typeDef,cTypeArgs,typeArgs,pClassID) )
+
+#define ICorProfilerInfo3_GetFunctionFromTokenAndTypeArgs(This,moduleID,funcDef,classId,cTypeArgs,typeArgs,pFunctionID) \
+ ( (This)->lpVtbl -> GetFunctionFromTokenAndTypeArgs(This,moduleID,funcDef,classId,cTypeArgs,typeArgs,pFunctionID) )
+
+#define ICorProfilerInfo3_EnumModuleFrozenObjects(This,moduleID,ppEnum) \
+ ( (This)->lpVtbl -> EnumModuleFrozenObjects(This,moduleID,ppEnum) )
+
+#define ICorProfilerInfo3_GetArrayObjectInfo(This,objectId,cDimensions,pDimensionSizes,pDimensionLowerBounds,ppData) \
+ ( (This)->lpVtbl -> GetArrayObjectInfo(This,objectId,cDimensions,pDimensionSizes,pDimensionLowerBounds,ppData) )
+
+#define ICorProfilerInfo3_GetBoxClassLayout(This,classId,pBufferOffset) \
+ ( (This)->lpVtbl -> GetBoxClassLayout(This,classId,pBufferOffset) )
+
+#define ICorProfilerInfo3_GetThreadAppDomain(This,threadId,pAppDomainId) \
+ ( (This)->lpVtbl -> GetThreadAppDomain(This,threadId,pAppDomainId) )
+
+#define ICorProfilerInfo3_GetRVAStaticAddress(This,classId,fieldToken,ppAddress) \
+ ( (This)->lpVtbl -> GetRVAStaticAddress(This,classId,fieldToken,ppAddress) )
+
+#define ICorProfilerInfo3_GetAppDomainStaticAddress(This,classId,fieldToken,appDomainId,ppAddress) \
+ ( (This)->lpVtbl -> GetAppDomainStaticAddress(This,classId,fieldToken,appDomainId,ppAddress) )
+
+#define ICorProfilerInfo3_GetThreadStaticAddress(This,classId,fieldToken,threadId,ppAddress) \
+ ( (This)->lpVtbl -> GetThreadStaticAddress(This,classId,fieldToken,threadId,ppAddress) )
+
+#define ICorProfilerInfo3_GetContextStaticAddress(This,classId,fieldToken,contextId,ppAddress) \
+ ( (This)->lpVtbl -> GetContextStaticAddress(This,classId,fieldToken,contextId,ppAddress) )
+
+#define ICorProfilerInfo3_GetStaticFieldInfo(This,classId,fieldToken,pFieldInfo) \
+ ( (This)->lpVtbl -> GetStaticFieldInfo(This,classId,fieldToken,pFieldInfo) )
+
+#define ICorProfilerInfo3_GetGenerationBounds(This,cObjectRanges,pcObjectRanges,ranges) \
+ ( (This)->lpVtbl -> GetGenerationBounds(This,cObjectRanges,pcObjectRanges,ranges) )
+
+#define ICorProfilerInfo3_GetObjectGeneration(This,objectId,range) \
+ ( (This)->lpVtbl -> GetObjectGeneration(This,objectId,range) )
+
+#define ICorProfilerInfo3_GetNotifiedExceptionClauseInfo(This,pinfo) \
+ ( (This)->lpVtbl -> GetNotifiedExceptionClauseInfo(This,pinfo) )
+
+
+#define ICorProfilerInfo3_EnumJITedFunctions(This,ppEnum) \
+ ( (This)->lpVtbl -> EnumJITedFunctions(This,ppEnum) )
+
+#define ICorProfilerInfo3_RequestProfilerDetach(This,dwExpectedCompletionMilliseconds) \
+ ( (This)->lpVtbl -> RequestProfilerDetach(This,dwExpectedCompletionMilliseconds) )
+
+#define ICorProfilerInfo3_SetFunctionIDMapper2(This,pFunc,clientData) \
+ ( (This)->lpVtbl -> SetFunctionIDMapper2(This,pFunc,clientData) )
+
+#define ICorProfilerInfo3_GetStringLayout2(This,pStringLengthOffset,pBufferOffset) \
+ ( (This)->lpVtbl -> GetStringLayout2(This,pStringLengthOffset,pBufferOffset) )
+
+#define ICorProfilerInfo3_SetEnterLeaveFunctionHooks3(This,pFuncEnter3,pFuncLeave3,pFuncTailcall3) \
+ ( (This)->lpVtbl -> SetEnterLeaveFunctionHooks3(This,pFuncEnter3,pFuncLeave3,pFuncTailcall3) )
+
+#define ICorProfilerInfo3_SetEnterLeaveFunctionHooks3WithInfo(This,pFuncEnter3WithInfo,pFuncLeave3WithInfo,pFuncTailcall3WithInfo) \
+ ( (This)->lpVtbl -> SetEnterLeaveFunctionHooks3WithInfo(This,pFuncEnter3WithInfo,pFuncLeave3WithInfo,pFuncTailcall3WithInfo) )
+
+#define ICorProfilerInfo3_GetFunctionEnter3Info(This,functionId,eltInfo,pFrameInfo,pcbArgumentInfo,pArgumentInfo) \
+ ( (This)->lpVtbl -> GetFunctionEnter3Info(This,functionId,eltInfo,pFrameInfo,pcbArgumentInfo,pArgumentInfo) )
+
+#define ICorProfilerInfo3_GetFunctionLeave3Info(This,functionId,eltInfo,pFrameInfo,pRetvalRange) \
+ ( (This)->lpVtbl -> GetFunctionLeave3Info(This,functionId,eltInfo,pFrameInfo,pRetvalRange) )
+
+#define ICorProfilerInfo3_GetFunctionTailcall3Info(This,functionId,eltInfo,pFrameInfo) \
+ ( (This)->lpVtbl -> GetFunctionTailcall3Info(This,functionId,eltInfo,pFrameInfo) )
+
+#define ICorProfilerInfo3_EnumModules(This,ppEnum) \
+ ( (This)->lpVtbl -> EnumModules(This,ppEnum) )
+
+#define ICorProfilerInfo3_GetRuntimeInformation(This,pClrInstanceId,pRuntimeType,pMajorVersion,pMinorVersion,pBuildNumber,pQFEVersion,cchVersionString,pcchVersionString,szVersionString) \
+ ( (This)->lpVtbl -> GetRuntimeInformation(This,pClrInstanceId,pRuntimeType,pMajorVersion,pMinorVersion,pBuildNumber,pQFEVersion,cchVersionString,pcchVersionString,szVersionString) )
+
+#define ICorProfilerInfo3_GetThreadStaticAddress2(This,classId,fieldToken,appDomainId,threadId,ppAddress) \
+ ( (This)->lpVtbl -> GetThreadStaticAddress2(This,classId,fieldToken,appDomainId,threadId,ppAddress) )
+
+#define ICorProfilerInfo3_GetAppDomainsContainingModule(This,moduleId,cAppDomainIds,pcAppDomainIds,appDomainIds) \
+ ( (This)->lpVtbl -> GetAppDomainsContainingModule(This,moduleId,cAppDomainIds,pcAppDomainIds,appDomainIds) )
+
+#define ICorProfilerInfo3_GetModuleInfo2(This,moduleId,ppBaseLoadAddress,cchName,pcchName,szName,pAssemblyId,pdwModuleFlags) \
+ ( (This)->lpVtbl -> GetModuleInfo2(This,moduleId,ppBaseLoadAddress,cchName,pcchName,szName,pAssemblyId,pdwModuleFlags) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorProfilerInfo3_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorProfilerObjectEnum_INTERFACE_DEFINED__
+#define __ICorProfilerObjectEnum_INTERFACE_DEFINED__
+
+/* interface ICorProfilerObjectEnum */
+/* [local][unique][uuid][object] */
+
+
+EXTERN_C const IID IID_ICorProfilerObjectEnum;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("2C6269BD-2D13-4321-AE12-6686365FD6AF")
+ ICorProfilerObjectEnum : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE Skip(
+ /* [in] */ ULONG celt) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Reset( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Clone(
+ /* [out] */ ICorProfilerObjectEnum **ppEnum) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetCount(
+ /* [out] */ ULONG *pcelt) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Next(
+ /* [in] */ ULONG celt,
+ /* [length_is][size_is][out] */ ObjectID objects[ ],
+ /* [out] */ ULONG *pceltFetched) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorProfilerObjectEnumVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorProfilerObjectEnum * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorProfilerObjectEnum * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorProfilerObjectEnum * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Skip )(
+ ICorProfilerObjectEnum * This,
+ /* [in] */ ULONG celt);
+
+ HRESULT ( STDMETHODCALLTYPE *Reset )(
+ ICorProfilerObjectEnum * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Clone )(
+ ICorProfilerObjectEnum * This,
+ /* [out] */ ICorProfilerObjectEnum **ppEnum);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCount )(
+ ICorProfilerObjectEnum * This,
+ /* [out] */ ULONG *pcelt);
+
+ HRESULT ( STDMETHODCALLTYPE *Next )(
+ ICorProfilerObjectEnum * This,
+ /* [in] */ ULONG celt,
+ /* [length_is][size_is][out] */ ObjectID objects[ ],
+ /* [out] */ ULONG *pceltFetched);
+
+ END_INTERFACE
+ } ICorProfilerObjectEnumVtbl;
+
+ interface ICorProfilerObjectEnum
+ {
+ CONST_VTBL struct ICorProfilerObjectEnumVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorProfilerObjectEnum_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorProfilerObjectEnum_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorProfilerObjectEnum_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorProfilerObjectEnum_Skip(This,celt) \
+ ( (This)->lpVtbl -> Skip(This,celt) )
+
+#define ICorProfilerObjectEnum_Reset(This) \
+ ( (This)->lpVtbl -> Reset(This) )
+
+#define ICorProfilerObjectEnum_Clone(This,ppEnum) \
+ ( (This)->lpVtbl -> Clone(This,ppEnum) )
+
+#define ICorProfilerObjectEnum_GetCount(This,pcelt) \
+ ( (This)->lpVtbl -> GetCount(This,pcelt) )
+
+#define ICorProfilerObjectEnum_Next(This,celt,objects,pceltFetched) \
+ ( (This)->lpVtbl -> Next(This,celt,objects,pceltFetched) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorProfilerObjectEnum_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorProfilerFunctionEnum_INTERFACE_DEFINED__
+#define __ICorProfilerFunctionEnum_INTERFACE_DEFINED__
+
+/* interface ICorProfilerFunctionEnum */
+/* [local][unique][uuid][object] */
+
+
+EXTERN_C const IID IID_ICorProfilerFunctionEnum;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("FF71301A-B994-429D-A10B-B345A65280EF")
+ ICorProfilerFunctionEnum : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE Skip(
+ /* [in] */ ULONG celt) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Reset( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Clone(
+ /* [out] */ ICorProfilerFunctionEnum **ppEnum) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetCount(
+ /* [out] */ ULONG *pcelt) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Next(
+ /* [in] */ ULONG celt,
+ /* [length_is][size_is][out] */ COR_PRF_FUNCTION ids[ ],
+ /* [out] */ ULONG *pceltFetched) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorProfilerFunctionEnumVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorProfilerFunctionEnum * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorProfilerFunctionEnum * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorProfilerFunctionEnum * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Skip )(
+ ICorProfilerFunctionEnum * This,
+ /* [in] */ ULONG celt);
+
+ HRESULT ( STDMETHODCALLTYPE *Reset )(
+ ICorProfilerFunctionEnum * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Clone )(
+ ICorProfilerFunctionEnum * This,
+ /* [out] */ ICorProfilerFunctionEnum **ppEnum);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCount )(
+ ICorProfilerFunctionEnum * This,
+ /* [out] */ ULONG *pcelt);
+
+ HRESULT ( STDMETHODCALLTYPE *Next )(
+ ICorProfilerFunctionEnum * This,
+ /* [in] */ ULONG celt,
+ /* [length_is][size_is][out] */ COR_PRF_FUNCTION ids[ ],
+ /* [out] */ ULONG *pceltFetched);
+
+ END_INTERFACE
+ } ICorProfilerFunctionEnumVtbl;
+
+ interface ICorProfilerFunctionEnum
+ {
+ CONST_VTBL struct ICorProfilerFunctionEnumVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorProfilerFunctionEnum_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorProfilerFunctionEnum_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorProfilerFunctionEnum_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorProfilerFunctionEnum_Skip(This,celt) \
+ ( (This)->lpVtbl -> Skip(This,celt) )
+
+#define ICorProfilerFunctionEnum_Reset(This) \
+ ( (This)->lpVtbl -> Reset(This) )
+
+#define ICorProfilerFunctionEnum_Clone(This,ppEnum) \
+ ( (This)->lpVtbl -> Clone(This,ppEnum) )
+
+#define ICorProfilerFunctionEnum_GetCount(This,pcelt) \
+ ( (This)->lpVtbl -> GetCount(This,pcelt) )
+
+#define ICorProfilerFunctionEnum_Next(This,celt,ids,pceltFetched) \
+ ( (This)->lpVtbl -> Next(This,celt,ids,pceltFetched) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorProfilerFunctionEnum_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorProfilerModuleEnum_INTERFACE_DEFINED__
+#define __ICorProfilerModuleEnum_INTERFACE_DEFINED__
+
+/* interface ICorProfilerModuleEnum */
+/* [local][unique][uuid][object] */
+
+
+EXTERN_C const IID IID_ICorProfilerModuleEnum;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("b0266d75-2081-4493-af7f-028ba34db891")
+ ICorProfilerModuleEnum : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE Skip(
+ /* [in] */ ULONG celt) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Reset( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Clone(
+ /* [out] */ ICorProfilerModuleEnum **ppEnum) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetCount(
+ /* [out] */ ULONG *pcelt) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Next(
+ /* [in] */ ULONG celt,
+ /* [length_is][size_is][out] */ ModuleID ids[ ],
+ /* [out] */ ULONG *pceltFetched) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorProfilerModuleEnumVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorProfilerModuleEnum * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorProfilerModuleEnum * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorProfilerModuleEnum * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Skip )(
+ ICorProfilerModuleEnum * This,
+ /* [in] */ ULONG celt);
+
+ HRESULT ( STDMETHODCALLTYPE *Reset )(
+ ICorProfilerModuleEnum * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Clone )(
+ ICorProfilerModuleEnum * This,
+ /* [out] */ ICorProfilerModuleEnum **ppEnum);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCount )(
+ ICorProfilerModuleEnum * This,
+ /* [out] */ ULONG *pcelt);
+
+ HRESULT ( STDMETHODCALLTYPE *Next )(
+ ICorProfilerModuleEnum * This,
+ /* [in] */ ULONG celt,
+ /* [length_is][size_is][out] */ ModuleID ids[ ],
+ /* [out] */ ULONG *pceltFetched);
+
+ END_INTERFACE
+ } ICorProfilerModuleEnumVtbl;
+
+ interface ICorProfilerModuleEnum
+ {
+ CONST_VTBL struct ICorProfilerModuleEnumVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorProfilerModuleEnum_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorProfilerModuleEnum_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorProfilerModuleEnum_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorProfilerModuleEnum_Skip(This,celt) \
+ ( (This)->lpVtbl -> Skip(This,celt) )
+
+#define ICorProfilerModuleEnum_Reset(This) \
+ ( (This)->lpVtbl -> Reset(This) )
+
+#define ICorProfilerModuleEnum_Clone(This,ppEnum) \
+ ( (This)->lpVtbl -> Clone(This,ppEnum) )
+
+#define ICorProfilerModuleEnum_GetCount(This,pcelt) \
+ ( (This)->lpVtbl -> GetCount(This,pcelt) )
+
+#define ICorProfilerModuleEnum_Next(This,celt,ids,pceltFetched) \
+ ( (This)->lpVtbl -> Next(This,celt,ids,pceltFetched) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorProfilerModuleEnum_INTERFACE_DEFINED__ */
+
+
+#ifndef __IMethodMalloc_INTERFACE_DEFINED__
+#define __IMethodMalloc_INTERFACE_DEFINED__
+
+/* interface IMethodMalloc */
+/* [local][unique][uuid][object] */
+
+
+EXTERN_C const IID IID_IMethodMalloc;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("A0EFB28B-6EE2-4d7b-B983-A75EF7BEEDB8")
+ IMethodMalloc : public IUnknown
+ {
+ public:
+ virtual PVOID STDMETHODCALLTYPE Alloc(
+ /* [in] */ ULONG cb) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IMethodMallocVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IMethodMalloc * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IMethodMalloc * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IMethodMalloc * This);
+
+ PVOID ( STDMETHODCALLTYPE *Alloc )(
+ IMethodMalloc * This,
+ /* [in] */ ULONG cb);
+
+ END_INTERFACE
+ } IMethodMallocVtbl;
+
+ interface IMethodMalloc
+ {
+ CONST_VTBL struct IMethodMallocVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IMethodMalloc_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IMethodMalloc_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IMethodMalloc_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IMethodMalloc_Alloc(This,cb) \
+ ( (This)->lpVtbl -> Alloc(This,cb) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IMethodMalloc_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorProfilerFunctionControl_INTERFACE_DEFINED__
+#define __ICorProfilerFunctionControl_INTERFACE_DEFINED__
+
+/* interface ICorProfilerFunctionControl */
+/* [local][unique][uuid][object] */
+
+
+EXTERN_C const IID IID_ICorProfilerFunctionControl;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("F0963021-E1EA-4732-8581-E01B0BD3C0C6")
+ ICorProfilerFunctionControl : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE SetCodegenFlags(
+ /* [in] */ DWORD flags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetILFunctionBody(
+ /* [in] */ ULONG cbNewILMethodHeader,
+ /* [size_is][in] */ LPCBYTE pbNewILMethodHeader) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetILInstrumentedCodeMap(
+ /* [in] */ ULONG cILMapEntries,
+ /* [size_is][in] */ COR_IL_MAP rgILMapEntries[ ]) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorProfilerFunctionControlVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorProfilerFunctionControl * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorProfilerFunctionControl * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorProfilerFunctionControl * This);
+
+ HRESULT ( STDMETHODCALLTYPE *SetCodegenFlags )(
+ ICorProfilerFunctionControl * This,
+ /* [in] */ DWORD flags);
+
+ HRESULT ( STDMETHODCALLTYPE *SetILFunctionBody )(
+ ICorProfilerFunctionControl * This,
+ /* [in] */ ULONG cbNewILMethodHeader,
+ /* [size_is][in] */ LPCBYTE pbNewILMethodHeader);
+
+ HRESULT ( STDMETHODCALLTYPE *SetILInstrumentedCodeMap )(
+ ICorProfilerFunctionControl * This,
+ /* [in] */ ULONG cILMapEntries,
+ /* [size_is][in] */ COR_IL_MAP rgILMapEntries[ ]);
+
+ END_INTERFACE
+ } ICorProfilerFunctionControlVtbl;
+
+ interface ICorProfilerFunctionControl
+ {
+ CONST_VTBL struct ICorProfilerFunctionControlVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorProfilerFunctionControl_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorProfilerFunctionControl_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorProfilerFunctionControl_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorProfilerFunctionControl_SetCodegenFlags(This,flags) \
+ ( (This)->lpVtbl -> SetCodegenFlags(This,flags) )
+
+#define ICorProfilerFunctionControl_SetILFunctionBody(This,cbNewILMethodHeader,pbNewILMethodHeader) \
+ ( (This)->lpVtbl -> SetILFunctionBody(This,cbNewILMethodHeader,pbNewILMethodHeader) )
+
+#define ICorProfilerFunctionControl_SetILInstrumentedCodeMap(This,cILMapEntries,rgILMapEntries) \
+ ( (This)->lpVtbl -> SetILInstrumentedCodeMap(This,cILMapEntries,rgILMapEntries) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorProfilerFunctionControl_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorProfilerInfo4_INTERFACE_DEFINED__
+#define __ICorProfilerInfo4_INTERFACE_DEFINED__
+
+/* interface ICorProfilerInfo4 */
+/* [local][unique][uuid][object] */
+
+
+EXTERN_C const IID IID_ICorProfilerInfo4;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("0d8fdcaa-6257-47bf-b1bf-94dac88466ee")
+ ICorProfilerInfo4 : public ICorProfilerInfo3
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE EnumThreads(
+ /* [out] */ ICorProfilerThreadEnum **ppEnum) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE InitializeCurrentThread( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE RequestReJIT(
+ /* [in] */ ULONG cFunctions,
+ /* [size_is][in] */ ModuleID moduleIds[ ],
+ /* [size_is][in] */ mdMethodDef methodIds[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE RequestRevert(
+ /* [in] */ ULONG cFunctions,
+ /* [size_is][in] */ ModuleID moduleIds[ ],
+ /* [size_is][in] */ mdMethodDef methodIds[ ],
+ /* [size_is][out] */ HRESULT status[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetCodeInfo3(
+ /* [in] */ FunctionID functionID,
+ /* [in] */ ReJITID reJitId,
+ /* [in] */ ULONG32 cCodeInfos,
+ /* [out] */ ULONG32 *pcCodeInfos,
+ /* [length_is][size_is][out] */ COR_PRF_CODE_INFO codeInfos[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetFunctionFromIP2(
+ /* [in] */ LPCBYTE ip,
+ /* [out] */ FunctionID *pFunctionId,
+ /* [out] */ ReJITID *pReJitId) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetReJITIDs(
+ /* [in] */ FunctionID functionId,
+ /* [in] */ ULONG cReJitIds,
+ /* [out] */ ULONG *pcReJitIds,
+ /* [length_is][size_is][out] */ ReJITID reJitIds[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetILToNativeMapping2(
+ /* [in] */ FunctionID functionId,
+ /* [in] */ ReJITID reJitId,
+ /* [in] */ ULONG32 cMap,
+ /* [out] */ ULONG32 *pcMap,
+ /* [length_is][size_is][out] */ COR_DEBUG_IL_TO_NATIVE_MAP map[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnumJITedFunctions2(
+ /* [out] */ ICorProfilerFunctionEnum **ppEnum) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetObjectSize2(
+ /* [in] */ ObjectID objectId,
+ /* [out] */ SIZE_T *pcSize) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorProfilerInfo4Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorProfilerInfo4 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorProfilerInfo4 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorProfilerInfo4 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetClassFromObject )(
+ ICorProfilerInfo4 * This,
+ /* [in] */ ObjectID objectId,
+ /* [out] */ ClassID *pClassId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetClassFromToken )(
+ ICorProfilerInfo4 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ mdTypeDef typeDef,
+ /* [out] */ ClassID *pClassId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCodeInfo )(
+ ICorProfilerInfo4 * This,
+ /* [in] */ FunctionID functionId,
+ /* [out] */ LPCBYTE *pStart,
+ /* [out] */ ULONG *pcSize);
+
+ HRESULT ( STDMETHODCALLTYPE *GetEventMask )(
+ ICorProfilerInfo4 * This,
+ /* [out] */ DWORD *pdwEvents);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFunctionFromIP )(
+ ICorProfilerInfo4 * This,
+ /* [in] */ LPCBYTE ip,
+ /* [out] */ FunctionID *pFunctionId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFunctionFromToken )(
+ ICorProfilerInfo4 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ mdToken token,
+ /* [out] */ FunctionID *pFunctionId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetHandleFromThread )(
+ ICorProfilerInfo4 * This,
+ /* [in] */ ThreadID threadId,
+ /* [out] */ HANDLE *phThread);
+
+ HRESULT ( STDMETHODCALLTYPE *GetObjectSize )(
+ ICorProfilerInfo4 * This,
+ /* [in] */ ObjectID objectId,
+ /* [out] */ ULONG *pcSize);
+
+ HRESULT ( STDMETHODCALLTYPE *IsArrayClass )(
+ ICorProfilerInfo4 * This,
+ /* [in] */ ClassID classId,
+ /* [out] */ CorElementType *pBaseElemType,
+ /* [out] */ ClassID *pBaseClassId,
+ /* [out] */ ULONG *pcRank);
+
+ HRESULT ( STDMETHODCALLTYPE *GetThreadInfo )(
+ ICorProfilerInfo4 * This,
+ /* [in] */ ThreadID threadId,
+ /* [out] */ DWORD *pdwWin32ThreadId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCurrentThreadID )(
+ ICorProfilerInfo4 * This,
+ /* [out] */ ThreadID *pThreadId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetClassIDInfo )(
+ ICorProfilerInfo4 * This,
+ /* [in] */ ClassID classId,
+ /* [out] */ ModuleID *pModuleId,
+ /* [out] */ mdTypeDef *pTypeDefToken);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFunctionInfo )(
+ ICorProfilerInfo4 * This,
+ /* [in] */ FunctionID functionId,
+ /* [out] */ ClassID *pClassId,
+ /* [out] */ ModuleID *pModuleId,
+ /* [out] */ mdToken *pToken);
+
+ HRESULT ( STDMETHODCALLTYPE *SetEventMask )(
+ ICorProfilerInfo4 * This,
+ /* [in] */ DWORD dwEvents);
+
+ HRESULT ( STDMETHODCALLTYPE *SetEnterLeaveFunctionHooks )(
+ ICorProfilerInfo4 * This,
+ /* [in] */ FunctionEnter *pFuncEnter,
+ /* [in] */ FunctionLeave *pFuncLeave,
+ /* [in] */ FunctionTailcall *pFuncTailcall);
+
+ HRESULT ( STDMETHODCALLTYPE *SetFunctionIDMapper )(
+ ICorProfilerInfo4 * This,
+ /* [in] */ FunctionIDMapper *pFunc);
+
+ HRESULT ( STDMETHODCALLTYPE *GetTokenAndMetaDataFromFunction )(
+ ICorProfilerInfo4 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ REFIID riid,
+ /* [out] */ IUnknown **ppImport,
+ /* [out] */ mdToken *pToken);
+
+ HRESULT ( STDMETHODCALLTYPE *GetModuleInfo )(
+ ICorProfilerInfo4 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [out] */ LPCBYTE *ppBaseLoadAddress,
+ /* [in] */ ULONG cchName,
+ /* [out] */ ULONG *pcchName,
+ /* [annotation][out] */
+ _Out_writes_to_(cchName, *pcchName) WCHAR szName[ ],
+ /* [out] */ AssemblyID *pAssemblyId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetModuleMetaData )(
+ ICorProfilerInfo4 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ DWORD dwOpenFlags,
+ /* [in] */ REFIID riid,
+ /* [out] */ IUnknown **ppOut);
+
+ HRESULT ( STDMETHODCALLTYPE *GetILFunctionBody )(
+ ICorProfilerInfo4 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ mdMethodDef methodId,
+ /* [out] */ LPCBYTE *ppMethodHeader,
+ /* [out] */ ULONG *pcbMethodSize);
+
+ HRESULT ( STDMETHODCALLTYPE *GetILFunctionBodyAllocator )(
+ ICorProfilerInfo4 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [out] */ IMethodMalloc **ppMalloc);
+
+ HRESULT ( STDMETHODCALLTYPE *SetILFunctionBody )(
+ ICorProfilerInfo4 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ mdMethodDef methodid,
+ /* [in] */ LPCBYTE pbNewILMethodHeader);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAppDomainInfo )(
+ ICorProfilerInfo4 * This,
+ /* [in] */ AppDomainID appDomainId,
+ /* [in] */ ULONG cchName,
+ /* [out] */ ULONG *pcchName,
+ /* [annotation][out] */
+ _Out_writes_to_(cchName, *pcchName) WCHAR szName[ ],
+ /* [out] */ ProcessID *pProcessId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAssemblyInfo )(
+ ICorProfilerInfo4 * This,
+ /* [in] */ AssemblyID assemblyId,
+ /* [in] */ ULONG cchName,
+ /* [out] */ ULONG *pcchName,
+ /* [annotation][out] */
+ _Out_writes_to_(cchName, *pcchName) WCHAR szName[ ],
+ /* [out] */ AppDomainID *pAppDomainId,
+ /* [out] */ ModuleID *pModuleId);
+
+ HRESULT ( STDMETHODCALLTYPE *SetFunctionReJIT )(
+ ICorProfilerInfo4 * This,
+ /* [in] */ FunctionID functionId);
+
+ HRESULT ( STDMETHODCALLTYPE *ForceGC )(
+ ICorProfilerInfo4 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *SetILInstrumentedCodeMap )(
+ ICorProfilerInfo4 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ BOOL fStartJit,
+ /* [in] */ ULONG cILMapEntries,
+ /* [size_is][in] */ COR_IL_MAP rgILMapEntries[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetInprocInspectionInterface )(
+ ICorProfilerInfo4 * This,
+ /* [out] */ IUnknown **ppicd);
+
+ HRESULT ( STDMETHODCALLTYPE *GetInprocInspectionIThisThread )(
+ ICorProfilerInfo4 * This,
+ /* [out] */ IUnknown **ppicd);
+
+ HRESULT ( STDMETHODCALLTYPE *GetThreadContext )(
+ ICorProfilerInfo4 * This,
+ /* [in] */ ThreadID threadId,
+ /* [out] */ ContextID *pContextId);
+
+ HRESULT ( STDMETHODCALLTYPE *BeginInprocDebugging )(
+ ICorProfilerInfo4 * This,
+ /* [in] */ BOOL fThisThreadOnly,
+ /* [out] */ DWORD *pdwProfilerContext);
+
+ HRESULT ( STDMETHODCALLTYPE *EndInprocDebugging )(
+ ICorProfilerInfo4 * This,
+ /* [in] */ DWORD dwProfilerContext);
+
+ HRESULT ( STDMETHODCALLTYPE *GetILToNativeMapping )(
+ ICorProfilerInfo4 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ ULONG32 cMap,
+ /* [out] */ ULONG32 *pcMap,
+ /* [length_is][size_is][out] */ COR_DEBUG_IL_TO_NATIVE_MAP map[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *DoStackSnapshot )(
+ ICorProfilerInfo4 * This,
+ /* [in] */ ThreadID thread,
+ /* [in] */ StackSnapshotCallback *callback,
+ /* [in] */ ULONG32 infoFlags,
+ /* [in] */ void *clientData,
+ /* [size_is][in] */ BYTE context[ ],
+ /* [in] */ ULONG32 contextSize);
+
+ HRESULT ( STDMETHODCALLTYPE *SetEnterLeaveFunctionHooks2 )(
+ ICorProfilerInfo4 * This,
+ /* [in] */ FunctionEnter2 *pFuncEnter,
+ /* [in] */ FunctionLeave2 *pFuncLeave,
+ /* [in] */ FunctionTailcall2 *pFuncTailcall);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFunctionInfo2 )(
+ ICorProfilerInfo4 * This,
+ /* [in] */ FunctionID funcId,
+ /* [in] */ COR_PRF_FRAME_INFO frameInfo,
+ /* [out] */ ClassID *pClassId,
+ /* [out] */ ModuleID *pModuleId,
+ /* [out] */ mdToken *pToken,
+ /* [in] */ ULONG32 cTypeArgs,
+ /* [out] */ ULONG32 *pcTypeArgs,
+ /* [out] */ ClassID typeArgs[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetStringLayout )(
+ ICorProfilerInfo4 * This,
+ /* [out] */ ULONG *pBufferLengthOffset,
+ /* [out] */ ULONG *pStringLengthOffset,
+ /* [out] */ ULONG *pBufferOffset);
+
+ HRESULT ( STDMETHODCALLTYPE *GetClassLayout )(
+ ICorProfilerInfo4 * This,
+ /* [in] */ ClassID classID,
+ /* [out][in] */ COR_FIELD_OFFSET rFieldOffset[ ],
+ /* [in] */ ULONG cFieldOffset,
+ /* [out] */ ULONG *pcFieldOffset,
+ /* [out] */ ULONG *pulClassSize);
+
+ HRESULT ( STDMETHODCALLTYPE *GetClassIDInfo2 )(
+ ICorProfilerInfo4 * This,
+ /* [in] */ ClassID classId,
+ /* [out] */ ModuleID *pModuleId,
+ /* [out] */ mdTypeDef *pTypeDefToken,
+ /* [out] */ ClassID *pParentClassId,
+ /* [in] */ ULONG32 cNumTypeArgs,
+ /* [out] */ ULONG32 *pcNumTypeArgs,
+ /* [out] */ ClassID typeArgs[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCodeInfo2 )(
+ ICorProfilerInfo4 * This,
+ /* [in] */ FunctionID functionID,
+ /* [in] */ ULONG32 cCodeInfos,
+ /* [out] */ ULONG32 *pcCodeInfos,
+ /* [length_is][size_is][out] */ COR_PRF_CODE_INFO codeInfos[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetClassFromTokenAndTypeArgs )(
+ ICorProfilerInfo4 * This,
+ /* [in] */ ModuleID moduleID,
+ /* [in] */ mdTypeDef typeDef,
+ /* [in] */ ULONG32 cTypeArgs,
+ /* [size_is][in] */ ClassID typeArgs[ ],
+ /* [out] */ ClassID *pClassID);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFunctionFromTokenAndTypeArgs )(
+ ICorProfilerInfo4 * This,
+ /* [in] */ ModuleID moduleID,
+ /* [in] */ mdMethodDef funcDef,
+ /* [in] */ ClassID classId,
+ /* [in] */ ULONG32 cTypeArgs,
+ /* [size_is][in] */ ClassID typeArgs[ ],
+ /* [out] */ FunctionID *pFunctionID);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumModuleFrozenObjects )(
+ ICorProfilerInfo4 * This,
+ /* [in] */ ModuleID moduleID,
+ /* [out] */ ICorProfilerObjectEnum **ppEnum);
+
+ HRESULT ( STDMETHODCALLTYPE *GetArrayObjectInfo )(
+ ICorProfilerInfo4 * This,
+ /* [in] */ ObjectID objectId,
+ /* [in] */ ULONG32 cDimensions,
+ /* [size_is][out] */ ULONG32 pDimensionSizes[ ],
+ /* [size_is][out] */ int pDimensionLowerBounds[ ],
+ /* [out] */ BYTE **ppData);
+
+ HRESULT ( STDMETHODCALLTYPE *GetBoxClassLayout )(
+ ICorProfilerInfo4 * This,
+ /* [in] */ ClassID classId,
+ /* [out] */ ULONG32 *pBufferOffset);
+
+ HRESULT ( STDMETHODCALLTYPE *GetThreadAppDomain )(
+ ICorProfilerInfo4 * This,
+ /* [in] */ ThreadID threadId,
+ /* [out] */ AppDomainID *pAppDomainId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetRVAStaticAddress )(
+ ICorProfilerInfo4 * This,
+ /* [in] */ ClassID classId,
+ /* [in] */ mdFieldDef fieldToken,
+ /* [out] */ void **ppAddress);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAppDomainStaticAddress )(
+ ICorProfilerInfo4 * This,
+ /* [in] */ ClassID classId,
+ /* [in] */ mdFieldDef fieldToken,
+ /* [in] */ AppDomainID appDomainId,
+ /* [out] */ void **ppAddress);
+
+ HRESULT ( STDMETHODCALLTYPE *GetThreadStaticAddress )(
+ ICorProfilerInfo4 * This,
+ /* [in] */ ClassID classId,
+ /* [in] */ mdFieldDef fieldToken,
+ /* [in] */ ThreadID threadId,
+ /* [out] */ void **ppAddress);
+
+ HRESULT ( STDMETHODCALLTYPE *GetContextStaticAddress )(
+ ICorProfilerInfo4 * This,
+ /* [in] */ ClassID classId,
+ /* [in] */ mdFieldDef fieldToken,
+ /* [in] */ ContextID contextId,
+ /* [out] */ void **ppAddress);
+
+ HRESULT ( STDMETHODCALLTYPE *GetStaticFieldInfo )(
+ ICorProfilerInfo4 * This,
+ /* [in] */ ClassID classId,
+ /* [in] */ mdFieldDef fieldToken,
+ /* [out] */ COR_PRF_STATIC_TYPE *pFieldInfo);
+
+ HRESULT ( STDMETHODCALLTYPE *GetGenerationBounds )(
+ ICorProfilerInfo4 * This,
+ /* [in] */ ULONG cObjectRanges,
+ /* [out] */ ULONG *pcObjectRanges,
+ /* [length_is][size_is][out] */ COR_PRF_GC_GENERATION_RANGE ranges[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetObjectGeneration )(
+ ICorProfilerInfo4 * This,
+ /* [in] */ ObjectID objectId,
+ /* [out] */ COR_PRF_GC_GENERATION_RANGE *range);
+
+ HRESULT ( STDMETHODCALLTYPE *GetNotifiedExceptionClauseInfo )(
+ ICorProfilerInfo4 * This,
+ /* [out] */ COR_PRF_EX_CLAUSE_INFO *pinfo);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumJITedFunctions )(
+ ICorProfilerInfo4 * This,
+ /* [out] */ ICorProfilerFunctionEnum **ppEnum);
+
+ HRESULT ( STDMETHODCALLTYPE *RequestProfilerDetach )(
+ ICorProfilerInfo4 * This,
+ /* [in] */ DWORD dwExpectedCompletionMilliseconds);
+
+ HRESULT ( STDMETHODCALLTYPE *SetFunctionIDMapper2 )(
+ ICorProfilerInfo4 * This,
+ /* [in] */ FunctionIDMapper2 *pFunc,
+ /* [in] */ void *clientData);
+
+ HRESULT ( STDMETHODCALLTYPE *GetStringLayout2 )(
+ ICorProfilerInfo4 * This,
+ /* [out] */ ULONG *pStringLengthOffset,
+ /* [out] */ ULONG *pBufferOffset);
+
+ HRESULT ( STDMETHODCALLTYPE *SetEnterLeaveFunctionHooks3 )(
+ ICorProfilerInfo4 * This,
+ /* [in] */ FunctionEnter3 *pFuncEnter3,
+ /* [in] */ FunctionLeave3 *pFuncLeave3,
+ /* [in] */ FunctionTailcall3 *pFuncTailcall3);
+
+ HRESULT ( STDMETHODCALLTYPE *SetEnterLeaveFunctionHooks3WithInfo )(
+ ICorProfilerInfo4 * This,
+ /* [in] */ FunctionEnter3WithInfo *pFuncEnter3WithInfo,
+ /* [in] */ FunctionLeave3WithInfo *pFuncLeave3WithInfo,
+ /* [in] */ FunctionTailcall3WithInfo *pFuncTailcall3WithInfo);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFunctionEnter3Info )(
+ ICorProfilerInfo4 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ COR_PRF_ELT_INFO eltInfo,
+ /* [out] */ COR_PRF_FRAME_INFO *pFrameInfo,
+ /* [out][in] */ ULONG *pcbArgumentInfo,
+ /* [size_is][out] */ COR_PRF_FUNCTION_ARGUMENT_INFO *pArgumentInfo);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFunctionLeave3Info )(
+ ICorProfilerInfo4 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ COR_PRF_ELT_INFO eltInfo,
+ /* [out] */ COR_PRF_FRAME_INFO *pFrameInfo,
+ /* [out] */ COR_PRF_FUNCTION_ARGUMENT_RANGE *pRetvalRange);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFunctionTailcall3Info )(
+ ICorProfilerInfo4 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ COR_PRF_ELT_INFO eltInfo,
+ /* [out] */ COR_PRF_FRAME_INFO *pFrameInfo);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumModules )(
+ ICorProfilerInfo4 * This,
+ /* [out] */ ICorProfilerModuleEnum **ppEnum);
+
+ HRESULT ( STDMETHODCALLTYPE *GetRuntimeInformation )(
+ ICorProfilerInfo4 * This,
+ /* [out] */ USHORT *pClrInstanceId,
+ /* [out] */ COR_PRF_RUNTIME_TYPE *pRuntimeType,
+ /* [out] */ USHORT *pMajorVersion,
+ /* [out] */ USHORT *pMinorVersion,
+ /* [out] */ USHORT *pBuildNumber,
+ /* [out] */ USHORT *pQFEVersion,
+ /* [in] */ ULONG cchVersionString,
+ /* [out] */ ULONG *pcchVersionString,
+ /* [annotation][out] */
+ _Out_writes_to_(cchVersionString, *pcchVersionString) WCHAR szVersionString[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetThreadStaticAddress2 )(
+ ICorProfilerInfo4 * This,
+ /* [in] */ ClassID classId,
+ /* [in] */ mdFieldDef fieldToken,
+ /* [in] */ AppDomainID appDomainId,
+ /* [in] */ ThreadID threadId,
+ /* [out] */ void **ppAddress);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAppDomainsContainingModule )(
+ ICorProfilerInfo4 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ ULONG32 cAppDomainIds,
+ /* [out] */ ULONG32 *pcAppDomainIds,
+ /* [length_is][size_is][out] */ AppDomainID appDomainIds[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetModuleInfo2 )(
+ ICorProfilerInfo4 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [out] */ LPCBYTE *ppBaseLoadAddress,
+ /* [in] */ ULONG cchName,
+ /* [out] */ ULONG *pcchName,
+ /* [annotation][out] */
+ _Out_writes_to_(cchName, *pcchName) WCHAR szName[ ],
+ /* [out] */ AssemblyID *pAssemblyId,
+ /* [out] */ DWORD *pdwModuleFlags);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumThreads )(
+ ICorProfilerInfo4 * This,
+ /* [out] */ ICorProfilerThreadEnum **ppEnum);
+
+ HRESULT ( STDMETHODCALLTYPE *InitializeCurrentThread )(
+ ICorProfilerInfo4 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *RequestReJIT )(
+ ICorProfilerInfo4 * This,
+ /* [in] */ ULONG cFunctions,
+ /* [size_is][in] */ ModuleID moduleIds[ ],
+ /* [size_is][in] */ mdMethodDef methodIds[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *RequestRevert )(
+ ICorProfilerInfo4 * This,
+ /* [in] */ ULONG cFunctions,
+ /* [size_is][in] */ ModuleID moduleIds[ ],
+ /* [size_is][in] */ mdMethodDef methodIds[ ],
+ /* [size_is][out] */ HRESULT status[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCodeInfo3 )(
+ ICorProfilerInfo4 * This,
+ /* [in] */ FunctionID functionID,
+ /* [in] */ ReJITID reJitId,
+ /* [in] */ ULONG32 cCodeInfos,
+ /* [out] */ ULONG32 *pcCodeInfos,
+ /* [length_is][size_is][out] */ COR_PRF_CODE_INFO codeInfos[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFunctionFromIP2 )(
+ ICorProfilerInfo4 * This,
+ /* [in] */ LPCBYTE ip,
+ /* [out] */ FunctionID *pFunctionId,
+ /* [out] */ ReJITID *pReJitId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetReJITIDs )(
+ ICorProfilerInfo4 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ ULONG cReJitIds,
+ /* [out] */ ULONG *pcReJitIds,
+ /* [length_is][size_is][out] */ ReJITID reJitIds[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetILToNativeMapping2 )(
+ ICorProfilerInfo4 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ ReJITID reJitId,
+ /* [in] */ ULONG32 cMap,
+ /* [out] */ ULONG32 *pcMap,
+ /* [length_is][size_is][out] */ COR_DEBUG_IL_TO_NATIVE_MAP map[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumJITedFunctions2 )(
+ ICorProfilerInfo4 * This,
+ /* [out] */ ICorProfilerFunctionEnum **ppEnum);
+
+ HRESULT ( STDMETHODCALLTYPE *GetObjectSize2 )(
+ ICorProfilerInfo4 * This,
+ /* [in] */ ObjectID objectId,
+ /* [out] */ SIZE_T *pcSize);
+
+ END_INTERFACE
+ } ICorProfilerInfo4Vtbl;
+
+ interface ICorProfilerInfo4
+ {
+ CONST_VTBL struct ICorProfilerInfo4Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorProfilerInfo4_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorProfilerInfo4_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorProfilerInfo4_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorProfilerInfo4_GetClassFromObject(This,objectId,pClassId) \
+ ( (This)->lpVtbl -> GetClassFromObject(This,objectId,pClassId) )
+
+#define ICorProfilerInfo4_GetClassFromToken(This,moduleId,typeDef,pClassId) \
+ ( (This)->lpVtbl -> GetClassFromToken(This,moduleId,typeDef,pClassId) )
+
+#define ICorProfilerInfo4_GetCodeInfo(This,functionId,pStart,pcSize) \
+ ( (This)->lpVtbl -> GetCodeInfo(This,functionId,pStart,pcSize) )
+
+#define ICorProfilerInfo4_GetEventMask(This,pdwEvents) \
+ ( (This)->lpVtbl -> GetEventMask(This,pdwEvents) )
+
+#define ICorProfilerInfo4_GetFunctionFromIP(This,ip,pFunctionId) \
+ ( (This)->lpVtbl -> GetFunctionFromIP(This,ip,pFunctionId) )
+
+#define ICorProfilerInfo4_GetFunctionFromToken(This,moduleId,token,pFunctionId) \
+ ( (This)->lpVtbl -> GetFunctionFromToken(This,moduleId,token,pFunctionId) )
+
+#define ICorProfilerInfo4_GetHandleFromThread(This,threadId,phThread) \
+ ( (This)->lpVtbl -> GetHandleFromThread(This,threadId,phThread) )
+
+#define ICorProfilerInfo4_GetObjectSize(This,objectId,pcSize) \
+ ( (This)->lpVtbl -> GetObjectSize(This,objectId,pcSize) )
+
+#define ICorProfilerInfo4_IsArrayClass(This,classId,pBaseElemType,pBaseClassId,pcRank) \
+ ( (This)->lpVtbl -> IsArrayClass(This,classId,pBaseElemType,pBaseClassId,pcRank) )
+
+#define ICorProfilerInfo4_GetThreadInfo(This,threadId,pdwWin32ThreadId) \
+ ( (This)->lpVtbl -> GetThreadInfo(This,threadId,pdwWin32ThreadId) )
+
+#define ICorProfilerInfo4_GetCurrentThreadID(This,pThreadId) \
+ ( (This)->lpVtbl -> GetCurrentThreadID(This,pThreadId) )
+
+#define ICorProfilerInfo4_GetClassIDInfo(This,classId,pModuleId,pTypeDefToken) \
+ ( (This)->lpVtbl -> GetClassIDInfo(This,classId,pModuleId,pTypeDefToken) )
+
+#define ICorProfilerInfo4_GetFunctionInfo(This,functionId,pClassId,pModuleId,pToken) \
+ ( (This)->lpVtbl -> GetFunctionInfo(This,functionId,pClassId,pModuleId,pToken) )
+
+#define ICorProfilerInfo4_SetEventMask(This,dwEvents) \
+ ( (This)->lpVtbl -> SetEventMask(This,dwEvents) )
+
+#define ICorProfilerInfo4_SetEnterLeaveFunctionHooks(This,pFuncEnter,pFuncLeave,pFuncTailcall) \
+ ( (This)->lpVtbl -> SetEnterLeaveFunctionHooks(This,pFuncEnter,pFuncLeave,pFuncTailcall) )
+
+#define ICorProfilerInfo4_SetFunctionIDMapper(This,pFunc) \
+ ( (This)->lpVtbl -> SetFunctionIDMapper(This,pFunc) )
+
+#define ICorProfilerInfo4_GetTokenAndMetaDataFromFunction(This,functionId,riid,ppImport,pToken) \
+ ( (This)->lpVtbl -> GetTokenAndMetaDataFromFunction(This,functionId,riid,ppImport,pToken) )
+
+#define ICorProfilerInfo4_GetModuleInfo(This,moduleId,ppBaseLoadAddress,cchName,pcchName,szName,pAssemblyId) \
+ ( (This)->lpVtbl -> GetModuleInfo(This,moduleId,ppBaseLoadAddress,cchName,pcchName,szName,pAssemblyId) )
+
+#define ICorProfilerInfo4_GetModuleMetaData(This,moduleId,dwOpenFlags,riid,ppOut) \
+ ( (This)->lpVtbl -> GetModuleMetaData(This,moduleId,dwOpenFlags,riid,ppOut) )
+
+#define ICorProfilerInfo4_GetILFunctionBody(This,moduleId,methodId,ppMethodHeader,pcbMethodSize) \
+ ( (This)->lpVtbl -> GetILFunctionBody(This,moduleId,methodId,ppMethodHeader,pcbMethodSize) )
+
+#define ICorProfilerInfo4_GetILFunctionBodyAllocator(This,moduleId,ppMalloc) \
+ ( (This)->lpVtbl -> GetILFunctionBodyAllocator(This,moduleId,ppMalloc) )
+
+#define ICorProfilerInfo4_SetILFunctionBody(This,moduleId,methodid,pbNewILMethodHeader) \
+ ( (This)->lpVtbl -> SetILFunctionBody(This,moduleId,methodid,pbNewILMethodHeader) )
+
+#define ICorProfilerInfo4_GetAppDomainInfo(This,appDomainId,cchName,pcchName,szName,pProcessId) \
+ ( (This)->lpVtbl -> GetAppDomainInfo(This,appDomainId,cchName,pcchName,szName,pProcessId) )
+
+#define ICorProfilerInfo4_GetAssemblyInfo(This,assemblyId,cchName,pcchName,szName,pAppDomainId,pModuleId) \
+ ( (This)->lpVtbl -> GetAssemblyInfo(This,assemblyId,cchName,pcchName,szName,pAppDomainId,pModuleId) )
+
+#define ICorProfilerInfo4_SetFunctionReJIT(This,functionId) \
+ ( (This)->lpVtbl -> SetFunctionReJIT(This,functionId) )
+
+#define ICorProfilerInfo4_ForceGC(This) \
+ ( (This)->lpVtbl -> ForceGC(This) )
+
+#define ICorProfilerInfo4_SetILInstrumentedCodeMap(This,functionId,fStartJit,cILMapEntries,rgILMapEntries) \
+ ( (This)->lpVtbl -> SetILInstrumentedCodeMap(This,functionId,fStartJit,cILMapEntries,rgILMapEntries) )
+
+#define ICorProfilerInfo4_GetInprocInspectionInterface(This,ppicd) \
+ ( (This)->lpVtbl -> GetInprocInspectionInterface(This,ppicd) )
+
+#define ICorProfilerInfo4_GetInprocInspectionIThisThread(This,ppicd) \
+ ( (This)->lpVtbl -> GetInprocInspectionIThisThread(This,ppicd) )
+
+#define ICorProfilerInfo4_GetThreadContext(This,threadId,pContextId) \
+ ( (This)->lpVtbl -> GetThreadContext(This,threadId,pContextId) )
+
+#define ICorProfilerInfo4_BeginInprocDebugging(This,fThisThreadOnly,pdwProfilerContext) \
+ ( (This)->lpVtbl -> BeginInprocDebugging(This,fThisThreadOnly,pdwProfilerContext) )
+
+#define ICorProfilerInfo4_EndInprocDebugging(This,dwProfilerContext) \
+ ( (This)->lpVtbl -> EndInprocDebugging(This,dwProfilerContext) )
+
+#define ICorProfilerInfo4_GetILToNativeMapping(This,functionId,cMap,pcMap,map) \
+ ( (This)->lpVtbl -> GetILToNativeMapping(This,functionId,cMap,pcMap,map) )
+
+
+#define ICorProfilerInfo4_DoStackSnapshot(This,thread,callback,infoFlags,clientData,context,contextSize) \
+ ( (This)->lpVtbl -> DoStackSnapshot(This,thread,callback,infoFlags,clientData,context,contextSize) )
+
+#define ICorProfilerInfo4_SetEnterLeaveFunctionHooks2(This,pFuncEnter,pFuncLeave,pFuncTailcall) \
+ ( (This)->lpVtbl -> SetEnterLeaveFunctionHooks2(This,pFuncEnter,pFuncLeave,pFuncTailcall) )
+
+#define ICorProfilerInfo4_GetFunctionInfo2(This,funcId,frameInfo,pClassId,pModuleId,pToken,cTypeArgs,pcTypeArgs,typeArgs) \
+ ( (This)->lpVtbl -> GetFunctionInfo2(This,funcId,frameInfo,pClassId,pModuleId,pToken,cTypeArgs,pcTypeArgs,typeArgs) )
+
+#define ICorProfilerInfo4_GetStringLayout(This,pBufferLengthOffset,pStringLengthOffset,pBufferOffset) \
+ ( (This)->lpVtbl -> GetStringLayout(This,pBufferLengthOffset,pStringLengthOffset,pBufferOffset) )
+
+#define ICorProfilerInfo4_GetClassLayout(This,classID,rFieldOffset,cFieldOffset,pcFieldOffset,pulClassSize) \
+ ( (This)->lpVtbl -> GetClassLayout(This,classID,rFieldOffset,cFieldOffset,pcFieldOffset,pulClassSize) )
+
+#define ICorProfilerInfo4_GetClassIDInfo2(This,classId,pModuleId,pTypeDefToken,pParentClassId,cNumTypeArgs,pcNumTypeArgs,typeArgs) \
+ ( (This)->lpVtbl -> GetClassIDInfo2(This,classId,pModuleId,pTypeDefToken,pParentClassId,cNumTypeArgs,pcNumTypeArgs,typeArgs) )
+
+#define ICorProfilerInfo4_GetCodeInfo2(This,functionID,cCodeInfos,pcCodeInfos,codeInfos) \
+ ( (This)->lpVtbl -> GetCodeInfo2(This,functionID,cCodeInfos,pcCodeInfos,codeInfos) )
+
+#define ICorProfilerInfo4_GetClassFromTokenAndTypeArgs(This,moduleID,typeDef,cTypeArgs,typeArgs,pClassID) \
+ ( (This)->lpVtbl -> GetClassFromTokenAndTypeArgs(This,moduleID,typeDef,cTypeArgs,typeArgs,pClassID) )
+
+#define ICorProfilerInfo4_GetFunctionFromTokenAndTypeArgs(This,moduleID,funcDef,classId,cTypeArgs,typeArgs,pFunctionID) \
+ ( (This)->lpVtbl -> GetFunctionFromTokenAndTypeArgs(This,moduleID,funcDef,classId,cTypeArgs,typeArgs,pFunctionID) )
+
+#define ICorProfilerInfo4_EnumModuleFrozenObjects(This,moduleID,ppEnum) \
+ ( (This)->lpVtbl -> EnumModuleFrozenObjects(This,moduleID,ppEnum) )
+
+#define ICorProfilerInfo4_GetArrayObjectInfo(This,objectId,cDimensions,pDimensionSizes,pDimensionLowerBounds,ppData) \
+ ( (This)->lpVtbl -> GetArrayObjectInfo(This,objectId,cDimensions,pDimensionSizes,pDimensionLowerBounds,ppData) )
+
+#define ICorProfilerInfo4_GetBoxClassLayout(This,classId,pBufferOffset) \
+ ( (This)->lpVtbl -> GetBoxClassLayout(This,classId,pBufferOffset) )
+
+#define ICorProfilerInfo4_GetThreadAppDomain(This,threadId,pAppDomainId) \
+ ( (This)->lpVtbl -> GetThreadAppDomain(This,threadId,pAppDomainId) )
+
+#define ICorProfilerInfo4_GetRVAStaticAddress(This,classId,fieldToken,ppAddress) \
+ ( (This)->lpVtbl -> GetRVAStaticAddress(This,classId,fieldToken,ppAddress) )
+
+#define ICorProfilerInfo4_GetAppDomainStaticAddress(This,classId,fieldToken,appDomainId,ppAddress) \
+ ( (This)->lpVtbl -> GetAppDomainStaticAddress(This,classId,fieldToken,appDomainId,ppAddress) )
+
+#define ICorProfilerInfo4_GetThreadStaticAddress(This,classId,fieldToken,threadId,ppAddress) \
+ ( (This)->lpVtbl -> GetThreadStaticAddress(This,classId,fieldToken,threadId,ppAddress) )
+
+#define ICorProfilerInfo4_GetContextStaticAddress(This,classId,fieldToken,contextId,ppAddress) \
+ ( (This)->lpVtbl -> GetContextStaticAddress(This,classId,fieldToken,contextId,ppAddress) )
+
+#define ICorProfilerInfo4_GetStaticFieldInfo(This,classId,fieldToken,pFieldInfo) \
+ ( (This)->lpVtbl -> GetStaticFieldInfo(This,classId,fieldToken,pFieldInfo) )
+
+#define ICorProfilerInfo4_GetGenerationBounds(This,cObjectRanges,pcObjectRanges,ranges) \
+ ( (This)->lpVtbl -> GetGenerationBounds(This,cObjectRanges,pcObjectRanges,ranges) )
+
+#define ICorProfilerInfo4_GetObjectGeneration(This,objectId,range) \
+ ( (This)->lpVtbl -> GetObjectGeneration(This,objectId,range) )
+
+#define ICorProfilerInfo4_GetNotifiedExceptionClauseInfo(This,pinfo) \
+ ( (This)->lpVtbl -> GetNotifiedExceptionClauseInfo(This,pinfo) )
+
+
+#define ICorProfilerInfo4_EnumJITedFunctions(This,ppEnum) \
+ ( (This)->lpVtbl -> EnumJITedFunctions(This,ppEnum) )
+
+#define ICorProfilerInfo4_RequestProfilerDetach(This,dwExpectedCompletionMilliseconds) \
+ ( (This)->lpVtbl -> RequestProfilerDetach(This,dwExpectedCompletionMilliseconds) )
+
+#define ICorProfilerInfo4_SetFunctionIDMapper2(This,pFunc,clientData) \
+ ( (This)->lpVtbl -> SetFunctionIDMapper2(This,pFunc,clientData) )
+
+#define ICorProfilerInfo4_GetStringLayout2(This,pStringLengthOffset,pBufferOffset) \
+ ( (This)->lpVtbl -> GetStringLayout2(This,pStringLengthOffset,pBufferOffset) )
+
+#define ICorProfilerInfo4_SetEnterLeaveFunctionHooks3(This,pFuncEnter3,pFuncLeave3,pFuncTailcall3) \
+ ( (This)->lpVtbl -> SetEnterLeaveFunctionHooks3(This,pFuncEnter3,pFuncLeave3,pFuncTailcall3) )
+
+#define ICorProfilerInfo4_SetEnterLeaveFunctionHooks3WithInfo(This,pFuncEnter3WithInfo,pFuncLeave3WithInfo,pFuncTailcall3WithInfo) \
+ ( (This)->lpVtbl -> SetEnterLeaveFunctionHooks3WithInfo(This,pFuncEnter3WithInfo,pFuncLeave3WithInfo,pFuncTailcall3WithInfo) )
+
+#define ICorProfilerInfo4_GetFunctionEnter3Info(This,functionId,eltInfo,pFrameInfo,pcbArgumentInfo,pArgumentInfo) \
+ ( (This)->lpVtbl -> GetFunctionEnter3Info(This,functionId,eltInfo,pFrameInfo,pcbArgumentInfo,pArgumentInfo) )
+
+#define ICorProfilerInfo4_GetFunctionLeave3Info(This,functionId,eltInfo,pFrameInfo,pRetvalRange) \
+ ( (This)->lpVtbl -> GetFunctionLeave3Info(This,functionId,eltInfo,pFrameInfo,pRetvalRange) )
+
+#define ICorProfilerInfo4_GetFunctionTailcall3Info(This,functionId,eltInfo,pFrameInfo) \
+ ( (This)->lpVtbl -> GetFunctionTailcall3Info(This,functionId,eltInfo,pFrameInfo) )
+
+#define ICorProfilerInfo4_EnumModules(This,ppEnum) \
+ ( (This)->lpVtbl -> EnumModules(This,ppEnum) )
+
+#define ICorProfilerInfo4_GetRuntimeInformation(This,pClrInstanceId,pRuntimeType,pMajorVersion,pMinorVersion,pBuildNumber,pQFEVersion,cchVersionString,pcchVersionString,szVersionString) \
+ ( (This)->lpVtbl -> GetRuntimeInformation(This,pClrInstanceId,pRuntimeType,pMajorVersion,pMinorVersion,pBuildNumber,pQFEVersion,cchVersionString,pcchVersionString,szVersionString) )
+
+#define ICorProfilerInfo4_GetThreadStaticAddress2(This,classId,fieldToken,appDomainId,threadId,ppAddress) \
+ ( (This)->lpVtbl -> GetThreadStaticAddress2(This,classId,fieldToken,appDomainId,threadId,ppAddress) )
+
+#define ICorProfilerInfo4_GetAppDomainsContainingModule(This,moduleId,cAppDomainIds,pcAppDomainIds,appDomainIds) \
+ ( (This)->lpVtbl -> GetAppDomainsContainingModule(This,moduleId,cAppDomainIds,pcAppDomainIds,appDomainIds) )
+
+#define ICorProfilerInfo4_GetModuleInfo2(This,moduleId,ppBaseLoadAddress,cchName,pcchName,szName,pAssemblyId,pdwModuleFlags) \
+ ( (This)->lpVtbl -> GetModuleInfo2(This,moduleId,ppBaseLoadAddress,cchName,pcchName,szName,pAssemblyId,pdwModuleFlags) )
+
+
+#define ICorProfilerInfo4_EnumThreads(This,ppEnum) \
+ ( (This)->lpVtbl -> EnumThreads(This,ppEnum) )
+
+#define ICorProfilerInfo4_InitializeCurrentThread(This) \
+ ( (This)->lpVtbl -> InitializeCurrentThread(This) )
+
+#define ICorProfilerInfo4_RequestReJIT(This,cFunctions,moduleIds,methodIds) \
+ ( (This)->lpVtbl -> RequestReJIT(This,cFunctions,moduleIds,methodIds) )
+
+#define ICorProfilerInfo4_RequestRevert(This,cFunctions,moduleIds,methodIds,status) \
+ ( (This)->lpVtbl -> RequestRevert(This,cFunctions,moduleIds,methodIds,status) )
+
+#define ICorProfilerInfo4_GetCodeInfo3(This,functionID,reJitId,cCodeInfos,pcCodeInfos,codeInfos) \
+ ( (This)->lpVtbl -> GetCodeInfo3(This,functionID,reJitId,cCodeInfos,pcCodeInfos,codeInfos) )
+
+#define ICorProfilerInfo4_GetFunctionFromIP2(This,ip,pFunctionId,pReJitId) \
+ ( (This)->lpVtbl -> GetFunctionFromIP2(This,ip,pFunctionId,pReJitId) )
+
+#define ICorProfilerInfo4_GetReJITIDs(This,functionId,cReJitIds,pcReJitIds,reJitIds) \
+ ( (This)->lpVtbl -> GetReJITIDs(This,functionId,cReJitIds,pcReJitIds,reJitIds) )
+
+#define ICorProfilerInfo4_GetILToNativeMapping2(This,functionId,reJitId,cMap,pcMap,map) \
+ ( (This)->lpVtbl -> GetILToNativeMapping2(This,functionId,reJitId,cMap,pcMap,map) )
+
+#define ICorProfilerInfo4_EnumJITedFunctions2(This,ppEnum) \
+ ( (This)->lpVtbl -> EnumJITedFunctions2(This,ppEnum) )
+
+#define ICorProfilerInfo4_GetObjectSize2(This,objectId,pcSize) \
+ ( (This)->lpVtbl -> GetObjectSize2(This,objectId,pcSize) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorProfilerInfo4_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorProfilerInfo5_INTERFACE_DEFINED__
+#define __ICorProfilerInfo5_INTERFACE_DEFINED__
+
+/* interface ICorProfilerInfo5 */
+/* [local][unique][uuid][object] */
+
+
+EXTERN_C const IID IID_ICorProfilerInfo5;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("07602928-CE38-4B83-81E7-74ADAF781214")
+ ICorProfilerInfo5 : public ICorProfilerInfo4
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetEventMask2(
+ /* [out] */ DWORD *pdwEventsLow,
+ /* [out] */ DWORD *pdwEventsHigh) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetEventMask2(
+ /* [in] */ DWORD dwEventsLow,
+ /* [in] */ DWORD dwEventsHigh) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorProfilerInfo5Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorProfilerInfo5 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorProfilerInfo5 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorProfilerInfo5 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetClassFromObject )(
+ ICorProfilerInfo5 * This,
+ /* [in] */ ObjectID objectId,
+ /* [out] */ ClassID *pClassId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetClassFromToken )(
+ ICorProfilerInfo5 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ mdTypeDef typeDef,
+ /* [out] */ ClassID *pClassId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCodeInfo )(
+ ICorProfilerInfo5 * This,
+ /* [in] */ FunctionID functionId,
+ /* [out] */ LPCBYTE *pStart,
+ /* [out] */ ULONG *pcSize);
+
+ HRESULT ( STDMETHODCALLTYPE *GetEventMask )(
+ ICorProfilerInfo5 * This,
+ /* [out] */ DWORD *pdwEvents);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFunctionFromIP )(
+ ICorProfilerInfo5 * This,
+ /* [in] */ LPCBYTE ip,
+ /* [out] */ FunctionID *pFunctionId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFunctionFromToken )(
+ ICorProfilerInfo5 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ mdToken token,
+ /* [out] */ FunctionID *pFunctionId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetHandleFromThread )(
+ ICorProfilerInfo5 * This,
+ /* [in] */ ThreadID threadId,
+ /* [out] */ HANDLE *phThread);
+
+ HRESULT ( STDMETHODCALLTYPE *GetObjectSize )(
+ ICorProfilerInfo5 * This,
+ /* [in] */ ObjectID objectId,
+ /* [out] */ ULONG *pcSize);
+
+ HRESULT ( STDMETHODCALLTYPE *IsArrayClass )(
+ ICorProfilerInfo5 * This,
+ /* [in] */ ClassID classId,
+ /* [out] */ CorElementType *pBaseElemType,
+ /* [out] */ ClassID *pBaseClassId,
+ /* [out] */ ULONG *pcRank);
+
+ HRESULT ( STDMETHODCALLTYPE *GetThreadInfo )(
+ ICorProfilerInfo5 * This,
+ /* [in] */ ThreadID threadId,
+ /* [out] */ DWORD *pdwWin32ThreadId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCurrentThreadID )(
+ ICorProfilerInfo5 * This,
+ /* [out] */ ThreadID *pThreadId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetClassIDInfo )(
+ ICorProfilerInfo5 * This,
+ /* [in] */ ClassID classId,
+ /* [out] */ ModuleID *pModuleId,
+ /* [out] */ mdTypeDef *pTypeDefToken);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFunctionInfo )(
+ ICorProfilerInfo5 * This,
+ /* [in] */ FunctionID functionId,
+ /* [out] */ ClassID *pClassId,
+ /* [out] */ ModuleID *pModuleId,
+ /* [out] */ mdToken *pToken);
+
+ HRESULT ( STDMETHODCALLTYPE *SetEventMask )(
+ ICorProfilerInfo5 * This,
+ /* [in] */ DWORD dwEvents);
+
+ HRESULT ( STDMETHODCALLTYPE *SetEnterLeaveFunctionHooks )(
+ ICorProfilerInfo5 * This,
+ /* [in] */ FunctionEnter *pFuncEnter,
+ /* [in] */ FunctionLeave *pFuncLeave,
+ /* [in] */ FunctionTailcall *pFuncTailcall);
+
+ HRESULT ( STDMETHODCALLTYPE *SetFunctionIDMapper )(
+ ICorProfilerInfo5 * This,
+ /* [in] */ FunctionIDMapper *pFunc);
+
+ HRESULT ( STDMETHODCALLTYPE *GetTokenAndMetaDataFromFunction )(
+ ICorProfilerInfo5 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ REFIID riid,
+ /* [out] */ IUnknown **ppImport,
+ /* [out] */ mdToken *pToken);
+
+ HRESULT ( STDMETHODCALLTYPE *GetModuleInfo )(
+ ICorProfilerInfo5 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [out] */ LPCBYTE *ppBaseLoadAddress,
+ /* [in] */ ULONG cchName,
+ /* [out] */ ULONG *pcchName,
+ /* [annotation][out] */
+ _Out_writes_to_(cchName, *pcchName) WCHAR szName[ ],
+ /* [out] */ AssemblyID *pAssemblyId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetModuleMetaData )(
+ ICorProfilerInfo5 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ DWORD dwOpenFlags,
+ /* [in] */ REFIID riid,
+ /* [out] */ IUnknown **ppOut);
+
+ HRESULT ( STDMETHODCALLTYPE *GetILFunctionBody )(
+ ICorProfilerInfo5 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ mdMethodDef methodId,
+ /* [out] */ LPCBYTE *ppMethodHeader,
+ /* [out] */ ULONG *pcbMethodSize);
+
+ HRESULT ( STDMETHODCALLTYPE *GetILFunctionBodyAllocator )(
+ ICorProfilerInfo5 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [out] */ IMethodMalloc **ppMalloc);
+
+ HRESULT ( STDMETHODCALLTYPE *SetILFunctionBody )(
+ ICorProfilerInfo5 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ mdMethodDef methodid,
+ /* [in] */ LPCBYTE pbNewILMethodHeader);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAppDomainInfo )(
+ ICorProfilerInfo5 * This,
+ /* [in] */ AppDomainID appDomainId,
+ /* [in] */ ULONG cchName,
+ /* [out] */ ULONG *pcchName,
+ /* [annotation][out] */
+ _Out_writes_to_(cchName, *pcchName) WCHAR szName[ ],
+ /* [out] */ ProcessID *pProcessId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAssemblyInfo )(
+ ICorProfilerInfo5 * This,
+ /* [in] */ AssemblyID assemblyId,
+ /* [in] */ ULONG cchName,
+ /* [out] */ ULONG *pcchName,
+ /* [annotation][out] */
+ _Out_writes_to_(cchName, *pcchName) WCHAR szName[ ],
+ /* [out] */ AppDomainID *pAppDomainId,
+ /* [out] */ ModuleID *pModuleId);
+
+ HRESULT ( STDMETHODCALLTYPE *SetFunctionReJIT )(
+ ICorProfilerInfo5 * This,
+ /* [in] */ FunctionID functionId);
+
+ HRESULT ( STDMETHODCALLTYPE *ForceGC )(
+ ICorProfilerInfo5 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *SetILInstrumentedCodeMap )(
+ ICorProfilerInfo5 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ BOOL fStartJit,
+ /* [in] */ ULONG cILMapEntries,
+ /* [size_is][in] */ COR_IL_MAP rgILMapEntries[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetInprocInspectionInterface )(
+ ICorProfilerInfo5 * This,
+ /* [out] */ IUnknown **ppicd);
+
+ HRESULT ( STDMETHODCALLTYPE *GetInprocInspectionIThisThread )(
+ ICorProfilerInfo5 * This,
+ /* [out] */ IUnknown **ppicd);
+
+ HRESULT ( STDMETHODCALLTYPE *GetThreadContext )(
+ ICorProfilerInfo5 * This,
+ /* [in] */ ThreadID threadId,
+ /* [out] */ ContextID *pContextId);
+
+ HRESULT ( STDMETHODCALLTYPE *BeginInprocDebugging )(
+ ICorProfilerInfo5 * This,
+ /* [in] */ BOOL fThisThreadOnly,
+ /* [out] */ DWORD *pdwProfilerContext);
+
+ HRESULT ( STDMETHODCALLTYPE *EndInprocDebugging )(
+ ICorProfilerInfo5 * This,
+ /* [in] */ DWORD dwProfilerContext);
+
+ HRESULT ( STDMETHODCALLTYPE *GetILToNativeMapping )(
+ ICorProfilerInfo5 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ ULONG32 cMap,
+ /* [out] */ ULONG32 *pcMap,
+ /* [length_is][size_is][out] */ COR_DEBUG_IL_TO_NATIVE_MAP map[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *DoStackSnapshot )(
+ ICorProfilerInfo5 * This,
+ /* [in] */ ThreadID thread,
+ /* [in] */ StackSnapshotCallback *callback,
+ /* [in] */ ULONG32 infoFlags,
+ /* [in] */ void *clientData,
+ /* [size_is][in] */ BYTE context[ ],
+ /* [in] */ ULONG32 contextSize);
+
+ HRESULT ( STDMETHODCALLTYPE *SetEnterLeaveFunctionHooks2 )(
+ ICorProfilerInfo5 * This,
+ /* [in] */ FunctionEnter2 *pFuncEnter,
+ /* [in] */ FunctionLeave2 *pFuncLeave,
+ /* [in] */ FunctionTailcall2 *pFuncTailcall);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFunctionInfo2 )(
+ ICorProfilerInfo5 * This,
+ /* [in] */ FunctionID funcId,
+ /* [in] */ COR_PRF_FRAME_INFO frameInfo,
+ /* [out] */ ClassID *pClassId,
+ /* [out] */ ModuleID *pModuleId,
+ /* [out] */ mdToken *pToken,
+ /* [in] */ ULONG32 cTypeArgs,
+ /* [out] */ ULONG32 *pcTypeArgs,
+ /* [out] */ ClassID typeArgs[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetStringLayout )(
+ ICorProfilerInfo5 * This,
+ /* [out] */ ULONG *pBufferLengthOffset,
+ /* [out] */ ULONG *pStringLengthOffset,
+ /* [out] */ ULONG *pBufferOffset);
+
+ HRESULT ( STDMETHODCALLTYPE *GetClassLayout )(
+ ICorProfilerInfo5 * This,
+ /* [in] */ ClassID classID,
+ /* [out][in] */ COR_FIELD_OFFSET rFieldOffset[ ],
+ /* [in] */ ULONG cFieldOffset,
+ /* [out] */ ULONG *pcFieldOffset,
+ /* [out] */ ULONG *pulClassSize);
+
+ HRESULT ( STDMETHODCALLTYPE *GetClassIDInfo2 )(
+ ICorProfilerInfo5 * This,
+ /* [in] */ ClassID classId,
+ /* [out] */ ModuleID *pModuleId,
+ /* [out] */ mdTypeDef *pTypeDefToken,
+ /* [out] */ ClassID *pParentClassId,
+ /* [in] */ ULONG32 cNumTypeArgs,
+ /* [out] */ ULONG32 *pcNumTypeArgs,
+ /* [out] */ ClassID typeArgs[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCodeInfo2 )(
+ ICorProfilerInfo5 * This,
+ /* [in] */ FunctionID functionID,
+ /* [in] */ ULONG32 cCodeInfos,
+ /* [out] */ ULONG32 *pcCodeInfos,
+ /* [length_is][size_is][out] */ COR_PRF_CODE_INFO codeInfos[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetClassFromTokenAndTypeArgs )(
+ ICorProfilerInfo5 * This,
+ /* [in] */ ModuleID moduleID,
+ /* [in] */ mdTypeDef typeDef,
+ /* [in] */ ULONG32 cTypeArgs,
+ /* [size_is][in] */ ClassID typeArgs[ ],
+ /* [out] */ ClassID *pClassID);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFunctionFromTokenAndTypeArgs )(
+ ICorProfilerInfo5 * This,
+ /* [in] */ ModuleID moduleID,
+ /* [in] */ mdMethodDef funcDef,
+ /* [in] */ ClassID classId,
+ /* [in] */ ULONG32 cTypeArgs,
+ /* [size_is][in] */ ClassID typeArgs[ ],
+ /* [out] */ FunctionID *pFunctionID);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumModuleFrozenObjects )(
+ ICorProfilerInfo5 * This,
+ /* [in] */ ModuleID moduleID,
+ /* [out] */ ICorProfilerObjectEnum **ppEnum);
+
+ HRESULT ( STDMETHODCALLTYPE *GetArrayObjectInfo )(
+ ICorProfilerInfo5 * This,
+ /* [in] */ ObjectID objectId,
+ /* [in] */ ULONG32 cDimensions,
+ /* [size_is][out] */ ULONG32 pDimensionSizes[ ],
+ /* [size_is][out] */ int pDimensionLowerBounds[ ],
+ /* [out] */ BYTE **ppData);
+
+ HRESULT ( STDMETHODCALLTYPE *GetBoxClassLayout )(
+ ICorProfilerInfo5 * This,
+ /* [in] */ ClassID classId,
+ /* [out] */ ULONG32 *pBufferOffset);
+
+ HRESULT ( STDMETHODCALLTYPE *GetThreadAppDomain )(
+ ICorProfilerInfo5 * This,
+ /* [in] */ ThreadID threadId,
+ /* [out] */ AppDomainID *pAppDomainId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetRVAStaticAddress )(
+ ICorProfilerInfo5 * This,
+ /* [in] */ ClassID classId,
+ /* [in] */ mdFieldDef fieldToken,
+ /* [out] */ void **ppAddress);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAppDomainStaticAddress )(
+ ICorProfilerInfo5 * This,
+ /* [in] */ ClassID classId,
+ /* [in] */ mdFieldDef fieldToken,
+ /* [in] */ AppDomainID appDomainId,
+ /* [out] */ void **ppAddress);
+
+ HRESULT ( STDMETHODCALLTYPE *GetThreadStaticAddress )(
+ ICorProfilerInfo5 * This,
+ /* [in] */ ClassID classId,
+ /* [in] */ mdFieldDef fieldToken,
+ /* [in] */ ThreadID threadId,
+ /* [out] */ void **ppAddress);
+
+ HRESULT ( STDMETHODCALLTYPE *GetContextStaticAddress )(
+ ICorProfilerInfo5 * This,
+ /* [in] */ ClassID classId,
+ /* [in] */ mdFieldDef fieldToken,
+ /* [in] */ ContextID contextId,
+ /* [out] */ void **ppAddress);
+
+ HRESULT ( STDMETHODCALLTYPE *GetStaticFieldInfo )(
+ ICorProfilerInfo5 * This,
+ /* [in] */ ClassID classId,
+ /* [in] */ mdFieldDef fieldToken,
+ /* [out] */ COR_PRF_STATIC_TYPE *pFieldInfo);
+
+ HRESULT ( STDMETHODCALLTYPE *GetGenerationBounds )(
+ ICorProfilerInfo5 * This,
+ /* [in] */ ULONG cObjectRanges,
+ /* [out] */ ULONG *pcObjectRanges,
+ /* [length_is][size_is][out] */ COR_PRF_GC_GENERATION_RANGE ranges[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetObjectGeneration )(
+ ICorProfilerInfo5 * This,
+ /* [in] */ ObjectID objectId,
+ /* [out] */ COR_PRF_GC_GENERATION_RANGE *range);
+
+ HRESULT ( STDMETHODCALLTYPE *GetNotifiedExceptionClauseInfo )(
+ ICorProfilerInfo5 * This,
+ /* [out] */ COR_PRF_EX_CLAUSE_INFO *pinfo);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumJITedFunctions )(
+ ICorProfilerInfo5 * This,
+ /* [out] */ ICorProfilerFunctionEnum **ppEnum);
+
+ HRESULT ( STDMETHODCALLTYPE *RequestProfilerDetach )(
+ ICorProfilerInfo5 * This,
+ /* [in] */ DWORD dwExpectedCompletionMilliseconds);
+
+ HRESULT ( STDMETHODCALLTYPE *SetFunctionIDMapper2 )(
+ ICorProfilerInfo5 * This,
+ /* [in] */ FunctionIDMapper2 *pFunc,
+ /* [in] */ void *clientData);
+
+ HRESULT ( STDMETHODCALLTYPE *GetStringLayout2 )(
+ ICorProfilerInfo5 * This,
+ /* [out] */ ULONG *pStringLengthOffset,
+ /* [out] */ ULONG *pBufferOffset);
+
+ HRESULT ( STDMETHODCALLTYPE *SetEnterLeaveFunctionHooks3 )(
+ ICorProfilerInfo5 * This,
+ /* [in] */ FunctionEnter3 *pFuncEnter3,
+ /* [in] */ FunctionLeave3 *pFuncLeave3,
+ /* [in] */ FunctionTailcall3 *pFuncTailcall3);
+
+ HRESULT ( STDMETHODCALLTYPE *SetEnterLeaveFunctionHooks3WithInfo )(
+ ICorProfilerInfo5 * This,
+ /* [in] */ FunctionEnter3WithInfo *pFuncEnter3WithInfo,
+ /* [in] */ FunctionLeave3WithInfo *pFuncLeave3WithInfo,
+ /* [in] */ FunctionTailcall3WithInfo *pFuncTailcall3WithInfo);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFunctionEnter3Info )(
+ ICorProfilerInfo5 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ COR_PRF_ELT_INFO eltInfo,
+ /* [out] */ COR_PRF_FRAME_INFO *pFrameInfo,
+ /* [out][in] */ ULONG *pcbArgumentInfo,
+ /* [size_is][out] */ COR_PRF_FUNCTION_ARGUMENT_INFO *pArgumentInfo);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFunctionLeave3Info )(
+ ICorProfilerInfo5 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ COR_PRF_ELT_INFO eltInfo,
+ /* [out] */ COR_PRF_FRAME_INFO *pFrameInfo,
+ /* [out] */ COR_PRF_FUNCTION_ARGUMENT_RANGE *pRetvalRange);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFunctionTailcall3Info )(
+ ICorProfilerInfo5 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ COR_PRF_ELT_INFO eltInfo,
+ /* [out] */ COR_PRF_FRAME_INFO *pFrameInfo);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumModules )(
+ ICorProfilerInfo5 * This,
+ /* [out] */ ICorProfilerModuleEnum **ppEnum);
+
+ HRESULT ( STDMETHODCALLTYPE *GetRuntimeInformation )(
+ ICorProfilerInfo5 * This,
+ /* [out] */ USHORT *pClrInstanceId,
+ /* [out] */ COR_PRF_RUNTIME_TYPE *pRuntimeType,
+ /* [out] */ USHORT *pMajorVersion,
+ /* [out] */ USHORT *pMinorVersion,
+ /* [out] */ USHORT *pBuildNumber,
+ /* [out] */ USHORT *pQFEVersion,
+ /* [in] */ ULONG cchVersionString,
+ /* [out] */ ULONG *pcchVersionString,
+ /* [annotation][out] */
+ _Out_writes_to_(cchVersionString, *pcchVersionString) WCHAR szVersionString[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetThreadStaticAddress2 )(
+ ICorProfilerInfo5 * This,
+ /* [in] */ ClassID classId,
+ /* [in] */ mdFieldDef fieldToken,
+ /* [in] */ AppDomainID appDomainId,
+ /* [in] */ ThreadID threadId,
+ /* [out] */ void **ppAddress);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAppDomainsContainingModule )(
+ ICorProfilerInfo5 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ ULONG32 cAppDomainIds,
+ /* [out] */ ULONG32 *pcAppDomainIds,
+ /* [length_is][size_is][out] */ AppDomainID appDomainIds[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetModuleInfo2 )(
+ ICorProfilerInfo5 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [out] */ LPCBYTE *ppBaseLoadAddress,
+ /* [in] */ ULONG cchName,
+ /* [out] */ ULONG *pcchName,
+ /* [annotation][out] */
+ _Out_writes_to_(cchName, *pcchName) WCHAR szName[ ],
+ /* [out] */ AssemblyID *pAssemblyId,
+ /* [out] */ DWORD *pdwModuleFlags);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumThreads )(
+ ICorProfilerInfo5 * This,
+ /* [out] */ ICorProfilerThreadEnum **ppEnum);
+
+ HRESULT ( STDMETHODCALLTYPE *InitializeCurrentThread )(
+ ICorProfilerInfo5 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *RequestReJIT )(
+ ICorProfilerInfo5 * This,
+ /* [in] */ ULONG cFunctions,
+ /* [size_is][in] */ ModuleID moduleIds[ ],
+ /* [size_is][in] */ mdMethodDef methodIds[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *RequestRevert )(
+ ICorProfilerInfo5 * This,
+ /* [in] */ ULONG cFunctions,
+ /* [size_is][in] */ ModuleID moduleIds[ ],
+ /* [size_is][in] */ mdMethodDef methodIds[ ],
+ /* [size_is][out] */ HRESULT status[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCodeInfo3 )(
+ ICorProfilerInfo5 * This,
+ /* [in] */ FunctionID functionID,
+ /* [in] */ ReJITID reJitId,
+ /* [in] */ ULONG32 cCodeInfos,
+ /* [out] */ ULONG32 *pcCodeInfos,
+ /* [length_is][size_is][out] */ COR_PRF_CODE_INFO codeInfos[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFunctionFromIP2 )(
+ ICorProfilerInfo5 * This,
+ /* [in] */ LPCBYTE ip,
+ /* [out] */ FunctionID *pFunctionId,
+ /* [out] */ ReJITID *pReJitId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetReJITIDs )(
+ ICorProfilerInfo5 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ ULONG cReJitIds,
+ /* [out] */ ULONG *pcReJitIds,
+ /* [length_is][size_is][out] */ ReJITID reJitIds[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetILToNativeMapping2 )(
+ ICorProfilerInfo5 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ ReJITID reJitId,
+ /* [in] */ ULONG32 cMap,
+ /* [out] */ ULONG32 *pcMap,
+ /* [length_is][size_is][out] */ COR_DEBUG_IL_TO_NATIVE_MAP map[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumJITedFunctions2 )(
+ ICorProfilerInfo5 * This,
+ /* [out] */ ICorProfilerFunctionEnum **ppEnum);
+
+ HRESULT ( STDMETHODCALLTYPE *GetObjectSize2 )(
+ ICorProfilerInfo5 * This,
+ /* [in] */ ObjectID objectId,
+ /* [out] */ SIZE_T *pcSize);
+
+ HRESULT ( STDMETHODCALLTYPE *GetEventMask2 )(
+ ICorProfilerInfo5 * This,
+ /* [out] */ DWORD *pdwEventsLow,
+ /* [out] */ DWORD *pdwEventsHigh);
+
+ HRESULT ( STDMETHODCALLTYPE *SetEventMask2 )(
+ ICorProfilerInfo5 * This,
+ /* [in] */ DWORD dwEventsLow,
+ /* [in] */ DWORD dwEventsHigh);
+
+ END_INTERFACE
+ } ICorProfilerInfo5Vtbl;
+
+ interface ICorProfilerInfo5
+ {
+ CONST_VTBL struct ICorProfilerInfo5Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorProfilerInfo5_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorProfilerInfo5_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorProfilerInfo5_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorProfilerInfo5_GetClassFromObject(This,objectId,pClassId) \
+ ( (This)->lpVtbl -> GetClassFromObject(This,objectId,pClassId) )
+
+#define ICorProfilerInfo5_GetClassFromToken(This,moduleId,typeDef,pClassId) \
+ ( (This)->lpVtbl -> GetClassFromToken(This,moduleId,typeDef,pClassId) )
+
+#define ICorProfilerInfo5_GetCodeInfo(This,functionId,pStart,pcSize) \
+ ( (This)->lpVtbl -> GetCodeInfo(This,functionId,pStart,pcSize) )
+
+#define ICorProfilerInfo5_GetEventMask(This,pdwEvents) \
+ ( (This)->lpVtbl -> GetEventMask(This,pdwEvents) )
+
+#define ICorProfilerInfo5_GetFunctionFromIP(This,ip,pFunctionId) \
+ ( (This)->lpVtbl -> GetFunctionFromIP(This,ip,pFunctionId) )
+
+#define ICorProfilerInfo5_GetFunctionFromToken(This,moduleId,token,pFunctionId) \
+ ( (This)->lpVtbl -> GetFunctionFromToken(This,moduleId,token,pFunctionId) )
+
+#define ICorProfilerInfo5_GetHandleFromThread(This,threadId,phThread) \
+ ( (This)->lpVtbl -> GetHandleFromThread(This,threadId,phThread) )
+
+#define ICorProfilerInfo5_GetObjectSize(This,objectId,pcSize) \
+ ( (This)->lpVtbl -> GetObjectSize(This,objectId,pcSize) )
+
+#define ICorProfilerInfo5_IsArrayClass(This,classId,pBaseElemType,pBaseClassId,pcRank) \
+ ( (This)->lpVtbl -> IsArrayClass(This,classId,pBaseElemType,pBaseClassId,pcRank) )
+
+#define ICorProfilerInfo5_GetThreadInfo(This,threadId,pdwWin32ThreadId) \
+ ( (This)->lpVtbl -> GetThreadInfo(This,threadId,pdwWin32ThreadId) )
+
+#define ICorProfilerInfo5_GetCurrentThreadID(This,pThreadId) \
+ ( (This)->lpVtbl -> GetCurrentThreadID(This,pThreadId) )
+
+#define ICorProfilerInfo5_GetClassIDInfo(This,classId,pModuleId,pTypeDefToken) \
+ ( (This)->lpVtbl -> GetClassIDInfo(This,classId,pModuleId,pTypeDefToken) )
+
+#define ICorProfilerInfo5_GetFunctionInfo(This,functionId,pClassId,pModuleId,pToken) \
+ ( (This)->lpVtbl -> GetFunctionInfo(This,functionId,pClassId,pModuleId,pToken) )
+
+#define ICorProfilerInfo5_SetEventMask(This,dwEvents) \
+ ( (This)->lpVtbl -> SetEventMask(This,dwEvents) )
+
+#define ICorProfilerInfo5_SetEnterLeaveFunctionHooks(This,pFuncEnter,pFuncLeave,pFuncTailcall) \
+ ( (This)->lpVtbl -> SetEnterLeaveFunctionHooks(This,pFuncEnter,pFuncLeave,pFuncTailcall) )
+
+#define ICorProfilerInfo5_SetFunctionIDMapper(This,pFunc) \
+ ( (This)->lpVtbl -> SetFunctionIDMapper(This,pFunc) )
+
+#define ICorProfilerInfo5_GetTokenAndMetaDataFromFunction(This,functionId,riid,ppImport,pToken) \
+ ( (This)->lpVtbl -> GetTokenAndMetaDataFromFunction(This,functionId,riid,ppImport,pToken) )
+
+#define ICorProfilerInfo5_GetModuleInfo(This,moduleId,ppBaseLoadAddress,cchName,pcchName,szName,pAssemblyId) \
+ ( (This)->lpVtbl -> GetModuleInfo(This,moduleId,ppBaseLoadAddress,cchName,pcchName,szName,pAssemblyId) )
+
+#define ICorProfilerInfo5_GetModuleMetaData(This,moduleId,dwOpenFlags,riid,ppOut) \
+ ( (This)->lpVtbl -> GetModuleMetaData(This,moduleId,dwOpenFlags,riid,ppOut) )
+
+#define ICorProfilerInfo5_GetILFunctionBody(This,moduleId,methodId,ppMethodHeader,pcbMethodSize) \
+ ( (This)->lpVtbl -> GetILFunctionBody(This,moduleId,methodId,ppMethodHeader,pcbMethodSize) )
+
+#define ICorProfilerInfo5_GetILFunctionBodyAllocator(This,moduleId,ppMalloc) \
+ ( (This)->lpVtbl -> GetILFunctionBodyAllocator(This,moduleId,ppMalloc) )
+
+#define ICorProfilerInfo5_SetILFunctionBody(This,moduleId,methodid,pbNewILMethodHeader) \
+ ( (This)->lpVtbl -> SetILFunctionBody(This,moduleId,methodid,pbNewILMethodHeader) )
+
+#define ICorProfilerInfo5_GetAppDomainInfo(This,appDomainId,cchName,pcchName,szName,pProcessId) \
+ ( (This)->lpVtbl -> GetAppDomainInfo(This,appDomainId,cchName,pcchName,szName,pProcessId) )
+
+#define ICorProfilerInfo5_GetAssemblyInfo(This,assemblyId,cchName,pcchName,szName,pAppDomainId,pModuleId) \
+ ( (This)->lpVtbl -> GetAssemblyInfo(This,assemblyId,cchName,pcchName,szName,pAppDomainId,pModuleId) )
+
+#define ICorProfilerInfo5_SetFunctionReJIT(This,functionId) \
+ ( (This)->lpVtbl -> SetFunctionReJIT(This,functionId) )
+
+#define ICorProfilerInfo5_ForceGC(This) \
+ ( (This)->lpVtbl -> ForceGC(This) )
+
+#define ICorProfilerInfo5_SetILInstrumentedCodeMap(This,functionId,fStartJit,cILMapEntries,rgILMapEntries) \
+ ( (This)->lpVtbl -> SetILInstrumentedCodeMap(This,functionId,fStartJit,cILMapEntries,rgILMapEntries) )
+
+#define ICorProfilerInfo5_GetInprocInspectionInterface(This,ppicd) \
+ ( (This)->lpVtbl -> GetInprocInspectionInterface(This,ppicd) )
+
+#define ICorProfilerInfo5_GetInprocInspectionIThisThread(This,ppicd) \
+ ( (This)->lpVtbl -> GetInprocInspectionIThisThread(This,ppicd) )
+
+#define ICorProfilerInfo5_GetThreadContext(This,threadId,pContextId) \
+ ( (This)->lpVtbl -> GetThreadContext(This,threadId,pContextId) )
+
+#define ICorProfilerInfo5_BeginInprocDebugging(This,fThisThreadOnly,pdwProfilerContext) \
+ ( (This)->lpVtbl -> BeginInprocDebugging(This,fThisThreadOnly,pdwProfilerContext) )
+
+#define ICorProfilerInfo5_EndInprocDebugging(This,dwProfilerContext) \
+ ( (This)->lpVtbl -> EndInprocDebugging(This,dwProfilerContext) )
+
+#define ICorProfilerInfo5_GetILToNativeMapping(This,functionId,cMap,pcMap,map) \
+ ( (This)->lpVtbl -> GetILToNativeMapping(This,functionId,cMap,pcMap,map) )
+
+
+#define ICorProfilerInfo5_DoStackSnapshot(This,thread,callback,infoFlags,clientData,context,contextSize) \
+ ( (This)->lpVtbl -> DoStackSnapshot(This,thread,callback,infoFlags,clientData,context,contextSize) )
+
+#define ICorProfilerInfo5_SetEnterLeaveFunctionHooks2(This,pFuncEnter,pFuncLeave,pFuncTailcall) \
+ ( (This)->lpVtbl -> SetEnterLeaveFunctionHooks2(This,pFuncEnter,pFuncLeave,pFuncTailcall) )
+
+#define ICorProfilerInfo5_GetFunctionInfo2(This,funcId,frameInfo,pClassId,pModuleId,pToken,cTypeArgs,pcTypeArgs,typeArgs) \
+ ( (This)->lpVtbl -> GetFunctionInfo2(This,funcId,frameInfo,pClassId,pModuleId,pToken,cTypeArgs,pcTypeArgs,typeArgs) )
+
+#define ICorProfilerInfo5_GetStringLayout(This,pBufferLengthOffset,pStringLengthOffset,pBufferOffset) \
+ ( (This)->lpVtbl -> GetStringLayout(This,pBufferLengthOffset,pStringLengthOffset,pBufferOffset) )
+
+#define ICorProfilerInfo5_GetClassLayout(This,classID,rFieldOffset,cFieldOffset,pcFieldOffset,pulClassSize) \
+ ( (This)->lpVtbl -> GetClassLayout(This,classID,rFieldOffset,cFieldOffset,pcFieldOffset,pulClassSize) )
+
+#define ICorProfilerInfo5_GetClassIDInfo2(This,classId,pModuleId,pTypeDefToken,pParentClassId,cNumTypeArgs,pcNumTypeArgs,typeArgs) \
+ ( (This)->lpVtbl -> GetClassIDInfo2(This,classId,pModuleId,pTypeDefToken,pParentClassId,cNumTypeArgs,pcNumTypeArgs,typeArgs) )
+
+#define ICorProfilerInfo5_GetCodeInfo2(This,functionID,cCodeInfos,pcCodeInfos,codeInfos) \
+ ( (This)->lpVtbl -> GetCodeInfo2(This,functionID,cCodeInfos,pcCodeInfos,codeInfos) )
+
+#define ICorProfilerInfo5_GetClassFromTokenAndTypeArgs(This,moduleID,typeDef,cTypeArgs,typeArgs,pClassID) \
+ ( (This)->lpVtbl -> GetClassFromTokenAndTypeArgs(This,moduleID,typeDef,cTypeArgs,typeArgs,pClassID) )
+
+#define ICorProfilerInfo5_GetFunctionFromTokenAndTypeArgs(This,moduleID,funcDef,classId,cTypeArgs,typeArgs,pFunctionID) \
+ ( (This)->lpVtbl -> GetFunctionFromTokenAndTypeArgs(This,moduleID,funcDef,classId,cTypeArgs,typeArgs,pFunctionID) )
+
+#define ICorProfilerInfo5_EnumModuleFrozenObjects(This,moduleID,ppEnum) \
+ ( (This)->lpVtbl -> EnumModuleFrozenObjects(This,moduleID,ppEnum) )
+
+#define ICorProfilerInfo5_GetArrayObjectInfo(This,objectId,cDimensions,pDimensionSizes,pDimensionLowerBounds,ppData) \
+ ( (This)->lpVtbl -> GetArrayObjectInfo(This,objectId,cDimensions,pDimensionSizes,pDimensionLowerBounds,ppData) )
+
+#define ICorProfilerInfo5_GetBoxClassLayout(This,classId,pBufferOffset) \
+ ( (This)->lpVtbl -> GetBoxClassLayout(This,classId,pBufferOffset) )
+
+#define ICorProfilerInfo5_GetThreadAppDomain(This,threadId,pAppDomainId) \
+ ( (This)->lpVtbl -> GetThreadAppDomain(This,threadId,pAppDomainId) )
+
+#define ICorProfilerInfo5_GetRVAStaticAddress(This,classId,fieldToken,ppAddress) \
+ ( (This)->lpVtbl -> GetRVAStaticAddress(This,classId,fieldToken,ppAddress) )
+
+#define ICorProfilerInfo5_GetAppDomainStaticAddress(This,classId,fieldToken,appDomainId,ppAddress) \
+ ( (This)->lpVtbl -> GetAppDomainStaticAddress(This,classId,fieldToken,appDomainId,ppAddress) )
+
+#define ICorProfilerInfo5_GetThreadStaticAddress(This,classId,fieldToken,threadId,ppAddress) \
+ ( (This)->lpVtbl -> GetThreadStaticAddress(This,classId,fieldToken,threadId,ppAddress) )
+
+#define ICorProfilerInfo5_GetContextStaticAddress(This,classId,fieldToken,contextId,ppAddress) \
+ ( (This)->lpVtbl -> GetContextStaticAddress(This,classId,fieldToken,contextId,ppAddress) )
+
+#define ICorProfilerInfo5_GetStaticFieldInfo(This,classId,fieldToken,pFieldInfo) \
+ ( (This)->lpVtbl -> GetStaticFieldInfo(This,classId,fieldToken,pFieldInfo) )
+
+#define ICorProfilerInfo5_GetGenerationBounds(This,cObjectRanges,pcObjectRanges,ranges) \
+ ( (This)->lpVtbl -> GetGenerationBounds(This,cObjectRanges,pcObjectRanges,ranges) )
+
+#define ICorProfilerInfo5_GetObjectGeneration(This,objectId,range) \
+ ( (This)->lpVtbl -> GetObjectGeneration(This,objectId,range) )
+
+#define ICorProfilerInfo5_GetNotifiedExceptionClauseInfo(This,pinfo) \
+ ( (This)->lpVtbl -> GetNotifiedExceptionClauseInfo(This,pinfo) )
+
+
+#define ICorProfilerInfo5_EnumJITedFunctions(This,ppEnum) \
+ ( (This)->lpVtbl -> EnumJITedFunctions(This,ppEnum) )
+
+#define ICorProfilerInfo5_RequestProfilerDetach(This,dwExpectedCompletionMilliseconds) \
+ ( (This)->lpVtbl -> RequestProfilerDetach(This,dwExpectedCompletionMilliseconds) )
+
+#define ICorProfilerInfo5_SetFunctionIDMapper2(This,pFunc,clientData) \
+ ( (This)->lpVtbl -> SetFunctionIDMapper2(This,pFunc,clientData) )
+
+#define ICorProfilerInfo5_GetStringLayout2(This,pStringLengthOffset,pBufferOffset) \
+ ( (This)->lpVtbl -> GetStringLayout2(This,pStringLengthOffset,pBufferOffset) )
+
+#define ICorProfilerInfo5_SetEnterLeaveFunctionHooks3(This,pFuncEnter3,pFuncLeave3,pFuncTailcall3) \
+ ( (This)->lpVtbl -> SetEnterLeaveFunctionHooks3(This,pFuncEnter3,pFuncLeave3,pFuncTailcall3) )
+
+#define ICorProfilerInfo5_SetEnterLeaveFunctionHooks3WithInfo(This,pFuncEnter3WithInfo,pFuncLeave3WithInfo,pFuncTailcall3WithInfo) \
+ ( (This)->lpVtbl -> SetEnterLeaveFunctionHooks3WithInfo(This,pFuncEnter3WithInfo,pFuncLeave3WithInfo,pFuncTailcall3WithInfo) )
+
+#define ICorProfilerInfo5_GetFunctionEnter3Info(This,functionId,eltInfo,pFrameInfo,pcbArgumentInfo,pArgumentInfo) \
+ ( (This)->lpVtbl -> GetFunctionEnter3Info(This,functionId,eltInfo,pFrameInfo,pcbArgumentInfo,pArgumentInfo) )
+
+#define ICorProfilerInfo5_GetFunctionLeave3Info(This,functionId,eltInfo,pFrameInfo,pRetvalRange) \
+ ( (This)->lpVtbl -> GetFunctionLeave3Info(This,functionId,eltInfo,pFrameInfo,pRetvalRange) )
+
+#define ICorProfilerInfo5_GetFunctionTailcall3Info(This,functionId,eltInfo,pFrameInfo) \
+ ( (This)->lpVtbl -> GetFunctionTailcall3Info(This,functionId,eltInfo,pFrameInfo) )
+
+#define ICorProfilerInfo5_EnumModules(This,ppEnum) \
+ ( (This)->lpVtbl -> EnumModules(This,ppEnum) )
+
+#define ICorProfilerInfo5_GetRuntimeInformation(This,pClrInstanceId,pRuntimeType,pMajorVersion,pMinorVersion,pBuildNumber,pQFEVersion,cchVersionString,pcchVersionString,szVersionString) \
+ ( (This)->lpVtbl -> GetRuntimeInformation(This,pClrInstanceId,pRuntimeType,pMajorVersion,pMinorVersion,pBuildNumber,pQFEVersion,cchVersionString,pcchVersionString,szVersionString) )
+
+#define ICorProfilerInfo5_GetThreadStaticAddress2(This,classId,fieldToken,appDomainId,threadId,ppAddress) \
+ ( (This)->lpVtbl -> GetThreadStaticAddress2(This,classId,fieldToken,appDomainId,threadId,ppAddress) )
+
+#define ICorProfilerInfo5_GetAppDomainsContainingModule(This,moduleId,cAppDomainIds,pcAppDomainIds,appDomainIds) \
+ ( (This)->lpVtbl -> GetAppDomainsContainingModule(This,moduleId,cAppDomainIds,pcAppDomainIds,appDomainIds) )
+
+#define ICorProfilerInfo5_GetModuleInfo2(This,moduleId,ppBaseLoadAddress,cchName,pcchName,szName,pAssemblyId,pdwModuleFlags) \
+ ( (This)->lpVtbl -> GetModuleInfo2(This,moduleId,ppBaseLoadAddress,cchName,pcchName,szName,pAssemblyId,pdwModuleFlags) )
+
+
+#define ICorProfilerInfo5_EnumThreads(This,ppEnum) \
+ ( (This)->lpVtbl -> EnumThreads(This,ppEnum) )
+
+#define ICorProfilerInfo5_InitializeCurrentThread(This) \
+ ( (This)->lpVtbl -> InitializeCurrentThread(This) )
+
+#define ICorProfilerInfo5_RequestReJIT(This,cFunctions,moduleIds,methodIds) \
+ ( (This)->lpVtbl -> RequestReJIT(This,cFunctions,moduleIds,methodIds) )
+
+#define ICorProfilerInfo5_RequestRevert(This,cFunctions,moduleIds,methodIds,status) \
+ ( (This)->lpVtbl -> RequestRevert(This,cFunctions,moduleIds,methodIds,status) )
+
+#define ICorProfilerInfo5_GetCodeInfo3(This,functionID,reJitId,cCodeInfos,pcCodeInfos,codeInfos) \
+ ( (This)->lpVtbl -> GetCodeInfo3(This,functionID,reJitId,cCodeInfos,pcCodeInfos,codeInfos) )
+
+#define ICorProfilerInfo5_GetFunctionFromIP2(This,ip,pFunctionId,pReJitId) \
+ ( (This)->lpVtbl -> GetFunctionFromIP2(This,ip,pFunctionId,pReJitId) )
+
+#define ICorProfilerInfo5_GetReJITIDs(This,functionId,cReJitIds,pcReJitIds,reJitIds) \
+ ( (This)->lpVtbl -> GetReJITIDs(This,functionId,cReJitIds,pcReJitIds,reJitIds) )
+
+#define ICorProfilerInfo5_GetILToNativeMapping2(This,functionId,reJitId,cMap,pcMap,map) \
+ ( (This)->lpVtbl -> GetILToNativeMapping2(This,functionId,reJitId,cMap,pcMap,map) )
+
+#define ICorProfilerInfo5_EnumJITedFunctions2(This,ppEnum) \
+ ( (This)->lpVtbl -> EnumJITedFunctions2(This,ppEnum) )
+
+#define ICorProfilerInfo5_GetObjectSize2(This,objectId,pcSize) \
+ ( (This)->lpVtbl -> GetObjectSize2(This,objectId,pcSize) )
+
+
+#define ICorProfilerInfo5_GetEventMask2(This,pdwEventsLow,pdwEventsHigh) \
+ ( (This)->lpVtbl -> GetEventMask2(This,pdwEventsLow,pdwEventsHigh) )
+
+#define ICorProfilerInfo5_SetEventMask2(This,dwEventsLow,dwEventsHigh) \
+ ( (This)->lpVtbl -> SetEventMask2(This,dwEventsLow,dwEventsHigh) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorProfilerInfo5_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorProfilerInfo6_INTERFACE_DEFINED__
+#define __ICorProfilerInfo6_INTERFACE_DEFINED__
+
+/* interface ICorProfilerInfo6 */
+/* [local][unique][uuid][object] */
+
+
+EXTERN_C const IID IID_ICorProfilerInfo6;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("F30A070D-BFFB-46A7-B1D8-8781EF7B698A")
+ ICorProfilerInfo6 : public ICorProfilerInfo5
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE EnumNgenModuleMethodsInliningThisMethod(
+ /* [in] */ ModuleID inlinersModuleId,
+ /* [in] */ ModuleID inlineeModuleId,
+ /* [in] */ mdMethodDef inlineeMethodId,
+ /* [out] */ BOOL *incompleteData,
+ /* [out] */ ICorProfilerMethodEnum **ppEnum) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorProfilerInfo6Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorProfilerInfo6 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorProfilerInfo6 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorProfilerInfo6 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetClassFromObject )(
+ ICorProfilerInfo6 * This,
+ /* [in] */ ObjectID objectId,
+ /* [out] */ ClassID *pClassId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetClassFromToken )(
+ ICorProfilerInfo6 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ mdTypeDef typeDef,
+ /* [out] */ ClassID *pClassId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCodeInfo )(
+ ICorProfilerInfo6 * This,
+ /* [in] */ FunctionID functionId,
+ /* [out] */ LPCBYTE *pStart,
+ /* [out] */ ULONG *pcSize);
+
+ HRESULT ( STDMETHODCALLTYPE *GetEventMask )(
+ ICorProfilerInfo6 * This,
+ /* [out] */ DWORD *pdwEvents);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFunctionFromIP )(
+ ICorProfilerInfo6 * This,
+ /* [in] */ LPCBYTE ip,
+ /* [out] */ FunctionID *pFunctionId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFunctionFromToken )(
+ ICorProfilerInfo6 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ mdToken token,
+ /* [out] */ FunctionID *pFunctionId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetHandleFromThread )(
+ ICorProfilerInfo6 * This,
+ /* [in] */ ThreadID threadId,
+ /* [out] */ HANDLE *phThread);
+
+ HRESULT ( STDMETHODCALLTYPE *GetObjectSize )(
+ ICorProfilerInfo6 * This,
+ /* [in] */ ObjectID objectId,
+ /* [out] */ ULONG *pcSize);
+
+ HRESULT ( STDMETHODCALLTYPE *IsArrayClass )(
+ ICorProfilerInfo6 * This,
+ /* [in] */ ClassID classId,
+ /* [out] */ CorElementType *pBaseElemType,
+ /* [out] */ ClassID *pBaseClassId,
+ /* [out] */ ULONG *pcRank);
+
+ HRESULT ( STDMETHODCALLTYPE *GetThreadInfo )(
+ ICorProfilerInfo6 * This,
+ /* [in] */ ThreadID threadId,
+ /* [out] */ DWORD *pdwWin32ThreadId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCurrentThreadID )(
+ ICorProfilerInfo6 * This,
+ /* [out] */ ThreadID *pThreadId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetClassIDInfo )(
+ ICorProfilerInfo6 * This,
+ /* [in] */ ClassID classId,
+ /* [out] */ ModuleID *pModuleId,
+ /* [out] */ mdTypeDef *pTypeDefToken);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFunctionInfo )(
+ ICorProfilerInfo6 * This,
+ /* [in] */ FunctionID functionId,
+ /* [out] */ ClassID *pClassId,
+ /* [out] */ ModuleID *pModuleId,
+ /* [out] */ mdToken *pToken);
+
+ HRESULT ( STDMETHODCALLTYPE *SetEventMask )(
+ ICorProfilerInfo6 * This,
+ /* [in] */ DWORD dwEvents);
+
+ HRESULT ( STDMETHODCALLTYPE *SetEnterLeaveFunctionHooks )(
+ ICorProfilerInfo6 * This,
+ /* [in] */ FunctionEnter *pFuncEnter,
+ /* [in] */ FunctionLeave *pFuncLeave,
+ /* [in] */ FunctionTailcall *pFuncTailcall);
+
+ HRESULT ( STDMETHODCALLTYPE *SetFunctionIDMapper )(
+ ICorProfilerInfo6 * This,
+ /* [in] */ FunctionIDMapper *pFunc);
+
+ HRESULT ( STDMETHODCALLTYPE *GetTokenAndMetaDataFromFunction )(
+ ICorProfilerInfo6 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ REFIID riid,
+ /* [out] */ IUnknown **ppImport,
+ /* [out] */ mdToken *pToken);
+
+ HRESULT ( STDMETHODCALLTYPE *GetModuleInfo )(
+ ICorProfilerInfo6 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [out] */ LPCBYTE *ppBaseLoadAddress,
+ /* [in] */ ULONG cchName,
+ /* [out] */ ULONG *pcchName,
+ /* [annotation][out] */
+ _Out_writes_to_(cchName, *pcchName) WCHAR szName[ ],
+ /* [out] */ AssemblyID *pAssemblyId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetModuleMetaData )(
+ ICorProfilerInfo6 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ DWORD dwOpenFlags,
+ /* [in] */ REFIID riid,
+ /* [out] */ IUnknown **ppOut);
+
+ HRESULT ( STDMETHODCALLTYPE *GetILFunctionBody )(
+ ICorProfilerInfo6 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ mdMethodDef methodId,
+ /* [out] */ LPCBYTE *ppMethodHeader,
+ /* [out] */ ULONG *pcbMethodSize);
+
+ HRESULT ( STDMETHODCALLTYPE *GetILFunctionBodyAllocator )(
+ ICorProfilerInfo6 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [out] */ IMethodMalloc **ppMalloc);
+
+ HRESULT ( STDMETHODCALLTYPE *SetILFunctionBody )(
+ ICorProfilerInfo6 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ mdMethodDef methodid,
+ /* [in] */ LPCBYTE pbNewILMethodHeader);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAppDomainInfo )(
+ ICorProfilerInfo6 * This,
+ /* [in] */ AppDomainID appDomainId,
+ /* [in] */ ULONG cchName,
+ /* [out] */ ULONG *pcchName,
+ /* [annotation][out] */
+ _Out_writes_to_(cchName, *pcchName) WCHAR szName[ ],
+ /* [out] */ ProcessID *pProcessId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAssemblyInfo )(
+ ICorProfilerInfo6 * This,
+ /* [in] */ AssemblyID assemblyId,
+ /* [in] */ ULONG cchName,
+ /* [out] */ ULONG *pcchName,
+ /* [annotation][out] */
+ _Out_writes_to_(cchName, *pcchName) WCHAR szName[ ],
+ /* [out] */ AppDomainID *pAppDomainId,
+ /* [out] */ ModuleID *pModuleId);
+
+ HRESULT ( STDMETHODCALLTYPE *SetFunctionReJIT )(
+ ICorProfilerInfo6 * This,
+ /* [in] */ FunctionID functionId);
+
+ HRESULT ( STDMETHODCALLTYPE *ForceGC )(
+ ICorProfilerInfo6 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *SetILInstrumentedCodeMap )(
+ ICorProfilerInfo6 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ BOOL fStartJit,
+ /* [in] */ ULONG cILMapEntries,
+ /* [size_is][in] */ COR_IL_MAP rgILMapEntries[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetInprocInspectionInterface )(
+ ICorProfilerInfo6 * This,
+ /* [out] */ IUnknown **ppicd);
+
+ HRESULT ( STDMETHODCALLTYPE *GetInprocInspectionIThisThread )(
+ ICorProfilerInfo6 * This,
+ /* [out] */ IUnknown **ppicd);
+
+ HRESULT ( STDMETHODCALLTYPE *GetThreadContext )(
+ ICorProfilerInfo6 * This,
+ /* [in] */ ThreadID threadId,
+ /* [out] */ ContextID *pContextId);
+
+ HRESULT ( STDMETHODCALLTYPE *BeginInprocDebugging )(
+ ICorProfilerInfo6 * This,
+ /* [in] */ BOOL fThisThreadOnly,
+ /* [out] */ DWORD *pdwProfilerContext);
+
+ HRESULT ( STDMETHODCALLTYPE *EndInprocDebugging )(
+ ICorProfilerInfo6 * This,
+ /* [in] */ DWORD dwProfilerContext);
+
+ HRESULT ( STDMETHODCALLTYPE *GetILToNativeMapping )(
+ ICorProfilerInfo6 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ ULONG32 cMap,
+ /* [out] */ ULONG32 *pcMap,
+ /* [length_is][size_is][out] */ COR_DEBUG_IL_TO_NATIVE_MAP map[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *DoStackSnapshot )(
+ ICorProfilerInfo6 * This,
+ /* [in] */ ThreadID thread,
+ /* [in] */ StackSnapshotCallback *callback,
+ /* [in] */ ULONG32 infoFlags,
+ /* [in] */ void *clientData,
+ /* [size_is][in] */ BYTE context[ ],
+ /* [in] */ ULONG32 contextSize);
+
+ HRESULT ( STDMETHODCALLTYPE *SetEnterLeaveFunctionHooks2 )(
+ ICorProfilerInfo6 * This,
+ /* [in] */ FunctionEnter2 *pFuncEnter,
+ /* [in] */ FunctionLeave2 *pFuncLeave,
+ /* [in] */ FunctionTailcall2 *pFuncTailcall);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFunctionInfo2 )(
+ ICorProfilerInfo6 * This,
+ /* [in] */ FunctionID funcId,
+ /* [in] */ COR_PRF_FRAME_INFO frameInfo,
+ /* [out] */ ClassID *pClassId,
+ /* [out] */ ModuleID *pModuleId,
+ /* [out] */ mdToken *pToken,
+ /* [in] */ ULONG32 cTypeArgs,
+ /* [out] */ ULONG32 *pcTypeArgs,
+ /* [out] */ ClassID typeArgs[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetStringLayout )(
+ ICorProfilerInfo6 * This,
+ /* [out] */ ULONG *pBufferLengthOffset,
+ /* [out] */ ULONG *pStringLengthOffset,
+ /* [out] */ ULONG *pBufferOffset);
+
+ HRESULT ( STDMETHODCALLTYPE *GetClassLayout )(
+ ICorProfilerInfo6 * This,
+ /* [in] */ ClassID classID,
+ /* [out][in] */ COR_FIELD_OFFSET rFieldOffset[ ],
+ /* [in] */ ULONG cFieldOffset,
+ /* [out] */ ULONG *pcFieldOffset,
+ /* [out] */ ULONG *pulClassSize);
+
+ HRESULT ( STDMETHODCALLTYPE *GetClassIDInfo2 )(
+ ICorProfilerInfo6 * This,
+ /* [in] */ ClassID classId,
+ /* [out] */ ModuleID *pModuleId,
+ /* [out] */ mdTypeDef *pTypeDefToken,
+ /* [out] */ ClassID *pParentClassId,
+ /* [in] */ ULONG32 cNumTypeArgs,
+ /* [out] */ ULONG32 *pcNumTypeArgs,
+ /* [out] */ ClassID typeArgs[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCodeInfo2 )(
+ ICorProfilerInfo6 * This,
+ /* [in] */ FunctionID functionID,
+ /* [in] */ ULONG32 cCodeInfos,
+ /* [out] */ ULONG32 *pcCodeInfos,
+ /* [length_is][size_is][out] */ COR_PRF_CODE_INFO codeInfos[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetClassFromTokenAndTypeArgs )(
+ ICorProfilerInfo6 * This,
+ /* [in] */ ModuleID moduleID,
+ /* [in] */ mdTypeDef typeDef,
+ /* [in] */ ULONG32 cTypeArgs,
+ /* [size_is][in] */ ClassID typeArgs[ ],
+ /* [out] */ ClassID *pClassID);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFunctionFromTokenAndTypeArgs )(
+ ICorProfilerInfo6 * This,
+ /* [in] */ ModuleID moduleID,
+ /* [in] */ mdMethodDef funcDef,
+ /* [in] */ ClassID classId,
+ /* [in] */ ULONG32 cTypeArgs,
+ /* [size_is][in] */ ClassID typeArgs[ ],
+ /* [out] */ FunctionID *pFunctionID);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumModuleFrozenObjects )(
+ ICorProfilerInfo6 * This,
+ /* [in] */ ModuleID moduleID,
+ /* [out] */ ICorProfilerObjectEnum **ppEnum);
+
+ HRESULT ( STDMETHODCALLTYPE *GetArrayObjectInfo )(
+ ICorProfilerInfo6 * This,
+ /* [in] */ ObjectID objectId,
+ /* [in] */ ULONG32 cDimensions,
+ /* [size_is][out] */ ULONG32 pDimensionSizes[ ],
+ /* [size_is][out] */ int pDimensionLowerBounds[ ],
+ /* [out] */ BYTE **ppData);
+
+ HRESULT ( STDMETHODCALLTYPE *GetBoxClassLayout )(
+ ICorProfilerInfo6 * This,
+ /* [in] */ ClassID classId,
+ /* [out] */ ULONG32 *pBufferOffset);
+
+ HRESULT ( STDMETHODCALLTYPE *GetThreadAppDomain )(
+ ICorProfilerInfo6 * This,
+ /* [in] */ ThreadID threadId,
+ /* [out] */ AppDomainID *pAppDomainId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetRVAStaticAddress )(
+ ICorProfilerInfo6 * This,
+ /* [in] */ ClassID classId,
+ /* [in] */ mdFieldDef fieldToken,
+ /* [out] */ void **ppAddress);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAppDomainStaticAddress )(
+ ICorProfilerInfo6 * This,
+ /* [in] */ ClassID classId,
+ /* [in] */ mdFieldDef fieldToken,
+ /* [in] */ AppDomainID appDomainId,
+ /* [out] */ void **ppAddress);
+
+ HRESULT ( STDMETHODCALLTYPE *GetThreadStaticAddress )(
+ ICorProfilerInfo6 * This,
+ /* [in] */ ClassID classId,
+ /* [in] */ mdFieldDef fieldToken,
+ /* [in] */ ThreadID threadId,
+ /* [out] */ void **ppAddress);
+
+ HRESULT ( STDMETHODCALLTYPE *GetContextStaticAddress )(
+ ICorProfilerInfo6 * This,
+ /* [in] */ ClassID classId,
+ /* [in] */ mdFieldDef fieldToken,
+ /* [in] */ ContextID contextId,
+ /* [out] */ void **ppAddress);
+
+ HRESULT ( STDMETHODCALLTYPE *GetStaticFieldInfo )(
+ ICorProfilerInfo6 * This,
+ /* [in] */ ClassID classId,
+ /* [in] */ mdFieldDef fieldToken,
+ /* [out] */ COR_PRF_STATIC_TYPE *pFieldInfo);
+
+ HRESULT ( STDMETHODCALLTYPE *GetGenerationBounds )(
+ ICorProfilerInfo6 * This,
+ /* [in] */ ULONG cObjectRanges,
+ /* [out] */ ULONG *pcObjectRanges,
+ /* [length_is][size_is][out] */ COR_PRF_GC_GENERATION_RANGE ranges[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetObjectGeneration )(
+ ICorProfilerInfo6 * This,
+ /* [in] */ ObjectID objectId,
+ /* [out] */ COR_PRF_GC_GENERATION_RANGE *range);
+
+ HRESULT ( STDMETHODCALLTYPE *GetNotifiedExceptionClauseInfo )(
+ ICorProfilerInfo6 * This,
+ /* [out] */ COR_PRF_EX_CLAUSE_INFO *pinfo);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumJITedFunctions )(
+ ICorProfilerInfo6 * This,
+ /* [out] */ ICorProfilerFunctionEnum **ppEnum);
+
+ HRESULT ( STDMETHODCALLTYPE *RequestProfilerDetach )(
+ ICorProfilerInfo6 * This,
+ /* [in] */ DWORD dwExpectedCompletionMilliseconds);
+
+ HRESULT ( STDMETHODCALLTYPE *SetFunctionIDMapper2 )(
+ ICorProfilerInfo6 * This,
+ /* [in] */ FunctionIDMapper2 *pFunc,
+ /* [in] */ void *clientData);
+
+ HRESULT ( STDMETHODCALLTYPE *GetStringLayout2 )(
+ ICorProfilerInfo6 * This,
+ /* [out] */ ULONG *pStringLengthOffset,
+ /* [out] */ ULONG *pBufferOffset);
+
+ HRESULT ( STDMETHODCALLTYPE *SetEnterLeaveFunctionHooks3 )(
+ ICorProfilerInfo6 * This,
+ /* [in] */ FunctionEnter3 *pFuncEnter3,
+ /* [in] */ FunctionLeave3 *pFuncLeave3,
+ /* [in] */ FunctionTailcall3 *pFuncTailcall3);
+
+ HRESULT ( STDMETHODCALLTYPE *SetEnterLeaveFunctionHooks3WithInfo )(
+ ICorProfilerInfo6 * This,
+ /* [in] */ FunctionEnter3WithInfo *pFuncEnter3WithInfo,
+ /* [in] */ FunctionLeave3WithInfo *pFuncLeave3WithInfo,
+ /* [in] */ FunctionTailcall3WithInfo *pFuncTailcall3WithInfo);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFunctionEnter3Info )(
+ ICorProfilerInfo6 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ COR_PRF_ELT_INFO eltInfo,
+ /* [out] */ COR_PRF_FRAME_INFO *pFrameInfo,
+ /* [out][in] */ ULONG *pcbArgumentInfo,
+ /* [size_is][out] */ COR_PRF_FUNCTION_ARGUMENT_INFO *pArgumentInfo);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFunctionLeave3Info )(
+ ICorProfilerInfo6 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ COR_PRF_ELT_INFO eltInfo,
+ /* [out] */ COR_PRF_FRAME_INFO *pFrameInfo,
+ /* [out] */ COR_PRF_FUNCTION_ARGUMENT_RANGE *pRetvalRange);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFunctionTailcall3Info )(
+ ICorProfilerInfo6 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ COR_PRF_ELT_INFO eltInfo,
+ /* [out] */ COR_PRF_FRAME_INFO *pFrameInfo);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumModules )(
+ ICorProfilerInfo6 * This,
+ /* [out] */ ICorProfilerModuleEnum **ppEnum);
+
+ HRESULT ( STDMETHODCALLTYPE *GetRuntimeInformation )(
+ ICorProfilerInfo6 * This,
+ /* [out] */ USHORT *pClrInstanceId,
+ /* [out] */ COR_PRF_RUNTIME_TYPE *pRuntimeType,
+ /* [out] */ USHORT *pMajorVersion,
+ /* [out] */ USHORT *pMinorVersion,
+ /* [out] */ USHORT *pBuildNumber,
+ /* [out] */ USHORT *pQFEVersion,
+ /* [in] */ ULONG cchVersionString,
+ /* [out] */ ULONG *pcchVersionString,
+ /* [annotation][out] */
+ _Out_writes_to_(cchVersionString, *pcchVersionString) WCHAR szVersionString[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetThreadStaticAddress2 )(
+ ICorProfilerInfo6 * This,
+ /* [in] */ ClassID classId,
+ /* [in] */ mdFieldDef fieldToken,
+ /* [in] */ AppDomainID appDomainId,
+ /* [in] */ ThreadID threadId,
+ /* [out] */ void **ppAddress);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAppDomainsContainingModule )(
+ ICorProfilerInfo6 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ ULONG32 cAppDomainIds,
+ /* [out] */ ULONG32 *pcAppDomainIds,
+ /* [length_is][size_is][out] */ AppDomainID appDomainIds[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetModuleInfo2 )(
+ ICorProfilerInfo6 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [out] */ LPCBYTE *ppBaseLoadAddress,
+ /* [in] */ ULONG cchName,
+ /* [out] */ ULONG *pcchName,
+ /* [annotation][out] */
+ _Out_writes_to_(cchName, *pcchName) WCHAR szName[ ],
+ /* [out] */ AssemblyID *pAssemblyId,
+ /* [out] */ DWORD *pdwModuleFlags);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumThreads )(
+ ICorProfilerInfo6 * This,
+ /* [out] */ ICorProfilerThreadEnum **ppEnum);
+
+ HRESULT ( STDMETHODCALLTYPE *InitializeCurrentThread )(
+ ICorProfilerInfo6 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *RequestReJIT )(
+ ICorProfilerInfo6 * This,
+ /* [in] */ ULONG cFunctions,
+ /* [size_is][in] */ ModuleID moduleIds[ ],
+ /* [size_is][in] */ mdMethodDef methodIds[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *RequestRevert )(
+ ICorProfilerInfo6 * This,
+ /* [in] */ ULONG cFunctions,
+ /* [size_is][in] */ ModuleID moduleIds[ ],
+ /* [size_is][in] */ mdMethodDef methodIds[ ],
+ /* [size_is][out] */ HRESULT status[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCodeInfo3 )(
+ ICorProfilerInfo6 * This,
+ /* [in] */ FunctionID functionID,
+ /* [in] */ ReJITID reJitId,
+ /* [in] */ ULONG32 cCodeInfos,
+ /* [out] */ ULONG32 *pcCodeInfos,
+ /* [length_is][size_is][out] */ COR_PRF_CODE_INFO codeInfos[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFunctionFromIP2 )(
+ ICorProfilerInfo6 * This,
+ /* [in] */ LPCBYTE ip,
+ /* [out] */ FunctionID *pFunctionId,
+ /* [out] */ ReJITID *pReJitId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetReJITIDs )(
+ ICorProfilerInfo6 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ ULONG cReJitIds,
+ /* [out] */ ULONG *pcReJitIds,
+ /* [length_is][size_is][out] */ ReJITID reJitIds[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetILToNativeMapping2 )(
+ ICorProfilerInfo6 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ ReJITID reJitId,
+ /* [in] */ ULONG32 cMap,
+ /* [out] */ ULONG32 *pcMap,
+ /* [length_is][size_is][out] */ COR_DEBUG_IL_TO_NATIVE_MAP map[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumJITedFunctions2 )(
+ ICorProfilerInfo6 * This,
+ /* [out] */ ICorProfilerFunctionEnum **ppEnum);
+
+ HRESULT ( STDMETHODCALLTYPE *GetObjectSize2 )(
+ ICorProfilerInfo6 * This,
+ /* [in] */ ObjectID objectId,
+ /* [out] */ SIZE_T *pcSize);
+
+ HRESULT ( STDMETHODCALLTYPE *GetEventMask2 )(
+ ICorProfilerInfo6 * This,
+ /* [out] */ DWORD *pdwEventsLow,
+ /* [out] */ DWORD *pdwEventsHigh);
+
+ HRESULT ( STDMETHODCALLTYPE *SetEventMask2 )(
+ ICorProfilerInfo6 * This,
+ /* [in] */ DWORD dwEventsLow,
+ /* [in] */ DWORD dwEventsHigh);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumNgenModuleMethodsInliningThisMethod )(
+ ICorProfilerInfo6 * This,
+ /* [in] */ ModuleID inlinersModuleId,
+ /* [in] */ ModuleID inlineeModuleId,
+ /* [in] */ mdMethodDef inlineeMethodId,
+ /* [out] */ BOOL *incompleteData,
+ /* [out] */ ICorProfilerMethodEnum **ppEnum);
+
+ END_INTERFACE
+ } ICorProfilerInfo6Vtbl;
+
+ interface ICorProfilerInfo6
+ {
+ CONST_VTBL struct ICorProfilerInfo6Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorProfilerInfo6_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorProfilerInfo6_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorProfilerInfo6_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorProfilerInfo6_GetClassFromObject(This,objectId,pClassId) \
+ ( (This)->lpVtbl -> GetClassFromObject(This,objectId,pClassId) )
+
+#define ICorProfilerInfo6_GetClassFromToken(This,moduleId,typeDef,pClassId) \
+ ( (This)->lpVtbl -> GetClassFromToken(This,moduleId,typeDef,pClassId) )
+
+#define ICorProfilerInfo6_GetCodeInfo(This,functionId,pStart,pcSize) \
+ ( (This)->lpVtbl -> GetCodeInfo(This,functionId,pStart,pcSize) )
+
+#define ICorProfilerInfo6_GetEventMask(This,pdwEvents) \
+ ( (This)->lpVtbl -> GetEventMask(This,pdwEvents) )
+
+#define ICorProfilerInfo6_GetFunctionFromIP(This,ip,pFunctionId) \
+ ( (This)->lpVtbl -> GetFunctionFromIP(This,ip,pFunctionId) )
+
+#define ICorProfilerInfo6_GetFunctionFromToken(This,moduleId,token,pFunctionId) \
+ ( (This)->lpVtbl -> GetFunctionFromToken(This,moduleId,token,pFunctionId) )
+
+#define ICorProfilerInfo6_GetHandleFromThread(This,threadId,phThread) \
+ ( (This)->lpVtbl -> GetHandleFromThread(This,threadId,phThread) )
+
+#define ICorProfilerInfo6_GetObjectSize(This,objectId,pcSize) \
+ ( (This)->lpVtbl -> GetObjectSize(This,objectId,pcSize) )
+
+#define ICorProfilerInfo6_IsArrayClass(This,classId,pBaseElemType,pBaseClassId,pcRank) \
+ ( (This)->lpVtbl -> IsArrayClass(This,classId,pBaseElemType,pBaseClassId,pcRank) )
+
+#define ICorProfilerInfo6_GetThreadInfo(This,threadId,pdwWin32ThreadId) \
+ ( (This)->lpVtbl -> GetThreadInfo(This,threadId,pdwWin32ThreadId) )
+
+#define ICorProfilerInfo6_GetCurrentThreadID(This,pThreadId) \
+ ( (This)->lpVtbl -> GetCurrentThreadID(This,pThreadId) )
+
+#define ICorProfilerInfo6_GetClassIDInfo(This,classId,pModuleId,pTypeDefToken) \
+ ( (This)->lpVtbl -> GetClassIDInfo(This,classId,pModuleId,pTypeDefToken) )
+
+#define ICorProfilerInfo6_GetFunctionInfo(This,functionId,pClassId,pModuleId,pToken) \
+ ( (This)->lpVtbl -> GetFunctionInfo(This,functionId,pClassId,pModuleId,pToken) )
+
+#define ICorProfilerInfo6_SetEventMask(This,dwEvents) \
+ ( (This)->lpVtbl -> SetEventMask(This,dwEvents) )
+
+#define ICorProfilerInfo6_SetEnterLeaveFunctionHooks(This,pFuncEnter,pFuncLeave,pFuncTailcall) \
+ ( (This)->lpVtbl -> SetEnterLeaveFunctionHooks(This,pFuncEnter,pFuncLeave,pFuncTailcall) )
+
+#define ICorProfilerInfo6_SetFunctionIDMapper(This,pFunc) \
+ ( (This)->lpVtbl -> SetFunctionIDMapper(This,pFunc) )
+
+#define ICorProfilerInfo6_GetTokenAndMetaDataFromFunction(This,functionId,riid,ppImport,pToken) \
+ ( (This)->lpVtbl -> GetTokenAndMetaDataFromFunction(This,functionId,riid,ppImport,pToken) )
+
+#define ICorProfilerInfo6_GetModuleInfo(This,moduleId,ppBaseLoadAddress,cchName,pcchName,szName,pAssemblyId) \
+ ( (This)->lpVtbl -> GetModuleInfo(This,moduleId,ppBaseLoadAddress,cchName,pcchName,szName,pAssemblyId) )
+
+#define ICorProfilerInfo6_GetModuleMetaData(This,moduleId,dwOpenFlags,riid,ppOut) \
+ ( (This)->lpVtbl -> GetModuleMetaData(This,moduleId,dwOpenFlags,riid,ppOut) )
+
+#define ICorProfilerInfo6_GetILFunctionBody(This,moduleId,methodId,ppMethodHeader,pcbMethodSize) \
+ ( (This)->lpVtbl -> GetILFunctionBody(This,moduleId,methodId,ppMethodHeader,pcbMethodSize) )
+
+#define ICorProfilerInfo6_GetILFunctionBodyAllocator(This,moduleId,ppMalloc) \
+ ( (This)->lpVtbl -> GetILFunctionBodyAllocator(This,moduleId,ppMalloc) )
+
+#define ICorProfilerInfo6_SetILFunctionBody(This,moduleId,methodid,pbNewILMethodHeader) \
+ ( (This)->lpVtbl -> SetILFunctionBody(This,moduleId,methodid,pbNewILMethodHeader) )
+
+#define ICorProfilerInfo6_GetAppDomainInfo(This,appDomainId,cchName,pcchName,szName,pProcessId) \
+ ( (This)->lpVtbl -> GetAppDomainInfo(This,appDomainId,cchName,pcchName,szName,pProcessId) )
+
+#define ICorProfilerInfo6_GetAssemblyInfo(This,assemblyId,cchName,pcchName,szName,pAppDomainId,pModuleId) \
+ ( (This)->lpVtbl -> GetAssemblyInfo(This,assemblyId,cchName,pcchName,szName,pAppDomainId,pModuleId) )
+
+#define ICorProfilerInfo6_SetFunctionReJIT(This,functionId) \
+ ( (This)->lpVtbl -> SetFunctionReJIT(This,functionId) )
+
+#define ICorProfilerInfo6_ForceGC(This) \
+ ( (This)->lpVtbl -> ForceGC(This) )
+
+#define ICorProfilerInfo6_SetILInstrumentedCodeMap(This,functionId,fStartJit,cILMapEntries,rgILMapEntries) \
+ ( (This)->lpVtbl -> SetILInstrumentedCodeMap(This,functionId,fStartJit,cILMapEntries,rgILMapEntries) )
+
+#define ICorProfilerInfo6_GetInprocInspectionInterface(This,ppicd) \
+ ( (This)->lpVtbl -> GetInprocInspectionInterface(This,ppicd) )
+
+#define ICorProfilerInfo6_GetInprocInspectionIThisThread(This,ppicd) \
+ ( (This)->lpVtbl -> GetInprocInspectionIThisThread(This,ppicd) )
+
+#define ICorProfilerInfo6_GetThreadContext(This,threadId,pContextId) \
+ ( (This)->lpVtbl -> GetThreadContext(This,threadId,pContextId) )
+
+#define ICorProfilerInfo6_BeginInprocDebugging(This,fThisThreadOnly,pdwProfilerContext) \
+ ( (This)->lpVtbl -> BeginInprocDebugging(This,fThisThreadOnly,pdwProfilerContext) )
+
+#define ICorProfilerInfo6_EndInprocDebugging(This,dwProfilerContext) \
+ ( (This)->lpVtbl -> EndInprocDebugging(This,dwProfilerContext) )
+
+#define ICorProfilerInfo6_GetILToNativeMapping(This,functionId,cMap,pcMap,map) \
+ ( (This)->lpVtbl -> GetILToNativeMapping(This,functionId,cMap,pcMap,map) )
+
+
+#define ICorProfilerInfo6_DoStackSnapshot(This,thread,callback,infoFlags,clientData,context,contextSize) \
+ ( (This)->lpVtbl -> DoStackSnapshot(This,thread,callback,infoFlags,clientData,context,contextSize) )
+
+#define ICorProfilerInfo6_SetEnterLeaveFunctionHooks2(This,pFuncEnter,pFuncLeave,pFuncTailcall) \
+ ( (This)->lpVtbl -> SetEnterLeaveFunctionHooks2(This,pFuncEnter,pFuncLeave,pFuncTailcall) )
+
+#define ICorProfilerInfo6_GetFunctionInfo2(This,funcId,frameInfo,pClassId,pModuleId,pToken,cTypeArgs,pcTypeArgs,typeArgs) \
+ ( (This)->lpVtbl -> GetFunctionInfo2(This,funcId,frameInfo,pClassId,pModuleId,pToken,cTypeArgs,pcTypeArgs,typeArgs) )
+
+#define ICorProfilerInfo6_GetStringLayout(This,pBufferLengthOffset,pStringLengthOffset,pBufferOffset) \
+ ( (This)->lpVtbl -> GetStringLayout(This,pBufferLengthOffset,pStringLengthOffset,pBufferOffset) )
+
+#define ICorProfilerInfo6_GetClassLayout(This,classID,rFieldOffset,cFieldOffset,pcFieldOffset,pulClassSize) \
+ ( (This)->lpVtbl -> GetClassLayout(This,classID,rFieldOffset,cFieldOffset,pcFieldOffset,pulClassSize) )
+
+#define ICorProfilerInfo6_GetClassIDInfo2(This,classId,pModuleId,pTypeDefToken,pParentClassId,cNumTypeArgs,pcNumTypeArgs,typeArgs) \
+ ( (This)->lpVtbl -> GetClassIDInfo2(This,classId,pModuleId,pTypeDefToken,pParentClassId,cNumTypeArgs,pcNumTypeArgs,typeArgs) )
+
+#define ICorProfilerInfo6_GetCodeInfo2(This,functionID,cCodeInfos,pcCodeInfos,codeInfos) \
+ ( (This)->lpVtbl -> GetCodeInfo2(This,functionID,cCodeInfos,pcCodeInfos,codeInfos) )
+
+#define ICorProfilerInfo6_GetClassFromTokenAndTypeArgs(This,moduleID,typeDef,cTypeArgs,typeArgs,pClassID) \
+ ( (This)->lpVtbl -> GetClassFromTokenAndTypeArgs(This,moduleID,typeDef,cTypeArgs,typeArgs,pClassID) )
+
+#define ICorProfilerInfo6_GetFunctionFromTokenAndTypeArgs(This,moduleID,funcDef,classId,cTypeArgs,typeArgs,pFunctionID) \
+ ( (This)->lpVtbl -> GetFunctionFromTokenAndTypeArgs(This,moduleID,funcDef,classId,cTypeArgs,typeArgs,pFunctionID) )
+
+#define ICorProfilerInfo6_EnumModuleFrozenObjects(This,moduleID,ppEnum) \
+ ( (This)->lpVtbl -> EnumModuleFrozenObjects(This,moduleID,ppEnum) )
+
+#define ICorProfilerInfo6_GetArrayObjectInfo(This,objectId,cDimensions,pDimensionSizes,pDimensionLowerBounds,ppData) \
+ ( (This)->lpVtbl -> GetArrayObjectInfo(This,objectId,cDimensions,pDimensionSizes,pDimensionLowerBounds,ppData) )
+
+#define ICorProfilerInfo6_GetBoxClassLayout(This,classId,pBufferOffset) \
+ ( (This)->lpVtbl -> GetBoxClassLayout(This,classId,pBufferOffset) )
+
+#define ICorProfilerInfo6_GetThreadAppDomain(This,threadId,pAppDomainId) \
+ ( (This)->lpVtbl -> GetThreadAppDomain(This,threadId,pAppDomainId) )
+
+#define ICorProfilerInfo6_GetRVAStaticAddress(This,classId,fieldToken,ppAddress) \
+ ( (This)->lpVtbl -> GetRVAStaticAddress(This,classId,fieldToken,ppAddress) )
+
+#define ICorProfilerInfo6_GetAppDomainStaticAddress(This,classId,fieldToken,appDomainId,ppAddress) \
+ ( (This)->lpVtbl -> GetAppDomainStaticAddress(This,classId,fieldToken,appDomainId,ppAddress) )
+
+#define ICorProfilerInfo6_GetThreadStaticAddress(This,classId,fieldToken,threadId,ppAddress) \
+ ( (This)->lpVtbl -> GetThreadStaticAddress(This,classId,fieldToken,threadId,ppAddress) )
+
+#define ICorProfilerInfo6_GetContextStaticAddress(This,classId,fieldToken,contextId,ppAddress) \
+ ( (This)->lpVtbl -> GetContextStaticAddress(This,classId,fieldToken,contextId,ppAddress) )
+
+#define ICorProfilerInfo6_GetStaticFieldInfo(This,classId,fieldToken,pFieldInfo) \
+ ( (This)->lpVtbl -> GetStaticFieldInfo(This,classId,fieldToken,pFieldInfo) )
+
+#define ICorProfilerInfo6_GetGenerationBounds(This,cObjectRanges,pcObjectRanges,ranges) \
+ ( (This)->lpVtbl -> GetGenerationBounds(This,cObjectRanges,pcObjectRanges,ranges) )
+
+#define ICorProfilerInfo6_GetObjectGeneration(This,objectId,range) \
+ ( (This)->lpVtbl -> GetObjectGeneration(This,objectId,range) )
+
+#define ICorProfilerInfo6_GetNotifiedExceptionClauseInfo(This,pinfo) \
+ ( (This)->lpVtbl -> GetNotifiedExceptionClauseInfo(This,pinfo) )
+
+
+#define ICorProfilerInfo6_EnumJITedFunctions(This,ppEnum) \
+ ( (This)->lpVtbl -> EnumJITedFunctions(This,ppEnum) )
+
+#define ICorProfilerInfo6_RequestProfilerDetach(This,dwExpectedCompletionMilliseconds) \
+ ( (This)->lpVtbl -> RequestProfilerDetach(This,dwExpectedCompletionMilliseconds) )
+
+#define ICorProfilerInfo6_SetFunctionIDMapper2(This,pFunc,clientData) \
+ ( (This)->lpVtbl -> SetFunctionIDMapper2(This,pFunc,clientData) )
+
+#define ICorProfilerInfo6_GetStringLayout2(This,pStringLengthOffset,pBufferOffset) \
+ ( (This)->lpVtbl -> GetStringLayout2(This,pStringLengthOffset,pBufferOffset) )
+
+#define ICorProfilerInfo6_SetEnterLeaveFunctionHooks3(This,pFuncEnter3,pFuncLeave3,pFuncTailcall3) \
+ ( (This)->lpVtbl -> SetEnterLeaveFunctionHooks3(This,pFuncEnter3,pFuncLeave3,pFuncTailcall3) )
+
+#define ICorProfilerInfo6_SetEnterLeaveFunctionHooks3WithInfo(This,pFuncEnter3WithInfo,pFuncLeave3WithInfo,pFuncTailcall3WithInfo) \
+ ( (This)->lpVtbl -> SetEnterLeaveFunctionHooks3WithInfo(This,pFuncEnter3WithInfo,pFuncLeave3WithInfo,pFuncTailcall3WithInfo) )
+
+#define ICorProfilerInfo6_GetFunctionEnter3Info(This,functionId,eltInfo,pFrameInfo,pcbArgumentInfo,pArgumentInfo) \
+ ( (This)->lpVtbl -> GetFunctionEnter3Info(This,functionId,eltInfo,pFrameInfo,pcbArgumentInfo,pArgumentInfo) )
+
+#define ICorProfilerInfo6_GetFunctionLeave3Info(This,functionId,eltInfo,pFrameInfo,pRetvalRange) \
+ ( (This)->lpVtbl -> GetFunctionLeave3Info(This,functionId,eltInfo,pFrameInfo,pRetvalRange) )
+
+#define ICorProfilerInfo6_GetFunctionTailcall3Info(This,functionId,eltInfo,pFrameInfo) \
+ ( (This)->lpVtbl -> GetFunctionTailcall3Info(This,functionId,eltInfo,pFrameInfo) )
+
+#define ICorProfilerInfo6_EnumModules(This,ppEnum) \
+ ( (This)->lpVtbl -> EnumModules(This,ppEnum) )
+
+#define ICorProfilerInfo6_GetRuntimeInformation(This,pClrInstanceId,pRuntimeType,pMajorVersion,pMinorVersion,pBuildNumber,pQFEVersion,cchVersionString,pcchVersionString,szVersionString) \
+ ( (This)->lpVtbl -> GetRuntimeInformation(This,pClrInstanceId,pRuntimeType,pMajorVersion,pMinorVersion,pBuildNumber,pQFEVersion,cchVersionString,pcchVersionString,szVersionString) )
+
+#define ICorProfilerInfo6_GetThreadStaticAddress2(This,classId,fieldToken,appDomainId,threadId,ppAddress) \
+ ( (This)->lpVtbl -> GetThreadStaticAddress2(This,classId,fieldToken,appDomainId,threadId,ppAddress) )
+
+#define ICorProfilerInfo6_GetAppDomainsContainingModule(This,moduleId,cAppDomainIds,pcAppDomainIds,appDomainIds) \
+ ( (This)->lpVtbl -> GetAppDomainsContainingModule(This,moduleId,cAppDomainIds,pcAppDomainIds,appDomainIds) )
+
+#define ICorProfilerInfo6_GetModuleInfo2(This,moduleId,ppBaseLoadAddress,cchName,pcchName,szName,pAssemblyId,pdwModuleFlags) \
+ ( (This)->lpVtbl -> GetModuleInfo2(This,moduleId,ppBaseLoadAddress,cchName,pcchName,szName,pAssemblyId,pdwModuleFlags) )
+
+
+#define ICorProfilerInfo6_EnumThreads(This,ppEnum) \
+ ( (This)->lpVtbl -> EnumThreads(This,ppEnum) )
+
+#define ICorProfilerInfo6_InitializeCurrentThread(This) \
+ ( (This)->lpVtbl -> InitializeCurrentThread(This) )
+
+#define ICorProfilerInfo6_RequestReJIT(This,cFunctions,moduleIds,methodIds) \
+ ( (This)->lpVtbl -> RequestReJIT(This,cFunctions,moduleIds,methodIds) )
+
+#define ICorProfilerInfo6_RequestRevert(This,cFunctions,moduleIds,methodIds,status) \
+ ( (This)->lpVtbl -> RequestRevert(This,cFunctions,moduleIds,methodIds,status) )
+
+#define ICorProfilerInfo6_GetCodeInfo3(This,functionID,reJitId,cCodeInfos,pcCodeInfos,codeInfos) \
+ ( (This)->lpVtbl -> GetCodeInfo3(This,functionID,reJitId,cCodeInfos,pcCodeInfos,codeInfos) )
+
+#define ICorProfilerInfo6_GetFunctionFromIP2(This,ip,pFunctionId,pReJitId) \
+ ( (This)->lpVtbl -> GetFunctionFromIP2(This,ip,pFunctionId,pReJitId) )
+
+#define ICorProfilerInfo6_GetReJITIDs(This,functionId,cReJitIds,pcReJitIds,reJitIds) \
+ ( (This)->lpVtbl -> GetReJITIDs(This,functionId,cReJitIds,pcReJitIds,reJitIds) )
+
+#define ICorProfilerInfo6_GetILToNativeMapping2(This,functionId,reJitId,cMap,pcMap,map) \
+ ( (This)->lpVtbl -> GetILToNativeMapping2(This,functionId,reJitId,cMap,pcMap,map) )
+
+#define ICorProfilerInfo6_EnumJITedFunctions2(This,ppEnum) \
+ ( (This)->lpVtbl -> EnumJITedFunctions2(This,ppEnum) )
+
+#define ICorProfilerInfo6_GetObjectSize2(This,objectId,pcSize) \
+ ( (This)->lpVtbl -> GetObjectSize2(This,objectId,pcSize) )
+
+
+#define ICorProfilerInfo6_GetEventMask2(This,pdwEventsLow,pdwEventsHigh) \
+ ( (This)->lpVtbl -> GetEventMask2(This,pdwEventsLow,pdwEventsHigh) )
+
+#define ICorProfilerInfo6_SetEventMask2(This,dwEventsLow,dwEventsHigh) \
+ ( (This)->lpVtbl -> SetEventMask2(This,dwEventsLow,dwEventsHigh) )
+
+
+#define ICorProfilerInfo6_EnumNgenModuleMethodsInliningThisMethod(This,inlinersModuleId,inlineeModuleId,inlineeMethodId,incompleteData,ppEnum) \
+ ( (This)->lpVtbl -> EnumNgenModuleMethodsInliningThisMethod(This,inlinersModuleId,inlineeModuleId,inlineeMethodId,incompleteData,ppEnum) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorProfilerInfo6_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorProfilerInfo7_INTERFACE_DEFINED__
+#define __ICorProfilerInfo7_INTERFACE_DEFINED__
+
+/* interface ICorProfilerInfo7 */
+/* [local][unique][uuid][object] */
+
+
+EXTERN_C const IID IID_ICorProfilerInfo7;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("9AEECC0D-63E0-4187-8C00-E312F503F663")
+ ICorProfilerInfo7 : public ICorProfilerInfo6
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE ApplyMetaData(
+ /* [in] */ ModuleID moduleId) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetInMemorySymbolsLength(
+ /* [in] */ ModuleID moduleId,
+ /* [out] */ DWORD *pCountSymbolBytes) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ReadInMemorySymbols(
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ DWORD symbolsReadOffset,
+ /* [out] */ BYTE *pSymbolBytes,
+ /* [in] */ DWORD countSymbolBytes,
+ /* [out] */ DWORD *pCountSymbolBytesRead) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorProfilerInfo7Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorProfilerInfo7 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorProfilerInfo7 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorProfilerInfo7 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetClassFromObject )(
+ ICorProfilerInfo7 * This,
+ /* [in] */ ObjectID objectId,
+ /* [out] */ ClassID *pClassId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetClassFromToken )(
+ ICorProfilerInfo7 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ mdTypeDef typeDef,
+ /* [out] */ ClassID *pClassId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCodeInfo )(
+ ICorProfilerInfo7 * This,
+ /* [in] */ FunctionID functionId,
+ /* [out] */ LPCBYTE *pStart,
+ /* [out] */ ULONG *pcSize);
+
+ HRESULT ( STDMETHODCALLTYPE *GetEventMask )(
+ ICorProfilerInfo7 * This,
+ /* [out] */ DWORD *pdwEvents);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFunctionFromIP )(
+ ICorProfilerInfo7 * This,
+ /* [in] */ LPCBYTE ip,
+ /* [out] */ FunctionID *pFunctionId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFunctionFromToken )(
+ ICorProfilerInfo7 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ mdToken token,
+ /* [out] */ FunctionID *pFunctionId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetHandleFromThread )(
+ ICorProfilerInfo7 * This,
+ /* [in] */ ThreadID threadId,
+ /* [out] */ HANDLE *phThread);
+
+ HRESULT ( STDMETHODCALLTYPE *GetObjectSize )(
+ ICorProfilerInfo7 * This,
+ /* [in] */ ObjectID objectId,
+ /* [out] */ ULONG *pcSize);
+
+ HRESULT ( STDMETHODCALLTYPE *IsArrayClass )(
+ ICorProfilerInfo7 * This,
+ /* [in] */ ClassID classId,
+ /* [out] */ CorElementType *pBaseElemType,
+ /* [out] */ ClassID *pBaseClassId,
+ /* [out] */ ULONG *pcRank);
+
+ HRESULT ( STDMETHODCALLTYPE *GetThreadInfo )(
+ ICorProfilerInfo7 * This,
+ /* [in] */ ThreadID threadId,
+ /* [out] */ DWORD *pdwWin32ThreadId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCurrentThreadID )(
+ ICorProfilerInfo7 * This,
+ /* [out] */ ThreadID *pThreadId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetClassIDInfo )(
+ ICorProfilerInfo7 * This,
+ /* [in] */ ClassID classId,
+ /* [out] */ ModuleID *pModuleId,
+ /* [out] */ mdTypeDef *pTypeDefToken);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFunctionInfo )(
+ ICorProfilerInfo7 * This,
+ /* [in] */ FunctionID functionId,
+ /* [out] */ ClassID *pClassId,
+ /* [out] */ ModuleID *pModuleId,
+ /* [out] */ mdToken *pToken);
+
+ HRESULT ( STDMETHODCALLTYPE *SetEventMask )(
+ ICorProfilerInfo7 * This,
+ /* [in] */ DWORD dwEvents);
+
+ HRESULT ( STDMETHODCALLTYPE *SetEnterLeaveFunctionHooks )(
+ ICorProfilerInfo7 * This,
+ /* [in] */ FunctionEnter *pFuncEnter,
+ /* [in] */ FunctionLeave *pFuncLeave,
+ /* [in] */ FunctionTailcall *pFuncTailcall);
+
+ HRESULT ( STDMETHODCALLTYPE *SetFunctionIDMapper )(
+ ICorProfilerInfo7 * This,
+ /* [in] */ FunctionIDMapper *pFunc);
+
+ HRESULT ( STDMETHODCALLTYPE *GetTokenAndMetaDataFromFunction )(
+ ICorProfilerInfo7 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ REFIID riid,
+ /* [out] */ IUnknown **ppImport,
+ /* [out] */ mdToken *pToken);
+
+ HRESULT ( STDMETHODCALLTYPE *GetModuleInfo )(
+ ICorProfilerInfo7 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [out] */ LPCBYTE *ppBaseLoadAddress,
+ /* [in] */ ULONG cchName,
+ /* [out] */ ULONG *pcchName,
+ /* [annotation][out] */
+ _Out_writes_to_(cchName, *pcchName) WCHAR szName[ ],
+ /* [out] */ AssemblyID *pAssemblyId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetModuleMetaData )(
+ ICorProfilerInfo7 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ DWORD dwOpenFlags,
+ /* [in] */ REFIID riid,
+ /* [out] */ IUnknown **ppOut);
+
+ HRESULT ( STDMETHODCALLTYPE *GetILFunctionBody )(
+ ICorProfilerInfo7 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ mdMethodDef methodId,
+ /* [out] */ LPCBYTE *ppMethodHeader,
+ /* [out] */ ULONG *pcbMethodSize);
+
+ HRESULT ( STDMETHODCALLTYPE *GetILFunctionBodyAllocator )(
+ ICorProfilerInfo7 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [out] */ IMethodMalloc **ppMalloc);
+
+ HRESULT ( STDMETHODCALLTYPE *SetILFunctionBody )(
+ ICorProfilerInfo7 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ mdMethodDef methodid,
+ /* [in] */ LPCBYTE pbNewILMethodHeader);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAppDomainInfo )(
+ ICorProfilerInfo7 * This,
+ /* [in] */ AppDomainID appDomainId,
+ /* [in] */ ULONG cchName,
+ /* [out] */ ULONG *pcchName,
+ /* [annotation][out] */
+ _Out_writes_to_(cchName, *pcchName) WCHAR szName[ ],
+ /* [out] */ ProcessID *pProcessId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAssemblyInfo )(
+ ICorProfilerInfo7 * This,
+ /* [in] */ AssemblyID assemblyId,
+ /* [in] */ ULONG cchName,
+ /* [out] */ ULONG *pcchName,
+ /* [annotation][out] */
+ _Out_writes_to_(cchName, *pcchName) WCHAR szName[ ],
+ /* [out] */ AppDomainID *pAppDomainId,
+ /* [out] */ ModuleID *pModuleId);
+
+ HRESULT ( STDMETHODCALLTYPE *SetFunctionReJIT )(
+ ICorProfilerInfo7 * This,
+ /* [in] */ FunctionID functionId);
+
+ HRESULT ( STDMETHODCALLTYPE *ForceGC )(
+ ICorProfilerInfo7 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *SetILInstrumentedCodeMap )(
+ ICorProfilerInfo7 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ BOOL fStartJit,
+ /* [in] */ ULONG cILMapEntries,
+ /* [size_is][in] */ COR_IL_MAP rgILMapEntries[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetInprocInspectionInterface )(
+ ICorProfilerInfo7 * This,
+ /* [out] */ IUnknown **ppicd);
+
+ HRESULT ( STDMETHODCALLTYPE *GetInprocInspectionIThisThread )(
+ ICorProfilerInfo7 * This,
+ /* [out] */ IUnknown **ppicd);
+
+ HRESULT ( STDMETHODCALLTYPE *GetThreadContext )(
+ ICorProfilerInfo7 * This,
+ /* [in] */ ThreadID threadId,
+ /* [out] */ ContextID *pContextId);
+
+ HRESULT ( STDMETHODCALLTYPE *BeginInprocDebugging )(
+ ICorProfilerInfo7 * This,
+ /* [in] */ BOOL fThisThreadOnly,
+ /* [out] */ DWORD *pdwProfilerContext);
+
+ HRESULT ( STDMETHODCALLTYPE *EndInprocDebugging )(
+ ICorProfilerInfo7 * This,
+ /* [in] */ DWORD dwProfilerContext);
+
+ HRESULT ( STDMETHODCALLTYPE *GetILToNativeMapping )(
+ ICorProfilerInfo7 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ ULONG32 cMap,
+ /* [out] */ ULONG32 *pcMap,
+ /* [length_is][size_is][out] */ COR_DEBUG_IL_TO_NATIVE_MAP map[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *DoStackSnapshot )(
+ ICorProfilerInfo7 * This,
+ /* [in] */ ThreadID thread,
+ /* [in] */ StackSnapshotCallback *callback,
+ /* [in] */ ULONG32 infoFlags,
+ /* [in] */ void *clientData,
+ /* [size_is][in] */ BYTE context[ ],
+ /* [in] */ ULONG32 contextSize);
+
+ HRESULT ( STDMETHODCALLTYPE *SetEnterLeaveFunctionHooks2 )(
+ ICorProfilerInfo7 * This,
+ /* [in] */ FunctionEnter2 *pFuncEnter,
+ /* [in] */ FunctionLeave2 *pFuncLeave,
+ /* [in] */ FunctionTailcall2 *pFuncTailcall);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFunctionInfo2 )(
+ ICorProfilerInfo7 * This,
+ /* [in] */ FunctionID funcId,
+ /* [in] */ COR_PRF_FRAME_INFO frameInfo,
+ /* [out] */ ClassID *pClassId,
+ /* [out] */ ModuleID *pModuleId,
+ /* [out] */ mdToken *pToken,
+ /* [in] */ ULONG32 cTypeArgs,
+ /* [out] */ ULONG32 *pcTypeArgs,
+ /* [out] */ ClassID typeArgs[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetStringLayout )(
+ ICorProfilerInfo7 * This,
+ /* [out] */ ULONG *pBufferLengthOffset,
+ /* [out] */ ULONG *pStringLengthOffset,
+ /* [out] */ ULONG *pBufferOffset);
+
+ HRESULT ( STDMETHODCALLTYPE *GetClassLayout )(
+ ICorProfilerInfo7 * This,
+ /* [in] */ ClassID classID,
+ /* [out][in] */ COR_FIELD_OFFSET rFieldOffset[ ],
+ /* [in] */ ULONG cFieldOffset,
+ /* [out] */ ULONG *pcFieldOffset,
+ /* [out] */ ULONG *pulClassSize);
+
+ HRESULT ( STDMETHODCALLTYPE *GetClassIDInfo2 )(
+ ICorProfilerInfo7 * This,
+ /* [in] */ ClassID classId,
+ /* [out] */ ModuleID *pModuleId,
+ /* [out] */ mdTypeDef *pTypeDefToken,
+ /* [out] */ ClassID *pParentClassId,
+ /* [in] */ ULONG32 cNumTypeArgs,
+ /* [out] */ ULONG32 *pcNumTypeArgs,
+ /* [out] */ ClassID typeArgs[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCodeInfo2 )(
+ ICorProfilerInfo7 * This,
+ /* [in] */ FunctionID functionID,
+ /* [in] */ ULONG32 cCodeInfos,
+ /* [out] */ ULONG32 *pcCodeInfos,
+ /* [length_is][size_is][out] */ COR_PRF_CODE_INFO codeInfos[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetClassFromTokenAndTypeArgs )(
+ ICorProfilerInfo7 * This,
+ /* [in] */ ModuleID moduleID,
+ /* [in] */ mdTypeDef typeDef,
+ /* [in] */ ULONG32 cTypeArgs,
+ /* [size_is][in] */ ClassID typeArgs[ ],
+ /* [out] */ ClassID *pClassID);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFunctionFromTokenAndTypeArgs )(
+ ICorProfilerInfo7 * This,
+ /* [in] */ ModuleID moduleID,
+ /* [in] */ mdMethodDef funcDef,
+ /* [in] */ ClassID classId,
+ /* [in] */ ULONG32 cTypeArgs,
+ /* [size_is][in] */ ClassID typeArgs[ ],
+ /* [out] */ FunctionID *pFunctionID);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumModuleFrozenObjects )(
+ ICorProfilerInfo7 * This,
+ /* [in] */ ModuleID moduleID,
+ /* [out] */ ICorProfilerObjectEnum **ppEnum);
+
+ HRESULT ( STDMETHODCALLTYPE *GetArrayObjectInfo )(
+ ICorProfilerInfo7 * This,
+ /* [in] */ ObjectID objectId,
+ /* [in] */ ULONG32 cDimensions,
+ /* [size_is][out] */ ULONG32 pDimensionSizes[ ],
+ /* [size_is][out] */ int pDimensionLowerBounds[ ],
+ /* [out] */ BYTE **ppData);
+
+ HRESULT ( STDMETHODCALLTYPE *GetBoxClassLayout )(
+ ICorProfilerInfo7 * This,
+ /* [in] */ ClassID classId,
+ /* [out] */ ULONG32 *pBufferOffset);
+
+ HRESULT ( STDMETHODCALLTYPE *GetThreadAppDomain )(
+ ICorProfilerInfo7 * This,
+ /* [in] */ ThreadID threadId,
+ /* [out] */ AppDomainID *pAppDomainId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetRVAStaticAddress )(
+ ICorProfilerInfo7 * This,
+ /* [in] */ ClassID classId,
+ /* [in] */ mdFieldDef fieldToken,
+ /* [out] */ void **ppAddress);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAppDomainStaticAddress )(
+ ICorProfilerInfo7 * This,
+ /* [in] */ ClassID classId,
+ /* [in] */ mdFieldDef fieldToken,
+ /* [in] */ AppDomainID appDomainId,
+ /* [out] */ void **ppAddress);
+
+ HRESULT ( STDMETHODCALLTYPE *GetThreadStaticAddress )(
+ ICorProfilerInfo7 * This,
+ /* [in] */ ClassID classId,
+ /* [in] */ mdFieldDef fieldToken,
+ /* [in] */ ThreadID threadId,
+ /* [out] */ void **ppAddress);
+
+ HRESULT ( STDMETHODCALLTYPE *GetContextStaticAddress )(
+ ICorProfilerInfo7 * This,
+ /* [in] */ ClassID classId,
+ /* [in] */ mdFieldDef fieldToken,
+ /* [in] */ ContextID contextId,
+ /* [out] */ void **ppAddress);
+
+ HRESULT ( STDMETHODCALLTYPE *GetStaticFieldInfo )(
+ ICorProfilerInfo7 * This,
+ /* [in] */ ClassID classId,
+ /* [in] */ mdFieldDef fieldToken,
+ /* [out] */ COR_PRF_STATIC_TYPE *pFieldInfo);
+
+ HRESULT ( STDMETHODCALLTYPE *GetGenerationBounds )(
+ ICorProfilerInfo7 * This,
+ /* [in] */ ULONG cObjectRanges,
+ /* [out] */ ULONG *pcObjectRanges,
+ /* [length_is][size_is][out] */ COR_PRF_GC_GENERATION_RANGE ranges[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetObjectGeneration )(
+ ICorProfilerInfo7 * This,
+ /* [in] */ ObjectID objectId,
+ /* [out] */ COR_PRF_GC_GENERATION_RANGE *range);
+
+ HRESULT ( STDMETHODCALLTYPE *GetNotifiedExceptionClauseInfo )(
+ ICorProfilerInfo7 * This,
+ /* [out] */ COR_PRF_EX_CLAUSE_INFO *pinfo);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumJITedFunctions )(
+ ICorProfilerInfo7 * This,
+ /* [out] */ ICorProfilerFunctionEnum **ppEnum);
+
+ HRESULT ( STDMETHODCALLTYPE *RequestProfilerDetach )(
+ ICorProfilerInfo7 * This,
+ /* [in] */ DWORD dwExpectedCompletionMilliseconds);
+
+ HRESULT ( STDMETHODCALLTYPE *SetFunctionIDMapper2 )(
+ ICorProfilerInfo7 * This,
+ /* [in] */ FunctionIDMapper2 *pFunc,
+ /* [in] */ void *clientData);
+
+ HRESULT ( STDMETHODCALLTYPE *GetStringLayout2 )(
+ ICorProfilerInfo7 * This,
+ /* [out] */ ULONG *pStringLengthOffset,
+ /* [out] */ ULONG *pBufferOffset);
+
+ HRESULT ( STDMETHODCALLTYPE *SetEnterLeaveFunctionHooks3 )(
+ ICorProfilerInfo7 * This,
+ /* [in] */ FunctionEnter3 *pFuncEnter3,
+ /* [in] */ FunctionLeave3 *pFuncLeave3,
+ /* [in] */ FunctionTailcall3 *pFuncTailcall3);
+
+ HRESULT ( STDMETHODCALLTYPE *SetEnterLeaveFunctionHooks3WithInfo )(
+ ICorProfilerInfo7 * This,
+ /* [in] */ FunctionEnter3WithInfo *pFuncEnter3WithInfo,
+ /* [in] */ FunctionLeave3WithInfo *pFuncLeave3WithInfo,
+ /* [in] */ FunctionTailcall3WithInfo *pFuncTailcall3WithInfo);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFunctionEnter3Info )(
+ ICorProfilerInfo7 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ COR_PRF_ELT_INFO eltInfo,
+ /* [out] */ COR_PRF_FRAME_INFO *pFrameInfo,
+ /* [out][in] */ ULONG *pcbArgumentInfo,
+ /* [size_is][out] */ COR_PRF_FUNCTION_ARGUMENT_INFO *pArgumentInfo);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFunctionLeave3Info )(
+ ICorProfilerInfo7 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ COR_PRF_ELT_INFO eltInfo,
+ /* [out] */ COR_PRF_FRAME_INFO *pFrameInfo,
+ /* [out] */ COR_PRF_FUNCTION_ARGUMENT_RANGE *pRetvalRange);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFunctionTailcall3Info )(
+ ICorProfilerInfo7 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ COR_PRF_ELT_INFO eltInfo,
+ /* [out] */ COR_PRF_FRAME_INFO *pFrameInfo);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumModules )(
+ ICorProfilerInfo7 * This,
+ /* [out] */ ICorProfilerModuleEnum **ppEnum);
+
+ HRESULT ( STDMETHODCALLTYPE *GetRuntimeInformation )(
+ ICorProfilerInfo7 * This,
+ /* [out] */ USHORT *pClrInstanceId,
+ /* [out] */ COR_PRF_RUNTIME_TYPE *pRuntimeType,
+ /* [out] */ USHORT *pMajorVersion,
+ /* [out] */ USHORT *pMinorVersion,
+ /* [out] */ USHORT *pBuildNumber,
+ /* [out] */ USHORT *pQFEVersion,
+ /* [in] */ ULONG cchVersionString,
+ /* [out] */ ULONG *pcchVersionString,
+ /* [annotation][out] */
+ _Out_writes_to_(cchVersionString, *pcchVersionString) WCHAR szVersionString[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetThreadStaticAddress2 )(
+ ICorProfilerInfo7 * This,
+ /* [in] */ ClassID classId,
+ /* [in] */ mdFieldDef fieldToken,
+ /* [in] */ AppDomainID appDomainId,
+ /* [in] */ ThreadID threadId,
+ /* [out] */ void **ppAddress);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAppDomainsContainingModule )(
+ ICorProfilerInfo7 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ ULONG32 cAppDomainIds,
+ /* [out] */ ULONG32 *pcAppDomainIds,
+ /* [length_is][size_is][out] */ AppDomainID appDomainIds[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetModuleInfo2 )(
+ ICorProfilerInfo7 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [out] */ LPCBYTE *ppBaseLoadAddress,
+ /* [in] */ ULONG cchName,
+ /* [out] */ ULONG *pcchName,
+ /* [annotation][out] */
+ _Out_writes_to_(cchName, *pcchName) WCHAR szName[ ],
+ /* [out] */ AssemblyID *pAssemblyId,
+ /* [out] */ DWORD *pdwModuleFlags);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumThreads )(
+ ICorProfilerInfo7 * This,
+ /* [out] */ ICorProfilerThreadEnum **ppEnum);
+
+ HRESULT ( STDMETHODCALLTYPE *InitializeCurrentThread )(
+ ICorProfilerInfo7 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *RequestReJIT )(
+ ICorProfilerInfo7 * This,
+ /* [in] */ ULONG cFunctions,
+ /* [size_is][in] */ ModuleID moduleIds[ ],
+ /* [size_is][in] */ mdMethodDef methodIds[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *RequestRevert )(
+ ICorProfilerInfo7 * This,
+ /* [in] */ ULONG cFunctions,
+ /* [size_is][in] */ ModuleID moduleIds[ ],
+ /* [size_is][in] */ mdMethodDef methodIds[ ],
+ /* [size_is][out] */ HRESULT status[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCodeInfo3 )(
+ ICorProfilerInfo7 * This,
+ /* [in] */ FunctionID functionID,
+ /* [in] */ ReJITID reJitId,
+ /* [in] */ ULONG32 cCodeInfos,
+ /* [out] */ ULONG32 *pcCodeInfos,
+ /* [length_is][size_is][out] */ COR_PRF_CODE_INFO codeInfos[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFunctionFromIP2 )(
+ ICorProfilerInfo7 * This,
+ /* [in] */ LPCBYTE ip,
+ /* [out] */ FunctionID *pFunctionId,
+ /* [out] */ ReJITID *pReJitId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetReJITIDs )(
+ ICorProfilerInfo7 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ ULONG cReJitIds,
+ /* [out] */ ULONG *pcReJitIds,
+ /* [length_is][size_is][out] */ ReJITID reJitIds[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetILToNativeMapping2 )(
+ ICorProfilerInfo7 * This,
+ /* [in] */ FunctionID functionId,
+ /* [in] */ ReJITID reJitId,
+ /* [in] */ ULONG32 cMap,
+ /* [out] */ ULONG32 *pcMap,
+ /* [length_is][size_is][out] */ COR_DEBUG_IL_TO_NATIVE_MAP map[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumJITedFunctions2 )(
+ ICorProfilerInfo7 * This,
+ /* [out] */ ICorProfilerFunctionEnum **ppEnum);
+
+ HRESULT ( STDMETHODCALLTYPE *GetObjectSize2 )(
+ ICorProfilerInfo7 * This,
+ /* [in] */ ObjectID objectId,
+ /* [out] */ SIZE_T *pcSize);
+
+ HRESULT ( STDMETHODCALLTYPE *GetEventMask2 )(
+ ICorProfilerInfo7 * This,
+ /* [out] */ DWORD *pdwEventsLow,
+ /* [out] */ DWORD *pdwEventsHigh);
+
+ HRESULT ( STDMETHODCALLTYPE *SetEventMask2 )(
+ ICorProfilerInfo7 * This,
+ /* [in] */ DWORD dwEventsLow,
+ /* [in] */ DWORD dwEventsHigh);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumNgenModuleMethodsInliningThisMethod )(
+ ICorProfilerInfo7 * This,
+ /* [in] */ ModuleID inlinersModuleId,
+ /* [in] */ ModuleID inlineeModuleId,
+ /* [in] */ mdMethodDef inlineeMethodId,
+ /* [out] */ BOOL *incompleteData,
+ /* [out] */ ICorProfilerMethodEnum **ppEnum);
+
+ HRESULT ( STDMETHODCALLTYPE *ApplyMetaData )(
+ ICorProfilerInfo7 * This,
+ /* [in] */ ModuleID moduleId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetInMemorySymbolsLength )(
+ ICorProfilerInfo7 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [out] */ DWORD *pCountSymbolBytes);
+
+ HRESULT ( STDMETHODCALLTYPE *ReadInMemorySymbols )(
+ ICorProfilerInfo7 * This,
+ /* [in] */ ModuleID moduleId,
+ /* [in] */ DWORD symbolsReadOffset,
+ /* [out] */ BYTE *pSymbolBytes,
+ /* [in] */ DWORD countSymbolBytes,
+ /* [out] */ DWORD *pCountSymbolBytesRead);
+
+ END_INTERFACE
+ } ICorProfilerInfo7Vtbl;
+
+ interface ICorProfilerInfo7
+ {
+ CONST_VTBL struct ICorProfilerInfo7Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorProfilerInfo7_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorProfilerInfo7_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorProfilerInfo7_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorProfilerInfo7_GetClassFromObject(This,objectId,pClassId) \
+ ( (This)->lpVtbl -> GetClassFromObject(This,objectId,pClassId) )
+
+#define ICorProfilerInfo7_GetClassFromToken(This,moduleId,typeDef,pClassId) \
+ ( (This)->lpVtbl -> GetClassFromToken(This,moduleId,typeDef,pClassId) )
+
+#define ICorProfilerInfo7_GetCodeInfo(This,functionId,pStart,pcSize) \
+ ( (This)->lpVtbl -> GetCodeInfo(This,functionId,pStart,pcSize) )
+
+#define ICorProfilerInfo7_GetEventMask(This,pdwEvents) \
+ ( (This)->lpVtbl -> GetEventMask(This,pdwEvents) )
+
+#define ICorProfilerInfo7_GetFunctionFromIP(This,ip,pFunctionId) \
+ ( (This)->lpVtbl -> GetFunctionFromIP(This,ip,pFunctionId) )
+
+#define ICorProfilerInfo7_GetFunctionFromToken(This,moduleId,token,pFunctionId) \
+ ( (This)->lpVtbl -> GetFunctionFromToken(This,moduleId,token,pFunctionId) )
+
+#define ICorProfilerInfo7_GetHandleFromThread(This,threadId,phThread) \
+ ( (This)->lpVtbl -> GetHandleFromThread(This,threadId,phThread) )
+
+#define ICorProfilerInfo7_GetObjectSize(This,objectId,pcSize) \
+ ( (This)->lpVtbl -> GetObjectSize(This,objectId,pcSize) )
+
+#define ICorProfilerInfo7_IsArrayClass(This,classId,pBaseElemType,pBaseClassId,pcRank) \
+ ( (This)->lpVtbl -> IsArrayClass(This,classId,pBaseElemType,pBaseClassId,pcRank) )
+
+#define ICorProfilerInfo7_GetThreadInfo(This,threadId,pdwWin32ThreadId) \
+ ( (This)->lpVtbl -> GetThreadInfo(This,threadId,pdwWin32ThreadId) )
+
+#define ICorProfilerInfo7_GetCurrentThreadID(This,pThreadId) \
+ ( (This)->lpVtbl -> GetCurrentThreadID(This,pThreadId) )
+
+#define ICorProfilerInfo7_GetClassIDInfo(This,classId,pModuleId,pTypeDefToken) \
+ ( (This)->lpVtbl -> GetClassIDInfo(This,classId,pModuleId,pTypeDefToken) )
+
+#define ICorProfilerInfo7_GetFunctionInfo(This,functionId,pClassId,pModuleId,pToken) \
+ ( (This)->lpVtbl -> GetFunctionInfo(This,functionId,pClassId,pModuleId,pToken) )
+
+#define ICorProfilerInfo7_SetEventMask(This,dwEvents) \
+ ( (This)->lpVtbl -> SetEventMask(This,dwEvents) )
+
+#define ICorProfilerInfo7_SetEnterLeaveFunctionHooks(This,pFuncEnter,pFuncLeave,pFuncTailcall) \
+ ( (This)->lpVtbl -> SetEnterLeaveFunctionHooks(This,pFuncEnter,pFuncLeave,pFuncTailcall) )
+
+#define ICorProfilerInfo7_SetFunctionIDMapper(This,pFunc) \
+ ( (This)->lpVtbl -> SetFunctionIDMapper(This,pFunc) )
+
+#define ICorProfilerInfo7_GetTokenAndMetaDataFromFunction(This,functionId,riid,ppImport,pToken) \
+ ( (This)->lpVtbl -> GetTokenAndMetaDataFromFunction(This,functionId,riid,ppImport,pToken) )
+
+#define ICorProfilerInfo7_GetModuleInfo(This,moduleId,ppBaseLoadAddress,cchName,pcchName,szName,pAssemblyId) \
+ ( (This)->lpVtbl -> GetModuleInfo(This,moduleId,ppBaseLoadAddress,cchName,pcchName,szName,pAssemblyId) )
+
+#define ICorProfilerInfo7_GetModuleMetaData(This,moduleId,dwOpenFlags,riid,ppOut) \
+ ( (This)->lpVtbl -> GetModuleMetaData(This,moduleId,dwOpenFlags,riid,ppOut) )
+
+#define ICorProfilerInfo7_GetILFunctionBody(This,moduleId,methodId,ppMethodHeader,pcbMethodSize) \
+ ( (This)->lpVtbl -> GetILFunctionBody(This,moduleId,methodId,ppMethodHeader,pcbMethodSize) )
+
+#define ICorProfilerInfo7_GetILFunctionBodyAllocator(This,moduleId,ppMalloc) \
+ ( (This)->lpVtbl -> GetILFunctionBodyAllocator(This,moduleId,ppMalloc) )
+
+#define ICorProfilerInfo7_SetILFunctionBody(This,moduleId,methodid,pbNewILMethodHeader) \
+ ( (This)->lpVtbl -> SetILFunctionBody(This,moduleId,methodid,pbNewILMethodHeader) )
+
+#define ICorProfilerInfo7_GetAppDomainInfo(This,appDomainId,cchName,pcchName,szName,pProcessId) \
+ ( (This)->lpVtbl -> GetAppDomainInfo(This,appDomainId,cchName,pcchName,szName,pProcessId) )
+
+#define ICorProfilerInfo7_GetAssemblyInfo(This,assemblyId,cchName,pcchName,szName,pAppDomainId,pModuleId) \
+ ( (This)->lpVtbl -> GetAssemblyInfo(This,assemblyId,cchName,pcchName,szName,pAppDomainId,pModuleId) )
+
+#define ICorProfilerInfo7_SetFunctionReJIT(This,functionId) \
+ ( (This)->lpVtbl -> SetFunctionReJIT(This,functionId) )
+
+#define ICorProfilerInfo7_ForceGC(This) \
+ ( (This)->lpVtbl -> ForceGC(This) )
+
+#define ICorProfilerInfo7_SetILInstrumentedCodeMap(This,functionId,fStartJit,cILMapEntries,rgILMapEntries) \
+ ( (This)->lpVtbl -> SetILInstrumentedCodeMap(This,functionId,fStartJit,cILMapEntries,rgILMapEntries) )
+
+#define ICorProfilerInfo7_GetInprocInspectionInterface(This,ppicd) \
+ ( (This)->lpVtbl -> GetInprocInspectionInterface(This,ppicd) )
+
+#define ICorProfilerInfo7_GetInprocInspectionIThisThread(This,ppicd) \
+ ( (This)->lpVtbl -> GetInprocInspectionIThisThread(This,ppicd) )
+
+#define ICorProfilerInfo7_GetThreadContext(This,threadId,pContextId) \
+ ( (This)->lpVtbl -> GetThreadContext(This,threadId,pContextId) )
+
+#define ICorProfilerInfo7_BeginInprocDebugging(This,fThisThreadOnly,pdwProfilerContext) \
+ ( (This)->lpVtbl -> BeginInprocDebugging(This,fThisThreadOnly,pdwProfilerContext) )
+
+#define ICorProfilerInfo7_EndInprocDebugging(This,dwProfilerContext) \
+ ( (This)->lpVtbl -> EndInprocDebugging(This,dwProfilerContext) )
+
+#define ICorProfilerInfo7_GetILToNativeMapping(This,functionId,cMap,pcMap,map) \
+ ( (This)->lpVtbl -> GetILToNativeMapping(This,functionId,cMap,pcMap,map) )
+
+
+#define ICorProfilerInfo7_DoStackSnapshot(This,thread,callback,infoFlags,clientData,context,contextSize) \
+ ( (This)->lpVtbl -> DoStackSnapshot(This,thread,callback,infoFlags,clientData,context,contextSize) )
+
+#define ICorProfilerInfo7_SetEnterLeaveFunctionHooks2(This,pFuncEnter,pFuncLeave,pFuncTailcall) \
+ ( (This)->lpVtbl -> SetEnterLeaveFunctionHooks2(This,pFuncEnter,pFuncLeave,pFuncTailcall) )
+
+#define ICorProfilerInfo7_GetFunctionInfo2(This,funcId,frameInfo,pClassId,pModuleId,pToken,cTypeArgs,pcTypeArgs,typeArgs) \
+ ( (This)->lpVtbl -> GetFunctionInfo2(This,funcId,frameInfo,pClassId,pModuleId,pToken,cTypeArgs,pcTypeArgs,typeArgs) )
+
+#define ICorProfilerInfo7_GetStringLayout(This,pBufferLengthOffset,pStringLengthOffset,pBufferOffset) \
+ ( (This)->lpVtbl -> GetStringLayout(This,pBufferLengthOffset,pStringLengthOffset,pBufferOffset) )
+
+#define ICorProfilerInfo7_GetClassLayout(This,classID,rFieldOffset,cFieldOffset,pcFieldOffset,pulClassSize) \
+ ( (This)->lpVtbl -> GetClassLayout(This,classID,rFieldOffset,cFieldOffset,pcFieldOffset,pulClassSize) )
+
+#define ICorProfilerInfo7_GetClassIDInfo2(This,classId,pModuleId,pTypeDefToken,pParentClassId,cNumTypeArgs,pcNumTypeArgs,typeArgs) \
+ ( (This)->lpVtbl -> GetClassIDInfo2(This,classId,pModuleId,pTypeDefToken,pParentClassId,cNumTypeArgs,pcNumTypeArgs,typeArgs) )
+
+#define ICorProfilerInfo7_GetCodeInfo2(This,functionID,cCodeInfos,pcCodeInfos,codeInfos) \
+ ( (This)->lpVtbl -> GetCodeInfo2(This,functionID,cCodeInfos,pcCodeInfos,codeInfos) )
+
+#define ICorProfilerInfo7_GetClassFromTokenAndTypeArgs(This,moduleID,typeDef,cTypeArgs,typeArgs,pClassID) \
+ ( (This)->lpVtbl -> GetClassFromTokenAndTypeArgs(This,moduleID,typeDef,cTypeArgs,typeArgs,pClassID) )
+
+#define ICorProfilerInfo7_GetFunctionFromTokenAndTypeArgs(This,moduleID,funcDef,classId,cTypeArgs,typeArgs,pFunctionID) \
+ ( (This)->lpVtbl -> GetFunctionFromTokenAndTypeArgs(This,moduleID,funcDef,classId,cTypeArgs,typeArgs,pFunctionID) )
+
+#define ICorProfilerInfo7_EnumModuleFrozenObjects(This,moduleID,ppEnum) \
+ ( (This)->lpVtbl -> EnumModuleFrozenObjects(This,moduleID,ppEnum) )
+
+#define ICorProfilerInfo7_GetArrayObjectInfo(This,objectId,cDimensions,pDimensionSizes,pDimensionLowerBounds,ppData) \
+ ( (This)->lpVtbl -> GetArrayObjectInfo(This,objectId,cDimensions,pDimensionSizes,pDimensionLowerBounds,ppData) )
+
+#define ICorProfilerInfo7_GetBoxClassLayout(This,classId,pBufferOffset) \
+ ( (This)->lpVtbl -> GetBoxClassLayout(This,classId,pBufferOffset) )
+
+#define ICorProfilerInfo7_GetThreadAppDomain(This,threadId,pAppDomainId) \
+ ( (This)->lpVtbl -> GetThreadAppDomain(This,threadId,pAppDomainId) )
+
+#define ICorProfilerInfo7_GetRVAStaticAddress(This,classId,fieldToken,ppAddress) \
+ ( (This)->lpVtbl -> GetRVAStaticAddress(This,classId,fieldToken,ppAddress) )
+
+#define ICorProfilerInfo7_GetAppDomainStaticAddress(This,classId,fieldToken,appDomainId,ppAddress) \
+ ( (This)->lpVtbl -> GetAppDomainStaticAddress(This,classId,fieldToken,appDomainId,ppAddress) )
+
+#define ICorProfilerInfo7_GetThreadStaticAddress(This,classId,fieldToken,threadId,ppAddress) \
+ ( (This)->lpVtbl -> GetThreadStaticAddress(This,classId,fieldToken,threadId,ppAddress) )
+
+#define ICorProfilerInfo7_GetContextStaticAddress(This,classId,fieldToken,contextId,ppAddress) \
+ ( (This)->lpVtbl -> GetContextStaticAddress(This,classId,fieldToken,contextId,ppAddress) )
+
+#define ICorProfilerInfo7_GetStaticFieldInfo(This,classId,fieldToken,pFieldInfo) \
+ ( (This)->lpVtbl -> GetStaticFieldInfo(This,classId,fieldToken,pFieldInfo) )
+
+#define ICorProfilerInfo7_GetGenerationBounds(This,cObjectRanges,pcObjectRanges,ranges) \
+ ( (This)->lpVtbl -> GetGenerationBounds(This,cObjectRanges,pcObjectRanges,ranges) )
+
+#define ICorProfilerInfo7_GetObjectGeneration(This,objectId,range) \
+ ( (This)->lpVtbl -> GetObjectGeneration(This,objectId,range) )
+
+#define ICorProfilerInfo7_GetNotifiedExceptionClauseInfo(This,pinfo) \
+ ( (This)->lpVtbl -> GetNotifiedExceptionClauseInfo(This,pinfo) )
+
+
+#define ICorProfilerInfo7_EnumJITedFunctions(This,ppEnum) \
+ ( (This)->lpVtbl -> EnumJITedFunctions(This,ppEnum) )
+
+#define ICorProfilerInfo7_RequestProfilerDetach(This,dwExpectedCompletionMilliseconds) \
+ ( (This)->lpVtbl -> RequestProfilerDetach(This,dwExpectedCompletionMilliseconds) )
+
+#define ICorProfilerInfo7_SetFunctionIDMapper2(This,pFunc,clientData) \
+ ( (This)->lpVtbl -> SetFunctionIDMapper2(This,pFunc,clientData) )
+
+#define ICorProfilerInfo7_GetStringLayout2(This,pStringLengthOffset,pBufferOffset) \
+ ( (This)->lpVtbl -> GetStringLayout2(This,pStringLengthOffset,pBufferOffset) )
+
+#define ICorProfilerInfo7_SetEnterLeaveFunctionHooks3(This,pFuncEnter3,pFuncLeave3,pFuncTailcall3) \
+ ( (This)->lpVtbl -> SetEnterLeaveFunctionHooks3(This,pFuncEnter3,pFuncLeave3,pFuncTailcall3) )
+
+#define ICorProfilerInfo7_SetEnterLeaveFunctionHooks3WithInfo(This,pFuncEnter3WithInfo,pFuncLeave3WithInfo,pFuncTailcall3WithInfo) \
+ ( (This)->lpVtbl -> SetEnterLeaveFunctionHooks3WithInfo(This,pFuncEnter3WithInfo,pFuncLeave3WithInfo,pFuncTailcall3WithInfo) )
+
+#define ICorProfilerInfo7_GetFunctionEnter3Info(This,functionId,eltInfo,pFrameInfo,pcbArgumentInfo,pArgumentInfo) \
+ ( (This)->lpVtbl -> GetFunctionEnter3Info(This,functionId,eltInfo,pFrameInfo,pcbArgumentInfo,pArgumentInfo) )
+
+#define ICorProfilerInfo7_GetFunctionLeave3Info(This,functionId,eltInfo,pFrameInfo,pRetvalRange) \
+ ( (This)->lpVtbl -> GetFunctionLeave3Info(This,functionId,eltInfo,pFrameInfo,pRetvalRange) )
+
+#define ICorProfilerInfo7_GetFunctionTailcall3Info(This,functionId,eltInfo,pFrameInfo) \
+ ( (This)->lpVtbl -> GetFunctionTailcall3Info(This,functionId,eltInfo,pFrameInfo) )
+
+#define ICorProfilerInfo7_EnumModules(This,ppEnum) \
+ ( (This)->lpVtbl -> EnumModules(This,ppEnum) )
+
+#define ICorProfilerInfo7_GetRuntimeInformation(This,pClrInstanceId,pRuntimeType,pMajorVersion,pMinorVersion,pBuildNumber,pQFEVersion,cchVersionString,pcchVersionString,szVersionString) \
+ ( (This)->lpVtbl -> GetRuntimeInformation(This,pClrInstanceId,pRuntimeType,pMajorVersion,pMinorVersion,pBuildNumber,pQFEVersion,cchVersionString,pcchVersionString,szVersionString) )
+
+#define ICorProfilerInfo7_GetThreadStaticAddress2(This,classId,fieldToken,appDomainId,threadId,ppAddress) \
+ ( (This)->lpVtbl -> GetThreadStaticAddress2(This,classId,fieldToken,appDomainId,threadId,ppAddress) )
+
+#define ICorProfilerInfo7_GetAppDomainsContainingModule(This,moduleId,cAppDomainIds,pcAppDomainIds,appDomainIds) \
+ ( (This)->lpVtbl -> GetAppDomainsContainingModule(This,moduleId,cAppDomainIds,pcAppDomainIds,appDomainIds) )
+
+#define ICorProfilerInfo7_GetModuleInfo2(This,moduleId,ppBaseLoadAddress,cchName,pcchName,szName,pAssemblyId,pdwModuleFlags) \
+ ( (This)->lpVtbl -> GetModuleInfo2(This,moduleId,ppBaseLoadAddress,cchName,pcchName,szName,pAssemblyId,pdwModuleFlags) )
+
+
+#define ICorProfilerInfo7_EnumThreads(This,ppEnum) \
+ ( (This)->lpVtbl -> EnumThreads(This,ppEnum) )
+
+#define ICorProfilerInfo7_InitializeCurrentThread(This) \
+ ( (This)->lpVtbl -> InitializeCurrentThread(This) )
+
+#define ICorProfilerInfo7_RequestReJIT(This,cFunctions,moduleIds,methodIds) \
+ ( (This)->lpVtbl -> RequestReJIT(This,cFunctions,moduleIds,methodIds) )
+
+#define ICorProfilerInfo7_RequestRevert(This,cFunctions,moduleIds,methodIds,status) \
+ ( (This)->lpVtbl -> RequestRevert(This,cFunctions,moduleIds,methodIds,status) )
+
+#define ICorProfilerInfo7_GetCodeInfo3(This,functionID,reJitId,cCodeInfos,pcCodeInfos,codeInfos) \
+ ( (This)->lpVtbl -> GetCodeInfo3(This,functionID,reJitId,cCodeInfos,pcCodeInfos,codeInfos) )
+
+#define ICorProfilerInfo7_GetFunctionFromIP2(This,ip,pFunctionId,pReJitId) \
+ ( (This)->lpVtbl -> GetFunctionFromIP2(This,ip,pFunctionId,pReJitId) )
+
+#define ICorProfilerInfo7_GetReJITIDs(This,functionId,cReJitIds,pcReJitIds,reJitIds) \
+ ( (This)->lpVtbl -> GetReJITIDs(This,functionId,cReJitIds,pcReJitIds,reJitIds) )
+
+#define ICorProfilerInfo7_GetILToNativeMapping2(This,functionId,reJitId,cMap,pcMap,map) \
+ ( (This)->lpVtbl -> GetILToNativeMapping2(This,functionId,reJitId,cMap,pcMap,map) )
+
+#define ICorProfilerInfo7_EnumJITedFunctions2(This,ppEnum) \
+ ( (This)->lpVtbl -> EnumJITedFunctions2(This,ppEnum) )
+
+#define ICorProfilerInfo7_GetObjectSize2(This,objectId,pcSize) \
+ ( (This)->lpVtbl -> GetObjectSize2(This,objectId,pcSize) )
+
+
+#define ICorProfilerInfo7_GetEventMask2(This,pdwEventsLow,pdwEventsHigh) \
+ ( (This)->lpVtbl -> GetEventMask2(This,pdwEventsLow,pdwEventsHigh) )
+
+#define ICorProfilerInfo7_SetEventMask2(This,dwEventsLow,dwEventsHigh) \
+ ( (This)->lpVtbl -> SetEventMask2(This,dwEventsLow,dwEventsHigh) )
+
+
+#define ICorProfilerInfo7_EnumNgenModuleMethodsInliningThisMethod(This,inlinersModuleId,inlineeModuleId,inlineeMethodId,incompleteData,ppEnum) \
+ ( (This)->lpVtbl -> EnumNgenModuleMethodsInliningThisMethod(This,inlinersModuleId,inlineeModuleId,inlineeMethodId,incompleteData,ppEnum) )
+
+
+#define ICorProfilerInfo7_ApplyMetaData(This,moduleId) \
+ ( (This)->lpVtbl -> ApplyMetaData(This,moduleId) )
+
+#define ICorProfilerInfo7_GetInMemorySymbolsLength(This,moduleId,pCountSymbolBytes) \
+ ( (This)->lpVtbl -> GetInMemorySymbolsLength(This,moduleId,pCountSymbolBytes) )
+
+#define ICorProfilerInfo7_ReadInMemorySymbols(This,moduleId,symbolsReadOffset,pSymbolBytes,countSymbolBytes,pCountSymbolBytesRead) \
+ ( (This)->lpVtbl -> ReadInMemorySymbols(This,moduleId,symbolsReadOffset,pSymbolBytes,countSymbolBytes,pCountSymbolBytesRead) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorProfilerInfo7_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorProfilerMethodEnum_INTERFACE_DEFINED__
+#define __ICorProfilerMethodEnum_INTERFACE_DEFINED__
+
+/* interface ICorProfilerMethodEnum */
+/* [local][unique][uuid][object] */
+
+
+EXTERN_C const IID IID_ICorProfilerMethodEnum;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("FCCEE788-0088-454B-A811-C99F298D1942")
+ ICorProfilerMethodEnum : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE Skip(
+ /* [in] */ ULONG celt) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Reset( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Clone(
+ /* [out] */ ICorProfilerMethodEnum **ppEnum) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetCount(
+ /* [out] */ ULONG *pcelt) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Next(
+ /* [in] */ ULONG celt,
+ /* [length_is][size_is][out] */ COR_PRF_METHOD elements[ ],
+ /* [out] */ ULONG *pceltFetched) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorProfilerMethodEnumVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorProfilerMethodEnum * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorProfilerMethodEnum * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorProfilerMethodEnum * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Skip )(
+ ICorProfilerMethodEnum * This,
+ /* [in] */ ULONG celt);
+
+ HRESULT ( STDMETHODCALLTYPE *Reset )(
+ ICorProfilerMethodEnum * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Clone )(
+ ICorProfilerMethodEnum * This,
+ /* [out] */ ICorProfilerMethodEnum **ppEnum);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCount )(
+ ICorProfilerMethodEnum * This,
+ /* [out] */ ULONG *pcelt);
+
+ HRESULT ( STDMETHODCALLTYPE *Next )(
+ ICorProfilerMethodEnum * This,
+ /* [in] */ ULONG celt,
+ /* [length_is][size_is][out] */ COR_PRF_METHOD elements[ ],
+ /* [out] */ ULONG *pceltFetched);
+
+ END_INTERFACE
+ } ICorProfilerMethodEnumVtbl;
+
+ interface ICorProfilerMethodEnum
+ {
+ CONST_VTBL struct ICorProfilerMethodEnumVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorProfilerMethodEnum_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorProfilerMethodEnum_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorProfilerMethodEnum_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorProfilerMethodEnum_Skip(This,celt) \
+ ( (This)->lpVtbl -> Skip(This,celt) )
+
+#define ICorProfilerMethodEnum_Reset(This) \
+ ( (This)->lpVtbl -> Reset(This) )
+
+#define ICorProfilerMethodEnum_Clone(This,ppEnum) \
+ ( (This)->lpVtbl -> Clone(This,ppEnum) )
+
+#define ICorProfilerMethodEnum_GetCount(This,pcelt) \
+ ( (This)->lpVtbl -> GetCount(This,pcelt) )
+
+#define ICorProfilerMethodEnum_Next(This,celt,elements,pceltFetched) \
+ ( (This)->lpVtbl -> Next(This,celt,elements,pceltFetched) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorProfilerMethodEnum_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorProfilerThreadEnum_INTERFACE_DEFINED__
+#define __ICorProfilerThreadEnum_INTERFACE_DEFINED__
+
+/* interface ICorProfilerThreadEnum */
+/* [local][unique][uuid][object] */
+
+
+EXTERN_C const IID IID_ICorProfilerThreadEnum;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("571194f7-25ed-419f-aa8b-7016b3159701")
+ ICorProfilerThreadEnum : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE Skip(
+ /* [in] */ ULONG celt) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Reset( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Clone(
+ /* [out] */ ICorProfilerThreadEnum **ppEnum) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetCount(
+ /* [out] */ ULONG *pcelt) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Next(
+ /* [in] */ ULONG celt,
+ /* [length_is][size_is][out] */ ThreadID ids[ ],
+ /* [out] */ ULONG *pceltFetched) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorProfilerThreadEnumVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorProfilerThreadEnum * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorProfilerThreadEnum * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorProfilerThreadEnum * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Skip )(
+ ICorProfilerThreadEnum * This,
+ /* [in] */ ULONG celt);
+
+ HRESULT ( STDMETHODCALLTYPE *Reset )(
+ ICorProfilerThreadEnum * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Clone )(
+ ICorProfilerThreadEnum * This,
+ /* [out] */ ICorProfilerThreadEnum **ppEnum);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCount )(
+ ICorProfilerThreadEnum * This,
+ /* [out] */ ULONG *pcelt);
+
+ HRESULT ( STDMETHODCALLTYPE *Next )(
+ ICorProfilerThreadEnum * This,
+ /* [in] */ ULONG celt,
+ /* [length_is][size_is][out] */ ThreadID ids[ ],
+ /* [out] */ ULONG *pceltFetched);
+
+ END_INTERFACE
+ } ICorProfilerThreadEnumVtbl;
+
+ interface ICorProfilerThreadEnum
+ {
+ CONST_VTBL struct ICorProfilerThreadEnumVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorProfilerThreadEnum_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorProfilerThreadEnum_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorProfilerThreadEnum_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorProfilerThreadEnum_Skip(This,celt) \
+ ( (This)->lpVtbl -> Skip(This,celt) )
+
+#define ICorProfilerThreadEnum_Reset(This) \
+ ( (This)->lpVtbl -> Reset(This) )
+
+#define ICorProfilerThreadEnum_Clone(This,ppEnum) \
+ ( (This)->lpVtbl -> Clone(This,ppEnum) )
+
+#define ICorProfilerThreadEnum_GetCount(This,pcelt) \
+ ( (This)->lpVtbl -> GetCount(This,pcelt) )
+
+#define ICorProfilerThreadEnum_Next(This,celt,ids,pceltFetched) \
+ ( (This)->lpVtbl -> Next(This,celt,ids,pceltFetched) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorProfilerThreadEnum_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorProfilerAssemblyReferenceProvider_INTERFACE_DEFINED__
+#define __ICorProfilerAssemblyReferenceProvider_INTERFACE_DEFINED__
+
+/* interface ICorProfilerAssemblyReferenceProvider */
+/* [local][unique][uuid][object] */
+
+
+EXTERN_C const IID IID_ICorProfilerAssemblyReferenceProvider;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("66A78C24-2EEF-4F65-B45F-DD1D8038BF3C")
+ ICorProfilerAssemblyReferenceProvider : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE AddAssemblyReference(
+ const COR_PRF_ASSEMBLY_REFERENCE_INFO *pAssemblyRefInfo) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorProfilerAssemblyReferenceProviderVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorProfilerAssemblyReferenceProvider * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorProfilerAssemblyReferenceProvider * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorProfilerAssemblyReferenceProvider * This);
+
+ HRESULT ( STDMETHODCALLTYPE *AddAssemblyReference )(
+ ICorProfilerAssemblyReferenceProvider * This,
+ const COR_PRF_ASSEMBLY_REFERENCE_INFO *pAssemblyRefInfo);
+
+ END_INTERFACE
+ } ICorProfilerAssemblyReferenceProviderVtbl;
+
+ interface ICorProfilerAssemblyReferenceProvider
+ {
+ CONST_VTBL struct ICorProfilerAssemblyReferenceProviderVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorProfilerAssemblyReferenceProvider_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorProfilerAssemblyReferenceProvider_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorProfilerAssemblyReferenceProvider_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorProfilerAssemblyReferenceProvider_AddAssemblyReference(This,pAssemblyRefInfo) \
+ ( (This)->lpVtbl -> AddAssemblyReference(This,pAssemblyRefInfo) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorProfilerAssemblyReferenceProvider_INTERFACE_DEFINED__ */
+
+
+/* Additional Prototypes for ALL interfaces */
+
+/* end of Additional Prototypes */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+
diff --git a/src/pal/prebuilt/inc/corpub.h b/src/pal/prebuilt/inc/corpub.h
new file mode 100644
index 0000000000..94c01c660a
--- /dev/null
+++ b/src/pal/prebuilt/inc/corpub.h
@@ -0,0 +1,821 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+
+
+/* this ALWAYS GENERATED file contains the definitions for the interfaces */
+
+
+ /* File created by MIDL compiler version 8.00.0603 */
+/* @@MIDL_FILE_HEADING( ) */
+
+#pragma warning( disable: 4049 ) /* more than 64k source lines */
+
+
+/* verify that the <rpcndr.h> version is high enough to compile this file*/
+#ifndef __REQUIRED_RPCNDR_H_VERSION__
+#define __REQUIRED_RPCNDR_H_VERSION__ 475
+#endif
+
+#include "rpc.h"
+#include "rpcndr.h"
+
+#ifndef __RPCNDR_H_VERSION__
+#error this stub requires an updated version of <rpcndr.h>
+#endif // __RPCNDR_H_VERSION__
+
+#ifndef COM_NO_WINDOWS_H
+#include "windows.h"
+#include "ole2.h"
+#endif /*COM_NO_WINDOWS_H*/
+
+#ifndef __corpub_h__
+#define __corpub_h__
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+/* Forward Declarations */
+
+#ifndef __CorpubPublish_FWD_DEFINED__
+#define __CorpubPublish_FWD_DEFINED__
+
+#ifdef __cplusplus
+typedef class CorpubPublish CorpubPublish;
+#else
+typedef struct CorpubPublish CorpubPublish;
+#endif /* __cplusplus */
+
+#endif /* __CorpubPublish_FWD_DEFINED__ */
+
+
+#ifndef __ICorPublish_FWD_DEFINED__
+#define __ICorPublish_FWD_DEFINED__
+typedef interface ICorPublish ICorPublish;
+
+#endif /* __ICorPublish_FWD_DEFINED__ */
+
+
+#ifndef __ICorPublishEnum_FWD_DEFINED__
+#define __ICorPublishEnum_FWD_DEFINED__
+typedef interface ICorPublishEnum ICorPublishEnum;
+
+#endif /* __ICorPublishEnum_FWD_DEFINED__ */
+
+
+#ifndef __ICorPublishProcess_FWD_DEFINED__
+#define __ICorPublishProcess_FWD_DEFINED__
+typedef interface ICorPublishProcess ICorPublishProcess;
+
+#endif /* __ICorPublishProcess_FWD_DEFINED__ */
+
+
+#ifndef __ICorPublishAppDomain_FWD_DEFINED__
+#define __ICorPublishAppDomain_FWD_DEFINED__
+typedef interface ICorPublishAppDomain ICorPublishAppDomain;
+
+#endif /* __ICorPublishAppDomain_FWD_DEFINED__ */
+
+
+#ifndef __ICorPublishProcessEnum_FWD_DEFINED__
+#define __ICorPublishProcessEnum_FWD_DEFINED__
+typedef interface ICorPublishProcessEnum ICorPublishProcessEnum;
+
+#endif /* __ICorPublishProcessEnum_FWD_DEFINED__ */
+
+
+#ifndef __ICorPublishAppDomainEnum_FWD_DEFINED__
+#define __ICorPublishAppDomainEnum_FWD_DEFINED__
+typedef interface ICorPublishAppDomainEnum ICorPublishAppDomainEnum;
+
+#endif /* __ICorPublishAppDomainEnum_FWD_DEFINED__ */
+
+
+/* header files for imported files */
+#include "unknwn.h"
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+
+/* interface __MIDL_itf_corpub_0000_0000 */
+/* [local] */
+
+#if 0
+#endif
+typedef /* [public][public] */
+enum __MIDL___MIDL_itf_corpub_0000_0000_0001
+ {
+ COR_PUB_MANAGEDONLY = 0x1
+ } COR_PUB_ENUMPROCESS;
+
+#pragma warning(push)
+#pragma warning(disable:28718)
+
+
+
+
+
+#pragma warning(pop)
+
+
+extern RPC_IF_HANDLE __MIDL_itf_corpub_0000_0000_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_corpub_0000_0000_v0_0_s_ifspec;
+
+
+#ifndef __CorpubProcessLib_LIBRARY_DEFINED__
+#define __CorpubProcessLib_LIBRARY_DEFINED__
+
+/* library CorpubProcessLib */
+/* [helpstring][version][uuid] */
+
+
+EXTERN_C const IID LIBID_CorpubProcessLib;
+
+EXTERN_C const CLSID CLSID_CorpubPublish;
+
+#ifdef __cplusplus
+
+class DECLSPEC_UUID("047a9a40-657e-11d3-8d5b-00104b35e7ef")
+CorpubPublish;
+#endif
+#endif /* __CorpubProcessLib_LIBRARY_DEFINED__ */
+
+#ifndef __ICorPublish_INTERFACE_DEFINED__
+#define __ICorPublish_INTERFACE_DEFINED__
+
+/* interface ICorPublish */
+/* [local][unique][uuid][object] */
+
+
+EXTERN_C const IID IID_ICorPublish;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("9613A0E7-5A68-11d3-8F84-00A0C9B4D50C")
+ ICorPublish : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE EnumProcesses(
+ /* [in] */ COR_PUB_ENUMPROCESS Type,
+ /* [out] */ ICorPublishProcessEnum **ppIEnum) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetProcess(
+ /* [in] */ unsigned int pid,
+ /* [out] */ ICorPublishProcess **ppProcess) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorPublishVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorPublish * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorPublish * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorPublish * This);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumProcesses )(
+ ICorPublish * This,
+ /* [in] */ COR_PUB_ENUMPROCESS Type,
+ /* [out] */ ICorPublishProcessEnum **ppIEnum);
+
+ HRESULT ( STDMETHODCALLTYPE *GetProcess )(
+ ICorPublish * This,
+ /* [in] */ unsigned int pid,
+ /* [out] */ ICorPublishProcess **ppProcess);
+
+ END_INTERFACE
+ } ICorPublishVtbl;
+
+ interface ICorPublish
+ {
+ CONST_VTBL struct ICorPublishVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorPublish_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorPublish_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorPublish_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorPublish_EnumProcesses(This,Type,ppIEnum) \
+ ( (This)->lpVtbl -> EnumProcesses(This,Type,ppIEnum) )
+
+#define ICorPublish_GetProcess(This,pid,ppProcess) \
+ ( (This)->lpVtbl -> GetProcess(This,pid,ppProcess) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorPublish_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorPublishEnum_INTERFACE_DEFINED__
+#define __ICorPublishEnum_INTERFACE_DEFINED__
+
+/* interface ICorPublishEnum */
+/* [local][unique][uuid][object] */
+
+
+EXTERN_C const IID IID_ICorPublishEnum;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("C0B22967-5A69-11d3-8F84-00A0C9B4D50C")
+ ICorPublishEnum : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE Skip(
+ /* [in] */ ULONG celt) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Reset( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Clone(
+ /* [out] */ ICorPublishEnum **ppEnum) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetCount(
+ /* [out] */ ULONG *pcelt) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorPublishEnumVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorPublishEnum * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorPublishEnum * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorPublishEnum * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Skip )(
+ ICorPublishEnum * This,
+ /* [in] */ ULONG celt);
+
+ HRESULT ( STDMETHODCALLTYPE *Reset )(
+ ICorPublishEnum * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Clone )(
+ ICorPublishEnum * This,
+ /* [out] */ ICorPublishEnum **ppEnum);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCount )(
+ ICorPublishEnum * This,
+ /* [out] */ ULONG *pcelt);
+
+ END_INTERFACE
+ } ICorPublishEnumVtbl;
+
+ interface ICorPublishEnum
+ {
+ CONST_VTBL struct ICorPublishEnumVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorPublishEnum_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorPublishEnum_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorPublishEnum_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorPublishEnum_Skip(This,celt) \
+ ( (This)->lpVtbl -> Skip(This,celt) )
+
+#define ICorPublishEnum_Reset(This) \
+ ( (This)->lpVtbl -> Reset(This) )
+
+#define ICorPublishEnum_Clone(This,ppEnum) \
+ ( (This)->lpVtbl -> Clone(This,ppEnum) )
+
+#define ICorPublishEnum_GetCount(This,pcelt) \
+ ( (This)->lpVtbl -> GetCount(This,pcelt) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorPublishEnum_INTERFACE_DEFINED__ */
+
+
+/* interface __MIDL_itf_corpub_0000_0003 */
+/* [local] */
+
+#pragma warning(push)
+#pragma warning(disable:28718)
+
+
+extern RPC_IF_HANDLE __MIDL_itf_corpub_0000_0003_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_corpub_0000_0003_v0_0_s_ifspec;
+
+#ifndef __ICorPublishProcess_INTERFACE_DEFINED__
+#define __ICorPublishProcess_INTERFACE_DEFINED__
+
+/* interface ICorPublishProcess */
+/* [local][unique][uuid][object] */
+
+
+EXTERN_C const IID IID_ICorPublishProcess;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("18D87AF1-5A6A-11d3-8F84-00A0C9B4D50C")
+ ICorPublishProcess : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE IsManaged(
+ /* [out] */ BOOL *pbManaged) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnumAppDomains(
+ /* [out] */ ICorPublishAppDomainEnum **ppEnum) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetProcessID(
+ /* [out] */ unsigned int *pid) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetDisplayName(
+ /* [in] */ ULONG32 cchName,
+ /* [out] */ ULONG32 *pcchName,
+ /* [length_is][size_is][out] */ WCHAR *szName) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorPublishProcessVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorPublishProcess * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorPublishProcess * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorPublishProcess * This);
+
+ HRESULT ( STDMETHODCALLTYPE *IsManaged )(
+ ICorPublishProcess * This,
+ /* [out] */ BOOL *pbManaged);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumAppDomains )(
+ ICorPublishProcess * This,
+ /* [out] */ ICorPublishAppDomainEnum **ppEnum);
+
+ HRESULT ( STDMETHODCALLTYPE *GetProcessID )(
+ ICorPublishProcess * This,
+ /* [out] */ unsigned int *pid);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDisplayName )(
+ ICorPublishProcess * This,
+ /* [in] */ ULONG32 cchName,
+ /* [out] */ ULONG32 *pcchName,
+ /* [length_is][size_is][out] */ WCHAR *szName);
+
+ END_INTERFACE
+ } ICorPublishProcessVtbl;
+
+ interface ICorPublishProcess
+ {
+ CONST_VTBL struct ICorPublishProcessVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorPublishProcess_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorPublishProcess_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorPublishProcess_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorPublishProcess_IsManaged(This,pbManaged) \
+ ( (This)->lpVtbl -> IsManaged(This,pbManaged) )
+
+#define ICorPublishProcess_EnumAppDomains(This,ppEnum) \
+ ( (This)->lpVtbl -> EnumAppDomains(This,ppEnum) )
+
+#define ICorPublishProcess_GetProcessID(This,pid) \
+ ( (This)->lpVtbl -> GetProcessID(This,pid) )
+
+#define ICorPublishProcess_GetDisplayName(This,cchName,pcchName,szName) \
+ ( (This)->lpVtbl -> GetDisplayName(This,cchName,pcchName,szName) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorPublishProcess_INTERFACE_DEFINED__ */
+
+
+/* interface __MIDL_itf_corpub_0000_0004 */
+/* [local] */
+
+#pragma warning(pop)
+#pragma warning(push)
+#pragma warning(disable:28718)
+
+
+extern RPC_IF_HANDLE __MIDL_itf_corpub_0000_0004_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_corpub_0000_0004_v0_0_s_ifspec;
+
+#ifndef __ICorPublishAppDomain_INTERFACE_DEFINED__
+#define __ICorPublishAppDomain_INTERFACE_DEFINED__
+
+/* interface ICorPublishAppDomain */
+/* [local][unique][uuid][object] */
+
+
+EXTERN_C const IID IID_ICorPublishAppDomain;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("D6315C8F-5A6A-11d3-8F84-00A0C9B4D50C")
+ ICorPublishAppDomain : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetID(
+ /* [out] */ ULONG32 *puId) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetName(
+ /* [in] */ ULONG32 cchName,
+ /* [out] */ ULONG32 *pcchName,
+ /* [length_is][size_is][out] */ WCHAR *szName) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorPublishAppDomainVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorPublishAppDomain * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorPublishAppDomain * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorPublishAppDomain * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetID )(
+ ICorPublishAppDomain * This,
+ /* [out] */ ULONG32 *puId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetName )(
+ ICorPublishAppDomain * This,
+ /* [in] */ ULONG32 cchName,
+ /* [out] */ ULONG32 *pcchName,
+ /* [length_is][size_is][out] */ WCHAR *szName);
+
+ END_INTERFACE
+ } ICorPublishAppDomainVtbl;
+
+ interface ICorPublishAppDomain
+ {
+ CONST_VTBL struct ICorPublishAppDomainVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorPublishAppDomain_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorPublishAppDomain_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorPublishAppDomain_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorPublishAppDomain_GetID(This,puId) \
+ ( (This)->lpVtbl -> GetID(This,puId) )
+
+#define ICorPublishAppDomain_GetName(This,cchName,pcchName,szName) \
+ ( (This)->lpVtbl -> GetName(This,cchName,pcchName,szName) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorPublishAppDomain_INTERFACE_DEFINED__ */
+
+
+/* interface __MIDL_itf_corpub_0000_0005 */
+/* [local] */
+
+#pragma warning(pop)
+
+
+extern RPC_IF_HANDLE __MIDL_itf_corpub_0000_0005_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_corpub_0000_0005_v0_0_s_ifspec;
+
+#ifndef __ICorPublishProcessEnum_INTERFACE_DEFINED__
+#define __ICorPublishProcessEnum_INTERFACE_DEFINED__
+
+/* interface ICorPublishProcessEnum */
+/* [local][unique][uuid][object] */
+
+
+EXTERN_C const IID IID_ICorPublishProcessEnum;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("A37FBD41-5A69-11d3-8F84-00A0C9B4D50C")
+ ICorPublishProcessEnum : public ICorPublishEnum
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE Next(
+ /* [in] */ ULONG celt,
+ /* [length_is][size_is][out] */ ICorPublishProcess **objects,
+ /* [out] */ ULONG *pceltFetched) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorPublishProcessEnumVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorPublishProcessEnum * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorPublishProcessEnum * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorPublishProcessEnum * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Skip )(
+ ICorPublishProcessEnum * This,
+ /* [in] */ ULONG celt);
+
+ HRESULT ( STDMETHODCALLTYPE *Reset )(
+ ICorPublishProcessEnum * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Clone )(
+ ICorPublishProcessEnum * This,
+ /* [out] */ ICorPublishEnum **ppEnum);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCount )(
+ ICorPublishProcessEnum * This,
+ /* [out] */ ULONG *pcelt);
+
+ HRESULT ( STDMETHODCALLTYPE *Next )(
+ ICorPublishProcessEnum * This,
+ /* [in] */ ULONG celt,
+ /* [length_is][size_is][out] */ ICorPublishProcess **objects,
+ /* [out] */ ULONG *pceltFetched);
+
+ END_INTERFACE
+ } ICorPublishProcessEnumVtbl;
+
+ interface ICorPublishProcessEnum
+ {
+ CONST_VTBL struct ICorPublishProcessEnumVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorPublishProcessEnum_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorPublishProcessEnum_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorPublishProcessEnum_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorPublishProcessEnum_Skip(This,celt) \
+ ( (This)->lpVtbl -> Skip(This,celt) )
+
+#define ICorPublishProcessEnum_Reset(This) \
+ ( (This)->lpVtbl -> Reset(This) )
+
+#define ICorPublishProcessEnum_Clone(This,ppEnum) \
+ ( (This)->lpVtbl -> Clone(This,ppEnum) )
+
+#define ICorPublishProcessEnum_GetCount(This,pcelt) \
+ ( (This)->lpVtbl -> GetCount(This,pcelt) )
+
+
+#define ICorPublishProcessEnum_Next(This,celt,objects,pceltFetched) \
+ ( (This)->lpVtbl -> Next(This,celt,objects,pceltFetched) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorPublishProcessEnum_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorPublishAppDomainEnum_INTERFACE_DEFINED__
+#define __ICorPublishAppDomainEnum_INTERFACE_DEFINED__
+
+/* interface ICorPublishAppDomainEnum */
+/* [local][unique][uuid][object] */
+
+
+EXTERN_C const IID IID_ICorPublishAppDomainEnum;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("9F0C98F5-5A6A-11d3-8F84-00A0C9B4D50C")
+ ICorPublishAppDomainEnum : public ICorPublishEnum
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE Next(
+ /* [in] */ ULONG celt,
+ /* [length_is][size_is][out] */ ICorPublishAppDomain **objects,
+ /* [out] */ ULONG *pceltFetched) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorPublishAppDomainEnumVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorPublishAppDomainEnum * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorPublishAppDomainEnum * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorPublishAppDomainEnum * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Skip )(
+ ICorPublishAppDomainEnum * This,
+ /* [in] */ ULONG celt);
+
+ HRESULT ( STDMETHODCALLTYPE *Reset )(
+ ICorPublishAppDomainEnum * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Clone )(
+ ICorPublishAppDomainEnum * This,
+ /* [out] */ ICorPublishEnum **ppEnum);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCount )(
+ ICorPublishAppDomainEnum * This,
+ /* [out] */ ULONG *pcelt);
+
+ HRESULT ( STDMETHODCALLTYPE *Next )(
+ ICorPublishAppDomainEnum * This,
+ /* [in] */ ULONG celt,
+ /* [length_is][size_is][out] */ ICorPublishAppDomain **objects,
+ /* [out] */ ULONG *pceltFetched);
+
+ END_INTERFACE
+ } ICorPublishAppDomainEnumVtbl;
+
+ interface ICorPublishAppDomainEnum
+ {
+ CONST_VTBL struct ICorPublishAppDomainEnumVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorPublishAppDomainEnum_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorPublishAppDomainEnum_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorPublishAppDomainEnum_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorPublishAppDomainEnum_Skip(This,celt) \
+ ( (This)->lpVtbl -> Skip(This,celt) )
+
+#define ICorPublishAppDomainEnum_Reset(This) \
+ ( (This)->lpVtbl -> Reset(This) )
+
+#define ICorPublishAppDomainEnum_Clone(This,ppEnum) \
+ ( (This)->lpVtbl -> Clone(This,ppEnum) )
+
+#define ICorPublishAppDomainEnum_GetCount(This,pcelt) \
+ ( (This)->lpVtbl -> GetCount(This,pcelt) )
+
+
+#define ICorPublishAppDomainEnum_Next(This,celt,objects,pceltFetched) \
+ ( (This)->lpVtbl -> Next(This,celt,objects,pceltFetched) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorPublishAppDomainEnum_INTERFACE_DEFINED__ */
+
+
+/* Additional Prototypes for ALL interfaces */
+
+/* end of Additional Prototypes */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+
diff --git a/src/pal/prebuilt/inc/corsym.h b/src/pal/prebuilt/inc/corsym.h
new file mode 100644
index 0000000000..dd80eae55d
--- /dev/null
+++ b/src/pal/prebuilt/inc/corsym.h
@@ -0,0 +1,5706 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+
+
+/* this ALWAYS GENERATED file contains the definitions for the interfaces */
+
+
+ /* File created by MIDL compiler version 8.00.0601 */
+/* @@MIDL_FILE_HEADING( ) */
+
+#pragma warning( disable: 4049 ) /* more than 64k source lines */
+
+
+/* verify that the <rpcndr.h> version is high enough to compile this file*/
+#ifndef __REQUIRED_RPCNDR_H_VERSION__
+#define __REQUIRED_RPCNDR_H_VERSION__ 475
+#endif
+
+/* verify that the <rpcsal.h> version is high enough to compile this file*/
+#ifndef __REQUIRED_RPCSAL_H_VERSION__
+#define __REQUIRED_RPCSAL_H_VERSION__ 100
+#endif
+
+#include "rpc.h"
+#include "rpcndr.h"
+
+#ifndef __RPCNDR_H_VERSION__
+#error this stub requires an updated version of <rpcndr.h>
+#endif // __RPCNDR_H_VERSION__
+
+#ifndef COM_NO_WINDOWS_H
+#include "windows.h"
+#include "ole2.h"
+#endif /*COM_NO_WINDOWS_H*/
+
+#ifndef __corsym_h__
+#define __corsym_h__
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+/* Forward Declarations */
+
+#ifndef __CorSymWriter_deprecated_FWD_DEFINED__
+#define __CorSymWriter_deprecated_FWD_DEFINED__
+
+#ifdef __cplusplus
+typedef class CorSymWriter_deprecated CorSymWriter_deprecated;
+#else
+typedef struct CorSymWriter_deprecated CorSymWriter_deprecated;
+#endif /* __cplusplus */
+
+#endif /* __CorSymWriter_deprecated_FWD_DEFINED__ */
+
+
+#ifndef __CorSymReader_deprecated_FWD_DEFINED__
+#define __CorSymReader_deprecated_FWD_DEFINED__
+
+#ifdef __cplusplus
+typedef class CorSymReader_deprecated CorSymReader_deprecated;
+#else
+typedef struct CorSymReader_deprecated CorSymReader_deprecated;
+#endif /* __cplusplus */
+
+#endif /* __CorSymReader_deprecated_FWD_DEFINED__ */
+
+
+#ifndef __CorSymBinder_deprecated_FWD_DEFINED__
+#define __CorSymBinder_deprecated_FWD_DEFINED__
+
+#ifdef __cplusplus
+typedef class CorSymBinder_deprecated CorSymBinder_deprecated;
+#else
+typedef struct CorSymBinder_deprecated CorSymBinder_deprecated;
+#endif /* __cplusplus */
+
+#endif /* __CorSymBinder_deprecated_FWD_DEFINED__ */
+
+
+#ifndef __CorSymWriter_SxS_FWD_DEFINED__
+#define __CorSymWriter_SxS_FWD_DEFINED__
+
+#ifdef __cplusplus
+typedef class CorSymWriter_SxS CorSymWriter_SxS;
+#else
+typedef struct CorSymWriter_SxS CorSymWriter_SxS;
+#endif /* __cplusplus */
+
+#endif /* __CorSymWriter_SxS_FWD_DEFINED__ */
+
+
+#ifndef __CorSymReader_SxS_FWD_DEFINED__
+#define __CorSymReader_SxS_FWD_DEFINED__
+
+#ifdef __cplusplus
+typedef class CorSymReader_SxS CorSymReader_SxS;
+#else
+typedef struct CorSymReader_SxS CorSymReader_SxS;
+#endif /* __cplusplus */
+
+#endif /* __CorSymReader_SxS_FWD_DEFINED__ */
+
+
+#ifndef __CorSymBinder_SxS_FWD_DEFINED__
+#define __CorSymBinder_SxS_FWD_DEFINED__
+
+#ifdef __cplusplus
+typedef class CorSymBinder_SxS CorSymBinder_SxS;
+#else
+typedef struct CorSymBinder_SxS CorSymBinder_SxS;
+#endif /* __cplusplus */
+
+#endif /* __CorSymBinder_SxS_FWD_DEFINED__ */
+
+
+#ifndef __ISymUnmanagedBinder_FWD_DEFINED__
+#define __ISymUnmanagedBinder_FWD_DEFINED__
+typedef interface ISymUnmanagedBinder ISymUnmanagedBinder;
+
+#endif /* __ISymUnmanagedBinder_FWD_DEFINED__ */
+
+
+#ifndef __ISymUnmanagedBinder2_FWD_DEFINED__
+#define __ISymUnmanagedBinder2_FWD_DEFINED__
+typedef interface ISymUnmanagedBinder2 ISymUnmanagedBinder2;
+
+#endif /* __ISymUnmanagedBinder2_FWD_DEFINED__ */
+
+
+#ifndef __ISymUnmanagedBinder3_FWD_DEFINED__
+#define __ISymUnmanagedBinder3_FWD_DEFINED__
+typedef interface ISymUnmanagedBinder3 ISymUnmanagedBinder3;
+
+#endif /* __ISymUnmanagedBinder3_FWD_DEFINED__ */
+
+
+#ifndef __ISymUnmanagedDispose_FWD_DEFINED__
+#define __ISymUnmanagedDispose_FWD_DEFINED__
+typedef interface ISymUnmanagedDispose ISymUnmanagedDispose;
+
+#endif /* __ISymUnmanagedDispose_FWD_DEFINED__ */
+
+
+#ifndef __ISymUnmanagedDocument_FWD_DEFINED__
+#define __ISymUnmanagedDocument_FWD_DEFINED__
+typedef interface ISymUnmanagedDocument ISymUnmanagedDocument;
+
+#endif /* __ISymUnmanagedDocument_FWD_DEFINED__ */
+
+
+#ifndef __ISymUnmanagedDocumentWriter_FWD_DEFINED__
+#define __ISymUnmanagedDocumentWriter_FWD_DEFINED__
+typedef interface ISymUnmanagedDocumentWriter ISymUnmanagedDocumentWriter;
+
+#endif /* __ISymUnmanagedDocumentWriter_FWD_DEFINED__ */
+
+
+#ifndef __ISymUnmanagedMethod_FWD_DEFINED__
+#define __ISymUnmanagedMethod_FWD_DEFINED__
+typedef interface ISymUnmanagedMethod ISymUnmanagedMethod;
+
+#endif /* __ISymUnmanagedMethod_FWD_DEFINED__ */
+
+
+#ifndef __ISymENCUnmanagedMethod_FWD_DEFINED__
+#define __ISymENCUnmanagedMethod_FWD_DEFINED__
+typedef interface ISymENCUnmanagedMethod ISymENCUnmanagedMethod;
+
+#endif /* __ISymENCUnmanagedMethod_FWD_DEFINED__ */
+
+
+#ifndef __ISymUnmanagedNamespace_FWD_DEFINED__
+#define __ISymUnmanagedNamespace_FWD_DEFINED__
+typedef interface ISymUnmanagedNamespace ISymUnmanagedNamespace;
+
+#endif /* __ISymUnmanagedNamespace_FWD_DEFINED__ */
+
+
+#ifndef __ISymUnmanagedReader_FWD_DEFINED__
+#define __ISymUnmanagedReader_FWD_DEFINED__
+typedef interface ISymUnmanagedReader ISymUnmanagedReader;
+
+#endif /* __ISymUnmanagedReader_FWD_DEFINED__ */
+
+
+#ifndef __ISymUnmanagedSourceServerModule_FWD_DEFINED__
+#define __ISymUnmanagedSourceServerModule_FWD_DEFINED__
+typedef interface ISymUnmanagedSourceServerModule ISymUnmanagedSourceServerModule;
+
+#endif /* __ISymUnmanagedSourceServerModule_FWD_DEFINED__ */
+
+
+#ifndef __ISymUnmanagedENCUpdate_FWD_DEFINED__
+#define __ISymUnmanagedENCUpdate_FWD_DEFINED__
+typedef interface ISymUnmanagedENCUpdate ISymUnmanagedENCUpdate;
+
+#endif /* __ISymUnmanagedENCUpdate_FWD_DEFINED__ */
+
+
+#ifndef __ISymUnmanagedReaderSymbolSearchInfo_FWD_DEFINED__
+#define __ISymUnmanagedReaderSymbolSearchInfo_FWD_DEFINED__
+typedef interface ISymUnmanagedReaderSymbolSearchInfo ISymUnmanagedReaderSymbolSearchInfo;
+
+#endif /* __ISymUnmanagedReaderSymbolSearchInfo_FWD_DEFINED__ */
+
+
+#ifndef __ISymUnmanagedScope_FWD_DEFINED__
+#define __ISymUnmanagedScope_FWD_DEFINED__
+typedef interface ISymUnmanagedScope ISymUnmanagedScope;
+
+#endif /* __ISymUnmanagedScope_FWD_DEFINED__ */
+
+
+#ifndef __ISymUnmanagedConstant_FWD_DEFINED__
+#define __ISymUnmanagedConstant_FWD_DEFINED__
+typedef interface ISymUnmanagedConstant ISymUnmanagedConstant;
+
+#endif /* __ISymUnmanagedConstant_FWD_DEFINED__ */
+
+
+#ifndef __ISymUnmanagedScope2_FWD_DEFINED__
+#define __ISymUnmanagedScope2_FWD_DEFINED__
+typedef interface ISymUnmanagedScope2 ISymUnmanagedScope2;
+
+#endif /* __ISymUnmanagedScope2_FWD_DEFINED__ */
+
+
+#ifndef __ISymUnmanagedVariable_FWD_DEFINED__
+#define __ISymUnmanagedVariable_FWD_DEFINED__
+typedef interface ISymUnmanagedVariable ISymUnmanagedVariable;
+
+#endif /* __ISymUnmanagedVariable_FWD_DEFINED__ */
+
+
+#ifndef __ISymUnmanagedSymbolSearchInfo_FWD_DEFINED__
+#define __ISymUnmanagedSymbolSearchInfo_FWD_DEFINED__
+typedef interface ISymUnmanagedSymbolSearchInfo ISymUnmanagedSymbolSearchInfo;
+
+#endif /* __ISymUnmanagedSymbolSearchInfo_FWD_DEFINED__ */
+
+
+#ifndef __ISymUnmanagedWriter_FWD_DEFINED__
+#define __ISymUnmanagedWriter_FWD_DEFINED__
+typedef interface ISymUnmanagedWriter ISymUnmanagedWriter;
+
+#endif /* __ISymUnmanagedWriter_FWD_DEFINED__ */
+
+
+#ifndef __ISymUnmanagedWriter2_FWD_DEFINED__
+#define __ISymUnmanagedWriter2_FWD_DEFINED__
+typedef interface ISymUnmanagedWriter2 ISymUnmanagedWriter2;
+
+#endif /* __ISymUnmanagedWriter2_FWD_DEFINED__ */
+
+
+#ifndef __ISymUnmanagedWriter3_FWD_DEFINED__
+#define __ISymUnmanagedWriter3_FWD_DEFINED__
+typedef interface ISymUnmanagedWriter3 ISymUnmanagedWriter3;
+
+#endif /* __ISymUnmanagedWriter3_FWD_DEFINED__ */
+
+
+#ifndef __ISymUnmanagedWriter4_FWD_DEFINED__
+#define __ISymUnmanagedWriter4_FWD_DEFINED__
+typedef interface ISymUnmanagedWriter4 ISymUnmanagedWriter4;
+
+#endif /* __ISymUnmanagedWriter4_FWD_DEFINED__ */
+
+
+#ifndef __ISymUnmanagedWriter5_FWD_DEFINED__
+#define __ISymUnmanagedWriter5_FWD_DEFINED__
+typedef interface ISymUnmanagedWriter5 ISymUnmanagedWriter5;
+
+#endif /* __ISymUnmanagedWriter5_FWD_DEFINED__ */
+
+
+#ifndef __ISymUnmanagedReader2_FWD_DEFINED__
+#define __ISymUnmanagedReader2_FWD_DEFINED__
+typedef interface ISymUnmanagedReader2 ISymUnmanagedReader2;
+
+#endif /* __ISymUnmanagedReader2_FWD_DEFINED__ */
+
+
+#ifndef __ISymNGenWriter_FWD_DEFINED__
+#define __ISymNGenWriter_FWD_DEFINED__
+typedef interface ISymNGenWriter ISymNGenWriter;
+
+#endif /* __ISymNGenWriter_FWD_DEFINED__ */
+
+
+#ifndef __ISymNGenWriter2_FWD_DEFINED__
+#define __ISymNGenWriter2_FWD_DEFINED__
+typedef interface ISymNGenWriter2 ISymNGenWriter2;
+
+#endif /* __ISymNGenWriter2_FWD_DEFINED__ */
+
+
+#ifndef __ISymUnmanagedAsyncMethodPropertiesWriter_FWD_DEFINED__
+#define __ISymUnmanagedAsyncMethodPropertiesWriter_FWD_DEFINED__
+typedef interface ISymUnmanagedAsyncMethodPropertiesWriter ISymUnmanagedAsyncMethodPropertiesWriter;
+
+#endif /* __ISymUnmanagedAsyncMethodPropertiesWriter_FWD_DEFINED__ */
+
+
+#ifndef __ISymUnmanagedAsyncMethod_FWD_DEFINED__
+#define __ISymUnmanagedAsyncMethod_FWD_DEFINED__
+typedef interface ISymUnmanagedAsyncMethod ISymUnmanagedAsyncMethod;
+
+#endif /* __ISymUnmanagedAsyncMethod_FWD_DEFINED__ */
+
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+
+/* interface __MIDL_itf_corsym_0000_0000 */
+/* [local] */
+
+#if 0
+typedef typedef unsigned int UINT32;
+;
+
+typedef mdToken mdTypeDef;
+
+typedef mdToken mdMethodDef;
+
+typedef typedef ULONG_PTR SIZE_T;
+;
+
+#endif
+#ifndef __CORHDR_H__
+typedef mdToken mdSignature;
+
+#endif
+#pragma once
+#pragma once
+#pragma region Input Buffer SAL 1 compatibility macros
+#pragma endregion Input Buffer SAL 1 compatibility macros
+#pragma once
+#pragma once
+EXTERN_GUID(CorSym_LanguageType_C, 0x63a08714, 0xfc37, 0x11d2, 0x90, 0x4c, 0x0, 0xc0, 0x4f, 0xa3, 0x02, 0xa1);
+EXTERN_GUID(CorSym_LanguageType_CPlusPlus, 0x3a12d0b7, 0xc26c, 0x11d0, 0xb4, 0x42, 0x0, 0xa0, 0x24, 0x4a, 0x1d, 0xd2);
+EXTERN_GUID(CorSym_LanguageType_CSharp, 0x3f5162f8, 0x07c6, 0x11d3, 0x90, 0x53, 0x0, 0xc0, 0x4f, 0xa3, 0x02, 0xa1);
+EXTERN_GUID(CorSym_LanguageType_Basic, 0x3a12d0b8, 0xc26c, 0x11d0, 0xb4, 0x42, 0x0, 0xa0, 0x24, 0x4a, 0x1d, 0xd2);
+EXTERN_GUID(CorSym_LanguageType_Java, 0x3a12d0b4, 0xc26c, 0x11d0, 0xb4, 0x42, 0x0, 0xa0, 0x24, 0x4a, 0x1d, 0xd2);
+EXTERN_GUID(CorSym_LanguageType_Cobol, 0xaf046cd1, 0xd0e1, 0x11d2, 0x97, 0x7c, 0x0, 0xa0, 0xc9, 0xb4, 0xd5, 0xc);
+EXTERN_GUID(CorSym_LanguageType_Pascal, 0xaf046cd2, 0xd0e1, 0x11d2, 0x97, 0x7c, 0x0, 0xa0, 0xc9, 0xb4, 0xd5, 0xc);
+EXTERN_GUID(CorSym_LanguageType_ILAssembly, 0xaf046cd3, 0xd0e1, 0x11d2, 0x97, 0x7c, 0x0, 0xa0, 0xc9, 0xb4, 0xd5, 0xc);
+EXTERN_GUID(CorSym_LanguageType_JScript, 0x3a12d0b6, 0xc26c, 0x11d0, 0xb4, 0x42, 0x00, 0xa0, 0x24, 0x4a, 0x1d, 0xd2);
+EXTERN_GUID(CorSym_LanguageType_SMC, 0xd9b9f7b, 0x6611, 0x11d3, 0xbd, 0x2a, 0x0, 0x0, 0xf8, 0x8, 0x49, 0xbd);
+EXTERN_GUID(CorSym_LanguageType_MCPlusPlus, 0x4b35fde8, 0x07c6, 0x11d3, 0x90, 0x53, 0x0, 0xc0, 0x4f, 0xa3, 0x02, 0xa1);
+EXTERN_GUID(CorSym_LanguageVendor_Microsoft, 0x994b45c4, 0xe6e9, 0x11d2, 0x90, 0x3f, 0x00, 0xc0, 0x4f, 0xa3, 0x02, 0xa1);
+EXTERN_GUID(CorSym_DocumentType_Text, 0x5a869d0b, 0x6611, 0x11d3, 0xbd, 0x2a, 0x0, 0x0, 0xf8, 0x8, 0x49, 0xbd);
+EXTERN_GUID(CorSym_DocumentType_MC, 0xeb40cb65, 0x3c1f, 0x4352, 0x9d, 0x7b, 0xba, 0xf, 0xc4, 0x7a, 0x9d, 0x77);
+EXTERN_GUID(CorSym_SourceHash_MD5, 0x406ea660, 0x64cf, 0x4c82, 0xb6, 0xf0, 0x42, 0xd4, 0x81, 0x72, 0xa7, 0x99);
+EXTERN_GUID(CorSym_SourceHash_SHA1, 0xff1816ec, 0xaa5e, 0x4d10, 0x87, 0xf7, 0x6f, 0x49, 0x63, 0x83, 0x34, 0x60);
+
+
+
+
+
+
+
+
+
+
+
+
+typedef
+enum CorSymAddrKind
+ {
+ ADDR_IL_OFFSET = 1,
+ ADDR_NATIVE_RVA = 2,
+ ADDR_NATIVE_REGISTER = 3,
+ ADDR_NATIVE_REGREL = 4,
+ ADDR_NATIVE_OFFSET = 5,
+ ADDR_NATIVE_REGREG = 6,
+ ADDR_NATIVE_REGSTK = 7,
+ ADDR_NATIVE_STKREG = 8,
+ ADDR_BITFIELD = 9,
+ ADDR_NATIVE_ISECTOFFSET = 10
+ } CorSymAddrKind;
+
+typedef
+enum CorSymVarFlag
+ {
+ VAR_IS_COMP_GEN = 1
+ } CorSymVarFlag;
+
+
+
+extern RPC_IF_HANDLE __MIDL_itf_corsym_0000_0000_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_corsym_0000_0000_v0_0_s_ifspec;
+
+
+#ifndef __CorSymLib_LIBRARY_DEFINED__
+#define __CorSymLib_LIBRARY_DEFINED__
+
+/* library CorSymLib */
+/* [helpstring][version][uuid] */
+
+
+EXTERN_C const IID LIBID_CorSymLib;
+
+EXTERN_C const CLSID CLSID_CorSymWriter_deprecated;
+
+#ifdef __cplusplus
+
+class DECLSPEC_UUID("108296C1-281E-11d3-BD22-0000F80849BD")
+CorSymWriter_deprecated;
+#endif
+
+EXTERN_C const CLSID CLSID_CorSymReader_deprecated;
+
+#ifdef __cplusplus
+
+class DECLSPEC_UUID("108296C2-281E-11d3-BD22-0000F80849BD")
+CorSymReader_deprecated;
+#endif
+
+EXTERN_C const CLSID CLSID_CorSymBinder_deprecated;
+
+#ifdef __cplusplus
+
+class DECLSPEC_UUID("AA544D41-28CB-11d3-BD22-0000F80849BD")
+CorSymBinder_deprecated;
+#endif
+
+EXTERN_C const CLSID CLSID_CorSymWriter_SxS;
+
+#ifdef __cplusplus
+
+class DECLSPEC_UUID("0AE2DEB0-F901-478b-BB9F-881EE8066788")
+CorSymWriter_SxS;
+#endif
+
+EXTERN_C const CLSID CLSID_CorSymReader_SxS;
+
+#ifdef __cplusplus
+
+class DECLSPEC_UUID("0A3976C5-4529-4ef8-B0B0-42EED37082CD")
+CorSymReader_SxS;
+#endif
+
+EXTERN_C const CLSID CLSID_CorSymBinder_SxS;
+
+#ifdef __cplusplus
+
+class DECLSPEC_UUID("0A29FF9E-7F9C-4437-8B11-F424491E3931")
+CorSymBinder_SxS;
+#endif
+#endif /* __CorSymLib_LIBRARY_DEFINED__ */
+
+#ifndef __ISymUnmanagedBinder_INTERFACE_DEFINED__
+#define __ISymUnmanagedBinder_INTERFACE_DEFINED__
+
+/* interface ISymUnmanagedBinder */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_ISymUnmanagedBinder;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("AA544D42-28CB-11d3-BD22-0000F80849BD")
+ ISymUnmanagedBinder : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetReaderForFile(
+ /* [in] */ __RPC__in_opt IUnknown *importer,
+ /* [in] */ __RPC__in const WCHAR *fileName,
+ /* [in] */ __RPC__in const WCHAR *searchPath,
+ /* [retval][out] */ __RPC__deref_out_opt ISymUnmanagedReader **pRetVal) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetReaderFromStream(
+ /* [in] */ __RPC__in_opt IUnknown *importer,
+ /* [in] */ __RPC__in_opt IStream *pstream,
+ /* [retval][out] */ __RPC__deref_out_opt ISymUnmanagedReader **pRetVal) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ISymUnmanagedBinderVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ __RPC__in ISymUnmanagedBinder * This,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ __RPC__in ISymUnmanagedBinder * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ __RPC__in ISymUnmanagedBinder * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetReaderForFile )(
+ __RPC__in ISymUnmanagedBinder * This,
+ /* [in] */ __RPC__in_opt IUnknown *importer,
+ /* [in] */ __RPC__in const WCHAR *fileName,
+ /* [in] */ __RPC__in const WCHAR *searchPath,
+ /* [retval][out] */ __RPC__deref_out_opt ISymUnmanagedReader **pRetVal);
+
+ HRESULT ( STDMETHODCALLTYPE *GetReaderFromStream )(
+ __RPC__in ISymUnmanagedBinder * This,
+ /* [in] */ __RPC__in_opt IUnknown *importer,
+ /* [in] */ __RPC__in_opt IStream *pstream,
+ /* [retval][out] */ __RPC__deref_out_opt ISymUnmanagedReader **pRetVal);
+
+ END_INTERFACE
+ } ISymUnmanagedBinderVtbl;
+
+ interface ISymUnmanagedBinder
+ {
+ CONST_VTBL struct ISymUnmanagedBinderVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ISymUnmanagedBinder_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ISymUnmanagedBinder_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ISymUnmanagedBinder_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ISymUnmanagedBinder_GetReaderForFile(This,importer,fileName,searchPath,pRetVal) \
+ ( (This)->lpVtbl -> GetReaderForFile(This,importer,fileName,searchPath,pRetVal) )
+
+#define ISymUnmanagedBinder_GetReaderFromStream(This,importer,pstream,pRetVal) \
+ ( (This)->lpVtbl -> GetReaderFromStream(This,importer,pstream,pRetVal) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ISymUnmanagedBinder_INTERFACE_DEFINED__ */
+
+
+/* interface __MIDL_itf_corsym_0000_0002 */
+/* [local] */
+
+typedef
+enum CorSymSearchPolicyAttributes
+ {
+ AllowRegistryAccess = 0x1,
+ AllowSymbolServerAccess = 0x2,
+ AllowOriginalPathAccess = 0x4,
+ AllowReferencePathAccess = 0x8
+ } CorSymSearchPolicyAttributes;
+
+
+
+extern RPC_IF_HANDLE __MIDL_itf_corsym_0000_0002_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_corsym_0000_0002_v0_0_s_ifspec;
+
+#ifndef __ISymUnmanagedBinder2_INTERFACE_DEFINED__
+#define __ISymUnmanagedBinder2_INTERFACE_DEFINED__
+
+/* interface ISymUnmanagedBinder2 */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_ISymUnmanagedBinder2;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("ACCEE350-89AF-4ccb-8B40-1C2C4C6F9434")
+ ISymUnmanagedBinder2 : public ISymUnmanagedBinder
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetReaderForFile2(
+ /* [in] */ __RPC__in_opt IUnknown *importer,
+ /* [in] */ __RPC__in const WCHAR *fileName,
+ /* [in] */ __RPC__in const WCHAR *searchPath,
+ /* [in] */ ULONG32 searchPolicy,
+ /* [retval][out] */ __RPC__deref_out_opt ISymUnmanagedReader **pRetVal) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ISymUnmanagedBinder2Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ __RPC__in ISymUnmanagedBinder2 * This,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ __RPC__in ISymUnmanagedBinder2 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ __RPC__in ISymUnmanagedBinder2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetReaderForFile )(
+ __RPC__in ISymUnmanagedBinder2 * This,
+ /* [in] */ __RPC__in_opt IUnknown *importer,
+ /* [in] */ __RPC__in const WCHAR *fileName,
+ /* [in] */ __RPC__in const WCHAR *searchPath,
+ /* [retval][out] */ __RPC__deref_out_opt ISymUnmanagedReader **pRetVal);
+
+ HRESULT ( STDMETHODCALLTYPE *GetReaderFromStream )(
+ __RPC__in ISymUnmanagedBinder2 * This,
+ /* [in] */ __RPC__in_opt IUnknown *importer,
+ /* [in] */ __RPC__in_opt IStream *pstream,
+ /* [retval][out] */ __RPC__deref_out_opt ISymUnmanagedReader **pRetVal);
+
+ HRESULT ( STDMETHODCALLTYPE *GetReaderForFile2 )(
+ __RPC__in ISymUnmanagedBinder2 * This,
+ /* [in] */ __RPC__in_opt IUnknown *importer,
+ /* [in] */ __RPC__in const WCHAR *fileName,
+ /* [in] */ __RPC__in const WCHAR *searchPath,
+ /* [in] */ ULONG32 searchPolicy,
+ /* [retval][out] */ __RPC__deref_out_opt ISymUnmanagedReader **pRetVal);
+
+ END_INTERFACE
+ } ISymUnmanagedBinder2Vtbl;
+
+ interface ISymUnmanagedBinder2
+ {
+ CONST_VTBL struct ISymUnmanagedBinder2Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ISymUnmanagedBinder2_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ISymUnmanagedBinder2_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ISymUnmanagedBinder2_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ISymUnmanagedBinder2_GetReaderForFile(This,importer,fileName,searchPath,pRetVal) \
+ ( (This)->lpVtbl -> GetReaderForFile(This,importer,fileName,searchPath,pRetVal) )
+
+#define ISymUnmanagedBinder2_GetReaderFromStream(This,importer,pstream,pRetVal) \
+ ( (This)->lpVtbl -> GetReaderFromStream(This,importer,pstream,pRetVal) )
+
+
+#define ISymUnmanagedBinder2_GetReaderForFile2(This,importer,fileName,searchPath,searchPolicy,pRetVal) \
+ ( (This)->lpVtbl -> GetReaderForFile2(This,importer,fileName,searchPath,searchPolicy,pRetVal) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ISymUnmanagedBinder2_INTERFACE_DEFINED__ */
+
+
+#ifndef __ISymUnmanagedBinder3_INTERFACE_DEFINED__
+#define __ISymUnmanagedBinder3_INTERFACE_DEFINED__
+
+/* interface ISymUnmanagedBinder3 */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_ISymUnmanagedBinder3;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("28AD3D43-B601-4d26-8A1B-25F9165AF9D7")
+ ISymUnmanagedBinder3 : public ISymUnmanagedBinder2
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetReaderFromCallback(
+ /* [in] */ __RPC__in_opt IUnknown *importer,
+ /* [in] */ __RPC__in const WCHAR *fileName,
+ /* [in] */ __RPC__in const WCHAR *searchPath,
+ /* [in] */ ULONG32 searchPolicy,
+ /* [in] */ __RPC__in_opt IUnknown *callback,
+ /* [retval][out] */ __RPC__deref_out_opt ISymUnmanagedReader **pRetVal) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ISymUnmanagedBinder3Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ __RPC__in ISymUnmanagedBinder3 * This,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ __RPC__in ISymUnmanagedBinder3 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ __RPC__in ISymUnmanagedBinder3 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetReaderForFile )(
+ __RPC__in ISymUnmanagedBinder3 * This,
+ /* [in] */ __RPC__in_opt IUnknown *importer,
+ /* [in] */ __RPC__in const WCHAR *fileName,
+ /* [in] */ __RPC__in const WCHAR *searchPath,
+ /* [retval][out] */ __RPC__deref_out_opt ISymUnmanagedReader **pRetVal);
+
+ HRESULT ( STDMETHODCALLTYPE *GetReaderFromStream )(
+ __RPC__in ISymUnmanagedBinder3 * This,
+ /* [in] */ __RPC__in_opt IUnknown *importer,
+ /* [in] */ __RPC__in_opt IStream *pstream,
+ /* [retval][out] */ __RPC__deref_out_opt ISymUnmanagedReader **pRetVal);
+
+ HRESULT ( STDMETHODCALLTYPE *GetReaderForFile2 )(
+ __RPC__in ISymUnmanagedBinder3 * This,
+ /* [in] */ __RPC__in_opt IUnknown *importer,
+ /* [in] */ __RPC__in const WCHAR *fileName,
+ /* [in] */ __RPC__in const WCHAR *searchPath,
+ /* [in] */ ULONG32 searchPolicy,
+ /* [retval][out] */ __RPC__deref_out_opt ISymUnmanagedReader **pRetVal);
+
+ HRESULT ( STDMETHODCALLTYPE *GetReaderFromCallback )(
+ __RPC__in ISymUnmanagedBinder3 * This,
+ /* [in] */ __RPC__in_opt IUnknown *importer,
+ /* [in] */ __RPC__in const WCHAR *fileName,
+ /* [in] */ __RPC__in const WCHAR *searchPath,
+ /* [in] */ ULONG32 searchPolicy,
+ /* [in] */ __RPC__in_opt IUnknown *callback,
+ /* [retval][out] */ __RPC__deref_out_opt ISymUnmanagedReader **pRetVal);
+
+ END_INTERFACE
+ } ISymUnmanagedBinder3Vtbl;
+
+ interface ISymUnmanagedBinder3
+ {
+ CONST_VTBL struct ISymUnmanagedBinder3Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ISymUnmanagedBinder3_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ISymUnmanagedBinder3_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ISymUnmanagedBinder3_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ISymUnmanagedBinder3_GetReaderForFile(This,importer,fileName,searchPath,pRetVal) \
+ ( (This)->lpVtbl -> GetReaderForFile(This,importer,fileName,searchPath,pRetVal) )
+
+#define ISymUnmanagedBinder3_GetReaderFromStream(This,importer,pstream,pRetVal) \
+ ( (This)->lpVtbl -> GetReaderFromStream(This,importer,pstream,pRetVal) )
+
+
+#define ISymUnmanagedBinder3_GetReaderForFile2(This,importer,fileName,searchPath,searchPolicy,pRetVal) \
+ ( (This)->lpVtbl -> GetReaderForFile2(This,importer,fileName,searchPath,searchPolicy,pRetVal) )
+
+
+#define ISymUnmanagedBinder3_GetReaderFromCallback(This,importer,fileName,searchPath,searchPolicy,callback,pRetVal) \
+ ( (This)->lpVtbl -> GetReaderFromCallback(This,importer,fileName,searchPath,searchPolicy,callback,pRetVal) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ISymUnmanagedBinder3_INTERFACE_DEFINED__ */
+
+
+/* interface __MIDL_itf_corsym_0000_0004 */
+/* [local] */
+
+static const int E_SYM_DESTROYED = MAKE_HRESULT(1, FACILITY_ITF, 0xdead);
+
+
+extern RPC_IF_HANDLE __MIDL_itf_corsym_0000_0004_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_corsym_0000_0004_v0_0_s_ifspec;
+
+#ifndef __ISymUnmanagedDispose_INTERFACE_DEFINED__
+#define __ISymUnmanagedDispose_INTERFACE_DEFINED__
+
+/* interface ISymUnmanagedDispose */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_ISymUnmanagedDispose;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("969708D2-05E5-4861-A3B0-96E473CDF63F")
+ ISymUnmanagedDispose : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE Destroy( void) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ISymUnmanagedDisposeVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ __RPC__in ISymUnmanagedDispose * This,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ __RPC__in ISymUnmanagedDispose * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ __RPC__in ISymUnmanagedDispose * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Destroy )(
+ __RPC__in ISymUnmanagedDispose * This);
+
+ END_INTERFACE
+ } ISymUnmanagedDisposeVtbl;
+
+ interface ISymUnmanagedDispose
+ {
+ CONST_VTBL struct ISymUnmanagedDisposeVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ISymUnmanagedDispose_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ISymUnmanagedDispose_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ISymUnmanagedDispose_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ISymUnmanagedDispose_Destroy(This) \
+ ( (This)->lpVtbl -> Destroy(This) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ISymUnmanagedDispose_INTERFACE_DEFINED__ */
+
+
+#ifndef __ISymUnmanagedDocument_INTERFACE_DEFINED__
+#define __ISymUnmanagedDocument_INTERFACE_DEFINED__
+
+/* interface ISymUnmanagedDocument */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_ISymUnmanagedDocument;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("40DE4037-7C81-3E1E-B022-AE1ABFF2CA08")
+ ISymUnmanagedDocument : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetURL(
+ /* [in] */ ULONG32 cchUrl,
+ /* [out] */ __RPC__out ULONG32 *pcchUrl,
+ /* [length_is][size_is][out] */ __RPC__out_ecount_part(cchUrl, *pcchUrl) WCHAR szUrl[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetDocumentType(
+ /* [retval][out] */ __RPC__out GUID *pRetVal) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetLanguage(
+ /* [retval][out] */ __RPC__out GUID *pRetVal) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetLanguageVendor(
+ /* [retval][out] */ __RPC__out GUID *pRetVal) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetCheckSumAlgorithmId(
+ /* [retval][out] */ __RPC__out GUID *pRetVal) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetCheckSum(
+ /* [in] */ ULONG32 cData,
+ /* [out] */ __RPC__out ULONG32 *pcData,
+ /* [length_is][size_is][out] */ __RPC__out_ecount_part(cData, *pcData) BYTE data[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE FindClosestLine(
+ /* [in] */ ULONG32 line,
+ /* [retval][out] */ __RPC__out ULONG32 *pRetVal) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE HasEmbeddedSource(
+ /* [retval][out] */ __RPC__out BOOL *pRetVal) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetSourceLength(
+ /* [retval][out] */ __RPC__out ULONG32 *pRetVal) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetSourceRange(
+ /* [in] */ ULONG32 startLine,
+ /* [in] */ ULONG32 startColumn,
+ /* [in] */ ULONG32 endLine,
+ /* [in] */ ULONG32 endColumn,
+ /* [in] */ ULONG32 cSourceBytes,
+ /* [out] */ __RPC__out ULONG32 *pcSourceBytes,
+ /* [length_is][size_is][out] */ __RPC__out_ecount_part(cSourceBytes, *pcSourceBytes) BYTE source[ ]) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ISymUnmanagedDocumentVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ __RPC__in ISymUnmanagedDocument * This,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ __RPC__in ISymUnmanagedDocument * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ __RPC__in ISymUnmanagedDocument * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetURL )(
+ __RPC__in ISymUnmanagedDocument * This,
+ /* [in] */ ULONG32 cchUrl,
+ /* [out] */ __RPC__out ULONG32 *pcchUrl,
+ /* [length_is][size_is][out] */ __RPC__out_ecount_part(cchUrl, *pcchUrl) WCHAR szUrl[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDocumentType )(
+ __RPC__in ISymUnmanagedDocument * This,
+ /* [retval][out] */ __RPC__out GUID *pRetVal);
+
+ HRESULT ( STDMETHODCALLTYPE *GetLanguage )(
+ __RPC__in ISymUnmanagedDocument * This,
+ /* [retval][out] */ __RPC__out GUID *pRetVal);
+
+ HRESULT ( STDMETHODCALLTYPE *GetLanguageVendor )(
+ __RPC__in ISymUnmanagedDocument * This,
+ /* [retval][out] */ __RPC__out GUID *pRetVal);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCheckSumAlgorithmId )(
+ __RPC__in ISymUnmanagedDocument * This,
+ /* [retval][out] */ __RPC__out GUID *pRetVal);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCheckSum )(
+ __RPC__in ISymUnmanagedDocument * This,
+ /* [in] */ ULONG32 cData,
+ /* [out] */ __RPC__out ULONG32 *pcData,
+ /* [length_is][size_is][out] */ __RPC__out_ecount_part(cData, *pcData) BYTE data[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *FindClosestLine )(
+ __RPC__in ISymUnmanagedDocument * This,
+ /* [in] */ ULONG32 line,
+ /* [retval][out] */ __RPC__out ULONG32 *pRetVal);
+
+ HRESULT ( STDMETHODCALLTYPE *HasEmbeddedSource )(
+ __RPC__in ISymUnmanagedDocument * This,
+ /* [retval][out] */ __RPC__out BOOL *pRetVal);
+
+ HRESULT ( STDMETHODCALLTYPE *GetSourceLength )(
+ __RPC__in ISymUnmanagedDocument * This,
+ /* [retval][out] */ __RPC__out ULONG32 *pRetVal);
+
+ HRESULT ( STDMETHODCALLTYPE *GetSourceRange )(
+ __RPC__in ISymUnmanagedDocument * This,
+ /* [in] */ ULONG32 startLine,
+ /* [in] */ ULONG32 startColumn,
+ /* [in] */ ULONG32 endLine,
+ /* [in] */ ULONG32 endColumn,
+ /* [in] */ ULONG32 cSourceBytes,
+ /* [out] */ __RPC__out ULONG32 *pcSourceBytes,
+ /* [length_is][size_is][out] */ __RPC__out_ecount_part(cSourceBytes, *pcSourceBytes) BYTE source[ ]);
+
+ END_INTERFACE
+ } ISymUnmanagedDocumentVtbl;
+
+ interface ISymUnmanagedDocument
+ {
+ CONST_VTBL struct ISymUnmanagedDocumentVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ISymUnmanagedDocument_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ISymUnmanagedDocument_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ISymUnmanagedDocument_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ISymUnmanagedDocument_GetURL(This,cchUrl,pcchUrl,szUrl) \
+ ( (This)->lpVtbl -> GetURL(This,cchUrl,pcchUrl,szUrl) )
+
+#define ISymUnmanagedDocument_GetDocumentType(This,pRetVal) \
+ ( (This)->lpVtbl -> GetDocumentType(This,pRetVal) )
+
+#define ISymUnmanagedDocument_GetLanguage(This,pRetVal) \
+ ( (This)->lpVtbl -> GetLanguage(This,pRetVal) )
+
+#define ISymUnmanagedDocument_GetLanguageVendor(This,pRetVal) \
+ ( (This)->lpVtbl -> GetLanguageVendor(This,pRetVal) )
+
+#define ISymUnmanagedDocument_GetCheckSumAlgorithmId(This,pRetVal) \
+ ( (This)->lpVtbl -> GetCheckSumAlgorithmId(This,pRetVal) )
+
+#define ISymUnmanagedDocument_GetCheckSum(This,cData,pcData,data) \
+ ( (This)->lpVtbl -> GetCheckSum(This,cData,pcData,data) )
+
+#define ISymUnmanagedDocument_FindClosestLine(This,line,pRetVal) \
+ ( (This)->lpVtbl -> FindClosestLine(This,line,pRetVal) )
+
+#define ISymUnmanagedDocument_HasEmbeddedSource(This,pRetVal) \
+ ( (This)->lpVtbl -> HasEmbeddedSource(This,pRetVal) )
+
+#define ISymUnmanagedDocument_GetSourceLength(This,pRetVal) \
+ ( (This)->lpVtbl -> GetSourceLength(This,pRetVal) )
+
+#define ISymUnmanagedDocument_GetSourceRange(This,startLine,startColumn,endLine,endColumn,cSourceBytes,pcSourceBytes,source) \
+ ( (This)->lpVtbl -> GetSourceRange(This,startLine,startColumn,endLine,endColumn,cSourceBytes,pcSourceBytes,source) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ISymUnmanagedDocument_INTERFACE_DEFINED__ */
+
+
+#ifndef __ISymUnmanagedDocumentWriter_INTERFACE_DEFINED__
+#define __ISymUnmanagedDocumentWriter_INTERFACE_DEFINED__
+
+/* interface ISymUnmanagedDocumentWriter */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_ISymUnmanagedDocumentWriter;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("B01FAFEB-C450-3A4D-BEEC-B4CEEC01E006")
+ ISymUnmanagedDocumentWriter : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE SetSource(
+ /* [in] */ ULONG32 sourceSize,
+ /* [size_is][in] */ __RPC__in_ecount_full(sourceSize) BYTE source[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetCheckSum(
+ /* [in] */ GUID algorithmId,
+ /* [in] */ ULONG32 checkSumSize,
+ /* [size_is][in] */ __RPC__in_ecount_full(checkSumSize) BYTE checkSum[ ]) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ISymUnmanagedDocumentWriterVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ __RPC__in ISymUnmanagedDocumentWriter * This,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ __RPC__in ISymUnmanagedDocumentWriter * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ __RPC__in ISymUnmanagedDocumentWriter * This);
+
+ HRESULT ( STDMETHODCALLTYPE *SetSource )(
+ __RPC__in ISymUnmanagedDocumentWriter * This,
+ /* [in] */ ULONG32 sourceSize,
+ /* [size_is][in] */ __RPC__in_ecount_full(sourceSize) BYTE source[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *SetCheckSum )(
+ __RPC__in ISymUnmanagedDocumentWriter * This,
+ /* [in] */ GUID algorithmId,
+ /* [in] */ ULONG32 checkSumSize,
+ /* [size_is][in] */ __RPC__in_ecount_full(checkSumSize) BYTE checkSum[ ]);
+
+ END_INTERFACE
+ } ISymUnmanagedDocumentWriterVtbl;
+
+ interface ISymUnmanagedDocumentWriter
+ {
+ CONST_VTBL struct ISymUnmanagedDocumentWriterVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ISymUnmanagedDocumentWriter_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ISymUnmanagedDocumentWriter_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ISymUnmanagedDocumentWriter_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ISymUnmanagedDocumentWriter_SetSource(This,sourceSize,source) \
+ ( (This)->lpVtbl -> SetSource(This,sourceSize,source) )
+
+#define ISymUnmanagedDocumentWriter_SetCheckSum(This,algorithmId,checkSumSize,checkSum) \
+ ( (This)->lpVtbl -> SetCheckSum(This,algorithmId,checkSumSize,checkSum) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ISymUnmanagedDocumentWriter_INTERFACE_DEFINED__ */
+
+
+#ifndef __ISymUnmanagedMethod_INTERFACE_DEFINED__
+#define __ISymUnmanagedMethod_INTERFACE_DEFINED__
+
+/* interface ISymUnmanagedMethod */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_ISymUnmanagedMethod;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("B62B923C-B500-3158-A543-24F307A8B7E1")
+ ISymUnmanagedMethod : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetToken(
+ /* [retval][out] */ __RPC__out mdMethodDef *pToken) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetSequencePointCount(
+ /* [retval][out] */ __RPC__out ULONG32 *pRetVal) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetRootScope(
+ /* [retval][out] */ __RPC__deref_out_opt ISymUnmanagedScope **pRetVal) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetScopeFromOffset(
+ /* [in] */ ULONG32 offset,
+ /* [retval][out] */ __RPC__deref_out_opt ISymUnmanagedScope **pRetVal) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetOffset(
+ /* [in] */ __RPC__in_opt ISymUnmanagedDocument *document,
+ /* [in] */ ULONG32 line,
+ /* [in] */ ULONG32 column,
+ /* [retval][out] */ __RPC__out ULONG32 *pRetVal) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetRanges(
+ /* [in] */ __RPC__in_opt ISymUnmanagedDocument *document,
+ /* [in] */ ULONG32 line,
+ /* [in] */ ULONG32 column,
+ /* [in] */ ULONG32 cRanges,
+ /* [out] */ __RPC__out ULONG32 *pcRanges,
+ /* [length_is][size_is][out] */ __RPC__out_ecount_part(cRanges, *pcRanges) ULONG32 ranges[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetParameters(
+ /* [in] */ ULONG32 cParams,
+ /* [out] */ __RPC__out ULONG32 *pcParams,
+ /* [length_is][size_is][out] */ __RPC__out_ecount_part(cParams, *pcParams) ISymUnmanagedVariable *params[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetNamespace(
+ /* [out] */ __RPC__deref_out_opt ISymUnmanagedNamespace **pRetVal) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetSourceStartEnd(
+ /* [in] */ __RPC__in_ecount_full(2) ISymUnmanagedDocument *docs[ 2 ],
+ /* [in] */ __RPC__in_ecount_full(2) ULONG32 lines[ 2 ],
+ /* [in] */ __RPC__in_ecount_full(2) ULONG32 columns[ 2 ],
+ /* [out] */ __RPC__out BOOL *pRetVal) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetSequencePoints(
+ /* [in] */ ULONG32 cPoints,
+ /* [out] */ __RPC__out ULONG32 *pcPoints,
+ /* [size_is][in] */ __RPC__in_ecount_full(cPoints) ULONG32 offsets[ ],
+ /* [size_is][in] */ __RPC__in_ecount_full(cPoints) ISymUnmanagedDocument *documents[ ],
+ /* [size_is][in] */ __RPC__in_ecount_full(cPoints) ULONG32 lines[ ],
+ /* [size_is][in] */ __RPC__in_ecount_full(cPoints) ULONG32 columns[ ],
+ /* [size_is][in] */ __RPC__in_ecount_full(cPoints) ULONG32 endLines[ ],
+ /* [size_is][in] */ __RPC__in_ecount_full(cPoints) ULONG32 endColumns[ ]) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ISymUnmanagedMethodVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ __RPC__in ISymUnmanagedMethod * This,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ __RPC__in ISymUnmanagedMethod * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ __RPC__in ISymUnmanagedMethod * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetToken )(
+ __RPC__in ISymUnmanagedMethod * This,
+ /* [retval][out] */ __RPC__out mdMethodDef *pToken);
+
+ HRESULT ( STDMETHODCALLTYPE *GetSequencePointCount )(
+ __RPC__in ISymUnmanagedMethod * This,
+ /* [retval][out] */ __RPC__out ULONG32 *pRetVal);
+
+ HRESULT ( STDMETHODCALLTYPE *GetRootScope )(
+ __RPC__in ISymUnmanagedMethod * This,
+ /* [retval][out] */ __RPC__deref_out_opt ISymUnmanagedScope **pRetVal);
+
+ HRESULT ( STDMETHODCALLTYPE *GetScopeFromOffset )(
+ __RPC__in ISymUnmanagedMethod * This,
+ /* [in] */ ULONG32 offset,
+ /* [retval][out] */ __RPC__deref_out_opt ISymUnmanagedScope **pRetVal);
+
+ HRESULT ( STDMETHODCALLTYPE *GetOffset )(
+ __RPC__in ISymUnmanagedMethod * This,
+ /* [in] */ __RPC__in_opt ISymUnmanagedDocument *document,
+ /* [in] */ ULONG32 line,
+ /* [in] */ ULONG32 column,
+ /* [retval][out] */ __RPC__out ULONG32 *pRetVal);
+
+ HRESULT ( STDMETHODCALLTYPE *GetRanges )(
+ __RPC__in ISymUnmanagedMethod * This,
+ /* [in] */ __RPC__in_opt ISymUnmanagedDocument *document,
+ /* [in] */ ULONG32 line,
+ /* [in] */ ULONG32 column,
+ /* [in] */ ULONG32 cRanges,
+ /* [out] */ __RPC__out ULONG32 *pcRanges,
+ /* [length_is][size_is][out] */ __RPC__out_ecount_part(cRanges, *pcRanges) ULONG32 ranges[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetParameters )(
+ __RPC__in ISymUnmanagedMethod * This,
+ /* [in] */ ULONG32 cParams,
+ /* [out] */ __RPC__out ULONG32 *pcParams,
+ /* [length_is][size_is][out] */ __RPC__out_ecount_part(cParams, *pcParams) ISymUnmanagedVariable *params[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetNamespace )(
+ __RPC__in ISymUnmanagedMethod * This,
+ /* [out] */ __RPC__deref_out_opt ISymUnmanagedNamespace **pRetVal);
+
+ HRESULT ( STDMETHODCALLTYPE *GetSourceStartEnd )(
+ __RPC__in ISymUnmanagedMethod * This,
+ /* [in] */ __RPC__in_ecount_full(2) ISymUnmanagedDocument *docs[ 2 ],
+ /* [in] */ __RPC__in_ecount_full(2) ULONG32 lines[ 2 ],
+ /* [in] */ __RPC__in_ecount_full(2) ULONG32 columns[ 2 ],
+ /* [out] */ __RPC__out BOOL *pRetVal);
+
+ HRESULT ( STDMETHODCALLTYPE *GetSequencePoints )(
+ __RPC__in ISymUnmanagedMethod * This,
+ /* [in] */ ULONG32 cPoints,
+ /* [out] */ __RPC__out ULONG32 *pcPoints,
+ /* [size_is][in] */ __RPC__in_ecount_full(cPoints) ULONG32 offsets[ ],
+ /* [size_is][in] */ __RPC__in_ecount_full(cPoints) ISymUnmanagedDocument *documents[ ],
+ /* [size_is][in] */ __RPC__in_ecount_full(cPoints) ULONG32 lines[ ],
+ /* [size_is][in] */ __RPC__in_ecount_full(cPoints) ULONG32 columns[ ],
+ /* [size_is][in] */ __RPC__in_ecount_full(cPoints) ULONG32 endLines[ ],
+ /* [size_is][in] */ __RPC__in_ecount_full(cPoints) ULONG32 endColumns[ ]);
+
+ END_INTERFACE
+ } ISymUnmanagedMethodVtbl;
+
+ interface ISymUnmanagedMethod
+ {
+ CONST_VTBL struct ISymUnmanagedMethodVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ISymUnmanagedMethod_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ISymUnmanagedMethod_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ISymUnmanagedMethod_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ISymUnmanagedMethod_GetToken(This,pToken) \
+ ( (This)->lpVtbl -> GetToken(This,pToken) )
+
+#define ISymUnmanagedMethod_GetSequencePointCount(This,pRetVal) \
+ ( (This)->lpVtbl -> GetSequencePointCount(This,pRetVal) )
+
+#define ISymUnmanagedMethod_GetRootScope(This,pRetVal) \
+ ( (This)->lpVtbl -> GetRootScope(This,pRetVal) )
+
+#define ISymUnmanagedMethod_GetScopeFromOffset(This,offset,pRetVal) \
+ ( (This)->lpVtbl -> GetScopeFromOffset(This,offset,pRetVal) )
+
+#define ISymUnmanagedMethod_GetOffset(This,document,line,column,pRetVal) \
+ ( (This)->lpVtbl -> GetOffset(This,document,line,column,pRetVal) )
+
+#define ISymUnmanagedMethod_GetRanges(This,document,line,column,cRanges,pcRanges,ranges) \
+ ( (This)->lpVtbl -> GetRanges(This,document,line,column,cRanges,pcRanges,ranges) )
+
+#define ISymUnmanagedMethod_GetParameters(This,cParams,pcParams,params) \
+ ( (This)->lpVtbl -> GetParameters(This,cParams,pcParams,params) )
+
+#define ISymUnmanagedMethod_GetNamespace(This,pRetVal) \
+ ( (This)->lpVtbl -> GetNamespace(This,pRetVal) )
+
+#define ISymUnmanagedMethod_GetSourceStartEnd(This,docs,lines,columns,pRetVal) \
+ ( (This)->lpVtbl -> GetSourceStartEnd(This,docs,lines,columns,pRetVal) )
+
+#define ISymUnmanagedMethod_GetSequencePoints(This,cPoints,pcPoints,offsets,documents,lines,columns,endLines,endColumns) \
+ ( (This)->lpVtbl -> GetSequencePoints(This,cPoints,pcPoints,offsets,documents,lines,columns,endLines,endColumns) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ISymUnmanagedMethod_INTERFACE_DEFINED__ */
+
+
+#ifndef __ISymENCUnmanagedMethod_INTERFACE_DEFINED__
+#define __ISymENCUnmanagedMethod_INTERFACE_DEFINED__
+
+/* interface ISymENCUnmanagedMethod */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_ISymENCUnmanagedMethod;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("85E891DA-A631-4c76-ACA2-A44A39C46B8C")
+ ISymENCUnmanagedMethod : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetFileNameFromOffset(
+ /* [in] */ ULONG32 dwOffset,
+ /* [in] */ ULONG32 cchName,
+ /* [out] */ __RPC__out ULONG32 *pcchName,
+ /* [length_is][size_is][out] */ __RPC__out_ecount_part(cchName, *pcchName) WCHAR szName[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetLineFromOffset(
+ /* [in] */ ULONG32 dwOffset,
+ /* [out] */ __RPC__out ULONG32 *pline,
+ /* [out] */ __RPC__out ULONG32 *pcolumn,
+ /* [out] */ __RPC__out ULONG32 *pendLine,
+ /* [out] */ __RPC__out ULONG32 *pendColumn,
+ /* [out] */ __RPC__out ULONG32 *pdwStartOffset) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetDocumentsForMethodCount(
+ /* [retval][out] */ __RPC__out ULONG32 *pRetVal) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetDocumentsForMethod(
+ /* [in] */ ULONG32 cDocs,
+ /* [out] */ __RPC__out ULONG32 *pcDocs,
+ /* [size_is][in] */ __RPC__in_ecount_full(cDocs) ISymUnmanagedDocument *documents[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetSourceExtentInDocument(
+ /* [in] */ __RPC__in_opt ISymUnmanagedDocument *document,
+ /* [out] */ __RPC__out ULONG32 *pstartLine,
+ /* [out] */ __RPC__out ULONG32 *pendLine) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ISymENCUnmanagedMethodVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ __RPC__in ISymENCUnmanagedMethod * This,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ __RPC__in ISymENCUnmanagedMethod * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ __RPC__in ISymENCUnmanagedMethod * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFileNameFromOffset )(
+ __RPC__in ISymENCUnmanagedMethod * This,
+ /* [in] */ ULONG32 dwOffset,
+ /* [in] */ ULONG32 cchName,
+ /* [out] */ __RPC__out ULONG32 *pcchName,
+ /* [length_is][size_is][out] */ __RPC__out_ecount_part(cchName, *pcchName) WCHAR szName[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetLineFromOffset )(
+ __RPC__in ISymENCUnmanagedMethod * This,
+ /* [in] */ ULONG32 dwOffset,
+ /* [out] */ __RPC__out ULONG32 *pline,
+ /* [out] */ __RPC__out ULONG32 *pcolumn,
+ /* [out] */ __RPC__out ULONG32 *pendLine,
+ /* [out] */ __RPC__out ULONG32 *pendColumn,
+ /* [out] */ __RPC__out ULONG32 *pdwStartOffset);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDocumentsForMethodCount )(
+ __RPC__in ISymENCUnmanagedMethod * This,
+ /* [retval][out] */ __RPC__out ULONG32 *pRetVal);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDocumentsForMethod )(
+ __RPC__in ISymENCUnmanagedMethod * This,
+ /* [in] */ ULONG32 cDocs,
+ /* [out] */ __RPC__out ULONG32 *pcDocs,
+ /* [size_is][in] */ __RPC__in_ecount_full(cDocs) ISymUnmanagedDocument *documents[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetSourceExtentInDocument )(
+ __RPC__in ISymENCUnmanagedMethod * This,
+ /* [in] */ __RPC__in_opt ISymUnmanagedDocument *document,
+ /* [out] */ __RPC__out ULONG32 *pstartLine,
+ /* [out] */ __RPC__out ULONG32 *pendLine);
+
+ END_INTERFACE
+ } ISymENCUnmanagedMethodVtbl;
+
+ interface ISymENCUnmanagedMethod
+ {
+ CONST_VTBL struct ISymENCUnmanagedMethodVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ISymENCUnmanagedMethod_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ISymENCUnmanagedMethod_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ISymENCUnmanagedMethod_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ISymENCUnmanagedMethod_GetFileNameFromOffset(This,dwOffset,cchName,pcchName,szName) \
+ ( (This)->lpVtbl -> GetFileNameFromOffset(This,dwOffset,cchName,pcchName,szName) )
+
+#define ISymENCUnmanagedMethod_GetLineFromOffset(This,dwOffset,pline,pcolumn,pendLine,pendColumn,pdwStartOffset) \
+ ( (This)->lpVtbl -> GetLineFromOffset(This,dwOffset,pline,pcolumn,pendLine,pendColumn,pdwStartOffset) )
+
+#define ISymENCUnmanagedMethod_GetDocumentsForMethodCount(This,pRetVal) \
+ ( (This)->lpVtbl -> GetDocumentsForMethodCount(This,pRetVal) )
+
+#define ISymENCUnmanagedMethod_GetDocumentsForMethod(This,cDocs,pcDocs,documents) \
+ ( (This)->lpVtbl -> GetDocumentsForMethod(This,cDocs,pcDocs,documents) )
+
+#define ISymENCUnmanagedMethod_GetSourceExtentInDocument(This,document,pstartLine,pendLine) \
+ ( (This)->lpVtbl -> GetSourceExtentInDocument(This,document,pstartLine,pendLine) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ISymENCUnmanagedMethod_INTERFACE_DEFINED__ */
+
+
+#ifndef __ISymUnmanagedNamespace_INTERFACE_DEFINED__
+#define __ISymUnmanagedNamespace_INTERFACE_DEFINED__
+
+/* interface ISymUnmanagedNamespace */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_ISymUnmanagedNamespace;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("0DFF7289-54F8-11d3-BD28-0000F80849BD")
+ ISymUnmanagedNamespace : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetName(
+ /* [in] */ ULONG32 cchName,
+ /* [out] */ __RPC__out ULONG32 *pcchName,
+ /* [length_is][size_is][out] */ __RPC__out_ecount_part(cchName, *pcchName) WCHAR szName[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetNamespaces(
+ /* [in] */ ULONG32 cNameSpaces,
+ /* [out] */ __RPC__out ULONG32 *pcNameSpaces,
+ /* [length_is][size_is][out] */ __RPC__out_ecount_part(cNameSpaces, *pcNameSpaces) ISymUnmanagedNamespace *namespaces[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetVariables(
+ /* [in] */ ULONG32 cVars,
+ /* [out] */ __RPC__out ULONG32 *pcVars,
+ /* [length_is][size_is][out] */ __RPC__out_ecount_part(cVars, *pcVars) ISymUnmanagedVariable *pVars[ ]) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ISymUnmanagedNamespaceVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ __RPC__in ISymUnmanagedNamespace * This,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ __RPC__in ISymUnmanagedNamespace * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ __RPC__in ISymUnmanagedNamespace * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetName )(
+ __RPC__in ISymUnmanagedNamespace * This,
+ /* [in] */ ULONG32 cchName,
+ /* [out] */ __RPC__out ULONG32 *pcchName,
+ /* [length_is][size_is][out] */ __RPC__out_ecount_part(cchName, *pcchName) WCHAR szName[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetNamespaces )(
+ __RPC__in ISymUnmanagedNamespace * This,
+ /* [in] */ ULONG32 cNameSpaces,
+ /* [out] */ __RPC__out ULONG32 *pcNameSpaces,
+ /* [length_is][size_is][out] */ __RPC__out_ecount_part(cNameSpaces, *pcNameSpaces) ISymUnmanagedNamespace *namespaces[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetVariables )(
+ __RPC__in ISymUnmanagedNamespace * This,
+ /* [in] */ ULONG32 cVars,
+ /* [out] */ __RPC__out ULONG32 *pcVars,
+ /* [length_is][size_is][out] */ __RPC__out_ecount_part(cVars, *pcVars) ISymUnmanagedVariable *pVars[ ]);
+
+ END_INTERFACE
+ } ISymUnmanagedNamespaceVtbl;
+
+ interface ISymUnmanagedNamespace
+ {
+ CONST_VTBL struct ISymUnmanagedNamespaceVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ISymUnmanagedNamespace_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ISymUnmanagedNamespace_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ISymUnmanagedNamespace_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ISymUnmanagedNamespace_GetName(This,cchName,pcchName,szName) \
+ ( (This)->lpVtbl -> GetName(This,cchName,pcchName,szName) )
+
+#define ISymUnmanagedNamespace_GetNamespaces(This,cNameSpaces,pcNameSpaces,namespaces) \
+ ( (This)->lpVtbl -> GetNamespaces(This,cNameSpaces,pcNameSpaces,namespaces) )
+
+#define ISymUnmanagedNamespace_GetVariables(This,cVars,pcVars,pVars) \
+ ( (This)->lpVtbl -> GetVariables(This,cVars,pcVars,pVars) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ISymUnmanagedNamespace_INTERFACE_DEFINED__ */
+
+
+#ifndef __ISymUnmanagedReader_INTERFACE_DEFINED__
+#define __ISymUnmanagedReader_INTERFACE_DEFINED__
+
+/* interface ISymUnmanagedReader */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_ISymUnmanagedReader;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("B4CE6286-2A6B-3712-A3B7-1EE1DAD467B5")
+ ISymUnmanagedReader : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetDocument(
+ /* [in] */ __RPC__in WCHAR *url,
+ /* [in] */ GUID language,
+ /* [in] */ GUID languageVendor,
+ /* [in] */ GUID documentType,
+ /* [retval][out] */ __RPC__deref_out_opt ISymUnmanagedDocument **pRetVal) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetDocuments(
+ /* [in] */ ULONG32 cDocs,
+ /* [out] */ __RPC__out ULONG32 *pcDocs,
+ /* [length_is][size_is][out] */ __RPC__out_ecount_part(cDocs, *pcDocs) ISymUnmanagedDocument *pDocs[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetUserEntryPoint(
+ /* [retval][out] */ __RPC__out mdMethodDef *pToken) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetMethod(
+ /* [in] */ mdMethodDef token,
+ /* [retval][out] */ __RPC__deref_out_opt ISymUnmanagedMethod **pRetVal) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetMethodByVersion(
+ /* [in] */ mdMethodDef token,
+ /* [in] */ int version,
+ /* [retval][out] */ __RPC__deref_out_opt ISymUnmanagedMethod **pRetVal) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetVariables(
+ /* [in] */ mdToken parent,
+ /* [in] */ ULONG32 cVars,
+ /* [out] */ __RPC__out ULONG32 *pcVars,
+ /* [length_is][size_is][out] */ __RPC__out_ecount_part(cVars, *pcVars) ISymUnmanagedVariable *pVars[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetGlobalVariables(
+ /* [in] */ ULONG32 cVars,
+ /* [out] */ __RPC__out ULONG32 *pcVars,
+ /* [length_is][size_is][out] */ __RPC__out_ecount_part(cVars, *pcVars) ISymUnmanagedVariable *pVars[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetMethodFromDocumentPosition(
+ /* [in] */ __RPC__in_opt ISymUnmanagedDocument *document,
+ /* [in] */ ULONG32 line,
+ /* [in] */ ULONG32 column,
+ /* [retval][out] */ __RPC__deref_out_opt ISymUnmanagedMethod **pRetVal) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetSymAttribute(
+ /* [in] */ mdToken parent,
+ /* [in] */ __RPC__in WCHAR *name,
+ /* [in] */ ULONG32 cBuffer,
+ /* [out] */ __RPC__out ULONG32 *pcBuffer,
+ /* [length_is][size_is][out] */ __RPC__out_ecount_part(cBuffer, *pcBuffer) BYTE buffer[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetNamespaces(
+ /* [in] */ ULONG32 cNameSpaces,
+ /* [out] */ __RPC__out ULONG32 *pcNameSpaces,
+ /* [length_is][size_is][out] */ __RPC__out_ecount_part(cNameSpaces, *pcNameSpaces) ISymUnmanagedNamespace *namespaces[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Initialize(
+ /* [in] */ __RPC__in_opt IUnknown *importer,
+ /* [in] */ __RPC__in const WCHAR *filename,
+ /* [in] */ __RPC__in const WCHAR *searchPath,
+ /* [in] */ __RPC__in_opt IStream *pIStream) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE UpdateSymbolStore(
+ /* [in] */ __RPC__in const WCHAR *filename,
+ /* [in] */ __RPC__in_opt IStream *pIStream) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ReplaceSymbolStore(
+ /* [in] */ __RPC__in const WCHAR *filename,
+ /* [in] */ __RPC__in_opt IStream *pIStream) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetSymbolStoreFileName(
+ /* [in] */ ULONG32 cchName,
+ /* [out] */ __RPC__out ULONG32 *pcchName,
+ /* [length_is][size_is][out] */ __RPC__out_ecount_part(cchName, *pcchName) WCHAR szName[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetMethodsFromDocumentPosition(
+ /* [in] */ __RPC__in_opt ISymUnmanagedDocument *document,
+ /* [in] */ ULONG32 line,
+ /* [in] */ ULONG32 column,
+ /* [in] */ ULONG32 cMethod,
+ /* [out] */ __RPC__out ULONG32 *pcMethod,
+ /* [length_is][size_is][out] */ __RPC__out_ecount_part(cMethod, *pcMethod) ISymUnmanagedMethod *pRetVal[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetDocumentVersion(
+ /* [in] */ __RPC__in_opt ISymUnmanagedDocument *pDoc,
+ /* [out] */ __RPC__out int *version,
+ /* [out] */ __RPC__out BOOL *pbCurrent) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetMethodVersion(
+ /* [in] */ __RPC__in_opt ISymUnmanagedMethod *pMethod,
+ /* [out] */ __RPC__out int *version) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ISymUnmanagedReaderVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ __RPC__in ISymUnmanagedReader * This,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ __RPC__in ISymUnmanagedReader * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ __RPC__in ISymUnmanagedReader * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDocument )(
+ __RPC__in ISymUnmanagedReader * This,
+ /* [in] */ __RPC__in WCHAR *url,
+ /* [in] */ GUID language,
+ /* [in] */ GUID languageVendor,
+ /* [in] */ GUID documentType,
+ /* [retval][out] */ __RPC__deref_out_opt ISymUnmanagedDocument **pRetVal);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDocuments )(
+ __RPC__in ISymUnmanagedReader * This,
+ /* [in] */ ULONG32 cDocs,
+ /* [out] */ __RPC__out ULONG32 *pcDocs,
+ /* [length_is][size_is][out] */ __RPC__out_ecount_part(cDocs, *pcDocs) ISymUnmanagedDocument *pDocs[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetUserEntryPoint )(
+ __RPC__in ISymUnmanagedReader * This,
+ /* [retval][out] */ __RPC__out mdMethodDef *pToken);
+
+ HRESULT ( STDMETHODCALLTYPE *GetMethod )(
+ __RPC__in ISymUnmanagedReader * This,
+ /* [in] */ mdMethodDef token,
+ /* [retval][out] */ __RPC__deref_out_opt ISymUnmanagedMethod **pRetVal);
+
+ HRESULT ( STDMETHODCALLTYPE *GetMethodByVersion )(
+ __RPC__in ISymUnmanagedReader * This,
+ /* [in] */ mdMethodDef token,
+ /* [in] */ int version,
+ /* [retval][out] */ __RPC__deref_out_opt ISymUnmanagedMethod **pRetVal);
+
+ HRESULT ( STDMETHODCALLTYPE *GetVariables )(
+ __RPC__in ISymUnmanagedReader * This,
+ /* [in] */ mdToken parent,
+ /* [in] */ ULONG32 cVars,
+ /* [out] */ __RPC__out ULONG32 *pcVars,
+ /* [length_is][size_is][out] */ __RPC__out_ecount_part(cVars, *pcVars) ISymUnmanagedVariable *pVars[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetGlobalVariables )(
+ __RPC__in ISymUnmanagedReader * This,
+ /* [in] */ ULONG32 cVars,
+ /* [out] */ __RPC__out ULONG32 *pcVars,
+ /* [length_is][size_is][out] */ __RPC__out_ecount_part(cVars, *pcVars) ISymUnmanagedVariable *pVars[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetMethodFromDocumentPosition )(
+ __RPC__in ISymUnmanagedReader * This,
+ /* [in] */ __RPC__in_opt ISymUnmanagedDocument *document,
+ /* [in] */ ULONG32 line,
+ /* [in] */ ULONG32 column,
+ /* [retval][out] */ __RPC__deref_out_opt ISymUnmanagedMethod **pRetVal);
+
+ HRESULT ( STDMETHODCALLTYPE *GetSymAttribute )(
+ __RPC__in ISymUnmanagedReader * This,
+ /* [in] */ mdToken parent,
+ /* [in] */ __RPC__in WCHAR *name,
+ /* [in] */ ULONG32 cBuffer,
+ /* [out] */ __RPC__out ULONG32 *pcBuffer,
+ /* [length_is][size_is][out] */ __RPC__out_ecount_part(cBuffer, *pcBuffer) BYTE buffer[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetNamespaces )(
+ __RPC__in ISymUnmanagedReader * This,
+ /* [in] */ ULONG32 cNameSpaces,
+ /* [out] */ __RPC__out ULONG32 *pcNameSpaces,
+ /* [length_is][size_is][out] */ __RPC__out_ecount_part(cNameSpaces, *pcNameSpaces) ISymUnmanagedNamespace *namespaces[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *Initialize )(
+ __RPC__in ISymUnmanagedReader * This,
+ /* [in] */ __RPC__in_opt IUnknown *importer,
+ /* [in] */ __RPC__in const WCHAR *filename,
+ /* [in] */ __RPC__in const WCHAR *searchPath,
+ /* [in] */ __RPC__in_opt IStream *pIStream);
+
+ HRESULT ( STDMETHODCALLTYPE *UpdateSymbolStore )(
+ __RPC__in ISymUnmanagedReader * This,
+ /* [in] */ __RPC__in const WCHAR *filename,
+ /* [in] */ __RPC__in_opt IStream *pIStream);
+
+ HRESULT ( STDMETHODCALLTYPE *ReplaceSymbolStore )(
+ __RPC__in ISymUnmanagedReader * This,
+ /* [in] */ __RPC__in const WCHAR *filename,
+ /* [in] */ __RPC__in_opt IStream *pIStream);
+
+ HRESULT ( STDMETHODCALLTYPE *GetSymbolStoreFileName )(
+ __RPC__in ISymUnmanagedReader * This,
+ /* [in] */ ULONG32 cchName,
+ /* [out] */ __RPC__out ULONG32 *pcchName,
+ /* [length_is][size_is][out] */ __RPC__out_ecount_part(cchName, *pcchName) WCHAR szName[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetMethodsFromDocumentPosition )(
+ __RPC__in ISymUnmanagedReader * This,
+ /* [in] */ __RPC__in_opt ISymUnmanagedDocument *document,
+ /* [in] */ ULONG32 line,
+ /* [in] */ ULONG32 column,
+ /* [in] */ ULONG32 cMethod,
+ /* [out] */ __RPC__out ULONG32 *pcMethod,
+ /* [length_is][size_is][out] */ __RPC__out_ecount_part(cMethod, *pcMethod) ISymUnmanagedMethod *pRetVal[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDocumentVersion )(
+ __RPC__in ISymUnmanagedReader * This,
+ /* [in] */ __RPC__in_opt ISymUnmanagedDocument *pDoc,
+ /* [out] */ __RPC__out int *version,
+ /* [out] */ __RPC__out BOOL *pbCurrent);
+
+ HRESULT ( STDMETHODCALLTYPE *GetMethodVersion )(
+ __RPC__in ISymUnmanagedReader * This,
+ /* [in] */ __RPC__in_opt ISymUnmanagedMethod *pMethod,
+ /* [out] */ __RPC__out int *version);
+
+ END_INTERFACE
+ } ISymUnmanagedReaderVtbl;
+
+ interface ISymUnmanagedReader
+ {
+ CONST_VTBL struct ISymUnmanagedReaderVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ISymUnmanagedReader_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ISymUnmanagedReader_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ISymUnmanagedReader_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ISymUnmanagedReader_GetDocument(This,url,language,languageVendor,documentType,pRetVal) \
+ ( (This)->lpVtbl -> GetDocument(This,url,language,languageVendor,documentType,pRetVal) )
+
+#define ISymUnmanagedReader_GetDocuments(This,cDocs,pcDocs,pDocs) \
+ ( (This)->lpVtbl -> GetDocuments(This,cDocs,pcDocs,pDocs) )
+
+#define ISymUnmanagedReader_GetUserEntryPoint(This,pToken) \
+ ( (This)->lpVtbl -> GetUserEntryPoint(This,pToken) )
+
+#define ISymUnmanagedReader_GetMethod(This,token,pRetVal) \
+ ( (This)->lpVtbl -> GetMethod(This,token,pRetVal) )
+
+#define ISymUnmanagedReader_GetMethodByVersion(This,token,version,pRetVal) \
+ ( (This)->lpVtbl -> GetMethodByVersion(This,token,version,pRetVal) )
+
+#define ISymUnmanagedReader_GetVariables(This,parent,cVars,pcVars,pVars) \
+ ( (This)->lpVtbl -> GetVariables(This,parent,cVars,pcVars,pVars) )
+
+#define ISymUnmanagedReader_GetGlobalVariables(This,cVars,pcVars,pVars) \
+ ( (This)->lpVtbl -> GetGlobalVariables(This,cVars,pcVars,pVars) )
+
+#define ISymUnmanagedReader_GetMethodFromDocumentPosition(This,document,line,column,pRetVal) \
+ ( (This)->lpVtbl -> GetMethodFromDocumentPosition(This,document,line,column,pRetVal) )
+
+#define ISymUnmanagedReader_GetSymAttribute(This,parent,name,cBuffer,pcBuffer,buffer) \
+ ( (This)->lpVtbl -> GetSymAttribute(This,parent,name,cBuffer,pcBuffer,buffer) )
+
+#define ISymUnmanagedReader_GetNamespaces(This,cNameSpaces,pcNameSpaces,namespaces) \
+ ( (This)->lpVtbl -> GetNamespaces(This,cNameSpaces,pcNameSpaces,namespaces) )
+
+#define ISymUnmanagedReader_Initialize(This,importer,filename,searchPath,pIStream) \
+ ( (This)->lpVtbl -> Initialize(This,importer,filename,searchPath,pIStream) )
+
+#define ISymUnmanagedReader_UpdateSymbolStore(This,filename,pIStream) \
+ ( (This)->lpVtbl -> UpdateSymbolStore(This,filename,pIStream) )
+
+#define ISymUnmanagedReader_ReplaceSymbolStore(This,filename,pIStream) \
+ ( (This)->lpVtbl -> ReplaceSymbolStore(This,filename,pIStream) )
+
+#define ISymUnmanagedReader_GetSymbolStoreFileName(This,cchName,pcchName,szName) \
+ ( (This)->lpVtbl -> GetSymbolStoreFileName(This,cchName,pcchName,szName) )
+
+#define ISymUnmanagedReader_GetMethodsFromDocumentPosition(This,document,line,column,cMethod,pcMethod,pRetVal) \
+ ( (This)->lpVtbl -> GetMethodsFromDocumentPosition(This,document,line,column,cMethod,pcMethod,pRetVal) )
+
+#define ISymUnmanagedReader_GetDocumentVersion(This,pDoc,version,pbCurrent) \
+ ( (This)->lpVtbl -> GetDocumentVersion(This,pDoc,version,pbCurrent) )
+
+#define ISymUnmanagedReader_GetMethodVersion(This,pMethod,version) \
+ ( (This)->lpVtbl -> GetMethodVersion(This,pMethod,version) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ISymUnmanagedReader_INTERFACE_DEFINED__ */
+
+
+#ifndef __ISymUnmanagedSourceServerModule_INTERFACE_DEFINED__
+#define __ISymUnmanagedSourceServerModule_INTERFACE_DEFINED__
+
+/* interface ISymUnmanagedSourceServerModule */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_ISymUnmanagedSourceServerModule;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("997DD0CC-A76F-4c82-8D79-EA87559D27AD")
+ ISymUnmanagedSourceServerModule : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetSourceServerData(
+ /* [out] */ __RPC__out ULONG *pDataByteCount,
+ /* [size_is][size_is][out] */ __RPC__deref_out_ecount_full_opt(*pDataByteCount) BYTE **ppData) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ISymUnmanagedSourceServerModuleVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ __RPC__in ISymUnmanagedSourceServerModule * This,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ __RPC__in ISymUnmanagedSourceServerModule * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ __RPC__in ISymUnmanagedSourceServerModule * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetSourceServerData )(
+ __RPC__in ISymUnmanagedSourceServerModule * This,
+ /* [out] */ __RPC__out ULONG *pDataByteCount,
+ /* [size_is][size_is][out] */ __RPC__deref_out_ecount_full_opt(*pDataByteCount) BYTE **ppData);
+
+ END_INTERFACE
+ } ISymUnmanagedSourceServerModuleVtbl;
+
+ interface ISymUnmanagedSourceServerModule
+ {
+ CONST_VTBL struct ISymUnmanagedSourceServerModuleVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ISymUnmanagedSourceServerModule_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ISymUnmanagedSourceServerModule_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ISymUnmanagedSourceServerModule_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ISymUnmanagedSourceServerModule_GetSourceServerData(This,pDataByteCount,ppData) \
+ ( (This)->lpVtbl -> GetSourceServerData(This,pDataByteCount,ppData) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ISymUnmanagedSourceServerModule_INTERFACE_DEFINED__ */
+
+
+#ifndef __ISymUnmanagedENCUpdate_INTERFACE_DEFINED__
+#define __ISymUnmanagedENCUpdate_INTERFACE_DEFINED__
+
+/* interface ISymUnmanagedENCUpdate */
+/* [unique][uuid][object] */
+
+typedef struct _SYMLINEDELTA
+ {
+ mdMethodDef mdMethod;
+ INT32 delta;
+ } SYMLINEDELTA;
+
+
+EXTERN_C const IID IID_ISymUnmanagedENCUpdate;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("E502D2DD-8671-4338-8F2A-FC08229628C4")
+ ISymUnmanagedENCUpdate : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE UpdateSymbolStore2(
+ /* [in] */ __RPC__in_opt IStream *pIStream,
+ /* [in] */ __RPC__in SYMLINEDELTA *pDeltaLines,
+ /* [in] */ ULONG cDeltaLines) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetLocalVariableCount(
+ /* [in] */ mdMethodDef mdMethodToken,
+ /* [out] */ __RPC__out ULONG *pcLocals) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetLocalVariables(
+ /* [in] */ mdMethodDef mdMethodToken,
+ /* [in] */ ULONG cLocals,
+ /* [length_is][size_is][out] */ __RPC__out_ecount_part(cLocals, *pceltFetched) ISymUnmanagedVariable *rgLocals[ ],
+ /* [out] */ __RPC__out ULONG *pceltFetched) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE InitializeForEnc( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE UpdateMethodLines(
+ /* [in] */ mdMethodDef mdMethodToken,
+ /* [size_is][in] */ __RPC__in_ecount_full(cDeltas) INT32 *pDeltas,
+ /* [in] */ ULONG cDeltas) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ISymUnmanagedENCUpdateVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ __RPC__in ISymUnmanagedENCUpdate * This,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ __RPC__in ISymUnmanagedENCUpdate * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ __RPC__in ISymUnmanagedENCUpdate * This);
+
+ HRESULT ( STDMETHODCALLTYPE *UpdateSymbolStore2 )(
+ __RPC__in ISymUnmanagedENCUpdate * This,
+ /* [in] */ __RPC__in_opt IStream *pIStream,
+ /* [in] */ __RPC__in SYMLINEDELTA *pDeltaLines,
+ /* [in] */ ULONG cDeltaLines);
+
+ HRESULT ( STDMETHODCALLTYPE *GetLocalVariableCount )(
+ __RPC__in ISymUnmanagedENCUpdate * This,
+ /* [in] */ mdMethodDef mdMethodToken,
+ /* [out] */ __RPC__out ULONG *pcLocals);
+
+ HRESULT ( STDMETHODCALLTYPE *GetLocalVariables )(
+ __RPC__in ISymUnmanagedENCUpdate * This,
+ /* [in] */ mdMethodDef mdMethodToken,
+ /* [in] */ ULONG cLocals,
+ /* [length_is][size_is][out] */ __RPC__out_ecount_part(cLocals, *pceltFetched) ISymUnmanagedVariable *rgLocals[ ],
+ /* [out] */ __RPC__out ULONG *pceltFetched);
+
+ HRESULT ( STDMETHODCALLTYPE *InitializeForEnc )(
+ __RPC__in ISymUnmanagedENCUpdate * This);
+
+ HRESULT ( STDMETHODCALLTYPE *UpdateMethodLines )(
+ __RPC__in ISymUnmanagedENCUpdate * This,
+ /* [in] */ mdMethodDef mdMethodToken,
+ /* [size_is][in] */ __RPC__in_ecount_full(cDeltas) INT32 *pDeltas,
+ /* [in] */ ULONG cDeltas);
+
+ END_INTERFACE
+ } ISymUnmanagedENCUpdateVtbl;
+
+ interface ISymUnmanagedENCUpdate
+ {
+ CONST_VTBL struct ISymUnmanagedENCUpdateVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ISymUnmanagedENCUpdate_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ISymUnmanagedENCUpdate_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ISymUnmanagedENCUpdate_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ISymUnmanagedENCUpdate_UpdateSymbolStore2(This,pIStream,pDeltaLines,cDeltaLines) \
+ ( (This)->lpVtbl -> UpdateSymbolStore2(This,pIStream,pDeltaLines,cDeltaLines) )
+
+#define ISymUnmanagedENCUpdate_GetLocalVariableCount(This,mdMethodToken,pcLocals) \
+ ( (This)->lpVtbl -> GetLocalVariableCount(This,mdMethodToken,pcLocals) )
+
+#define ISymUnmanagedENCUpdate_GetLocalVariables(This,mdMethodToken,cLocals,rgLocals,pceltFetched) \
+ ( (This)->lpVtbl -> GetLocalVariables(This,mdMethodToken,cLocals,rgLocals,pceltFetched) )
+
+#define ISymUnmanagedENCUpdate_InitializeForEnc(This) \
+ ( (This)->lpVtbl -> InitializeForEnc(This) )
+
+#define ISymUnmanagedENCUpdate_UpdateMethodLines(This,mdMethodToken,pDeltas,cDeltas) \
+ ( (This)->lpVtbl -> UpdateMethodLines(This,mdMethodToken,pDeltas,cDeltas) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ISymUnmanagedENCUpdate_INTERFACE_DEFINED__ */
+
+
+#ifndef __ISymUnmanagedReaderSymbolSearchInfo_INTERFACE_DEFINED__
+#define __ISymUnmanagedReaderSymbolSearchInfo_INTERFACE_DEFINED__
+
+/* interface ISymUnmanagedReaderSymbolSearchInfo */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_ISymUnmanagedReaderSymbolSearchInfo;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("20D9645D-03CD-4e34-9C11-9848A5B084F1")
+ ISymUnmanagedReaderSymbolSearchInfo : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetSymbolSearchInfoCount(
+ /* [out] */ __RPC__out ULONG32 *pcSearchInfo) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetSymbolSearchInfo(
+ /* [in] */ ULONG32 cSearchInfo,
+ /* [out] */ __RPC__out ULONG32 *pcSearchInfo,
+ /* [length_is][size_is][out] */ __RPC__out_ecount_part(cSearchInfo, *pcSearchInfo) ISymUnmanagedSymbolSearchInfo **rgpSearchInfo) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ISymUnmanagedReaderSymbolSearchInfoVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ __RPC__in ISymUnmanagedReaderSymbolSearchInfo * This,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ __RPC__in ISymUnmanagedReaderSymbolSearchInfo * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ __RPC__in ISymUnmanagedReaderSymbolSearchInfo * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetSymbolSearchInfoCount )(
+ __RPC__in ISymUnmanagedReaderSymbolSearchInfo * This,
+ /* [out] */ __RPC__out ULONG32 *pcSearchInfo);
+
+ HRESULT ( STDMETHODCALLTYPE *GetSymbolSearchInfo )(
+ __RPC__in ISymUnmanagedReaderSymbolSearchInfo * This,
+ /* [in] */ ULONG32 cSearchInfo,
+ /* [out] */ __RPC__out ULONG32 *pcSearchInfo,
+ /* [length_is][size_is][out] */ __RPC__out_ecount_part(cSearchInfo, *pcSearchInfo) ISymUnmanagedSymbolSearchInfo **rgpSearchInfo);
+
+ END_INTERFACE
+ } ISymUnmanagedReaderSymbolSearchInfoVtbl;
+
+ interface ISymUnmanagedReaderSymbolSearchInfo
+ {
+ CONST_VTBL struct ISymUnmanagedReaderSymbolSearchInfoVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ISymUnmanagedReaderSymbolSearchInfo_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ISymUnmanagedReaderSymbolSearchInfo_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ISymUnmanagedReaderSymbolSearchInfo_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ISymUnmanagedReaderSymbolSearchInfo_GetSymbolSearchInfoCount(This,pcSearchInfo) \
+ ( (This)->lpVtbl -> GetSymbolSearchInfoCount(This,pcSearchInfo) )
+
+#define ISymUnmanagedReaderSymbolSearchInfo_GetSymbolSearchInfo(This,cSearchInfo,pcSearchInfo,rgpSearchInfo) \
+ ( (This)->lpVtbl -> GetSymbolSearchInfo(This,cSearchInfo,pcSearchInfo,rgpSearchInfo) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ISymUnmanagedReaderSymbolSearchInfo_INTERFACE_DEFINED__ */
+
+
+#ifndef __ISymUnmanagedScope_INTERFACE_DEFINED__
+#define __ISymUnmanagedScope_INTERFACE_DEFINED__
+
+/* interface ISymUnmanagedScope */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_ISymUnmanagedScope;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("68005D0F-B8E0-3B01-84D5-A11A94154942")
+ ISymUnmanagedScope : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetMethod(
+ /* [retval][out] */ __RPC__deref_out_opt ISymUnmanagedMethod **pRetVal) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetParent(
+ /* [retval][out] */ __RPC__deref_out_opt ISymUnmanagedScope **pRetVal) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetChildren(
+ /* [in] */ ULONG32 cChildren,
+ /* [out] */ __RPC__out ULONG32 *pcChildren,
+ /* [length_is][size_is][out] */ __RPC__out_ecount_part(cChildren, *pcChildren) ISymUnmanagedScope *children[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetStartOffset(
+ /* [retval][out] */ __RPC__out ULONG32 *pRetVal) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetEndOffset(
+ /* [retval][out] */ __RPC__out ULONG32 *pRetVal) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetLocalCount(
+ /* [retval][out] */ __RPC__out ULONG32 *pRetVal) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetLocals(
+ /* [in] */ ULONG32 cLocals,
+ /* [out] */ __RPC__out ULONG32 *pcLocals,
+ /* [length_is][size_is][out] */ __RPC__out_ecount_part(cLocals, *pcLocals) ISymUnmanagedVariable *locals[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetNamespaces(
+ /* [in] */ ULONG32 cNameSpaces,
+ /* [out] */ __RPC__out ULONG32 *pcNameSpaces,
+ /* [length_is][size_is][out] */ __RPC__out_ecount_part(cNameSpaces, *pcNameSpaces) ISymUnmanagedNamespace *namespaces[ ]) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ISymUnmanagedScopeVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ __RPC__in ISymUnmanagedScope * This,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ __RPC__in ISymUnmanagedScope * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ __RPC__in ISymUnmanagedScope * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetMethod )(
+ __RPC__in ISymUnmanagedScope * This,
+ /* [retval][out] */ __RPC__deref_out_opt ISymUnmanagedMethod **pRetVal);
+
+ HRESULT ( STDMETHODCALLTYPE *GetParent )(
+ __RPC__in ISymUnmanagedScope * This,
+ /* [retval][out] */ __RPC__deref_out_opt ISymUnmanagedScope **pRetVal);
+
+ HRESULT ( STDMETHODCALLTYPE *GetChildren )(
+ __RPC__in ISymUnmanagedScope * This,
+ /* [in] */ ULONG32 cChildren,
+ /* [out] */ __RPC__out ULONG32 *pcChildren,
+ /* [length_is][size_is][out] */ __RPC__out_ecount_part(cChildren, *pcChildren) ISymUnmanagedScope *children[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetStartOffset )(
+ __RPC__in ISymUnmanagedScope * This,
+ /* [retval][out] */ __RPC__out ULONG32 *pRetVal);
+
+ HRESULT ( STDMETHODCALLTYPE *GetEndOffset )(
+ __RPC__in ISymUnmanagedScope * This,
+ /* [retval][out] */ __RPC__out ULONG32 *pRetVal);
+
+ HRESULT ( STDMETHODCALLTYPE *GetLocalCount )(
+ __RPC__in ISymUnmanagedScope * This,
+ /* [retval][out] */ __RPC__out ULONG32 *pRetVal);
+
+ HRESULT ( STDMETHODCALLTYPE *GetLocals )(
+ __RPC__in ISymUnmanagedScope * This,
+ /* [in] */ ULONG32 cLocals,
+ /* [out] */ __RPC__out ULONG32 *pcLocals,
+ /* [length_is][size_is][out] */ __RPC__out_ecount_part(cLocals, *pcLocals) ISymUnmanagedVariable *locals[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetNamespaces )(
+ __RPC__in ISymUnmanagedScope * This,
+ /* [in] */ ULONG32 cNameSpaces,
+ /* [out] */ __RPC__out ULONG32 *pcNameSpaces,
+ /* [length_is][size_is][out] */ __RPC__out_ecount_part(cNameSpaces, *pcNameSpaces) ISymUnmanagedNamespace *namespaces[ ]);
+
+ END_INTERFACE
+ } ISymUnmanagedScopeVtbl;
+
+ interface ISymUnmanagedScope
+ {
+ CONST_VTBL struct ISymUnmanagedScopeVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ISymUnmanagedScope_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ISymUnmanagedScope_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ISymUnmanagedScope_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ISymUnmanagedScope_GetMethod(This,pRetVal) \
+ ( (This)->lpVtbl -> GetMethod(This,pRetVal) )
+
+#define ISymUnmanagedScope_GetParent(This,pRetVal) \
+ ( (This)->lpVtbl -> GetParent(This,pRetVal) )
+
+#define ISymUnmanagedScope_GetChildren(This,cChildren,pcChildren,children) \
+ ( (This)->lpVtbl -> GetChildren(This,cChildren,pcChildren,children) )
+
+#define ISymUnmanagedScope_GetStartOffset(This,pRetVal) \
+ ( (This)->lpVtbl -> GetStartOffset(This,pRetVal) )
+
+#define ISymUnmanagedScope_GetEndOffset(This,pRetVal) \
+ ( (This)->lpVtbl -> GetEndOffset(This,pRetVal) )
+
+#define ISymUnmanagedScope_GetLocalCount(This,pRetVal) \
+ ( (This)->lpVtbl -> GetLocalCount(This,pRetVal) )
+
+#define ISymUnmanagedScope_GetLocals(This,cLocals,pcLocals,locals) \
+ ( (This)->lpVtbl -> GetLocals(This,cLocals,pcLocals,locals) )
+
+#define ISymUnmanagedScope_GetNamespaces(This,cNameSpaces,pcNameSpaces,namespaces) \
+ ( (This)->lpVtbl -> GetNamespaces(This,cNameSpaces,pcNameSpaces,namespaces) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ISymUnmanagedScope_INTERFACE_DEFINED__ */
+
+
+#ifndef __ISymUnmanagedConstant_INTERFACE_DEFINED__
+#define __ISymUnmanagedConstant_INTERFACE_DEFINED__
+
+/* interface ISymUnmanagedConstant */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_ISymUnmanagedConstant;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("48B25ED8-5BAD-41bc-9CEE-CD62FABC74E9")
+ ISymUnmanagedConstant : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetName(
+ /* [in] */ ULONG32 cchName,
+ /* [out] */ __RPC__out ULONG32 *pcchName,
+ /* [length_is][size_is][out] */ __RPC__out_ecount_part(cchName, *pcchName) WCHAR szName[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetValue(
+ __RPC__in VARIANT *pValue) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetSignature(
+ /* [in] */ ULONG32 cSig,
+ /* [out] */ __RPC__out ULONG32 *pcSig,
+ /* [length_is][size_is][out] */ __RPC__out_ecount_part(cSig, *pcSig) BYTE sig[ ]) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ISymUnmanagedConstantVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ __RPC__in ISymUnmanagedConstant * This,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ __RPC__in ISymUnmanagedConstant * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ __RPC__in ISymUnmanagedConstant * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetName )(
+ __RPC__in ISymUnmanagedConstant * This,
+ /* [in] */ ULONG32 cchName,
+ /* [out] */ __RPC__out ULONG32 *pcchName,
+ /* [length_is][size_is][out] */ __RPC__out_ecount_part(cchName, *pcchName) WCHAR szName[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetValue )(
+ __RPC__in ISymUnmanagedConstant * This,
+ __RPC__in VARIANT *pValue);
+
+ HRESULT ( STDMETHODCALLTYPE *GetSignature )(
+ __RPC__in ISymUnmanagedConstant * This,
+ /* [in] */ ULONG32 cSig,
+ /* [out] */ __RPC__out ULONG32 *pcSig,
+ /* [length_is][size_is][out] */ __RPC__out_ecount_part(cSig, *pcSig) BYTE sig[ ]);
+
+ END_INTERFACE
+ } ISymUnmanagedConstantVtbl;
+
+ interface ISymUnmanagedConstant
+ {
+ CONST_VTBL struct ISymUnmanagedConstantVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ISymUnmanagedConstant_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ISymUnmanagedConstant_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ISymUnmanagedConstant_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ISymUnmanagedConstant_GetName(This,cchName,pcchName,szName) \
+ ( (This)->lpVtbl -> GetName(This,cchName,pcchName,szName) )
+
+#define ISymUnmanagedConstant_GetValue(This,pValue) \
+ ( (This)->lpVtbl -> GetValue(This,pValue) )
+
+#define ISymUnmanagedConstant_GetSignature(This,cSig,pcSig,sig) \
+ ( (This)->lpVtbl -> GetSignature(This,cSig,pcSig,sig) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ISymUnmanagedConstant_INTERFACE_DEFINED__ */
+
+
+#ifndef __ISymUnmanagedScope2_INTERFACE_DEFINED__
+#define __ISymUnmanagedScope2_INTERFACE_DEFINED__
+
+/* interface ISymUnmanagedScope2 */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_ISymUnmanagedScope2;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("AE932FBA-3FD8-4dba-8232-30A2309B02DB")
+ ISymUnmanagedScope2 : public ISymUnmanagedScope
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetConstantCount(
+ /* [retval][out] */ __RPC__out ULONG32 *pRetVal) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetConstants(
+ /* [in] */ ULONG32 cConstants,
+ /* [out] */ __RPC__out ULONG32 *pcConstants,
+ /* [length_is][size_is][out] */ __RPC__out_ecount_part(cConstants, *pcConstants) ISymUnmanagedConstant *constants[ ]) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ISymUnmanagedScope2Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ __RPC__in ISymUnmanagedScope2 * This,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ __RPC__in ISymUnmanagedScope2 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ __RPC__in ISymUnmanagedScope2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetMethod )(
+ __RPC__in ISymUnmanagedScope2 * This,
+ /* [retval][out] */ __RPC__deref_out_opt ISymUnmanagedMethod **pRetVal);
+
+ HRESULT ( STDMETHODCALLTYPE *GetParent )(
+ __RPC__in ISymUnmanagedScope2 * This,
+ /* [retval][out] */ __RPC__deref_out_opt ISymUnmanagedScope **pRetVal);
+
+ HRESULT ( STDMETHODCALLTYPE *GetChildren )(
+ __RPC__in ISymUnmanagedScope2 * This,
+ /* [in] */ ULONG32 cChildren,
+ /* [out] */ __RPC__out ULONG32 *pcChildren,
+ /* [length_is][size_is][out] */ __RPC__out_ecount_part(cChildren, *pcChildren) ISymUnmanagedScope *children[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetStartOffset )(
+ __RPC__in ISymUnmanagedScope2 * This,
+ /* [retval][out] */ __RPC__out ULONG32 *pRetVal);
+
+ HRESULT ( STDMETHODCALLTYPE *GetEndOffset )(
+ __RPC__in ISymUnmanagedScope2 * This,
+ /* [retval][out] */ __RPC__out ULONG32 *pRetVal);
+
+ HRESULT ( STDMETHODCALLTYPE *GetLocalCount )(
+ __RPC__in ISymUnmanagedScope2 * This,
+ /* [retval][out] */ __RPC__out ULONG32 *pRetVal);
+
+ HRESULT ( STDMETHODCALLTYPE *GetLocals )(
+ __RPC__in ISymUnmanagedScope2 * This,
+ /* [in] */ ULONG32 cLocals,
+ /* [out] */ __RPC__out ULONG32 *pcLocals,
+ /* [length_is][size_is][out] */ __RPC__out_ecount_part(cLocals, *pcLocals) ISymUnmanagedVariable *locals[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetNamespaces )(
+ __RPC__in ISymUnmanagedScope2 * This,
+ /* [in] */ ULONG32 cNameSpaces,
+ /* [out] */ __RPC__out ULONG32 *pcNameSpaces,
+ /* [length_is][size_is][out] */ __RPC__out_ecount_part(cNameSpaces, *pcNameSpaces) ISymUnmanagedNamespace *namespaces[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetConstantCount )(
+ __RPC__in ISymUnmanagedScope2 * This,
+ /* [retval][out] */ __RPC__out ULONG32 *pRetVal);
+
+ HRESULT ( STDMETHODCALLTYPE *GetConstants )(
+ __RPC__in ISymUnmanagedScope2 * This,
+ /* [in] */ ULONG32 cConstants,
+ /* [out] */ __RPC__out ULONG32 *pcConstants,
+ /* [length_is][size_is][out] */ __RPC__out_ecount_part(cConstants, *pcConstants) ISymUnmanagedConstant *constants[ ]);
+
+ END_INTERFACE
+ } ISymUnmanagedScope2Vtbl;
+
+ interface ISymUnmanagedScope2
+ {
+ CONST_VTBL struct ISymUnmanagedScope2Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ISymUnmanagedScope2_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ISymUnmanagedScope2_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ISymUnmanagedScope2_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ISymUnmanagedScope2_GetMethod(This,pRetVal) \
+ ( (This)->lpVtbl -> GetMethod(This,pRetVal) )
+
+#define ISymUnmanagedScope2_GetParent(This,pRetVal) \
+ ( (This)->lpVtbl -> GetParent(This,pRetVal) )
+
+#define ISymUnmanagedScope2_GetChildren(This,cChildren,pcChildren,children) \
+ ( (This)->lpVtbl -> GetChildren(This,cChildren,pcChildren,children) )
+
+#define ISymUnmanagedScope2_GetStartOffset(This,pRetVal) \
+ ( (This)->lpVtbl -> GetStartOffset(This,pRetVal) )
+
+#define ISymUnmanagedScope2_GetEndOffset(This,pRetVal) \
+ ( (This)->lpVtbl -> GetEndOffset(This,pRetVal) )
+
+#define ISymUnmanagedScope2_GetLocalCount(This,pRetVal) \
+ ( (This)->lpVtbl -> GetLocalCount(This,pRetVal) )
+
+#define ISymUnmanagedScope2_GetLocals(This,cLocals,pcLocals,locals) \
+ ( (This)->lpVtbl -> GetLocals(This,cLocals,pcLocals,locals) )
+
+#define ISymUnmanagedScope2_GetNamespaces(This,cNameSpaces,pcNameSpaces,namespaces) \
+ ( (This)->lpVtbl -> GetNamespaces(This,cNameSpaces,pcNameSpaces,namespaces) )
+
+
+#define ISymUnmanagedScope2_GetConstantCount(This,pRetVal) \
+ ( (This)->lpVtbl -> GetConstantCount(This,pRetVal) )
+
+#define ISymUnmanagedScope2_GetConstants(This,cConstants,pcConstants,constants) \
+ ( (This)->lpVtbl -> GetConstants(This,cConstants,pcConstants,constants) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ISymUnmanagedScope2_INTERFACE_DEFINED__ */
+
+
+#ifndef __ISymUnmanagedVariable_INTERFACE_DEFINED__
+#define __ISymUnmanagedVariable_INTERFACE_DEFINED__
+
+/* interface ISymUnmanagedVariable */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_ISymUnmanagedVariable;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("9F60EEBE-2D9A-3F7C-BF58-80BC991C60BB")
+ ISymUnmanagedVariable : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetName(
+ /* [in] */ ULONG32 cchName,
+ /* [out] */ __RPC__out ULONG32 *pcchName,
+ /* [length_is][size_is][out] */ __RPC__out_ecount_part(cchName, *pcchName) WCHAR szName[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetAttributes(
+ /* [retval][out] */ __RPC__out ULONG32 *pRetVal) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetSignature(
+ /* [in] */ ULONG32 cSig,
+ /* [out] */ __RPC__out ULONG32 *pcSig,
+ /* [length_is][size_is][out] */ __RPC__out_ecount_part(cSig, *pcSig) BYTE sig[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetAddressKind(
+ /* [retval][out] */ __RPC__out ULONG32 *pRetVal) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetAddressField1(
+ /* [retval][out] */ __RPC__out ULONG32 *pRetVal) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetAddressField2(
+ /* [retval][out] */ __RPC__out ULONG32 *pRetVal) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetAddressField3(
+ /* [retval][out] */ __RPC__out ULONG32 *pRetVal) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetStartOffset(
+ /* [retval][out] */ __RPC__out ULONG32 *pRetVal) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetEndOffset(
+ /* [retval][out] */ __RPC__out ULONG32 *pRetVal) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ISymUnmanagedVariableVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ __RPC__in ISymUnmanagedVariable * This,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ __RPC__in ISymUnmanagedVariable * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ __RPC__in ISymUnmanagedVariable * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetName )(
+ __RPC__in ISymUnmanagedVariable * This,
+ /* [in] */ ULONG32 cchName,
+ /* [out] */ __RPC__out ULONG32 *pcchName,
+ /* [length_is][size_is][out] */ __RPC__out_ecount_part(cchName, *pcchName) WCHAR szName[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAttributes )(
+ __RPC__in ISymUnmanagedVariable * This,
+ /* [retval][out] */ __RPC__out ULONG32 *pRetVal);
+
+ HRESULT ( STDMETHODCALLTYPE *GetSignature )(
+ __RPC__in ISymUnmanagedVariable * This,
+ /* [in] */ ULONG32 cSig,
+ /* [out] */ __RPC__out ULONG32 *pcSig,
+ /* [length_is][size_is][out] */ __RPC__out_ecount_part(cSig, *pcSig) BYTE sig[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAddressKind )(
+ __RPC__in ISymUnmanagedVariable * This,
+ /* [retval][out] */ __RPC__out ULONG32 *pRetVal);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAddressField1 )(
+ __RPC__in ISymUnmanagedVariable * This,
+ /* [retval][out] */ __RPC__out ULONG32 *pRetVal);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAddressField2 )(
+ __RPC__in ISymUnmanagedVariable * This,
+ /* [retval][out] */ __RPC__out ULONG32 *pRetVal);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAddressField3 )(
+ __RPC__in ISymUnmanagedVariable * This,
+ /* [retval][out] */ __RPC__out ULONG32 *pRetVal);
+
+ HRESULT ( STDMETHODCALLTYPE *GetStartOffset )(
+ __RPC__in ISymUnmanagedVariable * This,
+ /* [retval][out] */ __RPC__out ULONG32 *pRetVal);
+
+ HRESULT ( STDMETHODCALLTYPE *GetEndOffset )(
+ __RPC__in ISymUnmanagedVariable * This,
+ /* [retval][out] */ __RPC__out ULONG32 *pRetVal);
+
+ END_INTERFACE
+ } ISymUnmanagedVariableVtbl;
+
+ interface ISymUnmanagedVariable
+ {
+ CONST_VTBL struct ISymUnmanagedVariableVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ISymUnmanagedVariable_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ISymUnmanagedVariable_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ISymUnmanagedVariable_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ISymUnmanagedVariable_GetName(This,cchName,pcchName,szName) \
+ ( (This)->lpVtbl -> GetName(This,cchName,pcchName,szName) )
+
+#define ISymUnmanagedVariable_GetAttributes(This,pRetVal) \
+ ( (This)->lpVtbl -> GetAttributes(This,pRetVal) )
+
+#define ISymUnmanagedVariable_GetSignature(This,cSig,pcSig,sig) \
+ ( (This)->lpVtbl -> GetSignature(This,cSig,pcSig,sig) )
+
+#define ISymUnmanagedVariable_GetAddressKind(This,pRetVal) \
+ ( (This)->lpVtbl -> GetAddressKind(This,pRetVal) )
+
+#define ISymUnmanagedVariable_GetAddressField1(This,pRetVal) \
+ ( (This)->lpVtbl -> GetAddressField1(This,pRetVal) )
+
+#define ISymUnmanagedVariable_GetAddressField2(This,pRetVal) \
+ ( (This)->lpVtbl -> GetAddressField2(This,pRetVal) )
+
+#define ISymUnmanagedVariable_GetAddressField3(This,pRetVal) \
+ ( (This)->lpVtbl -> GetAddressField3(This,pRetVal) )
+
+#define ISymUnmanagedVariable_GetStartOffset(This,pRetVal) \
+ ( (This)->lpVtbl -> GetStartOffset(This,pRetVal) )
+
+#define ISymUnmanagedVariable_GetEndOffset(This,pRetVal) \
+ ( (This)->lpVtbl -> GetEndOffset(This,pRetVal) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ISymUnmanagedVariable_INTERFACE_DEFINED__ */
+
+
+#ifndef __ISymUnmanagedSymbolSearchInfo_INTERFACE_DEFINED__
+#define __ISymUnmanagedSymbolSearchInfo_INTERFACE_DEFINED__
+
+/* interface ISymUnmanagedSymbolSearchInfo */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_ISymUnmanagedSymbolSearchInfo;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("F8B3534A-A46B-4980-B520-BEC4ACEABA8F")
+ ISymUnmanagedSymbolSearchInfo : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetSearchPathLength(
+ /* [out] */ __RPC__out ULONG32 *pcchPath) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetSearchPath(
+ /* [in] */ ULONG32 cchPath,
+ /* [out] */ __RPC__out ULONG32 *pcchPath,
+ /* [length_is][size_is][out] */ __RPC__out_ecount_part(cchPath, *pcchPath) WCHAR szPath[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetHRESULT(
+ /* [out] */ __RPC__out HRESULT *phr) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ISymUnmanagedSymbolSearchInfoVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ __RPC__in ISymUnmanagedSymbolSearchInfo * This,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ __RPC__in ISymUnmanagedSymbolSearchInfo * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ __RPC__in ISymUnmanagedSymbolSearchInfo * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetSearchPathLength )(
+ __RPC__in ISymUnmanagedSymbolSearchInfo * This,
+ /* [out] */ __RPC__out ULONG32 *pcchPath);
+
+ HRESULT ( STDMETHODCALLTYPE *GetSearchPath )(
+ __RPC__in ISymUnmanagedSymbolSearchInfo * This,
+ /* [in] */ ULONG32 cchPath,
+ /* [out] */ __RPC__out ULONG32 *pcchPath,
+ /* [length_is][size_is][out] */ __RPC__out_ecount_part(cchPath, *pcchPath) WCHAR szPath[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetHRESULT )(
+ __RPC__in ISymUnmanagedSymbolSearchInfo * This,
+ /* [out] */ __RPC__out HRESULT *phr);
+
+ END_INTERFACE
+ } ISymUnmanagedSymbolSearchInfoVtbl;
+
+ interface ISymUnmanagedSymbolSearchInfo
+ {
+ CONST_VTBL struct ISymUnmanagedSymbolSearchInfoVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ISymUnmanagedSymbolSearchInfo_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ISymUnmanagedSymbolSearchInfo_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ISymUnmanagedSymbolSearchInfo_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ISymUnmanagedSymbolSearchInfo_GetSearchPathLength(This,pcchPath) \
+ ( (This)->lpVtbl -> GetSearchPathLength(This,pcchPath) )
+
+#define ISymUnmanagedSymbolSearchInfo_GetSearchPath(This,cchPath,pcchPath,szPath) \
+ ( (This)->lpVtbl -> GetSearchPath(This,cchPath,pcchPath,szPath) )
+
+#define ISymUnmanagedSymbolSearchInfo_GetHRESULT(This,phr) \
+ ( (This)->lpVtbl -> GetHRESULT(This,phr) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ISymUnmanagedSymbolSearchInfo_INTERFACE_DEFINED__ */
+
+
+#ifndef __ISymUnmanagedWriter_INTERFACE_DEFINED__
+#define __ISymUnmanagedWriter_INTERFACE_DEFINED__
+
+/* interface ISymUnmanagedWriter */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_ISymUnmanagedWriter;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("ED14AA72-78E2-4884-84E2-334293AE5214")
+ ISymUnmanagedWriter : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE DefineDocument(
+ /* [in] */ __RPC__in const WCHAR *url,
+ /* [in] */ __RPC__in const GUID *language,
+ /* [in] */ __RPC__in const GUID *languageVendor,
+ /* [in] */ __RPC__in const GUID *documentType,
+ /* [retval][out] */ __RPC__deref_out_opt ISymUnmanagedDocumentWriter **pRetVal) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetUserEntryPoint(
+ /* [in] */ mdMethodDef entryMethod) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE OpenMethod(
+ /* [in] */ mdMethodDef method) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE CloseMethod( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE OpenScope(
+ /* [in] */ ULONG32 startOffset,
+ /* [retval][out] */ __RPC__out ULONG32 *pRetVal) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE CloseScope(
+ /* [in] */ ULONG32 endOffset) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetScopeRange(
+ /* [in] */ ULONG32 scopeID,
+ /* [in] */ ULONG32 startOffset,
+ /* [in] */ ULONG32 endOffset) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE DefineLocalVariable(
+ /* [in] */ __RPC__in const WCHAR *name,
+ /* [in] */ ULONG32 attributes,
+ /* [in] */ ULONG32 cSig,
+ /* [size_is][in] */ __RPC__in_ecount_full(cSig) unsigned char signature[ ],
+ /* [in] */ ULONG32 addrKind,
+ /* [in] */ ULONG32 addr1,
+ /* [in] */ ULONG32 addr2,
+ /* [in] */ ULONG32 addr3,
+ /* [in] */ ULONG32 startOffset,
+ /* [in] */ ULONG32 endOffset) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE DefineParameter(
+ /* [in] */ __RPC__in const WCHAR *name,
+ /* [in] */ ULONG32 attributes,
+ /* [in] */ ULONG32 sequence,
+ /* [in] */ ULONG32 addrKind,
+ /* [in] */ ULONG32 addr1,
+ /* [in] */ ULONG32 addr2,
+ /* [in] */ ULONG32 addr3) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE DefineField(
+ /* [in] */ mdTypeDef parent,
+ /* [in] */ __RPC__in const WCHAR *name,
+ /* [in] */ ULONG32 attributes,
+ /* [in] */ ULONG32 cSig,
+ /* [size_is][in] */ __RPC__in_ecount_full(cSig) unsigned char signature[ ],
+ /* [in] */ ULONG32 addrKind,
+ /* [in] */ ULONG32 addr1,
+ /* [in] */ ULONG32 addr2,
+ /* [in] */ ULONG32 addr3) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE DefineGlobalVariable(
+ /* [in] */ __RPC__in const WCHAR *name,
+ /* [in] */ ULONG32 attributes,
+ /* [in] */ ULONG32 cSig,
+ /* [size_is][in] */ __RPC__in_ecount_full(cSig) unsigned char signature[ ],
+ /* [in] */ ULONG32 addrKind,
+ /* [in] */ ULONG32 addr1,
+ /* [in] */ ULONG32 addr2,
+ /* [in] */ ULONG32 addr3) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Close( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetSymAttribute(
+ /* [in] */ mdToken parent,
+ /* [in] */ __RPC__in const WCHAR *name,
+ /* [in] */ ULONG32 cData,
+ /* [size_is][in] */ __RPC__in_ecount_full(cData) unsigned char data[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE OpenNamespace(
+ /* [in] */ __RPC__in const WCHAR *name) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE CloseNamespace( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE UsingNamespace(
+ /* [in] */ __RPC__in const WCHAR *fullName) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetMethodSourceRange(
+ /* [in] */ __RPC__in_opt ISymUnmanagedDocumentWriter *startDoc,
+ /* [in] */ ULONG32 startLine,
+ /* [in] */ ULONG32 startColumn,
+ /* [in] */ __RPC__in_opt ISymUnmanagedDocumentWriter *endDoc,
+ /* [in] */ ULONG32 endLine,
+ /* [in] */ ULONG32 endColumn) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Initialize(
+ /* [in] */ __RPC__in_opt IUnknown *emitter,
+ /* [in] */ __RPC__in const WCHAR *filename,
+ /* [in] */ __RPC__in_opt IStream *pIStream,
+ /* [in] */ BOOL fFullBuild) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetDebugInfo(
+ /* [out][in] */ __RPC__inout IMAGE_DEBUG_DIRECTORY *pIDD,
+ /* [in] */ DWORD cData,
+ /* [out] */ __RPC__out DWORD *pcData,
+ /* [length_is][size_is][out] */ __RPC__out_ecount_part(cData, *pcData) BYTE data[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE DefineSequencePoints(
+ /* [in] */ __RPC__in_opt ISymUnmanagedDocumentWriter *document,
+ /* [in] */ ULONG32 spCount,
+ /* [size_is][in] */ __RPC__in_ecount_full(spCount) ULONG32 offsets[ ],
+ /* [size_is][in] */ __RPC__in_ecount_full(spCount) ULONG32 lines[ ],
+ /* [size_is][in] */ __RPC__in_ecount_full(spCount) ULONG32 columns[ ],
+ /* [size_is][in] */ __RPC__in_ecount_full(spCount) ULONG32 endLines[ ],
+ /* [size_is][in] */ __RPC__in_ecount_full(spCount) ULONG32 endColumns[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE RemapToken(
+ /* [in] */ mdToken oldToken,
+ /* [in] */ mdToken newToken) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Initialize2(
+ /* [in] */ __RPC__in_opt IUnknown *emitter,
+ /* [in] */ __RPC__in const WCHAR *tempfilename,
+ /* [in] */ __RPC__in_opt IStream *pIStream,
+ /* [in] */ BOOL fFullBuild,
+ /* [in] */ __RPC__in const WCHAR *finalfilename) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE DefineConstant(
+ /* [in] */ __RPC__in const WCHAR *name,
+ /* [in] */ VARIANT value,
+ /* [in] */ ULONG32 cSig,
+ /* [size_is][in] */ __RPC__in_ecount_full(cSig) unsigned char signature[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Abort( void) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ISymUnmanagedWriterVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ __RPC__in ISymUnmanagedWriter * This,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ __RPC__in ISymUnmanagedWriter * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ __RPC__in ISymUnmanagedWriter * This);
+
+ HRESULT ( STDMETHODCALLTYPE *DefineDocument )(
+ __RPC__in ISymUnmanagedWriter * This,
+ /* [in] */ __RPC__in const WCHAR *url,
+ /* [in] */ __RPC__in const GUID *language,
+ /* [in] */ __RPC__in const GUID *languageVendor,
+ /* [in] */ __RPC__in const GUID *documentType,
+ /* [retval][out] */ __RPC__deref_out_opt ISymUnmanagedDocumentWriter **pRetVal);
+
+ HRESULT ( STDMETHODCALLTYPE *SetUserEntryPoint )(
+ __RPC__in ISymUnmanagedWriter * This,
+ /* [in] */ mdMethodDef entryMethod);
+
+ HRESULT ( STDMETHODCALLTYPE *OpenMethod )(
+ __RPC__in ISymUnmanagedWriter * This,
+ /* [in] */ mdMethodDef method);
+
+ HRESULT ( STDMETHODCALLTYPE *CloseMethod )(
+ __RPC__in ISymUnmanagedWriter * This);
+
+ HRESULT ( STDMETHODCALLTYPE *OpenScope )(
+ __RPC__in ISymUnmanagedWriter * This,
+ /* [in] */ ULONG32 startOffset,
+ /* [retval][out] */ __RPC__out ULONG32 *pRetVal);
+
+ HRESULT ( STDMETHODCALLTYPE *CloseScope )(
+ __RPC__in ISymUnmanagedWriter * This,
+ /* [in] */ ULONG32 endOffset);
+
+ HRESULT ( STDMETHODCALLTYPE *SetScopeRange )(
+ __RPC__in ISymUnmanagedWriter * This,
+ /* [in] */ ULONG32 scopeID,
+ /* [in] */ ULONG32 startOffset,
+ /* [in] */ ULONG32 endOffset);
+
+ HRESULT ( STDMETHODCALLTYPE *DefineLocalVariable )(
+ __RPC__in ISymUnmanagedWriter * This,
+ /* [in] */ __RPC__in const WCHAR *name,
+ /* [in] */ ULONG32 attributes,
+ /* [in] */ ULONG32 cSig,
+ /* [size_is][in] */ __RPC__in_ecount_full(cSig) unsigned char signature[ ],
+ /* [in] */ ULONG32 addrKind,
+ /* [in] */ ULONG32 addr1,
+ /* [in] */ ULONG32 addr2,
+ /* [in] */ ULONG32 addr3,
+ /* [in] */ ULONG32 startOffset,
+ /* [in] */ ULONG32 endOffset);
+
+ HRESULT ( STDMETHODCALLTYPE *DefineParameter )(
+ __RPC__in ISymUnmanagedWriter * This,
+ /* [in] */ __RPC__in const WCHAR *name,
+ /* [in] */ ULONG32 attributes,
+ /* [in] */ ULONG32 sequence,
+ /* [in] */ ULONG32 addrKind,
+ /* [in] */ ULONG32 addr1,
+ /* [in] */ ULONG32 addr2,
+ /* [in] */ ULONG32 addr3);
+
+ HRESULT ( STDMETHODCALLTYPE *DefineField )(
+ __RPC__in ISymUnmanagedWriter * This,
+ /* [in] */ mdTypeDef parent,
+ /* [in] */ __RPC__in const WCHAR *name,
+ /* [in] */ ULONG32 attributes,
+ /* [in] */ ULONG32 cSig,
+ /* [size_is][in] */ __RPC__in_ecount_full(cSig) unsigned char signature[ ],
+ /* [in] */ ULONG32 addrKind,
+ /* [in] */ ULONG32 addr1,
+ /* [in] */ ULONG32 addr2,
+ /* [in] */ ULONG32 addr3);
+
+ HRESULT ( STDMETHODCALLTYPE *DefineGlobalVariable )(
+ __RPC__in ISymUnmanagedWriter * This,
+ /* [in] */ __RPC__in const WCHAR *name,
+ /* [in] */ ULONG32 attributes,
+ /* [in] */ ULONG32 cSig,
+ /* [size_is][in] */ __RPC__in_ecount_full(cSig) unsigned char signature[ ],
+ /* [in] */ ULONG32 addrKind,
+ /* [in] */ ULONG32 addr1,
+ /* [in] */ ULONG32 addr2,
+ /* [in] */ ULONG32 addr3);
+
+ HRESULT ( STDMETHODCALLTYPE *Close )(
+ __RPC__in ISymUnmanagedWriter * This);
+
+ HRESULT ( STDMETHODCALLTYPE *SetSymAttribute )(
+ __RPC__in ISymUnmanagedWriter * This,
+ /* [in] */ mdToken parent,
+ /* [in] */ __RPC__in const WCHAR *name,
+ /* [in] */ ULONG32 cData,
+ /* [size_is][in] */ __RPC__in_ecount_full(cData) unsigned char data[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *OpenNamespace )(
+ __RPC__in ISymUnmanagedWriter * This,
+ /* [in] */ __RPC__in const WCHAR *name);
+
+ HRESULT ( STDMETHODCALLTYPE *CloseNamespace )(
+ __RPC__in ISymUnmanagedWriter * This);
+
+ HRESULT ( STDMETHODCALLTYPE *UsingNamespace )(
+ __RPC__in ISymUnmanagedWriter * This,
+ /* [in] */ __RPC__in const WCHAR *fullName);
+
+ HRESULT ( STDMETHODCALLTYPE *SetMethodSourceRange )(
+ __RPC__in ISymUnmanagedWriter * This,
+ /* [in] */ __RPC__in_opt ISymUnmanagedDocumentWriter *startDoc,
+ /* [in] */ ULONG32 startLine,
+ /* [in] */ ULONG32 startColumn,
+ /* [in] */ __RPC__in_opt ISymUnmanagedDocumentWriter *endDoc,
+ /* [in] */ ULONG32 endLine,
+ /* [in] */ ULONG32 endColumn);
+
+ HRESULT ( STDMETHODCALLTYPE *Initialize )(
+ __RPC__in ISymUnmanagedWriter * This,
+ /* [in] */ __RPC__in_opt IUnknown *emitter,
+ /* [in] */ __RPC__in const WCHAR *filename,
+ /* [in] */ __RPC__in_opt IStream *pIStream,
+ /* [in] */ BOOL fFullBuild);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDebugInfo )(
+ __RPC__in ISymUnmanagedWriter * This,
+ /* [out][in] */ __RPC__inout IMAGE_DEBUG_DIRECTORY *pIDD,
+ /* [in] */ DWORD cData,
+ /* [out] */ __RPC__out DWORD *pcData,
+ /* [length_is][size_is][out] */ __RPC__out_ecount_part(cData, *pcData) BYTE data[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *DefineSequencePoints )(
+ __RPC__in ISymUnmanagedWriter * This,
+ /* [in] */ __RPC__in_opt ISymUnmanagedDocumentWriter *document,
+ /* [in] */ ULONG32 spCount,
+ /* [size_is][in] */ __RPC__in_ecount_full(spCount) ULONG32 offsets[ ],
+ /* [size_is][in] */ __RPC__in_ecount_full(spCount) ULONG32 lines[ ],
+ /* [size_is][in] */ __RPC__in_ecount_full(spCount) ULONG32 columns[ ],
+ /* [size_is][in] */ __RPC__in_ecount_full(spCount) ULONG32 endLines[ ],
+ /* [size_is][in] */ __RPC__in_ecount_full(spCount) ULONG32 endColumns[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *RemapToken )(
+ __RPC__in ISymUnmanagedWriter * This,
+ /* [in] */ mdToken oldToken,
+ /* [in] */ mdToken newToken);
+
+ HRESULT ( STDMETHODCALLTYPE *Initialize2 )(
+ __RPC__in ISymUnmanagedWriter * This,
+ /* [in] */ __RPC__in_opt IUnknown *emitter,
+ /* [in] */ __RPC__in const WCHAR *tempfilename,
+ /* [in] */ __RPC__in_opt IStream *pIStream,
+ /* [in] */ BOOL fFullBuild,
+ /* [in] */ __RPC__in const WCHAR *finalfilename);
+
+ HRESULT ( STDMETHODCALLTYPE *DefineConstant )(
+ __RPC__in ISymUnmanagedWriter * This,
+ /* [in] */ __RPC__in const WCHAR *name,
+ /* [in] */ VARIANT value,
+ /* [in] */ ULONG32 cSig,
+ /* [size_is][in] */ __RPC__in_ecount_full(cSig) unsigned char signature[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *Abort )(
+ __RPC__in ISymUnmanagedWriter * This);
+
+ END_INTERFACE
+ } ISymUnmanagedWriterVtbl;
+
+ interface ISymUnmanagedWriter
+ {
+ CONST_VTBL struct ISymUnmanagedWriterVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ISymUnmanagedWriter_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ISymUnmanagedWriter_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ISymUnmanagedWriter_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ISymUnmanagedWriter_DefineDocument(This,url,language,languageVendor,documentType,pRetVal) \
+ ( (This)->lpVtbl -> DefineDocument(This,url,language,languageVendor,documentType,pRetVal) )
+
+#define ISymUnmanagedWriter_SetUserEntryPoint(This,entryMethod) \
+ ( (This)->lpVtbl -> SetUserEntryPoint(This,entryMethod) )
+
+#define ISymUnmanagedWriter_OpenMethod(This,method) \
+ ( (This)->lpVtbl -> OpenMethod(This,method) )
+
+#define ISymUnmanagedWriter_CloseMethod(This) \
+ ( (This)->lpVtbl -> CloseMethod(This) )
+
+#define ISymUnmanagedWriter_OpenScope(This,startOffset,pRetVal) \
+ ( (This)->lpVtbl -> OpenScope(This,startOffset,pRetVal) )
+
+#define ISymUnmanagedWriter_CloseScope(This,endOffset) \
+ ( (This)->lpVtbl -> CloseScope(This,endOffset) )
+
+#define ISymUnmanagedWriter_SetScopeRange(This,scopeID,startOffset,endOffset) \
+ ( (This)->lpVtbl -> SetScopeRange(This,scopeID,startOffset,endOffset) )
+
+#define ISymUnmanagedWriter_DefineLocalVariable(This,name,attributes,cSig,signature,addrKind,addr1,addr2,addr3,startOffset,endOffset) \
+ ( (This)->lpVtbl -> DefineLocalVariable(This,name,attributes,cSig,signature,addrKind,addr1,addr2,addr3,startOffset,endOffset) )
+
+#define ISymUnmanagedWriter_DefineParameter(This,name,attributes,sequence,addrKind,addr1,addr2,addr3) \
+ ( (This)->lpVtbl -> DefineParameter(This,name,attributes,sequence,addrKind,addr1,addr2,addr3) )
+
+#define ISymUnmanagedWriter_DefineField(This,parent,name,attributes,cSig,signature,addrKind,addr1,addr2,addr3) \
+ ( (This)->lpVtbl -> DefineField(This,parent,name,attributes,cSig,signature,addrKind,addr1,addr2,addr3) )
+
+#define ISymUnmanagedWriter_DefineGlobalVariable(This,name,attributes,cSig,signature,addrKind,addr1,addr2,addr3) \
+ ( (This)->lpVtbl -> DefineGlobalVariable(This,name,attributes,cSig,signature,addrKind,addr1,addr2,addr3) )
+
+#define ISymUnmanagedWriter_Close(This) \
+ ( (This)->lpVtbl -> Close(This) )
+
+#define ISymUnmanagedWriter_SetSymAttribute(This,parent,name,cData,data) \
+ ( (This)->lpVtbl -> SetSymAttribute(This,parent,name,cData,data) )
+
+#define ISymUnmanagedWriter_OpenNamespace(This,name) \
+ ( (This)->lpVtbl -> OpenNamespace(This,name) )
+
+#define ISymUnmanagedWriter_CloseNamespace(This) \
+ ( (This)->lpVtbl -> CloseNamespace(This) )
+
+#define ISymUnmanagedWriter_UsingNamespace(This,fullName) \
+ ( (This)->lpVtbl -> UsingNamespace(This,fullName) )
+
+#define ISymUnmanagedWriter_SetMethodSourceRange(This,startDoc,startLine,startColumn,endDoc,endLine,endColumn) \
+ ( (This)->lpVtbl -> SetMethodSourceRange(This,startDoc,startLine,startColumn,endDoc,endLine,endColumn) )
+
+#define ISymUnmanagedWriter_Initialize(This,emitter,filename,pIStream,fFullBuild) \
+ ( (This)->lpVtbl -> Initialize(This,emitter,filename,pIStream,fFullBuild) )
+
+#define ISymUnmanagedWriter_GetDebugInfo(This,pIDD,cData,pcData,data) \
+ ( (This)->lpVtbl -> GetDebugInfo(This,pIDD,cData,pcData,data) )
+
+#define ISymUnmanagedWriter_DefineSequencePoints(This,document,spCount,offsets,lines,columns,endLines,endColumns) \
+ ( (This)->lpVtbl -> DefineSequencePoints(This,document,spCount,offsets,lines,columns,endLines,endColumns) )
+
+#define ISymUnmanagedWriter_RemapToken(This,oldToken,newToken) \
+ ( (This)->lpVtbl -> RemapToken(This,oldToken,newToken) )
+
+#define ISymUnmanagedWriter_Initialize2(This,emitter,tempfilename,pIStream,fFullBuild,finalfilename) \
+ ( (This)->lpVtbl -> Initialize2(This,emitter,tempfilename,pIStream,fFullBuild,finalfilename) )
+
+#define ISymUnmanagedWriter_DefineConstant(This,name,value,cSig,signature) \
+ ( (This)->lpVtbl -> DefineConstant(This,name,value,cSig,signature) )
+
+#define ISymUnmanagedWriter_Abort(This) \
+ ( (This)->lpVtbl -> Abort(This) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ISymUnmanagedWriter_INTERFACE_DEFINED__ */
+
+
+#ifndef __ISymUnmanagedWriter2_INTERFACE_DEFINED__
+#define __ISymUnmanagedWriter2_INTERFACE_DEFINED__
+
+/* interface ISymUnmanagedWriter2 */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_ISymUnmanagedWriter2;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("0B97726E-9E6D-4f05-9A26-424022093CAA")
+ ISymUnmanagedWriter2 : public ISymUnmanagedWriter
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE DefineLocalVariable2(
+ /* [in] */ __RPC__in const WCHAR *name,
+ /* [in] */ ULONG32 attributes,
+ /* [in] */ mdSignature sigToken,
+ /* [in] */ ULONG32 addrKind,
+ /* [in] */ ULONG32 addr1,
+ /* [in] */ ULONG32 addr2,
+ /* [in] */ ULONG32 addr3,
+ /* [in] */ ULONG32 startOffset,
+ /* [in] */ ULONG32 endOffset) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE DefineGlobalVariable2(
+ /* [in] */ __RPC__in const WCHAR *name,
+ /* [in] */ ULONG32 attributes,
+ /* [in] */ mdSignature sigToken,
+ /* [in] */ ULONG32 addrKind,
+ /* [in] */ ULONG32 addr1,
+ /* [in] */ ULONG32 addr2,
+ /* [in] */ ULONG32 addr3) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE DefineConstant2(
+ /* [in] */ __RPC__in const WCHAR *name,
+ /* [in] */ VARIANT value,
+ /* [in] */ mdSignature sigToken) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ISymUnmanagedWriter2Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ __RPC__in ISymUnmanagedWriter2 * This,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ __RPC__in ISymUnmanagedWriter2 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ __RPC__in ISymUnmanagedWriter2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *DefineDocument )(
+ __RPC__in ISymUnmanagedWriter2 * This,
+ /* [in] */ __RPC__in const WCHAR *url,
+ /* [in] */ __RPC__in const GUID *language,
+ /* [in] */ __RPC__in const GUID *languageVendor,
+ /* [in] */ __RPC__in const GUID *documentType,
+ /* [retval][out] */ __RPC__deref_out_opt ISymUnmanagedDocumentWriter **pRetVal);
+
+ HRESULT ( STDMETHODCALLTYPE *SetUserEntryPoint )(
+ __RPC__in ISymUnmanagedWriter2 * This,
+ /* [in] */ mdMethodDef entryMethod);
+
+ HRESULT ( STDMETHODCALLTYPE *OpenMethod )(
+ __RPC__in ISymUnmanagedWriter2 * This,
+ /* [in] */ mdMethodDef method);
+
+ HRESULT ( STDMETHODCALLTYPE *CloseMethod )(
+ __RPC__in ISymUnmanagedWriter2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *OpenScope )(
+ __RPC__in ISymUnmanagedWriter2 * This,
+ /* [in] */ ULONG32 startOffset,
+ /* [retval][out] */ __RPC__out ULONG32 *pRetVal);
+
+ HRESULT ( STDMETHODCALLTYPE *CloseScope )(
+ __RPC__in ISymUnmanagedWriter2 * This,
+ /* [in] */ ULONG32 endOffset);
+
+ HRESULT ( STDMETHODCALLTYPE *SetScopeRange )(
+ __RPC__in ISymUnmanagedWriter2 * This,
+ /* [in] */ ULONG32 scopeID,
+ /* [in] */ ULONG32 startOffset,
+ /* [in] */ ULONG32 endOffset);
+
+ HRESULT ( STDMETHODCALLTYPE *DefineLocalVariable )(
+ __RPC__in ISymUnmanagedWriter2 * This,
+ /* [in] */ __RPC__in const WCHAR *name,
+ /* [in] */ ULONG32 attributes,
+ /* [in] */ ULONG32 cSig,
+ /* [size_is][in] */ __RPC__in_ecount_full(cSig) unsigned char signature[ ],
+ /* [in] */ ULONG32 addrKind,
+ /* [in] */ ULONG32 addr1,
+ /* [in] */ ULONG32 addr2,
+ /* [in] */ ULONG32 addr3,
+ /* [in] */ ULONG32 startOffset,
+ /* [in] */ ULONG32 endOffset);
+
+ HRESULT ( STDMETHODCALLTYPE *DefineParameter )(
+ __RPC__in ISymUnmanagedWriter2 * This,
+ /* [in] */ __RPC__in const WCHAR *name,
+ /* [in] */ ULONG32 attributes,
+ /* [in] */ ULONG32 sequence,
+ /* [in] */ ULONG32 addrKind,
+ /* [in] */ ULONG32 addr1,
+ /* [in] */ ULONG32 addr2,
+ /* [in] */ ULONG32 addr3);
+
+ HRESULT ( STDMETHODCALLTYPE *DefineField )(
+ __RPC__in ISymUnmanagedWriter2 * This,
+ /* [in] */ mdTypeDef parent,
+ /* [in] */ __RPC__in const WCHAR *name,
+ /* [in] */ ULONG32 attributes,
+ /* [in] */ ULONG32 cSig,
+ /* [size_is][in] */ __RPC__in_ecount_full(cSig) unsigned char signature[ ],
+ /* [in] */ ULONG32 addrKind,
+ /* [in] */ ULONG32 addr1,
+ /* [in] */ ULONG32 addr2,
+ /* [in] */ ULONG32 addr3);
+
+ HRESULT ( STDMETHODCALLTYPE *DefineGlobalVariable )(
+ __RPC__in ISymUnmanagedWriter2 * This,
+ /* [in] */ __RPC__in const WCHAR *name,
+ /* [in] */ ULONG32 attributes,
+ /* [in] */ ULONG32 cSig,
+ /* [size_is][in] */ __RPC__in_ecount_full(cSig) unsigned char signature[ ],
+ /* [in] */ ULONG32 addrKind,
+ /* [in] */ ULONG32 addr1,
+ /* [in] */ ULONG32 addr2,
+ /* [in] */ ULONG32 addr3);
+
+ HRESULT ( STDMETHODCALLTYPE *Close )(
+ __RPC__in ISymUnmanagedWriter2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *SetSymAttribute )(
+ __RPC__in ISymUnmanagedWriter2 * This,
+ /* [in] */ mdToken parent,
+ /* [in] */ __RPC__in const WCHAR *name,
+ /* [in] */ ULONG32 cData,
+ /* [size_is][in] */ __RPC__in_ecount_full(cData) unsigned char data[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *OpenNamespace )(
+ __RPC__in ISymUnmanagedWriter2 * This,
+ /* [in] */ __RPC__in const WCHAR *name);
+
+ HRESULT ( STDMETHODCALLTYPE *CloseNamespace )(
+ __RPC__in ISymUnmanagedWriter2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *UsingNamespace )(
+ __RPC__in ISymUnmanagedWriter2 * This,
+ /* [in] */ __RPC__in const WCHAR *fullName);
+
+ HRESULT ( STDMETHODCALLTYPE *SetMethodSourceRange )(
+ __RPC__in ISymUnmanagedWriter2 * This,
+ /* [in] */ __RPC__in_opt ISymUnmanagedDocumentWriter *startDoc,
+ /* [in] */ ULONG32 startLine,
+ /* [in] */ ULONG32 startColumn,
+ /* [in] */ __RPC__in_opt ISymUnmanagedDocumentWriter *endDoc,
+ /* [in] */ ULONG32 endLine,
+ /* [in] */ ULONG32 endColumn);
+
+ HRESULT ( STDMETHODCALLTYPE *Initialize )(
+ __RPC__in ISymUnmanagedWriter2 * This,
+ /* [in] */ __RPC__in_opt IUnknown *emitter,
+ /* [in] */ __RPC__in const WCHAR *filename,
+ /* [in] */ __RPC__in_opt IStream *pIStream,
+ /* [in] */ BOOL fFullBuild);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDebugInfo )(
+ __RPC__in ISymUnmanagedWriter2 * This,
+ /* [out][in] */ __RPC__inout IMAGE_DEBUG_DIRECTORY *pIDD,
+ /* [in] */ DWORD cData,
+ /* [out] */ __RPC__out DWORD *pcData,
+ /* [length_is][size_is][out] */ __RPC__out_ecount_part(cData, *pcData) BYTE data[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *DefineSequencePoints )(
+ __RPC__in ISymUnmanagedWriter2 * This,
+ /* [in] */ __RPC__in_opt ISymUnmanagedDocumentWriter *document,
+ /* [in] */ ULONG32 spCount,
+ /* [size_is][in] */ __RPC__in_ecount_full(spCount) ULONG32 offsets[ ],
+ /* [size_is][in] */ __RPC__in_ecount_full(spCount) ULONG32 lines[ ],
+ /* [size_is][in] */ __RPC__in_ecount_full(spCount) ULONG32 columns[ ],
+ /* [size_is][in] */ __RPC__in_ecount_full(spCount) ULONG32 endLines[ ],
+ /* [size_is][in] */ __RPC__in_ecount_full(spCount) ULONG32 endColumns[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *RemapToken )(
+ __RPC__in ISymUnmanagedWriter2 * This,
+ /* [in] */ mdToken oldToken,
+ /* [in] */ mdToken newToken);
+
+ HRESULT ( STDMETHODCALLTYPE *Initialize2 )(
+ __RPC__in ISymUnmanagedWriter2 * This,
+ /* [in] */ __RPC__in_opt IUnknown *emitter,
+ /* [in] */ __RPC__in const WCHAR *tempfilename,
+ /* [in] */ __RPC__in_opt IStream *pIStream,
+ /* [in] */ BOOL fFullBuild,
+ /* [in] */ __RPC__in const WCHAR *finalfilename);
+
+ HRESULT ( STDMETHODCALLTYPE *DefineConstant )(
+ __RPC__in ISymUnmanagedWriter2 * This,
+ /* [in] */ __RPC__in const WCHAR *name,
+ /* [in] */ VARIANT value,
+ /* [in] */ ULONG32 cSig,
+ /* [size_is][in] */ __RPC__in_ecount_full(cSig) unsigned char signature[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *Abort )(
+ __RPC__in ISymUnmanagedWriter2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *DefineLocalVariable2 )(
+ __RPC__in ISymUnmanagedWriter2 * This,
+ /* [in] */ __RPC__in const WCHAR *name,
+ /* [in] */ ULONG32 attributes,
+ /* [in] */ mdSignature sigToken,
+ /* [in] */ ULONG32 addrKind,
+ /* [in] */ ULONG32 addr1,
+ /* [in] */ ULONG32 addr2,
+ /* [in] */ ULONG32 addr3,
+ /* [in] */ ULONG32 startOffset,
+ /* [in] */ ULONG32 endOffset);
+
+ HRESULT ( STDMETHODCALLTYPE *DefineGlobalVariable2 )(
+ __RPC__in ISymUnmanagedWriter2 * This,
+ /* [in] */ __RPC__in const WCHAR *name,
+ /* [in] */ ULONG32 attributes,
+ /* [in] */ mdSignature sigToken,
+ /* [in] */ ULONG32 addrKind,
+ /* [in] */ ULONG32 addr1,
+ /* [in] */ ULONG32 addr2,
+ /* [in] */ ULONG32 addr3);
+
+ HRESULT ( STDMETHODCALLTYPE *DefineConstant2 )(
+ __RPC__in ISymUnmanagedWriter2 * This,
+ /* [in] */ __RPC__in const WCHAR *name,
+ /* [in] */ VARIANT value,
+ /* [in] */ mdSignature sigToken);
+
+ END_INTERFACE
+ } ISymUnmanagedWriter2Vtbl;
+
+ interface ISymUnmanagedWriter2
+ {
+ CONST_VTBL struct ISymUnmanagedWriter2Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ISymUnmanagedWriter2_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ISymUnmanagedWriter2_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ISymUnmanagedWriter2_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ISymUnmanagedWriter2_DefineDocument(This,url,language,languageVendor,documentType,pRetVal) \
+ ( (This)->lpVtbl -> DefineDocument(This,url,language,languageVendor,documentType,pRetVal) )
+
+#define ISymUnmanagedWriter2_SetUserEntryPoint(This,entryMethod) \
+ ( (This)->lpVtbl -> SetUserEntryPoint(This,entryMethod) )
+
+#define ISymUnmanagedWriter2_OpenMethod(This,method) \
+ ( (This)->lpVtbl -> OpenMethod(This,method) )
+
+#define ISymUnmanagedWriter2_CloseMethod(This) \
+ ( (This)->lpVtbl -> CloseMethod(This) )
+
+#define ISymUnmanagedWriter2_OpenScope(This,startOffset,pRetVal) \
+ ( (This)->lpVtbl -> OpenScope(This,startOffset,pRetVal) )
+
+#define ISymUnmanagedWriter2_CloseScope(This,endOffset) \
+ ( (This)->lpVtbl -> CloseScope(This,endOffset) )
+
+#define ISymUnmanagedWriter2_SetScopeRange(This,scopeID,startOffset,endOffset) \
+ ( (This)->lpVtbl -> SetScopeRange(This,scopeID,startOffset,endOffset) )
+
+#define ISymUnmanagedWriter2_DefineLocalVariable(This,name,attributes,cSig,signature,addrKind,addr1,addr2,addr3,startOffset,endOffset) \
+ ( (This)->lpVtbl -> DefineLocalVariable(This,name,attributes,cSig,signature,addrKind,addr1,addr2,addr3,startOffset,endOffset) )
+
+#define ISymUnmanagedWriter2_DefineParameter(This,name,attributes,sequence,addrKind,addr1,addr2,addr3) \
+ ( (This)->lpVtbl -> DefineParameter(This,name,attributes,sequence,addrKind,addr1,addr2,addr3) )
+
+#define ISymUnmanagedWriter2_DefineField(This,parent,name,attributes,cSig,signature,addrKind,addr1,addr2,addr3) \
+ ( (This)->lpVtbl -> DefineField(This,parent,name,attributes,cSig,signature,addrKind,addr1,addr2,addr3) )
+
+#define ISymUnmanagedWriter2_DefineGlobalVariable(This,name,attributes,cSig,signature,addrKind,addr1,addr2,addr3) \
+ ( (This)->lpVtbl -> DefineGlobalVariable(This,name,attributes,cSig,signature,addrKind,addr1,addr2,addr3) )
+
+#define ISymUnmanagedWriter2_Close(This) \
+ ( (This)->lpVtbl -> Close(This) )
+
+#define ISymUnmanagedWriter2_SetSymAttribute(This,parent,name,cData,data) \
+ ( (This)->lpVtbl -> SetSymAttribute(This,parent,name,cData,data) )
+
+#define ISymUnmanagedWriter2_OpenNamespace(This,name) \
+ ( (This)->lpVtbl -> OpenNamespace(This,name) )
+
+#define ISymUnmanagedWriter2_CloseNamespace(This) \
+ ( (This)->lpVtbl -> CloseNamespace(This) )
+
+#define ISymUnmanagedWriter2_UsingNamespace(This,fullName) \
+ ( (This)->lpVtbl -> UsingNamespace(This,fullName) )
+
+#define ISymUnmanagedWriter2_SetMethodSourceRange(This,startDoc,startLine,startColumn,endDoc,endLine,endColumn) \
+ ( (This)->lpVtbl -> SetMethodSourceRange(This,startDoc,startLine,startColumn,endDoc,endLine,endColumn) )
+
+#define ISymUnmanagedWriter2_Initialize(This,emitter,filename,pIStream,fFullBuild) \
+ ( (This)->lpVtbl -> Initialize(This,emitter,filename,pIStream,fFullBuild) )
+
+#define ISymUnmanagedWriter2_GetDebugInfo(This,pIDD,cData,pcData,data) \
+ ( (This)->lpVtbl -> GetDebugInfo(This,pIDD,cData,pcData,data) )
+
+#define ISymUnmanagedWriter2_DefineSequencePoints(This,document,spCount,offsets,lines,columns,endLines,endColumns) \
+ ( (This)->lpVtbl -> DefineSequencePoints(This,document,spCount,offsets,lines,columns,endLines,endColumns) )
+
+#define ISymUnmanagedWriter2_RemapToken(This,oldToken,newToken) \
+ ( (This)->lpVtbl -> RemapToken(This,oldToken,newToken) )
+
+#define ISymUnmanagedWriter2_Initialize2(This,emitter,tempfilename,pIStream,fFullBuild,finalfilename) \
+ ( (This)->lpVtbl -> Initialize2(This,emitter,tempfilename,pIStream,fFullBuild,finalfilename) )
+
+#define ISymUnmanagedWriter2_DefineConstant(This,name,value,cSig,signature) \
+ ( (This)->lpVtbl -> DefineConstant(This,name,value,cSig,signature) )
+
+#define ISymUnmanagedWriter2_Abort(This) \
+ ( (This)->lpVtbl -> Abort(This) )
+
+
+#define ISymUnmanagedWriter2_DefineLocalVariable2(This,name,attributes,sigToken,addrKind,addr1,addr2,addr3,startOffset,endOffset) \
+ ( (This)->lpVtbl -> DefineLocalVariable2(This,name,attributes,sigToken,addrKind,addr1,addr2,addr3,startOffset,endOffset) )
+
+#define ISymUnmanagedWriter2_DefineGlobalVariable2(This,name,attributes,sigToken,addrKind,addr1,addr2,addr3) \
+ ( (This)->lpVtbl -> DefineGlobalVariable2(This,name,attributes,sigToken,addrKind,addr1,addr2,addr3) )
+
+#define ISymUnmanagedWriter2_DefineConstant2(This,name,value,sigToken) \
+ ( (This)->lpVtbl -> DefineConstant2(This,name,value,sigToken) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ISymUnmanagedWriter2_INTERFACE_DEFINED__ */
+
+
+#ifndef __ISymUnmanagedWriter3_INTERFACE_DEFINED__
+#define __ISymUnmanagedWriter3_INTERFACE_DEFINED__
+
+/* interface ISymUnmanagedWriter3 */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_ISymUnmanagedWriter3;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("12F1E02C-1E05-4B0E-9468-EBC9D1BB040F")
+ ISymUnmanagedWriter3 : public ISymUnmanagedWriter2
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE OpenMethod2(
+ /* [in] */ mdMethodDef method,
+ /* [in] */ ULONG32 isect,
+ /* [in] */ ULONG32 offset) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Commit( void) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ISymUnmanagedWriter3Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ __RPC__in ISymUnmanagedWriter3 * This,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ __RPC__in ISymUnmanagedWriter3 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ __RPC__in ISymUnmanagedWriter3 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *DefineDocument )(
+ __RPC__in ISymUnmanagedWriter3 * This,
+ /* [in] */ __RPC__in const WCHAR *url,
+ /* [in] */ __RPC__in const GUID *language,
+ /* [in] */ __RPC__in const GUID *languageVendor,
+ /* [in] */ __RPC__in const GUID *documentType,
+ /* [retval][out] */ __RPC__deref_out_opt ISymUnmanagedDocumentWriter **pRetVal);
+
+ HRESULT ( STDMETHODCALLTYPE *SetUserEntryPoint )(
+ __RPC__in ISymUnmanagedWriter3 * This,
+ /* [in] */ mdMethodDef entryMethod);
+
+ HRESULT ( STDMETHODCALLTYPE *OpenMethod )(
+ __RPC__in ISymUnmanagedWriter3 * This,
+ /* [in] */ mdMethodDef method);
+
+ HRESULT ( STDMETHODCALLTYPE *CloseMethod )(
+ __RPC__in ISymUnmanagedWriter3 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *OpenScope )(
+ __RPC__in ISymUnmanagedWriter3 * This,
+ /* [in] */ ULONG32 startOffset,
+ /* [retval][out] */ __RPC__out ULONG32 *pRetVal);
+
+ HRESULT ( STDMETHODCALLTYPE *CloseScope )(
+ __RPC__in ISymUnmanagedWriter3 * This,
+ /* [in] */ ULONG32 endOffset);
+
+ HRESULT ( STDMETHODCALLTYPE *SetScopeRange )(
+ __RPC__in ISymUnmanagedWriter3 * This,
+ /* [in] */ ULONG32 scopeID,
+ /* [in] */ ULONG32 startOffset,
+ /* [in] */ ULONG32 endOffset);
+
+ HRESULT ( STDMETHODCALLTYPE *DefineLocalVariable )(
+ __RPC__in ISymUnmanagedWriter3 * This,
+ /* [in] */ __RPC__in const WCHAR *name,
+ /* [in] */ ULONG32 attributes,
+ /* [in] */ ULONG32 cSig,
+ /* [size_is][in] */ __RPC__in_ecount_full(cSig) unsigned char signature[ ],
+ /* [in] */ ULONG32 addrKind,
+ /* [in] */ ULONG32 addr1,
+ /* [in] */ ULONG32 addr2,
+ /* [in] */ ULONG32 addr3,
+ /* [in] */ ULONG32 startOffset,
+ /* [in] */ ULONG32 endOffset);
+
+ HRESULT ( STDMETHODCALLTYPE *DefineParameter )(
+ __RPC__in ISymUnmanagedWriter3 * This,
+ /* [in] */ __RPC__in const WCHAR *name,
+ /* [in] */ ULONG32 attributes,
+ /* [in] */ ULONG32 sequence,
+ /* [in] */ ULONG32 addrKind,
+ /* [in] */ ULONG32 addr1,
+ /* [in] */ ULONG32 addr2,
+ /* [in] */ ULONG32 addr3);
+
+ HRESULT ( STDMETHODCALLTYPE *DefineField )(
+ __RPC__in ISymUnmanagedWriter3 * This,
+ /* [in] */ mdTypeDef parent,
+ /* [in] */ __RPC__in const WCHAR *name,
+ /* [in] */ ULONG32 attributes,
+ /* [in] */ ULONG32 cSig,
+ /* [size_is][in] */ __RPC__in_ecount_full(cSig) unsigned char signature[ ],
+ /* [in] */ ULONG32 addrKind,
+ /* [in] */ ULONG32 addr1,
+ /* [in] */ ULONG32 addr2,
+ /* [in] */ ULONG32 addr3);
+
+ HRESULT ( STDMETHODCALLTYPE *DefineGlobalVariable )(
+ __RPC__in ISymUnmanagedWriter3 * This,
+ /* [in] */ __RPC__in const WCHAR *name,
+ /* [in] */ ULONG32 attributes,
+ /* [in] */ ULONG32 cSig,
+ /* [size_is][in] */ __RPC__in_ecount_full(cSig) unsigned char signature[ ],
+ /* [in] */ ULONG32 addrKind,
+ /* [in] */ ULONG32 addr1,
+ /* [in] */ ULONG32 addr2,
+ /* [in] */ ULONG32 addr3);
+
+ HRESULT ( STDMETHODCALLTYPE *Close )(
+ __RPC__in ISymUnmanagedWriter3 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *SetSymAttribute )(
+ __RPC__in ISymUnmanagedWriter3 * This,
+ /* [in] */ mdToken parent,
+ /* [in] */ __RPC__in const WCHAR *name,
+ /* [in] */ ULONG32 cData,
+ /* [size_is][in] */ __RPC__in_ecount_full(cData) unsigned char data[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *OpenNamespace )(
+ __RPC__in ISymUnmanagedWriter3 * This,
+ /* [in] */ __RPC__in const WCHAR *name);
+
+ HRESULT ( STDMETHODCALLTYPE *CloseNamespace )(
+ __RPC__in ISymUnmanagedWriter3 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *UsingNamespace )(
+ __RPC__in ISymUnmanagedWriter3 * This,
+ /* [in] */ __RPC__in const WCHAR *fullName);
+
+ HRESULT ( STDMETHODCALLTYPE *SetMethodSourceRange )(
+ __RPC__in ISymUnmanagedWriter3 * This,
+ /* [in] */ __RPC__in_opt ISymUnmanagedDocumentWriter *startDoc,
+ /* [in] */ ULONG32 startLine,
+ /* [in] */ ULONG32 startColumn,
+ /* [in] */ __RPC__in_opt ISymUnmanagedDocumentWriter *endDoc,
+ /* [in] */ ULONG32 endLine,
+ /* [in] */ ULONG32 endColumn);
+
+ HRESULT ( STDMETHODCALLTYPE *Initialize )(
+ __RPC__in ISymUnmanagedWriter3 * This,
+ /* [in] */ __RPC__in_opt IUnknown *emitter,
+ /* [in] */ __RPC__in const WCHAR *filename,
+ /* [in] */ __RPC__in_opt IStream *pIStream,
+ /* [in] */ BOOL fFullBuild);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDebugInfo )(
+ __RPC__in ISymUnmanagedWriter3 * This,
+ /* [out][in] */ __RPC__inout IMAGE_DEBUG_DIRECTORY *pIDD,
+ /* [in] */ DWORD cData,
+ /* [out] */ __RPC__out DWORD *pcData,
+ /* [length_is][size_is][out] */ __RPC__out_ecount_part(cData, *pcData) BYTE data[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *DefineSequencePoints )(
+ __RPC__in ISymUnmanagedWriter3 * This,
+ /* [in] */ __RPC__in_opt ISymUnmanagedDocumentWriter *document,
+ /* [in] */ ULONG32 spCount,
+ /* [size_is][in] */ __RPC__in_ecount_full(spCount) ULONG32 offsets[ ],
+ /* [size_is][in] */ __RPC__in_ecount_full(spCount) ULONG32 lines[ ],
+ /* [size_is][in] */ __RPC__in_ecount_full(spCount) ULONG32 columns[ ],
+ /* [size_is][in] */ __RPC__in_ecount_full(spCount) ULONG32 endLines[ ],
+ /* [size_is][in] */ __RPC__in_ecount_full(spCount) ULONG32 endColumns[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *RemapToken )(
+ __RPC__in ISymUnmanagedWriter3 * This,
+ /* [in] */ mdToken oldToken,
+ /* [in] */ mdToken newToken);
+
+ HRESULT ( STDMETHODCALLTYPE *Initialize2 )(
+ __RPC__in ISymUnmanagedWriter3 * This,
+ /* [in] */ __RPC__in_opt IUnknown *emitter,
+ /* [in] */ __RPC__in const WCHAR *tempfilename,
+ /* [in] */ __RPC__in_opt IStream *pIStream,
+ /* [in] */ BOOL fFullBuild,
+ /* [in] */ __RPC__in const WCHAR *finalfilename);
+
+ HRESULT ( STDMETHODCALLTYPE *DefineConstant )(
+ __RPC__in ISymUnmanagedWriter3 * This,
+ /* [in] */ __RPC__in const WCHAR *name,
+ /* [in] */ VARIANT value,
+ /* [in] */ ULONG32 cSig,
+ /* [size_is][in] */ __RPC__in_ecount_full(cSig) unsigned char signature[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *Abort )(
+ __RPC__in ISymUnmanagedWriter3 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *DefineLocalVariable2 )(
+ __RPC__in ISymUnmanagedWriter3 * This,
+ /* [in] */ __RPC__in const WCHAR *name,
+ /* [in] */ ULONG32 attributes,
+ /* [in] */ mdSignature sigToken,
+ /* [in] */ ULONG32 addrKind,
+ /* [in] */ ULONG32 addr1,
+ /* [in] */ ULONG32 addr2,
+ /* [in] */ ULONG32 addr3,
+ /* [in] */ ULONG32 startOffset,
+ /* [in] */ ULONG32 endOffset);
+
+ HRESULT ( STDMETHODCALLTYPE *DefineGlobalVariable2 )(
+ __RPC__in ISymUnmanagedWriter3 * This,
+ /* [in] */ __RPC__in const WCHAR *name,
+ /* [in] */ ULONG32 attributes,
+ /* [in] */ mdSignature sigToken,
+ /* [in] */ ULONG32 addrKind,
+ /* [in] */ ULONG32 addr1,
+ /* [in] */ ULONG32 addr2,
+ /* [in] */ ULONG32 addr3);
+
+ HRESULT ( STDMETHODCALLTYPE *DefineConstant2 )(
+ __RPC__in ISymUnmanagedWriter3 * This,
+ /* [in] */ __RPC__in const WCHAR *name,
+ /* [in] */ VARIANT value,
+ /* [in] */ mdSignature sigToken);
+
+ HRESULT ( STDMETHODCALLTYPE *OpenMethod2 )(
+ __RPC__in ISymUnmanagedWriter3 * This,
+ /* [in] */ mdMethodDef method,
+ /* [in] */ ULONG32 isect,
+ /* [in] */ ULONG32 offset);
+
+ HRESULT ( STDMETHODCALLTYPE *Commit )(
+ __RPC__in ISymUnmanagedWriter3 * This);
+
+ END_INTERFACE
+ } ISymUnmanagedWriter3Vtbl;
+
+ interface ISymUnmanagedWriter3
+ {
+ CONST_VTBL struct ISymUnmanagedWriter3Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ISymUnmanagedWriter3_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ISymUnmanagedWriter3_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ISymUnmanagedWriter3_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ISymUnmanagedWriter3_DefineDocument(This,url,language,languageVendor,documentType,pRetVal) \
+ ( (This)->lpVtbl -> DefineDocument(This,url,language,languageVendor,documentType,pRetVal) )
+
+#define ISymUnmanagedWriter3_SetUserEntryPoint(This,entryMethod) \
+ ( (This)->lpVtbl -> SetUserEntryPoint(This,entryMethod) )
+
+#define ISymUnmanagedWriter3_OpenMethod(This,method) \
+ ( (This)->lpVtbl -> OpenMethod(This,method) )
+
+#define ISymUnmanagedWriter3_CloseMethod(This) \
+ ( (This)->lpVtbl -> CloseMethod(This) )
+
+#define ISymUnmanagedWriter3_OpenScope(This,startOffset,pRetVal) \
+ ( (This)->lpVtbl -> OpenScope(This,startOffset,pRetVal) )
+
+#define ISymUnmanagedWriter3_CloseScope(This,endOffset) \
+ ( (This)->lpVtbl -> CloseScope(This,endOffset) )
+
+#define ISymUnmanagedWriter3_SetScopeRange(This,scopeID,startOffset,endOffset) \
+ ( (This)->lpVtbl -> SetScopeRange(This,scopeID,startOffset,endOffset) )
+
+#define ISymUnmanagedWriter3_DefineLocalVariable(This,name,attributes,cSig,signature,addrKind,addr1,addr2,addr3,startOffset,endOffset) \
+ ( (This)->lpVtbl -> DefineLocalVariable(This,name,attributes,cSig,signature,addrKind,addr1,addr2,addr3,startOffset,endOffset) )
+
+#define ISymUnmanagedWriter3_DefineParameter(This,name,attributes,sequence,addrKind,addr1,addr2,addr3) \
+ ( (This)->lpVtbl -> DefineParameter(This,name,attributes,sequence,addrKind,addr1,addr2,addr3) )
+
+#define ISymUnmanagedWriter3_DefineField(This,parent,name,attributes,cSig,signature,addrKind,addr1,addr2,addr3) \
+ ( (This)->lpVtbl -> DefineField(This,parent,name,attributes,cSig,signature,addrKind,addr1,addr2,addr3) )
+
+#define ISymUnmanagedWriter3_DefineGlobalVariable(This,name,attributes,cSig,signature,addrKind,addr1,addr2,addr3) \
+ ( (This)->lpVtbl -> DefineGlobalVariable(This,name,attributes,cSig,signature,addrKind,addr1,addr2,addr3) )
+
+#define ISymUnmanagedWriter3_Close(This) \
+ ( (This)->lpVtbl -> Close(This) )
+
+#define ISymUnmanagedWriter3_SetSymAttribute(This,parent,name,cData,data) \
+ ( (This)->lpVtbl -> SetSymAttribute(This,parent,name,cData,data) )
+
+#define ISymUnmanagedWriter3_OpenNamespace(This,name) \
+ ( (This)->lpVtbl -> OpenNamespace(This,name) )
+
+#define ISymUnmanagedWriter3_CloseNamespace(This) \
+ ( (This)->lpVtbl -> CloseNamespace(This) )
+
+#define ISymUnmanagedWriter3_UsingNamespace(This,fullName) \
+ ( (This)->lpVtbl -> UsingNamespace(This,fullName) )
+
+#define ISymUnmanagedWriter3_SetMethodSourceRange(This,startDoc,startLine,startColumn,endDoc,endLine,endColumn) \
+ ( (This)->lpVtbl -> SetMethodSourceRange(This,startDoc,startLine,startColumn,endDoc,endLine,endColumn) )
+
+#define ISymUnmanagedWriter3_Initialize(This,emitter,filename,pIStream,fFullBuild) \
+ ( (This)->lpVtbl -> Initialize(This,emitter,filename,pIStream,fFullBuild) )
+
+#define ISymUnmanagedWriter3_GetDebugInfo(This,pIDD,cData,pcData,data) \
+ ( (This)->lpVtbl -> GetDebugInfo(This,pIDD,cData,pcData,data) )
+
+#define ISymUnmanagedWriter3_DefineSequencePoints(This,document,spCount,offsets,lines,columns,endLines,endColumns) \
+ ( (This)->lpVtbl -> DefineSequencePoints(This,document,spCount,offsets,lines,columns,endLines,endColumns) )
+
+#define ISymUnmanagedWriter3_RemapToken(This,oldToken,newToken) \
+ ( (This)->lpVtbl -> RemapToken(This,oldToken,newToken) )
+
+#define ISymUnmanagedWriter3_Initialize2(This,emitter,tempfilename,pIStream,fFullBuild,finalfilename) \
+ ( (This)->lpVtbl -> Initialize2(This,emitter,tempfilename,pIStream,fFullBuild,finalfilename) )
+
+#define ISymUnmanagedWriter3_DefineConstant(This,name,value,cSig,signature) \
+ ( (This)->lpVtbl -> DefineConstant(This,name,value,cSig,signature) )
+
+#define ISymUnmanagedWriter3_Abort(This) \
+ ( (This)->lpVtbl -> Abort(This) )
+
+
+#define ISymUnmanagedWriter3_DefineLocalVariable2(This,name,attributes,sigToken,addrKind,addr1,addr2,addr3,startOffset,endOffset) \
+ ( (This)->lpVtbl -> DefineLocalVariable2(This,name,attributes,sigToken,addrKind,addr1,addr2,addr3,startOffset,endOffset) )
+
+#define ISymUnmanagedWriter3_DefineGlobalVariable2(This,name,attributes,sigToken,addrKind,addr1,addr2,addr3) \
+ ( (This)->lpVtbl -> DefineGlobalVariable2(This,name,attributes,sigToken,addrKind,addr1,addr2,addr3) )
+
+#define ISymUnmanagedWriter3_DefineConstant2(This,name,value,sigToken) \
+ ( (This)->lpVtbl -> DefineConstant2(This,name,value,sigToken) )
+
+
+#define ISymUnmanagedWriter3_OpenMethod2(This,method,isect,offset) \
+ ( (This)->lpVtbl -> OpenMethod2(This,method,isect,offset) )
+
+#define ISymUnmanagedWriter3_Commit(This) \
+ ( (This)->lpVtbl -> Commit(This) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ISymUnmanagedWriter3_INTERFACE_DEFINED__ */
+
+
+#ifndef __ISymUnmanagedWriter4_INTERFACE_DEFINED__
+#define __ISymUnmanagedWriter4_INTERFACE_DEFINED__
+
+/* interface ISymUnmanagedWriter4 */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_ISymUnmanagedWriter4;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("BC7E3F53-F458-4C23-9DBD-A189E6E96594")
+ ISymUnmanagedWriter4 : public ISymUnmanagedWriter3
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetDebugInfoWithPadding(
+ /* [out][in] */ __RPC__inout IMAGE_DEBUG_DIRECTORY *pIDD,
+ /* [in] */ DWORD cData,
+ /* [out] */ __RPC__out DWORD *pcData,
+ /* [length_is][size_is][out] */ __RPC__out_ecount_part(cData, *pcData) BYTE data[ ]) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ISymUnmanagedWriter4Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ __RPC__in ISymUnmanagedWriter4 * This,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ __RPC__in ISymUnmanagedWriter4 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ __RPC__in ISymUnmanagedWriter4 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *DefineDocument )(
+ __RPC__in ISymUnmanagedWriter4 * This,
+ /* [in] */ __RPC__in const WCHAR *url,
+ /* [in] */ __RPC__in const GUID *language,
+ /* [in] */ __RPC__in const GUID *languageVendor,
+ /* [in] */ __RPC__in const GUID *documentType,
+ /* [retval][out] */ __RPC__deref_out_opt ISymUnmanagedDocumentWriter **pRetVal);
+
+ HRESULT ( STDMETHODCALLTYPE *SetUserEntryPoint )(
+ __RPC__in ISymUnmanagedWriter4 * This,
+ /* [in] */ mdMethodDef entryMethod);
+
+ HRESULT ( STDMETHODCALLTYPE *OpenMethod )(
+ __RPC__in ISymUnmanagedWriter4 * This,
+ /* [in] */ mdMethodDef method);
+
+ HRESULT ( STDMETHODCALLTYPE *CloseMethod )(
+ __RPC__in ISymUnmanagedWriter4 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *OpenScope )(
+ __RPC__in ISymUnmanagedWriter4 * This,
+ /* [in] */ ULONG32 startOffset,
+ /* [retval][out] */ __RPC__out ULONG32 *pRetVal);
+
+ HRESULT ( STDMETHODCALLTYPE *CloseScope )(
+ __RPC__in ISymUnmanagedWriter4 * This,
+ /* [in] */ ULONG32 endOffset);
+
+ HRESULT ( STDMETHODCALLTYPE *SetScopeRange )(
+ __RPC__in ISymUnmanagedWriter4 * This,
+ /* [in] */ ULONG32 scopeID,
+ /* [in] */ ULONG32 startOffset,
+ /* [in] */ ULONG32 endOffset);
+
+ HRESULT ( STDMETHODCALLTYPE *DefineLocalVariable )(
+ __RPC__in ISymUnmanagedWriter4 * This,
+ /* [in] */ __RPC__in const WCHAR *name,
+ /* [in] */ ULONG32 attributes,
+ /* [in] */ ULONG32 cSig,
+ /* [size_is][in] */ __RPC__in_ecount_full(cSig) unsigned char signature[ ],
+ /* [in] */ ULONG32 addrKind,
+ /* [in] */ ULONG32 addr1,
+ /* [in] */ ULONG32 addr2,
+ /* [in] */ ULONG32 addr3,
+ /* [in] */ ULONG32 startOffset,
+ /* [in] */ ULONG32 endOffset);
+
+ HRESULT ( STDMETHODCALLTYPE *DefineParameter )(
+ __RPC__in ISymUnmanagedWriter4 * This,
+ /* [in] */ __RPC__in const WCHAR *name,
+ /* [in] */ ULONG32 attributes,
+ /* [in] */ ULONG32 sequence,
+ /* [in] */ ULONG32 addrKind,
+ /* [in] */ ULONG32 addr1,
+ /* [in] */ ULONG32 addr2,
+ /* [in] */ ULONG32 addr3);
+
+ HRESULT ( STDMETHODCALLTYPE *DefineField )(
+ __RPC__in ISymUnmanagedWriter4 * This,
+ /* [in] */ mdTypeDef parent,
+ /* [in] */ __RPC__in const WCHAR *name,
+ /* [in] */ ULONG32 attributes,
+ /* [in] */ ULONG32 cSig,
+ /* [size_is][in] */ __RPC__in_ecount_full(cSig) unsigned char signature[ ],
+ /* [in] */ ULONG32 addrKind,
+ /* [in] */ ULONG32 addr1,
+ /* [in] */ ULONG32 addr2,
+ /* [in] */ ULONG32 addr3);
+
+ HRESULT ( STDMETHODCALLTYPE *DefineGlobalVariable )(
+ __RPC__in ISymUnmanagedWriter4 * This,
+ /* [in] */ __RPC__in const WCHAR *name,
+ /* [in] */ ULONG32 attributes,
+ /* [in] */ ULONG32 cSig,
+ /* [size_is][in] */ __RPC__in_ecount_full(cSig) unsigned char signature[ ],
+ /* [in] */ ULONG32 addrKind,
+ /* [in] */ ULONG32 addr1,
+ /* [in] */ ULONG32 addr2,
+ /* [in] */ ULONG32 addr3);
+
+ HRESULT ( STDMETHODCALLTYPE *Close )(
+ __RPC__in ISymUnmanagedWriter4 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *SetSymAttribute )(
+ __RPC__in ISymUnmanagedWriter4 * This,
+ /* [in] */ mdToken parent,
+ /* [in] */ __RPC__in const WCHAR *name,
+ /* [in] */ ULONG32 cData,
+ /* [size_is][in] */ __RPC__in_ecount_full(cData) unsigned char data[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *OpenNamespace )(
+ __RPC__in ISymUnmanagedWriter4 * This,
+ /* [in] */ __RPC__in const WCHAR *name);
+
+ HRESULT ( STDMETHODCALLTYPE *CloseNamespace )(
+ __RPC__in ISymUnmanagedWriter4 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *UsingNamespace )(
+ __RPC__in ISymUnmanagedWriter4 * This,
+ /* [in] */ __RPC__in const WCHAR *fullName);
+
+ HRESULT ( STDMETHODCALLTYPE *SetMethodSourceRange )(
+ __RPC__in ISymUnmanagedWriter4 * This,
+ /* [in] */ __RPC__in_opt ISymUnmanagedDocumentWriter *startDoc,
+ /* [in] */ ULONG32 startLine,
+ /* [in] */ ULONG32 startColumn,
+ /* [in] */ __RPC__in_opt ISymUnmanagedDocumentWriter *endDoc,
+ /* [in] */ ULONG32 endLine,
+ /* [in] */ ULONG32 endColumn);
+
+ HRESULT ( STDMETHODCALLTYPE *Initialize )(
+ __RPC__in ISymUnmanagedWriter4 * This,
+ /* [in] */ __RPC__in_opt IUnknown *emitter,
+ /* [in] */ __RPC__in const WCHAR *filename,
+ /* [in] */ __RPC__in_opt IStream *pIStream,
+ /* [in] */ BOOL fFullBuild);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDebugInfo )(
+ __RPC__in ISymUnmanagedWriter4 * This,
+ /* [out][in] */ __RPC__inout IMAGE_DEBUG_DIRECTORY *pIDD,
+ /* [in] */ DWORD cData,
+ /* [out] */ __RPC__out DWORD *pcData,
+ /* [length_is][size_is][out] */ __RPC__out_ecount_part(cData, *pcData) BYTE data[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *DefineSequencePoints )(
+ __RPC__in ISymUnmanagedWriter4 * This,
+ /* [in] */ __RPC__in_opt ISymUnmanagedDocumentWriter *document,
+ /* [in] */ ULONG32 spCount,
+ /* [size_is][in] */ __RPC__in_ecount_full(spCount) ULONG32 offsets[ ],
+ /* [size_is][in] */ __RPC__in_ecount_full(spCount) ULONG32 lines[ ],
+ /* [size_is][in] */ __RPC__in_ecount_full(spCount) ULONG32 columns[ ],
+ /* [size_is][in] */ __RPC__in_ecount_full(spCount) ULONG32 endLines[ ],
+ /* [size_is][in] */ __RPC__in_ecount_full(spCount) ULONG32 endColumns[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *RemapToken )(
+ __RPC__in ISymUnmanagedWriter4 * This,
+ /* [in] */ mdToken oldToken,
+ /* [in] */ mdToken newToken);
+
+ HRESULT ( STDMETHODCALLTYPE *Initialize2 )(
+ __RPC__in ISymUnmanagedWriter4 * This,
+ /* [in] */ __RPC__in_opt IUnknown *emitter,
+ /* [in] */ __RPC__in const WCHAR *tempfilename,
+ /* [in] */ __RPC__in_opt IStream *pIStream,
+ /* [in] */ BOOL fFullBuild,
+ /* [in] */ __RPC__in const WCHAR *finalfilename);
+
+ HRESULT ( STDMETHODCALLTYPE *DefineConstant )(
+ __RPC__in ISymUnmanagedWriter4 * This,
+ /* [in] */ __RPC__in const WCHAR *name,
+ /* [in] */ VARIANT value,
+ /* [in] */ ULONG32 cSig,
+ /* [size_is][in] */ __RPC__in_ecount_full(cSig) unsigned char signature[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *Abort )(
+ __RPC__in ISymUnmanagedWriter4 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *DefineLocalVariable2 )(
+ __RPC__in ISymUnmanagedWriter4 * This,
+ /* [in] */ __RPC__in const WCHAR *name,
+ /* [in] */ ULONG32 attributes,
+ /* [in] */ mdSignature sigToken,
+ /* [in] */ ULONG32 addrKind,
+ /* [in] */ ULONG32 addr1,
+ /* [in] */ ULONG32 addr2,
+ /* [in] */ ULONG32 addr3,
+ /* [in] */ ULONG32 startOffset,
+ /* [in] */ ULONG32 endOffset);
+
+ HRESULT ( STDMETHODCALLTYPE *DefineGlobalVariable2 )(
+ __RPC__in ISymUnmanagedWriter4 * This,
+ /* [in] */ __RPC__in const WCHAR *name,
+ /* [in] */ ULONG32 attributes,
+ /* [in] */ mdSignature sigToken,
+ /* [in] */ ULONG32 addrKind,
+ /* [in] */ ULONG32 addr1,
+ /* [in] */ ULONG32 addr2,
+ /* [in] */ ULONG32 addr3);
+
+ HRESULT ( STDMETHODCALLTYPE *DefineConstant2 )(
+ __RPC__in ISymUnmanagedWriter4 * This,
+ /* [in] */ __RPC__in const WCHAR *name,
+ /* [in] */ VARIANT value,
+ /* [in] */ mdSignature sigToken);
+
+ HRESULT ( STDMETHODCALLTYPE *OpenMethod2 )(
+ __RPC__in ISymUnmanagedWriter4 * This,
+ /* [in] */ mdMethodDef method,
+ /* [in] */ ULONG32 isect,
+ /* [in] */ ULONG32 offset);
+
+ HRESULT ( STDMETHODCALLTYPE *Commit )(
+ __RPC__in ISymUnmanagedWriter4 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDebugInfoWithPadding )(
+ __RPC__in ISymUnmanagedWriter4 * This,
+ /* [out][in] */ __RPC__inout IMAGE_DEBUG_DIRECTORY *pIDD,
+ /* [in] */ DWORD cData,
+ /* [out] */ __RPC__out DWORD *pcData,
+ /* [length_is][size_is][out] */ __RPC__out_ecount_part(cData, *pcData) BYTE data[ ]);
+
+ END_INTERFACE
+ } ISymUnmanagedWriter4Vtbl;
+
+ interface ISymUnmanagedWriter4
+ {
+ CONST_VTBL struct ISymUnmanagedWriter4Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ISymUnmanagedWriter4_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ISymUnmanagedWriter4_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ISymUnmanagedWriter4_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ISymUnmanagedWriter4_DefineDocument(This,url,language,languageVendor,documentType,pRetVal) \
+ ( (This)->lpVtbl -> DefineDocument(This,url,language,languageVendor,documentType,pRetVal) )
+
+#define ISymUnmanagedWriter4_SetUserEntryPoint(This,entryMethod) \
+ ( (This)->lpVtbl -> SetUserEntryPoint(This,entryMethod) )
+
+#define ISymUnmanagedWriter4_OpenMethod(This,method) \
+ ( (This)->lpVtbl -> OpenMethod(This,method) )
+
+#define ISymUnmanagedWriter4_CloseMethod(This) \
+ ( (This)->lpVtbl -> CloseMethod(This) )
+
+#define ISymUnmanagedWriter4_OpenScope(This,startOffset,pRetVal) \
+ ( (This)->lpVtbl -> OpenScope(This,startOffset,pRetVal) )
+
+#define ISymUnmanagedWriter4_CloseScope(This,endOffset) \
+ ( (This)->lpVtbl -> CloseScope(This,endOffset) )
+
+#define ISymUnmanagedWriter4_SetScopeRange(This,scopeID,startOffset,endOffset) \
+ ( (This)->lpVtbl -> SetScopeRange(This,scopeID,startOffset,endOffset) )
+
+#define ISymUnmanagedWriter4_DefineLocalVariable(This,name,attributes,cSig,signature,addrKind,addr1,addr2,addr3,startOffset,endOffset) \
+ ( (This)->lpVtbl -> DefineLocalVariable(This,name,attributes,cSig,signature,addrKind,addr1,addr2,addr3,startOffset,endOffset) )
+
+#define ISymUnmanagedWriter4_DefineParameter(This,name,attributes,sequence,addrKind,addr1,addr2,addr3) \
+ ( (This)->lpVtbl -> DefineParameter(This,name,attributes,sequence,addrKind,addr1,addr2,addr3) )
+
+#define ISymUnmanagedWriter4_DefineField(This,parent,name,attributes,cSig,signature,addrKind,addr1,addr2,addr3) \
+ ( (This)->lpVtbl -> DefineField(This,parent,name,attributes,cSig,signature,addrKind,addr1,addr2,addr3) )
+
+#define ISymUnmanagedWriter4_DefineGlobalVariable(This,name,attributes,cSig,signature,addrKind,addr1,addr2,addr3) \
+ ( (This)->lpVtbl -> DefineGlobalVariable(This,name,attributes,cSig,signature,addrKind,addr1,addr2,addr3) )
+
+#define ISymUnmanagedWriter4_Close(This) \
+ ( (This)->lpVtbl -> Close(This) )
+
+#define ISymUnmanagedWriter4_SetSymAttribute(This,parent,name,cData,data) \
+ ( (This)->lpVtbl -> SetSymAttribute(This,parent,name,cData,data) )
+
+#define ISymUnmanagedWriter4_OpenNamespace(This,name) \
+ ( (This)->lpVtbl -> OpenNamespace(This,name) )
+
+#define ISymUnmanagedWriter4_CloseNamespace(This) \
+ ( (This)->lpVtbl -> CloseNamespace(This) )
+
+#define ISymUnmanagedWriter4_UsingNamespace(This,fullName) \
+ ( (This)->lpVtbl -> UsingNamespace(This,fullName) )
+
+#define ISymUnmanagedWriter4_SetMethodSourceRange(This,startDoc,startLine,startColumn,endDoc,endLine,endColumn) \
+ ( (This)->lpVtbl -> SetMethodSourceRange(This,startDoc,startLine,startColumn,endDoc,endLine,endColumn) )
+
+#define ISymUnmanagedWriter4_Initialize(This,emitter,filename,pIStream,fFullBuild) \
+ ( (This)->lpVtbl -> Initialize(This,emitter,filename,pIStream,fFullBuild) )
+
+#define ISymUnmanagedWriter4_GetDebugInfo(This,pIDD,cData,pcData,data) \
+ ( (This)->lpVtbl -> GetDebugInfo(This,pIDD,cData,pcData,data) )
+
+#define ISymUnmanagedWriter4_DefineSequencePoints(This,document,spCount,offsets,lines,columns,endLines,endColumns) \
+ ( (This)->lpVtbl -> DefineSequencePoints(This,document,spCount,offsets,lines,columns,endLines,endColumns) )
+
+#define ISymUnmanagedWriter4_RemapToken(This,oldToken,newToken) \
+ ( (This)->lpVtbl -> RemapToken(This,oldToken,newToken) )
+
+#define ISymUnmanagedWriter4_Initialize2(This,emitter,tempfilename,pIStream,fFullBuild,finalfilename) \
+ ( (This)->lpVtbl -> Initialize2(This,emitter,tempfilename,pIStream,fFullBuild,finalfilename) )
+
+#define ISymUnmanagedWriter4_DefineConstant(This,name,value,cSig,signature) \
+ ( (This)->lpVtbl -> DefineConstant(This,name,value,cSig,signature) )
+
+#define ISymUnmanagedWriter4_Abort(This) \
+ ( (This)->lpVtbl -> Abort(This) )
+
+
+#define ISymUnmanagedWriter4_DefineLocalVariable2(This,name,attributes,sigToken,addrKind,addr1,addr2,addr3,startOffset,endOffset) \
+ ( (This)->lpVtbl -> DefineLocalVariable2(This,name,attributes,sigToken,addrKind,addr1,addr2,addr3,startOffset,endOffset) )
+
+#define ISymUnmanagedWriter4_DefineGlobalVariable2(This,name,attributes,sigToken,addrKind,addr1,addr2,addr3) \
+ ( (This)->lpVtbl -> DefineGlobalVariable2(This,name,attributes,sigToken,addrKind,addr1,addr2,addr3) )
+
+#define ISymUnmanagedWriter4_DefineConstant2(This,name,value,sigToken) \
+ ( (This)->lpVtbl -> DefineConstant2(This,name,value,sigToken) )
+
+
+#define ISymUnmanagedWriter4_OpenMethod2(This,method,isect,offset) \
+ ( (This)->lpVtbl -> OpenMethod2(This,method,isect,offset) )
+
+#define ISymUnmanagedWriter4_Commit(This) \
+ ( (This)->lpVtbl -> Commit(This) )
+
+
+#define ISymUnmanagedWriter4_GetDebugInfoWithPadding(This,pIDD,cData,pcData,data) \
+ ( (This)->lpVtbl -> GetDebugInfoWithPadding(This,pIDD,cData,pcData,data) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ISymUnmanagedWriter4_INTERFACE_DEFINED__ */
+
+
+#ifndef __ISymUnmanagedWriter5_INTERFACE_DEFINED__
+#define __ISymUnmanagedWriter5_INTERFACE_DEFINED__
+
+/* interface ISymUnmanagedWriter5 */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_ISymUnmanagedWriter5;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("DCF7780D-BDE9-45DF-ACFE-21731A32000C")
+ ISymUnmanagedWriter5 : public ISymUnmanagedWriter4
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE OpenMapTokensToSourceSpans( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE CloseMapTokensToSourceSpans( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE MapTokenToSourceSpan(
+ /* [in] */ mdToken token,
+ /* [in] */ __RPC__in_opt ISymUnmanagedDocumentWriter *document,
+ /* [in] */ ULONG32 line,
+ /* [in] */ ULONG32 column,
+ /* [in] */ ULONG32 endLine,
+ /* [in] */ ULONG32 endColumn) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ISymUnmanagedWriter5Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ __RPC__in ISymUnmanagedWriter5 * This,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ __RPC__in ISymUnmanagedWriter5 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ __RPC__in ISymUnmanagedWriter5 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *DefineDocument )(
+ __RPC__in ISymUnmanagedWriter5 * This,
+ /* [in] */ __RPC__in const WCHAR *url,
+ /* [in] */ __RPC__in const GUID *language,
+ /* [in] */ __RPC__in const GUID *languageVendor,
+ /* [in] */ __RPC__in const GUID *documentType,
+ /* [retval][out] */ __RPC__deref_out_opt ISymUnmanagedDocumentWriter **pRetVal);
+
+ HRESULT ( STDMETHODCALLTYPE *SetUserEntryPoint )(
+ __RPC__in ISymUnmanagedWriter5 * This,
+ /* [in] */ mdMethodDef entryMethod);
+
+ HRESULT ( STDMETHODCALLTYPE *OpenMethod )(
+ __RPC__in ISymUnmanagedWriter5 * This,
+ /* [in] */ mdMethodDef method);
+
+ HRESULT ( STDMETHODCALLTYPE *CloseMethod )(
+ __RPC__in ISymUnmanagedWriter5 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *OpenScope )(
+ __RPC__in ISymUnmanagedWriter5 * This,
+ /* [in] */ ULONG32 startOffset,
+ /* [retval][out] */ __RPC__out ULONG32 *pRetVal);
+
+ HRESULT ( STDMETHODCALLTYPE *CloseScope )(
+ __RPC__in ISymUnmanagedWriter5 * This,
+ /* [in] */ ULONG32 endOffset);
+
+ HRESULT ( STDMETHODCALLTYPE *SetScopeRange )(
+ __RPC__in ISymUnmanagedWriter5 * This,
+ /* [in] */ ULONG32 scopeID,
+ /* [in] */ ULONG32 startOffset,
+ /* [in] */ ULONG32 endOffset);
+
+ HRESULT ( STDMETHODCALLTYPE *DefineLocalVariable )(
+ __RPC__in ISymUnmanagedWriter5 * This,
+ /* [in] */ __RPC__in const WCHAR *name,
+ /* [in] */ ULONG32 attributes,
+ /* [in] */ ULONG32 cSig,
+ /* [size_is][in] */ __RPC__in_ecount_full(cSig) unsigned char signature[ ],
+ /* [in] */ ULONG32 addrKind,
+ /* [in] */ ULONG32 addr1,
+ /* [in] */ ULONG32 addr2,
+ /* [in] */ ULONG32 addr3,
+ /* [in] */ ULONG32 startOffset,
+ /* [in] */ ULONG32 endOffset);
+
+ HRESULT ( STDMETHODCALLTYPE *DefineParameter )(
+ __RPC__in ISymUnmanagedWriter5 * This,
+ /* [in] */ __RPC__in const WCHAR *name,
+ /* [in] */ ULONG32 attributes,
+ /* [in] */ ULONG32 sequence,
+ /* [in] */ ULONG32 addrKind,
+ /* [in] */ ULONG32 addr1,
+ /* [in] */ ULONG32 addr2,
+ /* [in] */ ULONG32 addr3);
+
+ HRESULT ( STDMETHODCALLTYPE *DefineField )(
+ __RPC__in ISymUnmanagedWriter5 * This,
+ /* [in] */ mdTypeDef parent,
+ /* [in] */ __RPC__in const WCHAR *name,
+ /* [in] */ ULONG32 attributes,
+ /* [in] */ ULONG32 cSig,
+ /* [size_is][in] */ __RPC__in_ecount_full(cSig) unsigned char signature[ ],
+ /* [in] */ ULONG32 addrKind,
+ /* [in] */ ULONG32 addr1,
+ /* [in] */ ULONG32 addr2,
+ /* [in] */ ULONG32 addr3);
+
+ HRESULT ( STDMETHODCALLTYPE *DefineGlobalVariable )(
+ __RPC__in ISymUnmanagedWriter5 * This,
+ /* [in] */ __RPC__in const WCHAR *name,
+ /* [in] */ ULONG32 attributes,
+ /* [in] */ ULONG32 cSig,
+ /* [size_is][in] */ __RPC__in_ecount_full(cSig) unsigned char signature[ ],
+ /* [in] */ ULONG32 addrKind,
+ /* [in] */ ULONG32 addr1,
+ /* [in] */ ULONG32 addr2,
+ /* [in] */ ULONG32 addr3);
+
+ HRESULT ( STDMETHODCALLTYPE *Close )(
+ __RPC__in ISymUnmanagedWriter5 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *SetSymAttribute )(
+ __RPC__in ISymUnmanagedWriter5 * This,
+ /* [in] */ mdToken parent,
+ /* [in] */ __RPC__in const WCHAR *name,
+ /* [in] */ ULONG32 cData,
+ /* [size_is][in] */ __RPC__in_ecount_full(cData) unsigned char data[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *OpenNamespace )(
+ __RPC__in ISymUnmanagedWriter5 * This,
+ /* [in] */ __RPC__in const WCHAR *name);
+
+ HRESULT ( STDMETHODCALLTYPE *CloseNamespace )(
+ __RPC__in ISymUnmanagedWriter5 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *UsingNamespace )(
+ __RPC__in ISymUnmanagedWriter5 * This,
+ /* [in] */ __RPC__in const WCHAR *fullName);
+
+ HRESULT ( STDMETHODCALLTYPE *SetMethodSourceRange )(
+ __RPC__in ISymUnmanagedWriter5 * This,
+ /* [in] */ __RPC__in_opt ISymUnmanagedDocumentWriter *startDoc,
+ /* [in] */ ULONG32 startLine,
+ /* [in] */ ULONG32 startColumn,
+ /* [in] */ __RPC__in_opt ISymUnmanagedDocumentWriter *endDoc,
+ /* [in] */ ULONG32 endLine,
+ /* [in] */ ULONG32 endColumn);
+
+ HRESULT ( STDMETHODCALLTYPE *Initialize )(
+ __RPC__in ISymUnmanagedWriter5 * This,
+ /* [in] */ __RPC__in_opt IUnknown *emitter,
+ /* [in] */ __RPC__in const WCHAR *filename,
+ /* [in] */ __RPC__in_opt IStream *pIStream,
+ /* [in] */ BOOL fFullBuild);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDebugInfo )(
+ __RPC__in ISymUnmanagedWriter5 * This,
+ /* [out][in] */ __RPC__inout IMAGE_DEBUG_DIRECTORY *pIDD,
+ /* [in] */ DWORD cData,
+ /* [out] */ __RPC__out DWORD *pcData,
+ /* [length_is][size_is][out] */ __RPC__out_ecount_part(cData, *pcData) BYTE data[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *DefineSequencePoints )(
+ __RPC__in ISymUnmanagedWriter5 * This,
+ /* [in] */ __RPC__in_opt ISymUnmanagedDocumentWriter *document,
+ /* [in] */ ULONG32 spCount,
+ /* [size_is][in] */ __RPC__in_ecount_full(spCount) ULONG32 offsets[ ],
+ /* [size_is][in] */ __RPC__in_ecount_full(spCount) ULONG32 lines[ ],
+ /* [size_is][in] */ __RPC__in_ecount_full(spCount) ULONG32 columns[ ],
+ /* [size_is][in] */ __RPC__in_ecount_full(spCount) ULONG32 endLines[ ],
+ /* [size_is][in] */ __RPC__in_ecount_full(spCount) ULONG32 endColumns[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *RemapToken )(
+ __RPC__in ISymUnmanagedWriter5 * This,
+ /* [in] */ mdToken oldToken,
+ /* [in] */ mdToken newToken);
+
+ HRESULT ( STDMETHODCALLTYPE *Initialize2 )(
+ __RPC__in ISymUnmanagedWriter5 * This,
+ /* [in] */ __RPC__in_opt IUnknown *emitter,
+ /* [in] */ __RPC__in const WCHAR *tempfilename,
+ /* [in] */ __RPC__in_opt IStream *pIStream,
+ /* [in] */ BOOL fFullBuild,
+ /* [in] */ __RPC__in const WCHAR *finalfilename);
+
+ HRESULT ( STDMETHODCALLTYPE *DefineConstant )(
+ __RPC__in ISymUnmanagedWriter5 * This,
+ /* [in] */ __RPC__in const WCHAR *name,
+ /* [in] */ VARIANT value,
+ /* [in] */ ULONG32 cSig,
+ /* [size_is][in] */ __RPC__in_ecount_full(cSig) unsigned char signature[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *Abort )(
+ __RPC__in ISymUnmanagedWriter5 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *DefineLocalVariable2 )(
+ __RPC__in ISymUnmanagedWriter5 * This,
+ /* [in] */ __RPC__in const WCHAR *name,
+ /* [in] */ ULONG32 attributes,
+ /* [in] */ mdSignature sigToken,
+ /* [in] */ ULONG32 addrKind,
+ /* [in] */ ULONG32 addr1,
+ /* [in] */ ULONG32 addr2,
+ /* [in] */ ULONG32 addr3,
+ /* [in] */ ULONG32 startOffset,
+ /* [in] */ ULONG32 endOffset);
+
+ HRESULT ( STDMETHODCALLTYPE *DefineGlobalVariable2 )(
+ __RPC__in ISymUnmanagedWriter5 * This,
+ /* [in] */ __RPC__in const WCHAR *name,
+ /* [in] */ ULONG32 attributes,
+ /* [in] */ mdSignature sigToken,
+ /* [in] */ ULONG32 addrKind,
+ /* [in] */ ULONG32 addr1,
+ /* [in] */ ULONG32 addr2,
+ /* [in] */ ULONG32 addr3);
+
+ HRESULT ( STDMETHODCALLTYPE *DefineConstant2 )(
+ __RPC__in ISymUnmanagedWriter5 * This,
+ /* [in] */ __RPC__in const WCHAR *name,
+ /* [in] */ VARIANT value,
+ /* [in] */ mdSignature sigToken);
+
+ HRESULT ( STDMETHODCALLTYPE *OpenMethod2 )(
+ __RPC__in ISymUnmanagedWriter5 * This,
+ /* [in] */ mdMethodDef method,
+ /* [in] */ ULONG32 isect,
+ /* [in] */ ULONG32 offset);
+
+ HRESULT ( STDMETHODCALLTYPE *Commit )(
+ __RPC__in ISymUnmanagedWriter5 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDebugInfoWithPadding )(
+ __RPC__in ISymUnmanagedWriter5 * This,
+ /* [out][in] */ __RPC__inout IMAGE_DEBUG_DIRECTORY *pIDD,
+ /* [in] */ DWORD cData,
+ /* [out] */ __RPC__out DWORD *pcData,
+ /* [length_is][size_is][out] */ __RPC__out_ecount_part(cData, *pcData) BYTE data[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *OpenMapTokensToSourceSpans )(
+ __RPC__in ISymUnmanagedWriter5 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *CloseMapTokensToSourceSpans )(
+ __RPC__in ISymUnmanagedWriter5 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *MapTokenToSourceSpan )(
+ __RPC__in ISymUnmanagedWriter5 * This,
+ /* [in] */ mdToken token,
+ /* [in] */ __RPC__in_opt ISymUnmanagedDocumentWriter *document,
+ /* [in] */ ULONG32 line,
+ /* [in] */ ULONG32 column,
+ /* [in] */ ULONG32 endLine,
+ /* [in] */ ULONG32 endColumn);
+
+ END_INTERFACE
+ } ISymUnmanagedWriter5Vtbl;
+
+ interface ISymUnmanagedWriter5
+ {
+ CONST_VTBL struct ISymUnmanagedWriter5Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ISymUnmanagedWriter5_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ISymUnmanagedWriter5_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ISymUnmanagedWriter5_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ISymUnmanagedWriter5_DefineDocument(This,url,language,languageVendor,documentType,pRetVal) \
+ ( (This)->lpVtbl -> DefineDocument(This,url,language,languageVendor,documentType,pRetVal) )
+
+#define ISymUnmanagedWriter5_SetUserEntryPoint(This,entryMethod) \
+ ( (This)->lpVtbl -> SetUserEntryPoint(This,entryMethod) )
+
+#define ISymUnmanagedWriter5_OpenMethod(This,method) \
+ ( (This)->lpVtbl -> OpenMethod(This,method) )
+
+#define ISymUnmanagedWriter5_CloseMethod(This) \
+ ( (This)->lpVtbl -> CloseMethod(This) )
+
+#define ISymUnmanagedWriter5_OpenScope(This,startOffset,pRetVal) \
+ ( (This)->lpVtbl -> OpenScope(This,startOffset,pRetVal) )
+
+#define ISymUnmanagedWriter5_CloseScope(This,endOffset) \
+ ( (This)->lpVtbl -> CloseScope(This,endOffset) )
+
+#define ISymUnmanagedWriter5_SetScopeRange(This,scopeID,startOffset,endOffset) \
+ ( (This)->lpVtbl -> SetScopeRange(This,scopeID,startOffset,endOffset) )
+
+#define ISymUnmanagedWriter5_DefineLocalVariable(This,name,attributes,cSig,signature,addrKind,addr1,addr2,addr3,startOffset,endOffset) \
+ ( (This)->lpVtbl -> DefineLocalVariable(This,name,attributes,cSig,signature,addrKind,addr1,addr2,addr3,startOffset,endOffset) )
+
+#define ISymUnmanagedWriter5_DefineParameter(This,name,attributes,sequence,addrKind,addr1,addr2,addr3) \
+ ( (This)->lpVtbl -> DefineParameter(This,name,attributes,sequence,addrKind,addr1,addr2,addr3) )
+
+#define ISymUnmanagedWriter5_DefineField(This,parent,name,attributes,cSig,signature,addrKind,addr1,addr2,addr3) \
+ ( (This)->lpVtbl -> DefineField(This,parent,name,attributes,cSig,signature,addrKind,addr1,addr2,addr3) )
+
+#define ISymUnmanagedWriter5_DefineGlobalVariable(This,name,attributes,cSig,signature,addrKind,addr1,addr2,addr3) \
+ ( (This)->lpVtbl -> DefineGlobalVariable(This,name,attributes,cSig,signature,addrKind,addr1,addr2,addr3) )
+
+#define ISymUnmanagedWriter5_Close(This) \
+ ( (This)->lpVtbl -> Close(This) )
+
+#define ISymUnmanagedWriter5_SetSymAttribute(This,parent,name,cData,data) \
+ ( (This)->lpVtbl -> SetSymAttribute(This,parent,name,cData,data) )
+
+#define ISymUnmanagedWriter5_OpenNamespace(This,name) \
+ ( (This)->lpVtbl -> OpenNamespace(This,name) )
+
+#define ISymUnmanagedWriter5_CloseNamespace(This) \
+ ( (This)->lpVtbl -> CloseNamespace(This) )
+
+#define ISymUnmanagedWriter5_UsingNamespace(This,fullName) \
+ ( (This)->lpVtbl -> UsingNamespace(This,fullName) )
+
+#define ISymUnmanagedWriter5_SetMethodSourceRange(This,startDoc,startLine,startColumn,endDoc,endLine,endColumn) \
+ ( (This)->lpVtbl -> SetMethodSourceRange(This,startDoc,startLine,startColumn,endDoc,endLine,endColumn) )
+
+#define ISymUnmanagedWriter5_Initialize(This,emitter,filename,pIStream,fFullBuild) \
+ ( (This)->lpVtbl -> Initialize(This,emitter,filename,pIStream,fFullBuild) )
+
+#define ISymUnmanagedWriter5_GetDebugInfo(This,pIDD,cData,pcData,data) \
+ ( (This)->lpVtbl -> GetDebugInfo(This,pIDD,cData,pcData,data) )
+
+#define ISymUnmanagedWriter5_DefineSequencePoints(This,document,spCount,offsets,lines,columns,endLines,endColumns) \
+ ( (This)->lpVtbl -> DefineSequencePoints(This,document,spCount,offsets,lines,columns,endLines,endColumns) )
+
+#define ISymUnmanagedWriter5_RemapToken(This,oldToken,newToken) \
+ ( (This)->lpVtbl -> RemapToken(This,oldToken,newToken) )
+
+#define ISymUnmanagedWriter5_Initialize2(This,emitter,tempfilename,pIStream,fFullBuild,finalfilename) \
+ ( (This)->lpVtbl -> Initialize2(This,emitter,tempfilename,pIStream,fFullBuild,finalfilename) )
+
+#define ISymUnmanagedWriter5_DefineConstant(This,name,value,cSig,signature) \
+ ( (This)->lpVtbl -> DefineConstant(This,name,value,cSig,signature) )
+
+#define ISymUnmanagedWriter5_Abort(This) \
+ ( (This)->lpVtbl -> Abort(This) )
+
+
+#define ISymUnmanagedWriter5_DefineLocalVariable2(This,name,attributes,sigToken,addrKind,addr1,addr2,addr3,startOffset,endOffset) \
+ ( (This)->lpVtbl -> DefineLocalVariable2(This,name,attributes,sigToken,addrKind,addr1,addr2,addr3,startOffset,endOffset) )
+
+#define ISymUnmanagedWriter5_DefineGlobalVariable2(This,name,attributes,sigToken,addrKind,addr1,addr2,addr3) \
+ ( (This)->lpVtbl -> DefineGlobalVariable2(This,name,attributes,sigToken,addrKind,addr1,addr2,addr3) )
+
+#define ISymUnmanagedWriter5_DefineConstant2(This,name,value,sigToken) \
+ ( (This)->lpVtbl -> DefineConstant2(This,name,value,sigToken) )
+
+
+#define ISymUnmanagedWriter5_OpenMethod2(This,method,isect,offset) \
+ ( (This)->lpVtbl -> OpenMethod2(This,method,isect,offset) )
+
+#define ISymUnmanagedWriter5_Commit(This) \
+ ( (This)->lpVtbl -> Commit(This) )
+
+
+#define ISymUnmanagedWriter5_GetDebugInfoWithPadding(This,pIDD,cData,pcData,data) \
+ ( (This)->lpVtbl -> GetDebugInfoWithPadding(This,pIDD,cData,pcData,data) )
+
+
+#define ISymUnmanagedWriter5_OpenMapTokensToSourceSpans(This) \
+ ( (This)->lpVtbl -> OpenMapTokensToSourceSpans(This) )
+
+#define ISymUnmanagedWriter5_CloseMapTokensToSourceSpans(This) \
+ ( (This)->lpVtbl -> CloseMapTokensToSourceSpans(This) )
+
+#define ISymUnmanagedWriter5_MapTokenToSourceSpan(This,token,document,line,column,endLine,endColumn) \
+ ( (This)->lpVtbl -> MapTokenToSourceSpan(This,token,document,line,column,endLine,endColumn) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ISymUnmanagedWriter5_INTERFACE_DEFINED__ */
+
+
+#ifndef __ISymUnmanagedReader2_INTERFACE_DEFINED__
+#define __ISymUnmanagedReader2_INTERFACE_DEFINED__
+
+/* interface ISymUnmanagedReader2 */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_ISymUnmanagedReader2;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("A09E53B2-2A57-4cca-8F63-B84F7C35D4AA")
+ ISymUnmanagedReader2 : public ISymUnmanagedReader
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetMethodByVersionPreRemap(
+ /* [in] */ mdMethodDef token,
+ /* [in] */ int version,
+ /* [retval][out] */ __RPC__deref_out_opt ISymUnmanagedMethod **pRetVal) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetSymAttributePreRemap(
+ /* [in] */ mdToken parent,
+ /* [in] */ __RPC__in WCHAR *name,
+ /* [in] */ ULONG32 cBuffer,
+ /* [out] */ __RPC__out ULONG32 *pcBuffer,
+ /* [length_is][size_is][out] */ __RPC__out_ecount_part(cBuffer, *pcBuffer) BYTE buffer[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetMethodsInDocument(
+ /* [in] */ __RPC__in_opt ISymUnmanagedDocument *document,
+ /* [in] */ ULONG32 cMethod,
+ /* [out] */ __RPC__out ULONG32 *pcMethod,
+ /* [length_is][size_is][out] */ __RPC__out_ecount_part(cMethod, *pcMethod) ISymUnmanagedMethod *pRetVal[ ]) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ISymUnmanagedReader2Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ __RPC__in ISymUnmanagedReader2 * This,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ __RPC__in ISymUnmanagedReader2 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ __RPC__in ISymUnmanagedReader2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDocument )(
+ __RPC__in ISymUnmanagedReader2 * This,
+ /* [in] */ __RPC__in WCHAR *url,
+ /* [in] */ GUID language,
+ /* [in] */ GUID languageVendor,
+ /* [in] */ GUID documentType,
+ /* [retval][out] */ __RPC__deref_out_opt ISymUnmanagedDocument **pRetVal);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDocuments )(
+ __RPC__in ISymUnmanagedReader2 * This,
+ /* [in] */ ULONG32 cDocs,
+ /* [out] */ __RPC__out ULONG32 *pcDocs,
+ /* [length_is][size_is][out] */ __RPC__out_ecount_part(cDocs, *pcDocs) ISymUnmanagedDocument *pDocs[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetUserEntryPoint )(
+ __RPC__in ISymUnmanagedReader2 * This,
+ /* [retval][out] */ __RPC__out mdMethodDef *pToken);
+
+ HRESULT ( STDMETHODCALLTYPE *GetMethod )(
+ __RPC__in ISymUnmanagedReader2 * This,
+ /* [in] */ mdMethodDef token,
+ /* [retval][out] */ __RPC__deref_out_opt ISymUnmanagedMethod **pRetVal);
+
+ HRESULT ( STDMETHODCALLTYPE *GetMethodByVersion )(
+ __RPC__in ISymUnmanagedReader2 * This,
+ /* [in] */ mdMethodDef token,
+ /* [in] */ int version,
+ /* [retval][out] */ __RPC__deref_out_opt ISymUnmanagedMethod **pRetVal);
+
+ HRESULT ( STDMETHODCALLTYPE *GetVariables )(
+ __RPC__in ISymUnmanagedReader2 * This,
+ /* [in] */ mdToken parent,
+ /* [in] */ ULONG32 cVars,
+ /* [out] */ __RPC__out ULONG32 *pcVars,
+ /* [length_is][size_is][out] */ __RPC__out_ecount_part(cVars, *pcVars) ISymUnmanagedVariable *pVars[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetGlobalVariables )(
+ __RPC__in ISymUnmanagedReader2 * This,
+ /* [in] */ ULONG32 cVars,
+ /* [out] */ __RPC__out ULONG32 *pcVars,
+ /* [length_is][size_is][out] */ __RPC__out_ecount_part(cVars, *pcVars) ISymUnmanagedVariable *pVars[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetMethodFromDocumentPosition )(
+ __RPC__in ISymUnmanagedReader2 * This,
+ /* [in] */ __RPC__in_opt ISymUnmanagedDocument *document,
+ /* [in] */ ULONG32 line,
+ /* [in] */ ULONG32 column,
+ /* [retval][out] */ __RPC__deref_out_opt ISymUnmanagedMethod **pRetVal);
+
+ HRESULT ( STDMETHODCALLTYPE *GetSymAttribute )(
+ __RPC__in ISymUnmanagedReader2 * This,
+ /* [in] */ mdToken parent,
+ /* [in] */ __RPC__in WCHAR *name,
+ /* [in] */ ULONG32 cBuffer,
+ /* [out] */ __RPC__out ULONG32 *pcBuffer,
+ /* [length_is][size_is][out] */ __RPC__out_ecount_part(cBuffer, *pcBuffer) BYTE buffer[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetNamespaces )(
+ __RPC__in ISymUnmanagedReader2 * This,
+ /* [in] */ ULONG32 cNameSpaces,
+ /* [out] */ __RPC__out ULONG32 *pcNameSpaces,
+ /* [length_is][size_is][out] */ __RPC__out_ecount_part(cNameSpaces, *pcNameSpaces) ISymUnmanagedNamespace *namespaces[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *Initialize )(
+ __RPC__in ISymUnmanagedReader2 * This,
+ /* [in] */ __RPC__in_opt IUnknown *importer,
+ /* [in] */ __RPC__in const WCHAR *filename,
+ /* [in] */ __RPC__in const WCHAR *searchPath,
+ /* [in] */ __RPC__in_opt IStream *pIStream);
+
+ HRESULT ( STDMETHODCALLTYPE *UpdateSymbolStore )(
+ __RPC__in ISymUnmanagedReader2 * This,
+ /* [in] */ __RPC__in const WCHAR *filename,
+ /* [in] */ __RPC__in_opt IStream *pIStream);
+
+ HRESULT ( STDMETHODCALLTYPE *ReplaceSymbolStore )(
+ __RPC__in ISymUnmanagedReader2 * This,
+ /* [in] */ __RPC__in const WCHAR *filename,
+ /* [in] */ __RPC__in_opt IStream *pIStream);
+
+ HRESULT ( STDMETHODCALLTYPE *GetSymbolStoreFileName )(
+ __RPC__in ISymUnmanagedReader2 * This,
+ /* [in] */ ULONG32 cchName,
+ /* [out] */ __RPC__out ULONG32 *pcchName,
+ /* [length_is][size_is][out] */ __RPC__out_ecount_part(cchName, *pcchName) WCHAR szName[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetMethodsFromDocumentPosition )(
+ __RPC__in ISymUnmanagedReader2 * This,
+ /* [in] */ __RPC__in_opt ISymUnmanagedDocument *document,
+ /* [in] */ ULONG32 line,
+ /* [in] */ ULONG32 column,
+ /* [in] */ ULONG32 cMethod,
+ /* [out] */ __RPC__out ULONG32 *pcMethod,
+ /* [length_is][size_is][out] */ __RPC__out_ecount_part(cMethod, *pcMethod) ISymUnmanagedMethod *pRetVal[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDocumentVersion )(
+ __RPC__in ISymUnmanagedReader2 * This,
+ /* [in] */ __RPC__in_opt ISymUnmanagedDocument *pDoc,
+ /* [out] */ __RPC__out int *version,
+ /* [out] */ __RPC__out BOOL *pbCurrent);
+
+ HRESULT ( STDMETHODCALLTYPE *GetMethodVersion )(
+ __RPC__in ISymUnmanagedReader2 * This,
+ /* [in] */ __RPC__in_opt ISymUnmanagedMethod *pMethod,
+ /* [out] */ __RPC__out int *version);
+
+ HRESULT ( STDMETHODCALLTYPE *GetMethodByVersionPreRemap )(
+ __RPC__in ISymUnmanagedReader2 * This,
+ /* [in] */ mdMethodDef token,
+ /* [in] */ int version,
+ /* [retval][out] */ __RPC__deref_out_opt ISymUnmanagedMethod **pRetVal);
+
+ HRESULT ( STDMETHODCALLTYPE *GetSymAttributePreRemap )(
+ __RPC__in ISymUnmanagedReader2 * This,
+ /* [in] */ mdToken parent,
+ /* [in] */ __RPC__in WCHAR *name,
+ /* [in] */ ULONG32 cBuffer,
+ /* [out] */ __RPC__out ULONG32 *pcBuffer,
+ /* [length_is][size_is][out] */ __RPC__out_ecount_part(cBuffer, *pcBuffer) BYTE buffer[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetMethodsInDocument )(
+ __RPC__in ISymUnmanagedReader2 * This,
+ /* [in] */ __RPC__in_opt ISymUnmanagedDocument *document,
+ /* [in] */ ULONG32 cMethod,
+ /* [out] */ __RPC__out ULONG32 *pcMethod,
+ /* [length_is][size_is][out] */ __RPC__out_ecount_part(cMethod, *pcMethod) ISymUnmanagedMethod *pRetVal[ ]);
+
+ END_INTERFACE
+ } ISymUnmanagedReader2Vtbl;
+
+ interface ISymUnmanagedReader2
+ {
+ CONST_VTBL struct ISymUnmanagedReader2Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ISymUnmanagedReader2_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ISymUnmanagedReader2_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ISymUnmanagedReader2_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ISymUnmanagedReader2_GetDocument(This,url,language,languageVendor,documentType,pRetVal) \
+ ( (This)->lpVtbl -> GetDocument(This,url,language,languageVendor,documentType,pRetVal) )
+
+#define ISymUnmanagedReader2_GetDocuments(This,cDocs,pcDocs,pDocs) \
+ ( (This)->lpVtbl -> GetDocuments(This,cDocs,pcDocs,pDocs) )
+
+#define ISymUnmanagedReader2_GetUserEntryPoint(This,pToken) \
+ ( (This)->lpVtbl -> GetUserEntryPoint(This,pToken) )
+
+#define ISymUnmanagedReader2_GetMethod(This,token,pRetVal) \
+ ( (This)->lpVtbl -> GetMethod(This,token,pRetVal) )
+
+#define ISymUnmanagedReader2_GetMethodByVersion(This,token,version,pRetVal) \
+ ( (This)->lpVtbl -> GetMethodByVersion(This,token,version,pRetVal) )
+
+#define ISymUnmanagedReader2_GetVariables(This,parent,cVars,pcVars,pVars) \
+ ( (This)->lpVtbl -> GetVariables(This,parent,cVars,pcVars,pVars) )
+
+#define ISymUnmanagedReader2_GetGlobalVariables(This,cVars,pcVars,pVars) \
+ ( (This)->lpVtbl -> GetGlobalVariables(This,cVars,pcVars,pVars) )
+
+#define ISymUnmanagedReader2_GetMethodFromDocumentPosition(This,document,line,column,pRetVal) \
+ ( (This)->lpVtbl -> GetMethodFromDocumentPosition(This,document,line,column,pRetVal) )
+
+#define ISymUnmanagedReader2_GetSymAttribute(This,parent,name,cBuffer,pcBuffer,buffer) \
+ ( (This)->lpVtbl -> GetSymAttribute(This,parent,name,cBuffer,pcBuffer,buffer) )
+
+#define ISymUnmanagedReader2_GetNamespaces(This,cNameSpaces,pcNameSpaces,namespaces) \
+ ( (This)->lpVtbl -> GetNamespaces(This,cNameSpaces,pcNameSpaces,namespaces) )
+
+#define ISymUnmanagedReader2_Initialize(This,importer,filename,searchPath,pIStream) \
+ ( (This)->lpVtbl -> Initialize(This,importer,filename,searchPath,pIStream) )
+
+#define ISymUnmanagedReader2_UpdateSymbolStore(This,filename,pIStream) \
+ ( (This)->lpVtbl -> UpdateSymbolStore(This,filename,pIStream) )
+
+#define ISymUnmanagedReader2_ReplaceSymbolStore(This,filename,pIStream) \
+ ( (This)->lpVtbl -> ReplaceSymbolStore(This,filename,pIStream) )
+
+#define ISymUnmanagedReader2_GetSymbolStoreFileName(This,cchName,pcchName,szName) \
+ ( (This)->lpVtbl -> GetSymbolStoreFileName(This,cchName,pcchName,szName) )
+
+#define ISymUnmanagedReader2_GetMethodsFromDocumentPosition(This,document,line,column,cMethod,pcMethod,pRetVal) \
+ ( (This)->lpVtbl -> GetMethodsFromDocumentPosition(This,document,line,column,cMethod,pcMethod,pRetVal) )
+
+#define ISymUnmanagedReader2_GetDocumentVersion(This,pDoc,version,pbCurrent) \
+ ( (This)->lpVtbl -> GetDocumentVersion(This,pDoc,version,pbCurrent) )
+
+#define ISymUnmanagedReader2_GetMethodVersion(This,pMethod,version) \
+ ( (This)->lpVtbl -> GetMethodVersion(This,pMethod,version) )
+
+
+#define ISymUnmanagedReader2_GetMethodByVersionPreRemap(This,token,version,pRetVal) \
+ ( (This)->lpVtbl -> GetMethodByVersionPreRemap(This,token,version,pRetVal) )
+
+#define ISymUnmanagedReader2_GetSymAttributePreRemap(This,parent,name,cBuffer,pcBuffer,buffer) \
+ ( (This)->lpVtbl -> GetSymAttributePreRemap(This,parent,name,cBuffer,pcBuffer,buffer) )
+
+#define ISymUnmanagedReader2_GetMethodsInDocument(This,document,cMethod,pcMethod,pRetVal) \
+ ( (This)->lpVtbl -> GetMethodsInDocument(This,document,cMethod,pcMethod,pRetVal) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ISymUnmanagedReader2_INTERFACE_DEFINED__ */
+
+
+#ifndef __ISymNGenWriter_INTERFACE_DEFINED__
+#define __ISymNGenWriter_INTERFACE_DEFINED__
+
+/* interface ISymNGenWriter */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_ISymNGenWriter;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("d682fd12-43de-411c-811b-be8404cea126")
+ ISymNGenWriter : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE AddSymbol(
+ /* [in] */ __RPC__in BSTR pSymbol,
+ /* [in] */ USHORT iSection,
+ /* [in] */ ULONGLONG rva) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE AddSection(
+ /* [in] */ USHORT iSection,
+ /* [in] */ USHORT flags,
+ /* [in] */ long offset,
+ /* [in] */ long cb) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ISymNGenWriterVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ __RPC__in ISymNGenWriter * This,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ __RPC__in ISymNGenWriter * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ __RPC__in ISymNGenWriter * This);
+
+ HRESULT ( STDMETHODCALLTYPE *AddSymbol )(
+ __RPC__in ISymNGenWriter * This,
+ /* [in] */ __RPC__in BSTR pSymbol,
+ /* [in] */ USHORT iSection,
+ /* [in] */ ULONGLONG rva);
+
+ HRESULT ( STDMETHODCALLTYPE *AddSection )(
+ __RPC__in ISymNGenWriter * This,
+ /* [in] */ USHORT iSection,
+ /* [in] */ USHORT flags,
+ /* [in] */ long offset,
+ /* [in] */ long cb);
+
+ END_INTERFACE
+ } ISymNGenWriterVtbl;
+
+ interface ISymNGenWriter
+ {
+ CONST_VTBL struct ISymNGenWriterVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ISymNGenWriter_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ISymNGenWriter_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ISymNGenWriter_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ISymNGenWriter_AddSymbol(This,pSymbol,iSection,rva) \
+ ( (This)->lpVtbl -> AddSymbol(This,pSymbol,iSection,rva) )
+
+#define ISymNGenWriter_AddSection(This,iSection,flags,offset,cb) \
+ ( (This)->lpVtbl -> AddSection(This,iSection,flags,offset,cb) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ISymNGenWriter_INTERFACE_DEFINED__ */
+
+
+#ifndef __ISymNGenWriter2_INTERFACE_DEFINED__
+#define __ISymNGenWriter2_INTERFACE_DEFINED__
+
+/* interface ISymNGenWriter2 */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ISymNGenWriter2;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("B029E51B-4C55-4fe2-B993-9F7BC1F10DB4")
+ ISymNGenWriter2 : public ISymNGenWriter
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE OpenModW(
+ /* [in] */ const wchar_t *wszModule,
+ /* [in] */ const wchar_t *wszObjFile,
+ /* [out] */ BYTE **ppmod) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE CloseMod(
+ /* [in] */ BYTE *pmod) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ModAddSymbols(
+ /* [in] */ BYTE *pmod,
+ /* [in] */ BYTE *pbSym,
+ /* [in] */ long cb) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ModAddSecContribEx(
+ /* [in] */ BYTE *pmod,
+ /* [in] */ USHORT isect,
+ /* [in] */ long off,
+ /* [in] */ long cb,
+ /* [in] */ ULONG dwCharacteristics,
+ /* [in] */ DWORD dwDataCrc,
+ /* [in] */ DWORD dwRelocCrc) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE QueryPDBNameExW(
+ /* [size_is][out] */ wchar_t wszPDB[ ],
+ /* [in] */ SIZE_T cchMax) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ISymNGenWriter2Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ISymNGenWriter2 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ISymNGenWriter2 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ISymNGenWriter2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *AddSymbol )(
+ ISymNGenWriter2 * This,
+ /* [in] */ BSTR pSymbol,
+ /* [in] */ USHORT iSection,
+ /* [in] */ ULONGLONG rva);
+
+ HRESULT ( STDMETHODCALLTYPE *AddSection )(
+ ISymNGenWriter2 * This,
+ /* [in] */ USHORT iSection,
+ /* [in] */ USHORT flags,
+ /* [in] */ long offset,
+ /* [in] */ long cb);
+
+ HRESULT ( STDMETHODCALLTYPE *OpenModW )(
+ ISymNGenWriter2 * This,
+ /* [in] */ const wchar_t *wszModule,
+ /* [in] */ const wchar_t *wszObjFile,
+ /* [out] */ BYTE **ppmod);
+
+ HRESULT ( STDMETHODCALLTYPE *CloseMod )(
+ ISymNGenWriter2 * This,
+ /* [in] */ BYTE *pmod);
+
+ HRESULT ( STDMETHODCALLTYPE *ModAddSymbols )(
+ ISymNGenWriter2 * This,
+ /* [in] */ BYTE *pmod,
+ /* [in] */ BYTE *pbSym,
+ /* [in] */ long cb);
+
+ HRESULT ( STDMETHODCALLTYPE *ModAddSecContribEx )(
+ ISymNGenWriter2 * This,
+ /* [in] */ BYTE *pmod,
+ /* [in] */ USHORT isect,
+ /* [in] */ long off,
+ /* [in] */ long cb,
+ /* [in] */ ULONG dwCharacteristics,
+ /* [in] */ DWORD dwDataCrc,
+ /* [in] */ DWORD dwRelocCrc);
+
+ HRESULT ( STDMETHODCALLTYPE *QueryPDBNameExW )(
+ ISymNGenWriter2 * This,
+ /* [size_is][out] */ wchar_t wszPDB[ ],
+ /* [in] */ SIZE_T cchMax);
+
+ END_INTERFACE
+ } ISymNGenWriter2Vtbl;
+
+ interface ISymNGenWriter2
+ {
+ CONST_VTBL struct ISymNGenWriter2Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ISymNGenWriter2_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ISymNGenWriter2_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ISymNGenWriter2_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ISymNGenWriter2_AddSymbol(This,pSymbol,iSection,rva) \
+ ( (This)->lpVtbl -> AddSymbol(This,pSymbol,iSection,rva) )
+
+#define ISymNGenWriter2_AddSection(This,iSection,flags,offset,cb) \
+ ( (This)->lpVtbl -> AddSection(This,iSection,flags,offset,cb) )
+
+
+#define ISymNGenWriter2_OpenModW(This,wszModule,wszObjFile,ppmod) \
+ ( (This)->lpVtbl -> OpenModW(This,wszModule,wszObjFile,ppmod) )
+
+#define ISymNGenWriter2_CloseMod(This,pmod) \
+ ( (This)->lpVtbl -> CloseMod(This,pmod) )
+
+#define ISymNGenWriter2_ModAddSymbols(This,pmod,pbSym,cb) \
+ ( (This)->lpVtbl -> ModAddSymbols(This,pmod,pbSym,cb) )
+
+#define ISymNGenWriter2_ModAddSecContribEx(This,pmod,isect,off,cb,dwCharacteristics,dwDataCrc,dwRelocCrc) \
+ ( (This)->lpVtbl -> ModAddSecContribEx(This,pmod,isect,off,cb,dwCharacteristics,dwDataCrc,dwRelocCrc) )
+
+#define ISymNGenWriter2_QueryPDBNameExW(This,wszPDB,cchMax) \
+ ( (This)->lpVtbl -> QueryPDBNameExW(This,wszPDB,cchMax) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ISymNGenWriter2_INTERFACE_DEFINED__ */
+
+
+#ifndef __ISymUnmanagedAsyncMethodPropertiesWriter_INTERFACE_DEFINED__
+#define __ISymUnmanagedAsyncMethodPropertiesWriter_INTERFACE_DEFINED__
+
+/* interface ISymUnmanagedAsyncMethodPropertiesWriter */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_ISymUnmanagedAsyncMethodPropertiesWriter;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("FC073774-1739-4232-BD56-A027294BEC15")
+ ISymUnmanagedAsyncMethodPropertiesWriter : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE DefineKickoffMethod(
+ /* [in] */ mdToken kickoffMethod) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE DefineCatchHandlerILOffset(
+ /* [in] */ ULONG32 catchHandlerOffset) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE DefineAsyncStepInfo(
+ /* [in] */ ULONG32 count,
+ /* [size_is][in] */ __RPC__in_ecount_full(count) ULONG32 yieldOffsets[ ],
+ /* [size_is][in] */ __RPC__in_ecount_full(count) ULONG32 breakpointOffset[ ],
+ /* [size_is][in] */ __RPC__in_ecount_full(count) mdToken breakpointMethod[ ]) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ISymUnmanagedAsyncMethodPropertiesWriterVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ __RPC__in ISymUnmanagedAsyncMethodPropertiesWriter * This,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ __RPC__in ISymUnmanagedAsyncMethodPropertiesWriter * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ __RPC__in ISymUnmanagedAsyncMethodPropertiesWriter * This);
+
+ HRESULT ( STDMETHODCALLTYPE *DefineKickoffMethod )(
+ __RPC__in ISymUnmanagedAsyncMethodPropertiesWriter * This,
+ /* [in] */ mdToken kickoffMethod);
+
+ HRESULT ( STDMETHODCALLTYPE *DefineCatchHandlerILOffset )(
+ __RPC__in ISymUnmanagedAsyncMethodPropertiesWriter * This,
+ /* [in] */ ULONG32 catchHandlerOffset);
+
+ HRESULT ( STDMETHODCALLTYPE *DefineAsyncStepInfo )(
+ __RPC__in ISymUnmanagedAsyncMethodPropertiesWriter * This,
+ /* [in] */ ULONG32 count,
+ /* [size_is][in] */ __RPC__in_ecount_full(count) ULONG32 yieldOffsets[ ],
+ /* [size_is][in] */ __RPC__in_ecount_full(count) ULONG32 breakpointOffset[ ],
+ /* [size_is][in] */ __RPC__in_ecount_full(count) mdToken breakpointMethod[ ]);
+
+ END_INTERFACE
+ } ISymUnmanagedAsyncMethodPropertiesWriterVtbl;
+
+ interface ISymUnmanagedAsyncMethodPropertiesWriter
+ {
+ CONST_VTBL struct ISymUnmanagedAsyncMethodPropertiesWriterVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ISymUnmanagedAsyncMethodPropertiesWriter_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ISymUnmanagedAsyncMethodPropertiesWriter_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ISymUnmanagedAsyncMethodPropertiesWriter_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ISymUnmanagedAsyncMethodPropertiesWriter_DefineKickoffMethod(This,kickoffMethod) \
+ ( (This)->lpVtbl -> DefineKickoffMethod(This,kickoffMethod) )
+
+#define ISymUnmanagedAsyncMethodPropertiesWriter_DefineCatchHandlerILOffset(This,catchHandlerOffset) \
+ ( (This)->lpVtbl -> DefineCatchHandlerILOffset(This,catchHandlerOffset) )
+
+#define ISymUnmanagedAsyncMethodPropertiesWriter_DefineAsyncStepInfo(This,count,yieldOffsets,breakpointOffset,breakpointMethod) \
+ ( (This)->lpVtbl -> DefineAsyncStepInfo(This,count,yieldOffsets,breakpointOffset,breakpointMethod) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ISymUnmanagedAsyncMethodPropertiesWriter_INTERFACE_DEFINED__ */
+
+
+#ifndef __ISymUnmanagedAsyncMethod_INTERFACE_DEFINED__
+#define __ISymUnmanagedAsyncMethod_INTERFACE_DEFINED__
+
+/* interface ISymUnmanagedAsyncMethod */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_ISymUnmanagedAsyncMethod;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("B20D55B3-532E-4906-87E7-25BD5734ABD2")
+ ISymUnmanagedAsyncMethod : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE IsAsyncMethod(
+ /* [retval][out] */ __RPC__out BOOL *pRetVal) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetKickoffMethod(
+ /* [retval][out] */ __RPC__out mdToken *kickoffMethod) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE HasCatchHandlerILOffset(
+ /* [retval][out] */ __RPC__out BOOL *pRetVal) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetCatchHandlerILOffset(
+ /* [retval][out] */ __RPC__out ULONG32 *pRetVal) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetAsyncStepInfoCount(
+ /* [retval][out] */ __RPC__out ULONG32 *pRetVal) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetAsyncStepInfo(
+ /* [in] */ ULONG32 cStepInfo,
+ /* [out] */ __RPC__out ULONG32 *pcStepInfo,
+ /* [size_is][in] */ __RPC__in_ecount_full(cStepInfo) ULONG32 yieldOffsets[ ],
+ /* [size_is][in] */ __RPC__in_ecount_full(cStepInfo) ULONG32 breakpointOffset[ ],
+ /* [size_is][in] */ __RPC__in_ecount_full(cStepInfo) mdToken breakpointMethod[ ]) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ISymUnmanagedAsyncMethodVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ __RPC__in ISymUnmanagedAsyncMethod * This,
+ /* [in] */ __RPC__in REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ __RPC__in ISymUnmanagedAsyncMethod * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ __RPC__in ISymUnmanagedAsyncMethod * This);
+
+ HRESULT ( STDMETHODCALLTYPE *IsAsyncMethod )(
+ __RPC__in ISymUnmanagedAsyncMethod * This,
+ /* [retval][out] */ __RPC__out BOOL *pRetVal);
+
+ HRESULT ( STDMETHODCALLTYPE *GetKickoffMethod )(
+ __RPC__in ISymUnmanagedAsyncMethod * This,
+ /* [retval][out] */ __RPC__out mdToken *kickoffMethod);
+
+ HRESULT ( STDMETHODCALLTYPE *HasCatchHandlerILOffset )(
+ __RPC__in ISymUnmanagedAsyncMethod * This,
+ /* [retval][out] */ __RPC__out BOOL *pRetVal);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCatchHandlerILOffset )(
+ __RPC__in ISymUnmanagedAsyncMethod * This,
+ /* [retval][out] */ __RPC__out ULONG32 *pRetVal);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAsyncStepInfoCount )(
+ __RPC__in ISymUnmanagedAsyncMethod * This,
+ /* [retval][out] */ __RPC__out ULONG32 *pRetVal);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAsyncStepInfo )(
+ __RPC__in ISymUnmanagedAsyncMethod * This,
+ /* [in] */ ULONG32 cStepInfo,
+ /* [out] */ __RPC__out ULONG32 *pcStepInfo,
+ /* [size_is][in] */ __RPC__in_ecount_full(cStepInfo) ULONG32 yieldOffsets[ ],
+ /* [size_is][in] */ __RPC__in_ecount_full(cStepInfo) ULONG32 breakpointOffset[ ],
+ /* [size_is][in] */ __RPC__in_ecount_full(cStepInfo) mdToken breakpointMethod[ ]);
+
+ END_INTERFACE
+ } ISymUnmanagedAsyncMethodVtbl;
+
+ interface ISymUnmanagedAsyncMethod
+ {
+ CONST_VTBL struct ISymUnmanagedAsyncMethodVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ISymUnmanagedAsyncMethod_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ISymUnmanagedAsyncMethod_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ISymUnmanagedAsyncMethod_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ISymUnmanagedAsyncMethod_IsAsyncMethod(This,pRetVal) \
+ ( (This)->lpVtbl -> IsAsyncMethod(This,pRetVal) )
+
+#define ISymUnmanagedAsyncMethod_GetKickoffMethod(This,kickoffMethod) \
+ ( (This)->lpVtbl -> GetKickoffMethod(This,kickoffMethod) )
+
+#define ISymUnmanagedAsyncMethod_HasCatchHandlerILOffset(This,pRetVal) \
+ ( (This)->lpVtbl -> HasCatchHandlerILOffset(This,pRetVal) )
+
+#define ISymUnmanagedAsyncMethod_GetCatchHandlerILOffset(This,pRetVal) \
+ ( (This)->lpVtbl -> GetCatchHandlerILOffset(This,pRetVal) )
+
+#define ISymUnmanagedAsyncMethod_GetAsyncStepInfoCount(This,pRetVal) \
+ ( (This)->lpVtbl -> GetAsyncStepInfoCount(This,pRetVal) )
+
+#define ISymUnmanagedAsyncMethod_GetAsyncStepInfo(This,cStepInfo,pcStepInfo,yieldOffsets,breakpointOffset,breakpointMethod) \
+ ( (This)->lpVtbl -> GetAsyncStepInfo(This,cStepInfo,pcStepInfo,yieldOffsets,breakpointOffset,breakpointMethod) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ISymUnmanagedAsyncMethod_INTERFACE_DEFINED__ */
+
+
+/* Additional Prototypes for ALL interfaces */
+
+unsigned long __RPC_USER BSTR_UserSize( __RPC__in unsigned long *, unsigned long , __RPC__in BSTR * );
+unsigned char * __RPC_USER BSTR_UserMarshal( __RPC__in unsigned long *, __RPC__inout_xcount(0) unsigned char *, __RPC__in BSTR * );
+unsigned char * __RPC_USER BSTR_UserUnmarshal(__RPC__in unsigned long *, __RPC__in_xcount(0) unsigned char *, __RPC__out BSTR * );
+void __RPC_USER BSTR_UserFree( __RPC__in unsigned long *, __RPC__in BSTR * );
+
+unsigned long __RPC_USER VARIANT_UserSize( __RPC__in unsigned long *, unsigned long , __RPC__in VARIANT * );
+unsigned char * __RPC_USER VARIANT_UserMarshal( __RPC__in unsigned long *, __RPC__inout_xcount(0) unsigned char *, __RPC__in VARIANT * );
+unsigned char * __RPC_USER VARIANT_UserUnmarshal(__RPC__in unsigned long *, __RPC__in_xcount(0) unsigned char *, __RPC__out VARIANT * );
+void __RPC_USER VARIANT_UserFree( __RPC__in unsigned long *, __RPC__in VARIANT * );
+
+/* end of Additional Prototypes */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+
diff --git a/src/pal/prebuilt/inc/fusion.h b/src/pal/prebuilt/inc/fusion.h
new file mode 100644
index 0000000000..b7a577016a
--- /dev/null
+++ b/src/pal/prebuilt/inc/fusion.h
@@ -0,0 +1,407 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+
+
+/* this ALWAYS GENERATED file contains the definitions for the interfaces */
+
+
+ /* File created by MIDL compiler version 8.00.0603 */
+/* @@MIDL_FILE_HEADING( ) */
+
+#pragma warning( disable: 4049 ) /* more than 64k source lines */
+
+
+/* verify that the <rpcndr.h> version is high enough to compile this file*/
+#ifndef __REQUIRED_RPCNDR_H_VERSION__
+#define __REQUIRED_RPCNDR_H_VERSION__ 475
+#endif
+
+#include "rpc.h"
+#include "rpcndr.h"
+
+#ifndef __RPCNDR_H_VERSION__
+#error this stub requires an updated version of <rpcndr.h>
+#endif // __RPCNDR_H_VERSION__
+
+#ifndef COM_NO_WINDOWS_H
+#include "windows.h"
+#include "ole2.h"
+#endif /*COM_NO_WINDOWS_H*/
+
+#ifndef __fusion_h__
+#define __fusion_h__
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+/* Forward Declarations */
+
+#ifndef __IAssemblyName_FWD_DEFINED__
+#define __IAssemblyName_FWD_DEFINED__
+typedef interface IAssemblyName IAssemblyName;
+
+#endif /* __IAssemblyName_FWD_DEFINED__ */
+
+
+/* header files for imported files */
+#include "objidl.h"
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+
+/* interface __MIDL_itf_fusion_0000_0000 */
+/* [local] */
+
+
+#ifdef _MSC_VER
+#pragma comment(lib,"uuid.lib")
+#endif
+
+//---------------------------------------------------------------------------=
+// Fusion Interfaces.
+
+#ifdef _MSC_VER
+#pragma once
+#endif
+
+
+
+
+#ifndef PEKIND_ENUM_DEFINED
+#define PEKIND_ENUM_DEFINED
+typedef
+enum _tagPEKIND
+ {
+ peNone = 0,
+ peMSIL = 0x1,
+ peI386 = 0x2,
+ peIA64 = 0x3,
+ peAMD64 = 0x4,
+ peARM = 0x5,
+ peARM64 = 0x6,
+ peInvalid = 0xffffffff
+ } PEKIND;
+
+#endif
+typedef
+enum _tagAssemblyContentType
+ {
+ AssemblyContentType_Default = 0,
+ AssemblyContentType_WindowsRuntime = 0x1,
+ AssemblyContentType_Invalid = 0xffffffff
+ } AssemblyContentType;
+
+// {CD193BC0-B4BC-11d2-9833-00C04FC31D2E}
+EXTERN_GUID(IID_IAssemblyName, 0xCD193BC0, 0xB4BC, 0x11d2, 0x98, 0x33, 0x00, 0xC0, 0x4F, 0xC3, 0x1D, 0x2E);
+
+
+extern RPC_IF_HANDLE __MIDL_itf_fusion_0000_0000_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_fusion_0000_0000_v0_0_s_ifspec;
+
+#ifndef __IAssemblyName_INTERFACE_DEFINED__
+#define __IAssemblyName_INTERFACE_DEFINED__
+
+/* interface IAssemblyName */
+/* [unique][uuid][object][local] */
+
+typedef /* [unique] */ IAssemblyName *LPASSEMBLYNAME;
+
+typedef /* [public] */
+enum __MIDL_IAssemblyName_0001
+ {
+ CANOF_PARSE_DISPLAY_NAME = 0x1,
+ CANOF_SET_DEFAULT_VALUES = 0x2,
+ CANOF_VERIFY_FRIEND_ASSEMBLYNAME = 0x4,
+ CANOF_PARSE_FRIEND_DISPLAY_NAME = ( CANOF_PARSE_DISPLAY_NAME | CANOF_VERIFY_FRIEND_ASSEMBLYNAME )
+ } CREATE_ASM_NAME_OBJ_FLAGS;
+
+typedef /* [public] */
+enum __MIDL_IAssemblyName_0002
+ {
+ ASM_NAME_PUBLIC_KEY = 0,
+ ASM_NAME_PUBLIC_KEY_TOKEN = ( ASM_NAME_PUBLIC_KEY + 1 ) ,
+ ASM_NAME_HASH_VALUE = ( ASM_NAME_PUBLIC_KEY_TOKEN + 1 ) ,
+ ASM_NAME_NAME = ( ASM_NAME_HASH_VALUE + 1 ) ,
+ ASM_NAME_MAJOR_VERSION = ( ASM_NAME_NAME + 1 ) ,
+ ASM_NAME_MINOR_VERSION = ( ASM_NAME_MAJOR_VERSION + 1 ) ,
+ ASM_NAME_BUILD_NUMBER = ( ASM_NAME_MINOR_VERSION + 1 ) ,
+ ASM_NAME_REVISION_NUMBER = ( ASM_NAME_BUILD_NUMBER + 1 ) ,
+ ASM_NAME_CULTURE = ( ASM_NAME_REVISION_NUMBER + 1 ) ,
+ ASM_NAME_PROCESSOR_ID_ARRAY = ( ASM_NAME_CULTURE + 1 ) ,
+ ASM_NAME_OSINFO_ARRAY = ( ASM_NAME_PROCESSOR_ID_ARRAY + 1 ) ,
+ ASM_NAME_HASH_ALGID = ( ASM_NAME_OSINFO_ARRAY + 1 ) ,
+ ASM_NAME_ALIAS = ( ASM_NAME_HASH_ALGID + 1 ) ,
+ ASM_NAME_CODEBASE_URL = ( ASM_NAME_ALIAS + 1 ) ,
+ ASM_NAME_CODEBASE_LASTMOD = ( ASM_NAME_CODEBASE_URL + 1 ) ,
+ ASM_NAME_NULL_PUBLIC_KEY = ( ASM_NAME_CODEBASE_LASTMOD + 1 ) ,
+ ASM_NAME_NULL_PUBLIC_KEY_TOKEN = ( ASM_NAME_NULL_PUBLIC_KEY + 1 ) ,
+ ASM_NAME_CUSTOM = ( ASM_NAME_NULL_PUBLIC_KEY_TOKEN + 1 ) ,
+ ASM_NAME_NULL_CUSTOM = ( ASM_NAME_CUSTOM + 1 ) ,
+ ASM_NAME_MVID = ( ASM_NAME_NULL_CUSTOM + 1 ) ,
+ ASM_NAME_FILE_MAJOR_VERSION = ( ASM_NAME_MVID + 1 ) ,
+ ASM_NAME_FILE_MINOR_VERSION = ( ASM_NAME_FILE_MAJOR_VERSION + 1 ) ,
+ ASM_NAME_FILE_BUILD_NUMBER = ( ASM_NAME_FILE_MINOR_VERSION + 1 ) ,
+ ASM_NAME_FILE_REVISION_NUMBER = ( ASM_NAME_FILE_BUILD_NUMBER + 1 ) ,
+ ASM_NAME_RETARGET = ( ASM_NAME_FILE_REVISION_NUMBER + 1 ) ,
+ ASM_NAME_SIGNATURE_BLOB = ( ASM_NAME_RETARGET + 1 ) ,
+ ASM_NAME_CONFIG_MASK = ( ASM_NAME_SIGNATURE_BLOB + 1 ) ,
+ ASM_NAME_ARCHITECTURE = ( ASM_NAME_CONFIG_MASK + 1 ) ,
+ ASM_NAME_CONTENT_TYPE = ( ASM_NAME_ARCHITECTURE + 1 ) ,
+ ASM_NAME_MAX_PARAMS = ( ASM_NAME_CONTENT_TYPE + 1 )
+ } ASM_NAME;
+
+typedef /* [public] */
+enum __MIDL_IAssemblyName_0003
+ {
+ ASM_DISPLAYF_VERSION = 0x1,
+ ASM_DISPLAYF_CULTURE = 0x2,
+ ASM_DISPLAYF_PUBLIC_KEY_TOKEN = 0x4,
+ ASM_DISPLAYF_PUBLIC_KEY = 0x8,
+ ASM_DISPLAYF_CUSTOM = 0x10,
+ ASM_DISPLAYF_PROCESSORARCHITECTURE = 0x20,
+ ASM_DISPLAYF_LANGUAGEID = 0x40,
+ ASM_DISPLAYF_RETARGET = 0x80,
+ ASM_DISPLAYF_CONFIG_MASK = 0x100,
+ ASM_DISPLAYF_MVID = 0x200,
+ ASM_DISPLAYF_CONTENT_TYPE = 0x400,
+ ASM_DISPLAYF_FULL = ( ( ( ( ( ASM_DISPLAYF_VERSION | ASM_DISPLAYF_CULTURE ) | ASM_DISPLAYF_PUBLIC_KEY_TOKEN ) | ASM_DISPLAYF_RETARGET ) | ASM_DISPLAYF_PROCESSORARCHITECTURE ) | ASM_DISPLAYF_CONTENT_TYPE )
+ } ASM_DISPLAY_FLAGS;
+
+typedef /* [public] */
+enum __MIDL_IAssemblyName_0004
+ {
+ ASM_CMPF_NAME = 0x1,
+ ASM_CMPF_MAJOR_VERSION = 0x2,
+ ASM_CMPF_MINOR_VERSION = 0x4,
+ ASM_CMPF_BUILD_NUMBER = 0x8,
+ ASM_CMPF_REVISION_NUMBER = 0x10,
+ ASM_CMPF_VERSION = ( ( ( ASM_CMPF_MAJOR_VERSION | ASM_CMPF_MINOR_VERSION ) | ASM_CMPF_BUILD_NUMBER ) | ASM_CMPF_REVISION_NUMBER ) ,
+ ASM_CMPF_PUBLIC_KEY_TOKEN = 0x20,
+ ASM_CMPF_CULTURE = 0x40,
+ ASM_CMPF_CUSTOM = 0x80,
+ ASM_CMPF_DEFAULT = 0x100,
+ ASM_CMPF_RETARGET = 0x200,
+ ASM_CMPF_ARCHITECTURE = 0x400,
+ ASM_CMPF_CONFIG_MASK = 0x800,
+ ASM_CMPF_MVID = 0x1000,
+ ASM_CMPF_SIGNATURE = 0x2000,
+ ASM_CMPF_CONTENT_TYPE = 0x4000,
+ ASM_CMPF_IL_ALL = ( ( ( ASM_CMPF_NAME | ASM_CMPF_VERSION ) | ASM_CMPF_PUBLIC_KEY_TOKEN ) | ASM_CMPF_CULTURE ) ,
+ ASM_CMPF_IL_NO_VERSION = ( ( ASM_CMPF_NAME | ASM_CMPF_PUBLIC_KEY_TOKEN ) | ASM_CMPF_CULTURE )
+ } ASM_CMP_FLAGS;
+
+
+EXTERN_C const IID IID_IAssemblyName;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("CD193BC0-B4BC-11d2-9833-00C04FC31D2E")
+ IAssemblyName : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE SetProperty(
+ /* [in] */ DWORD PropertyId,
+ /* [in] */ const void *pvProperty,
+ /* [in] */ DWORD cbProperty) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetProperty(
+ /* [in] */ DWORD PropertyId,
+ /* [out] */ LPVOID pvProperty,
+ /* [out][in] */ LPDWORD pcbProperty) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Finalize( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetDisplayName(
+ /* [annotation][out] */
+ _Out_writes_opt_(*pccDisplayName) LPOLESTR szDisplayName,
+ /* [out][in] */ LPDWORD pccDisplayName,
+ /* [in] */ DWORD dwDisplayFlags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Reserved(
+ /* [in] */ REFIID refIID,
+ /* [in] */ IUnknown *pUnkReserved1,
+ /* [in] */ IUnknown *pUnkReserved2,
+ /* [in] */ LPCOLESTR szReserved,
+ /* [in] */ LONGLONG llReserved,
+ /* [in] */ LPVOID pvReserved,
+ /* [in] */ DWORD cbReserved,
+ /* [out] */ LPVOID *ppReserved) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetName(
+ /* [annotation][out][in] */
+ _Inout_ LPDWORD lpcwBuffer,
+ /* [annotation][out] */
+ _Out_writes_opt_(*lpcwBuffer) WCHAR *pwzName) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetVersion(
+ /* [out] */ LPDWORD pdwVersionHi,
+ /* [out] */ LPDWORD pdwVersionLow) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE IsEqual(
+ /* [in] */ IAssemblyName *pName,
+ /* [in] */ DWORD dwCmpFlags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Clone(
+ /* [out] */ IAssemblyName **pName) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IAssemblyNameVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IAssemblyName * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IAssemblyName * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IAssemblyName * This);
+
+ HRESULT ( STDMETHODCALLTYPE *SetProperty )(
+ IAssemblyName * This,
+ /* [in] */ DWORD PropertyId,
+ /* [in] */ const void *pvProperty,
+ /* [in] */ DWORD cbProperty);
+
+ HRESULT ( STDMETHODCALLTYPE *GetProperty )(
+ IAssemblyName * This,
+ /* [in] */ DWORD PropertyId,
+ /* [out] */ LPVOID pvProperty,
+ /* [out][in] */ LPDWORD pcbProperty);
+
+ HRESULT ( STDMETHODCALLTYPE *Finalize )(
+ IAssemblyName * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDisplayName )(
+ IAssemblyName * This,
+ /* [annotation][out] */
+ _Out_writes_opt_(*pccDisplayName) LPOLESTR szDisplayName,
+ /* [out][in] */ LPDWORD pccDisplayName,
+ /* [in] */ DWORD dwDisplayFlags);
+
+ HRESULT ( STDMETHODCALLTYPE *Reserved )(
+ IAssemblyName * This,
+ /* [in] */ REFIID refIID,
+ /* [in] */ IUnknown *pUnkReserved1,
+ /* [in] */ IUnknown *pUnkReserved2,
+ /* [in] */ LPCOLESTR szReserved,
+ /* [in] */ LONGLONG llReserved,
+ /* [in] */ LPVOID pvReserved,
+ /* [in] */ DWORD cbReserved,
+ /* [out] */ LPVOID *ppReserved);
+
+ HRESULT ( STDMETHODCALLTYPE *GetName )(
+ IAssemblyName * This,
+ /* [annotation][out][in] */
+ _Inout_ LPDWORD lpcwBuffer,
+ /* [annotation][out] */
+ _Out_writes_opt_(*lpcwBuffer) WCHAR *pwzName);
+
+ HRESULT ( STDMETHODCALLTYPE *GetVersion )(
+ IAssemblyName * This,
+ /* [out] */ LPDWORD pdwVersionHi,
+ /* [out] */ LPDWORD pdwVersionLow);
+
+ HRESULT ( STDMETHODCALLTYPE *IsEqual )(
+ IAssemblyName * This,
+ /* [in] */ IAssemblyName *pName,
+ /* [in] */ DWORD dwCmpFlags);
+
+ HRESULT ( STDMETHODCALLTYPE *Clone )(
+ IAssemblyName * This,
+ /* [out] */ IAssemblyName **pName);
+
+ END_INTERFACE
+ } IAssemblyNameVtbl;
+
+ interface IAssemblyName
+ {
+ CONST_VTBL struct IAssemblyNameVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IAssemblyName_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IAssemblyName_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IAssemblyName_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IAssemblyName_SetProperty(This,PropertyId,pvProperty,cbProperty) \
+ ( (This)->lpVtbl -> SetProperty(This,PropertyId,pvProperty,cbProperty) )
+
+#define IAssemblyName_GetProperty(This,PropertyId,pvProperty,pcbProperty) \
+ ( (This)->lpVtbl -> GetProperty(This,PropertyId,pvProperty,pcbProperty) )
+
+#define IAssemblyName_Finalize(This) \
+ ( (This)->lpVtbl -> Finalize(This) )
+
+#define IAssemblyName_GetDisplayName(This,szDisplayName,pccDisplayName,dwDisplayFlags) \
+ ( (This)->lpVtbl -> GetDisplayName(This,szDisplayName,pccDisplayName,dwDisplayFlags) )
+
+#define IAssemblyName_Reserved(This,refIID,pUnkReserved1,pUnkReserved2,szReserved,llReserved,pvReserved,cbReserved,ppReserved) \
+ ( (This)->lpVtbl -> Reserved(This,refIID,pUnkReserved1,pUnkReserved2,szReserved,llReserved,pvReserved,cbReserved,ppReserved) )
+
+#define IAssemblyName_GetName(This,lpcwBuffer,pwzName) \
+ ( (This)->lpVtbl -> GetName(This,lpcwBuffer,pwzName) )
+
+#define IAssemblyName_GetVersion(This,pdwVersionHi,pdwVersionLow) \
+ ( (This)->lpVtbl -> GetVersion(This,pdwVersionHi,pdwVersionLow) )
+
+#define IAssemblyName_IsEqual(This,pName,dwCmpFlags) \
+ ( (This)->lpVtbl -> IsEqual(This,pName,dwCmpFlags) )
+
+#define IAssemblyName_Clone(This,pName) \
+ ( (This)->lpVtbl -> Clone(This,pName) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IAssemblyName_INTERFACE_DEFINED__ */
+
+
+/* interface __MIDL_itf_fusion_0000_0001 */
+/* [local] */
+
+STDAPI CreateAssemblyNameObject(LPASSEMBLYNAME *ppAssemblyNameObj, LPCWSTR szAssemblyName, DWORD dwFlags, LPVOID pvReserved);
+
+
+extern RPC_IF_HANDLE __MIDL_itf_fusion_0000_0001_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_fusion_0000_0001_v0_0_s_ifspec;
+
+/* Additional Prototypes for ALL interfaces */
+
+/* end of Additional Prototypes */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+
diff --git a/src/pal/prebuilt/inc/fusionpriv.h b/src/pal/prebuilt/inc/fusionpriv.h
new file mode 100644
index 0000000000..b0bca9e1f4
--- /dev/null
+++ b/src/pal/prebuilt/inc/fusionpriv.h
@@ -0,0 +1,2919 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+
+
+/* this ALWAYS GENERATED file contains the definitions for the interfaces */
+
+
+ /* File created by MIDL compiler version 8.00.0603 */
+/* @@MIDL_FILE_HEADING( ) */
+
+#pragma warning( disable: 4049 ) /* more than 64k source lines */
+
+
+/* verify that the <rpcndr.h> version is high enough to compile this file*/
+#ifndef __REQUIRED_RPCNDR_H_VERSION__
+#define __REQUIRED_RPCNDR_H_VERSION__ 475
+#endif
+
+#include "rpc.h"
+#include "rpcndr.h"
+
+#ifndef __RPCNDR_H_VERSION__
+#error this stub requires an updated version of <rpcndr.h>
+#endif // __RPCNDR_H_VERSION__
+
+#ifndef COM_NO_WINDOWS_H
+#include "windows.h"
+#include "ole2.h"
+#endif /*COM_NO_WINDOWS_H*/
+
+#ifndef __fusionpriv_h__
+#define __fusionpriv_h__
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+/* Forward Declarations */
+
+#ifndef __IHistoryAssembly_FWD_DEFINED__
+#define __IHistoryAssembly_FWD_DEFINED__
+typedef interface IHistoryAssembly IHistoryAssembly;
+
+#endif /* __IHistoryAssembly_FWD_DEFINED__ */
+
+
+#ifndef __IHistoryReader_FWD_DEFINED__
+#define __IHistoryReader_FWD_DEFINED__
+typedef interface IHistoryReader IHistoryReader;
+
+#endif /* __IHistoryReader_FWD_DEFINED__ */
+
+
+#ifndef __IFusionBindLog_FWD_DEFINED__
+#define __IFusionBindLog_FWD_DEFINED__
+typedef interface IFusionBindLog IFusionBindLog;
+
+#endif /* __IFusionBindLog_FWD_DEFINED__ */
+
+
+#ifndef __IAssemblyManifestImport_FWD_DEFINED__
+#define __IAssemblyManifestImport_FWD_DEFINED__
+typedef interface IAssemblyManifestImport IAssemblyManifestImport;
+
+#endif /* __IAssemblyManifestImport_FWD_DEFINED__ */
+
+
+#ifndef __IApplicationContext_FWD_DEFINED__
+#define __IApplicationContext_FWD_DEFINED__
+typedef interface IApplicationContext IApplicationContext;
+
+#endif /* __IApplicationContext_FWD_DEFINED__ */
+
+
+#ifndef __IAssemblyNameBinder_FWD_DEFINED__
+#define __IAssemblyNameBinder_FWD_DEFINED__
+typedef interface IAssemblyNameBinder IAssemblyNameBinder;
+
+#endif /* __IAssemblyNameBinder_FWD_DEFINED__ */
+
+
+#ifndef __IAssembly_FWD_DEFINED__
+#define __IAssembly_FWD_DEFINED__
+typedef interface IAssembly IAssembly;
+
+#endif /* __IAssembly_FWD_DEFINED__ */
+
+
+#ifndef __IAssemblyBindingClosureEnumerator_FWD_DEFINED__
+#define __IAssemblyBindingClosureEnumerator_FWD_DEFINED__
+typedef interface IAssemblyBindingClosureEnumerator IAssemblyBindingClosureEnumerator;
+
+#endif /* __IAssemblyBindingClosureEnumerator_FWD_DEFINED__ */
+
+
+#ifndef __IAssemblyBindingClosure_FWD_DEFINED__
+#define __IAssemblyBindingClosure_FWD_DEFINED__
+typedef interface IAssemblyBindingClosure IAssemblyBindingClosure;
+
+#endif /* __IAssemblyBindingClosure_FWD_DEFINED__ */
+
+
+#ifndef __IAssemblyBindSink_FWD_DEFINED__
+#define __IAssemblyBindSink_FWD_DEFINED__
+typedef interface IAssemblyBindSink IAssemblyBindSink;
+
+#endif /* __IAssemblyBindSink_FWD_DEFINED__ */
+
+
+#ifndef __IAssemblyBinding_FWD_DEFINED__
+#define __IAssemblyBinding_FWD_DEFINED__
+typedef interface IAssemblyBinding IAssemblyBinding;
+
+#endif /* __IAssemblyBinding_FWD_DEFINED__ */
+
+
+#ifndef __IAssemblyModuleImport_FWD_DEFINED__
+#define __IAssemblyModuleImport_FWD_DEFINED__
+typedef interface IAssemblyModuleImport IAssemblyModuleImport;
+
+#endif /* __IAssemblyModuleImport_FWD_DEFINED__ */
+
+
+#ifndef __IAssemblyScavenger_FWD_DEFINED__
+#define __IAssemblyScavenger_FWD_DEFINED__
+typedef interface IAssemblyScavenger IAssemblyScavenger;
+
+#endif /* __IAssemblyScavenger_FWD_DEFINED__ */
+
+
+#ifndef __ICodebaseList_FWD_DEFINED__
+#define __ICodebaseList_FWD_DEFINED__
+typedef interface ICodebaseList ICodebaseList;
+
+#endif /* __ICodebaseList_FWD_DEFINED__ */
+
+
+#ifndef __IDownloadMgr_FWD_DEFINED__
+#define __IDownloadMgr_FWD_DEFINED__
+typedef interface IDownloadMgr IDownloadMgr;
+
+#endif /* __IDownloadMgr_FWD_DEFINED__ */
+
+
+#ifndef __IHostAssembly_FWD_DEFINED__
+#define __IHostAssembly_FWD_DEFINED__
+typedef interface IHostAssembly IHostAssembly;
+
+#endif /* __IHostAssembly_FWD_DEFINED__ */
+
+
+#ifndef __IHostAssemblyModuleImport_FWD_DEFINED__
+#define __IHostAssemblyModuleImport_FWD_DEFINED__
+typedef interface IHostAssemblyModuleImport IHostAssemblyModuleImport;
+
+#endif /* __IHostAssemblyModuleImport_FWD_DEFINED__ */
+
+
+/* header files for imported files */
+#include "objidl.h"
+#include "oleidl.h"
+#include "fusion.h"
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+
+/* interface __MIDL_itf_fusionpriv_0000_0000 */
+/* [local] */
+
+//=--------------------------------------------------------------------------=
+// fusionpriv.h
+//=--------------------------------------------------------------------------=
+
+//
+// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
+// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
+// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
+// PARTICULAR PURPOSE.
+//=--------------------------------------------------------------------------=
+
+#ifdef _MSC_VER
+#pragma comment(lib,"uuid.lib")
+#endif
+
+//---------------------------------------------------------------------------=
+// Fusion Interfaces.
+
+#if defined(_CLR_BLD) && !defined(FEATURE_FUSION)
+#error FEATURE_FUSION is not enabled, please do not include fusionpriv.h
+#endif
+#ifdef _MSC_VER
+#pragma once
+#endif
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+struct IMetaDataAssemblyImport;
+
+EXTERN_C const IID IID_IApplicationContext;
+EXTERN_C const IID IID_IAssembly;
+EXTERN_C const IID IID_IAssemblyBindSink;
+EXTERN_C const IID IID_IAssemblyBinding;
+EXTERN_C const IID IID_IAssemblyManifestImport;
+EXTERN_C const IID IID_IAssemblyModuleImport;
+EXTERN_C const IID IID_IHistoryAssembly;
+EXTERN_C const IID IID_IHistoryReader;
+EXTERN_C const IID IID_IMetaDataAssemblyImportControl;
+EXTERN_C const IID IID_IAssemblyScavenger;
+EXTERN_C const IID IID_IHostAssembly;
+EXTERN_C const IID IID_IHostAssemblyModuleImport;
+typedef /* [public] */
+enum __MIDL___MIDL_itf_fusionpriv_0000_0000_0001
+ {
+ ASM_BINDF_NONE = 0,
+ ASM_BINDF_FORCE_CACHE_INSTALL = 0x1,
+ ASM_BINDF_RFS_INTEGRITY_CHECK = 0x2,
+ ASM_BINDF_RFS_MODULE_CHECK = 0x4,
+ ASM_BINDF_BINPATH_PROBE_ONLY = 0x8,
+ ASM_BINDF_PARENT_ASM_HINT = 0x20,
+ ASM_BINDF_DISALLOW_APPLYPUBLISHERPOLICY = 0x40,
+ ASM_BINDF_DISALLOW_APPBINDINGREDIRECTS = 0x80,
+ ASM_BINDF_DISABLE_FX_UNIFICATION = 0x100,
+ ASM_BINDF_DO_NOT_PROBE_NATIVE_IMAGE = 0x200,
+ ASM_BINDF_DISABLE_DOWNLOAD = 0x400,
+ ASM_BINDF_INSPECTION_ONLY = 0x800,
+ ASM_BINDF_DISALLOW_APP_BASE_PROBING = 0x1000,
+ ASM_BINDF_SUPPRESS_SECURITY_CHECKS = 0x2000
+ } ASM_BIND_FLAGS;
+
+typedef
+enum tagDEVOVERRIDEMODE
+ {
+ DEVOVERRIDE_LOCAL = 0x1,
+ DEVOVERRIDE_GLOBAL = 0x2
+ } DEVOVERRIDEMODE;
+
+typedef
+enum tagWALK_LEVEL
+ {
+ LEVEL_STARTING = 0,
+ LEVEL_WINRTCHECK = ( LEVEL_STARTING + 1 ) ,
+ LEVEL_GACCHECK = ( LEVEL_WINRTCHECK + 1 ) ,
+ LEVEL_COMPLETE = ( LEVEL_GACCHECK + 1 ) ,
+ LEVEL_FXPREDICTED = ( LEVEL_COMPLETE + 1 ) ,
+ LEVEL_FXPROBED = ( LEVEL_FXPREDICTED + 1 )
+ } WALK_LEVEL;
+
+
+
+extern RPC_IF_HANDLE __MIDL_itf_fusionpriv_0000_0000_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_fusionpriv_0000_0000_v0_0_s_ifspec;
+
+#ifndef __IHistoryAssembly_INTERFACE_DEFINED__
+#define __IHistoryAssembly_INTERFACE_DEFINED__
+
+/* interface IHistoryAssembly */
+/* [unique][uuid][object][local] */
+
+
+EXTERN_C const IID IID_IHistoryAssembly;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("e6096a07-e188-4a49-8d50-2a0172a0d205")
+ IHistoryAssembly : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetAssemblyName(
+ /* [annotation][out] */
+ __out LPWSTR wzAsmName,
+ /* [annotation][out][in] */
+ __inout DWORD *pdwSize) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetPublicKeyToken(
+ /* [annotation][out] */
+ __out LPWSTR wzPublicKeyToken,
+ /* [annotation][out][in] */
+ __inout DWORD *pdwSize) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetCulture(
+ /* [annotation][out] */
+ __out LPWSTR wzCulture,
+ /* [annotation][out][in] */
+ __inout DWORD *pdwSize) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetReferenceVersion(
+ /* [annotation][out] */
+ __out LPWSTR wzVerRef,
+ /* [annotation][out][in] */
+ __inout DWORD *pdwSize) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetActivationDate(
+ /* [annotation][out] */
+ __out LPWSTR wzActivationDate,
+ /* [annotation][out][in] */
+ __inout DWORD *pdwSize) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetAppCfgVersion(
+ /* [annotation][out] */
+ __out LPWSTR pwzVerAppCfg,
+ /* [annotation][out][in] */
+ __inout DWORD *pdwSize) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetPublisherCfgVersion(
+ /* [annotation][out] */
+ __out LPWSTR pwzVerPublisherCfg,
+ /* [annotation][out][in] */
+ __inout DWORD *pdwSize) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetAdminCfgVersion(
+ /* [annotation][out] */
+ __out LPWSTR pwzAdminCfg,
+ /* [annotation][out][in] */
+ __inout DWORD *pdwSize) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IHistoryAssemblyVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IHistoryAssembly * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IHistoryAssembly * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IHistoryAssembly * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAssemblyName )(
+ IHistoryAssembly * This,
+ /* [annotation][out] */
+ __out LPWSTR wzAsmName,
+ /* [annotation][out][in] */
+ __inout DWORD *pdwSize);
+
+ HRESULT ( STDMETHODCALLTYPE *GetPublicKeyToken )(
+ IHistoryAssembly * This,
+ /* [annotation][out] */
+ __out LPWSTR wzPublicKeyToken,
+ /* [annotation][out][in] */
+ __inout DWORD *pdwSize);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCulture )(
+ IHistoryAssembly * This,
+ /* [annotation][out] */
+ __out LPWSTR wzCulture,
+ /* [annotation][out][in] */
+ __inout DWORD *pdwSize);
+
+ HRESULT ( STDMETHODCALLTYPE *GetReferenceVersion )(
+ IHistoryAssembly * This,
+ /* [annotation][out] */
+ __out LPWSTR wzVerRef,
+ /* [annotation][out][in] */
+ __inout DWORD *pdwSize);
+
+ HRESULT ( STDMETHODCALLTYPE *GetActivationDate )(
+ IHistoryAssembly * This,
+ /* [annotation][out] */
+ __out LPWSTR wzActivationDate,
+ /* [annotation][out][in] */
+ __inout DWORD *pdwSize);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAppCfgVersion )(
+ IHistoryAssembly * This,
+ /* [annotation][out] */
+ __out LPWSTR pwzVerAppCfg,
+ /* [annotation][out][in] */
+ __inout DWORD *pdwSize);
+
+ HRESULT ( STDMETHODCALLTYPE *GetPublisherCfgVersion )(
+ IHistoryAssembly * This,
+ /* [annotation][out] */
+ __out LPWSTR pwzVerPublisherCfg,
+ /* [annotation][out][in] */
+ __inout DWORD *pdwSize);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAdminCfgVersion )(
+ IHistoryAssembly * This,
+ /* [annotation][out] */
+ __out LPWSTR pwzAdminCfg,
+ /* [annotation][out][in] */
+ __inout DWORD *pdwSize);
+
+ END_INTERFACE
+ } IHistoryAssemblyVtbl;
+
+ interface IHistoryAssembly
+ {
+ CONST_VTBL struct IHistoryAssemblyVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IHistoryAssembly_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IHistoryAssembly_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IHistoryAssembly_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IHistoryAssembly_GetAssemblyName(This,wzAsmName,pdwSize) \
+ ( (This)->lpVtbl -> GetAssemblyName(This,wzAsmName,pdwSize) )
+
+#define IHistoryAssembly_GetPublicKeyToken(This,wzPublicKeyToken,pdwSize) \
+ ( (This)->lpVtbl -> GetPublicKeyToken(This,wzPublicKeyToken,pdwSize) )
+
+#define IHistoryAssembly_GetCulture(This,wzCulture,pdwSize) \
+ ( (This)->lpVtbl -> GetCulture(This,wzCulture,pdwSize) )
+
+#define IHistoryAssembly_GetReferenceVersion(This,wzVerRef,pdwSize) \
+ ( (This)->lpVtbl -> GetReferenceVersion(This,wzVerRef,pdwSize) )
+
+#define IHistoryAssembly_GetActivationDate(This,wzActivationDate,pdwSize) \
+ ( (This)->lpVtbl -> GetActivationDate(This,wzActivationDate,pdwSize) )
+
+#define IHistoryAssembly_GetAppCfgVersion(This,pwzVerAppCfg,pdwSize) \
+ ( (This)->lpVtbl -> GetAppCfgVersion(This,pwzVerAppCfg,pdwSize) )
+
+#define IHistoryAssembly_GetPublisherCfgVersion(This,pwzVerPublisherCfg,pdwSize) \
+ ( (This)->lpVtbl -> GetPublisherCfgVersion(This,pwzVerPublisherCfg,pdwSize) )
+
+#define IHistoryAssembly_GetAdminCfgVersion(This,pwzAdminCfg,pdwSize) \
+ ( (This)->lpVtbl -> GetAdminCfgVersion(This,pwzAdminCfg,pdwSize) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IHistoryAssembly_INTERFACE_DEFINED__ */
+
+
+#ifndef __IHistoryReader_INTERFACE_DEFINED__
+#define __IHistoryReader_INTERFACE_DEFINED__
+
+/* interface IHistoryReader */
+/* [unique][uuid][object][local] */
+
+
+EXTERN_C const IID IID_IHistoryReader;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("1d23df4d-a1e2-4b8b-93d6-6ea3dc285a54")
+ IHistoryReader : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetFilePath(
+ /* [annotation][out] */
+ __out LPWSTR wzFilePath,
+ /* [annotation][out][in] */
+ __inout DWORD *pdwSize) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetApplicationName(
+ /* [annotation][out] */
+ __out LPWSTR wzAppName,
+ /* [annotation][out][in] */
+ __inout DWORD *pdwSize) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetEXEModulePath(
+ /* [annotation][out] */
+ __out LPWSTR wzExePath,
+ /* [annotation][out][in] */
+ __inout DWORD *pdwSize) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetNumActivations(
+ /* [out] */ DWORD *pdwNumActivations) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetActivationDate(
+ /* [in] */ DWORD dwIdx,
+ /* [out] */ FILETIME *pftDate) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetRunTimeVersion(
+ /* [in] */ FILETIME *pftActivationDate,
+ /* [annotation][out] */
+ __out LPWSTR wzRunTimeVersion,
+ /* [annotation][out][in] */
+ __inout DWORD *pdwSize) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetNumAssemblies(
+ /* [in] */ FILETIME *pftActivationDate,
+ /* [out] */ DWORD *pdwNumAsms) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetHistoryAssembly(
+ /* [in] */ FILETIME *pftActivationDate,
+ /* [in] */ DWORD dwIdx,
+ /* [out] */ IHistoryAssembly **ppHistAsm) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IHistoryReaderVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IHistoryReader * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IHistoryReader * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IHistoryReader * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFilePath )(
+ IHistoryReader * This,
+ /* [annotation][out] */
+ __out LPWSTR wzFilePath,
+ /* [annotation][out][in] */
+ __inout DWORD *pdwSize);
+
+ HRESULT ( STDMETHODCALLTYPE *GetApplicationName )(
+ IHistoryReader * This,
+ /* [annotation][out] */
+ __out LPWSTR wzAppName,
+ /* [annotation][out][in] */
+ __inout DWORD *pdwSize);
+
+ HRESULT ( STDMETHODCALLTYPE *GetEXEModulePath )(
+ IHistoryReader * This,
+ /* [annotation][out] */
+ __out LPWSTR wzExePath,
+ /* [annotation][out][in] */
+ __inout DWORD *pdwSize);
+
+ HRESULT ( STDMETHODCALLTYPE *GetNumActivations )(
+ IHistoryReader * This,
+ /* [out] */ DWORD *pdwNumActivations);
+
+ HRESULT ( STDMETHODCALLTYPE *GetActivationDate )(
+ IHistoryReader * This,
+ /* [in] */ DWORD dwIdx,
+ /* [out] */ FILETIME *pftDate);
+
+ HRESULT ( STDMETHODCALLTYPE *GetRunTimeVersion )(
+ IHistoryReader * This,
+ /* [in] */ FILETIME *pftActivationDate,
+ /* [annotation][out] */
+ __out LPWSTR wzRunTimeVersion,
+ /* [annotation][out][in] */
+ __inout DWORD *pdwSize);
+
+ HRESULT ( STDMETHODCALLTYPE *GetNumAssemblies )(
+ IHistoryReader * This,
+ /* [in] */ FILETIME *pftActivationDate,
+ /* [out] */ DWORD *pdwNumAsms);
+
+ HRESULT ( STDMETHODCALLTYPE *GetHistoryAssembly )(
+ IHistoryReader * This,
+ /* [in] */ FILETIME *pftActivationDate,
+ /* [in] */ DWORD dwIdx,
+ /* [out] */ IHistoryAssembly **ppHistAsm);
+
+ END_INTERFACE
+ } IHistoryReaderVtbl;
+
+ interface IHistoryReader
+ {
+ CONST_VTBL struct IHistoryReaderVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IHistoryReader_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IHistoryReader_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IHistoryReader_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IHistoryReader_GetFilePath(This,wzFilePath,pdwSize) \
+ ( (This)->lpVtbl -> GetFilePath(This,wzFilePath,pdwSize) )
+
+#define IHistoryReader_GetApplicationName(This,wzAppName,pdwSize) \
+ ( (This)->lpVtbl -> GetApplicationName(This,wzAppName,pdwSize) )
+
+#define IHistoryReader_GetEXEModulePath(This,wzExePath,pdwSize) \
+ ( (This)->lpVtbl -> GetEXEModulePath(This,wzExePath,pdwSize) )
+
+#define IHistoryReader_GetNumActivations(This,pdwNumActivations) \
+ ( (This)->lpVtbl -> GetNumActivations(This,pdwNumActivations) )
+
+#define IHistoryReader_GetActivationDate(This,dwIdx,pftDate) \
+ ( (This)->lpVtbl -> GetActivationDate(This,dwIdx,pftDate) )
+
+#define IHistoryReader_GetRunTimeVersion(This,pftActivationDate,wzRunTimeVersion,pdwSize) \
+ ( (This)->lpVtbl -> GetRunTimeVersion(This,pftActivationDate,wzRunTimeVersion,pdwSize) )
+
+#define IHistoryReader_GetNumAssemblies(This,pftActivationDate,pdwNumAsms) \
+ ( (This)->lpVtbl -> GetNumAssemblies(This,pftActivationDate,pdwNumAsms) )
+
+#define IHistoryReader_GetHistoryAssembly(This,pftActivationDate,dwIdx,ppHistAsm) \
+ ( (This)->lpVtbl -> GetHistoryAssembly(This,pftActivationDate,dwIdx,ppHistAsm) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IHistoryReader_INTERFACE_DEFINED__ */
+
+
+/* interface __MIDL_itf_fusionpriv_0000_0002 */
+/* [local] */
+
+typedef /* [public][public][public] */
+enum __MIDL___MIDL_itf_fusionpriv_0000_0002_0001
+ {
+ LOADCTX_TYPE_DEFAULT = 0,
+ LOADCTX_TYPE_LOADFROM = ( LOADCTX_TYPE_DEFAULT + 1 ) ,
+ LOADCTX_TYPE_UNKNOWN = ( LOADCTX_TYPE_LOADFROM + 1 ) ,
+ LOADCTX_TYPE_HOSTED = ( LOADCTX_TYPE_UNKNOWN + 1 )
+ } LOADCTX_TYPE;
+
+#define FUSION_BIND_LOG_CATEGORY_DEFAULT 0
+#define FUSION_BIND_LOG_CATEGORY_NGEN 1
+#define FUSION_BIND_LOG_CATEGORY_MAX 2
+
+
+extern RPC_IF_HANDLE __MIDL_itf_fusionpriv_0000_0002_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_fusionpriv_0000_0002_v0_0_s_ifspec;
+
+#ifndef __IFusionBindLog_INTERFACE_DEFINED__
+#define __IFusionBindLog_INTERFACE_DEFINED__
+
+/* interface IFusionBindLog */
+/* [unique][uuid][object][local] */
+
+
+EXTERN_C const IID IID_IFusionBindLog;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("67E9F87D-8B8A-4a90-9D3E-85ED5B2DCC83")
+ IFusionBindLog : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE SetResultCode(
+ /* [in] */ DWORD dwLogCategory,
+ /* [in] */ HRESULT hr) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetResultCode(
+ /* [in] */ DWORD dwLogCategory,
+ /* [out] */ HRESULT *pHr) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetBindLog(
+ /* [in] */ DWORD dwDetailLevel,
+ /* [in] */ DWORD dwLogCategory,
+ /* [annotation][out] */
+ __out_opt LPWSTR pwzDebugLog,
+ /* [annotation][out][in] */
+ __inout DWORD *pcbDebugLog) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE LogMessage(
+ /* [in] */ DWORD dwDetailLevel,
+ /* [in] */ DWORD dwLogCategory,
+ /* [in] */ LPCWSTR pwzDebugLog) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Flush(
+ /* [in] */ DWORD dwDetailLevel,
+ /* [in] */ DWORD dwLogCategory) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetBindingID(
+ /* [out] */ ULONGLONG *pullBindingID) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ETWTraceLogMessage(
+ /* [in] */ DWORD dwETWLogCategory,
+ /* [in] */ IAssemblyName *pAsm) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IFusionBindLogVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IFusionBindLog * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IFusionBindLog * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IFusionBindLog * This);
+
+ HRESULT ( STDMETHODCALLTYPE *SetResultCode )(
+ IFusionBindLog * This,
+ /* [in] */ DWORD dwLogCategory,
+ /* [in] */ HRESULT hr);
+
+ HRESULT ( STDMETHODCALLTYPE *GetResultCode )(
+ IFusionBindLog * This,
+ /* [in] */ DWORD dwLogCategory,
+ /* [out] */ HRESULT *pHr);
+
+ HRESULT ( STDMETHODCALLTYPE *GetBindLog )(
+ IFusionBindLog * This,
+ /* [in] */ DWORD dwDetailLevel,
+ /* [in] */ DWORD dwLogCategory,
+ /* [annotation][out] */
+ __out_opt LPWSTR pwzDebugLog,
+ /* [annotation][out][in] */
+ __inout DWORD *pcbDebugLog);
+
+ HRESULT ( STDMETHODCALLTYPE *LogMessage )(
+ IFusionBindLog * This,
+ /* [in] */ DWORD dwDetailLevel,
+ /* [in] */ DWORD dwLogCategory,
+ /* [in] */ LPCWSTR pwzDebugLog);
+
+ HRESULT ( STDMETHODCALLTYPE *Flush )(
+ IFusionBindLog * This,
+ /* [in] */ DWORD dwDetailLevel,
+ /* [in] */ DWORD dwLogCategory);
+
+ HRESULT ( STDMETHODCALLTYPE *GetBindingID )(
+ IFusionBindLog * This,
+ /* [out] */ ULONGLONG *pullBindingID);
+
+ HRESULT ( STDMETHODCALLTYPE *ETWTraceLogMessage )(
+ IFusionBindLog * This,
+ /* [in] */ DWORD dwETWLogCategory,
+ /* [in] */ IAssemblyName *pAsm);
+
+ END_INTERFACE
+ } IFusionBindLogVtbl;
+
+ interface IFusionBindLog
+ {
+ CONST_VTBL struct IFusionBindLogVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IFusionBindLog_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IFusionBindLog_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IFusionBindLog_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IFusionBindLog_SetResultCode(This,dwLogCategory,hr) \
+ ( (This)->lpVtbl -> SetResultCode(This,dwLogCategory,hr) )
+
+#define IFusionBindLog_GetResultCode(This,dwLogCategory,pHr) \
+ ( (This)->lpVtbl -> GetResultCode(This,dwLogCategory,pHr) )
+
+#define IFusionBindLog_GetBindLog(This,dwDetailLevel,dwLogCategory,pwzDebugLog,pcbDebugLog) \
+ ( (This)->lpVtbl -> GetBindLog(This,dwDetailLevel,dwLogCategory,pwzDebugLog,pcbDebugLog) )
+
+#define IFusionBindLog_LogMessage(This,dwDetailLevel,dwLogCategory,pwzDebugLog) \
+ ( (This)->lpVtbl -> LogMessage(This,dwDetailLevel,dwLogCategory,pwzDebugLog) )
+
+#define IFusionBindLog_Flush(This,dwDetailLevel,dwLogCategory) \
+ ( (This)->lpVtbl -> Flush(This,dwDetailLevel,dwLogCategory) )
+
+#define IFusionBindLog_GetBindingID(This,pullBindingID) \
+ ( (This)->lpVtbl -> GetBindingID(This,pullBindingID) )
+
+#define IFusionBindLog_ETWTraceLogMessage(This,dwETWLogCategory,pAsm) \
+ ( (This)->lpVtbl -> ETWTraceLogMessage(This,dwETWLogCategory,pAsm) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IFusionBindLog_INTERFACE_DEFINED__ */
+
+
+#ifndef __IAssemblyManifestImport_INTERFACE_DEFINED__
+#define __IAssemblyManifestImport_INTERFACE_DEFINED__
+
+/* interface IAssemblyManifestImport */
+/* [unique][uuid][object][local] */
+
+typedef /* [unique] */ IAssemblyManifestImport *LPASSEMBLY_MANIFEST_IMPORT;
+
+
+EXTERN_C const IID IID_IAssemblyManifestImport;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("de9a68ba-0fa2-11d3-94aa-00c04fc308ff")
+ IAssemblyManifestImport : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetAssemblyNameDef(
+ /* [out] */ IAssemblyName **ppAssemblyName) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetNextAssemblyNameRef(
+ /* [in] */ DWORD nIndex,
+ /* [out] */ IAssemblyName **ppAssemblyName) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetNextAssemblyModule(
+ /* [in] */ DWORD nIndex,
+ /* [out] */ IAssemblyModuleImport **ppImport) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetModuleByName(
+ /* [in] */ LPCOLESTR szModuleName,
+ /* [out] */ IAssemblyModuleImport **ppModImport) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetManifestModulePath(
+ /* [annotation][size_is][out] */
+ __out_ecount_full(*pccModulePath) LPOLESTR szModulePath,
+ /* [out][in] */ LPDWORD pccModulePath) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetInternalMDImport(
+ /* [out] */ IMetaDataAssemblyImport **ppMDImport) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE LoadDataFromMDImport(
+ /* [in] */ IMetaDataAssemblyImport *ppMDImport) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IAssemblyManifestImportVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IAssemblyManifestImport * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IAssemblyManifestImport * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IAssemblyManifestImport * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAssemblyNameDef )(
+ IAssemblyManifestImport * This,
+ /* [out] */ IAssemblyName **ppAssemblyName);
+
+ HRESULT ( STDMETHODCALLTYPE *GetNextAssemblyNameRef )(
+ IAssemblyManifestImport * This,
+ /* [in] */ DWORD nIndex,
+ /* [out] */ IAssemblyName **ppAssemblyName);
+
+ HRESULT ( STDMETHODCALLTYPE *GetNextAssemblyModule )(
+ IAssemblyManifestImport * This,
+ /* [in] */ DWORD nIndex,
+ /* [out] */ IAssemblyModuleImport **ppImport);
+
+ HRESULT ( STDMETHODCALLTYPE *GetModuleByName )(
+ IAssemblyManifestImport * This,
+ /* [in] */ LPCOLESTR szModuleName,
+ /* [out] */ IAssemblyModuleImport **ppModImport);
+
+ HRESULT ( STDMETHODCALLTYPE *GetManifestModulePath )(
+ IAssemblyManifestImport * This,
+ /* [annotation][size_is][out] */
+ __out_ecount_full(*pccModulePath) LPOLESTR szModulePath,
+ /* [out][in] */ LPDWORD pccModulePath);
+
+ HRESULT ( STDMETHODCALLTYPE *GetInternalMDImport )(
+ IAssemblyManifestImport * This,
+ /* [out] */ IMetaDataAssemblyImport **ppMDImport);
+
+ HRESULT ( STDMETHODCALLTYPE *LoadDataFromMDImport )(
+ IAssemblyManifestImport * This,
+ /* [in] */ IMetaDataAssemblyImport *ppMDImport);
+
+ END_INTERFACE
+ } IAssemblyManifestImportVtbl;
+
+ interface IAssemblyManifestImport
+ {
+ CONST_VTBL struct IAssemblyManifestImportVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IAssemblyManifestImport_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IAssemblyManifestImport_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IAssemblyManifestImport_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IAssemblyManifestImport_GetAssemblyNameDef(This,ppAssemblyName) \
+ ( (This)->lpVtbl -> GetAssemblyNameDef(This,ppAssemblyName) )
+
+#define IAssemblyManifestImport_GetNextAssemblyNameRef(This,nIndex,ppAssemblyName) \
+ ( (This)->lpVtbl -> GetNextAssemblyNameRef(This,nIndex,ppAssemblyName) )
+
+#define IAssemblyManifestImport_GetNextAssemblyModule(This,nIndex,ppImport) \
+ ( (This)->lpVtbl -> GetNextAssemblyModule(This,nIndex,ppImport) )
+
+#define IAssemblyManifestImport_GetModuleByName(This,szModuleName,ppModImport) \
+ ( (This)->lpVtbl -> GetModuleByName(This,szModuleName,ppModImport) )
+
+#define IAssemblyManifestImport_GetManifestModulePath(This,szModulePath,pccModulePath) \
+ ( (This)->lpVtbl -> GetManifestModulePath(This,szModulePath,pccModulePath) )
+
+#define IAssemblyManifestImport_GetInternalMDImport(This,ppMDImport) \
+ ( (This)->lpVtbl -> GetInternalMDImport(This,ppMDImport) )
+
+#define IAssemblyManifestImport_LoadDataFromMDImport(This,ppMDImport) \
+ ( (This)->lpVtbl -> LoadDataFromMDImport(This,ppMDImport) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IAssemblyManifestImport_INTERFACE_DEFINED__ */
+
+
+#ifndef __IApplicationContext_INTERFACE_DEFINED__
+#define __IApplicationContext_INTERFACE_DEFINED__
+
+/* interface IApplicationContext */
+/* [unique][uuid][object][local] */
+
+// App context configuration variables
+#define ACTAG_APP_BASE_URL L"APPBASE"
+#define ACTAG_MACHINE_CONFIG L"MACHINE_CONFIG"
+#define ACTAG_APP_PRIVATE_BINPATH L"PRIVATE_BINPATH"
+#define ACTAG_APP_SHARED_BINPATH L"SHARED_BINPATH"
+#define ACTAG_APP_SNAPSHOT_ID L"SNAPSHOT_ID"
+#define ACTAG_APP_CONFIG_FILE L"APP_CONFIG_FILE"
+#define ACTAG_APP_ID L"APPLICATION_ID"
+#define ACTAG_APP_SHADOW_COPY_DIRS L"SHADOW_COPY_DIRS"
+#define ACTAG_APP_DYNAMIC_BASE L"DYNAMIC_BASE"
+#define ACTAG_APP_CACHE_BASE L"CACHE_BASE"
+#define ACTAG_APP_NAME L"APP_NAME"
+#define ACTAG_DEV_PATH L"DEV_PATH"
+#define ACTAG_HOST_CONFIG_FILE L"HOST_CONFIG"
+#define ACTAG_SXS_ACTIVATION_CONTEXT L"SXS"
+#define ACTAG_APP_CFG_LOCAL_FILEPATH L"APP_CFG_LOCAL_FILEPATH"
+#define ACTAG_ZAP_STRING L"ZAP_STRING"
+#define ACTAG_ZAP_CONFIG_FLAGS L"ZAP_CONFIG_FLAGS"
+#define ACTAG_APP_DOMAIN_ID L"APPDOMAIN_ID"
+#define ACTAG_APP_CONFIG_BLOB L"APP_CONFIG_BLOB"
+#define ACTAG_FX_ONLY L"FX_ONLY"
+// App context flag overrides
+#define ACTAG_FORCE_CACHE_INSTALL L"FORCE_CACHE_INSTALL"
+#define ACTAG_RFS_INTEGRITY_CHECK L"RFS_INTEGRITY_CHECK"
+#define ACTAG_RFS_MODULE_CHECK L"RFS_MODULE_CHECK"
+#define ACTAG_BINPATH_PROBE_ONLY L"BINPATH_PROBE_ONLY"
+#define ACTAG_DISALLOW_APPLYPUBLISHERPOLICY L"DISALLOW_APP"
+#define ACTAG_DISALLOW_APP_BINDING_REDIRECTS L"DISALLOW_APP_REDIRECTS"
+#define ACTAG_DISALLOW_APP_BASE_PROBING L"DISALLOW_APP_BASE_PROBING"
+#define ACTAG_CODE_DOWNLOAD_DISABLED L"CODE_DOWNLOAD_DISABLED"
+#define ACTAG_DISABLE_FX_ASM_UNIFICATION L"DISABLE_FX_ASM_UNIFICATION"
+typedef /* [unique] */ IApplicationContext *LPAPPLICATIONCONTEXT;
+
+typedef /* [public] */
+enum __MIDL_IApplicationContext_0001
+ {
+ APP_CTX_FLAGS_INTERFACE = 0x1
+ } APP_FLAGS;
+
+
+EXTERN_C const IID IID_IApplicationContext;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("7c23ff90-33af-11d3-95da-00a024a85b51")
+ IApplicationContext : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE SetContextNameObject(
+ /* [in] */ LPASSEMBLYNAME pName) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetContextNameObject(
+ /* [out] */ LPASSEMBLYNAME *ppName) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Set(
+ /* [in] */ LPCOLESTR szName,
+ /* [in] */ LPVOID pvValue,
+ /* [in] */ DWORD cbValue,
+ /* [in] */ DWORD dwFlags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Get(
+ /* [in] */ LPCOLESTR szName,
+ /* [out] */ LPVOID pvValue,
+ /* [out][in] */ LPDWORD pcbValue,
+ /* [in] */ DWORD dwFlags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetDynamicDirectory(
+ /* [annotation][out] */
+ __out_ecount_opt(*pdwSize) LPWSTR wzDynamicDir,
+ /* [out][in] */ LPDWORD pdwSize) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetAppCacheDirectory(
+ /* [annotation][out] */
+ __out_ecount_opt(*pdwSize) LPWSTR wzAppCacheDir,
+ /* [out][in] */ LPDWORD pdwSize) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE RegisterKnownAssembly(
+ /* [in] */ IAssemblyName *pName,
+ /* [in] */ LPCWSTR pwzAsmURL,
+ /* [out] */ IAssembly **ppAsmOut) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE PrefetchAppConfigFile( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetAssemblyBindingClosure(
+ /* [in] */ IUnknown *pUnk,
+ /* [in] */ LPCWSTR pwzNativeImagePath,
+ /* [out] */ IAssemblyBindingClosure **ppAsmClosure) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IApplicationContextVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IApplicationContext * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IApplicationContext * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IApplicationContext * This);
+
+ HRESULT ( STDMETHODCALLTYPE *SetContextNameObject )(
+ IApplicationContext * This,
+ /* [in] */ LPASSEMBLYNAME pName);
+
+ HRESULT ( STDMETHODCALLTYPE *GetContextNameObject )(
+ IApplicationContext * This,
+ /* [out] */ LPASSEMBLYNAME *ppName);
+
+ HRESULT ( STDMETHODCALLTYPE *Set )(
+ IApplicationContext * This,
+ /* [in] */ LPCOLESTR szName,
+ /* [in] */ LPVOID pvValue,
+ /* [in] */ DWORD cbValue,
+ /* [in] */ DWORD dwFlags);
+
+ HRESULT ( STDMETHODCALLTYPE *Get )(
+ IApplicationContext * This,
+ /* [in] */ LPCOLESTR szName,
+ /* [out] */ LPVOID pvValue,
+ /* [out][in] */ LPDWORD pcbValue,
+ /* [in] */ DWORD dwFlags);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDynamicDirectory )(
+ IApplicationContext * This,
+ /* [annotation][out] */
+ __out_ecount_opt(*pdwSize) LPWSTR wzDynamicDir,
+ /* [out][in] */ LPDWORD pdwSize);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAppCacheDirectory )(
+ IApplicationContext * This,
+ /* [annotation][out] */
+ __out_ecount_opt(*pdwSize) LPWSTR wzAppCacheDir,
+ /* [out][in] */ LPDWORD pdwSize);
+
+ HRESULT ( STDMETHODCALLTYPE *RegisterKnownAssembly )(
+ IApplicationContext * This,
+ /* [in] */ IAssemblyName *pName,
+ /* [in] */ LPCWSTR pwzAsmURL,
+ /* [out] */ IAssembly **ppAsmOut);
+
+ HRESULT ( STDMETHODCALLTYPE *PrefetchAppConfigFile )(
+ IApplicationContext * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAssemblyBindingClosure )(
+ IApplicationContext * This,
+ /* [in] */ IUnknown *pUnk,
+ /* [in] */ LPCWSTR pwzNativeImagePath,
+ /* [out] */ IAssemblyBindingClosure **ppAsmClosure);
+
+ END_INTERFACE
+ } IApplicationContextVtbl;
+
+ interface IApplicationContext
+ {
+ CONST_VTBL struct IApplicationContextVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IApplicationContext_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IApplicationContext_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IApplicationContext_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IApplicationContext_SetContextNameObject(This,pName) \
+ ( (This)->lpVtbl -> SetContextNameObject(This,pName) )
+
+#define IApplicationContext_GetContextNameObject(This,ppName) \
+ ( (This)->lpVtbl -> GetContextNameObject(This,ppName) )
+
+#define IApplicationContext_Set(This,szName,pvValue,cbValue,dwFlags) \
+ ( (This)->lpVtbl -> Set(This,szName,pvValue,cbValue,dwFlags) )
+
+#define IApplicationContext_Get(This,szName,pvValue,pcbValue,dwFlags) \
+ ( (This)->lpVtbl -> Get(This,szName,pvValue,pcbValue,dwFlags) )
+
+#define IApplicationContext_GetDynamicDirectory(This,wzDynamicDir,pdwSize) \
+ ( (This)->lpVtbl -> GetDynamicDirectory(This,wzDynamicDir,pdwSize) )
+
+#define IApplicationContext_GetAppCacheDirectory(This,wzAppCacheDir,pdwSize) \
+ ( (This)->lpVtbl -> GetAppCacheDirectory(This,wzAppCacheDir,pdwSize) )
+
+#define IApplicationContext_RegisterKnownAssembly(This,pName,pwzAsmURL,ppAsmOut) \
+ ( (This)->lpVtbl -> RegisterKnownAssembly(This,pName,pwzAsmURL,ppAsmOut) )
+
+#define IApplicationContext_PrefetchAppConfigFile(This) \
+ ( (This)->lpVtbl -> PrefetchAppConfigFile(This) )
+
+#define IApplicationContext_GetAssemblyBindingClosure(This,pUnk,pwzNativeImagePath,ppAsmClosure) \
+ ( (This)->lpVtbl -> GetAssemblyBindingClosure(This,pUnk,pwzNativeImagePath,ppAsmClosure) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IApplicationContext_INTERFACE_DEFINED__ */
+
+
+#ifndef __IAssemblyNameBinder_INTERFACE_DEFINED__
+#define __IAssemblyNameBinder_INTERFACE_DEFINED__
+
+/* interface IAssemblyNameBinder */
+/* [unique][uuid][object][local] */
+
+
+EXTERN_C const IID IID_IAssemblyNameBinder;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("56972d9d-0f6c-47de-a038-e82d5de3a777")
+ IAssemblyNameBinder : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE BindToObject(
+ /* [in] */ REFIID refIID,
+ /* [in] */ IUnknown *pUnkSink,
+ /* [in] */ IUnknown *pUnkContext,
+ /* [in] */ LPCOLESTR szCodeBase,
+ /* [in] */ LONGLONG llFlags,
+ /* [in] */ LPVOID pParentAssembly,
+ /* [in] */ DWORD cbReserved,
+ /* [out] */ LPVOID *ppv,
+ /* [out] */ LPVOID *ppvNI) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IAssemblyNameBinderVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IAssemblyNameBinder * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IAssemblyNameBinder * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IAssemblyNameBinder * This);
+
+ HRESULT ( STDMETHODCALLTYPE *BindToObject )(
+ IAssemblyNameBinder * This,
+ /* [in] */ REFIID refIID,
+ /* [in] */ IUnknown *pUnkSink,
+ /* [in] */ IUnknown *pUnkContext,
+ /* [in] */ LPCOLESTR szCodeBase,
+ /* [in] */ LONGLONG llFlags,
+ /* [in] */ LPVOID pParentAssembly,
+ /* [in] */ DWORD cbReserved,
+ /* [out] */ LPVOID *ppv,
+ /* [out] */ LPVOID *ppvNI);
+
+ END_INTERFACE
+ } IAssemblyNameBinderVtbl;
+
+ interface IAssemblyNameBinder
+ {
+ CONST_VTBL struct IAssemblyNameBinderVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IAssemblyNameBinder_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IAssemblyNameBinder_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IAssemblyNameBinder_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IAssemblyNameBinder_BindToObject(This,refIID,pUnkSink,pUnkContext,szCodeBase,llFlags,pParentAssembly,cbReserved,ppv,ppvNI) \
+ ( (This)->lpVtbl -> BindToObject(This,refIID,pUnkSink,pUnkContext,szCodeBase,llFlags,pParentAssembly,cbReserved,ppv,ppvNI) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IAssemblyNameBinder_INTERFACE_DEFINED__ */
+
+
+#ifndef __IAssembly_INTERFACE_DEFINED__
+#define __IAssembly_INTERFACE_DEFINED__
+
+/* interface IAssembly */
+/* [unique][uuid][object][local] */
+
+typedef /* [unique] */ IAssembly *LPASSEMBLY;
+
+#define ASMLOC_LOCATION_MASK 0x0000001B
+#define ASMLOC_UNKNOWN 0x00000000
+#define ASMLOC_GAC 0x00000001
+#define ASMLOC_DOWNLOAD_CACHE 0x00000002
+#define ASMLOC_RUN_FROM_SOURCE 0x00000003
+#define ASMLOC_CODEBASE_HINT 0x00000004
+#define ASMLOC_ZAP 0x00000008
+#define ASMLOC_DEV_OVERRIDE 0x00000010
+
+EXTERN_C const IID IID_IAssembly;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("ff08d7d4-04c2-11d3-94aa-00c04fc308ff")
+ IAssembly : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetAssemblyNameDef(
+ /* [out] */ IAssemblyName **ppAssemblyName) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetNextAssemblyNameRef(
+ /* [in] */ DWORD nIndex,
+ /* [out] */ IAssemblyName **ppAssemblyName) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetNextAssemblyModule(
+ /* [in] */ DWORD nIndex,
+ /* [out] */ IAssemblyModuleImport **ppModImport) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetModuleByName(
+ /* [in] */ LPCOLESTR szModuleName,
+ /* [out] */ IAssemblyModuleImport **ppModImport) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetManifestModulePath(
+ /* [annotation][size_is][out] */
+ __out_ecount_full_opt(*pccModulePath) LPOLESTR szModulePath,
+ /* [out][in] */ LPDWORD pccModulePath) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetAssemblyPath(
+ /* [annotation][size_is][out] */
+ __out_ecount_full_opt(*lpcwBuffer) LPOLESTR pStr,
+ /* [out][in] */ LPDWORD lpcwBuffer) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetAssemblyLocation(
+ /* [out] */ DWORD *pdwAsmLocation) = 0;
+
+ virtual LOADCTX_TYPE STDMETHODCALLTYPE GetFusionLoadContext( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetNextHardBoundDependency(
+ /* [in] */ DWORD dwIndex,
+ /* [out] */ IAssembly **ppILAsm,
+ /* [out] */ IAssembly **ppNIAsm) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IAssemblyVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IAssembly * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IAssembly * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IAssembly * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAssemblyNameDef )(
+ IAssembly * This,
+ /* [out] */ IAssemblyName **ppAssemblyName);
+
+ HRESULT ( STDMETHODCALLTYPE *GetNextAssemblyNameRef )(
+ IAssembly * This,
+ /* [in] */ DWORD nIndex,
+ /* [out] */ IAssemblyName **ppAssemblyName);
+
+ HRESULT ( STDMETHODCALLTYPE *GetNextAssemblyModule )(
+ IAssembly * This,
+ /* [in] */ DWORD nIndex,
+ /* [out] */ IAssemblyModuleImport **ppModImport);
+
+ HRESULT ( STDMETHODCALLTYPE *GetModuleByName )(
+ IAssembly * This,
+ /* [in] */ LPCOLESTR szModuleName,
+ /* [out] */ IAssemblyModuleImport **ppModImport);
+
+ HRESULT ( STDMETHODCALLTYPE *GetManifestModulePath )(
+ IAssembly * This,
+ /* [annotation][size_is][out] */
+ __out_ecount_full_opt(*pccModulePath) LPOLESTR szModulePath,
+ /* [out][in] */ LPDWORD pccModulePath);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAssemblyPath )(
+ IAssembly * This,
+ /* [annotation][size_is][out] */
+ __out_ecount_full_opt(*lpcwBuffer) LPOLESTR pStr,
+ /* [out][in] */ LPDWORD lpcwBuffer);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAssemblyLocation )(
+ IAssembly * This,
+ /* [out] */ DWORD *pdwAsmLocation);
+
+ LOADCTX_TYPE ( STDMETHODCALLTYPE *GetFusionLoadContext )(
+ IAssembly * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetNextHardBoundDependency )(
+ IAssembly * This,
+ /* [in] */ DWORD dwIndex,
+ /* [out] */ IAssembly **ppILAsm,
+ /* [out] */ IAssembly **ppNIAsm);
+
+ END_INTERFACE
+ } IAssemblyVtbl;
+
+ interface IAssembly
+ {
+ CONST_VTBL struct IAssemblyVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IAssembly_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IAssembly_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IAssembly_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IAssembly_GetAssemblyNameDef(This,ppAssemblyName) \
+ ( (This)->lpVtbl -> GetAssemblyNameDef(This,ppAssemblyName) )
+
+#define IAssembly_GetNextAssemblyNameRef(This,nIndex,ppAssemblyName) \
+ ( (This)->lpVtbl -> GetNextAssemblyNameRef(This,nIndex,ppAssemblyName) )
+
+#define IAssembly_GetNextAssemblyModule(This,nIndex,ppModImport) \
+ ( (This)->lpVtbl -> GetNextAssemblyModule(This,nIndex,ppModImport) )
+
+#define IAssembly_GetModuleByName(This,szModuleName,ppModImport) \
+ ( (This)->lpVtbl -> GetModuleByName(This,szModuleName,ppModImport) )
+
+#define IAssembly_GetManifestModulePath(This,szModulePath,pccModulePath) \
+ ( (This)->lpVtbl -> GetManifestModulePath(This,szModulePath,pccModulePath) )
+
+#define IAssembly_GetAssemblyPath(This,pStr,lpcwBuffer) \
+ ( (This)->lpVtbl -> GetAssemblyPath(This,pStr,lpcwBuffer) )
+
+#define IAssembly_GetAssemblyLocation(This,pdwAsmLocation) \
+ ( (This)->lpVtbl -> GetAssemblyLocation(This,pdwAsmLocation) )
+
+#define IAssembly_GetFusionLoadContext(This) \
+ ( (This)->lpVtbl -> GetFusionLoadContext(This) )
+
+#define IAssembly_GetNextHardBoundDependency(This,dwIndex,ppILAsm,ppNIAsm) \
+ ( (This)->lpVtbl -> GetNextHardBoundDependency(This,dwIndex,ppILAsm,ppNIAsm) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IAssembly_INTERFACE_DEFINED__ */
+
+
+#ifndef __IAssemblyBindingClosureEnumerator_INTERFACE_DEFINED__
+#define __IAssemblyBindingClosureEnumerator_INTERFACE_DEFINED__
+
+/* interface IAssemblyBindingClosureEnumerator */
+/* [unique][uuid][object][local] */
+
+
+EXTERN_C const IID IID_IAssemblyBindingClosureEnumerator;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("b3f1e4ed-cb09-4b85-9a1b-6809582f1ebc")
+ IAssemblyBindingClosureEnumerator : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetNextAssemblyPath(
+ /* [out] */ LPCOLESTR *ppPath,
+ /* [out] */ LPCOLESTR *ppniPath) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IAssemblyBindingClosureEnumeratorVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IAssemblyBindingClosureEnumerator * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IAssemblyBindingClosureEnumerator * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IAssemblyBindingClosureEnumerator * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetNextAssemblyPath )(
+ IAssemblyBindingClosureEnumerator * This,
+ /* [out] */ LPCOLESTR *ppPath,
+ /* [out] */ LPCOLESTR *ppniPath);
+
+ END_INTERFACE
+ } IAssemblyBindingClosureEnumeratorVtbl;
+
+ interface IAssemblyBindingClosureEnumerator
+ {
+ CONST_VTBL struct IAssemblyBindingClosureEnumeratorVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IAssemblyBindingClosureEnumerator_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IAssemblyBindingClosureEnumerator_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IAssemblyBindingClosureEnumerator_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IAssemblyBindingClosureEnumerator_GetNextAssemblyPath(This,ppPath,ppniPath) \
+ ( (This)->lpVtbl -> GetNextAssemblyPath(This,ppPath,ppniPath) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IAssemblyBindingClosureEnumerator_INTERFACE_DEFINED__ */
+
+
+#ifndef __IAssemblyBindingClosure_INTERFACE_DEFINED__
+#define __IAssemblyBindingClosure_INTERFACE_DEFINED__
+
+/* interface IAssemblyBindingClosure */
+/* [unique][uuid][object][local] */
+
+
+EXTERN_C const IID IID_IAssemblyBindingClosure;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("415c226a-e513-41ba-9651-9c48e97aa5de")
+ IAssemblyBindingClosure : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE IsAllAssembliesInGAC( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE IsEqual(
+ /* [in] */ IAssemblyBindingClosure *pAssemblyClosure) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetNextFailureAssembly(
+ /* [in] */ DWORD dwIndex,
+ /* [out] */ IAssemblyName **ppName,
+ /* [out] */ HRESULT *pHResult) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnsureWalked(
+ /* [in] */ IUnknown *pStartingAssembly,
+ /* [in] */ IApplicationContext *pAppCtx,
+ /* [in] */ WALK_LEVEL level) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnumerateAssemblies(
+ /* [out] */ IAssemblyBindingClosureEnumerator **ppEnumerator) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE HasBeenWalked(
+ /* [in] */ WALK_LEVEL level) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE MayHaveUnknownDependencies( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE AddProfilerAssemblyReference(
+ /* [in] */ LPVOID pbPublicKeyOrToken,
+ /* [in] */ ULONG cbPublicKeyOrToken,
+ /* [in] */ LPCWSTR szName,
+ /* [in] */ LPVOID pMetaData,
+ /* [in] */ void *pbHashValue,
+ /* [in] */ ULONG cbHashValue,
+ /* [in] */ DWORD dwAssemblyRefFlags,
+ /* [in] */ struct AssemblyReferenceClosureWalkContextForProfAPI *pContext) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IAssemblyBindingClosureVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IAssemblyBindingClosure * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IAssemblyBindingClosure * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IAssemblyBindingClosure * This);
+
+ HRESULT ( STDMETHODCALLTYPE *IsAllAssembliesInGAC )(
+ IAssemblyBindingClosure * This);
+
+ HRESULT ( STDMETHODCALLTYPE *IsEqual )(
+ IAssemblyBindingClosure * This,
+ /* [in] */ IAssemblyBindingClosure *pAssemblyClosure);
+
+ HRESULT ( STDMETHODCALLTYPE *GetNextFailureAssembly )(
+ IAssemblyBindingClosure * This,
+ /* [in] */ DWORD dwIndex,
+ /* [out] */ IAssemblyName **ppName,
+ /* [out] */ HRESULT *pHResult);
+
+ HRESULT ( STDMETHODCALLTYPE *EnsureWalked )(
+ IAssemblyBindingClosure * This,
+ /* [in] */ IUnknown *pStartingAssembly,
+ /* [in] */ IApplicationContext *pAppCtx,
+ /* [in] */ WALK_LEVEL level);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumerateAssemblies )(
+ IAssemblyBindingClosure * This,
+ /* [out] */ IAssemblyBindingClosureEnumerator **ppEnumerator);
+
+ HRESULT ( STDMETHODCALLTYPE *HasBeenWalked )(
+ IAssemblyBindingClosure * This,
+ /* [in] */ WALK_LEVEL level);
+
+ HRESULT ( STDMETHODCALLTYPE *MayHaveUnknownDependencies )(
+ IAssemblyBindingClosure * This);
+
+ HRESULT ( STDMETHODCALLTYPE *AddProfilerAssemblyReference )(
+ IAssemblyBindingClosure * This,
+ /* [in] */ LPVOID pbPublicKeyOrToken,
+ /* [in] */ ULONG cbPublicKeyOrToken,
+ /* [in] */ LPCWSTR szName,
+ /* [in] */ LPVOID pMetaData,
+ /* [in] */ void *pbHashValue,
+ /* [in] */ ULONG cbHashValue,
+ /* [in] */ DWORD dwAssemblyRefFlags,
+ /* [in] */ struct AssemblyReferenceClosureWalkContextForProfAPI *pContext);
+
+ END_INTERFACE
+ } IAssemblyBindingClosureVtbl;
+
+ interface IAssemblyBindingClosure
+ {
+ CONST_VTBL struct IAssemblyBindingClosureVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IAssemblyBindingClosure_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IAssemblyBindingClosure_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IAssemblyBindingClosure_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IAssemblyBindingClosure_IsAllAssembliesInGAC(This) \
+ ( (This)->lpVtbl -> IsAllAssembliesInGAC(This) )
+
+#define IAssemblyBindingClosure_IsEqual(This,pAssemblyClosure) \
+ ( (This)->lpVtbl -> IsEqual(This,pAssemblyClosure) )
+
+#define IAssemblyBindingClosure_GetNextFailureAssembly(This,dwIndex,ppName,pHResult) \
+ ( (This)->lpVtbl -> GetNextFailureAssembly(This,dwIndex,ppName,pHResult) )
+
+#define IAssemblyBindingClosure_EnsureWalked(This,pStartingAssembly,pAppCtx,level) \
+ ( (This)->lpVtbl -> EnsureWalked(This,pStartingAssembly,pAppCtx,level) )
+
+#define IAssemblyBindingClosure_EnumerateAssemblies(This,ppEnumerator) \
+ ( (This)->lpVtbl -> EnumerateAssemblies(This,ppEnumerator) )
+
+#define IAssemblyBindingClosure_HasBeenWalked(This,level) \
+ ( (This)->lpVtbl -> HasBeenWalked(This,level) )
+
+#define IAssemblyBindingClosure_MayHaveUnknownDependencies(This) \
+ ( (This)->lpVtbl -> MayHaveUnknownDependencies(This) )
+
+#define IAssemblyBindingClosure_AddProfilerAssemblyReference(This,pbPublicKeyOrToken,cbPublicKeyOrToken,szName,pMetaData,pbHashValue,cbHashValue,dwAssemblyRefFlags,pContext) \
+ ( (This)->lpVtbl -> AddProfilerAssemblyReference(This,pbPublicKeyOrToken,cbPublicKeyOrToken,szName,pMetaData,pbHashValue,cbHashValue,dwAssemblyRefFlags,pContext) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IAssemblyBindingClosure_INTERFACE_DEFINED__ */
+
+
+#ifndef __IAssemblyBindSink_INTERFACE_DEFINED__
+#define __IAssemblyBindSink_INTERFACE_DEFINED__
+
+/* interface IAssemblyBindSink */
+/* [unique][uuid][object][local] */
+
+typedef /* [unique] */ IAssemblyBindSink *LPASSEMBLY_BIND_SINK;
+
+typedef struct _tagFusionBindInfo
+ {
+ IFusionBindLog *pdbglog;
+ IAssemblyName *pNamePolicy;
+ DWORD dwPoliciesApplied;
+ } FusionBindInfo;
+
+typedef /* [public] */
+enum __MIDL_IAssemblyBindSink_0001
+ {
+ ASM_NOTIFICATION_START = 0,
+ ASM_NOTIFICATION_PROGRESS = ( ASM_NOTIFICATION_START + 1 ) ,
+ ASM_NOTIFICATION_SUSPEND = ( ASM_NOTIFICATION_PROGRESS + 1 ) ,
+ ASM_NOTIFICATION_ATTEMPT_NEXT_CODEBASE = ( ASM_NOTIFICATION_SUSPEND + 1 ) ,
+ ASM_NOTIFICATION_BIND_INFO = ( ASM_NOTIFICATION_ATTEMPT_NEXT_CODEBASE + 1 ) ,
+ ASM_NOTIFICATION_DONE = ( ASM_NOTIFICATION_BIND_INFO + 1 ) ,
+ ASM_NOTIFICATION_NATIVE_IMAGE_DONE = ( ASM_NOTIFICATION_DONE + 1 )
+ } ASM_NOTIFICATION;
+
+
+EXTERN_C const IID IID_IAssemblyBindSink;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("af0bc960-0b9a-11d3-95ca-00a024a85b51")
+ IAssemblyBindSink : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE OnProgress(
+ /* [in] */ DWORD dwNotification,
+ /* [in] */ HRESULT hrNotification,
+ /* [in] */ LPCWSTR szNotification,
+ /* [in] */ DWORD dwProgress,
+ /* [in] */ DWORD dwProgressMax,
+ /* [in] */ LPVOID pvBindInfo,
+ /* [in] */ IUnknown *pUnk) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IAssemblyBindSinkVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IAssemblyBindSink * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IAssemblyBindSink * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IAssemblyBindSink * This);
+
+ HRESULT ( STDMETHODCALLTYPE *OnProgress )(
+ IAssemblyBindSink * This,
+ /* [in] */ DWORD dwNotification,
+ /* [in] */ HRESULT hrNotification,
+ /* [in] */ LPCWSTR szNotification,
+ /* [in] */ DWORD dwProgress,
+ /* [in] */ DWORD dwProgressMax,
+ /* [in] */ LPVOID pvBindInfo,
+ /* [in] */ IUnknown *pUnk);
+
+ END_INTERFACE
+ } IAssemblyBindSinkVtbl;
+
+ interface IAssemblyBindSink
+ {
+ CONST_VTBL struct IAssemblyBindSinkVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IAssemblyBindSink_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IAssemblyBindSink_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IAssemblyBindSink_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IAssemblyBindSink_OnProgress(This,dwNotification,hrNotification,szNotification,dwProgress,dwProgressMax,pvBindInfo,pUnk) \
+ ( (This)->lpVtbl -> OnProgress(This,dwNotification,hrNotification,szNotification,dwProgress,dwProgressMax,pvBindInfo,pUnk) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IAssemblyBindSink_INTERFACE_DEFINED__ */
+
+
+#ifndef __IAssemblyBinding_INTERFACE_DEFINED__
+#define __IAssemblyBinding_INTERFACE_DEFINED__
+
+/* interface IAssemblyBinding */
+/* [unique][uuid][object][local] */
+
+typedef /* [unique] */ IAssemblyBinding *LPASSEMBLY_BINDINDING;
+
+
+EXTERN_C const IID IID_IAssemblyBinding;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("cfe52a80-12bd-11d3-95ca-00a024a85b51")
+ IAssemblyBinding : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE Control(
+ /* [in] */ HRESULT hrControl) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE DoDefaultUI(
+ /* [in] */ HWND hWnd,
+ /* [in] */ DWORD dwFlags) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IAssemblyBindingVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IAssemblyBinding * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IAssemblyBinding * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IAssemblyBinding * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Control )(
+ IAssemblyBinding * This,
+ /* [in] */ HRESULT hrControl);
+
+ HRESULT ( STDMETHODCALLTYPE *DoDefaultUI )(
+ IAssemblyBinding * This,
+ /* [in] */ HWND hWnd,
+ /* [in] */ DWORD dwFlags);
+
+ END_INTERFACE
+ } IAssemblyBindingVtbl;
+
+ interface IAssemblyBinding
+ {
+ CONST_VTBL struct IAssemblyBindingVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IAssemblyBinding_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IAssemblyBinding_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IAssemblyBinding_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IAssemblyBinding_Control(This,hrControl) \
+ ( (This)->lpVtbl -> Control(This,hrControl) )
+
+#define IAssemblyBinding_DoDefaultUI(This,hWnd,dwFlags) \
+ ( (This)->lpVtbl -> DoDefaultUI(This,hWnd,dwFlags) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IAssemblyBinding_INTERFACE_DEFINED__ */
+
+
+#ifndef __IAssemblyModuleImport_INTERFACE_DEFINED__
+#define __IAssemblyModuleImport_INTERFACE_DEFINED__
+
+/* interface IAssemblyModuleImport */
+/* [unique][uuid][object][local] */
+
+typedef /* [unique] */ IAssemblyModuleImport *LPASSEMBLY_MODULE_IMPORT;
+
+
+EXTERN_C const IID IID_IAssemblyModuleImport;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("da0cd4b0-1117-11d3-95ca-00a024a85b51")
+ IAssemblyModuleImport : public IStream
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetModuleName(
+ /* [annotation][size_is][out] */
+ __out_ecount_full_opt(*pccModuleName) LPOLESTR szModuleName,
+ /* [out][in] */ LPDWORD pccModuleName) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetHashAlgId(
+ /* [out] */ LPDWORD pdwHashAlgId) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetHashValue(
+ /* [size_is][out] */ BYTE *pbHashValue,
+ /* [out][in] */ LPDWORD pcbHashValue) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetFlags(
+ /* [out] */ LPDWORD pdwFlags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetModulePath(
+ /* [annotation][size_is][out] */
+ __out_ecount_full_opt(*pccModulePath) LPOLESTR szModulePath,
+ /* [out][in] */ LPDWORD pccModulePath) = 0;
+
+ virtual BOOL STDMETHODCALLTYPE IsAvailable( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE BindToObject(
+ /* [in] */ IAssemblyBindSink *pBindSink,
+ /* [in] */ IApplicationContext *pAppCtx,
+ /* [in] */ LONGLONG llFlags,
+ /* [out] */ LPVOID *ppv) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IAssemblyModuleImportVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IAssemblyModuleImport * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IAssemblyModuleImport * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IAssemblyModuleImport * This);
+
+ /* [local] */ HRESULT ( STDMETHODCALLTYPE *Read )(
+ IAssemblyModuleImport * This,
+ /* [annotation] */
+ _Out_writes_bytes_to_(cb, *pcbRead) void *pv,
+ /* [annotation][in] */
+ _In_ ULONG cb,
+ /* [annotation] */
+ _Out_opt_ ULONG *pcbRead);
+
+ /* [local] */ HRESULT ( STDMETHODCALLTYPE *Write )(
+ IAssemblyModuleImport * This,
+ /* [annotation] */
+ _In_reads_bytes_(cb) const void *pv,
+ /* [annotation][in] */
+ _In_ ULONG cb,
+ /* [annotation] */
+ _Out_opt_ ULONG *pcbWritten);
+
+ /* [local] */ HRESULT ( STDMETHODCALLTYPE *Seek )(
+ IAssemblyModuleImport * This,
+ /* [in] */ LARGE_INTEGER dlibMove,
+ /* [in] */ DWORD dwOrigin,
+ /* [annotation] */
+ _Out_opt_ ULARGE_INTEGER *plibNewPosition);
+
+ HRESULT ( STDMETHODCALLTYPE *SetSize )(
+ IAssemblyModuleImport * This,
+ /* [in] */ ULARGE_INTEGER libNewSize);
+
+ /* [local] */ HRESULT ( STDMETHODCALLTYPE *CopyTo )(
+ IAssemblyModuleImport * This,
+ /* [annotation][unique][in] */
+ _In_ IStream *pstm,
+ /* [in] */ ULARGE_INTEGER cb,
+ /* [annotation] */
+ _Out_opt_ ULARGE_INTEGER *pcbRead,
+ /* [annotation] */
+ _Out_opt_ ULARGE_INTEGER *pcbWritten);
+
+ HRESULT ( STDMETHODCALLTYPE *Commit )(
+ IAssemblyModuleImport * This,
+ /* [in] */ DWORD grfCommitFlags);
+
+ HRESULT ( STDMETHODCALLTYPE *Revert )(
+ IAssemblyModuleImport * This);
+
+ HRESULT ( STDMETHODCALLTYPE *LockRegion )(
+ IAssemblyModuleImport * This,
+ /* [in] */ ULARGE_INTEGER libOffset,
+ /* [in] */ ULARGE_INTEGER cb,
+ /* [in] */ DWORD dwLockType);
+
+ HRESULT ( STDMETHODCALLTYPE *UnlockRegion )(
+ IAssemblyModuleImport * This,
+ /* [in] */ ULARGE_INTEGER libOffset,
+ /* [in] */ ULARGE_INTEGER cb,
+ /* [in] */ DWORD dwLockType);
+
+ HRESULT ( STDMETHODCALLTYPE *Stat )(
+ IAssemblyModuleImport * This,
+ /* [out] */ STATSTG *pstatstg,
+ /* [in] */ DWORD grfStatFlag);
+
+ HRESULT ( STDMETHODCALLTYPE *Clone )(
+ IAssemblyModuleImport * This,
+ /* [out] */ IStream **ppstm);
+
+ HRESULT ( STDMETHODCALLTYPE *GetModuleName )(
+ IAssemblyModuleImport * This,
+ /* [annotation][size_is][out] */
+ __out_ecount_full_opt(*pccModuleName) LPOLESTR szModuleName,
+ /* [out][in] */ LPDWORD pccModuleName);
+
+ HRESULT ( STDMETHODCALLTYPE *GetHashAlgId )(
+ IAssemblyModuleImport * This,
+ /* [out] */ LPDWORD pdwHashAlgId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetHashValue )(
+ IAssemblyModuleImport * This,
+ /* [size_is][out] */ BYTE *pbHashValue,
+ /* [out][in] */ LPDWORD pcbHashValue);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFlags )(
+ IAssemblyModuleImport * This,
+ /* [out] */ LPDWORD pdwFlags);
+
+ HRESULT ( STDMETHODCALLTYPE *GetModulePath )(
+ IAssemblyModuleImport * This,
+ /* [annotation][size_is][out] */
+ __out_ecount_full_opt(*pccModulePath) LPOLESTR szModulePath,
+ /* [out][in] */ LPDWORD pccModulePath);
+
+ BOOL ( STDMETHODCALLTYPE *IsAvailable )(
+ IAssemblyModuleImport * This);
+
+ HRESULT ( STDMETHODCALLTYPE *BindToObject )(
+ IAssemblyModuleImport * This,
+ /* [in] */ IAssemblyBindSink *pBindSink,
+ /* [in] */ IApplicationContext *pAppCtx,
+ /* [in] */ LONGLONG llFlags,
+ /* [out] */ LPVOID *ppv);
+
+ END_INTERFACE
+ } IAssemblyModuleImportVtbl;
+
+ interface IAssemblyModuleImport
+ {
+ CONST_VTBL struct IAssemblyModuleImportVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IAssemblyModuleImport_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IAssemblyModuleImport_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IAssemblyModuleImport_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IAssemblyModuleImport_Read(This,pv,cb,pcbRead) \
+ ( (This)->lpVtbl -> Read(This,pv,cb,pcbRead) )
+
+#define IAssemblyModuleImport_Write(This,pv,cb,pcbWritten) \
+ ( (This)->lpVtbl -> Write(This,pv,cb,pcbWritten) )
+
+
+#define IAssemblyModuleImport_Seek(This,dlibMove,dwOrigin,plibNewPosition) \
+ ( (This)->lpVtbl -> Seek(This,dlibMove,dwOrigin,plibNewPosition) )
+
+#define IAssemblyModuleImport_SetSize(This,libNewSize) \
+ ( (This)->lpVtbl -> SetSize(This,libNewSize) )
+
+#define IAssemblyModuleImport_CopyTo(This,pstm,cb,pcbRead,pcbWritten) \
+ ( (This)->lpVtbl -> CopyTo(This,pstm,cb,pcbRead,pcbWritten) )
+
+#define IAssemblyModuleImport_Commit(This,grfCommitFlags) \
+ ( (This)->lpVtbl -> Commit(This,grfCommitFlags) )
+
+#define IAssemblyModuleImport_Revert(This) \
+ ( (This)->lpVtbl -> Revert(This) )
+
+#define IAssemblyModuleImport_LockRegion(This,libOffset,cb,dwLockType) \
+ ( (This)->lpVtbl -> LockRegion(This,libOffset,cb,dwLockType) )
+
+#define IAssemblyModuleImport_UnlockRegion(This,libOffset,cb,dwLockType) \
+ ( (This)->lpVtbl -> UnlockRegion(This,libOffset,cb,dwLockType) )
+
+#define IAssemblyModuleImport_Stat(This,pstatstg,grfStatFlag) \
+ ( (This)->lpVtbl -> Stat(This,pstatstg,grfStatFlag) )
+
+#define IAssemblyModuleImport_Clone(This,ppstm) \
+ ( (This)->lpVtbl -> Clone(This,ppstm) )
+
+
+#define IAssemblyModuleImport_GetModuleName(This,szModuleName,pccModuleName) \
+ ( (This)->lpVtbl -> GetModuleName(This,szModuleName,pccModuleName) )
+
+#define IAssemblyModuleImport_GetHashAlgId(This,pdwHashAlgId) \
+ ( (This)->lpVtbl -> GetHashAlgId(This,pdwHashAlgId) )
+
+#define IAssemblyModuleImport_GetHashValue(This,pbHashValue,pcbHashValue) \
+ ( (This)->lpVtbl -> GetHashValue(This,pbHashValue,pcbHashValue) )
+
+#define IAssemblyModuleImport_GetFlags(This,pdwFlags) \
+ ( (This)->lpVtbl -> GetFlags(This,pdwFlags) )
+
+#define IAssemblyModuleImport_GetModulePath(This,szModulePath,pccModulePath) \
+ ( (This)->lpVtbl -> GetModulePath(This,szModulePath,pccModulePath) )
+
+#define IAssemblyModuleImport_IsAvailable(This) \
+ ( (This)->lpVtbl -> IsAvailable(This) )
+
+#define IAssemblyModuleImport_BindToObject(This,pBindSink,pAppCtx,llFlags,ppv) \
+ ( (This)->lpVtbl -> BindToObject(This,pBindSink,pAppCtx,llFlags,ppv) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IAssemblyModuleImport_INTERFACE_DEFINED__ */
+
+
+#ifndef __IAssemblyScavenger_INTERFACE_DEFINED__
+#define __IAssemblyScavenger_INTERFACE_DEFINED__
+
+/* interface IAssemblyScavenger */
+/* [unique][uuid][object][local] */
+
+
+EXTERN_C const IID IID_IAssemblyScavenger;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("21b8916c-f28e-11d2-a473-00ccff8ef448")
+ IAssemblyScavenger : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE ScavengeAssemblyCache( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetCacheDiskQuotas(
+ /* [out] */ DWORD *pdwZapQuotaInGAC,
+ /* [out] */ DWORD *pdwDownloadQuotaAdmin,
+ /* [out] */ DWORD *pdwDownloadQuotaUser) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetCacheDiskQuotas(
+ /* [in] */ DWORD dwZapQuotaInGAC,
+ /* [in] */ DWORD dwDownloadQuotaAdmin,
+ /* [in] */ DWORD dwDownloadQuotaUser) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetCurrentCacheUsage(
+ /* [out] */ DWORD *dwZapUsage,
+ /* [out] */ DWORD *dwDownloadUsage) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IAssemblyScavengerVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IAssemblyScavenger * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IAssemblyScavenger * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IAssemblyScavenger * This);
+
+ HRESULT ( STDMETHODCALLTYPE *ScavengeAssemblyCache )(
+ IAssemblyScavenger * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCacheDiskQuotas )(
+ IAssemblyScavenger * This,
+ /* [out] */ DWORD *pdwZapQuotaInGAC,
+ /* [out] */ DWORD *pdwDownloadQuotaAdmin,
+ /* [out] */ DWORD *pdwDownloadQuotaUser);
+
+ HRESULT ( STDMETHODCALLTYPE *SetCacheDiskQuotas )(
+ IAssemblyScavenger * This,
+ /* [in] */ DWORD dwZapQuotaInGAC,
+ /* [in] */ DWORD dwDownloadQuotaAdmin,
+ /* [in] */ DWORD dwDownloadQuotaUser);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCurrentCacheUsage )(
+ IAssemblyScavenger * This,
+ /* [out] */ DWORD *dwZapUsage,
+ /* [out] */ DWORD *dwDownloadUsage);
+
+ END_INTERFACE
+ } IAssemblyScavengerVtbl;
+
+ interface IAssemblyScavenger
+ {
+ CONST_VTBL struct IAssemblyScavengerVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IAssemblyScavenger_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IAssemblyScavenger_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IAssemblyScavenger_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IAssemblyScavenger_ScavengeAssemblyCache(This) \
+ ( (This)->lpVtbl -> ScavengeAssemblyCache(This) )
+
+#define IAssemblyScavenger_GetCacheDiskQuotas(This,pdwZapQuotaInGAC,pdwDownloadQuotaAdmin,pdwDownloadQuotaUser) \
+ ( (This)->lpVtbl -> GetCacheDiskQuotas(This,pdwZapQuotaInGAC,pdwDownloadQuotaAdmin,pdwDownloadQuotaUser) )
+
+#define IAssemblyScavenger_SetCacheDiskQuotas(This,dwZapQuotaInGAC,dwDownloadQuotaAdmin,dwDownloadQuotaUser) \
+ ( (This)->lpVtbl -> SetCacheDiskQuotas(This,dwZapQuotaInGAC,dwDownloadQuotaAdmin,dwDownloadQuotaUser) )
+
+#define IAssemblyScavenger_GetCurrentCacheUsage(This,dwZapUsage,dwDownloadUsage) \
+ ( (This)->lpVtbl -> GetCurrentCacheUsage(This,dwZapUsage,dwDownloadUsage) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IAssemblyScavenger_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICodebaseList_INTERFACE_DEFINED__
+#define __ICodebaseList_INTERFACE_DEFINED__
+
+/* interface ICodebaseList */
+/* [unique][uuid][object][local] */
+
+
+EXTERN_C const IID IID_ICodebaseList;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("D8FB9BD6-3969-11d3-B4AF-00C04F8ECB26")
+ ICodebaseList : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE AddCodebase(
+ /* [in] */ LPCWSTR wzCodebase,
+ /* [in] */ DWORD dwFlags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE RemoveCodebase(
+ /* [in] */ DWORD dwIndex) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE RemoveAll( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetCount(
+ /* [out] */ DWORD *pdwCount) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetCodebase(
+ /* [in] */ DWORD dwIndex,
+ /* [out] */ DWORD *pdwFlags,
+ /* [annotation][out] */
+ __out_ecount_opt(*pcbCodebase) LPWSTR wzCodebase,
+ /* [out][in] */ DWORD *pcbCodebase) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICodebaseListVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICodebaseList * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICodebaseList * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICodebaseList * This);
+
+ HRESULT ( STDMETHODCALLTYPE *AddCodebase )(
+ ICodebaseList * This,
+ /* [in] */ LPCWSTR wzCodebase,
+ /* [in] */ DWORD dwFlags);
+
+ HRESULT ( STDMETHODCALLTYPE *RemoveCodebase )(
+ ICodebaseList * This,
+ /* [in] */ DWORD dwIndex);
+
+ HRESULT ( STDMETHODCALLTYPE *RemoveAll )(
+ ICodebaseList * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCount )(
+ ICodebaseList * This,
+ /* [out] */ DWORD *pdwCount);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCodebase )(
+ ICodebaseList * This,
+ /* [in] */ DWORD dwIndex,
+ /* [out] */ DWORD *pdwFlags,
+ /* [annotation][out] */
+ __out_ecount_opt(*pcbCodebase) LPWSTR wzCodebase,
+ /* [out][in] */ DWORD *pcbCodebase);
+
+ END_INTERFACE
+ } ICodebaseListVtbl;
+
+ interface ICodebaseList
+ {
+ CONST_VTBL struct ICodebaseListVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICodebaseList_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICodebaseList_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICodebaseList_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICodebaseList_AddCodebase(This,wzCodebase,dwFlags) \
+ ( (This)->lpVtbl -> AddCodebase(This,wzCodebase,dwFlags) )
+
+#define ICodebaseList_RemoveCodebase(This,dwIndex) \
+ ( (This)->lpVtbl -> RemoveCodebase(This,dwIndex) )
+
+#define ICodebaseList_RemoveAll(This) \
+ ( (This)->lpVtbl -> RemoveAll(This) )
+
+#define ICodebaseList_GetCount(This,pdwCount) \
+ ( (This)->lpVtbl -> GetCount(This,pdwCount) )
+
+#define ICodebaseList_GetCodebase(This,dwIndex,pdwFlags,wzCodebase,pcbCodebase) \
+ ( (This)->lpVtbl -> GetCodebase(This,dwIndex,pdwFlags,wzCodebase,pcbCodebase) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICodebaseList_INTERFACE_DEFINED__ */
+
+
+#ifndef __IDownloadMgr_INTERFACE_DEFINED__
+#define __IDownloadMgr_INTERFACE_DEFINED__
+
+/* interface IDownloadMgr */
+/* [unique][uuid][object][local] */
+
+
+EXTERN_C const IID IID_IDownloadMgr;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("0A6F16F8-ACD7-11d3-B4ED-00C04F8ECB26")
+ IDownloadMgr : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE PreDownloadCheck(
+ /* [out] */ void **ppv,
+ /* [out] */ void **ppvNI) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE DoSetup(
+ /* [in] */ LPCWSTR wzSourceUrl,
+ /* [in] */ LPCWSTR wzFilePath,
+ /* [in] */ const FILETIME *pftLastMod,
+ /* [out] */ IUnknown **ppUnk,
+ /* [out] */ IUnknown **ppAsmNI) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ProbeFailed(
+ /* [out] */ IUnknown **ppUnk) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE IsDuplicate(
+ /* [out] */ IDownloadMgr *ppDLMgr) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE LogResult( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE DownloadEnabled(
+ /* [out] */ BOOL *pbEnabled) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetBindInfo(
+ /* [out] */ FusionBindInfo *pBindInfo) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE CacheBindingResult(
+ /* [in] */ HRESULT hrResult) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IDownloadMgrVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IDownloadMgr * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IDownloadMgr * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IDownloadMgr * This);
+
+ HRESULT ( STDMETHODCALLTYPE *PreDownloadCheck )(
+ IDownloadMgr * This,
+ /* [out] */ void **ppv,
+ /* [out] */ void **ppvNI);
+
+ HRESULT ( STDMETHODCALLTYPE *DoSetup )(
+ IDownloadMgr * This,
+ /* [in] */ LPCWSTR wzSourceUrl,
+ /* [in] */ LPCWSTR wzFilePath,
+ /* [in] */ const FILETIME *pftLastMod,
+ /* [out] */ IUnknown **ppUnk,
+ /* [out] */ IUnknown **ppAsmNI);
+
+ HRESULT ( STDMETHODCALLTYPE *ProbeFailed )(
+ IDownloadMgr * This,
+ /* [out] */ IUnknown **ppUnk);
+
+ HRESULT ( STDMETHODCALLTYPE *IsDuplicate )(
+ IDownloadMgr * This,
+ /* [out] */ IDownloadMgr *ppDLMgr);
+
+ HRESULT ( STDMETHODCALLTYPE *LogResult )(
+ IDownloadMgr * This);
+
+ HRESULT ( STDMETHODCALLTYPE *DownloadEnabled )(
+ IDownloadMgr * This,
+ /* [out] */ BOOL *pbEnabled);
+
+ HRESULT ( STDMETHODCALLTYPE *GetBindInfo )(
+ IDownloadMgr * This,
+ /* [out] */ FusionBindInfo *pBindInfo);
+
+ HRESULT ( STDMETHODCALLTYPE *CacheBindingResult )(
+ IDownloadMgr * This,
+ /* [in] */ HRESULT hrResult);
+
+ END_INTERFACE
+ } IDownloadMgrVtbl;
+
+ interface IDownloadMgr
+ {
+ CONST_VTBL struct IDownloadMgrVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IDownloadMgr_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IDownloadMgr_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IDownloadMgr_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IDownloadMgr_PreDownloadCheck(This,ppv,ppvNI) \
+ ( (This)->lpVtbl -> PreDownloadCheck(This,ppv,ppvNI) )
+
+#define IDownloadMgr_DoSetup(This,wzSourceUrl,wzFilePath,pftLastMod,ppUnk,ppAsmNI) \
+ ( (This)->lpVtbl -> DoSetup(This,wzSourceUrl,wzFilePath,pftLastMod,ppUnk,ppAsmNI) )
+
+#define IDownloadMgr_ProbeFailed(This,ppUnk) \
+ ( (This)->lpVtbl -> ProbeFailed(This,ppUnk) )
+
+#define IDownloadMgr_IsDuplicate(This,ppDLMgr) \
+ ( (This)->lpVtbl -> IsDuplicate(This,ppDLMgr) )
+
+#define IDownloadMgr_LogResult(This) \
+ ( (This)->lpVtbl -> LogResult(This) )
+
+#define IDownloadMgr_DownloadEnabled(This,pbEnabled) \
+ ( (This)->lpVtbl -> DownloadEnabled(This,pbEnabled) )
+
+#define IDownloadMgr_GetBindInfo(This,pBindInfo) \
+ ( (This)->lpVtbl -> GetBindInfo(This,pBindInfo) )
+
+#define IDownloadMgr_CacheBindingResult(This,hrResult) \
+ ( (This)->lpVtbl -> CacheBindingResult(This,hrResult) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IDownloadMgr_INTERFACE_DEFINED__ */
+
+
+#ifndef __IHostAssembly_INTERFACE_DEFINED__
+#define __IHostAssembly_INTERFACE_DEFINED__
+
+/* interface IHostAssembly */
+/* [unique][uuid][object][local] */
+
+typedef /* [unique] */ IHostAssembly *LPHOSTASSEMBLY;
+
+
+EXTERN_C const IID IID_IHostAssembly;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("711f7c2d-8234-4505-b02f-7554f46cbf29")
+ IHostAssembly : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetAssemblyNameDef(
+ /* [out] */ IAssemblyName **ppAssemblyName) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetNextAssemblyNameRef(
+ /* [in] */ DWORD nIndex,
+ /* [out] */ IAssemblyName **ppAssemblyName) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetNextAssemblyModule(
+ /* [in] */ DWORD nIndex,
+ /* [out] */ IHostAssemblyModuleImport **ppModImport) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetModuleByName(
+ /* [in] */ LPCOLESTR szModuleName,
+ /* [out] */ IHostAssemblyModuleImport **ppModImport) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetAssemblyStream(
+ /* [out] */ IStream **ppStreamAsm) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetAssemblyId(
+ /* [out] */ UINT64 *pAssemblyId) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetAssemblyDebugStream(
+ /* [out] */ IStream **ppDebugStream) = 0;
+
+ virtual LOADCTX_TYPE STDMETHODCALLTYPE GetFusionLoadContext( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetAssemblyContext(
+ /* [out] */ UINT64 *pdwAssemblyContext) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IHostAssemblyVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IHostAssembly * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IHostAssembly * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IHostAssembly * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAssemblyNameDef )(
+ IHostAssembly * This,
+ /* [out] */ IAssemblyName **ppAssemblyName);
+
+ HRESULT ( STDMETHODCALLTYPE *GetNextAssemblyNameRef )(
+ IHostAssembly * This,
+ /* [in] */ DWORD nIndex,
+ /* [out] */ IAssemblyName **ppAssemblyName);
+
+ HRESULT ( STDMETHODCALLTYPE *GetNextAssemblyModule )(
+ IHostAssembly * This,
+ /* [in] */ DWORD nIndex,
+ /* [out] */ IHostAssemblyModuleImport **ppModImport);
+
+ HRESULT ( STDMETHODCALLTYPE *GetModuleByName )(
+ IHostAssembly * This,
+ /* [in] */ LPCOLESTR szModuleName,
+ /* [out] */ IHostAssemblyModuleImport **ppModImport);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAssemblyStream )(
+ IHostAssembly * This,
+ /* [out] */ IStream **ppStreamAsm);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAssemblyId )(
+ IHostAssembly * This,
+ /* [out] */ UINT64 *pAssemblyId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAssemblyDebugStream )(
+ IHostAssembly * This,
+ /* [out] */ IStream **ppDebugStream);
+
+ LOADCTX_TYPE ( STDMETHODCALLTYPE *GetFusionLoadContext )(
+ IHostAssembly * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAssemblyContext )(
+ IHostAssembly * This,
+ /* [out] */ UINT64 *pdwAssemblyContext);
+
+ END_INTERFACE
+ } IHostAssemblyVtbl;
+
+ interface IHostAssembly
+ {
+ CONST_VTBL struct IHostAssemblyVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IHostAssembly_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IHostAssembly_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IHostAssembly_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IHostAssembly_GetAssemblyNameDef(This,ppAssemblyName) \
+ ( (This)->lpVtbl -> GetAssemblyNameDef(This,ppAssemblyName) )
+
+#define IHostAssembly_GetNextAssemblyNameRef(This,nIndex,ppAssemblyName) \
+ ( (This)->lpVtbl -> GetNextAssemblyNameRef(This,nIndex,ppAssemblyName) )
+
+#define IHostAssembly_GetNextAssemblyModule(This,nIndex,ppModImport) \
+ ( (This)->lpVtbl -> GetNextAssemblyModule(This,nIndex,ppModImport) )
+
+#define IHostAssembly_GetModuleByName(This,szModuleName,ppModImport) \
+ ( (This)->lpVtbl -> GetModuleByName(This,szModuleName,ppModImport) )
+
+#define IHostAssembly_GetAssemblyStream(This,ppStreamAsm) \
+ ( (This)->lpVtbl -> GetAssemblyStream(This,ppStreamAsm) )
+
+#define IHostAssembly_GetAssemblyId(This,pAssemblyId) \
+ ( (This)->lpVtbl -> GetAssemblyId(This,pAssemblyId) )
+
+#define IHostAssembly_GetAssemblyDebugStream(This,ppDebugStream) \
+ ( (This)->lpVtbl -> GetAssemblyDebugStream(This,ppDebugStream) )
+
+#define IHostAssembly_GetFusionLoadContext(This) \
+ ( (This)->lpVtbl -> GetFusionLoadContext(This) )
+
+#define IHostAssembly_GetAssemblyContext(This,pdwAssemblyContext) \
+ ( (This)->lpVtbl -> GetAssemblyContext(This,pdwAssemblyContext) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IHostAssembly_INTERFACE_DEFINED__ */
+
+
+#ifndef __IHostAssemblyModuleImport_INTERFACE_DEFINED__
+#define __IHostAssemblyModuleImport_INTERFACE_DEFINED__
+
+/* interface IHostAssemblyModuleImport */
+/* [unique][uuid][object][local] */
+
+typedef /* [unique] */ IHostAssemblyModuleImport *LPHOSTASSEMBLY_MODULE_IMPORT;
+
+
+EXTERN_C const IID IID_IHostAssemblyModuleImport;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("b6f2729d-6c0f-4944-b692-e5a2ce2c6e7a")
+ IHostAssemblyModuleImport : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetModuleName(
+ /* [annotation][size_is][out] */
+ __out_ecount_full(*pccModuleName) LPOLESTR szModuleName,
+ /* [out][in] */ LPDWORD pccModuleName) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetModuleStream(
+ /* [out] */ IStream **ppStreamModule) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetModuleId(
+ /* [out] */ DWORD *pdwModuleId) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetModuleDebugStream(
+ /* [out] */ IStream **ppDebugStream) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IHostAssemblyModuleImportVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IHostAssemblyModuleImport * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IHostAssemblyModuleImport * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IHostAssemblyModuleImport * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetModuleName )(
+ IHostAssemblyModuleImport * This,
+ /* [annotation][size_is][out] */
+ __out_ecount_full(*pccModuleName) LPOLESTR szModuleName,
+ /* [out][in] */ LPDWORD pccModuleName);
+
+ HRESULT ( STDMETHODCALLTYPE *GetModuleStream )(
+ IHostAssemblyModuleImport * This,
+ /* [out] */ IStream **ppStreamModule);
+
+ HRESULT ( STDMETHODCALLTYPE *GetModuleId )(
+ IHostAssemblyModuleImport * This,
+ /* [out] */ DWORD *pdwModuleId);
+
+ HRESULT ( STDMETHODCALLTYPE *GetModuleDebugStream )(
+ IHostAssemblyModuleImport * This,
+ /* [out] */ IStream **ppDebugStream);
+
+ END_INTERFACE
+ } IHostAssemblyModuleImportVtbl;
+
+ interface IHostAssemblyModuleImport
+ {
+ CONST_VTBL struct IHostAssemblyModuleImportVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IHostAssemblyModuleImport_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IHostAssemblyModuleImport_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IHostAssemblyModuleImport_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IHostAssemblyModuleImport_GetModuleName(This,szModuleName,pccModuleName) \
+ ( (This)->lpVtbl -> GetModuleName(This,szModuleName,pccModuleName) )
+
+#define IHostAssemblyModuleImport_GetModuleStream(This,ppStreamModule) \
+ ( (This)->lpVtbl -> GetModuleStream(This,ppStreamModule) )
+
+#define IHostAssemblyModuleImport_GetModuleId(This,pdwModuleId) \
+ ( (This)->lpVtbl -> GetModuleId(This,pdwModuleId) )
+
+#define IHostAssemblyModuleImport_GetModuleDebugStream(This,ppDebugStream) \
+ ( (This)->lpVtbl -> GetModuleDebugStream(This,ppDebugStream) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IHostAssemblyModuleImport_INTERFACE_DEFINED__ */
+
+
+/* interface __MIDL_itf_fusionpriv_0000_0017 */
+/* [local] */
+
+STDAPI CreateHistoryReader(LPCWSTR wzFilePath, IHistoryReader **ppHistReader);
+STDAPI LookupHistoryAssembly(LPCWSTR pwzFilePath, FILETIME *pftActivationDate, LPCWSTR pwzAsmName, LPCWSTR pwzPublicKeyToken, LPCWSTR wzCulture, LPCWSTR pwzVerRef, IHistoryAssembly **pHistAsm);
+STDAPI GetHistoryFileDirectory(__out_ecount_opt(*pdwSize) LPWSTR wzDir, DWORD *pdwSize);
+STDAPI PreBindAssembly(IApplicationContext *pAppCtx, IAssemblyName *pName, IAssembly *pAsmParent, IAssemblyName **ppNamePostPolicy, LPVOID pvReserved);
+STDAPI CreateApplicationContext(IAssemblyName *pName, LPAPPLICATIONCONTEXT *ppCtx);
+STDAPI IsRetargetableAssembly(IAssemblyName *pName, BOOL *pbIsRetargetable);
+STDAPI IsOptionallyRetargetableAssembly(IAssemblyName *pName, BOOL *pbIsRetargetable);
+#define EXPLICITBIND_FLAGS_NON_BINDABLE 0x0
+#define EXPLICITBIND_FLAGS_EXE 0x1
+
+
+extern RPC_IF_HANDLE __MIDL_itf_fusionpriv_0000_0017_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_fusionpriv_0000_0017_v0_0_s_ifspec;
+
+/* Additional Prototypes for ALL interfaces */
+
+/* end of Additional Prototypes */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+
diff --git a/src/pal/prebuilt/inc/fxver.h b/src/pal/prebuilt/inc/fxver.h
new file mode 100644
index 0000000000..7cb0cae0f4
--- /dev/null
+++ b/src/pal/prebuilt/inc/fxver.h
@@ -0,0 +1,203 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+//
+// Insert just the #defines in winver.h, so that the
+// C# compiler can include this file after macro preprocessing.
+//
+
+#ifdef __cplusplus
+#ifndef FXVER_H_
+#define FXVER_H_
+#define INCLUDE_FXVER_H
+#endif
+#else
+#define RC_INVOKED 1
+#define INCLUDE_FXVER_H
+#endif
+
+#ifdef INCLUDE_FXVER_H
+#undef INCLUDE_FXVER_H
+
+#ifndef RC_INVOKED
+#define FXVER_H_RC_INVOKED_ENABLED
+#define RC_INVOKED 1
+#endif
+
+#include <verrsrc.h>
+
+#ifdef FXVER_H_RC_INVOKED_ENABLED
+#undef RC_INVOKED
+#undef FXVER_H_RC_INVOKED_ENABLED
+#endif
+
+//
+// Include the definitions for rmj, rmm, rup, rpt
+//
+
+#include <product_version.h>
+
+/*
+ * Product version, name and copyright
+ */
+
+#include "fxverstrings.h"
+
+/*
+ * File version, names, description.
+ */
+
+// FX_VER_INTERNALNAME_STR is passed in by the build environment.
+#ifndef FX_VER_INTERNALNAME_STR
+#define FX_VER_INTERNALNAME_STR UNKNOWN_FILE
+#endif
+
+#define VER_INTERNALNAME_STR QUOTE_MACRO(FX_VER_INTERNALNAME_STR)
+#define VER_ORIGINALFILENAME_STR QUOTE_MACRO(FX_VER_INTERNALNAME_STR)
+
+// FX_VER_FILEDESCRIPTION_STR is defined in RC files that include fxver.h
+
+#ifndef FX_VER_FILEDESCRIPTION_STR
+#define FX_VER_FILEDESCRIPTION_STR QUOTE_MACRO(FX_VER_INTERNALNAME_STR)
+#endif
+
+#define VER_FILEDESCRIPTION_STR FX_VER_FILEDESCRIPTION_STR
+
+#ifndef FX_VER_FILEVERSION_STR
+#define FX_VER_FILEVERSION_STR FX_FILEVERSION_STR
+#endif
+
+#define VER_FILEVERSION_STR FX_VER_FILEVERSION_STR
+#define VER_FILEVERSION_STR_L VER_PRODUCTVERSION_STR_L
+
+#ifndef FX_VER_FILEVERSION
+#define FX_VER_FILEVERSION VER_DOTFILEVERSION
+#endif
+
+#define VER_FILEVERSION FX_VER_FILEVERSION
+
+//URT_VFT passed in by the build environment.
+#ifndef FX_VFT
+#define FX_VFT VFT_UNKNOWN
+#endif
+
+#define VER_FILETYPE FX_VFT
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+
+/* default is nodebug */
+#if DBG
+#define VER_DEBUG VS_FF_DEBUG
+#else
+#define VER_DEBUG 0
+#endif
+
+#define VER_PRERELEASE 0
+
+#define EXPORT_TAG
+
+#if OFFICIAL_BUILD
+#define VER_PRIVATE 0
+#else
+#define VER_PRIVATE VS_FF_PRIVATEBUILD
+#endif
+
+#define VER_SPECIALBUILD 0
+
+#define VER_FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+#define VER_FILEFLAGS (VER_PRERELEASE|VER_DEBUG|VER_PRIVATE|VER_SPECIALBUILD)
+#define VER_FILEOS VOS__WINDOWS32
+
+#define VER_COMPANYNAME_STR "Microsoft Corporation"
+
+#ifdef VER_LANGNEUTRAL
+#define VER_VERSION_UNICODE_LANG "000004B0" /* LANG_NEUTRAL/SUBLANG_NEUTRAL, Unicode CP */
+#define VER_VERSION_ANSI_LANG "000004E4" /* LANG_NEUTRAL/SUBLANG_NEUTRAL, Ansi CP */
+#define VER_VERSION_TRANSLATION 0x0000, 0x04B0
+#else
+#define VER_VERSION_UNICODE_LANG "040904B0" /* LANG_ENGLISH/SUBLANG_ENGLISH_US, Unicode CP */
+#define VER_VERSION_ANSI_LANG "040904E4" /* LANG_ENGLISH/SUBLANG_ENGLISH_US, Ansi CP */
+#define VER_VERSION_TRANSLATION 0x0409, 0x04B0
+#endif
+
+#if defined(CSC_INVOKED)
+#define VER_COMMENTS_STR "Flavor=" + QUOTE_MACRO(URTBLDENV_FRIENDLY)
+#else
+#define VER_COMMENTS_STR "Flavor=" QUOTE_MACRO(URTBLDENV_FRIENDLY)
+#endif
+
+#define VER_PRIVATEBUILD_STR QUOTE_MACRO(FX_VER_PRIVATEBUILD_STR)
+
+#if defined(__BUILDMACHINE__)
+#if defined(__BUILDDATE__)
+#define B2(x,y) " (" #x "." #y ")"
+#define B1(x,y) B2(x, y)
+#define BUILD_MACHINE_TAG B1(__BUILDMACHINE__, __BUILDDATE__)
+#else
+#define B2(x) " built by: " #x
+#define B1(x) B2(x)
+#define BUILD_MACHINE_TAG B1(__BUILDMACHINE__)
+#endif
+#if defined(__BUILDMACHINE_LEN__)
+#if __BUILDMACHINE_LEN__ >= 25
+#define BUILD_MACHINE_TAG_PADDED BUILD_MACHINE_TAG
+#elif __BUILDMACHINE_LEN__ == 24
+#define BUILD_MACHINE_TAG_PADDED BUILD_MACHINE_TAG " "
+#elif __BUILDMACHINE_LEN__ == 23
+#define BUILD_MACHINE_TAG_PADDED BUILD_MACHINE_TAG " "
+#elif __BUILDMACHINE_LEN__ == 22
+#define BUILD_MACHINE_TAG_PADDED BUILD_MACHINE_TAG " "
+#elif __BUILDMACHINE_LEN__ == 21
+#define BUILD_MACHINE_TAG_PADDED BUILD_MACHINE_TAG " "
+#elif __BUILDMACHINE_LEN__ == 20
+#define BUILD_MACHINE_TAG_PADDED BUILD_MACHINE_TAG " "
+#elif __BUILDMACHINE_LEN__ == 19
+#define BUILD_MACHINE_TAG_PADDED BUILD_MACHINE_TAG " "
+#elif __BUILDMACHINE_LEN__ == 18
+#define BUILD_MACHINE_TAG_PADDED BUILD_MACHINE_TAG " "
+#elif __BUILDMACHINE_LEN__ == 17
+#define BUILD_MACHINE_TAG_PADDED BUILD_MACHINE_TAG " "
+#elif __BUILDMACHINE_LEN__ == 16
+#define BUILD_MACHINE_TAG_PADDED BUILD_MACHINE_TAG " "
+#elif __BUILDMACHINE_LEN__ == 15
+#define BUILD_MACHINE_TAG_PADDED BUILD_MACHINE_TAG " "
+#elif __BUILDMACHINE_LEN__ == 14
+#define BUILD_MACHINE_TAG_PADDED BUILD_MACHINE_TAG " "
+#elif __BUILDMACHINE_LEN__ == 13
+#define BUILD_MACHINE_TAG_PADDED BUILD_MACHINE_TAG " "
+#elif __BUILDMACHINE_LEN__ == 12
+#define BUILD_MACHINE_TAG_PADDED BUILD_MACHINE_TAG " "
+#elif __BUILDMACHINE_LEN__ == 11
+#define BUILD_MACHINE_TAG_PADDED BUILD_MACHINE_TAG " "
+#elif __BUILDMACHINE_LEN__ == 10
+#define BUILD_MACHINE_TAG_PADDED BUILD_MACHINE_TAG " "
+#elif __BUILDMACHINE_LEN__ == 9
+#define BUILD_MACHINE_TAG_PADDED BUILD_MACHINE_TAG " "
+#elif __BUILDMACHINE_LEN__ == 8
+#define BUILD_MACHINE_TAG_PADDED BUILD_MACHINE_TAG " "
+#elif __BUILDMACHINE_LEN__ == 7
+#define BUILD_MACHINE_TAG_PADDED BUILD_MACHINE_TAG " "
+#elif __BUILDMACHINE_LEN__ == 6
+#define BUILD_MACHINE_TAG_PADDED BUILD_MACHINE_TAG " "
+#elif __BUILDMACHINE_LEN__ == 5
+#define BUILD_MACHINE_TAG_PADDED BUILD_MACHINE_TAG " "
+#elif __BUILDMACHINE_LEN__ == 4
+#define BUILD_MACHINE_TAG_PADDED BUILD_MACHINE_TAG " "
+#elif __BUILDMACHINE_LEN__ == 3
+#define BUILD_MACHINE_TAG_PADDED BUILD_MACHINE_TAG " "
+#elif __BUILDMACHINE_LEN__ == 2
+#define BUILD_MACHINE_TAG_PADDED BUILD_MACHINE_TAG " "
+#elif __BUILDMACHINE_LEN__ == 1
+#define BUILD_MACHINE_TAG_PADDED BUILD_MACHINE_TAG " "
+#else
+#define BUILD_MACHINE_TAG_PADDED BUILD_MACHINE_TAG
+#endif
+#else
+#define BUILD_MACHINE_TAG_PADDED BUILD_MACHINE_TAG
+#endif
+#else
+#define BUILD_MACHINE_TAG
+#define BUILD_MACHINE_TAG_PADDED
+#endif
+
+#endif
diff --git a/src/pal/prebuilt/inc/fxver.rc b/src/pal/prebuilt/inc/fxver.rc
new file mode 100644
index 0000000000..a341041309
--- /dev/null
+++ b/src/pal/prebuilt/inc/fxver.rc
@@ -0,0 +1,106 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*---------------------------------------------------------------*/
+/* */
+/* The following section actually creates the version structure. */
+/* They are ignored if we are not being invoked by RC. */
+/* */
+/* ntverp.H must be included before including this file */
+/* */
+/* If VER_LEGALCOPYRIGHT_STR is not defined, it will be */
+/* constructed using VER_LEGALCOPYRIGHT_YEARS, so at least one */
+/* these macros must be defined before including this file. */
+/* */
+/* VER_FILETYPE, VER_FILESUBTYPE, VER_FILEDESCRIPTION_STR, and */
+/* VER_INTERNALNAME_STR must be defined before including this */
+/* file. */
+/* */
+/* If VER_FILEVERSION is not defined, VER_PRODUCTVERSION will be */
+/* used instead. If VER_FILEVERSION_STR is not defined, */
+/* VER_PRODUCTVERSION_STR will be used instead. */
+/* */
+/* If VER_ORIGINALFILENAME_STR is not defined, it is set to */
+/* the value in VER_INTERNALNAME_STR. */
+/* */
+/* If INTL is defined, then this is assumed to be an */
+/* an international build; two string blocks will be created, */
+/* (since all version resources must have English), and the */
+/* second one can be localized */
+/* */
+/*---------------------------------------------------------------*/
+
+#ifdef _WIN32
+#include <_version.h>
+#endif //_WIN32
+
+#ifdef RC_INVOKED
+
+VS_VERSION_INFO VERSIONINFO
+FILEVERSION VER_FILEVERSION
+PRODUCTVERSION VER_PRODUCTVERSION
+FILEFLAGSMASK VER_FILEFLAGSMASK
+FILEFLAGS VER_FILEFLAGS
+FILEOS VER_FILEOS
+FILETYPE VER_FILETYPE
+FILESUBTYPE VER_FILESUBTYPE
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK VER_VERSION_UNICODE_LANG
+ BEGIN
+ VALUE "CompanyName", VER_COMPANYNAME_STR
+ VALUE "FileDescription", VER_FILEDESCRIPTION_STR EXPORT_TAG
+ VALUE "FileVersion", VER_FILEVERSION_STR BUILD_MACHINE_TAG_PADDED
+ VALUE "InternalName", VER_INTERNALNAME_STR
+ VALUE "LegalCopyright", VER_LEGALCOPYRIGHT_STR
+ VALUE "OriginalFilename",VER_ORIGINALFILENAME_STR
+ VALUE "ProductName", VER_PRODUCTNAME_STR
+ VALUE "ProductVersion", VER_FILEVERSION_STR
+#ifdef VER_OLESELFREGISTER
+ VALUE "OleSelfRegister", "\0"
+#endif
+ VALUE "Comments", VER_COMMENTS_STR
+#if VER_PRIVATE
+ VALUE "PrivateBuild", VER_PRIVATEBUILD_STR
+#endif
+#ifdef VER_EXTRA_VALUES
+ VER_EXTRA_VALUES
+#endif
+
+ END
+
+
+#ifdef VER_ANSICP /* Some apps are hard coded to look for ANSI CP. */
+ BLOCK VER_VERSION_ANSI_LANG
+ BEGIN
+ VALUE "CompanyName", VER_COMPANYNAME_STR
+ VALUE "FileDescription", VER_FILEDESCRIPTION_STR EXPORT_TAG
+ VALUE "FileVersion", VER_FILEVERSION_STR
+ VALUE "InternalName", VER_INTERNALNAME_STR
+ VALUE "LegalCopyright", VER_LEGALCOPYRIGHT_STR
+ VALUE "OriginalFilename",VER_ORIGINALFILENAME_STR
+ VALUE "ProductName", VER_PRODUCTNAME_STR
+ VALUE "ProductVersion", VER_FILEVERSION_STR
+#ifdef VER_OLESELFREGISTER
+ VALUE "OleSelfRegister", "\0"
+#endif
+ VALUE "Comments", VER_COMMENTS_STR
+#if VER_PRIVATE
+ VALUE "PrivateBuild", VER_PRIVATEBUILD_STR
+#endif
+#ifdef VER_EXTRA_VALUES
+ VER_EXTRA_VALUES
+#endif
+ END
+#endif
+ END
+
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", VER_VERSION_TRANSLATION
+ END
+END
+
+#endif
diff --git a/src/pal/prebuilt/inc/fxverstrings.h b/src/pal/prebuilt/inc/fxverstrings.h
new file mode 100644
index 0000000000..cafcbadf30
--- /dev/null
+++ b/src/pal/prebuilt/inc/fxverstrings.h
@@ -0,0 +1,17 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#ifndef VER_PRODUCTNAME_STR
+ #define VER_PRODUCTNAME_STR L"Microsoft\256 .NET Core"
+#endif
+
+#ifndef VER_LEGALCOPYRIGHT_STR
+ #define VER_LEGALCOPYRIGHT_STR "\251 Microsoft Corporation. All rights reserved."
+ #define VER_LEGALCOPYRIGHT_STR_L L"\251 Microsoft Corporation. All rights reserved."
+#endif
+
+#ifndef VER_LEGALCOPYRIGHT_LOGO_STR
+ #define VER_LEGALCOPYRIGHT_LOGO_STR "Copyright (c) Microsoft Corporation. All rights reserved."
+ #define VER_LEGALCOPYRIGHT_LOGO_STR_L L"Copyright (c) Microsoft Corporation. All rights reserved."
+#endif
diff --git a/src/pal/prebuilt/inc/gchost.h b/src/pal/prebuilt/inc/gchost.h
new file mode 100644
index 0000000000..6829b0f531
--- /dev/null
+++ b/src/pal/prebuilt/inc/gchost.h
@@ -0,0 +1,166 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+
+
+/* this ALWAYS GENERATED file contains the definitions for the interfaces */
+
+
+ /* File created by MIDL compiler version 8.00.0603 */
+/* @@MIDL_FILE_HEADING( ) */
+
+#pragma warning( disable: 4049 ) /* more than 64k source lines */
+
+
+/* verify that the <rpcndr.h> version is high enough to compile this file*/
+#ifndef __REQUIRED_RPCNDR_H_VERSION__
+#define __REQUIRED_RPCNDR_H_VERSION__ 475
+#endif
+
+#include "rpc.h"
+#include "rpcndr.h"
+
+#ifndef __RPCNDR_H_VERSION__
+#error this stub requires an updated version of <rpcndr.h>
+#endif // __RPCNDR_H_VERSION__
+
+#ifndef COM_NO_WINDOWS_H
+#include "windows.h"
+#include "ole2.h"
+#endif /*COM_NO_WINDOWS_H*/
+
+#ifndef __gchost_h__
+#define __gchost_h__
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+/* Forward Declarations */
+
+#ifndef __IDummyDoNotUse_FWD_DEFINED__
+#define __IDummyDoNotUse_FWD_DEFINED__
+typedef interface IDummyDoNotUse IDummyDoNotUse;
+
+#endif /* __IDummyDoNotUse_FWD_DEFINED__ */
+
+
+/* header files for imported files */
+#include "unknwn.h"
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+
+/* interface __MIDL_itf_gchost_0000_0000 */
+/* [local] */
+
+typedef struct _COR_GC_STATS
+ {
+ ULONG Flags;
+ SIZE_T ExplicitGCCount;
+ SIZE_T GenCollectionsTaken[ 3 ];
+ SIZE_T CommittedKBytes;
+ SIZE_T ReservedKBytes;
+ SIZE_T Gen0HeapSizeKBytes;
+ SIZE_T Gen1HeapSizeKBytes;
+ SIZE_T Gen2HeapSizeKBytes;
+ SIZE_T LargeObjectHeapSizeKBytes;
+ SIZE_T KBytesPromotedFromGen0;
+ SIZE_T KBytesPromotedFromGen1;
+ } COR_GC_STATS;
+
+/*
+ * WARNING - This is a dummy interface that should never be used.
+ * The code is written this way because Midl requires a CoClass, Interface, etc... that generates
+ * a guid. Removing the IGCHost interface for FEATURE_INCLUDE_ALL_INTERFACES removes the only guid
+ * This option was selected because ifdefs are not simple to implement for excluding files in SOURCES
+*/
+
+
+extern RPC_IF_HANDLE __MIDL_itf_gchost_0000_0000_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_gchost_0000_0000_v0_0_s_ifspec;
+
+#ifndef __IDummyDoNotUse_INTERFACE_DEFINED__
+#define __IDummyDoNotUse_INTERFACE_DEFINED__
+
+/* interface IDummyDoNotUse */
+/* [local][unique][uuid][object] */
+
+
+EXTERN_C const IID IID_IDummyDoNotUse;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("F9423916-2A35-4f03-9EE9-DDAFA3C8AEE0")
+ IDummyDoNotUse : public IUnknown
+ {
+ public:
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IDummyDoNotUseVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IDummyDoNotUse * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IDummyDoNotUse * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IDummyDoNotUse * This);
+
+ END_INTERFACE
+ } IDummyDoNotUseVtbl;
+
+ interface IDummyDoNotUse
+ {
+ CONST_VTBL struct IDummyDoNotUseVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IDummyDoNotUse_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IDummyDoNotUse_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IDummyDoNotUse_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IDummyDoNotUse_INTERFACE_DEFINED__ */
+
+
+/* Additional Prototypes for ALL interfaces */
+
+/* end of Additional Prototypes */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+
diff --git a/src/pal/prebuilt/inc/ivalidator.h b/src/pal/prebuilt/inc/ivalidator.h
new file mode 100644
index 0000000000..320022dc40
--- /dev/null
+++ b/src/pal/prebuilt/inc/ivalidator.h
@@ -0,0 +1,334 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+
+
+/* this ALWAYS GENERATED file contains the definitions for the interfaces */
+
+
+ /* File created by MIDL compiler version 8.00.0603 */
+/* @@MIDL_FILE_HEADING( ) */
+
+#pragma warning( disable: 4049 ) /* more than 64k source lines */
+
+
+/* verify that the <rpcndr.h> version is high enough to compile this file*/
+#ifndef __REQUIRED_RPCNDR_H_VERSION__
+#define __REQUIRED_RPCNDR_H_VERSION__ 475
+#endif
+
+#include "rpc.h"
+#include "rpcndr.h"
+
+#ifndef __RPCNDR_H_VERSION__
+#error this stub requires an updated version of <rpcndr.h>
+#endif // __RPCNDR_H_VERSION__
+
+#ifndef COM_NO_WINDOWS_H
+#include "windows.h"
+#include "ole2.h"
+#endif /*COM_NO_WINDOWS_H*/
+
+#ifndef __IValidator_h__
+#define __IValidator_h__
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+/* Forward Declarations */
+
+#ifndef __IValidator_FWD_DEFINED__
+#define __IValidator_FWD_DEFINED__
+typedef interface IValidator IValidator;
+
+#endif /* __IValidator_FWD_DEFINED__ */
+
+
+#ifndef __ICLRValidator_FWD_DEFINED__
+#define __ICLRValidator_FWD_DEFINED__
+typedef interface ICLRValidator ICLRValidator;
+
+#endif /* __ICLRValidator_FWD_DEFINED__ */
+
+
+/* header files for imported files */
+#include "ivehandler.h"
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+
+/* interface __MIDL_itf_IValidator_0000_0000 */
+/* [local] */
+
+#pragma warning(push)
+#pragma warning(disable:28718)
+
+
+
+enum ValidatorFlags
+ {
+ VALIDATOR_EXTRA_VERBOSE = 0x1,
+ VALIDATOR_SHOW_SOURCE_LINES = 0x2,
+ VALIDATOR_CHECK_ILONLY = 0x4,
+ VALIDATOR_CHECK_PEFORMAT_ONLY = 0x8,
+ VALIDATOR_NOCHECK_PEFORMAT = 0x10,
+ VALIDATOR_TRANSPARENT_ONLY = 0x20
+ } ;
+
+
+extern RPC_IF_HANDLE __MIDL_itf_IValidator_0000_0000_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_IValidator_0000_0000_v0_0_s_ifspec;
+
+#ifndef __IValidator_INTERFACE_DEFINED__
+#define __IValidator_INTERFACE_DEFINED__
+
+/* interface IValidator */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_IValidator;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("63DF8730-DC81-4062-84A2-1FF943F59FAC")
+ IValidator : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE Validate(
+ /* [in] */ IVEHandler *veh,
+ /* [in] */ IUnknown *pAppDomain,
+ /* [in] */ unsigned long ulFlags,
+ /* [in] */ unsigned long ulMaxError,
+ /* [in] */ unsigned long token,
+ /* [in] */ LPWSTR fileName,
+ /* [size_is][in] */ BYTE *pe,
+ /* [in] */ unsigned long ulSize) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE FormatEventInfo(
+ /* [in] */ HRESULT hVECode,
+ /* [in] */ VEContext Context,
+ /* [out][in] */ LPWSTR msg,
+ /* [in] */ unsigned long ulMaxLength,
+ /* [in] */ SAFEARRAY * psa) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IValidatorVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IValidator * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IValidator * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IValidator * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Validate )(
+ IValidator * This,
+ /* [in] */ IVEHandler *veh,
+ /* [in] */ IUnknown *pAppDomain,
+ /* [in] */ unsigned long ulFlags,
+ /* [in] */ unsigned long ulMaxError,
+ /* [in] */ unsigned long token,
+ /* [in] */ LPWSTR fileName,
+ /* [size_is][in] */ BYTE *pe,
+ /* [in] */ unsigned long ulSize);
+
+ HRESULT ( STDMETHODCALLTYPE *FormatEventInfo )(
+ IValidator * This,
+ /* [in] */ HRESULT hVECode,
+ /* [in] */ VEContext Context,
+ /* [out][in] */ LPWSTR msg,
+ /* [in] */ unsigned long ulMaxLength,
+ /* [in] */ SAFEARRAY * psa);
+
+ END_INTERFACE
+ } IValidatorVtbl;
+
+ interface IValidator
+ {
+ CONST_VTBL struct IValidatorVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IValidator_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IValidator_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IValidator_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IValidator_Validate(This,veh,pAppDomain,ulFlags,ulMaxError,token,fileName,pe,ulSize) \
+ ( (This)->lpVtbl -> Validate(This,veh,pAppDomain,ulFlags,ulMaxError,token,fileName,pe,ulSize) )
+
+#define IValidator_FormatEventInfo(This,hVECode,Context,msg,ulMaxLength,psa) \
+ ( (This)->lpVtbl -> FormatEventInfo(This,hVECode,Context,msg,ulMaxLength,psa) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IValidator_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICLRValidator_INTERFACE_DEFINED__
+#define __ICLRValidator_INTERFACE_DEFINED__
+
+/* interface ICLRValidator */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_ICLRValidator;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("63DF8730-DC81-4062-84A2-1FF943F59FDD")
+ ICLRValidator : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE Validate(
+ /* [in] */ IVEHandler *veh,
+ /* [in] */ unsigned long ulAppDomainId,
+ /* [in] */ unsigned long ulFlags,
+ /* [in] */ unsigned long ulMaxError,
+ /* [in] */ unsigned long token,
+ /* [in] */ LPWSTR fileName,
+ /* [size_is][in] */ BYTE *pe,
+ /* [in] */ unsigned long ulSize) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE FormatEventInfo(
+ /* [in] */ HRESULT hVECode,
+ /* [in] */ VEContext Context,
+ /* [out][in] */ LPWSTR msg,
+ /* [in] */ unsigned long ulMaxLength,
+ /* [in] */ SAFEARRAY * psa) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICLRValidatorVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICLRValidator * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICLRValidator * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICLRValidator * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Validate )(
+ ICLRValidator * This,
+ /* [in] */ IVEHandler *veh,
+ /* [in] */ unsigned long ulAppDomainId,
+ /* [in] */ unsigned long ulFlags,
+ /* [in] */ unsigned long ulMaxError,
+ /* [in] */ unsigned long token,
+ /* [in] */ LPWSTR fileName,
+ /* [size_is][in] */ BYTE *pe,
+ /* [in] */ unsigned long ulSize);
+
+ HRESULT ( STDMETHODCALLTYPE *FormatEventInfo )(
+ ICLRValidator * This,
+ /* [in] */ HRESULT hVECode,
+ /* [in] */ VEContext Context,
+ /* [out][in] */ LPWSTR msg,
+ /* [in] */ unsigned long ulMaxLength,
+ /* [in] */ SAFEARRAY * psa);
+
+ END_INTERFACE
+ } ICLRValidatorVtbl;
+
+ interface ICLRValidator
+ {
+ CONST_VTBL struct ICLRValidatorVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICLRValidator_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICLRValidator_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICLRValidator_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICLRValidator_Validate(This,veh,ulAppDomainId,ulFlags,ulMaxError,token,fileName,pe,ulSize) \
+ ( (This)->lpVtbl -> Validate(This,veh,ulAppDomainId,ulFlags,ulMaxError,token,fileName,pe,ulSize) )
+
+#define ICLRValidator_FormatEventInfo(This,hVECode,Context,msg,ulMaxLength,psa) \
+ ( (This)->lpVtbl -> FormatEventInfo(This,hVECode,Context,msg,ulMaxLength,psa) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICLRValidator_INTERFACE_DEFINED__ */
+
+
+/* interface __MIDL_itf_IValidator_0000_0002 */
+/* [local] */
+
+#pragma warning(pop)
+
+
+extern RPC_IF_HANDLE __MIDL_itf_IValidator_0000_0002_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_IValidator_0000_0002_v0_0_s_ifspec;
+
+/* Additional Prototypes for ALL interfaces */
+
+unsigned long __RPC_USER LPSAFEARRAY_UserSize( unsigned long *, unsigned long , LPSAFEARRAY * );
+unsigned char * __RPC_USER LPSAFEARRAY_UserMarshal( unsigned long *, unsigned char *, LPSAFEARRAY * );
+unsigned char * __RPC_USER LPSAFEARRAY_UserUnmarshal(unsigned long *, unsigned char *, LPSAFEARRAY * );
+void __RPC_USER LPSAFEARRAY_UserFree( unsigned long *, LPSAFEARRAY * );
+
+/* end of Additional Prototypes */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+
diff --git a/src/pal/prebuilt/inc/ivehandler.h b/src/pal/prebuilt/inc/ivehandler.h
new file mode 100644
index 0000000000..bdd8cb521b
--- /dev/null
+++ b/src/pal/prebuilt/inc/ivehandler.h
@@ -0,0 +1,220 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+
+
+/* this ALWAYS GENERATED file contains the definitions for the interfaces */
+
+
+ /* File created by MIDL compiler version 8.00.0603 */
+/* @@MIDL_FILE_HEADING( ) */
+
+#pragma warning( disable: 4049 ) /* more than 64k source lines */
+
+
+/* verify that the <rpcndr.h> version is high enough to compile this file*/
+#ifndef __REQUIRED_RPCNDR_H_VERSION__
+#define __REQUIRED_RPCNDR_H_VERSION__ 475
+#endif
+
+#include "rpc.h"
+#include "rpcndr.h"
+
+#ifndef __RPCNDR_H_VERSION__
+#error this stub requires an updated version of <rpcndr.h>
+#endif // __RPCNDR_H_VERSION__
+
+#ifndef COM_NO_WINDOWS_H
+#include "windows.h"
+#include "ole2.h"
+#endif /*COM_NO_WINDOWS_H*/
+
+#ifndef __IVEHandler_h__
+#define __IVEHandler_h__
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+/* Forward Declarations */
+
+#ifndef __VEHandlerClass_FWD_DEFINED__
+#define __VEHandlerClass_FWD_DEFINED__
+
+#ifdef __cplusplus
+typedef class VEHandlerClass VEHandlerClass;
+#else
+typedef struct VEHandlerClass VEHandlerClass;
+#endif /* __cplusplus */
+
+#endif /* __VEHandlerClass_FWD_DEFINED__ */
+
+
+#ifndef __IVEHandler_FWD_DEFINED__
+#define __IVEHandler_FWD_DEFINED__
+typedef interface IVEHandler IVEHandler;
+
+#endif /* __IVEHandler_FWD_DEFINED__ */
+
+
+/* header files for imported files */
+#include "unknwn.h"
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+
+/* interface __MIDL_itf_IVEHandler_0000_0000 */
+/* [local] */
+
+typedef struct tag_VerError
+ {
+ unsigned long flags;
+ unsigned long opcode;
+ unsigned long uOffset;
+ unsigned long Token;
+ unsigned long item1_flags;
+ int *item1_data;
+ unsigned long item2_flags;
+ int *item2_data;
+ } _VerError;
+
+typedef _VerError VEContext;
+
+
+
+
+extern RPC_IF_HANDLE __MIDL_itf_IVEHandler_0000_0000_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_IVEHandler_0000_0000_v0_0_s_ifspec;
+
+
+#ifndef __VEHandlerLib_LIBRARY_DEFINED__
+#define __VEHandlerLib_LIBRARY_DEFINED__
+
+/* library VEHandlerLib */
+/* [helpstring][version][uuid] */
+
+
+EXTERN_C const IID LIBID_VEHandlerLib;
+
+EXTERN_C const CLSID CLSID_VEHandlerClass;
+
+#ifdef __cplusplus
+
+class DECLSPEC_UUID("856CA1B1-7DAB-11d3-ACEC-00C04F86C309")
+VEHandlerClass;
+#endif
+#endif /* __VEHandlerLib_LIBRARY_DEFINED__ */
+
+#ifndef __IVEHandler_INTERFACE_DEFINED__
+#define __IVEHandler_INTERFACE_DEFINED__
+
+/* interface IVEHandler */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_IVEHandler;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("856CA1B2-7DAB-11d3-ACEC-00C04F86C309")
+ IVEHandler : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE VEHandler(
+ /* [in] */ HRESULT VECode,
+ /* [in] */ VEContext Context,
+ /* [in] */ SAFEARRAY * psa) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetReporterFtn(
+ /* [in] */ __int64 lFnPtr) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IVEHandlerVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IVEHandler * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IVEHandler * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IVEHandler * This);
+
+ HRESULT ( STDMETHODCALLTYPE *VEHandler )(
+ IVEHandler * This,
+ /* [in] */ HRESULT VECode,
+ /* [in] */ VEContext Context,
+ /* [in] */ SAFEARRAY * psa);
+
+ HRESULT ( STDMETHODCALLTYPE *SetReporterFtn )(
+ IVEHandler * This,
+ /* [in] */ __int64 lFnPtr);
+
+ END_INTERFACE
+ } IVEHandlerVtbl;
+
+ interface IVEHandler
+ {
+ CONST_VTBL struct IVEHandlerVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IVEHandler_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IVEHandler_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IVEHandler_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IVEHandler_VEHandler(This,VECode,Context,psa) \
+ ( (This)->lpVtbl -> VEHandler(This,VECode,Context,psa) )
+
+#define IVEHandler_SetReporterFtn(This,lFnPtr) \
+ ( (This)->lpVtbl -> SetReporterFtn(This,lFnPtr) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IVEHandler_INTERFACE_DEFINED__ */
+
+
+/* Additional Prototypes for ALL interfaces */
+
+unsigned long __RPC_USER LPSAFEARRAY_UserSize( unsigned long *, unsigned long , LPSAFEARRAY * );
+unsigned char * __RPC_USER LPSAFEARRAY_UserMarshal( unsigned long *, unsigned char *, LPSAFEARRAY * );
+unsigned char * __RPC_USER LPSAFEARRAY_UserUnmarshal(unsigned long *, unsigned char *, LPSAFEARRAY * );
+void __RPC_USER LPSAFEARRAY_UserFree( unsigned long *, LPSAFEARRAY * );
+
+/* end of Additional Prototypes */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+
diff --git a/src/pal/prebuilt/inc/metahost.h b/src/pal/prebuilt/inc/metahost.h
new file mode 100644
index 0000000000..0714e42157
--- /dev/null
+++ b/src/pal/prebuilt/inc/metahost.h
@@ -0,0 +1,1767 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+
+
+/* this ALWAYS GENERATED file contains the definitions for the interfaces */
+
+
+ /* File created by MIDL compiler version 8.00.0603 */
+/* @@MIDL_FILE_HEADING( ) */
+
+#pragma warning( disable: 4049 ) /* more than 64k source lines */
+
+
+/* verify that the <rpcndr.h> version is high enough to compile this file*/
+#ifndef __REQUIRED_RPCNDR_H_VERSION__
+#define __REQUIRED_RPCNDR_H_VERSION__ 475
+#endif
+
+#include "rpc.h"
+#include "rpcndr.h"
+
+#ifndef __RPCNDR_H_VERSION__
+#error this stub requires an updated version of <rpcndr.h>
+#endif // __RPCNDR_H_VERSION__
+
+#ifndef COM_NO_WINDOWS_H
+#include "windows.h"
+#include "ole2.h"
+#endif /*COM_NO_WINDOWS_H*/
+
+#ifndef __metahost_h__
+#define __metahost_h__
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+/* Forward Declarations */
+
+#ifndef __ICLRMetaHost_FWD_DEFINED__
+#define __ICLRMetaHost_FWD_DEFINED__
+typedef interface ICLRMetaHost ICLRMetaHost;
+
+#endif /* __ICLRMetaHost_FWD_DEFINED__ */
+
+
+#ifndef __ICLRMetaHostPolicy_FWD_DEFINED__
+#define __ICLRMetaHostPolicy_FWD_DEFINED__
+typedef interface ICLRMetaHostPolicy ICLRMetaHostPolicy;
+
+#endif /* __ICLRMetaHostPolicy_FWD_DEFINED__ */
+
+
+#ifndef __ICLRProfiling_FWD_DEFINED__
+#define __ICLRProfiling_FWD_DEFINED__
+typedef interface ICLRProfiling ICLRProfiling;
+
+#endif /* __ICLRProfiling_FWD_DEFINED__ */
+
+
+#ifndef __ICLRDebuggingLibraryProvider_FWD_DEFINED__
+#define __ICLRDebuggingLibraryProvider_FWD_DEFINED__
+typedef interface ICLRDebuggingLibraryProvider ICLRDebuggingLibraryProvider;
+
+#endif /* __ICLRDebuggingLibraryProvider_FWD_DEFINED__ */
+
+
+#ifndef __ICLRDebugging_FWD_DEFINED__
+#define __ICLRDebugging_FWD_DEFINED__
+typedef interface ICLRDebugging ICLRDebugging;
+
+#endif /* __ICLRDebugging_FWD_DEFINED__ */
+
+
+#ifndef __ICLRRuntimeInfo_FWD_DEFINED__
+#define __ICLRRuntimeInfo_FWD_DEFINED__
+typedef interface ICLRRuntimeInfo ICLRRuntimeInfo;
+
+#endif /* __ICLRRuntimeInfo_FWD_DEFINED__ */
+
+
+#ifndef __ICLRStrongName_FWD_DEFINED__
+#define __ICLRStrongName_FWD_DEFINED__
+typedef interface ICLRStrongName ICLRStrongName;
+
+#endif /* __ICLRStrongName_FWD_DEFINED__ */
+
+
+#ifndef __ICLRStrongName2_FWD_DEFINED__
+#define __ICLRStrongName2_FWD_DEFINED__
+typedef interface ICLRStrongName2 ICLRStrongName2;
+
+#endif /* __ICLRStrongName2_FWD_DEFINED__ */
+
+
+#ifndef __ICLRStrongName3_FWD_DEFINED__
+#define __ICLRStrongName3_FWD_DEFINED__
+typedef interface ICLRStrongName3 ICLRStrongName3;
+
+#endif /* __ICLRStrongName3_FWD_DEFINED__ */
+
+
+#ifndef __ICLRMetaHost_FWD_DEFINED__
+#define __ICLRMetaHost_FWD_DEFINED__
+typedef interface ICLRMetaHost ICLRMetaHost;
+
+#endif /* __ICLRMetaHost_FWD_DEFINED__ */
+
+
+#ifndef __ICLRMetaHostPolicy_FWD_DEFINED__
+#define __ICLRMetaHostPolicy_FWD_DEFINED__
+typedef interface ICLRMetaHostPolicy ICLRMetaHostPolicy;
+
+#endif /* __ICLRMetaHostPolicy_FWD_DEFINED__ */
+
+
+#ifndef __ICLRProfiling_FWD_DEFINED__
+#define __ICLRProfiling_FWD_DEFINED__
+typedef interface ICLRProfiling ICLRProfiling;
+
+#endif /* __ICLRProfiling_FWD_DEFINED__ */
+
+
+#ifndef __ICLRDebuggingLibraryProvider_FWD_DEFINED__
+#define __ICLRDebuggingLibraryProvider_FWD_DEFINED__
+typedef interface ICLRDebuggingLibraryProvider ICLRDebuggingLibraryProvider;
+
+#endif /* __ICLRDebuggingLibraryProvider_FWD_DEFINED__ */
+
+
+#ifndef __ICLRDebugging_FWD_DEFINED__
+#define __ICLRDebugging_FWD_DEFINED__
+typedef interface ICLRDebugging ICLRDebugging;
+
+#endif /* __ICLRDebugging_FWD_DEFINED__ */
+
+
+#ifndef __ICLRRuntimeInfo_FWD_DEFINED__
+#define __ICLRRuntimeInfo_FWD_DEFINED__
+typedef interface ICLRRuntimeInfo ICLRRuntimeInfo;
+
+#endif /* __ICLRRuntimeInfo_FWD_DEFINED__ */
+
+
+#ifndef __ICLRStrongName_FWD_DEFINED__
+#define __ICLRStrongName_FWD_DEFINED__
+typedef interface ICLRStrongName ICLRStrongName;
+
+#endif /* __ICLRStrongName_FWD_DEFINED__ */
+
+
+/* header files for imported files */
+#include "unknwn.h"
+#include "oaidl.h"
+#include "ocidl.h"
+#include "mscoree.h"
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+
+/* interface __MIDL_itf_metahost_0000_0000 */
+/* [local] */
+
+#include <winapifamily.h>
+#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+STDAPI CLRCreateInstance(REFCLSID clsid, REFIID riid, /*iid_is(riid)*/ LPVOID *ppInterface);
+EXTERN_GUID(CLSID_CLRStrongName, 0xB79B0ACD, 0xF5CD, 0x409b, 0xB5, 0xA5, 0xA1, 0x62, 0x44, 0x61, 0x0B, 0x92);
+EXTERN_GUID(IID_ICLRMetaHost, 0xD332DB9E, 0xB9B3, 0x4125, 0x82, 0x07, 0xA1, 0x48, 0x84, 0xF5, 0x32, 0x16);
+EXTERN_GUID(CLSID_CLRMetaHost, 0x9280188d, 0xe8e, 0x4867, 0xb3, 0xc, 0x7f, 0xa8, 0x38, 0x84, 0xe8, 0xde);
+EXTERN_GUID(IID_ICLRMetaHostPolicy, 0xE2190695, 0x77B2, 0x492e, 0x8E, 0x14, 0xC4, 0xB3, 0xA7, 0xFD, 0xD5, 0x93);
+EXTERN_GUID(CLSID_CLRMetaHostPolicy, 0x2ebcd49a, 0x1b47, 0x4a61, 0xb1, 0x3a, 0x4a, 0x3, 0x70, 0x1e, 0x59, 0x4b);
+EXTERN_GUID(IID_ICLRDebugging, 0xd28f3c5a, 0x9634, 0x4206, 0xa5, 0x9, 0x47, 0x75, 0x52, 0xee, 0xfb, 0x10);
+EXTERN_GUID(CLSID_CLRDebugging, 0xbacc578d, 0xfbdd, 0x48a4, 0x96, 0x9f, 0x2, 0xd9, 0x32, 0xb7, 0x46, 0x34);
+EXTERN_GUID(IID_ICLRRuntimeInfo, 0xBD39D1D2, 0xBA2F, 0x486a, 0x89, 0xB0, 0xB4, 0xB0, 0xCB, 0x46, 0x68, 0x91);
+EXTERN_GUID(IID_ICLRStrongName, 0x9FD93CCF, 0x3280, 0x4391, 0xB3, 0xA9, 0x96, 0xE1, 0xCD, 0xE7, 0x7C, 0x8D);
+EXTERN_GUID(IID_ICLRStrongName2, 0xC22ED5C5, 0x4B59, 0x4975, 0x90, 0xEB, 0x85, 0xEA, 0x55, 0xC0, 0x06, 0x9B);
+EXTERN_GUID(IID_ICLRStrongName3, 0x22c7089b, 0xbbd3, 0x414a, 0xb6, 0x98, 0x21, 0x0f, 0x26, 0x3f, 0x1f, 0xed);
+EXTERN_GUID(CLSID_CLRDebuggingLegacy, 0xDF8395B5, 0xA4BA, 0x450b, 0xA7, 0x7C, 0xA9, 0xA4, 0x77, 0x62, 0xC5, 0x20);
+EXTERN_GUID(CLSID_CLRProfiling, 0xbd097ed8, 0x733e, 0x43fe, 0x8e, 0xd7, 0xa9, 0x5f, 0xf9, 0xa8, 0x44, 0x8c);
+EXTERN_GUID(IID_ICLRProfiling, 0xb349abe3, 0xb56f, 0x4689, 0xbf, 0xcd, 0x76, 0xbf, 0x39, 0xd8, 0x88, 0xea);
+EXTERN_GUID(IID_ICLRDebuggingLibraryProvider, 0x3151c08d, 0x4d09, 0x4f9b, 0x88, 0x38, 0x28, 0x80, 0xbf, 0x18, 0xfe, 0x51);
+typedef HRESULT ( __stdcall *CLRCreateInstanceFnPtr )(
+ REFCLSID clsid,
+ REFIID riid,
+ LPVOID *ppInterface);
+
+typedef HRESULT ( __stdcall *CreateInterfaceFnPtr )(
+ REFCLSID clsid,
+ REFIID riid,
+ LPVOID *ppInterface);
+
+
+typedef HRESULT ( __stdcall *CallbackThreadSetFnPtr )( void);
+
+typedef HRESULT ( __stdcall *CallbackThreadUnsetFnPtr )( void);
+
+typedef void ( __stdcall *RuntimeLoadedCallbackFnPtr )(
+ ICLRRuntimeInfo *pRuntimeInfo,
+ CallbackThreadSetFnPtr pfnCallbackThreadSet,
+ CallbackThreadUnsetFnPtr pfnCallbackThreadUnset);
+
+
+
+extern RPC_IF_HANDLE __MIDL_itf_metahost_0000_0000_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_metahost_0000_0000_v0_0_s_ifspec;
+
+#ifndef __ICLRMetaHost_INTERFACE_DEFINED__
+#define __ICLRMetaHost_INTERFACE_DEFINED__
+
+/* interface ICLRMetaHost */
+/* [object][local][helpstring][version][uuid] */
+
+
+EXTERN_C const IID IID_ICLRMetaHost;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("D332DB9E-B9B3-4125-8207-A14884F53216")
+ ICLRMetaHost : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetRuntime(
+ /* [in] */ LPCWSTR pwzVersion,
+ /* [in] */ REFIID riid,
+ /* [retval][iid_is][out] */ LPVOID *ppRuntime) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetVersionFromFile(
+ /* [in] */ LPCWSTR pwzFilePath,
+ /* [annotation][size_is][out] */
+ _Out_writes_all_(*pcchBuffer) LPWSTR pwzBuffer,
+ /* [out][in] */ DWORD *pcchBuffer) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnumerateInstalledRuntimes(
+ /* [retval][out] */ IEnumUnknown **ppEnumerator) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnumerateLoadedRuntimes(
+ /* [in] */ HANDLE hndProcess,
+ /* [retval][out] */ IEnumUnknown **ppEnumerator) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE RequestRuntimeLoadedNotification(
+ /* [in] */ RuntimeLoadedCallbackFnPtr pCallbackFunction) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE QueryLegacyV2RuntimeBinding(
+ /* [in] */ REFIID riid,
+ /* [retval][iid_is][out] */ LPVOID *ppUnk) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ExitProcess(
+ /* [in] */ INT32 iExitCode) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICLRMetaHostVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICLRMetaHost * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICLRMetaHost * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICLRMetaHost * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetRuntime )(
+ ICLRMetaHost * This,
+ /* [in] */ LPCWSTR pwzVersion,
+ /* [in] */ REFIID riid,
+ /* [retval][iid_is][out] */ LPVOID *ppRuntime);
+
+ HRESULT ( STDMETHODCALLTYPE *GetVersionFromFile )(
+ ICLRMetaHost * This,
+ /* [in] */ LPCWSTR pwzFilePath,
+ /* [annotation][size_is][out] */
+ _Out_writes_all_(*pcchBuffer) LPWSTR pwzBuffer,
+ /* [out][in] */ DWORD *pcchBuffer);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumerateInstalledRuntimes )(
+ ICLRMetaHost * This,
+ /* [retval][out] */ IEnumUnknown **ppEnumerator);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumerateLoadedRuntimes )(
+ ICLRMetaHost * This,
+ /* [in] */ HANDLE hndProcess,
+ /* [retval][out] */ IEnumUnknown **ppEnumerator);
+
+ HRESULT ( STDMETHODCALLTYPE *RequestRuntimeLoadedNotification )(
+ ICLRMetaHost * This,
+ /* [in] */ RuntimeLoadedCallbackFnPtr pCallbackFunction);
+
+ HRESULT ( STDMETHODCALLTYPE *QueryLegacyV2RuntimeBinding )(
+ ICLRMetaHost * This,
+ /* [in] */ REFIID riid,
+ /* [retval][iid_is][out] */ LPVOID *ppUnk);
+
+ HRESULT ( STDMETHODCALLTYPE *ExitProcess )(
+ ICLRMetaHost * This,
+ /* [in] */ INT32 iExitCode);
+
+ END_INTERFACE
+ } ICLRMetaHostVtbl;
+
+ interface ICLRMetaHost
+ {
+ CONST_VTBL struct ICLRMetaHostVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICLRMetaHost_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICLRMetaHost_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICLRMetaHost_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICLRMetaHost_GetRuntime(This,pwzVersion,riid,ppRuntime) \
+ ( (This)->lpVtbl -> GetRuntime(This,pwzVersion,riid,ppRuntime) )
+
+#define ICLRMetaHost_GetVersionFromFile(This,pwzFilePath,pwzBuffer,pcchBuffer) \
+ ( (This)->lpVtbl -> GetVersionFromFile(This,pwzFilePath,pwzBuffer,pcchBuffer) )
+
+#define ICLRMetaHost_EnumerateInstalledRuntimes(This,ppEnumerator) \
+ ( (This)->lpVtbl -> EnumerateInstalledRuntimes(This,ppEnumerator) )
+
+#define ICLRMetaHost_EnumerateLoadedRuntimes(This,hndProcess,ppEnumerator) \
+ ( (This)->lpVtbl -> EnumerateLoadedRuntimes(This,hndProcess,ppEnumerator) )
+
+#define ICLRMetaHost_RequestRuntimeLoadedNotification(This,pCallbackFunction) \
+ ( (This)->lpVtbl -> RequestRuntimeLoadedNotification(This,pCallbackFunction) )
+
+#define ICLRMetaHost_QueryLegacyV2RuntimeBinding(This,riid,ppUnk) \
+ ( (This)->lpVtbl -> QueryLegacyV2RuntimeBinding(This,riid,ppUnk) )
+
+#define ICLRMetaHost_ExitProcess(This,iExitCode) \
+ ( (This)->lpVtbl -> ExitProcess(This,iExitCode) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICLRMetaHost_INTERFACE_DEFINED__ */
+
+
+/* interface __MIDL_itf_metahost_0000_0001 */
+/* [local] */
+
+typedef /* [public][public] */
+enum __MIDL___MIDL_itf_metahost_0000_0001_0001
+ {
+ METAHOST_POLICY_HIGHCOMPAT = 0,
+ METAHOST_POLICY_APPLY_UPGRADE_POLICY = 0x8,
+ METAHOST_POLICY_EMULATE_EXE_LAUNCH = 0x10,
+ METAHOST_POLICY_SHOW_ERROR_DIALOG = 0x20,
+ METAHOST_POLICY_USE_PROCESS_IMAGE_PATH = 0x40,
+ METAHOST_POLICY_ENSURE_SKU_SUPPORTED = 0x80,
+ METAHOST_POLICY_IGNORE_ERROR_MODE = 0x1000
+ } METAHOST_POLICY_FLAGS;
+
+typedef /* [public] */
+enum __MIDL___MIDL_itf_metahost_0000_0001_0002
+ {
+ METAHOST_CONFIG_FLAGS_LEGACY_V2_ACTIVATION_POLICY_UNSET = 0,
+ METAHOST_CONFIG_FLAGS_LEGACY_V2_ACTIVATION_POLICY_TRUE = 0x1,
+ METAHOST_CONFIG_FLAGS_LEGACY_V2_ACTIVATION_POLICY_FALSE = 0x2,
+ METAHOST_CONFIG_FLAGS_LEGACY_V2_ACTIVATION_POLICY_MASK = 0x3
+ } METAHOST_CONFIG_FLAGS;
+
+
+
+extern RPC_IF_HANDLE __MIDL_itf_metahost_0000_0001_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_metahost_0000_0001_v0_0_s_ifspec;
+
+#ifndef __ICLRMetaHostPolicy_INTERFACE_DEFINED__
+#define __ICLRMetaHostPolicy_INTERFACE_DEFINED__
+
+/* interface ICLRMetaHostPolicy */
+/* [object][local][helpstring][version][uuid] */
+
+
+EXTERN_C const IID IID_ICLRMetaHostPolicy;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("E2190695-77B2-492e-8E14-C4B3A7FDD593")
+ ICLRMetaHostPolicy : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetRequestedRuntime(
+ /* [in] */ METAHOST_POLICY_FLAGS dwPolicyFlags,
+ /* [in] */ LPCWSTR pwzBinary,
+ /* [in] */ IStream *pCfgStream,
+ /* [annotation][size_is][out][in] */
+ _Inout_updates_all_opt_(*pcchVersion) LPWSTR pwzVersion,
+ /* [out][in] */ DWORD *pcchVersion,
+ /* [annotation][size_is][out] */
+ _Out_writes_all_opt_(*pcchImageVersion) LPWSTR pwzImageVersion,
+ /* [out][in] */ DWORD *pcchImageVersion,
+ /* [out] */ DWORD *pdwConfigFlags,
+ /* [in] */ REFIID riid,
+ /* [retval][iid_is][out] */ LPVOID *ppRuntime) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICLRMetaHostPolicyVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICLRMetaHostPolicy * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICLRMetaHostPolicy * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICLRMetaHostPolicy * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetRequestedRuntime )(
+ ICLRMetaHostPolicy * This,
+ /* [in] */ METAHOST_POLICY_FLAGS dwPolicyFlags,
+ /* [in] */ LPCWSTR pwzBinary,
+ /* [in] */ IStream *pCfgStream,
+ /* [annotation][size_is][out][in] */
+ _Inout_updates_all_opt_(*pcchVersion) LPWSTR pwzVersion,
+ /* [out][in] */ DWORD *pcchVersion,
+ /* [annotation][size_is][out] */
+ _Out_writes_all_opt_(*pcchImageVersion) LPWSTR pwzImageVersion,
+ /* [out][in] */ DWORD *pcchImageVersion,
+ /* [out] */ DWORD *pdwConfigFlags,
+ /* [in] */ REFIID riid,
+ /* [retval][iid_is][out] */ LPVOID *ppRuntime);
+
+ END_INTERFACE
+ } ICLRMetaHostPolicyVtbl;
+
+ interface ICLRMetaHostPolicy
+ {
+ CONST_VTBL struct ICLRMetaHostPolicyVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICLRMetaHostPolicy_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICLRMetaHostPolicy_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICLRMetaHostPolicy_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICLRMetaHostPolicy_GetRequestedRuntime(This,dwPolicyFlags,pwzBinary,pCfgStream,pwzVersion,pcchVersion,pwzImageVersion,pcchImageVersion,pdwConfigFlags,riid,ppRuntime) \
+ ( (This)->lpVtbl -> GetRequestedRuntime(This,dwPolicyFlags,pwzBinary,pCfgStream,pwzVersion,pcchVersion,pwzImageVersion,pcchImageVersion,pdwConfigFlags,riid,ppRuntime) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICLRMetaHostPolicy_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICLRProfiling_INTERFACE_DEFINED__
+#define __ICLRProfiling_INTERFACE_DEFINED__
+
+/* interface ICLRProfiling */
+/* [object][local][helpstring][version][uuid] */
+
+
+EXTERN_C const IID IID_ICLRProfiling;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("B349ABE3-B56F-4689-BFCD-76BF39D888EA")
+ ICLRProfiling : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE AttachProfiler(
+ /* [in] */ DWORD dwProfileeProcessID,
+ /* [in] */ DWORD dwMillisecondsMax,
+ /* [in] */ const CLSID *pClsidProfiler,
+ /* [in] */ LPCWSTR wszProfilerPath,
+ /* [size_is][in] */ void *pvClientData,
+ /* [in] */ UINT cbClientData) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICLRProfilingVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICLRProfiling * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICLRProfiling * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICLRProfiling * This);
+
+ HRESULT ( STDMETHODCALLTYPE *AttachProfiler )(
+ ICLRProfiling * This,
+ /* [in] */ DWORD dwProfileeProcessID,
+ /* [in] */ DWORD dwMillisecondsMax,
+ /* [in] */ const CLSID *pClsidProfiler,
+ /* [in] */ LPCWSTR wszProfilerPath,
+ /* [size_is][in] */ void *pvClientData,
+ /* [in] */ UINT cbClientData);
+
+ END_INTERFACE
+ } ICLRProfilingVtbl;
+
+ interface ICLRProfiling
+ {
+ CONST_VTBL struct ICLRProfilingVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICLRProfiling_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICLRProfiling_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICLRProfiling_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICLRProfiling_AttachProfiler(This,dwProfileeProcessID,dwMillisecondsMax,pClsidProfiler,wszProfilerPath,pvClientData,cbClientData) \
+ ( (This)->lpVtbl -> AttachProfiler(This,dwProfileeProcessID,dwMillisecondsMax,pClsidProfiler,wszProfilerPath,pvClientData,cbClientData) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICLRProfiling_INTERFACE_DEFINED__ */
+
+
+/* interface __MIDL_itf_metahost_0000_0003 */
+/* [local] */
+
+typedef struct _CLR_DEBUGGING_VERSION
+ {
+ WORD wStructVersion;
+ WORD wMajor;
+ WORD wMinor;
+ WORD wBuild;
+ WORD wRevision;
+ } CLR_DEBUGGING_VERSION;
+
+typedef /* [public][public] */
+enum __MIDL___MIDL_itf_metahost_0000_0003_0001
+ {
+ CLR_DEBUGGING_MANAGED_EVENT_PENDING = 1,
+ CLR_DEBUGGING_MANAGED_EVENT_DEBUGGER_LAUNCH = 2
+ } CLR_DEBUGGING_PROCESS_FLAGS;
+
+
+
+extern RPC_IF_HANDLE __MIDL_itf_metahost_0000_0003_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_metahost_0000_0003_v0_0_s_ifspec;
+
+#ifndef __ICLRDebuggingLibraryProvider_INTERFACE_DEFINED__
+#define __ICLRDebuggingLibraryProvider_INTERFACE_DEFINED__
+
+/* interface ICLRDebuggingLibraryProvider */
+/* [object][local][helpstring][version][uuid] */
+
+
+EXTERN_C const IID IID_ICLRDebuggingLibraryProvider;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("3151C08D-4D09-4f9b-8838-2880BF18FE51")
+ ICLRDebuggingLibraryProvider : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE ProvideLibrary(
+ /* [in] */ const WCHAR *pwszFileName,
+ /* [in] */ DWORD dwTimestamp,
+ /* [in] */ DWORD dwSizeOfImage,
+ /* [out] */ HMODULE *phModule) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICLRDebuggingLibraryProviderVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICLRDebuggingLibraryProvider * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICLRDebuggingLibraryProvider * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICLRDebuggingLibraryProvider * This);
+
+ HRESULT ( STDMETHODCALLTYPE *ProvideLibrary )(
+ ICLRDebuggingLibraryProvider * This,
+ /* [in] */ const WCHAR *pwszFileName,
+ /* [in] */ DWORD dwTimestamp,
+ /* [in] */ DWORD dwSizeOfImage,
+ /* [out] */ HMODULE *phModule);
+
+ END_INTERFACE
+ } ICLRDebuggingLibraryProviderVtbl;
+
+ interface ICLRDebuggingLibraryProvider
+ {
+ CONST_VTBL struct ICLRDebuggingLibraryProviderVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICLRDebuggingLibraryProvider_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICLRDebuggingLibraryProvider_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICLRDebuggingLibraryProvider_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICLRDebuggingLibraryProvider_ProvideLibrary(This,pwszFileName,dwTimestamp,dwSizeOfImage,phModule) \
+ ( (This)->lpVtbl -> ProvideLibrary(This,pwszFileName,dwTimestamp,dwSizeOfImage,phModule) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICLRDebuggingLibraryProvider_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICLRDebugging_INTERFACE_DEFINED__
+#define __ICLRDebugging_INTERFACE_DEFINED__
+
+/* interface ICLRDebugging */
+/* [object][local][helpstring][version][uuid] */
+
+
+EXTERN_C const IID IID_ICLRDebugging;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("D28F3C5A-9634-4206-A509-477552EEFB10")
+ ICLRDebugging : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE OpenVirtualProcess(
+ /* [in] */ ULONG64 moduleBaseAddress,
+ /* [in] */ IUnknown *pDataTarget,
+ /* [in] */ ICLRDebuggingLibraryProvider *pLibraryProvider,
+ /* [in] */ CLR_DEBUGGING_VERSION *pMaxDebuggerSupportedVersion,
+ /* [in] */ REFIID riidProcess,
+ /* [iid_is][out] */ IUnknown **ppProcess,
+ /* [out][in] */ CLR_DEBUGGING_VERSION *pVersion,
+ /* [out] */ CLR_DEBUGGING_PROCESS_FLAGS *pdwFlags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE CanUnloadNow(
+ HMODULE hModule) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICLRDebuggingVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICLRDebugging * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICLRDebugging * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICLRDebugging * This);
+
+ HRESULT ( STDMETHODCALLTYPE *OpenVirtualProcess )(
+ ICLRDebugging * This,
+ /* [in] */ ULONG64 moduleBaseAddress,
+ /* [in] */ IUnknown *pDataTarget,
+ /* [in] */ ICLRDebuggingLibraryProvider *pLibraryProvider,
+ /* [in] */ CLR_DEBUGGING_VERSION *pMaxDebuggerSupportedVersion,
+ /* [in] */ REFIID riidProcess,
+ /* [iid_is][out] */ IUnknown **ppProcess,
+ /* [out][in] */ CLR_DEBUGGING_VERSION *pVersion,
+ /* [out] */ CLR_DEBUGGING_PROCESS_FLAGS *pdwFlags);
+
+ HRESULT ( STDMETHODCALLTYPE *CanUnloadNow )(
+ ICLRDebugging * This,
+ HMODULE hModule);
+
+ END_INTERFACE
+ } ICLRDebuggingVtbl;
+
+ interface ICLRDebugging
+ {
+ CONST_VTBL struct ICLRDebuggingVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICLRDebugging_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICLRDebugging_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICLRDebugging_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICLRDebugging_OpenVirtualProcess(This,moduleBaseAddress,pDataTarget,pLibraryProvider,pMaxDebuggerSupportedVersion,riidProcess,ppProcess,pVersion,pdwFlags) \
+ ( (This)->lpVtbl -> OpenVirtualProcess(This,moduleBaseAddress,pDataTarget,pLibraryProvider,pMaxDebuggerSupportedVersion,riidProcess,ppProcess,pVersion,pdwFlags) )
+
+#define ICLRDebugging_CanUnloadNow(This,hModule) \
+ ( (This)->lpVtbl -> CanUnloadNow(This,hModule) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICLRDebugging_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICLRRuntimeInfo_INTERFACE_DEFINED__
+#define __ICLRRuntimeInfo_INTERFACE_DEFINED__
+
+/* interface ICLRRuntimeInfo */
+/* [object][local][helpstring][version][uuid] */
+
+
+EXTERN_C const IID IID_ICLRRuntimeInfo;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("BD39D1D2-BA2F-486a-89B0-B4B0CB466891")
+ ICLRRuntimeInfo : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetVersionString(
+ /* [annotation][size_is][out] */
+ _Out_writes_all_opt_(*pcchBuffer) LPWSTR pwzBuffer,
+ /* [out][in] */ DWORD *pcchBuffer) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetRuntimeDirectory(
+ /* [annotation][size_is][out] */
+ _Out_writes_all_(*pcchBuffer) LPWSTR pwzBuffer,
+ /* [out][in] */ DWORD *pcchBuffer) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE IsLoaded(
+ /* [in] */ HANDLE hndProcess,
+ /* [retval][out] */ BOOL *pbLoaded) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE LoadErrorString(
+ /* [in] */ UINT iResourceID,
+ /* [annotation][size_is][out] */
+ _Out_writes_all_(*pcchBuffer) LPWSTR pwzBuffer,
+ /* [out][in] */ DWORD *pcchBuffer,
+ /* [lcid][in] */ LONG iLocaleID) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE LoadLibrary(
+ /* [in] */ LPCWSTR pwzDllName,
+ /* [retval][out] */ HMODULE *phndModule) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetProcAddress(
+ /* [in] */ LPCSTR pszProcName,
+ /* [retval][out] */ LPVOID *ppProc) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetInterface(
+ /* [in] */ REFCLSID rclsid,
+ /* [in] */ REFIID riid,
+ /* [retval][iid_is][out] */ LPVOID *ppUnk) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE IsLoadable(
+ /* [retval][out] */ BOOL *pbLoadable) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetDefaultStartupFlags(
+ /* [in] */ DWORD dwStartupFlags,
+ /* [in] */ LPCWSTR pwzHostConfigFile) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetDefaultStartupFlags(
+ /* [out] */ DWORD *pdwStartupFlags,
+ /* [annotation][size_is][out] */
+ _Out_writes_all_opt_(*pcchHostConfigFile) LPWSTR pwzHostConfigFile,
+ /* [out][in] */ DWORD *pcchHostConfigFile) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE BindAsLegacyV2Runtime( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE IsStarted(
+ /* [out] */ BOOL *pbStarted,
+ /* [out] */ DWORD *pdwStartupFlags) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICLRRuntimeInfoVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICLRRuntimeInfo * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICLRRuntimeInfo * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICLRRuntimeInfo * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetVersionString )(
+ ICLRRuntimeInfo * This,
+ /* [annotation][size_is][out] */
+ _Out_writes_all_opt_(*pcchBuffer) LPWSTR pwzBuffer,
+ /* [out][in] */ DWORD *pcchBuffer);
+
+ HRESULT ( STDMETHODCALLTYPE *GetRuntimeDirectory )(
+ ICLRRuntimeInfo * This,
+ /* [annotation][size_is][out] */
+ _Out_writes_all_(*pcchBuffer) LPWSTR pwzBuffer,
+ /* [out][in] */ DWORD *pcchBuffer);
+
+ HRESULT ( STDMETHODCALLTYPE *IsLoaded )(
+ ICLRRuntimeInfo * This,
+ /* [in] */ HANDLE hndProcess,
+ /* [retval][out] */ BOOL *pbLoaded);
+
+ HRESULT ( STDMETHODCALLTYPE *LoadErrorString )(
+ ICLRRuntimeInfo * This,
+ /* [in] */ UINT iResourceID,
+ /* [annotation][size_is][out] */
+ _Out_writes_all_(*pcchBuffer) LPWSTR pwzBuffer,
+ /* [out][in] */ DWORD *pcchBuffer,
+ /* [lcid][in] */ LONG iLocaleID);
+
+ HRESULT ( STDMETHODCALLTYPE *LoadLibrary )(
+ ICLRRuntimeInfo * This,
+ /* [in] */ LPCWSTR pwzDllName,
+ /* [retval][out] */ HMODULE *phndModule);
+
+ HRESULT ( STDMETHODCALLTYPE *GetProcAddress )(
+ ICLRRuntimeInfo * This,
+ /* [in] */ LPCSTR pszProcName,
+ /* [retval][out] */ LPVOID *ppProc);
+
+ HRESULT ( STDMETHODCALLTYPE *GetInterface )(
+ ICLRRuntimeInfo * This,
+ /* [in] */ REFCLSID rclsid,
+ /* [in] */ REFIID riid,
+ /* [retval][iid_is][out] */ LPVOID *ppUnk);
+
+ HRESULT ( STDMETHODCALLTYPE *IsLoadable )(
+ ICLRRuntimeInfo * This,
+ /* [retval][out] */ BOOL *pbLoadable);
+
+ HRESULT ( STDMETHODCALLTYPE *SetDefaultStartupFlags )(
+ ICLRRuntimeInfo * This,
+ /* [in] */ DWORD dwStartupFlags,
+ /* [in] */ LPCWSTR pwzHostConfigFile);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDefaultStartupFlags )(
+ ICLRRuntimeInfo * This,
+ /* [out] */ DWORD *pdwStartupFlags,
+ /* [annotation][size_is][out] */
+ _Out_writes_all_opt_(*pcchHostConfigFile) LPWSTR pwzHostConfigFile,
+ /* [out][in] */ DWORD *pcchHostConfigFile);
+
+ HRESULT ( STDMETHODCALLTYPE *BindAsLegacyV2Runtime )(
+ ICLRRuntimeInfo * This);
+
+ HRESULT ( STDMETHODCALLTYPE *IsStarted )(
+ ICLRRuntimeInfo * This,
+ /* [out] */ BOOL *pbStarted,
+ /* [out] */ DWORD *pdwStartupFlags);
+
+ END_INTERFACE
+ } ICLRRuntimeInfoVtbl;
+
+ interface ICLRRuntimeInfo
+ {
+ CONST_VTBL struct ICLRRuntimeInfoVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICLRRuntimeInfo_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICLRRuntimeInfo_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICLRRuntimeInfo_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICLRRuntimeInfo_GetVersionString(This,pwzBuffer,pcchBuffer) \
+ ( (This)->lpVtbl -> GetVersionString(This,pwzBuffer,pcchBuffer) )
+
+#define ICLRRuntimeInfo_GetRuntimeDirectory(This,pwzBuffer,pcchBuffer) \
+ ( (This)->lpVtbl -> GetRuntimeDirectory(This,pwzBuffer,pcchBuffer) )
+
+#define ICLRRuntimeInfo_IsLoaded(This,hndProcess,pbLoaded) \
+ ( (This)->lpVtbl -> IsLoaded(This,hndProcess,pbLoaded) )
+
+#define ICLRRuntimeInfo_LoadErrorString(This,iResourceID,pwzBuffer,pcchBuffer,iLocaleID) \
+ ( (This)->lpVtbl -> LoadErrorString(This,iResourceID,pwzBuffer,pcchBuffer,iLocaleID) )
+
+#define ICLRRuntimeInfo_LoadLibrary(This,pwzDllName,phndModule) \
+ ( (This)->lpVtbl -> LoadLibrary(This,pwzDllName,phndModule) )
+
+#define ICLRRuntimeInfo_GetProcAddress(This,pszProcName,ppProc) \
+ ( (This)->lpVtbl -> GetProcAddress(This,pszProcName,ppProc) )
+
+#define ICLRRuntimeInfo_GetInterface(This,rclsid,riid,ppUnk) \
+ ( (This)->lpVtbl -> GetInterface(This,rclsid,riid,ppUnk) )
+
+#define ICLRRuntimeInfo_IsLoadable(This,pbLoadable) \
+ ( (This)->lpVtbl -> IsLoadable(This,pbLoadable) )
+
+#define ICLRRuntimeInfo_SetDefaultStartupFlags(This,dwStartupFlags,pwzHostConfigFile) \
+ ( (This)->lpVtbl -> SetDefaultStartupFlags(This,dwStartupFlags,pwzHostConfigFile) )
+
+#define ICLRRuntimeInfo_GetDefaultStartupFlags(This,pdwStartupFlags,pwzHostConfigFile,pcchHostConfigFile) \
+ ( (This)->lpVtbl -> GetDefaultStartupFlags(This,pdwStartupFlags,pwzHostConfigFile,pcchHostConfigFile) )
+
+#define ICLRRuntimeInfo_BindAsLegacyV2Runtime(This) \
+ ( (This)->lpVtbl -> BindAsLegacyV2Runtime(This) )
+
+#define ICLRRuntimeInfo_IsStarted(This,pbStarted,pdwStartupFlags) \
+ ( (This)->lpVtbl -> IsStarted(This,pbStarted,pdwStartupFlags) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICLRRuntimeInfo_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICLRStrongName_INTERFACE_DEFINED__
+#define __ICLRStrongName_INTERFACE_DEFINED__
+
+/* interface ICLRStrongName */
+/* [object][local][helpstring][version][uuid] */
+
+
+EXTERN_C const IID IID_ICLRStrongName;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("9FD93CCF-3280-4391-B3A9-96E1CDE77C8D")
+ ICLRStrongName : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetHashFromAssemblyFile(
+ /* [in] */ LPCSTR pszFilePath,
+ /* [out][in] */ unsigned int *piHashAlg,
+ /* [length_is][size_is][out] */ BYTE *pbHash,
+ /* [in] */ DWORD cchHash,
+ /* [out] */ DWORD *pchHash) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetHashFromAssemblyFileW(
+ /* [in] */ LPCWSTR pwzFilePath,
+ /* [out][in] */ unsigned int *piHashAlg,
+ /* [length_is][size_is][out] */ BYTE *pbHash,
+ /* [in] */ DWORD cchHash,
+ /* [out] */ DWORD *pchHash) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetHashFromBlob(
+ /* [in] */ BYTE *pbBlob,
+ /* [in] */ DWORD cchBlob,
+ /* [out][in] */ unsigned int *piHashAlg,
+ /* [length_is][size_is][out] */ BYTE *pbHash,
+ /* [in] */ DWORD cchHash,
+ /* [out] */ DWORD *pchHash) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetHashFromFile(
+ /* [in] */ LPCSTR pszFilePath,
+ /* [out][in] */ unsigned int *piHashAlg,
+ /* [length_is][size_is][out] */ BYTE *pbHash,
+ /* [in] */ DWORD cchHash,
+ /* [out] */ DWORD *pchHash) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetHashFromFileW(
+ /* [in] */ LPCWSTR pwzFilePath,
+ /* [out][in] */ unsigned int *piHashAlg,
+ /* [length_is][size_is][out] */ BYTE *pbHash,
+ /* [in] */ DWORD cchHash,
+ /* [out] */ DWORD *pchHash) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetHashFromHandle(
+ /* [in] */ HANDLE hFile,
+ /* [out][in] */ unsigned int *piHashAlg,
+ /* [length_is][size_is][out] */ BYTE *pbHash,
+ /* [in] */ DWORD cchHash,
+ /* [out] */ DWORD *pchHash) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StrongNameCompareAssemblies(
+ /* [in] */ LPCWSTR pwzAssembly1,
+ /* [in] */ LPCWSTR pwzAssembly2,
+ /* [retval][out] */ DWORD *pdwResult) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StrongNameFreeBuffer(
+ /* [in] */ BYTE *pbMemory) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StrongNameGetBlob(
+ /* [in] */ LPCWSTR pwzFilePath,
+ /* [length_is][size_is][out][in] */ BYTE *pbBlob,
+ /* [out][in] */ DWORD *pcbBlob) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StrongNameGetBlobFromImage(
+ /* [size_is][in] */ BYTE *pbBase,
+ /* [in] */ DWORD dwLength,
+ /* [length_is][size_is][out] */ BYTE *pbBlob,
+ /* [out][in] */ DWORD *pcbBlob) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StrongNameGetPublicKey(
+ /* [in] */ LPCWSTR pwzKeyContainer,
+ /* [in] */ BYTE *pbKeyBlob,
+ /* [in] */ ULONG cbKeyBlob,
+ /* [out] */ BYTE **ppbPublicKeyBlob,
+ /* [out] */ ULONG *pcbPublicKeyBlob) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StrongNameHashSize(
+ /* [in] */ ULONG ulHashAlg,
+ /* [retval][out] */ DWORD *pcbSize) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StrongNameKeyDelete(
+ /* [in] */ LPCWSTR pwzKeyContainer) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StrongNameKeyGen(
+ /* [in] */ LPCWSTR pwzKeyContainer,
+ /* [in] */ DWORD dwFlags,
+ /* [out] */ BYTE **ppbKeyBlob,
+ /* [out] */ ULONG *pcbKeyBlob) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StrongNameKeyGenEx(
+ /* [in] */ LPCWSTR pwzKeyContainer,
+ /* [in] */ DWORD dwFlags,
+ /* [in] */ DWORD dwKeySize,
+ /* [out] */ BYTE **ppbKeyBlob,
+ /* [out] */ ULONG *pcbKeyBlob) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StrongNameKeyInstall(
+ /* [in] */ LPCWSTR pwzKeyContainer,
+ /* [in] */ BYTE *pbKeyBlob,
+ /* [in] */ ULONG cbKeyBlob) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StrongNameSignatureGeneration(
+ /* [in] */ LPCWSTR pwzFilePath,
+ /* [in] */ LPCWSTR pwzKeyContainer,
+ /* [in] */ BYTE *pbKeyBlob,
+ /* [in] */ ULONG cbKeyBlob,
+ /* [out] */ BYTE **ppbSignatureBlob,
+ /* [out] */ ULONG *pcbSignatureBlob) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StrongNameSignatureGenerationEx(
+ /* [in] */ LPCWSTR wszFilePath,
+ /* [in] */ LPCWSTR wszKeyContainer,
+ /* [in] */ BYTE *pbKeyBlob,
+ /* [in] */ ULONG cbKeyBlob,
+ /* [out] */ BYTE **ppbSignatureBlob,
+ /* [out] */ ULONG *pcbSignatureBlob,
+ /* [in] */ DWORD dwFlags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StrongNameSignatureSize(
+ /* [in] */ BYTE *pbPublicKeyBlob,
+ /* [in] */ ULONG cbPublicKeyBlob,
+ /* [in] */ DWORD *pcbSize) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StrongNameSignatureVerification(
+ /* [in] */ LPCWSTR pwzFilePath,
+ /* [in] */ DWORD dwInFlags,
+ /* [retval][out] */ DWORD *pdwOutFlags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StrongNameSignatureVerificationEx(
+ /* [in] */ LPCWSTR pwzFilePath,
+ /* [in] */ BOOLEAN fForceVerification,
+ /* [retval][out] */ BOOLEAN *pfWasVerified) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StrongNameSignatureVerificationFromImage(
+ /* [in] */ BYTE *pbBase,
+ /* [in] */ DWORD dwLength,
+ /* [in] */ DWORD dwInFlags,
+ /* [retval][out] */ DWORD *pdwOutFlags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StrongNameTokenFromAssembly(
+ /* [in] */ LPCWSTR pwzFilePath,
+ /* [out] */ BYTE **ppbStrongNameToken,
+ /* [out] */ ULONG *pcbStrongNameToken) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StrongNameTokenFromAssemblyEx(
+ /* [in] */ LPCWSTR pwzFilePath,
+ /* [out] */ BYTE **ppbStrongNameToken,
+ /* [out] */ ULONG *pcbStrongNameToken,
+ /* [out] */ BYTE **ppbPublicKeyBlob,
+ /* [out] */ ULONG *pcbPublicKeyBlob) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StrongNameTokenFromPublicKey(
+ /* [in] */ BYTE *pbPublicKeyBlob,
+ /* [in] */ ULONG cbPublicKeyBlob,
+ /* [out] */ BYTE **ppbStrongNameToken,
+ /* [out] */ ULONG *pcbStrongNameToken) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICLRStrongNameVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICLRStrongName * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICLRStrongName * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICLRStrongName * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetHashFromAssemblyFile )(
+ ICLRStrongName * This,
+ /* [in] */ LPCSTR pszFilePath,
+ /* [out][in] */ unsigned int *piHashAlg,
+ /* [length_is][size_is][out] */ BYTE *pbHash,
+ /* [in] */ DWORD cchHash,
+ /* [out] */ DWORD *pchHash);
+
+ HRESULT ( STDMETHODCALLTYPE *GetHashFromAssemblyFileW )(
+ ICLRStrongName * This,
+ /* [in] */ LPCWSTR pwzFilePath,
+ /* [out][in] */ unsigned int *piHashAlg,
+ /* [length_is][size_is][out] */ BYTE *pbHash,
+ /* [in] */ DWORD cchHash,
+ /* [out] */ DWORD *pchHash);
+
+ HRESULT ( STDMETHODCALLTYPE *GetHashFromBlob )(
+ ICLRStrongName * This,
+ /* [in] */ BYTE *pbBlob,
+ /* [in] */ DWORD cchBlob,
+ /* [out][in] */ unsigned int *piHashAlg,
+ /* [length_is][size_is][out] */ BYTE *pbHash,
+ /* [in] */ DWORD cchHash,
+ /* [out] */ DWORD *pchHash);
+
+ HRESULT ( STDMETHODCALLTYPE *GetHashFromFile )(
+ ICLRStrongName * This,
+ /* [in] */ LPCSTR pszFilePath,
+ /* [out][in] */ unsigned int *piHashAlg,
+ /* [length_is][size_is][out] */ BYTE *pbHash,
+ /* [in] */ DWORD cchHash,
+ /* [out] */ DWORD *pchHash);
+
+ HRESULT ( STDMETHODCALLTYPE *GetHashFromFileW )(
+ ICLRStrongName * This,
+ /* [in] */ LPCWSTR pwzFilePath,
+ /* [out][in] */ unsigned int *piHashAlg,
+ /* [length_is][size_is][out] */ BYTE *pbHash,
+ /* [in] */ DWORD cchHash,
+ /* [out] */ DWORD *pchHash);
+
+ HRESULT ( STDMETHODCALLTYPE *GetHashFromHandle )(
+ ICLRStrongName * This,
+ /* [in] */ HANDLE hFile,
+ /* [out][in] */ unsigned int *piHashAlg,
+ /* [length_is][size_is][out] */ BYTE *pbHash,
+ /* [in] */ DWORD cchHash,
+ /* [out] */ DWORD *pchHash);
+
+ HRESULT ( STDMETHODCALLTYPE *StrongNameCompareAssemblies )(
+ ICLRStrongName * This,
+ /* [in] */ LPCWSTR pwzAssembly1,
+ /* [in] */ LPCWSTR pwzAssembly2,
+ /* [retval][out] */ DWORD *pdwResult);
+
+ HRESULT ( STDMETHODCALLTYPE *StrongNameFreeBuffer )(
+ ICLRStrongName * This,
+ /* [in] */ BYTE *pbMemory);
+
+ HRESULT ( STDMETHODCALLTYPE *StrongNameGetBlob )(
+ ICLRStrongName * This,
+ /* [in] */ LPCWSTR pwzFilePath,
+ /* [length_is][size_is][out][in] */ BYTE *pbBlob,
+ /* [out][in] */ DWORD *pcbBlob);
+
+ HRESULT ( STDMETHODCALLTYPE *StrongNameGetBlobFromImage )(
+ ICLRStrongName * This,
+ /* [size_is][in] */ BYTE *pbBase,
+ /* [in] */ DWORD dwLength,
+ /* [length_is][size_is][out] */ BYTE *pbBlob,
+ /* [out][in] */ DWORD *pcbBlob);
+
+ HRESULT ( STDMETHODCALLTYPE *StrongNameGetPublicKey )(
+ ICLRStrongName * This,
+ /* [in] */ LPCWSTR pwzKeyContainer,
+ /* [in] */ BYTE *pbKeyBlob,
+ /* [in] */ ULONG cbKeyBlob,
+ /* [out] */ BYTE **ppbPublicKeyBlob,
+ /* [out] */ ULONG *pcbPublicKeyBlob);
+
+ HRESULT ( STDMETHODCALLTYPE *StrongNameHashSize )(
+ ICLRStrongName * This,
+ /* [in] */ ULONG ulHashAlg,
+ /* [retval][out] */ DWORD *pcbSize);
+
+ HRESULT ( STDMETHODCALLTYPE *StrongNameKeyDelete )(
+ ICLRStrongName * This,
+ /* [in] */ LPCWSTR pwzKeyContainer);
+
+ HRESULT ( STDMETHODCALLTYPE *StrongNameKeyGen )(
+ ICLRStrongName * This,
+ /* [in] */ LPCWSTR pwzKeyContainer,
+ /* [in] */ DWORD dwFlags,
+ /* [out] */ BYTE **ppbKeyBlob,
+ /* [out] */ ULONG *pcbKeyBlob);
+
+ HRESULT ( STDMETHODCALLTYPE *StrongNameKeyGenEx )(
+ ICLRStrongName * This,
+ /* [in] */ LPCWSTR pwzKeyContainer,
+ /* [in] */ DWORD dwFlags,
+ /* [in] */ DWORD dwKeySize,
+ /* [out] */ BYTE **ppbKeyBlob,
+ /* [out] */ ULONG *pcbKeyBlob);
+
+ HRESULT ( STDMETHODCALLTYPE *StrongNameKeyInstall )(
+ ICLRStrongName * This,
+ /* [in] */ LPCWSTR pwzKeyContainer,
+ /* [in] */ BYTE *pbKeyBlob,
+ /* [in] */ ULONG cbKeyBlob);
+
+ HRESULT ( STDMETHODCALLTYPE *StrongNameSignatureGeneration )(
+ ICLRStrongName * This,
+ /* [in] */ LPCWSTR pwzFilePath,
+ /* [in] */ LPCWSTR pwzKeyContainer,
+ /* [in] */ BYTE *pbKeyBlob,
+ /* [in] */ ULONG cbKeyBlob,
+ /* [out] */ BYTE **ppbSignatureBlob,
+ /* [out] */ ULONG *pcbSignatureBlob);
+
+ HRESULT ( STDMETHODCALLTYPE *StrongNameSignatureGenerationEx )(
+ ICLRStrongName * This,
+ /* [in] */ LPCWSTR wszFilePath,
+ /* [in] */ LPCWSTR wszKeyContainer,
+ /* [in] */ BYTE *pbKeyBlob,
+ /* [in] */ ULONG cbKeyBlob,
+ /* [out] */ BYTE **ppbSignatureBlob,
+ /* [out] */ ULONG *pcbSignatureBlob,
+ /* [in] */ DWORD dwFlags);
+
+ HRESULT ( STDMETHODCALLTYPE *StrongNameSignatureSize )(
+ ICLRStrongName * This,
+ /* [in] */ BYTE *pbPublicKeyBlob,
+ /* [in] */ ULONG cbPublicKeyBlob,
+ /* [in] */ DWORD *pcbSize);
+
+ HRESULT ( STDMETHODCALLTYPE *StrongNameSignatureVerification )(
+ ICLRStrongName * This,
+ /* [in] */ LPCWSTR pwzFilePath,
+ /* [in] */ DWORD dwInFlags,
+ /* [retval][out] */ DWORD *pdwOutFlags);
+
+ HRESULT ( STDMETHODCALLTYPE *StrongNameSignatureVerificationEx )(
+ ICLRStrongName * This,
+ /* [in] */ LPCWSTR pwzFilePath,
+ /* [in] */ BOOLEAN fForceVerification,
+ /* [retval][out] */ BOOLEAN *pfWasVerified);
+
+ HRESULT ( STDMETHODCALLTYPE *StrongNameSignatureVerificationFromImage )(
+ ICLRStrongName * This,
+ /* [in] */ BYTE *pbBase,
+ /* [in] */ DWORD dwLength,
+ /* [in] */ DWORD dwInFlags,
+ /* [retval][out] */ DWORD *pdwOutFlags);
+
+ HRESULT ( STDMETHODCALLTYPE *StrongNameTokenFromAssembly )(
+ ICLRStrongName * This,
+ /* [in] */ LPCWSTR pwzFilePath,
+ /* [out] */ BYTE **ppbStrongNameToken,
+ /* [out] */ ULONG *pcbStrongNameToken);
+
+ HRESULT ( STDMETHODCALLTYPE *StrongNameTokenFromAssemblyEx )(
+ ICLRStrongName * This,
+ /* [in] */ LPCWSTR pwzFilePath,
+ /* [out] */ BYTE **ppbStrongNameToken,
+ /* [out] */ ULONG *pcbStrongNameToken,
+ /* [out] */ BYTE **ppbPublicKeyBlob,
+ /* [out] */ ULONG *pcbPublicKeyBlob);
+
+ HRESULT ( STDMETHODCALLTYPE *StrongNameTokenFromPublicKey )(
+ ICLRStrongName * This,
+ /* [in] */ BYTE *pbPublicKeyBlob,
+ /* [in] */ ULONG cbPublicKeyBlob,
+ /* [out] */ BYTE **ppbStrongNameToken,
+ /* [out] */ ULONG *pcbStrongNameToken);
+
+ END_INTERFACE
+ } ICLRStrongNameVtbl;
+
+ interface ICLRStrongName
+ {
+ CONST_VTBL struct ICLRStrongNameVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICLRStrongName_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICLRStrongName_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICLRStrongName_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICLRStrongName_GetHashFromAssemblyFile(This,pszFilePath,piHashAlg,pbHash,cchHash,pchHash) \
+ ( (This)->lpVtbl -> GetHashFromAssemblyFile(This,pszFilePath,piHashAlg,pbHash,cchHash,pchHash) )
+
+#define ICLRStrongName_GetHashFromAssemblyFileW(This,pwzFilePath,piHashAlg,pbHash,cchHash,pchHash) \
+ ( (This)->lpVtbl -> GetHashFromAssemblyFileW(This,pwzFilePath,piHashAlg,pbHash,cchHash,pchHash) )
+
+#define ICLRStrongName_GetHashFromBlob(This,pbBlob,cchBlob,piHashAlg,pbHash,cchHash,pchHash) \
+ ( (This)->lpVtbl -> GetHashFromBlob(This,pbBlob,cchBlob,piHashAlg,pbHash,cchHash,pchHash) )
+
+#define ICLRStrongName_GetHashFromFile(This,pszFilePath,piHashAlg,pbHash,cchHash,pchHash) \
+ ( (This)->lpVtbl -> GetHashFromFile(This,pszFilePath,piHashAlg,pbHash,cchHash,pchHash) )
+
+#define ICLRStrongName_GetHashFromFileW(This,pwzFilePath,piHashAlg,pbHash,cchHash,pchHash) \
+ ( (This)->lpVtbl -> GetHashFromFileW(This,pwzFilePath,piHashAlg,pbHash,cchHash,pchHash) )
+
+#define ICLRStrongName_GetHashFromHandle(This,hFile,piHashAlg,pbHash,cchHash,pchHash) \
+ ( (This)->lpVtbl -> GetHashFromHandle(This,hFile,piHashAlg,pbHash,cchHash,pchHash) )
+
+#define ICLRStrongName_StrongNameCompareAssemblies(This,pwzAssembly1,pwzAssembly2,pdwResult) \
+ ( (This)->lpVtbl -> StrongNameCompareAssemblies(This,pwzAssembly1,pwzAssembly2,pdwResult) )
+
+#define ICLRStrongName_StrongNameFreeBuffer(This,pbMemory) \
+ ( (This)->lpVtbl -> StrongNameFreeBuffer(This,pbMemory) )
+
+#define ICLRStrongName_StrongNameGetBlob(This,pwzFilePath,pbBlob,pcbBlob) \
+ ( (This)->lpVtbl -> StrongNameGetBlob(This,pwzFilePath,pbBlob,pcbBlob) )
+
+#define ICLRStrongName_StrongNameGetBlobFromImage(This,pbBase,dwLength,pbBlob,pcbBlob) \
+ ( (This)->lpVtbl -> StrongNameGetBlobFromImage(This,pbBase,dwLength,pbBlob,pcbBlob) )
+
+#define ICLRStrongName_StrongNameGetPublicKey(This,pwzKeyContainer,pbKeyBlob,cbKeyBlob,ppbPublicKeyBlob,pcbPublicKeyBlob) \
+ ( (This)->lpVtbl -> StrongNameGetPublicKey(This,pwzKeyContainer,pbKeyBlob,cbKeyBlob,ppbPublicKeyBlob,pcbPublicKeyBlob) )
+
+#define ICLRStrongName_StrongNameHashSize(This,ulHashAlg,pcbSize) \
+ ( (This)->lpVtbl -> StrongNameHashSize(This,ulHashAlg,pcbSize) )
+
+#define ICLRStrongName_StrongNameKeyDelete(This,pwzKeyContainer) \
+ ( (This)->lpVtbl -> StrongNameKeyDelete(This,pwzKeyContainer) )
+
+#define ICLRStrongName_StrongNameKeyGen(This,pwzKeyContainer,dwFlags,ppbKeyBlob,pcbKeyBlob) \
+ ( (This)->lpVtbl -> StrongNameKeyGen(This,pwzKeyContainer,dwFlags,ppbKeyBlob,pcbKeyBlob) )
+
+#define ICLRStrongName_StrongNameKeyGenEx(This,pwzKeyContainer,dwFlags,dwKeySize,ppbKeyBlob,pcbKeyBlob) \
+ ( (This)->lpVtbl -> StrongNameKeyGenEx(This,pwzKeyContainer,dwFlags,dwKeySize,ppbKeyBlob,pcbKeyBlob) )
+
+#define ICLRStrongName_StrongNameKeyInstall(This,pwzKeyContainer,pbKeyBlob,cbKeyBlob) \
+ ( (This)->lpVtbl -> StrongNameKeyInstall(This,pwzKeyContainer,pbKeyBlob,cbKeyBlob) )
+
+#define ICLRStrongName_StrongNameSignatureGeneration(This,pwzFilePath,pwzKeyContainer,pbKeyBlob,cbKeyBlob,ppbSignatureBlob,pcbSignatureBlob) \
+ ( (This)->lpVtbl -> StrongNameSignatureGeneration(This,pwzFilePath,pwzKeyContainer,pbKeyBlob,cbKeyBlob,ppbSignatureBlob,pcbSignatureBlob) )
+
+#define ICLRStrongName_StrongNameSignatureGenerationEx(This,wszFilePath,wszKeyContainer,pbKeyBlob,cbKeyBlob,ppbSignatureBlob,pcbSignatureBlob,dwFlags) \
+ ( (This)->lpVtbl -> StrongNameSignatureGenerationEx(This,wszFilePath,wszKeyContainer,pbKeyBlob,cbKeyBlob,ppbSignatureBlob,pcbSignatureBlob,dwFlags) )
+
+#define ICLRStrongName_StrongNameSignatureSize(This,pbPublicKeyBlob,cbPublicKeyBlob,pcbSize) \
+ ( (This)->lpVtbl -> StrongNameSignatureSize(This,pbPublicKeyBlob,cbPublicKeyBlob,pcbSize) )
+
+#define ICLRStrongName_StrongNameSignatureVerification(This,pwzFilePath,dwInFlags,pdwOutFlags) \
+ ( (This)->lpVtbl -> StrongNameSignatureVerification(This,pwzFilePath,dwInFlags,pdwOutFlags) )
+
+#define ICLRStrongName_StrongNameSignatureVerificationEx(This,pwzFilePath,fForceVerification,pfWasVerified) \
+ ( (This)->lpVtbl -> StrongNameSignatureVerificationEx(This,pwzFilePath,fForceVerification,pfWasVerified) )
+
+#define ICLRStrongName_StrongNameSignatureVerificationFromImage(This,pbBase,dwLength,dwInFlags,pdwOutFlags) \
+ ( (This)->lpVtbl -> StrongNameSignatureVerificationFromImage(This,pbBase,dwLength,dwInFlags,pdwOutFlags) )
+
+#define ICLRStrongName_StrongNameTokenFromAssembly(This,pwzFilePath,ppbStrongNameToken,pcbStrongNameToken) \
+ ( (This)->lpVtbl -> StrongNameTokenFromAssembly(This,pwzFilePath,ppbStrongNameToken,pcbStrongNameToken) )
+
+#define ICLRStrongName_StrongNameTokenFromAssemblyEx(This,pwzFilePath,ppbStrongNameToken,pcbStrongNameToken,ppbPublicKeyBlob,pcbPublicKeyBlob) \
+ ( (This)->lpVtbl -> StrongNameTokenFromAssemblyEx(This,pwzFilePath,ppbStrongNameToken,pcbStrongNameToken,ppbPublicKeyBlob,pcbPublicKeyBlob) )
+
+#define ICLRStrongName_StrongNameTokenFromPublicKey(This,pbPublicKeyBlob,cbPublicKeyBlob,ppbStrongNameToken,pcbStrongNameToken) \
+ ( (This)->lpVtbl -> StrongNameTokenFromPublicKey(This,pbPublicKeyBlob,cbPublicKeyBlob,ppbStrongNameToken,pcbStrongNameToken) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICLRStrongName_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICLRStrongName2_INTERFACE_DEFINED__
+#define __ICLRStrongName2_INTERFACE_DEFINED__
+
+/* interface ICLRStrongName2 */
+/* [object][local][helpstring][version][uuid] */
+
+
+EXTERN_C const IID IID_ICLRStrongName2;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("C22ED5C5-4B59-4975-90EB-85EA55C0069B")
+ ICLRStrongName2 : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE StrongNameGetPublicKeyEx(
+ /* [in] */ LPCWSTR pwzKeyContainer,
+ /* [in] */ BYTE *pbKeyBlob,
+ /* [in] */ ULONG cbKeyBlob,
+ /* [out] */ BYTE **ppbPublicKeyBlob,
+ /* [out] */ ULONG *pcbPublicKeyBlob,
+ /* [in] */ ULONG uHashAlgId,
+ /* [in] */ ULONG uReserved) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StrongNameSignatureVerificationEx2(
+ /* [in] */ LPCWSTR wszFilePath,
+ /* [in] */ BOOLEAN fForceVerification,
+ /* [in] */ BYTE *pbEcmaPublicKey,
+ /* [in] */ DWORD cbEcmaPublicKey,
+ /* [out] */ BOOLEAN *pfWasVerified) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICLRStrongName2Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICLRStrongName2 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICLRStrongName2 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICLRStrongName2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *StrongNameGetPublicKeyEx )(
+ ICLRStrongName2 * This,
+ /* [in] */ LPCWSTR pwzKeyContainer,
+ /* [in] */ BYTE *pbKeyBlob,
+ /* [in] */ ULONG cbKeyBlob,
+ /* [out] */ BYTE **ppbPublicKeyBlob,
+ /* [out] */ ULONG *pcbPublicKeyBlob,
+ /* [in] */ ULONG uHashAlgId,
+ /* [in] */ ULONG uReserved);
+
+ HRESULT ( STDMETHODCALLTYPE *StrongNameSignatureVerificationEx2 )(
+ ICLRStrongName2 * This,
+ /* [in] */ LPCWSTR wszFilePath,
+ /* [in] */ BOOLEAN fForceVerification,
+ /* [in] */ BYTE *pbEcmaPublicKey,
+ /* [in] */ DWORD cbEcmaPublicKey,
+ /* [out] */ BOOLEAN *pfWasVerified);
+
+ END_INTERFACE
+ } ICLRStrongName2Vtbl;
+
+ interface ICLRStrongName2
+ {
+ CONST_VTBL struct ICLRStrongName2Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICLRStrongName2_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICLRStrongName2_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICLRStrongName2_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICLRStrongName2_StrongNameGetPublicKeyEx(This,pwzKeyContainer,pbKeyBlob,cbKeyBlob,ppbPublicKeyBlob,pcbPublicKeyBlob,uHashAlgId,uReserved) \
+ ( (This)->lpVtbl -> StrongNameGetPublicKeyEx(This,pwzKeyContainer,pbKeyBlob,cbKeyBlob,ppbPublicKeyBlob,pcbPublicKeyBlob,uHashAlgId,uReserved) )
+
+#define ICLRStrongName2_StrongNameSignatureVerificationEx2(This,wszFilePath,fForceVerification,pbEcmaPublicKey,cbEcmaPublicKey,pfWasVerified) \
+ ( (This)->lpVtbl -> StrongNameSignatureVerificationEx2(This,wszFilePath,fForceVerification,pbEcmaPublicKey,cbEcmaPublicKey,pfWasVerified) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICLRStrongName2_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICLRStrongName3_INTERFACE_DEFINED__
+#define __ICLRStrongName3_INTERFACE_DEFINED__
+
+/* interface ICLRStrongName3 */
+/* [object][local][helpstring][version][uuid] */
+
+
+EXTERN_C const IID IID_ICLRStrongName3;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("22c7089b-bbd3-414a-b698-210f263f1fed")
+ ICLRStrongName3 : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE StrongNameDigestGenerate(
+ /* [in] */ LPCWSTR wszFilePath,
+ /* [out] */ BYTE **ppbDigestBlob,
+ /* [out] */ ULONG *pcbDigestBlob,
+ /* [in] */ DWORD dwFlags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StrongNameDigestSign(
+ /* [in] */ LPCWSTR wszKeyContainer,
+ /* [size_is][in] */ BYTE *pbKeyBlob,
+ /* [in] */ ULONG cbKeyBlob,
+ /* [size_is][in] */ BYTE *pbDigestBlob,
+ /* [in] */ ULONG cbDigestBlob,
+ /* [in] */ DWORD hashAlgId,
+ /* [out] */ BYTE **ppbSignatureBlob,
+ /* [out] */ ULONG *pcbSignatureBlob,
+ /* [in] */ DWORD dwFlags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StrongNameDigestEmbed(
+ /* [in] */ LPCWSTR wszFilePath,
+ /* [size_is][in] */ BYTE *pbSignatureBlob,
+ /* [in] */ ULONG cbSignatureBlob) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICLRStrongName3Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICLRStrongName3 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICLRStrongName3 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICLRStrongName3 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *StrongNameDigestGenerate )(
+ ICLRStrongName3 * This,
+ /* [in] */ LPCWSTR wszFilePath,
+ /* [out] */ BYTE **ppbDigestBlob,
+ /* [out] */ ULONG *pcbDigestBlob,
+ /* [in] */ DWORD dwFlags);
+
+ HRESULT ( STDMETHODCALLTYPE *StrongNameDigestSign )(
+ ICLRStrongName3 * This,
+ /* [in] */ LPCWSTR wszKeyContainer,
+ /* [size_is][in] */ BYTE *pbKeyBlob,
+ /* [in] */ ULONG cbKeyBlob,
+ /* [size_is][in] */ BYTE *pbDigestBlob,
+ /* [in] */ ULONG cbDigestBlob,
+ /* [in] */ DWORD hashAlgId,
+ /* [out] */ BYTE **ppbSignatureBlob,
+ /* [out] */ ULONG *pcbSignatureBlob,
+ /* [in] */ DWORD dwFlags);
+
+ HRESULT ( STDMETHODCALLTYPE *StrongNameDigestEmbed )(
+ ICLRStrongName3 * This,
+ /* [in] */ LPCWSTR wszFilePath,
+ /* [size_is][in] */ BYTE *pbSignatureBlob,
+ /* [in] */ ULONG cbSignatureBlob);
+
+ END_INTERFACE
+ } ICLRStrongName3Vtbl;
+
+ interface ICLRStrongName3
+ {
+ CONST_VTBL struct ICLRStrongName3Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICLRStrongName3_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICLRStrongName3_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICLRStrongName3_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICLRStrongName3_StrongNameDigestGenerate(This,wszFilePath,ppbDigestBlob,pcbDigestBlob,dwFlags) \
+ ( (This)->lpVtbl -> StrongNameDigestGenerate(This,wszFilePath,ppbDigestBlob,pcbDigestBlob,dwFlags) )
+
+#define ICLRStrongName3_StrongNameDigestSign(This,wszKeyContainer,pbKeyBlob,cbKeyBlob,pbDigestBlob,cbDigestBlob,hashAlgId,ppbSignatureBlob,pcbSignatureBlob,dwFlags) \
+ ( (This)->lpVtbl -> StrongNameDigestSign(This,wszKeyContainer,pbKeyBlob,cbKeyBlob,pbDigestBlob,cbDigestBlob,hashAlgId,ppbSignatureBlob,pcbSignatureBlob,dwFlags) )
+
+#define ICLRStrongName3_StrongNameDigestEmbed(This,wszFilePath,pbSignatureBlob,cbSignatureBlob) \
+ ( (This)->lpVtbl -> StrongNameDigestEmbed(This,wszFilePath,pbSignatureBlob,cbSignatureBlob) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICLRStrongName3_INTERFACE_DEFINED__ */
+
+
+
+#ifndef __CLRMetaHost_LIBRARY_DEFINED__
+#define __CLRMetaHost_LIBRARY_DEFINED__
+
+/* library CLRMetaHost */
+/* [version][uuid] */
+
+
+
+
+
+
+
+
+
+EXTERN_C const IID LIBID_CLRMetaHost;
+#endif /* __CLRMetaHost_LIBRARY_DEFINED__ */
+
+/* interface __MIDL_itf_metahost_0000_0010 */
+/* [local] */
+
+#endif // WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+
+
+extern RPC_IF_HANDLE __MIDL_itf_metahost_0000_0010_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_metahost_0000_0010_v0_0_s_ifspec;
+
+/* Additional Prototypes for ALL interfaces */
+
+/* end of Additional Prototypes */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+
diff --git a/src/pal/prebuilt/inc/mscoree.h b/src/pal/prebuilt/inc/mscoree.h
new file mode 100644
index 0000000000..12d2172a85
--- /dev/null
+++ b/src/pal/prebuilt/inc/mscoree.h
@@ -0,0 +1,2929 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+
+/* this ALWAYS GENERATED file contains the definitions for the interfaces */
+
+
+ /* File created by MIDL compiler version 8.00.0603 */
+/* @@MIDL_FILE_HEADING( ) */
+
+#pragma warning( disable: 4049 ) /* more than 64k source lines */
+
+
+/* verify that the <rpcndr.h> version is high enough to compile this file*/
+#ifndef __REQUIRED_RPCNDR_H_VERSION__
+#define __REQUIRED_RPCNDR_H_VERSION__ 475
+#endif
+
+#include "rpc.h"
+#include "rpcndr.h"
+
+#ifndef __RPCNDR_H_VERSION__
+#error this stub requires an updated version of <rpcndr.h>
+#endif // __RPCNDR_H_VERSION__
+
+#ifndef COM_NO_WINDOWS_H
+#include "windows.h"
+#include "ole2.h"
+#endif /*COM_NO_WINDOWS_H*/
+
+#ifndef __mscoree_h__
+#define __mscoree_h__
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+/* Forward Declarations */
+
+#ifndef __IDebuggerThreadControl_FWD_DEFINED__
+#define __IDebuggerThreadControl_FWD_DEFINED__
+typedef interface IDebuggerThreadControl IDebuggerThreadControl;
+
+#endif /* __IDebuggerThreadControl_FWD_DEFINED__ */
+
+
+#ifndef __IDebuggerInfo_FWD_DEFINED__
+#define __IDebuggerInfo_FWD_DEFINED__
+typedef interface IDebuggerInfo IDebuggerInfo;
+
+#endif /* __IDebuggerInfo_FWD_DEFINED__ */
+
+
+#ifndef __ICLRErrorReportingManager_FWD_DEFINED__
+#define __ICLRErrorReportingManager_FWD_DEFINED__
+typedef interface ICLRErrorReportingManager ICLRErrorReportingManager;
+
+#endif /* __ICLRErrorReportingManager_FWD_DEFINED__ */
+
+
+#ifndef __ICLRErrorReportingManager2_FWD_DEFINED__
+#define __ICLRErrorReportingManager2_FWD_DEFINED__
+typedef interface ICLRErrorReportingManager2 ICLRErrorReportingManager2;
+
+#endif /* __ICLRErrorReportingManager2_FWD_DEFINED__ */
+
+
+#ifndef __ICLRPolicyManager_FWD_DEFINED__
+#define __ICLRPolicyManager_FWD_DEFINED__
+typedef interface ICLRPolicyManager ICLRPolicyManager;
+
+#endif /* __ICLRPolicyManager_FWD_DEFINED__ */
+
+
+#ifndef __ICLRGCManager_FWD_DEFINED__
+#define __ICLRGCManager_FWD_DEFINED__
+typedef interface ICLRGCManager ICLRGCManager;
+
+#endif /* __ICLRGCManager_FWD_DEFINED__ */
+
+
+#ifndef __ICLRGCManager2_FWD_DEFINED__
+#define __ICLRGCManager2_FWD_DEFINED__
+typedef interface ICLRGCManager2 ICLRGCManager2;
+
+#endif /* __ICLRGCManager2_FWD_DEFINED__ */
+
+
+#ifndef __IHostControl_FWD_DEFINED__
+#define __IHostControl_FWD_DEFINED__
+typedef interface IHostControl IHostControl;
+
+#endif /* __IHostControl_FWD_DEFINED__ */
+
+
+#ifndef __ICLRControl_FWD_DEFINED__
+#define __ICLRControl_FWD_DEFINED__
+typedef interface ICLRControl ICLRControl;
+
+#endif /* __ICLRControl_FWD_DEFINED__ */
+
+
+#ifndef __ICLRRuntimeHost_FWD_DEFINED__
+#define __ICLRRuntimeHost_FWD_DEFINED__
+typedef interface ICLRRuntimeHost ICLRRuntimeHost;
+
+#endif /* __ICLRRuntimeHost_FWD_DEFINED__ */
+
+
+#ifndef __ICLRRuntimeHost2_FWD_DEFINED__
+#define __ICLRRuntimeHost2_FWD_DEFINED__
+typedef interface ICLRRuntimeHost2 ICLRRuntimeHost2;
+
+#endif /* __ICLRRuntimeHost2_FWD_DEFINED__ */
+
+
+#ifndef __ICLRExecutionManager_FWD_DEFINED__
+#define __ICLRExecutionManager_FWD_DEFINED__
+typedef interface ICLRExecutionManager ICLRExecutionManager;
+
+#endif /* __ICLRExecutionManager_FWD_DEFINED__ */
+
+
+#ifndef __IHostNetCFDebugControlManager_FWD_DEFINED__
+#define __IHostNetCFDebugControlManager_FWD_DEFINED__
+typedef interface IHostNetCFDebugControlManager IHostNetCFDebugControlManager;
+
+#endif /* __IHostNetCFDebugControlManager_FWD_DEFINED__ */
+
+
+#ifndef __ITypeName_FWD_DEFINED__
+#define __ITypeName_FWD_DEFINED__
+typedef interface ITypeName ITypeName;
+
+#endif /* __ITypeName_FWD_DEFINED__ */
+
+
+#ifndef __ITypeNameBuilder_FWD_DEFINED__
+#define __ITypeNameBuilder_FWD_DEFINED__
+typedef interface ITypeNameBuilder ITypeNameBuilder;
+
+#endif /* __ITypeNameBuilder_FWD_DEFINED__ */
+
+
+#ifndef __ITypeNameFactory_FWD_DEFINED__
+#define __ITypeNameFactory_FWD_DEFINED__
+typedef interface ITypeNameFactory ITypeNameFactory;
+
+#endif /* __ITypeNameFactory_FWD_DEFINED__ */
+
+
+#ifndef __IManagedObject_FWD_DEFINED__
+#define __IManagedObject_FWD_DEFINED__
+typedef interface IManagedObject IManagedObject;
+
+#endif /* __IManagedObject_FWD_DEFINED__ */
+
+
+#ifndef __ComCallUnmarshal_FWD_DEFINED__
+#define __ComCallUnmarshal_FWD_DEFINED__
+
+#ifdef __cplusplus
+typedef class ComCallUnmarshal ComCallUnmarshal;
+#else
+typedef struct ComCallUnmarshal ComCallUnmarshal;
+#endif /* __cplusplus */
+
+#endif /* __ComCallUnmarshal_FWD_DEFINED__ */
+
+
+#ifndef __ComCallUnmarshalV4_FWD_DEFINED__
+#define __ComCallUnmarshalV4_FWD_DEFINED__
+
+#ifdef __cplusplus
+typedef class ComCallUnmarshalV4 ComCallUnmarshalV4;
+#else
+typedef struct ComCallUnmarshalV4 ComCallUnmarshalV4;
+#endif /* __cplusplus */
+
+#endif /* __ComCallUnmarshalV4_FWD_DEFINED__ */
+
+
+#ifndef __CLRRuntimeHost_FWD_DEFINED__
+#define __CLRRuntimeHost_FWD_DEFINED__
+
+#ifdef __cplusplus
+typedef class CLRRuntimeHost CLRRuntimeHost;
+#else
+typedef struct CLRRuntimeHost CLRRuntimeHost;
+#endif /* __cplusplus */
+
+#endif /* __CLRRuntimeHost_FWD_DEFINED__ */
+
+
+#ifndef __TypeNameFactory_FWD_DEFINED__
+#define __TypeNameFactory_FWD_DEFINED__
+
+#ifdef __cplusplus
+typedef class TypeNameFactory TypeNameFactory;
+#else
+typedef struct TypeNameFactory TypeNameFactory;
+#endif /* __cplusplus */
+
+#endif /* __TypeNameFactory_FWD_DEFINED__ */
+
+
+#ifndef __ICLRAppDomainResourceMonitor_FWD_DEFINED__
+#define __ICLRAppDomainResourceMonitor_FWD_DEFINED__
+typedef interface ICLRAppDomainResourceMonitor ICLRAppDomainResourceMonitor;
+
+#endif /* __ICLRAppDomainResourceMonitor_FWD_DEFINED__ */
+
+
+/* header files for imported files */
+#include "unknwn.h"
+#include "gchost.h"
+#include "ivalidator.h"
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+
+/* interface __MIDL_itf_mscoree_0000_0000 */
+/* [local] */
+
+#define DECLARE_DEPRECATED
+#define DEPRECATED_CLR_STDAPI STDAPI
+
+struct IActivationFactory;
+
+#define CLR_MAJOR_VERSION ( 4 )
+
+#define CLR_MINOR_VERSION ( 0 )
+
+#define CLR_BUILD_VERSION ( 23203 )
+
+#define CLR_ASSEMBLY_MAJOR_VERSION ( 4 )
+
+#define CLR_ASSEMBLY_MINOR_VERSION ( 0 )
+
+#define CLR_ASSEMBLY_BUILD_VERSION ( 0 )
+
+EXTERN_GUID(CLSID_TypeNameFactory, 0xB81FF171, 0x20F3, 0x11d2, 0x8d, 0xcc, 0x00, 0xa0, 0xc9, 0xb0, 0x05, 0x25);
+EXTERN_GUID(CLSID_ComCallUnmarshal, 0x3F281000,0xE95A,0x11d2,0x88,0x6B,0x00,0xC0,0x4F,0x86,0x9F,0x04);
+EXTERN_GUID(CLSID_ComCallUnmarshalV4, 0x45fb4600,0xe6e8,0x4928,0xb2,0x5e,0x50,0x47,0x6f,0xf7,0x94,0x25);
+EXTERN_GUID(IID_IManagedObject, 0xc3fcc19e, 0xa970, 0x11d2, 0x8b, 0x5a, 0x00, 0xa0, 0xc9, 0xb7, 0xc9, 0xc4);
+EXTERN_GUID(IID_ICLRAppDomainResourceMonitor, 0XC62DE18C, 0X2E23, 0X4AEA, 0X84, 0X23, 0XB4, 0X0C, 0X1F, 0XC5, 0X9E, 0XAE);
+EXTERN_GUID(IID_ICLRPolicyManager, 0x7D290010, 0xD781, 0x45da, 0xA6, 0xF8, 0xAA, 0x5D, 0x71, 0x1A, 0x73, 0x0E);
+EXTERN_GUID(IID_ICLRGCManager, 0x54D9007E, 0xA8E2, 0x4885, 0xB7, 0xBF, 0xF9, 0x98, 0xDE, 0xEE, 0x4F, 0x2A);
+EXTERN_GUID(IID_ICLRGCManager2, 0x0603B793, 0xA97A, 0x4712, 0x9C, 0xB4, 0x0C, 0xD1, 0xC7, 0x4C, 0x0F, 0x7C);
+EXTERN_GUID(IID_ICLRErrorReportingManager, 0x980d2f1a, 0xbf79, 0x4c08, 0x81, 0x2a, 0xbb, 0x97, 0x78, 0x92, 0x8f, 0x78);
+EXTERN_GUID(IID_ICLRErrorReportingManager2, 0xc68f63b1, 0x4d8b, 0x4e0b, 0x95, 0x64, 0x9d, 0x2e, 0xfe, 0x2f, 0xa1, 0x8c);
+EXTERN_GUID(IID_ICLRRuntimeHost, 0x90F1A06C, 0x7712, 0x4762, 0x86, 0xB5, 0x7A, 0x5E, 0xBA, 0x6B, 0xDB, 0x02);
+EXTERN_GUID(IID_ICLRRuntimeHost2, 0x712AB73F, 0x2C22, 0x4807, 0xAD, 0x7E, 0xF5, 0x01, 0xD7, 0xb7, 0x2C, 0x2D);
+EXTERN_GUID(IID_ICLRExecutionManager, 0x1000A3E7, 0xB420, 0x4620, 0xAE, 0x30, 0xFB, 0x19, 0xB5, 0x87, 0xAD, 0x1D);
+EXTERN_GUID(IID_ITypeName, 0xB81FF171, 0x20F3, 0x11d2, 0x8d, 0xcc, 0x00, 0xa0, 0xc9, 0xb0, 0x05, 0x22);
+EXTERN_GUID(IID_ITypeNameBuilder, 0xB81FF171, 0x20F3, 0x11d2, 0x8d, 0xcc, 0x00, 0xa0, 0xc9, 0xb0, 0x05, 0x23);
+EXTERN_GUID(IID_ITypeNameFactory, 0xB81FF171, 0x20F3, 0x11d2, 0x8d, 0xcc, 0x00, 0xa0, 0xc9, 0xb0, 0x05, 0x21);
+DEPRECATED_CLR_STDAPI GetCORSystemDirectory(_Out_writes_to_(cchBuffer, *dwLength) LPWSTR pbuffer, DWORD cchBuffer, DWORD* dwLength);
+DEPRECATED_CLR_STDAPI GetCORVersion(_Out_writes_to_(cchBuffer, *dwLength) LPWSTR pbBuffer, DWORD cchBuffer, DWORD* dwLength);
+DEPRECATED_CLR_STDAPI GetFileVersion(LPCWSTR szFilename, _Out_writes_to_opt_(cchBuffer, *dwLength) LPWSTR szBuffer, DWORD cchBuffer, DWORD* dwLength);
+DEPRECATED_CLR_STDAPI GetCORRequiredVersion(_Out_writes_to_(cchBuffer, *dwLength) LPWSTR pbuffer, DWORD cchBuffer, DWORD* dwLength);
+DEPRECATED_CLR_STDAPI GetRequestedRuntimeInfo(LPCWSTR pExe, LPCWSTR pwszVersion, LPCWSTR pConfigurationFile, DWORD startupFlags, DWORD runtimeInfoFlags, _Out_writes_opt_(dwDirectory) LPWSTR pDirectory, DWORD dwDirectory, _Out_opt_ DWORD *dwDirectoryLength, _Out_writes_opt_(cchBuffer) LPWSTR pVersion, DWORD cchBuffer, _Out_opt_ DWORD* dwlength);
+DEPRECATED_CLR_STDAPI GetRequestedRuntimeVersion(_In_ LPWSTR pExe, _Out_writes_to_(cchBuffer, *dwLength) LPWSTR pVersion, DWORD cchBuffer, _Out_ DWORD* dwLength);
+DEPRECATED_CLR_STDAPI CorBindToRuntimeHost(LPCWSTR pwszVersion, LPCWSTR pwszBuildFlavor, LPCWSTR pwszHostConfigFile, VOID* pReserved, DWORD startupFlags, REFCLSID rclsid, REFIID riid, LPVOID FAR *ppv);
+DEPRECATED_CLR_STDAPI CorBindToRuntimeEx(LPCWSTR pwszVersion, LPCWSTR pwszBuildFlavor, DWORD startupFlags, REFCLSID rclsid, REFIID riid, LPVOID FAR *ppv);
+DEPRECATED_CLR_STDAPI CorBindToRuntimeByCfg(IStream* pCfgStream, DWORD reserved, DWORD startupFlags, REFCLSID rclsid,REFIID riid, LPVOID FAR* ppv);
+DEPRECATED_CLR_STDAPI CorBindToRuntime(LPCWSTR pwszVersion, LPCWSTR pwszBuildFlavor, REFCLSID rclsid, REFIID riid, LPVOID FAR *ppv);
+DEPRECATED_CLR_STDAPI CorBindToCurrentRuntime(LPCWSTR pwszFileName, REFCLSID rclsid, REFIID riid, LPVOID FAR *ppv);
+DEPRECATED_CLR_STDAPI ClrCreateManagedInstance(LPCWSTR pTypeName, REFIID riid, void **ppObject);
+DECLARE_DEPRECATED void STDMETHODCALLTYPE CorMarkThreadInThreadPool();
+DEPRECATED_CLR_STDAPI RunDll32ShimW(HWND hwnd, HINSTANCE hinst, LPCWSTR lpszCmdLine, int nCmdShow);
+DEPRECATED_CLR_STDAPI LoadLibraryShim(LPCWSTR szDllName, LPCWSTR szVersion, LPVOID pvReserved, HMODULE *phModDll);
+DEPRECATED_CLR_STDAPI CallFunctionShim(LPCWSTR szDllName, LPCSTR szFunctionName, LPVOID lpvArgument1, LPVOID lpvArgument2, LPCWSTR szVersion, LPVOID pvReserved);
+DEPRECATED_CLR_STDAPI GetRealProcAddress(LPCSTR pwszProcName, VOID** ppv);
+DECLARE_DEPRECATED void STDMETHODCALLTYPE CorExitProcess(int exitCode);
+DEPRECATED_CLR_STDAPI LoadStringRC(UINT iResouceID, _Out_writes_z_(iMax) LPWSTR szBuffer, int iMax, int bQuiet);
+typedef HRESULT (STDAPICALLTYPE *FnGetCLRRuntimeHost)(REFIID riid, IUnknown **pUnk);
+typedef /* [public] */
+enum __MIDL___MIDL_itf_mscoree_0000_0000_0001
+ {
+ HOST_TYPE_DEFAULT = 0,
+ HOST_TYPE_APPLAUNCH = 0x1,
+ HOST_TYPE_CORFLAG = 0x2
+ } HOST_TYPE;
+
+STDAPI CorLaunchApplication(HOST_TYPE dwClickOnceHost, LPCWSTR pwzAppFullName, DWORD dwManifestPaths, LPCWSTR* ppwzManifestPaths, DWORD dwActivationData, LPCWSTR* ppwzActivationData, LPPROCESS_INFORMATION lpProcessInformation);
+typedef HRESULT ( __stdcall *FExecuteInAppDomainCallback )(
+ void *cookie);
+
+typedef /* [public][public] */
+enum __MIDL___MIDL_itf_mscoree_0000_0000_0002
+ {
+ STARTUP_CONCURRENT_GC = 0x1,
+ STARTUP_LOADER_OPTIMIZATION_MASK = ( 0x3 << 1 ) ,
+ STARTUP_LOADER_OPTIMIZATION_SINGLE_DOMAIN = ( 0x1 << 1 ) ,
+ STARTUP_LOADER_OPTIMIZATION_MULTI_DOMAIN = ( 0x2 << 1 ) ,
+ STARTUP_LOADER_OPTIMIZATION_MULTI_DOMAIN_HOST = ( 0x3 << 1 ) ,
+ STARTUP_LOADER_SAFEMODE = 0x10,
+ STARTUP_LOADER_SETPREFERENCE = 0x100,
+ STARTUP_SERVER_GC = 0x1000,
+ STARTUP_HOARD_GC_VM = 0x2000,
+ STARTUP_SINGLE_VERSION_HOSTING_INTERFACE = 0x4000,
+ STARTUP_LEGACY_IMPERSONATION = 0x10000,
+ STARTUP_DISABLE_COMMITTHREADSTACK = 0x20000,
+ STARTUP_ALWAYSFLOW_IMPERSONATION = 0x40000,
+ STARTUP_TRIM_GC_COMMIT = 0x80000,
+ STARTUP_ETW = 0x100000,
+ STARTUP_ARM = 0x400000,
+ STARTUP_SINGLE_APPDOMAIN = 0x800000,
+ STARTUP_APPX_APP_MODEL = 0x1000000,
+ STARTUP_DISABLE_RANDOMIZED_STRING_HASHING = 0x2000000
+ } STARTUP_FLAGS;
+
+typedef /* [public] */
+enum __MIDL___MIDL_itf_mscoree_0000_0000_0003
+ {
+ CLSID_RESOLUTION_DEFAULT = 0,
+ CLSID_RESOLUTION_REGISTERED = 0x1
+ } CLSID_RESOLUTION_FLAGS;
+
+typedef /* [public] */
+enum __MIDL___MIDL_itf_mscoree_0000_0000_0004
+ {
+ RUNTIME_INFO_UPGRADE_VERSION = 0x1,
+ RUNTIME_INFO_REQUEST_IA64 = 0x2,
+ RUNTIME_INFO_REQUEST_AMD64 = 0x4,
+ RUNTIME_INFO_REQUEST_X86 = 0x8,
+ RUNTIME_INFO_DONT_RETURN_DIRECTORY = 0x10,
+ RUNTIME_INFO_DONT_RETURN_VERSION = 0x20,
+ RUNTIME_INFO_DONT_SHOW_ERROR_DIALOG = 0x40,
+ RUNTIME_INFO_IGNORE_ERROR_MODE = 0x1000
+ } RUNTIME_INFO_FLAGS;
+
+typedef /* [public] */
+enum __MIDL___MIDL_itf_mscoree_0000_0000_0005
+ {
+ APPDOMAIN_SECURITY_DEFAULT = 0,
+ APPDOMAIN_SECURITY_SANDBOXED = 0x1,
+ APPDOMAIN_SECURITY_FORBID_CROSSAD_REVERSE_PINVOKE = 0x2,
+ APPDOMAIN_IGNORE_UNHANDLED_EXCEPTIONS = 0x4,
+ APPDOMAIN_FORCE_TRIVIAL_WAIT_OPERATIONS = 0x8,
+ APPDOMAIN_ENABLE_PINVOKE_AND_CLASSIC_COMINTEROP = 0x10,
+ APPDOMAIN_SET_TEST_KEY = 0x20,
+ APPDOMAIN_ENABLE_PLATFORM_SPECIFIC_APPS = 0x40,
+ APPDOMAIN_ENABLE_ASSEMBLY_LOADFILE = 0x80,
+ APPDOMAIN_DISABLE_TRANSPARENCY_ENFORCEMENT = 0x100
+ } APPDOMAIN_SECURITY_FLAGS;
+
+STDAPI GetRequestedRuntimeVersionForCLSID(REFCLSID rclsid, _Out_writes_opt_(cchBuffer) LPWSTR pVersion, DWORD cchBuffer, _Out_opt_ DWORD* dwLength, CLSID_RESOLUTION_FLAGS dwResolutionFlags);
+EXTERN_GUID(IID_IDebuggerThreadControl, 0x23d86786, 0x0bb5, 0x4774, 0x8f, 0xb5, 0xe3, 0x52, 0x2a, 0xdd, 0x62, 0x46);
+
+
+extern RPC_IF_HANDLE __MIDL_itf_mscoree_0000_0000_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_mscoree_0000_0000_v0_0_s_ifspec;
+
+#ifndef __IDebuggerThreadControl_INTERFACE_DEFINED__
+#define __IDebuggerThreadControl_INTERFACE_DEFINED__
+
+/* interface IDebuggerThreadControl */
+/* [object][local][unique][helpstring][version][uuid] */
+
+
+EXTERN_C const IID IID_IDebuggerThreadControl;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("23D86786-0BB5-4774-8FB5-E3522ADD6246")
+ IDebuggerThreadControl : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE ThreadIsBlockingForDebugger( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ReleaseAllRuntimeThreads( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StartBlockingForDebugger(
+ DWORD dwUnused) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IDebuggerThreadControlVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IDebuggerThreadControl * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IDebuggerThreadControl * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IDebuggerThreadControl * This);
+
+ HRESULT ( STDMETHODCALLTYPE *ThreadIsBlockingForDebugger )(
+ IDebuggerThreadControl * This);
+
+ HRESULT ( STDMETHODCALLTYPE *ReleaseAllRuntimeThreads )(
+ IDebuggerThreadControl * This);
+
+ HRESULT ( STDMETHODCALLTYPE *StartBlockingForDebugger )(
+ IDebuggerThreadControl * This,
+ DWORD dwUnused);
+
+ END_INTERFACE
+ } IDebuggerThreadControlVtbl;
+
+ interface IDebuggerThreadControl
+ {
+ CONST_VTBL struct IDebuggerThreadControlVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IDebuggerThreadControl_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IDebuggerThreadControl_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IDebuggerThreadControl_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IDebuggerThreadControl_ThreadIsBlockingForDebugger(This) \
+ ( (This)->lpVtbl -> ThreadIsBlockingForDebugger(This) )
+
+#define IDebuggerThreadControl_ReleaseAllRuntimeThreads(This) \
+ ( (This)->lpVtbl -> ReleaseAllRuntimeThreads(This) )
+
+#define IDebuggerThreadControl_StartBlockingForDebugger(This,dwUnused) \
+ ( (This)->lpVtbl -> StartBlockingForDebugger(This,dwUnused) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IDebuggerThreadControl_INTERFACE_DEFINED__ */
+
+
+/* interface __MIDL_itf_mscoree_0000_0001 */
+/* [local] */
+
+EXTERN_GUID(IID_IDebuggerInfo, 0xbf24142d, 0xa47d, 0x4d24, 0xa6, 0x6d, 0x8c, 0x21, 0x41, 0x94, 0x4e, 0x44);
+
+
+extern RPC_IF_HANDLE __MIDL_itf_mscoree_0000_0001_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_mscoree_0000_0001_v0_0_s_ifspec;
+
+#ifndef __IDebuggerInfo_INTERFACE_DEFINED__
+#define __IDebuggerInfo_INTERFACE_DEFINED__
+
+/* interface IDebuggerInfo */
+/* [object][local][unique][helpstring][version][uuid] */
+
+
+EXTERN_C const IID IID_IDebuggerInfo;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("BF24142D-A47D-4d24-A66D-8C2141944E44")
+ IDebuggerInfo : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE IsDebuggerAttached(
+ /* [out] */ BOOL *pbAttached) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IDebuggerInfoVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IDebuggerInfo * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IDebuggerInfo * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IDebuggerInfo * This);
+
+ HRESULT ( STDMETHODCALLTYPE *IsDebuggerAttached )(
+ IDebuggerInfo * This,
+ /* [out] */ BOOL *pbAttached);
+
+ END_INTERFACE
+ } IDebuggerInfoVtbl;
+
+ interface IDebuggerInfo
+ {
+ CONST_VTBL struct IDebuggerInfoVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IDebuggerInfo_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IDebuggerInfo_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IDebuggerInfo_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IDebuggerInfo_IsDebuggerAttached(This,pbAttached) \
+ ( (This)->lpVtbl -> IsDebuggerAttached(This,pbAttached) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IDebuggerInfo_INTERFACE_DEFINED__ */
+
+
+/* interface __MIDL_itf_mscoree_0000_0002 */
+/* [local] */
+
+typedef void *HDOMAINENUM;
+
+typedef /* [public] */
+enum __MIDL___MIDL_itf_mscoree_0000_0002_0001
+ {
+ eMemoryAvailableLow = 1,
+ eMemoryAvailableNeutral = 2,
+ eMemoryAvailableHigh = 3
+ } EMemoryAvailable;
+
+typedef /* [public] */
+enum __MIDL___MIDL_itf_mscoree_0000_0002_0002
+ {
+ eTaskCritical = 0,
+ eAppDomainCritical = 1,
+ eProcessCritical = 2
+ } EMemoryCriticalLevel;
+
+typedef /* [public] */
+enum __MIDL___MIDL_itf_mscoree_0000_0002_0003
+ {
+ WAIT_MSGPUMP = 0x1,
+ WAIT_ALERTABLE = 0x2,
+ WAIT_NOTINDEADLOCK = 0x4
+ } WAIT_OPTION;
+
+typedef UINT64 TASKID;
+
+typedef DWORD CONNID;
+
+typedef
+enum ETaskType
+ {
+ TT_DEBUGGERHELPER = 0x1,
+ TT_GC = 0x2,
+ TT_FINALIZER = 0x4,
+ TT_THREADPOOL_TIMER = 0x8,
+ TT_THREADPOOL_GATE = 0x10,
+ TT_THREADPOOL_WORKER = 0x20,
+ TT_THREADPOOL_IOCOMPLETION = 0x40,
+ TT_ADUNLOAD = 0x80,
+ TT_USER = 0x100,
+ TT_THREADPOOL_WAIT = 0x200,
+ TT_UNKNOWN = 0x80000000
+ } ETaskType;
+
+typedef /* [public] */
+enum __MIDL___MIDL_itf_mscoree_0000_0002_0004
+ {
+ eSymbolReadingNever = 0,
+ eSymbolReadingAlways = 1,
+ eSymbolReadingFullTrustOnly = 2
+ } ESymbolReadingPolicy;
+
+typedef /* [public][public] */
+enum __MIDL___MIDL_itf_mscoree_0000_0002_0005
+ {
+ DUMP_FLAVOR_Mini = 0,
+ DUMP_FLAVOR_CriticalCLRState = 1,
+ DUMP_FLAVOR_NonHeapCLRState = 2,
+ DUMP_FLAVOR_Default = DUMP_FLAVOR_Mini
+ } ECustomDumpFlavor;
+
+typedef /* [public][public][public] */
+enum __MIDL___MIDL_itf_mscoree_0000_0002_0006
+ {
+ DUMP_ITEM_None = 0
+ } ECustomDumpItemKind;
+
+typedef /* [public][public] */ struct __MIDL___MIDL_itf_mscoree_0000_0002_0007
+ {
+ ECustomDumpItemKind itemKind;
+ union
+ {
+ UINT_PTR pReserved;
+ } ;
+ } CustomDumpItem;
+
+#define BucketParamsCount ( 10 )
+
+#define BucketParamLength ( 255 )
+
+typedef /* [public] */
+enum __MIDL___MIDL_itf_mscoree_0000_0002_0009
+ {
+ Parameter1 = 0,
+ Parameter2 = ( Parameter1 + 1 ) ,
+ Parameter3 = ( Parameter2 + 1 ) ,
+ Parameter4 = ( Parameter3 + 1 ) ,
+ Parameter5 = ( Parameter4 + 1 ) ,
+ Parameter6 = ( Parameter5 + 1 ) ,
+ Parameter7 = ( Parameter6 + 1 ) ,
+ Parameter8 = ( Parameter7 + 1 ) ,
+ Parameter9 = ( Parameter8 + 1 ) ,
+ InvalidBucketParamIndex = ( Parameter9 + 1 )
+ } BucketParameterIndex;
+
+typedef struct _BucketParameters
+ {
+ BOOL fInited;
+ WCHAR pszEventTypeName[ 255 ];
+ WCHAR pszParams[ 10 ][ 255 ];
+ } BucketParameters;
+
+
+
+extern RPC_IF_HANDLE __MIDL_itf_mscoree_0000_0002_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_mscoree_0000_0002_v0_0_s_ifspec;
+
+#ifndef __ICLRErrorReportingManager_INTERFACE_DEFINED__
+#define __ICLRErrorReportingManager_INTERFACE_DEFINED__
+
+/* interface ICLRErrorReportingManager */
+/* [object][local][unique][helpstring][version][uuid] */
+
+
+EXTERN_C const IID IID_ICLRErrorReportingManager;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("980D2F1A-BF79-4c08-812A-BB9778928F78")
+ ICLRErrorReportingManager : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetBucketParametersForCurrentException(
+ /* [out] */ BucketParameters *pParams) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE BeginCustomDump(
+ /* [in] */ ECustomDumpFlavor dwFlavor,
+ /* [in] */ DWORD dwNumItems,
+ /* [length_is][size_is][in] */ CustomDumpItem *items,
+ DWORD dwReserved) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EndCustomDump( void) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICLRErrorReportingManagerVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICLRErrorReportingManager * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICLRErrorReportingManager * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICLRErrorReportingManager * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetBucketParametersForCurrentException )(
+ ICLRErrorReportingManager * This,
+ /* [out] */ BucketParameters *pParams);
+
+ HRESULT ( STDMETHODCALLTYPE *BeginCustomDump )(
+ ICLRErrorReportingManager * This,
+ /* [in] */ ECustomDumpFlavor dwFlavor,
+ /* [in] */ DWORD dwNumItems,
+ /* [length_is][size_is][in] */ CustomDumpItem *items,
+ DWORD dwReserved);
+
+ HRESULT ( STDMETHODCALLTYPE *EndCustomDump )(
+ ICLRErrorReportingManager * This);
+
+ END_INTERFACE
+ } ICLRErrorReportingManagerVtbl;
+
+ interface ICLRErrorReportingManager
+ {
+ CONST_VTBL struct ICLRErrorReportingManagerVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICLRErrorReportingManager_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICLRErrorReportingManager_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICLRErrorReportingManager_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICLRErrorReportingManager_GetBucketParametersForCurrentException(This,pParams) \
+ ( (This)->lpVtbl -> GetBucketParametersForCurrentException(This,pParams) )
+
+#define ICLRErrorReportingManager_BeginCustomDump(This,dwFlavor,dwNumItems,items,dwReserved) \
+ ( (This)->lpVtbl -> BeginCustomDump(This,dwFlavor,dwNumItems,items,dwReserved) )
+
+#define ICLRErrorReportingManager_EndCustomDump(This) \
+ ( (This)->lpVtbl -> EndCustomDump(This) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICLRErrorReportingManager_INTERFACE_DEFINED__ */
+
+
+/* interface __MIDL_itf_mscoree_0000_0003 */
+/* [local] */
+
+typedef /* [public][public] */
+enum __MIDL___MIDL_itf_mscoree_0000_0003_0001
+ {
+ ApplicationID = 0x1,
+ InstanceID = 0x2
+ } ApplicationDataKey;
+
+
+
+extern RPC_IF_HANDLE __MIDL_itf_mscoree_0000_0003_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_mscoree_0000_0003_v0_0_s_ifspec;
+
+#ifndef __ICLRErrorReportingManager2_INTERFACE_DEFINED__
+#define __ICLRErrorReportingManager2_INTERFACE_DEFINED__
+
+/* interface ICLRErrorReportingManager2 */
+/* [object][local][unique][helpstring][version][uuid] */
+
+
+EXTERN_C const IID IID_ICLRErrorReportingManager2;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("C68F63B1-4D8B-4E0B-9564-9D2EFE2FA18C")
+ ICLRErrorReportingManager2 : public ICLRErrorReportingManager
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE SetApplicationData(
+ /* [in] */ ApplicationDataKey key,
+ /* [in] */ const WCHAR *pValue) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetBucketParametersForUnhandledException(
+ /* [in] */ const BucketParameters *pBucketParams,
+ /* [out] */ DWORD *pCountParams) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICLRErrorReportingManager2Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICLRErrorReportingManager2 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICLRErrorReportingManager2 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICLRErrorReportingManager2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetBucketParametersForCurrentException )(
+ ICLRErrorReportingManager2 * This,
+ /* [out] */ BucketParameters *pParams);
+
+ HRESULT ( STDMETHODCALLTYPE *BeginCustomDump )(
+ ICLRErrorReportingManager2 * This,
+ /* [in] */ ECustomDumpFlavor dwFlavor,
+ /* [in] */ DWORD dwNumItems,
+ /* [length_is][size_is][in] */ CustomDumpItem *items,
+ DWORD dwReserved);
+
+ HRESULT ( STDMETHODCALLTYPE *EndCustomDump )(
+ ICLRErrorReportingManager2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *SetApplicationData )(
+ ICLRErrorReportingManager2 * This,
+ /* [in] */ ApplicationDataKey key,
+ /* [in] */ const WCHAR *pValue);
+
+ HRESULT ( STDMETHODCALLTYPE *SetBucketParametersForUnhandledException )(
+ ICLRErrorReportingManager2 * This,
+ /* [in] */ const BucketParameters *pBucketParams,
+ /* [out] */ DWORD *pCountParams);
+
+ END_INTERFACE
+ } ICLRErrorReportingManager2Vtbl;
+
+ interface ICLRErrorReportingManager2
+ {
+ CONST_VTBL struct ICLRErrorReportingManager2Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICLRErrorReportingManager2_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICLRErrorReportingManager2_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICLRErrorReportingManager2_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICLRErrorReportingManager2_GetBucketParametersForCurrentException(This,pParams) \
+ ( (This)->lpVtbl -> GetBucketParametersForCurrentException(This,pParams) )
+
+#define ICLRErrorReportingManager2_BeginCustomDump(This,dwFlavor,dwNumItems,items,dwReserved) \
+ ( (This)->lpVtbl -> BeginCustomDump(This,dwFlavor,dwNumItems,items,dwReserved) )
+
+#define ICLRErrorReportingManager2_EndCustomDump(This) \
+ ( (This)->lpVtbl -> EndCustomDump(This) )
+
+
+#define ICLRErrorReportingManager2_SetApplicationData(This,key,pValue) \
+ ( (This)->lpVtbl -> SetApplicationData(This,key,pValue) )
+
+#define ICLRErrorReportingManager2_SetBucketParametersForUnhandledException(This,pBucketParams,pCountParams) \
+ ( (This)->lpVtbl -> SetBucketParametersForUnhandledException(This,pBucketParams,pCountParams) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICLRErrorReportingManager2_INTERFACE_DEFINED__ */
+
+
+/* interface __MIDL_itf_mscoree_0000_0004 */
+/* [local] */
+
+typedef /* [public][public][public][public][public] */
+enum __MIDL___MIDL_itf_mscoree_0000_0004_0001
+ {
+ OPR_ThreadAbort = 0,
+ OPR_ThreadRudeAbortInNonCriticalRegion = ( OPR_ThreadAbort + 1 ) ,
+ OPR_ThreadRudeAbortInCriticalRegion = ( OPR_ThreadRudeAbortInNonCriticalRegion + 1 ) ,
+ OPR_AppDomainUnload = ( OPR_ThreadRudeAbortInCriticalRegion + 1 ) ,
+ OPR_AppDomainRudeUnload = ( OPR_AppDomainUnload + 1 ) ,
+ OPR_ProcessExit = ( OPR_AppDomainRudeUnload + 1 ) ,
+ OPR_FinalizerRun = ( OPR_ProcessExit + 1 ) ,
+ MaxClrOperation = ( OPR_FinalizerRun + 1 )
+ } EClrOperation;
+
+typedef /* [public][public] */
+enum __MIDL___MIDL_itf_mscoree_0000_0004_0002
+ {
+ FAIL_NonCriticalResource = 0,
+ FAIL_CriticalResource = ( FAIL_NonCriticalResource + 1 ) ,
+ FAIL_FatalRuntime = ( FAIL_CriticalResource + 1 ) ,
+ FAIL_OrphanedLock = ( FAIL_FatalRuntime + 1 ) ,
+ FAIL_StackOverflow = ( FAIL_OrphanedLock + 1 ) ,
+ FAIL_AccessViolation = ( FAIL_StackOverflow + 1 ) ,
+ FAIL_CodeContract = ( FAIL_AccessViolation + 1 ) ,
+ MaxClrFailure = ( FAIL_CodeContract + 1 )
+ } EClrFailure;
+
+typedef /* [public][public] */
+enum __MIDL___MIDL_itf_mscoree_0000_0004_0003
+ {
+ eRuntimeDeterminedPolicy = 0,
+ eHostDeterminedPolicy = ( eRuntimeDeterminedPolicy + 1 )
+ } EClrUnhandledException;
+
+typedef /* [public][public][public][public][public] */
+enum __MIDL___MIDL_itf_mscoree_0000_0004_0004
+ {
+ eNoAction = 0,
+ eThrowException = ( eNoAction + 1 ) ,
+ eAbortThread = ( eThrowException + 1 ) ,
+ eRudeAbortThread = ( eAbortThread + 1 ) ,
+ eUnloadAppDomain = ( eRudeAbortThread + 1 ) ,
+ eRudeUnloadAppDomain = ( eUnloadAppDomain + 1 ) ,
+ eExitProcess = ( eRudeUnloadAppDomain + 1 ) ,
+ eFastExitProcess = ( eExitProcess + 1 ) ,
+ eRudeExitProcess = ( eFastExitProcess + 1 ) ,
+ eDisableRuntime = ( eRudeExitProcess + 1 ) ,
+ MaxPolicyAction = ( eDisableRuntime + 1 )
+ } EPolicyAction;
+
+
+
+extern RPC_IF_HANDLE __MIDL_itf_mscoree_0000_0004_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_mscoree_0000_0004_v0_0_s_ifspec;
+
+#ifndef __ICLRPolicyManager_INTERFACE_DEFINED__
+#define __ICLRPolicyManager_INTERFACE_DEFINED__
+
+/* interface ICLRPolicyManager */
+/* [object][local][unique][helpstring][version][uuid] */
+
+
+EXTERN_C const IID IID_ICLRPolicyManager;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("7D290010-D781-45da-A6F8-AA5D711A730E")
+ ICLRPolicyManager : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE SetDefaultAction(
+ /* [in] */ EClrOperation operation,
+ /* [in] */ EPolicyAction action) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetTimeout(
+ /* [in] */ EClrOperation operation,
+ /* [in] */ DWORD dwMilliseconds) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetActionOnTimeout(
+ /* [in] */ EClrOperation operation,
+ /* [in] */ EPolicyAction action) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetTimeoutAndAction(
+ /* [in] */ EClrOperation operation,
+ /* [in] */ DWORD dwMilliseconds,
+ /* [in] */ EPolicyAction action) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetActionOnFailure(
+ /* [in] */ EClrFailure failure,
+ /* [in] */ EPolicyAction action) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetUnhandledExceptionPolicy(
+ /* [in] */ EClrUnhandledException policy) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICLRPolicyManagerVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICLRPolicyManager * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICLRPolicyManager * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICLRPolicyManager * This);
+
+ HRESULT ( STDMETHODCALLTYPE *SetDefaultAction )(
+ ICLRPolicyManager * This,
+ /* [in] */ EClrOperation operation,
+ /* [in] */ EPolicyAction action);
+
+ HRESULT ( STDMETHODCALLTYPE *SetTimeout )(
+ ICLRPolicyManager * This,
+ /* [in] */ EClrOperation operation,
+ /* [in] */ DWORD dwMilliseconds);
+
+ HRESULT ( STDMETHODCALLTYPE *SetActionOnTimeout )(
+ ICLRPolicyManager * This,
+ /* [in] */ EClrOperation operation,
+ /* [in] */ EPolicyAction action);
+
+ HRESULT ( STDMETHODCALLTYPE *SetTimeoutAndAction )(
+ ICLRPolicyManager * This,
+ /* [in] */ EClrOperation operation,
+ /* [in] */ DWORD dwMilliseconds,
+ /* [in] */ EPolicyAction action);
+
+ HRESULT ( STDMETHODCALLTYPE *SetActionOnFailure )(
+ ICLRPolicyManager * This,
+ /* [in] */ EClrFailure failure,
+ /* [in] */ EPolicyAction action);
+
+ HRESULT ( STDMETHODCALLTYPE *SetUnhandledExceptionPolicy )(
+ ICLRPolicyManager * This,
+ /* [in] */ EClrUnhandledException policy);
+
+ END_INTERFACE
+ } ICLRPolicyManagerVtbl;
+
+ interface ICLRPolicyManager
+ {
+ CONST_VTBL struct ICLRPolicyManagerVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICLRPolicyManager_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICLRPolicyManager_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICLRPolicyManager_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICLRPolicyManager_SetDefaultAction(This,operation,action) \
+ ( (This)->lpVtbl -> SetDefaultAction(This,operation,action) )
+
+#define ICLRPolicyManager_SetTimeout(This,operation,dwMilliseconds) \
+ ( (This)->lpVtbl -> SetTimeout(This,operation,dwMilliseconds) )
+
+#define ICLRPolicyManager_SetActionOnTimeout(This,operation,action) \
+ ( (This)->lpVtbl -> SetActionOnTimeout(This,operation,action) )
+
+#define ICLRPolicyManager_SetTimeoutAndAction(This,operation,dwMilliseconds,action) \
+ ( (This)->lpVtbl -> SetTimeoutAndAction(This,operation,dwMilliseconds,action) )
+
+#define ICLRPolicyManager_SetActionOnFailure(This,failure,action) \
+ ( (This)->lpVtbl -> SetActionOnFailure(This,failure,action) )
+
+#define ICLRPolicyManager_SetUnhandledExceptionPolicy(This,policy) \
+ ( (This)->lpVtbl -> SetUnhandledExceptionPolicy(This,policy) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICLRPolicyManager_INTERFACE_DEFINED__ */
+
+
+/* interface __MIDL_itf_mscoree_0000_0005 */
+/* [local] */
+
+typedef /* [public] */
+enum __MIDL___MIDL_itf_mscoree_0000_0005_0001
+ {
+ Event_DomainUnload = 0,
+ Event_ClrDisabled = ( Event_DomainUnload + 1 ) ,
+ Event_MDAFired = ( Event_ClrDisabled + 1 ) ,
+ Event_StackOverflow = ( Event_MDAFired + 1 ) ,
+ MaxClrEvent = ( Event_StackOverflow + 1 )
+ } EClrEvent;
+
+typedef struct _MDAInfo
+ {
+ LPCWSTR lpMDACaption;
+ LPCWSTR lpMDAMessage;
+ LPCWSTR lpStackTrace;
+ } MDAInfo;
+
+typedef /* [public] */
+enum __MIDL___MIDL_itf_mscoree_0000_0005_0002
+ {
+ SO_Managed = 0,
+ SO_ClrEngine = ( SO_Managed + 1 ) ,
+ SO_Other = ( SO_ClrEngine + 1 )
+ } StackOverflowType;
+
+typedef struct _StackOverflowInfo
+{
+ StackOverflowType soType;
+ EXCEPTION_POINTERS *pExceptionInfo;
+} StackOverflowInfo;
+
+
+extern RPC_IF_HANDLE __MIDL_itf_mscoree_0000_0005_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_mscoree_0000_0005_v0_0_s_ifspec;
+
+#ifndef __ICLRGCManager_INTERFACE_DEFINED__
+#define __ICLRGCManager_INTERFACE_DEFINED__
+
+/* interface ICLRGCManager */
+/* [object][local][unique][version][uuid] */
+
+
+EXTERN_C const IID IID_ICLRGCManager;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("54D9007E-A8E2-4885-B7BF-F998DEEE4F2A")
+ ICLRGCManager : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE Collect(
+ /* [in] */ LONG Generation) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetStats(
+ /* [out][in] */ COR_GC_STATS *pStats) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetGCStartupLimits(
+ /* [in] */ DWORD SegmentSize,
+ /* [in] */ DWORD MaxGen0Size) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICLRGCManagerVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICLRGCManager * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICLRGCManager * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICLRGCManager * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Collect )(
+ ICLRGCManager * This,
+ /* [in] */ LONG Generation);
+
+ HRESULT ( STDMETHODCALLTYPE *GetStats )(
+ ICLRGCManager * This,
+ /* [out][in] */ COR_GC_STATS *pStats);
+
+ HRESULT ( STDMETHODCALLTYPE *SetGCStartupLimits )(
+ ICLRGCManager * This,
+ /* [in] */ DWORD SegmentSize,
+ /* [in] */ DWORD MaxGen0Size);
+
+ END_INTERFACE
+ } ICLRGCManagerVtbl;
+
+ interface ICLRGCManager
+ {
+ CONST_VTBL struct ICLRGCManagerVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICLRGCManager_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICLRGCManager_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICLRGCManager_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICLRGCManager_Collect(This,Generation) \
+ ( (This)->lpVtbl -> Collect(This,Generation) )
+
+#define ICLRGCManager_GetStats(This,pStats) \
+ ( (This)->lpVtbl -> GetStats(This,pStats) )
+
+#define ICLRGCManager_SetGCStartupLimits(This,SegmentSize,MaxGen0Size) \
+ ( (This)->lpVtbl -> SetGCStartupLimits(This,SegmentSize,MaxGen0Size) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICLRGCManager_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICLRGCManager2_INTERFACE_DEFINED__
+#define __ICLRGCManager2_INTERFACE_DEFINED__
+
+/* interface ICLRGCManager2 */
+/* [object][local][unique][version][uuid] */
+
+
+EXTERN_C const IID IID_ICLRGCManager2;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("0603B793-A97A-4712-9CB4-0CD1C74C0F7C")
+ ICLRGCManager2 : public ICLRGCManager
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE SetGCStartupLimitsEx(
+ /* [in] */ SIZE_T SegmentSize,
+ /* [in] */ SIZE_T MaxGen0Size) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICLRGCManager2Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICLRGCManager2 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICLRGCManager2 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICLRGCManager2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Collect )(
+ ICLRGCManager2 * This,
+ /* [in] */ LONG Generation);
+
+ HRESULT ( STDMETHODCALLTYPE *GetStats )(
+ ICLRGCManager2 * This,
+ /* [out][in] */ COR_GC_STATS *pStats);
+
+ HRESULT ( STDMETHODCALLTYPE *SetGCStartupLimits )(
+ ICLRGCManager2 * This,
+ /* [in] */ DWORD SegmentSize,
+ /* [in] */ DWORD MaxGen0Size);
+
+ HRESULT ( STDMETHODCALLTYPE *SetGCStartupLimitsEx )(
+ ICLRGCManager2 * This,
+ /* [in] */ SIZE_T SegmentSize,
+ /* [in] */ SIZE_T MaxGen0Size);
+
+ END_INTERFACE
+ } ICLRGCManager2Vtbl;
+
+ interface ICLRGCManager2
+ {
+ CONST_VTBL struct ICLRGCManager2Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICLRGCManager2_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICLRGCManager2_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICLRGCManager2_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICLRGCManager2_Collect(This,Generation) \
+ ( (This)->lpVtbl -> Collect(This,Generation) )
+
+#define ICLRGCManager2_GetStats(This,pStats) \
+ ( (This)->lpVtbl -> GetStats(This,pStats) )
+
+#define ICLRGCManager2_SetGCStartupLimits(This,SegmentSize,MaxGen0Size) \
+ ( (This)->lpVtbl -> SetGCStartupLimits(This,SegmentSize,MaxGen0Size) )
+
+
+#define ICLRGCManager2_SetGCStartupLimitsEx(This,SegmentSize,MaxGen0Size) \
+ ( (This)->lpVtbl -> SetGCStartupLimitsEx(This,SegmentSize,MaxGen0Size) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICLRGCManager2_INTERFACE_DEFINED__ */
+
+
+/* interface __MIDL_itf_mscoree_0000_0007 */
+/* [local] */
+
+typedef /* [public] */
+enum __MIDL___MIDL_itf_mscoree_0000_0007_0001
+ {
+ ePolicyLevelNone = 0,
+ ePolicyLevelRetargetable = 0x1,
+ ePolicyUnifiedToCLR = 0x2,
+ ePolicyLevelApp = 0x4,
+ ePolicyLevelPublisher = 0x8,
+ ePolicyLevelHost = 0x10,
+ ePolicyLevelAdmin = 0x20,
+ ePolicyPortability = 0x40
+ } EBindPolicyLevels;
+
+typedef struct _AssemblyBindInfo
+ {
+ DWORD dwAppDomainId;
+ LPCWSTR lpReferencedIdentity;
+ LPCWSTR lpPostPolicyIdentity;
+ DWORD ePolicyLevel;
+ } AssemblyBindInfo;
+
+typedef struct _ModuleBindInfo
+ {
+ DWORD dwAppDomainId;
+ LPCWSTR lpAssemblyIdentity;
+ LPCWSTR lpModuleName;
+ } ModuleBindInfo;
+
+typedef
+enum _HostApplicationPolicy
+ {
+ HOST_APPLICATION_BINDING_POLICY = 1
+ } EHostApplicationPolicy;
+
+STDAPI GetCLRIdentityManager(REFIID riid, IUnknown **ppManager);
+EXTERN_GUID(IID_IHostControl, 0x02CA073C, 0x7079, 0x4860, 0x88, 0x0A, 0xC2, 0xF7, 0xA4, 0x49, 0xC9, 0x91);
+
+
+extern RPC_IF_HANDLE __MIDL_itf_mscoree_0000_0007_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_mscoree_0000_0007_v0_0_s_ifspec;
+
+#ifndef __IHostControl_INTERFACE_DEFINED__
+#define __IHostControl_INTERFACE_DEFINED__
+
+/* interface IHostControl */
+/* [object][local][unique][helpstring][version][uuid] */
+
+
+EXTERN_C const IID IID_IHostControl;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("02CA073C-7079-4860-880A-C2F7A449C991")
+ IHostControl : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetHostManager(
+ /* [in] */ REFIID riid,
+ /* [out] */ void **ppObject) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetAppDomainManager(
+ /* [in] */ DWORD dwAppDomainID,
+ /* [in] */ IUnknown *pUnkAppDomainManager) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IHostControlVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IHostControl * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IHostControl * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IHostControl * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetHostManager )(
+ IHostControl * This,
+ /* [in] */ REFIID riid,
+ /* [out] */ void **ppObject);
+
+ HRESULT ( STDMETHODCALLTYPE *SetAppDomainManager )(
+ IHostControl * This,
+ /* [in] */ DWORD dwAppDomainID,
+ /* [in] */ IUnknown *pUnkAppDomainManager);
+
+ END_INTERFACE
+ } IHostControlVtbl;
+
+ interface IHostControl
+ {
+ CONST_VTBL struct IHostControlVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IHostControl_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IHostControl_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IHostControl_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IHostControl_GetHostManager(This,riid,ppObject) \
+ ( (This)->lpVtbl -> GetHostManager(This,riid,ppObject) )
+
+#define IHostControl_SetAppDomainManager(This,dwAppDomainID,pUnkAppDomainManager) \
+ ( (This)->lpVtbl -> SetAppDomainManager(This,dwAppDomainID,pUnkAppDomainManager) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IHostControl_INTERFACE_DEFINED__ */
+
+
+/* interface __MIDL_itf_mscoree_0000_0008 */
+/* [local] */
+
+EXTERN_GUID(IID_ICLRControl, 0x9065597E, 0xD1A1, 0x4fb2, 0xB6, 0xBA, 0x7E, 0x1F, 0xCE, 0x23, 0x0F, 0x61);
+
+
+extern RPC_IF_HANDLE __MIDL_itf_mscoree_0000_0008_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_mscoree_0000_0008_v0_0_s_ifspec;
+
+#ifndef __ICLRControl_INTERFACE_DEFINED__
+#define __ICLRControl_INTERFACE_DEFINED__
+
+/* interface ICLRControl */
+/* [object][local][unique][helpstring][version][uuid] */
+
+
+EXTERN_C const IID IID_ICLRControl;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("9065597E-D1A1-4fb2-B6BA-7E1FCE230F61")
+ ICLRControl : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetCLRManager(
+ /* [in] */ REFIID riid,
+ /* [out] */ void **ppObject) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetAppDomainManagerType(
+ /* [in] */ LPCWSTR pwzAppDomainManagerAssembly,
+ /* [in] */ LPCWSTR pwzAppDomainManagerType) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICLRControlVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICLRControl * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICLRControl * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICLRControl * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCLRManager )(
+ ICLRControl * This,
+ /* [in] */ REFIID riid,
+ /* [out] */ void **ppObject);
+
+ HRESULT ( STDMETHODCALLTYPE *SetAppDomainManagerType )(
+ ICLRControl * This,
+ /* [in] */ LPCWSTR pwzAppDomainManagerAssembly,
+ /* [in] */ LPCWSTR pwzAppDomainManagerType);
+
+ END_INTERFACE
+ } ICLRControlVtbl;
+
+ interface ICLRControl
+ {
+ CONST_VTBL struct ICLRControlVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICLRControl_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICLRControl_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICLRControl_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICLRControl_GetCLRManager(This,riid,ppObject) \
+ ( (This)->lpVtbl -> GetCLRManager(This,riid,ppObject) )
+
+#define ICLRControl_SetAppDomainManagerType(This,pwzAppDomainManagerAssembly,pwzAppDomainManagerType) \
+ ( (This)->lpVtbl -> SetAppDomainManagerType(This,pwzAppDomainManagerAssembly,pwzAppDomainManagerType) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICLRControl_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICLRRuntimeHost_INTERFACE_DEFINED__
+#define __ICLRRuntimeHost_INTERFACE_DEFINED__
+
+/* interface ICLRRuntimeHost */
+/* [object][local][unique][helpstring][version][uuid] */
+
+
+EXTERN_C const IID IID_ICLRRuntimeHost;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("90F1A06C-7712-4762-86B5-7A5EBA6BDB02")
+ ICLRRuntimeHost : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE Start( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Stop( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetHostControl(
+ /* [in] */ IHostControl *pHostControl) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetCLRControl(
+ /* [out] */ ICLRControl **pCLRControl) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE UnloadAppDomain(
+ /* [in] */ DWORD dwAppDomainId,
+ /* [in] */ BOOL fWaitUntilDone) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ExecuteInAppDomain(
+ /* [in] */ DWORD dwAppDomainId,
+ /* [in] */ FExecuteInAppDomainCallback pCallback,
+ /* [in] */ void *cookie) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetCurrentAppDomainId(
+ /* [out] */ DWORD *pdwAppDomainId) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ExecuteApplication(
+ /* [in] */ LPCWSTR pwzAppFullName,
+ /* [in] */ DWORD dwManifestPaths,
+ /* [in] */ LPCWSTR *ppwzManifestPaths,
+ /* [in] */ DWORD dwActivationData,
+ /* [in] */ LPCWSTR *ppwzActivationData,
+ /* [out] */ int *pReturnValue) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ExecuteInDefaultAppDomain(
+ /* [in] */ LPCWSTR pwzAssemblyPath,
+ /* [in] */ LPCWSTR pwzTypeName,
+ /* [in] */ LPCWSTR pwzMethodName,
+ /* [in] */ LPCWSTR pwzArgument,
+ /* [out] */ DWORD *pReturnValue) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICLRRuntimeHostVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICLRRuntimeHost * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICLRRuntimeHost * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICLRRuntimeHost * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Start )(
+ ICLRRuntimeHost * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Stop )(
+ ICLRRuntimeHost * This);
+
+ HRESULT ( STDMETHODCALLTYPE *SetHostControl )(
+ ICLRRuntimeHost * This,
+ /* [in] */ IHostControl *pHostControl);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCLRControl )(
+ ICLRRuntimeHost * This,
+ /* [out] */ ICLRControl **pCLRControl);
+
+ HRESULT ( STDMETHODCALLTYPE *UnloadAppDomain )(
+ ICLRRuntimeHost * This,
+ /* [in] */ DWORD dwAppDomainId,
+ /* [in] */ BOOL fWaitUntilDone);
+
+ HRESULT ( STDMETHODCALLTYPE *ExecuteInAppDomain )(
+ ICLRRuntimeHost * This,
+ /* [in] */ DWORD dwAppDomainId,
+ /* [in] */ FExecuteInAppDomainCallback pCallback,
+ /* [in] */ void *cookie);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCurrentAppDomainId )(
+ ICLRRuntimeHost * This,
+ /* [out] */ DWORD *pdwAppDomainId);
+
+ HRESULT ( STDMETHODCALLTYPE *ExecuteApplication )(
+ ICLRRuntimeHost * This,
+ /* [in] */ LPCWSTR pwzAppFullName,
+ /* [in] */ DWORD dwManifestPaths,
+ /* [in] */ LPCWSTR *ppwzManifestPaths,
+ /* [in] */ DWORD dwActivationData,
+ /* [in] */ LPCWSTR *ppwzActivationData,
+ /* [out] */ int *pReturnValue);
+
+ HRESULT ( STDMETHODCALLTYPE *ExecuteInDefaultAppDomain )(
+ ICLRRuntimeHost * This,
+ /* [in] */ LPCWSTR pwzAssemblyPath,
+ /* [in] */ LPCWSTR pwzTypeName,
+ /* [in] */ LPCWSTR pwzMethodName,
+ /* [in] */ LPCWSTR pwzArgument,
+ /* [out] */ DWORD *pReturnValue);
+
+ END_INTERFACE
+ } ICLRRuntimeHostVtbl;
+
+ interface ICLRRuntimeHost
+ {
+ CONST_VTBL struct ICLRRuntimeHostVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICLRRuntimeHost_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICLRRuntimeHost_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICLRRuntimeHost_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICLRRuntimeHost_Start(This) \
+ ( (This)->lpVtbl -> Start(This) )
+
+#define ICLRRuntimeHost_Stop(This) \
+ ( (This)->lpVtbl -> Stop(This) )
+
+#define ICLRRuntimeHost_SetHostControl(This,pHostControl) \
+ ( (This)->lpVtbl -> SetHostControl(This,pHostControl) )
+
+#define ICLRRuntimeHost_GetCLRControl(This,pCLRControl) \
+ ( (This)->lpVtbl -> GetCLRControl(This,pCLRControl) )
+
+#define ICLRRuntimeHost_UnloadAppDomain(This,dwAppDomainId,fWaitUntilDone) \
+ ( (This)->lpVtbl -> UnloadAppDomain(This,dwAppDomainId,fWaitUntilDone) )
+
+#define ICLRRuntimeHost_ExecuteInAppDomain(This,dwAppDomainId,pCallback,cookie) \
+ ( (This)->lpVtbl -> ExecuteInAppDomain(This,dwAppDomainId,pCallback,cookie) )
+
+#define ICLRRuntimeHost_GetCurrentAppDomainId(This,pdwAppDomainId) \
+ ( (This)->lpVtbl -> GetCurrentAppDomainId(This,pdwAppDomainId) )
+
+#define ICLRRuntimeHost_ExecuteApplication(This,pwzAppFullName,dwManifestPaths,ppwzManifestPaths,dwActivationData,ppwzActivationData,pReturnValue) \
+ ( (This)->lpVtbl -> ExecuteApplication(This,pwzAppFullName,dwManifestPaths,ppwzManifestPaths,dwActivationData,ppwzActivationData,pReturnValue) )
+
+#define ICLRRuntimeHost_ExecuteInDefaultAppDomain(This,pwzAssemblyPath,pwzTypeName,pwzMethodName,pwzArgument,pReturnValue) \
+ ( (This)->lpVtbl -> ExecuteInDefaultAppDomain(This,pwzAssemblyPath,pwzTypeName,pwzMethodName,pwzArgument,pReturnValue) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICLRRuntimeHost_INTERFACE_DEFINED__ */
+
+
+/* interface __MIDL_itf_mscoree_0000_0010 */
+/* [local] */
+
+#define CORECLR_HOST_AUTHENTICATION_KEY 0x1C6CA6F94025800LL
+#define CORECLR_HOST_AUTHENTICATION_KEY_NONGEN 0x1C6CA6F94025801LL
+
+
+extern RPC_IF_HANDLE __MIDL_itf_mscoree_0000_0010_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_mscoree_0000_0010_v0_0_s_ifspec;
+
+#ifndef __ICLRRuntimeHost2_INTERFACE_DEFINED__
+#define __ICLRRuntimeHost2_INTERFACE_DEFINED__
+
+/* interface ICLRRuntimeHost2 */
+/* [local][unique][helpstring][version][uuid][object] */
+
+
+EXTERN_C const IID IID_ICLRRuntimeHost2;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("712AB73F-2C22-4807-AD7E-F501D7B72C2D")
+ ICLRRuntimeHost2 : public ICLRRuntimeHost
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE CreateAppDomainWithManager(
+ /* [in] */ LPCWSTR wszFriendlyName,
+ /* [in] */ DWORD dwFlags,
+ /* [in] */ LPCWSTR wszAppDomainManagerAssemblyName,
+ /* [in] */ LPCWSTR wszAppDomainManagerTypeName,
+ /* [in] */ int nProperties,
+ /* [in] */ LPCWSTR *pPropertyNames,
+ /* [in] */ LPCWSTR *pPropertyValues,
+ /* [out] */ DWORD *pAppDomainID) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE CreateDelegate(
+ /* [in] */ DWORD appDomainID,
+ /* [in] */ LPCWSTR wszAssemblyName,
+ /* [in] */ LPCWSTR wszClassName,
+ /* [in] */ LPCWSTR wszMethodName,
+ /* [out] */ INT_PTR *fnPtr) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Authenticate(
+ /* [in] */ ULONGLONG authKey) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE RegisterMacEHPort( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetStartupFlags(
+ /* [in] */ STARTUP_FLAGS dwFlags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE DllGetActivationFactory(
+ /* [in] */ DWORD appDomainID,
+ /* [in] */ LPCWSTR wszTypeName,
+ /* [out] */ IActivationFactory **factory) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ExecuteAssembly(
+ /* [in] */ DWORD dwAppDomainId,
+ /* [in] */ LPCWSTR pwzAssemblyPath,
+ /* [in] */ int argc,
+ /* [in] */ LPCWSTR *argv,
+ /* [out] */ DWORD *pReturnValue) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICLRRuntimeHost2Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICLRRuntimeHost2 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICLRRuntimeHost2 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICLRRuntimeHost2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Start )(
+ ICLRRuntimeHost2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Stop )(
+ ICLRRuntimeHost2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *SetHostControl )(
+ ICLRRuntimeHost2 * This,
+ /* [in] */ IHostControl *pHostControl);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCLRControl )(
+ ICLRRuntimeHost2 * This,
+ /* [out] */ ICLRControl **pCLRControl);
+
+ HRESULT ( STDMETHODCALLTYPE *UnloadAppDomain )(
+ ICLRRuntimeHost2 * This,
+ /* [in] */ DWORD dwAppDomainId,
+ /* [in] */ BOOL fWaitUntilDone);
+
+ HRESULT ( STDMETHODCALLTYPE *ExecuteInAppDomain )(
+ ICLRRuntimeHost2 * This,
+ /* [in] */ DWORD dwAppDomainId,
+ /* [in] */ FExecuteInAppDomainCallback pCallback,
+ /* [in] */ void *cookie);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCurrentAppDomainId )(
+ ICLRRuntimeHost2 * This,
+ /* [out] */ DWORD *pdwAppDomainId);
+
+ HRESULT ( STDMETHODCALLTYPE *ExecuteApplication )(
+ ICLRRuntimeHost2 * This,
+ /* [in] */ LPCWSTR pwzAppFullName,
+ /* [in] */ DWORD dwManifestPaths,
+ /* [in] */ LPCWSTR *ppwzManifestPaths,
+ /* [in] */ DWORD dwActivationData,
+ /* [in] */ LPCWSTR *ppwzActivationData,
+ /* [out] */ int *pReturnValue);
+
+ HRESULT ( STDMETHODCALLTYPE *ExecuteInDefaultAppDomain )(
+ ICLRRuntimeHost2 * This,
+ /* [in] */ LPCWSTR pwzAssemblyPath,
+ /* [in] */ LPCWSTR pwzTypeName,
+ /* [in] */ LPCWSTR pwzMethodName,
+ /* [in] */ LPCWSTR pwzArgument,
+ /* [out] */ DWORD *pReturnValue);
+
+ HRESULT ( STDMETHODCALLTYPE *CreateAppDomainWithManager )(
+ ICLRRuntimeHost2 * This,
+ /* [in] */ LPCWSTR wszFriendlyName,
+ /* [in] */ DWORD dwFlags,
+ /* [in] */ LPCWSTR wszAppDomainManagerAssemblyName,
+ /* [in] */ LPCWSTR wszAppDomainManagerTypeName,
+ /* [in] */ int nProperties,
+ /* [in] */ LPCWSTR *pPropertyNames,
+ /* [in] */ LPCWSTR *pPropertyValues,
+ /* [out] */ DWORD *pAppDomainID);
+
+ HRESULT ( STDMETHODCALLTYPE *CreateDelegate )(
+ ICLRRuntimeHost2 * This,
+ /* [in] */ DWORD appDomainID,
+ /* [in] */ LPCWSTR wszAssemblyName,
+ /* [in] */ LPCWSTR wszClassName,
+ /* [in] */ LPCWSTR wszMethodName,
+ /* [out] */ INT_PTR *fnPtr);
+
+ HRESULT ( STDMETHODCALLTYPE *Authenticate )(
+ ICLRRuntimeHost2 * This,
+ /* [in] */ ULONGLONG authKey);
+
+ HRESULT ( STDMETHODCALLTYPE *RegisterMacEHPort )(
+ ICLRRuntimeHost2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *SetStartupFlags )(
+ ICLRRuntimeHost2 * This,
+ /* [in] */ STARTUP_FLAGS dwFlags);
+
+ HRESULT ( STDMETHODCALLTYPE *DllGetActivationFactory )(
+ ICLRRuntimeHost2 * This,
+ /* [in] */ DWORD appDomainID,
+ /* [in] */ LPCWSTR wszTypeName,
+ /* [out] */ IActivationFactory **factory);
+
+ HRESULT ( STDMETHODCALLTYPE *ExecuteAssembly )(
+ ICLRRuntimeHost2 * This,
+ /* [in] */ DWORD dwAppDomainId,
+ /* [in] */ LPCWSTR pwzAssemblyPath,
+ /* [in] */ int argc,
+ /* [in] */ LPCWSTR *argv,
+ /* [out] */ DWORD *pReturnValue);
+
+ END_INTERFACE
+ } ICLRRuntimeHost2Vtbl;
+
+ interface ICLRRuntimeHost2
+ {
+ CONST_VTBL struct ICLRRuntimeHost2Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICLRRuntimeHost2_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICLRRuntimeHost2_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICLRRuntimeHost2_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICLRRuntimeHost2_Start(This) \
+ ( (This)->lpVtbl -> Start(This) )
+
+#define ICLRRuntimeHost2_Stop(This) \
+ ( (This)->lpVtbl -> Stop(This) )
+
+#define ICLRRuntimeHost2_SetHostControl(This,pHostControl) \
+ ( (This)->lpVtbl -> SetHostControl(This,pHostControl) )
+
+#define ICLRRuntimeHost2_GetCLRControl(This,pCLRControl) \
+ ( (This)->lpVtbl -> GetCLRControl(This,pCLRControl) )
+
+#define ICLRRuntimeHost2_UnloadAppDomain(This,dwAppDomainId,fWaitUntilDone) \
+ ( (This)->lpVtbl -> UnloadAppDomain(This,dwAppDomainId,fWaitUntilDone) )
+
+#define ICLRRuntimeHost2_ExecuteInAppDomain(This,dwAppDomainId,pCallback,cookie) \
+ ( (This)->lpVtbl -> ExecuteInAppDomain(This,dwAppDomainId,pCallback,cookie) )
+
+#define ICLRRuntimeHost2_GetCurrentAppDomainId(This,pdwAppDomainId) \
+ ( (This)->lpVtbl -> GetCurrentAppDomainId(This,pdwAppDomainId) )
+
+#define ICLRRuntimeHost2_ExecuteApplication(This,pwzAppFullName,dwManifestPaths,ppwzManifestPaths,dwActivationData,ppwzActivationData,pReturnValue) \
+ ( (This)->lpVtbl -> ExecuteApplication(This,pwzAppFullName,dwManifestPaths,ppwzManifestPaths,dwActivationData,ppwzActivationData,pReturnValue) )
+
+#define ICLRRuntimeHost2_ExecuteInDefaultAppDomain(This,pwzAssemblyPath,pwzTypeName,pwzMethodName,pwzArgument,pReturnValue) \
+ ( (This)->lpVtbl -> ExecuteInDefaultAppDomain(This,pwzAssemblyPath,pwzTypeName,pwzMethodName,pwzArgument,pReturnValue) )
+
+
+#define ICLRRuntimeHost2_CreateAppDomainWithManager(This,wszFriendlyName,dwFlags,wszAppDomainManagerAssemblyName,wszAppDomainManagerTypeName,nProperties,pPropertyNames,pPropertyValues,pAppDomainID) \
+ ( (This)->lpVtbl -> CreateAppDomainWithManager(This,wszFriendlyName,dwFlags,wszAppDomainManagerAssemblyName,wszAppDomainManagerTypeName,nProperties,pPropertyNames,pPropertyValues,pAppDomainID) )
+
+#define ICLRRuntimeHost2_CreateDelegate(This,appDomainID,wszAssemblyName,wszClassName,wszMethodName,fnPtr) \
+ ( (This)->lpVtbl -> CreateDelegate(This,appDomainID,wszAssemblyName,wszClassName,wszMethodName,fnPtr) )
+
+#define ICLRRuntimeHost2_Authenticate(This,authKey) \
+ ( (This)->lpVtbl -> Authenticate(This,authKey) )
+
+#define ICLRRuntimeHost2_RegisterMacEHPort(This) \
+ ( (This)->lpVtbl -> RegisterMacEHPort(This) )
+
+#define ICLRRuntimeHost2_SetStartupFlags(This,dwFlags) \
+ ( (This)->lpVtbl -> SetStartupFlags(This,dwFlags) )
+
+#define ICLRRuntimeHost2_DllGetActivationFactory(This,appDomainID,wszTypeName,factory) \
+ ( (This)->lpVtbl -> DllGetActivationFactory(This,appDomainID,wszTypeName,factory) )
+
+#define ICLRRuntimeHost2_ExecuteAssembly(This,dwAppDomainId,pwzAssemblyPath,argc,argv,pReturnValue) \
+ ( (This)->lpVtbl -> ExecuteAssembly(This,dwAppDomainId,pwzAssemblyPath,argc,argv,pReturnValue) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICLRRuntimeHost2_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICLRExecutionManager_INTERFACE_DEFINED__
+#define __ICLRExecutionManager_INTERFACE_DEFINED__
+
+/* interface ICLRExecutionManager */
+/* [object][local][unique][helpstring][version][uuid] */
+
+
+EXTERN_C const IID IID_ICLRExecutionManager;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("1000A3E7-B420-4620-AE30-FB19B587AD1D")
+ ICLRExecutionManager : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE Pause(
+ /* [in] */ DWORD dwAppDomainId,
+ /* [in] */ DWORD dwFlags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Resume(
+ /* [in] */ DWORD dwAppDomainId) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICLRExecutionManagerVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICLRExecutionManager * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICLRExecutionManager * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICLRExecutionManager * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Pause )(
+ ICLRExecutionManager * This,
+ /* [in] */ DWORD dwAppDomainId,
+ /* [in] */ DWORD dwFlags);
+
+ HRESULT ( STDMETHODCALLTYPE *Resume )(
+ ICLRExecutionManager * This,
+ /* [in] */ DWORD dwAppDomainId);
+
+ END_INTERFACE
+ } ICLRExecutionManagerVtbl;
+
+ interface ICLRExecutionManager
+ {
+ CONST_VTBL struct ICLRExecutionManagerVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICLRExecutionManager_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICLRExecutionManager_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICLRExecutionManager_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICLRExecutionManager_Pause(This,dwAppDomainId,dwFlags) \
+ ( (This)->lpVtbl -> Pause(This,dwAppDomainId,dwFlags) )
+
+#define ICLRExecutionManager_Resume(This,dwAppDomainId) \
+ ( (This)->lpVtbl -> Resume(This,dwAppDomainId) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICLRExecutionManager_INTERFACE_DEFINED__ */
+
+
+#ifndef __IHostNetCFDebugControlManager_INTERFACE_DEFINED__
+#define __IHostNetCFDebugControlManager_INTERFACE_DEFINED__
+
+/* interface IHostNetCFDebugControlManager */
+/* [object][local][unique][helpstring][version][uuid] */
+
+
+EXTERN_C const IID IID_IHostNetCFDebugControlManager;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("F2833A0C-F944-48d8-940E-F59425EDBFCF")
+ IHostNetCFDebugControlManager : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE NotifyPause(
+ DWORD dwReserved) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE NotifyResume(
+ DWORD dwReserved) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IHostNetCFDebugControlManagerVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IHostNetCFDebugControlManager * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IHostNetCFDebugControlManager * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IHostNetCFDebugControlManager * This);
+
+ HRESULT ( STDMETHODCALLTYPE *NotifyPause )(
+ IHostNetCFDebugControlManager * This,
+ DWORD dwReserved);
+
+ HRESULT ( STDMETHODCALLTYPE *NotifyResume )(
+ IHostNetCFDebugControlManager * This,
+ DWORD dwReserved);
+
+ END_INTERFACE
+ } IHostNetCFDebugControlManagerVtbl;
+
+ interface IHostNetCFDebugControlManager
+ {
+ CONST_VTBL struct IHostNetCFDebugControlManagerVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IHostNetCFDebugControlManager_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IHostNetCFDebugControlManager_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IHostNetCFDebugControlManager_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IHostNetCFDebugControlManager_NotifyPause(This,dwReserved) \
+ ( (This)->lpVtbl -> NotifyPause(This,dwReserved) )
+
+#define IHostNetCFDebugControlManager_NotifyResume(This,dwReserved) \
+ ( (This)->lpVtbl -> NotifyResume(This,dwReserved) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IHostNetCFDebugControlManager_INTERFACE_DEFINED__ */
+
+
+/* interface __MIDL_itf_mscoree_0000_0013 */
+/* [local] */
+
+typedef /* [public] */
+enum __MIDL___MIDL_itf_mscoree_0000_0013_0001
+ {
+ eNoChecks = 0,
+ eSynchronization = 0x1,
+ eSharedState = 0x2,
+ eExternalProcessMgmt = 0x4,
+ eSelfAffectingProcessMgmt = 0x8,
+ eExternalThreading = 0x10,
+ eSelfAffectingThreading = 0x20,
+ eSecurityInfrastructure = 0x40,
+ eUI = 0x80,
+ eMayLeakOnAbort = 0x100,
+ eAll = 0x1ff
+ } EApiCategories;
+
+typedef /* [public] */
+enum __MIDL___MIDL_itf_mscoree_0000_0013_0002
+ {
+ eInitializeNewDomainFlags_None = 0,
+ eInitializeNewDomainFlags_NoSecurityChanges = 0x2
+ } EInitializeNewDomainFlags;
+
+
+
+extern RPC_IF_HANDLE __MIDL_itf_mscoree_0000_0013_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_mscoree_0000_0013_v0_0_s_ifspec;
+
+
+#ifndef __mscoree_LIBRARY_DEFINED__
+#define __mscoree_LIBRARY_DEFINED__
+
+/* library mscoree */
+/* [helpstring][version][uuid] */
+
+#define CCW_PTR int *
+
+EXTERN_C const IID LIBID_mscoree;
+
+#ifndef __ITypeName_INTERFACE_DEFINED__
+#define __ITypeName_INTERFACE_DEFINED__
+
+/* interface ITypeName */
+/* [unique][helpstring][uuid][oleautomation][object] */
+
+
+EXTERN_C const IID IID_ITypeName;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("B81FF171-20F3-11d2-8DCC-00A0C9B00522")
+ ITypeName : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetNameCount(
+ /* [retval][out] */ DWORD *pCount) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetNames(
+ /* [in] */ DWORD count,
+ /* [out] */ BSTR *rgbszNames,
+ /* [retval][out] */ DWORD *pCount) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetTypeArgumentCount(
+ /* [retval][out] */ DWORD *pCount) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetTypeArguments(
+ /* [in] */ DWORD count,
+ /* [out] */ ITypeName **rgpArguments,
+ /* [retval][out] */ DWORD *pCount) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetModifierLength(
+ /* [retval][out] */ DWORD *pCount) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetModifiers(
+ /* [in] */ DWORD count,
+ /* [out] */ DWORD *rgModifiers,
+ /* [retval][out] */ DWORD *pCount) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetAssemblyName(
+ /* [retval][out] */ BSTR *rgbszAssemblyNames) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ITypeNameVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ITypeName * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ITypeName * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ITypeName * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetNameCount )(
+ ITypeName * This,
+ /* [retval][out] */ DWORD *pCount);
+
+ HRESULT ( STDMETHODCALLTYPE *GetNames )(
+ ITypeName * This,
+ /* [in] */ DWORD count,
+ /* [out] */ BSTR *rgbszNames,
+ /* [retval][out] */ DWORD *pCount);
+
+ HRESULT ( STDMETHODCALLTYPE *GetTypeArgumentCount )(
+ ITypeName * This,
+ /* [retval][out] */ DWORD *pCount);
+
+ HRESULT ( STDMETHODCALLTYPE *GetTypeArguments )(
+ ITypeName * This,
+ /* [in] */ DWORD count,
+ /* [out] */ ITypeName **rgpArguments,
+ /* [retval][out] */ DWORD *pCount);
+
+ HRESULT ( STDMETHODCALLTYPE *GetModifierLength )(
+ ITypeName * This,
+ /* [retval][out] */ DWORD *pCount);
+
+ HRESULT ( STDMETHODCALLTYPE *GetModifiers )(
+ ITypeName * This,
+ /* [in] */ DWORD count,
+ /* [out] */ DWORD *rgModifiers,
+ /* [retval][out] */ DWORD *pCount);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAssemblyName )(
+ ITypeName * This,
+ /* [retval][out] */ BSTR *rgbszAssemblyNames);
+
+ END_INTERFACE
+ } ITypeNameVtbl;
+
+ interface ITypeName
+ {
+ CONST_VTBL struct ITypeNameVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ITypeName_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ITypeName_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ITypeName_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ITypeName_GetNameCount(This,pCount) \
+ ( (This)->lpVtbl -> GetNameCount(This,pCount) )
+
+#define ITypeName_GetNames(This,count,rgbszNames,pCount) \
+ ( (This)->lpVtbl -> GetNames(This,count,rgbszNames,pCount) )
+
+#define ITypeName_GetTypeArgumentCount(This,pCount) \
+ ( (This)->lpVtbl -> GetTypeArgumentCount(This,pCount) )
+
+#define ITypeName_GetTypeArguments(This,count,rgpArguments,pCount) \
+ ( (This)->lpVtbl -> GetTypeArguments(This,count,rgpArguments,pCount) )
+
+#define ITypeName_GetModifierLength(This,pCount) \
+ ( (This)->lpVtbl -> GetModifierLength(This,pCount) )
+
+#define ITypeName_GetModifiers(This,count,rgModifiers,pCount) \
+ ( (This)->lpVtbl -> GetModifiers(This,count,rgModifiers,pCount) )
+
+#define ITypeName_GetAssemblyName(This,rgbszAssemblyNames) \
+ ( (This)->lpVtbl -> GetAssemblyName(This,rgbszAssemblyNames) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ITypeName_INTERFACE_DEFINED__ */
+
+
+#ifndef __ITypeNameBuilder_INTERFACE_DEFINED__
+#define __ITypeNameBuilder_INTERFACE_DEFINED__
+
+/* interface ITypeNameBuilder */
+/* [unique][helpstring][uuid][oleautomation][object] */
+
+
+EXTERN_C const IID IID_ITypeNameBuilder;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("B81FF171-20F3-11d2-8DCC-00A0C9B00523")
+ ITypeNameBuilder : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE OpenGenericArguments( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE CloseGenericArguments( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE OpenGenericArgument( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE CloseGenericArgument( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE AddName(
+ /* [in] */ LPCWSTR szName) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE AddPointer( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE AddByRef( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE AddSzArray( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE AddArray(
+ /* [in] */ DWORD rank) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE AddAssemblySpec(
+ /* [in] */ LPCWSTR szAssemblySpec) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ToString(
+ /* [retval][out] */ BSTR *pszStringRepresentation) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Clear( void) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ITypeNameBuilderVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ITypeNameBuilder * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ITypeNameBuilder * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ITypeNameBuilder * This);
+
+ HRESULT ( STDMETHODCALLTYPE *OpenGenericArguments )(
+ ITypeNameBuilder * This);
+
+ HRESULT ( STDMETHODCALLTYPE *CloseGenericArguments )(
+ ITypeNameBuilder * This);
+
+ HRESULT ( STDMETHODCALLTYPE *OpenGenericArgument )(
+ ITypeNameBuilder * This);
+
+ HRESULT ( STDMETHODCALLTYPE *CloseGenericArgument )(
+ ITypeNameBuilder * This);
+
+ HRESULT ( STDMETHODCALLTYPE *AddName )(
+ ITypeNameBuilder * This,
+ /* [in] */ LPCWSTR szName);
+
+ HRESULT ( STDMETHODCALLTYPE *AddPointer )(
+ ITypeNameBuilder * This);
+
+ HRESULT ( STDMETHODCALLTYPE *AddByRef )(
+ ITypeNameBuilder * This);
+
+ HRESULT ( STDMETHODCALLTYPE *AddSzArray )(
+ ITypeNameBuilder * This);
+
+ HRESULT ( STDMETHODCALLTYPE *AddArray )(
+ ITypeNameBuilder * This,
+ /* [in] */ DWORD rank);
+
+ HRESULT ( STDMETHODCALLTYPE *AddAssemblySpec )(
+ ITypeNameBuilder * This,
+ /* [in] */ LPCWSTR szAssemblySpec);
+
+ HRESULT ( STDMETHODCALLTYPE *ToString )(
+ ITypeNameBuilder * This,
+ /* [retval][out] */ BSTR *pszStringRepresentation);
+
+ HRESULT ( STDMETHODCALLTYPE *Clear )(
+ ITypeNameBuilder * This);
+
+ END_INTERFACE
+ } ITypeNameBuilderVtbl;
+
+ interface ITypeNameBuilder
+ {
+ CONST_VTBL struct ITypeNameBuilderVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ITypeNameBuilder_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ITypeNameBuilder_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ITypeNameBuilder_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ITypeNameBuilder_OpenGenericArguments(This) \
+ ( (This)->lpVtbl -> OpenGenericArguments(This) )
+
+#define ITypeNameBuilder_CloseGenericArguments(This) \
+ ( (This)->lpVtbl -> CloseGenericArguments(This) )
+
+#define ITypeNameBuilder_OpenGenericArgument(This) \
+ ( (This)->lpVtbl -> OpenGenericArgument(This) )
+
+#define ITypeNameBuilder_CloseGenericArgument(This) \
+ ( (This)->lpVtbl -> CloseGenericArgument(This) )
+
+#define ITypeNameBuilder_AddName(This,szName) \
+ ( (This)->lpVtbl -> AddName(This,szName) )
+
+#define ITypeNameBuilder_AddPointer(This) \
+ ( (This)->lpVtbl -> AddPointer(This) )
+
+#define ITypeNameBuilder_AddByRef(This) \
+ ( (This)->lpVtbl -> AddByRef(This) )
+
+#define ITypeNameBuilder_AddSzArray(This) \
+ ( (This)->lpVtbl -> AddSzArray(This) )
+
+#define ITypeNameBuilder_AddArray(This,rank) \
+ ( (This)->lpVtbl -> AddArray(This,rank) )
+
+#define ITypeNameBuilder_AddAssemblySpec(This,szAssemblySpec) \
+ ( (This)->lpVtbl -> AddAssemblySpec(This,szAssemblySpec) )
+
+#define ITypeNameBuilder_ToString(This,pszStringRepresentation) \
+ ( (This)->lpVtbl -> ToString(This,pszStringRepresentation) )
+
+#define ITypeNameBuilder_Clear(This) \
+ ( (This)->lpVtbl -> Clear(This) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ITypeNameBuilder_INTERFACE_DEFINED__ */
+
+
+#ifndef __ITypeNameFactory_INTERFACE_DEFINED__
+#define __ITypeNameFactory_INTERFACE_DEFINED__
+
+/* interface ITypeNameFactory */
+/* [unique][helpstring][uuid][oleautomation][object] */
+
+
+EXTERN_C const IID IID_ITypeNameFactory;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("B81FF171-20F3-11d2-8DCC-00A0C9B00521")
+ ITypeNameFactory : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE ParseTypeName(
+ /* [in] */ LPCWSTR szName,
+ /* [out] */ DWORD *pError,
+ /* [retval][out] */ ITypeName **ppTypeName) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetTypeNameBuilder(
+ /* [retval][out] */ ITypeNameBuilder **ppTypeBuilder) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ITypeNameFactoryVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ITypeNameFactory * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ITypeNameFactory * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ITypeNameFactory * This);
+
+ HRESULT ( STDMETHODCALLTYPE *ParseTypeName )(
+ ITypeNameFactory * This,
+ /* [in] */ LPCWSTR szName,
+ /* [out] */ DWORD *pError,
+ /* [retval][out] */ ITypeName **ppTypeName);
+
+ HRESULT ( STDMETHODCALLTYPE *GetTypeNameBuilder )(
+ ITypeNameFactory * This,
+ /* [retval][out] */ ITypeNameBuilder **ppTypeBuilder);
+
+ END_INTERFACE
+ } ITypeNameFactoryVtbl;
+
+ interface ITypeNameFactory
+ {
+ CONST_VTBL struct ITypeNameFactoryVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ITypeNameFactory_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ITypeNameFactory_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ITypeNameFactory_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ITypeNameFactory_ParseTypeName(This,szName,pError,ppTypeName) \
+ ( (This)->lpVtbl -> ParseTypeName(This,szName,pError,ppTypeName) )
+
+#define ITypeNameFactory_GetTypeNameBuilder(This,ppTypeBuilder) \
+ ( (This)->lpVtbl -> GetTypeNameBuilder(This,ppTypeBuilder) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ITypeNameFactory_INTERFACE_DEFINED__ */
+
+
+#ifndef __IManagedObject_INTERFACE_DEFINED__
+#define __IManagedObject_INTERFACE_DEFINED__
+
+/* interface IManagedObject */
+/* [proxy][unique][helpstring][uuid][oleautomation][object] */
+
+
+EXTERN_C const IID IID_IManagedObject;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("C3FCC19E-A970-11d2-8B5A-00A0C9B7C9C4")
+ IManagedObject : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetSerializedBuffer(
+ /* [out] */ BSTR *pBSTR) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetObjectIdentity(
+ /* [out] */ BSTR *pBSTRGUID,
+ /* [out] */ int *AppDomainID,
+ /* [out] */ int *pCCW) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IManagedObjectVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IManagedObject * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IManagedObject * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IManagedObject * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetSerializedBuffer )(
+ IManagedObject * This,
+ /* [out] */ BSTR *pBSTR);
+
+ HRESULT ( STDMETHODCALLTYPE *GetObjectIdentity )(
+ IManagedObject * This,
+ /* [out] */ BSTR *pBSTRGUID,
+ /* [out] */ int *AppDomainID,
+ /* [out] */ int *pCCW);
+
+ END_INTERFACE
+ } IManagedObjectVtbl;
+
+ interface IManagedObject
+ {
+ CONST_VTBL struct IManagedObjectVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IManagedObject_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IManagedObject_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IManagedObject_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IManagedObject_GetSerializedBuffer(This,pBSTR) \
+ ( (This)->lpVtbl -> GetSerializedBuffer(This,pBSTR) )
+
+#define IManagedObject_GetObjectIdentity(This,pBSTRGUID,AppDomainID,pCCW) \
+ ( (This)->lpVtbl -> GetObjectIdentity(This,pBSTRGUID,AppDomainID,pCCW) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IManagedObject_INTERFACE_DEFINED__ */
+
+
+EXTERN_C const CLSID CLSID_ComCallUnmarshal;
+
+#ifdef __cplusplus
+
+class DECLSPEC_UUID("3F281000-E95A-11d2-886B-00C04F869F04")
+ComCallUnmarshal;
+#endif
+
+EXTERN_C const CLSID CLSID_ComCallUnmarshalV4;
+
+#ifdef __cplusplus
+
+class DECLSPEC_UUID("45FB4600-E6E8-4928-B25E-50476FF79425")
+ComCallUnmarshalV4;
+#endif
+
+EXTERN_C const CLSID CLSID_CLRRuntimeHost;
+
+#ifdef __cplusplus
+
+class DECLSPEC_UUID("90F1A06E-7712-4762-86B5-7A5EBA6BDB02")
+CLRRuntimeHost;
+#endif
+
+EXTERN_C const CLSID CLSID_TypeNameFactory;
+
+#ifdef __cplusplus
+
+class DECLSPEC_UUID("B81FF171-20F3-11d2-8DCC-00A0C9B00525")
+TypeNameFactory;
+#endif
+#endif /* __mscoree_LIBRARY_DEFINED__ */
+
+/* interface __MIDL_itf_mscoree_0000_0014 */
+/* [local] */
+
+typedef /* [public] */
+enum __MIDL___MIDL_itf_mscoree_0000_0014_0001
+ {
+ eCurrentContext = 0,
+ eRestrictedContext = 0x1
+ } EContextType;
+
+
+
+extern RPC_IF_HANDLE __MIDL_itf_mscoree_0000_0014_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_mscoree_0000_0014_v0_0_s_ifspec;
+
+#ifndef __ICLRAppDomainResourceMonitor_INTERFACE_DEFINED__
+#define __ICLRAppDomainResourceMonitor_INTERFACE_DEFINED__
+
+/* interface ICLRAppDomainResourceMonitor */
+/* [object][local][unique][helpstring][uuid][version] */
+
+
+EXTERN_C const IID IID_ICLRAppDomainResourceMonitor;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("c62de18c-2e23-4aea-8423-b40c1fc59eae")
+ ICLRAppDomainResourceMonitor : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetCurrentAllocated(
+ /* [in] */ DWORD dwAppDomainId,
+ /* [out] */ ULONGLONG *pBytesAllocated) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetCurrentSurvived(
+ /* [in] */ DWORD dwAppDomainId,
+ /* [out] */ ULONGLONG *pAppDomainBytesSurvived,
+ /* [out] */ ULONGLONG *pTotalBytesSurvived) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetCurrentCpuTime(
+ /* [in] */ DWORD dwAppDomainId,
+ /* [out] */ ULONGLONG *pMilliseconds) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICLRAppDomainResourceMonitorVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICLRAppDomainResourceMonitor * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICLRAppDomainResourceMonitor * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICLRAppDomainResourceMonitor * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCurrentAllocated )(
+ ICLRAppDomainResourceMonitor * This,
+ /* [in] */ DWORD dwAppDomainId,
+ /* [out] */ ULONGLONG *pBytesAllocated);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCurrentSurvived )(
+ ICLRAppDomainResourceMonitor * This,
+ /* [in] */ DWORD dwAppDomainId,
+ /* [out] */ ULONGLONG *pAppDomainBytesSurvived,
+ /* [out] */ ULONGLONG *pTotalBytesSurvived);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCurrentCpuTime )(
+ ICLRAppDomainResourceMonitor * This,
+ /* [in] */ DWORD dwAppDomainId,
+ /* [out] */ ULONGLONG *pMilliseconds);
+
+ END_INTERFACE
+ } ICLRAppDomainResourceMonitorVtbl;
+
+ interface ICLRAppDomainResourceMonitor
+ {
+ CONST_VTBL struct ICLRAppDomainResourceMonitorVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICLRAppDomainResourceMonitor_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICLRAppDomainResourceMonitor_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICLRAppDomainResourceMonitor_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICLRAppDomainResourceMonitor_GetCurrentAllocated(This,dwAppDomainId,pBytesAllocated) \
+ ( (This)->lpVtbl -> GetCurrentAllocated(This,dwAppDomainId,pBytesAllocated) )
+
+#define ICLRAppDomainResourceMonitor_GetCurrentSurvived(This,dwAppDomainId,pAppDomainBytesSurvived,pTotalBytesSurvived) \
+ ( (This)->lpVtbl -> GetCurrentSurvived(This,dwAppDomainId,pAppDomainBytesSurvived,pTotalBytesSurvived) )
+
+#define ICLRAppDomainResourceMonitor_GetCurrentCpuTime(This,dwAppDomainId,pMilliseconds) \
+ ( (This)->lpVtbl -> GetCurrentCpuTime(This,dwAppDomainId,pMilliseconds) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICLRAppDomainResourceMonitor_INTERFACE_DEFINED__ */
+
+
+/* interface __MIDL_itf_mscoree_0000_0015 */
+/* [local] */
+
+#undef DEPRECATED_CLR_STDAPI
+#undef DECLARE_DEPRECATED
+#undef DEPRECATED_CLR_API_MESG
+
+
+extern RPC_IF_HANDLE __MIDL_itf_mscoree_0000_0015_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_mscoree_0000_0015_v0_0_s_ifspec;
+
+/* Additional Prototypes for ALL interfaces */
+
+/* end of Additional Prototypes */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+
diff --git a/src/pal/prebuilt/inc/mscorsvc.h b/src/pal/prebuilt/inc/mscorsvc.h
new file mode 100644
index 0000000000..c51d8bdc9a
--- /dev/null
+++ b/src/pal/prebuilt/inc/mscorsvc.h
@@ -0,0 +1,2824 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+
+
+/* this ALWAYS GENERATED file contains the definitions for the interfaces */
+
+
+ /* File created by MIDL compiler version 8.00.0603 */
+/* @@MIDL_FILE_HEADING( ) */
+
+#pragma warning( disable: 4049 ) /* more than 64k source lines */
+
+
+/* verify that the <rpcndr.h> version is high enough to compile this file*/
+#ifndef __REQUIRED_RPCNDR_H_VERSION__
+#define __REQUIRED_RPCNDR_H_VERSION__ 475
+#endif
+
+#include "rpc.h"
+#include "rpcndr.h"
+
+#ifndef __RPCNDR_H_VERSION__
+#error this stub requires an updated version of <rpcndr.h>
+#endif // __RPCNDR_H_VERSION__
+
+#ifndef COM_NO_WINDOWS_H
+#include "windows.h"
+#include "ole2.h"
+#endif /*COM_NO_WINDOWS_H*/
+
+#ifndef __mscorsvc_h__
+#define __mscorsvc_h__
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+/* Forward Declarations */
+
+#ifndef __ICorSvcDependencies_FWD_DEFINED__
+#define __ICorSvcDependencies_FWD_DEFINED__
+typedef interface ICorSvcDependencies ICorSvcDependencies;
+
+#endif /* __ICorSvcDependencies_FWD_DEFINED__ */
+
+
+#ifndef __ICorSvcWorker_FWD_DEFINED__
+#define __ICorSvcWorker_FWD_DEFINED__
+typedef interface ICorSvcWorker ICorSvcWorker;
+
+#endif /* __ICorSvcWorker_FWD_DEFINED__ */
+
+
+#ifndef __ICorSvcWorker2_FWD_DEFINED__
+#define __ICorSvcWorker2_FWD_DEFINED__
+typedef interface ICorSvcWorker2 ICorSvcWorker2;
+
+#endif /* __ICorSvcWorker2_FWD_DEFINED__ */
+
+
+#ifndef __ICorSvcWorker3_FWD_DEFINED__
+#define __ICorSvcWorker3_FWD_DEFINED__
+typedef interface ICorSvcWorker3 ICorSvcWorker3;
+
+#endif /* __ICorSvcWorker3_FWD_DEFINED__ */
+
+
+#ifndef __ICorSvcSetPrivateAttributes_FWD_DEFINED__
+#define __ICorSvcSetPrivateAttributes_FWD_DEFINED__
+typedef interface ICorSvcSetPrivateAttributes ICorSvcSetPrivateAttributes;
+
+#endif /* __ICorSvcSetPrivateAttributes_FWD_DEFINED__ */
+
+
+#ifndef __ICorSvcRepository_FWD_DEFINED__
+#define __ICorSvcRepository_FWD_DEFINED__
+typedef interface ICorSvcRepository ICorSvcRepository;
+
+#endif /* __ICorSvcRepository_FWD_DEFINED__ */
+
+
+#ifndef __ICorSvcAppX_FWD_DEFINED__
+#define __ICorSvcAppX_FWD_DEFINED__
+typedef interface ICorSvcAppX ICorSvcAppX;
+
+#endif /* __ICorSvcAppX_FWD_DEFINED__ */
+
+
+#ifndef __ICorSvcLogger_FWD_DEFINED__
+#define __ICorSvcLogger_FWD_DEFINED__
+typedef interface ICorSvcLogger ICorSvcLogger;
+
+#endif /* __ICorSvcLogger_FWD_DEFINED__ */
+
+
+#ifndef __ICorSvcPooledWorker_FWD_DEFINED__
+#define __ICorSvcPooledWorker_FWD_DEFINED__
+typedef interface ICorSvcPooledWorker ICorSvcPooledWorker;
+
+#endif /* __ICorSvcPooledWorker_FWD_DEFINED__ */
+
+
+#ifndef __ICorSvcBindToWorker_FWD_DEFINED__
+#define __ICorSvcBindToWorker_FWD_DEFINED__
+typedef interface ICorSvcBindToWorker ICorSvcBindToWorker;
+
+#endif /* __ICorSvcBindToWorker_FWD_DEFINED__ */
+
+
+#ifndef __ICorSvc_FWD_DEFINED__
+#define __ICorSvc_FWD_DEFINED__
+typedef interface ICorSvc ICorSvc;
+
+#endif /* __ICorSvc_FWD_DEFINED__ */
+
+
+#ifndef __ICompileProgressNotification_FWD_DEFINED__
+#define __ICompileProgressNotification_FWD_DEFINED__
+typedef interface ICompileProgressNotification ICompileProgressNotification;
+
+#endif /* __ICompileProgressNotification_FWD_DEFINED__ */
+
+
+#ifndef __ICompileProgressNotification2_FWD_DEFINED__
+#define __ICompileProgressNotification2_FWD_DEFINED__
+typedef interface ICompileProgressNotification2 ICompileProgressNotification2;
+
+#endif /* __ICompileProgressNotification2_FWD_DEFINED__ */
+
+
+#ifndef __ICorSvcInstaller_FWD_DEFINED__
+#define __ICorSvcInstaller_FWD_DEFINED__
+typedef interface ICorSvcInstaller ICorSvcInstaller;
+
+#endif /* __ICorSvcInstaller_FWD_DEFINED__ */
+
+
+#ifndef __ICorSvcAdvancedInstaller_FWD_DEFINED__
+#define __ICorSvcAdvancedInstaller_FWD_DEFINED__
+typedef interface ICorSvcAdvancedInstaller ICorSvcAdvancedInstaller;
+
+#endif /* __ICorSvcAdvancedInstaller_FWD_DEFINED__ */
+
+
+#ifndef __ICorSvcOptimizer_FWD_DEFINED__
+#define __ICorSvcOptimizer_FWD_DEFINED__
+typedef interface ICorSvcOptimizer ICorSvcOptimizer;
+
+#endif /* __ICorSvcOptimizer_FWD_DEFINED__ */
+
+
+#ifndef __ICorSvcOptimizer2_FWD_DEFINED__
+#define __ICorSvcOptimizer2_FWD_DEFINED__
+typedef interface ICorSvcOptimizer2 ICorSvcOptimizer2;
+
+#endif /* __ICorSvcOptimizer2_FWD_DEFINED__ */
+
+
+#ifndef __ICorSvcOptimizer3_FWD_DEFINED__
+#define __ICorSvcOptimizer3_FWD_DEFINED__
+typedef interface ICorSvcOptimizer3 ICorSvcOptimizer3;
+
+#endif /* __ICorSvcOptimizer3_FWD_DEFINED__ */
+
+
+#ifndef __ICorSvcManager_FWD_DEFINED__
+#define __ICorSvcManager_FWD_DEFINED__
+typedef interface ICorSvcManager ICorSvcManager;
+
+#endif /* __ICorSvcManager_FWD_DEFINED__ */
+
+
+#ifndef __ICorSvcManager2_FWD_DEFINED__
+#define __ICorSvcManager2_FWD_DEFINED__
+typedef interface ICorSvcManager2 ICorSvcManager2;
+
+#endif /* __ICorSvcManager2_FWD_DEFINED__ */
+
+
+#ifndef __ICorSvcSetLegacyServiceBehavior_FWD_DEFINED__
+#define __ICorSvcSetLegacyServiceBehavior_FWD_DEFINED__
+typedef interface ICorSvcSetLegacyServiceBehavior ICorSvcSetLegacyServiceBehavior;
+
+#endif /* __ICorSvcSetLegacyServiceBehavior_FWD_DEFINED__ */
+
+
+#ifndef __ICorSvcSetTaskBootTriggerState_FWD_DEFINED__
+#define __ICorSvcSetTaskBootTriggerState_FWD_DEFINED__
+typedef interface ICorSvcSetTaskBootTriggerState ICorSvcSetTaskBootTriggerState;
+
+#endif /* __ICorSvcSetTaskBootTriggerState_FWD_DEFINED__ */
+
+
+#ifndef __ICorSvcSetTaskDelayStartTriggerState_FWD_DEFINED__
+#define __ICorSvcSetTaskDelayStartTriggerState_FWD_DEFINED__
+typedef interface ICorSvcSetTaskDelayStartTriggerState ICorSvcSetTaskDelayStartTriggerState;
+
+#endif /* __ICorSvcSetTaskDelayStartTriggerState_FWD_DEFINED__ */
+
+
+/* header files for imported files */
+#include "unknwn.h"
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+
+/* interface __MIDL_itf_mscorsvc_0000_0000 */
+/* [local] */
+
+#if 0
+#endif
+EXTERN_GUID(CLSID_CorSvcWorker, 0x8ed1a844, 0x32a7, 0x4a67, 0xba, 0x62, 0xf8, 0xd5, 0xaf, 0xdf, 0xf4, 0x60);
+EXTERN_GUID(CLSID_CorSvcBindToWorker, 0x9f74fb09, 0x4221, 0x40b4, 0xae, 0x21, 0xae, 0xb6, 0xdf, 0xf2, 0x99, 0x4e);
+STDAPI CorGetSvc(IUnknown **pIUnknown);
+
+
+extern RPC_IF_HANDLE __MIDL_itf_mscorsvc_0000_0000_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_mscorsvc_0000_0000_v0_0_s_ifspec;
+
+
+#ifndef __mscorsvc_LIBRARY_DEFINED__
+#define __mscorsvc_LIBRARY_DEFINED__
+
+/* library mscorsvc */
+/* [helpstring][version][uuid] */
+
+typedef /* [public][public][public][public][public][public][public][public] */
+enum __MIDL___MIDL_itf_mscorsvc_0001_0004_0001
+ {
+ ScenarioDefault = 0,
+ ScenarioAll = 0x1,
+ ScenarioDebug = 0x2,
+ ScenarioProfile = 0x8,
+ ScenarioTuningDataCollection = 0x10,
+ ScenarioLegacy = 0x20,
+ ScenarioNgenLastRetry = 0x10000,
+ ScenarioAutoNGen = 0x100000,
+ ScenarioRepositoryOnly = 0x200000
+ } OptimizationScenario;
+
+typedef /* [public] */
+enum __MIDL___MIDL_itf_mscorsvc_0001_0004_0002
+ {
+ ScenarioEmitFixups = 0x10000,
+ ScenarioProfileInfo = 0x20000
+ } PrivateOptimizationScenario;
+
+typedef struct _SvcWorkerPriority
+ {
+ DWORD dwPriorityClass;
+ } SvcWorkerPriority;
+
+typedef /* [public] */
+enum __MIDL___MIDL_itf_mscorsvc_0001_0007_0001
+ {
+ DbgTypePdb = 0x1
+ } NGenPrivateAttributesFlags;
+
+typedef struct _NGenPrivateAttributes
+ {
+ DWORD Flags;
+ DWORD ZapStats;
+ BSTR DbgDir;
+ } NGenPrivateAttributes;
+
+typedef /* [public][public] */
+enum __MIDL___MIDL_itf_mscorsvc_0001_0008_0001
+ {
+ RepositoryDefault = 0,
+ MoveFromRepository = 0x1,
+ CopyToRepository = 0x2,
+ IgnoreRepository = 0x4
+ } RepositoryFlags;
+
+typedef
+enum CorSvcLogLevel
+ {
+ LogLevel_Error = 0,
+ LogLevel_Warning = ( LogLevel_Error + 1 ) ,
+ LogLevel_Success = ( LogLevel_Warning + 1 ) ,
+ LogLevel_Info = ( LogLevel_Success + 1 )
+ } CorSvcLogLevel;
+
+
+EXTERN_C const IID LIBID_mscorsvc;
+
+#ifndef __ICorSvcDependencies_INTERFACE_DEFINED__
+#define __ICorSvcDependencies_INTERFACE_DEFINED__
+
+/* interface ICorSvcDependencies */
+/* [unique][uuid][oleautomation][object] */
+
+
+EXTERN_C const IID IID_ICorSvcDependencies;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("ddb34005-9ba3-4025-9554-f00a2df5dbf5")
+ ICorSvcDependencies : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetAssemblyDependencies(
+ /* [in] */ BSTR pAssemblyName,
+ /* [out] */ SAFEARRAY * *pDependencies,
+ /* [out] */ DWORD *assemblyNGenSetting,
+ /* [out] */ BSTR *pNativeImageIdentity,
+ /* [out] */ BSTR *pAssemblyDisplayName,
+ /* [out] */ SAFEARRAY * *pDependencyLoadSetting,
+ /* [out] */ SAFEARRAY * *pDependencyNGenSetting) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorSvcDependenciesVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorSvcDependencies * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorSvcDependencies * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorSvcDependencies * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAssemblyDependencies )(
+ ICorSvcDependencies * This,
+ /* [in] */ BSTR pAssemblyName,
+ /* [out] */ SAFEARRAY * *pDependencies,
+ /* [out] */ DWORD *assemblyNGenSetting,
+ /* [out] */ BSTR *pNativeImageIdentity,
+ /* [out] */ BSTR *pAssemblyDisplayName,
+ /* [out] */ SAFEARRAY * *pDependencyLoadSetting,
+ /* [out] */ SAFEARRAY * *pDependencyNGenSetting);
+
+ END_INTERFACE
+ } ICorSvcDependenciesVtbl;
+
+ interface ICorSvcDependencies
+ {
+ CONST_VTBL struct ICorSvcDependenciesVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorSvcDependencies_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorSvcDependencies_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorSvcDependencies_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorSvcDependencies_GetAssemblyDependencies(This,pAssemblyName,pDependencies,assemblyNGenSetting,pNativeImageIdentity,pAssemblyDisplayName,pDependencyLoadSetting,pDependencyNGenSetting) \
+ ( (This)->lpVtbl -> GetAssemblyDependencies(This,pAssemblyName,pDependencies,assemblyNGenSetting,pNativeImageIdentity,pAssemblyDisplayName,pDependencyLoadSetting,pDependencyNGenSetting) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorSvcDependencies_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorSvcWorker_INTERFACE_DEFINED__
+#define __ICorSvcWorker_INTERFACE_DEFINED__
+
+/* interface ICorSvcWorker */
+/* [unique][uuid][oleautomation][object] */
+
+
+EXTERN_C const IID IID_ICorSvcWorker;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("d1047bc2-67c0-400c-a94c-e64446a67fbe")
+ ICorSvcWorker : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE SetPriority(
+ /* [in] */ SvcWorkerPriority priority) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE OptimizeAssembly(
+ /* [in] */ BSTR pAssemblyName,
+ /* [in] */ BSTR pApplicationName,
+ /* [in] */ OptimizationScenario scenario,
+ /* [in] */ SAFEARRAY * loadAlwaysList,
+ /* [in] */ SAFEARRAY * loadSometimesList,
+ /* [in] */ SAFEARRAY * loadNeverList,
+ /* [out] */ BSTR *pNativeImageIdentity) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE DeleteNativeImage(
+ /* [in] */ BSTR pAssemblyName,
+ /* [in] */ BSTR pNativeImage) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE DisplayNativeImages(
+ /* [in] */ BSTR pAssemblyName) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetCorSvcDependencies(
+ /* [in] */ BSTR pApplicationName,
+ /* [in] */ OptimizationScenario scenario,
+ /* [out] */ ICorSvcDependencies **pCorSvcDependencies) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Stop( void) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorSvcWorkerVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorSvcWorker * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorSvcWorker * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorSvcWorker * This);
+
+ HRESULT ( STDMETHODCALLTYPE *SetPriority )(
+ ICorSvcWorker * This,
+ /* [in] */ SvcWorkerPriority priority);
+
+ HRESULT ( STDMETHODCALLTYPE *OptimizeAssembly )(
+ ICorSvcWorker * This,
+ /* [in] */ BSTR pAssemblyName,
+ /* [in] */ BSTR pApplicationName,
+ /* [in] */ OptimizationScenario scenario,
+ /* [in] */ SAFEARRAY * loadAlwaysList,
+ /* [in] */ SAFEARRAY * loadSometimesList,
+ /* [in] */ SAFEARRAY * loadNeverList,
+ /* [out] */ BSTR *pNativeImageIdentity);
+
+ HRESULT ( STDMETHODCALLTYPE *DeleteNativeImage )(
+ ICorSvcWorker * This,
+ /* [in] */ BSTR pAssemblyName,
+ /* [in] */ BSTR pNativeImage);
+
+ HRESULT ( STDMETHODCALLTYPE *DisplayNativeImages )(
+ ICorSvcWorker * This,
+ /* [in] */ BSTR pAssemblyName);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCorSvcDependencies )(
+ ICorSvcWorker * This,
+ /* [in] */ BSTR pApplicationName,
+ /* [in] */ OptimizationScenario scenario,
+ /* [out] */ ICorSvcDependencies **pCorSvcDependencies);
+
+ HRESULT ( STDMETHODCALLTYPE *Stop )(
+ ICorSvcWorker * This);
+
+ END_INTERFACE
+ } ICorSvcWorkerVtbl;
+
+ interface ICorSvcWorker
+ {
+ CONST_VTBL struct ICorSvcWorkerVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorSvcWorker_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorSvcWorker_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorSvcWorker_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorSvcWorker_SetPriority(This,priority) \
+ ( (This)->lpVtbl -> SetPriority(This,priority) )
+
+#define ICorSvcWorker_OptimizeAssembly(This,pAssemblyName,pApplicationName,scenario,loadAlwaysList,loadSometimesList,loadNeverList,pNativeImageIdentity) \
+ ( (This)->lpVtbl -> OptimizeAssembly(This,pAssemblyName,pApplicationName,scenario,loadAlwaysList,loadSometimesList,loadNeverList,pNativeImageIdentity) )
+
+#define ICorSvcWorker_DeleteNativeImage(This,pAssemblyName,pNativeImage) \
+ ( (This)->lpVtbl -> DeleteNativeImage(This,pAssemblyName,pNativeImage) )
+
+#define ICorSvcWorker_DisplayNativeImages(This,pAssemblyName) \
+ ( (This)->lpVtbl -> DisplayNativeImages(This,pAssemblyName) )
+
+#define ICorSvcWorker_GetCorSvcDependencies(This,pApplicationName,scenario,pCorSvcDependencies) \
+ ( (This)->lpVtbl -> GetCorSvcDependencies(This,pApplicationName,scenario,pCorSvcDependencies) )
+
+#define ICorSvcWorker_Stop(This) \
+ ( (This)->lpVtbl -> Stop(This) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorSvcWorker_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorSvcWorker2_INTERFACE_DEFINED__
+#define __ICorSvcWorker2_INTERFACE_DEFINED__
+
+/* interface ICorSvcWorker2 */
+/* [unique][uuid][oleautomation][object] */
+
+
+EXTERN_C const IID IID_ICorSvcWorker2;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("f3358a7d-0061-4776-880e-a2f21b9ef93e")
+ ICorSvcWorker2 : public ICorSvcWorker
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE CreatePdb(
+ /* [in] */ BSTR pAssemblyName,
+ /* [in] */ BSTR pAppBaseOrConfig,
+ /* [in] */ OptimizationScenario scenario,
+ /* [in] */ BSTR pNativeImagePath,
+ /* [in] */ BSTR pPdbPath) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorSvcWorker2Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorSvcWorker2 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorSvcWorker2 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorSvcWorker2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *SetPriority )(
+ ICorSvcWorker2 * This,
+ /* [in] */ SvcWorkerPriority priority);
+
+ HRESULT ( STDMETHODCALLTYPE *OptimizeAssembly )(
+ ICorSvcWorker2 * This,
+ /* [in] */ BSTR pAssemblyName,
+ /* [in] */ BSTR pApplicationName,
+ /* [in] */ OptimizationScenario scenario,
+ /* [in] */ SAFEARRAY * loadAlwaysList,
+ /* [in] */ SAFEARRAY * loadSometimesList,
+ /* [in] */ SAFEARRAY * loadNeverList,
+ /* [out] */ BSTR *pNativeImageIdentity);
+
+ HRESULT ( STDMETHODCALLTYPE *DeleteNativeImage )(
+ ICorSvcWorker2 * This,
+ /* [in] */ BSTR pAssemblyName,
+ /* [in] */ BSTR pNativeImage);
+
+ HRESULT ( STDMETHODCALLTYPE *DisplayNativeImages )(
+ ICorSvcWorker2 * This,
+ /* [in] */ BSTR pAssemblyName);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCorSvcDependencies )(
+ ICorSvcWorker2 * This,
+ /* [in] */ BSTR pApplicationName,
+ /* [in] */ OptimizationScenario scenario,
+ /* [out] */ ICorSvcDependencies **pCorSvcDependencies);
+
+ HRESULT ( STDMETHODCALLTYPE *Stop )(
+ ICorSvcWorker2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *CreatePdb )(
+ ICorSvcWorker2 * This,
+ /* [in] */ BSTR pAssemblyName,
+ /* [in] */ BSTR pAppBaseOrConfig,
+ /* [in] */ OptimizationScenario scenario,
+ /* [in] */ BSTR pNativeImagePath,
+ /* [in] */ BSTR pPdbPath);
+
+ END_INTERFACE
+ } ICorSvcWorker2Vtbl;
+
+ interface ICorSvcWorker2
+ {
+ CONST_VTBL struct ICorSvcWorker2Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorSvcWorker2_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorSvcWorker2_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorSvcWorker2_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorSvcWorker2_SetPriority(This,priority) \
+ ( (This)->lpVtbl -> SetPriority(This,priority) )
+
+#define ICorSvcWorker2_OptimizeAssembly(This,pAssemblyName,pApplicationName,scenario,loadAlwaysList,loadSometimesList,loadNeverList,pNativeImageIdentity) \
+ ( (This)->lpVtbl -> OptimizeAssembly(This,pAssemblyName,pApplicationName,scenario,loadAlwaysList,loadSometimesList,loadNeverList,pNativeImageIdentity) )
+
+#define ICorSvcWorker2_DeleteNativeImage(This,pAssemblyName,pNativeImage) \
+ ( (This)->lpVtbl -> DeleteNativeImage(This,pAssemblyName,pNativeImage) )
+
+#define ICorSvcWorker2_DisplayNativeImages(This,pAssemblyName) \
+ ( (This)->lpVtbl -> DisplayNativeImages(This,pAssemblyName) )
+
+#define ICorSvcWorker2_GetCorSvcDependencies(This,pApplicationName,scenario,pCorSvcDependencies) \
+ ( (This)->lpVtbl -> GetCorSvcDependencies(This,pApplicationName,scenario,pCorSvcDependencies) )
+
+#define ICorSvcWorker2_Stop(This) \
+ ( (This)->lpVtbl -> Stop(This) )
+
+
+#define ICorSvcWorker2_CreatePdb(This,pAssemblyName,pAppBaseOrConfig,scenario,pNativeImagePath,pPdbPath) \
+ ( (This)->lpVtbl -> CreatePdb(This,pAssemblyName,pAppBaseOrConfig,scenario,pNativeImagePath,pPdbPath) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorSvcWorker2_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorSvcWorker3_INTERFACE_DEFINED__
+#define __ICorSvcWorker3_INTERFACE_DEFINED__
+
+/* interface ICorSvcWorker3 */
+/* [unique][uuid][oleautomation][object] */
+
+
+EXTERN_C const IID IID_ICorSvcWorker3;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("DC516615-47BE-477e-8B55-C5ABE0D76B8F")
+ ICorSvcWorker3 : public ICorSvcWorker2
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE CreatePdb2(
+ /* [in] */ BSTR pAssemblyName,
+ /* [in] */ BSTR pAppBaseOrConfig,
+ /* [in] */ OptimizationScenario scenario,
+ /* [in] */ BSTR pNativeImagePath,
+ /* [in] */ BSTR pPdbPath,
+ /* [in] */ BOOL pdbLines,
+ /* [in] */ BSTR managedPdbSearchPath) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorSvcWorker3Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorSvcWorker3 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorSvcWorker3 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorSvcWorker3 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *SetPriority )(
+ ICorSvcWorker3 * This,
+ /* [in] */ SvcWorkerPriority priority);
+
+ HRESULT ( STDMETHODCALLTYPE *OptimizeAssembly )(
+ ICorSvcWorker3 * This,
+ /* [in] */ BSTR pAssemblyName,
+ /* [in] */ BSTR pApplicationName,
+ /* [in] */ OptimizationScenario scenario,
+ /* [in] */ SAFEARRAY * loadAlwaysList,
+ /* [in] */ SAFEARRAY * loadSometimesList,
+ /* [in] */ SAFEARRAY * loadNeverList,
+ /* [out] */ BSTR *pNativeImageIdentity);
+
+ HRESULT ( STDMETHODCALLTYPE *DeleteNativeImage )(
+ ICorSvcWorker3 * This,
+ /* [in] */ BSTR pAssemblyName,
+ /* [in] */ BSTR pNativeImage);
+
+ HRESULT ( STDMETHODCALLTYPE *DisplayNativeImages )(
+ ICorSvcWorker3 * This,
+ /* [in] */ BSTR pAssemblyName);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCorSvcDependencies )(
+ ICorSvcWorker3 * This,
+ /* [in] */ BSTR pApplicationName,
+ /* [in] */ OptimizationScenario scenario,
+ /* [out] */ ICorSvcDependencies **pCorSvcDependencies);
+
+ HRESULT ( STDMETHODCALLTYPE *Stop )(
+ ICorSvcWorker3 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *CreatePdb )(
+ ICorSvcWorker3 * This,
+ /* [in] */ BSTR pAssemblyName,
+ /* [in] */ BSTR pAppBaseOrConfig,
+ /* [in] */ OptimizationScenario scenario,
+ /* [in] */ BSTR pNativeImagePath,
+ /* [in] */ BSTR pPdbPath);
+
+ HRESULT ( STDMETHODCALLTYPE *CreatePdb2 )(
+ ICorSvcWorker3 * This,
+ /* [in] */ BSTR pAssemblyName,
+ /* [in] */ BSTR pAppBaseOrConfig,
+ /* [in] */ OptimizationScenario scenario,
+ /* [in] */ BSTR pNativeImagePath,
+ /* [in] */ BSTR pPdbPath,
+ /* [in] */ BOOL pdbLines,
+ /* [in] */ BSTR managedPdbSearchPath);
+
+ END_INTERFACE
+ } ICorSvcWorker3Vtbl;
+
+ interface ICorSvcWorker3
+ {
+ CONST_VTBL struct ICorSvcWorker3Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorSvcWorker3_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorSvcWorker3_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorSvcWorker3_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorSvcWorker3_SetPriority(This,priority) \
+ ( (This)->lpVtbl -> SetPriority(This,priority) )
+
+#define ICorSvcWorker3_OptimizeAssembly(This,pAssemblyName,pApplicationName,scenario,loadAlwaysList,loadSometimesList,loadNeverList,pNativeImageIdentity) \
+ ( (This)->lpVtbl -> OptimizeAssembly(This,pAssemblyName,pApplicationName,scenario,loadAlwaysList,loadSometimesList,loadNeverList,pNativeImageIdentity) )
+
+#define ICorSvcWorker3_DeleteNativeImage(This,pAssemblyName,pNativeImage) \
+ ( (This)->lpVtbl -> DeleteNativeImage(This,pAssemblyName,pNativeImage) )
+
+#define ICorSvcWorker3_DisplayNativeImages(This,pAssemblyName) \
+ ( (This)->lpVtbl -> DisplayNativeImages(This,pAssemblyName) )
+
+#define ICorSvcWorker3_GetCorSvcDependencies(This,pApplicationName,scenario,pCorSvcDependencies) \
+ ( (This)->lpVtbl -> GetCorSvcDependencies(This,pApplicationName,scenario,pCorSvcDependencies) )
+
+#define ICorSvcWorker3_Stop(This) \
+ ( (This)->lpVtbl -> Stop(This) )
+
+
+#define ICorSvcWorker3_CreatePdb(This,pAssemblyName,pAppBaseOrConfig,scenario,pNativeImagePath,pPdbPath) \
+ ( (This)->lpVtbl -> CreatePdb(This,pAssemblyName,pAppBaseOrConfig,scenario,pNativeImagePath,pPdbPath) )
+
+
+#define ICorSvcWorker3_CreatePdb2(This,pAssemblyName,pAppBaseOrConfig,scenario,pNativeImagePath,pPdbPath,pdbLines,managedPdbSearchPath) \
+ ( (This)->lpVtbl -> CreatePdb2(This,pAssemblyName,pAppBaseOrConfig,scenario,pNativeImagePath,pPdbPath,pdbLines,managedPdbSearchPath) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorSvcWorker3_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorSvcSetPrivateAttributes_INTERFACE_DEFINED__
+#define __ICorSvcSetPrivateAttributes_INTERFACE_DEFINED__
+
+/* interface ICorSvcSetPrivateAttributes */
+/* [unique][uuid][oleautomation][object] */
+
+
+EXTERN_C const IID IID_ICorSvcSetPrivateAttributes;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("b18e0b40-c089-4350-8328-066c668bccc2")
+ ICorSvcSetPrivateAttributes : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE SetNGenPrivateAttributes(
+ /* [in] */ NGenPrivateAttributes ngenPrivateAttributes) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorSvcSetPrivateAttributesVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorSvcSetPrivateAttributes * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorSvcSetPrivateAttributes * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorSvcSetPrivateAttributes * This);
+
+ HRESULT ( STDMETHODCALLTYPE *SetNGenPrivateAttributes )(
+ ICorSvcSetPrivateAttributes * This,
+ /* [in] */ NGenPrivateAttributes ngenPrivateAttributes);
+
+ END_INTERFACE
+ } ICorSvcSetPrivateAttributesVtbl;
+
+ interface ICorSvcSetPrivateAttributes
+ {
+ CONST_VTBL struct ICorSvcSetPrivateAttributesVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorSvcSetPrivateAttributes_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorSvcSetPrivateAttributes_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorSvcSetPrivateAttributes_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorSvcSetPrivateAttributes_SetNGenPrivateAttributes(This,ngenPrivateAttributes) \
+ ( (This)->lpVtbl -> SetNGenPrivateAttributes(This,ngenPrivateAttributes) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorSvcSetPrivateAttributes_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorSvcRepository_INTERFACE_DEFINED__
+#define __ICorSvcRepository_INTERFACE_DEFINED__
+
+/* interface ICorSvcRepository */
+/* [unique][uuid][oleautomation][object] */
+
+
+EXTERN_C const IID IID_ICorSvcRepository;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("d5346658-b5fd-4353-9647-07ad4783d5a0")
+ ICorSvcRepository : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE SetRepository(
+ /* [in] */ BSTR pRepositoryDir,
+ /* [in] */ RepositoryFlags repositoryFlags) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorSvcRepositoryVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorSvcRepository * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorSvcRepository * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorSvcRepository * This);
+
+ HRESULT ( STDMETHODCALLTYPE *SetRepository )(
+ ICorSvcRepository * This,
+ /* [in] */ BSTR pRepositoryDir,
+ /* [in] */ RepositoryFlags repositoryFlags);
+
+ END_INTERFACE
+ } ICorSvcRepositoryVtbl;
+
+ interface ICorSvcRepository
+ {
+ CONST_VTBL struct ICorSvcRepositoryVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorSvcRepository_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorSvcRepository_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorSvcRepository_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorSvcRepository_SetRepository(This,pRepositoryDir,repositoryFlags) \
+ ( (This)->lpVtbl -> SetRepository(This,pRepositoryDir,repositoryFlags) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorSvcRepository_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorSvcAppX_INTERFACE_DEFINED__
+#define __ICorSvcAppX_INTERFACE_DEFINED__
+
+/* interface ICorSvcAppX */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_ICorSvcAppX;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("5c814791-559e-4f7f-83ce-184a4ccbae24")
+ ICorSvcAppX : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE SetPackage(
+ /* [in] */ BSTR pPackageFullName) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetLocalAppDataDirectory(
+ /* [in] */ BSTR pLocalAppDataDirectory) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorSvcAppXVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorSvcAppX * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorSvcAppX * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorSvcAppX * This);
+
+ HRESULT ( STDMETHODCALLTYPE *SetPackage )(
+ ICorSvcAppX * This,
+ /* [in] */ BSTR pPackageFullName);
+
+ HRESULT ( STDMETHODCALLTYPE *SetLocalAppDataDirectory )(
+ ICorSvcAppX * This,
+ /* [in] */ BSTR pLocalAppDataDirectory);
+
+ END_INTERFACE
+ } ICorSvcAppXVtbl;
+
+ interface ICorSvcAppX
+ {
+ CONST_VTBL struct ICorSvcAppXVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorSvcAppX_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorSvcAppX_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorSvcAppX_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorSvcAppX_SetPackage(This,pPackageFullName) \
+ ( (This)->lpVtbl -> SetPackage(This,pPackageFullName) )
+
+#define ICorSvcAppX_SetLocalAppDataDirectory(This,pLocalAppDataDirectory) \
+ ( (This)->lpVtbl -> SetLocalAppDataDirectory(This,pLocalAppDataDirectory) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorSvcAppX_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorSvcLogger_INTERFACE_DEFINED__
+#define __ICorSvcLogger_INTERFACE_DEFINED__
+
+/* interface ICorSvcLogger */
+/* [unique][uuid][oleautomation][object] */
+
+
+EXTERN_C const IID IID_ICorSvcLogger;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("d189ff1a-e266-4f13-9637-4b9522279ffc")
+ ICorSvcLogger : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE Log(
+ /* [in] */ CorSvcLogLevel logLevel,
+ /* [in] */ BSTR message) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorSvcLoggerVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorSvcLogger * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorSvcLogger * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorSvcLogger * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Log )(
+ ICorSvcLogger * This,
+ /* [in] */ CorSvcLogLevel logLevel,
+ /* [in] */ BSTR message);
+
+ END_INTERFACE
+ } ICorSvcLoggerVtbl;
+
+ interface ICorSvcLogger
+ {
+ CONST_VTBL struct ICorSvcLoggerVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorSvcLogger_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorSvcLogger_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorSvcLogger_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorSvcLogger_Log(This,logLevel,message) \
+ ( (This)->lpVtbl -> Log(This,logLevel,message) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorSvcLogger_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorSvcPooledWorker_INTERFACE_DEFINED__
+#define __ICorSvcPooledWorker_INTERFACE_DEFINED__
+
+/* interface ICorSvcPooledWorker */
+/* [unique][uuid][oleautomation][object] */
+
+
+EXTERN_C const IID IID_ICorSvcPooledWorker;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("0631e7e2-6046-4fde-8b6d-a09b64fda6f3")
+ ICorSvcPooledWorker : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE CanReuseProcess(
+ /* [in] */ OptimizationScenario scenario,
+ /* [in] */ ICorSvcLogger *pCorSvcLogger,
+ /* [out] */ BOOL *pCanContinue) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorSvcPooledWorkerVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorSvcPooledWorker * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorSvcPooledWorker * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorSvcPooledWorker * This);
+
+ HRESULT ( STDMETHODCALLTYPE *CanReuseProcess )(
+ ICorSvcPooledWorker * This,
+ /* [in] */ OptimizationScenario scenario,
+ /* [in] */ ICorSvcLogger *pCorSvcLogger,
+ /* [out] */ BOOL *pCanContinue);
+
+ END_INTERFACE
+ } ICorSvcPooledWorkerVtbl;
+
+ interface ICorSvcPooledWorker
+ {
+ CONST_VTBL struct ICorSvcPooledWorkerVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorSvcPooledWorker_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorSvcPooledWorker_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorSvcPooledWorker_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorSvcPooledWorker_CanReuseProcess(This,scenario,pCorSvcLogger,pCanContinue) \
+ ( (This)->lpVtbl -> CanReuseProcess(This,scenario,pCorSvcLogger,pCanContinue) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorSvcPooledWorker_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorSvcBindToWorker_INTERFACE_DEFINED__
+#define __ICorSvcBindToWorker_INTERFACE_DEFINED__
+
+/* interface ICorSvcBindToWorker */
+/* [unique][uuid][oleautomation][object] */
+
+
+EXTERN_C const IID IID_ICorSvcBindToWorker;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("5c6fb596-4828-4ed5-b9dd-293dad736fb5")
+ ICorSvcBindToWorker : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE BindToRuntimeWorker(
+ /* [in] */ BSTR pRuntimeVersion,
+ /* [in] */ DWORD ParentProcessID,
+ /* [in] */ BSTR pInterruptEventName,
+ /* [in] */ ICorSvcLogger *pCorSvcLogger,
+ /* [out] */ ICorSvcWorker **pCorSvcWorker) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorSvcBindToWorkerVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorSvcBindToWorker * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorSvcBindToWorker * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorSvcBindToWorker * This);
+
+ HRESULT ( STDMETHODCALLTYPE *BindToRuntimeWorker )(
+ ICorSvcBindToWorker * This,
+ /* [in] */ BSTR pRuntimeVersion,
+ /* [in] */ DWORD ParentProcessID,
+ /* [in] */ BSTR pInterruptEventName,
+ /* [in] */ ICorSvcLogger *pCorSvcLogger,
+ /* [out] */ ICorSvcWorker **pCorSvcWorker);
+
+ END_INTERFACE
+ } ICorSvcBindToWorkerVtbl;
+
+ interface ICorSvcBindToWorker
+ {
+ CONST_VTBL struct ICorSvcBindToWorkerVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorSvcBindToWorker_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorSvcBindToWorker_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorSvcBindToWorker_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorSvcBindToWorker_BindToRuntimeWorker(This,pRuntimeVersion,ParentProcessID,pInterruptEventName,pCorSvcLogger,pCorSvcWorker) \
+ ( (This)->lpVtbl -> BindToRuntimeWorker(This,pRuntimeVersion,ParentProcessID,pInterruptEventName,pCorSvcLogger,pCorSvcWorker) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorSvcBindToWorker_INTERFACE_DEFINED__ */
+
+#endif /* __mscorsvc_LIBRARY_DEFINED__ */
+
+/* interface __MIDL_itf_mscorsvc_0000_0001 */
+/* [local] */
+
+typedef /* [public][public] */
+enum __MIDL___MIDL_itf_mscorsvc_0000_0001_0001
+ {
+ Service_NoAction = -1,
+ Service_Start = 0,
+ Service_Stop = 0x1,
+ Service_Pause = 0x2,
+ Service_Continue = 0x3,
+ Service_Interrogate = 0x4,
+ Service_StartPaused = 0x5
+ } ControlServiceAction;
+
+typedef struct _COR_SERVICE_STATUS
+ {
+ WCHAR sServiceName[ 64 ];
+ DWORD dwServiceType;
+ DWORD dwCurrentState;
+ DWORD dwControlsAccepted;
+ DWORD dwWin32ExitCode;
+ DWORD dwServiceSpecificExitCode;
+ DWORD dwCheckPoint;
+ DWORD dwWaitHint;
+ } COR_SERVICE_STATUS;
+
+typedef struct _COR_SERVICE_STATUS *LPCOR_SERVICE_STATUS;
+
+typedef struct _ServiceOptions
+ {
+ BOOL RunAsWindowsService;
+ BOOL RunAsPrivateRuntime;
+ BOOL StartPaused;
+ } ServiceOptions;
+
+
+
+extern RPC_IF_HANDLE __MIDL_itf_mscorsvc_0000_0001_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_mscorsvc_0000_0001_v0_0_s_ifspec;
+
+#ifndef __ICorSvc_INTERFACE_DEFINED__
+#define __ICorSvc_INTERFACE_DEFINED__
+
+/* interface ICorSvc */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_ICorSvc;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("3eef5ff0-3680-4f20-8a8f-9051aca66b22")
+ ICorSvc : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetServiceManagerInterface(
+ /* [in] */ IUnknown **pIUnknown) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE InstallService( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE UninstallService( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ControlService(
+ /* [in] */ ControlServiceAction Action,
+ /* [out] */ LPCOR_SERVICE_STATUS lpServiceStatus) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE RunService(
+ /* [in] */ ServiceOptions options) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorSvcVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorSvc * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorSvc * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorSvc * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetServiceManagerInterface )(
+ ICorSvc * This,
+ /* [in] */ IUnknown **pIUnknown);
+
+ HRESULT ( STDMETHODCALLTYPE *InstallService )(
+ ICorSvc * This);
+
+ HRESULT ( STDMETHODCALLTYPE *UninstallService )(
+ ICorSvc * This);
+
+ HRESULT ( STDMETHODCALLTYPE *ControlService )(
+ ICorSvc * This,
+ /* [in] */ ControlServiceAction Action,
+ /* [out] */ LPCOR_SERVICE_STATUS lpServiceStatus);
+
+ HRESULT ( STDMETHODCALLTYPE *RunService )(
+ ICorSvc * This,
+ /* [in] */ ServiceOptions options);
+
+ END_INTERFACE
+ } ICorSvcVtbl;
+
+ interface ICorSvc
+ {
+ CONST_VTBL struct ICorSvcVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorSvc_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorSvc_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorSvc_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorSvc_GetServiceManagerInterface(This,pIUnknown) \
+ ( (This)->lpVtbl -> GetServiceManagerInterface(This,pIUnknown) )
+
+#define ICorSvc_InstallService(This) \
+ ( (This)->lpVtbl -> InstallService(This) )
+
+#define ICorSvc_UninstallService(This) \
+ ( (This)->lpVtbl -> UninstallService(This) )
+
+#define ICorSvc_ControlService(This,Action,lpServiceStatus) \
+ ( (This)->lpVtbl -> ControlService(This,Action,lpServiceStatus) )
+
+#define ICorSvc_RunService(This,options) \
+ ( (This)->lpVtbl -> RunService(This,options) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorSvc_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICompileProgressNotification_INTERFACE_DEFINED__
+#define __ICompileProgressNotification_INTERFACE_DEFINED__
+
+/* interface ICompileProgressNotification */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_ICompileProgressNotification;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("01c10030-6c81-4671-bd51-14b184c673b2")
+ ICompileProgressNotification : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE CompileStarted(
+ /* [in] */ DWORD cAssembliesToCompile,
+ /* [in] */ DWORD cTimeEstimate) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ProgressNotification(
+ /* [in] */ DWORD cAssembly,
+ /* [in] */ BSTR pAssemblyName,
+ /* [in] */ BOOL isStartNotification,
+ /* [in] */ HRESULT hrResult,
+ /* [in] */ BSTR errorExplanation,
+ /* [in] */ DWORD cTimeRemainingEstimate) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICompileProgressNotificationVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICompileProgressNotification * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICompileProgressNotification * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICompileProgressNotification * This);
+
+ HRESULT ( STDMETHODCALLTYPE *CompileStarted )(
+ ICompileProgressNotification * This,
+ /* [in] */ DWORD cAssembliesToCompile,
+ /* [in] */ DWORD cTimeEstimate);
+
+ HRESULT ( STDMETHODCALLTYPE *ProgressNotification )(
+ ICompileProgressNotification * This,
+ /* [in] */ DWORD cAssembly,
+ /* [in] */ BSTR pAssemblyName,
+ /* [in] */ BOOL isStartNotification,
+ /* [in] */ HRESULT hrResult,
+ /* [in] */ BSTR errorExplanation,
+ /* [in] */ DWORD cTimeRemainingEstimate);
+
+ END_INTERFACE
+ } ICompileProgressNotificationVtbl;
+
+ interface ICompileProgressNotification
+ {
+ CONST_VTBL struct ICompileProgressNotificationVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICompileProgressNotification_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICompileProgressNotification_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICompileProgressNotification_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICompileProgressNotification_CompileStarted(This,cAssembliesToCompile,cTimeEstimate) \
+ ( (This)->lpVtbl -> CompileStarted(This,cAssembliesToCompile,cTimeEstimate) )
+
+#define ICompileProgressNotification_ProgressNotification(This,cAssembly,pAssemblyName,isStartNotification,hrResult,errorExplanation,cTimeRemainingEstimate) \
+ ( (This)->lpVtbl -> ProgressNotification(This,cAssembly,pAssemblyName,isStartNotification,hrResult,errorExplanation,cTimeRemainingEstimate) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICompileProgressNotification_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICompileProgressNotification2_INTERFACE_DEFINED__
+#define __ICompileProgressNotification2_INTERFACE_DEFINED__
+
+/* interface ICompileProgressNotification2 */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_ICompileProgressNotification2;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("98E5BDE2-E9A0-4ADE-9CB2-6CD06FDB1A85")
+ ICompileProgressNotification2 : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE CompileStarted(
+ /* [in] */ DWORD cAssembliesToCompile,
+ /* [in] */ DWORD cTimeEstimate,
+ /* [in] */ DWORD threadID) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ProgressNotification(
+ /* [in] */ DWORD cAssembly,
+ /* [in] */ BSTR pAssemblyName,
+ /* [in] */ BOOL isStartNotification,
+ /* [in] */ HRESULT hrResult,
+ /* [in] */ BSTR errorExplanation,
+ /* [in] */ DWORD cTimeRemainingEstimate,
+ /* [in] */ DWORD threadID) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICompileProgressNotification2Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICompileProgressNotification2 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICompileProgressNotification2 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICompileProgressNotification2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *CompileStarted )(
+ ICompileProgressNotification2 * This,
+ /* [in] */ DWORD cAssembliesToCompile,
+ /* [in] */ DWORD cTimeEstimate,
+ /* [in] */ DWORD threadID);
+
+ HRESULT ( STDMETHODCALLTYPE *ProgressNotification )(
+ ICompileProgressNotification2 * This,
+ /* [in] */ DWORD cAssembly,
+ /* [in] */ BSTR pAssemblyName,
+ /* [in] */ BOOL isStartNotification,
+ /* [in] */ HRESULT hrResult,
+ /* [in] */ BSTR errorExplanation,
+ /* [in] */ DWORD cTimeRemainingEstimate,
+ /* [in] */ DWORD threadID);
+
+ END_INTERFACE
+ } ICompileProgressNotification2Vtbl;
+
+ interface ICompileProgressNotification2
+ {
+ CONST_VTBL struct ICompileProgressNotification2Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICompileProgressNotification2_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICompileProgressNotification2_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICompileProgressNotification2_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICompileProgressNotification2_CompileStarted(This,cAssembliesToCompile,cTimeEstimate,threadID) \
+ ( (This)->lpVtbl -> CompileStarted(This,cAssembliesToCompile,cTimeEstimate,threadID) )
+
+#define ICompileProgressNotification2_ProgressNotification(This,cAssembly,pAssemblyName,isStartNotification,hrResult,errorExplanation,cTimeRemainingEstimate,threadID) \
+ ( (This)->lpVtbl -> ProgressNotification(This,cAssembly,pAssemblyName,isStartNotification,hrResult,errorExplanation,cTimeRemainingEstimate,threadID) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICompileProgressNotification2_INTERFACE_DEFINED__ */
+
+
+/* interface __MIDL_itf_mscorsvc_0000_0004 */
+/* [local] */
+
+typedef /* [public][public] */
+enum __MIDL___MIDL_itf_mscorsvc_0000_0004_0001
+ {
+ DefaultOptimizeFlags = 0,
+ TolerateCompilationFailures = 0x1,
+ OptimizeNGenQueueOnly = 0x2
+ } OptimizeFlags;
+
+
+
+extern RPC_IF_HANDLE __MIDL_itf_mscorsvc_0000_0004_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_mscorsvc_0000_0004_v0_0_s_ifspec;
+
+#ifndef __ICorSvcInstaller_INTERFACE_DEFINED__
+#define __ICorSvcInstaller_INTERFACE_DEFINED__
+
+/* interface ICorSvcInstaller */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_ICorSvcInstaller;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("0523feee-eb0e-4857-b2aa-db787521d077")
+ ICorSvcInstaller : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE Install(
+ /* [in] */ BSTR path) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Uninstall(
+ /* [in] */ BSTR path) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Optimize(
+ /* [in] */ ICompileProgressNotification *pCompileProgressNotification,
+ /* [in] */ OptimizeFlags optimizeFlags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetLogger(
+ /* [in] */ ICorSvcLogger *pCorSvcLogger) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorSvcInstallerVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorSvcInstaller * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorSvcInstaller * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorSvcInstaller * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Install )(
+ ICorSvcInstaller * This,
+ /* [in] */ BSTR path);
+
+ HRESULT ( STDMETHODCALLTYPE *Uninstall )(
+ ICorSvcInstaller * This,
+ /* [in] */ BSTR path);
+
+ HRESULT ( STDMETHODCALLTYPE *Optimize )(
+ ICorSvcInstaller * This,
+ /* [in] */ ICompileProgressNotification *pCompileProgressNotification,
+ /* [in] */ OptimizeFlags optimizeFlags);
+
+ HRESULT ( STDMETHODCALLTYPE *SetLogger )(
+ ICorSvcInstaller * This,
+ /* [in] */ ICorSvcLogger *pCorSvcLogger);
+
+ END_INTERFACE
+ } ICorSvcInstallerVtbl;
+
+ interface ICorSvcInstaller
+ {
+ CONST_VTBL struct ICorSvcInstallerVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorSvcInstaller_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorSvcInstaller_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorSvcInstaller_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorSvcInstaller_Install(This,path) \
+ ( (This)->lpVtbl -> Install(This,path) )
+
+#define ICorSvcInstaller_Uninstall(This,path) \
+ ( (This)->lpVtbl -> Uninstall(This,path) )
+
+#define ICorSvcInstaller_Optimize(This,pCompileProgressNotification,optimizeFlags) \
+ ( (This)->lpVtbl -> Optimize(This,pCompileProgressNotification,optimizeFlags) )
+
+#define ICorSvcInstaller_SetLogger(This,pCorSvcLogger) \
+ ( (This)->lpVtbl -> SetLogger(This,pCorSvcLogger) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorSvcInstaller_INTERFACE_DEFINED__ */
+
+
+/* interface __MIDL_itf_mscorsvc_0000_0005 */
+/* [local] */
+
+typedef /* [public][public][public][public][public] */
+enum __MIDL___MIDL_itf_mscorsvc_0000_0005_0001
+ {
+ DefaultFlags = 0,
+ AllowPartialNames = 0x1,
+ KeepPriority = 0x2,
+ NoRoot = 0x4
+ } GeneralFlags;
+
+typedef /* [public][public][public][public][public] */
+enum __MIDL___MIDL_itf_mscorsvc_0000_0005_0002
+ {
+ Priority_None = -1,
+ Priority_0 = 0,
+ Priority_1 = 0x1,
+ Priority_2 = 0x2,
+ Priority_3 = 0x3,
+ Priority_Default = Priority_3,
+ Priority_Lowest = Priority_3,
+ Priority_LowestAggressive = Priority_2,
+ Priority_Highest = Priority_0,
+ Priority_Highest_Root = Priority_1,
+ Priority_Lowest_Root = Priority_3
+ } PriorityLevel;
+
+
+
+extern RPC_IF_HANDLE __MIDL_itf_mscorsvc_0000_0005_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_mscorsvc_0000_0005_v0_0_s_ifspec;
+
+#ifndef __ICorSvcAdvancedInstaller_INTERFACE_DEFINED__
+#define __ICorSvcAdvancedInstaller_INTERFACE_DEFINED__
+
+/* interface ICorSvcAdvancedInstaller */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_ICorSvcAdvancedInstaller;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("0871fb80-3ea0-47cc-9b51-d92e2aee75db")
+ ICorSvcAdvancedInstaller : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE Install(
+ /* [in] */ BSTR path,
+ /* [in] */ OptimizationScenario optScenario,
+ /* [in] */ BSTR config,
+ /* [in] */ GeneralFlags generalFlags,
+ /* [in] */ PriorityLevel priorityLevel) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Uninstall(
+ /* [in] */ BSTR path,
+ /* [in] */ OptimizationScenario optScenario,
+ /* [in] */ BSTR config,
+ /* [in] */ GeneralFlags generalFlags) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorSvcAdvancedInstallerVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorSvcAdvancedInstaller * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorSvcAdvancedInstaller * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorSvcAdvancedInstaller * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Install )(
+ ICorSvcAdvancedInstaller * This,
+ /* [in] */ BSTR path,
+ /* [in] */ OptimizationScenario optScenario,
+ /* [in] */ BSTR config,
+ /* [in] */ GeneralFlags generalFlags,
+ /* [in] */ PriorityLevel priorityLevel);
+
+ HRESULT ( STDMETHODCALLTYPE *Uninstall )(
+ ICorSvcAdvancedInstaller * This,
+ /* [in] */ BSTR path,
+ /* [in] */ OptimizationScenario optScenario,
+ /* [in] */ BSTR config,
+ /* [in] */ GeneralFlags generalFlags);
+
+ END_INTERFACE
+ } ICorSvcAdvancedInstallerVtbl;
+
+ interface ICorSvcAdvancedInstaller
+ {
+ CONST_VTBL struct ICorSvcAdvancedInstallerVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorSvcAdvancedInstaller_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorSvcAdvancedInstaller_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorSvcAdvancedInstaller_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorSvcAdvancedInstaller_Install(This,path,optScenario,config,generalFlags,priorityLevel) \
+ ( (This)->lpVtbl -> Install(This,path,optScenario,config,generalFlags,priorityLevel) )
+
+#define ICorSvcAdvancedInstaller_Uninstall(This,path,optScenario,config,generalFlags) \
+ ( (This)->lpVtbl -> Uninstall(This,path,optScenario,config,generalFlags) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorSvcAdvancedInstaller_INTERFACE_DEFINED__ */
+
+
+/* interface __MIDL_itf_mscorsvc_0000_0006 */
+/* [local] */
+
+typedef /* [public][public][public] */
+enum __MIDL___MIDL_itf_mscorsvc_0000_0006_0001
+ {
+ UpdateDefault = 0,
+ Force = 0x1,
+ PostReboot = 0x2
+ } UpdateFlags;
+
+
+
+extern RPC_IF_HANDLE __MIDL_itf_mscorsvc_0000_0006_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_mscorsvc_0000_0006_v0_0_s_ifspec;
+
+#ifndef __ICorSvcOptimizer_INTERFACE_DEFINED__
+#define __ICorSvcOptimizer_INTERFACE_DEFINED__
+
+/* interface ICorSvcOptimizer */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_ICorSvcOptimizer;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("94af0ec4-c10d-45d4-a625-d68d1b02a396")
+ ICorSvcOptimizer : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE Update(
+ /* [in] */ BSTR path,
+ /* [in] */ UpdateFlags updateFlags,
+ /* [in] */ GeneralFlags generalFlags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Display(
+ /* [in] */ BSTR path,
+ /* [in] */ GeneralFlags generalFlags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ScheduleWork(
+ /* [in] */ PriorityLevel priorityLevel) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorSvcOptimizerVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorSvcOptimizer * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorSvcOptimizer * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorSvcOptimizer * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Update )(
+ ICorSvcOptimizer * This,
+ /* [in] */ BSTR path,
+ /* [in] */ UpdateFlags updateFlags,
+ /* [in] */ GeneralFlags generalFlags);
+
+ HRESULT ( STDMETHODCALLTYPE *Display )(
+ ICorSvcOptimizer * This,
+ /* [in] */ BSTR path,
+ /* [in] */ GeneralFlags generalFlags);
+
+ HRESULT ( STDMETHODCALLTYPE *ScheduleWork )(
+ ICorSvcOptimizer * This,
+ /* [in] */ PriorityLevel priorityLevel);
+
+ END_INTERFACE
+ } ICorSvcOptimizerVtbl;
+
+ interface ICorSvcOptimizer
+ {
+ CONST_VTBL struct ICorSvcOptimizerVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorSvcOptimizer_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorSvcOptimizer_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorSvcOptimizer_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorSvcOptimizer_Update(This,path,updateFlags,generalFlags) \
+ ( (This)->lpVtbl -> Update(This,path,updateFlags,generalFlags) )
+
+#define ICorSvcOptimizer_Display(This,path,generalFlags) \
+ ( (This)->lpVtbl -> Display(This,path,generalFlags) )
+
+#define ICorSvcOptimizer_ScheduleWork(This,priorityLevel) \
+ ( (This)->lpVtbl -> ScheduleWork(This,priorityLevel) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorSvcOptimizer_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorSvcOptimizer2_INTERFACE_DEFINED__
+#define __ICorSvcOptimizer2_INTERFACE_DEFINED__
+
+/* interface ICorSvcOptimizer2 */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_ICorSvcOptimizer2;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("ee3b09c2-0110-4b6e-a73f-a3d6562f98ab")
+ ICorSvcOptimizer2 : public ICorSvcOptimizer
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE CreatePdb(
+ /* [in] */ BSTR nativeImagePath,
+ /* [in] */ BSTR pdbPath) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorSvcOptimizer2Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorSvcOptimizer2 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorSvcOptimizer2 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorSvcOptimizer2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Update )(
+ ICorSvcOptimizer2 * This,
+ /* [in] */ BSTR path,
+ /* [in] */ UpdateFlags updateFlags,
+ /* [in] */ GeneralFlags generalFlags);
+
+ HRESULT ( STDMETHODCALLTYPE *Display )(
+ ICorSvcOptimizer2 * This,
+ /* [in] */ BSTR path,
+ /* [in] */ GeneralFlags generalFlags);
+
+ HRESULT ( STDMETHODCALLTYPE *ScheduleWork )(
+ ICorSvcOptimizer2 * This,
+ /* [in] */ PriorityLevel priorityLevel);
+
+ HRESULT ( STDMETHODCALLTYPE *CreatePdb )(
+ ICorSvcOptimizer2 * This,
+ /* [in] */ BSTR nativeImagePath,
+ /* [in] */ BSTR pdbPath);
+
+ END_INTERFACE
+ } ICorSvcOptimizer2Vtbl;
+
+ interface ICorSvcOptimizer2
+ {
+ CONST_VTBL struct ICorSvcOptimizer2Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorSvcOptimizer2_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorSvcOptimizer2_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorSvcOptimizer2_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorSvcOptimizer2_Update(This,path,updateFlags,generalFlags) \
+ ( (This)->lpVtbl -> Update(This,path,updateFlags,generalFlags) )
+
+#define ICorSvcOptimizer2_Display(This,path,generalFlags) \
+ ( (This)->lpVtbl -> Display(This,path,generalFlags) )
+
+#define ICorSvcOptimizer2_ScheduleWork(This,priorityLevel) \
+ ( (This)->lpVtbl -> ScheduleWork(This,priorityLevel) )
+
+
+#define ICorSvcOptimizer2_CreatePdb(This,nativeImagePath,pdbPath) \
+ ( (This)->lpVtbl -> CreatePdb(This,nativeImagePath,pdbPath) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorSvcOptimizer2_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorSvcOptimizer3_INTERFACE_DEFINED__
+#define __ICorSvcOptimizer3_INTERFACE_DEFINED__
+
+/* interface ICorSvcOptimizer3 */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_ICorSvcOptimizer3;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("6EED164F-61EE-4a07-ABE8-670F92B4B7A9")
+ ICorSvcOptimizer3 : public ICorSvcOptimizer2
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE CreatePdb2(
+ /* [in] */ BSTR nativeImagePath,
+ /* [in] */ BSTR pdbPath,
+ /* [in] */ BOOL pdbLines,
+ /* [in] */ BSTR managedPdbSearchPath) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorSvcOptimizer3Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorSvcOptimizer3 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorSvcOptimizer3 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorSvcOptimizer3 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Update )(
+ ICorSvcOptimizer3 * This,
+ /* [in] */ BSTR path,
+ /* [in] */ UpdateFlags updateFlags,
+ /* [in] */ GeneralFlags generalFlags);
+
+ HRESULT ( STDMETHODCALLTYPE *Display )(
+ ICorSvcOptimizer3 * This,
+ /* [in] */ BSTR path,
+ /* [in] */ GeneralFlags generalFlags);
+
+ HRESULT ( STDMETHODCALLTYPE *ScheduleWork )(
+ ICorSvcOptimizer3 * This,
+ /* [in] */ PriorityLevel priorityLevel);
+
+ HRESULT ( STDMETHODCALLTYPE *CreatePdb )(
+ ICorSvcOptimizer3 * This,
+ /* [in] */ BSTR nativeImagePath,
+ /* [in] */ BSTR pdbPath);
+
+ HRESULT ( STDMETHODCALLTYPE *CreatePdb2 )(
+ ICorSvcOptimizer3 * This,
+ /* [in] */ BSTR nativeImagePath,
+ /* [in] */ BSTR pdbPath,
+ /* [in] */ BOOL pdbLines,
+ /* [in] */ BSTR managedPdbSearchPath);
+
+ END_INTERFACE
+ } ICorSvcOptimizer3Vtbl;
+
+ interface ICorSvcOptimizer3
+ {
+ CONST_VTBL struct ICorSvcOptimizer3Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorSvcOptimizer3_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorSvcOptimizer3_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorSvcOptimizer3_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorSvcOptimizer3_Update(This,path,updateFlags,generalFlags) \
+ ( (This)->lpVtbl -> Update(This,path,updateFlags,generalFlags) )
+
+#define ICorSvcOptimizer3_Display(This,path,generalFlags) \
+ ( (This)->lpVtbl -> Display(This,path,generalFlags) )
+
+#define ICorSvcOptimizer3_ScheduleWork(This,priorityLevel) \
+ ( (This)->lpVtbl -> ScheduleWork(This,priorityLevel) )
+
+
+#define ICorSvcOptimizer3_CreatePdb(This,nativeImagePath,pdbPath) \
+ ( (This)->lpVtbl -> CreatePdb(This,nativeImagePath,pdbPath) )
+
+
+#define ICorSvcOptimizer3_CreatePdb2(This,nativeImagePath,pdbPath,pdbLines,managedPdbSearchPath) \
+ ( (This)->lpVtbl -> CreatePdb2(This,nativeImagePath,pdbPath,pdbLines,managedPdbSearchPath) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorSvcOptimizer3_INTERFACE_DEFINED__ */
+
+
+/* interface __MIDL_itf_mscorsvc_0000_0009 */
+/* [local] */
+
+typedef /* [public][public] */
+enum __MIDL___MIDL_itf_mscorsvc_0000_0009_0001
+ {
+ NewWorkAvailable = 0,
+ ClientWorkStart = 0x1,
+ ClientWorkDone = 0x2,
+ UpdatePostReboot = 0x3,
+ NewWorkAvailableWithDelay = 0x4
+ } ServiceNotification;
+
+
+
+extern RPC_IF_HANDLE __MIDL_itf_mscorsvc_0000_0009_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_mscorsvc_0000_0009_v0_0_s_ifspec;
+
+#ifndef __ICorSvcManager_INTERFACE_DEFINED__
+#define __ICorSvcManager_INTERFACE_DEFINED__
+
+/* interface ICorSvcManager */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_ICorSvcManager;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("8f416a48-d663-4a7e-9732-fbca3fc46ea8")
+ ICorSvcManager : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE ScheduleWorkForSinglePriorityLevel(
+ /* [in] */ PriorityLevel priorityLevel,
+ /* [in] */ BSTR pInterruptEventName,
+ /* [out] */ BOOL *pWorkScheduled) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Optimize(
+ /* [in] */ DWORD dwWorkerPriorityClass,
+ /* [in] */ ICompileProgressNotification *pCompileProgressNotification,
+ /* [in] */ BSTR pInterruptEventName) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE NotifyService(
+ ServiceNotification notification) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE IsWorkAvailable(
+ /* [in] */ PriorityLevel priorityLevel,
+ /* [out] */ BOOL *pWorkAvailable) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Update(
+ /* [in] */ UpdateFlags updateFlags,
+ /* [in] */ BSTR pInterruptEventName) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetSvcLogger(
+ /* [in] */ ICorSvcLogger *pCorSvcLogger) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorSvcManagerVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorSvcManager * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorSvcManager * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorSvcManager * This);
+
+ HRESULT ( STDMETHODCALLTYPE *ScheduleWorkForSinglePriorityLevel )(
+ ICorSvcManager * This,
+ /* [in] */ PriorityLevel priorityLevel,
+ /* [in] */ BSTR pInterruptEventName,
+ /* [out] */ BOOL *pWorkScheduled);
+
+ HRESULT ( STDMETHODCALLTYPE *Optimize )(
+ ICorSvcManager * This,
+ /* [in] */ DWORD dwWorkerPriorityClass,
+ /* [in] */ ICompileProgressNotification *pCompileProgressNotification,
+ /* [in] */ BSTR pInterruptEventName);
+
+ HRESULT ( STDMETHODCALLTYPE *NotifyService )(
+ ICorSvcManager * This,
+ ServiceNotification notification);
+
+ HRESULT ( STDMETHODCALLTYPE *IsWorkAvailable )(
+ ICorSvcManager * This,
+ /* [in] */ PriorityLevel priorityLevel,
+ /* [out] */ BOOL *pWorkAvailable);
+
+ HRESULT ( STDMETHODCALLTYPE *Update )(
+ ICorSvcManager * This,
+ /* [in] */ UpdateFlags updateFlags,
+ /* [in] */ BSTR pInterruptEventName);
+
+ HRESULT ( STDMETHODCALLTYPE *SetSvcLogger )(
+ ICorSvcManager * This,
+ /* [in] */ ICorSvcLogger *pCorSvcLogger);
+
+ END_INTERFACE
+ } ICorSvcManagerVtbl;
+
+ interface ICorSvcManager
+ {
+ CONST_VTBL struct ICorSvcManagerVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorSvcManager_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorSvcManager_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorSvcManager_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorSvcManager_ScheduleWorkForSinglePriorityLevel(This,priorityLevel,pInterruptEventName,pWorkScheduled) \
+ ( (This)->lpVtbl -> ScheduleWorkForSinglePriorityLevel(This,priorityLevel,pInterruptEventName,pWorkScheduled) )
+
+#define ICorSvcManager_Optimize(This,dwWorkerPriorityClass,pCompileProgressNotification,pInterruptEventName) \
+ ( (This)->lpVtbl -> Optimize(This,dwWorkerPriorityClass,pCompileProgressNotification,pInterruptEventName) )
+
+#define ICorSvcManager_NotifyService(This,notification) \
+ ( (This)->lpVtbl -> NotifyService(This,notification) )
+
+#define ICorSvcManager_IsWorkAvailable(This,priorityLevel,pWorkAvailable) \
+ ( (This)->lpVtbl -> IsWorkAvailable(This,priorityLevel,pWorkAvailable) )
+
+#define ICorSvcManager_Update(This,updateFlags,pInterruptEventName) \
+ ( (This)->lpVtbl -> Update(This,updateFlags,pInterruptEventName) )
+
+#define ICorSvcManager_SetSvcLogger(This,pCorSvcLogger) \
+ ( (This)->lpVtbl -> SetSvcLogger(This,pCorSvcLogger) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorSvcManager_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorSvcManager2_INTERFACE_DEFINED__
+#define __ICorSvcManager2_INTERFACE_DEFINED__
+
+/* interface ICorSvcManager2 */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_ICorSvcManager2;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("29626056-8031-441b-affa-7a82480058b3")
+ ICorSvcManager2 : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE SetRuntimeVersion(
+ BSTR version) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetPackageMoniker(
+ BSTR moniker) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetLocalAppData(
+ BSTR directory) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorSvcManager2Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorSvcManager2 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorSvcManager2 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorSvcManager2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *SetRuntimeVersion )(
+ ICorSvcManager2 * This,
+ BSTR version);
+
+ HRESULT ( STDMETHODCALLTYPE *SetPackageMoniker )(
+ ICorSvcManager2 * This,
+ BSTR moniker);
+
+ HRESULT ( STDMETHODCALLTYPE *SetLocalAppData )(
+ ICorSvcManager2 * This,
+ BSTR directory);
+
+ END_INTERFACE
+ } ICorSvcManager2Vtbl;
+
+ interface ICorSvcManager2
+ {
+ CONST_VTBL struct ICorSvcManager2Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorSvcManager2_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorSvcManager2_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorSvcManager2_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorSvcManager2_SetRuntimeVersion(This,version) \
+ ( (This)->lpVtbl -> SetRuntimeVersion(This,version) )
+
+#define ICorSvcManager2_SetPackageMoniker(This,moniker) \
+ ( (This)->lpVtbl -> SetPackageMoniker(This,moniker) )
+
+#define ICorSvcManager2_SetLocalAppData(This,directory) \
+ ( (This)->lpVtbl -> SetLocalAppData(This,directory) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorSvcManager2_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorSvcSetLegacyServiceBehavior_INTERFACE_DEFINED__
+#define __ICorSvcSetLegacyServiceBehavior_INTERFACE_DEFINED__
+
+/* interface ICorSvcSetLegacyServiceBehavior */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_ICorSvcSetLegacyServiceBehavior;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("35e5d609-ec3d-4fc2-9ba2-5f99e42ff42f")
+ ICorSvcSetLegacyServiceBehavior : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE SetLegacyServiceBehavior( void) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorSvcSetLegacyServiceBehaviorVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorSvcSetLegacyServiceBehavior * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorSvcSetLegacyServiceBehavior * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorSvcSetLegacyServiceBehavior * This);
+
+ HRESULT ( STDMETHODCALLTYPE *SetLegacyServiceBehavior )(
+ ICorSvcSetLegacyServiceBehavior * This);
+
+ END_INTERFACE
+ } ICorSvcSetLegacyServiceBehaviorVtbl;
+
+ interface ICorSvcSetLegacyServiceBehavior
+ {
+ CONST_VTBL struct ICorSvcSetLegacyServiceBehaviorVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorSvcSetLegacyServiceBehavior_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorSvcSetLegacyServiceBehavior_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorSvcSetLegacyServiceBehavior_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorSvcSetLegacyServiceBehavior_SetLegacyServiceBehavior(This) \
+ ( (This)->lpVtbl -> SetLegacyServiceBehavior(This) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorSvcSetLegacyServiceBehavior_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorSvcSetTaskBootTriggerState_INTERFACE_DEFINED__
+#define __ICorSvcSetTaskBootTriggerState_INTERFACE_DEFINED__
+
+/* interface ICorSvcSetTaskBootTriggerState */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_ICorSvcSetTaskBootTriggerState;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("115466A4-7005-4CA3-971F-01F0A2C8EF09")
+ ICorSvcSetTaskBootTriggerState : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE SetTaskBootTriggerState(
+ BOOL bEnabled) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorSvcSetTaskBootTriggerStateVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorSvcSetTaskBootTriggerState * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorSvcSetTaskBootTriggerState * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorSvcSetTaskBootTriggerState * This);
+
+ HRESULT ( STDMETHODCALLTYPE *SetTaskBootTriggerState )(
+ ICorSvcSetTaskBootTriggerState * This,
+ BOOL bEnabled);
+
+ END_INTERFACE
+ } ICorSvcSetTaskBootTriggerStateVtbl;
+
+ interface ICorSvcSetTaskBootTriggerState
+ {
+ CONST_VTBL struct ICorSvcSetTaskBootTriggerStateVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorSvcSetTaskBootTriggerState_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorSvcSetTaskBootTriggerState_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorSvcSetTaskBootTriggerState_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorSvcSetTaskBootTriggerState_SetTaskBootTriggerState(This,bEnabled) \
+ ( (This)->lpVtbl -> SetTaskBootTriggerState(This,bEnabled) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorSvcSetTaskBootTriggerState_INTERFACE_DEFINED__ */
+
+
+#ifndef __ICorSvcSetTaskDelayStartTriggerState_INTERFACE_DEFINED__
+#define __ICorSvcSetTaskDelayStartTriggerState_INTERFACE_DEFINED__
+
+/* interface ICorSvcSetTaskDelayStartTriggerState */
+/* [unique][uuid][object] */
+
+
+EXTERN_C const IID IID_ICorSvcSetTaskDelayStartTriggerState;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("261DD1E3-F07E-4B8D-B54E-F26889413626")
+ ICorSvcSetTaskDelayStartTriggerState : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE SetTaskDelayStartTriggerState(
+ BOOL bEnabled) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorSvcSetTaskDelayStartTriggerStateVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorSvcSetTaskDelayStartTriggerState * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorSvcSetTaskDelayStartTriggerState * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorSvcSetTaskDelayStartTriggerState * This);
+
+ HRESULT ( STDMETHODCALLTYPE *SetTaskDelayStartTriggerState )(
+ ICorSvcSetTaskDelayStartTriggerState * This,
+ BOOL bEnabled);
+
+ END_INTERFACE
+ } ICorSvcSetTaskDelayStartTriggerStateVtbl;
+
+ interface ICorSvcSetTaskDelayStartTriggerState
+ {
+ CONST_VTBL struct ICorSvcSetTaskDelayStartTriggerStateVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorSvcSetTaskDelayStartTriggerState_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorSvcSetTaskDelayStartTriggerState_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorSvcSetTaskDelayStartTriggerState_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorSvcSetTaskDelayStartTriggerState_SetTaskDelayStartTriggerState(This,bEnabled) \
+ ( (This)->lpVtbl -> SetTaskDelayStartTriggerState(This,bEnabled) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorSvcSetTaskDelayStartTriggerState_INTERFACE_DEFINED__ */
+
+
+/* Additional Prototypes for ALL interfaces */
+
+unsigned long __RPC_USER BSTR_UserSize( unsigned long *, unsigned long , BSTR * );
+unsigned char * __RPC_USER BSTR_UserMarshal( unsigned long *, unsigned char *, BSTR * );
+unsigned char * __RPC_USER BSTR_UserUnmarshal(unsigned long *, unsigned char *, BSTR * );
+void __RPC_USER BSTR_UserFree( unsigned long *, BSTR * );
+
+/* end of Additional Prototypes */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+
diff --git a/src/pal/prebuilt/inc/ndpversion.h b/src/pal/prebuilt/inc/ndpversion.h
new file mode 100644
index 0000000000..ba6d018266
--- /dev/null
+++ b/src/pal/prebuilt/inc/ndpversion.h
@@ -0,0 +1,4 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+#include <fxver.h>
diff --git a/src/pal/prebuilt/inc/ndpversion_generated.h b/src/pal/prebuilt/inc/ndpversion_generated.h
new file mode 100644
index 0000000000..563e316971
--- /dev/null
+++ b/src/pal/prebuilt/inc/ndpversion_generated.h
@@ -0,0 +1,15 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#if 0
+/**** Generated Based on d:\ProjectK\src\InternalApis\Version\buildnumber.settings.targets
+One can't put comments in this file (without the #if)
+because this header is preprocessed in non-C++ context (xml, perl, etc.). *****/
+#endif
+#define NDPVersionNumberMajor 4
+#define NDPVersionNumberMinor 0
+#define NDPVersionNumberMajor_A "4"
+#define NDPVersionNumberMinor_A "00"
+#define NDPVersionNumbers_A "4.00"
+#include "buildnumber.h"
diff --git a/src/pal/prebuilt/inc/product_version.h b/src/pal/prebuilt/inc/product_version.h
new file mode 100644
index 0000000000..5b4a67076d
--- /dev/null
+++ b/src/pal/prebuilt/inc/product_version.h
@@ -0,0 +1,113 @@
+
+#if 0
+ Version strings for product keys... no comments can be allowed in this
+ file due to some usage of this in the build process.
+ // Licensed to the .NET Foundation under one or more agreements.
+ // The .NET Foundation licenses this file to you under the MIT license.
+ // See the LICENSE file in the project root for more information.
+#endif
+
+#include <version.h>
+#ifdef USE_CLR20_VERSION
+#include <asm_version20.h>
+#else
+#include <asm_version.h>
+#endif
+
+#ifdef VER_MAJORVERSION
+#undef VER_MAJORVERSION
+#endif
+
+#ifdef VER_MINORVERSION
+#undef VER_MINORVERSION
+#endif
+
+#ifdef VER_PRODUCTBUILD
+#undef VER_PRODUCTBUILD
+#endif
+
+#ifdef VER_PRODUCTBUILD_QFE
+#undef VER_PRODUCTBUILD_QFE
+#endif
+
+#ifdef VER_FILEVERSIONMINOR
+#undef VER_FILEVERSIONMINOR
+#endif
+
+#ifdef VER_FILEVERSIONBUILD
+#undef VER_FILEVERSIONBUILD
+#endif
+
+#ifdef VER_FILEVERSIONREVISION
+#undef VER_FILEVERSIONREVISION
+#endif
+
+#define VER_MAJORVERSION rmj
+#define VER_MINORVERSION rmm
+#define VER_PRODUCTBUILD rup
+#define VER_PRODUCTBUILD_QFE rpt
+
+#define VER_FILEVERSIONMINOR fvn
+#define VER_FILEVERSIONBUILD fvb
+#define VER_FILEVERSIONREVISION fvr
+
+#define VER_ASSEMBLYMAJORVERSION asm_rmj
+#define VER_ASSEMBLYMINORVERSION asm_rmm
+#define VER_ASSEMBLYBUILD asm_rup
+#define VER_ASSEMBLYBUILD_QFE asm_rpt
+
+#define QUOTE_MACRO_HELPER(x) #x
+#define QUOTE_MACRO(x) QUOTE_MACRO_HELPER(x)
+
+#ifndef QUOTE_MACRO_L
+#define QUOTE_MACRO_L_HELPER(x) L###x
+#define QUOTE_MACRO_L(x) QUOTE_MACRO_L_HELPER(x)
+#endif
+
+#define CONCAT_MACRO_HELPER(x, y) x ## y
+#define CONCAT_MACRO(x, y) CONCAT_MACRO_HELPER(x, y)
+
+#define VER_PRODUCTVERSION VER_MAJORVERSION,VER_MINORVERSION,VER_PRODUCTBUILD,VER_PRODUCTBUILD_QFE
+#define VER_DOTFILEVERSION VER_MAJORVERSION,VER_FILEVERSIONMINOR,VER_FILEVERSIONBUILD,VER_FILEVERSIONREVISION
+#define VER_MANAGED_DOTFILEVERSION VER_MAJORVERSION.VER_FILEVERSIONMINOR.VER_FILEVERSIONBUILD.VER_FILEVERSIONREVISION
+
+#define VER_DOTPRODUCTVERSION VER_MAJORVERSION.VER_MINORVERSION.VER_PRODUCTBUILD.VER_PRODUCTBUILD_QFE
+#define VER_DOTPRODUCTMAJORMINOR VER_MAJORVERSION.VER_MINORVERSION
+#define VER_DOTPRODUCTVERSIONNOQFE VER_MAJORVERSION.VER_MINORVERSION.VER_PRODUCTBUILD
+#define VER_DOTPRODUCTVERSIONZEROQFE VER_MAJORVERSION.VER_MINORVERSION.VER_PRODUCTBUILD.0
+#define VER_DOTASSEMBLYVERSION VER_ASSEMBLYMAJORVERSION.VER_ASSEMBLYMINORVERSION.VER_ASSEMBLYBUILD.VER_ASSEMBLYBUILD_QFE
+#define VER_DOTASSEMBLYVERSION3PART VER_ASSEMBLYMAJORVERSION.VER_ASSEMBLYMINORVERSION.VER_ASSEMBLYBUILD
+
+#define VER_UNDERSCORE_PRODUCTVERSION_STR3 CONCAT_MACRO(_, VER_PRODUCTBUILD)
+#define VER_UNDERSCORE_PRODUCTVERSION_STR2 CONCAT_MACRO(VER_MINORVERSION, VER_UNDERSCORE_PRODUCTVERSION_STR3)
+#define VER_UNDERSCORE_PRODUCTVERSION_STR1 CONCAT_MACRO(_, VER_UNDERSCORE_PRODUCTVERSION_STR2)
+#define VER_UNDERSCORE_PRODUCTVERSION CONCAT_MACRO(VER_MAJORVERSION, VER_UNDERSCORE_PRODUCTVERSION_STR1)
+
+#define VER_UNDERSCORE_PRODUCTVERSION_STR QUOTE_MACRO(VER_UNDERSCORE_PRODUCTVERSION)
+#define VER_UNDERSCORE_PRODUCTVERSION_STR_L QUOTE_MACRO_L(VER_UNDERSCORE_PRODUCTVERSION)
+
+#define FX_FILEVERSION_STR QUOTE_MACRO(VER_MANAGED_DOTFILEVERSION)
+#define VER_PRODUCTVERSION_STR QUOTE_MACRO(VER_DOTPRODUCTVERSION)
+#define VER_PRODUCTVERSION_STR_L QUOTE_MACRO_L(VER_DOTPRODUCTVERSION)
+
+#define VER_PRODUCTMAJORMINOR_STR QUOTE_MACRO(VER_DOTPRODUCTMAJORMINOR)
+#define VER_PRODUCTMAJORMINOR_STR_L QUOTE_MACRO_L(VER_DOTPRODUCTMAJORMINOR)
+
+#define VER_PRODUCTVERSION_NO_QFE_STR QUOTE_MACRO(VER_DOTPRODUCTVERSIONNOQFE)
+#define VER_PRODUCTVERSION_NO_QFE_STR_L QUOTE_MACRO_L(VER_DOTPRODUCTVERSIONNOQFE)
+
+#define VER_PRODUCTVERSION_ZERO_QFE_STR QUOTE_MACRO(VER_DOTPRODUCTVERSIONZEROQFE)
+#define VER_PRODUCTVERSION_ZERO_QFE_STR_L QUOTE_MACRO_L(VER_DOTPRODUCTVERSIONZEROQFE)
+
+#define VER_PRODUCTVERSION_NO_QFE_STR QUOTE_MACRO(VER_DOTPRODUCTVERSIONNOQFE)
+#define VER_PRODUCTVERSION_NO_QFE_STR_L QUOTE_MACRO_L(VER_DOTPRODUCTVERSIONNOQFE)
+
+#define VER_ASSEMBLYVERSION_STR QUOTE_MACRO(VER_DOTASSEMBLYVERSION)
+#define VER_ASSEMBLYVERSION_STR_L QUOTE_MACRO_L(VER_DOTASSEMBLYVERSION)
+
+#define VER_ASSEMBLYVERSION3PART_STR QUOTE_MACRO(VER_DOTASSEMBLYVERSION3PART)
+#define VER_ASSEMBLYVERSION3PART_STR_L QUOTE_MACRO_L(VER_DOTASSEMBLYVERSION3PART)
+
+#define VER_ECMA_PUBLICKEY b77a5c561934e089
+#define ECMA_PUBLICKEY_STR QUOTE_MACRO(VER_ECMA_PUBLICKEY)
+#define ECMA_PUBLICKEY_STR_L QUOTE_MACRO_L(VER_ECMA_PUBLICKEY)
diff --git a/src/pal/prebuilt/inc/readme.txt b/src/pal/prebuilt/inc/readme.txt
new file mode 100644
index 0000000000..3b453d2d9d
--- /dev/null
+++ b/src/pal/prebuilt/inc/readme.txt
@@ -0,0 +1 @@
+This folder contains include files generated from idl sources. Since we cannot run MIDL on non-Windows platforms, we have to have them checked in.
diff --git a/src/pal/prebuilt/inc/sospriv.h b/src/pal/prebuilt/inc/sospriv.h
new file mode 100644
index 0000000000..ae881659e5
--- /dev/null
+++ b/src/pal/prebuilt/inc/sospriv.h
@@ -0,0 +1,2199 @@
+
+
+/* this ALWAYS GENERATED file contains the definitions for the interfaces */
+
+
+ /* File created by MIDL compiler version 8.00.0613 */
+/* at Mon Jan 18 19:14:07 2038
+ */
+/* Compiler settings for C:/ssd/coreclr/src/inc/sospriv.idl:
+ Oicf, W1, Zp8, env=Win32 (32b run), target_arch=X86 8.00.0613
+ protocol : dce , ms_ext, c_ext, robust
+ error checks: allocation ref bounds_check enum stub_data
+ VC __declspec() decoration level:
+ __declspec(uuid()), __declspec(selectany), __declspec(novtable)
+ DECLSPEC_UUID(), MIDL_INTERFACE()
+*/
+/* @@MIDL_FILE_HEADING( ) */
+
+#pragma warning( disable: 4049 ) /* more than 64k source lines */
+
+
+/* verify that the <rpcndr.h> version is high enough to compile this file*/
+#ifndef __REQUIRED_RPCNDR_H_VERSION__
+#define __REQUIRED_RPCNDR_H_VERSION__ 475
+#endif
+
+#include "rpc.h"
+#include "rpcndr.h"
+
+#ifndef __RPCNDR_H_VERSION__
+#error this stub requires an updated version of <rpcndr.h>
+#endif /* __RPCNDR_H_VERSION__ */
+
+#ifndef COM_NO_WINDOWS_H
+#include "windows.h"
+#include "ole2.h"
+#endif /*COM_NO_WINDOWS_H*/
+
+#ifndef __sospriv_h__
+#define __sospriv_h__
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+/* Forward Declarations */
+
+#ifndef __ISOSEnum_FWD_DEFINED__
+#define __ISOSEnum_FWD_DEFINED__
+typedef interface ISOSEnum ISOSEnum;
+
+#endif /* __ISOSEnum_FWD_DEFINED__ */
+
+
+#ifndef __ISOSHandleEnum_FWD_DEFINED__
+#define __ISOSHandleEnum_FWD_DEFINED__
+typedef interface ISOSHandleEnum ISOSHandleEnum;
+
+#endif /* __ISOSHandleEnum_FWD_DEFINED__ */
+
+
+#ifndef __ISOSStackRefErrorEnum_FWD_DEFINED__
+#define __ISOSStackRefErrorEnum_FWD_DEFINED__
+typedef interface ISOSStackRefErrorEnum ISOSStackRefErrorEnum;
+
+#endif /* __ISOSStackRefErrorEnum_FWD_DEFINED__ */
+
+
+#ifndef __ISOSStackRefEnum_FWD_DEFINED__
+#define __ISOSStackRefEnum_FWD_DEFINED__
+typedef interface ISOSStackRefEnum ISOSStackRefEnum;
+
+#endif /* __ISOSStackRefEnum_FWD_DEFINED__ */
+
+
+#ifndef __ISOSDacInterface_FWD_DEFINED__
+#define __ISOSDacInterface_FWD_DEFINED__
+typedef interface ISOSDacInterface ISOSDacInterface;
+
+#endif /* __ISOSDacInterface_FWD_DEFINED__ */
+
+
+#ifndef __ISOSDacInterface2_FWD_DEFINED__
+#define __ISOSDacInterface2_FWD_DEFINED__
+typedef interface ISOSDacInterface2 ISOSDacInterface2;
+
+#endif /* __ISOSDacInterface2_FWD_DEFINED__ */
+
+
+#ifndef __ISOSDacInterface3_FWD_DEFINED__
+#define __ISOSDacInterface3_FWD_DEFINED__
+typedef interface ISOSDacInterface3 ISOSDacInterface3;
+
+#endif /* __ISOSDacInterface3_FWD_DEFINED__ */
+
+
+#ifndef __ISOSDacInterface4_FWD_DEFINED__
+#define __ISOSDacInterface4_FWD_DEFINED__
+typedef interface ISOSDacInterface4 ISOSDacInterface4;
+
+#endif /* __ISOSDacInterface4_FWD_DEFINED__ */
+
+
+/* header files for imported files */
+#include "unknwn.h"
+#include "xclrdata.h"
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+
+/* interface __MIDL_itf_sospriv_0000_0000 */
+/* [local] */
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#if 0
+typedef ULONG64 CLRDATA_ADDRESS;
+
+typedef int CONTEXT;
+
+typedef int T_CONTEXT;
+
+typedef int mdToken;
+
+typedef unsigned int size_t;
+
+typedef int ModuleMapType;
+
+typedef int VCSHeapType;
+
+#endif
+enum ModuleMapType { TYPEDEFTOMETHODTABLE, TYPEREFTOMETHODTABLE };
+enum VCSHeapType {IndcellHeap, LookupHeap, ResolveHeap, DispatchHeap, CacheEntryHeap};
+typedef void ( *MODULEMAPTRAVERSE )(
+ UINT index,
+ CLRDATA_ADDRESS methodTable,
+ LPVOID token);
+
+typedef void ( *VISITHEAP )(
+ CLRDATA_ADDRESS blockData,
+ size_t blockSize,
+ BOOL blockIsCurrentBlock);
+
+typedef BOOL ( *VISITRCWFORCLEANUP )(
+ CLRDATA_ADDRESS RCW,
+ CLRDATA_ADDRESS Context,
+ CLRDATA_ADDRESS Thread,
+ BOOL bIsFreeThreaded,
+ LPVOID token);
+
+typedef BOOL ( *DUMPEHINFO )(
+ UINT clauseIndex,
+ UINT totalClauses,
+ struct DACEHInfo *pEHInfo,
+ LPVOID token);
+
+#ifndef _SOS_HandleData
+#define _SOS_HandleData
+typedef struct _SOSHandleData
+ {
+ CLRDATA_ADDRESS AppDomain;
+ CLRDATA_ADDRESS Handle;
+ CLRDATA_ADDRESS Secondary;
+ unsigned int Type;
+ BOOL StrongReference;
+ unsigned int RefCount;
+ unsigned int JupiterRefCount;
+ BOOL IsPegged;
+ } SOSHandleData;
+
+#endif //HandleData
+
+
+extern RPC_IF_HANDLE __MIDL_itf_sospriv_0000_0000_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_sospriv_0000_0000_v0_0_s_ifspec;
+
+#ifndef __ISOSEnum_INTERFACE_DEFINED__
+#define __ISOSEnum_INTERFACE_DEFINED__
+
+/* interface ISOSEnum */
+/* [uuid][local][object] */
+
+
+EXTERN_C const IID IID_ISOSEnum;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("286CA186-E763-4F61-9760-487D43AE4341")
+ ISOSEnum : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE Skip(
+ /* [in] */ unsigned int count) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Reset( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetCount(
+ /* [out] */ unsigned int *pCount) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ISOSEnumVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ISOSEnum * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ISOSEnum * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ISOSEnum * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Skip )(
+ ISOSEnum * This,
+ /* [in] */ unsigned int count);
+
+ HRESULT ( STDMETHODCALLTYPE *Reset )(
+ ISOSEnum * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCount )(
+ ISOSEnum * This,
+ /* [out] */ unsigned int *pCount);
+
+ END_INTERFACE
+ } ISOSEnumVtbl;
+
+ interface ISOSEnum
+ {
+ CONST_VTBL struct ISOSEnumVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ISOSEnum_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ISOSEnum_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ISOSEnum_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ISOSEnum_Skip(This,count) \
+ ( (This)->lpVtbl -> Skip(This,count) )
+
+#define ISOSEnum_Reset(This) \
+ ( (This)->lpVtbl -> Reset(This) )
+
+#define ISOSEnum_GetCount(This,pCount) \
+ ( (This)->lpVtbl -> GetCount(This,pCount) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ISOSEnum_INTERFACE_DEFINED__ */
+
+
+#ifndef __ISOSHandleEnum_INTERFACE_DEFINED__
+#define __ISOSHandleEnum_INTERFACE_DEFINED__
+
+/* interface ISOSHandleEnum */
+/* [uuid][local][object] */
+
+
+EXTERN_C const IID IID_ISOSHandleEnum;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("3E269830-4A2B-4301-8EE2-D6805B29B2FA")
+ ISOSHandleEnum : public ISOSEnum
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE Next(
+ /* [in] */ unsigned int count,
+ /* [length_is][size_is][out] */ SOSHandleData handles[ ],
+ /* [out] */ unsigned int *pNeeded) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ISOSHandleEnumVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ISOSHandleEnum * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ISOSHandleEnum * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ISOSHandleEnum * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Skip )(
+ ISOSHandleEnum * This,
+ /* [in] */ unsigned int count);
+
+ HRESULT ( STDMETHODCALLTYPE *Reset )(
+ ISOSHandleEnum * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCount )(
+ ISOSHandleEnum * This,
+ /* [out] */ unsigned int *pCount);
+
+ HRESULT ( STDMETHODCALLTYPE *Next )(
+ ISOSHandleEnum * This,
+ /* [in] */ unsigned int count,
+ /* [length_is][size_is][out] */ SOSHandleData handles[ ],
+ /* [out] */ unsigned int *pNeeded);
+
+ END_INTERFACE
+ } ISOSHandleEnumVtbl;
+
+ interface ISOSHandleEnum
+ {
+ CONST_VTBL struct ISOSHandleEnumVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ISOSHandleEnum_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ISOSHandleEnum_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ISOSHandleEnum_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ISOSHandleEnum_Skip(This,count) \
+ ( (This)->lpVtbl -> Skip(This,count) )
+
+#define ISOSHandleEnum_Reset(This) \
+ ( (This)->lpVtbl -> Reset(This) )
+
+#define ISOSHandleEnum_GetCount(This,pCount) \
+ ( (This)->lpVtbl -> GetCount(This,pCount) )
+
+
+#define ISOSHandleEnum_Next(This,count,handles,pNeeded) \
+ ( (This)->lpVtbl -> Next(This,count,handles,pNeeded) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ISOSHandleEnum_INTERFACE_DEFINED__ */
+
+
+/* interface __MIDL_itf_sospriv_0000_0002 */
+/* [local] */
+
+#ifndef _SOS_StackReference_
+#define _SOS_StackReference_
+typedef
+enum SOSStackSourceType
+ {
+ SOS_StackSourceIP = 0,
+ SOS_StackSourceFrame = ( SOS_StackSourceIP + 1 )
+ } SOSStackSourceType;
+
+typedef
+enum SOSRefFlags
+ {
+ SOSRefInterior = 1,
+ SOSRefPinned = 2
+ } SOSRefFlags;
+
+typedef struct _SOS_StackRefData
+ {
+ BOOL HasRegisterInformation;
+ int Register;
+ int Offset;
+ CLRDATA_ADDRESS Address;
+ CLRDATA_ADDRESS Object;
+ unsigned int Flags;
+ SOSStackSourceType SourceType;
+ CLRDATA_ADDRESS Source;
+ CLRDATA_ADDRESS StackPointer;
+ } SOSStackRefData;
+
+typedef struct _SOS_StackRefError
+ {
+ SOSStackSourceType SourceType;
+ CLRDATA_ADDRESS Source;
+ CLRDATA_ADDRESS StackPointer;
+ } SOSStackRefError;
+
+#endif // _SOS_StackReference_
+
+
+extern RPC_IF_HANDLE __MIDL_itf_sospriv_0000_0002_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_sospriv_0000_0002_v0_0_s_ifspec;
+
+#ifndef __ISOSStackRefErrorEnum_INTERFACE_DEFINED__
+#define __ISOSStackRefErrorEnum_INTERFACE_DEFINED__
+
+/* interface ISOSStackRefErrorEnum */
+/* [uuid][local][object] */
+
+
+EXTERN_C const IID IID_ISOSStackRefErrorEnum;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("774F4E1B-FB7B-491B-976D-A8130FE355E9")
+ ISOSStackRefErrorEnum : public ISOSEnum
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE Next(
+ /* [in] */ unsigned int count,
+ /* [length_is][size_is][out] */ SOSStackRefError ref[ ],
+ /* [out] */ unsigned int *pFetched) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ISOSStackRefErrorEnumVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ISOSStackRefErrorEnum * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ISOSStackRefErrorEnum * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ISOSStackRefErrorEnum * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Skip )(
+ ISOSStackRefErrorEnum * This,
+ /* [in] */ unsigned int count);
+
+ HRESULT ( STDMETHODCALLTYPE *Reset )(
+ ISOSStackRefErrorEnum * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCount )(
+ ISOSStackRefErrorEnum * This,
+ /* [out] */ unsigned int *pCount);
+
+ HRESULT ( STDMETHODCALLTYPE *Next )(
+ ISOSStackRefErrorEnum * This,
+ /* [in] */ unsigned int count,
+ /* [length_is][size_is][out] */ SOSStackRefError ref[ ],
+ /* [out] */ unsigned int *pFetched);
+
+ END_INTERFACE
+ } ISOSStackRefErrorEnumVtbl;
+
+ interface ISOSStackRefErrorEnum
+ {
+ CONST_VTBL struct ISOSStackRefErrorEnumVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ISOSStackRefErrorEnum_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ISOSStackRefErrorEnum_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ISOSStackRefErrorEnum_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ISOSStackRefErrorEnum_Skip(This,count) \
+ ( (This)->lpVtbl -> Skip(This,count) )
+
+#define ISOSStackRefErrorEnum_Reset(This) \
+ ( (This)->lpVtbl -> Reset(This) )
+
+#define ISOSStackRefErrorEnum_GetCount(This,pCount) \
+ ( (This)->lpVtbl -> GetCount(This,pCount) )
+
+
+#define ISOSStackRefErrorEnum_Next(This,count,ref,pFetched) \
+ ( (This)->lpVtbl -> Next(This,count,ref,pFetched) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ISOSStackRefErrorEnum_INTERFACE_DEFINED__ */
+
+
+#ifndef __ISOSStackRefEnum_INTERFACE_DEFINED__
+#define __ISOSStackRefEnum_INTERFACE_DEFINED__
+
+/* interface ISOSStackRefEnum */
+/* [uuid][local][object] */
+
+
+EXTERN_C const IID IID_ISOSStackRefEnum;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("8FA642BD-9F10-4799-9AA3-512AE78C77EE")
+ ISOSStackRefEnum : public ISOSEnum
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE Next(
+ /* [in] */ unsigned int count,
+ /* [length_is][size_is][out] */ SOSStackRefData ref[ ],
+ /* [out] */ unsigned int *pFetched) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnumerateErrors(
+ /* [out] */ ISOSStackRefErrorEnum **ppEnum) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ISOSStackRefEnumVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ISOSStackRefEnum * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ISOSStackRefEnum * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ISOSStackRefEnum * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Skip )(
+ ISOSStackRefEnum * This,
+ /* [in] */ unsigned int count);
+
+ HRESULT ( STDMETHODCALLTYPE *Reset )(
+ ISOSStackRefEnum * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCount )(
+ ISOSStackRefEnum * This,
+ /* [out] */ unsigned int *pCount);
+
+ HRESULT ( STDMETHODCALLTYPE *Next )(
+ ISOSStackRefEnum * This,
+ /* [in] */ unsigned int count,
+ /* [length_is][size_is][out] */ SOSStackRefData ref[ ],
+ /* [out] */ unsigned int *pFetched);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumerateErrors )(
+ ISOSStackRefEnum * This,
+ /* [out] */ ISOSStackRefErrorEnum **ppEnum);
+
+ END_INTERFACE
+ } ISOSStackRefEnumVtbl;
+
+ interface ISOSStackRefEnum
+ {
+ CONST_VTBL struct ISOSStackRefEnumVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ISOSStackRefEnum_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ISOSStackRefEnum_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ISOSStackRefEnum_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ISOSStackRefEnum_Skip(This,count) \
+ ( (This)->lpVtbl -> Skip(This,count) )
+
+#define ISOSStackRefEnum_Reset(This) \
+ ( (This)->lpVtbl -> Reset(This) )
+
+#define ISOSStackRefEnum_GetCount(This,pCount) \
+ ( (This)->lpVtbl -> GetCount(This,pCount) )
+
+
+#define ISOSStackRefEnum_Next(This,count,ref,pFetched) \
+ ( (This)->lpVtbl -> Next(This,count,ref,pFetched) )
+
+#define ISOSStackRefEnum_EnumerateErrors(This,ppEnum) \
+ ( (This)->lpVtbl -> EnumerateErrors(This,ppEnum) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ISOSStackRefEnum_INTERFACE_DEFINED__ */
+
+
+#ifndef __ISOSDacInterface_INTERFACE_DEFINED__
+#define __ISOSDacInterface_INTERFACE_DEFINED__
+
+/* interface ISOSDacInterface */
+/* [uuid][local][object] */
+
+
+EXTERN_C const IID IID_ISOSDacInterface;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("436f00f2-b42a-4b9f-870c-e73db66ae930")
+ ISOSDacInterface : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetThreadStoreData(
+ struct DacpThreadStoreData *data) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetAppDomainStoreData(
+ struct DacpAppDomainStoreData *data) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetAppDomainList(
+ unsigned int count,
+ CLRDATA_ADDRESS values[ ],
+ unsigned int *pNeeded) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetAppDomainData(
+ CLRDATA_ADDRESS addr,
+ struct DacpAppDomainData *data) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetAppDomainName(
+ CLRDATA_ADDRESS addr,
+ unsigned int count,
+ WCHAR *name,
+ unsigned int *pNeeded) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetDomainFromContext(
+ CLRDATA_ADDRESS context,
+ CLRDATA_ADDRESS *domain) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetAssemblyList(
+ CLRDATA_ADDRESS appDomain,
+ int count,
+ CLRDATA_ADDRESS values[ ],
+ int *pNeeded) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetAssemblyData(
+ CLRDATA_ADDRESS baseDomainPtr,
+ CLRDATA_ADDRESS assembly,
+ struct DacpAssemblyData *data) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetAssemblyName(
+ CLRDATA_ADDRESS assembly,
+ unsigned int count,
+ WCHAR *name,
+ unsigned int *pNeeded) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetModule(
+ CLRDATA_ADDRESS addr,
+ IXCLRDataModule **mod) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetModuleData(
+ CLRDATA_ADDRESS moduleAddr,
+ struct DacpModuleData *data) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE TraverseModuleMap(
+ ModuleMapType mmt,
+ CLRDATA_ADDRESS moduleAddr,
+ MODULEMAPTRAVERSE pCallback,
+ LPVOID token) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetAssemblyModuleList(
+ CLRDATA_ADDRESS assembly,
+ unsigned int count,
+ CLRDATA_ADDRESS modules[ ],
+ unsigned int *pNeeded) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetILForModule(
+ CLRDATA_ADDRESS moduleAddr,
+ DWORD rva,
+ CLRDATA_ADDRESS *il) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetThreadData(
+ CLRDATA_ADDRESS thread,
+ struct DacpThreadData *data) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetThreadFromThinlockID(
+ UINT thinLockId,
+ CLRDATA_ADDRESS *pThread) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetStackLimits(
+ CLRDATA_ADDRESS threadPtr,
+ CLRDATA_ADDRESS *lower,
+ CLRDATA_ADDRESS *upper,
+ CLRDATA_ADDRESS *fp) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetMethodDescData(
+ CLRDATA_ADDRESS methodDesc,
+ CLRDATA_ADDRESS ip,
+ struct DacpMethodDescData *data,
+ ULONG cRevertedRejitVersions,
+ struct DacpReJitData *rgRevertedRejitData,
+ ULONG *pcNeededRevertedRejitData) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetMethodDescPtrFromIP(
+ CLRDATA_ADDRESS ip,
+ CLRDATA_ADDRESS *ppMD) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetMethodDescName(
+ CLRDATA_ADDRESS methodDesc,
+ unsigned int count,
+ WCHAR *name,
+ unsigned int *pNeeded) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetMethodDescPtrFromFrame(
+ CLRDATA_ADDRESS frameAddr,
+ CLRDATA_ADDRESS *ppMD) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetMethodDescFromToken(
+ CLRDATA_ADDRESS moduleAddr,
+ mdToken token,
+ CLRDATA_ADDRESS *methodDesc) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetMethodDescTransparencyData(
+ CLRDATA_ADDRESS methodDesc,
+ struct DacpMethodDescTransparencyData *data) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetCodeHeaderData(
+ CLRDATA_ADDRESS ip,
+ struct DacpCodeHeaderData *data) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetJitManagerList(
+ unsigned int count,
+ struct DacpJitManagerInfo *managers,
+ unsigned int *pNeeded) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetJitHelperFunctionName(
+ CLRDATA_ADDRESS ip,
+ unsigned int count,
+ char *name,
+ unsigned int *pNeeded) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetJumpThunkTarget(
+ T_CONTEXT *ctx,
+ CLRDATA_ADDRESS *targetIP,
+ CLRDATA_ADDRESS *targetMD) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetThreadpoolData(
+ struct DacpThreadpoolData *data) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetWorkRequestData(
+ CLRDATA_ADDRESS addrWorkRequest,
+ struct DacpWorkRequestData *data) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetHillClimbingLogEntry(
+ CLRDATA_ADDRESS addr,
+ struct DacpHillClimbingLogEntry *data) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetObjectData(
+ CLRDATA_ADDRESS objAddr,
+ struct DacpObjectData *data) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetObjectStringData(
+ CLRDATA_ADDRESS obj,
+ unsigned int count,
+ WCHAR *stringData,
+ unsigned int *pNeeded) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetObjectClassName(
+ CLRDATA_ADDRESS obj,
+ unsigned int count,
+ WCHAR *className,
+ unsigned int *pNeeded) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetMethodTableName(
+ CLRDATA_ADDRESS mt,
+ unsigned int count,
+ WCHAR *mtName,
+ unsigned int *pNeeded) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetMethodTableData(
+ CLRDATA_ADDRESS mt,
+ struct DacpMethodTableData *data) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetMethodTableSlot(
+ CLRDATA_ADDRESS mt,
+ unsigned int slot,
+ CLRDATA_ADDRESS *value) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetMethodTableFieldData(
+ CLRDATA_ADDRESS mt,
+ struct DacpMethodTableFieldData *data) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetMethodTableTransparencyData(
+ CLRDATA_ADDRESS mt,
+ struct DacpMethodTableTransparencyData *data) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetMethodTableForEEClass(
+ CLRDATA_ADDRESS eeClass,
+ CLRDATA_ADDRESS *value) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetFieldDescData(
+ CLRDATA_ADDRESS fieldDesc,
+ struct DacpFieldDescData *data) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetFrameName(
+ CLRDATA_ADDRESS vtable,
+ unsigned int count,
+ WCHAR *frameName,
+ unsigned int *pNeeded) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetPEFileBase(
+ CLRDATA_ADDRESS addr,
+ CLRDATA_ADDRESS *base) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetPEFileName(
+ CLRDATA_ADDRESS addr,
+ unsigned int count,
+ WCHAR *fileName,
+ unsigned int *pNeeded) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetGCHeapData(
+ struct DacpGcHeapData *data) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetGCHeapList(
+ unsigned int count,
+ CLRDATA_ADDRESS heaps[ ],
+ unsigned int *pNeeded) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetGCHeapDetails(
+ CLRDATA_ADDRESS heap,
+ struct DacpGcHeapDetails *details) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetGCHeapStaticData(
+ struct DacpGcHeapDetails *data) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetHeapSegmentData(
+ CLRDATA_ADDRESS seg,
+ struct DacpHeapSegmentData *data) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetOOMData(
+ CLRDATA_ADDRESS oomAddr,
+ struct DacpOomData *data) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetOOMStaticData(
+ struct DacpOomData *data) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetHeapAnalyzeData(
+ CLRDATA_ADDRESS addr,
+ struct DacpGcHeapAnalyzeData *data) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetHeapAnalyzeStaticData(
+ struct DacpGcHeapAnalyzeData *data) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetDomainLocalModuleData(
+ CLRDATA_ADDRESS addr,
+ struct DacpDomainLocalModuleData *data) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetDomainLocalModuleDataFromAppDomain(
+ CLRDATA_ADDRESS appDomainAddr,
+ int moduleID,
+ struct DacpDomainLocalModuleData *data) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetDomainLocalModuleDataFromModule(
+ CLRDATA_ADDRESS moduleAddr,
+ struct DacpDomainLocalModuleData *data) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetThreadLocalModuleData(
+ CLRDATA_ADDRESS thread,
+ unsigned int index,
+ struct DacpThreadLocalModuleData *data) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetSyncBlockData(
+ unsigned int number,
+ struct DacpSyncBlockData *data) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetSyncBlockCleanupData(
+ CLRDATA_ADDRESS addr,
+ struct DacpSyncBlockCleanupData *data) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetHandleEnum(
+ ISOSHandleEnum **ppHandleEnum) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetHandleEnumForTypes(
+ unsigned int types[ ],
+ unsigned int count,
+ ISOSHandleEnum **ppHandleEnum) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetHandleEnumForGC(
+ unsigned int gen,
+ ISOSHandleEnum **ppHandleEnum) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE TraverseEHInfo(
+ CLRDATA_ADDRESS ip,
+ DUMPEHINFO pCallback,
+ LPVOID token) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetNestedExceptionData(
+ CLRDATA_ADDRESS exception,
+ CLRDATA_ADDRESS *exceptionObject,
+ CLRDATA_ADDRESS *nextNestedException) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetStressLogAddress(
+ CLRDATA_ADDRESS *stressLog) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE TraverseLoaderHeap(
+ CLRDATA_ADDRESS loaderHeapAddr,
+ VISITHEAP pCallback) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetCodeHeapList(
+ CLRDATA_ADDRESS jitManager,
+ unsigned int count,
+ struct DacpJitCodeHeapInfo *codeHeaps,
+ unsigned int *pNeeded) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE TraverseVirtCallStubHeap(
+ CLRDATA_ADDRESS pAppDomain,
+ VCSHeapType heaptype,
+ VISITHEAP pCallback) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetUsefulGlobals(
+ struct DacpUsefulGlobalsData *data) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetClrWatsonBuckets(
+ CLRDATA_ADDRESS thread,
+ void *pGenericModeBlock) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetTLSIndex(
+ ULONG *pIndex) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetDacModuleHandle(
+ HMODULE *phModule) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetRCWData(
+ CLRDATA_ADDRESS addr,
+ struct DacpRCWData *data) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetRCWInterfaces(
+ CLRDATA_ADDRESS rcw,
+ unsigned int count,
+ struct DacpCOMInterfacePointerData *interfaces,
+ unsigned int *pNeeded) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetCCWData(
+ CLRDATA_ADDRESS ccw,
+ struct DacpCCWData *data) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetCCWInterfaces(
+ CLRDATA_ADDRESS ccw,
+ unsigned int count,
+ struct DacpCOMInterfacePointerData *interfaces,
+ unsigned int *pNeeded) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE TraverseRCWCleanupList(
+ CLRDATA_ADDRESS cleanupListPtr,
+ VISITRCWFORCLEANUP pCallback,
+ LPVOID token) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetStackReferences(
+ /* [in] */ DWORD osThreadID,
+ /* [out] */ ISOSStackRefEnum **ppEnum) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetRegisterName(
+ /* [in] */ int regName,
+ /* [in] */ unsigned int count,
+ /* [out] */ WCHAR *buffer,
+ /* [out] */ unsigned int *pNeeded) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetThreadAllocData(
+ CLRDATA_ADDRESS thread,
+ struct DacpAllocData *data) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetHeapAllocData(
+ unsigned int count,
+ struct DacpGenerationAllocData *data,
+ unsigned int *pNeeded) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetFailedAssemblyList(
+ CLRDATA_ADDRESS appDomain,
+ int count,
+ CLRDATA_ADDRESS values[ ],
+ unsigned int *pNeeded) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetPrivateBinPaths(
+ CLRDATA_ADDRESS appDomain,
+ int count,
+ WCHAR *paths,
+ unsigned int *pNeeded) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetAssemblyLocation(
+ CLRDATA_ADDRESS assembly,
+ int count,
+ WCHAR *location,
+ unsigned int *pNeeded) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetAppDomainConfigFile(
+ CLRDATA_ADDRESS appDomain,
+ int count,
+ WCHAR *configFile,
+ unsigned int *pNeeded) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetApplicationBase(
+ CLRDATA_ADDRESS appDomain,
+ int count,
+ WCHAR *base,
+ unsigned int *pNeeded) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetFailedAssemblyData(
+ CLRDATA_ADDRESS assembly,
+ unsigned int *pContext,
+ HRESULT *pResult) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetFailedAssemblyLocation(
+ CLRDATA_ADDRESS assesmbly,
+ unsigned int count,
+ WCHAR *location,
+ unsigned int *pNeeded) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetFailedAssemblyDisplayName(
+ CLRDATA_ADDRESS assembly,
+ unsigned int count,
+ WCHAR *name,
+ unsigned int *pNeeded) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ISOSDacInterfaceVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ISOSDacInterface * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ISOSDacInterface * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ISOSDacInterface * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetThreadStoreData )(
+ ISOSDacInterface * This,
+ struct DacpThreadStoreData *data);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAppDomainStoreData )(
+ ISOSDacInterface * This,
+ struct DacpAppDomainStoreData *data);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAppDomainList )(
+ ISOSDacInterface * This,
+ unsigned int count,
+ CLRDATA_ADDRESS values[ ],
+ unsigned int *pNeeded);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAppDomainData )(
+ ISOSDacInterface * This,
+ CLRDATA_ADDRESS addr,
+ struct DacpAppDomainData *data);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAppDomainName )(
+ ISOSDacInterface * This,
+ CLRDATA_ADDRESS addr,
+ unsigned int count,
+ WCHAR *name,
+ unsigned int *pNeeded);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDomainFromContext )(
+ ISOSDacInterface * This,
+ CLRDATA_ADDRESS context,
+ CLRDATA_ADDRESS *domain);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAssemblyList )(
+ ISOSDacInterface * This,
+ CLRDATA_ADDRESS appDomain,
+ int count,
+ CLRDATA_ADDRESS values[ ],
+ int *pNeeded);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAssemblyData )(
+ ISOSDacInterface * This,
+ CLRDATA_ADDRESS baseDomainPtr,
+ CLRDATA_ADDRESS assembly,
+ struct DacpAssemblyData *data);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAssemblyName )(
+ ISOSDacInterface * This,
+ CLRDATA_ADDRESS assembly,
+ unsigned int count,
+ WCHAR *name,
+ unsigned int *pNeeded);
+
+ HRESULT ( STDMETHODCALLTYPE *GetModule )(
+ ISOSDacInterface * This,
+ CLRDATA_ADDRESS addr,
+ IXCLRDataModule **mod);
+
+ HRESULT ( STDMETHODCALLTYPE *GetModuleData )(
+ ISOSDacInterface * This,
+ CLRDATA_ADDRESS moduleAddr,
+ struct DacpModuleData *data);
+
+ HRESULT ( STDMETHODCALLTYPE *TraverseModuleMap )(
+ ISOSDacInterface * This,
+ ModuleMapType mmt,
+ CLRDATA_ADDRESS moduleAddr,
+ MODULEMAPTRAVERSE pCallback,
+ LPVOID token);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAssemblyModuleList )(
+ ISOSDacInterface * This,
+ CLRDATA_ADDRESS assembly,
+ unsigned int count,
+ CLRDATA_ADDRESS modules[ ],
+ unsigned int *pNeeded);
+
+ HRESULT ( STDMETHODCALLTYPE *GetILForModule )(
+ ISOSDacInterface * This,
+ CLRDATA_ADDRESS moduleAddr,
+ DWORD rva,
+ CLRDATA_ADDRESS *il);
+
+ HRESULT ( STDMETHODCALLTYPE *GetThreadData )(
+ ISOSDacInterface * This,
+ CLRDATA_ADDRESS thread,
+ struct DacpThreadData *data);
+
+ HRESULT ( STDMETHODCALLTYPE *GetThreadFromThinlockID )(
+ ISOSDacInterface * This,
+ UINT thinLockId,
+ CLRDATA_ADDRESS *pThread);
+
+ HRESULT ( STDMETHODCALLTYPE *GetStackLimits )(
+ ISOSDacInterface * This,
+ CLRDATA_ADDRESS threadPtr,
+ CLRDATA_ADDRESS *lower,
+ CLRDATA_ADDRESS *upper,
+ CLRDATA_ADDRESS *fp);
+
+ HRESULT ( STDMETHODCALLTYPE *GetMethodDescData )(
+ ISOSDacInterface * This,
+ CLRDATA_ADDRESS methodDesc,
+ CLRDATA_ADDRESS ip,
+ struct DacpMethodDescData *data,
+ ULONG cRevertedRejitVersions,
+ struct DacpReJitData *rgRevertedRejitData,
+ ULONG *pcNeededRevertedRejitData);
+
+ HRESULT ( STDMETHODCALLTYPE *GetMethodDescPtrFromIP )(
+ ISOSDacInterface * This,
+ CLRDATA_ADDRESS ip,
+ CLRDATA_ADDRESS *ppMD);
+
+ HRESULT ( STDMETHODCALLTYPE *GetMethodDescName )(
+ ISOSDacInterface * This,
+ CLRDATA_ADDRESS methodDesc,
+ unsigned int count,
+ WCHAR *name,
+ unsigned int *pNeeded);
+
+ HRESULT ( STDMETHODCALLTYPE *GetMethodDescPtrFromFrame )(
+ ISOSDacInterface * This,
+ CLRDATA_ADDRESS frameAddr,
+ CLRDATA_ADDRESS *ppMD);
+
+ HRESULT ( STDMETHODCALLTYPE *GetMethodDescFromToken )(
+ ISOSDacInterface * This,
+ CLRDATA_ADDRESS moduleAddr,
+ mdToken token,
+ CLRDATA_ADDRESS *methodDesc);
+
+ HRESULT ( STDMETHODCALLTYPE *GetMethodDescTransparencyData )(
+ ISOSDacInterface * This,
+ CLRDATA_ADDRESS methodDesc,
+ struct DacpMethodDescTransparencyData *data);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCodeHeaderData )(
+ ISOSDacInterface * This,
+ CLRDATA_ADDRESS ip,
+ struct DacpCodeHeaderData *data);
+
+ HRESULT ( STDMETHODCALLTYPE *GetJitManagerList )(
+ ISOSDacInterface * This,
+ unsigned int count,
+ struct DacpJitManagerInfo *managers,
+ unsigned int *pNeeded);
+
+ HRESULT ( STDMETHODCALLTYPE *GetJitHelperFunctionName )(
+ ISOSDacInterface * This,
+ CLRDATA_ADDRESS ip,
+ unsigned int count,
+ char *name,
+ unsigned int *pNeeded);
+
+ HRESULT ( STDMETHODCALLTYPE *GetJumpThunkTarget )(
+ ISOSDacInterface * This,
+ T_CONTEXT *ctx,
+ CLRDATA_ADDRESS *targetIP,
+ CLRDATA_ADDRESS *targetMD);
+
+ HRESULT ( STDMETHODCALLTYPE *GetThreadpoolData )(
+ ISOSDacInterface * This,
+ struct DacpThreadpoolData *data);
+
+ HRESULT ( STDMETHODCALLTYPE *GetWorkRequestData )(
+ ISOSDacInterface * This,
+ CLRDATA_ADDRESS addrWorkRequest,
+ struct DacpWorkRequestData *data);
+
+ HRESULT ( STDMETHODCALLTYPE *GetHillClimbingLogEntry )(
+ ISOSDacInterface * This,
+ CLRDATA_ADDRESS addr,
+ struct DacpHillClimbingLogEntry *data);
+
+ HRESULT ( STDMETHODCALLTYPE *GetObjectData )(
+ ISOSDacInterface * This,
+ CLRDATA_ADDRESS objAddr,
+ struct DacpObjectData *data);
+
+ HRESULT ( STDMETHODCALLTYPE *GetObjectStringData )(
+ ISOSDacInterface * This,
+ CLRDATA_ADDRESS obj,
+ unsigned int count,
+ WCHAR *stringData,
+ unsigned int *pNeeded);
+
+ HRESULT ( STDMETHODCALLTYPE *GetObjectClassName )(
+ ISOSDacInterface * This,
+ CLRDATA_ADDRESS obj,
+ unsigned int count,
+ WCHAR *className,
+ unsigned int *pNeeded);
+
+ HRESULT ( STDMETHODCALLTYPE *GetMethodTableName )(
+ ISOSDacInterface * This,
+ CLRDATA_ADDRESS mt,
+ unsigned int count,
+ WCHAR *mtName,
+ unsigned int *pNeeded);
+
+ HRESULT ( STDMETHODCALLTYPE *GetMethodTableData )(
+ ISOSDacInterface * This,
+ CLRDATA_ADDRESS mt,
+ struct DacpMethodTableData *data);
+
+ HRESULT ( STDMETHODCALLTYPE *GetMethodTableSlot )(
+ ISOSDacInterface * This,
+ CLRDATA_ADDRESS mt,
+ unsigned int slot,
+ CLRDATA_ADDRESS *value);
+
+ HRESULT ( STDMETHODCALLTYPE *GetMethodTableFieldData )(
+ ISOSDacInterface * This,
+ CLRDATA_ADDRESS mt,
+ struct DacpMethodTableFieldData *data);
+
+ HRESULT ( STDMETHODCALLTYPE *GetMethodTableTransparencyData )(
+ ISOSDacInterface * This,
+ CLRDATA_ADDRESS mt,
+ struct DacpMethodTableTransparencyData *data);
+
+ HRESULT ( STDMETHODCALLTYPE *GetMethodTableForEEClass )(
+ ISOSDacInterface * This,
+ CLRDATA_ADDRESS eeClass,
+ CLRDATA_ADDRESS *value);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFieldDescData )(
+ ISOSDacInterface * This,
+ CLRDATA_ADDRESS fieldDesc,
+ struct DacpFieldDescData *data);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFrameName )(
+ ISOSDacInterface * This,
+ CLRDATA_ADDRESS vtable,
+ unsigned int count,
+ WCHAR *frameName,
+ unsigned int *pNeeded);
+
+ HRESULT ( STDMETHODCALLTYPE *GetPEFileBase )(
+ ISOSDacInterface * This,
+ CLRDATA_ADDRESS addr,
+ CLRDATA_ADDRESS *base);
+
+ HRESULT ( STDMETHODCALLTYPE *GetPEFileName )(
+ ISOSDacInterface * This,
+ CLRDATA_ADDRESS addr,
+ unsigned int count,
+ WCHAR *fileName,
+ unsigned int *pNeeded);
+
+ HRESULT ( STDMETHODCALLTYPE *GetGCHeapData )(
+ ISOSDacInterface * This,
+ struct DacpGcHeapData *data);
+
+ HRESULT ( STDMETHODCALLTYPE *GetGCHeapList )(
+ ISOSDacInterface * This,
+ unsigned int count,
+ CLRDATA_ADDRESS heaps[ ],
+ unsigned int *pNeeded);
+
+ HRESULT ( STDMETHODCALLTYPE *GetGCHeapDetails )(
+ ISOSDacInterface * This,
+ CLRDATA_ADDRESS heap,
+ struct DacpGcHeapDetails *details);
+
+ HRESULT ( STDMETHODCALLTYPE *GetGCHeapStaticData )(
+ ISOSDacInterface * This,
+ struct DacpGcHeapDetails *data);
+
+ HRESULT ( STDMETHODCALLTYPE *GetHeapSegmentData )(
+ ISOSDacInterface * This,
+ CLRDATA_ADDRESS seg,
+ struct DacpHeapSegmentData *data);
+
+ HRESULT ( STDMETHODCALLTYPE *GetOOMData )(
+ ISOSDacInterface * This,
+ CLRDATA_ADDRESS oomAddr,
+ struct DacpOomData *data);
+
+ HRESULT ( STDMETHODCALLTYPE *GetOOMStaticData )(
+ ISOSDacInterface * This,
+ struct DacpOomData *data);
+
+ HRESULT ( STDMETHODCALLTYPE *GetHeapAnalyzeData )(
+ ISOSDacInterface * This,
+ CLRDATA_ADDRESS addr,
+ struct DacpGcHeapAnalyzeData *data);
+
+ HRESULT ( STDMETHODCALLTYPE *GetHeapAnalyzeStaticData )(
+ ISOSDacInterface * This,
+ struct DacpGcHeapAnalyzeData *data);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDomainLocalModuleData )(
+ ISOSDacInterface * This,
+ CLRDATA_ADDRESS addr,
+ struct DacpDomainLocalModuleData *data);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDomainLocalModuleDataFromAppDomain )(
+ ISOSDacInterface * This,
+ CLRDATA_ADDRESS appDomainAddr,
+ int moduleID,
+ struct DacpDomainLocalModuleData *data);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDomainLocalModuleDataFromModule )(
+ ISOSDacInterface * This,
+ CLRDATA_ADDRESS moduleAddr,
+ struct DacpDomainLocalModuleData *data);
+
+ HRESULT ( STDMETHODCALLTYPE *GetThreadLocalModuleData )(
+ ISOSDacInterface * This,
+ CLRDATA_ADDRESS thread,
+ unsigned int index,
+ struct DacpThreadLocalModuleData *data);
+
+ HRESULT ( STDMETHODCALLTYPE *GetSyncBlockData )(
+ ISOSDacInterface * This,
+ unsigned int number,
+ struct DacpSyncBlockData *data);
+
+ HRESULT ( STDMETHODCALLTYPE *GetSyncBlockCleanupData )(
+ ISOSDacInterface * This,
+ CLRDATA_ADDRESS addr,
+ struct DacpSyncBlockCleanupData *data);
+
+ HRESULT ( STDMETHODCALLTYPE *GetHandleEnum )(
+ ISOSDacInterface * This,
+ ISOSHandleEnum **ppHandleEnum);
+
+ HRESULT ( STDMETHODCALLTYPE *GetHandleEnumForTypes )(
+ ISOSDacInterface * This,
+ unsigned int types[ ],
+ unsigned int count,
+ ISOSHandleEnum **ppHandleEnum);
+
+ HRESULT ( STDMETHODCALLTYPE *GetHandleEnumForGC )(
+ ISOSDacInterface * This,
+ unsigned int gen,
+ ISOSHandleEnum **ppHandleEnum);
+
+ HRESULT ( STDMETHODCALLTYPE *TraverseEHInfo )(
+ ISOSDacInterface * This,
+ CLRDATA_ADDRESS ip,
+ DUMPEHINFO pCallback,
+ LPVOID token);
+
+ HRESULT ( STDMETHODCALLTYPE *GetNestedExceptionData )(
+ ISOSDacInterface * This,
+ CLRDATA_ADDRESS exception,
+ CLRDATA_ADDRESS *exceptionObject,
+ CLRDATA_ADDRESS *nextNestedException);
+
+ HRESULT ( STDMETHODCALLTYPE *GetStressLogAddress )(
+ ISOSDacInterface * This,
+ CLRDATA_ADDRESS *stressLog);
+
+ HRESULT ( STDMETHODCALLTYPE *TraverseLoaderHeap )(
+ ISOSDacInterface * This,
+ CLRDATA_ADDRESS loaderHeapAddr,
+ VISITHEAP pCallback);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCodeHeapList )(
+ ISOSDacInterface * This,
+ CLRDATA_ADDRESS jitManager,
+ unsigned int count,
+ struct DacpJitCodeHeapInfo *codeHeaps,
+ unsigned int *pNeeded);
+
+ HRESULT ( STDMETHODCALLTYPE *TraverseVirtCallStubHeap )(
+ ISOSDacInterface * This,
+ CLRDATA_ADDRESS pAppDomain,
+ VCSHeapType heaptype,
+ VISITHEAP pCallback);
+
+ HRESULT ( STDMETHODCALLTYPE *GetUsefulGlobals )(
+ ISOSDacInterface * This,
+ struct DacpUsefulGlobalsData *data);
+
+ HRESULT ( STDMETHODCALLTYPE *GetClrWatsonBuckets )(
+ ISOSDacInterface * This,
+ CLRDATA_ADDRESS thread,
+ void *pGenericModeBlock);
+
+ HRESULT ( STDMETHODCALLTYPE *GetTLSIndex )(
+ ISOSDacInterface * This,
+ ULONG *pIndex);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDacModuleHandle )(
+ ISOSDacInterface * This,
+ HMODULE *phModule);
+
+ HRESULT ( STDMETHODCALLTYPE *GetRCWData )(
+ ISOSDacInterface * This,
+ CLRDATA_ADDRESS addr,
+ struct DacpRCWData *data);
+
+ HRESULT ( STDMETHODCALLTYPE *GetRCWInterfaces )(
+ ISOSDacInterface * This,
+ CLRDATA_ADDRESS rcw,
+ unsigned int count,
+ struct DacpCOMInterfacePointerData *interfaces,
+ unsigned int *pNeeded);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCCWData )(
+ ISOSDacInterface * This,
+ CLRDATA_ADDRESS ccw,
+ struct DacpCCWData *data);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCCWInterfaces )(
+ ISOSDacInterface * This,
+ CLRDATA_ADDRESS ccw,
+ unsigned int count,
+ struct DacpCOMInterfacePointerData *interfaces,
+ unsigned int *pNeeded);
+
+ HRESULT ( STDMETHODCALLTYPE *TraverseRCWCleanupList )(
+ ISOSDacInterface * This,
+ CLRDATA_ADDRESS cleanupListPtr,
+ VISITRCWFORCLEANUP pCallback,
+ LPVOID token);
+
+ HRESULT ( STDMETHODCALLTYPE *GetStackReferences )(
+ ISOSDacInterface * This,
+ /* [in] */ DWORD osThreadID,
+ /* [out] */ ISOSStackRefEnum **ppEnum);
+
+ HRESULT ( STDMETHODCALLTYPE *GetRegisterName )(
+ ISOSDacInterface * This,
+ /* [in] */ int regName,
+ /* [in] */ unsigned int count,
+ /* [out] */ WCHAR *buffer,
+ /* [out] */ unsigned int *pNeeded);
+
+ HRESULT ( STDMETHODCALLTYPE *GetThreadAllocData )(
+ ISOSDacInterface * This,
+ CLRDATA_ADDRESS thread,
+ struct DacpAllocData *data);
+
+ HRESULT ( STDMETHODCALLTYPE *GetHeapAllocData )(
+ ISOSDacInterface * This,
+ unsigned int count,
+ struct DacpGenerationAllocData *data,
+ unsigned int *pNeeded);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFailedAssemblyList )(
+ ISOSDacInterface * This,
+ CLRDATA_ADDRESS appDomain,
+ int count,
+ CLRDATA_ADDRESS values[ ],
+ unsigned int *pNeeded);
+
+ HRESULT ( STDMETHODCALLTYPE *GetPrivateBinPaths )(
+ ISOSDacInterface * This,
+ CLRDATA_ADDRESS appDomain,
+ int count,
+ WCHAR *paths,
+ unsigned int *pNeeded);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAssemblyLocation )(
+ ISOSDacInterface * This,
+ CLRDATA_ADDRESS assembly,
+ int count,
+ WCHAR *location,
+ unsigned int *pNeeded);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAppDomainConfigFile )(
+ ISOSDacInterface * This,
+ CLRDATA_ADDRESS appDomain,
+ int count,
+ WCHAR *configFile,
+ unsigned int *pNeeded);
+
+ HRESULT ( STDMETHODCALLTYPE *GetApplicationBase )(
+ ISOSDacInterface * This,
+ CLRDATA_ADDRESS appDomain,
+ int count,
+ WCHAR *base,
+ unsigned int *pNeeded);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFailedAssemblyData )(
+ ISOSDacInterface * This,
+ CLRDATA_ADDRESS assembly,
+ unsigned int *pContext,
+ HRESULT *pResult);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFailedAssemblyLocation )(
+ ISOSDacInterface * This,
+ CLRDATA_ADDRESS assesmbly,
+ unsigned int count,
+ WCHAR *location,
+ unsigned int *pNeeded);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFailedAssemblyDisplayName )(
+ ISOSDacInterface * This,
+ CLRDATA_ADDRESS assembly,
+ unsigned int count,
+ WCHAR *name,
+ unsigned int *pNeeded);
+
+ END_INTERFACE
+ } ISOSDacInterfaceVtbl;
+
+ interface ISOSDacInterface
+ {
+ CONST_VTBL struct ISOSDacInterfaceVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ISOSDacInterface_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ISOSDacInterface_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ISOSDacInterface_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ISOSDacInterface_GetThreadStoreData(This,data) \
+ ( (This)->lpVtbl -> GetThreadStoreData(This,data) )
+
+#define ISOSDacInterface_GetAppDomainStoreData(This,data) \
+ ( (This)->lpVtbl -> GetAppDomainStoreData(This,data) )
+
+#define ISOSDacInterface_GetAppDomainList(This,count,values,pNeeded) \
+ ( (This)->lpVtbl -> GetAppDomainList(This,count,values,pNeeded) )
+
+#define ISOSDacInterface_GetAppDomainData(This,addr,data) \
+ ( (This)->lpVtbl -> GetAppDomainData(This,addr,data) )
+
+#define ISOSDacInterface_GetAppDomainName(This,addr,count,name,pNeeded) \
+ ( (This)->lpVtbl -> GetAppDomainName(This,addr,count,name,pNeeded) )
+
+#define ISOSDacInterface_GetDomainFromContext(This,context,domain) \
+ ( (This)->lpVtbl -> GetDomainFromContext(This,context,domain) )
+
+#define ISOSDacInterface_GetAssemblyList(This,appDomain,count,values,pNeeded) \
+ ( (This)->lpVtbl -> GetAssemblyList(This,appDomain,count,values,pNeeded) )
+
+#define ISOSDacInterface_GetAssemblyData(This,baseDomainPtr,assembly,data) \
+ ( (This)->lpVtbl -> GetAssemblyData(This,baseDomainPtr,assembly,data) )
+
+#define ISOSDacInterface_GetAssemblyName(This,assembly,count,name,pNeeded) \
+ ( (This)->lpVtbl -> GetAssemblyName(This,assembly,count,name,pNeeded) )
+
+#define ISOSDacInterface_GetModule(This,addr,mod) \
+ ( (This)->lpVtbl -> GetModule(This,addr,mod) )
+
+#define ISOSDacInterface_GetModuleData(This,moduleAddr,data) \
+ ( (This)->lpVtbl -> GetModuleData(This,moduleAddr,data) )
+
+#define ISOSDacInterface_TraverseModuleMap(This,mmt,moduleAddr,pCallback,token) \
+ ( (This)->lpVtbl -> TraverseModuleMap(This,mmt,moduleAddr,pCallback,token) )
+
+#define ISOSDacInterface_GetAssemblyModuleList(This,assembly,count,modules,pNeeded) \
+ ( (This)->lpVtbl -> GetAssemblyModuleList(This,assembly,count,modules,pNeeded) )
+
+#define ISOSDacInterface_GetILForModule(This,moduleAddr,rva,il) \
+ ( (This)->lpVtbl -> GetILForModule(This,moduleAddr,rva,il) )
+
+#define ISOSDacInterface_GetThreadData(This,thread,data) \
+ ( (This)->lpVtbl -> GetThreadData(This,thread,data) )
+
+#define ISOSDacInterface_GetThreadFromThinlockID(This,thinLockId,pThread) \
+ ( (This)->lpVtbl -> GetThreadFromThinlockID(This,thinLockId,pThread) )
+
+#define ISOSDacInterface_GetStackLimits(This,threadPtr,lower,upper,fp) \
+ ( (This)->lpVtbl -> GetStackLimits(This,threadPtr,lower,upper,fp) )
+
+#define ISOSDacInterface_GetMethodDescData(This,methodDesc,ip,data,cRevertedRejitVersions,rgRevertedRejitData,pcNeededRevertedRejitData) \
+ ( (This)->lpVtbl -> GetMethodDescData(This,methodDesc,ip,data,cRevertedRejitVersions,rgRevertedRejitData,pcNeededRevertedRejitData) )
+
+#define ISOSDacInterface_GetMethodDescPtrFromIP(This,ip,ppMD) \
+ ( (This)->lpVtbl -> GetMethodDescPtrFromIP(This,ip,ppMD) )
+
+#define ISOSDacInterface_GetMethodDescName(This,methodDesc,count,name,pNeeded) \
+ ( (This)->lpVtbl -> GetMethodDescName(This,methodDesc,count,name,pNeeded) )
+
+#define ISOSDacInterface_GetMethodDescPtrFromFrame(This,frameAddr,ppMD) \
+ ( (This)->lpVtbl -> GetMethodDescPtrFromFrame(This,frameAddr,ppMD) )
+
+#define ISOSDacInterface_GetMethodDescFromToken(This,moduleAddr,token,methodDesc) \
+ ( (This)->lpVtbl -> GetMethodDescFromToken(This,moduleAddr,token,methodDesc) )
+
+#define ISOSDacInterface_GetMethodDescTransparencyData(This,methodDesc,data) \
+ ( (This)->lpVtbl -> GetMethodDescTransparencyData(This,methodDesc,data) )
+
+#define ISOSDacInterface_GetCodeHeaderData(This,ip,data) \
+ ( (This)->lpVtbl -> GetCodeHeaderData(This,ip,data) )
+
+#define ISOSDacInterface_GetJitManagerList(This,count,managers,pNeeded) \
+ ( (This)->lpVtbl -> GetJitManagerList(This,count,managers,pNeeded) )
+
+#define ISOSDacInterface_GetJitHelperFunctionName(This,ip,count,name,pNeeded) \
+ ( (This)->lpVtbl -> GetJitHelperFunctionName(This,ip,count,name,pNeeded) )
+
+#define ISOSDacInterface_GetJumpThunkTarget(This,ctx,targetIP,targetMD) \
+ ( (This)->lpVtbl -> GetJumpThunkTarget(This,ctx,targetIP,targetMD) )
+
+#define ISOSDacInterface_GetThreadpoolData(This,data) \
+ ( (This)->lpVtbl -> GetThreadpoolData(This,data) )
+
+#define ISOSDacInterface_GetWorkRequestData(This,addrWorkRequest,data) \
+ ( (This)->lpVtbl -> GetWorkRequestData(This,addrWorkRequest,data) )
+
+#define ISOSDacInterface_GetHillClimbingLogEntry(This,addr,data) \
+ ( (This)->lpVtbl -> GetHillClimbingLogEntry(This,addr,data) )
+
+#define ISOSDacInterface_GetObjectData(This,objAddr,data) \
+ ( (This)->lpVtbl -> GetObjectData(This,objAddr,data) )
+
+#define ISOSDacInterface_GetObjectStringData(This,obj,count,stringData,pNeeded) \
+ ( (This)->lpVtbl -> GetObjectStringData(This,obj,count,stringData,pNeeded) )
+
+#define ISOSDacInterface_GetObjectClassName(This,obj,count,className,pNeeded) \
+ ( (This)->lpVtbl -> GetObjectClassName(This,obj,count,className,pNeeded) )
+
+#define ISOSDacInterface_GetMethodTableName(This,mt,count,mtName,pNeeded) \
+ ( (This)->lpVtbl -> GetMethodTableName(This,mt,count,mtName,pNeeded) )
+
+#define ISOSDacInterface_GetMethodTableData(This,mt,data) \
+ ( (This)->lpVtbl -> GetMethodTableData(This,mt,data) )
+
+#define ISOSDacInterface_GetMethodTableSlot(This,mt,slot,value) \
+ ( (This)->lpVtbl -> GetMethodTableSlot(This,mt,slot,value) )
+
+#define ISOSDacInterface_GetMethodTableFieldData(This,mt,data) \
+ ( (This)->lpVtbl -> GetMethodTableFieldData(This,mt,data) )
+
+#define ISOSDacInterface_GetMethodTableTransparencyData(This,mt,data) \
+ ( (This)->lpVtbl -> GetMethodTableTransparencyData(This,mt,data) )
+
+#define ISOSDacInterface_GetMethodTableForEEClass(This,eeClass,value) \
+ ( (This)->lpVtbl -> GetMethodTableForEEClass(This,eeClass,value) )
+
+#define ISOSDacInterface_GetFieldDescData(This,fieldDesc,data) \
+ ( (This)->lpVtbl -> GetFieldDescData(This,fieldDesc,data) )
+
+#define ISOSDacInterface_GetFrameName(This,vtable,count,frameName,pNeeded) \
+ ( (This)->lpVtbl -> GetFrameName(This,vtable,count,frameName,pNeeded) )
+
+#define ISOSDacInterface_GetPEFileBase(This,addr,base) \
+ ( (This)->lpVtbl -> GetPEFileBase(This,addr,base) )
+
+#define ISOSDacInterface_GetPEFileName(This,addr,count,fileName,pNeeded) \
+ ( (This)->lpVtbl -> GetPEFileName(This,addr,count,fileName,pNeeded) )
+
+#define ISOSDacInterface_GetGCHeapData(This,data) \
+ ( (This)->lpVtbl -> GetGCHeapData(This,data) )
+
+#define ISOSDacInterface_GetGCHeapList(This,count,heaps,pNeeded) \
+ ( (This)->lpVtbl -> GetGCHeapList(This,count,heaps,pNeeded) )
+
+#define ISOSDacInterface_GetGCHeapDetails(This,heap,details) \
+ ( (This)->lpVtbl -> GetGCHeapDetails(This,heap,details) )
+
+#define ISOSDacInterface_GetGCHeapStaticData(This,data) \
+ ( (This)->lpVtbl -> GetGCHeapStaticData(This,data) )
+
+#define ISOSDacInterface_GetHeapSegmentData(This,seg,data) \
+ ( (This)->lpVtbl -> GetHeapSegmentData(This,seg,data) )
+
+#define ISOSDacInterface_GetOOMData(This,oomAddr,data) \
+ ( (This)->lpVtbl -> GetOOMData(This,oomAddr,data) )
+
+#define ISOSDacInterface_GetOOMStaticData(This,data) \
+ ( (This)->lpVtbl -> GetOOMStaticData(This,data) )
+
+#define ISOSDacInterface_GetHeapAnalyzeData(This,addr,data) \
+ ( (This)->lpVtbl -> GetHeapAnalyzeData(This,addr,data) )
+
+#define ISOSDacInterface_GetHeapAnalyzeStaticData(This,data) \
+ ( (This)->lpVtbl -> GetHeapAnalyzeStaticData(This,data) )
+
+#define ISOSDacInterface_GetDomainLocalModuleData(This,addr,data) \
+ ( (This)->lpVtbl -> GetDomainLocalModuleData(This,addr,data) )
+
+#define ISOSDacInterface_GetDomainLocalModuleDataFromAppDomain(This,appDomainAddr,moduleID,data) \
+ ( (This)->lpVtbl -> GetDomainLocalModuleDataFromAppDomain(This,appDomainAddr,moduleID,data) )
+
+#define ISOSDacInterface_GetDomainLocalModuleDataFromModule(This,moduleAddr,data) \
+ ( (This)->lpVtbl -> GetDomainLocalModuleDataFromModule(This,moduleAddr,data) )
+
+#define ISOSDacInterface_GetThreadLocalModuleData(This,thread,index,data) \
+ ( (This)->lpVtbl -> GetThreadLocalModuleData(This,thread,index,data) )
+
+#define ISOSDacInterface_GetSyncBlockData(This,number,data) \
+ ( (This)->lpVtbl -> GetSyncBlockData(This,number,data) )
+
+#define ISOSDacInterface_GetSyncBlockCleanupData(This,addr,data) \
+ ( (This)->lpVtbl -> GetSyncBlockCleanupData(This,addr,data) )
+
+#define ISOSDacInterface_GetHandleEnum(This,ppHandleEnum) \
+ ( (This)->lpVtbl -> GetHandleEnum(This,ppHandleEnum) )
+
+#define ISOSDacInterface_GetHandleEnumForTypes(This,types,count,ppHandleEnum) \
+ ( (This)->lpVtbl -> GetHandleEnumForTypes(This,types,count,ppHandleEnum) )
+
+#define ISOSDacInterface_GetHandleEnumForGC(This,gen,ppHandleEnum) \
+ ( (This)->lpVtbl -> GetHandleEnumForGC(This,gen,ppHandleEnum) )
+
+#define ISOSDacInterface_TraverseEHInfo(This,ip,pCallback,token) \
+ ( (This)->lpVtbl -> TraverseEHInfo(This,ip,pCallback,token) )
+
+#define ISOSDacInterface_GetNestedExceptionData(This,exception,exceptionObject,nextNestedException) \
+ ( (This)->lpVtbl -> GetNestedExceptionData(This,exception,exceptionObject,nextNestedException) )
+
+#define ISOSDacInterface_GetStressLogAddress(This,stressLog) \
+ ( (This)->lpVtbl -> GetStressLogAddress(This,stressLog) )
+
+#define ISOSDacInterface_TraverseLoaderHeap(This,loaderHeapAddr,pCallback) \
+ ( (This)->lpVtbl -> TraverseLoaderHeap(This,loaderHeapAddr,pCallback) )
+
+#define ISOSDacInterface_GetCodeHeapList(This,jitManager,count,codeHeaps,pNeeded) \
+ ( (This)->lpVtbl -> GetCodeHeapList(This,jitManager,count,codeHeaps,pNeeded) )
+
+#define ISOSDacInterface_TraverseVirtCallStubHeap(This,pAppDomain,heaptype,pCallback) \
+ ( (This)->lpVtbl -> TraverseVirtCallStubHeap(This,pAppDomain,heaptype,pCallback) )
+
+#define ISOSDacInterface_GetUsefulGlobals(This,data) \
+ ( (This)->lpVtbl -> GetUsefulGlobals(This,data) )
+
+#define ISOSDacInterface_GetClrWatsonBuckets(This,thread,pGenericModeBlock) \
+ ( (This)->lpVtbl -> GetClrWatsonBuckets(This,thread,pGenericModeBlock) )
+
+#define ISOSDacInterface_GetTLSIndex(This,pIndex) \
+ ( (This)->lpVtbl -> GetTLSIndex(This,pIndex) )
+
+#define ISOSDacInterface_GetDacModuleHandle(This,phModule) \
+ ( (This)->lpVtbl -> GetDacModuleHandle(This,phModule) )
+
+#define ISOSDacInterface_GetRCWData(This,addr,data) \
+ ( (This)->lpVtbl -> GetRCWData(This,addr,data) )
+
+#define ISOSDacInterface_GetRCWInterfaces(This,rcw,count,interfaces,pNeeded) \
+ ( (This)->lpVtbl -> GetRCWInterfaces(This,rcw,count,interfaces,pNeeded) )
+
+#define ISOSDacInterface_GetCCWData(This,ccw,data) \
+ ( (This)->lpVtbl -> GetCCWData(This,ccw,data) )
+
+#define ISOSDacInterface_GetCCWInterfaces(This,ccw,count,interfaces,pNeeded) \
+ ( (This)->lpVtbl -> GetCCWInterfaces(This,ccw,count,interfaces,pNeeded) )
+
+#define ISOSDacInterface_TraverseRCWCleanupList(This,cleanupListPtr,pCallback,token) \
+ ( (This)->lpVtbl -> TraverseRCWCleanupList(This,cleanupListPtr,pCallback,token) )
+
+#define ISOSDacInterface_GetStackReferences(This,osThreadID,ppEnum) \
+ ( (This)->lpVtbl -> GetStackReferences(This,osThreadID,ppEnum) )
+
+#define ISOSDacInterface_GetRegisterName(This,regName,count,buffer,pNeeded) \
+ ( (This)->lpVtbl -> GetRegisterName(This,regName,count,buffer,pNeeded) )
+
+#define ISOSDacInterface_GetThreadAllocData(This,thread,data) \
+ ( (This)->lpVtbl -> GetThreadAllocData(This,thread,data) )
+
+#define ISOSDacInterface_GetHeapAllocData(This,count,data,pNeeded) \
+ ( (This)->lpVtbl -> GetHeapAllocData(This,count,data,pNeeded) )
+
+#define ISOSDacInterface_GetFailedAssemblyList(This,appDomain,count,values,pNeeded) \
+ ( (This)->lpVtbl -> GetFailedAssemblyList(This,appDomain,count,values,pNeeded) )
+
+#define ISOSDacInterface_GetPrivateBinPaths(This,appDomain,count,paths,pNeeded) \
+ ( (This)->lpVtbl -> GetPrivateBinPaths(This,appDomain,count,paths,pNeeded) )
+
+#define ISOSDacInterface_GetAssemblyLocation(This,assembly,count,location,pNeeded) \
+ ( (This)->lpVtbl -> GetAssemblyLocation(This,assembly,count,location,pNeeded) )
+
+#define ISOSDacInterface_GetAppDomainConfigFile(This,appDomain,count,configFile,pNeeded) \
+ ( (This)->lpVtbl -> GetAppDomainConfigFile(This,appDomain,count,configFile,pNeeded) )
+
+#define ISOSDacInterface_GetApplicationBase(This,appDomain,count,base,pNeeded) \
+ ( (This)->lpVtbl -> GetApplicationBase(This,appDomain,count,base,pNeeded) )
+
+#define ISOSDacInterface_GetFailedAssemblyData(This,assembly,pContext,pResult) \
+ ( (This)->lpVtbl -> GetFailedAssemblyData(This,assembly,pContext,pResult) )
+
+#define ISOSDacInterface_GetFailedAssemblyLocation(This,assesmbly,count,location,pNeeded) \
+ ( (This)->lpVtbl -> GetFailedAssemblyLocation(This,assesmbly,count,location,pNeeded) )
+
+#define ISOSDacInterface_GetFailedAssemblyDisplayName(This,assembly,count,name,pNeeded) \
+ ( (This)->lpVtbl -> GetFailedAssemblyDisplayName(This,assembly,count,name,pNeeded) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ISOSDacInterface_INTERFACE_DEFINED__ */
+
+
+#ifndef __ISOSDacInterface2_INTERFACE_DEFINED__
+#define __ISOSDacInterface2_INTERFACE_DEFINED__
+
+/* interface ISOSDacInterface2 */
+/* [uuid][local][object] */
+
+
+EXTERN_C const IID IID_ISOSDacInterface2;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("A16026EC-96F4-40BA-87FB-5575986FB7AF")
+ ISOSDacInterface2 : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetObjectExceptionData(
+ CLRDATA_ADDRESS objAddr,
+ struct DacpExceptionObjectData *data) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE IsRCWDCOMProxy(
+ CLRDATA_ADDRESS rcwAddr,
+ BOOL *isDCOMProxy) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ISOSDacInterface2Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ISOSDacInterface2 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ISOSDacInterface2 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ISOSDacInterface2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetObjectExceptionData )(
+ ISOSDacInterface2 * This,
+ CLRDATA_ADDRESS objAddr,
+ struct DacpExceptionObjectData *data);
+
+ HRESULT ( STDMETHODCALLTYPE *IsRCWDCOMProxy )(
+ ISOSDacInterface2 * This,
+ CLRDATA_ADDRESS rcwAddr,
+ BOOL *isDCOMProxy);
+
+ END_INTERFACE
+ } ISOSDacInterface2Vtbl;
+
+ interface ISOSDacInterface2
+ {
+ CONST_VTBL struct ISOSDacInterface2Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ISOSDacInterface2_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ISOSDacInterface2_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ISOSDacInterface2_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ISOSDacInterface2_GetObjectExceptionData(This,objAddr,data) \
+ ( (This)->lpVtbl -> GetObjectExceptionData(This,objAddr,data) )
+
+#define ISOSDacInterface2_IsRCWDCOMProxy(This,rcwAddr,isDCOMProxy) \
+ ( (This)->lpVtbl -> IsRCWDCOMProxy(This,rcwAddr,isDCOMProxy) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ISOSDacInterface2_INTERFACE_DEFINED__ */
+
+
+#ifndef __ISOSDacInterface3_INTERFACE_DEFINED__
+#define __ISOSDacInterface3_INTERFACE_DEFINED__
+
+/* interface ISOSDacInterface3 */
+/* [uuid][local][object] */
+
+
+EXTERN_C const IID IID_ISOSDacInterface3;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("B08C5CDC-FD8A-49C5-AB38-5FEEF35235B4")
+ ISOSDacInterface3 : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetGCInterestingInfoData(
+ CLRDATA_ADDRESS interestingInfoAddr,
+ struct DacpGCInterestingInfoData *data) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetGCInterestingInfoStaticData(
+ struct DacpGCInterestingInfoData *data) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetGCGlobalMechanisms(
+ size_t *globalMechanisms) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ISOSDacInterface3Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ISOSDacInterface3 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ISOSDacInterface3 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ISOSDacInterface3 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetGCInterestingInfoData )(
+ ISOSDacInterface3 * This,
+ CLRDATA_ADDRESS interestingInfoAddr,
+ struct DacpGCInterestingInfoData *data);
+
+ HRESULT ( STDMETHODCALLTYPE *GetGCInterestingInfoStaticData )(
+ ISOSDacInterface3 * This,
+ struct DacpGCInterestingInfoData *data);
+
+ HRESULT ( STDMETHODCALLTYPE *GetGCGlobalMechanisms )(
+ ISOSDacInterface3 * This,
+ size_t *globalMechanisms);
+
+ END_INTERFACE
+ } ISOSDacInterface3Vtbl;
+
+ interface ISOSDacInterface3
+ {
+ CONST_VTBL struct ISOSDacInterface3Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ISOSDacInterface3_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ISOSDacInterface3_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ISOSDacInterface3_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ISOSDacInterface3_GetGCInterestingInfoData(This,interestingInfoAddr,data) \
+ ( (This)->lpVtbl -> GetGCInterestingInfoData(This,interestingInfoAddr,data) )
+
+#define ISOSDacInterface3_GetGCInterestingInfoStaticData(This,data) \
+ ( (This)->lpVtbl -> GetGCInterestingInfoStaticData(This,data) )
+
+#define ISOSDacInterface3_GetGCGlobalMechanisms(This,globalMechanisms) \
+ ( (This)->lpVtbl -> GetGCGlobalMechanisms(This,globalMechanisms) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ISOSDacInterface3_INTERFACE_DEFINED__ */
+
+
+#ifndef __ISOSDacInterface4_INTERFACE_DEFINED__
+#define __ISOSDacInterface4_INTERFACE_DEFINED__
+
+/* interface ISOSDacInterface4 */
+/* [uuid][local][object] */
+
+
+EXTERN_C const IID IID_ISOSDacInterface4;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("74B9D34C-A612-4B07-93DD-5462178FCE11")
+ ISOSDacInterface4 : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetClrNotification(
+ CLRDATA_ADDRESS arguments[ ],
+ int count,
+ int *pNeeded) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ISOSDacInterface4Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ISOSDacInterface4 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ISOSDacInterface4 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ISOSDacInterface4 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetClrNotification )(
+ ISOSDacInterface4 * This,
+ CLRDATA_ADDRESS arguments[ ],
+ int count,
+ int *pNeeded);
+
+ END_INTERFACE
+ } ISOSDacInterface4Vtbl;
+
+ interface ISOSDacInterface4
+ {
+ CONST_VTBL struct ISOSDacInterface4Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ISOSDacInterface4_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ISOSDacInterface4_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ISOSDacInterface4_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ISOSDacInterface4_GetClrNotification(This,arguments,count,pNeeded) \
+ ( (This)->lpVtbl -> GetClrNotification(This,arguments,count,pNeeded) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ISOSDacInterface4_INTERFACE_DEFINED__ */
+
+
+/* Additional Prototypes for ALL interfaces */
+
+/* end of Additional Prototypes */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+
diff --git a/src/pal/prebuilt/inc/version.h b/src/pal/prebuilt/inc/version.h
new file mode 100644
index 0000000000..a6de92ca95
--- /dev/null
+++ b/src/pal/prebuilt/inc/version.h
@@ -0,0 +1,17 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#include <ndpversion_generated.h>
+
+#define rmj NDPVersionNumberMajor
+#define rmm NDPVersionNumberMinor
+#define rup NDPBuildNumberMajor
+#define rpt NDPBuildNumberMinor
+
+#define fvn NDPFileVersionMinor
+#define fvb NDPFileVersionBuild
+#define fvr NDPFileVersionRevision
+
+#define szVerName ""
+#define szVerUser ""
diff --git a/src/pal/prebuilt/inc/xclrdata.h b/src/pal/prebuilt/inc/xclrdata.h
new file mode 100644
index 0000000000..3f46c31319
--- /dev/null
+++ b/src/pal/prebuilt/inc/xclrdata.h
@@ -0,0 +1,7730 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+
+
+/* this ALWAYS GENERATED file contains the definitions for the interfaces */
+
+
+ /* File created by MIDL compiler version 8.00.0603 */
+/* @@MIDL_FILE_HEADING( ) */
+
+#pragma warning( disable: 4049 ) /* more than 64k source lines */
+
+
+/* verify that the <rpcndr.h> version is high enough to compile this file*/
+#ifndef __REQUIRED_RPCNDR_H_VERSION__
+#define __REQUIRED_RPCNDR_H_VERSION__ 475
+#endif
+
+#include "rpc.h"
+#include "rpcndr.h"
+
+#ifndef __RPCNDR_H_VERSION__
+#error this stub requires an updated version of <rpcndr.h>
+#endif // __RPCNDR_H_VERSION__
+
+#ifndef COM_NO_WINDOWS_H
+#include "windows.h"
+#include "ole2.h"
+#endif /*COM_NO_WINDOWS_H*/
+
+#ifndef __xclrdata_h__
+#define __xclrdata_h__
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+/* Forward Declarations */
+
+#ifndef __IXCLRDataTarget3_FWD_DEFINED__
+#define __IXCLRDataTarget3_FWD_DEFINED__
+typedef interface IXCLRDataTarget3 IXCLRDataTarget3;
+
+#endif /* __IXCLRDataTarget3_FWD_DEFINED__ */
+
+
+#ifndef __IXCLRLibrarySupport_FWD_DEFINED__
+#define __IXCLRLibrarySupport_FWD_DEFINED__
+typedef interface IXCLRLibrarySupport IXCLRLibrarySupport;
+
+#endif /* __IXCLRLibrarySupport_FWD_DEFINED__ */
+
+
+#ifndef __IXCLRDisassemblySupport_FWD_DEFINED__
+#define __IXCLRDisassemblySupport_FWD_DEFINED__
+typedef interface IXCLRDisassemblySupport IXCLRDisassemblySupport;
+
+#endif /* __IXCLRDisassemblySupport_FWD_DEFINED__ */
+
+
+#ifndef __IXCLRDataDisplay_FWD_DEFINED__
+#define __IXCLRDataDisplay_FWD_DEFINED__
+typedef interface IXCLRDataDisplay IXCLRDataDisplay;
+
+#endif /* __IXCLRDataDisplay_FWD_DEFINED__ */
+
+
+#ifndef __IXCLRDataProcess_FWD_DEFINED__
+#define __IXCLRDataProcess_FWD_DEFINED__
+typedef interface IXCLRDataProcess IXCLRDataProcess;
+
+#endif /* __IXCLRDataProcess_FWD_DEFINED__ */
+
+
+#ifndef __IXCLRDataProcess2_FWD_DEFINED__
+#define __IXCLRDataProcess2_FWD_DEFINED__
+typedef interface IXCLRDataProcess2 IXCLRDataProcess2;
+
+#endif /* __IXCLRDataProcess2_FWD_DEFINED__ */
+
+
+#ifndef __IXCLRDataAppDomain_FWD_DEFINED__
+#define __IXCLRDataAppDomain_FWD_DEFINED__
+typedef interface IXCLRDataAppDomain IXCLRDataAppDomain;
+
+#endif /* __IXCLRDataAppDomain_FWD_DEFINED__ */
+
+
+#ifndef __IXCLRDataAssembly_FWD_DEFINED__
+#define __IXCLRDataAssembly_FWD_DEFINED__
+typedef interface IXCLRDataAssembly IXCLRDataAssembly;
+
+#endif /* __IXCLRDataAssembly_FWD_DEFINED__ */
+
+
+#ifndef __IXCLRDataModule_FWD_DEFINED__
+#define __IXCLRDataModule_FWD_DEFINED__
+typedef interface IXCLRDataModule IXCLRDataModule;
+
+#endif /* __IXCLRDataModule_FWD_DEFINED__ */
+
+
+#ifndef __IXCLRDataModule2_FWD_DEFINED__
+#define __IXCLRDataModule2_FWD_DEFINED__
+typedef interface IXCLRDataModule2 IXCLRDataModule2;
+
+#endif /* __IXCLRDataModule2_FWD_DEFINED__ */
+
+
+#ifndef __IXCLRDataTypeDefinition_FWD_DEFINED__
+#define __IXCLRDataTypeDefinition_FWD_DEFINED__
+typedef interface IXCLRDataTypeDefinition IXCLRDataTypeDefinition;
+
+#endif /* __IXCLRDataTypeDefinition_FWD_DEFINED__ */
+
+
+#ifndef __IXCLRDataTypeInstance_FWD_DEFINED__
+#define __IXCLRDataTypeInstance_FWD_DEFINED__
+typedef interface IXCLRDataTypeInstance IXCLRDataTypeInstance;
+
+#endif /* __IXCLRDataTypeInstance_FWD_DEFINED__ */
+
+
+#ifndef __IXCLRDataMethodDefinition_FWD_DEFINED__
+#define __IXCLRDataMethodDefinition_FWD_DEFINED__
+typedef interface IXCLRDataMethodDefinition IXCLRDataMethodDefinition;
+
+#endif /* __IXCLRDataMethodDefinition_FWD_DEFINED__ */
+
+
+#ifndef __IXCLRDataMethodInstance_FWD_DEFINED__
+#define __IXCLRDataMethodInstance_FWD_DEFINED__
+typedef interface IXCLRDataMethodInstance IXCLRDataMethodInstance;
+
+#endif /* __IXCLRDataMethodInstance_FWD_DEFINED__ */
+
+
+#ifndef __IXCLRDataTask_FWD_DEFINED__
+#define __IXCLRDataTask_FWD_DEFINED__
+typedef interface IXCLRDataTask IXCLRDataTask;
+
+#endif /* __IXCLRDataTask_FWD_DEFINED__ */
+
+
+#ifndef __IXCLRDataStackWalk_FWD_DEFINED__
+#define __IXCLRDataStackWalk_FWD_DEFINED__
+typedef interface IXCLRDataStackWalk IXCLRDataStackWalk;
+
+#endif /* __IXCLRDataStackWalk_FWD_DEFINED__ */
+
+
+#ifndef __IXCLRDataFrame_FWD_DEFINED__
+#define __IXCLRDataFrame_FWD_DEFINED__
+typedef interface IXCLRDataFrame IXCLRDataFrame;
+
+#endif /* __IXCLRDataFrame_FWD_DEFINED__ */
+
+
+#ifndef __IXCLRDataFrame2_FWD_DEFINED__
+#define __IXCLRDataFrame2_FWD_DEFINED__
+typedef interface IXCLRDataFrame2 IXCLRDataFrame2;
+
+#endif /* __IXCLRDataFrame2_FWD_DEFINED__ */
+
+
+#ifndef __IXCLRDataExceptionState_FWD_DEFINED__
+#define __IXCLRDataExceptionState_FWD_DEFINED__
+typedef interface IXCLRDataExceptionState IXCLRDataExceptionState;
+
+#endif /* __IXCLRDataExceptionState_FWD_DEFINED__ */
+
+
+#ifndef __IXCLRDataValue_FWD_DEFINED__
+#define __IXCLRDataValue_FWD_DEFINED__
+typedef interface IXCLRDataValue IXCLRDataValue;
+
+#endif /* __IXCLRDataValue_FWD_DEFINED__ */
+
+
+#ifndef __IXCLRDataExceptionNotification_FWD_DEFINED__
+#define __IXCLRDataExceptionNotification_FWD_DEFINED__
+typedef interface IXCLRDataExceptionNotification IXCLRDataExceptionNotification;
+
+#endif /* __IXCLRDataExceptionNotification_FWD_DEFINED__ */
+
+
+#ifndef __IXCLRDataExceptionNotification2_FWD_DEFINED__
+#define __IXCLRDataExceptionNotification2_FWD_DEFINED__
+typedef interface IXCLRDataExceptionNotification2 IXCLRDataExceptionNotification2;
+
+#endif /* __IXCLRDataExceptionNotification2_FWD_DEFINED__ */
+
+
+#ifndef __IXCLRDataExceptionNotification3_FWD_DEFINED__
+#define __IXCLRDataExceptionNotification3_FWD_DEFINED__
+typedef interface IXCLRDataExceptionNotification3 IXCLRDataExceptionNotification3;
+
+#endif /* __IXCLRDataExceptionNotification3_FWD_DEFINED__ */
+
+
+#ifndef __IXCLRDataExceptionNotification4_FWD_DEFINED__
+#define __IXCLRDataExceptionNotification4_FWD_DEFINED__
+typedef interface IXCLRDataExceptionNotification4 IXCLRDataExceptionNotification4;
+
+#endif /* __IXCLRDataExceptionNotification4_FWD_DEFINED__ */
+
+
+/* header files for imported files */
+#include "clrdata.h"
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+
+/* interface __MIDL_itf_xclrdata_0000_0000 */
+/* [local] */
+
+#if 0
+typedef UINT32 mdToken;
+
+typedef mdToken mdTypeDef;
+
+typedef mdToken mdMethodDef;
+
+typedef mdToken mdFieldDef;
+
+typedef ULONG CorElementType;
+
+typedef struct _EXCEPTION_RECORD64
+ {
+ DWORD ExceptionCode;
+ DWORD ExceptionFlags;
+ DWORD64 ExceptionRecord;
+ DWORD64 ExceptionAddress;
+ DWORD NumberParameters;
+ DWORD __unusedAlignment;
+ DWORD64 ExceptionInformation[ 15 ];
+ } EXCEPTION_RECORD64;
+
+typedef struct _EXCEPTION_RECORD64 *PEXCEPTION_RECORD64;
+
+#endif
+#pragma warning(push)
+#pragma warning(disable:28718)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#pragma warning(pop)
+typedef /* [public][public][public] */ struct __MIDL___MIDL_itf_xclrdata_0000_0000_0001
+ {
+ CLRDATA_ADDRESS startAddress;
+ CLRDATA_ADDRESS endAddress;
+ } CLRDATA_ADDRESS_RANGE;
+
+typedef ULONG64 CLRDATA_ENUM;
+
+#define CLRDATA_NOTIFY_EXCEPTION 0xe0444143
+typedef /* [public] */
+enum __MIDL___MIDL_itf_xclrdata_0000_0000_0002
+ {
+ CLRDATA_REQUEST_REVISION = 0xe0000000
+ } CLRDataGeneralRequest;
+
+typedef /* [public] */
+enum __MIDL___MIDL_itf_xclrdata_0000_0000_0003
+ {
+ CLRDATA_TYPE_DEFAULT = 0,
+ CLRDATA_TYPE_IS_PRIMITIVE = 0x1,
+ CLRDATA_TYPE_IS_VALUE_TYPE = 0x2,
+ CLRDATA_TYPE_IS_STRING = 0x4,
+ CLRDATA_TYPE_IS_ARRAY = 0x8,
+ CLRDATA_TYPE_IS_REFERENCE = 0x10,
+ CLRDATA_TYPE_IS_POINTER = 0x20,
+ CLRDATA_TYPE_IS_ENUM = 0x40,
+ CLRDATA_TYPE_ALL_KINDS = 0x7f
+ } CLRDataTypeFlag;
+
+typedef /* [public] */
+enum __MIDL___MIDL_itf_xclrdata_0000_0000_0004
+ {
+ CLRDATA_FIELD_DEFAULT = 0,
+ CLRDATA_FIELD_IS_PRIMITIVE = CLRDATA_TYPE_IS_PRIMITIVE,
+ CLRDATA_FIELD_IS_VALUE_TYPE = CLRDATA_TYPE_IS_VALUE_TYPE,
+ CLRDATA_FIELD_IS_STRING = CLRDATA_TYPE_IS_STRING,
+ CLRDATA_FIELD_IS_ARRAY = CLRDATA_TYPE_IS_ARRAY,
+ CLRDATA_FIELD_IS_REFERENCE = CLRDATA_TYPE_IS_REFERENCE,
+ CLRDATA_FIELD_IS_POINTER = CLRDATA_TYPE_IS_POINTER,
+ CLRDATA_FIELD_IS_ENUM = CLRDATA_TYPE_IS_ENUM,
+ CLRDATA_FIELD_ALL_KINDS = CLRDATA_TYPE_ALL_KINDS,
+ CLRDATA_FIELD_IS_INHERITED = 0x80,
+ CLRDATA_FIELD_IS_LITERAL = 0x100,
+ CLRDATA_FIELD_FROM_INSTANCE = 0x200,
+ CLRDATA_FIELD_FROM_TASK_LOCAL = 0x400,
+ CLRDATA_FIELD_FROM_STATIC = 0x800,
+ CLRDATA_FIELD_ALL_LOCATIONS = 0xe00,
+ CLRDATA_FIELD_ALL_FIELDS = 0xeff
+ } CLRDataFieldFlag;
+
+typedef /* [public] */
+enum __MIDL___MIDL_itf_xclrdata_0000_0000_0005
+ {
+ CLRDATA_VALUE_DEFAULT = 0,
+ CLRDATA_VALUE_IS_PRIMITIVE = CLRDATA_TYPE_IS_PRIMITIVE,
+ CLRDATA_VALUE_IS_VALUE_TYPE = CLRDATA_TYPE_IS_VALUE_TYPE,
+ CLRDATA_VALUE_IS_STRING = CLRDATA_TYPE_IS_STRING,
+ CLRDATA_VALUE_IS_ARRAY = CLRDATA_TYPE_IS_ARRAY,
+ CLRDATA_VALUE_IS_REFERENCE = CLRDATA_TYPE_IS_REFERENCE,
+ CLRDATA_VALUE_IS_POINTER = CLRDATA_TYPE_IS_POINTER,
+ CLRDATA_VALUE_IS_ENUM = CLRDATA_TYPE_IS_ENUM,
+ CLRDATA_VALUE_ALL_KINDS = CLRDATA_TYPE_ALL_KINDS,
+ CLRDATA_VALUE_IS_INHERITED = CLRDATA_FIELD_IS_INHERITED,
+ CLRDATA_VALUE_IS_LITERAL = CLRDATA_FIELD_IS_LITERAL,
+ CLRDATA_VALUE_FROM_INSTANCE = CLRDATA_FIELD_FROM_INSTANCE,
+ CLRDATA_VALUE_FROM_TASK_LOCAL = CLRDATA_FIELD_FROM_TASK_LOCAL,
+ CLRDATA_VALUE_FROM_STATIC = CLRDATA_FIELD_FROM_STATIC,
+ CLRDATA_VALUE_ALL_LOCATIONS = CLRDATA_FIELD_ALL_LOCATIONS,
+ CLRDATA_VALUE_ALL_FIELDS = CLRDATA_FIELD_ALL_FIELDS,
+ CLRDATA_VALUE_IS_BOXED = 0x1000
+ } CLRDataValueFlag;
+
+
+
+extern RPC_IF_HANDLE __MIDL_itf_xclrdata_0000_0000_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_xclrdata_0000_0000_v0_0_s_ifspec;
+
+#ifndef __IXCLRDataTarget3_INTERFACE_DEFINED__
+#define __IXCLRDataTarget3_INTERFACE_DEFINED__
+
+/* interface IXCLRDataTarget3 */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_IXCLRDataTarget3;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("59d9b5e1-4a6f-4531-84c3-51d12da22fd4")
+ IXCLRDataTarget3 : public ICLRDataTarget2
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetMetaData(
+ /* [in] */ LPCWSTR imagePath,
+ /* [in] */ ULONG32 imageTimestamp,
+ /* [in] */ ULONG32 imageSize,
+ /* [in] */ GUID *mvid,
+ /* [in] */ ULONG32 mdRva,
+ /* [in] */ ULONG32 flags,
+ /* [in] */ ULONG32 bufferSize,
+ /* [length_is][size_is][out] */ BYTE *buffer,
+ /* [out] */ ULONG32 *dataSize) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IXCLRDataTarget3Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IXCLRDataTarget3 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IXCLRDataTarget3 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IXCLRDataTarget3 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetMachineType )(
+ IXCLRDataTarget3 * This,
+ /* [out] */ ULONG32 *machineType);
+
+ HRESULT ( STDMETHODCALLTYPE *GetPointerSize )(
+ IXCLRDataTarget3 * This,
+ /* [out] */ ULONG32 *pointerSize);
+
+ HRESULT ( STDMETHODCALLTYPE *GetImageBase )(
+ IXCLRDataTarget3 * This,
+ /* [string][in] */ LPCWSTR imagePath,
+ /* [out] */ CLRDATA_ADDRESS *baseAddress);
+
+ HRESULT ( STDMETHODCALLTYPE *ReadVirtual )(
+ IXCLRDataTarget3 * This,
+ /* [in] */ CLRDATA_ADDRESS address,
+ /* [length_is][size_is][out] */ BYTE *buffer,
+ /* [in] */ ULONG32 bytesRequested,
+ /* [out] */ ULONG32 *bytesRead);
+
+ HRESULT ( STDMETHODCALLTYPE *WriteVirtual )(
+ IXCLRDataTarget3 * This,
+ /* [in] */ CLRDATA_ADDRESS address,
+ /* [size_is][in] */ BYTE *buffer,
+ /* [in] */ ULONG32 bytesRequested,
+ /* [out] */ ULONG32 *bytesWritten);
+
+ HRESULT ( STDMETHODCALLTYPE *GetTLSValue )(
+ IXCLRDataTarget3 * This,
+ /* [in] */ ULONG32 threadID,
+ /* [in] */ ULONG32 index,
+ /* [out] */ CLRDATA_ADDRESS *value);
+
+ HRESULT ( STDMETHODCALLTYPE *SetTLSValue )(
+ IXCLRDataTarget3 * This,
+ /* [in] */ ULONG32 threadID,
+ /* [in] */ ULONG32 index,
+ /* [in] */ CLRDATA_ADDRESS value);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCurrentThreadID )(
+ IXCLRDataTarget3 * This,
+ /* [out] */ ULONG32 *threadID);
+
+ HRESULT ( STDMETHODCALLTYPE *GetThreadContext )(
+ IXCLRDataTarget3 * This,
+ /* [in] */ ULONG32 threadID,
+ /* [in] */ ULONG32 contextFlags,
+ /* [in] */ ULONG32 contextSize,
+ /* [size_is][out] */ BYTE *context);
+
+ HRESULT ( STDMETHODCALLTYPE *SetThreadContext )(
+ IXCLRDataTarget3 * This,
+ /* [in] */ ULONG32 threadID,
+ /* [in] */ ULONG32 contextSize,
+ /* [size_is][in] */ BYTE *context);
+
+ HRESULT ( STDMETHODCALLTYPE *Request )(
+ IXCLRDataTarget3 * This,
+ /* [in] */ ULONG32 reqCode,
+ /* [in] */ ULONG32 inBufferSize,
+ /* [size_is][in] */ BYTE *inBuffer,
+ /* [in] */ ULONG32 outBufferSize,
+ /* [size_is][out] */ BYTE *outBuffer);
+
+ HRESULT ( STDMETHODCALLTYPE *AllocVirtual )(
+ IXCLRDataTarget3 * This,
+ /* [in] */ CLRDATA_ADDRESS addr,
+ /* [in] */ ULONG32 size,
+ /* [in] */ ULONG32 typeFlags,
+ /* [in] */ ULONG32 protectFlags,
+ /* [out] */ CLRDATA_ADDRESS *virt);
+
+ HRESULT ( STDMETHODCALLTYPE *FreeVirtual )(
+ IXCLRDataTarget3 * This,
+ /* [in] */ CLRDATA_ADDRESS addr,
+ /* [in] */ ULONG32 size,
+ /* [in] */ ULONG32 typeFlags);
+
+ HRESULT ( STDMETHODCALLTYPE *GetMetaData )(
+ IXCLRDataTarget3 * This,
+ /* [in] */ LPCWSTR imagePath,
+ /* [in] */ ULONG32 imageTimestamp,
+ /* [in] */ ULONG32 imageSize,
+ /* [in] */ GUID *mvid,
+ /* [in] */ ULONG32 mdRva,
+ /* [in] */ ULONG32 flags,
+ /* [in] */ ULONG32 bufferSize,
+ /* [length_is][size_is][out] */ BYTE *buffer,
+ /* [out] */ ULONG32 *dataSize);
+
+ END_INTERFACE
+ } IXCLRDataTarget3Vtbl;
+
+ interface IXCLRDataTarget3
+ {
+ CONST_VTBL struct IXCLRDataTarget3Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IXCLRDataTarget3_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IXCLRDataTarget3_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IXCLRDataTarget3_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IXCLRDataTarget3_GetMachineType(This,machineType) \
+ ( (This)->lpVtbl -> GetMachineType(This,machineType) )
+
+#define IXCLRDataTarget3_GetPointerSize(This,pointerSize) \
+ ( (This)->lpVtbl -> GetPointerSize(This,pointerSize) )
+
+#define IXCLRDataTarget3_GetImageBase(This,imagePath,baseAddress) \
+ ( (This)->lpVtbl -> GetImageBase(This,imagePath,baseAddress) )
+
+#define IXCLRDataTarget3_ReadVirtual(This,address,buffer,bytesRequested,bytesRead) \
+ ( (This)->lpVtbl -> ReadVirtual(This,address,buffer,bytesRequested,bytesRead) )
+
+#define IXCLRDataTarget3_WriteVirtual(This,address,buffer,bytesRequested,bytesWritten) \
+ ( (This)->lpVtbl -> WriteVirtual(This,address,buffer,bytesRequested,bytesWritten) )
+
+#define IXCLRDataTarget3_GetTLSValue(This,threadID,index,value) \
+ ( (This)->lpVtbl -> GetTLSValue(This,threadID,index,value) )
+
+#define IXCLRDataTarget3_SetTLSValue(This,threadID,index,value) \
+ ( (This)->lpVtbl -> SetTLSValue(This,threadID,index,value) )
+
+#define IXCLRDataTarget3_GetCurrentThreadID(This,threadID) \
+ ( (This)->lpVtbl -> GetCurrentThreadID(This,threadID) )
+
+#define IXCLRDataTarget3_GetThreadContext(This,threadID,contextFlags,contextSize,context) \
+ ( (This)->lpVtbl -> GetThreadContext(This,threadID,contextFlags,contextSize,context) )
+
+#define IXCLRDataTarget3_SetThreadContext(This,threadID,contextSize,context) \
+ ( (This)->lpVtbl -> SetThreadContext(This,threadID,contextSize,context) )
+
+#define IXCLRDataTarget3_Request(This,reqCode,inBufferSize,inBuffer,outBufferSize,outBuffer) \
+ ( (This)->lpVtbl -> Request(This,reqCode,inBufferSize,inBuffer,outBufferSize,outBuffer) )
+
+
+#define IXCLRDataTarget3_AllocVirtual(This,addr,size,typeFlags,protectFlags,virt) \
+ ( (This)->lpVtbl -> AllocVirtual(This,addr,size,typeFlags,protectFlags,virt) )
+
+#define IXCLRDataTarget3_FreeVirtual(This,addr,size,typeFlags) \
+ ( (This)->lpVtbl -> FreeVirtual(This,addr,size,typeFlags) )
+
+
+#define IXCLRDataTarget3_GetMetaData(This,imagePath,imageTimestamp,imageSize,mvid,mdRva,flags,bufferSize,buffer,dataSize) \
+ ( (This)->lpVtbl -> GetMetaData(This,imagePath,imageTimestamp,imageSize,mvid,mdRva,flags,bufferSize,buffer,dataSize) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IXCLRDataTarget3_INTERFACE_DEFINED__ */
+
+
+/* interface __MIDL_itf_xclrdata_0000_0001 */
+/* [local] */
+
+typedef /* [public] */
+enum __MIDL___MIDL_itf_xclrdata_0000_0001_0001
+ {
+ CLRDATA_BYNAME_CASE_SENSITIVE = 0,
+ CLRDATA_BYNAME_CASE_INSENSITIVE = 0x1
+ } CLRDataByNameFlag;
+
+typedef /* [public] */
+enum __MIDL___MIDL_itf_xclrdata_0000_0001_0002
+ {
+ CLRDATA_GETNAME_DEFAULT = 0,
+ CLRDATA_GETNAME_NO_NAMESPACES = 0x1,
+ CLRDATA_GETNAME_NO_PARAMETERS = 0x2
+ } CLRDataGetNameFlag;
+
+typedef /* [public] */
+enum __MIDL___MIDL_itf_xclrdata_0000_0001_0003
+ {
+ CLRDATA_PROCESS_DEFAULT = 0,
+ CLRDATA_PROCESS_IN_GC = 0x1
+ } CLRDataProcessFlag;
+
+typedef /* [public][public] */
+enum __MIDL___MIDL_itf_xclrdata_0000_0001_0004
+ {
+ CLRDATA_ADDRESS_UNRECOGNIZED = 0,
+ CLRDATA_ADDRESS_MANAGED_METHOD = ( CLRDATA_ADDRESS_UNRECOGNIZED + 1 ) ,
+ CLRDATA_ADDRESS_RUNTIME_MANAGED_CODE = ( CLRDATA_ADDRESS_MANAGED_METHOD + 1 ) ,
+ CLRDATA_ADDRESS_RUNTIME_UNMANAGED_CODE = ( CLRDATA_ADDRESS_RUNTIME_MANAGED_CODE + 1 ) ,
+ CLRDATA_ADDRESS_GC_DATA = ( CLRDATA_ADDRESS_RUNTIME_UNMANAGED_CODE + 1 ) ,
+ CLRDATA_ADDRESS_RUNTIME_MANAGED_STUB = ( CLRDATA_ADDRESS_GC_DATA + 1 ) ,
+ CLRDATA_ADDRESS_RUNTIME_UNMANAGED_STUB = ( CLRDATA_ADDRESS_RUNTIME_MANAGED_STUB + 1 )
+ } CLRDataAddressType;
+
+typedef /* [public] */
+enum __MIDL___MIDL_itf_xclrdata_0000_0001_0005
+ {
+ CLRDATA_NOTIFY_ON_MODULE_LOAD = 0x1,
+ CLRDATA_NOTIFY_ON_MODULE_UNLOAD = 0x2,
+ CLRDATA_NOTIFY_ON_EXCEPTION = 0x4,
+ CLRDATA_NOTIFY_ON_EXCEPTION_CATCH_ENTER = 0x8
+ } CLRDataOtherNotifyFlag;
+
+typedef /* [public][public][public][public][public] */ struct __MIDL___MIDL_itf_xclrdata_0000_0001_0006
+ {
+ ULONG64 Data[ 8 ];
+ } CLRDATA_FOLLOW_STUB_BUFFER;
+
+typedef /* [public] */
+enum __MIDL___MIDL_itf_xclrdata_0000_0001_0007
+ {
+ CLRDATA_FOLLOW_STUB_DEFAULT = 0
+ } CLRDataFollowStubInFlag;
+
+typedef /* [public] */
+enum __MIDL___MIDL_itf_xclrdata_0000_0001_0008
+ {
+ CLRDATA_FOLLOW_STUB_INTERMEDIATE = 0,
+ CLRDATA_FOLLOW_STUB_EXIT = 0x1
+ } CLRDataFollowStubOutFlag;
+
+typedef /* [public][public] */
+enum __MIDL___MIDL_itf_xclrdata_0000_0001_0009
+ {
+ CLRNATIVEIMAGE_PE_INFO = 0x1,
+ CLRNATIVEIMAGE_COR_INFO = 0x2,
+ CLRNATIVEIMAGE_FIXUP_TABLES = 0x4,
+ CLRNATIVEIMAGE_FIXUP_HISTOGRAM = 0x8,
+ CLRNATIVEIMAGE_MODULE = 0x10,
+ CLRNATIVEIMAGE_METHODS = 0x20,
+ CLRNATIVEIMAGE_DISASSEMBLE_CODE = 0x40,
+ CLRNATIVEIMAGE_IL = 0x80,
+ CLRNATIVEIMAGE_METHODTABLES = 0x100,
+ CLRNATIVEIMAGE_NATIVE_INFO = 0x200,
+ CLRNATIVEIMAGE_MODULE_TABLES = 0x400,
+ CLRNATIVEIMAGE_FROZEN_SEGMENT = 0x800,
+ CLRNATIVEIMAGE_PE_FILE = 0x1000,
+ CLRNATIVEIMAGE_GC_INFO = 0x2000,
+ CLRNATIVEIMAGE_EECLASSES = 0x4000,
+ CLRNATIVEIMAGE_NATIVE_TABLES = 0x8000,
+ CLRNATIVEIMAGE_PRECODES = 0x10000,
+ CLRNATIVEIMAGE_TYPEDESCS = 0x20000,
+ CLRNATIVEIMAGE_VERBOSE_TYPES = 0x40000,
+ CLRNATIVEIMAGE_METHODDESCS = 0x80000,
+ CLRNATIVEIMAGE_METADATA = 0x100000,
+ CLRNATIVEIMAGE_DISABLE_NAMES = 0x200000,
+ CLRNATIVEIMAGE_DISABLE_REBASING = 0x400000,
+ CLRNATIVEIMAGE_SLIM_MODULE_TBLS = 0x800000,
+ CLRNATIVEIMAGE_RESOURCES = 0x1000000,
+ CLRNATIVEIMAGE_FILE_OFFSET = 0x2000000,
+ CLRNATIVEIMAGE_DEBUG_TRACE = 0x4000000,
+ CLRNATIVEIMAGE_RELOCATIONS = 0x8000000,
+ CLRNATIVEIMAGE_FIXUP_THUNKS = 0x10000000,
+ CLRNATIVEIMAGE_DEBUG_COVERAGE = 0x80000000
+ } CLRNativeImageDumpOptions;
+
+#ifdef __cplusplus
+inline CLRNativeImageDumpOptions operator|=(CLRNativeImageDumpOptions& lhs, CLRNativeImageDumpOptions rhs) { return (lhs = (CLRNativeImageDumpOptions)( ((unsigned)lhs) | ((unsigned)rhs) )); }
+#endif
+typedef /* [public] */
+enum __MIDL___MIDL_itf_xclrdata_0000_0001_0010
+ {
+ CLRDATAHINT_DISPLAY_HINTS_NONE = 0,
+ CLRDATAHINT_DISPLAY_ARRAY_AS_TABLE = 0x1,
+ CLRDATAHINT_DISPLAY_ARRAY_AS_ARRAY = 0x2,
+ CLRDATAHINT_DISPLAY_ARRAY_AS_ARRAY_IDX = 0x3,
+ CLRDATAHINT_DISPLAY_ARRAY_AS_MAP = 0x4,
+ CLRDATAHINT_DISPLAY_ARRAY_HINT_MASK = 0xff,
+ CLRDATAHINT_DISPLAY_STRUCT_AS_TABLE = 0x100,
+ CLRDATAHINT_DISPLAY_STRUCT_HINT_MASK = 0xff00,
+ CLRDATAHINT_DISPLAY_SEP_TAB = 0,
+ CLRDATAHINT_DISPLAY_SEP_SPACE = 0x1000000,
+ CLRDATAHINT_DISPLAY_SEP_TAB_SPACE = 0x2000000,
+ CLRDATAHINT_DISPLAY_SEP_MASK = 0xff000000
+ } CLRDataDisplayHints;
+
+#pragma warning(push)
+#pragma warning(disable:28718)
+
+
+extern RPC_IF_HANDLE __MIDL_itf_xclrdata_0000_0001_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_xclrdata_0000_0001_v0_0_s_ifspec;
+
+#ifndef __IXCLRLibrarySupport_INTERFACE_DEFINED__
+#define __IXCLRLibrarySupport_INTERFACE_DEFINED__
+
+/* interface IXCLRLibrarySupport */
+/* [uuid][local][object] */
+
+
+EXTERN_C const IID IID_IXCLRLibrarySupport;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("E5F3039D-2C0C-4230-A69E-12AF1C3E563C")
+ IXCLRLibrarySupport : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE LoadHardboundDependency(
+ const WCHAR *name,
+ REFGUID mvid,
+ /* [out] */ SIZE_T *loadedBase) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE LoadSoftboundDependency(
+ const WCHAR *name,
+ const BYTE *assemblymetadataBinding,
+ const BYTE *hash,
+ ULONG hashLength,
+ /* [out] */ SIZE_T *loadedBase) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IXCLRLibrarySupportVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IXCLRLibrarySupport * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IXCLRLibrarySupport * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IXCLRLibrarySupport * This);
+
+ HRESULT ( STDMETHODCALLTYPE *LoadHardboundDependency )(
+ IXCLRLibrarySupport * This,
+ const WCHAR *name,
+ REFGUID mvid,
+ /* [out] */ SIZE_T *loadedBase);
+
+ HRESULT ( STDMETHODCALLTYPE *LoadSoftboundDependency )(
+ IXCLRLibrarySupport * This,
+ const WCHAR *name,
+ const BYTE *assemblymetadataBinding,
+ const BYTE *hash,
+ ULONG hashLength,
+ /* [out] */ SIZE_T *loadedBase);
+
+ END_INTERFACE
+ } IXCLRLibrarySupportVtbl;
+
+ interface IXCLRLibrarySupport
+ {
+ CONST_VTBL struct IXCLRLibrarySupportVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IXCLRLibrarySupport_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IXCLRLibrarySupport_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IXCLRLibrarySupport_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IXCLRLibrarySupport_LoadHardboundDependency(This,name,mvid,loadedBase) \
+ ( (This)->lpVtbl -> LoadHardboundDependency(This,name,mvid,loadedBase) )
+
+#define IXCLRLibrarySupport_LoadSoftboundDependency(This,name,assemblymetadataBinding,hash,hashLength,loadedBase) \
+ ( (This)->lpVtbl -> LoadSoftboundDependency(This,name,assemblymetadataBinding,hash,hashLength,loadedBase) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IXCLRLibrarySupport_INTERFACE_DEFINED__ */
+
+
+/* interface __MIDL_itf_xclrdata_0000_0002 */
+/* [local] */
+
+
+typedef SIZE_T ( __stdcall *CDSTranslateAddrCB )(
+ IXCLRDisassemblySupport *__MIDL____MIDL_itf_xclrdata_0000_00020000,
+ CLRDATA_ADDRESS __MIDL____MIDL_itf_xclrdata_0000_00020001,
+ wchar_t *__MIDL____MIDL_itf_xclrdata_0000_00020002,
+ SIZE_T __MIDL____MIDL_itf_xclrdata_0000_00020003,
+ DWORDLONG *__MIDL____MIDL_itf_xclrdata_0000_00020004);
+
+typedef SIZE_T ( __stdcall *CDSTranslateFixupCB )(
+ IXCLRDisassemblySupport *__MIDL____MIDL_itf_xclrdata_0000_00020006,
+ CLRDATA_ADDRESS __MIDL____MIDL_itf_xclrdata_0000_00020007,
+ SIZE_T __MIDL____MIDL_itf_xclrdata_0000_00020008,
+ wchar_t *__MIDL____MIDL_itf_xclrdata_0000_00020009,
+ SIZE_T __MIDL____MIDL_itf_xclrdata_0000_00020010,
+ DWORDLONG *__MIDL____MIDL_itf_xclrdata_0000_00020011);
+
+typedef SIZE_T ( __stdcall *CDSTranslateConstCB )(
+ IXCLRDisassemblySupport *__MIDL____MIDL_itf_xclrdata_0000_00020013,
+ DWORD __MIDL____MIDL_itf_xclrdata_0000_00020014,
+ wchar_t *__MIDL____MIDL_itf_xclrdata_0000_00020015,
+ SIZE_T __MIDL____MIDL_itf_xclrdata_0000_00020016);
+
+typedef SIZE_T ( __stdcall *CDSTranslateRegrelCB )(
+ IXCLRDisassemblySupport *__MIDL____MIDL_itf_xclrdata_0000_00020018,
+ unsigned int rega,
+ CLRDATA_ADDRESS __MIDL____MIDL_itf_xclrdata_0000_00020019,
+ wchar_t *__MIDL____MIDL_itf_xclrdata_0000_00020020,
+ SIZE_T __MIDL____MIDL_itf_xclrdata_0000_00020021,
+ DWORD *__MIDL____MIDL_itf_xclrdata_0000_00020022);
+
+
+
+extern RPC_IF_HANDLE __MIDL_itf_xclrdata_0000_0002_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_xclrdata_0000_0002_v0_0_s_ifspec;
+
+#ifndef __IXCLRDisassemblySupport_INTERFACE_DEFINED__
+#define __IXCLRDisassemblySupport_INTERFACE_DEFINED__
+
+/* interface IXCLRDisassemblySupport */
+/* [uuid][local][object] */
+
+
+EXTERN_C const IID IID_IXCLRDisassemblySupport;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("1F0F7134-D3F3-47DE-8E9B-C2FD358A2936")
+ IXCLRDisassemblySupport : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE SetTranslateAddrCallback(
+ /* [in] */ CDSTranslateAddrCB cb) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE PvClientSet(
+ /* [in] */ void *pv) = 0;
+
+ virtual SIZE_T STDMETHODCALLTYPE CbDisassemble(
+ CLRDATA_ADDRESS __MIDL__IXCLRDisassemblySupport0000,
+ const void *__MIDL__IXCLRDisassemblySupport0001,
+ SIZE_T __MIDL__IXCLRDisassemblySupport0002) = 0;
+
+ virtual SIZE_T STDMETHODCALLTYPE Cinstruction( void) = 0;
+
+ virtual BOOL STDMETHODCALLTYPE FSelectInstruction(
+ SIZE_T __MIDL__IXCLRDisassemblySupport0003) = 0;
+
+ virtual SIZE_T STDMETHODCALLTYPE CchFormatInstr(
+ wchar_t *__MIDL__IXCLRDisassemblySupport0004,
+ SIZE_T __MIDL__IXCLRDisassemblySupport0005) = 0;
+
+ virtual void *STDMETHODCALLTYPE PvClient( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetTranslateFixupCallback(
+ /* [in] */ CDSTranslateFixupCB cb) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetTranslateConstCallback(
+ /* [in] */ CDSTranslateConstCB cb) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetTranslateRegrelCallback(
+ /* [in] */ CDSTranslateRegrelCB cb) = 0;
+
+ virtual BOOL STDMETHODCALLTYPE TargetIsAddress( void) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IXCLRDisassemblySupportVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IXCLRDisassemblySupport * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IXCLRDisassemblySupport * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IXCLRDisassemblySupport * This);
+
+ HRESULT ( STDMETHODCALLTYPE *SetTranslateAddrCallback )(
+ IXCLRDisassemblySupport * This,
+ /* [in] */ CDSTranslateAddrCB cb);
+
+ HRESULT ( STDMETHODCALLTYPE *PvClientSet )(
+ IXCLRDisassemblySupport * This,
+ /* [in] */ void *pv);
+
+ SIZE_T ( STDMETHODCALLTYPE *CbDisassemble )(
+ IXCLRDisassemblySupport * This,
+ CLRDATA_ADDRESS __MIDL__IXCLRDisassemblySupport0000,
+ const void *__MIDL__IXCLRDisassemblySupport0001,
+ SIZE_T __MIDL__IXCLRDisassemblySupport0002);
+
+ SIZE_T ( STDMETHODCALLTYPE *Cinstruction )(
+ IXCLRDisassemblySupport * This);
+
+ BOOL ( STDMETHODCALLTYPE *FSelectInstruction )(
+ IXCLRDisassemblySupport * This,
+ SIZE_T __MIDL__IXCLRDisassemblySupport0003);
+
+ SIZE_T ( STDMETHODCALLTYPE *CchFormatInstr )(
+ IXCLRDisassemblySupport * This,
+ wchar_t *__MIDL__IXCLRDisassemblySupport0004,
+ SIZE_T __MIDL__IXCLRDisassemblySupport0005);
+
+ void *( STDMETHODCALLTYPE *PvClient )(
+ IXCLRDisassemblySupport * This);
+
+ HRESULT ( STDMETHODCALLTYPE *SetTranslateFixupCallback )(
+ IXCLRDisassemblySupport * This,
+ /* [in] */ CDSTranslateFixupCB cb);
+
+ HRESULT ( STDMETHODCALLTYPE *SetTranslateConstCallback )(
+ IXCLRDisassemblySupport * This,
+ /* [in] */ CDSTranslateConstCB cb);
+
+ HRESULT ( STDMETHODCALLTYPE *SetTranslateRegrelCallback )(
+ IXCLRDisassemblySupport * This,
+ /* [in] */ CDSTranslateRegrelCB cb);
+
+ BOOL ( STDMETHODCALLTYPE *TargetIsAddress )(
+ IXCLRDisassemblySupport * This);
+
+ END_INTERFACE
+ } IXCLRDisassemblySupportVtbl;
+
+ interface IXCLRDisassemblySupport
+ {
+ CONST_VTBL struct IXCLRDisassemblySupportVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IXCLRDisassemblySupport_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IXCLRDisassemblySupport_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IXCLRDisassemblySupport_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IXCLRDisassemblySupport_SetTranslateAddrCallback(This,cb) \
+ ( (This)->lpVtbl -> SetTranslateAddrCallback(This,cb) )
+
+#define IXCLRDisassemblySupport_PvClientSet(This,pv) \
+ ( (This)->lpVtbl -> PvClientSet(This,pv) )
+
+#define IXCLRDisassemblySupport_CbDisassemble(This,__MIDL__IXCLRDisassemblySupport0000,__MIDL__IXCLRDisassemblySupport0001,__MIDL__IXCLRDisassemblySupport0002) \
+ ( (This)->lpVtbl -> CbDisassemble(This,__MIDL__IXCLRDisassemblySupport0000,__MIDL__IXCLRDisassemblySupport0001,__MIDL__IXCLRDisassemblySupport0002) )
+
+#define IXCLRDisassemblySupport_Cinstruction(This) \
+ ( (This)->lpVtbl -> Cinstruction(This) )
+
+#define IXCLRDisassemblySupport_FSelectInstruction(This,__MIDL__IXCLRDisassemblySupport0003) \
+ ( (This)->lpVtbl -> FSelectInstruction(This,__MIDL__IXCLRDisassemblySupport0003) )
+
+#define IXCLRDisassemblySupport_CchFormatInstr(This,__MIDL__IXCLRDisassemblySupport0004,__MIDL__IXCLRDisassemblySupport0005) \
+ ( (This)->lpVtbl -> CchFormatInstr(This,__MIDL__IXCLRDisassemblySupport0004,__MIDL__IXCLRDisassemblySupport0005) )
+
+#define IXCLRDisassemblySupport_PvClient(This) \
+ ( (This)->lpVtbl -> PvClient(This) )
+
+#define IXCLRDisassemblySupport_SetTranslateFixupCallback(This,cb) \
+ ( (This)->lpVtbl -> SetTranslateFixupCallback(This,cb) )
+
+#define IXCLRDisassemblySupport_SetTranslateConstCallback(This,cb) \
+ ( (This)->lpVtbl -> SetTranslateConstCallback(This,cb) )
+
+#define IXCLRDisassemblySupport_SetTranslateRegrelCallback(This,cb) \
+ ( (This)->lpVtbl -> SetTranslateRegrelCallback(This,cb) )
+
+#define IXCLRDisassemblySupport_TargetIsAddress(This) \
+ ( (This)->lpVtbl -> TargetIsAddress(This) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IXCLRDisassemblySupport_INTERFACE_DEFINED__ */
+
+
+#ifndef __IXCLRDataDisplay_INTERFACE_DEFINED__
+#define __IXCLRDataDisplay_INTERFACE_DEFINED__
+
+/* interface IXCLRDataDisplay */
+/* [uuid][local][object] */
+
+
+EXTERN_C const IID IID_IXCLRDataDisplay;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("A3C1704A-4559-4a67-8D28-E8F4FE3B3F62")
+ IXCLRDataDisplay : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE ErrorPrintF(
+ const char *const fmt,
+ ...) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE NativeImageDimensions(
+ SIZE_T base,
+ SIZE_T size,
+ DWORD sectionAlign) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Section(
+ const char *const name,
+ SIZE_T rva,
+ SIZE_T size) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetDumpOptions(
+ /* [out] */ CLRNativeImageDumpOptions *pOptions) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StartDocument( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EndDocument( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StartCategory(
+ const char *const name) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EndCategory( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StartElement(
+ const char *const name) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EndElement( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StartVStructure(
+ const char *const name) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StartVStructureWithOffset(
+ const char *const name,
+ unsigned int fieldOffset,
+ unsigned int fieldSize) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EndVStructure( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StartTextElement(
+ const char *const name) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EndTextElement( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE WriteXmlText(
+ const char *const fmt,
+ ...) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE WriteXmlTextBlock(
+ const char *const fmt,
+ ...) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE WriteEmptyElement(
+ const char *const element) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE WriteElementPointer(
+ const char *const element,
+ SIZE_T ptr) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE WriteElementPointerAnnotated(
+ const char *const element,
+ SIZE_T ptr,
+ const WCHAR *const annotation) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE WriteElementAddress(
+ const char *const element,
+ SIZE_T base,
+ SIZE_T size) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE WriteElementAddressNamed(
+ const char *const element,
+ const char *const name,
+ SIZE_T base,
+ SIZE_T size) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE WriteElementAddressNamedW(
+ const char *const element,
+ const WCHAR *const name,
+ SIZE_T base,
+ SIZE_T size) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE WriteElementString(
+ const char *const element,
+ const char *const data) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE WriteElementStringW(
+ const char *const element,
+ const WCHAR *const data) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE WriteElementInt(
+ const char *const element,
+ int value) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE WriteElementUInt(
+ const char *const element,
+ DWORD value) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE WriteElementEnumerated(
+ const char *const element,
+ DWORD value,
+ const WCHAR *const mnemonic) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE WriteElementIntWithSuppress(
+ const char *const element,
+ int value,
+ int suppressIfEqual) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE WriteElementFlag(
+ const char *const element,
+ BOOL flag) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StartArray(
+ const char *const name,
+ const WCHAR *const fmt) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EndArray(
+ const char *const countPrefix) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StartList(
+ const WCHAR *const fmt) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EndList( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StartArrayWithOffset(
+ const char *const name,
+ unsigned int fieldOffset,
+ unsigned int fieldSize,
+ const WCHAR *const fmt) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE WriteFieldString(
+ const char *const element,
+ unsigned int fieldOffset,
+ unsigned int fieldSize,
+ const char *const data) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE WriteFieldStringW(
+ const char *const element,
+ unsigned int fieldOffset,
+ unsigned int fieldSize,
+ const WCHAR *const data) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE WriteFieldPointer(
+ const char *const element,
+ unsigned int fieldOffset,
+ unsigned int fieldSize,
+ SIZE_T ptr) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE WriteFieldPointerWithSize(
+ const char *const element,
+ unsigned int fieldOffset,
+ unsigned int fieldSize,
+ SIZE_T ptr,
+ SIZE_T size) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE WriteFieldInt(
+ const char *const element,
+ unsigned int fieldOffset,
+ unsigned int fieldSize,
+ int value) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE WriteFieldUInt(
+ const char *const element,
+ unsigned int fieldOffset,
+ unsigned int fieldSize,
+ DWORD value) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE WriteFieldEnumerated(
+ const char *const element,
+ unsigned int fieldOffset,
+ unsigned int fieldSize,
+ DWORD value,
+ const WCHAR *const mnemonic) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE WriteFieldEmpty(
+ const char *const element,
+ unsigned int fieldOffset,
+ unsigned int fieldSize) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE WriteFieldFlag(
+ const char *const element,
+ unsigned int fieldOffset,
+ unsigned int fieldSize,
+ BOOL flag) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE WriteFieldPointerAnnotated(
+ const char *const element,
+ unsigned int fieldOffset,
+ unsigned int fieldSize,
+ SIZE_T ptr,
+ const WCHAR *const annotation) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE WriteFieldAddress(
+ const char *const element,
+ unsigned int fieldOffset,
+ unsigned int fieldSize,
+ SIZE_T base,
+ SIZE_T size) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StartStructure(
+ const char *const name,
+ SIZE_T ptr,
+ SIZE_T size) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StartStructureWithNegSpace(
+ const char *const name,
+ SIZE_T ptr,
+ SIZE_T startPtr,
+ SIZE_T totalSize) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StartStructureWithOffset(
+ const char *const name,
+ unsigned int fieldOffset,
+ unsigned int fieldSize,
+ SIZE_T ptr,
+ SIZE_T size) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EndStructure( void) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IXCLRDataDisplayVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IXCLRDataDisplay * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IXCLRDataDisplay * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IXCLRDataDisplay * This);
+
+ HRESULT ( STDMETHODCALLTYPE *ErrorPrintF )(
+ IXCLRDataDisplay * This,
+ const char *const fmt,
+ ...);
+
+ HRESULT ( STDMETHODCALLTYPE *NativeImageDimensions )(
+ IXCLRDataDisplay * This,
+ SIZE_T base,
+ SIZE_T size,
+ DWORD sectionAlign);
+
+ HRESULT ( STDMETHODCALLTYPE *Section )(
+ IXCLRDataDisplay * This,
+ const char *const name,
+ SIZE_T rva,
+ SIZE_T size);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDumpOptions )(
+ IXCLRDataDisplay * This,
+ /* [out] */ CLRNativeImageDumpOptions *pOptions);
+
+ HRESULT ( STDMETHODCALLTYPE *StartDocument )(
+ IXCLRDataDisplay * This);
+
+ HRESULT ( STDMETHODCALLTYPE *EndDocument )(
+ IXCLRDataDisplay * This);
+
+ HRESULT ( STDMETHODCALLTYPE *StartCategory )(
+ IXCLRDataDisplay * This,
+ const char *const name);
+
+ HRESULT ( STDMETHODCALLTYPE *EndCategory )(
+ IXCLRDataDisplay * This);
+
+ HRESULT ( STDMETHODCALLTYPE *StartElement )(
+ IXCLRDataDisplay * This,
+ const char *const name);
+
+ HRESULT ( STDMETHODCALLTYPE *EndElement )(
+ IXCLRDataDisplay * This);
+
+ HRESULT ( STDMETHODCALLTYPE *StartVStructure )(
+ IXCLRDataDisplay * This,
+ const char *const name);
+
+ HRESULT ( STDMETHODCALLTYPE *StartVStructureWithOffset )(
+ IXCLRDataDisplay * This,
+ const char *const name,
+ unsigned int fieldOffset,
+ unsigned int fieldSize);
+
+ HRESULT ( STDMETHODCALLTYPE *EndVStructure )(
+ IXCLRDataDisplay * This);
+
+ HRESULT ( STDMETHODCALLTYPE *StartTextElement )(
+ IXCLRDataDisplay * This,
+ const char *const name);
+
+ HRESULT ( STDMETHODCALLTYPE *EndTextElement )(
+ IXCLRDataDisplay * This);
+
+ HRESULT ( STDMETHODCALLTYPE *WriteXmlText )(
+ IXCLRDataDisplay * This,
+ const char *const fmt,
+ ...);
+
+ HRESULT ( STDMETHODCALLTYPE *WriteXmlTextBlock )(
+ IXCLRDataDisplay * This,
+ const char *const fmt,
+ ...);
+
+ HRESULT ( STDMETHODCALLTYPE *WriteEmptyElement )(
+ IXCLRDataDisplay * This,
+ const char *const element);
+
+ HRESULT ( STDMETHODCALLTYPE *WriteElementPointer )(
+ IXCLRDataDisplay * This,
+ const char *const element,
+ SIZE_T ptr);
+
+ HRESULT ( STDMETHODCALLTYPE *WriteElementPointerAnnotated )(
+ IXCLRDataDisplay * This,
+ const char *const element,
+ SIZE_T ptr,
+ const WCHAR *const annotation);
+
+ HRESULT ( STDMETHODCALLTYPE *WriteElementAddress )(
+ IXCLRDataDisplay * This,
+ const char *const element,
+ SIZE_T base,
+ SIZE_T size);
+
+ HRESULT ( STDMETHODCALLTYPE *WriteElementAddressNamed )(
+ IXCLRDataDisplay * This,
+ const char *const element,
+ const char *const name,
+ SIZE_T base,
+ SIZE_T size);
+
+ HRESULT ( STDMETHODCALLTYPE *WriteElementAddressNamedW )(
+ IXCLRDataDisplay * This,
+ const char *const element,
+ const WCHAR *const name,
+ SIZE_T base,
+ SIZE_T size);
+
+ HRESULT ( STDMETHODCALLTYPE *WriteElementString )(
+ IXCLRDataDisplay * This,
+ const char *const element,
+ const char *const data);
+
+ HRESULT ( STDMETHODCALLTYPE *WriteElementStringW )(
+ IXCLRDataDisplay * This,
+ const char *const element,
+ const WCHAR *const data);
+
+ HRESULT ( STDMETHODCALLTYPE *WriteElementInt )(
+ IXCLRDataDisplay * This,
+ const char *const element,
+ int value);
+
+ HRESULT ( STDMETHODCALLTYPE *WriteElementUInt )(
+ IXCLRDataDisplay * This,
+ const char *const element,
+ DWORD value);
+
+ HRESULT ( STDMETHODCALLTYPE *WriteElementEnumerated )(
+ IXCLRDataDisplay * This,
+ const char *const element,
+ DWORD value,
+ const WCHAR *const mnemonic);
+
+ HRESULT ( STDMETHODCALLTYPE *WriteElementIntWithSuppress )(
+ IXCLRDataDisplay * This,
+ const char *const element,
+ int value,
+ int suppressIfEqual);
+
+ HRESULT ( STDMETHODCALLTYPE *WriteElementFlag )(
+ IXCLRDataDisplay * This,
+ const char *const element,
+ BOOL flag);
+
+ HRESULT ( STDMETHODCALLTYPE *StartArray )(
+ IXCLRDataDisplay * This,
+ const char *const name,
+ const WCHAR *const fmt);
+
+ HRESULT ( STDMETHODCALLTYPE *EndArray )(
+ IXCLRDataDisplay * This,
+ const char *const countPrefix);
+
+ HRESULT ( STDMETHODCALLTYPE *StartList )(
+ IXCLRDataDisplay * This,
+ const WCHAR *const fmt);
+
+ HRESULT ( STDMETHODCALLTYPE *EndList )(
+ IXCLRDataDisplay * This);
+
+ HRESULT ( STDMETHODCALLTYPE *StartArrayWithOffset )(
+ IXCLRDataDisplay * This,
+ const char *const name,
+ unsigned int fieldOffset,
+ unsigned int fieldSize,
+ const WCHAR *const fmt);
+
+ HRESULT ( STDMETHODCALLTYPE *WriteFieldString )(
+ IXCLRDataDisplay * This,
+ const char *const element,
+ unsigned int fieldOffset,
+ unsigned int fieldSize,
+ const char *const data);
+
+ HRESULT ( STDMETHODCALLTYPE *WriteFieldStringW )(
+ IXCLRDataDisplay * This,
+ const char *const element,
+ unsigned int fieldOffset,
+ unsigned int fieldSize,
+ const WCHAR *const data);
+
+ HRESULT ( STDMETHODCALLTYPE *WriteFieldPointer )(
+ IXCLRDataDisplay * This,
+ const char *const element,
+ unsigned int fieldOffset,
+ unsigned int fieldSize,
+ SIZE_T ptr);
+
+ HRESULT ( STDMETHODCALLTYPE *WriteFieldPointerWithSize )(
+ IXCLRDataDisplay * This,
+ const char *const element,
+ unsigned int fieldOffset,
+ unsigned int fieldSize,
+ SIZE_T ptr,
+ SIZE_T size);
+
+ HRESULT ( STDMETHODCALLTYPE *WriteFieldInt )(
+ IXCLRDataDisplay * This,
+ const char *const element,
+ unsigned int fieldOffset,
+ unsigned int fieldSize,
+ int value);
+
+ HRESULT ( STDMETHODCALLTYPE *WriteFieldUInt )(
+ IXCLRDataDisplay * This,
+ const char *const element,
+ unsigned int fieldOffset,
+ unsigned int fieldSize,
+ DWORD value);
+
+ HRESULT ( STDMETHODCALLTYPE *WriteFieldEnumerated )(
+ IXCLRDataDisplay * This,
+ const char *const element,
+ unsigned int fieldOffset,
+ unsigned int fieldSize,
+ DWORD value,
+ const WCHAR *const mnemonic);
+
+ HRESULT ( STDMETHODCALLTYPE *WriteFieldEmpty )(
+ IXCLRDataDisplay * This,
+ const char *const element,
+ unsigned int fieldOffset,
+ unsigned int fieldSize);
+
+ HRESULT ( STDMETHODCALLTYPE *WriteFieldFlag )(
+ IXCLRDataDisplay * This,
+ const char *const element,
+ unsigned int fieldOffset,
+ unsigned int fieldSize,
+ BOOL flag);
+
+ HRESULT ( STDMETHODCALLTYPE *WriteFieldPointerAnnotated )(
+ IXCLRDataDisplay * This,
+ const char *const element,
+ unsigned int fieldOffset,
+ unsigned int fieldSize,
+ SIZE_T ptr,
+ const WCHAR *const annotation);
+
+ HRESULT ( STDMETHODCALLTYPE *WriteFieldAddress )(
+ IXCLRDataDisplay * This,
+ const char *const element,
+ unsigned int fieldOffset,
+ unsigned int fieldSize,
+ SIZE_T base,
+ SIZE_T size);
+
+ HRESULT ( STDMETHODCALLTYPE *StartStructure )(
+ IXCLRDataDisplay * This,
+ const char *const name,
+ SIZE_T ptr,
+ SIZE_T size);
+
+ HRESULT ( STDMETHODCALLTYPE *StartStructureWithNegSpace )(
+ IXCLRDataDisplay * This,
+ const char *const name,
+ SIZE_T ptr,
+ SIZE_T startPtr,
+ SIZE_T totalSize);
+
+ HRESULT ( STDMETHODCALLTYPE *StartStructureWithOffset )(
+ IXCLRDataDisplay * This,
+ const char *const name,
+ unsigned int fieldOffset,
+ unsigned int fieldSize,
+ SIZE_T ptr,
+ SIZE_T size);
+
+ HRESULT ( STDMETHODCALLTYPE *EndStructure )(
+ IXCLRDataDisplay * This);
+
+ END_INTERFACE
+ } IXCLRDataDisplayVtbl;
+
+ interface IXCLRDataDisplay
+ {
+ CONST_VTBL struct IXCLRDataDisplayVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IXCLRDataDisplay_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IXCLRDataDisplay_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IXCLRDataDisplay_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IXCLRDataDisplay_ErrorPrintF(This,fmt,...) \
+ ( (This)->lpVtbl -> ErrorPrintF(This,fmt,...) )
+
+#define IXCLRDataDisplay_NativeImageDimensions(This,base,size,sectionAlign) \
+ ( (This)->lpVtbl -> NativeImageDimensions(This,base,size,sectionAlign) )
+
+#define IXCLRDataDisplay_Section(This,name,rva,size) \
+ ( (This)->lpVtbl -> Section(This,name,rva,size) )
+
+#define IXCLRDataDisplay_GetDumpOptions(This,pOptions) \
+ ( (This)->lpVtbl -> GetDumpOptions(This,pOptions) )
+
+#define IXCLRDataDisplay_StartDocument(This) \
+ ( (This)->lpVtbl -> StartDocument(This) )
+
+#define IXCLRDataDisplay_EndDocument(This) \
+ ( (This)->lpVtbl -> EndDocument(This) )
+
+#define IXCLRDataDisplay_StartCategory(This,name) \
+ ( (This)->lpVtbl -> StartCategory(This,name) )
+
+#define IXCLRDataDisplay_EndCategory(This) \
+ ( (This)->lpVtbl -> EndCategory(This) )
+
+#define IXCLRDataDisplay_StartElement(This,name) \
+ ( (This)->lpVtbl -> StartElement(This,name) )
+
+#define IXCLRDataDisplay_EndElement(This) \
+ ( (This)->lpVtbl -> EndElement(This) )
+
+#define IXCLRDataDisplay_StartVStructure(This,name) \
+ ( (This)->lpVtbl -> StartVStructure(This,name) )
+
+#define IXCLRDataDisplay_StartVStructureWithOffset(This,name,fieldOffset,fieldSize) \
+ ( (This)->lpVtbl -> StartVStructureWithOffset(This,name,fieldOffset,fieldSize) )
+
+#define IXCLRDataDisplay_EndVStructure(This) \
+ ( (This)->lpVtbl -> EndVStructure(This) )
+
+#define IXCLRDataDisplay_StartTextElement(This,name) \
+ ( (This)->lpVtbl -> StartTextElement(This,name) )
+
+#define IXCLRDataDisplay_EndTextElement(This) \
+ ( (This)->lpVtbl -> EndTextElement(This) )
+
+#define IXCLRDataDisplay_WriteXmlText(This,fmt,...) \
+ ( (This)->lpVtbl -> WriteXmlText(This,fmt,...) )
+
+#define IXCLRDataDisplay_WriteXmlTextBlock(This,fmt,...) \
+ ( (This)->lpVtbl -> WriteXmlTextBlock(This,fmt,...) )
+
+#define IXCLRDataDisplay_WriteEmptyElement(This,element) \
+ ( (This)->lpVtbl -> WriteEmptyElement(This,element) )
+
+#define IXCLRDataDisplay_WriteElementPointer(This,element,ptr) \
+ ( (This)->lpVtbl -> WriteElementPointer(This,element,ptr) )
+
+#define IXCLRDataDisplay_WriteElementPointerAnnotated(This,element,ptr,annotation) \
+ ( (This)->lpVtbl -> WriteElementPointerAnnotated(This,element,ptr,annotation) )
+
+#define IXCLRDataDisplay_WriteElementAddress(This,element,base,size) \
+ ( (This)->lpVtbl -> WriteElementAddress(This,element,base,size) )
+
+#define IXCLRDataDisplay_WriteElementAddressNamed(This,element,name,base,size) \
+ ( (This)->lpVtbl -> WriteElementAddressNamed(This,element,name,base,size) )
+
+#define IXCLRDataDisplay_WriteElementAddressNamedW(This,element,name,base,size) \
+ ( (This)->lpVtbl -> WriteElementAddressNamedW(This,element,name,base,size) )
+
+#define IXCLRDataDisplay_WriteElementString(This,element,data) \
+ ( (This)->lpVtbl -> WriteElementString(This,element,data) )
+
+#define IXCLRDataDisplay_WriteElementStringW(This,element,data) \
+ ( (This)->lpVtbl -> WriteElementStringW(This,element,data) )
+
+#define IXCLRDataDisplay_WriteElementInt(This,element,value) \
+ ( (This)->lpVtbl -> WriteElementInt(This,element,value) )
+
+#define IXCLRDataDisplay_WriteElementUInt(This,element,value) \
+ ( (This)->lpVtbl -> WriteElementUInt(This,element,value) )
+
+#define IXCLRDataDisplay_WriteElementEnumerated(This,element,value,mnemonic) \
+ ( (This)->lpVtbl -> WriteElementEnumerated(This,element,value,mnemonic) )
+
+#define IXCLRDataDisplay_WriteElementIntWithSuppress(This,element,value,suppressIfEqual) \
+ ( (This)->lpVtbl -> WriteElementIntWithSuppress(This,element,value,suppressIfEqual) )
+
+#define IXCLRDataDisplay_WriteElementFlag(This,element,flag) \
+ ( (This)->lpVtbl -> WriteElementFlag(This,element,flag) )
+
+#define IXCLRDataDisplay_StartArray(This,name,fmt) \
+ ( (This)->lpVtbl -> StartArray(This,name,fmt) )
+
+#define IXCLRDataDisplay_EndArray(This,countPrefix) \
+ ( (This)->lpVtbl -> EndArray(This,countPrefix) )
+
+#define IXCLRDataDisplay_StartList(This,fmt) \
+ ( (This)->lpVtbl -> StartList(This,fmt) )
+
+#define IXCLRDataDisplay_EndList(This) \
+ ( (This)->lpVtbl -> EndList(This) )
+
+#define IXCLRDataDisplay_StartArrayWithOffset(This,name,fieldOffset,fieldSize,fmt) \
+ ( (This)->lpVtbl -> StartArrayWithOffset(This,name,fieldOffset,fieldSize,fmt) )
+
+#define IXCLRDataDisplay_WriteFieldString(This,element,fieldOffset,fieldSize,data) \
+ ( (This)->lpVtbl -> WriteFieldString(This,element,fieldOffset,fieldSize,data) )
+
+#define IXCLRDataDisplay_WriteFieldStringW(This,element,fieldOffset,fieldSize,data) \
+ ( (This)->lpVtbl -> WriteFieldStringW(This,element,fieldOffset,fieldSize,data) )
+
+#define IXCLRDataDisplay_WriteFieldPointer(This,element,fieldOffset,fieldSize,ptr) \
+ ( (This)->lpVtbl -> WriteFieldPointer(This,element,fieldOffset,fieldSize,ptr) )
+
+#define IXCLRDataDisplay_WriteFieldPointerWithSize(This,element,fieldOffset,fieldSize,ptr,size) \
+ ( (This)->lpVtbl -> WriteFieldPointerWithSize(This,element,fieldOffset,fieldSize,ptr,size) )
+
+#define IXCLRDataDisplay_WriteFieldInt(This,element,fieldOffset,fieldSize,value) \
+ ( (This)->lpVtbl -> WriteFieldInt(This,element,fieldOffset,fieldSize,value) )
+
+#define IXCLRDataDisplay_WriteFieldUInt(This,element,fieldOffset,fieldSize,value) \
+ ( (This)->lpVtbl -> WriteFieldUInt(This,element,fieldOffset,fieldSize,value) )
+
+#define IXCLRDataDisplay_WriteFieldEnumerated(This,element,fieldOffset,fieldSize,value,mnemonic) \
+ ( (This)->lpVtbl -> WriteFieldEnumerated(This,element,fieldOffset,fieldSize,value,mnemonic) )
+
+#define IXCLRDataDisplay_WriteFieldEmpty(This,element,fieldOffset,fieldSize) \
+ ( (This)->lpVtbl -> WriteFieldEmpty(This,element,fieldOffset,fieldSize) )
+
+#define IXCLRDataDisplay_WriteFieldFlag(This,element,fieldOffset,fieldSize,flag) \
+ ( (This)->lpVtbl -> WriteFieldFlag(This,element,fieldOffset,fieldSize,flag) )
+
+#define IXCLRDataDisplay_WriteFieldPointerAnnotated(This,element,fieldOffset,fieldSize,ptr,annotation) \
+ ( (This)->lpVtbl -> WriteFieldPointerAnnotated(This,element,fieldOffset,fieldSize,ptr,annotation) )
+
+#define IXCLRDataDisplay_WriteFieldAddress(This,element,fieldOffset,fieldSize,base,size) \
+ ( (This)->lpVtbl -> WriteFieldAddress(This,element,fieldOffset,fieldSize,base,size) )
+
+#define IXCLRDataDisplay_StartStructure(This,name,ptr,size) \
+ ( (This)->lpVtbl -> StartStructure(This,name,ptr,size) )
+
+#define IXCLRDataDisplay_StartStructureWithNegSpace(This,name,ptr,startPtr,totalSize) \
+ ( (This)->lpVtbl -> StartStructureWithNegSpace(This,name,ptr,startPtr,totalSize) )
+
+#define IXCLRDataDisplay_StartStructureWithOffset(This,name,fieldOffset,fieldSize,ptr,size) \
+ ( (This)->lpVtbl -> StartStructureWithOffset(This,name,fieldOffset,fieldSize,ptr,size) )
+
+#define IXCLRDataDisplay_EndStructure(This) \
+ ( (This)->lpVtbl -> EndStructure(This) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IXCLRDataDisplay_INTERFACE_DEFINED__ */
+
+
+#ifndef __IXCLRDataProcess_INTERFACE_DEFINED__
+#define __IXCLRDataProcess_INTERFACE_DEFINED__
+
+/* interface IXCLRDataProcess */
+/* [uuid][local][object] */
+
+
+EXTERN_C const IID IID_IXCLRDataProcess;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("5c552ab6-fc09-4cb3-8e36-22fa03c798b7")
+ IXCLRDataProcess : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE Flush( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StartEnumTasks(
+ /* [out] */ CLRDATA_ENUM *handle) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnumTask(
+ /* [out][in] */ CLRDATA_ENUM *handle,
+ /* [out] */ IXCLRDataTask **task) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EndEnumTasks(
+ /* [in] */ CLRDATA_ENUM handle) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetTaskByOSThreadID(
+ /* [in] */ ULONG32 osThreadID,
+ /* [out] */ IXCLRDataTask **task) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetTaskByUniqueID(
+ /* [in] */ ULONG64 taskID,
+ /* [out] */ IXCLRDataTask **task) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetFlags(
+ /* [out] */ ULONG32 *flags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE IsSameObject(
+ /* [in] */ IXCLRDataProcess *process) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetManagedObject(
+ /* [out] */ IXCLRDataValue **value) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetDesiredExecutionState(
+ /* [out] */ ULONG32 *state) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetDesiredExecutionState(
+ /* [in] */ ULONG32 state) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetAddressType(
+ /* [in] */ CLRDATA_ADDRESS address,
+ /* [out] */ CLRDataAddressType *type) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetRuntimeNameByAddress(
+ /* [in] */ CLRDATA_ADDRESS address,
+ /* [in] */ ULONG32 flags,
+ /* [in] */ ULONG32 bufLen,
+ /* [out] */ ULONG32 *nameLen,
+ /* [size_is][out] */ WCHAR nameBuf[ ],
+ /* [out] */ CLRDATA_ADDRESS *displacement) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StartEnumAppDomains(
+ /* [out] */ CLRDATA_ENUM *handle) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnumAppDomain(
+ /* [out][in] */ CLRDATA_ENUM *handle,
+ /* [out] */ IXCLRDataAppDomain **appDomain) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EndEnumAppDomains(
+ /* [in] */ CLRDATA_ENUM handle) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetAppDomainByUniqueID(
+ /* [in] */ ULONG64 id,
+ /* [out] */ IXCLRDataAppDomain **appDomain) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StartEnumAssemblies(
+ /* [out] */ CLRDATA_ENUM *handle) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnumAssembly(
+ /* [out][in] */ CLRDATA_ENUM *handle,
+ /* [out] */ IXCLRDataAssembly **assembly) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EndEnumAssemblies(
+ /* [in] */ CLRDATA_ENUM handle) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StartEnumModules(
+ /* [out] */ CLRDATA_ENUM *handle) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnumModule(
+ /* [out][in] */ CLRDATA_ENUM *handle,
+ /* [out] */ IXCLRDataModule **mod) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EndEnumModules(
+ /* [in] */ CLRDATA_ENUM handle) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetModuleByAddress(
+ /* [in] */ CLRDATA_ADDRESS address,
+ /* [out] */ IXCLRDataModule **mod) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StartEnumMethodInstancesByAddress(
+ /* [in] */ CLRDATA_ADDRESS address,
+ /* [in] */ IXCLRDataAppDomain *appDomain,
+ /* [out] */ CLRDATA_ENUM *handle) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnumMethodInstanceByAddress(
+ /* [in] */ CLRDATA_ENUM *handle,
+ /* [out] */ IXCLRDataMethodInstance **method) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EndEnumMethodInstancesByAddress(
+ /* [in] */ CLRDATA_ENUM handle) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetDataByAddress(
+ /* [in] */ CLRDATA_ADDRESS address,
+ /* [in] */ ULONG32 flags,
+ /* [in] */ IXCLRDataAppDomain *appDomain,
+ /* [in] */ IXCLRDataTask *tlsTask,
+ /* [in] */ ULONG32 bufLen,
+ /* [out] */ ULONG32 *nameLen,
+ /* [size_is][out] */ WCHAR nameBuf[ ],
+ /* [out] */ IXCLRDataValue **value,
+ /* [out] */ CLRDATA_ADDRESS *displacement) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetExceptionStateByExceptionRecord(
+ /* [in] */ EXCEPTION_RECORD64 *record,
+ /* [out] */ IXCLRDataExceptionState **exState) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE TranslateExceptionRecordToNotification(
+ /* [in] */ EXCEPTION_RECORD64 *record,
+ /* [in] */ IXCLRDataExceptionNotification *notify) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Request(
+ /* [in] */ ULONG32 reqCode,
+ /* [in] */ ULONG32 inBufferSize,
+ /* [size_is][in] */ BYTE *inBuffer,
+ /* [in] */ ULONG32 outBufferSize,
+ /* [size_is][out] */ BYTE *outBuffer) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE CreateMemoryValue(
+ /* [in] */ IXCLRDataAppDomain *appDomain,
+ /* [in] */ IXCLRDataTask *tlsTask,
+ /* [in] */ IXCLRDataTypeInstance *type,
+ /* [in] */ CLRDATA_ADDRESS addr,
+ /* [out] */ IXCLRDataValue **value) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetAllTypeNotifications(
+ IXCLRDataModule *mod,
+ ULONG32 flags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetAllCodeNotifications(
+ IXCLRDataModule *mod,
+ ULONG32 flags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetTypeNotifications(
+ /* [in] */ ULONG32 numTokens,
+ /* [size_is][in] */ IXCLRDataModule *mods[ ],
+ /* [in] */ IXCLRDataModule *singleMod,
+ /* [size_is][in] */ mdTypeDef tokens[ ],
+ /* [size_is][out] */ ULONG32 flags[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetTypeNotifications(
+ /* [in] */ ULONG32 numTokens,
+ /* [size_is][in] */ IXCLRDataModule *mods[ ],
+ /* [in] */ IXCLRDataModule *singleMod,
+ /* [size_is][in] */ mdTypeDef tokens[ ],
+ /* [size_is][in] */ ULONG32 flags[ ],
+ /* [in] */ ULONG32 singleFlags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetCodeNotifications(
+ /* [in] */ ULONG32 numTokens,
+ /* [size_is][in] */ IXCLRDataModule *mods[ ],
+ /* [in] */ IXCLRDataModule *singleMod,
+ /* [size_is][in] */ mdMethodDef tokens[ ],
+ /* [size_is][out] */ ULONG32 flags[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetCodeNotifications(
+ /* [in] */ ULONG32 numTokens,
+ /* [size_is][in] */ IXCLRDataModule *mods[ ],
+ /* [in] */ IXCLRDataModule *singleMod,
+ /* [size_is][in] */ mdMethodDef tokens[ ],
+ /* [size_is][in] */ ULONG32 flags[ ],
+ /* [in] */ ULONG32 singleFlags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetOtherNotificationFlags(
+ /* [out] */ ULONG32 *flags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetOtherNotificationFlags(
+ /* [in] */ ULONG32 flags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StartEnumMethodDefinitionsByAddress(
+ /* [in] */ CLRDATA_ADDRESS address,
+ /* [out] */ CLRDATA_ENUM *handle) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnumMethodDefinitionByAddress(
+ /* [in] */ CLRDATA_ENUM *handle,
+ /* [out] */ IXCLRDataMethodDefinition **method) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EndEnumMethodDefinitionsByAddress(
+ /* [in] */ CLRDATA_ENUM handle) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE FollowStub(
+ /* [in] */ ULONG32 inFlags,
+ /* [in] */ CLRDATA_ADDRESS inAddr,
+ /* [in] */ CLRDATA_FOLLOW_STUB_BUFFER *inBuffer,
+ /* [out] */ CLRDATA_ADDRESS *outAddr,
+ /* [out] */ CLRDATA_FOLLOW_STUB_BUFFER *outBuffer,
+ /* [out] */ ULONG32 *outFlags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE FollowStub2(
+ /* [in] */ IXCLRDataTask *task,
+ /* [in] */ ULONG32 inFlags,
+ /* [in] */ CLRDATA_ADDRESS inAddr,
+ /* [in] */ CLRDATA_FOLLOW_STUB_BUFFER *inBuffer,
+ /* [out] */ CLRDATA_ADDRESS *outAddr,
+ /* [out] */ CLRDATA_FOLLOW_STUB_BUFFER *outBuffer,
+ /* [out] */ ULONG32 *outFlags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE DumpNativeImage(
+ /* [in] */ CLRDATA_ADDRESS loadedBase,
+ /* [in] */ LPCWSTR name,
+ /* [in] */ IXCLRDataDisplay *display,
+ /* [in] */ IXCLRLibrarySupport *libSupport,
+ /* [in] */ IXCLRDisassemblySupport *dis) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IXCLRDataProcessVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IXCLRDataProcess * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IXCLRDataProcess * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IXCLRDataProcess * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Flush )(
+ IXCLRDataProcess * This);
+
+ HRESULT ( STDMETHODCALLTYPE *StartEnumTasks )(
+ IXCLRDataProcess * This,
+ /* [out] */ CLRDATA_ENUM *handle);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumTask )(
+ IXCLRDataProcess * This,
+ /* [out][in] */ CLRDATA_ENUM *handle,
+ /* [out] */ IXCLRDataTask **task);
+
+ HRESULT ( STDMETHODCALLTYPE *EndEnumTasks )(
+ IXCLRDataProcess * This,
+ /* [in] */ CLRDATA_ENUM handle);
+
+ HRESULT ( STDMETHODCALLTYPE *GetTaskByOSThreadID )(
+ IXCLRDataProcess * This,
+ /* [in] */ ULONG32 osThreadID,
+ /* [out] */ IXCLRDataTask **task);
+
+ HRESULT ( STDMETHODCALLTYPE *GetTaskByUniqueID )(
+ IXCLRDataProcess * This,
+ /* [in] */ ULONG64 taskID,
+ /* [out] */ IXCLRDataTask **task);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFlags )(
+ IXCLRDataProcess * This,
+ /* [out] */ ULONG32 *flags);
+
+ HRESULT ( STDMETHODCALLTYPE *IsSameObject )(
+ IXCLRDataProcess * This,
+ /* [in] */ IXCLRDataProcess *process);
+
+ HRESULT ( STDMETHODCALLTYPE *GetManagedObject )(
+ IXCLRDataProcess * This,
+ /* [out] */ IXCLRDataValue **value);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDesiredExecutionState )(
+ IXCLRDataProcess * This,
+ /* [out] */ ULONG32 *state);
+
+ HRESULT ( STDMETHODCALLTYPE *SetDesiredExecutionState )(
+ IXCLRDataProcess * This,
+ /* [in] */ ULONG32 state);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAddressType )(
+ IXCLRDataProcess * This,
+ /* [in] */ CLRDATA_ADDRESS address,
+ /* [out] */ CLRDataAddressType *type);
+
+ HRESULT ( STDMETHODCALLTYPE *GetRuntimeNameByAddress )(
+ IXCLRDataProcess * This,
+ /* [in] */ CLRDATA_ADDRESS address,
+ /* [in] */ ULONG32 flags,
+ /* [in] */ ULONG32 bufLen,
+ /* [out] */ ULONG32 *nameLen,
+ /* [size_is][out] */ WCHAR nameBuf[ ],
+ /* [out] */ CLRDATA_ADDRESS *displacement);
+
+ HRESULT ( STDMETHODCALLTYPE *StartEnumAppDomains )(
+ IXCLRDataProcess * This,
+ /* [out] */ CLRDATA_ENUM *handle);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumAppDomain )(
+ IXCLRDataProcess * This,
+ /* [out][in] */ CLRDATA_ENUM *handle,
+ /* [out] */ IXCLRDataAppDomain **appDomain);
+
+ HRESULT ( STDMETHODCALLTYPE *EndEnumAppDomains )(
+ IXCLRDataProcess * This,
+ /* [in] */ CLRDATA_ENUM handle);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAppDomainByUniqueID )(
+ IXCLRDataProcess * This,
+ /* [in] */ ULONG64 id,
+ /* [out] */ IXCLRDataAppDomain **appDomain);
+
+ HRESULT ( STDMETHODCALLTYPE *StartEnumAssemblies )(
+ IXCLRDataProcess * This,
+ /* [out] */ CLRDATA_ENUM *handle);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumAssembly )(
+ IXCLRDataProcess * This,
+ /* [out][in] */ CLRDATA_ENUM *handle,
+ /* [out] */ IXCLRDataAssembly **assembly);
+
+ HRESULT ( STDMETHODCALLTYPE *EndEnumAssemblies )(
+ IXCLRDataProcess * This,
+ /* [in] */ CLRDATA_ENUM handle);
+
+ HRESULT ( STDMETHODCALLTYPE *StartEnumModules )(
+ IXCLRDataProcess * This,
+ /* [out] */ CLRDATA_ENUM *handle);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumModule )(
+ IXCLRDataProcess * This,
+ /* [out][in] */ CLRDATA_ENUM *handle,
+ /* [out] */ IXCLRDataModule **mod);
+
+ HRESULT ( STDMETHODCALLTYPE *EndEnumModules )(
+ IXCLRDataProcess * This,
+ /* [in] */ CLRDATA_ENUM handle);
+
+ HRESULT ( STDMETHODCALLTYPE *GetModuleByAddress )(
+ IXCLRDataProcess * This,
+ /* [in] */ CLRDATA_ADDRESS address,
+ /* [out] */ IXCLRDataModule **mod);
+
+ HRESULT ( STDMETHODCALLTYPE *StartEnumMethodInstancesByAddress )(
+ IXCLRDataProcess * This,
+ /* [in] */ CLRDATA_ADDRESS address,
+ /* [in] */ IXCLRDataAppDomain *appDomain,
+ /* [out] */ CLRDATA_ENUM *handle);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumMethodInstanceByAddress )(
+ IXCLRDataProcess * This,
+ /* [in] */ CLRDATA_ENUM *handle,
+ /* [out] */ IXCLRDataMethodInstance **method);
+
+ HRESULT ( STDMETHODCALLTYPE *EndEnumMethodInstancesByAddress )(
+ IXCLRDataProcess * This,
+ /* [in] */ CLRDATA_ENUM handle);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDataByAddress )(
+ IXCLRDataProcess * This,
+ /* [in] */ CLRDATA_ADDRESS address,
+ /* [in] */ ULONG32 flags,
+ /* [in] */ IXCLRDataAppDomain *appDomain,
+ /* [in] */ IXCLRDataTask *tlsTask,
+ /* [in] */ ULONG32 bufLen,
+ /* [out] */ ULONG32 *nameLen,
+ /* [size_is][out] */ WCHAR nameBuf[ ],
+ /* [out] */ IXCLRDataValue **value,
+ /* [out] */ CLRDATA_ADDRESS *displacement);
+
+ HRESULT ( STDMETHODCALLTYPE *GetExceptionStateByExceptionRecord )(
+ IXCLRDataProcess * This,
+ /* [in] */ EXCEPTION_RECORD64 *record,
+ /* [out] */ IXCLRDataExceptionState **exState);
+
+ HRESULT ( STDMETHODCALLTYPE *TranslateExceptionRecordToNotification )(
+ IXCLRDataProcess * This,
+ /* [in] */ EXCEPTION_RECORD64 *record,
+ /* [in] */ IXCLRDataExceptionNotification *notify);
+
+ HRESULT ( STDMETHODCALLTYPE *Request )(
+ IXCLRDataProcess * This,
+ /* [in] */ ULONG32 reqCode,
+ /* [in] */ ULONG32 inBufferSize,
+ /* [size_is][in] */ BYTE *inBuffer,
+ /* [in] */ ULONG32 outBufferSize,
+ /* [size_is][out] */ BYTE *outBuffer);
+
+ HRESULT ( STDMETHODCALLTYPE *CreateMemoryValue )(
+ IXCLRDataProcess * This,
+ /* [in] */ IXCLRDataAppDomain *appDomain,
+ /* [in] */ IXCLRDataTask *tlsTask,
+ /* [in] */ IXCLRDataTypeInstance *type,
+ /* [in] */ CLRDATA_ADDRESS addr,
+ /* [out] */ IXCLRDataValue **value);
+
+ HRESULT ( STDMETHODCALLTYPE *SetAllTypeNotifications )(
+ IXCLRDataProcess * This,
+ IXCLRDataModule *mod,
+ ULONG32 flags);
+
+ HRESULT ( STDMETHODCALLTYPE *SetAllCodeNotifications )(
+ IXCLRDataProcess * This,
+ IXCLRDataModule *mod,
+ ULONG32 flags);
+
+ HRESULT ( STDMETHODCALLTYPE *GetTypeNotifications )(
+ IXCLRDataProcess * This,
+ /* [in] */ ULONG32 numTokens,
+ /* [size_is][in] */ IXCLRDataModule *mods[ ],
+ /* [in] */ IXCLRDataModule *singleMod,
+ /* [size_is][in] */ mdTypeDef tokens[ ],
+ /* [size_is][out] */ ULONG32 flags[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *SetTypeNotifications )(
+ IXCLRDataProcess * This,
+ /* [in] */ ULONG32 numTokens,
+ /* [size_is][in] */ IXCLRDataModule *mods[ ],
+ /* [in] */ IXCLRDataModule *singleMod,
+ /* [size_is][in] */ mdTypeDef tokens[ ],
+ /* [size_is][in] */ ULONG32 flags[ ],
+ /* [in] */ ULONG32 singleFlags);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCodeNotifications )(
+ IXCLRDataProcess * This,
+ /* [in] */ ULONG32 numTokens,
+ /* [size_is][in] */ IXCLRDataModule *mods[ ],
+ /* [in] */ IXCLRDataModule *singleMod,
+ /* [size_is][in] */ mdMethodDef tokens[ ],
+ /* [size_is][out] */ ULONG32 flags[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *SetCodeNotifications )(
+ IXCLRDataProcess * This,
+ /* [in] */ ULONG32 numTokens,
+ /* [size_is][in] */ IXCLRDataModule *mods[ ],
+ /* [in] */ IXCLRDataModule *singleMod,
+ /* [size_is][in] */ mdMethodDef tokens[ ],
+ /* [size_is][in] */ ULONG32 flags[ ],
+ /* [in] */ ULONG32 singleFlags);
+
+ HRESULT ( STDMETHODCALLTYPE *GetOtherNotificationFlags )(
+ IXCLRDataProcess * This,
+ /* [out] */ ULONG32 *flags);
+
+ HRESULT ( STDMETHODCALLTYPE *SetOtherNotificationFlags )(
+ IXCLRDataProcess * This,
+ /* [in] */ ULONG32 flags);
+
+ HRESULT ( STDMETHODCALLTYPE *StartEnumMethodDefinitionsByAddress )(
+ IXCLRDataProcess * This,
+ /* [in] */ CLRDATA_ADDRESS address,
+ /* [out] */ CLRDATA_ENUM *handle);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumMethodDefinitionByAddress )(
+ IXCLRDataProcess * This,
+ /* [in] */ CLRDATA_ENUM *handle,
+ /* [out] */ IXCLRDataMethodDefinition **method);
+
+ HRESULT ( STDMETHODCALLTYPE *EndEnumMethodDefinitionsByAddress )(
+ IXCLRDataProcess * This,
+ /* [in] */ CLRDATA_ENUM handle);
+
+ HRESULT ( STDMETHODCALLTYPE *FollowStub )(
+ IXCLRDataProcess * This,
+ /* [in] */ ULONG32 inFlags,
+ /* [in] */ CLRDATA_ADDRESS inAddr,
+ /* [in] */ CLRDATA_FOLLOW_STUB_BUFFER *inBuffer,
+ /* [out] */ CLRDATA_ADDRESS *outAddr,
+ /* [out] */ CLRDATA_FOLLOW_STUB_BUFFER *outBuffer,
+ /* [out] */ ULONG32 *outFlags);
+
+ HRESULT ( STDMETHODCALLTYPE *FollowStub2 )(
+ IXCLRDataProcess * This,
+ /* [in] */ IXCLRDataTask *task,
+ /* [in] */ ULONG32 inFlags,
+ /* [in] */ CLRDATA_ADDRESS inAddr,
+ /* [in] */ CLRDATA_FOLLOW_STUB_BUFFER *inBuffer,
+ /* [out] */ CLRDATA_ADDRESS *outAddr,
+ /* [out] */ CLRDATA_FOLLOW_STUB_BUFFER *outBuffer,
+ /* [out] */ ULONG32 *outFlags);
+
+ HRESULT ( STDMETHODCALLTYPE *DumpNativeImage )(
+ IXCLRDataProcess * This,
+ /* [in] */ CLRDATA_ADDRESS loadedBase,
+ /* [in] */ LPCWSTR name,
+ /* [in] */ IXCLRDataDisplay *display,
+ /* [in] */ IXCLRLibrarySupport *libSupport,
+ /* [in] */ IXCLRDisassemblySupport *dis);
+
+ END_INTERFACE
+ } IXCLRDataProcessVtbl;
+
+ interface IXCLRDataProcess
+ {
+ CONST_VTBL struct IXCLRDataProcessVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IXCLRDataProcess_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IXCLRDataProcess_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IXCLRDataProcess_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IXCLRDataProcess_Flush(This) \
+ ( (This)->lpVtbl -> Flush(This) )
+
+#define IXCLRDataProcess_StartEnumTasks(This,handle) \
+ ( (This)->lpVtbl -> StartEnumTasks(This,handle) )
+
+#define IXCLRDataProcess_EnumTask(This,handle,task) \
+ ( (This)->lpVtbl -> EnumTask(This,handle,task) )
+
+#define IXCLRDataProcess_EndEnumTasks(This,handle) \
+ ( (This)->lpVtbl -> EndEnumTasks(This,handle) )
+
+#define IXCLRDataProcess_GetTaskByOSThreadID(This,osThreadID,task) \
+ ( (This)->lpVtbl -> GetTaskByOSThreadID(This,osThreadID,task) )
+
+#define IXCLRDataProcess_GetTaskByUniqueID(This,taskID,task) \
+ ( (This)->lpVtbl -> GetTaskByUniqueID(This,taskID,task) )
+
+#define IXCLRDataProcess_GetFlags(This,flags) \
+ ( (This)->lpVtbl -> GetFlags(This,flags) )
+
+#define IXCLRDataProcess_IsSameObject(This,process) \
+ ( (This)->lpVtbl -> IsSameObject(This,process) )
+
+#define IXCLRDataProcess_GetManagedObject(This,value) \
+ ( (This)->lpVtbl -> GetManagedObject(This,value) )
+
+#define IXCLRDataProcess_GetDesiredExecutionState(This,state) \
+ ( (This)->lpVtbl -> GetDesiredExecutionState(This,state) )
+
+#define IXCLRDataProcess_SetDesiredExecutionState(This,state) \
+ ( (This)->lpVtbl -> SetDesiredExecutionState(This,state) )
+
+#define IXCLRDataProcess_GetAddressType(This,address,type) \
+ ( (This)->lpVtbl -> GetAddressType(This,address,type) )
+
+#define IXCLRDataProcess_GetRuntimeNameByAddress(This,address,flags,bufLen,nameLen,nameBuf,displacement) \
+ ( (This)->lpVtbl -> GetRuntimeNameByAddress(This,address,flags,bufLen,nameLen,nameBuf,displacement) )
+
+#define IXCLRDataProcess_StartEnumAppDomains(This,handle) \
+ ( (This)->lpVtbl -> StartEnumAppDomains(This,handle) )
+
+#define IXCLRDataProcess_EnumAppDomain(This,handle,appDomain) \
+ ( (This)->lpVtbl -> EnumAppDomain(This,handle,appDomain) )
+
+#define IXCLRDataProcess_EndEnumAppDomains(This,handle) \
+ ( (This)->lpVtbl -> EndEnumAppDomains(This,handle) )
+
+#define IXCLRDataProcess_GetAppDomainByUniqueID(This,id,appDomain) \
+ ( (This)->lpVtbl -> GetAppDomainByUniqueID(This,id,appDomain) )
+
+#define IXCLRDataProcess_StartEnumAssemblies(This,handle) \
+ ( (This)->lpVtbl -> StartEnumAssemblies(This,handle) )
+
+#define IXCLRDataProcess_EnumAssembly(This,handle,assembly) \
+ ( (This)->lpVtbl -> EnumAssembly(This,handle,assembly) )
+
+#define IXCLRDataProcess_EndEnumAssemblies(This,handle) \
+ ( (This)->lpVtbl -> EndEnumAssemblies(This,handle) )
+
+#define IXCLRDataProcess_StartEnumModules(This,handle) \
+ ( (This)->lpVtbl -> StartEnumModules(This,handle) )
+
+#define IXCLRDataProcess_EnumModule(This,handle,mod) \
+ ( (This)->lpVtbl -> EnumModule(This,handle,mod) )
+
+#define IXCLRDataProcess_EndEnumModules(This,handle) \
+ ( (This)->lpVtbl -> EndEnumModules(This,handle) )
+
+#define IXCLRDataProcess_GetModuleByAddress(This,address,mod) \
+ ( (This)->lpVtbl -> GetModuleByAddress(This,address,mod) )
+
+#define IXCLRDataProcess_StartEnumMethodInstancesByAddress(This,address,appDomain,handle) \
+ ( (This)->lpVtbl -> StartEnumMethodInstancesByAddress(This,address,appDomain,handle) )
+
+#define IXCLRDataProcess_EnumMethodInstanceByAddress(This,handle,method) \
+ ( (This)->lpVtbl -> EnumMethodInstanceByAddress(This,handle,method) )
+
+#define IXCLRDataProcess_EndEnumMethodInstancesByAddress(This,handle) \
+ ( (This)->lpVtbl -> EndEnumMethodInstancesByAddress(This,handle) )
+
+#define IXCLRDataProcess_GetDataByAddress(This,address,flags,appDomain,tlsTask,bufLen,nameLen,nameBuf,value,displacement) \
+ ( (This)->lpVtbl -> GetDataByAddress(This,address,flags,appDomain,tlsTask,bufLen,nameLen,nameBuf,value,displacement) )
+
+#define IXCLRDataProcess_GetExceptionStateByExceptionRecord(This,record,exState) \
+ ( (This)->lpVtbl -> GetExceptionStateByExceptionRecord(This,record,exState) )
+
+#define IXCLRDataProcess_TranslateExceptionRecordToNotification(This,record,notify) \
+ ( (This)->lpVtbl -> TranslateExceptionRecordToNotification(This,record,notify) )
+
+#define IXCLRDataProcess_Request(This,reqCode,inBufferSize,inBuffer,outBufferSize,outBuffer) \
+ ( (This)->lpVtbl -> Request(This,reqCode,inBufferSize,inBuffer,outBufferSize,outBuffer) )
+
+#define IXCLRDataProcess_CreateMemoryValue(This,appDomain,tlsTask,type,addr,value) \
+ ( (This)->lpVtbl -> CreateMemoryValue(This,appDomain,tlsTask,type,addr,value) )
+
+#define IXCLRDataProcess_SetAllTypeNotifications(This,mod,flags) \
+ ( (This)->lpVtbl -> SetAllTypeNotifications(This,mod,flags) )
+
+#define IXCLRDataProcess_SetAllCodeNotifications(This,mod,flags) \
+ ( (This)->lpVtbl -> SetAllCodeNotifications(This,mod,flags) )
+
+#define IXCLRDataProcess_GetTypeNotifications(This,numTokens,mods,singleMod,tokens,flags) \
+ ( (This)->lpVtbl -> GetTypeNotifications(This,numTokens,mods,singleMod,tokens,flags) )
+
+#define IXCLRDataProcess_SetTypeNotifications(This,numTokens,mods,singleMod,tokens,flags,singleFlags) \
+ ( (This)->lpVtbl -> SetTypeNotifications(This,numTokens,mods,singleMod,tokens,flags,singleFlags) )
+
+#define IXCLRDataProcess_GetCodeNotifications(This,numTokens,mods,singleMod,tokens,flags) \
+ ( (This)->lpVtbl -> GetCodeNotifications(This,numTokens,mods,singleMod,tokens,flags) )
+
+#define IXCLRDataProcess_SetCodeNotifications(This,numTokens,mods,singleMod,tokens,flags,singleFlags) \
+ ( (This)->lpVtbl -> SetCodeNotifications(This,numTokens,mods,singleMod,tokens,flags,singleFlags) )
+
+#define IXCLRDataProcess_GetOtherNotificationFlags(This,flags) \
+ ( (This)->lpVtbl -> GetOtherNotificationFlags(This,flags) )
+
+#define IXCLRDataProcess_SetOtherNotificationFlags(This,flags) \
+ ( (This)->lpVtbl -> SetOtherNotificationFlags(This,flags) )
+
+#define IXCLRDataProcess_StartEnumMethodDefinitionsByAddress(This,address,handle) \
+ ( (This)->lpVtbl -> StartEnumMethodDefinitionsByAddress(This,address,handle) )
+
+#define IXCLRDataProcess_EnumMethodDefinitionByAddress(This,handle,method) \
+ ( (This)->lpVtbl -> EnumMethodDefinitionByAddress(This,handle,method) )
+
+#define IXCLRDataProcess_EndEnumMethodDefinitionsByAddress(This,handle) \
+ ( (This)->lpVtbl -> EndEnumMethodDefinitionsByAddress(This,handle) )
+
+#define IXCLRDataProcess_FollowStub(This,inFlags,inAddr,inBuffer,outAddr,outBuffer,outFlags) \
+ ( (This)->lpVtbl -> FollowStub(This,inFlags,inAddr,inBuffer,outAddr,outBuffer,outFlags) )
+
+#define IXCLRDataProcess_FollowStub2(This,task,inFlags,inAddr,inBuffer,outAddr,outBuffer,outFlags) \
+ ( (This)->lpVtbl -> FollowStub2(This,task,inFlags,inAddr,inBuffer,outAddr,outBuffer,outFlags) )
+
+#define IXCLRDataProcess_DumpNativeImage(This,loadedBase,name,display,libSupport,dis) \
+ ( (This)->lpVtbl -> DumpNativeImage(This,loadedBase,name,display,libSupport,dis) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IXCLRDataProcess_INTERFACE_DEFINED__ */
+
+
+/* interface __MIDL_itf_xclrdata_0000_0005 */
+/* [local] */
+
+#pragma warning(pop)
+typedef /* [public][public][public][public] */
+enum __MIDL___MIDL_itf_xclrdata_0000_0005_0001
+ {
+ GC_MARK_END = 1,
+ GC_EVENT_TYPE_MAX = ( GC_MARK_END + 1 )
+ } GcEvt_t;
+
+typedef /* [public][public][public][public] */ struct __MIDL___MIDL_itf_xclrdata_0000_0005_0002
+ {
+ GcEvt_t typ;
+ /* [switch_is] */ /* [switch_type] */ union
+ {
+ /* [case()] */ int condemnedGeneration;
+ } ;
+ } GcEvtArgs;
+
+
+
+extern RPC_IF_HANDLE __MIDL_itf_xclrdata_0000_0005_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_xclrdata_0000_0005_v0_0_s_ifspec;
+
+#ifndef __IXCLRDataProcess2_INTERFACE_DEFINED__
+#define __IXCLRDataProcess2_INTERFACE_DEFINED__
+
+/* interface IXCLRDataProcess2 */
+/* [uuid][local][object] */
+
+
+EXTERN_C const IID IID_IXCLRDataProcess2;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("5c552ab6-fc09-4cb3-8e36-22fa03c798b8")
+ IXCLRDataProcess2 : public IXCLRDataProcess
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetGcNotification(
+ /* [out][in] */ GcEvtArgs *gcEvtArgs) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetGcNotification(
+ /* [in] */ GcEvtArgs gcEvtArgs) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IXCLRDataProcess2Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IXCLRDataProcess2 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IXCLRDataProcess2 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IXCLRDataProcess2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Flush )(
+ IXCLRDataProcess2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *StartEnumTasks )(
+ IXCLRDataProcess2 * This,
+ /* [out] */ CLRDATA_ENUM *handle);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumTask )(
+ IXCLRDataProcess2 * This,
+ /* [out][in] */ CLRDATA_ENUM *handle,
+ /* [out] */ IXCLRDataTask **task);
+
+ HRESULT ( STDMETHODCALLTYPE *EndEnumTasks )(
+ IXCLRDataProcess2 * This,
+ /* [in] */ CLRDATA_ENUM handle);
+
+ HRESULT ( STDMETHODCALLTYPE *GetTaskByOSThreadID )(
+ IXCLRDataProcess2 * This,
+ /* [in] */ ULONG32 osThreadID,
+ /* [out] */ IXCLRDataTask **task);
+
+ HRESULT ( STDMETHODCALLTYPE *GetTaskByUniqueID )(
+ IXCLRDataProcess2 * This,
+ /* [in] */ ULONG64 taskID,
+ /* [out] */ IXCLRDataTask **task);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFlags )(
+ IXCLRDataProcess2 * This,
+ /* [out] */ ULONG32 *flags);
+
+ HRESULT ( STDMETHODCALLTYPE *IsSameObject )(
+ IXCLRDataProcess2 * This,
+ /* [in] */ IXCLRDataProcess *process);
+
+ HRESULT ( STDMETHODCALLTYPE *GetManagedObject )(
+ IXCLRDataProcess2 * This,
+ /* [out] */ IXCLRDataValue **value);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDesiredExecutionState )(
+ IXCLRDataProcess2 * This,
+ /* [out] */ ULONG32 *state);
+
+ HRESULT ( STDMETHODCALLTYPE *SetDesiredExecutionState )(
+ IXCLRDataProcess2 * This,
+ /* [in] */ ULONG32 state);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAddressType )(
+ IXCLRDataProcess2 * This,
+ /* [in] */ CLRDATA_ADDRESS address,
+ /* [out] */ CLRDataAddressType *type);
+
+ HRESULT ( STDMETHODCALLTYPE *GetRuntimeNameByAddress )(
+ IXCLRDataProcess2 * This,
+ /* [in] */ CLRDATA_ADDRESS address,
+ /* [in] */ ULONG32 flags,
+ /* [in] */ ULONG32 bufLen,
+ /* [out] */ ULONG32 *nameLen,
+ /* [size_is][out] */ WCHAR nameBuf[ ],
+ /* [out] */ CLRDATA_ADDRESS *displacement);
+
+ HRESULT ( STDMETHODCALLTYPE *StartEnumAppDomains )(
+ IXCLRDataProcess2 * This,
+ /* [out] */ CLRDATA_ENUM *handle);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumAppDomain )(
+ IXCLRDataProcess2 * This,
+ /* [out][in] */ CLRDATA_ENUM *handle,
+ /* [out] */ IXCLRDataAppDomain **appDomain);
+
+ HRESULT ( STDMETHODCALLTYPE *EndEnumAppDomains )(
+ IXCLRDataProcess2 * This,
+ /* [in] */ CLRDATA_ENUM handle);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAppDomainByUniqueID )(
+ IXCLRDataProcess2 * This,
+ /* [in] */ ULONG64 id,
+ /* [out] */ IXCLRDataAppDomain **appDomain);
+
+ HRESULT ( STDMETHODCALLTYPE *StartEnumAssemblies )(
+ IXCLRDataProcess2 * This,
+ /* [out] */ CLRDATA_ENUM *handle);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumAssembly )(
+ IXCLRDataProcess2 * This,
+ /* [out][in] */ CLRDATA_ENUM *handle,
+ /* [out] */ IXCLRDataAssembly **assembly);
+
+ HRESULT ( STDMETHODCALLTYPE *EndEnumAssemblies )(
+ IXCLRDataProcess2 * This,
+ /* [in] */ CLRDATA_ENUM handle);
+
+ HRESULT ( STDMETHODCALLTYPE *StartEnumModules )(
+ IXCLRDataProcess2 * This,
+ /* [out] */ CLRDATA_ENUM *handle);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumModule )(
+ IXCLRDataProcess2 * This,
+ /* [out][in] */ CLRDATA_ENUM *handle,
+ /* [out] */ IXCLRDataModule **mod);
+
+ HRESULT ( STDMETHODCALLTYPE *EndEnumModules )(
+ IXCLRDataProcess2 * This,
+ /* [in] */ CLRDATA_ENUM handle);
+
+ HRESULT ( STDMETHODCALLTYPE *GetModuleByAddress )(
+ IXCLRDataProcess2 * This,
+ /* [in] */ CLRDATA_ADDRESS address,
+ /* [out] */ IXCLRDataModule **mod);
+
+ HRESULT ( STDMETHODCALLTYPE *StartEnumMethodInstancesByAddress )(
+ IXCLRDataProcess2 * This,
+ /* [in] */ CLRDATA_ADDRESS address,
+ /* [in] */ IXCLRDataAppDomain *appDomain,
+ /* [out] */ CLRDATA_ENUM *handle);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumMethodInstanceByAddress )(
+ IXCLRDataProcess2 * This,
+ /* [in] */ CLRDATA_ENUM *handle,
+ /* [out] */ IXCLRDataMethodInstance **method);
+
+ HRESULT ( STDMETHODCALLTYPE *EndEnumMethodInstancesByAddress )(
+ IXCLRDataProcess2 * This,
+ /* [in] */ CLRDATA_ENUM handle);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDataByAddress )(
+ IXCLRDataProcess2 * This,
+ /* [in] */ CLRDATA_ADDRESS address,
+ /* [in] */ ULONG32 flags,
+ /* [in] */ IXCLRDataAppDomain *appDomain,
+ /* [in] */ IXCLRDataTask *tlsTask,
+ /* [in] */ ULONG32 bufLen,
+ /* [out] */ ULONG32 *nameLen,
+ /* [size_is][out] */ WCHAR nameBuf[ ],
+ /* [out] */ IXCLRDataValue **value,
+ /* [out] */ CLRDATA_ADDRESS *displacement);
+
+ HRESULT ( STDMETHODCALLTYPE *GetExceptionStateByExceptionRecord )(
+ IXCLRDataProcess2 * This,
+ /* [in] */ EXCEPTION_RECORD64 *record,
+ /* [out] */ IXCLRDataExceptionState **exState);
+
+ HRESULT ( STDMETHODCALLTYPE *TranslateExceptionRecordToNotification )(
+ IXCLRDataProcess2 * This,
+ /* [in] */ EXCEPTION_RECORD64 *record,
+ /* [in] */ IXCLRDataExceptionNotification *notify);
+
+ HRESULT ( STDMETHODCALLTYPE *Request )(
+ IXCLRDataProcess2 * This,
+ /* [in] */ ULONG32 reqCode,
+ /* [in] */ ULONG32 inBufferSize,
+ /* [size_is][in] */ BYTE *inBuffer,
+ /* [in] */ ULONG32 outBufferSize,
+ /* [size_is][out] */ BYTE *outBuffer);
+
+ HRESULT ( STDMETHODCALLTYPE *CreateMemoryValue )(
+ IXCLRDataProcess2 * This,
+ /* [in] */ IXCLRDataAppDomain *appDomain,
+ /* [in] */ IXCLRDataTask *tlsTask,
+ /* [in] */ IXCLRDataTypeInstance *type,
+ /* [in] */ CLRDATA_ADDRESS addr,
+ /* [out] */ IXCLRDataValue **value);
+
+ HRESULT ( STDMETHODCALLTYPE *SetAllTypeNotifications )(
+ IXCLRDataProcess2 * This,
+ IXCLRDataModule *mod,
+ ULONG32 flags);
+
+ HRESULT ( STDMETHODCALLTYPE *SetAllCodeNotifications )(
+ IXCLRDataProcess2 * This,
+ IXCLRDataModule *mod,
+ ULONG32 flags);
+
+ HRESULT ( STDMETHODCALLTYPE *GetTypeNotifications )(
+ IXCLRDataProcess2 * This,
+ /* [in] */ ULONG32 numTokens,
+ /* [size_is][in] */ IXCLRDataModule *mods[ ],
+ /* [in] */ IXCLRDataModule *singleMod,
+ /* [size_is][in] */ mdTypeDef tokens[ ],
+ /* [size_is][out] */ ULONG32 flags[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *SetTypeNotifications )(
+ IXCLRDataProcess2 * This,
+ /* [in] */ ULONG32 numTokens,
+ /* [size_is][in] */ IXCLRDataModule *mods[ ],
+ /* [in] */ IXCLRDataModule *singleMod,
+ /* [size_is][in] */ mdTypeDef tokens[ ],
+ /* [size_is][in] */ ULONG32 flags[ ],
+ /* [in] */ ULONG32 singleFlags);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCodeNotifications )(
+ IXCLRDataProcess2 * This,
+ /* [in] */ ULONG32 numTokens,
+ /* [size_is][in] */ IXCLRDataModule *mods[ ],
+ /* [in] */ IXCLRDataModule *singleMod,
+ /* [size_is][in] */ mdMethodDef tokens[ ],
+ /* [size_is][out] */ ULONG32 flags[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *SetCodeNotifications )(
+ IXCLRDataProcess2 * This,
+ /* [in] */ ULONG32 numTokens,
+ /* [size_is][in] */ IXCLRDataModule *mods[ ],
+ /* [in] */ IXCLRDataModule *singleMod,
+ /* [size_is][in] */ mdMethodDef tokens[ ],
+ /* [size_is][in] */ ULONG32 flags[ ],
+ /* [in] */ ULONG32 singleFlags);
+
+ HRESULT ( STDMETHODCALLTYPE *GetOtherNotificationFlags )(
+ IXCLRDataProcess2 * This,
+ /* [out] */ ULONG32 *flags);
+
+ HRESULT ( STDMETHODCALLTYPE *SetOtherNotificationFlags )(
+ IXCLRDataProcess2 * This,
+ /* [in] */ ULONG32 flags);
+
+ HRESULT ( STDMETHODCALLTYPE *StartEnumMethodDefinitionsByAddress )(
+ IXCLRDataProcess2 * This,
+ /* [in] */ CLRDATA_ADDRESS address,
+ /* [out] */ CLRDATA_ENUM *handle);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumMethodDefinitionByAddress )(
+ IXCLRDataProcess2 * This,
+ /* [in] */ CLRDATA_ENUM *handle,
+ /* [out] */ IXCLRDataMethodDefinition **method);
+
+ HRESULT ( STDMETHODCALLTYPE *EndEnumMethodDefinitionsByAddress )(
+ IXCLRDataProcess2 * This,
+ /* [in] */ CLRDATA_ENUM handle);
+
+ HRESULT ( STDMETHODCALLTYPE *FollowStub )(
+ IXCLRDataProcess2 * This,
+ /* [in] */ ULONG32 inFlags,
+ /* [in] */ CLRDATA_ADDRESS inAddr,
+ /* [in] */ CLRDATA_FOLLOW_STUB_BUFFER *inBuffer,
+ /* [out] */ CLRDATA_ADDRESS *outAddr,
+ /* [out] */ CLRDATA_FOLLOW_STUB_BUFFER *outBuffer,
+ /* [out] */ ULONG32 *outFlags);
+
+ HRESULT ( STDMETHODCALLTYPE *FollowStub2 )(
+ IXCLRDataProcess2 * This,
+ /* [in] */ IXCLRDataTask *task,
+ /* [in] */ ULONG32 inFlags,
+ /* [in] */ CLRDATA_ADDRESS inAddr,
+ /* [in] */ CLRDATA_FOLLOW_STUB_BUFFER *inBuffer,
+ /* [out] */ CLRDATA_ADDRESS *outAddr,
+ /* [out] */ CLRDATA_FOLLOW_STUB_BUFFER *outBuffer,
+ /* [out] */ ULONG32 *outFlags);
+
+ HRESULT ( STDMETHODCALLTYPE *DumpNativeImage )(
+ IXCLRDataProcess2 * This,
+ /* [in] */ CLRDATA_ADDRESS loadedBase,
+ /* [in] */ LPCWSTR name,
+ /* [in] */ IXCLRDataDisplay *display,
+ /* [in] */ IXCLRLibrarySupport *libSupport,
+ /* [in] */ IXCLRDisassemblySupport *dis);
+
+ HRESULT ( STDMETHODCALLTYPE *GetGcNotification )(
+ IXCLRDataProcess2 * This,
+ /* [out][in] */ GcEvtArgs *gcEvtArgs);
+
+ HRESULT ( STDMETHODCALLTYPE *SetGcNotification )(
+ IXCLRDataProcess2 * This,
+ /* [in] */ GcEvtArgs gcEvtArgs);
+
+ END_INTERFACE
+ } IXCLRDataProcess2Vtbl;
+
+ interface IXCLRDataProcess2
+ {
+ CONST_VTBL struct IXCLRDataProcess2Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IXCLRDataProcess2_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IXCLRDataProcess2_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IXCLRDataProcess2_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IXCLRDataProcess2_Flush(This) \
+ ( (This)->lpVtbl -> Flush(This) )
+
+#define IXCLRDataProcess2_StartEnumTasks(This,handle) \
+ ( (This)->lpVtbl -> StartEnumTasks(This,handle) )
+
+#define IXCLRDataProcess2_EnumTask(This,handle,task) \
+ ( (This)->lpVtbl -> EnumTask(This,handle,task) )
+
+#define IXCLRDataProcess2_EndEnumTasks(This,handle) \
+ ( (This)->lpVtbl -> EndEnumTasks(This,handle) )
+
+#define IXCLRDataProcess2_GetTaskByOSThreadID(This,osThreadID,task) \
+ ( (This)->lpVtbl -> GetTaskByOSThreadID(This,osThreadID,task) )
+
+#define IXCLRDataProcess2_GetTaskByUniqueID(This,taskID,task) \
+ ( (This)->lpVtbl -> GetTaskByUniqueID(This,taskID,task) )
+
+#define IXCLRDataProcess2_GetFlags(This,flags) \
+ ( (This)->lpVtbl -> GetFlags(This,flags) )
+
+#define IXCLRDataProcess2_IsSameObject(This,process) \
+ ( (This)->lpVtbl -> IsSameObject(This,process) )
+
+#define IXCLRDataProcess2_GetManagedObject(This,value) \
+ ( (This)->lpVtbl -> GetManagedObject(This,value) )
+
+#define IXCLRDataProcess2_GetDesiredExecutionState(This,state) \
+ ( (This)->lpVtbl -> GetDesiredExecutionState(This,state) )
+
+#define IXCLRDataProcess2_SetDesiredExecutionState(This,state) \
+ ( (This)->lpVtbl -> SetDesiredExecutionState(This,state) )
+
+#define IXCLRDataProcess2_GetAddressType(This,address,type) \
+ ( (This)->lpVtbl -> GetAddressType(This,address,type) )
+
+#define IXCLRDataProcess2_GetRuntimeNameByAddress(This,address,flags,bufLen,nameLen,nameBuf,displacement) \
+ ( (This)->lpVtbl -> GetRuntimeNameByAddress(This,address,flags,bufLen,nameLen,nameBuf,displacement) )
+
+#define IXCLRDataProcess2_StartEnumAppDomains(This,handle) \
+ ( (This)->lpVtbl -> StartEnumAppDomains(This,handle) )
+
+#define IXCLRDataProcess2_EnumAppDomain(This,handle,appDomain) \
+ ( (This)->lpVtbl -> EnumAppDomain(This,handle,appDomain) )
+
+#define IXCLRDataProcess2_EndEnumAppDomains(This,handle) \
+ ( (This)->lpVtbl -> EndEnumAppDomains(This,handle) )
+
+#define IXCLRDataProcess2_GetAppDomainByUniqueID(This,id,appDomain) \
+ ( (This)->lpVtbl -> GetAppDomainByUniqueID(This,id,appDomain) )
+
+#define IXCLRDataProcess2_StartEnumAssemblies(This,handle) \
+ ( (This)->lpVtbl -> StartEnumAssemblies(This,handle) )
+
+#define IXCLRDataProcess2_EnumAssembly(This,handle,assembly) \
+ ( (This)->lpVtbl -> EnumAssembly(This,handle,assembly) )
+
+#define IXCLRDataProcess2_EndEnumAssemblies(This,handle) \
+ ( (This)->lpVtbl -> EndEnumAssemblies(This,handle) )
+
+#define IXCLRDataProcess2_StartEnumModules(This,handle) \
+ ( (This)->lpVtbl -> StartEnumModules(This,handle) )
+
+#define IXCLRDataProcess2_EnumModule(This,handle,mod) \
+ ( (This)->lpVtbl -> EnumModule(This,handle,mod) )
+
+#define IXCLRDataProcess2_EndEnumModules(This,handle) \
+ ( (This)->lpVtbl -> EndEnumModules(This,handle) )
+
+#define IXCLRDataProcess2_GetModuleByAddress(This,address,mod) \
+ ( (This)->lpVtbl -> GetModuleByAddress(This,address,mod) )
+
+#define IXCLRDataProcess2_StartEnumMethodInstancesByAddress(This,address,appDomain,handle) \
+ ( (This)->lpVtbl -> StartEnumMethodInstancesByAddress(This,address,appDomain,handle) )
+
+#define IXCLRDataProcess2_EnumMethodInstanceByAddress(This,handle,method) \
+ ( (This)->lpVtbl -> EnumMethodInstanceByAddress(This,handle,method) )
+
+#define IXCLRDataProcess2_EndEnumMethodInstancesByAddress(This,handle) \
+ ( (This)->lpVtbl -> EndEnumMethodInstancesByAddress(This,handle) )
+
+#define IXCLRDataProcess2_GetDataByAddress(This,address,flags,appDomain,tlsTask,bufLen,nameLen,nameBuf,value,displacement) \
+ ( (This)->lpVtbl -> GetDataByAddress(This,address,flags,appDomain,tlsTask,bufLen,nameLen,nameBuf,value,displacement) )
+
+#define IXCLRDataProcess2_GetExceptionStateByExceptionRecord(This,record,exState) \
+ ( (This)->lpVtbl -> GetExceptionStateByExceptionRecord(This,record,exState) )
+
+#define IXCLRDataProcess2_TranslateExceptionRecordToNotification(This,record,notify) \
+ ( (This)->lpVtbl -> TranslateExceptionRecordToNotification(This,record,notify) )
+
+#define IXCLRDataProcess2_Request(This,reqCode,inBufferSize,inBuffer,outBufferSize,outBuffer) \
+ ( (This)->lpVtbl -> Request(This,reqCode,inBufferSize,inBuffer,outBufferSize,outBuffer) )
+
+#define IXCLRDataProcess2_CreateMemoryValue(This,appDomain,tlsTask,type,addr,value) \
+ ( (This)->lpVtbl -> CreateMemoryValue(This,appDomain,tlsTask,type,addr,value) )
+
+#define IXCLRDataProcess2_SetAllTypeNotifications(This,mod,flags) \
+ ( (This)->lpVtbl -> SetAllTypeNotifications(This,mod,flags) )
+
+#define IXCLRDataProcess2_SetAllCodeNotifications(This,mod,flags) \
+ ( (This)->lpVtbl -> SetAllCodeNotifications(This,mod,flags) )
+
+#define IXCLRDataProcess2_GetTypeNotifications(This,numTokens,mods,singleMod,tokens,flags) \
+ ( (This)->lpVtbl -> GetTypeNotifications(This,numTokens,mods,singleMod,tokens,flags) )
+
+#define IXCLRDataProcess2_SetTypeNotifications(This,numTokens,mods,singleMod,tokens,flags,singleFlags) \
+ ( (This)->lpVtbl -> SetTypeNotifications(This,numTokens,mods,singleMod,tokens,flags,singleFlags) )
+
+#define IXCLRDataProcess2_GetCodeNotifications(This,numTokens,mods,singleMod,tokens,flags) \
+ ( (This)->lpVtbl -> GetCodeNotifications(This,numTokens,mods,singleMod,tokens,flags) )
+
+#define IXCLRDataProcess2_SetCodeNotifications(This,numTokens,mods,singleMod,tokens,flags,singleFlags) \
+ ( (This)->lpVtbl -> SetCodeNotifications(This,numTokens,mods,singleMod,tokens,flags,singleFlags) )
+
+#define IXCLRDataProcess2_GetOtherNotificationFlags(This,flags) \
+ ( (This)->lpVtbl -> GetOtherNotificationFlags(This,flags) )
+
+#define IXCLRDataProcess2_SetOtherNotificationFlags(This,flags) \
+ ( (This)->lpVtbl -> SetOtherNotificationFlags(This,flags) )
+
+#define IXCLRDataProcess2_StartEnumMethodDefinitionsByAddress(This,address,handle) \
+ ( (This)->lpVtbl -> StartEnumMethodDefinitionsByAddress(This,address,handle) )
+
+#define IXCLRDataProcess2_EnumMethodDefinitionByAddress(This,handle,method) \
+ ( (This)->lpVtbl -> EnumMethodDefinitionByAddress(This,handle,method) )
+
+#define IXCLRDataProcess2_EndEnumMethodDefinitionsByAddress(This,handle) \
+ ( (This)->lpVtbl -> EndEnumMethodDefinitionsByAddress(This,handle) )
+
+#define IXCLRDataProcess2_FollowStub(This,inFlags,inAddr,inBuffer,outAddr,outBuffer,outFlags) \
+ ( (This)->lpVtbl -> FollowStub(This,inFlags,inAddr,inBuffer,outAddr,outBuffer,outFlags) )
+
+#define IXCLRDataProcess2_FollowStub2(This,task,inFlags,inAddr,inBuffer,outAddr,outBuffer,outFlags) \
+ ( (This)->lpVtbl -> FollowStub2(This,task,inFlags,inAddr,inBuffer,outAddr,outBuffer,outFlags) )
+
+#define IXCLRDataProcess2_DumpNativeImage(This,loadedBase,name,display,libSupport,dis) \
+ ( (This)->lpVtbl -> DumpNativeImage(This,loadedBase,name,display,libSupport,dis) )
+
+
+#define IXCLRDataProcess2_GetGcNotification(This,gcEvtArgs) \
+ ( (This)->lpVtbl -> GetGcNotification(This,gcEvtArgs) )
+
+#define IXCLRDataProcess2_SetGcNotification(This,gcEvtArgs) \
+ ( (This)->lpVtbl -> SetGcNotification(This,gcEvtArgs) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IXCLRDataProcess2_INTERFACE_DEFINED__ */
+
+
+/* interface __MIDL_itf_xclrdata_0000_0006 */
+/* [local] */
+
+typedef /* [public] */
+enum __MIDL___MIDL_itf_xclrdata_0000_0006_0001
+ {
+ CLRDATA_DOMAIN_DEFAULT = 0
+ } CLRDataAppDomainFlag;
+
+#pragma warning(push)
+#pragma warning(disable:28718)
+
+
+extern RPC_IF_HANDLE __MIDL_itf_xclrdata_0000_0006_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_xclrdata_0000_0006_v0_0_s_ifspec;
+
+#ifndef __IXCLRDataAppDomain_INTERFACE_DEFINED__
+#define __IXCLRDataAppDomain_INTERFACE_DEFINED__
+
+/* interface IXCLRDataAppDomain */
+/* [uuid][local][object] */
+
+
+EXTERN_C const IID IID_IXCLRDataAppDomain;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("7CA04601-C702-4670-A63C-FA44F7DA7BD5")
+ IXCLRDataAppDomain : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetProcess(
+ /* [out] */ IXCLRDataProcess **process) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetName(
+ /* [in] */ ULONG32 bufLen,
+ /* [out] */ ULONG32 *nameLen,
+ /* [size_is][out] */ WCHAR name[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetUniqueID(
+ /* [out] */ ULONG64 *id) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetFlags(
+ /* [out] */ ULONG32 *flags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE IsSameObject(
+ /* [in] */ IXCLRDataAppDomain *appDomain) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetManagedObject(
+ /* [out] */ IXCLRDataValue **value) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Request(
+ /* [in] */ ULONG32 reqCode,
+ /* [in] */ ULONG32 inBufferSize,
+ /* [size_is][in] */ BYTE *inBuffer,
+ /* [in] */ ULONG32 outBufferSize,
+ /* [size_is][out] */ BYTE *outBuffer) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IXCLRDataAppDomainVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IXCLRDataAppDomain * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IXCLRDataAppDomain * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IXCLRDataAppDomain * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetProcess )(
+ IXCLRDataAppDomain * This,
+ /* [out] */ IXCLRDataProcess **process);
+
+ HRESULT ( STDMETHODCALLTYPE *GetName )(
+ IXCLRDataAppDomain * This,
+ /* [in] */ ULONG32 bufLen,
+ /* [out] */ ULONG32 *nameLen,
+ /* [size_is][out] */ WCHAR name[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetUniqueID )(
+ IXCLRDataAppDomain * This,
+ /* [out] */ ULONG64 *id);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFlags )(
+ IXCLRDataAppDomain * This,
+ /* [out] */ ULONG32 *flags);
+
+ HRESULT ( STDMETHODCALLTYPE *IsSameObject )(
+ IXCLRDataAppDomain * This,
+ /* [in] */ IXCLRDataAppDomain *appDomain);
+
+ HRESULT ( STDMETHODCALLTYPE *GetManagedObject )(
+ IXCLRDataAppDomain * This,
+ /* [out] */ IXCLRDataValue **value);
+
+ HRESULT ( STDMETHODCALLTYPE *Request )(
+ IXCLRDataAppDomain * This,
+ /* [in] */ ULONG32 reqCode,
+ /* [in] */ ULONG32 inBufferSize,
+ /* [size_is][in] */ BYTE *inBuffer,
+ /* [in] */ ULONG32 outBufferSize,
+ /* [size_is][out] */ BYTE *outBuffer);
+
+ END_INTERFACE
+ } IXCLRDataAppDomainVtbl;
+
+ interface IXCLRDataAppDomain
+ {
+ CONST_VTBL struct IXCLRDataAppDomainVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IXCLRDataAppDomain_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IXCLRDataAppDomain_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IXCLRDataAppDomain_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IXCLRDataAppDomain_GetProcess(This,process) \
+ ( (This)->lpVtbl -> GetProcess(This,process) )
+
+#define IXCLRDataAppDomain_GetName(This,bufLen,nameLen,name) \
+ ( (This)->lpVtbl -> GetName(This,bufLen,nameLen,name) )
+
+#define IXCLRDataAppDomain_GetUniqueID(This,id) \
+ ( (This)->lpVtbl -> GetUniqueID(This,id) )
+
+#define IXCLRDataAppDomain_GetFlags(This,flags) \
+ ( (This)->lpVtbl -> GetFlags(This,flags) )
+
+#define IXCLRDataAppDomain_IsSameObject(This,appDomain) \
+ ( (This)->lpVtbl -> IsSameObject(This,appDomain) )
+
+#define IXCLRDataAppDomain_GetManagedObject(This,value) \
+ ( (This)->lpVtbl -> GetManagedObject(This,value) )
+
+#define IXCLRDataAppDomain_Request(This,reqCode,inBufferSize,inBuffer,outBufferSize,outBuffer) \
+ ( (This)->lpVtbl -> Request(This,reqCode,inBufferSize,inBuffer,outBufferSize,outBuffer) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IXCLRDataAppDomain_INTERFACE_DEFINED__ */
+
+
+/* interface __MIDL_itf_xclrdata_0000_0007 */
+/* [local] */
+
+#pragma warning(pop)
+typedef /* [public] */
+enum __MIDL___MIDL_itf_xclrdata_0000_0007_0001
+ {
+ CLRDATA_ASSEMBLY_DEFAULT = 0
+ } CLRDataAssemblyFlag;
+
+#pragma warning(push)
+#pragma warning(disable:28718)
+
+
+extern RPC_IF_HANDLE __MIDL_itf_xclrdata_0000_0007_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_xclrdata_0000_0007_v0_0_s_ifspec;
+
+#ifndef __IXCLRDataAssembly_INTERFACE_DEFINED__
+#define __IXCLRDataAssembly_INTERFACE_DEFINED__
+
+/* interface IXCLRDataAssembly */
+/* [uuid][local][object] */
+
+
+EXTERN_C const IID IID_IXCLRDataAssembly;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("2FA17588-43C2-46ab-9B51-C8F01E39C9AC")
+ IXCLRDataAssembly : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE StartEnumModules(
+ /* [out] */ CLRDATA_ENUM *handle) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnumModule(
+ /* [out][in] */ CLRDATA_ENUM *handle,
+ /* [out] */ IXCLRDataModule **mod) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EndEnumModules(
+ /* [in] */ CLRDATA_ENUM handle) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetName(
+ /* [in] */ ULONG32 bufLen,
+ /* [out] */ ULONG32 *nameLen,
+ /* [size_is][out] */ WCHAR name[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetFileName(
+ /* [in] */ ULONG32 bufLen,
+ /* [out] */ ULONG32 *nameLen,
+ /* [size_is][out] */ WCHAR name[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetFlags(
+ /* [out] */ ULONG32 *flags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE IsSameObject(
+ /* [in] */ IXCLRDataAssembly *assembly) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Request(
+ /* [in] */ ULONG32 reqCode,
+ /* [in] */ ULONG32 inBufferSize,
+ /* [size_is][in] */ BYTE *inBuffer,
+ /* [in] */ ULONG32 outBufferSize,
+ /* [size_is][out] */ BYTE *outBuffer) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StartEnumAppDomains(
+ /* [out] */ CLRDATA_ENUM *handle) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnumAppDomain(
+ /* [out][in] */ CLRDATA_ENUM *handle,
+ /* [out] */ IXCLRDataAppDomain **appDomain) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EndEnumAppDomains(
+ /* [in] */ CLRDATA_ENUM handle) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetDisplayName(
+ /* [in] */ ULONG32 bufLen,
+ /* [out] */ ULONG32 *nameLen,
+ /* [size_is][out] */ WCHAR name[ ]) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IXCLRDataAssemblyVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IXCLRDataAssembly * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IXCLRDataAssembly * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IXCLRDataAssembly * This);
+
+ HRESULT ( STDMETHODCALLTYPE *StartEnumModules )(
+ IXCLRDataAssembly * This,
+ /* [out] */ CLRDATA_ENUM *handle);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumModule )(
+ IXCLRDataAssembly * This,
+ /* [out][in] */ CLRDATA_ENUM *handle,
+ /* [out] */ IXCLRDataModule **mod);
+
+ HRESULT ( STDMETHODCALLTYPE *EndEnumModules )(
+ IXCLRDataAssembly * This,
+ /* [in] */ CLRDATA_ENUM handle);
+
+ HRESULT ( STDMETHODCALLTYPE *GetName )(
+ IXCLRDataAssembly * This,
+ /* [in] */ ULONG32 bufLen,
+ /* [out] */ ULONG32 *nameLen,
+ /* [size_is][out] */ WCHAR name[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFileName )(
+ IXCLRDataAssembly * This,
+ /* [in] */ ULONG32 bufLen,
+ /* [out] */ ULONG32 *nameLen,
+ /* [size_is][out] */ WCHAR name[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFlags )(
+ IXCLRDataAssembly * This,
+ /* [out] */ ULONG32 *flags);
+
+ HRESULT ( STDMETHODCALLTYPE *IsSameObject )(
+ IXCLRDataAssembly * This,
+ /* [in] */ IXCLRDataAssembly *assembly);
+
+ HRESULT ( STDMETHODCALLTYPE *Request )(
+ IXCLRDataAssembly * This,
+ /* [in] */ ULONG32 reqCode,
+ /* [in] */ ULONG32 inBufferSize,
+ /* [size_is][in] */ BYTE *inBuffer,
+ /* [in] */ ULONG32 outBufferSize,
+ /* [size_is][out] */ BYTE *outBuffer);
+
+ HRESULT ( STDMETHODCALLTYPE *StartEnumAppDomains )(
+ IXCLRDataAssembly * This,
+ /* [out] */ CLRDATA_ENUM *handle);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumAppDomain )(
+ IXCLRDataAssembly * This,
+ /* [out][in] */ CLRDATA_ENUM *handle,
+ /* [out] */ IXCLRDataAppDomain **appDomain);
+
+ HRESULT ( STDMETHODCALLTYPE *EndEnumAppDomains )(
+ IXCLRDataAssembly * This,
+ /* [in] */ CLRDATA_ENUM handle);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDisplayName )(
+ IXCLRDataAssembly * This,
+ /* [in] */ ULONG32 bufLen,
+ /* [out] */ ULONG32 *nameLen,
+ /* [size_is][out] */ WCHAR name[ ]);
+
+ END_INTERFACE
+ } IXCLRDataAssemblyVtbl;
+
+ interface IXCLRDataAssembly
+ {
+ CONST_VTBL struct IXCLRDataAssemblyVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IXCLRDataAssembly_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IXCLRDataAssembly_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IXCLRDataAssembly_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IXCLRDataAssembly_StartEnumModules(This,handle) \
+ ( (This)->lpVtbl -> StartEnumModules(This,handle) )
+
+#define IXCLRDataAssembly_EnumModule(This,handle,mod) \
+ ( (This)->lpVtbl -> EnumModule(This,handle,mod) )
+
+#define IXCLRDataAssembly_EndEnumModules(This,handle) \
+ ( (This)->lpVtbl -> EndEnumModules(This,handle) )
+
+#define IXCLRDataAssembly_GetName(This,bufLen,nameLen,name) \
+ ( (This)->lpVtbl -> GetName(This,bufLen,nameLen,name) )
+
+#define IXCLRDataAssembly_GetFileName(This,bufLen,nameLen,name) \
+ ( (This)->lpVtbl -> GetFileName(This,bufLen,nameLen,name) )
+
+#define IXCLRDataAssembly_GetFlags(This,flags) \
+ ( (This)->lpVtbl -> GetFlags(This,flags) )
+
+#define IXCLRDataAssembly_IsSameObject(This,assembly) \
+ ( (This)->lpVtbl -> IsSameObject(This,assembly) )
+
+#define IXCLRDataAssembly_Request(This,reqCode,inBufferSize,inBuffer,outBufferSize,outBuffer) \
+ ( (This)->lpVtbl -> Request(This,reqCode,inBufferSize,inBuffer,outBufferSize,outBuffer) )
+
+#define IXCLRDataAssembly_StartEnumAppDomains(This,handle) \
+ ( (This)->lpVtbl -> StartEnumAppDomains(This,handle) )
+
+#define IXCLRDataAssembly_EnumAppDomain(This,handle,appDomain) \
+ ( (This)->lpVtbl -> EnumAppDomain(This,handle,appDomain) )
+
+#define IXCLRDataAssembly_EndEnumAppDomains(This,handle) \
+ ( (This)->lpVtbl -> EndEnumAppDomains(This,handle) )
+
+#define IXCLRDataAssembly_GetDisplayName(This,bufLen,nameLen,name) \
+ ( (This)->lpVtbl -> GetDisplayName(This,bufLen,nameLen,name) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IXCLRDataAssembly_INTERFACE_DEFINED__ */
+
+
+/* interface __MIDL_itf_xclrdata_0000_0008 */
+/* [local] */
+
+#pragma warning(pop)
+typedef /* [public] */
+enum __MIDL___MIDL_itf_xclrdata_0000_0008_0001
+ {
+ CLRDATA_MODULE_DEFAULT = 0,
+ CLRDATA_MODULE_IS_DYNAMIC = 0x1,
+ CLRDATA_MODULE_IS_MEMORY_STREAM = 0x2
+ } CLRDataModuleFlag;
+
+typedef /* [public][public][public] */
+enum __MIDL___MIDL_itf_xclrdata_0000_0008_0002
+ {
+ CLRDATA_MODULE_PE_FILE = 0,
+ CLRDATA_MODULE_PREJIT_FILE = ( CLRDATA_MODULE_PE_FILE + 1 ) ,
+ CLRDATA_MODULE_MEMORY_STREAM = ( CLRDATA_MODULE_PREJIT_FILE + 1 ) ,
+ CLRDATA_MODULE_OTHER = ( CLRDATA_MODULE_MEMORY_STREAM + 1 )
+ } CLRDataModuleExtentType;
+
+typedef /* [public][public] */ struct __MIDL___MIDL_itf_xclrdata_0000_0008_0003
+ {
+ CLRDATA_ADDRESS base;
+ ULONG32 length;
+ CLRDataModuleExtentType type;
+ } CLRDATA_MODULE_EXTENT;
+
+typedef /* [public] */
+enum __MIDL___MIDL_itf_xclrdata_0000_0008_0004
+ {
+ CLRDATA_TYPENOTIFY_NONE = 0,
+ CLRDATA_TYPENOTIFY_LOADED = 0x1,
+ CLRDATA_TYPENOTIFY_UNLOADED = 0x2
+ } CLRDataTypeNotification;
+
+typedef /* [public] */
+enum __MIDL___MIDL_itf_xclrdata_0000_0008_0005
+ {
+ CLRDATA_METHNOTIFY_NONE = 0,
+ CLRDATA_METHNOTIFY_GENERATED = 0x1,
+ CLRDATA_METHNOTIFY_DISCARDED = 0x2
+ } CLRDataMethodCodeNotification;
+
+#pragma warning(push)
+#pragma warning(disable:28718)
+
+
+extern RPC_IF_HANDLE __MIDL_itf_xclrdata_0000_0008_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_xclrdata_0000_0008_v0_0_s_ifspec;
+
+#ifndef __IXCLRDataModule_INTERFACE_DEFINED__
+#define __IXCLRDataModule_INTERFACE_DEFINED__
+
+/* interface IXCLRDataModule */
+/* [uuid][local][object] */
+
+
+EXTERN_C const IID IID_IXCLRDataModule;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("88E32849-0A0A-4cb0-9022-7CD2E9E139E2")
+ IXCLRDataModule : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE StartEnumAssemblies(
+ /* [out] */ CLRDATA_ENUM *handle) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnumAssembly(
+ /* [out][in] */ CLRDATA_ENUM *handle,
+ /* [out] */ IXCLRDataAssembly **assembly) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EndEnumAssemblies(
+ /* [in] */ CLRDATA_ENUM handle) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StartEnumTypeDefinitions(
+ /* [out] */ CLRDATA_ENUM *handle) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnumTypeDefinition(
+ /* [out][in] */ CLRDATA_ENUM *handle,
+ /* [out] */ IXCLRDataTypeDefinition **typeDefinition) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EndEnumTypeDefinitions(
+ /* [in] */ CLRDATA_ENUM handle) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StartEnumTypeInstances(
+ /* [in] */ IXCLRDataAppDomain *appDomain,
+ /* [out] */ CLRDATA_ENUM *handle) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnumTypeInstance(
+ /* [out][in] */ CLRDATA_ENUM *handle,
+ /* [out] */ IXCLRDataTypeInstance **typeInstance) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EndEnumTypeInstances(
+ /* [in] */ CLRDATA_ENUM handle) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StartEnumTypeDefinitionsByName(
+ /* [in] */ LPCWSTR name,
+ /* [in] */ ULONG32 flags,
+ /* [out] */ CLRDATA_ENUM *handle) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnumTypeDefinitionByName(
+ /* [out][in] */ CLRDATA_ENUM *handle,
+ /* [out] */ IXCLRDataTypeDefinition **type) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EndEnumTypeDefinitionsByName(
+ /* [in] */ CLRDATA_ENUM handle) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StartEnumTypeInstancesByName(
+ /* [in] */ LPCWSTR name,
+ /* [in] */ ULONG32 flags,
+ /* [in] */ IXCLRDataAppDomain *appDomain,
+ /* [out] */ CLRDATA_ENUM *handle) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnumTypeInstanceByName(
+ /* [out][in] */ CLRDATA_ENUM *handle,
+ /* [out] */ IXCLRDataTypeInstance **type) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EndEnumTypeInstancesByName(
+ /* [in] */ CLRDATA_ENUM handle) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetTypeDefinitionByToken(
+ /* [in] */ mdTypeDef token,
+ /* [out] */ IXCLRDataTypeDefinition **typeDefinition) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StartEnumMethodDefinitionsByName(
+ /* [in] */ LPCWSTR name,
+ /* [in] */ ULONG32 flags,
+ /* [out] */ CLRDATA_ENUM *handle) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnumMethodDefinitionByName(
+ /* [out][in] */ CLRDATA_ENUM *handle,
+ /* [out] */ IXCLRDataMethodDefinition **method) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EndEnumMethodDefinitionsByName(
+ /* [in] */ CLRDATA_ENUM handle) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StartEnumMethodInstancesByName(
+ /* [in] */ LPCWSTR name,
+ /* [in] */ ULONG32 flags,
+ /* [in] */ IXCLRDataAppDomain *appDomain,
+ /* [out] */ CLRDATA_ENUM *handle) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnumMethodInstanceByName(
+ /* [out][in] */ CLRDATA_ENUM *handle,
+ /* [out] */ IXCLRDataMethodInstance **method) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EndEnumMethodInstancesByName(
+ /* [in] */ CLRDATA_ENUM handle) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetMethodDefinitionByToken(
+ /* [in] */ mdMethodDef token,
+ /* [out] */ IXCLRDataMethodDefinition **methodDefinition) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StartEnumDataByName(
+ /* [in] */ LPCWSTR name,
+ /* [in] */ ULONG32 flags,
+ /* [in] */ IXCLRDataAppDomain *appDomain,
+ /* [in] */ IXCLRDataTask *tlsTask,
+ /* [out] */ CLRDATA_ENUM *handle) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnumDataByName(
+ /* [out][in] */ CLRDATA_ENUM *handle,
+ /* [out] */ IXCLRDataValue **value) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EndEnumDataByName(
+ /* [in] */ CLRDATA_ENUM handle) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetName(
+ /* [in] */ ULONG32 bufLen,
+ /* [out] */ ULONG32 *nameLen,
+ /* [size_is][out] */ WCHAR name[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetFileName(
+ /* [in] */ ULONG32 bufLen,
+ /* [out] */ ULONG32 *nameLen,
+ /* [size_is][out] */ WCHAR name[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetFlags(
+ /* [out] */ ULONG32 *flags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE IsSameObject(
+ /* [in] */ IXCLRDataModule *mod) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StartEnumExtents(
+ /* [out] */ CLRDATA_ENUM *handle) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnumExtent(
+ /* [out][in] */ CLRDATA_ENUM *handle,
+ /* [out] */ CLRDATA_MODULE_EXTENT *extent) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EndEnumExtents(
+ /* [in] */ CLRDATA_ENUM handle) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Request(
+ /* [in] */ ULONG32 reqCode,
+ /* [in] */ ULONG32 inBufferSize,
+ /* [size_is][in] */ BYTE *inBuffer,
+ /* [in] */ ULONG32 outBufferSize,
+ /* [size_is][out] */ BYTE *outBuffer) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StartEnumAppDomains(
+ /* [out] */ CLRDATA_ENUM *handle) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnumAppDomain(
+ /* [out][in] */ CLRDATA_ENUM *handle,
+ /* [out] */ IXCLRDataAppDomain **appDomain) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EndEnumAppDomains(
+ /* [in] */ CLRDATA_ENUM handle) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetVersionId(
+ /* [out] */ GUID *vid) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IXCLRDataModuleVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IXCLRDataModule * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IXCLRDataModule * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IXCLRDataModule * This);
+
+ HRESULT ( STDMETHODCALLTYPE *StartEnumAssemblies )(
+ IXCLRDataModule * This,
+ /* [out] */ CLRDATA_ENUM *handle);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumAssembly )(
+ IXCLRDataModule * This,
+ /* [out][in] */ CLRDATA_ENUM *handle,
+ /* [out] */ IXCLRDataAssembly **assembly);
+
+ HRESULT ( STDMETHODCALLTYPE *EndEnumAssemblies )(
+ IXCLRDataModule * This,
+ /* [in] */ CLRDATA_ENUM handle);
+
+ HRESULT ( STDMETHODCALLTYPE *StartEnumTypeDefinitions )(
+ IXCLRDataModule * This,
+ /* [out] */ CLRDATA_ENUM *handle);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumTypeDefinition )(
+ IXCLRDataModule * This,
+ /* [out][in] */ CLRDATA_ENUM *handle,
+ /* [out] */ IXCLRDataTypeDefinition **typeDefinition);
+
+ HRESULT ( STDMETHODCALLTYPE *EndEnumTypeDefinitions )(
+ IXCLRDataModule * This,
+ /* [in] */ CLRDATA_ENUM handle);
+
+ HRESULT ( STDMETHODCALLTYPE *StartEnumTypeInstances )(
+ IXCLRDataModule * This,
+ /* [in] */ IXCLRDataAppDomain *appDomain,
+ /* [out] */ CLRDATA_ENUM *handle);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumTypeInstance )(
+ IXCLRDataModule * This,
+ /* [out][in] */ CLRDATA_ENUM *handle,
+ /* [out] */ IXCLRDataTypeInstance **typeInstance);
+
+ HRESULT ( STDMETHODCALLTYPE *EndEnumTypeInstances )(
+ IXCLRDataModule * This,
+ /* [in] */ CLRDATA_ENUM handle);
+
+ HRESULT ( STDMETHODCALLTYPE *StartEnumTypeDefinitionsByName )(
+ IXCLRDataModule * This,
+ /* [in] */ LPCWSTR name,
+ /* [in] */ ULONG32 flags,
+ /* [out] */ CLRDATA_ENUM *handle);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumTypeDefinitionByName )(
+ IXCLRDataModule * This,
+ /* [out][in] */ CLRDATA_ENUM *handle,
+ /* [out] */ IXCLRDataTypeDefinition **type);
+
+ HRESULT ( STDMETHODCALLTYPE *EndEnumTypeDefinitionsByName )(
+ IXCLRDataModule * This,
+ /* [in] */ CLRDATA_ENUM handle);
+
+ HRESULT ( STDMETHODCALLTYPE *StartEnumTypeInstancesByName )(
+ IXCLRDataModule * This,
+ /* [in] */ LPCWSTR name,
+ /* [in] */ ULONG32 flags,
+ /* [in] */ IXCLRDataAppDomain *appDomain,
+ /* [out] */ CLRDATA_ENUM *handle);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumTypeInstanceByName )(
+ IXCLRDataModule * This,
+ /* [out][in] */ CLRDATA_ENUM *handle,
+ /* [out] */ IXCLRDataTypeInstance **type);
+
+ HRESULT ( STDMETHODCALLTYPE *EndEnumTypeInstancesByName )(
+ IXCLRDataModule * This,
+ /* [in] */ CLRDATA_ENUM handle);
+
+ HRESULT ( STDMETHODCALLTYPE *GetTypeDefinitionByToken )(
+ IXCLRDataModule * This,
+ /* [in] */ mdTypeDef token,
+ /* [out] */ IXCLRDataTypeDefinition **typeDefinition);
+
+ HRESULT ( STDMETHODCALLTYPE *StartEnumMethodDefinitionsByName )(
+ IXCLRDataModule * This,
+ /* [in] */ LPCWSTR name,
+ /* [in] */ ULONG32 flags,
+ /* [out] */ CLRDATA_ENUM *handle);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumMethodDefinitionByName )(
+ IXCLRDataModule * This,
+ /* [out][in] */ CLRDATA_ENUM *handle,
+ /* [out] */ IXCLRDataMethodDefinition **method);
+
+ HRESULT ( STDMETHODCALLTYPE *EndEnumMethodDefinitionsByName )(
+ IXCLRDataModule * This,
+ /* [in] */ CLRDATA_ENUM handle);
+
+ HRESULT ( STDMETHODCALLTYPE *StartEnumMethodInstancesByName )(
+ IXCLRDataModule * This,
+ /* [in] */ LPCWSTR name,
+ /* [in] */ ULONG32 flags,
+ /* [in] */ IXCLRDataAppDomain *appDomain,
+ /* [out] */ CLRDATA_ENUM *handle);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumMethodInstanceByName )(
+ IXCLRDataModule * This,
+ /* [out][in] */ CLRDATA_ENUM *handle,
+ /* [out] */ IXCLRDataMethodInstance **method);
+
+ HRESULT ( STDMETHODCALLTYPE *EndEnumMethodInstancesByName )(
+ IXCLRDataModule * This,
+ /* [in] */ CLRDATA_ENUM handle);
+
+ HRESULT ( STDMETHODCALLTYPE *GetMethodDefinitionByToken )(
+ IXCLRDataModule * This,
+ /* [in] */ mdMethodDef token,
+ /* [out] */ IXCLRDataMethodDefinition **methodDefinition);
+
+ HRESULT ( STDMETHODCALLTYPE *StartEnumDataByName )(
+ IXCLRDataModule * This,
+ /* [in] */ LPCWSTR name,
+ /* [in] */ ULONG32 flags,
+ /* [in] */ IXCLRDataAppDomain *appDomain,
+ /* [in] */ IXCLRDataTask *tlsTask,
+ /* [out] */ CLRDATA_ENUM *handle);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumDataByName )(
+ IXCLRDataModule * This,
+ /* [out][in] */ CLRDATA_ENUM *handle,
+ /* [out] */ IXCLRDataValue **value);
+
+ HRESULT ( STDMETHODCALLTYPE *EndEnumDataByName )(
+ IXCLRDataModule * This,
+ /* [in] */ CLRDATA_ENUM handle);
+
+ HRESULT ( STDMETHODCALLTYPE *GetName )(
+ IXCLRDataModule * This,
+ /* [in] */ ULONG32 bufLen,
+ /* [out] */ ULONG32 *nameLen,
+ /* [size_is][out] */ WCHAR name[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFileName )(
+ IXCLRDataModule * This,
+ /* [in] */ ULONG32 bufLen,
+ /* [out] */ ULONG32 *nameLen,
+ /* [size_is][out] */ WCHAR name[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFlags )(
+ IXCLRDataModule * This,
+ /* [out] */ ULONG32 *flags);
+
+ HRESULT ( STDMETHODCALLTYPE *IsSameObject )(
+ IXCLRDataModule * This,
+ /* [in] */ IXCLRDataModule *mod);
+
+ HRESULT ( STDMETHODCALLTYPE *StartEnumExtents )(
+ IXCLRDataModule * This,
+ /* [out] */ CLRDATA_ENUM *handle);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumExtent )(
+ IXCLRDataModule * This,
+ /* [out][in] */ CLRDATA_ENUM *handle,
+ /* [out] */ CLRDATA_MODULE_EXTENT *extent);
+
+ HRESULT ( STDMETHODCALLTYPE *EndEnumExtents )(
+ IXCLRDataModule * This,
+ /* [in] */ CLRDATA_ENUM handle);
+
+ HRESULT ( STDMETHODCALLTYPE *Request )(
+ IXCLRDataModule * This,
+ /* [in] */ ULONG32 reqCode,
+ /* [in] */ ULONG32 inBufferSize,
+ /* [size_is][in] */ BYTE *inBuffer,
+ /* [in] */ ULONG32 outBufferSize,
+ /* [size_is][out] */ BYTE *outBuffer);
+
+ HRESULT ( STDMETHODCALLTYPE *StartEnumAppDomains )(
+ IXCLRDataModule * This,
+ /* [out] */ CLRDATA_ENUM *handle);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumAppDomain )(
+ IXCLRDataModule * This,
+ /* [out][in] */ CLRDATA_ENUM *handle,
+ /* [out] */ IXCLRDataAppDomain **appDomain);
+
+ HRESULT ( STDMETHODCALLTYPE *EndEnumAppDomains )(
+ IXCLRDataModule * This,
+ /* [in] */ CLRDATA_ENUM handle);
+
+ HRESULT ( STDMETHODCALLTYPE *GetVersionId )(
+ IXCLRDataModule * This,
+ /* [out] */ GUID *vid);
+
+ END_INTERFACE
+ } IXCLRDataModuleVtbl;
+
+ interface IXCLRDataModule
+ {
+ CONST_VTBL struct IXCLRDataModuleVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IXCLRDataModule_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IXCLRDataModule_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IXCLRDataModule_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IXCLRDataModule_StartEnumAssemblies(This,handle) \
+ ( (This)->lpVtbl -> StartEnumAssemblies(This,handle) )
+
+#define IXCLRDataModule_EnumAssembly(This,handle,assembly) \
+ ( (This)->lpVtbl -> EnumAssembly(This,handle,assembly) )
+
+#define IXCLRDataModule_EndEnumAssemblies(This,handle) \
+ ( (This)->lpVtbl -> EndEnumAssemblies(This,handle) )
+
+#define IXCLRDataModule_StartEnumTypeDefinitions(This,handle) \
+ ( (This)->lpVtbl -> StartEnumTypeDefinitions(This,handle) )
+
+#define IXCLRDataModule_EnumTypeDefinition(This,handle,typeDefinition) \
+ ( (This)->lpVtbl -> EnumTypeDefinition(This,handle,typeDefinition) )
+
+#define IXCLRDataModule_EndEnumTypeDefinitions(This,handle) \
+ ( (This)->lpVtbl -> EndEnumTypeDefinitions(This,handle) )
+
+#define IXCLRDataModule_StartEnumTypeInstances(This,appDomain,handle) \
+ ( (This)->lpVtbl -> StartEnumTypeInstances(This,appDomain,handle) )
+
+#define IXCLRDataModule_EnumTypeInstance(This,handle,typeInstance) \
+ ( (This)->lpVtbl -> EnumTypeInstance(This,handle,typeInstance) )
+
+#define IXCLRDataModule_EndEnumTypeInstances(This,handle) \
+ ( (This)->lpVtbl -> EndEnumTypeInstances(This,handle) )
+
+#define IXCLRDataModule_StartEnumTypeDefinitionsByName(This,name,flags,handle) \
+ ( (This)->lpVtbl -> StartEnumTypeDefinitionsByName(This,name,flags,handle) )
+
+#define IXCLRDataModule_EnumTypeDefinitionByName(This,handle,type) \
+ ( (This)->lpVtbl -> EnumTypeDefinitionByName(This,handle,type) )
+
+#define IXCLRDataModule_EndEnumTypeDefinitionsByName(This,handle) \
+ ( (This)->lpVtbl -> EndEnumTypeDefinitionsByName(This,handle) )
+
+#define IXCLRDataModule_StartEnumTypeInstancesByName(This,name,flags,appDomain,handle) \
+ ( (This)->lpVtbl -> StartEnumTypeInstancesByName(This,name,flags,appDomain,handle) )
+
+#define IXCLRDataModule_EnumTypeInstanceByName(This,handle,type) \
+ ( (This)->lpVtbl -> EnumTypeInstanceByName(This,handle,type) )
+
+#define IXCLRDataModule_EndEnumTypeInstancesByName(This,handle) \
+ ( (This)->lpVtbl -> EndEnumTypeInstancesByName(This,handle) )
+
+#define IXCLRDataModule_GetTypeDefinitionByToken(This,token,typeDefinition) \
+ ( (This)->lpVtbl -> GetTypeDefinitionByToken(This,token,typeDefinition) )
+
+#define IXCLRDataModule_StartEnumMethodDefinitionsByName(This,name,flags,handle) \
+ ( (This)->lpVtbl -> StartEnumMethodDefinitionsByName(This,name,flags,handle) )
+
+#define IXCLRDataModule_EnumMethodDefinitionByName(This,handle,method) \
+ ( (This)->lpVtbl -> EnumMethodDefinitionByName(This,handle,method) )
+
+#define IXCLRDataModule_EndEnumMethodDefinitionsByName(This,handle) \
+ ( (This)->lpVtbl -> EndEnumMethodDefinitionsByName(This,handle) )
+
+#define IXCLRDataModule_StartEnumMethodInstancesByName(This,name,flags,appDomain,handle) \
+ ( (This)->lpVtbl -> StartEnumMethodInstancesByName(This,name,flags,appDomain,handle) )
+
+#define IXCLRDataModule_EnumMethodInstanceByName(This,handle,method) \
+ ( (This)->lpVtbl -> EnumMethodInstanceByName(This,handle,method) )
+
+#define IXCLRDataModule_EndEnumMethodInstancesByName(This,handle) \
+ ( (This)->lpVtbl -> EndEnumMethodInstancesByName(This,handle) )
+
+#define IXCLRDataModule_GetMethodDefinitionByToken(This,token,methodDefinition) \
+ ( (This)->lpVtbl -> GetMethodDefinitionByToken(This,token,methodDefinition) )
+
+#define IXCLRDataModule_StartEnumDataByName(This,name,flags,appDomain,tlsTask,handle) \
+ ( (This)->lpVtbl -> StartEnumDataByName(This,name,flags,appDomain,tlsTask,handle) )
+
+#define IXCLRDataModule_EnumDataByName(This,handle,value) \
+ ( (This)->lpVtbl -> EnumDataByName(This,handle,value) )
+
+#define IXCLRDataModule_EndEnumDataByName(This,handle) \
+ ( (This)->lpVtbl -> EndEnumDataByName(This,handle) )
+
+#define IXCLRDataModule_GetName(This,bufLen,nameLen,name) \
+ ( (This)->lpVtbl -> GetName(This,bufLen,nameLen,name) )
+
+#define IXCLRDataModule_GetFileName(This,bufLen,nameLen,name) \
+ ( (This)->lpVtbl -> GetFileName(This,bufLen,nameLen,name) )
+
+#define IXCLRDataModule_GetFlags(This,flags) \
+ ( (This)->lpVtbl -> GetFlags(This,flags) )
+
+#define IXCLRDataModule_IsSameObject(This,mod) \
+ ( (This)->lpVtbl -> IsSameObject(This,mod) )
+
+#define IXCLRDataModule_StartEnumExtents(This,handle) \
+ ( (This)->lpVtbl -> StartEnumExtents(This,handle) )
+
+#define IXCLRDataModule_EnumExtent(This,handle,extent) \
+ ( (This)->lpVtbl -> EnumExtent(This,handle,extent) )
+
+#define IXCLRDataModule_EndEnumExtents(This,handle) \
+ ( (This)->lpVtbl -> EndEnumExtents(This,handle) )
+
+#define IXCLRDataModule_Request(This,reqCode,inBufferSize,inBuffer,outBufferSize,outBuffer) \
+ ( (This)->lpVtbl -> Request(This,reqCode,inBufferSize,inBuffer,outBufferSize,outBuffer) )
+
+#define IXCLRDataModule_StartEnumAppDomains(This,handle) \
+ ( (This)->lpVtbl -> StartEnumAppDomains(This,handle) )
+
+#define IXCLRDataModule_EnumAppDomain(This,handle,appDomain) \
+ ( (This)->lpVtbl -> EnumAppDomain(This,handle,appDomain) )
+
+#define IXCLRDataModule_EndEnumAppDomains(This,handle) \
+ ( (This)->lpVtbl -> EndEnumAppDomains(This,handle) )
+
+#define IXCLRDataModule_GetVersionId(This,vid) \
+ ( (This)->lpVtbl -> GetVersionId(This,vid) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IXCLRDataModule_INTERFACE_DEFINED__ */
+
+
+/* interface __MIDL_itf_xclrdata_0000_0009 */
+/* [local] */
+
+#pragma warning(pop)
+
+
+extern RPC_IF_HANDLE __MIDL_itf_xclrdata_0000_0009_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_xclrdata_0000_0009_v0_0_s_ifspec;
+
+#ifndef __IXCLRDataModule2_INTERFACE_DEFINED__
+#define __IXCLRDataModule2_INTERFACE_DEFINED__
+
+/* interface IXCLRDataModule2 */
+/* [uuid][local][object] */
+
+
+EXTERN_C const IID IID_IXCLRDataModule2;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("34625881-7EB3-4524-817B-8DB9D064C760")
+ IXCLRDataModule2 : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE SetJITCompilerFlags(
+ /* [in] */ DWORD dwFlags) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IXCLRDataModule2Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IXCLRDataModule2 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IXCLRDataModule2 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IXCLRDataModule2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *SetJITCompilerFlags )(
+ IXCLRDataModule2 * This,
+ /* [in] */ DWORD dwFlags);
+
+ END_INTERFACE
+ } IXCLRDataModule2Vtbl;
+
+ interface IXCLRDataModule2
+ {
+ CONST_VTBL struct IXCLRDataModule2Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IXCLRDataModule2_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IXCLRDataModule2_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IXCLRDataModule2_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IXCLRDataModule2_SetJITCompilerFlags(This,dwFlags) \
+ ( (This)->lpVtbl -> SetJITCompilerFlags(This,dwFlags) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IXCLRDataModule2_INTERFACE_DEFINED__ */
+
+
+/* interface __MIDL_itf_xclrdata_0000_0010 */
+/* [local] */
+
+#pragma warning(push)
+#pragma warning(disable:28718)
+
+
+extern RPC_IF_HANDLE __MIDL_itf_xclrdata_0000_0010_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_xclrdata_0000_0010_v0_0_s_ifspec;
+
+#ifndef __IXCLRDataTypeDefinition_INTERFACE_DEFINED__
+#define __IXCLRDataTypeDefinition_INTERFACE_DEFINED__
+
+/* interface IXCLRDataTypeDefinition */
+/* [uuid][local][object] */
+
+
+EXTERN_C const IID IID_IXCLRDataTypeDefinition;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("4675666C-C275-45b8-9F6C-AB165D5C1E09")
+ IXCLRDataTypeDefinition : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetModule(
+ /* [out] */ IXCLRDataModule **mod) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StartEnumMethodDefinitions(
+ /* [out] */ CLRDATA_ENUM *handle) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnumMethodDefinition(
+ /* [out][in] */ CLRDATA_ENUM *handle,
+ /* [out] */ IXCLRDataMethodDefinition **methodDefinition) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EndEnumMethodDefinitions(
+ /* [in] */ CLRDATA_ENUM handle) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StartEnumMethodDefinitionsByName(
+ /* [in] */ LPCWSTR name,
+ /* [in] */ ULONG32 flags,
+ /* [out] */ CLRDATA_ENUM *handle) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnumMethodDefinitionByName(
+ /* [out][in] */ CLRDATA_ENUM *handle,
+ /* [out] */ IXCLRDataMethodDefinition **method) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EndEnumMethodDefinitionsByName(
+ /* [in] */ CLRDATA_ENUM handle) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetMethodDefinitionByToken(
+ /* [in] */ mdMethodDef token,
+ /* [out] */ IXCLRDataMethodDefinition **methodDefinition) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StartEnumInstances(
+ /* [in] */ IXCLRDataAppDomain *appDomain,
+ /* [out] */ CLRDATA_ENUM *handle) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnumInstance(
+ /* [out][in] */ CLRDATA_ENUM *handle,
+ /* [out] */ IXCLRDataTypeInstance **instance) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EndEnumInstances(
+ /* [in] */ CLRDATA_ENUM handle) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetName(
+ /* [in] */ ULONG32 flags,
+ /* [in] */ ULONG32 bufLen,
+ /* [out] */ ULONG32 *nameLen,
+ /* [size_is][out] */ WCHAR nameBuf[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetTokenAndScope(
+ /* [out] */ mdTypeDef *token,
+ /* [out] */ IXCLRDataModule **mod) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetCorElementType(
+ /* [out] */ CorElementType *type) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetFlags(
+ /* [out] */ ULONG32 *flags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE IsSameObject(
+ /* [in] */ IXCLRDataTypeDefinition *type) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Request(
+ /* [in] */ ULONG32 reqCode,
+ /* [in] */ ULONG32 inBufferSize,
+ /* [size_is][in] */ BYTE *inBuffer,
+ /* [in] */ ULONG32 outBufferSize,
+ /* [size_is][out] */ BYTE *outBuffer) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetArrayRank(
+ /* [out] */ ULONG32 *rank) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetBase(
+ /* [out] */ IXCLRDataTypeDefinition **base) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetNumFields(
+ /* [in] */ ULONG32 flags,
+ /* [out] */ ULONG32 *numFields) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StartEnumFields(
+ /* [in] */ ULONG32 flags,
+ /* [out] */ CLRDATA_ENUM *handle) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnumField(
+ /* [out][in] */ CLRDATA_ENUM *handle,
+ /* [in] */ ULONG32 nameBufLen,
+ /* [out] */ ULONG32 *nameLen,
+ /* [size_is][out] */ WCHAR nameBuf[ ],
+ /* [out] */ IXCLRDataTypeDefinition **type,
+ /* [out] */ ULONG32 *flags,
+ /* [out] */ mdFieldDef *token) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EndEnumFields(
+ /* [in] */ CLRDATA_ENUM handle) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StartEnumFieldsByName(
+ /* [in] */ LPCWSTR name,
+ /* [in] */ ULONG32 nameFlags,
+ /* [in] */ ULONG32 fieldFlags,
+ /* [out] */ CLRDATA_ENUM *handle) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnumFieldByName(
+ /* [out][in] */ CLRDATA_ENUM *handle,
+ /* [out] */ IXCLRDataTypeDefinition **type,
+ /* [out] */ ULONG32 *flags,
+ /* [out] */ mdFieldDef *token) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EndEnumFieldsByName(
+ /* [in] */ CLRDATA_ENUM handle) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetFieldByToken(
+ /* [in] */ mdFieldDef token,
+ /* [in] */ ULONG32 nameBufLen,
+ /* [out] */ ULONG32 *nameLen,
+ /* [size_is][out] */ WCHAR nameBuf[ ],
+ /* [out] */ IXCLRDataTypeDefinition **type,
+ /* [out] */ ULONG32 *flags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetTypeNotification(
+ /* [out] */ ULONG32 *flags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetTypeNotification(
+ /* [in] */ ULONG32 flags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnumField2(
+ /* [out][in] */ CLRDATA_ENUM *handle,
+ /* [in] */ ULONG32 nameBufLen,
+ /* [out] */ ULONG32 *nameLen,
+ /* [size_is][out] */ WCHAR nameBuf[ ],
+ /* [out] */ IXCLRDataTypeDefinition **type,
+ /* [out] */ ULONG32 *flags,
+ /* [out] */ IXCLRDataModule **tokenScope,
+ /* [out] */ mdFieldDef *token) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnumFieldByName2(
+ /* [out][in] */ CLRDATA_ENUM *handle,
+ /* [out] */ IXCLRDataTypeDefinition **type,
+ /* [out] */ ULONG32 *flags,
+ /* [out] */ IXCLRDataModule **tokenScope,
+ /* [out] */ mdFieldDef *token) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetFieldByToken2(
+ /* [in] */ IXCLRDataModule *tokenScope,
+ /* [in] */ mdFieldDef token,
+ /* [in] */ ULONG32 nameBufLen,
+ /* [out] */ ULONG32 *nameLen,
+ /* [size_is][out] */ WCHAR nameBuf[ ],
+ /* [out] */ IXCLRDataTypeDefinition **type,
+ /* [out] */ ULONG32 *flags) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IXCLRDataTypeDefinitionVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IXCLRDataTypeDefinition * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IXCLRDataTypeDefinition * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IXCLRDataTypeDefinition * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetModule )(
+ IXCLRDataTypeDefinition * This,
+ /* [out] */ IXCLRDataModule **mod);
+
+ HRESULT ( STDMETHODCALLTYPE *StartEnumMethodDefinitions )(
+ IXCLRDataTypeDefinition * This,
+ /* [out] */ CLRDATA_ENUM *handle);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumMethodDefinition )(
+ IXCLRDataTypeDefinition * This,
+ /* [out][in] */ CLRDATA_ENUM *handle,
+ /* [out] */ IXCLRDataMethodDefinition **methodDefinition);
+
+ HRESULT ( STDMETHODCALLTYPE *EndEnumMethodDefinitions )(
+ IXCLRDataTypeDefinition * This,
+ /* [in] */ CLRDATA_ENUM handle);
+
+ HRESULT ( STDMETHODCALLTYPE *StartEnumMethodDefinitionsByName )(
+ IXCLRDataTypeDefinition * This,
+ /* [in] */ LPCWSTR name,
+ /* [in] */ ULONG32 flags,
+ /* [out] */ CLRDATA_ENUM *handle);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumMethodDefinitionByName )(
+ IXCLRDataTypeDefinition * This,
+ /* [out][in] */ CLRDATA_ENUM *handle,
+ /* [out] */ IXCLRDataMethodDefinition **method);
+
+ HRESULT ( STDMETHODCALLTYPE *EndEnumMethodDefinitionsByName )(
+ IXCLRDataTypeDefinition * This,
+ /* [in] */ CLRDATA_ENUM handle);
+
+ HRESULT ( STDMETHODCALLTYPE *GetMethodDefinitionByToken )(
+ IXCLRDataTypeDefinition * This,
+ /* [in] */ mdMethodDef token,
+ /* [out] */ IXCLRDataMethodDefinition **methodDefinition);
+
+ HRESULT ( STDMETHODCALLTYPE *StartEnumInstances )(
+ IXCLRDataTypeDefinition * This,
+ /* [in] */ IXCLRDataAppDomain *appDomain,
+ /* [out] */ CLRDATA_ENUM *handle);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumInstance )(
+ IXCLRDataTypeDefinition * This,
+ /* [out][in] */ CLRDATA_ENUM *handle,
+ /* [out] */ IXCLRDataTypeInstance **instance);
+
+ HRESULT ( STDMETHODCALLTYPE *EndEnumInstances )(
+ IXCLRDataTypeDefinition * This,
+ /* [in] */ CLRDATA_ENUM handle);
+
+ HRESULT ( STDMETHODCALLTYPE *GetName )(
+ IXCLRDataTypeDefinition * This,
+ /* [in] */ ULONG32 flags,
+ /* [in] */ ULONG32 bufLen,
+ /* [out] */ ULONG32 *nameLen,
+ /* [size_is][out] */ WCHAR nameBuf[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetTokenAndScope )(
+ IXCLRDataTypeDefinition * This,
+ /* [out] */ mdTypeDef *token,
+ /* [out] */ IXCLRDataModule **mod);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCorElementType )(
+ IXCLRDataTypeDefinition * This,
+ /* [out] */ CorElementType *type);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFlags )(
+ IXCLRDataTypeDefinition * This,
+ /* [out] */ ULONG32 *flags);
+
+ HRESULT ( STDMETHODCALLTYPE *IsSameObject )(
+ IXCLRDataTypeDefinition * This,
+ /* [in] */ IXCLRDataTypeDefinition *type);
+
+ HRESULT ( STDMETHODCALLTYPE *Request )(
+ IXCLRDataTypeDefinition * This,
+ /* [in] */ ULONG32 reqCode,
+ /* [in] */ ULONG32 inBufferSize,
+ /* [size_is][in] */ BYTE *inBuffer,
+ /* [in] */ ULONG32 outBufferSize,
+ /* [size_is][out] */ BYTE *outBuffer);
+
+ HRESULT ( STDMETHODCALLTYPE *GetArrayRank )(
+ IXCLRDataTypeDefinition * This,
+ /* [out] */ ULONG32 *rank);
+
+ HRESULT ( STDMETHODCALLTYPE *GetBase )(
+ IXCLRDataTypeDefinition * This,
+ /* [out] */ IXCLRDataTypeDefinition **base);
+
+ HRESULT ( STDMETHODCALLTYPE *GetNumFields )(
+ IXCLRDataTypeDefinition * This,
+ /* [in] */ ULONG32 flags,
+ /* [out] */ ULONG32 *numFields);
+
+ HRESULT ( STDMETHODCALLTYPE *StartEnumFields )(
+ IXCLRDataTypeDefinition * This,
+ /* [in] */ ULONG32 flags,
+ /* [out] */ CLRDATA_ENUM *handle);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumField )(
+ IXCLRDataTypeDefinition * This,
+ /* [out][in] */ CLRDATA_ENUM *handle,
+ /* [in] */ ULONG32 nameBufLen,
+ /* [out] */ ULONG32 *nameLen,
+ /* [size_is][out] */ WCHAR nameBuf[ ],
+ /* [out] */ IXCLRDataTypeDefinition **type,
+ /* [out] */ ULONG32 *flags,
+ /* [out] */ mdFieldDef *token);
+
+ HRESULT ( STDMETHODCALLTYPE *EndEnumFields )(
+ IXCLRDataTypeDefinition * This,
+ /* [in] */ CLRDATA_ENUM handle);
+
+ HRESULT ( STDMETHODCALLTYPE *StartEnumFieldsByName )(
+ IXCLRDataTypeDefinition * This,
+ /* [in] */ LPCWSTR name,
+ /* [in] */ ULONG32 nameFlags,
+ /* [in] */ ULONG32 fieldFlags,
+ /* [out] */ CLRDATA_ENUM *handle);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumFieldByName )(
+ IXCLRDataTypeDefinition * This,
+ /* [out][in] */ CLRDATA_ENUM *handle,
+ /* [out] */ IXCLRDataTypeDefinition **type,
+ /* [out] */ ULONG32 *flags,
+ /* [out] */ mdFieldDef *token);
+
+ HRESULT ( STDMETHODCALLTYPE *EndEnumFieldsByName )(
+ IXCLRDataTypeDefinition * This,
+ /* [in] */ CLRDATA_ENUM handle);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFieldByToken )(
+ IXCLRDataTypeDefinition * This,
+ /* [in] */ mdFieldDef token,
+ /* [in] */ ULONG32 nameBufLen,
+ /* [out] */ ULONG32 *nameLen,
+ /* [size_is][out] */ WCHAR nameBuf[ ],
+ /* [out] */ IXCLRDataTypeDefinition **type,
+ /* [out] */ ULONG32 *flags);
+
+ HRESULT ( STDMETHODCALLTYPE *GetTypeNotification )(
+ IXCLRDataTypeDefinition * This,
+ /* [out] */ ULONG32 *flags);
+
+ HRESULT ( STDMETHODCALLTYPE *SetTypeNotification )(
+ IXCLRDataTypeDefinition * This,
+ /* [in] */ ULONG32 flags);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumField2 )(
+ IXCLRDataTypeDefinition * This,
+ /* [out][in] */ CLRDATA_ENUM *handle,
+ /* [in] */ ULONG32 nameBufLen,
+ /* [out] */ ULONG32 *nameLen,
+ /* [size_is][out] */ WCHAR nameBuf[ ],
+ /* [out] */ IXCLRDataTypeDefinition **type,
+ /* [out] */ ULONG32 *flags,
+ /* [out] */ IXCLRDataModule **tokenScope,
+ /* [out] */ mdFieldDef *token);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumFieldByName2 )(
+ IXCLRDataTypeDefinition * This,
+ /* [out][in] */ CLRDATA_ENUM *handle,
+ /* [out] */ IXCLRDataTypeDefinition **type,
+ /* [out] */ ULONG32 *flags,
+ /* [out] */ IXCLRDataModule **tokenScope,
+ /* [out] */ mdFieldDef *token);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFieldByToken2 )(
+ IXCLRDataTypeDefinition * This,
+ /* [in] */ IXCLRDataModule *tokenScope,
+ /* [in] */ mdFieldDef token,
+ /* [in] */ ULONG32 nameBufLen,
+ /* [out] */ ULONG32 *nameLen,
+ /* [size_is][out] */ WCHAR nameBuf[ ],
+ /* [out] */ IXCLRDataTypeDefinition **type,
+ /* [out] */ ULONG32 *flags);
+
+ END_INTERFACE
+ } IXCLRDataTypeDefinitionVtbl;
+
+ interface IXCLRDataTypeDefinition
+ {
+ CONST_VTBL struct IXCLRDataTypeDefinitionVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IXCLRDataTypeDefinition_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IXCLRDataTypeDefinition_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IXCLRDataTypeDefinition_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IXCLRDataTypeDefinition_GetModule(This,mod) \
+ ( (This)->lpVtbl -> GetModule(This,mod) )
+
+#define IXCLRDataTypeDefinition_StartEnumMethodDefinitions(This,handle) \
+ ( (This)->lpVtbl -> StartEnumMethodDefinitions(This,handle) )
+
+#define IXCLRDataTypeDefinition_EnumMethodDefinition(This,handle,methodDefinition) \
+ ( (This)->lpVtbl -> EnumMethodDefinition(This,handle,methodDefinition) )
+
+#define IXCLRDataTypeDefinition_EndEnumMethodDefinitions(This,handle) \
+ ( (This)->lpVtbl -> EndEnumMethodDefinitions(This,handle) )
+
+#define IXCLRDataTypeDefinition_StartEnumMethodDefinitionsByName(This,name,flags,handle) \
+ ( (This)->lpVtbl -> StartEnumMethodDefinitionsByName(This,name,flags,handle) )
+
+#define IXCLRDataTypeDefinition_EnumMethodDefinitionByName(This,handle,method) \
+ ( (This)->lpVtbl -> EnumMethodDefinitionByName(This,handle,method) )
+
+#define IXCLRDataTypeDefinition_EndEnumMethodDefinitionsByName(This,handle) \
+ ( (This)->lpVtbl -> EndEnumMethodDefinitionsByName(This,handle) )
+
+#define IXCLRDataTypeDefinition_GetMethodDefinitionByToken(This,token,methodDefinition) \
+ ( (This)->lpVtbl -> GetMethodDefinitionByToken(This,token,methodDefinition) )
+
+#define IXCLRDataTypeDefinition_StartEnumInstances(This,appDomain,handle) \
+ ( (This)->lpVtbl -> StartEnumInstances(This,appDomain,handle) )
+
+#define IXCLRDataTypeDefinition_EnumInstance(This,handle,instance) \
+ ( (This)->lpVtbl -> EnumInstance(This,handle,instance) )
+
+#define IXCLRDataTypeDefinition_EndEnumInstances(This,handle) \
+ ( (This)->lpVtbl -> EndEnumInstances(This,handle) )
+
+#define IXCLRDataTypeDefinition_GetName(This,flags,bufLen,nameLen,nameBuf) \
+ ( (This)->lpVtbl -> GetName(This,flags,bufLen,nameLen,nameBuf) )
+
+#define IXCLRDataTypeDefinition_GetTokenAndScope(This,token,mod) \
+ ( (This)->lpVtbl -> GetTokenAndScope(This,token,mod) )
+
+#define IXCLRDataTypeDefinition_GetCorElementType(This,type) \
+ ( (This)->lpVtbl -> GetCorElementType(This,type) )
+
+#define IXCLRDataTypeDefinition_GetFlags(This,flags) \
+ ( (This)->lpVtbl -> GetFlags(This,flags) )
+
+#define IXCLRDataTypeDefinition_IsSameObject(This,type) \
+ ( (This)->lpVtbl -> IsSameObject(This,type) )
+
+#define IXCLRDataTypeDefinition_Request(This,reqCode,inBufferSize,inBuffer,outBufferSize,outBuffer) \
+ ( (This)->lpVtbl -> Request(This,reqCode,inBufferSize,inBuffer,outBufferSize,outBuffer) )
+
+#define IXCLRDataTypeDefinition_GetArrayRank(This,rank) \
+ ( (This)->lpVtbl -> GetArrayRank(This,rank) )
+
+#define IXCLRDataTypeDefinition_GetBase(This,base) \
+ ( (This)->lpVtbl -> GetBase(This,base) )
+
+#define IXCLRDataTypeDefinition_GetNumFields(This,flags,numFields) \
+ ( (This)->lpVtbl -> GetNumFields(This,flags,numFields) )
+
+#define IXCLRDataTypeDefinition_StartEnumFields(This,flags,handle) \
+ ( (This)->lpVtbl -> StartEnumFields(This,flags,handle) )
+
+#define IXCLRDataTypeDefinition_EnumField(This,handle,nameBufLen,nameLen,nameBuf,type,flags,token) \
+ ( (This)->lpVtbl -> EnumField(This,handle,nameBufLen,nameLen,nameBuf,type,flags,token) )
+
+#define IXCLRDataTypeDefinition_EndEnumFields(This,handle) \
+ ( (This)->lpVtbl -> EndEnumFields(This,handle) )
+
+#define IXCLRDataTypeDefinition_StartEnumFieldsByName(This,name,nameFlags,fieldFlags,handle) \
+ ( (This)->lpVtbl -> StartEnumFieldsByName(This,name,nameFlags,fieldFlags,handle) )
+
+#define IXCLRDataTypeDefinition_EnumFieldByName(This,handle,type,flags,token) \
+ ( (This)->lpVtbl -> EnumFieldByName(This,handle,type,flags,token) )
+
+#define IXCLRDataTypeDefinition_EndEnumFieldsByName(This,handle) \
+ ( (This)->lpVtbl -> EndEnumFieldsByName(This,handle) )
+
+#define IXCLRDataTypeDefinition_GetFieldByToken(This,token,nameBufLen,nameLen,nameBuf,type,flags) \
+ ( (This)->lpVtbl -> GetFieldByToken(This,token,nameBufLen,nameLen,nameBuf,type,flags) )
+
+#define IXCLRDataTypeDefinition_GetTypeNotification(This,flags) \
+ ( (This)->lpVtbl -> GetTypeNotification(This,flags) )
+
+#define IXCLRDataTypeDefinition_SetTypeNotification(This,flags) \
+ ( (This)->lpVtbl -> SetTypeNotification(This,flags) )
+
+#define IXCLRDataTypeDefinition_EnumField2(This,handle,nameBufLen,nameLen,nameBuf,type,flags,tokenScope,token) \
+ ( (This)->lpVtbl -> EnumField2(This,handle,nameBufLen,nameLen,nameBuf,type,flags,tokenScope,token) )
+
+#define IXCLRDataTypeDefinition_EnumFieldByName2(This,handle,type,flags,tokenScope,token) \
+ ( (This)->lpVtbl -> EnumFieldByName2(This,handle,type,flags,tokenScope,token) )
+
+#define IXCLRDataTypeDefinition_GetFieldByToken2(This,tokenScope,token,nameBufLen,nameLen,nameBuf,type,flags) \
+ ( (This)->lpVtbl -> GetFieldByToken2(This,tokenScope,token,nameBufLen,nameLen,nameBuf,type,flags) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IXCLRDataTypeDefinition_INTERFACE_DEFINED__ */
+
+
+/* interface __MIDL_itf_xclrdata_0000_0011 */
+/* [local] */
+
+#pragma warning(pop)
+#pragma warning(push)
+#pragma warning(disable:28718)
+
+
+extern RPC_IF_HANDLE __MIDL_itf_xclrdata_0000_0011_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_xclrdata_0000_0011_v0_0_s_ifspec;
+
+#ifndef __IXCLRDataTypeInstance_INTERFACE_DEFINED__
+#define __IXCLRDataTypeInstance_INTERFACE_DEFINED__
+
+/* interface IXCLRDataTypeInstance */
+/* [uuid][local][object] */
+
+
+EXTERN_C const IID IID_IXCLRDataTypeInstance;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("4D078D91-9CB3-4b0d-97AC-28C8A5A82597")
+ IXCLRDataTypeInstance : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE StartEnumMethodInstances(
+ /* [out] */ CLRDATA_ENUM *handle) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnumMethodInstance(
+ /* [out][in] */ CLRDATA_ENUM *handle,
+ /* [out] */ IXCLRDataMethodInstance **methodInstance) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EndEnumMethodInstances(
+ /* [in] */ CLRDATA_ENUM handle) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StartEnumMethodInstancesByName(
+ /* [in] */ LPCWSTR name,
+ /* [in] */ ULONG32 flags,
+ /* [out] */ CLRDATA_ENUM *handle) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnumMethodInstanceByName(
+ /* [out][in] */ CLRDATA_ENUM *handle,
+ /* [out] */ IXCLRDataMethodInstance **method) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EndEnumMethodInstancesByName(
+ /* [in] */ CLRDATA_ENUM handle) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetNumStaticFields(
+ /* [out] */ ULONG32 *numFields) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetStaticFieldByIndex(
+ /* [in] */ ULONG32 index,
+ /* [in] */ IXCLRDataTask *tlsTask,
+ /* [out] */ IXCLRDataValue **field,
+ /* [in] */ ULONG32 bufLen,
+ /* [out] */ ULONG32 *nameLen,
+ /* [size_is][out] */ WCHAR nameBuf[ ],
+ /* [out] */ mdFieldDef *token) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StartEnumStaticFieldsByName(
+ /* [in] */ LPCWSTR name,
+ /* [in] */ ULONG32 flags,
+ /* [in] */ IXCLRDataTask *tlsTask,
+ /* [out] */ CLRDATA_ENUM *handle) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnumStaticFieldByName(
+ /* [out][in] */ CLRDATA_ENUM *handle,
+ /* [out] */ IXCLRDataValue **value) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EndEnumStaticFieldsByName(
+ /* [in] */ CLRDATA_ENUM handle) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetNumTypeArguments(
+ /* [out] */ ULONG32 *numTypeArgs) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetTypeArgumentByIndex(
+ /* [in] */ ULONG32 index,
+ /* [out] */ IXCLRDataTypeInstance **typeArg) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetName(
+ /* [in] */ ULONG32 flags,
+ /* [in] */ ULONG32 bufLen,
+ /* [out] */ ULONG32 *nameLen,
+ /* [size_is][out] */ WCHAR nameBuf[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetModule(
+ /* [out] */ IXCLRDataModule **mod) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetDefinition(
+ /* [out] */ IXCLRDataTypeDefinition **typeDefinition) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetFlags(
+ /* [out] */ ULONG32 *flags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE IsSameObject(
+ /* [in] */ IXCLRDataTypeInstance *type) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Request(
+ /* [in] */ ULONG32 reqCode,
+ /* [in] */ ULONG32 inBufferSize,
+ /* [size_is][in] */ BYTE *inBuffer,
+ /* [in] */ ULONG32 outBufferSize,
+ /* [size_is][out] */ BYTE *outBuffer) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetNumStaticFields2(
+ /* [in] */ ULONG32 flags,
+ /* [out] */ ULONG32 *numFields) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StartEnumStaticFields(
+ /* [in] */ ULONG32 flags,
+ /* [in] */ IXCLRDataTask *tlsTask,
+ /* [out] */ CLRDATA_ENUM *handle) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnumStaticField(
+ /* [out][in] */ CLRDATA_ENUM *handle,
+ /* [out] */ IXCLRDataValue **value) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EndEnumStaticFields(
+ /* [in] */ CLRDATA_ENUM handle) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StartEnumStaticFieldsByName2(
+ /* [in] */ LPCWSTR name,
+ /* [in] */ ULONG32 nameFlags,
+ /* [in] */ ULONG32 fieldFlags,
+ /* [in] */ IXCLRDataTask *tlsTask,
+ /* [out] */ CLRDATA_ENUM *handle) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnumStaticFieldByName2(
+ /* [out][in] */ CLRDATA_ENUM *handle,
+ /* [out] */ IXCLRDataValue **value) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EndEnumStaticFieldsByName2(
+ /* [in] */ CLRDATA_ENUM handle) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetStaticFieldByToken(
+ /* [in] */ mdFieldDef token,
+ /* [in] */ IXCLRDataTask *tlsTask,
+ /* [out] */ IXCLRDataValue **field,
+ /* [in] */ ULONG32 bufLen,
+ /* [out] */ ULONG32 *nameLen,
+ /* [size_is][out] */ WCHAR nameBuf[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetBase(
+ /* [out] */ IXCLRDataTypeInstance **base) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnumStaticField2(
+ /* [out][in] */ CLRDATA_ENUM *handle,
+ /* [out] */ IXCLRDataValue **value,
+ /* [in] */ ULONG32 bufLen,
+ /* [out] */ ULONG32 *nameLen,
+ /* [size_is][out] */ WCHAR nameBuf[ ],
+ /* [out] */ IXCLRDataModule **tokenScope,
+ /* [out] */ mdFieldDef *token) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnumStaticFieldByName3(
+ /* [out][in] */ CLRDATA_ENUM *handle,
+ /* [out] */ IXCLRDataValue **value,
+ /* [out] */ IXCLRDataModule **tokenScope,
+ /* [out] */ mdFieldDef *token) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetStaticFieldByToken2(
+ /* [in] */ IXCLRDataModule *tokenScope,
+ /* [in] */ mdFieldDef token,
+ /* [in] */ IXCLRDataTask *tlsTask,
+ /* [out] */ IXCLRDataValue **field,
+ /* [in] */ ULONG32 bufLen,
+ /* [out] */ ULONG32 *nameLen,
+ /* [size_is][out] */ WCHAR nameBuf[ ]) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IXCLRDataTypeInstanceVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IXCLRDataTypeInstance * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IXCLRDataTypeInstance * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IXCLRDataTypeInstance * This);
+
+ HRESULT ( STDMETHODCALLTYPE *StartEnumMethodInstances )(
+ IXCLRDataTypeInstance * This,
+ /* [out] */ CLRDATA_ENUM *handle);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumMethodInstance )(
+ IXCLRDataTypeInstance * This,
+ /* [out][in] */ CLRDATA_ENUM *handle,
+ /* [out] */ IXCLRDataMethodInstance **methodInstance);
+
+ HRESULT ( STDMETHODCALLTYPE *EndEnumMethodInstances )(
+ IXCLRDataTypeInstance * This,
+ /* [in] */ CLRDATA_ENUM handle);
+
+ HRESULT ( STDMETHODCALLTYPE *StartEnumMethodInstancesByName )(
+ IXCLRDataTypeInstance * This,
+ /* [in] */ LPCWSTR name,
+ /* [in] */ ULONG32 flags,
+ /* [out] */ CLRDATA_ENUM *handle);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumMethodInstanceByName )(
+ IXCLRDataTypeInstance * This,
+ /* [out][in] */ CLRDATA_ENUM *handle,
+ /* [out] */ IXCLRDataMethodInstance **method);
+
+ HRESULT ( STDMETHODCALLTYPE *EndEnumMethodInstancesByName )(
+ IXCLRDataTypeInstance * This,
+ /* [in] */ CLRDATA_ENUM handle);
+
+ HRESULT ( STDMETHODCALLTYPE *GetNumStaticFields )(
+ IXCLRDataTypeInstance * This,
+ /* [out] */ ULONG32 *numFields);
+
+ HRESULT ( STDMETHODCALLTYPE *GetStaticFieldByIndex )(
+ IXCLRDataTypeInstance * This,
+ /* [in] */ ULONG32 index,
+ /* [in] */ IXCLRDataTask *tlsTask,
+ /* [out] */ IXCLRDataValue **field,
+ /* [in] */ ULONG32 bufLen,
+ /* [out] */ ULONG32 *nameLen,
+ /* [size_is][out] */ WCHAR nameBuf[ ],
+ /* [out] */ mdFieldDef *token);
+
+ HRESULT ( STDMETHODCALLTYPE *StartEnumStaticFieldsByName )(
+ IXCLRDataTypeInstance * This,
+ /* [in] */ LPCWSTR name,
+ /* [in] */ ULONG32 flags,
+ /* [in] */ IXCLRDataTask *tlsTask,
+ /* [out] */ CLRDATA_ENUM *handle);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumStaticFieldByName )(
+ IXCLRDataTypeInstance * This,
+ /* [out][in] */ CLRDATA_ENUM *handle,
+ /* [out] */ IXCLRDataValue **value);
+
+ HRESULT ( STDMETHODCALLTYPE *EndEnumStaticFieldsByName )(
+ IXCLRDataTypeInstance * This,
+ /* [in] */ CLRDATA_ENUM handle);
+
+ HRESULT ( STDMETHODCALLTYPE *GetNumTypeArguments )(
+ IXCLRDataTypeInstance * This,
+ /* [out] */ ULONG32 *numTypeArgs);
+
+ HRESULT ( STDMETHODCALLTYPE *GetTypeArgumentByIndex )(
+ IXCLRDataTypeInstance * This,
+ /* [in] */ ULONG32 index,
+ /* [out] */ IXCLRDataTypeInstance **typeArg);
+
+ HRESULT ( STDMETHODCALLTYPE *GetName )(
+ IXCLRDataTypeInstance * This,
+ /* [in] */ ULONG32 flags,
+ /* [in] */ ULONG32 bufLen,
+ /* [out] */ ULONG32 *nameLen,
+ /* [size_is][out] */ WCHAR nameBuf[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetModule )(
+ IXCLRDataTypeInstance * This,
+ /* [out] */ IXCLRDataModule **mod);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDefinition )(
+ IXCLRDataTypeInstance * This,
+ /* [out] */ IXCLRDataTypeDefinition **typeDefinition);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFlags )(
+ IXCLRDataTypeInstance * This,
+ /* [out] */ ULONG32 *flags);
+
+ HRESULT ( STDMETHODCALLTYPE *IsSameObject )(
+ IXCLRDataTypeInstance * This,
+ /* [in] */ IXCLRDataTypeInstance *type);
+
+ HRESULT ( STDMETHODCALLTYPE *Request )(
+ IXCLRDataTypeInstance * This,
+ /* [in] */ ULONG32 reqCode,
+ /* [in] */ ULONG32 inBufferSize,
+ /* [size_is][in] */ BYTE *inBuffer,
+ /* [in] */ ULONG32 outBufferSize,
+ /* [size_is][out] */ BYTE *outBuffer);
+
+ HRESULT ( STDMETHODCALLTYPE *GetNumStaticFields2 )(
+ IXCLRDataTypeInstance * This,
+ /* [in] */ ULONG32 flags,
+ /* [out] */ ULONG32 *numFields);
+
+ HRESULT ( STDMETHODCALLTYPE *StartEnumStaticFields )(
+ IXCLRDataTypeInstance * This,
+ /* [in] */ ULONG32 flags,
+ /* [in] */ IXCLRDataTask *tlsTask,
+ /* [out] */ CLRDATA_ENUM *handle);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumStaticField )(
+ IXCLRDataTypeInstance * This,
+ /* [out][in] */ CLRDATA_ENUM *handle,
+ /* [out] */ IXCLRDataValue **value);
+
+ HRESULT ( STDMETHODCALLTYPE *EndEnumStaticFields )(
+ IXCLRDataTypeInstance * This,
+ /* [in] */ CLRDATA_ENUM handle);
+
+ HRESULT ( STDMETHODCALLTYPE *StartEnumStaticFieldsByName2 )(
+ IXCLRDataTypeInstance * This,
+ /* [in] */ LPCWSTR name,
+ /* [in] */ ULONG32 nameFlags,
+ /* [in] */ ULONG32 fieldFlags,
+ /* [in] */ IXCLRDataTask *tlsTask,
+ /* [out] */ CLRDATA_ENUM *handle);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumStaticFieldByName2 )(
+ IXCLRDataTypeInstance * This,
+ /* [out][in] */ CLRDATA_ENUM *handle,
+ /* [out] */ IXCLRDataValue **value);
+
+ HRESULT ( STDMETHODCALLTYPE *EndEnumStaticFieldsByName2 )(
+ IXCLRDataTypeInstance * This,
+ /* [in] */ CLRDATA_ENUM handle);
+
+ HRESULT ( STDMETHODCALLTYPE *GetStaticFieldByToken )(
+ IXCLRDataTypeInstance * This,
+ /* [in] */ mdFieldDef token,
+ /* [in] */ IXCLRDataTask *tlsTask,
+ /* [out] */ IXCLRDataValue **field,
+ /* [in] */ ULONG32 bufLen,
+ /* [out] */ ULONG32 *nameLen,
+ /* [size_is][out] */ WCHAR nameBuf[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetBase )(
+ IXCLRDataTypeInstance * This,
+ /* [out] */ IXCLRDataTypeInstance **base);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumStaticField2 )(
+ IXCLRDataTypeInstance * This,
+ /* [out][in] */ CLRDATA_ENUM *handle,
+ /* [out] */ IXCLRDataValue **value,
+ /* [in] */ ULONG32 bufLen,
+ /* [out] */ ULONG32 *nameLen,
+ /* [size_is][out] */ WCHAR nameBuf[ ],
+ /* [out] */ IXCLRDataModule **tokenScope,
+ /* [out] */ mdFieldDef *token);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumStaticFieldByName3 )(
+ IXCLRDataTypeInstance * This,
+ /* [out][in] */ CLRDATA_ENUM *handle,
+ /* [out] */ IXCLRDataValue **value,
+ /* [out] */ IXCLRDataModule **tokenScope,
+ /* [out] */ mdFieldDef *token);
+
+ HRESULT ( STDMETHODCALLTYPE *GetStaticFieldByToken2 )(
+ IXCLRDataTypeInstance * This,
+ /* [in] */ IXCLRDataModule *tokenScope,
+ /* [in] */ mdFieldDef token,
+ /* [in] */ IXCLRDataTask *tlsTask,
+ /* [out] */ IXCLRDataValue **field,
+ /* [in] */ ULONG32 bufLen,
+ /* [out] */ ULONG32 *nameLen,
+ /* [size_is][out] */ WCHAR nameBuf[ ]);
+
+ END_INTERFACE
+ } IXCLRDataTypeInstanceVtbl;
+
+ interface IXCLRDataTypeInstance
+ {
+ CONST_VTBL struct IXCLRDataTypeInstanceVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IXCLRDataTypeInstance_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IXCLRDataTypeInstance_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IXCLRDataTypeInstance_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IXCLRDataTypeInstance_StartEnumMethodInstances(This,handle) \
+ ( (This)->lpVtbl -> StartEnumMethodInstances(This,handle) )
+
+#define IXCLRDataTypeInstance_EnumMethodInstance(This,handle,methodInstance) \
+ ( (This)->lpVtbl -> EnumMethodInstance(This,handle,methodInstance) )
+
+#define IXCLRDataTypeInstance_EndEnumMethodInstances(This,handle) \
+ ( (This)->lpVtbl -> EndEnumMethodInstances(This,handle) )
+
+#define IXCLRDataTypeInstance_StartEnumMethodInstancesByName(This,name,flags,handle) \
+ ( (This)->lpVtbl -> StartEnumMethodInstancesByName(This,name,flags,handle) )
+
+#define IXCLRDataTypeInstance_EnumMethodInstanceByName(This,handle,method) \
+ ( (This)->lpVtbl -> EnumMethodInstanceByName(This,handle,method) )
+
+#define IXCLRDataTypeInstance_EndEnumMethodInstancesByName(This,handle) \
+ ( (This)->lpVtbl -> EndEnumMethodInstancesByName(This,handle) )
+
+#define IXCLRDataTypeInstance_GetNumStaticFields(This,numFields) \
+ ( (This)->lpVtbl -> GetNumStaticFields(This,numFields) )
+
+#define IXCLRDataTypeInstance_GetStaticFieldByIndex(This,index,tlsTask,field,bufLen,nameLen,nameBuf,token) \
+ ( (This)->lpVtbl -> GetStaticFieldByIndex(This,index,tlsTask,field,bufLen,nameLen,nameBuf,token) )
+
+#define IXCLRDataTypeInstance_StartEnumStaticFieldsByName(This,name,flags,tlsTask,handle) \
+ ( (This)->lpVtbl -> StartEnumStaticFieldsByName(This,name,flags,tlsTask,handle) )
+
+#define IXCLRDataTypeInstance_EnumStaticFieldByName(This,handle,value) \
+ ( (This)->lpVtbl -> EnumStaticFieldByName(This,handle,value) )
+
+#define IXCLRDataTypeInstance_EndEnumStaticFieldsByName(This,handle) \
+ ( (This)->lpVtbl -> EndEnumStaticFieldsByName(This,handle) )
+
+#define IXCLRDataTypeInstance_GetNumTypeArguments(This,numTypeArgs) \
+ ( (This)->lpVtbl -> GetNumTypeArguments(This,numTypeArgs) )
+
+#define IXCLRDataTypeInstance_GetTypeArgumentByIndex(This,index,typeArg) \
+ ( (This)->lpVtbl -> GetTypeArgumentByIndex(This,index,typeArg) )
+
+#define IXCLRDataTypeInstance_GetName(This,flags,bufLen,nameLen,nameBuf) \
+ ( (This)->lpVtbl -> GetName(This,flags,bufLen,nameLen,nameBuf) )
+
+#define IXCLRDataTypeInstance_GetModule(This,mod) \
+ ( (This)->lpVtbl -> GetModule(This,mod) )
+
+#define IXCLRDataTypeInstance_GetDefinition(This,typeDefinition) \
+ ( (This)->lpVtbl -> GetDefinition(This,typeDefinition) )
+
+#define IXCLRDataTypeInstance_GetFlags(This,flags) \
+ ( (This)->lpVtbl -> GetFlags(This,flags) )
+
+#define IXCLRDataTypeInstance_IsSameObject(This,type) \
+ ( (This)->lpVtbl -> IsSameObject(This,type) )
+
+#define IXCLRDataTypeInstance_Request(This,reqCode,inBufferSize,inBuffer,outBufferSize,outBuffer) \
+ ( (This)->lpVtbl -> Request(This,reqCode,inBufferSize,inBuffer,outBufferSize,outBuffer) )
+
+#define IXCLRDataTypeInstance_GetNumStaticFields2(This,flags,numFields) \
+ ( (This)->lpVtbl -> GetNumStaticFields2(This,flags,numFields) )
+
+#define IXCLRDataTypeInstance_StartEnumStaticFields(This,flags,tlsTask,handle) \
+ ( (This)->lpVtbl -> StartEnumStaticFields(This,flags,tlsTask,handle) )
+
+#define IXCLRDataTypeInstance_EnumStaticField(This,handle,value) \
+ ( (This)->lpVtbl -> EnumStaticField(This,handle,value) )
+
+#define IXCLRDataTypeInstance_EndEnumStaticFields(This,handle) \
+ ( (This)->lpVtbl -> EndEnumStaticFields(This,handle) )
+
+#define IXCLRDataTypeInstance_StartEnumStaticFieldsByName2(This,name,nameFlags,fieldFlags,tlsTask,handle) \
+ ( (This)->lpVtbl -> StartEnumStaticFieldsByName2(This,name,nameFlags,fieldFlags,tlsTask,handle) )
+
+#define IXCLRDataTypeInstance_EnumStaticFieldByName2(This,handle,value) \
+ ( (This)->lpVtbl -> EnumStaticFieldByName2(This,handle,value) )
+
+#define IXCLRDataTypeInstance_EndEnumStaticFieldsByName2(This,handle) \
+ ( (This)->lpVtbl -> EndEnumStaticFieldsByName2(This,handle) )
+
+#define IXCLRDataTypeInstance_GetStaticFieldByToken(This,token,tlsTask,field,bufLen,nameLen,nameBuf) \
+ ( (This)->lpVtbl -> GetStaticFieldByToken(This,token,tlsTask,field,bufLen,nameLen,nameBuf) )
+
+#define IXCLRDataTypeInstance_GetBase(This,base) \
+ ( (This)->lpVtbl -> GetBase(This,base) )
+
+#define IXCLRDataTypeInstance_EnumStaticField2(This,handle,value,bufLen,nameLen,nameBuf,tokenScope,token) \
+ ( (This)->lpVtbl -> EnumStaticField2(This,handle,value,bufLen,nameLen,nameBuf,tokenScope,token) )
+
+#define IXCLRDataTypeInstance_EnumStaticFieldByName3(This,handle,value,tokenScope,token) \
+ ( (This)->lpVtbl -> EnumStaticFieldByName3(This,handle,value,tokenScope,token) )
+
+#define IXCLRDataTypeInstance_GetStaticFieldByToken2(This,tokenScope,token,tlsTask,field,bufLen,nameLen,nameBuf) \
+ ( (This)->lpVtbl -> GetStaticFieldByToken2(This,tokenScope,token,tlsTask,field,bufLen,nameLen,nameBuf) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IXCLRDataTypeInstance_INTERFACE_DEFINED__ */
+
+
+/* interface __MIDL_itf_xclrdata_0000_0012 */
+/* [local] */
+
+#pragma warning(pop)
+typedef /* [public][public][public] */
+enum __MIDL___MIDL_itf_xclrdata_0000_0012_0001
+ {
+ CLRDATA_SOURCE_TYPE_INVALID = 0
+ } CLRDataSourceType;
+
+typedef /* [public] */
+enum __MIDL___MIDL_itf_xclrdata_0000_0012_0002
+ {
+ CLRDATA_IL_OFFSET_NO_MAPPING = -1,
+ CLRDATA_IL_OFFSET_PROLOG = -2,
+ CLRDATA_IL_OFFSET_EPILOG = -3
+ } CLRDATA_IL_OFFSET_MARKER;
+
+typedef /* [public][public] */ struct __MIDL___MIDL_itf_xclrdata_0000_0012_0003
+ {
+ ULONG32 ilOffset;
+ CLRDATA_ADDRESS startAddress;
+ CLRDATA_ADDRESS endAddress;
+ CLRDataSourceType type;
+ } CLRDATA_IL_ADDRESS_MAP;
+
+typedef /* [public] */
+enum __MIDL___MIDL_itf_xclrdata_0000_0012_0004
+ {
+ CLRDATA_METHOD_DEFAULT = 0,
+ CLRDATA_METHOD_HAS_THIS = 0x1
+ } CLRDataMethodFlag;
+
+typedef /* [public][public][public] */
+enum __MIDL___MIDL_itf_xclrdata_0000_0012_0005
+ {
+ CLRDATA_METHDEF_IL = 0
+ } CLRDataMethodDefinitionExtentType;
+
+typedef /* [public][public] */ struct __MIDL___MIDL_itf_xclrdata_0000_0012_0006
+ {
+ CLRDATA_ADDRESS startAddress;
+ CLRDATA_ADDRESS endAddress;
+ ULONG32 enCVersion;
+ CLRDataMethodDefinitionExtentType type;
+ } CLRDATA_METHDEF_EXTENT;
+
+#pragma warning(push)
+#pragma warning(disable:28718)
+
+
+extern RPC_IF_HANDLE __MIDL_itf_xclrdata_0000_0012_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_xclrdata_0000_0012_v0_0_s_ifspec;
+
+#ifndef __IXCLRDataMethodDefinition_INTERFACE_DEFINED__
+#define __IXCLRDataMethodDefinition_INTERFACE_DEFINED__
+
+/* interface IXCLRDataMethodDefinition */
+/* [uuid][local][object] */
+
+
+EXTERN_C const IID IID_IXCLRDataMethodDefinition;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("AAF60008-FB2C-420b-8FB1-42D244A54A97")
+ IXCLRDataMethodDefinition : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetTypeDefinition(
+ /* [out] */ IXCLRDataTypeDefinition **typeDefinition) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StartEnumInstances(
+ /* [in] */ IXCLRDataAppDomain *appDomain,
+ /* [out] */ CLRDATA_ENUM *handle) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnumInstance(
+ /* [out][in] */ CLRDATA_ENUM *handle,
+ /* [out] */ IXCLRDataMethodInstance **instance) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EndEnumInstances(
+ /* [in] */ CLRDATA_ENUM handle) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetName(
+ /* [in] */ ULONG32 flags,
+ /* [in] */ ULONG32 bufLen,
+ /* [out] */ ULONG32 *nameLen,
+ /* [size_is][out] */ WCHAR name[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetTokenAndScope(
+ /* [out] */ mdMethodDef *token,
+ /* [out] */ IXCLRDataModule **mod) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetFlags(
+ /* [out] */ ULONG32 *flags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE IsSameObject(
+ /* [in] */ IXCLRDataMethodDefinition *method) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetLatestEnCVersion(
+ /* [out] */ ULONG32 *version) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StartEnumExtents(
+ /* [out] */ CLRDATA_ENUM *handle) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnumExtent(
+ /* [out][in] */ CLRDATA_ENUM *handle,
+ /* [out] */ CLRDATA_METHDEF_EXTENT *extent) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EndEnumExtents(
+ /* [in] */ CLRDATA_ENUM handle) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetCodeNotification(
+ /* [out] */ ULONG32 *flags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetCodeNotification(
+ /* [in] */ ULONG32 flags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Request(
+ /* [in] */ ULONG32 reqCode,
+ /* [in] */ ULONG32 inBufferSize,
+ /* [size_is][in] */ BYTE *inBuffer,
+ /* [in] */ ULONG32 outBufferSize,
+ /* [size_is][out] */ BYTE *outBuffer) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetRepresentativeEntryAddress(
+ /* [out] */ CLRDATA_ADDRESS *addr) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE HasClassOrMethodInstantiation(
+ /* [out] */ BOOL *bGeneric) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IXCLRDataMethodDefinitionVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IXCLRDataMethodDefinition * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IXCLRDataMethodDefinition * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IXCLRDataMethodDefinition * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetTypeDefinition )(
+ IXCLRDataMethodDefinition * This,
+ /* [out] */ IXCLRDataTypeDefinition **typeDefinition);
+
+ HRESULT ( STDMETHODCALLTYPE *StartEnumInstances )(
+ IXCLRDataMethodDefinition * This,
+ /* [in] */ IXCLRDataAppDomain *appDomain,
+ /* [out] */ CLRDATA_ENUM *handle);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumInstance )(
+ IXCLRDataMethodDefinition * This,
+ /* [out][in] */ CLRDATA_ENUM *handle,
+ /* [out] */ IXCLRDataMethodInstance **instance);
+
+ HRESULT ( STDMETHODCALLTYPE *EndEnumInstances )(
+ IXCLRDataMethodDefinition * This,
+ /* [in] */ CLRDATA_ENUM handle);
+
+ HRESULT ( STDMETHODCALLTYPE *GetName )(
+ IXCLRDataMethodDefinition * This,
+ /* [in] */ ULONG32 flags,
+ /* [in] */ ULONG32 bufLen,
+ /* [out] */ ULONG32 *nameLen,
+ /* [size_is][out] */ WCHAR name[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetTokenAndScope )(
+ IXCLRDataMethodDefinition * This,
+ /* [out] */ mdMethodDef *token,
+ /* [out] */ IXCLRDataModule **mod);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFlags )(
+ IXCLRDataMethodDefinition * This,
+ /* [out] */ ULONG32 *flags);
+
+ HRESULT ( STDMETHODCALLTYPE *IsSameObject )(
+ IXCLRDataMethodDefinition * This,
+ /* [in] */ IXCLRDataMethodDefinition *method);
+
+ HRESULT ( STDMETHODCALLTYPE *GetLatestEnCVersion )(
+ IXCLRDataMethodDefinition * This,
+ /* [out] */ ULONG32 *version);
+
+ HRESULT ( STDMETHODCALLTYPE *StartEnumExtents )(
+ IXCLRDataMethodDefinition * This,
+ /* [out] */ CLRDATA_ENUM *handle);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumExtent )(
+ IXCLRDataMethodDefinition * This,
+ /* [out][in] */ CLRDATA_ENUM *handle,
+ /* [out] */ CLRDATA_METHDEF_EXTENT *extent);
+
+ HRESULT ( STDMETHODCALLTYPE *EndEnumExtents )(
+ IXCLRDataMethodDefinition * This,
+ /* [in] */ CLRDATA_ENUM handle);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCodeNotification )(
+ IXCLRDataMethodDefinition * This,
+ /* [out] */ ULONG32 *flags);
+
+ HRESULT ( STDMETHODCALLTYPE *SetCodeNotification )(
+ IXCLRDataMethodDefinition * This,
+ /* [in] */ ULONG32 flags);
+
+ HRESULT ( STDMETHODCALLTYPE *Request )(
+ IXCLRDataMethodDefinition * This,
+ /* [in] */ ULONG32 reqCode,
+ /* [in] */ ULONG32 inBufferSize,
+ /* [size_is][in] */ BYTE *inBuffer,
+ /* [in] */ ULONG32 outBufferSize,
+ /* [size_is][out] */ BYTE *outBuffer);
+
+ HRESULT ( STDMETHODCALLTYPE *GetRepresentativeEntryAddress )(
+ IXCLRDataMethodDefinition * This,
+ /* [out] */ CLRDATA_ADDRESS *addr);
+
+ HRESULT ( STDMETHODCALLTYPE *HasClassOrMethodInstantiation )(
+ IXCLRDataMethodDefinition * This,
+ /* [out] */ BOOL *bGeneric);
+
+ END_INTERFACE
+ } IXCLRDataMethodDefinitionVtbl;
+
+ interface IXCLRDataMethodDefinition
+ {
+ CONST_VTBL struct IXCLRDataMethodDefinitionVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IXCLRDataMethodDefinition_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IXCLRDataMethodDefinition_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IXCLRDataMethodDefinition_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IXCLRDataMethodDefinition_GetTypeDefinition(This,typeDefinition) \
+ ( (This)->lpVtbl -> GetTypeDefinition(This,typeDefinition) )
+
+#define IXCLRDataMethodDefinition_StartEnumInstances(This,appDomain,handle) \
+ ( (This)->lpVtbl -> StartEnumInstances(This,appDomain,handle) )
+
+#define IXCLRDataMethodDefinition_EnumInstance(This,handle,instance) \
+ ( (This)->lpVtbl -> EnumInstance(This,handle,instance) )
+
+#define IXCLRDataMethodDefinition_EndEnumInstances(This,handle) \
+ ( (This)->lpVtbl -> EndEnumInstances(This,handle) )
+
+#define IXCLRDataMethodDefinition_GetName(This,flags,bufLen,nameLen,name) \
+ ( (This)->lpVtbl -> GetName(This,flags,bufLen,nameLen,name) )
+
+#define IXCLRDataMethodDefinition_GetTokenAndScope(This,token,mod) \
+ ( (This)->lpVtbl -> GetTokenAndScope(This,token,mod) )
+
+#define IXCLRDataMethodDefinition_GetFlags(This,flags) \
+ ( (This)->lpVtbl -> GetFlags(This,flags) )
+
+#define IXCLRDataMethodDefinition_IsSameObject(This,method) \
+ ( (This)->lpVtbl -> IsSameObject(This,method) )
+
+#define IXCLRDataMethodDefinition_GetLatestEnCVersion(This,version) \
+ ( (This)->lpVtbl -> GetLatestEnCVersion(This,version) )
+
+#define IXCLRDataMethodDefinition_StartEnumExtents(This,handle) \
+ ( (This)->lpVtbl -> StartEnumExtents(This,handle) )
+
+#define IXCLRDataMethodDefinition_EnumExtent(This,handle,extent) \
+ ( (This)->lpVtbl -> EnumExtent(This,handle,extent) )
+
+#define IXCLRDataMethodDefinition_EndEnumExtents(This,handle) \
+ ( (This)->lpVtbl -> EndEnumExtents(This,handle) )
+
+#define IXCLRDataMethodDefinition_GetCodeNotification(This,flags) \
+ ( (This)->lpVtbl -> GetCodeNotification(This,flags) )
+
+#define IXCLRDataMethodDefinition_SetCodeNotification(This,flags) \
+ ( (This)->lpVtbl -> SetCodeNotification(This,flags) )
+
+#define IXCLRDataMethodDefinition_Request(This,reqCode,inBufferSize,inBuffer,outBufferSize,outBuffer) \
+ ( (This)->lpVtbl -> Request(This,reqCode,inBufferSize,inBuffer,outBufferSize,outBuffer) )
+
+#define IXCLRDataMethodDefinition_GetRepresentativeEntryAddress(This,addr) \
+ ( (This)->lpVtbl -> GetRepresentativeEntryAddress(This,addr) )
+
+#define IXCLRDataMethodDefinition_HasClassOrMethodInstantiation(This,bGeneric) \
+ ( (This)->lpVtbl -> HasClassOrMethodInstantiation(This,bGeneric) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IXCLRDataMethodDefinition_INTERFACE_DEFINED__ */
+
+
+/* interface __MIDL_itf_xclrdata_0000_0013 */
+/* [local] */
+
+#pragma warning(pop)
+#pragma warning(push)
+#pragma warning(disable:28718)
+
+
+extern RPC_IF_HANDLE __MIDL_itf_xclrdata_0000_0013_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_xclrdata_0000_0013_v0_0_s_ifspec;
+
+#ifndef __IXCLRDataMethodInstance_INTERFACE_DEFINED__
+#define __IXCLRDataMethodInstance_INTERFACE_DEFINED__
+
+/* interface IXCLRDataMethodInstance */
+/* [uuid][local][object] */
+
+
+EXTERN_C const IID IID_IXCLRDataMethodInstance;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("ECD73800-22CA-4b0d-AB55-E9BA7E6318A5")
+ IXCLRDataMethodInstance : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetTypeInstance(
+ /* [out] */ IXCLRDataTypeInstance **typeInstance) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetDefinition(
+ /* [out] */ IXCLRDataMethodDefinition **methodDefinition) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetTokenAndScope(
+ /* [out] */ mdMethodDef *token,
+ /* [out] */ IXCLRDataModule **mod) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetName(
+ /* [in] */ ULONG32 flags,
+ /* [in] */ ULONG32 bufLen,
+ /* [out] */ ULONG32 *nameLen,
+ /* [size_is][out] */ WCHAR nameBuf[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetFlags(
+ /* [out] */ ULONG32 *flags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE IsSameObject(
+ /* [in] */ IXCLRDataMethodInstance *method) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetEnCVersion(
+ /* [out] */ ULONG32 *version) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetNumTypeArguments(
+ /* [out] */ ULONG32 *numTypeArgs) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetTypeArgumentByIndex(
+ /* [in] */ ULONG32 index,
+ /* [out] */ IXCLRDataTypeInstance **typeArg) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetILOffsetsByAddress(
+ /* [in] */ CLRDATA_ADDRESS address,
+ /* [in] */ ULONG32 offsetsLen,
+ /* [out] */ ULONG32 *offsetsNeeded,
+ /* [size_is][out] */ ULONG32 ilOffsets[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetAddressRangesByILOffset(
+ /* [in] */ ULONG32 ilOffset,
+ /* [in] */ ULONG32 rangesLen,
+ /* [out] */ ULONG32 *rangesNeeded,
+ /* [size_is][out] */ CLRDATA_ADDRESS_RANGE addressRanges[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetILAddressMap(
+ /* [in] */ ULONG32 mapLen,
+ /* [out] */ ULONG32 *mapNeeded,
+ /* [size_is][out] */ CLRDATA_IL_ADDRESS_MAP maps[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StartEnumExtents(
+ /* [out] */ CLRDATA_ENUM *handle) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnumExtent(
+ /* [out][in] */ CLRDATA_ENUM *handle,
+ /* [out] */ CLRDATA_ADDRESS_RANGE *extent) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EndEnumExtents(
+ /* [in] */ CLRDATA_ENUM handle) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Request(
+ /* [in] */ ULONG32 reqCode,
+ /* [in] */ ULONG32 inBufferSize,
+ /* [size_is][in] */ BYTE *inBuffer,
+ /* [in] */ ULONG32 outBufferSize,
+ /* [size_is][out] */ BYTE *outBuffer) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetRepresentativeEntryAddress(
+ /* [out] */ CLRDATA_ADDRESS *addr) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IXCLRDataMethodInstanceVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IXCLRDataMethodInstance * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IXCLRDataMethodInstance * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IXCLRDataMethodInstance * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetTypeInstance )(
+ IXCLRDataMethodInstance * This,
+ /* [out] */ IXCLRDataTypeInstance **typeInstance);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDefinition )(
+ IXCLRDataMethodInstance * This,
+ /* [out] */ IXCLRDataMethodDefinition **methodDefinition);
+
+ HRESULT ( STDMETHODCALLTYPE *GetTokenAndScope )(
+ IXCLRDataMethodInstance * This,
+ /* [out] */ mdMethodDef *token,
+ /* [out] */ IXCLRDataModule **mod);
+
+ HRESULT ( STDMETHODCALLTYPE *GetName )(
+ IXCLRDataMethodInstance * This,
+ /* [in] */ ULONG32 flags,
+ /* [in] */ ULONG32 bufLen,
+ /* [out] */ ULONG32 *nameLen,
+ /* [size_is][out] */ WCHAR nameBuf[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFlags )(
+ IXCLRDataMethodInstance * This,
+ /* [out] */ ULONG32 *flags);
+
+ HRESULT ( STDMETHODCALLTYPE *IsSameObject )(
+ IXCLRDataMethodInstance * This,
+ /* [in] */ IXCLRDataMethodInstance *method);
+
+ HRESULT ( STDMETHODCALLTYPE *GetEnCVersion )(
+ IXCLRDataMethodInstance * This,
+ /* [out] */ ULONG32 *version);
+
+ HRESULT ( STDMETHODCALLTYPE *GetNumTypeArguments )(
+ IXCLRDataMethodInstance * This,
+ /* [out] */ ULONG32 *numTypeArgs);
+
+ HRESULT ( STDMETHODCALLTYPE *GetTypeArgumentByIndex )(
+ IXCLRDataMethodInstance * This,
+ /* [in] */ ULONG32 index,
+ /* [out] */ IXCLRDataTypeInstance **typeArg);
+
+ HRESULT ( STDMETHODCALLTYPE *GetILOffsetsByAddress )(
+ IXCLRDataMethodInstance * This,
+ /* [in] */ CLRDATA_ADDRESS address,
+ /* [in] */ ULONG32 offsetsLen,
+ /* [out] */ ULONG32 *offsetsNeeded,
+ /* [size_is][out] */ ULONG32 ilOffsets[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAddressRangesByILOffset )(
+ IXCLRDataMethodInstance * This,
+ /* [in] */ ULONG32 ilOffset,
+ /* [in] */ ULONG32 rangesLen,
+ /* [out] */ ULONG32 *rangesNeeded,
+ /* [size_is][out] */ CLRDATA_ADDRESS_RANGE addressRanges[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetILAddressMap )(
+ IXCLRDataMethodInstance * This,
+ /* [in] */ ULONG32 mapLen,
+ /* [out] */ ULONG32 *mapNeeded,
+ /* [size_is][out] */ CLRDATA_IL_ADDRESS_MAP maps[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *StartEnumExtents )(
+ IXCLRDataMethodInstance * This,
+ /* [out] */ CLRDATA_ENUM *handle);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumExtent )(
+ IXCLRDataMethodInstance * This,
+ /* [out][in] */ CLRDATA_ENUM *handle,
+ /* [out] */ CLRDATA_ADDRESS_RANGE *extent);
+
+ HRESULT ( STDMETHODCALLTYPE *EndEnumExtents )(
+ IXCLRDataMethodInstance * This,
+ /* [in] */ CLRDATA_ENUM handle);
+
+ HRESULT ( STDMETHODCALLTYPE *Request )(
+ IXCLRDataMethodInstance * This,
+ /* [in] */ ULONG32 reqCode,
+ /* [in] */ ULONG32 inBufferSize,
+ /* [size_is][in] */ BYTE *inBuffer,
+ /* [in] */ ULONG32 outBufferSize,
+ /* [size_is][out] */ BYTE *outBuffer);
+
+ HRESULT ( STDMETHODCALLTYPE *GetRepresentativeEntryAddress )(
+ IXCLRDataMethodInstance * This,
+ /* [out] */ CLRDATA_ADDRESS *addr);
+
+ END_INTERFACE
+ } IXCLRDataMethodInstanceVtbl;
+
+ interface IXCLRDataMethodInstance
+ {
+ CONST_VTBL struct IXCLRDataMethodInstanceVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IXCLRDataMethodInstance_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IXCLRDataMethodInstance_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IXCLRDataMethodInstance_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IXCLRDataMethodInstance_GetTypeInstance(This,typeInstance) \
+ ( (This)->lpVtbl -> GetTypeInstance(This,typeInstance) )
+
+#define IXCLRDataMethodInstance_GetDefinition(This,methodDefinition) \
+ ( (This)->lpVtbl -> GetDefinition(This,methodDefinition) )
+
+#define IXCLRDataMethodInstance_GetTokenAndScope(This,token,mod) \
+ ( (This)->lpVtbl -> GetTokenAndScope(This,token,mod) )
+
+#define IXCLRDataMethodInstance_GetName(This,flags,bufLen,nameLen,nameBuf) \
+ ( (This)->lpVtbl -> GetName(This,flags,bufLen,nameLen,nameBuf) )
+
+#define IXCLRDataMethodInstance_GetFlags(This,flags) \
+ ( (This)->lpVtbl -> GetFlags(This,flags) )
+
+#define IXCLRDataMethodInstance_IsSameObject(This,method) \
+ ( (This)->lpVtbl -> IsSameObject(This,method) )
+
+#define IXCLRDataMethodInstance_GetEnCVersion(This,version) \
+ ( (This)->lpVtbl -> GetEnCVersion(This,version) )
+
+#define IXCLRDataMethodInstance_GetNumTypeArguments(This,numTypeArgs) \
+ ( (This)->lpVtbl -> GetNumTypeArguments(This,numTypeArgs) )
+
+#define IXCLRDataMethodInstance_GetTypeArgumentByIndex(This,index,typeArg) \
+ ( (This)->lpVtbl -> GetTypeArgumentByIndex(This,index,typeArg) )
+
+#define IXCLRDataMethodInstance_GetILOffsetsByAddress(This,address,offsetsLen,offsetsNeeded,ilOffsets) \
+ ( (This)->lpVtbl -> GetILOffsetsByAddress(This,address,offsetsLen,offsetsNeeded,ilOffsets) )
+
+#define IXCLRDataMethodInstance_GetAddressRangesByILOffset(This,ilOffset,rangesLen,rangesNeeded,addressRanges) \
+ ( (This)->lpVtbl -> GetAddressRangesByILOffset(This,ilOffset,rangesLen,rangesNeeded,addressRanges) )
+
+#define IXCLRDataMethodInstance_GetILAddressMap(This,mapLen,mapNeeded,maps) \
+ ( (This)->lpVtbl -> GetILAddressMap(This,mapLen,mapNeeded,maps) )
+
+#define IXCLRDataMethodInstance_StartEnumExtents(This,handle) \
+ ( (This)->lpVtbl -> StartEnumExtents(This,handle) )
+
+#define IXCLRDataMethodInstance_EnumExtent(This,handle,extent) \
+ ( (This)->lpVtbl -> EnumExtent(This,handle,extent) )
+
+#define IXCLRDataMethodInstance_EndEnumExtents(This,handle) \
+ ( (This)->lpVtbl -> EndEnumExtents(This,handle) )
+
+#define IXCLRDataMethodInstance_Request(This,reqCode,inBufferSize,inBuffer,outBufferSize,outBuffer) \
+ ( (This)->lpVtbl -> Request(This,reqCode,inBufferSize,inBuffer,outBufferSize,outBuffer) )
+
+#define IXCLRDataMethodInstance_GetRepresentativeEntryAddress(This,addr) \
+ ( (This)->lpVtbl -> GetRepresentativeEntryAddress(This,addr) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IXCLRDataMethodInstance_INTERFACE_DEFINED__ */
+
+
+/* interface __MIDL_itf_xclrdata_0000_0014 */
+/* [local] */
+
+#pragma warning(pop)
+typedef /* [public] */
+enum __MIDL___MIDL_itf_xclrdata_0000_0014_0001
+ {
+ CLRDATA_TASK_DEFAULT = 0,
+ CLRDATA_TASK_WAITING_FOR_GC = 0x1
+ } CLRDataTaskFlag;
+
+#pragma warning(push)
+#pragma warning(disable:28718)
+
+
+extern RPC_IF_HANDLE __MIDL_itf_xclrdata_0000_0014_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_xclrdata_0000_0014_v0_0_s_ifspec;
+
+#ifndef __IXCLRDataTask_INTERFACE_DEFINED__
+#define __IXCLRDataTask_INTERFACE_DEFINED__
+
+/* interface IXCLRDataTask */
+/* [uuid][local][object] */
+
+
+EXTERN_C const IID IID_IXCLRDataTask;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("A5B0BEEA-EC62-4618-8012-A24FFC23934C")
+ IXCLRDataTask : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetProcess(
+ /* [out] */ IXCLRDataProcess **process) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetCurrentAppDomain(
+ /* [out] */ IXCLRDataAppDomain **appDomain) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetUniqueID(
+ /* [out] */ ULONG64 *id) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetFlags(
+ /* [out] */ ULONG32 *flags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE IsSameObject(
+ /* [in] */ IXCLRDataTask *task) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetManagedObject(
+ /* [out] */ IXCLRDataValue **value) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetDesiredExecutionState(
+ /* [out] */ ULONG32 *state) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetDesiredExecutionState(
+ /* [in] */ ULONG32 state) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE CreateStackWalk(
+ /* [in] */ ULONG32 flags,
+ /* [out] */ IXCLRDataStackWalk **stackWalk) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetOSThreadID(
+ /* [out] */ ULONG32 *id) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetContext(
+ /* [in] */ ULONG32 contextFlags,
+ /* [in] */ ULONG32 contextBufSize,
+ /* [out] */ ULONG32 *contextSize,
+ /* [size_is][out] */ BYTE contextBuf[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetContext(
+ /* [in] */ ULONG32 contextSize,
+ /* [size_is][in] */ BYTE context[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetCurrentExceptionState(
+ /* [out] */ IXCLRDataExceptionState **exception) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Request(
+ /* [in] */ ULONG32 reqCode,
+ /* [in] */ ULONG32 inBufferSize,
+ /* [size_is][in] */ BYTE *inBuffer,
+ /* [in] */ ULONG32 outBufferSize,
+ /* [size_is][out] */ BYTE *outBuffer) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetName(
+ /* [in] */ ULONG32 bufLen,
+ /* [out] */ ULONG32 *nameLen,
+ /* [size_is][out] */ WCHAR name[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetLastExceptionState(
+ /* [out] */ IXCLRDataExceptionState **exception) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IXCLRDataTaskVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IXCLRDataTask * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IXCLRDataTask * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IXCLRDataTask * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetProcess )(
+ IXCLRDataTask * This,
+ /* [out] */ IXCLRDataProcess **process);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCurrentAppDomain )(
+ IXCLRDataTask * This,
+ /* [out] */ IXCLRDataAppDomain **appDomain);
+
+ HRESULT ( STDMETHODCALLTYPE *GetUniqueID )(
+ IXCLRDataTask * This,
+ /* [out] */ ULONG64 *id);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFlags )(
+ IXCLRDataTask * This,
+ /* [out] */ ULONG32 *flags);
+
+ HRESULT ( STDMETHODCALLTYPE *IsSameObject )(
+ IXCLRDataTask * This,
+ /* [in] */ IXCLRDataTask *task);
+
+ HRESULT ( STDMETHODCALLTYPE *GetManagedObject )(
+ IXCLRDataTask * This,
+ /* [out] */ IXCLRDataValue **value);
+
+ HRESULT ( STDMETHODCALLTYPE *GetDesiredExecutionState )(
+ IXCLRDataTask * This,
+ /* [out] */ ULONG32 *state);
+
+ HRESULT ( STDMETHODCALLTYPE *SetDesiredExecutionState )(
+ IXCLRDataTask * This,
+ /* [in] */ ULONG32 state);
+
+ HRESULT ( STDMETHODCALLTYPE *CreateStackWalk )(
+ IXCLRDataTask * This,
+ /* [in] */ ULONG32 flags,
+ /* [out] */ IXCLRDataStackWalk **stackWalk);
+
+ HRESULT ( STDMETHODCALLTYPE *GetOSThreadID )(
+ IXCLRDataTask * This,
+ /* [out] */ ULONG32 *id);
+
+ HRESULT ( STDMETHODCALLTYPE *GetContext )(
+ IXCLRDataTask * This,
+ /* [in] */ ULONG32 contextFlags,
+ /* [in] */ ULONG32 contextBufSize,
+ /* [out] */ ULONG32 *contextSize,
+ /* [size_is][out] */ BYTE contextBuf[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *SetContext )(
+ IXCLRDataTask * This,
+ /* [in] */ ULONG32 contextSize,
+ /* [size_is][in] */ BYTE context[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCurrentExceptionState )(
+ IXCLRDataTask * This,
+ /* [out] */ IXCLRDataExceptionState **exception);
+
+ HRESULT ( STDMETHODCALLTYPE *Request )(
+ IXCLRDataTask * This,
+ /* [in] */ ULONG32 reqCode,
+ /* [in] */ ULONG32 inBufferSize,
+ /* [size_is][in] */ BYTE *inBuffer,
+ /* [in] */ ULONG32 outBufferSize,
+ /* [size_is][out] */ BYTE *outBuffer);
+
+ HRESULT ( STDMETHODCALLTYPE *GetName )(
+ IXCLRDataTask * This,
+ /* [in] */ ULONG32 bufLen,
+ /* [out] */ ULONG32 *nameLen,
+ /* [size_is][out] */ WCHAR name[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetLastExceptionState )(
+ IXCLRDataTask * This,
+ /* [out] */ IXCLRDataExceptionState **exception);
+
+ END_INTERFACE
+ } IXCLRDataTaskVtbl;
+
+ interface IXCLRDataTask
+ {
+ CONST_VTBL struct IXCLRDataTaskVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IXCLRDataTask_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IXCLRDataTask_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IXCLRDataTask_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IXCLRDataTask_GetProcess(This,process) \
+ ( (This)->lpVtbl -> GetProcess(This,process) )
+
+#define IXCLRDataTask_GetCurrentAppDomain(This,appDomain) \
+ ( (This)->lpVtbl -> GetCurrentAppDomain(This,appDomain) )
+
+#define IXCLRDataTask_GetUniqueID(This,id) \
+ ( (This)->lpVtbl -> GetUniqueID(This,id) )
+
+#define IXCLRDataTask_GetFlags(This,flags) \
+ ( (This)->lpVtbl -> GetFlags(This,flags) )
+
+#define IXCLRDataTask_IsSameObject(This,task) \
+ ( (This)->lpVtbl -> IsSameObject(This,task) )
+
+#define IXCLRDataTask_GetManagedObject(This,value) \
+ ( (This)->lpVtbl -> GetManagedObject(This,value) )
+
+#define IXCLRDataTask_GetDesiredExecutionState(This,state) \
+ ( (This)->lpVtbl -> GetDesiredExecutionState(This,state) )
+
+#define IXCLRDataTask_SetDesiredExecutionState(This,state) \
+ ( (This)->lpVtbl -> SetDesiredExecutionState(This,state) )
+
+#define IXCLRDataTask_CreateStackWalk(This,flags,stackWalk) \
+ ( (This)->lpVtbl -> CreateStackWalk(This,flags,stackWalk) )
+
+#define IXCLRDataTask_GetOSThreadID(This,id) \
+ ( (This)->lpVtbl -> GetOSThreadID(This,id) )
+
+#define IXCLRDataTask_GetContext(This,contextFlags,contextBufSize,contextSize,contextBuf) \
+ ( (This)->lpVtbl -> GetContext(This,contextFlags,contextBufSize,contextSize,contextBuf) )
+
+#define IXCLRDataTask_SetContext(This,contextSize,context) \
+ ( (This)->lpVtbl -> SetContext(This,contextSize,context) )
+
+#define IXCLRDataTask_GetCurrentExceptionState(This,exception) \
+ ( (This)->lpVtbl -> GetCurrentExceptionState(This,exception) )
+
+#define IXCLRDataTask_Request(This,reqCode,inBufferSize,inBuffer,outBufferSize,outBuffer) \
+ ( (This)->lpVtbl -> Request(This,reqCode,inBufferSize,inBuffer,outBufferSize,outBuffer) )
+
+#define IXCLRDataTask_GetName(This,bufLen,nameLen,name) \
+ ( (This)->lpVtbl -> GetName(This,bufLen,nameLen,name) )
+
+#define IXCLRDataTask_GetLastExceptionState(This,exception) \
+ ( (This)->lpVtbl -> GetLastExceptionState(This,exception) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IXCLRDataTask_INTERFACE_DEFINED__ */
+
+
+/* interface __MIDL_itf_xclrdata_0000_0015 */
+/* [local] */
+
+#pragma warning(pop)
+typedef /* [public][public][public] */
+enum __MIDL___MIDL_itf_xclrdata_0000_0015_0001
+ {
+ CLRDATA_SIMPFRAME_UNRECOGNIZED = 0x1,
+ CLRDATA_SIMPFRAME_MANAGED_METHOD = 0x2,
+ CLRDATA_SIMPFRAME_RUNTIME_MANAGED_CODE = 0x4,
+ CLRDATA_SIMPFRAME_RUNTIME_UNMANAGED_CODE = 0x8
+ } CLRDataSimpleFrameType;
+
+typedef /* [public][public][public] */
+enum __MIDL___MIDL_itf_xclrdata_0000_0015_0002
+ {
+ CLRDATA_DETFRAME_UNRECOGNIZED = 0,
+ CLRDATA_DETFRAME_UNKNOWN_STUB = ( CLRDATA_DETFRAME_UNRECOGNIZED + 1 ) ,
+ CLRDATA_DETFRAME_CLASS_INIT = ( CLRDATA_DETFRAME_UNKNOWN_STUB + 1 ) ,
+ CLRDATA_DETFRAME_EXCEPTION_FILTER = ( CLRDATA_DETFRAME_CLASS_INIT + 1 ) ,
+ CLRDATA_DETFRAME_SECURITY = ( CLRDATA_DETFRAME_EXCEPTION_FILTER + 1 ) ,
+ CLRDATA_DETFRAME_CONTEXT_POLICY = ( CLRDATA_DETFRAME_SECURITY + 1 ) ,
+ CLRDATA_DETFRAME_INTERCEPTION = ( CLRDATA_DETFRAME_CONTEXT_POLICY + 1 ) ,
+ CLRDATA_DETFRAME_PROCESS_START = ( CLRDATA_DETFRAME_INTERCEPTION + 1 ) ,
+ CLRDATA_DETFRAME_THREAD_START = ( CLRDATA_DETFRAME_PROCESS_START + 1 ) ,
+ CLRDATA_DETFRAME_TRANSITION_TO_MANAGED = ( CLRDATA_DETFRAME_THREAD_START + 1 ) ,
+ CLRDATA_DETFRAME_TRANSITION_TO_UNMANAGED = ( CLRDATA_DETFRAME_TRANSITION_TO_MANAGED + 1 ) ,
+ CLRDATA_DETFRAME_COM_INTEROP_STUB = ( CLRDATA_DETFRAME_TRANSITION_TO_UNMANAGED + 1 ) ,
+ CLRDATA_DETFRAME_DEBUGGER_EVAL = ( CLRDATA_DETFRAME_COM_INTEROP_STUB + 1 ) ,
+ CLRDATA_DETFRAME_CONTEXT_SWITCH = ( CLRDATA_DETFRAME_DEBUGGER_EVAL + 1 ) ,
+ CLRDATA_DETFRAME_FUNC_EVAL = ( CLRDATA_DETFRAME_CONTEXT_SWITCH + 1 ) ,
+ CLRDATA_DETFRAME_FINALLY = ( CLRDATA_DETFRAME_FUNC_EVAL + 1 )
+ } CLRDataDetailedFrameType;
+
+typedef /* [public] */
+enum __MIDL___MIDL_itf_xclrdata_0000_0015_0003
+ {
+ CLRDATA_STACK_WALK_REQUEST_SET_FIRST_FRAME = 0xe1000000
+ } CLRDataStackWalkRequest;
+
+typedef /* [public] */
+enum __MIDL___MIDL_itf_xclrdata_0000_0015_0004
+ {
+ CLRDATA_STACK_SET_UNWIND_CONTEXT = 0,
+ CLRDATA_STACK_SET_CURRENT_CONTEXT = 0x1
+ } CLRDataStackSetContextFlag;
+
+
+
+extern RPC_IF_HANDLE __MIDL_itf_xclrdata_0000_0015_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_xclrdata_0000_0015_v0_0_s_ifspec;
+
+#ifndef __IXCLRDataStackWalk_INTERFACE_DEFINED__
+#define __IXCLRDataStackWalk_INTERFACE_DEFINED__
+
+/* interface IXCLRDataStackWalk */
+/* [uuid][local][object] */
+
+
+EXTERN_C const IID IID_IXCLRDataStackWalk;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("E59D8D22-ADA7-49a2-89B5-A415AFCFC95F")
+ IXCLRDataStackWalk : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetContext(
+ /* [in] */ ULONG32 contextFlags,
+ /* [in] */ ULONG32 contextBufSize,
+ /* [out] */ ULONG32 *contextSize,
+ /* [size_is][out] */ BYTE contextBuf[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetContext(
+ /* [in] */ ULONG32 contextSize,
+ /* [size_is][in] */ BYTE context[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Next( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetStackSizeSkipped(
+ /* [out] */ ULONG64 *stackSizeSkipped) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetFrameType(
+ /* [out] */ CLRDataSimpleFrameType *simpleType,
+ /* [out] */ CLRDataDetailedFrameType *detailedType) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetFrame(
+ /* [out] */ IXCLRDataFrame **frame) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Request(
+ /* [in] */ ULONG32 reqCode,
+ /* [in] */ ULONG32 inBufferSize,
+ /* [size_is][in] */ BYTE *inBuffer,
+ /* [in] */ ULONG32 outBufferSize,
+ /* [size_is][out] */ BYTE *outBuffer) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetContext2(
+ /* [in] */ ULONG32 flags,
+ /* [in] */ ULONG32 contextSize,
+ /* [size_is][in] */ BYTE context[ ]) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IXCLRDataStackWalkVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IXCLRDataStackWalk * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IXCLRDataStackWalk * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IXCLRDataStackWalk * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetContext )(
+ IXCLRDataStackWalk * This,
+ /* [in] */ ULONG32 contextFlags,
+ /* [in] */ ULONG32 contextBufSize,
+ /* [out] */ ULONG32 *contextSize,
+ /* [size_is][out] */ BYTE contextBuf[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *SetContext )(
+ IXCLRDataStackWalk * This,
+ /* [in] */ ULONG32 contextSize,
+ /* [size_is][in] */ BYTE context[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *Next )(
+ IXCLRDataStackWalk * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetStackSizeSkipped )(
+ IXCLRDataStackWalk * This,
+ /* [out] */ ULONG64 *stackSizeSkipped);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFrameType )(
+ IXCLRDataStackWalk * This,
+ /* [out] */ CLRDataSimpleFrameType *simpleType,
+ /* [out] */ CLRDataDetailedFrameType *detailedType);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFrame )(
+ IXCLRDataStackWalk * This,
+ /* [out] */ IXCLRDataFrame **frame);
+
+ HRESULT ( STDMETHODCALLTYPE *Request )(
+ IXCLRDataStackWalk * This,
+ /* [in] */ ULONG32 reqCode,
+ /* [in] */ ULONG32 inBufferSize,
+ /* [size_is][in] */ BYTE *inBuffer,
+ /* [in] */ ULONG32 outBufferSize,
+ /* [size_is][out] */ BYTE *outBuffer);
+
+ HRESULT ( STDMETHODCALLTYPE *SetContext2 )(
+ IXCLRDataStackWalk * This,
+ /* [in] */ ULONG32 flags,
+ /* [in] */ ULONG32 contextSize,
+ /* [size_is][in] */ BYTE context[ ]);
+
+ END_INTERFACE
+ } IXCLRDataStackWalkVtbl;
+
+ interface IXCLRDataStackWalk
+ {
+ CONST_VTBL struct IXCLRDataStackWalkVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IXCLRDataStackWalk_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IXCLRDataStackWalk_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IXCLRDataStackWalk_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IXCLRDataStackWalk_GetContext(This,contextFlags,contextBufSize,contextSize,contextBuf) \
+ ( (This)->lpVtbl -> GetContext(This,contextFlags,contextBufSize,contextSize,contextBuf) )
+
+#define IXCLRDataStackWalk_SetContext(This,contextSize,context) \
+ ( (This)->lpVtbl -> SetContext(This,contextSize,context) )
+
+#define IXCLRDataStackWalk_Next(This) \
+ ( (This)->lpVtbl -> Next(This) )
+
+#define IXCLRDataStackWalk_GetStackSizeSkipped(This,stackSizeSkipped) \
+ ( (This)->lpVtbl -> GetStackSizeSkipped(This,stackSizeSkipped) )
+
+#define IXCLRDataStackWalk_GetFrameType(This,simpleType,detailedType) \
+ ( (This)->lpVtbl -> GetFrameType(This,simpleType,detailedType) )
+
+#define IXCLRDataStackWalk_GetFrame(This,frame) \
+ ( (This)->lpVtbl -> GetFrame(This,frame) )
+
+#define IXCLRDataStackWalk_Request(This,reqCode,inBufferSize,inBuffer,outBufferSize,outBuffer) \
+ ( (This)->lpVtbl -> Request(This,reqCode,inBufferSize,inBuffer,outBufferSize,outBuffer) )
+
+#define IXCLRDataStackWalk_SetContext2(This,flags,contextSize,context) \
+ ( (This)->lpVtbl -> SetContext2(This,flags,contextSize,context) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IXCLRDataStackWalk_INTERFACE_DEFINED__ */
+
+
+/* interface __MIDL_itf_xclrdata_0000_0016 */
+/* [local] */
+
+#pragma warning(push)
+#pragma warning(disable:28718)
+
+
+extern RPC_IF_HANDLE __MIDL_itf_xclrdata_0000_0016_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_xclrdata_0000_0016_v0_0_s_ifspec;
+
+#ifndef __IXCLRDataFrame_INTERFACE_DEFINED__
+#define __IXCLRDataFrame_INTERFACE_DEFINED__
+
+/* interface IXCLRDataFrame */
+/* [uuid][local][object] */
+
+
+EXTERN_C const IID IID_IXCLRDataFrame;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("271498C2-4085-4766-BC3A-7F8ED188A173")
+ IXCLRDataFrame : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetFrameType(
+ /* [out] */ CLRDataSimpleFrameType *simpleType,
+ /* [out] */ CLRDataDetailedFrameType *detailedType) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetContext(
+ /* [in] */ ULONG32 contextFlags,
+ /* [in] */ ULONG32 contextBufSize,
+ /* [out] */ ULONG32 *contextSize,
+ /* [size_is][out] */ BYTE contextBuf[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetAppDomain(
+ /* [out] */ IXCLRDataAppDomain **appDomain) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetNumArguments(
+ /* [out] */ ULONG32 *numArgs) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetArgumentByIndex(
+ /* [in] */ ULONG32 index,
+ /* [out] */ IXCLRDataValue **arg,
+ /* [in] */ ULONG32 bufLen,
+ /* [out] */ ULONG32 *nameLen,
+ /* [size_is][out] */ WCHAR name[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetNumLocalVariables(
+ /* [out] */ ULONG32 *numLocals) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetLocalVariableByIndex(
+ /* [in] */ ULONG32 index,
+ /* [out] */ IXCLRDataValue **localVariable,
+ /* [in] */ ULONG32 bufLen,
+ /* [out] */ ULONG32 *nameLen,
+ /* [size_is][out] */ WCHAR name[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetCodeName(
+ /* [in] */ ULONG32 flags,
+ /* [in] */ ULONG32 bufLen,
+ /* [out] */ ULONG32 *nameLen,
+ /* [size_is][out] */ WCHAR nameBuf[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetMethodInstance(
+ /* [out] */ IXCLRDataMethodInstance **method) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Request(
+ /* [in] */ ULONG32 reqCode,
+ /* [in] */ ULONG32 inBufferSize,
+ /* [size_is][in] */ BYTE *inBuffer,
+ /* [in] */ ULONG32 outBufferSize,
+ /* [size_is][out] */ BYTE *outBuffer) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetNumTypeArguments(
+ /* [out] */ ULONG32 *numTypeArgs) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetTypeArgumentByIndex(
+ /* [in] */ ULONG32 index,
+ /* [out] */ IXCLRDataTypeInstance **typeArg) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IXCLRDataFrameVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IXCLRDataFrame * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IXCLRDataFrame * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IXCLRDataFrame * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFrameType )(
+ IXCLRDataFrame * This,
+ /* [out] */ CLRDataSimpleFrameType *simpleType,
+ /* [out] */ CLRDataDetailedFrameType *detailedType);
+
+ HRESULT ( STDMETHODCALLTYPE *GetContext )(
+ IXCLRDataFrame * This,
+ /* [in] */ ULONG32 contextFlags,
+ /* [in] */ ULONG32 contextBufSize,
+ /* [out] */ ULONG32 *contextSize,
+ /* [size_is][out] */ BYTE contextBuf[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAppDomain )(
+ IXCLRDataFrame * This,
+ /* [out] */ IXCLRDataAppDomain **appDomain);
+
+ HRESULT ( STDMETHODCALLTYPE *GetNumArguments )(
+ IXCLRDataFrame * This,
+ /* [out] */ ULONG32 *numArgs);
+
+ HRESULT ( STDMETHODCALLTYPE *GetArgumentByIndex )(
+ IXCLRDataFrame * This,
+ /* [in] */ ULONG32 index,
+ /* [out] */ IXCLRDataValue **arg,
+ /* [in] */ ULONG32 bufLen,
+ /* [out] */ ULONG32 *nameLen,
+ /* [size_is][out] */ WCHAR name[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetNumLocalVariables )(
+ IXCLRDataFrame * This,
+ /* [out] */ ULONG32 *numLocals);
+
+ HRESULT ( STDMETHODCALLTYPE *GetLocalVariableByIndex )(
+ IXCLRDataFrame * This,
+ /* [in] */ ULONG32 index,
+ /* [out] */ IXCLRDataValue **localVariable,
+ /* [in] */ ULONG32 bufLen,
+ /* [out] */ ULONG32 *nameLen,
+ /* [size_is][out] */ WCHAR name[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCodeName )(
+ IXCLRDataFrame * This,
+ /* [in] */ ULONG32 flags,
+ /* [in] */ ULONG32 bufLen,
+ /* [out] */ ULONG32 *nameLen,
+ /* [size_is][out] */ WCHAR nameBuf[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetMethodInstance )(
+ IXCLRDataFrame * This,
+ /* [out] */ IXCLRDataMethodInstance **method);
+
+ HRESULT ( STDMETHODCALLTYPE *Request )(
+ IXCLRDataFrame * This,
+ /* [in] */ ULONG32 reqCode,
+ /* [in] */ ULONG32 inBufferSize,
+ /* [size_is][in] */ BYTE *inBuffer,
+ /* [in] */ ULONG32 outBufferSize,
+ /* [size_is][out] */ BYTE *outBuffer);
+
+ HRESULT ( STDMETHODCALLTYPE *GetNumTypeArguments )(
+ IXCLRDataFrame * This,
+ /* [out] */ ULONG32 *numTypeArgs);
+
+ HRESULT ( STDMETHODCALLTYPE *GetTypeArgumentByIndex )(
+ IXCLRDataFrame * This,
+ /* [in] */ ULONG32 index,
+ /* [out] */ IXCLRDataTypeInstance **typeArg);
+
+ END_INTERFACE
+ } IXCLRDataFrameVtbl;
+
+ interface IXCLRDataFrame
+ {
+ CONST_VTBL struct IXCLRDataFrameVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IXCLRDataFrame_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IXCLRDataFrame_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IXCLRDataFrame_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IXCLRDataFrame_GetFrameType(This,simpleType,detailedType) \
+ ( (This)->lpVtbl -> GetFrameType(This,simpleType,detailedType) )
+
+#define IXCLRDataFrame_GetContext(This,contextFlags,contextBufSize,contextSize,contextBuf) \
+ ( (This)->lpVtbl -> GetContext(This,contextFlags,contextBufSize,contextSize,contextBuf) )
+
+#define IXCLRDataFrame_GetAppDomain(This,appDomain) \
+ ( (This)->lpVtbl -> GetAppDomain(This,appDomain) )
+
+#define IXCLRDataFrame_GetNumArguments(This,numArgs) \
+ ( (This)->lpVtbl -> GetNumArguments(This,numArgs) )
+
+#define IXCLRDataFrame_GetArgumentByIndex(This,index,arg,bufLen,nameLen,name) \
+ ( (This)->lpVtbl -> GetArgumentByIndex(This,index,arg,bufLen,nameLen,name) )
+
+#define IXCLRDataFrame_GetNumLocalVariables(This,numLocals) \
+ ( (This)->lpVtbl -> GetNumLocalVariables(This,numLocals) )
+
+#define IXCLRDataFrame_GetLocalVariableByIndex(This,index,localVariable,bufLen,nameLen,name) \
+ ( (This)->lpVtbl -> GetLocalVariableByIndex(This,index,localVariable,bufLen,nameLen,name) )
+
+#define IXCLRDataFrame_GetCodeName(This,flags,bufLen,nameLen,nameBuf) \
+ ( (This)->lpVtbl -> GetCodeName(This,flags,bufLen,nameLen,nameBuf) )
+
+#define IXCLRDataFrame_GetMethodInstance(This,method) \
+ ( (This)->lpVtbl -> GetMethodInstance(This,method) )
+
+#define IXCLRDataFrame_Request(This,reqCode,inBufferSize,inBuffer,outBufferSize,outBuffer) \
+ ( (This)->lpVtbl -> Request(This,reqCode,inBufferSize,inBuffer,outBufferSize,outBuffer) )
+
+#define IXCLRDataFrame_GetNumTypeArguments(This,numTypeArgs) \
+ ( (This)->lpVtbl -> GetNumTypeArguments(This,numTypeArgs) )
+
+#define IXCLRDataFrame_GetTypeArgumentByIndex(This,index,typeArg) \
+ ( (This)->lpVtbl -> GetTypeArgumentByIndex(This,index,typeArg) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IXCLRDataFrame_INTERFACE_DEFINED__ */
+
+
+/* interface __MIDL_itf_xclrdata_0000_0017 */
+/* [local] */
+
+#pragma warning(pop)
+
+
+extern RPC_IF_HANDLE __MIDL_itf_xclrdata_0000_0017_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_xclrdata_0000_0017_v0_0_s_ifspec;
+
+#ifndef __IXCLRDataFrame2_INTERFACE_DEFINED__
+#define __IXCLRDataFrame2_INTERFACE_DEFINED__
+
+/* interface IXCLRDataFrame2 */
+/* [uuid][local][object] */
+
+
+EXTERN_C const IID IID_IXCLRDataFrame2;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("1C4D9A4B-702D-4CF6-B290-1DB6F43050D0")
+ IXCLRDataFrame2 : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetExactGenericArgsToken(
+ /* [out] */ IXCLRDataValue **genericToken) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IXCLRDataFrame2Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IXCLRDataFrame2 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IXCLRDataFrame2 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IXCLRDataFrame2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetExactGenericArgsToken )(
+ IXCLRDataFrame2 * This,
+ /* [out] */ IXCLRDataValue **genericToken);
+
+ END_INTERFACE
+ } IXCLRDataFrame2Vtbl;
+
+ interface IXCLRDataFrame2
+ {
+ CONST_VTBL struct IXCLRDataFrame2Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IXCLRDataFrame2_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IXCLRDataFrame2_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IXCLRDataFrame2_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IXCLRDataFrame2_GetExactGenericArgsToken(This,genericToken) \
+ ( (This)->lpVtbl -> GetExactGenericArgsToken(This,genericToken) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IXCLRDataFrame2_INTERFACE_DEFINED__ */
+
+
+/* interface __MIDL_itf_xclrdata_0000_0018 */
+/* [local] */
+
+typedef /* [public] */
+enum __MIDL___MIDL_itf_xclrdata_0000_0018_0001
+ {
+ CLRDATA_EXCEPTION_DEFAULT = 0,
+ CLRDATA_EXCEPTION_NESTED = 0x1,
+ CLRDATA_EXCEPTION_PARTIAL = 0x2
+ } CLRDataExceptionStateFlag;
+
+typedef /* [public][public] */
+enum __MIDL___MIDL_itf_xclrdata_0000_0018_0002
+ {
+ CLRDATA_EXBASE_EXCEPTION = 0,
+ CLRDATA_EXBASE_OUT_OF_MEMORY = ( CLRDATA_EXBASE_EXCEPTION + 1 ) ,
+ CLRDATA_EXBASE_INVALID_ARGUMENT = ( CLRDATA_EXBASE_OUT_OF_MEMORY + 1 )
+ } CLRDataBaseExceptionType;
+
+typedef /* [public] */
+enum __MIDL___MIDL_itf_xclrdata_0000_0018_0003
+ {
+ CLRDATA_EXSAME_SECOND_CHANCE = 0,
+ CLRDATA_EXSAME_FIRST_CHANCE = 0x1
+ } CLRDataExceptionSameFlag;
+
+#pragma warning(push)
+#pragma warning(disable:28718)
+
+
+extern RPC_IF_HANDLE __MIDL_itf_xclrdata_0000_0018_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_xclrdata_0000_0018_v0_0_s_ifspec;
+
+#ifndef __IXCLRDataExceptionState_INTERFACE_DEFINED__
+#define __IXCLRDataExceptionState_INTERFACE_DEFINED__
+
+/* interface IXCLRDataExceptionState */
+/* [uuid][local][object] */
+
+
+EXTERN_C const IID IID_IXCLRDataExceptionState;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("75DA9E4C-BD33-43C8-8F5C-96E8A5241F57")
+ IXCLRDataExceptionState : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetFlags(
+ /* [out] */ ULONG32 *flags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetPrevious(
+ /* [out] */ IXCLRDataExceptionState **exState) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetManagedObject(
+ /* [out] */ IXCLRDataValue **value) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetBaseType(
+ /* [out] */ CLRDataBaseExceptionType *type) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetCode(
+ /* [out] */ ULONG32 *code) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetString(
+ /* [in] */ ULONG32 bufLen,
+ /* [out] */ ULONG32 *strLen,
+ /* [size_is][out] */ WCHAR str[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Request(
+ /* [in] */ ULONG32 reqCode,
+ /* [in] */ ULONG32 inBufferSize,
+ /* [size_is][in] */ BYTE *inBuffer,
+ /* [in] */ ULONG32 outBufferSize,
+ /* [size_is][out] */ BYTE *outBuffer) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE IsSameState(
+ /* [in] */ EXCEPTION_RECORD64 *exRecord,
+ /* [in] */ ULONG32 contextSize,
+ /* [size_is][in] */ BYTE cxRecord[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE IsSameState2(
+ /* [in] */ ULONG32 flags,
+ /* [in] */ EXCEPTION_RECORD64 *exRecord,
+ /* [in] */ ULONG32 contextSize,
+ /* [size_is][in] */ BYTE cxRecord[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetTask(
+ /* [out] */ IXCLRDataTask **task) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IXCLRDataExceptionStateVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IXCLRDataExceptionState * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IXCLRDataExceptionState * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IXCLRDataExceptionState * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFlags )(
+ IXCLRDataExceptionState * This,
+ /* [out] */ ULONG32 *flags);
+
+ HRESULT ( STDMETHODCALLTYPE *GetPrevious )(
+ IXCLRDataExceptionState * This,
+ /* [out] */ IXCLRDataExceptionState **exState);
+
+ HRESULT ( STDMETHODCALLTYPE *GetManagedObject )(
+ IXCLRDataExceptionState * This,
+ /* [out] */ IXCLRDataValue **value);
+
+ HRESULT ( STDMETHODCALLTYPE *GetBaseType )(
+ IXCLRDataExceptionState * This,
+ /* [out] */ CLRDataBaseExceptionType *type);
+
+ HRESULT ( STDMETHODCALLTYPE *GetCode )(
+ IXCLRDataExceptionState * This,
+ /* [out] */ ULONG32 *code);
+
+ HRESULT ( STDMETHODCALLTYPE *GetString )(
+ IXCLRDataExceptionState * This,
+ /* [in] */ ULONG32 bufLen,
+ /* [out] */ ULONG32 *strLen,
+ /* [size_is][out] */ WCHAR str[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *Request )(
+ IXCLRDataExceptionState * This,
+ /* [in] */ ULONG32 reqCode,
+ /* [in] */ ULONG32 inBufferSize,
+ /* [size_is][in] */ BYTE *inBuffer,
+ /* [in] */ ULONG32 outBufferSize,
+ /* [size_is][out] */ BYTE *outBuffer);
+
+ HRESULT ( STDMETHODCALLTYPE *IsSameState )(
+ IXCLRDataExceptionState * This,
+ /* [in] */ EXCEPTION_RECORD64 *exRecord,
+ /* [in] */ ULONG32 contextSize,
+ /* [size_is][in] */ BYTE cxRecord[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *IsSameState2 )(
+ IXCLRDataExceptionState * This,
+ /* [in] */ ULONG32 flags,
+ /* [in] */ EXCEPTION_RECORD64 *exRecord,
+ /* [in] */ ULONG32 contextSize,
+ /* [size_is][in] */ BYTE cxRecord[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetTask )(
+ IXCLRDataExceptionState * This,
+ /* [out] */ IXCLRDataTask **task);
+
+ END_INTERFACE
+ } IXCLRDataExceptionStateVtbl;
+
+ interface IXCLRDataExceptionState
+ {
+ CONST_VTBL struct IXCLRDataExceptionStateVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IXCLRDataExceptionState_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IXCLRDataExceptionState_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IXCLRDataExceptionState_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IXCLRDataExceptionState_GetFlags(This,flags) \
+ ( (This)->lpVtbl -> GetFlags(This,flags) )
+
+#define IXCLRDataExceptionState_GetPrevious(This,exState) \
+ ( (This)->lpVtbl -> GetPrevious(This,exState) )
+
+#define IXCLRDataExceptionState_GetManagedObject(This,value) \
+ ( (This)->lpVtbl -> GetManagedObject(This,value) )
+
+#define IXCLRDataExceptionState_GetBaseType(This,type) \
+ ( (This)->lpVtbl -> GetBaseType(This,type) )
+
+#define IXCLRDataExceptionState_GetCode(This,code) \
+ ( (This)->lpVtbl -> GetCode(This,code) )
+
+#define IXCLRDataExceptionState_GetString(This,bufLen,strLen,str) \
+ ( (This)->lpVtbl -> GetString(This,bufLen,strLen,str) )
+
+#define IXCLRDataExceptionState_Request(This,reqCode,inBufferSize,inBuffer,outBufferSize,outBuffer) \
+ ( (This)->lpVtbl -> Request(This,reqCode,inBufferSize,inBuffer,outBufferSize,outBuffer) )
+
+#define IXCLRDataExceptionState_IsSameState(This,exRecord,contextSize,cxRecord) \
+ ( (This)->lpVtbl -> IsSameState(This,exRecord,contextSize,cxRecord) )
+
+#define IXCLRDataExceptionState_IsSameState2(This,flags,exRecord,contextSize,cxRecord) \
+ ( (This)->lpVtbl -> IsSameState2(This,flags,exRecord,contextSize,cxRecord) )
+
+#define IXCLRDataExceptionState_GetTask(This,task) \
+ ( (This)->lpVtbl -> GetTask(This,task) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IXCLRDataExceptionState_INTERFACE_DEFINED__ */
+
+
+/* interface __MIDL_itf_xclrdata_0000_0019 */
+/* [local] */
+
+#pragma warning(pop)
+typedef /* [public] */
+enum __MIDL___MIDL_itf_xclrdata_0000_0019_0001
+ {
+ CLRDATA_VLOC_MEMORY = 0,
+ CLRDATA_VLOC_REGISTER = 0x1
+ } ClrDataValueLocationFlag;
+
+#pragma warning(push)
+#pragma warning(disable:28718)
+
+
+extern RPC_IF_HANDLE __MIDL_itf_xclrdata_0000_0019_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_xclrdata_0000_0019_v0_0_s_ifspec;
+
+#ifndef __IXCLRDataValue_INTERFACE_DEFINED__
+#define __IXCLRDataValue_INTERFACE_DEFINED__
+
+/* interface IXCLRDataValue */
+/* [uuid][local][object] */
+
+
+EXTERN_C const IID IID_IXCLRDataValue;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("96EC93C7-1000-4e93-8991-98D8766E6666")
+ IXCLRDataValue : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE GetFlags(
+ /* [out] */ ULONG32 *flags) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetAddress(
+ /* [out] */ CLRDATA_ADDRESS *address) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetSize(
+ /* [out] */ ULONG64 *size) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetBytes(
+ /* [in] */ ULONG32 bufLen,
+ /* [out] */ ULONG32 *dataSize,
+ /* [size_is][out] */ BYTE buffer[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE SetBytes(
+ /* [in] */ ULONG32 bufLen,
+ /* [out] */ ULONG32 *dataSize,
+ /* [size_is][in] */ BYTE buffer[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetType(
+ /* [out] */ IXCLRDataTypeInstance **typeInstance) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetNumFields(
+ /* [out] */ ULONG32 *numFields) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetFieldByIndex(
+ /* [in] */ ULONG32 index,
+ /* [out] */ IXCLRDataValue **field,
+ /* [in] */ ULONG32 bufLen,
+ /* [out] */ ULONG32 *nameLen,
+ /* [size_is][out] */ WCHAR nameBuf[ ],
+ /* [out] */ mdFieldDef *token) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE Request(
+ /* [in] */ ULONG32 reqCode,
+ /* [in] */ ULONG32 inBufferSize,
+ /* [size_is][in] */ BYTE *inBuffer,
+ /* [in] */ ULONG32 outBufferSize,
+ /* [size_is][out] */ BYTE *outBuffer) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetNumFields2(
+ /* [in] */ ULONG32 flags,
+ /* [in] */ IXCLRDataTypeInstance *fromType,
+ /* [out] */ ULONG32 *numFields) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StartEnumFields(
+ /* [in] */ ULONG32 flags,
+ /* [in] */ IXCLRDataTypeInstance *fromType,
+ /* [out] */ CLRDATA_ENUM *handle) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnumField(
+ /* [out][in] */ CLRDATA_ENUM *handle,
+ /* [out] */ IXCLRDataValue **field,
+ /* [in] */ ULONG32 nameBufLen,
+ /* [out] */ ULONG32 *nameLen,
+ /* [size_is][out] */ WCHAR nameBuf[ ],
+ /* [out] */ mdFieldDef *token) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EndEnumFields(
+ /* [in] */ CLRDATA_ENUM handle) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE StartEnumFieldsByName(
+ /* [in] */ LPCWSTR name,
+ /* [in] */ ULONG32 nameFlags,
+ /* [in] */ ULONG32 fieldFlags,
+ /* [in] */ IXCLRDataTypeInstance *fromType,
+ /* [out] */ CLRDATA_ENUM *handle) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnumFieldByName(
+ /* [out][in] */ CLRDATA_ENUM *handle,
+ /* [out] */ IXCLRDataValue **field,
+ /* [out] */ mdFieldDef *token) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EndEnumFieldsByName(
+ /* [in] */ CLRDATA_ENUM handle) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetFieldByToken(
+ /* [in] */ mdFieldDef token,
+ /* [out] */ IXCLRDataValue **field,
+ /* [in] */ ULONG32 bufLen,
+ /* [out] */ ULONG32 *nameLen,
+ /* [size_is][out] */ WCHAR nameBuf[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetAssociatedValue(
+ /* [out] */ IXCLRDataValue **assocValue) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetAssociatedType(
+ /* [out] */ IXCLRDataTypeInstance **assocType) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetString(
+ /* [in] */ ULONG32 bufLen,
+ /* [out] */ ULONG32 *strLen,
+ /* [size_is][out] */ WCHAR str[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetArrayProperties(
+ /* [out] */ ULONG32 *rank,
+ /* [out] */ ULONG32 *totalElements,
+ /* [in] */ ULONG32 numDim,
+ /* [size_is][out] */ ULONG32 dims[ ],
+ /* [in] */ ULONG32 numBases,
+ /* [size_is][out] */ LONG32 bases[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetArrayElement(
+ /* [in] */ ULONG32 numInd,
+ /* [size_is][in] */ LONG32 indices[ ],
+ /* [out] */ IXCLRDataValue **value) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnumField2(
+ /* [out][in] */ CLRDATA_ENUM *handle,
+ /* [out] */ IXCLRDataValue **field,
+ /* [in] */ ULONG32 nameBufLen,
+ /* [out] */ ULONG32 *nameLen,
+ /* [size_is][out] */ WCHAR nameBuf[ ],
+ /* [out] */ IXCLRDataModule **tokenScope,
+ /* [out] */ mdFieldDef *token) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE EnumFieldByName2(
+ /* [out][in] */ CLRDATA_ENUM *handle,
+ /* [out] */ IXCLRDataValue **field,
+ /* [out] */ IXCLRDataModule **tokenScope,
+ /* [out] */ mdFieldDef *token) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetFieldByToken2(
+ /* [in] */ IXCLRDataModule *tokenScope,
+ /* [in] */ mdFieldDef token,
+ /* [out] */ IXCLRDataValue **field,
+ /* [in] */ ULONG32 bufLen,
+ /* [out] */ ULONG32 *nameLen,
+ /* [size_is][out] */ WCHAR nameBuf[ ]) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetNumLocations(
+ /* [out] */ ULONG32 *numLocs) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE GetLocationByIndex(
+ /* [in] */ ULONG32 loc,
+ /* [out] */ ULONG32 *flags,
+ /* [out] */ CLRDATA_ADDRESS *arg) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IXCLRDataValueVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IXCLRDataValue * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IXCLRDataValue * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IXCLRDataValue * This);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFlags )(
+ IXCLRDataValue * This,
+ /* [out] */ ULONG32 *flags);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAddress )(
+ IXCLRDataValue * This,
+ /* [out] */ CLRDATA_ADDRESS *address);
+
+ HRESULT ( STDMETHODCALLTYPE *GetSize )(
+ IXCLRDataValue * This,
+ /* [out] */ ULONG64 *size);
+
+ HRESULT ( STDMETHODCALLTYPE *GetBytes )(
+ IXCLRDataValue * This,
+ /* [in] */ ULONG32 bufLen,
+ /* [out] */ ULONG32 *dataSize,
+ /* [size_is][out] */ BYTE buffer[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *SetBytes )(
+ IXCLRDataValue * This,
+ /* [in] */ ULONG32 bufLen,
+ /* [out] */ ULONG32 *dataSize,
+ /* [size_is][in] */ BYTE buffer[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetType )(
+ IXCLRDataValue * This,
+ /* [out] */ IXCLRDataTypeInstance **typeInstance);
+
+ HRESULT ( STDMETHODCALLTYPE *GetNumFields )(
+ IXCLRDataValue * This,
+ /* [out] */ ULONG32 *numFields);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFieldByIndex )(
+ IXCLRDataValue * This,
+ /* [in] */ ULONG32 index,
+ /* [out] */ IXCLRDataValue **field,
+ /* [in] */ ULONG32 bufLen,
+ /* [out] */ ULONG32 *nameLen,
+ /* [size_is][out] */ WCHAR nameBuf[ ],
+ /* [out] */ mdFieldDef *token);
+
+ HRESULT ( STDMETHODCALLTYPE *Request )(
+ IXCLRDataValue * This,
+ /* [in] */ ULONG32 reqCode,
+ /* [in] */ ULONG32 inBufferSize,
+ /* [size_is][in] */ BYTE *inBuffer,
+ /* [in] */ ULONG32 outBufferSize,
+ /* [size_is][out] */ BYTE *outBuffer);
+
+ HRESULT ( STDMETHODCALLTYPE *GetNumFields2 )(
+ IXCLRDataValue * This,
+ /* [in] */ ULONG32 flags,
+ /* [in] */ IXCLRDataTypeInstance *fromType,
+ /* [out] */ ULONG32 *numFields);
+
+ HRESULT ( STDMETHODCALLTYPE *StartEnumFields )(
+ IXCLRDataValue * This,
+ /* [in] */ ULONG32 flags,
+ /* [in] */ IXCLRDataTypeInstance *fromType,
+ /* [out] */ CLRDATA_ENUM *handle);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumField )(
+ IXCLRDataValue * This,
+ /* [out][in] */ CLRDATA_ENUM *handle,
+ /* [out] */ IXCLRDataValue **field,
+ /* [in] */ ULONG32 nameBufLen,
+ /* [out] */ ULONG32 *nameLen,
+ /* [size_is][out] */ WCHAR nameBuf[ ],
+ /* [out] */ mdFieldDef *token);
+
+ HRESULT ( STDMETHODCALLTYPE *EndEnumFields )(
+ IXCLRDataValue * This,
+ /* [in] */ CLRDATA_ENUM handle);
+
+ HRESULT ( STDMETHODCALLTYPE *StartEnumFieldsByName )(
+ IXCLRDataValue * This,
+ /* [in] */ LPCWSTR name,
+ /* [in] */ ULONG32 nameFlags,
+ /* [in] */ ULONG32 fieldFlags,
+ /* [in] */ IXCLRDataTypeInstance *fromType,
+ /* [out] */ CLRDATA_ENUM *handle);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumFieldByName )(
+ IXCLRDataValue * This,
+ /* [out][in] */ CLRDATA_ENUM *handle,
+ /* [out] */ IXCLRDataValue **field,
+ /* [out] */ mdFieldDef *token);
+
+ HRESULT ( STDMETHODCALLTYPE *EndEnumFieldsByName )(
+ IXCLRDataValue * This,
+ /* [in] */ CLRDATA_ENUM handle);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFieldByToken )(
+ IXCLRDataValue * This,
+ /* [in] */ mdFieldDef token,
+ /* [out] */ IXCLRDataValue **field,
+ /* [in] */ ULONG32 bufLen,
+ /* [out] */ ULONG32 *nameLen,
+ /* [size_is][out] */ WCHAR nameBuf[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAssociatedValue )(
+ IXCLRDataValue * This,
+ /* [out] */ IXCLRDataValue **assocValue);
+
+ HRESULT ( STDMETHODCALLTYPE *GetAssociatedType )(
+ IXCLRDataValue * This,
+ /* [out] */ IXCLRDataTypeInstance **assocType);
+
+ HRESULT ( STDMETHODCALLTYPE *GetString )(
+ IXCLRDataValue * This,
+ /* [in] */ ULONG32 bufLen,
+ /* [out] */ ULONG32 *strLen,
+ /* [size_is][out] */ WCHAR str[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetArrayProperties )(
+ IXCLRDataValue * This,
+ /* [out] */ ULONG32 *rank,
+ /* [out] */ ULONG32 *totalElements,
+ /* [in] */ ULONG32 numDim,
+ /* [size_is][out] */ ULONG32 dims[ ],
+ /* [in] */ ULONG32 numBases,
+ /* [size_is][out] */ LONG32 bases[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetArrayElement )(
+ IXCLRDataValue * This,
+ /* [in] */ ULONG32 numInd,
+ /* [size_is][in] */ LONG32 indices[ ],
+ /* [out] */ IXCLRDataValue **value);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumField2 )(
+ IXCLRDataValue * This,
+ /* [out][in] */ CLRDATA_ENUM *handle,
+ /* [out] */ IXCLRDataValue **field,
+ /* [in] */ ULONG32 nameBufLen,
+ /* [out] */ ULONG32 *nameLen,
+ /* [size_is][out] */ WCHAR nameBuf[ ],
+ /* [out] */ IXCLRDataModule **tokenScope,
+ /* [out] */ mdFieldDef *token);
+
+ HRESULT ( STDMETHODCALLTYPE *EnumFieldByName2 )(
+ IXCLRDataValue * This,
+ /* [out][in] */ CLRDATA_ENUM *handle,
+ /* [out] */ IXCLRDataValue **field,
+ /* [out] */ IXCLRDataModule **tokenScope,
+ /* [out] */ mdFieldDef *token);
+
+ HRESULT ( STDMETHODCALLTYPE *GetFieldByToken2 )(
+ IXCLRDataValue * This,
+ /* [in] */ IXCLRDataModule *tokenScope,
+ /* [in] */ mdFieldDef token,
+ /* [out] */ IXCLRDataValue **field,
+ /* [in] */ ULONG32 bufLen,
+ /* [out] */ ULONG32 *nameLen,
+ /* [size_is][out] */ WCHAR nameBuf[ ]);
+
+ HRESULT ( STDMETHODCALLTYPE *GetNumLocations )(
+ IXCLRDataValue * This,
+ /* [out] */ ULONG32 *numLocs);
+
+ HRESULT ( STDMETHODCALLTYPE *GetLocationByIndex )(
+ IXCLRDataValue * This,
+ /* [in] */ ULONG32 loc,
+ /* [out] */ ULONG32 *flags,
+ /* [out] */ CLRDATA_ADDRESS *arg);
+
+ END_INTERFACE
+ } IXCLRDataValueVtbl;
+
+ interface IXCLRDataValue
+ {
+ CONST_VTBL struct IXCLRDataValueVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IXCLRDataValue_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IXCLRDataValue_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IXCLRDataValue_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IXCLRDataValue_GetFlags(This,flags) \
+ ( (This)->lpVtbl -> GetFlags(This,flags) )
+
+#define IXCLRDataValue_GetAddress(This,address) \
+ ( (This)->lpVtbl -> GetAddress(This,address) )
+
+#define IXCLRDataValue_GetSize(This,size) \
+ ( (This)->lpVtbl -> GetSize(This,size) )
+
+#define IXCLRDataValue_GetBytes(This,bufLen,dataSize,buffer) \
+ ( (This)->lpVtbl -> GetBytes(This,bufLen,dataSize,buffer) )
+
+#define IXCLRDataValue_SetBytes(This,bufLen,dataSize,buffer) \
+ ( (This)->lpVtbl -> SetBytes(This,bufLen,dataSize,buffer) )
+
+#define IXCLRDataValue_GetType(This,typeInstance) \
+ ( (This)->lpVtbl -> GetType(This,typeInstance) )
+
+#define IXCLRDataValue_GetNumFields(This,numFields) \
+ ( (This)->lpVtbl -> GetNumFields(This,numFields) )
+
+#define IXCLRDataValue_GetFieldByIndex(This,index,field,bufLen,nameLen,nameBuf,token) \
+ ( (This)->lpVtbl -> GetFieldByIndex(This,index,field,bufLen,nameLen,nameBuf,token) )
+
+#define IXCLRDataValue_Request(This,reqCode,inBufferSize,inBuffer,outBufferSize,outBuffer) \
+ ( (This)->lpVtbl -> Request(This,reqCode,inBufferSize,inBuffer,outBufferSize,outBuffer) )
+
+#define IXCLRDataValue_GetNumFields2(This,flags,fromType,numFields) \
+ ( (This)->lpVtbl -> GetNumFields2(This,flags,fromType,numFields) )
+
+#define IXCLRDataValue_StartEnumFields(This,flags,fromType,handle) \
+ ( (This)->lpVtbl -> StartEnumFields(This,flags,fromType,handle) )
+
+#define IXCLRDataValue_EnumField(This,handle,field,nameBufLen,nameLen,nameBuf,token) \
+ ( (This)->lpVtbl -> EnumField(This,handle,field,nameBufLen,nameLen,nameBuf,token) )
+
+#define IXCLRDataValue_EndEnumFields(This,handle) \
+ ( (This)->lpVtbl -> EndEnumFields(This,handle) )
+
+#define IXCLRDataValue_StartEnumFieldsByName(This,name,nameFlags,fieldFlags,fromType,handle) \
+ ( (This)->lpVtbl -> StartEnumFieldsByName(This,name,nameFlags,fieldFlags,fromType,handle) )
+
+#define IXCLRDataValue_EnumFieldByName(This,handle,field,token) \
+ ( (This)->lpVtbl -> EnumFieldByName(This,handle,field,token) )
+
+#define IXCLRDataValue_EndEnumFieldsByName(This,handle) \
+ ( (This)->lpVtbl -> EndEnumFieldsByName(This,handle) )
+
+#define IXCLRDataValue_GetFieldByToken(This,token,field,bufLen,nameLen,nameBuf) \
+ ( (This)->lpVtbl -> GetFieldByToken(This,token,field,bufLen,nameLen,nameBuf) )
+
+#define IXCLRDataValue_GetAssociatedValue(This,assocValue) \
+ ( (This)->lpVtbl -> GetAssociatedValue(This,assocValue) )
+
+#define IXCLRDataValue_GetAssociatedType(This,assocType) \
+ ( (This)->lpVtbl -> GetAssociatedType(This,assocType) )
+
+#define IXCLRDataValue_GetString(This,bufLen,strLen,str) \
+ ( (This)->lpVtbl -> GetString(This,bufLen,strLen,str) )
+
+#define IXCLRDataValue_GetArrayProperties(This,rank,totalElements,numDim,dims,numBases,bases) \
+ ( (This)->lpVtbl -> GetArrayProperties(This,rank,totalElements,numDim,dims,numBases,bases) )
+
+#define IXCLRDataValue_GetArrayElement(This,numInd,indices,value) \
+ ( (This)->lpVtbl -> GetArrayElement(This,numInd,indices,value) )
+
+#define IXCLRDataValue_EnumField2(This,handle,field,nameBufLen,nameLen,nameBuf,tokenScope,token) \
+ ( (This)->lpVtbl -> EnumField2(This,handle,field,nameBufLen,nameLen,nameBuf,tokenScope,token) )
+
+#define IXCLRDataValue_EnumFieldByName2(This,handle,field,tokenScope,token) \
+ ( (This)->lpVtbl -> EnumFieldByName2(This,handle,field,tokenScope,token) )
+
+#define IXCLRDataValue_GetFieldByToken2(This,tokenScope,token,field,bufLen,nameLen,nameBuf) \
+ ( (This)->lpVtbl -> GetFieldByToken2(This,tokenScope,token,field,bufLen,nameLen,nameBuf) )
+
+#define IXCLRDataValue_GetNumLocations(This,numLocs) \
+ ( (This)->lpVtbl -> GetNumLocations(This,numLocs) )
+
+#define IXCLRDataValue_GetLocationByIndex(This,loc,flags,arg) \
+ ( (This)->lpVtbl -> GetLocationByIndex(This,loc,flags,arg) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IXCLRDataValue_INTERFACE_DEFINED__ */
+
+
+/* interface __MIDL_itf_xclrdata_0000_0020 */
+/* [local] */
+
+#pragma warning(pop)
+
+
+extern RPC_IF_HANDLE __MIDL_itf_xclrdata_0000_0020_v0_0_c_ifspec;
+extern RPC_IF_HANDLE __MIDL_itf_xclrdata_0000_0020_v0_0_s_ifspec;
+
+#ifndef __IXCLRDataExceptionNotification_INTERFACE_DEFINED__
+#define __IXCLRDataExceptionNotification_INTERFACE_DEFINED__
+
+/* interface IXCLRDataExceptionNotification */
+/* [uuid][local][object] */
+
+
+EXTERN_C const IID IID_IXCLRDataExceptionNotification;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("2D95A079-42A1-4837-818F-0B97D7048E0E")
+ IXCLRDataExceptionNotification : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE OnCodeGenerated(
+ /* [in] */ IXCLRDataMethodInstance *method) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE OnCodeDiscarded(
+ /* [in] */ IXCLRDataMethodInstance *method) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE OnProcessExecution(
+ /* [in] */ ULONG32 state) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE OnTaskExecution(
+ /* [in] */ IXCLRDataTask *task,
+ /* [in] */ ULONG32 state) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE OnModuleLoaded(
+ /* [in] */ IXCLRDataModule *mod) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE OnModuleUnloaded(
+ /* [in] */ IXCLRDataModule *mod) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE OnTypeLoaded(
+ /* [in] */ IXCLRDataTypeInstance *typeInst) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE OnTypeUnloaded(
+ /* [in] */ IXCLRDataTypeInstance *typeInst) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IXCLRDataExceptionNotificationVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IXCLRDataExceptionNotification * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IXCLRDataExceptionNotification * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IXCLRDataExceptionNotification * This);
+
+ HRESULT ( STDMETHODCALLTYPE *OnCodeGenerated )(
+ IXCLRDataExceptionNotification * This,
+ /* [in] */ IXCLRDataMethodInstance *method);
+
+ HRESULT ( STDMETHODCALLTYPE *OnCodeDiscarded )(
+ IXCLRDataExceptionNotification * This,
+ /* [in] */ IXCLRDataMethodInstance *method);
+
+ HRESULT ( STDMETHODCALLTYPE *OnProcessExecution )(
+ IXCLRDataExceptionNotification * This,
+ /* [in] */ ULONG32 state);
+
+ HRESULT ( STDMETHODCALLTYPE *OnTaskExecution )(
+ IXCLRDataExceptionNotification * This,
+ /* [in] */ IXCLRDataTask *task,
+ /* [in] */ ULONG32 state);
+
+ HRESULT ( STDMETHODCALLTYPE *OnModuleLoaded )(
+ IXCLRDataExceptionNotification * This,
+ /* [in] */ IXCLRDataModule *mod);
+
+ HRESULT ( STDMETHODCALLTYPE *OnModuleUnloaded )(
+ IXCLRDataExceptionNotification * This,
+ /* [in] */ IXCLRDataModule *mod);
+
+ HRESULT ( STDMETHODCALLTYPE *OnTypeLoaded )(
+ IXCLRDataExceptionNotification * This,
+ /* [in] */ IXCLRDataTypeInstance *typeInst);
+
+ HRESULT ( STDMETHODCALLTYPE *OnTypeUnloaded )(
+ IXCLRDataExceptionNotification * This,
+ /* [in] */ IXCLRDataTypeInstance *typeInst);
+
+ END_INTERFACE
+ } IXCLRDataExceptionNotificationVtbl;
+
+ interface IXCLRDataExceptionNotification
+ {
+ CONST_VTBL struct IXCLRDataExceptionNotificationVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IXCLRDataExceptionNotification_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IXCLRDataExceptionNotification_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IXCLRDataExceptionNotification_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IXCLRDataExceptionNotification_OnCodeGenerated(This,method) \
+ ( (This)->lpVtbl -> OnCodeGenerated(This,method) )
+
+#define IXCLRDataExceptionNotification_OnCodeDiscarded(This,method) \
+ ( (This)->lpVtbl -> OnCodeDiscarded(This,method) )
+
+#define IXCLRDataExceptionNotification_OnProcessExecution(This,state) \
+ ( (This)->lpVtbl -> OnProcessExecution(This,state) )
+
+#define IXCLRDataExceptionNotification_OnTaskExecution(This,task,state) \
+ ( (This)->lpVtbl -> OnTaskExecution(This,task,state) )
+
+#define IXCLRDataExceptionNotification_OnModuleLoaded(This,mod) \
+ ( (This)->lpVtbl -> OnModuleLoaded(This,mod) )
+
+#define IXCLRDataExceptionNotification_OnModuleUnloaded(This,mod) \
+ ( (This)->lpVtbl -> OnModuleUnloaded(This,mod) )
+
+#define IXCLRDataExceptionNotification_OnTypeLoaded(This,typeInst) \
+ ( (This)->lpVtbl -> OnTypeLoaded(This,typeInst) )
+
+#define IXCLRDataExceptionNotification_OnTypeUnloaded(This,typeInst) \
+ ( (This)->lpVtbl -> OnTypeUnloaded(This,typeInst) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IXCLRDataExceptionNotification_INTERFACE_DEFINED__ */
+
+
+#ifndef __IXCLRDataExceptionNotification2_INTERFACE_DEFINED__
+#define __IXCLRDataExceptionNotification2_INTERFACE_DEFINED__
+
+/* interface IXCLRDataExceptionNotification2 */
+/* [uuid][local][object] */
+
+
+EXTERN_C const IID IID_IXCLRDataExceptionNotification2;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("31201a94-4337-49b7-aef7-0c755054091f")
+ IXCLRDataExceptionNotification2 : public IXCLRDataExceptionNotification
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE OnAppDomainLoaded(
+ /* [in] */ IXCLRDataAppDomain *domain) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE OnAppDomainUnloaded(
+ /* [in] */ IXCLRDataAppDomain *domain) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE OnException(
+ /* [in] */ IXCLRDataExceptionState *exception) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IXCLRDataExceptionNotification2Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IXCLRDataExceptionNotification2 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IXCLRDataExceptionNotification2 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IXCLRDataExceptionNotification2 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *OnCodeGenerated )(
+ IXCLRDataExceptionNotification2 * This,
+ /* [in] */ IXCLRDataMethodInstance *method);
+
+ HRESULT ( STDMETHODCALLTYPE *OnCodeDiscarded )(
+ IXCLRDataExceptionNotification2 * This,
+ /* [in] */ IXCLRDataMethodInstance *method);
+
+ HRESULT ( STDMETHODCALLTYPE *OnProcessExecution )(
+ IXCLRDataExceptionNotification2 * This,
+ /* [in] */ ULONG32 state);
+
+ HRESULT ( STDMETHODCALLTYPE *OnTaskExecution )(
+ IXCLRDataExceptionNotification2 * This,
+ /* [in] */ IXCLRDataTask *task,
+ /* [in] */ ULONG32 state);
+
+ HRESULT ( STDMETHODCALLTYPE *OnModuleLoaded )(
+ IXCLRDataExceptionNotification2 * This,
+ /* [in] */ IXCLRDataModule *mod);
+
+ HRESULT ( STDMETHODCALLTYPE *OnModuleUnloaded )(
+ IXCLRDataExceptionNotification2 * This,
+ /* [in] */ IXCLRDataModule *mod);
+
+ HRESULT ( STDMETHODCALLTYPE *OnTypeLoaded )(
+ IXCLRDataExceptionNotification2 * This,
+ /* [in] */ IXCLRDataTypeInstance *typeInst);
+
+ HRESULT ( STDMETHODCALLTYPE *OnTypeUnloaded )(
+ IXCLRDataExceptionNotification2 * This,
+ /* [in] */ IXCLRDataTypeInstance *typeInst);
+
+ HRESULT ( STDMETHODCALLTYPE *OnAppDomainLoaded )(
+ IXCLRDataExceptionNotification2 * This,
+ /* [in] */ IXCLRDataAppDomain *domain);
+
+ HRESULT ( STDMETHODCALLTYPE *OnAppDomainUnloaded )(
+ IXCLRDataExceptionNotification2 * This,
+ /* [in] */ IXCLRDataAppDomain *domain);
+
+ HRESULT ( STDMETHODCALLTYPE *OnException )(
+ IXCLRDataExceptionNotification2 * This,
+ /* [in] */ IXCLRDataExceptionState *exception);
+
+ END_INTERFACE
+ } IXCLRDataExceptionNotification2Vtbl;
+
+ interface IXCLRDataExceptionNotification2
+ {
+ CONST_VTBL struct IXCLRDataExceptionNotification2Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IXCLRDataExceptionNotification2_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IXCLRDataExceptionNotification2_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IXCLRDataExceptionNotification2_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IXCLRDataExceptionNotification2_OnCodeGenerated(This,method) \
+ ( (This)->lpVtbl -> OnCodeGenerated(This,method) )
+
+#define IXCLRDataExceptionNotification2_OnCodeDiscarded(This,method) \
+ ( (This)->lpVtbl -> OnCodeDiscarded(This,method) )
+
+#define IXCLRDataExceptionNotification2_OnProcessExecution(This,state) \
+ ( (This)->lpVtbl -> OnProcessExecution(This,state) )
+
+#define IXCLRDataExceptionNotification2_OnTaskExecution(This,task,state) \
+ ( (This)->lpVtbl -> OnTaskExecution(This,task,state) )
+
+#define IXCLRDataExceptionNotification2_OnModuleLoaded(This,mod) \
+ ( (This)->lpVtbl -> OnModuleLoaded(This,mod) )
+
+#define IXCLRDataExceptionNotification2_OnModuleUnloaded(This,mod) \
+ ( (This)->lpVtbl -> OnModuleUnloaded(This,mod) )
+
+#define IXCLRDataExceptionNotification2_OnTypeLoaded(This,typeInst) \
+ ( (This)->lpVtbl -> OnTypeLoaded(This,typeInst) )
+
+#define IXCLRDataExceptionNotification2_OnTypeUnloaded(This,typeInst) \
+ ( (This)->lpVtbl -> OnTypeUnloaded(This,typeInst) )
+
+
+#define IXCLRDataExceptionNotification2_OnAppDomainLoaded(This,domain) \
+ ( (This)->lpVtbl -> OnAppDomainLoaded(This,domain) )
+
+#define IXCLRDataExceptionNotification2_OnAppDomainUnloaded(This,domain) \
+ ( (This)->lpVtbl -> OnAppDomainUnloaded(This,domain) )
+
+#define IXCLRDataExceptionNotification2_OnException(This,exception) \
+ ( (This)->lpVtbl -> OnException(This,exception) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IXCLRDataExceptionNotification2_INTERFACE_DEFINED__ */
+
+
+#ifndef __IXCLRDataExceptionNotification3_INTERFACE_DEFINED__
+#define __IXCLRDataExceptionNotification3_INTERFACE_DEFINED__
+
+/* interface IXCLRDataExceptionNotification3 */
+/* [uuid][local][object] */
+
+
+EXTERN_C const IID IID_IXCLRDataExceptionNotification3;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("31201a94-4337-49b7-aef7-0c7550540920")
+ IXCLRDataExceptionNotification3 : public IXCLRDataExceptionNotification2
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE OnGcEvent(
+ /* [in] */ GcEvtArgs gcEvtArgs) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IXCLRDataExceptionNotification3Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IXCLRDataExceptionNotification3 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IXCLRDataExceptionNotification3 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IXCLRDataExceptionNotification3 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *OnCodeGenerated )(
+ IXCLRDataExceptionNotification3 * This,
+ /* [in] */ IXCLRDataMethodInstance *method);
+
+ HRESULT ( STDMETHODCALLTYPE *OnCodeDiscarded )(
+ IXCLRDataExceptionNotification3 * This,
+ /* [in] */ IXCLRDataMethodInstance *method);
+
+ HRESULT ( STDMETHODCALLTYPE *OnProcessExecution )(
+ IXCLRDataExceptionNotification3 * This,
+ /* [in] */ ULONG32 state);
+
+ HRESULT ( STDMETHODCALLTYPE *OnTaskExecution )(
+ IXCLRDataExceptionNotification3 * This,
+ /* [in] */ IXCLRDataTask *task,
+ /* [in] */ ULONG32 state);
+
+ HRESULT ( STDMETHODCALLTYPE *OnModuleLoaded )(
+ IXCLRDataExceptionNotification3 * This,
+ /* [in] */ IXCLRDataModule *mod);
+
+ HRESULT ( STDMETHODCALLTYPE *OnModuleUnloaded )(
+ IXCLRDataExceptionNotification3 * This,
+ /* [in] */ IXCLRDataModule *mod);
+
+ HRESULT ( STDMETHODCALLTYPE *OnTypeLoaded )(
+ IXCLRDataExceptionNotification3 * This,
+ /* [in] */ IXCLRDataTypeInstance *typeInst);
+
+ HRESULT ( STDMETHODCALLTYPE *OnTypeUnloaded )(
+ IXCLRDataExceptionNotification3 * This,
+ /* [in] */ IXCLRDataTypeInstance *typeInst);
+
+ HRESULT ( STDMETHODCALLTYPE *OnAppDomainLoaded )(
+ IXCLRDataExceptionNotification3 * This,
+ /* [in] */ IXCLRDataAppDomain *domain);
+
+ HRESULT ( STDMETHODCALLTYPE *OnAppDomainUnloaded )(
+ IXCLRDataExceptionNotification3 * This,
+ /* [in] */ IXCLRDataAppDomain *domain);
+
+ HRESULT ( STDMETHODCALLTYPE *OnException )(
+ IXCLRDataExceptionNotification3 * This,
+ /* [in] */ IXCLRDataExceptionState *exception);
+
+ HRESULT ( STDMETHODCALLTYPE *OnGcEvent )(
+ IXCLRDataExceptionNotification3 * This,
+ /* [in] */ GcEvtArgs gcEvtArgs);
+
+ END_INTERFACE
+ } IXCLRDataExceptionNotification3Vtbl;
+
+ interface IXCLRDataExceptionNotification3
+ {
+ CONST_VTBL struct IXCLRDataExceptionNotification3Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IXCLRDataExceptionNotification3_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IXCLRDataExceptionNotification3_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IXCLRDataExceptionNotification3_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IXCLRDataExceptionNotification3_OnCodeGenerated(This,method) \
+ ( (This)->lpVtbl -> OnCodeGenerated(This,method) )
+
+#define IXCLRDataExceptionNotification3_OnCodeDiscarded(This,method) \
+ ( (This)->lpVtbl -> OnCodeDiscarded(This,method) )
+
+#define IXCLRDataExceptionNotification3_OnProcessExecution(This,state) \
+ ( (This)->lpVtbl -> OnProcessExecution(This,state) )
+
+#define IXCLRDataExceptionNotification3_OnTaskExecution(This,task,state) \
+ ( (This)->lpVtbl -> OnTaskExecution(This,task,state) )
+
+#define IXCLRDataExceptionNotification3_OnModuleLoaded(This,mod) \
+ ( (This)->lpVtbl -> OnModuleLoaded(This,mod) )
+
+#define IXCLRDataExceptionNotification3_OnModuleUnloaded(This,mod) \
+ ( (This)->lpVtbl -> OnModuleUnloaded(This,mod) )
+
+#define IXCLRDataExceptionNotification3_OnTypeLoaded(This,typeInst) \
+ ( (This)->lpVtbl -> OnTypeLoaded(This,typeInst) )
+
+#define IXCLRDataExceptionNotification3_OnTypeUnloaded(This,typeInst) \
+ ( (This)->lpVtbl -> OnTypeUnloaded(This,typeInst) )
+
+
+#define IXCLRDataExceptionNotification3_OnAppDomainLoaded(This,domain) \
+ ( (This)->lpVtbl -> OnAppDomainLoaded(This,domain) )
+
+#define IXCLRDataExceptionNotification3_OnAppDomainUnloaded(This,domain) \
+ ( (This)->lpVtbl -> OnAppDomainUnloaded(This,domain) )
+
+#define IXCLRDataExceptionNotification3_OnException(This,exception) \
+ ( (This)->lpVtbl -> OnException(This,exception) )
+
+
+#define IXCLRDataExceptionNotification3_OnGcEvent(This,gcEvtArgs) \
+ ( (This)->lpVtbl -> OnGcEvent(This,gcEvtArgs) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IXCLRDataExceptionNotification3_INTERFACE_DEFINED__ */
+
+
+#ifndef __IXCLRDataExceptionNotification4_INTERFACE_DEFINED__
+#define __IXCLRDataExceptionNotification4_INTERFACE_DEFINED__
+
+/* interface IXCLRDataExceptionNotification4 */
+/* [uuid][local][object] */
+
+
+EXTERN_C const IID IID_IXCLRDataExceptionNotification4;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("C25E926E-5F09-4AA2-BBAD-B7FC7F10CFD7")
+ IXCLRDataExceptionNotification4 : public IXCLRDataExceptionNotification3
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE ExceptionCatcherEnter(
+ /* [in] */ IXCLRDataMethodInstance *catchingMethod,
+ DWORD catcherNativeOffset) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct IXCLRDataExceptionNotification4Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ IXCLRDataExceptionNotification4 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ IXCLRDataExceptionNotification4 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ IXCLRDataExceptionNotification4 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *OnCodeGenerated )(
+ IXCLRDataExceptionNotification4 * This,
+ /* [in] */ IXCLRDataMethodInstance *method);
+
+ HRESULT ( STDMETHODCALLTYPE *OnCodeDiscarded )(
+ IXCLRDataExceptionNotification4 * This,
+ /* [in] */ IXCLRDataMethodInstance *method);
+
+ HRESULT ( STDMETHODCALLTYPE *OnProcessExecution )(
+ IXCLRDataExceptionNotification4 * This,
+ /* [in] */ ULONG32 state);
+
+ HRESULT ( STDMETHODCALLTYPE *OnTaskExecution )(
+ IXCLRDataExceptionNotification4 * This,
+ /* [in] */ IXCLRDataTask *task,
+ /* [in] */ ULONG32 state);
+
+ HRESULT ( STDMETHODCALLTYPE *OnModuleLoaded )(
+ IXCLRDataExceptionNotification4 * This,
+ /* [in] */ IXCLRDataModule *mod);
+
+ HRESULT ( STDMETHODCALLTYPE *OnModuleUnloaded )(
+ IXCLRDataExceptionNotification4 * This,
+ /* [in] */ IXCLRDataModule *mod);
+
+ HRESULT ( STDMETHODCALLTYPE *OnTypeLoaded )(
+ IXCLRDataExceptionNotification4 * This,
+ /* [in] */ IXCLRDataTypeInstance *typeInst);
+
+ HRESULT ( STDMETHODCALLTYPE *OnTypeUnloaded )(
+ IXCLRDataExceptionNotification4 * This,
+ /* [in] */ IXCLRDataTypeInstance *typeInst);
+
+ HRESULT ( STDMETHODCALLTYPE *OnAppDomainLoaded )(
+ IXCLRDataExceptionNotification4 * This,
+ /* [in] */ IXCLRDataAppDomain *domain);
+
+ HRESULT ( STDMETHODCALLTYPE *OnAppDomainUnloaded )(
+ IXCLRDataExceptionNotification4 * This,
+ /* [in] */ IXCLRDataAppDomain *domain);
+
+ HRESULT ( STDMETHODCALLTYPE *OnException )(
+ IXCLRDataExceptionNotification4 * This,
+ /* [in] */ IXCLRDataExceptionState *exception);
+
+ HRESULT ( STDMETHODCALLTYPE *OnGcEvent )(
+ IXCLRDataExceptionNotification4 * This,
+ /* [in] */ GcEvtArgs gcEvtArgs);
+
+ HRESULT ( STDMETHODCALLTYPE *ExceptionCatcherEnter )(
+ IXCLRDataExceptionNotification4 * This,
+ /* [in] */ IXCLRDataMethodInstance *catchingMethod,
+ DWORD catcherNativeOffset);
+
+ END_INTERFACE
+ } IXCLRDataExceptionNotification4Vtbl;
+
+ interface IXCLRDataExceptionNotification4
+ {
+ CONST_VTBL struct IXCLRDataExceptionNotification4Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define IXCLRDataExceptionNotification4_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define IXCLRDataExceptionNotification4_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define IXCLRDataExceptionNotification4_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define IXCLRDataExceptionNotification4_OnCodeGenerated(This,method) \
+ ( (This)->lpVtbl -> OnCodeGenerated(This,method) )
+
+#define IXCLRDataExceptionNotification4_OnCodeDiscarded(This,method) \
+ ( (This)->lpVtbl -> OnCodeDiscarded(This,method) )
+
+#define IXCLRDataExceptionNotification4_OnProcessExecution(This,state) \
+ ( (This)->lpVtbl -> OnProcessExecution(This,state) )
+
+#define IXCLRDataExceptionNotification4_OnTaskExecution(This,task,state) \
+ ( (This)->lpVtbl -> OnTaskExecution(This,task,state) )
+
+#define IXCLRDataExceptionNotification4_OnModuleLoaded(This,mod) \
+ ( (This)->lpVtbl -> OnModuleLoaded(This,mod) )
+
+#define IXCLRDataExceptionNotification4_OnModuleUnloaded(This,mod) \
+ ( (This)->lpVtbl -> OnModuleUnloaded(This,mod) )
+
+#define IXCLRDataExceptionNotification4_OnTypeLoaded(This,typeInst) \
+ ( (This)->lpVtbl -> OnTypeLoaded(This,typeInst) )
+
+#define IXCLRDataExceptionNotification4_OnTypeUnloaded(This,typeInst) \
+ ( (This)->lpVtbl -> OnTypeUnloaded(This,typeInst) )
+
+
+#define IXCLRDataExceptionNotification4_OnAppDomainLoaded(This,domain) \
+ ( (This)->lpVtbl -> OnAppDomainLoaded(This,domain) )
+
+#define IXCLRDataExceptionNotification4_OnAppDomainUnloaded(This,domain) \
+ ( (This)->lpVtbl -> OnAppDomainUnloaded(This,domain) )
+
+#define IXCLRDataExceptionNotification4_OnException(This,exception) \
+ ( (This)->lpVtbl -> OnException(This,exception) )
+
+
+#define IXCLRDataExceptionNotification4_OnGcEvent(This,gcEvtArgs) \
+ ( (This)->lpVtbl -> OnGcEvent(This,gcEvtArgs) )
+
+
+#define IXCLRDataExceptionNotification4_ExceptionCatcherEnter(This,catchingMethod,catcherNativeOffset) \
+ ( (This)->lpVtbl -> ExceptionCatcherEnter(This,catchingMethod,catcherNativeOffset) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __IXCLRDataExceptionNotification4_INTERFACE_DEFINED__ */
+
+
+/* Additional Prototypes for ALL interfaces */
+
+/* end of Additional Prototypes */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+
diff --git a/src/pal/prebuilt/inc/xcordebug.h b/src/pal/prebuilt/inc/xcordebug.h
new file mode 100644
index 0000000000..ce4dc07bbc
--- /dev/null
+++ b/src/pal/prebuilt/inc/xcordebug.h
@@ -0,0 +1,259 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+
+
+/* this ALWAYS GENERATED file contains the definitions for the interfaces */
+
+
+ /* File created by MIDL compiler version 8.00.0603 */
+/* @@MIDL_FILE_HEADING( ) */
+
+#pragma warning( disable: 4049 ) /* more than 64k source lines */
+
+
+/* verify that the <rpcndr.h> version is high enough to compile this file*/
+#ifndef __REQUIRED_RPCNDR_H_VERSION__
+#define __REQUIRED_RPCNDR_H_VERSION__ 475
+#endif
+
+#include "rpc.h"
+#include "rpcndr.h"
+
+#ifndef __RPCNDR_H_VERSION__
+#error this stub requires an updated version of <rpcndr.h>
+#endif // __RPCNDR_H_VERSION__
+
+#ifndef COM_NO_WINDOWS_H
+#include "windows.h"
+#include "ole2.h"
+#endif /*COM_NO_WINDOWS_H*/
+
+#ifndef __xcordebug_h__
+#define __xcordebug_h__
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+#pragma once
+#endif
+
+/* Forward Declarations */
+
+#ifndef __ICorDebugProcess4_FWD_DEFINED__
+#define __ICorDebugProcess4_FWD_DEFINED__
+typedef interface ICorDebugProcess4 ICorDebugProcess4;
+
+#endif /* __ICorDebugProcess4_FWD_DEFINED__ */
+
+#ifndef __ICorDebugLegacyNetCFHostCallbackInvoker_PrivateWindowsPhoneOnly_FWD_DEFINED__
+#define __ICorDebugLegacyNetCFHostCallbackInvoker_PrivateWindowsPhoneOnly_FWD_DEFINED__
+typedef interface ICorDebugLegacyNetCFHostCallbackInvoker_PrivateWindowsPhoneOnly ICorDebugLegacyNetCFHostCallbackInvoker_PrivateWindowsPhoneOnly;
+
+#endif /* __ICorDebugLegacyNetCFHostCallbackInvoker_PrivateWindowsPhoneOnly_FWD_DEFINED__ */
+
+/* header files for imported files */
+#include "cordebug.h"
+
+#ifdef __cplusplus
+extern "C"{
+#endif
+
+
+#ifndef __ICorDebugProcess4_INTERFACE_DEFINED__
+#define __ICorDebugProcess4_INTERFACE_DEFINED__
+
+/* interface ICorDebugProcess4 */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugProcess4;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("E930C679-78AF-4953-8AB7-B0AABF0F9F80")
+ ICorDebugProcess4 : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE Filter(
+ /* [size_is][length_is][in] */ const BYTE pRecord[ ],
+ /* [in] */ DWORD countBytes,
+ /* [in] */ CorDebugRecordFormat format,
+ /* [in] */ DWORD dwFlags,
+ /* [in] */ DWORD dwThreadId,
+ /* [in] */ ICorDebugManagedCallback *pCallback,
+ /* [out][in] */ CORDB_CONTINUE_STATUS *pContinueStatus) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE ProcessStateChanged(
+ /* [in] */ CorDebugStateChange eChange) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugProcess4Vtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugProcess4 * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugProcess4 * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugProcess4 * This);
+
+ HRESULT ( STDMETHODCALLTYPE *Filter )(
+ ICorDebugProcess4 * This,
+ /* [size_is][length_is][in] */ const BYTE pRecord[ ],
+ /* [in] */ DWORD countBytes,
+ /* [in] */ CorDebugRecordFormat format,
+ /* [in] */ DWORD dwFlags,
+ /* [in] */ DWORD dwThreadId,
+ /* [in] */ ICorDebugManagedCallback *pCallback,
+ /* [out][in] */ CORDB_CONTINUE_STATUS *pContinueStatus);
+
+ HRESULT ( STDMETHODCALLTYPE *ProcessStateChanged )(
+ ICorDebugProcess4 * This,
+ /* [in] */ CorDebugStateChange eChange);
+
+ END_INTERFACE
+ } ICorDebugProcess4Vtbl;
+
+ interface ICorDebugProcess4
+ {
+ CONST_VTBL struct ICorDebugProcess4Vtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugProcess4_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugProcess4_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugProcess4_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugProcess4_Filter(This,pRecord,countBytes,format,dwFlags,dwThreadId,pCallback,pContinueStatus) \
+ ( (This)->lpVtbl -> Filter(This,pRecord,countBytes,format,dwFlags,dwThreadId,pCallback,pContinueStatus) )
+
+#define ICorDebugProcess4_ProcessStateChanged(This,eChange) \
+ ( (This)->lpVtbl -> ProcessStateChanged(This,eChange) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugProcess4_INTERFACE_DEFINED__ */
+
+#ifndef __ICorDebugLegacyNetCFHostCallbackInvoker_PrivateWindowsPhoneOnly_INTERFACE_DEFINED__
+#define __ICorDebugLegacyNetCFHostCallbackInvoker_PrivateWindowsPhoneOnly_INTERFACE_DEFINED__
+
+/* interface ICorDebugLegacyNetCFHostCallbackInvoker_PrivateWindowsPhoneOnly */
+/* [unique][uuid][local][object] */
+
+
+EXTERN_C const IID IID_ICorDebugLegacyNetCFHostCallbackInvoker_PrivateWindowsPhoneOnly;
+
+#if defined(__cplusplus) && !defined(CINTERFACE)
+
+ MIDL_INTERFACE("34B27FB0-A318-450D-A0DD-11B70B21F41D")
+ ICorDebugLegacyNetCFHostCallbackInvoker_PrivateWindowsPhoneOnly : public IUnknown
+ {
+ public:
+ virtual HRESULT STDMETHODCALLTYPE InvokePauseCallback( void) = 0;
+
+ virtual HRESULT STDMETHODCALLTYPE InvokeResumeCallback( void) = 0;
+
+ };
+
+
+#else /* C style interface */
+
+ typedef struct ICorDebugLegacyNetCFHostCallbackInvoker_PrivateWindowsPhoneOnlyVtbl
+ {
+ BEGIN_INTERFACE
+
+ HRESULT ( STDMETHODCALLTYPE *QueryInterface )(
+ ICorDebugLegacyNetCFHostCallbackInvoker_PrivateWindowsPhoneOnly * This,
+ /* [in] */ REFIID riid,
+ /* [annotation][iid_is][out] */
+ _COM_Outptr_ void **ppvObject);
+
+ ULONG ( STDMETHODCALLTYPE *AddRef )(
+ ICorDebugLegacyNetCFHostCallbackInvoker_PrivateWindowsPhoneOnly * This);
+
+ ULONG ( STDMETHODCALLTYPE *Release )(
+ ICorDebugLegacyNetCFHostCallbackInvoker_PrivateWindowsPhoneOnly * This);
+
+ HRESULT ( STDMETHODCALLTYPE *InvokePauseCallback )(
+ ICorDebugLegacyNetCFHostCallbackInvoker_PrivateWindowsPhoneOnly * This);
+
+ HRESULT ( STDMETHODCALLTYPE *InvokeResumeCallback )(
+ ICorDebugLegacyNetCFHostCallbackInvoker_PrivateWindowsPhoneOnly * This);
+
+ END_INTERFACE
+ } ICorDebugLegacyNetCFHostCallbackInvoker_PrivateWindowsPhoneOnlyVtbl;
+
+ interface ICorDebugLegacyNetCFHostCallbackInvoker_PrivateWindowsPhoneOnly
+ {
+ CONST_VTBL struct ICorDebugLegacyNetCFHostCallbackInvoker_PrivateWindowsPhoneOnlyVtbl *lpVtbl;
+ };
+
+
+
+#ifdef COBJMACROS
+
+
+#define ICorDebugLegacyNetCFHostCallbackInvoker_PrivateWindowsPhoneOnly_QueryInterface(This,riid,ppvObject) \
+ ( (This)->lpVtbl -> QueryInterface(This,riid,ppvObject) )
+
+#define ICorDebugLegacyNetCFHostCallbackInvoker_PrivateWindowsPhoneOnly_AddRef(This) \
+ ( (This)->lpVtbl -> AddRef(This) )
+
+#define ICorDebugLegacyNetCFHostCallbackInvoker_PrivateWindowsPhoneOnly_Release(This) \
+ ( (This)->lpVtbl -> Release(This) )
+
+
+#define ICorDebugLegacyNetCFHostCallbackInvoker_PrivateWindowsPhoneOnly_InvokePauseCallback(This) \
+ ( (This)->lpVtbl -> InvokePauseCallback(This) )
+
+#define ICorDebugLegacyNetCFHostCallbackInvoker_PrivateWindowsPhoneOnly_InvokeResumeCallback(This) \
+ ( (This)->lpVtbl -> InvokeResumeCallback(This) )
+
+#endif /* COBJMACROS */
+
+
+#endif /* C style interface */
+
+
+
+
+#endif /* __ICorDebugLegacyNetCFHostCallbackInvoker_PrivateWindowsPhoneOnly_INTERFACE_DEFINED__ */
+
+
+/* Additional Prototypes for ALL interfaces */
+
+/* end of Additional Prototypes */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+
diff --git a/src/pal/src/.tpattributes b/src/pal/src/.tpattributes
new file mode 100644
index 0000000000..ca534f0fbf
--- /dev/null
+++ b/src/pal/src/.tpattributes
@@ -0,0 +1 @@
+configure:x
diff --git a/src/pal/src/CMakeLists.txt b/src/pal/src/CMakeLists.txt
new file mode 100644
index 0000000000..7df0aaf360
--- /dev/null
+++ b/src/pal/src/CMakeLists.txt
@@ -0,0 +1,311 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+include_directories(SYSTEM /usr/local/include)
+
+# set kernel version to detect Alpine
+EXEC_PROGRAM(uname ARGS -v OUTPUT_VARIABLE CMAKE_SYSTEM_KERNEL_VERSION)
+string(FIND "${CMAKE_SYSTEM_KERNEL_VERSION}" "Alpine" PAL_SYSTEM_ALPINE)
+if(PAL_SYSTEM_ALPINE EQUAL -1)
+ unset(PAL_SYSTEM_ALPINE)
+endif()
+
+include(configure.cmake)
+
+project(coreclrpal)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+if(CORECLR_SET_RPATH)
+ # Enable @rpath support for shared libraries.
+ set(MACOSX_RPATH ON)
+endif(CORECLR_SET_RPATH)
+
+if(CMAKE_VERSION VERSION_EQUAL 3.0 OR CMAKE_VERSION VERSION_GREATER 3.0)
+ cmake_policy(SET CMP0042 NEW)
+endif()
+
+# Include directories
+
+include_directories(include)
+
+# Compile options
+
+if(CMAKE_SYSTEM_PROCESSOR STREQUAL x86_64 OR CMAKE_SYSTEM_PROCESSOR STREQUAL amd64 OR CMAKE_SYSTEM_PROCESSOR STREQUAL AMD64)
+ set(PAL_CMAKE_PLATFORM_ARCH_AMD64 1)
+ add_definitions(-D_AMD64_)
+elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL armv7l)
+ set(PAL_CMAKE_PLATFORM_ARCH_ARM 1)
+ add_definitions(-D_ARM_)
+elseif(CMAKE_SYSTEM_PROCESSOR STREQUAL aarch64)
+ set(PAL_CMAKE_PLATFORM_ARCH_ARM64 1)
+ add_definitions(-D_ARM64_)
+else()
+ message(FATAL_ERROR "Only ARM and AMD64 is supported")
+endif()
+
+if(CMAKE_SYSTEM_NAME STREQUAL Darwin)
+ add_definitions(-D_TARGET_MAC64)
+ set(PLATFORM_SOURCES
+ arch/i386/activationhandlerwrapper.S
+ arch/i386/context.S
+ arch/i386/dispatchexceptionwrapper.S
+ exception/machexception.cpp
+ exception/machmessage.cpp
+ )
+endif(CMAKE_SYSTEM_NAME STREQUAL Darwin)
+
+add_definitions(-DPLATFORM_UNIX=1)
+add_definitions(-DLP64COMPATIBLE=1)
+add_definitions(-DFEATURE_PAL=1)
+add_definitions(-DCORECLR=1)
+add_definitions(-DPIC=1)
+add_definitions(-D_FILE_OFFSET_BITS=64)
+if(PAL_CMAKE_PLATFORM_ARCH_AMD64)
+ add_definitions(-DBIT64=1)
+ add_definitions(-D_WIN64=1)
+elseif(PAL_CMAKE_PLATFORM_ARCH_ARM)
+ add_definitions(-DBIT32=1)
+elseif(PAL_CMAKE_PLATFORM_ARCH_ARM64)
+ add_definitions(-DBIT64=1)
+ add_definitions(-D_WIN64=1)
+endif()
+
+# turn off capability to remove unused functions (which was enabled in debug build with sanitizers)
+set(CMAKE_SHARED_LINKER_FLAGS_DEBUG "${CMAKE_SHARED_LINKER_FLAGS_DEBUG} -Wl,--no-gc-sections")
+
+add_compile_options(-fPIC)
+
+if(PAL_CMAKE_PLATFORM_ARCH_AMD64)
+ set(ARCH_SOURCES
+ arch/i386/context2.S
+ arch/i386/debugbreak.S
+ arch/i386/exceptionhelper.S
+ arch/i386/processor.cpp
+ )
+elseif(PAL_CMAKE_PLATFORM_ARCH_ARM)
+ set(ARCH_SOURCES
+ arch/arm/context2.S
+ arch/arm/debugbreak.S
+ arch/arm/exceptionhelper.S
+ arch/arm/processor.cpp
+ )
+elseif(PAL_CMAKE_PLATFORM_ARCH_ARM64)
+ set(ARCH_SOURCES
+ arch/arm64/context2.S
+ arch/arm64/debugbreak.S
+ arch/arm64/exceptionhelper.S
+ arch/arm64/processor.cpp
+ )
+endif()
+
+if(PAL_CMAKE_PLATFORM_ARCH_ARM)
+ set_source_files_properties(exception/seh.cpp PROPERTIES COMPILE_FLAGS -Wno-error=inline-asm)
+endif(PAL_CMAKE_PLATFORM_ARCH_ARM)
+
+set(SOURCES
+ cruntime/file.cpp
+ cruntime/filecrt.cpp
+ cruntime/lstr.cpp
+ cruntime/malloc.cpp
+ cruntime/math.cpp
+ cruntime/mbstring.cpp
+ cruntime/misc.cpp
+ cruntime/misctls.cpp
+ cruntime/path.cpp
+ cruntime/printf.cpp
+ cruntime/printfcpp.cpp
+ cruntime/silent_printf.cpp
+ cruntime/string.cpp
+ cruntime/stringtls.cpp
+ cruntime/thread.cpp
+ cruntime/wchar.cpp
+ cruntime/wchartls.cpp
+ debug/debug.cpp
+ exception/seh.cpp
+ exception/signal.cpp
+ file/directory.cpp
+ file/disk.cpp
+ file/file.cpp
+ file/filetime.cpp
+ file/find.cpp
+ file/path.cpp
+ file/shmfilelockmgr.cpp
+ handlemgr/handleapi.cpp
+ handlemgr/handlemgr.cpp
+ init/pal.cpp
+ init/sxs.cpp
+ loader/module.cpp
+ loader/modulename.cpp
+ locale/unicode.cpp
+ locale/unicode_data.cpp
+ locale/utf8.cpp
+ map/common.cpp
+ map/map.cpp
+ map/virtual.cpp
+ memory/heap.cpp
+ memory/local.cpp
+ misc/dbgmsg.cpp
+ misc/environ.cpp
+ misc/error.cpp
+ misc/errorstrings.cpp
+ misc/fmtmessage.cpp
+ misc/identity.cpp
+ misc/miscpalapi.cpp
+ misc/msgbox.cpp
+ misc/strutil.cpp
+ misc/sysinfo.cpp
+ misc/time.cpp
+ misc/utils.cpp
+ misc/version.cpp
+ objmgr/palobjbase.cpp
+ objmgr/shmobject.cpp
+ objmgr/shmobjectmanager.cpp
+ safecrt/makepath_s.c
+ safecrt/memcpy_s.c
+ safecrt/memmove_s.c
+ safecrt/mbusafecrt.c
+ safecrt/safecrt_input_s.c
+ safecrt/safecrt_output_l.c
+ safecrt/safecrt_output_s.c
+ safecrt/safecrt_winput_s.c
+ safecrt/safecrt_woutput_s.c
+ safecrt/splitpath_s.c
+ safecrt/sprintf.c
+ safecrt/sscanf.c
+ safecrt/strcat_s.c
+ safecrt/strcpy_s.c
+ safecrt/strlen_s.c
+ safecrt/strncat_s.c
+ safecrt/strncpy_s.c
+ safecrt/strtok_s.c
+ safecrt/swprintf.c
+ safecrt/vsprintf.c
+ safecrt/vswprint.c
+ safecrt/wcscat_s.c
+ safecrt/wcscpy_s.c
+ safecrt/wcslen_s.c
+ safecrt/wcsncat_s.c
+ safecrt/wcsncpy_s.c
+ safecrt/wcstok_s.c
+ safecrt/wmakepath_s.c
+ safecrt/wsplitpath_s.c
+ safecrt/xtoa_s.c
+ safecrt/xtow_s.c
+ sharedmemory/sharedmemory.cpp
+ shmemory/shmemory.cpp
+ sync/cs.cpp
+ synchobj/event.cpp
+ synchobj/semaphore.cpp
+ synchobj/mutex.cpp
+ synchmgr/synchcontrollers.cpp
+ synchmgr/synchmanager.cpp
+ synchmgr/wait.cpp
+ thread/context.cpp
+ thread/process.cpp
+ thread/thread.cpp
+ thread/threadsusp.cpp
+ thread/tls.cpp
+)
+
+add_library(coreclrpal
+ STATIC
+ ${SOURCES}
+ ${ARCH_SOURCES}
+ ${PLATFORM_SOURCES}
+)
+
+add_library(tracepointprovider
+ STATIC
+ misc/tracepointprovider.cpp
+)
+
+if(CMAKE_SYSTEM_NAME STREQUAL Darwin)
+ find_library(COREFOUNDATION CoreFoundation)
+ find_library(CORESERVICES CoreServices)
+ find_library(SECURITY Security)
+ find_library(SYSTEM System)
+ target_link_libraries(coreclrpal
+ ${COREFOUNDATION}
+ ${CORESERVICES}
+ ${SECURITY}
+ ${SYSTEM}
+ )
+endif(CMAKE_SYSTEM_NAME STREQUAL Darwin)
+
+if(CMAKE_SYSTEM_NAME STREQUAL FreeBSD)
+ find_library(UNWIND unwind)
+ find_library(INTL intl)
+ target_link_libraries(coreclrpal
+ pthread
+ rt
+ ${UNWIND}
+ ${INTL}
+ )
+endif(CMAKE_SYSTEM_NAME STREQUAL FreeBSD)
+
+if(CMAKE_SYSTEM_NAME STREQUAL Linux)
+ if(PAL_CMAKE_PLATFORM_ARCH_ARM)
+ find_library(UNWIND_ARCH NAMES unwind-arm)
+ endif()
+
+ if(PAL_CMAKE_PLATFORM_ARCH_AMD64)
+ find_library(UNWIND_ARCH NAMES unwind-x86_64)
+ endif()
+
+ if(PAL_SYSTEM_ALPINE)
+ find_library(INTL intl)
+ endif()
+
+ find_library(UNWIND NAMES unwind)
+ find_library(UNWIND_GENERIC NAMES unwind-generic)
+
+ target_link_libraries(coreclrpal
+ gcc_s
+ pthread
+ rt
+ dl
+ uuid
+ )
+
+ if(UNWIND STREQUAL UNWIND-NOTFOUND)
+ message(FATAL_ERROR "Cannot find libunwind. Try installing libunwind8-dev and libunwind8.")
+ endif(UNWIND STREQUAL UNWIND-NOTFOUND)
+
+ target_link_libraries(coreclrpal ${UNWIND})
+
+ if(NOT UNWIND_GENERIC STREQUAL UNWIND_GENERIC-NOTFOUND)
+ target_link_libraries(coreclrpal ${UNWIND_GENERIC})
+ endif(NOT UNWIND_GENERIC STREQUAL UNWIND_GENERIC-NOTFOUND)
+
+ if(NOT UNWIND_ARCH STREQUAL UNWIND_ARCH-NOTFOUND)
+ target_link_libraries(coreclrpal ${UNWIND_ARCH})
+ endif(NOT UNWIND_ARCH STREQUAL UNWIND_ARCH-NOTFOUND)
+
+ if(NOT INTL STREQUAL INTL-NOTFOUND)
+ target_link_libraries(coreclrpal ${INTL})
+ endif(NOT INTL STREQUAL INTL-NOTFOUND)
+
+endif(CMAKE_SYSTEM_NAME STREQUAL Linux)
+
+if(CMAKE_SYSTEM_NAME STREQUAL NetBSD)
+ add_definitions(-D_KMEMUSER)
+ find_library(UNWIND unwind)
+ find_library(INTL intl)
+ find_library(KVM kvm)
+ target_link_libraries(coreclrpal
+ pthread
+ rt
+ ${UNWIND}
+ ${INTL}
+ ${KVM}
+ )
+endif(CMAKE_SYSTEM_NAME STREQUAL NetBSD)
+
+add_subdirectory(examples)
+
+if(FEATURE_EVENT_TRACE)
+ add_subdirectory($ENV{__IntermediatesDir}/Generated/eventprovider ${CMAKE_CURRENT_BINARY_DIR}/eventprovider)
+endif(FEATURE_EVENT_TRACE)
+
+# Install the static PAL library for VS
+install (TARGETS coreclrpal DESTINATION lib)
diff --git a/src/pal/src/arch/arm/asmconstants.h b/src/pal/src/arch/arm/asmconstants.h
new file mode 100644
index 0000000000..ae4b01b8dc
--- /dev/null
+++ b/src/pal/src/arch/arm/asmconstants.h
@@ -0,0 +1,61 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#ifndef __PAL_ARM_ASMCONSTANTS_H__
+#define __PAL_ARM_ASMCONSTANTS_H__
+
+#define CONTEXT_ContextFlags 0
+#define CONTEXT_R0 CONTEXT_ContextFlags+4
+#define CONTEXT_R1 CONTEXT_R0+4
+#define CONTEXT_R2 CONTEXT_R1+4
+#define CONTEXT_R3 CONTEXT_R2+4
+#define CONTEXT_R4 CONTEXT_R3+4
+#define CONTEXT_R5 CONTEXT_R4+4
+#define CONTEXT_R6 CONTEXT_R5+4
+#define CONTEXT_R7 CONTEXT_R6+4
+#define CONTEXT_R8 CONTEXT_R7+4
+#define CONTEXT_R9 CONTEXT_R8+4
+#define CONTEXT_R10 CONTEXT_R9+4
+#define CONTEXT_R11 CONTEXT_R10+4
+#define CONTEXT_R12 CONTEXT_R11+4
+#define CONTEXT_Sp CONTEXT_R12+4
+#define CONTEXT_Lr CONTEXT_Sp+4
+#define CONTEXT_Pc CONTEXT_Lr+4
+#define CONTEXT_Cpsr CONTEXT_Pc+4
+#define CONTEXT_Fpscr CONTEXT_Cpsr+4
+#define CONTEXT_Padding CONTEXT_Fpscr+4
+#define CONTEXT_D0 CONTEXT_Padding+4
+#define CONTEXT_D1 CONTEXT_D0+8
+#define CONTEXT_D2 CONTEXT_D1+8
+#define CONTEXT_D3 CONTEXT_D2+8
+#define CONTEXT_D4 CONTEXT_D3+8
+#define CONTEXT_D5 CONTEXT_D4+8
+#define CONTEXT_D6 CONTEXT_D5+8
+#define CONTEXT_D7 CONTEXT_D6+8
+#define CONTEXT_D8 CONTEXT_D7+8
+#define CONTEXT_D9 CONTEXT_D8+8
+#define CONTEXT_D10 CONTEXT_D9+8
+#define CONTEXT_D11 CONTEXT_D10+8
+#define CONTEXT_D12 CONTEXT_D11+8
+#define CONTEXT_D13 CONTEXT_D12+8
+#define CONTEXT_D14 CONTEXT_D13+8
+#define CONTEXT_D15 CONTEXT_D14+8
+#define CONTEXT_D16 CONTEXT_D15+8
+#define CONTEXT_D17 CONTEXT_D16+8
+#define CONTEXT_D18 CONTEXT_D17+8
+#define CONTEXT_D19 CONTEXT_D18+8
+#define CONTEXT_D20 CONTEXT_D19+8
+#define CONTEXT_D21 CONTEXT_D20+8
+#define CONTEXT_D22 CONTEXT_D21+8
+#define CONTEXT_D23 CONTEXT_D22+8
+#define CONTEXT_D24 CONTEXT_D23+8
+#define CONTEXT_D25 CONTEXT_D24+8
+#define CONTEXT_D26 CONTEXT_D25+8
+#define CONTEXT_D27 CONTEXT_D26+8
+#define CONTEXT_D28 CONTEXT_D27+8
+#define CONTEXT_D29 CONTEXT_D28+8
+#define CONTEXT_D30 CONTEXT_D29+8
+#define CONTEXT_D31 CONTEXT_D30+8
+
+#endif
diff --git a/src/pal/src/arch/arm/context2.S b/src/pal/src/arch/arm/context2.S
new file mode 100644
index 0000000000..61e9ab8463
--- /dev/null
+++ b/src/pal/src/arch/arm/context2.S
@@ -0,0 +1,174 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+// Implementation of _CONTEXT_CaptureContext for the ARM platform.
+// This function is processor dependent. It is used by exception handling,
+// and is always apply to the current thread.
+//
+
+#include "unixasmmacros.inc"
+#include "asmconstants.h"
+
+.syntax unified
+.thumb
+
+#define CONTEXT_ARM 0x00200000
+
+#define CONTEXT_CONTROL 1 // Sp, Lr, Pc, Cpsr
+#define CONTEXT_INTEGER 2 // R0-R12
+#define CONTEXT_SEGMENTS 4 //
+#define CONTEXT_FLOATING_POINT 8
+#define CONTEXT_DEBUG_REGISTERS 16 //
+
+#define CONTEXT_FULL (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT)
+
+
+// Incoming:
+// r0: Context*
+//
+LEAF_ENTRY CONTEXT_CaptureContext, _TEXT
+ // Ensure we save these registers
+ push {r4-r11}
+ // Save processor flags before calling any of the following 'test' instructions
+ // because they will modify state of some flags
+ push {r1}
+ mrs r1, apsr // Get APSR - equivalent to eflags
+ push {r1} // Save APSR
+ END_PROLOGUE
+
+ push {r2}
+ ldr r2, [r0, #(CONTEXT_ContextFlags)]
+ tst r2, #(CONTEXT_INTEGER)
+ pop {r2}
+
+ // Add 4 to stack so we point at R1, pop, then sub 8 to point at APSR
+ add sp, sp, #4
+ pop {r1}
+ sub sp, sp, #8
+
+ itttt ne
+ strne r0, [r0, #(CONTEXT_R0)]
+ addne r0, CONTEXT_R1
+ stmiane r0, {r1-r12}
+ subne r0, CONTEXT_R1
+
+ ldr r2, [r0, #(CONTEXT_ContextFlags)]
+ tst r2, #(CONTEXT_CONTROL)
+
+ ittt ne
+ addne sp, sp, #(10*4) // This needs to put the stack in the same state as it started
+ strne sp, [r0, #(CONTEXT_Sp)]
+ subne sp, sp, #(10*4)
+
+ itt ne
+ strne lr, [r0, #(CONTEXT_Lr)]
+ strne lr, [r0, #(CONTEXT_Pc)]
+
+ // Get the APSR pushed onto the stack at the start
+ pop {r1}
+ it ne
+ strne r1, [r0, #(CONTEXT_Cpsr)]
+
+ ldr r2, [r0, #(CONTEXT_ContextFlags)]
+ tst r2, #(CONTEXT_FLOATING_POINT)
+
+ itt ne
+ vmrsne r3, fpscr
+ strne r3, [r0, #(CONTEXT_Fpscr)]
+
+ itttt ne
+ addne r0, CONTEXT_D0
+ vstmiane r0!, {d0-d15}
+ vstmiane r0!, {d16-d31}
+ subne r0, CONTEXT_D31
+
+ // Make sure sp is restored
+ add sp, sp, #4
+
+ // Restore callee saved registers
+ pop {r4-r11}
+ bx lr
+LEAF_END CONTEXT_CaptureContext, _TEXT
+
+// Incoming:
+// R0: Context*
+//
+LEAF_ENTRY RtlCaptureContext, _TEXT
+ push {r1}
+ mov r1, #0
+ orr r1, r1, #CONTEXT_ARM
+ orr r1, r1, #CONTEXT_INTEGER
+ orr r1, r1, #CONTEXT_CONTROL
+ orr r1, r1, #CONTEXT_FLOATING_POINT
+ str r1, [r0, #(CONTEXT_ContextFlags)]
+ pop {r1}
+ b C_FUNC(CONTEXT_CaptureContext)
+LEAF_END RtlCaptureContext, _TEXT
+
+// Incoming:
+// r0: Context*
+// r1: Exception*
+//
+LEAF_ENTRY RtlRestoreContext, _TEXT
+ END_PROLOGUE
+
+ ldr r2, [r0, #(CONTEXT_ContextFlags)]
+ tst r2, #(CONTEXT_FLOATING_POINT)
+
+ itttt ne
+ addne r0, CONTEXT_D0
+ vldmiane r0!, {d0-d15}
+ vldmiane r0, {d16-d31}
+ subne r0, CONTEXT_D16
+
+ itt ne
+ ldrne r3, [r0, #(CONTEXT_Fpscr)]
+ vmrsne r3, FPSCR
+
+ ldr r2, [r0, #(CONTEXT_ContextFlags)]
+ tst r2, #(CONTEXT_CONTROL)
+
+ it eq
+ beq LOCAL_LABEL(No_Restore_CONTEXT_CONTROL)
+
+ ldr r2, [r0, #(CONTEXT_ContextFlags)]
+ tst r2, #(CONTEXT_INTEGER)
+
+ it eq
+ beq LOCAL_LABEL(No_Restore_CONTEXT_INTEGER)
+
+ ldr R2, [r0, #(CONTEXT_Cpsr)]
+ msr APSR, r2
+
+ // Ideally, we would like to use `ldmia r0, {r0-r12, sp, lr, pc}` here,
+ // but clang 3.6 and later, as per ARM recommendation, disallows using
+ // Sp in the register list, and Pc and Lr simultaneously.
+ // So we are going to use the IPC register r12 to copy Sp, Lr and Pc
+ // which should be ok -- TODO: Is this really ok?
+ add r12, r0, CONTEXT_R0
+ ldm r12, {r0-r11}
+ ldr sp, [r12, #(CONTEXT_Sp - (CONTEXT_R0))]
+ ldr lr, [r12, #(CONTEXT_Lr - (CONTEXT_R0))]
+ ldr pc, [r12, #(CONTEXT_Pc - (CONTEXT_R0))]
+
+LOCAL_LABEL(No_Restore_CONTEXT_INTEGER):
+
+ ldr r2, [r0, #(CONTEXT_Cpsr)]
+ msr APSR, r2
+
+ ldr sp, [r0, #(CONTEXT_Sp)]
+ ldr lr, [r0, #(CONTEXT_Lr)]
+ ldr pc, [r0, #(CONTEXT_Pc)]
+
+LOCAL_LABEL(No_Restore_CONTEXT_CONTROL):
+ ldr r2, [r0, #(CONTEXT_ContextFlags)]
+ tst r2, #(CONTEXT_INTEGER)
+
+ itt ne
+ addne r0, CONTEXT_R0
+ ldmiane r0, {r0-r12}
+
+ sub sp, sp, #4
+ bx lr
+LEAF_END RtlRestoreContext, _TEXT
diff --git a/src/pal/src/arch/arm/debugbreak.S b/src/pal/src/arch/arm/debugbreak.S
new file mode 100644
index 0000000000..863d7cf40b
--- /dev/null
+++ b/src/pal/src/arch/arm/debugbreak.S
@@ -0,0 +1,14 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#include "unixasmmacros.inc"
+
+.syntax unified
+.thumb
+
+LEAF_ENTRY DBG_DebugBreak, _TEXT
+ EMIT_BREAKPOINT
+ bx lr
+LEAF_END_MARKED DBG_DebugBreak, _TEXT
+
diff --git a/src/pal/src/arch/arm/exceptionhelper.S b/src/pal/src/arch/arm/exceptionhelper.S
new file mode 100644
index 0000000000..ed1c9c3dc2
--- /dev/null
+++ b/src/pal/src/arch/arm/exceptionhelper.S
@@ -0,0 +1,30 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#include "unixasmmacros.inc"
+#include "asmconstants.h"
+
+.syntax unified
+.thumb
+
+// EXTERN_C void ThrowExceptionFromContextInternal(CONTEXT* context, PAL_SEHException* ex);
+LEAF_ENTRY ThrowExceptionFromContextInternal, _TEXT
+ // Ported from src/pal/src/arch/i386/exceptionhelper.S
+ push_nonvol_reg {r7} /* FP. x64-RBP */
+
+ ldr r4, [r0, #(CONTEXT_R4)]
+ ldr r5, [r0, #(CONTEXT_R5)]
+ ldr r6, [r0, #(CONTEXT_R6)]
+ ldr r7, [r0, #(CONTEXT_R7)]
+ ldr r8, [r0, #(CONTEXT_R8)]
+ ldr r9, [r0, #(CONTEXT_R9)]
+ ldr r10, [r0, #(CONTEXT_R10)]
+ ldr r11, [r0, #(CONTEXT_R11)]
+ ldr sp, [r0, #(CONTEXT_Sp)]
+ ldr lr, [r0, #(CONTEXT_Pc)]
+
+ // The PAL_SEHException pointer
+ mov r0, r1
+ b EXTERNAL_C_FUNC(ThrowExceptionHelper)
+LEAF_END ThrowExceptionFromContextInternal, _TEXT
diff --git a/src/pal/src/arch/arm/processor.cpp b/src/pal/src/arch/arm/processor.cpp
new file mode 100644
index 0000000000..f41caff1e0
--- /dev/null
+++ b/src/pal/src/arch/arm/processor.cpp
@@ -0,0 +1,42 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ processor.cpp
+
+Abstract:
+
+ Implementation of processor related functions for the ARM
+ platform. These functions are processor dependent.
+
+
+
+--*/
+
+#include "pal/palinternal.h"
+
+/*++
+Function:
+YieldProcessor
+
+The YieldProcessor function signals to the processor to give resources
+to threads that are waiting for them. This macro is only effective on
+processors that support technology allowing multiple threads running
+on a single processor, such as Intel's Hyper-Threading technology.
+
+--*/
+void
+PALAPI
+YieldProcessor(
+ VOID)
+{
+ // Pretty sure ARM has no useful function here?
+ return;
+}
+
diff --git a/src/pal/src/arch/arm64/context2.S b/src/pal/src/arch/arm64/context2.S
new file mode 100644
index 0000000000..a64e62c94d
--- /dev/null
+++ b/src/pal/src/arch/arm64/context2.S
@@ -0,0 +1,300 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+// Implementation of _CONTEXT_CaptureContext for the ARM platform.
+// This function is processor dependent. It is used by exception handling,
+// and is always apply to the current thread.
+//
+
+#include "unixasmmacros.inc"
+
+#define CONTEXT_ARM64 0x00400000L
+
+#define CONTEXT_CONTROL (CONTEXT_ARM64 | 0x1L)
+#define CONTEXT_INTEGER (CONTEXT_ARM64 | 0x2L)
+#define CONTEXT_FLOATING_POINT (CONTEXT_ARM64 | 0x4L)
+#define CONTEXT_DEBUG_REGISTERS (CONTEXT_ARM64 | 0x8L)
+
+#define CONTEXT_FULL (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT)
+
+#define CONTEXT_ContextFlags 0
+#define CONTEXT_Cpsr CONTEXT_ContextFlags+4
+#define CONTEXT_X0 CONTEXT_Cpsr+4
+#define CONTEXT_X1 CONTEXT_X0+8
+#define CONTEXT_X2 CONTEXT_X1+8
+#define CONTEXT_X3 CONTEXT_X2+8
+#define CONTEXT_X4 CONTEXT_X3+8
+#define CONTEXT_X5 CONTEXT_X4+8
+#define CONTEXT_X6 CONTEXT_X5+8
+#define CONTEXT_X7 CONTEXT_X6+8
+#define CONTEXT_X8 CONTEXT_X7+8
+#define CONTEXT_X9 CONTEXT_X8+8
+#define CONTEXT_X10 CONTEXT_X9+8
+#define CONTEXT_X11 CONTEXT_X10+8
+#define CONTEXT_X12 CONTEXT_X11+8
+#define CONTEXT_X13 CONTEXT_X12+8
+#define CONTEXT_X14 CONTEXT_X13+8
+#define CONTEXT_X15 CONTEXT_X14+8
+#define CONTEXT_X16 CONTEXT_X15+8
+#define CONTEXT_X17 CONTEXT_X16+8
+#define CONTEXT_X18 CONTEXT_X17+8
+#define CONTEXT_X19 CONTEXT_X18+8
+#define CONTEXT_X20 CONTEXT_X19+8
+#define CONTEXT_X21 CONTEXT_X20+8
+#define CONTEXT_X22 CONTEXT_X21+8
+#define CONTEXT_X23 CONTEXT_X22+8
+#define CONTEXT_X24 CONTEXT_X23+8
+#define CONTEXT_X25 CONTEXT_X24+8
+#define CONTEXT_X26 CONTEXT_X25+8
+#define CONTEXT_X27 CONTEXT_X26+8
+#define CONTEXT_X28 CONTEXT_X27+8
+#define CONTEXT_Fp CONTEXT_X28+8
+#define CONTEXT_Lr CONTEXT_Fp+8
+#define CONTEXT_Sp CONTEXT_Lr+8
+#define CONTEXT_Pc CONTEXT_Sp+8
+#define CONTEXT_NEON_OFFSET CONTEXT_Pc+8
+#define CONTEXT_V0 0
+#define CONTEXT_V1 CONTEXT_V0+16
+#define CONTEXT_V2 CONTEXT_V1+16
+#define CONTEXT_V3 CONTEXT_V2+16
+#define CONTEXT_V4 CONTEXT_V3+16
+#define CONTEXT_V5 CONTEXT_V4+16
+#define CONTEXT_V6 CONTEXT_V5+16
+#define CONTEXT_V7 CONTEXT_V6+16
+#define CONTEXT_V8 CONTEXT_V7+16
+#define CONTEXT_V9 CONTEXT_V8+16
+#define CONTEXT_V10 CONTEXT_V9+16
+#define CONTEXT_V11 CONTEXT_V10+16
+#define CONTEXT_V12 CONTEXT_V11+16
+#define CONTEXT_V13 CONTEXT_V12+16
+#define CONTEXT_V14 CONTEXT_V13+16
+#define CONTEXT_V15 CONTEXT_V14+16
+#define CONTEXT_V16 CONTEXT_V15+16
+#define CONTEXT_V17 CONTEXT_V16+16
+#define CONTEXT_V18 CONTEXT_V17+16
+#define CONTEXT_V19 CONTEXT_V18+16
+#define CONTEXT_V20 CONTEXT_V19+16
+#define CONTEXT_V21 CONTEXT_V20+16
+#define CONTEXT_V22 CONTEXT_V21+16
+#define CONTEXT_V23 CONTEXT_V22+16
+#define CONTEXT_V24 CONTEXT_V23+16
+#define CONTEXT_V25 CONTEXT_V24+16
+#define CONTEXT_V26 CONTEXT_V25+16
+#define CONTEXT_V27 CONTEXT_V26+16
+#define CONTEXT_V28 CONTEXT_V27+16
+#define CONTEXT_V29 CONTEXT_V28+16
+#define CONTEXT_V30 CONTEXT_V29+16
+#define CONTEXT_V31 CONTEXT_V30+16
+#define CONTEXT_FLOAT_CONTROL_OFFSET CONTEXT_V31
+#define CONTEXT_Fpcr 0
+#define CONTEXT_Fpsr CONTEXT_Fpcr+4
+
+// Incoming:
+// x0: Context*
+//
+LEAF_ENTRY CONTEXT_CaptureContext, _TEXT
+ sub sp, sp, #32
+ // save x1, x2 and x3 on stack so we can use them as scratch
+ stp x1, x2, [sp]
+ str x3, [sp, 16]
+ // save the current flags on the stack
+ mrs x1, nzcv
+ str x1, [sp, 24]
+
+ ldr w1, [x0, CONTEXT_ContextFlags]
+ // clangs assembler doesn't seem to support the mov Wx, imm32 yet
+ movz w2, #0x40, lsl #16
+ movk w2, #0x1
+ mov w3, w2
+ and w2, w1, w2
+ cmp w2, w3
+ b.ne LOCAL_LABEL(Done_CONTEXT_CONTROL)
+
+ // save the cpsr
+ ldr x2, [sp, 24]
+ str w2, [x0, CONTEXT_Cpsr]
+ stp fp, lr, [x0, CONTEXT_Fp]
+ add sp, sp, #32
+ mov x2, sp
+ stp x2, lr, [x0, CONTEXT_Sp]
+ sub sp, sp, #32
+
+LOCAL_LABEL(Done_CONTEXT_CONTROL):
+ // we dont clobber x1 in the CONTEXT_CONTROL case
+ // ldr w1, [x0, CONTEXT_ContextFlags]
+ // clangs assembler doesn't seem to support the mov Wx, imm32 yet
+ movz w2, #0x40, lsl #16
+ movk w2, #0x2
+ mov w3, w2
+ and w2, w1, w2
+ cmp w2, w3
+ b.ne LOCAL_LABEL(Done_CONTEXT_INTEGER)
+
+ ldp x1, x2, [sp]
+ ldr x3, [sp, 16]
+
+ stp x0, x1, [x0, CONTEXT_X0]
+ stp x2, x3, [x0, CONTEXT_X2]
+ stp x4, x5, [x0, CONTEXT_X4]
+ stp x6, x7, [x0, CONTEXT_X6]
+ stp x8, x9, [x0, CONTEXT_X8]
+ stp x10, x11, [x0, CONTEXT_X10]
+ stp x12, x13, [x0, CONTEXT_X12]
+ stp x14, x15, [x0, CONTEXT_X14]
+ stp x16, x17, [x0, CONTEXT_X16]
+ stp x18, x19, [x0, CONTEXT_X18]
+ stp x20, x21, [x0, CONTEXT_X20]
+ stp x22, x23, [x0, CONTEXT_X22]
+ stp x24, x25, [x0, CONTEXT_X24]
+ stp x26, x27, [x0, CONTEXT_X26]
+ str x28, [x0, CONTEXT_X28]
+
+
+LOCAL_LABEL(Done_CONTEXT_INTEGER):
+ ldr w1, [x0, CONTEXT_ContextFlags]
+ // clangs assembler doesn't seem to support the mov Wx, imm32 yet
+ movz w2, #0x40, lsl #16
+ movk w2, #0x4
+ mov w3, w2
+ and w2, w1, w2
+ cmp w2, w3
+ b.ne LOCAL_LABEL(Done_CONTEXT_FLOATING_POINT)
+
+ add x0, x0, CONTEXT_NEON_OFFSET
+ stp q0, q1, [x0, CONTEXT_V0]
+ stp q2, q3, [x0, CONTEXT_V2]
+ stp q4, q5, [x0, CONTEXT_V4]
+ stp q6, q7, [x0, CONTEXT_V6]
+ stp q8, q9, [x0, CONTEXT_V8]
+ stp q10, q11, [x0, CONTEXT_V10]
+ stp q12, q13, [x0, CONTEXT_V12]
+ stp q14, q15, [x0, CONTEXT_V14]
+ stp q16, q17, [x0, CONTEXT_V16]
+ stp q18, q19, [x0, CONTEXT_V18]
+ stp q20, q21, [x0, CONTEXT_V20]
+ stp q22, q23, [x0, CONTEXT_V22]
+ stp q24, q25, [x0, CONTEXT_V24]
+ stp q26, q27, [x0, CONTEXT_V26]
+ stp q28, q29, [x0, CONTEXT_V28]
+ stp q30, q31, [x0, CONTEXT_V30]
+ add x0, x0, CONTEXT_FLOAT_CONTROL_OFFSET
+ mrs x1, fpcr
+ mrs x2, fpsr
+ sub x0, x0, CONTEXT_FLOAT_CONTROL_OFFSET
+ stp x1, x2, [x0, CONTEXT_Fpcr]
+ sub x0, x0, CONTEXT_NEON_OFFSET
+
+LOCAL_LABEL(Done_CONTEXT_FLOATING_POINT):
+
+ add sp, sp, #32
+ ret
+LEAF_END CONTEXT_CaptureContext, _TEXT
+
+// Incoming:
+// x0: Context*
+
+LEAF_ENTRY RtlCaptureContext, _TEXT
+ sub sp, sp, #16
+ str x1, [sp]
+ // same as above, clang doesn't like mov with #imm32
+ // keep this in sync if CONTEXT_FULL changes
+ movz w1, #0x40, lsl #16
+ orr w1, w1, #0x1
+ orr w1, w1, #0x2
+ orr w1, w1, #0x4
+ orr w1, w1, #0x8
+ str w1, [x0, CONTEXT_ContextFlags]
+ ldr x1, [sp]
+ add sp, sp, #16
+ b C_FUNC(CONTEXT_CaptureContext)
+LEAF_END RtlCaptureContext, _TEXT
+
+// Incoming:
+// x0: Context*
+// x1: Exception*
+//
+LEAF_ENTRY RtlRestoreContext, _TEXT
+ // aarch64 specifies:
+ // IP0 and IP1, the Intra-Procedure Call temporary registers,
+ // are available for use by e.g. veneers or branch islands during a procedure call.
+ // They are otherwise corruptible.
+ // Since we cannot control $pc directly, we're going to corrupt x16 and x17
+ // so that we can restore control
+ // since we potentially clobber x0 below, we'll bank it in x16
+ mov x16, x0
+
+ ldr w2, [x16, CONTEXT_ContextFlags]
+ // clangs assembler doesn't seem to support the mov Wx, imm32 yet
+ movz w3, #0x40, lsl #16
+ movk w3, #0x4
+ mov w4, w3
+ and w3, w2, w3
+ cmp w3, w4
+ b.ne LOCAL_LABEL(No_Restore_CONTEXT_FLOATING_POINT)
+
+ add x16, x16, CONTEXT_NEON_OFFSET
+ ldp q0, q1, [x16, CONTEXT_V0]
+ ldp q2, q3, [x16, CONTEXT_V2]
+ ldp q4, q5, [x16, CONTEXT_V4]
+ ldp q6, q7, [x16, CONTEXT_V6]
+ ldp q8, q9, [x16, CONTEXT_V8]
+ ldp q10, q11, [x16, CONTEXT_V10]
+ ldp q12, q13, [x16, CONTEXT_V12]
+ ldp q14, q15, [x16, CONTEXT_V14]
+ ldp q16, q17, [x16, CONTEXT_V16]
+ ldp q18, q19, [x16, CONTEXT_V18]
+ ldp q20, q21, [x16, CONTEXT_V20]
+ ldp q22, q23, [x16, CONTEXT_V22]
+ ldp q24, q25, [x16, CONTEXT_V24]
+ ldp q26, q27, [x16, CONTEXT_V26]
+ ldp q28, q29, [x16, CONTEXT_V28]
+ ldp q30, q31, [x16, CONTEXT_V30]
+ ldp x1, x2, [x16, CONTEXT_Fpcr]
+ msr fpcr, x1
+ msr fpsr, x2
+ sub x16, x16, CONTEXT_NEON_OFFSET
+
+LOCAL_LABEL(No_Restore_CONTEXT_FLOATING_POINT):
+ movz w2, #0x40, lsl #16
+ movk w2, #0x2
+ mov w3, w2
+ and w2, w1, w2
+ cmp w2, w3
+ b.ne LOCAL_LABEL(No_Restore_CONTEXT_INTEGER)
+
+ ldp x0, x1, [x16, CONTEXT_X0]
+ ldp x2, x3, [x16, CONTEXT_X2]
+ ldp x4, x5, [x16, CONTEXT_X4]
+ ldp x6, x7, [x16, CONTEXT_X6]
+ ldp x8, x9, [x16, CONTEXT_X8]
+ ldp x10, x11, [x16, CONTEXT_X10]
+ ldp x12, x13, [x16, CONTEXT_X12]
+ ldp x14, x15, [x16, CONTEXT_X14]
+ ldp x18, x19, [x16, CONTEXT_X18]
+ ldp x20, x21, [x16, CONTEXT_X20]
+ ldp x22, x23, [x16, CONTEXT_X22]
+ ldp x24, x25, [x16, CONTEXT_X24]
+ ldp x26, x27, [x16, CONTEXT_X26]
+ ldr x28, [x16, CONTEXT_X28]
+
+LOCAL_LABEL(No_Restore_CONTEXT_INTEGER):
+ movz w2, #0x40, lsl #16
+ movk w2, #0x2
+ mov w3, w2
+ and w2, w1, w2
+ cmp w2, w3
+ b.ne LOCAL_LABEL(No_Restore_CONTEXT_CONTROL)
+
+ ldr w17, [x16, CONTEXT_Cpsr]
+ msr nzcv, x17
+ ldp fp, lr, [x16, CONTEXT_Fp]
+ ldr x17, [x16, CONTEXT_Sp]
+ mov sp, x17
+ ldr x17, [x16, CONTEXT_Pc]
+ br x17
+
+LOCAL_LABEL(No_Restore_CONTEXT_CONTROL):
+ ret
+
+LEAF_END RtlRestoreContext, _TEXT
diff --git a/src/pal/src/arch/arm64/debugbreak.S b/src/pal/src/arch/arm64/debugbreak.S
new file mode 100644
index 0000000000..0dc5bb6bd3
--- /dev/null
+++ b/src/pal/src/arch/arm64/debugbreak.S
@@ -0,0 +1,11 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#include "unixasmmacros.inc"
+
+LEAF_ENTRY DBG_DebugBreak, _TEXT
+ EMIT_BREAKPOINT
+ ret
+LEAF_END_MARKED DBG_DebugBreak, _TEXT
+
diff --git a/src/pal/src/arch/arm64/exceptionhelper.S b/src/pal/src/arch/arm64/exceptionhelper.S
new file mode 100644
index 0000000000..4fdcfc5eb1
--- /dev/null
+++ b/src/pal/src/arch/arm64/exceptionhelper.S
@@ -0,0 +1,9 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#include "unixasmmacros.inc"
+
+LEAF_ENTRY ThrowExceptionFromContextInternal, _TEXT
+ EMIT_BREAKPOINT
+LEAF_END ThrowExceptionFromContextInternal, _TEXT
diff --git a/src/pal/src/arch/arm64/processor.cpp b/src/pal/src/arch/arm64/processor.cpp
new file mode 100644
index 0000000000..6c7851a2b1
--- /dev/null
+++ b/src/pal/src/arch/arm64/processor.cpp
@@ -0,0 +1,41 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ processor.cpp
+
+Abstract:
+
+ Implementation of processor related functions for the ARM64
+ platform. These functions are processor dependent.
+
+
+
+--*/
+
+#include "pal/palinternal.h"
+
+/*++
+Function:
+YieldProcessor
+
+The YieldProcessor function signals to the processor to give resources
+to threads that are waiting for them. This macro is only effective on
+processors that support technology allowing multiple threads running
+on a single processor, such as Intel's Hyper-Threading technology.
+
+--*/
+void
+PALAPI
+YieldProcessor(
+ VOID)
+{
+ return;
+}
+
diff --git a/src/pal/src/arch/i386/activationhandlerwrapper.S b/src/pal/src/arch/i386/activationhandlerwrapper.S
new file mode 100644
index 0000000000..63f718e81f
--- /dev/null
+++ b/src/pal/src/arch/i386/activationhandlerwrapper.S
@@ -0,0 +1,30 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+.intel_syntax noprefix
+#include "unixasmmacros.inc"
+#include "asmconstants.h"
+
+#ifdef BIT64
+// Offset of the return address from the ActivationHandler in the ActivationHandlerWrapper
+.globl C_FUNC(ActivationHandlerReturnOffset)
+C_FUNC(ActivationHandlerReturnOffset):
+ .int LOCAL_LABEL(ActivationHandlerReturn)-C_FUNC(ActivationHandlerWrapper)
+
+NESTED_ENTRY ActivationHandlerWrapper, _TEXT, NoHandler
+ push_nonvol_reg rbp
+ mov rbp, rsp
+ alloc_stack (CONTEXT_Size)
+ set_cfa_register rbp, (2*8)
+ mov rdi, rsp
+ int3
+ call C_FUNC(ActivationHandler)
+LOCAL_LABEL(ActivationHandlerReturn):
+ int3
+ free_stack (CONTEXT_Size)
+ pop_nonvol_reg rbp
+ ret
+NESTED_END ActivationHandlerWrapper, _TEXT
+
+#endif // BIT64
diff --git a/src/pal/src/arch/i386/asmconstants.h b/src/pal/src/arch/i386/asmconstants.h
new file mode 100644
index 0000000000..182c1191e4
--- /dev/null
+++ b/src/pal/src/arch/i386/asmconstants.h
@@ -0,0 +1,106 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#ifdef BIT64
+
+#define CONTEXT_AMD64 0x100000
+
+#define CONTEXT_CONTROL 1 // SegSs, Rsp, SegCs, Rip, and EFlags
+#define CONTEXT_INTEGER 2 // Rax, Rcx, Rdx, Rbx, Rbp, Rsi, Rdi, R8-R15
+#define CONTEXT_SEGMENTS 4 // SegDs, SegEs, SegFs, SegGs
+#define CONTEXT_FLOATING_POINT 8
+#define CONTEXT_DEBUG_REGISTERS 16 // Dr0-Dr3 and Dr6-Dr7
+
+#define CONTEXT_FULL (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT)
+
+#define CONTEXT_XSTATE 64
+
+#define CONTEXT_ContextFlags 6*8
+#define CONTEXT_SegCs CONTEXT_ContextFlags+8
+#define CONTEXT_SegDs CONTEXT_SegCs+2
+#define CONTEXT_SegEs CONTEXT_SegDs+2
+#define CONTEXT_SegFs CONTEXT_SegEs+2
+#define CONTEXT_SegGs CONTEXT_SegFs+2
+#define CONTEXT_SegSs CONTEXT_SegGs+2
+#define CONTEXT_EFlags CONTEXT_SegSs+2
+#define CONTEXT_Dr0 CONTEXT_EFlags+4
+#define CONTEXT_Dr1 CONTEXT_Dr0+8
+#define CONTEXT_Dr2 CONTEXT_Dr1+8
+#define CONTEXT_Dr3 CONTEXT_Dr2+8
+#define CONTEXT_Dr6 CONTEXT_Dr3+8
+#define CONTEXT_Dr7 CONTEXT_Dr6+8
+#define CONTEXT_Rax CONTEXT_Dr7+8
+#define CONTEXT_Rcx CONTEXT_Rax+8
+#define CONTEXT_Rdx CONTEXT_Rcx+8
+#define CONTEXT_Rbx CONTEXT_Rdx+8
+#define CONTEXT_Rsp CONTEXT_Rbx+8
+#define CONTEXT_Rbp CONTEXT_Rsp+8
+#define CONTEXT_Rsi CONTEXT_Rbp+8
+#define CONTEXT_Rdi CONTEXT_Rsi+8
+#define CONTEXT_R8 CONTEXT_Rdi+8
+#define CONTEXT_R9 CONTEXT_R8+8
+#define CONTEXT_R10 CONTEXT_R9+8
+#define CONTEXT_R11 CONTEXT_R10+8
+#define CONTEXT_R12 CONTEXT_R11+8
+#define CONTEXT_R13 CONTEXT_R12+8
+#define CONTEXT_R14 CONTEXT_R13+8
+#define CONTEXT_R15 CONTEXT_R14+8
+#define CONTEXT_Rip CONTEXT_R15+8
+#define CONTEXT_FltSave CONTEXT_Rip+8
+#define FLOATING_SAVE_AREA_SIZE 4*8+24*16+96
+#define CONTEXT_Xmm0 CONTEXT_FltSave+10*16
+#define CONTEXT_Xmm1 CONTEXT_Xmm0+16
+#define CONTEXT_Xmm2 CONTEXT_Xmm1+16
+#define CONTEXT_Xmm3 CONTEXT_Xmm2+16
+#define CONTEXT_Xmm4 CONTEXT_Xmm3+16
+#define CONTEXT_Xmm5 CONTEXT_Xmm4+16
+#define CONTEXT_Xmm6 CONTEXT_Xmm5+16
+#define CONTEXT_Xmm7 CONTEXT_Xmm6+16
+#define CONTEXT_Xmm8 CONTEXT_Xmm7+16
+#define CONTEXT_Xmm9 CONTEXT_Xmm8+16
+#define CONTEXT_Xmm10 CONTEXT_Xmm9+16
+#define CONTEXT_Xmm11 CONTEXT_Xmm10+16
+#define CONTEXT_Xmm12 CONTEXT_Xmm11+16
+#define CONTEXT_Xmm13 CONTEXT_Xmm12+16
+#define CONTEXT_Xmm14 CONTEXT_Xmm13+16
+#define CONTEXT_Xmm15 CONTEXT_Xmm14+16
+#define CONTEXT_VectorRegister CONTEXT_FltSave+FLOATING_SAVE_AREA_SIZE
+#define CONTEXT_VectorControl CONTEXT_VectorRegister+16*26
+#define CONTEXT_DebugControl CONTEXT_VectorControl+8
+#define CONTEXT_LastBranchToRip CONTEXT_DebugControl+8
+#define CONTEXT_LastBranchFromRip CONTEXT_LastBranchToRip+8
+#define CONTEXT_LastExceptionToRip CONTEXT_LastBranchFromRip+8
+#define CONTEXT_LastExceptionFromRip CONTEXT_LastExceptionToRip+8
+#define CONTEXT_Size CONTEXT_LastExceptionFromRip+8
+
+#else // BIT64
+
+#define CONTEXT_ContextFlags 0
+#define CONTEXT_FLOATING_POINT 8
+#define CONTEXT_FloatSave 7*4
+#define FLOATING_SAVE_AREA_SIZE 8*4+80
+#define CONTEXT_Edi CONTEXT_FloatSave + FLOATING_SAVE_AREA_SIZE + 4*4
+#define CONTEXT_Esi CONTEXT_Edi+4
+#define CONTEXT_Ebx CONTEXT_Esi+4
+#define CONTEXT_Edx CONTEXT_Ebx+4
+#define CONTEXT_Ecx CONTEXT_Edx+4
+#define CONTEXT_Eax CONTEXT_Ecx+4
+#define CONTEXT_Ebp CONTEXT_Eax+4
+#define CONTEXT_Eip CONTEXT_Ebp+4
+#define CONTEXT_SegCs CONTEXT_Eip+4
+#define CONTEXT_EFlags CONTEXT_SegCs+4
+#define CONTEXT_Esp CONTEXT_EFlags+4
+#define CONTEXT_SegSs CONTEXT_Esp+4
+#define CONTEXT_EXTENDED_REGISTERS 32
+#define CONTEXT_ExtendedRegisters CONTEXT_SegSs+4
+#define CONTEXT_Xmm0 CONTEXT_ExtendedRegisters+160
+#define CONTEXT_Xmm1 CONTEXT_Xmm0+16
+#define CONTEXT_Xmm2 CONTEXT_Xmm1+16
+#define CONTEXT_Xmm3 CONTEXT_Xmm2+16
+#define CONTEXT_Xmm4 CONTEXT_Xmm3+16
+#define CONTEXT_Xmm5 CONTEXT_Xmm4+16
+#define CONTEXT_Xmm6 CONTEXT_Xmm5+16
+#define CONTEXT_Xmm7 CONTEXT_Xmm6+16
+
+#endif // BIT64
diff --git a/src/pal/src/arch/i386/context.S b/src/pal/src/arch/i386/context.S
new file mode 100644
index 0000000000..f8a2dca89c
--- /dev/null
+++ b/src/pal/src/arch/i386/context.S
@@ -0,0 +1,21 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#if defined(_DEBUG)
+ .text
+ .globl _DBG_CheckStackAlignment
+
+_DBG_CheckStackAlignment:
+ // Prolog - at this point we are at aligned - 8 (for the call)
+ pushq %rbp // aligned -16
+ movq %rsp, %rbp
+
+ testl $0xf,%esp // can get away with esp even on AMD64.
+ jz .+3
+ int3
+
+ // Epilog
+ popq %rbp
+ ret
+#endif
diff --git a/src/pal/src/arch/i386/context2.S b/src/pal/src/arch/i386/context2.S
new file mode 100644
index 0000000000..0e93e81a55
--- /dev/null
+++ b/src/pal/src/arch/i386/context2.S
@@ -0,0 +1,259 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+// Implementation of _CONTEXT_CaptureContext for the Intel x86 platform.
+// This function is processor dependent. It is used by exception handling,
+// and is always apply to the current thread.
+//
+
+.intel_syntax noprefix
+#include "unixasmmacros.inc"
+#include "asmconstants.h"
+
+#ifdef BIT64
+
+#define IRETFRAME_Rip 0
+#define IRETFRAME_SegCs IRETFRAME_Rip+8
+#define IRETFRAME_EFlags IRETFRAME_SegCs+8
+#define IRETFRAME_Rsp IRETFRAME_EFlags+8
+#define IRETFRAME_SegSs IRETFRAME_Rsp+8
+#define IRetFrameLength IRETFRAME_SegSs+8
+#define IRetFrameLengthAligned 16*((IRetFrameLength+8)/16)
+
+// Incoming:
+// RDI: Context*
+//
+LEAF_ENTRY CONTEXT_CaptureContext, _TEXT
+ // Save processor flags before calling any of the following 'test' instructions
+ // because they will modify state of some flags
+ push_eflags
+ END_PROLOGUE
+
+ test BYTE PTR [rdi + CONTEXT_ContextFlags], CONTEXT_INTEGER
+ je LOCAL_LABEL(Done_CONTEXT_INTEGER)
+ mov [rdi + CONTEXT_Rdi], rdi
+ mov [rdi + CONTEXT_Rsi], rsi
+ mov [rdi + CONTEXT_Rbx], rbx
+ mov [rdi + CONTEXT_Rdx], rdx
+ mov [rdi + CONTEXT_Rcx], rcx
+ mov [rdi + CONTEXT_Rax], rax
+ mov [rdi + CONTEXT_Rbp], rbp
+ mov [rdi + CONTEXT_R8], r8
+ mov [rdi + CONTEXT_R9], r9
+ mov [rdi + CONTEXT_R10], r10
+ mov [rdi + CONTEXT_R11], r11
+ mov [rdi + CONTEXT_R12], r12
+ mov [rdi + CONTEXT_R13], r13
+ mov [rdi + CONTEXT_R14], r14
+ mov [rdi + CONTEXT_R15], r15
+LOCAL_LABEL(Done_CONTEXT_INTEGER):
+
+ test BYTE PTR [rdi + CONTEXT_ContextFlags], CONTEXT_CONTROL
+ je LOCAL_LABEL(Done_CONTEXT_CONTROL)
+
+ // Return address is @ (RSP + 8)
+ mov rdx, [rsp + 8]
+ mov [rdi + CONTEXT_Rip], rdx
+.att_syntax
+ mov %cs, CONTEXT_SegCs(%rdi)
+.intel_syntax noprefix
+ // Get the value of EFlags that was pushed on stack at the beginning of the function
+ mov rdx, [rsp]
+ mov [rdi + CONTEXT_EFlags], edx
+ lea rdx, [rsp + 16]
+ mov [rdi + CONTEXT_Rsp], rdx
+.att_syntax
+ mov %ss, CONTEXT_SegSs(%rdi)
+.intel_syntax noprefix
+LOCAL_LABEL(Done_CONTEXT_CONTROL):
+
+ // Need to double check this is producing the right result
+ // also that FFSXR (fast save/restore) is not turned on
+ // otherwise it omits the xmm registers.
+ test BYTE PTR [rdi + CONTEXT_ContextFlags], CONTEXT_FLOATING_POINT
+ je LOCAL_LABEL(Done_CONTEXT_FLOATING_POINT)
+ fxsave [rdi + CONTEXT_FltSave]
+LOCAL_LABEL(Done_CONTEXT_FLOATING_POINT):
+
+ test BYTE PTR [rdi + CONTEXT_ContextFlags], CONTEXT_DEBUG_REGISTERS
+ je LOCAL_LABEL(Done_CONTEXT_DEBUG_REGISTERS)
+ mov rdx, dr0
+ mov [rdi + CONTEXT_Dr0], rdx
+ mov rdx, dr1
+ mov [rdi + CONTEXT_Dr1], rdx
+ mov rdx, dr2
+ mov [rdi + CONTEXT_Dr2], rdx
+ mov rdx, dr3
+ mov [rdi + CONTEXT_Dr3], rdx
+ mov rdx, dr6
+ mov [rdi + CONTEXT_Dr6], rdx
+ mov rdx, dr7
+ mov [rdi + CONTEXT_Dr7], rdx
+LOCAL_LABEL(Done_CONTEXT_DEBUG_REGISTERS):
+
+ free_stack 8
+ ret
+LEAF_END CONTEXT_CaptureContext, _TEXT
+
+LEAF_ENTRY RtlCaptureContext, _TEXT
+ mov DWORD PTR [rdi + CONTEXT_ContextFlags], (CONTEXT_AMD64 | CONTEXT_FULL | CONTEXT_SEGMENTS)
+ jmp C_FUNC(CONTEXT_CaptureContext)
+LEAF_END RtlCaptureContext, _TEXT
+
+LEAF_ENTRY RtlRestoreContext, _TEXT
+ push_nonvol_reg rbp
+ alloc_stack (IRetFrameLengthAligned)
+
+ test BYTE PTR [rdi + CONTEXT_ContextFlags], CONTEXT_DEBUG_REGISTERS
+ je LOCAL_LABEL(Done_Restore_CONTEXT_DEBUG_REGISTERS)
+ mov rdx, [rdi + CONTEXT_Dr0]
+ mov dr0, rdx
+ mov rdx, [rdi + CONTEXT_Dr1]
+ mov dr1, rdx
+ mov rdx, [rdi + CONTEXT_Dr2]
+ mov dr2, rdx
+ mov rdx, [rdi + CONTEXT_Dr3]
+ mov dr3, rdx
+ mov rdx, [rdi + CONTEXT_Dr6]
+ mov dr6, rdx
+ mov rdx, [rdi + CONTEXT_Dr7]
+ mov dr7, rdx
+LOCAL_LABEL(Done_Restore_CONTEXT_DEBUG_REGISTERS):
+
+ test BYTE PTR [rdi + CONTEXT_ContextFlags], CONTEXT_FLOATING_POINT
+ je LOCAL_LABEL(Done_Restore_CONTEXT_FLOATING_POINT)
+ fxrstor [rdi + CONTEXT_FltSave]
+LOCAL_LABEL(Done_Restore_CONTEXT_FLOATING_POINT):
+
+ test BYTE PTR [rdi + CONTEXT_ContextFlags], CONTEXT_XSTATE
+ je LOCAL_LABEL(Done_Restore_CONTEXT_XSTATE)
+
+ // Restore the extended state (for now, this is just the upper halves of YMM registers)
+ vinsertf128 ymm0, ymm0, xmmword ptr [rdi + (CONTEXT_VectorRegister + 0 * 16)], 1
+ vinsertf128 ymm1, ymm1, xmmword ptr [rdi + (CONTEXT_VectorRegister + 1 * 16)], 1
+ vinsertf128 ymm2, ymm2, xmmword ptr [rdi + (CONTEXT_VectorRegister + 2 * 16)], 1
+ vinsertf128 ymm3, ymm3, xmmword ptr [rdi + (CONTEXT_VectorRegister + 3 * 16)], 1
+ vinsertf128 ymm4, ymm4, xmmword ptr [rdi + (CONTEXT_VectorRegister + 4 * 16)], 1
+ vinsertf128 ymm5, ymm5, xmmword ptr [rdi + (CONTEXT_VectorRegister + 5 * 16)], 1
+ vinsertf128 ymm6, ymm6, xmmword ptr [rdi + (CONTEXT_VectorRegister + 6 * 16)], 1
+ vinsertf128 ymm7, ymm7, xmmword ptr [rdi + (CONTEXT_VectorRegister + 7 * 16)], 1
+ vinsertf128 ymm8, ymm8, xmmword ptr [rdi + (CONTEXT_VectorRegister + 8 * 16)], 1
+ vinsertf128 ymm9, ymm9, xmmword ptr [rdi + (CONTEXT_VectorRegister + 9 * 16)], 1
+ vinsertf128 ymm10, ymm10, xmmword ptr [rdi + (CONTEXT_VectorRegister + 10 * 16)], 1
+ vinsertf128 ymm11, ymm11, xmmword ptr [rdi + (CONTEXT_VectorRegister + 11 * 16)], 1
+ vinsertf128 ymm12, ymm12, xmmword ptr [rdi + (CONTEXT_VectorRegister + 12 * 16)], 1
+ vinsertf128 ymm13, ymm13, xmmword ptr [rdi + (CONTEXT_VectorRegister + 13 * 16)], 1
+ vinsertf128 ymm14, ymm14, xmmword ptr [rdi + (CONTEXT_VectorRegister + 14 * 16)], 1
+ vinsertf128 ymm15, ymm15, xmmword ptr [rdi + (CONTEXT_VectorRegister + 15 * 16)], 1
+LOCAL_LABEL(Done_Restore_CONTEXT_XSTATE):
+
+ test BYTE PTR [rdi + CONTEXT_ContextFlags], CONTEXT_CONTROL
+ je LOCAL_LABEL(Done_Restore_CONTEXT_CONTROL)
+
+ // The control registers are restored via the iret instruction
+ // so we build the frame for the iret on the stack.
+#ifdef __APPLE__
+.att_syntax
+ // On OSX, we cannot read SS via the thread_get_context and RtlRestoreContext
+ // needs to be used on context extracted by thread_get_context. So we
+ // don't change the SS.
+ mov %ss, %ax
+.intel_syntax noprefix
+#else
+ mov ax, [rdi + CONTEXT_SegSs]
+#endif
+ mov [rsp + IRETFRAME_SegSs], ax
+ mov rax, [rdi + CONTEXT_Rsp]
+ mov [rsp + IRETFRAME_Rsp], rax
+ mov eax, [rdi + CONTEXT_EFlags]
+ mov [rsp + IRETFRAME_EFlags], eax
+ mov ax, [rdi + CONTEXT_SegCs]
+ mov [rsp + IRETFRAME_SegCs], ax
+ mov rax, [rdi + CONTEXT_Rip]
+ mov [rsp + IRETFRAME_Rip], rax
+
+LOCAL_LABEL(Done_Restore_CONTEXT_CONTROL):
+ // Remember the result of the test for the CONTEXT_CONTROL
+ push_eflags
+ test BYTE PTR [rdi + CONTEXT_ContextFlags], CONTEXT_INTEGER
+ je LOCAL_LABEL(Done_Restore_CONTEXT_INTEGER)
+ mov rsi, [rdi + CONTEXT_Rsi]
+ mov rbx, [rdi + CONTEXT_Rbx]
+ mov rdx, [rdi + CONTEXT_Rdx]
+ mov rcx, [rdi + CONTEXT_Rcx]
+ mov rax, [rdi + CONTEXT_Rax]
+ mov rbp, [rdi + CONTEXT_Rbp]
+ mov r8, [rdi + CONTEXT_R8]
+ mov r9, [rdi + CONTEXT_R9]
+ mov r10, [rdi + CONTEXT_R10]
+ mov r11, [rdi + CONTEXT_R11]
+ mov r12, [rdi + CONTEXT_R12]
+ mov r13, [rdi + CONTEXT_R13]
+ mov r14, [rdi + CONTEXT_R14]
+ mov r15, [rdi + CONTEXT_R15]
+ mov rdi, [rdi + CONTEXT_Rdi]
+LOCAL_LABEL(Done_Restore_CONTEXT_INTEGER):
+
+ // Restore the result of the test for the CONTEXT_CONTROL
+ pop_eflags
+ je LOCAL_LABEL(No_Restore_CONTEXT_CONTROL)
+ // The function was asked to restore the control registers, so
+ // we perform iretq that restores them all.
+ // We don't return to the caller in this case.
+ iretq
+LOCAL_LABEL(No_Restore_CONTEXT_CONTROL):
+
+ // The function was not asked to restore the control registers
+ // so we return back to the caller.
+ free_stack (IRetFrameLengthAligned)
+ pop_nonvol_reg rbp
+ ret
+LEAF_END RtlRestoreContext, _TEXT
+
+#else
+
+ .globl C_FUNC(CONTEXT_CaptureContext)
+C_FUNC(CONTEXT_CaptureContext):
+ push %eax
+ mov 8(%esp), %eax
+ mov %edi, CONTEXT_Edi(%eax)
+ mov %esi, CONTEXT_Esi(%eax)
+ mov %ebx, CONTEXT_Ebx(%eax)
+ mov %edx, CONTEXT_Edx(%eax)
+ mov %ecx, CONTEXT_Ecx(%eax)
+ pop %ecx
+ mov %ecx, CONTEXT_Eax(%eax)
+ mov %ebp, CONTEXT_Ebp(%eax)
+ mov (%esp), %edx
+ mov %edx, CONTEXT_Eip(%eax)
+ push %cs
+ pop %edx
+ mov %edx, CONTEXT_SegCs(%eax)
+ pushf
+ pop %edx
+ mov %edx, CONTEXT_EFlags(%eax)
+ lea 4(%esp), %edx
+ mov %edx, CONTEXT_Esp(%eax)
+ push %ss
+ pop %edx
+ mov %edx, CONTEXT_SegSs(%eax)
+ testb $CONTEXT_FLOATING_POINT, CONTEXT_ContextFlags(%eax)
+ je 0f
+ fnsave CONTEXT_FloatSave(%eax)
+ frstor CONTEXT_FloatSave(%eax)
+0:
+ testb $CONTEXT_EXTENDED_REGISTERS, CONTEXT_ContextFlags(%eax)
+ je 2f
+ movdqu %xmm0, CONTEXT_Xmm0(%eax)
+ movdqu %xmm1, CONTEXT_Xmm1(%eax)
+ movdqu %xmm2, CONTEXT_Xmm2(%eax)
+ movdqu %xmm3, CONTEXT_Xmm3(%eax)
+ movdqu %xmm4, CONTEXT_Xmm4(%eax)
+ movdqu %xmm5, CONTEXT_Xmm5(%eax)
+ movdqu %xmm6, CONTEXT_Xmm6(%eax)
+ movdqu %xmm7, CONTEXT_Xmm7(%eax)
+2:
+ ret
+
+#endif
diff --git a/src/pal/src/arch/i386/debugbreak.S b/src/pal/src/arch/i386/debugbreak.S
new file mode 100644
index 0000000000..3065e4064c
--- /dev/null
+++ b/src/pal/src/arch/i386/debugbreak.S
@@ -0,0 +1,12 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+.intel_syntax noprefix
+#include "unixasmmacros.inc"
+
+LEAF_ENTRY DBG_DebugBreak, _TEXT
+ int3
+ ret
+LEAF_END_MARKED DBG_DebugBreak, _TEXT
+
diff --git a/src/pal/src/arch/i386/dispatchexceptionwrapper.S b/src/pal/src/arch/i386/dispatchexceptionwrapper.S
new file mode 100644
index 0000000000..ee5ff468d6
--- /dev/null
+++ b/src/pal/src/arch/i386/dispatchexceptionwrapper.S
@@ -0,0 +1,51 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+// ==++==
+//
+
+// ==--==
+//
+// Implementation of the PAL_DispatchExceptionWrapper that is
+// interposed between a function that caused a hardware fault
+// and PAL_DispatchException that throws an SEH exception for
+// the fault, to make the stack unwindable.
+//
+
+.intel_syntax noprefix
+#include "unixasmmacros.inc"
+
+// Offset of the return address from the PAL_DispatchException in the PAL_DispatchExceptionWrapper
+.globl C_FUNC(PAL_DispatchExceptionReturnOffset)
+C_FUNC(PAL_DispatchExceptionReturnOffset):
+ .int LOCAL_LABEL(PAL_DispatchExceptionReturn) - C_FUNC(PAL_DispatchExceptionWrapper)
+
+//
+// PAL_DispatchExceptionWrapper will never be called; it only serves
+// to be referenced from a stack frame on the faulting thread. Its
+// unwinding behavior is equivalent to any standard function having
+// an ebp frame. It is analogous to the following source file.
+//
+// extern "C" void PAL_DispatchException(CONTEXT *pContext, EXCEPTION_RECORD *pExceptionRecord, MachExceptionInfo *pMachExceptionInfo);
+//
+// extern "C" void PAL_DispatchExceptionWrapper()
+// {
+// CONTEXT Context;
+// EXCEPTION_RECORD ExceptionRecord;
+// MachExceptionInfo MachExceptionInfo;
+// PAL_DispatchException(&Context, &ExceptionRecord, &MachExceptionInfo);
+// }
+//
+
+NESTED_ENTRY PAL_DispatchExceptionWrapper, _TEXT, NoHandler
+ push_nonvol_reg rbp
+ mov rbp, rsp
+ set_cfa_register rbp, (2*8)
+ int3
+ call C_FUNC(PAL_DispatchException)
+LOCAL_LABEL(PAL_DispatchExceptionReturn):
+ int3
+ pop_nonvol_reg rbp
+ ret
+NESTED_END PAL_DispatchExceptionWrapper, _TEXT
diff --git a/src/pal/src/arch/i386/exceptionhelper.S b/src/pal/src/arch/i386/exceptionhelper.S
new file mode 100644
index 0000000000..b7b34ace41
--- /dev/null
+++ b/src/pal/src/arch/i386/exceptionhelper.S
@@ -0,0 +1,42 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+.intel_syntax noprefix
+#include "unixasmmacros.inc"
+#include "asmconstants.h"
+
+//////////////////////////////////////////////////////////////////////////
+//
+// This function creates a stack frame right below the target frame, restores all callee
+// saved registers from the passed in context, sets the RSP to that frame and sets the
+// return address to the target frame's RIP.
+// Then it uses the ThrowExceptionHelper to throw the passed in exception from that context.
+// EXTERN_C void ThrowExceptionFromContextInternal(CONTEXT* context, PAL_SEHException* ex);
+LEAF_ENTRY ThrowExceptionFromContextInternal, _TEXT
+ // Save the RBP to the stack so that the unwind can work at the instruction after
+ // loading the RBP from the context, but before loading the RSP from the context.
+ push_nonvol_reg rbp
+ mov r12, [rdi + CONTEXT_R12]
+ mov r13, [rdi + CONTEXT_R13]
+ mov r14, [rdi + CONTEXT_R14]
+ mov r15, [rdi + CONTEXT_R15]
+ mov rbx, [rdi + CONTEXT_Rbx]
+ mov rbp, [rdi + CONTEXT_Rbp]
+ mov rsp, [rdi + CONTEXT_Rsp]
+ // The RSP was set to the target frame's value, so the current function's
+ // CFA is now right at the RSP.
+ .cfi_def_cfa_offset 0
+
+ // Indicate that now that we have moved the RSP to the target address,
+ // the RBP is no longer saved in the current stack frame.
+ .cfi_restore rbp
+
+ mov rax, [rdi + CONTEXT_Rip]
+
+ // Store return address to the stack
+ push_register rax
+ // The PAL_SEHException pointer
+ mov rdi, rsi
+ jmp EXTERNAL_C_FUNC(ThrowExceptionHelper)
+LEAF_END ThrowExceptionFromContextInternal, _TEXT
diff --git a/src/pal/src/arch/i386/optimizedtls.cpp b/src/pal/src/arch/i386/optimizedtls.cpp
new file mode 100644
index 0000000000..910a6eb931
--- /dev/null
+++ b/src/pal/src/arch/i386/optimizedtls.cpp
@@ -0,0 +1,237 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ optimizedtls.cpp
+
+Abstract:
+
+ Implementation of platform-specific Thread local storage functions.
+
+
+
+--*/
+
+#include "pal/thread.hpp"
+#include "pal/malloc.hpp"
+
+#include <pthread.h>
+
+#include "pal/dbgmsg.h"
+#include "pal/misc.h"
+#include "pal/debug.h"
+
+#include <stddef.h>
+
+using namespace CorUnix;
+
+SET_DEFAULT_DEBUG_CHANNEL(THREAD);
+
+#if defined(USE_OPTIMIZEDTLSGETTER)
+
+#define PAL_safe_offsetof(s,m) ((size_t)((ptrdiff_t)&(char&)(((s *)64)->m))-64)
+
+/*++
+Function:
+ CorUnix::TLSMakeOptimizedGetter
+
+ Creates a platform-optimized version of TlsGetValue compiled
+ for a particular index.
+
+ Generates the hot part of CorUnix::InternalGetCurrentThread
+ as a chunk of highly optimized machine-specific code at runtime.
+
+ Check the difference between CorUnix::InternalGetCurrentThread and
+ CorUnix::InternalGetCurrentThreadSlow to see the C/C++ code that matches
+ the code generated by this function.
+--*/
+PAL_POPTIMIZEDTLSGETTER
+CorUnix::TLSMakeOptimizedGetter(
+ IN CPalThread* pThread,
+ IN DWORD dwTlsIndex)
+{
+#ifdef BIT64
+#pragma unused(pThread, dwTlsIndex)
+ ERROR("TLSMakeOptimizedGetter not rewritten for amd64 yet.");
+ return NULL;
+#else
+ PAL_POPTIMIZEDTLSGETTER Ret = NULL;
+ BYTE* p;
+ int i = 0;
+
+#ifdef __APPLE__
+#define TLS_OPTIMIZED_GETTER_SIZE 118
+#else
+#define TLS_OPTIMIZED_GETTER_SIZE 115
+#endif
+
+ p = (BYTE*)InternalMalloc(pThread, TLS_OPTIMIZED_GETTER_SIZE * sizeof(BYTE));
+
+ if (p == NULL)
+ {
+ return Ret;
+ }
+
+ // Need to preserve %ecx, %edx, and %esi registers as specified in
+ // GetThreadGeneric(void) in vm/i386/asmhelpers.s
+ p[i++] = 0x51; // push %ecx
+ p[i++] = 0x52; // push %edx
+ p[i++] = 0x89; // mov %esp,%eax // %eax = sp;
+ p[i++] = 0xe0;
+ p[i++] = 0xc1; // shr $0x11,%eax // sp >> 17;
+ p[i++] = 0xe8;
+ p[i++] = 0x11;
+ p[i++] = 0x89; // mov %eax,%edx // key = sp >> 17;
+ p[i++] = 0xc2;
+ p[i++] = 0xc1; // sar $0x7,%edx // key >> 7;
+ p[i++] = 0xfa;
+ p[i++] = 0x07;
+ p[i++] = 0x29; // sub %edx,%eax // key -= key >> 7;
+ p[i++] = 0xd0;
+ p[i++] = 0x89; // mov %eax,%edx
+ p[i++] = 0xc2;
+ p[i++] = 0xc1; // sar $0x5,%edx // key >> 5;
+ p[i++] = 0xfa;
+ p[i++] = 0x05;
+ p[i++] = 0x29; // sub %edx,%eax // key -= key >> 5;
+ p[i++] = 0xd0;
+ p[i++] = 0x89; // mov %eax,%edx
+ p[i++] = 0xc2;
+ p[i++] = 0xc1; // sar $0x3,%edx // key >> 3;
+ p[i++] = 0xfa;
+ p[i++] = 0x03;
+ p[i++] = 0x29; // sub %edx,%eax // key -= key >> 3;
+ p[i++] = 0xd0;
+ p[i++] = 0x25; // and $0xff,%eax // key &= 0xFF;
+ p[i++] = 0xff;
+ p[i++] = 0x00;
+ p[i++] = 0x00;
+ p[i++] = 0x00;
+ p[i++] = 0x8b; // mov (flush_counter),%ecx // %ecx = counter = flush_counter;
+ p[i++] = 0x0d;
+ *((DWORD*) &p[i]) = (DWORD)&flush_counter;
+ i += sizeof(DWORD);
+ p[i++] = 0x8b; // mov (thread_hints,%eax,4),%eax // %edx = pThread = thread_hints[key];
+ p[i++] = 0x14;
+ p[i++] = 0x85;
+ *((DWORD*) &p[i]) = (DWORD)&thread_hints;
+ i += sizeof(DWORD);
+ p[i++] = 0x39; // cmp %esp,offsetof(CPalThread,tlsInfo)+offsetof(CThreadTLSInfo,minStack)(%edx)
+ // if ((size_t)pThread->tlsInfo.minStack <= sp)
+ p[i++] = 0xa2;
+ *((DWORD*) &p[i]) = (DWORD)(PAL_safe_offsetof(CPalThread,tlsInfo)+PAL_safe_offsetof(CThreadTLSInfo,minStack));
+ i += sizeof(DWORD);
+ p[i++] = 0x77; // ja CallInternalGetCurrentThreadSlow:
+ p[i++] = 0x19;
+ p[i++] = 0x3b; // cmp offsetof(CPalThread,tlsInfo)+offsetof(CThreadTLSInfo,maxStack)(%edx),%esp
+ // if (sp < (size_t)pThread->tlsInfo.maxStack)
+ p[i++] = 0xa2;
+ *((DWORD*) &p[i]) = (DWORD)(PAL_safe_offsetof(CPalThread,tlsInfo)+PAL_safe_offsetof(CThreadTLSInfo,maxStack));
+ i += sizeof(DWORD);
+ p[i++] = 0x73; // jae CallInternalGetCurrentThreadSlow:
+ p[i++] = 0x11;
+ p[i++] = 0x39; // cmp (flush_counter),%ecx // if (counter == flush_counter)
+ p[i++] = 0x0d;
+ *((DWORD*) &p[i]) = (DWORD)&flush_counter;
+ i += sizeof(DWORD);
+ p[i++] = 0x75; // jne CallInternalGetCurrentThreadSlow:
+ p[i++] = 0x09;
+ if (dwTlsIndex != THREAD_OBJECT_TLS_INDEX)
+ {
+ p[i++] = 0x8b; // mov offsetof(pThread->tlsSlots[dwTlsIndex])(%edx),%eax // %eax = pThread->tlsSlots[dwTlsIndex];
+ p[i++] = 0x82;
+ *((DWORD*) &p[i]) = (DWORD)(PAL_safe_offsetof(CPalThread,tlsInfo)+PAL_safe_offsetof(CThreadTLSInfo,tlsSlots[dwTlsIndex]));
+ i += sizeof(DWORD);
+ }
+ else
+ {
+ p[i++] = 0x89; // mov %edx,%eax // %eax = pThread;
+ p[i++] = 0xd0;
+ p[i++] = 0x90; // nop
+ p[i++] = 0x90; // nop
+ p[i++] = 0x90; // nop
+ p[i++] = 0x90; // nop
+ }
+ p[i++] = 0x5a; // pop %edx
+ p[i++] = 0x59; // pop %ecx
+ p[i++] = 0xc3; // ret
+ // CallInternalGetCurrentThreadSlow:
+ p[i++] = 0x5a; // pop %edx
+ p[i++] = 0x59; // pop %ecx
+ p[i++] = 0x8d; // lea (thread_hints,%eax,4),%eax // %eax = &thread_hints[key];
+ p[i++] = 0x04;
+ p[i++] = 0x85;
+ *((DWORD*) &p[i]) = (DWORD)&thread_hints;
+ i += sizeof(DWORD);
+ p[i++] = 0x55; // push %ebp
+ p[i++] = 0x89; // mov %esp,%ebp
+ p[i++] = 0xe5;
+ p[i++] = 0x51; // push %ecx
+ p[i++] = 0x89; // mov %esp,%ecx // this is the reference esp - need to match the reference esp used in the fast path.
+ p[i++] = 0xe1;
+ p[i++] = 0x52; // push %edx
+#ifdef __APPLE__
+ // establish 16-byte stack alignment
+ p[i++] = 0x83; // subl $8,%esp
+ p[i++] = 0xec;
+ p[i++] = 0x08;
+#endif
+ p[i++] = 0x50; // push %eax // store &thread_hints[key] on stack as 2nd argument;
+ p[i++] = 0x51; // push %ecx // reference esp - The 1st argument for call to InternalGetCurrentThreadSlow.
+ p[i++] = 0xe8; // call InternalGetCurrentThreadSlow
+ *((DWORD*) &p[i]) = (DWORD)&InternalGetCurrentThreadSlow - (DWORD)(&p[i+sizeof(DWORD)]);
+ i += sizeof(DWORD);
+#ifdef __APPLE__
+ p[i++] = 0x83; // addl $16,%esp
+ p[i++] = 0xc4;
+ p[i++] = 0x10;
+#else
+ p[i++] = 0x83; // addl $8,%esp
+ p[i++] = 0xc4;
+ p[i++] = 0x08;
+#endif
+ if (dwTlsIndex != THREAD_OBJECT_TLS_INDEX)
+ {
+ p[i++] = 0x8b; // mov offsetof(pThread->tlsSlots[dwTlsIndex])(%eax),%eax // %eax = pThread->tlsSlots[dwTlsIndex];
+ p[i++] = 0x80;
+ *((DWORD*) &p[i]) = (DWORD)(PAL_safe_offsetof(CPalThread,tlsInfo)+PAL_safe_offsetof(CThreadTLSInfo,tlsSlots[dwTlsIndex]));
+ i += sizeof(DWORD);
+ }
+ p[i++] = 0x5a; // pop %edx
+ p[i++] = 0x59; // pop %ecx
+ p[i++] = 0xc9; // leave
+ p[i++] = 0xc3; // ret
+
+ if (i > TLS_OPTIMIZED_GETTER_SIZE)
+ {
+ ASSERT("Invalid TLS_OPTIMIZED_GETTER_SIZE %d\n", i);
+ }
+
+ DBG_FlushInstructionCache(p, TLS_OPTIMIZED_GETTER_SIZE * sizeof(BYTE));
+
+ Ret = (PAL_POPTIMIZEDTLSGETTER)p;
+
+ return Ret;
+#endif // BIT64 else
+}
+
+/*++
+Function:
+ TLSFreeOptimizedGetter
+
+ Frees a function created by MakeOptimizedTlsGetter().
+--*/
+VOID
+CorUnix::TLSFreeOptimizedGetter(
+ IN PAL_POPTIMIZEDTLSGETTER pOptimizedTlsGetter)
+{
+ InternalFree(InternalGetCurrentThread(), (void *)pOptimizedTlsGetter);
+}
+
+#endif // USE_OPTIMIZEDTLSGETTER
diff --git a/src/pal/src/arch/i386/processor.cpp b/src/pal/src/arch/i386/processor.cpp
new file mode 100644
index 0000000000..4fd3a4abc8
--- /dev/null
+++ b/src/pal/src/arch/i386/processor.cpp
@@ -0,0 +1,44 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ processor.cpp
+
+Abstract:
+
+ Implementation of processor related functions for the Intel x86/x64
+ platforms. These functions are processor dependent.
+
+
+
+--*/
+
+#include "pal/palinternal.h"
+
+/*++
+Function:
+YieldProcessor
+
+The YieldProcessor function signals to the processor to give resources
+to threads that are waiting for them. This macro is only effective on
+processors that support technology allowing multiple threads running
+on a single processor, such as Intel's Hyper-Threading technology.
+
+--*/
+void
+PALAPI
+YieldProcessor(
+ VOID)
+{
+ __asm__ __volatile__ (
+ "rep\n"
+ "nop"
+ );
+}
+
diff --git a/src/pal/src/build_tools/mdtool_dummy b/src/pal/src/build_tools/mdtool_dummy
new file mode 100644
index 0000000000..1005a3496f
--- /dev/null
+++ b/src/pal/src/build_tools/mdtool_dummy
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+echo mdtool_dummy : not generating any dependencies
diff --git a/src/pal/src/build_tools/mdtool_gcc.in b/src/pal/src/build_tools/mdtool_gcc.in
new file mode 100644
index 0000000000..bef95d5cce
--- /dev/null
+++ b/src/pal/src/build_tools/mdtool_gcc.in
@@ -0,0 +1,43 @@
+#!/bin/sh
+
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+#
+# mdtool_gcc
+#
+#Abstract:
+# Generates dependencies for a makefile
+# (for gcc compilers)
+#
+
+str=`grep -n '#mdtool output goes here>' obj${BUILD_ALT_DIR}/${_BUILDARCH}/makefile`
+if [ "$str" = "" ] ; then
+#didn't find our placeholder string : don't change file
+ echo mdtool_gcc : makefile not setup for mdtool : ignoring
+ exit 0
+fi
+
+#truncate makefile to remove old dependencies
+sed /'#mdtool output goes here>'/q obj${BUILD_ALT_DIR}/${_BUILDARCH}/makefile > obj${BUILD_ALT_DIR}/${_BUILDARCH}/makefile.final
+
+echo '#dependencies generated by mdtool_gcc :' >> obj${BUILD_ALT_DIR}/${_BUILDARCH}/makefile.final
+echo >> obj${BUILD_ALT_DIR}/${_BUILDARCH}/makefile.final
+# gcc -M generates make-friendly dependencies;
+# -MM ignores system includes (#include <file.h>)
+@CC@ @MDTOOL_CFLAGS@ $@ >> obj${BUILD_ALT_DIR}/${_BUILDARCH}/makefile.depfromgcc
+#Prepend ../.. to the source's filename
+#with some sed magic, since gcc doesn't do it for us.
+sed 's#: \(.*\)$#: ../../\1#g' obj${BUILD_ALT_DIR}/${_BUILDARCH}/makefile.depfromgcc > obj${BUILD_ALT_DIR}/${_BUILDARCH}/makefile.aftersed
+cat obj${BUILD_ALT_DIR}/${_BUILDARCH}/makefile.aftersed >> obj${BUILD_ALT_DIR}/${_BUILDARCH}/makefile.final
+
+if [ "$?" = "0" ] ; then
+ echo mdtool_gcc : dependencies generated
+ # replace old makefile by new one.
+ mv -f obj${BUILD_ALT_DIR}/${_BUILDARCH}/makefile.final obj${BUILD_ALT_DIR}/${_BUILDARCH}/makefile
+ rm -f obj${BUILD_ALT_DIR}/${_BUILDARCH}/makefile.aftersed
+ rm -f obj${BUILD_ALT_DIR}/${_BUILDARCH}/makefile.depfromgcc
+ exit 0
+fi
+exit 1
+
diff --git a/src/pal/src/config.h.in b/src/pal/src/config.h.in
new file mode 100644
index 0000000000..7a53c8cb5d
--- /dev/null
+++ b/src/pal/src/config.h.in
@@ -0,0 +1,155 @@
+#ifndef _PAL_CONFIG_H_INCLUDED
+#define _PAL_CONFIG_H_INCLUDED 1
+
+#cmakedefine01 HAVE_IEEEFP_H
+#cmakedefine01 HAVE_SYS_VMPARAM_H
+#cmakedefine01 HAVE_MACH_VM_TYPES_H
+#cmakedefine01 HAVE_MACH_VM_PARAM_H
+#cmakedefine01 HAVE_MACHINE_NPX_H
+#cmakedefine01 HAVE_MACHINE_REG_H
+#cmakedefine01 HAVE_MACHINE_VMPARAM_H
+#cmakedefine01 HAVE_PROCFS_H
+#cmakedefine01 HAVE_CRT_EXTERNS_H
+#cmakedefine01 HAVE_SYS_TIME_H
+#cmakedefine01 HAVE_PTHREAD_NP_H
+#cmakedefine01 HAVE_SYS_LWP_H
+#cmakedefine01 HAVE_LWP_H
+#cmakedefine01 HAVE_LIBUNWIND_H
+#cmakedefine01 HAVE_LIBUUID_H
+#cmakedefine01 HAVE_BSD_UUID_H
+#cmakedefine01 HAVE_RUNETYPE_H
+#cmakedefine01 HAVE_SYS_SYSCTL_H
+#cmakedefine01 HAVE_GNU_LIBNAMES_H
+
+#cmakedefine01 HAVE_KQUEUE
+#cmakedefine01 HAVE_GETPWUID_R
+#cmakedefine01 HAVE_PTHREAD_SUSPEND
+#cmakedefine01 HAVE_PTHREAD_SUSPEND_NP
+#cmakedefine01 HAVE_PTHREAD_CONTINUE
+#cmakedefine01 HAVE_PTHREAD_RESUME_NP
+#cmakedefine01 HAVE_PTHREAD_CONTINUE_NP
+#cmakedefine01 HAVE_PTHREAD_ATTR_GET_NP
+#cmakedefine01 HAVE_PTHREAD_GETATTR_NP
+#cmakedefine01 HAVE_PTHREAD_GETCPUCLOCKID
+#cmakedefine01 HAVE_PTHREAD_SIGQUEUE
+#cmakedefine01 HAVE_SIGRETURN
+#cmakedefine01 HAVE__THREAD_SYS_SIGRETURN
+#cmakedefine01 HAVE_COPYSIGN
+#cmakedefine01 HAVE_FSYNC
+#cmakedefine01 HAVE_FUTIMES
+#cmakedefine01 HAVE_UTIMES
+#cmakedefine01 HAVE_SYSCTL
+#cmakedefine01 HAVE_SYSCONF
+#cmakedefine01 HAVE_LOCALTIME_R
+#cmakedefine01 HAVE_GMTIME_R
+#cmakedefine01 HAVE_TIMEGM
+#cmakedefine01 HAVE__SNWPRINTF
+#cmakedefine01 HAVE_POLL
+#cmakedefine01 HAVE_STATVFS
+#cmakedefine01 HAVE_THREAD_SELF
+#cmakedefine01 HAVE__LWP_SELF
+#cmakedefine01 HAVE_MACH_THREADS
+#cmakedefine01 HAVE_MACH_EXCEPTIONS
+#cmakedefine01 HAVE_VM_ALLOCATE
+#cmakedefine01 HAVE_VM_READ
+#cmakedefine01 HAS_SYSV_SEMAPHORES
+#cmakedefine01 HAS_PTHREAD_MUTEXES
+#cmakedefine01 HAVE_TTRACE
+#cmakedefine HAVE_UNW_GET_SAVE_LOC
+#cmakedefine HAVE_UNW_GET_ACCESSORS
+
+#cmakedefine01 HAVE_STAT_TIMESPEC
+#cmakedefine01 HAVE_STAT_NSEC
+#cmakedefine01 HAVE_TM_GMTOFF
+
+#cmakedefine01 HAVE_BSD_REGS_T
+#cmakedefine01 HAVE_PT_REGS
+#cmakedefine01 HAVE_GREGSET_T
+#cmakedefine01 HAVE___GREGSET_T
+#cmakedefine01 HAVE_SIGINFO_T
+#cmakedefine01 HAVE_UCONTEXT_T
+#cmakedefine01 HAVE_PTHREAD_RWLOCK_T
+#cmakedefine01 HAVE_PRWATCH_T
+#cmakedefine SIZEOF_OFF_T @SIZEOF_OFF_T@
+
+#cmakedefine01 HAVE_YIELD_SYSCALL
+#cmakedefine01 HAVE_INFTIM
+#cmakedefine01 HAVE_CHAR_BIT
+#cmakedefine01 USER_H_DEFINES_DEBUG
+#cmakedefine01 HAVE__SC_PHYS_PAGES
+#cmakedefine01 HAVE__SC_AVPHYS_PAGES
+
+#cmakedefine01 REALPATH_SUPPORTS_NONEXISTENT_FILES
+#cmakedefine01 SSCANF_CANNOT_HANDLE_MISSING_EXPONENT
+#cmakedefine01 SSCANF_SUPPORT_ll
+#cmakedefine01 HAVE_LARGE_SNPRINTF_SUPPORT
+#cmakedefine01 HAVE_BROKEN_FIFO_SELECT
+#cmakedefine01 HAVE_BROKEN_FIFO_KEVENT
+#cmakedefine01 HAS_FTRUNCATE_LENGTH_ISSUE
+#cmakedefine01 HAVE_SCHED_GET_PRIORITY
+#cmakedefine01 HAVE_SCHED_GETCPU
+#cmakedefine01 HAVE_WORKING_GETTIMEOFDAY
+#cmakedefine01 HAVE_WORKING_CLOCK_GETTIME
+#cmakedefine01 HAVE_CLOCK_MONOTONIC
+#cmakedefine01 HAVE_CLOCK_MONOTONIC_COARSE
+#cmakedefine01 HAVE_MACH_ABSOLUTE_TIME
+#cmakedefine01 HAVE_CLOCK_THREAD_CPUTIME
+#cmakedefine01 STATVFS64_PROTOTYPE_BROKEN
+#cmakedefine01 HAVE_MMAP_DEV_ZERO
+#cmakedefine01 MMAP_ANON_IGNORES_PROTECTION
+#cmakedefine01 ONE_SHARED_MAPPING_PER_FILEREGION_PER_PROCESS
+#cmakedefine01 PTHREAD_CREATE_MODIFIES_ERRNO
+#cmakedefine01 SEM_INIT_MODIFIES_ERRNO
+#cmakedefine01 HAVE_PROCFS_CTL
+#cmakedefine01 HAVE_PROCFS_MAPS
+#cmakedefine01 HAVE_PROCFS_STAT
+#cmakedefine01 HAVE_PROCFS_STATUS
+#cmakedefine01 HAVE_COMPATIBLE_ACOS
+#cmakedefine01 HAVE_COMPATIBLE_ASIN
+#cmakedefine01 HAVE_COMPATIBLE_POW
+#cmakedefine01 HAVE_VALID_NEGATIVE_INF_POW
+#cmakedefine01 HAVE_VALID_POSITIVE_INF_POW
+#cmakedefine01 HAVE_COMPATIBLE_ATAN2
+#cmakedefine01 HAVE_COMPATIBLE_EXP
+#cmakedefine01 HAVE_COMPATIBLE_LOG
+#cmakedefine01 HAVE_COMPATIBLE_LOG10
+#cmakedefine01 UNGETC_NOT_RETURN_EOF
+#cmakedefine01 HAS_POSIX_SEMAPHORES
+#cmakedefine01 GETPWUID_R_SETS_ERRNO
+#cmakedefine01 FILE_OPS_CHECK_FERROR_OF_PREVIOUS_CALL
+
+#define PAL_THREAD_PRIORITY_MIN 0
+#define PAL_THREAD_PRIORITY_MAX 0
+
+#cmakedefine01 HAVE_COREFOUNDATION
+#cmakedefine01 HAVE__NSGETENVIRON
+#cmakedefine01 DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX
+#cmakedefine PAL_PTRACE(cmd, pid, addr, data) @PAL_PTRACE@
+#cmakedefine PAL_PT_ATTACH @PAL_PT_ATTACH@
+#cmakedefine PAL_PT_DETACH @PAL_PT_DETACH@
+#cmakedefine PAL_PT_READ_D @PAL_PT_READ_D@
+#cmakedefine PAL_PT_WRITE_D @PAL_PT_WRITE_D@
+#cmakedefine01 SYNCHMGR_SUSPENSION_SAFE_CONDITION_SIGNALING
+#cmakedefine01 ERROR_FUNC_FOR_GLOB_HAS_FIXED_PARAMS
+#cmakedefine01 HAS_FTRUNCATE_LENGTH_ISSUE
+#cmakedefine01 UNWIND_CONTEXT_IS_UCONTEXT_T
+#cmakedefine01 HAVE_FULLY_FEATURED_PTHREAD_MUTEXES
+#cmakedefine01 HAVE_FUNCTIONAL_PTHREAD_ROBUST_MUTEXES
+#cmakedefine BSD_REGS_STYLE(reg, RR, rr) @BSD_REGS_STYLE@
+#cmakedefine01 HAVE_SCHED_OTHER_ASSIGNABLE
+
+#define CHECK_TRACE_SPECIFIERS 0
+#define HAVE_GETHRTIME 0
+#define HAVE_LOWERCASE_ISO_NAME 0
+#define HAVE_READ_REAL_TIME 0
+#define HAVE_UNDERSCORE_ISO_NAME 0
+#define MKSTEMP64_IS_USED_INSTEAD_OF_MKSTEMP 0
+#define NEED_DLCOMPAT 0
+#define OPEN64_IS_USED_INSTEAD_OF_OPEN 0
+#define PAL_IGNORE_NORMAL_THREAD_PRIORITY 0
+#define SELF_SUSPEND_FAILS_WITH_NATIVE_SUSPENSION 0
+#define SET_SCHEDPARAM_NEEDS_PRIVS 0
+#define SIGWAIT_FAILS_WHEN_PASSED_FULL_SIGSET 0
+#define WRITE_0_BYTES_HANGS_TTY 0
+#define HAVE_FTRUNCATE_LARGE_LENGTH_SUPPORT 1
+#endif
diff --git a/src/pal/src/configure.cmake b/src/pal/src/configure.cmake
new file mode 100644
index 0000000000..cc38bc8541
--- /dev/null
+++ b/src/pal/src/configure.cmake
@@ -0,0 +1,1281 @@
+include(CheckCXXSourceCompiles)
+include(CheckCXXSourceRuns)
+include(CheckCXXSymbolExists)
+include(CheckFunctionExists)
+include(CheckIncludeFiles)
+include(CheckStructHasMember)
+include(CheckTypeSize)
+include(CheckLibraryExists)
+
+if(CMAKE_SYSTEM_NAME STREQUAL FreeBSD)
+ set(CMAKE_REQUIRED_INCLUDES /usr/local/include)
+elseif(CMAKE_SYSTEM_NAME STREQUAL SunOS)
+ set(CMAKE_REQUIRED_INCLUDES /opt/local/include)
+endif()
+if(NOT CMAKE_SYSTEM_NAME STREQUAL Darwin AND NOT CMAKE_SYSTEM_NAME STREQUAL FreeBSD AND NOT CMAKE_SYSTEM_NAME STREQUAL NetBSD)
+ set(CMAKE_REQUIRED_DEFINITIONS "-D_DEFAULT_SOURCE -D_POSIX_C_SOURCE=200809L")
+endif()
+
+list(APPEND CMAKE_REQUIRED_DEFINITIONS -D_FILE_OFFSET_BITS=64)
+
+check_include_files(ieeefp.h HAVE_IEEEFP_H)
+check_include_files(sys/vmparam.h HAVE_SYS_VMPARAM_H)
+check_include_files(mach/vm_types.h HAVE_MACH_VM_TYPES_H)
+check_include_files(mach/vm_param.h HAVE_MACH_VM_PARAM_H)
+check_include_files("sys/param.h;sys/types.h;machine/npx.h" HAVE_MACHINE_NPX_H)
+check_include_files("sys/param.h;sys/cdefs.h;machine/reg.h" HAVE_MACHINE_REG_H)
+check_include_files(machine/vmparam.h HAVE_MACHINE_VMPARAM_H)
+check_include_files(procfs.h HAVE_PROCFS_H)
+check_include_files(crt_externs.h HAVE_CRT_EXTERNS_H)
+check_include_files(sys/time.h HAVE_SYS_TIME_H)
+check_include_files(pthread_np.h HAVE_PTHREAD_NP_H)
+check_include_files(sys/lwp.h HAVE_SYS_LWP_H)
+check_include_files(lwp.h HAVE_LWP_H)
+check_include_files(libunwind.h HAVE_LIBUNWIND_H)
+check_include_files(runetype.h HAVE_RUNETYPE_H)
+check_include_files(lttng/tracepoint.h HAVE_LTTNG_TRACEPOINT_H)
+check_include_files(uuid/uuid.h HAVE_LIBUUID_H)
+check_include_files(sys/sysctl.h HAVE_SYS_SYSCTL_H)
+check_include_files(gnu/lib-names.h HAVE_GNU_LIBNAMES_H)
+
+check_function_exists(kqueue HAVE_KQUEUE)
+check_function_exists(getpwuid_r HAVE_GETPWUID_R)
+check_library_exists(pthread pthread_suspend "" HAVE_PTHREAD_SUSPEND)
+check_library_exists(pthread pthread_suspend_np "" HAVE_PTHREAD_SUSPEND_NP)
+check_library_exists(pthread pthread_continue "" HAVE_PTHREAD_CONTINUE)
+check_library_exists(pthread pthread_continue_np "" HAVE_PTHREAD_CONTINUE_NP)
+check_library_exists(pthread pthread_resume_np "" HAVE_PTHREAD_RESUME_NP)
+check_library_exists(pthread pthread_attr_get_np "" HAVE_PTHREAD_ATTR_GET_NP)
+check_library_exists(pthread pthread_getattr_np "" HAVE_PTHREAD_GETATTR_NP)
+check_library_exists(pthread pthread_getcpuclockid "" HAVE_PTHREAD_GETCPUCLOCKID)
+check_library_exists(pthread pthread_sigqueue "" HAVE_PTHREAD_SIGQUEUE)
+check_function_exists(sigreturn HAVE_SIGRETURN)
+check_function_exists(_thread_sys_sigreturn HAVE__THREAD_SYS_SIGRETURN)
+set(CMAKE_REQUIRED_LIBRARIES m)
+check_function_exists(copysign HAVE_COPYSIGN)
+set(CMAKE_REQUIRED_LIBRARIES)
+check_function_exists(fsync HAVE_FSYNC)
+check_function_exists(futimes HAVE_FUTIMES)
+check_function_exists(utimes HAVE_UTIMES)
+check_function_exists(sysctl HAVE_SYSCTL)
+check_function_exists(sysconf HAVE_SYSCONF)
+check_function_exists(localtime_r HAVE_LOCALTIME_R)
+check_function_exists(gmtime_r HAVE_GMTIME_R)
+check_function_exists(timegm HAVE_TIMEGM)
+check_function_exists(_snwprintf HAVE__SNWPRINTF)
+check_function_exists(poll HAVE_POLL)
+check_function_exists(statvfs HAVE_STATVFS)
+check_function_exists(thread_self HAVE_THREAD_SELF)
+check_function_exists(_lwp_self HAVE__LWP_SELF)
+check_function_exists(pthread_mach_thread_np HAVE_MACH_THREADS)
+check_function_exists(thread_set_exception_ports HAVE_MACH_EXCEPTIONS)
+check_function_exists(vm_allocate HAVE_VM_ALLOCATE)
+check_function_exists(vm_read HAVE_VM_READ)
+check_function_exists(directio HAVE_DIRECTIO)
+check_function_exists(semget HAS_SYSV_SEMAPHORES)
+check_function_exists(pthread_mutex_init HAS_PTHREAD_MUTEXES)
+check_function_exists(ttrace HAVE_TTRACE)
+set(CMAKE_REQUIRED_LIBRARIES unwind unwind-generic)
+check_cxx_source_compiles("
+#include <libunwind.h>
+
+int main(int argc, char **argv) {
+ unw_cursor_t cursor;
+ unw_save_loc_t saveLoc;
+ int reg = UNW_REG_IP;
+ unw_get_save_loc(&cursor, reg, &saveLoc);
+
+ return 0;
+}" HAVE_UNW_GET_SAVE_LOC)
+check_cxx_source_compiles("
+#include <libunwind.h>
+
+int main(int argc, char **argv) {
+ unw_addr_space_t as;
+ unw_get_accessors(as);
+
+ return 0;
+}" HAVE_UNW_GET_ACCESSORS)
+set(CMAKE_REQUIRED_LIBRARIES)
+
+check_struct_has_member ("struct stat" st_atimespec "sys/types.h;sys/stat.h" HAVE_STAT_TIMESPEC)
+check_struct_has_member ("struct stat" st_atimensec "sys/types.h;sys/stat.h" HAVE_STAT_NSEC)
+check_struct_has_member ("struct tm" tm_gmtoff time.h HAVE_TM_GMTOFF)
+check_struct_has_member ("ucontext_t" uc_mcontext.gregs[0] ucontext.h HAVE_GREGSET_T)
+check_struct_has_member ("ucontext_t" uc_mcontext.__gregs[0] ucontext.h HAVE___GREGSET_T)
+
+set(CMAKE_EXTRA_INCLUDE_FILES machine/reg.h)
+check_type_size("struct reg" BSD_REGS_T)
+set(CMAKE_EXTRA_INCLUDE_FILES)
+set(CMAKE_EXTRA_INCLUDE_FILES asm/ptrace.h)
+check_type_size("struct pt_regs" PT_REGS)
+set(CMAKE_EXTRA_INCLUDE_FILES)
+set(CMAKE_EXTRA_INCLUDE_FILES signal.h)
+check_type_size(siginfo_t SIGINFO_T)
+set(CMAKE_EXTRA_INCLUDE_FILES)
+set(CMAKE_EXTRA_INCLUDE_FILES ucontext.h)
+check_type_size(ucontext_t UCONTEXT_T)
+set(CMAKE_EXTRA_INCLUDE_FILES)
+set(CMAKE_EXTRA_INCLUDE_FILES pthread.h)
+check_type_size(pthread_rwlock_t PTHREAD_RWLOCK_T)
+set(CMAKE_EXTRA_INCLUDE_FILES)
+set(CMAKE_EXTRA_INCLUDE_FILE procfs.h)
+check_type_size(prwatch_t PRWATCH_T)
+set(CMAKE_EXTRA_INCLUDE_FILE)
+check_type_size(off_t SIZEOF_OFF_T)
+
+check_cxx_symbol_exists(SYS_yield sys/syscall.h HAVE_YIELD_SYSCALL)
+check_cxx_symbol_exists(INFTIM poll.h HAVE_INFTIM)
+check_cxx_symbol_exists(CHAR_BIT limits.h HAVE_CHAR_BIT)
+check_cxx_symbol_exists(_DEBUG sys/user.h USER_H_DEFINES_DEBUG)
+check_cxx_symbol_exists(_SC_PHYS_PAGES unistd.h HAVE__SC_PHYS_PAGES)
+check_cxx_symbol_exists(_SC_AVPHYS_PAGES unistd.h HAVE__SC_AVPHYS_PAGES)
+
+check_cxx_source_runs("
+#include <uuid.h>
+
+int main(void) {
+ uuid_t uuid;
+ uint32_t status;
+ uuid_create(&uuid, &status);
+ return 0;
+}" HAVE_BSD_UUID_H)
+
+check_cxx_source_runs("
+#include <sys/param.h>
+#include <stdlib.h>
+
+int main(void) {
+ char *path;
+#ifdef PATH_MAX
+ char resolvedPath[PATH_MAX];
+#elif defined(MAXPATHLEN)
+ char resolvedPath[MAXPATHLEN];
+#else
+ char resolvedPath[1024];
+#endif
+ path = realpath(\"a_nonexistent_file\", resolvedPath);
+ if (path == NULL) {
+ exit(1);
+ }
+ exit(0);
+}" REALPATH_SUPPORTS_NONEXISTENT_FILES)
+check_cxx_source_runs("
+#include <stdio.h>
+#include <stdlib.h>
+int main(void)
+{
+ long long n = 0;
+ sscanf(\"5000000000\", \"%qu\", &n);
+ exit (n != 5000000000);
+ }" SSCANF_SUPPORT_ll)
+check_cxx_source_runs("
+#include <stdio.h>
+#include <stdlib.h>
+
+int main()
+{
+ int ret;
+ float f = 0;
+ char * strin = \"12.34e\";
+
+ ret = sscanf (strin, \"%e\", &f);
+ if (ret <= 0)
+ exit (0);
+ exit(1);
+}" SSCANF_CANNOT_HANDLE_MISSING_EXPONENT)
+check_cxx_source_runs("
+#include <stdio.h>
+#include <stdlib.h>
+
+int main(void) {
+ char buf[256] = { 0 };
+ snprintf(buf, 0x7fffffff, \"%#x\", 0x12345678);
+ if (buf[0] == 0x0) {
+ exit(1);
+ }
+ exit(0);
+}" HAVE_LARGE_SNPRINTF_SUPPORT)
+check_cxx_source_runs("
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+int main(void) {
+ int fd, numFDs;
+ fd_set readFDs, writeFDs, exceptFDs;
+ struct timeval time = { 0 };
+ char * filename = NULL;
+
+ filename = (char *)malloc(L_tmpnam * sizeof(char)); /* ok to leak this at exit */
+ if (NULL == filename) {
+ exit(0);
+ }
+
+ /* On some platforms (e.g. HP-UX) the multithreading c-runtime does not
+ support the tmpnam(NULL) semantics, and it returns NULL. Therefore
+ we need to use the tmpnam(pbuffer) version.
+ */
+ if (NULL == tmpnam(filename)) {
+ exit(0);
+ }
+ if (mkfifo(filename, S_IRWXU) != 0) {
+ if (unlink(filename) != 0) {
+ exit(0);
+ }
+ if (mkfifo(filename, S_IRWXU) != 0) {
+ exit(0);
+ }
+ }
+ fd = open(filename, O_RDWR | O_NONBLOCK);
+ if (fd == -1) {
+ exit(0);
+ }
+
+ FD_ZERO(&readFDs);
+ FD_ZERO(&writeFDs);
+ FD_ZERO(&exceptFDs);
+ FD_SET(fd, &readFDs);
+ numFDs = select(fd + 1, &readFDs, &writeFDs, &exceptFDs, &time);
+
+ close(fd);
+ unlink(filename);
+
+ /* numFDs is zero if select() works correctly */
+ exit(numFD==0);
+}" HAVE_BROKEN_FIFO_SELECT)
+check_cxx_source_runs("
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/event.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+
+int main(void)
+{
+ int ikq;
+ int iRet;
+ int fd;
+ struct kevent ke, keChangeList;
+ struct timespec ts = { 0, 0 };
+
+ char * filename = NULL;
+
+ filename = (char *)malloc(L_tmpnam * sizeof(char)); /* ok to leak this at exit */
+ if (NULL == filename)
+ {
+ exit(1);
+ }
+
+ /* On some platforms (e.g. HP-UX) the multithreading c-runtime does not
+ support the tmpnam(NULL) semantics, and it returns NULL. Therefore
+ we need to use the tmpnam(pbuffer) version.
+ */
+ if (NULL == tmpnam(filename)) {
+ exit(0);
+ }
+ if (mkfifo(filename, S_IRWXU) != 0) {
+ if (unlink(filename) != 0) {
+ exit(0);
+ }
+ if (mkfifo(filename, S_IRWXU) != 0) {
+ exit(0);
+ }
+ }
+ fd = open(filename, O_RDWR | O_NONBLOCK);
+ if (fd == -1) {
+ exit(0);
+ }
+
+ EV_SET(&keChangeList, fd, EVFILT_READ, EV_ADD | EV_CLEAR, 0, 0, NULL);
+ ikq = kqueue();
+ iRet = kevent(ikq, &keChangeList, 1, &ke, 1, &ts);
+
+ close(fd);
+ unlink(filename);
+
+ /* iRet is zero is kevent() works correctly */
+ return(iRet==0);
+}" HAVE_BROKEN_FIFO_KEVENT)
+set(CMAKE_REQUIRED_LIBRARIES pthread)
+check_cxx_source_runs("
+#include <stdio.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <sched.h>
+
+int main(void)
+{
+ int policy;
+ struct sched_param schedParam;
+ int max_priority;
+ int min_priority;
+
+ if (0 != pthread_getschedparam(pthread_self(), &policy, &schedParam))
+ {
+ exit(1);
+ }
+
+ max_priority = sched_get_priority_max(policy);
+ min_priority = sched_get_priority_min(policy);
+
+ exit(-1 == max_priority || -1 == min_priority);
+}" HAVE_SCHED_GET_PRIORITY)
+set(CMAKE_REQUIRED_LIBRARIES pthread)
+check_cxx_source_runs("
+#include <stdlib.h>
+#include <sched.h>
+
+int main(void)
+{
+ if (sched_getcpu() >= 0)
+ {
+ exit(0);
+ }
+ exit(1);
+}" HAVE_SCHED_GETCPU)
+set(CMAKE_REQUIRED_LIBRARIES)
+check_cxx_source_runs("
+#include <stdlib.h>
+#include <time.h>
+#include <sys/time.h>
+
+int main()
+{
+ int ret;
+ struct timeval tv;
+ ret = gettimeofday(&tv, NULL);
+
+ exit(ret);
+}" HAVE_WORKING_GETTIMEOFDAY)
+check_cxx_source_runs("
+#include <stdlib.h>
+#include <time.h>
+#include <sys/time.h>
+
+int main()
+{
+ int ret;
+ struct timespec ts;
+ ret = clock_gettime(CLOCK_REALTIME, &ts);
+
+ exit(ret);
+}" HAVE_WORKING_CLOCK_GETTIME)
+check_cxx_source_runs("
+#include <stdlib.h>
+#include <time.h>
+#include <sys/time.h>
+
+int main()
+{
+ int ret;
+ struct timespec ts;
+ ret = clock_gettime(CLOCK_MONOTONIC, &ts);
+
+ exit(ret);
+}" HAVE_CLOCK_MONOTONIC)
+check_cxx_source_runs("
+#include <stdlib.h>
+#include <time.h>
+#include <sys/time.h>
+
+int main()
+{
+ int ret;
+ struct timespec ts;
+ ret = clock_gettime(CLOCK_MONOTONIC_COARSE, &ts);
+
+ exit(ret);
+}" HAVE_CLOCK_MONOTONIC_COARSE)
+check_cxx_source_runs("
+#include <stdlib.h>
+#include <mach/mach_time.h>
+
+int main()
+{
+ int ret;
+ mach_timebase_info_data_t timebaseInfo;
+ ret = mach_timebase_info(&timebaseInfo);
+ mach_absolute_time();
+ exit(ret);
+}" HAVE_MACH_ABSOLUTE_TIME)
+check_cxx_source_runs("
+#include <stdlib.h>
+#include <time.h>
+#include <sys/time.h>
+
+int main()
+{
+ int ret;
+ struct timespec ts;
+ ret = clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts);
+
+ exit(ret);
+}" HAVE_CLOCK_THREAD_CPUTIME)
+check_cxx_source_runs("
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+
+int main(void) {
+ int devzero;
+ void *retval;
+
+ devzero = open(\"/dev/zero\", O_RDWR);
+ if (-1 == devzero) {
+ exit(1);
+ }
+ retval = mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_SHARED, devzero, 0);
+ if (retval == (void *)-1) {
+ exit(1);
+ }
+ exit(0);
+}" HAVE_MMAP_DEV_ZERO)
+check_cxx_source_runs("
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#ifndef MAP_ANON
+#define MAP_ANON MAP_ANONYMOUS
+#endif
+
+void *handle_signal(int signal) {
+ /* If we reach this, we've crashed due to mmap honoring
+ PROT_NONE. */
+ _exit(1);
+}
+
+int main(void) {
+ int *ptr;
+ struct sigaction action;
+
+ ptr = (int *) mmap(NULL, getpagesize(), PROT_NONE,
+ MAP_ANON | MAP_PRIVATE, -1, 0);
+ if (ptr == (int *) MAP_FAILED) {
+ exit(0);
+ }
+ action.sa_handler = &handle_signal;
+ action.sa_flags = 0;
+ sigemptyset(&action.sa_mask);
+ if (sigaction(SIGBUS, &action, NULL) != 0) {
+ exit(0);
+ }
+ if (sigaction(SIGSEGV, &action, NULL) != 0) {
+ exit(0);
+ }
+ /* This will drop us into the signal handler if PROT_NONE
+ is honored. */
+ *ptr = 123;
+ exit(0);
+}" MMAP_ANON_IGNORES_PROTECTION)
+check_cxx_source_runs("
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+
+#define MEM_SIZE 1024
+
+int main(void)
+{
+ char * fname;
+ int fd;
+ int ret;
+ void * pAddr0, * pAddr1;
+
+ fname = (char *)malloc(MEM_SIZE);
+ if (!fname)
+ exit(1);
+ strcpy(fname, \"/tmp/name/multiplemaptestXXXXXX\");
+
+ fd = mkstemp(fname);
+ if (fd < 0)
+ exit(1);
+
+ ret = write (fd, (void *)fname, MEM_SIZE);
+ if (ret < 0)
+ exit(1);
+
+ pAddr0 = mmap(0, MEM_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ pAddr1 = mmap(0, MEM_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+
+ /* In theory we should look for (pAddr1 == MAP_FAILED) && (pAddr1 != MAP_FAILED)
+ but in case the first test also failed, i.e. we failed to run the test,
+ let's assume that the system might not allow multiple shared mapping of the
+ same file region in the same process. The code enabled in this case is
+ only a fall-back code path. In case the double mmap actually works, virtually
+ nothing will change and the normal code path will be executed */
+ if (pAddr1 == MAP_FAILED)
+ ret = 1;
+ else
+ ret = 0;
+
+ if (pAddr0)
+ munmap (pAddr0, MEM_SIZE);
+ if (pAddr1)
+ munmap (pAddr1, MEM_SIZE);
+ close(fd);
+ unlink(fname);
+ free(fname);
+
+ exit(ret != 1);
+}" ONE_SHARED_MAPPING_PER_FILEREGION_PER_PROCESS)
+set(CMAKE_REQUIRED_LIBRARIES pthread)
+check_cxx_source_runs("
+#include <errno.h>
+#include <pthread.h>
+#include <stdlib.h>
+
+void *start_routine(void *param) { return NULL; }
+
+int main() {
+ int result;
+ pthread_t tid;
+
+ errno = 0;
+ result = pthread_create(&tid, NULL, start_routine, NULL);
+ if (result != 0) {
+ exit(1);
+ }
+ if (errno != 0) {
+ exit(0);
+ }
+ exit(1);
+}" PTHREAD_CREATE_MODIFIES_ERRNO)
+set(CMAKE_REQUIRED_LIBRARIES)
+set(CMAKE_REQUIRED_LIBRARIES pthread)
+check_cxx_source_runs("
+#include <errno.h>
+#include <semaphore.h>
+#include <stdlib.h>
+
+int main() {
+ int result;
+ sem_t sema;
+
+ errno = 50;
+ result = sem_init(&sema, 0, 0);
+ if (result != 0)
+ {
+ exit(1);
+ }
+ if (errno != 50)
+ {
+ exit(0);
+ }
+ exit(1);
+}" SEM_INIT_MODIFIES_ERRNO)
+set(CMAKE_REQUIRED_LIBRARIES)
+check_cxx_source_runs("
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+
+int main(void) {
+ int fd;
+#ifdef PATH_MAX
+ char path[PATH_MAX];
+#elif defined(MAXPATHLEN)
+ char path[MAXPATHLEN];
+#else
+ char path[1024];
+#endif
+
+ sprintf(path, \"/proc/%u/ctl\", getpid());
+ fd = open(path, O_WRONLY);
+ if (fd == -1) {
+ exit(1);
+ }
+ exit(0);
+}" HAVE_PROCFS_CTL)
+set(CMAKE_REQUIRED_LIBRARIES)
+check_cxx_source_runs("
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+
+int main(void) {
+ int fd;
+#ifdef PATH_MAX
+ char path[PATH_MAX];
+#elif defined(MAXPATHLEN)
+ char path[MAXPATHLEN];
+#else
+ char path[1024];
+#endif
+
+ sprintf(path, \"/proc/%u/maps\", getpid());
+ fd = open(path, O_RDONLY);
+ if (fd == -1) {
+ exit(1);
+ }
+ exit(0);
+}" HAVE_PROCFS_MAPS)
+set(CMAKE_REQUIRED_LIBRARIES)
+check_cxx_source_runs("
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+
+int main(void) {
+ int fd;
+#ifdef PATH_MAX
+ char path[PATH_MAX];
+#elif defined(MAXPATHLEN)
+ char path[MAXPATHLEN];
+#else
+ char path[1024];
+#endif
+
+ sprintf(path, \"/proc/%u/stat\", getpid());
+ fd = open(path, O_RDONLY);
+ if (fd == -1) {
+ exit(1);
+ }
+ exit(0);
+}" HAVE_PROCFS_STAT)
+set(CMAKE_REQUIRED_LIBRARIES)
+check_cxx_source_runs("
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+
+int main(void) {
+ int fd;
+#ifdef PATH_MAX
+ char path[PATH_MAX];
+#elif defined(MAXPATHLEN)
+ char path[MAXPATHLEN];
+#else
+ char path[1024];
+#endif
+
+ sprintf(path, \"/proc/%u/status\", getpid());
+ fd = open(path, O_RDONLY);
+ if (fd == -1) {
+ exit(1);
+ }
+ exit(0);
+}" HAVE_PROCFS_STATUS)
+set(CMAKE_REQUIRED_LIBRARIES m)
+check_cxx_source_runs("
+#include <math.h>
+#include <stdlib.h>
+
+int main(void) {
+ if (!isnan(acos(10))) {
+ exit(1);
+ }
+ exit(0);
+}" HAVE_COMPATIBLE_ACOS)
+set(CMAKE_REQUIRED_LIBRARIES)
+set(CMAKE_REQUIRED_LIBRARIES m)
+check_cxx_source_runs("
+#include <math.h>
+#include <stdlib.h>
+
+int main(void) {
+ if (!isnan(asin(10))) {
+ exit(1);
+ }
+ exit(0);
+}" HAVE_COMPATIBLE_ASIN)
+set(CMAKE_REQUIRED_LIBRARIES)
+set(CMAKE_REQUIRED_LIBRARIES m)
+check_cxx_source_runs("
+#include <math.h>
+#include <stdlib.h>
+
+int main(void) {
+ double infinity = 1.0 / 0.0;
+ if (pow(1.0, infinity) != 1.0 || pow(1.0, -infinity) != 1.0) {
+ exit(1)
+ }
+ if (!isnan(pow(-1.0, infinity)) || !isnan(pow(-1.0, -infinity))) {
+ exit(1);
+ }
+ if (pow(0.0, infinity) != 0.0) {
+ exit(1);
+ }
+ if (pow(0.0, -infinity) != infinity) {
+ exit(1);
+ }
+ if (pow(-1.1, infinity) != infinity || pow(1.1, infinity) != infinity) {
+ exit(1);
+ }
+ if (pow(-1.1, -infinity) != 0.0 || pow(1.1, infinity) != 0.0) {
+ exit(1);
+ }
+ if (pow(-0.0, -1) != -infinity) {
+ exit(1);
+ }
+ if (pow(0.0, -1) != infinity) {
+ exit(1);
+ }
+ exit(0);
+}" HAVE_COMPATIBLE_POW)
+set(CMAKE_REQUIRED_LIBRARIES)
+set(CMAKE_REQUIRED_LIBRARIES m)
+check_cxx_source_runs("
+#include <math.h>
+#include <stdlib.h>
+
+int main(int argc, char **argv) {
+ double result;
+
+ result = pow(-3.2e-10, -5e14 + 1);
+ if (result != -1.0 / 0.0) {
+ exit(1);
+ }
+ exit(0);
+}" HAVE_VALID_NEGATIVE_INF_POW)
+set(CMAKE_REQUIRED_LIBRARIES)
+set(CMAKE_REQUIRED_LIBRARIES m)
+check_cxx_source_runs("
+#include <math.h>
+#include <stdlib.h>
+
+int main(int argc, char **argv) {
+ double result;
+
+ result = pow(-3.5, 3e100);
+ if (result != 1.0 / 0.0) {
+ exit(1);
+ }
+ exit(0);
+}" HAVE_VALID_POSITIVE_INF_POW)
+set(CMAKE_REQUIRED_LIBRARIES)
+set(CMAKE_REQUIRED_LIBRARIES m)
+check_cxx_source_runs("
+#include <math.h>
+#include <stdlib.h>
+
+int main(void) {
+ double pi = 3.14159265358979323846;
+ double result;
+
+ result = atan2(0.0, -0.0);
+ if (fabs(pi - result) > 0.0000001) {
+ exit(1);
+ }
+
+ result = atan2(-0.0, -0.0);
+ if (fabs(-pi - result) > 0.0000001) {
+ exit(1);
+ }
+
+ result = atan2 (-0.0, 0.0);
+ if (result != 0.0 || copysign (1.0, result) > 0) {
+ exit(1);
+ }
+
+ result = atan2 (0.0, 0.0);
+ if (result != 0.0 || copysign (1.0, result) < 0) {
+ exit(1);
+ }
+
+ exit (0);
+}" HAVE_COMPATIBLE_ATAN2)
+set(CMAKE_REQUIRED_LIBRARIES)
+set(CMAKE_REQUIRED_LIBRARIES m)
+check_cxx_source_runs("
+#include <math.h>
+#include <stdlib.h>
+
+int main(void) {
+ double d = exp(1.0), e = M_E;
+
+ /* Used memcmp rather than == to test that the doubles are equal to
+ prevent gcc's optimizer from using its 80 bit internal long
+ doubles. If you use ==, then on BSD you get a false negative since
+ exp(1.0) == M_E to 64 bits, but not 80.
+ */
+
+ if (memcmp (&d, &e, sizeof (double)) == 0) {
+ exit(0);
+ }
+ exit(1);
+}" HAVE_COMPATIBLE_EXP)
+set(CMAKE_REQUIRED_LIBRARIES)
+set(CMAKE_REQUIRED_LIBRARIES m)
+check_cxx_source_runs("
+#include <math.h>
+#include <stdlib.h>
+
+int main(void) {
+ if (!isnan(log(-10000))) {
+ exit(1);
+ }
+ exit(0);
+}" HAVE_COMPATIBLE_LOG)
+set(CMAKE_REQUIRED_LIBRARIES)
+set(CMAKE_REQUIRED_LIBRARIES m)
+check_cxx_source_runs("
+#include <math.h>
+#include <stdlib.h>
+
+int main(void) {
+ if (!isnan(log10(-10000))) {
+ exit(1);
+ }
+ exit(0);
+}" HAVE_COMPATIBLE_LOG10)
+set(CMAKE_REQUIRED_LIBRARIES)
+check_cxx_source_runs("
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+int main(void)
+{
+ char* szFileName;
+ FILE* pFile = NULL;
+ int ret = 1;
+
+ szFileName = tempnam(\".\", \"tmp\");
+
+ /* open the file write-only */
+ pFile = fopen(szFileName, \"a\");
+ if (pFile == NULL)
+ {
+ exit(0);
+ }
+ if (ungetc('A', pFile) != EOF)
+ {
+ ret = 0;
+ }
+ unlink(szFileName);
+ exit(ret);
+}" UNGETC_NOT_RETURN_EOF)
+set(CMAKE_REQUIRED_LIBRARIES pthread)
+check_cxx_source_runs("
+#include <stdlib.h>
+#include <errno.h>
+#include <semaphore.h>
+
+int main() {
+ sem_t sema;
+ if (sem_init(&sema, 0, 0) == -1){
+ exit(1);
+ }
+ exit(0);
+}" HAS_POSIX_SEMAPHORES)
+set(CMAKE_REQUIRED_LIBRARIES)
+check_cxx_source_runs("
+#include <sys/types.h>
+#include <pwd.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+int main(void)
+{
+ struct passwd sPasswd;
+ struct passwd *pPasswd;
+ char buf[1];
+ int bufLen = sizeof(buf)/sizeof(buf[0]);
+ int euid = geteuid();
+ int ret = 0;
+
+ errno = 0; // clear errno
+ ret = getpwuid_r(euid, &sPasswd, buf, bufLen, &pPasswd);
+ if (0 != ret)
+ {
+ if (ERANGE == errno)
+ {
+ return 0;
+ }
+ }
+
+ return 1; // assume errno is NOT set for all other cases
+}" GETPWUID_R_SETS_ERRNO)
+check_cxx_source_runs("
+#include <stdio.h>
+#include <stdlib.h>
+
+int main()
+{
+ FILE *fp = NULL;
+ char *fileName = \"/dev/zero\";
+ char buf[10];
+
+ /*
+ * Open the file in append mode and try to read some text.
+ * And, make sure ferror() is set.
+ */
+ fp = fopen (fileName, \"a\");
+ if ( (NULL == fp) ||
+ (fread (buf, sizeof(buf), 1, fp) > 0) ||
+ (!ferror(fp))
+ )
+ {
+ return 0;
+ }
+
+ /*
+ * Now that ferror() is set, try to close the file.
+ * If we get an error, we can conclude that this
+ * fgets() depended on the previous ferror().
+ */
+ if ( fclose(fp) != 0 )
+ {
+ return 0;
+ }
+
+ return 1;
+}" FILE_OPS_CHECK_FERROR_OF_PREVIOUS_CALL)
+set(CMAKE_REQUIRED_DEFINITIONS)
+
+set(SYNCHMGR_SUSPENSION_SAFE_CONDITION_SIGNALING 1)
+set(ERROR_FUNC_FOR_GLOB_HAS_FIXED_PARAMS 1)
+
+check_cxx_source_compiles("
+#include <libunwind.h>
+#include <ucontext.h>
+
+int main(int argc, char **argv)
+{
+ unw_context_t libUnwindContext;
+ ucontext_t uContext;
+
+ libUnwindContext = uContext;
+ return 0;
+}" UNWIND_CONTEXT_IS_UCONTEXT_T)
+
+set(CMAKE_REQUIRED_LIBRARIES pthread)
+check_cxx_source_compiles("
+#include <errno.h>
+#include <pthread.h>
+#include <time.h>
+
+int main()
+{
+ pthread_mutexattr_t mutexAttributes;
+ pthread_mutexattr_init(&mutexAttributes);
+ pthread_mutexattr_setpshared(&mutexAttributes, PTHREAD_PROCESS_SHARED);
+ pthread_mutexattr_settype(&mutexAttributes, PTHREAD_MUTEX_RECURSIVE);
+ pthread_mutexattr_setrobust(&mutexAttributes, PTHREAD_MUTEX_ROBUST);
+
+ pthread_mutex_t mutex;
+ pthread_mutex_init(&mutex, &mutexAttributes);
+
+ pthread_mutexattr_destroy(&mutexAttributes);
+
+ struct timespec timeoutTime;
+ timeoutTime.tv_sec = 1; // not the right way to specify absolute time, but just checking availability of timed lock
+ timeoutTime.tv_nsec = 0;
+ pthread_mutex_timedlock(&mutex, &timeoutTime);
+ pthread_mutex_consistent(&mutex);
+
+ pthread_mutex_destroy(&mutex);
+
+ int error = EOWNERDEAD;
+ error = ENOTRECOVERABLE;
+ error = ETIMEDOUT;
+ error = 0;
+ return error;
+}" HAVE_FULLY_FEATURED_PTHREAD_MUTEXES)
+set(CMAKE_REQUIRED_LIBRARIES)
+
+if(NOT CLR_CMAKE_PLATFORM_ARCH_ARM AND NOT CLR_CMAKE_PLATFORM_ARCH_ARM64)
+ set(CMAKE_REQUIRED_LIBRARIES pthread)
+ check_cxx_source_runs("
+ // This test case verifies the pthread process-shared robust mutex's cross-process abandon detection. The parent process starts
+ // a child process that locks the mutex, the process process then waits to acquire the lock, and the child process abandons the
+ // mutex by exiting the process while holding the lock. The parent process should then be released from its wait, be assigned
+ // ownership of the lock, and be notified that the mutex was abandoned.
+
+ #include <sys/mman.h>
+ #include <sys/time.h>
+
+ #include <errno.h>
+ #include <pthread.h>
+ #include <stdio.h>
+ #include <unistd.h>
+
+ #include <new>
+ using namespace std;
+
+ struct Shm
+ {
+ pthread_mutex_t syncMutex;
+ pthread_cond_t syncCondition;
+ pthread_mutex_t robustMutex;
+ int conditionValue;
+
+ Shm() : conditionValue(0)
+ {
+ }
+ } *shm;
+
+ int GetFailTimeoutTime(struct timespec *timeoutTimeRef)
+ {
+ int getTimeResult = clock_gettime(CLOCK_REALTIME, timeoutTimeRef);
+ if (getTimeResult != 0)
+ {
+ struct timeval tv;
+ getTimeResult = gettimeofday(&tv, NULL);
+ if (getTimeResult != 0)
+ return 1;
+ timeoutTimeRef->tv_sec = tv.tv_sec;
+ timeoutTimeRef->tv_nsec = tv.tv_usec * 1000;
+ }
+ timeoutTimeRef->tv_sec += 30;
+ return 0;
+ }
+
+ int WaitForConditionValue(int desiredConditionValue)
+ {
+ struct timespec timeoutTime;
+ if (GetFailTimeoutTime(&timeoutTime) != 0)
+ return 1;
+ if (pthread_mutex_timedlock(&shm->syncMutex, &timeoutTime) != 0)
+ return 1;
+
+ if (shm->conditionValue != desiredConditionValue)
+ {
+ if (GetFailTimeoutTime(&timeoutTime) != 0)
+ return 1;
+ if (pthread_cond_timedwait(&shm->syncCondition, &shm->syncMutex, &timeoutTime) != 0)
+ return 1;
+ if (shm->conditionValue != desiredConditionValue)
+ return 1;
+ }
+
+ if (pthread_mutex_unlock(&shm->syncMutex) != 0)
+ return 1;
+ return 0;
+ }
+
+ int SetConditionValue(int newConditionValue)
+ {
+ struct timespec timeoutTime;
+ if (GetFailTimeoutTime(&timeoutTime) != 0)
+ return 1;
+ if (pthread_mutex_timedlock(&shm->syncMutex, &timeoutTime) != 0)
+ return 1;
+
+ shm->conditionValue = newConditionValue;
+ if (pthread_cond_signal(&shm->syncCondition) != 0)
+ return 1;
+
+ if (pthread_mutex_unlock(&shm->syncMutex) != 0)
+ return 1;
+ return 0;
+ }
+
+ void DoTest_Child();
+
+ int DoTest()
+ {
+ // Map some shared memory
+ void *shmBuffer = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_SHARED, -1, 0);
+ if (shmBuffer == MAP_FAILED)
+ return 1;
+ shm = new(shmBuffer) Shm;
+
+ // Create sync mutex
+ pthread_mutexattr_t syncMutexAttributes;
+ if (pthread_mutexattr_init(&syncMutexAttributes) != 0)
+ return 1;
+ if (pthread_mutexattr_setpshared(&syncMutexAttributes, PTHREAD_PROCESS_SHARED) != 0)
+ return 1;
+ if (pthread_mutex_init(&shm->syncMutex, &syncMutexAttributes) != 0)
+ return 1;
+ if (pthread_mutexattr_destroy(&syncMutexAttributes) != 0)
+ return 1;
+
+ // Create sync condition
+ pthread_condattr_t syncConditionAttributes;
+ if (pthread_condattr_init(&syncConditionAttributes) != 0)
+ return 1;
+ if (pthread_condattr_setpshared(&syncConditionAttributes, PTHREAD_PROCESS_SHARED) != 0)
+ return 1;
+ if (pthread_cond_init(&shm->syncCondition, &syncConditionAttributes) != 0)
+ return 1;
+ if (pthread_condattr_destroy(&syncConditionAttributes) != 0)
+ return 1;
+
+ // Create the robust mutex that will be tested
+ pthread_mutexattr_t robustMutexAttributes;
+ if (pthread_mutexattr_init(&robustMutexAttributes) != 0)
+ return 1;
+ if (pthread_mutexattr_setpshared(&robustMutexAttributes, PTHREAD_PROCESS_SHARED) != 0)
+ return 1;
+ if (pthread_mutexattr_setrobust(&robustMutexAttributes, PTHREAD_MUTEX_ROBUST) != 0)
+ return 1;
+ if (pthread_mutex_init(&shm->robustMutex, &robustMutexAttributes) != 0)
+ return 1;
+ if (pthread_mutexattr_destroy(&robustMutexAttributes) != 0)
+ return 1;
+
+ // Start child test process
+ int error = fork();
+ if (error == -1)
+ return 1;
+ if (error == 0)
+ {
+ DoTest_Child();
+ return -1;
+ }
+
+ // Wait for child to take a lock
+ WaitForConditionValue(1);
+
+ // Wait to try to take a lock. Meanwhile, child abandons the robust mutex.
+ struct timespec timeoutTime;
+ if (GetFailTimeoutTime(&timeoutTime) != 0)
+ return 1;
+ error = pthread_mutex_timedlock(&shm->robustMutex, &timeoutTime);
+ if (error != EOWNERDEAD) // expect to be notified that the robust mutex was abandoned
+ return 1;
+ if (pthread_mutex_consistent(&shm->robustMutex) != 0)
+ return 1;
+
+ if (pthread_mutex_unlock(&shm->robustMutex) != 0)
+ return 1;
+ if (pthread_mutex_destroy(&shm->robustMutex) != 0)
+ return 1;
+ return 0;
+ }
+
+ void DoTest_Child()
+ {
+ // Lock the robust mutex
+ struct timespec timeoutTime;
+ if (GetFailTimeoutTime(&timeoutTime) != 0)
+ return;
+ if (pthread_mutex_timedlock(&shm->robustMutex, &timeoutTime) != 0)
+ return;
+
+ // Notify parent that robust mutex is locked
+ if (SetConditionValue(1) != 0)
+ return;
+
+ // Wait a short period to let the parent block on waiting for a lock
+ sleep(1);
+
+ // Abandon the mutex by exiting the process while holding the lock. Parent's wait should be released by EOWNERDEAD.
+ }
+
+ int main()
+ {
+ int result = DoTest();
+ return result >= 0 ? result : 0;
+ }" HAVE_FUNCTIONAL_PTHREAD_ROBUST_MUTEXES)
+ set(CMAKE_REQUIRED_LIBRARIES)
+endif()
+
+if(CMAKE_SYSTEM_NAME STREQUAL Darwin)
+ if(NOT HAVE_LIBUUID_H)
+ unset(HAVE_LIBUUID_H CACHE)
+ message(FATAL_ERROR "Cannot find libuuid. Try installing uuid-dev or the appropriate packages for your platform")
+ endif()
+ set(HAVE_COREFOUNDATION 1)
+ set(HAVE__NSGETENVIRON 1)
+ set(DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX 1)
+ set(PAL_PTRACE "ptrace((cmd), (pid), (caddr_t)(addr), (data))")
+ set(PAL_PT_ATTACH PT_ATTACH)
+ set(PAL_PT_DETACH PT_DETACH)
+ set(PAL_PT_READ_D PT_READ_D)
+ set(PAL_PT_WRITE_D PT_WRITE_D)
+ set(HAS_FTRUNCATE_LENGTH_ISSUE 1)
+ set(HAVE_SCHED_OTHER_ASSIGNABLE 1)
+
+elseif(CMAKE_SYSTEM_NAME STREQUAL FreeBSD)
+ if(NOT HAVE_LIBUNWIND_H)
+ unset(HAVE_LIBUNWIND_H CACHE)
+ message(FATAL_ERROR "Cannot find libunwind. Try installing libunwind8 and libunwind8-dev (or the appropriate packages for your platform)")
+ endif()
+ if(NOT HAVE_BSD_UUID_H)
+ unset(HAVE_BSD_UUID_H CACHE)
+ message(FATAL_ERROR "Cannot find uuid.h")
+ endif()
+ set(DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX 0)
+ set(PAL_PTRACE "ptrace((cmd), (pid), (caddr_t)(addr), (data))")
+ set(PAL_PT_ATTACH PT_ATTACH)
+ set(PAL_PT_DETACH PT_DETACH)
+ set(PAL_PT_READ_D PT_READ_D)
+ set(PAL_PT_WRITE_D PT_WRITE_D)
+ set(HAS_FTRUNCATE_LENGTH_ISSUE 0)
+ set(BSD_REGS_STYLE "((reg).r_##rr)")
+ set(HAVE_SCHED_OTHER_ASSIGNABLE 1)
+elseif(CMAKE_SYSTEM_NAME STREQUAL NetBSD)
+ if(NOT HAVE_LIBUNWIND_H)
+ unset(HAVE_LIBUNWIND_H CACHE)
+ message(FATAL_ERROR "Cannot find libunwind. Try installing libunwind8 and libunwind8-dev (or the appropriate packages for your platform)")
+ endif()
+ if(NOT HAVE_BSD_UUID_H)
+ unset(HAVE_BSD_UUID_H CACHE)
+ message(FATAL_ERROR "Cannot find uuid.h")
+ endif()
+ set(DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX 0)
+ set(PAL_PTRACE "ptrace((cmd), (pid), (void*)(addr), (data))")
+ set(PAL_PT_ATTACH PT_ATTACH)
+ set(PAL_PT_DETACH PT_DETACH)
+ set(PAL_PT_READ_D PT_READ_D)
+ set(PAL_PT_WRITE_D PT_WRITE_D)
+ set(HAS_FTRUNCATE_LENGTH_ISSUE 0)
+ set(BSD_REGS_STYLE "((reg).regs[_REG_##RR])")
+ set(HAVE_SCHED_OTHER_ASSIGNABLE 0)
+
+elseif(CMAKE_SYSTEM_NAME STREQUAL SunOS)
+ if(NOT HAVE_LIBUNWIND_H)
+ unset(HAVE_LIBUNWIND_H CACHE)
+ message(FATAL_ERROR "Cannot find libunwind. Try installing libunwind8 and libunwind8-dev (or the appropriate packages for your platform)")
+ endif()
+ if(NOT HAVE_LIBUUID_H)
+ unset(HAVE_LIBUUID_H CACHE)
+ message(FATAL_ERROR "Cannot find libuuid. Try installing uuid-dev or the appropriate packages for your platform")
+ endif()
+ set(DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX 0)
+ set(PAL_PTRACE "ptrace((cmd), (pid), (caddr_t)(addr), (data))")
+ set(PAL_PT_ATTACH PT_ATTACH)
+ set(PAL_PT_DETACH PT_DETACH)
+ set(PAL_PT_READ_D PT_READ_D)
+ set(PAL_PT_WRITE_D PT_WRITE_D)
+ set(HAS_FTRUNCATE_LENGTH_ISSUE 0)
+else() # Anything else is Linux
+ if(NOT HAVE_LIBUNWIND_H)
+ unset(HAVE_LIBUNWIND_H CACHE)
+ message(FATAL_ERROR "Cannot find libunwind. Try installing libunwind8 and libunwind8-dev (or the appropriate packages for your platform)")
+ endif()
+ if(NOT HAVE_LTTNG_TRACEPOINT_H AND FEATURE_EVENT_TRACE)
+ unset(HAVE_LTTNG_TRACEPOINT_H CACHE)
+ message(FATAL_ERROR "Cannot find liblttng-ust-dev. Try installing liblttng-ust-dev (or the appropriate packages for your platform)")
+ endif()
+ if(NOT HAVE_LIBUUID_H)
+ unset(HAVE_LIBUUID_H CACHE)
+ message(FATAL_ERROR "Cannot find libuuid. Try installing uuid-dev or the appropriate packages for your platform")
+ endif()
+ set(DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX 0)
+ set(PAL_PTRACE "ptrace((cmd), (pid), (void*)(addr), (data))")
+ set(PAL_PT_ATTACH PTRACE_ATTACH)
+ set(PAL_PT_DETACH PTRACE_DETACH)
+ set(PAL_PT_READ_D PTRACE_PEEKDATA)
+ set(PAL_PT_WRITE_D PTRACE_POKEDATA)
+ set(HAS_FTRUNCATE_LENGTH_ISSUE 0)
+ set(HAVE_SCHED_OTHER_ASSIGNABLE 1)
+endif(CMAKE_SYSTEM_NAME STREQUAL Darwin)
+
+configure_file(${CMAKE_CURRENT_SOURCE_DIR}/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h)
diff --git a/src/pal/src/cruntime/file.cpp b/src/pal/src/cruntime/file.cpp
new file mode 100644
index 0000000000..5fe2b671f3
--- /dev/null
+++ b/src/pal/src/cruntime/file.cpp
@@ -0,0 +1,954 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ file.c
+
+Abstract:
+
+ Implementation of the file functions in the C runtime library that
+ are Windows specific.
+
+
+
+--*/
+
+#include "pal/palinternal.h"
+#include "pal/dbgmsg.h"
+#include "pal/file.h"
+#include "pal/cruntime.h"
+
+#include "pal/thread.hpp"
+#include "pal/threadsusp.hpp"
+
+#include <unistd.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <pthread.h>
+
+#if FILE_OPS_CHECK_FERROR_OF_PREVIOUS_CALL
+ #define CLEARERR(f) clearerr((f)->bsdFilePtr)
+#else
+ #define CLEARERR(f)
+#endif
+
+SET_DEFAULT_DEBUG_CHANNEL(CRT);
+
+/* Global variables storing the std streams.*/
+PAL_FILE PAL_Stdout;
+PAL_FILE PAL_Stdin;
+PAL_FILE PAL_Stderr;
+
+/*++
+
+Function:
+
+ CRTInitStdStreams.
+
+ Initilizes the standard streams.
+ Returns TRUE on success, FALSE otherwise.
+--*/
+BOOL CRTInitStdStreams()
+{
+ /* stdout */
+ PAL_Stdout.bsdFilePtr = stdout;
+ PAL_Stdout.PALferrorCode = PAL_FILE_NOERROR;
+ PAL_Stdout.bTextMode = TRUE;
+
+ /* stdin */
+ PAL_Stdin.bsdFilePtr = stdin;
+ PAL_Stdin.PALferrorCode = PAL_FILE_NOERROR;
+ PAL_Stdin.bTextMode = TRUE;
+
+ /* stderr */
+ PAL_Stderr.bsdFilePtr = stderr;
+ PAL_Stderr.PALferrorCode = PAL_FILE_NOERROR;
+ PAL_Stderr.bTextMode = TRUE;
+ return TRUE;
+}
+
+/*++
+Function :
+
+ MapFileOpenModes
+
+ Maps Windows file open modes to Unix fopen modes and validates.
+
+--*/
+static LPSTR MapFileOpenModes(LPSTR str , BOOL * bTextMode)
+{
+ LPSTR retval = NULL;
+ LPSTR temp = NULL;
+
+ if (NULL == bTextMode)
+ {
+ ASSERT("MapFileOpenModes called with a NULL parameter for bTextMode.\n");
+ return NULL;
+ }
+
+ *bTextMode = TRUE;
+
+ if (NULL == str)
+ {
+ ASSERT("MapFileOpenModes called with a NULL parameter for str.\n");
+ return NULL;
+ }
+
+ /* The PAL behaves differently for some Windows file open modes:
+
+ c, n, S, R, and T: these are all hints to the system that aren't supported
+ by the PAL. Since the user cannot depend on this behavior, it's safe to
+ simply ignore these modes.
+
+ D: specifies a file as temporary. This file is expected to be deleted when
+ the last file descriptor is closed. The PAL does not support this behavior
+ and asserts when this mode is used.
+
+ t: represents opening in text mode. Calls to fdopen on Unix don't accept
+ 't' so it is silently stripped out. However, the PAL supports the mode by
+ having the PAL wrappers do the translation of CR-LF to LF and vice versa.
+
+ t vs. b: To get binary mode, you must explicitly use 'b'. If neither mode
+ is specified on Windows, the default mode is defined by the global
+ variable _fmode. The PAL simply defaults to text mode. After examining
+ CLR usage patterns, the PAL behavior seems acceptable. */
+
+ /* Check if the mode specifies deleting the temporary file
+ automatically when the last file descriptor is closed.
+ The PAL does not support this behavior. */
+ if (NULL != strchr(str,'D'))
+ {
+ ASSERT("The PAL doesn't support the 'D' flag for _fdopen and fopen.\n");
+ return NULL;
+ }
+
+ /* Check if the mode specifies opening in binary.
+ If so, set the bTextMode to false. */
+ if(NULL != strchr(str,'b'))
+ {
+ *bTextMode = FALSE;
+ }
+
+ retval = (LPSTR)PAL_malloc( ( strlen( str ) + 1 ) * sizeof( CHAR ) );
+ if (NULL == retval)
+ {
+ ERROR("Unable to allocate memory.\n");
+ return NULL;
+ }
+
+ temp = retval;
+ while ( *str )
+ {
+ if ( *str == 'r' || *str == 'w' || *str == 'a' )
+ {
+ *temp = *str;
+ temp++;
+ if ( ( ++str != NULL ) && *str == '+' )
+ {
+ *temp = *str;
+ temp++;
+ str++;
+ }
+ }
+ else
+ {
+ str++;
+ }
+ }
+ *temp = '\0';
+ return retval;
+}
+
+#if UNGETC_NOT_RETURN_EOF
+/*++
+Function :
+
+ WriteOnlyMode
+
+ Returns TRUE to if a file is opened in write-only mode,
+ Otherwise FALSE.
+
+--*/
+static BOOL WriteOnlyMode(FILE* pFile)
+{
+ INT fd, flags;
+
+ if (pFile != NULL)
+ {
+ fd = fileno(pFile);
+ if ((flags = fcntl(fd, F_GETFL)) >= 0)
+ {
+ if ((flags & O_ACCMODE) == O_WRONLY)
+ {
+ return TRUE;
+ }
+ }
+ }
+ return FALSE;
+}
+#endif //UNGETC_NOT_RETURN_EOF
+
+/*++
+Function:
+ _getw
+
+Gets an integer from a stream.
+
+Return Value
+
+_getw returns the integer value read. A return value of EOF indicates
+either an error or end of file. However, because the EOF value is also
+a legitimate integer value, use feof or ferror to verify an
+end-of-file or error condition.
+
+Parameter
+
+file Pointer to FILE structure
+
+--*/
+int
+__cdecl
+_getw(PAL_FILE *f)
+{
+ INT ret = 0;
+
+ PERF_ENTRY(_getw);
+ ENTRY("_getw (f=%p)\n", f);
+
+ _ASSERTE(f != NULL);
+
+ CLEARERR(f);
+
+ ret = getw( f->bsdFilePtr );
+ LOGEXIT( "returning %d\n", ret );
+ PERF_EXIT(_getw);
+
+ return ret;
+}
+
+
+/*++
+Function:
+ _fdopen
+
+see MSDN
+
+--*/
+PAL_FILE *
+__cdecl
+_fdopen(
+ int handle,
+ const char *mode)
+{
+ PAL_FILE *f = NULL;
+ LPSTR supported = NULL;
+ BOOL bTextMode = TRUE;
+
+ PERF_ENTRY(_fdopen);
+ ENTRY("_fdopen (handle=%d mode=%p (%s))\n", handle, mode, mode);
+
+ _ASSERTE(mode != NULL);
+
+ f = (PAL_FILE*)PAL_malloc( sizeof( PAL_FILE ) );
+ if ( f )
+ {
+ supported = MapFileOpenModes( (char*)mode , &bTextMode);
+ if ( !supported )
+ {
+ PAL_free(f);
+ f = NULL;
+ goto EXIT;
+ }
+
+ f->bsdFilePtr = (FILE *)fdopen( handle, supported );
+ f->PALferrorCode = PAL_FILE_NOERROR;
+ /* Make sure fdopen did not fail. */
+ if ( !f->bsdFilePtr )
+ {
+ PAL_free( f );
+ f = NULL;
+ }
+
+ PAL_free( supported );
+ supported = NULL;
+ }
+ else
+ {
+ ERROR( "Unable to allocate memory for the PAL_FILE wrapper!\n" );
+ }
+
+EXIT:
+ LOGEXIT( "_fdopen returns FILE* %p\n", f );
+ PERF_EXIT(_fdopen);
+ return f;
+}
+
+
+/*++
+
+Function :
+ fopen
+
+see MSDN doc.
+
+--*/
+PAL_FILE *
+__cdecl
+PAL_fopen(const char * fileName, const char * mode)
+{
+ PAL_FILE *f = NULL;
+ LPSTR supported = NULL;
+ LPSTR UnixFileName = NULL;
+ struct stat stat_data;
+ BOOL bTextMode = TRUE;
+
+ PERF_ENTRY(fopen);
+ ENTRY("fopen ( fileName=%p (%s) mode=%p (%s))\n", fileName, fileName, mode , mode );
+
+ _ASSERTE(fileName != NULL);
+ _ASSERTE(mode != NULL);
+
+ if ( *mode == 'r' || *mode == 'w' || *mode == 'a' )
+ {
+ supported = MapFileOpenModes( (char*)mode,&bTextMode);
+
+ if ( !supported )
+ {
+ goto done;
+ }
+
+ UnixFileName = PAL__strdup(fileName);
+ if (UnixFileName == NULL )
+ {
+ ERROR("PAL__strdup() failed\n");
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ goto done;
+ }
+
+ FILEDosToUnixPathA( UnixFileName );
+
+ /*I am not checking for the case where stat fails
+ *as fopen will handle the error more gracefully in case
+ *UnixFileName is invalid*/
+ if ((stat(UnixFileName, &stat_data) == 0 ) &&
+ ((stat_data.st_mode & S_IFMT) == S_IFDIR))
+ {
+ goto done;
+ }
+
+ f = (PAL_FILE*)PAL_malloc( sizeof( PAL_FILE ) );
+ if ( f )
+ {
+ f->bsdFilePtr = (FILE*)fopen( UnixFileName, supported );
+ f->PALferrorCode = PAL_FILE_NOERROR;
+ f->bTextMode = bTextMode;
+ if ( !f->bsdFilePtr )
+ {
+ /* Failed */
+ PAL_free( f );
+ f = NULL;
+ }
+#if UNGETC_NOT_RETURN_EOF
+ else
+ {
+ f->bWriteOnlyMode = WriteOnlyMode(f->bsdFilePtr);
+ }
+#endif //UNGETC_NOT_RETURN_EOF
+ }
+ else
+ {
+ ERROR( "Unable to allocate memory to the PAL_FILE wrapper\n" );
+ }
+ }
+ else
+ {
+ ERROR( "The mode flags must start with either an a, w, or r.\n" );
+ }
+
+done:
+ PAL_free( supported );
+ supported = NULL;
+ PAL_free( UnixFileName );
+
+ LOGEXIT( "fopen returns FILE* %p\n", f );
+ PERF_EXIT(fopen);
+ return f;
+}
+
+/*++
+Function:
+ _wfopen
+
+see MSDN doc.
+
+--*/
+PAL_FILE *
+__cdecl
+_wfopen(
+ const wchar_16 *fileName,
+ const wchar_16 *mode)
+{
+ CHAR mbFileName[ _MAX_PATH ];
+ CHAR mbMode[ 10 ];
+ PAL_FILE * filePtr = NULL;
+
+ PERF_ENTRY(_wfopen);
+ ENTRY("_wfopen(fileName:%p (%S), mode:%p (%S))\n", fileName, fileName, mode, mode);
+
+ _ASSERTE(fileName != NULL);
+ _ASSERTE(mode != NULL);
+
+ /* Convert the parameters to ASCII and defer to PAL_fopen */
+ if ( WideCharToMultiByte( CP_ACP, 0, fileName, -1, mbFileName,
+ sizeof mbFileName, NULL, NULL ) != 0 )
+ {
+ if ( WideCharToMultiByte( CP_ACP, 0, mode, -1, mbMode,
+ sizeof mbMode, NULL, NULL ) != 0 )
+ {
+ filePtr = PAL_fopen(mbFileName, mbMode);
+ }
+ else
+ {
+ ERROR( "An error occurred while converting mode to ANSI.\n" );
+ }
+ }
+ else
+ {
+ ERROR( "An error occurred while converting"
+ " fileName to ANSI string.\n" );
+ }
+ LOGEXIT("_wfopen returning FILE* %p\n", filePtr);
+ PERF_EXIT(_wfopen);
+ return filePtr;
+}
+
+/*++
+Function:
+_wfsopen
+
+see MSDN doc.
+
+--*/
+PAL_FILE *
+__cdecl
+_wfsopen(
+ const wchar_16 *fileName,
+ const wchar_16 *mode,
+ int shflag)
+{
+ // UNIXTODO: Implement this.
+ ERROR("Needs Implementation!!!");
+ return NULL;
+}
+
+/*++
+Function:
+ _putw
+
+Writes an integer to a stream.
+
+Return Value
+
+_putw returns the value written. A return value of EOF may indicate an
+error. Because EOF is also a legitimate integer value, use ferror to
+verify an error.
+
+Parameters
+
+c Binary integer to be output
+file Pointer to FILE structure
+
+--*/
+int
+__cdecl
+_putw(int c, PAL_FILE *f)
+{
+ INT ret = 0;
+
+ PERF_ENTRY(_putw);
+ ENTRY("_putw (c=0x%x, f=%p)\n", c, f);
+
+ _ASSERTE(f != NULL);
+
+ CLEARERR(f);
+
+ ret = putw(c, f->bsdFilePtr );
+ LOGEXIT( "returning %d\n", ret );
+ PERF_EXIT(_putw);
+
+ return ret;
+}
+
+
+/*++
+Function
+ PAL_get_stdout.
+
+ Returns the stdout stream.
+--*/
+PAL_FILE * __cdecl PAL_get_stdout(int caller)
+{
+ PERF_ENTRY(get_stdout);
+ ENTRY("PAL_get_stdout\n");
+ LOGEXIT("PAL_get_stdout returns PAL_FILE * %p\n", &PAL_Stdout );
+ PERF_EXIT(get_stdout);
+ return &PAL_Stdout;
+}
+
+/*++
+Function
+ PAL_get_stdin.
+
+ Returns the stdin stream.
+--*/
+PAL_FILE * __cdecl PAL_get_stdin(int caller)
+{
+ PERF_ENTRY(get_stdin);
+ ENTRY("PAL_get_stdin\n");
+ LOGEXIT("PAL_get_stdin returns PAL_FILE * %p\n", &PAL_Stdin );
+ PERF_EXIT(get_stdin);
+ return &PAL_Stdin;
+}
+
+/*++
+Function
+ PAL_get_stderr.
+
+ Returns the stderr stream.
+--*/
+PAL_FILE * __cdecl PAL_get_stderr(int caller)
+{
+ PERF_ENTRY(get_stderr);
+ ENTRY("PAL_get_stderr\n");
+ LOGEXIT("PAL_get_stderr returns PAL_FILE * %p\n", &PAL_Stderr );
+ PERF_EXIT(get_stderr);
+ return &PAL_Stderr;
+}
+
+
+/*++
+
+Function:
+
+ _close
+
+See msdn for more details.
+--*/
+int __cdecl PAL__close(int handle)
+{
+ INT nRetVal = 0;
+
+ PERF_ENTRY(_close);
+ ENTRY( "_close( handle=%d )\n", handle );
+
+ nRetVal = close( handle );
+
+ LOGEXIT( "_close returning %d.\n", nRetVal );
+ PERF_EXIT(_close);
+ return nRetVal;
+}
+
+ int __cdecl PAL__flushall()
+ {
+ return fflush(NULL);
+ }
+
+wchar_16 *
+__cdecl
+PAL_fgetws(wchar_16 *s, int n, PAL_FILE *f)
+{
+ ASSERT (0);
+ return NULL;
+}
+
+
+/*++
+Function :
+
+ fread
+
+ See MSDN for more details.
+--*/
+
+size_t
+__cdecl
+PAL_fread(void * buffer, size_t size, size_t count, PAL_FILE * f)
+{
+ size_t nReadBytes = 0;
+
+ PERF_ENTRY(fread);
+ ENTRY( "fread( buffer=%p, size=%d, count=%d, f=%p )\n",
+ buffer, size, count, f );
+
+ _ASSERTE(f != NULL);
+
+ CLEARERR(f);
+
+ if(f->bTextMode != TRUE)
+ {
+ nReadBytes = fread( buffer, size, count, f->bsdFilePtr );
+ }
+ else
+ {
+ size_t i=0;
+ if(size > 0)
+ {
+ size_t j=0;
+ LPSTR temp = (LPSTR)buffer;
+ int nChar = 0;
+ int nCount =0;
+
+ for(i=0; i< count; i++)
+ {
+ for(j=0; j< size; j++)
+ {
+ if((nChar = PAL_getc(f)) == EOF)
+ {
+ nReadBytes = i;
+ goto done;
+ }
+ else
+ {
+ temp[nCount++]=nChar;
+ }
+ }
+ }
+ }
+ nReadBytes = i;
+ }
+
+done:
+ LOGEXIT( "fread returning size_t %d\n", nReadBytes );
+ PERF_EXIT(fread);
+ return nReadBytes;
+}
+
+
+/*++
+Function :
+
+ ferror
+
+ See MSDN for more details.
+--*/
+int
+_cdecl
+PAL_ferror(PAL_FILE * f)
+{
+ INT nErrorCode = PAL_FILE_NOERROR;
+
+ PERF_ENTRY(ferror);
+ ENTRY( "ferror( f=%p )\n", f );
+
+ _ASSERTE(f != NULL);
+
+ nErrorCode = ferror( f->bsdFilePtr );
+ if ( 0 == nErrorCode )
+ {
+ /* See if the PAL file error code is set. */
+ nErrorCode = f->PALferrorCode;
+ }
+
+ LOGEXIT( "ferror returns %d\n", nErrorCode );
+ PERF_EXIT(ferror);
+ return nErrorCode;
+}
+
+
+/*++
+Function :
+
+ fclose
+
+ See MSDN for more details.
+--*/
+int
+_cdecl
+PAL_fclose(PAL_FILE * f)
+{
+ INT nRetVal = 0;
+
+ PERF_ENTRY(fclose);
+ ENTRY( "fclose( f=%p )\n", f );
+
+ _ASSERTE(f != NULL);
+
+ CLEARERR(f);
+
+ nRetVal = fclose( f->bsdFilePtr );
+ PAL_free( f );
+
+ LOGEXIT( "fclose returning %d\n", nRetVal );
+ PERF_EXIT(fclose);
+ return nRetVal;
+}
+
+/*++
+Function :
+
+ setbuf
+
+ See MSDN for more details.
+--*/
+void
+_cdecl
+PAL_setbuf(PAL_FILE * f, char * buffer)
+{
+ PERF_ENTRY(setbuf);
+ ENTRY( "setbuf( %p, %p )\n", f, buffer );
+
+ _ASSERTE(f != NULL);
+
+ setbuf( f->bsdFilePtr, buffer );
+
+ LOGEXIT( "setbuf\n" );
+ PERF_EXIT(setbuf);
+}
+
+/*++
+Function :
+
+ fputs
+
+ See MSDN for more details.
+--*/
+int
+_cdecl
+PAL_fputs(const char * str, PAL_FILE * f)
+{
+ INT nRetVal = 0;
+
+ PERF_ENTRY(fputs);
+ ENTRY( "fputs( %p (%s), %p )\n", str, str, f);
+
+ _ASSERTE(str != NULL);
+ _ASSERTE(f != NULL);
+
+ CLEARERR(f);
+
+ nRetVal = fputs( str, f->bsdFilePtr );
+
+ LOGEXIT( "fputs returning %d\n", nRetVal );
+ PERF_EXIT(fputs);
+ return nRetVal;
+}
+
+/*--
+Function :
+
+ fputc
+
+ See MSDN for more details.
+--*/
+int
+_cdecl
+PAL_fputc(int c, PAL_FILE * f)
+{
+ INT nRetVal = 0;
+
+ PERF_ENTRY(fputc);
+ ENTRY( "fputc( 0x%x (%c), %p )\n", c, c, f);
+
+ _ASSERTE(f != NULL);
+
+ CLEARERR(f);
+
+ nRetVal = fputc( c, f->bsdFilePtr );
+
+ LOGEXIT( "fputc returning %d\n", nRetVal );
+ PERF_EXIT(fputc);
+ return nRetVal;
+}
+
+/*--
+Function :
+
+ putchar
+
+ See MSDN for more details.
+--*/
+int
+_cdecl
+PAL_putchar( int c )
+{
+ INT nRetVal = 0;
+
+ PERF_ENTRY(putchar);
+ ENTRY( "putchar( 0x%x (%c) )\n", c, c);
+
+ nRetVal = putchar( c );
+
+ LOGEXIT( "putchar returning %d\n", nRetVal );
+ PERF_EXIT(putchar);
+ return nRetVal;
+}
+
+/*++
+Function :
+
+ ftell
+
+ See MSDN for more details.
+--*/
+LONG
+_cdecl
+PAL_ftell(PAL_FILE * f)
+{
+ long lRetVal = 0;
+
+ PERF_ENTRY(ftell);
+ ENTRY( "ftell( %p )\n", f );
+
+ _ASSERTE(f != NULL);
+ lRetVal = ftell( f->bsdFilePtr );
+
+#ifdef BIT64
+ /* Windows does not set an error if the file pointer's position
+ is greater than _I32_MAX. It just returns -1. */
+ if (lRetVal > _I32_MAX)
+ {
+ lRetVal = -1;
+ }
+#endif
+
+ LOGEXIT( "ftell returning %ld\n", lRetVal );
+ PERF_EXIT(ftell);
+ /* This explicit cast to LONG is used to silence any potential warnings
+ due to implicitly casting the native long lRetVal to LONG when returning. */
+ return (LONG)lRetVal;
+}
+
+/*++
+Function :
+
+ feof
+
+ See MSDN for more details.
+--*/
+int
+_cdecl
+PAL_feof(PAL_FILE * f)
+{
+ INT nRetVal = 0;
+
+ PERF_ENTRY(feof);
+ ENTRY( "feof( %p )\n", f );
+
+ _ASSERTE(f != NULL);
+ nRetVal = feof( f->bsdFilePtr );
+
+ LOGEXIT( "feof returning %d\n", nRetVal );
+ PERF_EXIT(feof);
+ return nRetVal;
+}
+
+/*++
+Function :
+
+ getc
+
+ See MSDN for more details.
+--*/
+int
+_cdecl
+PAL_getc(PAL_FILE * f)
+{
+ INT nRetVal = 0;
+ INT temp =0;
+
+ PERF_ENTRY(getc);
+ ENTRY( "getc( %p )\n", f );
+
+ _ASSERTE(f != NULL);
+
+ CLEARERR(f);
+
+ nRetVal = getc( f->bsdFilePtr );
+
+ if ( (f->bTextMode) && (nRetVal == '\r') )
+ {
+ if ((temp = getc( f->bsdFilePtr ))== '\n')
+ {
+ nRetVal ='\n';
+ }
+ else if (EOF == ungetc( temp, f->bsdFilePtr ))
+ {
+ ERROR("ungetc operation failed\n");
+ }
+ }
+
+ LOGEXIT( "getc returning %d\n", nRetVal );
+ PERF_EXIT(getc);
+ return nRetVal;
+}
+
+/*++
+Function :
+
+ ungetc
+
+ See MSDN for more details.
+--*/
+int
+_cdecl
+PAL_ungetc(int c, PAL_FILE * f)
+{
+ INT nRetVal = 0;
+
+ PERF_ENTRY(ungetc);
+ ENTRY( "ungetc( %c, %p )\n", c, f );
+
+ _ASSERTE(f != NULL);
+
+#if UNGETC_NOT_RETURN_EOF
+ /* On some Unix platform such as Solaris, ungetc does not return EOF
+ on write-only file. */
+ if (f->bWriteOnlyMode)
+ {
+ nRetVal = EOF;
+ }
+ else
+#endif //UNGETC_NOT_RETURN_EOF
+ {
+ CLEARERR(f);
+
+ nRetVal = ungetc( c, f->bsdFilePtr );
+ }
+
+ LOGEXIT( "ungetc returning %d\n", nRetVal );
+ PERF_EXIT(ungetc);
+ return nRetVal;
+}
+
+
+
+/*++
+Function :
+
+ setvbuf
+
+ See MSDN for more details.
+--*/
+int
+_cdecl
+PAL_setvbuf(PAL_FILE *f, char *buf, int type, size_t size)
+{
+ INT nRetVal = 0;
+
+ PERF_ENTRY(setvbuf);
+ ENTRY( "setvbuf( %p, %p, %d, %ul )\n", f, buf, type, size);
+
+ _ASSERTE(f != NULL);
+
+ nRetVal = setvbuf(f->bsdFilePtr, buf, type, size);
+
+ LOGEXIT( "setvbuf returning %d\n", nRetVal );
+ PERF_EXIT(setvbuf);
+ return nRetVal;
+}
diff --git a/src/pal/src/cruntime/filecrt.cpp b/src/pal/src/cruntime/filecrt.cpp
new file mode 100644
index 0000000000..48079b309c
--- /dev/null
+++ b/src/pal/src/cruntime/filecrt.cpp
@@ -0,0 +1,571 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ filecrt.cpp
+
+Abstract:
+
+ Implementation of the file functions in the C runtime library that
+ are Windows specific.
+
+
+
+--*/
+
+#include "pal/thread.hpp"
+#include "pal/file.hpp"
+
+#include "pal/palinternal.h"
+#include "pal/dbgmsg.h"
+#include "pal/file.h"
+#include "pal/cruntime.h"
+
+#include <unistd.h>
+#include <errno.h>
+#include <sys/stat.h>
+
+#ifdef __APPLE__
+#include <sys/syscall.h>
+#endif // __APPLE__
+
+using namespace CorUnix;
+
+SET_DEFAULT_DEBUG_CHANNEL(CRT);
+
+/*++
+Function:
+ _open_osfhandle
+
+See MSDN doc.
+--*/
+int
+__cdecl
+_open_osfhandle( INT_PTR osfhandle, int flags )
+{
+ PAL_ERROR palError = NO_ERROR;
+ CPalThread *pthrCurrent = NULL;
+ IPalObject *pobjFile = NULL;
+ CFileProcessLocalData *pLocalData = NULL;
+ IDataLock *pDataLock = NULL;
+ INT nRetVal = -1;
+ INT openFlags = 0;
+
+ PERF_ENTRY(_open_osfhandle);
+ ENTRY( "_open_osfhandle (osfhandle=%#x, flags=%#x)\n", osfhandle, flags );
+
+ pthrCurrent = InternalGetCurrentThread();
+
+ if (flags != _O_RDONLY)
+ {
+ ASSERT("flag(%#x) not supported\n", flags);
+ goto EXIT;
+ }
+
+ openFlags |= O_RDONLY;
+
+ palError = g_pObjectManager->ReferenceObjectByHandle(
+ pthrCurrent,
+ reinterpret_cast<HANDLE>(osfhandle),
+ &aotFile,
+ 0,
+ &pobjFile
+ );
+
+ if (NO_ERROR != palError)
+ {
+ ERROR("Error dereferencing file handle\n");
+ goto EXIT;
+ }
+
+ palError = pobjFile->GetProcessLocalData(
+ pthrCurrent,
+ ReadLock,
+ &pDataLock,
+ reinterpret_cast<void **>(&pLocalData)
+ );
+
+ if (NO_ERROR == palError)
+ {
+ if ('\0' != pLocalData->unix_filename[0])
+ {
+ nRetVal = InternalOpen(pLocalData->unix_filename, openFlags);
+ }
+ else /* the only file object with no unix_filename is a pipe */
+ {
+ /* check if the file pipe descrptor is for read or write */
+ if (pLocalData->open_flags == O_WRONLY)
+ {
+ ERROR( "Couldn't open a write pipe on read mode\n");
+ goto EXIT;
+ }
+
+ nRetVal = pLocalData->unix_fd;
+ }
+
+ if ( nRetVal == -1 )
+ {
+ ERROR( "Error: %s.\n", strerror( errno ) );
+ }
+ }
+ else
+ {
+ ASSERT("Unable to access file data");
+ }
+
+EXIT:
+
+ if (NULL != pDataLock)
+ {
+ pDataLock->ReleaseLock(pthrCurrent, FALSE);
+ }
+
+ if (NULL != pobjFile)
+ {
+ pobjFile->ReleaseReference(pthrCurrent);
+ }
+
+ LOGEXIT( "_open_osfhandle return nRetVal:%d\n", nRetVal);
+ PERF_EXIT(_open_osfhandle);
+ return nRetVal;
+}
+
+
+/*++
+Function:
+ PAL_fflush
+
+See MSDN for more details.
+--*/
+int
+_cdecl
+PAL_fflush( PAL_FILE *stream )
+{
+ int nRetVal = 0;
+
+ PERF_ENTRY(fflush);
+ ENTRY( "fflush( %p )\n", stream );
+
+ nRetVal = fflush(stream ? stream->bsdFilePtr : NULL);
+
+ LOGEXIT( "fflush returning %d\n", nRetVal );
+ PERF_EXIT(fflush);
+ return nRetVal;
+}
+
+
+/*++
+PAL__getcwd
+
+Wrapper function for getcwd.
+
+Input parameters:
+
+szBuf = a copy of the absolute pathname of the current working directory
+is copied into szBuf.
+nSize = size, in bytes, of the array referenced by szBuf.
+
+Return value:
+ A pointer to the pathname if successful, otherwise NULL is returned
+--*/
+char *
+__cdecl
+PAL__getcwd(
+ char *szBuf,
+ size_t nSize
+ )
+{
+ return (char *)getcwd(szBuf, nSize);
+}
+
+
+/*++
+PAL_mkstemp
+
+Wrapper function for InternalMkstemp.
+
+Input parameters:
+
+szNameTemplate = template to follow when naming the created file
+
+Return value:
+ Open file descriptor on success, -1 if file could not be created
+--*/
+int
+__cdecl
+PAL_mkstemp(char *szNameTemplate)
+{
+ return InternalMkstemp(szNameTemplate);
+}
+
+/*++
+InternalMkstemp
+
+Wrapper for mkstemp.
+
+Input parameters:
+
+szNameTemplate = template to follow when naming the created file
+
+Return value:
+ Open file descriptor on success, -1 if file could not be created
+--*/
+int
+CorUnix::InternalMkstemp(
+ char *szNameTemplate
+ )
+{
+ int nRet = -1;
+#if MKSTEMP64_IS_USED_INSTEAD_OF_MKSTEMP
+ nRet = mkstemp64(szNameTemplate);
+#else
+ nRet = mkstemp(szNameTemplate);
+#endif
+ return nRet;
+}
+
+
+/*++
+PAL__open
+
+Wrapper function for InternalOpen.
+
+Input parameters:
+
+szPath = pointer to a pathname of a file to be opened
+nFlags = arguments that control how the file should be accessed
+mode = file permission settings that are used only when a file is created
+
+Return value:
+ File descriptor on success, -1 on failure
+--*/
+int
+__cdecl
+PAL__open(
+ const char *szPath,
+ int nFlags,
+ ...
+ )
+{
+ int nRet = -1;
+ int mode = 0;
+ va_list ap;
+
+ // If nFlags does not contain O_CREAT, the mode parameter will be ignored.
+ if (nFlags & O_CREAT)
+ {
+ va_start(ap, nFlags);
+ mode = va_arg(ap, int);
+ va_end(ap);
+ }
+
+ nRet = InternalOpen(szPath, nFlags, mode);
+ return nRet;
+}
+
+/*++
+InternalOpen
+
+Wrapper for open.
+
+Input parameters:
+
+szPath = pointer to a pathname of a file to be opened
+nFlags = arguments that control how the file should be accessed
+mode = file permission settings that are used only when a file is created
+
+Return value:
+ File descriptor on success, -1 on failure
+--*/
+int
+CorUnix::InternalOpen(
+ const char *szPath,
+ int nFlags,
+ ...
+ )
+{
+ int nRet = -1;
+ int mode = 0;
+ va_list ap;
+
+ // If nFlags does not contain O_CREAT, the mode parameter will be ignored.
+ if (nFlags & O_CREAT)
+ {
+ va_start(ap, nFlags);
+ mode = va_arg(ap, int);
+ va_end(ap);
+ }
+
+#if OPEN64_IS_USED_INSTEAD_OF_OPEN
+ nRet = open64(szPath, nFlags, mode);
+#else
+ nRet = open(szPath, nFlags, mode);
+#endif
+ return nRet;
+}
+
+
+/*++
+PAL_rename
+
+Wrapper function for rename.
+
+Input parameters:
+
+szOldName = pointer to the pathname of the file to be renamed
+szNewName = pointer to the new pathname of the file
+
+Return value:
+ Returns 0 on success and -1 on failure
+--*/
+int
+__cdecl
+PAL_rename(
+ const char *szOldName,
+ const char *szNewName
+ )
+{
+ return rename(szOldName, szNewName);
+}
+
+
+/*++
+PAL_fgets
+
+Wrapper function for InternalFgets.
+
+Input parameters:
+
+sz = stores characters read from the given file stream
+nSize = number of characters to be read
+pf = stream to read characters from
+
+Return value:
+ Returns a pointer to the string storing the characters on success
+ and NULL on failure.
+--*/
+char *
+__cdecl
+PAL_fgets(
+ char *sz,
+ int nSize,
+ PAL_FILE *pf
+ )
+{
+ char * szBuf;
+
+ PERF_ENTRY(fgets);
+ ENTRY( "fgets(sz=%p (%s) nSize=%d pf=%p)\n", sz, sz, nSize, pf);
+
+ if (pf != NULL)
+ {
+ szBuf = InternalFgets(sz, nSize, pf->bsdFilePtr, pf->bTextMode);
+ }
+ else
+ {
+ szBuf = NULL;
+ }
+
+ LOGEXIT("fgets() returns %p\n", szBuf);
+ PERF_EXIT(fgets);
+
+ return szBuf;
+}
+
+/*++
+InternalFgets
+
+Wrapper for fgets.
+
+Input parameters:
+
+sz = stores characters read from the given file stream
+nSize = number of characters to be read
+f = stream to read characters from
+fTextMode = flag that indicates if file contents are text or binary
+
+Return value:
+ Returns a pointer to the string storing the characters on success
+ and NULL on failure.
+
+Notes:
+In Unix systems, fgets() can return an error if it gets interrupted by a
+signal before reading anything, and errno is set to EINTR. When this
+happens, it is SOP to call fgets again.
+--*/
+char *
+CorUnix::InternalFgets(
+ char *sz,
+ int nSize,
+ FILE *f,
+ bool fTextMode
+ )
+{
+ char *retval = NULL;
+
+ _ASSERTE(sz != NULL);
+ _ASSERTE(f != NULL);
+
+#if FILE_OPS_CHECK_FERROR_OF_PREVIOUS_CALL
+ clearerr(f);
+#endif
+
+ do
+ {
+ retval = fgets(sz, nSize, f);
+ if (NULL==retval)
+ {
+ if (feof(f))
+ {
+ TRACE("Reached EOF\n");
+ break;
+ }
+ /* The man page suggests using ferror and feof to distinguish
+ between error and EOF, but feof and errno is sufficient.
+ Not all cases that set errno also flag ferror, so just
+ checking errno is the best solution. */
+ if (EINTR != errno)
+ {
+ WARN("got error; errno is %d (%s)\n",errno, strerror(errno));
+ break;
+ }
+ /* we ignored a EINTR error, reset the stream's error state */
+ clearerr(f);
+ TRACE("call got interrupted (EINTR), trying again\n");
+ }
+ if (fTextMode)
+ {
+ int len = strlen(sz);
+ if ((len>=2) && (sz[len-1]=='\n') && (sz[len-2]=='\r'))
+ {
+ sz[len-2]='\n';
+ sz[len-1]='\0';
+ }
+ }
+ } while(NULL == retval);
+
+ return retval;
+}
+
+/*++
+PAL_fwrite
+
+Wrapper function for InternalFwrite.
+
+Input parameters:
+
+pvBuffer = array of objects to write to the given file stream
+nSize = size of a object in bytes
+nCount = number of objects to write
+pf = stream to write characters to
+
+Return value:
+ Returns the number of objects written.
+--*/
+size_t
+__cdecl
+PAL_fwrite(
+ const void *pvBuffer,
+ size_t nSize,
+ size_t nCount,
+ PAL_FILE *pf
+ )
+{
+ size_t nWrittenBytes = 0;
+
+ PERF_ENTRY(fwrite);
+ ENTRY( "fwrite( pvBuffer=%p, nSize=%d, nCount=%d, pf=%p )\n",
+ pvBuffer, nSize, nCount, pf);
+ _ASSERTE(pf != NULL);
+
+ nWrittenBytes = InternalFwrite(pvBuffer, nSize, nCount, pf->bsdFilePtr, &pf->PALferrorCode);
+
+ LOGEXIT( "fwrite returning size_t %d\n", nWrittenBytes );
+ PERF_EXIT(fwrite);
+ return nWrittenBytes;
+}
+
+/*++
+InternalFwrite
+
+Wrapper for fwrite.
+
+Input parameters:
+
+pvBuffer = array of objects to write to the given file stream
+nSize = size of a object in bytes
+nCount = number of objects to write
+f = stream to write characters to
+pnErrorCode = reference to a PAL_FILE's fwrite error code field
+
+Return value:
+ Returns the number of objects written.
+--*/
+size_t
+CorUnix::InternalFwrite(
+ const void *pvBuffer,
+ size_t nSize,
+ size_t nCount,
+ FILE *f,
+ INT *pnErrorCode
+ )
+{
+ size_t nWrittenBytes = 0;
+ _ASSERTE(f != NULL);
+
+#if FILE_OPS_CHECK_FERROR_OF_PREVIOUS_CALL
+ clearerr(f);
+#endif
+
+ nWrittenBytes = fwrite(pvBuffer, nSize, nCount, f);
+
+ // Make sure no error ocurred.
+ if ( nWrittenBytes < nCount )
+ {
+ // Set the FILE* error code
+ *pnErrorCode = PAL_FILE_ERROR;
+ }
+
+ return nWrittenBytes;
+}
+
+
+/*++
+PAL_fseek
+
+Wrapper function for fseek.
+
+Input parameters:
+
+pf = a given file stream
+lOffset = distance from position to set file-position indicator
+nWhence = method used to determine the file_position indicator location relative to lOffset
+
+Return value:
+ 0 on success, -1 on failure.
+--*/
+int
+_cdecl
+PAL_fseek(
+ PAL_FILE * pf,
+ LONG lOffset,
+ int nWhence
+ )
+{
+ int nRet = 0;
+
+ PERF_ENTRY(fseek);
+ ENTRY( "fseek( %p, %ld, %d )\n", pf, lOffset, nWhence );
+
+ nRet = fseek(pf ? pf->bsdFilePtr : NULL, lOffset, nWhence);
+
+ LOGEXIT("fseek returning %d\n", nRet);
+ PERF_EXIT(fseek);
+ return nRet;
+}
diff --git a/src/pal/src/cruntime/lstr.cpp b/src/pal/src/cruntime/lstr.cpp
new file mode 100644
index 0000000000..2267d8491b
--- /dev/null
+++ b/src/pal/src/cruntime/lstr.cpp
@@ -0,0 +1,316 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ lstr.c
+
+Abstract:
+
+ Implementation of functions manipulating unicode/ansi strings. (lstr*A/W)
+
+
+
+--*/
+
+#include "pal/palinternal.h"
+#include "pal/dbgmsg.h"
+
+SET_DEFAULT_DEBUG_CHANNEL(CRT);
+
+
+
+/*++
+Function:
+ lstrcatW
+
+The lstrcat function appends one string to another.
+
+Parameters
+
+lpString1 [in/out] Pointer to a null-terminated string. The buffer must be large
+ enough to contain both strings.
+lpString2 [in] Pointer to the null-terminated string to be appended to the
+ string specified in the lpString1 parameter.
+
+Return Values
+
+If the function succeeds, the return value is a pointer to the buffer.
+If the function fails, the return value is NULL.
+
+--*/
+LPWSTR
+PALAPI
+lstrcatW(
+ IN OUT LPWSTR lpString1,
+ IN LPCWSTR lpString2)
+{
+ LPWSTR lpStart = lpString1;
+
+ PERF_ENTRY(lstrcatW);
+ ENTRY("lstrcatW (lpString1=%p (%S), lpString2=%p (%S))\n",
+ lpString1?lpString1:W16_NULLSTRING,
+ lpString1?lpString1:W16_NULLSTRING, lpString2?lpString2:W16_NULLSTRING, lpString2?lpString2:W16_NULLSTRING);
+
+ if (lpString1 == NULL)
+ {
+ ERROR("invalid lpString1 argument\n");
+ LOGEXIT("lstrcatW returning LPWSTR NULL\n");
+ PERF_EXIT(lstrcatW);
+ return NULL;
+ }
+
+ if (lpString2 == NULL)
+ {
+ ERROR("invalid lpString2 argument\n");
+ LOGEXIT("lstrcatW returning LPWSTR NULL\n");
+ PERF_EXIT(lstrcatW);
+ return NULL;
+ }
+
+ /* find end of source string */
+ while (*lpString1)
+ {
+ lpString1++;
+ }
+
+ /* concatenate new string */
+ while(*lpString2)
+ {
+ *lpString1++ = *lpString2++;
+ }
+
+ /* add terminating null */
+ *lpString1 = '\0';
+
+ LOGEXIT("lstrcatW returning LPWSTR %p (%S)\n", lpStart, lpStart);
+ PERF_EXIT(lstrcatW);
+ return lpStart;
+}
+
+
+/*++
+Function:
+ lstrcpyW
+
+The lstrcpy function copies a string to a buffer.
+
+To copy a specified number of characters, use the lstrcpyn function.
+
+Parameters
+
+lpString1 [out] Pointer to a buffer to receive the contents of the string pointed
+ to by the lpString2 parameter. The buffer must be large enough to
+ contain the string, including the terminating null character.
+
+lpString2 [in] Pointer to the null-terminated string to be copied.
+
+Return Values
+
+If the function succeeds, the return value is a pointer to the buffer.
+If the function fails, the return value is NULL.
+
+--*/
+LPWSTR
+PALAPI
+lstrcpyW(
+ OUT LPWSTR lpString1,
+ IN LPCWSTR lpString2)
+{
+ LPWSTR lpStart = lpString1;
+
+ PERF_ENTRY(lstrcpyW);
+ ENTRY("lstrcpyW (lpString1=%p, lpString2=%p (%S))\n",
+ lpString1?lpString1:W16_NULLSTRING, lpString2?lpString2:W16_NULLSTRING, lpString2?lpString2:W16_NULLSTRING);
+
+ if (lpString1 == NULL)
+ {
+ ERROR("invalid lpString1 argument\n");
+ LOGEXIT("lstrcpyW returning LPWSTR NULL\n");
+ PERF_EXIT(lstrcpyW);
+ return NULL;
+ }
+
+ if (lpString2 == NULL)
+ {
+ ERROR("invalid lpString2 argument\n");
+ LOGEXIT("lstrcpyW returning LPWSTR NULL\n");
+ PERF_EXIT(lstrcpyW);
+ return NULL;
+ }
+
+ /* copy source string to destination string */
+ while(*lpString2)
+ {
+ *lpString1++ = *lpString2++;
+ }
+
+ /* add terminating null */
+ *lpString1 = '\0';
+
+ LOGEXIT("lstrcpyW returning LPWSTR %p (%S)\n", lpStart, lpStart);
+ PERF_EXIT(lstrcpyW);
+ return lpStart;
+}
+
+
+/*++
+Function:
+ lstrlenA
+
+
+The lstrlen function returns the length in bytes (ANSI version) or
+characters (Unicode version) of the specified string (not including
+the terminating null character).
+
+Parameters
+
+lpString [in] Pointer to a null-terminated string.
+
+Return Values
+
+The return value specifies the length of the string, in TCHARs. This
+refers to bytes for ANSI versions of the function or characters for
+Unicode versions.
+
+--*/
+int
+PALAPI
+lstrlenA( IN LPCSTR lpString)
+{
+ int nChar = 0;
+
+ PERF_ENTRY(lstrlenA);
+ ENTRY("lstrlenA (lpString=%p (%s))\n", lpString?lpString:"NULL", lpString?lpString:"NULL");
+ if (lpString)
+ {
+ while (*lpString++)
+ {
+ nChar++;
+ }
+ }
+ LOGEXIT("lstrlenA returning int %d\n", nChar);
+ PERF_EXIT(lstrlenA);
+ return nChar;
+}
+
+
+/*++
+Function:
+ lstrlenW
+
+The lstrlen function returns the length in bytes (ANSI version) or
+characters (Unicode version) of the specified string (not including
+the terminating null character).
+
+Parameters
+
+lpString [in] Pointer to a null-terminated string.
+
+Return Values
+
+The return value specifies the length of the string, in TCHARs. This
+refers to bytes for ANSI versions of the function or characters for
+Unicode versions.
+
+--*/
+int
+PALAPI
+lstrlenW(
+ IN LPCWSTR lpString)
+{
+ int nChar = 0;
+
+ PERF_ENTRY(lstrlenW);
+ ENTRY("lstrlenW (lpString=%p (%S))\n", lpString?lpString:W16_NULLSTRING, lpString?lpString:W16_NULLSTRING);
+ if (lpString != NULL)
+ {
+ while (*lpString++)
+ {
+ nChar++;
+ }
+ }
+ LOGEXIT("lstrlenW returning int %d\n", nChar);
+ PERF_EXIT(lstrlenW);
+ return nChar;
+}
+
+
+/*++
+Function:
+ lstrcpynW
+
+The lstrcpyn function copies a specified number of characters from a
+source string into a buffer.
+
+Parameters
+
+lpString1 [out] Pointer to a buffer into which the function copies characters.
+ The buffer must be large enough to contain the number of TCHARs
+ specified by iMaxLength, including room for a terminating null character.
+lpString2 [in] Pointer to a null-terminated string from which the function copies
+ characters.
+iMaxLength [in] Specifies the number of TCHARs to be copied from the string pointed
+ to by lpString2 into the buffer pointed to by lpString1, including a
+ terminating null character.
+
+Return Values
+
+If the function succeeds, the return value is a pointer to the buffer.
+If the function fails, the return value is NULL.
+
+--*/
+LPWSTR
+PALAPI
+lstrcpynW(
+ OUT LPWSTR lpString1,
+ IN LPCWSTR lpString2,
+ IN int iMaxLength)
+{
+ LPWSTR lpStart = lpString1;
+
+ PERF_ENTRY(lstrcpynW);
+ ENTRY("lstrcpynW (lpString1=%p, lpString2=%p (%S), iMaxLength=%d)\n",
+ lpString1?lpString1:W16_NULLSTRING, lpString2?lpString2:W16_NULLSTRING, lpString2?lpString2:W16_NULLSTRING, iMaxLength);
+
+ if (lpString1 == NULL)
+ {
+ ERROR("invalid lpString1 argument\n");
+ LOGEXIT("lstrcpynW returning LPWSTR NULL\n");
+ PERF_EXIT(lstrcpynW);
+ return NULL;
+ }
+
+ if (lpString2 == NULL)
+ {
+ ERROR("invalid lpString2 argument\n");
+ LOGEXIT("lstrcpynW returning LPWSTR NULL\n");
+ PERF_EXIT(lstrcpynW);
+ return NULL;
+ }
+
+ /* copy source string to destination string */
+ while(iMaxLength > 1 && *lpString2)
+ {
+ *lpString1++ = *lpString2++;
+ iMaxLength--;
+ }
+
+ /* add terminating null */
+ if (iMaxLength > 0)
+ {
+ *lpString1 = '\0';
+ }
+
+ LOGEXIT("lstrcpynW returning LPWSTR %p (%S)\n", lpStart, lpStart);
+ PERF_EXIT(lstrcpynW);
+ return lpStart;
+
+}
+
+
diff --git a/src/pal/src/cruntime/malloc.cpp b/src/pal/src/cruntime/malloc.cpp
new file mode 100644
index 0000000000..3083a2005f
--- /dev/null
+++ b/src/pal/src/cruntime/malloc.cpp
@@ -0,0 +1,116 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ malloc.cpp
+
+Abstract:
+
+ Implementation of suspension safe memory allocation functions.
+
+Revision History:
+
+
+
+--*/
+
+#include "pal/corunix.hpp"
+#include "pal/thread.hpp"
+#include "pal/malloc.hpp"
+#include "pal/dbgmsg.h"
+
+#include <string.h>
+
+SET_DEFAULT_DEBUG_CHANNEL(CRT);
+
+using namespace CorUnix;
+
+void *
+__cdecl
+PAL_realloc(
+ void* pvMemblock,
+ size_t szSize
+ )
+{
+ return InternalRealloc(pvMemblock, szSize);
+}
+
+void *
+CorUnix::InternalRealloc(
+ void* pvMemblock,
+ size_t szSize
+ )
+{
+ void *pvMem;
+
+ PERF_ENTRY(InternalRealloc);
+ ENTRY("realloc (memblock:%p size=%d)\n", pvMemblock, szSize);
+
+ if (szSize == 0)
+ {
+ // If pvMemblock is NULL, there's no reason to call free.
+ if (pvMemblock != NULL)
+ {
+ free(pvMemblock);
+ }
+ pvMem = NULL;
+ }
+ else
+ {
+ pvMem = realloc(pvMemblock, szSize);
+ }
+
+ LOGEXIT("realloc returns void * %p\n", pvMem);
+ PERF_EXIT(InternalRealloc);
+ return pvMem;
+}
+
+void
+__cdecl
+PAL_free(
+ void *pvMem
+ )
+{
+ free(pvMem);
+}
+
+void *
+__cdecl
+PAL_malloc(
+ size_t szSize
+ )
+{
+ return InternalMalloc(szSize);
+}
+
+void *
+CorUnix::InternalMalloc(
+ size_t szSize
+ )
+{
+ void *pvMem;
+
+ if (szSize == 0)
+ {
+ // malloc may return null for a requested size of zero bytes. Force a nonzero size to get a valid pointer.
+ szSize = 1;
+ }
+
+ pvMem = (void*)malloc(szSize);
+ return pvMem;
+}
+
+char *
+__cdecl
+PAL__strdup(
+ const char *c_szStr
+ )
+{
+ return strdup(c_szStr);
+} \ No newline at end of file
diff --git a/src/pal/src/cruntime/math.cpp b/src/pal/src/cruntime/math.cpp
new file mode 100644
index 0000000000..7075fd60f9
--- /dev/null
+++ b/src/pal/src/cruntime/math.cpp
@@ -0,0 +1,424 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ math.cpp
+
+Abstract:
+
+ Implementation of math family functions.
+
+
+
+--*/
+
+#include "pal/palinternal.h"
+#include "pal/dbgmsg.h"
+
+#include <math.h>
+
+#if HAVE_IEEEFP_H
+#include <ieeefp.h>
+#endif // HAVE_IEEEFP_H
+
+#include <errno.h>
+
+#define PAL_NAN_DBL sqrt(-1.0)
+#define PAL_POSINF_DBL -log(0.0)
+#define PAL_NEGINF_DBL log(0.0)
+
+#define IS_DBL_NEGZERO(x) (((*((INT64*)((void*)&x))) & I64(0xFFFFFFFFFFFFFFFF)) == I64(0x8000000000000000))
+
+SET_DEFAULT_DEBUG_CHANNEL(CRT);
+
+/*++
+Function:
+ _finite
+
+Determines whether given double-precision floating point value is finite.
+
+Return Value
+
+_finite returns a nonzero value (TRUE) if its argument x is not
+infinite, that is, if -INF < x < +INF. It returns 0 (FALSE) if the
+argument is infinite or a NaN.
+
+Parameter
+
+x Double-precision floating-point value
+
+--*/
+int __cdecl _finite(double x)
+{
+ int ret;
+ PERF_ENTRY(_finite);
+ ENTRY("_finite (x=%f)\n", x);
+
+#if defined(_IA64_) && defined (_HPUX_)
+ ret = !isnan(x) && (x != PAL_POSINF_DBL) && (x != PAL_NEGINF_DBL);
+#else
+ ret = isfinite(x);
+#endif
+
+ LOGEXIT("_finite returns int %d\n", ret);
+ PERF_EXIT(_finite);
+ return ret;
+}
+
+/*++
+Function:
+ _isnan
+
+See MSDN doc
+--*/
+int __cdecl _isnan(double x)
+{
+ int ret;
+ PERF_ENTRY(_isnan);
+ ENTRY("_isnan (x=%f)\n", x);
+
+ ret = isnan(x);
+
+ LOGEXIT("_isnan returns int %d\n", ret);
+ PERF_EXIT(_isnan);
+ return ret;
+}
+
+/*++
+Function:
+ _copysign
+
+See MSDN doc
+--*/
+double __cdecl _copysign(double x, double y)
+{
+ double ret;
+ PERF_ENTRY(_copysign);
+ ENTRY("_copysign (x=%f, y=%f)\n", x, y);
+
+ ret = copysign(x, y);
+
+ LOGEXIT("_copysign returns double %f\n", ret);
+ PERF_EXIT(_copysign);
+ return ret;
+}
+
+/*++
+Function:
+ acos
+
+See MSDN.
+--*/
+PALIMPORT double __cdecl PAL_acos(double x)
+{
+ double ret;
+ PERF_ENTRY(acos);
+ ENTRY("acos (x=%f)\n", x);
+
+#if !HAVE_COMPATIBLE_ACOS
+ errno = 0;
+#endif // HAVE_COMPATIBLE_ACOS
+
+ ret = acos(x);
+
+#if !HAVE_COMPATIBLE_ACOS
+ if (errno == EDOM)
+ {
+ ret = PAL_NAN_DBL; // NaN
+ }
+#endif // HAVE_COMPATIBLE_ACOS
+
+ LOGEXIT("acos returns double %f\n", ret);
+ PERF_EXIT(acos);
+ return ret;
+}
+
+/*++
+Function:
+ asin
+
+See MSDN.
+--*/
+PALIMPORT double __cdecl PAL_asin(double x)
+{
+ double ret;
+ PERF_ENTRY(asin);
+ ENTRY("asin (x=%f)\n", x);
+
+#if !HAVE_COMPATIBLE_ASIN
+ errno = 0;
+#endif // HAVE_COMPATIBLE_ASIN
+
+ ret = asin(x);
+
+#if !HAVE_COMPATIBLE_ASIN
+ if (errno == EDOM)
+ {
+ ret = PAL_NAN_DBL; // NaN
+ }
+#endif // HAVE_COMPATIBLE_ASIN
+
+ LOGEXIT("asin returns double %f\n", ret);
+ PERF_EXIT(asin);
+ return ret;
+}
+
+/*++
+Function:
+ atan2
+
+See MSDN.
+--*/
+PALIMPORT double __cdecl PAL_atan2(double y, double x)
+{
+ double ret;
+ PERF_ENTRY(atan2);
+ ENTRY("atan2 (y=%f, x=%f)\n", y, x);
+
+#if !HAVE_COMPATIBLE_ATAN2
+ errno = 0;
+#endif // !HAVE_COMPATIBLE_ATAN2
+
+ ret = atan2(y, x);
+
+#if !HAVE_COMPATIBLE_ATAN2
+ if ((errno == EDOM) && (x == 0.0) && (y == 0.0))
+ {
+ const double sign_x = copysign(1.0, x);
+ const double sign_y = copysign(1.0, y);
+
+ if (sign_x > 0)
+ {
+ ret = copysign(0.0, sign_y);
+ }
+ else
+ {
+ ret = copysign(atan2(0.0, -1.0), sign_y);
+ }
+ }
+#endif // !HAVE_COMPATIBLE_ATAN2
+
+ LOGEXIT("atan2 returns double %f\n", ret);
+ PERF_EXIT(atan2);
+ return ret;
+}
+
+/*++
+Function:
+ exp
+
+See MSDN.
+--*/
+PALIMPORT double __cdecl PAL_exp(double x)
+{
+ double ret;
+ PERF_ENTRY(exp);
+ ENTRY("exp (x=%f)\n", x);
+
+#if !HAVE_COMPATIBLE_EXP
+ if (x == 1.0)
+ {
+ ret = M_E;
+ }
+ else
+ {
+#endif // HAVE_COMPATIBLE_EXP
+
+ ret = exp(x);
+
+#if !HAVE_COMPATIBLE_EXP
+ }
+#endif // HAVE_COMPATIBLE_EXP
+
+ LOGEXIT("exp returns double %f\n", ret);
+ PERF_EXIT(exp);
+ return ret;
+}
+
+/*++
+Function:
+ labs
+
+See MSDN.
+--*/
+PALIMPORT LONG __cdecl PAL_labs(LONG l)
+{
+ long lRet;
+ PERF_ENTRY(labs);
+ ENTRY("labs (l=%ld)\n", l);
+
+ lRet = labs(l);
+
+ LOGEXIT("labs returns long %ld\n", lRet);
+ PERF_EXIT(labs);
+ return (LONG)lRet; // This explicit cast to LONG is used to silence any potential warnings due to implicitly casting the native long lRet to LONG when returning.
+}
+
+/*++
+Function:
+ log
+
+See MSDN.
+--*/
+PALIMPORT double __cdecl PAL_log(double x)
+{
+ double ret;
+ PERF_ENTRY(log);
+ ENTRY("log (x=%f)\n", x);
+
+#if !HAVE_COMPATIBLE_LOG
+ errno = 0;
+#endif // !HAVE_COMPATIBLE_LOG
+
+ ret = log(x);
+
+#if !HAVE_COMPATIBLE_LOG
+ if ((errno == EDOM) && (x < 0))
+ {
+ ret = PAL_NAN_DBL; // NaN
+ }
+#endif // !HAVE_COMPATIBLE_LOG
+
+ LOGEXIT("log returns double %f\n", ret);
+ PERF_EXIT(log);
+ return ret;
+}
+
+/*++
+Function:
+ log10
+
+See MSDN.
+--*/
+PALIMPORT double __cdecl PAL_log10(double x)
+{
+ double ret;
+ PERF_ENTRY(log10);
+ ENTRY("log10 (x=%f)\n", x);
+
+#if !HAVE_COMPATIBLE_LOG10
+ errno = 0;
+#endif // !HAVE_COMPATIBLE_LOG10
+
+ ret = log10(x);
+
+#if !HAVE_COMPATIBLE_LOG10
+ if ((errno == EDOM) && (x < 0))
+ {
+ ret = PAL_NAN_DBL; // NaN
+ }
+#endif // !HAVE_COMPATIBLE_LOG10
+
+ LOGEXIT("log10 returns double %f\n", ret);
+ PERF_EXIT(log10);
+ return ret;
+}
+
+/*++
+Function:
+ pow
+
+See MSDN.
+--*/
+PALIMPORT double __cdecl PAL_pow(double x, double y)
+{
+ double ret;
+ PERF_ENTRY(pow);
+ ENTRY("pow (x=%f, y=%f)\n", x, y);
+
+#if !HAVE_COMPATIBLE_POW
+ if ((y == PAL_POSINF_DBL) && !isnan(x)) // +Inf
+ {
+ if (x == 1.0)
+ {
+ ret = x;
+ }
+ else if (x == -1.0)
+ {
+ ret = PAL_NAN_DBL; // NaN
+ }
+ else if ((x > -1.0) && (x < 1.0))
+ {
+ ret = 0.0;
+ }
+ else
+ {
+ ret = PAL_POSINF_DBL; // +Inf
+ }
+ }
+ else if ((y == PAL_NEGINF_DBL) && !isnan(x)) // -Inf
+ {
+ if (x == 1.0)
+ {
+ ret = x;
+ }
+ else if (x == -1.0)
+ {
+ ret = PAL_NAN_DBL; // NaN
+ }
+ else if ((x > -1.0) && (x < 1.0))
+ {
+ ret = PAL_POSINF_DBL; // +Inf
+ }
+ else
+ {
+ ret = 0.0;
+ }
+ }
+ else if (IS_DBL_NEGZERO(x) && (y == -1.0))
+ {
+ ret = PAL_NEGINF_DBL; // -Inf
+ }
+ else if ((x == 0.0) && (y < 0.0))
+ {
+ ret = PAL_POSINF_DBL; // +Inf
+ }
+ else
+#endif // !HAVE_COMPATIBLE_POW
+
+ if ((y == 0.0) && isnan(x))
+ {
+ // Windows returns NaN for pow(NaN, 0), but POSIX specifies
+ // a return value of 1 for that case. We need to return
+ // the same result as Windows.
+ ret = PAL_NAN_DBL;
+ }
+ else
+ {
+ ret = pow(x, y);
+ }
+
+#if !HAVE_VALID_NEGATIVE_INF_POW
+ if ((ret == PAL_POSINF_DBL) && (x < 0) && isfinite(x) && (ceil(y / 2) != floor(y / 2)))
+ {
+ ret = PAL_NEGINF_DBL; // -Inf
+ }
+#endif // !HAVE_VALID_NEGATIVE_INF_POW
+
+#if !HAVE_VALID_POSITIVE_INF_POW
+ /*
+ * The even/odd test in the if (this one and the one above) used to be ((long long) y % 2 == 0)
+ * on SPARC (long long) y for large y (>2**63) is always 0x7fffffff7fffffff, which
+ * is an odd number, so the test ((long long) y % 2 == 0) will always fail for
+ * large y. Since large double numbers are always even (e.g., the representation of
+ * 1E20+1 is the same as that of 1E20, the last .+1. is too insignificant to be part
+ * of the representation), this test will always return the wrong result for large y.
+ *
+ * The (ceil(y/2) == floor(y/2)) test is slower, but more robust.
+ */
+ if ((ret == PAL_NEGINF_DBL) && (x < 0) && isfinite(x) && (ceil(y / 2) == floor(y / 2)))
+ {
+ ret = PAL_POSINF_DBL; // +Inf
+ }
+#endif // !HAVE_VALID_POSITIVE_INF_POW
+
+ LOGEXIT("pow returns double %f\n", ret);
+ PERF_EXIT(pow);
+ return ret;
+}
diff --git a/src/pal/src/cruntime/mbstring.cpp b/src/pal/src/cruntime/mbstring.cpp
new file mode 100644
index 0000000000..dd4bcbbdce
--- /dev/null
+++ b/src/pal/src/cruntime/mbstring.cpp
@@ -0,0 +1,257 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ mbstring.c
+
+Abstract:
+
+ Implementation of the multi-byte string functions in the C runtime library that
+ are Windows specific.
+
+Implementation Notes:
+
+ Assuming it is not possible to change multi-byte code page using
+ the PAL (_setmbcp does not seem to be required), these functions
+ should have a trivial implementation (treat as single-byte). If it
+ is possible, then support for multi-byte code pages will have to
+ be implemented before these functions can behave correctly for
+ multi-byte strings.
+
+
+
+--*/
+
+#include "pal/palinternal.h"
+#include "pal/dbgmsg.h"
+
+
+SET_DEFAULT_DEBUG_CHANNEL(CRT);
+
+
+/*++
+Function:
+ _mbslen
+
+Determines the number of characters (code points) in a multibyte
+character string.
+
+Parameters
+
+string Points to a multibyte character string.
+
+Return Values
+
+The mbslen subroutine returns the number of multibyte characters in a
+multibyte character string. It returns 0 if the string parameter
+points to a null character or if a character cannot be formed from the
+string pointed to by this parameter.
+
+--*/
+size_t
+__cdecl
+_mbslen(
+ const unsigned char *string)
+{
+ size_t ret = 0;
+ CPINFO cpinfo;
+ PERF_ENTRY(_mbslen);
+ ENTRY("_mbslen (string=%p (%s))\n", string, string);
+
+ if (string)
+ {
+ if (GetCPInfo(CP_ACP, &cpinfo) && cpinfo.MaxCharSize == 1)
+ {
+ ret = strlen((const char*)string);
+ }
+ else
+ {
+ while (*string)
+ {
+ if (IsDBCSLeadByteEx(CP_ACP, *string))
+ {
+ ++string;
+ }
+ ++string;
+ ++ret;
+ }
+ }
+ }
+
+ LOGEXIT("_mbslen returning size_t %u\n", ret);
+ PERF_EXIT(_mbslen);
+ return ret;
+}
+
+/*++
+Function:
+ _mbsinc
+
+Return Value
+
+Returns a pointer to the character that immediately follows string.
+
+Parameter
+
+string Character pointer
+
+Remarks
+
+The _mbsinc function returns a pointer to the first byte of the
+multibyte character that immediately follows string.
+
+--*/
+unsigned char *
+__cdecl
+_mbsinc(
+ const unsigned char *string)
+{
+ unsigned char *ret;
+
+ PERF_ENTRY(_mbsinc);
+ ENTRY("_mbsinc (string=%p)\n", string);
+
+ if (string == NULL)
+ {
+ ret = NULL;
+ }
+ else
+ {
+ ret = (unsigned char *) string;
+ if (IsDBCSLeadByteEx(CP_ACP, *ret))
+ {
+ ++ret;
+ }
+ ++ret;
+ }
+
+ LOGEXIT("_mbsinc returning unsigned char* %p (%s)\n", ret, ret);
+ PERF_EXIT(_mbsinc);
+ return ret;
+}
+
+
+/*++
+Function:
+ _mbsninc
+
+Return Value
+
+Returns a pointer to string after string has been incremented by count
+characters, or NULL if the supplied pointer is NULL. If count is
+greater than or equal to the number of characters in string, the
+result is undefined.
+
+Parameters
+
+string Source string
+count Number of characters to increment string pointer
+
+Remarks
+
+The _mbsninc function increments string by count multibyte
+characters. _mbsninc recognizes multibyte-character sequences
+according to the multibyte code page currently in use.
+
+--*/
+unsigned char *
+__cdecl
+_mbsninc(
+ const unsigned char *string, size_t count)
+{
+ unsigned char *ret;
+ CPINFO cpinfo;
+
+ PERF_ENTRY(_mbsninc);
+ ENTRY("_mbsninc (string=%p, count=%lu)\n", string, count);
+ if (string == NULL)
+ {
+ ret = NULL;
+ }
+ else
+ {
+ ret = (unsigned char *) string;
+ if (GetCPInfo(CP_ACP, &cpinfo) && cpinfo.MaxCharSize == 1)
+ {
+ ret += min(count, strlen((const char*)string));
+ }
+ else
+ {
+ while (count-- && (*ret != 0))
+ {
+ if (IsDBCSLeadByteEx(CP_ACP, *ret))
+ {
+ ++ret;
+ }
+ ++ret;
+ }
+ }
+ }
+ LOGEXIT("_mbsninc returning unsigned char* %p (%s)\n", ret, ret);
+ PERF_EXIT(_mbsninc);
+ return ret;
+}
+
+/*++
+Function:
+ _mbsdec
+
+Return Value
+
+_mbsdec returns a pointer to the character that immediately precedes
+current; _mbsdec returns NULL if the value of start is greater than or
+equal to that of current.
+
+Parameters
+
+start Pointer to first byte of any multibyte character in the source
+ string; start must precede current in the source string
+
+current Pointer to first byte of any multibyte character in the source
+ string; current must follow start in the source string
+
+--*/
+unsigned char *
+__cdecl
+_mbsdec(
+ const unsigned char *start,
+ const unsigned char *current)
+{
+ unsigned char *ret;
+ unsigned char *strPtr;
+ CPINFO cpinfo;
+
+ PERF_ENTRY(_mbsdec);
+ ENTRY("_mbsdec (start=%p, current=%p)\n", start, current);
+
+ if (current <= start)
+ {
+ ret = NULL;
+ }
+ else if (GetCPInfo(CP_ACP, &cpinfo) && cpinfo.MaxCharSize == 1)
+ {
+ ret = (unsigned char *) current - 1;
+ }
+ else
+ {
+ ret = strPtr = (unsigned char *) start;
+ while (strPtr < current)
+ {
+ ret = strPtr;
+ if (IsDBCSLeadByteEx(CP_ACP, *strPtr))
+ {
+ ++strPtr;
+ }
+ ++strPtr;
+ }
+ }
+ LOGEXIT("_mbsdec returning unsigned int %p (%s)\n", ret, ret);
+ PERF_EXIT(_mbsdec);
+ return ret;
+}
diff --git a/src/pal/src/cruntime/misc.cpp b/src/pal/src/cruntime/misc.cpp
new file mode 100644
index 0000000000..9e5acf65ff
--- /dev/null
+++ b/src/pal/src/cruntime/misc.cpp
@@ -0,0 +1,314 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ cruntime/misc.cpp
+
+Abstract:
+
+ Implementation of C runtime functions that don't fit anywhere else.
+
+
+
+--*/
+
+#include "pal/thread.hpp"
+#include "pal/threadsusp.hpp"
+#include "pal/palinternal.h"
+#include "pal/dbgmsg.h"
+#include "pal/misc.h"
+
+#include <errno.h>
+/* <stdarg.h> needs to be included after "palinternal.h" to avoid name
+ collision for va_start and va_end */
+#include <stdarg.h>
+#include <time.h>
+#include <limits.h>
+
+#if defined(_AMD64_) || defined(_x86_)
+#include <xmmintrin.h>
+#endif // defined(_AMD64_) || defined(_x86_)
+#if defined(_DEBUG)
+#include <assert.h>
+#endif //defined(_DEBUG)
+
+SET_DEFAULT_DEBUG_CHANNEL(CRT);
+
+using namespace CorUnix;
+
+/*++
+Function:
+ _gcvt_s
+
+See MSDN doc.
+--*/
+char *
+__cdecl
+_gcvt_s( char * buffer, int iSize, double value, int digits )
+{
+ PERF_ENTRY(_gcvt);
+ ENTRY( "_gcvt( value:%f digits=%d, buffer=%p )\n", value, digits, buffer );
+
+ if ( !buffer )
+ {
+ ERROR( "buffer was an invalid pointer.\n" );
+ }
+
+ switch ( digits )
+ {
+ case 7 :
+ /* Fall through */
+ case 8 :
+ /* Fall through */
+ case 15 :
+ /* Fall through */
+ case 17 :
+
+ sprintf_s( buffer, iSize, "%.*g", digits, value );
+ break;
+
+ default :
+ ASSERT( "Only the digits 7, 8, 15, and 17 are valid.\n" );
+ *buffer = '\0';
+ }
+
+ LOGEXIT( "_gcvt returns %p (%s)\n", buffer , buffer );
+ PERF_EXIT(_gcvt);
+ return buffer;
+}
+
+
+/*++
+Function :
+
+ __iscsym
+
+See MSDN for more details.
+--*/
+int
+__cdecl
+__iscsym( int c )
+{
+ PERF_ENTRY(__iscsym);
+ ENTRY( "__iscsym( c=%d )\n", c );
+
+ if ( isalnum( c ) || c == '_' )
+ {
+ LOGEXIT( "__iscsym returning 1\n" );
+ PERF_EXIT(__iscsym);
+ return 1;
+ }
+
+ LOGEXIT( "__iscsym returning 0\n" );
+ PERF_EXIT(__iscsym);
+ return 0;
+}
+
+
+/*++
+
+Function :
+
+ PAL_errno
+
+ Returns the address of the errno.
+
+--*/
+int * __cdecl PAL_errno( int caller )
+{
+ int *retval;
+ PERF_ENTRY(errno);
+ ENTRY( "PAL_errno( void )\n" );
+ retval = (INT*)(&errno);
+ LOGEXIT("PAL_errno returns %p\n",retval);
+ PERF_EXIT(errno);
+ return retval;
+}
+
+/*++
+Function:
+
+ mktime
+
+See MSDN for more details.
+--*/
+
+PAL_time_t
+__cdecl
+PAL_mktime(struct PAL_tm *tm)
+{
+ time_t result;
+ struct tm tmpTm;
+
+ PERF_ENTRY(mktime);
+ ENTRY( "mktime( tm=%p )\n",tm );
+
+ /*copy the value of Windows struct into BSD struct*/
+ tmpTm.tm_sec = tm->tm_sec;
+ tmpTm.tm_min = tm->tm_min;
+ tmpTm.tm_hour = tm->tm_hour;
+ tmpTm.tm_mday = tm->tm_mday;
+ tmpTm.tm_mon = tm->tm_mon;
+ tmpTm.tm_year = tm->tm_year;
+ tmpTm.tm_wday = tm->tm_wday;
+ tmpTm.tm_yday = tm->tm_yday;
+ tmpTm.tm_isdst = tm->tm_isdst;
+
+ result = mktime(&tmpTm);
+
+ LOGEXIT( "mktime returned %#lx\n",result );
+ PERF_EXIT(mktime);
+ return result;
+}
+
+/*++
+Function:
+
+ rand
+
+ The RAND_MAX value can vary by platform.
+
+See MSDN for more details.
+--*/
+int
+__cdecl
+PAL_rand(void)
+{
+ int ret;
+ PERF_ENTRY(rand);
+ ENTRY("rand(void)\n");
+
+ ret = (rand() % (PAL_RAND_MAX + 1));
+
+ LOGEXIT("rand() returning %d\n", ret);
+ PERF_EXIT(rand);
+ return ret;
+}
+
+
+/*++
+Function:
+
+ time
+
+See MSDN for more details.
+--*/
+PAL_time_t
+__cdecl
+PAL_time(PAL_time_t *tloc)
+{
+ time_t result;
+
+ PERF_ENTRY(time);
+ ENTRY( "time( tloc=%p )\n",tloc );
+
+ result = time(tloc);
+
+ LOGEXIT( "time returning %#lx\n",result );
+ PERF_EXIT(time);
+ return result;
+}
+
+
+PALIMPORT
+void __cdecl
+PAL_qsort(void *base, size_t nmemb, size_t size,
+ int (__cdecl *compar )(const void *, const void *))
+{
+ PERF_ENTRY(qsort);
+ ENTRY("qsort(base=%p, nmemb=%lu, size=%lu, compar=%p\n",
+ base,(unsigned long) nmemb,(unsigned long) size, compar);
+
+/* reset ENTRY nesting level back to zero, qsort will invoke app-defined
+ callbacks and we want their entry traces... */
+#if _ENABLE_DEBUG_MESSAGES_
+{
+ int old_level;
+ old_level = DBG_change_entrylevel(0);
+#endif /* _ENABLE_DEBUG_MESSAGES_ */
+
+ qsort(base,nmemb,size,compar);
+
+/* ...and set nesting level back to what it was */
+#if _ENABLE_DEBUG_MESSAGES_
+ DBG_change_entrylevel(old_level);
+}
+#endif /* _ENABLE_DEBUG_MESSAGES_ */
+
+ LOGEXIT("qsort returns\n");
+ PERF_EXIT(qsort);
+}
+
+PALIMPORT
+void * __cdecl
+PAL_bsearch(const void *key, const void *base, size_t nmemb, size_t size,
+ int (__cdecl *compar)(const void *, const void *))
+{
+ void *retval;
+
+ PERF_ENTRY(bsearch);
+ ENTRY("bsearch(key=%p, base=%p, nmemb=%lu, size=%lu, compar=%p\n",
+ key, base, (unsigned long) nmemb, (unsigned long) size, compar);
+
+/* reset ENTRY nesting level back to zero, bsearch will invoke app-defined
+ callbacks and we want their entry traces... */
+#if _ENABLE_DEBUG_MESSAGES_
+{
+ int old_level;
+ old_level = DBG_change_entrylevel(0);
+#endif /* _ENABLE_DEBUG_MESSAGES_ */
+
+ retval = bsearch(key,base,nmemb,size,compar);
+
+/* ...and set nesting level back to what it was */
+#if _ENABLE_DEBUG_MESSAGES_
+ DBG_change_entrylevel(old_level);
+}
+#endif /* _ENABLE_DEBUG_MESSAGES_ */
+
+ LOGEXIT("bsearch returns %p\n",retval);
+ PERF_EXIT(bsearch);
+ return retval;
+}
+
+#ifdef _AMD64_
+
+PALIMPORT
+unsigned int PAL__mm_getcsr(void)
+{
+ return _mm_getcsr();
+}
+
+PALIMPORT
+void PAL__mm_setcsr(unsigned int i)
+{
+ _mm_setcsr(i);
+}
+
+#endif // _AMD64_
+
+/*++
+Function:
+PAL_memcpy
+
+Overlapping buffer-safe version of memcpy.
+See MSDN doc for memcpy
+--*/
+EXTERN_C
+PALIMPORT
+void *PAL_memcpy (void *dest, const void *src, size_t count)
+{
+ UINT_PTR x = (UINT_PTR)dest, y = (UINT_PTR)src;
+ _ASSERTE((x + count <= y) || (y + count <= x));
+
+ void *ret;
+ #undef memcpy
+ ret = memcpy(dest, src, count);
+ return ret;
+}
diff --git a/src/pal/src/cruntime/misctls.cpp b/src/pal/src/cruntime/misctls.cpp
new file mode 100644
index 0000000000..e46582ec17
--- /dev/null
+++ b/src/pal/src/cruntime/misctls.cpp
@@ -0,0 +1,399 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ cruntime/misctls.ccpp
+
+Abstract:
+
+ Implementation of C runtime functions that don't fit anywhere else
+ and depend on per-thread data
+
+
+
+--*/
+
+#include "pal/thread.hpp"
+#include "pal/palinternal.h"
+
+extern "C"
+{
+#include "pal/dbgmsg.h"
+#include "pal/misc.h"
+}
+
+#include <errno.h>
+/* <stdarg.h> needs to be included after "palinternal.h" to avoid name
+ collision for va_start and va_end */
+#include <stdarg.h>
+#include <time.h>
+#if HAVE_CRT_EXTERNS_H
+#include <crt_externs.h>
+#endif // HAVE_CRT_EXTERNS_H
+
+using namespace CorUnix;
+
+SET_DEFAULT_DEBUG_CHANNEL(CRT);
+
+/*++
+Function:
+
+ localtime
+
+See MSDN for more details.
+--*/
+
+struct PAL_tm *
+__cdecl
+PAL_localtime(const PAL_time_t *clock)
+{
+ CPalThread *pThread = NULL;
+ struct tm tmpResult;
+ struct PAL_tm *result = NULL;
+
+ PERF_ENTRY(localtime);
+ ENTRY( "localtime( clock=%p )\n",clock );
+
+ /* Get the per-thread buffer from the thread structure. */
+ pThread = InternalGetCurrentThread();
+
+ result = &pThread->crtInfo.localtimeBuffer;
+
+ localtime_r(reinterpret_cast<const time_t*>(clock), &tmpResult);
+
+ // Copy the result into the Windows struct.
+ result->tm_sec = tmpResult.tm_sec;
+ result->tm_min = tmpResult.tm_min;
+ result->tm_hour = tmpResult.tm_hour;
+ result->tm_mday = tmpResult.tm_mday;
+ result->tm_mon = tmpResult.tm_mon;
+ result->tm_year = tmpResult.tm_year;
+ result->tm_wday = tmpResult.tm_wday;
+ result->tm_yday = tmpResult.tm_yday;
+ result->tm_isdst = tmpResult.tm_isdst;
+
+ LOGEXIT( "localtime returned %p\n", result );
+ PERF_EXIT(localtime);
+
+ return result;
+}
+
+/*++
+Function:
+
+ ctime
+
+ There appears to be a difference between the FreeBSD and windows
+ implementations. FreeBSD gives Wed Dec 31 18:59:59 1969 for a
+ -1 param, and Windows returns NULL
+
+See MSDN for more details.
+--*/
+char *
+__cdecl
+PAL_ctime( const PAL_time_t *clock )
+{
+ CPalThread *pThread = NULL;
+ char * retval = NULL;
+
+ PERF_ENTRY(ctime);
+ ENTRY( "ctime( clock=%p )\n",clock );
+ if(*clock < 0)
+ {
+ /*If the input param is less than zero the value
+ *returned is less than the Unix epoch
+ *1st of January 1970*/
+ WARN("The input param is less than zero");
+ goto done;
+ }
+
+ /* Get the per-thread buffer from the thread structure. */
+ pThread = InternalGetCurrentThread();
+
+ retval = pThread->crtInfo.ctimeBuffer;
+
+ ctime_r(reinterpret_cast<const time_t*>(clock),retval);
+
+done:
+
+ LOGEXIT( "ctime() returning %p (%s)\n",retval,retval);
+ PERF_EXIT(ctime);
+
+ return retval;
+}
+
+/**
+Function:
+
+ _ecvt
+
+See MSDN for more information.
+
+NOTES:
+ There is a difference between PAL _ecvt and Win32 _ecvt.
+
+ If Window's _ecvt receives a double 0.000000000000000000005, and count 50
+ the result is "49999999999999998000000000000000000000000000000000"
+
+ Under BSD the same call will result in :
+ 49999999999999998021734900744965462766153934333829
+
+ The difference is due to the difference between BSD and Win32 sprintf.
+
+--*/
+char * __cdecl
+_ecvt( double value, int count, int * dec, int * sign )
+{
+ CONST CHAR * FORMAT_STRING = "%.348e";
+ CHAR TempBuffer[ ECVT_MAX_BUFFER_SIZE ];
+ CPalThread *pThread = NULL;
+ LPSTR lpReturnBuffer = NULL;
+ LPSTR lpStartOfReturnBuffer = NULL;
+ LPSTR lpTempBuffer = NULL;
+ LPSTR lpEndOfTempBuffer = NULL;
+ INT nTempBufferLength = 0;
+ CHAR ExponentBuffer[ 6 ];
+ INT nExponentValue = 0;
+ INT LoopIndex = 0;
+
+ PERF_ENTRY(_ecvt);
+ ENTRY( "_ecvt( value=%.30g, count=%d, dec=%p, sign=%p )\n",
+ value, count, dec, sign );
+
+ /* Get the per-thread buffer from the thread structure. */
+ pThread = InternalGetCurrentThread();
+
+ lpStartOfReturnBuffer = lpReturnBuffer = pThread->crtInfo.ECVTBuffer;
+
+ /* Sanity checks */
+ if ( !dec || !sign )
+ {
+ ERROR( "dec and sign have to be valid pointers.\n" );
+ *lpReturnBuffer = '\0';
+ goto done;
+ }
+ else
+ {
+ *dec = *sign = 0;
+ }
+
+ if ( value < 0.0 )
+ {
+ *sign = 1;
+ }
+
+ if ( count > ECVT_MAX_COUNT_SIZE )
+ {
+ count = ECVT_MAX_COUNT_SIZE;
+ }
+
+ /* Get the string to work with. */
+ sprintf_s( TempBuffer, sizeof(TempBuffer), FORMAT_STRING, value );
+
+ /* Check to see if value was a valid number. */
+ if ( strcmp( "NaN", TempBuffer ) == 0 || strcmp( "-NaN", TempBuffer ) == 0 )
+ {
+ TRACE( "value was not a number!\n" );
+ if (strcpy_s( lpStartOfReturnBuffer, ECVT_MAX_BUFFER_SIZE, "1#QNAN0" ) != SAFECRT_SUCCESS)
+ {
+ ERROR( "strcpy_s failed!\n" );
+ *lpStartOfReturnBuffer = '\0';
+ goto done;
+ }
+
+ *dec = 1;
+ goto done;
+ }
+
+ /* Check to see if it is infinite. */
+ if ( strcmp( "Inf", TempBuffer ) == 0 || strcmp( "-Inf", TempBuffer ) == 0 )
+ {
+ TRACE( "value is infinite!\n" );
+ if (strcpy_s( lpStartOfReturnBuffer, ECVT_MAX_BUFFER_SIZE, "1#INF00" ) != SAFECRT_SUCCESS)
+ {
+ ERROR( "strcpy_s failed!\n" );
+ *lpStartOfReturnBuffer = '\0';
+ goto done;
+ }
+
+ *dec = 1;
+ if ( *TempBuffer == '-' )
+ {
+ *sign = 1;
+ }
+ goto done;
+ }
+
+ nTempBufferLength = strlen( TempBuffer );
+ lpEndOfTempBuffer = &(TempBuffer[ nTempBufferLength ]);
+
+ /* Extract the exponent, and convert it to integer. */
+ while ( *lpEndOfTempBuffer != 'e' && nTempBufferLength > 0 )
+ {
+ nTempBufferLength--;
+ lpEndOfTempBuffer--;
+ }
+
+ ExponentBuffer[ 0 ] = '\0';
+ if (strncat_s( ExponentBuffer, sizeof(ExponentBuffer), lpEndOfTempBuffer + 1, 5 ) != SAFECRT_SUCCESS)
+ {
+ ERROR( "strncat_s failed!\n" );
+ *lpStartOfReturnBuffer = '\0';
+ goto done;
+ }
+
+ nExponentValue = atoi( ExponentBuffer );
+
+ /* End the string at the 'e' */
+ *lpEndOfTempBuffer = '\0';
+ nTempBufferLength--;
+
+ /* Determine decimal location. */
+ if ( nExponentValue == 0 )
+ {
+ *dec = 1;
+ }
+ else
+ {
+ *dec = nExponentValue + 1;
+ }
+
+ if ( value == 0.0 )
+ {
+ *dec = 0;
+ }
+ /* Copy the string from the temp buffer upto count characters,
+ removing the sign, and decimal as required. */
+ lpTempBuffer = TempBuffer;
+ *lpReturnBuffer = '0';
+ lpReturnBuffer++;
+
+ while ( LoopIndex < ECVT_MAX_COUNT_SIZE )
+ {
+ if ( isdigit(*lpTempBuffer) )
+ {
+ *lpReturnBuffer = *lpTempBuffer;
+ LoopIndex++;
+ lpReturnBuffer++;
+ }
+ lpTempBuffer++;
+
+ if ( LoopIndex == count + 1 )
+ {
+ break;
+ }
+ }
+
+ *lpReturnBuffer = '\0';
+
+ /* Round if needed. If count is less then 0
+ then windows does not round for some reason.*/
+ nTempBufferLength = strlen( lpStartOfReturnBuffer ) - 1;
+
+ /* Add one for the preceeding zero. */
+ lpReturnBuffer = ( lpStartOfReturnBuffer + 1 );
+
+ if ( nTempBufferLength >= count && count >= 0 )
+ {
+ /* Determine whether I need to round up. */
+ if ( *(lpReturnBuffer + count) >= '5' )
+ {
+ CHAR cNumberToBeRounded;
+ if ( count != 0 )
+ {
+ cNumberToBeRounded = *(lpReturnBuffer + count - 1);
+ }
+ else
+ {
+ cNumberToBeRounded = *lpReturnBuffer;
+ }
+
+ if ( cNumberToBeRounded < '9' )
+ {
+ if ( count > 0 )
+ {
+ /* Add one to the character. */
+ (*(lpReturnBuffer + count - 1))++;
+ }
+ else
+ {
+ if ( cNumberToBeRounded >= '5' )
+ {
+ (*dec)++;
+ }
+ }
+ }
+ else
+ {
+ LPSTR lpRounding = NULL;
+
+ if ( count > 0 )
+ {
+ lpRounding = lpReturnBuffer + count - 1;
+ }
+ else
+ {
+ lpRounding = lpReturnBuffer + count;
+ }
+
+ while ( cNumberToBeRounded == '9' )
+ {
+ cNumberToBeRounded = *lpRounding;
+
+ if ( cNumberToBeRounded == '9' )
+ {
+ *lpRounding = '0';
+ lpRounding--;
+ }
+ }
+
+ if ( lpRounding == lpStartOfReturnBuffer )
+ {
+ /* Overflow. number is a whole number now. */
+ *lpRounding = '1';
+ memset( ++lpRounding, '0', count);
+
+ /* The decimal has moved. */
+ (*dec)++;
+ }
+ else
+ {
+ *lpRounding = ++cNumberToBeRounded;
+ }
+ }
+ }
+ else
+ {
+ /* Get rid of the preceding 0 */
+ lpStartOfReturnBuffer++;
+ }
+ }
+
+ if ( *lpStartOfReturnBuffer == '0' )
+ {
+ lpStartOfReturnBuffer++;
+ }
+
+ if ( count >= 0 )
+ {
+ *(lpStartOfReturnBuffer + count) = '\0';
+ }
+ else
+ {
+ *lpStartOfReturnBuffer = '\0';
+ }
+
+done:
+
+ LOGEXIT( "_ecvt returning %p (%s)\n", lpStartOfReturnBuffer , lpStartOfReturnBuffer );
+ PERF_EXIT(_ecvt);
+
+ return lpStartOfReturnBuffer;
+}
+
diff --git a/src/pal/src/cruntime/path.cpp b/src/pal/src/cruntime/path.cpp
new file mode 100644
index 0000000000..e5b955ebd9
--- /dev/null
+++ b/src/pal/src/cruntime/path.cpp
@@ -0,0 +1,596 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ path.c
+
+Abstract:
+
+ Implementation of path functions part of Windows runtime library.
+
+Revision History:
+
+
+
+--*/
+
+#include "pal/palinternal.h"
+#include "pal/dbgmsg.h"
+#include "pal/file.h"
+#include "pal/printfcpp.hpp"
+
+#include <string.h>
+#include <stdlib.h>
+#include <sys/param.h>
+#include <errno.h>
+#include <limits.h>
+
+SET_DEFAULT_DEBUG_CHANNEL(CRT);
+
+
+/* ON_ERROR. A Helper macro for _?splitpath functions. */
+#define ON_ERROR if ( drive ) \
+ {\
+ drive[0] = 0;\
+ }\
+ if(dir)\
+ {\
+ dir[0] = 0;\
+ }\
+ if(fname)\
+ {\
+ fname[0] = 0;\
+ }\
+ if(ext)\
+ {\
+ ext[0] = 0;\
+ }\
+ goto done;\
+
+/*++
+Function:
+ _wsplitpath
+
+See MSDN doc.
+
+Notes :
+ This implementation ignores drive letters as they should not be
+ present. If the drive argument is non-NULL, it always returns an empty
+ string.
+ File names in which the only period is at the beginning (like .bashrc, but
+ not .bashrc.bak), the file is treated as having no extension
+ (fname is ".bashrc", ext is "")
+
+--*/
+void
+__cdecl
+_wsplitpath(
+ const wchar_16 *dospath,
+ wchar_16 *drive,
+ wchar_16 *dir,
+ wchar_16 *fname,
+ wchar_16 *ext)
+{
+ WCHAR path[_MAX_PATH+1];
+ LPCWSTR slash_ptr = NULL;
+ LPCWSTR period_ptr = NULL;
+ INT size = 0;
+
+ PERF_ENTRY(_wsplitpath);
+ ENTRY("_wsplitpath (path=%p (%S), drive=%p, dir=%p, fname=%p, ext=%p)\n",
+ dospath?dospath:W16_NULLSTRING,
+ dospath?dospath:W16_NULLSTRING, drive, dir, fname, ext);
+
+ /* Do performance intensive error checking only in debug builds.
+
+ NOTE: This function must fail predictably across all platforms.
+ Under Windows this function throw an access violation if NULL
+ was passed in as the value for path.
+
+ */
+#if _DEBUG
+ if ( !dospath )
+ {
+ ERROR( "path cannot be NULL!\n" );
+ }
+#endif
+
+ if( lstrlenW( dospath ) >= _MAX_PATH )
+ {
+ ERROR("Path length is > _MAX_PATH (%d)!\n", _MAX_PATH);
+ ON_ERROR;
+ }
+
+
+ PAL_wcscpy(path, dospath);
+ FILEDosToUnixPathW(path);
+
+ /* no drive letters in the PAL */
+ if( drive != NULL )
+ {
+ drive[0] = 0;
+ }
+
+ /* find last path separator char */
+ slash_ptr = PAL_wcsrchr(path, '/');
+
+ if( slash_ptr == NULL )
+ {
+ TRACE("No path separator in path\n");
+ slash_ptr = path - 1;
+ }
+ /* find extension separator, if any */
+ period_ptr = PAL_wcsrchr(path, '.');
+
+ /* make sure we only consider periods after the last path separator */
+ if( period_ptr < slash_ptr )
+ {
+ period_ptr = NULL;
+ }
+
+ /* if the only period in the file is a leading period (denoting a hidden
+ file), don't treat what follows as an extension */
+ if( period_ptr == slash_ptr+1 )
+ {
+ period_ptr = NULL;
+ }
+
+ if( period_ptr == NULL )
+ {
+ TRACE("No extension in path\n");
+ period_ptr = path + lstrlenW(path);
+ }
+
+ size = slash_ptr - path + 1;
+ if( dir != NULL )
+ {
+ INT i;
+
+ if( (size + 1 ) > _MAX_DIR )
+ {
+ ERROR("Directory component needs %d characters, _MAX_DIR is %d\n",
+ size+1, _MAX_DIR);
+ ON_ERROR;
+ }
+
+ memcpy(dir, path, size*sizeof(WCHAR));
+ dir[size] = 0;
+
+ /* only allow / separators in returned path */
+ i = 0;
+ while( dir[ i ] )
+ {
+ if( dir[ i ] == '\\' )
+ {
+ dir[i]='/';
+ }
+ i++;
+ }
+ }
+
+ size = period_ptr-slash_ptr-1;
+ if( fname != NULL )
+ {
+ if( (size+1) > _MAX_FNAME )
+ {
+ ERROR("Filename component needs %d characters, _MAX_FNAME is %d\n",
+ size+1, _MAX_FNAME);
+ ON_ERROR;
+ }
+ memcpy(fname, slash_ptr+1, size*sizeof(WCHAR));
+ fname[size] = 0;
+ }
+
+ size = 1 + lstrlenW( period_ptr );
+ if( ext != NULL )
+ {
+ if( size > _MAX_EXT )
+ {
+ ERROR("Extension component needs %d characters, _MAX_EXT is %d\n",
+ size, _MAX_EXT);
+ ON_ERROR;
+ }
+ memcpy(ext, period_ptr, size*sizeof(WCHAR));
+ ext[size-1] = 0;
+ }
+
+ TRACE("Path components are '%S' '%S' '%S'\n", dir, fname, ext);
+
+done:
+
+ LOGEXIT("_wsplitpath returns.\n");
+ PERF_EXIT(_wsplitpath);
+}
+
+
+/*++
+Function:
+ _splitpath
+
+See description above for _wsplitpath.
+
+--*/
+void
+__cdecl
+_splitpath(
+ const char *path,
+ char *drive,
+ char *dir,
+ char *fname,
+ char *ext)
+{
+ WCHAR w_path[_MAX_PATH];
+ WCHAR w_dir[_MAX_DIR];
+ WCHAR w_fname[_MAX_FNAME];
+ WCHAR w_ext[_MAX_EXT];
+
+ PERF_ENTRY(_splitpath);
+ ENTRY("_splitpath (path=%p (%s), drive=%p, dir=%p, fname=%p, ext=%p)\n",
+ path?path:"NULL",
+ path?path:"NULL", drive, dir, fname, ext);
+
+ /* Do performance intensive error checking only in debug builds.
+
+ NOTE: This function must fail predictably across all platforms.
+ Under Windows this function throw an access violation if NULL
+ was passed in as the value for path.
+
+ */
+#if _DEBUG
+ if ( !path )
+ {
+ ERROR( "path cannot be NULL!\n" );
+ }
+
+ if( strlen( path ) >= _MAX_PATH )
+ {
+ ERROR( "Path length is > _MAX_PATH (%d)!\n", _MAX_PATH);
+ }
+#endif
+
+ /* no drive letters in the PAL */
+ if(drive)
+ {
+ drive[0] = '\0';
+ }
+
+ if(0 == MultiByteToWideChar(CP_ACP, 0, path, -1, w_path, _MAX_PATH))
+ {
+ ASSERT("MultiByteToWideChar failed!\n");
+ ON_ERROR;
+ }
+
+ /* Call up to Unicode version; pass NULL for parameters the caller doesn't
+ care about */
+ _wsplitpath(w_path, NULL, dir?w_dir:NULL,
+ fname?w_fname:NULL, ext?w_ext:NULL);
+
+ /* Convert result back to MultiByte; report conversion errors but don't
+ stop because of them */
+
+ if(dir)
+ {
+ if(0 == WideCharToMultiByte(CP_ACP, 0, w_dir, -1, dir, _MAX_DIR,
+ NULL, NULL))
+ {
+ ASSERT("WideCharToMultiByte failed!\n");
+ ON_ERROR;
+ }
+ }
+ if(fname)
+ {
+ if(0 == WideCharToMultiByte(CP_ACP, 0, w_fname, -1, fname, _MAX_FNAME,
+ NULL, NULL))
+ {
+ ASSERT("WideCharToMultiByte failed!\n");
+ ON_ERROR;
+ }
+ }
+ if(ext)
+ {
+ if(0 == WideCharToMultiByte(CP_ACP, 0, w_ext, -1, ext, _MAX_EXT,
+ NULL, NULL))
+ {
+ ASSERT("WideCharToMultiByte failed!\n");
+ ON_ERROR;
+ }
+ }
+
+done:
+ LOGEXIT("_splitpath returns.\n");
+ PERF_EXIT(_splitpath);
+}
+
+
+
+/*++
+Function:
+ _makepath
+
+See MSDN doc.
+
+--*/
+void
+__cdecl
+_makepath(
+ char *path,
+ const char *drive,
+ const char *dir,
+ const char *fname,
+ const char *ext)
+{
+ UINT Length = 0;
+
+ PERF_ENTRY(_makepath);
+ ENTRY( "_makepath (path=%p, drive=%p (%s), dir=%p (%s), fname=%p (%s), ext=%p (%s))\n",
+ path, drive ? drive:"NULL", drive ? drive:"NULL", dir ? dir:"NULL", dir ? dir:"NULL", fname ? fname:"NULL", fname ? fname:"NULL",
+ ext ? ext:"NULL",
+ ext ? ext:"NULL");
+
+ path[ 0 ] = '\0';
+
+ /* According to the pal documentation, host operating systems that
+ don't support drive letters, the "drive" parameter must always be null. */
+ if ( drive != NULL && drive[0] != '\0' )
+ {
+ ASSERT( "The drive parameter must always be NULL on systems that don't"
+ "support drive letters. drive is being ignored!.\n" );
+ }
+
+ if ( dir != NULL && dir[ 0 ] != '\0' )
+ {
+ UINT DirLength = strlen( dir );
+ Length += DirLength ;
+
+ if ( Length < _MAX_PATH )
+ {
+ strncat( path, dir, DirLength );
+ if ( dir[ DirLength - 1 ] != '/' && dir[ DirLength - 1 ] != '\\' )
+ {
+ if ( Length + 1 < _MAX_PATH )
+ {
+ path[ Length ] = '/';
+ Length++;
+ path[ Length ] = '\0';
+ }
+ else
+ {
+ goto Max_Path_Error;
+ }
+ }
+ }
+ else
+ {
+ goto Max_Path_Error;
+ }
+ }
+
+ if ( fname != NULL && fname[ 0 ] != '\0' )
+ {
+ UINT fNameLength = strlen( fname );
+ Length += fNameLength;
+
+ if ( Length < _MAX_PATH )
+ {
+ strncat( path, fname, fNameLength );
+ }
+ else
+ {
+ goto Max_Path_Error;
+ }
+ }
+
+ if ( ext != NULL && ext[ 0 ] != '\0' )
+ {
+ UINT ExtLength = strlen( ext );
+ Length += ExtLength;
+
+ if ( ext[ 0 ] != '.' )
+ {
+ /* Add a '.' */
+ if ( Length + 1 < _MAX_PATH )
+ {
+ path[ Length - ExtLength ] = '.';
+ Length++;
+ path[ Length - ExtLength ] = '\0';
+ strncat( path, ext, ExtLength );
+ }
+ else
+ {
+ goto Max_Path_Error;
+ }
+ }
+ else
+ {
+ /* Already has a '.' */
+ if ( Length < _MAX_PATH )
+ {
+ strncat( path, ext, ExtLength );
+ }
+ else
+ {
+ goto Max_Path_Error;
+ }
+ }
+ }
+
+ FILEDosToUnixPathA( path );
+ LOGEXIT( "_makepath returning void.\n" );
+ PERF_EXIT(_makepath);
+ return;
+
+Max_Path_Error:
+
+ ERROR( "path cannot be greater then _MAX_PATH\n" );
+ path[ 0 ] = '\0';
+ LOGEXIT( "_makepath returning void \n" );
+ PERF_EXIT(_makepath);
+ return;
+}
+
+/*++
+Function:
+ _wmakepath
+
+See MSDN doc.
+
+--*/
+void
+__cdecl
+_wmakepath(
+ wchar_16 *path,
+ const wchar_16 *drive,
+ const wchar_16 *dir,
+ const wchar_16 *fname,
+ const wchar_16 *ext)
+{
+ CHAR Dir[ _MAX_DIR ]={0};
+ CHAR FileName[ _MAX_FNAME ]={0};
+ CHAR Ext[ _MAX_EXT ]={0};
+ CHAR Path[ _MAX_PATH ]={0};
+
+ PERF_ENTRY(_wmakepath);
+ ENTRY("_wmakepath (path=%p, drive=%p (%S), dir=%p (%S), fname=%p (%S), ext=%p (%S))\n",
+ path, drive ? drive:W16_NULLSTRING, drive ? drive:W16_NULLSTRING, dir ? dir:W16_NULLSTRING, dir ? dir:W16_NULLSTRING,
+ fname ? fname:W16_NULLSTRING,
+ fname ? fname:W16_NULLSTRING, ext ? ext:W16_NULLSTRING, ext ? ext:W16_NULLSTRING);
+
+ /* According to the pal documentation, host operating systems that
+ don't support drive letters, the "drive" parameter must always be null. */
+ if ( drive != NULL && drive[0] != '\0' )
+ {
+ ASSERT( "The drive parameter must always be NULL on systems that don't"
+ "support drive letters. drive is being ignored!.\n" );
+ }
+
+ if ((dir != NULL) && WideCharToMultiByte( CP_ACP, 0, dir, -1, Dir,
+ _MAX_DIR, NULL, NULL ) == 0 )
+ {
+ ASSERT( "An error occurred while converting dir to multibyte."
+ "Possible error: Length of dir is greater than _MAX_DIR.\n" );
+ goto error;
+ }
+
+ if ((fname != NULL) && WideCharToMultiByte( CP_ACP, 0, fname, -1, FileName,
+ _MAX_FNAME, NULL, NULL ) == 0 )
+ {
+ ASSERT( "An error occurred while converting fname to multibyte."
+ "Possible error: Length of fname is greater than _MAX_FNAME.\n" );
+ goto error;
+ }
+
+ if ((ext != NULL) && WideCharToMultiByte( CP_ACP, 0, ext, -1, Ext,
+ _MAX_EXT, NULL, NULL ) == 0 )
+ {
+ ASSERT( "An error occurred while converting ext to multibyte."
+ "Possible error: Length of ext is greater than _MAX_EXT.\n" );
+ goto error;
+ }
+
+ /* Call up to the ANSI _makepath. */
+ _makepath_s( Path, sizeof(Path), NULL, Dir, FileName, Ext );
+
+ if ( MultiByteToWideChar( CP_ACP, 0, Path, -1, path, _MAX_PATH ) == 0 )
+ {
+ ASSERT( "An error occurred while converting the back wide char."
+ "Possible error: The length of combined path is greater "
+ "than _MAX_PATH.\n" );
+ goto error;
+ }
+
+ LOGEXIT("_wmakepath returns void\n");
+ PERF_EXIT(_wmakepath);
+ return;
+
+error:
+ *path = '\0';
+ LOGEXIT("_wmakepath returns void\n");
+ PERF_EXIT(_wmakepath);
+}
+
+
+/*++
+Function:
+ _fullpath
+
+See MSDN doc.
+
+--*/
+char *
+__cdecl
+_fullpath(
+ char *absPath,
+ const char *relPath,
+ size_t maxLength)
+{
+ char realpath_buf[PATH_MAX+1];
+ char path_copy[PATH_MAX+1];
+ char *retval = NULL;
+ DWORD cPathCopy = sizeof(path_copy)/sizeof(path_copy[0]);
+ size_t min_length;
+ BOOL fBufAllocated = FALSE;
+
+ PERF_ENTRY(_fullpath);
+ ENTRY("_fullpath (absPath=%p, relPath=%p (%s), maxLength = %lu)\n",
+ absPath, relPath ? relPath:"NULL", relPath ? relPath:"NULL", maxLength);
+
+ if (strncpy_s(path_copy, sizeof(path_copy), relPath ? relPath : ".", cPathCopy) != SAFECRT_SUCCESS)
+ {
+ TRACE("_fullpath: strncpy_s failed!\n");
+ goto fullpathExit;
+ }
+
+ FILEDosToUnixPathA(path_copy);
+
+ if(NULL == realpath(path_copy, realpath_buf))
+ {
+ ERROR("realpath() failed; problem path is '%s'. errno is %d (%s)\n",
+ realpath_buf, errno, strerror(errno));
+ goto fullpathExit;
+ }
+
+ TRACE("real path is %s\n", realpath_buf);
+ min_length = strlen(realpath_buf)+1; // +1 for the NULL terminator
+
+ if(NULL == absPath)
+ {
+ absPath = static_cast<char *>(
+ PAL_malloc(_MAX_PATH * sizeof(char)));
+ if (!absPath)
+ {
+ ERROR("PAL_malloc failed with error %d\n", errno);
+ goto fullpathExit;
+ }
+ maxLength = _MAX_PATH;
+ fBufAllocated = TRUE;
+ }
+
+ if(min_length > maxLength)
+ {
+ ERROR("maxLength is %lu, we need at least %lu\n",
+ maxLength, min_length);
+ if (fBufAllocated)
+ {
+ PAL_free(absPath);
+ fBufAllocated = FALSE;
+ }
+ goto fullpathExit;
+ }
+
+ strcpy_s(absPath, maxLength, realpath_buf);
+ retval = absPath;
+
+fullpathExit:
+ LOGEXIT("_fullpath returns char * %p\n", retval);
+ PERF_EXIT(_fullpath);
+ return retval;
+}
+
+
+
diff --git a/src/pal/src/cruntime/printf.cpp b/src/pal/src/cruntime/printf.cpp
new file mode 100644
index 0000000000..2d9d6e4b94
--- /dev/null
+++ b/src/pal/src/cruntime/printf.cpp
@@ -0,0 +1,1758 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ printf.c
+
+Abstract:
+
+ Implementation of the printf family functions.
+
+Revision History:
+
+
+
+--*/
+
+#include "pal/palinternal.h"
+#include "pal/dbgmsg.h"
+#include "pal/cruntime.h"
+#include "pal/thread.hpp"
+#include "pal/threadsusp.hpp"
+#include "pal/printfcpp.hpp"
+
+/* <stdarg.h> needs to be included after "palinternal.h" to avoid name
+ collision for va_start and va_end */
+#include <stdarg.h>
+#include <errno.h>
+
+SET_DEFAULT_DEBUG_CHANNEL(CRT);
+
+#if SSCANF_SUPPORT_ll
+const static char *scanf_longlongfmt = "ll";
+#else
+const static char *scanf_longlongfmt = "q";
+#endif
+
+#if SSCANF_CANNOT_HANDLE_MISSING_EXPONENT
+static int SscanfFloatCheckExponent(LPCSTR buff, LPCSTR floatFmt,
+ void * voidPtr, int * pn);
+#endif // SSCANF_CANNOT_HANDLE_MISSING_EXPONENT
+
+/*******************************************************************************
+Function:
+ Internal_AddPaddingA
+
+Parameters:
+ Out
+ - buffer to place padding and given string (In)
+ Count
+ - maximum chars to be copied so as not to overrun given buffer
+ In
+ - string to place into (Out) accompanied with padding
+ Padding
+ - number of padding chars to add
+ Flags
+ - padding style flags (PRINTF_FORMAT_FLAGS)
+*******************************************************************************/
+BOOL Internal_AddPaddingA(LPSTR *Out, INT Count, LPSTR In,
+ INT Padding, INT Flags)
+{
+ LPSTR OutOriginal = *Out;
+ INT PaddingOriginal = Padding;
+ INT LengthInStr;
+ LengthInStr = strlen(In);
+
+
+ if (Padding < 0)
+ {
+ /* this is used at the bottom to determine if the buffer ran out */
+ PaddingOriginal = 0;
+ }
+ if (Flags & PFF_MINUS) /* pad on right */
+ {
+ if (strncpy_s(*Out, Count, In, min(LengthInStr + 1, Count)) != SAFECRT_SUCCESS)
+ {
+ return FALSE;
+ }
+
+ *Out += min(LengthInStr, Count);
+ }
+ if (Padding > 0)
+ {
+ if (Flags & PFF_ZERO) /* '0', pad with zeros */
+ {
+ while (Padding-- && Count > *Out - OutOriginal)
+ {
+ *(*Out)++ = '0';
+ }
+ }
+ else /* pad left with spaces */
+ {
+ while (Padding-- && Count > *Out - OutOriginal)
+ {
+ *(*Out)++ = ' ';
+ }
+ }
+ }
+ if (!(Flags & PFF_MINUS)) /* put 'In' after padding */
+ {
+ if (strncpy_s(*Out, Count, In,
+ min(LengthInStr + 1, Count - (*Out - OutOriginal))) != SAFECRT_SUCCESS)
+ {
+ return FALSE;
+ }
+
+ *Out += min(LengthInStr, Count - (*Out - OutOriginal));
+ }
+
+ if (LengthInStr + PaddingOriginal > Count)
+ {
+ return FALSE;
+ }
+ else
+ {
+ return TRUE;
+ }
+}
+
+/*******************************************************************************
+Function:
+ PAL_printf_arg_remover
+
+Parameters:
+ ap
+ - pointer to the va_list from which to remove arguments
+ Width
+ - the width of the current format operation
+ Precision
+ - the precision of the current format option
+ Type
+ - the type of the argument for the current format option
+ Prefix
+ - the prefix for the current format option
+*******************************************************************************/
+void PAL_printf_arg_remover(va_list *ap, INT Width, INT Precision, INT Type, INT Prefix)
+{
+ /* remove arg and precision if needed */
+ if (PRECISION_STAR == Precision ||
+ PRECISION_INVALID == Precision)
+ {
+ (void)va_arg(*ap, int);
+ }
+ if (WIDTH_STAR == Width ||
+ WIDTH_INVALID == Width)
+ {
+ (void)va_arg(*ap, int);
+ }
+ if (Type == PFF_TYPE_FLOAT)
+ {
+ (void)va_arg(*ap, double);
+ }
+ else if (Type == PFF_TYPE_INT && Prefix == PFF_PREFIX_LONGLONG)
+ {
+ (void)va_arg(*ap, INT64);
+ }
+ else if (Type == PFF_TYPE_INT || Type == PFF_TYPE_CHAR)
+ {
+ (void)va_arg(*ap, int);
+ }
+ else
+ {
+ (void)va_arg(*ap, void *);
+ }
+}
+
+/*++
+Function:
+ PAL_printf
+
+See MSDN doc.
+--*/
+int
+__cdecl
+PAL_printf(
+ const char *format,
+ ...)
+{
+ LONG Length;
+ va_list ap;
+
+ PERF_ENTRY(printf);
+ ENTRY("PAL_printf (format=%p (%s))\n", format, format);
+
+ va_start(ap, format);
+ Length = PAL_vprintf(format, ap);
+ va_end(ap);
+
+ LOGEXIT("PAL_printf returns int %d\n", Length);
+ PERF_EXIT(printf);
+ return Length;
+}
+
+/*++
+Function:
+ PAL_fprintf
+
+See MSDN doc.
+--*/
+int
+__cdecl
+PAL_fprintf(PAL_FILE *stream,const char *format,...)
+{
+ LONG Length = 0;
+ va_list ap;
+
+ PERF_ENTRY(fprintf);
+ ENTRY("PAL_fprintf(stream=%p,format=%p (%s))\n",stream, format, format);
+
+ va_start(ap, format);
+ Length = PAL_vfprintf( stream, format, ap);
+ va_end(ap);
+
+ LOGEXIT("PAL_fprintf returns int %d\n", Length);
+ PERF_EXIT(fprintf);
+ return Length;
+}
+
+/*++
+Function:
+ PAL_wprintf
+
+See MSDN doc.
+--*/
+int
+__cdecl
+PAL_wprintf(
+ const wchar_16 *format,
+ ...)
+{
+ LONG Length;
+ va_list ap;
+
+ PERF_ENTRY(wprintf);
+ ENTRY("PAL_wprintf (format=%p (%S))\n", format, format);
+
+ va_start(ap, format);
+ Length = PAL_vfwprintf( PAL_get_stdout(PAL_get_caller), format, ap);
+ va_end(ap);
+
+ LOGEXIT("PAL_wprintf returns int %d\n", Length);
+ PERF_EXIT(wprintf);
+ return Length;
+}
+
+
+
+/*++
+Function:
+ PAL_vprintf
+
+See MSDN doc.
+--*/
+int
+__cdecl
+PAL_vprintf(
+ const char *format,
+ va_list ap)
+{
+ LONG Length;
+
+ PERF_ENTRY(vprintf);
+ ENTRY("PAL_vprintf (format=%p (%s))\n", format, format);
+
+ Length = PAL_vfprintf( PAL_get_stdout(PAL_get_caller), format, ap);
+
+ LOGEXIT("PAL_vprintf returns int %d\n", Length);
+ PERF_EXIT(vprintf);
+ return Length;
+}
+
+
+/*++
+Function:
+ wsprintfA
+
+See MSDN doc.
+--*/
+int
+PALAPIV
+wsprintfA(
+ OUT LPSTR buffer,
+ IN LPCSTR format,
+ ...)
+{
+ LONG Length;
+ va_list ap;
+
+ PERF_ENTRY(wsprintfA);
+ ENTRY("wsprintfA (buffer=%p, format=%p (%s))\n", buffer, format, format);
+
+ va_start(ap, format);
+ Length = InternalVsnprintf(CorUnix::InternalGetCurrentThread(), buffer, 1024, format, ap);
+ va_end(ap);
+
+ LOGEXIT("wsprintfA returns int %d\n", Length);
+ PERF_EXIT(wsprintfA);
+ return Length;
+}
+
+/*++
+Function:
+ wsprintfW
+
+See MSDN doc.
+--*/
+int
+PALAPIV
+wsprintfW(
+ OUT LPWSTR buffer,
+ IN LPCWSTR format,
+ ...)
+{
+ LONG Length;
+ va_list ap;
+
+ PERF_ENTRY(wsprintfW);
+ ENTRY("wsprintfW (buffer=%p, format=%p (%S))\n", buffer, format, format);
+
+ va_start(ap, format);
+ Length = PAL__wvsnprintf(buffer, 1024, format, ap);
+ va_end(ap);
+
+ LOGEXIT("wsprintfW returns int %d\n", Length);
+ PERF_EXIT(wsprintfW);
+ return Length;
+}
+
+
+/*++
+Function:
+ _snprintf
+
+See MSDN doc.
+--*/
+int
+__cdecl
+_snprintf(
+ char *buffer,
+ size_t count,
+ const char *format,
+ ...)
+{
+ LONG Length;
+ va_list ap;
+
+ PERF_ENTRY(_snprintf);
+ ENTRY("_snprintf (buffer=%p, count=%lu, format=%p (%s))\n",
+ buffer, (unsigned long) count, format, format);
+
+ va_start(ap, format);
+ Length = InternalVsnprintf(CorUnix::InternalGetCurrentThread(), buffer, count, format, ap);
+ va_end(ap);
+
+ LOGEXIT("_snprintf returns int %d\n", Length);
+ PERF_EXIT(_snprintf);
+ return Length;
+}
+
+
+/*++
+Function:
+ _snwprintf
+
+See MSDN doc.
+--*/
+int
+__cdecl
+_snwprintf(
+ wchar_16 *buffer,
+ size_t count,
+ const wchar_16 *format,
+ ...)
+{
+ LONG Length;
+ va_list ap;
+
+ PERF_ENTRY(_snwprintf);
+ ENTRY("_snwprintf (buffer=%p, count=%lu, format=%p (%S))\n",
+ buffer, (unsigned long) count, format, format);
+
+ va_start(ap, format);
+ Length = PAL__wvsnprintf(buffer, count, format, ap);
+ va_end(ap);
+
+ LOGEXIT("_snwprintf returns int %d\n", Length);
+ PERF_EXIT(_snwprintf);
+ return Length;
+}
+
+/*++
+Function:
+ fwprintf
+
+See MSDN doc.
+--*/
+int
+__cdecl
+PAL_fwprintf(
+ PAL_FILE *stream,
+ const wchar_16 *format,
+ ...)
+{
+ LONG Length;
+ va_list ap;
+
+ PERF_ENTRY(fwprintf);
+ ENTRY("PAL_fwprintf (stream=%p, format=%p (%S))\n", stream, format, format);
+
+ va_start(ap, format);
+ Length = PAL_vfwprintf( stream, format, ap);
+ va_end(ap);
+
+ LOGEXIT("PAL_fwprintf returns int %d\n", Length);
+ PERF_EXIT(fwprintf);
+ return Length;
+}
+
+/*******************************************************************************
+Function:
+ Internal_ScanfExtractFormatA
+
+Paramaters:
+ Fmt
+ - format string to parse
+ - first character must be a '%'
+ - paramater gets updated to point to the character after
+ the %<foo> format string
+ Out
+ - buffer will contain the %<foo> format string
+ Store
+ - boolean value representing whether to store the type to be parsed
+ - '*' flag
+ Width
+ - will contain the width specified by the format string
+ - -1 if none given
+ Prefix
+ - an enumeration of the type prefix
+ Type
+ - an enumeration of the value type to be parsed
+
+Notes:
+ - I'm also handling the undocumented %ws, %wc, %w...
+*******************************************************************************/
+
+#define CHECK_OUT_IN_ITS_RANGE(Out,BeginOut,EndOut) \
+ if ((Out)<(BeginOut) || (Out)>=(EndOut)) \
+ { \
+ SetLastError(ERROR_INSUFFICIENT_BUFFER); \
+ ERROR("Pointer Out wanted to access 0x%p. However the range of buffer is [0x%p,0x%p).",\
+ (Out), (BeginOut), (EndOut)); \
+ return false; \
+ }
+
+static BOOL Internal_ScanfExtractFormatA(LPCSTR *Fmt, LPSTR Out, int iOutSize, LPBOOL Store,
+ LPINT Width, LPINT Prefix, LPINT Type)
+{
+ BOOL Result = FALSE;
+ LPSTR TempStr;
+ LPSTR TempStrPtr;
+ LPSTR BaseOut = Out;
+ LPSTR EndOut = Out + iOutSize;
+
+ *Width = -1;
+ *Store = TRUE;
+ *Prefix = -1;
+ *Type = -1;
+
+ if (*Fmt && **Fmt == '%')
+ {
+ CHECK_OUT_IN_ITS_RANGE(Out,BaseOut,EndOut)
+ *Out++ = *(*Fmt)++;
+ }
+ else
+ {
+ return Result;
+ }
+
+ /* we'll never need a temp string longer than the original */
+ TempStrPtr = TempStr = (LPSTR) PAL_malloc(strlen(*Fmt)+1);
+ if (!TempStr)
+ {
+ ERROR("PAL_malloc failed\n");
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ return Result;
+ }
+
+ /* parse '*' flag which means don't store */
+ if (**Fmt == '*')
+ {
+ *Store = FALSE;
+ CHECK_OUT_IN_ITS_RANGE(Out,BaseOut,EndOut)
+ *Out++ = *(*Fmt)++;
+ }
+
+ /* grab width specifier */
+ if (isdigit((unsigned char) **Fmt))
+ {
+ TempStrPtr = TempStr;
+ while (isdigit((unsigned char) **Fmt))
+ {
+ *TempStrPtr++ = **Fmt;
+ CHECK_OUT_IN_ITS_RANGE(Out,BaseOut,EndOut)
+ *Out++ = *(*Fmt)++;
+ }
+ *TempStrPtr = 0; /* end string */
+ *Width = atoi(TempStr);
+ if (*Width < 0)
+ {
+ ERROR("atoi returned a negative value indicative of an overflow.\n");
+ SetLastError(ERROR_INTERNAL_ERROR);
+ return Result;
+ }
+ }
+
+#ifdef BIT64
+ if (**Fmt == 'p')
+ {
+ *Prefix = SCANF_PREFIX_LONGLONG;
+ }
+#endif
+ /* grab prefix of 'I64' for __int64 */
+ if ((*Fmt)[0] == 'I' && (*Fmt)[1] == '6' && (*Fmt)[2] == '4')
+ {
+ /* convert to 'q'/'ll' so Unix sscanf can handle it */
+ *Fmt += 3;
+ *Prefix = SCANF_PREFIX_LONGLONG;
+ }
+ /* grab a prefix of 'h' */
+ else if (**Fmt == 'h')
+ {
+ *Prefix = SCANF_PREFIX_SHORT;
+ ++(*Fmt);
+ }
+ /* grab prefix of 'l' or the undocumented 'w' (at least in MSDN) */
+ else if (**Fmt == 'l' || **Fmt == 'w')
+ {
+ ++(*Fmt);
+#ifdef BIT64
+ // Only want to change the prefix on 64 bit when inputing characters.
+ if (**Fmt == 'c' || **Fmt == 's')
+#endif
+ {
+ *Prefix = SCANF_PREFIX_LONG; /* give it a wide prefix */
+ }
+ if (**Fmt == 'l')
+ {
+ *Prefix = SCANF_PREFIX_LONGLONG;
+ ++(*Fmt);
+ }
+ }
+ else if (**Fmt == 'L')
+ {
+ /* a prefix of 'L' seems to be ignored */
+ ++(*Fmt);
+ }
+
+ /* grab type 'c' */
+ if (**Fmt == 'c' || **Fmt == 'C')
+ {
+ *Type = SCANF_TYPE_CHAR;
+ if (*Prefix != SCANF_PREFIX_SHORT && **Fmt == 'C')
+ {
+ *Prefix = SCANF_PREFIX_LONG; /* give it a wide prefix */
+ }
+ if (*Prefix == SCANF_PREFIX_LONG)
+ {
+ CHECK_OUT_IN_ITS_RANGE(Out,BaseOut,EndOut)
+ *Out++ = 'l';
+ }
+ CHECK_OUT_IN_ITS_RANGE(Out,BaseOut,EndOut)
+ *Out++ = 'c';
+ ++(*Fmt);
+ Result = TRUE;
+ }
+ /* grab type 's' */
+ else if (**Fmt == 's' || **Fmt == 'S')
+ {
+ *Type = SCANF_TYPE_STRING;
+ if (*Prefix != SCANF_PREFIX_SHORT && **Fmt == 'S')
+ {
+ *Prefix = SCANF_PREFIX_LONG; /* give it a wide prefix */
+ }
+ if (*Prefix == SCANF_PREFIX_LONG)
+ {
+ CHECK_OUT_IN_ITS_RANGE(Out,BaseOut,EndOut)
+ *Out++ = 'l';
+ }
+ CHECK_OUT_IN_ITS_RANGE(Out,BaseOut,EndOut)
+ *Out++ = 's';
+ ++(*Fmt);
+ Result = TRUE;
+ }
+ /* grab int types */
+ else if (**Fmt == 'd' || **Fmt == 'i' || **Fmt == 'o' ||
+ **Fmt == 'u' || **Fmt == 'x' || **Fmt == 'X' ||
+ **Fmt == 'p')
+ {
+ *Type = SCANF_TYPE_INT;
+ if (*Prefix == SCANF_PREFIX_SHORT)
+ {
+ CHECK_OUT_IN_ITS_RANGE(Out,BaseOut,EndOut)
+ *Out++ = 'h';
+ }
+ else if (*Prefix == SCANF_PREFIX_LONG)
+ {
+ CHECK_OUT_IN_ITS_RANGE(Out,BaseOut,EndOut)
+ *Out++ = 'l';
+ }
+ else if (*Prefix == SCANF_PREFIX_LONGLONG)
+ {
+ CHECK_OUT_IN_ITS_RANGE(Out,BaseOut,EndOut)
+
+ if (strcpy_s(Out, iOutSize-(Out-BaseOut), scanf_longlongfmt) != SAFECRT_SUCCESS)
+ {
+ ERROR("strcpy_s failed\n");
+ SetLastError(ERROR_INSUFFICIENT_BUFFER);
+ return FALSE;
+ }
+
+ Out += strlen(scanf_longlongfmt);
+ }
+ CHECK_OUT_IN_ITS_RANGE(Out,BaseOut,EndOut)
+ *Out++ = *(*Fmt)++;
+ Result = TRUE;
+ }
+ else if (**Fmt == 'e' || **Fmt == 'E' || **Fmt == 'f' ||
+ **Fmt == 'g' || **Fmt == 'G')
+ {
+ /* we can safely ignore the prefixes and only add the type*/
+ *Type = SCANF_TYPE_FLOAT;
+ /* this gets rid of %E/%G since they're they're the
+ same when scanning */
+ CHECK_OUT_IN_ITS_RANGE(Out,BaseOut,EndOut)
+ *Out++ = tolower( *(*Fmt)++ );
+ Result = TRUE;
+ }
+ else if (**Fmt == 'n')
+ {
+ if (*Prefix == SCANF_PREFIX_SHORT)
+ {
+ CHECK_OUT_IN_ITS_RANGE(Out,BaseOut,EndOut)
+ *Out++ = 'h';
+ }
+ CHECK_OUT_IN_ITS_RANGE(Out,BaseOut,EndOut)
+ *Out++ = *(*Fmt)++;
+ *Type = SCANF_TYPE_N;
+ Result = TRUE;
+ }
+ else if (**Fmt == '[')
+ {
+ /* There is a small compatibility problem in the handling of the []
+ option in FreeBSD vs. Windows. In Windows, you can have [z-a]
+ as well as [a-z]. In FreeBSD, [z-a] fails. So, we need to
+ reverse the instances of z-a to a-z (and [m-e] to [e-m], etc). */
+
+ /* step 1 : copy the leading [ */
+ CHECK_OUT_IN_ITS_RANGE(Out,BaseOut,EndOut)
+ *Out++ = '[';
+ (*Fmt)++;
+
+ /* step 2 : copy a leading ^, if present */
+ if( '^' == **Fmt )
+ {
+ CHECK_OUT_IN_ITS_RANGE(Out,BaseOut,EndOut)
+ *Out++ = '^';
+ (*Fmt)++;
+ }
+
+ /* step 3 : copy a leading ], if present; a ] immediately after the
+ leading [ (or [^) does *not* end the sequence, it is part of the
+ characters to match */
+ if( ']' == **Fmt )
+ {
+ CHECK_OUT_IN_ITS_RANGE(Out,BaseOut,EndOut)
+ *Out++ = ']';
+ (*Fmt)++;
+ }
+
+ /* step 4 : if the next character is already a '-', it's not part of an
+ interval specifier, so just copy it */
+ if('-' == **Fmt )
+ {
+ CHECK_OUT_IN_ITS_RANGE(Out,BaseOut,EndOut)
+ *Out++ = '-';
+ (*Fmt)++;
+ }
+
+ /* ok then, process the rest of it */
+ while( '\0' != **Fmt )
+ {
+ if(']' == **Fmt)
+ {
+ /* ']' marks end of the format specifier; we're done */
+ CHECK_OUT_IN_ITS_RANGE(Out,BaseOut,EndOut)
+ *Out++ = ']';
+ (*Fmt)++;
+ break;
+ }
+ if('-' == **Fmt)
+ {
+ if( ']' == (*Fmt)[1] )
+ {
+ /* got a '-', next character is the terminating ']';
+ copy '-' literally */
+ CHECK_OUT_IN_ITS_RANGE(Out,BaseOut,EndOut)
+ *Out++ = '-';
+ (*Fmt)++;
+ }
+ else
+ {
+ /* got a '-' indicating an interval specifier */
+ unsigned char prev, next;
+
+ /* get the interval boundaries */
+ prev = (*Fmt)[-1];
+ next = (*Fmt)[1];
+
+ /* if boundaries were inverted, replace the already-copied
+ low boundary by the 'real' low boundary */
+ if( prev > next )
+ {
+ CHECK_OUT_IN_ITS_RANGE(Out-1,BaseOut,EndOut)
+ Out[-1] = next;
+
+ /* ...and save the 'real' upper boundary, which will be
+ copied to 'Out' below */
+ next = prev;
+ }
+
+ CHECK_OUT_IN_ITS_RANGE(Out,BaseOut,EndOut)
+ *Out++ = '-';
+ CHECK_OUT_IN_ITS_RANGE(Out,BaseOut,EndOut)
+ *Out++ = next;
+
+ /* skip over the '-' and the next character, which we
+ already copied */
+ (*Fmt)+=2;
+ }
+ }
+ else
+ {
+ /* plain character; just copy it */
+ CHECK_OUT_IN_ITS_RANGE(Out,BaseOut,EndOut)
+ *Out++ = **Fmt;
+ (*Fmt)++;
+ }
+ }
+
+ *Type = SCANF_TYPE_BRACKETS;
+ Result = TRUE;
+ }
+ else if (**Fmt == ' ')
+ {
+ *Type = SCANF_TYPE_SPACE;
+ }
+
+ /* add %n so we know how far to increment the pointer */
+ CHECK_OUT_IN_ITS_RANGE(Out,BaseOut,EndOut)
+ *Out++ = '%';
+ CHECK_OUT_IN_ITS_RANGE(Out,BaseOut,EndOut)
+ *Out++ = 'n';
+
+ CHECK_OUT_IN_ITS_RANGE(Out,BaseOut,EndOut)
+ *Out = 0; /* end the string */
+ PAL_free(TempStr);
+ return Result;
+}
+
+/*******************************************************************************
+Function:
+ Internal_ScanfExtractFormatW
+
+ -- see Internal_ScanfExtractFormatA above
+*******************************************************************************/
+static BOOL Internal_ScanfExtractFormatW(LPCWSTR *Fmt, LPSTR Out, int iOutSize, LPBOOL Store,
+ LPINT Width, LPINT Prefix, LPINT Type)
+{
+ BOOL Result = FALSE;
+ LPSTR TempStr;
+ LPSTR TempStrPtr;
+
+ *Width = -1;
+ *Store = TRUE;
+ *Prefix = -1;
+ *Type = -1;
+
+ if (*Fmt && **Fmt == '%')
+ {
+ *Out++ = *(*Fmt)++;
+ }
+ else
+ {
+ return Result;
+ }
+
+ /* we'll never need a temp string longer than the original */
+ TempStrPtr = TempStr = (LPSTR) PAL_malloc(PAL_wcslen(*Fmt)+1);
+ if (!TempStr)
+ {
+ ERROR("PAL_malloc failed\n");
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ return Result;
+ }
+
+ /* parse '*' flag which means don't store */
+ if (**Fmt == '*')
+ {
+ *Store = FALSE;
+ *Out++ = *(*Fmt)++;
+ }
+
+ /* grab width specifier */
+ if (isdigit(**Fmt))
+ {
+ TempStrPtr = TempStr;
+ while (isdigit(**Fmt))
+ {
+ *TempStrPtr++ = **Fmt;
+ *Out++ = *(*Fmt)++;
+ }
+ *TempStrPtr = 0; /* end string */
+ *Width = atoi(TempStr);
+ if (*Width < 0)
+ {
+ ERROR("atoi returned a negative value indicative of an overflow.\n");
+ SetLastError(ERROR_INTERNAL_ERROR);
+ return Result;
+ }
+ }
+
+#ifdef BIT64
+ if (**Fmt == 'p')
+ {
+ *Prefix = SCANF_PREFIX_LONGLONG;
+ }
+#endif
+ /* grab prefix of 'I64' for __int64 */
+ if ((*Fmt)[0] == 'I' && (*Fmt)[1] == '6' && (*Fmt)[2] == '4')
+ {
+ /* convert to 'q'/'ll' so that Unix sscanf can handle it */
+ *Fmt += 3;
+ *Prefix = SCANF_PREFIX_LONGLONG;
+ }
+ /* grab a prefix of 'h' */
+ else if (**Fmt == 'h')
+ {
+ *Prefix = SCANF_PREFIX_SHORT;
+ ++(*Fmt);
+ }
+ /* grab prefix of 'l' or the undocumented 'w' (at least in MSDN) */
+ else if (**Fmt == 'l' || **Fmt == 'w')
+ {
+ ++(*Fmt);
+#ifdef BIT64
+ // Only want to change the prefix on 64 bit when inputing characters.
+ if (**Fmt == 'C' || **Fmt == 'S')
+#endif
+ {
+ *Prefix = SCANF_PREFIX_LONG; /* give it a wide prefix */
+ }
+ if (**Fmt == 'l')
+ {
+ *Prefix = SCANF_PREFIX_LONGLONG;
+ ++(*Fmt);
+ }
+ }
+ else if (**Fmt == 'L')
+ {
+ /* a prefix of 'L' seems to be ignored */
+ ++(*Fmt);
+ }
+
+ /* grab type 'c' */
+ if (**Fmt == 'c' || **Fmt == 'C')
+ {
+ *Type = SCANF_TYPE_CHAR;
+ if (*Prefix != SCANF_PREFIX_SHORT && **Fmt == 'c')
+ {
+ *Prefix = SCANF_PREFIX_LONG; /* give it a wide prefix */
+ }
+ if (*Prefix == SCANF_PREFIX_LONG)
+ {
+ *Out++ = 'l';
+ }
+ *Out++ = 'c';
+ ++(*Fmt);
+ Result = TRUE;
+ }
+ /* grab type 's' */
+ else if (**Fmt == 's' || **Fmt == 'S')
+ {
+ *Type = SCANF_TYPE_STRING;
+ if (*Prefix != SCANF_PREFIX_SHORT && **Fmt == 's')
+ {
+ *Prefix = SCANF_PREFIX_LONG; /* give it a wide prefix */
+ }
+ if (*Prefix == SCANF_PREFIX_LONG)
+ {
+ *Out++ = 'l';
+ }
+ *Out++ = 's';
+ ++(*Fmt);
+ Result = TRUE;
+ }
+ /* grab int types */
+ else if (**Fmt == 'd' || **Fmt == 'i' || **Fmt == 'o' ||
+ **Fmt == 'u' || **Fmt == 'x' || **Fmt == 'X' ||
+ **Fmt == 'p')
+ {
+ *Type = SCANF_TYPE_INT;
+ if (*Prefix == SCANF_PREFIX_SHORT)
+ {
+ *Out++ = 'h';
+ }
+ else if (*Prefix == SCANF_PREFIX_LONG)
+ {
+ *Out++ = 'l';
+ }
+ else if (*Prefix == SCANF_PREFIX_LONGLONG)
+ {
+ if (strcpy_s(Out, iOutSize, scanf_longlongfmt) != SAFECRT_SUCCESS)
+ {
+ ERROR("strcpy_s failed\n");
+ SetLastError(ERROR_INSUFFICIENT_BUFFER);
+ return FALSE;
+ }
+
+ Out += strlen(scanf_longlongfmt);
+ }
+ *Out++ = *(*Fmt)++;
+ Result = TRUE;
+ }
+ else if (**Fmt == 'e' || **Fmt == 'E' || **Fmt == 'f' ||
+ **Fmt == 'g' || **Fmt == 'G')
+ {
+ /* we can safely ignore the prefixes and only add the type*/
+ *Type = SCANF_TYPE_FLOAT;
+ /* this gets rid of %E/%G since they're they're the
+ same when scanning */
+ *Out++ = tolower( *(*Fmt)++ );
+ Result = TRUE;
+ }
+ else if (**Fmt == 'n')
+ {
+ if (*Prefix == SCANF_PREFIX_SHORT)
+ {
+ *Out++ = 'h';
+ }
+ *Out++ = *(*Fmt)++;
+ *Type = SCANF_TYPE_N;
+ Result = TRUE;
+ }
+ else if (**Fmt == '[')
+ {
+ /* There is a small compatibility problem in the handling of the []
+ option in FreeBSD vs. Windows. In Windows, you can have [z-a]
+ as well as [a-z]. In FreeBSD, [z-a] fails. So, we need to
+ reverse the instances of z-a to a-z (and [m-e] to [e-m], etc). */
+
+ /* step 1 : copy the leading [ */
+ *Out++ = '[';
+ (*Fmt)++;
+
+ /* step 2 : copy a leading ^, if present */
+ if( '^' == **Fmt )
+ {
+ *Out++ = '^';
+ (*Fmt)++;
+ }
+
+ /* step 3 : copy a leading ], if present; a ] immediately after the
+ leading [ (or [^) does *not* end the sequence, it is part of the
+ characters to match */
+ if( ']' == **Fmt )
+ {
+ *Out++ = ']';
+ (*Fmt)++;
+ }
+
+ /* step 4 : if the next character is already a '-', it's not part of an
+ interval specifier, so just copy it */
+ if('-' == **Fmt )
+ {
+ *Out++ = '-';
+ (*Fmt)++;
+ }
+
+ /* ok then, process the rest of it */
+ while( '\0' != **Fmt )
+ {
+ if(']' == **Fmt)
+ {
+ /* ']' marks end of the format specifier; we're done */
+ *Out++ = ']';
+ (*Fmt)++;
+ break;
+ }
+ if('-' == **Fmt)
+ {
+ if( ']' == (*Fmt)[1] )
+ {
+ /* got a '-', next character is the terminating ']';
+ copy '-' literally */
+ *Out++ = '-';
+ (*Fmt)++;
+ }
+ else
+ {
+ /* got a '-' indicating an interval specifier */
+ unsigned char prev, next;
+
+ /* get the interval boundaries */
+ prev = (*Fmt)[-1];
+ next = (*Fmt)[1];
+
+ /* if boundaries were inverted, replace the already-copied
+ low boundary by the 'real' low boundary */
+ if( prev > next )
+ {
+ Out[-1] = next;
+
+ /* ...and save the 'real' upper boundary, which will be
+ copied to 'Out' below */
+ next = prev;
+ }
+
+ *Out++ = '-';
+ *Out++ = next;
+
+ /* skip over the '-' and the next character, which we
+ already copied */
+ (*Fmt)+=2;
+ }
+ }
+ else
+ {
+ /* plain character; just copy it */
+ *Out++ = **Fmt;
+ (*Fmt)++;
+ }
+ }
+
+ *Type = SCANF_TYPE_BRACKETS;
+ Result = TRUE;
+ }
+ else if (**Fmt == ' ')
+ {
+ *Type = SCANF_TYPE_SPACE;
+ }
+
+ /* add %n so we know how far to increment the pointer */
+ *Out++ = '%';
+ *Out++ = 'n';
+
+ *Out = 0; /* end the string */
+ PAL_free(TempStr);
+ return Result;
+}
+
+/*******************************************************************************
+Function:
+ PAL_vsscanf
+
+Parameters:
+ Buffer
+ - buffer to parse values from
+ Format
+ - format string
+ ap
+ - stdarg parameter list
+*******************************************************************************/
+int PAL_vsscanf(LPCSTR Buffer, LPCSTR Format, va_list ap)
+{
+ INT Length = 0;
+ LPCSTR Buff = Buffer;
+ LPCSTR Fmt = Format;
+ CHAR TempBuff[1024]; /* used to hold a single %<foo> format string */
+ BOOL Store;
+ INT Width;
+ INT Prefix;
+ INT Type = -1;
+
+ while (*Fmt)
+ {
+ if (!*Buff && Length == 0)
+ {
+ Length = EOF;
+ break;
+ }
+ /* remove any number of blanks */
+ else if (isspace((unsigned char) *Fmt))
+ {
+ while (isspace((unsigned char) *Buff))
+ {
+ ++Buff;
+ }
+ ++Fmt;
+ }
+ else if (*Fmt == '%' &&
+ Internal_ScanfExtractFormatA(&Fmt, TempBuff, sizeof(TempBuff), &Store,
+ &Width, &Prefix, &Type))
+ {
+ if (Prefix == SCANF_PREFIX_LONG &&
+ (Type == SCANF_TYPE_STRING || Type == SCANF_TYPE_CHAR))
+ {
+ int len = 0;
+ int res;
+ WCHAR *charPtr = 0;
+
+ /* a single character */
+ if (Type == SCANF_TYPE_CHAR && Width == -1)
+ {
+ len = Width = 1;
+ }
+
+ /* calculate length of string to copy */
+ while (Buff[len] && !isspace((unsigned char) Buff[len]))
+ {
+ if (Width != -1 && len >= Width)
+ {
+ break;
+ }
+ ++len;
+ }
+
+ if (Store)
+ {
+ charPtr = va_arg(ap, WCHAR *);
+
+ res = MultiByteToWideChar(CP_ACP, 0, Buff, len,
+ charPtr, len);
+ if (!res)
+ {
+ ASSERT("MultiByteToWideChar failed. Error is %d\n",
+ GetLastError());
+ return -1;
+ }
+ if (Type == SCANF_TYPE_STRING)
+ {
+ /* end string */
+ charPtr[res] = 0;
+ }
+ ++Length;
+ }
+ Buff += len;
+ }
+ /* this places the number of bytes stored into the next arg */
+ else if (Type == SCANF_TYPE_N)
+ {
+ if (Prefix == SCANF_PREFIX_SHORT)
+ {
+ *(va_arg(ap, short *)) = Buff - Buffer;
+ }
+ else
+ {
+ *(va_arg(ap, LPLONG)) = Buff - Buffer;
+ }
+ }
+ /* types that sscanf can handle */
+ else
+ {
+ int ret;
+ int n;
+ LPVOID voidPtr = NULL;
+
+ if (Store)
+ {
+ // sscanf_s requires that if we are trying to read "%s" or "%c" or “%[“, then
+ // the size of the buffer must follow the buffer we are trying to read into.
+ voidPtr = va_arg(ap, LPVOID);
+ unsigned typeLen = 0;
+ if ((Type == SCANF_TYPE_STRING) || (Type == SCANF_TYPE_BRACKETS))
+ {
+ // Since this is not a Safe CRT API we don’t really know the size of the destination
+ // buffer provided by the caller. So we have to assume that the caller has allocated
+ // enough space to hold either the width specified in the format or the entire input
+ // string plus ‘\0’.
+ typeLen = ((Width > 0) ? Width : strlen(Buffer)) + 1;
+ }
+ else if (Type == SCANF_TYPE_CHAR)
+ {
+ // Check whether the format string contains number of characters
+ // that should be read from the input string.
+ // Note: ‘\0’ does not get appended in the “%c†case.
+ typeLen = (Width > 0) ? Width : 1;
+ }
+
+ if (typeLen > 0)
+ {
+ ret = sscanf_s(Buff, TempBuff, voidPtr, typeLen, &n);
+ }
+ else
+ {
+ ret = sscanf_s(Buff, TempBuff, voidPtr, &n);
+ }
+ }
+ else
+ {
+ ret = sscanf_s(Buff, TempBuff, &n);
+ }
+
+#if SSCANF_CANNOT_HANDLE_MISSING_EXPONENT
+ if ((ret == 0) && (Type == SCANF_TYPE_FLOAT))
+ {
+ ret = SscanfFloatCheckExponent(Buff, TempBuff, voidPtr, &n);
+ }
+#endif // SSCANF_CANNOT_HANDLE_MISSING_EXPONENT
+
+ if (ret > 0)
+ {
+ Length += ret;
+ }
+ else
+ {
+ /* no match, break scan */
+ break;
+ }
+ Buff += n;
+ }
+ }
+ else
+ {
+ /* grab, but not store */
+ if (*Fmt == *Buff && Type != SCANF_TYPE_SPACE)
+ {
+ ++Fmt;
+ ++Buff;
+ }
+ /* doesn't match, break scan */
+ else
+ {
+ break;
+ }
+ }
+ }
+
+ return Length;
+}
+
+/*******************************************************************************
+Function:
+ PAL_wvsscanf
+
+ -- see PAL_vsscanf above
+*******************************************************************************/
+int PAL_wvsscanf(LPCWSTR Buffer, LPCWSTR Format, va_list ap)
+{
+ INT Length = 0;
+ LPCWSTR Buff = Buffer;
+ LPCWSTR Fmt = Format;
+ CHAR TempBuff[1024]; /* used to hold a single %<foo> format string */
+ BOOL Store;
+ INT Width;
+ INT Prefix;
+ INT Type = -1;
+
+ while (*Fmt)
+ {
+ if (!*Buff && Length == 0)
+ {
+ Length = EOF;
+ break;
+ }
+ /* remove any number of blanks */
+ else if (isspace(*Fmt))
+ {
+ while (isspace(*Buff))
+ {
+ ++Buff;
+ }
+ ++Fmt;
+ }
+ else if (*Fmt == '%' &&
+ Internal_ScanfExtractFormatW(&Fmt, TempBuff, sizeof(TempBuff), &Store,
+ &Width, &Prefix, &Type))
+ {
+ if (Prefix == SCANF_PREFIX_LONG &&
+ (Type == SCANF_TYPE_STRING || Type == SCANF_TYPE_CHAR))
+ {
+ int len = 0;
+ WCHAR *charPtr = 0;
+
+ /* a single character */
+ if (Type == SCANF_TYPE_CHAR && Width == -1)
+ {
+ len = Width = 1;
+ }
+
+ /* calculate length of string to copy */
+ while (Buff[len] && !isspace(Buff[len]))
+ {
+ if (Width != -1 && len >= Width)
+ {
+ break;
+ }
+ ++len;
+ }
+
+ if (Store)
+ {
+ int i;
+ charPtr = va_arg(ap, WCHAR *);
+
+ for (i = 0; i < len; i++)
+ {
+ charPtr[i] = Buff[i];
+ }
+ if (Type == SCANF_TYPE_STRING)
+ {
+ /* end string */
+ charPtr[len] = 0;
+ }
+ ++Length;
+ }
+ Buff += len;
+ }
+ /* this places the number of bytes stored into the next arg */
+ else if (Type == SCANF_TYPE_N)
+ {
+ if (Prefix == SCANF_PREFIX_SHORT)
+ {
+ *(va_arg(ap, short *)) = Buff - Buffer;
+ }
+ else
+ {
+ *(va_arg(ap, LPLONG)) = Buff - Buffer;
+ }
+ }
+ /* types that sscanf can handle */
+ else
+ {
+ int ret;
+ int n;
+ int size;
+ LPSTR newBuff = 0;
+ LPVOID voidPtr = NULL;
+
+ size = WideCharToMultiByte(CP_ACP, 0, Buff, -1, 0, 0, 0, 0);
+ if (!size)
+ {
+ ASSERT("WideCharToMultiByte failed. Error is %d\n",
+ GetLastError());
+ return -1;
+ }
+ newBuff = (LPSTR) PAL_malloc(size);
+ if (!newBuff)
+ {
+ ERROR("PAL_malloc failed\n");
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ return -1;
+ }
+ size = WideCharToMultiByte(CP_ACP, 0, Buff, size,
+ newBuff, size, 0, 0);
+ if (!size)
+ {
+ ASSERT("WideCharToMultiByte failed. Error is %d\n",
+ GetLastError());
+ PAL_free(newBuff);
+ return -1;
+ }
+
+ if (Store)
+ {
+ if (Type == SCANF_TYPE_BRACKETS)
+ {
+ WCHAR *strPtr;
+ int i;
+
+ /* add a '*' to %[] --> %*[] */
+ i = strlen(TempBuff) + 1;
+ while (i)
+ {
+ /* shift everything right one */
+ TempBuff[i] = TempBuff[i - 1];
+ --i;
+ }
+ TempBuff[0] = '%';
+ TempBuff[1] = '*';
+
+ /* %n doesn't count as a conversion. Since we're
+ suppressing conversion of the %[], sscanf will
+ always return 0, so we can't use the return value
+ to determine success. Set n to 0 before the call; if
+ it's still 0 afterwards, we know the call failed */
+ n = 0;
+ sscanf_s(newBuff, TempBuff, &n);
+ if(0 == n)
+ {
+ /* sscanf failed, nothing matched. set ret to 0,
+ so we know we have to break */
+ ret = 0;
+ }
+ else
+ {
+ strPtr = va_arg(ap, WCHAR *);
+ for (i = 0; i < n; i++)
+ {
+ strPtr[i] = Buff[i];
+ }
+ strPtr[n] = 0; /* end string */
+ ret = 1;
+ }
+ }
+ else
+ {
+ voidPtr = va_arg(ap, LPVOID);
+ // sscanf_s requires that if we are trying to read "%s" or "%c", then
+ // the size of the buffer must follow the buffer we are trying to read into.
+ unsigned typeLen = 0;
+ if (Type == SCANF_TYPE_STRING)
+ {
+ // We don’t really know the size of the destination buffer provided by the
+ // caller. So we have to assume that the caller has allocated enough space
+ // to hold either the width specified in the format or the entire input
+ // string plus ‘\0’.
+ typeLen = ((Width > 0) ? Width : PAL_wcslen(Buffer)) + 1;
+ }
+ else if (Type == SCANF_TYPE_CHAR)
+ {
+ // Check whether the format string contains number of characters
+ // that should be read from the input string.
+ // Note: ‘\0’ does not get appended in the “%c†case.
+ typeLen = (Width > 0) ? Width : 1;
+ }
+
+ if (typeLen > 0)
+ {
+ ret = sscanf_s(newBuff, TempBuff, voidPtr, typeLen, &n);
+ }
+ else
+ ret = sscanf_s(newBuff, TempBuff, voidPtr, &n);
+ }
+ }
+ else
+ {
+ ret = sscanf_s(newBuff, TempBuff, &n);
+ }
+
+#if SSCANF_CANNOT_HANDLE_MISSING_EXPONENT
+ if ((ret == 0) && (Type == SCANF_TYPE_FLOAT))
+ {
+ ret = SscanfFloatCheckExponent(newBuff, TempBuff, voidPtr, &n);
+ }
+#endif // SSCANF_CANNOT_HANDLE_MISSING_EXPONENT
+
+ PAL_free(newBuff);
+ if (ret > 0)
+ {
+ Length += ret;
+ }
+ else
+ {
+ /* no match; break scan */
+ break;
+ }
+ Buff += n;
+ }
+ }
+ else
+ {
+ /* grab, but not store */
+ if (*Fmt == *Buff && Type != SCANF_TYPE_SPACE)
+ {
+ ++Fmt;
+ ++Buff;
+ }
+ /* doesn't match, break scan */
+ else
+ {
+ break;
+ }
+ }
+ }
+
+ return Length;
+}
+
+/*++
+Function:
+ PAL_sscanf
+
+See MSDN doc.
+--*/
+int
+__cdecl
+PAL_sscanf(
+ const char *buffer,
+ const char *format,
+ ...)
+{
+ int Length;
+ va_list ap;
+
+ PERF_ENTRY(sscanf);
+ ENTRY("PAL_sscanf (buffer=%p (%s), format=%p (%s))\n", buffer, buffer, format, format);
+
+ va_start(ap, format);
+ Length = PAL_vsscanf(buffer, format, ap);
+ va_end(ap);
+
+ LOGEXIT("PAL_sscanf returns int %d\n", Length);
+ PERF_EXIT(sscanf);
+ return Length;
+}
+
+/*++
+Function:
+ PAL_sprintf
+
+See MSDN doc.
+--*/
+int
+__cdecl
+PAL_sprintf(
+ char *buffer,
+ const char *format,
+ ...)
+{
+ LONG Length;
+ va_list ap;
+
+ PERF_ENTRY(sprintf);
+ ENTRY("PAL_sprintf (buffer=%p, format=%p (%s))\n", buffer, format, format);
+
+ va_start(ap, format);
+ Length = InternalVsnprintf(CorUnix::InternalGetCurrentThread(), buffer, 0x7fffffff, format, ap);
+ va_end(ap);
+
+ LOGEXIT("PAL_sprintf returns int %d\n", Length);
+ PERF_EXIT(sprintf);
+ return Length;
+}
+
+
+/*++
+Function:
+ PAL_swprintf
+
+See MSDN doc.
+--*/
+int
+__cdecl
+PAL_swprintf(
+ wchar_16 *buffer,
+ const wchar_16 *format,
+ ...)
+{
+ LONG Length;
+ va_list ap;
+
+ PERF_ENTRY(swprintf);
+ ENTRY("PAL_swprintf (buffer=%p, format=%p (%S))\n", buffer, format, format);
+
+ va_start(ap, format);
+ Length = PAL__wvsnprintf(buffer, 0x7fffffff, format, ap);
+ va_end(ap);
+
+ LOGEXIT("PAL_swprintf returns int %d\n", Length);
+ PERF_EXIT(swprintf);
+ return Length;
+}
+
+/*++
+Function:
+ PAL_swscanf
+
+See MSDN doc.
+--*/
+int
+__cdecl
+PAL_swscanf(
+ const wchar_16 *buffer,
+ const wchar_16 *format,
+ ...)
+{
+ int Length;
+ va_list ap;
+
+ PERF_ENTRY(swscanf);
+ ENTRY("PAL_swscanf (buffer=%p (%S), format=%p (%S))\n", buffer, buffer, format, format);
+
+ va_start(ap, format);
+ Length = PAL_wvsscanf(buffer, format, ap);
+ va_end(ap);
+
+ LOGEXIT("PAL_swscanf returns int %d\n", Length);
+ PERF_EXIT(swscanf);
+ return Length;
+}
+
+
+/*++
+Function:
+ PAL_vsprintf
+
+See MSDN doc.
+--*/
+int
+__cdecl
+PAL_vsprintf(char *buffer,
+ const char *format,
+ va_list argptr)
+{
+ LONG Length;
+
+ PERF_ENTRY(vsprintf);
+ ENTRY("PAL_vsprintf (buffer=%p, format=%p (%s), argptr=%p)\n",
+ buffer, format, format, argptr);
+
+ Length = InternalVsnprintf(CorUnix::InternalGetCurrentThread(), buffer, 0x7fffffff, format, argptr);
+
+ LOGEXIT("PAL_vsprintf returns int %d\n", Length);
+ PERF_EXIT(vsprintf);
+
+ return Length;
+}
+
+
+/*++
+Function:
+ PAL_vswprintf
+
+See MSDN doc.
+--*/
+int
+__cdecl
+PAL_vswprintf(wchar_16 *buffer,
+ const wchar_16 *format,
+ va_list argptr)
+{
+ LONG Length;
+
+ PERF_ENTRY(vswprintf);
+ ENTRY("PAL_vswprintf (buffer=%p, format=%p (%S), argptr=%p)\n",
+ buffer, format, format, argptr);
+
+ Length = PAL__wvsnprintf(buffer, 0x7fffffff, format, argptr);
+
+ LOGEXIT("PAL_vswprintf returns int %d\n", Length);
+ PERF_EXIT(vswprintf);
+
+ return Length;
+}
+
+
+/*++
+Function:
+ _vsnwprintf
+
+See MSDN doc.
+--*/
+int
+__cdecl
+_vsnwprintf(wchar_16 *buffer,
+ size_t count,
+ const wchar_16 *format,
+ va_list argptr)
+{
+ LONG Length;
+
+ PERF_ENTRY(_vsnwprintf);
+ ENTRY("_vsnwprintf (buffer=%p, count=%lu, format=%p (%S), argptr=%p)\n",
+ buffer, (unsigned long) count, format, format, argptr);
+
+ Length = PAL__wvsnprintf(buffer, count, format, argptr);
+
+ LOGEXIT("_vsnwprintf returns int %d\n", Length);
+ PERF_EXIT(_vsnwprintf);
+
+ return Length;
+}
+
+#if SSCANF_CANNOT_HANDLE_MISSING_EXPONENT
+/*++
+Function:
+ SscanfFloatCheckExponent
+
+ Parameters:
+ buff: pointer to the buffer to be parsed; the target float must be at
+ the beginning of the buffer, except for any number of leading
+ spaces
+ floatFmt: must be "%e%n" (or "%f%n" or "%g%n")
+ voidptr: optional pointer to output variable (which should be a float)
+ pn: pointer to an int to receive the number of bytes parsed.
+
+ Notes:
+ On some platforms (specifically AIX) sscanf fails to parse a float from
+ a string such as 12.34e (while it succeeds for e.g. 12.34a). Sscanf
+ initially interprets the 'e' as the keyword for the beginning of a
+ 10-exponent of a floating point in scientific notation (as in 12.34e5),
+ but then it fails to parse the actual exponent. At this point sscanf should
+ be able to fall back on the narrower pattern, and parse the floating point
+ in common decimal notation (i.e. 12.34). However AIX's sscanf fails to do
+ so and it does not parse any number.
+ This function checks the given string for a such case and removes
+ the 'e' before parsing the float.
+
+--*/
+
+static int SscanfFloatCheckExponent(LPCSTR buff, LPCSTR floatFmt,
+ void * voidPtr, int * pn)
+{
+ int ret = 0;
+ int digits = 0;
+ int points = 0;
+ LPCSTR pos = buff;
+
+ /* skip initial spaces */
+ while (*pos && isspace(*pos))
+ pos++;
+
+ /* go to the end of a float, if there is one */
+ while (*pos)
+ {
+ if (isdigit(*pos))
+ digits++;
+ else if (*pos == '.')
+ {
+ if (++points > 1)
+ break;
+ }
+ else
+ break;
+
+ pos++;
+ }
+
+ /* check if it is something like 12.34e and the trailing 'e' is not
+ the suffix of a valid exponent of 10, such as 12.34e+5 */
+ if ( digits > 0 && *pos && tolower(*pos) == 'e' &&
+ !( *(pos+1) &&
+ ( isdigit(*(pos+1)) ||
+ ( (*(pos+1) == '+' || *(pos+1) == '-') && isdigit(*(pos+2)) )
+ )
+ )
+ )
+ {
+ CHAR * pLocBuf = (CHAR *)PAL_malloc((pos-buff+1)*sizeof(CHAR));
+ if (pLocBuf)
+ {
+ memcpy(pLocBuf, buff, (pos-buff)*sizeof(CHAR));
+ pLocBuf[pos-buff] = 0;
+ if (voidPtr)
+ ret = sscanf_s(pLocBuf, floatFmt, voidPtr, pn);
+ else
+ ret = sscanf_s(pLocBuf, floatFmt, pn);
+ PAL_free (pLocBuf);
+ }
+ }
+ return ret;
+}
+#endif // SSCANF_CANNOT_HANDLE_MISSING_EXPONENT
diff --git a/src/pal/src/cruntime/printfcpp.cpp b/src/pal/src/cruntime/printfcpp.cpp
new file mode 100644
index 0000000000..ea074a604b
--- /dev/null
+++ b/src/pal/src/cruntime/printfcpp.cpp
@@ -0,0 +1,2556 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ printfcpp.cpp
+
+Abstract:
+
+ Implementation of suspension safe printf functions.
+
+Revision History:
+
+
+
+--*/
+
+#include "pal/corunix.hpp"
+#include "pal/thread.hpp"
+#include "pal/malloc.hpp"
+#include "pal/file.hpp"
+#include "pal/printfcpp.hpp"
+#include "pal/palinternal.h"
+#include "pal/dbgmsg.h"
+#include "pal/cruntime.h"
+
+#include <errno.h>
+
+SET_DEFAULT_DEBUG_CHANNEL(CRT);
+
+using namespace CorUnix;
+
+int CoreWvsnprintf(CPalThread *pthrCurrent, LPWSTR Buffer, size_t Count, LPCWSTR Format, va_list ap);
+int CoreVsnprintf(CPalThread *pthrCurrent, LPSTR Buffer, size_t Count, LPCSTR Format, va_list ap);
+int CoreVfprintf(CPalThread *pthrCurrent, PAL_FILE *stream, const char *format, va_list ap);
+int CoreVfwprintf(CPalThread *pthrCurrent, PAL_FILE *stream, const wchar_16 *format, va_list ap);
+
+extern "C"
+{
+
+/*******************************************************************************
+Function:
+ Internal_Convertfwrite
+ This function is a wrapper around fwrite for cases where the buffer has
+ to be converted from WideChar to MultiByte
+*******************************************************************************/
+
+static int Internal_Convertfwrite(CPalThread *pthrCurrent, const void *buffer, size_t size, size_t count, FILE *stream, BOOL convert)
+{
+ int ret;
+ int iError = 0;
+
+#if FILE_OPS_CHECK_FERROR_OF_PREVIOUS_CALL
+ clearerr (stream);
+#endif
+
+ if(convert)
+ {
+ int nsize;
+ LPSTR newBuff = 0;
+ nsize = WideCharToMultiByte(CP_ACP, 0,(LPCWSTR)buffer, count, 0, 0, 0, 0);
+ if (!nsize)
+ {
+ ASSERT("WideCharToMultiByte failed. Error is %d\n", GetLastError());
+ return -1;
+ }
+ newBuff = (LPSTR) InternalMalloc(nsize);
+ if (!newBuff)
+ {
+ ERROR("InternalMalloc failed\n");
+ pthrCurrent->SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ return -1;
+ }
+ nsize = WideCharToMultiByte(CP_ACP, 0, (LPCWSTR)buffer, count, newBuff, nsize, 0, 0);
+ if (!nsize)
+ {
+ ASSERT("WideCharToMultiByte failed. Error is %d\n", GetLastError());
+ free(newBuff);
+ return -1;
+ }
+ ret = InternalFwrite(newBuff, 1, count, stream, &iError);
+ if (iError != 0)
+ {
+ ERROR("InternalFwrite did not write the whole buffer. Error is %d\n", iError);
+ free(newBuff);
+ return -1;
+ }
+ free(newBuff);
+ }
+ else
+ {
+ ret = InternalFwrite(buffer, size, count, stream, &iError);
+ if (iError != 0)
+ {
+ ERROR("InternalFwrite did not write the whole buffer. Error is %d\n", iError);
+ return -1;
+ }
+ }
+ return ret;
+
+}
+
+/*******************************************************************************
+Function:
+ Internal_ExtractFormatA
+
+Paramaters:
+ Fmt
+ - format string to parse
+ - first character must be a '%'
+ - paramater gets updated to point to the character after
+ the %<foo> format string
+ Out
+ - buffer will contain the %<foo> format string
+ Flags
+ - paramater will be set with the PRINTF_FORMAT_FLAGS defined above
+ Width
+ - will contain the width specified by the format string
+ - -1 if none given
+ Precision
+ - will contain the precision specified in the format string
+ - -1 if none given
+ Prefix
+ - an enumeration of the type prefix
+ Type
+ - an enumeration of the type value
+
+Notes:
+ - I'm also handling the undocumented %ws, %wc, %w...
+ - %#10x, when we have a width greater than the length (i.e padding) the
+ length of the padding is not consistent with MS's wsprintf
+ (MS adds an extra 2 padding chars, length of "0x")
+ - MS's wsprintf seems to ingore a 'h' prefix for number types
+ - MS's "%p" is different than gcc's
+ e.g. printf("%p", NULL);
+ MS --> 00000000
+ gcc --> 0x0
+ - the length of the exponent (precision) for floating types is different
+ between MS and gcc
+ e.g. printf("%E", 256.0);
+ MS --> 2.560000E+002
+ gcc --> 2.560000E+02
+*******************************************************************************/
+BOOL Internal_ExtractFormatA(CPalThread *pthrCurrent, LPCSTR *Fmt, LPSTR Out, LPINT Flags,
+ LPINT Width, LPINT Precision, LPINT Prefix, LPINT Type)
+{
+ BOOL Result = FALSE;
+ LPSTR TempStr;
+ LPSTR TempStrPtr;
+
+ *Width = WIDTH_DEFAULT;
+ *Precision = PRECISION_DEFAULT;
+ *Flags = PFF_NONE;
+ *Prefix = PFF_PREFIX_DEFAULT;
+ *Type = PFF_TYPE_DEFAULT;
+
+ if (*Fmt && **Fmt == '%')
+ {
+ *Out++ = *(*Fmt)++;
+ }
+ else
+ {
+ return Result;
+ }
+
+ /* we'll never need a temp string longer than the original */
+ TempStrPtr = TempStr = (LPSTR) InternalMalloc(strlen(*Fmt)+1);
+ if (!TempStr)
+ {
+ ERROR("InternalMalloc failed\n");
+ pthrCurrent->SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ return Result;
+ }
+
+ /* parse flags */
+ while (**Fmt && (**Fmt == '-' || **Fmt == '+' ||
+ **Fmt == '0' || **Fmt == ' ' || **Fmt == '#'))
+ {
+ switch (**Fmt)
+ {
+ case '-':
+ *Flags |= PFF_MINUS; break;
+ case '+':
+ *Flags |= PFF_PLUS; break;
+ case '0':
+ *Flags |= PFF_ZERO; break;
+ case ' ':
+ *Flags |= PFF_SPACE; break;
+ case '#':
+ *Flags |= PFF_POUND; break;
+ }
+ *Out++ = *(*Fmt)++;
+ }
+ /* '-' flag negates '0' flag */
+ if ((*Flags & PFF_MINUS) && (*Flags & PFF_ZERO))
+ {
+ *Flags -= PFF_ZERO;
+ }
+
+ /* grab width specifier */
+ if (isdigit((unsigned char) **Fmt))
+ {
+ TempStrPtr = TempStr;
+ while (isdigit((unsigned char) **Fmt))
+ {
+ *TempStrPtr++ = **Fmt;
+ *Out++ = *(*Fmt)++;
+ }
+ *TempStrPtr = 0; /* end string */
+ *Width = atoi(TempStr);
+ if (*Width < 0)
+ {
+ ERROR("atoi returned a negative value indicative of an overflow.\n");
+ pthrCurrent->SetLastError(ERROR_INTERNAL_ERROR);
+ return Result;
+ }
+ }
+ else if (**Fmt == '*')
+ {
+ *Width = WIDTH_STAR;
+ *Out++ = *(*Fmt)++;
+ if (isdigit((unsigned char) **Fmt))
+ {
+ /* this is an invalid width because we have a * then a number */
+ /* printf handles this by just printing the whole string */
+ *Width = WIDTH_INVALID;
+ while (isdigit((unsigned char) **Fmt))
+ {
+ *Out++ = *(*Fmt)++;
+ }
+ }
+ }
+
+
+ /* grab precision specifier */
+ if (**Fmt == '.')
+ {
+ *Out++ = *(*Fmt)++;
+ if (isdigit((unsigned char) **Fmt))
+ {
+ TempStrPtr = TempStr;
+ while (isdigit((unsigned char) **Fmt))
+ {
+ *TempStrPtr++ = **Fmt;
+ *Out++ = *(*Fmt)++;
+ }
+ *TempStrPtr = 0; /* end string */
+ *Precision = atoi(TempStr);
+ if (*Precision < 0)
+ {
+ ERROR("atoi returned a negative value indicative of an overflow.\n");
+ pthrCurrent->SetLastError(ERROR_INTERNAL_ERROR);
+ return Result;
+ }
+ }
+ else if (**Fmt == '*')
+ {
+ *Precision = PRECISION_STAR;
+ *Out++ = *(*Fmt)++;
+ if (isdigit((unsigned char) **Fmt))
+ {
+ /* this is an invalid precision because we have a .* then a number */
+ /* printf handles this by just printing the whole string */
+ *Precision = PRECISION_INVALID;
+ while (isdigit((unsigned char) **Fmt))
+ {
+ *Out++ = *(*Fmt)++;
+ }
+ }
+ }
+ else
+ {
+ *Precision = PRECISION_DOT;
+ }
+ }
+
+#ifdef BIT64
+ if (**Fmt == 'p')
+ {
+ *Prefix = PFF_PREFIX_LONGLONG;
+ }
+#endif
+ if ((*Fmt)[0] == 'I')
+ {
+ /* grab prefix of 'I64' for __int64 */
+ if ((*Fmt)[1] == '6' && (*Fmt)[2] == '4')
+ {
+ /* convert to 'll' so that Unix snprintf can handle it */
+ *Fmt += 3;
+ *Prefix = PFF_PREFIX_LONGLONG;
+ }
+ /* grab prefix of 'I32' for __int32 */
+ else if ((*Fmt)[1] == '3' && (*Fmt)[2] == '2')
+ {
+ *Fmt += 3;
+ }
+ else
+ {
+ ++(*Fmt);
+ #ifdef BIT64
+ /* convert to 'll' so that Unix snprintf can handle it */
+ *Prefix = PFF_PREFIX_LONGLONG;
+ #endif
+ }
+ }
+ /* grab a prefix of 'h' */
+ else if (**Fmt == 'h')
+ {
+ *Prefix = PFF_PREFIX_SHORT;
+ ++(*Fmt);
+ }
+ /* grab prefix of 'l' or the undocumented 'w' (at least in MSDN) */
+ else if (**Fmt == 'l' || **Fmt == 'w')
+ {
+ ++(*Fmt);
+#ifdef BIT64
+ // Only want to change the prefix on 64 bit when printing characters.
+ if (**Fmt == 'c' || **Fmt == 's')
+#endif
+ {
+ *Prefix = PFF_PREFIX_LONG;
+ }
+ if (**Fmt == 'l')
+ {
+ *Prefix = PFF_PREFIX_LONGLONG;
+ ++(*Fmt);
+ }
+ }
+ else if (**Fmt == 'L')
+ {
+ /* a prefix of 'L' seems to be ignored */
+ ++(*Fmt);
+ }
+
+ /* grab type 'c' */
+ if (**Fmt == 'c' || **Fmt == 'C')
+ {
+ *Type = PFF_TYPE_CHAR;
+ if (*Prefix != PFF_PREFIX_SHORT && **Fmt == 'C')
+ {
+ *Prefix = PFF_PREFIX_LONG; /* give it a wide prefix */
+ }
+ if (*Prefix == PFF_PREFIX_LONG)
+ {
+ *Out++ = 'l';
+ }
+ *Out++ = 'c';
+ ++(*Fmt);
+ Result = TRUE;
+ }
+ /* grab type 's' */
+ else if (**Fmt == 's' || **Fmt == 'S')
+ {
+ *Type = PFF_TYPE_STRING;
+ if (*Prefix != PFF_PREFIX_SHORT && **Fmt == 'S')
+ {
+ *Prefix = PFF_PREFIX_LONG; /* give it a wide prefix */
+ }
+ if (*Prefix == PFF_PREFIX_LONG)
+ {
+ *Out++ = 'l';
+ }
+ *Out++ = 's';
+ ++(*Fmt);
+ Result = TRUE;
+ }
+ /* grab int types */
+ else if (**Fmt == 'd' || **Fmt == 'i' || **Fmt == 'o' ||
+ **Fmt == 'u' || **Fmt == 'x' || **Fmt == 'X')
+ {
+ *Type = PFF_TYPE_INT;
+ if (*Prefix == PFF_PREFIX_SHORT)
+ {
+ *Out++ = 'h';
+ }
+ else if (*Prefix == PFF_PREFIX_LONG)
+ {
+ *Out++ = 'l';
+ }
+ else if (*Prefix == PFF_PREFIX_LONGLONG)
+ {
+ *Out++ = 'l';
+ *Out++ = 'l';
+ }
+ *Out++ = *(*Fmt)++;
+ Result = TRUE;
+ }
+ else if (**Fmt == 'e' || **Fmt == 'E' || **Fmt == 'f' ||
+ **Fmt == 'g' || **Fmt == 'G')
+ {
+ /* we can safely ignore the prefixes and only add the type*/
+ *Type = PFF_TYPE_FLOAT;
+ *Out++ = *(*Fmt)++;
+ Result = TRUE;
+ }
+ else if (**Fmt == 'n')
+ {
+ if (*Prefix == PFF_PREFIX_SHORT)
+ {
+ *Out++ = 'h';
+ }
+ *Out++ = *(*Fmt)++;
+ *Type = PFF_TYPE_N;
+ Result = TRUE;
+ }
+ else if (**Fmt == 'p')
+ {
+ *Type = PFF_TYPE_P;
+ (*Fmt)++;
+
+ if (*Prefix == PFF_PREFIX_LONGLONG)
+ {
+ if (*Precision == PRECISION_DEFAULT)
+ {
+ *Precision = 16;
+ *Out++ = '.';
+ *Out++ = '1';
+ *Out++ = '6';
+ }
+ /* native *printf does not support %I64p
+ (actually %llp), so we need to cheat a little bit */
+ *Out++ = 'l';
+ *Out++ = 'l';
+ }
+ else
+ {
+ if (*Precision == PRECISION_DEFAULT)
+ {
+ *Precision = 8;
+ *Out++ = '.';
+ *Out++ = '8';
+ }
+ }
+ *Out++ = 'X';
+ Result = TRUE;
+ }
+
+ *Out = 0; /* end the string */
+ free(TempStr);
+ return Result;
+}
+
+/*******************************************************************************
+Function:
+ Internal_ExtractFormatW
+
+ -- see Internal_ExtractFormatA above
+*******************************************************************************/
+BOOL Internal_ExtractFormatW(CPalThread *pthrCurrent, LPCWSTR *Fmt, LPSTR Out, LPINT Flags,
+ LPINT Width, LPINT Precision, LPINT Prefix, LPINT Type)
+{
+ BOOL Result = FALSE;
+ LPSTR TempStr;
+ LPSTR TempStrPtr;
+
+ *Width = WIDTH_DEFAULT;
+ *Precision = PRECISION_DEFAULT;
+ *Flags = PFF_NONE;
+ *Prefix = PFF_PREFIX_DEFAULT;
+ *Type = PFF_TYPE_DEFAULT;
+
+ if (*Fmt && **Fmt == '%')
+ {
+ *Out++ = (CHAR) *(*Fmt)++;
+ }
+ else
+ {
+ return Result;
+ }
+
+ /* we'll never need a temp string longer than the original */
+ TempStrPtr = TempStr = (LPSTR) InternalMalloc(PAL_wcslen(*Fmt)+1);
+ if (!TempStr)
+ {
+ ERROR("InternalMalloc failed\n");
+ pthrCurrent->SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ return Result;
+ }
+
+ /* parse flags */
+ while (**Fmt && (**Fmt == '-' || **Fmt == '+' ||
+ **Fmt == '0' || **Fmt == ' ' || **Fmt == '#'))
+ {
+ switch (**Fmt)
+ {
+ case '-':
+ *Flags |= PFF_MINUS; break;
+ case '+':
+ *Flags |= PFF_PLUS; break;
+ case '0':
+ *Flags |= PFF_ZERO; break;
+ case ' ':
+ *Flags |= PFF_SPACE; break;
+ case '#':
+ *Flags |= PFF_POUND; break;
+ }
+ *Out++ = (CHAR) *(*Fmt)++;
+ }
+ /* '-' flag negates '0' flag */
+ if ((*Flags & PFF_MINUS) && (*Flags & PFF_ZERO))
+ {
+ *Flags -= PFF_ZERO;
+ }
+
+ /* grab width specifier */
+ if (isdigit(**Fmt))
+ {
+ TempStrPtr = TempStr;
+ while (isdigit(**Fmt))
+ {
+ *TempStrPtr++ = (CHAR) **Fmt;
+ *Out++ = (CHAR) *(*Fmt)++;
+ }
+ *TempStrPtr = 0; /* end string */
+ *Width = atoi(TempStr);
+ if (*Width < 0)
+ {
+ ERROR("atoi returned a negative value indicative of an overflow.\n");
+ pthrCurrent->SetLastError(ERROR_INTERNAL_ERROR);
+ return Result;
+ }
+ }
+ else if (**Fmt == '*')
+ {
+ *Width = WIDTH_STAR;
+ *Out++ = (CHAR) *(*Fmt)++;
+ if (isdigit(**Fmt))
+ {
+ /* this is an invalid width because we have a * then a number */
+ /* printf handles this by just printing the whole string */
+ *Width = WIDTH_INVALID;
+ while (isdigit(**Fmt))
+ {
+ *Out++ = (CHAR) *(*Fmt)++;
+ }
+ }
+ }
+
+ /* grab precision specifier */
+ if (**Fmt == '.')
+ {
+ *Out++ = (CHAR) *(*Fmt)++;
+ if (isdigit(**Fmt))
+ {
+ TempStrPtr = TempStr;
+ while (isdigit(**Fmt))
+ {
+ *TempStrPtr++ = (CHAR) **Fmt;
+ *Out++ = (CHAR) *(*Fmt)++;
+ }
+ *TempStrPtr = 0; /* end string */
+ *Precision = atoi(TempStr);
+ if (*Precision < 0)
+ {
+ ERROR("atoi returned a negative value indicative of an overflow.\n");
+ pthrCurrent->SetLastError(ERROR_INTERNAL_ERROR);
+ return Result;
+ }
+ }
+ else if (**Fmt == '*')
+ {
+ *Precision = PRECISION_STAR;
+ *Out++ = (CHAR) *(*Fmt)++;
+ if (isdigit(**Fmt))
+ {
+ /* this is an invalid precision because we have a .* then a number */
+ /* printf handles this by just printing the whole string */
+ *Precision = PRECISION_INVALID;
+ while (isdigit(**Fmt))
+ {
+ *Out++ = (CHAR) *(*Fmt)++;
+ }
+ }
+ }
+ else
+ {
+ *Precision = PRECISION_DOT;
+ }
+ }
+
+#ifdef BIT64
+ if (**Fmt == 'p')
+ {
+ *Prefix = PFF_PREFIX_LONGLONG;
+ }
+#endif
+ if ((*Fmt)[0] == 'I')
+ {
+ /* grab prefix of 'I64' for __int64 */
+ if ((*Fmt)[1] == '6' && (*Fmt)[2] == '4')
+ {
+ /* convert to 'll' so that Unix snprintf can handle it */
+ *Fmt += 3;
+ *Prefix = PFF_PREFIX_LONGLONG;
+ }
+ /* grab prefix of 'I32' for __int32 */
+ else if ((*Fmt)[1] == '3' && (*Fmt)[2] == '2')
+ {
+ *Fmt += 3;
+ }
+ else
+ {
+ ++(*Fmt);
+ #ifdef BIT64
+ /* convert to 'll' so that Unix snprintf can handle it */
+ *Prefix = PFF_PREFIX_LONGLONG;
+ #endif
+ }
+ }
+ /* grab a prefix of 'h' */
+ else if (**Fmt == 'h')
+ {
+ *Prefix = PFF_PREFIX_SHORT;
+ ++(*Fmt);
+ }
+ else if (**Fmt == 'l' || **Fmt == 'w')
+ {
+ ++(*Fmt);
+ #ifdef BIT64
+ // Only want to change the prefix on 64 bit when printing characters.
+ if (**Fmt == 'C' || **Fmt == 'S')
+#endif
+ {
+ *Prefix = PFF_PREFIX_LONG_W;
+ }
+ if (**Fmt == 'l')
+ {
+ *Prefix = PFF_PREFIX_LONGLONG;
+ ++(*Fmt);
+ }
+ }
+ else if (**Fmt == 'L')
+ {
+ /* a prefix of 'L' seems to be ignored */
+ ++(*Fmt);
+ }
+
+
+ /* grab type 'c' */
+ if (**Fmt == 'c' || **Fmt == 'C')
+ {
+ *Type = PFF_TYPE_CHAR;
+ if (*Prefix != PFF_PREFIX_SHORT && **Fmt == 'c')
+ {
+ *Prefix = PFF_PREFIX_LONG; /* give it a wide prefix */
+ }
+ if (*Prefix == PFF_PREFIX_LONG || *Prefix == PFF_PREFIX_LONG_W)
+ {
+ *Out++ = 'l';
+ *Prefix = PFF_PREFIX_LONG;
+ }
+ *Out++ = 'c';
+ ++(*Fmt);
+ Result = TRUE;
+ }
+ /* grab type 's' */
+ else if (**Fmt == 's' || **Fmt == 'S' )
+ {
+ if ( **Fmt == 'S' )
+ {
+ *Type = PFF_TYPE_WSTRING;
+ }
+ else
+ {
+ *Type = PFF_TYPE_STRING;
+ }
+ if (*Prefix != PFF_PREFIX_SHORT && **Fmt == 's')
+ {
+ *Prefix = PFF_PREFIX_LONG; /* give it a wide prefix */
+ }
+ if (*Prefix == PFF_PREFIX_LONG)
+ {
+ *Out++ = 'l';
+ }
+
+ *Out++ = 's';
+ ++(*Fmt);
+ Result = TRUE;
+ }
+ /* grab int types */
+ else if (**Fmt == 'd' || **Fmt == 'i' || **Fmt == 'o' ||
+ **Fmt == 'u' || **Fmt == 'x' || **Fmt == 'X')
+ {
+ *Type = PFF_TYPE_INT;
+ if (*Prefix == PFF_PREFIX_SHORT)
+ {
+ *Out++ = 'h';
+ }
+ else if (*Prefix == PFF_PREFIX_LONG || *Prefix == PFF_PREFIX_LONG_W)
+ {
+ *Out++ = 'l';
+ *Prefix = PFF_PREFIX_LONG;
+ }
+ else if (*Prefix == PFF_PREFIX_LONGLONG)
+ {
+ *Out++ = 'l';
+ *Out++ = 'l';
+ }
+ *Out++ = *(*Fmt)++;
+ Result = TRUE;
+ }
+ else if (**Fmt == 'e' || **Fmt == 'E' || **Fmt == 'f' ||
+ **Fmt == 'g' || **Fmt == 'G')
+ {
+ /* we can safely ignore the prefixes and only add the type*/
+ if (*Prefix == PFF_PREFIX_LONG_W)
+ {
+ *Prefix = PFF_PREFIX_LONG;
+ }
+
+ *Type = PFF_TYPE_FLOAT;
+ *Out++ = *(*Fmt)++;
+ Result = TRUE;
+ }
+ else if (**Fmt == 'n')
+ {
+ if (*Prefix == PFF_PREFIX_LONG_W)
+ {
+ *Prefix = PFF_PREFIX_LONG;
+ }
+
+ if (*Prefix == PFF_PREFIX_SHORT)
+ {
+ *Out++ = 'h';
+ }
+ *Out++ = *(*Fmt)++;
+ *Type = PFF_TYPE_N;
+ Result = TRUE;
+ }
+ else if (**Fmt == 'p')
+ {
+ *Type = PFF_TYPE_P;
+ (*Fmt)++;
+
+ if (*Prefix == PFF_PREFIX_LONGLONG)
+ {
+ if (*Precision == PRECISION_DEFAULT)
+ {
+ *Precision = 16;
+ *Out++ = '.';
+ *Out++ = '1';
+ *Out++ = '6';
+ }
+ /* native *printf does not support %I64p
+ (actually %llp), so we need to cheat a little bit */
+ *Out++ = 'l';
+ *Out++ = 'l';
+ }
+ else
+ {
+ if (*Precision == PRECISION_DEFAULT)
+ {
+ *Precision = 8;
+ *Out++ = '.';
+ *Out++ = '8';
+ }
+ if (*Prefix == PFF_PREFIX_LONG_W)
+ {
+ *Prefix = PFF_PREFIX_LONG;
+ }
+ }
+ *Out++ = 'X';
+ Result = TRUE;
+ }
+
+ *Out = 0; /* end the string */
+ free(TempStr);
+ return Result;
+}
+
+/*******************************************************************************
+Function:
+ Internal_AddPaddingW
+
+Parameters:
+ Out
+ - buffer to place padding and given string (In)
+ Count
+ - maximum chars to be copied so as not to overrun given buffer
+ In
+ - string to place into (Out) accompanied with padding
+ Padding
+ - number of padding chars to add
+ Flags
+ - padding style flags (PRINTF_FORMAT_FLAGS)
+*******************************************************************************/
+
+BOOL Internal_AddPaddingW(LPWSTR *Out, INT Count, LPWSTR In, INT Padding, INT Flags)
+{
+ LPWSTR OutOriginal = *Out;
+ INT PaddingOriginal = Padding;
+ INT LengthInStr;
+ LengthInStr = PAL_wcslen(In);
+
+
+ if (Padding < 0)
+ {
+ /* this is used at the bottom to determine if the buffer ran out */
+ PaddingOriginal = 0;
+ }
+ if (Flags & PFF_MINUS) /* pad on right */
+ {
+ if (wcsncpy_s(*Out, Count, In, min(LengthInStr + 1, Count - 1)) != SAFECRT_SUCCESS)
+ {
+ return FALSE;
+ }
+
+ *Out += min(LengthInStr, Count - 1);
+ }
+ if (Padding > 0)
+ {
+ if (Flags & PFF_ZERO) /* '0', pad with zeros */
+ {
+ while (Padding-- && Count > *Out - OutOriginal)
+ {
+ *(*Out)++ = '0';
+ }
+ }
+ else /* pad left with spaces */
+ {
+ while (Padding-- && Count > *Out - OutOriginal)
+ {
+ *(*Out)++ = ' ';
+ }
+ }
+ }
+ if (!(Flags & PFF_MINUS)) /* put 'In' after padding */
+ {
+ if (wcsncpy_s(*Out, Count - (*Out - OutOriginal), In,
+ min(LengthInStr, Count - (*Out - OutOriginal) - 1)) != SAFECRT_SUCCESS)
+ {
+ return FALSE;
+ }
+
+ *Out += min(LengthInStr, Count - (*Out - OutOriginal) - 1);
+ }
+
+ if (LengthInStr + PaddingOriginal > Count - 1)
+ {
+ return FALSE;
+ }
+ else
+ {
+ return TRUE;
+ }
+}
+
+/*******************************************************************************
+Function:
+ Internal_AddPaddingVfprintf
+
+Parameters:
+ stream
+ - file stream to place padding and given string (In)
+ In
+ - string to place into (Out) accompanied with padding
+ Padding
+ - number of padding chars to add
+ Flags
+ - padding style flags (PRINTF_FORMAT_FLAGS)
+*******************************************************************************/
+
+INT Internal_AddPaddingVfprintf(CPalThread *pthrCurrent, PAL_FILE *stream, LPSTR In,
+ INT Padding, INT Flags)
+{
+ LPSTR Out;
+ INT LengthInStr;
+ INT Length;
+ LPSTR OutOriginal;
+ INT Written;
+
+ LengthInStr = strlen(In);
+ Length = LengthInStr;
+
+ if (Padding > 0)
+ {
+ Length += Padding;
+ }
+ Out = (LPSTR) InternalMalloc(Length+1);
+ int iLength = Length+1;
+ if (!Out)
+ {
+ ERROR("InternalMalloc failed\n");
+ pthrCurrent->SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ return -1;
+ }
+ OutOriginal = Out;
+
+ if (Flags & PFF_MINUS) /* pad on right */
+ {
+ if (strcpy_s(Out, iLength, In) != SAFECRT_SUCCESS)
+ {
+ ERROR("strcpy_s failed\n");
+ pthrCurrent->SetLastError(ERROR_INSUFFICIENT_BUFFER);
+ Written = -1;
+ goto Done;
+ }
+
+ Out += LengthInStr;
+ iLength -= LengthInStr;
+ }
+ if (Padding > 0)
+ {
+ iLength -= Padding;
+ if (Flags & PFF_ZERO) /* '0', pad with zeros */
+ {
+ while (Padding--)
+ {
+ *Out++ = '0';
+ }
+ }
+ else /* pad with spaces */
+ {
+ while (Padding--)
+ {
+ *Out++ = ' ';
+ }
+ }
+ }
+ if (!(Flags & PFF_MINUS)) /* put 'In' after padding */
+ {
+ if (strcpy_s(Out, iLength, In) != SAFECRT_SUCCESS)
+ {
+ ERROR("strcpy_s failed\n");
+ pthrCurrent->SetLastError(ERROR_INSUFFICIENT_BUFFER);
+ Written = -1;
+ goto Done;
+ }
+
+ Out += LengthInStr;
+ iLength -= LengthInStr;
+ }
+
+#if FILE_OPS_CHECK_FERROR_OF_PREVIOUS_CALL
+ clearerr (stream->bsdFilePtr);
+#endif
+
+ Written = InternalFwrite(OutOriginal, 1, Length, stream->bsdFilePtr, &stream->PALferrorCode);
+ if (stream->PALferrorCode == PAL_FILE_ERROR)
+ {
+ ERROR("fwrite() failed with errno == %d\n", errno);
+ }
+
+Done:
+ free(OutOriginal);
+
+ return Written;
+}
+
+/*******************************************************************************
+Function:
+ Internal_AddPaddingVfwprintf
+
+Parameters:
+ stream
+ - file stream to place padding and given string (In)
+ In
+ - string to place into (Out) accompanied with padding
+ Padding
+ - number of padding chars to add
+ Flags
+ - padding style flags (PRINTF_FORMAT_FLAGS)
+*******************************************************************************/
+static INT Internal_AddPaddingVfwprintf(CPalThread *pthrCurrent, PAL_FILE *stream, LPWSTR In,
+ INT Padding, INT Flags,BOOL convert)
+{
+ LPWSTR Out;
+ LPWSTR OutOriginal;
+ INT LengthInStr;
+ INT Length;
+ INT Written = 0;
+
+ LengthInStr = PAL_wcslen(In);
+ Length = LengthInStr;
+
+ if (Padding > 0)
+ {
+ Length += Padding;
+ }
+
+ int iLen = (Length+1);
+ Out = (LPWSTR) InternalMalloc(iLen * sizeof(WCHAR));
+ if (!Out)
+ {
+ ERROR("InternalMalloc failed\n");
+ pthrCurrent->SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ return -1;
+ }
+ OutOriginal = Out;
+
+ if (Flags & PFF_MINUS) /* pad on right */
+ {
+ if (wcscpy_s(Out, iLen, In) != SAFECRT_SUCCESS)
+ {
+ ERROR("wcscpy_s failed!\n");
+ free(OutOriginal);
+ pthrCurrent->SetLastError(ERROR_INSUFFICIENT_BUFFER);
+ return -1;
+ }
+ Out += LengthInStr;
+ iLen -= LengthInStr;
+ }
+ if (Padding > 0)
+ {
+ iLen -= Padding;
+ if (Flags & PFF_ZERO) /* '0', pad with zeros */
+ {
+ while (Padding--)
+ {
+ *Out++ = '0';
+ }
+ }
+ else /* pad with spaces */
+ {
+ while (Padding--)
+ {
+ *Out++ = ' ';
+ }
+ }
+ }
+ if (!(Flags & PFF_MINUS)) /* put 'In' after padding */
+ {
+ if (wcscpy_s(Out, iLen, In) != SAFECRT_SUCCESS)
+ {
+ ERROR("wcscpy_s failed!\n");
+ free(OutOriginal);
+ pthrCurrent->SetLastError(ERROR_INSUFFICIENT_BUFFER);
+ return -1;
+ }
+
+ Out += LengthInStr;
+ iLen -= LengthInStr;
+ }
+
+ if (Length > 0) {
+ Written = Internal_Convertfwrite(pthrCurrent, OutOriginal, sizeof(wchar_16), Length,
+ (FILE*)(stream->bsdFilePtr), convert);
+
+ if (-1 == Written)
+ {
+ ERROR("fwrite() failed with errno == %d\n", errno);
+ }
+ free(OutOriginal);
+ }
+
+ return Written;
+}
+
+/*******************************************************************************
+Function:
+ PAL_vsnprintf
+
+Parameters:
+ Buffer
+ - out buffer
+ Count
+ - buffer size
+ Format
+ - format string
+ ap
+ - stdarg parameter list
+*******************************************************************************/
+
+int __cdecl PAL__vsnprintf(LPSTR Buffer, size_t Count, LPCSTR Format, va_list ap)
+{
+ LONG Length;
+
+ PERF_ENTRY(PAL__vsnprintf);
+ ENTRY("PAL__vsnprintf (buffer=%p, count=%d, format=%p (%s), argptr=%p)\n",
+ Buffer, Count, Format, Format, ap);
+
+ Length = CoreVsnprintf(InternalGetCurrentThread(), Buffer, Count, Format, ap);
+
+ LOGEXIT("PAL__vsnprintf returns int %d\n", Length);
+ PERF_EXIT(PAL__vsnprintf);
+
+ return Length;
+}
+
+/*******************************************************************************
+Function:
+ PAL_wvsnprintf
+
+ -- see PAL_vsnprintf above
+*******************************************************************************/
+
+int __cdecl PAL__wvsnprintf(LPWSTR Buffer, size_t Count, LPCWSTR Format, va_list ap)
+{
+ return CoreWvsnprintf(InternalGetCurrentThread(), Buffer, Count, Format, ap);
+}
+
+/*******************************************************************************
+Function:
+ PAL_vfprintf
+
+Parameters:
+ stream
+ - out stream
+ Format
+ - format string
+ ap
+ - stdarg parameter list
+*******************************************************************************/
+
+int __cdecl PAL_vfprintf(PAL_FILE *stream, const char *format, va_list ap)
+{
+ return CoreVfprintf(InternalGetCurrentThread(), stream, format, ap);
+}
+
+/*******************************************************************************
+Function:
+ PAL_vfwprintf
+
+Parameters:
+ stream
+ - out stream
+ Format
+ - format string
+ ap
+ - stdarg parameter list
+*******************************************************************************/
+
+int __cdecl PAL_vfwprintf(PAL_FILE *stream, const wchar_16 *format, va_list ap)
+{
+ return CoreVfwprintf(InternalGetCurrentThread(), stream, format, ap);
+}
+
+} // end extern "C"
+
+int CorUnix::InternalWvsnprintf(CPalThread *pthrCurrent, LPWSTR Buffer, size_t Count, LPCWSTR Format, va_list ap)
+{
+ return CoreWvsnprintf(pthrCurrent, Buffer, Count, Format, ap);
+}
+
+int CorUnix::InternalVsnprintf(CPalThread *pthrCurrent, LPSTR Buffer, size_t Count, LPCSTR Format, va_list ap)
+{
+ return CoreVsnprintf(pthrCurrent, Buffer, Count, Format, ap);
+}
+
+int CorUnix::InternalVfprintf(CPalThread *pthrCurrent, PAL_FILE *stream, const char *format, va_list ap)
+{
+ return CoreVfprintf(pthrCurrent, stream, format, ap);
+}
+
+int CorUnix::InternalVfwprintf(CPalThread *pthrCurrent, PAL_FILE *stream, const wchar_16 *format, va_list ap)
+{
+ return CoreVfwprintf(pthrCurrent, stream, format, ap);
+}
+
+int CoreVfwprintf(CPalThread *pthrCurrent, PAL_FILE *stream, const wchar_16 *format, va_list aparg)
+{
+ CHAR TempBuff[1024]; /* used to hold a single %<foo> format string */
+ LPCWSTR Fmt = format;
+ LPWSTR TempWStr = NULL;
+ LPWSTR WorkingWStr = NULL;
+ WCHAR TempWChar[2];
+ INT Flags;
+ INT Width;
+ INT Precision;
+ INT Prefix;
+ INT Type;
+ INT TempInt;
+ BOOL WStrWasMalloced = FALSE;
+ int mbtowcResult;
+ int written=0;
+ int paddingReturnValue;
+ int ret;
+ va_list ap;
+
+ /* fwprintf for now in the PAL is always used on file opened
+ in text mode. In those case the output should be ANSI not Unicode */
+ BOOL textMode = TRUE;
+
+ PERF_ENTRY(vfwprintf);
+ ENTRY("vfwprintf (stream=%p, format=%p (%S))\n",
+ stream, format, format);
+
+ va_copy(ap, aparg);
+
+ while (*Fmt)
+ {
+ if(*Fmt == '%' &&
+ TRUE == Internal_ExtractFormatW(pthrCurrent, &Fmt, TempBuff, &Flags,
+ &Width, &Precision,
+ &Prefix, &Type))
+ {
+ if (((Prefix == PFF_PREFIX_LONG || Prefix == PFF_PREFIX_LONG_W) &&
+ (Type == PFF_TYPE_STRING || Type == PFF_TYPE_WSTRING)) ||
+ (Type == PFF_TYPE_WSTRING && (Flags & PFF_ZERO) != 0))
+ {
+ WStrWasMalloced = FALSE;
+
+ if (WIDTH_STAR == Width)
+ {
+ Width = va_arg(ap, INT);
+ }
+ else if (WIDTH_INVALID == Width)
+ {
+ /* both a '*' and a number, ignore, but remove arg */
+ TempInt = va_arg(ap, INT); /* value not used */
+ }
+
+ if (PRECISION_STAR == Precision)
+ {
+ Precision = va_arg(ap, INT);
+ }
+ else if (PRECISION_INVALID == Precision)
+ {
+ /* both a '*' and a number, ignore, but remove arg */
+ TempInt = va_arg(ap, INT); /* value not used */
+ }
+
+ if (Type == PFF_TYPE_STRING || Prefix == PFF_PREFIX_LONG_W)
+ {
+ TempWStr = va_arg(ap, LPWSTR);
+ }
+ else
+ {
+ /* %lS assumes a LPSTR argument. */
+ LPSTR s = va_arg(ap, LPSTR );
+ UINT Length = 0;
+ Length = MultiByteToWideChar( CP_ACP, 0, s, -1, NULL, 0 );
+ if ( Length != 0 )
+ {
+ TempWStr =
+ (LPWSTR)InternalMalloc( (Length) * sizeof( WCHAR ) );
+ if ( TempWStr )
+ {
+ WStrWasMalloced = TRUE;
+ MultiByteToWideChar( CP_ACP, 0, s, -1,
+ TempWStr, Length );
+ }
+ else
+ {
+ ERROR( "InternalMalloc failed.\n" );
+ LOGEXIT("vfwprintf returns int -1\n");
+ PERF_EXIT(vfwprintf);
+ va_end(ap);
+ return -1;
+ }
+ }
+ else
+ {
+ ASSERT( "Unable to convert from multibyte "
+ " to wide char.\n" );
+ LOGEXIT("vfwprintf returns int -1\n");
+ PERF_EXIT(vfwprintf);
+ va_end(ap);
+ return -1;
+ }
+ }
+
+ INT Length = PAL_wcslen(TempWStr);
+ WorkingWStr = (LPWSTR) InternalMalloc((sizeof(WCHAR) * (Length + 1)));
+ if (!WorkingWStr)
+ {
+ ERROR("InternalMalloc failed\n");
+ LOGEXIT("vfwprintf returns int -1\n");
+ PERF_EXIT(vfwprintf);
+ pthrCurrent->SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ if (WStrWasMalloced)
+ {
+ free(TempWStr);
+ }
+ va_end(ap);
+ return -1;
+ }
+ if (PRECISION_DOT == Precision)
+ {
+ /* copy nothing */
+ *WorkingWStr = 0;
+ Length = 0;
+ }
+ else if (Precision > 0 && Precision < Length)
+ {
+ if (wcsncpy_s(WorkingWStr, (Length + 1), TempWStr, Precision+1) != SAFECRT_SUCCESS)
+ {
+ ERROR("Internal_AddPaddingVfwprintf failed\n");
+ if (WStrWasMalloced)
+ {
+ free(TempWStr);
+ }
+ free(WorkingWStr);
+ LOGEXIT("wcsncpy_s failed!\n");
+ PERF_EXIT(vfwprintf);
+ va_end(ap);
+ return (-1);
+ }
+
+ Length = Precision;
+ }
+ /* copy everything */
+ else
+ {
+ PAL_wcscpy(WorkingWStr, TempWStr);
+ }
+
+
+ /* do the padding (if needed)*/
+ paddingReturnValue =
+ Internal_AddPaddingVfwprintf( pthrCurrent, stream, WorkingWStr,
+ Width - Length,
+ Flags,textMode);
+
+ if (paddingReturnValue == -1)
+ {
+ ERROR("Internal_AddPaddingVfwprintf failed\n");
+ if (WStrWasMalloced)
+ {
+ free(TempWStr);
+ }
+ free(WorkingWStr);
+ LOGEXIT("vfwprintf returns int -1\n");
+ PERF_EXIT(vfwprintf);
+ va_end(ap);
+ return (-1);
+ }
+ written += paddingReturnValue;
+
+ free(WorkingWStr);
+ if (WStrWasMalloced)
+ {
+ free(TempWStr);
+ }
+ }
+ else if (Prefix == PFF_PREFIX_LONG && Type == PFF_TYPE_CHAR)
+ {
+ if (WIDTH_STAR == Width ||
+ WIDTH_INVALID == Width)
+ {
+ /* ignore (because it's a char), and remove arg */
+ TempInt = va_arg(ap, INT); /* value not used */
+ }
+
+ if (PRECISION_STAR == Precision ||
+ PRECISION_INVALID == Precision)
+ {
+ /* ignore (because it's a char), and remove arg */
+ TempInt = va_arg(ap, INT); /* value not used */
+ }
+
+ TempWChar[0] = va_arg(ap, int);
+ TempWChar[1] = 0;
+
+ /* do the padding (if needed)*/
+ paddingReturnValue =
+ Internal_AddPaddingVfwprintf(pthrCurrent, stream, TempWChar,
+ Width - 1,
+ Flags,textMode);
+ if (paddingReturnValue == -1)
+ {
+ ERROR("Internal_AddPaddingVfwprintf failed\n");
+ LOGEXIT("vfwprintf returns int -1\n");
+ PERF_EXIT(vfwprintf);
+ va_end(ap);
+ return(-1);
+ }
+ written += paddingReturnValue;
+ }
+ /* this places the number of bytes written to the buffer in the
+ next arg */
+ else if (Type == PFF_TYPE_N)
+ {
+ if (WIDTH_STAR == Width)
+ {
+ Width = va_arg(ap, INT);
+ }
+
+ if (PRECISION_STAR == Precision)
+ {
+ Precision = va_arg(ap, INT);
+ }
+
+ if (Prefix == PFF_PREFIX_SHORT)
+ {
+ *(va_arg(ap, short *)) = written;
+ }
+ else
+ {
+ *(va_arg(ap, LPLONG)) = written;
+ }
+ }
+ else
+ {
+ // Types that sprintf can handle.
+
+ /* note: I'm using the wide buffer as a (char *) buffer when I
+ pass it to sprintf(). After I get the buffer back I make a
+ backup of the chars copied and then convert them to wide
+ and place them in the buffer (BufferPtr) */
+
+ // This argument will be limited to 1024 characters.
+ // It should be enough.
+ size_t TEMP_COUNT = 1024;
+ char TempSprintfStrBuffer[1024];
+ char *TempSprintfStrPtr = NULL;
+ char *TempSprintfStr = TempSprintfStrBuffer;
+ LPWSTR TempWideBuffer;
+
+ TempInt = 0;
+ // %h (short) doesn't seem to be handled properly by local sprintf,
+ // so we do the truncation ourselves for some cases.
+ if (Type == PFF_TYPE_P && Prefix == PFF_PREFIX_SHORT)
+ {
+ // Convert from pointer -> int -> short to avoid warnings.
+ long trunc1;
+ short trunc2;
+
+ trunc1 = va_arg(ap, LONG);
+ trunc2 = (short)trunc1;
+ trunc1 = trunc2;
+
+ TempInt = snprintf(TempSprintfStr, TEMP_COUNT, TempBuff, trunc1);
+
+ if (TempInt < 0 || static_cast<size_t>(TempInt) >= TEMP_COUNT)
+ {
+ if (NULL == (TempSprintfStrPtr = (char*)InternalMalloc(++TempInt)))
+ {
+ ERROR("InternalMalloc failed\n");
+ LOGEXIT("vfwprintf returns int -1\n");
+ PERF_EXIT(vfwprintf);
+ pthrCurrent->SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ va_end(ap);
+ return -1;
+ }
+
+ TempSprintfStr = TempSprintfStrPtr;
+ snprintf(TempSprintfStr, TempInt, TempBuff, trunc2);
+ }
+ }
+ else if (Type == PFF_TYPE_INT && Prefix == PFF_PREFIX_SHORT)
+ {
+ // Convert explicitly from int to short to get
+ // correct sign extension for shorts on all systems.
+ int n;
+ short s;
+
+ n = va_arg(ap, int);
+ s = (short) n;
+
+ TempInt = snprintf(TempSprintfStr, TEMP_COUNT, TempBuff, s);
+
+ if (TempInt < 0 || static_cast<size_t>(TempInt) >= TEMP_COUNT)
+ {
+ if (NULL == (TempSprintfStrPtr = (char*)InternalMalloc(++TempInt)))
+ {
+ ERROR("InternalMalloc failed\n");
+ LOGEXIT("vfwprintf returns int -1\n");
+ PERF_EXIT(vfwprintf);
+ pthrCurrent->SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ va_end(ap);
+ return -1;
+ }
+
+ TempSprintfStr = TempSprintfStrPtr;
+ snprintf(TempSprintfStr, TempInt, TempBuff, s);
+ }
+ }
+ else
+ {
+ va_list apcopy;
+
+ va_copy(apcopy, ap);
+ TempInt = vsnprintf(TempSprintfStr, TEMP_COUNT, TempBuff, apcopy);
+ va_end(apcopy);
+ PAL_printf_arg_remover(&ap, Width, Precision, Type, Prefix);
+
+ if (TempInt < 0 || static_cast<size_t>(TempInt) >= TEMP_COUNT)
+ {
+ if (NULL == (TempSprintfStrPtr = (char*)InternalMalloc(++TempInt)))
+ {
+ ERROR("InternalMalloc failed\n");
+ LOGEXIT("vfwprintf returns int -1\n");
+ PERF_EXIT(vfwprintf);
+ pthrCurrent->SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ va_end(ap);
+ return -1;
+ }
+
+ TempSprintfStr = TempSprintfStrPtr;
+ va_copy(apcopy, ap);
+ vsnprintf(TempSprintfStr, TempInt, TempBuff, apcopy);
+ va_end(apcopy);
+ PAL_printf_arg_remover(&ap, Width, Precision, Type, Prefix);
+ }
+ }
+
+ mbtowcResult = MultiByteToWideChar(CP_ACP, 0,
+ TempSprintfStr, -1,
+ NULL, 0);
+
+ if (mbtowcResult == 0)
+ {
+ ERROR("MultiByteToWideChar failed\n");
+ if(TempSprintfStrPtr)
+ {
+ free(TempSprintfStrPtr);
+ }
+ LOGEXIT("vfwprintf returns int -1\n");
+ PERF_EXIT(vfwprintf);
+ va_end(ap);
+ return -1;
+ }
+
+ TempWideBuffer = (LPWSTR) InternalMalloc(mbtowcResult*sizeof(WCHAR));
+ if (!TempWideBuffer)
+ {
+ ERROR("InternalMalloc failed\n");
+ LOGEXIT("vfwprintf returns int -1\n");
+ PERF_EXIT(vfwprintf);
+ pthrCurrent->SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ if(TempSprintfStrPtr)
+ {
+ free(TempSprintfStrPtr);
+ }
+ va_end(ap);
+ return -1;
+ }
+
+ MultiByteToWideChar(CP_ACP, 0, TempSprintfStr, -1,
+ TempWideBuffer, mbtowcResult);
+
+ ret = Internal_Convertfwrite(
+ pthrCurrent,
+ TempWideBuffer,
+ sizeof(wchar_16),
+ mbtowcResult-1,
+ (FILE*)stream->bsdFilePtr,
+ textMode);
+
+ if (-1 == ret)
+ {
+ ERROR("fwrite() failed with errno == %d (%s)\n", errno, strerror(errno));
+ LOGEXIT("vfwprintf returns int -1\n");
+ PERF_EXIT(vfwprintf);
+ free(TempWideBuffer);
+ if(TempSprintfStrPtr)
+ {
+ free(TempSprintfStrPtr);
+ }
+ va_end(ap);
+ return -1;
+ }
+ if(TempSprintfStrPtr)
+ {
+ free(TempSprintfStrPtr);
+ }
+ free(TempWideBuffer);
+ }
+ }
+ else
+ {
+ ret = Internal_Convertfwrite(
+ pthrCurrent,
+ Fmt++,
+ sizeof(wchar_16),
+ 1,
+ (FILE*)stream->bsdFilePtr,
+ textMode); /* copy regular chars into buffer */
+
+ if (-1 == ret)
+ {
+ ERROR("fwrite() failed with errno == %d\n", errno);
+ LOGEXIT("vfwprintf returns int -1\n");
+ PERF_EXIT(vfwprintf);
+ va_end(ap);
+ return -1;
+ }
+ ++written;
+ }
+ }
+
+ LOGEXIT("vfwprintf returns int %d\n", written);
+ PERF_EXIT(vfwprintf);
+ va_end(ap);
+ return (written);
+}
+
+int CoreVsnprintf(CPalThread *pthrCurrent, LPSTR Buffer, size_t Count, LPCSTR Format, va_list aparg)
+{
+ BOOL BufferRanOut = FALSE;
+ CHAR TempBuff[1024]; /* used to hold a single %<foo> format string */
+ LPSTR BufferPtr = Buffer;
+ LPCSTR Fmt = Format;
+ LPWSTR TempWStr;
+ LPSTR TempStr;
+ WCHAR TempWChar;
+ INT Flags;
+ INT Width;
+ INT Precision;
+ INT Prefix;
+ INT Type;
+ INT Length;
+ INT TempInt;
+ int wctombResult;
+ va_list ap;
+
+ va_copy(ap, aparg);
+
+ while (*Fmt)
+ {
+ if (BufferRanOut || (BufferPtr - Buffer) >= static_cast<int>(Count)) //Count is assumed to be in the range of int
+ {
+ BufferRanOut = TRUE;
+ break;
+ }
+ else if(*Fmt == '%' &&
+ TRUE == Internal_ExtractFormatA(pthrCurrent, &Fmt, TempBuff, &Flags,
+ &Width, &Precision,
+ &Prefix, &Type))
+ {
+ if (Prefix == PFF_PREFIX_LONG && Type == PFF_TYPE_STRING)
+ {
+ if (WIDTH_STAR == Width)
+ {
+ Width = va_arg(ap, INT);
+ }
+ else if (WIDTH_INVALID == Width)
+ {
+ /* both a '*' and a number, ignore, but remove arg */
+ TempInt = va_arg(ap, INT); /* value not used */
+ }
+
+ if (PRECISION_STAR == Precision)
+ {
+ Precision = va_arg(ap, INT);
+ }
+ else if (PRECISION_INVALID == Precision)
+ {
+ /* both a '*' and a number, ignore, but remove arg */
+ TempInt = va_arg(ap, INT); /* value not used */
+ }
+
+ TempWStr = va_arg(ap, LPWSTR);
+ Length = WideCharToMultiByte(CP_ACP, 0, TempWStr, -1, 0,
+ 0, 0, 0);
+ if (!Length)
+ {
+ ASSERT("WideCharToMultiByte failed. Error is %d\n",
+ GetLastError());
+ va_end(ap);
+ return -1;
+ }
+ TempStr = (LPSTR) InternalMalloc(Length);
+ if (!TempStr)
+ {
+ ERROR("InternalMalloc failed\n");
+ pthrCurrent->SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ va_end(ap);
+ return -1;
+ }
+ if (PRECISION_DOT == Precision)
+ {
+ /* copy nothing */
+ *TempStr = 0;
+ Length = 0;
+ }
+ else if (Precision > 0 && Precision < Length - 1)
+ {
+ Length = WideCharToMultiByte(CP_ACP, 0, TempWStr,
+ Precision, TempStr, Length,
+ 0, 0);
+ if (!Length)
+ {
+ ASSERT("WideCharToMultiByte failed. Error is %d\n",
+ GetLastError());
+ free(TempStr);
+ va_end(ap);
+ return -1;
+ }
+ TempStr[Length] = 0;
+ Length = Precision;
+ }
+ /* copy everything */
+ else
+ {
+ wctombResult = WideCharToMultiByte(CP_ACP, 0, TempWStr, -1,
+ TempStr, Length, 0, 0);
+ if (!wctombResult)
+ {
+ ASSERT("WideCharToMultiByte failed. Error is %d\n",
+ GetLastError());
+ free(TempStr);
+ va_end(ap);
+ return -1;
+ }
+ --Length; /* exclude null char */
+ }
+
+ /* do the padding (if needed)*/
+ BufferRanOut = !Internal_AddPaddingA(&BufferPtr,
+ Count - (BufferPtr - Buffer),
+ TempStr,
+ Width - Length,
+ Flags);
+
+ free(TempStr);
+ }
+ else if (Prefix == PFF_PREFIX_LONG && Type == PFF_TYPE_CHAR)
+ {
+ CHAR TempBuffer[5];
+
+ if (WIDTH_STAR == Width ||
+ WIDTH_INVALID == Width)
+ {
+ /* ignore (because it's a char), and remove arg */
+ TempInt = va_arg(ap, INT); /* value not used */
+ }
+ if (PRECISION_STAR == Precision ||
+ PRECISION_INVALID == Precision)
+ {
+ /* ignore (because it's a char), and remove arg */
+ TempInt = va_arg(ap, INT); /* value not used */
+ }
+
+ TempWChar = va_arg(ap, int);
+ Length = WideCharToMultiByte(CP_ACP, 0, &TempWChar, 1,
+ TempBuffer, sizeof(TempBuffer),
+ 0, 0);
+ if (!Length)
+ {
+ ASSERT("WideCharToMultiByte failed. Error is %d\n",
+ GetLastError());
+ va_end(ap);
+ return -1;
+ }
+ TempBuffer[Length] = 0;
+
+ /* do the padding (if needed)*/
+ BufferRanOut = !Internal_AddPaddingA(&BufferPtr,
+ Count - (BufferPtr - Buffer),
+ TempBuffer,
+ Width - Length,
+ Flags);
+
+ }
+ /* this places the number of bytes written to the buffer in the
+ next arg */
+ else if (Type == PFF_TYPE_N)
+ {
+ if (WIDTH_STAR == Width)
+ {
+ Width = va_arg(ap, INT);
+ }
+ if (PRECISION_STAR == Precision)
+ {
+ Precision = va_arg(ap, INT);
+ }
+
+ if (Prefix == PFF_PREFIX_SHORT)
+ {
+ *(va_arg(ap, short *)) = BufferPtr - Buffer;
+ }
+ else
+ {
+ *(va_arg(ap, LPLONG)) = BufferPtr - Buffer;
+ }
+ }
+ else if (Type == PFF_TYPE_CHAR && (Flags & PFF_ZERO) != 0)
+ {
+ // Some versions of sprintf don't support 0-padded chars,
+ // so we handle them here.
+ char ch[2];
+
+ ch[0] = (char) va_arg(ap, int);
+ ch[1] = '\0';
+ Length = 1;
+ BufferRanOut = !Internal_AddPaddingA(&BufferPtr,
+ Count - (BufferPtr - Buffer),
+ ch,
+ Width - Length,
+ Flags);
+ }
+ else if (Type == PFF_TYPE_STRING && (Flags & PFF_ZERO) != 0)
+ {
+ // Some versions of sprintf don't support 0-padded strings,
+ // so we handle them here.
+ char *tempStr;
+
+ tempStr = va_arg(ap, char *);
+ Length = strlen(tempStr);
+ BufferRanOut = !Internal_AddPaddingA(&BufferPtr,
+ Count - (BufferPtr - Buffer),
+ tempStr,
+ Width - Length,
+ Flags);
+ }
+ else
+ {
+ // Types that sprintf can handle
+ size_t TempCount = Count - (BufferPtr - Buffer);
+
+#if !HAVE_LARGE_SNPRINTF_SUPPORT
+ // Limit TempCount to 0x40000000, which is sufficient
+ // for platforms on which snprintf fails for very large
+ // sizes.
+ if (TempCount > 0x40000000)
+ {
+ TempCount = 0x40000000;
+ }
+#endif // HAVE_LARGE_SNPRINTF_SUPPORT
+
+ TempInt = 0;
+ // %h (short) doesn't seem to be handled properly by local sprintf,
+ // so we do the truncation ourselves for some cases.
+ if (Type == PFF_TYPE_P && Prefix == PFF_PREFIX_SHORT)
+ {
+ // Convert from pointer -> int -> short to avoid warnings.
+ long trunc1;
+ short trunc2;
+
+ trunc1 = va_arg(ap, LONG);
+ trunc2 = (short) trunc1;
+ trunc1 = trunc2;
+
+ TempInt = snprintf(BufferPtr, TempCount, TempBuff, trunc1);
+ }
+ else if (Type == PFF_TYPE_INT && Prefix == PFF_PREFIX_SHORT)
+ {
+ // Convert explicitly from int to short to get
+ // correct sign extension for shorts on all systems.
+ int n;
+ short s;
+
+ n = va_arg(ap, int);
+ s = (short) n;
+
+ TempInt = snprintf(BufferPtr, TempCount, TempBuff, s);
+ }
+ else
+ {
+ va_list apcopy;
+ va_copy(apcopy, ap);
+ TempInt = vsnprintf(BufferPtr, TempCount, TempBuff, apcopy);
+ va_end(apcopy);
+ PAL_printf_arg_remover(&ap, Width, Precision, Type, Prefix);
+ }
+
+ if (TempInt < 0 || static_cast<size_t>(TempInt) >= TempCount) /* buffer not long enough */
+ {
+ BufferPtr += TempCount;
+ BufferRanOut = TRUE;
+ }
+ else
+ {
+ BufferPtr += TempInt;
+ }
+ }
+ }
+ else
+ {
+ *BufferPtr++ = *Fmt++; /* copy regular chars into buffer */
+ }
+ }
+
+ if (static_cast<int>(Count) > (BufferPtr - Buffer)) //Count is assumed to be in the range of int
+ {
+ *BufferPtr = 0; /* end the string */
+ }
+
+ va_end(ap);
+
+ if (BufferRanOut)
+ {
+ errno = ERANGE;
+ return -1;
+ }
+ else
+ {
+ return BufferPtr - Buffer;
+ }
+}
+
+int CoreWvsnprintf(CPalThread *pthrCurrent, LPWSTR Buffer, size_t Count, LPCWSTR Format, va_list aparg)
+{
+ BOOL BufferRanOut = FALSE;
+ CHAR TempBuff[1024]; /* used to hold a single %<foo> format string */
+ LPWSTR BufferPtr = Buffer;
+ LPCWSTR Fmt = Format;
+ LPWSTR TempWStr = NULL;
+ LPWSTR WorkingWStr = NULL;
+ WCHAR TempWChar[2];
+ INT Flags;
+ INT Width;
+ INT Precision;
+ INT Prefix;
+ INT Type;
+ INT TempInt;
+ LPSTR TempNumberBuffer;
+ int mbtowcResult;
+ va_list(ap);
+
+ PERF_ENTRY(wvsnprintf);
+ ENTRY("wvsnprintf (buffer=%p, count=%u, format=%p (%S))\n",
+ Buffer, Count, Format, Format);
+
+ va_copy(ap, aparg);
+
+ while (*Fmt)
+ {
+ if (BufferRanOut || (BufferPtr - Buffer) >= static_cast<int>(Count)) //Count is assumed to be in the range of int
+ {
+ BufferRanOut = TRUE;
+ break;
+ }
+ else if(*Fmt == '%' &&
+ TRUE == Internal_ExtractFormatW(pthrCurrent, &Fmt, TempBuff, &Flags,
+ &Width, &Precision,
+ &Prefix, &Type))
+ {
+ if (((Prefix == PFF_PREFIX_LONG || Prefix == PFF_PREFIX_LONG_W) &&
+ (Type == PFF_TYPE_STRING || Type == PFF_TYPE_WSTRING)) ||
+ (Prefix == PFF_PREFIX_SHORT && Type == PFF_TYPE_STRING) ||
+ (Type == PFF_TYPE_WSTRING && (Flags & PFF_ZERO) != 0))
+ {
+ BOOL needToFree = FALSE;
+
+ if (WIDTH_STAR == Width)
+ {
+ Width = va_arg(ap, INT);
+ }
+ else if (WIDTH_INVALID == Width)
+ {
+ /* both a '*' and a number, ignore, but remove arg */
+ TempInt = va_arg(ap, INT); /* value not used */
+ }
+
+ if (PRECISION_STAR == Precision)
+ {
+ Precision = va_arg(ap, INT);
+ }
+ else if (PRECISION_INVALID == Precision)
+ {
+ /* both a '*' and a number, ignore, but remove arg */
+ TempInt = va_arg(ap, INT); /* value not used */
+ }
+
+ if ((Type == PFF_TYPE_STRING && Prefix == PFF_PREFIX_LONG) ||
+ Prefix == PFF_PREFIX_LONG_W)
+ {
+ TempWStr = va_arg(ap, LPWSTR);
+ }
+ else
+ {
+ // %lS and %hs assume an LPSTR argument.
+ LPSTR s = va_arg(ap, LPSTR );
+ UINT Length = 0;
+ Length = MultiByteToWideChar( CP_ACP, 0, s, -1, NULL, 0 );
+ if ( Length != 0 )
+ {
+ TempWStr =
+ (LPWSTR)InternalMalloc((Length + 1 ) * sizeof( WCHAR ) );
+ if ( TempWStr )
+ {
+ needToFree = TRUE;
+ MultiByteToWideChar( CP_ACP, 0, s, -1,
+ TempWStr, Length );
+ }
+ else
+ {
+ ERROR( "InternalMalloc failed.\n" );
+ va_end(ap);
+ return -1;
+ }
+ }
+ else
+ {
+ ASSERT( "Unable to convert from multibyte "
+ " to wide char.\n" );
+ va_end(ap);
+ return -1;
+ }
+
+ }
+
+ INT Length = PAL_wcslen(TempWStr);
+ WorkingWStr = (LPWSTR) InternalMalloc(sizeof(WCHAR) * (Length + 1));
+ if (!WorkingWStr)
+ {
+ ERROR("InternalMalloc failed\n");
+ pthrCurrent->SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ if (needToFree)
+ {
+ free(TempWStr);
+ }
+ va_end(ap);
+ return -1;
+ }
+ if (PRECISION_DOT == Precision)
+ {
+ // Copy nothing
+ *WorkingWStr = 0;
+ Length = 0;
+ }
+ else if (Precision > 0 && Precision < Length)
+ {
+ if (wcsncpy_s(WorkingWStr, (Length + 1), TempWStr, Precision+1) != SAFECRT_SUCCESS)
+ {
+ ERROR("CoreWvsnprintf failed\n");
+ if (needToFree)
+ {
+ free(TempWStr);
+ }
+ free(WorkingWStr);
+ LOGEXIT("wcsncpy_s failed!\n");
+ PERF_EXIT(wvsnprintf);
+ va_end(ap);
+ return (-1);
+ }
+
+ Length = Precision;
+ }
+ else
+ {
+ // Copy everything
+ PAL_wcscpy(WorkingWStr, TempWStr);
+ }
+
+ // Add padding if needed.
+ BufferRanOut = !Internal_AddPaddingW(&BufferPtr,
+ Count - (BufferPtr - Buffer),
+ WorkingWStr,
+ Width - Length,
+ Flags);
+
+ if (needToFree)
+ {
+ free(TempWStr);
+ }
+ free(WorkingWStr);
+ }
+ else if (Prefix == PFF_PREFIX_LONG && Type == PFF_TYPE_CHAR)
+ {
+ if (WIDTH_STAR == Width ||
+ WIDTH_INVALID == Width)
+ {
+ /* ignore (because it's a char), and remove arg */
+ TempInt = va_arg(ap, INT); /* value not used */
+ }
+
+ if (PRECISION_STAR == Precision ||
+ PRECISION_INVALID == Precision)
+ {
+ /* ignore (because it's a char), and remove arg */
+ TempInt = va_arg(ap, INT); /* value not used */
+ }
+
+ TempWChar[0] = va_arg(ap, int);
+ TempWChar[1] = 0;
+
+ /* do the padding (if needed)*/
+ BufferRanOut = !Internal_AddPaddingW(&BufferPtr,
+ Count - (BufferPtr - Buffer),
+ TempWChar,
+ Width - 1,
+ Flags);
+
+ }
+ /* this places the number of bytes written to the buffer in the
+ next arg */
+ else if (Type == PFF_TYPE_N)
+ {
+ if (WIDTH_STAR == Width)
+ {
+ Width = va_arg(ap, INT);
+ }
+ if (PRECISION_STAR == Precision)
+ {
+ Precision = va_arg(ap, INT);
+ }
+
+ if (Prefix == PFF_PREFIX_SHORT)
+ {
+ *(va_arg(ap, short *)) = BufferPtr - Buffer;
+ }
+ else
+ {
+ *(va_arg(ap, LPLONG)) = BufferPtr - Buffer;
+ }
+ }
+ else
+ {
+ // Types that sprintf can handle
+
+ /* note: I'm using the wide buffer as a (char *) buffer when I
+ pass it to sprintf(). After I get the buffer back I make a
+ backup of the chars copied and then convert them to wide
+ and place them in the buffer (BufferPtr) */
+ size_t TempCount = Count - (BufferPtr - Buffer);
+ TempInt = 0;
+
+#if !HAVE_LARGE_SNPRINTF_SUPPORT
+ // Limit TempCount to 0x40000000, which is sufficient
+ // for platforms on which snprintf fails for very large
+ // sizes.
+ if (TempCount > 0x40000000)
+ {
+ TempCount = 0x40000000;
+ }
+#endif // HAVE_LARGE_SNPRINTF_SUPPORT
+
+ // %h (short) doesn't seem to be handled properly by local sprintf,
+ // so we do the truncation ourselves for some cases.
+ if (Type == PFF_TYPE_P && Prefix == PFF_PREFIX_SHORT)
+ {
+ // Convert from pointer -> int -> short to avoid warnings.
+ long trunc1;
+ short trunc2;
+
+ trunc1 = va_arg(ap, LONG);
+ trunc2 = (short)trunc1;
+ trunc1 = trunc2;
+
+ TempInt = snprintf((LPSTR)BufferPtr, TempCount, TempBuff, trunc1);
+ }
+ else if (Type == PFF_TYPE_INT && Prefix == PFF_PREFIX_SHORT)
+ {
+ // Convert explicitly from int to short to get
+ // correct sign extension for shorts on all systems.
+ int n;
+ short s;
+
+ n = va_arg(ap, int);
+ s = (short) n;
+
+ TempInt = snprintf((LPSTR)BufferPtr, TempCount, TempBuff, s);
+ }
+ else
+ {
+ va_list apcopy;
+ va_copy(apcopy, ap);
+ TempInt = vsnprintf((LPSTR) BufferPtr, TempCount, TempBuff, apcopy);
+ va_end(apcopy);
+ PAL_printf_arg_remover(&ap, Width, Precision, Type, Prefix);
+ }
+
+ if (TempInt == 0)
+ {
+ // The argument is "".
+ continue;
+ }
+ if (TempInt < 0 || static_cast<size_t>(TempInt) >= TempCount) /* buffer not long enough */
+ {
+ TempNumberBuffer = (LPSTR) InternalMalloc(TempCount+1);
+ if (!TempNumberBuffer)
+ {
+ ERROR("InternalMalloc failed\n");
+ pthrCurrent->SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ errno = ENOMEM;
+ va_end(ap);
+ return -1;
+ }
+
+ if (strncpy_s(TempNumberBuffer, TempCount+1, (LPSTR) BufferPtr, TempCount) != SAFECRT_SUCCESS)
+ {
+ ASSERT("strncpy_s failed!\n");
+ free(TempNumberBuffer);
+ va_end(ap);
+ return -1;
+ }
+
+ mbtowcResult = MultiByteToWideChar(CP_ACP, 0,
+ TempNumberBuffer,
+ TempCount,
+ BufferPtr, TempCount);
+ if (!mbtowcResult)
+ {
+ ASSERT("MultiByteToWideChar failed. Error is %d\n",
+ GetLastError());
+ free(TempNumberBuffer);
+ va_end(ap);
+ return -1;
+ }
+ BufferPtr += TempCount;
+ BufferRanOut = TRUE;
+ }
+ else
+ {
+ TempNumberBuffer = (LPSTR) InternalMalloc(TempInt+1);
+ if (!TempNumberBuffer)
+ {
+ ERROR("InternalMalloc failed\n");
+ pthrCurrent->SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ va_end(ap);
+ return -1;
+ }
+
+ if (strncpy_s(TempNumberBuffer, TempInt+1, (LPSTR) BufferPtr, TempInt) != SAFECRT_SUCCESS)
+ {
+ ASSERT("strncpy_s failed!\n");
+ free(TempNumberBuffer);
+ va_end(ap);
+ return -1;
+ }
+
+ mbtowcResult = MultiByteToWideChar(CP_ACP, 0,
+ TempNumberBuffer,
+ TempInt,
+ BufferPtr, TempInt);
+ if (!mbtowcResult)
+ {
+ ASSERT("MultiByteToWideChar failed. Error is %d\n",
+ GetLastError());
+ free(TempNumberBuffer);
+ va_end(ap);
+ return -1;
+ }
+ BufferPtr += TempInt;
+ }
+ free(TempNumberBuffer);
+ }
+ }
+ else
+ {
+ *BufferPtr++ = *Fmt++; /* copy regular chars into buffer */
+ }
+ }
+
+ if (static_cast<int>(Count) > (BufferPtr - Buffer)) //Count is assumed to be in the range of int
+ {
+ *BufferPtr = 0; /* end the string */
+ }
+
+ va_end(ap);
+
+ if (BufferRanOut)
+ {
+ errno = ERANGE;
+ return -1;
+ }
+ else
+ {
+ return BufferPtr - Buffer;
+ }
+}
+
+int CoreVfprintf(CPalThread *pthrCurrent, PAL_FILE *stream, const char *format, va_list aparg)
+{
+ CHAR TempBuff[1024]; /* used to hold a single %<foo> format string */
+ LPCSTR Fmt = format;
+ LPWSTR TempWStr;
+ LPSTR TempStr;
+ WCHAR TempWChar;
+ INT Flags;
+ INT Width;
+ INT Precision;
+ INT Prefix;
+ INT Type;
+ INT Length;
+ INT TempInt;
+ int wctombResult;
+ int written = 0;
+ int paddingReturnValue;
+ va_list ap;
+
+ PERF_ENTRY(vfprintf);
+
+ va_copy(ap, aparg);
+
+ while (*Fmt)
+ {
+ if (*Fmt == '%' &&
+ TRUE == Internal_ExtractFormatA(pthrCurrent, &Fmt, TempBuff, &Flags,
+ &Width, &Precision,
+ &Prefix, &Type))
+ {
+ if (Prefix == PFF_PREFIX_LONG && Type == PFF_TYPE_STRING)
+ {
+ if (WIDTH_STAR == Width)
+ {
+ Width = va_arg(ap, INT);
+ }
+ else if (WIDTH_INVALID == Width)
+ {
+ /* both a '*' and a number, ignore, but remove arg */
+ TempInt = va_arg(ap, INT); /* value not used */
+ }
+
+ if (PRECISION_STAR == Precision)
+ {
+ Precision = va_arg(ap, INT);
+ }
+ else if (PRECISION_INVALID == Precision)
+ {
+ /* both a '*' and a number, ignore, but remove arg */
+ TempInt = va_arg(ap, INT); /* value not used */
+ }
+
+ TempWStr = va_arg(ap, LPWSTR);
+ Length = WideCharToMultiByte(CP_ACP, 0, TempWStr, -1, 0,
+ 0, 0, 0);
+ if (!Length)
+ {
+ ASSERT("WideCharToMultiByte failed. Error is %d\n",
+ GetLastError());
+ PERF_EXIT(vfprintf);
+ va_end(ap);
+ return -1;
+ }
+ TempStr = (LPSTR) InternalMalloc(Length);
+ if (!TempStr)
+ {
+ ERROR("InternalMalloc failed\n");
+ pthrCurrent->SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ PERF_EXIT(vfprintf);
+ va_end(ap);
+ return -1;
+ }
+ if (PRECISION_DOT == Precision)
+ {
+ /* copy nothing */
+ *TempStr = 0;
+ Length = 0;
+ }
+ else if (Precision > 0 && Precision < Length - 1)
+ {
+ Length = WideCharToMultiByte(CP_ACP, 0, TempWStr,
+ Precision, TempStr, Length,
+ 0, 0);
+ if (!Length)
+ {
+ ASSERT("WideCharToMultiByte failed. Error is %d\n",
+ GetLastError());
+ free(TempStr);
+ PERF_EXIT(vfprintf);
+ va_end(ap);
+ return -1;
+ }
+ TempStr[Length] = 0;
+ Length = Precision;
+ }
+ /* copy everything */
+ else
+ {
+ wctombResult = WideCharToMultiByte(CP_ACP, 0, TempWStr, -1,
+ TempStr, Length, 0, 0);
+ if (!wctombResult)
+ {
+ ASSERT("WideCharToMultiByte failed. Error is %d\n",
+ GetLastError());
+ free(TempStr);
+ PERF_EXIT(vfprintf);
+ va_end(ap);
+ return -1;
+ }
+ --Length; /* exclude null char */
+ }
+
+ /* do the padding (if needed)*/
+ paddingReturnValue =
+ Internal_AddPaddingVfprintf(pthrCurrent, stream, TempStr,
+ Width - Length, Flags);
+ if (-1 == paddingReturnValue)
+ {
+ ERROR("Internal_AddPaddingVfprintf failed\n");
+ free(TempStr);
+ PERF_EXIT(vfprintf);
+ va_end(ap);
+ return -1;
+ }
+ written += paddingReturnValue;
+
+ free(TempStr);
+ }
+ else if (Prefix == PFF_PREFIX_LONG && Type == PFF_TYPE_CHAR)
+ {
+ CHAR TempBuffer[5];
+ if (WIDTH_STAR == Width ||
+ WIDTH_INVALID == Width)
+ {
+ /* ignore (because it's a char), and remove arg */
+ TempInt = va_arg(ap, INT); /* value not used */
+ }
+ if (PRECISION_STAR == Precision ||
+ PRECISION_INVALID == Precision)
+ {
+ /* ignore (because it's a char), and remove arg */
+ TempInt = va_arg(ap, INT); /* value not used */
+ }
+
+ TempWChar = va_arg(ap, int);
+ Length = WideCharToMultiByte(CP_ACP, 0, &TempWChar, 1,
+ TempBuffer, sizeof(TempBuffer),
+ 0, 0);
+ if (!Length)
+ {
+ ASSERT("WideCharToMultiByte failed. Error is %d\n",
+ GetLastError());
+ PERF_EXIT(vfprintf);
+ va_end(ap);
+ return -1;
+ }
+ TempBuffer[Length] = 0;
+
+ /* do the padding (if needed)*/
+ paddingReturnValue =
+ Internal_AddPaddingVfprintf(pthrCurrent, stream, TempBuffer,
+ Width - Length, Flags);
+ if (-1 == paddingReturnValue)
+ {
+ ERROR("Internal_AddPaddingVfprintf failed\n");
+ PERF_EXIT(vfprintf);
+ va_end(ap);
+ return -1;
+ }
+ written += paddingReturnValue;
+
+ }
+ /* this places the number of bytes written to the buffer in the
+ next arg */
+ else if (Type == PFF_TYPE_N)
+ {
+ if (WIDTH_STAR == Width)
+ {
+ Width = va_arg(ap, INT);
+ }
+ if (PRECISION_STAR == Precision)
+ {
+ Precision = va_arg(ap, INT);
+ }
+
+ if (Prefix == PFF_PREFIX_SHORT)
+ {
+ *(va_arg(ap, short *)) = written;
+ }
+ else
+ {
+ *(va_arg(ap, LPLONG)) = written;
+ }
+ }
+ else if (Type == PFF_TYPE_CHAR && (Flags & PFF_ZERO) != 0)
+ {
+ // Some versions of fprintf don't support 0-padded chars,
+ // so we handle them here.
+ char ch[2];
+
+ ch[0] = (char) va_arg(ap, int);
+ ch[1] = '\0';
+ Length = 1;
+ paddingReturnValue = Internal_AddPaddingVfprintf(
+ pthrCurrent,
+ stream,
+ ch,
+ Width - Length,
+ Flags);
+ if (-1 == paddingReturnValue)
+ {
+ ERROR("Internal_AddPaddingVfprintf failed\n");
+ PERF_EXIT(vfprintf);
+ va_end(ap);
+ return -1;
+ }
+ written += paddingReturnValue;
+ }
+ else if (Type == PFF_TYPE_STRING && (Flags & PFF_ZERO) != 0)
+ {
+ // Some versions of fprintf don't support 0-padded strings,
+ // so we handle them here.
+ char *tempStr;
+
+ tempStr = va_arg(ap, char *);
+ Length = strlen(tempStr);
+ paddingReturnValue = Internal_AddPaddingVfprintf(
+ pthrCurrent,
+ stream,
+ tempStr,
+ Width - Length,
+ Flags);
+ if (-1 == paddingReturnValue)
+ {
+ ERROR("Internal_AddPaddingVfprintf failed\n");
+ PERF_EXIT(vfprintf);
+ va_end(ap);
+ return -1;
+ }
+ written += paddingReturnValue;
+ }
+ else
+ {
+ // Types that fprintf can handle.
+ TempInt = 0;
+
+ // %h (short) doesn't seem to be handled properly by local sprintf,
+ // so we do the truncation ourselves for some cases.
+ if (Type == PFF_TYPE_P && Prefix == PFF_PREFIX_SHORT)
+ {
+ // Convert from pointer -> int -> short to avoid warnings.
+ long trunc1;
+ short trunc2;
+
+ trunc1 = va_arg(ap, LONG);
+ trunc2 = (short)trunc1;
+ trunc1 = trunc2;
+
+ TempInt = fprintf(stream->bsdFilePtr, TempBuff, trunc1);
+ }
+ else if (Type == PFF_TYPE_INT && Prefix == PFF_PREFIX_SHORT)
+ {
+ // Convert explicitly from int to short to get
+ // correct sign extension for shorts on all systems.
+ int n;
+ short s;
+
+ n = va_arg(ap, int);
+ s = (short) n;
+
+ TempInt = fprintf( stream->bsdFilePtr, TempBuff, s);
+ }
+ else
+ {
+ va_list apcopy;
+ va_copy(apcopy, ap);
+ TempInt = vfprintf(stream->bsdFilePtr, TempBuff, apcopy);
+ va_end(apcopy);
+ PAL_printf_arg_remover(&ap, Width, Precision, Type, Prefix);
+ }
+
+ if (-1 == TempInt)
+ {
+ ERROR("vfprintf returned an error\n");
+ }
+ else
+ {
+ written += TempInt;
+ }
+ }
+ }
+ else
+ {
+
+#if FILE_OPS_CHECK_FERROR_OF_PREVIOUS_CALL
+ clearerr (stream->bsdFilePtr);
+#endif
+
+ InternalFwrite(Fmt++, 1, 1, stream->bsdFilePtr, &stream->PALferrorCode); /* copy regular chars into buffer */
+ if (stream->PALferrorCode == PAL_FILE_ERROR)
+ {
+ ERROR("fwrite() failed with errno == %d\n", errno);
+ PERF_EXIT(vfprintf);
+ va_end(ap);
+ return -1;
+ }
+ ++written;
+ }
+ }
+
+ va_end(ap);
+
+ PERF_EXIT(vfprintf);
+ return written;
+}
diff --git a/src/pal/src/cruntime/silent_printf.cpp b/src/pal/src/cruntime/silent_printf.cpp
new file mode 100644
index 0000000000..1d10963973
--- /dev/null
+++ b/src/pal/src/cruntime/silent_printf.cpp
@@ -0,0 +1,990 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ silent_printf.c
+
+Abstract:
+
+ Implementation of a silent version of PAL_vsprintf and PAL_vfprintf function.
+ (without any reference to TRACE/ERROR/... macros, needed by the tracing macros)
+
+Revision History:
+
+
+
+--*/
+
+
+#include "pal/palinternal.h"
+#include "pal/cruntime.h"
+#include "pal/locale.h"
+#include "pal/printfcpp.hpp"
+#include "pal/thread.hpp"
+
+/* clip strings (%s, %S) at this number of characters */
+#define MAX_STR_LEN 300
+
+static int Silent_WideCharToMultiByte(LPCWSTR lpWideCharStr, int cchWideChar,
+ LPSTR lpMultiByteStr, int cbMultiByte);
+static BOOL Silent_ExtractFormatA(LPCSTR *Fmt, LPSTR Out, LPINT Flags, LPINT Width,
+ LPINT Precision, LPINT Prefix, LPINT Type);
+static INT Silent_AddPaddingVfprintf(PAL_FILE *stream, LPSTR In, INT Padding,
+ INT Flags);
+
+static size_t Silent_PAL_wcslen(const wchar_16 *string);
+
+/*******************************************************************************
+Function:
+ PAL_vsnprintf (silent version)
+ for more details, see PAL_vsnprintf in printf.c
+*******************************************************************************/
+INT Silent_PAL_vsnprintf(LPSTR Buffer, INT Count, LPCSTR Format, va_list aparg)
+{
+ BOOL BufferRanOut = FALSE;
+ CHAR TempBuff[1024]; /* used to hold a single %<foo> format string */
+ LPSTR BufferPtr = Buffer;
+ LPCSTR Fmt = Format;
+ LPWSTR TempWStr;
+ CHAR TempStr[MAX_STR_LEN+1];
+ WCHAR TempWChar;
+ INT Flags;
+ INT Width;
+ INT Precision;
+ INT Prefix;
+ INT Type;
+ INT Length;
+ INT TempInt;
+ int wctombResult;
+ va_list ap;
+
+ va_copy(ap, aparg);
+
+ while (*Fmt)
+ {
+ if ((BufferPtr - Buffer) >= Count)
+ {
+ BufferRanOut = TRUE;
+ break;
+ }
+ else if(*Fmt == '%' &&
+ TRUE == Silent_ExtractFormatA(&Fmt, TempBuff, &Flags,
+ &Width, &Precision,
+ &Prefix, &Type))
+ {
+ if (Prefix == PFF_PREFIX_LONG && Type == PFF_TYPE_STRING)
+ {
+ if (WIDTH_STAR == Width)
+ {
+ Width = va_arg(ap, INT);
+ }
+ else if (WIDTH_INVALID == Width)
+ {
+ /* both a '*' and a number, ignore, but remove arg */
+ TempInt = va_arg(ap, INT); /* value not used */
+ }
+
+ if (PRECISION_STAR == Precision)
+ {
+ Precision = va_arg(ap, INT);
+ }
+ else if (PRECISION_INVALID == Precision)
+ {
+ /* both a '*' and a number, ignore, but remove arg */
+ TempInt = va_arg(ap, INT); /* value not used */
+ }
+
+ TempWStr = va_arg(ap, LPWSTR);
+ Length = Silent_WideCharToMultiByte(TempWStr, -1, 0, 0);
+ if (!Length)
+ {
+ va_end(ap);
+ return -1;
+ }
+
+ /* clip string output to MAX_STR_LEN characters */
+ if (PRECISION_DOT == Precision)
+ {
+ Precision = MAX_STR_LEN;
+ }
+
+ if (PRECISION_DOT == Precision)
+ {
+ /* copy nothing */
+ *TempStr = 0;
+ Length = 0;
+ }
+ else if (Precision > 0 && Precision < Length - 1)
+ {
+ Length = Silent_WideCharToMultiByte(TempWStr, Precision,
+ TempStr, Length);
+ if (!Length)
+ {
+ va_end(ap);
+ return -1;
+ }
+ TempStr[Length] = 0;
+ Length = Precision;
+ }
+ /* copy everything */
+ else
+ {
+ wctombResult = Silent_WideCharToMultiByte(TempWStr, -1,
+ TempStr, Length);
+ if (!wctombResult)
+ {
+ PAL_free(TempStr);
+ va_end(ap);
+ return -1;
+ }
+ --Length; /* exclude null char */
+ }
+
+ /* do the padding (if needed)*/
+ BufferRanOut = !Internal_AddPaddingA(&BufferPtr,
+ Count - (BufferPtr - Buffer),
+ TempStr,
+ Width - Length,
+ Flags);
+ }
+ else if (Prefix == PFF_PREFIX_LONG && Type == PFF_TYPE_CHAR)
+ {
+ CHAR TempBuffer[4];
+
+ if (WIDTH_STAR == Width ||
+ WIDTH_INVALID == Width)
+ {
+ /* ignore (because it's a char), and remove arg */
+ TempInt = va_arg(ap, INT); /* value not used */
+ }
+ if (PRECISION_STAR == Precision ||
+ PRECISION_INVALID == Precision)
+ {
+ /* ignore (because it's a char), and remove arg */
+ TempInt = va_arg(ap, INT); /* value not used */
+ }
+
+ TempWChar = va_arg(ap, int);
+ Length = Silent_WideCharToMultiByte(&TempWChar, 1, TempBuffer, 4);
+ if (!Length)
+ {
+ va_end(ap);
+ return -1;
+ }
+ TempBuffer[Length] = 0;
+
+ /* do the padding (if needed)*/
+ BufferRanOut = !Internal_AddPaddingA(&BufferPtr,
+ Count - (BufferPtr - Buffer),
+ TempBuffer,
+ Width - Length,
+ Flags);
+
+ }
+ /* this places the number of bytes written to the buffer in the
+ next arg */
+ else if (Type == PFF_TYPE_N)
+ {
+ if (WIDTH_STAR == Width)
+ {
+ Width = va_arg(ap, INT);
+ }
+ if (PRECISION_STAR == Precision)
+ {
+ Precision = va_arg(ap, INT);
+ }
+ if (Prefix == PFF_PREFIX_SHORT)
+ {
+ *(va_arg(ap, short *)) = BufferPtr - Buffer;
+ }
+ else
+ {
+ *(va_arg(ap, LPLONG)) = BufferPtr - Buffer;
+ }
+ }
+ else if (Type == PFF_TYPE_CHAR && (Flags & PFF_ZERO) != 0)
+ {
+ // Some versions of sprintf don't support 0-padded chars,
+ // so we handle them here.
+ char ch[2];
+
+ ch[0] = (char) va_arg(ap, int);
+ ch[1] = '\0';
+ Length = 1;
+ BufferRanOut = !Internal_AddPaddingA(&BufferPtr,
+ Count - (BufferPtr - Buffer),
+ ch,
+ Width - Length,
+ Flags);
+ }
+ else if (Type == PFF_TYPE_STRING && (Flags & PFF_ZERO) != 0)
+ {
+ // Some versions of sprintf don't support 0-padded strings,
+ // so we handle them here.
+ char *tempStr;
+
+ tempStr = va_arg(ap, char *);
+ Length = strlen(tempStr);
+ BufferRanOut = !Internal_AddPaddingA(&BufferPtr,
+ Count - (BufferPtr - Buffer),
+ tempStr,
+ Width - Length,
+ Flags);
+ }
+ /* types that sprintf can handle */
+ else
+ {
+ size_t TempCount = Count - (BufferPtr - Buffer);
+
+ TempInt = 0;
+ /* %h (short) doesn't seem to be handled properly by local sprintf,
+ so lets do the truncation ourselves. (ptr -> int -> short to avoid
+ warnings */
+ if (Type == PFF_TYPE_P && Prefix == PFF_PREFIX_SHORT)
+ {
+ long trunc1;
+ short trunc2;
+
+ trunc1 = va_arg(ap, LONG);
+ trunc2 = (short)trunc1;
+
+ TempInt = snprintf(BufferPtr, TempCount, TempBuff, trunc2);
+ }
+ else if (Type == PFF_TYPE_INT && Prefix == PFF_PREFIX_SHORT)
+ {
+ // Convert explicitly from int to short to get
+ // correct sign extension for shorts on all systems.
+ int n;
+ short s;
+
+ n = va_arg(ap, int);
+ s = (short) n;
+
+ TempInt = snprintf(BufferPtr, TempCount, TempBuff, s);
+ }
+ else
+ {
+ /* limit string output (%s) to 300 characters */
+ if(TempBuff[0] == '%' && TempBuff[1] == 's')
+ {
+ if (strcpy_s(TempBuff, sizeof(TempBuff), "%.300s") != SAFECRT_SUCCESS)
+ {
+ va_end(ap);
+ return -1;
+ }
+ }
+ va_list apcopy;
+ va_copy(apcopy, ap);
+ TempInt = InternalVsnprintf(CorUnix::InternalGetCurrentThread(), BufferPtr, TempCount, TempBuff, apcopy);
+ va_end(apcopy);
+ PAL_printf_arg_remover(&ap, Width, Precision, Type, Prefix);
+ }
+
+ if (TempInt < 0 || static_cast<size_t>(TempInt) >= TempCount) /* buffer not long enough */
+ {
+ BufferPtr += TempCount;
+ BufferRanOut = TRUE;
+ }
+ else
+ {
+ BufferPtr += TempInt;
+ }
+ }
+ }
+ else
+ {
+ *BufferPtr++ = *Fmt++; /* copy regular chars into buffer */
+ }
+ }
+
+ if (Count > (BufferPtr - Buffer))
+ {
+ *BufferPtr = 0; /* end the string */
+ }
+
+ va_end(ap);
+
+ if (BufferRanOut)
+ {
+ return -1;
+ }
+ else
+ {
+ return BufferPtr - Buffer;
+ }
+}
+
+/*++
+Function:
+ PAL_vfprintf (silent version)
+
+ for more details, see PAL_vfprintf in printf.c
+--*/
+int Silent_PAL_vfprintf(PAL_FILE *stream, const char *format, va_list aparg)
+{
+ CHAR TempBuff[1024]; /* used to hold a single %<foo> format string */
+ LPCSTR Fmt = format;
+ LPWSTR TempWStr;
+ LPSTR TempStr;
+ WCHAR TempWChar;
+ INT Flags;
+ INT Width;
+ INT Precision;
+ INT Prefix;
+ INT Type;
+ INT Length;
+ INT TempInt;
+ int wctombResult;
+ int written = 0;
+ int paddingReturnValue;
+ va_list ap;
+
+ va_copy(ap, aparg);
+
+ while (*Fmt)
+ {
+ if (*Fmt == '%' &&
+ TRUE == Silent_ExtractFormatA(&Fmt, TempBuff, &Flags, &Width,
+ &Precision, &Prefix, &Type))
+ {
+ if (Prefix == PFF_PREFIX_LONG && Type == PFF_TYPE_STRING)
+ {
+ if (WIDTH_STAR == Width)
+ {
+ Width = va_arg(ap, INT);
+ }
+ else if (WIDTH_INVALID == Width)
+ {
+ /* both a '*' and a number, ignore, but remove arg */
+ TempInt = va_arg(ap, INT); /* value not used */
+ }
+
+ if (PRECISION_STAR == Precision)
+ {
+ Precision = va_arg(ap, INT);
+ }
+ else if (PRECISION_INVALID == Precision)
+ {
+ /* both a '*' and a number, ignore, but remove arg */
+ TempInt = va_arg(ap, INT); /* value not used */
+ }
+
+ TempWStr = va_arg(ap, LPWSTR);
+ Length = Silent_WideCharToMultiByte(TempWStr, -1, 0, 0);
+ if (!Length)
+ {
+ va_end(ap);
+ return -1;
+ }
+ TempStr = (LPSTR) PAL_malloc(Length);
+ if (!TempStr)
+ {
+ va_end(ap);
+ return -1;
+ }
+ if (PRECISION_DOT == Precision)
+ {
+ /* copy nothing */
+ *TempStr = 0;
+ Length = 0;
+ }
+ else if (Precision > 0 && Precision < Length - 1)
+ {
+ Length = Silent_WideCharToMultiByte(TempWStr, Precision,
+ TempStr, Length);
+ if (!Length)
+ {
+ PAL_free(TempStr);
+ va_end(ap);
+ return -1;
+ }
+ TempStr[Length] = 0;
+ Length = Precision;
+ }
+ /* copy everything */
+ else
+ {
+ wctombResult = Silent_WideCharToMultiByte(TempWStr, -1,
+ TempStr, Length);
+ if (!wctombResult)
+ {
+ PAL_free(TempStr);
+ va_end(ap);
+ return -1;
+ }
+ --Length; /* exclude null char */
+ }
+
+ /* do the padding (if needed)*/
+ paddingReturnValue =
+ Silent_AddPaddingVfprintf(stream, TempStr, Width - Length, Flags);
+ if (-1 == paddingReturnValue)
+ {
+ PAL_free(TempStr);
+ va_end(ap);
+ return -1;
+ }
+ written += paddingReturnValue;
+
+ PAL_free(TempStr);
+ }
+ else if (Prefix == PFF_PREFIX_LONG && Type == PFF_TYPE_CHAR)
+ {
+ CHAR TempBuffer[4];
+ if (WIDTH_STAR == Width ||
+ WIDTH_INVALID == Width)
+ {
+ /* ignore (because it's a char), and remove arg */
+ TempInt = va_arg(ap, INT); /* value not used */
+ }
+ if (PRECISION_STAR == Precision ||
+ PRECISION_INVALID == Precision)
+ {
+ /* ignore (because it's a char), and remove arg */
+ TempInt = va_arg(ap, INT); /* value not used */
+ }
+
+ TempWChar = va_arg(ap, int);
+ Length = Silent_WideCharToMultiByte(&TempWChar, 1, TempBuffer, 4);
+ if (!Length)
+ {
+ va_end(ap);
+ return -1;
+ }
+ TempBuffer[Length] = 0;
+
+ /* do the padding (if needed)*/
+ paddingReturnValue =
+ Silent_AddPaddingVfprintf(stream, TempBuffer,
+ Width - Length, Flags);
+ if (-1 == paddingReturnValue)
+ {
+ va_end(ap);
+ return -1;
+ }
+ written += paddingReturnValue;
+
+ }
+ /* this places the number of bytes written to the buffer in the
+ next arg */
+ else if (Type == PFF_TYPE_N)
+ {
+ if (WIDTH_STAR == Width)
+ {
+ Width = va_arg(ap, INT);
+ }
+ if (PRECISION_STAR == Precision)
+ {
+ Precision = va_arg(ap, INT);
+ }
+
+ if (Prefix == PFF_PREFIX_SHORT)
+ {
+ *(va_arg(ap, short *)) = written;
+ }
+ else
+ {
+ *(va_arg(ap, LPLONG)) = written;
+ }
+ }
+ /* types that sprintf can handle */
+ else
+ {
+ TempInt = 0;
+
+ /* %h (short) doesn't seem to be handled properly by local sprintf,
+ so lets do the truncation ourselves. (ptr -> int -> short to avoid
+ warnings */
+ if (Type == PFF_TYPE_P && Prefix == PFF_PREFIX_SHORT)
+ {
+ long trunc1;
+ short trunc2;
+
+ trunc1 = va_arg(ap, LONG);
+ trunc2 = (short)trunc1;
+
+ TempInt = fprintf((FILE*)stream, TempBuff, trunc2);
+ }
+ else if (Type == PFF_TYPE_INT && Prefix == PFF_PREFIX_SHORT)
+ {
+ // Convert explicitly from int to short to get
+ // correct sign extension for shorts on all systems.
+ int n;
+ short s;
+
+ n = va_arg(ap, int);
+ s = (short)n;
+
+ TempInt = fprintf((FILE*)stream, TempBuff, s);
+ }
+ else
+ {
+ va_list apcopy;
+ va_copy(apcopy, ap);
+ TempInt = PAL_vfprintf(stream, TempBuff, apcopy);
+ va_end(apcopy);
+ PAL_printf_arg_remover(&ap, Width, Precision, Type, Prefix);
+ }
+
+ if (-1 != TempInt)
+ {
+ written += TempInt;
+ }
+ }
+ }
+ else
+ {
+#if FILE_OPS_CHECK_FERROR_OF_PREVIOUS_CALL
+ clearerr((FILE*)stream);
+#endif
+
+ PAL_fwrite(Fmt++, 1, 1, stream); /* copy regular chars into buffer */
+ if (stream->PALferrorCode == PAL_FILE_ERROR)
+ {
+ va_end(ap);
+ return -1;
+ }
+ ++written;
+ }
+ }
+
+ va_end(ap);
+ return written;
+}
+
+/*++
+Function:
+ WideCharToMultiByte (reduced and silent version)
+
+See MSDN doc.
+--*/
+int Silent_WideCharToMultiByte(LPCWSTR lpWideCharStr, int cchWideChar,
+ LPSTR lpMultiByteStr, int cbMultiByte)
+{
+ INT retval =0;
+
+ if ((lpWideCharStr == NULL)||
+ (lpWideCharStr == (LPCWSTR) lpMultiByteStr))
+ {
+ goto EXIT;
+ }
+
+ if (cchWideChar == -1)
+ {
+ cchWideChar = Silent_PAL_wcslen(lpWideCharStr) + 1;
+ }
+
+ if (cbMultiByte == 0)
+ {
+ retval = cchWideChar;
+ goto EXIT;
+ }
+ else if(cbMultiByte < cchWideChar)
+ {
+ retval = 0;
+ goto EXIT;
+ }
+
+ retval = cchWideChar;
+ while(cchWideChar > 0)
+ {
+ if(*lpWideCharStr > 255)
+ {
+ *lpMultiByteStr = '?';
+ }
+ else
+ {
+ *lpMultiByteStr = (unsigned char)*lpWideCharStr;
+ }
+ lpMultiByteStr++;
+ lpWideCharStr++;
+ cchWideChar--;
+ }
+
+EXIT:
+ return retval;
+}
+
+/*******************************************************************************
+Function:
+ Internal_ExtractFormatA (silent version)
+
+ see Internal_ExtractFormatA function in printf.c
+*******************************************************************************/
+BOOL Silent_ExtractFormatA(LPCSTR *Fmt, LPSTR Out, LPINT Flags, LPINT Width, LPINT Precision, LPINT Prefix, LPINT Type)
+{
+ BOOL Result = FALSE;
+ LPSTR TempStr;
+ LPSTR TempStrPtr;
+
+ *Width = WIDTH_DEFAULT;
+ *Precision = PRECISION_DEFAULT;
+ *Flags = PFF_NONE;
+ *Prefix = PFF_PREFIX_DEFAULT;
+ *Type = PFF_TYPE_DEFAULT;
+
+ if (*Fmt && **Fmt == '%')
+ {
+ *Out++ = *(*Fmt)++;
+ }
+ else
+ {
+ return Result;
+ }
+
+ /* we'll never need a temp string longer than the original */
+ TempStrPtr = TempStr = (LPSTR) PAL_malloc(strlen(*Fmt)+1);
+ if (!TempStr)
+ {
+ return Result;
+ }
+
+ /* parse flags */
+ while (**Fmt && (**Fmt == '-' || **Fmt == '+' ||
+ **Fmt == '0' || **Fmt == ' ' || **Fmt == '#'))
+ {
+ switch (**Fmt)
+ {
+ case '-':
+ *Flags |= PFF_MINUS; break;
+ case '+':
+ *Flags |= PFF_PLUS; break;
+ case '0':
+ *Flags |= PFF_ZERO; break;
+ case ' ':
+ *Flags |= PFF_SPACE; break;
+ case '#':
+ *Flags |= PFF_POUND; break;
+ }
+ *Out++ = *(*Fmt)++;
+ }
+ /* '-' flag negates '0' flag */
+ if ((*Flags & PFF_MINUS) && (*Flags & PFF_ZERO))
+ {
+ *Flags -= PFF_ZERO;
+ }
+
+ /* grab width specifier */
+ if (isdigit((unsigned char) **Fmt))
+ {
+ TempStrPtr = TempStr;
+ while (isdigit((unsigned char) **Fmt))
+ {
+ *TempStrPtr++ = **Fmt;
+ *Out++ = *(*Fmt)++;
+ }
+ *TempStrPtr = 0; /* end string */
+ *Width = atoi(TempStr);
+ if (*Width < 0)
+ {
+ SetLastError(ERROR_INTERNAL_ERROR);
+ return Result;
+ }
+ }
+ else if (**Fmt == '*')
+ {
+ *Width = WIDTH_STAR;
+ *Out++ = *(*Fmt)++;
+ if (isdigit((unsigned char) **Fmt))
+ {
+ /* this is an invalid width because we have a * then a number */
+ /* printf handles this by just printing the whole string */
+ *Width = WIDTH_INVALID;
+ while (isdigit((unsigned char) **Fmt))
+ {
+ *Out++ = *(*Fmt)++;
+ }
+ }
+ }
+
+
+ /* grab precision specifier */
+ if (**Fmt == '.')
+ {
+ *Out++ = *(*Fmt)++;
+ if (isdigit((unsigned char) **Fmt))
+ {
+ TempStrPtr = TempStr;
+ while (isdigit((unsigned char) **Fmt))
+ {
+ *TempStrPtr++ = **Fmt;
+ *Out++ = *(*Fmt)++;
+ }
+ *TempStrPtr = 0; /* end string */
+ *Precision = atoi(TempStr);
+ if (*Precision < 0)
+ {
+ SetLastError(ERROR_INTERNAL_ERROR);
+ return Result;
+ }
+ }
+ else if (**Fmt == '*')
+ {
+ *Precision = PRECISION_STAR;
+ *Out++ = *(*Fmt)++;
+ if (isdigit((unsigned char) **Fmt))
+ {
+ /* this is an invalid precision because we have a .* then a
+ number */
+ /* printf handles this by just printing the whole string */
+ *Precision = PRECISION_INVALID;
+ while (isdigit((unsigned char) **Fmt))
+ {
+ *Out++ = *(*Fmt)++;
+ }
+ }
+ }
+ else
+ {
+ *Precision = PRECISION_DOT;
+ }
+ }
+
+#ifdef BIT64
+ if (**Fmt == 'p')
+ {
+ *Prefix = PFF_PREFIX_LONGLONG;
+ }
+#endif
+ /* grab prefix of 'I64' for __int64 */
+ if ((*Fmt)[0] == 'I' && (*Fmt)[1] == '6' && (*Fmt)[2] == '4')
+ {
+ /* convert to 'll' so BSD's snprintf can handle it */
+ *Fmt += 3;
+ *Prefix = PFF_PREFIX_LONGLONG;
+ }
+ /* grab a prefix of 'h' */
+ else if (**Fmt == 'h')
+ {
+ *Prefix = PFF_PREFIX_SHORT;
+ ++(*Fmt);
+ }
+ /* grab prefix of 'l' or the undocumented 'w' (at least in MSDN) */
+ else if (**Fmt == 'l' || **Fmt == 'w')
+ {
+ ++(*Fmt);
+#ifdef BIT64
+ // Only want to change the prefix on 64 bit when printing characters.
+ if (**Fmt == 'c' || **Fmt == 's')
+#endif
+ {
+ *Prefix = PFF_PREFIX_LONG;
+ }
+ }
+ else if (**Fmt == 'L')
+ {
+ /* a prefix of 'L' seems to be ignored */
+ ++(*Fmt);
+ }
+
+ /* grab type 'c' */
+ if (**Fmt == 'c' || **Fmt == 'C')
+ {
+ *Type = PFF_TYPE_CHAR;
+ if (*Prefix != PFF_PREFIX_SHORT && **Fmt == 'C')
+ {
+ *Prefix = PFF_PREFIX_LONG; /* give it a wide prefix */
+ }
+ if (*Prefix == PFF_PREFIX_LONG)
+ {
+ *Out++ = 'l';
+ }
+ *Out++ = 'c';
+ ++(*Fmt);
+ Result = TRUE;
+ }
+ /* grab type 's' */
+ else if (**Fmt == 's' || **Fmt == 'S')
+ {
+ *Type = PFF_TYPE_STRING;
+ if (*Prefix != PFF_PREFIX_SHORT && **Fmt == 'S')
+ {
+ *Prefix = PFF_PREFIX_LONG; /* give it a wide prefix */
+ }
+ if (*Prefix == PFF_PREFIX_LONG)
+ {
+ *Out++ = 'l';
+ }
+ *Out++ = 's';
+ ++(*Fmt);
+ Result = TRUE;
+ }
+ /* grab int types types */
+ else if (**Fmt == 'd' || **Fmt == 'i' || **Fmt == 'o' ||
+ **Fmt == 'u' || **Fmt == 'x' || **Fmt == 'X')
+ {
+ *Type = PFF_TYPE_INT;
+ if (*Prefix == PFF_PREFIX_SHORT)
+ {
+ *Out++ = 'h';
+ }
+ else if (*Prefix == PFF_PREFIX_LONG)
+ {
+ *Out++ = 'l';
+ }
+ else if (*Prefix == PFF_PREFIX_LONGLONG)
+ {
+ *Out++ = 'l';
+ *Out++ = 'l';
+ }
+ *Out++ = *(*Fmt)++;
+ Result = TRUE;
+ }
+ else if (**Fmt == 'e' || **Fmt == 'E' || **Fmt == 'f' ||
+ **Fmt == 'g' || **Fmt == 'G')
+ {
+ /* we can safely ignore the prefixes and only add the type*/
+ *Type = PFF_TYPE_FLOAT;
+ *Out++ = *(*Fmt)++;
+ Result = TRUE;
+ }
+ else if (**Fmt == 'n')
+ {
+ if (*Prefix == PFF_PREFIX_SHORT)
+ {
+ *Out++ = 'h';
+ }
+ *Out++ = *(*Fmt)++;
+ *Type = PFF_TYPE_N;
+ Result = TRUE;
+ }
+ else if (**Fmt == 'p')
+ {
+ *Type = PFF_TYPE_P;
+ *Out++ = *(*Fmt)++;
+
+ if (*Prefix == PFF_PREFIX_LONGLONG)
+ {
+ if (*Precision == PRECISION_DEFAULT)
+ {
+ *Precision = 16;
+ }
+ }
+ else
+ {
+ if (*Precision == PRECISION_DEFAULT)
+ {
+ *Precision = 8;
+ }
+ }
+ Result = TRUE;
+ }
+
+ *Out = 0; /* end the string */
+ PAL_free(TempStr);
+ return Result;
+}
+
+/*******************************************************************************
+Function:
+ AddPaddingVfprintf (silent version)
+ see Internal_AddPaddingVfprintf in printf.c
+*******************************************************************************/
+INT Silent_AddPaddingVfprintf(PAL_FILE *stream, LPSTR In, INT Padding, INT Flags)
+{
+ LPSTR Out;
+ INT LengthInStr;
+ INT Length;
+ LPSTR OutOriginal;
+ INT Written;
+
+ LengthInStr = strlen(In);
+ Length = LengthInStr;
+
+
+ if (Padding > 0)
+ {
+ Length += Padding;
+ }
+ Out = (LPSTR) PAL_malloc(Length+1);
+ int iLen = Length+1;
+ if (!Out)
+ {
+ return -1;
+ }
+ OutOriginal = Out;
+
+ if (Flags & PFF_MINUS) /* pad on right */
+ {
+ if (strcpy_s(Out, iLen, In) != SAFECRT_SUCCESS)
+ {
+ Written = -1;
+ goto Done;
+ }
+
+ Out += LengthInStr;
+ iLen -= LengthInStr;
+ }
+ if (Padding > 0)
+ {
+ iLen -= Padding;
+ if (Flags & PFF_ZERO) /* '0', pad with zeros */
+ {
+ while (Padding--)
+ {
+ *Out++ = '0';
+ }
+ }
+ else /* pad with spaces */
+ {
+ while (Padding--)
+ {
+ *Out++ = ' ';
+ }
+ }
+ }
+ if (!(Flags & PFF_MINUS)) /* put 'In' after padding */
+ {
+ if (strcpy_s(Out, Length+1, In) != SAFECRT_SUCCESS)
+ {
+ Written = -1;
+ goto Done;
+ }
+
+ Out += LengthInStr;
+ iLen -= LengthInStr;
+ }
+
+#if FILE_OPS_CHECK_FERROR_OF_PREVIOUS_CALL
+ clearerr((FILE*)stream);
+#endif
+
+ Written = PAL_fwrite(OutOriginal, 1, Length, stream);
+ if (stream->PALferrorCode == PAL_FILE_ERROR)
+ {
+ Written = -1;
+ }
+
+Done:
+ PAL_free(OutOriginal);
+ return Written;
+}
+
+/*++
+Function:
+ PAL_wcslen (silent version)
+
+See MSDN or the man page for wcslen.
+
+--*/
+size_t Silent_PAL_wcslen(const wchar_16 *string)
+{
+ size_t nChar = 0;
+
+ if ( !string )
+ {
+ return 0;
+ }
+ while (*string++)
+ {
+ nChar++;
+ }
+
+ return nChar;
+}
diff --git a/src/pal/src/cruntime/string.cpp b/src/pal/src/cruntime/string.cpp
new file mode 100644
index 0000000000..23781d8b39
--- /dev/null
+++ b/src/pal/src/cruntime/string.cpp
@@ -0,0 +1,348 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ string.cpp
+
+Abstract:
+
+ Implementation of the string functions in the C runtime library that are Windows specific.
+
+
+
+--*/
+
+#include "pal/palinternal.h"
+#include "pal/dbgmsg.h"
+#include "pal/cruntime.h"
+
+#include <string.h>
+#include <ctype.h>
+#include <pthread.h>
+#include <errno.h>
+#include <limits.h>
+#include <unistd.h>
+
+
+SET_DEFAULT_DEBUG_CHANNEL(CRT);
+
+/*++
+Function:
+ _strnicmp
+
+compare at most count characters from two strings, ignoring case
+
+The strnicmp() function compares, with case insensitivity, at most count
+characters from s1 to s2. All uppercase characters from s1 and s2 are
+mapped to lowercase for the purposes of doing the comparison.
+
+Returns:
+
+Value Meaning
+
+< 0 s1 is less than s2
+0 s1 is equal to s2
+> 0 s1 is greater than s2
+
+--*/
+int
+__cdecl
+_strnicmp( const char *s1, const char *s2, size_t count )
+{
+ int ret;
+
+ PERF_ENTRY(_strnicmp);
+ ENTRY("_strnicmp (s1=%p (%s), s2=%p (%s), count=%d)\n", s1?s1:"NULL", s1?s1:"NULL", s2?s2:"NULL", s2?s2:"NULL", count);
+
+ ret = strncasecmp(s1, s2, count );
+
+ LOGEXIT("_strnicmp returning int %d\n", ret);
+ PERF_EXIT(_strnicmp);
+ return ret;
+}
+
+/*++
+Function:
+ _stricmp
+
+compare two strings, ignoring case
+
+The stricmp() function compares, with case insensitivity, the string
+pointed to by s1 to the string pointed to by s2. All uppercase
+characters from s1 and s2 are mapped to lowercase for the purposes of
+doing the comparison.
+
+Returns:
+
+Value Meaning
+
+< 0 s1 is less than s2
+0 s1 is equal to s2
+> 0 s1 is greater than s2
+
+--*/
+int
+__cdecl
+_stricmp(
+ const char *s1,
+ const char *s2)
+{
+ int ret;
+
+ PERF_ENTRY(_stricmp);
+ ENTRY("_stricmp (s1=%p (%s), s2=%p (%s))\n", s1?s1:"NULL", s1?s1:"NULL", s2?s2:"NULL", s2?s2:"NULL");
+
+ ret = strcasecmp(s1, s2);
+
+ LOGEXIT("_stricmp returning int %d\n", ret);
+ PERF_EXIT(_stricmp);
+ return ret;
+}
+
+
+/*++
+Function:
+ _strlwr
+
+Convert a string to lowercase.
+
+
+This function returns a pointer to the converted string. Because the
+modification is done in place, the pointer returned is the same as the
+pointer passed as the input argument. No return value is reserved to
+indicate an error.
+
+Parameter
+
+string Null-terminated string to convert to lowercase
+
+Remarks
+
+The _strlwr function converts any uppercase letters in string to
+lowercase as determined by the LC_CTYPE category setting of the
+current locale. Other characters are not affected. For more
+information on LC_CTYPE, see setlocale.
+
+--*/
+char *
+__cdecl
+_strlwr(
+ char *str)
+{
+ char *orig = str;
+
+ PERF_ENTRY(_strlwr);
+ ENTRY("_strlwr (str=%p (%s))\n", str?str:"NULL", str?str:"NULL");
+
+ while (*str)
+ {
+ *str = tolower(*str);
+ str++;
+ }
+
+ LOGEXIT("_strlwr returning char* %p (%s)\n", orig?orig:"NULL", orig?orig:"NULL");
+ PERF_EXIT(_strlwr);
+ return orig;
+}
+
+
+/*++
+Function:
+ _swab
+
+Swaps bytes.
+
+Return Value
+
+None
+
+Parameters
+
+src Data to be copied and swapped
+dest Storage location for swapped data
+n Number of bytes to be copied and swapped
+
+Remarks
+
+The _swab function copies n bytes from src, swaps each pair of
+adjacent bytes, and stores the result at dest. The integer n should be
+an even number to allow for swapping. _swab is typically used to
+prepare binary data for transfer to a machine that uses a different
+byte order.
+
+Example
+
+char from[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+char to[] = "..........................";
+
+printf("Before:\n%s\n%s\n\n", from, to);
+_swab(from, to, strlen(from));
+printf("After:\n%s\n%s\n\n", from, to);
+
+Before:
+ABCDEFGHIJKLMNOPQRSTUVWXYZ
+..........................
+
+After:
+ABCDEFGHIJKLMNOPQRSTUVWXYZ
+BADCFEHGJILKNMPORQTSVUXWZY
+
+--*/
+void
+__cdecl
+_swab(char *src, char *dest, int n)
+{
+ PERF_ENTRY(_swab);
+ ENTRY("_swab (src=%p (%s), dest=%p (%s), n=%d)\n", src?src:"NULL", src?src:"NULL", dest?dest:"NULL", dest?dest:"NULL", n);
+ swab(src, dest, n);
+ LOGEXIT("_swab returning\n");
+ PERF_EXIT(_swab);
+}
+
+
+/*++
+Function:
+ PAL_strtoul
+
+Convert string to an unsigned long-integer value.
+
+Return Value
+
+strtoul returns the converted value, if any, or ULONG_MAX on
+overflow. It returns 0 if no conversion can be performed. errno is
+set to ERANGE if overflow or underflow occurs.
+
+Parameters
+
+szNumber Null-terminated string to convert to a ULONG
+pszEnd Pointer to character that stops scan
+nBase Number base to use
+
+Remarks
+
+strtoul stops reading the string szNumber at the first character it cannot
+recognize as part of a number. This may be the terminating null
+character, or it may be the first numeric character greater than or
+equal to base. The LC_NUMERIC category setting of the current locale
+determines recognition of the radix character in szNumber; for more
+information, see setlocale. If pszEnd is not NULL, a pointer to the
+character that stopped the scan is stored at the location pointed to
+by pszEnd. If no conversion can be performed (no valid digits were
+found or an invalid base was specified), the value of szNumber is stored
+at the location pointed to by pszEnd.
+
+Notes :
+ MSDN states that only space and tab are accepted as leading whitespace, but
+ tests indicate that other whitespace characters (newline, carriage return,
+ etc) are also accepted. This matches the behavior on Unix systems.
+
+ For strtoul, we need to check if the value to be returned
+ is outside the 32 bit range. If so, the returned value needs to be set
+ as appropriate, according to the MSDN pages and in all instances errno
+ must be set to ERANGE (The one exception is converting a string
+ representing a negative value to unsigned long).
+ Note that on 64 bit Windows, long's are still 32 bit. Thus, to match
+ Windows behavior, we must return long's in the 32 bit range.
+ --*/
+
+/* The use of ULONG is by design, to ensure that a 32 bit value is always
+returned from this function. If "unsigned long" is used instead of ULONG,
+then a 64 bit value could be returned on 64 bit platforms like HP-UX, thus
+breaking Windows behavior. */
+ULONG
+__cdecl
+PAL_strtoul(const char *szNumber, char **pszEnd, int nBase)
+{
+ unsigned long ulResult;
+
+ PERF_ENTRY(strtoul);
+ ENTRY("strtoul (szNumber=%p (%s), pszEnd=%p, nBase=%d)\n",
+ szNumber?szNumber:"NULL",
+ szNumber?szNumber:"NULL",
+ pszEnd,
+ nBase);
+
+ ulResult = strtoul(szNumber, pszEnd, nBase);
+
+#ifdef BIT64
+ if (ulResult > _UI32_MAX)
+ {
+ char ch = *szNumber;
+ while (isspace(ch))
+ {
+ ch = *szNumber++;
+ }
+ /* If the string represents a positive number that is greater than
+ _UI32_MAX, set errno to ERANGE. Otherwise, don't set errno
+ to match Windows behavior. */
+ if (ch != '-')
+ {
+ ulResult = _UI32_MAX;
+ errno = ERANGE;
+ }
+ }
+#endif
+
+ LOGEXIT("strtoul returning unsigned long %lu\n", ulResult);
+ PERF_EXIT(wcstoul);
+
+ /* When returning unsigned long res from this function, it will be
+ implicitly cast to ULONG. This handles situations where a string that
+ represents a negative number is passed in to strtoul. The Windows
+ behavior is analogous to taking the binary equivalent of the negative
+ value and treating it as a positive number. Returning a ULONG from
+ this function, as opposed to native unsigned long, allows us to match
+ this behavior. The explicit cast to ULONG below is used to silence any
+ potential warnings due to the implicit casting. */
+ return (ULONG)ulResult;
+
+}
+
+
+/*++
+Function:
+ PAL_atol
+
+Convert string to a long value.
+
+Return Value
+
+atol returns the converted value, if any. In the case of overflow,
+the return value is undefined.
+
+Parameters
+
+szNumber Null-terminated string to convert to a LONG
+--*/
+
+/* The use of LONG is by design, to ensure that a 32 bit value is always
+returned from this function. If "long" is used instead of LONG, then a 64 bit
+value could be returned on 64 bit platforms like HP-UX, thus breaking
+Windows behavior. */
+LONG
+__cdecl
+PAL_atol(const char *szNumber)
+{
+ long lResult;
+
+ PERF_ENTRY(atol);
+ ENTRY("atol (szNumber=%p (%s))\n",
+ szNumber?szNumber:"NULL"
+ );
+
+ lResult = atol(szNumber);
+
+ LOGEXIT("atol returning long %ld\n", (LONG)lResult);
+ PERF_EXIT(atol);
+ /* This explicit cast to LONG is used to silence any potential warnings
+ due to implicitly casting the native long lResult to LONG when returning. */
+ return (LONG)lResult;
+
+}
+
diff --git a/src/pal/src/cruntime/stringtls.cpp b/src/pal/src/cruntime/stringtls.cpp
new file mode 100644
index 0000000000..1504813f91
--- /dev/null
+++ b/src/pal/src/cruntime/stringtls.cpp
@@ -0,0 +1,78 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ stringtls.cpp
+
+Abstract:
+
+ Implementation of the string functions in the C runtime library that
+ are Windows specific and depend on per-thread data
+
+
+
+--*/
+
+#include "pal/thread.hpp"
+#include "pal/dbgmsg.h"
+
+#include <string.h>
+#include <ctype.h>
+#include <pthread.h>
+#include <limits.h>
+#include <unistd.h>
+
+using namespace CorUnix;
+
+SET_DEFAULT_DEBUG_CHANNEL(CRT);
+
+/*++
+Function:
+ PAL_strtok
+
+Finds the next token in a string.
+
+Return value:
+
+A pointer to the next token found in strToken. Returns NULL when no more
+tokens are found. Each call modifies strToken by substituting a NULL
+character for each delimiter that is encountered.
+
+Parameters:
+strToken String cotaining token(s)
+strDelimit Set of delimiter characters
+
+Remarks:
+In FreeBSD, strtok is not re-entrant, strtok_r is. It manages re-entrancy
+by using a passed-in context pointer (which will be stored in thread local
+storage) According to the strtok MSDN documentation, "Calling these functions
+simultaneously from multiple threads does not have undesirable effects", so
+we need to use strtok_r.
+--*/
+char *
+__cdecl
+PAL_strtok(char *strToken, const char *strDelimit)
+{
+ CPalThread *pThread = NULL;
+ char *retval=NULL;
+
+ PERF_ENTRY(strtok);
+ ENTRY("strtok (strToken=%p (%s), strDelimit=%p (%s))\n",
+ strToken?strToken:"NULL",
+ strToken?strToken:"NULL", strDelimit?strDelimit:"NULL", strDelimit?strDelimit:"NULL");
+
+ pThread = InternalGetCurrentThread();
+
+ retval = strtok_r(strToken, strDelimit, &pThread->crtInfo.strtokContext);
+
+ LOGEXIT("strtok returns %p (%s)\n", retval?retval:"NULL", retval?retval:"NULL");
+ PERF_EXIT(strtok);
+
+ return retval;
+}
diff --git a/src/pal/src/cruntime/thread.cpp b/src/pal/src/cruntime/thread.cpp
new file mode 100644
index 0000000000..6c96b1b511
--- /dev/null
+++ b/src/pal/src/cruntime/thread.cpp
@@ -0,0 +1,52 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ thread.c
+
+Abstract:
+
+ Implementation of the threads/process functions in the C runtime library
+ that are Windows specific.
+
+
+
+--*/
+
+#include "pal/palinternal.h"
+#include "pal/dbgmsg.h"
+#include "pal/init.h"
+
+SET_DEFAULT_DEBUG_CHANNEL(CRT);
+
+void
+PAL_exit(int status)
+{
+ PERF_ENTRY(exit);
+ ENTRY ("exit(status=%d)\n", status);
+
+ /* should also clean up any resources allocated by pal/cruntime, if any */
+ ExitProcess(status);
+
+ LOGEXIT ("exit returns void");
+ PERF_EXIT(exit);
+}
+
+int
+PAL_atexit(void (__cdecl *function)(void))
+{
+ int ret;
+
+ PERF_ENTRY(atexit);
+ ENTRY ("atexit(function=%p)\n", function);
+ ret = atexit(function);
+ LOGEXIT ("atexit returns int %d", ret);
+ PERF_EXIT(atexit);
+ return ret;
+}
diff --git a/src/pal/src/cruntime/wchar.cpp b/src/pal/src/cruntime/wchar.cpp
new file mode 100644
index 0000000000..2d244a639f
--- /dev/null
+++ b/src/pal/src/cruntime/wchar.cpp
@@ -0,0 +1,1885 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ wchar.c
+
+Abstract:
+
+ Implementation of wide char string functions.
+
+
+
+--*/
+
+
+#include "pal/palinternal.h"
+#include "pal/cruntime.h"
+#include "pal/dbgmsg.h"
+#include "pal/unicode_data.h"
+
+#include "pal/thread.hpp"
+#include "pal/threadsusp.hpp"
+
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#if HAVE_COREFOUNDATION
+#define CF_EXCLUDE_CSTD_HEADERS
+#include <CoreFoundation/CoreFoundation.h>
+#include <wctype.h>
+#else
+#include <wctype.h>
+#endif
+
+#include <errno.h>
+
+SET_DEFAULT_DEBUG_CHANNEL(CRT);
+
+
+/*--
+Function:
+ wtolower (internal)
+
+16-bit wide character version of the ANSI tolower() function.
+
+ --*/
+static
+wchar_16
+wtolower(wchar_16 c)
+{
+ /* Note: Surrogate pairs unicode character are not supported */
+
+#if HAVE_TOWLOWER
+
+ wchar_t w;
+ w = (wchar_t) c;
+ w = towlower(w);
+ return (wchar_16) w;
+
+#else
+
+ return PAL_towlower(c);
+
+#endif
+
+}
+
+/*******************************************************************************
+Function:
+ Internal_i64tow
+
+Parameters:
+ value
+ - INT64 value to be converted to a string
+ string
+ - out buffer to place interger string
+ radix
+ - numeric base to convert to
+ isI64
+ - TRUE if value is INT64, FALSE if value is a long
+
+Note:
+ - only a radix of ten (and value < 0) will result in a negative
+ sign in the output buffer
+*******************************************************************************/
+LPWSTR Internal_i64tow(INT64 value, LPWSTR string, int radix, BOOL isI64)
+{
+ int length = 0;
+ int n;
+ int r;
+ UINT64 uval = value;
+ LPWSTR stringPtr = string;
+ int start = 0;
+ int end;
+ WCHAR tempCh;
+
+ if (radix < 2 || radix > 36)
+ {
+ ASSERT( "Invalid radix, radix must be between 2 and 36\n" );
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return string;
+ }
+ if (FALSE == isI64)
+ {
+ uval = (ULONG) uval;
+ }
+ if (10 == radix && value < 0)
+ {
+ uval = value * -1;
+ }
+ if(0 == uval)
+ {
+ ++length;
+ *stringPtr++ = '0';
+ }
+ else while (uval > 0)
+ {
+ ++length;
+ n = uval / radix;
+ r = uval - (n * radix);
+ uval /= radix;
+ if (r > 9)
+ {
+ *stringPtr++ = r + 87;
+ }
+ else
+ {
+ *stringPtr++ = r + 48;
+ }
+ }
+ if (10 == radix && value < 0)
+ {
+ *stringPtr++ = '-';
+ ++length;
+ }
+ *stringPtr = 0; /* end the string */
+
+ /* reverse the string */
+ end = length - 1;
+ while (start < end)
+ {
+ tempCh = string[start];
+ string[start] = string[end];
+ string[end] = tempCh;
+ ++start;
+ --end;
+ }
+
+ return string;
+}
+
+/*--
+Function:
+ _itow
+
+16-bit wide character version of the ANSI tolower() function.
+
+ --*/
+wchar_16 *
+__cdecl
+_itow(
+ int value,
+ wchar_16 *string,
+ int radix)
+{
+ wchar_16 *ret;
+
+ PERF_ENTRY(_itow);
+ ENTRY("_itow (value=%d, string=%p, radix=%d)\n",
+ value, string, radix);
+
+ ret = Internal_i64tow(value, string, radix, FALSE);
+
+ LOGEXIT("_itow returns wchar_t* %p\n", ret);
+ PERF_EXIT(_itow);
+
+ return ret;
+}
+
+/*--
+Function:
+ _i64tow
+
+See MSDN doc
+--*/
+wchar_16 *
+ __cdecl
+_i64tow(
+ __int64 value,
+ wchar_16 *string,
+ int radix)
+{
+ wchar_16 *ret;
+
+ PERF_ENTRY(_i64tow);
+ ENTRY("_i64tow (value=%ld, string=%p, radix=%d)\n",
+ value, string, radix);
+
+ ret = Internal_i64tow(value, string, radix, TRUE);
+
+ LOGEXIT("_i64tow returns wchar_t* %p\n", ret);
+ PERF_EXIT(_i64tow);
+
+ return ret;
+}
+
+
+/*--
+Function:
+ _wtoi
+
+See MSDN doc
+--*/
+int
+__cdecl
+_wtoi(
+ const wchar_16 *string)
+{
+ int len;
+ int ret;
+ char *tempStr;
+
+ PERF_ENTRY(_wtoi);
+ ENTRY("_wtoi (string=%p)\n", string);
+
+ len = WideCharToMultiByte(CP_ACP, 0, string, -1, 0, 0, 0, 0);
+ if (!len)
+ {
+ ASSERT("WideCharToMultiByte failed. Error is %d\n",
+ GetLastError());
+ return -1;
+ }
+ tempStr = (char *) PAL_malloc(len);
+ if (!tempStr)
+ {
+ ERROR("PAL_malloc failed\n");
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ return -1;
+ }
+ len = WideCharToMultiByte(CP_ACP, 0, string, -1, tempStr, len, 0, 0);
+ if (!len)
+ {
+ ASSERT("WideCharToMultiByte failed. Error is %d\n",
+ GetLastError());
+ PAL_free(tempStr);
+ return -1;
+ }
+ ret = atoi(tempStr);
+
+ PAL_free(tempStr);
+ LOGEXIT("_wtoi returns int %d\n", ret);
+ PERF_EXIT(_wtoi);
+ return ret;
+}
+
+
+/*--
+Function:
+ PAL_iswspace
+
+See MSDN doc
+--*/
+int
+__cdecl
+PAL_iswspace(wchar_16 c)
+{
+ int ret;
+
+ PERF_ENTRY(iswspace);
+ ENTRY("PAL_iswspace (c=%C)\n", c);
+
+ ret = iswspace(c);
+
+ LOGEXIT("PAL_iswspace returns int %d\n", ret);
+ PERF_EXIT(iswspace);
+ return ret;
+}
+
+/*++
+Function:
+ _wcsnicmp
+
+Compare characters of two strings without regard to case
+
+Return Value
+
+The return value indicates the relationship between the substrings as follows.
+
+Return Value
+
+Description
+
+< 0 string1 substring less than string2 substring
+ 0 string1 substring identical to string2 substring
+> 0 string1 substring greater than string2 substring
+
+Parameters
+
+string1, string2 Null-terminated strings to compare
+count Number of characters to compare
+
+Remarks
+
+The _strnicmp function lexicographically compares, at most, the first
+count characters of string1 and string2. The comparison is performed
+without regard to case; _strnicmp is a case-insensitive version of
+strncmp. The comparison ends if a terminating null character is
+reached in either string before count characters are compared. If the
+strings are equal when a terminating null character is reached in
+either string before count characters are compared, the shorter string
+is lesser.
+
+--*/
+int
+__cdecl
+_wcsnicmp(
+ const wchar_16 *string1,
+ const wchar_16 *string2,
+ size_t count)
+{
+ size_t i;
+ int diff = 0;
+
+ PERF_ENTRY(_wcsnicmp);
+ ENTRY("_wcsnicmp (string1=%p (%S), string2=%p (%S), count=%lu)\n",
+ string1?string1:W16_NULLSTRING,
+ string1?string1:W16_NULLSTRING, string2?string2:W16_NULLSTRING, string2?string2:W16_NULLSTRING,
+ (unsigned long) count);
+
+ for (i = 0; i < count; i++)
+ {
+ diff = wtolower(string1[i]) - wtolower(string2[i]);
+ if (diff != 0 || 0 == string1[i] || 0 == string2[i])
+ {
+ break;
+ }
+ }
+ LOGEXIT("_wcsnicmp returning int %d\n", diff);
+ PERF_EXIT(_wcsnicmp);
+ return diff;
+}
+
+/*++
+Function:
+ _wcsicmp
+
+Compare characters of two strings without regard to case
+
+Return Value
+
+The return value indicates the relationship between the substrings as follows.
+
+Return Value
+
+Description
+
+< 0 string1 substring less than string2 substring
+ 0 string1 substring identical to string2 substring
+> 0 string1 substring greater than string2 substring
+
+Parameters
+
+string1, string2 Null-terminated strings to compare
+
+--*/
+int
+__cdecl
+_wcsicmp(
+ const wchar_16 *string1,
+ const wchar_16 *string2)
+{
+ int ret;
+
+ PERF_ENTRY(_wcsicmp);
+ ENTRY("_wcsicmp (string1=%p (%S), string2=%p (%S))\n",
+ string1?string1:W16_NULLSTRING,
+ string1?string1:W16_NULLSTRING, string2?string2:W16_NULLSTRING, string2?string2:W16_NULLSTRING);
+
+ ret = _wcsnicmp(string1, string2, 0x7fffffff);
+
+ LOGEXIT("_wcsnicmp returns int %d\n", ret);
+ PERF_EXIT(_wcsicmp);
+ return ret;
+}
+
+
+/*++
+Function:
+ _wcslwr
+
+Convert a string to lowercase.
+
+Return Value
+
+Returns a pointer to the converted string. Because the modification is
+done in place, the pointer returned is the same as the pointer passed
+as the input argument. No return value is reserved to indicate an
+error.
+
+Parameter
+
+string Null-terminated string to convert to lowercase
+
+Remarks
+
+--*/
+wchar_16 *
+__cdecl
+_wcslwr(
+ wchar_16 *string)
+{
+ int i;
+
+ PERF_ENTRY(_wcslwr);
+ ENTRY("_wcslwr (string=%p (%S))\n", string?string:W16_NULLSTRING, string?string:W16_NULLSTRING);
+
+ for (i=0 ; string[i] != 0; i++)
+ {
+ string[i] = wtolower(string[i]);
+ }
+
+ LOGEXIT("_wcslwr returning wchar_t %p (%S)\n", string?string:W16_NULLSTRING, string?string:W16_NULLSTRING);
+ PERF_EXIT(_wcslwr);
+ return string;
+}
+
+
+/*++
+Function:
+ PAL_wcstol
+
+Convert string to a long-integer value.
+
+Return Value
+
+wcstol returns the value represented in the string nptr, except when
+the representation would cause an overflow, in which case it returns
+LONG_MAX or LONG_MIN. strtol returns 0 if no conversion can be
+performed. errno is set to ERANGE if overflow or underflow occurs.
+
+Parameters
+
+nptr Null-terminated string to convert
+endptr Pointer to character that stops scan
+base Number base to use
+
+Remarks
+
+The wcstol function converts nptr to a long. It stops reading the
+string nptr at the first character it cannot recognize as part of a
+number. This may be the terminating null character, or it may be the
+first numeric character greater than or equal to base.
+
+Notes :
+ MSDN states that only space and tab are accepted as leading whitespace, but
+ tests indicate that other whitespace characters (newline, carriage return,
+ etc) are also accepted. This matches the behavior on Unix systems.
+
+ For wcstol and wcstoul, we need to check if the value to be returned
+ is outside the 32 bit range. If so, the returned value needs to be set
+ as appropriate, according to the MSDN pages for wcstol and wcstoul,
+ and in all instances errno must be set to ERANGE (The one exception
+ is converting a string representing a negative value to unsigned long).
+ Note that on 64 bit Windows, long's are still 32 bit. Thus, to match
+ Windows behavior, we must return long's in the 32 bit range.
+--*/
+
+/* The use of LONG is by design, to ensure that a 32 bit value is always
+returned from this function. If "long" is used instead of LONG, then a 64 bit
+value could be returned on 64 bit platforms like HP-UX, thus breaking
+Windows behavior. */
+LONG
+__cdecl
+PAL_wcstol(
+ const wchar_16 *nptr,
+ wchar_16 **endptr,
+ int base)
+{
+ char *s_nptr = 0;
+ char *s_endptr = 0;
+ long res;
+ int size;
+ DWORD dwLastError = 0;
+
+ PERF_ENTRY(wcstol);
+ ENTRY("wcstol (nptr=%p (%S), endptr=%p, base=%d)\n", nptr?nptr:W16_NULLSTRING, nptr?nptr:W16_NULLSTRING,
+ endptr, base);
+
+ size = WideCharToMultiByte(CP_ACP, 0, nptr, -1, NULL, 0, NULL, NULL);
+ if (!size)
+ {
+ dwLastError = GetLastError();
+ ASSERT("WideCharToMultiByte failed. Error is %d\n", dwLastError);
+ SetLastError(ERROR_INVALID_PARAMETER);
+ res = 0;
+ goto PAL_wcstolExit;
+ }
+ s_nptr = (char *)PAL_malloc(size);
+ if (!s_nptr)
+ {
+ ERROR("PAL_malloc failed\n");
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ res = 0;
+ goto PAL_wcstolExit;
+ }
+ size = WideCharToMultiByte(CP_ACP, 0, nptr, -1, s_nptr, size, NULL, NULL);
+ if( size==0 )
+ {
+ dwLastError = GetLastError();
+ ASSERT("WideCharToMultiByte failed. Error is %d\n", dwLastError);
+ SetLastError(ERROR_INVALID_PARAMETER);
+ res = 0;
+ goto PAL_wcstolExit;
+ }
+
+ res = strtol(s_nptr, &s_endptr, base);
+
+#ifdef BIT64
+ if (res > _I32_MAX)
+ {
+ res = _I32_MAX;
+ errno = ERANGE;
+ }
+ else if (res < _I32_MIN)
+ {
+ res = _I32_MIN;
+ errno = ERANGE;
+ }
+#endif
+
+ /* only ASCII characters will be accepted by strtol, and those always get
+ mapped to single-byte characters, so the first rejected character will
+ have the same index in the multibyte and widechar strings */
+ if( endptr )
+ {
+ size = s_endptr - s_nptr;
+ *endptr = (wchar_16 *)&nptr[size];
+ }
+
+PAL_wcstolExit:
+ PAL_free(s_nptr);
+ LOGEXIT("wcstol returning long %ld\n", res);
+ PERF_EXIT(wcstol);
+ /* This explicit cast to LONG is used to silence any potential warnings
+ due to implicitly casting the native long res to LONG when returning. */
+ return (LONG)res;
+}
+
+
+/*++
+Function:
+ PAL_wcstoul
+
+Convert string to an unsigned long-integer value.
+
+Return Value
+
+wcstoul returns the converted value, if any, or ULONG_MAX on
+overflow. It returns 0 if no conversion can be performed. errno is
+set to ERANGE if overflow or underflow occurs.
+
+Parameters
+
+nptr Null-terminated string to convert
+endptr Pointer to character that stops scan
+base Number base to use
+
+Remarks
+
+wcstoul stops reading the string nptr at the first character it cannot
+recognize as part of a number. This may be the terminating null
+character, or it may be the first numeric character greater than or
+equal to base. The LC_NUMERIC category setting of the current locale
+determines recognition of the radix character in nptr; for more
+information, see setlocale. If endptr is not NULL, a pointer to the
+character that stopped the scan is stored at the location pointed to
+by endptr. If no conversion can be performed (no valid digits were
+found or an invalid base was specified), the value of nptr is stored
+at the location pointed to by endptr.
+
+Notes :
+ MSDN states that only space and tab are accepted as leading whitespace, but
+ tests indicate that other whitespace characters (newline, carriage return,
+ etc) are also accepted. This matches the behavior on Unix systems.
+
+ For wcstol and wcstoul, we need to check if the value to be returned
+ is outside the 32 bit range. If so, the returned value needs to be set
+ as appropriate, according to the MSDN pages for wcstol and wcstoul,
+ and in all instances errno must be set to ERANGE (The one exception
+ is converting a string representing a negative value to unsigned long).
+ Note that on 64 bit Windows, long's are still 32 bit. Thus, to match
+ Windows behavior, we must return long's in the 32 bit range.
+--*/
+
+/* The use of ULONG is by design, to ensure that a 32 bit value is always
+returned from this function. If "unsigned long" is used instead of ULONG,
+then a 64 bit value could be returned on 64 bit platforms like HP-UX, thus
+breaking Windows behavior .*/
+ULONG
+__cdecl
+PAL_wcstoul(
+ const wchar_16 *nptr,
+ wchar_16 **endptr,
+ int base)
+{
+ char *s_nptr = 0;
+ char *s_endptr = 0;
+ unsigned long res;
+ int size;
+ DWORD dwLastError = 0;
+
+ PERF_ENTRY(wcstoul);
+ ENTRY("wcstoul (nptr=%p (%S), endptr=%p, base=%d)\n", nptr?nptr:W16_NULLSTRING, nptr?nptr:W16_NULLSTRING,
+ endptr, base);
+
+ size = WideCharToMultiByte(CP_ACP, 0, nptr, -1, NULL, 0, NULL, NULL);
+ if (!size)
+ {
+ dwLastError = GetLastError();
+ ASSERT("WideCharToMultiByte failed. Error is %d\n", dwLastError);
+ SetLastError(ERROR_INVALID_PARAMETER);
+ res = 0;
+ goto PAL_wcstoulExit;
+ }
+ s_nptr = (char *)PAL_malloc(size);
+ if (!s_nptr)
+ {
+ ERROR("PAL_malloc failed\n");
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ res = 0;
+ goto PAL_wcstoulExit;
+ }
+ size = WideCharToMultiByte(CP_ACP, 0, nptr, -1, s_nptr, size, NULL, NULL);
+ if (!size)
+ {
+ dwLastError = GetLastError();
+ ASSERT("WideCharToMultiByte failed. Error is %d\n", dwLastError);
+ SetLastError(ERROR_INVALID_PARAMETER);
+ res = 0;
+ goto PAL_wcstoulExit;
+ }
+
+ res = strtoul(s_nptr, &s_endptr, base);
+
+#ifdef BIT64
+ if (res > _UI32_MAX)
+ {
+ wchar_16 wc = *nptr;
+ while (PAL_iswspace(wc))
+ {
+ wc = *nptr++;
+ }
+ /* If the string represents a positive number that is greater than
+ _UI32_MAX, set errno to ERANGE. Otherwise, don't set errno
+ to match Windows behavior. */
+ if (wc != '-')
+ {
+ res = _UI32_MAX;
+ errno = ERANGE;
+ }
+ }
+#endif
+
+ /* only ASCII characters will be accepted by strtol, and those always get
+ mapped to single-byte characters, so the first rejected character will
+ have the same index in the multibyte and widechar strings */
+ if( endptr )
+ {
+ size = s_endptr - s_nptr;
+ *endptr = (wchar_16 *)&nptr[size];
+ }
+
+PAL_wcstoulExit:
+ PAL_free(s_nptr);
+ LOGEXIT("wcstoul returning unsigned long %lu\n", res);
+ PERF_EXIT(wcstoul);
+
+ /* When returning unsigned long res from this function, it will be
+ implicitly cast to ULONG. This handles situations where a string that
+ represents a negative number is passed in to wcstoul. The Windows
+ behavior is analogous to taking the binary equivalent of the negative
+ value and treating it as a positive number. Returning a ULONG from
+ this function, as opposed to native unsigned long, allows us to match
+ this behavior. The explicit case to ULONG below is used to silence any
+ potential warnings due to the implicit casting. */
+ return (ULONG)res;
+}
+
+ULONGLONG
+__cdecl
+PAL__wcstoui64(
+ const wchar_16 *nptr,
+ wchar_16 **endptr,
+ int base)
+{
+ char *s_nptr = 0;
+ char *s_endptr = 0;
+ unsigned long long res;
+ int size;
+ DWORD dwLastError = 0;
+
+ PERF_ENTRY(wcstoul);
+ ENTRY("_wcstoui64 (nptr=%p (%S), endptr=%p, base=%d)\n", nptr?nptr:W16_NULLSTRING, nptr?nptr:W16_NULLSTRING,
+ endptr, base);
+
+ size = WideCharToMultiByte(CP_ACP, 0, nptr, -1, NULL, 0, NULL, NULL);
+ if (!size)
+ {
+ dwLastError = GetLastError();
+ ASSERT("WideCharToMultiByte failed. Error is %d\n", dwLastError);
+ SetLastError(ERROR_INVALID_PARAMETER);
+ res = 0;
+ goto PAL__wcstoui64Exit;
+ }
+ s_nptr = (char *)PAL_malloc(size);
+ if (!s_nptr)
+ {
+ ERROR("PAL_malloc failed\n");
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ res = 0;
+ goto PAL__wcstoui64Exit;
+ }
+ size = WideCharToMultiByte(CP_ACP, 0, nptr, -1, s_nptr, size, NULL, NULL);
+ if (!size)
+ {
+ dwLastError = GetLastError();
+ ASSERT("WideCharToMultiByte failed. Error is %d\n", dwLastError);
+ SetLastError(ERROR_INVALID_PARAMETER);
+ res = 0;
+ goto PAL__wcstoui64Exit;
+ }
+
+ res = strtoull(s_nptr, &s_endptr, base);
+
+ /* only ASCII characters will be accepted by strtoull, and those always get
+ mapped to single-byte characters, so the first rejected character will
+ have the same index in the multibyte and widechar strings */
+ if( endptr )
+ {
+ size = s_endptr - s_nptr;
+ *endptr = (wchar_16 *)&nptr[size];
+ }
+
+PAL__wcstoui64Exit:
+ PAL_free(s_nptr);
+ LOGEXIT("_wcstoui64 returning unsigned long long %llu\n", res);
+ PERF_EXIT(_wcstoui64);
+
+ return res;
+}
+
+/*++
+Function:
+ PAL_towlower
+
+See MSDN
+
+--*/
+wchar_16
+__cdecl
+PAL_towlower( wchar_16 c )
+{
+#if HAVE_COREFOUNDATION
+ PERF_ENTRY(towlower);
+ ENTRY("towlower (c=%d)\n", c);
+ if (!PAL_iswlower(c))
+ {
+ CFMutableStringRef cfString = CFStringCreateMutable(
+ kCFAllocatorDefault, 1);
+ if (cfString != NULL)
+ {
+ CFStringAppendCharacters(cfString, (const UniChar*)&c, 1);
+ CFStringLowercase(cfString, NULL);
+ c = CFStringGetCharacterAtIndex(cfString, 0);
+ CFRelease(cfString);
+ }
+ }
+ LOGEXIT("towlower returns int %d\n", c );
+ PERF_EXIT(towlower);
+ return c;
+#else /* HAVE_COREFOUNDATION */
+ UnicodeDataRec dataRec;
+
+ PERF_ENTRY(towlower);
+ ENTRY("towlower (c=%d)\n", c);
+
+ if (!GetUnicodeData(c, &dataRec))
+ {
+ TRACE( "Unable to retrieve unicode data for the character %c.\n", c );
+ LOGEXIT("towlower returns int %d\n", c );
+ PERF_EXIT(towlower);
+ return c;
+ }
+
+ if ( (dataRec.C1_TYPE_FLAGS & C1_LOWER) || (dataRec.nOpposingCase == 0 ))
+ {
+ LOGEXIT("towlower returns int %d\n", c );
+ PERF_EXIT(towlower);
+ return c;
+ }
+ else
+ {
+ LOGEXIT("towlower returns int %d\n", dataRec.nOpposingCase );
+ PERF_EXIT(towlower);
+ return dataRec.nOpposingCase;
+ }
+#endif /* HAVE_COREFOUNDATION */
+}
+
+
+/*++
+Function:
+ PAL_towupper
+
+See MSDN
+
+--*/
+wchar_16
+__cdecl
+PAL_towupper( wchar_16 c )
+{
+#if HAVE_COREFOUNDATION
+ PERF_ENTRY(towupper);
+ ENTRY("towupper (c=%d)\n", c);
+ if (!PAL_iswupper(c))
+ {
+ CFMutableStringRef cfString = CFStringCreateMutable(
+ kCFAllocatorDefault, 1);
+ if (cfString != NULL)
+ {
+ CFStringAppendCharacters(cfString, (const UniChar*)&c, 1);
+ CFStringUppercase(cfString, NULL);
+ c = CFStringGetCharacterAtIndex(cfString, 0);
+ CFRelease(cfString);
+ }
+ }
+ LOGEXIT("towupper returns int %d\n", c );
+ PERF_EXIT(towupper);
+ return c;
+#else /* HAVE_COREFOUNDATION */
+ UnicodeDataRec dataRec;
+
+ PERF_ENTRY(towupper);
+ ENTRY("towupper (c=%d)\n", c);
+
+ if (!GetUnicodeData(c, &dataRec))
+ {
+ TRACE( "Unable to retrieve unicode data for the character %c.\n", c );
+ LOGEXIT("towupper returns int %d\n", c );
+ PERF_EXIT(towupper);
+ return c;
+ }
+
+ if ( (dataRec.C1_TYPE_FLAGS & C1_UPPER) || (dataRec.nOpposingCase == 0 ))
+ {
+ LOGEXIT("towupper returns int %d\n", c );
+ PERF_EXIT(towupper);
+ return c;
+ }
+ else
+ {
+ LOGEXIT("towupper returns int %d\n", dataRec.nOpposingCase );
+ PERF_EXIT(towupper);
+ return dataRec.nOpposingCase;
+ }
+#endif /* HAVE_COREFOUNDATION */
+}
+
+/*++
+Function:
+ PAL_iswupper
+
+See MSDN
+
+--*/
+int
+__cdecl
+PAL_iswupper( wchar_16 c )
+{
+ BOOL bRetVal = FALSE;
+#if HAVE_COREFOUNDATION
+ static CFCharacterSetRef sUppercaseSet;
+
+ if (sUppercaseSet == NULL)
+ {
+ sUppercaseSet = CFCharacterSetGetPredefined(
+ kCFCharacterSetUppercaseLetter);
+ }
+ PERF_ENTRY(iswupper);
+ ENTRY( "iswupper (c=%d)\n", c );
+ bRetVal = CFCharacterSetIsCharacterMember(sUppercaseSet, c);
+#else /* HAVE_COREFOUNDATION */
+ UnicodeDataRec dataRec;
+
+ PERF_ENTRY(iswupper);
+ ENTRY( "iswupper (c=%d)\n", c );
+
+ if (!GetUnicodeData(c, &dataRec))
+ {
+ TRACE( "Unable to retrieve unicode data for the character %c.\n", c );
+ goto exit;
+ }
+
+ if (dataRec.C1_TYPE_FLAGS & C1_UPPER)
+ {
+ bRetVal = TRUE;
+ }
+exit:
+#endif /* HAVE_COREFOUNDATION */
+ LOGEXIT( "iswupper returns %s.\n", bRetVal == TRUE ? "TRUE" : "FALSE" );
+ PERF_EXIT(iswupper);
+ return bRetVal;
+}
+
+/*++
+Function:
+ PAL_iswlower
+
+See MSDN
+
+--*/
+int
+__cdecl
+PAL_iswlower( wchar_16 c )
+{
+ BOOL bRetVal = FALSE;
+#if HAVE_COREFOUNDATION
+ static CFCharacterSetRef sLowercaseSet;
+
+ if (sLowercaseSet == NULL)
+ {
+ sLowercaseSet = CFCharacterSetGetPredefined(
+ kCFCharacterSetLowercaseLetter);
+ }
+ PERF_ENTRY(iswlower);
+ ENTRY("PAL_iswlower (c=%d)\n", c);
+ bRetVal = CFCharacterSetIsCharacterMember(sLowercaseSet, c);
+#else /* HAVE_COREFOUNDATION */
+ UnicodeDataRec dataRec;
+
+ PERF_ENTRY(iswlower);
+ ENTRY("PAL_iswlower (c=%d)\n", c);
+
+ if (!GetUnicodeData(c, &dataRec))
+ {
+ TRACE( "Unable to retrieve unicode data for the character %c.\n", c );
+ goto exit;
+ }
+
+ if (dataRec.C1_TYPE_FLAGS & C1_LOWER)
+ {
+ bRetVal = TRUE;
+ }
+exit:
+#endif /* HAVE_COREFOUNDATION */
+ LOGEXIT("PAL_iswlower returns %s.\n", bRetVal == TRUE ? "TRUE" : "FALSE");
+ PERF_EXIT(iswlower);
+ return bRetVal;
+}
+
+/*++
+Function:
+ PAL_iswalpha
+
+See MSDN
+
+--*/
+int
+__cdecl
+PAL_iswalpha( wchar_16 c )
+{
+ PERF_ENTRY(iswalpha);
+ ENTRY( "PAL_iswalpha (c=%d)\n", c);
+
+ if ( PAL_iswupper( c ) || PAL_iswlower( c ) )
+ {
+ LOGEXIT( "PAL_iswalpha returns 1.\n" );
+ PERF_EXIT(iswalpha);
+ return 1;
+ }
+
+ LOGEXIT( "PAL_iswalpha returns 0.\n" );
+ PERF_EXIT(iswalpha);
+ return 0;
+}
+
+
+/*++
+Function:
+ PAL_wcscat
+
+See MSDN or the man page for mcscat.
+
+--*/
+wchar_16 *
+__cdecl
+PAL_wcscat(
+ wchar_16 *strDestination,
+ const wchar_16 *strSource)
+{
+ wchar_16 *ret;
+ PERF_ENTRY(wcscat);
+ ENTRY("wcscat (strDestination=%p (%S), strSource=%p (%S))\n",
+ strDestination?strDestination:W16_NULLSTRING,
+ strDestination?strDestination:W16_NULLSTRING, strSource?strSource:W16_NULLSTRING, strSource?strSource:W16_NULLSTRING);
+
+ ret = PAL_wcsncat( strDestination, strSource, PAL_wcslen( strSource ) );
+
+ LOGEXIT("wcscat returnng wchar_t %p (%S)\n", ret, ret);
+ PERF_EXIT(wcscat);
+ return ret;
+}
+
+
+/*++
+Function:
+ PAL_wcscpy
+
+See MSDN or the man page for mcscpy.
+
+--*/
+wchar_16 *
+__cdecl
+PAL_wcscpy(
+ wchar_16 *strDestination,
+ const wchar_16 *strSource)
+{
+ wchar_16 *start = strDestination;
+
+ PERF_ENTRY(wcscpy);
+ ENTRY("wcscpy (strDestination=%p, strSource=%p (%S))\n",
+ strDestination, strSource ? strSource:W16_NULLSTRING, strSource ? strSource:W16_NULLSTRING);
+
+ if (strDestination == NULL)
+ {
+ ERROR("invalid strDestination argument\n");
+ LOGEXIT("wcscpy returning wchar_t NULL\n");
+ PERF_EXIT(wcscpy);
+ return NULL;
+ }
+
+ if (strSource == NULL)
+ {
+ ERROR("invalid strSource argument\n");
+ LOGEXIT("wcscpy returning wchar_t NULL\n");
+ PERF_EXIT(wcscpy);
+ return NULL;
+ }
+
+ /* copy source string to destination string */
+ while(*strSource)
+ {
+ *strDestination++ = *strSource++;
+ }
+
+ /* add terminating null */
+ *strDestination = '\0';
+
+ LOGEXIT("wcscpy returning wchar_t %p (%S)\n", start, start);
+ PERF_EXIT(wcscpy);
+ return start;
+}
+
+
+/*++
+Function:
+ PAL_wcslen
+
+See MSDN or the man page for wcslen.
+
+--*/
+size_t
+__cdecl
+PAL_wcslen(
+ const wchar_16 *string)
+{
+ size_t nChar = 0;
+
+ PERF_ENTRY(wcslen);
+ ENTRY("wcslen (string=%p (%S))\n", string?string:W16_NULLSTRING, string?string:W16_NULLSTRING);
+
+ if ( !string )
+ {
+ LOGEXIT("wcslen returning size_t %u\n", 0);
+ PERF_EXIT(wcslen);
+ return 0;
+ }
+ while (*string++)
+ {
+ nChar++;
+ }
+
+ LOGEXIT("wcslen returning size_t %u\n", nChar);
+ PERF_EXIT(wcslen);
+ return nChar;
+}
+
+
+/*++
+Function:
+ PAL_wcsncmp
+
+See MSDN or the man page for wcsncmp.
+--*/
+int
+__cdecl
+PAL_wcsncmp(
+ const wchar_16 *string1,
+ const wchar_16 *string2,
+ size_t count)
+{
+ size_t i;
+ int diff = 0;
+
+ PERF_ENTRY(wcsncmp);
+ ENTRY("wcsncmp (string1=%p (%S), string2=%p (%S) count=%lu)\n",
+ string1?string1:W16_NULLSTRING,
+ string1?string1:W16_NULLSTRING, string2?string2:W16_NULLSTRING, string2?string2:W16_NULLSTRING,
+ (unsigned long) count);
+
+ for (i = 0; i < count; i++)
+ {
+ diff = string1[i] - string2[i];
+ if (diff != 0)
+ {
+ break;
+ }
+
+ /* stop if we reach the end of the string */
+ if(string1[i]==0)
+ {
+ break;
+ }
+ }
+ LOGEXIT("wcsncmp returning int %d\n", diff);
+ PERF_EXIT(wcsncmp);
+ return diff;
+}
+
+/*++
+Function:
+ PAL_wcscmp
+
+See MSDN or the man page for wcscmp.
+--*/
+int
+__cdecl
+PAL_wcscmp(
+ const wchar_16 *string1,
+ const wchar_16 *string2)
+{
+ int ret;
+
+ PERF_ENTRY(wcscmp);
+ ENTRY("wcscmp (string1=%p (%S), string2=%p (%S))\n",
+ string1?string1:W16_NULLSTRING,
+ string1?string1:W16_NULLSTRING, string2?string2:W16_NULLSTRING, string2?string2:W16_NULLSTRING);
+
+ ret = PAL_wcsncmp(string1, string2, 0x7fffffff);
+
+ LOGEXIT("wcscmp returns int %d\n", ret);
+ PERF_EXIT(wcscmp);
+ return ret;
+}
+
+/*++
+Function:
+ PAL_wcschr
+
+See MSDN or man page for wcschr.
+
+--*/
+wchar_16 _WConst_return *
+__cdecl
+PAL_wcschr(
+ const wchar_16 * string,
+ wchar_16 c)
+{
+ PERF_ENTRY(wcschr);
+ ENTRY("wcschr (string=%p (%S), c=%C)\n", string?string:W16_NULLSTRING, string?string:W16_NULLSTRING, c);
+
+ while (*string)
+ {
+ if (*string == c)
+ {
+ LOGEXIT("wcschr returning wchar_t %p (%S)\n", string?string:W16_NULLSTRING, string?string:W16_NULLSTRING);
+ PERF_EXIT(wcschr);
+ return (wchar_16 *) string;
+ }
+ string++;
+ }
+
+ // Check if the comparand was \000
+ if (*string == c)
+ return (wchar_16 *) string;
+
+ LOGEXIT("wcschr returning wchar_t NULL\n");
+ PERF_EXIT(wcschr);
+ return NULL;
+}
+
+
+/*++
+Function:
+ PAL_wcsrchr
+
+See MSDN or man page for wcsrchr.
+
+--*/
+wchar_16 _WConst_return *
+__cdecl
+PAL_wcsrchr(
+ const wchar_16 * string,
+ wchar_16 c)
+{
+ wchar_16 *last = NULL;
+
+ PERF_ENTRY(wcsrchr);
+ ENTRY("wcsrchr (string=%p (%S), c=%C)\n", string?string:W16_NULLSTRING, string?string:W16_NULLSTRING, c);
+
+ while (*string)
+ {
+ if (*string == c)
+ {
+ last = (wchar_16 *) string;
+ }
+ string++;
+ }
+
+ LOGEXIT("wcsrchr returning wchar_t %p (%S)\n", last?last:W16_NULLSTRING, last?last:W16_NULLSTRING);
+ PERF_EXIT(wcsrchr);
+ return (wchar_16 *)last;
+}
+
+
+/*++
+Function:
+ PAL_wcsspn
+
+See MSDN or man page for wcspbrk.
+--*/
+size_t
+__cdecl
+PAL_wcsspn (const wchar_16 *string, const wchar_16 *stringCharSet)
+{
+ ASSERT(0);
+ return 0;
+}
+
+
+/*++
+Function:
+ PAL_wcspbrk
+
+See MSDN or man page for wcspbrk.
+--*/
+const wchar_16 *
+__cdecl
+PAL_wcspbrk(
+ const wchar_16 *string,
+ const wchar_16 *strCharSet)
+{
+ PERF_ENTRY(wcspbrk);
+ ENTRY("wcspbrk (string=%p (%S), strCharSet=%p (%S))\n",
+ string?string:W16_NULLSTRING,
+ string?string:W16_NULLSTRING, strCharSet?strCharSet:W16_NULLSTRING, strCharSet?strCharSet:W16_NULLSTRING);
+
+ while (*string)
+ {
+ if (PAL_wcschr(strCharSet, *string) != NULL)
+ {
+ LOGEXIT("wcspbrk returning wchar_t %p (%S)\n", string?string:W16_NULLSTRING, string?string:W16_NULLSTRING);
+ PERF_EXIT(wcspbrk);
+ return (wchar_16 *) string;
+ }
+
+ string++;
+ }
+
+ LOGEXIT("wcspbrk returning wchar_t NULL\n");
+ PERF_EXIT(wcspbrk);
+ return NULL;
+}
+
+
+/*++
+Function:
+ PAL_wcsstr
+
+See MSDN or man page for wcsstr.
+--*/
+const wchar_16 *
+__cdecl
+PAL_wcsstr(
+ const wchar_16 *string,
+ const wchar_16 *strCharSet)
+{
+ wchar_16 *ret = NULL;
+ int i;
+
+ PERF_ENTRY(wcsstr);
+ ENTRY("wcsstr (string=%p (%S), strCharSet=%p (%S))\n",
+ string?string:W16_NULLSTRING,
+ string?string:W16_NULLSTRING, strCharSet?strCharSet:W16_NULLSTRING, strCharSet?strCharSet:W16_NULLSTRING);
+
+ if (string == NULL)
+ {
+ ret = NULL;
+ goto leave;
+ }
+
+ if (strCharSet == NULL)
+ {
+ ret = NULL;
+ goto leave;
+ }
+
+ if (*strCharSet == 0)
+ {
+ ret = (wchar_16 *)string;
+ goto leave;
+ }
+
+ while (*string != 0)
+ {
+ i = 0;
+ while (1)
+ {
+ if (*(string + i) == 0 || *(strCharSet + i) == 0)
+ {
+ ret = (wchar_16 *) string;
+ goto leave;
+ }
+ if (*(string + i) != *(strCharSet + i))
+ {
+ break;
+ }
+ i++;
+ }
+ string++;
+ }
+
+ leave:
+ LOGEXIT("wcsstr returning wchar_t %p (%S)\n", ret?ret:W16_NULLSTRING, ret?ret:W16_NULLSTRING);
+ PERF_EXIT(wcsstr);
+ return ret;
+}
+
+/*++
+Function :
+
+ PAL_wcsncpy
+
+see msdn doc.
+--*/
+wchar_16 *
+__cdecl
+PAL_wcsncpy( wchar_16 * strDest, const wchar_16 *strSource, size_t count )
+{
+ UINT length = sizeof( wchar_16 ) * count;
+ PERF_ENTRY(wcsncpy);
+ ENTRY("wcsncpy( strDest:%p, strSource:%p (%S), count:%lu)\n",
+ strDest, strSource, strSource, (unsigned long) count);
+
+ memset( strDest, 0, length );
+ length = min( count, PAL_wcslen( strSource ) ) * sizeof( wchar_16 );
+ memcpy( strDest, strSource, length );
+
+ LOGEXIT("wcsncpy returning (wchar_16*): %p\n", strDest);
+ PERF_EXIT(wcsncpy);
+ return strDest;
+}
+
+/*++
+Function :
+
+ wcsncat
+
+see msdn doc.
+--*/
+wchar_16 *
+__cdecl
+PAL_wcsncat( wchar_16 * strDest, const wchar_16 *strSource, size_t count )
+{
+ wchar_16 *start = strDest;
+ UINT LoopCount = 0;
+ UINT StrSourceLength = 0;
+
+ PERF_ENTRY(wcsncat);
+ ENTRY( "wcsncat (strDestination=%p (%S), strSource=%p (%S), count=%lu )\n",
+ strDest ? strDest : W16_NULLSTRING,
+ strDest ? strDest : W16_NULLSTRING,
+ strSource ? strSource : W16_NULLSTRING,
+ strSource ? strSource : W16_NULLSTRING, (unsigned long) count);
+
+ if ( strDest == NULL )
+ {
+ ERROR("invalid strDest argument\n");
+ LOGEXIT("wcsncat returning wchar_t NULL\n");
+ PERF_EXIT(wcsncat);
+ return NULL;
+ }
+
+ if ( strSource == NULL )
+ {
+ ERROR("invalid strSource argument\n");
+ LOGEXIT("wcsncat returning wchar_t NULL\n");
+ PERF_EXIT(wcsncat);
+ return NULL;
+ }
+
+ /* find end of source string */
+ while ( *strDest )
+ {
+ strDest++;
+ }
+
+ StrSourceLength = PAL_wcslen( strSource );
+ if ( StrSourceLength < count )
+ {
+ count = StrSourceLength;
+ }
+
+ /* concatenate new string */
+ while( *strSource && LoopCount < count )
+ {
+ *strDest++ = *strSource++;
+ LoopCount++;
+ }
+
+ /* add terminating null */
+ *strDest = '\0';
+
+ LOGEXIT("wcsncat returning wchar_t %p (%S)\n", start, start);
+ PERF_EXIT(wcsncat);
+ return start;
+}
+
+static BOOL MISC_CRT_WCSTOD_IsValidCharacter( WCHAR c )
+{
+ if ( c == '+' || c == '-' || c == '.' || ( c >= '0' && c <= '9' ) ||
+ c == 'e' || c == 'E' || c == 'd' || c == 'D' )
+ {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*++
+Function :
+
+ wcstod
+
+ There is a slight difference between the Windows version of wcstod
+ and the BSD versio of wcstod.
+
+ Under Windows the string " -1b " returns -1.000000 stop char = 'b'
+ Under BSD the same string returns 0.000000 stop ' '
+
+see msdn doc.
+--*/
+double
+__cdecl
+PAL_wcstod( const wchar_16 * nptr, wchar_16 **endptr )
+{
+ double RetVal = 0.0;
+ LPSTR lpStringRep = NULL;
+ LPWSTR lpStartOfExpression = (LPWSTR)nptr;
+ LPWSTR lpEndOfExpression = NULL;
+ UINT Length = 0;
+
+ PERF_ENTRY(wcstod);
+ ENTRY( "wcstod( %p (%S), %p (%S) )\n", nptr, nptr, endptr , endptr );
+
+ if ( !nptr )
+ {
+ ERROR( "nptr is invalid.\n" );
+ LOGEXIT( "wcstod returning 0.0\n" );
+ PERF_EXIT(wcstod);
+ return 0.0;
+ }
+
+ /* Eat white space. */
+ while ( PAL_iswspace( *lpStartOfExpression ) )
+ {
+ lpStartOfExpression++;
+ }
+
+ /* Get the end of the expression. */
+ lpEndOfExpression = lpStartOfExpression;
+ while ( *lpEndOfExpression )
+ {
+ if ( !MISC_CRT_WCSTOD_IsValidCharacter( *lpEndOfExpression ) )
+ {
+ break;
+ }
+ lpEndOfExpression++;
+ }
+
+ if ( lpEndOfExpression != lpStartOfExpression )
+ {
+ Length = lpEndOfExpression - lpStartOfExpression;
+ lpStringRep = (LPSTR)PAL_malloc( Length + 1);
+
+ if ( lpStringRep )
+ {
+ if ( WideCharToMultiByte( CP_ACP, 0, lpStartOfExpression, Length,
+ lpStringRep, Length + 1 ,
+ NULL, 0 ) != 0 )
+ {
+ LPSTR ScanStop = NULL;
+ lpStringRep[Length]= 0;
+ RetVal = strtod( lpStringRep, &ScanStop );
+
+ /* See if strtod failed. */
+ if ( RetVal == 0.0 && ScanStop == lpStringRep )
+ {
+ ASSERT( "An error occurred in the conversion.\n" );
+ lpEndOfExpression = (LPWSTR)nptr;
+ }
+ }
+ else
+ {
+ ASSERT( "Wide char to multibyte conversion failed.\n" );
+ lpEndOfExpression = (LPWSTR)nptr;
+ }
+ }
+ else
+ {
+ ERROR( "Not enough memory.\n" );
+ lpEndOfExpression = (LPWSTR)nptr;
+ }
+ }
+ else
+ {
+ ERROR( "Malformed expression.\n" );
+ lpEndOfExpression = (LPWSTR)nptr;
+ }
+
+ /* Set the stop scan character. */
+ if ( endptr != NULL )
+ {
+ *endptr = lpEndOfExpression;
+ }
+
+ PAL_free( lpStringRep );
+ LOGEXIT( "wcstod returning %f.\n", RetVal );
+ PERF_EXIT(wcstod);
+ return RetVal;
+}
+
+/*++
+Function :
+
+ _ui64tow
+
+See MSDN for more details.
+--*/
+wchar_16 *
+__cdecl
+_ui64tow( unsigned __int64 value , wchar_16 * string , int radix )
+{
+ UINT ReversedIndex = 0;
+ WCHAR ReversedString[ 65 ];
+ LPWSTR lpString = string;
+ UINT Index = 0;
+
+ PERF_ENTRY(_ui64tow);
+ ENTRY( "_ui64tow( value=%I64d, string=%p (%S), radix=%d )\n",
+ value, string, string, radix );
+
+ if ( !string )
+ {
+ ERROR( "string has to be a valid pointer.\n" );
+ LOGEXIT( "_ui64tow returning NULL.\n" );
+ PERF_EXIT(_ui64tow);
+ return NULL;
+ }
+ if ( radix < 2 || radix > 36 )
+ {
+ ERROR( "radix has to be between 2 and 36.\n" );
+ LOGEXIT( "_ui64tow returning NULL.\n" );
+ PERF_EXIT(_ui64tow);
+ return NULL;
+ }
+
+ if(0 == value)
+ {
+ ReversedString[0] = '0';
+ Index++;
+ }
+ else while ( value )
+ {
+ int temp = value % radix;
+ value /= radix;
+
+ if ( temp < 10 )
+ {
+ ReversedString[ Index ] = temp + '0';
+ Index++;
+ }
+ else
+ {
+ ReversedString[ Index ] = temp - 10 + 'a';
+ Index++;
+ }
+ }
+
+ /* Reverse the string. */
+ ReversedIndex = Index;
+ for ( Index = 0; ReversedIndex > 0; ReversedIndex--, Index++ )
+ {
+ string[ Index ] = ReversedString[ ReversedIndex - 1 ];
+ }
+
+ string[ Index ] = '\0';
+ LOGEXIT( "_ui64tow returning %p (%S).\n", lpString , lpString );
+ PERF_EXIT(_ui64tow);
+ return lpString;
+}
+
+
+/*++
+Function:
+
+ iswdigit
+
+See MSDN for more details.
+--*/
+int
+__cdecl
+PAL_iswdigit( wchar_16 c )
+{
+ UINT nRetVal = 0;
+#if HAVE_COREFOUNDATION
+ static CFCharacterSetRef sDigitSet;
+
+ if (sDigitSet == NULL)
+ {
+ sDigitSet = CFCharacterSetGetPredefined(
+ kCFCharacterSetDecimalDigit);
+ }
+ PERF_ENTRY(iswdigit);
+ ENTRY("PAL_iswdigit (c=%d)\n", c);
+ nRetVal = CFCharacterSetIsCharacterMember(sDigitSet, c);
+#else /* HAVE_COREFOUNDATION */
+ UnicodeDataRec dataRec;
+
+ PERF_ENTRY(iswdigit);
+ ENTRY("PAL_iswdigit (c=%d)\n", c);
+
+ if (GetUnicodeData(c, &dataRec))
+ {
+ if (dataRec.C1_TYPE_FLAGS & C1_DIGIT)
+ {
+ nRetVal = 1;
+ }
+ else
+ {
+ nRetVal = 0;
+ }
+ }
+ else
+ {
+ TRACE( "No corresonding unicode record for character %d.\n", c );
+ }
+#endif /* HAVE_COREFOUNDATION */
+ LOGEXIT("PAL_iswdigit returning %d\n", nRetVal);
+ PERF_EXIT(iswdigit);
+ return nRetVal;
+}
+
+/*++
+Function:
+
+ iswxdigit
+
+See MSDN for more details.
+
+Notes :
+the information in UnicodeData doesn't help us, it doesn't have enough
+granularity. Results in windows show that only ASCII and "Fullwidth" (>0xFF10)
+numbers and letters are considered as "hex"; other "numbers"
+(nGeneralCategory==8) aren't.
+--*/
+int
+__cdecl
+PAL_iswxdigit( wchar_16 c )
+{
+ UINT nRetVal = 0;
+
+ PERF_ENTRY(iswxdigit);
+ ENTRY("PAL_iswxdigit( c=%d )\n", c);
+
+ /* ASCII characters */
+ if((c>= 'A' && c<='F') || /* uppercase hex letters */
+ (c>= 'a' && c<='f') || /* lowercase hex letters */
+ (c>= '0' && c<='9')) /* digits */
+ {
+ nRetVal = 1;
+ }
+ else
+ /* "fullwidth" characters, whatever that is */
+ if((c>= 0xFF10 && c<=0xFF19) || /* digits */
+ (c>= 0xFF21 && c<=0xFF26) || /* uppercase hex letters */
+ (c>= 0xFF41 && c<=0xFF46)) /* lowercase hex letters */
+ {
+ nRetVal = 1;
+ }
+ else
+ {
+ nRetVal = 0;
+ }
+ LOGEXIT("PAL_iswxdigit returning %d\n", nRetVal);
+ PERF_EXIT(iswxdigit);
+ return nRetVal;
+}
+
+
+/*++
+Function:
+
+ iswprint
+
+See MSDN for more details.
+--*/
+int
+__cdecl
+PAL_iswprint( wchar_16 c )
+{
+ int ret;
+
+
+ PERF_ENTRY(iswprint);
+ ENTRY("PAL_iswprint (%#X)\n", c);
+
+ ret = iswprint(c);
+
+ LOGEXIT("PAL_iswprint returns %d\n", ret);
+ PERF_EXIT(iswprint);
+ return (ret);
+}
+
+
+/*++
+Function:
+ PAL_wcscspn
+
+Finds the number of consecutive characters from the start of the string
+that are not in the set.
+
+Return value:
+
+The number of characters from the start of the string that are not in
+the set.
+
+Parameters:
+string String
+strCharSet Set of delimiter characters
+
+--*/
+size_t
+__cdecl
+PAL_wcscspn(const wchar_16 *string, const wchar_16 *strCharSet)
+{
+ const wchar_16 *temp;
+ size_t count = 0;
+
+ PERF_ENTRY(wcscspn);
+
+ while(*string != 0)
+ {
+ for(temp = strCharSet; *temp != 0; temp++)
+ {
+ if (*string == *temp)
+ {
+ PERF_EXIT(wcscspn);
+ return count;
+ }
+ }
+ count++;
+ string++;
+ }
+ PERF_EXIT(wcscspn);
+ return count;
+}
+
+#if HAVE_COREFOUNDATION
+/*--
+Function:
+ PAL_iswblank
+
+Returns TRUE if c is a Win32 "blank" character.
+--*/
+int
+__cdecl
+PAL_iswblank(wchar_16 c)
+{
+ int ret;
+ static CFCharacterSetRef sSpaceAndNewlineSet;
+
+ if (sSpaceAndNewlineSet == NULL)
+ {
+ sSpaceAndNewlineSet = CFCharacterSetGetPredefined(
+ kCFCharacterSetWhitespaceAndNewline);
+ }
+ switch (c)
+ {
+ case 0x0085:
+ case 0x1680:
+ case 0x202f:
+ case 0xfeff:
+ // These are blank characters on Windows, but are not part
+ // of the SpaceAndNewline character set in Core Foundation.
+ ret = TRUE;
+ break;
+ case 0x2028:
+ case 0x2029:
+ // These are not blank characters on Windows, but are part
+ // of the SpaceAndNewline character set in Core Foundation.
+ ret = FALSE;
+ break;
+ default:
+ ret = CFCharacterSetIsCharacterMember(sSpaceAndNewlineSet, c);
+ break;
+ }
+ return ret;
+}
+
+/*--
+Function:
+ PAL_iswcntrl
+
+Returns TRUE if c is a control character.
+--*/
+int
+__cdecl
+PAL_iswcntrl(wchar_16 c)
+{
+ int ret;
+ static CFCharacterSetRef sControlSet;
+
+ if (sControlSet == NULL)
+ {
+ sControlSet = CFCharacterSetGetPredefined(kCFCharacterSetControl);
+ }
+ ret = CFCharacterSetIsCharacterMember(sControlSet, c);
+ return ret;
+}
+
+/*--
+Function:
+ PAL_iswpunct
+
+Returns TRUE if c is a punctuation character.
+--*/
+int
+__cdecl
+PAL_iswpunct(wchar_16 c)
+{
+ int ret;
+ static CFCharacterSetRef sPunctuationSet = NULL;
+ static CFCharacterSetRef sSymbolSet = NULL;
+
+ if (sPunctuationSet == NULL)
+ {
+ sPunctuationSet = CFCharacterSetGetPredefined(kCFCharacterSetPunctuation);
+ }
+ if (sSymbolSet == NULL)
+ {
+ sSymbolSet = CFCharacterSetGetPredefined(kCFCharacterSetSymbol);
+ }
+ ret = CFCharacterSetIsCharacterMember(sPunctuationSet, c) ||
+ CFCharacterSetIsCharacterMember(sSymbolSet, c);
+ return ret;
+}
+#endif // HAVE_COREFOUNDATION
diff --git a/src/pal/src/cruntime/wchartls.cpp b/src/pal/src/cruntime/wchartls.cpp
new file mode 100644
index 0000000000..5350f0551b
--- /dev/null
+++ b/src/pal/src/cruntime/wchartls.cpp
@@ -0,0 +1,127 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ wchartls.c
+
+Abstract:
+
+ Implementation of wide char string functions that depend on per-thread data
+
+
+
+--*/
+
+#include "pal/palinternal.h"
+#include "pal/thread.hpp"
+#include "pal/dbgmsg.h"
+#include "pal/unicode_data.h"
+
+using namespace CorUnix;
+
+
+SET_DEFAULT_DEBUG_CHANNEL(CRT);
+
+/*++
+Function:
+ PAL_wcstok
+
+Finds the next token in a wide character string.
+
+Return value:
+
+A pointer to the next token found in strToken. Returns NULL when no more
+tokens are found. Each call modifies strToken by substituting a NULL
+character for each delimiter that is encountered.
+
+Parameters:
+strToken String containing token(s)
+strDelimit Set of delimiter characters
+
+--*/
+WCHAR *
+__cdecl
+PAL_wcstok(WCHAR *strToken, const WCHAR *strDelimit)
+{
+ CPalThread *pThread = NULL;
+ WCHAR *retval = NULL;
+ WCHAR *delim_ptr;
+ WCHAR *next_context; /* string to save in TLS for future calls */
+
+ PERF_ENTRY(wcstok);
+ ENTRY("PAL_wcstok (strToken=%p (%S), strDelimit=%p (%S))\n",
+ strToken?strToken:W16_NULLSTRING,
+ strToken?strToken:W16_NULLSTRING,
+ strDelimit?strDelimit:W16_NULLSTRING,
+ strDelimit?strDelimit:W16_NULLSTRING);
+
+ /* Get the per-thread buffer from the thread structure. */
+ pThread = InternalGetCurrentThread();
+
+ if(NULL == strDelimit)
+ {
+ ERROR("delimiter string is NULL\n");
+ goto done;
+ }
+
+ /* get token string from TLS if none is provided */
+ if(NULL == strToken)
+ {
+ TRACE("wcstok() called with NULL string, using previous string\n");
+ strToken = pThread->crtInfo.wcstokContext;
+ if(NULL == strToken)
+ {
+ ERROR("wcstok called with NULL string without a previous call\n");
+ goto done;
+ }
+ }
+
+ /* first, skip all leading delimiters */
+ while ((*strToken != '\0') && (PAL_wcschr(strDelimit,*strToken)))
+ {
+ strToken++;
+ }
+
+ /* if there were only delimiters, there's no string */
+ if('\0' == strToken[0])
+ {
+ TRACE("end of string already reached, returning NULL\n");
+ goto done;
+ }
+
+ /* we're now at the beginning of the token; look for the first delimiter */
+ delim_ptr = PAL_wcspbrk(strToken,strDelimit);
+ if(NULL == delim_ptr)
+ {
+ TRACE("no delimiters found, this is the last token\n");
+ /* place the next context at the end of the string, so that subsequent
+ calls will return NULL */
+ next_context = strToken+PAL_wcslen(strToken);
+ retval = strToken;
+ }
+ else
+ {
+ /* null-terminate current token */
+ *delim_ptr=0;
+
+ /* place the next context right after the delimiter */
+ next_context = delim_ptr+1;
+ retval = strToken;
+
+ TRACE("found delimiter; next token will be %p\n",next_context);
+ }
+
+ pThread->crtInfo.wcstokContext = next_context;
+
+done:
+ LOGEXIT("PAL_wcstok() returns %p (%S)\n", retval?retval:W16_NULLSTRING, retval?retval:W16_NULLSTRING);
+ PERF_EXIT(wcstok);
+ return(retval);
+}
+
diff --git a/src/pal/src/debug/debug.cpp b/src/pal/src/debug/debug.cpp
new file mode 100644
index 0000000000..5461ac6265
--- /dev/null
+++ b/src/pal/src/debug/debug.cpp
@@ -0,0 +1,1844 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ debug.c
+
+Abstract:
+
+ Implementation of Win32 debugging API functions.
+
+Revision History:
+
+
+
+--*/
+
+#ifndef BIT64
+#undef _LARGEFILE64_SOURCE
+#undef _FILE_OFFSET_BITS
+#endif
+
+#include "pal/dbgmsg.h"
+SET_DEFAULT_DEBUG_CHANNEL(DEBUG); // some headers have code with asserts, so do this first
+
+#include "pal/thread.hpp"
+#include "pal/procobj.hpp"
+#include "pal/file.hpp"
+
+#include "pal/palinternal.h"
+#include "pal/process.h"
+#include "pal/context.h"
+#include "pal/debug.h"
+#include "pal/environ.h"
+#include "pal/malloc.hpp"
+#include "pal/module.h"
+#include "pal/stackstring.hpp"
+#include "pal/virtual.h"
+
+#include <signal.h>
+#include <unistd.h>
+#if HAVE_PROCFS_CTL
+#include <unistd.h>
+#elif HAVE_TTRACE // HAVE_PROCFS_CTL
+#include <sys/ttrace.h>
+#else // HAVE_TTRACE
+#include <sys/ptrace.h>
+#endif // HAVE_PROCFS_CTL
+#if HAVE_VM_READ
+#include <mach/mach.h>
+#endif // HAVE_VM_READ
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#if HAVE_PROCFS_H
+#include <procfs.h>
+#endif // HAVE_PROCFS_H
+
+#if HAVE_MACH_EXCEPTIONS
+#include "../exception/machexception.h"
+#endif // HAVE_MACH_EXCEPTIONS
+
+using namespace CorUnix;
+
+extern "C" void DBG_DebugBreak_End();
+
+#if HAVE_PROCFS_CTL
+#define CTL_ATTACH "attach"
+#define CTL_DETACH "detach"
+#define CTL_WAIT "wait"
+#endif // HAVE_PROCFS_CTL
+
+/* ------------------- Constant definitions ----------------------------------*/
+
+#if !HAVE_VM_READ && !HAVE_PROCFS_CTL
+const BOOL DBG_ATTACH = TRUE;
+const BOOL DBG_DETACH = FALSE;
+#endif
+static const char PAL_OUTPUTDEBUGSTRING[] = "PAL_OUTPUTDEBUGSTRING";
+
+#ifdef _DEBUG
+#define ENABLE_RUN_ON_DEBUG_BREAK 1
+#endif // _DEBUG
+
+#ifdef ENABLE_RUN_ON_DEBUG_BREAK
+static const char PAL_RUN_ON_DEBUG_BREAK[] = "PAL_RUN_ON_DEBUG_BREAK";
+#endif // ENABLE_RUN_ON_DEBUG_BREAK
+
+/* ------------------- Static function prototypes ----------------------------*/
+
+#if !HAVE_VM_READ && !HAVE_PROCFS_CTL && !HAVE_TTRACE
+static int
+DBGWriteProcMem_Int(DWORD processId, int *addr, int data);
+static int
+DBGWriteProcMem_IntWithMask(DWORD processId, int *addr, int data,
+ unsigned int mask);
+#endif // !HAVE_VM_READ && !HAVE_PROCFS_CTL && !HAVE_TTRACE
+
+#if !HAVE_VM_READ && !HAVE_PROCFS_CTL
+
+static BOOL
+DBGAttachProcess(CPalThread *pThread, HANDLE hProcess, DWORD dwProcessId);
+
+static BOOL
+DBGDetachProcess(CPalThread *pThread, HANDLE hProcess, DWORD dwProcessId);
+
+static int
+DBGSetProcessAttached(CPalThread *pThread, HANDLE hProcess, BOOL bAttach);
+
+#endif // !HAVE_VM_READ && !HAVE_PROCFS_CTL
+
+extern "C" {
+
+/*++
+Function:
+ FlushInstructionCache
+
+The FlushInstructionCache function flushes the instruction cache for
+the specified process.
+
+Remarks
+
+This is a no-op for x86 architectures where the instruction and data
+caches are coherent in hardware. For non-X86 architectures, this call
+usually maps to a kernel API to flush the D-caches on all processors.
+
+--*/
+BOOL
+PALAPI
+FlushInstructionCache(
+ IN HANDLE hProcess,
+ IN LPCVOID lpBaseAddress,
+ IN SIZE_T dwSize)
+{
+ BOOL Ret;
+
+ PERF_ENTRY(FlushInstructionCache);
+ ENTRY("FlushInstructionCache (hProcess=%p, lpBaseAddress=%p dwSize=%d)\
+ \n", hProcess, lpBaseAddress, dwSize);
+
+ if (lpBaseAddress != NULL)
+ {
+ Ret = DBG_FlushInstructionCache(lpBaseAddress, dwSize);
+ }
+ else
+ {
+ Ret = TRUE;
+ }
+
+ LOGEXIT("FlushInstructionCache returns BOOL %d\n", Ret);
+ PERF_EXIT(FlushInstructionCache);
+ return Ret;
+}
+
+
+/*++
+Function:
+ OutputDebugStringA
+
+See MSDN doc.
+--*/
+VOID
+PALAPI
+OutputDebugStringA(
+ IN LPCSTR lpOutputString)
+{
+ PERF_ENTRY(OutputDebugStringA);
+ ENTRY("OutputDebugStringA (lpOutputString=%p (%s))\n",
+ lpOutputString ? lpOutputString : "NULL",
+ lpOutputString ? lpOutputString : "NULL");
+
+ // As we don't support debug events, we are going to output the debug string
+ // to stderr instead of generating OUT_DEBUG_STRING_EVENT. It's safe to tell
+ // EnvironGetenv not to make a copy of the value here since we only want to
+ // check whether it exists, not actually use it.
+ if ((lpOutputString != NULL) &&
+ (NULL != EnvironGetenv(PAL_OUTPUTDEBUGSTRING, /* copyValue */ FALSE)))
+ {
+ fprintf(stderr, "%s", lpOutputString);
+ }
+
+ LOGEXIT("OutputDebugStringA returns\n");
+ PERF_EXIT(OutputDebugStringA);
+}
+
+/*++
+Function:
+ OutputDebugStringW
+
+See MSDN doc.
+--*/
+VOID
+PALAPI
+OutputDebugStringW(
+ IN LPCWSTR lpOutputString)
+{
+ CHAR *lpOutputStringA;
+ int strLen;
+
+ PERF_ENTRY(OutputDebugStringW);
+ ENTRY("OutputDebugStringW (lpOutputString=%p (%S))\n",
+ lpOutputString ? lpOutputString: W16_NULLSTRING,
+ lpOutputString ? lpOutputString: W16_NULLSTRING);
+
+ if (lpOutputString == NULL)
+ {
+ OutputDebugStringA("");
+ goto EXIT;
+ }
+
+ if ((strLen = WideCharToMultiByte(CP_ACP, 0, lpOutputString, -1, NULL, 0,
+ NULL, NULL))
+ == 0)
+ {
+ ASSERT("failed to get wide chars length\n");
+ SetLastError(ERROR_INTERNAL_ERROR);
+ goto EXIT;
+ }
+
+ /* strLen includes the null terminator */
+ if ((lpOutputStringA = (LPSTR) InternalMalloc((strLen * sizeof(CHAR)))) == NULL)
+ {
+ ERROR("Insufficient memory available !\n");
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ goto EXIT;
+ }
+
+ if(! WideCharToMultiByte(CP_ACP, 0, lpOutputString, -1,
+ lpOutputStringA, strLen, NULL, NULL))
+ {
+ ASSERT("failed to convert wide chars to multibytes\n");
+ SetLastError(ERROR_INTERNAL_ERROR);
+ free(lpOutputStringA);
+ goto EXIT;
+ }
+
+ OutputDebugStringA(lpOutputStringA);
+ free(lpOutputStringA);
+
+EXIT:
+ LOGEXIT("OutputDebugStringW returns\n");
+ PERF_EXIT(OutputDebugStringW);
+}
+
+#ifdef ENABLE_RUN_ON_DEBUG_BREAK
+/*
+ When DebugBreak() is called, if PAL_RUN_ON_DEBUG_BREAK is set,
+ DebugBreak() will execute whatever command is in there.
+
+ PAL_RUN_ON_DEBUG_BREAK must be no longer than 255 characters.
+
+ This command string inherits the current process's environment,
+ with two additions:
+ PAL_EXE_PID - the process ID of the current process
+ PAL_EXE_NAME - the name of the executable of the current process
+
+ When DebugBreak() runs this string, it periodically polls the child process
+ and blocks until it finishes. If you use this mechanism to start a
+ debugger, you can break this poll loop by setting the "spin" variable in
+ run_debug_command()'s frame to 0, and then the parent process can
+ continue.
+
+ suggested values for PAL_RUN_ON_DEBUG_BREAK:
+ to halt the process for later inspection:
+ 'echo stopping $PAL_EXE_PID; kill -STOP $PAL_EXE_PID; sleep 10'
+
+ to print out the stack trace:
+ 'pstack $PAL_EXE_PID'
+
+ to invoke the gdb debugger on the process:
+ 'set -x; gdb $PAL_EXE_NAME $PAL_EXE_PID'
+
+ to invoke the ddd debugger on the process (requires X11):
+ 'set -x; ddd $PAL_EXE_NAME $PAL_EXE_PID'
+*/
+
+static
+int
+run_debug_command (const char *command)
+{
+ int pid;
+ Volatile<int> spin = 1;
+
+ if (!command) {
+ return 1;
+ }
+
+ printf("Spawning command: %s\n", command);
+
+ pid = fork();
+ if (pid == -1) {
+ return -1;
+ }
+ if (pid == 0) {
+ const char *argv[4] = { "sh", "-c", command, 0 };
+ execv("/bin/sh", (char **)argv);
+ exit(127);
+ }
+
+ /* We continue either when the spawned process has stopped, or when
+ an attached debugger sets spin to 0 */
+ while (spin != 0) {
+ int status = 0;
+ int ret = waitpid(pid, &status, WNOHANG);
+ if (ret == 0) {
+ int i;
+ /* I tried to use sleep for this, and that works everywhere except
+ FreeBSD. The problem on FreeBSD is that if the process gets a
+ signal while blocked in sleep(), gdb is confused by the stack */
+ for (i = 0; i < 1000000; i++)
+ ;
+ }
+ else if (ret == -1) {
+ if (errno != EINTR) {
+ return -1;
+ }
+ }
+ else if (WIFEXITED(status)) {
+ return WEXITSTATUS(status);
+ }
+ else {
+ fprintf (stderr, "unexpected return from waitpid\n");
+ return -1;
+ }
+ };
+ return 0;
+}
+#endif // ENABLE_RUN_ON_DEBUG_BREAK
+
+#define PID_TEXT "PAL_EXE_PID="
+#define EXE_TEXT "PAL_EXE_NAME="
+
+static
+int
+DebugBreakCommand()
+{
+#ifdef ENABLE_RUN_ON_DEBUG_BREAK
+ extern MODSTRUCT exe_module;
+
+ char *command_string = EnvironGetenv(PAL_RUN_ON_DEBUG_BREAK);
+ if (command_string)
+ {
+ char pid_buf[sizeof (PID_TEXT) + 32];
+ PathCharString exe_bufString;
+ int libNameLength = 10;
+
+ if (exe_module.lib_name != NULL)
+ {
+ libNameLength = PAL_wcslen(exe_module.lib_name);
+ }
+
+ SIZE_T dwexe_buf = strlen(EXE_TEXT) + libNameLength + 1;
+ CHAR * exe_buf = exe_bufString.OpenStringBuffer(dwexe_buf);
+
+ if (NULL == exe_buf)
+ {
+ goto FAILED;
+ }
+
+ if (snprintf (pid_buf, sizeof (pid_buf), PID_TEXT "%d", getpid()) <= 0)
+ {
+ goto FAILED;
+ }
+
+ if (snprintf (exe_buf, sizeof (CHAR) * (dwexe_buf + 1), EXE_TEXT "%ls", (wchar_t *)exe_module.lib_name) <= 0)
+ {
+ goto FAILED;
+ }
+
+ exe_bufString.CloseBuffer(dwexe_buf);
+ /* strictly speaking, we might want to only set these environment
+ variables in the child process, but if we do that we can't check
+ for errors. putenv/setenv can fail when out of memory */
+
+ if (!EnvironPutenv (pid_buf, FALSE) || !EnvironPutenv (exe_buf, FALSE))
+ {
+ goto FAILED;
+ }
+
+ if (run_debug_command (command_string))
+ {
+ goto FAILED;
+ }
+
+ free(command_string);
+ return 1;
+ }
+
+ return 0;
+
+FAILED:
+ if (command_string)
+ {
+ free(command_string);
+ }
+
+ fprintf (stderr, "Failed to execute command: '%s'\n", command_string);
+ return -1;
+#else // ENABLE_RUN_ON_DEBUG_BREAK
+ return 0;
+#endif // ENABLE_RUN_ON_DEBUG_BREAK
+}
+
+/*++
+Function:
+ DebugBreak
+
+See MSDN doc.
+--*/
+VOID
+PALAPI
+DebugBreak(
+ VOID)
+{
+ PERF_ENTRY(DebugBreak);
+ ENTRY("DebugBreak()\n");
+
+ if (DebugBreakCommand() <= 0) {
+ // either didn't do anything, or failed
+ TRACE("Calling DBG_DebugBreak\n");
+ DBG_DebugBreak();
+ }
+
+ LOGEXIT("DebugBreak returns\n");
+ PERF_EXIT(DebugBreak);
+}
+
+/*++
+Function:
+ IsInDebugBreak(addr)
+
+ Returns true if the address is in DBG_DebugBreak.
+
+--*/
+BOOL
+IsInDebugBreak(void *addr)
+{
+ return (addr >= (void *)DBG_DebugBreak) && (addr <= (void *)DBG_DebugBreak_End);
+}
+
+/*++
+Function:
+ GetThreadContext
+
+See MSDN doc.
+--*/
+BOOL
+PALAPI
+GetThreadContext(
+ IN HANDLE hThread,
+ IN OUT LPCONTEXT lpContext)
+{
+ PAL_ERROR palError;
+ CPalThread *pThread;
+ CPalThread *pTargetThread;
+ IPalObject *pobjThread = NULL;
+ BOOL ret = FALSE;
+
+ PERF_ENTRY(GetThreadContext);
+ ENTRY("GetThreadContext (hThread=%p, lpContext=%p)\n",hThread,lpContext);
+
+ pThread = InternalGetCurrentThread();
+
+ palError = InternalGetThreadDataFromHandle(
+ pThread,
+ hThread,
+ 0, // THREAD_GET_CONTEXT
+ &pTargetThread,
+ &pobjThread
+ );
+
+ if (NO_ERROR == palError)
+ {
+ if (!pTargetThread->IsDummy())
+ {
+ ret = CONTEXT_GetThreadContext(
+ GetCurrentProcessId(),
+ pTargetThread->GetPThreadSelf(),
+ lpContext
+ );
+ }
+ else
+ {
+ ASSERT("Dummy thread handle passed to GetThreadContext\n");
+ pThread->SetLastError(ERROR_INVALID_HANDLE);
+ }
+ }
+ else
+ {
+ pThread->SetLastError(palError);
+ }
+
+ if (NULL != pobjThread)
+ {
+ pobjThread->ReleaseReference(pThread);
+ }
+
+ LOGEXIT("GetThreadContext returns ret:%d\n", ret);
+ PERF_EXIT(GetThreadContext);
+ return ret;
+}
+
+/*++
+Function:
+ SetThreadContext
+
+See MSDN doc.
+--*/
+BOOL
+PALAPI
+SetThreadContext(
+ IN HANDLE hThread,
+ IN CONST CONTEXT *lpContext)
+{
+ PAL_ERROR palError;
+ CPalThread *pThread;
+ CPalThread *pTargetThread;
+ IPalObject *pobjThread = NULL;
+ BOOL ret = FALSE;
+
+ PERF_ENTRY(SetThreadContext);
+ ENTRY("SetThreadContext (hThread=%p, lpContext=%p)\n",hThread,lpContext);
+
+ pThread = InternalGetCurrentThread();
+
+ palError = InternalGetThreadDataFromHandle(
+ pThread,
+ hThread,
+ 0, // THREAD_SET_CONTEXT
+ &pTargetThread,
+ &pobjThread
+ );
+
+ if (NO_ERROR == palError)
+ {
+ if (!pTargetThread->IsDummy())
+ {
+ ret = CONTEXT_SetThreadContext(
+ GetCurrentProcessId(),
+ pTargetThread->GetPThreadSelf(),
+ lpContext
+ );
+ }
+ else
+ {
+ ASSERT("Dummy thread handle passed to SetThreadContext\n");
+ pThread->SetLastError(ERROR_INVALID_HANDLE);
+ }
+ }
+ else
+ {
+ pThread->SetLastError(palError);
+ }
+
+ if (NULL != pobjThread)
+ {
+ pobjThread->ReleaseReference(pThread);
+ }
+
+ return ret;
+}
+
+#if !HAVE_VM_READ && !HAVE_PROCFS_CTL && !HAVE_TTRACE
+/*++
+Function:
+ DBGWriteProcMem_Int
+
+Abstract
+ write one int to a process memory address
+
+Parameter
+ processId : process handle
+ addr : memory address where the int should be written
+ data : int to be written in addr
+
+Return
+ Return 1 if it succeeds, or 0 if it's fails
+--*/
+static
+int
+DBGWriteProcMem_Int(IN DWORD processId,
+ IN int *addr,
+ IN int data)
+{
+ if (PAL_PTRACE( PAL_PT_WRITE_D, processId, addr, data ) == -1)
+ {
+ if (errno == EFAULT)
+ {
+ ERROR("ptrace(PT_WRITE_D, pid:%d caddr_t:%p data:%x) failed "
+ "errno:%d (%s)\n", processId, addr, data, errno, strerror(errno));
+ SetLastError(ERROR_INVALID_ADDRESS);
+ }
+ else
+ {
+ ASSERT("ptrace(PT_WRITE_D, pid:%d caddr_t:%p data:%x) failed "
+ "errno:%d (%s)\n", processId, addr, data, errno, strerror(errno));
+ SetLastError(ERROR_INTERNAL_ERROR);
+ }
+ return 0;
+ }
+
+ return 1;
+}
+
+/*++
+Function:
+ DBGWriteProcMem_IntWithMask
+
+Abstract
+ write one int to a process memory address space using mask
+
+Parameter
+ processId : process ID
+ addr : memory address where the int should be written
+ data : int to be written in addr
+ mask : the mask used to write only a parts of data
+
+Return
+ Return 1 if it succeeds, or 0 if it's fails
+--*/
+static
+int
+DBGWriteProcMem_IntWithMask(IN DWORD processId,
+ IN int *addr,
+ IN int data,
+ IN unsigned int mask )
+{
+ int readInt;
+
+ if (mask != ~0)
+ {
+ errno = 0;
+ if (((readInt = PAL_PTRACE( PAL_PT_READ_D, processId, addr, 0 )) == -1)
+ && errno)
+ {
+ if (errno == EFAULT)
+ {
+ ERROR("ptrace(PT_READ_D, pid:%d, caddr_t:%p, 0) failed "
+ "errno:%d (%s)\n", processId, addr, errno, strerror(errno));
+ SetLastError(ERROR_INVALID_ADDRESS);
+ }
+ else
+ {
+ ASSERT("ptrace(PT_READ_D, pid:%d, caddr_t:%p, 0) failed "
+ "errno:%d (%s)\n", processId, addr, errno, strerror(errno));
+ SetLastError(ERROR_INTERNAL_ERROR);
+ }
+
+ return 0;
+ }
+ data = (data & mask) | (readInt & ~mask);
+ }
+ return DBGWriteProcMem_Int(processId, addr, data);
+}
+#endif // !HAVE_VM_READ && !HAVE_PROCFS_CTL && !HAVE_TTRACE
+
+#if !HAVE_VM_READ && !HAVE_PROCFS_CTL
+
+/*++
+Function:
+ DBGAttachProcess
+
+Abstract
+
+ Attach the indicated process to the current process.
+
+ if the indicated process is already attached by the current process, then
+ increment the number of attachment pending. if ot, attach it to the current
+ process (with PT_ATTACH).
+
+Parameter
+ hProcess : handle to process to attach to
+ processId : process ID to attach
+Return
+ Return true if it succeeds, or false if it's fails
+--*/
+static
+BOOL
+DBGAttachProcess(
+ CPalThread *pThread,
+ HANDLE hProcess,
+ DWORD processId
+ )
+{
+ int attchmentCount;
+ int savedErrno;
+#if HAVE_PROCFS_CTL
+ int fd = -1;
+ char ctlPath[1024];
+#endif // HAVE_PROCFS_CTL
+
+ attchmentCount =
+ DBGSetProcessAttached(pThread, hProcess, DBG_ATTACH);
+
+ if (attchmentCount == -1)
+ {
+ /* Failed to set the process as attached */
+ goto EXIT;
+ }
+
+ if (attchmentCount == 1)
+ {
+#if HAVE_PROCFS_CTL
+ struct timespec waitTime;
+
+ // FreeBSD has some trouble when a series of attach/detach sequences
+ // occurs too close together. When this happens, we'll be able to
+ // attach to the process, but waiting for the process to stop
+ // (either via writing "wait" to /proc/<pid>/ctl or via waitpid)
+ // will hang. If we pause for a very short amount of time before
+ // trying to attach, we don't run into this situation.
+ waitTime.tv_sec = 0;
+ waitTime.tv_nsec = 50000000;
+ nanosleep(&waitTime, NULL);
+
+ sprintf_s(ctlPath, sizeof(ctlPath), "/proc/%d/ctl", processId);
+ fd = InternalOpen(ctlPath, O_WRONLY);
+ if (fd == -1)
+ {
+ ERROR("Failed to open %s: errno is %d (%s)\n", ctlPath,
+ errno, strerror(errno));
+ goto DETACH1;
+ }
+
+ if (write(fd, CTL_ATTACH, sizeof(CTL_ATTACH)) < (int)sizeof(CTL_ATTACH))
+ {
+ ERROR("Failed to attach to %s: errno is %d (%s)\n", ctlPath,
+ errno, strerror(errno));
+ close(fd);
+ goto DETACH1;
+ }
+
+ if (write(fd, CTL_WAIT, sizeof(CTL_WAIT)) < (int)sizeof(CTL_WAIT))
+ {
+ ERROR("Failed to wait for %s: errno is %d (%s)\n", ctlPath,
+ errno, strerror(errno));
+ goto DETACH2;
+ }
+
+ close(fd);
+#elif HAVE_TTRACE
+ if (ttrace(TT_PROC_ATTACH, processId, 0, TT_DETACH_ON_EXIT, TT_VERSION, 0) == -1)
+ {
+ if (errno != ESRCH)
+ {
+ ASSERT("ttrace(TT_PROC_ATTACH, pid:%d) failed errno:%d (%s)\n",
+ processId, errno, strerror(errno));
+ }
+ goto DETACH1;
+ }
+#else // HAVE_TTRACE
+ if (PAL_PTRACE( PAL_PT_ATTACH, processId, 0, 0 ) == -1)
+ {
+ if (errno != ESRCH)
+ {
+ ASSERT("ptrace(PT_ATTACH, pid:%d) failed errno:%d (%s)\n",
+ processId, errno, strerror(errno));
+ }
+ goto DETACH1;
+ }
+
+ if (waitpid(processId, NULL, WUNTRACED) == -1)
+ {
+ if (errno != ESRCH)
+ {
+ ASSERT("waitpid(pid:%d, NULL, WUNTRACED) failed.errno:%d"
+ " (%s)\n", processId, errno, strerror(errno));
+ }
+ goto DETACH2;
+ }
+#endif // HAVE_PROCFS_CTL
+ }
+
+ return TRUE;
+
+#if HAVE_PROCFS_CTL
+DETACH2:
+ if (write(fd, CTL_DETACH, sizeof(CTL_DETACH)) < (int)sizeof(CTL_DETACH))
+ {
+ ASSERT("Failed to detach from %s: errno is %d (%s)\n", ctlPath,
+ errno, strerror(errno));
+ }
+ close(fd);
+#elif !HAVE_TTRACE
+DETACH2:
+ if (PAL_PTRACE(PAL_PT_DETACH, processId, 0, 0) == -1)
+ {
+ ASSERT("ptrace(PT_DETACH, pid:%d) failed. errno:%d (%s)\n", processId,
+ errno, strerror(errno));
+ }
+#endif // HAVE_PROCFS_CTL
+
+DETACH1:
+ savedErrno = errno;
+ DBGSetProcessAttached(pThread, hProcess, DBG_DETACH);
+ errno = savedErrno;
+EXIT:
+ if (errno == ESRCH || errno == ENOENT || errno == EBADF)
+ {
+ ERROR("Invalid process ID:%d\n", processId);
+ SetLastError(ERROR_INVALID_PARAMETER);
+ }
+ else
+ {
+ SetLastError(ERROR_INTERNAL_ERROR);
+ }
+ return FALSE;
+}
+
+/*++
+Function:
+ DBGDetachProcess
+
+Abstract
+ Detach the indicated process from the current process.
+
+ if the indicated process is already attached by the current process, then
+ decrement the number of attachment pending and detach it from the current
+ process (with PT_DETACH) if there's no more attachment left.
+
+Parameter
+ hProcess : process handle
+ processId : process ID
+
+Return
+ Return true if it succeeds, or true if it's fails
+--*/
+static
+BOOL
+DBGDetachProcess(
+ CPalThread *pThread,
+ HANDLE hProcess,
+ DWORD processId
+ )
+{
+ int nbAttachLeft;
+#if HAVE_PROCFS_CTL
+ int fd = -1;
+ char ctlPath[1024];
+#endif // HAVE_PROCFS_CTL
+
+ nbAttachLeft = DBGSetProcessAttached(pThread, hProcess, DBG_DETACH);
+
+ if (nbAttachLeft == -1)
+ {
+ /* Failed to set the process as detached */
+ return FALSE;
+ }
+
+ /* check if there's no more attachment left on processId */
+ if (nbAttachLeft == 0)
+ {
+#if HAVE_PROCFS_CTL
+ sprintf(ctlPath, sizeof(ctlPath), "/proc/%d/ctl", processId);
+ fd = InternalOpen(pThread, ctlPath, O_WRONLY);
+ if (fd == -1)
+ {
+ if (errno == ENOENT)
+ {
+ ERROR("Invalid process ID: %d\n", processId);
+ SetLastError(ERROR_INVALID_PARAMETER);
+ }
+ else
+ {
+ ERROR("Failed to open %s: errno is %d (%s)\n", ctlPath,
+ errno, strerror(errno));
+ SetLastError(ERROR_INTERNAL_ERROR);
+ }
+ return FALSE;
+ }
+
+ if (write(fd, CTL_DETACH, sizeof(CTL_DETACH)) < (int)sizeof(CTL_DETACH))
+ {
+ ERROR("Failed to detach from %s: errno is %d (%s)\n", ctlPath,
+ errno, strerror(errno));
+ close(fd);
+ return FALSE;
+ }
+ close(fd);
+
+#elif HAVE_TTRACE
+ if (ttrace(TT_PROC_DETACH, processId, 0, 0, 0, 0) == -1)
+ {
+ if (errno == ESRCH)
+ {
+ ERROR("Invalid process ID: %d\n", processId);
+ SetLastError(ERROR_INVALID_PARAMETER);
+ }
+ else
+ {
+ ASSERT("ttrace(TT_PROC_DETACH, pid:%d) failed. errno:%d (%s)\n",
+ processId, errno, strerror(errno));
+ SetLastError(ERROR_INTERNAL_ERROR);
+ }
+ return FALSE;
+ }
+#else // HAVE_TTRACE
+ if (PAL_PTRACE(PAL_PT_DETACH, processId, 1, 0) == -1)
+ {
+ if (errno == ESRCH)
+ {
+ ERROR("Invalid process ID: %d\n", processId);
+ SetLastError(ERROR_INVALID_PARAMETER);
+ }
+ else
+ {
+ ASSERT("ptrace(PT_DETACH, pid:%d) failed. errno:%d (%s)\n",
+ processId, errno, strerror(errno));
+ SetLastError(ERROR_INTERNAL_ERROR);
+ }
+ return FALSE;
+ }
+#endif // HAVE_PROCFS_CTL
+
+#if !HAVE_TTRACE
+ if (kill(processId, SIGCONT) == -1)
+ {
+ ERROR("Failed to continue the detached process:%d errno:%d (%s)\n",
+ processId, errno, strerror(errno));
+ return FALSE;
+ }
+#endif // !HAVE_TTRACE
+ }
+ return TRUE;
+}
+
+/*++
+Function:
+ DBGSetProcessAttached
+
+Abstract
+ saves the current process Id in the attached process structure
+
+Parameter
+ hProcess : process handle
+ bAttach : true (false) to set the process as attached (as detached)
+Return
+ returns the number of attachment left on attachedProcId, or -1 if it fails
+--*/
+static int
+DBGSetProcessAttached(
+ CPalThread *pThread,
+ HANDLE hProcess,
+ BOOL bAttach
+ )
+{
+ PAL_ERROR palError = NO_ERROR;
+ IPalObject *pobjProcess = NULL;
+ IDataLock *pDataLock = NULL;
+ CProcProcessLocalData *pLocalData = NULL;
+ int ret = -1;
+ CAllowedObjectTypes aotProcess(otiProcess);
+
+ palError = g_pObjectManager->ReferenceObjectByHandle(
+ pThread,
+ hProcess,
+ &aotProcess,
+ 0,
+ &pobjProcess
+ );
+
+ if (NO_ERROR != palError)
+ {
+ goto DBGSetProcessAttachedExit;
+ }
+
+ palError = pobjProcess->GetProcessLocalData(
+ pThread,
+ WriteLock,
+ &pDataLock,
+ reinterpret_cast<void **>(&pLocalData)
+ );
+
+ if (NO_ERROR != palError)
+ {
+ goto DBGSetProcessAttachedExit;
+ }
+
+ if (bAttach)
+ {
+ pLocalData->lAttachCount += 1;
+ }
+ else
+ {
+ pLocalData->lAttachCount -= 1;
+
+ if (pLocalData->lAttachCount < 0)
+ {
+ ASSERT("pLocalData->lAttachCount < 0 check for extra DBGDetachProcess calls\n");
+ palError = ERROR_INTERNAL_ERROR;
+ goto DBGSetProcessAttachedExit;
+ }
+ }
+
+ ret = pLocalData->lAttachCount;
+
+DBGSetProcessAttachedExit:
+
+ if (NULL != pDataLock)
+ {
+ pDataLock->ReleaseLock(pThread, TRUE);
+ }
+
+ if (NULL != pobjProcess)
+ {
+ pobjProcess->ReleaseReference(pThread);
+ }
+
+ return ret;
+}
+
+#endif // !HAVE_VM_READ && !HAVE_PROCFS_CTL
+
+/*++
+Function:
+ PAL_CreateExecWatchpoint
+
+Abstract
+ Creates an OS exec watchpoint for the specified instruction
+ and thread. This function should only be called on architectures
+ that do not support a hardware single-step mode (e.g., SPARC).
+
+Parameter
+ hThread : the thread for which the watchpoint is to apply
+ pvInstruction : the instruction on which the watchpoint is to be set
+
+Return
+ A Win32 error code
+--*/
+
+DWORD
+PAL_CreateExecWatchpoint(
+ HANDLE hThread,
+ PVOID pvInstruction
+ )
+{
+ PERF_ENTRY(PAL_CreateExecWatchpoint);
+ ENTRY("PAL_CreateExecWatchpoint (hThread=%p, pvInstruction=%p)\n", hThread, pvInstruction);
+
+ DWORD dwError = ERROR_NOT_SUPPORTED;
+
+#if HAVE_PRWATCH_T
+
+ CPalThread *pThread = NULL;
+ CPalThread *pTargetThread = NULL;
+ IPalObject *pobjThread = NULL;
+ int fd = -1;
+ char ctlPath[50];
+
+ struct
+ {
+ long ctlCode;
+ prwatch_t prwatch;
+ } ctlStruct;
+
+ //
+ // We must never set a watchpoint on an instruction that enters a syscall;
+ // if such a request comes in we succeed it w/o actually creating the
+ // watchpoint. This mirrors the behavior of setting the single-step flag
+ // in a thread context when the thread is w/in a system service -- the
+ // flag is ignored and will not be present when the thread returns
+ // to user mode.
+ //
+
+#if defined(_SPARC_)
+ if (*(DWORD*)pvInstruction == 0x91d02008) // ta 8
+ {
+ TRACE("Watchpoint requested on sysenter instruction -- ignoring");
+ dwError = ERROR_SUCCESS;
+ goto PAL_CreateExecWatchpointExit;
+ }
+#else
+#error Need syscall instruction for this platform
+#endif // _SPARC_
+
+ pThread = InternalGetCurrentThread();
+
+ dwError = InternalGetThreadDataFromHandle(
+ pThread,
+ hThread,
+ 0, // THREAD_SET_CONTEXT
+ &pTargetThread,
+ &pobjThread
+ );
+
+ if (NO_ERROR != dwError)
+ {
+ goto PAL_CreateExecWatchpointExit;
+ }
+
+ snprintf(ctlPath, sizeof(ctlPath), "/proc/%u/lwp/%u/lwpctl", getpid(), pTargetThread->GetLwpId());
+
+ fd = InternalOpen(pThread, ctlPath, O_WRONLY);
+ if (-1 == fd)
+ {
+ ERROR("Failed to open %s\n", ctlPath);
+ dwError = ERROR_INVALID_ACCESS;
+ goto PAL_CreateExecWatchpointExit;
+ }
+
+ ctlStruct.ctlCode = PCWATCH;
+ ctlStruct.prwatch.pr_vaddr = (uintptr_t) pvInstruction;
+ ctlStruct.prwatch.pr_size = sizeof(DWORD);
+ ctlStruct.prwatch.pr_wflags = WA_EXEC | WA_TRAPAFTER;
+
+ if (write(fd, (void*) &ctlStruct, sizeof(ctlStruct)) != sizeof(ctlStruct))
+ {
+ ERROR("Failure writing control structure (errno = %u)\n", errno);
+ dwError = ERROR_INTERNAL_ERROR;
+ goto PAL_CreateExecWatchpointExit;
+ }
+
+ dwError = ERROR_SUCCESS;
+
+PAL_CreateExecWatchpointExit:
+
+ if (NULL != pobjThread)
+ {
+ pobjThread->ReleaseReference(pThread);
+ }
+
+ if (-1 != fd)
+ {
+ close(fd);
+ }
+
+#endif // HAVE_PRWATCH_T
+
+ LOGEXIT("PAL_CreateExecWatchpoint returns ret:%d\n", dwError);
+ PERF_EXIT(PAL_CreateExecWatchpoint);
+ return dwError;
+}
+
+/*++
+Function:
+ PAL_DeleteExecWatchpoint
+
+Abstract
+ Deletes an OS exec watchpoint for the specified instruction
+ and thread. This function should only be called on architectures
+ that do not support a hardware single-step mode (e.g., SPARC).
+
+Parameter
+ hThread : the thread to remove the watchpoint from
+ pvInstruction : the instruction for which the watchpoint is to be removed
+
+Return
+ A Win32 error code. Attempting to delete a watchpoint that does not exist
+ may or may not result in an error, depending on the behavior of the
+ underlying operating system.
+--*/
+
+DWORD
+PAL_DeleteExecWatchpoint(
+ HANDLE hThread,
+ PVOID pvInstruction
+ )
+{
+ PERF_ENTRY(PAL_DeleteExecWatchpoint);
+ ENTRY("PAL_DeleteExecWatchpoint (hThread=%p, pvInstruction=%p)\n", hThread, pvInstruction);
+
+ DWORD dwError = ERROR_NOT_SUPPORTED;
+
+#if HAVE_PRWATCH_T
+
+ CPalThread *pThread = NULL;
+ CPalThread *pTargetThread = NULL;
+ IPalObject *pobjThread = NULL;
+ int fd = -1;
+ char ctlPath[50];
+
+ struct
+ {
+ long ctlCode;
+ prwatch_t prwatch;
+ } ctlStruct;
+
+
+ pThread = InternalGetCurrentThread();
+
+ dwError = InternalGetThreadDataFromHandle(
+ pThread,
+ hThread,
+ 0, // THREAD_SET_CONTEXT
+ &pTargetThread,
+ &pobjThread
+ );
+
+ if (NO_ERROR != dwError)
+ {
+ goto PAL_DeleteExecWatchpointExit;
+ }
+
+ snprintf(ctlPath, sizeof(ctlPath), "/proc/%u/lwp/%u/lwpctl", getpid(), pTargetThread->GetLwpId());
+
+ fd = InternalOpen(pThread, ctlPath, O_WRONLY);
+ if (-1 == fd)
+ {
+ ERROR("Failed to open %s\n", ctlPath);
+ dwError = ERROR_INVALID_ACCESS;
+ goto PAL_DeleteExecWatchpointExit;
+ }
+
+ ctlStruct.ctlCode = PCWATCH;
+ ctlStruct.prwatch.pr_vaddr = (uintptr_t) pvInstruction;
+ ctlStruct.prwatch.pr_size = sizeof(DWORD);
+ ctlStruct.prwatch.pr_wflags = 0;
+
+ if (write(fd, (void*) &ctlStruct, sizeof(ctlStruct)) != sizeof(ctlStruct))
+ {
+ ERROR("Failure writing control structure (errno = %u)\n", errno);
+ dwError = ERROR_INTERNAL_ERROR;
+ goto PAL_DeleteExecWatchpointExit;
+ }
+
+ dwError = ERROR_SUCCESS;
+
+PAL_DeleteExecWatchpointExit:
+
+ if (NULL != pobjThread)
+ {
+ pobjThread->ReleaseReference(pThread);
+ }
+
+ if (-1 != fd)
+ {
+ close(fd);
+ }
+
+#endif // HAVE_PRWATCH_T
+
+ LOGEXIT("PAL_DeleteExecWatchpoint returns ret:%d\n", dwError);
+ PERF_EXIT(PAL_DeleteExecWatchpoint);
+ return dwError;
+}
+
+// We want to enable hardware exception handling for ReadProcessMemory
+// and WriteProcessMemory in all cases since it is acceptable if they
+// hit AVs, so redefine HardwareExceptionHolder for these two functions
+// (here to the end of the file).
+#undef HardwareExceptionHolder
+#define HardwareExceptionHolder CatchHardwareExceptionHolder __catchHardwareException;
+
+/*++
+Function:
+ ReadProcessMemory
+
+See MSDN doc.
+--*/
+BOOL
+PALAPI
+ReadProcessMemory(
+ IN HANDLE hProcess,
+ IN LPCVOID lpBaseAddress,
+ IN LPVOID lpBuffer,
+ IN SIZE_T nSize,
+ OUT SIZE_T * lpNumberOfBytesRead
+ )
+{
+ CPalThread *pThread;
+ DWORD processId;
+ Volatile<BOOL> ret = FALSE;
+ Volatile<SIZE_T> numberOfBytesRead = 0;
+#if HAVE_VM_READ
+ kern_return_t result;
+ vm_map_t task;
+ LONG_PTR bytesToRead;
+#elif HAVE_PROCFS_CTL
+ int fd = -1;
+ char memPath[64];
+ off_t offset;
+#elif !HAVE_TTRACE
+ SIZE_T nbInts;
+ int* ptrInt;
+ int* lpTmpBuffer;
+#endif
+#if !HAVE_PROCFS_CTL && !HAVE_TTRACE
+ int* lpBaseAddressAligned;
+ SIZE_T offset;
+#endif // !HAVE_PROCFS_CTL && !HAVE_TTRACE
+
+ PERF_ENTRY(ReadProcessMemory);
+ ENTRY("ReadProcessMemory (hProcess=%p,lpBaseAddress=%p, lpBuffer=%p, "
+ "nSize=%u, lpNumberOfBytesRead=%p)\n",hProcess,lpBaseAddress,
+ lpBuffer, (unsigned int)nSize, lpNumberOfBytesRead);
+
+ pThread = InternalGetCurrentThread();
+
+ if (!(processId = PROCGetProcessIDFromHandle(hProcess)))
+ {
+ ERROR("Invalid process handler hProcess:%p.",hProcess);
+ SetLastError(ERROR_INVALID_HANDLE);
+ goto EXIT;
+ }
+
+ // Check if the read request is for the current process.
+ // We don't need ptrace in that case.
+ if (GetCurrentProcessId() == processId)
+ {
+ TRACE("We are in the same process, so ptrace is not needed\n");
+
+ struct Param
+ {
+ LPCVOID lpBaseAddress;
+ LPVOID lpBuffer;
+ SIZE_T nSize;
+ SIZE_T numberOfBytesRead;
+ BOOL ret;
+ } param;
+ param.lpBaseAddress = lpBaseAddress;
+ param.lpBuffer = lpBuffer;
+ param.nSize = nSize;
+ param.numberOfBytesRead = numberOfBytesRead;
+ param.ret = ret;
+
+ PAL_TRY(Param *, pParam, &param)
+ {
+ SIZE_T i;
+
+ // Seg fault in memcpy can't be caught
+ // so we simulate the memcpy here
+
+ for (i = 0; i<pParam->nSize; i++)
+ {
+ *((char*)(pParam->lpBuffer)+i) = *((char*)(pParam->lpBaseAddress)+i);
+ }
+
+ pParam->numberOfBytesRead = pParam->nSize;
+ pParam->ret = TRUE;
+ }
+ PAL_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ SetLastError(ERROR_ACCESS_DENIED);
+ }
+ PAL_ENDTRY
+
+ numberOfBytesRead = param.numberOfBytesRead;
+ ret = param.ret;
+ goto EXIT;
+ }
+
+#if HAVE_VM_READ
+ result = task_for_pid(mach_task_self(), processId, &task);
+ if (result != KERN_SUCCESS)
+ {
+ ERROR("No Mach task for pid %d: %d\n", processId, ret.Load());
+ SetLastError(ERROR_INVALID_HANDLE);
+ goto EXIT;
+ }
+ // vm_read_overwrite usually requires that the address be page-aligned
+ // and the size be a multiple of the page size. We can't differentiate
+ // between the cases in which that's required and those in which it
+ // isn't, so we do it all the time.
+ lpBaseAddressAligned = (int*)((SIZE_T) lpBaseAddress & ~VIRTUAL_PAGE_MASK);
+ offset = ((SIZE_T) lpBaseAddress & VIRTUAL_PAGE_MASK);
+ char *data;
+ data = (char*)alloca(VIRTUAL_PAGE_SIZE);
+ while (nSize > 0)
+ {
+ vm_size_t bytesRead;
+
+ bytesToRead = VIRTUAL_PAGE_SIZE - offset;
+ if (bytesToRead > (LONG_PTR)nSize)
+ {
+ bytesToRead = nSize;
+ }
+ bytesRead = VIRTUAL_PAGE_SIZE;
+ result = vm_read_overwrite(task, (vm_address_t) lpBaseAddressAligned,
+ VIRTUAL_PAGE_SIZE, (vm_address_t) data, &bytesRead);
+ if (result != KERN_SUCCESS || bytesRead != VIRTUAL_PAGE_SIZE)
+ {
+ ERROR("vm_read_overwrite failed for %d bytes from %p in %d: %d\n",
+ VIRTUAL_PAGE_SIZE, (char *) lpBaseAddressAligned, task, result);
+ if (result <= KERN_RETURN_MAX)
+ {
+ SetLastError(ERROR_INVALID_ACCESS);
+ }
+ else
+ {
+ SetLastError(ERROR_INTERNAL_ERROR);
+ }
+ goto EXIT;
+ }
+ memcpy((LPSTR)lpBuffer + numberOfBytesRead, data + offset, bytesToRead);
+ numberOfBytesRead.Store(numberOfBytesRead.Load() + bytesToRead);
+ lpBaseAddressAligned = (int*)((char*)lpBaseAddressAligned + VIRTUAL_PAGE_SIZE);
+ nSize -= bytesToRead;
+ offset = 0;
+ }
+ ret = TRUE;
+#else // HAVE_VM_READ
+#if HAVE_PROCFS_CTL
+ snprintf(memPath, sizeof(memPath), "/proc/%u/%s", processId, PROCFS_MEM_NAME);
+ fd = InternalOpen(memPath, O_RDONLY);
+ if (fd == -1)
+ {
+ ERROR("Failed to open %s\n", memPath);
+ SetLastError(ERROR_INVALID_ACCESS);
+ goto PROCFSCLEANUP;
+ }
+
+ //
+ // off_t may be greater in size than void*, so first cast to
+ // an unsigned type to ensure that no sign extension takes place
+ //
+
+ offset = (off_t) (UINT_PTR) lpBaseAddress;
+
+ if (lseek(fd, offset, SEEK_SET) == -1)
+ {
+ ERROR("Failed to seek to base address\n");
+ SetLastError(ERROR_INVALID_ACCESS);
+ goto PROCFSCLEANUP;
+ }
+
+ numberOfBytesRead = read(fd, lpBuffer, nSize);
+ ret = TRUE;
+
+#else // HAVE_PROCFS_CTL
+ // Attach the process before calling ttrace/ptrace otherwise it fails.
+ if (DBGAttachProcess(pThread, hProcess, processId))
+ {
+#if HAVE_TTRACE
+ if (ttrace(TT_PROC_RDDATA, processId, 0, (__uint64_t)lpBaseAddress, (__uint64_t)nSize, (__uint64_t)lpBuffer) == -1)
+ {
+ if (errno == EFAULT)
+ {
+ ERROR("ttrace(TT_PROC_RDDATA, pid:%d, 0, addr:%p, data:%d, addr2:%d) failed"
+ " errno=%d (%s)\n", processId, lpBaseAddress, (int)nSize, lpBuffer,
+ errno, strerror(errno));
+
+ SetLastError(ERROR_ACCESS_DENIED);
+ }
+ else
+ {
+ ASSERT("ttrace(TT_PROC_RDDATA, pid:%d, 0, addr:%p, data:%d, addr2:%d) failed"
+ " errno=%d (%s)\n", processId, lpBaseAddress, (int)nSize, lpBuffer,
+ errno, strerror(errno));
+ SetLastError(ERROR_INTERNAL_ERROR);
+ }
+
+ goto CLEANUP1;
+ }
+
+ numberOfBytesRead = nSize;
+ ret = TRUE;
+
+#else // HAVE_TTRACE
+
+ offset = (SIZE_T)lpBaseAddress % sizeof(int);
+ lpBaseAddressAligned = (int*)((char*)lpBaseAddress - offset);
+ nbInts = (nSize + offset)/sizeof(int) +
+ ((nSize + offset)%sizeof(int) ? 1:0);
+
+ /* before transferring any data to lpBuffer we should make sure that all
+ data is accessible for read. so we need to use a temp buffer for that.*/
+ if (!(lpTmpBuffer = (int*)InternalMalloc((nbInts * sizeof(int)))))
+ {
+ ERROR("Insufficient memory available !\n");
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ goto CLEANUP1;
+ }
+
+ for (ptrInt = lpTmpBuffer; nbInts; ptrInt++,
+ lpBaseAddressAligned++, nbInts--)
+ {
+ errno = 0;
+ *ptrInt =
+ PAL_PTRACE(PAL_PT_READ_D, processId, lpBaseAddressAligned, 0);
+ if (*ptrInt == -1 && errno)
+ {
+ if (errno == EFAULT)
+ {
+ ERROR("ptrace(PT_READ_D, pid:%d, addr:%p, data:0) failed"
+ " errno=%d (%s)\n", processId, lpBaseAddressAligned,
+ errno, strerror(errno));
+
+ SetLastError(ptrInt == lpTmpBuffer ? ERROR_ACCESS_DENIED :
+ ERROR_PARTIAL_COPY);
+ }
+ else
+ {
+ ASSERT("ptrace(PT_READ_D, pid:%d, addr:%p, data:0) failed"
+ " errno=%d (%s)\n", processId, lpBaseAddressAligned,
+ errno, strerror(errno));
+ SetLastError(ERROR_INTERNAL_ERROR);
+ }
+
+ goto CLEANUP2;
+ }
+ }
+
+ /* transfer data from temp buffer to lpBuffer */
+ memcpy( (char *)lpBuffer, ((char*)lpTmpBuffer) + offset, nSize);
+ numberOfBytesRead = nSize;
+ ret = TRUE;
+#endif // HAVE_TTRACE
+ }
+ else
+ {
+ /* Failed to attach processId */
+ goto EXIT;
+ }
+#endif // HAVE_PROCFS_CTL
+
+#if HAVE_PROCFS_CTL
+PROCFSCLEANUP:
+ if (fd != -1)
+ {
+ close(fd);
+ }
+#elif !HAVE_TTRACE
+CLEANUP2:
+ if (lpTmpBuffer)
+ {
+ free(lpTmpBuffer);
+ }
+#endif // !HAVE_TTRACE
+
+#if !HAVE_PROCFS_CTL
+CLEANUP1:
+ if (!DBGDetachProcess(pThread, hProcess, processId))
+ {
+ /* Failed to detach processId */
+ ret = FALSE;
+ }
+#endif // HAVE_PROCFS_CTL
+#endif // HAVE_VM_READ
+
+EXIT:
+ if (lpNumberOfBytesRead)
+ {
+ *lpNumberOfBytesRead = numberOfBytesRead;
+ }
+ LOGEXIT("ReadProcessMemory returns BOOL %d\n", ret.Load());
+ PERF_EXIT(ReadProcessMemory);
+ return ret;
+}
+
+/*++
+Function:
+ WriteProcessMemory
+
+See MSDN doc.
+--*/
+BOOL
+PALAPI
+WriteProcessMemory(
+ IN HANDLE hProcess,
+ IN LPVOID lpBaseAddress,
+ IN LPCVOID lpBuffer,
+ IN SIZE_T nSize,
+ OUT SIZE_T * lpNumberOfBytesWritten
+ )
+
+{
+ CPalThread *pThread;
+ DWORD processId;
+ Volatile<BOOL> ret = FALSE;
+ Volatile<SIZE_T> numberOfBytesWritten = 0;
+#if HAVE_VM_READ
+ kern_return_t result;
+ vm_map_t task;
+#elif HAVE_PROCFS_CTL
+ int fd = -1;
+ char memPath[64];
+ LONG_PTR bytesWritten;
+ off_t offset;
+#elif !HAVE_TTRACE
+ SIZE_T FirstIntOffset;
+ SIZE_T LastIntOffset;
+ unsigned int FirstIntMask;
+ unsigned int LastIntMask;
+ SIZE_T nbInts;
+ int *lpTmpBuffer = 0, *lpInt;
+ int* lpBaseAddressAligned;
+#endif
+
+ PERF_ENTRY(WriteProcessMemory);
+ ENTRY("WriteProcessMemory (hProcess=%p,lpBaseAddress=%p, lpBuffer=%p, "
+ "nSize=%u, lpNumberOfBytesWritten=%p)\n",
+ hProcess,lpBaseAddress, lpBuffer, (unsigned int)nSize, lpNumberOfBytesWritten);
+
+ pThread = InternalGetCurrentThread();
+
+ if (!(nSize && (processId = PROCGetProcessIDFromHandle(hProcess))))
+ {
+ ERROR("Invalid nSize:%u number or invalid process handler "
+ "hProcess:%p\n", (unsigned int)nSize, hProcess);
+ SetLastError(ERROR_INVALID_PARAMETER);
+ goto EXIT;
+ }
+
+ // Check if the write request is for the current process.
+ // In that case we don't need ptrace.
+ if (GetCurrentProcessId() == processId)
+ {
+ TRACE("We are in the same process so we don't need ptrace\n");
+
+ struct Param
+ {
+ LPVOID lpBaseAddress;
+ LPCVOID lpBuffer;
+ SIZE_T nSize;
+ SIZE_T numberOfBytesWritten;
+ BOOL ret;
+ } param;
+ param.lpBaseAddress = lpBaseAddress;
+ param.lpBuffer = lpBuffer;
+ param.nSize = nSize;
+ param.numberOfBytesWritten = numberOfBytesWritten;
+ param.ret = ret;
+
+ PAL_TRY(Param *, pParam, &param)
+ {
+ SIZE_T i;
+
+ // Seg fault in memcpy can't be caught
+ // so we simulate the memcpy here
+
+ for (i = 0; i<pParam->nSize; i++)
+ {
+ *((char*)(pParam->lpBaseAddress)+i) = *((char*)(pParam->lpBuffer)+i);
+ }
+
+ pParam->numberOfBytesWritten = pParam->nSize;
+ pParam->ret = TRUE;
+ }
+ PAL_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ SetLastError(ERROR_ACCESS_DENIED);
+ }
+ PAL_ENDTRY
+
+ numberOfBytesWritten = param.numberOfBytesWritten;
+ ret = param.ret;
+ goto EXIT;
+ }
+
+#if HAVE_VM_READ
+ result = task_for_pid(mach_task_self(), processId, &task);
+ if (result != KERN_SUCCESS)
+ {
+ ERROR("No Mach task for pid %d: %d\n", processId, ret.Load());
+ SetLastError(ERROR_INVALID_HANDLE);
+ goto EXIT;
+ }
+ result = vm_write(task, (vm_address_t) lpBaseAddress,
+ (vm_address_t) lpBuffer, nSize);
+ if (result != KERN_SUCCESS)
+ {
+ ERROR("vm_write failed for %d bytes from %p in %d: %d\n",
+ (int)nSize, lpBaseAddress, task, result);
+ if (result <= KERN_RETURN_MAX)
+ {
+ SetLastError(ERROR_ACCESS_DENIED);
+ }
+ else
+ {
+ SetLastError(ERROR_INTERNAL_ERROR);
+ }
+ goto EXIT;
+ }
+ numberOfBytesWritten = nSize;
+ ret = TRUE;
+#else // HAVE_VM_READ
+#if HAVE_PROCFS_CTL
+ snprintf(memPath, sizeof(memPath), "/proc/%u/%s", processId, PROCFS_MEM_NAME);
+ fd = InternalOpen(memPath, O_WRONLY);
+ if (fd == -1)
+ {
+ ERROR("Failed to open %s\n", memPath);
+ SetLastError(ERROR_INVALID_ACCESS);
+ goto PROCFSCLEANUP;
+ }
+
+ //
+ // off_t may be greater in size than void*, so first cast to
+ // an unsigned type to ensure that no sign extension takes place
+ //
+
+ offset = (off_t) (UINT_PTR) lpBaseAddress;
+
+ if (lseek(fd, offset, SEEK_SET) == -1)
+ {
+ ERROR("Failed to seek to base address\n");
+ SetLastError(ERROR_INVALID_ACCESS);
+ goto PROCFSCLEANUP;
+ }
+
+ bytesWritten = write(fd, lpBuffer, nSize);
+ if (bytesWritten < 0)
+ {
+ ERROR("Failed to write to %s\n", memPath);
+ SetLastError(ERROR_INVALID_ACCESS);
+ goto PROCFSCLEANUP;
+ }
+
+ numberOfBytesWritten = bytesWritten;
+ ret = TRUE;
+
+#else // HAVE_PROCFS_CTL
+ /* Attach the process before calling ptrace otherwise it fails */
+ if (DBGAttachProcess(pThread, hProcess, processId))
+ {
+#if HAVE_TTRACE
+ if (ttrace(TT_PROC_WRDATA, processId, 0, (__uint64_t)lpBaseAddress, (__uint64_t)nSize, (__uint64_t)lpBuffer) == -1)
+ {
+ if (errno == EFAULT)
+ {
+ ERROR("ttrace(TT_PROC_WRDATA, pid:%d, addr:%p, data:%d, addr2:%d) failed"
+ " errno=%d (%s)\n", processId, lpBaseAddress, nSize, lpBuffer,
+ errno, strerror(errno));
+
+ SetLastError(ERROR_ACCESS_DENIED);
+ }
+ else
+ {
+ ASSERT("ttrace(TT_PROC_WRDATA, pid:%d, addr:%p, data:%d, addr2:%d) failed"
+ " errno=%d (%s)\n", processId, lpBaseAddress, nSize, lpBuffer,
+ errno, strerror(errno));
+ SetLastError(ERROR_INTERNAL_ERROR);
+ }
+
+ goto CLEANUP1;
+ }
+
+ numberOfBytesWritten = nSize;
+ ret = TRUE;
+
+#else // HAVE_TTRACE
+
+ FirstIntOffset = (SIZE_T)lpBaseAddress % sizeof(int);
+ FirstIntMask = -1;
+ FirstIntMask <<= (FirstIntOffset * 8);
+
+ nbInts = (nSize + FirstIntOffset) / sizeof(int) +
+ (((nSize + FirstIntOffset)%sizeof(int)) ? 1:0);
+ lpBaseAddressAligned = (int*)((char*)lpBaseAddress - FirstIntOffset);
+
+ if ((lpTmpBuffer = (int*)InternalMalloc((nbInts * sizeof(int)))) == NULL)
+ {
+ ERROR("Insufficient memory available !\n");
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ goto CLEANUP1;
+ }
+
+ memcpy((char *)lpTmpBuffer + FirstIntOffset, (char *)lpBuffer, nSize);
+ lpInt = lpTmpBuffer;
+
+ LastIntOffset = (nSize + FirstIntOffset) % sizeof(int);
+ LastIntMask = -1;
+ LastIntMask >>= ((sizeof(int) - LastIntOffset) * 8);
+
+ if (nbInts == 1)
+ {
+ if (DBGWriteProcMem_IntWithMask(processId, lpBaseAddressAligned,
+ *lpInt,
+ LastIntMask & FirstIntMask)
+ == 0)
+ {
+ goto CLEANUP2;
+ }
+ numberOfBytesWritten = nSize;
+ ret = TRUE;
+ goto CLEANUP2;
+ }
+
+ if (DBGWriteProcMem_IntWithMask(processId,
+ lpBaseAddressAligned++,
+ *lpInt++, FirstIntMask)
+ == 0)
+ {
+ goto CLEANUP2;
+ }
+
+ while (--nbInts > 1)
+ {
+ if (DBGWriteProcMem_Int(processId, lpBaseAddressAligned++,
+ *lpInt++) == 0)
+ {
+ goto CLEANUP2;
+ }
+ }
+
+ if (DBGWriteProcMem_IntWithMask(processId, lpBaseAddressAligned,
+ *lpInt, LastIntMask ) == 0)
+ {
+ goto CLEANUP2;
+ }
+
+ numberOfBytesWritten = nSize;
+ ret = TRUE;
+#endif // HAVE_TTRACE
+ }
+ else
+ {
+ /* Failed to attach processId */
+ goto EXIT;
+ }
+#endif // HAVE_PROCFS_CTL
+
+#if HAVE_PROCFS_CTL
+PROCFSCLEANUP:
+ if (fd != -1)
+ {
+ close(fd);
+ }
+#elif !HAVE_TTRACE
+CLEANUP2:
+ if (lpTmpBuffer)
+ {
+ free(lpTmpBuffer);
+ }
+#endif // !HAVE_TTRACE
+
+#if !HAVE_PROCFS_CTL
+CLEANUP1:
+ if (!DBGDetachProcess(pThread, hProcess, processId))
+ {
+ /* Failed to detach processId */
+ ret = FALSE;
+ }
+#endif // !HAVE_PROCFS_CTL
+#endif // HAVE_VM_READ
+
+EXIT:
+ if (lpNumberOfBytesWritten)
+ {
+ *lpNumberOfBytesWritten = numberOfBytesWritten;
+ }
+
+ LOGEXIT("WriteProcessMemory returns BOOL %d\n", ret.Load());
+ PERF_EXIT(WriteProcessMemory);
+ return ret;
+}
+
+} // extern "C"
diff --git a/src/pal/src/examples/CMakeLists.txt b/src/pal/src/examples/CMakeLists.txt
new file mode 100644
index 0000000000..2cef914892
--- /dev/null
+++ b/src/pal/src/examples/CMakeLists.txt
@@ -0,0 +1,18 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+project(palexmpl)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ example1.c
+)
+
+add_executable(palexmpl
+ ${SOURCES}
+)
+
+add_dependencies(palexmpl coreclrpal)
+
+target_link_libraries(palexmpl
+ coreclrpal
+)
diff --git a/src/pal/src/examples/example1.c b/src/pal/src/examples/example1.c
new file mode 100644
index 0000000000..071f42e4f9
--- /dev/null
+++ b/src/pal/src/examples/example1.c
@@ -0,0 +1,49 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*
+
+ *
+ * Example of minimal program running under PAL.
+ *
+ * Run it using:
+ * export PAL_DBG_CHANNELS="+all.all"
+ * export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:..
+ * ./example1
+ *
+ * With the PAL_DEBUG_CHANNELS environment variable set as above you
+ * should see a trace output when the program runs. Setting
+ * LD_LIBRARY_PATH is necessary unless you have installed librotor_pal.so in
+ * a standard location.
+ *
+ * Build notes :
+ * Since the PAL uses pthreads, some options must be passed to gcc to tell it
+ * to link against thread-safe versions of the standard libraries.
+ * On FreeBSD, use gcc -pthread
+ *
+ */
+
+#include <pal.h>
+extern void *dlopen(const char *file, int mode);
+
+int main(int argc, char *argv[])
+{
+ WCHAR src[4] = {'f', 'o', 'o', '\0'};
+ WCHAR dest[4] = {'b', 'a', 'r', '\0'};
+ WCHAR dir[5] = {'/', 't', 'm', 'p', '\0'};
+ HANDLE h;
+ unsigned int b;
+
+ PAL_Initialize(argc, (const char**)argv);
+ SetCurrentDirectoryW(dir);
+ SetCurrentDirectoryW(dir);
+ h = CreateFileW(src, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_NEW, 0, NULL);
+ WriteFile(h, "Testing\n", 8, &b, FALSE);
+ CloseHandle(h);
+ CopyFileW(src, dest, FALSE);
+ DeleteFileW(src);
+ PAL_Terminate();
+ return 0;
+}
+
diff --git a/src/pal/src/exception/machexception.cpp b/src/pal/src/exception/machexception.cpp
new file mode 100644
index 0000000000..8b0d7f22a8
--- /dev/null
+++ b/src/pal/src/exception/machexception.cpp
@@ -0,0 +1,1612 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+Module Name:
+
+ machexception.cpp
+
+Abstract:
+
+ Implementation of MACH exception API functions.
+
+--*/
+
+#include "pal/dbgmsg.h"
+SET_DEFAULT_DEBUG_CHANNEL(EXCEPT); // some headers have code with asserts, so do this first
+
+#include "pal/thread.hpp"
+#include "pal/seh.hpp"
+#include "pal/palinternal.h"
+#if HAVE_MACH_EXCEPTIONS
+#include "machexception.h"
+#include "pal/critsect.h"
+#include "pal/debug.h"
+#include "pal/init.h"
+#include "pal/utils.h"
+#include "pal/context.h"
+#include "pal/malloc.hpp"
+#include "pal/process.h"
+#include "pal/virtual.h"
+#include "pal/map.hpp"
+#include "pal/environ.h"
+
+#include "machmessage.h"
+
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <dlfcn.h>
+#include <mach-o/loader.h>
+
+using namespace CorUnix;
+
+// The port we use to handle exceptions and to set the thread context
+mach_port_t s_ExceptionPort;
+
+static BOOL s_DebugInitialized = FALSE;
+
+static DWORD s_PalInitializeFlags = 0;
+
+static const char * PAL_MACH_EXCEPTION_MODE = "PAL_MachExceptionMode";
+
+// This struct is used to track the threads that need to have an exception forwarded
+// to the next thread level port in the chain (if exists). An entry is added by the
+// faulting sending a special message to the exception thread which saves it on an
+// list that is searched when the restarted exception notification is received again.
+struct ForwardedException
+{
+ ForwardedException *m_next;
+ thread_act_t Thread;
+ exception_type_t ExceptionType;
+ CPalThread *PalThread;
+};
+
+// The singly linked list and enumerator for the ForwardException struct
+struct ForwardedExceptionList
+{
+private:
+ ForwardedException *m_head;
+ ForwardedException *m_previous;
+
+public:
+ ForwardedException *Current;
+
+ ForwardedExceptionList()
+ {
+ m_head = NULL;
+ MoveFirst();
+ }
+
+ void MoveFirst()
+ {
+ Current = m_head;
+ m_previous = NULL;
+ }
+
+ bool IsEOL()
+ {
+ return Current == NULL;
+ }
+
+ void MoveNext()
+ {
+ m_previous = Current;
+ Current = Current->m_next;
+ }
+
+ void Add(ForwardedException *item)
+ {
+ item->m_next = m_head;
+ m_head = item;
+ }
+
+ void Delete()
+ {
+ if (m_previous == NULL)
+ {
+ m_head = Current->m_next;
+ }
+ else
+ {
+ m_previous->m_next = Current->m_next;
+ }
+ free(Current);
+
+ Current = m_head;
+ m_previous = NULL;
+ }
+};
+
+enum MachExceptionMode
+{
+ // special value to indicate we've not initialized yet
+ MachException_Uninitialized = -1,
+
+ // These can be combined with bitwise OR to incrementally turn off
+ // functionality for diagnostics purposes.
+ //
+ // In practice, the following values are probably useful:
+ // 1: Don't turn illegal instructions into SEH exceptions.
+ // On Intel, stack misalignment usually shows up as an
+ // illegal instruction. PAL client code shouldn't
+ // expect to see any of these, so this option should
+ // always be safe to set.
+ // 2: Don't listen for breakpoint exceptions. This makes an
+ // SEH-based debugger (i.e., managed debugger) unusable,
+ // but you may need this option if you find that native
+ // breakpoints you set in PAL-dependent code don't work
+ // (causing hangs or crashes in the native debugger).
+ // 3: Combination of the above.
+ // This is the typical setting for development
+ // (unless you're working on the managed debugger).
+ // 7: In addition to the above, don't turn bad accesses and
+ // arithmetic exceptions into SEH.
+ // This is the typical setting for stress.
+ MachException_SuppressIllegal = 1,
+ MachException_SuppressDebugging = 2,
+ MachException_SuppressManaged = 4,
+
+ // Default value to use if environment variable not set.
+ MachException_Default = 0,
+};
+
+/*++
+Function :
+ GetExceptionMask()
+
+ Returns the mach exception mask for the exceptions to hook for a thread.
+
+Return value :
+ mach exception mask
+--*/
+static
+exception_mask_t
+GetExceptionMask()
+{
+ static MachExceptionMode exMode = MachException_Uninitialized;
+
+ if (exMode == MachException_Uninitialized)
+ {
+ exMode = MachException_Default;
+
+ char* exceptionSettings = EnvironGetenv(PAL_MACH_EXCEPTION_MODE);
+ if (exceptionSettings)
+ {
+ exMode = (MachExceptionMode)atoi(exceptionSettings);
+ free(exceptionSettings);
+ }
+ else
+ {
+ if (PAL_IsDebuggerPresent())
+ {
+ exMode = MachException_SuppressDebugging;
+ }
+ }
+ }
+
+ exception_mask_t machExceptionMask = 0;
+ if (!(exMode & MachException_SuppressIllegal))
+ {
+ machExceptionMask |= PAL_EXC_ILLEGAL_MASK;
+ }
+ if (!(exMode & MachException_SuppressDebugging) && (s_PalInitializeFlags & PAL_INITIALIZE_DEBUGGER_EXCEPTIONS))
+ {
+#ifdef FEATURE_PAL_SXS
+ // Always hook exception ports for breakpoint exceptions.
+ // The reason is that we don't know when a managed debugger
+ // will attach, so we have to be prepared. We don't want
+ // to later go through the thread list and hook exception
+ // ports for exactly those threads that currently are in
+ // this PAL.
+ machExceptionMask |= PAL_EXC_DEBUGGING_MASK;
+#else // FEATURE_PAL_SXS
+ if (s_DebugInitialized)
+ {
+ machExceptionMask |= PAL_EXC_DEBUGGING_MASK;
+ }
+#endif // FEATURE_PAL_SXS
+ }
+ if (!(exMode & MachException_SuppressManaged))
+ {
+ machExceptionMask |= PAL_EXC_MANAGED_MASK;
+ }
+
+ return machExceptionMask;
+}
+
+#ifdef FEATURE_PAL_SXS
+
+/*++
+Function :
+ CPalThread::EnableMachExceptions
+
+ Hook Mach exceptions, i.e., call thread_swap_exception_ports
+ to replace the thread's current exception ports with our own.
+ The previously active exception ports are saved. Called when
+ this thread enters a region of code that depends on this PAL.
+
+Return value :
+ ERROR_SUCCESS, if enabling succeeded
+ an error code, otherwise
+--*/
+PAL_ERROR CorUnix::CPalThread::EnableMachExceptions()
+{
+ TRACE("%08X: Enter()\n", (unsigned int)(size_t)this);
+
+ exception_mask_t machExceptionMask = GetExceptionMask();
+ if (machExceptionMask != 0)
+ {
+#ifdef _DEBUG
+ // verify that the arrays we've allocated to hold saved exception ports
+ // are the right size.
+ exception_mask_t countBits = PAL_EXC_ALL_MASK;
+ countBits = ((countBits & 0xAAAAAAAA) >> 1) + (countBits & 0x55555555);
+ countBits = ((countBits & 0xCCCCCCCC) >> 2) + (countBits & 0x33333333);
+ countBits = ((countBits & 0xF0F0F0F0) >> 4) + (countBits & 0x0F0F0F0F);
+ countBits = ((countBits & 0xFF00FF00) >> 8) + (countBits & 0x00FF00FF);
+ countBits = ((countBits & 0xFFFF0000) >> 16) + (countBits & 0x0000FFFF);
+ if (countBits != static_cast<exception_mask_t>(CThreadMachExceptionHandlers::s_nPortsMax))
+ {
+ ASSERT("s_nPortsMax is %u, but needs to be %u\n",
+ CThreadMachExceptionHandlers::s_nPortsMax, countBits);
+ }
+#endif // _DEBUG
+
+ NONPAL_TRACE("Enabling handlers for thread %08x exception mask %08x exception port %08x\n",
+ GetMachPortSelf(), machExceptionMask, s_ExceptionPort);
+
+ CThreadMachExceptionHandlers *pSavedHandlers = GetSavedMachHandlers();
+
+ // Swap current handlers into temporary storage first. That's because it's possible (even likely) that
+ // some or all of the handlers might still be ours. In those cases we don't want to overwrite the
+ // chain-back entries with these useless self-references.
+ kern_return_t machret;
+ kern_return_t machretDeallocate;
+ thread_port_t thread = mach_thread_self();
+
+ machret = thread_swap_exception_ports(
+ thread,
+ machExceptionMask,
+ s_ExceptionPort,
+ EXCEPTION_DEFAULT | MACH_EXCEPTION_CODES,
+ THREAD_STATE_NONE,
+ pSavedHandlers->m_masks,
+ &pSavedHandlers->m_nPorts,
+ pSavedHandlers->m_handlers,
+ pSavedHandlers->m_behaviors,
+ pSavedHandlers->m_flavors);
+
+ machretDeallocate = mach_port_deallocate(mach_task_self(), thread);
+ CHECK_MACH("mach_port_deallocate", machretDeallocate);
+
+ if (machret != KERN_SUCCESS)
+ {
+ ASSERT("thread_swap_exception_ports failed: %d %s\n", machret, mach_error_string(machret));
+ return UTIL_MachErrorToPalError(machret);
+ }
+
+#ifdef _DEBUG
+ NONPAL_TRACE("EnableMachExceptions: THREAD PORT count %d\n", pSavedHandlers->m_nPorts);
+ for (mach_msg_type_number_t i = 0; i < pSavedHandlers->m_nPorts; i++)
+ {
+ _ASSERTE(pSavedHandlers->m_handlers[i] != s_ExceptionPort);
+ NONPAL_TRACE("EnableMachExceptions: THREAD PORT mask %08x handler: %08x behavior %08x flavor %u\n",
+ pSavedHandlers->m_masks[i],
+ pSavedHandlers->m_handlers[i],
+ pSavedHandlers->m_behaviors[i],
+ pSavedHandlers->m_flavors[i]);
+ }
+#endif // _DEBUG
+ }
+ return ERROR_SUCCESS;
+}
+
+/*++
+Function :
+ CPalThread::DisableMachExceptions
+
+ Unhook Mach exceptions, i.e., call thread_set_exception_ports
+ to restore the thread's exception ports with those we saved
+ in EnableMachExceptions. Called when this thread leaves a
+ region of code that depends on this PAL.
+
+Return value :
+ ERROR_SUCCESS, if disabling succeeded
+ an error code, otherwise
+--*/
+PAL_ERROR CorUnix::CPalThread::DisableMachExceptions()
+{
+ TRACE("%08X: Leave()\n", (unsigned int)(size_t)this);
+
+ PAL_ERROR palError = NO_ERROR;
+
+ // We only store exceptions when we're installing exceptions.
+ if (0 == GetExceptionMask())
+ return palError;
+
+ // Get the handlers to restore.
+ CThreadMachExceptionHandlers *savedPorts = GetSavedMachHandlers();
+
+ kern_return_t MachRet = KERN_SUCCESS;
+ for (int i = 0; i < savedPorts->m_nPorts; i++)
+ {
+ // If no handler was ever set, thread_swap_exception_ports returns
+ // MACH_PORT_NULL for the handler and zero values for behavior
+ // and flavor. Unfortunately, the latter are invalid even for
+ // MACH_PORT_NULL when you use thread_set_exception_ports.
+ exception_behavior_t behavior = savedPorts->m_behaviors[i] ? savedPorts->m_behaviors[i] : EXCEPTION_DEFAULT;
+ thread_state_flavor_t flavor = savedPorts->m_flavors[i] ? savedPorts->m_flavors[i] : MACHINE_THREAD_STATE;
+ thread_port_t thread = mach_thread_self();
+ MachRet = thread_set_exception_ports(thread,
+ savedPorts->m_masks[i],
+ savedPorts->m_handlers[i],
+ behavior,
+ flavor);
+
+ kern_return_t MachRetDeallocate = mach_port_deallocate(mach_task_self(), thread);
+ CHECK_MACH("mach_port_deallocate", MachRetDeallocate);
+
+ if (MachRet != KERN_SUCCESS)
+ break;
+ }
+
+ if (MachRet != KERN_SUCCESS)
+ {
+ ASSERT("thread_set_exception_ports failed: %d\n", MachRet);
+ palError = UTIL_MachErrorToPalError(MachRet);
+ }
+
+ return palError;
+}
+
+#else // FEATURE_PAL_SXS
+
+/*++
+Function :
+ SEHEnableMachExceptions
+
+ Enable SEH-related stuff related to mach exceptions
+
+ (no parameters)
+
+Return value :
+ TRUE if enabling succeeded
+ FALSE otherwise
+--*/
+BOOL SEHEnableMachExceptions()
+{
+ exception_mask_t machExceptionMask = GetExceptionMask();
+ if (machExceptionMask != 0)
+ {
+ kern_return_t MachRet;
+ MachRet = task_set_exception_ports(mach_task_self(),
+ machExceptionMask,
+ s_ExceptionPort,
+ EXCEPTION_DEFAULT,
+ MACHINE_THREAD_STATE);
+
+ if (MachRet != KERN_SUCCESS)
+ {
+ ASSERT("task_set_exception_ports failed: %d\n", MachRet);
+ UTIL_SetLastErrorFromMach(MachRet);
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+/*++
+Function :
+ SEHDisableMachExceptions
+
+ Disable SEH-related stuff related to mach exceptions
+
+ (no parameters)
+
+Return value :
+ TRUE if enabling succeeded
+ FALSE otherwise
+--*/
+BOOL SEHDisableMachExceptions()
+{
+ exception_mask_t machExceptionMask = GetExceptionMask();
+ if (machExceptionMask != 0)
+ {
+ kern_return_t MachRet;
+ MachRet = task_set_exception_ports(mach_task_self(),
+ machExceptionMask,
+ MACH_PORT_NULL,
+ EXCEPTION_DEFAULT,
+ MACHINE_THREAD_STATE);
+
+ if (MachRet != KERN_SUCCESS)
+ {
+ ASSERT("task_set_exception_ports failed: %d\n", MachRet);
+ UTIL_SetLastErrorFromMach(MachRet);
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+#endif // FEATURE_PAL_SXS
+
+#if !defined(_AMD64_)
+extern "C"
+void PAL_DispatchException(PCONTEXT pContext, PEXCEPTION_RECORD pExRecord, MachExceptionInfo *pMachExceptionInfo)
+#else // defined(_AMD64_)
+
+// Since HijackFaultingThread pushed the context, exception record and info on the stack, we need to adjust the
+// signature of PAL_DispatchException such that the corresponding arguments are considered to be on the stack
+// per GCC64 calling convention rules. Hence, the first 6 dummy arguments (corresponding to RDI, RSI, RDX,RCX, R8, R9).
+extern "C"
+void PAL_DispatchException(DWORD64 dwRDI, DWORD64 dwRSI, DWORD64 dwRDX, DWORD64 dwRCX, DWORD64 dwR8, DWORD64 dwR9, PCONTEXT pContext, PEXCEPTION_RECORD pExRecord, MachExceptionInfo *pMachExceptionInfo)
+#endif // !defined(_AMD64_)
+{
+ CPalThread *pThread = InternalGetCurrentThread();
+
+#if FEATURE_PAL_SXS
+ if (!pThread->IsInPal())
+ {
+ // It's now possible to observe system exceptions in code running outside the PAL (as the result of a
+ // p/invoke since we no longer revert our Mach exception ports in this case). In that scenario we need
+ // to re-enter the PAL now as the exception signals the end of the p/invoke.
+ PAL_Reenter(PAL_BoundaryBottom);
+ }
+#endif // FEATURE_PAL_SXS
+
+ CONTEXT *contextRecord;
+ EXCEPTION_RECORD *exceptionRecord;
+ AllocateExceptionRecords(&exceptionRecord, &contextRecord);
+
+ *contextRecord = *pContext;
+ *exceptionRecord = *pExRecord;
+
+ contextRecord->ContextFlags |= CONTEXT_EXCEPTION_ACTIVE;
+ bool continueExecution;
+
+ {
+ // The exception object takes ownership of the exceptionRecord and contextRecord
+ PAL_SEHException exception(exceptionRecord, contextRecord);
+
+ TRACE("PAL_DispatchException(EC %08x EA %p)\n", pExRecord->ExceptionCode, pExRecord->ExceptionAddress);
+
+ continueExecution = SEHProcessException(&exception);
+ if (continueExecution)
+ {
+ // Make a copy of the exception records so that we can free them before restoring the context
+ *pContext = *contextRecord;
+ *pExRecord = *exceptionRecord;
+ }
+
+ // The exception records are destroyed by the PAL_SEHException destructor now.
+ }
+
+ if (continueExecution)
+ {
+ RtlRestoreContext(pContext, pExRecord);
+ }
+
+ // Send the forward request to the exception thread to process
+ MachMessage sSendMessage;
+ sSendMessage.SendForwardException(s_ExceptionPort, pMachExceptionInfo, pThread);
+
+ // Spin wait until this thread is hijacked by the exception thread
+ while (TRUE)
+ {
+ sched_yield();
+ }
+}
+
+#if defined(_X86_) || defined(_AMD64_)
+extern "C" void PAL_DispatchExceptionWrapper();
+extern "C" int PAL_DispatchExceptionReturnOffset;
+#endif // _X86_ || _AMD64_
+
+/*++
+Function :
+ BuildExceptionRecord
+
+ Sets up up an ExceptionRecord from an exception message
+
+Parameters :
+ exceptionInfo - exception info to build the exception record
+ pExceptionRecord - exception record to setup
+*/
+static
+void
+BuildExceptionRecord(
+ MachExceptionInfo& exceptionInfo, // [in] exception info
+ EXCEPTION_RECORD *pExceptionRecord) // [out] Used to return exception parameters
+{
+ memset(pExceptionRecord, 0, sizeof(EXCEPTION_RECORD));
+
+ DWORD exceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION;
+
+ switch(exceptionInfo.ExceptionType)
+ {
+ // Could not access memory. subcode contains the bad memory address.
+ case EXC_BAD_ACCESS:
+ if (exceptionInfo.SubcodeCount != 2)
+ {
+ NONPAL_RETAIL_ASSERT("Got an unexpected subcode");
+ exceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION;
+ }
+ else
+ {
+ exceptionCode = EXCEPTION_ACCESS_VIOLATION;
+
+ pExceptionRecord->NumberParameters = 2;
+ pExceptionRecord->ExceptionInformation[0] = 0;
+ pExceptionRecord->ExceptionInformation[1] = exceptionInfo.Subcodes[1];
+ NONPAL_TRACE("subcodes[1] = %llx\n", exceptionInfo.Subcodes[1]);
+ }
+ break;
+
+ // Instruction failed. Illegal or undefined instruction or operand.
+ case EXC_BAD_INSTRUCTION :
+ // TODO: Identify privileged instruction. Need to get the thread state and read the machine code. May
+ // be better to do this in the place that calls SEHProcessException, similar to how it's done on Linux.
+ exceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION;
+ break;
+
+ // Arithmetic exception; exact nature of exception is in subcode field.
+ case EXC_ARITHMETIC:
+ if (exceptionInfo.SubcodeCount != 2)
+ {
+ NONPAL_RETAIL_ASSERT("Got an unexpected subcode");
+ exceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION;
+ }
+ else
+ {
+ switch (exceptionInfo.Subcodes[0])
+ {
+#if defined(_X86_) || defined(_AMD64_)
+ case EXC_I386_DIV:
+ exceptionCode = EXCEPTION_INT_DIVIDE_BY_ZERO;
+ break;
+ case EXC_I386_INTO:
+ exceptionCode = EXCEPTION_INT_OVERFLOW;
+ break;
+ case EXC_I386_EXTOVR:
+ exceptionCode = EXCEPTION_FLT_OVERFLOW;
+ break;
+ case EXC_I386_BOUND:
+ exceptionCode = EXCEPTION_ARRAY_BOUNDS_EXCEEDED;
+ break;
+#else
+#error Trap code to exception mapping not defined for this architecture
+#endif
+ default:
+ exceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION;
+ break;
+ }
+ }
+ break;
+
+ case EXC_SOFTWARE:
+#if defined(_X86_) || defined(_AMD64_)
+ exceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION;
+ break;
+#else
+#error Trap code to exception mapping not defined for this architecture
+#endif
+
+ // Trace, breakpoint, etc. Details in subcode field.
+ case EXC_BREAKPOINT:
+#if defined(_X86_) || defined(_AMD64_)
+ if (exceptionInfo.Subcodes[0] == EXC_I386_SGL)
+ {
+ exceptionCode = EXCEPTION_SINGLE_STEP;
+ }
+ else if (exceptionInfo.Subcodes[0] == EXC_I386_BPT)
+ {
+ exceptionCode = EXCEPTION_BREAKPOINT;
+ }
+#else
+#error Trap code to exception mapping not defined for this architecture
+#endif
+ else
+ {
+ WARN("unexpected subcode %d for EXC_BREAKPOINT", exceptionInfo.Subcodes[0]);
+ exceptionCode = EXCEPTION_BREAKPOINT;
+ }
+ break;
+
+
+ // System call requested. Details in subcode field.
+ case EXC_SYSCALL:
+ exceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION;
+ break;
+
+ // System call with a number in the Mach call range requested. Details in subcode field.
+ case EXC_MACH_SYSCALL:
+ exceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION;
+ break;
+
+ default:
+ NONPAL_ASSERT("Got unknown trap code %d\n", exceptionInfo.ExceptionType);
+ break;
+ }
+
+ pExceptionRecord->ExceptionCode = exceptionCode;
+}
+
+#ifdef _DEBUG
+const char *
+GetExceptionString(
+ exception_type_t exception
+)
+{
+ switch(exception)
+ {
+ case EXC_BAD_ACCESS:
+ return "EXC_BAD_ACCESS";
+
+ case EXC_BAD_INSTRUCTION:
+ return "EXC_BAD_INSTRUCTION";
+
+ case EXC_ARITHMETIC:
+ return "EXC_ARITHMETIC";
+
+ case EXC_SOFTWARE:
+ return "EXC_SOFTWARE";
+
+ case EXC_BREAKPOINT:
+ return "EXC_BREAKPOINT";
+
+ case EXC_SYSCALL:
+ return "EXC_SYSCALL";
+
+ case EXC_MACH_SYSCALL:
+ return "EXC_MACH_SYSCALL";
+
+ default:
+ NONPAL_ASSERT("Got unknown trap code %d\n", exception);
+ break;
+ }
+ return "INVALID CODE";
+}
+#endif // _DEBUG
+
+/*++
+Function :
+ HijackFaultingThread
+
+ Sets the faulting thread up to return to PAL_DispatchException with an
+ ExceptionRecord and thread CONTEXT.
+
+Parameters:
+ thread - thread the exception happened
+ task - task the exception happened
+ message - exception message
+
+Return value :
+ None
+--*/
+static
+void
+HijackFaultingThread(
+ mach_port_t thread, // [in] thread the exception happened on
+ mach_port_t task, // [in] task the exception happened on
+ MachMessage& message) // [in] exception message
+{
+ MachExceptionInfo exceptionInfo(thread, message);
+ EXCEPTION_RECORD exceptionRecord;
+ CONTEXT threadContext;
+ kern_return_t machret;
+
+ // Fill in the exception record from the exception info
+ BuildExceptionRecord(exceptionInfo, &exceptionRecord);
+
+#ifdef _X86_
+ threadContext.ContextFlags = CONTEXT_FLOATING_POINT | CONTEXT_EXTENDED_REGISTERS;
+#else
+ threadContext.ContextFlags = CONTEXT_FLOATING_POINT;
+#endif
+ CONTEXT_GetThreadContextFromThreadState(x86_FLOAT_STATE, (thread_state_t)&exceptionInfo.FloatState, &threadContext);
+
+ threadContext.ContextFlags |= CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS;
+ CONTEXT_GetThreadContextFromThreadState(x86_THREAD_STATE, (thread_state_t)&exceptionInfo.ThreadState, &threadContext);
+
+#if defined(CORECLR) && (defined(_X86_) || defined(_AMD64_))
+ // For CoreCLR we look more deeply at access violations to determine whether they're the result of a stack
+ // overflow. If so we'll terminate the process immediately (the current default policy of the CoreCLR EE).
+ // Otherwise we'll either A/V ourselves trying to set up the SEH exception record and context on the
+ // target thread's stack (unlike Windows there's no extra stack reservation to guarantee this can be done)
+ // or, and this the case we're trying to avoid, it's possible we'll succeed and the runtime will go ahead
+ // and process the SO like it was a simple AV. Since the runtime doesn't currently implement stack probing
+ // on non-Windows platforms, this could lead to data corruption (we have SO intolerant code in the runtime
+ // which manipulates global state under the assumption that an SO cannot occur due to a prior stack
+ // probe).
+
+ // Determining whether an AV is really an SO is not quite straightforward. We can get stack bounds
+ // information from pthreads but (a) we only have the target Mach thread port and no way to map to a
+ // pthread easily and (b) the pthread functions lie about the bounds on the main thread.
+
+ // Instead we inspect the target thread SP we just retrieved above and compare it with the AV address. If
+ // they both lie in the same page or the SP is at a higher address than the AV but in the same VM region,
+ // then we'll consider the AV to be an SO. Note that we can't assume that SP will be in the same page as
+ // the AV on an SO, even though we force GCC to generate stack probes on stack extension (-fstack-check).
+ // That's because GCC currently generates the probe *before* altering SP. Since a given stack extension can
+ // involve multiple pages and GCC generates all the required probes before updating SP in a single
+ // operation, the faulting probe can be at an address that is far removed from the thread's current value
+ // of SP.
+
+ // In the case where the AV and SP aren't in the same or adjacent pages we check if the first page
+ // following the faulting address belongs in the same VM region as the current value of SP. Since all pages
+ // in a VM region have the same attributes this check eliminates the possibility that there's another guard
+ // page in the range between the fault and the SP, effectively establishing that the AV occurred in the
+ // guard page associated with the stack associated with the SP.
+
+ // We are assuming here that thread stacks are always allocated in a single VM region. I've seen no
+ // evidence thus far that this is not the case (and the mere fact we rely on Mach apis already puts us on
+ // brittle ground anyway).
+
+ // (a) SP always marks the current limit of the stack (in that all valid stack accesses will be of
+ // the form [SP + delta]). The Mac x86 ABI appears to guarantee this (or rather it does not
+ // guarantee that stack slots below SP will not be invalidated by asynchronous events such as
+ // interrupts, which mostly amounts to the same thing for user mode code). Note that the Mac PPC
+ // ABI does allow some (constrained) access below SP, but we're not currently supporting this
+ // platform.
+ // (b) All code will extend the stack "carefully" (by which we mean that stack extensions of more
+ // than one page in size will touch at least one byte in each intervening page (in decreasing
+ // address order), to guarantee that the guard page is hit before memory beyond the guard page is
+ // corrupted). Our managed jits always generate code which does this as does MSVC. GCC, however,
+ // does not do this by default. We have to explicitly provide the -fstack-check compiler option
+ // to enable the behavior.
+#if (defined(_X86_) || defined(_AMD64_)) && defined(__APPLE__)
+ if (exceptionRecord.ExceptionCode == EXCEPTION_ACCESS_VIOLATION)
+ {
+ // Assume this AV isn't an SO to begin with.
+ bool fIsStackOverflow = false;
+
+ // Calculate the page base addresses for the fault and the faulting thread's SP.
+ int cbPage = getpagesize();
+ char *pFaultPage = (char*)(exceptionRecord.ExceptionInformation[1] & ~(cbPage - 1));
+#ifdef _X86_
+ char *pStackTopPage = (char*)(threadContext.Esp & ~(cbPage - 1));
+#elif defined(_AMD64_)
+ char *pStackTopPage = (char*)(threadContext.Rsp & ~(cbPage - 1));
+#endif
+
+ if (pFaultPage == pStackTopPage || pFaultPage == (pStackTopPage - cbPage))
+ {
+ // The easy case is when the AV occurred in the same or adjacent page as the stack pointer.
+ fIsStackOverflow = true;
+ }
+ else if (pFaultPage < pStackTopPage)
+ {
+ // Calculate the address of the page immediately following the fault and check that it
+ // lies in the same VM region as the stack pointer.
+ vm_address_t vm_address;
+ vm_size_t vm_size;
+ vm_region_flavor_t vm_flavor;
+ mach_msg_type_number_t infoCnt;
+#ifdef BIT64
+ vm_region_basic_info_data_64_t info;
+ infoCnt = VM_REGION_BASIC_INFO_COUNT_64;
+ vm_flavor = VM_REGION_BASIC_INFO_64;
+#else
+ vm_region_basic_info_data_t info;
+ infoCnt = VM_REGION_BASIC_INFO_COUNT;
+ vm_flavor = VM_REGION_BASIC_INFO;
+#endif
+ mach_port_t object_name;
+
+ vm_address = (vm_address_t)(pFaultPage + cbPage);
+
+#ifdef BIT64
+ machret = vm_region_64(
+#else
+ machret = vm_region(
+#endif
+ mach_task_self(),
+ &vm_address,
+ &vm_size,
+ vm_flavor,
+ (vm_region_info_t)&info,
+ &infoCnt,
+ &object_name);
+#ifdef _X86_
+ CHECK_MACH("vm_region", machret);
+#elif defined(_AMD64_)
+ CHECK_MACH("vm_region_64", machret);
+#endif
+
+ // If vm_region updated the address we gave it then that address was not part of a region at all
+ // (and so this cannot be an SO). Otherwise check that the ESP lies in the region returned.
+ char *pRegionStart = (char*)vm_address;
+ char *pRegionEnd = (char*)vm_address + vm_size;
+ if (pRegionStart == (pFaultPage + cbPage) && pStackTopPage < pRegionEnd)
+ fIsStackOverflow = true;
+ }
+
+#if defined(_AMD64_)
+ if (!fIsStackOverflow)
+ {
+ // Check if we can read pointer sizeD bytes below the target thread's stack pointer.
+ // If we are unable to, then it implies we have run into SO.
+ void **targetSP = (void **)threadContext.Rsp;
+ vm_address_t targetAddr = (mach_vm_address_t)(targetSP);
+ targetAddr -= sizeof(void *);
+ vm_size_t vm_size = sizeof(void *);
+ char arr[8];
+ vm_size_t data_count = 8;
+ machret = vm_read_overwrite(mach_task_self(), targetAddr, vm_size, (pointer_t)arr, &data_count);
+ if (machret == KERN_INVALID_ADDRESS)
+ {
+ fIsStackOverflow = true;
+ }
+ }
+#endif // _AMD64_
+
+ if (fIsStackOverflow)
+ {
+ // We have a stack overflow. Abort the process immediately. It would be nice to let the VM do this
+ // but the Windows mechanism (where a stack overflow SEH exception is delivered on the faulting
+ // thread) will not work most of the time since non-Windows OSs don't keep a reserve stack
+ // extension allocated for this purpose.
+
+ // TODO: Once our event reporting story is further along we probably want to report something
+ // here. If our runtime policy for SO ever changes (the most likely candidate being "unload
+ // appdomain on SO) then we'll have to do something more complex here, probably involving a
+ // handshake with the runtime in order to report the SO without attempting to extend the faulting
+ // thread's stack any further. Note that we cannot call most PAL functions from the context of
+ // this thread since we're not a PAL thread.
+
+ write(STDERR_FILENO, StackOverflowMessage, sizeof(StackOverflowMessage) - 1);
+ abort();
+ }
+ }
+#else // (_X86_ || _AMD64_) && __APPLE__
+#error Platform not supported for correct stack overflow handling
+#endif // (_X86_ || _AMD64_) && __APPLE__
+#endif // CORECLR && _X86_
+
+#if defined(_X86_)
+ NONPAL_ASSERTE(exceptionInfo.ThreadState.tsh.flavor == x86_THREAD_STATE32);
+
+ // Make a copy of the thread state because the one in exceptionInfo needs to be preserved to restore
+ // the state if the exception is forwarded.
+ x86_thread_state32_t ts32 = exceptionInfo.ThreadState.uts.ts32;
+
+ // If we're in single step mode, disable it since we're going to call PAL_DispatchException
+ if (exceptionRecord.ExceptionCode == EXCEPTION_SINGLE_STEP)
+ {
+ ts32.eflags &= ~EFL_TF;
+ }
+
+ exceptionRecord.ExceptionFlags = EXCEPTION_IS_SIGNAL;
+ exceptionRecord.ExceptionRecord = NULL;
+ exceptionRecord.ExceptionAddress = (void *)ts32.eip;
+
+ void **FramePointer = (void **)ts32.esp;
+
+ *--FramePointer = (void *)ts32.eip;
+
+ // Construct a stack frame for a pretend activation of the function
+ // PAL_DispatchExceptionWrapper that serves only to make the stack
+ // correctly unwindable by the system exception unwinder.
+ // PAL_DispatchExceptionWrapper has an ebp frame, its local variables
+ // are the context and exception record, and it has just "called"
+ // PAL_DispatchException.
+ *--FramePointer = (void *)ts32.ebp;
+ ts32.ebp = (unsigned)FramePointer;
+
+ // Put the context on the stack
+ FramePointer = (void **)((ULONG_PTR)FramePointer - sizeof(CONTEXT));
+ // Make sure it's aligned - CONTEXT has 8-byte alignment
+ FramePointer = (void **)((ULONG_PTR)FramePointer - ((ULONG_PTR)FramePointer % 8));
+ CONTEXT *pContext = (CONTEXT *)FramePointer;
+ *pContext = threadContext;
+
+ // Put the exception record on the stack
+ FramePointer = (void **)((ULONG_PTR)FramePointer - sizeof(EXCEPTION_RECORD));
+ EXCEPTION_RECORD *pExceptionRecord = (EXCEPTION_RECORD *)FramePointer;
+ *pExceptionRecord = exceptionRecord;
+
+ FramePointer = (void **)((ULONG_PTR)FramePointer - sizeof(MachExceptionInfo));
+ MachExceptionInfo *pMachExceptionInfo = (MachExceptionInfo *)FramePointer;
+ *pMachExceptionInfo = exceptionInfo;
+
+ // Push arguments to PAL_DispatchException
+ FramePointer = (void **)((ULONG_PTR)FramePointer - 3 * sizeof(void *));
+
+ // Make sure it's aligned - ABI requires 16-byte alignment
+ FramePointer = (void **)((ULONG_PTR)FramePointer - ((ULONG_PTR)FramePointer % 16));
+ FramePointer[0] = pContext;
+ FramePointer[1] = pExceptionRecord;
+ FramePointer[2] = pMachExceptionInfo;
+
+ // Place the return address to right after the fake call in PAL_DispatchExceptionWrapper
+ FramePointer[-1] = (void *)((ULONG_PTR)PAL_DispatchExceptionWrapper + PAL_DispatchExceptionReturnOffset);
+
+ // Make the instruction register point to DispatchException
+ ts32.eip = (unsigned)PAL_DispatchException;
+ ts32.esp = (unsigned)&FramePointer[-1]; // skip return address
+
+ // Now set the thread state for the faulting thread so that PAL_DispatchException executes next
+ machret = thread_set_state(thread, x86_THREAD_STATE32, (thread_state_t)&ts32, x86_THREAD_STATE32_COUNT);
+ CHECK_MACH("thread_set_state(thread)", machret);
+#elif defined(_AMD64_)
+ NONPAL_ASSERTE(exceptionInfo.ThreadState.tsh.flavor == x86_THREAD_STATE64);
+
+ // Make a copy of the thread state because the one in exceptionInfo needs to be preserved to restore
+ // the state if the exception is forwarded.
+ x86_thread_state64_t ts64 = exceptionInfo.ThreadState.uts.ts64;
+
+ // If we're in single step mode, disable it since we're going to call PAL_DispatchException
+ if (exceptionRecord.ExceptionCode == EXCEPTION_SINGLE_STEP)
+ {
+ ts64.__rflags &= ~EFL_TF;
+ }
+
+ exceptionRecord.ExceptionFlags = EXCEPTION_IS_SIGNAL;
+ exceptionRecord.ExceptionRecord = NULL;
+ exceptionRecord.ExceptionAddress = (void *)ts64.__rip;
+
+ void **FramePointer = (void **)ts64.__rsp;
+
+ *--FramePointer = (void *)ts64.__rip;
+
+ // Construct a stack frame for a pretend activation of the function
+ // PAL_DispatchExceptionWrapper that serves only to make the stack
+ // correctly unwindable by the system exception unwinder.
+ // PAL_DispatchExceptionWrapper has an ebp frame, its local variables
+ // are the context and exception record, and it has just "called"
+ // PAL_DispatchException.
+ *--FramePointer = (void *)ts64.__rbp;
+ ts64.__rbp = (SIZE_T)FramePointer;
+
+ // Put the context on the stack
+ FramePointer = (void **)((ULONG_PTR)FramePointer - sizeof(CONTEXT));
+ // Make sure it's aligned - CONTEXT has 16-byte alignment
+ FramePointer = (void **)((ULONG_PTR)FramePointer - ((ULONG_PTR)FramePointer % 16));
+ CONTEXT *pContext = (CONTEXT *)FramePointer;
+ *pContext = threadContext;
+
+ // Put the exception record on the stack
+ FramePointer = (void **)((ULONG_PTR)FramePointer - sizeof(EXCEPTION_RECORD));
+ EXCEPTION_RECORD *pExceptionRecord = (EXCEPTION_RECORD *)FramePointer;
+ *pExceptionRecord = exceptionRecord;
+
+ FramePointer = (void **)((ULONG_PTR)FramePointer - sizeof(MachExceptionInfo));
+ MachExceptionInfo *pMachExceptionInfo = (MachExceptionInfo *)FramePointer;
+ *pMachExceptionInfo = exceptionInfo;
+
+ // Push arguments to PAL_DispatchException
+ FramePointer = (void **)((ULONG_PTR)FramePointer - 3 * sizeof(void *));
+
+ // Make sure it's aligned - ABI requires 16-byte alignment
+ FramePointer = (void **)((ULONG_PTR)FramePointer - ((ULONG_PTR)FramePointer % 16));
+ FramePointer[0] = pContext;
+ FramePointer[1] = pExceptionRecord;
+ FramePointer[2] = pMachExceptionInfo;
+
+ // Place the return address to right after the fake call in PAL_DispatchExceptionWrapper
+ FramePointer[-1] = (void *)((ULONG_PTR)PAL_DispatchExceptionWrapper + PAL_DispatchExceptionReturnOffset);
+
+ // Make the instruction register point to DispatchException
+ ts64.__rip = (SIZE_T)PAL_DispatchException;
+ ts64.__rsp = (SIZE_T)&FramePointer[-1]; // skip return address
+
+ // Now set the thread state for the faulting thread so that PAL_DispatchException executes next
+ machret = thread_set_state(thread, x86_THREAD_STATE64, (thread_state_t)&ts64, x86_THREAD_STATE64_COUNT);
+ CHECK_MACH("thread_set_state(thread)", machret);
+#else
+#error HijackFaultingThread not defined for this architecture
+#endif
+}
+
+/*++
+Function :
+ SuspendMachThread
+
+ Suspend the specified thread.
+
+Parameters:
+ thread - mach thread port
+
+Return value :
+ None
+--*/
+static
+void
+SuspendMachThread(thread_act_t thread)
+{
+ kern_return_t machret;
+
+ while (true)
+ {
+ machret = thread_suspend(thread);
+ CHECK_MACH("thread_suspend", machret);
+
+ // Ensure that if the thread was running in the kernel, the kernel operation
+ // is safely aborted so that it can be restarted later.
+ machret = thread_abort_safely(thread);
+ if (machret == KERN_SUCCESS)
+ {
+ break;
+ }
+
+ // The thread was running in the kernel executing a non-atomic operation
+ // that cannot be restarted, so we need to resume the thread and retry
+ machret = thread_resume(thread);
+ CHECK_MACH("thread_resume", machret);
+ }
+}
+
+/*++
+Function :
+ SEHExceptionThread
+
+ Entry point for the thread that will listen for exception in any other thread.
+
+#ifdef FEATURE_PAL_SXS
+ NOTE: This thread is not a PAL thread, and it must not be one. If it was,
+ exceptions on this thread would be delivered to the port this thread itself
+ is listening on.
+
+ In particular, if another thread overflows its stack, the exception handling
+ thread receives a message. It will try to create a PAL_DispatchException
+ frame on the faulting thread, which will likely fault. If the exception
+ processing thread is not a PAL thread, the process gets terminated with a
+ bus error; if the exception processing thread was a PAL thread, we would see
+ a hang (since no thread is listening for the exception message that gets sent).
+ Of the two ugly behaviors, the bus error is definitely favorable.
+
+ This means: no printf, no TRACE, no PAL allocation, no ExitProcess,
+ no LastError in this function and its helpers. To report fatal failure,
+ use NONPAL_RETAIL_ASSERT.
+#endif // FEATURE_PAL_SXS
+
+Parameters :
+ void *args - not used
+
+Return value :
+ Never returns
+--*/
+void *
+SEHExceptionThread(void *args)
+{
+ ForwardedExceptionList feList;
+ MachMessage sReplyOrForward;
+ MachMessage sMessage;
+ kern_return_t machret;
+ thread_act_t thread;
+
+ // Loop processing incoming messages forever.
+ while (true)
+ {
+ // Receive the next message.
+ sMessage.Receive(s_ExceptionPort);
+
+ NONPAL_TRACE("Received message %s (%08x) from (remote) %08x to (local) %08x\n",
+ sMessage.GetMessageTypeName(),
+ sMessage.GetMessageType(),
+ sMessage.GetRemotePort(),
+ sMessage.GetLocalPort());
+
+ if (sMessage.IsSetThreadRequest())
+ {
+ // Handle a request to set the thread context for the specified target thread.
+ CONTEXT sContext;
+ thread = sMessage.GetThreadContext(&sContext);
+
+ // Suspend the target thread
+ SuspendMachThread(thread);
+
+ machret = CONTEXT_SetThreadContextOnPort(thread, &sContext);
+ CHECK_MACH("CONTEXT_SetThreadContextOnPort", machret);
+
+ machret = thread_resume(thread);
+ CHECK_MACH("thread_resume", machret);
+ }
+ else if (sMessage.IsExceptionNotification())
+ {
+ // This is a notification of an exception occurring on another thread.
+ exception_type_t exceptionType = sMessage.GetException();
+ thread = sMessage.GetThread();
+
+#ifdef _DEBUG
+ if (NONPAL_TRACE_ENABLED)
+ {
+ NONPAL_TRACE("ExceptionNotification %s (%u) thread %08x flavor %u\n",
+ GetExceptionString(exceptionType),
+ exceptionType,
+ thread,
+ sMessage.GetThreadStateFlavor());
+
+ int subcode_count = sMessage.GetExceptionCodeCount();
+ for (int i = 0; i < subcode_count; i++)
+ NONPAL_TRACE("ExceptionNotification subcode[%d] = %llx\n", i, sMessage.GetExceptionCode(i));
+
+ x86_thread_state64_t threadStateActual;
+ unsigned int count = sizeof(threadStateActual) / sizeof(unsigned);
+ machret = thread_get_state(thread, x86_THREAD_STATE64, (thread_state_t)&threadStateActual, &count);
+ CHECK_MACH("thread_get_state", machret);
+
+ NONPAL_TRACE("ExceptionNotification actual rip %016llx rsp %016llx rbp %016llx rax %016llx r15 %016llx eflags %08llx\n",
+ threadStateActual.__rip,
+ threadStateActual.__rsp,
+ threadStateActual.__rbp,
+ threadStateActual.__rax,
+ threadStateActual.__r15,
+ threadStateActual.__rflags);
+
+ x86_exception_state64_t threadExceptionState;
+ unsigned int ehStateCount = sizeof(threadExceptionState) / sizeof(unsigned);
+ machret = thread_get_state(thread, x86_EXCEPTION_STATE64, (thread_state_t)&threadExceptionState, &ehStateCount);
+ CHECK_MACH("thread_get_state", machret);
+
+ NONPAL_TRACE("ExceptionNotification trapno %04x cpu %04x err %08x faultAddr %016llx\n",
+ threadExceptionState.__trapno,
+ threadExceptionState.__cpu,
+ threadExceptionState.__err,
+ threadExceptionState.__faultvaddr);
+ }
+#endif // _DEBUG
+
+ bool feFound = false;
+ feList.MoveFirst();
+
+ while (!feList.IsEOL())
+ {
+ mach_port_type_t ePortType;
+ if (mach_port_type(mach_task_self(), feList.Current->Thread, &ePortType) != KERN_SUCCESS || (ePortType & MACH_PORT_TYPE_DEAD_NAME))
+ {
+ NONPAL_TRACE("Forwarded exception: invalid thread port %08x\n", feList.Current->Thread);
+
+ // Unlink and delete the forwarded exception instance
+ feList.Delete();
+ }
+ else
+ {
+ if (feList.Current->Thread == thread)
+ {
+ bool isSameException = feList.Current->ExceptionType == exceptionType;
+ feFound = true;
+
+ // Locate the record of previously installed handlers that the target thread keeps.
+ CThreadMachExceptionHandlers *pHandlers = feList.Current->PalThread->GetSavedMachHandlers();
+
+ // Unlink and delete the forwarded exception instance
+ feList.Delete();
+
+ // Check if the current exception type matches the forwarded one and whether
+ // there's a handler for the particular exception we've been handed.
+ MachExceptionHandler sHandler;
+ if (isSameException && pHandlers->GetHandler(exceptionType, &sHandler))
+ {
+ NONPAL_TRACE("ForwardNotification thread %08x to handler %08x\n", thread, sHandler.m_handler);
+ sReplyOrForward.ForwardNotification(&sHandler, sMessage);
+ }
+ else
+ {
+ NONPAL_TRACE("ReplyToNotification KERN_FAILURE thread %08x port %08x sameException %d\n",
+ thread, sMessage.GetRemotePort(), isSameException);
+ sReplyOrForward.ReplyToNotification(sMessage, KERN_FAILURE);
+ }
+ break;
+ }
+
+ feList.MoveNext();
+ }
+ }
+
+ if (!feFound)
+ {
+ NONPAL_TRACE("HijackFaultingThread thread %08x\n", thread);
+ HijackFaultingThread(thread, mach_task_self(), sMessage);
+
+ // Send the result of handling the exception back in a reply.
+ NONPAL_TRACE("ReplyToNotification KERN_SUCCESS thread %08x port %08x\n", thread, sMessage.GetRemotePort());
+ sReplyOrForward.ReplyToNotification(sMessage, KERN_SUCCESS);
+ }
+ }
+ else if (sMessage.IsForwardExceptionRequest())
+ {
+ thread = sMessage.GetThread();
+
+ NONPAL_TRACE("ForwardExceptionRequest for thread %08x\n", thread);
+
+ // Suspend the faulting thread.
+ SuspendMachThread(thread);
+
+ // Set the context back to the original faulting state.
+ MachExceptionInfo *pExceptionInfo = sMessage.GetExceptionInfo();
+ pExceptionInfo->RestoreState(thread);
+
+ // Allocate an forwarded exception entry
+ ForwardedException *pfe = (ForwardedException *)malloc(sizeof(ForwardedException));
+ if (pfe == NULL)
+ {
+ NONPAL_RETAIL_ASSERT("Exception thread ran out of memory to track forwarded exception notifications");
+ }
+
+ // Save the forwarded exception entry away for the restarted exception message
+ pfe->Thread = thread;
+ pfe->ExceptionType = pExceptionInfo->ExceptionType;
+ pfe->PalThread = sMessage.GetPalThread();
+ feList.Add(pfe);
+
+ // Now let the thread run at the original exception context to restart the exception
+ NONPAL_TRACE("ForwardExceptionRequest resuming thread %08x exception type %08x\n", thread, pfe->ExceptionType);
+ machret = thread_resume(thread);
+ CHECK_MACH("thread_resume", machret);
+ }
+ else
+ {
+ NONPAL_RETAIL_ASSERT("Unknown message type: %u", sMessage.GetMessageType());
+ }
+ }
+}
+
+/*++
+Function :
+ MachExceptionInfo constructor
+
+ Saves the exception info from the exception notification message and
+ the current thread state.
+
+Parameters:
+ thread - thread port to restore
+ message - exception message
+
+Return value :
+ none
+--*/
+MachExceptionInfo::MachExceptionInfo(mach_port_t thread, MachMessage& message)
+{
+ kern_return_t machret;
+
+ ExceptionType = message.GetException();
+ SubcodeCount = message.GetExceptionCodeCount();
+ NONPAL_RETAIL_ASSERTE(SubcodeCount >= 0 && SubcodeCount <= 2);
+
+ for (int i = 0; i < SubcodeCount; i++)
+ Subcodes[i] = message.GetExceptionCode(i);
+
+ mach_msg_type_number_t count = x86_THREAD_STATE_COUNT;
+ machret = thread_get_state(thread, x86_THREAD_STATE, (thread_state_t)&ThreadState, &count);
+ CHECK_MACH("thread_get_state", machret);
+
+ count = x86_FLOAT_STATE_COUNT;
+ machret = thread_get_state(thread, x86_FLOAT_STATE, (thread_state_t)&FloatState, &count);
+ CHECK_MACH("thread_get_state(float)", machret);
+
+ count = x86_DEBUG_STATE_COUNT;
+ machret = thread_get_state(thread, x86_DEBUG_STATE, (thread_state_t)&DebugState, &count);
+ CHECK_MACH("thread_get_state(debug)", machret);
+}
+
+/*++
+Function :
+ MachExceptionInfo::RestoreState
+
+ Restore the thread to the saved exception info state.
+
+Parameters:
+ thread - thread port to restore
+
+Return value :
+ none
+--*/
+void MachExceptionInfo::RestoreState(mach_port_t thread)
+{
+ // If we are restarting a breakpoint, we need to bump the IP back one to
+ // point at the actual int 3 instructions.
+ if (ExceptionType == EXC_BREAKPOINT)
+ {
+ if (Subcodes[0] == EXC_I386_BPT)
+ {
+#ifdef _X86_
+ ThreadState.uts.ts32.eip--;
+#elif defined(_AMD64_)
+ ThreadState.uts.ts64.__rip--;
+#else
+#error Platform not supported
+#endif
+ }
+ }
+ kern_return_t machret = thread_set_state(thread, x86_THREAD_STATE, (thread_state_t)&ThreadState, x86_THREAD_STATE_COUNT);
+ CHECK_MACH("thread_set_state(thread)", machret);
+
+ machret = thread_set_state(thread, x86_FLOAT_STATE, (thread_state_t)&FloatState, x86_FLOAT_STATE_COUNT);
+ CHECK_MACH("thread_set_state(float)", machret);
+
+ machret = thread_set_state(thread, x86_DEBUG_STATE, (thread_state_t)&DebugState, x86_DEBUG_STATE_COUNT);
+ CHECK_MACH("thread_set_state(debug)", machret);
+}
+
+/*++
+Function :
+ MachSetThreadContext
+
+ Sets the context of the current thread by sending a notification
+ to the exception thread.
+
+Parameters:
+ lpContext - the CONTEXT to set the current thread
+
+Return value :
+ Doesn't return
+--*/
+PAL_NORETURN
+void
+MachSetThreadContext(CONTEXT *lpContext)
+{
+ // We need to send a message to the worker thread so that it can set our thread context.
+ MachMessage sRequest;
+ sRequest.SendSetThread(s_ExceptionPort, lpContext);
+
+ // Make sure we don't do anything
+ while (TRUE)
+ {
+ sched_yield();
+ }
+}
+
+
+/*++
+Function :
+ SEHInitializeMachExceptions
+
+ Initialize all SEH-related stuff related to mach exceptions
+
+ flags - PAL_INITIALIZE flags
+
+Return value :
+ TRUE if SEH support initialization succeeded
+ FALSE otherwise
+--*/
+BOOL
+SEHInitializeMachExceptions(DWORD flags)
+{
+ pthread_t exception_thread;
+ kern_return_t machret;
+
+ s_PalInitializeFlags = flags;
+
+ // Allocate a mach port that will listen in on exceptions
+ machret = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &s_ExceptionPort);
+ if (machret != KERN_SUCCESS)
+ {
+ ASSERT("mach_port_allocate failed: %d\n", machret);
+ UTIL_SetLastErrorFromMach(machret);
+ return FALSE;
+ }
+
+ // Insert the send right into the task
+ machret = mach_port_insert_right(mach_task_self(), s_ExceptionPort, s_ExceptionPort, MACH_MSG_TYPE_MAKE_SEND);
+ if (machret != KERN_SUCCESS)
+ {
+ ASSERT("mach_port_insert_right failed: %d\n", machret);
+ UTIL_SetLastErrorFromMach(machret);
+ return FALSE;
+ }
+
+ // Create the thread that will listen to the exception for all threads
+ int createret = pthread_create(&exception_thread, NULL, SEHExceptionThread, NULL);
+ if (createret != 0)
+ {
+ ERROR("pthread_create failed, error is %d (%s)\n", createret, strerror(createret));
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ return FALSE;
+ }
+
+#ifdef _DEBUG
+ if (NONPAL_TRACE_ENABLED)
+ {
+ CThreadMachExceptionHandlers taskHandlers;
+ machret = task_get_exception_ports(mach_task_self(),
+ PAL_EXC_ALL_MASK,
+ taskHandlers.m_masks,
+ &taskHandlers.m_nPorts,
+ taskHandlers.m_handlers,
+ taskHandlers.m_behaviors,
+ taskHandlers.m_flavors);
+
+ if (machret == KERN_SUCCESS)
+ {
+ NONPAL_TRACE("SEHInitializeMachExceptions: TASK PORT count %d\n", taskHandlers.m_nPorts);
+ for (mach_msg_type_number_t i = 0; i < taskHandlers.m_nPorts; i++)
+ {
+ NONPAL_TRACE("SEHInitializeMachExceptions: TASK PORT mask %08x handler: %08x behavior %08x flavor %u\n",
+ taskHandlers.m_masks[i],
+ taskHandlers.m_handlers[i],
+ taskHandlers.m_behaviors[i],
+ taskHandlers.m_flavors[i]);
+ }
+ }
+ else
+ {
+ NONPAL_TRACE("SEHInitializeMachExceptions: task_get_exception_ports FAILED %d %s\n", machret, mach_error_string(machret));
+ }
+ }
+#endif // _DEBUG
+
+#ifndef FEATURE_PAL_SXS
+ if (!SEHEnableMachExceptions())
+ {
+ return FALSE;
+ }
+#endif // !FEATURE_PAL_SXS
+
+ // Tell the system to ignore SIGPIPE signals rather than use the default
+ // behavior of terminating the process. Ignoring SIGPIPE will cause
+ // calls that would otherwise raise that signal to return EPIPE instead.
+ // The PAL expects EPIPE from those functions and won't handle a
+ // SIGPIPE signal.
+ signal(SIGPIPE, SIG_IGN);
+
+ // We're done
+ return TRUE;
+}
+
+/*++
+Function :
+ MachExceptionInitializeDebug
+
+ Initialize the mach exception handlers necessary for a managed debugger
+ to work
+
+Return value :
+ None
+--*/
+void MachExceptionInitializeDebug(void)
+{
+ if (s_DebugInitialized == FALSE)
+ {
+#ifndef FEATURE_PAL_SXS
+ kern_return_t MachRet;
+ MachRet = task_set_exception_ports(mach_task_self(),
+ PAL_EXC_DEBUGGING_MASK,
+ s_ExceptionPort,
+ EXCEPTION_DEFAULT,
+ MACHINE_THREAD_STATE);
+ if (MachRet != KERN_SUCCESS)
+ {
+ ASSERT("task_set_exception_ports failed: %d\n", MachRet);
+ TerminateProcess(GetCurrentProcess(), (UINT)(-1));
+ }
+#endif // !FEATURE_PAL_SXS
+ s_DebugInitialized = TRUE;
+ }
+}
+
+/*++
+Function :
+ SEHCleanupExceptionPort
+
+ Restore default exception port handler
+
+ (no parameters, no return value)
+
+Note :
+During PAL_Terminate, we reach a point where SEH isn't possible any more
+(handle manager is off, etc). Past that point, we can't avoid crashing on
+an exception.
+--*/
+void
+SEHCleanupExceptionPort(void)
+{
+ TRACE("Restoring default exception ports\n");
+#ifndef FEATURE_PAL_SXS
+ SEHDisableMachExceptions();
+#endif // !FEATURE_PAL_SXS
+ s_DebugInitialized = FALSE;
+}
+
+extern "C"
+void
+ActivationHandler(CONTEXT* context)
+{
+ if (g_activationFunction != NULL)
+ {
+ g_activationFunction(context);
+ }
+
+ RtlRestoreContext(context, NULL);
+ DebugBreak();
+}
+
+extern "C" void ActivationHandlerWrapper();
+extern "C" int ActivationHandlerReturnOffset;
+
+/*++
+Function :
+ InjectActivationInternal
+
+ Sets up the specified thread to call the ActivationHandler.
+
+Parameters:
+ pThread - PAL thread instance
+
+Return value :
+ PAL_ERROR
+--*/
+PAL_ERROR
+InjectActivationInternal(CPalThread* pThread)
+{
+ PAL_ERROR palError;
+
+ mach_port_t threadPort = pThread->GetMachPortSelf();
+ kern_return_t MachRet = thread_suspend(threadPort);
+ palError = (MachRet == KERN_SUCCESS) ? NO_ERROR : ERROR_GEN_FAILURE;
+
+ if (palError == NO_ERROR)
+ {
+ mach_msg_type_number_t count;
+
+ x86_exception_state64_t ExceptionState;
+ count = x86_EXCEPTION_STATE64_COUNT;
+ MachRet = thread_get_state(threadPort,
+ x86_EXCEPTION_STATE64,
+ (thread_state_t)&ExceptionState,
+ &count);
+ _ASSERT_MSG(MachRet == KERN_SUCCESS, "thread_get_state for x86_EXCEPTION_STATE64\n");
+
+ // Inject the activation only if the thread doesn't have a pending hardware exception
+ static const int MaxHardwareExceptionVector = 31;
+ if (ExceptionState.__trapno > MaxHardwareExceptionVector)
+ {
+ x86_thread_state64_t ThreadState;
+ count = x86_THREAD_STATE64_COUNT;
+ MachRet = thread_get_state(threadPort,
+ x86_THREAD_STATE64,
+ (thread_state_t)&ThreadState,
+ &count);
+ _ASSERT_MSG(MachRet == KERN_SUCCESS, "thread_get_state for x86_THREAD_STATE64\n");
+
+ if ((g_safeActivationCheckFunction != NULL) && g_safeActivationCheckFunction(ThreadState.__rip, /* checkingCurrentThread */ FALSE))
+ {
+ // TODO: it would be nice to preserve the red zone in case a jitter would want to use it
+ // Do we really care about unwinding through the wrapper?
+ size_t* sp = (size_t*)ThreadState.__rsp;
+ *(--sp) = ThreadState.__rip;
+ *(--sp) = ThreadState.__rbp;
+ size_t rbpAddress = (size_t)sp;
+ size_t contextAddress = (((size_t)sp) - sizeof(CONTEXT)) & ~15;
+ size_t returnAddressAddress = contextAddress - sizeof(size_t);
+ *(size_t*)(returnAddressAddress) = ActivationHandlerReturnOffset + (size_t)ActivationHandlerWrapper;
+
+ // Fill in the context in the helper frame with the full context of the suspended thread.
+ // The ActivationHandler will use the context to resume the execution of the thread
+ // after the activation function returns.
+ CONTEXT *pContext = (CONTEXT *)contextAddress;
+ pContext->ContextFlags = CONTEXT_FULL | CONTEXT_SEGMENTS;
+ MachRet = CONTEXT_GetThreadContextFromPort(threadPort, pContext);
+ _ASSERT_MSG(MachRet == KERN_SUCCESS, "CONTEXT_GetThreadContextFromPort\n");
+
+ // Make the instruction register point to ActivationHandler
+ ThreadState.__rip = (size_t)ActivationHandler;
+ ThreadState.__rsp = returnAddressAddress;
+ ThreadState.__rbp = rbpAddress;
+ ThreadState.__rdi = contextAddress;
+
+ MachRet = thread_set_state(threadPort,
+ x86_THREAD_STATE64,
+ (thread_state_t)&ThreadState,
+ count);
+ _ASSERT_MSG(MachRet == KERN_SUCCESS, "thread_set_state\n");
+ }
+ }
+
+ MachRet = thread_resume(threadPort);
+ palError = (MachRet == ERROR_SUCCESS) ? NO_ERROR : ERROR_GEN_FAILURE;
+ }
+ else
+ {
+ printf("Suspension failed with error 0x%x\n", palError);
+ }
+
+ return palError;
+}
+
+#endif // HAVE_MACH_EXCEPTIONS
diff --git a/src/pal/src/exception/machexception.h b/src/pal/src/exception/machexception.h
new file mode 100644
index 0000000000..18e31501b2
--- /dev/null
+++ b/src/pal/src/exception/machexception.h
@@ -0,0 +1,48 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+Module Name:
+
+ machexception.h
+
+Abstract:
+ Private mach exception handling utilities for SEH
+
+--*/
+
+#ifndef _MACHEXCEPTION_H_
+#define _MACHEXCEPTION_H_
+
+#include <mach/mach.h>
+#include <mach/mach_error.h>
+#include <mach/thread_status.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif // __cplusplus
+
+#define HIJACK_ON_SIGNAL 1
+
+// List of exception types we will be watching for
+// NOTE: if you change any of these, you need to adapt s_nMachExceptionPortsMax in thread.hpp
+#define PAL_EXC_ILLEGAL_MASK (EXC_MASK_BAD_INSTRUCTION | EXC_MASK_EMULATION)
+#define PAL_EXC_DEBUGGING_MASK (EXC_MASK_BREAKPOINT | EXC_MASK_SOFTWARE)
+#define PAL_EXC_MANAGED_MASK (EXC_MASK_BAD_ACCESS | EXC_MASK_ARITHMETIC)
+#define PAL_EXC_ALL_MASK (PAL_EXC_ILLEGAL_MASK | PAL_EXC_DEBUGGING_MASK | PAL_EXC_MANAGED_MASK)
+
+// Process and thread initialization/cleanup/context routines
+BOOL SEHInitializeMachExceptions(DWORD flags);
+void SEHCleanupExceptionPort (void);
+void MachExceptionInitializeDebug(void);
+PAL_NORETURN void MachSetThreadContext(CONTEXT *lpContext);
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif /* _MACHEXCEPTION_H_ */
+
diff --git a/src/pal/src/exception/machmessage.cpp b/src/pal/src/exception/machmessage.cpp
new file mode 100644
index 0000000000..a6f7e57484
--- /dev/null
+++ b/src/pal/src/exception/machmessage.cpp
@@ -0,0 +1,1383 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+Module Name:
+
+ machmessage.cpp
+
+Abstract:
+
+ Abstraction over Mach messages used during exception handling.
+
+--*/
+
+#include "config.h"
+#include "pal/dbgmsg.h"
+#include "pal/environ.h"
+#include "pal/malloc.hpp"
+#include "pal/thread.hpp"
+#include "machmessage.h"
+
+#if HAVE_MACH_EXCEPTIONS
+
+// Construct an empty message. Use Receive() to form a message that can be inspected or SendSetThread(),
+// ForwardNotification(), ReplyToNotification() or ForwardReply() to construct a message and sent it.
+MachMessage::MachMessage()
+{
+ m_fPortsOwned = false;
+ ResetMessage();
+}
+
+// Listen for the next message on the given port and initialize this class with the contents. The message type
+// must match one of the MessageTypes indicated above (or the process will be aborted).
+void MachMessage::Receive(mach_port_t hPort)
+{
+ kern_return_t machret;
+
+ // Erase any stale data.
+ ResetMessage();
+
+ // Pull the next Mach message into the buffer.
+ machret = mach_msg((mach_msg_header_t*)m_rgMessageBuffer,
+ MACH_RCV_MSG | MACH_RCV_LARGE | MACH_RCV_NOTIFY,
+ 0,
+ kcbMaxMessageSize,
+ hPort,
+ MACH_MSG_TIMEOUT_NONE,
+ MACH_PORT_NULL);
+ CHECK_MACH("mach_msg()", machret);
+
+ // Check it's one of the messages we're expecting.
+ switch (m_pMessage->header.msgh_id)
+ {
+ case SET_THREAD_MESSAGE_ID:
+ case FORWARD_EXCEPTION_MESSAGE_ID:
+ case EXCEPTION_RAISE_MESSAGE_ID:
+ case EXCEPTION_RAISE_STATE_MESSAGE_ID:
+ case EXCEPTION_RAISE_STATE_IDENTITY_MESSAGE_ID:
+ case EXCEPTION_RAISE_REPLY_MESSAGE_ID:
+ case EXCEPTION_RAISE_STATE_REPLY_MESSAGE_ID:
+ case EXCEPTION_RAISE_STATE_IDENTITY_REPLY_MESSAGE_ID:
+ case EXCEPTION_RAISE_64_MESSAGE_ID:
+ case EXCEPTION_RAISE_STATE_64_MESSAGE_ID:
+ case EXCEPTION_RAISE_STATE_IDENTITY_64_MESSAGE_ID:
+ case EXCEPTION_RAISE_REPLY_64_MESSAGE_ID:
+ case EXCEPTION_RAISE_STATE_REPLY_64_MESSAGE_ID:
+ case EXCEPTION_RAISE_STATE_IDENTITY_REPLY_64_MESSAGE_ID:
+ case NOTIFY_SEND_ONCE_MESSAGE_ID:
+ break;
+ default:
+ NONPAL_RETAIL_ASSERT("Unsupported message type: %u", m_pMessage->header.msgh_id);
+ }
+
+ m_fPortsOwned = true;
+}
+
+// Indicates whether the message is a request to set the context of a thread.
+bool MachMessage::IsSetThreadRequest()
+{
+ return m_pMessage->header.msgh_id == SET_THREAD_MESSAGE_ID;
+}
+
+// Indicates whether the message is a request to forward the exception
+bool MachMessage::IsForwardExceptionRequest()
+{
+ return m_pMessage->header.msgh_id == FORWARD_EXCEPTION_MESSAGE_ID;
+}
+
+// Indicates whether the message is a notification that a send-once message was destroyed by the receiver.
+bool MachMessage::IsSendOnceDestroyedNotify()
+{
+ return m_pMessage->header.msgh_id == NOTIFY_SEND_ONCE_MESSAGE_ID;
+}
+
+// Indicates whether the message is a notification of an exception.
+bool MachMessage::IsExceptionNotification()
+{
+ switch (m_pMessage->header.msgh_id)
+ {
+ case EXCEPTION_RAISE_MESSAGE_ID:
+ case EXCEPTION_RAISE_STATE_MESSAGE_ID:
+ case EXCEPTION_RAISE_STATE_IDENTITY_MESSAGE_ID:
+ case EXCEPTION_RAISE_64_MESSAGE_ID:
+ case EXCEPTION_RAISE_STATE_64_MESSAGE_ID:
+ case EXCEPTION_RAISE_STATE_IDENTITY_64_MESSAGE_ID:
+ return true;
+ default:
+ return false;
+ }
+}
+
+// Indicates whether the message is a reply to a notification of an exception.
+bool MachMessage::IsExceptionReply()
+{
+ switch (m_pMessage->header.msgh_id)
+ {
+ case EXCEPTION_RAISE_REPLY_MESSAGE_ID:
+ case EXCEPTION_RAISE_STATE_REPLY_MESSAGE_ID:
+ case EXCEPTION_RAISE_STATE_IDENTITY_REPLY_MESSAGE_ID:
+ case EXCEPTION_RAISE_REPLY_64_MESSAGE_ID:
+ case EXCEPTION_RAISE_STATE_REPLY_64_MESSAGE_ID:
+ case EXCEPTION_RAISE_STATE_IDENTITY_REPLY_64_MESSAGE_ID:
+ return true;
+ default:
+ return false;
+ }
+}
+
+// Returns the type code for a received message.
+MachMessage::MessageType MachMessage::GetMessageType()
+{
+ return (MessageType)m_pMessage->header.msgh_id;
+}
+
+// Returns a textual form of the type of a received message. Useful for logging.
+const char *MachMessage::GetMessageTypeName()
+{
+ switch (GetMessageType())
+ {
+ case SET_THREAD_MESSAGE_ID:
+ return "SET_THREAD";
+ case FORWARD_EXCEPTION_MESSAGE_ID:
+ return "FORWARD_EXCEPTION";
+ case EXCEPTION_RAISE_MESSAGE_ID:
+ return "EXCEPTION_RAISE";
+ case EXCEPTION_RAISE_REPLY_MESSAGE_ID:
+ return "EXCEPTION_RAISE_REPLY";
+ case EXCEPTION_RAISE_STATE_MESSAGE_ID:
+ return "EXCEPTION_RAISE_STATE";
+ case EXCEPTION_RAISE_STATE_REPLY_MESSAGE_ID:
+ return "EXCEPTION_RAISE_STATE_REPLY";
+ case EXCEPTION_RAISE_STATE_IDENTITY_MESSAGE_ID:
+ return "EXCEPTION_RAISE_STATE_IDENTITY";
+ case EXCEPTION_RAISE_STATE_IDENTITY_REPLY_MESSAGE_ID:
+ return "EXCEPTION_RAISE_STATE_IDENTITY_REPLY";
+ case EXCEPTION_RAISE_64_MESSAGE_ID:
+ return "EXCEPTION_RAISE_64";
+ case EXCEPTION_RAISE_REPLY_64_MESSAGE_ID:
+ return "EXCEPTION_RAISE_REPLY_64";
+ case EXCEPTION_RAISE_STATE_64_MESSAGE_ID:
+ return "EXCEPTION_RAISE_STATE_64";
+ case EXCEPTION_RAISE_STATE_REPLY_64_MESSAGE_ID:
+ return "EXCEPTION_RAISE_STATE_REPLY_64";
+ case EXCEPTION_RAISE_STATE_IDENTITY_64_MESSAGE_ID:
+ return "EXCEPTION_RAISE_STATE_IDENTITY_64";
+ case EXCEPTION_RAISE_STATE_IDENTITY_REPLY_64_MESSAGE_ID:
+ return "EXCEPTION_RAISE_STATE_IDENTITY_REPLY_64";
+ case NOTIFY_SEND_ONCE_MESSAGE_ID:
+ return "NOTIFY_SEND_ONCE";
+ default:
+ return "<unknown message type>";
+ }
+}
+
+// Returns the destination port (i.e. the port we listened on to receive this message).
+mach_port_t MachMessage::GetLocalPort()
+{
+ return m_pMessage->header.msgh_local_port;
+}
+
+// Returns the source port (the port sending the message) unless no reply is expected, in which case
+// MACH_PORT_NULL is returned instead.
+mach_port_t MachMessage::GetRemotePort()
+{
+ return m_pMessage->header.msgh_remote_port;
+}
+
+// Do the work of getting ports from the message.
+// * fCalculate -- calculate the thread port if the message did not contain it.
+// * fValidate -- failfast if the message was not one expected to have a (calculable) thread port.
+void MachMessage::GetPorts(bool fCalculate, bool fValidThread)
+{
+ switch (m_pMessage->header.msgh_id)
+ {
+ case SET_THREAD_MESSAGE_ID:
+ m_hThread = m_pMessage->data.set_thread.thread;
+ break;
+
+ case FORWARD_EXCEPTION_MESSAGE_ID:
+ m_hThread = m_pMessage->data.forward_exception.thread;
+ break;
+
+ case EXCEPTION_RAISE_MESSAGE_ID:
+ m_hThread = m_pMessage->data.raise.thread_port.name;
+ m_hTask = m_pMessage->data.raise.task_port.name;
+ break;
+
+ case EXCEPTION_RAISE_64_MESSAGE_ID:
+ m_hThread = m_pMessage->data.raise_64.thread_port.name;
+ m_hTask = m_pMessage->data.raise_64.task_port.name;
+ break;
+
+ case EXCEPTION_RAISE_STATE_MESSAGE_ID:
+ if (fCalculate && m_hThread == MACH_PORT_NULL)
+ {
+ // This is a tricky case since the message itself doesn't contain the target thread.
+ m_hThread = GetThreadFromState(m_pMessage->data.raise_state.flavor,
+ m_pMessage->data.raise_state.old_state);
+ }
+ break;
+
+ case EXCEPTION_RAISE_STATE_64_MESSAGE_ID:
+ if (fCalculate && m_hThread == MACH_PORT_NULL)
+ {
+ // This is a tricky case since the message itself doesn't contain the target thread.
+ m_hThread = GetThreadFromState(m_pMessage->data.raise_state_64.flavor,
+ m_pMessage->data.raise_state_64.old_state);
+ }
+ break;
+
+ case EXCEPTION_RAISE_STATE_IDENTITY_MESSAGE_ID:
+ m_hThread = m_pMessage->data.raise_state_identity.thread_port.name;
+ m_hTask = m_pMessage->data.raise_state_identity.task_port.name;
+ break;
+
+ case EXCEPTION_RAISE_STATE_IDENTITY_64_MESSAGE_ID:
+ m_hThread = m_pMessage->data.raise_state_identity_64.thread_port.name;
+ m_hTask = m_pMessage->data.raise_state_identity_64.task_port.name;
+ break;
+
+ default:
+ if (fValidThread)
+ {
+ NONPAL_RETAIL_ASSERT("Can only get thread from notification message.");
+ }
+ break;
+ }
+}
+
+// Get the properties of a set thread or forward exception request. Fills in the provided
+// context structure with the context from the message and returns the target thread to
+// which the context should be applied.
+thread_act_t MachMessage::GetThreadContext(CONTEXT *pContext)
+{
+ NONPAL_ASSERTE(IsSetThreadRequest());
+
+ memcpy(pContext, &m_pMessage->data.set_thread.new_context, sizeof(CONTEXT));
+ m_hThread = m_pMessage->data.set_thread.thread;
+ return m_hThread;
+}
+
+// Get the target thread for an exception notification message.
+thread_act_t MachMessage::GetThread()
+{
+ GetPorts(true /* fCalculate */, true /* fValidThread */);
+ return m_hThread;
+}
+
+// Get the exception type for an exception notification message.
+exception_type_t MachMessage::GetException()
+{
+ switch (m_pMessage->header.msgh_id)
+ {
+ case EXCEPTION_RAISE_MESSAGE_ID:
+ return m_pMessage->data.raise.exception;
+
+ case EXCEPTION_RAISE_64_MESSAGE_ID:
+ return m_pMessage->data.raise_64.exception;
+
+ case EXCEPTION_RAISE_STATE_MESSAGE_ID:
+ return m_pMessage->data.raise_state.exception;
+
+ case EXCEPTION_RAISE_STATE_64_MESSAGE_ID:
+ return m_pMessage->data.raise_state_64.exception;
+
+ case EXCEPTION_RAISE_STATE_IDENTITY_MESSAGE_ID:
+ return m_pMessage->data.raise_state_identity.exception;
+
+ case EXCEPTION_RAISE_STATE_IDENTITY_64_MESSAGE_ID:
+ return m_pMessage->data.raise_state_identity_64.exception;
+
+ default:
+ NONPAL_RETAIL_ASSERT("Can only get exception from notification message.");
+ }
+}
+
+// Get the count of sub-codes for an exception notification message.
+int MachMessage::GetExceptionCodeCount()
+{
+ switch (m_pMessage->header.msgh_id)
+ {
+ case EXCEPTION_RAISE_MESSAGE_ID:
+ return m_pMessage->data.raise.code_count;
+
+ case EXCEPTION_RAISE_64_MESSAGE_ID:
+ return m_pMessage->data.raise_64.code_count;
+
+ case EXCEPTION_RAISE_STATE_MESSAGE_ID:
+ return m_pMessage->data.raise_state.code_count;
+
+ case EXCEPTION_RAISE_STATE_64_MESSAGE_ID:
+ return m_pMessage->data.raise_state_64.code_count;
+
+ case EXCEPTION_RAISE_STATE_IDENTITY_MESSAGE_ID:
+ return m_pMessage->data.raise_state_identity.code_count;
+
+ case EXCEPTION_RAISE_STATE_IDENTITY_64_MESSAGE_ID:
+ return m_pMessage->data.raise_state_identity_64.code_count;
+
+ default:
+ NONPAL_RETAIL_ASSERT("Can only get exception code count from notification message.");
+ }
+}
+
+// Get the exception sub-code at the specified zero-based index for an exception notification message.
+MACH_EH_TYPE(exception_data_type_t) MachMessage::GetExceptionCode(int iIndex)
+{
+ if (iIndex < 0 || iIndex >= GetExceptionCodeCount())
+ {
+ NONPAL_RETAIL_ASSERT("GetExceptionCode() index out of range.");
+ }
+
+ switch (m_pMessage->header.msgh_id)
+ {
+ case EXCEPTION_RAISE_MESSAGE_ID:
+ return (MACH_EH_TYPE(exception_data_type_t))m_pMessage->data.raise.code[iIndex];
+
+ case EXCEPTION_RAISE_64_MESSAGE_ID:
+ return m_pMessage->data.raise_64.code[iIndex];
+
+ case EXCEPTION_RAISE_STATE_MESSAGE_ID:
+ return (MACH_EH_TYPE(exception_data_type_t))m_pMessage->data.raise_state.code[iIndex];
+
+ case EXCEPTION_RAISE_STATE_64_MESSAGE_ID:
+ return m_pMessage->data.raise_state_64.code[iIndex];
+
+ case EXCEPTION_RAISE_STATE_IDENTITY_MESSAGE_ID:
+ return (MACH_EH_TYPE(exception_data_type_t))m_pMessage->data.raise_state_identity.code[iIndex];
+
+ case EXCEPTION_RAISE_STATE_IDENTITY_64_MESSAGE_ID:
+ return m_pMessage->data.raise_state_identity_64.code[iIndex];
+
+ default:
+ NONPAL_RETAIL_ASSERT("Can only get exception code from notification message.");
+ }
+}
+
+// Fetch the thread state flavor from a notification or reply message (return THREAD_STATE_NONE for the
+// messages that don't contain a thread state).
+thread_state_flavor_t MachMessage::GetThreadStateFlavor()
+{
+ switch (m_pMessage->header.msgh_id)
+ {
+ case EXCEPTION_RAISE_MESSAGE_ID:
+ case EXCEPTION_RAISE_REPLY_MESSAGE_ID:
+ case EXCEPTION_RAISE_64_MESSAGE_ID:
+ case EXCEPTION_RAISE_REPLY_64_MESSAGE_ID:
+ return THREAD_STATE_NONE;
+
+ case EXCEPTION_RAISE_STATE_MESSAGE_ID:
+ return m_pMessage->data.raise_state.flavor;
+
+ case EXCEPTION_RAISE_STATE_64_MESSAGE_ID:
+ return m_pMessage->data.raise_state_64.flavor;
+
+ case EXCEPTION_RAISE_STATE_IDENTITY_MESSAGE_ID:
+ return m_pMessage->data.raise_state_identity.flavor;
+
+ case EXCEPTION_RAISE_STATE_IDENTITY_64_MESSAGE_ID:
+ return m_pMessage->data.raise_state_identity_64.flavor;
+
+ case EXCEPTION_RAISE_STATE_REPLY_MESSAGE_ID:
+ return m_pMessage->data.raise_state_reply.flavor;
+
+ case EXCEPTION_RAISE_STATE_REPLY_64_MESSAGE_ID:
+ return m_pMessage->data.raise_state_reply_64.flavor;
+
+ case EXCEPTION_RAISE_STATE_IDENTITY_REPLY_MESSAGE_ID:
+ return m_pMessage->data.raise_state_identity_reply.flavor;
+
+ case EXCEPTION_RAISE_STATE_IDENTITY_REPLY_64_MESSAGE_ID:
+ return m_pMessage->data.raise_state_identity_reply_64.flavor;
+
+ default:
+ NONPAL_RETAIL_ASSERT("Unsupported message type: %u", m_pMessage->header.msgh_id);
+ }
+}
+
+// Get the thread state with the given flavor from the exception or exception reply message. If the message
+// doesn't contain a thread state or the flavor of the state in the message doesn't match, the state will be
+// fetched directly from the target thread instead (which can be computed implicitly for exception messages or
+// passed explicitly for reply messages).
+mach_msg_type_number_t MachMessage::GetThreadState(thread_state_flavor_t eFlavor, thread_state_t pState, thread_act_t thread)
+{
+ mach_msg_type_number_t count;
+ kern_return_t machret;
+
+ switch (m_pMessage->header.msgh_id)
+ {
+ case EXCEPTION_RAISE_MESSAGE_ID:
+ case EXCEPTION_RAISE_REPLY_MESSAGE_ID:
+ case EXCEPTION_RAISE_64_MESSAGE_ID:
+ case EXCEPTION_RAISE_REPLY_64_MESSAGE_ID:
+ // No state in the message, fall through to get it directly from the thread.
+ break;
+
+ case EXCEPTION_RAISE_STATE_MESSAGE_ID:
+ {
+ // There's a state in the message, but we need to check that the flavor matches what the caller's
+ // after (if not we'll fall through and get the correct flavor below).
+ if (m_pMessage->data.raise_state.flavor == eFlavor)
+ {
+ count = m_pMessage->data.raise_state.old_state_count;
+ memcpy(pState, m_pMessage->data.raise_state.old_state, count * sizeof(natural_t));
+ return count;
+ }
+ break;
+ }
+
+ case EXCEPTION_RAISE_STATE_64_MESSAGE_ID:
+ {
+ // There's a state in the message, but we need to check that the flavor matches what the caller's
+ // after (if not we'll fall through and get the correct flavor below).
+ if (m_pMessage->data.raise_state_64.flavor == eFlavor)
+ {
+ count = m_pMessage->data.raise_state_64.old_state_count;
+ memcpy(pState, m_pMessage->data.raise_state_64.old_state, count * sizeof(natural_t));
+ return count;
+ }
+ break;
+ }
+
+ case EXCEPTION_RAISE_STATE_IDENTITY_MESSAGE_ID:
+ {
+ // There's a state in the message, but we need to check that the flavor matches what the caller's
+ // after (if not we'll fall through and get the correct flavor below).
+ if (m_pMessage->data.raise_state_identity.flavor == eFlavor)
+ {
+ count = m_pMessage->data.raise_state_identity.old_state_count;
+ memcpy(pState, m_pMessage->data.raise_state_identity.old_state, count * sizeof(natural_t));
+ return count;
+ }
+ break;
+ }
+
+ case EXCEPTION_RAISE_STATE_IDENTITY_64_MESSAGE_ID:
+ {
+ // There's a state in the message, but we need to check that the flavor matches what the caller's
+ // after (if not we'll fall through and get the correct flavor below).
+ if (m_pMessage->data.raise_state_identity_64.flavor == eFlavor)
+ {
+ count = m_pMessage->data.raise_state_identity_64.old_state_count;
+ memcpy(pState, m_pMessage->data.raise_state_identity_64.old_state, count * sizeof(natural_t));
+ return count;
+ }
+ break;
+ }
+
+ case EXCEPTION_RAISE_STATE_REPLY_MESSAGE_ID:
+ {
+ // There's a state in the message, but we need to check that the flavor matches what the caller's
+ // after (if not we'll fall through and get the correct flavor below).
+ if (m_pMessage->data.raise_state_reply.flavor == eFlavor)
+ {
+ count = m_pMessage->data.raise_state_reply.new_state_count;
+ memcpy(pState, m_pMessage->data.raise_state_reply.new_state, count * sizeof(natural_t));
+ return count;
+ }
+ break;
+ }
+
+ case EXCEPTION_RAISE_STATE_REPLY_64_MESSAGE_ID:
+ {
+ // There's a state in the message, but we need to check that the flavor matches what the caller's
+ // after (if not we'll fall through and get the correct flavor below).
+ if (m_pMessage->data.raise_state_reply_64.flavor == eFlavor)
+ {
+ count = m_pMessage->data.raise_state_reply_64.new_state_count;
+ memcpy(pState, m_pMessage->data.raise_state_reply_64.new_state, count * sizeof(natural_t));
+ return count;
+ }
+ break;
+ }
+
+ case EXCEPTION_RAISE_STATE_IDENTITY_REPLY_MESSAGE_ID:
+ {
+ // There's a state in the message, but we need to check that the flavor matches what the caller's
+ // after (if not we'll fall through and get the correct flavor below).
+ if (m_pMessage->data.raise_state_identity_reply.flavor == eFlavor)
+ {
+ count = m_pMessage->data.raise_state_identity_reply.new_state_count;
+ memcpy(pState, m_pMessage->data.raise_state_identity_reply.new_state, count * sizeof(natural_t));
+ return count;
+ }
+ break;
+ }
+
+ case EXCEPTION_RAISE_STATE_IDENTITY_REPLY_64_MESSAGE_ID:
+ {
+ // There's a state in the message, but we need to check that the flavor matches what the caller's
+ // after (if not we'll fall through and get the correct flavor below).
+ if (m_pMessage->data.raise_state_identity_reply_64.flavor == eFlavor)
+ {
+ count = m_pMessage->data.raise_state_identity_reply_64.new_state_count;
+ memcpy(pState, m_pMessage->data.raise_state_identity_reply_64.new_state, count * sizeof(natural_t));
+ return count;
+ }
+ break;
+ }
+
+ default:
+ NONPAL_RETAIL_ASSERT("Unsupported message type for requesting thread state.");
+ }
+
+ // No state in the message or the flavor didn't match. Get the requested flavor of state directly from the
+ // thread instead.
+ count = THREAD_STATE_MAX;
+ machret = thread_get_state(thread ? thread : GetThread(), eFlavor, (thread_state_t)pState, &count);
+ CHECK_MACH("thread_get_state()", machret);
+
+ return count;
+}
+
+// Fetch the return code from a reply type message.
+kern_return_t MachMessage::GetReturnCode()
+{
+ switch (m_pMessage->header.msgh_id)
+ {
+ case EXCEPTION_RAISE_REPLY_MESSAGE_ID:
+ return m_pMessage->data.raise_reply.ret;
+
+ case EXCEPTION_RAISE_REPLY_64_MESSAGE_ID:
+ return m_pMessage->data.raise_reply_64.ret;
+
+ case EXCEPTION_RAISE_STATE_REPLY_MESSAGE_ID:
+ return m_pMessage->data.raise_state_reply.ret;
+
+ case EXCEPTION_RAISE_STATE_REPLY_64_MESSAGE_ID:
+ return m_pMessage->data.raise_state_reply_64.ret;
+
+ case EXCEPTION_RAISE_STATE_IDENTITY_REPLY_MESSAGE_ID:
+ return m_pMessage->data.raise_state_identity_reply.ret;
+
+ case EXCEPTION_RAISE_STATE_IDENTITY_REPLY_64_MESSAGE_ID:
+ return m_pMessage->data.raise_state_identity_reply_64.ret;
+
+ default:
+ NONPAL_RETAIL_ASSERT("Unsupported message type: %u", m_pMessage->header.msgh_id);
+ }
+}
+
+// Initialize and send a request to set the register context of a particular thread.
+void MachMessage::SendSetThread(mach_port_t hServerPort, CONTEXT *pContext)
+{
+ kern_return_t machret;
+
+ // Set the message type.
+ m_pMessage->header.msgh_id = SET_THREAD_MESSAGE_ID;
+
+ // Initialize the fields that don't need any further input (this depends on the message type having been
+ // set above).
+ InitFixedFields();
+
+ // Initialize type-specific fields. The receiving end is responsible for deallocating the thread port.
+ m_pMessage->data.set_thread.thread = mach_thread_self();
+ memcpy(&m_pMessage->data.set_thread.new_context, pContext, sizeof(CONTEXT));
+
+ // Initialize header fields.
+ m_pMessage->header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0);
+ m_pMessage->header.msgh_remote_port = hServerPort; // Destination port
+ m_pMessage->header.msgh_local_port = MACH_PORT_NULL; // We expect no reply
+
+ // Set the message header size field based on the contents of the message (call this function after all
+ // other fields have been initialized).
+ InitMessageSize();
+
+ // Send the formatted message.
+ machret = mach_msg((mach_msg_header_t*)m_pMessage,
+ MACH_SEND_MSG | MACH_MSG_OPTION_NONE,
+ m_pMessage->header.msgh_size,
+ 0,
+ MACH_PORT_NULL,
+ MACH_MSG_TIMEOUT_NONE,
+ MACH_PORT_NULL);
+ CHECK_MACH("mach_msg()", machret);
+
+ // Erase any stale data. (This may not finish executing; nothing is needed to be freed here.)
+ ResetMessage();
+}
+
+void MachMessage::SendForwardException(mach_port_t hServerPort, MachExceptionInfo *pExceptionInfo, CPalThread *ppalThread)
+{
+ kern_return_t machret;
+
+ // Set the message type.
+ m_pMessage->header.msgh_id = FORWARD_EXCEPTION_MESSAGE_ID;
+
+ // Initialize the fields that don't need any further input (this depends on the message type having been
+ // set above).
+ InitFixedFields();
+
+ // Initialize type-specific fields. The receiving end is responsible for deallocating the thread port.
+ m_pMessage->data.forward_exception.thread = mach_thread_self();
+ m_pMessage->data.forward_exception.ppalThread = ppalThread;
+ memcpy(&m_pMessage->data.forward_exception.exception_info, pExceptionInfo, sizeof(MachExceptionInfo));
+
+ // Initialize header fields.
+ m_pMessage->header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0);
+ m_pMessage->header.msgh_remote_port = hServerPort; // Destination port
+ m_pMessage->header.msgh_local_port = MACH_PORT_NULL; // We expect no reply
+
+ // Set the message header size field based on the contents of the message (call this function after all
+ // other fields have been initialized).
+ InitMessageSize();
+
+ // Send the formatted message.
+ machret = mach_msg((mach_msg_header_t*)m_pMessage,
+ MACH_SEND_MSG | MACH_MSG_OPTION_NONE,
+ m_pMessage->header.msgh_size,
+ 0,
+ MACH_PORT_NULL,
+ MACH_MSG_TIMEOUT_NONE,
+ MACH_PORT_NULL);
+ CHECK_MACH("mach_msg()", machret);
+
+ // Erase any stale data.
+ ResetMessage();
+}
+
+// Returns the pal thread instance for the forward exception message
+CPalThread *MachMessage::GetPalThread()
+{
+ NONPAL_ASSERTE(IsForwardExceptionRequest());
+ return m_pMessage->data.forward_exception.ppalThread;
+}
+
+MachExceptionInfo *MachMessage::GetExceptionInfo()
+{
+ NONPAL_ASSERTE(IsForwardExceptionRequest());
+ return &m_pMessage->data.forward_exception.exception_info;
+}
+
+// Initialize the message to represent a forwarded version of the given exception notification message and
+// send that message to the chain-back handler previously registered for the exception type being notified.
+// The new message takes account of the fact that the target handler may not have requested the same notification
+// behavior or flavor as our handler. A new Mach port is created to receive the reply, and this port is returned
+// to the caller. Clean up the message afterwards.
+void MachMessage::ForwardNotification(MachExceptionHandler *pHandler, MachMessage& message)
+{
+ kern_return_t machret;
+
+ // Set the message type.
+ m_pMessage->header.msgh_id = MapBehaviorToNotificationType(pHandler->m_behavior);
+
+ // Initialize the fields that don't need any further input (this depends on the message type having been
+ // set above).
+ InitFixedFields();
+
+ // Copy data from the incoming message. Use the getter and setter abstractions to simplify the act that
+ // the two messages may be in different formats (e.g. RAISE vs RAISE_STATE). We silently drop data that is
+ // not needed in the outgoing message and synthesize any required data that is not present in the incoming
+ // message.
+ SetThread(message.GetThread());
+ SetException(message.GetException());
+
+ int cCodes = message.GetExceptionCodeCount();
+ SetExceptionCodeCount(cCodes);
+ for (int i = 0; i < cCodes; i++)
+ SetExceptionCode(i, message.GetExceptionCode(i));
+
+ // Don't bother fetching thread state unless the destination actually requires it.
+ if (pHandler->m_flavor != THREAD_STATE_NONE)
+ {
+ thread_state_data_t threadState;
+ mach_msg_type_number_t count = message.GetThreadState(pHandler->m_flavor, (thread_state_t)&threadState);
+ SetThreadState(pHandler->m_flavor, (thread_state_t)&threadState, count);
+ }
+
+ // Initialize header fields.
+ m_pMessage->header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MOVE_SEND_ONCE);
+ m_pMessage->header.msgh_remote_port = pHandler->m_handler; // Forward to here
+ m_pMessage->header.msgh_local_port = message.GetRemotePort(); // The reply will come here
+
+ // Set the message header size field based on the contents of the message (call this function after all
+ // other fields have been initialized).
+ InitMessageSize();
+
+ // Send the formatted message.
+ machret = mach_msg((mach_msg_header_t*)m_pMessage,
+ MACH_SEND_MSG | MACH_MSG_OPTION_NONE,
+ m_pMessage->header.msgh_size,
+ 0,
+ MACH_PORT_NULL,
+ MACH_MSG_TIMEOUT_NONE,
+ MACH_PORT_NULL);
+ CHECK_MACH("mach_msg()", machret);
+
+ // Erase any stale data.
+ ResetMessage();
+}
+
+// Initialize the message to represent a reply to the given exception notification message
+// and send that reply back to the original sender of the notification. This is used when
+// our handler handles the exception rather than forwarding it to a chain-back handler.
+// Clean up the message afterwards.
+void MachMessage::ReplyToNotification(MachMessage& message, kern_return_t eResult)
+{
+ kern_return_t machret;
+
+ // Set the message type.
+ m_pMessage->header.msgh_id = MapNotificationToReplyType(message.m_pMessage->header.msgh_id);
+
+ // Initialize the fields that don't need any further input (this depends on the message type having been
+ // set above).
+ InitFixedFields();
+
+ SetReturnCode(eResult);
+
+ thread_state_flavor_t eNotificationFlavor = message.GetThreadStateFlavor();
+ if (eNotificationFlavor != THREAD_STATE_NONE)
+ {
+ // If the reply requires a thread state be sure to get it from the thread directly rather than the
+ // notification message (handling the exception is likely to have changed the thread state).
+ thread_state_data_t threadState;
+ mach_msg_type_number_t count = THREAD_STATE_MAX;
+ machret = thread_get_state(message.GetThread(), eNotificationFlavor, (thread_state_t)&threadState, &count);
+
+ SetThreadState(eNotificationFlavor, (thread_state_t)&threadState, count);
+ }
+
+ // Initialize header fields.
+ m_pMessage->header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE, 0);
+ m_pMessage->header.msgh_remote_port = message.GetRemotePort(); // Reply goes back to sender
+ m_pMessage->header.msgh_local_port = 0; // No reply to this expected
+
+ // Set the message header size field based on the contents of the message (call this function after all
+ // other fields have been initialized).
+ InitMessageSize();
+
+ // Send the formatted message.
+ machret = mach_msg((mach_msg_header_t*)m_pMessage,
+ MACH_SEND_MSG | MACH_MSG_OPTION_NONE,
+ m_pMessage->header.msgh_size,
+ 0,
+ MACH_PORT_NULL,
+ MACH_MSG_TIMEOUT_NONE,
+ MACH_PORT_NULL);
+ CHECK_MACH("mach_msg()", machret);
+
+ // Erase any stale data.
+ ResetMessage();
+}
+
+// Re-initializes this data structure (to the same state as default construction, containing no message).
+void MachMessage::ResetMessage()
+{
+ // Clean up ports if we own them.
+ if (m_fPortsOwned)
+ {
+ kern_return_t machret;
+
+ GetPorts(false /* fCalculate */, false /* fValidThread */);
+ if (m_hThread != MACH_PORT_NULL)
+ {
+ machret = mach_port_deallocate(mach_task_self(), m_hThread);
+ CHECK_MACH("mach_port_deallocate(m_hThread)", machret);
+ }
+
+ if (m_hTask != MACH_PORT_NULL)
+ {
+ machret = mach_port_deallocate(mach_task_self(), m_hTask);
+ CHECK_MACH("mach_port_deallocate(m_hTask)", machret);
+ }
+ }
+
+#ifdef _DEBUG
+ memset(this, 0xcc, sizeof(*this));
+#endif
+
+ m_pMessage = (mach_message_t*)m_rgMessageBuffer;
+ m_hThread = MACH_PORT_NULL;
+ m_hTask = MACH_PORT_NULL;
+ m_fPortsOwned = false;
+}
+
+// Initialize those fields of a message that are invariant. This method expects that the msgh_id field has
+// been filled in prior to the call so it can determine which non-header fields to initialize.
+void MachMessage::InitFixedFields()
+{
+ switch (m_pMessage->header.msgh_id)
+ {
+ case SET_THREAD_MESSAGE_ID:
+ break;
+
+ case FORWARD_EXCEPTION_MESSAGE_ID:
+ break;
+
+ case EXCEPTION_RAISE_MESSAGE_ID:
+ m_pMessage->data.raise.msgh_body.msgh_descriptor_count = 0;
+ m_pMessage->data.raise.ndr = NDR_record;
+ m_pMessage->data.raise.task_port.name = mach_task_self();
+ m_pMessage->data.raise.task_port.pad1 = 0;
+ m_pMessage->data.raise.task_port.pad2 = 0;
+ m_pMessage->data.raise.task_port.disposition = MACH_MSG_TYPE_COPY_SEND;
+ m_pMessage->data.raise.task_port.type = MACH_MSG_PORT_DESCRIPTOR;
+ m_hTask = mach_task_self();
+ break;
+
+ case EXCEPTION_RAISE_64_MESSAGE_ID:
+ m_pMessage->data.raise_64.msgh_body.msgh_descriptor_count = 0;
+ m_pMessage->data.raise_64.ndr = NDR_record;
+ m_pMessage->data.raise_64.task_port.name = mach_task_self();
+ m_pMessage->data.raise_64.task_port.pad1 = 0;
+ m_pMessage->data.raise_64.task_port.pad2 = 0;
+ m_pMessage->data.raise_64.task_port.disposition = MACH_MSG_TYPE_COPY_SEND;
+ m_pMessage->data.raise_64.task_port.type = MACH_MSG_PORT_DESCRIPTOR;
+ m_hTask = mach_task_self();
+ break;
+
+ case EXCEPTION_RAISE_STATE_MESSAGE_ID:
+ m_pMessage->data.raise_state.ndr = NDR_record;
+ break;
+
+ case EXCEPTION_RAISE_STATE_64_MESSAGE_ID:
+ m_pMessage->data.raise_state_64.ndr = NDR_record;
+ break;
+
+ case EXCEPTION_RAISE_STATE_IDENTITY_MESSAGE_ID:
+ m_pMessage->data.raise_state_identity.msgh_body.msgh_descriptor_count = 0;
+ m_pMessage->data.raise_state_identity.ndr = NDR_record;
+ m_pMessage->data.raise_state_identity.task_port.name = mach_task_self();
+ m_pMessage->data.raise_state_identity.task_port.pad1 = 0;
+ m_pMessage->data.raise_state_identity.task_port.pad2 = 0;
+ m_pMessage->data.raise_state_identity.task_port.disposition = MACH_MSG_TYPE_COPY_SEND;
+ m_pMessage->data.raise_state_identity.task_port.type = MACH_MSG_PORT_DESCRIPTOR;
+ m_hTask = mach_task_self();
+ break;
+
+ case EXCEPTION_RAISE_STATE_IDENTITY_64_MESSAGE_ID:
+ m_pMessage->data.raise_state_identity_64.msgh_body.msgh_descriptor_count = 0;
+ m_pMessage->data.raise_state_identity_64.ndr = NDR_record;
+ m_pMessage->data.raise_state_identity_64.task_port.name = mach_task_self();
+ m_pMessage->data.raise_state_identity_64.task_port.pad1 = 0;
+ m_pMessage->data.raise_state_identity_64.task_port.pad2 = 0;
+ m_pMessage->data.raise_state_identity_64.task_port.disposition = MACH_MSG_TYPE_COPY_SEND;
+ m_pMessage->data.raise_state_identity_64.task_port.type = MACH_MSG_PORT_DESCRIPTOR;
+ m_hTask = mach_task_self();
+ break;
+
+ case EXCEPTION_RAISE_REPLY_MESSAGE_ID:
+ m_pMessage->data.raise_reply.ndr = NDR_record;
+ break;
+
+ case EXCEPTION_RAISE_REPLY_64_MESSAGE_ID:
+ m_pMessage->data.raise_reply_64.ndr = NDR_record;
+ break;
+
+ case EXCEPTION_RAISE_STATE_REPLY_MESSAGE_ID:
+ m_pMessage->data.raise_state_reply.ndr = NDR_record;
+ break;
+
+ case EXCEPTION_RAISE_STATE_REPLY_64_MESSAGE_ID:
+ m_pMessage->data.raise_state_reply_64.ndr = NDR_record;
+ break;
+
+ case EXCEPTION_RAISE_STATE_IDENTITY_REPLY_MESSAGE_ID:
+ m_pMessage->data.raise_state_identity_reply.ndr = NDR_record;
+ break;
+
+ case EXCEPTION_RAISE_STATE_IDENTITY_REPLY_64_MESSAGE_ID:
+ m_pMessage->data.raise_state_identity_reply_64.ndr = NDR_record;
+ break;
+
+ default:
+ NONPAL_RETAIL_ASSERT("Unhandled message type: %u", m_pMessage->header.msgh_id);
+ }
+
+ m_pMessage->header.msgh_reserved = 0;
+
+ if (m_hTask)
+ {
+ kern_return_t machret;
+ // Addref the task, because the receiver will expect it to own it. (or, if we
+ // free it unsent, we'll expect to deallocate it).
+ machret = mach_port_mod_refs(mach_task_self(), m_hTask, MACH_PORT_RIGHT_SEND, 1);
+ }
+}
+
+// Initialize the size field of the message header (msgh_size) based on the message type and other fields.
+// This should be called after all other fields have been initialized.
+void MachMessage::InitMessageSize()
+{
+ // Note that in particular the kernel is very particular about the size of messages with embedded thread
+ // states. The size of the message must reflect the exact size of the state flavor contained, not the
+ // maximum size of a thread state that the message format implies.
+
+ switch (m_pMessage->header.msgh_id)
+ {
+ case SET_THREAD_MESSAGE_ID:
+ m_pMessage->header.msgh_size = sizeof(mach_msg_header_t) + sizeof(set_thread_request_t);
+ break;
+
+ case FORWARD_EXCEPTION_MESSAGE_ID:
+ m_pMessage->header.msgh_size = sizeof(mach_msg_header_t) + sizeof(forward_exception_request_t);
+ break;
+
+ case EXCEPTION_RAISE_MESSAGE_ID:
+ m_pMessage->header.msgh_size = sizeof(mach_msg_header_t) + sizeof(exception_raise_notification_t);
+ break;
+
+ case EXCEPTION_RAISE_64_MESSAGE_ID:
+ m_pMessage->header.msgh_size = sizeof(mach_msg_header_t) + sizeof(exception_raise_notification_64_t);
+ break;
+
+ case EXCEPTION_RAISE_STATE_MESSAGE_ID:
+ m_pMessage->header.msgh_size = sizeof(mach_msg_header_t) +
+ offsetof(exception_raise_state_notification_t, old_state) +
+ (m_pMessage->data.raise_state.old_state_count * sizeof(natural_t));
+ break;
+
+ case EXCEPTION_RAISE_STATE_64_MESSAGE_ID:
+ m_pMessage->header.msgh_size = sizeof(mach_msg_header_t) +
+ offsetof(exception_raise_state_notification_64_t, old_state) +
+ (m_pMessage->data.raise_state_64.old_state_count * sizeof(natural_t));
+ break;
+
+ case EXCEPTION_RAISE_STATE_IDENTITY_MESSAGE_ID:
+ m_pMessage->header.msgh_size = sizeof(mach_msg_header_t) +
+ offsetof(exception_raise_state_identity_notification_t, old_state) +
+ (m_pMessage->data.raise_state_identity.old_state_count * sizeof(natural_t));
+ break;
+
+ case EXCEPTION_RAISE_STATE_IDENTITY_64_MESSAGE_ID:
+ m_pMessage->header.msgh_size = sizeof(mach_msg_header_t) +
+ offsetof(exception_raise_state_identity_notification_64_t, old_state) +
+ (m_pMessage->data.raise_state_identity_64.old_state_count * sizeof(natural_t));
+ break;
+
+ case EXCEPTION_RAISE_REPLY_MESSAGE_ID:
+ m_pMessage->header.msgh_size = sizeof(mach_msg_header_t) + sizeof(exception_raise_reply_t);
+ break;
+
+ case EXCEPTION_RAISE_REPLY_64_MESSAGE_ID:
+ m_pMessage->header.msgh_size = sizeof(mach_msg_header_t) + sizeof(exception_raise_reply_64_t);
+ break;
+
+ case EXCEPTION_RAISE_STATE_REPLY_MESSAGE_ID:
+ m_pMessage->header.msgh_size = sizeof(mach_msg_header_t) +
+ offsetof(exception_raise_state_reply_t, new_state) +
+ (m_pMessage->data.raise_state_reply.new_state_count * sizeof(natural_t));
+ break;
+
+ case EXCEPTION_RAISE_STATE_REPLY_64_MESSAGE_ID:
+ m_pMessage->header.msgh_size = sizeof(mach_msg_header_t) +
+ offsetof(exception_raise_state_reply_64_t, new_state) +
+ (m_pMessage->data.raise_state_reply_64.new_state_count * sizeof(natural_t));
+ break;
+
+ case EXCEPTION_RAISE_STATE_IDENTITY_REPLY_MESSAGE_ID:
+ m_pMessage->header.msgh_size = sizeof(mach_msg_header_t) +
+ offsetof(exception_raise_state_identity_reply_t, new_state) +
+ (m_pMessage->data.raise_state_identity_reply.new_state_count * sizeof(natural_t));
+ break;
+
+ case EXCEPTION_RAISE_STATE_IDENTITY_REPLY_64_MESSAGE_ID:
+ m_pMessage->header.msgh_size = sizeof(mach_msg_header_t) +
+ offsetof(exception_raise_state_identity_reply_64_t, new_state) +
+ (m_pMessage->data.raise_state_identity_reply_64.new_state_count * sizeof(natural_t));
+ break;
+
+ default:
+ NONPAL_RETAIL_ASSERT("Unhandled message type: %u", m_pMessage->header.msgh_id);
+ }
+}
+
+// Given a thread's register context, locate and return the Mach port representing that thread. Only the
+// x86_THREAD_STATE and x86_THREAD_STATE32 state flavors are supported for 32-bit.
+thread_act_t MachMessage::GetThreadFromState(thread_state_flavor_t eFlavor, thread_state_t pState)
+{
+ SIZE_T targetSP;
+
+ // Determine SP from the state provided based on its flavor (this algorithm only works with SP, so
+ // flavors that don't report this register can't be used). However, hosts that use RAISE_STATE and a
+ // flavor of state that don't contain SP should be very, very rare indeed (it's hard to imagine many
+ // useful exception handlers that receive neither the exception thread or the general registers of that
+ // thread).
+ switch (eFlavor)
+ {
+#ifdef _X86_
+ case x86_THREAD_STATE:
+ targetSP = ((x86_thread_state_t*)pState)->uts.ts32.esp;
+ break;
+
+ case x86_THREAD_STATE32:
+ targetSP = ((x86_thread_state32_t*)pState)->esp;
+ break;
+#elif defined(_AMD64_)
+ case x86_THREAD_STATE:
+ targetSP = ((x86_thread_state_t*)pState)->uts.ts64.__rsp;
+ break;
+
+ case x86_THREAD_STATE64:
+ targetSP = ((x86_thread_state64_t*)pState)->__rsp;
+ break;
+#else
+#error Unexpected architecture.
+#endif
+ default:
+ NONPAL_RETAIL_ASSERT("Unhandled thread state flavor: %u", eFlavor);
+ }
+
+ // Capture the list of threads in the current task. Obviously this changes asynchronously to us, but that
+ // doesn't matter since we know the thread we're after is suspended in the kernel and can't go anywhere.
+ mach_msg_type_number_t cThreads;
+ thread_act_t *pThreads;
+ kern_return_t machret = task_threads(mach_task_self(), &pThreads, &cThreads);
+ CHECK_MACH("task_threads()", machret);
+
+ // Iterate through each of the threads in the list.
+ for (mach_msg_type_number_t i = 0; i < cThreads; i++)
+ {
+ // Get the general register state of each thread.
+ x86_thread_state_t threadState;
+ mach_msg_type_number_t count = x86_THREAD_STATE_COUNT;
+ machret = thread_get_state(pThreads[i], x86_THREAD_STATE, (thread_state_t)&threadState, &count);
+ if (machret == KERN_SUCCESS)
+ {
+ // If a thread has the same SP as our target it should be the same thread (otherwise we have two
+ // threads sharing the same stack which is very bad). Conversely the thread we're looking for is
+ // suspended in the kernel so its SP should not change. We should always be able to find an exact
+ // match as a result.
+#ifdef _X86_
+ if (threadState.uts.ts32.esp == targetSP)
+#elif defined(_AMD64_)
+ if (threadState.uts.ts64.__rsp == targetSP)
+#else
+#error Unexpected architecture.
+#endif
+ {
+ thread_act_t thread = pThreads[i];
+
+ // Increment the refcount; the thread is a "send" right.
+ machret = mach_port_mod_refs(mach_task_self(), thread, MACH_PORT_RIGHT_SEND, 1);
+ CHECK_MACH("mach_port_mod_refs()", machret);
+
+ // Deallocate the thread list now we're done with it.
+ machret = vm_deallocate(mach_task_self(), (vm_address_t)pThreads, cThreads * sizeof(thread_act_t));
+ CHECK_MACH("vm_deallocate()", machret);
+
+ // Return the thread we found.
+ return thread;
+ }
+ }
+ }
+
+ // If we got here no thread matched. That shouldn't be possible.
+ NONPAL_RETAIL_ASSERT("Failed to locate thread from state.");
+}
+
+// Transform a exception handler behavior type into the corresponding Mach message ID for the notification.
+mach_msg_id_t MachMessage::MapBehaviorToNotificationType(exception_behavior_t eBehavior)
+{
+ switch ((uint)eBehavior)
+ {
+ case EXCEPTION_DEFAULT:
+ return EXCEPTION_RAISE_MESSAGE_ID;
+ case EXCEPTION_STATE:
+ return EXCEPTION_RAISE_STATE_MESSAGE_ID;
+ case EXCEPTION_STATE_IDENTITY:
+ return EXCEPTION_RAISE_STATE_IDENTITY_MESSAGE_ID;
+ case MACH_EXCEPTION_CODES|EXCEPTION_DEFAULT:
+ return EXCEPTION_RAISE_64_MESSAGE_ID;
+ case MACH_EXCEPTION_CODES|EXCEPTION_STATE:
+ return EXCEPTION_RAISE_STATE_64_MESSAGE_ID;
+ case MACH_EXCEPTION_CODES|EXCEPTION_STATE_IDENTITY:
+ return EXCEPTION_RAISE_STATE_IDENTITY_64_MESSAGE_ID;
+ default:
+ NONPAL_RETAIL_ASSERT("Unsupported exception behavior type: %u", eBehavior);
+ }
+}
+
+// Transform a Mach message ID for an exception notification into the corresponding ID for the reply.
+mach_msg_id_t MachMessage::MapNotificationToReplyType(mach_msg_id_t eNotificationType)
+{
+ switch (eNotificationType)
+ {
+ case EXCEPTION_RAISE_MESSAGE_ID:
+ return EXCEPTION_RAISE_REPLY_MESSAGE_ID;
+ case EXCEPTION_RAISE_STATE_MESSAGE_ID:
+ return EXCEPTION_RAISE_STATE_REPLY_MESSAGE_ID;
+ case EXCEPTION_RAISE_STATE_IDENTITY_MESSAGE_ID:
+ return EXCEPTION_RAISE_STATE_IDENTITY_REPLY_MESSAGE_ID;
+ case EXCEPTION_RAISE_64_MESSAGE_ID:
+ return EXCEPTION_RAISE_REPLY_64_MESSAGE_ID;
+ case EXCEPTION_RAISE_STATE_64_MESSAGE_ID:
+ return EXCEPTION_RAISE_STATE_REPLY_64_MESSAGE_ID;
+ case EXCEPTION_RAISE_STATE_IDENTITY_64_MESSAGE_ID:
+ return EXCEPTION_RAISE_STATE_IDENTITY_REPLY_64_MESSAGE_ID;
+ default:
+ NONPAL_RETAIL_ASSERT("Unsupported message type: %u", eNotificationType);
+ }
+}
+
+// Set faulting thread in an exception notification message.
+void MachMessage::SetThread(thread_act_t thread)
+{
+ bool fSet = false;
+
+ switch (m_pMessage->header.msgh_id)
+ {
+ case EXCEPTION_RAISE_MESSAGE_ID:
+ m_pMessage->data.raise.thread_port.name = thread;
+ m_pMessage->data.raise.thread_port.pad1 = 0;
+ m_pMessage->data.raise.thread_port.pad2 = 0;
+ m_pMessage->data.raise.thread_port.disposition = MACH_MSG_TYPE_COPY_SEND;
+ m_pMessage->data.raise.thread_port.type = MACH_MSG_PORT_DESCRIPTOR;
+ fSet = true;
+ break;
+
+ case EXCEPTION_RAISE_64_MESSAGE_ID:
+ m_pMessage->data.raise_64.thread_port.name = thread;
+ m_pMessage->data.raise_64.thread_port.pad1 = 0;
+ m_pMessage->data.raise_64.thread_port.pad2 = 0;
+ m_pMessage->data.raise_64.thread_port.disposition = MACH_MSG_TYPE_COPY_SEND;
+ m_pMessage->data.raise_64.thread_port.type = MACH_MSG_PORT_DESCRIPTOR;
+ fSet = true;
+ break;
+
+ case EXCEPTION_RAISE_STATE_MESSAGE_ID:
+ case EXCEPTION_RAISE_STATE_64_MESSAGE_ID:
+ // No thread field in RAISE_STATE messages.
+ break;
+
+ case EXCEPTION_RAISE_STATE_IDENTITY_MESSAGE_ID:
+ m_pMessage->data.raise_state_identity.thread_port.name = thread;
+ m_pMessage->data.raise_state_identity.thread_port.pad1 = 0;
+ m_pMessage->data.raise_state_identity.thread_port.pad2 = 0;
+ m_pMessage->data.raise_state_identity.thread_port.disposition = MACH_MSG_TYPE_COPY_SEND;
+ m_pMessage->data.raise_state_identity.thread_port.type = MACH_MSG_PORT_DESCRIPTOR;
+ fSet = true;
+ break;
+
+ case EXCEPTION_RAISE_STATE_IDENTITY_64_MESSAGE_ID:
+ m_pMessage->data.raise_state_identity_64.thread_port.name = thread;
+ m_pMessage->data.raise_state_identity_64.thread_port.pad1 = 0;
+ m_pMessage->data.raise_state_identity_64.thread_port.pad2 = 0;
+ m_pMessage->data.raise_state_identity_64.thread_port.disposition = MACH_MSG_TYPE_COPY_SEND;
+ m_pMessage->data.raise_state_identity_64.thread_port.type = MACH_MSG_PORT_DESCRIPTOR;
+ fSet = true;
+ break;
+
+ default:
+ NONPAL_RETAIL_ASSERT("Unsupported message type: %u", m_pMessage->header.msgh_id);
+ }
+
+ if (fSet)
+ {
+ // Addref the thread port.
+ kern_return_t machret;
+ machret = mach_port_mod_refs(mach_task_self(), thread, MACH_PORT_RIGHT_SEND, 1);
+ }
+}
+
+// Set exception type in an exception notification message.
+void MachMessage::SetException(exception_type_t eException)
+{
+ switch (m_pMessage->header.msgh_id)
+ {
+ case EXCEPTION_RAISE_MESSAGE_ID:
+ m_pMessage->data.raise.exception = eException;
+ break;
+
+ case EXCEPTION_RAISE_64_MESSAGE_ID:
+ m_pMessage->data.raise_64.exception = eException;
+ break;
+
+ case EXCEPTION_RAISE_STATE_MESSAGE_ID:
+ m_pMessage->data.raise_state.exception = eException;
+ break;
+
+ case EXCEPTION_RAISE_STATE_64_MESSAGE_ID:
+ m_pMessage->data.raise_state_64.exception = eException;
+ break;
+
+ case EXCEPTION_RAISE_STATE_IDENTITY_MESSAGE_ID:
+ m_pMessage->data.raise_state_identity.exception = eException;
+ break;
+
+ case EXCEPTION_RAISE_STATE_IDENTITY_64_MESSAGE_ID:
+ m_pMessage->data.raise_state_identity_64.exception = eException;
+ break;
+
+ default:
+ NONPAL_RETAIL_ASSERT("Unsupported message type: %u", m_pMessage->header.msgh_id);
+ }
+}
+
+// Set exception sub-code count in an exception notification message.
+void MachMessage::SetExceptionCodeCount(int cCodes)
+{
+ switch (m_pMessage->header.msgh_id)
+ {
+ case EXCEPTION_RAISE_MESSAGE_ID:
+ m_pMessage->data.raise.code_count = cCodes;
+ break;
+
+ case EXCEPTION_RAISE_64_MESSAGE_ID:
+ m_pMessage->data.raise_64.code_count = cCodes;
+ break;
+
+ case EXCEPTION_RAISE_STATE_MESSAGE_ID:
+ m_pMessage->data.raise_state.code_count = cCodes;
+ break;
+
+ case EXCEPTION_RAISE_STATE_64_MESSAGE_ID:
+ m_pMessage->data.raise_state_64.code_count = cCodes;
+ break;
+
+ case EXCEPTION_RAISE_STATE_IDENTITY_MESSAGE_ID:
+ m_pMessage->data.raise_state_identity.code_count = cCodes;
+ break;
+
+ case EXCEPTION_RAISE_STATE_IDENTITY_64_MESSAGE_ID:
+ m_pMessage->data.raise_state_identity_64.code_count = cCodes;
+ break;
+
+ default:
+ NONPAL_RETAIL_ASSERT("Unsupported message type: %u", m_pMessage->header.msgh_id);
+ }
+}
+
+// Set exception sub-code in an exception notification message.
+void MachMessage::SetExceptionCode(int iIndex, MACH_EH_TYPE(exception_data_type_t) iCode)
+{
+ if (iIndex < 0 || iIndex > 1)
+ NONPAL_RETAIL_ASSERT("Exception code index out of range");
+
+ // Note that although the 64-bit message variants support 64-bit exception sub-codes the CoreCLR only
+ // supports 32-bit processes. We should never see the upper 32-bits containing a non-zero value therefore.
+
+ switch (m_pMessage->header.msgh_id)
+ {
+ case EXCEPTION_RAISE_MESSAGE_ID:
+ m_pMessage->data.raise.code[iIndex] = (int)iCode;
+ break;
+
+ case EXCEPTION_RAISE_64_MESSAGE_ID:
+ m_pMessage->data.raise_64.code[iIndex] = iCode;
+ break;
+
+ case EXCEPTION_RAISE_STATE_MESSAGE_ID:
+ m_pMessage->data.raise_state.code[iIndex] = (int)iCode;
+ break;
+
+ case EXCEPTION_RAISE_STATE_64_MESSAGE_ID:
+ m_pMessage->data.raise_state_64.code[iIndex] = iCode;
+ break;
+
+ case EXCEPTION_RAISE_STATE_IDENTITY_MESSAGE_ID:
+ m_pMessage->data.raise_state_identity.code[iIndex] = (int)iCode;
+ break;
+
+ case EXCEPTION_RAISE_STATE_IDENTITY_64_MESSAGE_ID:
+ m_pMessage->data.raise_state_identity_64.code[iIndex] = iCode;
+ break;
+
+ default:
+ NONPAL_RETAIL_ASSERT("Unsupported message type: %u", m_pMessage->header.msgh_id);
+ }
+}
+
+// Set return code in a reply message.
+void MachMessage::SetReturnCode(kern_return_t eReturnCode)
+{
+ switch (m_pMessage->header.msgh_id)
+ {
+ case EXCEPTION_RAISE_REPLY_MESSAGE_ID:
+ m_pMessage->data.raise_reply.ret = eReturnCode;
+ break;
+
+ case EXCEPTION_RAISE_REPLY_64_MESSAGE_ID:
+ m_pMessage->data.raise_reply_64.ret = eReturnCode;
+ break;
+
+ case EXCEPTION_RAISE_STATE_REPLY_MESSAGE_ID:
+ m_pMessage->data.raise_state_reply.ret = eReturnCode;
+ break;
+
+ case EXCEPTION_RAISE_STATE_REPLY_64_MESSAGE_ID:
+ m_pMessage->data.raise_state_reply_64.ret = eReturnCode;
+ break;
+
+ case EXCEPTION_RAISE_STATE_IDENTITY_REPLY_MESSAGE_ID:
+ m_pMessage->data.raise_state_identity_reply.ret = eReturnCode;
+ break;
+
+ case EXCEPTION_RAISE_STATE_IDENTITY_REPLY_64_MESSAGE_ID:
+ m_pMessage->data.raise_state_identity_reply_64.ret = eReturnCode;
+ break;
+
+ default:
+ NONPAL_RETAIL_ASSERT("Unsupported message type: %u", m_pMessage->header.msgh_id);
+ }
+}
+
+// Set faulting thread register state in an exception notification or reply message.
+void MachMessage::SetThreadState(thread_state_flavor_t eFlavor, thread_state_t pState, mach_msg_type_number_t count)
+{
+ switch (m_pMessage->header.msgh_id)
+ {
+ case EXCEPTION_RAISE_MESSAGE_ID:
+ case EXCEPTION_RAISE_REPLY_MESSAGE_ID:
+ case EXCEPTION_RAISE_64_MESSAGE_ID:
+ case EXCEPTION_RAISE_REPLY_64_MESSAGE_ID:
+ // No thread state in RAISE or RAISE_REPLY messages.
+ break;
+
+ case EXCEPTION_RAISE_STATE_MESSAGE_ID:
+ m_pMessage->data.raise_state.flavor = eFlavor;
+ m_pMessage->data.raise_state.old_state_count = count;
+ memcpy(m_pMessage->data.raise_state.old_state, pState, count * sizeof(natural_t));
+ break;
+
+ case EXCEPTION_RAISE_STATE_64_MESSAGE_ID:
+ m_pMessage->data.raise_state_64.flavor = eFlavor;
+ m_pMessage->data.raise_state_64.old_state_count = count;
+ memcpy(m_pMessage->data.raise_state_64.old_state, pState, count * sizeof(natural_t));
+ break;
+
+ case EXCEPTION_RAISE_STATE_IDENTITY_MESSAGE_ID:
+ m_pMessage->data.raise_state_identity.flavor = eFlavor;
+ m_pMessage->data.raise_state_identity.old_state_count = count;
+ memcpy(m_pMessage->data.raise_state_identity.old_state, pState, count * sizeof(natural_t));
+ break;
+
+ case EXCEPTION_RAISE_STATE_IDENTITY_64_MESSAGE_ID:
+ m_pMessage->data.raise_state_identity_64.flavor = eFlavor;
+ m_pMessage->data.raise_state_identity_64.old_state_count = count;
+ memcpy(m_pMessage->data.raise_state_identity_64.old_state, pState, count * sizeof(natural_t));
+ break;
+
+ case EXCEPTION_RAISE_STATE_REPLY_MESSAGE_ID:
+ m_pMessage->data.raise_state_reply.flavor = eFlavor;
+ m_pMessage->data.raise_state_reply.new_state_count = count;
+ memcpy(m_pMessage->data.raise_state_reply.new_state, pState, count * sizeof(natural_t));
+ break;
+
+ case EXCEPTION_RAISE_STATE_REPLY_64_MESSAGE_ID:
+ m_pMessage->data.raise_state_reply_64.flavor = eFlavor;
+ m_pMessage->data.raise_state_reply_64.new_state_count = count;
+ memcpy(m_pMessage->data.raise_state_reply_64.new_state, pState, count * sizeof(natural_t));
+ break;
+
+ case EXCEPTION_RAISE_STATE_IDENTITY_REPLY_MESSAGE_ID:
+ m_pMessage->data.raise_state_identity_reply.flavor = eFlavor;
+ m_pMessage->data.raise_state_identity_reply.new_state_count = count;
+ memcpy(m_pMessage->data.raise_state_identity_reply.new_state, pState, count * sizeof(natural_t));
+ break;
+
+ case EXCEPTION_RAISE_STATE_IDENTITY_REPLY_64_MESSAGE_ID:
+ m_pMessage->data.raise_state_identity_reply_64.flavor = eFlavor;
+ m_pMessage->data.raise_state_identity_reply_64.new_state_count = count;
+ memcpy(m_pMessage->data.raise_state_identity_reply_64.new_state, pState, count * sizeof(natural_t));
+ break;
+
+ default:
+ NONPAL_RETAIL_ASSERT("Unsupported message type: %u", m_pMessage->header.msgh_id);
+ }
+}
+
+#endif // HAVE_MACH_EXCEPTIONS
diff --git a/src/pal/src/exception/machmessage.h b/src/pal/src/exception/machmessage.h
new file mode 100644
index 0000000000..244396cd35
--- /dev/null
+++ b/src/pal/src/exception/machmessage.h
@@ -0,0 +1,441 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+Module Name:
+
+ machmessage.h
+
+Abstract:
+
+ Abstraction over Mach messages used during exception handling.
+
+--*/
+
+#include <mach/mach.h>
+#include <mach/mach_error.h>
+#include <mach/thread_status.h>
+
+using namespace CorUnix;
+
+#if HAVE_MACH_EXCEPTIONS
+
+#if defined(_AMD64_)
+#define MACH_EH_TYPE(x) mach_##x
+#else
+#define MACH_EH_TYPE(x) x
+#endif // defined(_AMD64_)
+
+// The vast majority of Mach calls we make in this module are critical: we cannot recover from failures of
+// these methods (principally because we're handling hardware exceptions in the context of a single dedicated
+// handler thread). The following macro encapsulates checking the return code from Mach methods and emitting
+// some useful data and aborting the process on failure.
+#define CHECK_MACH(_msg, machret) do { \
+ if (machret != KERN_SUCCESS) \
+ { \
+ char _szError[1024]; \
+ sprintf(_szError, "%s: %u: %s", __FUNCTION__, __LINE__, _msg); \
+ mach_error(_szError, machret); \
+ abort(); \
+ } \
+ } while (false)
+
+// This macro terminates the process with some useful debug info as above, but for the general failure points
+// that have nothing to do with Mach.
+#define NONPAL_RETAIL_ASSERT(_msg, ...) do { \
+ printf("%s: %u: " _msg "\n", __FUNCTION__, __LINE__, ## __VA_ARGS__); \
+ abort(); \
+ } while (false)
+
+#define NONPAL_RETAIL_ASSERTE(_expr) do { \
+ if (!(_expr)) \
+ NONPAL_RETAIL_ASSERT("ASSERT: %s\n", #_expr); \
+ } while (false)
+
+#ifdef _DEBUG
+
+#define NONPAL_TRACE_ENABLED EnvironGetenv("NONPAL_TRACING", /* copyValue */ false)
+
+#define NONPAL_ASSERT(_msg, ...) NONPAL_RETAIL_ASSERT(_msg, __VA_ARGS__)
+
+// Assert macro that doesn't rely on the PAL.
+#define NONPAL_ASSERTE(_expr) do { \
+ if (!(_expr)) \
+ NONPAL_RETAIL_ASSERT("ASSERT: %s\n", #_expr); \
+ } while (false)
+
+// Debug-only output with printf-style formatting.
+#define NONPAL_TRACE(_format, ...) do { \
+ if (NONPAL_TRACE_ENABLED) printf("NONPAL_TRACE: " _format, ## __VA_ARGS__); \
+ } while (false)
+
+#else // _DEBUG
+
+#define NONPAL_TRACE_ENABLED false
+#define NONPAL_ASSERT(_msg, ...)
+#define NONPAL_ASSERTE(_expr)
+#define NONPAL_TRACE(_format, ...)
+
+#endif // _DEBUG
+
+class MachMessage;
+
+// Contains all the exception and thread state information needed to forward the exception.
+struct MachExceptionInfo
+{
+ exception_type_t ExceptionType;
+ mach_msg_type_number_t SubcodeCount;
+ MACH_EH_TYPE(exception_data_type_t) Subcodes[2];
+ x86_thread_state_t ThreadState;
+ x86_float_state_t FloatState;
+ x86_debug_state_t DebugState;
+
+ MachExceptionInfo(mach_port_t thread, MachMessage& message);
+ void RestoreState(mach_port_t thread);
+};
+
+// Abstraction of a subset of Mach message types. Provides accessors that hide the subtle differences in the
+// message layout of similar message types.
+class MachMessage
+{
+public:
+ // The message types handled by this class. The values are the actual type codes set in the Mach message
+ // header.
+ enum MessageType
+ {
+ SET_THREAD_MESSAGE_ID = 1,
+ FORWARD_EXCEPTION_MESSAGE_ID = 2,
+ NOTIFY_SEND_ONCE_MESSAGE_ID = 71,
+ EXCEPTION_RAISE_MESSAGE_ID = 2401,
+ EXCEPTION_RAISE_STATE_MESSAGE_ID = 2402,
+ EXCEPTION_RAISE_STATE_IDENTITY_MESSAGE_ID = 2403,
+ EXCEPTION_RAISE_64_MESSAGE_ID = 2405,
+ EXCEPTION_RAISE_STATE_64_MESSAGE_ID = 2406,
+ EXCEPTION_RAISE_STATE_IDENTITY_64_MESSAGE_ID = 2407,
+ EXCEPTION_RAISE_REPLY_MESSAGE_ID = 2501,
+ EXCEPTION_RAISE_STATE_REPLY_MESSAGE_ID = 2502,
+ EXCEPTION_RAISE_STATE_IDENTITY_REPLY_MESSAGE_ID = 2503,
+ EXCEPTION_RAISE_REPLY_64_MESSAGE_ID = 2505,
+ EXCEPTION_RAISE_STATE_REPLY_64_MESSAGE_ID = 2506,
+ EXCEPTION_RAISE_STATE_IDENTITY_REPLY_64_MESSAGE_ID = 2507
+ };
+
+ // Construct an empty message. Use Receive() to form a message that can be inspected or SendSetThread(),
+ // ForwardNotification() or ReplyToNotification() to construct a message and sent it.
+ MachMessage();
+
+ // Listen for the next message on the given port and initialize this class with the contents. The message
+ // type must match one of the MessageTypes indicated above (or the process will be aborted).
+ void Receive(mach_port_t hPort);
+
+ // Indicate whether a received message belongs to a particular semantic class.
+ bool IsSetThreadRequest(); // Message is a request to set the context of a particular thread
+ bool IsForwardExceptionRequest(); // Message is a request to forward the exception
+ bool IsSendOnceDestroyedNotify(); // Message is a notification that a send-once message was destroyed by the receiver
+ bool IsExceptionNotification(); // Message is a notification of an exception
+ bool IsExceptionReply(); // Message is a reply to the notification of an exception
+
+ // Get properties of a received message header.
+ MessageType GetMessageType(); // The message type
+ const char *GetMessageTypeName(); // An ASCII representation of the message type for logging purposes
+ mach_port_t GetLocalPort(); // The destination port the message was sent to
+ mach_port_t GetRemotePort(); // The source port the message came from (if a reply is expected)
+
+ // Get the properties of a set thread request. Fills in the provided context structure with the context
+ // from the message and returns the target thread to which the context should be applied.
+ thread_act_t GetThreadContext(CONTEXT *pContext);
+
+ // Returns the pal thread instance for the forward exception message
+ CPalThread *GetPalThread();
+
+ // Returns the exception info from the forward exception message
+ MachExceptionInfo *GetExceptionInfo();
+
+ // Get properties of the type-specific portion of the message. The following properties are supported by
+ // exception notification messages only.
+ thread_act_t GetThread(); // Get the faulting thread
+ exception_type_t GetException(); // Get the exception type (e.g. EXC_BAD_ACCESS)
+ int GetExceptionCodeCount(); // Get the number of exception sub-codes
+ MACH_EH_TYPE(exception_data_type_t) GetExceptionCode(int iIndex); // Get the exception sub-code at the given index
+
+ // Fetch the thread state flavor from a notification or reply message (return THREAD_STATE_NONE for the
+ // messages that don't contain a thread state).
+ thread_state_flavor_t GetThreadStateFlavor();
+
+ // Get the thread state with the given flavor from the exception or exception reply message. If the
+ // message doesn't contain a thread state or the flavor of the state in the message doesn't match, the
+ // state will be fetched directly from the target thread instead (which can be computed implicitly for
+ // exception messages or passed explicitly for reply messages).
+ mach_msg_type_number_t GetThreadState(thread_state_flavor_t eFlavor, thread_state_t pState, thread_act_t thread = NULL);
+
+ // Fetch the return code from a reply type message.
+ kern_return_t GetReturnCode();
+
+ // Initialize and send a request to set the register context of a particular thread.
+ void SendSetThread(mach_port_t hServerPort, CONTEXT *pContext);
+
+ // Initialize and send a request to forward the exception message to the notification thread
+ void SendForwardException(mach_port_t hServerPort, MachExceptionInfo *pExceptionInfo, CPalThread *ppalThread);
+
+ // Initialize the message (overwriting any previous content) to represent a forwarded version of the given
+ // exception notification message and send that message to the chain-back handler previously registered
+ // for the exception type being notified. The new message takes account of the fact that the target
+ // handler may not have requested the same notification behavior or flavor as our handler.
+ void ForwardNotification(MachExceptionHandler *pHandler, MachMessage& message);
+
+ // Initialize the message (overwriting any previous content) to represent a reply to the given exception
+ // notification and send that reply back to the original sender of the notification. This is used when our
+ // handler handles the exception rather than forwarding it to a chain-back handler.
+ void ReplyToNotification(MachMessage& message, kern_return_t eResult);
+
+private:
+ // The maximum size in bytes of any Mach message we can send or receive. Calculating an exact size for
+ // this is non trivial (basically because of the security trailers that Mach appends) but the current
+ // value has proven to be more than enough so far.
+ static const size_t kcbMaxMessageSize = 1500;
+
+ // The following are structures describing the formats of the Mach messages we understand.
+
+ // Request to set the register context on a particular thread.
+ // SET_THREAD_MESSAGE_ID
+ struct set_thread_request_t
+ {
+ thread_act_t thread;
+ CONTEXT new_context;
+ };
+
+ // Request to forward the exception notification
+ // FORWARD_EXCEPTION_MESSAGE_ID
+ struct forward_exception_request_t
+ {
+ thread_act_t thread;
+ CPalThread *ppalThread;
+ MachExceptionInfo exception_info;
+ };
+
+#pragma pack(4)
+
+ // EXCEPTION_RAISE_MESSAGE_ID
+ struct exception_raise_notification_t
+ {
+ mach_msg_body_t msgh_body;
+ mach_msg_port_descriptor_t thread_port;
+ mach_msg_port_descriptor_t task_port;
+ NDR_record_t ndr;
+ exception_type_t exception;
+ mach_msg_type_number_t code_count;
+ exception_data_type_t code[2];
+ };
+
+ // EXCEPTION_RAISE_REPLY_MESSAGE_ID
+ struct exception_raise_reply_t
+ {
+ NDR_record_t ndr;
+ kern_return_t ret;
+ };
+
+ // EXCEPTION_RAISE_64_MESSAGE_ID
+ struct exception_raise_notification_64_t
+ {
+ mach_msg_body_t msgh_body;
+ mach_msg_port_descriptor_t thread_port;
+ mach_msg_port_descriptor_t task_port;
+ NDR_record_t ndr;
+ exception_type_t exception;
+ mach_msg_type_number_t code_count;
+ mach_exception_data_type_t code[2];
+ };
+
+ // EXCEPTION_RAISE_REPLY_64_MESSAGE_ID
+ struct exception_raise_reply_64_t
+ {
+ NDR_record_t ndr;
+ kern_return_t ret;
+ };
+
+ // EXCEPTION_RAISE_STATE_MESSAGE_ID
+ struct exception_raise_state_notification_t
+ {
+ NDR_record_t ndr;
+ exception_type_t exception;
+ mach_msg_type_number_t code_count;
+ exception_data_type_t code[2];
+ thread_state_flavor_t flavor;
+ mach_msg_type_number_t old_state_count;
+ natural_t old_state[THREAD_STATE_MAX];
+ };
+
+ // EXCEPTION_RAISE_STATE_REPLY_MESSAGE_ID
+ struct exception_raise_state_reply_t
+ {
+ NDR_record_t ndr;
+ kern_return_t ret;
+ thread_state_flavor_t flavor;
+ mach_msg_type_number_t new_state_count;
+ natural_t new_state[THREAD_STATE_MAX];
+ };
+
+ // EXCEPTION_RAISE_STATE_64_MESSAGE_ID
+ struct exception_raise_state_notification_64_t
+ {
+ NDR_record_t ndr;
+ exception_type_t exception;
+ mach_msg_type_number_t code_count;
+ mach_exception_data_type_t code[2];
+ thread_state_flavor_t flavor;
+ mach_msg_type_number_t old_state_count;
+ natural_t old_state[THREAD_STATE_MAX];
+ };
+
+ // EXCEPTION_RAISE_STATE_REPLY_64_MESSAGE_ID
+ struct exception_raise_state_reply_64_t
+ {
+ NDR_record_t ndr;
+ kern_return_t ret;
+ thread_state_flavor_t flavor;
+ mach_msg_type_number_t new_state_count;
+ natural_t new_state[THREAD_STATE_MAX];
+ };
+
+ // EXCEPTION_RAISE_STATE_IDENTITY_MESSAGE_ID
+ struct exception_raise_state_identity_notification_t
+ {
+ mach_msg_body_t msgh_body;
+ mach_msg_port_descriptor_t thread_port;
+ mach_msg_port_descriptor_t task_port;
+ NDR_record_t ndr;
+ exception_type_t exception;
+ mach_msg_type_number_t code_count;
+ exception_data_type_t code[2];
+ thread_state_flavor_t flavor;
+ mach_msg_type_number_t old_state_count;
+ natural_t old_state[THREAD_STATE_MAX];
+ };
+
+ // EXCEPTION_RAISE_STATE_IDENTITY_REPLY_MESSAGE_ID
+ struct exception_raise_state_identity_reply_t
+ {
+ NDR_record_t ndr;
+ kern_return_t ret;
+ thread_state_flavor_t flavor;
+ mach_msg_type_number_t new_state_count;
+ natural_t new_state[THREAD_STATE_MAX];
+ };
+
+ // EXCEPTION_RAISE_STATE_IDENTITY_64_MESSAGE_ID
+ struct exception_raise_state_identity_notification_64_t
+ {
+ mach_msg_body_t msgh_body;
+ mach_msg_port_descriptor_t thread_port;
+ mach_msg_port_descriptor_t task_port;
+ NDR_record_t ndr;
+ exception_type_t exception;
+ mach_msg_type_number_t code_count;
+ mach_exception_data_type_t code[2];
+ thread_state_flavor_t flavor;
+ mach_msg_type_number_t old_state_count;
+ natural_t old_state[THREAD_STATE_MAX];
+ };
+
+ // EXCEPTION_RAISE_STATE_IDENTITY_REPLY_64_MESSAGE_ID
+ struct exception_raise_state_identity_reply_64_t
+ {
+ NDR_record_t ndr;
+ kern_return_t ret;
+ thread_state_flavor_t flavor;
+ mach_msg_type_number_t new_state_count;
+ natural_t new_state[THREAD_STATE_MAX];
+ };
+
+#pragma pack()
+
+ // All the above messages are sent with a standard Mach header prepended. This structure unifies the
+ // message formats.
+ struct mach_message_t
+ {
+ mach_msg_header_t header;
+ union
+ {
+ set_thread_request_t set_thread;
+ forward_exception_request_t forward_exception;
+ exception_raise_notification_t raise;
+ exception_raise_state_notification_t raise_state;
+ exception_raise_state_identity_notification_t raise_state_identity;
+ exception_raise_notification_64_t raise_64;
+ exception_raise_state_notification_64_t raise_state_64;
+ exception_raise_state_identity_notification_64_t raise_state_identity_64;
+ exception_raise_reply_t raise_reply;
+ exception_raise_state_reply_t raise_state_reply;
+ exception_raise_state_identity_reply_t raise_state_identity_reply;
+ exception_raise_reply_64_t raise_reply_64;
+ exception_raise_state_reply_64_t raise_state_reply_64;
+ exception_raise_state_identity_reply_64_t raise_state_identity_reply_64;
+ } data;
+ } __attribute__((packed));;
+
+ // Re-initializes this data structure (to the same state as default construction, containing no message).
+ void ResetMessage();
+
+ // Initialize those fields of a message that are invariant. This method expects that the msgh_id field has
+ // been filled in prior to the call so it can determine which non-header fields to initialize.
+ void InitFixedFields();
+
+ // Initialize the size field of the message header (msgh_size) based on the message type and other fields.
+ // This should be called after all other fields have been initialized.
+ void InitMessageSize();
+
+ // Do the work of getting ports from the message.
+ // * fCalculate -- calculate the thread port if the message did not contain it.
+ // * fValidate -- failfast if the message was not one expected to have a (calculable) thread port.
+ void GetPorts(bool fCalculate, bool fValidThread);
+
+ // Given a thread's register context, locate and return the Mach port representing that thread. Only the
+ // x86_THREAD_STATE and x86_THREAD_STATE32 state flavors are supported.
+ thread_act_t GetThreadFromState(thread_state_flavor_t eFlavor, thread_state_t pState);
+
+ // Transform a exception handler behavior type into the corresponding Mach message ID for the
+ // notification.
+ mach_msg_id_t MapBehaviorToNotificationType(exception_behavior_t eBehavior);
+
+ // Transform a Mach message ID for an exception notification into the corresponding ID for the reply.
+ mach_msg_id_t MapNotificationToReplyType(mach_msg_id_t eNotificationType);
+
+ // The following methods initialize fields on the message prior to transmission. Each is valid for either
+ // notification, replies or both. If a particular setter is defined for replies, say, then it will be a
+ // no-op for any replies which don't contain that field. This makes transforming between notifications and
+ // replies of different types simpler (we can copy a super-set of all fields between the two, but only
+ // those operations that make sense will do any work).
+
+ // Defined for notifications:
+ void SetThread(thread_act_t thread);
+ void SetException(exception_type_t eException);
+ void SetExceptionCodeCount(int cCodes);
+ void SetExceptionCode(int iIndex, MACH_EH_TYPE(exception_data_type_t) iCode);
+
+ // Defined for replies:
+ void SetReturnCode(kern_return_t eReturnCode);
+
+ // Defined for both notifications and replies.
+ void SetThreadState(thread_state_flavor_t eFlavor, thread_state_t pState, mach_msg_type_number_t count);
+
+ // Maximally sized buffer for the message to be received into or transmitted out of this class.
+ unsigned char m_rgMessageBuffer[kcbMaxMessageSize];
+
+ // Initialized by ResetMessage() to point to the buffer above. Gives a typed view of the encapsulated Mach
+ // message.
+ mach_message_t *m_pMessage;
+
+ // Cached value of GetThread() or MACH_PORT_NULL if that has not been computed yet.
+ thread_act_t m_hThread;
+
+ // Cached value of the task port or MACH_PORT_NULL if the message doesn't have one.
+ mach_port_t m_hTask;
+
+ // Considered whether we are responsible for the deallocation of the ports in
+ // this message. It is true for messages we receive, and false for messages we send.
+ bool m_fPortsOwned;
+};
+
+#endif // HAVE_MACH_EXCEPTIONS
diff --git a/src/pal/src/exception/seh-unwind.cpp b/src/pal/src/exception/seh-unwind.cpp
new file mode 100644
index 0000000000..24eebbbf94
--- /dev/null
+++ b/src/pal/src/exception/seh-unwind.cpp
@@ -0,0 +1,737 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ seh-unwind.cpp
+
+Abstract:
+
+ Implementation of exception API functions based on
+ the Unwind API.
+
+
+
+--*/
+
+#ifndef FEATURE_PAL_SXS
+#error FEATURE_PAL_SXS needs to be defined for this file.
+#endif // !FEATURE_PAL_SXS
+
+#include "pal/context.h"
+#include "pal.h"
+#include <dlfcn.h>
+
+#if HAVE_LIBUNWIND_H
+#ifndef __linux__
+#define UNW_LOCAL_ONLY
+#endif // !__linux__
+#include <libunwind.h>
+#ifdef __linux__
+#ifdef HAVE_LIBUNWIND_PTRACE
+#include <libunwind-ptrace.h>
+#endif // HAVE_LIBUNWIND_PTRACE
+#endif // __linux__
+#endif // HAVE_LIBUNWIND_H
+
+
+//----------------------------------------------------------------------
+// Virtual Unwinding
+//----------------------------------------------------------------------
+
+#if HAVE_LIBUNWIND_H
+#if UNWIND_CONTEXT_IS_UCONTEXT_T
+
+#if defined(_AMD64_)
+#define ASSIGN_UNWIND_REGS \
+ ASSIGN_REG(Rip) \
+ ASSIGN_REG(Rsp) \
+ ASSIGN_REG(Rbp) \
+ ASSIGN_REG(Rbx) \
+ ASSIGN_REG(R12) \
+ ASSIGN_REG(R13) \
+ ASSIGN_REG(R14) \
+ ASSIGN_REG(R15)
+#elif defined(_ARM64_)
+#define ASSIGN_UNWIND_REGS \
+ ASSIGN_REG(Pc) \
+ ASSIGN_REG(Sp) \
+ ASSIGN_REG(Fp) \
+ ASSIGN_REG(Lr) \
+ ASSIGN_REG(X19) \
+ ASSIGN_REG(X20) \
+ ASSIGN_REG(X21) \
+ ASSIGN_REG(X22) \
+ ASSIGN_REG(X23) \
+ ASSIGN_REG(X24) \
+ ASSIGN_REG(X25) \
+ ASSIGN_REG(X26) \
+ ASSIGN_REG(X27) \
+ ASSIGN_REG(X28)
+#else
+#error unsupported architecture
+#endif
+
+static void WinContextToUnwindContext(CONTEXT *winContext, unw_context_t *unwContext)
+{
+#define ASSIGN_REG(reg) MCREG_##reg(unwContext->uc_mcontext) = winContext->reg;
+ ASSIGN_UNWIND_REGS
+#undef ASSIGN_REG
+}
+#else
+static void WinContextToUnwindContext(CONTEXT *winContext, unw_context_t *unwContext)
+{
+#if defined(_ARM_)
+ // Assuming that unw_set_reg() on cursor will point the cursor to the
+ // supposed stack frame is dangerous for libunwind-arm in Linux.
+ // It is because libunwind's unw_cursor_t has other data structure
+ // initialized by unw_init_local(), which are not updated by
+ // unw_set_reg().
+ unwContext->regs[0] = 0;
+ unwContext->regs[1] = 0;
+ unwContext->regs[2] = 0;
+ unwContext->regs[3] = 0;
+ unwContext->regs[4] = winContext->R4;
+ unwContext->regs[5] = winContext->R5;
+ unwContext->regs[6] = winContext->R6;
+ unwContext->regs[7] = winContext->R7;
+ unwContext->regs[8] = winContext->R8;
+ unwContext->regs[9] = winContext->R9;
+ unwContext->regs[10] = winContext->R10;
+ unwContext->regs[11] = winContext->R11;
+ unwContext->regs[12] = 0;
+ unwContext->regs[13] = winContext->Sp;
+ unwContext->regs[14] = winContext->Lr;
+ unwContext->regs[15] = winContext->Pc;
+#endif
+}
+
+static void WinContextToUnwindCursor(CONTEXT *winContext, unw_cursor_t *cursor)
+{
+#if defined(_AMD64_)
+ unw_set_reg(cursor, UNW_REG_IP, winContext->Rip);
+ unw_set_reg(cursor, UNW_REG_SP, winContext->Rsp);
+ unw_set_reg(cursor, UNW_X86_64_RBP, winContext->Rbp);
+ unw_set_reg(cursor, UNW_X86_64_RBX, winContext->Rbx);
+ unw_set_reg(cursor, UNW_X86_64_R12, winContext->R12);
+ unw_set_reg(cursor, UNW_X86_64_R13, winContext->R13);
+ unw_set_reg(cursor, UNW_X86_64_R14, winContext->R14);
+ unw_set_reg(cursor, UNW_X86_64_R15, winContext->R15);
+#endif
+}
+#endif
+
+static void UnwindContextToWinContext(unw_cursor_t *cursor, CONTEXT *winContext)
+{
+#if defined(_AMD64_)
+ unw_get_reg(cursor, UNW_REG_IP, (unw_word_t *) &winContext->Rip);
+ unw_get_reg(cursor, UNW_REG_SP, (unw_word_t *) &winContext->Rsp);
+ unw_get_reg(cursor, UNW_X86_64_RBP, (unw_word_t *) &winContext->Rbp);
+ unw_get_reg(cursor, UNW_X86_64_RBX, (unw_word_t *) &winContext->Rbx);
+ unw_get_reg(cursor, UNW_X86_64_R12, (unw_word_t *) &winContext->R12);
+ unw_get_reg(cursor, UNW_X86_64_R13, (unw_word_t *) &winContext->R13);
+ unw_get_reg(cursor, UNW_X86_64_R14, (unw_word_t *) &winContext->R14);
+ unw_get_reg(cursor, UNW_X86_64_R15, (unw_word_t *) &winContext->R15);
+#elif defined(_ARM_)
+ unw_get_reg(cursor, UNW_REG_SP, (unw_word_t *) &winContext->Sp);
+ unw_get_reg(cursor, UNW_REG_IP, (unw_word_t *) &winContext->Pc);
+ unw_get_reg(cursor, UNW_ARM_R14, (unw_word_t *) &winContext->Lr);
+ unw_get_reg(cursor, UNW_ARM_R4, (unw_word_t *) &winContext->R4);
+ unw_get_reg(cursor, UNW_ARM_R5, (unw_word_t *) &winContext->R5);
+ unw_get_reg(cursor, UNW_ARM_R6, (unw_word_t *) &winContext->R6);
+ unw_get_reg(cursor, UNW_ARM_R7, (unw_word_t *) &winContext->R7);
+ unw_get_reg(cursor, UNW_ARM_R8, (unw_word_t *) &winContext->R8);
+ unw_get_reg(cursor, UNW_ARM_R9, (unw_word_t *) &winContext->R9);
+ unw_get_reg(cursor, UNW_ARM_R10, (unw_word_t *) &winContext->R10);
+ unw_get_reg(cursor, UNW_ARM_R11, (unw_word_t *) &winContext->R11);
+#elif defined(_ARM64_)
+ unw_get_reg(cursor, UNW_REG_IP, (unw_word_t *) &winContext->Pc);
+ unw_get_reg(cursor, UNW_REG_SP, (unw_word_t *) &winContext->Sp);
+ unw_get_reg(cursor, UNW_AARCH64_X29, (unw_word_t *) &winContext->Fp);
+ unw_get_reg(cursor, UNW_AARCH64_X30, (unw_word_t *) &winContext->Lr);
+ unw_get_reg(cursor, UNW_AARCH64_X19, (unw_word_t *) &winContext->X19);
+ unw_get_reg(cursor, UNW_AARCH64_X20, (unw_word_t *) &winContext->X20);
+ unw_get_reg(cursor, UNW_AARCH64_X21, (unw_word_t *) &winContext->X21);
+ unw_get_reg(cursor, UNW_AARCH64_X22, (unw_word_t *) &winContext->X22);
+ unw_get_reg(cursor, UNW_AARCH64_X23, (unw_word_t *) &winContext->X23);
+ unw_get_reg(cursor, UNW_AARCH64_X24, (unw_word_t *) &winContext->X24);
+ unw_get_reg(cursor, UNW_AARCH64_X25, (unw_word_t *) &winContext->X25);
+ unw_get_reg(cursor, UNW_AARCH64_X26, (unw_word_t *) &winContext->X26);
+ unw_get_reg(cursor, UNW_AARCH64_X27, (unw_word_t *) &winContext->X27);
+ unw_get_reg(cursor, UNW_AARCH64_X28, (unw_word_t *) &winContext->X28);
+#else
+#error unsupported architecture
+#endif
+}
+
+static void GetContextPointer(unw_cursor_t *cursor, unw_context_t *unwContext, int reg, SIZE_T **contextPointer)
+{
+#if defined(HAVE_UNW_GET_SAVE_LOC)
+ unw_save_loc_t saveLoc;
+ unw_get_save_loc(cursor, reg, &saveLoc);
+ if (saveLoc.type == UNW_SLT_MEMORY)
+ {
+ SIZE_T *pLoc = (SIZE_T *)saveLoc.u.addr;
+ // Filter out fake save locations that point to unwContext
+ if (unwContext == NULL || (pLoc < (SIZE_T *)unwContext) || ((SIZE_T *)(unwContext + 1) <= pLoc))
+ *contextPointer = (SIZE_T *)saveLoc.u.addr;
+ }
+#else
+ // Returning NULL indicates that we don't have context pointers available
+ *contextPointer = NULL;
+#endif
+}
+
+static void GetContextPointers(unw_cursor_t *cursor, unw_context_t *unwContext, KNONVOLATILE_CONTEXT_POINTERS *contextPointers)
+{
+#if defined(_AMD64_)
+ GetContextPointer(cursor, unwContext, UNW_X86_64_RBP, &contextPointers->Rbp);
+ GetContextPointer(cursor, unwContext, UNW_X86_64_RBX, &contextPointers->Rbx);
+ GetContextPointer(cursor, unwContext, UNW_X86_64_R12, &contextPointers->R12);
+ GetContextPointer(cursor, unwContext, UNW_X86_64_R13, &contextPointers->R13);
+ GetContextPointer(cursor, unwContext, UNW_X86_64_R14, &contextPointers->R14);
+ GetContextPointer(cursor, unwContext, UNW_X86_64_R15, &contextPointers->R15);
+#elif defined(_ARM_)
+ GetContextPointer(cursor, unwContext, UNW_ARM_R4, &contextPointers->R4);
+ GetContextPointer(cursor, unwContext, UNW_ARM_R5, &contextPointers->R5);
+ GetContextPointer(cursor, unwContext, UNW_ARM_R6, &contextPointers->R6);
+ GetContextPointer(cursor, unwContext, UNW_ARM_R7, &contextPointers->R7);
+ GetContextPointer(cursor, unwContext, UNW_ARM_R8, &contextPointers->R8);
+ GetContextPointer(cursor, unwContext, UNW_ARM_R9, &contextPointers->R9);
+ GetContextPointer(cursor, unwContext, UNW_ARM_R10, &contextPointers->R10);
+ GetContextPointer(cursor, unwContext, UNW_ARM_R11, &contextPointers->R11);
+#elif defined(_ARM64_)
+ GetContextPointer(cursor, unwContext, UNW_AARCH64_X19, &contextPointers->X19);
+ GetContextPointer(cursor, unwContext, UNW_AARCH64_X20, &contextPointers->X20);
+ GetContextPointer(cursor, unwContext, UNW_AARCH64_X21, &contextPointers->X21);
+ GetContextPointer(cursor, unwContext, UNW_AARCH64_X22, &contextPointers->X22);
+ GetContextPointer(cursor, unwContext, UNW_AARCH64_X23, &contextPointers->X23);
+ GetContextPointer(cursor, unwContext, UNW_AARCH64_X24, &contextPointers->X24);
+ GetContextPointer(cursor, unwContext, UNW_AARCH64_X25, &contextPointers->X25);
+ GetContextPointer(cursor, unwContext, UNW_AARCH64_X26, &contextPointers->X26);
+ GetContextPointer(cursor, unwContext, UNW_AARCH64_X27, &contextPointers->X27);
+ GetContextPointer(cursor, unwContext, UNW_AARCH64_X28, &contextPointers->X28);
+#else
+#error unsupported architecture
+#endif
+}
+
+BOOL PAL_VirtualUnwind(CONTEXT *context, KNONVOLATILE_CONTEXT_POINTERS *contextPointers)
+{
+ int st;
+ unw_context_t unwContext;
+ unw_cursor_t cursor;
+
+#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(_ARM64_) || defined(_ARM_)
+ DWORD64 curPc;
+#endif
+
+ if ((context->ContextFlags & CONTEXT_EXCEPTION_ACTIVE) != 0)
+ {
+ // The current frame is a source of hardware exception. Due to the fact that
+ // we use the low level unwinder to unwind just one frame a time, the
+ // unwinder doesn't have the signal_frame flag set. So it doesn't
+ // know that it should not decrement the PC before looking up the unwind info.
+ // So we compensate it by incrementing the PC before passing it to the unwinder.
+ // Without it, the unwinder would not find unwind info if the hardware exception
+ // happened in the first instruction of a function.
+ CONTEXTSetPC(context, CONTEXTGetPC(context) + 1);
+ }
+
+#if !UNWIND_CONTEXT_IS_UCONTEXT_T
+ st = unw_getcontext(&unwContext);
+ if (st < 0)
+ {
+ return FALSE;
+ }
+#endif
+
+ WinContextToUnwindContext(context, &unwContext);
+
+ st = unw_init_local(&cursor, &unwContext);
+ if (st < 0)
+ {
+ return FALSE;
+ }
+
+#if !UNWIND_CONTEXT_IS_UCONTEXT_T
+ // Set the unwind context to the specified windows context
+ WinContextToUnwindCursor(context, &cursor);
+#endif
+
+#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(_ARM64_) || defined(_ARM_)
+ // FreeBSD, NetBSD and OSX appear to do two different things when unwinding
+ // 1: If it reaches where it cannot unwind anymore, say a
+ // managed frame. It wil return 0, but also update the $pc
+ // 2: If it unwinds all the way to _start it will return
+ // 0 from the step, but $pc will stay the same.
+ // The behaviour of libunwind from nongnu.org is to null the PC
+ // So we bank the original PC here, so we can compare it after
+ // the step
+ curPc = CONTEXTGetPC(context);
+#endif
+
+ st = unw_step(&cursor);
+ if (st < 0)
+ {
+ return FALSE;
+ }
+
+ // Check if the frame we have unwound to is a frame that caused
+ // synchronous signal, like a hardware exception and record it
+ // in the context flags.
+ if (unw_is_signal_frame(&cursor) > 0)
+ {
+ context->ContextFlags |= CONTEXT_EXCEPTION_ACTIVE;
+#if defined(_ARM_) || defined(_ARM64_)
+ context->ContextFlags &= ~CONTEXT_UNWOUND_TO_CALL;
+#endif // _ARM_ || _ARM64_
+ }
+ else
+ {
+ context->ContextFlags &= ~CONTEXT_EXCEPTION_ACTIVE;
+#if defined(_ARM_) || defined(_ARM64_)
+ context->ContextFlags |= CONTEXT_UNWOUND_TO_CALL;
+#endif // _ARM_ || _ARM64_
+ }
+
+ // Update the passed in windows context to reflect the unwind
+ //
+ UnwindContextToWinContext(&cursor, context);
+#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(_ARM64_) || defined(_ARM_)
+ if (st == 0 && CONTEXTGetPC(context) == curPc)
+ {
+ CONTEXTSetPC(context, 0);
+ }
+#endif
+
+ if (contextPointers != NULL)
+ {
+ GetContextPointers(&cursor, &unwContext, contextPointers);
+ }
+ return TRUE;
+}
+
+#else
+#error don't know how to unwind on this platform
+#endif
+
+// These methods are only used on the AMD64 build
+#ifdef _AMD64_
+#ifdef HAVE_UNW_GET_ACCESSORS
+
+static struct LibunwindCallbacksInfoType
+{
+ CONTEXT *Context;
+ ReadMemoryWordCallback readMemCallback;
+} LibunwindCallbacksInfo;
+
+static int get_dyn_info_list_addr(unw_addr_space_t as, unw_word_t *dilap, void *arg)
+{
+ return -UNW_ENOINFO;
+}
+
+static int access_mem(unw_addr_space_t as, unw_word_t addr, unw_word_t *valp, int write, void *arg)
+{
+ if (write)
+ {
+ ASSERT("Memory write must never be called by libunwind during stackwalk");
+ return -UNW_EINVAL;
+ }
+
+ // access_mem sometimes gets called by _UPT_find_proc_info, in such cases arg has a pointer to libunwind internal data
+ // returned by _UPT_create. It makes it impossible to use arg for passing readMemCallback. That's why we have to use global variable.
+ if (LibunwindCallbacksInfo.readMemCallback((SIZE_T)addr, (SIZE_T *)valp))
+ {
+ return UNW_ESUCCESS;
+ }
+ else
+ {
+ return -UNW_EUNSPEC;
+ }
+}
+
+static int access_reg(unw_addr_space_t as, unw_regnum_t regnum, unw_word_t *valp, int write, void *arg)
+{
+ if (write)
+ {
+ ASSERT("Register write must never be called by libunwind during stackwalk");
+ return -UNW_EREADONLYREG;
+ }
+
+ CONTEXT *winContext = LibunwindCallbacksInfo.Context;
+
+ switch (regnum)
+ {
+#if defined(_AMD64_)
+ case UNW_REG_IP: *valp = (unw_word_t) winContext->Rip; break;
+ case UNW_REG_SP: *valp = (unw_word_t) winContext->Rsp; break;
+ case UNW_X86_64_RBP: *valp = (unw_word_t) winContext->Rbp; break;
+ case UNW_X86_64_RBX: *valp = (unw_word_t) winContext->Rbx; break;
+ case UNW_X86_64_R12: *valp = (unw_word_t) winContext->R12; break;
+ case UNW_X86_64_R13: *valp = (unw_word_t) winContext->R13; break;
+ case UNW_X86_64_R14: *valp = (unw_word_t) winContext->R14; break;
+ case UNW_X86_64_R15: *valp = (unw_word_t) winContext->R15; break;
+#elif defined(_ARM_)
+ case UNW_ARM_R13: *valp = (unw_word_t) winContext->Sp; break;
+ case UNW_ARM_R14: *valp = (unw_word_t) winContext->Lr; break;
+ case UNW_ARM_R15: *valp = (unw_word_t) winContext->Pc; break;
+ case UNW_ARM_R4: *valp = (unw_word_t) winContext->R4; break;
+ case UNW_ARM_R5: *valp = (unw_word_t) winContext->R5; break;
+ case UNW_ARM_R6: *valp = (unw_word_t) winContext->R6; break;
+ case UNW_ARM_R7: *valp = (unw_word_t) winContext->R7; break;
+ case UNW_ARM_R8: *valp = (unw_word_t) winContext->R8; break;
+ case UNW_ARM_R9: *valp = (unw_word_t) winContext->R9; break;
+ case UNW_ARM_R10: *valp = (unw_word_t) winContext->R10; break;
+ case UNW_ARM_R11: *valp = (unw_word_t) winContext->R11; break;
+#elif defined(_ARM64_)
+ case UNW_REG_IP: *valp = (unw_word_t) winContext->Pc; break;
+ case UNW_REG_SP: *valp = (unw_word_t) winContext->Sp; break;
+ case UNW_AARCH64_X29: *valp = (unw_word_t) winContext->Fp; break;
+ case UNW_AARCH64_X30: *valp = (unw_word_t) winContext->Lr; break;
+ case UNW_AARCH64_X19: *valp = (unw_word_t) winContext->X19; break;
+ case UNW_AARCH64_X20: *valp = (unw_word_t) winContext->X20; break;
+ case UNW_AARCH64_X21: *valp = (unw_word_t) winContext->X21; break;
+ case UNW_AARCH64_X22: *valp = (unw_word_t) winContext->X22; break;
+ case UNW_AARCH64_X23: *valp = (unw_word_t) winContext->X23; break;
+ case UNW_AARCH64_X24: *valp = (unw_word_t) winContext->X24; break;
+ case UNW_AARCH64_X25: *valp = (unw_word_t) winContext->X25; break;
+ case UNW_AARCH64_X26: *valp = (unw_word_t) winContext->X26; break;
+ case UNW_AARCH64_X27: *valp = (unw_word_t) winContext->X27; break;
+ case UNW_AARCH64_X28: *valp = (unw_word_t) winContext->X28; break;
+#else
+#error unsupported architecture
+#endif
+ default:
+ ASSERT("Attempt to read an unknown register.");
+ return -UNW_EBADREG;
+ }
+ return UNW_ESUCCESS;
+}
+
+static int access_fpreg(unw_addr_space_t as, unw_regnum_t regnum, unw_fpreg_t *fpvalp, int write, void *arg)
+{
+ ASSERT("Not supposed to be ever called");
+ return -UNW_EINVAL;
+}
+
+static int resume(unw_addr_space_t as, unw_cursor_t *cp, void *arg)
+{
+ ASSERT("Not supposed to be ever called");
+ return -UNW_EINVAL;
+}
+
+static int get_proc_name(unw_addr_space_t as, unw_word_t addr, char *bufp, size_t buf_len, unw_word_t *offp, void *arg)
+{
+ ASSERT("Not supposed to be ever called");
+ return -UNW_EINVAL;
+}
+
+int find_proc_info(unw_addr_space_t as,
+ unw_word_t ip, unw_proc_info_t *pip,
+ int need_unwind_info, void *arg)
+{
+#ifdef HAVE_LIBUNWIND_PTRACE
+ // UNIXTODO: libunwind RPM package on Fedora/CentOS/RedHat doesn't have libunwind-ptrace.so
+ // and we can't use it from a shared library like libmscordaccore.so.
+ // That's why all calls to ptrace parts of libunwind ifdeffed out for now.
+ return _UPT_find_proc_info(as, ip, pip, need_unwind_info, arg);
+#else
+ return -UNW_EINVAL;
+#endif
+}
+
+void put_unwind_info(unw_addr_space_t as, unw_proc_info_t *pip, void *arg)
+{
+#ifdef HAVE_LIBUNWIND_PTRACE
+ return _UPT_put_unwind_info(as, pip, arg);
+#endif
+}
+
+static unw_accessors_t unwind_accessors =
+{
+ .find_proc_info = find_proc_info,
+ .put_unwind_info = put_unwind_info,
+ .get_dyn_info_list_addr = get_dyn_info_list_addr,
+ .access_mem = access_mem,
+ .access_reg = access_reg,
+ .access_fpreg = access_fpreg,
+ .resume = resume,
+ .get_proc_name = get_proc_name
+};
+
+BOOL PAL_VirtualUnwindOutOfProc(CONTEXT *context,
+ KNONVOLATILE_CONTEXT_POINTERS *contextPointers,
+ DWORD pid,
+ ReadMemoryWordCallback readMemCallback)
+{
+ // This function can be executed only by one thread at a time.
+ // The reason for this is that we need to pass context and read mem function to libunwind callbacks
+ // but "arg" is already used by the pointer returned from _UPT_create().
+ // So we resort to using global variables and a lock.
+ struct Lock
+ {
+ CRITICAL_SECTION cs;
+ Lock()
+ {
+ // ctor of a static variable is a thread-safe way to initialize critical section exactly once (clang,gcc)
+ InitializeCriticalSection(&cs);
+ }
+ };
+ struct LockHolder
+ {
+ CRITICAL_SECTION *cs;
+ LockHolder(CRITICAL_SECTION *cs)
+ {
+ this->cs = cs;
+ EnterCriticalSection(cs);
+ }
+
+ ~LockHolder()
+ {
+ LeaveCriticalSection(cs);
+ cs = NULL;
+ }
+ };
+ static Lock lock;
+ LockHolder lockHolder(&lock.cs);
+
+ int st;
+ unw_cursor_t cursor;
+ unw_addr_space_t addrSpace = 0;
+ void *libunwindUptPtr = NULL;
+ BOOL result = FALSE;
+
+ LibunwindCallbacksInfo.Context = context;
+ LibunwindCallbacksInfo.readMemCallback = readMemCallback;
+
+ addrSpace = unw_create_addr_space(&unwind_accessors, 0);
+#ifdef HAVE_LIBUNWIND_PTRACE
+ libunwindUptPtr = _UPT_create(pid);
+#endif
+ st = unw_init_remote(&cursor, addrSpace, libunwindUptPtr);
+ if (st < 0)
+ {
+ result = FALSE;
+ goto Exit;
+ }
+
+ st = unw_step(&cursor);
+ if (st < 0)
+ {
+ result = FALSE;
+ goto Exit;
+ }
+
+ UnwindContextToWinContext(&cursor, context);
+
+ if (contextPointers != NULL)
+ {
+ GetContextPointers(&cursor, NULL, contextPointers);
+ }
+ result = TRUE;
+
+Exit:
+#ifdef HAVE_LIBUNWIND_PTRACE
+ if (libunwindUptPtr != NULL)
+ {
+ _UPT_destroy(libunwindUptPtr);
+ }
+#endif
+ if (addrSpace != 0)
+ {
+ unw_destroy_addr_space(addrSpace);
+ }
+ return result;
+}
+#else // HAVE_UNW_GET_ACCESSORS
+
+BOOL PAL_VirtualUnwindOutOfProc(CONTEXT *context,
+ KNONVOLATILE_CONTEXT_POINTERS *contextPointers,
+ DWORD pid,
+ ReadMemoryWordCallback readMemCallback)
+{
+ //UNIXTODO: Implement for Mac flavor of libunwind
+ return FALSE;
+}
+
+#endif // !HAVE_UNW_GET_ACCESSORS
+#endif // _AMD64_
+
+struct ExceptionRecords
+{
+ CONTEXT ContextRecord;
+ EXCEPTION_RECORD ExceptionRecord;
+};
+
+// Max number of fallback contexts that are used when malloc fails to allocate ExceptionRecords structure
+static const int MaxFallbackContexts = sizeof(size_t) * 8;
+// Array of fallback contexts
+static ExceptionRecords s_fallbackContexts[MaxFallbackContexts];
+// Bitmap used for allocating fallback contexts - bits set to 1 represent already allocated context.
+static volatile size_t s_allocatedContextsBitmap = 0;
+
+/*++
+Function:
+ AllocateExceptionRecords
+
+ Allocate EXCEPTION_RECORD and CONTEXT structures for an exception.
+Parameters:
+ exceptionRecord - output pointer to the allocated exception record
+ contextRecord - output pointer to the allocated context record
+--*/
+VOID
+AllocateExceptionRecords(EXCEPTION_RECORD** exceptionRecord, CONTEXT** contextRecord)
+{
+ ExceptionRecords* records;
+ if (posix_memalign((void**)&records, alignof(ExceptionRecords), sizeof(ExceptionRecords)) != 0)
+ {
+ size_t bitmap;
+ size_t newBitmap;
+ int index;
+
+ do
+ {
+ bitmap = s_allocatedContextsBitmap;
+ index = __builtin_ffsl(~bitmap) - 1;
+ if (index < 0)
+ {
+ PROCAbort();
+ }
+
+ newBitmap = bitmap | ((size_t)1 << index);
+ }
+ while (__sync_val_compare_and_swap(&s_allocatedContextsBitmap, bitmap, newBitmap) != bitmap);
+
+ records = &s_fallbackContexts[index];
+ }
+
+ *contextRecord = &records->ContextRecord;
+ *exceptionRecord = &records->ExceptionRecord;
+}
+
+/*++
+Function:
+ PAL_FreeExceptionRecords
+
+ Free EXCEPTION_RECORD and CONTEXT structures of an exception that were allocated by the
+ AllocateExceptionRecords.
+Parameters:
+ exceptionRecord - exception record
+ contextRecord - context record
+--*/
+VOID
+PALAPI
+PAL_FreeExceptionRecords(IN EXCEPTION_RECORD *exceptionRecord, IN CONTEXT *contextRecord)
+{
+ // Both records are allocated at once and the allocated memory starts at the contextRecord
+ ExceptionRecords* records = (ExceptionRecords*)contextRecord;
+ if ((records >= &s_fallbackContexts[0]) && (records < &s_fallbackContexts[MaxFallbackContexts]))
+ {
+ int index = records - &s_fallbackContexts[0];
+ __sync_fetch_and_and(&s_allocatedContextsBitmap, ~((size_t)1 << index));
+ }
+ else
+ {
+ free(contextRecord);
+ }
+}
+
+/*++
+Function:
+ RtlpRaiseException
+
+Parameters:
+ ExceptionRecord - the Windows exception record to throw
+
+Note:
+ The name of this function and the name of the ExceptionRecord
+ parameter is used in the sos lldb plugin code to read the exception
+ record. See coreclr\src\ToolBox\SOS\lldbplugin\services.cpp.
+
+ This function must not be inlined or optimized so the below PAL_VirtualUnwind
+ calls end up with RaiseException caller's context and so the above debugger
+ code finds the function and ExceptionRecord parameter.
+--*/
+PAL_NORETURN
+__attribute__((noinline))
+__attribute__((optnone))
+static void
+RtlpRaiseException(EXCEPTION_RECORD *ExceptionRecord, CONTEXT *ContextRecord)
+{
+ throw PAL_SEHException(ExceptionRecord, ContextRecord);
+}
+
+/*++
+Function:
+ RaiseException
+
+See MSDN doc.
+--*/
+// no PAL_NORETURN, as callers must assume this can return for continuable exceptions.
+__attribute__((noinline))
+VOID
+PALAPI
+RaiseException(IN DWORD dwExceptionCode,
+ IN DWORD dwExceptionFlags,
+ IN DWORD nNumberOfArguments,
+ IN CONST ULONG_PTR *lpArguments)
+{
+ // PERF_ENTRY_ONLY is used here because RaiseException may or may not
+ // return. We can not get latency data without PERF_EXIT. For this reason,
+ // PERF_ENTRY_ONLY is used to profile frequency only.
+ PERF_ENTRY_ONLY(RaiseException);
+ ENTRY("RaiseException(dwCode=%#x, dwFlags=%#x, nArgs=%u, lpArguments=%p)\n",
+ dwExceptionCode, dwExceptionFlags, nNumberOfArguments, lpArguments);
+
+ /* Validate parameters */
+ if (dwExceptionCode & RESERVED_SEH_BIT)
+ {
+ WARN("Exception code %08x has bit 28 set; clearing it.\n", dwExceptionCode);
+ dwExceptionCode ^= RESERVED_SEH_BIT;
+ }
+
+ if (nNumberOfArguments > EXCEPTION_MAXIMUM_PARAMETERS)
+ {
+ WARN("Number of arguments (%d) exceeds the limit "
+ "EXCEPTION_MAXIMUM_PARAMETERS (%d); ignoring extra parameters.\n",
+ nNumberOfArguments, EXCEPTION_MAXIMUM_PARAMETERS);
+ nNumberOfArguments = EXCEPTION_MAXIMUM_PARAMETERS;
+ }
+
+ CONTEXT *contextRecord;
+ EXCEPTION_RECORD *exceptionRecord;
+ AllocateExceptionRecords(&exceptionRecord, &contextRecord);
+
+ ZeroMemory(exceptionRecord, sizeof(EXCEPTION_RECORD));
+
+ exceptionRecord->ExceptionCode = dwExceptionCode;
+ exceptionRecord->ExceptionFlags = dwExceptionFlags;
+ exceptionRecord->ExceptionRecord = NULL;
+ exceptionRecord->ExceptionAddress = NULL; // will be set by RtlpRaiseException
+ exceptionRecord->NumberParameters = nNumberOfArguments;
+ if (nNumberOfArguments)
+ {
+ CopyMemory(exceptionRecord->ExceptionInformation, lpArguments,
+ nNumberOfArguments * sizeof(ULONG_PTR));
+ }
+
+ // Capture the context of RaiseException.
+ ZeroMemory(contextRecord, sizeof(CONTEXT));
+ contextRecord->ContextFlags = CONTEXT_FULL;
+ CONTEXT_CaptureContext(contextRecord);
+
+ // We have to unwind one level to get the actual context user code could be resumed at.
+ PAL_VirtualUnwind(contextRecord, NULL);
+
+ exceptionRecord->ExceptionAddress = (void *)CONTEXTGetPC(contextRecord);
+
+ RtlpRaiseException(exceptionRecord, contextRecord);
+
+ LOGEXIT("RaiseException returns\n");
+}
diff --git a/src/pal/src/exception/seh.cpp b/src/pal/src/exception/seh.cpp
new file mode 100644
index 0000000000..38779bf59b
--- /dev/null
+++ b/src/pal/src/exception/seh.cpp
@@ -0,0 +1,431 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ seh.cpp
+
+Abstract:
+
+ Implementation of exception API functions.
+
+
+
+--*/
+
+#include "pal/thread.hpp"
+#include "pal/handleapi.hpp"
+#include "pal/seh.hpp"
+#include "pal/dbgmsg.h"
+#include "pal/critsect.h"
+#include "pal/debug.h"
+#include "pal/init.h"
+#include "pal/process.h"
+#include "pal/malloc.hpp"
+#include "signal.hpp"
+
+#if HAVE_MACH_EXCEPTIONS
+#include "machexception.h"
+#else
+#include <signal.h>
+#endif
+
+#include <string.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <stdlib.h>
+
+// Define the std::move so that we don't have to include the <utility> header
+// which on some platforms pulls in STL stuff that collides with PAL stuff.
+// The std::move is needed to enable using move constructor and assignment operator
+// for PAL_SEHException.
+namespace std
+{
+ template<typename T>
+ struct remove_reference
+ {
+ typedef T type;
+ };
+
+ template<typename T>
+ struct remove_reference<T&>
+ {
+ typedef T type;
+ };
+
+ template<typename T>
+ struct remove_reference<T&&>
+ {
+ typedef T type;
+ };
+
+ template<class T> inline
+ typename remove_reference<T>::type&& move(T&& arg)
+ { // forward arg as movable
+ return ((typename remove_reference<T>::type&&)arg);
+ }
+}
+
+using namespace CorUnix;
+
+SET_DEFAULT_DEBUG_CHANNEL(EXCEPT);
+
+/* Constant and type definitions **********************************************/
+
+/* Bit 28 of exception codes is reserved. */
+const UINT RESERVED_SEH_BIT = 0x800000;
+
+/* Internal variables definitions **********************************************/
+
+PHARDWARE_EXCEPTION_HANDLER g_hardwareExceptionHandler = NULL;
+// Function to check if an activation can be safely injected at a specified context
+PHARDWARE_EXCEPTION_SAFETY_CHECK_FUNCTION g_safeExceptionCheckFunction = NULL;
+
+PGET_GCMARKER_EXCEPTION_CODE g_getGcMarkerExceptionCode = NULL;
+
+/* Internal function definitions **********************************************/
+
+/*++
+Function :
+ SEHInitialize
+
+ Initialize all SEH-related stuff (signals, etc)
+
+Parameters :
+ CPalThread * pthrCurrent : reference to the current thread.
+ PAL initialize flags
+
+Return value :
+ TRUE if SEH support initialization succeeded
+ FALSE otherwise
+--*/
+BOOL
+SEHInitialize (CPalThread *pthrCurrent, DWORD flags)
+{
+#if !HAVE_MACH_EXCEPTIONS
+ if (!SEHInitializeSignals(flags))
+ {
+ ERROR("SEHInitializeSignals failed!\n");
+ SEHCleanup();
+ return FALSE;
+ }
+#endif
+
+ return TRUE;
+}
+
+/*++
+Function :
+ SEHCleanup
+
+ Undo work done by SEHInitialize
+
+Parameters :
+ None
+
+ (no return value)
+
+--*/
+VOID
+SEHCleanup()
+{
+ TRACE("Cleaning up SEH\n");
+
+#if HAVE_MACH_EXCEPTIONS
+ SEHCleanupExceptionPort();
+#else
+ SEHCleanupSignals();
+#endif
+}
+
+/*++
+Function:
+ PAL_SetHardwareExceptionHandler
+
+ Register a hardware exception handler.
+
+Parameters:
+ handler - exception handler
+
+Return value:
+ None
+--*/
+VOID
+PALAPI
+PAL_SetHardwareExceptionHandler(
+ IN PHARDWARE_EXCEPTION_HANDLER exceptionHandler,
+ IN PHARDWARE_EXCEPTION_SAFETY_CHECK_FUNCTION exceptionCheckFunction)
+{
+ g_hardwareExceptionHandler = exceptionHandler;
+ g_safeExceptionCheckFunction = exceptionCheckFunction;
+}
+
+/*++
+Function:
+ PAL_SetGetGcMarkerExceptionCode
+
+ Register a function that determines if the specified IP has code that is a GC marker for GCCover.
+
+Parameters:
+ getGcMarkerExceptionCode - the function to register
+
+Return value:
+ None
+--*/
+VOID
+PALAPI
+PAL_SetGetGcMarkerExceptionCode(
+ IN PGET_GCMARKER_EXCEPTION_CODE getGcMarkerExceptionCode)
+{
+ g_getGcMarkerExceptionCode = getGcMarkerExceptionCode;
+}
+
+EXTERN_C void ThrowExceptionFromContextInternal(CONTEXT* context, PAL_SEHException* ex);
+
+/*++
+Function:
+ PAL_ThrowExceptionFromContext
+
+ This function creates a stack frame right below the target frame, restores all callee
+ saved registers from the passed in context, sets the RSP to that frame and sets the
+ return address to the target frame's RIP.
+ Then it uses the ThrowExceptionHelper to throw the passed in exception from that context.
+
+Parameters:
+ CONTEXT* context - context from which the exception will be thrown
+ PAL_SEHException* ex - the exception to throw.
+--*/
+VOID
+PALAPI
+PAL_ThrowExceptionFromContext(CONTEXT* context, PAL_SEHException* ex)
+{
+ // We need to make a copy of the exception off stack, since the "ex" is located in one of the stack
+ // frames that will become obsolete by the ThrowExceptionFromContextInternal and the ThrowExceptionHelper
+ // could overwrite the "ex" object by stack e.g. when allocating the low level exception object for "throw".
+ static __thread BYTE threadLocalExceptionStorage[sizeof(PAL_SEHException)];
+ ThrowExceptionFromContextInternal(context, new (threadLocalExceptionStorage) PAL_SEHException(std::move(*ex)));
+}
+
+/*++
+Function:
+ ThrowExceptionHelper
+
+ Helper function to throw the passed in exception.
+ It is called from the assembler function ThrowExceptionFromContextInternal
+
+Parameters:
+ PAL_SEHException* ex - the exception to throw.
+--*/
+extern "C"
+void ThrowExceptionHelper(PAL_SEHException* ex)
+{
+ throw std::move(*ex);
+}
+
+/*++
+Function:
+ SEHProcessException
+
+ Send the PAL exception to any handler registered.
+
+Parameters:
+ PAL_SEHException* exception
+
+Return value:
+ Returns TRUE if the exception happened in managed code and the execution should
+ continue (with possibly modified context).
+ Returns FALSE if the exception happened in managed code and it was not handled.
+ In case the exception was handled by calling a catch handler, it doesn't return at all.
+--*/
+BOOL
+SEHProcessException(PAL_SEHException* exception)
+{
+ CONTEXT* contextRecord = exception->GetContextRecord();
+ EXCEPTION_RECORD* exceptionRecord = exception->GetExceptionRecord();
+
+ if (!IsInDebugBreak(exceptionRecord->ExceptionAddress))
+ {
+ if (g_hardwareExceptionHandler != NULL)
+ {
+ _ASSERTE(g_safeExceptionCheckFunction != NULL);
+ // Check if it is safe to handle the hardware exception (the exception happened in managed code
+ // or in a jitter helper or it is a debugger breakpoint)
+ if (g_safeExceptionCheckFunction(contextRecord, exceptionRecord))
+ {
+ if (exceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION)
+ {
+ // Check if the failed access has hit a stack guard page. In such case, it
+ // was a stack probe that detected that there is not enough stack left.
+ void* stackLimit = CPalThread::GetStackLimit();
+ void* stackGuard = (void*)((size_t)stackLimit - getpagesize());
+ void* violationAddr = (void*)exceptionRecord->ExceptionInformation[1];
+ if ((violationAddr >= stackGuard) && (violationAddr < stackLimit))
+ {
+ // The exception happened in the page right below the stack limit,
+ // so it is a stack overflow
+ write(STDERR_FILENO, StackOverflowMessage, sizeof(StackOverflowMessage) - 1);
+ PROCAbort();
+ }
+ }
+
+ if (g_hardwareExceptionHandler(exception))
+ {
+ // The exception happened in managed code and the execution should continue.
+ return TRUE;
+ }
+
+ // The exception was a single step or a breakpoint and it was not handled by the debugger.
+ }
+ }
+
+ if (CatchHardwareExceptionHolder::IsEnabled())
+ {
+ PAL_ThrowExceptionFromContext(exception->GetContextRecord(), exception);
+ }
+ }
+
+ // Unhandled hardware exception pointers->ExceptionRecord->ExceptionCode at pointers->ExceptionRecord->ExceptionAddress
+ return FALSE;
+}
+
+/*++
+Function :
+ SEHEnable
+
+ Enable SEH-related stuff on this thread
+
+Parameters:
+ CPalThread * pthrCurrent : reference to the current thread.
+
+Return value :
+ TRUE if enabling succeeded
+ FALSE otherwise
+--*/
+extern "C"
+PAL_ERROR SEHEnable(CPalThread *pthrCurrent)
+{
+#if HAVE_MACH_EXCEPTIONS
+ return pthrCurrent->EnableMachExceptions();
+#elif defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__)
+ // TODO: This needs to be implemented. Cannot put an ASSERT here
+ // because it will make other parts of PAL fail.
+ return NO_ERROR;
+#else// HAVE_MACH_EXCEPTIONS
+#error not yet implemented
+#endif // HAVE_MACH_EXCEPTIONS
+}
+
+/*++
+Function :
+ SEHDisable
+
+ Disable SEH-related stuff on this thread
+
+Parameters:
+ CPalThread * pthrCurrent : reference to the current thread.
+
+Return value :
+ TRUE if enabling succeeded
+ FALSE otherwise
+--*/
+extern "C"
+PAL_ERROR SEHDisable(CPalThread *pthrCurrent)
+{
+#if HAVE_MACH_EXCEPTIONS
+ return pthrCurrent->DisableMachExceptions();
+ // TODO: This needs to be implemented. Cannot put an ASSERT here
+ // because it will make other parts of PAL fail.
+#elif defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__)
+ return NO_ERROR;
+#else // HAVE_MACH_EXCEPTIONS
+#error not yet implemented
+#endif // HAVE_MACH_EXCEPTIONS
+}
+
+/*++
+
+ CatchHardwareExceptionHolder implementation
+
+--*/
+
+CatchHardwareExceptionHolder::CatchHardwareExceptionHolder()
+{
+ CPalThread *pThread = InternalGetCurrentThread();
+ ++pThread->m_hardwareExceptionHolderCount;
+}
+
+CatchHardwareExceptionHolder::~CatchHardwareExceptionHolder()
+{
+ CPalThread *pThread = InternalGetCurrentThread();
+ --pThread->m_hardwareExceptionHolderCount;
+}
+
+bool CatchHardwareExceptionHolder::IsEnabled()
+{
+ CPalThread *pThread = InternalGetCurrentThread();
+ return pThread->IsHardwareExceptionsEnabled();
+}
+
+/*++
+
+ NativeExceptionHolderBase implementation
+
+--*/
+
+#ifdef __llvm__
+__thread
+#else // __llvm__
+__declspec(thread)
+#endif // !__llvm__
+static NativeExceptionHolderBase *t_nativeExceptionHolderHead = nullptr;
+
+NativeExceptionHolderBase::NativeExceptionHolderBase()
+{
+ m_head = nullptr;
+ m_next = nullptr;
+}
+
+NativeExceptionHolderBase::~NativeExceptionHolderBase()
+{
+ // Only destroy if Push was called
+ if (m_head != nullptr)
+ {
+ *m_head = m_next;
+ m_head = nullptr;
+ m_next = nullptr;
+ }
+}
+
+void
+NativeExceptionHolderBase::Push()
+{
+ NativeExceptionHolderBase **head = &t_nativeExceptionHolderHead;
+ m_head = head;
+ m_next = *head;
+ *head = this;
+}
+
+NativeExceptionHolderBase *
+NativeExceptionHolderBase::FindNextHolder(NativeExceptionHolderBase *currentHolder, void *stackLowAddress, void *stackHighAddress)
+{
+ NativeExceptionHolderBase *holder = (currentHolder == nullptr) ? t_nativeExceptionHolderHead : currentHolder->m_next;
+
+ while (holder != nullptr)
+ {
+ if (((void *)holder >= stackLowAddress) && ((void *)holder < stackHighAddress))
+ {
+ return holder;
+ }
+ // Get next holder
+ holder = holder->m_next;
+ }
+
+ return nullptr;
+}
+
+#include "seh-unwind.cpp"
diff --git a/src/pal/src/exception/signal.cpp b/src/pal/src/exception/signal.cpp
new file mode 100644
index 0000000000..c2c217993a
--- /dev/null
+++ b/src/pal/src/exception/signal.cpp
@@ -0,0 +1,705 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ exception/signal.cpp
+
+Abstract:
+
+ Signal handler implementation (map signals to exceptions)
+
+
+
+--*/
+
+#include "pal/dbgmsg.h"
+SET_DEFAULT_DEBUG_CHANNEL(EXCEPT); // some headers have code with asserts, so do this first
+
+#include "pal/corunix.hpp"
+#include "pal/handleapi.hpp"
+#include "pal/thread.hpp"
+#include "pal/threadinfo.hpp"
+#include "pal/threadsusp.hpp"
+#include "pal/seh.hpp"
+
+#include "pal/palinternal.h"
+#if !HAVE_MACH_EXCEPTIONS
+#include "pal/init.h"
+#include "pal/process.h"
+#include "pal/debug.h"
+
+#include <signal.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/ucontext.h>
+#include <sys/utsname.h>
+#include <unistd.h>
+
+#include "pal/context.h"
+
+using namespace CorUnix;
+
+#ifdef SIGRTMIN
+#define INJECT_ACTIVATION_SIGNAL SIGRTMIN
+#endif
+
+#if !defined(INJECT_ACTIVATION_SIGNAL) && defined(FEATURE_HIJACK)
+#error FEATURE_HIJACK requires INJECT_ACTIVATION_SIGNAL to be defined
+#endif
+
+/* local type definitions *****************************************************/
+
+#if !HAVE_SIGINFO_T
+/* This allows us to compile on platforms that don't have siginfo_t.
+ * Exceptions will work poorly on those platforms. */
+#warning Exceptions will work poorly on this platform
+typedef void *siginfo_t;
+#endif /* !HAVE_SIGINFO_T */
+typedef void (*SIGFUNC)(int, siginfo_t *, void *);
+
+/* internal function declarations *********************************************/
+
+static void sigill_handler(int code, siginfo_t *siginfo, void *context);
+static void sigfpe_handler(int code, siginfo_t *siginfo, void *context);
+static void sigsegv_handler(int code, siginfo_t *siginfo, void *context);
+static void sigtrap_handler(int code, siginfo_t *siginfo, void *context);
+static void sigbus_handler(int code, siginfo_t *siginfo, void *context);
+static void sigint_handler(int code, siginfo_t *siginfo, void *context);
+static void sigquit_handler(int code, siginfo_t *siginfo, void *context);
+static void sigterm_handler(int code, siginfo_t *siginfo, void *context);
+
+static bool common_signal_handler(int code, siginfo_t *siginfo, void *sigcontext, int numParams, ...);
+
+#ifdef INJECT_ACTIVATION_SIGNAL
+static void inject_activation_handler(int code, siginfo_t *siginfo, void *context);
+#endif
+
+static void handle_signal(int signal_id, SIGFUNC sigfunc, struct sigaction *previousAction);
+static void restore_signal(int signal_id, struct sigaction *previousAction);
+
+/* internal data declarations *********************************************/
+
+struct sigaction g_previous_sigill;
+struct sigaction g_previous_sigtrap;
+struct sigaction g_previous_sigfpe;
+struct sigaction g_previous_sigbus;
+struct sigaction g_previous_sigsegv;
+struct sigaction g_previous_sigint;
+struct sigaction g_previous_sigquit;
+struct sigaction g_previous_sigterm;
+
+static bool registered_sigterm_handler = false;
+
+#ifdef INJECT_ACTIVATION_SIGNAL
+struct sigaction g_previous_activation;
+#endif
+
+/* public function definitions ************************************************/
+
+/*++
+Function :
+ SEHInitializeSignals
+
+ Set up signal handlers to catch signals and translate them to exceptions
+
+Parameters :
+ None
+
+Return :
+ TRUE in case of a success, FALSE otherwise
+--*/
+BOOL SEHInitializeSignals(DWORD flags)
+{
+ TRACE("Initializing signal handlers\n");
+
+ /* we call handle_signal for every possible signal, even
+ if we don't provide a signal handler.
+
+ handle_signal will set SA_RESTART flag for specified signal.
+ Therefore, all signals will have SA_RESTART flag set, preventing
+ slow Unix system calls from being interrupted. On systems without
+ siginfo_t, SIGKILL and SIGSTOP can't be restarted, so we don't
+ handle those signals. Both the Darwin and FreeBSD man pages say
+ that SIGKILL and SIGSTOP can't be handled, but FreeBSD allows us
+ to register a handler for them anyway. We don't do that.
+
+ see sigaction man page for more details
+ */
+ handle_signal(SIGILL, sigill_handler, &g_previous_sigill);
+ handle_signal(SIGTRAP, sigtrap_handler, &g_previous_sigtrap);
+ handle_signal(SIGFPE, sigfpe_handler, &g_previous_sigfpe);
+ handle_signal(SIGBUS, sigbus_handler, &g_previous_sigbus);
+ handle_signal(SIGSEGV, sigsegv_handler, &g_previous_sigsegv);
+ handle_signal(SIGINT, sigint_handler, &g_previous_sigint);
+ handle_signal(SIGQUIT, sigquit_handler, &g_previous_sigquit);
+
+ if (flags & PAL_INITIALIZE_REGISTER_SIGTERM_HANDLER)
+ {
+ handle_signal(SIGTERM, sigterm_handler, &g_previous_sigterm);
+ registered_sigterm_handler = true;
+ }
+
+#ifdef INJECT_ACTIVATION_SIGNAL
+ handle_signal(INJECT_ACTIVATION_SIGNAL, inject_activation_handler, &g_previous_activation);
+#endif
+
+ /* The default action for SIGPIPE is process termination.
+ Since SIGPIPE can be signaled when trying to write on a socket for which
+ the connection has been dropped, we need to tell the system we want
+ to ignore this signal.
+
+ Instead of terminating the process, the system call which would had
+ issued a SIGPIPE will, instead, report an error and set errno to EPIPE.
+ */
+ signal(SIGPIPE, SIG_IGN);
+
+ return TRUE;
+}
+
+/*++
+Function :
+ SEHCleanupSignals
+
+ Restore default signal handlers
+
+Parameters :
+ None
+
+ (no return value)
+
+note :
+reason for this function is that during PAL_Terminate, we reach a point where
+SEH isn't possible anymore (handle manager is off, etc). Past that point,
+we can't avoid crashing on a signal.
+--*/
+void SEHCleanupSignals()
+{
+ TRACE("Restoring default signal handlers\n");
+
+ restore_signal(SIGILL, &g_previous_sigill);
+ restore_signal(SIGTRAP, &g_previous_sigtrap);
+ restore_signal(SIGFPE, &g_previous_sigfpe);
+ restore_signal(SIGBUS, &g_previous_sigbus);
+ restore_signal(SIGSEGV, &g_previous_sigsegv);
+ restore_signal(SIGINT, &g_previous_sigint);
+ restore_signal(SIGQUIT, &g_previous_sigquit);
+
+ if (registered_sigterm_handler)
+ {
+ restore_signal(SIGTERM, &g_previous_sigterm);
+ }
+
+#ifdef INJECT_ACTIVATION_SIGNAL
+ restore_signal(INJECT_ACTIVATION_SIGNAL, &g_previous_activation);
+#endif
+}
+
+/* internal function definitions **********************************************/
+
+/*++
+Function :
+ sigill_handler
+
+ handle SIGILL signal (EXCEPTION_ILLEGAL_INSTRUCTION, others?)
+
+Parameters :
+ POSIX signal handler parameter list ("man sigaction" for details)
+
+ (no return value)
+--*/
+static void sigill_handler(int code, siginfo_t *siginfo, void *context)
+{
+ if (PALIsInitialized())
+ {
+ if (common_signal_handler(code, siginfo, context, 0))
+ {
+ return;
+ }
+ }
+
+ if (g_previous_sigill.sa_sigaction != NULL)
+ {
+ g_previous_sigill.sa_sigaction(code, siginfo, context);
+ }
+ else
+ {
+ // Restore the original or default handler and restart h/w exception
+ restore_signal(code, &g_previous_sigill);
+ }
+
+ PROCNotifyProcessShutdown();
+}
+
+/*++
+Function :
+ sigfpe_handler
+
+ handle SIGFPE signal (division by zero, floating point exception)
+
+Parameters :
+ POSIX signal handler parameter list ("man sigaction" for details)
+
+ (no return value)
+--*/
+static void sigfpe_handler(int code, siginfo_t *siginfo, void *context)
+{
+ if (PALIsInitialized())
+ {
+ if (common_signal_handler(code, siginfo, context, 0))
+ {
+ return;
+ }
+ }
+
+ if (g_previous_sigfpe.sa_sigaction != NULL)
+ {
+ g_previous_sigfpe.sa_sigaction(code, siginfo, context);
+ }
+ else
+ {
+ // Restore the original or default handler and restart h/w exception
+ restore_signal(code, &g_previous_sigfpe);
+ }
+
+ PROCNotifyProcessShutdown();
+}
+
+/*++
+Function :
+ sigsegv_handler
+
+ handle SIGSEGV signal (EXCEPTION_ACCESS_VIOLATION, others)
+
+Parameters :
+ POSIX signal handler parameter list ("man sigaction" for details)
+
+ (no return value)
+--*/
+static void sigsegv_handler(int code, siginfo_t *siginfo, void *context)
+{
+ if (PALIsInitialized())
+ {
+ // TODO: First variable parameter says whether a read (0) or write (non-0) caused the
+ // fault. We must disassemble the instruction at record.ExceptionAddress
+ // to correctly fill in this value.
+ if (common_signal_handler(code, siginfo, context, 2, (size_t)0, (size_t)siginfo->si_addr))
+ {
+ return;
+ }
+ }
+
+ if (g_previous_sigsegv.sa_sigaction != NULL)
+ {
+ g_previous_sigsegv.sa_sigaction(code, siginfo, context);
+ }
+ else
+ {
+ // Restore the original or default handler and restart h/w exception
+ restore_signal(code, &g_previous_sigsegv);
+ }
+
+ PROCNotifyProcessShutdown();
+}
+
+/*++
+Function :
+ sigtrap_handler
+
+ handle SIGTRAP signal (EXCEPTION_SINGLE_STEP, EXCEPTION_BREAKPOINT)
+
+Parameters :
+ POSIX signal handler parameter list ("man sigaction" for details)
+
+ (no return value)
+--*/
+static void sigtrap_handler(int code, siginfo_t *siginfo, void *context)
+{
+ if (PALIsInitialized())
+ {
+ if (common_signal_handler(code, siginfo, context, 0))
+ {
+ return;
+ }
+ }
+
+ if (g_previous_sigtrap.sa_sigaction != NULL)
+ {
+ g_previous_sigtrap.sa_sigaction(code, siginfo, context);
+ }
+ else
+ {
+ // We abort instead of restore the original or default handler and returning
+ // because returning from a SIGTRAP handler continues execution past the trap.
+ PROCAbort();
+ }
+
+ PROCNotifyProcessShutdown();
+}
+
+/*++
+Function :
+ sigbus_handler
+
+ handle SIGBUS signal (EXCEPTION_ACCESS_VIOLATION?)
+
+Parameters :
+ POSIX signal handler parameter list ("man sigaction" for details)
+
+ (no return value)
+--*/
+static void sigbus_handler(int code, siginfo_t *siginfo, void *context)
+{
+ if (PALIsInitialized())
+ {
+ // TODO: First variable parameter says whether a read (0) or write (non-0) caused the
+ // fault. We must disassemble the instruction at record.ExceptionAddress
+ // to correctly fill in this value.
+ if (common_signal_handler(code, siginfo, context, 2, (size_t)0, (size_t)siginfo->si_addr))
+ {
+ return;
+ }
+ }
+
+ if (g_previous_sigbus.sa_sigaction != NULL)
+ {
+ g_previous_sigbus.sa_sigaction(code, siginfo, context);
+ }
+ else
+ {
+ // Restore the original or default handler and restart h/w exception
+ restore_signal(code, &g_previous_sigbus);
+ }
+
+ PROCNotifyProcessShutdown();
+}
+
+/*++
+Function :
+ sigint_handler
+
+ handle SIGINT signal
+
+Parameters :
+ POSIX signal handler parameter list ("man sigaction" for details)
+
+ (no return value)
+--*/
+static void sigint_handler(int code, siginfo_t *siginfo, void *context)
+{
+ PROCNotifyProcessShutdown();
+
+ // Restore the original or default handler and resend signal
+ restore_signal(code, &g_previous_sigint);
+ kill(gPID, code);
+}
+
+/*++
+Function :
+ sigquit_handler
+
+ handle SIGQUIT signal
+
+Parameters :
+ POSIX signal handler parameter list ("man sigaction" for details)
+
+ (no return value)
+--*/
+static void sigquit_handler(int code, siginfo_t *siginfo, void *context)
+{
+ PROCNotifyProcessShutdown();
+
+ // Restore the original or default handler and resend signal
+ restore_signal(code, &g_previous_sigquit);
+ kill(gPID, code);
+}
+
+/*++
+Function :
+ sigterm_handler
+
+ handle SIGTERM signal
+
+Parameters :
+ POSIX signal handler parameter list ("man sigaction" for details)
+
+ (no return value)
+--*/
+static void sigterm_handler(int code, siginfo_t *siginfo, void *context)
+{
+ if (PALIsInitialized())
+ {
+ // g_pSynchronizationManager shouldn't be null if PAL is initialized.
+ _ASSERTE(g_pSynchronizationManager != nullptr);
+
+ g_pSynchronizationManager->SendTerminationRequestToWorkerThread();
+ }
+ else
+ {
+ if (g_previous_sigterm.sa_sigaction != NULL)
+ {
+ g_previous_sigterm.sa_sigaction(code, siginfo, context);
+ }
+ }
+}
+
+#ifdef INJECT_ACTIVATION_SIGNAL
+/*++
+Function :
+ inject_activation_handler
+
+ Handle the INJECT_ACTIVATION_SIGNAL signal. This signal interrupts a running thread
+ so it can call the activation function that was specified when sending the signal.
+
+Parameters :
+ POSIX signal handler parameter list ("man sigaction" for details)
+
+(no return value)
+--*/
+static void inject_activation_handler(int code, siginfo_t *siginfo, void *context)
+{
+ // Only accept activations from the current process
+ if (g_activationFunction != NULL && siginfo->si_pid == getpid())
+ {
+ _ASSERTE(g_safeActivationCheckFunction != NULL);
+
+ native_context_t *ucontext = (native_context_t *)context;
+
+ CONTEXT winContext;
+ CONTEXTFromNativeContext(
+ ucontext,
+ &winContext,
+ CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT);
+
+ if (g_safeActivationCheckFunction(CONTEXTGetPC(&winContext), /* checkingCurrentThread */ TRUE))
+ {
+ g_activationFunction(&winContext);
+ // Activation function may have modified the context, so update it.
+ CONTEXTToNativeContext(&winContext, ucontext);
+ }
+ }
+ else if (g_previous_activation.sa_sigaction != NULL)
+ {
+ g_previous_activation.sa_sigaction(code, siginfo, context);
+ }
+}
+#endif
+
+/*++
+Function :
+ InjectActivationInternal
+
+ Interrupt the specified thread and have it call the activationFunction passed in
+
+Parameters :
+ pThread - target PAL thread
+ activationFunction - function to call
+
+(no return value)
+--*/
+PAL_ERROR InjectActivationInternal(CorUnix::CPalThread* pThread)
+{
+#ifdef INJECT_ACTIVATION_SIGNAL
+ int status = pthread_kill(pThread->GetPThreadSelf(), INJECT_ACTIVATION_SIGNAL);
+ if (status != 0)
+ {
+ // Failure to send the signal is fatal. There are only two cases when sending
+ // the signal can fail. First, if the signal ID is invalid and second,
+ // if the thread doesn't exist anymore.
+ PROCAbort();
+ }
+
+ return NO_ERROR;
+#else
+ return ERROR_CANCELLED;
+#endif
+}
+
+/*++
+Function :
+ SEHSetSafeState
+
+ specify whether the current thread is in a state where exception handling
+ of signals can be done safely
+
+Parameters:
+ BOOL state : TRUE if the thread is safe, FALSE otherwise
+
+(no return value)
+--*/
+void SEHSetSafeState(CPalThread *pthrCurrent, BOOL state)
+{
+ if (NULL == pthrCurrent)
+ {
+ ASSERT( "Unable to get the thread object.\n" );
+ return;
+ }
+ pthrCurrent->sehInfo.safe_state = state;
+}
+
+/*++
+Function :
+ SEHGetSafeState
+
+ determine whether the current thread is in a state where exception handling
+ of signals can be done safely
+
+ (no parameters)
+
+Return value :
+ TRUE if the thread is in a safe state, FALSE otherwise
+--*/
+BOOL SEHGetSafeState(CPalThread *pthrCurrent)
+{
+ if (NULL == pthrCurrent)
+ {
+ ASSERT( "Unable to get the thread object.\n" );
+ return FALSE;
+ }
+ return pthrCurrent->sehInfo.safe_state;
+}
+
+/*++
+Function :
+ common_signal_handler
+
+ common code for all signal handlers
+
+Parameters :
+ int code : signal received
+ siginfo_t *siginfo : siginfo passed to the signal handler
+ void *context : context structure passed to the signal handler
+ int numParams : number of variable parameters of the exception
+ ... : variable parameters of the exception (each of size_t type)
+
+ Returns true if the execution should continue or false if the exception was unhandled
+Note:
+ the "pointers" parameter should contain a valid exception record pointer,
+ but the ContextRecord pointer will be overwritten.
+--*/
+static bool common_signal_handler(int code, siginfo_t *siginfo, void *sigcontext, int numParams, ...)
+{
+ sigset_t signal_set;
+ CONTEXT *contextRecord;
+ EXCEPTION_RECORD *exceptionRecord;
+ native_context_t *ucontext;
+
+ ucontext = (native_context_t *)sigcontext;
+
+ AllocateExceptionRecords(&exceptionRecord, &contextRecord);
+
+ exceptionRecord->ExceptionCode = CONTEXTGetExceptionCodeForSignal(siginfo, ucontext);
+ exceptionRecord->ExceptionFlags = EXCEPTION_IS_SIGNAL;
+ exceptionRecord->ExceptionRecord = NULL;
+ exceptionRecord->ExceptionAddress = GetNativeContextPC(ucontext);
+ exceptionRecord->NumberParameters = numParams;
+
+ va_list params;
+ va_start(params, numParams);
+
+ for (int i = 0; i < numParams; i++)
+ {
+ exceptionRecord->ExceptionInformation[i] = va_arg(params, size_t);
+ }
+
+ // Pre-populate context with data from current frame, because ucontext doesn't have some data (e.g. SS register)
+ // which is required for restoring context
+ RtlCaptureContext(contextRecord);
+
+ ULONG contextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT;
+
+#if defined(_AMD64_)
+ contextFlags |= CONTEXT_XSTATE;
+#endif
+
+ // Fill context record with required information. from pal.h:
+ // On non-Win32 platforms, the CONTEXT pointer in the
+ // PEXCEPTION_POINTERS will contain at least the CONTEXT_CONTROL registers.
+ CONTEXTFromNativeContext(ucontext, contextRecord, contextFlags);
+
+ /* Unmask signal so we can receive it again */
+ sigemptyset(&signal_set);
+ sigaddset(&signal_set, code);
+ int sigmaskRet = pthread_sigmask(SIG_UNBLOCK, &signal_set, NULL);
+ if (sigmaskRet != 0)
+ {
+ ASSERT("pthread_sigmask failed; error number is %d\n", sigmaskRet);
+ }
+
+ contextRecord->ContextFlags |= CONTEXT_EXCEPTION_ACTIVE;
+ // The exception object takes ownership of the exceptionRecord and contextRecord
+ PAL_SEHException exception(exceptionRecord, contextRecord);
+
+ if (SEHProcessException(&exception))
+ {
+ // Exception handling may have modified the context, so update it.
+ CONTEXTToNativeContext(contextRecord, ucontext);
+ return true;
+ }
+
+ return false;
+}
+
+/*++
+Function :
+ handle_signal
+
+ register handler for specified signal
+
+Parameters :
+ int signal_id : signal to handle
+ SIGFUNC sigfunc : signal handler
+ previousAction : previous sigaction struct
+
+ (no return value)
+
+note : if sigfunc is NULL, the default signal handler is restored
+--*/
+void handle_signal(int signal_id, SIGFUNC sigfunc, struct sigaction *previousAction)
+{
+ struct sigaction newAction;
+
+ newAction.sa_flags = SA_RESTART;
+#if HAVE_SIGINFO_T
+ newAction.sa_handler = NULL;
+ newAction.sa_sigaction = sigfunc;
+ newAction.sa_flags |= SA_SIGINFO;
+#else /* HAVE_SIGINFO_T */
+ newAction.sa_handler = SIG_DFL;
+#endif /* HAVE_SIGINFO_T */
+ sigemptyset(&newAction.sa_mask);
+
+ if (-1 == sigaction(signal_id, &newAction, previousAction))
+ {
+ ASSERT("handle_signal: sigaction() call failed with error code %d (%s)\n",
+ errno, strerror(errno));
+ }
+}
+
+/*++
+Function :
+ restore_signal
+
+ restore handler for specified signal
+
+Parameters :
+ int signal_id : signal to handle
+ previousAction : previous sigaction struct to restore
+
+ (no return value)
+--*/
+void restore_signal(int signal_id, struct sigaction *previousAction)
+{
+ if (-1 == sigaction(signal_id, previousAction, NULL))
+ {
+ ASSERT("restore_signal: sigaction() call failed with error code %d (%s)\n",
+ errno, strerror(errno));
+ }
+}
+
+#endif // !HAVE_MACH_EXCEPTIONS
diff --git a/src/pal/src/exception/signal.hpp b/src/pal/src/exception/signal.hpp
new file mode 100644
index 0000000000..c0c950ed4d
--- /dev/null
+++ b/src/pal/src/exception/signal.hpp
@@ -0,0 +1,59 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ exception/signal.hpp
+
+Abstract:
+ Private signal handling utilities for SEH
+
+
+
+--*/
+
+#ifndef _PAL_SIGNAL_HPP_
+#define _PAL_SIGNAL_HPP_
+
+#if !HAVE_MACH_EXCEPTIONS
+
+/*++
+Function :
+ SEHInitializeSignals
+
+ Set-up signal handlers to catch signals and translate them to exceptions
+
+Parameters :
+ flags: PAL initialization flags
+
+Return :
+ TRUE in case of a success, FALSE otherwise
+--*/
+BOOL SEHInitializeSignals(DWORD flags);
+
+/*++
+Function :
+ SEHCleanupSignals
+
+ Restore default signal handlers
+
+ (no parameters, no return value)
+--*/
+void SEHCleanupSignals();
+
+#if (__GNUC__ > 3 || \
+ (__GNUC__ == 3 && __GNUC_MINOR__ > 2))
+// For gcc > 3.2, sjlj exceptions semantics are no longer available
+// Therefore we need to hijack out of signal handlers before second pass
+#define HIJACK_ON_SIGNAL 1
+#endif
+
+#endif // !HAVE_MACH_EXCEPTIONS
+
+#endif /* _PAL_SIGNAL_HPP_ */
+
diff --git a/src/pal/src/file/directory.cpp b/src/pal/src/file/directory.cpp
new file mode 100644
index 0000000000..8e54f94d69
--- /dev/null
+++ b/src/pal/src/file/directory.cpp
@@ -0,0 +1,725 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ directory.c
+
+Abstract:
+
+ Implementation of the file WIN API for the PAL
+
+Revision History:
+
+
+
+--*/
+
+#include "pal/palinternal.h"
+#include "pal/dbgmsg.h"
+#include "pal/file.h"
+#include "pal/stackstring.hpp"
+
+#include <stdlib.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+
+SET_DEFAULT_DEBUG_CHANNEL(FILE);
+
+
+
+/*++
+Function:
+ CreateDirectoryW
+
+Note:
+ lpSecurityAttributes always NULL.
+
+See MSDN doc.
+--*/
+BOOL
+PALAPI
+CreateDirectoryW(
+ IN LPCWSTR lpPathName,
+ IN LPSECURITY_ATTRIBUTES lpSecurityAttributes)
+{
+ BOOL bRet = FALSE;
+ DWORD dwLastError = 0;
+ int mb_size;
+ char *mb_dir = NULL;
+
+ PERF_ENTRY(CreateDirectoryW);
+ ENTRY("CreateDirectoryW(lpPathName=%p (%S), lpSecurityAttr=%p)\n",
+ lpPathName?lpPathName:W16_NULLSTRING,
+ lpPathName?lpPathName:W16_NULLSTRING, lpSecurityAttributes);
+
+ if ( lpSecurityAttributes )
+ {
+ ASSERT("lpSecurityAttributes is not NULL as it should be\n");
+ dwLastError = ERROR_INVALID_PARAMETER;
+ goto done;
+ }
+
+ /* translate the wide char lpPathName string to multibyte string */
+ if(0 == (mb_size = WideCharToMultiByte( CP_ACP, 0, lpPathName, -1, NULL, 0,
+ NULL, NULL )))
+ {
+ ASSERT("WideCharToMultiByte failure! error is %d\n", GetLastError());
+ dwLastError = ERROR_INTERNAL_ERROR;
+ goto done;
+ }
+
+ if (((mb_dir = (char *)PAL_malloc(mb_size)) == NULL) ||
+ (WideCharToMultiByte( CP_ACP, 0, lpPathName, -1, mb_dir, mb_size, NULL,
+ NULL) != mb_size))
+ {
+ ASSERT("WideCharToMultiByte or PAL_malloc failure! LastError:%d errno:%d\n",
+ GetLastError(), errno);
+ dwLastError = ERROR_INTERNAL_ERROR;
+ goto done;
+ }
+
+ bRet = CreateDirectoryA(mb_dir,NULL);
+done:
+ if( dwLastError )
+ {
+ SetLastError( dwLastError );
+ }
+ if (mb_dir != NULL)
+ {
+ PAL_free(mb_dir);
+ }
+ LOGEXIT("CreateDirectoryW returns BOOL %d\n", bRet);
+ PERF_EXIT(CreateDirectoryW);
+ return bRet;
+}
+
+/*++
+Routine Name:
+
+ RemoveDirectoryHelper
+
+Routine Description:
+
+ Core function which removes a directory. Called by RemoveDirectory[AW]
+
+Parameters:
+
+ LPSTR lpPathName - [in/out]
+ The directory name to remove. It is converted in place to a unix path.
+
+Return Value:
+
+ BOOL -
+ TRUE <=> successful
+
+--*/
+
+static
+BOOL
+RemoveDirectoryHelper (
+ PathCharString& lpPathName,
+ LPDWORD dwLastError
+)
+{
+ BOOL bRet = FALSE;
+ *dwLastError = 0;
+
+ FILEDosToUnixPathA( lpPathName );
+
+ if ( rmdir(lpPathName) != 0 )
+ {
+ TRACE("Removal of directory [%s] was unsuccessful, errno = %d.\n",
+ lpPathName.GetString(), errno);
+
+ switch( errno )
+ {
+ case ENOTDIR:
+ /* FALL THROUGH */
+ case ENOENT:
+ {
+ struct stat stat_data;
+
+ if ( stat( lpPathName, &stat_data) == 0 &&
+ (stat_data.st_mode & S_IFMT) == S_IFREG )
+ {
+ /* Not a directory, it is a file. */
+ *dwLastError = ERROR_DIRECTORY;
+ }
+ else
+ {
+ FILEGetProperNotFoundError( lpPathName, dwLastError );
+ }
+ break;
+ }
+ case ENOTEMPTY:
+ *dwLastError = ERROR_DIR_NOT_EMPTY;
+ break;
+ default:
+ *dwLastError = ERROR_ACCESS_DENIED;
+ }
+ }
+ else {
+ TRACE("Removal of directory [%s] was successful.\n", lpPathName.GetString());
+ bRet = TRUE;
+ }
+
+ return bRet;
+}
+
+/*++
+Function:
+ RemoveDirectoryA
+
+See MSDN doc.
+--*/
+BOOL
+PALAPI
+RemoveDirectoryA(
+ IN LPCSTR lpPathName)
+{
+ DWORD dwLastError = 0;
+ BOOL bRet = FALSE;
+ PathCharString mb_dirPathString;
+
+ PERF_ENTRY(RemoveDirectoryA);
+ ENTRY("RemoveDirectoryA(lpPathName=%p (%s))\n",
+ lpPathName,
+ lpPathName);
+
+ if (lpPathName == NULL)
+ {
+ dwLastError = ERROR_PATH_NOT_FOUND;
+ goto done;
+ }
+
+ if (!mb_dirPathString.Set(lpPathName, strlen(lpPathName)))
+ {
+ WARN("Set failed !\n");
+ dwLastError = ERROR_NOT_ENOUGH_MEMORY;
+ goto done;
+ }
+
+ bRet = RemoveDirectoryHelper (mb_dirPathString, &dwLastError);
+
+done:
+ if( dwLastError )
+ {
+ SetLastError( dwLastError );
+ }
+
+ LOGEXIT("RemoveDirectoryA returns BOOL %d\n", bRet);
+ PERF_EXIT(RemoveDirectoryA);
+ return bRet;
+}
+
+/*++
+Function:
+ RemoveDirectoryW
+
+See MSDN doc.
+--*/
+BOOL
+PALAPI
+RemoveDirectoryW(
+ IN LPCWSTR lpPathName)
+{
+ PathCharString mb_dirPathString;
+ int mb_size;
+ DWORD dwLastError = 0;
+ BOOL bRet = FALSE;
+ size_t length;
+ char * mb_dir = NULL;
+
+ PERF_ENTRY(RemoveDirectoryW);
+ ENTRY("RemoveDirectoryW(lpPathName=%p (%S))\n",
+ lpPathName?lpPathName:W16_NULLSTRING,
+ lpPathName?lpPathName:W16_NULLSTRING);
+
+ if (lpPathName == NULL)
+ {
+ dwLastError = ERROR_PATH_NOT_FOUND;
+ goto done;
+ }
+
+ length = (PAL_wcslen(lpPathName)+1) * 3;
+ mb_dir = mb_dirPathString.OpenStringBuffer(length);
+ if (NULL == mb_dir)
+ {
+ dwLastError = ERROR_NOT_ENOUGH_MEMORY;
+ goto done;
+ }
+
+ mb_size = WideCharToMultiByte( CP_ACP, 0, lpPathName, -1, mb_dir, length,
+ NULL, NULL );
+
+ if( mb_size == 0 )
+ {
+ mb_dirPathString.CloseBuffer(0);
+ ASSERT("WideCharToMultiByte failure! error is %d\n", dwLastError);
+ dwLastError = ERROR_INTERNAL_ERROR;
+ goto done;
+ }
+
+ mb_dirPathString.CloseBuffer(mb_size - 1);
+
+ if ((bRet = RemoveDirectoryHelper (mb_dirPathString, &dwLastError)))
+ {
+ TRACE("Removal of directory [%s] was successful.\n", mb_dir);
+ }
+
+done:
+ if( dwLastError )
+ {
+ SetLastError( dwLastError );
+ }
+
+ LOGEXIT("RemoveDirectoryW returns BOOL %d\n", bRet);
+ PERF_EXIT(RemoveDirectoryW);
+ return bRet;
+}
+
+
+/*++
+Function:
+ GetCurrentDirectoryA
+
+--*/
+DWORD
+GetCurrentDirectoryA(PathCharString& lpBuffer)
+{
+ DWORD dwDirLen = 0;
+ DWORD dwLastError = 0;
+
+ char *current_dir;
+
+ PERF_ENTRY(GetCurrentDirectoryA);
+ ENTRY("GetCurrentDirectoryA(lpBuffer=%p)\n", lpBuffer.GetString());
+
+ current_dir = lpBuffer.OpenStringBuffer(MAX_PATH);
+ /* NULL first arg means getcwd will allocate the string */
+ current_dir = PAL__getcwd( current_dir, MAX_PATH);
+
+ if (current_dir != NULL )
+ {
+ dwDirLen = strlen( current_dir );
+ lpBuffer.CloseBuffer(dwDirLen);
+ goto done;
+ }
+ else if ( errno == ERANGE )
+ {
+ lpBuffer.CloseBuffer(0);
+ current_dir = PAL__getcwd( NULL, 0);
+ }
+
+ if ( !current_dir )
+ {
+ WARN("Getcwd failed with errno=%d [%s]\n", errno, strerror(errno));
+ dwLastError = DIRGetLastErrorFromErrno();
+ dwDirLen = 0;
+ goto done;
+ }
+
+ dwDirLen = strlen( current_dir );
+ lpBuffer.Set(current_dir, dwDirLen);
+ PAL_free(current_dir);
+done:
+
+ if ( dwLastError )
+ {
+ SetLastError(dwLastError);
+ }
+
+ LOGEXIT("GetCurrentDirectoryA returns DWORD %u\n", dwDirLen);
+ PERF_EXIT(GetCurrentDirectoryA);
+ return dwDirLen;
+}
+
+/*++
+Function:
+ GetCurrentDirectoryA
+
+See MSDN doc.
+--*/
+DWORD
+PALAPI
+GetCurrentDirectoryA(
+ IN DWORD nBufferLength,
+ OUT LPSTR lpBuffer)
+{
+
+ PathCharString lpBufferString;
+ DWORD dwDirLen = GetCurrentDirectoryA(lpBufferString);
+
+ /* if the supplied buffer isn't long enough, return the required
+ length, including room for the NULL terminator */
+ if ( nBufferLength <= dwDirLen )
+ {
+ ++dwDirLen; /* include space for the NULL */
+ }
+ else
+ {
+ strcpy_s( lpBuffer, nBufferLength, lpBufferString );
+ }
+
+ return dwDirLen;
+}
+
+/*++
+Function:
+ GetCurrentDirectoryW
+
+See MSDN doc.
+--*/
+DWORD
+PALAPI
+GetCurrentDirectoryW(
+ IN DWORD nBufferLength,
+ OUT LPWSTR lpBuffer)
+{
+ DWORD dwWideLen = 0;
+ DWORD dwLastError = ERROR_BAD_PATHNAME;
+ int dir_len;
+ PathCharString current_dir;
+
+ PERF_ENTRY(GetCurrentDirectoryW);
+ ENTRY("GetCurrentDirectoryW(nBufferLength=%u, lpBuffer=%p)\n",
+ nBufferLength, lpBuffer);
+
+
+ dir_len = GetCurrentDirectoryA(current_dir);
+
+ if( dir_len == 0)
+ {
+ dwLastError = DIRGetLastErrorFromErrno();
+ goto done;
+ }
+
+ dwWideLen = MultiByteToWideChar( CP_ACP, 0,
+ current_dir, dir_len,
+ NULL, 0 );
+
+ /* if the supplied buffer isn't long enough, return the required
+ length, including room for the NULL terminator */
+ if ( nBufferLength > dwWideLen )
+ {
+ if(!MultiByteToWideChar( CP_ACP, 0, current_dir, dir_len + 1,
+ lpBuffer, nBufferLength ))
+ {
+ ASSERT("MultiByteToWideChar failure!\n");
+ dwWideLen = 0;
+ dwLastError = ERROR_INTERNAL_ERROR;
+ }
+ }
+ else
+ {
+ ++dwWideLen; /* include the space for the NULL */
+ }
+
+done:
+
+ if ( dwLastError )
+ {
+ SetLastError(dwLastError);
+ }
+
+ LOGEXIT("GetCurrentDirectoryW returns DWORD %u\n", dwWideLen);
+ PERF_EXIT(GetCurrentDirectoryW);
+ return dwWideLen;
+}
+
+
+/*++
+Function:
+ SetCurrentDirectoryW
+
+See MSDN doc.
+--*/
+BOOL
+PALAPI
+SetCurrentDirectoryW(
+ IN LPCWSTR lpPathName)
+{
+ BOOL bRet;
+ DWORD dwLastError = 0;
+ PathCharString dirPathString;
+ int size;
+ size_t length;
+ char * dir = NULL;
+
+ PERF_ENTRY(SetCurrentDirectoryW);
+ ENTRY("SetCurrentDirectoryW(lpPathName=%p (%S))\n",
+ lpPathName?lpPathName:W16_NULLSTRING,
+ lpPathName?lpPathName:W16_NULLSTRING);
+
+ /*check if the given path is null. If so
+ return FALSE*/
+ if (lpPathName == NULL )
+ {
+ ERROR("Invalid path/directory name\n");
+ dwLastError = ERROR_INVALID_NAME;
+ bRet = FALSE;
+ goto done;
+ }
+
+ length = (PAL_wcslen(lpPathName)+1) * 3;
+ dir = dirPathString.OpenStringBuffer(length);
+ if (NULL == dir)
+ {
+ dwLastError = ERROR_NOT_ENOUGH_MEMORY;
+ bRet = FALSE;
+ goto done;
+ }
+
+ size = WideCharToMultiByte( CP_ACP, 0, lpPathName, -1, dir, length,
+ NULL, NULL );
+
+ if( size == 0 )
+ {
+ dirPathString.CloseBuffer(0);
+ dwLastError = GetLastError();
+ ASSERT("WideCharToMultiByte failure! error is %d\n", dwLastError);
+ dwLastError = ERROR_INTERNAL_ERROR;
+ bRet = FALSE;
+ goto done;
+ }
+
+ dirPathString.CloseBuffer(size - 1);
+ bRet = SetCurrentDirectoryA(dir);
+done:
+ if( dwLastError )
+ {
+ SetLastError(dwLastError);
+ }
+
+ LOGEXIT("SetCurrentDirectoryW returns BOOL %d\n", bRet);
+ PERF_EXIT(SetCurrentDirectoryW);
+ return bRet;
+}
+
+/*++
+Function:
+ CreateDirectoryA
+
+Note:
+ lpSecurityAttributes always NULL.
+
+See MSDN doc.
+--*/
+BOOL
+PALAPI
+CreateDirectoryA(
+ IN LPCSTR lpPathName,
+ IN LPSECURITY_ATTRIBUTES lpSecurityAttributes)
+{
+ BOOL bRet = FALSE;
+ DWORD dwLastError = 0;
+ PathCharString realPath;
+ char* realPathBuf;
+ LPSTR unixPathName = NULL;
+ int pathLength;
+ int i;
+ const int mode = S_IRWXU | S_IRWXG | S_IRWXO;
+
+ PERF_ENTRY(CreateDirectoryA);
+ ENTRY("CreateDirectoryA(lpPathName=%p (%s), lpSecurityAttr=%p)\n",
+ lpPathName?lpPathName:"NULL",
+ lpPathName?lpPathName:"NULL", lpSecurityAttributes);
+
+ if ( lpSecurityAttributes )
+ {
+ ASSERT("lpSecurityAttributes is not NULL as it should be\n");
+ dwLastError = ERROR_INVALID_PARAMETER;
+ goto done;
+ }
+
+ // Windows returns ERROR_PATH_NOT_FOUND when called with NULL.
+ // If we don't have this check, strdup(NULL) segfaults.
+ if (lpPathName == NULL)
+ {
+ ERROR("CreateDirectoryA called with NULL pathname!\n");
+ dwLastError = ERROR_PATH_NOT_FOUND;
+ goto done;
+ }
+
+ unixPathName = PAL__strdup(lpPathName);
+ if (unixPathName == NULL )
+ {
+ ERROR("PAL__strdup() failed\n");
+ dwLastError = ERROR_NOT_ENOUGH_MEMORY;
+ goto done;
+ }
+ FILEDosToUnixPathA( unixPathName );
+ // Remove any trailing slashes at the end because mkdir might not
+ // handle them appropriately on all platforms.
+ pathLength = strlen(unixPathName);
+ i = pathLength;
+ while(i > 1)
+ {
+ if(unixPathName[i - 1] =='/')
+ {
+ unixPathName[i - 1]='\0';
+ i--;
+ }
+ else
+ {
+ break;
+ }
+ }
+
+
+ // Get an absolute path.
+ if (unixPathName[0] == '/')
+ {
+ realPathBuf = unixPathName;
+ }
+ else
+ {
+
+ DWORD len = GetCurrentDirectoryA(realPath);
+ if (len == 0 || !realPath.Reserve(realPath.GetCount() + pathLength + 1 ))
+ {
+ dwLastError = DIRGetLastErrorFromErrno();
+ WARN("Getcwd failed with errno=%d \n", dwLastError);
+ goto done;
+ }
+
+ realPath.Append("/", 1);
+ realPath.Append(unixPathName, pathLength);
+ realPathBuf = realPath.OpenStringBuffer(realPath.GetCount());
+ }
+
+ // Canonicalize the path so we can determine its length.
+ FILECanonicalizePath(realPathBuf);
+
+ if ( mkdir(realPathBuf, mode) != 0 )
+ {
+ TRACE("Creation of directory [%s] was unsuccessful, errno = %d.\n",
+ unixPathName, errno);
+
+ switch( errno )
+ {
+ case ENOTDIR:
+ /* FALL THROUGH */
+ case ENOENT:
+ FILEGetProperNotFoundError( realPathBuf, &dwLastError );
+ goto done;
+ case EEXIST:
+ dwLastError = ERROR_ALREADY_EXISTS;
+ break;
+ default:
+ dwLastError = ERROR_ACCESS_DENIED;
+ }
+ }
+ else
+ {
+ TRACE("Creation of directory [%s] was successful.\n", unixPathName);
+ bRet = TRUE;
+ }
+
+ realPath.CloseBuffer(0); //The PathCharString usage is done
+done:
+ if( dwLastError )
+ {
+ SetLastError( dwLastError );
+ }
+ PAL_free( unixPathName );
+ LOGEXIT("CreateDirectoryA returns BOOL %d\n", bRet);
+ PERF_EXIT(CreateDirectoryA);
+ return bRet;
+}
+
+/*++
+Function:
+ SetCurrentDirectoryA
+
+See MSDN doc.
+--*/
+BOOL
+PALAPI
+SetCurrentDirectoryA(
+ IN LPCSTR lpPathName)
+{
+ BOOL bRet = FALSE;
+ DWORD dwLastError = 0;
+ int result;
+ LPSTR unixPathName = NULL;
+
+ PERF_ENTRY(SetCurrentDirectoryA);
+ ENTRY("SetCurrentDirectoryA(lpPathName=%p (%s))\n",
+ lpPathName?lpPathName:"NULL",
+ lpPathName?lpPathName:"NULL");
+
+ /*check if the given path is null. If so
+ return FALSE*/
+ if (lpPathName == NULL )
+ {
+ ERROR("Invalid path/directory name\n");
+ dwLastError = ERROR_INVALID_NAME;
+ goto done;
+ }
+
+ unixPathName = PAL__strdup(lpPathName);
+ if (unixPathName == NULL )
+ {
+ ERROR("PAL__strdup() failed\n");
+ dwLastError = ERROR_NOT_ENOUGH_MEMORY;
+ goto done;
+ }
+ FILEDosToUnixPathA( unixPathName );
+
+ TRACE("Attempting to open Unix dir [%s]\n", unixPathName);
+ result = chdir(unixPathName);
+
+ if ( result == 0 )
+ {
+ bRet = TRUE;
+ }
+ else
+ {
+ if ( errno == ENOTDIR || errno == ENOENT )
+ {
+ struct stat stat_data;
+
+ if ( stat( unixPathName, &stat_data) == 0 &&
+ (stat_data.st_mode & S_IFMT) == S_IFREG )
+ {
+ /* Not a directory, it is a file. */
+ dwLastError = ERROR_DIRECTORY;
+ }
+ else
+ {
+ FILEGetProperNotFoundError( unixPathName, &dwLastError );
+ }
+ TRACE("chdir() failed, path was invalid.\n");
+ }
+ else
+ {
+ dwLastError = ERROR_ACCESS_DENIED;
+ ERROR("chdir() failed; errno is %d (%s)\n", errno, strerror(errno));
+ }
+ }
+
+
+done:
+ if( dwLastError )
+ {
+ SetLastError(dwLastError);
+ }
+
+ if(unixPathName != NULL)
+ {
+ PAL_free( unixPathName );
+ }
+
+ LOGEXIT("SetCurrentDirectoryA returns BOOL %d\n", bRet);
+ PERF_EXIT(SetCurrentDirectoryA);
+ return bRet;
+}
diff --git a/src/pal/src/file/disk.cpp b/src/pal/src/file/disk.cpp
new file mode 100644
index 0000000000..ef1d488b28
--- /dev/null
+++ b/src/pal/src/file/disk.cpp
@@ -0,0 +1,180 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ disk.c
+
+Abstract:
+
+ Implementation of the disk information functions.
+
+Revision History:
+
+
+
+--*/
+
+#include "pal/palinternal.h"
+#include "pal/dbgmsg.h"
+#include "pal/file.h"
+#include "pal/stackstring.hpp"
+
+#include <sys/param.h>
+#if !defined(_AIX)
+// do we actually need this on other platforms. We don't seem to be using anything from there
+#include <sys/mount.h>
+#endif
+#include <errno.h>
+#if HAVE_STATVFS
+#include <sys/types.h>
+#include <sys/statvfs.h>
+#define statfs statvfs
+#if STATVFS64_PROTOTYPE_BROKEN
+typedef statvfs_t pal_statfs;
+#else // STATVFS64_PROTOTYPE_BROKEN
+typedef struct statvfs pal_statfs;
+#endif // STATVFS64_PROTOTYPE_BROKEN
+#else // HAVE_STATVFS
+typedef struct statfs pal_statfs;
+#endif // HAVE_STATVFS
+
+SET_DEFAULT_DEBUG_CHANNEL(FILE);
+
+/*++
+
+Function:
+
+ GetDiskFreeSpaceW
+
+See MSDN doc.
+--*/
+PALIMPORT
+BOOL
+PALAPI
+GetDiskFreeSpaceW(
+ LPCWSTR lpDirectoryName,
+ LPDWORD lpSectorsPerCluster,
+ LPDWORD lpBytesPerSector,
+ LPDWORD lpNumberOfFreeClusters, /* Caller will ignore output value */
+ LPDWORD lpTotalNumberOfClusters) /* Caller will ignore output value */
+{
+ BOOL bRetVal = FALSE;
+ pal_statfs fsInfoBuffer;
+ INT statfsRetVal = 0;
+ DWORD dwLastError = NO_ERROR;
+ PathCharString dirNameBufferPathString;
+ size_t length;
+ char * dirNameBuffer;
+ int size;
+
+ PERF_ENTRY(GetDiskFreeSpaceW);
+ ENTRY( "GetDiskFreeSpaceW( lpDirectoryName=%p (%S), lpSectorsPerCluster=%p,"
+ "lpBytesPerSector=%p, lpNumberOfFreeClusters=%p, "
+ "lpTotalNumberOfClusters=%p )\n", lpDirectoryName ? lpDirectoryName :
+ W16_NULLSTRING, lpDirectoryName ? lpDirectoryName :
+ W16_NULLSTRING, lpSectorsPerCluster, lpBytesPerSector,
+ lpNumberOfFreeClusters, lpTotalNumberOfClusters );
+
+ /* Sanity checks. */
+ if ( !lpSectorsPerCluster )
+ {
+ ERROR( "lpSectorsPerCluster cannot be NULL!\n" );
+ dwLastError = ERROR_INVALID_PARAMETER;
+ goto exit;
+ }
+ if ( !lpBytesPerSector )
+ {
+ ERROR( "lpBytesPerSector cannot be NULL!\n" );
+ dwLastError = ERROR_INVALID_PARAMETER;
+ goto exit;
+ }
+ if ( lpNumberOfFreeClusters || lpTotalNumberOfClusters )
+ {
+ TRACE("GetDiskFreeSpaceW is ignoring lpNumberOfFreeClusters"
+ " and lpTotalNumberOfClusters\n" );
+ }
+ if ( lpDirectoryName && PAL_wcslen( lpDirectoryName ) == 0 )
+ {
+ ERROR( "lpDirectoryName is empty.\n" );
+ dwLastError = ERROR_INVALID_PARAMETER;
+ goto exit;
+ }
+
+ /* Fusion uses this API to round file sizes up to their actual size
+ on-disk based on the BytesPerSector * SectorsPerCluster.
+ The intent is to avoid computing the sum of all file sizes in the
+ cache just in bytes and not account for the cluster-sized slop, when
+ determining if the cache is too large or not. */
+
+ if ( lpDirectoryName )
+ {
+ length = (PAL_wcslen(lpDirectoryName)+1) * 3;
+ dirNameBuffer = dirNameBufferPathString.OpenStringBuffer(length);
+ if (NULL == dirNameBuffer)
+ {
+ dwLastError = ERROR_NOT_ENOUGH_MEMORY;
+ goto exit;
+ }
+
+ size = WideCharToMultiByte( CP_ACP, 0, lpDirectoryName, -1,
+ dirNameBuffer,length, 0, 0 );
+ dirNameBufferPathString.CloseBuffer(size);
+ if ( size != 0 )
+ {
+ FILEDosToUnixPathA( dirNameBuffer );
+ statfsRetVal = statfs( dirNameBuffer, &fsInfoBuffer );
+ }
+ else
+ {
+ ASSERT( "Unable to convert the lpDirectoryName to multibyte.\n" );
+ dwLastError = ERROR_INTERNAL_ERROR;
+ goto exit;
+ }
+ }
+ else
+ {
+ statfsRetVal = statfs( "/", &fsInfoBuffer );
+ }
+
+ if ( statfsRetVal == 0 )
+ {
+ *lpBytesPerSector = fsInfoBuffer.f_bsize;
+ *lpSectorsPerCluster = 1;
+ bRetVal = TRUE;
+ }
+ else
+ {
+ if ( errno == ENOTDIR || errno == ENOENT )
+ {
+ FILEGetProperNotFoundError( dirNameBuffer, &dwLastError );
+ goto exit;
+ }
+ dwLastError = FILEGetLastErrorFromErrno();
+ if ( ERROR_INTERNAL_ERROR == dwLastError )
+ {
+ ASSERT("statfs() not expected to fail with errno:%d (%s)\n",
+ errno, strerror(errno));
+ }
+ else
+ {
+ TRACE("statfs() failed, errno:%d (%s)\n", errno, strerror(errno));
+ }
+ }
+
+exit:
+ if ( NO_ERROR != dwLastError )
+ {
+ SetLastError( dwLastError );
+ }
+
+ LOGEXIT( "GetDiskFreeSpace returning %s.\n", bRetVal == TRUE ? "TRUE" : "FALSE" );
+ PERF_EXIT(GetDiskFreeSpaceW);
+ return bRetVal;
+}
+
diff --git a/src/pal/src/file/file.cpp b/src/pal/src/file/file.cpp
new file mode 100644
index 0000000000..6443a5e7b9
--- /dev/null
+++ b/src/pal/src/file/file.cpp
@@ -0,0 +1,4900 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ file.cpp
+
+Abstract:
+
+ Implementation of the file WIN API for the PAL
+
+
+
+--*/
+
+#include "pal/thread.hpp"
+#include "pal/file.hpp"
+#include "shmfilelockmgr.hpp"
+#include "pal/malloc.hpp"
+#include "pal/stackstring.hpp"
+
+#include "pal/palinternal.h"
+#include "pal/dbgmsg.h"
+#include "pal/file.h"
+#include "pal/filetime.h"
+#include "pal/utils.h"
+
+#include <time.h>
+#include <stdio.h>
+#include <sys/file.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <sys/mount.h>
+#include <errno.h>
+#include <limits.h>
+
+using namespace CorUnix;
+
+SET_DEFAULT_DEBUG_CHANNEL(FILE);
+
+int MaxWCharToAcpLengthFactor = 3;
+
+PAL_ERROR
+InternalSetFilePointerForUnixFd(
+ int iUnixFd,
+ LONG lDistanceToMove,
+ PLONG lpDistanceToMoveHigh,
+ DWORD dwMoveMethod,
+ PLONG lpNewFilePointerLow
+ );
+
+void
+FileCleanupRoutine(
+ CPalThread *pThread,
+ IPalObject *pObjectToCleanup,
+ bool fShutdown,
+ bool fCleanupSharedState
+ );
+
+CObjectType CorUnix::otFile(
+ otiFile,
+ FileCleanupRoutine,
+ NULL, // No initialization routine
+ 0, // No immutable data
+ sizeof(CFileProcessLocalData),
+ 0, // No shared data
+ GENERIC_READ|GENERIC_WRITE, // Ignored -- no Win32 object security support
+ CObjectType::SecuritySupported,
+ CObjectType::OSPersistedSecurityInfo,
+ CObjectType::UnnamedObject,
+ CObjectType::LocalDuplicationOnly,
+ CObjectType::UnwaitableObject,
+ CObjectType::SignalingNotApplicable,
+ CObjectType::ThreadReleaseNotApplicable,
+ CObjectType::OwnershipNotApplicable
+ );
+
+CAllowedObjectTypes CorUnix::aotFile(otiFile);
+static CSharedMemoryFileLockMgr _FileLockManager;
+IFileLockManager *CorUnix::g_pFileLockManager = &_FileLockManager;
+
+void
+FileCleanupRoutine(
+ CPalThread *pThread,
+ IPalObject *pObjectToCleanup,
+ bool fShutdown,
+ bool fCleanupSharedState
+ )
+{
+ PAL_ERROR palError;
+ CFileProcessLocalData *pLocalData = NULL;
+ IDataLock *pLocalDataLock = NULL;
+
+ palError = pObjectToCleanup->GetProcessLocalData(
+ pThread,
+ ReadLock,
+ &pLocalDataLock,
+ reinterpret_cast<void**>(&pLocalData)
+ );
+
+ if (NO_ERROR != palError)
+ {
+ ASSERT("Unable to obtain data to cleanup file object");
+ return;
+ }
+
+ if (pLocalData->pLockController != NULL)
+ {
+ pLocalData->pLockController->ReleaseController();
+ }
+
+ if (!fShutdown && -1 != pLocalData->unix_fd)
+ {
+ close(pLocalData->unix_fd);
+ }
+
+ pLocalDataLock->ReleaseLock(pThread, FALSE);
+}
+
+typedef enum
+{
+ PIID_STDIN_HANDLE,
+ PIID_STDOUT_HANDLE,
+ PIID_STDERR_HANDLE
+} PROCINFO_ID;
+
+#define PAL_LEGAL_FLAGS_ATTRIBS (FILE_ATTRIBUTE_NORMAL| \
+ FILE_FLAG_SEQUENTIAL_SCAN| \
+ FILE_FLAG_WRITE_THROUGH| \
+ FILE_FLAG_NO_BUFFERING| \
+ FILE_FLAG_RANDOM_ACCESS| \
+ FILE_FLAG_BACKUP_SEMANTICS)
+
+/* Static global. The init function must be called
+before any other functions and if it is not successful,
+no other functions should be done. */
+static HANDLE pStdIn = INVALID_HANDLE_VALUE;
+static HANDLE pStdOut = INVALID_HANDLE_VALUE;
+static HANDLE pStdErr = INVALID_HANDLE_VALUE;
+
+/*++
+Function :
+ FILEGetProperNotFoundError
+
+Returns the proper error code, based on the
+Windows behavior.
+
+ IN LPSTR lpPath - The path to check.
+ LPDWORD lpErrorCode - The error to set.
+*/
+void FILEGetProperNotFoundError( LPCSTR lpPath, LPDWORD lpErrorCode )
+{
+ struct stat stat_data;
+ LPSTR lpDupedPath = NULL;
+ LPSTR lpLastPathSeparator = NULL;
+
+ TRACE( "FILEGetProperNotFoundError( %s )\n", lpPath?lpPath:"(null)" );
+
+ if ( !lpErrorCode )
+ {
+ ASSERT( "lpErrorCode has to be valid\n" );
+ return;
+ }
+
+ if ( NULL == ( lpDupedPath = strdup(lpPath) ) )
+ {
+ ERROR( "strdup() failed!\n" );
+ *lpErrorCode = ERROR_NOT_ENOUGH_MEMORY;
+ return;
+ }
+
+ /* Determine whether it's a file not found or path not found. */
+ lpLastPathSeparator = strrchr( lpDupedPath, '/');
+ if ( lpLastPathSeparator != NULL )
+ {
+ *lpLastPathSeparator = '\0';
+
+ /* If the last path component is a directory,
+ we return file not found. If it's a file or
+ doesn't exist, we return path not found. */
+ if ( '\0' == *lpDupedPath ||
+ ( stat( lpDupedPath, &stat_data ) == 0 &&
+ ( stat_data.st_mode & S_IFMT ) == S_IFDIR ) )
+ {
+ TRACE( "ERROR_FILE_NOT_FOUND\n" );
+ *lpErrorCode = ERROR_FILE_NOT_FOUND;
+ }
+ else
+ {
+ TRACE( "ERROR_PATH_NOT_FOUND\n" );
+ *lpErrorCode = ERROR_PATH_NOT_FOUND;
+ }
+ }
+ else
+ {
+ TRACE( "ERROR_FILE_NOT_FOUND\n" );
+ *lpErrorCode = ERROR_FILE_NOT_FOUND;
+ }
+
+ free(lpDupedPath);
+ lpDupedPath = NULL;
+ TRACE( "FILEGetProperNotFoundError returning TRUE\n" );
+ return;
+}
+
+/*++
+Function :
+ FILEGetLastErrorFromErrnoAndFilename
+
+Returns the proper error code for errno, or, if errno is ENOENT,
+based on the Windows behavior for nonexistent filenames.
+
+ IN LPSTR lpPath - The path to check.
+*/
+PAL_ERROR FILEGetLastErrorFromErrnoAndFilename(LPCSTR lpPath)
+{
+ PAL_ERROR palError;
+ if (ENOENT == errno)
+ {
+ FILEGetProperNotFoundError(lpPath, &palError);
+ }
+ else
+ {
+ palError = FILEGetLastErrorFromErrno();
+ }
+ return palError;
+}
+
+BOOL
+CorUnix::RealPathHelper(LPCSTR lpUnixPath, PathCharString& lpBuffer)
+{
+ StringHolder lpRealPath;
+ lpRealPath = realpath(lpUnixPath, NULL);
+ if (lpRealPath.IsNull())
+ {
+ return FALSE;
+ }
+
+ lpBuffer.Set(lpRealPath, strlen(lpRealPath));
+ return TRUE;
+}
+/*++
+InternalCanonicalizeRealPath
+ Wraps realpath() to hide platform differences. See the man page for
+ realpath(3) for details of how realpath() works.
+
+ On systems on which realpath() allows the last path component to not
+ exist, this is a straight thunk through to realpath(). On other
+ systems, we remove the last path component, then call realpath().
+
+--*/
+PAL_ERROR
+CorUnix::InternalCanonicalizeRealPath(LPCSTR lpUnixPath, PathCharString& lpBuffer)
+{
+ PAL_ERROR palError = NO_ERROR;
+
+#if !REALPATH_SUPPORTS_NONEXISTENT_FILES
+ StringHolder lpExistingPath;
+ LPSTR pchSeparator = NULL;
+ LPSTR lpFilename = NULL;
+ DWORD cchBuffer = 0;
+ DWORD cchFilename = 0;
+#endif // !REALPATH_SUPPORTS_NONEXISTENT_FILES
+
+ if (lpUnixPath == NULL)
+ {
+ ERROR ("Invalid argument to InternalCanonicalizeRealPath\n");
+ palError = ERROR_INVALID_PARAMETER;
+ goto LExit;
+ }
+
+#if REALPATH_SUPPORTS_NONEXISTENT_FILES
+ RealPathHelper(lpUnixPath, lpBuffer);
+#else // !REALPATH_SUPPORTS_NONEXISTENT_FILES
+
+ lpExistingPath = strdup(lpUnixPath);
+ if (lpExistingPath.IsNull())
+ {
+ ERROR ("strdup failed with error %d\n", errno);
+ palError = ERROR_NOT_ENOUGH_MEMORY;
+ goto LExit;
+ }
+
+ pchSeparator = strrchr(lpExistingPath, '/');
+ if (pchSeparator == NULL)
+ {
+ PathCharString pszCwdBuffer;
+
+ if (GetCurrentDirectoryA(pszCwdBuffer)== 0)
+ {
+ WARN("getcwd(NULL) failed with error %d\n", errno);
+ palError = DIRGetLastErrorFromErrno();
+ goto LExit;
+ }
+
+ if (! RealPathHelper(pszCwdBuffer, lpBuffer))
+ {
+ WARN("realpath() failed with error %d\n", errno);
+ palError = FILEGetLastErrorFromErrno();
+#if defined(_AMD64_)
+ // If we are here, then we tried to invoke realpath
+ // against a directory.
+ //
+ // On Mac64, realpath implementation differs from Mac32
+ // by *not* supporting invalid filenames in the path (while
+ // Mac32 implementation does).
+ //
+ // Thus, if we are here, and the error code we see is
+ // ERROR_FILE_NOT_FOUND, then we should map it to
+ // ERROR_PATH_NOT_FOUND since it was a directory that
+ // was not found (and not a file).
+ if (palError == ERROR_FILE_NOT_FOUND)
+ {
+ // Since lpBuffer can be modified by the realpath call,
+ // and can result in a truncated subset of the original buffer,
+ // we use strstr as a level of safety.
+ if (strstr(pszCwdBuffer, lpBuffer) != 0)
+ {
+ palError = ERROR_PATH_NOT_FOUND;
+ }
+ }
+#endif // defined(_AMD64_)
+
+ goto LExit;
+ }
+ lpFilename = lpExistingPath;
+ }
+ else
+ {
+#if defined(_AMD64_)
+ bool fSetFilename = true;
+ // Since realpath implementation cannot handle inexistent filenames,
+ // check if we are going to truncate the "/" corresponding to the
+ // root folder (e.g. case of "/Volumes"). If so:
+ //
+ // 1) Set the seperator to point to the NULL terminator of the specified
+ // file/folder name.
+ //
+ // 2) Null terminate lpBuffer
+ //
+ // 3) Since there is no explicit filename component in lpExistingPath (as
+ // we only have "/" corresponding to the root), set lpFilename to NULL,
+ // alongwith a flag indicating that it has already been set.
+ if (pchSeparator == lpExistingPath)
+ {
+ pchSeparator = lpExistingPath+strlen(lpExistingPath);
+
+ // Set the lpBuffer to NULL
+ lpBuffer.Clear();
+ lpFilename = NULL;
+ fSetFilename = false;
+ }
+ else
+#endif // defined(_AMD64_)
+ *pchSeparator = '\0';
+
+ if (!RealPathHelper(lpExistingPath, lpBuffer))
+ {
+ WARN("realpath() failed with error %d\n", errno);
+ palError = FILEGetLastErrorFromErrno();
+
+#if defined(_AMD64_)
+ // If we are here, then we tried to invoke realpath
+ // against a directory after stripping out the filename
+ // from the original path.
+ //
+ // On Mac64, realpath implementation differs from Mac32
+ // by *not* supporting invalid filenames in the path (while
+ // Mac32 implementation does).
+ //
+ // Thus, if we are here, and the error code we see is
+ // ERROR_FILE_NOT_FOUND, then we should map it to
+ // ERROR_PATH_NOT_FOUND since it was a directory that
+ // was not found (and not a file).
+ if (palError == ERROR_FILE_NOT_FOUND)
+ {
+ // Since lpBuffer can be modified by the realpath call,
+ // and can result in a truncated subset of the original buffer,
+ // we use strstr as a level of safety.
+ if (strstr(lpExistingPath, lpBuffer) != 0)
+ {
+ palError = ERROR_PATH_NOT_FOUND;
+ }
+ }
+#endif // defined(_AMD64_)
+
+ goto LExit;
+ }
+
+#if defined(_AMD64_)
+ if (fSetFilename == true)
+#endif // defined(_AMD64_)
+ lpFilename = pchSeparator + 1;
+ }
+
+#if defined(_AMD64_)
+ if (lpFilename == NULL)
+ goto LExit;
+#endif // _AMD64_
+
+ if (!lpBuffer.Append("/",1) || !lpBuffer.Append(lpFilename, strlen(lpFilename)))
+ {
+ ERROR ("Append failed!\n");
+ palError = ERROR_INSUFFICIENT_BUFFER;
+
+ // Doing a goto here since we want to exit now. This will work
+ // incase someone else adds another if clause below us.
+ goto LExit;
+ }
+
+#endif // REALPATH_SUPPORTS_NONEXISTENT_FILES
+LExit:
+
+ if ((palError == NO_ERROR) && lpBuffer.IsEmpty())
+ {
+ // convert all these into ERROR_PATH_NOT_FOUND
+ palError = ERROR_PATH_NOT_FOUND;
+ }
+
+ return palError;
+}
+
+PAL_ERROR
+CorUnix::InternalCreateFile(
+ CPalThread *pThread,
+ LPCSTR lpFileName,
+ DWORD dwDesiredAccess,
+ DWORD dwShareMode,
+ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
+ DWORD dwCreationDisposition,
+ DWORD dwFlagsAndAttributes,
+ HANDLE hTemplateFile,
+ HANDLE *phFile
+ )
+{
+ PAL_ERROR palError = 0;
+ IPalObject *pFileObject = NULL;
+ IPalObject *pRegisteredFile = NULL;
+ IDataLock *pDataLock = NULL;
+ CFileProcessLocalData *pLocalData = NULL;
+ IFileLockController *pLockController = NULL;
+ CObjectAttributes oaFile(NULL, lpSecurityAttributes);
+ BOOL fFileExists = FALSE;
+
+ BOOL inheritable = FALSE;
+ PathCharString lpUnixPath;
+ int filed = -1;
+ int create_flags = (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+ int open_flags = 0;
+ int lock_mode = LOCK_SH;
+
+ // track whether we've created the file with the intended name,
+ // so that it can be removed on failure exit
+ BOOL bFileCreated = FALSE;
+
+ const char* szNonfilePrefix = "\\\\.\\";
+ PathCharString lpFullUnixPath;
+
+ /* for dwShareMode only three flags are accepted */
+ if ( dwShareMode & ~(FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE) )
+ {
+ ASSERT( "dwShareMode is invalid\n" );
+ palError = ERROR_INVALID_PARAMETER;
+ goto done;
+ }
+
+ if ( lpFileName == NULL )
+ {
+ ERROR("InternalCreateFile called with NULL filename\n");
+ palError = ERROR_PATH_NOT_FOUND;
+ goto done;
+ }
+
+ if ( strncmp(lpFileName, szNonfilePrefix, strlen(szNonfilePrefix)) == 0 )
+ {
+ ERROR("InternalCreateFile does not support paths beginning with %s\n", szNonfilePrefix);
+ palError = ERROR_INVALID_PARAMETER;
+ goto done;
+ }
+
+ if( !lpUnixPath.Set(lpFileName,strlen(lpFileName)))
+ {
+ ERROR("strdup() failed\n");
+ palError = ERROR_NOT_ENOUGH_MEMORY;
+ goto done;
+ }
+
+ FILEDosToUnixPathA( lpUnixPath );
+
+ // Compute the absolute pathname to the file. This pathname is used
+ // to determine if two file names represent the same file.
+ palError = InternalCanonicalizeRealPath(lpUnixPath, lpFullUnixPath);
+ if (palError != NO_ERROR)
+ {
+ goto done;
+ }
+
+ lpUnixPath.Set(lpFullUnixPath);
+
+ switch( dwDesiredAccess )
+ {
+ case 0:
+ /* Device Query Access was requested. let's use open() with
+ no flags, it's basically the equivalent of O_RDONLY, since
+ O_RDONLY is defined as 0x0000 */
+ break;
+ case( GENERIC_READ ):
+ open_flags |= O_RDONLY;
+ break;
+ case( GENERIC_WRITE ):
+ open_flags |= O_WRONLY;
+ break;
+ case( GENERIC_READ | GENERIC_WRITE ):
+ open_flags |= O_RDWR;
+ break;
+ default:
+ ERROR("dwDesiredAccess value of %d is invalid\n", dwDesiredAccess);
+ palError = ERROR_INVALID_PARAMETER;
+ goto done;
+ }
+
+ TRACE("open flags are 0x%lx\n", open_flags);
+
+ if ( lpSecurityAttributes )
+ {
+ if ( lpSecurityAttributes->nLength != sizeof( SECURITY_ATTRIBUTES ) ||
+ lpSecurityAttributes->lpSecurityDescriptor != NULL ||
+ !lpSecurityAttributes->bInheritHandle )
+ {
+ ASSERT("lpSecurityAttributes points to invalid values.\n");
+ palError = ERROR_INVALID_PARAMETER;
+ goto done;
+ }
+ inheritable = TRUE;
+ }
+
+ if ( (dwFlagsAndAttributes & PAL_LEGAL_FLAGS_ATTRIBS) !=
+ dwFlagsAndAttributes)
+ {
+ ASSERT("Bad dwFlagsAndAttributes\n");
+ palError = ERROR_INVALID_PARAMETER;
+ goto done;
+ }
+ else if (dwFlagsAndAttributes & FILE_FLAG_BACKUP_SEMANTICS)
+ {
+ /* Override the open flags, and always open as readonly. This
+ flag is used when opening a directory, to change its
+ creation/modification/access times. On Windows, the directory
+ must be open for write, but on Unix, it needs to be readonly. */
+ open_flags = O_RDONLY;
+ } else {
+ struct stat st;
+
+ if (stat(lpUnixPath, &st) == 0 && (st.st_mode & S_IFDIR))
+ {
+ /* The file exists and it is a directory. Without
+ FILE_FLAG_BACKUP_SEMANTICS, Win32 CreateFile always fails
+ to open directories. */
+ palError = ERROR_ACCESS_DENIED;
+ goto done;
+ }
+ }
+
+ if ( hTemplateFile )
+ {
+ ASSERT("hTemplateFile is not NULL, as it should be.\n");
+ palError = ERROR_INVALID_PARAMETER;
+ goto done;
+ }
+
+ //
+ // The file sharing mode checks are performed by the lock manager so we need
+ // to get the lock controller for this file.
+ // Do this before modifying the file system since we wouldn't want to, for
+ // instance, truncate a file before finding out if we have write access to it.
+ // It may seem odd that in some cases we will acquire a lock on a file that
+ // doesn't exist yet but the lock manager does not care -- files are
+ // abstract entities represented by a name from its point of view.
+ //
+
+ palError = g_pFileLockManager->GetLockControllerForFile(
+ pThread,
+ lpUnixPath,
+ dwDesiredAccess,
+ dwShareMode,
+ &pLockController
+ );
+
+ if (NO_ERROR != palError)
+ {
+ goto done;
+ }
+
+ /* NB: According to MSDN docs, When CREATE_ALWAYS or OPEN_ALWAYS is
+ set, CreateFile should SetLastError to ERROR_ALREADY_EXISTS,
+ even though/if CreateFile will be successful.
+ */
+ switch( dwCreationDisposition )
+ {
+ case( CREATE_ALWAYS ):
+ // check whether the file exists
+ if ( access( lpUnixPath, F_OK ) == 0 )
+ {
+ fFileExists = TRUE;
+ }
+ open_flags |= O_CREAT | O_TRUNC;
+ break;
+ case( CREATE_NEW ):
+ open_flags |= O_CREAT | O_EXCL;
+ break;
+ case( OPEN_EXISTING ):
+ /* don't need to do anything here */
+ break;
+ case( OPEN_ALWAYS ):
+ if ( access( lpUnixPath, F_OK ) == 0 )
+ {
+ fFileExists = TRUE;
+ }
+ open_flags |= O_CREAT;
+ break;
+ case( TRUNCATE_EXISTING ):
+ open_flags |= O_TRUNC;
+ break;
+ default:
+ ASSERT("dwCreationDisposition value of %d is not valid\n",
+ dwCreationDisposition);
+ palError = ERROR_INVALID_PARAMETER;
+ goto done;
+ }
+
+ if ( dwFlagsAndAttributes & FILE_FLAG_NO_BUFFERING )
+ {
+ TRACE("I/O will be unbuffered\n");
+#ifdef O_DIRECT
+ open_flags |= O_DIRECT;
+#endif
+ }
+ else
+ {
+ TRACE("I/O will be buffered\n");
+ }
+
+ filed = InternalOpen(lpUnixPath, open_flags, create_flags);
+ TRACE("Allocated file descriptor [%d]\n", filed);
+
+ if ( filed < 0 )
+ {
+ TRACE("open() failed; error is %s (%d)\n", strerror(errno), errno);
+ palError = FILEGetLastErrorFromErrnoAndFilename(lpUnixPath);
+ goto done;
+ }
+
+ // Deduce whether we created a file in the previous operation (there's a
+ // small timing window between the access() used to determine fFileExists
+ // and the open() operation, but there's not much we can do about that.
+ bFileCreated = (dwCreationDisposition == CREATE_ALWAYS ||
+ dwCreationDisposition == CREATE_NEW ||
+ dwCreationDisposition == OPEN_ALWAYS) &&
+ !fFileExists;
+
+
+ // While the lock manager is able to provide support for share modes within an instance of
+ // the PAL, other PALs will ignore these locks. In order to support a basic level of cross
+ // process locking, we'll use advisory locks. FILE_SHARE_NONE implies a exclusive lock on the
+ // file and all other modes use a shared lock. While this is not as granular as Windows,
+ // you can atleast implement a lock file using this.
+ lock_mode = (dwShareMode == 0 /* FILE_SHARE_NONE */) ? LOCK_EX : LOCK_SH;
+
+ if(flock(filed, lock_mode | LOCK_NB) != 0)
+ {
+ TRACE("flock() failed; error is %s (%d)\n", strerror(errno), errno);
+ if (errno == EWOULDBLOCK)
+ {
+ palError = ERROR_SHARING_VIOLATION;
+ }
+ else
+ {
+ palError = FILEGetLastErrorFromErrno();
+ }
+
+ goto done;
+ }
+
+#ifndef O_DIRECT
+ if ( dwFlagsAndAttributes & FILE_FLAG_NO_BUFFERING )
+ {
+#ifdef F_NOCACHE
+ if (-1 == fcntl(filed, F_NOCACHE, 1))
+ {
+ ASSERT("Can't set F_NOCACHE; fcntl() failed. errno is %d (%s)\n",
+ errno, strerror(errno));
+ palError = ERROR_INTERNAL_ERROR;
+ goto done;
+ }
+#else
+#error Insufficient support for uncached I/O on this platform
+#endif
+ }
+#endif
+
+ /* make file descriptor close-on-exec; inheritable handles will get
+ "uncloseonexeced" in CreateProcess if they are actually being inherited*/
+ if(-1 == fcntl(filed,F_SETFD,1))
+ {
+ ASSERT("can't set close-on-exec flag; fcntl() failed. errno is %d "
+ "(%s)\n", errno, strerror(errno));
+ palError = ERROR_INTERNAL_ERROR;
+ goto done;
+ }
+
+ palError = g_pObjectManager->AllocateObject(
+ pThread,
+ &otFile,
+ &oaFile,
+ &pFileObject
+ );
+
+ if (NO_ERROR != palError)
+ {
+ goto done;
+ }
+
+ palError = pFileObject->GetProcessLocalData(
+ pThread,
+ WriteLock,
+ &pDataLock,
+ reinterpret_cast<void**>(&pLocalData)
+ );
+
+ if (NO_ERROR != palError)
+ {
+ goto done;
+ }
+
+ if (strcpy_s(pLocalData->unix_filename, sizeof(pLocalData->unix_filename), lpUnixPath) != SAFECRT_SUCCESS)
+ {
+ palError = ERROR_INSUFFICIENT_BUFFER;
+ TRACE("strcpy_s failed!\n");
+ goto done;
+ }
+
+ pLocalData->inheritable = inheritable;
+ pLocalData->unix_fd = filed;
+ pLocalData->dwDesiredAccess = dwDesiredAccess;
+ pLocalData->open_flags = open_flags;
+ pLocalData->open_flags_deviceaccessonly = (dwDesiredAccess == 0);
+
+ //
+ // Transfer the lock controller reference from our local variable
+ // to the local file data
+ //
+
+ pLocalData->pLockController = pLockController;
+ pLockController = NULL;
+
+ //
+ // We've finished initializing our local data, so release that lock
+ //
+
+ pDataLock->ReleaseLock(pThread, TRUE);
+ pDataLock = NULL;
+
+ palError = g_pObjectManager->RegisterObject(
+ pThread,
+ pFileObject,
+ &aotFile,
+ dwDesiredAccess,
+ phFile,
+ &pRegisteredFile
+ );
+
+ //
+ // pFileObject is invalidated by the call to RegisterObject, so NULL it
+ // out here to ensure that we don't try to release a reference on
+ // it down the line.
+ //
+
+ pFileObject = NULL;
+
+done:
+
+ // At this point, if we've been successful, palError will be NO_ERROR.
+ // CreateFile can return ERROR_ALREADY_EXISTS in some success cases;
+ // those cases are flagged by fFileExists and are handled below.
+ if (NO_ERROR != palError)
+ {
+ if (filed >= 0)
+ {
+ close(filed);
+ }
+ if (bFileCreated)
+ {
+ if (-1 == unlink(lpUnixPath))
+ {
+ WARN("can't delete file; unlink() failed with errno %d (%s)\n",
+ errno, strerror(errno));
+ }
+ }
+ }
+
+ if (NULL != pLockController)
+ {
+ pLockController->ReleaseController();
+ }
+
+ if (NULL != pDataLock)
+ {
+ pDataLock->ReleaseLock(pThread, TRUE);
+ }
+
+ if (NULL != pFileObject)
+ {
+ pFileObject->ReleaseReference(pThread);
+ }
+
+ if (NULL != pRegisteredFile)
+ {
+ pRegisteredFile->ReleaseReference(pThread);
+ }
+
+ if (NO_ERROR == palError && fFileExists)
+ {
+ palError = ERROR_ALREADY_EXISTS;
+ }
+
+ return palError;
+}
+
+/*++
+Function:
+ CreateFileA
+
+Note:
+ Only bInherit flag is used from the LPSECURITY_ATTRIBUTES struct.
+ Desired access is READ, WRITE or 0
+ Share mode is READ, WRITE or DELETE
+
+See MSDN doc.
+--*/
+HANDLE
+PALAPI
+CreateFileA(
+ IN LPCSTR lpFileName,
+ IN DWORD dwDesiredAccess,
+ IN DWORD dwShareMode,
+ IN LPSECURITY_ATTRIBUTES lpSecurityAttributes,
+ IN DWORD dwCreationDisposition,
+ IN DWORD dwFlagsAndAttributes,
+ IN HANDLE hTemplateFile
+ )
+{
+ CPalThread *pThread;
+ PAL_ERROR palError = NO_ERROR;
+ HANDLE hRet = INVALID_HANDLE_VALUE;
+
+ PERF_ENTRY(CreateFileA);
+ ENTRY("CreateFileA(lpFileName=%p (%s), dwAccess=%#x, dwShareMode=%#x, "
+ "lpSecurityAttr=%p, dwDisposition=%#x, dwFlags=%#x, "
+ "hTemplateFile=%p )\n",lpFileName?lpFileName:"NULL",lpFileName?lpFileName:"NULL", dwDesiredAccess,
+ dwShareMode, lpSecurityAttributes, dwCreationDisposition,
+ dwFlagsAndAttributes, hTemplateFile);
+
+ pThread = InternalGetCurrentThread();
+
+ palError = InternalCreateFile(
+ pThread,
+ lpFileName,
+ dwDesiredAccess,
+ dwShareMode,
+ lpSecurityAttributes,
+ dwCreationDisposition,
+ dwFlagsAndAttributes,
+ hTemplateFile,
+ &hRet
+ );
+
+ //
+ // We always need to set last error, even on success:
+ // we need to protect ourselves from the situation
+ // where last error is set to ERROR_ALREADY_EXISTS on
+ // entry to the function
+ //
+
+ pThread->SetLastError(palError);
+
+ LOGEXIT("CreateFileA returns HANDLE %p\n", hRet);
+ PERF_EXIT(CreateFileA);
+ return hRet;
+}
+
+
+/*++
+Function:
+ CreateFileW
+
+Note:
+ Only bInherit flag is used from the LPSECURITY_ATTRIBUTES struct.
+ Desired access is READ, WRITE or 0
+ Share mode is READ, WRITE or DELETE
+
+See MSDN doc.
+--*/
+HANDLE
+PALAPI
+CreateFileW(
+ IN LPCWSTR lpFileName,
+ IN DWORD dwDesiredAccess,
+ IN DWORD dwShareMode,
+ IN LPSECURITY_ATTRIBUTES lpSecurityAttributes,
+ IN DWORD dwCreationDisposition,
+ IN DWORD dwFlagsAndAttributes,
+ IN HANDLE hTemplateFile)
+{
+ CPalThread *pThread;
+ PAL_ERROR palError = NO_ERROR;
+ PathCharString namePathString;
+ char * name;
+ int size;
+ int length = 0;
+ HANDLE hRet = INVALID_HANDLE_VALUE;
+
+ PERF_ENTRY(CreateFileW);
+ ENTRY("CreateFileW(lpFileName=%p (%S), dwAccess=%#x, dwShareMode=%#x, "
+ "lpSecurityAttr=%p, dwDisposition=%#x, dwFlags=%#x, hTemplateFile=%p )\n",
+ lpFileName?lpFileName:W16_NULLSTRING,
+ lpFileName?lpFileName:W16_NULLSTRING, dwDesiredAccess, dwShareMode,
+ lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes,
+ hTemplateFile);
+
+ pThread = InternalGetCurrentThread();
+
+ if (lpFileName != NULL)
+ {
+ length = (PAL_wcslen(lpFileName)+1) * MaxWCharToAcpLengthFactor;
+ }
+
+ name = namePathString.OpenStringBuffer(length);
+ if (NULL == name)
+ {
+ palError = ERROR_NOT_ENOUGH_MEMORY;
+ goto done;
+ }
+
+ size = WideCharToMultiByte( CP_ACP, 0, lpFileName, -1, name, length,
+ NULL, NULL );
+
+ if( size == 0 )
+ {
+ namePathString.CloseBuffer(0);
+ DWORD dwLastError = GetLastError();
+ ASSERT("WideCharToMultiByte failure! error is %d\n", dwLastError);
+ palError = ERROR_INTERNAL_ERROR;
+ goto done;
+ }
+
+ namePathString.CloseBuffer(size - 1);
+
+ palError = InternalCreateFile(
+ pThread,
+ name,
+ dwDesiredAccess,
+ dwShareMode,
+ lpSecurityAttributes,
+ dwCreationDisposition,
+ dwFlagsAndAttributes,
+ hTemplateFile,
+ &hRet
+ );
+
+ //
+ // We always need to set last error, even on success:
+ // we need to protect ourselves from the situation
+ // where last error is set to ERROR_ALREADY_EXISTS on
+ // entry to the function
+ //
+
+done:
+ pThread->SetLastError(palError);
+ LOGEXIT( "CreateFileW returns HANDLE %p\n", hRet );
+ PERF_EXIT(CreateFileW);
+ return hRet;
+}
+
+
+/*++
+Function:
+ CopyFileW
+
+See MSDN doc.
+
+Notes:
+ There are several (most) error paths here that do not call SetLastError().
+This is because we know that CreateFile, ReadFile, and WriteFile will do so,
+and will have a much better idea of the specific error.
+--*/
+BOOL
+PALAPI
+CopyFileW(
+ IN LPCWSTR lpExistingFileName,
+ IN LPCWSTR lpNewFileName,
+ IN BOOL bFailIfExists)
+{
+ CPalThread *pThread;
+ PathCharString sourcePathString;
+ PathCharString destPathString;
+ char * source;
+ char * dest;
+ int src_size, dest_size, length = 0;
+ BOOL bRet = FALSE;
+
+ PERF_ENTRY(CopyFileW);
+ ENTRY("CopyFileW(lpExistingFileName=%p (%S), lpNewFileName=%p (%S), bFailIfExists=%d)\n",
+ lpExistingFileName?lpExistingFileName:W16_NULLSTRING,
+ lpExistingFileName?lpExistingFileName:W16_NULLSTRING,
+ lpNewFileName?lpNewFileName:W16_NULLSTRING,
+ lpNewFileName?lpNewFileName:W16_NULLSTRING, bFailIfExists);
+
+ pThread = InternalGetCurrentThread();
+ if (lpExistingFileName != NULL)
+ {
+ length = (PAL_wcslen(lpExistingFileName)+1) * MaxWCharToAcpLengthFactor;
+ }
+
+ source = sourcePathString.OpenStringBuffer(length);
+ if (NULL == source)
+ {
+ pThread->SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ goto done;
+ }
+
+ src_size = WideCharToMultiByte( CP_ACP, 0, lpExistingFileName, -1, source, length,
+ NULL, NULL );
+
+ if( src_size == 0 )
+ {
+ sourcePathString.CloseBuffer(0);
+ DWORD dwLastError = GetLastError();
+ ASSERT("WideCharToMultiByte failure! error is %d\n", dwLastError);
+ pThread->SetLastError(ERROR_INTERNAL_ERROR);
+ goto done;
+ }
+
+ sourcePathString.CloseBuffer(src_size - 1);
+ length = 0;
+
+ if (lpNewFileName != NULL)
+ {
+ length = (PAL_wcslen(lpNewFileName)+1) * MaxWCharToAcpLengthFactor;
+ }
+
+ dest = destPathString.OpenStringBuffer(length);
+ if (NULL == dest)
+ {
+ pThread->SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ goto done;
+ }
+ dest_size = WideCharToMultiByte( CP_ACP, 0, lpNewFileName, -1, dest, length,
+ NULL, NULL );
+
+ if( dest_size == 0 )
+ {
+ destPathString.CloseBuffer(0);
+ DWORD dwLastError = GetLastError();
+ ASSERT("WideCharToMultiByte failure! error is %d\n", dwLastError);
+ pThread->SetLastError(ERROR_INTERNAL_ERROR);
+ goto done;
+ }
+
+ destPathString.CloseBuffer(dest_size - 1);
+ bRet = CopyFileA(source,dest,bFailIfExists);
+
+done:
+ LOGEXIT("CopyFileW returns BOOL %d\n", bRet);
+ PERF_EXIT(CopyFileW);
+ return bRet;
+}
+
+
+/*++
+Function:
+ DeleteFileA
+
+See MSDN doc.
+--*/
+BOOL
+PALAPI
+DeleteFileA(
+ IN LPCSTR lpFileName)
+{
+ PAL_ERROR palError = NO_ERROR;
+ CPalThread *pThread;
+ int result;
+ BOOL bRet = FALSE;
+ DWORD dwLastError = 0;
+ PathCharString lpunixFileName;
+ PathCharString lpFullunixFileName;
+
+ PERF_ENTRY(DeleteFileA);
+ ENTRY("DeleteFileA(lpFileName=%p (%s))\n", lpFileName?lpFileName:"NULL", lpFileName?lpFileName:"NULL");
+
+ pThread = InternalGetCurrentThread();
+
+ if( !lpunixFileName.Set(lpFileName, strlen(lpFileName)))
+ {
+ palError = ERROR_NOT_ENOUGH_MEMORY;
+ goto done;
+ }
+
+ FILEDosToUnixPathA( lpunixFileName );
+
+ // Compute the absolute pathname to the file. This pathname is used
+ // to determine if two file names represent the same file.
+ palError = InternalCanonicalizeRealPath(lpunixFileName, lpFullunixFileName);
+ if (palError != NO_ERROR)
+ {
+ if (!lpFullunixFileName.Set(lpunixFileName, strlen(lpunixFileName)))
+ {
+ palError = ERROR_NOT_ENOUGH_MEMORY;
+ goto done;
+ }
+ }
+
+ result = unlink( lpFullunixFileName );
+
+ if (result < 0)
+ {
+ TRACE("unlink returns %d\n", result);
+ dwLastError = FILEGetLastErrorFromErrnoAndFilename(lpFullunixFileName);
+ }
+ else
+ {
+ bRet = TRUE;
+ }
+
+done:
+ if(dwLastError)
+ {
+ pThread->SetLastError( dwLastError );
+ }
+
+ LOGEXIT("DeleteFileA returns BOOL %d\n", bRet);
+ PERF_EXIT(DeleteFileA);
+ return bRet;
+}
+
+/*++
+Function:
+ DeleteFileW
+
+See MSDN doc.
+--*/
+BOOL
+PALAPI
+DeleteFileW(
+ IN LPCWSTR lpFileName)
+{
+ CPalThread *pThread;
+ int size;
+ PathCharString namePS;
+ char * name;
+ int length = 0;
+ BOOL bRet = FALSE;
+
+ PERF_ENTRY(DeleteFileW);
+ ENTRY("DeleteFileW(lpFileName=%p (%S))\n",
+ lpFileName?lpFileName:W16_NULLSTRING,
+ lpFileName?lpFileName:W16_NULLSTRING);
+
+ pThread = InternalGetCurrentThread();
+
+ if (lpFileName != NULL)
+ {
+ length = (PAL_wcslen(lpFileName)+1) * MaxWCharToAcpLengthFactor;
+ }
+
+ name = namePS.OpenStringBuffer(length);
+ if (NULL == name)
+ {
+ pThread->SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ goto done;
+ }
+
+ size = WideCharToMultiByte( CP_ACP, 0, lpFileName, -1, name, length,
+ NULL, NULL );
+
+ if( size == 0 )
+ {
+ namePS.CloseBuffer(0);
+ DWORD dwLastError = GetLastError();
+ ASSERT("WideCharToMultiByte failure! error is %d\n", dwLastError);
+ pThread->SetLastError(ERROR_INTERNAL_ERROR);
+ bRet = FALSE;
+ goto done;
+ }
+
+ namePS.CloseBuffer(size - 1);
+ bRet = DeleteFileA( name );
+
+done:
+ LOGEXIT("DeleteFileW returns BOOL %d\n", bRet);
+ PERF_EXIT(DeleteFileW);
+ return bRet;
+}
+
+
+/*++
+Function:
+ MoveFileA
+
+See MSDN doc.
+--*/
+BOOL
+PALAPI
+MoveFileA(
+ IN LPCSTR lpExistingFileName,
+ IN LPCSTR lpNewFileName)
+{
+ BOOL bRet;
+
+ PERF_ENTRY(MoveFileA);
+ ENTRY("MoveFileA(lpExistingFileName=%p (%s), lpNewFileName=%p (%s))\n",
+ lpExistingFileName?lpExistingFileName:"NULL",
+ lpExistingFileName?lpExistingFileName:"NULL",
+ lpNewFileName?lpNewFileName:"NULL",
+ lpNewFileName?lpNewFileName:"NULL");
+
+ bRet = MoveFileExA( lpExistingFileName,
+ lpNewFileName,
+ MOVEFILE_COPY_ALLOWED );
+
+ LOGEXIT("MoveFileA returns BOOL %d\n", bRet);
+ PERF_EXIT(MoveFileA);
+ return bRet;
+}
+
+
+/*++
+Function:
+ MoveFileW
+
+See MSDN doc.
+--*/
+BOOL
+PALAPI
+MoveFileW(
+ IN LPCWSTR lpExistingFileName,
+ IN LPCWSTR lpNewFileName)
+{
+ BOOL bRet;
+
+ PERF_ENTRY(MoveFileW);
+ ENTRY("MoveFileW(lpExistingFileName=%p (%S), lpNewFileName=%p (%S))\n",
+ lpExistingFileName?lpExistingFileName:W16_NULLSTRING,
+ lpExistingFileName?lpExistingFileName:W16_NULLSTRING,
+ lpNewFileName?lpNewFileName:W16_NULLSTRING,
+ lpNewFileName?lpNewFileName:W16_NULLSTRING);
+
+ bRet = MoveFileExW( lpExistingFileName,
+ lpNewFileName,
+ MOVEFILE_COPY_ALLOWED );
+
+ LOGEXIT("MoveFileW returns BOOL %d\n", bRet);
+ PERF_EXIT(MoveFileW);
+ return bRet;
+}
+
+/*++
+Function:
+ MoveFileExA
+
+See MSDN doc.
+--*/
+BOOL
+PALAPI
+MoveFileExA(
+ IN LPCSTR lpExistingFileName,
+ IN LPCSTR lpNewFileName,
+ IN DWORD dwFlags)
+{
+ CPalThread *pThread;
+ int result;
+ PathCharString source;
+ PathCharString dest;
+ BOOL bRet = TRUE;
+ DWORD dwLastError = 0;
+
+ PERF_ENTRY(MoveFileExA);
+ ENTRY("MoveFileExA(lpExistingFileName=%p (%S), lpNewFileName=%p (%S), "
+ "dwFlags=%#x)\n",
+ lpExistingFileName?lpExistingFileName:"NULL",
+ lpExistingFileName?lpExistingFileName:"NULL",
+ lpNewFileName?lpNewFileName:"NULL",
+ lpNewFileName?lpNewFileName:"NULL", dwFlags);
+
+ pThread = InternalGetCurrentThread();
+ /* only two flags are accepted */
+ if ( dwFlags & ~(MOVEFILE_COPY_ALLOWED | MOVEFILE_REPLACE_EXISTING) )
+ {
+ ASSERT( "dwFlags is invalid\n" );
+ dwLastError = ERROR_INVALID_PARAMETER;
+ goto done;
+ }
+
+
+ if( !source.Set(lpExistingFileName, strlen(lpExistingFileName)))
+ {
+ dwLastError = ERROR_NOT_ENOUGH_MEMORY;
+ goto done;
+ }
+
+ FILEDosToUnixPathA( source );
+
+ if( !dest.Set(lpNewFileName, strlen(lpNewFileName)))
+ {
+ dwLastError = ERROR_NOT_ENOUGH_MEMORY;
+ goto done;
+ }
+
+ FILEDosToUnixPathA( dest );
+
+ if ( !(dwFlags & MOVEFILE_REPLACE_EXISTING) )
+ {
+#if HAVE_CASE_SENSITIVE_FILESYSTEM
+ if ( strcmp(source, dest) != 0 )
+#else // HAVE_CASE_SENSITIVE_FILESYSTEM
+ if ( strcasecmp(source, dest) != 0 )
+#endif // HAVE_CASE_SENSITIVE_FILESYSTEM
+ {
+ // Let things proceed normally if source and
+ // dest are the same.
+ if ( access(dest, F_OK) == 0 )
+ {
+ dwLastError = ERROR_ALREADY_EXISTS;
+ goto done;
+ }
+ }
+ }
+
+ result = rename( source, dest );
+ if ((result < 0) && (dwFlags & MOVEFILE_REPLACE_EXISTING) &&
+ ((errno == ENOTDIR) || (errno == EEXIST)))
+ {
+ bRet = DeleteFileA( lpNewFileName );
+
+ if ( bRet )
+ {
+ result = rename( source, dest );
+ }
+ else
+ {
+ dwLastError = GetLastError();
+ }
+ }
+
+ if ( result < 0 )
+ {
+ switch( errno )
+ {
+ case EXDEV: /* we tried to link across devices */
+
+ if ( dwFlags & MOVEFILE_COPY_ALLOWED )
+ {
+ BOOL bFailIfExists = !(dwFlags & MOVEFILE_REPLACE_EXISTING);
+
+ /* if CopyFile fails here, so should MoveFailEx */
+ bRet = CopyFileA( lpExistingFileName,
+ lpNewFileName,
+ bFailIfExists );
+ /* CopyFile should set the appropriate error */
+ if ( !bRet )
+ {
+ dwLastError = GetLastError();
+ }
+ else
+ {
+ if (!DeleteFileA(lpExistingFileName))
+ {
+ ERROR("Failed to delete the source file\n");
+ dwLastError = GetLastError();
+
+ /* Delete the destination file if we're unable to delete
+ the source file */
+ if (!DeleteFileA(lpNewFileName))
+ {
+ ERROR("Failed to delete the destination file\n");
+ }
+ }
+ }
+ }
+ else
+ {
+ dwLastError = ERROR_ACCESS_DENIED;
+ }
+ break;
+ case EINVAL: // tried to rename "." or ".."
+ dwLastError = ERROR_SHARING_VIOLATION;
+ break;
+ case ENOENT:
+ {
+ struct stat buf;
+ if (lstat(source, &buf) == -1)
+ {
+ FILEGetProperNotFoundError(source, &dwLastError);
+ }
+ else
+ {
+ dwLastError = ERROR_PATH_NOT_FOUND;
+ }
+ }
+ break;
+ default:
+ dwLastError = FILEGetLastErrorFromErrno();
+ break;
+ }
+ }
+
+done:
+ if ( dwLastError )
+ {
+ pThread->SetLastError( dwLastError );
+ bRet = FALSE;
+ }
+
+ LOGEXIT( "MoveFileExA returns BOOL %d\n", bRet );
+ PERF_EXIT(MoveFileExA);
+ return bRet;
+}
+
+/*++
+Function:
+ MoveFileExW
+
+See MSDN doc.
+--*/
+BOOL
+PALAPI
+MoveFileExW(
+ IN LPCWSTR lpExistingFileName,
+ IN LPCWSTR lpNewFileName,
+ IN DWORD dwFlags)
+{
+ CPalThread *pThread;
+ PathCharString sourcePS;
+ PathCharString destPS;
+ char * source;
+ char * dest;
+ int length = 0;
+ int src_size,dest_size;
+ BOOL bRet = FALSE;
+
+ PERF_ENTRY(MoveFileExW);
+ ENTRY("MoveFileExW(lpExistingFileName=%p (%S), lpNewFileName=%p (%S), dwFlags=%#x)\n",
+ lpExistingFileName?lpExistingFileName:W16_NULLSTRING,
+ lpExistingFileName?lpExistingFileName:W16_NULLSTRING,
+ lpNewFileName?lpNewFileName:W16_NULLSTRING,
+ lpNewFileName?lpNewFileName:W16_NULLSTRING, dwFlags);
+
+ pThread = InternalGetCurrentThread();
+
+ if (lpExistingFileName != NULL)
+ {
+ length = (PAL_wcslen(lpExistingFileName)+1) * MaxWCharToAcpLengthFactor;
+ }
+
+ source = sourcePS.OpenStringBuffer(length);
+ if (NULL == source)
+ {
+ pThread->SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ goto done;
+ }
+ src_size = WideCharToMultiByte( CP_ACP, 0, lpExistingFileName, -1, source, length,
+ NULL, NULL );
+ if( src_size == 0 )
+ {
+ sourcePS.CloseBuffer(0);
+ DWORD dwLastError = GetLastError();
+ ASSERT("WideCharToMultiByte failure! error is %d\n", dwLastError);
+ pThread->SetLastError(ERROR_INTERNAL_ERROR);
+ goto done;
+ }
+
+ sourcePS.CloseBuffer(src_size - 1);
+ length = 0;
+ if (lpNewFileName != NULL)
+ {
+ length = (PAL_wcslen(lpNewFileName)+1) * MaxWCharToAcpLengthFactor;
+ }
+
+ dest = destPS.OpenStringBuffer(length);
+ if (NULL == dest)
+ {
+ pThread->SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ goto done;
+ }
+ dest_size = WideCharToMultiByte( CP_ACP, 0, lpNewFileName, -1, dest, length,
+ NULL, NULL );
+
+ if( dest_size == 0 )
+ {
+ destPS.CloseBuffer(0);
+ DWORD dwLastError = GetLastError();
+ ASSERT("WideCharToMultiByte failure! error is %d\n", dwLastError);
+ pThread->SetLastError(ERROR_INTERNAL_ERROR);
+ goto done;
+ }
+
+ destPS.CloseBuffer(dest_size - 1);
+ bRet = MoveFileExA(source,dest,dwFlags);
+
+done:
+ LOGEXIT("MoveFileExW returns BOOL %d\n", bRet);
+ PERF_EXIT(MoveFileExW);
+ return bRet;
+}
+
+/*++
+Function:
+ GetFileAttributesA
+
+Note:
+ Checking for directory and read-only file, according to Rotor spec.
+
+Caveats:
+ There are some important things to note about this implementation, which
+are due to the differences between the FAT filesystem and Unix filesystems:
+
+- fifo's, sockets, and symlinks will return -1, and GetLastError() will
+ return ERROR_ACCESS_DENIED
+
+- if a file is write-only, or has no permissions at all, it is treated
+ the same as if it had mode 'rw'. This is consistent with behaviour on
+ NTFS files with the same permissions.
+
+- the following flags will never be returned:
+
+FILE_ATTRIBUTE_SYSTEM
+FILE_ATTRIBUTE_ARCHIVE
+FILE_ATTRIBUTE_HIDDEN
+
+--*/
+DWORD
+PALAPI
+GetFileAttributesA(
+ IN LPCSTR lpFileName)
+{
+ CPalThread *pThread;
+ struct stat stat_data;
+ DWORD dwAttr = 0;
+ DWORD dwLastError = 0;
+ PathCharString unixFileName;
+
+ PERF_ENTRY(GetFileAttributesA);
+ ENTRY("GetFileAttributesA(lpFileName=%p (%s))\n", lpFileName?lpFileName:"NULL", lpFileName?lpFileName:"NULL");
+
+ pThread = InternalGetCurrentThread();
+ if (lpFileName == NULL)
+ {
+ dwLastError = ERROR_PATH_NOT_FOUND;
+ goto done;
+ }
+
+
+ if( !unixFileName.Set(lpFileName, strlen(lpFileName)))
+ {
+ dwLastError = ERROR_NOT_ENOUGH_MEMORY;
+ goto done;
+ }
+
+ FILEDosToUnixPathA( unixFileName );
+
+ if ( stat(unixFileName, &stat_data) != 0 )
+ {
+ dwLastError = FILEGetLastErrorFromErrnoAndFilename(unixFileName);
+ goto done;
+ }
+
+ if ( (stat_data.st_mode & S_IFMT) == S_IFDIR )
+ {
+ dwAttr |= FILE_ATTRIBUTE_DIRECTORY;
+ }
+ else if ( (stat_data.st_mode & S_IFMT) != S_IFREG )
+ {
+ ERROR("Not a regular file or directory, S_IFMT is %#x\n",
+ stat_data.st_mode & S_IFMT);
+ dwLastError = ERROR_ACCESS_DENIED;
+ goto done;
+ }
+
+ if ( UTIL_IsReadOnlyBitsSet( &stat_data ) )
+ {
+ dwAttr |= FILE_ATTRIBUTE_READONLY;
+ }
+
+ /* finally, if nothing is set... */
+ if ( dwAttr == 0 )
+ {
+ dwAttr = FILE_ATTRIBUTE_NORMAL;
+ }
+
+done:
+ if (dwLastError)
+ {
+ pThread->SetLastError(dwLastError);
+ dwAttr = INVALID_FILE_ATTRIBUTES;
+ }
+
+ LOGEXIT("GetFileAttributesA returns DWORD %#x\n", dwAttr);
+ PERF_EXIT(GetFileAttributesA);
+ return dwAttr;
+}
+
+
+
+
+/*++
+Function:
+ GetFileAttributesW
+
+Note:
+ Checking for directory and read-only file
+
+See MSDN doc.
+--*/
+DWORD
+PALAPI
+GetFileAttributesW(
+ IN LPCWSTR lpFileName)
+{
+ CPalThread *pThread;
+ int size;
+ PathCharString filenamePS;
+ int length = 0;
+ char * filename;
+ DWORD dwRet = (DWORD) -1;
+
+ PERF_ENTRY(GetFileAttributesW);
+ ENTRY("GetFileAttributesW(lpFileName=%p (%S))\n",
+ lpFileName?lpFileName:W16_NULLSTRING,
+ lpFileName?lpFileName:W16_NULLSTRING);
+
+ pThread = InternalGetCurrentThread();
+ if (lpFileName == NULL)
+ {
+ pThread->SetLastError(ERROR_PATH_NOT_FOUND);
+ goto done;
+ }
+
+ length = (PAL_wcslen(lpFileName)+1) * MaxWCharToAcpLengthFactor;
+ filename = filenamePS.OpenStringBuffer(length);
+ if (NULL == filename)
+ {
+ pThread->SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ goto done;
+ }
+ size = WideCharToMultiByte( CP_ACP, 0, lpFileName, -1, filename, length,
+ NULL, NULL );
+
+ if( size == 0 )
+ {
+ filenamePS.CloseBuffer(0);
+ DWORD dwLastError = GetLastError();
+ ASSERT("WideCharToMultiByte failure! error is %d\n", dwLastError);
+ pThread->SetLastError(ERROR_INTERNAL_ERROR);
+ }
+ else
+ {
+ filenamePS.CloseBuffer(size - 1);
+ dwRet = GetFileAttributesA( filename );
+ }
+
+done:
+ LOGEXIT("GetFileAttributesW returns DWORD %#x\n", dwRet);
+ PERF_EXIT(GetFileAttributesW);
+ return dwRet;
+}
+
+
+/*++
+Function:
+ GetFileAttributesExW
+
+See MSDN doc, and notes for GetFileAttributesW.
+--*/
+BOOL
+PALAPI
+GetFileAttributesExW(
+ IN LPCWSTR lpFileName,
+ IN GET_FILEEX_INFO_LEVELS fInfoLevelId,
+ OUT LPVOID lpFileInformation)
+{
+ CPalThread *pThread;
+ BOOL bRet = FALSE;
+ DWORD dwLastError = 0;
+ LPWIN32_FILE_ATTRIBUTE_DATA attr_data;
+
+ struct stat stat_data;
+
+ char * name;
+ PathCharString namePS;
+ int length = 0;
+ int size;
+
+ PERF_ENTRY(GetFileAttributesExW);
+ ENTRY("GetFileAttributesExW(lpFileName=%p (%S), fInfoLevelId=%d, "
+ "lpFileInformation=%p)\n", lpFileName?lpFileName:W16_NULLSTRING, lpFileName?lpFileName:W16_NULLSTRING,
+ fInfoLevelId, lpFileInformation);
+
+ pThread = InternalGetCurrentThread();
+ if ( fInfoLevelId != GetFileExInfoStandard )
+ {
+ ASSERT("Unrecognized value for fInfoLevelId=%d\n", fInfoLevelId);
+ dwLastError = ERROR_INVALID_PARAMETER;
+ goto done;
+ }
+
+ if ( !lpFileInformation )
+ {
+ ASSERT("lpFileInformation is NULL\n");
+ dwLastError = ERROR_INVALID_PARAMETER;
+ goto done;
+ }
+
+ if (lpFileName == NULL)
+ {
+ dwLastError = ERROR_PATH_NOT_FOUND;
+ goto done;
+ }
+
+ length = (PAL_wcslen(lpFileName)+1) * MaxWCharToAcpLengthFactor;
+ name = namePS.OpenStringBuffer(length);
+ if (NULL == name)
+ {
+ dwLastError = ERROR_NOT_ENOUGH_MEMORY;
+ goto done;
+ }
+ size = WideCharToMultiByte( CP_ACP, 0, lpFileName, -1, name, length,
+ NULL, NULL );
+
+ if( size == 0 )
+ {
+ namePS.CloseBuffer(0);
+ dwLastError = GetLastError();
+ ASSERT("WideCharToMultiByte failure! error is %d\n", dwLastError);
+ dwLastError = ERROR_INTERNAL_ERROR;
+ goto done;
+ }
+
+ namePS.CloseBuffer(size - 1);
+ attr_data = (LPWIN32_FILE_ATTRIBUTE_DATA)lpFileInformation;
+
+ attr_data->dwFileAttributes = GetFileAttributesW(lpFileName);
+ /* assume that GetFileAttributes will call SetLastError appropriately */
+ if ( attr_data->dwFileAttributes == (DWORD)-1 )
+ {
+ goto done;
+ }
+
+ FILEDosToUnixPathA(name);
+ /* do the stat */
+ if ( stat(name, &stat_data) != 0 )
+ {
+ ERROR("stat failed on %S\n", lpFileName);
+ dwLastError = FILEGetLastErrorFromErrnoAndFilename(name);
+ goto done;
+ }
+
+ /* get the file times */
+ attr_data->ftCreationTime =
+ FILEUnixTimeToFileTime( stat_data.st_ctime,
+ ST_CTIME_NSEC(&stat_data) );
+ attr_data->ftLastAccessTime =
+ FILEUnixTimeToFileTime( stat_data.st_atime,
+ ST_ATIME_NSEC(&stat_data) );
+ attr_data->ftLastWriteTime =
+ FILEUnixTimeToFileTime( stat_data.st_mtime,
+ ST_MTIME_NSEC(&stat_data) );
+
+ /* Get the file size. GetFileSize is not used because it gets the
+ size of an already-open file */
+ attr_data->nFileSizeLow = (DWORD) stat_data.st_size;
+#if SIZEOF_OFF_T > 4
+ attr_data->nFileSizeHigh = (DWORD)(stat_data.st_size >> 32);
+#else
+ attr_data->nFileSizeHigh = 0;
+#endif
+
+ bRet = TRUE;
+
+done:
+ if (dwLastError) pThread->SetLastError(dwLastError);
+
+ LOGEXIT("GetFileAttributesExW returns BOOL %d\n", bRet);
+ PERF_EXIT(GetFileAttributesExW);
+ return bRet;
+}
+
+/*++
+Function:
+ SetFileAttributesW
+
+Notes:
+ Used for setting read-only attribute on file only.
+
+--*/
+BOOL
+PALAPI
+SetFileAttributesW(
+ IN LPCWSTR lpFileName,
+ IN DWORD dwFileAttributes)
+{
+ CPalThread *pThread;
+ char * name;
+ PathCharString namePS;
+ int length = 0;
+ int size;
+
+ DWORD dwLastError = 0;
+ BOOL bRet = FALSE;
+
+ PERF_ENTRY(SetFileAttributesW);
+ ENTRY("SetFileAttributesW(lpFileName=%p (%S), dwFileAttributes=%#x)\n",
+ lpFileName?lpFileName:W16_NULLSTRING,
+ lpFileName?lpFileName:W16_NULLSTRING, dwFileAttributes);
+
+ pThread = InternalGetCurrentThread();
+ if (lpFileName == NULL)
+ {
+ dwLastError = ERROR_PATH_NOT_FOUND;
+ goto done;
+ }
+
+ length = (PAL_wcslen(lpFileName)+1) * MaxWCharToAcpLengthFactor;
+ name = namePS.OpenStringBuffer(length);
+ if (NULL == name)
+ {
+ dwLastError = ERROR_NOT_ENOUGH_MEMORY;
+ goto done;
+ }
+ size = WideCharToMultiByte( CP_ACP, 0, lpFileName, -1, name, length,
+ NULL, NULL );
+
+ if( size == 0 )
+ {
+ namePS.CloseBuffer(0);
+ dwLastError = GetLastError();
+ ASSERT("WideCharToMultiByte failure! error is %d\n", dwLastError);
+ dwLastError = ERROR_INVALID_PARAMETER;
+ goto done;
+ }
+ namePS.CloseBuffer(size - 1);
+ bRet = SetFileAttributesA(name,dwFileAttributes);
+
+done:
+ if (dwLastError) pThread->SetLastError(dwLastError);
+
+ LOGEXIT("SetFileAttributes returns BOOL %d\n", bRet);
+ PERF_EXIT(SetFileAttributesW);
+ return bRet;
+}
+
+PAL_ERROR
+CorUnix::InternalWriteFile(
+ CPalThread *pThread,
+ HANDLE hFile,
+ LPCVOID lpBuffer,
+ DWORD nNumberOfBytesToWrite,
+ LPDWORD lpNumberOfBytesWritten,
+ LPOVERLAPPED lpOverlapped
+ )
+{
+ PAL_ERROR palError = 0;
+ IPalObject *pFileObject = NULL;
+ CFileProcessLocalData *pLocalData = NULL;
+ IDataLock *pLocalDataLock = NULL;
+ IFileTransactionLock *pTransactionLock = NULL;
+ int ifd;
+
+ LONG writeOffsetStartLow = 0, writeOffsetStartHigh = 0;
+ int res;
+
+ if (NULL != lpNumberOfBytesWritten)
+ {
+ //
+ // This must be set to 0 before any other error checking takes
+ // place, per MSDN
+ //
+
+ *lpNumberOfBytesWritten = 0;
+ }
+ else
+ {
+ ASSERT( "lpNumberOfBytesWritten is NULL\n" );
+ palError = ERROR_INVALID_PARAMETER;
+ goto done;
+ }
+
+ // Win32 WriteFile disallows writing to STD_INPUT_HANDLE
+ if (hFile == INVALID_HANDLE_VALUE || hFile == pStdIn)
+ {
+ palError = ERROR_INVALID_HANDLE;
+ goto done;
+ }
+ else if ( lpOverlapped )
+ {
+ ASSERT( "lpOverlapped is not NULL, as it should be.\n" );
+ palError = ERROR_INVALID_PARAMETER;
+ goto done;
+ }
+
+ palError = g_pObjectManager->ReferenceObjectByHandle(
+ pThread,
+ hFile,
+ &aotFile,
+ GENERIC_WRITE,
+ &pFileObject
+ );
+
+ if (NO_ERROR != palError)
+ {
+ goto done;
+ }
+
+ palError = pFileObject->GetProcessLocalData(
+ pThread,
+ ReadLock,
+ &pLocalDataLock,
+ reinterpret_cast<void**>(&pLocalData)
+ );
+
+ if (NO_ERROR != palError)
+ {
+ goto done;
+ }
+
+ if (pLocalData->open_flags_deviceaccessonly == TRUE)
+ {
+ ERROR("File open for device access only\n");
+ palError = ERROR_ACCESS_DENIED;
+ goto done;
+ }
+
+ ifd = pLocalData->unix_fd;
+
+ //
+ // Inform the lock controller for this file (if any) of our intention
+ // to perform a write. (Note that pipes don't have lock controllers.)
+ //
+
+ if (NULL != pLocalData->pLockController)
+ {
+ /* Get the current file position to calculate the region to lock */
+ palError = InternalSetFilePointerForUnixFd(
+ ifd,
+ 0,
+ &writeOffsetStartHigh,
+ FILE_CURRENT,
+ &writeOffsetStartLow
+ );
+
+ if (NO_ERROR != palError)
+ {
+ ASSERT("Failed to get the current file position\n");
+ palError = ERROR_INTERNAL_ERROR;
+ goto done;
+ }
+
+ palError = pLocalData->pLockController->GetTransactionLock(
+ pThread,
+ IFileLockController::WriteLock,
+ writeOffsetStartLow,
+ writeOffsetStartHigh,
+ nNumberOfBytesToWrite,
+ 0,
+ &pTransactionLock
+ );
+
+ if (NO_ERROR != palError)
+ {
+ ERROR("Unable to obtain write transaction lock");
+ goto done;
+ }
+ }
+
+ //
+ // Release the data lock before performing the (possibly blocking)
+ // write call
+ //
+
+ pLocalDataLock->ReleaseLock(pThread, FALSE);
+ pLocalDataLock = NULL;
+ pLocalData = NULL;
+
+#if WRITE_0_BYTES_HANGS_TTY
+ if( nNumberOfBytesToWrite == 0 && isatty(ifd) )
+ {
+ res = 0;
+ *lpNumberOfBytesWritten = 0;
+ goto done;
+ }
+#endif
+
+ res = write( ifd, lpBuffer, nNumberOfBytesToWrite );
+ TRACE("write() returns %d\n", res);
+
+ if ( res >= 0 )
+ {
+ *lpNumberOfBytesWritten = res;
+ }
+ else
+ {
+ palError = FILEGetLastErrorFromErrno();
+ }
+
+done:
+
+ if (NULL != pTransactionLock)
+ {
+ pTransactionLock->ReleaseLock();
+ }
+
+ if (NULL != pLocalDataLock)
+ {
+ pLocalDataLock->ReleaseLock(pThread, FALSE);
+ }
+
+ if (NULL != pFileObject)
+ {
+ pFileObject->ReleaseReference(pThread);
+ }
+
+ return palError;
+}
+
+
+/*++
+Function:
+ WriteFileW
+
+Note:
+ lpOverlapped always NULL.
+
+See MSDN doc.
+--*/
+BOOL
+PALAPI
+WriteFile(
+ IN HANDLE hFile,
+ IN LPCVOID lpBuffer,
+ IN DWORD nNumberOfBytesToWrite,
+ OUT LPDWORD lpNumberOfBytesWritten,
+ IN LPOVERLAPPED lpOverlapped)
+{
+ PAL_ERROR palError;
+ CPalThread *pThread;
+
+ PERF_ENTRY(WriteFile);
+ ENTRY("WriteFile(hFile=%p, lpBuffer=%p, nToWrite=%u, lpWritten=%p, "
+ "lpOverlapped=%p)\n", hFile, lpBuffer, nNumberOfBytesToWrite,
+ lpNumberOfBytesWritten, lpOverlapped);
+
+ pThread = InternalGetCurrentThread();
+
+ palError = InternalWriteFile(
+ pThread,
+ hFile,
+ lpBuffer,
+ nNumberOfBytesToWrite,
+ lpNumberOfBytesWritten,
+ lpOverlapped
+ );
+
+ if (NO_ERROR != palError)
+ {
+ pThread->SetLastError(palError);
+ }
+
+ LOGEXIT("WriteFile returns BOOL %d\n", NO_ERROR == palError);
+ PERF_EXIT(WriteFile);
+ return NO_ERROR == palError;
+}
+
+PAL_ERROR
+CorUnix::InternalReadFile(
+ CPalThread *pThread,
+ HANDLE hFile,
+ LPVOID lpBuffer,
+ DWORD nNumberOfBytesToRead,
+ LPDWORD lpNumberOfBytesRead,
+ LPOVERLAPPED lpOverlapped
+ )
+{
+ PAL_ERROR palError = 0;
+ IPalObject *pFileObject = NULL;
+ CFileProcessLocalData *pLocalData = NULL;
+ IDataLock *pLocalDataLock = NULL;
+ IFileTransactionLock *pTransactionLock = NULL;
+ int ifd;
+
+ LONG readOffsetStartLow = 0, readOffsetStartHigh = 0;
+ int res;
+
+ if (NULL != lpNumberOfBytesRead)
+ {
+ //
+ // This must be set to 0 before any other error checking takes
+ // place, per MSDN
+ //
+
+ *lpNumberOfBytesRead = 0;
+ }
+ else
+ {
+ ERROR( "lpNumberOfBytesRead is NULL\n" );
+ palError = ERROR_INVALID_PARAMETER;
+ goto done;
+ }
+
+ if (INVALID_HANDLE_VALUE == hFile)
+ {
+ ERROR( "Invalid file handle\n" );
+ palError = ERROR_INVALID_HANDLE;
+ goto done;
+ }
+ else if (NULL != lpOverlapped)
+ {
+ ASSERT( "lpOverlapped is not NULL, as it should be.\n" );
+ palError = ERROR_INVALID_PARAMETER;
+ goto done;
+ }
+ else if (NULL == lpBuffer)
+ {
+ ERROR( "Invalid parameter. (lpBuffer:%p)\n", lpBuffer);
+ palError = ERROR_NOACCESS;
+ goto done;
+ }
+
+ palError = g_pObjectManager->ReferenceObjectByHandle(
+ pThread,
+ hFile,
+ &aotFile,
+ GENERIC_READ,
+ &pFileObject
+ );
+
+ if (NO_ERROR != palError)
+ {
+ goto done;
+ }
+
+ palError = pFileObject->GetProcessLocalData(
+ pThread,
+ ReadLock,
+ &pLocalDataLock,
+ reinterpret_cast<void**>(&pLocalData)
+ );
+
+ if (NO_ERROR != palError)
+ {
+ goto done;
+ }
+
+ if (pLocalData->open_flags_deviceaccessonly == TRUE)
+ {
+ ERROR("File open for device access only\n");
+ palError = ERROR_ACCESS_DENIED;
+ goto done;
+ }
+
+ ifd = pLocalData->unix_fd;
+
+ //
+ // Inform the lock controller for this file (if any) of our intention
+ // to perform a read. (Note that pipes don't have lock controllers.)
+ //
+
+ if (NULL != pLocalData->pLockController)
+ {
+ /* Get the current file position to calculate the region to lock */
+ palError = InternalSetFilePointerForUnixFd(
+ ifd,
+ 0,
+ &readOffsetStartHigh,
+ FILE_CURRENT,
+ &readOffsetStartLow
+ );
+
+ if (NO_ERROR != palError)
+ {
+ ASSERT("Failed to get the current file position\n");
+ palError = ERROR_INTERNAL_ERROR;
+ goto done;
+ }
+
+ palError = pLocalData->pLockController->GetTransactionLock(
+ pThread,
+ IFileLockController::ReadLock,
+ readOffsetStartLow,
+ readOffsetStartHigh,
+ nNumberOfBytesToRead,
+ 0,
+ &pTransactionLock
+ );
+
+ if (NO_ERROR != palError)
+ {
+ ERROR("Unable to obtain read transaction lock");
+ goto done;
+ }
+ }
+
+ //
+ // Release the data lock before performing the (possibly blocking)
+ // read call
+ //
+
+ pLocalDataLock->ReleaseLock(pThread, FALSE);
+ pLocalDataLock = NULL;
+ pLocalData = NULL;
+
+Read:
+ TRACE("Reading from file descriptor %d\n", ifd);
+ res = read(ifd, lpBuffer, nNumberOfBytesToRead);
+ TRACE("read() returns %d\n", res);
+
+ if (res >= 0)
+ {
+ *lpNumberOfBytesRead = res;
+ }
+ else if (errno == EINTR)
+ {
+ // Try to read again.
+ goto Read;
+ }
+ else
+ {
+ palError = FILEGetLastErrorFromErrno();
+ }
+
+done:
+
+ if (NULL != pTransactionLock)
+ {
+ pTransactionLock->ReleaseLock();
+ }
+
+ if (NULL != pLocalDataLock)
+ {
+ pLocalDataLock->ReleaseLock(pThread, FALSE);
+ }
+
+ if (NULL != pFileObject)
+ {
+ pFileObject->ReleaseReference(pThread);
+ }
+
+ return palError;
+}
+
+/*++
+Function:
+ ReadFile
+
+Note:
+ lpOverlapped always NULL.
+
+See MSDN doc.
+--*/
+BOOL
+PALAPI
+ReadFile(
+ IN HANDLE hFile,
+ OUT LPVOID lpBuffer,
+ IN DWORD nNumberOfBytesToRead,
+ OUT LPDWORD lpNumberOfBytesRead,
+ IN LPOVERLAPPED lpOverlapped)
+{
+ PAL_ERROR palError;
+ CPalThread *pThread;
+
+ PERF_ENTRY(ReadFile);
+ ENTRY("ReadFile(hFile=%p, lpBuffer=%p, nToRead=%u, "
+ "lpRead=%p, lpOverlapped=%p)\n",
+ hFile, lpBuffer, nNumberOfBytesToRead,
+ lpNumberOfBytesRead, lpOverlapped);
+
+ pThread = InternalGetCurrentThread();
+
+ palError = InternalReadFile(
+ pThread,
+ hFile,
+ lpBuffer,
+ nNumberOfBytesToRead,
+ lpNumberOfBytesRead,
+ lpOverlapped
+ );
+
+ if (NO_ERROR != palError)
+ {
+ pThread->SetLastError(palError);
+ }
+
+ LOGEXIT("ReadFile returns BOOL %d\n", NO_ERROR == palError);
+ PERF_EXIT(ReadFile);
+ return NO_ERROR == palError;
+}
+
+
+/*++
+Function:
+ GetStdHandle
+
+See MSDN doc.
+--*/
+HANDLE
+PALAPI
+GetStdHandle(
+ IN DWORD nStdHandle)
+{
+ CPalThread *pThread;
+ HANDLE hRet = INVALID_HANDLE_VALUE;
+
+ PERF_ENTRY(GetStdHandle);
+ ENTRY("GetStdHandle(nStdHandle=%#x)\n", nStdHandle);
+
+ pThread = InternalGetCurrentThread();
+ switch( nStdHandle )
+ {
+ case STD_INPUT_HANDLE:
+ hRet = pStdIn;
+ break;
+ case STD_OUTPUT_HANDLE:
+ hRet = pStdOut;
+ break;
+ case STD_ERROR_HANDLE:
+ hRet = pStdErr;
+ break;
+ default:
+ ERROR("nStdHandle is invalid\n");
+ pThread->SetLastError(ERROR_INVALID_PARAMETER);
+ break;
+ }
+
+ LOGEXIT("GetStdHandle returns HANDLE %p\n", hRet);
+ PERF_EXIT(GetStdHandle);
+ return hRet;
+}
+
+PAL_ERROR
+CorUnix::InternalSetEndOfFile(
+ CPalThread *pThread,
+ HANDLE hFile
+ )
+{
+ PAL_ERROR palError = 0;
+ IPalObject *pFileObject = NULL;
+ CFileProcessLocalData *pLocalData = NULL;
+ IDataLock *pLocalDataLock = NULL;
+
+ off_t curr = 0;
+
+ if (INVALID_HANDLE_VALUE == hFile)
+ {
+ ERROR( "Invalid file handle\n" );
+ palError = ERROR_INVALID_HANDLE;
+ goto InternalSetEndOfFileExit;
+ }
+
+ palError = g_pObjectManager->ReferenceObjectByHandle(
+ pThread,
+ hFile,
+ &aotFile,
+ GENERIC_WRITE,
+ &pFileObject
+ );
+
+ if (NO_ERROR != palError)
+ {
+ goto InternalSetEndOfFileExit;
+ }
+
+ palError = pFileObject->GetProcessLocalData(
+ pThread,
+ ReadLock,
+ &pLocalDataLock,
+ reinterpret_cast<void**>(&pLocalData)
+ );
+
+ if (NO_ERROR != palError)
+ {
+ goto InternalSetEndOfFileExit;
+ }
+
+ if (pLocalData->open_flags_deviceaccessonly == TRUE)
+ {
+ ERROR("File open for device access only\n");
+ palError = ERROR_ACCESS_DENIED;
+ goto InternalSetEndOfFileExit;
+ }
+
+ curr = lseek(pLocalData->unix_fd, 0, SEEK_CUR);
+
+ TRACE("current file pointer offset is %u\n", curr);
+ if ( curr < 0 )
+ {
+ ERROR("lseek returned %ld\n", curr);
+ palError = FILEGetLastErrorFromErrno();
+ goto InternalSetEndOfFileExit;
+ }
+
+#if SIZEOF_OFF_T > 4
+#if !HAVE_FTRUNCATE_LARGE_LENGTH_SUPPORT
+ // ftruncate will return the wrong value for some large lengths.
+ // We'll short-circuit the process and simply return failure for
+ // the set of values that covers those cases, all of which would
+ // have failed anyway on any standard-sized hard drive.
+ if (curr >= 0xFFFFFFFF000ULL)
+ {
+ ERROR("Skipping ftruncate because the offset is too large\n");
+ palError = ERROR_INVALID_PARAMETER;
+ goto InternalSetEndOfFileExit;
+ }
+#endif // !HAVE_FTRUNCATE_LARGE_LENGTH_SUPPORT
+#endif // SIZEOF_OFF_T
+
+#if HAS_FTRUNCATE_LENGTH_ISSUE
+ // Perform an additional check to make sure that there's likely to be enough free space to satisfy the
+ // request. Do this because it's been observed on Mac OSX that ftruncate can return failure but still
+ // extend the file to consume the remainder of free space.
+ //
+ struct statfs sFileSystemStats;
+ off_t cbFreeSpace;
+ if (fstatfs(pLocalData->unix_fd, &sFileSystemStats) != 0)
+ {
+ ERROR("fstatfs failed\n");
+ palError = FILEGetLastErrorFromErrno();
+ goto InternalSetEndOfFileExit;
+ }
+
+ // Free space is free blocks times the size of each block in bytes.
+ cbFreeSpace = (off_t)sFileSystemStats.f_bavail * (off_t)sFileSystemStats.f_bsize;
+
+ if (curr > cbFreeSpace)
+ {
+ ERROR("Not enough disk space for ftruncate\n");
+ palError = ERROR_DISK_FULL;
+ goto InternalSetEndOfFileExit;
+ }
+#endif // HAS_FTRUNCATE_LENGTH_ISSUE
+
+ if ( ftruncate(pLocalData->unix_fd, curr) != 0 )
+ {
+ ERROR("ftruncate failed\n");
+ if ( errno == EACCES )
+ {
+ ERROR("file may not be writable\n");
+ }
+ palError = FILEGetLastErrorFromErrno();
+ goto InternalSetEndOfFileExit;
+ }
+
+
+InternalSetEndOfFileExit:
+
+ // Windows starts returning ERROR_INVALID_PARAMETER at an arbitrary file size (~16TB). The file system
+ // underneath us may be able to support larger and it would be a shame to prevent that. As a compromise,
+ // if the operation fails and the file size was above the Windows limit map ERROR_DISK_FULL to
+ // ERROR_INVALID_PARAMETER.
+ // curr has been checked to be positive after getting the value from lseek. The following cast is put to
+ // suppress the compilation warning.
+ if (palError == ERROR_DISK_FULL && (static_cast<UINT64>(curr) > 0x00000fffffff0000ULL ) )
+ palError = ERROR_INVALID_PARAMETER;
+
+ if (NULL != pLocalDataLock)
+ {
+ pLocalDataLock->ReleaseLock(pThread, FALSE);
+ }
+
+ if (NULL != pFileObject)
+ {
+ pFileObject->ReleaseReference(pThread);
+ }
+
+ return palError;
+}
+
+
+
+/*++
+Function:
+ SetEndOfFile
+
+See MSDN doc.
+--*/
+BOOL
+PALAPI
+SetEndOfFile(
+ IN HANDLE hFile)
+{
+ PAL_ERROR palError = NO_ERROR;
+ CPalThread *pThread;;
+
+ PERF_ENTRY(SetEndOfFile);
+ ENTRY("SetEndOfFile(hFile=%p)\n", hFile);
+
+ pThread = InternalGetCurrentThread();
+
+ palError = InternalSetEndOfFile(
+ pThread,
+ hFile
+ );
+
+ if (NO_ERROR != palError)
+ {
+ pThread->SetLastError(palError);
+ }
+
+ LOGEXIT("SetEndOfFile returns BOOL %d\n", NO_ERROR == palError);
+ PERF_EXIT(SetEndOfFile);
+ return NO_ERROR == palError;
+}
+
+//
+// We need to break out the actual mechanics of setting the file pointer
+// on the unix FD for InternalReadFile and InternalWriteFile, as they
+// need to call this routine in order to determine the value of the
+// current file pointer when computing the scope of their transaction
+// lock. If we didn't break out this logic we'd end up referencing the file
+// handle multiple times, and, in the process, would attempt to recursively
+// obtain the local process data lock for the underlying file object.
+//
+
+PAL_ERROR
+InternalSetFilePointerForUnixFd(
+ int iUnixFd,
+ LONG lDistanceToMove,
+ PLONG lpDistanceToMoveHigh,
+ DWORD dwMoveMethod,
+ PLONG lpNewFilePointerLow
+ )
+{
+ PAL_ERROR palError = NO_ERROR;
+ int seek_whence = 0;
+ __int64 seek_offset = 0LL;
+ __int64 seek_res = 0LL;
+ off_t old_offset;
+
+ switch( dwMoveMethod )
+ {
+ case FILE_BEGIN:
+ seek_whence = SEEK_SET;
+ break;
+ case FILE_CURRENT:
+ seek_whence = SEEK_CUR;
+ break;
+ case FILE_END:
+ seek_whence = SEEK_END;
+ break;
+ default:
+ ERROR("dwMoveMethod = %d is invalid\n", dwMoveMethod);
+ palError = ERROR_INVALID_PARAMETER;
+ goto done;
+ }
+
+ //
+ // According to MSDN, if lpDistanceToMoveHigh is not null,
+ // lDistanceToMove is treated as unsigned;
+ // it is treated as signed otherwise
+ //
+
+ if ( lpDistanceToMoveHigh )
+ {
+ /* set the high 32 bits of the offset */
+ seek_offset = ((__int64)*lpDistanceToMoveHigh << 32);
+
+ /* set the low 32 bits */
+ /* cast to unsigned long to avoid sign extension */
+ seek_offset |= (ULONG) lDistanceToMove;
+ }
+ else
+ {
+ seek_offset |= lDistanceToMove;
+ }
+
+ /* store the current position, in case the lseek moves the pointer
+ before the beginning of the file */
+ old_offset = lseek(iUnixFd, 0, SEEK_CUR);
+ if (old_offset == -1)
+ {
+ ERROR("lseek(fd,0,SEEK_CUR) failed errno:%d (%s)\n",
+ errno, strerror(errno));
+ palError = ERROR_ACCESS_DENIED;
+ goto done;
+ }
+
+ // Check to see if we're going to seek to a negative offset.
+ // If we're seeking from the beginning or the current mark,
+ // this is simple.
+ if ((seek_whence == SEEK_SET && seek_offset < 0) ||
+ (seek_whence == SEEK_CUR && seek_offset + old_offset < 0))
+ {
+ palError = ERROR_NEGATIVE_SEEK;
+ goto done;
+ }
+ else if (seek_whence == SEEK_END && seek_offset < 0)
+ {
+ // We need to determine if we're seeking past the
+ // beginning of the file, but we don't want to adjust
+ // the mark in the process. stat is the only way to
+ // do that.
+ struct stat fileData;
+ int result;
+
+ result = fstat(iUnixFd, &fileData);
+ if (result == -1)
+ {
+ // It's a bad fd. This shouldn't happen because
+ // we've already called lseek on it, but you
+ // never know. This is the best we can do.
+ palError = ERROR_ACCESS_DENIED;
+ goto done;
+ }
+ if (fileData.st_size < -seek_offset)
+ {
+ // Seeking past the beginning.
+ palError = ERROR_NEGATIVE_SEEK;
+ goto done;
+ }
+ }
+
+ seek_res = (__int64)lseek( iUnixFd,
+ seek_offset,
+ seek_whence );
+ if ( seek_res < 0 )
+ {
+ /* lseek() returns -1 on error, but also can seek to negative
+ file offsets, so -1 can also indicate a successful seek to offset
+ -1. Win32 doesn't allow negative file offsets, so either case
+ is an error. */
+ ERROR("lseek failed errno:%d (%s)\n", errno, strerror(errno));
+ lseek(iUnixFd, old_offset, SEEK_SET);
+ palError = ERROR_ACCESS_DENIED;
+ }
+ else
+ {
+ /* store high-order DWORD */
+ if ( lpDistanceToMoveHigh )
+ *lpDistanceToMoveHigh = (DWORD)(seek_res >> 32);
+
+ /* return low-order DWORD of seek result */
+ *lpNewFilePointerLow = (DWORD)seek_res;
+ }
+
+done:
+
+ return palError;
+}
+
+PAL_ERROR
+CorUnix::InternalSetFilePointer(
+ CPalThread *pThread,
+ HANDLE hFile,
+ LONG lDistanceToMove,
+ PLONG lpDistanceToMoveHigh,
+ DWORD dwMoveMethod,
+ PLONG lpNewFilePointerLow
+ )
+{
+ PAL_ERROR palError = NO_ERROR;
+ IPalObject *pFileObject = NULL;
+ CFileProcessLocalData *pLocalData = NULL;
+ IDataLock *pLocalDataLock = NULL;
+
+ if (INVALID_HANDLE_VALUE == hFile)
+ {
+ ERROR( "Invalid file handle\n" );
+ palError = ERROR_INVALID_HANDLE;
+ goto InternalSetFilePointerExit;
+ }
+
+ palError = g_pObjectManager->ReferenceObjectByHandle(
+ pThread,
+ hFile,
+ &aotFile,
+ GENERIC_READ,
+ &pFileObject
+ );
+
+ if (NO_ERROR != palError)
+ {
+ goto InternalSetFilePointerExit;
+ }
+
+ palError = pFileObject->GetProcessLocalData(
+ pThread,
+ ReadLock,
+ &pLocalDataLock,
+ reinterpret_cast<void**>(&pLocalData)
+ );
+
+ if (NO_ERROR != palError)
+ {
+ goto InternalSetFilePointerExit;
+ }
+
+ palError = InternalSetFilePointerForUnixFd(
+ pLocalData->unix_fd,
+ lDistanceToMove,
+ lpDistanceToMoveHigh,
+ dwMoveMethod,
+ lpNewFilePointerLow
+ );
+
+InternalSetFilePointerExit:
+
+ if (NULL != pLocalDataLock)
+ {
+ pLocalDataLock->ReleaseLock(pThread, FALSE);
+ }
+
+ if (NULL != pFileObject)
+ {
+ pFileObject->ReleaseReference(pThread);
+ }
+
+ return palError;
+}
+
+/*++
+Function:
+ SetFilePointer
+
+See MSDN doc.
+--*/
+DWORD
+PALAPI
+SetFilePointer(
+ IN HANDLE hFile,
+ IN LONG lDistanceToMove,
+ IN PLONG lpDistanceToMoveHigh,
+ IN DWORD dwMoveMethod)
+{
+ PAL_ERROR palError = NO_ERROR;
+ CPalThread *pThread;
+ LONG lNewFilePointerLow = 0;
+
+ PERF_ENTRY(SetFilePointer);
+ ENTRY("SetFilePointer(hFile=%p, lDistance=%d, lpDistanceHigh=%p, "
+ "dwMoveMethod=%#x)\n", hFile, lDistanceToMove,
+ lpDistanceToMoveHigh, dwMoveMethod);
+
+ pThread = InternalGetCurrentThread();
+
+ palError = InternalSetFilePointer(
+ pThread,
+ hFile,
+ lDistanceToMove,
+ lpDistanceToMoveHigh,
+ dwMoveMethod,
+ &lNewFilePointerLow
+ );
+
+ if (NO_ERROR != palError)
+ {
+ lNewFilePointerLow = INVALID_SET_FILE_POINTER;
+ }
+
+ /* This function must always call SetLastError - even if successful.
+ If we seek to a value greater than 2^32 - 1, we will effectively be
+ returning a negative value from this function. Now, let's say that
+ returned value is -1. Furthermore, assume that win32error has been
+ set before even entering this function. Then, when this function
+ returns to SetFilePointer in win32native.cs, it will have returned
+ -1 and win32error will have been set, which will cause an error to be
+ returned. Since -1 may not be an error in this case and since we
+ can't assume that the win32error is related to SetFilePointer,
+ we need to always call SetLastError here. That way, if this function
+ succeeds, SetFilePointer in win32native won't mistakenly determine
+ that it failed. */
+ pThread->SetLastError(palError);
+
+ LOGEXIT("SetFilePointer returns DWORD %#x\n", lNewFilePointerLow);
+ PERF_EXIT(SetFilePointer);
+ return lNewFilePointerLow;
+}
+
+/*++
+Function:
+ SetFilePointerEx
+
+See MSDN doc.
+--*/
+BOOL
+PALAPI
+SetFilePointerEx(
+ IN HANDLE hFile,
+ IN LARGE_INTEGER liDistanceToMove,
+ OUT PLARGE_INTEGER lpNewFilePointer,
+ IN DWORD dwMoveMethod)
+{
+ PAL_ERROR palError = NO_ERROR;
+ CPalThread *pThread;
+ BOOL Ret = FALSE;
+
+ PERF_ENTRY(SetFilePointerEx);
+ ENTRY("SetFilePointerEx(hFile=%p, liDistanceToMove=0x%llx, "
+ "lpNewFilePointer=%p (0x%llx), dwMoveMethod=0x%x)\n", hFile,
+ liDistanceToMove.QuadPart, lpNewFilePointer,
+ (lpNewFilePointer) ? (*lpNewFilePointer).QuadPart : 0, dwMoveMethod);
+
+ LONG lDistanceToMove;
+ lDistanceToMove = (LONG)liDistanceToMove.u.LowPart;
+ LONG lDistanceToMoveHigh;
+ lDistanceToMoveHigh = liDistanceToMove.u.HighPart;
+
+ LONG lNewFilePointerLow = 0;
+
+ pThread = InternalGetCurrentThread();
+
+ palError = InternalSetFilePointer(
+ pThread,
+ hFile,
+ lDistanceToMove,
+ &lDistanceToMoveHigh,
+ dwMoveMethod,
+ &lNewFilePointerLow
+ );
+
+ if (NO_ERROR != palError)
+ {
+ pThread->SetLastError(palError);
+ }
+ else
+ {
+ if (lpNewFilePointer != NULL)
+ {
+ lpNewFilePointer->u.LowPart = (DWORD)lNewFilePointerLow;
+ lpNewFilePointer->u.HighPart = (DWORD)lDistanceToMoveHigh;
+ }
+ Ret = TRUE;
+ }
+
+ LOGEXIT("SetFilePointerEx returns BOOL %d\n", Ret);
+ PERF_EXIT(SetFilePointerEx);
+ return Ret;
+}
+
+PAL_ERROR
+CorUnix::InternalGetFileSize(
+ CPalThread *pThread,
+ HANDLE hFile,
+ DWORD *pdwFileSizeLow,
+ DWORD *pdwFileSizeHigh
+ )
+{
+ PAL_ERROR palError = NO_ERROR;
+ IPalObject *pFileObject = NULL;
+ CFileProcessLocalData *pLocalData = NULL;
+ IDataLock *pLocalDataLock = NULL;
+
+ struct stat stat_data;
+
+ if (INVALID_HANDLE_VALUE == hFile)
+ {
+ ERROR( "Invalid file handle\n" );
+ palError = ERROR_INVALID_HANDLE;
+ goto InternalGetFileSizeExit;
+ }
+
+ palError = g_pObjectManager->ReferenceObjectByHandle(
+ pThread,
+ hFile,
+ &aotFile,
+ GENERIC_READ,
+ &pFileObject
+ );
+
+ if (NO_ERROR != palError)
+ {
+ goto InternalGetFileSizeExit;
+ }
+
+ palError = pFileObject->GetProcessLocalData(
+ pThread,
+ ReadLock,
+ &pLocalDataLock,
+ reinterpret_cast<void**>(&pLocalData)
+ );
+
+ if (NO_ERROR != palError)
+ {
+ goto InternalGetFileSizeExit;
+ }
+
+ if (fstat(pLocalData->unix_fd, &stat_data) != 0)
+ {
+ ERROR("fstat failed of file descriptor %d\n", pLocalData->unix_fd);
+ palError = FILEGetLastErrorFromErrno();
+ goto InternalGetFileSizeExit;
+ }
+
+ *pdwFileSizeLow = (DWORD)stat_data.st_size;
+
+ if (NULL != pdwFileSizeHigh)
+ {
+#if SIZEOF_OFF_T > 4
+ *pdwFileSizeHigh = (DWORD)(stat_data.st_size >> 32);
+#else
+ *pdwFileSizeHigh = 0;
+#endif
+ }
+
+InternalGetFileSizeExit:
+
+ if (NULL != pLocalDataLock)
+ {
+ pLocalDataLock->ReleaseLock(pThread, FALSE);
+ }
+
+ if (NULL != pFileObject)
+ {
+ pFileObject->ReleaseReference(pThread);
+ }
+
+ return palError;
+}
+
+/*++
+Function:
+ GetFileSize
+
+See MSDN doc.
+--*/
+DWORD
+PALAPI
+GetFileSize(
+ IN HANDLE hFile,
+ OUT LPDWORD lpFileSizeHigh)
+{
+ PAL_ERROR palError = NO_ERROR;
+ CPalThread *pThread;
+ DWORD dwFileSizeLow;
+
+ PERF_ENTRY(GetFileSize);
+ ENTRY("GetFileSize(hFile=%p, lpFileSizeHigh=%p)\n", hFile, lpFileSizeHigh);
+
+ pThread = InternalGetCurrentThread();
+
+ palError = InternalGetFileSize(
+ pThread,
+ hFile,
+ &dwFileSizeLow,
+ lpFileSizeHigh
+ );
+
+ if (NO_ERROR != palError)
+ {
+ pThread->SetLastError(palError);
+ dwFileSizeLow = INVALID_FILE_SIZE;
+ }
+
+ LOGEXIT("GetFileSize returns DWORD %u\n", dwFileSizeLow);
+ PERF_EXIT(GetFileSize);
+ return dwFileSizeLow;
+}
+
+/*++
+Function:
+GetFileSizeEx
+
+See MSDN doc.
+--*/
+BOOL
+PALAPI GetFileSizeEx(
+IN HANDLE hFile,
+OUT PLARGE_INTEGER lpFileSize)
+{
+ PAL_ERROR palError = NO_ERROR;
+ CPalThread *pThread;
+ DWORD dwFileSizeHigh;
+ DWORD dwFileSizeLow;
+
+ PERF_ENTRY(GetFileSizeEx);
+ ENTRY("GetFileSizeEx(hFile=%p, lpFileSize=%p)\n", hFile, lpFileSize);
+
+ pThread = InternalGetCurrentThread();
+
+ if (lpFileSize != NULL)
+ {
+ palError = InternalGetFileSize(
+ pThread,
+ hFile,
+ &dwFileSizeLow,
+ &dwFileSizeHigh
+ );
+
+ lpFileSize->u.LowPart = dwFileSizeLow;
+ lpFileSize->u.HighPart = dwFileSizeHigh;
+ }
+ else
+ {
+ palError = ERROR_INVALID_PARAMETER;
+ }
+
+ if (NO_ERROR != palError)
+ {
+ pThread->SetLastError(palError);
+ }
+
+ LOGEXIT("GetFileSizeEx returns BOOL %d\n", NO_ERROR == palError);
+ PERF_EXIT(GetFileSizeEx);
+ return NO_ERROR == palError;
+}
+
+PAL_ERROR
+CorUnix::InternalFlushFileBuffers(
+ CPalThread *pThread,
+ HANDLE hFile
+ )
+{
+ PAL_ERROR palError = NO_ERROR;
+ IPalObject *pFileObject = NULL;
+ CFileProcessLocalData *pLocalData = NULL;
+ IDataLock *pLocalDataLock = NULL;
+
+ if (INVALID_HANDLE_VALUE == hFile)
+ {
+ ERROR( "Invalid file handle\n" );
+ palError = ERROR_INVALID_HANDLE;
+ goto InternalFlushFileBuffersExit;
+ }
+
+ palError = g_pObjectManager->ReferenceObjectByHandle(
+ pThread,
+ hFile,
+ &aotFile,
+ GENERIC_WRITE,
+ &pFileObject
+ );
+
+ if (NO_ERROR != palError)
+ {
+ goto InternalFlushFileBuffersExit;
+ }
+
+ palError = pFileObject->GetProcessLocalData(
+ pThread,
+ ReadLock,
+ &pLocalDataLock,
+ reinterpret_cast<void**>(&pLocalData)
+ );
+
+ if (NO_ERROR != palError)
+ {
+ goto InternalFlushFileBuffersExit;
+ }
+
+ if (pLocalData->open_flags_deviceaccessonly == TRUE)
+ {
+ ERROR("File open for device access only\n");
+ palError = ERROR_ACCESS_DENIED;
+ goto InternalFlushFileBuffersExit;
+ }
+
+#if HAVE_FSYNC || defined(__APPLE__)
+ do
+ {
+
+#if defined(__APPLE__)
+ if (fcntl(pLocalData->unix_fd, F_FULLFSYNC) != -1)
+ break;
+#else // __APPLE__
+ if (fsync(pLocalData->unix_fd) == 0)
+ break;
+#endif // __APPLE__
+
+ switch (errno)
+ {
+ case EINTR:
+ // Execution was interrupted by a signal, so restart.
+ TRACE("fsync(%d) was interrupted. Restarting\n", pLocalData->unix_fd);
+ break;
+
+ default:
+ palError = FILEGetLastErrorFromErrno();
+ WARN("fsync(%d) failed with error %d\n", pLocalData->unix_fd, errno);
+ break;
+ }
+ } while (NO_ERROR == palError);
+#else // HAVE_FSYNC
+ /* flush all buffers out to disk - there is no way to flush
+ an individual file descriptor's buffers out. */
+ sync();
+#endif // HAVE_FSYNC else
+
+
+InternalFlushFileBuffersExit:
+
+ if (NULL != pLocalDataLock)
+ {
+ pLocalDataLock->ReleaseLock(pThread, FALSE);
+ }
+
+ if (NULL != pFileObject)
+ {
+ pFileObject->ReleaseReference(pThread);
+ }
+
+ return palError;
+}
+
+
+/*++
+Function:
+ FlushFileBuffers
+
+See MSDN doc.
+--*/
+BOOL
+PALAPI
+FlushFileBuffers(
+ IN HANDLE hFile)
+{
+ PAL_ERROR palError = NO_ERROR;
+ CPalThread *pThread;
+
+ PERF_ENTRY(FlushFileBuffers);
+ ENTRY("FlushFileBuffers(hFile=%p)\n", hFile);
+
+ pThread = InternalGetCurrentThread();
+
+ palError = InternalFlushFileBuffers(
+ pThread,
+ hFile
+ );
+
+ if (NO_ERROR != palError)
+ {
+ pThread->SetLastError(palError);
+ }
+
+ LOGEXIT("FlushFileBuffers returns BOOL %d\n", NO_ERROR == palError);
+ PERF_EXIT(FlushFileBuffers);
+ return NO_ERROR == palError;
+}
+
+PAL_ERROR
+CorUnix::InternalGetFileType(
+ CPalThread *pThread,
+ HANDLE hFile,
+ DWORD *pdwFileType
+ )
+{
+ PAL_ERROR palError = NO_ERROR;
+ IPalObject *pFileObject = NULL;
+ CFileProcessLocalData *pLocalData = NULL;
+ IDataLock *pLocalDataLock = NULL;
+
+ struct stat stat_data;
+
+ if (INVALID_HANDLE_VALUE == hFile)
+ {
+ ERROR( "Invalid file handle\n" );
+ palError = ERROR_INVALID_HANDLE;
+ goto InternalGetFileTypeExit;
+ }
+
+ palError = g_pObjectManager->ReferenceObjectByHandle(
+ pThread,
+ hFile,
+ &aotFile,
+ GENERIC_READ,
+ &pFileObject
+ );
+
+ if (NO_ERROR != palError)
+ {
+ goto InternalGetFileTypeExit;
+ }
+
+ palError = pFileObject->GetProcessLocalData(
+ pThread,
+ ReadLock,
+ &pLocalDataLock,
+ reinterpret_cast<void**>(&pLocalData)
+ );
+
+ if (NO_ERROR != palError)
+ {
+ goto InternalGetFileTypeExit;
+ }
+
+ if (pLocalData->open_flags_deviceaccessonly == TRUE)
+ {
+ ERROR("File open for device access only\n");
+ palError = ERROR_ACCESS_DENIED;
+ goto InternalGetFileTypeExit;
+ }
+
+ if (fstat(pLocalData->unix_fd, &stat_data) != 0)
+ {
+ ERROR("fstat failed of file descriptor %d\n", pLocalData->unix_fd);
+ palError = FILEGetLastErrorFromErrno();
+ goto InternalGetFileTypeExit;
+ }
+
+ TRACE("st_mode & S_IFMT = %#x\n", stat_data.st_mode & S_IFMT);
+ if (S_ISREG(stat_data.st_mode) || S_ISDIR(stat_data.st_mode))
+ {
+ *pdwFileType = FILE_TYPE_DISK;
+ }
+ else if (S_ISCHR(stat_data.st_mode))
+ {
+ *pdwFileType = FILE_TYPE_CHAR;
+ }
+ else if (S_ISFIFO(stat_data.st_mode))
+ {
+ *pdwFileType = FILE_TYPE_PIPE;
+ }
+ else
+ {
+ *pdwFileType = FILE_TYPE_UNKNOWN;
+ }
+
+
+InternalGetFileTypeExit:
+
+ if (NULL != pLocalDataLock)
+ {
+ pLocalDataLock->ReleaseLock(pThread, FALSE);
+ }
+
+ if (NULL != pFileObject)
+ {
+ pFileObject->ReleaseReference(pThread);
+ }
+
+ return palError;
+
+}
+
+
+/*++
+Function:
+ GetFileType
+
+See MSDN doc.
+
+--*/
+DWORD
+PALAPI
+GetFileType(
+ IN HANDLE hFile)
+{
+ PAL_ERROR palError = NO_ERROR;
+ CPalThread *pThread;
+ DWORD dwFileType;
+
+ PERF_ENTRY(GetFileType);
+ ENTRY("GetFileType(hFile=%p)\n", hFile);
+
+ pThread = InternalGetCurrentThread();
+
+ palError = InternalGetFileType(
+ pThread,
+ hFile,
+ &dwFileType
+ );
+
+ if (NO_ERROR != palError)
+ {
+ dwFileType = FILE_TYPE_UNKNOWN;
+ pThread->SetLastError(palError);
+ }
+ else if (FILE_TYPE_UNKNOWN == dwFileType)
+ {
+ pThread->SetLastError(palError);
+ }
+
+
+ LOGEXIT("GetFileType returns DWORD %#x\n", dwFileType);
+ PERF_EXIT(GetFileType);
+ return dwFileType;
+}
+
+#define ENSURE_UNIQUE_NOT_ZERO \
+ if ( uUniqueSeed == 0 ) \
+ {\
+ uUniqueSeed++;\
+ }
+
+/*++
+ Function:
+ GetTempFileNameA
+
+uUnique is always 0.
+ --*/
+const int MAX_PREFIX = 3;
+const int MAX_SEEDSIZE = 8; /* length of "unique portion of
+ the string, plus extension(FFFF.TMP). */
+static USHORT uUniqueSeed = 0;
+static BOOL IsInitialized = FALSE;
+
+UINT
+PALAPI
+GetTempFileNameA(
+ IN LPCSTR lpPathName,
+ IN LPCSTR lpPrefixString,
+ IN UINT uUnique,
+ OUT LPSTR lpTempFileName)
+{
+ CPalThread *pThread;
+ CHAR * full_name;
+ PathCharString full_namePS;
+ int length;
+ CHAR * file_template;
+ PathCharString file_templatePS;
+ CHAR chLastPathNameChar;
+
+ HANDLE hTempFile;
+ UINT uRet = 0;
+ DWORD dwError;
+ USHORT uLoopCounter = 0;
+
+ PERF_ENTRY(GetTempFileNameA);
+ ENTRY("GetTempFileNameA(lpPathName=%p (%s), lpPrefixString=%p (%s), uUnique=%u, "
+ "lpTempFileName=%p)\n", lpPathName?lpPathName:"NULL", lpPathName?lpPathName:"NULL",
+ lpPrefixString?lpPrefixString:"NULL",
+ lpPrefixString?lpPrefixString:"NULL", uUnique,
+ lpTempFileName?lpTempFileName:"NULL");
+
+ pThread = InternalGetCurrentThread();
+ if ( !IsInitialized )
+ {
+ uUniqueSeed = (USHORT)( time( NULL ) );
+
+ /* On the off chance 0 is returned.
+ 0 being the error return code. */
+ ENSURE_UNIQUE_NOT_ZERO
+ IsInitialized = TRUE;
+ }
+
+ if ( !lpPathName || *lpPathName == '\0' )
+ {
+ pThread->SetLastError( ERROR_DIRECTORY );
+ goto done;
+ }
+
+ if ( NULL == lpTempFileName )
+ {
+ ERROR( "lpTempFileName cannot be NULL\n" );
+ pThread->SetLastError( ERROR_INVALID_PARAMETER );
+ goto done;
+ }
+
+ if ( strlen( lpPathName ) + MAX_SEEDSIZE + MAX_PREFIX >= MAX_LONGPATH )
+ {
+ WARN( "File names larger than MAX_LONGPATH (%d)!\n", MAX_LONGPATH );
+ pThread->SetLastError( ERROR_FILENAME_EXCED_RANGE );
+ goto done;
+ }
+
+ length = strlen(lpPathName) + MAX_SEEDSIZE + MAX_PREFIX + 10;
+ file_template = file_templatePS.OpenStringBuffer(length);
+ if (NULL == file_template)
+ {
+ pThread->SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ goto done;
+ }
+ *file_template = '\0';
+ strcat_s( file_template, file_templatePS.GetSizeOf(), lpPathName );
+ file_templatePS.CloseBuffer(length);
+
+ chLastPathNameChar = file_template[strlen(file_template)-1];
+ if (chLastPathNameChar != '\\' && chLastPathNameChar != '/')
+ {
+ strcat_s( file_template, file_templatePS.GetSizeOf(), "\\" );
+ }
+
+ if ( lpPrefixString )
+ {
+ strncat_s( file_template, file_templatePS.GetSizeOf(), lpPrefixString, MAX_PREFIX );
+ }
+ FILEDosToUnixPathA( file_template );
+ strncat_s( file_template, file_templatePS.GetSizeOf(), "%.4x.TMP", MAX_SEEDSIZE );
+
+ /* Create the file. */
+ dwError = GetLastError();
+ pThread->SetLastError( NOERROR );
+
+ length = strlen(file_template) + MAX_SEEDSIZE + MAX_PREFIX;
+ full_name = full_namePS.OpenStringBuffer(length);
+ if (NULL == full_name)
+ {
+ pThread->SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ goto done;
+ }
+ sprintf_s( full_name, full_namePS.GetSizeOf(), file_template, (0 == uUnique) ? uUniqueSeed : uUnique);
+ full_namePS.CloseBuffer(length);
+
+ hTempFile = CreateFileA( full_name, GENERIC_WRITE,
+ FILE_SHARE_READ, NULL, CREATE_NEW, 0, NULL );
+
+ if (uUnique == 0)
+ {
+ /* The USHORT will overflow back to 0 if we go past
+ 65536 files, so break the loop after 65536 iterations.
+ If the CreateFile call was not successful within that
+ number of iterations, then there are no temp file names
+ left for that directory. */
+ while ( ERROR_PATH_NOT_FOUND != GetLastError() &&
+ INVALID_HANDLE_VALUE == hTempFile && uLoopCounter < 0xFFFF )
+ {
+ uUniqueSeed++;
+ ENSURE_UNIQUE_NOT_ZERO;
+
+ pThread->SetLastError( NOERROR );
+ sprintf_s( full_name, full_namePS.GetSizeOf(), file_template, uUniqueSeed );
+ hTempFile = CreateFileA( full_name, GENERIC_WRITE,
+ FILE_SHARE_READ, NULL, CREATE_NEW, 0, NULL );
+ uLoopCounter++;
+
+ }
+ }
+
+ /* Reset the error code.*/
+ if ( NOERROR == GetLastError() )
+ {
+ pThread->SetLastError( dwError );
+ }
+
+ /* Windows sets ERROR_FILE_EXISTS,if there
+ are no available temp files. */
+ if ( INVALID_HANDLE_VALUE != hTempFile )
+ {
+ if (0 == uUnique)
+ {
+ uRet = uUniqueSeed;
+ uUniqueSeed++;
+ ENSURE_UNIQUE_NOT_ZERO;
+ }
+ else
+ {
+ uRet = uUnique;
+ }
+
+ if ( CloseHandle( hTempFile ) )
+ {
+ if (strcpy_s( lpTempFileName, MAX_LONGPATH, full_name ) != SAFECRT_SUCCESS)
+ {
+ ERROR( "strcpy_s failed!\n");
+ pThread->SetLastError( ERROR_FILENAME_EXCED_RANGE );
+ *lpTempFileName = '\0';
+ uRet = 0;
+ }
+ }
+ else
+ {
+ ASSERT( "Unable to close the handle %p\n", hTempFile );
+ pThread->SetLastError( ERROR_INTERNAL_ERROR );
+ *lpTempFileName = '\0';
+ uRet = 0;
+ }
+ }
+ else if ( INVALID_HANDLE_VALUE == hTempFile && uLoopCounter < 0xFFFF )
+ {
+ ERROR( "Unable to create temp file. \n" );
+ uRet = 0;
+
+ if ( ERROR_PATH_NOT_FOUND == GetLastError() )
+ {
+ /* CreateFile failed because it could not
+ find the path. */
+ pThread->SetLastError( ERROR_DIRECTORY );
+ } /* else use the lasterror value from CreateFileA */
+ }
+ else
+ {
+ TRACE( "65535 files already exist in the directory. "
+ "No temp files available for creation.\n" );
+ pThread->SetLastError( ERROR_FILE_EXISTS );
+ }
+
+done:
+ LOGEXIT("GetTempFileNameA returns UINT %u\n", uRet);
+ PERF_EXIT(GetTempFileNameA);
+ return uRet;
+
+}
+
+/*++
+Function:
+ GetTempFileNameW
+
+uUnique is always 0.
+--*/
+UINT
+PALAPI
+GetTempFileNameW(
+ IN LPCWSTR lpPathName,
+ IN LPCWSTR lpPrefixString,
+ IN UINT uUnique,
+ OUT LPWSTR lpTempFileName)
+{
+ CPalThread *pThread;
+ INT path_size = 0;
+ INT prefix_size = 0;
+ CHAR * full_name;
+ CHAR * prefix_string;
+ CHAR * tempfile_name;
+ PathCharString full_namePS, prefix_stringPS;
+ INT length = 0;
+ UINT uRet;
+
+ PERF_ENTRY(GetTempFileNameW);
+ ENTRY("GetTempFileNameW(lpPathName=%p (%S), lpPrefixString=%p (%S), uUnique=%u, "
+ "lpTempFileName=%p)\n", lpPathName?lpPathName:W16_NULLSTRING, lpPathName?lpPathName:W16_NULLSTRING,
+ lpPrefixString?lpPrefixString:W16_NULLSTRING,
+ lpPrefixString?lpPrefixString:W16_NULLSTRING,uUnique, lpTempFileName);
+
+ pThread = InternalGetCurrentThread();
+ /* Sanity checks. */
+ if ( !lpPathName || *lpPathName == '\0' )
+ {
+ pThread->SetLastError( ERROR_DIRECTORY );
+ uRet = 0;
+ goto done;
+ }
+
+ length = (PAL_wcslen(lpPathName)+1) * MaxWCharToAcpLengthFactor;
+ full_name = full_namePS.OpenStringBuffer(length);
+ if (NULL == full_name)
+ {
+ pThread->SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ uRet = 0;
+ goto done;
+ }
+ path_size = WideCharToMultiByte( CP_ACP, 0, lpPathName, -1, full_name,
+ length, NULL, NULL );
+
+ if( path_size == 0 )
+ {
+ full_namePS.CloseBuffer(0);
+ DWORD dwLastError = GetLastError();
+ ASSERT("WideCharToMultiByte failure! error is %d\n", dwLastError);
+ pThread->SetLastError(ERROR_INTERNAL_ERROR);
+ uRet = 0;
+ goto done;
+ }
+
+ full_namePS.CloseBuffer(path_size - 1);
+
+ if (lpPrefixString != NULL)
+ {
+ length = (PAL_wcslen(lpPrefixString)+1) * MaxWCharToAcpLengthFactor;
+ prefix_string = prefix_stringPS.OpenStringBuffer(length);
+ if (NULL == prefix_string)
+ {
+ pThread->SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ uRet = 0;
+ goto done;
+ }
+ prefix_size = WideCharToMultiByte( CP_ACP, 0, lpPrefixString, -1,
+ prefix_string,
+ MAX_LONGPATH - path_size - MAX_SEEDSIZE,
+ NULL, NULL );
+
+ if( prefix_size == 0 )
+ {
+ prefix_stringPS.CloseBuffer(0);
+ DWORD dwLastError = GetLastError();
+ ASSERT("WideCharToMultiByte failure! error is %d\n", dwLastError);
+ pThread->SetLastError(ERROR_INTERNAL_ERROR);
+ uRet = 0;
+ goto done;
+ }
+ prefix_stringPS.CloseBuffer(prefix_size - 1);
+ }
+
+ tempfile_name = (char*)InternalMalloc(MAX_LONGPATH);
+ if (tempfile_name == NULL)
+ {
+ pThread->SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ uRet = 0;
+ goto done;
+ }
+
+ uRet = GetTempFileNameA(full_name,
+ (lpPrefixString == NULL) ? NULL : prefix_string,
+ 0, tempfile_name);
+ if (uRet)
+ {
+ path_size = MultiByteToWideChar( CP_ACP, 0, tempfile_name, -1,
+ lpTempFileName, MAX_LONGPATH );
+
+ free(tempfile_name);
+ tempfile_name = NULL;
+ if (!path_size)
+ {
+ DWORD dwLastError = GetLastError();
+ if (dwLastError == ERROR_INSUFFICIENT_BUFFER)
+ {
+ WARN("File names larger than MAX_PATH_FNAME (%d)! \n", MAX_LONGPATH);
+ dwLastError = ERROR_FILENAME_EXCED_RANGE;
+ }
+ else
+ {
+ ASSERT("MultiByteToWideChar failure! error is %d", dwLastError);
+ dwLastError = ERROR_INTERNAL_ERROR;
+ }
+ pThread->SetLastError(dwLastError);
+ uRet = 0;
+ }
+ }
+
+done:
+ LOGEXIT("GetTempFileNameW returns UINT %u\n", uRet);
+ PERF_EXIT(GetTempFileNameW);
+ return uRet;
+}
+
+/*++
+Function:
+ FILEGetLastErrorFromErrno
+
+Convert errno into the appropriate win32 error and return it.
+--*/
+DWORD FILEGetLastErrorFromErrno( void )
+{
+ DWORD dwRet;
+
+ switch(errno)
+ {
+ case 0:
+ dwRet = ERROR_SUCCESS;
+ break;
+ case ENAMETOOLONG:
+ dwRet = ERROR_FILENAME_EXCED_RANGE;
+ break;
+ case ENOTDIR:
+ dwRet = ERROR_PATH_NOT_FOUND;
+ break;
+ case ENOENT:
+ dwRet = ERROR_FILE_NOT_FOUND;
+ break;
+ case EACCES:
+ case EPERM:
+ case EROFS:
+ case EISDIR:
+ dwRet = ERROR_ACCESS_DENIED;
+ break;
+ case EEXIST:
+ dwRet = ERROR_ALREADY_EXISTS;
+ break;
+#if !defined(_AIX)
+ // ENOTEMPTY is the same as EEXIST on AIX. Meaningful when involving directory operations
+ case ENOTEMPTY:
+ dwRet = ERROR_DIR_NOT_EMPTY;
+ break;
+#endif
+ case EBADF:
+ dwRet = ERROR_INVALID_HANDLE;
+ break;
+ case ENOMEM:
+ dwRet = ERROR_NOT_ENOUGH_MEMORY;
+ break;
+ case EBUSY:
+ dwRet = ERROR_BUSY;
+ break;
+ case ENOSPC:
+ case EDQUOT:
+ dwRet = ERROR_DISK_FULL;
+ break;
+ case ELOOP:
+ dwRet = ERROR_BAD_PATHNAME;
+ break;
+ case EIO:
+ dwRet = ERROR_WRITE_FAULT;
+ break;
+ case ERANGE:
+ dwRet = ERROR_BAD_PATHNAME;
+ break;
+ default:
+ ERROR("unexpected errno %d (%s); returning ERROR_GEN_FAILURE\n",
+ errno, strerror(errno));
+ dwRet = ERROR_GEN_FAILURE;
+ }
+
+ TRACE("errno = %d (%s), LastError = %d\n", errno, strerror(errno), dwRet);
+
+ return dwRet;
+}
+
+/*++
+Function:
+ DIRGetLastErrorFromErrno
+
+Convert errno into the appropriate win32 error and return it.
+--*/
+DWORD DIRGetLastErrorFromErrno( void )
+{
+ if (errno == ENOENT)
+ return ERROR_PATH_NOT_FOUND;
+ else
+ return FILEGetLastErrorFromErrno();
+}
+
+
+/*++
+Function:
+ CopyFileA
+
+See MSDN doc.
+
+Notes:
+ There are several (most) error paths here that do not call SetLastError().
+This is because we know that CreateFile, ReadFile, and WriteFile will do so,
+and will have a much better idea of the specific error.
+--*/
+BOOL
+PALAPI
+CopyFileA(
+ IN LPCSTR lpExistingFileName,
+ IN LPCSTR lpNewFileName,
+ IN BOOL bFailIfExists)
+{
+ CPalThread *pThread;
+ HANDLE hSource = INVALID_HANDLE_VALUE;
+ HANDLE hDest = INVALID_HANDLE_VALUE;
+ DWORD dwDestCreationMode;
+ BOOL bGood = FALSE;
+ DWORD dwSrcFileAttributes;
+ struct stat SrcFileStats;
+
+ LPSTR lpUnixPath = NULL;
+ const int buffer_size = 16*1024;
+ char *buffer = (char*)alloca(buffer_size);
+ DWORD bytes_read;
+ DWORD bytes_written;
+ int permissions;
+
+
+ PERF_ENTRY(CopyFileA);
+ ENTRY("CopyFileA(lpExistingFileName=%p (%s), lpNewFileName=%p (%s), bFailIfExists=%d)\n",
+ lpExistingFileName?lpExistingFileName:"NULL",
+ lpExistingFileName?lpExistingFileName:"NULL",
+ lpNewFileName?lpNewFileName:"NULL",
+ lpNewFileName?lpNewFileName:"NULL", bFailIfExists);
+
+ pThread = InternalGetCurrentThread();
+ if ( bFailIfExists )
+ {
+ dwDestCreationMode = CREATE_NEW;
+ }
+ else
+ {
+ dwDestCreationMode = CREATE_ALWAYS;
+ }
+
+ hSource = CreateFileA( lpExistingFileName,
+ GENERIC_READ,
+ FILE_SHARE_READ,
+ NULL,
+ OPEN_EXISTING,
+ 0,
+ NULL );
+
+ if ( hSource == INVALID_HANDLE_VALUE )
+ {
+ ERROR("CreateFileA failed for %s\n", lpExistingFileName);
+ goto done;
+ }
+
+ /* Need to preserve the file attributes */
+ dwSrcFileAttributes = GetFileAttributes(lpExistingFileName);
+ if (dwSrcFileAttributes == 0xffffffff)
+ {
+ ERROR("GetFileAttributes failed for %s\n", lpExistingFileName);
+ goto done;
+ }
+
+ /* Need to preserve the owner/group and chmod() flags */
+ lpUnixPath = strdup(lpExistingFileName);
+ if ( lpUnixPath == NULL )
+ {
+ ERROR("strdup() failed\n");
+ pThread->SetLastError(FILEGetLastErrorFromErrno());
+ goto done;
+ }
+ FILEDosToUnixPathA(lpUnixPath);
+ if (stat (lpUnixPath, &SrcFileStats) == -1)
+ {
+ ERROR("stat() failed for %s\n", lpExistingFileName);
+ pThread->SetLastError(FILEGetLastErrorFromErrnoAndFilename(lpUnixPath));
+ goto done;
+ }
+
+ hDest = CreateFileA( lpNewFileName,
+ GENERIC_WRITE,
+ FILE_SHARE_READ,
+ NULL,
+ dwDestCreationMode,
+ 0,
+ NULL );
+
+ if ( hDest == INVALID_HANDLE_VALUE )
+ {
+ ERROR("CreateFileA failed for %s\n", lpNewFileName);
+ goto done;
+ }
+
+ free(lpUnixPath);
+ lpUnixPath = strdup(lpNewFileName);
+ if ( lpUnixPath == NULL )
+ {
+ ERROR("strdup() failed\n");
+ pThread->SetLastError(FILEGetLastErrorFromErrno());
+ goto done;
+ }
+ FILEDosToUnixPathA( lpUnixPath );
+
+
+ // We don't set file attributes in CreateFile. The only attribute
+ // that is reflected on disk in Unix is read-only, and we set that
+ // here.
+ permissions = (S_IRWXU | S_IRWXG | S_IRWXO);
+ if ((dwSrcFileAttributes & FILE_ATTRIBUTE_READONLY) != 0)
+ {
+ permissions &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
+ }
+
+ /* Make sure the new file has the same chmod() flags. */
+ if (chmod(lpUnixPath, SrcFileStats.st_mode & permissions) == -1)
+ {
+ WARN ("chmod() failed to set mode 0x%x on new file\n",
+ SrcFileStats.st_mode & permissions);
+ pThread->SetLastError(FILEGetLastErrorFromErrnoAndFilename(lpUnixPath));
+ goto done;
+ }
+
+ while( (bGood = ReadFile( hSource, buffer, buffer_size, &bytes_read, NULL ))
+ && bytes_read > 0 )
+ {
+ bGood = ( WriteFile( hDest, buffer, bytes_read, &bytes_written, NULL )
+ && bytes_written == bytes_read);
+ if (!bGood) break;
+ }
+
+ if (!bGood)
+ {
+ ERROR("Copy failed\n");
+
+ if ( !CloseHandle(hDest) ||
+ !DeleteFileA(lpNewFileName) )
+ {
+ ERROR("Unable to clean up partial copy\n");
+ }
+ hDest = INVALID_HANDLE_VALUE;
+
+ goto done;
+ }
+
+done:
+
+ if ( hSource != INVALID_HANDLE_VALUE )
+ {
+ CloseHandle( hSource );
+ }
+ if ( hDest != INVALID_HANDLE_VALUE )
+ {
+ CloseHandle( hDest );
+ }
+ if (lpUnixPath)
+ {
+ free(lpUnixPath);
+ }
+
+ LOGEXIT("CopyFileA returns BOOL %d\n", bGood);
+ PERF_EXIT(CopyFileA);
+ return bGood;
+}
+
+
+/*++
+Function:
+ SetFileAttributesA
+
+Notes:
+ Used for setting read-only attribute on file only.
+
+--*/
+BOOL
+PALAPI
+SetFileAttributesA(
+ IN LPCSTR lpFileName,
+ IN DWORD dwFileAttributes)
+{
+ CPalThread *pThread;
+ struct stat stat_data;
+ mode_t new_mode;
+
+ DWORD dwLastError = 0;
+ BOOL bRet = FALSE;
+ LPSTR unixFileName = NULL;
+
+ PERF_ENTRY(SetFileAttributesA);
+ ENTRY("SetFileAttributesA(lpFileName=%p (%s), dwFileAttributes=%#x)\n",
+ lpFileName?lpFileName:"NULL",
+ lpFileName?lpFileName:"NULL", dwFileAttributes);
+
+ pThread = InternalGetCurrentThread();
+
+ /* Windows behavior for SetFileAttributes is that any valid attributes
+ are set on a file and any invalid attributes are ignored. SetFileAttributes
+ returns success and does not set an error even if some or all of the
+ attributes are invalid. If all the attributes are invalid, SetFileAttributes
+ sets a file's attribute to NORMAL. */
+
+ /* If dwFileAttributes does not contain READONLY or NORMAL, set it to NORMAL
+ and print a warning message. */
+ if ( !(dwFileAttributes & (FILE_ATTRIBUTE_READONLY |FILE_ATTRIBUTE_NORMAL)) )
+ {
+ dwFileAttributes = FILE_ATTRIBUTE_NORMAL;
+ WARN("dwFileAttributes(%#x) contains attributes that are either not supported "
+ "or cannot be set via SetFileAttributes.\n");
+ }
+
+ if ( (dwFileAttributes & FILE_ATTRIBUTE_NORMAL) &&
+ (dwFileAttributes != FILE_ATTRIBUTE_NORMAL) )
+ {
+ WARN("Ignoring FILE_ATTRIBUTE_NORMAL -- it must be used alone\n");
+ }
+
+ if (lpFileName == NULL)
+ {
+ dwLastError = ERROR_FILE_NOT_FOUND;
+ goto done;
+ }
+
+ if ((unixFileName = strdup(lpFileName)) == NULL)
+ {
+ ERROR("strdup() failed\n");
+ dwLastError = ERROR_NOT_ENOUGH_MEMORY;
+ goto done;
+ }
+
+ FILEDosToUnixPathA( unixFileName );
+ if ( stat(unixFileName, &stat_data) != 0 )
+ {
+ TRACE("stat failed on %s; errno is %d (%s)\n",
+ unixFileName, errno, strerror(errno));
+ dwLastError = FILEGetLastErrorFromErrnoAndFilename(unixFileName);
+ goto done;
+ }
+
+ new_mode = stat_data.st_mode;
+ TRACE("st_mode is %#x\n", new_mode);
+
+ /* if we can't do GetFileAttributes on it, don't do SetFileAttributes */
+ if ( !(new_mode & S_IFREG) && !(new_mode & S_IFDIR) )
+ {
+ ERROR("Not a regular file or directory, S_IFMT is %#x\n",
+ new_mode & S_IFMT);
+ dwLastError = ERROR_ACCESS_DENIED;
+ goto done;
+ }
+
+ /* set or unset the "read-only" attribute */
+ if (dwFileAttributes & FILE_ATTRIBUTE_READONLY)
+ {
+ /* remove the write bit from everybody */
+ new_mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH);
+ }
+ else
+ {
+ /* give write permission to the owner if the owner
+ * already has read permission */
+ if ( new_mode & S_IRUSR )
+ {
+ new_mode |= S_IWUSR;
+ }
+ }
+ TRACE("new mode is %#x\n", new_mode);
+
+ bRet = TRUE;
+ if ( new_mode != stat_data.st_mode )
+ {
+ if ( chmod(unixFileName, new_mode) != 0 )
+ {
+ ERROR("chmod(%s, %#x) failed\n", unixFileName, new_mode);
+ dwLastError = FILEGetLastErrorFromErrnoAndFilename(unixFileName);
+ bRet = FALSE;
+ }
+ }
+
+done:
+ if (dwLastError)
+ {
+ pThread->SetLastError(dwLastError);
+ }
+
+ free(unixFileName);
+
+ LOGEXIT("SetFileAttributesA returns BOOL %d\n", bRet);
+ PERF_EXIT(SetFileAttributesA);
+ return bRet;
+}
+
+PAL_ERROR
+CorUnix::InternalCreatePipe(
+ CPalThread *pThread,
+ HANDLE *phReadPipe,
+ HANDLE *phWritePipe,
+ LPSECURITY_ATTRIBUTES lpPipeAttributes,
+ DWORD nSize
+ )
+{
+ PAL_ERROR palError = NO_ERROR;
+ IPalObject *pReadFileObject = NULL;
+ IPalObject *pReadRegisteredFile = NULL;
+ IPalObject *pWriteFileObject = NULL;
+ IPalObject *pWriteRegisteredFile = NULL;
+ IDataLock *pDataLock = NULL;
+ CFileProcessLocalData *pLocalData = NULL;
+ CObjectAttributes oaFile(NULL, lpPipeAttributes);
+
+ int readWritePipeDes[2] = {-1, -1};
+
+ if ((phReadPipe == NULL) || (phWritePipe == NULL))
+ {
+ ERROR("One of the two parameters hReadPipe(%p) and hWritePipe(%p) is Null\n",phReadPipe,phWritePipe);
+ palError = ERROR_INVALID_PARAMETER;
+ goto InternalCreatePipeExit;
+ }
+
+ if ((lpPipeAttributes == NULL) ||
+ (lpPipeAttributes->bInheritHandle == FALSE) ||
+ (lpPipeAttributes->lpSecurityDescriptor != NULL))
+ {
+ ASSERT("invalid security attributes!\n");
+ palError = ERROR_INVALID_PARAMETER;
+ goto InternalCreatePipeExit;
+ }
+
+ if (pipe(readWritePipeDes) == -1)
+ {
+ ERROR("pipe() call failed errno:%d (%s) \n", errno, strerror(errno));
+ palError = ERROR_INTERNAL_ERROR;
+ goto InternalCreatePipeExit;
+ }
+
+ /* enable close-on-exec for both pipes; if one gets passed to CreateProcess
+ it will be "uncloseonexeced" in order to be inherited */
+ if(-1 == fcntl(readWritePipeDes[0],F_SETFD,1))
+ {
+ ASSERT("can't set close-on-exec flag; fcntl() failed. errno is %d "
+ "(%s)\n", errno, strerror(errno));
+ palError = ERROR_INTERNAL_ERROR;
+ goto InternalCreatePipeExit;
+ }
+ if(-1 == fcntl(readWritePipeDes[1],F_SETFD,1))
+ {
+ ASSERT("can't set close-on-exec flag; fcntl() failed. errno is %d "
+ "(%s)\n", errno, strerror(errno));
+ palError = ERROR_INTERNAL_ERROR;
+ goto InternalCreatePipeExit;
+ }
+
+ //
+ // Setup the object for the read end of the pipe
+ //
+
+ palError = g_pObjectManager->AllocateObject(
+ pThread,
+ &otFile,
+ &oaFile,
+ &pReadFileObject
+ );
+
+ if (NO_ERROR != palError)
+ {
+ goto InternalCreatePipeExit;
+ }
+
+ palError = pReadFileObject->GetProcessLocalData(
+ pThread,
+ WriteLock,
+ &pDataLock,
+ reinterpret_cast<void**>(&pLocalData)
+ );
+
+ if (NO_ERROR != palError)
+ {
+ goto InternalCreatePipeExit;
+ }
+
+ pLocalData->inheritable = TRUE;
+ pLocalData->open_flags = O_RDONLY;
+
+ //
+ // After storing the file descriptor in the object's local data
+ // we want to clear it from the array to prevent a possible double
+ // close if an error occurs.
+ //
+
+ pLocalData->unix_fd = readWritePipeDes[0];
+ readWritePipeDes[0] = -1;
+
+ pDataLock->ReleaseLock(pThread, TRUE);
+ pDataLock = NULL;
+
+ //
+ // Setup the object for the write end of the pipe
+ //
+
+ palError = g_pObjectManager->AllocateObject(
+ pThread,
+ &otFile,
+ &oaFile,
+ &pWriteFileObject
+ );
+
+ if (NO_ERROR != palError)
+ {
+ goto InternalCreatePipeExit;
+ }
+
+ palError = pWriteFileObject->GetProcessLocalData(
+ pThread,
+ WriteLock,
+ &pDataLock,
+ reinterpret_cast<void**>(&pLocalData)
+ );
+
+ if (NO_ERROR != palError)
+ {
+ goto InternalCreatePipeExit;
+ }
+
+ pLocalData->inheritable = TRUE;
+ pLocalData->open_flags = O_WRONLY;
+
+ //
+ // After storing the file descriptor in the object's local data
+ // we want to clear it from the array to prevent a possible double
+ // close if an error occurs.
+ //
+
+ pLocalData->unix_fd = readWritePipeDes[1];
+ readWritePipeDes[1] = -1;
+
+ pDataLock->ReleaseLock(pThread, TRUE);
+ pDataLock = NULL;
+
+ //
+ // Register the pipe objects
+ //
+
+ palError = g_pObjectManager->RegisterObject(
+ pThread,
+ pReadFileObject,
+ &aotFile,
+ GENERIC_READ,
+ phReadPipe,
+ &pReadRegisteredFile
+ );
+
+ //
+ // pReadFileObject is invalidated by the call to RegisterObject, so NULL it
+ // out here to ensure that we don't try to release a reference on
+ // it down the line.
+ //
+
+ pReadFileObject = NULL;
+
+ if (NO_ERROR != palError)
+ {
+ goto InternalCreatePipeExit;
+ }
+
+ palError = g_pObjectManager->RegisterObject(
+ pThread,
+ pWriteFileObject,
+ &aotFile,
+ GENERIC_WRITE,
+ phWritePipe,
+ &pWriteRegisteredFile
+ );
+
+ //
+ // pWriteFileObject is invalidated by the call to RegisterObject, so NULL it
+ // out here to ensure that we don't try to release a reference on
+ // it down the line.
+ //
+
+ pWriteFileObject = NULL;
+
+InternalCreatePipeExit:
+
+ if (NO_ERROR != palError)
+ {
+ if (-1 != readWritePipeDes[0])
+ {
+ close(readWritePipeDes[0]);
+ }
+
+ if (-1 != readWritePipeDes[1])
+ {
+ close(readWritePipeDes[1]);
+ }
+ }
+
+ if (NULL != pReadFileObject)
+ {
+ pReadFileObject->ReleaseReference(pThread);
+ }
+
+ if (NULL != pReadRegisteredFile)
+ {
+ pReadRegisteredFile->ReleaseReference(pThread);
+ }
+
+ if (NULL != pWriteFileObject)
+ {
+ pWriteFileObject->ReleaseReference(pThread);
+ }
+
+ if (NULL != pWriteRegisteredFile)
+ {
+ pWriteRegisteredFile->ReleaseReference(pThread);
+ }
+
+ return palError;
+}
+
+/*++
+Function:
+ CreatePipe
+
+See MSDN doc.
+--*/
+PALIMPORT
+BOOL
+PALAPI
+CreatePipe(
+ OUT PHANDLE hReadPipe,
+ OUT PHANDLE hWritePipe,
+ IN LPSECURITY_ATTRIBUTES lpPipeAttributes,
+ IN DWORD nSize)
+{
+ PAL_ERROR palError;
+ CPalThread *pThread;
+
+ PERF_ENTRY(CreatePipe);
+ ENTRY("CreatePipe(hReadPipe:%p, hWritePipe:%p, lpPipeAttributes:%p, nSize:%d\n",
+ hReadPipe, hWritePipe, lpPipeAttributes, nSize);
+
+ pThread = InternalGetCurrentThread();
+
+ palError = InternalCreatePipe(
+ pThread,
+ hReadPipe,
+ hWritePipe,
+ lpPipeAttributes,
+ nSize
+ );
+
+ if (NO_ERROR != palError)
+ {
+ pThread->SetLastError(palError);
+ }
+
+ LOGEXIT("CreatePipe return %s\n", NO_ERROR == palError ? "TRUE":"FALSE");
+ PERF_EXIT(CreatePipe);
+ return NO_ERROR == palError;
+}
+
+PAL_ERROR
+CorUnix::InternalLockFile(
+ CPalThread *pThread,
+ HANDLE hFile,
+ DWORD dwFileOffsetLow,
+ DWORD dwFileOffsetHigh,
+ DWORD nNumberOfBytesToLockLow,
+ DWORD nNumberOfBytesToLockHigh
+ )
+{
+ PAL_ERROR palError = NO_ERROR;
+ IPalObject *pFileObject = NULL;
+ CFileProcessLocalData *pLocalData = NULL;
+ IDataLock *pLocalDataLock = NULL;
+
+ if (INVALID_HANDLE_VALUE == hFile)
+ {
+ ERROR( "Invalid file handle\n" );
+ palError = ERROR_INVALID_HANDLE;
+ goto InternalLockFileExit;
+ }
+
+ palError = g_pObjectManager->ReferenceObjectByHandle(
+ pThread,
+ hFile,
+ &aotFile,
+ GENERIC_READ,
+ &pFileObject
+ );
+
+ if (NO_ERROR != palError)
+ {
+ goto InternalLockFileExit;
+ }
+
+ palError = pFileObject->GetProcessLocalData(
+ pThread,
+ ReadLock,
+ &pLocalDataLock,
+ reinterpret_cast<void**>(&pLocalData)
+ );
+
+ if (NO_ERROR != palError)
+ {
+ goto InternalLockFileExit;
+ }
+
+ if (NULL != pLocalData->pLockController)
+ {
+ palError = pLocalData->pLockController->CreateFileLock(
+ pThread,
+ dwFileOffsetLow,
+ dwFileOffsetHigh,
+ nNumberOfBytesToLockLow,
+ nNumberOfBytesToLockHigh,
+ IFileLockController::ExclusiveFileLock,
+ IFileLockController::FailImmediately
+ );
+ }
+ else
+ {
+ //
+ // This isn't a lockable file (e.g., it may be a pipe)
+ //
+
+ palError = ERROR_ACCESS_DENIED;
+ goto InternalLockFileExit;
+ }
+
+InternalLockFileExit:
+
+ if (NULL != pLocalDataLock)
+ {
+ pLocalDataLock->ReleaseLock(pThread, FALSE);
+ }
+
+ if (NULL != pFileObject)
+ {
+ pFileObject->ReleaseReference(pThread);
+ }
+
+ return palError;
+}
+
+
+/*++
+Function:
+ LockFile
+
+See MSDN doc.
+--*/
+PALIMPORT
+BOOL
+PALAPI
+LockFile(HANDLE hFile,
+ DWORD dwFileOffsetLow,
+ DWORD dwFileOffsetHigh,
+ DWORD nNumberOfBytesToLockLow,
+ DWORD nNumberOfBytesToLockHigh)
+{
+ CPalThread *pThread;
+ PAL_ERROR palError = NO_ERROR;
+
+ PERF_ENTRY(LockFile);
+ ENTRY("LockFile(hFile:%p, offsetLow:%u, offsetHigh:%u, nbBytesLow:%u,"
+ " nbBytesHigh:%u\n", hFile, dwFileOffsetLow, dwFileOffsetHigh,
+ nNumberOfBytesToLockLow, nNumberOfBytesToLockHigh);
+
+ pThread = InternalGetCurrentThread();
+
+ palError = InternalLockFile(
+ pThread,
+ hFile,
+ dwFileOffsetLow,
+ dwFileOffsetHigh,
+ nNumberOfBytesToLockLow,
+ nNumberOfBytesToLockHigh
+ );
+
+ if (NO_ERROR != palError)
+ {
+ pThread->SetLastError(palError);
+ }
+
+ LOGEXIT("LockFile returns %s\n", NO_ERROR == palError ? "TRUE":"FALSE");
+ PERF_EXIT(LockFile);
+ return NO_ERROR == palError;
+}
+
+PAL_ERROR
+CorUnix::InternalUnlockFile(
+ CPalThread *pThread,
+ HANDLE hFile,
+ DWORD dwFileOffsetLow,
+ DWORD dwFileOffsetHigh,
+ DWORD nNumberOfBytesToUnlockLow,
+ DWORD nNumberOfBytesToUnlockHigh
+ )
+{
+ PAL_ERROR palError = NO_ERROR;
+ IPalObject *pFileObject = NULL;
+ CFileProcessLocalData *pLocalData = NULL;
+ IDataLock *pLocalDataLock = NULL;
+
+ if (INVALID_HANDLE_VALUE == hFile)
+ {
+ ERROR( "Invalid file handle\n" );
+ palError = ERROR_INVALID_HANDLE;
+ goto InternalUnlockFileExit;
+ }
+
+ palError = g_pObjectManager->ReferenceObjectByHandle(
+ pThread,
+ hFile,
+ &aotFile,
+ GENERIC_READ,
+ &pFileObject
+ );
+
+ if (NO_ERROR != palError)
+ {
+ goto InternalUnlockFileExit;
+ }
+
+ palError = pFileObject->GetProcessLocalData(
+ pThread,
+ ReadLock,
+ &pLocalDataLock,
+ reinterpret_cast<void**>(&pLocalData)
+ );
+
+ if (NO_ERROR != palError)
+ {
+ goto InternalUnlockFileExit;
+ }
+
+ if (NULL != pLocalData->pLockController)
+ {
+ palError = pLocalData->pLockController->ReleaseFileLock(
+ pThread,
+ dwFileOffsetLow,
+ dwFileOffsetHigh,
+ nNumberOfBytesToUnlockLow,
+ nNumberOfBytesToUnlockHigh
+ );
+ }
+ else
+ {
+ //
+ // This isn't a lockable file (e.g., it may be a pipe)
+ //
+
+ palError = ERROR_ACCESS_DENIED;
+ goto InternalUnlockFileExit;
+ }
+
+InternalUnlockFileExit:
+
+ if (NULL != pLocalDataLock)
+ {
+ pLocalDataLock->ReleaseLock(pThread, FALSE);
+ }
+
+ if (NULL != pFileObject)
+ {
+ pFileObject->ReleaseReference(pThread);
+ }
+
+ return palError;
+}
+
+/*++
+Function:
+ UnlockFile
+
+See MSDN doc.
+--*/
+PALIMPORT
+BOOL
+PALAPI
+UnlockFile(HANDLE hFile,
+ DWORD dwFileOffsetLow,
+ DWORD dwFileOffsetHigh,
+ DWORD nNumberOfBytesToUnlockLow,
+ DWORD nNumberOfBytesToUnlockHigh)
+{
+ CPalThread *pThread;
+ PAL_ERROR palError = NO_ERROR;
+
+ PERF_ENTRY(UnlockFile);
+ ENTRY("UnlockFile(hFile:%p, offsetLow:%u, offsetHigh:%u, nbBytesLow:%u,"
+ "nbBytesHigh:%u\n", hFile, dwFileOffsetLow, dwFileOffsetHigh,
+ nNumberOfBytesToUnlockLow, nNumberOfBytesToUnlockHigh);
+
+ pThread = InternalGetCurrentThread();
+
+ palError = InternalUnlockFile(
+ pThread,
+ hFile,
+ dwFileOffsetLow,
+ dwFileOffsetHigh,
+ nNumberOfBytesToUnlockLow,
+ nNumberOfBytesToUnlockHigh
+ );
+
+ if (NO_ERROR != palError)
+ {
+ pThread->SetLastError(palError);
+ }
+
+ LOGEXIT("UnlockFile returns %s\n", NO_ERROR == palError ? "TRUE" : "FALSE");
+ PERF_EXIT(UnlockFile);
+ return NO_ERROR == palError;
+}
+
+/*++
+init_std_handle [static]
+
+utility function for FILEInitStdHandles. do the work that is common to all
+three standard handles
+
+Parameters:
+ HANDLE pStd : Defines which standard handle to assign
+ FILE *stream : file stream to associate to handle
+
+Return value:
+ handle for specified stream, or INVALID_HANDLE_VALUE on failure
+--*/
+static HANDLE init_std_handle(HANDLE * pStd, FILE *stream)
+{
+ CPalThread *pThread = InternalGetCurrentThread();
+ PAL_ERROR palError = NO_ERROR;
+ IPalObject *pFileObject = NULL;
+ IPalObject *pRegisteredFile = NULL;
+ IDataLock *pDataLock = NULL;
+ CFileProcessLocalData *pLocalData = NULL;
+ IFileLockController *pLockController = NULL;
+ CObjectAttributes oa;
+
+ HANDLE hFile = INVALID_HANDLE_VALUE;
+ int new_fd = -1;
+
+ /* duplicate the FILE *, so that we can fclose() in FILECloseHandle without
+ closing the original */
+ new_fd = dup(fileno(stream));
+ if(-1 == new_fd)
+ {
+ ERROR("dup() failed; errno is %d (%s)\n", errno, strerror(errno));
+ goto done;
+ }
+
+ palError = g_pObjectManager->AllocateObject(
+ pThread,
+ &otFile,
+ &oa,
+ &pFileObject
+ );
+
+ if (NO_ERROR != palError)
+ {
+ goto done;
+ }
+
+ palError = pFileObject->GetProcessLocalData(
+ pThread,
+ WriteLock,
+ &pDataLock,
+ reinterpret_cast<void**>(&pLocalData)
+ );
+
+ if (NO_ERROR != palError)
+ {
+ goto done;
+ }
+
+ pLocalData->inheritable = TRUE;
+ pLocalData->unix_fd = new_fd;
+ pLocalData->dwDesiredAccess = 0;
+ pLocalData->open_flags = 0;
+ pLocalData->open_flags_deviceaccessonly = FALSE;
+
+ //
+ // Transfer the lock controller reference from our local variable
+ // to the local file data
+ //
+
+ pLocalData->pLockController = pLockController;
+ pLockController = NULL;
+
+ //
+ // We've finished initializing our local data, so release that lock
+ //
+
+ pDataLock->ReleaseLock(pThread, TRUE);
+ pDataLock = NULL;
+
+ palError = g_pObjectManager->RegisterObject(
+ pThread,
+ pFileObject,
+ &aotFile,
+ 0,
+ &hFile,
+ &pRegisteredFile
+ );
+
+ //
+ // pFileObject is invalidated by the call to RegisterObject, so NULL it
+ // out here to ensure that we don't try to release a reference on
+ // it down the line.
+ //
+
+ pFileObject = NULL;
+
+done:
+
+ if (NULL != pLockController)
+ {
+ pLockController->ReleaseController();
+ }
+
+ if (NULL != pDataLock)
+ {
+ pDataLock->ReleaseLock(pThread, TRUE);
+ }
+
+ if (NULL != pFileObject)
+ {
+ pFileObject->ReleaseReference(pThread);
+ }
+
+ if (NULL != pRegisteredFile)
+ {
+ pRegisteredFile->ReleaseReference(pThread);
+ }
+
+ if (NO_ERROR == palError)
+ {
+ *pStd = hFile;
+ }
+ else if (-1 != new_fd)
+ {
+ close(new_fd);
+ }
+
+ return hFile;
+}
+
+
+/*++
+FILEInitStdHandles
+
+Create handle objects for stdin, stdout and stderr
+
+(no parameters)
+
+Return value:
+ TRUE on success, FALSE on failure
+--*/
+BOOL FILEInitStdHandles(void)
+{
+ HANDLE stdin_handle;
+ HANDLE stdout_handle;
+ HANDLE stderr_handle;
+
+ TRACE("creating handle objects for stdin, stdout, stderr\n");
+
+ stdin_handle = init_std_handle(&pStdIn, stdin);
+ if(INVALID_HANDLE_VALUE == stdin_handle)
+ {
+ ERROR("failed to create stdin handle\n");
+ goto fail;
+ }
+
+ stdout_handle = init_std_handle(&pStdOut, stdout);
+ if(INVALID_HANDLE_VALUE == stdout_handle)
+ {
+ ERROR("failed to create stdout handle\n");
+ CloseHandle(stdin_handle);
+ goto fail;
+ }
+
+ stderr_handle = init_std_handle(&pStdErr, stderr);
+ if(INVALID_HANDLE_VALUE == stderr_handle)
+ {
+ ERROR("failed to create stderr handle\n");
+ CloseHandle(stdin_handle);
+ CloseHandle(stdout_handle);
+ goto fail;
+ }
+ return TRUE;
+
+fail:
+ pStdIn = INVALID_HANDLE_VALUE;
+ pStdOut = INVALID_HANDLE_VALUE;
+ pStdErr = INVALID_HANDLE_VALUE;
+ return FALSE;
+}
+
+/*++
+FILECleanupStdHandles
+
+Remove all regions, locked by a file pointer, from shared memory
+
+(no parameters)
+
+--*/
+void FILECleanupStdHandles(void)
+{
+ HANDLE stdin_handle;
+ HANDLE stdout_handle;
+ HANDLE stderr_handle;
+
+ TRACE("closing standard handles\n");
+ stdin_handle = pStdIn;
+ stdout_handle = pStdOut;
+ stderr_handle = pStdErr;
+
+ pStdIn = INVALID_HANDLE_VALUE;
+ pStdOut = INVALID_HANDLE_VALUE;
+ pStdErr = INVALID_HANDLE_VALUE;
+
+ if (stdin_handle != INVALID_HANDLE_VALUE)
+ {
+ CloseHandle(stdin_handle);
+ }
+
+ if (stdout_handle != INVALID_HANDLE_VALUE)
+ {
+ CloseHandle(stdout_handle);
+ }
+
+ if (stderr_handle != INVALID_HANDLE_VALUE)
+ {
+ CloseHandle(stderr_handle);
+ }
+}
+
+/*++
+Function:
+ GetFileInformationByHandle
+
+See MSDN doc.
+--*/
+BOOL
+PALAPI
+GetFileInformationByHandle(
+ IN HANDLE hFile,
+ OUT LPBY_HANDLE_FILE_INFORMATION lpFileInformation)
+{
+ CPalThread *pThread;
+ BOOL bRet = FALSE;
+ DWORD dwLastError = 0;
+
+ IPalObject *pFileObject = NULL;
+ CFileProcessLocalData *pLocalData = NULL;
+ IDataLock *pLocalDataLock = NULL;
+
+ DWORD dwAttr = 0;
+ struct stat stat_data;
+
+ PERF_ENTRY(GetFileInformationByHandle);
+ ENTRY("GetFileInformationByHandle(hFile=%p, lpFileInformation=%p)\n",
+ hFile, lpFileInformation);
+
+ pThread = InternalGetCurrentThread();
+
+ if (INVALID_HANDLE_VALUE == hFile)
+ {
+ ERROR( "Invalid file handle\n" );
+ dwLastError = ERROR_INVALID_HANDLE;
+ goto done;
+ }
+
+ dwLastError = g_pObjectManager->ReferenceObjectByHandle(
+ pThread,
+ hFile,
+ &aotFile,
+ GENERIC_READ,
+ &pFileObject
+ );
+
+ if (NO_ERROR != dwLastError)
+ {
+ goto done;
+ }
+
+ dwLastError = pFileObject->GetProcessLocalData(
+ pThread,
+ ReadLock,
+ &pLocalDataLock,
+ reinterpret_cast<void**>(&pLocalData)
+ );
+
+ if (NO_ERROR != dwLastError)
+ {
+ goto done;
+ }
+
+ if ( fstat(pLocalData->unix_fd, &stat_data) != 0 )
+ {
+ if ((dwLastError = FILEGetLastErrorFromErrno()) == ERROR_INTERNAL_ERROR)
+ {
+ ASSERT("fstat() not expected to fail with errno:%d (%s)\n",
+ errno, strerror(errno));
+ }
+ goto done;
+ }
+
+ if ( (stat_data.st_mode & S_IFMT) == S_IFDIR )
+ {
+ dwAttr |= FILE_ATTRIBUTE_DIRECTORY;
+ }
+ else if ( (stat_data.st_mode & S_IFMT) != S_IFREG )
+ {
+ ERROR("Not a regular file or directory, S_IFMT is %#x\n",
+ stat_data.st_mode & S_IFMT);
+ dwLastError = ERROR_ACCESS_DENIED;
+ goto done;
+ }
+
+ if ( UTIL_IsReadOnlyBitsSet( &stat_data ) )
+ {
+ dwAttr |= FILE_ATTRIBUTE_READONLY;
+ }
+
+ /* finally, if nothing is set... */
+ if ( dwAttr == 0 )
+ {
+ dwAttr = FILE_ATTRIBUTE_NORMAL;
+ }
+
+ lpFileInformation->dwFileAttributes = dwAttr;
+
+ /* get the file times */
+ lpFileInformation->ftCreationTime =
+ FILEUnixTimeToFileTime( stat_data.st_ctime,
+ ST_CTIME_NSEC(&stat_data) );
+ lpFileInformation->ftLastAccessTime =
+ FILEUnixTimeToFileTime( stat_data.st_atime,
+ ST_ATIME_NSEC(&stat_data) );
+ lpFileInformation->ftLastWriteTime =
+ FILEUnixTimeToFileTime( stat_data.st_mtime,
+ ST_MTIME_NSEC(&stat_data) );
+
+ lpFileInformation->dwVolumeSerialNumber = stat_data.st_dev;
+
+ /* Get the file size. GetFileSize is not used because it gets the
+ size of an already-open file */
+ lpFileInformation->nFileSizeLow = (DWORD) stat_data.st_size;
+#if SIZEOF_OFF_T > 4
+ lpFileInformation->nFileSizeHigh = (DWORD)(stat_data.st_size >> 32);
+#else
+ lpFileInformation->nFileSizeHigh = 0;
+#endif
+
+ lpFileInformation->nNumberOfLinks = stat_data.st_nlink;
+ lpFileInformation->nFileIndexHigh = 0;
+ lpFileInformation->nFileIndexLow = stat_data.st_ino;
+
+ bRet = TRUE;
+
+done:
+ if (NULL != pLocalDataLock)
+ {
+ pLocalDataLock->ReleaseLock(pThread, FALSE);
+ }
+
+ if (NULL != pFileObject)
+ {
+ pFileObject->ReleaseReference(pThread);
+ }
+
+ if (dwLastError) pThread->SetLastError(dwLastError);
+
+ LOGEXIT("GetFileInformationByHandle returns BOOL %d\n", bRet);
+ PERF_EXIT(GetFileInformationByHandle);
+ return bRet;
+}
diff --git a/src/pal/src/file/filetime.cpp b/src/pal/src/file/filetime.cpp
new file mode 100644
index 0000000000..a8666b0dff
--- /dev/null
+++ b/src/pal/src/file/filetime.cpp
@@ -0,0 +1,788 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ filetime.cpp
+
+Abstract:
+
+ Implementation of the file WIN API related to file time.
+
+Notes:
+
+One very important thing to note is that on BSD systems, the stat structure
+stores nanoseconds for the time-related fields. This is implemented by
+replacing the time_t fields st_atime, st_mtime, and st_ctime by timespec
+structures, instead named st_atimespec, st_mtimespec, and st_ctimespec.
+
+However, if _POSIX_SOURCE is defined, the fields are time_t values and use
+their POSIX names. For compatibility purposes, when _POSIX_SOURCE is NOT
+defined, the time-related fields are defined in sys/stat.h as:
+
+#ifndef _POSIX_SOURCE
+#define st_atime st_atimespec.tv_sec
+#define st_mtime st_mtimespec.tv_sec
+#define st_ctime st_ctimespec.tv_sec
+#endif
+
+Furthermore, if _POSIX_SOURCE is defined, the structure still has
+additional fields for nanoseconds, named st_atimensec, st_mtimensec, and
+st_ctimensec.
+
+In the PAL, there is a configure check to see if the system supports
+nanoseconds for the time-related fields. This source file also sets macros
+so that STAT_ATIME_NSEC etc. will always refer to the appropriate field
+if it exists, and are defined as 0 otherwise.
+
+--
+
+Also note that there is no analog to "creation time" on Unix systems.
+Instead, we use the inode change time, which is set to the current time
+whenever mtime changes or when chmod, chown, etc. syscalls modify the
+file status.
+
+
+
+--*/
+
+#include "pal/corunix.hpp"
+#include "pal/dbgmsg.h"
+#include "pal/filetime.h"
+#include "pal/thread.hpp"
+#include "pal/file.hpp"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <utime.h>
+#include <time.h>
+
+#if HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif // HAVE_SYS_TIME_H
+
+using namespace CorUnix;
+
+SET_DEFAULT_DEBUG_CHANNEL(FILE);
+
+// In safemath.h, Template SafeInt uses macro _ASSERTE, which need to use variable
+// defdbgchan defined by SET_DEFAULT_DEBUG_CHANNEL. Therefore, the include statement
+// should be placed after the SET_DEFAULT_DEBUG_CHANNEL(FILE)
+#include <safemath.h>
+
+/* Magic number explanation:
+
+ To 1970:
+ Both epochs are Gregorian. 1970 - 1601 = 369. Assuming a leap
+ year every four years, 369 / 4 = 92. However, 1700, 1800, and 1900
+ were NOT leap years, so 89 leap years, 280 non-leap years.
+ 89 * 366 + 280 * 365 = 134744 days between epochs. Of course
+ 60 * 60 * 24 = 86400 seconds per day, so 134744 * 86400 =
+ 11644473600 = SECS_BETWEEN_1601_AND_1970_EPOCHS.
+
+ To 2001:
+ Again, both epochs are Gregorian. 2001 - 1601 = 400. Assuming a leap
+ year every four years, 400 / 4 = 100. However, 1700, 1800, and 1900
+ were NOT leap years (2000 was because it was divisible by 400), so
+ 97 leap years, 303 non-leap years.
+ 97 * 366 + 303 * 365 = 146097 days between epochs. 146097 * 86400 =
+ 12622780800 = SECS_BETWEEN_1601_AND_2001_EPOCHS.
+
+ This result is also confirmed in the MSDN documentation on how
+ to convert a time_t value to a win32 FILETIME.
+*/
+static const __int64 SECS_BETWEEN_1601_AND_1970_EPOCHS = 11644473600LL;
+static const __int64 SECS_TO_100NS = 10000000; /* 10^7 */
+
+#ifdef __APPLE__
+static const __int64 SECS_BETWEEN_1601_AND_2001_EPOCHS = 12622780800LL;
+#endif // __APPLE__
+
+/*++
+Function:
+ CompareFileTime
+
+See MSDN doc.
+--*/
+LONG
+PALAPI
+CompareFileTime(
+ IN CONST FILETIME *lpFileTime1,
+ IN CONST FILETIME *lpFileTime2)
+{
+ __int64 First;
+ __int64 Second;
+
+ long Ret;
+
+ PERF_ENTRY(CompareFileTime);
+ ENTRY("CompareFileTime(lpFileTime1=%p lpFileTime2=%p)\n",
+ lpFileTime1, lpFileTime2);
+
+ First = ((__int64)lpFileTime1->dwHighDateTime << 32) +
+ lpFileTime1->dwLowDateTime;
+ Second = ((__int64)lpFileTime2->dwHighDateTime << 32) +
+ lpFileTime2->dwLowDateTime;
+
+ if ( First < Second )
+ {
+ Ret = -1;
+ }
+ else if ( First > Second )
+ {
+ Ret = 1;
+ }
+ else
+ {
+ Ret = 0;
+ }
+
+ LOGEXIT("CompareFileTime returns LONG %ld\n", Ret);
+ PERF_EXIT(CompareFileTime);
+ return Ret;
+}
+
+
+
+/*++
+Function:
+ SetFileTime
+
+Notes: This function will drop one digit (radix 10) of precision from
+the supplied times, since Unix can set to the microsecond (at most, i.e.
+if the futimes() function is available).
+
+As noted in the file header, there is no analog to "creation time" on Unix
+systems, so the lpCreationTime argument to this function will always be
+ignored, and the inode change time will be set to the current time.
+--*/
+BOOL
+PALAPI
+SetFileTime(
+ IN HANDLE hFile,
+ IN CONST FILETIME *lpCreationTime,
+ IN CONST FILETIME *lpLastAccessTime,
+ IN CONST FILETIME *lpLastWriteTime)
+{
+ CPalThread *pThread;
+ PAL_ERROR palError = NO_ERROR;
+ const UINT64 MAX_FILETIMEVALUE = 0x8000000000000000LL;
+
+ PERF_ENTRY(SetFileTime);
+ ENTRY("SetFileTime(hFile=%p, lpCreationTime=%p, lpLastAccessTime=%p, "
+ "lpLastWriteTime=%p)\n", hFile, lpCreationTime, lpLastAccessTime,
+ lpLastWriteTime);
+
+ pThread = InternalGetCurrentThread();
+
+ /* validate filetime values */
+ if ( (lpCreationTime && (((UINT64)lpCreationTime->dwHighDateTime << 32) +
+ lpCreationTime->dwLowDateTime >= MAX_FILETIMEVALUE)) ||
+ (lpLastAccessTime && (((UINT64)lpLastAccessTime->dwHighDateTime << 32) +
+ lpLastAccessTime->dwLowDateTime >= MAX_FILETIMEVALUE)) ||
+ (lpLastWriteTime && (((UINT64)lpLastWriteTime->dwHighDateTime << 32) +
+ lpLastWriteTime->dwLowDateTime >= MAX_FILETIMEVALUE)))
+ {
+ pThread->SetLastError(ERROR_INVALID_HANDLE);
+ return FALSE;
+ }
+
+ palError = InternalSetFileTime(
+ pThread,
+ hFile,
+ lpCreationTime,
+ lpLastAccessTime,
+ lpLastWriteTime
+ );
+
+ if (NO_ERROR != palError)
+ {
+ pThread->SetLastError(palError);
+ }
+
+ LOGEXIT("SetFileTime returns BOOL %s\n", NO_ERROR == palError ? "TRUE":"FALSE");
+ PERF_EXIT(SetFileTime);
+ return NO_ERROR == palError;
+}
+
+PAL_ERROR
+CorUnix::InternalSetFileTime(
+ CPalThread *pThread,
+ IN HANDLE hFile,
+ IN CONST FILETIME *lpCreationTime,
+ IN CONST FILETIME *lpLastAccessTime,
+ IN CONST FILETIME *lpLastWriteTime)
+{
+ PAL_ERROR palError = NO_ERROR;
+ IPalObject *pFileObject = NULL;
+ CFileProcessLocalData *pLocalData = NULL;
+ IDataLock *pLocalDataLock = NULL;
+ struct timeval Times[2];
+ int fd;
+ long nsec;
+ struct stat stat_buf;
+
+ if (INVALID_HANDLE_VALUE == hFile)
+ {
+ ERROR( "Invalid file handle\n" );
+ palError = ERROR_INVALID_HANDLE;
+ goto InternalSetFileTimeExit;
+ }
+
+ palError = g_pObjectManager->ReferenceObjectByHandle(
+ pThread,
+ hFile,
+ &aotFile,
+ GENERIC_READ,
+ &pFileObject
+ );
+
+ if (NO_ERROR != palError)
+ {
+ goto InternalSetFileTimeExit;
+ }
+
+ palError = pFileObject->GetProcessLocalData(
+ pThread,
+ ReadLock,
+ &pLocalDataLock,
+ reinterpret_cast<void**>(&pLocalData)
+ );
+
+ if (NO_ERROR != palError)
+ {
+ goto InternalSetFileTimeExit;
+ }
+
+ if (lpCreationTime)
+ {
+ palError = ERROR_NOT_SUPPORTED;
+ goto InternalSetFileTimeExit;
+ }
+
+ if( !lpLastAccessTime && !lpLastWriteTime )
+ {
+ // if both pointers are NULL, the function simply returns.
+ goto InternalSetFileTimeExit;
+ }
+ else if( !lpLastAccessTime || !lpLastWriteTime )
+ {
+ // if either pointer is NULL, fstat will need to be called.
+ fd = pLocalData->unix_fd;
+ if ( fd == -1 )
+ {
+ TRACE("pLocalData = [%p], fd = %d\n", pLocalData, fd);
+ palError = ERROR_INVALID_HANDLE;
+ goto InternalSetFileTimeExit;
+ }
+
+ if ( fstat(fd, &stat_buf) != 0 )
+ {
+ TRACE("fstat failed on file descriptor %d\n", fd);
+ palError = FILEGetLastErrorFromErrno();
+ goto InternalSetFileTimeExit;
+ }
+ }
+
+ if (lpLastAccessTime)
+ {
+ Times[0].tv_sec = FILEFileTimeToUnixTime( *lpLastAccessTime, &nsec );
+ Times[0].tv_usec = nsec / 1000; /* convert to microseconds */
+ }
+ else
+ {
+ Times[0].tv_sec = stat_buf.st_atime;
+ Times[0].tv_usec = ST_ATIME_NSEC(&stat_buf) / 1000;
+ }
+
+ if (lpLastWriteTime)
+ {
+ Times[1].tv_sec = FILEFileTimeToUnixTime( *lpLastWriteTime, &nsec );
+ Times[1].tv_usec = nsec / 1000; /* convert to microseconds */
+ }
+ else
+ {
+ Times[1].tv_sec = stat_buf.st_mtime;
+ Times[1].tv_usec = ST_MTIME_NSEC(&stat_buf) / 1000;
+ }
+
+ TRACE("Setting atime = [%ld.%ld], mtime = [%ld.%ld]\n",
+ Times[0].tv_sec, Times[0].tv_usec,
+ Times[1].tv_sec, Times[1].tv_usec);
+
+#if HAVE_FUTIMES
+ if ( futimes(pLocalData->unix_fd, Times) != 0 )
+#elif HAVE_UTIMES
+ if ( utimes(pLocalData->unix_filename, Times) != 0 )
+#else
+ #error Operating system not supported
+#endif
+ {
+ palError = FILEGetLastErrorFromErrno();
+ }
+
+InternalSetFileTimeExit:
+ if (NULL != pLocalDataLock)
+ {
+ pLocalDataLock->ReleaseLock(pThread, FALSE);
+ }
+
+ if (NULL != pFileObject)
+ {
+ pFileObject->ReleaseReference(pThread);
+ }
+
+ return palError;
+}
+
+
+/*++
+Function:
+ GetFileTime
+
+Notes: As noted at the top of this file, there is no analog to "creation
+time" on Unix systems, so the inode change time is used instead. Also, Win32
+LastAccessTime is updated after a write operation, but it is not on Unix.
+To be consistent with Win32, this function returns the greater of mtime and
+atime for LastAccessTime.
+--*/
+BOOL
+PALAPI
+GetFileTime(
+ IN HANDLE hFile,
+ OUT LPFILETIME lpCreationTime,
+ OUT LPFILETIME lpLastAccessTime,
+ OUT LPFILETIME lpLastWriteTime)
+{
+ CPalThread *pThread;
+ PAL_ERROR palError = NO_ERROR;
+
+ PERF_ENTRY(GetFileTime);
+ ENTRY("GetFileTime(hFile=%p, lpCreationTime=%p, lpLastAccessTime=%p, "
+ "lpLastWriteTime=%p)\n",
+ hFile, lpCreationTime, lpLastAccessTime, lpLastWriteTime);
+
+ pThread = InternalGetCurrentThread();
+
+ palError = InternalGetFileTime(
+ pThread,
+ hFile,
+ lpCreationTime,
+ lpLastAccessTime,
+ lpLastWriteTime
+ );
+
+ if (NO_ERROR != palError)
+ {
+ pThread->SetLastError(palError);
+ }
+
+ LOGEXIT("GetFileTime returns BOOL %s\n", NO_ERROR == palError ? "TRUE":"FALSE");
+ PERF_EXIT(GetFileTime);
+ return NO_ERROR == palError;
+}
+
+PAL_ERROR
+CorUnix::InternalGetFileTime(
+ CPalThread *pThread,
+ IN HANDLE hFile,
+ OUT LPFILETIME lpCreationTime,
+ OUT LPFILETIME lpLastAccessTime,
+ OUT LPFILETIME lpLastWriteTime)
+{
+ PAL_ERROR palError = NO_ERROR;
+ IPalObject *pFileObject = NULL;
+ CFileProcessLocalData *pLocalData = NULL;
+ IDataLock *pLocalDataLock = NULL;
+ int Fd = -1;
+
+ struct stat StatData;
+
+ if (INVALID_HANDLE_VALUE == hFile)
+ {
+ ERROR( "Invalid file handle\n" );
+ palError = ERROR_INVALID_HANDLE;
+ goto InternalGetFileTimeExit;
+ }
+
+ palError = g_pObjectManager->ReferenceObjectByHandle(
+ pThread,
+ hFile,
+ &aotFile,
+ GENERIC_READ,
+ &pFileObject
+ );
+
+ if (NO_ERROR != palError)
+ {
+ goto InternalGetFileTimeExit;
+ }
+
+ palError = pFileObject->GetProcessLocalData(
+ pThread,
+ ReadLock,
+ &pLocalDataLock,
+ reinterpret_cast<void**>(&pLocalData)
+ );
+
+ if (NO_ERROR != palError)
+ {
+ goto InternalGetFileTimeExit;
+ }
+
+ Fd = pLocalData->unix_fd;
+
+ if ( Fd == -1 )
+ {
+ TRACE("pLocalData = [%p], Fd = %d\n", pLocalData, Fd);
+ palError = ERROR_INVALID_HANDLE;
+ goto InternalGetFileTimeExit;
+ }
+
+ if ( fstat(Fd, &StatData) != 0 )
+ {
+ TRACE("fstat failed on file descriptor %d\n", Fd);
+ palError = FILEGetLastErrorFromErrno();
+ goto InternalGetFileTimeExit;
+ }
+
+ if ( lpCreationTime )
+ {
+ *lpCreationTime = FILEUnixTimeToFileTime(StatData.st_ctime,
+ ST_CTIME_NSEC(&StatData));
+ }
+ if ( lpLastWriteTime )
+ {
+ *lpLastWriteTime = FILEUnixTimeToFileTime(StatData.st_mtime,
+ ST_MTIME_NSEC(&StatData));
+ }
+ if ( lpLastAccessTime )
+ {
+ *lpLastAccessTime = FILEUnixTimeToFileTime(StatData.st_atime,
+ ST_ATIME_NSEC(&StatData));
+ /* if Unix mtime is greater than atime, return mtime as the last
+ access time */
+ if ( lpLastWriteTime &&
+ CompareFileTime(lpLastAccessTime, lpLastWriteTime) < 0 )
+ {
+ *lpLastAccessTime = *lpLastWriteTime;
+ }
+ }
+
+InternalGetFileTimeExit:
+ if (NULL != pLocalDataLock)
+ {
+ pLocalDataLock->ReleaseLock(pThread, FALSE);
+ }
+
+ if (NULL != pFileObject)
+ {
+ pFileObject->ReleaseReference(pThread);
+ }
+
+ return palError;
+}
+
+
+
+
+
+
+/*++
+Function:
+ GetSystemTimeAsFileTime
+
+See MSDN doc.
+--*/
+VOID
+PALAPI
+GetSystemTimeAsFileTime(
+ OUT LPFILETIME lpSystemTimeAsFileTime)
+{
+ struct timeval Time;
+
+ PERF_ENTRY(GetSystemTimeAsFileTime);
+ ENTRY("GetSystemTimeAsFileTime(lpSystemTimeAsFileTime=%p)\n",
+ lpSystemTimeAsFileTime);
+
+ if ( gettimeofday( &Time, NULL ) != 0 )
+ {
+ ASSERT("gettimeofday() failed");
+ /* no way to indicate failure, so set time to zero */
+ *lpSystemTimeAsFileTime = FILEUnixTimeToFileTime( 0, 0 );
+ }
+ else
+ {
+ /* use (tv_usec * 1000) because 2nd arg is in nanoseconds */
+ *lpSystemTimeAsFileTime = FILEUnixTimeToFileTime( Time.tv_sec,
+ Time.tv_usec * 1000 );
+ }
+
+ LOGEXIT("GetSystemTimeAsFileTime returns.\n");
+ PERF_EXIT(GetSystemTimeAsFileTime);
+}
+
+
+#ifdef __APPLE__
+/*++
+Function:
+ FILECFAbsoluteTimeToFileTime
+
+Convert a CFAbsoluteTime value to a win32 FILETIME structure, as described
+in MSDN documentation. CFAbsoluteTime is the number of seconds elapsed since
+00:00 01 January 2001 UTC (Mac OS X epoch), while FILETIME represents a
+64-bit number of 100-nanosecond intervals that have passed since 00:00
+01 January 1601 UTC (win32 epoch).
+--*/
+FILETIME FILECFAbsoluteTimeToFileTime( CFAbsoluteTime sec )
+{
+ __int64 Result;
+ FILETIME Ret;
+
+ Result = ((__int64)sec + SECS_BETWEEN_1601_AND_2001_EPOCHS) * SECS_TO_100NS;
+
+ Ret.dwLowDateTime = (DWORD)Result;
+ Ret.dwHighDateTime = (DWORD)(Result >> 32);
+
+ TRACE("CFAbsoluteTime = [%9f] converts to Win32 FILETIME = [%#x:%#x]\n",
+ sec, Ret.dwHighDateTime, Ret.dwLowDateTime);
+
+ return Ret;
+}
+#endif // __APPLE__
+
+
+/*++
+Function:
+ FILEUnixTimeToFileTime
+
+Convert a time_t value to a win32 FILETIME structure, as described in
+MSDN documentation. time_t is the number of seconds elapsed since
+00:00 01 January 1970 UTC (Unix epoch), while FILETIME represents a
+64-bit number of 100-nanosecond intervals that have passed since 00:00
+01 January 1601 UTC (win32 epoch).
+--*/
+FILETIME FILEUnixTimeToFileTime( time_t sec, long nsec )
+{
+ __int64 Result;
+ FILETIME Ret;
+
+ Result = ((__int64)sec + SECS_BETWEEN_1601_AND_1970_EPOCHS) * SECS_TO_100NS +
+ (nsec / 100);
+
+ Ret.dwLowDateTime = (DWORD)Result;
+ Ret.dwHighDateTime = (DWORD)(Result >> 32);
+
+ TRACE("Unix time = [%ld.%09ld] converts to Win32 FILETIME = [%#x:%#x]\n",
+ sec, nsec, Ret.dwHighDateTime, Ret.dwLowDateTime);
+
+ return Ret;
+}
+
+
+/*++
+Function:
+ FILEFileTimeToUnixTime
+
+See FILEUnixTimeToFileTime above.
+
+This function takes a win32 FILETIME structures, returns the equivalent
+time_t value, and, if the nsec parameter is non-null, also returns the
+nanoseconds.
+
+NOTE: a 32-bit time_t is only capable of representing dates between
+13 December 1901 and 19 January 2038. This function will calculate the
+number of seconds (positive or negative) since the Unix epoch, however if
+this value is outside of the range of 32-bit numbers, the result will be
+truncated on systems with a 32-bit time_t.
+--*/
+time_t FILEFileTimeToUnixTime( FILETIME FileTime, long *nsec )
+{
+ __int64 UnixTime;
+
+ /* get the full win32 value, in 100ns */
+ UnixTime = ((__int64)FileTime.dwHighDateTime << 32) +
+ FileTime.dwLowDateTime;
+
+ /* convert to the Unix epoch */
+ UnixTime -= (SECS_BETWEEN_1601_AND_1970_EPOCHS * SECS_TO_100NS);
+
+ TRACE("nsec=%p\n", nsec);
+
+ if ( nsec )
+ {
+ /* get the number of 100ns, convert to ns */
+ *nsec = (UnixTime % SECS_TO_100NS) * 100;
+ }
+
+ UnixTime /= SECS_TO_100NS; /* now convert to seconds */
+
+ if ( (time_t)UnixTime != UnixTime )
+ {
+ WARN("Resulting value is too big for a time_t value\n");
+ }
+
+ TRACE("Win32 FILETIME = [%#x:%#x] converts to Unix time = [%ld.%09ld]\n",
+ FileTime.dwHighDateTime, FileTime.dwLowDateTime ,(long) UnixTime,
+ nsec?*nsec:0L);
+
+ return (time_t)UnixTime;
+}
+
+
+
+/**
+Function
+
+ FileTimeToSystemTime()
+
+ Helper function for FileTimeToDosTime.
+ Converts the necessary file time attibutes to system time, for
+ easier manipulation in FileTimeToDosTime.
+
+--*/
+BOOL PALAPI FileTimeToSystemTime( CONST FILETIME * lpFileTime,
+ LPSYSTEMTIME lpSystemTime )
+{
+ UINT64 FileTime = 0;
+ time_t UnixFileTime = 0;
+ struct tm * UnixSystemTime = 0;
+
+ /* Combine the file time. */
+ FileTime = lpFileTime->dwHighDateTime;
+ FileTime <<= 32;
+ FileTime |= (UINT)lpFileTime->dwLowDateTime;
+ bool isSafe = ClrSafeInt<UINT64>::subtraction(
+ FileTime,
+ SECS_BETWEEN_1601_AND_1970_EPOCHS * SECS_TO_100NS,
+ FileTime);
+
+ if (isSafe == true)
+ {
+#if HAVE_GMTIME_R
+ struct tm timeBuf;
+#endif /* HAVE_GMTIME_R */
+ /* Convert file time to unix time. */
+ if (((INT64)FileTime) < 0)
+ {
+ UnixFileTime = -1 - ( ( -FileTime - 1 ) / 10000000 );
+ }
+ else
+ {
+ UnixFileTime = FileTime / 10000000;
+ }
+
+ /* Convert unix file time to Unix System time. */
+#if HAVE_GMTIME_R
+ UnixSystemTime = gmtime_r( &UnixFileTime, &timeBuf );
+#else /* HAVE_GMTIME_R */
+ UnixSystemTime = gmtime( &UnixFileTime );
+#endif /* HAVE_GMTIME_R */
+
+ /* Convert unix system time to Windows system time. */
+ lpSystemTime->wDay = UnixSystemTime->tm_mday;
+
+ /* Unix time counts January as a 0, under Windows it is 1*/
+ lpSystemTime->wMonth = UnixSystemTime->tm_mon + 1;
+ /* Unix time returns the year - 1900, Windows returns the current year*/
+ lpSystemTime->wYear = UnixSystemTime->tm_year + 1900;
+
+ lpSystemTime->wSecond = UnixSystemTime->tm_sec;
+ lpSystemTime->wMinute = UnixSystemTime->tm_min;
+ lpSystemTime->wHour = UnixSystemTime->tm_hour;
+ return TRUE;
+ }
+ else
+ {
+ ERROR( "The file time is to large.\n" );
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+}
+
+
+
+/**
+Function:
+ FileTimeToDosDateTime
+
+ Notes due to the difference between how BSD and Windows
+ calculates time, this function can only repersent dates between
+ 1980 and 2037. 2037 is the upperlimit for the BSD time functions( 1900 -
+ 2037 range ).
+
+See msdn for more details.
+--*/
+BOOL
+PALAPI
+FileTimeToDosDateTime(
+ IN CONST FILETIME *lpFileTime,
+ OUT LPWORD lpFatDate,
+ OUT LPWORD lpFatTime )
+{
+ BOOL bRetVal = FALSE;
+
+ PERF_ENTRY(FileTimeToDosDateTime);
+ ENTRY( "FileTimeToDosDateTime( lpFileTime=%p, lpFatDate=%p, lpFatTime=%p )\n",
+ lpFileTime, lpFatDate, lpFatTime );
+
+ /* Sanity checks. */
+ if ( !lpFileTime || !lpFatDate || !lpFatTime )
+ {
+ ERROR( "Incorrect parameters.\n" );
+ SetLastError( ERROR_INVALID_PARAMETER );
+ }
+ else
+ {
+ /* Do conversion. */
+ SYSTEMTIME SysTime;
+ if ( FileTimeToSystemTime( lpFileTime, &SysTime ) )
+ {
+ if ( SysTime.wYear >= 1980 && SysTime.wYear <= 2037 )
+ {
+ *lpFatDate = 0;
+ *lpFatTime = 0;
+
+ *lpFatDate |= ( SysTime.wDay & 0x1F );
+ *lpFatDate |= ( ( SysTime.wMonth & 0xF ) << 5 );
+ *lpFatDate |= ( ( ( SysTime.wYear - 1980 ) & 0x7F ) << 9 );
+
+ if ( SysTime.wSecond % 2 == 0 )
+ {
+ *lpFatTime |= ( ( SysTime.wSecond / 2 ) & 0x1F );
+ }
+ else
+ {
+ *lpFatTime |= ( ( SysTime.wSecond / 2 + 1 ) & 0x1F );
+ }
+
+ *lpFatTime |= ( ( SysTime.wMinute & 0x3F ) << 5 );
+ *lpFatTime |= ( ( SysTime.wHour & 0x1F ) << 11 );
+
+ bRetVal = TRUE;
+ }
+ else
+ {
+ ERROR( "The function can only repersent dates between 1/1/1980"
+ " and 12/31/2037\n" );
+ SetLastError( ERROR_INVALID_PARAMETER );
+ }
+ }
+ else
+ {
+ ERROR( "Unable to convert file time to system time.\n" );
+ SetLastError( ERROR_INVALID_PARAMETER );
+ bRetVal = FALSE;
+ }
+ }
+
+ LOGEXIT( "returning BOOL %d\n", bRetVal );
+ PERF_EXIT(FileTimeToDosDateTime);
+ return bRetVal;
+}
+
diff --git a/src/pal/src/file/find.cpp b/src/pal/src/file/find.cpp
new file mode 100644
index 0000000000..18639d3d14
--- /dev/null
+++ b/src/pal/src/file/find.cpp
@@ -0,0 +1,999 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ find.c
+
+Abstract:
+
+ Implementation of the FindFile function family
+
+Revision History:
+
+
+
+--*/
+
+#include "pal/thread.hpp"
+#include "pal/malloc.hpp"
+#include "pal/file.hpp"
+#include "pal/stackstring.hpp"
+
+#include "pal/palinternal.h"
+#include "pal/dbgmsg.h"
+#include "pal/file.h"
+#include "pal/filetime.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <limits.h>
+
+using namespace CorUnix;
+
+SET_DEFAULT_DEBUG_CHANNEL(FILE);
+
+namespace CorUnix
+{
+ int InternalGlob(
+ const char *szPattern,
+ int nFlags,
+#if ERROR_FUNC_FOR_GLOB_HAS_FIXED_PARAMS
+ int (*pnErrFunc)(const char *, int),
+#else
+ int (*pnErrFunc)(...),
+#endif
+ glob_t *pgGlob
+ );
+
+ /*++
+ InternalGlob
+
+ Input parameters:
+
+ szPattern = pointer to a pathname pattern to be expanded
+ nFlags = arguments to modify the behavior of glob
+ pnErrFunc = pointer to a routine that handles errors during the glob call
+ pgGlob = pointer to a glob structure
+
+ Return value:
+ 0 on success, -1 on failure.
+
+ Some platforms expect the error function for glob to take a variable number
+ of parameters, whereas other platforms insist that the error function take
+ a const char * and an int. A test in configure determines which is the case
+ for each platform and sets ERROR_FUNC_FOR_GLOB_HAS_FIXED_PARAMS
+ to 1 if the error func must have the char * and int parameters.
+ --*/
+ int
+ InternalGlob(
+ const char *szPattern,
+ int nFlags,
+#if ERROR_FUNC_FOR_GLOB_HAS_FIXED_PARAMS
+ int (*pnErrFunc)(const char *, int),
+#else
+ int (*pnErrFunc)(...),
+#endif
+ glob_t *pgGlob
+ )
+ {
+ int nRet = -1;
+ nRet = glob(szPattern, nFlags, pnErrFunc, pgGlob);
+ return nRet;
+ }
+}
+
+static BOOL FILEDosGlobA(
+ CPalThread *pthrCurrent,
+ const char *pattern,
+ int flags,
+ glob_t *pgGlob );
+
+static int FILEGlobQsortCompare(const void *in_str1, const void *in_str2);
+
+static int FILEGlobFromSplitPath(
+ const char *dir,
+ const char *fname,
+ const char *ext,
+ int flags,
+ glob_t *pgGlob );
+
+/*++
+Function:
+ FindFirstFileA
+
+See MSDN doc.
+--*/
+HANDLE
+PALAPI
+FindFirstFileA(
+ IN LPCSTR lpFileName,
+ OUT LPWIN32_FIND_DATAA lpFindFileData)
+{
+ HANDLE hRet = INVALID_HANDLE_VALUE;
+ DWORD dwLastError = NO_ERROR;
+ find_obj *find_data = NULL;
+ CPalThread *pthrCurrent = InternalGetCurrentThread();
+
+ PERF_ENTRY(FindFirstFileA);
+ ENTRY("FindFirstFileA(lpFileName=%p (%s), lpFindFileData=%p)\n",
+ lpFileName?lpFileName:"NULL",
+ lpFileName?lpFileName:"NULL", lpFindFileData);
+
+ if(NULL == lpFileName)
+ {
+ ERROR("lpFileName is NULL!\n");
+ dwLastError = ERROR_PATH_NOT_FOUND;
+ goto done;
+ }
+ if(NULL == lpFindFileData)
+ {
+ ASSERT("lpFindFileData is NULL!\n");
+ dwLastError = ERROR_INVALID_PARAMETER;
+ goto done;
+ }
+
+ find_data = (find_obj *)InternalMalloc(sizeof(find_obj));
+ if ( find_data == NULL )
+ {
+ ERROR("Unable to allocate memory for find_data\n");
+ dwLastError = ERROR_NOT_ENOUGH_MEMORY;
+ goto done;
+ }
+
+ find_data->self_addr = find_data;
+
+ // Clear the glob_t so we can safely call globfree() on it
+ // regardless of whether FILEDosGlobA ends up calling glob().
+ memset(&(find_data->gGlob), 0, sizeof(find_data->gGlob));
+
+ if (!FILEDosGlobA(pthrCurrent, lpFileName, 0, &(find_data->gGlob)))
+ {
+ // FILEDosGlobA will call SetLastError() on failure.
+ goto done;
+ }
+ else
+ {
+ // Check if there's at least one match.
+ if (find_data->gGlob.gl_pathc == 0)
+ {
+ /* Testing has indicated that for this API the
+ * last errors are as follows
+ * c:\temp\foo.txt - no error
+ * c:\temp\foo - ERROR_FILE_NOT_FOUND
+ * c:\temp\foo\bar - ERROR_PATH_NOT_FOUND
+ * c:\temp\foo.txt\bar - ERROR_DIRECTORY
+ *
+ */
+ LPSTR lpTemp = strdup((LPSTR)lpFileName);
+ if ( !lpTemp )
+ {
+ ERROR( "strdup failed!\n" );
+ SetLastError( ERROR_INTERNAL_ERROR );
+ goto done;
+ }
+ FILEDosToUnixPathA( lpTemp );
+ FILEGetProperNotFoundError( lpTemp, &dwLastError );
+
+ if ( ERROR_PATH_NOT_FOUND == dwLastError )
+ {
+ /* If stripping the last segment reveals a file name then
+ the error is ERROR_DIRECTORY. */
+ struct stat stat_data;
+ LPSTR lpLastPathSeparator = NULL;
+
+ lpLastPathSeparator = strrchr( lpTemp, '/');
+
+ if ( lpLastPathSeparator != NULL )
+ {
+ *lpLastPathSeparator = '\0';
+
+ if ( stat( lpTemp, &stat_data) == 0 &&
+ (stat_data.st_mode & S_IFMT) == S_IFREG )
+ {
+ dwLastError = ERROR_DIRECTORY;
+ }
+ }
+ }
+ free(lpTemp);
+ lpTemp = NULL;
+ goto done;
+ }
+
+ find_data->next = find_data->gGlob.gl_pathv;
+ }
+
+ if ( FindNextFileA( (HANDLE)find_data, lpFindFileData ) )
+ {
+ hRet = (HANDLE)find_data;
+ }
+
+done:
+
+ if ( hRet == INVALID_HANDLE_VALUE )
+ {
+ if(NULL != find_data)
+ {
+ // Call globfree only when there is any pattern match
+ // otherwise, HPUX C library segfaults.
+ if (NULL != find_data->gGlob.gl_pathv)
+ {
+ globfree( &(find_data->gGlob) );
+ }
+ free(find_data);
+ }
+ if (dwLastError)
+ {
+ SetLastError(dwLastError);
+ }
+ }
+
+ LOGEXIT("FindFirstFileA returns HANDLE %p\n", hRet );
+ PERF_EXIT(FindFirstFileA);
+ return hRet;
+}
+
+
+/*++
+Function:
+ FindFirstFileW
+
+See MSDN doc.
+--*/
+HANDLE
+PALAPI
+FindFirstFileW(
+ IN LPCWSTR lpFileName,
+ OUT LPWIN32_FIND_DATAW lpFindFileData)
+{
+ // MAX_PATH_FNAME in this context is a file name, not a full path to a file.
+ HANDLE retval = INVALID_HANDLE_VALUE;
+ CHAR FileNameA[MAX_PATH_FNAME];
+ WIN32_FIND_DATAA FindFileDataA;
+
+ PERF_ENTRY(FindFirstFileW);
+ ENTRY("FindFirstFileW(lpFileName=%p (%S), lpFindFileData=%p)\n",
+ lpFileName?lpFileName:W16_NULLSTRING,
+ lpFileName?lpFileName:W16_NULLSTRING, lpFindFileData);
+
+ if(NULL == lpFileName)
+ {
+ ERROR("lpFileName is NULL!\n");
+ SetLastError(ERROR_PATH_NOT_FOUND);
+ goto done;
+ }
+
+ if(NULL == lpFindFileData)
+ {
+ ERROR("lpFindFileData is NULL!\n");
+ SetLastError(ERROR_INVALID_PARAMETER);
+ goto done;
+ }
+ if( 0 == WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, lpFileName, -1,
+ FileNameA, MAX_PATH_FNAME, NULL, NULL))
+ {
+ DWORD dwLastError = GetLastError();
+ if (dwLastError == ERROR_INSUFFICIENT_BUFFER)
+ {
+ WARN("lpFileName is larger than MAX_PATH_FNAME (%d)!\n", MAX_PATH_FNAME);
+ SetLastError(ERROR_FILENAME_EXCED_RANGE);
+ }
+ else
+ {
+ ASSERT("WideCharToMultiByte failed! error is %d\n", dwLastError);
+ SetLastError(ERROR_INTERNAL_ERROR);
+ }
+ goto done;
+ }
+
+ retval = FindFirstFileA(FileNameA, &FindFileDataA);
+ if( INVALID_HANDLE_VALUE == retval )
+ {
+ TRACE("FindFirstFileA failed!\n");
+ goto done;
+ }
+
+ lpFindFileData->dwFileAttributes = FindFileDataA.dwFileAttributes;
+ lpFindFileData->dwReserved0 = FindFileDataA.dwReserved0;
+ lpFindFileData->dwReserved1 = FindFileDataA.dwReserved1;
+ lpFindFileData->ftCreationTime = FindFileDataA.ftCreationTime;
+ lpFindFileData->ftLastAccessTime = FindFileDataA.ftLastAccessTime;
+ lpFindFileData->ftLastWriteTime = FindFileDataA.ftLastWriteTime;
+ lpFindFileData->nFileSizeHigh = FindFileDataA.nFileSizeHigh;
+ lpFindFileData->nFileSizeLow = FindFileDataA.nFileSizeLow;
+
+ /* no 8.3 file names */
+ lpFindFileData->cAlternateFileName[0] = 0;
+
+ if( 0 == MultiByteToWideChar(CP_ACP, 0, FindFileDataA.cFileName, -1,
+ lpFindFileData->cFileName, MAX_PATH_FNAME))
+ {
+ DWORD dwLastError = GetLastError();
+ if (dwLastError == ERROR_INSUFFICIENT_BUFFER)
+ {
+ WARN("FindFileDataA.cFileName is larger than MAX_PATH_FNAME (%d)!\n", MAX_PATH_FNAME);
+ SetLastError(ERROR_FILENAME_EXCED_RANGE);
+ }
+ else
+ {
+ ASSERT("MultiByteToWideChar failed! error is %d\n", dwLastError);
+ SetLastError(ERROR_INTERNAL_ERROR);
+ }
+ FindClose(retval);
+ retval = INVALID_HANDLE_VALUE;
+ }
+done:
+ LOGEXIT("FindFirstFileW returns HANDLE %p\n", retval);
+ PERF_EXIT(FindFirstFileW);
+ return retval;
+}
+
+
+/*++
+Function:
+ FindNextFileA
+
+See MSDN doc.
+--*/
+BOOL
+PALAPI
+FindNextFileA(
+ IN HANDLE hFindFile,
+ OUT LPWIN32_FIND_DATAA lpFindFileData)
+{
+ find_obj *find_data;
+
+ BOOL bRet = FALSE;
+ DWORD dwLastError = 0;
+ DWORD Attr;
+
+ PERF_ENTRY(FindNextFileA);
+ ENTRY("FindNextFileA(hFindFile=%p, lpFindFileData=%p)\n",
+ hFindFile, lpFindFileData);
+
+ find_data = (find_obj*)hFindFile;
+
+ if ( hFindFile == INVALID_HANDLE_VALUE ||
+ find_data == NULL ||
+ find_data->self_addr != find_data )
+ {
+ TRACE("FindNextFileA received an invalid handle\n");
+ dwLastError = ERROR_INVALID_HANDLE;
+ goto done;
+ }
+
+ if ( find_data->next)
+ {
+ struct stat stat_data;
+ char ext[_MAX_EXT];
+ int stat_result;
+
+ while (*(find_data->next))
+ {
+ char *path = *(find_data->next);
+
+ TRACE("Found [%s]\n", path);
+
+ // Split the path into a dir and filename.
+ if (_splitpath_s(path, NULL, 0, find_data->dir, _MAX_DIR, find_data->fname, _MAX_PATH, ext, _MAX_EXT) != 0)
+ {
+ ASSERT("_splitpath failed on %s\n", path);
+ dwLastError = ERROR_INTERNAL_ERROR;
+ goto done;
+ }
+ strcat_s( find_data->fname, sizeof(find_data->fname), ext );
+
+ /* get the attributes, but continue if it fails */
+ Attr = GetFileAttributesA(path);
+ if (Attr == INVALID_FILE_ATTRIBUTES)
+ {
+ WARN("GetFileAttributes returned -1 on file [%s]\n",
+ *(find_data->next));
+ }
+ lpFindFileData->dwFileAttributes = Attr;
+
+ /* Note that cFileName is NOT the relative path */
+ if (strcpy_s( lpFindFileData->cFileName, sizeof(lpFindFileData->cFileName), find_data->fname ) != SAFECRT_SUCCESS)
+ {
+ TRACE("strcpy_s failed!\n");
+ dwLastError = ERROR_FILENAME_EXCED_RANGE;
+ goto done;
+ }
+
+ /* we don't support 8.3 filenames, so just leave it empty */
+ lpFindFileData->cAlternateFileName[0] = 0;
+
+ /* get the filetimes */
+ stat_result = stat(path, &stat_data) == 0 ||
+ lstat(path, &stat_data) == 0;
+
+ find_data->next++;
+
+ if ( stat_result )
+ {
+ lpFindFileData->ftCreationTime =
+ FILEUnixTimeToFileTime( stat_data.st_ctime,
+ ST_CTIME_NSEC(&stat_data) );
+ lpFindFileData->ftLastAccessTime =
+ FILEUnixTimeToFileTime( stat_data.st_atime,
+ ST_ATIME_NSEC(&stat_data) );
+ lpFindFileData->ftLastWriteTime =
+ FILEUnixTimeToFileTime( stat_data.st_mtime,
+ ST_MTIME_NSEC(&stat_data) );
+
+ /* if Unix mtime is greater than atime, return mtime
+ as the last access time */
+ if (CompareFileTime(&lpFindFileData->ftLastAccessTime,
+ &lpFindFileData->ftLastWriteTime) < 0)
+ {
+ lpFindFileData->ftLastAccessTime = lpFindFileData->ftLastWriteTime;
+ }
+
+ /* get file size */
+ lpFindFileData->nFileSizeLow = (DWORD)stat_data.st_size;
+ #if SIZEOF_OFF_T > 4
+ lpFindFileData->nFileSizeHigh =
+ (DWORD)(stat_data.st_size >> 32);
+ #else
+ lpFindFileData->nFileSizeHigh = 0;
+ #endif
+
+ bRet = TRUE;
+ break;
+ }
+ }
+ if(!bRet)
+ {
+ dwLastError = ERROR_NO_MORE_FILES;
+ }
+ }
+ else
+ {
+
+ ASSERT("find_data->next is (mysteriously) NULL\n");
+ }
+
+done:
+ if (dwLastError)
+ {
+ SetLastError(dwLastError);
+ }
+
+ LOGEXIT("FindNextFileA returns BOOL %d\n", bRet);
+ PERF_EXIT(FindNextFileA);
+ return bRet;
+}
+
+
+/*++
+Function:
+ FindNextFileW
+
+See MSDN doc.
+--*/
+BOOL
+PALAPI
+FindNextFileW(
+ IN HANDLE hFindFile,
+ OUT LPWIN32_FIND_DATAW lpFindFileData)
+{
+ BOOL retval = FALSE;
+ WIN32_FIND_DATAA FindFileDataA;
+
+ PERF_ENTRY(FindNextFileW);
+ ENTRY("FindNextFileW(hFindFile=%p, lpFindFileData=%p)\n",
+ hFindFile, lpFindFileData);
+
+ retval = FindNextFileA(hFindFile, &FindFileDataA);
+ if(!retval)
+ {
+ WARN("FindNextFileA failed!\n");
+ goto done;
+ }
+
+ lpFindFileData->dwFileAttributes = FindFileDataA.dwFileAttributes;
+ lpFindFileData->dwReserved0 = FindFileDataA.dwReserved0;
+ lpFindFileData->dwReserved1 = FindFileDataA.dwReserved1;
+ lpFindFileData->ftCreationTime = FindFileDataA.ftCreationTime;
+ lpFindFileData->ftLastAccessTime = FindFileDataA.ftLastAccessTime;
+ lpFindFileData->ftLastWriteTime = FindFileDataA.ftLastWriteTime;
+ lpFindFileData->nFileSizeHigh = FindFileDataA.nFileSizeHigh;
+ lpFindFileData->nFileSizeLow = FindFileDataA.nFileSizeLow;
+
+ /* no 8.3 file names */
+ lpFindFileData->cAlternateFileName[0] = 0;
+
+ if( 0 == MultiByteToWideChar(CP_ACP, 0, FindFileDataA.cFileName, -1,
+ lpFindFileData->cFileName, MAX_PATH_FNAME))
+ {
+ DWORD dwLastError = GetLastError();
+ if (dwLastError == ERROR_INSUFFICIENT_BUFFER)
+ {
+ WARN("FindFileDataA.cFileName is larger than MAX_PATH_FNAME (%d)!\n", MAX_PATH_FNAME);
+ SetLastError(ERROR_FILENAME_EXCED_RANGE);
+ }
+ else
+ {
+ ASSERT("MultiByteToWideChar failed! error is %d\n", dwLastError);
+ SetLastError(ERROR_INTERNAL_ERROR);
+ }
+ retval = FALSE;
+ }
+
+done:
+ LOGEXIT("FindNextFileW returns BOOL %d\n", retval);
+ PERF_EXIT(FindNextFileW);
+ return retval;
+}
+
+
+/*++
+Function:
+ FindClose
+
+See MSDN doc.
+--*/
+BOOL
+PALAPI
+FindClose(
+ IN OUT HANDLE hFindFile)
+{
+ find_obj *find_data;
+ BOOL hRet = TRUE;
+ DWORD dwLastError = 0;
+
+ PERF_ENTRY(FindClose);
+ ENTRY("FindClose(hFindFile=%p)\n", hFindFile);
+
+ find_data = (find_obj*)hFindFile;
+
+ if ( hFindFile == INVALID_HANDLE_VALUE ||
+ find_data == NULL ||
+ find_data->self_addr != find_data )
+ {
+ ERROR("Invalid find handle\n");
+ hRet = FALSE;
+ dwLastError = ERROR_INVALID_PARAMETER;
+ goto done;
+ }
+
+ find_data->self_addr = NULL;
+
+ // Call globfree only when there is any pattern match
+ // otherwise, HPUX C library segfaults.
+ if (NULL != find_data->gGlob.gl_pathv)
+ {
+ globfree( &(find_data->gGlob) );
+ }
+ free(find_data);
+
+done:
+ if (dwLastError)
+ {
+ SetLastError(dwLastError);
+ }
+
+ LOGEXIT("FindClose returns BOOL %d\n", hRet);
+ PERF_EXIT(FindClose);
+ return hRet;
+}
+
+
+/*++
+Function:
+ FILEMakePathA
+
+Mimics _makepath from windows, except it's a bit safer.
+Any or all of dir, fname, and ext can be NULL.
+--*/
+static int FILEMakePathA( char *buff,
+ int buff_size,
+ const char *dir,
+ const char *fname,
+ const char *ext )
+{
+ int dir_len = 0;
+ int fname_len = 0;
+ int ext_len = 0;
+ int len;
+ char *p;
+
+ TRACE("Attempting to assemble path from [%s][%s][%s], buff_size = %d\n",
+ dir?dir:"NULL", fname?fname:"NULL", ext?ext:"NULL", buff_size);
+
+ if (dir) dir_len = strlen(dir);
+ if (fname) fname_len = strlen(fname);
+ if (ext) ext_len = strlen(ext);
+
+ len = dir_len + fname_len + ext_len + 1;
+
+ TRACE("Required buffer size is %d bytes\n", len);
+
+ if ( len > buff_size )
+ {
+ ERROR("Buffer is too small (%d bytes), needs %d bytes\n",
+ buff_size, len);
+ return -1;
+ }
+ else
+ {
+ buff[0] = 0;
+
+ p = buff;
+ if (dir_len > 0)
+ {
+ if (strncpy_s( buff, buff_size, dir, dir_len + 1 ) != SAFECRT_SUCCESS)
+ {
+ ERROR("FILEMakePathA: strncpy_s failed\n");
+ return -1;
+ }
+
+ p += dir_len;
+ buff_size-= dir_len;
+ }
+ if (fname_len > 0)
+ {
+ if (strncpy_s( p, buff_size, fname, fname_len + 1 ) != SAFECRT_SUCCESS)
+ {
+ ERROR("FILEMakePathA: strncpy_s failed\n");
+ return -1;
+ }
+
+ p += fname_len;
+ buff_size-=fname_len;
+ }
+ if (ext_len > 0)
+ {
+ if (strncpy_s( p, buff_size, ext, ext_len + 1) != SAFECRT_SUCCESS)
+ {
+ ERROR("FILEMakePathA: strncpy_s failed\n");
+ return -1;
+ }
+ }
+
+ TRACE("FILEMakePathA assembled [%s]\n", buff);
+ return len - 1;
+ }
+}
+
+
+/*++
+ FILEGlobQsortCompare
+
+ Comparison function required by qsort, so that the
+ . and .. directories end up on top of the sorted list
+ of directories.
+--*/
+static int FILEGlobQsortCompare(const void *in_str1, const void *in_str2)
+{
+ char **str1 = (char**)in_str1;
+ char **str2 = (char**)in_str2;
+ const int FIRST_ARG_LESS = -1;
+ const int FIRST_ARG_EQUAL = 0;
+ const int FIRST_ARG_GREATER = 1;
+
+ /* If both strings are equal, return immediately */
+ if (strcmp(*(str1), *(str2)) == 0)
+ {
+ return(FIRST_ARG_EQUAL);
+ }
+
+ /* Have '.' always on top than any other search result */
+ if (strcmp(*(str1), ".") == 0)
+ {
+ return (FIRST_ARG_LESS);
+ }
+ if (strcmp(*(str2), ".") == 0)
+ {
+ return (FIRST_ARG_GREATER);
+ }
+
+ /* Have '..' next on top, over any other search result */
+ if (strcmp(*(str1), "..") == 0)
+ {
+ return (FIRST_ARG_LESS);
+ }
+ if (strcmp(*(str2), "..") == 0)
+ {
+ return (FIRST_ARG_GREATER);
+ }
+
+ /* Finally, let strcmp do the rest for us */
+ return (strcmp(*(str1),*(str2)));
+}
+
+/*++
+Function:
+ FILEEscapeSquareBrackets
+
+Simple helper function to insert backslashes before square brackets
+to prevent glob from using them as wildcards.
+
+note: this functions assumes all backslashes have previously been
+ converted into forwardslashes by _splitpath.
+--*/
+static void FILEEscapeSquareBrackets(char *pattern, char *escaped_pattern)
+{
+ TRACE("Entering FILEEscapeSquareBrackets: [%p (%s)][%p]\n",
+ pattern,pattern,escaped_pattern);
+
+#if _ENABLE_DEBUG_MESSAGES_
+ char *escaped_pattern_base = escaped_pattern;
+#endif // _ENABLE_DEBUG_MESSAGES_
+
+ while(*pattern)
+ {
+ if('[' == *pattern || ']' == *pattern)
+ {
+ *escaped_pattern = '\\';
+ escaped_pattern++;
+ }
+ *escaped_pattern = *pattern;
+ pattern++;
+ escaped_pattern++;
+ }
+ *escaped_pattern='\0';
+
+ TRACE("FILEEscapeSquareBrackets done. escaped_pattern=%s\n",
+ escaped_pattern_base);
+}
+
+
+/*++
+Function:
+ FILEGlobFromSplitPath
+
+Simple wrapper function around glob(3), except that the pattern is accepted
+in broken-down form like _splitpath produces.
+
+ie. calling splitpath on a pattern then calling this function should
+produce the same result as just calling glob() on the pattern.
+--*/
+static int FILEGlobFromSplitPath( const char *dir,
+ const char *fname,
+ const char *ext,
+ int flags,
+ glob_t *pgGlob )
+{
+ int Ret;
+ PathCharString PatternPS;
+ PathCharString EscapedPatternPS;
+ char * Pattern;
+ int length = 0;
+ char * EscapedPattern;
+
+ TRACE("We shall attempt to glob from components [%s][%s][%s]\n",
+ dir?dir:"NULL", fname?fname:"NULL", ext?ext:"NULL");
+
+ if (dir) length = strlen(dir);
+ if (fname) length += strlen(fname);
+ if (ext) length += strlen(ext);
+
+ Pattern = PatternPS.OpenStringBuffer(length);
+ if (NULL == Pattern)
+ {
+ ERROR("Not Enough memory.");
+ return -1;
+ }
+ FILEMakePathA( Pattern, length+1, dir, fname, ext );
+ PatternPS.CloseBuffer(length);
+ TRACE("Assembled Pattern = [%s]\n", Pattern);
+
+ /* special handling is needed to handle the case where
+ filename contains '[' and ']' */
+ EscapedPattern = EscapedPatternPS.OpenStringBuffer(length*2);
+ if (NULL == EscapedPattern)
+ {
+ ERROR("Not Enough memory.");
+ return -1;
+ }
+ FILEEscapeSquareBrackets( Pattern, EscapedPattern);
+ EscapedPatternPS.CloseBuffer(strlen(EscapedPattern));
+#ifdef GLOB_QUOTE
+ flags |= GLOB_QUOTE;
+#endif // GLOB_QUOTE
+ Ret = InternalGlob(EscapedPattern, flags, NULL, pgGlob);
+
+#ifdef GLOB_NOMATCH
+ if (Ret == GLOB_NOMATCH)
+ {
+ // pgGlob->gl_pathc will be 0 in this case. We'll check
+ // the return value to see if an error occurred, so we
+ // don't want to return an error if we simply didn't match
+ // anything.
+ Ret = 0;
+ }
+#endif // GLOB_NOMATCH
+
+ /* Ensure that . and .. are placed in front, and sort the rest */
+ qsort(pgGlob->gl_pathv, pgGlob->gl_pathc, sizeof(char*),
+ FILEGlobQsortCompare);
+ TRACE("Result of glob() is %d\n", Ret);
+
+ return Ret;
+}
+
+
+/*++
+Function:
+ FILEDosGlobA
+
+Generate pathnames matching a DOS globbing pattern. This function has a similar
+prototype to glob(3), and fulfils the same purpose. However, DOS globbing
+is slightly different than Unix in the following ways:
+
+- '.*' at the end of a pattern means "any file extension, or none at all",
+whereas Unix has no concept of file extensions, and will match the '.' like
+any other character
+
+- on Unix, filenames beginning with '.' must be explicitly matched. This is
+not true in DOS
+
+- in DOS, the first two entries (if they match) will be '.' and '..', followed
+by all other matching entries sorted in ASCII order. In Unix, all entries are
+treated equally, so '+file' would appear before '.' and '..'
+
+- DOS globbing will fail if any wildcard characters occur before the last path
+separator
+
+This implementation of glob implements the DOS behavior in all these cases,
+but otherwise attempts to behave exactly like POSIX glob. The only exception
+is its return value -- it returns TRUE if it succeeded (finding matches or
+finding no matches but without any error occurring) or FALSE if any error
+occurs. It calls SetLastError() if it returns FALSE.
+
+Sorting doesn't seem to be consistent on all Windows platform, and it's
+not required for Rotor to have the same sorting alogrithm than Windows 2000.
+This implementation will give slightly different result for the sort list
+than Windows 2000.
+
+--*/
+static BOOL FILEDosGlobA( CPalThread *pthrCurrent,
+ const char *pattern,
+ int flags,
+ glob_t *pgGlob )
+{
+ char Dir[_MAX_DIR];
+ char FilenameBuff[_MAX_FNAME + 1];
+ char *Filename = FilenameBuff + 1;
+ char Ext[_MAX_EXT];
+ int A, B, C;
+ BOOL result = TRUE;
+ int globResult = 0;
+
+ Dir[0] = 0;
+ FilenameBuff[0] = '.';
+ FilenameBuff[1] = 0;
+ Ext[0] = 0;
+
+ _splitpath_s( pattern, NULL, 0, Dir, _MAX_DIR, Filename, _MAX_FNAME+1, Ext, _MAX_EXT);
+
+ /* check to see if _splitpath failed */
+ if ( Filename[0] == 0 )
+ {
+ if ( Dir[0] == 0 )
+ {
+ ERROR("_splitpath failed on path [%s]\n", pattern);
+ }
+ else
+ {
+ ERROR("Pattern contains a trailing backslash\n");
+ }
+ SetLastError(ERROR_PATH_NOT_FOUND);
+ result = FALSE;
+ goto done;
+ }
+
+ TRACE("glob pattern [%s] split into [%s][%s][%s]\n",
+ pattern, Dir, Filename, Ext);
+
+ if ( strchr(Dir, '*') != NULL || strchr(Dir, '?') != NULL )
+ {
+ ERROR("Found wildcard character(s) ('*' and/or '?') before "
+ "last path separator\n");
+ SetLastError(ERROR_PATH_NOT_FOUND);
+ result = FALSE;
+ goto done;
+ }
+
+ if (Dir[0] != 0)
+ {
+ FILEDosToUnixPathA( Dir );
+ }
+
+ /* The meat of the routine happens below. Basically, there are three
+ special things to check for:
+
+ (A) If the extension is _exactly_ '.*', we will need to do two globs,
+ one for 'filename.*' and one for 'filename', EXCEPT if (B) the last
+ character of filename is '*', in which case we can eliminate the
+ extension altogether, since '*.*' and '*' are the same in DOS.
+ (C) If the first character of the filename is '*', we need to do
+ an additional glob for each one we have already done, except with
+ '.' prepended to the filename of the patterns, because in Unix,
+ hidden files need to be matched explicitly.
+
+ We can ignore the extension by calling FILEGlobFromSplitPath with
+ the extension parameter as "", and we can prepend '.' to the
+ filename by using (Filename - 1), since Filename conveniently points
+ to the second character of a buffer which happens to have '.' as
+ its first character.
+ */
+
+ A = strncmp(Ext, ".*", 3) == 0;
+ B = (Filename[strlen(Filename) - 1] == '*');
+ C = (*Filename == '*');
+
+ TRACE("Extension IS%s '.*', filename DOES%s end with '*', "
+ "and filename DOES%s begin with '*'\n",
+ A?"":" NOT", B?"":" NOT", C?"":" NOT");
+
+ if ( !(A && B) )
+ {
+ /* the original pattern */
+ globResult = FILEGlobFromSplitPath(Dir, Filename, Ext, 0, pgGlob);
+ if ( globResult != 0 )
+ {
+ goto done;
+ }
+
+ if (C)
+ {
+ /* the original pattern but '.' prepended to filename */
+ globResult = FILEGlobFromSplitPath(Dir, Filename - 1, Ext,
+ GLOB_APPEND, pgGlob);
+ if ( globResult != 0 )
+ {
+ goto done;
+ }
+ }
+ }
+
+ if (A)
+ {
+ /* if (A && B), this is the first glob() call. The first call
+ to glob must use flags = 0, while proceeding calls should
+ set the GLOB_APPEND flag. */
+ globResult = FILEGlobFromSplitPath(Dir, Filename, "",
+ (A && B)?0:GLOB_APPEND, pgGlob);
+ if ( globResult != 0 )
+ {
+ goto done;
+ }
+
+ if (C)
+ {
+ /* omit the extension and prepend '.' to filename */
+ globResult = FILEGlobFromSplitPath(Dir, Filename - 1, "",
+ GLOB_APPEND, pgGlob);
+ if ( globResult != 0 )
+ {
+ goto done;
+ }
+ }
+ }
+
+done:
+ if (globResult != 0)
+ {
+ if (globResult == GLOB_NOSPACE)
+ {
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ }
+ else
+ {
+ SetLastError(ERROR_INTERNAL_ERROR);
+ }
+ result = FALSE;
+ }
+ TRACE("Returning %d\n", result);
+ return result;
+}
+
+
diff --git a/src/pal/src/file/path.cpp b/src/pal/src/file/path.cpp
new file mode 100644
index 0000000000..c4ef31be32
--- /dev/null
+++ b/src/pal/src/file/path.cpp
@@ -0,0 +1,1624 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ path.c
+
+Abstract:
+
+ Implementation of all functions related to path support
+
+Revision History:
+
+
+
+--*/
+
+#include "pal/thread.hpp"
+#include "pal/palinternal.h"
+#include "pal/dbgmsg.h"
+#include "pal/file.h"
+#include "pal/malloc.hpp"
+#include "pal/stackstring.hpp"
+
+#include <errno.h>
+
+#include <unistd.h>
+#include <stdlib.h>
+
+SET_DEFAULT_DEBUG_CHANNEL(FILE);
+
+
+// In safemath.h, Template SafeInt uses macro _ASSERTE, which need to use variable
+// defdbgchan defined by SET_DEFAULT_DEBUG_CHANNEL. Therefore, the include statement
+// should be placed after the SET_DEFAULT_DEBUG_CHANNEL(FILE)
+#include <safemath.h>
+
+int MaxWCharToAcpLengthRatio = 3;
+/*++
+Function:
+ GetFullPathNameA
+
+See MSDN doc.
+--*/
+DWORD
+PALAPI
+GetFullPathNameA(
+ IN LPCSTR lpFileName,
+ IN DWORD nBufferLength,
+ OUT LPSTR lpBuffer,
+ OUT LPSTR *lpFilePart)
+{
+ DWORD nReqPathLen, nRet = 0;
+ PathCharString unixPath;
+ LPSTR unixPathBuf;
+ BOOL fullPath = FALSE;
+
+ PERF_ENTRY(GetFullPathNameA);
+ ENTRY("GetFullPathNameA(lpFileName=%p (%s), nBufferLength=%u, lpBuffer=%p, "
+ "lpFilePart=%p)\n",
+ lpFileName?lpFileName:"NULL",
+ lpFileName?lpFileName:"NULL", nBufferLength, lpBuffer, lpFilePart);
+
+ if(NULL == lpFileName)
+ {
+ WARN("lpFileName is NULL\n");
+ SetLastError(ERROR_INVALID_PARAMETER);
+ goto done;
+ }
+
+ /* find out if lpFileName is a partial or full path */
+ if ('\\' == *lpFileName || '/' == *lpFileName)
+ {
+ fullPath = TRUE;
+ }
+
+ if(fullPath)
+ {
+ if( !unixPath.Set(lpFileName, strlen(lpFileName)))
+ {
+ ERROR("Set() failed;\n");
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ goto done;
+ }
+ }
+ else
+ {
+
+ /* build full path */
+ if(!GetCurrentDirectoryA(unixPath))
+ {
+ /* no reason for this to fail now... */
+ ASSERT("GetCurrentDirectoryA() failed! lasterror is %#xd\n",
+ GetLastError());
+ SetLastError(ERROR_INTERNAL_ERROR);
+ goto done;
+ }
+
+ if (!unixPath.Append("/", 1) ||
+ !unixPath.Append(lpFileName,strlen(lpFileName))
+ )
+ {
+ ERROR("Append failed!\n");
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ goto done;
+ }
+
+ }
+
+ unixPathBuf = unixPath.OpenStringBuffer(unixPath.GetCount());
+ /* do conversion to Unix path */
+ FILEDosToUnixPathA( unixPathBuf );
+
+ /* now we can canonicalize this */
+ FILECanonicalizePath(unixPathBuf);
+
+ /* at last, we can figure out how long this path is */
+ nReqPathLen = strlen(unixPathBuf);
+
+ unixPath.CloseBuffer(nReqPathLen);
+ nReqPathLen++;
+ if(nBufferLength < nReqPathLen)
+ {
+ TRACE("reporting insufficient buffer : minimum is %d, caller "
+ "provided %d\n", nReqPathLen, nBufferLength);
+ nRet = nReqPathLen;
+ goto done;
+ }
+
+ nRet = nReqPathLen-1;
+ strcpy_s(lpBuffer, nBufferLength, unixPath);
+
+ /* locate the filename component if caller cares */
+ if(lpFilePart)
+ {
+ *lpFilePart = strrchr(lpBuffer, '/');
+
+ if (*lpFilePart == NULL)
+ {
+ ASSERT("Not able to find '/' in the full path.\n");
+ SetLastError( ERROR_INTERNAL_ERROR );
+ nRet = 0;
+ goto done;
+ }
+ else
+ {
+ (*lpFilePart)++;
+ }
+ }
+
+done:
+ LOGEXIT("GetFullPathNameA returns DWORD %u\n", nRet);
+ PERF_EXIT(GetFullPathNameA);
+ return nRet;
+}
+
+
+/*++
+Function:
+ GetFullPathNameW
+
+See MSDN doc.
+--*/
+DWORD
+PALAPI
+GetFullPathNameW(
+ IN LPCWSTR lpFileName,
+ IN DWORD nBufferLength,
+ OUT LPWSTR lpBuffer,
+ OUT LPWSTR *lpFilePart)
+{
+ LPSTR fileNameA;
+ CHAR * bufferA;
+ size_t bufferASize = 0;
+ PathCharString bufferAPS;
+ LPSTR lpFilePartA;
+ int fileNameLength;
+ int srcSize;
+ DWORD length;
+ DWORD nRet = 0;
+
+ PERF_ENTRY(GetFullPathNameW);
+ ENTRY("GetFullPathNameW(lpFileName=%p (%S), nBufferLength=%u, lpBuffer=%p"
+ ", lpFilePart=%p)\n",
+ lpFileName?lpFileName:W16_NULLSTRING,
+ lpFileName?lpFileName:W16_NULLSTRING, nBufferLength,
+ lpBuffer, lpFilePart);
+
+
+ fileNameLength = WideCharToMultiByte(CP_ACP, 0, lpFileName,
+ -1, NULL, 0, NULL, NULL);
+ if (fileNameLength == 0)
+ {
+ /* Couldn't convert to ANSI. That's odd. */
+ SetLastError(ERROR_INVALID_PARAMETER);
+ goto done;
+ }
+ else
+ {
+ fileNameA = static_cast<LPSTR>(alloca(fileNameLength));
+ }
+
+ /* Now convert lpFileName to ANSI. */
+ srcSize = WideCharToMultiByte (CP_ACP, 0, lpFileName,
+ -1, fileNameA, fileNameLength,
+ NULL, NULL );
+ if( srcSize == 0 )
+ {
+ DWORD dwLastError = GetLastError();
+ ASSERT("WideCharToMultiByte failure! error is %d\n", dwLastError);
+ SetLastError(ERROR_INVALID_PARAMETER);
+ goto done;
+ }
+
+ bufferASize = nBufferLength * MaxWCharToAcpLengthRatio;
+ bufferA = bufferAPS.OpenStringBuffer(bufferASize);
+ if (NULL == bufferA)
+ {
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ goto done;
+ }
+ length = GetFullPathNameA(fileNameA, bufferASize, bufferA, &lpFilePartA);
+ bufferAPS.CloseBuffer(length);
+
+ if (length == 0 || length > bufferASize)
+ {
+ /* Last error is set by GetFullPathNameA */
+ nRet = length;
+ goto done;
+ }
+
+ /* Convert back to Unicode the result */
+ nRet = MultiByteToWideChar( CP_ACP, 0, bufferA, -1,
+ lpBuffer, nBufferLength );
+
+ if (nRet == 0)
+ {
+ if ( GetLastError() == ERROR_INSUFFICIENT_BUFFER )
+ {
+ /* get the required length */
+ nRet = MultiByteToWideChar( CP_ACP, 0, bufferA, -1,
+ NULL, 0 );
+ SetLastError(ERROR_BUFFER_OVERFLOW);
+ }
+
+ goto done;
+ }
+
+ /* MultiByteToWideChar counts the trailing NULL, but
+ GetFullPathName does not. */
+ nRet--;
+
+ /* now set lpFilePart */
+ if (lpFilePart != NULL)
+ {
+ *lpFilePart = lpBuffer;
+ *lpFilePart += MultiByteToWideChar( CP_ACP, 0, bufferA,
+ lpFilePartA - bufferA, NULL, 0);
+ }
+
+done:
+ LOGEXIT("GetFullPathNameW returns DWORD %u\n", nRet);
+ PERF_EXIT(GetFullPathNameW);
+ return nRet;
+}
+
+
+/*++
+Function:
+ GetLongPathNameW
+
+See MSDN doc.
+
+Note:
+ Since short path names are not implemented (nor supported) in the PAL,
+ this function simply copies the given path into the new buffer.
+
+--*/
+DWORD
+PALAPI
+GetLongPathNameW(
+ IN LPCWSTR lpszShortPath,
+ OUT LPWSTR lpszLongPath,
+ IN DWORD cchBuffer)
+{
+ DWORD dwPathLen = 0;
+
+ PERF_ENTRY(GetLongPathNameW);
+ ENTRY("GetLongPathNameW(lpszShortPath=%p (%S), lpszLongPath=%p (%S), "
+ "cchBuffer=%d\n", lpszShortPath, lpszShortPath, lpszLongPath, lpszLongPath, cchBuffer);
+
+ if ( !lpszShortPath )
+ {
+ ERROR( "lpszShortPath was not a valid pointer.\n" )
+ SetLastError( ERROR_INVALID_PARAMETER );
+ LOGEXIT("GetLongPathNameW returns DWORD 0\n");
+ PERF_EXIT(GetLongPathNameW);
+ return 0;
+ }
+ else if (INVALID_FILE_ATTRIBUTES == GetFileAttributesW( lpszShortPath ))
+ {
+ // last error has been set by GetFileAttributes
+ ERROR( "lpszShortPath does not exist.\n" )
+ LOGEXIT("GetLongPathNameW returns DWORD 0\n");
+ PERF_EXIT(GetLongPathNameW);
+ return 0;
+ }
+
+ /* all lengths are # of TCHAR characters */
+ /* "required size" includes space for the terminating null character */
+ dwPathLen = PAL_wcslen(lpszShortPath)+1;
+
+ /* lpszLongPath == 0 means caller is asking only for size */
+ if ( lpszLongPath )
+ {
+ if ( dwPathLen > cchBuffer )
+ {
+ ERROR("Buffer is too small, need %d characters\n", dwPathLen);
+ SetLastError( ERROR_INSUFFICIENT_BUFFER );
+ } else
+ {
+ if ( lpszShortPath != lpszLongPath )
+ {
+ // Note: MSDN doesn't specify the behavior of GetLongPathName API
+ // if the buffers are overlap.
+ PAL_wcsncpy( lpszLongPath, lpszShortPath, cchBuffer );
+ }
+
+ /* actual size not including terminating null is returned */
+ dwPathLen--;
+ }
+ }
+
+ LOGEXIT("GetLongPathNameW returns DWORD %u\n", dwPathLen);
+ PERF_EXIT(GetLongPathNameW);
+ return dwPathLen;
+}
+
+
+/*++
+Function:
+ GetShortPathNameW
+
+See MSDN doc.
+
+Note:
+ Since short path names are not implemented (nor supported) in the PAL,
+ this function simply copies the given path into the new buffer.
+
+--*/
+DWORD
+PALAPI
+GetShortPathNameW(
+ IN LPCWSTR lpszLongPath,
+ OUT LPWSTR lpszShortPath,
+ IN DWORD cchBuffer)
+{
+ DWORD dwPathLen = 0;
+
+ PERF_ENTRY(GetShortPathNameW);
+ ENTRY("GetShortPathNameW(lpszLongPath=%p (%S), lpszShortPath=%p (%S), "
+ "cchBuffer=%d\n", lpszLongPath, lpszLongPath, lpszShortPath, lpszShortPath, cchBuffer);
+
+ if ( !lpszLongPath )
+ {
+ ERROR( "lpszLongPath was not a valid pointer.\n" )
+ SetLastError( ERROR_INVALID_PARAMETER );
+ LOGEXIT("GetShortPathNameW returns DWORD 0\n");
+ PERF_EXIT(GetShortPathNameW);
+ return 0;
+ }
+ else if (INVALID_FILE_ATTRIBUTES == GetFileAttributesW( lpszLongPath ))
+ {
+ // last error has been set by GetFileAttributes
+ ERROR( "lpszLongPath does not exist.\n" )
+ LOGEXIT("GetShortPathNameW returns DWORD 0\n");
+ PERF_EXIT(GetShortPathNameW);
+ return 0;
+ }
+
+ /* all lengths are # of TCHAR characters */
+ /* "required size" includes space for the terminating null character */
+ dwPathLen = PAL_wcslen(lpszLongPath)+1;
+
+ /* lpszShortPath == 0 means caller is asking only for size */
+ if ( lpszShortPath )
+ {
+ if ( dwPathLen > cchBuffer )
+ {
+ ERROR("Buffer is too small, need %d characters\n", dwPathLen);
+ SetLastError( ERROR_INSUFFICIENT_BUFFER );
+ } else
+ {
+ if ( lpszLongPath != lpszShortPath )
+ {
+ // Note: MSDN doesn't specify the behavior of GetShortPathName API
+ // if the buffers are overlap.
+ PAL_wcsncpy( lpszShortPath, lpszLongPath, cchBuffer );
+ }
+
+ /* actual size not including terminating null is returned */
+ dwPathLen--;
+ }
+ }
+
+ LOGEXIT("GetShortPathNameW returns DWORD %u\n", dwPathLen);
+ PERF_EXIT(GetShortPathNameW);
+ return dwPathLen;
+}
+
+
+/*++
+Function:
+ GetTempPathA
+
+See MSDN.
+
+Notes:
+ On Windows, the temp path is determined by the following steps:
+ 1. The value of the "TMP" environment variable, or if it doesn't exist,
+ 2. The value of the "TEMP" environment variable, or if it doesn't exist,
+ 3. The Windows directory.
+
+ On Unix, we follow in spirit:
+ 1. The value of the "TMPDIR" environment variable, or if it doesn't exist,
+ 2. The /tmp directory.
+ This is the same approach employed by mktemp.
+
+--*/
+DWORD
+PALAPI
+GetTempPathA(
+ IN DWORD nBufferLength,
+ OUT LPSTR lpBuffer)
+{
+ DWORD dwPathLen = 0;
+
+ PERF_ENTRY(GetTempPathA);
+ ENTRY("GetTempPathA(nBufferLength=%u, lpBuffer=%p)\n",
+ nBufferLength, lpBuffer);
+
+ if ( !lpBuffer )
+ {
+ ERROR( "lpBuffer was not a valid pointer.\n" )
+ SetLastError( ERROR_INVALID_PARAMETER );
+ LOGEXIT("GetTempPathA returns DWORD %u\n", dwPathLen);
+ PERF_EXIT(GetTempPathA);
+ return 0;
+ }
+
+ /* Try the TMPDIR environment variable. This is the same env var checked by mktemp. */
+ dwPathLen = GetEnvironmentVariableA("TMPDIR", lpBuffer, nBufferLength);
+ if (dwPathLen > 0)
+ {
+ /* The env var existed. dwPathLen will be the length without null termination
+ * if the entire value was successfully retrieved, or it'll be the length
+ * required to store the value with null termination.
+ */
+ if (dwPathLen < nBufferLength)
+ {
+ /* The environment variable fit in the buffer. Make sure it ends with '/'. */
+ if (lpBuffer[dwPathLen - 1] != '/')
+ {
+ /* If adding the slash would still fit in our provided buffer, do it. Otherwise,
+ * let the caller know how much space would be needed.
+ */
+ if (dwPathLen + 2 <= nBufferLength)
+ {
+ lpBuffer[dwPathLen++] = '/';
+ lpBuffer[dwPathLen] = '\0';
+ }
+ else
+ {
+ dwPathLen += 2;
+ }
+ }
+ }
+ else /* dwPathLen >= nBufferLength */
+ {
+ /* The value is too long for the supplied buffer. dwPathLen will now be the
+ * length required to hold the value, but we don't know whether that value
+ * is going to be '/' terminated. Since we'll need enough space for the '/', and since
+ * a caller would assume that the dwPathLen we return will be sufficient,
+ * we make sure to account for it in dwPathLen even if that means we end up saying
+ * one more byte of space is needed than actually is.
+ */
+ dwPathLen++;
+ }
+ }
+ else /* env var not found or was empty */
+ {
+ /* no luck, use /tmp/ */
+ const char *defaultDir = "/tmp/";
+ int defaultDirLen = strlen(defaultDir);
+ if (defaultDirLen < nBufferLength)
+ {
+ dwPathLen = defaultDirLen;
+ strcpy_s(lpBuffer, nBufferLength, defaultDir);
+ }
+ else
+ {
+ /* get the required length */
+ dwPathLen = defaultDirLen + 1;
+ }
+ }
+
+ if ( dwPathLen >= nBufferLength )
+ {
+ ERROR("Buffer is too small, need space for %d characters including null termination\n", dwPathLen);
+ SetLastError( ERROR_INSUFFICIENT_BUFFER );
+ }
+
+ LOGEXIT("GetTempPathA returns DWORD %u\n", dwPathLen);
+ PERF_EXIT(GetTempPathA);
+ return dwPathLen;
+}
+
+/*++
+Function:
+ GetTempPathW
+
+See MSDN.
+See also the comment for GetTempPathA.
+--*/
+DWORD
+PALAPI
+GetTempPathW(
+ IN DWORD nBufferLength,
+ OUT LPWSTR lpBuffer)
+{
+ PERF_ENTRY(GetTempPathW);
+ ENTRY("GetTempPathW(nBufferLength=%u, lpBuffer=%p)\n",
+ nBufferLength, lpBuffer);
+
+ if (!lpBuffer)
+ {
+ ERROR("lpBuffer was not a valid pointer.\n")
+ SetLastError(ERROR_INVALID_PARAMETER);
+ LOGEXIT("GetTempPathW returns DWORD 0\n");
+ PERF_EXIT(GetTempPathW);
+ return 0;
+ }
+
+ char TempBuffer[nBufferLength > 0 ? nBufferLength : 1];
+ DWORD dwRetVal = GetTempPathA( nBufferLength, TempBuffer );
+
+ if ( dwRetVal >= nBufferLength )
+ {
+ ERROR( "lpBuffer was not large enough.\n" )
+ SetLastError( ERROR_INSUFFICIENT_BUFFER );
+ *lpBuffer = '\0';
+ }
+ else if ( dwRetVal != 0 )
+ {
+ /* Convert to wide. */
+ if ( 0 == MultiByteToWideChar( CP_ACP, 0, TempBuffer, -1,
+ lpBuffer, dwRetVal + 1 ) )
+ {
+ ASSERT( "An error occurred while converting the string to wide.\n" );
+ SetLastError( ERROR_INTERNAL_ERROR );
+ dwRetVal = 0;
+ }
+ }
+ else
+ {
+ ERROR( "The function failed.\n" );
+ *lpBuffer = '\0';
+ }
+
+ LOGEXIT("GetTempPathW returns DWORD %u\n", dwRetVal );
+ PERF_EXIT(GetTempPathW);
+ return dwRetVal;
+}
+
+
+
+/*++
+Function:
+ FileDosToUnixPathA
+
+Abstract:
+ Change a DOS path to a Unix path.
+
+ Replaces '\' by '/', removes any trailing dots on directory/filenames,
+ and changes '*.*' to be equal to '*'
+
+Parameter:
+ IN/OUT lpPath: path to be modified
+--*/
+void
+FILEDosToUnixPathA(
+ LPSTR lpPath)
+{
+ LPSTR p;
+ LPSTR pPointAtDot=NULL;
+ char charBeforeFirstDot='\0';
+
+ TRACE("Original DOS path = [%s]\n", lpPath);
+
+ if (!lpPath)
+ {
+ return;
+ }
+
+ for (p = lpPath; *p; p++)
+ {
+ /* Make the \\ to / switch first */
+ if (*p == '\\')
+ {
+ /* Replace \ with / */
+ *p = '/';
+ }
+
+ if (pPointAtDot)
+ {
+ /* If pPointAtDot is not NULL, it is pointing at the first encountered
+ dot. If we encountered a \, that means it could be a trailing dot */
+ if (*p == '/')
+ {
+ /* If char before the first dot is a '\' or '.' (special case if the
+ dot is the first char in the path) , then we leave it alone,
+ because it is either . or .., otherwise it is a trailing dot
+ pattern and will be truncated */
+ if (charBeforeFirstDot != '.' && charBeforeFirstDot != '/')
+ {
+ memmove(pPointAtDot,p,(strlen(p)*sizeof(char))+1);
+ p = pPointAtDot;
+ }
+ pPointAtDot = NULL; /* Need to reset this */
+ }
+ else if (*p == '*')
+ {
+ /* Check our size before doing anything with our pointers */
+ if ((p - lpPath) >= 3)
+ {
+ /* At this point, we know that there is 1 or more dots and
+ then a star. AND we know the size of our string at this
+ point is at least 3 (so we can go backwards from our pointer
+ safely AND there could possilby be two characters back)
+ So lets check if there is a '*' and a '.' before, if there
+ is, replace just a '*'. Otherwise, reset pPointAtDot to NULL
+ and do nothing */
+ if (p[-2] == '*' &&
+ p[-1] == '.' &&
+ p[0] == '*')
+ {
+ memmove(&(p[-2]),p,(strlen(p)*sizeof(char))+1);
+ }
+
+ pPointAtDot = NULL;
+ }
+ }
+ else if (*p != '.')
+ {
+ /* If we are here, that means that this is NOT a trailing dot,
+ some other character is here, so forget our pointer */
+ pPointAtDot = NULL;
+ }
+ }
+ else
+ {
+ if (*p == '.')
+ {
+ /* If pPointAtDot is NULL, and we encounter a dot, save the pointer */
+ pPointAtDot = p;
+ if (pPointAtDot != lpPath)
+ {
+ charBeforeFirstDot = p[-1];
+ }
+ else
+ {
+ charBeforeFirstDot = lpPath[0];
+ }
+ }
+ }
+ }
+
+ /* If pPointAtDot still points at anything, then we still have trailing dots.
+ Truncate at pPointAtDot, unless the dots are path specifiers (. or ..) */
+ if (pPointAtDot)
+ {
+ /* make sure the trailing dots don't follow a '/', and that they aren't
+ the only thing in the name */
+ if(pPointAtDot != lpPath && *(pPointAtDot-1) != '/')
+ {
+ *pPointAtDot = '\0';
+ }
+ }
+
+ TRACE("Resulting Unix path = [%s]\n", lpPath);
+}
+
+void
+FILEDosToUnixPathA(
+ PathCharString& lpPath)
+{
+
+ SIZE_T len = lpPath.GetCount();
+ LPSTR lpPathBuf = lpPath.OpenStringBuffer(len);
+ FILEDosToUnixPathA(lpPathBuf);
+ lpPath.CloseBuffer(len);
+
+}
+
+/*++
+Function:
+ FileDosToUnixPathW
+
+Abstract:
+ Change a DOS path to a Unix path.
+
+ Replaces '\' by '/', removes any trailing dots on directory/filenames,
+ and changes '*.*' to be equal to '*'
+
+Parameter:
+ IN/OUT lpPath: path to be modified
+--*/
+void
+FILEDosToUnixPathW(
+ LPWSTR lpPath)
+{
+ LPWSTR p;
+ LPWSTR pPointAtDot=NULL;
+ WCHAR charBeforeFirstDot='\0';
+
+ TRACE("Original DOS path = [%S]\n", lpPath);
+
+ if (!lpPath)
+ {
+ return;
+ }
+
+ for (p = lpPath; *p; p++)
+ {
+ /* Make the \\ to / switch first */
+ if (*p == '\\')
+ {
+ /* Replace \ with / */
+ *p = '/';
+ }
+
+ if (pPointAtDot)
+ {
+ /* If pPointAtDot is not NULL, it is pointing at the first encountered
+ dot. If we encountered a \, that means it could be a trailing dot */
+ if (*p == '/')
+ {
+ /* If char before the first dot is a '\' or '.' (special case if the
+ dot is the first char in the path) , then we leave it alone,
+ because it is either . or .., otherwise it is a trailing dot
+ pattern and will be truncated */
+ if (charBeforeFirstDot != '.' && charBeforeFirstDot != '/')
+ {
+ memmove(pPointAtDot,p,((PAL_wcslen(p)+1)*sizeof(WCHAR)));
+ p = pPointAtDot;
+ }
+ pPointAtDot = NULL; /* Need to reset this */
+ }
+ else if (*p == '*')
+ {
+ /* Check our size before doing anything with our pointers */
+ if ((p - lpPath) >= 3)
+ {
+ /* At this point, we know that there is 1 or more dots and
+ then a star. AND we know the size of our string at this
+ point is at least 3 (so we can go backwards from our pointer
+ safely AND there could possilby be two characters back)
+ So lets check if there is a '*' and a '.' before, if there
+ is, replace just a '*'. Otherwise, reset pPointAtDot to NULL
+ and do nothing */
+ if (p[-2] == '*' &&
+ p[-1] == '.' &&
+ p[0] == '*')
+ {
+ memmove(&(p[-2]),p,(PAL_wcslen(p)*sizeof(WCHAR)));
+ }
+
+ pPointAtDot = NULL;
+ }
+ }
+ else if (*p != '.')
+ {
+ /* If we are here, that means that this is NOT a trailing dot,
+ some other character is here, so forget our pointer */
+ pPointAtDot = NULL;
+ }
+ }
+ else
+ {
+ if (*p == '.')
+ {
+ /* If pPointAtDot is NULL, and we encounter a dot, save the pointer */
+ pPointAtDot = p;
+ if (pPointAtDot != lpPath)
+ {
+ charBeforeFirstDot = p[-1];
+ }
+ else
+ {
+ charBeforeFirstDot = lpPath[0];
+ }
+ }
+ }
+ }
+
+ /* If pPointAtDot still points at anything, then we still have trailing dots.
+ Truncate at pPointAtDot, unless the dots are path specifiers (. or ..) */
+ if (pPointAtDot)
+ {
+ /* make sure the trailing dots don't follow a '/', and that they aren't
+ the only thing in the name */
+ if(pPointAtDot != lpPath && *(pPointAtDot-1) != '/')
+ {
+ *pPointAtDot = '\0';
+ }
+ }
+
+ TRACE("Resulting Unix path = [%S]\n", lpPath);
+}
+
+
+/*++
+Function:
+ FileUnixToDosPathA
+
+Abstract:
+ Change a Unix path to a DOS path. Replace '/' by '\'.
+
+Parameter:
+ IN/OUT lpPath: path to be modified
+--*/
+void
+FILEUnixToDosPathA(
+ LPSTR lpPath)
+{
+ LPSTR p;
+
+ TRACE("Original Unix path = [%s]\n", lpPath);
+
+ if (!lpPath)
+ return;
+
+ for (p = lpPath; *p; p++)
+ {
+ if (*p == '/')
+ *p = '\\';
+ }
+
+ TRACE("Resulting DOS path = [%s]\n", lpPath);
+}
+
+
+/*++
+Function:
+ FILEGetDirectoryFromFullPathA
+
+Parse the given path. If it contains a directory part and a file part,
+put the directory part into the supplied buffer, and return the number of
+characters written to the buffer. If the buffer is not large enough,
+return the required size of the buffer including the NULL character. If
+there is no directory part in the path, return 0.
+--*/
+DWORD FILEGetDirectoryFromFullPathA( LPCSTR lpFullPath,
+ DWORD nBufferLength,
+ LPSTR lpBuffer )
+{
+ int full_len, dir_len, i;
+ LPCSTR lpDirEnd;
+ DWORD dwRetLength;
+
+ full_len = lstrlenA( lpFullPath );
+
+ /* look for the first path separator backwards */
+ lpDirEnd = lpFullPath + full_len - 1;
+ while( lpDirEnd >= lpFullPath && *lpDirEnd != '/' && *lpDirEnd != '\\')
+ --lpDirEnd;
+
+ dir_len = lpDirEnd - lpFullPath + 1; /* +1 for fencepost */
+
+ if ( dir_len <= 0 )
+ {
+ dwRetLength = 0;
+ }
+ else if (static_cast<DWORD>(dir_len) >= nBufferLength)
+ {
+ dwRetLength = dir_len + 1; /* +1 for NULL char */
+ }
+ else
+ {
+ /* put the directory into the buffer, including 1 or more
+ trailing path separators */
+ for( i = 0; i < dir_len; ++i )
+ *(lpBuffer + i) = *(lpFullPath + i);
+
+ *(lpBuffer + i) = '\0';
+
+ dwRetLength = dir_len;
+ }
+
+ return( dwRetLength );
+}
+
+/*++
+Function:
+ FILEGetFileNameFromFullPath
+
+Given a full path, return a pointer to the first char of the filename part.
+--*/
+LPCSTR FILEGetFileNameFromFullPathA( LPCSTR lpFullPath )
+{
+ int DirLen = FILEGetDirectoryFromFullPathA( lpFullPath, 0, NULL );
+
+ if ( DirLen > 0 )
+ {
+ return lpFullPath + DirLen - 1;
+ }
+ else
+ {
+ return lpFullPath;
+ }
+}
+
+/*++
+FILECanonicalizePath
+ Removes all instances of '/./', '/../' and '//' from an absolute path.
+
+Parameters:
+ LPSTR lpUnixPath : absolute path to modify, in Unix format
+
+(no return value)
+
+Notes :
+-behavior is undefined if path is not absolute
+-the order of steps *is* important: /one/./../two would give /one/two
+ instead of /two if step 3 was done before step 2
+-reason for this function is that GetFullPathName can't use realpath(), since
+ realpath() requires the given path to be valid and GetFullPathName does not.
+--*/
+void FILECanonicalizePath(LPSTR lpUnixPath)
+{
+ LPSTR slashslashptr;
+ LPSTR dotdotptr;
+ LPSTR slashdotptr;
+ LPSTR slashptr;
+
+ /* step 1 : replace '//' sequences by a single '/' */
+
+ slashslashptr = lpUnixPath;
+ while(1)
+ {
+ slashslashptr = strstr(slashslashptr,"//");
+ if(NULL == slashslashptr)
+ {
+ break;
+ }
+ /* remove extra '/' */
+ TRACE("stripping '//' from %s\n", lpUnixPath);
+ memmove(slashslashptr,slashslashptr+1,strlen(slashslashptr+1)+1);
+ }
+
+ /* step 2 : replace '/./' sequences by a single '/' */
+
+ slashdotptr = lpUnixPath;
+ while(1)
+ {
+ slashdotptr = strstr(slashdotptr,"/./");
+ if(NULL == slashdotptr)
+ {
+ break;
+ }
+ /* strip the extra '/.' */
+ TRACE("removing '/./' sequence from %s\n", lpUnixPath);
+ memmove(slashdotptr,slashdotptr+2,strlen(slashdotptr+2)+1);
+ }
+
+ /* step 3 : replace '/<name>/../' sequences by a single '/' */
+
+ while(1)
+ {
+ dotdotptr = strstr(lpUnixPath,"/../");
+ if(NULL == dotdotptr)
+ {
+ break;
+ }
+ if(dotdotptr == lpUnixPath)
+ {
+ /* special case : '/../' at the beginning of the path are replaced
+ by a single '/' */
+ TRACE("stripping leading '/../' from %s\n", lpUnixPath);
+ memmove(lpUnixPath, lpUnixPath+3,strlen(lpUnixPath+3)+1);
+ continue;
+ }
+
+ /* null-terminate the string before the '/../', so that strrchr will
+ start looking right before it */
+ *dotdotptr = '\0';
+ slashptr = strrchr(lpUnixPath,'/');
+ if(NULL == slashptr)
+ {
+ /* this happens if this function was called with a relative path.
+ don't do that. */
+ ASSERT("can't find leading '/' before '/../ sequence\n");
+ break;
+ }
+ TRACE("removing '/<dir>/../' sequence from %s\n", lpUnixPath);
+ memmove(slashptr,dotdotptr+3,strlen(dotdotptr+3)+1);
+ }
+
+ /* step 4 : remove a trailing '/..' */
+
+ dotdotptr = strstr(lpUnixPath,"/..");
+ if(dotdotptr == lpUnixPath)
+ {
+ /* if the full path is simply '/..', replace it by '/' */
+ lpUnixPath[1] = '\0';
+ }
+ else if(NULL != dotdotptr && '\0' == dotdotptr[3])
+ {
+ *dotdotptr = '\0';
+ slashptr = strrchr(lpUnixPath,'/');
+ if(NULL != slashptr)
+ {
+ /* make sure the last slash isn't the root */
+ if (slashptr == lpUnixPath)
+ {
+ lpUnixPath[1] = '\0';
+ }
+ else
+ {
+ *slashptr = '\0';
+ }
+ }
+ }
+
+ /* step 5 : remove a traling '/.' */
+
+ slashdotptr = strstr(lpUnixPath,"/.");
+ if (slashdotptr != NULL && slashdotptr[2] == '\0')
+ {
+ if(slashdotptr == lpUnixPath)
+ {
+ // if the full path is simply '/.', replace it by '/' */
+ lpUnixPath[1] = '\0';
+ }
+ else
+ {
+ *slashdotptr = '\0';
+ }
+ }
+}
+
+
+/*++
+Function:
+ SearchPathA
+
+See MSDN doc.
+
+PAL-specific notes :
+-lpPath must be non-NULL; path delimiters are platform-dependent (':' for Unix)
+-lpFileName must be non-NULL, may be an absolute path
+-lpExtension must be NULL
+-lpFilePart (if non-NULL) doesn't need to be used (but we do)
+--*/
+DWORD
+PALAPI
+SearchPathA(
+ IN LPCSTR lpPath,
+ IN LPCSTR lpFileName,
+ IN LPCSTR lpExtension,
+ IN DWORD nBufferLength,
+ OUT LPSTR lpBuffer,
+ OUT LPSTR *lpFilePart
+ )
+{
+ DWORD nRet = 0;
+ CHAR * FullPath;
+ size_t FullPathLength = 0;
+ PathCharString FullPathPS;
+ PathCharString CanonicalFullPathPS;
+ CHAR * CanonicalFullPath;
+ LPCSTR pPathStart;
+ LPCSTR pPathEnd;
+ size_t PathLength;
+ size_t FileNameLength;
+ DWORD length;
+ DWORD dw;
+
+ PERF_ENTRY(SearchPathA);
+ ENTRY("SearchPathA(lpPath=%p (%s), lpFileName=%p (%s), lpExtension=%p, "
+ "nBufferLength=%u, lpBuffer=%p, lpFilePart=%p)\n",
+ lpPath,
+ lpPath, lpFileName, lpFileName, lpExtension, nBufferLength, lpBuffer,
+ lpFilePart);
+
+ /* validate parameters */
+
+ if(NULL == lpPath)
+ {
+ ASSERT("lpPath may not be NULL\n");
+ SetLastError(ERROR_INVALID_PARAMETER);
+ goto done;
+ }
+ if(NULL == lpFileName)
+ {
+ ASSERT("lpFileName may not be NULL\n");
+ SetLastError(ERROR_INVALID_PARAMETER);
+ goto done;
+ }
+ if(NULL != lpExtension)
+ {
+ ASSERT("lpExtension must be NULL, is %p instead\n", lpExtension);
+ SetLastError(ERROR_INVALID_PARAMETER);
+ goto done;
+ }
+
+ FileNameLength = strlen(lpFileName);
+
+ /* special case : if file name contains absolute path, don't search the
+ provided path */
+ if('\\' == lpFileName[0] || '/' == lpFileName[0])
+ {
+ /* Canonicalize the path to deal with back-to-back '/', etc. */
+ length = FileNameLength;
+ CanonicalFullPath = CanonicalFullPathPS.OpenStringBuffer(length);
+ if (NULL == CanonicalFullPath)
+ {
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ goto done;
+ }
+ dw = GetFullPathNameA(lpFileName, length+1, CanonicalFullPath, NULL);
+ CanonicalFullPathPS.CloseBuffer(dw);
+
+ if (length+1 < dw)
+ {
+ CanonicalFullPath = CanonicalFullPathPS.OpenStringBuffer(dw-1);
+ if (NULL == CanonicalFullPath)
+ {
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ goto done;
+ }
+ dw = GetFullPathNameA(lpFileName, dw,
+ CanonicalFullPath, NULL);
+ CanonicalFullPathPS.CloseBuffer(dw);
+ }
+
+ if (dw == 0)
+ {
+ WARN("couldn't canonicalize path <%s>, error is %#x. failing.\n",
+ lpFileName, GetLastError());
+ SetLastError(ERROR_INVALID_PARAMETER);
+ goto done;
+ }
+
+ /* see if the file exists */
+ if(0 == access(CanonicalFullPath, F_OK))
+ {
+ /* found it */
+ nRet = dw;
+ }
+ }
+ else
+ {
+ LPCSTR pNextPath;
+
+ pNextPath = lpPath;
+
+ while (*pNextPath)
+ {
+ pPathStart = pNextPath;
+
+ /* get a pointer to the end of the first path in pPathStart */
+ pPathEnd = strchr(pPathStart, ':');
+ if (!pPathEnd)
+ {
+ pPathEnd = pPathStart + strlen(pPathStart);
+ /* we want to break out of the loop after this pass, so let
+ *pNextPath be '\0' */
+ pNextPath = pPathEnd;
+ }
+ else
+ {
+ /* point to the next component in the path string */
+ pNextPath = pPathEnd+1;
+ }
+
+ PathLength = pPathEnd-pPathStart;
+
+ if(0 == PathLength)
+ {
+ /* empty component : there were 2 consecutive ':' */
+ continue;
+ }
+
+ /* Construct a pathname by concatenating one path from lpPath, '/'
+ and lpFileName */
+ FullPathLength = PathLength + FileNameLength;
+ FullPath = FullPathPS.OpenStringBuffer(FullPathLength+1);
+ if (NULL == FullPath)
+ {
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ goto done;
+ }
+ memcpy(FullPath, pPathStart, PathLength);
+ FullPath[PathLength] = '/';
+ if (strcpy_s(&FullPath[PathLength+1], FullPathLength+1-PathLength, lpFileName) != SAFECRT_SUCCESS)
+ {
+ ERROR("strcpy_s failed!\n");
+ SetLastError( ERROR_FILENAME_EXCED_RANGE );
+ nRet = 0;
+ goto done;
+ }
+
+ FullPathPS.CloseBuffer(FullPathLength+1);
+ /* Canonicalize the path to deal with back-to-back '/', etc. */
+ length = MAX_LONGPATH; //Use it for first try
+ CanonicalFullPath = CanonicalFullPathPS.OpenStringBuffer(length);
+ if (NULL == CanonicalFullPath)
+ {
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ goto done;
+ }
+ dw = GetFullPathNameA(FullPath, length+1,
+ CanonicalFullPath, NULL);
+ CanonicalFullPathPS.CloseBuffer(dw);
+
+ if (length+1 < dw)
+ {
+ CanonicalFullPath = CanonicalFullPathPS.OpenStringBuffer(dw-1);
+ dw = GetFullPathNameA(FullPath, dw,
+ CanonicalFullPath, NULL);
+ CanonicalFullPathPS.CloseBuffer(dw);
+ }
+
+ if (dw == 0)
+ {
+ /* Call failed - possibly low memory. Skip the path */
+ WARN("couldn't canonicalize path <%s>, error is %#x. "
+ "skipping it\n", FullPath, GetLastError());
+ continue;
+ }
+
+ /* see if the file exists */
+ if(0 == access(CanonicalFullPath, F_OK))
+ {
+ /* found it */
+ nRet = dw;
+ break;
+ }
+ }
+ }
+
+ if (nRet == 0)
+ {
+ /* file not found anywhere; say so. in Windows, this always seems to say
+ FILE_NOT_FOUND, even if path doesn't exist */
+ SetLastError(ERROR_FILE_NOT_FOUND);
+ }
+ else
+ {
+ if (nRet < nBufferLength)
+ {
+ if(NULL == lpBuffer)
+ {
+ /* Windows merily crashes here, but let's not */
+ ERROR("caller told us buffer size was %d, but buffer is NULL\n",
+ nBufferLength);
+ SetLastError(ERROR_INVALID_PARAMETER);
+ nRet = 0;
+ goto done;
+ }
+
+ if (strcpy_s(lpBuffer, nBufferLength, CanonicalFullPath) != SAFECRT_SUCCESS)
+ {
+ ERROR("strcpy_s failed!\n");
+ SetLastError( ERROR_FILENAME_EXCED_RANGE );
+ nRet = 0;
+ goto done;
+ }
+
+ if(NULL != lpFilePart)
+ {
+ *lpFilePart = strrchr(lpBuffer,'/');
+ if(NULL == *lpFilePart)
+ {
+ ASSERT("no '/' in full path!\n");
+ }
+ else
+ {
+ /* point to character after last '/' */
+ (*lpFilePart)++;
+ }
+ }
+ }
+ else
+ {
+ /* if buffer is too small, report required length, including
+ terminating null */
+ nRet++;
+ }
+ }
+done:
+ LOGEXIT("SearchPathA returns DWORD %u\n", nRet);
+ PERF_EXIT(SearchPathA);
+ return nRet;
+}
+
+
+/*++
+Function:
+ SearchPathW
+
+See MSDN doc.
+
+PAL-specific notes :
+-lpPath must be non-NULL; path delimiters are platform-dependent (':' for Unix)
+-lpFileName must be non-NULL, may be an absolute path
+-lpExtension must be NULL
+-lpFilePart (if non-NULL) doesn't need to be used (but we do)
+--*/
+DWORD
+PALAPI
+SearchPathW(
+ IN LPCWSTR lpPath,
+ IN LPCWSTR lpFileName,
+ IN LPCWSTR lpExtension,
+ IN DWORD nBufferLength,
+ OUT LPWSTR lpBuffer,
+ OUT LPWSTR *lpFilePart
+ )
+{
+ DWORD nRet = 0;
+ WCHAR * FullPath;
+ size_t FullPathLength = 0;
+ PathWCharString FullPathPS;
+ LPCWSTR pPathStart;
+ LPCWSTR pPathEnd;
+ size_t PathLength;
+ size_t FileNameLength;
+ DWORD dw;
+ DWORD length;
+ char * AnsiPath;
+ PathCharString AnsiPathPS;
+ size_t CanonicalPathLength;
+ int canonical_size;
+ WCHAR * CanonicalPath;
+ PathWCharString CanonicalPathPS;
+
+ PERF_ENTRY(SearchPathW);
+ ENTRY("SearchPathW(lpPath=%p (%S), lpFileName=%p (%S), lpExtension=%p, "
+ "nBufferLength=%u, lpBuffer=%p, lpFilePart=%p)\n",
+ lpPath,
+ lpPath, lpFileName, lpFileName, lpExtension, nBufferLength, lpBuffer,
+ lpFilePart);
+
+ /* validate parameters */
+
+ if(NULL == lpPath)
+ {
+ ASSERT("lpPath may not be NULL\n");
+ SetLastError(ERROR_INVALID_PARAMETER);
+ goto done;
+ }
+ if(NULL == lpFileName)
+ {
+ ASSERT("lpFileName may not be NULL\n");
+ SetLastError(ERROR_INVALID_PARAMETER);
+ goto done;
+ }
+ if(NULL != lpExtension)
+ {
+ ASSERT("lpExtension must be NULL, is %p instead\n", lpExtension);
+ SetLastError(ERROR_INVALID_PARAMETER);
+ goto done;
+ }
+
+ /* special case : if file name contains absolute path, don't search the
+ provided path */
+ if('\\' == lpFileName[0] || '/' == lpFileName[0])
+ {
+ /* Canonicalize the path to deal with back-to-back '/', etc. */
+ length = MAX_LONGPATH; //Use it for first try
+ CanonicalPath = CanonicalPathPS.OpenStringBuffer(length);
+ if (NULL == CanonicalPath)
+ {
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ goto done;
+ }
+ dw = GetFullPathNameW(lpFileName, length+1, CanonicalPath, NULL);
+ CanonicalPathPS.CloseBuffer(dw);
+ if (length+1 < dw)
+ {
+ CanonicalPath = CanonicalPathPS.OpenStringBuffer(dw-1);
+ if (NULL == CanonicalPath)
+ {
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ goto done;
+ }
+ dw = GetFullPathNameW(lpFileName, dw, CanonicalPath, NULL);
+ CanonicalPathPS.CloseBuffer(dw);
+ }
+
+ if (dw == 0)
+ {
+ WARN("couldn't canonicalize path <%S>, error is %#x. failing.\n",
+ lpPath, GetLastError());
+ SetLastError(ERROR_INVALID_PARAMETER);
+ goto done;
+ }
+
+ /* see if the file exists */
+ CanonicalPathLength = (PAL_wcslen(CanonicalPath)+1) * MaxWCharToAcpLengthRatio;
+ AnsiPath = AnsiPathPS.OpenStringBuffer(CanonicalPathLength);
+ if (NULL == AnsiPath)
+ {
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ goto done;
+ }
+ canonical_size = WideCharToMultiByte(CP_ACP, 0, CanonicalPath, -1,
+ AnsiPath, CanonicalPathLength, NULL, NULL);
+ AnsiPathPS.CloseBuffer(canonical_size);
+
+ if(0 == access(AnsiPath, F_OK))
+ {
+ /* found it */
+ nRet = dw;
+ }
+ }
+ else
+ {
+ LPCWSTR pNextPath;
+
+ pNextPath = lpPath;
+
+ FileNameLength = PAL_wcslen(lpFileName);
+
+ while (*pNextPath)
+ {
+ pPathStart = pNextPath;
+
+ /* get a pointer to the end of the first path in pPathStart */
+ pPathEnd = PAL_wcschr(pPathStart, ':');
+ if (!pPathEnd)
+ {
+ pPathEnd = pPathStart + PAL_wcslen(pPathStart);
+ /* we want to break out of the loop after this pass, so let
+ *pNextPath be '\0' */
+ pNextPath = pPathEnd;
+ }
+ else
+ {
+ /* point to the next component in the path string */
+ pNextPath = pPathEnd+1;
+ }
+
+ PathLength = pPathEnd-pPathStart;
+
+ if(0 == PathLength)
+ {
+ /* empty component : there were 2 consecutive ':' */
+ continue;
+ }
+
+ /* Construct a pathname by concatenating one path from lpPath, '/'
+ and lpFileName */
+ FullPathLength = PathLength + FileNameLength;
+ FullPath = FullPathPS.OpenStringBuffer(FullPathLength+1);
+ if (NULL == FullPath)
+ {
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ goto done;
+ }
+ memcpy(FullPath, pPathStart, PathLength*sizeof(WCHAR));
+ FullPath[PathLength] = '/';
+ PAL_wcscpy(&FullPath[PathLength+1], lpFileName);
+
+ FullPathPS.CloseBuffer(FullPathLength+1);
+
+ /* Canonicalize the path to deal with back-to-back '/', etc. */
+ length = MAX_LONGPATH; //Use it for first try
+ CanonicalPath = CanonicalPathPS.OpenStringBuffer(length);
+ if (NULL == CanonicalPath)
+ {
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ goto done;
+ }
+ dw = GetFullPathNameW(FullPath, length+1,
+ CanonicalPath, NULL);
+ CanonicalPathPS.CloseBuffer(dw);
+
+ if (length+1 < dw)
+ {
+ CanonicalPath = CanonicalPathPS.OpenStringBuffer(dw-1);
+ if (NULL == CanonicalPath)
+ {
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ goto done;
+ }
+ dw = GetFullPathNameW(FullPath, dw, CanonicalPath, NULL);
+ CanonicalPathPS.CloseBuffer(dw);
+ }
+
+ if (dw == 0)
+ {
+ /* Call failed - possibly low memory. Skip the path */
+ WARN("couldn't canonicalize path <%S>, error is %#x. "
+ "skipping it\n", FullPath, GetLastError());
+ continue;
+ }
+
+ /* see if the file exists */
+ CanonicalPathLength = (PAL_wcslen(CanonicalPath)+1) * MaxWCharToAcpLengthRatio;
+ AnsiPath = AnsiPathPS.OpenStringBuffer(CanonicalPathLength);
+ if (NULL == AnsiPath)
+ {
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ goto done;
+ }
+ canonical_size = WideCharToMultiByte(CP_ACP, 0, CanonicalPath, -1,
+ AnsiPath, CanonicalPathLength, NULL, NULL);
+ AnsiPathPS.CloseBuffer(canonical_size);
+
+ if(0 == access(AnsiPath, F_OK))
+ {
+ /* found it */
+ nRet = dw;
+ break;
+ }
+ }
+ }
+
+ if (nRet == 0)
+ {
+ /* file not found anywhere; say so. in Windows, this always seems to say
+ FILE_NOT_FOUND, even if path doesn't exist */
+ SetLastError(ERROR_FILE_NOT_FOUND);
+ }
+ else
+ {
+ /* find out the required buffer size, copy path to buffer if it's
+ large enough */
+ nRet = PAL_wcslen(CanonicalPath)+1;
+ if(nRet <= nBufferLength)
+ {
+ if(NULL == lpBuffer)
+ {
+ /* Windows merily crashes here, but let's not */
+ ERROR("caller told us buffer size was %d, but buffer is NULL\n",
+ nBufferLength);
+ SetLastError(ERROR_INVALID_PARAMETER);
+ nRet = 0;
+ goto done;
+ }
+ PAL_wcscpy(lpBuffer, CanonicalPath);
+
+ /* don't include the null-terminator in the count if buffer was
+ large enough */
+ nRet--;
+
+ if(NULL != lpFilePart)
+ {
+ *lpFilePart = PAL_wcsrchr(lpBuffer, '/');
+ if(NULL == *lpFilePart)
+ {
+ ASSERT("no '/' in full path!\n");
+ }
+ else
+ {
+ /* point to character after last '/' */
+ (*lpFilePart)++;
+ }
+ }
+ }
+ }
+done:
+ LOGEXIT("SearchPathW returns DWORD %u\n", nRet);
+ PERF_EXIT(SearchPathW);
+ return nRet;
+}
+
+/*++
+Function:
+ PathFindFileNameW
+
+See MSDN doc.
+--*/
+LPWSTR
+PALAPI
+PathFindFileNameW(
+ IN LPCWSTR pPath
+ )
+{
+ PERF_ENTRY(PathFindFileNameW);
+ ENTRY("PathFindFileNameW(pPath=%p (%S))\n",
+ pPath?pPath:W16_NULLSTRING,
+ pPath?pPath:W16_NULLSTRING);
+
+ LPWSTR ret = (LPWSTR)pPath;
+ if (ret != NULL && *ret != W('\0'))
+ {
+ ret = PAL_wcschr(ret, W('\0')) - 1;
+ if (ret > pPath && *ret == W('/'))
+ {
+ ret--;
+ }
+ while (ret > pPath && *ret != W('/'))
+ {
+ ret--;
+ }
+ if (*ret == W('/') && *(ret + 1) != W('\0'))
+ {
+ ret++;
+ }
+ }
+
+ LOGEXIT("PathFindFileNameW returns %S\n", ret);
+ PERF_EXIT(PathFindFileNameW);
+ return ret;
+}
diff --git a/src/pal/src/file/shmfilelockmgr.cpp b/src/pal/src/file/shmfilelockmgr.cpp
new file mode 100644
index 0000000000..a586abddbd
--- /dev/null
+++ b/src/pal/src/file/shmfilelockmgr.cpp
@@ -0,0 +1,1032 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ shmfilelockmgr.cpp
+
+Abstract:
+ Shared memory based file lock manager
+
+
+
+--*/
+
+#include "pal/thread.hpp"
+#include "pal/malloc.hpp"
+#include "pal/dbgmsg.h"
+#include "shmfilelockmgr.hpp"
+
+using namespace CorUnix;
+
+SET_DEFAULT_DEBUG_CHANNEL(FILE);
+
+PAL_ERROR
+FILEAddNewLockedRgn(
+ SHMFILELOCKS* fileLocks,
+ PVOID pvControllerInstance,
+ SHMFILELOCKRGNS *insertAfter,
+ UINT64 lockRgnStart,
+ UINT64 nbBytesToLock,
+ LOCK_TYPE lockType
+ );
+
+PAL_ERROR
+FILELockFileRegion(
+ SHMPTR shmFileLocks,
+ PVOID pvControllerInstance,
+ UINT64 lockRgnStart,
+ UINT64 nbBytesToLock,
+ LOCK_TYPE lockAction
+ );
+
+PAL_ERROR
+FILEUnlockFileRegion(
+ SHMPTR shmFileLocks,
+ PVOID pvControllerInstance,
+ UINT64 unlockRgnStart,
+ UINT64 nbBytesToUnlock,
+ LOCK_TYPE unlockType
+ );
+
+void
+FILECleanUpLockedRgn(
+ SHMPTR shmFileLocks,
+ DWORD dwAccessRights,
+ PVOID pvControllerInstance
+ );
+
+PAL_ERROR
+FILEGetSHMFileLocks(
+ LPCSTR filename,
+ SHMPTR *pshmFileLocks,
+ BOOL noCreate
+ );
+
+/* return TRUE if LockToTest region is behind lockRgn, FALSE otherwise */
+#define IS_LOCK_BEFORE(LockToTest, lockRgn) \
+ (((LockToTest)->lockRgnStart + (LockToTest)->nbBytesLocked) <= \
+ (lockRgn)->lockRgnStart)
+
+/* return TRUE if LockToTest region intersect with lockRgn, FALSE otherwise */
+#define IS_LOCK_INTERSECT(LockToTest, lockRgn) \
+ (!IS_LOCK_BEFORE(LockToTest, lockRgn) && !IS_LOCK_BEFORE(lockRgn, LockToTest))
+
+/* return TRUE if LockToTest region and lockRgn have the same file pointer and
+ the same process Id, FALSE otherwise */
+#define IS_LOCK_HAVE_SAME_OWNER(LockToTest, lockRgn) \
+ (((LockToTest)->pvControllerInstance == (lockRgn)->pvControllerInstance) && \
+ ((LockToTest)->processId == (lockRgn)->processId))
+
+/* return TRUE if LockToTest region and lockRgn represent the same lock,
+ FALSE otherwise*/
+#define IS_LOCK_EQUAL(LockToTest, lockRgn) \
+ (((LockToTest)->processId == (lockRgn)->processId) && \
+ ((LockToTest)->pvControllerInstance == (lockRgn)->pvControllerInstance) && \
+ ((LockToTest)->lockRgnStart == (lockRgn)->lockRgnStart) && \
+ ((LockToTest)->nbBytesLocked == (lockRgn)->nbBytesLocked) && \
+ ((LockToTest)->lockType == (lockRgn)->lockType))
+
+PAL_ERROR
+CSharedMemoryFileLockMgr::GetLockControllerForFile(
+ CPalThread *pThread, // IN, OPTIONAL
+ LPCSTR szFileName,
+ DWORD dwAccessRights,
+ DWORD dwShareMode,
+ IFileLockController **ppLockController // OUT
+ )
+{
+ PAL_ERROR palError = NO_ERROR;
+ SHMPTR shmFileLocks = SHMNULL;
+ SHMFILELOCKS* fileLocks = NULL;
+ CSharedMemoryFileLockController *pController = NULL;
+
+ SHMLock();
+
+ palError = FILEGetSHMFileLocks(szFileName, &shmFileLocks, FALSE);
+ if (NO_ERROR != palError)
+ {
+ goto GetLockControllerForFileExit;
+ }
+
+ if (SHMPTR_TO_TYPED_PTR_BOOL(SHMFILELOCKS, fileLocks, shmFileLocks) == FALSE || fileLocks == NULL)
+ {
+ ASSERT("Unable to get pointer from shm pointer.\n");
+ palError = ERROR_INTERNAL_ERROR;
+ goto GetLockControllerForFileExit;
+ }
+
+ if(SHARE_MODE_NOT_INITALIZED == fileLocks->share_mode)
+ {
+ /* this is the first time this file is open */
+ fileLocks->share_mode = (int) dwShareMode;
+ }
+ /* start checking for dwDesired access and dwShareMode conditions */
+ else if(0 == fileLocks->share_mode)
+ {
+ /* file is exclusively locked */
+ palError = ERROR_SHARING_VIOLATION;
+ goto GetLockControllerForFileExit;
+ }
+ /* check for if the desired access is allowed by the share mode */
+ else if( (dwAccessRights & GENERIC_READ) &&
+ !(fileLocks->share_mode & FILE_SHARE_READ) )
+ {
+ palError = ERROR_SHARING_VIOLATION;
+ goto GetLockControllerForFileExit;
+ }
+ else if( (dwAccessRights & GENERIC_WRITE) &&
+ !(fileLocks->share_mode & FILE_SHARE_WRITE) )
+ {
+ palError = ERROR_SHARING_VIOLATION;
+ goto GetLockControllerForFileExit;
+ }
+ /* The case when changing to a conflicting share mode is particular.
+ The general rule is: changing from conflicting share mode is invalid
+ (i.e changing from FILE_SHARE_WRITE to FILE_SHARE_READ is invalid).
+ However, if one of the share flags is the same
+ (i.e changing from FILE_SHARE_WRITE to FILE_SHARE_READ | FILE_SHARE_WRITE)
+ the result is valid. (Please note that FILE_SHARE_READ is ignored
+ in this case).
+ */
+ else if( (dwShareMode & FILE_SHARE_READ) &&
+ !(dwShareMode & FILE_SHARE_WRITE) &&
+ !(fileLocks->share_mode & FILE_SHARE_READ))
+
+ {
+ palError = ERROR_SHARING_VIOLATION;
+ goto GetLockControllerForFileExit;
+ }
+ else if( (dwShareMode & FILE_SHARE_WRITE) &&
+ !(dwShareMode & FILE_SHARE_READ) &&
+ !(fileLocks->share_mode & FILE_SHARE_WRITE))
+ {
+ palError = ERROR_SHARING_VIOLATION;
+ goto GetLockControllerForFileExit;
+ }
+ /* Changing to a less permissive sharing permissions is valid
+ if the file handle doesn't have an access right that conflicts with
+ the sharing permissions we are trying to set
+ (ex: changing from FILE_SHARE_READ|FILE_SHARE_WRITE to FILE_SHARE_WRITE
+ isn't valid if the file descriptor still has a GENERIC_READ permission).
+ */
+ else if( (fileLocks->nbReadAccess) &&
+ !(dwShareMode & FILE_SHARE_READ) )
+ {
+ palError = ERROR_SHARING_VIOLATION;
+ goto GetLockControllerForFileExit;
+ }
+ else if( (fileLocks->nbWriteAccess) &&
+ !(dwShareMode & FILE_SHARE_WRITE) )
+ {
+ palError = ERROR_SHARING_VIOLATION;
+ goto GetLockControllerForFileExit;
+ }
+
+ /* we are trying to change to a less restrictive sharing permission set
+ keep the current permissions */
+ if( (dwShareMode & FILE_SHARE_READ) &&
+ !(fileLocks->share_mode & FILE_SHARE_READ) )
+ {
+ dwShareMode = fileLocks->share_mode;
+ }
+
+ if( (dwShareMode & FILE_SHARE_WRITE) &&
+ !(fileLocks->share_mode & FILE_SHARE_WRITE) )
+ {
+ dwShareMode = fileLocks->share_mode;
+ }
+
+ pController = InternalNew<CSharedMemoryFileLockController>(dwAccessRights, shmFileLocks);
+ if (NULL == pController)
+ {
+ palError = ERROR_OUTOFMEMORY;
+ goto GetLockControllerForFileExit;
+ }
+
+ //
+ // pController now owns the shared memory pointer, so make sure we
+ // don't attempt to free it below.
+ //
+
+ shmFileLocks = SHMNULL;
+
+ /* set the share mode again, it's possible that the share mode is now more
+ restrictive than the previous mode set. */
+ fileLocks->share_mode = dwShareMode;
+ if( dwAccessRights & GENERIC_READ )
+ {
+ fileLocks->nbReadAccess++;
+ }
+ if( dwAccessRights & GENERIC_WRITE )
+ {
+ fileLocks->nbWriteAccess++;
+ }
+
+ // ************** NOTE **************
+ // If you add any error paths after this point you must communicate the value of dwAccessRights to
+ // FILECleanUpLockedRgn() in the cleanup code below so that it can correctly undo the changes to
+ // fileLocks->nbReadAccess and nbWriteAccess made above.
+ // ************** NOTE **************
+
+GetLockControllerForFileExit:
+
+ if (NO_ERROR == palError)
+ {
+ *ppLockController = pController;
+ }
+ else
+ {
+ if (NULL != pController)
+ {
+ pController->ReleaseController();
+ }
+
+ if (SHMNULL != shmFileLocks)
+ {
+ FILECleanUpLockedRgn(
+ shmFileLocks,
+ 0,
+ NULL
+ );
+ }
+ }
+
+ SHMRelease();
+
+ return palError;
+}
+
+PAL_ERROR
+CSharedMemoryFileLockMgr::GetFileShareModeForFile(
+ LPCSTR szFileName,
+ DWORD* pdwShareMode)
+{
+ PAL_ERROR palError = NO_ERROR;
+ *pdwShareMode = SHARE_MODE_NOT_INITALIZED;
+ SHMPTR shmFileLocks = SHMNULL;
+ SHMFILELOCKS* fileLocks = NULL;
+
+ SHMLock();
+
+ palError = FILEGetSHMFileLocks(szFileName, &shmFileLocks, TRUE);
+ if (NO_ERROR != palError || shmFileLocks == SHMNULL)
+ {
+ goto GetLockControllerForFileExit;
+ }
+
+ if (SHMPTR_TO_TYPED_PTR_BOOL(SHMFILELOCKS, fileLocks, shmFileLocks) == FALSE)
+ {
+ ASSERT("Unable to get pointer from shm pointer.\n");
+ palError = ERROR_INTERNAL_ERROR;
+ goto GetLockControllerForFileExit;
+ }
+
+ *pdwShareMode = fileLocks->share_mode;
+
+GetLockControllerForFileExit:
+
+ if (SHMNULL != shmFileLocks)
+ {
+ FILECleanUpLockedRgn(
+ shmFileLocks,
+ 0,
+ NULL
+ );
+ }
+
+ SHMRelease();
+
+ return palError;
+}
+
+PAL_ERROR
+CSharedMemoryFileLockController::GetTransactionLock(
+ CPalThread *pThread, // IN, OPTIONAL
+ FileTransactionLockType eLockType,
+ DWORD dwOffsetLow,
+ DWORD dwOffsetHigh,
+ DWORD nNumberOfBytesToLockLow,
+ DWORD nNumberOfBytesToLockHigh,
+ IFileTransactionLock **ppTransactionLock // OUT
+ )
+{
+ PAL_ERROR palError = NO_ERROR;
+ UINT64 lockRgnStart;
+ UINT64 nbBytesToLock;
+
+ lockRgnStart = ((UINT64)dwOffsetHigh) << 32 | dwOffsetLow;
+ nbBytesToLock = ((UINT64)nNumberOfBytesToLockHigh) << 32 |
+ nNumberOfBytesToLockLow;
+
+ palError = FILELockFileRegion(
+ m_shmFileLocks,
+ reinterpret_cast<PVOID>(this),
+ lockRgnStart,
+ nbBytesToLock,
+ RDWR_LOCK_RGN
+ );
+
+ if (NO_ERROR == palError)
+ {
+ *ppTransactionLock = InternalNew<CSharedMemoryFileTransactionLock>(m_shmFileLocks,
+ reinterpret_cast<PVOID>(this),
+ lockRgnStart,
+ nbBytesToLock);
+ if (NULL == *ppTransactionLock)
+ {
+ palError = ERROR_OUTOFMEMORY;
+ FILEUnlockFileRegion(
+ m_shmFileLocks,
+ reinterpret_cast<PVOID>(this),
+ lockRgnStart,
+ nbBytesToLock,
+ RDWR_LOCK_RGN
+ );
+ }
+ }
+
+ return palError;
+}
+
+PAL_ERROR
+CSharedMemoryFileLockController::CreateFileLock(
+ CPalThread *pThread, // IN, OPTIONAL
+ DWORD dwOffsetLow,
+ DWORD dwOffsetHigh,
+ DWORD nNumberOfBytesToLockLow,
+ DWORD nNumberOfBytesToLockHigh,
+ FileLockExclusivity eFileLockExclusivity,
+ FileLockWaitMode eFileLockWaitMode
+ )
+{
+ PAL_ERROR palError = NO_ERROR;
+ UINT64 lockRgnStart;
+ UINT64 nbBytesToLock;
+
+ if (ExclusiveFileLock != eFileLockExclusivity
+ || FailImmediately != eFileLockWaitMode)
+ {
+ ASSERT("LockFileEx functionality not yet supported");
+ palError = ERROR_NOT_SUPPORTED;
+ goto CreateFileLockExit;
+ }
+
+ lockRgnStart = ((UINT64)dwOffsetHigh) << 32 | dwOffsetLow;
+ nbBytesToLock = ((UINT64)nNumberOfBytesToLockHigh) << 32 |
+ nNumberOfBytesToLockLow;
+
+ palError = FILELockFileRegion(
+ m_shmFileLocks,
+ reinterpret_cast<PVOID>(this),
+ lockRgnStart,
+ nbBytesToLock,
+ USER_LOCK_RGN
+ );
+
+CreateFileLockExit:
+
+ return palError;
+}
+
+PAL_ERROR
+CSharedMemoryFileLockController::ReleaseFileLock(
+ CPalThread *pThread, // IN, OPTIONAL
+ DWORD dwOffsetLow,
+ DWORD dwOffsetHigh,
+ DWORD nNumberOfBytesToUnlockLow,
+ DWORD nNumberOfBytesToUnlockHigh
+ )
+{
+ PAL_ERROR palError = NO_ERROR;
+ UINT64 unlockRgnStart;
+ UINT64 nbBytesToUnlock;
+
+ unlockRgnStart = ((UINT64)dwOffsetHigh) << 32 | dwOffsetLow;
+ nbBytesToUnlock = ((UINT64)nNumberOfBytesToUnlockHigh) << 32 |
+ nNumberOfBytesToUnlockLow;
+
+ palError = FILEUnlockFileRegion(
+ m_shmFileLocks,
+ reinterpret_cast<PVOID>(this),
+ unlockRgnStart,
+ nbBytesToUnlock,
+ USER_LOCK_RGN
+ );
+
+ return palError;
+}
+
+void
+CSharedMemoryFileLockController::ReleaseController()
+{
+ if (SHMNULL != m_shmFileLocks)
+ {
+ FILECleanUpLockedRgn(
+ m_shmFileLocks,
+ m_dwAccessRights,
+ reinterpret_cast<PVOID>(this)
+ );
+ }
+
+ InternalDelete(this);
+}
+
+void
+CSharedMemoryFileTransactionLock::ReleaseLock()
+{
+ FILEUnlockFileRegion(
+ m_shmFileLocks,
+ m_pvControllerInstance,
+ m_lockRgnStart,
+ m_nbBytesToLock,
+ RDWR_LOCK_RGN
+ );
+
+ InternalDelete(this);
+}
+
+PAL_ERROR
+FILELockFileRegion(
+ SHMPTR shmFileLocks,
+ PVOID pvControllerInstance,
+ UINT64 lockRgnStart,
+ UINT64 nbBytesToLock,
+ LOCK_TYPE lockAction
+ )
+{
+ PAL_ERROR palError = NO_ERROR;
+ SHMFILELOCKRGNS *curLock, *prevLock, *insertAfter,
+ lockRgn, fakeLock = {0,0,0,0};
+ SHMFILELOCKS *fileLocks;
+
+ SHMLock();
+
+ /* nothing to do if the region to lock is empty */
+ if (nbBytesToLock == 0)
+ {
+ TRACE("Locking an empty region (%I64d, %I64d)\n", lockRgnStart, nbBytesToLock);
+ goto EXIT;
+ }
+
+ if (SHMPTR_TO_TYPED_PTR_BOOL(SHMFILELOCKS, fileLocks, shmFileLocks) == FALSE || fileLocks == NULL)
+ {
+ ASSERT("Unable to get pointer from shm pointer.\n");
+ palError = ERROR_INTERNAL_ERROR;
+ goto EXIT;
+ }
+
+ if (fileLocks->fileLockedRgns != 0)
+ {
+ prevLock = &fakeLock;
+
+ if (SHMPTR_TO_TYPED_PTR_BOOL(SHMFILELOCKRGNS, curLock, fileLocks->fileLockedRgns)
+ == FALSE)
+ {
+ ASSERT("Unable to get pointer from shm pointer.\n");
+ palError = ERROR_INTERNAL_ERROR;
+ goto EXIT;
+ }
+
+ lockRgn.lockRgnStart = lockRgnStart;
+ lockRgn.nbBytesLocked = nbBytesToLock;
+ lockRgn.pvControllerInstance = pvControllerInstance;
+ lockRgn.processId = GetCurrentProcessId();
+ lockRgn.lockType = lockAction;
+
+ while((curLock != NULL) && IS_LOCK_BEFORE(curLock, &lockRgn))
+ {
+ prevLock = curLock;
+ if (SHMPTR_TO_TYPED_PTR_BOOL(SHMFILELOCKRGNS, curLock, curLock->next) == FALSE)
+ {
+ ASSERT("Unable to get pointer from shm pointer.\n");
+ palError = ERROR_INTERNAL_ERROR;
+ goto EXIT;
+ }
+ }
+
+ while((curLock != NULL) && IS_LOCK_INTERSECT(curLock, &lockRgn))
+ {
+ /* we couldn't lock the requested region if it overlap with other
+ region locked explicitly (by LockFile call) by other file pointer */
+ if ((lockAction == USER_LOCK_RGN) ||
+ ((curLock->lockType == USER_LOCK_RGN) &&
+ !IS_LOCK_HAVE_SAME_OWNER(curLock, &lockRgn)))
+ {
+ WARN("The requested lock region overlaps an existing locked region\n");
+ palError = ERROR_LOCK_VIOLATION;
+ goto EXIT;
+ }
+
+ prevLock = curLock;
+ if (SHMPTR_TO_TYPED_PTR_BOOL(SHMFILELOCKRGNS, curLock, curLock->next) == FALSE)
+ {
+ ASSERT("Unable to get pointer from shm pointer.\n");
+ palError = ERROR_INTERNAL_ERROR;
+ goto EXIT;
+ }
+ }
+
+ /* save the previous lock in case we need to insert the requested lock */
+ insertAfter = prevLock;
+
+ while(((curLock != NULL) && IS_LOCK_INTERSECT(&lockRgn, curLock)))
+ {
+ /* we couldn't lock the requested region if it overlap with other region
+ locked explicitly (by LockFile call) by other file pointer */
+ if ((lockAction == USER_LOCK_RGN) ||
+ ((curLock->lockType == USER_LOCK_RGN) &&
+ !IS_LOCK_HAVE_SAME_OWNER(curLock, &lockRgn)))
+ {
+ WARN("The requested lock region overlaps an existing locked region\n");
+ palError = ERROR_LOCK_VIOLATION;
+ goto EXIT;
+ }
+
+ prevLock = curLock;
+ if (SHMPTR_TO_TYPED_PTR_BOOL(SHMFILELOCKRGNS, curLock, curLock->next) == FALSE)
+ {
+ ASSERT("Unable to get pointer from shm pointer.\n");
+ palError = ERROR_INTERNAL_ERROR;
+ goto EXIT;
+ }
+ }
+
+ if (insertAfter == &fakeLock)
+ {
+ insertAfter = NULL;
+ }
+
+ palError = FILEAddNewLockedRgn(
+ fileLocks,
+ pvControllerInstance,
+ insertAfter,
+ lockRgnStart,
+ nbBytesToLock,
+ lockAction
+ );
+
+ if (NO_ERROR != palError)
+ {
+ WARN("Couldn't add the new locked region into SHM\n");
+ goto EXIT;
+ }
+ }
+ else /* lock region list is empty. */
+ {
+ palError = FILEAddNewLockedRgn(
+ fileLocks,
+ pvControllerInstance,
+ NULL,
+ lockRgnStart,
+ nbBytesToLock,
+ lockAction
+ );
+
+ if (NO_ERROR != palError)
+ {
+ ERROR("Couldn't add the first file locked region \n");
+ goto EXIT;
+ }
+ }
+
+EXIT:
+ SHMRelease();
+ return palError;
+}
+
+PAL_ERROR
+FILEUnlockFileRegion(
+ SHMPTR shmFileLocks,
+ PVOID pvControllerInstance,
+ UINT64 unlockRgnStart,
+ UINT64 nbBytesToUnlock,
+ LOCK_TYPE unlockType
+ )
+{
+ PAL_ERROR palError = NO_ERROR;
+ SHMFILELOCKRGNS *prevLock = NULL, *curLockRgn = NULL, unlockRgn;
+ SHMPTR shmcurLockRgn;
+ SHMFILELOCKS *fileLocks;
+
+ SHMLock();
+
+
+ /* check if the region to unlock is empty or not */
+ if (nbBytesToUnlock == 0)
+ {
+ palError = ERROR_NOT_LOCKED;
+ WARN("Attempt to unlock an empty region\n");
+ goto EXIT;
+ }
+
+ if ((SHMPTR_TO_TYPED_PTR_BOOL(SHMFILELOCKS, fileLocks, shmFileLocks) == FALSE) ||
+ (fileLocks == NULL) ||
+ (SHMPTR_TO_TYPED_PTR_BOOL(SHMFILELOCKRGNS, curLockRgn, fileLocks->fileLockedRgns) == FALSE))
+ {
+ ASSERT("Unable to get pointer from shm pointer.\n");
+ palError = ERROR_INTERNAL_ERROR;
+ goto EXIT;
+ }
+
+ unlockRgn.processId = GetCurrentProcessId();
+ unlockRgn.pvControllerInstance = pvControllerInstance;
+ unlockRgn.lockRgnStart = unlockRgnStart;
+ unlockRgn.nbBytesLocked = nbBytesToUnlock;
+ unlockRgn.lockType = unlockType;
+
+ shmcurLockRgn = fileLocks->fileLockedRgns;
+
+ while((curLockRgn != NULL) && !IS_LOCK_EQUAL(curLockRgn, &unlockRgn))
+ {
+ prevLock = curLockRgn;
+ shmcurLockRgn = curLockRgn->next;
+ if (SHMPTR_TO_TYPED_PTR_BOOL(SHMFILELOCKRGNS, curLockRgn, shmcurLockRgn) == FALSE)
+ {
+ ASSERT("Unable to get pointer from shm pointer.\n");
+ goto EXIT;
+ }
+ }
+
+ if (curLockRgn != NULL)
+ {
+ TRACE("removing the lock region (%I64u, %I64u)\n",
+ curLockRgn->lockRgnStart, curLockRgn->nbBytesLocked);
+
+ if (prevLock == NULL)
+ {
+ /* removing the first lock */
+ fileLocks->fileLockedRgns = curLockRgn->next;
+ }
+ else
+ {
+ prevLock->next = curLockRgn->next;
+ }
+ SHMfree(shmcurLockRgn);
+ }
+ else
+ {
+ /* the lock doesn't exist */
+ WARN("Attempt to unlock a non locked region\n");
+ palError = ERROR_NOT_LOCKED;
+ goto EXIT;
+ }
+
+EXIT:
+ SHMRelease();
+ return palError;
+}
+
+
+PAL_ERROR
+FILEGetSHMFileLocks(
+ LPCSTR filename,
+ SHMPTR *pshmFileLocks,
+ BOOL noCreate
+ )
+{
+ PAL_ERROR palError = NO_ERROR;
+ SHMPTR shmPtrRet = 0;
+ SHMFILELOCKS *filelocksPtr, *nextFilelocksPtr;
+ char *unix_filename;
+
+ SHMLock();
+
+ shmPtrRet = SHMGetInfo(SIID_FILE_LOCKS);
+
+ while(shmPtrRet != 0)
+ {
+ if ( (SHMPTR_TO_TYPED_PTR_BOOL(SHMFILELOCKS, filelocksPtr, shmPtrRet) == FALSE) ||
+ (SHMPTR_TO_TYPED_PTR_BOOL(char, unix_filename, filelocksPtr->unix_filename) == FALSE))
+ {
+ ASSERT("Unable to get pointer from shm pointer.\n");
+ palError = ERROR_INTERNAL_ERROR;
+ goto EXIT;
+ }
+
+ if (unix_filename == NULL)
+ {
+ ERROR("Unexpected lock file name value.\n");
+ palError = ERROR_INTERNAL_ERROR;
+ goto EXIT;
+ }
+
+ if (strcmp(unix_filename, filename) == 0)
+ {
+ filelocksPtr->refCount++;
+ goto EXIT;
+ }
+
+ shmPtrRet = filelocksPtr->next;
+ }
+
+ /* the file has never been locked before.*/
+ shmPtrRet = 0;
+ if (noCreate)
+ {
+ goto EXIT;
+ }
+
+ TRACE("Create a new entry in the file lock list in SHM\n");
+
+ /* Create a new entry in the file lock list in SHM */
+ if ((shmPtrRet = SHMalloc(sizeof(SHMFILELOCKS))) == 0)
+ {
+ ERROR("Can't allocate SHMFILELOCKS structure\n");
+ palError = ERROR_NOT_ENOUGH_MEMORY;
+ goto EXIT;
+ }
+
+ if (SHMPTR_TO_TYPED_PTR_BOOL(SHMFILELOCKS, filelocksPtr, shmPtrRet) == FALSE)
+ {
+ ASSERT("Unable to get pointer from shm pointer.\n");
+ palError = ERROR_INTERNAL_ERROR;
+ goto CLEANUP1;
+ }
+
+ filelocksPtr->unix_filename = SHMStrDup(filename);
+ if (filelocksPtr->unix_filename == 0)
+ {
+ ERROR("Can't allocate shared memory for filename\n");
+ palError = ERROR_NOT_ENOUGH_MEMORY;
+ goto CLEANUP1;
+ }
+
+ filelocksPtr->fileLockedRgns = 0;
+ filelocksPtr->prev = 0;
+ filelocksPtr->next = SHMGetInfo(SIID_FILE_LOCKS);
+ filelocksPtr->refCount = 1;
+ filelocksPtr->share_mode = SHARE_MODE_NOT_INITALIZED;
+ filelocksPtr->nbReadAccess = 0;
+ filelocksPtr->nbWriteAccess = 0;
+
+ if (SHMPTR_TO_TYPED_PTR_BOOL(SHMFILELOCKS, nextFilelocksPtr, filelocksPtr->next) == FALSE)
+ {
+ ASSERT("Unable to get pointer from shm pointer.\n");
+ palError = ERROR_INTERNAL_ERROR;
+ goto CLEANUP2;
+ }
+
+ if (nextFilelocksPtr != NULL)
+ {
+ nextFilelocksPtr->prev = shmPtrRet;
+ }
+
+ SHMSetInfo(SIID_FILE_LOCKS, shmPtrRet);
+ goto EXIT;
+
+CLEANUP2:
+ SHMfree(filelocksPtr->unix_filename);
+CLEANUP1:
+ SHMfree(shmPtrRet);
+ shmPtrRet = 0;
+EXIT:
+ SHMRelease();
+
+ if (NO_ERROR == palError)
+ {
+ *pshmFileLocks = shmPtrRet;
+ }
+
+ return palError;
+}
+
+PAL_ERROR
+FILEAddNewLockedRgn(
+ SHMFILELOCKS* fileLocks,
+ PVOID pvControllerInstance,
+ SHMFILELOCKRGNS *insertAfter,
+ UINT64 lockRgnStart,
+ UINT64 nbBytesToLock,
+ LOCK_TYPE lockType
+ )
+{
+ PAL_ERROR palError = NO_ERROR;
+ SHMFILELOCKRGNS *newLockRgn, *lockRgnPtr;
+ SHMPTR shmNewLockRgn = SHMNULL;
+
+ if ((fileLocks == NULL) || (pvControllerInstance == NULL))
+ {
+ ASSERT("Invalid Null parameter.\n");
+ return FALSE;
+ }
+
+ SHMLock();
+
+ /* Create a new entry for the new locked region */
+ TRACE("Create a new entry for the new lock region (%I64u %I64u)\n",
+ lockRgnStart, nbBytesToLock);
+
+ if ((shmNewLockRgn = SHMalloc(sizeof(SHMFILELOCKRGNS))) == SHMNULL)
+ {
+ ERROR("Can't allocate SHMFILELOCKRGNS structure\n");
+ palError = ERROR_NOT_ENOUGH_MEMORY;
+ goto EXIT;
+ }
+
+ if (SHMPTR_TO_TYPED_PTR_BOOL(SHMFILELOCKRGNS, newLockRgn, shmNewLockRgn) == FALSE)
+ {
+ ASSERT("Unable to get pointer from shm pointer.\n");
+ palError = ERROR_INTERNAL_ERROR;
+ goto EXIT;
+ }
+
+ newLockRgn->processId = GetCurrentProcessId();
+ newLockRgn->pvControllerInstance = pvControllerInstance;
+ newLockRgn->lockRgnStart = lockRgnStart;
+ newLockRgn->nbBytesLocked = nbBytesToLock;
+ newLockRgn->lockType = lockType;
+
+ /* All locked regions with the same offset should be sorted ascending */
+ /* the sort is based on the length of the locked byte range */
+ if (insertAfter != NULL)
+ {
+ if (SHMPTR_TO_TYPED_PTR_BOOL(SHMFILELOCKRGNS, lockRgnPtr, insertAfter->next) == FALSE)
+ {
+ ASSERT("Unable to get pointer from shm pointer.\n");
+ palError = ERROR_INTERNAL_ERROR;
+ goto EXIT;
+ }
+ }
+ else
+ {
+ if (SHMPTR_TO_TYPED_PTR_BOOL(SHMFILELOCKRGNS, lockRgnPtr, fileLocks->fileLockedRgns) == FALSE)
+ {
+ ASSERT("Unable to get pointer from shm pointer.\n");
+ palError = ERROR_INTERNAL_ERROR;
+ goto EXIT;
+ }
+ }
+
+ while(lockRgnPtr != NULL)
+ {
+ if ( (lockRgnPtr->lockRgnStart == newLockRgn->lockRgnStart) &&
+ (newLockRgn->nbBytesLocked > lockRgnPtr->nbBytesLocked))
+ {
+ insertAfter = lockRgnPtr;
+ if (SHMPTR_TO_TYPED_PTR_BOOL(SHMFILELOCKRGNS, lockRgnPtr, lockRgnPtr->next) == FALSE)
+ {
+ ASSERT("Unable to get pointer from shm pointer.\n");
+ palError = ERROR_INTERNAL_ERROR;
+ goto EXIT;
+ }
+ continue;
+ }
+
+ break;
+ }
+
+ if (insertAfter != NULL)
+ {
+ TRACE("Adding lock after the lock rgn (%I64d %I64d)\n",
+ insertAfter->lockRgnStart,insertAfter->nbBytesLocked);
+ newLockRgn->next = insertAfter->next;
+ insertAfter->next = shmNewLockRgn;
+ }
+ else
+ {
+ TRACE("adding lock into the head of the list\n");
+ newLockRgn->next = fileLocks->fileLockedRgns;
+ fileLocks->fileLockedRgns = shmNewLockRgn;
+ }
+
+EXIT:
+
+ if (NO_ERROR != palError && SHMNULL != shmNewLockRgn)
+ {
+ SHMfree(shmNewLockRgn);
+ }
+
+ SHMRelease();
+
+ return palError;
+}
+
+void
+FILECleanUpLockedRgn(
+ SHMPTR shmFileLocks,
+ DWORD dwAccessRights,
+ PVOID pvControllerInstance
+ )
+{
+ SHMFILELOCKRGNS *curLockRgn = NULL, *prevLock = NULL;
+ SHMFILELOCKS *fileLocks, *prevFileLocks, *nextFileLocks;
+ SHMPTR shmcurLockRgn;
+
+ SHMLock();
+
+ if (SHMPTR_TO_TYPED_PTR_BOOL(SHMFILELOCKS, fileLocks, shmFileLocks) == FALSE)
+ {
+ ASSERT("Unable to get pointer from shm pointer.\n");
+ goto EXIT;
+ }
+
+ if (fileLocks != NULL)
+ {
+ if(fileLocks->fileLockedRgns !=0)
+ {
+ shmcurLockRgn = fileLocks->fileLockedRgns;
+ if (SHMPTR_TO_TYPED_PTR_BOOL(SHMFILELOCKRGNS, curLockRgn, shmcurLockRgn) == FALSE)
+ {
+ ASSERT("Unable to get pointer from shm pointer.\n");
+ goto EXIT;
+ }
+
+ while(curLockRgn != NULL)
+ {
+ if ((curLockRgn->pvControllerInstance == pvControllerInstance) &&
+ (curLockRgn->processId == GetCurrentProcessId()))
+ {
+ /* found the locked rgn to remove from SHM */
+ TRACE("Removing the locked region (%I64u, %I64u) from SMH\n",
+ curLockRgn->lockRgnStart, curLockRgn->nbBytesLocked);
+
+ if (prevLock == NULL)
+ {
+ /* removing the first lock */
+ fileLocks->fileLockedRgns = curLockRgn->next;
+ SHMfree(shmcurLockRgn);
+ shmcurLockRgn = fileLocks->fileLockedRgns;
+ if (SHMPTR_TO_TYPED_PTR_BOOL(SHMFILELOCKRGNS, curLockRgn, shmcurLockRgn) == FALSE)
+ {
+ ASSERT("Unable to get pointer from shm pointer.\n");
+ goto EXIT;
+ }
+ }
+ else
+ {
+ prevLock->next = curLockRgn->next;
+ SHMfree(shmcurLockRgn);
+ shmcurLockRgn = prevLock->next;
+ if (SHMPTR_TO_TYPED_PTR_BOOL(SHMFILELOCKRGNS, curLockRgn, shmcurLockRgn) == FALSE)
+ {
+ ASSERT("Unable to get pointer from shm pointer.\n");
+ goto EXIT;
+ }
+ }
+ continue;
+ }
+
+ prevLock = curLockRgn;
+ shmcurLockRgn = curLockRgn->next;
+ if (SHMPTR_TO_TYPED_PTR_BOOL(SHMFILELOCKRGNS, curLockRgn, shmcurLockRgn) == FALSE)
+ {
+ ASSERT("Unable to get pointer from shm pointer.\n");
+ goto EXIT;
+ }
+ }
+ }
+
+ if (dwAccessRights & GENERIC_READ)
+ {
+ fileLocks->nbReadAccess--;
+ }
+ if (dwAccessRights & GENERIC_WRITE)
+ {
+ fileLocks->nbWriteAccess--;
+ }
+
+ /* remove the SHMFILELOCKS structure from SHM if there's no more locked
+ region left and no more reference to it */
+ if ((--(fileLocks->refCount) == 0) && (fileLocks->fileLockedRgns == 0))
+ {
+ TRACE("Removing the SHMFILELOCKS structure from SHM\n");
+
+ if ( (SHMPTR_TO_TYPED_PTR_BOOL(SHMFILELOCKS, prevFileLocks, fileLocks->prev) == FALSE) ||
+ (SHMPTR_TO_TYPED_PTR_BOOL(SHMFILELOCKS, nextFileLocks, fileLocks->next) == FALSE))
+ {
+ ASSERT("Unable to get pointer from shm pointer.\n");
+ goto EXIT;
+ }
+
+ if (prevFileLocks == NULL)
+ {
+ /* removing the first lock file*/
+ SHMSetInfo(SIID_FILE_LOCKS, fileLocks->next);
+ }
+ else
+ {
+ prevFileLocks->next = fileLocks->next;
+ }
+
+ if (nextFileLocks != NULL)
+ {
+ nextFileLocks->prev = fileLocks->prev;
+ }
+
+ if (fileLocks->unix_filename)
+ SHMfree(fileLocks->unix_filename);
+
+ SHMfree(shmFileLocks);
+ }
+ }
+EXIT:
+ SHMRelease();
+ return;
+}
+
diff --git a/src/pal/src/file/shmfilelockmgr.hpp b/src/pal/src/file/shmfilelockmgr.hpp
new file mode 100644
index 0000000000..dd7d9b8014
--- /dev/null
+++ b/src/pal/src/file/shmfilelockmgr.hpp
@@ -0,0 +1,185 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ shmfilelockmgr.hpp
+
+Abstract:
+ Shared memory based file lock manager
+
+
+
+--*/
+
+#ifndef _PAL_SHMFILELOCKMGR_H_
+#define _PAL_SHMFILELOCKMGR_H_
+
+#include "pal/corunix.hpp"
+#include "pal/shm.hpp"
+
+namespace CorUnix
+{
+ #define SHARE_MODE_NOT_INITALIZED 0xFFFFFFFF
+
+ typedef struct
+ {
+ SHMPTR unix_filename;
+ SHMPTR fileLockedRgns;
+ UINT refCount;
+ SHMPTR next;
+ SHMPTR prev;
+ DWORD share_mode; /* FILE_SHARE_READ, FILE_SHARE_WRITE,
+ FILE_SHARE_DELETE, 0 ( not shared ) or
+ SHARE_MODE_NOT_INITALIZED */
+ int nbReadAccess; /* used to keep track of the minimal
+ access permissions */
+ int nbWriteAccess;
+ } SHMFILELOCKS;
+
+ typedef enum
+ {
+ USER_LOCK_RGN, /* Used only for user locks (LockFile or UnlockFile call) */
+ RDWR_LOCK_RGN /* Used to distinguish between the user locks and the internal
+ locks made when reading, writing or truncating file */
+ } LOCK_TYPE;
+
+ typedef struct
+ {
+ DWORD processId;
+ PVOID pvControllerInstance;
+ UINT64 lockRgnStart;
+ UINT64 nbBytesLocked;
+ LOCK_TYPE lockType;
+
+ SHMPTR next;
+ } SHMFILELOCKRGNS;
+
+ class CSharedMemoryFileLockMgr : public IFileLockManager
+ {
+ public:
+
+ virtual
+ PAL_ERROR
+ GetLockControllerForFile(
+ CPalThread *pThread, // IN, OPTIONAL
+ LPCSTR szFileName,
+ DWORD dwAccessRights,
+ DWORD dwShareMode,
+ IFileLockController **ppLockController // OUT
+ );
+
+ virtual
+ PAL_ERROR
+ GetFileShareModeForFile(
+ LPCSTR szFileName,
+ DWORD* pdwShareMode);
+ };
+
+ class CSharedMemoryFileLockController : public IFileLockController
+ {
+ template <class T> friend void InternalDelete(T *p);
+
+ private:
+ DWORD m_dwAccessRights;
+ SHMPTR m_shmFileLocks;
+ protected:
+ virtual ~CSharedMemoryFileLockController()
+ {
+ };
+
+ public:
+
+ CSharedMemoryFileLockController(
+ DWORD dwAccessRights,
+ SHMPTR shmFileLocks
+ )
+ :
+ m_dwAccessRights(dwAccessRights),
+ m_shmFileLocks(shmFileLocks)
+ {
+ };
+
+ virtual
+ PAL_ERROR
+ GetTransactionLock(
+ CPalThread *pThread, // IN, OPTIONAL
+ FileTransactionLockType eLockType,
+ DWORD dwOffsetLow,
+ DWORD dwOffsetHigh,
+ DWORD nNumberOfBytesToLockLow,
+ DWORD nNumberOfBytesToLockHigh,
+ IFileTransactionLock **ppTransactionLock // OUT
+ );
+
+ virtual
+ PAL_ERROR
+ CreateFileLock(
+ CPalThread *pThread, // IN, OPTIONAL
+ DWORD dwOffsetLow,
+ DWORD dwOffsetHigh,
+ DWORD nNumberOfBytesToLockLow,
+ DWORD nNumberOfBytesToLockHigh,
+ FileLockExclusivity eFileLockExclusivity,
+ FileLockWaitMode eFileLockWaitMode
+ );
+
+ virtual
+ PAL_ERROR
+ ReleaseFileLock(
+ CPalThread *pThread, // IN, OPTIONAL
+ DWORD dwOffsetLow,
+ DWORD dwOffsetHigh,
+ DWORD nNumberOfBytesToUnlockLow,
+ DWORD nNumberOfBytesToUnlockHigh
+ );
+
+ virtual
+ void
+ ReleaseController();
+ };
+
+ class CSharedMemoryFileTransactionLock : public IFileTransactionLock
+ {
+ template <class T> friend void InternalDelete(T *p);
+
+ private:
+
+ SHMPTR m_shmFileLocks;
+ PVOID m_pvControllerInstance;
+ UINT64 m_lockRgnStart;
+ UINT64 m_nbBytesToLock;
+ protected:
+ virtual ~CSharedMemoryFileTransactionLock()
+ {
+ };
+
+ public:
+
+ CSharedMemoryFileTransactionLock(
+ SHMPTR shmFileLocks,
+ PVOID pvControllerInstance,
+ UINT64 lockRgnStart,
+ UINT64 nbBytesToLock
+ )
+ :
+ m_shmFileLocks(shmFileLocks),
+ m_pvControllerInstance(pvControllerInstance),
+ m_lockRgnStart(lockRgnStart),
+ m_nbBytesToLock(nbBytesToLock)
+ {
+ };
+
+ virtual
+ void
+ ReleaseLock();
+ };
+}
+
+#endif /* _PAL_SHMFILELOCKMGR_H_ */
+
diff --git a/src/pal/src/handlemgr/handleapi.cpp b/src/pal/src/handlemgr/handleapi.cpp
new file mode 100644
index 0000000000..6b99a85cf7
--- /dev/null
+++ b/src/pal/src/handlemgr/handleapi.cpp
@@ -0,0 +1,338 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ handleapi.cpp
+
+Abstract:
+
+ Implementation of the handle management APIs
+
+
+
+--*/
+
+#include "pal/handleapi.hpp"
+#include "pal/handlemgr.hpp"
+#include "pal/thread.hpp"
+#include "pal/procobj.hpp"
+#include "pal/dbgmsg.h"
+#include "pal/process.h"
+
+using namespace CorUnix;
+
+SET_DEFAULT_DEBUG_CHANNEL(HANDLE);
+
+CAllowedObjectTypes aotDuplicateHandle(TRUE);
+
+PAL_ERROR
+CloseSpecialHandle(
+ HANDLE hObject
+ );
+
+/*++
+Function:
+ DuplicateHandle
+
+See MSDN doc.
+
+PAL-specific behavior :
+ -Source and Target process needs to be the current process.
+ -lpTargetHandle must be non-NULL
+ -dwDesiredAccess is ignored
+ -bInheritHandle must be FALSE
+ -dwOptions must be a combo of DUPLICATE_SAME_ACCESS and
+ DUPLICATE_CLOSE_SOURCE
+
+--*/
+BOOL
+PALAPI
+DuplicateHandle(
+ IN HANDLE hSourceProcessHandle,
+ IN HANDLE hSourceHandle,
+ IN HANDLE hTargetProcessHandle,
+ OUT LPHANDLE lpTargetHandle,
+ IN DWORD dwDesiredAccess,
+ IN BOOL bInheritHandle,
+ IN DWORD dwOptions)
+{
+ PAL_ERROR palError;
+ CPalThread *pThread;
+
+ PERF_ENTRY(DuplicateHandle);
+ ENTRY("DuplicateHandle( hSrcProcHandle=%p, hSrcHandle=%p, "
+ "hTargetProcHandle=%p, lpTargetHandle=%p, dwAccess=%#x, "
+ "bInheritHandle=%d, dwOptions=%#x) \n", hSourceProcessHandle,
+ hSourceHandle, hTargetProcessHandle, lpTargetHandle,
+ dwDesiredAccess, bInheritHandle, dwOptions);
+
+ pThread = InternalGetCurrentThread();
+
+ palError = InternalDuplicateHandle(
+ pThread,
+ hSourceProcessHandle,
+ hSourceHandle,
+ hTargetProcessHandle,
+ lpTargetHandle,
+ dwDesiredAccess,
+ bInheritHandle,
+ dwOptions
+ );
+
+ if (NO_ERROR != palError)
+ {
+ pThread->SetLastError(palError);
+ }
+
+ LOGEXIT("DuplicateHandle returns BOOL %d\n", (NO_ERROR == palError));
+ PERF_EXIT(DuplicateHandle);
+ return (NO_ERROR == palError);
+}
+
+PAL_ERROR
+CorUnix::InternalDuplicateHandle(
+ CPalThread *pThread,
+ HANDLE hSourceProcess,
+ HANDLE hSource,
+ HANDLE hTargetProcess,
+ LPHANDLE phDuplicate,
+ DWORD dwDesiredAccess,
+ BOOL bInheritHandle,
+ DWORD dwOptions
+ )
+{
+ PAL_ERROR palError = NO_ERROR;
+ IPalObject *pobjSource = NULL;
+
+ DWORD source_process_id;
+ DWORD target_process_id;
+ DWORD cur_process_id;
+
+ cur_process_id = GetCurrentProcessId();
+ source_process_id = PROCGetProcessIDFromHandle(hSourceProcess);
+ target_process_id = PROCGetProcessIDFromHandle(hTargetProcess);
+
+ /* Check validity of process handles */
+ if (0 == source_process_id || 0 == target_process_id)
+ {
+ ASSERT("Can't duplicate handle: invalid source or destination process");
+ palError = ERROR_INVALID_PARAMETER;
+ goto InternalDuplicateHandleExit;
+ }
+
+ /* At least source or target process should be the current process. */
+ if (source_process_id != cur_process_id
+ && target_process_id != cur_process_id)
+ {
+ ASSERT("Can't duplicate handle : neither source or destination"
+ "processes are from current process");
+ palError = ERROR_INVALID_PARAMETER;
+ goto InternalDuplicateHandleExit;
+ }
+
+ if (FALSE != bInheritHandle)
+ {
+ ASSERT("Can't duplicate handle : bInheritHandle is not FALSE.\n");
+ palError = ERROR_INVALID_PARAMETER;
+ goto InternalDuplicateHandleExit;
+ }
+
+ if (dwOptions & ~(DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE))
+ {
+ ASSERT(
+ "Can't duplicate handle : dwOptions is %#x which is not "
+ "a subset of (DUPLICATE_SAME_ACCESS|DUPLICATE_CLOSE_SOURCE) "
+ "(%#x).\n",
+ dwOptions,
+ DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
+ palError = ERROR_INVALID_PARAMETER;
+ goto InternalDuplicateHandleExit;
+ }
+
+ if (0 == (dwOptions & DUPLICATE_SAME_ACCESS))
+ {
+ ASSERT(
+ "Can't duplicate handle : dwOptions is %#x which does not "
+ "include DUPLICATE_SAME_ACCESS (%#x).\n",
+ dwOptions,
+ DUPLICATE_SAME_ACCESS);
+ palError = ERROR_INVALID_PARAMETER;
+ goto InternalDuplicateHandleExit;
+ }
+
+ if (NULL == phDuplicate)
+ {
+ ASSERT("Can't duplicate handle : lpTargetHandle is NULL.\n");
+ goto InternalDuplicateHandleExit;
+ }
+
+ /* Since handles can be remoted to others processes using PAL_LocalHsndleToRemote
+ and PAL_RemoteHandleToLocal, DuplicateHandle needs some special handling
+ when this scenario occurs.
+
+ if hSourceProcessHandle is from another process OR
+ hTargetProcessHandle is from another process but both aren't
+ ( handled above ) return hSourceHandle.
+ */
+ if (source_process_id != cur_process_id
+ || target_process_id != cur_process_id)
+ {
+ *phDuplicate = hSource;
+ palError = NO_ERROR;
+ goto InternalDuplicateHandleExit;
+ }
+
+ //
+ // Obtain the source IPalObject
+ //
+
+ if (!HandleIsSpecial(hSource))
+ {
+ palError = g_pObjectManager->ReferenceObjectByHandle(
+ pThread,
+ hSource,
+ &aotDuplicateHandle,
+ dwDesiredAccess,
+ &pobjSource
+ );
+
+ if (NO_ERROR != palError)
+ {
+ ERROR("Unable to get object for source handle %p (%i)\n", hSource, palError);
+ goto InternalDuplicateHandleExit;
+ }
+ }
+ else if (hPseudoCurrentProcess == hSource)
+ {
+ TRACE("Duplicating process pseudo handle(%p)\n", hSource);
+
+ pobjSource = g_pobjProcess;
+ pobjSource->AddReference();
+ }
+ else if (hPseudoCurrentThread == hSource)
+ {
+ TRACE("Duplicating thread pseudo handle(%p)\n", hSource);
+
+ pobjSource = pThread->GetThreadObject();
+ pobjSource->AddReference();
+ }
+ else
+ {
+ ASSERT("Duplication not supported for this special handle (%p)\n", hSource);
+ palError = ERROR_INVALID_HANDLE;
+ goto InternalDuplicateHandleExit;
+ }
+
+ palError = g_pObjectManager->ObtainHandleForObject(
+ pThread,
+ pobjSource,
+ dwDesiredAccess,
+ bInheritHandle,
+ NULL,
+ phDuplicate
+ );
+
+InternalDuplicateHandleExit:
+
+ if (NULL != pobjSource)
+ {
+ pobjSource->ReleaseReference(pThread);
+ }
+
+ if (dwOptions & DUPLICATE_CLOSE_SOURCE)
+ {
+ //
+ // Since DUPLICATE_CLOSE_SOURCE was specified the source handle
+ // MUST be closed, even if an error occurred during the duplication
+ // process
+ //
+
+ TRACE("DuplicateHandle closing source handle %p\n", hSource);
+ InternalCloseHandle(pThread, hSource);
+ }
+
+ return palError;
+}
+
+/*++
+Function:
+ CloseHandle
+
+See MSDN doc.
+
+Note : according to MSDN, FALSE is returned in case of error. But also
+according to MSDN, closing an invalid handle raises an exception when running a
+debugger [or, alternately, if a special registry key is set]. This behavior is
+not required in the PAL, so we'll always return FALSE.
+--*/
+BOOL
+PALAPI
+CloseHandle(
+ IN OUT HANDLE hObject)
+{
+ CPalThread *pThread;
+ PAL_ERROR palError;
+
+ PERF_ENTRY(CloseHandle);
+ ENTRY("CloseHandle (hObject=%p) \n", hObject);
+
+ pThread = InternalGetCurrentThread();
+
+ palError = InternalCloseHandle(
+ pThread,
+ hObject
+ );
+
+ if (NO_ERROR != palError)
+ {
+ pThread->SetLastError(palError);
+ }
+
+ LOGEXIT("CloseHandle returns BOOL %d\n", (NO_ERROR == palError));
+ PERF_EXIT(CloseHandle);
+ return (NO_ERROR == palError);
+}
+
+PAL_ERROR
+CorUnix::InternalCloseHandle(
+ CPalThread * pThread,
+ HANDLE hObject
+ )
+{
+ PAL_ERROR palError = NO_ERROR;
+
+ if (!HandleIsSpecial(hObject))
+ {
+ palError = g_pObjectManager->RevokeHandle(
+ pThread,
+ hObject
+ );
+ }
+ else
+ {
+ palError = CloseSpecialHandle(hObject);
+ }
+
+ return palError;
+}
+
+PAL_ERROR
+CloseSpecialHandle(
+ HANDLE hObject
+ )
+{
+ if ((hObject == hPseudoCurrentThread) ||
+ (hObject == hPseudoCurrentProcess))
+ {
+ return NO_ERROR;
+ }
+
+ return ERROR_INVALID_HANDLE;
+}
+
diff --git a/src/pal/src/handlemgr/handlemgr.cpp b/src/pal/src/handlemgr/handlemgr.cpp
new file mode 100644
index 0000000000..3516287af5
--- /dev/null
+++ b/src/pal/src/handlemgr/handlemgr.cpp
@@ -0,0 +1,327 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ handlemgr.cpp
+
+Abstract:
+
+ Implementation of a basic handle table
+
+
+
+--*/
+
+#include "pal/thread.hpp"
+#include "pal/handlemgr.hpp"
+#include "pal/cs.hpp"
+#include "pal/malloc.hpp"
+#include "pal/dbgmsg.h"
+
+using namespace CorUnix;
+
+SET_DEFAULT_DEBUG_CHANNEL(HANDLE);
+
+/* Constants */
+/* Special handles */
+/* Pseudo handles constant for current thread and process */
+const HANDLE hPseudoCurrentProcess = (HANDLE) 0xFFFFFF01;
+const HANDLE hPseudoCurrentThread = (HANDLE) 0xFFFFFF03;
+/* Pseudo handle constant for the global IO Completion port */
+const HANDLE hPseudoGlobalIOCP = (HANDLE) 0xFFFFFF05;
+
+PAL_ERROR
+CSimpleHandleManager::Initialize(
+ void
+ )
+{
+ PAL_ERROR palError = NO_ERROR;
+
+ InternalInitializeCriticalSection(&m_csLock);
+ m_fLockInitialized = TRUE;
+
+ m_dwTableGrowthRate = c_BasicGrowthRate;
+
+ /* initialize the handle table - the free list is stored in the 'object'
+ field, with the head in the global 'm_hiFreeListStart'. */
+ m_dwTableSize = m_dwTableGrowthRate;
+
+ m_rghteHandleTable = reinterpret_cast<HANDLE_TABLE_ENTRY*>(InternalMalloc((m_dwTableSize * sizeof(HANDLE_TABLE_ENTRY))));
+ if(NULL == m_rghteHandleTable)
+ {
+ ERROR("Unable to create initial handle table array");
+ palError = ERROR_OUTOFMEMORY;
+ goto InitializeExit;
+ }
+
+ for (DWORD i = 0; i < m_dwTableSize; i++)
+ {
+ m_rghteHandleTable[i].u.hiNextIndex = i + 1;
+ m_rghteHandleTable[i].fEntryAllocated = FALSE;
+ }
+
+ m_rghteHandleTable[m_dwTableSize - 1].u.hiNextIndex = (HANDLE_INDEX)-1;
+
+ m_hiFreeListStart = 0;
+ m_hiFreeListEnd = m_dwTableSize - 1;
+
+ TRACE("Handle Manager initialization complete.\n");
+
+InitializeExit:
+
+ return palError;
+}
+
+PAL_ERROR
+CSimpleHandleManager::AllocateHandle(
+ CPalThread *pThread,
+ IPalObject *pObject,
+ DWORD dwAccessRights,
+ bool fInheritable,
+ HANDLE *ph
+ )
+{
+ PAL_ERROR palError = NO_ERROR;
+ DWORD dwIndex;
+
+ Lock(pThread);
+
+ /* if no free handles are available, we need to grow the handle table and
+ add new handles to the pool */
+ if (m_hiFreeListStart == c_hiInvalid)
+ {
+ HANDLE_TABLE_ENTRY* rghteTempTable;
+
+ TRACE("Handle pool empty (%d handles allocated), growing handle table "
+ "by %d entries.\n", m_dwTableSize, m_dwTableGrowthRate );
+
+ /* make sure handle values don't overflow */
+ if (m_dwTableSize + m_dwTableGrowthRate >= c_MaxIndex)
+ {
+ WARN("Unable to allocate handle : maximum (%d) reached!\n",
+ m_dwTableSize);
+ palError = ERROR_OUTOFMEMORY;
+ goto AllocateHandleExit;
+ }
+
+ /* grow handle table */
+ rghteTempTable = reinterpret_cast<HANDLE_TABLE_ENTRY*>(InternalRealloc(
+ m_rghteHandleTable,
+ (m_dwTableSize + m_dwTableGrowthRate) * sizeof(HANDLE_TABLE_ENTRY)));
+
+ if (NULL == rghteTempTable)
+ {
+ WARN("not enough memory to grow handle table!\n");
+ palError = ERROR_OUTOFMEMORY;
+ goto AllocateHandleExit;
+ }
+ m_rghteHandleTable = rghteTempTable;
+
+ /* update handle table and handle pool */
+ for (DWORD dw = m_dwTableSize; dw < m_dwTableSize + m_dwTableGrowthRate; dw += 1)
+ {
+ /* new handles are initially invalid */
+ /* the last "old" handle was m_dwTableSize-1, so the new
+ handles range from m_dwTableSize to
+ m_dwTableSize+m_dwTableGrowthRate-1 */
+ m_rghteHandleTable[dw].u.hiNextIndex = dw + 1;
+ m_rghteHandleTable[dw].fEntryAllocated = FALSE;
+ }
+
+ m_hiFreeListStart = m_dwTableSize;
+ m_dwTableSize += m_dwTableGrowthRate;
+ m_rghteHandleTable[m_dwTableSize - 1].u.hiNextIndex = (HANDLE_INDEX)-1;
+ m_hiFreeListEnd = m_dwTableSize - 1;
+
+ }
+
+ /* take the next free handle */
+ dwIndex = m_hiFreeListStart;
+
+ /* remove the handle from the pool */
+ m_hiFreeListStart = m_rghteHandleTable[dwIndex].u.hiNextIndex;
+
+ /* clear the tail record if this is the last handle slot available */
+ if(m_hiFreeListStart == c_hiInvalid)
+ {
+ m_hiFreeListEnd = c_hiInvalid;
+ }
+
+ /* save the data associated with the new handle */
+ *ph = HandleIndexToHandle(dwIndex);
+
+ pObject->AddReference();
+ m_rghteHandleTable[dwIndex].u.pObject = pObject;
+ m_rghteHandleTable[dwIndex].dwAccessRights = dwAccessRights;
+ m_rghteHandleTable[dwIndex].fInheritable = fInheritable;
+ m_rghteHandleTable[dwIndex].fEntryAllocated = TRUE;
+
+AllocateHandleExit:
+
+ Unlock(pThread);
+
+ return palError;
+}
+
+PAL_ERROR
+CSimpleHandleManager::GetObjectFromHandle(
+ CPalThread *pThread,
+ HANDLE h,
+ DWORD *pdwRightsGranted,
+ IPalObject **ppObject
+ )
+{
+ PAL_ERROR palError = NO_ERROR;
+ HANDLE_INDEX hi;
+
+ Lock(pThread);
+
+ if (!ValidateHandle(h))
+ {
+ ERROR("Tried to dereference an invalid handle %p\n", h);
+ palError = ERROR_INVALID_HANDLE;
+ goto GetObjectFromHandleExit;
+ }
+
+ hi = HandleToHandleIndex(h);
+
+ *pdwRightsGranted = m_rghteHandleTable[hi].dwAccessRights;
+ *ppObject = m_rghteHandleTable[hi].u.pObject;
+ (*ppObject)->AddReference();
+
+GetObjectFromHandleExit:
+
+ Unlock(pThread);
+
+ return palError;
+}
+
+PAL_ERROR
+CSimpleHandleManager::FreeHandle(
+ CPalThread *pThread,
+ HANDLE h
+ )
+{
+ PAL_ERROR palError = NO_ERROR;
+ IPalObject *pobj = NULL;
+ HANDLE_INDEX hi = HandleToHandleIndex(h);
+
+ Lock(pThread);
+
+ if (!ValidateHandle(h))
+ {
+ ERROR("Trying to free invalid handle %p.\n", h);
+ palError = ERROR_INVALID_HANDLE;
+ goto FreeHandleExit;
+ }
+
+ if (HandleIsSpecial(h))
+ {
+ ASSERT("Trying to free Special Handle %p.\n", h);
+ palError = ERROR_INVALID_HANDLE;
+ goto FreeHandleExit;
+ }
+
+ pobj = m_rghteHandleTable[hi].u.pObject;
+ m_rghteHandleTable[hi].fEntryAllocated = FALSE;
+
+ /* add handle to the free pool */
+ if(m_hiFreeListEnd != c_hiInvalid)
+ {
+ m_rghteHandleTable[m_hiFreeListEnd].u.hiNextIndex = hi;
+ }
+ else
+ {
+ m_hiFreeListStart = hi;
+ }
+
+ m_rghteHandleTable[hi].u.hiNextIndex = c_hiInvalid;
+ m_hiFreeListEnd = hi;
+
+FreeHandleExit:
+
+ Unlock(pThread);
+
+ if (NULL != pobj)
+ {
+ pobj->ReleaseReference(pThread);
+ }
+
+ return palError;
+}
+
+/*++
+Function :
+ ValidateHandle
+
+ Check if a handle was allocated by this handle manager
+
+Parameters :
+ HANDLE handle : handle to check.
+
+Return Value :
+ TRUE if valid, FALSE if invalid.
+--*/
+bool CSimpleHandleManager::ValidateHandle(HANDLE handle)
+{
+ DWORD dwIndex;
+
+ if (NULL == m_rghteHandleTable)
+ {
+ ASSERT("Handle Manager is not initialized!\n");
+ return FALSE;
+ }
+
+ if (handle == INVALID_HANDLE_VALUE || handle == 0)
+ {
+ TRACE( "INVALID_HANDLE_VALUE or NULL value is not a valid handle.\n" );
+ return FALSE;
+ }
+
+ if (HandleIsSpecial(handle))
+ {
+ //
+ // Special handles are valid in the general sense. They are not valid
+ // in this context, though, as they were not allocated by the handle
+ // manager. Hitting this case indicates a logic error within the PAL
+ // (since clients of the handle manager should have already dealt with
+ // the specialness of the handle) so we assert here.
+ //
+
+ ASSERT ("Handle %p is a special handle, returning FALSE.\n", handle);
+ return FALSE;
+ }
+
+ dwIndex = HandleToHandleIndex(handle);
+
+ if (dwIndex >= m_dwTableSize)
+ {
+ WARN( "The handle value(%p) is out of the bounds for the handle table.\n", handle );
+ return FALSE;
+ }
+
+ if (!m_rghteHandleTable[dwIndex].fEntryAllocated)
+ {
+ WARN("The handle value (%p) has not been allocated\n", handle);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+bool
+CorUnix::HandleIsSpecial(
+ HANDLE h
+ )
+{
+ return (hPseudoCurrentProcess == h ||
+ hPseudoCurrentThread == h ||
+ hPseudoGlobalIOCP == h);
+}
+
diff --git a/src/pal/src/include/pal/cert.hpp b/src/pal/src/include/pal/cert.hpp
new file mode 100644
index 0000000000..77c7f28d1a
--- /dev/null
+++ b/src/pal/src/include/pal/cert.hpp
@@ -0,0 +1,33 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ include/pal/cert.hpp
+
+Abstract:
+ Header file for cert structures
+
+
+
+--*/
+
+#ifndef _PAL_CERT_HPP_
+#define _PAL_CERT_HPP_
+
+#include "corunix.hpp"
+
+#include <Security/Security.h>
+
+CorUnix::PAL_ERROR OIDToStr(CSSM_DATA &data, CHAR *&oidStrOut);
+
+CSSM_RETURN InitCSSMModule(const CSSM_GUID *inGuid, CSSM_SERVICE_TYPE inService,
+ CSSM_MODULE_HANDLE_PTR outModule);
+CSSM_RETURN TermCSSMModule(const CSSM_GUID *inGuid, CSSM_MODULE_HANDLE_PTR inModule);
+
+#endif // !_PAL_CERT_HPP_
diff --git a/src/pal/src/include/pal/context.h b/src/pal/src/include/pal/context.h
new file mode 100644
index 0000000000..5e378942fb
--- /dev/null
+++ b/src/pal/src/include/pal/context.h
@@ -0,0 +1,641 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ include/pal/context.h
+
+Abstract:
+
+ Header file for thread context utility functions.
+
+
+
+--*/
+
+#ifndef _PAL_CONTEXT_H_
+#define _PAL_CONTEXT_H_
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif // __cplusplus
+
+#include <signal.h>
+#include <pthread.h>
+
+#if !HAVE_MACH_EXCEPTIONS
+/* A type to wrap the native context type, which is ucontext_t on some
+ * platforms and another type elsewhere. */
+#if HAVE_UCONTEXT_T
+#include <ucontext.h>
+
+typedef ucontext_t native_context_t;
+#else // HAVE_UCONTEXT_T
+#error Native context type is not known on this platform!
+#endif // HAVE_UCONTEXT_T
+#else // !HAVE_MACH_EXCEPTIONS
+#include <mach/kern_return.h>
+#include <mach/mach_port.h>
+#endif // !HAVE_MACH_EXCEPTIONS else
+
+#if HAVE___GREGSET_T
+
+#ifdef BIT64
+#define MCREG_Rbx(mc) ((mc).__gregs[_REG_RBX])
+#define MCREG_Rcx(mc) ((mc).__gregs[_REG_RCX])
+#define MCREG_Rdx(mc) ((mc).__gregs[_REG_RDX])
+#define MCREG_Rsi(mc) ((mc).__gregs[_REG_RSI])
+#define MCREG_Rdi(mc) ((mc).__gregs[_REG_RDI])
+#define MCREG_Rbp(mc) ((mc).__gregs[_REG_RBP])
+#define MCREG_Rax(mc) ((mc).__gregs[_REG_RAX])
+#define MCREG_Rip(mc) ((mc).__gregs[_REG_RIP])
+#define MCREG_Rsp(mc) ((mc).__gregs[_REG_RSP])
+#define MCREG_SegCs(mc) ((mc).__gregs[_REG_CS])
+#define MCREG_SegSs(mc) ((mc).__gregs[_REG_SS])
+#define MCREG_R8(mc) ((mc).__gregs[_REG_R8])
+#define MCREG_R9(mc) ((mc).__gregs[_REG_R9])
+#define MCREG_R10(mc) ((mc).__gregs[_REG_R10])
+#define MCREG_R11(mc) ((mc).__gregs[_REG_R11])
+#define MCREG_R12(mc) ((mc).__gregs[_REG_R12])
+#define MCREG_R13(mc) ((mc).__gregs[_REG_R13])
+#define MCREG_R14(mc) ((mc).__gregs[_REG_R14])
+#define MCREG_R15(mc) ((mc).__gregs[_REG_R15])
+#define MCREG_EFlags(mc) ((mc).__gregs[_REG_RFLAGS])
+
+#define FPREG_Xmm(uc, index) *(M128A*)&(((struct fxsave*)(&(uc)->uc_mcontext.__fpregs))->fx_xmm[index])
+
+#define FPREG_St(uc, index) *(M128A*)&(((struct fxsave*)(&(uc)->uc_mcontext.__fpregs))->fx_87_ac[index])
+
+#define FPREG_ControlWord(uc) (((struct fxsave*)(&(uc)->uc_mcontext.__fpregs))->fx_cw)
+#define FPREG_StatusWord(uc) (((struct fxsave*)(&(uc)->uc_mcontext.__fpregs))->fx_sw)
+#define FPREG_TagWord(uc) (((struct fxsave*)(&(uc)->uc_mcontext.__fpregs))->fx_tw)
+#define FPREG_ErrorOffset(uc) (*(DWORD*) &(((struct fxsave*)(&(uc)->uc_mcontext.__fpregs))->fx_ip))
+#define FPREG_ErrorSelector(uc) *((WORD*) &(((struct fxsave*)(&(uc)->uc_mcontext.__fpregs))->fx_ip) + 2)
+#define FPREG_DataOffset(uc) (*(DWORD*) &(((struct fxsave*)(&(uc)->uc_mcontext.__fpregs))->fx_dp))
+#define FPREG_DataSelector(uc) *((WORD*) &(((struct fxsave*)(&(uc)->uc_mcontext.__fpregs))->fx_dp) + 2)
+#define FPREG_MxCsr(uc) (((struct fxsave*)(&(uc)->uc_mcontext.__fpregs))->fx_mxcsr)
+#define FPREG_MxCsr_Mask(uc) (((struct fxsave*)(&(uc)->uc_mcontext.__fpregs))->fx_mxcsr_mask)
+
+#else // BIT64
+
+#define MCREG_Ebx(mc) ((mc).__gregs[_REG_EBX])
+#define MCREG_Ecx(mc) ((mc).__gregs[_REG_ECX])
+#define MCREG_Edx(mc) ((mc).__gregs[_REG_EDX])
+#define MCREG_Esi(mc) ((mc).__gregs[_REG_ESI])
+#define MCREG_Edi(mc) ((mc).__gregs[_REG_EDI])
+#define MCREG_Ebp(mc) ((mc).__gregs[_REG_EBP])
+#define MCREG_Eax(mc) ((mc).__gregs[_REG_EAX])
+#define MCREG_Eip(mc) ((mc).__gregs[_REG_EIP])
+#define MCREG_Esp(mc) ((mc).__gregs[_REG_ESP])
+#define MCREG_SegCs(mc) ((mc).__gregs[_REG_CS])
+#define MCREG_SegSs(mc) ((mc).__gregs[_REG_SS])
+#define MCREG_EFlags(mc) ((mc).__gregs[_REG_RFLAGS])
+
+#endif // BIT64
+
+#elif HAVE_GREGSET_T
+
+#ifdef BIT64
+#define MCREG_Rbx(mc) ((mc).gregs[REG_RBX])
+#define MCREG_Rcx(mc) ((mc).gregs[REG_RCX])
+#define MCREG_Rdx(mc) ((mc).gregs[REG_RDX])
+#define MCREG_Rsi(mc) ((mc).gregs[REG_RSI])
+#define MCREG_Rdi(mc) ((mc).gregs[REG_RDI])
+#define MCREG_Rbp(mc) ((mc).gregs[REG_RBP])
+#define MCREG_Rax(mc) ((mc).gregs[REG_RAX])
+#define MCREG_Rip(mc) ((mc).gregs[REG_RIP])
+#define MCREG_Rsp(mc) ((mc).gregs[REG_RSP])
+#define MCREG_SegCs(mc) (*(WORD*)&((mc).gregs[REG_CSGSFS]))
+#define MCREG_R8(mc) ((mc).gregs[REG_R8])
+#define MCREG_R9(mc) ((mc).gregs[REG_R9])
+#define MCREG_R10(mc) ((mc).gregs[REG_R10])
+#define MCREG_R11(mc) ((mc).gregs[REG_R11])
+#define MCREG_R12(mc) ((mc).gregs[REG_R12])
+#define MCREG_R13(mc) ((mc).gregs[REG_R13])
+#define MCREG_R14(mc) ((mc).gregs[REG_R14])
+#define MCREG_R15(mc) ((mc).gregs[REG_R15])
+
+#define FPREG_Fpstate(uc) ((uc)->uc_mcontext.fpregs)
+#define FPREG_Xmm(uc, index) *(M128A*)&(FPREG_Fpstate(uc)->_xmm[index])
+
+#define FPREG_St(uc, index) *(M128A*)&(FPREG_Fpstate(uc)->_st[index])
+
+#define FPREG_ControlWord(uc) (FPREG_Fpstate(uc)->cwd)
+#define FPREG_StatusWord(uc) (FPREG_Fpstate(uc)->swd)
+#define FPREG_TagWord(uc) (FPREG_Fpstate(uc)->ftw)
+#define FPREG_ErrorOffset(uc) *(DWORD*)&(FPREG_Fpstate(uc)->rip)
+#define FPREG_ErrorSelector(uc) *(((WORD*)&(FPREG_Fpstate(uc)->rip)) + 2)
+#define FPREG_DataOffset(uc) *(DWORD*)&(FPREG_Fpstate(uc)->rdp)
+#define FPREG_DataSelector(uc) *(((WORD*)&(FPREG_Fpstate(uc)->rdp)) + 2)
+#define FPREG_MxCsr(uc) (FPREG_Fpstate(uc)->mxcsr)
+#define FPREG_MxCsr_Mask(uc) (FPREG_Fpstate(uc)->mxcr_mask)
+
+/////////////////////
+// Extended state
+
+inline _fpx_sw_bytes *FPREG_FpxSwBytes(const ucontext_t *uc)
+{
+ // Bytes 464..511 in the FXSAVE format are available for software to use for any purpose. In this case, they are used to
+ // indicate information about extended state.
+ _ASSERTE(reinterpret_cast<UINT8 *>(&FPREG_Fpstate(uc)->padding[12]) - reinterpret_cast<UINT8 *>(FPREG_Fpstate(uc)) == 464);
+
+ _ASSERTE(FPREG_Fpstate(uc) != nullptr);
+
+ return reinterpret_cast<_fpx_sw_bytes *>(&FPREG_Fpstate(uc)->padding[12]);
+}
+
+inline UINT32 FPREG_ExtendedSize(const ucontext_t *uc)
+{
+ _ASSERTE(FPREG_FpxSwBytes(uc)->magic1 == FP_XSTATE_MAGIC1);
+ return FPREG_FpxSwBytes(uc)->extended_size;
+}
+
+inline bool FPREG_HasExtendedState(const ucontext_t *uc)
+{
+ // See comments in /usr/include/x86_64-linux-gnu/asm/sigcontext.h for info on how to detect if extended state is present
+ static_assert_no_msg(FP_XSTATE_MAGIC2_SIZE == sizeof(UINT32));
+
+ if (FPREG_FpxSwBytes(uc)->magic1 != FP_XSTATE_MAGIC1)
+ {
+ return false;
+ }
+
+ UINT32 extendedSize = FPREG_ExtendedSize(uc);
+ if (extendedSize < sizeof(_xstate))
+ {
+ return false;
+ }
+
+ _ASSERTE(extendedSize >= FP_XSTATE_MAGIC2_SIZE);
+ return *reinterpret_cast<UINT32 *>(reinterpret_cast<UINT8 *>(FPREG_Fpstate(uc)) + (extendedSize - FP_XSTATE_MAGIC2_SIZE))
+ == FP_XSTATE_MAGIC2;
+}
+
+inline void *FPREG_Xstate_Ymmh(const ucontext_t *uc)
+{
+ static_assert_no_msg(sizeof(reinterpret_cast<_xstate *>(FPREG_Fpstate(uc))->ymmh.ymmh_space) == 16 * 16);
+ _ASSERTE(FPREG_HasExtendedState(uc));
+
+ return reinterpret_cast<_xstate *>(FPREG_Fpstate(uc))->ymmh.ymmh_space;
+}
+
+/////////////////////
+
+#else // BIT64
+
+#define MCREG_Ebx(mc) ((mc).gregs[REG_EBX])
+#define MCREG_Ecx(mc) ((mc).gregs[REG_ECX])
+#define MCREG_Edx(mc) ((mc).gregs[REG_EDX])
+#define MCREG_Esi(mc) ((mc).gregs[REG_ESI])
+#define MCREG_Edi(mc) ((mc).gregs[REG_EDI])
+#define MCREG_Ebp(mc) ((mc).gregs[REG_EBP])
+#define MCREG_Eax(mc) ((mc).gregs[REG_EAX])
+#define MCREG_Eip(mc) ((mc).gregs[REG_EIP])
+#define MCREG_Esp(mc) ((mc).gregs[REG_ESP])
+#define MCREG_SegCs(mc) ((mc).gregs[REG_CS])
+#define MCREG_SegSs(mc) ((mc).gregs[REG_SS])
+
+#endif // BIT64
+
+#define MCREG_EFlags(mc) ((mc).gregs[REG_EFL])
+
+#else // HAVE_GREGSET_T
+
+#ifdef BIT64
+
+#if defined(_ARM64_)
+#define MCREG_X0(mc) ((mc).regs[0])
+#define MCREG_X1(mc) ((mc).regs[1])
+#define MCREG_X2(mc) ((mc).regs[2])
+#define MCREG_X3(mc) ((mc).regs[3])
+#define MCREG_X4(mc) ((mc).regs[4])
+#define MCREG_X5(mc) ((mc).regs[5])
+#define MCREG_X6(mc) ((mc).regs[6])
+#define MCREG_X7(mc) ((mc).regs[7])
+#define MCREG_X8(mc) ((mc).regs[8])
+#define MCREG_X9(mc) ((mc).regs[9])
+#define MCREG_X10(mc) ((mc).regs[10])
+#define MCREG_X11(mc) ((mc).regs[11])
+#define MCREG_X12(mc) ((mc).regs[12])
+#define MCREG_X13(mc) ((mc).regs[13])
+#define MCREG_X14(mc) ((mc).regs[14])
+#define MCREG_X15(mc) ((mc).regs[15])
+#define MCREG_X16(mc) ((mc).regs[16])
+#define MCREG_X17(mc) ((mc).regs[17])
+#define MCREG_X18(mc) ((mc).regs[18])
+#define MCREG_X19(mc) ((mc).regs[19])
+#define MCREG_X20(mc) ((mc).regs[20])
+#define MCREG_X21(mc) ((mc).regs[21])
+#define MCREG_X22(mc) ((mc).regs[22])
+#define MCREG_X23(mc) ((mc).regs[23])
+#define MCREG_X24(mc) ((mc).regs[24])
+#define MCREG_X25(mc) ((mc).regs[25])
+#define MCREG_X26(mc) ((mc).regs[26])
+#define MCREG_X27(mc) ((mc).regs[27])
+#define MCREG_X28(mc) ((mc).regs[28])
+#define MCREG_Fp(mc) ((mc).regs[29])
+#define MCREG_Lr(mc) ((mc).regs[30])
+
+#define MCREG_Sp(mc) ((mc).sp)
+#define MCREG_Pc(mc) ((mc).pc)
+#define MCREG_PState(mc) ((mc).pstate)
+#define MCREG_Cpsr(mc) ((mc).cpsr)
+#else
+ // For FreeBSD, as found in x86/ucontext.h
+#define MCREG_Rbp(mc) ((mc).mc_rbp)
+#define MCREG_Rip(mc) ((mc).mc_rip)
+#define MCREG_Rsp(mc) ((mc).mc_rsp)
+#define MCREG_Rsi(mc) ((mc).mc_rsi)
+#define MCREG_Rdi(mc) ((mc).mc_rdi)
+#define MCREG_Rbx(mc) ((mc).mc_rbx)
+#define MCREG_Rdx(mc) ((mc).mc_rdx)
+#define MCREG_Rcx(mc) ((mc).mc_rcx)
+#define MCREG_Rax(mc) ((mc).mc_rax)
+#define MCREG_R8(mc) ((mc).mc_r8)
+#define MCREG_R9(mc) ((mc).mc_r9)
+#define MCREG_R10(mc) ((mc).mc_r10)
+#define MCREG_R11(mc) ((mc).mc_r11)
+#define MCREG_R12(mc) ((mc).mc_r12)
+#define MCREG_R13(mc) ((mc).mc_r13)
+#define MCREG_R14(mc) ((mc).mc_r14)
+#define MCREG_R15(mc) ((mc).mc_r15)
+#define MCREG_EFlags(mc) ((mc).mc_rflags)
+#define MCREG_SegCs(mc) ((mc).mc_cs)
+
+ // from x86/fpu.h: struct __envxmm64
+#define FPSTATE(uc) ((savefpu*)((uc)->uc_mcontext.mc_fpstate))
+#define FPREG_ControlWord(uc) FPSTATE(uc)->sv_env.en_cw
+#define FPREG_StatusWord(uc) FPSTATE(uc)->sv_env.en_sw
+#define FPREG_TagWord(uc) FPSTATE(uc)->sv_env.en_tw
+#define FPREG_MxCsr(uc) FPSTATE(uc)->sv_env.en_mxcsr
+#define FPREG_MxCsr_Mask(uc) FPSTATE(uc)->sv_env.en_mxcsr_mask
+#define FPREG_ErrorOffset(uc) *(DWORD*) &(FPSTATE(uc)->sv_env.en_rip)
+#define FPREG_ErrorSelector(uc) *((WORD*) &(FPSTATE(uc)->sv_env.en_rip) + 2)
+#define FPREG_DataOffset(uc) *(DWORD*) &(FPSTATE(uc)->sv_env.en_rdp)
+#define FPREG_DataSelector(uc) *((WORD*) &(FPSTATE(uc)->sv_env.en_rdp) + 2)
+
+#define FPREG_Xmm(uc, index) *(M128A*) &(FPSTATE(uc)->sv_xmm[index])
+#define FPREG_St(uc, index) *(M128A*) &(FPSTATE(uc)->sv_fp[index].fp_acc)
+#endif
+
+#else // BIT64
+
+#if defined(_ARM_)
+
+#define MCREG_R0(mc) ((mc).arm_r0)
+#define MCREG_R1(mc) ((mc).arm_r1)
+#define MCREG_R2(mc) ((mc).arm_r2)
+#define MCREG_R3(mc) ((mc).arm_r3)
+#define MCREG_R4(mc) ((mc).arm_r4)
+#define MCREG_R5(mc) ((mc).arm_r5)
+#define MCREG_R6(mc) ((mc).arm_r6)
+#define MCREG_R7(mc) ((mc).arm_r7)
+#define MCREG_R8(mc) ((mc).arm_r8)
+#define MCREG_R9(mc) ((mc).arm_r9)
+#define MCREG_R10(mc) ((mc).arm_r10)
+#define MCREG_R11(mc) ((mc).arm_fp)
+#define MCREG_R12(mc) ((mc).arm_ip)
+#define MCREG_Sp(mc) ((mc).arm_sp)
+#define MCREG_Lr(mc) ((mc).arm_lr)
+#define MCREG_Pc(mc) ((mc).arm_pc)
+#define MCREG_Cpsr(mc) ((mc).arm_cpsr)
+
+#elif defined(_X86_)
+
+#define MCREG_Ebx(mc) ((mc).mc_ebx)
+#define MCREG_Ecx(mc) ((mc).mc_ecx)
+#define MCREG_Edx(mc) ((mc).mc_edx)
+#define MCREG_Esi(mc) ((mc).mc_esi)
+#define MCREG_Edi(mc) ((mc).mc_edi)
+#define MCREG_Ebp(mc) ((mc).mc_ebp)
+#define MCREG_Eax(mc) ((mc).mc_eax)
+#define MCREG_Eip(mc) ((mc).mc_eip)
+#define MCREG_SegCs(mc) ((mc).mc_cs)
+#define MCREG_EFlags(mc) ((mc).mc_eflags)
+#define MCREG_Esp(mc) ((mc).mc_esp)
+#define MCREG_SegSs(mc) ((mc).mc_ss)
+
+#else
+#error "Unsupported arch"
+#endif
+
+#endif // BIT64
+
+#endif // HAVE_GREGSET_T
+
+
+#if HAVE_PT_REGS
+
+#ifdef BIT64
+#define PTREG_Rbx(ptreg) ((ptreg).rbx)
+#define PTREG_Rcx(ptreg) ((ptreg).rcx)
+#define PTREG_Rdx(ptreg) ((ptreg).rdx)
+#define PTREG_Rsi(ptreg) ((ptreg).rsi)
+#define PTREG_Rdi(ptreg) ((ptreg).rdi)
+#define PTREG_Rbp(ptreg) ((ptreg).rbp)
+#define PTREG_Rax(ptreg) ((ptreg).rax)
+#define PTREG_Rip(ptreg) ((ptreg).rip)
+#define PTREG_SegCs(ptreg) ((ptreg).cs)
+#define PTREG_SegSs(ptreg) ((ptreg).ss)
+#define PTREG_Rsp(ptreg) ((ptreg).rsp)
+#define PTREG_R8(ptreg) ((ptreg).r8)
+#define PTREG_R9(ptreg) ((ptreg).r9)
+#define PTREG_R10(ptreg) ((ptreg).r10)
+#define PTREG_R11(ptreg) ((ptreg).r11)
+#define PTREG_R12(ptreg) ((ptreg).r12)
+#define PTREG_R13(ptreg) ((ptreg).r13)
+#define PTREG_R14(ptreg) ((ptreg).r14)
+#define PTREG_R15(ptreg) ((ptreg).r15)
+
+#else // BIT64
+
+#if defined(_ARM_)
+#define PTREG_R0(ptreg) ((ptreg).uregs[0])
+#define PTREG_R1(ptreg) ((ptreg).uregs[1])
+#define PTREG_R2(ptreg) ((ptreg).uregs[2])
+#define PTREG_R3(ptreg) ((ptreg).uregs[3])
+#define PTREG_R4(ptreg) ((ptreg).uregs[4])
+#define PTREG_R5(ptreg) ((ptreg).uregs[5])
+#define PTREG_R6(ptreg) ((ptreg).uregs[6])
+#define PTREG_R7(ptreg) ((ptreg).uregs[7])
+#define PTREG_R8(ptreg) ((ptreg).uregs[8])
+#define PTREG_R9(ptreg) ((ptreg).uregs[9])
+#define PTREG_R10(ptreg) ((ptreg).uregs[10])
+#define PTREG_R11(ptreg) ((ptreg).uregs[11])
+#define PTREG_R12(ptreg) ((ptreg).uregs[12])
+#define PTREG_Sp(ptreg) ((ptreg).uregs[13])
+#define PTREG_Lr(ptreg) ((ptreg).uregs[14])
+#define PTREG_Pc(ptreg) ((ptreg).uregs[15])
+#define PTREG_Cpsr(ptreg) ((ptreg).uregs[16])
+#elif defined(_X86_)
+#define PTREG_Ebx(ptreg) ((ptreg).ebx)
+#define PTREG_Ecx(ptreg) ((ptreg).ecx)
+#define PTREG_Edx(ptreg) ((ptreg).edx)
+#define PTREG_Esi(ptreg) ((ptreg).esi)
+#define PTREG_Edi(ptreg) ((ptreg).edi)
+#define PTREG_Ebp(ptreg) ((ptreg).ebp)
+#define PTREG_Eax(ptreg) ((ptreg).eax)
+#define PTREG_Eip(ptreg) ((ptreg).eip)
+#define PTREG_SegCs(ptreg) ((ptreg).xcs)
+#define PTREG_SegSs(ptreg) ((ptreg).xss)
+#define PTREG_Esp(ptreg) ((ptreg).esp)
+#else
+#error "Unsupported arch"
+#endif
+
+#endif // BIT64
+
+
+#define PTREG_EFlags(ptreg) ((ptreg).eflags)
+
+#endif // HAVE_PT_REGS
+
+
+
+#if HAVE_BSD_REGS_T
+
+#ifndef BSD_REGS_STYLE
+#error "struct reg" has unrecognized format
+#endif
+
+#ifdef BIT64
+
+#define BSDREG_Rbx(reg) BSD_REGS_STYLE(reg,RBX,rbx)
+#define BSDREG_Rcx(reg) BSD_REGS_STYLE(reg,RCX,rcx)
+#define BSDREG_Rdx(reg) BSD_REGS_STYLE(reg,RDX,rdx)
+#define BSDREG_Rsi(reg) BSD_REGS_STYLE(reg,RSI,rsi)
+#define BSDREG_Rdi(reg) BSD_REGS_STYLE(reg,RDI,rdi)
+#define BSDREG_Rbp(reg) BSD_REGS_STYLE(reg,RBP,rbp)
+#define BSDREG_Rax(reg) BSD_REGS_STYLE(reg,RAX,rax)
+#define BSDREG_Rip(reg) BSD_REGS_STYLE(reg,RIP,rip)
+#define BSDREG_SegCs(reg) BSD_REGS_STYLE(reg,CS,cs)
+#define BSDREG_SegSs(reg) BSD_REGS_STYLE(reg,SS,ss)
+#define BSDREG_Rsp(reg) BSD_REGS_STYLE(reg,RSP,rsp)
+#define BSDREG_R8(reg) BSD_REGS_STYLE(reg,R8,r8)
+#define BSDREG_R9(reg) BSD_REGS_STYLE(reg,R9,r9)
+#define BSDREG_R10(reg) BSD_REGS_STYLE(reg,R10,r10)
+#define BSDREG_R11(reg) BSD_REGS_STYLE(reg,R11,r11)
+#define BSDREG_R12(reg) BSD_REGS_STYLE(reg,R12,r12)
+#define BSDREG_R13(reg) BSD_REGS_STYLE(reg,R13,r13)
+#define BSDREG_R14(reg) BSD_REGS_STYLE(reg,R14,r14)
+#define BSDREG_R15(reg) BSD_REGS_STYLE(reg,R15,r15)
+#define BSDREG_EFlags(reg) BSD_REGS_STYLE(reg,RFLAGS,rflags)
+
+#else // BIT64
+
+#define BSDREG_Ebx(reg) BSD_REGS_STYLE(reg,EBX,ebx)
+#define BSDREG_Ecx(reg) BSD_REGS_STYLE(reg,ECX,ecx)
+#define BSDREG_Edx(reg) BSD_REGS_STYLE(reg,EDX,edx)
+#define BSDREG_Esi(reg) BSD_REGS_STYLE(reg,ESI,esi)
+#define BSDREG_Edi(reg) BSD_REGS_STYLE(reg,EDI,edi)
+#define BSDREG_Ebp(reg) BSD_REGS_STYLE(reg,EDP,ebp)
+#define BSDREG_Eax(reg) BSD_REGS_STYLE(reg,EAX,eax)
+#define BSDREG_Eip(reg) BSD_REGS_STYLE(reg,EIP,eip)
+#define BSDREG_SegCs(reg) BSD_REGS_STYLE(reg,CS,cs)
+#define BSDREG_EFlags(reg) BSD_REGS_STYLE(reg,EFLAGS,eflags)
+#define BSDREG_Esp(reg) BSD_REGS_STYLE(reg,ESP,esp)
+#define BSDREG_SegSs(reg) BSD_REGS_STYLE(reg,SS,ss)
+
+#endif // BIT64
+
+#endif // HAVE_BSD_REGS_T
+
+inline static DWORD64 CONTEXTGetPC(LPCONTEXT pContext)
+{
+#if defined(_AMD64_)
+ return pContext->Rip;
+#elif defined(_ARM64_) || defined(_ARM_)
+ return pContext->Pc;
+#else
+#error don't know how to get the program counter for this architecture
+#endif
+}
+
+inline static void CONTEXTSetPC(LPCONTEXT pContext, DWORD64 pc)
+{
+#if defined(_AMD64_)
+ pContext->Rip = pc;
+#elif defined(_ARM64_) || defined(_ARM_)
+ pContext->Pc = pc;
+#else
+#error don't know how to set the program counter for this architecture
+#endif
+}
+
+/*++
+Function :
+ CONTEXT_CaptureContext
+
+ Captures the context of the caller.
+ The returned context is suitable for performing
+ a virtual unwind.
+
+Parameters :
+ LPCONTEXT lpContext : new context
+
+--*/
+void
+CONTEXT_CaptureContext(
+ LPCONTEXT lpContext
+ );
+
+/*++
+Function :
+ CONTEXT_SetThreadContext
+
+ Processor-dependent implementation of SetThreadContext
+
+Parameters :
+ HANDLE hThread : thread whose context is to be set
+ CONTEXT *lpContext : new context
+
+Return value :
+ TRUE on success, FALSE on failure
+
+--*/
+BOOL
+CONTEXT_SetThreadContext(
+ DWORD dwProcessId,
+ pthread_t self,
+ CONST CONTEXT *lpContext
+ );
+
+/*++
+Function :
+ CONTEXT_GetThreadContext
+
+ Processor-dependent implementation of GetThreadContext
+
+Parameters :
+ HANDLE hThread : thread whose context is to retrieved
+ LPCONTEXT lpContext : destination for thread's context
+
+Return value :
+ TRUE on success, FALSE on failure
+
+--*/
+BOOL
+CONTEXT_GetThreadContext(
+ DWORD dwProcessId,
+ pthread_t self,
+ LPCONTEXT lpContext);
+
+#if HAVE_MACH_EXCEPTIONS
+/*++
+Function:
+ CONTEXT_GetThreadContextFromPort
+
+ Helper for GetThreadContext that uses a mach_port
+--*/
+kern_return_t
+CONTEXT_GetThreadContextFromPort(
+ mach_port_t Port,
+ LPCONTEXT lpContext);
+
+/*++
+Function:
+ SetThreadContextOnPort
+
+ Helper for CONTEXT_SetThreadContext
+--*/
+kern_return_t
+CONTEXT_SetThreadContextOnPort(
+ mach_port_t Port,
+ IN CONST CONTEXT *lpContext);
+
+/*++
+Function:
+ GetThreadContextFromThreadState
+
+ Helper for mach exception support
+--*/
+void
+CONTEXT_GetThreadContextFromThreadState(
+ thread_state_flavor_t stateFlavor,
+ thread_state_t threadState,
+ LPCONTEXT lpContext);
+
+#else // HAVE_MACH_EXCEPTIONS
+/*++
+Function :
+ CONTEXTToNativeContext
+
+ Converts a CONTEXT record to a native context.
+
+Parameters :
+ CONST CONTEXT *lpContext : CONTEXT to convert, including
+ flags that determine which registers are valid in
+ lpContext and which ones to set in native
+ native_context_t *native : native context to fill in
+
+Return value :
+ None
+
+--*/
+void CONTEXTToNativeContext(CONST CONTEXT *lpContext, native_context_t *native);
+
+/*++
+Function :
+ CONTEXTFromNativeContext
+
+ Converts a native context to a CONTEXT record.
+
+Parameters :
+ const native_context_t *native : native context to convert
+ LPCONTEXT lpContext : CONTEXT to fill in
+ ULONG contextFlags : flags that determine which registers are valid in
+ native and which ones to set in lpContext
+
+Return value :
+ None
+
+--*/
+void CONTEXTFromNativeContext(const native_context_t *native, LPCONTEXT lpContext,
+ ULONG contextFlags);
+
+/*++
+Function :
+ GetNativeContextPC
+
+ Returns the program counter from the native context.
+
+Parameters :
+ const native_context_t *context : native context
+
+Return value :
+ The program counter from the native context.
+
+--*/
+LPVOID GetNativeContextPC(const native_context_t *context);
+
+/*++
+Function :
+ CONTEXTGetExceptionCodeForSignal
+
+ Translates signal and context information to a Win32 exception code.
+
+Parameters :
+ const siginfo_t *siginfo : signal information from a signal handler
+ const native_context_t *context : context information
+
+Return value :
+ The Win32 exception code that corresponds to the signal and context
+ information.
+
+--*/
+DWORD CONTEXTGetExceptionCodeForSignal(const siginfo_t *siginfo,
+ const native_context_t *context);
+
+#endif // HAVE_MACH_EXCEPTIONS else
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _PAL_CONTEXT_H_
diff --git a/src/pal/src/include/pal/corunix.hpp b/src/pal/src/include/pal/corunix.hpp
new file mode 100644
index 0000000000..e9e9503ed3
--- /dev/null
+++ b/src/pal/src/include/pal/corunix.hpp
@@ -0,0 +1,1359 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ corunix.hpp
+
+Abstract:
+
+ Internal interface and object definitions
+
+
+
+--*/
+
+#ifndef _CORUNIX_H
+#define _CORUNIX_H
+
+#include "palinternal.h"
+
+namespace CorUnix
+{
+ typedef DWORD PAL_ERROR;
+
+ //
+ // Forward declarations for classes defined in other headers
+ //
+
+ class CPalThread;
+
+ //
+ // Forward declarations for items in this header
+ //
+
+ class CObjectType;
+ class IPalObject;
+
+ //
+ // A simple counted string class. Using counted strings
+ // allows for some optimizations when searching for a matching string.
+ //
+
+ class CPalString
+ {
+ protected:
+
+ const WCHAR *m_pwsz; // NULL terminated
+
+ //
+ // Length of string, not including terminating NULL
+ //
+
+ DWORD m_dwStringLength;
+
+ //
+ // Length of buffer backing string; must be at least 1+dwStringLength
+ //
+
+ DWORD m_dwMaxLength;
+
+ public:
+
+ CPalString()
+ :
+ m_pwsz(NULL),
+ m_dwStringLength(0),
+ m_dwMaxLength(0)
+ {
+ };
+
+ CPalString(
+ const WCHAR *pwsz
+ )
+ {
+ SetString(pwsz);
+ };
+
+ void
+ SetString(
+ const WCHAR *pwsz
+ )
+ {
+ SetStringWithLength(pwsz, PAL_wcslen(pwsz));
+ };
+
+ void
+ SetStringWithLength(
+ const WCHAR *pwsz,
+ DWORD dwStringLength
+ )
+ {
+ m_pwsz = pwsz;
+ m_dwStringLength = dwStringLength;
+ m_dwMaxLength = m_dwStringLength + 1;
+
+ };
+
+ PAL_ERROR
+ CopyString(
+ CPalString *psSource
+ );
+
+ void
+ FreeBuffer();
+
+ const WCHAR *
+ GetString()
+ {
+ return m_pwsz;
+ };
+
+ DWORD
+ GetStringLength()
+ {
+ return m_dwStringLength;
+ };
+
+ DWORD
+ GetMaxLength()
+ {
+ return m_dwMaxLength;
+ };
+
+ };
+
+ //
+ // Signature of the cleanup routine that is to be called for an object
+ // type when:
+ // 1) The object's refcount drops to 0
+ // 2) A process is shutting down
+ // 3) A process has released all local references to the object
+ //
+ // The cleanup routine must only cleanup the object's shared state
+ // when the last parameter (fCleanupSharedSate) is TRUE. When
+ // fCleanupSharedState is FALSE the cleanup routine must not attempt
+ // to access the shared data for the object, as another process may
+ // have already deleted it. ($$REIVEW -- would someone ever need access
+ // to the shared data in order to cleanup process local state?)
+ //
+ // When the third paramter (fShutdown) is TRUE the process is in
+ // the act of exiting. The cleanup routine should not perform any
+ // unnecessary cleanup operations (e.g., closing file descriptors,
+ // since the OS will automatically close them when the process exits)
+ // in this situation.
+ //
+
+ typedef void (*OBJECTCLEANUPROUTINE) (
+ CPalThread *, // pThread
+ IPalObject *, // pObjectToCleanup
+ bool, // fShutdown
+ bool // fCleanupSharedState
+ );
+
+ //
+ // Signature of the initialization routine that is to be called
+ // when the first reference within a process to an existing
+ // object comes into existence. This routine is responsible for
+ // initializing the object's process local data, based on the
+ // immutable and shared data. The thread that this routine is
+ // called on holds an implicit read lock on the shared data.
+ //
+
+ typedef PAL_ERROR (*OBJECTINITROUTINE) (
+ CPalThread *, // pThread
+ CObjectType *, // pObjectType
+ void *, // pImmutableData
+ void *, // pSharedData
+ void * // pProcessLocalData
+ );
+
+ enum PalObjectTypeId
+ {
+ otiAutoResetEvent = 0,
+ otiManualResetEvent,
+ otiMutex,
+ otiNamedMutex,
+ otiSemaphore,
+ otiFile,
+ otiFileMapping,
+ otiSocket,
+ otiProcess,
+ otiThread,
+ otiIOCompletionPort,
+ ObjectTypeIdCount // This entry must come last in the enumeration
+ };
+
+ //
+ // There should be one instance of CObjectType for each supported
+ // type in a process; this allows for pointer equality tests
+ // to be used (though in general it's probably better to use
+ // checks based on the type ID). All members of this structure are
+ // immutable.
+ //
+ // The data size members control how much space will be allocated for
+ // instances of this object. Any or all of those members may be 0.
+ //
+ // dwSupportedAccessRights is the mask of valid access bits for this
+ // object type. Supported generic rights should not be included in
+ // this member.
+ //
+ // The generic access rights mapping (structure TBD) defines how the
+ // supported generic access rights (e.g., GENERIC_READ) map to the
+ // specific access rights for this object type.
+ //
+ // If instances of this object may have a security descriptor set on
+ // them eSecuritySupport should be set to SecuritySupported. If the OS can
+ // persist security information for the object type (as would be the case
+ // for, say, files) eSecurityPersistence should be set to
+ // OSPersistedSecurityInfo.
+ //
+ // If the object may have a name eObjectNameSupport should be
+ // ObjectCanHaveName. A named object can be opened in more than one
+ // process.
+ //
+ // If it is possible to duplicate a handle to an object across process
+ // boundaries then eHandleDuplicationSupport should be set to
+ // CrossProcessDuplicationAllowed. Note that it is possible to have
+ // an object type where eObjectNameSupport is ObjectCanHaveName and
+ // eHandleDuplicationSupport is LocalDuplicationOnly. For these object
+ // types an unnamed object instance will only have references from
+ // the creating process.
+ //
+ // If the object may be waited on eSynchronizationSupport should be
+ // WaitableObject. (Note that this implies that object type supports
+ // the SYNCHRONIZE access right.)
+ //
+ // The remaining members describe the wait-object semantics for the
+ // object type when eSynchronizationSupport is WaitableObject:
+ //
+ // * eSignalingSemantics: SingleTransitionObject for objects that, once
+ // they transition to the signaled state, can never transition back to
+ // the unsignaled state (e.g., processes and threads)
+ //
+ // * eThreadReleaseSemantics: if ThreadReleaseAltersSignalCount the object's
+ // signal count is decremented when a waiting thread is released; otherwise,
+ // the signal count is not modified (as is desired for a manual reset event).
+ // Must be ThreadReleaseHasNoSideEffects if eSignalingSemantics is
+ // SingleTransitionObject
+ //
+ // * eOwnershipSemantics: OwnershipTracked only for mutexes, for which the
+ // previous two items must also ObjectCanBeUnsignaled and
+ // ThreadReleaseAltersSignalCount.
+ //
+
+ class CObjectType
+ {
+ public:
+
+ enum SecuritySupport
+ {
+ SecuritySupported,
+ SecurityNotSupported
+ };
+
+ enum SecurityPersistence
+ {
+ OSPersistedSecurityInfo,
+ SecurityInfoNotPersisted
+ };
+
+ enum ObjectNameSupport
+ {
+ ObjectCanHaveName,
+ UnnamedObject
+ };
+
+ enum HandleDuplicationSupport
+ {
+ CrossProcessDuplicationAllowed,
+ LocalDuplicationOnly
+ };
+
+ enum SynchronizationSupport
+ {
+ WaitableObject,
+ UnwaitableObject
+ };
+
+ enum SignalingSemantics
+ {
+ ObjectCanBeUnsignaled,
+ SingleTransitionObject,
+ SignalingNotApplicable
+ };
+
+ enum ThreadReleaseSemantics
+ {
+ ThreadReleaseAltersSignalCount,
+ ThreadReleaseHasNoSideEffects,
+ ThreadReleaseNotApplicable
+ };
+
+ enum OwnershipSemantics
+ {
+ OwnershipTracked,
+ NoOwner,
+ OwnershipNotApplicable
+ };
+
+ private:
+
+ //
+ // Array that maps object type IDs to the corresponding
+ // CObjectType instance
+ //
+
+ static CObjectType* s_rgotIdMapping[];
+
+ PalObjectTypeId m_eTypeId;
+ OBJECTCLEANUPROUTINE m_pCleanupRoutine;
+ OBJECTINITROUTINE m_pInitRoutine;
+ DWORD m_dwImmutableDataSize;
+ DWORD m_dwProcessLocalDataSize;
+ DWORD m_dwSharedDataSize;
+ DWORD m_dwSupportedAccessRights;
+ // Generic access rights mapping
+ SecuritySupport m_eSecuritySupport;
+ SecurityPersistence m_eSecurityPersistence;
+ ObjectNameSupport m_eObjectNameSupport;
+ HandleDuplicationSupport m_eHandleDuplicationSupport;
+ SynchronizationSupport m_eSynchronizationSupport;
+ SignalingSemantics m_eSignalingSemantics;
+ ThreadReleaseSemantics m_eThreadReleaseSemantics;
+ OwnershipSemantics m_eOwnershipSemantics;
+
+ public:
+
+ CObjectType(
+ PalObjectTypeId eTypeId,
+ OBJECTCLEANUPROUTINE pCleanupRoutine,
+ OBJECTINITROUTINE pInitRoutine,
+ DWORD dwImmutableDataSize,
+ DWORD dwProcessLocalDataSize,
+ DWORD dwSharedDataSize,
+ DWORD dwSupportedAccessRights,
+ SecuritySupport eSecuritySupport,
+ SecurityPersistence eSecurityPersistence,
+ ObjectNameSupport eObjectNameSupport,
+ HandleDuplicationSupport eHandleDuplicationSupport,
+ SynchronizationSupport eSynchronizationSupport,
+ SignalingSemantics eSignalingSemantics,
+ ThreadReleaseSemantics eThreadReleaseSemantics,
+ OwnershipSemantics eOwnershipSemantics
+ )
+ :
+ m_eTypeId(eTypeId),
+ m_pCleanupRoutine(pCleanupRoutine),
+ m_pInitRoutine(pInitRoutine),
+ m_dwImmutableDataSize(dwImmutableDataSize),
+ m_dwProcessLocalDataSize(dwProcessLocalDataSize),
+ m_dwSharedDataSize(dwSharedDataSize),
+ m_dwSupportedAccessRights(dwSupportedAccessRights),
+ m_eSecuritySupport(eSecuritySupport),
+ m_eSecurityPersistence(eSecurityPersistence),
+ m_eObjectNameSupport(eObjectNameSupport),
+ m_eHandleDuplicationSupport(eHandleDuplicationSupport),
+ m_eSynchronizationSupport(eSynchronizationSupport),
+ m_eSignalingSemantics(eSignalingSemantics),
+ m_eThreadReleaseSemantics(eThreadReleaseSemantics),
+ m_eOwnershipSemantics(eOwnershipSemantics)
+ {
+ s_rgotIdMapping[eTypeId] = this;
+ };
+
+ static
+ CObjectType *
+ GetObjectTypeById(
+ PalObjectTypeId otid
+ )
+ {
+ return s_rgotIdMapping[otid];
+ };
+
+ PalObjectTypeId
+ GetId(
+ void
+ )
+ {
+ return m_eTypeId;
+ };
+
+ OBJECTCLEANUPROUTINE
+ GetObjectCleanupRoutine(
+ void
+ )
+ {
+ return m_pCleanupRoutine;
+ };
+
+ OBJECTINITROUTINE
+ GetObjectInitRoutine(
+ void
+ )
+ {
+ return m_pInitRoutine;
+ };
+
+ DWORD
+ GetImmutableDataSize(
+ void
+ )
+ {
+ return m_dwImmutableDataSize;
+ };
+
+ DWORD
+ GetProcessLocalDataSize(
+ void
+ )
+ {
+ return m_dwProcessLocalDataSize;
+ };
+
+ DWORD
+ GetSharedDataSize(
+ void
+ )
+ {
+ return m_dwSharedDataSize;
+ };
+
+ DWORD
+ GetSupportedAccessRights(
+ void
+ )
+ {
+ return m_dwSupportedAccessRights;
+ };
+
+ // Generic access rights mapping
+
+ SecuritySupport
+ GetSecuritySupport(
+ void
+ )
+ {
+ return m_eSecuritySupport;
+ };
+
+ SecurityPersistence
+ GetSecurityPersistence(
+ void
+ )
+ {
+ return m_eSecurityPersistence;
+ };
+
+ ObjectNameSupport
+ GetObjectNameSupport(
+ void
+ )
+ {
+ return m_eObjectNameSupport;
+ };
+
+ HandleDuplicationSupport
+ GetHandleDuplicationSupport(
+ void
+ )
+ {
+ return m_eHandleDuplicationSupport;
+ };
+
+ SynchronizationSupport
+ GetSynchronizationSupport(
+ void
+ )
+ {
+ return m_eSynchronizationSupport;
+ };
+
+ SignalingSemantics
+ GetSignalingSemantics(
+ void
+ )
+ {
+ return m_eSignalingSemantics;
+ };
+
+ ThreadReleaseSemantics
+ GetThreadReleaseSemantics(
+ void
+ )
+ {
+ return m_eThreadReleaseSemantics;
+ };
+
+ OwnershipSemantics
+ GetOwnershipSemantics(
+ void
+ )
+ {
+ return m_eOwnershipSemantics;
+ };
+ };
+
+ class CAllowedObjectTypes
+ {
+ private:
+
+ bool m_rgfAllowedTypes[ObjectTypeIdCount];
+
+ public:
+
+ bool
+ IsTypeAllowed(PalObjectTypeId eTypeId);
+
+ //
+ // Constructor for multiple allowed types
+ //
+
+ CAllowedObjectTypes(
+ PalObjectTypeId rgAllowedTypes[],
+ DWORD dwAllowedTypeCount
+ );
+
+ //
+ // Single allowed type constructor
+ //
+
+ CAllowedObjectTypes(
+ PalObjectTypeId eAllowedType
+ );
+
+ //
+ // Allow all types or no types constructor
+ //
+
+ CAllowedObjectTypes(
+ bool fAllowAllObjectTypes
+ )
+ {
+ for (DWORD dw = 0; dw < ObjectTypeIdCount; dw += 1)
+ {
+ m_rgfAllowedTypes[dw] = fAllowAllObjectTypes;
+ }
+ };
+
+ ~CAllowedObjectTypes()
+ {
+ };
+ };
+
+ //
+ // Attributes for a given object instance. If the object does not have
+ // a name the sObjectName member should be zero'd out. If the default
+ // security attributes are desired then pSecurityAttributes should
+ // be NULL.
+ //
+
+ class CObjectAttributes
+ {
+ public:
+
+ CPalString sObjectName;
+ LPSECURITY_ATTRIBUTES pSecurityAttributes;
+
+ CObjectAttributes(
+ const WCHAR *pwszObjectName,
+ LPSECURITY_ATTRIBUTES pSecurityAttributes_
+ )
+ :
+ pSecurityAttributes(pSecurityAttributes_)
+ {
+ if (NULL != pwszObjectName)
+ {
+ sObjectName.SetString(pwszObjectName);
+ }
+ };
+
+ CObjectAttributes()
+ :
+ pSecurityAttributes(NULL)
+ {
+ };
+ };
+
+ //
+ // ISynchStateController is used to modify any object's synchronization
+ // state. It is intended to be used from within the APIs exposed for
+ // various objects (e.g., SetEvent, ReleaseMutex, etc.).
+ //
+ // Each ISynchStateController instance implicitly holds what should be
+ // viewed as the global dispatcher lock, and as such should be released
+ // as quickly as possible. An ISynchStateController instance is bound to
+ // the thread that requested it; it may not be passed to a different
+ // thread.
+ //
+
+ class ISynchStateController
+ {
+ public:
+
+ virtual
+ PAL_ERROR
+ GetSignalCount(
+ LONG *plSignalCount
+ ) = 0;
+
+ virtual
+ PAL_ERROR
+ SetSignalCount(
+ LONG lNewCount
+ ) = 0;
+
+ virtual
+ PAL_ERROR
+ IncrementSignalCount(
+ LONG lAmountToIncrement
+ ) = 0;
+
+ virtual
+ PAL_ERROR
+ DecrementSignalCount(
+ LONG lAmountToDecrement
+ ) = 0;
+
+ //
+ // The following two routines may only be used for object types
+ // where eOwnershipSemantics is OwnershipTracked (i.e., mutexes).
+ //
+
+ //
+ // SetOwner is intended to be used in the implementation of
+ // CreateMutex when bInitialOwner is TRUE. It must be called
+ // before the new object instance is registered with the
+ // handle manager. Any other call to this method is an error.
+ //
+
+ virtual
+ PAL_ERROR
+ SetOwner(
+ CPalThread *pNewOwningThread
+ ) = 0;
+
+ //
+ // DecrementOwnershipCount returns an error if the object
+ // is unowned, or if the thread this controller is bound to
+ // is not the owner of the object.
+ //
+
+ virtual
+ PAL_ERROR
+ DecrementOwnershipCount(
+ void
+ ) = 0;
+
+ virtual
+ void
+ ReleaseController(
+ void
+ ) = 0;
+ };
+
+ //
+ // ISynchWaitController is used to indicate a thread's desire to wait for
+ // an object (which possibly includes detecting instances where the wait
+ // can be satisfied without blocking). It is intended to be used by object
+ // wait function (WaitForSingleObject, etc.).
+ //
+ // Each ISynchWaitController instance implicitly holds what should be
+ // viewed as the global dispatcher lock, and as such should be released
+ // as quickly as possible. An ISynchWaitController instance is bound to
+ // the thread that requested it; it may not be passed to a different
+ // thread.
+ //
+ // A thread may hold multiple ISynchWaitController instances
+ // simultaneously.
+ //
+
+ enum WaitType
+ {
+ SingleObject,
+ MultipleObjectsWaitOne,
+ MultipleObjectsWaitAll
+ };
+
+ class ISynchWaitController
+ {
+ public:
+
+ //
+ // CanThreadWaitWithoutBlocking informs the caller if a wait
+ // operation may succeed immediately, but does not actually
+ // alter any object state. ReleaseWaitingThreadWithoutBlocking
+ // alters the object state, and will return an error if it is
+ // not possible for the wait to be immediately satisfied.
+ //
+
+ virtual
+ PAL_ERROR
+ CanThreadWaitWithoutBlocking(
+ bool *pfCanWaitWithoutBlocking, // OUT
+ bool *pfAbandoned
+ ) = 0;
+
+ virtual
+ PAL_ERROR
+ ReleaseWaitingThreadWithoutBlocking(
+ ) = 0;
+
+ //
+ // dwIndex is intended for MultipleObjectsWaitOne situations. The
+ // index for the object that becomes signaled and satisfies the
+ // wait will be returned in the call to BlockThread.
+ //
+
+ virtual
+ PAL_ERROR
+ RegisterWaitingThread(
+ WaitType eWaitType,
+ DWORD dwIndex,
+ bool fAltertable
+ ) = 0;
+
+ //
+ // Why is there no unregister waiting thread routine? Unregistration
+ // is the responsibility of the synchronization provider, not the
+ // implementation of the wait object routines. (I can be convinced
+ // that this isn't the best approach, though...)
+ //
+
+ virtual
+ void
+ ReleaseController(
+ void
+ ) = 0;
+ };
+
+ enum LockType
+ {
+ ReadLock,
+ WriteLock
+ };
+
+ class IDataLock
+ {
+ public:
+
+ //
+ // If a thread obtains a write lock but does not actually
+ // modify any data it should set fDataChanged to FALSE. If
+ // a thread obtain a read lock and does actually modify any
+ // data it should be taken out back and shot.
+ //
+
+ virtual
+ void
+ ReleaseLock(
+ CPalThread *pThread, // IN, OPTIONAL
+ bool fDataChanged
+ ) = 0;
+ };
+
+ //
+ // The following two enums are part of the local object
+ // optimizations
+ //
+
+ enum ObjectDomain
+ {
+ ProcessLocalObject,
+ SharedObject
+ };
+
+ enum WaitDomain
+ {
+ LocalWait, // All objects in the wait set are local to this process
+ MixedWait, // Some objects are local; some are shared
+ SharedWait // All objects in the wait set are shared
+ };
+
+ class IPalObject
+ {
+ public:
+
+ virtual
+ CObjectType *
+ GetObjectType(
+ VOID
+ ) = 0;
+
+ virtual
+ CObjectAttributes *
+ GetObjectAttributes(
+ VOID
+ ) = 0;
+
+ virtual
+ PAL_ERROR
+ GetImmutableData(
+ void **ppvImmutableData // OUT
+ ) = 0;
+
+ //
+ // The following two routines obtain either a read or write
+ // lock on the data in question. If a thread needs to examine
+ // both process-local and shared data simultaneously it must obtain
+ // the shared data first. A thread may not hold data locks
+ // on two different objects at the same time.
+ //
+
+ virtual
+ PAL_ERROR
+ GetProcessLocalData(
+ CPalThread *pThread, // IN, OPTIONAL
+ LockType eLockRequest,
+ IDataLock **ppDataLock, // OUT
+ void **ppvProcessLocalData // OUT
+ ) = 0;
+
+ virtual
+ PAL_ERROR
+ GetSharedData(
+ CPalThread *pThread, // IN, OPTIONAL
+ LockType eLockRequest,
+ IDataLock **ppDataLock, // OUT
+ void **ppvSharedData // OUT
+ ) = 0;
+
+ //
+ // The following two routines obtain the global dispatcher lock.
+ // If a thread needs to make use of a synchronization interface
+ // and examine object data it must obtain the synchronization
+ // interface first. A thread is allowed to hold synchronization
+ // interfaces for multiple objects at the same time if it obtains
+ // all of the interfaces through a single call (see IPalSynchronizationManager
+ // below).
+ //
+ // The single-call restriction allows the underlying implementation
+ // to possibly segement the global dispatcher lock. If this restriction
+ // were not in place (i.e., if a single thread were allowed to call
+ // GetSynchXXXController for multiple objects) no such segmentation
+ // would be possible as there would be no way know in what order a
+ // thread would choose to obtain the controllers.
+ //
+ // Note: this design precludes simultaneous acquisition of both
+ // the state and wait controller for an object but there are
+ // currently no places where doing so would be necessary.
+ //
+
+ virtual
+ PAL_ERROR
+ GetSynchStateController(
+ CPalThread *pThread, // IN, OPTIONAL
+ ISynchStateController **ppStateController // OUT
+ ) = 0;
+
+ virtual
+ PAL_ERROR
+ GetSynchWaitController(
+ CPalThread *pThread, // IN, OPTIONAL
+ ISynchWaitController **ppWaitController // OUT
+ ) = 0;
+
+ virtual
+ DWORD
+ AddReference(
+ void
+ ) = 0;
+
+ virtual
+ DWORD
+ ReleaseReference(
+ CPalThread *pThread
+ ) = 0;
+
+ //
+ // This routine is mainly intended for the synchronization
+ // manager. The promotion / process synch lock must be held
+ // before calling this routine.
+ //
+
+ virtual
+ ObjectDomain
+ GetObjectDomain(
+ void
+ ) = 0;
+
+ //
+ // This routine is only for use by the synchronization manager
+ // (specifically, for GetSynch*ControllersForObjects). The
+ // caller must have acquired the appropriate lock before
+ // (whatever exactly that must be) before calling this routine.
+ //
+
+ virtual
+ PAL_ERROR
+ GetObjectSynchData(
+ VOID **ppvSynchData // OUT
+ ) = 0;
+
+ };
+
+ class IPalProcess
+ {
+ public:
+ virtual
+ DWORD
+ GetProcessID(
+ void
+ ) = 0;
+ };
+
+ class IPalObjectManager
+ {
+ public:
+
+ //
+ // Object creation (e.g., what is done by CreateEvent) is a two step
+ // process. First, the new object is allocated and the initial
+ // properties set (e.g., initially signaled). Next, the object is
+ // registered, yielding a handle. If an object of the same name
+ // and appropriate type already existed the returned handle will refer
+ // to the previously existing object, and the newly allocated object
+ // will have been thrown away.
+ //
+ // (The two phase process minimizes the amount of time that any
+ // namespace locks need to be held. While some wasted work may be
+ // done in the existing object case that work only impacts the calling
+ // thread. Checking first for existence and then allocating and
+ // initializing on failure requires any namespace lock to be held for
+ // a much longer period of time, impacting the entire system.)
+ //
+
+ virtual
+ PAL_ERROR
+ AllocateObject(
+ CPalThread *pThread, // IN, OPTIONAL
+ CObjectType *pType,
+ CObjectAttributes *pAttributes,
+ IPalObject **ppNewObject // OUT
+ ) = 0;
+
+ //
+ // After calling RegisterObject pObjectToRegister is no
+ // longer valid. If successful there are two references
+ // on the returned object -- one for the handle, and one
+ // for the instance returned in ppRegisteredObject. The
+ // caller, therefore, is responsible for releasing the
+ // latter.
+ //
+ // For named object pAllowedTypes specifies what type of
+ // existing objects can be returned in ppRegisteredObjects.
+ // This is primarily intended for CreateEvent, so that
+ // a ManualResetEvent can be returned when attempting to
+ // register an AutoResetEvent (and vice-versa). pAllowedTypes
+ // must include the type of pObjectToRegister.
+ //
+
+ virtual
+ PAL_ERROR
+ RegisterObject(
+ CPalThread *pThread, // IN, OPTIONAL
+ IPalObject *pObjectToRegister,
+ CAllowedObjectTypes *pAllowedTypes,
+ DWORD dwRightsRequested,
+ HANDLE *pHandle, // OUT
+ IPalObject **ppRegisteredObject // OUT
+ ) = 0;
+
+ //
+ // LocateObject is used for OpenXXX routines. ObtainHandleForObject
+ // is needed for the OpenXXX routines and DuplicateHandle.
+ //
+
+ virtual
+ PAL_ERROR
+ LocateObject(
+ CPalThread *pThread, // IN, OPTIONAL
+ CPalString *psObjectToLocate,
+ CAllowedObjectTypes *pAllowedTypes,
+ IPalObject **ppObject // OUT
+ ) = 0;
+
+ //
+ // pProcessForHandle is to support cross-process handle
+ // duplication. It only needs to be specified when acquiring
+ // a handle meant for use in a different process; it should
+ // be left NULL when acquiring a handle for the current
+ // process.
+ //
+
+ virtual
+ PAL_ERROR
+ ObtainHandleForObject(
+ CPalThread *pThread, // IN, OPTIONAL
+ IPalObject *pObject,
+ DWORD dwRightsRequested,
+ bool fInheritHandle,
+ IPalProcess *pProcessForHandle, // IN, OPTIONAL
+ HANDLE *pNewHandle // OUT
+ ) = 0;
+
+ virtual
+ PAL_ERROR
+ RevokeHandle(
+ CPalThread *pThread, // IN, OPTIONAL
+ HANDLE hHandleToRevoke
+ ) = 0;
+
+ //
+ // The Reference routines are called to obtain the
+ // object that a handle refers to. The caller must
+ // specify the rights that the handle must hold for
+ // the operation that it is about to perform. The caller
+ // is responsible for converting generic rights to specific
+ // rights. The caller must also specify what object types
+ // are permissible for the object.
+ //
+ // The returned object[s], on success, are referenced,
+ // and the caller is responsible for releasing those references
+ // when appropriate.
+ //
+
+ virtual
+ PAL_ERROR
+ ReferenceObjectByHandle(
+ CPalThread *pThread, // IN, OPTIONAL
+ HANDLE hHandleToReference,
+ CAllowedObjectTypes *pAllowedTypes,
+ DWORD dwRightsRequired,
+ IPalObject **ppObject // OUT
+ ) = 0;
+
+ //
+ // This routine is intended for WaitForMultipleObjects[Ex]
+ //
+
+ virtual
+ PAL_ERROR
+ ReferenceMultipleObjectsByHandleArray(
+ CPalThread *pThread, // IN, OPTIONAL
+ HANDLE rghHandlesToReference[],
+ DWORD dwHandleCount,
+ CAllowedObjectTypes *pAllowedTypes,
+ DWORD dwRightsRequired,
+ IPalObject *rgpObjects[] // OUT
+ ) = 0;
+
+ //
+ // This routine is for cross-process handle duplication.
+ //
+
+ virtual
+ PAL_ERROR
+ ReferenceObjectByForeignHandle(
+ CPalThread *pThread, // IN, OPTIONAL
+ HANDLE hForeignHandle,
+ IPalProcess *pForeignProcess,
+ CAllowedObjectTypes *pAllowedTypes,
+ DWORD dwRightsRequired,
+ IPalObject **ppObject // OUT
+ ) = 0;
+
+ };
+
+ extern IPalObjectManager *g_pObjectManager;
+
+ enum ThreadWakeupReason
+ {
+ WaitSucceeded,
+ Alerted,
+ MutexAbondoned,
+ WaitTimeout,
+ WaitFailed
+ };
+
+ class IPalSynchronizationManager
+ {
+ public:
+
+ //
+ // A thread calls BlockThread to put itself to sleep after it has
+ // registered itself with the objects it is to wait on. A thread
+ // need not have registered with any objects, as would occur in
+ // the implementation of Sleep[Ex].
+ //
+ // Needless to say a thread must not be holding any PAL locks
+ // directly or implicitly (e.g., by holding a reference to a
+ // synchronization controller) when it calls this method.
+ //
+
+ virtual
+ PAL_ERROR
+ BlockThread(
+ CPalThread *pCurrentThread,
+ DWORD dwTimeout,
+ bool fAlertable,
+ bool fIsSleep,
+ ThreadWakeupReason *peWakeupReason, // OUT
+ DWORD *pdwSignaledObject // OUT
+ ) = 0;
+
+ virtual
+ PAL_ERROR
+ AbandonObjectsOwnedByThread(
+ CPalThread *pCallingThread,
+ CPalThread *pTargetThread
+ ) = 0;
+
+ virtual
+ PAL_ERROR
+ QueueUserAPC(
+ CPalThread *pThread,
+ CPalThread *pTargetThread,
+ PAPCFUNC pfnAPC,
+ ULONG_PTR dwData
+ ) = 0;
+
+ virtual
+ bool
+ AreAPCsPending(
+ CPalThread *pThread
+ ) = 0;
+
+ virtual
+ PAL_ERROR
+ DispatchPendingAPCs(
+ CPalThread *pThread
+ ) = 0;
+
+ virtual
+ PAL_ERROR
+ SendTerminationRequestToWorkerThread() = 0;
+
+ //
+ // This routine is primarily meant for use by WaitForMultipleObjects[Ex].
+ // The caller must individually release each of the returned controller
+ // interfaces.
+ //
+
+ virtual
+ PAL_ERROR
+ GetSynchWaitControllersForObjects(
+ CPalThread *pThread,
+ IPalObject *rgObjects[],
+ DWORD dwObjectCount,
+ ISynchWaitController *rgControllers[]
+ ) = 0;
+
+ virtual
+ PAL_ERROR
+ GetSynchStateControllersForObjects(
+ CPalThread *pThread,
+ IPalObject *rgObjects[],
+ DWORD dwObjectCount,
+ ISynchStateController *rgControllers[]
+ ) = 0;
+
+ //
+ // These following routines are meant for use only by IPalObject
+ // implementations. The first two routines are used to
+ // allocate and free an object's synchronization state; the third
+ // is called during object promotion.
+ //
+
+ virtual
+ PAL_ERROR
+ AllocateObjectSynchData(
+ CObjectType *pObjectType,
+ ObjectDomain eObjectDomain,
+ VOID **ppvSynchData // OUT
+ ) = 0;
+
+ virtual
+ void
+ FreeObjectSynchData(
+ CObjectType *pObjectType,
+ ObjectDomain eObjectDomain,
+ VOID *pvSynchData
+ ) = 0;
+
+ virtual
+ PAL_ERROR
+ PromoteObjectSynchData(
+ CPalThread *pThread,
+ VOID *pvLocalSynchData,
+ VOID **ppvSharedSynchData // OUT
+ ) = 0;
+
+ //
+ // The next two routines provide access to the process-wide
+ // synchronization lock
+ //
+
+ virtual
+ void
+ AcquireProcessLock(
+ CPalThread *pThread
+ ) = 0;
+
+ virtual
+ void
+ ReleaseProcessLock(
+ CPalThread *pThread
+ ) = 0;
+
+ //
+ // The final routines are used by IPalObject::GetSynchStateController
+ // and IPalObject::GetSynchWaitController
+ //
+
+ virtual
+ PAL_ERROR
+ CreateSynchStateController(
+ CPalThread *pThread, // IN, OPTIONAL
+ CObjectType *pObjectType,
+ VOID *pvSynchData,
+ ObjectDomain eObjectDomain,
+ ISynchStateController **ppStateController // OUT
+ ) = 0;
+
+ virtual
+ PAL_ERROR
+ CreateSynchWaitController(
+ CPalThread *pThread, // IN, OPTIONAL
+ CObjectType *pObjectType,
+ VOID *pvSynchData,
+ ObjectDomain eObjectDomain,
+ ISynchWaitController **ppWaitController // OUT
+ ) = 0;
+ };
+
+ extern IPalSynchronizationManager *g_pSynchronizationManager;
+
+ class IFileTransactionLock
+ {
+ public:
+
+ //
+ // Called when the transaction completes (which includes
+ // error completions, or the outright failure to queue
+ // the transaction).
+ //
+
+ virtual
+ void
+ ReleaseLock() = 0;
+ };
+
+ class IFileLockController
+ {
+ public:
+
+ //
+ // A transaction lock is acquired before a read or write
+ // operation, and released when that operation completes.
+ // The lock is not tied to the calling thread, since w/
+ // asynch file IO the completion may occur on a different
+ // thread.
+ //
+
+ enum FileTransactionLockType
+ {
+ ReadLock,
+ WriteLock
+ };
+
+ virtual
+ PAL_ERROR
+ GetTransactionLock(
+ CPalThread *pThread, // IN, OPTIONAL
+ FileTransactionLockType eLockType,
+ DWORD dwOffsetLow,
+ DWORD dwOffsetHigh,
+ DWORD nNumberOfBytesToLockLow,
+ DWORD nNumberOfBytesToLockHigh,
+ IFileTransactionLock **ppTransactionLock // OUT
+ ) = 0;
+
+ enum FileLockExclusivity
+ {
+ ExclusiveFileLock,
+ SharedFileLock
+ };
+
+ enum FileLockWaitMode
+ {
+ FailImmediately,
+ WaitForLockAcquisition
+ };
+
+ virtual
+ PAL_ERROR
+ CreateFileLock(
+ CPalThread *pThread, // IN, OPTIONAL
+ DWORD dwOffsetLow,
+ DWORD dwOffsetHigh,
+ DWORD nNumberOfBytesToLockLow,
+ DWORD nNumberOfBytesToLockHigh,
+ FileLockExclusivity eFileLockExclusivity,
+ FileLockWaitMode eFileLockWaitMode
+ ) = 0;
+
+ virtual
+ PAL_ERROR
+ ReleaseFileLock(
+ CPalThread *pThread, // IN, OPTIONAL
+ DWORD dwOffsetLow,
+ DWORD dwOffsetHigh,
+ DWORD nNumberOfBytesToUnlockLow,
+ DWORD nNumberOfBytesToUnlockHigh
+ ) = 0;
+
+ //
+ // ReleaseController should be called from the file object's
+ // cleanup routine. It must always be called, even if fShutdown is
+ // TRUE or fCleanupSharedState is FALSE.
+ //
+
+ virtual
+ void
+ ReleaseController() = 0;
+ };
+
+ class IFileLockManager
+ {
+ public:
+
+ //
+ // GetLockControllerForFile should be called by CreateFile.
+ // It will fail if the requested access rights and share
+ // mode are not compatible with existing lock controllers
+ // for the file.
+ //
+
+ virtual
+ PAL_ERROR
+ GetLockControllerForFile(
+ CPalThread *pThread, // IN, OPTIONAL
+ LPCSTR szFileName,
+ DWORD dwAccessRights,
+ DWORD dwShareMode,
+ IFileLockController **ppLockController // OUT
+ ) = 0;
+
+ //
+ // Gets the share mode for the file
+ // (returns SHARE_MODE_NOT_INITIALIZED if file lock controller
+ // not found)
+ //
+ virtual
+ PAL_ERROR
+ GetFileShareModeForFile(
+ LPCSTR szFileName,
+ DWORD* pdwShareMode) = 0;
+ };
+
+ extern IFileLockManager *g_pFileLockManager;
+}
+
+#endif // _CORUNIX_H
+
diff --git a/src/pal/src/include/pal/corunix.inl b/src/pal/src/include/pal/corunix.inl
new file mode 100644
index 0000000000..ab0ac70462
--- /dev/null
+++ b/src/pal/src/include/pal/corunix.inl
@@ -0,0 +1,55 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+
+
+--*/
+
+#ifndef _CORUNIX_INL
+#define _CORUNIX_INL
+
+#include "corunix.hpp"
+#include "dbgmsg.h"
+
+namespace CorUnix
+{
+
+ bool CAllowedObjectTypes::IsTypeAllowed(PalObjectTypeId eTypeId)
+ {
+ _ASSERTE(eTypeId != ObjectTypeIdCount);
+ return m_rgfAllowedTypes[eTypeId];
+ };
+
+ CAllowedObjectTypes::CAllowedObjectTypes(
+ PalObjectTypeId rgAllowedTypes[],
+ DWORD dwAllowedTypeCount
+ )
+ {
+ ZeroMemory(m_rgfAllowedTypes, sizeof(m_rgfAllowedTypes));
+ for (DWORD dw = 0; dw < dwAllowedTypeCount; dw += 1)
+ {
+ _ASSERTE(rgAllowedTypes[dw] != ObjectTypeIdCount);
+ m_rgfAllowedTypes[rgAllowedTypes[dw]] = TRUE;
+ }
+ };
+
+ CAllowedObjectTypes::CAllowedObjectTypes(
+ PalObjectTypeId eAllowedType
+ )
+ {
+ ZeroMemory(m_rgfAllowedTypes, sizeof(m_rgfAllowedTypes));
+
+ _ASSERTE(eAllowedType != ObjectTypeIdCount);
+ m_rgfAllowedTypes[eAllowedType] = TRUE;
+ };
+}
+
+#endif // _CORUNIX_H
+
diff --git a/src/pal/src/include/pal/critsect.h b/src/pal/src/include/pal/critsect.h
new file mode 100644
index 0000000000..50dea95bc5
--- /dev/null
+++ b/src/pal/src/include/pal/critsect.h
@@ -0,0 +1,45 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ include/pal/critsect.h
+
+Abstract:
+
+ Header file for the critical sections functions.
+
+
+
+--*/
+
+#ifndef _PAL_CRITSECT_H_
+#define _PAL_CRITSECT_H_
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif // __cplusplus
+
+VOID InternalInitializeCriticalSection(CRITICAL_SECTION *pcs);
+VOID InternalDeleteCriticalSection(CRITICAL_SECTION *pcs);
+
+/* The following PALCEnterCriticalSection and PALCLeaveCriticalSection
+ functions are intended to provide CorUnix's InternalEnterCriticalSection
+ and InternalLeaveCriticalSection functionalities to legacy C code,
+ which has no knowledge of CPalThread, classes and namespaces.
+*/
+VOID PALCEnterCriticalSection(CRITICAL_SECTION *pcs);
+VOID PALCLeaveCriticalSection(CRITICAL_SECTION *pcs);
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif /* _PAL_CRITSECT_H_ */
+
diff --git a/src/pal/src/include/pal/cruntime.h b/src/pal/src/include/pal/cruntime.h
new file mode 100644
index 0000000000..65bf33c952
--- /dev/null
+++ b/src/pal/src/include/pal/cruntime.h
@@ -0,0 +1,247 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ include/pal/cruntime.h
+
+Abstract:
+
+ Header file for C runtime utility functions.
+
+
+
+--*/
+
+#ifndef _PAL_CRUNTIME_H_
+#define _PAL_CRUNTIME_H_
+
+#include <string.h>
+#include <stdarg.h>
+#include <pthread.h>
+
+#ifdef __cplusplus
+typedef char16_t wchar_16; // __wchar_16 (which is defined in palinternal.h) is defined as wchar_16_cpp.
+
+extern "C"
+{
+#endif // __cplusplus
+
+typedef enum
+{
+ PFF_NONE = 0,
+ PFF_MINUS = 1,
+ PFF_POUND = 2,
+ PFF_ZERO = 4,
+ PFF_SPACE = 8,
+ PFF_PLUS = 16
+}PRINTF_FORMAT_FLAGS;
+
+typedef enum
+{
+ WIDTH_DEFAULT = -1,
+ WIDTH_STAR = -2, /* e.g. "%*.10s" */
+ WIDTH_INVALID = -3 /* e.g. "%*3.10s" */
+}WIDTH_FLAGS;
+
+typedef enum
+{
+ PRECISION_DEFAULT = -1,
+ PRECISION_STAR = -2, /* e.g. "%10.*s" */
+ PRECISION_DOT = -3, /* e.g. "%10.s" */
+ PRECISION_INVALID = -4 /* e.g. "%10.*3s" */
+}PRECISION_FLAGS;
+
+typedef enum
+{
+ PFF_PREFIX_DEFAULT = -1,
+ PFF_PREFIX_SHORT = 1,
+ PFF_PREFIX_LONG = 2,
+ PFF_PREFIX_LONGLONG = 3,
+ PFF_PREFIX_LONG_W = 4
+}PRINTF_PREFIXES;
+
+typedef enum
+{
+ PFF_TYPE_DEFAULT = -1,
+ PFF_TYPE_CHAR = 1,
+ PFF_TYPE_STRING = 2,
+ PFF_TYPE_WSTRING = 3,
+ PFF_TYPE_INT = 4,
+ PFF_TYPE_P = 5,
+ PFF_TYPE_N = 6,
+ PFF_TYPE_FLOAT = 7
+}PRINTF_TYPES;
+
+typedef enum
+{
+ SCANF_PREFIX_SHORT = 1,
+ SCANF_PREFIX_LONG = 2,
+ SCANF_PREFIX_LONGLONG = 3
+}SCANF_PREFIXES;
+
+typedef enum
+{
+ SCANF_TYPE_CHAR = 1,
+ SCANF_TYPE_STRING = 2,
+ SCANF_TYPE_INT = 3,
+ SCANF_TYPE_N = 4,
+ SCANF_TYPE_FLOAT = 5,
+ SCANF_TYPE_BRACKETS = 6,
+ SCANF_TYPE_SPACE = 7
+}SCANF_TYPES;
+
+/*******************************************************************************
+Function:
+ Internal_AddPaddingA
+
+Parameters:
+ Out
+ - buffer to place padding and given string (In)
+ Count
+ - maximum chars to be copied so as not to overrun given buffer
+ In
+ - string to place into (Out) accompanied with padding
+ Padding
+ - number of padding chars to add
+ Flags
+ - padding style flags (PRINTF_FORMAT_FLAGS)
+*******************************************************************************/
+BOOL Internal_AddPaddingA(LPSTR *Out, INT Count, LPSTR In, INT Padding, INT Flags);
+
+/*******************************************************************************
+Function:
+ PAL_printf_arg_remover
+
+Parameters:
+ ap
+ - pointer to the va_list from which to remove arguments
+ Width
+ - the width of the current format option
+ Precision
+ - the precision of the current format option
+ Type
+ - the type of the argument for the current format option
+ Prefix
+ - the prefix for the current format option
+*******************************************************************************/
+void PAL_printf_arg_remover(va_list *ap, INT Width, INT Precision, INT Type, INT Prefix);
+
+/*++
+Function:
+ Silent_PAL_vsnprintf
+
+See MSDN doc.
+--*/
+INT Silent_PAL_vsnprintf(LPSTR Buffer, INT Count, LPCSTR Format, va_list ap);
+
+/*++
+Function:
+ Silent_PAL_vfprintf
+
+See MSDN doc.
+--*/
+int Silent_PAL_vfprintf(PAL_FILE *stream, const char *format, va_list ap);
+
+
+
+/*++
+Function:
+ PAL_iswlower
+
+See MSDN
+
+--*/
+int __cdecl PAL_iswlower( wchar_16 c );
+
+
+/*++
+Function:
+ PAL_iswalpha
+
+See MSDN
+
+--*/
+int __cdecl PAL_iswalpha( wchar_16 c );
+
+#if HAVE_COREFOUNDATION
+/*--
+Function:
+ PAL_iswblank
+
+Returns TRUE if c is a Win32 "blank" character.
+--*/
+int __cdecl PAL_iswblank(wchar_16 c);
+
+/*--
+Function:
+ PAL_iswcntrl
+
+Returns TRUE if c is a control character.
+--*/
+int __cdecl PAL_iswcntrl(wchar_16 c);
+
+/*--
+Function:
+ PAL_iswcntrl
+
+Returns TRUE if c is a control character.
+--*/
+int __cdecl PAL_iswpunct(wchar_16 c);
+#endif // HAVE_COREFOUNDATION
+
+/*++
+
+struct PAL_FILE.
+Used to mimic the behavior of windows.
+fwrite under windows can set the ferror flag,
+under BSD fwrite doesn't.
+--*/
+struct _FILE
+{
+ FILE * bsdFilePtr; /* The BSD file to be passed to the
+ functions needing it. */
+
+ INT PALferrorCode; /* The ferror code that fwrite sets,
+ incase of error */
+
+ BOOL bTextMode; /* Boolean variable to denote that the
+ fle is opened in text/binary mode*/
+#if UNGETC_NOT_RETURN_EOF
+ BOOL bWriteOnlyMode;/* Boolean variable to denote that the
+ fle is opened in write-only mode*/
+#endif //UNGETC_NOT_RETURN_EOF
+};
+
+enum CRT_ERROR_CODES
+{
+ PAL_FILE_NOERROR = 0,
+ PAL_FILE_ERROR
+};
+
+/* Global variables storing the std streams. Defined in cruntime/file.c. */
+extern PAL_FILE PAL_Stdout;
+extern PAL_FILE PAL_Stdin;
+extern PAL_FILE PAL_Stderr;
+
+/*++
+
+Functio:
+
+ CRTInitStdStreams.
+
+ Initilizes the standard streams.
+ Returns TRUE on success, FALSE otherwise.
+--*/
+BOOL CRTInitStdStreams( void );
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif /* _PAL_CRUNTIME_H_ */
diff --git a/src/pal/src/include/pal/cs.hpp b/src/pal/src/include/pal/cs.hpp
new file mode 100644
index 0000000000..76e268566b
--- /dev/null
+++ b/src/pal/src/include/pal/cs.hpp
@@ -0,0 +1,54 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// File:
+// cs.cpp
+//
+// Purpose:
+// Header file for critical sections implementation
+//
+
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef _PAL_CS_HPP
+#define _PAL_CS_HPP
+
+#include "corunix.hpp"
+#include "critsect.h"
+
+namespace CorUnix
+{
+ void CriticalSectionSubSysInitialize(void);
+
+ void InternalInitializeCriticalSectionAndSpinCount(
+ PCRITICAL_SECTION pCriticalSection,
+ DWORD dwSpinCount,
+ bool fInternal);
+
+ void InternalEnterCriticalSection(
+ CPalThread *pThread,
+ CRITICAL_SECTION *pcs
+ );
+
+ void InternalLeaveCriticalSection(
+ CPalThread *pThread,
+ CRITICAL_SECTION *pcs
+ );
+
+ bool InternalTryEnterCriticalSection(
+ CPalThread * pThread,
+ PCRITICAL_SECTION pCriticalSection);
+
+#ifdef _DEBUG
+ void PALCS_ReportStatisticalData(void);
+ void PALCS_DumpCSList();
+#endif // _DEBUG
+
+}
+
+#endif // _PAL_CS_HPP
+
diff --git a/src/pal/src/include/pal/dbgmsg.h b/src/pal/src/include/pal/dbgmsg.h
new file mode 100644
index 0000000000..7a49fc0ad6
--- /dev/null
+++ b/src/pal/src/include/pal/dbgmsg.h
@@ -0,0 +1,628 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ include/pal/dbgmsg.h
+
+Abstract:
+ Header file for Debug Message utilities. Output macros, type definitions,
+ extern variables. See overview section below for usage details.
+
+--*/
+
+/*
+Overview of Debug Message utilities
+
+Use debug channels to selectively output information to the console.
+
+Available macros :
+
+ - SET_DEFAULT_DEBUG_CHANNEL
+
+ This defines the channel to use with the macros TRACE, ERROR, etc
+ Use this macro once at the beginning of your source file.
+ (impl. details : this declares a constant static variable defdbgchan and
+ sets it to the apropriate channel)
+
+ usage : SET_DEFAULT_DEBUG_CHANNEL(somechannel);
+
+ - TRACE, ENTRY, WARN, ERROR, DBGOUT
+
+ Use this to output debug messages to the default debug channel (set with
+ SET_DEFAULT_DEBUG_CHANNEL). Messages will only be output if the channel is
+ active for the specified level.
+
+ usage : TRACE("printf format string", params...);
+
+ - TRACE_, ENTRY_, WARN_, ERROR_, DBGOUT_
+
+ Use this to autput debug messages to a channel other than the default.
+
+ usage : TRACE_(someotherchannel)("printf format string",params...);
+ ^ ^^ ^
+ don't forget the double set of parentheses!
+
+Available channels :
+ PAL : PAL-specific functionalities (PAL_Initialize, etc.)
+ LOADER : Loading API (LoadLibrary, etc); loader application
+ HANDLE : Handle manager (CloseHandle, etc.)
+ SHMEM : Shared Memory functions (for IPC)
+ PROCESS : Process related APIs
+ THREAD : Threading mechanism
+ EXCEPT : Structured Exception Handling functions
+ CRT : PAL implementation of the C Runtime Library functions
+ UNICODE : Unicode support API
+ ARCH : platform-dependent stuff
+ SYNC : Management of synchronization objects
+ FILE : File I/O API
+ VIRTUAL : Virtual memory and File mapping
+ MEM : Memory management (except Virtual* stuff)
+ SOCKET : WINSOCK implementation
+ DEBUG : Debugging API (ReadProcessMemory, etc.)
+ LOCALE : Locale support API
+ MISC : what doesn't fit anywhere else.
+ MUTEX : Mutex management functions
+ CRITSEC : Critical section API
+ POLL : ?
+ CRYPT : Cryptographic functions
+ SHFOLDER: Shared (well-known) folder functions
+ SXS : Side-by-side PALs (if supported)
+
+ Note : Most channels correspond to subdirectories $(PALROOT)
+ Note 2 : DON'T write TRACE("PAL") or TRACE(DCI_PAL), write TRACE(PAL)
+
+Available debug levels :
+ ENTRY : use this at the beginning of a function to print parameters.
+ TRACE : use this to output informational messages.
+ WARN : use this to report non-critical problems.
+ ERROR : use this to report critical problems.
+
+ DBGOUT: same as TRACE, but does not output line headers (thread ID, etc)
+
+Format specifiers :
+ These trace functions currently use the native fprintf() to output data.
+ All standard printf format specifiers should therefore work, while Microsoft
+ extensions will not.
+ There is one special case to consider : wide strings and wide characters.
+ Microsoft's extensions to printf include the specifiers %S and %C for
+ printing strings and characters of wchar_t. In the C99 standard,
+ the specifiers %ls and %ls serve the same purpose. However, Windows defines
+ wchar_t as a 16bit int, which is NOT guaranteed to match implementations
+ on other platforms. glibc on a x86 defines wchar_t as a 32bit int.
+ For this reason, %S and %C should be used in TRACE functions to output
+ Windows wide strings (of type wchar_t or WCHAR). To output wide-strings
+ in a platforms native format (litterals L"string" or variables of type
+ wchar_native), the specifiers %ls and %lc should be used instead.
+
+Using Debug channels at Run Time
+ To tell the PAL which debug channels should be open and which should be
+ closed, set the environment variable PAL_DBG_CHANNELS according to the
+ following syntax :
+ [+|-]<channel>.<level>[: ...]
+ + opens a channel, - closes it;
+ <channel> must be one of PAL, FILE, (etc), or the wildcard "all"
+ <level> must be TRACE, ENTRY, WARN, ERROR or "all"
+
+ Examples (for bash):
+
+ export PAL_DBG_CHANNELS="+PAL.TRACE:-FILE.ERROR"
+ export PAL_DBG_CHANNELS="+all.ENTRY"
+ export PAL_DBG_CHANNELS="-all.all"
+
+ To explicitly redirect the output of debug messages to a file (instead of
+ relying on the shell's > and |), set the environment variable
+ PAL_API_TRACING to the name of the file to write to. It can also be set to
+ "stdout" or "stderr". If PAL_API_TRACING is not set, output will go to
+ stderr.
+
+ ASSERT() messages cannot be controlled with PAL_DBG_CHANNELS; they can be
+ globally disabled (in debug builds) by setting the environment variable
+ PAL_DISABLE_ASSERTS to 1. In release builds, they will always be disabled
+
+ The environment variable "PAL_API_LEVELS" determines how many levels of
+ nesting will be allowed in ENTRY calls; if not set, the default is 1; a
+ value of 0 will allow infinite nesting, but will not indent the output
+
+ It is possible to disable/enable all channels during the execution of a
+ process; this involves using a debugger to modify a variable within the
+ address space of the running process. the variable is named
+ 'dbg_master_switch'; if set to zero, all debug chanels will be closed; if
+ set to nonzero, channels will be open or closed based on PAL_DBG_CHANNELS
+
+ Notes :
+ If _ENABLE_DEBUG_MESSAGES_ was not defined at build-time, no debug messages
+ will be generated.
+ If _ENABLE_DEBUG_MESSAGES_ was defined, all debug levels will be enabled,
+ but all channels will be closed by default
+
+ Another configure option is --enable-appendtraces
+ Normally, if the file specified by PAL_API_TRACING exists, its content will
+ be overwritten when a PAL process starts using it. If --enable-appendtraces
+ is used, debug output will be appended at the end of the file instead.
+
+
+
+ */
+
+#ifndef _PAL_DBGMSG_H_
+#define _PAL_DBGMSG_H_
+
+#include "pal/palinternal.h"
+#include "config.h"
+#include "pal/perftrace.h"
+#include "pal/debug.h"
+#include "pal/thread.hpp"
+#include "pal/tls.hpp"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif // __cplusplus
+
+/* Channel identifiers */
+typedef enum
+{
+ DCI_PAL,
+ DCI_LOADER,
+ DCI_HANDLE,
+ DCI_SHMEM,
+ DCI_PROCESS,
+ DCI_THREAD,
+ DCI_EXCEPT,
+ DCI_CRT,
+ DCI_UNICODE,
+ DCI_ARCH,
+ DCI_SYNC,
+ DCI_FILE,
+ DCI_VIRTUAL,
+ DCI_MEM,
+ DCI_SOCKET,
+ DCI_DEBUG,
+ DCI_LOCALE,
+ DCI_MISC,
+ DCI_MUTEX,
+ DCI_CRITSEC,
+ DCI_POLL,
+ DCI_CRYPT,
+ DCI_SHFOLDER,
+#ifdef FEATURE_PAL_SXS
+ DCI_SXS,
+#endif // FEATURE_PAL_SXS
+
+ DCI_LAST
+} DBG_CHANNEL_ID;
+
+/* Level identifiers */
+typedef enum
+{
+ DLI_ENTRY,
+ DLI_TRACE,
+ DLI_WARN,
+ DLI_ERROR,
+ DLI_ASSERT,
+ DLI_EXIT,
+
+ DLI_LAST
+} DBG_LEVEL_ID;
+
+
+/* extern variables */
+
+// Change W16_NULLSTRING to external variable to avoid multiple warnings showing up in prefast
+extern LPCWSTR W16_NULLSTRING;
+
+extern DWORD dbg_channel_flags[DCI_LAST];
+extern BOOL g_Dbg_asserts_enabled;
+
+/* we must use stdio functions directly rather that rely on PAL functions for
+ output, because those functions do tracing and we need to avoid recursion */
+extern FILE *output_file;
+
+/* master switch for debug channel enablement, to be modified by debugger */
+extern Volatile<BOOL> dbg_master_switch ;
+
+
+/* conditionnal compilation for other debug messages */
+#if !_ENABLE_DEBUG_MESSAGES_
+
+/* compile out these trace levels; see the definition of NOTRACE */
+#define TRACE NOTRACE
+#define TRACE_(x) NOTRACE
+#define WARN NOTRACE
+#define WARN_(x) NOTRACE
+#define ENTRY_EXTERNAL NOTRACE
+#define ENTRY NOTRACE
+#define ENTRY_(x) NOTRACE
+#define LOGEXIT NOTRACE
+#define LOGEXIT_(x) NOTRACE
+#define DBGOUT NOTRACE
+#define DBGOUT_(x) NOTRACE
+#define ERROR NOTRACE
+#define ERROR_(x) NOTRACE
+#define DBG_PRINTF(level, channel, bHeader) NOTRACE
+
+#define CHECK_STACK_ALIGN
+
+#define SET_DEFAULT_DEBUG_CHANNEL(x)
+#define DBG_ENABLED(level, channel)
+
+#else /* _ENABLE_DEBUG_MESSAGES_ */
+
+/* output macros */
+
+#define SET_DEFAULT_DEBUG_CHANNEL(x) \
+ static const DBG_CHANNEL_ID defdbgchan = DCI_##x
+
+/* Is debug output enabled for the given level and channel? */
+#define DBG_ENABLED(level, channel) (output_file && \
+ dbg_master_switch && \
+ (dbg_channel_flags[channel] & (1 << (level))))
+#define TRACE \
+ DBG_PRINTF(DLI_TRACE,defdbgchan,TRUE)
+
+#define TRACE_(x) \
+ DBG_PRINTF(DLI_TRACE,DCI_##x,TRUE)
+
+#define WARN \
+ DBG_PRINTF(DLI_WARN,defdbgchan,TRUE)
+
+#define WARN_(x) \
+ DBG_PRINTF(DLI_WARN,DCI_##x,TRUE)
+
+#if _DEBUG && defined(__APPLE__)
+bool DBG_ShouldCheckStackAlignment();
+#define CHECK_STACK_ALIGN if (DBG_ShouldCheckStackAlignment()) DBG_CheckStackAlignment()
+#else
+#define CHECK_STACK_ALIGN
+#endif
+
+#define ENTRY_EXTERNAL \
+ CHECK_STACK_ALIGN; \
+ DBG_PRINTF(DLI_ENTRY, defdbgchan,TRUE)
+
+#define ENTRY \
+ CHECK_STACK_ALIGN; \
+ DBG_PRINTF(DLI_ENTRY, defdbgchan,TRUE)
+
+#define ENTRY_(x) \
+ CHECK_STACK_ALIGN; \
+ DBG_PRINTF(DLI_ENTRY, DCI_##x,TRUE)
+
+#define LOGEXIT \
+ DBG_PRINTF(DLI_EXIT, defdbgchan,TRUE)
+
+#define LOGEXIT_(x) \
+ DBG_PRINTF(DLI_EXIT, DCI_##x,TRUE)
+
+#define DBGOUT \
+ DBG_PRINTF(DLI_TRACE,defdbgchan,FALSE)
+
+#define DBGOUT_(x) \
+ DBG_PRINTF(DLI_TRACE,DCI_##x,FALSE)
+
+/*Added this code here to stop error messages
+ *from appearing in retail build*/
+#define ERROR \
+ DBG_PRINTF(DLI_ERROR,defdbgchan,TRUE)
+
+#define ERROR_(x) \
+ DBG_PRINTF(DLI_ERROR,DCI_##x,TRUE)
+
+#define DBG_PRINTF(level, channel, bHeader) \
+{\
+ if( DBG_ENABLED(level, channel) ) { \
+ DBG_CHANNEL_ID __chanid=channel;\
+ DBG_LEVEL_ID __levid=level;\
+ BOOL __bHeader = bHeader;\
+ DBG_PRINTF2
+
+#ifdef __GNUC__
+#define DBG_PRINTF2(args...)\
+ DBG_printf_gcc(__chanid,__levid,__bHeader,__FUNCTION__,__FILE__,\
+ __LINE__,args);\
+ }\
+}
+#else /* __GNUC__ */
+#define DBG_PRINTF2(...)\
+ DBG_printf_c99(__chanid,__levid,__bHeader,__FILE__,__LINE__,__VA_ARGS__);\
+ }\
+}
+#endif /* __GNUC__ */
+
+#endif /* _ENABLE_DEBUG_MESSAGES_ */
+
+/* Use GNU C-specific features if available : __FUNCTION__ pseudo-macro,
+ variable-argument macros */
+#ifdef __GNUC__
+
+/* define NOTRACE as nothing; this will absorb the variable-argument list used
+ in tracing macros */
+#define NOTRACE(args...)
+
+#if defined(__cplusplus) && defined(FEATURE_PAL_SXS)
+#define __ASSERT_ENTER() \
+ /* DBG_printf_gcc() and DebugBreak() need a PAL thread */ \
+ PAL_EnterHolder __holder(PALIsThreadDataInitialized() && \
+ (CorUnix::InternalGetCurrentThread() == NULL || \
+ !CorUnix::InternalGetCurrentThread()->IsInPal()));
+#else /* __cplusplus && FEATURE_PAL_SXS */
+#define __ASSERT_ENTER()
+#endif /* __cplusplus && FEATURE_PAL_SXS */
+
+#if !defined(_DEBUG)
+
+#define ASSERT(args...)
+#define _ASSERT(expr)
+#define _ASSERTE(expr)
+#define _ASSERT_MSG(args...)
+
+#else /* defined(_DEBUG) */
+
+#define ASSERT(args...) \
+{ \
+ __ASSERT_ENTER(); \
+ if (output_file && dbg_master_switch) \
+ { \
+ DBG_printf_gcc(defdbgchan,DLI_ASSERT,TRUE,__FUNCTION__,__FILE__,__LINE__,args); \
+ } \
+ if (g_Dbg_asserts_enabled) \
+ { \
+ DebugBreak(); \
+ } \
+}
+
+#define _ASSERT(expr) do { if (!(expr)) { ASSERT(""); } } while(0)
+#define _ASSERTE(expr) do { if (!(expr)) { ASSERT("Expression: " #expr "\n"); } } while(0)
+#define _ASSERT_MSG(expr, args...) \
+ do { \
+ if (!(expr)) \
+ { \
+ ASSERT("Expression: " #expr ", Description: " args); \
+ } \
+ } while(0)
+
+#endif /* defined(_DEBUG) */
+
+#else /* __GNUC__ */
+/* Not GNU C : C99 [the latest version of the ISO C Standard] specifies
+ a different syntax for variable-argument macros, so try using that*/
+#if defined __STDC_VERSION__ && __STDC_VERSION__ >=199901L
+
+/* define NOTRACE as nothing; this will absorb the variable-argument list used
+ in tracing macros */
+#define NOTRACE(...)
+
+#if !defined(_DEBUG)
+
+#define ASSERT(...)
+#define _ASSERT(expr)
+#define _ASSERTE(expr)
+#define _ASSERT_MSG(...)
+
+#else /* defined(_DEBUG) */
+
+#define ASSERT(...) \
+{ \
+ __ASSERT_ENTER(); \
+ if (output_file && dbg_master_switch) \
+ { \
+ DBG_printf_c99(defdbgchan,DLI_ASSERT,TRUE,__FILE__,__LINE__,__VA_ARGS__); \
+ } \
+ if(g_Dbg_asserts_enabled) \
+ { \
+ PAL_Leave(); \
+ DebugBreak(); \
+ } \
+}
+
+#define _ASSERT(expr) do { if (!(expr)) { ASSERT(""); } } while(0)
+#define _ASSERTE(expr) do { if (!(expr)) { ASSERT("Expression: " #expr "\n"); } } while(0)
+#define _ASSERT_MSG(expr, ...) \
+ do { \
+ if (!(expr)) \
+ { \
+ ASSERT("Expression: " #expr ", Description: " __VA_ARGS__); \
+ } \
+ } while(0)
+
+#endif /* !_DEBUG */
+
+#else /* __STDC_VERSION__ */
+/* Not GNU C, not C99 :
+ possible work around for the lack of variable-argument macros:
+ by using 2 function calls; must wrap the whole thing in a critical
+ section to avoid interleaved output from multiple threads */
+
+#error The compiler is missing support for variable-argument macros.
+
+#endif /* __STDC_VERSION__*/
+#endif /* __GNUC__ */
+
+/* Function declarations */
+
+/*++
+Function :
+ DBG_init_channels
+
+ Initialize debug channel information based on environment settings
+ Call this only once at startup.
+
+ (no parameters, no return value)
+--*/
+BOOL DBG_init_channels(void);
+
+/*++
+Function :
+ DBG_close_channels
+
+ Close the output file for debug messages.
+
+ (no parameters, no return value)
+--*/
+void DBG_close_channels(void);
+
+/*++
+Function :
+ DBG_preprintf
+
+ Internal function for debug channels; don't use.
+ This function outputs the header information for debug messages (channel,
+ level, etc).
+
+Parameters :
+ DBG_CHANNEL_ID channel : debug channel to use
+ DBG_LEVEL_ID level : debug message level
+ BOOL bHeader : whether or not to output message header (thread id, etc)
+ LPSTR file : current file
+ INT line : line number
+
+Return Value :
+ TRUE if there's an output file, FALSE otherwise. this is so that
+ DBG_printf_plain doesn't get called unnecessarily.
+
+Notes :
+ This function is only used with compilers that don't support
+ variable-argument macros. It enters a critical section, which is left in
+ DBG_printf_plain.
+--*/
+BOOL DBG_preprintf(DBG_CHANNEL_ID channel, DBG_LEVEL_ID level, BOOL bHeader,
+ LPSTR file, INT line);
+
+/*++
+Function :
+ DBG_printf_gcc
+
+ Internal function for debug channels; don't use.
+ This function outputs a complete debug message, including the function name.
+
+Parameters :
+ DBG_CHANNEL_ID channel : debug channel to use
+ DBG_LEVEL_ID level : debug message level
+ BOOL bHeader : whether or not to output message header (thread id, etc)
+ LPSTR function : current function
+ LPSTR file : current file
+ INT line : line number
+ LPSTR format, ... : standard printf parameter list.
+
+Return Value :
+ always 1.
+
+Notes :
+ This version is for gnu compilers that support variable-argument macros
+ and the __FUNCTION__ pseudo-macro.
+
+--*/
+#if __GNUC__ && CHECK_TRACE_SPECIFIERS
+/* if requested, use an __attribute__ feature to ask gcc to check that format
+ specifiers match their parameters */
+int DBG_printf_gcc(DBG_CHANNEL_ID channel, DBG_LEVEL_ID level, BOOL bHeader,
+ LPCSTR function, LPCSTR file, INT line, LPCSTR format, ...)
+ __attribute__ ((format (printf,7, 8)));
+#else
+int DBG_printf_gcc(DBG_CHANNEL_ID channel, DBG_LEVEL_ID level, BOOL bHeader,
+ LPCSTR function, LPCSTR file, INT line, LPCSTR format, ...);
+#endif
+
+/*++
+Function :
+ DBG_printf_c99
+
+ Internal function for debug channels; don't use.
+ This function outputs a complete debug message, without function name.
+
+Parameters :
+ DBG_CHANNEL_ID channel : debug channel to use
+ DBG_LEVEL_ID level : debug message level
+ BOOL bHeader : whether or not to output message header (thread id, etc)
+ LPSTR file : current file
+ INT line : line number
+ LPSTR format, ... : standard printf parameter list.
+
+Return Value :
+ always 1.
+
+Notes :
+ This version is for compilers that support the C99 flavor of
+ variable-argument macros but not the gnu flavor, and do not support the
+ __FUNCTION__ pseudo-macro.
+
+--*/
+int DBG_printf_c99(DBG_CHANNEL_ID channel, DBG_LEVEL_ID level, BOOL bHeader,
+ LPSTR file, INT line, LPSTR format, ...);
+
+/*++
+Function :
+ DBG_printf_plain
+
+ Internal function for debug channels; don't use.
+ This function output the user-specified part of a debug-message.
+
+Parameters :
+ LPSTR format, ... : standard printf parameter list.
+
+Return value :
+ always 1.
+
+Notes :
+ This function is only used with compilers that don't support
+ variable-argument macros. It will leave the critical section entered in
+ DBG_preprintf.
+
+--*/
+int DBG_printf_plain(LPSTR format, ...);
+
+/*++
+Function :
+ DBG_change_entrylevel
+
+ retrieve current ENTRY nesting level and [optionnally] modify it
+
+Parameters :
+ int new_level : value to which the nesting level must be set, or -1
+
+Return value :
+ nesting level at the time the function was called
+
+Notes:
+if new_level is -1, the nesting level will not be modified
+--*/
+int DBG_change_entrylevel(int new_level);
+
+#ifdef __APPLE__
+/*++
+Function :
+ PAL_DisplayDialog
+
+ Display a simple modal dialog with an alert icon and a single OK button. Caller supplies the title of the
+ dialog and the main text. The dialog is displayed only if the COMPlus_EnableAssertDialog environment
+ variable is set to the value "1".
+
+--*/
+void PAL_DisplayDialog(const char *szTitle, const char *szText);
+
+/*++
+Function :
+ PAL_DisplayDialogFormatted
+
+ As above but takes a printf-style format string and insertion values to form the main text.
+
+--*/
+void PAL_DisplayDialogFormatted(const char *szTitle, const char *szTextFormat, ...);
+#else // __APPLE__
+#define PAL_DisplayDialog(_szTitle, _szText)
+#define PAL_DisplayDialogFormatted(_szTitle, _szTextFormat, args...)
+#endif // __APPLE__
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif /* _PAL_DBGMSG_H_ */
+
+
diff --git a/src/pal/src/include/pal/debug.h b/src/pal/src/include/pal/debug.h
new file mode 100644
index 0000000000..78cdeff0c3
--- /dev/null
+++ b/src/pal/src/include/pal/debug.h
@@ -0,0 +1,86 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ include/pal/debug.h
+
+Abstract:
+
+ Debug API utility functions
+
+
+
+--*/
+
+#ifndef _PAL_DEBUG_H_
+#define _PAL_DEBUG_H_
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif // __cplusplus
+
+/*++
+Function :
+ DBG_DebugBreak
+
+ Processor-dependent implementation of DebugBreak
+
+(no parameters, no return value)
+--*/
+extern "C" VOID
+DBG_DebugBreak();
+
+/*++
+Function:
+ IsInDebugBreak(addr)
+
+ Returns true if the address is in DBG_DebugBreak.
+
+--*/
+BOOL
+IsInDebugBreak(void *addr);
+
+/*++
+Function :
+ DBG_FlushInstructionCache
+
+ Processor-dependent implementation of FlushInstructionCache
+
+Parameters :
+ LPCVOID lpBaseAddress: start of region to flush
+ SIZE_T dwSize : length of region to flush
+
+Return value :
+ TRUE on success, FALSE on failure
+
+--*/
+BOOL
+DBG_FlushInstructionCache(
+ IN LPCVOID lpBaseAddress,
+ IN SIZE_T dwSize);
+
+#if defined(__APPLE__)
+/*++
+Function:
+ DBG_CheckStackAlignment
+
+ The Apple ABI requires 16-byte alignment on the stack pointer.
+ This function traps/interrupts otherwise.
+--*/
+VOID
+DBG_CheckStackAlignment();
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif //PAL_DEBUG_H_
diff --git a/src/pal/src/include/pal/dtraceprotocol.h b/src/pal/src/include/pal/dtraceprotocol.h
new file mode 100644
index 0000000000..d1a17a71ae
--- /dev/null
+++ b/src/pal/src/include/pal/dtraceprotocol.h
@@ -0,0 +1,39 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+// File: rotor/pal/corunix/include/pal/dtrace_protocal.h
+//
+
+//
+// Header file for the protocals between CLR and Dtrace server
+//
+// ======================================================================================
+
+#ifndef DTRACE_PROTOCOL_H
+#define DTRACE_PROTOCOL_H
+
+// Start DTrace Consumer by Unix Domain App
+#define kServerSocketPath "/Library/Application Support/com.microsoft.clr.CFDtraceServer/Socket"
+#define kPacketTypeStartDtrace 1
+#define kPacketTypeReply 3
+#define kMaxMessageSize 318
+#define kPacketMaximumSize 102400
+
+struct PacketHeader {
+ int fType; // for request from client to server, it should be kPacketTypeStartDtrace
+ // for reply from server to client, it should be kPacketTypeReply
+ unsigned int fSize; // includes size of header itself
+};
+
+struct PacketStartDTrace { // reply: PacketReply
+ PacketHeader fHeader; // fType is kPacketTypeStartDtrace
+ char fMessage[kMaxMessageSize]; // message to print
+};
+
+struct PacketReply { // reply: n/a
+ PacketHeader fHeader; // fType is kPacketTypeReply
+ int fErr; // result of operation, errno-style
+};
+
+#endif // DTRACE_PROTOCOL
diff --git a/src/pal/src/include/pal/environ.h b/src/pal/src/include/pal/environ.h
new file mode 100644
index 0000000000..1c0bce21ca
--- /dev/null
+++ b/src/pal/src/include/pal/environ.h
@@ -0,0 +1,78 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ include/pal/environ.h
+
+Abstract:
+ Header file for functions manipulating environment variables
+
+
+--*/
+
+#ifndef __ENVIRON_H_
+#define __ENVIRON_H_
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif // __cplusplus
+
+/*++
+Variables :
+
+ palEnvironment: a global variable equivalent to environ on systems on
+ which that exists, and a pointer to an array of environment
+ strings on systems without environ.
+ gcsEnvironment: critical section to synchronize access to palEnvironment
+--*/
+extern char **palEnvironment;
+extern CRITICAL_SECTION gcsEnvironment;
+
+/*++
+
+Function:
+ EnvironInitialize
+
+Initialization function for the PAL environment code.
+--*/
+BOOL EnvironInitialize();
+
+/*++
+Function:
+ EnvironGetenv
+
+Get the value of environment variable with the given name.
+--*/
+char *EnvironGetenv(const char *name, BOOL copyValue = TRUE);
+
+/*++
+Function:
+ EnvironPutenv
+
+Add the environment variable string provided to the PAL version
+of the environment.
+--*/
+BOOL EnvironPutenv(const char *string, BOOL deleteIfEmpty);
+
+/*++
+Function:
+ EnvironUnsetenv
+
+Remove the environment variable with the given name from the PAL
+version of the environment if it exists.
+--*/
+void EnvironUnsetenv(const char *name);
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif /* __ENVIRON_H_ */
+
diff --git a/src/pal/src/include/pal/event.hpp b/src/pal/src/include/pal/event.hpp
new file mode 100644
index 0000000000..98eeaee5db
--- /dev/null
+++ b/src/pal/src/include/pal/event.hpp
@@ -0,0 +1,69 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ event.hpp
+
+Abstract:
+
+ Event object structure definition.
+
+
+
+--*/
+
+#ifndef _PAL_EVENT_H_
+#define _PAL_EVENT_H_
+
+#include "corunix.hpp"
+
+namespace CorUnix
+{
+ extern CObjectType otManualResetEvent;
+ extern CObjectType otAutoResetEvent;
+
+ PAL_ERROR
+ InternalCreateEvent(
+ CPalThread *pThread,
+ LPSECURITY_ATTRIBUTES lpEventAttributes,
+ BOOL bManualReset,
+ BOOL bInitialState,
+ LPCWSTR lpName,
+ HANDLE *phEvent
+ );
+
+ PAL_ERROR
+ InternalSetEvent(
+ CPalThread *pThread,
+ HANDLE hEvent,
+ BOOL fSetEvent
+ );
+
+ PAL_ERROR
+ InternalOpenEvent(
+ CPalThread *pThread,
+ DWORD dwDesiredAccess,
+ BOOL bInheritHandle,
+ LPCWSTR lpName,
+ HANDLE *phEvent
+ );
+
+}
+
+#endif //PAL_EVENT_H_
+
+
+
+
+
+
+
+
+
+
diff --git a/src/pal/src/include/pal/fakepoll.h b/src/pal/src/include/pal/fakepoll.h
new file mode 100644
index 0000000000..eec40d6612
--- /dev/null
+++ b/src/pal/src/include/pal/fakepoll.h
@@ -0,0 +1,68 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+// fakepoll.h
+// poll using select
+// Warning: a call to this poll() takes about 4K of stack space.
+
+// Greg Parker gparker@cs.stanford.edu December 2000
+// This code is in the public domain and may be copied or modified without
+// permission.
+
+// Located at <http://www.sealiesoftware.com/fakepoll.h>.
+
+
+
+
+#ifndef _FAKE_POLL_H
+#define _FAKE_POLL_H
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif // __cplusplus
+
+#ifdef FD_SETSIZE
+#undef FD_SETSIZE
+#endif
+#define FD_SETSIZE OPEN_MAX
+
+typedef struct pollfd {
+ int fd; /* file desc to poll */
+ short events; /* events of interest on fd */
+ short revents; /* events that occurred on fd */
+} pollfd_t;
+
+// Typically defined in sys/stropts.h and used for an infinite timeout.
+#ifndef _INFTIM
+#define _INFTIM -1
+#endif
+#ifndef INFTIM
+#define INFTIM _INFTIM
+#endif
+
+// poll flags
+#define POLLIN 0x0001
+#define POLLOUT 0x0004
+#define POLLERR 0x0008
+
+// synonyms
+#define POLLNORM POLLIN
+#define POLLPRI POLLIN
+#define POLLRDNORM POLLIN
+#define POLLRDBAND POLLIN
+#define POLLWRNORM POLLOUT
+#define POLLWRBAND POLLOUT
+
+// ignored
+#define POLLHUP 0x0010
+#define POLLNVAL 0x0020
+
+int poll(struct pollfd *pollSet, int pollCount, int pollTimeout);
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif /* _FAKE_POLL_H */
diff --git a/src/pal/src/include/pal/file.h b/src/pal/src/include/pal/file.h
new file mode 100644
index 0000000000..93c8ad9784
--- /dev/null
+++ b/src/pal/src/include/pal/file.h
@@ -0,0 +1,304 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ include/pal/file.h
+
+Abstract:
+ Header file for file utility functions.
+
+Revision History:
+
+
+
+--*/
+
+#ifndef _PAL_FILE_H_
+#define _PAL_FILE_H_
+
+#include "pal/shmemory.h"
+#include "pal/stackstring.hpp"
+#include <sys/types.h>
+#include <dirent.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif // __cplusplus
+
+typedef struct _find_handle
+{
+ struct _find_handle *self_addr; /* for pointer verification */
+
+ char dir[_MAX_DIR];
+ char fname[MAX_PATH_FNAME]; /* includes extension */
+ glob_t gGlob;
+ char **next;
+} find_obj;
+
+/*++
+FILECanonicalizePath
+ Removes all instances of '/./', '/../' and '//' from an absolute path.
+
+Parameters:
+ LPSTR lpUnixPath : absolute path to modify, in Unix format
+
+(no return value)
+
+Notes :
+-behavior is undefined if path is not absolute
+-the order of steps *is* important: /one/./../two would give /one/two
+ instead of /two if step 3 was done before step 2
+-reason for this function is that GetFullPathName can't use realpath(), since
+ realpath() requires the given path to be valid and GetFullPathName does not.
+--*/
+void FILECanonicalizePath(LPSTR lpUnixPath);
+
+/*++
+Function:
+ FileDosToUnixPathA
+
+Abstract:
+ Change a DOS path to a Unix path. Replace '\' by '/'.
+
+Parameter:
+ IN/OUT lpPath: path to be modified
+--*/
+void
+FILEDosToUnixPathA(LPSTR lpPath);
+
+/*++
+Function:
+ FileDosToUnixPathW
+
+Abstract:
+ Change a DOS path to a Unix path. Replace '\' by '/'.
+
+Parameter:
+ IN/OUT lpPath: path to be modified
+ --*/
+void
+FILEDosToUnixPathW(LPWSTR lpPath);
+
+/*++
+Function:
+ FileUnixToDosPathA
+
+Abstract:
+ Change a Unix path to a DOS path. Replace '/' by '\'.
+
+Parameter:
+ IN/OUT lpPath: path to be modified
+--*/
+void
+FILEUnixToDosPathA(LPSTR lpPath);
+
+/*++
+Function:
+ FILEGetDirectoryFromFullPathA
+
+Parse the given path. If it contains a directory part and a file part,
+put the directory part into the supplied buffer, and return the number of
+characters written to the buffer. If the buffer is not large enough,
+return the required size of the buffer including the NULL character. If
+there is no directory part in the path, return 0.
+--*/
+DWORD FILEGetDirectoryFromFullPathA( LPCSTR lpFullPath,
+ DWORD nBufferLength,
+ LPSTR lpBuffer );
+
+/*++
+Function:
+ FILEGetFileNameFromFullPath
+
+Given a full path, return a pointer to the first char of the filename part.
+--*/
+LPCSTR FILEGetFileNameFromFullPathA( LPCSTR lpFullPath );
+
+/*++
+Function:
+ FILEGetLastErrorFromErrno
+
+Convert errno into the appropriate win32 error and return it.
+--*/
+DWORD FILEGetLastErrorFromErrno( void );
+
+/*++
+Function:
+ DIRGetLastErrorFromErrno
+
+Convert errno into the appropriate win32 error and return it.
+--*/
+DWORD DIRGetLastErrorFromErrno( void );
+
+/*++
+FILEInitStdHandles
+
+Create handle objects for stdin, stdout and stderr
+
+(no parameters)
+
+Return value:
+ TRUE on success, FALSE on failure
+--*/
+BOOL FILEInitStdHandles(void);
+
+/*++
+FILECleanupStdHandles
+
+Close promary handles for stdin, stdout and stderr
+
+(no parameters, no return value)
+--*/
+void FILECleanupStdHandles(void);
+
+/*++
+
+Function :
+ FILEGetProperNotFoundError
+
+Returns the proper error code, based on the
+Windows behavoir.
+
+ IN LPSTR lpPath - The path to check.
+ LPDWORD lpErrorCode - The error to set.
+*/
+void FILEGetProperNotFoundError( LPCSTR lpPath, LPDWORD lpErrorCode );
+
+/*++
+PAL__getcwd
+
+Calls getcwd
+
+Input parameters:
+
+char *szBuf = a copy of the absolute pathname of the current working directory
+is copied into szBuf.
+size_t nSize = size, in bytes, of the array referenced by szBuf.
+
+Return value:
+ A pointer to the pathname if successful, otherwise NULL is returned.
+--*/
+char * __cdecl PAL__getcwd(char *szBuf, size_t nSize);
+
+/*++
+PAL_fflush
+
+Calls fflush
+
+Input parameters:
+
+PAL_FILE *stream = stream to be flushed.
+
+Return value:
+ 0 is returned on success, otherwise EOF is returned.
+--*/
+int _cdecl PAL_fflush( PAL_FILE *stream );
+
+/*++
+PAL_mkstemp
+
+Calls InternalMkstemp to call mkstemp
+
+Input parameters:
+
+char *szNameTemplate = the pattern to follow when creating a new file.
+
+Return value:
+ file descriptor of opened file on success, -1 on failure.
+--*/
+int __cdecl PAL_mkstemp(char *szNameTemplate);
+
+/*++
+PAL_rename
+
+Calls rename
+
+Input parameters:
+
+szOldName = pointer to the pathname of the file to be renamed
+szNewName = pointer to the new pathname of the file
+
+Return value:
+ Returns 0 on success and -1 on failure
+--*/
+int __cdecl PAL_rename(const char *szOldName, const char *szNewName);
+
+/*++
+PAL_fgets
+
+Wrapper function for InternalFgets.
+
+Input parameters:
+
+sz = stores characters read from the given file stream
+nSize = number of characters to be read
+pf = stream to read characters from
+
+Return value:
+ Returns a pointer to the string storing the characters on success
+ and NULL on failure.
+--*/
+char * __cdecl PAL_fgets(char *sz, int nSize, PAL_FILE *pf);
+
+/*++
+PAL_fwrite
+
+Wrapper function for InternalFwrite
+
+Input parameters:
+
+pvBuffer = array of objects to write to the given file stream
+nSize = size of a object in bytes
+nCount = number of objects to write
+pf = stream to write characters to
+
+Return value:
+ Returns the number of objects written.
+--*/
+size_t __cdecl PAL_fwrite(const void *pvBuffer, size_t nSize, size_t nCount, PAL_FILE *pf);
+
+/*++
+PAL__open
+
+Wrapper function for InternalOpen.
+
+Input parameters:
+
+szPath = pointer to a pathname of a file to be opened
+nFlags = arguments that control how the file should be accessed
+mode = file permission settings that are used only when a file is created
+
+Return value:
+ File descriptor on success, -1 on failure
+--*/
+int __cdecl PAL__open(const char *szPath, int nFlags, ...);
+
+/*++
+PAL_fseek
+
+Wrapper function for fseek
+
+Input parameters:
+
+pf = a given file stream
+lOffset = distance from position to set file-position indicator
+nWhence = method used to determine the file_position indicator location relative to lOffset
+
+Return value:
+ 0 on success, -1 on failure.
+--*/
+int _cdecl PAL_fseek(PAL_FILE *pf, LONG lOffset, int nWhence);
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif /* _PAL_FILE_H_ */
+
diff --git a/src/pal/src/include/pal/file.hpp b/src/pal/src/include/pal/file.hpp
new file mode 100644
index 0000000000..5acccb0a24
--- /dev/null
+++ b/src/pal/src/include/pal/file.hpp
@@ -0,0 +1,365 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ include/pal/file.hpp
+
+Abstract:
+ Header file for file utility functions.
+
+Revision History:
+
+
+
+--*/
+
+#ifndef _PAL_FILE_HPP_
+#define _PAL_FILE_HPP_
+
+#include "corunix.hpp"
+#include "pal/stackstring.hpp"
+#include <sys/types.h>
+#include <sys/param.h>
+#include <dirent.h>
+
+
+namespace CorUnix
+{
+ extern CObjectType otFile;
+ extern CAllowedObjectTypes aotFile;
+
+ class CFileProcessLocalData
+ {
+ public:
+ IFileLockController *pLockController;
+
+ int unix_fd;
+ DWORD dwDesiredAccess; /* Unix assumes files are always opened for reading.
+ In Windows we can open a file for writing only */
+ int open_flags; /* stores Unix file creation flags */
+ BOOL open_flags_deviceaccessonly;
+ char unix_filename[MAXPATHLEN];
+ BOOL inheritable;
+ };
+
+ PAL_ERROR
+ InternalCreateFile(
+ CPalThread *pThread,
+ LPCSTR lpFileName,
+ DWORD dwDesiredAccess,
+ DWORD dwShareMode,
+ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
+ DWORD dwCreationDisposition,
+ DWORD dwFlagsAndAttributes,
+ HANDLE hTemplateFile,
+ HANDLE *pFileHandle
+ );
+
+ PAL_ERROR
+ InternalWriteFile(
+ CPalThread *pThread,
+ HANDLE hFile,
+ LPCVOID lpBuffer,
+ DWORD nNumberOfBytesToWrite,
+ LPDWORD lpNumberOfBytesWritten,
+ LPOVERLAPPED lpOverlapped
+ );
+
+ PAL_ERROR
+ InternalReadFile(
+ CPalThread *pThread,
+ HANDLE hFile,
+ LPVOID lpBuffer,
+ DWORD nNumberOfBytesToRead,
+ LPDWORD lpNumberOfBytesRead,
+ LPOVERLAPPED lpOverlapped
+ );
+
+ PAL_ERROR
+ InternalSetEndOfFile(
+ CPalThread *pThread,
+ HANDLE hFile
+ );
+
+ PAL_ERROR
+ InternalGetFileSize(
+ CPalThread *pThread,
+ HANDLE hFile,
+ DWORD *pdwFileSizeLow,
+ DWORD *pdwFileSizeHigh
+ );
+
+ PAL_ERROR
+ InternalFlushFileBuffers(
+ CPalThread *pThread,
+ HANDLE hFile
+ );
+
+ PAL_ERROR
+ InternalGetFileType(
+ CPalThread *pThread,
+ HANDLE hFile,
+ DWORD *pdwFileType
+ );
+
+ PAL_ERROR
+ InternalCreatePipe(
+ CPalThread *pThread,
+ HANDLE *phReadPipe,
+ HANDLE *phWritePipe,
+ LPSECURITY_ATTRIBUTES lpPipeAttributes,
+ DWORD nSize
+ );
+
+ PAL_ERROR
+ InternalLockFile(
+ CPalThread *pThread,
+ HANDLE hFile,
+ DWORD dwFileOffsetLow,
+ DWORD dwFileOffsetHigh,
+ DWORD nNumberOfBytesToLockLow,
+ DWORD nNumberOfBytesToLockHigh
+ );
+
+ PAL_ERROR
+ InternalUnlockFile(
+ CPalThread *pThread,
+ HANDLE hFile,
+ DWORD dwFileOffsetLow,
+ DWORD dwFileOffsetHigh,
+ DWORD nNumberOfBytesToUnlockLow,
+ DWORD nNumberOfBytesToUnlockHigh
+ );
+
+ PAL_ERROR
+ InternalSetFilePointer(
+ CPalThread *pThread,
+ HANDLE hFile,
+ LONG lDistanceToMove,
+ PLONG lpDistanceToMoveHigh,
+ DWORD dwMoveMethod,
+ PLONG lpNewFilePointerLow
+ );
+
+ PAL_ERROR
+ InternalSetFileTime(
+ CPalThread *pThread,
+ IN HANDLE hFile,
+ IN CONST FILETIME *lpCreationTime,
+ IN CONST FILETIME *lpLastAccessTime,
+ IN CONST FILETIME *lpLastWriteTime
+ );
+
+ PAL_ERROR
+ InternalGetFileTime(
+ CPalThread *pThread,
+ IN HANDLE hFile,
+ OUT LPFILETIME lpCreationTime,
+ OUT LPFILETIME lpLastAccessTime,
+ OUT LPFILETIME lpLastWriteTime
+ );
+
+ BOOL
+ RealPathHelper(LPCSTR lpUnixPath, PathCharString& lpBuffer);
+ /*++
+ InternalCanonicalizeRealPath
+ Wraps realpath() to hide platform differences. See the man page for
+ realpath(3) for details of how realpath() works.
+
+ On systems on which realpath() allows the last path component to not
+ exist, this is a straight thunk through to realpath(). On other
+ systems, we remove the last path component, then call realpath().
+ --*/
+ PAL_ERROR
+ InternalCanonicalizeRealPath(
+ LPCSTR lpUnixPath,
+ PathCharString& lpBuffer
+ );
+
+ /*++
+ InternalMkstemp
+ Wraps mkstemp
+ --*/
+ int
+ InternalMkstemp(
+ char *szNameTemplate
+ );
+
+ /*++
+ InternalFgets
+ Wraps fgets
+ --*/
+ char *
+ InternalFgets(
+ char *sz,
+ int nSize,
+ FILE *f,
+ bool fTextMode
+ );
+
+ /*++
+ InternalFwrite
+ Wraps fwrite
+ --*/
+ size_t
+ InternalFwrite(
+ const void *pvBuffer,
+ size_t nSize,
+ size_t nCount,
+ FILE *f,
+ INT *pnErrorCode
+ );
+
+ /*++
+ InternalOpen
+ Wraps open
+ --*/
+ int
+ InternalOpen(
+ const char *szFilename,
+ int nFlags,
+ ...
+ );
+}
+
+extern "C"
+{
+
+//
+// These routines should all be separated out into something along the lines
+// of fileutils.* (instead of being commingled with the core file object
+// code).
+//
+
+/*++
+FILECanonicalizePath
+ Removes all instances of '/./', '/../' and '//' from an absolute path.
+
+Parameters:
+ LPSTR lpUnixPath : absolute path to modify, in Unix format
+
+(no return value)
+
+Notes :
+-behavior is undefined if path is not absolute
+-the order of steps *is* important: /one/./../two would give /one/two
+ instead of /two if step 3 was done before step 2
+-reason for this function is that GetFullPathName can't use realpath(), since
+ realpath() requires the given path to be valid and GetFullPathName does not.
+--*/
+void FILECanonicalizePath(LPSTR lpUnixPath);
+
+/*++
+Function:
+ FileDosToUnixPathA
+
+Abstract:
+ Change a DOS path to a Unix path. Replace '\' by '/'.
+
+Parameter:
+ IN/OUT lpPath: path to be modified
+--*/
+void
+FILEDosToUnixPathA(LPSTR lpPath);
+
+/*++
+Function:
+ FileDosToUnixPathW
+
+Abstract:
+ Change a DOS path to a Unix path. Replace '\' by '/'.
+
+Parameter:
+ IN/OUT lpPath: path to be modified
+ --*/
+void
+FILEDosToUnixPathW(LPWSTR lpPath);
+
+/*++
+Function:
+ FileUnixToDosPathA
+
+Abstract:
+ Change a Unix path to a DOS path. Replace '/' by '\'.
+
+Parameter:
+ IN/OUT lpPath: path to be modified
+--*/
+void
+FILEUnixToDosPathA(LPSTR lpPath);
+
+
+/*++
+Function:
+ FILEGetDirectoryFromFullPathA
+
+Parse the given path. If it contains a directory part and a file part,
+put the directory part into the supplied buffer, and return the number of
+characters written to the buffer. If the buffer is not large enough,
+return the required size of the buffer including the NULL character. If
+there is no directory part in the path, return 0.
+--*/
+DWORD FILEGetDirectoryFromFullPathA( LPCSTR lpFullPath,
+ DWORD nBufferLength,
+ LPSTR lpBuffer );
+
+/*++
+Function:
+ FILEGetFileNameFromFullPath
+
+Given a full path, return a pointer to the first char of the filename part.
+--*/
+LPCSTR FILEGetFileNameFromFullPathA( LPCSTR lpFullPath );
+
+/*++
+Function:
+ FILEGetLastErrorFromErrno
+
+Convert errno into the appropriate win32 error and return it.
+--*/
+DWORD FILEGetLastErrorFromErrno( void );
+
+/*++
+FILEInitStdHandles
+
+Create handle objects for stdin, stdout and stderr
+
+(no parameters)
+
+Return value:
+ TRUE on success, FALSE on failure
+--*/
+BOOL FILEInitStdHandles(void);
+
+/*++
+FILECleanupStdHandles
+
+Close primary handles for stdin, stdout and stderr
+
+(no parameters, no return value)
+--*/
+void FILECleanupStdHandles(void);
+
+/*++
+
+Function :
+ FILEGetProperNotFoundError
+
+Returns the proper error code, based on the
+Windows behavoir.
+
+ IN LPSTR lpPath - The path to check.
+ LPDWORD lpErrorCode - The error to set.
+*/
+void FILEGetProperNotFoundError( LPCSTR lpPath, LPDWORD lpErrorCode );
+
+}
+
+#endif /* _PAL_FILE_HPP_ */
+
diff --git a/src/pal/src/include/pal/filetime.h b/src/pal/src/include/pal/filetime.h
new file mode 100644
index 0000000000..cb37b4115a
--- /dev/null
+++ b/src/pal/src/include/pal/filetime.h
@@ -0,0 +1,80 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ include/pal/filetime.h
+
+Abstract:
+
+ Header file for utility functions having to do with file times.
+
+Revision History:
+
+
+
+--*/
+
+#ifndef _PAL_FILETIME_H_
+#define _PAL_FILETIME_H_
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif // __cplusplus
+
+/* Provide consistent access to nanosecond fields, if they exist. */
+
+#if HAVE_STAT_TIMESPEC
+
+#define ST_ATIME_NSEC(statstruct) ((statstruct)->st_atimespec.tv_nsec)
+#define ST_MTIME_NSEC(statstruct) ((statstruct)->st_mtimespec.tv_nsec)
+#define ST_CTIME_NSEC(statstruct) ((statstruct)->st_ctimespec.tv_nsec)
+
+#else /* HAVE_STAT_TIMESPEC */
+
+#if HAVE_STAT_NSEC
+
+#define ST_ATIME_NSEC(statstruct) ((statstruct)->st_atimensec)
+#define ST_MTIME_NSEC(statstruct) ((statstruct)->st_mtimensec)
+#define ST_CTIME_NSEC(statstruct) ((statstruct)->st_ctimensec)
+
+#else /* HAVE_STAT_NSEC */
+
+#define ST_ATIME_NSEC(statstruct) 0
+#define ST_MTIME_NSEC(statstruct) 0
+#define ST_CTIME_NSEC(statstruct) 0
+
+#endif /* HAVE_STAT_NSEC */
+#endif /* HAVE_STAT_TIMESPEC */
+
+FILETIME FILEUnixTimeToFileTime( time_t sec, long nsec );
+time_t FILEFileTimeToUnixTime( FILETIME FileTime, long *nsec );
+
+#ifdef __APPLE__
+#include <CoreFoundation/CFDate.h>
+
+FILETIME FILECFAbsoluteTimeToFileTime( CFAbsoluteTime sec );
+#endif // __APPLE__
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif /* _PAL_FILE_H_ */
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/pal/src/include/pal/handleapi.hpp b/src/pal/src/include/pal/handleapi.hpp
new file mode 100644
index 0000000000..7974432a65
--- /dev/null
+++ b/src/pal/src/include/pal/handleapi.hpp
@@ -0,0 +1,48 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ handleapi.hpp
+
+Abstract:
+
+ Declaration of the handle management APIs
+
+
+
+--*/
+
+#ifndef _HANDLEAPI_HPP
+#define _HANDLEAPI_HPP
+
+#include "corunix.hpp"
+
+namespace CorUnix
+{
+ PAL_ERROR
+ InternalDuplicateHandle(
+ CPalThread *pThread,
+ HANDLE hSourceProcess,
+ HANDLE hSource,
+ HANDLE hTargetProcess,
+ LPHANDLE phDuplicate,
+ DWORD dwDesiredAccess,
+ BOOL bInheritHandle,
+ DWORD dwOptions
+ );
+
+ PAL_ERROR
+ InternalCloseHandle(
+ CPalThread *pThread,
+ HANDLE hObject
+ );
+}
+
+#endif // _HANDLEAPI_HPP
+
diff --git a/src/pal/src/include/pal/handlemgr.hpp b/src/pal/src/include/pal/handlemgr.hpp
new file mode 100644
index 0000000000..1fbdb87199
--- /dev/null
+++ b/src/pal/src/include/pal/handlemgr.hpp
@@ -0,0 +1,180 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ handlemgr.hpp
+
+Abstract:
+
+ Simple handle table manager class
+
+
+
+--*/
+
+#ifndef _PAL_HANDLEMGR_H_
+#define _PAL_HANDLEMGR_H_
+
+
+#include "corunix.hpp"
+#include "cs.hpp"
+#include "pal/thread.hpp"
+#include "pal/malloc.hpp"
+
+
+/* Pseudo handles constant for current thread and process */
+extern const HANDLE hPseudoCurrentProcess;
+extern const HANDLE hPseudoCurrentThread;
+extern const HANDLE hPseudoGlobalIOCP;
+
+namespace CorUnix
+{
+ class CSimpleHandleManager
+ {
+ private:
+ enum { c_BasicGrowthRate = 1024 };
+ enum { c_MaxIndex = 0x3FFFFFFE };
+
+ typedef UINT_PTR HANDLE_INDEX;
+ static const HANDLE_INDEX c_hiInvalid = (HANDLE_INDEX) -1;
+
+ HANDLE
+ HandleIndexToHandle(HANDLE_INDEX hi)
+ {
+ return (HANDLE) ((hi + 1) << 2);
+ };
+
+ HANDLE_INDEX
+ HandleToHandleIndex(HANDLE h)
+ {
+ return (HANDLE_INDEX) (((UINT_PTR) h) >> 2) - 1;
+ };
+
+ typedef struct _HANDLE_TABLE_ENTRY
+ {
+ union
+ {
+ IPalObject *pObject;
+ HANDLE_INDEX hiNextIndex;
+ } u;
+
+ DWORD dwAccessRights;
+ bool fInheritable;
+
+ bool fEntryAllocated;
+ } HANDLE_TABLE_ENTRY;
+
+ HANDLE_INDEX m_hiFreeListStart;
+ HANDLE_INDEX m_hiFreeListEnd;
+
+ DWORD m_dwTableSize;
+ DWORD m_dwTableGrowthRate;
+ HANDLE_TABLE_ENTRY* m_rghteHandleTable;
+
+ CRITICAL_SECTION m_csLock;
+ bool m_fLockInitialized;
+
+ bool ValidateHandle(HANDLE h);
+
+ public:
+
+ CSimpleHandleManager()
+ :
+ m_hiFreeListStart(c_hiInvalid),
+ m_hiFreeListEnd(c_hiInvalid),
+ m_dwTableSize(0),
+ m_dwTableGrowthRate(c_BasicGrowthRate),
+ m_rghteHandleTable(NULL),
+ m_fLockInitialized(FALSE)
+ {
+ };
+
+ virtual
+ ~CSimpleHandleManager()
+ {
+ if (m_fLockInitialized)
+ {
+ DeleteCriticalSection(&m_csLock);
+ }
+
+ if (NULL != m_rghteHandleTable)
+ {
+ free(m_rghteHandleTable);
+ }
+ }
+
+ PAL_ERROR
+ Initialize(
+ void
+ );
+
+ PAL_ERROR
+ AllocateHandle(
+ CPalThread *pThread,
+ IPalObject *pObject,
+ DWORD dwAccessRights,
+ bool fInheritable,
+ HANDLE *ph
+ );
+
+ //
+ // On success this will add a reference to the returned object.
+ //
+
+ PAL_ERROR
+ GetObjectFromHandle(
+ CPalThread *pThread,
+ HANDLE h,
+ DWORD *pdwRightsGranted,
+ IPalObject **ppObject
+ );
+
+ PAL_ERROR
+ FreeHandle(
+ CPalThread *pThread,
+ HANDLE h
+ );
+
+ void
+ Lock(
+ CPalThread *pThread
+ )
+ {
+ InternalEnterCriticalSection(pThread, &m_csLock);
+ };
+
+ void
+ Unlock(
+ CPalThread *pThread
+ )
+ {
+ InternalLeaveCriticalSection(pThread, &m_csLock);
+ };
+ };
+
+ bool
+ HandleIsSpecial(
+ HANDLE h
+ );
+}
+
+#endif // _PAL_HANDLEMGR_H_
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/pal/src/include/pal/identity.hpp b/src/pal/src/include/pal/identity.hpp
new file mode 100644
index 0000000000..bd64a659ac
--- /dev/null
+++ b/src/pal/src/include/pal/identity.hpp
@@ -0,0 +1,57 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ include/pal/identity.hpp
+
+Abstract:
+
+ Header file for identity functions.
+
+
+
+--*/
+
+#ifndef _PAL_IDENTITY_HPP_
+#define _PAL_IDENTITY_HPP_
+
+#include "config.h"
+#include "pal/palinternal.h"
+
+/*++
+
+Function:
+ IdentityInitialize
+
+--*/
+BOOL IdentityInitialize();
+
+/*++
+Function:
+ IdentityCleanup
+
+--*/
+VOID IdentityCleanup();
+
+#if HAVE_GETPWUID_R
+namespace CorUnix
+{
+ int
+ InternalGetpwuid_r(
+ CPalThread *pPalThread,
+ uid_t uid,
+ struct passwd *pPasswd,
+ char *pchBuffer,
+ size_t nBufSize,
+ struct passwd **ppResult
+ );
+}
+#endif /* HAVE_GETPWUID_R */
+
+#endif /* _PAL_IDENTITY_HPP_ */
diff --git a/src/pal/src/include/pal/init.h b/src/pal/src/include/pal/init.h
new file mode 100644
index 0000000000..d478ed275b
--- /dev/null
+++ b/src/pal/src/include/pal/init.h
@@ -0,0 +1,111 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ include/pal/init.h
+
+Abstract:
+ Header file for PAL init utility functions. Those functions
+ are only use by the PAL itself.
+
+Revision History:
+
+
+
+--*/
+
+#ifndef _PAL_INIT_H_
+#define _PAL_INIT_H_
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif // __cplusplus
+
+/*++
+Function:
+ PALCommonCleanup
+
+Utility function to prepare for shutdown.
+
+--*/
+void PALCommonCleanup();
+
+extern Volatile<INT> init_count;
+
+/*++
+MACRO:
+ PALIsInitialized
+
+Returns TRUE if the PAL is in an initialized state
+(#calls to PAL_Initialize > #calls to PAL_Terminate)
+
+Warning : this will only report the PAL's state at the moment it is called.
+If it is necessary to ensure the PAL remains initialized (or not) while doing
+some work, the Initialization lock (PALInitLock()) should be held.
+--*/
+#define PALIsInitialized() (0 < init_count)
+
+/*++
+Function:
+ PALIsThreadDataInitialized
+
+Returns TRUE if startup has reached a point where thread data is available
+--*/
+BOOL
+PALIsThreadDataInitialized();
+
+/*++
+Function:
+ PALIsShuttingDown
+
+Returns TRUE if the some thread has declared intent to shutdown
+--*/
+BOOL
+PALIsShuttingDown();
+
+/*++
+Function:
+ PALSetShutdownIntent
+
+Delcares intent to shutdown
+--*/
+void
+PALSetShutdownIntent();
+
+/*++
+Function:
+ PALInitLock
+
+Take the initializaiton critical section (init_critsec). necessary to serialize
+TerminateProcess along with PAL_Terminate and PAL_Initialize
+
+(no parameters)
+
+Return value :
+ TRUE if critical section existed (and was acquired)
+ FALSE if critical section doens't exist yet
+--*/
+BOOL PALInitLock(void);
+
+/*++
+Function:
+ PALInitUnlock
+
+Release the initialization critical section (init_critsec).
+
+(no parameters, no return value)
+--*/
+void PALInitUnlock(void);
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif /* _PAL_INIT_H_ */
diff --git a/src/pal/src/include/pal/list.h b/src/pal/src/include/pal/list.h
new file mode 100644
index 0000000000..cd78c0f03a
--- /dev/null
+++ b/src/pal/src/include/pal/list.h
@@ -0,0 +1,141 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ list.h
+
+Abstract:
+
+ Doubly-linked list manipulation macros (from ntrtl.h)
+
+Revision History:
+
+
+
+--*/
+
+#ifndef _LIST_H_INCLUDED
+#define _LIST_H_INCLUDED
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif // __cplusplus
+
+typedef struct _LIST_ENTRY {
+ struct _LIST_ENTRY *Flink;
+ struct _LIST_ENTRY *Blink;
+} LIST_ENTRY, *PLIST_ENTRY;
+
+//
+// VOID
+// InitializeListHead(
+// PLIST_ENTRY ListHead
+// );
+//
+
+#define InitializeListHead(ListHead) (\
+ (ListHead)->Flink = (ListHead)->Blink = (ListHead))
+
+//
+// BOOLEAN
+// IsListEmpty(
+// PLIST_ENTRY ListHead
+// );
+//
+
+#define IsListEmpty(ListHead) \
+ ((ListHead)->Flink == (ListHead))
+
+//
+// PLIST_ENTRY
+// RemoveHeadList(
+// PLIST_ENTRY ListHead
+// );
+//
+
+#define RemoveHeadList(ListHead) \
+ (ListHead)->Flink;\
+ {RemoveEntryList((ListHead)->Flink)}
+
+//
+// PLIST_ENTRY
+// RemoveTailList(
+// PLIST_ENTRY ListHead
+// );
+//
+
+#define RemoveTailList(ListHead) \
+ (ListHead)->Blink;\
+ {RemoveEntryList((ListHead)->Blink)}
+
+//
+// VOID
+// RemoveEntryList(
+// PLIST_ENTRY Entry
+// );
+//
+
+#define RemoveEntryList(Entry) {\
+ PLIST_ENTRY _EX_Blink;\
+ PLIST_ENTRY _EX_Flink;\
+ _EX_Flink = (Entry)->Flink;\
+ _EX_Blink = (Entry)->Blink;\
+ _EX_Blink->Flink = _EX_Flink;\
+ _EX_Flink->Blink = _EX_Blink;\
+ }
+
+//
+// VOID
+// InsertTailList(
+// PLIST_ENTRY ListHead,
+// PLIST_ENTRY Entry
+// );
+//
+
+#define InsertTailList(ListHead,Entry) {\
+ PLIST_ENTRY _EX_Blink;\
+ PLIST_ENTRY _EX_ListHead;\
+ _EX_ListHead = (ListHead);\
+ _EX_Blink = _EX_ListHead->Blink;\
+ (Entry)->Flink = _EX_ListHead;\
+ (Entry)->Blink = _EX_Blink;\
+ _EX_Blink->Flink = (Entry);\
+ _EX_ListHead->Blink = (Entry);\
+ }
+
+//
+// VOID
+// InsertHeadList(
+// PLIST_ENTRY ListHead,
+// PLIST_ENTRY Entry
+// );
+//
+
+#define InsertHeadList(ListHead,Entry) {\
+ PLIST_ENTRY _EX_Flink;\
+ PLIST_ENTRY _EX_ListHead;\
+ _EX_ListHead = (ListHead);\
+ _EX_Flink = _EX_ListHead->Flink;\
+ (Entry)->Flink = _EX_Flink;\
+ (Entry)->Blink = _EX_ListHead;\
+ _EX_Flink->Blink = (Entry);\
+ _EX_ListHead->Flink = (Entry);\
+ }
+
+#define CONTAINING_RECORD(address, type, field) ((type *)( \
+ (PCHAR)(address) - \
+ (ULONG_PTR)(&((type *)0)->field)))
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif // _LIST_H_INCLUDED
+
diff --git a/src/pal/src/include/pal/locale.h b/src/pal/src/include/pal/locale.h
new file mode 100644
index 0000000000..f59ce2e174
--- /dev/null
+++ b/src/pal/src/include/pal/locale.h
@@ -0,0 +1,75 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ locale.h
+
+Abstract:
+
+ Prototypes for codepage initialization, and control of the readwrite locks
+ for systems that use them.
+
+Revision History:
+
+
+
+--*/
+
+#ifndef _PAL_LOCALE_H_
+#define _PAL_LOCALE_H_
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif // __cplusplus
+
+#if HAVE_LOWERCASE_ISO_NAME
+#define ISO_NAME(region, encoding, part) region ".iso" encoding part
+#elif HAVE_UNDERSCORE_ISO_NAME
+#define ISO_NAME(region, encoding, part) region ".ISO_" encoding "-" part
+#else
+#define ISO_NAME(region, encoding, part) region ".ISO" encoding "-" part
+#endif
+
+#if HAVE_COREFOUNDATION
+#define CF_EXCLUDE_CSTD_HEADERS
+#include <CoreFoundation/CoreFoundation.h>
+#endif // HAVE_COREFOUNDATION
+
+#if HAVE_COREFOUNDATION
+#if !ENABLE_DOWNLEVEL_FOR_NLS
+BOOL LocaleInitialize( void );
+void LocaleCleanup( void );
+#endif // !ENABLE_DOWNLEVEL_FOR_NLS
+
+typedef
+struct _CP_MAPPING
+{
+ UINT nCodePage; /* Code page identifier. */
+ CFStringEncoding nCFEncoding; /* The equivalent CFString encoding. */
+ UINT nMaxByteSize; /* The max byte size of any character. */
+ BYTE LeadByte[ MAX_LEADBYTES ]; /* The lead byte array. */
+} CP_MAPPING;
+#elif HAVE_PTHREAD_RWLOCK_T
+typedef
+struct _CP_MAPPING
+{
+ UINT nCodePage; // Code page identifier.
+ LPCSTR lpBSDEquivalent; // The equivalent BSD locale identifier.
+ UINT nMaxByteSize; // The max byte size of any character.
+ BYTE LeadByte[ MAX_LEADBYTES ]; // The lead byte array.
+} CP_MAPPING;
+#else
+#error Insufficient platform support for text encodings
+#endif
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif /* _PAL_LOCALE_H_ */
diff --git a/src/pal/src/include/pal/malloc.hpp b/src/pal/src/include/pal/malloc.hpp
new file mode 100644
index 0000000000..c7333419a7
--- /dev/null
+++ b/src/pal/src/include/pal/malloc.hpp
@@ -0,0 +1,152 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ pal/malloc.hpp
+
+Abstract:
+ Declarations for suspension safe memory allocation functions
+
+
+
+--*/
+
+#ifndef _MALLOC_HPP
+#define _MALLOC_HPP
+
+#include "pal/corunix.hpp"
+#include "pal/thread.hpp"
+
+#include <stdarg.h>
+#include <stdlib.h>
+
+extern "C"
+{
+ void *
+ __cdecl
+ PAL_realloc(
+ void* pvMemblock,
+ size_t szSize
+ );
+
+ void *
+ __cdecl
+ PAL_malloc(
+ size_t szSize
+ );
+
+ void
+ __cdecl
+ PAL_free(
+ void *pvMem
+ );
+
+ char *
+ __cdecl
+ PAL__strdup(
+ const char *c_szStr
+ );
+}
+
+inline void* operator new(size_t, void* p) throw () { return p; }
+inline void* operator new[](size_t, void* p) throw () { return p; }
+
+namespace CorUnix{
+
+ void *
+ InternalRealloc(
+ void *pvMemblock,
+ size_t szSize
+ );
+
+ void *
+ InternalMalloc(
+ size_t szSize
+ );
+
+ // Define common code for "new" style allocators below.
+#define INTERNAL_NEW_COMMON() \
+ T *pMem = (T*)InternalMalloc(sizeof(T)); \
+ if (pMem == NULL) \
+ return NULL;
+
+ // Define "new" style allocators (which allocate then call a constructor) for different numbers of
+ // constructor arguments. Added based on usage.
+
+ // Default constructor (0 args) case.
+ template<class T>
+ T* InternalNew()
+ {
+ INTERNAL_NEW_COMMON();
+ return new (pMem) T();
+ }
+
+ // 2 args case.
+ template<class T, class A1, class A2>
+ T* InternalNew(A1 arg1, A2 arg2)
+ {
+ INTERNAL_NEW_COMMON();
+ return new (pMem) T(arg1, arg2);
+ }
+
+ // 4 args case.
+ template<class T, class A1, class A2, class A3, class A4>
+ T* InternalNew(A1 arg1, A2 arg2, A3 arg3, A4 arg4)
+ {
+ INTERNAL_NEW_COMMON();
+ return new (pMem) T(arg1, arg2, arg3, arg4);
+ }
+
+ // 5 args case.
+ template<class T, class A1, class A2, class A3, class A4, class A5>
+ T* InternalNew(A1 arg1, A2 arg2, A3 arg3, A4 arg4, A5 arg5)
+ {
+ INTERNAL_NEW_COMMON();
+ return new (pMem) T(arg1, arg2, arg3, arg4, arg5);
+ }
+
+ template<class T> T* InternalNewArray(size_t cElements)
+ {
+ size_t cbSize = (cElements * sizeof(T)) + sizeof(size_t);
+ T *pMem;
+
+ pMem = (T*)InternalMalloc(cbSize);
+
+ if (pMem == NULL)
+ return NULL;
+
+ *(size_t*)pMem = cElements;
+ pMem = (T*)((size_t*)pMem + 1);
+
+ return new (pMem) T[cElements]();
+ }
+
+ template<class T> void InternalDelete(T *p)
+ {
+ if (p)
+ {
+ p->~T();
+ free(p);
+ }
+ }
+
+ template<class T> void InternalDeleteArray(T *p)
+ {
+ if (p)
+ {
+ size_t *pRealMem = (size_t*)p - 1;
+ size_t cElements = *pRealMem;
+ for (size_t i = 0; i < cElements; i++)
+ p[i].~T();
+ free(pRealMem);
+ }
+ }
+}
+
+#endif // _MALLOC_HPP
diff --git a/src/pal/src/include/pal/map.h b/src/pal/src/include/pal/map.h
new file mode 100644
index 0000000000..96f538fbd1
--- /dev/null
+++ b/src/pal/src/include/pal/map.h
@@ -0,0 +1,52 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ include/pal/map.h
+
+Abstract:
+
+ Header file for file mapping functions.
+
+
+
+--*/
+
+#ifndef _PAL_MAP_H_
+#define _PAL_MAP_H_
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif // __cplusplus
+
+/*++
+Function :
+ MAPGetRegionInfo
+
+ Parameters:
+ lpAddress: pointer to the starting memory location, not necessary
+ to be rounded to the page location
+
+ lpBuffer: if this function finds information about the specified address,
+ the information is stored in this struct
+
+ Note: This function is to be used in virtual.c
+
+ Returns TRUE if this function finds information about the specified address
+--*/
+
+BOOL MAPGetRegionInfo(LPVOID lpAddress, PMEMORY_BASIC_INFORMATION lpBuffer);
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif /* _PAL_MAP_H_ */
+
diff --git a/src/pal/src/include/pal/map.hpp b/src/pal/src/include/pal/map.hpp
new file mode 100644
index 0000000000..854e6c549a
--- /dev/null
+++ b/src/pal/src/include/pal/map.hpp
@@ -0,0 +1,209 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ include/pal/map.hpp
+
+Abstract:
+
+ Header file for file mapping functions.
+
+
+
+--*/
+
+#ifndef _PAL_MAP_H_
+#define _PAL_MAP_H_
+
+#include "corunix.hpp"
+#include <sys/param.h>
+
+extern "C"
+{
+#include "list.h"
+
+#ifndef NO_INO
+#define NO_INO ((ino_t)-1)
+#endif
+
+ /*++
+ Function :
+ MapInitialize
+
+ Initialize the critical sections.
+
+ Return value:
+ TRUE if initialization succeeded
+ FALSE otherwise
+ --*/
+ BOOL MAPInitialize( void );
+
+ /*++
+ Function :
+ MapCleanup
+
+ Deletes the critical sections.
+
+ --*/
+ void MAPCleanup( void );
+
+ /*++
+ Function :
+ MAPGetRegionInfo
+
+ Parameters:
+ lpAddress: pointer to the starting memory location, not necessary
+ to be rounded to the page location
+
+ lpBuffer: if this function finds information about the specified address,
+ the information is stored in this struct
+
+ Note: This function is to be used in virtual.c
+
+ Returns TRUE if this function finds information about the specified address
+ --*/
+
+ BOOL MAPGetRegionInfo(LPVOID lpAddress, PMEMORY_BASIC_INFORMATION lpBuffer);
+
+ /*++
+ MAPMapPEFile -
+
+ Map a PE format file into memory like Windows LoadLibrary() would do.
+ Doesn't apply base relocations if the function is relocated.
+
+ Parameters:
+ IN hFile - file to map
+
+ Return value:
+ non-NULL - the base address of the mapped image
+ NULL - error, with last error set.
+ --*/
+
+ void * MAPMapPEFile(HANDLE hFile);
+
+ /*++
+ Function :
+ MAPUnmapPEFile - unmap a PE file, and remove it from the recorded list of PE files mapped
+
+ returns TRUE if successful, FALSE otherwise
+ --*/
+ BOOL MAPUnmapPEFile(LPCVOID lpAddress);
+}
+
+namespace CorUnix
+{
+ extern CObjectType otFileMapping;
+
+#if ONE_SHARED_MAPPING_PER_FILEREGION_PER_PROCESS
+ typedef struct _NativeMapHolder
+ {
+ Volatile<LONG> ref_count;
+ LPVOID address;
+ SIZE_T size;
+ SIZE_T offset; /* for future use */
+ } NativeMapHolder;
+#endif
+
+ /* Process specific information. This
+ structure is not stored in shared memory.*/
+ typedef struct _MVL
+ {
+ LIST_ENTRY Link;
+
+ //
+ // Each MVL entry holds a reference to its parent file
+ // mapping object.
+ //
+
+ IPalObject *pFileMapping;
+
+#if ONE_SHARED_MAPPING_PER_FILEREGION_PER_PROCESS
+ NativeMapHolder * pNMHolder; /* Ref-counted holder for memory mapping */
+ dev_t MappedFileDevNum; /* ID of device containing the file to be mapped */
+ ino_t MappedFileInodeNum; /* Inode number of file to be mapped.
+ These two fields are used used to uniquely
+ identify files on systems that do not allow
+ more than one shared mmapping per region of
+ physical file, per process */
+#endif
+ LPVOID lpAddress; /* The pointer to the mapped memory. */
+ SIZE_T NumberOfBytesToMap; /* Number of bytes to map. */
+ DWORD dwDesiredAccess; /* Desired access. */
+ LPVOID lpPEBaseAddress; /* If this mapping is part of a PE file mapping, this is the
+ base address pointer of the PE file (used to find all
+ parts of the PE file mapping to allow PE file unload).
+ Otherwise, it is NULL. */
+ } MAPPED_VIEW_LIST, * PMAPPED_VIEW_LIST;
+
+ class CFileMappingImmutableData
+ {
+ public:
+ CHAR szFileName[MAXPATHLEN];
+ UINT MaxSize; // The max size of the file mapping object
+ DWORD flProtect; // Protection desired for the file view
+ BOOL bPALCreatedTempFile; // TRUE if it's a PAL created file
+ DWORD dwDesiredAccessWhenOpened; // FILE_MAP_WRITE etc
+ };
+
+ class CFileMappingProcessLocalData
+ {
+ public:
+ INT UnixFd; /* File descriptor. */
+
+#if ONE_SHARED_MAPPING_PER_FILEREGION_PER_PROCESS
+ dev_t MappedFileDevNum; /* ID of device containing the file to be mapped */
+ ino_t MappedFileInodeNum; /* Inode number of file to be mapped.
+ These two fields are used used to uniquely
+ identify files on systems that do not allow
+ more than one shared mmapping per region of
+ physical file, per process */
+#endif
+ };
+
+ PAL_ERROR
+ InternalCreateFileMapping(
+ CPalThread *pThread,
+ HANDLE hFile,
+ LPSECURITY_ATTRIBUTES lpFileMappingAttributes,
+ DWORD flProtect,
+ DWORD dwMaximumSizeHigh,
+ DWORD dwMaximumSizeLow,
+ LPCWSTR lpName,
+ HANDLE *phMapping
+ );
+
+ PAL_ERROR
+ InternalOpenFileMapping(
+ CPalThread *pThread,
+ DWORD dwDesiredAccess,
+ BOOL bInheritHandle,
+ LPCWSTR lpName,
+ HANDLE *phMapping
+ );
+
+ PAL_ERROR
+ InternalMapViewOfFile(
+ CPalThread *pThread,
+ HANDLE hFileMappingObject,
+ DWORD dwDesiredAccess,
+ DWORD dwFileOffsetHigh,
+ DWORD dwFileOffsetLow,
+ SIZE_T dwNumberOfBytesToMap,
+ LPVOID *ppvBaseAddress
+ );
+
+ PAL_ERROR
+ InternalUnmapViewOfFile(
+ CPalThread *pThread,
+ LPCVOID lpBaseAddress
+ );
+
+}
+
+#endif /* _PAL_MAP_H_ */
diff --git a/src/pal/src/include/pal/misc.h b/src/pal/src/include/pal/misc.h
new file mode 100644
index 0000000000..65d59aee60
--- /dev/null
+++ b/src/pal/src/include/pal/misc.h
@@ -0,0 +1,83 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ include/pal/misc.h
+
+Abstract:
+ Header file for the initialization and clean up functions
+ for the misc Win32 functions
+
+
+
+--*/
+
+#ifndef __MISC_H_
+#define __MISC_H_
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif // __cplusplus
+
+/*++
+Function :
+
+ PAL_rand
+
+ Calls rand and mitigates the difference between RAND_MAX
+ on Windows and FreeBSD.
+--*/
+int __cdecl PAL_rand(void);
+
+/*++
+Function :
+
+ PAL_time
+--*/
+PAL_time_t __cdecl PAL_time(PAL_time_t*);
+
+/*++
+Function:
+TIMEInitialize
+
+Return value:
+TRUE if initialize succeeded
+FALSE otherwise
+
+--*/
+BOOL TIMEInitialize( void );
+
+/*++
+Function :
+ MsgBoxInitialize
+
+ Initialize the critical sections.
+
+Return value:
+ TRUE if initialize succeeded
+ FALSE otherwise
+
+--*/
+BOOL MsgBoxInitialize( void );
+
+/*++
+Function :
+ MsgBoxCleanup
+
+ Deletes the critical sections.
+
+--*/
+void MsgBoxCleanup( void );
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif /* __MISC_H_ */
diff --git a/src/pal/src/include/pal/module.h b/src/pal/src/include/pal/module.h
new file mode 100644
index 0000000000..95fa605c21
--- /dev/null
+++ b/src/pal/src/include/pal/module.h
@@ -0,0 +1,203 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ include/pal/module.h
+
+Abstract:
+ Header file for modle management utilities.
+
+
+
+--*/
+
+#ifndef _PAL_MODULE_H_
+#define _PAL_MODULE_H_
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif // __cplusplus
+
+typedef BOOL (__stdcall *PDLLMAIN)(HINSTANCE, DWORD, LPVOID); /* entry point of module */
+typedef HINSTANCE (PALAPI *PREGISTER_MODULE)(LPCSTR); /* used to create the HINSTANCE for above DLLMain entry point */
+typedef VOID (PALAPI *PUNREGISTER_MODULE)(HINSTANCE); /* used to cleanup the HINSTANCE for above DLLMain entry point */
+
+typedef struct _MODSTRUCT
+{
+ HMODULE self; /* circular reference to this module */
+ void *dl_handle; /* handle returned by dlopen() */
+ HINSTANCE hinstance; /* handle returned by PAL_RegisterLibrary */
+ LPWSTR lib_name; /* full path of module */
+ INT refcount; /* reference count */
+ /* -1 means infinite reference count - module is never released */
+ BOOL threadLibCalls; /* TRUE for DLL_THREAD_ATTACH/DETACH notifications enabled, FALSE if they are disabled */
+
+#if RETURNS_NEW_HANDLES_ON_REPEAT_DLOPEN
+ ino_t inode;
+ dev_t device;
+#endif
+
+ PDLLMAIN pDllMain; /* entry point of module */
+
+ /* reference to next and previous modules in list (in load order) */
+ struct _MODSTRUCT *next;
+ struct _MODSTRUCT *prev;
+} MODSTRUCT;
+
+
+/*++
+Function :
+ LOADInitializeModules
+
+ Initialize the process-wide list of modules
+
+Parameters :
+ None
+
+Return value :
+ TRUE on success, FALSE on failure
+
+--*/
+BOOL LOADInitializeModules();
+
+/*++
+Function :
+ LOADSetExeName
+
+ Set the exe name path
+
+Parameters :
+ LPWSTR man exe path and name
+
+Return value :
+ TRUE if initialization succeedded
+ FALSE otherwise
+
+--*/
+BOOL LOADSetExeName(LPWSTR name);
+
+/*++
+Function :
+ LOADCallDllMain
+
+ Call DllMain for all modules (that have one) with the given "fwReason"
+
+Parameters :
+ DWORD dwReason : parameter to pass down to DllMain, one of DLL_PROCESS_ATTACH, DLL_PROCESS_DETACH,
+ DLL_THREAD_ATTACH, DLL_THREAD_DETACH
+
+ LPVOID lpReserved : parameter to pass down to DllMain
+ If dwReason is DLL_PROCESS_ATTACH, lpvReserved is NULL for dynamic loads and non-NULL for static loads.
+ If dwReason is DLL_PROCESS_DETACH, lpvReserved is NULL if DllMain has been called by using FreeLibrary
+ and non-NULL if DllMain has been called during process termination.
+
+(no return value)
+
+Notes :
+ This is used to send DLL_THREAD_*TACH messages to modules
+--*/
+void LOADCallDllMain(DWORD dwReason, LPVOID lpReserved);
+
+/*++
+Function:
+ LockModuleList
+
+Abstract
+ Enter the critical section associated to the module list
+
+Parameter
+ void
+
+Return
+ void
+--*/
+void LockModuleList();
+
+/*++
+Function:
+ UnlockModuleList
+
+Abstract
+ Leave the critical section associated to the module list
+
+Parameter
+ void
+
+Return
+ void
+--*/
+void UnlockModuleList();
+
+/*++
+Function:
+ PAL_LOADLoadPEFile
+
+Abstract
+ Loads a PE file into memory. Properly maps all of the sections in the PE file. Returns a pointer to the
+ loaded base.
+
+Parameters:
+ IN hFile - The file to load
+
+Return value:
+ A valid base address if successful.
+ 0 if failure
+--*/
+void * PAL_LOADLoadPEFile(HANDLE hFile);
+
+/*++
+ PAL_LOADUnloadPEFile
+
+ Unload a PE file that was loaded by PAL_LOADLoadPEFile().
+
+Parameters:
+ IN ptr - the file pointer returned by PAL_LOADLoadPEFile()
+
+Return value:
+ TRUE - success
+ FALSE - failure (incorrect ptr, etc.)
+--*/
+BOOL PAL_LOADUnloadPEFile(void * ptr);
+
+/*++
+ LOADInitializeCoreCLRModule
+
+ Run the initialization methods for CoreCLR module.
+
+Parameters:
+ None
+
+Return value:
+ TRUE if successful
+ FALSE if failure
+--*/
+BOOL LOADInitializeCoreCLRModule();
+
+/*++
+Function :
+ LOADGetPalLibrary
+
+ Load and initialize the PAL module.
+
+Parameters :
+ None
+
+Return value :
+ handle to loaded module
+
+--*/
+MODSTRUCT *LOADGetPalLibrary();
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif /* _PAL_MODULE_H_ */
+
diff --git a/src/pal/src/include/pal/modulename.h b/src/pal/src/include/pal/modulename.h
new file mode 100644
index 0000000000..70b0a610dc
--- /dev/null
+++ b/src/pal/src/include/pal/modulename.h
@@ -0,0 +1,39 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ include/pal/modulename.h
+
+Abstract:
+ Header file for functions to get the name of a module
+
+Revision History:
+
+
+
+--*/
+
+#ifndef _PAL_MODULENAME_H_
+#define _PAL_MODULENAME_H_
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif // __cplusplus
+
+const char *PAL_dladdr(LPVOID ProcAddress);
+#if defined(_AIX)
+int GetLibRotorNameViaLoadQuery(LPSTR pszBuf);
+#endif
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif /*_PAL_MODULENAME_H_*/
diff --git a/src/pal/src/include/pal/mutex.hpp b/src/pal/src/include/pal/mutex.hpp
new file mode 100644
index 0000000000..6a46689d7d
--- /dev/null
+++ b/src/pal/src/include/pal/mutex.hpp
@@ -0,0 +1,191 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ mutex.hpp
+
+Abstract:
+
+ Mutex object structure definition.
+
+
+
+--*/
+
+#ifndef _PAL_MUTEX_H_
+#define _PAL_MUTEX_H_
+
+#include "corunix.hpp"
+#include "sharedmemory.h"
+
+#include <pthread.h>
+
+namespace CorUnix
+{
+ extern CObjectType otMutex;
+ extern CObjectType otNamedMutex;
+
+ PAL_ERROR
+ InternalCreateMutex(
+ CPalThread *pThread,
+ LPSECURITY_ATTRIBUTES lpMutexAttributes,
+ BOOL bInitialOwner,
+ LPCSTR lpName,
+ HANDLE *phMutex
+ );
+
+ PAL_ERROR
+ InternalReleaseMutex(
+ CPalThread *pThread,
+ HANDLE hMutex
+ );
+
+ PAL_ERROR
+ InternalOpenMutex(
+ CPalThread *pThread,
+ DWORD dwDesiredAccess,
+ BOOL bInheritHandle,
+ LPCSTR lpName,
+ HANDLE *phMutex
+ );
+
+}
+
+#define SYNCSPINLOCK_F_ASYMMETRIC 1
+
+#define SPINLOCKInit(lock) (*(lock) = 0)
+#define SPINLOCKDestroy SPINLOCKInit
+
+void SPINLOCKAcquire (LONG * lock, unsigned int flags);
+void SPINLOCKRelease (LONG * lock);
+DWORD SPINLOCKTryAcquire (LONG * lock);
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// Named mutex
+
+// Temporarily disabling usage of pthread process-shared mutexes on ARM/ARM64 due to functional issues that cannot easily be
+// detected with code due to hangs. See https://github.com/dotnet/coreclr/issues/5456.
+#if HAVE_FULLY_FEATURED_PTHREAD_MUTEXES && HAVE_FUNCTIONAL_PTHREAD_ROBUST_MUTEXES && !(defined(_ARM_) || defined(_ARM64_))
+ #define NAMED_MUTEX_USE_PTHREAD_MUTEX 1
+#else
+ #define NAMED_MUTEX_USE_PTHREAD_MUTEX 0
+#endif
+
+enum class NamedMutexError : DWORD
+{
+ MaximumRecursiveLocksReached = ERROR_NOT_ENOUGH_MEMORY,
+ ThreadHasNotAcquiredMutex = ERROR_NOT_OWNER,
+ Unknown = ERROR_NOT_ENOUGH_MEMORY
+};
+
+enum class MutexTryAcquireLockResult
+{
+ AcquiredLock,
+ AcquiredLockButMutexWasAbandoned,
+ TimedOut
+};
+
+#if NAMED_MUTEX_USE_PTHREAD_MUTEX
+class MutexHelpers
+{
+public:
+ static void InitializeProcessSharedRobustRecursiveMutex(pthread_mutex_t *mutex);
+ static void DestroyMutex(pthread_mutex_t *mutex);
+
+ static MutexTryAcquireLockResult TryAcquireLock(pthread_mutex_t *mutex, DWORD timeoutMilliseconds);
+ static void ReleaseLock(pthread_mutex_t *mutex);
+};
+#endif // NAMED_MUTEX_USE_PTHREAD_MUTEX
+
+class NamedMutexSharedData
+{
+private:
+#if NAMED_MUTEX_USE_PTHREAD_MUTEX
+ pthread_mutex_t m_lock;
+#else // !NAMED_MUTEX_USE_PTHREAD_MUTEX
+ UINT32 m_timedWaiterCount;
+#endif // NAMED_MUTEX_USE_PTHREAD_MUTEX
+ UINT32 m_lockOwnerProcessId;
+ UINT64 m_lockOwnerThreadId;
+ bool m_isAbandoned;
+
+public:
+ NamedMutexSharedData();
+ ~NamedMutexSharedData();
+
+#if NAMED_MUTEX_USE_PTHREAD_MUTEX
+public:
+ pthread_mutex_t *GetLock();
+#else // !NAMED_MUTEX_USE_PTHREAD_MUTEX
+public:
+ bool HasAnyTimedWaiters() const;
+ void IncTimedWaiterCount();
+ void DecTimedWaiterCount();
+#endif // NAMED_MUTEX_USE_PTHREAD_MUTEX
+
+public:
+ bool IsAbandoned() const;
+ void SetIsAbandoned(bool isAbandoned);
+
+public:
+ bool IsLockOwnedByAnyThread() const;
+ bool IsLockOwnedByCurrentThread() const;
+ void SetLockOwnerToCurrentThread();
+ void ClearLockOwner();
+};
+
+class NamedMutexProcessData : public SharedMemoryProcessDataBase
+{
+private:
+ static const UINT8 SyncSystemVersion;
+ static const DWORD PollLoopMaximumSleepMilliseconds;
+
+private:
+ SharedMemoryProcessDataHeader *m_processDataHeader;
+ NamedMutexSharedData *m_sharedData;
+ SIZE_T m_lockCount;
+#if !NAMED_MUTEX_USE_PTHREAD_MUTEX
+ HANDLE m_processLockHandle;
+ int m_sharedLockFileDescriptor;
+#endif // !NAMED_MUTEX_USE_PTHREAD_MUTEX
+ CorUnix::CPalThread *m_lockOwnerThread;
+ NamedMutexProcessData *m_nextInThreadOwnedNamedMutexList;
+
+public:
+ static SharedMemoryProcessDataHeader *CreateOrOpen(LPCSTR name, bool acquireLockIfCreated, bool *createdRef);
+ static SharedMemoryProcessDataHeader *Open(LPCSTR name);
+private:
+ static SharedMemoryProcessDataHeader *CreateOrOpen(LPCSTR name, bool createIfNotExist, bool acquireLockIfCreated, bool *createdRef);
+
+public:
+ NamedMutexProcessData(
+ SharedMemoryProcessDataHeader *processDataHeader
+ #if !NAMED_MUTEX_USE_PTHREAD_MUTEX
+ ,
+ int sharedLockFileDescriptor
+ #endif // !NAMED_MUTEX_USE_PTHREAD_MUTEX
+ );
+ virtual void Close(bool isAbruptShutdown, bool releaseSharedData) override;
+
+private:
+ NamedMutexSharedData *GetSharedData() const;
+ void SetLockOwnerThread(CorUnix::CPalThread *lockOwnerThread);
+public:
+ NamedMutexProcessData *GetNextInThreadOwnedNamedMutexList() const;
+ void SetNextInThreadOwnedNamedMutexList(NamedMutexProcessData *next);
+
+public:
+ MutexTryAcquireLockResult TryAcquireLock(DWORD timeoutMilliseconds);
+ void ReleaseLock();
+ void Abandon();
+private:
+ void ActuallyReleaseLock();
+};
+
+#endif //_PAL_MUTEX_H_
diff --git a/src/pal/src/include/pal/palinternal.h b/src/pal/src/include/pal/palinternal.h
new file mode 100644
index 0000000000..7348192e6d
--- /dev/null
+++ b/src/pal/src/include/pal/palinternal.h
@@ -0,0 +1,696 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ palinternal.h
+
+Abstract:
+
+ Rotor Platform Adaptation Layer (PAL) header file used by source
+ file part of the PAL implementation. This is a wrapper over
+ unix/inc/pal.h. It allows avoiding name collisions when including
+ system header files, and it allows redirecting calls to 'standard' functions
+ to their PAL counterpart
+
+Details :
+
+A] Rationale (see B] for the quick recipe)
+There are 2 types of namespace collisions that must be handled.
+
+1) standard functions declared in pal.h, which do not need to be
+ implemented in the PAL because the system's implementation is sufficient.
+
+ (examples : memcpy, strlen, fclose)
+
+ The problem with these is that a prototype for them is provided both in
+ pal.h and in a system header (stdio.h, etc). If a PAL file needs to
+ include the files containing both prototypes, the compiler may complain
+ about the multiple declarations.
+
+ To avoid this, the inclusion of pal.h must be wrapped in a
+ #define/#undef pair, which will effectiveily "hide" the pal.h
+ declaration by renaming it to something else. this is done by palinternal.h
+ in this way :
+
+ #define some_function DUMMY_some_function
+ #include <pal.h>
+ #undef some_function
+
+ when a PAL source file includes palinternal.h, it will see a prototype for
+ DUMMY_some_function instead of some_function; so when it includes the
+ system header with the "real" prototype, no collision occurs.
+
+ (note : technically, no functions should ever be treated this way, all
+ system functions should be wrapped according to method 2, so that call
+ logging through ENTRY macros is done for all functions n the PAL. However
+ this reason alone is not currently considered enough to warrant a wrapper)
+
+2) standard functions which must be reimplemented by the PAL, because the
+ system's implementation does not offer suitable functionnality.
+
+ (examples : widestring functions, networking)
+
+ Here, the problem is more complex. The PAL must provide functions with the
+ same name as system functions. Due to the nature of Unix dynamic linking,
+ if this is done, the PAL's implementation will effectively mask the "real"
+ function, so that all calls are directed to it. This makes it impossible for
+ a function to be implemented as calling its counterpart in the system, plus
+ some extra work, because instead of calling the system's implementation, the
+ function would only call itself in an infinitely recursing nightmare. Even
+ worse, if by bad luck the system libraries attempt to call the function for
+ which the PAL provides an implementation, it is the PAL's version that will
+ be called.
+ It is therefore necessary to give the PAL's implementation of such functions
+ a different name. However, PAL consumers (applications built on top of the
+ PAL) must be able to call the function by its 'official' name, not the PAL's
+ internal name.
+ This can be done with some more macro magic, by #defining the official name
+ to the internal name *in pal.h*. :
+
+ #define some_function PAL_some_function
+
+ This way, while PAL consumer code can use the official name, it is the
+ internal name that wil be seen at compile time.
+ However, one extra step is needed. While PAL consumers must use the PAL's
+ implementation of these functions, the PAL itself must still have access to
+ the "real" functions. This is done by #undefining in palinternal.h the names
+ #defined in pal.h :
+
+ #include <pal.h>
+ #undef some_function.
+
+ At this point, code in the PAL implementation can access *both* its own
+ implementation of the function (with PAL_some_function) *and* the system's
+ implementation (with some_function)
+
+ [side note : for the Win32 PAL, this can be accomplished without touching
+ pal.h. In Windows, symbols in in dynamic libraries are resolved at
+ compile time. if an application that uses some_function is only linked to
+ pal.dll, some_function will be resolved to the version in that DLL,
+ even if other DLLs in the system provide other implementations. In addition,
+ the function in the DLL can actually have a different name (e.g.
+ PAL_some_function), to which the 'official' name is aliased when the DLL
+ is compiled. All this is not possible with Unix dynamic linking, where
+ symbols are resolved at run-time in a first-found-first-used order. A
+ module may end up using the symbols from a module it was never linked with,
+ simply because that module was located somewhere in the dependency chain. ]
+
+ It should be mentionned that even if a function name is not documented as
+ being implemented in the system, it can still cause problems if it exists.
+ This is especially a problem for functions in the "reserved" namespace
+ (names starting with an underscore : _exit, etc). (We shouldn't really be
+ implementing functions with such a name, but we don't really have a choice)
+ If such a case is detected, it should be wrapped according to method 2
+
+ Note that for all this to work, it is important for the PAL's implementation
+ files to #include palinternal.h *before* any system files, and to never
+ include pal.h directly.
+
+B] Procedure for name conflict resolution :
+
+When adding a function to pal.h, which is implemented by the system and
+which does not need a different implementation :
+
+- add a #define function_name DUMMY_function_name to palinternal.h, after all
+ the other DUMMY_ #defines (above the #include <pal.h> line)
+- add the function's prototype to pal.h (if that isn't already done)
+- add a #undef function_name to palinternal.h near all the other #undefs
+ (after the #include <pal.h> line)
+
+When overriding a system function with the PAL's own implementation :
+
+- add a #define function_name PAL_function_name to pal.h, somewhere
+ before the function's prototype, inside a #ifndef _MSCVER/#endif pair
+ (to avoid affecting the Win32 build)
+- add a #undef function_name to palinternal.h near all the other #undefs
+ (after the #include <pal.h> line)
+- implement the function in the pal, naming it PAL_function_name
+- within the PAL, call PAL_function_name() to call the PAL's implementation,
+function_name() to call the system's implementation
+
+
+
+--*/
+
+#ifndef _PAL_INTERNAL_H_
+#define _PAL_INTERNAL_H_
+
+#define PAL_IMPLEMENTATION
+
+/* Include our configuration information so it's always present when
+ compiling PAL implementation files. */
+#include "config.h"
+
+#ifdef DEBUG
+#define _ENABLE_DEBUG_MESSAGES_ 1
+#else
+#define _ENABLE_DEBUG_MESSAGES_ 0
+#endif
+
+#ifdef PAL_PERF
+#include "pal_perf.h"
+#endif
+
+/* C runtime functions needed to be renamed to avoid duplicate definition
+ of those functions when including standard C header files */
+#define div DUMMY_div
+#define div_t DUMMY_div_t
+#if !defined(_DEBUG)
+#define memcpy DUMMY_memcpy
+#endif //!defined(_DEBUG)
+#define memcmp DUMMY_memcmp
+#define memset DUMMY_memset
+#define memmove DUMMY_memmove
+#define memchr DUMMY_memchr
+#define strlen DUMMY_strlen
+#define strnlen DUMMY_strnlen
+#define stricmp DUMMY_stricmp
+#define strstr DUMMY_strstr
+#define strcmp DUMMY_strcmp
+#define strcat DUMMY_strcat
+#define strncat DUMMY_strncat
+#define strcpy DUMMY_strcpy
+#define strcspn DUMMY_strcspn
+#define strncmp DUMMY_strncmp
+#define strncpy DUMMY_strncpy
+#define strchr DUMMY_strchr
+#define strrchr DUMMY_strrchr
+#define strpbrk DUMMY_strpbrk
+#define strtod DUMMY_strtod
+#define strspn DUMMY_strspn
+#if HAVE__SNPRINTF
+#define _snprintf DUMMY__snprintf
+#endif /* HAVE__SNPRINTF */
+#if HAVE__SNWPRINTF
+#define _snwprintf DUMMY__snwprintf
+#endif /* HAVE__SNWPRINTF */
+#define tolower DUMMY_tolower
+#define toupper DUMMY_toupper
+#define islower DUMMY_islower
+#define isupper DUMMY_isupper
+#define isprint DUMMY_isprint
+#define isdigit DUMMY_isdigit
+#define srand DUMMY_srand
+#define atoi DUMMY_atoi
+#define atof DUMMY_atof
+#define tm PAL_tm
+#define size_t DUMMY_size_t
+#define time_t PAL_time_t
+#define va_list DUMMY_va_list
+#define abs DUMMY_abs
+#define llabs DUMMY_llabs
+#define ceil DUMMY_ceil
+#define cos DUMMY_cos
+#define cosh DUMMY_cosh
+#define fabs DUMMY_fabs
+#define floor DUMMY_floor
+#define fmod DUMMY_fmod
+#define modf DUMMY_modf
+#define sin DUMMY_sin
+#define sinh DUMMY_sinh
+#define sqrt DUMMY_sqrt
+#define tan DUMMY_tan
+#define tanh DUMMY_tanh
+#define fabsf DUMMY_fabsf
+#define fmodf DUMMY_fmodf
+#define modff DUMMY_modff
+
+/* RAND_MAX needed to be renamed to avoid duplicate definition when including
+ stdlib.h header files. PAL_RAND_MAX should have the same value as RAND_MAX
+ defined in pal.h */
+#define PAL_RAND_MAX 0x7fff
+
+/* The standard headers define isspace and isxdigit as macros and functions,
+ To avoid redefinition problems, undefine those macros. */
+#ifdef isspace
+#undef isspace
+#endif
+#ifdef isxdigit
+#undef isxdigit
+#endif
+#ifdef isalpha
+#undef isalpha
+#endif
+#ifdef isalnum
+#undef isalnum
+#endif
+#define isspace DUMMY_isspace
+#define isxdigit DUMMY_isxdigit
+#define isalpha DUMMY_isalpha
+#define isalnum DUMMY_isalnum
+
+#ifdef stdin
+#undef stdin
+#endif
+#ifdef stdout
+#undef stdout
+#endif
+#ifdef stderr
+#undef stderr
+#endif
+
+#ifdef SCHAR_MIN
+#undef SCHAR_MIN
+#endif
+#ifdef SCHAR_MAX
+#undef SCHAR_MAX
+#endif
+#ifdef SHRT_MIN
+#undef SHRT_MIN
+#endif
+#ifdef SHRT_MAX
+#undef SHRT_MAX
+#endif
+#ifdef UCHAR_MAX
+#undef UCHAR_MAX
+#endif
+#ifdef USHRT_MAX
+#undef USHRT_MAX
+#endif
+#ifdef ULONG_MAX
+#undef ULONG_MAX
+#endif
+#ifdef LONG_MIN
+#undef LONG_MIN
+#endif
+#ifdef LONG_MAX
+#undef LONG_MAX
+#endif
+#ifdef RAND_MAX
+#undef RAND_MAX
+#endif
+#ifdef DBL_MAX
+#undef DBL_MAX
+#endif
+#ifdef FLT_MAX
+#undef FLT_MAX
+#endif
+#ifdef __record_type_class
+#undef __record_type_class
+#endif
+#ifdef __real_type_class
+#undef __real_type_class
+#endif
+
+// The standard headers define va_start and va_end as macros,
+// To avoid redefinition problems, undefine those macros.
+#ifdef va_start
+#undef va_start
+#endif
+#ifdef va_end
+#undef va_end
+#endif
+#ifdef va_copy
+#undef va_copy
+#endif
+
+
+#ifdef _VAC_
+#define wchar_16 wchar_t
+#else
+#define wchar_t wchar_16
+#endif // _VAC_
+
+#define ptrdiff_t PAL_ptrdiff_t
+#define intptr_t PAL_intptr_t
+#define uintptr_t PAL_uintptr_t
+#define timeval PAL_timeval
+#define FILE PAL_FILE
+
+#include "pal.h"
+#include "palprivate.h"
+
+#include "mbusafecrt.h"
+
+#ifdef _VAC_
+#undef CHAR_BIT
+#undef va_arg
+#endif
+
+#if !defined(_MSC_VER) && defined(FEATURE_PAL) && defined(_WIN64)
+#undef _BitScanForward64
+#endif
+
+/* pal.h defines alloca(3) as a compiler builtin.
+ Redefining it to native libc will result in undefined breakage because
+ a compiler is allowed to make assumptions about the stack and frame
+ pointers. */
+
+/* Undef all functions and types previously defined so those functions and
+ types could be mapped to the C runtime and socket implementation of the
+ native OS */
+#undef exit
+#undef atexit
+#undef div
+#undef div_t
+#if !defined(_DEBUG)
+#undef memcpy
+#endif //!defined(_DEBUG)
+#undef memcmp
+#undef memset
+#undef memmove
+#undef memchr
+#undef strlen
+#undef strnlen
+#undef stricmp
+#undef strstr
+#undef strcmp
+#undef strcat
+#undef strcspn
+#undef strncat
+#undef strcpy
+#undef strncmp
+#undef strncpy
+#undef strchr
+#undef strrchr
+#undef strpbrk
+#undef strtoul
+#undef strtod
+#undef strspn
+#undef strtok
+#undef strdup
+#undef tolower
+#undef toupper
+#undef islower
+#undef isupper
+#undef isprint
+#undef isdigit
+#undef isspace
+#undef iswdigit
+#undef iswxdigit
+#undef iswalpha
+#undef iswprint
+#undef isxdigit
+#undef isalpha
+#undef isalnum
+#undef atoi
+#undef atol
+#undef atof
+#undef malloc
+#undef realloc
+#undef free
+#undef qsort
+#undef bsearch
+#undef time
+#undef tm
+#undef localtime
+#undef mktime
+#undef FILE
+#undef fclose
+#undef setbuf
+#undef fopen
+#undef fread
+#undef feof
+#undef ferror
+#undef ftell
+#undef fflush
+#undef fwrite
+#undef fgets
+#undef fgetws
+#undef fputc
+#undef putchar
+#undef fputs
+#undef fseek
+#undef fgetpos
+#undef fsetpos
+#undef getcwd
+#undef getc
+#undef fgetc
+#undef ungetc
+#undef _flushall
+#undef setvbuf
+#undef mkstemp
+#undef rename
+#undef unlink
+#undef size_t
+#undef time_t
+#undef va_list
+#undef va_start
+#undef va_end
+#undef va_copy
+#undef stdin
+#undef stdout
+#undef stderr
+#undef abs
+#undef labs
+#undef llabs
+#undef acos
+#undef asin
+#undef atan
+#undef atan2
+#undef ceil
+#undef cos
+#undef cosh
+#undef exp
+#undef fabs
+#undef floor
+#undef fmod
+#undef log
+#undef log10
+#undef modf
+#undef pow
+#undef sin
+#undef sinh
+#undef sqrt
+#undef tan
+#undef tanh
+#undef fabsf
+#undef fmodf
+#undef modff
+#undef rand
+#undef srand
+#undef errno
+#undef getenv
+#undef wcsspn
+#undef open
+#undef glob
+
+#undef wchar_t
+#undef ptrdiff_t
+#undef intptr_t
+#undef uintptr_t
+#undef timeval
+
+
+#undef printf
+#undef fprintf
+#undef fwprintf
+#undef vfprintf
+#undef vfwprintf
+#undef vprintf
+#undef wprintf
+#undef sprintf
+#undef swprintf
+#undef _snprintf
+#if HAVE__SNWPRINTF
+#undef _snwprintf
+#endif /* HAVE__SNWPRINTF */
+#undef sscanf
+#undef wcstod
+#undef wcstol
+#undef wcstoul
+#undef _wcstoui64
+#undef wcscat
+#undef wcscpy
+#undef wcslen
+#undef wcsncmp
+#undef wcschr
+#undef wcsrchr
+#undef wsprintf
+#undef swscanf
+#undef wcspbrk
+#undef wcsstr
+#undef wcscmp
+#undef wcsncat
+#undef wcsncpy
+#undef wcstok
+#undef wcscspn
+#undef iswupper
+#undef iswspace
+#undef towlower
+#undef towupper
+#undef vsprintf
+#undef vswprintf
+#undef _vsnprintf
+#undef _vsnwprintf
+#undef vsnprintf
+#undef wvsnprintf
+
+#ifdef _AMD64_
+#undef _mm_getcsr
+#undef _mm_setcsr
+#endif // _AMD64_
+
+#undef ctime
+
+#undef SCHAR_MIN
+#undef SCHAR_MAX
+#undef UCHAR_MAX
+#undef SHRT_MIN
+#undef SHRT_MAX
+#undef USHRT_MAX
+#undef LONG_MIN
+#undef LONG_MAX
+#undef ULONG_MAX
+#undef RAND_MAX
+#undef DBL_MAX
+#undef FLT_MAX
+#undef __record_type_class
+#undef __real_type_class
+
+#if HAVE_CHAR_BIT
+#undef CHAR_BIT
+#endif
+
+// We need a sigsetjmp prototype in pal.h for the SEH macros, but we
+// can't use the "real" prototype (because we don't want to define sigjmp_buf).
+// So we must rename the "real" sigsetjmp to avoid redefinition errors.
+#define sigsetjmp REAL_sigsetjmp
+#define siglongjmp REAL_siglongjmp
+#include <setjmp.h>
+#undef sigsetjmp
+#undef siglongjmp
+
+#undef _SIZE_T_DEFINED
+#undef _WCHAR_T_DEFINED
+
+#define _DONT_USE_CTYPE_INLINE_
+#if HAVE_RUNETYPE_H
+#include <runetype.h>
+#endif
+#include <ctype.h>
+
+// Don't use C++ wrappers for stdlib.h
+// https://gcc.gnu.org/ml/libstdc++/2016-01/msg00025.html
+#define _GLIBCXX_INCLUDE_NEXT_C_HEADERS 1
+
+#define _WITH_GETLINE
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <pwd.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <glob.h>
+
+#ifdef __APPLE__
+
+#undef GetCurrentThread
+#include <CoreServices/CoreServices.h>
+
+#include <malloc/malloc.h>
+
+#endif // __APPLE__
+
+/* we don't really need this header here, but by including it we make sure
+ we'll catch any definition conflicts */
+#include <sys/socket.h>
+
+#if !HAVE_INFTIM
+#define INFTIM -1
+#endif // !HAVE_INFTIM
+
+#if (__GNUC__ >= 4)
+#define OffsetOf(TYPE, MEMBER) __builtin_offsetof(TYPE, MEMBER)
+#else
+#define OffsetOf(s, f) (INT)(SIZE_T)&(((s*)0)->f)
+#endif /* __GNUC__ version check*/
+
+#undef assert
+#define assert (Use__ASSERTE_instead_of_assert) assert
+
+#define PROCESS_PIPE_NAME_PREFIX ".dotnet-pal-processpipe"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif // __cplusplus
+
+typedef enum _TimeConversionConstants
+{
+ tccSecondsToMillieSeconds = 1000, // 10^3
+ tccSecondsToMicroSeconds = 1000000, // 10^6
+ tccSecondsToNanoSeconds = 1000000000, // 10^9
+ tccMillieSecondsToMicroSeconds = 1000, // 10^3
+ tccMillieSecondsToNanoSeconds = 1000000, // 10^6
+ tccMicroSecondsToNanoSeconds = 1000, // 10^3
+ tccSecondsTo100NanoSeconds = 10000000, // 10^7
+ tccMicroSecondsTo100NanoSeconds = 10 // 10^1
+} TimeConversionConstants;
+
+#ifdef __cplusplus
+}
+
+/* This is duplicated in utilcode.h for CLR, with cooler type-traits */
+template <typename T>
+inline
+T* InterlockedExchangePointerT(
+ T* volatile *Target,
+ T* Value)
+{
+ return (T*)(InterlockedExchangePointer(
+ (PVOID volatile*)Target,
+ (PVOID)Value));
+}
+
+template <typename T>
+inline
+T* InterlockedCompareExchangePointerT(
+ T* volatile *destination,
+ T* exchange,
+ T* comparand)
+{
+ return (T*)(InterlockedCompareExchangePointer(
+ (PVOID volatile*)destination,
+ (PVOID)exchange,
+ (PVOID)comparand));
+}
+
+template <typename T>
+inline T* InterlockedExchangePointerT(
+ T* volatile * target,
+ int value) // When NULL is provided as argument.
+{
+ //STATIC_ASSERT(value == 0);
+ return InterlockedExchangePointerT(target, reinterpret_cast<T*>(value));
+}
+
+template <typename T>
+inline T* InterlockedCompareExchangePointerT(
+ T* volatile * destination,
+ int exchange, // When NULL is provided as argument.
+ T* comparand)
+{
+ //STATIC_ASSERT(exchange == 0);
+ return InterlockedCompareExchangePointerT(destination, reinterpret_cast<T*>(exchange), comparand);
+}
+
+template <typename T>
+inline T* InterlockedCompareExchangePointerT(
+ T* volatile * destination,
+ T* exchange,
+ int comparand) // When NULL is provided as argument.
+{
+ //STATIC_ASSERT(comparand == 0);
+ return InterlockedCompareExchangePointerT(destination, exchange, reinterpret_cast<T*>(comparand));
+}
+
+#undef InterlockedExchangePointer
+#define InterlockedExchangePointer InterlockedExchangePointerT
+#undef InterlockedCompareExchangePointer
+#define InterlockedCompareExchangePointer InterlockedCompareExchangePointerT
+
+#include "volatile.h"
+
+const char StackOverflowMessage[] = "Process is terminated due to StackOverflowException.\n";
+
+#endif // __cplusplus
+
+#endif /* _PAL_INTERNAL_H_ */
diff --git a/src/pal/src/include/pal/perftrace.h b/src/pal/src/include/pal/perftrace.h
new file mode 100644
index 0000000000..fec46e2330
--- /dev/null
+++ b/src/pal/src/include/pal/perftrace.h
@@ -0,0 +1,70 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ include/pal/perftrace.h
+
+Abstract:
+ Header file for PAL Performance trace utilities.
+
+
+
+--*/
+
+/*
+Overview of PAL Performance utilities
+
+ */
+
+#ifndef _PAL_PERFTRACE_H_
+#define _PAL_PERFTRACE_H_
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif // __cplusplus
+
+#if PAL_PERF
+#define PERF_ENTRY(x) \
+ ULONGLONG pal_perf_start_tick = 0;\
+ PERFLogFunctionEntry( PAL_PERF_##x, &pal_perf_start_tick )
+#define PERF_EXIT(x) \
+ PERFLogFunctionExit( PAL_PERF_##x, &pal_perf_start_tick )
+#define PERF_ENTRY_ONLY(x) \
+ PERFNoLatencyProfileEntry( PAL_PERF_##x )
+
+BOOL PERFInitialize(LPWSTR command_line, LPWSTR exe_path) ;
+void PERFTerminate( );
+BOOL PERFAllocThreadInfo( );
+void PERFLogFunctionExit(unsigned int pal_api_id, ULONGLONG *pal_perf_start_tick);
+void PERFLogFunctionEntry(unsigned int pal_api_id, ULONGLONG *pal_perf_start_tick);
+void PERFEnableThreadProfile(BOOL isInternal);
+void PERFDisableThreadProfile(BOOL isInternal);
+void PERFEnableProcessProfile( );
+void PERFDisableProcessProfile( );
+BOOL PERFIsProcessProfileEnabled( );
+void PERFNoLatencyProfileEntry(unsigned int pal_api_id );
+void PERFCalibrate(const char* msg);
+
+#else /* PAL_PERF */
+
+#define PERF_ENTRY(x)
+#define PERF_ENTRY_ONLY(x)
+#define PERF_EXIT(x)
+
+#endif /* PAL_PERF */
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif /* _PAL_PERFTRACE_H_ */
+
+
+
diff --git a/src/pal/src/include/pal/printfcpp.hpp b/src/pal/src/include/pal/printfcpp.hpp
new file mode 100644
index 0000000000..0a728c9fd7
--- /dev/null
+++ b/src/pal/src/include/pal/printfcpp.hpp
@@ -0,0 +1,133 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ pal/printfcpp.hpp
+
+Abstract:
+ Declarations for suspension safe memory allocation functions
+
+
+
+--*/
+
+#ifndef _PRINTFCPP_HPP
+#define _PRINTFCPP_HPP
+
+#ifdef __cplusplus
+#include "pal/threadinfo.hpp"
+#endif
+
+#include <stdarg.h>
+
+#ifdef __cplusplus
+typedef char16_t wchar_16; // __wchar_16_cpp (which is defined in palinternal.h) needs to be redefined to wchar_16.
+
+extern "C"
+{
+ int
+ __cdecl
+ PAL__vsnprintf(
+ LPSTR Buffer,
+ size_t Count,
+ LPCSTR Format,
+ va_list ap);
+
+ int
+ __cdecl
+ PAL__wvsnprintf(
+ LPWSTR Buffer,
+ size_t Count,
+ LPCWSTR Format,
+ va_list ap);
+
+ int
+ __cdecl
+ PAL_vfprintf(
+ PAL_FILE *stream,
+ const char *format,
+ va_list ap);
+
+ int
+ __cdecl
+ PAL_vfwprintf(
+ PAL_FILE *stream,
+ const wchar_16 *format,
+ va_list ap);
+}
+
+namespace CorUnix
+{
+ int
+ InternalVfprintf(
+ CPalThread *pthrCurrent,
+ PAL_FILE *stream,
+ const char *format,
+ va_list ap);
+
+ int
+ InternalWvsnprintf(
+ CPalThread *pthrCurrent,
+ LPWSTR Buffer,
+ size_t Count,
+ LPCWSTR Format,
+ va_list ap);
+
+ int
+ InternalVsnprintf(
+ CPalThread *pthrCurrent,
+ LPSTR Buffer,
+ size_t Count,
+ LPCSTR Format,
+ va_list ap);
+
+ int
+ InternalVfwprintf(
+ CPalThread *pthrCurrent,
+ PAL_FILE *stream,
+ const wchar_16 *format,
+ va_list ap);
+
+}
+#else // __cplusplus
+
+ int
+ __cdecl
+ PAL__vsnprintf(
+ LPSTR Buffer,
+ size_t Count,
+ LPCSTR Format,
+ va_list ap);
+
+ int
+ __cdecl
+ PAL__wvsnprintf(
+ LPWSTR Buffer,
+ size_t Count,
+ LPCWSTR Format,
+ va_list ap);
+
+ int
+ __cdecl
+ PAL_vfprintf(
+ PAL_FILE *stream,
+ const char *format,
+ va_list ap);
+
+ int
+ __cdecl
+ PAL_vfwprintf(
+ PAL_FILE *stream,
+ const wchar_16 *format,
+ va_list ap);
+
+#endif // __cplusplus
+
+#endif // _PRINTFCPP_HPP
+
diff --git a/src/pal/src/include/pal/process.h b/src/pal/src/include/pal/process.h
new file mode 100644
index 0000000000..990aec5b21
--- /dev/null
+++ b/src/pal/src/include/pal/process.h
@@ -0,0 +1,162 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ include/pal/process.h
+
+Abstract:
+
+ Miscellaneous process related functions.
+
+Revision History:
+
+
+
+--*/
+
+#ifndef _PAL_PROCESS_H_
+#define _PAL_PROCESS_H_
+
+#include "pal/palinternal.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif // __cplusplus
+
+/* thread ID of thread that has initiated an ExitProcess (or TerminateProcess).
+ this is to make sure only one thread cleans up the PAL, and also to prevent
+ calls to CreateThread from succeeding once shutdown has started
+ [defined in process.c]
+*/
+extern Volatile<LONG> terminator;
+
+// The process and session ID of this process, so we can avoid excessive calls to getpid() and getsid().
+extern DWORD gPID;
+extern DWORD gSID;
+
+extern LPWSTR pAppDir;
+
+/*++
+Function:
+ PROCGetProcessIDFromHandle
+
+Abstract
+ Return the process ID from a process handle
+--*/
+DWORD PROCGetProcessIDFromHandle(HANDLE hProcess);
+
+/*++
+Function:
+ PROCCreateInitialProcess
+
+Abstract
+ Initialize all the structures for the initial process.
+
+Parameter
+ lpwstrCmdLine: Command line.
+ lpwstrFullPath : Full path to executable
+
+Return
+ TRUE: if successful
+ FALSE: otherwise
+
+Notes :
+ This function takes ownership of lpwstrCmdLine, but not of lpwstrFullPath
+--*/
+BOOL PROCCreateInitialProcess(LPWSTR lpwstrCmdLine, LPWSTR lpwstrFullPath);
+
+/*++
+Function:
+ PROCCleanupInitialProcess
+
+Abstract
+ Cleanup all the structures for the initial process.
+
+Parameter
+ VOID
+
+Return
+ VOID
+
+--*/
+VOID PROCCleanupInitialProcess(VOID);
+
+#if USE_SYSV_SEMAPHORES
+/*++
+Function:
+ PROCCleanupThreadSemIds(VOID);
+
+Abstract
+ Cleanup SysV semaphore ids for all threads.
+
+(no parameters, no return value)
+--*/
+VOID PROCCleanupThreadSemIds(VOID);
+#endif
+
+/*++
+Function:
+ PROCProcessLock
+
+Abstract
+ Enter the critical section associated to the current process
+--*/
+VOID PROCProcessLock(VOID);
+
+
+/*++
+Function:
+ PROCProcessUnlock
+
+Abstract
+ Leave the critical section associated to the current process
+--*/
+VOID PROCProcessUnlock(VOID);
+
+/*++
+Function:
+ PROCAbort()
+
+ Aborts the process after calling the shutdown cleanup handler. This function
+ should be called instead of calling abort() directly.
+
+ Does not return
+--*/
+PAL_NORETURN
+void PROCAbort();
+
+/*++
+Function:
+ PROCNotifyProcessShutdown
+
+ Calls the abort handler to do any shutdown cleanup. Call be
+ called from the unhandled native exception handler.
+
+(no return value)
+--*/
+void PROCNotifyProcessShutdown();
+
+/*++
+Function:
+ InitializeFlushProcessWriteBuffers
+
+Abstract
+ This function initializes data structures needed for the FlushProcessWriteBuffers
+Return
+ TRUE if it succeeded, FALSE otherwise
+--*/
+BOOL InitializeFlushProcessWriteBuffers();
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif //PAL_PROCESS_H_
+
diff --git a/src/pal/src/include/pal/procobj.hpp b/src/pal/src/include/pal/procobj.hpp
new file mode 100644
index 0000000000..a75c764246
--- /dev/null
+++ b/src/pal/src/include/pal/procobj.hpp
@@ -0,0 +1,125 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ include/pal/procobj.hpp
+
+Abstract:
+ Header file for process structures
+
+
+
+--*/
+
+#ifndef _PAL_PROCOBJ_HPP_
+#define _PAL_PROCOBJ_HPP_
+
+#include "corunix.hpp"
+
+namespace CorUnix
+{
+ extern CObjectType otProcess;
+
+ typedef enum
+ {
+ PS_IDLE,
+ PS_STARTING,
+ PS_RUNNING,
+ PS_DONE
+ } PROCESS_STATE;
+
+ //
+ // Struct for process module list (EnumProcessModules)
+ //
+ struct ProcessModules
+ {
+ ProcessModules *Next;
+ PVOID BaseAddress;
+ CHAR Name[0];
+ };
+
+ //
+ // Ideally dwProcessId would be part of the process object's immutable
+ // data. Doing so, though, creates complications in CreateProcess. The
+ // contents of the immutable data for a new object must be set before
+ // that object is registered with the object manager (as the object
+ // manager may make a copy of the immutable data). The PID for a new
+ // process, though, is not known until after creation. Registering the
+ // process object after process creation creates an undesirable error path
+ // -- if we are not able to register the process object (say, because of
+ // a low resource condition) we would be forced to return an error to
+ // the caller of CreateProcess, even though the new process was actually
+ // created...
+ //
+ // Note: we could work around this by effectively always going down
+ // the create suspended path. That is, the new process would not exec until
+ // the parent process released it. It's unclear how much benefit this would
+ // provide us.
+ //
+
+ class CProcProcessLocalData
+ {
+ public:
+ CProcProcessLocalData()
+ :
+ dwProcessId(0),
+ ps(PS_IDLE),
+ dwExitCode(0),
+ lAttachCount(0),
+ pProcessModules(NULL),
+ cProcessModules(0)
+ {
+ };
+
+ ~CProcProcessLocalData();
+
+ DWORD dwProcessId;
+ PROCESS_STATE ps;
+ DWORD dwExitCode;
+ LONG lAttachCount;
+ ProcessModules *pProcessModules;
+ DWORD cProcessModules;
+ };
+
+ PAL_ERROR
+ InternalCreateProcess(
+ CPalThread *pThread,
+ LPCWSTR lpApplicationName,
+ LPWSTR lpCommandLine,
+ LPSECURITY_ATTRIBUTES lpProcessAttributes,
+ LPSECURITY_ATTRIBUTES lpThreadAttributes,
+ BOOL bInheritHandles,
+ DWORD dwCreationFlags,
+ LPVOID lpEnvironment,
+ LPCWSTR lpCurrentDirectory,
+ LPSTARTUPINFOW lpStartupInfo,
+ LPPROCESS_INFORMATION lpProcessInformation
+ );
+
+ PAL_ERROR
+ InitializeProcessData(
+ void
+ );
+
+ PAL_ERROR
+ InitializeProcessCommandLine(
+ LPWSTR lpwstrCmdLine,
+ LPWSTR lpwstrFullPath
+ );
+
+ PAL_ERROR
+ CreateInitialProcessAndThreadObjects(
+ CPalThread *pThread
+ );
+
+ extern IPalObject *g_pobjProcess;
+}
+
+#endif // _PAL_PROCOBJ_HPP_
+
diff --git a/src/pal/src/include/pal/seh.hpp b/src/pal/src/include/pal/seh.hpp
new file mode 100644
index 0000000000..3ac93d655a
--- /dev/null
+++ b/src/pal/src/include/pal/seh.hpp
@@ -0,0 +1,185 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ include/pal/seh.hpp
+
+Abstract:
+ Header file for public Structured Exception Handling stuff
+
+
+
+--*/
+
+#ifndef _PAL_SEH_HPP_
+#define _PAL_SEH_HPP_
+
+#include "config.h"
+#include "pal/palinternal.h"
+#include "pal/corunix.hpp"
+
+// Uncomment this define to turn off the signal handling thread.
+// #define DO_NOT_USE_SIGNAL_HANDLING_THREAD
+
+/*++
+Function :
+ SEHInitialize
+
+ Initialize all SEH-related stuff (signals, etc)
+
+Parameters:
+ CPalThread * pthrCurrent : reference to the current thread.
+ flags : PAL initialize flags
+
+Return value:
+ TRUE if SEH support initialization succeeded,
+ FALSE otherwise
+
+--*/
+BOOL
+SEHInitialize(CorUnix::CPalThread *pthrCurrent, DWORD flags);
+
+/*++
+Function :
+ SEHCleanup
+
+ Clean up SEH-related stuff(signals, etc)
+
+Parameters:
+ None
+
+ (no return value)
+--*/
+VOID
+SEHCleanup();
+
+/*++
+Function:
+ SEHProcessException
+
+ Send the PAL exception to any handler registered.
+
+Parameters:
+ PAL_SEHException* exception
+
+Return value:
+ Returns TRUE if the exception happened in managed code and the execution should
+ continue (with possibly modified context).
+ Returns FALSE if the exception happened in managed code and it was not handled.
+ In case the exception was handled by calling a catch handler, it doesn't return at all.
+--*/
+BOOL
+SEHProcessException(PAL_SEHException* exception);
+
+/*++
+Function:
+ AllocateExceptionRecords
+
+Parameters:
+ exceptionRecord - output pointer to the allocated Windows exception record
+ contextRecord - output pointer to the allocated Windows context record
+--*/
+VOID
+AllocateExceptionRecords(EXCEPTION_RECORD** exceptionRecord, CONTEXT** contextRecord);
+
+#if !HAVE_MACH_EXCEPTIONS
+// TODO: Implement for Mach exceptions. Not in CoreCLR surface area.
+/*++
+Function :
+ SEHHandleControlEvent
+
+ handle Control-C and Control-Break events (call handler routines,
+ notify debugger)
+
+Parameters :
+ DWORD event : event that occurred
+ LPVOID eip : instruction pointer when exception occurred
+
+(no return value)
+
+Notes :
+ Handlers are called on a last-installed, first called basis, until a
+ handler returns TRUE. If no handler returns TRUE (or no hanlder is
+ installed), the default behavior is to call ExitProcess
+--*/
+void SEHHandleControlEvent(DWORD event, LPVOID eip);
+#endif // !HAVE_MACH_EXCEPTIONS
+
+#if !HAVE_MACH_EXCEPTIONS
+/*++
+Function :
+ SEHSetSafeState
+
+ specify whether the current thread is in a state where exception handling
+ of signals can be done safely
+
+Parameters:
+ CPalThread * pthrCurrent : reference to the current thread.
+ BOOL state : TRUE if the thread is safe, FALSE otherwise
+
+(no return value)
+--*/
+void SEHSetSafeState(CorUnix::CPalThread *pthrCurrent, BOOL state);
+
+/*++
+Function :
+ SEHGetSafeState
+
+ determine whether the current thread is in a state where exception handling
+ of signals can be done safely
+
+Parameters:
+ CPalThread * pthrCurrent : reference to the current thread.
+
+Return value :
+ TRUE if the thread is in a safe state, FALSE otherwise
+--*/
+BOOL SEHGetSafeState(CorUnix::CPalThread *pthrCurrent);
+#endif // !HAVE_MACH_EXCEPTIONS
+
+extern "C"
+{
+
+#ifdef FEATURE_PAL_SXS
+/*++
+Function :
+ SEHEnable
+
+ Enable SEH-related stuff on this thread
+
+Parameters:
+ CPalThread * pthrCurrent : reference to the current thread.
+
+Return value :
+ ERROR_SUCCESS, if enabling succeeded
+ an error code, otherwise
+--*/
+CorUnix::PAL_ERROR SEHEnable(CorUnix::CPalThread *pthrCurrent);
+
+/*++
+Function :
+ SEHDisable
+
+ Disable SEH-related stuff on this thread
+
+Parameters:
+ CPalThread * pthrCurrent : reference to the current thread.
+
+Return value :
+ ERROR_SUCCESS, if enabling succeeded
+ an error code, otherwise
+--*/
+CorUnix::PAL_ERROR SEHDisable(CorUnix::CPalThread *pthrCurrent);
+
+#endif // FEATURE_PAL_SXS
+
+}
+
+#endif /* _PAL_SEH_HPP_ */
+
diff --git a/src/pal/src/include/pal/semaphore.hpp b/src/pal/src/include/pal/semaphore.hpp
new file mode 100644
index 0000000000..2943d61c3d
--- /dev/null
+++ b/src/pal/src/include/pal/semaphore.hpp
@@ -0,0 +1,74 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ semaphore.hpp
+
+Abstract:
+
+ Semaphore object structure definition.
+
+
+
+--*/
+
+#ifndef _PAL_SEMAPHORE_H_
+#define _PAL_SEMAPHORE_H_
+
+#include "corunix.hpp"
+
+namespace CorUnix
+{
+ extern CObjectType otSemaphore;
+
+ typedef struct
+ {
+ LONG lMaximumCount;
+ } SemaphoreImmutableData;
+
+ PAL_ERROR
+ InternalCreateSemaphore(
+ CPalThread *pThread,
+ LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,
+ LONG lInitialCount,
+ LONG lMaximumCount,
+ LPCWSTR lpName,
+ HANDLE *phSemaphore
+ );
+
+ PAL_ERROR
+ InternalReleaseSemaphore(
+ CPalThread *pThread,
+ HANDLE hSemaphore,
+ LONG lReleaseCount,
+ LPLONG lpPreviousCount
+ );
+
+ PAL_ERROR
+ InternalOpenSemaphore(
+ CPalThread *pThread,
+ DWORD dwDesiredAccess,
+ BOOL bInheritHandle,
+ LPCWSTR lpName,
+ HANDLE *phSemaphore
+ );
+
+}
+
+#endif //_PAL_SEMAPHORE_H_
+
+
+
+
+
+
+
+
+
+
diff --git a/src/pal/src/include/pal/sharedmemory.h b/src/pal/src/include/pal/sharedmemory.h
new file mode 100644
index 0000000000..45cc4b2c8d
--- /dev/null
+++ b/src/pal/src/include/pal/sharedmemory.h
@@ -0,0 +1,268 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#ifndef _PAL_SHARED_MEMORY_H_
+#define _PAL_SHARED_MEMORY_H_
+
+#include "corunix.hpp"
+
+#ifndef static_assert_no_msg
+#define static_assert_no_msg( cond ) static_assert( cond, #cond )
+#endif // !static_assert_no_msg
+
+#ifndef _countof
+#define _countof(a) (sizeof(a) / sizeof(a[0]))
+#endif // !_countof
+
+// - Global shared memory files go in:
+// /tmp/.dotnet/shm/global/<fileName>
+// - Session-scoped shared memory files go in:
+// /tmp/.dotnet/shm/session<sessionId>/<fileName>
+// - Lock files associated with global shared memory files go in:
+// /tmp/.dotnet/lockfiles/global/<fileName>
+// - Lock files associated with session-scoped shared memory files go in:
+// /tmp/.dotnet/lockfiles/session<sessionId>/<fileName>
+
+#define SHARED_MEMORY_MAX_FILE_NAME_CHAR_COUNT (_MAX_FNAME - 1)
+#define SHARED_MEMORY_MAX_NAME_CHAR_COUNT (_countof("Global\\") - 1 + SHARED_MEMORY_MAX_FILE_NAME_CHAR_COUNT)
+
+#define SHARED_MEMORY_TEMP_DIRECTORY_PATH "/tmp"
+#define SHARED_MEMORY_RUNTIME_TEMP_DIRECTORY_PATH "/tmp/.dotnet"
+
+#define SHARED_MEMORY_SHARED_MEMORY_DIRECTORY_PATH "/tmp/.dotnet/shm"
+#define SHARED_MEMORY_LOCK_FILES_DIRECTORY_PATH "/tmp/.dotnet/lockfiles"
+static_assert_no_msg(_countof(SHARED_MEMORY_LOCK_FILES_DIRECTORY_PATH) >= _countof(SHARED_MEMORY_SHARED_MEMORY_DIRECTORY_PATH));
+
+#define SHARED_MEMORY_GLOBAL_DIRECTORY_NAME "global"
+#define SHARED_MEMORY_SESSION_DIRECTORY_NAME_PREFIX "session"
+static_assert_no_msg(_countof(SHARED_MEMORY_SESSION_DIRECTORY_NAME_PREFIX) >= _countof(SHARED_MEMORY_GLOBAL_DIRECTORY_NAME));
+
+#define SHARED_MEMORY_UNIQUE_TEMP_NAME_TEMPLATE "/tmp/.coreclr.XXXXXX"
+
+#define SHARED_MEMORY_MAX_SESSION_ID_CHAR_COUNT (10)
+
+#define SHARED_MEMORY_MAX_FILE_PATH_CHAR_COUNT \
+ ( \
+ _countof(SHARED_MEMORY_LOCK_FILES_DIRECTORY_PATH) - 1 + \
+ 1 /* path separator */ + \
+ _countof(SHARED_MEMORY_SESSION_DIRECTORY_NAME_PREFIX) - 1 + \
+ SHARED_MEMORY_MAX_SESSION_ID_CHAR_COUNT + \
+ 1 /* path separator */ + \
+ SHARED_MEMORY_MAX_FILE_NAME_CHAR_COUNT \
+ )
+static_assert_no_msg(SHARED_MEMORY_MAX_FILE_PATH_CHAR_COUNT + 1 /* null terminator */ <= MAX_LONGPATH);
+
+class AutoFreeBuffer
+{
+private:
+ void *m_buffer;
+ bool m_cancel;
+
+public:
+ AutoFreeBuffer(void *buffer);
+ ~AutoFreeBuffer();
+
+public:
+ void Cancel();
+};
+
+enum class SharedMemoryError : DWORD
+{
+ NameEmpty = ERROR_INVALID_PARAMETER,
+ NameTooLong = ERROR_FILENAME_EXCED_RANGE,
+ NameInvalid = ERROR_INVALID_NAME,
+ HeaderMismatch = ERROR_INVALID_HANDLE,
+ OutOfMemory = ERROR_NOT_ENOUGH_MEMORY,
+ IO = ERROR_OPEN_FAILED
+};
+
+class SharedMemoryException
+{
+private:
+ DWORD m_errorCode;
+
+public:
+ SharedMemoryException(DWORD errorCode);
+ DWORD GetErrorCode() const;
+};
+
+class SharedMemoryHelpers
+{
+private:
+ static const mode_t PermissionsMask_AllUsers_ReadWrite;
+ static const mode_t PermissionsMask_AllUsers_ReadWriteExecute;
+public:
+ static const UINT32 InvalidProcessId;
+ static const SIZE_T InvalidThreadId;
+ static const UINT64 InvalidSharedThreadId;
+
+public:
+ static SIZE_T AlignDown(SIZE_T value, SIZE_T alignment);
+ static SIZE_T AlignUp(SIZE_T value, SIZE_T alignment);
+
+ static void *Alloc(SIZE_T byteCount);
+
+ template<SIZE_T DestinationByteCount, SIZE_T SourceByteCount> static SIZE_T CopyString(char (&destination)[DestinationByteCount], SIZE_T destinationStartOffset, const char (&source)[SourceByteCount]);
+ template<SIZE_T DestinationByteCount> static SIZE_T CopyString(char (&destination)[DestinationByteCount], SIZE_T destinationStartOffset, LPCSTR source, SIZE_T sourceCharCount);
+ template<SIZE_T DestinationByteCount> static SIZE_T AppendUInt32String(char (&destination)[DestinationByteCount], SIZE_T destinationStartOffset, UINT32 value);
+
+ static bool EnsureDirectoryExists(const char *path, bool isGlobalLockAcquired, bool createIfNotExist = true);
+private:
+ static int Open(LPCSTR path, int flags, mode_t mode = static_cast<mode_t>(0));
+public:
+ static int OpenDirectory(LPCSTR path);
+ static int CreateOrOpenFile(LPCSTR path, bool createIfNotExist = true, bool *createdRef = nullptr);
+ static void CloseFile(int fileDescriptor);
+
+ static SIZE_T GetFileSize(int fileDescriptor);
+ static void SetFileSize(int fileDescriptor, SIZE_T byteCount);
+
+ static void *MemoryMapFile(int fileDescriptor, SIZE_T byteCount);
+
+ static bool TryAcquireFileLock(int fileDescriptor, int operation);
+ static void ReleaseFileLock(int fileDescriptor);
+};
+
+class SharedMemoryId
+{
+private:
+ LPCSTR m_name;
+ SIZE_T m_nameCharCount;
+ bool m_isSessionScope; // false indicates global scope
+
+public:
+ SharedMemoryId();
+ SharedMemoryId(LPCSTR name, SIZE_T nameCharCount, bool isSessionScope);
+ SharedMemoryId(LPCSTR name);
+
+public:
+ LPCSTR GetName() const;
+ SIZE_T GetNameCharCount() const;
+ bool IsSessionScope() const;
+ bool Equals(SharedMemoryId *other) const;
+
+public:
+ SIZE_T AppendSessionDirectoryName(char (&path)[SHARED_MEMORY_MAX_FILE_PATH_CHAR_COUNT + 1], SIZE_T pathCharCount) const;
+};
+
+enum class SharedMemoryType : UINT8
+{
+ Mutex
+};
+
+class SharedMemorySharedDataHeader
+{
+private:
+ union
+ {
+ struct
+ {
+ SharedMemoryType m_type;
+ UINT8 m_version;
+ };
+ UINT64 _raw; // use the same size for the header on all archs, and align the data to a pointer
+ };
+
+public:
+ static SIZE_T DetermineTotalByteCount(SIZE_T dataByteCount);
+
+public:
+ SharedMemorySharedDataHeader(SharedMemoryType type, UINT8 version);
+
+public:
+ SharedMemoryType GetType() const;
+ UINT8 GetVersion() const;
+ void *GetData();
+};
+
+class SharedMemoryProcessDataBase
+{
+public:
+ virtual void Close(bool isAbruptShutdown, bool releaseSharedData)
+ {
+ }
+
+ virtual ~SharedMemoryProcessDataBase()
+ {
+ }
+};
+
+class SharedMemoryProcessDataHeader
+{
+private:
+ SIZE_T m_refCount;
+ SharedMemoryId m_id;
+ SharedMemoryProcessDataBase *m_data;
+ int m_fileDescriptor;
+ SharedMemorySharedDataHeader *m_sharedDataHeader;
+ SIZE_T m_sharedDataTotalByteCount;
+ SharedMemoryProcessDataHeader *m_nextInProcessDataHeaderList;
+
+public:
+ static SharedMemoryProcessDataHeader *CreateOrOpen(LPCSTR name, SharedMemorySharedDataHeader requiredSharedDataHeader, SIZE_T sharedDataByteCount, bool createIfNotExist, bool *createdRef);
+
+public:
+ static SharedMemoryProcessDataHeader *PalObject_GetProcessDataHeader(CorUnix::IPalObject *object);
+ static void PalObject_SetProcessDataHeader(CorUnix::IPalObject *object, SharedMemoryProcessDataHeader *processDataHeader);
+ static void PalObject_Close(CorUnix::CPalThread *thread, CorUnix::IPalObject *object, bool isShuttingDown, bool cleanUpPalSharedState);
+
+private:
+ SharedMemoryProcessDataHeader(SharedMemoryId *id, int fileDescriptor, SharedMemorySharedDataHeader *sharedDataHeader, SIZE_T sharedDataTotalByteCount);
+public:
+ static SharedMemoryProcessDataHeader *New(SharedMemoryId *id, int fileDescriptor, SharedMemorySharedDataHeader *sharedDataHeader, SIZE_T sharedDataTotalByteCount);
+ ~SharedMemoryProcessDataHeader();
+ void Close();
+
+public:
+ SharedMemoryId *GetId();
+ SharedMemoryProcessDataBase *GetData() const;
+ void SetData(SharedMemoryProcessDataBase *data);
+ SharedMemorySharedDataHeader *GetSharedDataHeader() const;
+ SIZE_T GetSharedDataTotalByteCount() const;
+ SharedMemoryProcessDataHeader *GetNextInProcessDataHeaderList() const;
+ void SetNextInProcessDataHeaderList(SharedMemoryProcessDataHeader *next);
+
+public:
+ void IncRefCount();
+ void DecRefCount();
+};
+
+class SharedMemoryManager
+{
+private:
+ static CRITICAL_SECTION s_creationDeletionProcessLock;
+ static int s_creationDeletionLockFileDescriptor;
+
+private:
+ static SharedMemoryProcessDataHeader *s_processDataHeaderListHead;
+
+#ifdef _DEBUG
+private:
+ static SIZE_T s_creationDeletionProcessLockOwnerThreadId;
+ static SIZE_T s_creationDeletionFileLockOwnerThreadId;
+#endif // _DEBUG
+
+public:
+ static void StaticInitialize();
+ static void StaticClose();
+
+public:
+ static void AcquireCreationDeletionProcessLock();
+ static void ReleaseCreationDeletionProcessLock();
+ static void AcquireCreationDeletionFileLock();
+ static void ReleaseCreationDeletionFileLock();
+
+#ifdef _DEBUG
+public:
+ static bool IsCreationDeletionProcessLockAcquired();
+ static bool IsCreationDeletionFileLockAcquired();
+#endif // _DEBUG
+
+public:
+ static void AddProcessDataHeader(SharedMemoryProcessDataHeader *processDataHeader);
+ static void RemoveProcessDataHeader(SharedMemoryProcessDataHeader *processDataHeader);
+ static SharedMemoryProcessDataHeader *FindProcessDataHeader(SharedMemoryId *id);
+};
+
+#endif // !_PAL_SHARED_MEMORY_H_
diff --git a/src/pal/src/include/pal/sharedmemory.inl b/src/pal/src/include/pal/sharedmemory.inl
new file mode 100644
index 0000000000..69b8704b65
--- /dev/null
+++ b/src/pal/src/include/pal/sharedmemory.inl
@@ -0,0 +1,53 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#ifndef _PAL_SHARED_MEMORY_INL_
+#define _PAL_SHARED_MEMORY_INL_
+
+#include "sharedmemory.h"
+
+#include "dbgmsg.h"
+
+#include <string.h>
+
+template<SIZE_T DestinationByteCount, SIZE_T SourceByteCount>
+SIZE_T SharedMemoryHelpers::CopyString(
+ char (&destination)[DestinationByteCount],
+ SIZE_T destinationStartOffset,
+ const char(&source)[SourceByteCount])
+{
+ return CopyString(destination, destinationStartOffset, source, SourceByteCount - 1);
+}
+
+template<SIZE_T DestinationByteCount>
+SIZE_T SharedMemoryHelpers::CopyString(
+ char (&destination)[DestinationByteCount],
+ SIZE_T destinationStartOffset,
+ LPCSTR source,
+ SIZE_T sourceCharCount)
+{
+ _ASSERTE(destinationStartOffset < DestinationByteCount);
+ _ASSERTE(sourceCharCount < DestinationByteCount - destinationStartOffset);
+ _ASSERTE(strlen(source) == sourceCharCount);
+
+ memcpy_s(&destination[destinationStartOffset], DestinationByteCount - destinationStartOffset, source, sourceCharCount + 1);
+ return destinationStartOffset + sourceCharCount;
+}
+
+template<SIZE_T DestinationByteCount>
+SIZE_T SharedMemoryHelpers::AppendUInt32String(
+ char (&destination)[DestinationByteCount],
+ SIZE_T destinationStartOffset,
+ UINT32 value)
+{
+ _ASSERTE(destination != nullptr);
+ _ASSERTE(destinationStartOffset < DestinationByteCount);
+
+ int valueCharCount =
+ sprintf_s(&destination[destinationStartOffset], DestinationByteCount - destinationStartOffset, "%u", value);
+ _ASSERTE(valueCharCount > 0);
+ return destinationStartOffset + valueCharCount;
+}
+
+#endif // !_PAL_SHARED_MEMORY_INL_
diff --git a/src/pal/src/include/pal/shm.hpp b/src/pal/src/include/pal/shm.hpp
new file mode 100644
index 0000000000..de1d09e636
--- /dev/null
+++ b/src/pal/src/include/pal/shm.hpp
@@ -0,0 +1,83 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ include/pal/shm.hpp
+
+Abstract:
+ C++ typesafe accessors for shared memory routines
+
+
+
+--*/
+
+#ifndef _SHM_HPP_
+#define _SHM_HPP_
+
+#include "shmemory.h"
+
+//
+// Some compilers (e.g., HPUX/IA64) warn about using NULL to initialize
+// something of type SHMPTR, since SHMPTR is defined as DWORD_PTR, which
+// isn't considered a pointer type...
+//
+
+#define SHMNULL 0
+
+#ifndef _DEBUG
+
+inline
+void *
+ShmPtrToPtrFast(SHMPTR shmptr)
+{
+ void *pv = NULL;
+
+ if (SHMNULL != shmptr)
+ {
+ int segment = shmptr >> 24;
+
+ if (segment < shm_numsegments)
+ {
+ pv = reinterpret_cast<void*>(
+ reinterpret_cast<DWORD_PTR>(shm_segment_bases[(uint)segment].Load())
+ + (shmptr & 0x00FFFFFF)
+ );
+ }
+ else
+ {
+ pv = SHMPtrToPtr(shmptr);
+ }
+ }
+
+ return pv;
+}
+
+//
+// We could use a function template here to avoid the cast / macro
+//
+
+#define SHMPTR_TO_TYPED_PTR(type, shmptr) reinterpret_cast<type*>(ShmPtrToPtrFast((shmptr)))
+
+#else
+
+#define SHMPTR_TO_TYPED_PTR(type, shmptr) reinterpret_cast<type*>(SHMPtrToPtr((shmptr)))
+
+#endif
+
+/* Set ptr to NULL if shmPtr == 0, else set ptr to SHMPTR_TO_TYPED_PTR(type, shmptr)
+ return FALSE if SHMPTR_TO_TYPED_PTR returns NULL ptr from non null shmptr,
+ TRUE otherwise */
+#define SHMPTR_TO_TYPED_PTR_BOOL(type, ptr, shmptr) \
+ ((shmptr != 0) ? ((ptr = SHMPTR_TO_TYPED_PTR(type, shmptr)) != NULL) : ((ptr = NULL) == NULL))
+
+
+
+
+#endif // _SHM_HPP_
+
diff --git a/src/pal/src/include/pal/shmemory.h b/src/pal/src/include/pal/shmemory.h
new file mode 100644
index 0000000000..5ca848148c
--- /dev/null
+++ b/src/pal/src/include/pal/shmemory.h
@@ -0,0 +1,331 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ include/pal/shmemory.h
+
+Abstract:
+ Header file for interface to shared memory
+
+How to use :
+
+The SHMalloc function can be used to allocate memory in the shared memory area.
+It returns a value of type SHMPTR, which will be useable in all participating
+processes. The SHMPTR_TO_PTR macro can be used to convert a SHMPTR value into
+an address valid *only* within the current process. Do NOT store pointers in
+shared memory, since those will not be valid for other processes. If you need
+to construct linked lists or other strctures that usually use pointers, use
+SHMPTR values instead of pointers. In addition, Lock/Release functions must be
+used when manipulating data in shared memory, to ensure inter-process synchronization.
+
+Example :
+
+//a simple linked list type
+typedef struct
+{
+int count;
+SHMPTR string;
+SHMPTR next;
+}SHMLIST;
+
+// Allocate a new list item
+SHMPTR new_item = SHMalloc(sizeof(SHMLIST));
+
+// get a pointer to it
+SHMLIST *item_ptr = (SHMLIST *)SHMPTR_TO_PTR(new_item);
+
+// Allocate memory for the "string" member, initialize it
+item_ptr->string = SHMalloc(strlen("string"));
+LPSTR str_ptr = (LPSTR)SHMPTR_TO_PTR(item_ptr->string);
+strcpy(str_ptr, "string");
+
+//Take the shared memory lock to prevent anyone from modifying the linked list
+SHMLock();
+
+//get the list's head from somewhere
+SHMPTR list_head = get_list_head();
+
+//link the list to our new item
+item_ptr->next = list_head
+
+//get a pointer to the list head's structure
+SHMLIST *head_ptr = (SHMLIST *)SHMPTR_TO_PTR(list_head);
+
+//set the new item's count value based on the head's count value
+item_ptr->count = head_ptr->count + 1;
+
+//save the new item as the new head of the list
+set_list_head(new_item);
+
+//We're done modifying the list, release the lock
+SHMRelease
+
+
+
+--*/
+
+#ifndef _PAL_SHMEMORY_H_
+#define _PAL_SHMEMORY_H_
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif // __cplusplus
+
+/*
+Type for shared memory blocks. use SHMPTR_TO_PTR to get a useable address.
+ */
+typedef DWORD_PTR SHMPTR;
+
+#define MAX_SEGMENTS 256
+
+
+typedef enum {
+ SIID_PROCESS_INFO,/* pointers to PROCESS structures? */
+ SIID_NAMED_OBJECTS,
+ SIID_FILE_LOCKS,
+
+ SIID_LAST
+} SHM_INFO_ID;
+
+typedef enum
+{
+ SHM_NAMED_MAPPINGS, /* structs with map name, file name & flags? */
+ SHM_NAMED_EVENTS, /* structs with event names & ThreadWaitingList struct? */
+ SHM_NAMED_MUTEXS, /* structs with mutext names, and ThreadWaitingList struct */
+
+ SHM_NAMED_LAST
+} SHM_NAMED_OBJECTS_ID;
+
+typedef struct _SMNO
+{
+ SHM_NAMED_OBJECTS_ID ObjectType;
+ SHMPTR ShmNext;
+ SHMPTR ShmObjectName;
+ SHMPTR ShmSelf;
+
+}SHM_NAMED_OBJECTS, * PSHM_NAMED_OBJECTS;
+
+
+/*
+SHMPTR_TO_PTR
+
+Macro to convert a SHMPTR value into a valid (for this process) pointer.
+
+In debug builds, we always call the function to do full checks.
+In release builds, check if the segment is known, and if it is, do only minimal
+validation (if segment is unknown, we have to call the function)
+ */
+#if _DEBUG
+
+#define SHMPTR_TO_PTR(shmptr) \
+ SHMPtrToPtr(shmptr)
+
+#else /* !_DEBUG */
+
+extern int shm_numsegments;
+
+/* array containing the base address of each segment */
+extern Volatile<LPVOID> shm_segment_bases[MAX_SEGMENTS];
+
+#define SHMPTR_TO_PTR(shmptr)\
+ ((shmptr)?(((static_cast<int>(shmptr)>>24)<shm_numsegments)?\
+ reinterpret_cast<LPVOID>(reinterpret_cast<size_t>(shm_segment_bases[static_cast<int>(shmptr)>>24].Load())+(static_cast<int>(shmptr)&0x00FFFFFF)):\
+ SHMPtrToPtr(shmptr)): static_cast<LPVOID>(NULL))
+
+
+#endif /* _DEBUG */
+
+/* Set ptr to NULL if shmPtr == 0, else set ptr to SHMPTR_TO_PTR(shmptr)
+ return FALSE if SHMPTR_TO_PTR returns NULL ptr from non null shmptr,
+ TRUE otherwise */
+#define SHMPTR_TO_PTR_BOOL(ptr, shmptr) \
+ ((shmptr != 0) ? ((ptr = SHMPTR_TO_PTR(shmptr)) != NULL) : ((ptr = NULL) == NULL))
+
+/*++
+SHMPtrToPtr
+
+Convert a SHMPTR value into a useable pointer.
+
+Unlike the macro defined above, this function performs as much validation as
+possible, and can handle cases when the SHMPTR is located in an aread of shared
+memory the process doesn't yet know about.
+--*/
+LPVOID SHMPtrToPtr(SHMPTR shmptr);
+
+/*++
+SHMInitialize
+
+Hook this process into the PAL shared memory system; initialize the shared
+memory if no other process has done it.
+--*/
+BOOL SHMInitialize(void);
+
+/*++
+SHMCleanup
+
+Release all shared memory resources held; remove ourselves from the list of
+registered processes, and remove all shared memory files if no process remains
+--*/
+void SHMCleanup(void);
+
+/*++
+SHMalloc
+
+Allocate a block of memory of the specified size
+
+Parameters :
+ size_t size : size of block required
+
+Return value :
+ A SHMPTR identifying the new block, or 0 on failure. Use SHMPtrToPtr to
+ convert a SHMPTR into a useable pointer (but remember to lock the shared
+ memory first!)
+
+Notes :
+ SHMalloc will fail if the requested size is larger than a certain maximum.
+ At the moment, the maximum is 520 bytes (MAX_PATH_FNAME*2).
+--*/
+SHMPTR SHMalloc(size_t size);
+
+/*++
+SHMfree
+
+Release a block of shared memory and put it back in the shared memory pool
+
+Parameters :
+ SHMPTR shmptr : identifier of block to release
+
+(no return value)
+--*/
+void SHMfree(SHMPTR shmptr);
+
+/*++
+SHMLock
+
+Restrict shared memory access to the current thread of the current process
+
+(no parameters)
+
+Return value :
+ New lock count
+--*/
+int SHMLock(void);
+
+/*++
+SHMRelease
+
+Release a lock on shared memory taken with SHMLock.
+
+(no parameters)
+
+Return value :
+ New lock count
+--*/
+int SHMRelease(void);
+
+
+/*++
+Function :
+ SHMGetInfo
+
+ Retrieve some information from shared memory
+
+Parameters :
+ SHM_INFO_ID element : identifier of element to retrieve
+
+Return value :
+ Value of specified element
+
+Notes :
+ The SHM lock should be held while manipulating shared memory
+--*/
+SHMPTR SHMGetInfo(SHM_INFO_ID element);
+
+/*++
+Function :
+ SHMSetInfo
+
+ Place some information into shared memory
+
+Parameters :
+ SHM_INFO_ID element : identifier of element to save
+ SHMPTR value : new value of element
+
+Return value :
+ TRUE if successfull, FALSE otherwise.
+
+Notes :
+ The SHM lock should be held while manipulating shared memory
+--*/
+BOOL SHMSetInfo(SHM_INFO_ID element, SHMPTR value);
+
+
+/********************** Shared memory help functions ********************/
+
+/*++
+SHMStrDup
+
+Duplicates the string in shared memory.
+
+Returns the new address as SHMPTR on success.
+Returns (SHMPTR)NULL on failure.
+--*/
+SHMPTR SHMStrDup( LPCSTR string );
+
+/*++
+SHMWStrDup
+
+Duplicates the wide string in shared memory.
+
+Returns the new address as SHMPTR on success.
+Returns (SHMPTR)NULL on failure.
+--*/
+SHMPTR SHMWStrDup( LPCWSTR string );
+
+
+/*++
+SHMFindNamedObjectByName
+
+Searches for an object whose name matches the name and ID passed in.
+
+Returns a SHMPTR to its location in shared memory. If no object
+matches the name, the function returns NULL and sets pbNameExists to FALSE.
+If an object matches the name but is of a different type, the function
+returns NULL and sets pbNameExists to TRUE.
+
+--*/
+SHMPTR SHMFindNamedObjectByName( LPCWSTR lpName, SHM_NAMED_OBJECTS_ID oid,
+ BOOL *pbNameExists );
+
+/*++
+SHMRemoveNamedObject
+
+Removes the specified named object from the list
+
+No return.
+
+note : the caller is reponsible for releasing all associated memory
+--*/
+void SHMRemoveNamedObject( SHMPTR shmNamedObject );
+
+/*++ SHMAddNamedObject
+
+Adds the specified named object to the list.
+
+No return.
+--*/
+void SHMAddNamedObject( SHMPTR shmNewNamedObject );
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif /* _PAL_SHMEMORY_H_ */
+
diff --git a/src/pal/src/include/pal/stackstring.hpp b/src/pal/src/include/pal/stackstring.hpp
new file mode 100644
index 0000000000..1f18d5fe03
--- /dev/null
+++ b/src/pal/src/include/pal/stackstring.hpp
@@ -0,0 +1,239 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#ifndef __STACKSTRING_H_
+#define __STACKSTRING_H_
+
+template <SIZE_T STACKCOUNT, class T>
+class StackString
+{
+private:
+ T m_innerBuffer[STACKCOUNT + 1];
+ T * m_buffer;
+ SIZE_T m_size; // actual allocated size
+ SIZE_T m_count; // actual length of string
+
+ void NullTerminate()
+ {
+ m_buffer[m_count] = 0;
+ }
+
+ void DeleteBuffer()
+ {
+ if (m_innerBuffer != m_buffer)
+ PAL_free(m_buffer);
+
+ m_buffer = NULL;
+ return;
+ }
+
+ BOOL ReallocateBuffer(SIZE_T count)
+ {
+ // count is always > STACKCOUNT here.
+ // We got so far, we will allocate a little extra
+ // to prevent frequent allocations
+#if _DEBUG
+ SIZE_T count_allocated = count;
+#else
+ SIZE_T count_allocated = count + 100;
+#endif //_DEBUG
+
+ BOOL dataOnStack = m_buffer == m_innerBuffer;
+ if( dataOnStack )
+ {
+ m_buffer = NULL;
+ }
+
+ T * newBuffer = (T *)PAL_realloc(m_buffer, (count_allocated + 1) * sizeof(T));
+ if (NULL == newBuffer)
+ {
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+
+ DeleteBuffer();
+ m_count = 0;
+ m_buffer = m_innerBuffer;
+ return FALSE;
+ }
+
+ if( dataOnStack)
+ {
+ CopyMemory(newBuffer, m_innerBuffer, (m_count + 1) * sizeof(T));
+ }
+
+ m_buffer = newBuffer;
+ m_count = count;
+ m_size = count_allocated + 1;
+
+ return TRUE;
+ }
+
+ BOOL HasAvailableMemory(SIZE_T count)
+ {
+ return (count < m_size);
+ }
+
+ //NOTE: Always call this before modifying the underlying buffer
+ BOOL Resize(SIZE_T count)
+ {
+
+ if (NULL == m_buffer)
+ {
+ m_buffer = m_innerBuffer;
+ }
+
+ if (HasAvailableMemory(count))
+ {
+ m_count = count;
+ }
+ else
+ {
+ if (count > STACKCOUNT)
+ {
+ return ReallocateBuffer(count);
+ }
+ else
+ {
+ m_count = count;
+ m_size = STACKCOUNT+1;
+ }
+ }
+
+ return TRUE;
+ }
+
+ StackString(const StackString &s)
+ {
+ Set(s);
+ }
+
+public:
+ StackString()
+ : m_buffer(m_innerBuffer), m_size(0), m_count(0)
+ {
+ }
+
+
+ BOOL Set(const T * buffer, SIZE_T count)
+ {
+ if (!Resize(count))
+ return FALSE;
+
+ CopyMemory(m_buffer, buffer, (count + 1) * sizeof(T));
+ NullTerminate();
+ return TRUE;
+ }
+
+ BOOL Set(const StackString &s)
+ {
+ return Set(s.m_buffer, s.m_count);
+ }
+
+ SIZE_T GetCount() const
+ {
+ return m_count;
+ }
+
+ SIZE_T GetSizeOf() const
+ {
+ return m_size * sizeof(T);
+ }
+
+ CONST T * GetString() const
+ {
+ return (const T *)m_buffer;
+ }
+
+ operator const T * () const { return GetString(); }
+
+ //Always preserves the existing content
+ T * OpenStringBuffer(SIZE_T count)
+ {
+ T * result = NULL;
+ if (Resize(count))
+ {
+ result = (T *)m_buffer;
+ }
+ return result;
+ }
+
+ //count should not include the terminating null
+ void CloseBuffer(SIZE_T count)
+ {
+ if (m_count > count)
+ m_count = count;
+
+ NullTerminate();
+ return;
+ }
+
+ //Call this with the best estimate if you want to
+ //prevent possible reallocations on further operations
+ BOOL Reserve(SIZE_T count)
+ {
+ SIZE_T endpos = m_count;
+
+ if (!Resize(count))
+ return FALSE;
+
+ m_count = endpos;
+ NullTerminate();
+
+ return TRUE;
+ }
+
+ //count Should not include the terminating null
+ BOOL Append(const T * buffer, SIZE_T count)
+ {
+ SIZE_T endpos = m_count;
+ if (!Resize(m_count + count))
+ return FALSE;
+
+ CopyMemory(&m_buffer[endpos], buffer, (count + 1) * sizeof(T));
+ NullTerminate();
+ return TRUE;
+ }
+
+ BOOL Append(const StackString &s)
+ {
+ return Append(s.GetString(), s.GetCount());
+ }
+
+ BOOL IsEmpty()
+ {
+ return 0 == m_buffer[0];
+ }
+
+ void Clear()
+ {
+ m_count = 0;
+ NullTerminate();
+ }
+ ~StackString()
+ {
+ DeleteBuffer();
+ }
+};
+
+#if _DEBUG
+typedef StackString<32, CHAR> PathCharString;
+typedef StackString<32, WCHAR> PathWCharString;
+#else
+typedef StackString<260, CHAR> PathCharString;
+typedef StackString<260, WCHAR> PathWCharString;
+#endif
+#endif
+
+// Some Helper Definitions
+BOOL
+PAL_GetPALDirectoryW(
+ PathWCharString& lpDirectoryName);
+BOOL
+PAL_GetPALDirectoryA(
+ PathCharString& lpDirectoryName);
+DWORD
+GetCurrentDirectoryA(
+ PathCharString& lpBuffer);
+void
+FILEDosToUnixPathA(
+ PathCharString& lpPath);
diff --git a/src/pal/src/include/pal/synchcache.hpp b/src/pal/src/include/pal/synchcache.hpp
new file mode 100644
index 0000000000..c172842292
--- /dev/null
+++ b/src/pal/src/include/pal/synchcache.hpp
@@ -0,0 +1,397 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ include/pal/synchcache.hpp
+
+Abstract:
+ Simple look-aside cache for unused objects with default
+ constructor or no constructor
+
+
+
+--*/
+
+#ifndef _SYNCH_CACHE_H_
+#define _SYNCH_CACHE_H_
+
+#include "pal/thread.hpp"
+#include "pal/malloc.hpp"
+
+namespace CorUnix
+{
+ template <typename T> class CSynchCache
+ {
+ typedef union _USynchCacheStackNode
+ {
+ union _USynchCacheStackNode * next;
+ BYTE objraw[sizeof(T)];
+ } USynchCacheStackNode;
+
+ static const int MaxDepth = 256;
+
+ Volatile<USynchCacheStackNode*> m_pHead;
+ CRITICAL_SECTION m_cs;
+ Volatile<int> m_iDepth;
+ int m_iMaxDepth;
+#ifdef _DEBUG
+ int m_iMaxTrackedDepth;
+#endif
+
+ void Lock(CPalThread * pthrCurrent)
+ { InternalEnterCriticalSection(pthrCurrent, &m_cs); }
+ void Unlock(CPalThread * pthrCurrent)
+ { InternalLeaveCriticalSection(pthrCurrent, &m_cs); }
+
+ public:
+ CSynchCache(int iMaxDepth = MaxDepth) :
+ m_pHead(NULL),
+ m_iDepth(0),
+ m_iMaxDepth(iMaxDepth)
+#ifdef _DEBUG
+ ,m_iMaxTrackedDepth(0)
+#endif
+ {
+ InternalInitializeCriticalSection(&m_cs);
+ if (m_iMaxDepth < 0)
+ {
+ m_iMaxDepth = 0;
+ }
+ }
+
+ ~CSynchCache()
+ {
+ Flush(NULL, true);
+ InternalDeleteCriticalSection(&m_cs);
+ }
+
+#ifdef _DEBUG
+ int GetMaxTrackedDepth() { return m_iMaxTrackedDepth; }
+#endif
+
+ T * Get(CPalThread * pthrCurrent)
+ {
+ T * pObj = NULL;
+
+ Get(pthrCurrent, 1, &pObj);
+ return pObj;
+ }
+
+ int Get(CPalThread * pthrCurrent, int n, T ** ppObjs)
+ {
+ void * pvObjRaw;
+ USynchCacheStackNode * pNode;
+ int i = 0,j;
+
+ Lock(pthrCurrent);
+ pNode = m_pHead;
+ while (pNode && i < n)
+ {
+ ppObjs[i] = (T *)pNode;
+ pNode = pNode->next;
+ i++;
+ }
+ m_pHead = pNode;
+ m_iDepth -= i;
+
+#ifdef _DEBUG
+ if (NULL == m_pHead && m_iDepth != 0)
+ {
+ // Can't use ASSERT here, since this is header
+ // is included by other headers with inline methods
+ // which causes template instatiation in the header
+ // where the DEBUG CHANNEL is not defined and cannot
+ // be defined
+ fprintf(stderr,"SYNCCACHE: Invalid cache depth value");
+ DebugBreak();
+ }
+#endif // _DEBUG
+
+ Unlock(pthrCurrent);
+
+ for (j=i;j<n;j++)
+ {
+ pvObjRaw = (void *) InternalNew<USynchCacheStackNode>();
+ if (NULL == pvObjRaw)
+ break;
+#ifdef _DEBUG
+ memset(pvObjRaw, 0, sizeof(USynchCacheStackNode));
+#endif
+ ppObjs[j] = reinterpret_cast<T*>(pvObjRaw);
+ }
+
+ for (i=0;i<j;i++)
+ {
+ new ((void *)ppObjs[i]) T;
+ }
+
+ return j;
+ }
+
+ void Add(CPalThread * pthrCurrent, T * pobj)
+ {
+ USynchCacheStackNode * pNode = reinterpret_cast<USynchCacheStackNode *>(pobj);
+
+ if (NULL == pobj)
+ {
+ return;
+ }
+
+ pobj->~T();
+
+ Lock(pthrCurrent);
+ if (m_iDepth < m_iMaxDepth)
+ {
+#ifdef _DEBUG
+ if (m_iDepth > m_iMaxTrackedDepth)
+ {
+ m_iMaxTrackedDepth = m_iDepth;
+ }
+#endif
+ pNode->next = m_pHead;
+ m_pHead = pNode;
+ m_iDepth++;
+ }
+ else
+ {
+ InternalDelete((char *)pNode);
+ }
+ Unlock(pthrCurrent);
+ }
+
+ void Flush(CPalThread * pthrCurrent, bool fDontLock = false)
+ {
+ USynchCacheStackNode * pNode, * pTemp;
+
+ if (!fDontLock)
+ {
+ Lock(pthrCurrent);
+ }
+ pNode = m_pHead;
+ m_pHead = NULL;
+ m_iDepth = 0;
+ if (!fDontLock)
+ {
+ Unlock(pthrCurrent);
+ }
+
+ while (pNode)
+ {
+ pTemp = pNode;
+ pNode = pNode->next;
+ InternalDelete((char *)pTemp);
+ }
+ }
+ };
+
+ template <typename T> class CSHRSynchCache
+ {
+ union _USHRSynchCacheStackNode; // fwd declaration
+ typedef struct _SHRCachePTRs
+ {
+ union _USHRSynchCacheStackNode * pNext;
+ SharedID shrid;
+ } SHRCachePTRs;
+ typedef union _USHRSynchCacheStackNode
+ {
+ SHRCachePTRs pointers;
+ BYTE objraw[sizeof(T)];
+ } USHRSynchCacheStackNode;
+
+ static const int MaxDepth = 256;
+ static const int PreAllocFactor = 10; // Everytime a Get finds no available
+ // cached raw intances, it preallocates
+ // MaxDepth/PreAllocFactor new raw
+ // instances and store them into the
+ // cache before continuing
+
+ Volatile<USHRSynchCacheStackNode*> m_pHead;
+ CRITICAL_SECTION m_cs;
+ Volatile<int> m_iDepth;
+ int m_iMaxDepth;
+#ifdef _DEBUG
+ int m_iMaxTrackedDepth;
+#endif
+
+ void Lock(CPalThread * pthrCurrent)
+ { InternalEnterCriticalSection(pthrCurrent, &m_cs); }
+ void Unlock(CPalThread * pthrCurrent)
+ { InternalLeaveCriticalSection(pthrCurrent, &m_cs); }
+
+ public:
+ CSHRSynchCache(int iMaxDepth = MaxDepth) :
+ m_pHead(NULL),
+ m_iDepth(0),
+ m_iMaxDepth(iMaxDepth)
+#ifdef _DEBUG
+ ,m_iMaxTrackedDepth(0)
+#endif
+ {
+ InternalInitializeCriticalSection(&m_cs);
+ if (m_iMaxDepth < 0)
+ {
+ m_iMaxDepth = 0;
+ }
+ }
+
+ ~CSHRSynchCache()
+ {
+ Flush(NULL, true);
+ InternalDeleteCriticalSection(&m_cs);
+ }
+
+#ifdef _DEBUG
+ int GetMaxTrackedDepth() { return m_iMaxTrackedDepth; }
+#endif
+
+ SharedID Get(CPalThread * pthrCurrent)
+ {
+ SharedID shridObj = NULLSharedID;
+
+ Get(pthrCurrent, 1, &shridObj);
+ return shridObj;
+ }
+
+ int Get(CPalThread * pthrCurrent, int n, SharedID * shridpObjs)
+ {
+ SharedID shridObj;
+ void * pvObjRaw = NULL;
+ USHRSynchCacheStackNode * pNode;
+ int i = 0, j, k;
+
+ Lock(pthrCurrent);
+ pNode = m_pHead;
+ while (pNode && i < n)
+ {
+ shridpObjs[i] = pNode->pointers.shrid;
+ pvObjRaw = (void *)pNode;
+ pNode = pNode->pointers.pNext;
+ i++;
+ }
+ m_pHead = pNode;
+ m_iDepth -= i;
+
+#ifdef _DEBUG
+ if (NULL == m_pHead && m_iDepth != 0)
+ {
+ // Can't use ASSERT here, since this is header
+ // (see comment above)
+ fprintf(stderr,"SYNCCACHE: Invalid cache depth value");
+ DebugBreak();
+ }
+#endif // _DEBUG
+
+ if (0 == m_iDepth)
+ {
+ for (k=0; k<m_iMaxDepth/PreAllocFactor-n+i; k++)
+ {
+ shridObj = RawSharedObjectAlloc(sizeof(USHRSynchCacheStackNode), DefaultSharedPool);
+ if (NULLSharedID == shridObj)
+ {
+ Flush(pthrCurrent, true);
+ break;
+ }
+ pNode = SharedIDToTypePointer(USHRSynchCacheStackNode, shridObj);
+#ifdef _DEBUG
+ memset(reinterpret_cast<void*>(pNode), 0, sizeof(USHRSynchCacheStackNode));
+#endif
+ pNode->pointers.shrid = shridObj;
+ pNode->pointers.pNext = m_pHead;
+ m_pHead = pNode;
+ m_iDepth++;
+ }
+ }
+
+ Unlock(pthrCurrent);
+
+ for (j=i;j<n;j++)
+ {
+ shridObj = RawSharedObjectAlloc(sizeof(USHRSynchCacheStackNode), DefaultSharedPool);
+ if (NULLSharedID == shridObj)
+ break;
+#ifdef _DEBUG
+ pvObjRaw = SharedIDToPointer(shridObj);
+ memset(pvObjRaw, 0, sizeof(USHRSynchCacheStackNode));
+#endif
+ shridpObjs[j] = shridObj;
+ }
+
+ for (i=0;i<j;i++)
+ {
+ pvObjRaw = SharedIDToPointer(shridpObjs[i]);
+ new (pvObjRaw) T;
+ }
+
+ return j;
+ }
+
+ void Add(CPalThread * pthrCurrent, SharedID shridObj)
+ {
+ if (NULLSharedID == shridObj)
+ {
+ return;
+ }
+
+ USHRSynchCacheStackNode * pNode = SharedIDToTypePointer(USHRSynchCacheStackNode, shridObj);
+ T * pObj = reinterpret_cast<T *>(pNode);
+
+ pObj->~T();
+
+ pNode->pointers.shrid = shridObj;
+
+ Lock(pthrCurrent);
+ if (m_iDepth < m_iMaxDepth)
+ {
+ m_iDepth++;
+#ifdef _DEBUG
+ if (m_iDepth > m_iMaxTrackedDepth)
+ {
+ m_iMaxTrackedDepth = m_iDepth;
+ }
+#endif
+ pNode->pointers.pNext = m_pHead;
+ m_pHead = pNode;
+ }
+ else
+ {
+ RawSharedObjectFree(shridObj);
+ }
+ Unlock(pthrCurrent);
+ }
+
+ void Flush(CPalThread * pthrCurrent, bool fDontLock = false)
+ {
+ USHRSynchCacheStackNode * pNode, * pTemp;
+ SharedID shridTemp;
+
+ if (!fDontLock)
+ {
+ Lock(pthrCurrent);
+ }
+ pNode = m_pHead;
+ m_pHead = NULL;
+ m_iDepth = 0;
+ if (!fDontLock)
+ {
+ Unlock(pthrCurrent);
+ }
+
+ while (pNode)
+ {
+ pTemp = pNode;
+ pNode = pNode->pointers.pNext;
+ shridTemp = pTemp->pointers.shrid;
+ RawSharedObjectFree(shridTemp);
+ }
+ }
+ };
+}
+
+#endif // _SYNCH_CACHE_H_
+
diff --git a/src/pal/src/include/pal/synchobjects.hpp b/src/pal/src/include/pal/synchobjects.hpp
new file mode 100644
index 0000000000..aa3a8f1aa6
--- /dev/null
+++ b/src/pal/src/include/pal/synchobjects.hpp
@@ -0,0 +1,216 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ include/pal/synchobjects.hpp
+
+Abstract:
+ Header file for synchronization manager and controllers
+
+
+
+--*/
+
+#ifndef _SINCHOBJECTS_HPP_
+#define _SINCHOBJECTS_HPP_
+
+#include "corunix.hpp"
+#include "threadinfo.hpp"
+#include "mutex.hpp"
+#include "shm.hpp"
+#include "list.h"
+
+#include <pthread.h>
+
+#define SharedID SHMPTR
+#define SharedPoolId ULONG_PTR
+#define DefaultSharedPool ((ULONG_PTR)0)
+#define NULLSharedID ((SHMPTR)NULL)
+#define SharedIDToPointer(shID) SHMPTR_TO_TYPED_PTR(PVOID, shID)
+#define SharedIDToTypePointer(TYPE,shID) SHMPTR_TO_TYPED_PTR(TYPE, shID)
+#define RawSharedObjectAlloc(szSize, shPoolId) SHMalloc(szSize)
+#define RawSharedObjectFree(shID) SHMfree(shID)
+
+namespace CorUnix
+{
+ DWORD InternalWaitForMultipleObjectsEx(
+ CPalThread * pthrCurrent,
+ DWORD nCount,
+ CONST HANDLE *lpHandles,
+ BOOL bWaitAll,
+ DWORD dwMilliseconds,
+ BOOL bAlertable);
+
+ PAL_ERROR InternalSleepEx(
+ CPalThread * pthrCurrent,
+ DWORD dwMilliseconds,
+ BOOL bAlertable);
+
+ enum THREAD_STATE
+ {
+ TS_IDLE,
+ TS_STARTING,
+ TS_RUNNING,
+ TS_FAILED,
+ TS_DONE,
+ };
+
+ // forward declarations
+ struct _ThreadWaitInfo;
+ struct _WaitingThreadsListNode;
+ class CSynchData;
+
+ typedef struct _WaitingThreadsListNode * PWaitingThreadsListNode;
+ typedef struct _OwnedObjectsListNode * POwnedObjectsListNode;
+ typedef struct _ThreadApcInfoNode * PThreadApcInfoNode;
+
+ typedef struct _ThreadWaitInfo
+ {
+ WaitType wtWaitType;
+ WaitDomain wdWaitDomain;
+ LONG lObjCount;
+ LONG lSharedObjCount;
+ CPalThread * pthrOwner;
+ PWaitingThreadsListNode rgpWTLNodes[MAXIMUM_WAIT_OBJECTS];
+
+ _ThreadWaitInfo() : wtWaitType(SingleObject), wdWaitDomain(LocalWait),
+ lObjCount(0), lSharedObjCount(0),
+ pthrOwner(NULL) {}
+ } ThreadWaitInfo;
+
+ typedef struct _ThreadNativeWaitData
+ {
+ pthread_mutex_t mutex;
+ pthread_cond_t cond;
+ int iPred;
+ DWORD dwObjectIndex;
+ ThreadWakeupReason twrWakeupReason;
+ bool fInitialized;
+
+ _ThreadNativeWaitData() :
+ iPred(0),
+ dwObjectIndex(0),
+ twrWakeupReason(WaitSucceeded),
+ fInitialized(false)
+ {
+ }
+
+ ~_ThreadNativeWaitData();
+ } ThreadNativeWaitData;
+
+ class CThreadSynchronizationInfo : public CThreadInfoInitializer
+ {
+ friend class CPalSynchronizationManager;
+ friend class CSynchWaitController;
+
+ THREAD_STATE m_tsThreadState;
+ SharedID m_shridWaitAwakened;
+ Volatile<LONG> m_lLocalSynchLockCount;
+ Volatile<LONG> m_lSharedSynchLockCount;
+ LIST_ENTRY m_leOwnedObjsList;
+
+ CRITICAL_SECTION m_ownedNamedMutexListLock;
+ NamedMutexProcessData *m_ownedNamedMutexListHead;
+
+ ThreadNativeWaitData m_tnwdNativeData;
+ ThreadWaitInfo m_twiWaitInfo;
+
+#ifdef SYNCHMGR_SUSPENSION_SAFE_CONDITION_SIGNALING
+ static const int PendingSignalingsArraySize = 10;
+ LONG m_lPendingSignalingCount;
+ CPalThread * m_rgpthrPendingSignalings[PendingSignalingsArraySize];
+ LIST_ENTRY m_lePendingSignalingsOverflowList;
+#endif // SYNCHMGR_SUSPENSION_SAFE_CONDITION_SIGNALING
+
+ public:
+
+ CThreadSynchronizationInfo();
+ virtual ~CThreadSynchronizationInfo();
+
+ //
+ // CThreadInfoInitializer methods
+ //
+ virtual PAL_ERROR InitializePreCreate(void);
+
+ virtual PAL_ERROR InitializePostCreate(
+ CPalThread *pthrCurrent,
+ SIZE_T threadId,
+ DWORD dwLwpId
+ );
+
+ THREAD_STATE GetThreadState(void)
+ {
+ return m_tsThreadState;
+ };
+
+ void SetThreadState(THREAD_STATE tsThreadState)
+ {
+ m_tsThreadState = tsThreadState;
+ };
+
+ ThreadNativeWaitData * GetNativeData()
+ {
+ return &m_tnwdNativeData;
+ }
+
+#if SYNCHMGR_SUSPENSION_SAFE_CONDITION_SIGNALING
+ PAL_ERROR RunDeferredThreadConditionSignalings();
+#endif // SYNCHMGR_SUSPENSION_SAFE_CONDITION_SIGNALING
+
+ // NOTE: the following methods provide non-synchronized access to
+ // the list of owned objects for this thread. Any thread
+ // accessing this list MUST own the appropriate
+ // synchronization lock(s).
+ void AddObjectToOwnedList(POwnedObjectsListNode pooln);
+ void RemoveObjectFromOwnedList(POwnedObjectsListNode pooln);
+ POwnedObjectsListNode RemoveFirstObjectFromOwnedList(void);
+
+ void AddOwnedNamedMutex(NamedMutexProcessData *processData);
+ void RemoveOwnedNamedMutex(NamedMutexProcessData *processData);
+ NamedMutexProcessData *RemoveFirstOwnedNamedMutex();
+ bool OwnsNamedMutex(NamedMutexProcessData *processData);
+
+ // The following methods provide access to the native wait lock for
+ // those implementations that need a lock to protect the support for
+ // native thread blocking (e.g.: pthread conditions)
+ void AcquireNativeWaitLock(void);
+ void ReleaseNativeWaitLock(void);
+ bool TryAcquireNativeWaitLock(void);
+ };
+
+ class CThreadApcInfo : public CThreadInfoInitializer
+ {
+ friend class CPalSynchronizationManager;
+
+ PThreadApcInfoNode m_ptainHead;
+ PThreadApcInfoNode m_ptainTail;
+
+ public:
+ CThreadApcInfo() :
+ m_ptainHead(NULL),
+ m_ptainTail(NULL)
+ {
+ }
+ };
+
+ class CPalSynchMgrController
+ {
+ public:
+ static IPalSynchronizationManager * CreatePalSynchronizationManager();
+
+ static PAL_ERROR StartWorker(CPalThread * pthrCurrent);
+
+ static PAL_ERROR PrepareForShutdown(void);
+
+ static PAL_ERROR Shutdown(CPalThread *pthrCurrent, bool fFullCleanup);
+ };
+}
+
+#endif // _SINCHOBJECTS_HPP_
+
diff --git a/src/pal/src/include/pal/thread.hpp b/src/pal/src/include/pal/thread.hpp
new file mode 100644
index 0000000000..e6dacd2136
--- /dev/null
+++ b/src/pal/src/include/pal/thread.hpp
@@ -0,0 +1,838 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ include/pal/thread.hpp
+
+Abstract:
+ Header file for thread structures
+
+
+
+--*/
+
+#ifndef _PAL_THREAD_HPP_
+#define _PAL_THREAD_HPP_
+
+#include "corunix.hpp"
+#include "shm.hpp"
+#include "cs.hpp"
+
+#include <pthread.h>
+#include <sys/syscall.h>
+#if HAVE_MACH_EXCEPTIONS
+#include <mach/mach.h>
+#endif // HAVE_MACH_EXCEPTIONS
+
+#include "threadsusp.hpp"
+#include "tls.hpp"
+#include "synchobjects.hpp"
+#include <errno.h>
+
+namespace CorUnix
+{
+ enum PalThreadType
+ {
+ UserCreatedThread,
+ PalWorkerThread,
+ SignalHandlerThread
+ };
+
+ PAL_ERROR
+ InternalCreateThread(
+ CPalThread *pThread,
+ LPSECURITY_ATTRIBUTES lpThreadAttributes,
+ DWORD dwStackSize,
+ LPTHREAD_START_ROUTINE lpStartAddress,
+ LPVOID lpParameter,
+ DWORD dwCreationFlags,
+ PalThreadType eThreadType,
+ LPDWORD lpThreadId,
+ HANDLE *phThread
+ );
+
+ PAL_ERROR
+ InternalGetThreadPriority(
+ CPalThread *pThread,
+ HANDLE hTargetThread,
+ int *piNewPriority
+ );
+
+ PAL_ERROR
+ InternalSetThreadPriority(
+ CPalThread *pThread,
+ HANDLE hTargetThread,
+ int iNewPriority
+ );
+
+ PAL_ERROR
+ InternalGetThreadDataFromHandle(
+ CPalThread *pThread,
+ HANDLE hThread,
+ DWORD dwRightsRequired,
+ CPalThread **ppTargetThread,
+ IPalObject **ppobjThread
+ );
+
+ VOID
+ InternalEndCurrentThread(
+ CPalThread *pThread
+ );
+
+ PAL_ERROR
+ InternalCreateDummyThread(
+ CPalThread *pThread,
+ LPSECURITY_ATTRIBUTES lpThreadAttributes,
+ CPalThread **ppDummyThread,
+ HANDLE *phThread
+ );
+
+ PAL_ERROR
+ InitializeGlobalThreadData(
+ void
+ );
+
+ PAL_ERROR
+ CreateThreadData(
+ CPalThread **ppThread
+ );
+
+ PAL_ERROR
+ CreateThreadObject(
+ CPalThread *pThread,
+ CPalThread *pNewThread,
+ HANDLE *phThread
+ );
+
+ PAL_ERROR
+ InitializeEndingThreadsData(
+ void
+ );
+
+ BOOL
+ GetThreadTimesInternal(
+ IN HANDLE hThread,
+ OUT LPFILETIME lpKernelTime,
+ OUT LPFILETIME lpUserTime);
+
+#ifdef FEATURE_PAL_SXS
+#if HAVE_MACH_EXCEPTIONS
+
+ // Structure used to return data about a single handler to a caller.
+ struct MachExceptionHandler
+ {
+ exception_mask_t m_mask;
+ exception_handler_t m_handler;
+ exception_behavior_t m_behavior;
+ thread_state_flavor_t m_flavor;
+ };
+
+ // Class abstracting previously registered Mach exception handlers for a thread.
+ struct CThreadMachExceptionHandlers
+ {
+ public:
+ // Maximum number of exception ports we hook. Must be the count
+ // of all bits set in the exception masks defined in machexception.h.
+ static const int s_nPortsMax = 6;
+
+ // Saved exception ports, exactly as returned by
+ // thread_swap_exception_ports.
+ mach_msg_type_number_t m_nPorts;
+ exception_mask_t m_masks[s_nPortsMax];
+ exception_handler_t m_handlers[s_nPortsMax];
+ exception_behavior_t m_behaviors[s_nPortsMax];
+ thread_state_flavor_t m_flavors[s_nPortsMax];
+
+ CThreadMachExceptionHandlers() :
+ m_nPorts(-1)
+ {
+ }
+
+ // Get handler details for a given type of exception. If successful the structure pointed at by
+ // pHandler is filled in and true is returned. Otherwise false is returned.
+ bool GetHandler(exception_type_t eException, MachExceptionHandler *pHandler);
+
+ private:
+ // Look for a handler for the given exception within the given handler node. Return its index if
+ // successful or -1 otherwise.
+ int GetIndexOfHandler(exception_mask_t bmExceptionMask);
+ };
+#endif // HAVE_MACH_EXCEPTIONS
+#endif // FEATURE_PAL_SXS
+
+ class CThreadSEHInfo : public CThreadInfoInitializer
+ {
+ public:
+#if !HAVE_MACH_EXCEPTIONS
+ BOOL safe_state;
+ int signal_code;
+#endif // !HAVE_MACH_EXCEPTIONSG
+
+ CThreadSEHInfo()
+ {
+ };
+ };
+
+ /* In the windows CRT there is a constant defined for the max width
+ of a _ecvt conversion. That constant is 348. 348 for the value, plus
+ the exponent value, decimal, and sign if required. */
+#define ECVT_MAX_COUNT_SIZE 348
+#define ECVT_MAX_BUFFER_SIZE 357
+
+ /*STR_TIME_SIZE is defined as 26 the size of the
+ return val by ctime_r*/
+#define STR_TIME_SIZE 26
+
+ class CThreadCRTInfo : public CThreadInfoInitializer
+ {
+ public:
+ CHAR * strtokContext; // Context for strtok function
+ WCHAR * wcstokContext; // Context for wcstok function
+ struct PAL_tm localtimeBuffer; // Buffer for localtime function
+ CHAR ctimeBuffer[ STR_TIME_SIZE ]; // Buffer for ctime function
+ CHAR ECVTBuffer[ ECVT_MAX_BUFFER_SIZE ]; // Buffer for _ecvt function.
+
+ CThreadCRTInfo() :
+ strtokContext(NULL),
+ wcstokContext(NULL)
+ {
+ ZeroMemory(&localtimeBuffer, sizeof(localtimeBuffer));
+ ZeroMemory(ctimeBuffer, sizeof(ctimeBuffer));
+ ZeroMemory(ECVTBuffer, sizeof(ECVTBuffer));
+ };
+ };
+
+ class CPalThread
+ {
+ friend
+ PAL_ERROR
+ CorUnix::InternalCreateThread(
+ CPalThread *,
+ LPSECURITY_ATTRIBUTES,
+ DWORD,
+ LPTHREAD_START_ROUTINE,
+ LPVOID,
+ DWORD,
+ PalThreadType,
+ LPDWORD,
+ HANDLE*
+ );
+
+ friend
+ PAL_ERROR
+ InternalCreateDummyThread(
+ CPalThread *pThread,
+ LPSECURITY_ATTRIBUTES lpThreadAttributes,
+ CPalThread **ppDummyThread,
+ HANDLE *phThread
+ );
+
+ friend
+ PAL_ERROR
+ InternalSetThreadPriority(
+ CPalThread *,
+ HANDLE,
+ int
+ );
+
+ friend
+ PAL_ERROR
+ InitializeGlobalThreadData(
+ void
+ );
+
+ friend
+ PAL_ERROR
+ CreateThreadData(
+ CPalThread **ppThread
+ );
+
+ friend
+ PAL_ERROR
+ CreateThreadObject(
+ CPalThread *pThread,
+ CPalThread *pNewThread,
+ HANDLE *phThread
+ );
+
+ friend CatchHardwareExceptionHolder;
+
+ private:
+
+ CPalThread *m_pNext;
+ DWORD m_dwExitCode;
+ BOOL m_fExitCodeSet;
+ CRITICAL_SECTION m_csLock;
+ bool m_fLockInitialized;
+ bool m_fIsDummy;
+
+ //
+ // Minimal reference count, used primarily for cleanup purposes. A
+ // new thread object has an initial refcount of 1. This initial
+ // reference is removed by CorUnix::InternalEndCurrentThread.
+ //
+ // The only other spot the refcount is touched is from within
+ // CPalObjectBase::ReleaseReference -- incremented before the
+ // destructors for an ojbect are called, and decremented afterwords.
+ // This permits the freeing of the thread structure to happen after
+ // the freeing of the enclosing thread object has completed.
+ //
+
+ LONG m_lRefCount;
+
+ //
+ // The IPalObject for this thread. The thread will release its reference
+ // to this object when it exits.
+ //
+
+ IPalObject *m_pThreadObject;
+
+ //
+ // Thread ID info
+ //
+
+ SIZE_T m_threadId;
+ DWORD m_dwLwpId;
+ pthread_t m_pthreadSelf;
+
+#if HAVE_MACH_THREADS
+ mach_port_t m_machPortSelf;
+#endif
+
+ // > 0 when there is an exception holder which causes h/w
+ // exceptions to be sent down the C++ exception chain.
+ int m_hardwareExceptionHolderCount;
+
+ //
+ // Start info
+ //
+
+ LPTHREAD_START_ROUTINE m_lpStartAddress;
+ LPVOID m_lpStartParameter;
+ BOOL m_bCreateSuspended;
+
+ int m_iThreadPriority;
+ PalThreadType m_eThreadType;
+
+ //
+ // pthread mutex / condition variable for gating thread startup.
+ // InternalCreateThread waits on the condition variable to determine
+ // when the new thread has reached passed all failure points in
+ // the entry routine
+ //
+
+ pthread_mutex_t m_startMutex;
+ pthread_cond_t m_startCond;
+ bool m_fStartItemsInitialized;
+ bool m_fStartStatus;
+ bool m_fStartStatusSet;
+
+ // Base address of the stack of this thread
+ void* m_stackBase;
+ // Limit address of the stack of this thread
+ void* m_stackLimit;
+
+ // The default stack size of a newly created thread (currently 256KB)
+ // when the dwStackSize paramter of PAL_CreateThread()
+ // is zero. This value can be set by setting the
+ // environment variable PAL_THREAD_DEFAULT_STACK_SIZE
+ // (the value should be in bytes and in hex).
+ static DWORD s_dwDefaultThreadStackSize;
+
+ //
+ // The thread entry routine (called from InternalCreateThread)
+ //
+
+ static void* ThreadEntry(void * pvParam);
+
+#ifdef FEATURE_PAL_SXS
+ //
+ // Data for PAL side-by-side support
+ //
+
+ private:
+ // This is set whenever this thread is currently executing within
+ // a region of code that depends on this instance of the PAL
+ // in the process.
+ bool m_fInPal;
+
+#if HAVE_MACH_EXCEPTIONS
+ // Record of Mach exception handlers that were already registered when we register our own CoreCLR
+ // specific handlers.
+ CThreadMachExceptionHandlers m_sMachExceptionHandlers;
+#endif // HAVE_MACH_EXCEPTIONS
+#endif // FEATURE_PAL_SXS
+
+ public:
+
+ //
+ // Embedded information for areas owned by other subsystems
+ //
+
+ CThreadSynchronizationInfo synchronizationInfo;
+ CThreadSuspensionInfo suspensionInfo;
+ CThreadSEHInfo sehInfo;
+ CThreadTLSInfo tlsInfo;
+ CThreadApcInfo apcInfo;
+ CThreadCRTInfo crtInfo;
+
+ CPalThread()
+ :
+ m_pNext(NULL),
+ m_dwExitCode(STILL_ACTIVE),
+ m_fExitCodeSet(FALSE),
+ m_fLockInitialized(FALSE),
+ m_fIsDummy(FALSE),
+ m_lRefCount(1),
+ m_pThreadObject(NULL),
+ m_threadId(0),
+ m_dwLwpId(0),
+ m_pthreadSelf(0),
+#if HAVE_MACH_THREADS
+ m_machPortSelf(0),
+#endif
+ m_hardwareExceptionHolderCount(0),
+ m_lpStartAddress(NULL),
+ m_lpStartParameter(NULL),
+ m_bCreateSuspended(FALSE),
+ m_iThreadPriority(THREAD_PRIORITY_NORMAL),
+ m_eThreadType(UserCreatedThread),
+ m_fStartItemsInitialized(FALSE),
+ m_fStartStatus(FALSE),
+ m_fStartStatusSet(FALSE),
+ m_stackBase(NULL),
+ m_stackLimit(NULL)
+#ifdef FEATURE_PAL_SXS
+ , m_fInPal(TRUE)
+#endif // FEATURE_PAL_SXS
+ {
+ };
+
+ virtual ~CPalThread();
+
+ PAL_ERROR
+ RunPreCreateInitializers(
+ void
+ );
+
+ //
+ // m_threadId and m_dwLwpId must be set before calling
+ // RunPostCreateInitializers
+ //
+
+ PAL_ERROR
+ RunPostCreateInitializers(
+ void
+ );
+
+ //
+ // SetStartStatus is called by THREADEntry or InternalSuspendNewThread
+ // to inform InternalCreateThread of the results of the thread's
+ // initialization. InternalCreateThread calls WaitForStartStatus to
+ // obtain this information (and will not return to its caller until
+ // the info is available).
+ //
+
+ void
+ SetStartStatus(
+ bool fStartSucceeded
+ );
+
+ bool
+ WaitForStartStatus(
+ void
+ );
+
+ void
+ Lock(
+ CPalThread *pThread
+ )
+ {
+ InternalEnterCriticalSection(pThread, &m_csLock);
+ };
+
+ void
+ Unlock(
+ CPalThread *pThread
+ )
+ {
+ InternalLeaveCriticalSection(pThread, &m_csLock);
+ };
+
+ //
+ // The following three methods provide access to the
+ // native lock used to protect thread native wait data.
+ //
+
+ void
+ AcquireNativeWaitLock(
+ void
+ )
+ {
+ synchronizationInfo.AcquireNativeWaitLock();
+ }
+
+ void
+ ReleaseNativeWaitLock(
+ void
+ )
+ {
+ synchronizationInfo.ReleaseNativeWaitLock();
+ }
+
+ bool
+ TryAcquireNativeWaitLock(
+ void
+ )
+ {
+ return synchronizationInfo.TryAcquireNativeWaitLock();
+ }
+
+ static void
+ SetLastError(
+ DWORD dwLastError
+ )
+ {
+ // Reuse errno to store last error
+ errno = dwLastError;
+ };
+
+ static DWORD
+ GetLastError(
+ void
+ )
+ {
+ // Reuse errno to store last error
+ return errno;
+ };
+
+ void
+ SetExitCode(
+ DWORD dwExitCode
+ )
+ {
+ m_dwExitCode = dwExitCode;
+ m_fExitCodeSet = TRUE;
+ };
+
+ BOOL
+ GetExitCode(
+ DWORD *pdwExitCode
+ )
+ {
+ *pdwExitCode = m_dwExitCode;
+ return m_fExitCodeSet;
+ };
+
+ SIZE_T
+ GetThreadId(
+ void
+ )
+ {
+ return m_threadId;
+ };
+
+ DWORD
+ GetLwpId(
+ void
+ )
+ {
+ return m_dwLwpId;
+ };
+
+ pthread_t
+ GetPThreadSelf(
+ void
+ )
+ {
+ return m_pthreadSelf;
+ };
+
+#if HAVE_MACH_THREADS
+ mach_port_t
+ GetMachPortSelf(
+ void
+ )
+ {
+ return m_machPortSelf;
+ };
+#endif
+
+ bool
+ IsHardwareExceptionsEnabled()
+ {
+ return m_hardwareExceptionHolderCount > 0;
+ }
+
+ LPTHREAD_START_ROUTINE
+ GetStartAddress(
+ void
+ )
+ {
+ return m_lpStartAddress;
+ };
+
+ LPVOID
+ GetStartParameter(
+ void
+ )
+ {
+ return m_lpStartParameter;
+ };
+
+ BOOL
+ GetCreateSuspended(
+ void
+ )
+ {
+ return m_bCreateSuspended;
+ };
+
+ PalThreadType
+ GetThreadType(
+ void
+ )
+ {
+ return m_eThreadType;
+ };
+
+ int
+ GetThreadPriority(
+ void
+ )
+ {
+ return m_iThreadPriority;
+ };
+
+ IPalObject *
+ GetThreadObject(
+ void
+ )
+ {
+ return m_pThreadObject;
+ }
+
+ BOOL
+ IsDummy(
+ void
+ )
+ {
+ return m_fIsDummy;
+ };
+
+ CPalThread*
+ GetNext(
+ void
+ )
+ {
+ return m_pNext;
+ };
+
+ void
+ SetNext(
+ CPalThread *pNext
+ )
+ {
+ m_pNext = pNext;
+ };
+
+ void
+ AddThreadReference(
+ void
+ );
+
+ void
+ ReleaseThreadReference(
+ void
+ );
+
+ // Get base address of the current thread's stack
+ static
+ void *
+ GetStackBase(
+ void
+ );
+
+ // Get cached base address of this thread's stack
+ // Can be called only for the current thread.
+ void *
+ GetCachedStackBase(
+ void
+ );
+
+ // Get limit address of the current thread's stack
+ static
+ void *
+ GetStackLimit(
+ void
+ );
+
+ // Get cached limit address of this thread's stack
+ // Can be called only for the current thread.
+ void *
+ GetCachedStackLimit(
+ void
+ );
+
+#ifdef FEATURE_PAL_SXS
+ //
+ // Functions for PAL side-by-side support
+ //
+
+ // This function needs to be called on a thread when it enters
+ // a region of code that depends on this instance of the PAL
+ // in the process.
+ PAL_ERROR Enter(PAL_Boundary boundary);
+
+ // This function needs to be called on a thread when it leaves
+ // a region of code that depends on this instance of the PAL
+ // in the process.
+ PAL_ERROR Leave(PAL_Boundary boundary);
+
+ // Returns TRUE whenever this thread is executing in a region
+ // of code that depends on this instance of the PAL in the process.
+ BOOL IsInPal()
+ {
+ return m_fInPal;
+ };
+
+#if HAVE_MACH_EXCEPTIONS
+ // Hook Mach exceptions, i.e., call thread_swap_exception_ports
+ // to replace the thread's current exception ports with our own.
+ // The previously active exception ports are saved. Called when
+ // this thread enters a region of code that depends on this PAL.
+ // Should only fail on internal errors.
+ PAL_ERROR EnableMachExceptions();
+
+ // Unhook Mach exceptions, i.e., call thread_set_exception_ports
+ // to restore the thread's exception ports with those we saved
+ // in EnableMachExceptions. Called when this thread leaves a
+ // region of code that depends on this PAL. Should only fail
+ // on internal errors.
+ PAL_ERROR DisableMachExceptions();
+
+ // The exception handling thread needs to be able to get at the list of handlers that installing our
+ // own handler on a thread has displaced (in case we need to forward an exception that we don't want
+ // to handle).
+ CThreadMachExceptionHandlers *GetSavedMachHandlers()
+ {
+ return &m_sMachExceptionHandlers;
+ }
+#endif // HAVE_MACH_EXCEPTIONS
+#endif // FEATURE_PAL_SXS
+ };
+
+#if defined(FEATURE_PAL_SXS)
+ extern "C" CPalThread *CreateCurrentThreadData();
+#endif // FEATURE_PAL_SXS
+
+ inline CPalThread *GetCurrentPalThread()
+ {
+ return reinterpret_cast<CPalThread*>(pthread_getspecific(thObjKey));
+ }
+
+ inline CPalThread *InternalGetCurrentThread()
+ {
+ CPalThread *pThread = GetCurrentPalThread();
+#if defined(FEATURE_PAL_SXS)
+ if (pThread == nullptr)
+ pThread = CreateCurrentThreadData();
+#endif // FEATURE_PAL_SXS
+ return pThread;
+ }
+
+/***
+
+ $$TODO: These are needed only to support cross-process thread duplication
+
+ class CThreadImmutableData
+ {
+ public:
+ DWORD dwProcessId;
+ };
+
+ class CThreadSharedData
+ {
+ public:
+ DWORD dwThreadId;
+ DWORD dwExitCode;
+ };
+***/
+
+ //
+ // The process local information for a thread is just a pointer
+ // to the underlying CPalThread object.
+ //
+
+ class CThreadProcessLocalData
+ {
+ public:
+ CPalThread *pThread;
+ };
+
+ extern CObjectType otThread;
+}
+
+BOOL
+TLSInitialize(
+ void
+ );
+
+VOID
+TLSCleanup(
+ void
+ );
+
+VOID
+WaitForEndingThreads(
+ void
+ );
+
+extern int free_threads_spinlock;
+
+extern PAL_ActivationFunction g_activationFunction;
+extern PAL_SafeActivationCheckFunction g_safeActivationCheckFunction;
+
+/*++
+Macro:
+ THREADSilentGetCurrentThreadId
+
+Abstract:
+ Same as GetCurrentThreadId, but it doesn't output any traces.
+ It is useful for tracing functions to display the thread ID
+ without generating any new traces.
+
+ TODO: how does the perf of pthread_self compare to
+ InternalGetCurrentThread when we find the thread in the
+ cache?
+
+ If the perf of pthread_self is comparable to that of the stack
+ bounds based lookaside system, why aren't we using it in the
+ cache?
+
+ In order to match the thread ids that debuggers use at least for
+ linux we need to use gettid().
+
+--*/
+#if defined(__linux__)
+#define THREADSilentGetCurrentThreadId() (SIZE_T)syscall(SYS_gettid)
+#elif defined(__APPLE__)
+inline SIZE_T THREADSilentGetCurrentThreadId() {
+ uint64_t tid;
+ pthread_threadid_np(pthread_self(), &tid);
+ return (SIZE_T)tid;
+}
+#elif defined(__NetBSD__)
+#include <lwp.h>
+#define THREADSilentGetCurrentThreadId() (SIZE_T)_lwp_self()
+#else
+#define THREADSilentGetCurrentThreadId() (SIZE_T)pthread_self()
+#endif
+
+#endif // _PAL_THREAD_HPP_
diff --git a/src/pal/src/include/pal/threadinfo.hpp b/src/pal/src/include/pal/threadinfo.hpp
new file mode 100644
index 0000000000..93ba0ababd
--- /dev/null
+++ b/src/pal/src/include/pal/threadinfo.hpp
@@ -0,0 +1,89 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ include/pal/threadinfo.hpp
+
+Abstract:
+ Header file for thread info initialzer
+
+
+
+--*/
+
+#ifndef _PAL_THREADINFO_H_
+#define _PAL_THREADINFO_H_
+
+#include "corunix.hpp"
+
+namespace CorUnix
+{
+ //
+ // There are a number of different functional areas for which we need to
+ // store per-thread data:
+ // * synchronization
+ // * structure exception handling
+ // * asynchronous procedure calls
+ // * thread suspension
+ // * thread-local storage
+ // * CRT per-thread buffers
+ //
+ // For each of the above functional areas we build a class that stores
+ // the necessary data. An instance of each of these classes is embedded
+ // in the main thread class. The classes must not have any failure paths
+ // in their constructors. Each class inherits from a common parent class
+ // that exposes two virtual initialization routines (which may return an
+ // error). The first initialization routine is called after the thread
+ // object is allocated, but before the new thread is created. Any
+ // initialization that is not dependant on knowledge of the new thread's
+ // ID (and by extension need not run in the context of the new thread)
+ // should take place in the first routine. Work that must run in the
+ // context of the new thread or that must know the new thread's ID
+ // should take place in the second initialization routine.
+ //
+
+ class CThreadInfoInitializer
+ {
+ public:
+
+ //
+ // InitializePreCreate is called before the new thread is started.
+ // Any allocations or other initializations that may fail that do
+ // not need to run in the context of the new thread (or know the
+ // new thread's ID) should take place in this routine.
+ //
+
+ virtual
+ PAL_ERROR
+ InitializePreCreate(
+ void
+ )
+ {
+ return NO_ERROR;
+ };
+
+ //
+ // InitializePostCreate is called from within the context of the
+ // new thread.
+ //
+
+ virtual
+ PAL_ERROR
+ InitializePostCreate(
+ CPalThread *pThread,
+ SIZE_T threadId,
+ DWORD dwLwpId
+ )
+ {
+ return NO_ERROR;
+ };
+ };
+}
+
+#endif // _PAL_THREADINFO_H_
diff --git a/src/pal/src/include/pal/threadsusp.hpp b/src/pal/src/include/pal/threadsusp.hpp
new file mode 100644
index 0000000000..e1e85e265c
--- /dev/null
+++ b/src/pal/src/include/pal/threadsusp.hpp
@@ -0,0 +1,382 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ include/pal/threadsusp.hpp
+
+Abstract:
+ Declarations for thread suspension
+
+
+
+--*/
+
+#ifndef _PAL_THREADSUSP_HPP
+#define _PAL_THREADSUSP_HPP
+
+// Need this ifdef since this header is included by .c files so they can use the diagnostic function.
+#ifdef __cplusplus
+
+// Note: do not include malloc.hpp from this header. The template InternalDelete
+// needs to know the layout of class CPalThread, which includes a member of type
+// CThreadSuspensionInfo, which is defined later in this header, and it is not
+// yet known at this point.
+// If any future change should bring this issue back, the circular dependency can
+// be further broken by making the InternalDelete's CPalThread argument a
+// templatized argument, so that type checking on it takes place only at
+// instantiation time.
+#include "pal/threadinfo.hpp"
+#include "pal/thread.hpp"
+#include "pal/printfcpp.hpp"
+#include "pal/mutex.hpp"
+#include "pal/init.h"
+#if !HAVE_MACH_EXCEPTIONS
+#include <signal.h>
+#endif // !HAVE_MACH_EXCEPTIONS
+#include <semaphore.h>
+#include <sched.h>
+
+// We have a variety of options for synchronizing thread suspensions and resumptions between the requestor and
+// target threads. Analyze the various capabilities given to us by configure and define one of three macros
+// here for simplicity:
+// USE_POSIX_SEMAPHORES
+// USE_SYSV_SEMAPHORES
+// USE_PTHREAD_CONDVARS
+#if HAS_POSIX_SEMAPHORES
+
+// Favor posix semaphores.
+#define USE_POSIX_SEMAPHORES 1
+
+#if HAVE_SYS_SEMAPHORE_H
+#include <sys/semaphore.h>
+#endif // HAVE_SYS_SEMAPHORE_H
+
+#elif HAS_PTHREAD_MUTEXES && HAVE_MACH_EXCEPTIONS
+
+// Can only use the pthread solution if we're not using signals since pthread mutexes are not signal safe.
+#define USE_PTHREAD_CONDVARS 1
+
+#include <pthread.h>
+
+#elif HAS_SYSV_SEMAPHORES
+
+// SYSV semaphores are our last choice since they're shared across processes so it's possible to leak them
+// on abnormal process termination.
+#define USE_SYSV_SEMAPHORES 1
+
+#include <sys/sem.h>
+#include <sys/types.h>
+
+#else
+#error "Don't know how to synchronize thread suspends and resumes on this platform"
+#endif // HAS_POSIX_SEMAPHORES
+
+#include <stdarg.h>
+
+namespace CorUnix
+{
+#ifdef _DEBUG
+#define MAX_TRACKED_CRITSECS 8
+#endif
+
+ PAL_ERROR
+ InternalResumeThread(
+ CPalThread *pthrResumer,
+ HANDLE hTarget,
+ DWORD *pdwSuspendCount
+ );
+
+ class CThreadSuspensionInfo : public CThreadInfoInitializer
+ {
+ private:
+ BOOL m_fPending; // TRUE if a suspension is pending on a thread (because the thread is in an unsafe region)
+ BOOL m_fSelfsusp; // TRUE if thread is self suspending and while thread is self suspended
+ BOOL m_fSuspendedForShutdown; // TRUE once the thread is suspended during PAL cleanup
+ int m_nBlockingPipe; // blocking pipe used for a process that was created suspended
+#ifdef _DEBUG
+ Volatile<LONG> m_lNumThreadsSuspendedByThisThread; // number of threads that this thread has suspended; used for suspension diagnostics
+#endif
+#if DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX
+ int m_nSpinlock; // thread's suspension spinlock, which is used to synchronize suspension and resumption attempts
+#else // DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX
+ pthread_mutex_t m_ptmSuspmutex; // thread's suspension mutex, which is used to synchronize suspension and resumption attempts
+ BOOL m_fSuspmutexInitialized;
+#endif // DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX
+#if USE_POSIX_SEMAPHORES
+ sem_t m_semSusp; // suspension semaphore
+ sem_t m_semResume; // resumption semaphore
+ BOOL m_fSemaphoresInitialized;
+#elif USE_SYSV_SEMAPHORES
+ // necessary id's and sembuf structures for SysV semaphores
+ int m_nSemsuspid; // id for the suspend semaphore
+ int m_nSemrespid; // id for the resume semaphore
+ struct sembuf m_sbSemwait; // struct representing a wait operation
+ struct sembuf m_sbSempost; // struct representing a post operation
+#elif USE_PTHREAD_CONDVARS
+ pthread_cond_t m_condSusp; // suspension condition variable
+ pthread_mutex_t m_mutexSusp; // mutex associated with the condition above
+ BOOL m_fSuspended; // set to true once the suspend has been acknowledged
+
+ pthread_cond_t m_condResume; // resumption condition variable
+ pthread_mutex_t m_mutexResume; // mutex associated with the condition above
+ BOOL m_fResumed; // set to true once the resume has been acknowledged
+
+ BOOL m_fSemaphoresInitialized;
+#endif // USE_POSIX_SEMAPHORES
+
+ /* Most of the variables above are either accessed by a thread
+ holding the appropriate suspension mutex(es) or are only
+ accessed by their own threads (and thus don't require
+ synchronization).
+
+ m_fPending, m_fSuspendedForShutdown,
+ m_fSuspendSignalSent, and m_fResumeSignalSent
+ may be set by a different thread than the owner and thus
+ require synchronization.
+
+ m_fSelfsusp is set to TRUE only by its own thread but may be later
+ accessed by other threads.
+
+ m_lNumThreadsSuspendedByThisThread is accessed by its owning
+ thread and therefore does not require synchronization. */
+
+#ifdef _DEBUG
+ VOID
+ IncrNumThreadsSuspendedByThisThread(
+ )
+ {
+ InterlockedIncrement(&m_lNumThreadsSuspendedByThisThread);
+ };
+
+ VOID
+ DecrNumThreadsSuspendedByThisThread(
+ )
+ {
+ InterlockedDecrement(&m_lNumThreadsSuspendedByThisThread);
+ };
+#endif
+
+ VOID
+ AcquireSuspensionLocks(
+ CPalThread *pthrSuspender,
+ CPalThread *pthrTarget
+ );
+
+ VOID
+ ReleaseSuspensionLocks(
+ CPalThread *pthrSuspender,
+ CPalThread *pthrTarget
+ );
+
+#if USE_POSIX_SEMAPHORES
+ sem_t*
+ GetSuspendSemaphore(
+ void
+ )
+ {
+ return &m_semSusp;
+ };
+
+ sem_t*
+ GetResumeSemaphore(
+ void
+ )
+ {
+ return &m_semResume;
+ };
+#elif USE_SYSV_SEMAPHORES
+ int
+ GetSuspendSemaphoreId(
+ void
+ )
+ {
+ return m_nSemsuspid;
+ };
+
+ sembuf*
+ GetSemaphorePostBuffer(
+ void
+ )
+ {
+ return &m_sbSempost;
+ };
+#endif // USE_POSIX_SEMAPHORES
+
+#if DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX
+ LONG*
+ GetSuspensionSpinlock(
+ void
+ )
+ {
+ return &m_nSpinlock;
+ }
+#else // DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX
+ pthread_mutex_t*
+ GetSuspensionMutex(
+ void
+ )
+ {
+ return &m_ptmSuspmutex;
+ }
+#endif // DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX
+
+ void
+ SetSuspPending(
+ BOOL fPending
+ )
+ {
+ m_fPending = fPending;
+ };
+
+ BOOL
+ GetSuspPending(
+ void
+ )
+ {
+ return m_fPending;
+ };
+
+ void
+ SetSelfSusp(
+ BOOL fSelfsusp
+ )
+ {
+ m_fSelfsusp = fSelfsusp;
+ };
+
+ BOOL
+ GetSelfSusp(
+ void
+ )
+ {
+ return m_fSelfsusp;
+ };
+
+ void
+ PostOnSuspendSemaphore();
+
+ void
+ WaitOnSuspendSemaphore();
+
+ void
+ PostOnResumeSemaphore();
+
+ void
+ WaitOnResumeSemaphore();
+
+ static
+ BOOL
+ TryAcquireSuspensionLock(
+ CPalThread* pthrTarget
+ );
+
+ int GetBlockingPipe(
+ void
+ )
+ {
+ return m_nBlockingPipe;
+ };
+
+ public:
+ virtual PAL_ERROR InitializePreCreate();
+
+ CThreadSuspensionInfo()
+ : m_fPending(FALSE)
+ , m_fSelfsusp(FALSE)
+ , m_fSuspendedForShutdown(FALSE)
+ , m_nBlockingPipe(-1)
+#ifdef _DEBUG
+ , m_lNumThreadsSuspendedByThisThread(0)
+#endif // _DEBUG
+#if !DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX
+ , m_fSuspmutexInitialized(FALSE)
+#endif
+#if USE_POSIX_SEMAPHORES || USE_PTHREAD_CONDVARS
+ , m_fSemaphoresInitialized(FALSE)
+#endif
+ {
+ InitializeSuspensionLock();
+ };
+
+ virtual ~CThreadSuspensionInfo();
+
+#ifdef _DEBUG
+ LONG
+ GetNumThreadsSuspendedByThisThread(
+ void
+ )
+ {
+ return m_lNumThreadsSuspendedByThisThread;
+ };
+#endif // _DEBUG
+
+#if USE_SYSV_SEMAPHORES
+ void
+ DestroySemaphoreIds(
+ void
+ );
+#endif
+ void
+ SetSuspendedForShutdown(
+ BOOL fSuspendedForShutdown
+ )
+ {
+ m_fSuspendedForShutdown = fSuspendedForShutdown;
+ };
+
+ BOOL
+ GetSuspendedForShutdown(
+ void
+ )
+ {
+ return m_fSuspendedForShutdown;
+ };
+
+ void
+ AcquireSuspensionLock(
+ CPalThread *pthrCurrent
+ );
+
+ void
+ ReleaseSuspensionLock(
+ CPalThread *pthrCurrent
+ );
+
+ PAL_ERROR
+ InternalSuspendNewThreadFromData(
+ CPalThread *pThread
+ );
+
+ PAL_ERROR
+ InternalResumeThreadFromData(
+ CPalThread *pthrResumer,
+ CPalThread *pthrTarget,
+ DWORD *pdwSuspendCount
+ );
+
+ VOID InitializeSuspensionLock();
+
+ void SetBlockingPipe(
+ int nBlockingPipe
+ )
+ {
+ m_nBlockingPipe = nBlockingPipe;
+ };
+ };
+} //end CorUnix
+
+extern const BYTE WAKEUPCODE; // use for pipe reads during self suspend.
+#endif // __cplusplus
+
+#ifdef USE_GLOBAL_LOCK_FOR_SUSPENSION
+extern LONG g_ssSuspensionLock;
+#endif
+
+#endif // _PAL_THREADSUSP_HPP
+
diff --git a/src/pal/src/include/pal/tls.hpp b/src/pal/src/include/pal/tls.hpp
new file mode 100644
index 0000000000..a4d9926c49
--- /dev/null
+++ b/src/pal/src/include/pal/tls.hpp
@@ -0,0 +1,65 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ include/pal/tls.hpp
+
+Abstract:
+ Header file for thread local storage
+
+
+
+--*/
+
+#ifndef _PAL_TLS_HPP
+#define _PAL_TLS_HPP
+
+#include "threadinfo.hpp"
+
+namespace CorUnix
+{
+ /* This is the number of slots available for use in TlsAlloc().
+ sTlsSlotFields in thread/localstorage.c must be this number
+ of bits. */
+#define TLS_SLOT_SIZE 64
+
+ class CThreadTLSInfo : public CThreadInfoInitializer
+ {
+ public:
+ LPVOID tlsSlots[TLS_SLOT_SIZE];
+
+ virtual
+ PAL_ERROR
+ InitializePostCreate(
+ CPalThread *pThread,
+ SIZE_T threadId,
+ DWORD dwLwpId
+ );
+
+ CThreadTLSInfo()
+ {
+ ZeroMemory(tlsSlots, sizeof(tlsSlots));
+ };
+ };
+
+ //
+ // InternalGetCurrentThread obtains the CPalThread instance for the
+ // calling thread. That instance should only be used by the calling
+ // thread. If another thread will at some point need access to this
+ // thread information it should be given a referenced pointer to
+ // the IPalObject stored within the CPalThread.
+ //
+
+ extern pthread_key_t thObjKey;
+
+ CPalThread *InternalGetCurrentThread();
+}
+
+#endif // _PAL_TLS_HPP
+
diff --git a/src/pal/src/include/pal/unicode_data.h b/src/pal/src/include/pal/unicode_data.h
new file mode 100644
index 0000000000..0b7fe07447
--- /dev/null
+++ b/src/pal/src/include/pal/unicode_data.h
@@ -0,0 +1,69 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ include/pal/unicode_data.h
+
+Abstract:
+
+ Data, data retrieval function declarations.
+
+
+
+--*/
+
+#ifndef _UNICODE_DATA_H_
+#define _UNICODE_DATA_H_
+
+#include "pal/palinternal.h"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif // __cplusplus
+
+#if !HAVE_COREFOUNDATION
+
+typedef struct
+{
+ WCHAR nUnicodeValue;
+ WORD C1_TYPE_FLAGS;
+ WCHAR nOpposingCase; /* 0 if no opposing case. */
+ WORD rangeValue;
+} UnicodeDataRec;
+
+/* Global variables. */
+extern CONST UnicodeDataRec UnicodeData[];
+extern CONST UINT UNICODE_DATA_SIZE;
+extern CONST UINT UNICODE_DATA_DIRECT_ACCESS;
+
+/*++
+Function:
+ GetUnicodeData
+ This function is used to get information about a Unicode character.
+
+Parameters:
+nUnicodeValue
+ The numeric value of the Unicode character to get information about.
+pDataRec
+ The UnicodeDataRec to fill in with the data for the Unicode character.
+
+Return value:
+ TRUE if the Unicode character was found.
+
+--*/
+BOOL GetUnicodeData(INT nUnicodeValue, UnicodeDataRec *pDataRec);
+
+#endif /* !HAVE_COREFOUNDATION */
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif /* _UNICODE_DATA_H_ */
diff --git a/src/pal/src/include/pal/utf8.h b/src/pal/src/include/pal/utf8.h
new file mode 100644
index 0000000000..2516caafb0
--- /dev/null
+++ b/src/pal/src/include/pal/utf8.h
@@ -0,0 +1,53 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ include/pal/utf8.h
+
+Abstract:
+ Header file for UTF-8 conversion functions.
+
+Revision History:
+
+
+
+--*/
+
+#ifndef _PAL_UTF8_H_
+#define _PAL_UTF8_H_
+
+#include <pal/palinternal.h> /* for WCHAR */
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif // __cplusplus
+
+/*++
+Function :
+ UTF8ToUnicode
+
+ Convert a string from UTF-8 to UTF-16 (UCS-2)
+--*/
+int UTF8ToUnicode(LPCSTR lpSrcStr, int cchSrc, LPWSTR lpDestStr, int cchDest, DWORD dwFlags);
+
+
+/*++
+Function :
+ UnicodeToUTF8
+
+ Convert a string from UTF-16 (UCS-2) to UTF-8
+--*/
+int UnicodeToUTF8(LPCWSTR lpSrcStr, int cchSrc, LPSTR lpDestStr, int cchDest);
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+
+#endif /* _PAL_UTF8_H_ */
diff --git a/src/pal/src/include/pal/utils.h b/src/pal/src/include/pal/utils.h
new file mode 100644
index 0000000000..3ddad4ae2f
--- /dev/null
+++ b/src/pal/src/include/pal/utils.h
@@ -0,0 +1,157 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ include/pal/utils.h
+
+Abstract:
+ Miscellaneous helper functions for the PAL, which don't fit anywhere else
+
+
+
+--*/
+
+#ifndef _PAL_UTILS_H_
+#define _PAL_UTILS_H_
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif // __cplusplus
+
+/*++
+Function:
+ UTIL_inverse_wcspbrk
+
+ Opposite of wcspbrk : searches a string for the first character NOT in the
+ given set
+
+Parameters :
+ LPWSTR lpwstr : string to search
+ LPCWSTR charset : list of characters to search for
+
+Return value :
+ pointer to first character of lpwstr that isn't in the set
+ NULL if all characters are in the set
+--*/
+LPWSTR UTIL_inverse_wcspbrk(LPWSTR lpwstr, LPCWSTR charset);
+
+/*++
+Function :
+ UTIL_IsReadOnlyBitsSet
+
+ Takes a struct stat *
+ Returns true if the file is read only,
+--*/
+BOOL UTIL_IsReadOnlyBitsSet( struct stat * stat_data );
+
+/*++
+Function :
+ UTIL_IsExecuteBitsSet
+
+ Takes a struct stat *
+ Returns true if the file is executable.
+--*/
+BOOL UTIL_IsExecuteBitsSet( struct stat * stat_data );
+
+
+/*++
+Function :
+ UTIL_WCToMB_Alloc
+
+ Converts a wide string to a multibyte string, allocating the required buffer
+
+Parameters :
+ LPCWSTR lpWideCharStr : string to convert
+ int cchWideChar : number of wide characters to convert
+ (-1 to convert a complete null-termnated string)
+
+Return Value :
+ newly allocated buffer containing the converted string. Conversion is
+ performed using CP_ACP. Buffer is allocated with malloc(), release it
+ with free().
+ In case if failure, LastError will be set.
+--*/
+LPSTR UTIL_WCToMB_Alloc(LPCWSTR lpWideCharStr, int cchWideChar);
+
+/*++
+Function :
+ UTIL_MBToWC_Alloc
+
+ Converts a multibyte string to a wide string, allocating the required buffer
+
+Parameters :
+ LPCSTR lpMultiByteStr : string to convert
+ int cbMultiByte : number of bytes to convert
+ (-1 to convert a complete null-termnated string)
+
+Return Value :
+ newly allocated buffer containing the converted string. Conversion is
+ performed using CP_ACP. Buffer is allocated with malloc(), release it
+ with free().
+ In case if failure, LastError will be set.
+--*/
+LPWSTR UTIL_MBToWC_Alloc(LPCSTR lpMultiByteStr, int cbMultiByte);
+
+#if HAVE_VM_ALLOCATE
+#include <mach/kern_return.h>
+
+/*++
+Function:
+ UTIL_MachErrorToPalError
+
+ Maps a Mach kern_return_t to a Win32 error code.
+--*/
+DWORD UTIL_MachErrorToPalError(kern_return_t MachReturn);
+
+/*++
+Function:
+ UTIL_SetLastErrorFromMach
+
+ Sets Win32 LastError according to the argument Mach kern_return_t value,
+ provided it indicates an error. If the argument indicates success, does
+ not modify LastError.
+--*/
+void UTIL_SetLastErrorFromMach(kern_return_t MachReturn);
+
+#endif //HAVE_VM_ALLOCATE
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus
+class StringHolder
+ {
+ private:
+ LPSTR data;
+ public:
+ StringHolder() : data(NULL) { }
+ ~StringHolder()
+ {
+ PAL_free( data);
+ }
+
+ operator LPSTR () { return data;}
+
+ StringHolder& operator= (LPSTR value)
+ {
+ data = value;
+ return *this;
+ }
+
+ BOOL IsNull()
+ {
+ return data == NULL;
+ }
+
+ };
+#endif /* _PAL_UTILS_H_ */
diff --git a/src/pal/src/include/pal/virtual.h b/src/pal/src/include/pal/virtual.h
new file mode 100644
index 0000000000..a4e225281e
--- /dev/null
+++ b/src/pal/src/include/pal/virtual.h
@@ -0,0 +1,208 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ include/pal/virtual.h
+
+Abstract:
+ Header file for virtual memory management.
+
+
+
+--*/
+
+#ifndef _PAL_VIRTUAL_H_
+#define _PAL_VIRTUAL_H_
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif // __cplusplus
+
+typedef struct _CMI {
+
+ struct _CMI * pNext; /* Link to the next entry. */
+ struct _CMI * pPrevious; /* Link to the previous entry. */
+
+ UINT_PTR startBoundary; /* Starting location of the region. */
+ SIZE_T memSize; /* Size of the entire region.. */
+
+ DWORD accessProtection; /* Initial allocation access protection. */
+ DWORD allocationType; /* Initial allocation type. */
+
+ BYTE * pAllocState; /* Individual allocation type tracking for each */
+ /* page in the region. */
+
+ BYTE * pProtectionState; /* Individual allocation type tracking for each */
+ /* page in the region. */
+
+} CMI, * PCMI;
+
+enum VIRTUAL_CONSTANTS
+{
+ /* Allocation type. */
+ VIRTUAL_COMMIT_ALL_BITS = 0xFF,
+ VIRTUAL_RESERVE_ALL_BITS = 0x0,
+
+ /* Protection Type. */
+ VIRTUAL_READONLY,
+ VIRTUAL_READWRITE,
+ VIRTUAL_EXECUTE_READWRITE,
+ VIRTUAL_NOACCESS,
+ VIRTUAL_EXECUTE,
+ VIRTUAL_EXECUTE_READ,
+
+ /* Page manipulation constants. */
+#ifdef __sparc__
+ VIRTUAL_PAGE_SIZE = 0x2000,
+#else // __sparc__
+ VIRTUAL_PAGE_SIZE = 0x1000,
+#endif // __sparc__
+ VIRTUAL_PAGE_MASK = VIRTUAL_PAGE_SIZE - 1,
+ BOUNDARY_64K = 0xffff
+};
+
+/*++
+Function :
+ VIRTUALInitialize
+
+ Initialize the critical sections.
+
+Return value:
+ TRUE if initialization succeeded
+ FALSE otherwise.
+--*/
+BOOL VIRTUALInitialize(bool initializeExecutableMemoryAllocator);
+
+/*++
+Function :
+ VIRTUALCleanup
+
+ Deletes the critical sections.
+
+--*/
+void VIRTUALCleanup( void );
+
+#ifdef __cplusplus
+}
+
+/*++
+Class:
+ ExecutableMemoryAllocator
+
+ This class implements a virtual memory allocator for JIT'ed code.
+ The purpose of this allocator is to opportunistically reserve a chunk of virtual memory
+ that is located near the coreclr library (within 2GB range) that can be later used by
+ JIT. Having executable memory close to the coreclr library allows JIT to generate more
+ efficient code (by avoiding usage of jump stubs) and thus it can significantly improve
+ performance of the application.
+
+ This allocator is integrated with the VirtualAlloc/Reserve code. If VirtualAlloc has been
+ called with the MEM_RESERVE_EXECUTABLE flag then it will first try to obtain the requested size
+ of virtual memory from ExecutableMemoryAllocator. If ExecutableMemoryAllocator runs out of
+ the reserved memory (or fails to allocate it during initialization) then VirtualAlloc/Reserve code
+ will simply fall back to reserving memory using OS APIs.
+
+ Notes:
+ - the memory allocated by this class is NOT committed by default. It is responsibility
+ of the caller to commit the virtual memory before accessing it.
+ - in addition, this class does not provide ability to free the reserved memory. The caller
+ has full control of the memory it got from this allocator (i.e. the caller becomes
+ the owner of the allocated memory), so it is caller's responsibility to free the memory
+ if it is no longer needed.
+--*/
+class ExecutableMemoryAllocator
+{
+public:
+ /*++
+ Function:
+ Initialize
+
+ This function initializes the allocator. It should be called early during process startup
+ (when process address space is pretty much empty) in order to have a chance to reserve
+ sufficient amount of memory that is close to the coreclr library.
+ --*/
+ void Initialize();
+
+ /*++
+ Function:
+ AllocateMemory
+
+ This function attempts to allocate the requested amount of memory from its reserved virtual
+ address space. The function will return NULL if the allocation request cannot
+ be satisfied by the memory that is currently available in the allocator.
+ --*/
+ void* AllocateMemory(SIZE_T allocationSize);
+
+private:
+ /*++
+ Function:
+ TryReserveInitialMemory
+
+ This function is called during initialization. It opportunistically tries to reserve
+ a large chunk of virtual memory that can be later used to store JIT'ed code.
+ --*/
+ void TryReserveInitialMemory();
+
+ /*++
+ Function:
+ GenerateRandomStartOffset
+
+ This function returns a random offset (in multiples of the virtual page size)
+ at which the allocator should start allocating memory from its reserved memory range.
+ --*/
+ int32_t GenerateRandomStartOffset();
+
+private:
+ // There does not seem to be an easy way find the size of a library on Unix.
+ // So this constant represents an approximation of the libcoreclr size (on debug build)
+ // that can be used to calculate an approximate location of the memory that
+ // is in 2GB range from the coreclr library. In addition, having precise size of libcoreclr
+ // is not necessary for the calculations.
+ const int32_t CoreClrLibrarySize = 100 * 1024 * 1024;
+
+ // This constant represent the max size of the virtual memory that this allocator
+ // will try to reserve during initialization. We want all JIT-ed code and the
+ // entire libcoreclr to be located in a 2GB range.
+ const int32_t MaxExecutableMemorySize = 0x7FFF0000 - CoreClrLibrarySize;
+
+ // Start address of the reserved virtual address space
+ void* m_startAddress;
+
+ // Next available address in the reserved address space
+ void* m_nextFreeAddress;
+
+ // Total size of the virtual memory that the allocator has been able to
+ // reserve during its initialization.
+ int32_t m_totalSizeOfReservedMemory;
+
+ // Remaining size of the reserved virtual memory that can be used to satisfy allocation requests.
+ int32_t m_remainingReservedMemory;
+};
+
+#endif // __cplusplus
+
+/*++
+Function :
+ ReserveMemoryFromExecutableAllocator
+
+ This function is used to reserve a region of virual memory (not commited)
+ that is located close to the coreclr library. The memory comes from the virtual
+ address range that is managed by ExecutableMemoryAllocator.
+--*/
+void* ReserveMemoryFromExecutableAllocator(CorUnix::CPalThread* pthrCurrent, SIZE_T allocationSize);
+
+#endif /* _PAL_VIRTUAL_H_ */
+
+
+
+
+
+
+
diff --git a/src/pal/src/init/pal.cpp b/src/pal/src/init/pal.cpp
new file mode 100644
index 0000000000..a5edb36428
--- /dev/null
+++ b/src/pal/src/init/pal.cpp
@@ -0,0 +1,1480 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ init/pal.cpp
+
+Abstract:
+
+ Implementation of PAL exported functions not part of the Win32 API.
+
+
+
+--*/
+
+#include "pal/thread.hpp"
+#include "pal/synchobjects.hpp"
+#include "pal/procobj.hpp"
+#include "pal/cs.hpp"
+#include "pal/file.hpp"
+#include "pal/map.hpp"
+#include "../objmgr/shmobjectmanager.hpp"
+#include "pal/seh.hpp"
+#include "pal/palinternal.h"
+#include "pal/dbgmsg.h"
+#include "pal/sharedmemory.h"
+#include "pal/shmemory.h"
+#include "pal/process.h"
+#include "../thread/procprivate.hpp"
+#include "pal/module.h"
+#include "pal/virtual.h"
+#include "pal/misc.h"
+#include "pal/environ.h"
+#include "pal/utils.h"
+#include "pal/debug.h"
+#include "pal/locale.h"
+#include "pal/init.h"
+#include "pal/stackstring.hpp"
+
+#if HAVE_MACH_EXCEPTIONS
+#include "../exception/machexception.h"
+#endif
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <pwd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/resource.h>
+#include <sys/stat.h>
+#include <limits.h>
+#include <string.h>
+#include <fcntl.h>
+
+#if HAVE_POLL
+#include <poll.h>
+#else
+#include "pal/fakepoll.h"
+#endif // HAVE_POLL
+
+#if defined(__APPLE__)
+#include <sys/sysctl.h>
+int CacheLineSize;
+#endif //__APPLE__
+
+#ifdef __APPLE__
+#include <mach-o/dyld.h>
+#endif // __APPLE__
+
+#ifdef __NetBSD__
+#include <sys/cdefs.h>
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#include <kvm.h>
+#endif
+
+using namespace CorUnix;
+
+//
+// $$TODO The C++ compiler doesn't like pal/cruntime.h so duplicate the
+// necessary prototype here
+//
+
+extern "C" BOOL CRTInitStdStreams( void );
+
+
+SET_DEFAULT_DEBUG_CHANNEL(PAL);
+
+Volatile<INT> init_count = 0;
+Volatile<BOOL> shutdown_intent = 0;
+Volatile<LONG> g_coreclrInitialized = 0;
+static BOOL g_fThreadDataAvailable = FALSE;
+static pthread_mutex_t init_critsec_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+/* critical section to protect access to init_count. This is allocated on the
+ very first PAL_Initialize call, and is freed afterward. */
+static PCRITICAL_SECTION init_critsec = NULL;
+
+static int Initialize(int argc, const char *const argv[], DWORD flags);
+static BOOL INIT_IncreaseDescriptorLimit(void);
+static LPWSTR INIT_FormatCommandLine (int argc, const char * const *argv);
+static LPWSTR INIT_FindEXEPath(LPCSTR exe_name);
+
+#ifdef _DEBUG
+extern void PROCDumpThreadList(void);
+#endif
+
+#if defined(__APPLE__)
+static bool RunningNatively()
+{
+ int ret = 0;
+ size_t sz = sizeof(ret);
+ if (sysctlbyname("sysctl.proc_native", &ret, &sz, NULL, 0) != 0)
+ {
+ // if the sysctl failed, we'll assume this OS does not support
+ // binary translation - so we must be running natively.
+ return true;
+ }
+ return ret != 0;
+}
+#endif // __APPLE__
+
+/*++
+Function:
+ PAL_Initialize
+
+Abstract:
+ This function is the first function of the PAL to be called.
+ Internal structure initialization is done here. It could be called
+ several time by the same process, a reference count is kept.
+
+Return:
+ 0 if successful
+ -1 if it failed
+
+--*/
+int
+PALAPI
+PAL_Initialize(
+ int argc,
+ const char *const argv[])
+{
+ return Initialize(argc, argv, PAL_INITIALIZE);
+}
+
+/*++
+Function:
+ PAL_InitializeDLL
+
+Abstract:
+ Initializes the non-runtime DLLs/modules like the DAC and SOS.
+
+Return:
+ 0 if successful
+ -1 if it failed
+
+--*/
+int
+PALAPI
+PAL_InitializeDLL()
+{
+ return Initialize(0, NULL, PAL_INITIALIZE_DLL);
+}
+
+/*++
+Function:
+ Initialize
+
+Abstract:
+ Common PAL initialization function.
+
+Return:
+ 0 if successful
+ -1 if it failed
+
+--*/
+int
+Initialize(
+ int argc,
+ const char *const argv[],
+ DWORD flags)
+{
+ PAL_ERROR palError = ERROR_GEN_FAILURE;
+ CPalThread *pThread = NULL;
+ CSharedMemoryObjectManager *pshmom = NULL;
+ LPWSTR command_line = NULL;
+ LPWSTR exe_path = NULL;
+ int retval = -1;
+ bool fFirstTimeInit = false;
+
+ /* the first ENTRY within the first call to PAL_Initialize is a special
+ case, since debug channels are not initialized yet. So in that case the
+ ENTRY will be called after the DBG channels initialization */
+ ENTRY_EXTERNAL("PAL_Initialize(argc = %d argv = %p)\n", argc, argv);
+
+ /*Firstly initiate a lastError */
+ SetLastError(ERROR_GEN_FAILURE);
+
+#ifdef __APPLE__
+ if (!RunningNatively())
+ {
+ SetLastError(ERROR_BAD_FORMAT);
+ goto exit;
+ }
+#endif // __APPLE__
+
+ CriticalSectionSubSysInitialize();
+
+ if(NULL == init_critsec)
+ {
+ pthread_mutex_lock(&init_critsec_mutex); // prevents race condition of two threads
+ // initializing the critical section.
+ if(NULL == init_critsec)
+ {
+ static CRITICAL_SECTION temp_critsec;
+
+ // Want this critical section to NOT be internal to avoid the use of unsafe region markers.
+ InternalInitializeCriticalSectionAndSpinCount(&temp_critsec, 0, false);
+
+ if(NULL != InterlockedCompareExchangePointer(&init_critsec, &temp_critsec, NULL))
+ {
+ // Another thread got in before us! shouldn't happen, if the PAL
+ // isn't initialized there shouldn't be any other threads
+ WARN("Another thread initialized the critical section\n");
+ InternalDeleteCriticalSection(&temp_critsec);
+ }
+ }
+ pthread_mutex_unlock(&init_critsec_mutex);
+ }
+
+ InternalEnterCriticalSection(pThread, init_critsec); // here pThread is always NULL
+
+ if (init_count == 0)
+ {
+ // Set our pid and sid.
+ gPID = getpid();
+ gSID = getsid(gPID);
+
+ fFirstTimeInit = true;
+
+ // Initialize the TLS lookaside cache
+ if (FALSE == TLSInitialize())
+ {
+ goto done;
+ }
+
+ // Initialize the environment.
+ if (FALSE == EnvironInitialize())
+ {
+ goto CLEANUP0;
+ }
+
+ // Initialize debug channel settings before anything else.
+ // This depends on the environment, so it must come after
+ // EnvironInitialize.
+ if (FALSE == DBG_init_channels())
+ {
+ goto CLEANUP0;
+ }
+
+#if _DEBUG
+ // Verify that our page size is what we think it is. If it's
+ // different, we can't run.
+ if (VIRTUAL_PAGE_SIZE != getpagesize())
+ {
+ ASSERT("VIRTUAL_PAGE_SIZE is incorrect for this system!\n"
+ "Change include/pal/virtual.h and clr/src/inc/stdmacros.h "
+ "to reflect the correct page size of %d.\n", getpagesize());
+ }
+#endif // _DEBUG
+
+ if (!INIT_IncreaseDescriptorLimit())
+ {
+ ERROR("Unable to increase the file descriptor limit!\n");
+ // We can continue if this fails; we'll just have problems if
+ // we use large numbers of threads or have many open files.
+ }
+
+ SharedMemoryManager::StaticInitialize();
+
+ /* initialize the shared memory infrastructure */
+ if (!SHMInitialize())
+ {
+ ERROR("Shared memory initialization failed!\n");
+ goto CLEANUP0;
+ }
+
+ //
+ // Initialize global process data
+ //
+
+ palError = InitializeProcessData();
+ if (NO_ERROR != palError)
+ {
+ ERROR("Unable to initialize process data\n");
+ goto CLEANUP1;
+ }
+
+#if HAVE_MACH_EXCEPTIONS
+ // Mach exception port needs to be set up before the thread
+ // data or threads are set up.
+ if (!SEHInitializeMachExceptions(flags))
+ {
+ ERROR("SEHInitializeMachExceptions failed!\n");
+ palError = ERROR_GEN_FAILURE;
+ goto CLEANUP1;
+ }
+#endif // HAVE_MACH_EXCEPTIONS
+
+ //
+ // Initialize global thread data
+ //
+
+ palError = InitializeGlobalThreadData();
+ if (NO_ERROR != palError)
+ {
+ ERROR("Unable to initialize thread data\n");
+ goto CLEANUP1;
+ }
+
+ //
+ // Allocate the initial thread data
+ //
+
+ palError = CreateThreadData(&pThread);
+ if (NO_ERROR != palError)
+ {
+ ERROR("Unable to create initial thread data\n");
+ goto CLEANUP1a;
+ }
+
+ PROCAddThread(pThread, pThread);
+
+ //
+ // Initialize mutex and condition variable used to synchronize the ending threads count
+ //
+
+ palError = InitializeEndingThreadsData();
+ if (NO_ERROR != palError)
+ {
+ ERROR("Unable to create ending threads data\n");
+ goto CLEANUP1b;
+ }
+
+ //
+ // It's now safe to access our thread data
+ //
+
+ g_fThreadDataAvailable = TRUE;
+
+ //
+ // Initialize module manager
+ //
+ if (FALSE == LOADInitializeModules())
+ {
+ ERROR("Unable to initialize module manager\n");
+ palError = ERROR_INTERNAL_ERROR;
+ goto CLEANUP1b;
+ }
+
+ //
+ // Initialize the object manager
+ //
+
+ pshmom = InternalNew<CSharedMemoryObjectManager>();
+ if (NULL == pshmom)
+ {
+ ERROR("Unable to allocate new object manager\n");
+ palError = ERROR_OUTOFMEMORY;
+ goto CLEANUP1b;
+ }
+
+ palError = pshmom->Initialize();
+ if (NO_ERROR != palError)
+ {
+ ERROR("object manager initialization failed!\n");
+ InternalDelete(pshmom);
+ goto CLEANUP1b;
+ }
+
+ g_pObjectManager = pshmom;
+
+ //
+ // Initialize the synchronization manager
+ //
+ g_pSynchronizationManager =
+ CPalSynchMgrController::CreatePalSynchronizationManager();
+
+ if (NULL == g_pSynchronizationManager)
+ {
+ palError = ERROR_NOT_ENOUGH_MEMORY;
+ ERROR("Failure creating synchronization manager\n");
+ goto CLEANUP1c;
+ }
+ }
+ else
+ {
+ pThread = InternalGetCurrentThread();
+ }
+
+ palError = ERROR_GEN_FAILURE;
+
+ if (argc > 0 && argv != NULL)
+ {
+ /* build the command line */
+ command_line = INIT_FormatCommandLine(argc, argv);
+ if (NULL == command_line)
+ {
+ ERROR("Error building command line\n");
+ goto CLEANUP1d;
+ }
+
+ /* find out the application's full path */
+ exe_path = INIT_FindEXEPath(argv[0]);
+ if (NULL == exe_path)
+ {
+ ERROR("Unable to find exe path\n");
+ goto CLEANUP1e;
+ }
+
+ if (NULL == command_line || NULL == exe_path)
+ {
+ ERROR("Failed to process command-line parameters!\n");
+ goto CLEANUP2;
+ }
+
+ palError = InitializeProcessCommandLine(
+ command_line,
+ exe_path);
+
+ if (NO_ERROR != palError)
+ {
+ ERROR("Unable to initialize command line\n");
+ goto CLEANUP2;
+ }
+
+ // InitializeProcessCommandLine took ownership of this memory.
+ command_line = NULL;
+
+#ifdef PAL_PERF
+ // Initialize the Profiling structure
+ if(FALSE == PERFInitialize(command_line, exe_path))
+ {
+ ERROR("Performance profiling initial failed\n");
+ goto CLEANUP2;
+ }
+ PERFAllocThreadInfo();
+#endif
+
+ if (!LOADSetExeName(exe_path))
+ {
+ ERROR("Unable to set exe name\n");
+ goto CLEANUP2;
+ }
+
+ // LOADSetExeName took ownership of this memory.
+ exe_path = NULL;
+ }
+
+ if (init_count == 0)
+ {
+ //
+ // Create the initial process and thread objects
+ //
+ palError = CreateInitialProcessAndThreadObjects(pThread);
+ if (NO_ERROR != palError)
+ {
+ ERROR("Unable to create initial process and thread objects\n");
+ goto CLEANUP2;
+ }
+
+ if (flags & PAL_INITIALIZE_SYNC_THREAD)
+ {
+ //
+ // Tell the synchronization manager to start its worker thread
+ //
+ palError = CPalSynchMgrController::StartWorker(pThread);
+ if (NO_ERROR != palError)
+ {
+ ERROR("Synch manager failed to start worker thread\n");
+ goto CLEANUP5;
+ }
+ }
+
+ palError = ERROR_GEN_FAILURE;
+
+ /* initialize structured exception handling stuff (signals, etc) */
+ if (FALSE == SEHInitialize(pThread, flags))
+ {
+ ERROR("Unable to initialize SEH support\n");
+ goto CLEANUP5;
+ }
+
+ if (FALSE == TIMEInitialize())
+ {
+ ERROR("Unable to initialize TIME support\n");
+ goto CLEANUP6;
+ }
+
+ /* Initialize the File mapping critical section. */
+ if (FALSE == MAPInitialize())
+ {
+ ERROR("Unable to initialize file mapping support\n");
+ goto CLEANUP6;
+ }
+
+ /* Initialize the Virtual* functions. */
+ bool initializeExecutableMemoryAllocator = (flags & PAL_INITIALIZE_EXEC_ALLOCATOR) != 0;
+ if (FALSE == VIRTUALInitialize(initializeExecutableMemoryAllocator))
+ {
+ ERROR("Unable to initialize virtual memory support\n");
+ goto CLEANUP10;
+ }
+
+ if (flags & PAL_INITIALIZE_STD_HANDLES)
+ {
+ /* create file objects for standard handles */
+ if (!FILEInitStdHandles())
+ {
+ ERROR("Unable to initialize standard file handles\n");
+ goto CLEANUP13;
+ }
+ }
+
+ if (FALSE == CRTInitStdStreams())
+ {
+ ERROR("Unable to initialize CRT standard streams\n");
+ goto CLEANUP15;
+ }
+
+ TRACE("First-time PAL initialization complete.\n");
+ init_count++;
+
+ /* Set LastError to a non-good value - functions within the
+ PAL startup may set lasterror to a nonzero value. */
+ SetLastError(NO_ERROR);
+ retval = 0;
+ }
+ else
+ {
+ init_count++;
+
+ // Behave the same wrt entering the PAL independent of whether this
+ // is the first call to PAL_Initialize or not. The first call implied
+ // PAL_Enter by virtue of creating the CPalThread for the current
+ // thread, and its starting state is to be in the PAL.
+ (void)PAL_Enter(PAL_BoundaryTop);
+
+ TRACE("Initialization count increases to %d\n", init_count.Load());
+
+ SetLastError(NO_ERROR);
+ retval = 0;
+ }
+ goto done;
+
+ /* No cleanup required for CRTInitStdStreams */
+CLEANUP15:
+ FILECleanupStdHandles();
+CLEANUP13:
+ VIRTUALCleanup();
+CLEANUP10:
+ MAPCleanup();
+CLEANUP6:
+ SEHCleanup();
+CLEANUP5:
+ PROCCleanupInitialProcess();
+CLEANUP2:
+ free(exe_path);
+CLEANUP1e:
+ free(command_line);
+CLEANUP1d:
+ // Cleanup synchronization manager
+CLEANUP1c:
+ // Cleanup object manager
+CLEANUP1b:
+ // Cleanup initial thread data
+CLEANUP1a:
+ // Cleanup global process data
+CLEANUP1:
+ SHMCleanup();
+CLEANUP0:
+ TLSCleanup();
+ ERROR("PAL_Initialize failed\n");
+ SetLastError(palError);
+done:
+#ifdef PAL_PERF
+ if( retval == 0)
+ {
+ PERFEnableProcessProfile();
+ PERFEnableThreadProfile(FALSE);
+ PERFCalibrate("Overhead of PERF entry/exit");
+ }
+#endif
+
+ InternalLeaveCriticalSection(pThread, init_critsec);
+
+ if (fFirstTimeInit && 0 == retval)
+ {
+ _ASSERTE(NULL != pThread);
+ }
+
+ if (retval != 0 && GetLastError() == ERROR_SUCCESS)
+ {
+ ASSERT("returning failure, but last error not set\n");
+ }
+
+#ifdef __APPLE__
+exit :
+#endif // __APPLE__
+ LOGEXIT("PAL_Initialize returns int %d\n", retval);
+ return retval;
+}
+
+
+/*++
+Function:
+ PAL_InitializeCoreCLR
+
+Abstract:
+ A replacement for PAL_Initialize when loading CoreCLR. Instead of taking a command line (which CoreCLR
+ instances aren't given anyway) the path into which the CoreCLR is installed is supplied instead. This is
+ cached so that PAL_GetPALDirectoryW can return it later.
+
+ This routine also makes sure the psuedo dynamic libraries PALRT and mscorwks have their initialization
+ methods called.
+
+Return:
+ ERROR_SUCCESS if successful
+ An error code, if it failed
+
+--*/
+PAL_ERROR
+PALAPI
+PAL_InitializeCoreCLR(const char *szExePath)
+{
+ // Fake up a command line to call PAL initialization with.
+ int result = Initialize(1, &szExePath, PAL_INITIALIZE_CORECLR);
+ if (result != 0)
+ {
+ return GetLastError();
+ }
+
+ // Check for a repeated call (this is a no-op).
+ if (InterlockedIncrement(&g_coreclrInitialized) > 1)
+ {
+ PAL_Enter(PAL_BoundaryTop);
+ return ERROR_SUCCESS;
+ }
+
+ // Now that the PAL is initialized it's safe to call the initialization methods for the code that used to
+ // be dynamically loaded libraries but is now statically linked into CoreCLR just like the PAL, i.e. the
+ // PAL RT and mscorwks.
+ if (!LOADInitializeCoreCLRModule())
+ {
+ return ERROR_DLL_INIT_FAILED;
+ }
+
+ if (!InitializeFlushProcessWriteBuffers())
+ {
+ return ERROR_GEN_FAILURE;
+ }
+
+ return ERROR_SUCCESS;
+}
+
+/*++
+Function:
+PAL_IsDebuggerPresent
+
+Abstract:
+This function should be used to determine if a debugger is attached to the process.
+--*/
+PALIMPORT
+BOOL
+PALAPI
+PAL_IsDebuggerPresent()
+{
+#if defined(__linux__)
+ BOOL debugger_present = FALSE;
+ char buf[2048];
+
+ int status_fd = open("/proc/self/status", O_RDONLY);
+ if (status_fd == -1)
+ {
+ return FALSE;
+ }
+ ssize_t num_read = read(status_fd, buf, sizeof(buf) - 1);
+
+ if (num_read > 0)
+ {
+ static const char TracerPid[] = "TracerPid:";
+ char *tracer_pid;
+
+ buf[num_read] = '\0';
+ tracer_pid = strstr(buf, TracerPid);
+ if (tracer_pid)
+ {
+ debugger_present = !!atoi(tracer_pid + sizeof(TracerPid) - 1);
+ }
+ }
+
+ close(status_fd);
+
+ return debugger_present;
+#elif defined(__APPLE__)
+ struct kinfo_proc info = {};
+ size_t size = sizeof(info);
+ int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, getpid() };
+ int ret = sysctl(mib, sizeof(mib)/sizeof(*mib), &info, &size, NULL, 0);
+
+ if (ret == 0)
+ return ((info.kp_proc.p_flag & P_TRACED) != 0);
+
+ return FALSE;
+#elif defined(__NetBSD__)
+ int traced;
+ kvm_t *kd;
+ int cnt;
+
+ struct kinfo_proc *info;
+
+ kd = kvm_open(NULL, NULL, NULL, KVM_NO_FILES, "kvm_open");
+ if (kd == NULL)
+ return FALSE;
+
+ info = kvm_getprocs(kd, KERN_PROC_PID, getpid(), &cnt);
+ if (info == NULL || cnt < 1)
+ {
+ kvm_close(kd);
+ return FALSE;
+ }
+
+ traced = info->kp_proc.p_slflag & PSL_TRACED;
+ kvm_close(kd);
+
+ if (traced != 0)
+ return TRUE;
+ else
+ return FALSE;
+#else
+ return FALSE;
+#endif
+}
+
+/*++
+Function:
+ PAL_EntryPoint
+
+Abstract:
+ This function should be used to wrap code that uses PAL library on thread that was not created by PAL.
+--*/
+PALIMPORT
+DWORD_PTR
+PALAPI
+PAL_EntryPoint(
+ IN LPTHREAD_START_ROUTINE lpStartAddress,
+ IN LPVOID lpParameter)
+{
+ CPalThread *pThread;
+ DWORD_PTR retval = (DWORD) -1;
+
+ ENTRY("PAL_EntryPoint(lpStartAddress=%p, lpParameter=%p)\n", lpStartAddress, lpParameter);
+
+ pThread = InternalGetCurrentThread();
+ if (NULL == pThread)
+ {
+ /* This function works only for thread that called PAL_Initialize for now. */
+ ERROR( "Unable to get the thread object.\n" );
+ goto done;
+ }
+
+ retval = (*lpStartAddress)(lpParameter);
+
+done:
+ LOGEXIT("PAL_EntryPoint returns int %d\n", retval);
+ return retval;
+}
+
+/*++
+Function:
+ PAL_Shutdown
+
+Abstract:
+ This function shuts down the PAL WITHOUT exiting the current process.
+--*/
+void
+PALAPI
+PAL_Shutdown(
+ void)
+{
+ TerminateCurrentProcessNoExit(FALSE /* bTerminateUnconditionally */);
+}
+
+/*++
+Function:
+ PAL_Terminate
+
+Abstract:
+ This function is the called when a thread has finished using the PAL
+ library. It shuts down PAL and exits the current process.
+--*/
+void
+PALAPI
+PAL_Terminate(
+ void)
+{
+ PAL_TerminateEx(0);
+}
+
+/*++
+Function:
+PAL_TerminateEx
+
+Abstract:
+This function is the called when a thread has finished using the PAL
+library. It shuts down PAL and exits the current process with
+the specified exit code.
+--*/
+void
+PALAPI
+PAL_TerminateEx(
+ int exitCode)
+{
+ ENTRY_EXTERNAL("PAL_TerminateEx()\n");
+
+ if (NULL == init_critsec)
+ {
+ /* note that these macros probably won't output anything, since the
+ debug channels haven't been initialized yet */
+ ASSERT("PAL_Initialize has never been called!\n");
+ LOGEXIT("PAL_Terminate returns.\n");
+ }
+
+ // Declare the beginning of shutdown
+ PALSetShutdownIntent();
+
+ LOGEXIT("PAL_TerminateEx is exiting the current process.\n");
+ exit(exitCode);
+}
+
+/*++
+Function:
+ PAL_InitializeDebug
+
+Abstract:
+ This function is the called when cordbg attaches to the process.
+--*/
+void
+PALAPI
+PAL_InitializeDebug(
+ void)
+{
+ PERF_ENTRY(PAL_InitializeDebug);
+ ENTRY("PAL_InitializeDebug()\n");
+#if HAVE_MACH_EXCEPTIONS
+ MachExceptionInitializeDebug();
+#endif
+ LOGEXIT("PAL_InitializeDebug returns\n");
+ PERF_EXIT(PAL_InitializeDebug);
+}
+
+/*++
+Function:
+ PALIsThreadDataInitialized
+
+Returns TRUE if startup has reached a point where thread data is available
+--*/
+BOOL PALIsThreadDataInitialized()
+{
+ return g_fThreadDataAvailable;
+}
+
+/*++
+Function:
+ PALCommonCleanup
+
+ Utility function to prepare for shutdown.
+
+--*/
+void
+PALCommonCleanup()
+{
+ static bool cleanupDone = false;
+
+ // Declare the beginning of shutdown
+ PALSetShutdownIntent();
+
+ if (!cleanupDone)
+ {
+ cleanupDone = true;
+
+ //
+ // Let the synchronization manager know we're about to shutdown
+ //
+ CPalSynchMgrController::PrepareForShutdown();
+
+ SharedMemoryManager::StaticClose();
+
+#ifdef _DEBUG
+ PROCDumpThreadList();
+#endif
+ }
+
+ // Mark that the PAL is uninitialized
+ init_count = 0;
+}
+
+BOOL PALIsShuttingDown()
+{
+ /* ROTORTODO: This function may be used to provide a reader/writer-like
+ mechanism (or a ref counting one) to prevent PAL APIs that need to access
+ PAL runtime data, from working when PAL is shutting down. Each of those API
+ should acquire a read access while executing. The shutting down code would
+ acquire a write lock, i.e. suspending any new incoming reader, and waiting
+ for the current readers to be done. That would allow us to get rid of the
+ dangerous suspend-all-other-threads at shutdown time */
+ return shutdown_intent;
+}
+
+void PALSetShutdownIntent()
+{
+ /* ROTORTODO: See comment in PALIsShuttingDown */
+ shutdown_intent = TRUE;
+}
+
+/*++
+Function:
+ PALInitLock
+
+Take the initializaiton critical section (init_critsec). necessary to serialize
+TerminateProcess along with PAL_Terminate and PAL_Initialize
+
+(no parameters)
+
+Return value :
+ TRUE if critical section existed (and was acquired)
+ FALSE if critical section doens't exist yet
+--*/
+BOOL PALInitLock(void)
+{
+ if(!init_critsec)
+ {
+ return FALSE;
+ }
+
+ CPalThread * pThread =
+ (PALIsThreadDataInitialized() ? InternalGetCurrentThread() : NULL);
+
+ InternalEnterCriticalSection(pThread, init_critsec);
+ return TRUE;
+}
+
+/*++
+Function:
+ PALInitUnlock
+
+Release the initialization critical section (init_critsec).
+
+(no parameters, no return value)
+--*/
+void PALInitUnlock(void)
+{
+ if(!init_critsec)
+ {
+ return;
+ }
+
+ CPalThread * pThread =
+ (PALIsThreadDataInitialized() ? InternalGetCurrentThread() : NULL);
+
+ InternalLeaveCriticalSection(pThread, init_critsec);
+}
+
+/* Internal functions *********************************************************/
+
+/*++
+Function:
+ INIT_IncreaseDescriptorLimit [internal]
+
+Abstract:
+ Calls setrlimit(2) to increase the maximum number of file descriptors
+ this process can open.
+
+Return value:
+ TRUE if the call to setrlimit succeeded; FALSE otherwise.
+--*/
+static BOOL INIT_IncreaseDescriptorLimit(void)
+{
+ struct rlimit rlp;
+ int result;
+
+ result = getrlimit(RLIMIT_NOFILE, &rlp);
+ if (result != 0)
+ {
+ return FALSE;
+ }
+ // Set our soft limit for file descriptors to be the same
+ // as the max limit.
+ rlp.rlim_cur = rlp.rlim_max;
+ result = setrlimit(RLIMIT_NOFILE, &rlp);
+ if (result != 0)
+ {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/*++
+Function:
+ INIT_FormatCommandLine [Internal]
+
+Abstract:
+ This function converts an array of arguments (argv) into a Unicode
+ command-line for use by GetCommandLineW
+
+Parameters :
+ int argc : number of arguments in argv
+ char **argv : argument list in an array of NULL-terminated strings
+
+Return value :
+ pointer to Unicode command line. This is a buffer allocated with malloc;
+ caller is responsible for freeing it with free()
+
+Note : not all peculiarities of Windows command-line processing are supported;
+
+-what is supported :
+ -arguments with white-space must be double quoted (we'll just double-quote
+ all arguments to simplify things)
+ -some characters must be escaped with \ : particularly, the double-quote,
+ to avoid confusion with the double-quotes at the start and end of
+ arguments, and \ itself, to avoid confusion with escape sequences.
+-what is not supported:
+ -under Windows, \\ is interpreted as an escaped \ ONLY if it's followed by
+ an escaped double-quote \". \\\" is passed to argv as \", but \\a is
+ passed to argv as \\a... there may be other similar cases
+ -there may be other characters which must be escaped
+--*/
+static LPWSTR INIT_FormatCommandLine (int argc, const char * const *argv)
+{
+ LPWSTR retval;
+ LPSTR command_line=NULL, command_ptr;
+ LPCSTR arg_ptr;
+ INT length, i,j;
+ BOOL bQuoted = FALSE;
+
+ /* list of characters that need no be escaped with \ when building the
+ command line. currently " and \ */
+ LPCSTR ESCAPE_CHARS="\"\\";
+
+ /* allocate temporary memory for the string. Play it safe :
+ double the length of each argument (in case they're composed
+ exclusively of escaped characters), and add 3 (for the double-quotes
+ and separating space). This is temporary anyway, we return a LPWSTR */
+ length=0;
+ for(i=0; i<argc; i++)
+ {
+ TRACE("argument %d is %s\n", i, argv[i]);
+ length+=3;
+ length+=strlen(argv[i])*2;
+ }
+ command_line = reinterpret_cast<LPSTR>(InternalMalloc(length));
+
+ if(!command_line)
+ {
+ ERROR("couldn't allocate memory for command line!\n");
+ return NULL;
+ }
+
+ command_ptr=command_line;
+ for(i=0; i<argc; i++)
+ {
+ /* double-quote at beginning of argument containing at least one space */
+ for(j = 0; (argv[i][j] != 0) && (!isspace((unsigned char) argv[i][j])); j++);
+
+ if (argv[i][j] != 0)
+ {
+ *command_ptr++='"';
+ bQuoted = TRUE;
+ }
+ /* process the argument one character at a time */
+ for(arg_ptr=argv[i]; *arg_ptr; arg_ptr++)
+ {
+ /* if character needs to be escaped, prepend a \ to it. */
+ if( strchr(ESCAPE_CHARS,*arg_ptr))
+ {
+ *command_ptr++='\\';
+ }
+
+ /* now we can copy the actual character over. */
+ *command_ptr++=*arg_ptr;
+ }
+ /* double-quote at end of argument; space to separate arguments */
+ if (bQuoted == TRUE)
+ {
+ *command_ptr++='"';
+ bQuoted = FALSE;
+ }
+ *command_ptr++=' ';
+ }
+ /* replace the last space with a NULL terminator */
+ command_ptr--;
+ *command_ptr='\0';
+
+ /* convert to Unicode */
+ i = MultiByteToWideChar(CP_ACP, 0,command_line, -1, NULL, 0);
+ if (i == 0)
+ {
+ ASSERT("MultiByteToWideChar failure\n");
+ free(command_line);
+ return NULL;
+ }
+
+ retval = reinterpret_cast<LPWSTR>(InternalMalloc((sizeof(WCHAR)*i)));
+ if(retval == NULL)
+ {
+ ERROR("can't allocate memory for Unicode command line!\n");
+ free(command_line);
+ return NULL;
+ }
+
+ if(!MultiByteToWideChar(CP_ACP, 0,command_line, i, retval, i))
+ {
+ ASSERT("MultiByteToWideChar failure\n");
+ free(retval);
+ retval = NULL;
+ }
+ else
+ TRACE("Command line is %s\n", command_line);
+
+ free(command_line);
+ return retval;
+}
+
+/*++
+Function:
+ INIT_FindEXEPath
+
+Abstract:
+ Determine the full, canonical path of the current executable by searching
+ $PATH.
+
+Parameters:
+ LPCSTR exe_name : file to search for
+
+Return:
+ pointer to buffer containing the full path. This buffer must be released
+ by the caller using free()
+
+Notes :
+ this function assumes that "exe_name" is in Unix style (no \)
+
+Notes 2:
+ This doesn't handle the case of directories with the desired name
+ (and directories are usually executable...)
+--*/
+static LPWSTR INIT_FindEXEPath(LPCSTR exe_name)
+{
+#ifndef __APPLE__
+ PathCharString real_path;
+ LPSTR env_path;
+ LPSTR path_ptr;
+ LPSTR cur_dir;
+ INT exe_name_length;
+ BOOL need_slash;
+ LPWSTR return_value;
+ INT return_size;
+ struct stat theStats;
+ /* if a path is specified, only search there */
+ if (strchr(exe_name, '/'))
+ {
+ if ( -1 == stat( exe_name, &theStats ) )
+ {
+ ERROR( "The file does not exist\n" );
+ return NULL;
+ }
+
+ if ( UTIL_IsExecuteBitsSet( &theStats ) )
+ {
+ if (!CorUnix::RealPathHelper(exe_name, real_path))
+ {
+ ERROR("realpath() failed!\n");
+ return NULL;
+ }
+
+ return_size=MultiByteToWideChar(CP_ACP,0,real_path,-1,NULL,0);
+ if ( 0 == return_size )
+ {
+ ASSERT("MultiByteToWideChar failure\n");
+ return NULL;
+ }
+
+ return_value = reinterpret_cast<LPWSTR>(InternalMalloc((return_size*sizeof(WCHAR))));
+ if ( NULL == return_value )
+ {
+ ERROR("Not enough memory to create full path\n");
+ return NULL;
+ }
+ else
+ {
+ if (!MultiByteToWideChar(CP_ACP, 0, real_path, -1,
+ return_value, return_size))
+ {
+ ASSERT("MultiByteToWideChar failure\n");
+ free(return_value);
+ return_value = NULL;
+ }
+ else
+ {
+ TRACE("full path to executable is %s\n", real_path.GetString());
+ }
+ }
+ return return_value;
+ }
+ }
+
+ /* no path was specified : search $PATH */
+
+ env_path = EnvironGetenv("PATH");
+ if (!env_path || *env_path=='\0')
+ {
+ WARN("$PATH isn't set.\n");
+ if (env_path != NULL)
+ {
+ free(env_path);
+ }
+
+ goto last_resort;
+ }
+
+ exe_name_length=strlen(exe_name);
+
+ cur_dir=env_path;
+
+ while (cur_dir)
+ {
+ LPSTR full_path;
+ struct stat theStats;
+
+ /* skip all leading ':' */
+ while (*cur_dir==':')
+ {
+ cur_dir++;
+ }
+ if (*cur_dir=='\0')
+ {
+ break;
+ }
+
+ /* cut string at next ':' */
+ path_ptr = strchr(cur_dir, ':');
+ if (path_ptr)
+ {
+ /* check if we need to add a '/' between the path and filename */
+ need_slash=(*(path_ptr-1))!='/';
+
+ /* NULL_terminate path element */
+ *path_ptr++='\0';
+ }
+ else
+ {
+ /* check if we need to add a '/' between the path and filename */
+ need_slash=(cur_dir[strlen(cur_dir)-1])!='/';
+ }
+
+ TRACE("looking for %s in %s\n", exe_name, cur_dir);
+
+ /* build tentative full file name */
+ int iLength = (strlen(cur_dir)+exe_name_length+2);
+ full_path = reinterpret_cast<LPSTR>(InternalMalloc(iLength));
+ if (!full_path)
+ {
+ ERROR("Not enough memory!\n");
+ break;
+ }
+
+ if (strcpy_s(full_path, iLength, cur_dir) != SAFECRT_SUCCESS)
+ {
+ ERROR("strcpy_s failed!\n");
+ free(full_path);
+ free(env_path);
+ return NULL;
+ }
+
+ if (need_slash)
+ {
+ if (strcat_s(full_path, iLength, "/") != SAFECRT_SUCCESS)
+ {
+ ERROR("strcat_s failed!\n");
+ free(full_path);
+ free(env_path);
+ return NULL;
+ }
+ }
+
+ if (strcat_s(full_path, iLength, exe_name) != SAFECRT_SUCCESS)
+ {
+ ERROR("strcat_s failed!\n");
+ free(full_path);
+ free(env_path);
+ return NULL;
+ }
+
+ /* see if file exists AND is executable */
+ if ( -1 != stat( full_path, &theStats ) )
+ {
+ if( UTIL_IsExecuteBitsSet( &theStats ) )
+ {
+ /* generate canonical path */
+ if (!CorUnix::RealPathHelper(full_path, real_path))
+ {
+ ERROR("realpath() failed!\n");
+ free(full_path);
+ free(env_path);
+ return NULL;
+ }
+ free(full_path);
+
+ return_size = MultiByteToWideChar(CP_ACP,0,real_path,-1,NULL,0);
+ if ( 0 == return_size )
+ {
+ ASSERT("MultiByteToWideChar failure\n");
+ free(env_path);
+ return NULL;
+ }
+
+ return_value = reinterpret_cast<LPWSTR>(InternalMalloc((return_size*sizeof(WCHAR))));
+ if ( NULL == return_value )
+ {
+ ERROR("Not enough memory to create full path\n");
+ free(env_path);
+ return NULL;
+ }
+
+ if (!MultiByteToWideChar(CP_ACP, 0, real_path, -1, return_value,
+ return_size))
+ {
+ ASSERT("MultiByteToWideChar failure\n");
+ free(return_value);
+ return_value = NULL;
+ }
+ else
+ {
+ TRACE("found %s in %s; real path is %s\n", exe_name,
+ cur_dir,real_path.GetString());
+ }
+
+ free(env_path);
+ return return_value;
+ }
+ }
+
+ /* file doesn't exist : keep searching */
+ free(full_path);
+
+ /* path_ptr is NULL if there's no ':' after this directory */
+ cur_dir=path_ptr;
+ }
+
+ free(env_path);
+ TRACE("No %s found in $PATH (%s)\n", exe_name, EnvironGetenv("PATH", FALSE));
+
+last_resort:
+ /* last resort : see if the executable is in the current directory. This is
+ possible if it comes from a exec*() call. */
+ if (0 == stat(exe_name,&theStats))
+ {
+ if ( UTIL_IsExecuteBitsSet( &theStats ) )
+ {
+ if (!CorUnix::RealPathHelper(exe_name, real_path))
+ {
+ ERROR("realpath() failed!\n");
+ return NULL;
+ }
+
+ return_size = MultiByteToWideChar(CP_ACP,0,real_path,-1,NULL,0);
+ if (0 == return_size)
+ {
+ ASSERT("MultiByteToWideChar failure\n");
+ return NULL;
+ }
+
+ return_value = reinterpret_cast<LPWSTR>(InternalMalloc((return_size*sizeof(WCHAR))));
+ if (NULL == return_value)
+ {
+ ERROR("Not enough memory to create full path\n");
+ return NULL;
+ }
+ else
+ {
+ if (!MultiByteToWideChar(CP_ACP, 0, real_path, -1,
+ return_value, return_size))
+ {
+ ASSERT("MultiByteToWideChar failure\n");
+ free(return_value);
+ return_value = NULL;
+ }
+ else
+ {
+ TRACE("full path to executable is %s\n", real_path.GetString());
+ }
+ }
+
+ return return_value;
+ }
+ else
+ {
+ ERROR("found %s in current directory, but it isn't executable!\n",
+ exe_name);
+ }
+ }
+ else
+ {
+ TRACE("last resort failed : executable %s is not in the current "
+ "directory\n",exe_name);
+ }
+
+ ERROR("executable %s not found anywhere!\n", exe_name);
+ return NULL;
+#else // !__APPLE__
+ // On the Mac we can just directly ask the OS for the executable path.
+
+ LPWSTR return_value;
+ INT return_size;
+
+ PathCharString exec_pathPS;
+ LPSTR exec_path = exec_pathPS.OpenStringBuffer(MAX_PATH);
+ uint32_t bufsize = exec_pathPS.GetCount();
+
+ if (-1 == _NSGetExecutablePath(exec_path, &bufsize))
+ {
+ exec_pathPS.CloseBuffer(exec_pathPS.GetCount());
+ exec_path = exec_pathPS.OpenStringBuffer(bufsize);
+ }
+
+ if (_NSGetExecutablePath(exec_path, &bufsize))
+ {
+ ASSERT("_NSGetExecutablePath failure\n");
+ return NULL;
+ }
+
+ exec_pathPS.CloseBuffer(bufsize);
+
+ return_size = MultiByteToWideChar(CP_ACP,0,exec_path,-1,NULL,0);
+ if (0 == return_size)
+ {
+ ASSERT("MultiByteToWideChar failure\n");
+ return NULL;
+ }
+
+ return_value = reinterpret_cast<LPWSTR>(InternalMalloc((return_size*sizeof(WCHAR))));
+ if (NULL == return_value)
+ {
+ ERROR("Not enough memory to create full path\n");
+ return NULL;
+ }
+ else
+ {
+ if (!MultiByteToWideChar(CP_ACP, 0, exec_path, -1,
+ return_value, return_size))
+ {
+ ASSERT("MultiByteToWideChar failure\n");
+ free(return_value);
+ return_value = NULL;
+ }
+ else
+ {
+ TRACE("full path to executable is %s\n", exec_path);
+ }
+ }
+
+ return return_value;
+#endif // !__APPLE__
+}
diff --git a/src/pal/src/init/sxs.cpp b/src/pal/src/init/sxs.cpp
new file mode 100644
index 0000000000..225f91684b
--- /dev/null
+++ b/src/pal/src/init/sxs.cpp
@@ -0,0 +1,322 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+
+
+--*/
+
+#include "pal/dbgmsg.h"
+#include "pal/thread.hpp"
+#include "../thread/procprivate.hpp"
+#include "pal/module.h"
+#include "pal/process.h"
+#include "pal/seh.hpp"
+
+using namespace CorUnix;
+
+#ifdef FEATURE_PAL_SXS
+
+SET_DEFAULT_DEBUG_CHANNEL(SXS);
+
+PAL_ERROR AllocatePalThread(CPalThread **ppThread);
+
+/************************* Enter *************************/
+
+/*++
+Function:
+ PAL_Enter
+
+Abstract:
+ This function needs to be called on a thread when it enters
+ a region of code that depends on this instance of the PAL
+ in the process, and the current thread may or may not be
+ known to the PAL. This function can fail (for something else
+ than an internal error) if this is the first time that the
+ current thread entered this PAL. Note that PAL_Initialize
+ implies a call to this function.
+
+ NOTE: This function must not modify LastError.
+--*/
+PAL_ERROR
+PALAPI
+PAL_Enter(PAL_Boundary boundary)
+{
+ ENTRY_EXTERNAL("PAL_Enter(boundary=%u)\n", boundary);
+
+ PAL_ERROR palError = ERROR_SUCCESS;
+ CPalThread *pThread = GetCurrentPalThread();
+ if (pThread != NULL)
+ {
+ palError = pThread->Enter(boundary);
+ }
+ else
+ {
+ // If this assert fires, we'll have to pipe this information so that
+ // CPalThread's RunPostCreateInitializers call to SEHEnable
+ // can know what direction.
+ _ASSERT_MSG(PAL_BoundaryTop == boundary, "How are we entering a PAL "
+ "thread for the first time not from the top? (boundary=%u)", boundary);
+
+ palError = AllocatePalThread(&pThread);
+ if (NO_ERROR != palError)
+ {
+ ERROR("Unable to allocate pal thread: error %d\n", palError);
+ }
+ }
+
+ LOGEXIT("PAL_Enter returns %d\n", palError);
+ return palError;
+}
+
+/*++
+Function:
+ CreateCurrentThreadData
+
+Abstract:
+ This function is called by the InternalGetOrCreateCurrentThread inlined
+ function to create the thread data when it is null meaning the thread has
+ never been in this PAL.
+
+Warning:
+ If the allocation fails, this function asserts and exits the process.
+--*/
+extern "C" CPalThread *
+CreateCurrentThreadData()
+{
+ CPalThread *pThread = NULL;
+
+ if (PALIsThreadDataInitialized()) {
+ PAL_ERROR palError = AllocatePalThread(&pThread);
+ if (NO_ERROR != palError)
+ {
+ ASSERT("Unable to allocate pal thread: error %d - aborting\n", palError);
+ PROCAbort();
+ }
+ }
+
+ return pThread;
+}
+
+PAL_ERROR
+AllocatePalThread(CPalThread **ppThread)
+{
+ CPalThread *pThread = NULL;
+
+ PAL_ERROR palError = CreateThreadData(&pThread);
+ if (NO_ERROR != palError)
+ {
+ goto exit;
+ }
+
+ HANDLE hThread;
+ palError = CreateThreadObject(pThread, pThread, &hThread);
+ if (NO_ERROR != palError)
+ {
+ pthread_setspecific(thObjKey, NULL);
+ pThread->ReleaseThreadReference();
+ goto exit;
+ }
+
+ // Like CreateInitialProcessAndThreadObjects, we do not need this
+ // thread handle, since we're not returning it to anyone who will
+ // possibly release it.
+ (void)g_pObjectManager->RevokeHandle(pThread, hThread);
+
+ PROCAddThread(pThread, pThread);
+
+exit:
+ *ppThread = pThread;
+ return palError;
+}
+
+PALIMPORT
+DWORD
+PALAPI
+PAL_EnterTop()
+{
+ return PAL_Enter(PAL_BoundaryTop);
+}
+
+
+/*++
+Function:
+ PAL_Reenter
+
+Abstract:
+ This function needs to be called on a thread when it enters
+ a region of code that depends on this instance of the PAL
+ in the process, and the current thread is already known to
+ the PAL.
+
+ NOTE: This function must not modify LastError.
+--*/
+VOID
+PALAPI
+PAL_Reenter(PAL_Boundary boundary)
+{
+ ENTRY_EXTERNAL("PAL_Reenter(boundary=%u)\n", boundary);
+
+ CPalThread *pThread = GetCurrentPalThread();
+ if (pThread == NULL)
+ {
+ ASSERT("PAL_Reenter called on a thread unknown to this PAL\n");
+ }
+
+ // We ignore the return code. This call should only fail on internal
+ // error, and we assert at the actual failure.
+ pThread->Enter(boundary);
+
+ LOGEXIT("PAL_Reenter returns\n");
+}
+
+/*++
+Function:
+ PAL_HasEntered
+
+Abstract:
+ This function can be called to determine if the thread has entered the
+ PAL through PAL_Enter or related calls.
+--*/
+BOOL
+PALAPI
+PAL_HasEntered()
+{
+ ENTRY_EXTERNAL("PAL_HasEntered()\n");
+
+ CPalThread *pThread = GetCurrentPalThread();
+ if (pThread == NULL)
+ {
+ ASSERT("PAL_Reenter called on a thread unknown to this PAL\n");
+ }
+
+ LOGEXIT("PAL_HasEntered returned\n");
+
+ return pThread->IsInPal();
+}
+
+/*++
+Function:
+ PAL_ReenterForEH
+
+Abstract:
+ This function needs to be called on a thread when it enters
+ a region of code that depends on this instance of the PAL
+ in the process, and it is unknown whether the current thread
+ is already running in the PAL. Returns TRUE if and only if
+ the thread was not running in the PAL previously.
+
+ NOTE: This function must not modify LastError.
+--*/
+BOOL
+PALAPI
+PAL_ReenterForEH()
+{
+ // Only trace if we actually reenter (otherwise, too verbose)
+ // ENTRY_EXTERNAL("PAL_ReenterForEH()\n");
+ // Thus we have to split up what ENTRY_EXTERNAL does.
+ CHECK_STACK_ALIGN;
+
+ BOOL fEntered = FALSE;
+
+ CPalThread *pThread = GetCurrentPalThread();
+ if (pThread == NULL)
+ {
+ ASSERT("PAL_ReenterForEH called on a thread unknown to this PAL\n");
+ }
+ else if (!pThread->IsInPal())
+ {
+#if _ENABLE_DEBUG_MESSAGES_
+ DBG_PRINTF(DLI_ENTRY, defdbgchan, TRUE)("PAL_ReenterForEH()\n");
+#endif
+
+ // We ignore the return code. This call should only fail on internal
+ // error, and we assert at the actual failure.
+ pThread->Enter(PAL_BoundaryEH);
+ fEntered = TRUE;
+ LOGEXIT("PAL_ReenterForEH returns TRUE\n");
+ }
+ else
+ {
+ // LOGEXIT("PAL_ReenterForEH returns FALSE\n");
+ }
+
+ return fEntered;
+}
+
+PAL_ERROR CPalThread::Enter(PAL_Boundary /* boundary */)
+{
+ if (m_fInPal)
+ {
+ WARN("Enter called on a thread that already runs in this PAL\n");
+ return NO_ERROR;
+ }
+ m_fInPal = TRUE;
+
+ return ERROR_SUCCESS;
+}
+
+
+/************************* Leave *************************/
+
+/*++
+Function:
+ PAL_Leave
+
+Abstract:
+ This function needs to be called on a thread when it leaves a region
+ of code that depends on this instance of the PAL in the process.
+
+ NOTE: This function must not modify LastError.
+--*/
+VOID
+PALAPI
+PAL_Leave(PAL_Boundary boundary)
+{
+ ENTRY("PAL_Leave(boundary=%u)\n", boundary);
+
+ CPalThread *pThread = GetCurrentPalThread();
+ // We ignore the return code. This call should only fail on internal
+ // error, and we assert at the actual failure.
+ pThread->Leave(boundary);
+
+ LOGEXIT("PAL_Leave returns\n");
+}
+
+PALIMPORT
+VOID
+PALAPI
+PAL_LeaveBottom()
+{
+ PAL_Leave(PAL_BoundaryBottom);
+}
+
+PALIMPORT
+VOID
+PALAPI
+PAL_LeaveTop()
+{
+ PAL_Leave(PAL_BoundaryTop);
+}
+
+
+PAL_ERROR CPalThread::Leave(PAL_Boundary /* boundary */)
+{
+ if (!m_fInPal)
+ {
+ WARN("Leave called on a thread that is not running in this PAL\n");
+ return ERROR_NOT_SUPPORTED;
+ }
+
+ PAL_ERROR palError = ERROR_SUCCESS;
+
+ m_fInPal = FALSE;
+
+ return palError;
+}
+
+#endif // FEATURE_PAL_SXS
diff --git a/src/pal/src/loader/module.cpp b/src/pal/src/loader/module.cpp
new file mode 100644
index 0000000000..a4fc4949e4
--- /dev/null
+++ b/src/pal/src/loader/module.cpp
@@ -0,0 +1,1771 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ module.c
+
+Abstract:
+
+ Implementation of module related functions in the Win32 API
+
+
+
+--*/
+
+#include "pal/thread.hpp"
+#include "pal/malloc.hpp"
+#include "pal/file.hpp"
+#include "pal/palinternal.h"
+#include "pal/dbgmsg.h"
+#include "pal/module.h"
+#include "pal/cs.hpp"
+#include "pal/process.h"
+#include "pal/file.h"
+#include "pal/utils.h"
+#include "pal/init.h"
+#include "pal/modulename.h"
+#include "pal/environ.h"
+#include "pal/virtual.h"
+#include "pal/map.hpp"
+#include "pal/stackstring.hpp"
+
+#include <sys/param.h>
+#include <errno.h>
+#include <string.h>
+#include <limits.h>
+#if NEED_DLCOMPAT
+#include "dlcompat.h"
+#else // NEED_DLCOMPAT
+#include <dlfcn.h>
+#endif // NEED_DLCOMPAT
+#include <stdlib.h>
+
+#ifdef __APPLE__
+#include <mach-o/dyld.h>
+#include <mach-o/loader.h>
+#endif // __APPLE__
+
+#include <sys/types.h>
+#include <sys/mman.h>
+
+#if HAVE_GNU_LIBNAMES_H
+#include <gnu/lib-names.h>
+#endif
+
+using namespace CorUnix;
+
+SET_DEFAULT_DEBUG_CHANNEL(LOADER);
+
+// In safemath.h, Template SafeInt uses macro _ASSERTE, which need to use variable
+// defdbgchan defined by SET_DEFAULT_DEBUG_CHANNEL. Therefore, the include statement
+// should be placed after the SET_DEFAULT_DEBUG_CHANNEL(LOADER)
+#include <safemath.h>
+
+/* macro definitions **********************************************************/
+
+/* get the full name of a module if available, and the short name otherwise*/
+#define MODNAME(x) ((x)->lib_name)
+
+/* Which path should FindLibrary search? */
+#if defined(__APPLE__)
+#define LIBSEARCHPATH "DYLD_LIBRARY_PATH"
+#else
+#define LIBSEARCHPATH "LD_LIBRARY_PATH"
+#endif
+
+#define LIBC_NAME_WITHOUT_EXTENSION "libc"
+
+/* static variables ***********************************************************/
+
+/* critical section that regulates access to the module list */
+CRITICAL_SECTION module_critsec;
+
+/* always the first, in the in-load-order list */
+MODSTRUCT exe_module;
+MODSTRUCT *pal_module = nullptr;
+
+char * g_szCoreCLRPath = nullptr;
+
+int MaxWCharToAcpLength = 3;
+
+/* static function declarations ***********************************************/
+
+template<class TChar> static bool LOADVerifyLibraryPath(const TChar *libraryPath);
+static bool LOADConvertLibraryPathWideStringToMultibyteString(
+ LPCWSTR wideLibraryPath,
+ LPSTR multibyteLibraryPath,
+ INT *multibyteLibraryPathLengthRef);
+static BOOL LOADValidateModule(MODSTRUCT *module);
+static LPWSTR LOADGetModuleFileName(MODSTRUCT *module);
+static MODSTRUCT *LOADAddModule(void *dl_handle, LPCSTR libraryNameOrPath);
+static void *LOADLoadLibraryDirect(LPCSTR libraryNameOrPath);
+static BOOL LOADFreeLibrary(MODSTRUCT *module, BOOL fCallDllMain);
+static HMODULE LOADRegisterLibraryDirect(void *dl_handle, LPCSTR libraryNameOrPath, BOOL fDynamic);
+static HMODULE LOADLoadLibrary(LPCSTR shortAsciiName, BOOL fDynamic);
+static BOOL LOADCallDllMainSafe(MODSTRUCT *module, DWORD dwReason, LPVOID lpReserved);
+
+/* API function definitions ***************************************************/
+
+/*++
+Function:
+ LoadLibraryA
+
+See MSDN doc.
+--*/
+HMODULE
+PALAPI
+LoadLibraryA(
+ IN LPCSTR lpLibFileName)
+{
+ return LoadLibraryExA(lpLibFileName, nullptr, 0);
+}
+
+/*++
+Function:
+ LoadLibraryW
+
+See MSDN doc.
+--*/
+HMODULE
+PALAPI
+LoadLibraryW(
+ IN LPCWSTR lpLibFileName)
+{
+ return LoadLibraryExW(lpLibFileName, nullptr, 0);
+}
+
+/*++
+Function:
+LoadLibraryExA
+
+See MSDN doc.
+--*/
+HMODULE
+PALAPI
+LoadLibraryExA(
+ IN LPCSTR lpLibFileName,
+ IN /*Reserved*/ HANDLE hFile,
+ IN DWORD dwFlags)
+{
+ if (dwFlags != 0)
+ {
+ // UNIXTODO: Implement this!
+ ASSERT("Needs Implementation!!!");
+ return nullptr;
+ }
+
+ LPSTR lpstr = nullptr;
+ HMODULE hModule = nullptr;
+
+ PERF_ENTRY(LoadLibraryA);
+ ENTRY("LoadLibraryExA (lpLibFileName=%p (%s)) \n",
+ (lpLibFileName) ? lpLibFileName : "NULL",
+ (lpLibFileName) ? lpLibFileName : "NULL");
+
+ if (!LOADVerifyLibraryPath(lpLibFileName))
+ {
+ goto Done;
+ }
+
+ /* do the Dos/Unix conversion on our own copy of the name */
+ lpstr = strdup(lpLibFileName);
+ if (!lpstr)
+ {
+ ERROR("strdup failure!\n");
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ goto Done;
+ }
+ FILEDosToUnixPathA(lpstr);
+
+ hModule = LOADLoadLibrary(lpstr, TRUE);
+
+ /* let LOADLoadLibrary call SetLastError */
+ Done:
+ if (lpstr != nullptr)
+ {
+ free(lpstr);
+ }
+
+ LOGEXIT("LoadLibraryExA returns HMODULE %p\n", hModule);
+ PERF_EXIT(LoadLibraryExA);
+ return hModule;
+
+}
+
+/*++
+Function:
+LoadLibraryExW
+
+See MSDN doc.
+--*/
+HMODULE
+PALAPI
+LoadLibraryExW(
+ IN LPCWSTR lpLibFileName,
+ IN /*Reserved*/ HANDLE hFile,
+ IN DWORD dwFlags)
+{
+ if (dwFlags != 0)
+ {
+ // UNIXTODO: Implement this!
+ ASSERT("Needs Implementation!!!");
+ return nullptr;
+ }
+
+ CHAR * lpstr;
+ INT name_length;
+ PathCharString pathstr;
+ HMODULE hModule = nullptr;
+
+ PERF_ENTRY(LoadLibraryExW);
+ ENTRY("LoadLibraryExW (lpLibFileName=%p (%S)) \n",
+ lpLibFileName ? lpLibFileName : W16_NULLSTRING,
+ lpLibFileName ? lpLibFileName : W16_NULLSTRING);
+
+ if (!LOADVerifyLibraryPath(lpLibFileName))
+ {
+ goto done;
+ }
+
+ lpstr = pathstr.OpenStringBuffer((PAL_wcslen(lpLibFileName)+1) * MaxWCharToAcpLength);
+ if (nullptr == lpstr)
+ {
+ goto done;
+ }
+ if (!LOADConvertLibraryPathWideStringToMultibyteString(lpLibFileName, lpstr, &name_length))
+ {
+ goto done;
+ }
+
+ /* do the Dos/Unix conversion on our own copy of the name */
+ FILEDosToUnixPathA(lpstr);
+ pathstr.CloseBuffer(name_length);
+
+ /* let LOADLoadLibrary call SetLastError in case of failure */
+ hModule = LOADLoadLibrary(lpstr, TRUE);
+
+done:
+ LOGEXIT("LoadLibraryExW returns HMODULE %p\n", hModule);
+ PERF_EXIT(LoadLibraryExW);
+ return hModule;
+}
+
+/*++
+Function:
+ GetProcAddress
+
+See MSDN doc.
+--*/
+FARPROC
+PALAPI
+GetProcAddress(
+ IN HMODULE hModule,
+ IN LPCSTR lpProcName)
+{
+ MODSTRUCT *module;
+ FARPROC ProcAddress = nullptr;
+ LPCSTR symbolName = lpProcName;
+
+ PERF_ENTRY(GetProcAddress);
+ ENTRY("GetProcAddress (hModule=%p, lpProcName=%p (%s))\n",
+ hModule, lpProcName ? lpProcName : "NULL", lpProcName ? lpProcName : "NULL");
+
+ LockModuleList();
+
+ module = (MODSTRUCT *) hModule;
+
+ /* parameter validation */
+
+ if ((lpProcName == nullptr) || (*lpProcName == '\0'))
+ {
+ TRACE("No function name given\n");
+ SetLastError(ERROR_INVALID_PARAMETER);
+ goto done;
+ }
+
+ if (!LOADValidateModule(module))
+ {
+ TRACE("Invalid module handle %p\n", hModule);
+ SetLastError(ERROR_INVALID_HANDLE);
+ goto done;
+ }
+
+ /* try to assert on attempt to locate symbol by ordinal */
+ /* this can't be an exact test for HIWORD((DWORD)lpProcName) == 0
+ because of the address range reserved for ordinals contain can
+ be a valid string address on non-Windows systems
+ */
+ if ((DWORD_PTR)lpProcName < VIRTUAL_PAGE_SIZE)
+ {
+ ASSERT("Attempt to locate symbol by ordinal?!\n");
+ }
+
+ // Get the symbol's address.
+
+ // If we're looking for a symbol inside the PAL, we try the PAL_ variant
+ // first because otherwise we run the risk of having the non-PAL_
+ // variant preferred over the PAL's implementation.
+ if (pal_module && module->dl_handle == pal_module->dl_handle)
+ {
+ int iLen = 4 + strlen(lpProcName) + 1;
+ LPSTR lpPALProcName = (LPSTR) alloca(iLen);
+
+ if (strcpy_s(lpPALProcName, iLen, "PAL_") != SAFECRT_SUCCESS)
+ {
+ ERROR("strcpy_s failed!\n");
+ SetLastError(ERROR_INSUFFICIENT_BUFFER);
+ goto done;
+ }
+
+ if (strcat_s(lpPALProcName, iLen, lpProcName) != SAFECRT_SUCCESS)
+ {
+ ERROR("strcat_s failed!\n");
+ SetLastError(ERROR_INSUFFICIENT_BUFFER);
+ goto done;
+ }
+
+ ProcAddress = (FARPROC) dlsym(module->dl_handle, lpPALProcName);
+ symbolName = lpPALProcName;
+ }
+
+ // If we aren't looking inside the PAL or we didn't find a PAL_ variant
+ // inside the PAL, fall back to a normal search.
+ if (ProcAddress == nullptr)
+ {
+ ProcAddress = (FARPROC) dlsym(module->dl_handle, lpProcName);
+ }
+
+ if (ProcAddress)
+ {
+ TRACE("Symbol %s found at address %p in module %p (named %S)\n",
+ lpProcName, ProcAddress, module, MODNAME(module));
+
+ /* if we don't know the module's full name yet, this is our chance to obtain it */
+ if (!module->lib_name && module->dl_handle)
+ {
+ const char* libName = PAL_dladdr((LPVOID)ProcAddress);
+ if (libName)
+ {
+ module->lib_name = UTIL_MBToWC_Alloc(libName, -1);
+ if (nullptr == module->lib_name)
+ {
+ ERROR("MBToWC failure; can't save module's full name\n");
+ }
+ else
+ {
+ TRACE("Saving full path of module %p as %s\n",
+ module, libName);
+ }
+ }
+ }
+ }
+ else
+ {
+ TRACE("Symbol %s not found in module %p (named %S), dlerror message is \"%s\"\n",
+ lpProcName, module, MODNAME(module), dlerror());
+ SetLastError(ERROR_PROC_NOT_FOUND);
+ }
+done:
+ UnlockModuleList();
+ LOGEXIT("GetProcAddress returns FARPROC %p\n", ProcAddress);
+ PERF_EXIT(GetProcAddress);
+ return ProcAddress;
+}
+
+/*++
+Function:
+ FreeLibrary
+
+See MSDN doc.
+--*/
+BOOL
+PALAPI
+FreeLibrary(
+ IN OUT HMODULE hLibModule)
+{
+ BOOL retval = FALSE;
+
+ PERF_ENTRY(FreeLibrary);
+ ENTRY("FreeLibrary (hLibModule=%p)\n", hLibModule);
+
+ retval = LOADFreeLibrary((MODSTRUCT *)hLibModule, TRUE /* fCallDllMain */);
+
+ LOGEXIT("FreeLibrary returns BOOL %d\n", retval);
+ PERF_EXIT(FreeLibrary);
+ return retval;
+}
+
+/*++
+Function:
+ FreeLibraryAndExitThread
+
+See MSDN doc.
+
+--*/
+PALIMPORT
+VOID
+PALAPI
+FreeLibraryAndExitThread(
+ IN HMODULE hLibModule,
+ IN DWORD dwExitCode)
+{
+ PERF_ENTRY(FreeLibraryAndExitThread);
+ ENTRY("FreeLibraryAndExitThread()\n");
+ FreeLibrary(hLibModule);
+ ExitThread(dwExitCode);
+ LOGEXIT("FreeLibraryAndExitThread\n");
+ PERF_EXIT(FreeLibraryAndExitThread);
+}
+
+/*++
+Function:
+ GetModuleFileNameA
+
+See MSDN doc.
+
+Notes :
+ because of limitations in the dlopen() mechanism, this will only return the
+ full path name if a relative or absolute path was given to LoadLibrary, or
+ if the module was used in a GetProcAddress call. otherwise, this will return
+ the short name as given to LoadLibrary. The exception is if hModule is
+ NULL : in this case, the full path of the executable is always returned.
+--*/
+DWORD
+PALAPI
+GetModuleFileNameA(
+ IN HMODULE hModule,
+ OUT LPSTR lpFileName,
+ IN DWORD nSize)
+{
+ INT name_length;
+ DWORD retval = 0;
+ LPWSTR wide_name = nullptr;
+
+ PERF_ENTRY(GetModuleFileNameA);
+ ENTRY("GetModuleFileNameA (hModule=%p, lpFileName=%p, nSize=%u)\n",
+ hModule, lpFileName, nSize);
+
+ LockModuleList();
+ if (hModule && !LOADValidateModule((MODSTRUCT *)hModule))
+ {
+ TRACE("Can't find name for invalid module handle %p\n", hModule);
+ SetLastError(ERROR_INVALID_HANDLE);
+ goto done;
+ }
+ wide_name = LOADGetModuleFileName((MODSTRUCT *)hModule);
+
+ if (!wide_name)
+ {
+ ASSERT("Can't find name for valid module handle %p\n", hModule);
+ SetLastError(ERROR_INTERNAL_ERROR);
+ goto done;
+ }
+
+ /* Convert module name to Ascii, place it in the supplied buffer */
+
+ name_length = WideCharToMultiByte(CP_ACP, 0, wide_name, -1, lpFileName,
+ nSize, nullptr, nullptr);
+ if (name_length == 0)
+ {
+ TRACE("Buffer too small to copy module's file name.\n");
+ SetLastError(ERROR_INSUFFICIENT_BUFFER);
+ goto done;
+ }
+
+ TRACE("File name of module %p is %s\n", hModule, lpFileName);
+ retval = name_length;
+done:
+ UnlockModuleList();
+ LOGEXIT("GetModuleFileNameA returns DWORD %d\n", retval);
+ PERF_EXIT(GetModuleFileNameA);
+ return retval;
+}
+
+/*++
+Function:
+ GetModuleFileNameW
+
+See MSDN doc.
+
+Notes :
+ because of limitations in the dlopen() mechanism, this will only return the
+ full path name if a relative or absolute path was given to LoadLibrary, or
+ if the module was used in a GetProcAddress call. otherwise, this will return
+ the short name as given to LoadLibrary. The exception is if hModule is
+ NULL : in this case, the full path of the executable is always returned.
+--*/
+DWORD
+PALAPI
+GetModuleFileNameW(
+ IN HMODULE hModule,
+ OUT LPWSTR lpFileName,
+ IN DWORD nSize)
+{
+ INT name_length;
+ DWORD retval = 0;
+ LPWSTR wide_name = nullptr;
+
+ PERF_ENTRY(GetModuleFileNameW);
+ ENTRY("GetModuleFileNameW (hModule=%p, lpFileName=%p, nSize=%u)\n",
+ hModule, lpFileName, nSize);
+
+ LockModuleList();
+
+ wcscpy_s(lpFileName, nSize, W(""));
+
+ if (hModule && !LOADValidateModule((MODSTRUCT *)hModule))
+ {
+ TRACE("Can't find name for invalid module handle %p\n", hModule);
+ SetLastError(ERROR_INVALID_HANDLE);
+ goto done;
+ }
+ wide_name = LOADGetModuleFileName((MODSTRUCT *)hModule);
+
+ if (!wide_name)
+ {
+ TRACE("Can't find name for valid module handle %p\n", hModule);
+ SetLastError(ERROR_INTERNAL_ERROR);
+ goto done;
+ }
+
+ /* Copy module name into supplied buffer */
+
+ name_length = lstrlenW(wide_name);
+ if (name_length >= (INT)nSize)
+ {
+ TRACE("Buffer too small (%u) to copy module's file name (%u).\n", nSize, name_length);
+ retval = (INT)nSize;
+ SetLastError(ERROR_INSUFFICIENT_BUFFER);
+ goto done;
+ }
+
+ wcscpy_s(lpFileName, nSize, wide_name);
+
+ TRACE("file name of module %p is %S\n", hModule, lpFileName);
+ retval = name_length;
+done:
+ UnlockModuleList();
+ LOGEXIT("GetModuleFileNameW returns DWORD %u\n", retval);
+ PERF_EXIT(GetModuleFileNameW);
+ return retval;
+}
+
+/*
+Function:
+ PAL_LoadLibraryDirect
+
+ Loads a library using a system call, without registering the library with the module list.
+
+ Returns the system handle to the loaded library, or nullptr upon failure (error is set via SetLastError()).
+*/
+void *
+PALAPI
+PAL_LoadLibraryDirect(
+ IN LPCWSTR lpLibFileName)
+{
+ PathCharString pathstr;
+ CHAR * lpstr = nullptr;
+ INT name_length;
+ void *dl_handle = nullptr;
+
+ PERF_ENTRY(LoadLibraryDirect);
+ ENTRY("LoadLibraryDirect (lpLibFileName=%p (%S)) \n",
+ lpLibFileName ? lpLibFileName : W16_NULLSTRING,
+ lpLibFileName ? lpLibFileName : W16_NULLSTRING);
+
+ if (!LOADVerifyLibraryPath(lpLibFileName))
+ {
+ goto done;
+ }
+
+ lpstr = pathstr.OpenStringBuffer((PAL_wcslen(lpLibFileName)+1) * MaxWCharToAcpLength);
+ if (nullptr == lpstr)
+ {
+ goto done;
+ }
+ if (!LOADConvertLibraryPathWideStringToMultibyteString(lpLibFileName, lpstr, &name_length))
+ {
+ goto done;
+ }
+
+ /* do the Dos/Unix conversion on our own copy of the name */
+ FILEDosToUnixPathA(lpstr);
+ pathstr.CloseBuffer(name_length);
+
+ dl_handle = LOADLoadLibraryDirect(lpstr);
+
+done:
+ LOGEXIT("LoadLibraryDirect returns HMODULE %p\n", dl_handle);
+ PERF_EXIT(LoadLibraryDirect);
+ return dl_handle;
+}
+
+/*
+Function:
+ PAL_RegisterLibraryDirect
+
+ Registers a system handle to a loaded library with the module list.
+
+ Returns a PAL handle to the loaded library, or nullptr upon failure (error is set via SetLastError()).
+*/
+HMODULE
+PALAPI
+PAL_RegisterLibraryDirect(
+ IN void *dl_handle,
+ IN LPCWSTR lpLibFileName)
+{
+ PathCharString pathstr;
+ CHAR * lpstr = nullptr;
+ INT name_length;
+ HMODULE hModule = nullptr;
+
+ PERF_ENTRY(RegisterLibraryDirect);
+ ENTRY("RegisterLibraryDirect (lpLibFileName=%p (%S)) \n",
+ lpLibFileName ? lpLibFileName : W16_NULLSTRING,
+ lpLibFileName ? lpLibFileName : W16_NULLSTRING);
+
+ if (!LOADVerifyLibraryPath(lpLibFileName))
+ {
+ goto done;
+ }
+
+ lpstr = pathstr.OpenStringBuffer((PAL_wcslen(lpLibFileName)+1) * MaxWCharToAcpLength);
+ if (nullptr == lpstr)
+ {
+ goto done;
+ }
+ if (!LOADConvertLibraryPathWideStringToMultibyteString(lpLibFileName, lpstr, &name_length))
+ {
+ goto done;
+ }
+
+ /* do the Dos/Unix conversion on our own copy of the name */
+ FILEDosToUnixPathA(lpstr);
+ pathstr.CloseBuffer(name_length);
+
+ /* let LOADRegisterLibraryDirect call SetLastError in case of failure */
+ LockModuleList();
+ hModule = LOADRegisterLibraryDirect((void *)dl_handle, lpstr, true /* fDynamic */);
+ UnlockModuleList();
+
+done:
+ LOGEXIT("RegisterLibraryDirect returns HMODULE %p\n", hModule);
+ PERF_EXIT(RegisterLibraryDirect);
+ return hModule;
+}
+
+/*++
+Function:
+ PAL_RegisterModule
+
+ Register the module with the target module and return a module handle in
+ the target module's context. Doesn't call the DllMain because it is used
+ as part of calling DllMain in the calling module.
+
+--*/
+HINSTANCE
+PALAPI
+PAL_RegisterModule(
+ IN LPCSTR lpLibFileName)
+{
+ HINSTANCE hinstance = nullptr;
+
+ int err = PAL_InitializeDLL();
+ if (err == 0)
+ {
+ PERF_ENTRY(PAL_RegisterModule);
+ ENTRY("PAL_RegisterModule(%s)\n", lpLibFileName ? lpLibFileName : "");
+
+ LockModuleList();
+
+ void *dl_handle = LOADLoadLibraryDirect(lpLibFileName);
+ if (dl_handle)
+ {
+ // This only creates/adds the module handle and doesn't call DllMain
+ hinstance = LOADAddModule(dl_handle, lpLibFileName);
+ }
+
+ UnlockModuleList();
+
+ LOGEXIT("PAL_RegisterModule returns HINSTANCE %p\n", hinstance);
+ PERF_EXIT(PAL_RegisterModule);
+ }
+
+ return hinstance;
+}
+
+/*++
+Function:
+ PAL_UnregisterModule
+
+ Used to cleanup the module HINSTANCE from PAL_RegisterModule.
+--*/
+VOID
+PALAPI
+PAL_UnregisterModule(
+ IN HINSTANCE hInstance)
+{
+ PERF_ENTRY(PAL_UnregisterModule);
+ ENTRY("PAL_UnregisterModule(hInstance=%p)\n", hInstance);
+
+ LOADFreeLibrary((MODSTRUCT *)hInstance, FALSE /* fCallDllMain */);
+
+ LOGEXIT("PAL_UnregisterModule returns\n");
+ PERF_EXIT(PAL_UnregisterModule);
+}
+
+/*++
+ PAL_LOADLoadPEFile
+
+ Map a PE format file into memory like Windows LoadLibrary() would do.
+ Doesn't apply base relocations if the function is relocated.
+
+Parameters:
+ IN hFile - file to map
+
+Return value:
+ non-NULL - the base address of the mapped image
+ NULL - error, with last error set.
+--*/
+void *
+PALAPI
+PAL_LOADLoadPEFile(HANDLE hFile)
+{
+ ENTRY("PAL_LOADLoadPEFile (hFile=%p)\n", hFile);
+
+ void * loadedBase = MAPMapPEFile(hFile);
+
+#ifdef _DEBUG
+ if (loadedBase != nullptr)
+ {
+ char* envVar = EnvironGetenv("PAL_ForcePEMapFailure");
+ if (envVar)
+ {
+ if (strlen(envVar) > 0)
+ {
+ TRACE("Forcing failure of PE file map, and retry\n");
+ PAL_LOADUnloadPEFile(loadedBase); // unload it
+ loadedBase = MAPMapPEFile(hFile); // load it again
+ }
+
+ free(envVar);
+ }
+ }
+#endif // _DEBUG
+
+ LOGEXIT("PAL_LOADLoadPEFile returns %p\n", loadedBase);
+ return loadedBase;
+}
+
+/*++
+ PAL_LOADUnloadPEFile
+
+ Unload a PE file that was loaded by PAL_LOADLoadPEFile().
+
+Parameters:
+ IN ptr - the file pointer returned by PAL_LOADLoadPEFile()
+
+Return value:
+ TRUE - success
+ FALSE - failure (incorrect ptr, etc.)
+--*/
+BOOL
+PALAPI
+PAL_LOADUnloadPEFile(void * ptr)
+{
+ BOOL retval = FALSE;
+
+ ENTRY("PAL_LOADUnloadPEFile (ptr=%p)\n", ptr);
+
+ if (nullptr == ptr)
+ {
+ ERROR( "Invalid pointer value\n" );
+ }
+ else
+ {
+ retval = MAPUnmapPEFile(ptr);
+ }
+
+ LOGEXIT("PAL_LOADUnloadPEFile returns %d\n", retval);
+ return retval;
+}
+
+/*++
+ PAL_GetSymbolModuleBase
+
+ Get base address of the module containing a given symbol
+
+Parameters:
+ void *symbol - address of symbol
+
+Return value:
+ module base address
+--*/
+LPCVOID
+PALAPI
+PAL_GetSymbolModuleBase(void *symbol)
+{
+ LPCVOID retval = nullptr;
+
+ PERF_ENTRY(PAL_GetPalModuleBase);
+ ENTRY("PAL_GetPalModuleBase\n");
+
+ if (symbol == nullptr)
+ {
+ TRACE("Can't get base address. Argument symbol == nullptr\n");
+ SetLastError(ERROR_INVALID_DATA);
+ }
+ else
+ {
+ Dl_info info;
+ if (dladdr(symbol, &info) != 0)
+ {
+ retval = info.dli_fbase;
+ }
+ else
+ {
+ TRACE("Can't get base address of the current module\n");
+ SetLastError(ERROR_INVALID_DATA);
+ }
+ }
+
+ LOGEXIT("PAL_GetPalModuleBase returns %p\n", retval);
+ PERF_EXIT(PAL_GetPalModuleBase);
+ return retval;
+}
+
+/* Internal PAL functions *****************************************************/
+
+/*++
+Function :
+ LOADInitializeModules
+
+ Initialize the process-wide list of modules
+
+Parameters :
+ None
+
+Return value :
+ TRUE if initialization succeedded
+ FALSE otherwise
+
+--*/
+extern "C"
+BOOL LOADInitializeModules()
+{
+ _ASSERTE(exe_module.prev == nullptr);
+
+ InternalInitializeCriticalSection(&module_critsec);
+
+ // Initialize module for main executable
+ TRACE("Initializing module for main executable\n");
+
+ exe_module.self = (HMODULE)&exe_module;
+ exe_module.dl_handle = dlopen(nullptr, RTLD_LAZY);
+ if (exe_module.dl_handle == nullptr)
+ {
+ ERROR("Executable module will be broken : dlopen(nullptr) failed dlerror message is \"%s\" \n", dlerror());
+ return FALSE;
+ }
+ exe_module.lib_name = nullptr;
+ exe_module.refcount = -1;
+ exe_module.next = &exe_module;
+ exe_module.prev = &exe_module;
+ exe_module.pDllMain = nullptr;
+ exe_module.hinstance = nullptr;
+ exe_module.threadLibCalls = TRUE;
+ return TRUE;
+}
+
+/*++
+Function :
+ LOADSetExeName
+
+ Set the exe name path
+
+Parameters :
+ LPWSTR man exe path and name
+
+Return value :
+ TRUE if initialization succeedded
+ FALSE otherwise
+
+--*/
+extern "C"
+BOOL LOADSetExeName(LPWSTR name)
+{
+#if RETURNS_NEW_HANDLES_ON_REPEAT_DLOPEN
+ LPSTR pszExeName = nullptr;
+#endif
+ BOOL result = FALSE;
+
+ LockModuleList();
+
+ // Save the exe path in the exe module struct
+ free(exe_module.lib_name);
+ exe_module.lib_name = name;
+
+ // For platforms where we can't trust the handle to be constant, we need to
+ // store the inode/device pairs for the modules we just initialized.
+#if RETURNS_NEW_HANDLES_ON_REPEAT_DLOPEN
+ {
+ struct stat stat_buf;
+ pszExeName = UTIL_WCToMB_Alloc(name, -1);
+ if (nullptr == pszExeName)
+ {
+ ERROR("WCToMB failure, unable to get full name of exe\n");
+ goto exit;
+ }
+ if (-1 == stat(pszExeName, &stat_buf))
+ {
+ SetLastError(ERROR_MOD_NOT_FOUND);
+ goto exit;
+ }
+ TRACE("Executable has inode %d and device %d\n", stat_buf.st_ino, stat_buf.st_dev);
+
+ exe_module.inode = stat_buf.st_ino;
+ exe_module.device = stat_buf.st_dev;
+ }
+#endif
+ result = TRUE;
+
+#if RETURNS_NEW_HANDLES_ON_REPEAT_DLOPEN
+exit:
+ if (pszExeName)
+ {
+ free(pszExeName);
+ }
+#endif
+ UnlockModuleList();
+ return result;
+}
+
+/*++
+Function :
+ LOADCallDllMain
+
+ Call DllMain for all modules (that have one) with the given "fwReason"
+
+Parameters :
+ DWORD dwReason : parameter to pass down to DllMain, one of DLL_PROCESS_ATTACH, DLL_PROCESS_DETACH,
+ DLL_THREAD_ATTACH, DLL_THREAD_DETACH
+
+ LPVOID lpReserved : parameter to pass down to DllMain
+ If dwReason is DLL_PROCESS_ATTACH, lpvReserved is NULL for dynamic loads and non-NULL for static loads.
+ If dwReason is DLL_PROCESS_DETACH, lpvReserved is NULL if DllMain has been called by using FreeLibrary
+ and non-NULL if DllMain has been called during process termination.
+
+(no return value)
+
+Notes :
+ This is used to send DLL_THREAD_*TACH messages to modules
+--*/
+extern "C"
+void LOADCallDllMain(DWORD dwReason, LPVOID lpReserved)
+{
+ MODSTRUCT *module = nullptr;
+ BOOL InLoadOrder = TRUE; /* true if in load order, false for reverse */
+ CPalThread *pThread;
+
+ pThread = InternalGetCurrentThread();
+ if (UserCreatedThread != pThread->GetThreadType())
+ {
+ return;
+ }
+
+ /* Validate dwReason */
+ switch(dwReason)
+ {
+ case DLL_PROCESS_ATTACH:
+ ASSERT("got called with DLL_PROCESS_ATTACH parameter! Why?\n");
+ break;
+ case DLL_PROCESS_DETACH:
+ ASSERT("got called with DLL_PROCESS_DETACH parameter! Why?\n");
+ InLoadOrder = FALSE;
+ break;
+ case DLL_THREAD_ATTACH:
+ TRACE("Calling DllMain(DLL_THREAD_ATTACH) on all known modules.\n");
+ break;
+ case DLL_THREAD_DETACH:
+ TRACE("Calling DllMain(DLL_THREAD_DETACH) on all known modules.\n");
+ InLoadOrder = FALSE;
+ break;
+ default:
+ ASSERT("LOADCallDllMain called with unknown parameter %d!\n", dwReason);
+ return;
+ }
+
+ LockModuleList();
+
+ module = &exe_module;
+
+ do
+ {
+ if (!InLoadOrder)
+ module = module->prev;
+
+ if (module->threadLibCalls)
+ {
+ if (module->pDllMain)
+ {
+ LOADCallDllMainSafe(module, dwReason, lpReserved);
+ }
+ }
+
+ if (InLoadOrder)
+ module = module->next;
+
+ } while (module != &exe_module);
+
+ UnlockModuleList();
+}
+
+/*++
+Function:
+ LOADFreeLibrary
+
+Parameters:
+ MODSTRUCT * module - module to free
+ BOOL fCallDllMain - if TRUE, call the DllMain function
+
+Returns:
+ TRUE if successful
+
+--*/
+static BOOL LOADFreeLibrary(MODSTRUCT *module, BOOL fCallDllMain)
+{
+ BOOL retval = FALSE;
+
+ LockModuleList();
+
+ if (terminator)
+ {
+ /* PAL shutdown is in progress - ignore FreeLibrary calls */
+ retval = TRUE;
+ goto done;
+ }
+
+ if (!LOADValidateModule(module))
+ {
+ TRACE("Can't free invalid module %p\n", module);
+ SetLastError(ERROR_INVALID_HANDLE);
+ goto done;
+ }
+
+ if (module->refcount == -1)
+ {
+ /* special module - never released */
+ retval = TRUE;
+ goto done;
+ }
+
+ module->refcount--;
+ TRACE("Reference count for module %p (named %S) decreases to %d\n",
+ module, MODNAME(module), module->refcount);
+
+ if (module->refcount != 0)
+ {
+ retval = TRUE;
+ goto done;
+ }
+
+ /* Releasing the last reference : call dlclose(), remove module from the
+ process-wide module list */
+
+ TRACE("Reference count for module %p (named %S) now 0; destroying module structure\n",
+ module, MODNAME(module));
+
+ /* unlink the module structure from the list */
+ module->prev->next = module->next;
+ module->next->prev = module->prev;
+
+ /* remove the circular reference so that LOADValidateModule will fail */
+ module->self = nullptr;
+
+ /* Call DllMain if the module contains one */
+ if (fCallDllMain && module->pDllMain)
+ {
+ LOADCallDllMainSafe(module, DLL_PROCESS_DETACH, nullptr);
+ }
+
+ if (module->hinstance)
+ {
+ PUNREGISTER_MODULE unregisterModule = (PUNREGISTER_MODULE)dlsym(module->dl_handle, "PAL_UnregisterModule");
+ if (unregisterModule != nullptr)
+ {
+ unregisterModule(module->hinstance);
+ }
+ module->hinstance = nullptr;
+ }
+
+ if (module->dl_handle && 0 != dlclose(module->dl_handle))
+ {
+ /* report dlclose() failure, but proceed anyway. */
+ WARN("dlclose() call failed! error message is \"%s\"\n", dlerror());
+ }
+
+ /* release all memory */
+ free(module->lib_name);
+ free(module);
+
+ retval = TRUE;
+
+done:
+ UnlockModuleList();
+ return retval;
+}
+
+/*++
+Function :
+ LOADCallDllMainSafe
+
+ Exception-safe call to DllMain.
+
+Parameters :
+ MODSTRUCT *module : module whose DllMain must be called
+
+ DWORD dwReason : parameter to pass down to DllMain, one of DLL_PROCESS_ATTACH, DLL_PROCESS_DETACH,
+ DLL_THREAD_ATTACH, DLL_THREAD_DETACH
+
+ LPVOID lpvReserved : parameter to pass down to DllMain,
+ If dwReason is DLL_PROCESS_ATTACH, lpvReserved is NULL for dynamic loads and non-NULL for static loads.
+ If dwReason is DLL_PROCESS_DETACH, lpvReserved is NULL if DllMain has been called by using FreeLibrary
+ and non-NULL if DllMain has been called during process termination.
+
+Returns:
+ BOOL : DllMain's return value
+*/
+static BOOL LOADCallDllMainSafe(MODSTRUCT *module, DWORD dwReason, LPVOID lpReserved)
+{
+#if _ENABLE_DEBUG_MESSAGES_
+ /* reset ENTRY nesting level back to zero while inside the callback... */
+ int old_level = DBG_change_entrylevel(0);
+#endif /* _ENABLE_DEBUG_MESSAGES_ */
+
+ struct Param
+ {
+ MODSTRUCT *module;
+ DWORD dwReason;
+ LPVOID lpReserved;
+ BOOL ret;
+ } param;
+ param.module = module;
+ param.dwReason = dwReason;
+ param.lpReserved = lpReserved;
+ param.ret = FALSE;
+
+ PAL_TRY(Param *, pParam, &param)
+ {
+ TRACE("Calling DllMain (%p) for module %S\n",
+ pParam->module->pDllMain,
+ pParam->module->lib_name ? pParam->module->lib_name : W16_NULLSTRING);
+
+ {
+ // This module may be foreign to our PAL, so leave our PAL.
+ // If it depends on us, it will re-enter.
+ PAL_LeaveHolder holder;
+ pParam->ret = pParam->module->pDllMain(pParam->module->hinstance, pParam->dwReason, pParam->lpReserved);
+ }
+ }
+ PAL_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ WARN("Call to DllMain (%p) got an unhandled exception; ignoring.\n", module->pDllMain);
+ }
+ PAL_ENDTRY
+
+#if _ENABLE_DEBUG_MESSAGES_
+ /* ...and set nesting level back to what it was */
+ DBG_change_entrylevel(old_level);
+#endif /* _ENABLE_DEBUG_MESSAGES_ */
+
+ return param.ret;
+}
+
+/*++
+Function:
+ DisableThreadLibraryCalls
+
+See MSDN doc.
+--*/
+BOOL
+PALAPI
+DisableThreadLibraryCalls(
+ IN HMODULE hLibModule)
+{
+ BOOL ret = FALSE;
+ MODSTRUCT *module;
+ PERF_ENTRY(DisableThreadLibraryCalls);
+ ENTRY("DisableThreadLibraryCalls(hLibModule=%p)\n", hLibModule);
+
+ LockModuleList();
+
+ if (terminator)
+ {
+ /* PAL shutdown in progress - ignore DisableThreadLibraryCalls */
+ ret = TRUE;
+ goto done;
+ }
+
+ module = (MODSTRUCT *) hLibModule;
+
+ if (!LOADValidateModule(module))
+ {
+ // DisableThreadLibraryCalls() does nothing when given
+ // an invalid module handle. This matches the Windows
+ // behavior, though it is counter to MSDN.
+ WARN("Invalid module handle %p\n", hLibModule);
+ ret = TRUE;
+ goto done;
+ }
+
+ module->threadLibCalls = FALSE;
+ ret = TRUE;
+
+done:
+ UnlockModuleList();
+ LOGEXIT("DisableThreadLibraryCalls returns BOOL %d\n", ret);
+ PERF_EXIT(DisableThreadLibraryCalls);
+ return ret;
+}
+
+// Checks the library path for null or empty string. On error, calls SetLastError() and returns false.
+template<class TChar>
+static bool LOADVerifyLibraryPath(const TChar *libraryPath)
+{
+ if (libraryPath == nullptr)
+ {
+ ERROR("libraryPath is null\n");
+ SetLastError(ERROR_MOD_NOT_FOUND);
+ return false;
+ }
+ if (libraryPath[0] == '\0')
+ {
+ ERROR("libraryPath is empty\n");
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return false;
+ }
+ return true;
+}
+
+// Converts the wide char library path string into a multibyte-char string. On error, calls SetLastError() and returns false.
+static bool LOADConvertLibraryPathWideStringToMultibyteString(
+ LPCWSTR wideLibraryPath,
+ LPSTR multibyteLibraryPath,
+ INT *multibyteLibraryPathLengthRef)
+{
+ _ASSERTE(multibyteLibraryPathLengthRef != nullptr);
+ _ASSERTE(wideLibraryPath != nullptr);
+
+ size_t length = (PAL_wcslen(wideLibraryPath)+1) * MaxWCharToAcpLength;
+ *multibyteLibraryPathLengthRef = WideCharToMultiByte(CP_ACP, 0, wideLibraryPath, -1, multibyteLibraryPath,
+ length, nullptr, nullptr);
+
+ if (*multibyteLibraryPathLengthRef == 0)
+ {
+ DWORD dwLastError = GetLastError();
+
+ ASSERT("WideCharToMultiByte failure! error is %d\n", dwLastError);
+
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return false;
+ }
+ return true;
+}
+
+/*++
+Function :
+ LOADValidateModule
+
+ Check whether the given MODSTRUCT pointer is valid
+
+Parameters :
+ MODSTRUCT *module : module to check
+
+Return value :
+ TRUE if module is valid, FALSE otherwise
+
+NOTE :
+ The module lock MUST be owned.
+
+--*/
+static BOOL LOADValidateModule(MODSTRUCT *module)
+{
+ MODSTRUCT *modlist_enum = &exe_module;
+
+ /* enumerate through the list of modules to make sure the given handle is
+ really a module (HMODULEs are actually MODSTRUCT pointers) */
+ do
+ {
+ if (module == modlist_enum)
+ {
+ /* found it; check its integrity to be on the safe side */
+ if (module->self != module)
+ {
+ ERROR("Found corrupt module %p!\n",module);
+ return FALSE;
+ }
+ TRACE("Module %p is valid (name : %S)\n", module, MODNAME(module));
+ return TRUE;
+ }
+ modlist_enum = modlist_enum->next;
+ }
+ while (modlist_enum != &exe_module);
+
+ TRACE("Module %p is NOT valid.\n", module);
+ return FALSE;
+}
+
+/*++
+Function :
+ LOADGetModuleFileName [internal]
+
+ Retrieve the module's full path if it is known, the short name given to
+ LoadLibrary otherwise.
+
+Parameters :
+ MODSTRUCT *module : module to check
+
+Return value :
+ pointer to internal buffer with name of module (Unicode)
+
+Notes :
+ this function assumes that the module critical section is held, and that
+ the module has already been validated.
+--*/
+static LPWSTR LOADGetModuleFileName(MODSTRUCT *module)
+{
+ LPWSTR module_name;
+ /* special case : if module is NULL, we want the name of the executable */
+ if (!module)
+ {
+ module_name = exe_module.lib_name;
+ TRACE("Returning name of main executable\n");
+ return module_name;
+ }
+
+ /* return "real" name of module if it is known. we have this if LoadLibrary
+ was given an absolute or relative path; we can also determine it at the
+ first GetProcAdress call. */
+ TRACE("Returning full path name of module\n");
+ return module->lib_name;
+}
+
+/*
+Function:
+ LOADLoadLibraryDirect [internal]
+
+ Loads a library using a system call, without registering the library with the module list.
+
+Parameters:
+ LPCSTR libraryNameOrPath: The library to load.
+
+Return value:
+ System handle to the loaded library, or nullptr upon failure (error is set via SetLastError()).
+*/
+static void *LOADLoadLibraryDirect(LPCSTR libraryNameOrPath)
+{
+ _ASSERTE(libraryNameOrPath != nullptr);
+ _ASSERTE(libraryNameOrPath[0] != '\0');
+
+ void *dl_handle = dlopen(libraryNameOrPath, RTLD_LAZY);
+ if (dl_handle == nullptr)
+ {
+ WARN("dlopen() failed; dlerror says '%s'\n", dlerror());
+ SetLastError(ERROR_MOD_NOT_FOUND);
+ }
+ else
+ {
+ TRACE("dlopen() found module %s\n", libraryNameOrPath);
+ }
+
+ return dl_handle;
+}
+
+/*++
+Function :
+ LOADAllocModule
+
+ Allocate and initialize a new MODSTRUCT structure
+
+Parameters :
+ void *dl_handle : handle returned by dl_open, goes in MODSTRUCT::dl_handle
+
+ char *name : name of new module. after conversion to widechar,
+ goes in MODSTRUCT::lib_name
+
+Return value:
+ a pointer to a new, initialized MODSTRUCT strucutre, or NULL on failure.
+
+Notes :
+ 'name' is used to initialize MODSTRUCT::lib_name. The other member is set to NULL
+ In case of failure (in malloc or MBToWC), this function sets LastError.
+--*/
+static MODSTRUCT *LOADAllocModule(void *dl_handle, LPCSTR name)
+{
+ MODSTRUCT *module;
+ LPWSTR wide_name;
+
+ /* no match found : try to create a new module structure */
+ module = (MODSTRUCT *)InternalMalloc(sizeof(MODSTRUCT));
+ if (nullptr == module)
+ {
+ ERROR("malloc() failed! errno is %d (%s)\n", errno, strerror(errno));
+ return nullptr;
+ }
+
+ wide_name = UTIL_MBToWC_Alloc(name, -1);
+ if (nullptr == wide_name)
+ {
+ ERROR("couldn't convert name to a wide-character string\n");
+ free(module);
+ return nullptr;
+ }
+
+ module->dl_handle = dl_handle;
+#if NEED_DLCOMPAT
+ if (isdylib(module))
+ {
+ module->refcount = -1;
+ }
+ else
+ {
+ module->refcount = 1;
+ }
+#else // NEED_DLCOMPAT
+ module->refcount = 1;
+#endif // NEED_DLCOMPAT
+ module->self = module;
+ module->hinstance = nullptr;
+ module->threadLibCalls = TRUE;
+ module->pDllMain = nullptr;
+ module->next = nullptr;
+ module->prev = nullptr;
+
+ module->lib_name = wide_name;
+
+ return module;
+}
+
+/*
+Function:
+ LOADAddModule [internal]
+
+ Registers a system handle to a loaded library with the module list.
+
+Parameters:
+ void *dl_handle: System handle to the loaded library.
+ LPCSTR libraryNameOrPath: The library that was loaded.
+
+Return value:
+ PAL handle to the loaded library, or nullptr upon failure (error is set via SetLastError()).
+*/
+static MODSTRUCT *LOADAddModule(void *dl_handle, LPCSTR libraryNameOrPath)
+{
+ _ASSERTE(dl_handle != nullptr);
+ _ASSERTE(libraryNameOrPath != nullptr);
+ _ASSERTE(libraryNameOrPath[0] != '\0');
+
+#if !RETURNS_NEW_HANDLES_ON_REPEAT_DLOPEN
+ /* search module list for a match. */
+ MODSTRUCT *module = &exe_module;
+ do
+ {
+ if (dl_handle == module->dl_handle)
+ {
+ /* found the handle. increment the refcount and return the
+ existing module structure */
+ TRACE("Found matching module %p for module name %s\n", module, libraryNameOrPath);
+
+ if (module->refcount != -1)
+ {
+ module->refcount++;
+ }
+ dlclose(dl_handle);
+ return module;
+ }
+ module = module->next;
+
+ } while (module != &exe_module);
+#endif
+
+ TRACE("Module doesn't exist : creating %s.\n", libraryNameOrPath);
+
+ module = LOADAllocModule(dl_handle, libraryNameOrPath);
+ if (nullptr == module)
+ {
+ ERROR("couldn't create new module\n");
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ dlclose(dl_handle);
+ return nullptr;
+ }
+
+ /* We now get the address of DllMain if the module contains one. */
+ module->pDllMain = (PDLLMAIN)dlsym(module->dl_handle, "DllMain");
+
+ /* Add the new module on to the end of the list */
+ module->prev = exe_module.prev;
+ module->next = &exe_module;
+ exe_module.prev->next = module;
+ exe_module.prev = module;
+
+#if RETURNS_NEW_HANDLES_ON_REPEAT_DLOPEN
+ module->inode = stat_buf.st_ino;
+ module->device = stat_buf.st_dev;
+#endif
+
+ return module;
+}
+
+/*
+Function:
+ LOADRegisterLibraryDirect [internal]
+
+ Registers a system handle to a loaded library with the module list.
+
+Parameters:
+ void *dl_handle: System handle to the loaded library.
+ LPCSTR libraryNameOrPath: The library that was loaded.
+ BOOL fDynamic: TRUE if dynamic load through LoadLibrary, FALSE if static load through RegisterLibrary.
+
+Return value:
+ PAL handle to the loaded library, or nullptr upon failure (error is set via SetLastError()).
+*/
+static HMODULE LOADRegisterLibraryDirect(void *dl_handle, LPCSTR libraryNameOrPath, BOOL fDynamic)
+{
+ MODSTRUCT *module = LOADAddModule(dl_handle, libraryNameOrPath);
+ if (module == nullptr)
+ {
+ return nullptr;
+ }
+
+ /* If the module contains a DllMain, call it. */
+ if (module->pDllMain)
+ {
+ TRACE("Calling DllMain (%p) for module %S\n",
+ module->pDllMain,
+ module->lib_name ? module->lib_name : W16_NULLSTRING);
+
+ if (nullptr == module->hinstance)
+ {
+ PREGISTER_MODULE registerModule = (PREGISTER_MODULE)dlsym(module->dl_handle, "PAL_RegisterModule");
+ if (registerModule != nullptr)
+ {
+ module->hinstance = registerModule(libraryNameOrPath);
+ }
+ else
+ {
+ // If the target module doesn't have the PAL_RegisterModule export, then use this PAL's
+ // module handle assuming that the target module is referencing this PAL's exported
+ // functions on said handle.
+ module->hinstance = (HINSTANCE)module;
+ }
+ }
+
+ BOOL dllMainRetVal = LOADCallDllMainSafe(module, DLL_PROCESS_ATTACH, fDynamic ? nullptr : (LPVOID)-1);
+
+ // If DlMain(DLL_PROCESS_ATTACH) returns FALSE, we must immediately unload the module
+ if (!dllMainRetVal)
+ {
+ ERROR("DllMain returned FALSE; unloading module.\n");
+ module->pDllMain = nullptr;
+ FreeLibrary((HMODULE)module);
+ SetLastError(ERROR_DLL_INIT_FAILED);
+ module = nullptr;
+ }
+ }
+ else
+ {
+ TRACE("Module does not contain a DllMain function.\n");
+ }
+
+ return module;
+}
+
+/*++
+Function :
+ LOADLoadLibrary [internal]
+
+ implementation of LoadLibrary (for use by the A/W variants)
+
+Parameters :
+ LPSTR shortAsciiName : name of module as specified to LoadLibrary
+
+ BOOL fDynamic : TRUE if dynamic load through LoadLibrary, FALSE if static load through RegisterLibrary
+
+Return value :
+ handle to loaded module
+
+--*/
+static HMODULE LOADLoadLibrary(LPCSTR shortAsciiName, BOOL fDynamic)
+{
+ HMODULE module = nullptr;
+ void *dl_handle = nullptr;
+
+ // Check whether we have been requested to load 'libc'. If that's the case, then:
+ // * For Linux, use the full name of the library that is defined in <gnu/lib-names.h> by the
+ // LIBC_SO constant. The problem is that calling dlopen("libc.so") will fail for libc even
+ // though it works for other libraries. The reason is that libc.so is just linker script
+ // (i.e. a test file).
+ // As a result, we have to use the full name (i.e. lib.so.6) that is defined by LIBC_SO.
+ // * For macOS, use constant value absolute path "/usr/lib/libc.dylib".
+ // * For FreeBSD, use constant value "libc.so.7".
+ // * For rest of Unices, use constant value "libc.so".
+ if (strcmp(shortAsciiName, LIBC_NAME_WITHOUT_EXTENSION) == 0)
+ {
+#if defined(__APPLE__)
+ shortAsciiName = "/usr/lib/libc.dylib";
+#elif defined(__FreeBSD__)
+ shortAsciiName = "libc.so.7";
+#elif defined(LIBC_SO)
+ shortAsciiName = LIBC_SO;
+#else
+ shortAsciiName = "libc.so";
+#endif
+ }
+
+ LockModuleList();
+
+ dl_handle = LOADLoadLibraryDirect(shortAsciiName);
+ if (dl_handle)
+ {
+ module = LOADRegisterLibraryDirect(dl_handle, shortAsciiName, fDynamic);
+ }
+
+ UnlockModuleList();
+
+ return module;
+}
+
+/*++
+ LOADInitializeCoreCLRModule
+
+ Run the initialization methods for CoreCLR module (the module containing this PAL).
+
+Parameters:
+ None
+
+Return value:
+ TRUE if successful
+ FALSE if failure
+--*/
+BOOL LOADInitializeCoreCLRModule()
+{
+ MODSTRUCT *module = LOADGetPalLibrary();
+ if (!module)
+ {
+ ERROR("Can not load the PAL module\n");
+ return FALSE;
+ }
+ PDLLMAIN pRuntimeDllMain = (PDLLMAIN)dlsym(module->dl_handle, "CoreDllMain");
+ if (!pRuntimeDllMain)
+ {
+ ERROR("Can not find the CoreDllMain entry point\n");
+ return FALSE;
+ }
+ return pRuntimeDllMain(module->hinstance, DLL_PROCESS_ATTACH, nullptr);
+}
+
+/*++
+Function :
+ LOADGetPalLibrary
+
+ Load and initialize the PAL module.
+
+Parameters :
+ None
+
+Return value :
+ pointer to module struct
+
+--*/
+MODSTRUCT *LOADGetPalLibrary()
+{
+ if (pal_module == nullptr)
+ {
+ // Initialize the pal module (the module containing LOADGetPalLibrary). Assumes that
+ // the PAL is linked into the coreclr module because we use the module name containing
+ // this function for the coreclr path.
+ TRACE("Loading module for PAL library\n");
+
+ Dl_info info;
+ if (dladdr((PVOID)&LOADGetPalLibrary, &info) == 0)
+ {
+ ERROR("LOADGetPalLibrary: dladdr() failed. dlerror message is \"%s\"\n", dlerror());
+ goto exit;
+ }
+ // Stash a copy of the CoreCLR installation path in a global variable.
+ // Make sure it's terminated with a slash.
+ if (g_szCoreCLRPath == nullptr)
+ {
+ size_t cbszCoreCLRPath = strlen(info.dli_fname) + 1;
+ g_szCoreCLRPath = (char*) InternalMalloc(cbszCoreCLRPath);
+
+ if (g_szCoreCLRPath == nullptr)
+ {
+ ERROR("LOADGetPalLibrary: InternalMalloc failed!");
+ goto exit;
+ }
+
+ if (strcpy_s(g_szCoreCLRPath, cbszCoreCLRPath, info.dli_fname) != SAFECRT_SUCCESS)
+ {
+ ERROR("LOADGetPalLibrary: strcpy_s failed!");
+ goto exit;
+ }
+ }
+
+ pal_module = (MODSTRUCT *)LOADLoadLibrary(info.dli_fname, FALSE);
+ }
+
+exit:
+ return pal_module;
+}
+
+/*++
+Function:
+ LockModuleList
+
+Abstract
+ Enter the critical section associated to the module list
+
+Parameter
+ void
+
+Return
+ void
+--*/
+extern "C"
+void LockModuleList()
+{
+ CPalThread * pThread =
+ (PALIsThreadDataInitialized() ? InternalGetCurrentThread() : nullptr);
+
+ InternalEnterCriticalSection(pThread, &module_critsec);
+}
+
+/*++
+Function:
+ UnlockModuleList
+
+Abstract
+ Leave the critical section associated to the module list
+
+Parameter
+ void
+
+Return
+ void
+--*/
+extern "C"
+void UnlockModuleList()
+{
+ CPalThread * pThread =
+ (PALIsThreadDataInitialized() ? InternalGetCurrentThread() : nullptr);
+
+ InternalLeaveCriticalSection(pThread, &module_critsec);
+}
diff --git a/src/pal/src/loader/modulename.cpp b/src/pal/src/loader/modulename.cpp
new file mode 100644
index 0000000000..026f89b3ea
--- /dev/null
+++ b/src/pal/src/loader/modulename.cpp
@@ -0,0 +1,207 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ modulename.cpp
+
+Abstract:
+
+ Implementation of internal functions to get module names
+
+
+
+--*/
+
+#include "pal/thread.hpp"
+#include "pal/malloc.hpp"
+#include "pal/palinternal.h"
+#include "pal/dbgmsg.h"
+#include "pal/modulename.h"
+
+#if NEED_DLCOMPAT
+#include "dlcompat.h"
+#else // NEED_DLCOMPAT
+#include <dlfcn.h>
+#endif // NEED_DLCOMPAT
+
+#if defined(_AIX)
+#include <sys/ldr.h>
+#endif
+
+using namespace CorUnix;
+
+SET_DEFAULT_DEBUG_CHANNEL(LOADER);
+
+#if defined(_AIX)
+/*++
+ GetLibRotorNameViaLoadQuery
+
+ Retrieve the full path of the librotor_pal.so using loadquery()
+
+Parameters:
+ pszBuf - CHAR array of MAX_PATH_FNAME length
+
+Return value:
+ 0 on success
+ -1 on failure, with last error set
+--*/
+int GetLibRotorNameViaLoadQuery(LPSTR pszBuf)
+{
+ CHAR* pLoadQueryBuf = NULL;
+ UINT cbBuf = 1024;
+ struct ld_info * pInfo = NULL;
+ INT iLQRetVal = -1;
+ INT iRetVal = -1;
+ CPalThread *pThread = NULL;
+
+ if (!pszBuf)
+ {
+ ASSERT("GetLibRotorNameViaLoadQuery requires non-NULL pszBuf\n");
+ SetLastError(ERROR_INTERNAL_ERROR);
+ goto Done;
+ }
+
+ pThread = InternalGetCurrentThread();
+ // Loop trying to call loadquery with enough memory until either
+ // 1) we succeed, 2) we run out of memory or 3) loadquery throws
+ // an error other than ENOMEM
+ while (iLQRetVal != 0)
+ {
+ pLoadQueryBuf = (CHAR*) InternalMalloc (pThread, cbBuf * sizeof(char));
+ if (!pLoadQueryBuf)
+ {
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ goto Done;
+ }
+ iLQRetVal = loadquery(L_GETINFO, pLoadQueryBuf, cbBuf);
+ if (iLQRetVal < 0)
+ {
+ free(pThread, pLoadQueryBuf);
+ pLoadQueryBuf = NULL;
+ DWORD dwLastError = GetLastError();
+ if (dwLastError == ERROR_NOT_ENOUGH_MEMORY)
+ {
+ // The buffer's too small. Try twice as large as a guess...
+ cbBuf *= 2;
+ }
+ else
+ {
+ SetLastError(ERROR_INTERNAL_ERROR);
+ goto Done;
+ }
+ }
+ }
+
+ // We successfully called loadquery, so now see if we can find
+ // librotor_pal.a in the module list
+ if (pLoadQueryBuf)
+ {
+ pInfo = (struct ld_info *)pLoadQueryBuf;
+ while (TRUE)
+ {
+ if (strstr(pInfo->ldinfo_filename, "librotor_pal.a"))
+ {
+ UINT cchFileName = strlen(pInfo->ldinfo_filename);
+ if (cchFileName + 1 > MAX_PATH_FNAME)
+ {
+ ASSERT("Filename returned by loadquery was longer than MAX_PATH_FNAME!\n");
+ SetLastError(ERROR_INTERNAL_ERROR);
+ goto Done;
+ }
+ else
+ {
+ // The buffer should be large enough to accomodate the filename.
+ // So, we send in the size of the filename+1
+ strcpy_s(pszBuf, MAX_PATH_FNAME, pInfo->ldinfo_filename);
+ iRetVal = 0;
+ goto Done;
+ }
+ }
+ else
+ {
+ // The (wacky) design of ld_info is that the value of next is an offset in
+ // bytes rather than a pointer. So we need this weird cast to char * to get
+ // the pointer math correct.
+ if (pInfo->ldinfo_next == 0)
+ break;
+ else
+ pInfo = (struct ld_info *) ((char *)pInfo + pInfo->ldinfo_next);
+ }
+ }
+ }
+Done:
+ if (pLoadQueryBuf)
+ free(pThread, pLoadQueryBuf);
+ return iRetVal;
+}
+#endif // defined(_AIX)
+
+/*++
+ PAL_dladdr
+
+ Internal wrapper for dladder used only to get module name
+
+Parameters:
+ None
+
+Return value:
+ Pointer to string with the fullpath to the librotor_pal.so being
+ used.
+
+ NULL if error occurred.
+
+Notes:
+ The string returned by this function is owned by the OS.
+ If you need to keep it, strdup() it, because it is unknown how long
+ this ptr will point at the string you want (over the lifetime of
+ the system running) It is only safe to use it immediately after calling
+ this function.
+--*/
+const char *PAL_dladdr(LPVOID ProcAddress)
+{
+#if defined(_AIX) || defined(__hppa__)
+ /* dladdr is not supported on AIX or 32-bit HPUX-PARISC */
+ return (NULL);
+#elif defined(_HPUX_) && defined(_IA64_)
+ /* dladdr is not supported on HP-UX/IA64. That said, PAL_dladdr just returns to module name
+ and we can get that via dlgetname. So use that for HPUX. */
+ {
+ char* pszName = NULL;
+ load_module_desc desc;
+ __uint64_t uimodret = NULL;
+ uimodret = dlmodinfo((__uint64_t)ProcAddress, &desc, sizeof(desc), NULL, 0, 0);
+ if (!uimodret)
+ {
+ WARN("dlmodinfo call failed! dlerror says '%s'\n", dlerror());
+ return NULL;
+ }
+ pszName = dlgetname(&desc, sizeof(desc), NULL, 0, 0);
+ if (!pszName)
+ {
+ WARN("dlgetname desc didn't describe a loaded module?! dlerror says '%s'\n", dlerror());
+ return NULL;
+ }
+ return pszName;
+ }
+#else
+ Dl_info dl_info;
+ if (!dladdr(ProcAddress, &dl_info))
+ {
+ WARN("dladdr() call failed! dlerror says '%s'\n", dlerror());
+ /* If we get an error, return NULL */
+ return (NULL);
+ }
+ else
+ {
+ /* Return the module name */
+ return dl_info.dli_fname;
+ }
+#endif
+}
+
diff --git a/src/pal/src/locale/UnicodeData.txt b/src/pal/src/locale/UnicodeData.txt
new file mode 100644
index 0000000000..a137245b52
--- /dev/null
+++ b/src/pal/src/locale/UnicodeData.txt
@@ -0,0 +1,12860 @@
+0000;<control>;Cc;0;BN;;;;;N;NULL;;;;
+0001;<control>;Cc;0;BN;;;;;N;START OF HEADING;;;;
+0002;<control>;Cc;0;BN;;;;;N;START OF TEXT;;;;
+0003;<control>;Cc;0;BN;;;;;N;END OF TEXT;;;;
+0004;<control>;Cc;0;BN;;;;;N;END OF TRANSMISSION;;;;
+0005;<control>;Cc;0;BN;;;;;N;ENQUIRY;;;;
+0006;<control>;Cc;0;BN;;;;;N;ACKNOWLEDGE;;;;
+0007;<control>;Cc;0;BN;;;;;N;BELL;;;;
+0008;<control>;Cc;0;BN;;;;;N;BACKSPACE;;;;
+0009;<control>;Cc;0;S;;;;;N;HORIZONTAL TABULATION;;;;
+000A;<control>;Cc;0;B;;;;;N;LINE FEED;;;;
+000B;<control>;Cc;0;S;;;;;N;VERTICAL TABULATION;;;;
+000C;<control>;Cc;0;WS;;;;;N;FORM FEED;;;;
+000D;<control>;Cc;0;B;;;;;N;CARRIAGE RETURN;;;;
+000E;<control>;Cc;0;BN;;;;;N;SHIFT OUT;;;;
+000F;<control>;Cc;0;BN;;;;;N;SHIFT IN;;;;
+0010;<control>;Cc;0;BN;;;;;N;DATA LINK ESCAPE;;;;
+0011;<control>;Cc;0;BN;;;;;N;DEVICE CONTROL ONE;;;;
+0012;<control>;Cc;0;BN;;;;;N;DEVICE CONTROL TWO;;;;
+0013;<control>;Cc;0;BN;;;;;N;DEVICE CONTROL THREE;;;;
+0014;<control>;Cc;0;BN;;;;;N;DEVICE CONTROL FOUR;;;;
+0015;<control>;Cc;0;BN;;;;;N;NEGATIVE ACKNOWLEDGE;;;;
+0016;<control>;Cc;0;BN;;;;;N;SYNCHRONOUS IDLE;;;;
+0017;<control>;Cc;0;BN;;;;;N;END OF TRANSMISSION BLOCK;;;;
+0018;<control>;Cc;0;BN;;;;;N;CANCEL;;;;
+0019;<control>;Cc;0;BN;;;;;N;END OF MEDIUM;;;;
+001A;<control>;Cc;0;BN;;;;;N;SUBSTITUTE;;;;
+001B;<control>;Cc;0;BN;;;;;N;ESCAPE;;;;
+001C;<control>;Cc;0;B;;;;;N;FILE SEPARATOR;;;;
+001D;<control>;Cc;0;B;;;;;N;GROUP SEPARATOR;;;;
+001E;<control>;Cc;0;B;;;;;N;RECORD SEPARATOR;;;;
+001F;<control>;Cc;0;S;;;;;N;UNIT SEPARATOR;;;;
+0020;SPACE;Zs;0;WS;;;;;N;;;;;
+0021;EXCLAMATION MARK;Po;0;ON;;;;;N;;;;;
+0022;QUOTATION MARK;Po;0;ON;;;;;N;;;;;
+0023;NUMBER SIGN;Po;0;ET;;;;;N;;;;;
+0024;DOLLAR SIGN;Sc;0;ET;;;;;N;;;;;
+0025;PERCENT SIGN;Po;0;ET;;;;;N;;;;;
+0026;AMPERSAND;Po;0;ON;;;;;N;;;;;
+0027;APOSTROPHE;Po;0;ON;;;;;N;APOSTROPHE-QUOTE;;;;
+0028;LEFT PARENTHESIS;Ps;0;ON;;;;;Y;OPENING PARENTHESIS;;;;
+0029;RIGHT PARENTHESIS;Pe;0;ON;;;;;Y;CLOSING PARENTHESIS;;;;
+002A;ASTERISK;Po;0;ON;;;;;N;;;;;
+002B;PLUS SIGN;Sm;0;ET;;;;;N;;;;;
+002C;COMMA;Po;0;CS;;;;;N;;;;;
+002D;HYPHEN-MINUS;Pd;0;ET;;;;;N;;;;;
+002E;FULL STOP;Po;0;CS;;;;;N;PERIOD;;;;
+002F;SOLIDUS;Po;0;ES;;;;;N;SLASH;;;;
+0030;DIGIT ZERO;Nd;0;EN;;0;0;0;N;;;;;
+0031;DIGIT ONE;Nd;0;EN;;1;1;1;N;;;;;
+0032;DIGIT TWO;Nd;0;EN;;2;2;2;N;;;;;
+0033;DIGIT THREE;Nd;0;EN;;3;3;3;N;;;;;
+0034;DIGIT FOUR;Nd;0;EN;;4;4;4;N;;;;;
+0035;DIGIT FIVE;Nd;0;EN;;5;5;5;N;;;;;
+0036;DIGIT SIX;Nd;0;EN;;6;6;6;N;;;;;
+0037;DIGIT SEVEN;Nd;0;EN;;7;7;7;N;;;;;
+0038;DIGIT EIGHT;Nd;0;EN;;8;8;8;N;;;;;
+0039;DIGIT NINE;Nd;0;EN;;9;9;9;N;;;;;
+003A;COLON;Po;0;CS;;;;;N;;;;;
+003B;SEMICOLON;Po;0;ON;;;;;N;;;;;
+003C;LESS-THAN SIGN;Sm;0;ON;;;;;Y;;;;;
+003D;EQUALS SIGN;Sm;0;ON;;;;;N;;;;;
+003E;GREATER-THAN SIGN;Sm;0;ON;;;;;Y;;;;;
+003F;QUESTION MARK;Po;0;ON;;;;;N;;;;;
+0040;COMMERCIAL AT;Po;0;ON;;;;;N;;;;;
+0041;LATIN CAPITAL LETTER A;Lu;0;L;;;;;N;;;;0061;
+0042;LATIN CAPITAL LETTER B;Lu;0;L;;;;;N;;;;0062;
+0043;LATIN CAPITAL LETTER C;Lu;0;L;;;;;N;;;;0063;
+0044;LATIN CAPITAL LETTER D;Lu;0;L;;;;;N;;;;0064;
+0045;LATIN CAPITAL LETTER E;Lu;0;L;;;;;N;;;;0065;
+0046;LATIN CAPITAL LETTER F;Lu;0;L;;;;;N;;;;0066;
+0047;LATIN CAPITAL LETTER G;Lu;0;L;;;;;N;;;;0067;
+0048;LATIN CAPITAL LETTER H;Lu;0;L;;;;;N;;;;0068;
+0049;LATIN CAPITAL LETTER I;Lu;0;L;;;;;N;;;;0069;
+004A;LATIN CAPITAL LETTER J;Lu;0;L;;;;;N;;;;006A;
+004B;LATIN CAPITAL LETTER K;Lu;0;L;;;;;N;;;;006B;
+004C;LATIN CAPITAL LETTER L;Lu;0;L;;;;;N;;;;006C;
+004D;LATIN CAPITAL LETTER M;Lu;0;L;;;;;N;;;;006D;
+004E;LATIN CAPITAL LETTER N;Lu;0;L;;;;;N;;;;006E;
+004F;LATIN CAPITAL LETTER O;Lu;0;L;;;;;N;;;;006F;
+0050;LATIN CAPITAL LETTER P;Lu;0;L;;;;;N;;;;0070;
+0051;LATIN CAPITAL LETTER Q;Lu;0;L;;;;;N;;;;0071;
+0052;LATIN CAPITAL LETTER R;Lu;0;L;;;;;N;;;;0072;
+0053;LATIN CAPITAL LETTER S;Lu;0;L;;;;;N;;;;0073;
+0054;LATIN CAPITAL LETTER T;Lu;0;L;;;;;N;;;;0074;
+0055;LATIN CAPITAL LETTER U;Lu;0;L;;;;;N;;;;0075;
+0056;LATIN CAPITAL LETTER V;Lu;0;L;;;;;N;;;;0076;
+0057;LATIN CAPITAL LETTER W;Lu;0;L;;;;;N;;;;0077;
+0058;LATIN CAPITAL LETTER X;Lu;0;L;;;;;N;;;;0078;
+0059;LATIN CAPITAL LETTER Y;Lu;0;L;;;;;N;;;;0079;
+005A;LATIN CAPITAL LETTER Z;Lu;0;L;;;;;N;;;;007A;
+005B;LEFT SQUARE BRACKET;Ps;0;ON;;;;;Y;OPENING SQUARE BRACKET;;;;
+005C;REVERSE SOLIDUS;Po;0;ON;;;;;N;BACKSLASH;;;;
+005D;RIGHT SQUARE BRACKET;Pe;0;ON;;;;;Y;CLOSING SQUARE BRACKET;;;;
+005E;CIRCUMFLEX ACCENT;Sk;0;ON;;;;;N;SPACING CIRCUMFLEX;;;;
+005F;LOW LINE;Pc;0;ON;;;;;N;SPACING UNDERSCORE;;;;
+0060;GRAVE ACCENT;Sk;0;ON;;;;;N;SPACING GRAVE;;;;
+0061;LATIN SMALL LETTER A;Ll;0;L;;;;;N;;;0041;;0041
+0062;LATIN SMALL LETTER B;Ll;0;L;;;;;N;;;0042;;0042
+0063;LATIN SMALL LETTER C;Ll;0;L;;;;;N;;;0043;;0043
+0064;LATIN SMALL LETTER D;Ll;0;L;;;;;N;;;0044;;0044
+0065;LATIN SMALL LETTER E;Ll;0;L;;;;;N;;;0045;;0045
+0066;LATIN SMALL LETTER F;Ll;0;L;;;;;N;;;0046;;0046
+0067;LATIN SMALL LETTER G;Ll;0;L;;;;;N;;;0047;;0047
+0068;LATIN SMALL LETTER H;Ll;0;L;;;;;N;;;0048;;0048
+0069;LATIN SMALL LETTER I;Ll;0;L;;;;;N;;;0049;;0049
+006A;LATIN SMALL LETTER J;Ll;0;L;;;;;N;;;004A;;004A
+006B;LATIN SMALL LETTER K;Ll;0;L;;;;;N;;;004B;;004B
+006C;LATIN SMALL LETTER L;Ll;0;L;;;;;N;;;004C;;004C
+006D;LATIN SMALL LETTER M;Ll;0;L;;;;;N;;;004D;;004D
+006E;LATIN SMALL LETTER N;Ll;0;L;;;;;N;;;004E;;004E
+006F;LATIN SMALL LETTER O;Ll;0;L;;;;;N;;;004F;;004F
+0070;LATIN SMALL LETTER P;Ll;0;L;;;;;N;;;0050;;0050
+0071;LATIN SMALL LETTER Q;Ll;0;L;;;;;N;;;0051;;0051
+0072;LATIN SMALL LETTER R;Ll;0;L;;;;;N;;;0052;;0052
+0073;LATIN SMALL LETTER S;Ll;0;L;;;;;N;;;0053;;0053
+0074;LATIN SMALL LETTER T;Ll;0;L;;;;;N;;;0054;;0054
+0075;LATIN SMALL LETTER U;Ll;0;L;;;;;N;;;0055;;0055
+0076;LATIN SMALL LETTER V;Ll;0;L;;;;;N;;;0056;;0056
+0077;LATIN SMALL LETTER W;Ll;0;L;;;;;N;;;0057;;0057
+0078;LATIN SMALL LETTER X;Ll;0;L;;;;;N;;;0058;;0058
+0079;LATIN SMALL LETTER Y;Ll;0;L;;;;;N;;;0059;;0059
+007A;LATIN SMALL LETTER Z;Ll;0;L;;;;;N;;;005A;;005A
+007B;LEFT CURLY BRACKET;Ps;0;ON;;;;;Y;OPENING CURLY BRACKET;;;;
+007C;VERTICAL LINE;Sm;0;ON;;;;;N;VERTICAL BAR;;;;
+007D;RIGHT CURLY BRACKET;Pe;0;ON;;;;;Y;CLOSING CURLY BRACKET;;;;
+007E;TILDE;Sm;0;ON;;;;;N;;;;;
+007F;<control>;Cc;0;BN;;;;;N;DELETE;;;;
+0080;<control>;Cc;0;BN;;;;;N;;;;;
+0081;<control>;Cc;0;BN;;;;;N;;;;;
+0082;<control>;Cc;0;BN;;;;;N;BREAK PERMITTED HERE;;;;
+0083;<control>;Cc;0;BN;;;;;N;NO BREAK HERE;;;;
+0084;<control>;Cc;0;BN;;;;;N;;;;;
+0085;<control>;Cc;0;B;;;;;N;NEXT LINE;;;;
+0086;<control>;Cc;0;BN;;;;;N;START OF SELECTED AREA;;;;
+0087;<control>;Cc;0;BN;;;;;N;END OF SELECTED AREA;;;;
+0088;<control>;Cc;0;BN;;;;;N;CHARACTER TABULATION SET;;;;
+0089;<control>;Cc;0;BN;;;;;N;CHARACTER TABULATION WITH JUSTIFICATION;;;;
+008A;<control>;Cc;0;BN;;;;;N;LINE TABULATION SET;;;;
+008B;<control>;Cc;0;BN;;;;;N;PARTIAL LINE DOWN;;;;
+008C;<control>;Cc;0;BN;;;;;N;PARTIAL LINE UP;;;;
+008D;<control>;Cc;0;BN;;;;;N;REVERSE LINE FEED;;;;
+008E;<control>;Cc;0;BN;;;;;N;SINGLE SHIFT TWO;;;;
+008F;<control>;Cc;0;BN;;;;;N;SINGLE SHIFT THREE;;;;
+0090;<control>;Cc;0;BN;;;;;N;DEVICE CONTROL STRING;;;;
+0091;<control>;Cc;0;BN;;;;;N;PRIVATE USE ONE;;;;
+0092;<control>;Cc;0;BN;;;;;N;PRIVATE USE TWO;;;;
+0093;<control>;Cc;0;BN;;;;;N;SET TRANSMIT STATE;;;;
+0094;<control>;Cc;0;BN;;;;;N;CANCEL CHARACTER;;;;
+0095;<control>;Cc;0;BN;;;;;N;MESSAGE WAITING;;;;
+0096;<control>;Cc;0;BN;;;;;N;START OF GUARDED AREA;;;;
+0097;<control>;Cc;0;BN;;;;;N;END OF GUARDED AREA;;;;
+0098;<control>;Cc;0;BN;;;;;N;START OF STRING;;;;
+0099;<control>;Cc;0;BN;;;;;N;;;;;
+009A;<control>;Cc;0;BN;;;;;N;SINGLE CHARACTER INTRODUCER;;;;
+009B;<control>;Cc;0;BN;;;;;N;CONTROL SEQUENCE INTRODUCER;;;;
+009C;<control>;Cc;0;BN;;;;;N;STRING TERMINATOR;;;;
+009D;<control>;Cc;0;BN;;;;;N;OPERATING SYSTEM COMMAND;;;;
+009E;<control>;Cc;0;BN;;;;;N;PRIVACY MESSAGE;;;;
+009F;<control>;Cc;0;BN;;;;;N;APPLICATION PROGRAM COMMAND;;;;
+00A0;NO-BREAK SPACE;Zs;0;CS;<noBreak> 0020;;;;N;NON-BREAKING SPACE;;;;
+00A1;INVERTED EXCLAMATION MARK;Po;0;ON;;;;;N;;;;;
+00A2;CENT SIGN;Sc;0;ET;;;;;N;;;;;
+00A3;POUND SIGN;Sc;0;ET;;;;;N;;;;;
+00A4;CURRENCY SIGN;Sc;0;ET;;;;;N;;;;;
+00A5;YEN SIGN;Sc;0;ET;;;;;N;;;;;
+00A6;BROKEN BAR;So;0;ON;;;;;N;BROKEN VERTICAL BAR;;;;
+00A7;SECTION SIGN;So;0;ON;;;;;N;;;;;
+00A8;DIAERESIS;Sk;0;ON;<compat> 0020 0308;;;;N;SPACING DIAERESIS;;;;
+00A9;COPYRIGHT SIGN;So;0;ON;;;;;N;;;;;
+00AA;FEMININE ORDINAL INDICATOR;Ll;0;L;<super> 0061;;;;N;;;;;
+00AB;LEFT-POINTING DOUBLE ANGLE QUOTATION MARK;Pi;0;ON;;;;;Y;LEFT POINTING GUILLEMET;*;;;
+00AC;NOT SIGN;Sm;0;ON;;;;;N;;;;;
+00AD;SOFT HYPHEN;Pd;0;ON;;;;;N;;;;;
+00AE;REGISTERED SIGN;So;0;ON;;;;;N;REGISTERED TRADE MARK SIGN;;;;
+00AF;MACRON;Sk;0;ON;<compat> 0020 0304;;;;N;SPACING MACRON;;;;
+00B0;DEGREE SIGN;So;0;ET;;;;;N;;;;;
+00B1;PLUS-MINUS SIGN;Sm;0;ET;;;;;N;PLUS-OR-MINUS SIGN;;;;
+00B2;SUPERSCRIPT TWO;No;0;EN;<super> 0032;2;2;2;N;SUPERSCRIPT DIGIT TWO;;;;
+00B3;SUPERSCRIPT THREE;No;0;EN;<super> 0033;3;3;3;N;SUPERSCRIPT DIGIT THREE;;;;
+00B4;ACUTE ACCENT;Sk;0;ON;<compat> 0020 0301;;;;N;SPACING ACUTE;;;;
+00B5;MICRO SIGN;Ll;0;L;<compat> 03BC;;;;N;;;039C;;039C
+00B6;PILCROW SIGN;So;0;ON;;;;;N;PARAGRAPH SIGN;;;;
+00B7;MIDDLE DOT;Po;0;ON;;;;;N;;;;;
+00B8;CEDILLA;Sk;0;ON;<compat> 0020 0327;;;;N;SPACING CEDILLA;;;;
+00B9;SUPERSCRIPT ONE;No;0;EN;<super> 0031;1;1;1;N;SUPERSCRIPT DIGIT ONE;;;;
+00BA;MASCULINE ORDINAL INDICATOR;Ll;0;L;<super> 006F;;;;N;;;;;
+00BB;RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK;Pf;0;ON;;;;;Y;RIGHT POINTING GUILLEMET;*;;;
+00BC;VULGAR FRACTION ONE QUARTER;No;0;ON;<fraction> 0031 2044 0034;;;1/4;N;FRACTION ONE QUARTER;;;;
+00BD;VULGAR FRACTION ONE HALF;No;0;ON;<fraction> 0031 2044 0032;;;1/2;N;FRACTION ONE HALF;;;;
+00BE;VULGAR FRACTION THREE QUARTERS;No;0;ON;<fraction> 0033 2044 0034;;;3/4;N;FRACTION THREE QUARTERS;;;;
+00BF;INVERTED QUESTION MARK;Po;0;ON;;;;;N;;;;;
+00C0;LATIN CAPITAL LETTER A WITH GRAVE;Lu;0;L;0041 0300;;;;N;LATIN CAPITAL LETTER A GRAVE;;;00E0;
+00C1;LATIN CAPITAL LETTER A WITH ACUTE;Lu;0;L;0041 0301;;;;N;LATIN CAPITAL LETTER A ACUTE;;;00E1;
+00C2;LATIN CAPITAL LETTER A WITH CIRCUMFLEX;Lu;0;L;0041 0302;;;;N;LATIN CAPITAL LETTER A CIRCUMFLEX;;;00E2;
+00C3;LATIN CAPITAL LETTER A WITH TILDE;Lu;0;L;0041 0303;;;;N;LATIN CAPITAL LETTER A TILDE;;;00E3;
+00C4;LATIN CAPITAL LETTER A WITH DIAERESIS;Lu;0;L;0041 0308;;;;N;LATIN CAPITAL LETTER A DIAERESIS;;;00E4;
+00C5;LATIN CAPITAL LETTER A WITH RING ABOVE;Lu;0;L;0041 030A;;;;N;LATIN CAPITAL LETTER A RING;;;00E5;
+00C6;LATIN CAPITAL LETTER AE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER A E;ash *;;00E6;
+00C7;LATIN CAPITAL LETTER C WITH CEDILLA;Lu;0;L;0043 0327;;;;N;LATIN CAPITAL LETTER C CEDILLA;;;00E7;
+00C8;LATIN CAPITAL LETTER E WITH GRAVE;Lu;0;L;0045 0300;;;;N;LATIN CAPITAL LETTER E GRAVE;;;00E8;
+00C9;LATIN CAPITAL LETTER E WITH ACUTE;Lu;0;L;0045 0301;;;;N;LATIN CAPITAL LETTER E ACUTE;;;00E9;
+00CA;LATIN CAPITAL LETTER E WITH CIRCUMFLEX;Lu;0;L;0045 0302;;;;N;LATIN CAPITAL LETTER E CIRCUMFLEX;;;00EA;
+00CB;LATIN CAPITAL LETTER E WITH DIAERESIS;Lu;0;L;0045 0308;;;;N;LATIN CAPITAL LETTER E DIAERESIS;;;00EB;
+00CC;LATIN CAPITAL LETTER I WITH GRAVE;Lu;0;L;0049 0300;;;;N;LATIN CAPITAL LETTER I GRAVE;;;00EC;
+00CD;LATIN CAPITAL LETTER I WITH ACUTE;Lu;0;L;0049 0301;;;;N;LATIN CAPITAL LETTER I ACUTE;;;00ED;
+00CE;LATIN CAPITAL LETTER I WITH CIRCUMFLEX;Lu;0;L;0049 0302;;;;N;LATIN CAPITAL LETTER I CIRCUMFLEX;;;00EE;
+00CF;LATIN CAPITAL LETTER I WITH DIAERESIS;Lu;0;L;0049 0308;;;;N;LATIN CAPITAL LETTER I DIAERESIS;;;00EF;
+00D0;LATIN CAPITAL LETTER ETH;Lu;0;L;;;;;N;;Icelandic;;00F0;
+00D1;LATIN CAPITAL LETTER N WITH TILDE;Lu;0;L;004E 0303;;;;N;LATIN CAPITAL LETTER N TILDE;;;00F1;
+00D2;LATIN CAPITAL LETTER O WITH GRAVE;Lu;0;L;004F 0300;;;;N;LATIN CAPITAL LETTER O GRAVE;;;00F2;
+00D3;LATIN CAPITAL LETTER O WITH ACUTE;Lu;0;L;004F 0301;;;;N;LATIN CAPITAL LETTER O ACUTE;;;00F3;
+00D4;LATIN CAPITAL LETTER O WITH CIRCUMFLEX;Lu;0;L;004F 0302;;;;N;LATIN CAPITAL LETTER O CIRCUMFLEX;;;00F4;
+00D5;LATIN CAPITAL LETTER O WITH TILDE;Lu;0;L;004F 0303;;;;N;LATIN CAPITAL LETTER O TILDE;;;00F5;
+00D6;LATIN CAPITAL LETTER O WITH DIAERESIS;Lu;0;L;004F 0308;;;;N;LATIN CAPITAL LETTER O DIAERESIS;;;00F6;
+00D7;MULTIPLICATION SIGN;Sm;0;ON;;;;;N;;;;;
+00D8;LATIN CAPITAL LETTER O WITH STROKE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER O SLASH;;;00F8;
+00D9;LATIN CAPITAL LETTER U WITH GRAVE;Lu;0;L;0055 0300;;;;N;LATIN CAPITAL LETTER U GRAVE;;;00F9;
+00DA;LATIN CAPITAL LETTER U WITH ACUTE;Lu;0;L;0055 0301;;;;N;LATIN CAPITAL LETTER U ACUTE;;;00FA;
+00DB;LATIN CAPITAL LETTER U WITH CIRCUMFLEX;Lu;0;L;0055 0302;;;;N;LATIN CAPITAL LETTER U CIRCUMFLEX;;;00FB;
+00DC;LATIN CAPITAL LETTER U WITH DIAERESIS;Lu;0;L;0055 0308;;;;N;LATIN CAPITAL LETTER U DIAERESIS;;;00FC;
+00DD;LATIN CAPITAL LETTER Y WITH ACUTE;Lu;0;L;0059 0301;;;;N;LATIN CAPITAL LETTER Y ACUTE;;;00FD;
+00DE;LATIN CAPITAL LETTER THORN;Lu;0;L;;;;;N;;Icelandic;;00FE;
+00DF;LATIN SMALL LETTER SHARP S;Ll;0;L;;;;;N;;German;;;
+00E0;LATIN SMALL LETTER A WITH GRAVE;Ll;0;L;0061 0300;;;;N;LATIN SMALL LETTER A GRAVE;;00C0;;00C0
+00E1;LATIN SMALL LETTER A WITH ACUTE;Ll;0;L;0061 0301;;;;N;LATIN SMALL LETTER A ACUTE;;00C1;;00C1
+00E2;LATIN SMALL LETTER A WITH CIRCUMFLEX;Ll;0;L;0061 0302;;;;N;LATIN SMALL LETTER A CIRCUMFLEX;;00C2;;00C2
+00E3;LATIN SMALL LETTER A WITH TILDE;Ll;0;L;0061 0303;;;;N;LATIN SMALL LETTER A TILDE;;00C3;;00C3
+00E4;LATIN SMALL LETTER A WITH DIAERESIS;Ll;0;L;0061 0308;;;;N;LATIN SMALL LETTER A DIAERESIS;;00C4;;00C4
+00E5;LATIN SMALL LETTER A WITH RING ABOVE;Ll;0;L;0061 030A;;;;N;LATIN SMALL LETTER A RING;;00C5;;00C5
+00E6;LATIN SMALL LETTER AE;Ll;0;L;;;;;N;LATIN SMALL LETTER A E;ash *;00C6;;00C6
+00E7;LATIN SMALL LETTER C WITH CEDILLA;Ll;0;L;0063 0327;;;;N;LATIN SMALL LETTER C CEDILLA;;00C7;;00C7
+00E8;LATIN SMALL LETTER E WITH GRAVE;Ll;0;L;0065 0300;;;;N;LATIN SMALL LETTER E GRAVE;;00C8;;00C8
+00E9;LATIN SMALL LETTER E WITH ACUTE;Ll;0;L;0065 0301;;;;N;LATIN SMALL LETTER E ACUTE;;00C9;;00C9
+00EA;LATIN SMALL LETTER E WITH CIRCUMFLEX;Ll;0;L;0065 0302;;;;N;LATIN SMALL LETTER E CIRCUMFLEX;;00CA;;00CA
+00EB;LATIN SMALL LETTER E WITH DIAERESIS;Ll;0;L;0065 0308;;;;N;LATIN SMALL LETTER E DIAERESIS;;00CB;;00CB
+00EC;LATIN SMALL LETTER I WITH GRAVE;Ll;0;L;0069 0300;;;;N;LATIN SMALL LETTER I GRAVE;;00CC;;00CC
+00ED;LATIN SMALL LETTER I WITH ACUTE;Ll;0;L;0069 0301;;;;N;LATIN SMALL LETTER I ACUTE;;00CD;;00CD
+00EE;LATIN SMALL LETTER I WITH CIRCUMFLEX;Ll;0;L;0069 0302;;;;N;LATIN SMALL LETTER I CIRCUMFLEX;;00CE;;00CE
+00EF;LATIN SMALL LETTER I WITH DIAERESIS;Ll;0;L;0069 0308;;;;N;LATIN SMALL LETTER I DIAERESIS;;00CF;;00CF
+00F0;LATIN SMALL LETTER ETH;Ll;0;L;;;;;N;;Icelandic;00D0;;00D0
+00F1;LATIN SMALL LETTER N WITH TILDE;Ll;0;L;006E 0303;;;;N;LATIN SMALL LETTER N TILDE;;00D1;;00D1
+00F2;LATIN SMALL LETTER O WITH GRAVE;Ll;0;L;006F 0300;;;;N;LATIN SMALL LETTER O GRAVE;;00D2;;00D2
+00F3;LATIN SMALL LETTER O WITH ACUTE;Ll;0;L;006F 0301;;;;N;LATIN SMALL LETTER O ACUTE;;00D3;;00D3
+00F4;LATIN SMALL LETTER O WITH CIRCUMFLEX;Ll;0;L;006F 0302;;;;N;LATIN SMALL LETTER O CIRCUMFLEX;;00D4;;00D4
+00F5;LATIN SMALL LETTER O WITH TILDE;Ll;0;L;006F 0303;;;;N;LATIN SMALL LETTER O TILDE;;00D5;;00D5
+00F6;LATIN SMALL LETTER O WITH DIAERESIS;Ll;0;L;006F 0308;;;;N;LATIN SMALL LETTER O DIAERESIS;;00D6;;00D6
+00F7;DIVISION SIGN;Sm;0;ON;;;;;N;;;;;
+00F8;LATIN SMALL LETTER O WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER O SLASH;;00D8;;00D8
+00F9;LATIN SMALL LETTER U WITH GRAVE;Ll;0;L;0075 0300;;;;N;LATIN SMALL LETTER U GRAVE;;00D9;;00D9
+00FA;LATIN SMALL LETTER U WITH ACUTE;Ll;0;L;0075 0301;;;;N;LATIN SMALL LETTER U ACUTE;;00DA;;00DA
+00FB;LATIN SMALL LETTER U WITH CIRCUMFLEX;Ll;0;L;0075 0302;;;;N;LATIN SMALL LETTER U CIRCUMFLEX;;00DB;;00DB
+00FC;LATIN SMALL LETTER U WITH DIAERESIS;Ll;0;L;0075 0308;;;;N;LATIN SMALL LETTER U DIAERESIS;;00DC;;00DC
+00FD;LATIN SMALL LETTER Y WITH ACUTE;Ll;0;L;0079 0301;;;;N;LATIN SMALL LETTER Y ACUTE;;00DD;;00DD
+00FE;LATIN SMALL LETTER THORN;Ll;0;L;;;;;N;;Icelandic;00DE;;00DE
+00FF;LATIN SMALL LETTER Y WITH DIAERESIS;Ll;0;L;0079 0308;;;;N;LATIN SMALL LETTER Y DIAERESIS;;0178;;0178
+0100;LATIN CAPITAL LETTER A WITH MACRON;Lu;0;L;0041 0304;;;;N;LATIN CAPITAL LETTER A MACRON;;;0101;
+0101;LATIN SMALL LETTER A WITH MACRON;Ll;0;L;0061 0304;;;;N;LATIN SMALL LETTER A MACRON;;0100;;0100
+0102;LATIN CAPITAL LETTER A WITH BREVE;Lu;0;L;0041 0306;;;;N;LATIN CAPITAL LETTER A BREVE;;;0103;
+0103;LATIN SMALL LETTER A WITH BREVE;Ll;0;L;0061 0306;;;;N;LATIN SMALL LETTER A BREVE;;0102;;0102
+0104;LATIN CAPITAL LETTER A WITH OGONEK;Lu;0;L;0041 0328;;;;N;LATIN CAPITAL LETTER A OGONEK;;;0105;
+0105;LATIN SMALL LETTER A WITH OGONEK;Ll;0;L;0061 0328;;;;N;LATIN SMALL LETTER A OGONEK;;0104;;0104
+0106;LATIN CAPITAL LETTER C WITH ACUTE;Lu;0;L;0043 0301;;;;N;LATIN CAPITAL LETTER C ACUTE;;;0107;
+0107;LATIN SMALL LETTER C WITH ACUTE;Ll;0;L;0063 0301;;;;N;LATIN SMALL LETTER C ACUTE;;0106;;0106
+0108;LATIN CAPITAL LETTER C WITH CIRCUMFLEX;Lu;0;L;0043 0302;;;;N;LATIN CAPITAL LETTER C CIRCUMFLEX;;;0109;
+0109;LATIN SMALL LETTER C WITH CIRCUMFLEX;Ll;0;L;0063 0302;;;;N;LATIN SMALL LETTER C CIRCUMFLEX;;0108;;0108
+010A;LATIN CAPITAL LETTER C WITH DOT ABOVE;Lu;0;L;0043 0307;;;;N;LATIN CAPITAL LETTER C DOT;;;010B;
+010B;LATIN SMALL LETTER C WITH DOT ABOVE;Ll;0;L;0063 0307;;;;N;LATIN SMALL LETTER C DOT;;010A;;010A
+010C;LATIN CAPITAL LETTER C WITH CARON;Lu;0;L;0043 030C;;;;N;LATIN CAPITAL LETTER C HACEK;;;010D;
+010D;LATIN SMALL LETTER C WITH CARON;Ll;0;L;0063 030C;;;;N;LATIN SMALL LETTER C HACEK;;010C;;010C
+010E;LATIN CAPITAL LETTER D WITH CARON;Lu;0;L;0044 030C;;;;N;LATIN CAPITAL LETTER D HACEK;;;010F;
+010F;LATIN SMALL LETTER D WITH CARON;Ll;0;L;0064 030C;;;;N;LATIN SMALL LETTER D HACEK;;010E;;010E
+0110;LATIN CAPITAL LETTER D WITH STROKE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER D BAR;;;0111;
+0111;LATIN SMALL LETTER D WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER D BAR;;0110;;0110
+0112;LATIN CAPITAL LETTER E WITH MACRON;Lu;0;L;0045 0304;;;;N;LATIN CAPITAL LETTER E MACRON;;;0113;
+0113;LATIN SMALL LETTER E WITH MACRON;Ll;0;L;0065 0304;;;;N;LATIN SMALL LETTER E MACRON;;0112;;0112
+0114;LATIN CAPITAL LETTER E WITH BREVE;Lu;0;L;0045 0306;;;;N;LATIN CAPITAL LETTER E BREVE;;;0115;
+0115;LATIN SMALL LETTER E WITH BREVE;Ll;0;L;0065 0306;;;;N;LATIN SMALL LETTER E BREVE;;0114;;0114
+0116;LATIN CAPITAL LETTER E WITH DOT ABOVE;Lu;0;L;0045 0307;;;;N;LATIN CAPITAL LETTER E DOT;;;0117;
+0117;LATIN SMALL LETTER E WITH DOT ABOVE;Ll;0;L;0065 0307;;;;N;LATIN SMALL LETTER E DOT;;0116;;0116
+0118;LATIN CAPITAL LETTER E WITH OGONEK;Lu;0;L;0045 0328;;;;N;LATIN CAPITAL LETTER E OGONEK;;;0119;
+0119;LATIN SMALL LETTER E WITH OGONEK;Ll;0;L;0065 0328;;;;N;LATIN SMALL LETTER E OGONEK;;0118;;0118
+011A;LATIN CAPITAL LETTER E WITH CARON;Lu;0;L;0045 030C;;;;N;LATIN CAPITAL LETTER E HACEK;;;011B;
+011B;LATIN SMALL LETTER E WITH CARON;Ll;0;L;0065 030C;;;;N;LATIN SMALL LETTER E HACEK;;011A;;011A
+011C;LATIN CAPITAL LETTER G WITH CIRCUMFLEX;Lu;0;L;0047 0302;;;;N;LATIN CAPITAL LETTER G CIRCUMFLEX;;;011D;
+011D;LATIN SMALL LETTER G WITH CIRCUMFLEX;Ll;0;L;0067 0302;;;;N;LATIN SMALL LETTER G CIRCUMFLEX;;011C;;011C
+011E;LATIN CAPITAL LETTER G WITH BREVE;Lu;0;L;0047 0306;;;;N;LATIN CAPITAL LETTER G BREVE;;;011F;
+011F;LATIN SMALL LETTER G WITH BREVE;Ll;0;L;0067 0306;;;;N;LATIN SMALL LETTER G BREVE;;011E;;011E
+0120;LATIN CAPITAL LETTER G WITH DOT ABOVE;Lu;0;L;0047 0307;;;;N;LATIN CAPITAL LETTER G DOT;;;0121;
+0121;LATIN SMALL LETTER G WITH DOT ABOVE;Ll;0;L;0067 0307;;;;N;LATIN SMALL LETTER G DOT;;0120;;0120
+0122;LATIN CAPITAL LETTER G WITH CEDILLA;Lu;0;L;0047 0327;;;;N;LATIN CAPITAL LETTER G CEDILLA;;;0123;
+0123;LATIN SMALL LETTER G WITH CEDILLA;Ll;0;L;0067 0327;;;;N;LATIN SMALL LETTER G CEDILLA;;0122;;0122
+0124;LATIN CAPITAL LETTER H WITH CIRCUMFLEX;Lu;0;L;0048 0302;;;;N;LATIN CAPITAL LETTER H CIRCUMFLEX;;;0125;
+0125;LATIN SMALL LETTER H WITH CIRCUMFLEX;Ll;0;L;0068 0302;;;;N;LATIN SMALL LETTER H CIRCUMFLEX;;0124;;0124
+0126;LATIN CAPITAL LETTER H WITH STROKE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER H BAR;;;0127;
+0127;LATIN SMALL LETTER H WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER H BAR;;0126;;0126
+0128;LATIN CAPITAL LETTER I WITH TILDE;Lu;0;L;0049 0303;;;;N;LATIN CAPITAL LETTER I TILDE;;;0129;
+0129;LATIN SMALL LETTER I WITH TILDE;Ll;0;L;0069 0303;;;;N;LATIN SMALL LETTER I TILDE;;0128;;0128
+012A;LATIN CAPITAL LETTER I WITH MACRON;Lu;0;L;0049 0304;;;;N;LATIN CAPITAL LETTER I MACRON;;;012B;
+012B;LATIN SMALL LETTER I WITH MACRON;Ll;0;L;0069 0304;;;;N;LATIN SMALL LETTER I MACRON;;012A;;012A
+012C;LATIN CAPITAL LETTER I WITH BREVE;Lu;0;L;0049 0306;;;;N;LATIN CAPITAL LETTER I BREVE;;;012D;
+012D;LATIN SMALL LETTER I WITH BREVE;Ll;0;L;0069 0306;;;;N;LATIN SMALL LETTER I BREVE;;012C;;012C
+012E;LATIN CAPITAL LETTER I WITH OGONEK;Lu;0;L;0049 0328;;;;N;LATIN CAPITAL LETTER I OGONEK;;;012F;
+012F;LATIN SMALL LETTER I WITH OGONEK;Ll;0;L;0069 0328;;;;N;LATIN SMALL LETTER I OGONEK;;012E;;012E
+0130;LATIN CAPITAL LETTER I WITH DOT ABOVE;Lu;0;L;0049 0307;;;;N;LATIN CAPITAL LETTER I DOT;;;0069;
+0131;LATIN SMALL LETTER DOTLESS I;Ll;0;L;;;;;N;;;0049;;0049
+0132;LATIN CAPITAL LIGATURE IJ;Lu;0;L;<compat> 0049 004A;;;;N;LATIN CAPITAL LETTER I J;;;0133;
+0133;LATIN SMALL LIGATURE IJ;Ll;0;L;<compat> 0069 006A;;;;N;LATIN SMALL LETTER I J;;0132;;0132
+0134;LATIN CAPITAL LETTER J WITH CIRCUMFLEX;Lu;0;L;004A 0302;;;;N;LATIN CAPITAL LETTER J CIRCUMFLEX;;;0135;
+0135;LATIN SMALL LETTER J WITH CIRCUMFLEX;Ll;0;L;006A 0302;;;;N;LATIN SMALL LETTER J CIRCUMFLEX;;0134;;0134
+0136;LATIN CAPITAL LETTER K WITH CEDILLA;Lu;0;L;004B 0327;;;;N;LATIN CAPITAL LETTER K CEDILLA;;;0137;
+0137;LATIN SMALL LETTER K WITH CEDILLA;Ll;0;L;006B 0327;;;;N;LATIN SMALL LETTER K CEDILLA;;0136;;0136
+0138;LATIN SMALL LETTER KRA;Ll;0;L;;;;;N;;Greenlandic;;;
+0139;LATIN CAPITAL LETTER L WITH ACUTE;Lu;0;L;004C 0301;;;;N;LATIN CAPITAL LETTER L ACUTE;;;013A;
+013A;LATIN SMALL LETTER L WITH ACUTE;Ll;0;L;006C 0301;;;;N;LATIN SMALL LETTER L ACUTE;;0139;;0139
+013B;LATIN CAPITAL LETTER L WITH CEDILLA;Lu;0;L;004C 0327;;;;N;LATIN CAPITAL LETTER L CEDILLA;;;013C;
+013C;LATIN SMALL LETTER L WITH CEDILLA;Ll;0;L;006C 0327;;;;N;LATIN SMALL LETTER L CEDILLA;;013B;;013B
+013D;LATIN CAPITAL LETTER L WITH CARON;Lu;0;L;004C 030C;;;;N;LATIN CAPITAL LETTER L HACEK;;;013E;
+013E;LATIN SMALL LETTER L WITH CARON;Ll;0;L;006C 030C;;;;N;LATIN SMALL LETTER L HACEK;;013D;;013D
+013F;LATIN CAPITAL LETTER L WITH MIDDLE DOT;Lu;0;L;<compat> 004C 00B7;;;;N;;;;0140;
+0140;LATIN SMALL LETTER L WITH MIDDLE DOT;Ll;0;L;<compat> 006C 00B7;;;;N;;;013F;;013F
+0141;LATIN CAPITAL LETTER L WITH STROKE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER L SLASH;;;0142;
+0142;LATIN SMALL LETTER L WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER L SLASH;;0141;;0141
+0143;LATIN CAPITAL LETTER N WITH ACUTE;Lu;0;L;004E 0301;;;;N;LATIN CAPITAL LETTER N ACUTE;;;0144;
+0144;LATIN SMALL LETTER N WITH ACUTE;Ll;0;L;006E 0301;;;;N;LATIN SMALL LETTER N ACUTE;;0143;;0143
+0145;LATIN CAPITAL LETTER N WITH CEDILLA;Lu;0;L;004E 0327;;;;N;LATIN CAPITAL LETTER N CEDILLA;;;0146;
+0146;LATIN SMALL LETTER N WITH CEDILLA;Ll;0;L;006E 0327;;;;N;LATIN SMALL LETTER N CEDILLA;;0145;;0145
+0147;LATIN CAPITAL LETTER N WITH CARON;Lu;0;L;004E 030C;;;;N;LATIN CAPITAL LETTER N HACEK;;;0148;
+0148;LATIN SMALL LETTER N WITH CARON;Ll;0;L;006E 030C;;;;N;LATIN SMALL LETTER N HACEK;;0147;;0147
+0149;LATIN SMALL LETTER N PRECEDED BY APOSTROPHE;Ll;0;L;<compat> 02BC 006E;;;;N;LATIN SMALL LETTER APOSTROPHE N;;;;
+014A;LATIN CAPITAL LETTER ENG;Lu;0;L;;;;;N;;Sami;;014B;
+014B;LATIN SMALL LETTER ENG;Ll;0;L;;;;;N;;Sami;014A;;014A
+014C;LATIN CAPITAL LETTER O WITH MACRON;Lu;0;L;004F 0304;;;;N;LATIN CAPITAL LETTER O MACRON;;;014D;
+014D;LATIN SMALL LETTER O WITH MACRON;Ll;0;L;006F 0304;;;;N;LATIN SMALL LETTER O MACRON;;014C;;014C
+014E;LATIN CAPITAL LETTER O WITH BREVE;Lu;0;L;004F 0306;;;;N;LATIN CAPITAL LETTER O BREVE;;;014F;
+014F;LATIN SMALL LETTER O WITH BREVE;Ll;0;L;006F 0306;;;;N;LATIN SMALL LETTER O BREVE;;014E;;014E
+0150;LATIN CAPITAL LETTER O WITH DOUBLE ACUTE;Lu;0;L;004F 030B;;;;N;LATIN CAPITAL LETTER O DOUBLE ACUTE;;;0151;
+0151;LATIN SMALL LETTER O WITH DOUBLE ACUTE;Ll;0;L;006F 030B;;;;N;LATIN SMALL LETTER O DOUBLE ACUTE;;0150;;0150
+0152;LATIN CAPITAL LIGATURE OE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER O E;;;0153;
+0153;LATIN SMALL LIGATURE OE;Ll;0;L;;;;;N;LATIN SMALL LETTER O E;;0152;;0152
+0154;LATIN CAPITAL LETTER R WITH ACUTE;Lu;0;L;0052 0301;;;;N;LATIN CAPITAL LETTER R ACUTE;;;0155;
+0155;LATIN SMALL LETTER R WITH ACUTE;Ll;0;L;0072 0301;;;;N;LATIN SMALL LETTER R ACUTE;;0154;;0154
+0156;LATIN CAPITAL LETTER R WITH CEDILLA;Lu;0;L;0052 0327;;;;N;LATIN CAPITAL LETTER R CEDILLA;;;0157;
+0157;LATIN SMALL LETTER R WITH CEDILLA;Ll;0;L;0072 0327;;;;N;LATIN SMALL LETTER R CEDILLA;;0156;;0156
+0158;LATIN CAPITAL LETTER R WITH CARON;Lu;0;L;0052 030C;;;;N;LATIN CAPITAL LETTER R HACEK;;;0159;
+0159;LATIN SMALL LETTER R WITH CARON;Ll;0;L;0072 030C;;;;N;LATIN SMALL LETTER R HACEK;;0158;;0158
+015A;LATIN CAPITAL LETTER S WITH ACUTE;Lu;0;L;0053 0301;;;;N;LATIN CAPITAL LETTER S ACUTE;;;015B;
+015B;LATIN SMALL LETTER S WITH ACUTE;Ll;0;L;0073 0301;;;;N;LATIN SMALL LETTER S ACUTE;;015A;;015A
+015C;LATIN CAPITAL LETTER S WITH CIRCUMFLEX;Lu;0;L;0053 0302;;;;N;LATIN CAPITAL LETTER S CIRCUMFLEX;;;015D;
+015D;LATIN SMALL LETTER S WITH CIRCUMFLEX;Ll;0;L;0073 0302;;;;N;LATIN SMALL LETTER S CIRCUMFLEX;;015C;;015C
+015E;LATIN CAPITAL LETTER S WITH CEDILLA;Lu;0;L;0053 0327;;;;N;LATIN CAPITAL LETTER S CEDILLA;*;;015F;
+015F;LATIN SMALL LETTER S WITH CEDILLA;Ll;0;L;0073 0327;;;;N;LATIN SMALL LETTER S CEDILLA;*;015E;;015E
+0160;LATIN CAPITAL LETTER S WITH CARON;Lu;0;L;0053 030C;;;;N;LATIN CAPITAL LETTER S HACEK;;;0161;
+0161;LATIN SMALL LETTER S WITH CARON;Ll;0;L;0073 030C;;;;N;LATIN SMALL LETTER S HACEK;;0160;;0160
+0162;LATIN CAPITAL LETTER T WITH CEDILLA;Lu;0;L;0054 0327;;;;N;LATIN CAPITAL LETTER T CEDILLA;*;;0163;
+0163;LATIN SMALL LETTER T WITH CEDILLA;Ll;0;L;0074 0327;;;;N;LATIN SMALL LETTER T CEDILLA;*;0162;;0162
+0164;LATIN CAPITAL LETTER T WITH CARON;Lu;0;L;0054 030C;;;;N;LATIN CAPITAL LETTER T HACEK;;;0165;
+0165;LATIN SMALL LETTER T WITH CARON;Ll;0;L;0074 030C;;;;N;LATIN SMALL LETTER T HACEK;;0164;;0164
+0166;LATIN CAPITAL LETTER T WITH STROKE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER T BAR;;;0167;
+0167;LATIN SMALL LETTER T WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER T BAR;;0166;;0166
+0168;LATIN CAPITAL LETTER U WITH TILDE;Lu;0;L;0055 0303;;;;N;LATIN CAPITAL LETTER U TILDE;;;0169;
+0169;LATIN SMALL LETTER U WITH TILDE;Ll;0;L;0075 0303;;;;N;LATIN SMALL LETTER U TILDE;;0168;;0168
+016A;LATIN CAPITAL LETTER U WITH MACRON;Lu;0;L;0055 0304;;;;N;LATIN CAPITAL LETTER U MACRON;;;016B;
+016B;LATIN SMALL LETTER U WITH MACRON;Ll;0;L;0075 0304;;;;N;LATIN SMALL LETTER U MACRON;;016A;;016A
+016C;LATIN CAPITAL LETTER U WITH BREVE;Lu;0;L;0055 0306;;;;N;LATIN CAPITAL LETTER U BREVE;;;016D;
+016D;LATIN SMALL LETTER U WITH BREVE;Ll;0;L;0075 0306;;;;N;LATIN SMALL LETTER U BREVE;;016C;;016C
+016E;LATIN CAPITAL LETTER U WITH RING ABOVE;Lu;0;L;0055 030A;;;;N;LATIN CAPITAL LETTER U RING;;;016F;
+016F;LATIN SMALL LETTER U WITH RING ABOVE;Ll;0;L;0075 030A;;;;N;LATIN SMALL LETTER U RING;;016E;;016E
+0170;LATIN CAPITAL LETTER U WITH DOUBLE ACUTE;Lu;0;L;0055 030B;;;;N;LATIN CAPITAL LETTER U DOUBLE ACUTE;;;0171;
+0171;LATIN SMALL LETTER U WITH DOUBLE ACUTE;Ll;0;L;0075 030B;;;;N;LATIN SMALL LETTER U DOUBLE ACUTE;;0170;;0170
+0172;LATIN CAPITAL LETTER U WITH OGONEK;Lu;0;L;0055 0328;;;;N;LATIN CAPITAL LETTER U OGONEK;;;0173;
+0173;LATIN SMALL LETTER U WITH OGONEK;Ll;0;L;0075 0328;;;;N;LATIN SMALL LETTER U OGONEK;;0172;;0172
+0174;LATIN CAPITAL LETTER W WITH CIRCUMFLEX;Lu;0;L;0057 0302;;;;N;LATIN CAPITAL LETTER W CIRCUMFLEX;;;0175;
+0175;LATIN SMALL LETTER W WITH CIRCUMFLEX;Ll;0;L;0077 0302;;;;N;LATIN SMALL LETTER W CIRCUMFLEX;;0174;;0174
+0176;LATIN CAPITAL LETTER Y WITH CIRCUMFLEX;Lu;0;L;0059 0302;;;;N;LATIN CAPITAL LETTER Y CIRCUMFLEX;;;0177;
+0177;LATIN SMALL LETTER Y WITH CIRCUMFLEX;Ll;0;L;0079 0302;;;;N;LATIN SMALL LETTER Y CIRCUMFLEX;;0176;;0176
+0178;LATIN CAPITAL LETTER Y WITH DIAERESIS;Lu;0;L;0059 0308;;;;N;LATIN CAPITAL LETTER Y DIAERESIS;;;00FF;
+0179;LATIN CAPITAL LETTER Z WITH ACUTE;Lu;0;L;005A 0301;;;;N;LATIN CAPITAL LETTER Z ACUTE;;;017A;
+017A;LATIN SMALL LETTER Z WITH ACUTE;Ll;0;L;007A 0301;;;;N;LATIN SMALL LETTER Z ACUTE;;0179;;0179
+017B;LATIN CAPITAL LETTER Z WITH DOT ABOVE;Lu;0;L;005A 0307;;;;N;LATIN CAPITAL LETTER Z DOT;;;017C;
+017C;LATIN SMALL LETTER Z WITH DOT ABOVE;Ll;0;L;007A 0307;;;;N;LATIN SMALL LETTER Z DOT;;017B;;017B
+017D;LATIN CAPITAL LETTER Z WITH CARON;Lu;0;L;005A 030C;;;;N;LATIN CAPITAL LETTER Z HACEK;;;017E;
+017E;LATIN SMALL LETTER Z WITH CARON;Ll;0;L;007A 030C;;;;N;LATIN SMALL LETTER Z HACEK;;017D;;017D
+017F;LATIN SMALL LETTER LONG S;Ll;0;L;<compat> 0073;;;;N;;;0053;;0053
+0180;LATIN SMALL LETTER B WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER B BAR;;;;
+0181;LATIN CAPITAL LETTER B WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER B HOOK;;;0253;
+0182;LATIN CAPITAL LETTER B WITH TOPBAR;Lu;0;L;;;;;N;LATIN CAPITAL LETTER B TOPBAR;;;0183;
+0183;LATIN SMALL LETTER B WITH TOPBAR;Ll;0;L;;;;;N;LATIN SMALL LETTER B TOPBAR;;0182;;0182
+0184;LATIN CAPITAL LETTER TONE SIX;Lu;0;L;;;;;N;;;;0185;
+0185;LATIN SMALL LETTER TONE SIX;Ll;0;L;;;;;N;;;0184;;0184
+0186;LATIN CAPITAL LETTER OPEN O;Lu;0;L;;;;;N;;;;0254;
+0187;LATIN CAPITAL LETTER C WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER C HOOK;;;0188;
+0188;LATIN SMALL LETTER C WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER C HOOK;;0187;;0187
+0189;LATIN CAPITAL LETTER AFRICAN D;Lu;0;L;;;;;N;;*;;0256;
+018A;LATIN CAPITAL LETTER D WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER D HOOK;;;0257;
+018B;LATIN CAPITAL LETTER D WITH TOPBAR;Lu;0;L;;;;;N;LATIN CAPITAL LETTER D TOPBAR;;;018C;
+018C;LATIN SMALL LETTER D WITH TOPBAR;Ll;0;L;;;;;N;LATIN SMALL LETTER D TOPBAR;;018B;;018B
+018D;LATIN SMALL LETTER TURNED DELTA;Ll;0;L;;;;;N;;;;;
+018E;LATIN CAPITAL LETTER REVERSED E;Lu;0;L;;;;;N;LATIN CAPITAL LETTER TURNED E;;;01DD;
+018F;LATIN CAPITAL LETTER SCHWA;Lu;0;L;;;;;N;;;;0259;
+0190;LATIN CAPITAL LETTER OPEN E;Lu;0;L;;;;;N;LATIN CAPITAL LETTER EPSILON;;;025B;
+0191;LATIN CAPITAL LETTER F WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER F HOOK;;;0192;
+0192;LATIN SMALL LETTER F WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER SCRIPT F;;0191;;0191
+0193;LATIN CAPITAL LETTER G WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER G HOOK;;;0260;
+0194;LATIN CAPITAL LETTER GAMMA;Lu;0;L;;;;;N;;;;0263;
+0195;LATIN SMALL LETTER HV;Ll;0;L;;;;;N;LATIN SMALL LETTER H V;hwair;01F6;;01F6
+0196;LATIN CAPITAL LETTER IOTA;Lu;0;L;;;;;N;;;;0269;
+0197;LATIN CAPITAL LETTER I WITH STROKE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER BARRED I;;;0268;
+0198;LATIN CAPITAL LETTER K WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER K HOOK;;;0199;
+0199;LATIN SMALL LETTER K WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER K HOOK;;0198;;0198
+019A;LATIN SMALL LETTER L WITH BAR;Ll;0;L;;;;;N;LATIN SMALL LETTER BARRED L;;;;
+019B;LATIN SMALL LETTER LAMBDA WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER BARRED LAMBDA;;;;
+019C;LATIN CAPITAL LETTER TURNED M;Lu;0;L;;;;;N;;;;026F;
+019D;LATIN CAPITAL LETTER N WITH LEFT HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER N HOOK;;;0272;
+019E;LATIN SMALL LETTER N WITH LONG RIGHT LEG;Ll;0;L;;;;;N;;;;;
+019F;LATIN CAPITAL LETTER O WITH MIDDLE TILDE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER BARRED O;*;;0275;
+01A0;LATIN CAPITAL LETTER O WITH HORN;Lu;0;L;004F 031B;;;;N;LATIN CAPITAL LETTER O HORN;;;01A1;
+01A1;LATIN SMALL LETTER O WITH HORN;Ll;0;L;006F 031B;;;;N;LATIN SMALL LETTER O HORN;;01A0;;01A0
+01A2;LATIN CAPITAL LETTER OI;Lu;0;L;;;;;N;LATIN CAPITAL LETTER O I;gha;;01A3;
+01A3;LATIN SMALL LETTER OI;Ll;0;L;;;;;N;LATIN SMALL LETTER O I;gha;01A2;;01A2
+01A4;LATIN CAPITAL LETTER P WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER P HOOK;;;01A5;
+01A5;LATIN SMALL LETTER P WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER P HOOK;;01A4;;01A4
+01A6;LATIN LETTER YR;Lu;0;L;;;;;N;LATIN LETTER Y R;*;;0280;
+01A7;LATIN CAPITAL LETTER TONE TWO;Lu;0;L;;;;;N;;;;01A8;
+01A8;LATIN SMALL LETTER TONE TWO;Ll;0;L;;;;;N;;;01A7;;01A7
+01A9;LATIN CAPITAL LETTER ESH;Lu;0;L;;;;;N;;;;0283;
+01AA;LATIN LETTER REVERSED ESH LOOP;Ll;0;L;;;;;N;;;;;
+01AB;LATIN SMALL LETTER T WITH PALATAL HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER T PALATAL HOOK;;;;
+01AC;LATIN CAPITAL LETTER T WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER T HOOK;;;01AD;
+01AD;LATIN SMALL LETTER T WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER T HOOK;;01AC;;01AC
+01AE;LATIN CAPITAL LETTER T WITH RETROFLEX HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER T RETROFLEX HOOK;;;0288;
+01AF;LATIN CAPITAL LETTER U WITH HORN;Lu;0;L;0055 031B;;;;N;LATIN CAPITAL LETTER U HORN;;;01B0;
+01B0;LATIN SMALL LETTER U WITH HORN;Ll;0;L;0075 031B;;;;N;LATIN SMALL LETTER U HORN;;01AF;;01AF
+01B1;LATIN CAPITAL LETTER UPSILON;Lu;0;L;;;;;N;;;;028A;
+01B2;LATIN CAPITAL LETTER V WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER SCRIPT V;;;028B;
+01B3;LATIN CAPITAL LETTER Y WITH HOOK;Lu;0;L;;;;;N;LATIN CAPITAL LETTER Y HOOK;;;01B4;
+01B4;LATIN SMALL LETTER Y WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER Y HOOK;;01B3;;01B3
+01B5;LATIN CAPITAL LETTER Z WITH STROKE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER Z BAR;;;01B6;
+01B6;LATIN SMALL LETTER Z WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER Z BAR;;01B5;;01B5
+01B7;LATIN CAPITAL LETTER EZH;Lu;0;L;;;;;N;LATIN CAPITAL LETTER YOGH;;;0292;
+01B8;LATIN CAPITAL LETTER EZH REVERSED;Lu;0;L;;;;;N;LATIN CAPITAL LETTER REVERSED YOGH;;;01B9;
+01B9;LATIN SMALL LETTER EZH REVERSED;Ll;0;L;;;;;N;LATIN SMALL LETTER REVERSED YOGH;;01B8;;01B8
+01BA;LATIN SMALL LETTER EZH WITH TAIL;Ll;0;L;;;;;N;LATIN SMALL LETTER YOGH WITH TAIL;;;;
+01BB;LATIN LETTER TWO WITH STROKE;Lo;0;L;;;;;N;LATIN LETTER TWO BAR;;;;
+01BC;LATIN CAPITAL LETTER TONE FIVE;Lu;0;L;;;;;N;;;;01BD;
+01BD;LATIN SMALL LETTER TONE FIVE;Ll;0;L;;;;;N;;;01BC;;01BC
+01BE;LATIN LETTER INVERTED GLOTTAL STOP WITH STROKE;Ll;0;L;;;;;N;LATIN LETTER INVERTED GLOTTAL STOP BAR;;;;
+01BF;LATIN LETTER WYNN;Ll;0;L;;;;;N;;;01F7;;01F7
+01C0;LATIN LETTER DENTAL CLICK;Lo;0;L;;;;;N;LATIN LETTER PIPE;;;;
+01C1;LATIN LETTER LATERAL CLICK;Lo;0;L;;;;;N;LATIN LETTER DOUBLE PIPE;;;;
+01C2;LATIN LETTER ALVEOLAR CLICK;Lo;0;L;;;;;N;LATIN LETTER PIPE DOUBLE BAR;;;;
+01C3;LATIN LETTER RETROFLEX CLICK;Lo;0;L;;;;;N;LATIN LETTER EXCLAMATION MARK;;;;
+01C4;LATIN CAPITAL LETTER DZ WITH CARON;Lu;0;L;<compat> 0044 017D;;;;N;LATIN CAPITAL LETTER D Z HACEK;;;01C6;01C5
+01C5;LATIN CAPITAL LETTER D WITH SMALL LETTER Z WITH CARON;Lt;0;L;<compat> 0044 017E;;;;N;LATIN LETTER CAPITAL D SMALL Z HACEK;;01C4;01C6;
+01C6;LATIN SMALL LETTER DZ WITH CARON;Ll;0;L;<compat> 0064 017E;;;;N;LATIN SMALL LETTER D Z HACEK;;01C4;;01C5
+01C7;LATIN CAPITAL LETTER LJ;Lu;0;L;<compat> 004C 004A;;;;N;LATIN CAPITAL LETTER L J;;;01C9;01C8
+01C8;LATIN CAPITAL LETTER L WITH SMALL LETTER J;Lt;0;L;<compat> 004C 006A;;;;N;LATIN LETTER CAPITAL L SMALL J;;01C7;01C9;
+01C9;LATIN SMALL LETTER LJ;Ll;0;L;<compat> 006C 006A;;;;N;LATIN SMALL LETTER L J;;01C7;;01C8
+01CA;LATIN CAPITAL LETTER NJ;Lu;0;L;<compat> 004E 004A;;;;N;LATIN CAPITAL LETTER N J;;;01CC;01CB
+01CB;LATIN CAPITAL LETTER N WITH SMALL LETTER J;Lt;0;L;<compat> 004E 006A;;;;N;LATIN LETTER CAPITAL N SMALL J;;01CA;01CC;
+01CC;LATIN SMALL LETTER NJ;Ll;0;L;<compat> 006E 006A;;;;N;LATIN SMALL LETTER N J;;01CA;;01CB
+01CD;LATIN CAPITAL LETTER A WITH CARON;Lu;0;L;0041 030C;;;;N;LATIN CAPITAL LETTER A HACEK;;;01CE;
+01CE;LATIN SMALL LETTER A WITH CARON;Ll;0;L;0061 030C;;;;N;LATIN SMALL LETTER A HACEK;;01CD;;01CD
+01CF;LATIN CAPITAL LETTER I WITH CARON;Lu;0;L;0049 030C;;;;N;LATIN CAPITAL LETTER I HACEK;;;01D0;
+01D0;LATIN SMALL LETTER I WITH CARON;Ll;0;L;0069 030C;;;;N;LATIN SMALL LETTER I HACEK;;01CF;;01CF
+01D1;LATIN CAPITAL LETTER O WITH CARON;Lu;0;L;004F 030C;;;;N;LATIN CAPITAL LETTER O HACEK;;;01D2;
+01D2;LATIN SMALL LETTER O WITH CARON;Ll;0;L;006F 030C;;;;N;LATIN SMALL LETTER O HACEK;;01D1;;01D1
+01D3;LATIN CAPITAL LETTER U WITH CARON;Lu;0;L;0055 030C;;;;N;LATIN CAPITAL LETTER U HACEK;;;01D4;
+01D4;LATIN SMALL LETTER U WITH CARON;Ll;0;L;0075 030C;;;;N;LATIN SMALL LETTER U HACEK;;01D3;;01D3
+01D5;LATIN CAPITAL LETTER U WITH DIAERESIS AND MACRON;Lu;0;L;00DC 0304;;;;N;LATIN CAPITAL LETTER U DIAERESIS MACRON;;;01D6;
+01D6;LATIN SMALL LETTER U WITH DIAERESIS AND MACRON;Ll;0;L;00FC 0304;;;;N;LATIN SMALL LETTER U DIAERESIS MACRON;;01D5;;01D5
+01D7;LATIN CAPITAL LETTER U WITH DIAERESIS AND ACUTE;Lu;0;L;00DC 0301;;;;N;LATIN CAPITAL LETTER U DIAERESIS ACUTE;;;01D8;
+01D8;LATIN SMALL LETTER U WITH DIAERESIS AND ACUTE;Ll;0;L;00FC 0301;;;;N;LATIN SMALL LETTER U DIAERESIS ACUTE;;01D7;;01D7
+01D9;LATIN CAPITAL LETTER U WITH DIAERESIS AND CARON;Lu;0;L;00DC 030C;;;;N;LATIN CAPITAL LETTER U DIAERESIS HACEK;;;01DA;
+01DA;LATIN SMALL LETTER U WITH DIAERESIS AND CARON;Ll;0;L;00FC 030C;;;;N;LATIN SMALL LETTER U DIAERESIS HACEK;;01D9;;01D9
+01DB;LATIN CAPITAL LETTER U WITH DIAERESIS AND GRAVE;Lu;0;L;00DC 0300;;;;N;LATIN CAPITAL LETTER U DIAERESIS GRAVE;;;01DC;
+01DC;LATIN SMALL LETTER U WITH DIAERESIS AND GRAVE;Ll;0;L;00FC 0300;;;;N;LATIN SMALL LETTER U DIAERESIS GRAVE;;01DB;;01DB
+01DD;LATIN SMALL LETTER TURNED E;Ll;0;L;;;;;N;;;018E;;018E
+01DE;LATIN CAPITAL LETTER A WITH DIAERESIS AND MACRON;Lu;0;L;00C4 0304;;;;N;LATIN CAPITAL LETTER A DIAERESIS MACRON;;;01DF;
+01DF;LATIN SMALL LETTER A WITH DIAERESIS AND MACRON;Ll;0;L;00E4 0304;;;;N;LATIN SMALL LETTER A DIAERESIS MACRON;;01DE;;01DE
+01E0;LATIN CAPITAL LETTER A WITH DOT ABOVE AND MACRON;Lu;0;L;0226 0304;;;;N;LATIN CAPITAL LETTER A DOT MACRON;;;01E1;
+01E1;LATIN SMALL LETTER A WITH DOT ABOVE AND MACRON;Ll;0;L;0227 0304;;;;N;LATIN SMALL LETTER A DOT MACRON;;01E0;;01E0
+01E2;LATIN CAPITAL LETTER AE WITH MACRON;Lu;0;L;00C6 0304;;;;N;LATIN CAPITAL LETTER A E MACRON;ash *;;01E3;
+01E3;LATIN SMALL LETTER AE WITH MACRON;Ll;0;L;00E6 0304;;;;N;LATIN SMALL LETTER A E MACRON;ash *;01E2;;01E2
+01E4;LATIN CAPITAL LETTER G WITH STROKE;Lu;0;L;;;;;N;LATIN CAPITAL LETTER G BAR;;;01E5;
+01E5;LATIN SMALL LETTER G WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER G BAR;;01E4;;01E4
+01E6;LATIN CAPITAL LETTER G WITH CARON;Lu;0;L;0047 030C;;;;N;LATIN CAPITAL LETTER G HACEK;;;01E7;
+01E7;LATIN SMALL LETTER G WITH CARON;Ll;0;L;0067 030C;;;;N;LATIN SMALL LETTER G HACEK;;01E6;;01E6
+01E8;LATIN CAPITAL LETTER K WITH CARON;Lu;0;L;004B 030C;;;;N;LATIN CAPITAL LETTER K HACEK;;;01E9;
+01E9;LATIN SMALL LETTER K WITH CARON;Ll;0;L;006B 030C;;;;N;LATIN SMALL LETTER K HACEK;;01E8;;01E8
+01EA;LATIN CAPITAL LETTER O WITH OGONEK;Lu;0;L;004F 0328;;;;N;LATIN CAPITAL LETTER O OGONEK;;;01EB;
+01EB;LATIN SMALL LETTER O WITH OGONEK;Ll;0;L;006F 0328;;;;N;LATIN SMALL LETTER O OGONEK;;01EA;;01EA
+01EC;LATIN CAPITAL LETTER O WITH OGONEK AND MACRON;Lu;0;L;01EA 0304;;;;N;LATIN CAPITAL LETTER O OGONEK MACRON;;;01ED;
+01ED;LATIN SMALL LETTER O WITH OGONEK AND MACRON;Ll;0;L;01EB 0304;;;;N;LATIN SMALL LETTER O OGONEK MACRON;;01EC;;01EC
+01EE;LATIN CAPITAL LETTER EZH WITH CARON;Lu;0;L;01B7 030C;;;;N;LATIN CAPITAL LETTER YOGH HACEK;;;01EF;
+01EF;LATIN SMALL LETTER EZH WITH CARON;Ll;0;L;0292 030C;;;;N;LATIN SMALL LETTER YOGH HACEK;;01EE;;01EE
+01F0;LATIN SMALL LETTER J WITH CARON;Ll;0;L;006A 030C;;;;N;LATIN SMALL LETTER J HACEK;;;;
+01F1;LATIN CAPITAL LETTER DZ;Lu;0;L;<compat> 0044 005A;;;;N;;;;01F3;01F2
+01F2;LATIN CAPITAL LETTER D WITH SMALL LETTER Z;Lt;0;L;<compat> 0044 007A;;;;N;;;01F1;01F3;
+01F3;LATIN SMALL LETTER DZ;Ll;0;L;<compat> 0064 007A;;;;N;;;01F1;;01F2
+01F4;LATIN CAPITAL LETTER G WITH ACUTE;Lu;0;L;0047 0301;;;;N;;;;01F5;
+01F5;LATIN SMALL LETTER G WITH ACUTE;Ll;0;L;0067 0301;;;;N;;;01F4;;01F4
+01F6;LATIN CAPITAL LETTER HWAIR;Lu;0;L;;;;;N;;;;0195;
+01F7;LATIN CAPITAL LETTER WYNN;Lu;0;L;;;;;N;;;;01BF;
+01F8;LATIN CAPITAL LETTER N WITH GRAVE;Lu;0;L;004E 0300;;;;N;;;;01F9;
+01F9;LATIN SMALL LETTER N WITH GRAVE;Ll;0;L;006E 0300;;;;N;;;01F8;;01F8
+01FA;LATIN CAPITAL LETTER A WITH RING ABOVE AND ACUTE;Lu;0;L;00C5 0301;;;;N;;;;01FB;
+01FB;LATIN SMALL LETTER A WITH RING ABOVE AND ACUTE;Ll;0;L;00E5 0301;;;;N;;;01FA;;01FA
+01FC;LATIN CAPITAL LETTER AE WITH ACUTE;Lu;0;L;00C6 0301;;;;N;;ash *;;01FD;
+01FD;LATIN SMALL LETTER AE WITH ACUTE;Ll;0;L;00E6 0301;;;;N;;ash *;01FC;;01FC
+01FE;LATIN CAPITAL LETTER O WITH STROKE AND ACUTE;Lu;0;L;00D8 0301;;;;N;;;;01FF;
+01FF;LATIN SMALL LETTER O WITH STROKE AND ACUTE;Ll;0;L;00F8 0301;;;;N;;;01FE;;01FE
+0200;LATIN CAPITAL LETTER A WITH DOUBLE GRAVE;Lu;0;L;0041 030F;;;;N;;;;0201;
+0201;LATIN SMALL LETTER A WITH DOUBLE GRAVE;Ll;0;L;0061 030F;;;;N;;;0200;;0200
+0202;LATIN CAPITAL LETTER A WITH INVERTED BREVE;Lu;0;L;0041 0311;;;;N;;;;0203;
+0203;LATIN SMALL LETTER A WITH INVERTED BREVE;Ll;0;L;0061 0311;;;;N;;;0202;;0202
+0204;LATIN CAPITAL LETTER E WITH DOUBLE GRAVE;Lu;0;L;0045 030F;;;;N;;;;0205;
+0205;LATIN SMALL LETTER E WITH DOUBLE GRAVE;Ll;0;L;0065 030F;;;;N;;;0204;;0204
+0206;LATIN CAPITAL LETTER E WITH INVERTED BREVE;Lu;0;L;0045 0311;;;;N;;;;0207;
+0207;LATIN SMALL LETTER E WITH INVERTED BREVE;Ll;0;L;0065 0311;;;;N;;;0206;;0206
+0208;LATIN CAPITAL LETTER I WITH DOUBLE GRAVE;Lu;0;L;0049 030F;;;;N;;;;0209;
+0209;LATIN SMALL LETTER I WITH DOUBLE GRAVE;Ll;0;L;0069 030F;;;;N;;;0208;;0208
+020A;LATIN CAPITAL LETTER I WITH INVERTED BREVE;Lu;0;L;0049 0311;;;;N;;;;020B;
+020B;LATIN SMALL LETTER I WITH INVERTED BREVE;Ll;0;L;0069 0311;;;;N;;;020A;;020A
+020C;LATIN CAPITAL LETTER O WITH DOUBLE GRAVE;Lu;0;L;004F 030F;;;;N;;;;020D;
+020D;LATIN SMALL LETTER O WITH DOUBLE GRAVE;Ll;0;L;006F 030F;;;;N;;;020C;;020C
+020E;LATIN CAPITAL LETTER O WITH INVERTED BREVE;Lu;0;L;004F 0311;;;;N;;;;020F;
+020F;LATIN SMALL LETTER O WITH INVERTED BREVE;Ll;0;L;006F 0311;;;;N;;;020E;;020E
+0210;LATIN CAPITAL LETTER R WITH DOUBLE GRAVE;Lu;0;L;0052 030F;;;;N;;;;0211;
+0211;LATIN SMALL LETTER R WITH DOUBLE GRAVE;Ll;0;L;0072 030F;;;;N;;;0210;;0210
+0212;LATIN CAPITAL LETTER R WITH INVERTED BREVE;Lu;0;L;0052 0311;;;;N;;;;0213;
+0213;LATIN SMALL LETTER R WITH INVERTED BREVE;Ll;0;L;0072 0311;;;;N;;;0212;;0212
+0214;LATIN CAPITAL LETTER U WITH DOUBLE GRAVE;Lu;0;L;0055 030F;;;;N;;;;0215;
+0215;LATIN SMALL LETTER U WITH DOUBLE GRAVE;Ll;0;L;0075 030F;;;;N;;;0214;;0214
+0216;LATIN CAPITAL LETTER U WITH INVERTED BREVE;Lu;0;L;0055 0311;;;;N;;;;0217;
+0217;LATIN SMALL LETTER U WITH INVERTED BREVE;Ll;0;L;0075 0311;;;;N;;;0216;;0216
+0218;LATIN CAPITAL LETTER S WITH COMMA BELOW;Lu;0;L;0053 0326;;;;N;;*;;0219;
+0219;LATIN SMALL LETTER S WITH COMMA BELOW;Ll;0;L;0073 0326;;;;N;;*;0218;;0218
+021A;LATIN CAPITAL LETTER T WITH COMMA BELOW;Lu;0;L;0054 0326;;;;N;;*;;021B;
+021B;LATIN SMALL LETTER T WITH COMMA BELOW;Ll;0;L;0074 0326;;;;N;;*;021A;;021A
+021C;LATIN CAPITAL LETTER YOGH;Lu;0;L;;;;;N;;;;021D;
+021D;LATIN SMALL LETTER YOGH;Ll;0;L;;;;;N;;;021C;;021C
+021E;LATIN CAPITAL LETTER H WITH CARON;Lu;0;L;0048 030C;;;;N;;;;021F;
+021F;LATIN SMALL LETTER H WITH CARON;Ll;0;L;0068 030C;;;;N;;;021E;;021E
+0222;LATIN CAPITAL LETTER OU;Lu;0;L;;;;;N;;;;0223;
+0223;LATIN SMALL LETTER OU;Ll;0;L;;;;;N;;;0222;;0222
+0224;LATIN CAPITAL LETTER Z WITH HOOK;Lu;0;L;;;;;N;;;;0225;
+0225;LATIN SMALL LETTER Z WITH HOOK;Ll;0;L;;;;;N;;;0224;;0224
+0226;LATIN CAPITAL LETTER A WITH DOT ABOVE;Lu;0;L;0041 0307;;;;N;;;;0227;
+0227;LATIN SMALL LETTER A WITH DOT ABOVE;Ll;0;L;0061 0307;;;;N;;;0226;;0226
+0228;LATIN CAPITAL LETTER E WITH CEDILLA;Lu;0;L;0045 0327;;;;N;;;;0229;
+0229;LATIN SMALL LETTER E WITH CEDILLA;Ll;0;L;0065 0327;;;;N;;;0228;;0228
+022A;LATIN CAPITAL LETTER O WITH DIAERESIS AND MACRON;Lu;0;L;00D6 0304;;;;N;;;;022B;
+022B;LATIN SMALL LETTER O WITH DIAERESIS AND MACRON;Ll;0;L;00F6 0304;;;;N;;;022A;;022A
+022C;LATIN CAPITAL LETTER O WITH TILDE AND MACRON;Lu;0;L;00D5 0304;;;;N;;;;022D;
+022D;LATIN SMALL LETTER O WITH TILDE AND MACRON;Ll;0;L;00F5 0304;;;;N;;;022C;;022C
+022E;LATIN CAPITAL LETTER O WITH DOT ABOVE;Lu;0;L;004F 0307;;;;N;;;;022F;
+022F;LATIN SMALL LETTER O WITH DOT ABOVE;Ll;0;L;006F 0307;;;;N;;;022E;;022E
+0230;LATIN CAPITAL LETTER O WITH DOT ABOVE AND MACRON;Lu;0;L;022E 0304;;;;N;;;;0231;
+0231;LATIN SMALL LETTER O WITH DOT ABOVE AND MACRON;Ll;0;L;022F 0304;;;;N;;;0230;;0230
+0232;LATIN CAPITAL LETTER Y WITH MACRON;Lu;0;L;0059 0304;;;;N;;;;0233;
+0233;LATIN SMALL LETTER Y WITH MACRON;Ll;0;L;0079 0304;;;;N;;;0232;;0232
+0250;LATIN SMALL LETTER TURNED A;Ll;0;L;;;;;N;;;;;
+0251;LATIN SMALL LETTER ALPHA;Ll;0;L;;;;;N;LATIN SMALL LETTER SCRIPT A;;;;
+0252;LATIN SMALL LETTER TURNED ALPHA;Ll;0;L;;;;;N;LATIN SMALL LETTER TURNED SCRIPT A;;;;
+0253;LATIN SMALL LETTER B WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER B HOOK;;0181;;0181
+0254;LATIN SMALL LETTER OPEN O;Ll;0;L;;;;;N;;;0186;;0186
+0255;LATIN SMALL LETTER C WITH CURL;Ll;0;L;;;;;N;LATIN SMALL LETTER C CURL;;;;
+0256;LATIN SMALL LETTER D WITH TAIL;Ll;0;L;;;;;N;LATIN SMALL LETTER D RETROFLEX HOOK;;0189;;0189
+0257;LATIN SMALL LETTER D WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER D HOOK;;018A;;018A
+0258;LATIN SMALL LETTER REVERSED E;Ll;0;L;;;;;N;;;;;
+0259;LATIN SMALL LETTER SCHWA;Ll;0;L;;;;;N;;;018F;;018F
+025A;LATIN SMALL LETTER SCHWA WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER SCHWA HOOK;;;;
+025B;LATIN SMALL LETTER OPEN E;Ll;0;L;;;;;N;LATIN SMALL LETTER EPSILON;;0190;;0190
+025C;LATIN SMALL LETTER REVERSED OPEN E;Ll;0;L;;;;;N;LATIN SMALL LETTER REVERSED EPSILON;;;;
+025D;LATIN SMALL LETTER REVERSED OPEN E WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER REVERSED EPSILON HOOK;;;;
+025E;LATIN SMALL LETTER CLOSED REVERSED OPEN E;Ll;0;L;;;;;N;LATIN SMALL LETTER CLOSED REVERSED EPSILON;;;;
+025F;LATIN SMALL LETTER DOTLESS J WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER DOTLESS J BAR;;;;
+0260;LATIN SMALL LETTER G WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER G HOOK;;0193;;0193
+0261;LATIN SMALL LETTER SCRIPT G;Ll;0;L;;;;;N;;;;;
+0262;LATIN LETTER SMALL CAPITAL G;Ll;0;L;;;;;N;;;;;
+0263;LATIN SMALL LETTER GAMMA;Ll;0;L;;;;;N;;;0194;;0194
+0264;LATIN SMALL LETTER RAMS HORN;Ll;0;L;;;;;N;LATIN SMALL LETTER BABY GAMMA;;;;
+0265;LATIN SMALL LETTER TURNED H;Ll;0;L;;;;;N;;;;;
+0266;LATIN SMALL LETTER H WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER H HOOK;;;;
+0267;LATIN SMALL LETTER HENG WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER HENG HOOK;;;;
+0268;LATIN SMALL LETTER I WITH STROKE;Ll;0;L;;;;;N;LATIN SMALL LETTER BARRED I;;0197;;0197
+0269;LATIN SMALL LETTER IOTA;Ll;0;L;;;;;N;;;0196;;0196
+026A;LATIN LETTER SMALL CAPITAL I;Ll;0;L;;;;;N;;;;;
+026B;LATIN SMALL LETTER L WITH MIDDLE TILDE;Ll;0;L;;;;;N;;;;;
+026C;LATIN SMALL LETTER L WITH BELT;Ll;0;L;;;;;N;LATIN SMALL LETTER L BELT;;;;
+026D;LATIN SMALL LETTER L WITH RETROFLEX HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER L RETROFLEX HOOK;;;;
+026E;LATIN SMALL LETTER LEZH;Ll;0;L;;;;;N;LATIN SMALL LETTER L YOGH;;;;
+026F;LATIN SMALL LETTER TURNED M;Ll;0;L;;;;;N;;;019C;;019C
+0270;LATIN SMALL LETTER TURNED M WITH LONG LEG;Ll;0;L;;;;;N;;;;;
+0271;LATIN SMALL LETTER M WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER M HOOK;;;;
+0272;LATIN SMALL LETTER N WITH LEFT HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER N HOOK;;019D;;019D
+0273;LATIN SMALL LETTER N WITH RETROFLEX HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER N RETROFLEX HOOK;;;;
+0274;LATIN LETTER SMALL CAPITAL N;Ll;0;L;;;;;N;;;;;
+0275;LATIN SMALL LETTER BARRED O;Ll;0;L;;;;;N;;;019F;;019F
+0276;LATIN LETTER SMALL CAPITAL OE;Ll;0;L;;;;;N;LATIN LETTER SMALL CAPITAL O E;;;;
+0277;LATIN SMALL LETTER CLOSED OMEGA;Ll;0;L;;;;;N;;;;;
+0278;LATIN SMALL LETTER PHI;Ll;0;L;;;;;N;;;;;
+0279;LATIN SMALL LETTER TURNED R;Ll;0;L;;;;;N;;;;;
+027A;LATIN SMALL LETTER TURNED R WITH LONG LEG;Ll;0;L;;;;;N;;;;;
+027B;LATIN SMALL LETTER TURNED R WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER TURNED R HOOK;;;;
+027C;LATIN SMALL LETTER R WITH LONG LEG;Ll;0;L;;;;;N;;;;;
+027D;LATIN SMALL LETTER R WITH TAIL;Ll;0;L;;;;;N;LATIN SMALL LETTER R HOOK;;;;
+027E;LATIN SMALL LETTER R WITH FISHHOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER FISHHOOK R;;;;
+027F;LATIN SMALL LETTER REVERSED R WITH FISHHOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER REVERSED FISHHOOK R;;;;
+0280;LATIN LETTER SMALL CAPITAL R;Ll;0;L;;;;;N;;*;01A6;;01A6
+0281;LATIN LETTER SMALL CAPITAL INVERTED R;Ll;0;L;;;;;N;;;;;
+0282;LATIN SMALL LETTER S WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER S HOOK;;;;
+0283;LATIN SMALL LETTER ESH;Ll;0;L;;;;;N;;;01A9;;01A9
+0284;LATIN SMALL LETTER DOTLESS J WITH STROKE AND HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER DOTLESS J BAR HOOK;;;;
+0285;LATIN SMALL LETTER SQUAT REVERSED ESH;Ll;0;L;;;;;N;;;;;
+0286;LATIN SMALL LETTER ESH WITH CURL;Ll;0;L;;;;;N;LATIN SMALL LETTER ESH CURL;;;;
+0287;LATIN SMALL LETTER TURNED T;Ll;0;L;;;;;N;;;;;
+0288;LATIN SMALL LETTER T WITH RETROFLEX HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER T RETROFLEX HOOK;;01AE;;01AE
+0289;LATIN SMALL LETTER U BAR;Ll;0;L;;;;;N;;;;;
+028A;LATIN SMALL LETTER UPSILON;Ll;0;L;;;;;N;;;01B1;;01B1
+028B;LATIN SMALL LETTER V WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER SCRIPT V;;01B2;;01B2
+028C;LATIN SMALL LETTER TURNED V;Ll;0;L;;;;;N;;;;;
+028D;LATIN SMALL LETTER TURNED W;Ll;0;L;;;;;N;;;;;
+028E;LATIN SMALL LETTER TURNED Y;Ll;0;L;;;;;N;;;;;
+028F;LATIN LETTER SMALL CAPITAL Y;Ll;0;L;;;;;N;;;;;
+0290;LATIN SMALL LETTER Z WITH RETROFLEX HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER Z RETROFLEX HOOK;;;;
+0291;LATIN SMALL LETTER Z WITH CURL;Ll;0;L;;;;;N;LATIN SMALL LETTER Z CURL;;;;
+0292;LATIN SMALL LETTER EZH;Ll;0;L;;;;;N;LATIN SMALL LETTER YOGH;;01B7;;01B7
+0293;LATIN SMALL LETTER EZH WITH CURL;Ll;0;L;;;;;N;LATIN SMALL LETTER YOGH CURL;;;;
+0294;LATIN LETTER GLOTTAL STOP;Ll;0;L;;;;;N;;;;;
+0295;LATIN LETTER PHARYNGEAL VOICED FRICATIVE;Ll;0;L;;;;;N;LATIN LETTER REVERSED GLOTTAL STOP;;;;
+0296;LATIN LETTER INVERTED GLOTTAL STOP;Ll;0;L;;;;;N;;;;;
+0297;LATIN LETTER STRETCHED C;Ll;0;L;;;;;N;;;;;
+0298;LATIN LETTER BILABIAL CLICK;Ll;0;L;;;;;N;LATIN LETTER BULLSEYE;;;;
+0299;LATIN LETTER SMALL CAPITAL B;Ll;0;L;;;;;N;;;;;
+029A;LATIN SMALL LETTER CLOSED OPEN E;Ll;0;L;;;;;N;LATIN SMALL LETTER CLOSED EPSILON;;;;
+029B;LATIN LETTER SMALL CAPITAL G WITH HOOK;Ll;0;L;;;;;N;LATIN LETTER SMALL CAPITAL G HOOK;;;;
+029C;LATIN LETTER SMALL CAPITAL H;Ll;0;L;;;;;N;;;;;
+029D;LATIN SMALL LETTER J WITH CROSSED-TAIL;Ll;0;L;;;;;N;LATIN SMALL LETTER CROSSED-TAIL J;;;;
+029E;LATIN SMALL LETTER TURNED K;Ll;0;L;;;;;N;;;;;
+029F;LATIN LETTER SMALL CAPITAL L;Ll;0;L;;;;;N;;;;;
+02A0;LATIN SMALL LETTER Q WITH HOOK;Ll;0;L;;;;;N;LATIN SMALL LETTER Q HOOK;;;;
+02A1;LATIN LETTER GLOTTAL STOP WITH STROKE;Ll;0;L;;;;;N;LATIN LETTER GLOTTAL STOP BAR;;;;
+02A2;LATIN LETTER REVERSED GLOTTAL STOP WITH STROKE;Ll;0;L;;;;;N;LATIN LETTER REVERSED GLOTTAL STOP BAR;;;;
+02A3;LATIN SMALL LETTER DZ DIGRAPH;Ll;0;L;;;;;N;LATIN SMALL LETTER D Z;;;;
+02A4;LATIN SMALL LETTER DEZH DIGRAPH;Ll;0;L;;;;;N;LATIN SMALL LETTER D YOGH;;;;
+02A5;LATIN SMALL LETTER DZ DIGRAPH WITH CURL;Ll;0;L;;;;;N;LATIN SMALL LETTER D Z CURL;;;;
+02A6;LATIN SMALL LETTER TS DIGRAPH;Ll;0;L;;;;;N;LATIN SMALL LETTER T S;;;;
+02A7;LATIN SMALL LETTER TESH DIGRAPH;Ll;0;L;;;;;N;LATIN SMALL LETTER T ESH;;;;
+02A8;LATIN SMALL LETTER TC DIGRAPH WITH CURL;Ll;0;L;;;;;N;LATIN SMALL LETTER T C CURL;;;;
+02A9;LATIN SMALL LETTER FENG DIGRAPH;Ll;0;L;;;;;N;;;;;
+02AA;LATIN SMALL LETTER LS DIGRAPH;Ll;0;L;;;;;N;;;;;
+02AB;LATIN SMALL LETTER LZ DIGRAPH;Ll;0;L;;;;;N;;;;;
+02AC;LATIN LETTER BILABIAL PERCUSSIVE;Ll;0;L;;;;;N;;;;;
+02AD;LATIN LETTER BIDENTAL PERCUSSIVE;Ll;0;L;;;;;N;;;;;
+02B0;MODIFIER LETTER SMALL H;Lm;0;L;<super> 0068;;;;N;;;;;
+02B1;MODIFIER LETTER SMALL H WITH HOOK;Lm;0;L;<super> 0266;;;;N;MODIFIER LETTER SMALL H HOOK;;;;
+02B2;MODIFIER LETTER SMALL J;Lm;0;L;<super> 006A;;;;N;;;;;
+02B3;MODIFIER LETTER SMALL R;Lm;0;L;<super> 0072;;;;N;;;;;
+02B4;MODIFIER LETTER SMALL TURNED R;Lm;0;L;<super> 0279;;;;N;;;;;
+02B5;MODIFIER LETTER SMALL TURNED R WITH HOOK;Lm;0;L;<super> 027B;;;;N;MODIFIER LETTER SMALL TURNED R HOOK;;;;
+02B6;MODIFIER LETTER SMALL CAPITAL INVERTED R;Lm;0;L;<super> 0281;;;;N;;;;;
+02B7;MODIFIER LETTER SMALL W;Lm;0;L;<super> 0077;;;;N;;;;;
+02B8;MODIFIER LETTER SMALL Y;Lm;0;L;<super> 0079;;;;N;;;;;
+02B9;MODIFIER LETTER PRIME;Sk;0;ON;;;;;N;;;;;
+02BA;MODIFIER LETTER DOUBLE PRIME;Sk;0;ON;;;;;N;;;;;
+02BB;MODIFIER LETTER TURNED COMMA;Lm;0;L;;;;;N;;;;;
+02BC;MODIFIER LETTER APOSTROPHE;Lm;0;L;;;;;N;;;;;
+02BD;MODIFIER LETTER REVERSED COMMA;Lm;0;L;;;;;N;;;;;
+02BE;MODIFIER LETTER RIGHT HALF RING;Lm;0;L;;;;;N;;;;;
+02BF;MODIFIER LETTER LEFT HALF RING;Lm;0;L;;;;;N;;;;;
+02C0;MODIFIER LETTER GLOTTAL STOP;Lm;0;L;;;;;N;;;;;
+02C1;MODIFIER LETTER REVERSED GLOTTAL STOP;Lm;0;L;;;;;N;;;;;
+02C2;MODIFIER LETTER LEFT ARROWHEAD;Sk;0;ON;;;;;N;;;;;
+02C3;MODIFIER LETTER RIGHT ARROWHEAD;Sk;0;ON;;;;;N;;;;;
+02C4;MODIFIER LETTER UP ARROWHEAD;Sk;0;ON;;;;;N;;;;;
+02C5;MODIFIER LETTER DOWN ARROWHEAD;Sk;0;ON;;;;;N;;;;;
+02C6;MODIFIER LETTER CIRCUMFLEX ACCENT;Sk;0;ON;;;;;N;MODIFIER LETTER CIRCUMFLEX;;;;
+02C7;CARON;Sk;0;ON;;;;;N;MODIFIER LETTER HACEK;Mandarin Chinese third tone;;;
+02C8;MODIFIER LETTER VERTICAL LINE;Sk;0;ON;;;;;N;;;;;
+02C9;MODIFIER LETTER MACRON;Sk;0;ON;;;;;N;;Mandarin Chinese first tone;;;
+02CA;MODIFIER LETTER ACUTE ACCENT;Sk;0;ON;;;;;N;MODIFIER LETTER ACUTE;Mandarin Chinese second tone;;;
+02CB;MODIFIER LETTER GRAVE ACCENT;Sk;0;ON;;;;;N;MODIFIER LETTER GRAVE;Mandarin Chinese fourth tone;;;
+02CC;MODIFIER LETTER LOW VERTICAL LINE;Sk;0;ON;;;;;N;;;;;
+02CD;MODIFIER LETTER LOW MACRON;Sk;0;ON;;;;;N;;;;;
+02CE;MODIFIER LETTER LOW GRAVE ACCENT;Sk;0;ON;;;;;N;MODIFIER LETTER LOW GRAVE;;;;
+02CF;MODIFIER LETTER LOW ACUTE ACCENT;Sk;0;ON;;;;;N;MODIFIER LETTER LOW ACUTE;;;;
+02D0;MODIFIER LETTER TRIANGULAR COLON;Lm;0;L;;;;;N;;;;;
+02D1;MODIFIER LETTER HALF TRIANGULAR COLON;Lm;0;L;;;;;N;;;;;
+02D2;MODIFIER LETTER CENTRED RIGHT HALF RING;Sk;0;ON;;;;;N;MODIFIER LETTER CENTERED RIGHT HALF RING;;;;
+02D3;MODIFIER LETTER CENTRED LEFT HALF RING;Sk;0;ON;;;;;N;MODIFIER LETTER CENTERED LEFT HALF RING;;;;
+02D4;MODIFIER LETTER UP TACK;Sk;0;ON;;;;;N;;;;;
+02D5;MODIFIER LETTER DOWN TACK;Sk;0;ON;;;;;N;;;;;
+02D6;MODIFIER LETTER PLUS SIGN;Sk;0;ON;;;;;N;;;;;
+02D7;MODIFIER LETTER MINUS SIGN;Sk;0;ON;;;;;N;;;;;
+02D8;BREVE;Sk;0;ON;<compat> 0020 0306;;;;N;SPACING BREVE;;;;
+02D9;DOT ABOVE;Sk;0;ON;<compat> 0020 0307;;;;N;SPACING DOT ABOVE;Mandarin Chinese light tone;;;
+02DA;RING ABOVE;Sk;0;ON;<compat> 0020 030A;;;;N;SPACING RING ABOVE;;;;
+02DB;OGONEK;Sk;0;ON;<compat> 0020 0328;;;;N;SPACING OGONEK;;;;
+02DC;SMALL TILDE;Sk;0;ON;<compat> 0020 0303;;;;N;SPACING TILDE;;;;
+02DD;DOUBLE ACUTE ACCENT;Sk;0;ON;<compat> 0020 030B;;;;N;SPACING DOUBLE ACUTE;;;;
+02DE;MODIFIER LETTER RHOTIC HOOK;Sk;0;ON;;;;;N;;;;;
+02DF;MODIFIER LETTER CROSS ACCENT;Sk;0;ON;;;;;N;;;;;
+02E0;MODIFIER LETTER SMALL GAMMA;Lm;0;L;<super> 0263;;;;N;;;;;
+02E1;MODIFIER LETTER SMALL L;Lm;0;L;<super> 006C;;;;N;;;;;
+02E2;MODIFIER LETTER SMALL S;Lm;0;L;<super> 0073;;;;N;;;;;
+02E3;MODIFIER LETTER SMALL X;Lm;0;L;<super> 0078;;;;N;;;;;
+02E4;MODIFIER LETTER SMALL REVERSED GLOTTAL STOP;Lm;0;L;<super> 0295;;;;N;;;;;
+02E5;MODIFIER LETTER EXTRA-HIGH TONE BAR;Sk;0;ON;;;;;N;;;;;
+02E6;MODIFIER LETTER HIGH TONE BAR;Sk;0;ON;;;;;N;;;;;
+02E7;MODIFIER LETTER MID TONE BAR;Sk;0;ON;;;;;N;;;;;
+02E8;MODIFIER LETTER LOW TONE BAR;Sk;0;ON;;;;;N;;;;;
+02E9;MODIFIER LETTER EXTRA-LOW TONE BAR;Sk;0;ON;;;;;N;;;;;
+02EA;MODIFIER LETTER YIN DEPARTING TONE MARK;Sk;0;ON;;;;;N;;;;;
+02EB;MODIFIER LETTER YANG DEPARTING TONE MARK;Sk;0;ON;;;;;N;;;;;
+02EC;MODIFIER LETTER VOICING;Sk;0;ON;;;;;N;;;;;
+02ED;MODIFIER LETTER UNASPIRATED;Sk;0;ON;;;;;N;;;;;
+02EE;MODIFIER LETTER DOUBLE APOSTROPHE;Lm;0;L;;;;;N;;;;;
+0300;COMBINING GRAVE ACCENT;Mn;230;NSM;;;;;N;NON-SPACING GRAVE;Varia;;;
+0301;COMBINING ACUTE ACCENT;Mn;230;NSM;;;;;N;NON-SPACING ACUTE;Oxia;;;
+0302;COMBINING CIRCUMFLEX ACCENT;Mn;230;NSM;;;;;N;NON-SPACING CIRCUMFLEX;;;;
+0303;COMBINING TILDE;Mn;230;NSM;;;;;N;NON-SPACING TILDE;;;;
+0304;COMBINING MACRON;Mn;230;NSM;;;;;N;NON-SPACING MACRON;;;;
+0305;COMBINING OVERLINE;Mn;230;NSM;;;;;N;NON-SPACING OVERSCORE;;;;
+0306;COMBINING BREVE;Mn;230;NSM;;;;;N;NON-SPACING BREVE;Vrachy;;;
+0307;COMBINING DOT ABOVE;Mn;230;NSM;;;;;N;NON-SPACING DOT ABOVE;;;;
+0308;COMBINING DIAERESIS;Mn;230;NSM;;;;;N;NON-SPACING DIAERESIS;Dialytika;;;
+0309;COMBINING HOOK ABOVE;Mn;230;NSM;;;;;N;NON-SPACING HOOK ABOVE;;;;
+030A;COMBINING RING ABOVE;Mn;230;NSM;;;;;N;NON-SPACING RING ABOVE;;;;
+030B;COMBINING DOUBLE ACUTE ACCENT;Mn;230;NSM;;;;;N;NON-SPACING DOUBLE ACUTE;;;;
+030C;COMBINING CARON;Mn;230;NSM;;;;;N;NON-SPACING HACEK;;;;
+030D;COMBINING VERTICAL LINE ABOVE;Mn;230;NSM;;;;;N;NON-SPACING VERTICAL LINE ABOVE;Tonos;;;
+030E;COMBINING DOUBLE VERTICAL LINE ABOVE;Mn;230;NSM;;;;;N;NON-SPACING DOUBLE VERTICAL LINE ABOVE;;;;
+030F;COMBINING DOUBLE GRAVE ACCENT;Mn;230;NSM;;;;;N;NON-SPACING DOUBLE GRAVE;;;;
+0310;COMBINING CANDRABINDU;Mn;230;NSM;;;;;N;NON-SPACING CANDRABINDU;;;;
+0311;COMBINING INVERTED BREVE;Mn;230;NSM;;;;;N;NON-SPACING INVERTED BREVE;;;;
+0312;COMBINING TURNED COMMA ABOVE;Mn;230;NSM;;;;;N;NON-SPACING TURNED COMMA ABOVE;;;;
+0313;COMBINING COMMA ABOVE;Mn;230;NSM;;;;;N;NON-SPACING COMMA ABOVE;Psili;;;
+0314;COMBINING REVERSED COMMA ABOVE;Mn;230;NSM;;;;;N;NON-SPACING REVERSED COMMA ABOVE;Dasia;;;
+0315;COMBINING COMMA ABOVE RIGHT;Mn;232;NSM;;;;;N;NON-SPACING COMMA ABOVE RIGHT;;;;
+0316;COMBINING GRAVE ACCENT BELOW;Mn;220;NSM;;;;;N;NON-SPACING GRAVE BELOW;;;;
+0317;COMBINING ACUTE ACCENT BELOW;Mn;220;NSM;;;;;N;NON-SPACING ACUTE BELOW;;;;
+0318;COMBINING LEFT TACK BELOW;Mn;220;NSM;;;;;N;NON-SPACING LEFT TACK BELOW;;;;
+0319;COMBINING RIGHT TACK BELOW;Mn;220;NSM;;;;;N;NON-SPACING RIGHT TACK BELOW;;;;
+031A;COMBINING LEFT ANGLE ABOVE;Mn;232;NSM;;;;;N;NON-SPACING LEFT ANGLE ABOVE;;;;
+031B;COMBINING HORN;Mn;216;NSM;;;;;N;NON-SPACING HORN;;;;
+031C;COMBINING LEFT HALF RING BELOW;Mn;220;NSM;;;;;N;NON-SPACING LEFT HALF RING BELOW;;;;
+031D;COMBINING UP TACK BELOW;Mn;220;NSM;;;;;N;NON-SPACING UP TACK BELOW;;;;
+031E;COMBINING DOWN TACK BELOW;Mn;220;NSM;;;;;N;NON-SPACING DOWN TACK BELOW;;;;
+031F;COMBINING PLUS SIGN BELOW;Mn;220;NSM;;;;;N;NON-SPACING PLUS SIGN BELOW;;;;
+0320;COMBINING MINUS SIGN BELOW;Mn;220;NSM;;;;;N;NON-SPACING MINUS SIGN BELOW;;;;
+0321;COMBINING PALATALIZED HOOK BELOW;Mn;202;NSM;;;;;N;NON-SPACING PALATALIZED HOOK BELOW;;;;
+0322;COMBINING RETROFLEX HOOK BELOW;Mn;202;NSM;;;;;N;NON-SPACING RETROFLEX HOOK BELOW;;;;
+0323;COMBINING DOT BELOW;Mn;220;NSM;;;;;N;NON-SPACING DOT BELOW;;;;
+0324;COMBINING DIAERESIS BELOW;Mn;220;NSM;;;;;N;NON-SPACING DOUBLE DOT BELOW;;;;
+0325;COMBINING RING BELOW;Mn;220;NSM;;;;;N;NON-SPACING RING BELOW;;;;
+0326;COMBINING COMMA BELOW;Mn;220;NSM;;;;;N;NON-SPACING COMMA BELOW;;;;
+0327;COMBINING CEDILLA;Mn;202;NSM;;;;;N;NON-SPACING CEDILLA;;;;
+0328;COMBINING OGONEK;Mn;202;NSM;;;;;N;NON-SPACING OGONEK;;;;
+0329;COMBINING VERTICAL LINE BELOW;Mn;220;NSM;;;;;N;NON-SPACING VERTICAL LINE BELOW;;;;
+032A;COMBINING BRIDGE BELOW;Mn;220;NSM;;;;;N;NON-SPACING BRIDGE BELOW;;;;
+032B;COMBINING INVERTED DOUBLE ARCH BELOW;Mn;220;NSM;;;;;N;NON-SPACING INVERTED DOUBLE ARCH BELOW;;;;
+032C;COMBINING CARON BELOW;Mn;220;NSM;;;;;N;NON-SPACING HACEK BELOW;;;;
+032D;COMBINING CIRCUMFLEX ACCENT BELOW;Mn;220;NSM;;;;;N;NON-SPACING CIRCUMFLEX BELOW;;;;
+032E;COMBINING BREVE BELOW;Mn;220;NSM;;;;;N;NON-SPACING BREVE BELOW;;;;
+032F;COMBINING INVERTED BREVE BELOW;Mn;220;NSM;;;;;N;NON-SPACING INVERTED BREVE BELOW;;;;
+0330;COMBINING TILDE BELOW;Mn;220;NSM;;;;;N;NON-SPACING TILDE BELOW;;;;
+0331;COMBINING MACRON BELOW;Mn;220;NSM;;;;;N;NON-SPACING MACRON BELOW;;;;
+0332;COMBINING LOW LINE;Mn;220;NSM;;;;;N;NON-SPACING UNDERSCORE;;;;
+0333;COMBINING DOUBLE LOW LINE;Mn;220;NSM;;;;;N;NON-SPACING DOUBLE UNDERSCORE;;;;
+0334;COMBINING TILDE OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING TILDE OVERLAY;;;;
+0335;COMBINING SHORT STROKE OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING SHORT BAR OVERLAY;;;;
+0336;COMBINING LONG STROKE OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING LONG BAR OVERLAY;;;;
+0337;COMBINING SHORT SOLIDUS OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING SHORT SLASH OVERLAY;;;;
+0338;COMBINING LONG SOLIDUS OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING LONG SLASH OVERLAY;;;;
+0339;COMBINING RIGHT HALF RING BELOW;Mn;220;NSM;;;;;N;NON-SPACING RIGHT HALF RING BELOW;;;;
+033A;COMBINING INVERTED BRIDGE BELOW;Mn;220;NSM;;;;;N;NON-SPACING INVERTED BRIDGE BELOW;;;;
+033B;COMBINING SQUARE BELOW;Mn;220;NSM;;;;;N;NON-SPACING SQUARE BELOW;;;;
+033C;COMBINING SEAGULL BELOW;Mn;220;NSM;;;;;N;NON-SPACING SEAGULL BELOW;;;;
+033D;COMBINING X ABOVE;Mn;230;NSM;;;;;N;NON-SPACING X ABOVE;;;;
+033E;COMBINING VERTICAL TILDE;Mn;230;NSM;;;;;N;NON-SPACING VERTICAL TILDE;;;;
+033F;COMBINING DOUBLE OVERLINE;Mn;230;NSM;;;;;N;NON-SPACING DOUBLE OVERSCORE;;;;
+0340;COMBINING GRAVE TONE MARK;Mn;230;NSM;0300;;;;N;NON-SPACING GRAVE TONE MARK;Vietnamese;;;
+0341;COMBINING ACUTE TONE MARK;Mn;230;NSM;0301;;;;N;NON-SPACING ACUTE TONE MARK;Vietnamese;;;
+0342;COMBINING GREEK PERISPOMENI;Mn;230;NSM;;;;;N;;;;;
+0343;COMBINING GREEK KORONIS;Mn;230;NSM;0313;;;;N;;;;;
+0344;COMBINING GREEK DIALYTIKA TONOS;Mn;230;NSM;0308 0301;;;;N;GREEK NON-SPACING DIAERESIS TONOS;;;;
+0345;COMBINING GREEK YPOGEGRAMMENI;Mn;240;NSM;;;;;N;GREEK NON-SPACING IOTA BELOW;;0399;;0399
+0346;COMBINING BRIDGE ABOVE;Mn;230;NSM;;;;;N;;;;;
+0347;COMBINING EQUALS SIGN BELOW;Mn;220;NSM;;;;;N;;;;;
+0348;COMBINING DOUBLE VERTICAL LINE BELOW;Mn;220;NSM;;;;;N;;;;;
+0349;COMBINING LEFT ANGLE BELOW;Mn;220;NSM;;;;;N;;;;;
+034A;COMBINING NOT TILDE ABOVE;Mn;230;NSM;;;;;N;;;;;
+034B;COMBINING HOMOTHETIC ABOVE;Mn;230;NSM;;;;;N;;;;;
+034C;COMBINING ALMOST EQUAL TO ABOVE;Mn;230;NSM;;;;;N;;;;;
+034D;COMBINING LEFT RIGHT ARROW BELOW;Mn;220;NSM;;;;;N;;;;;
+034E;COMBINING UPWARDS ARROW BELOW;Mn;220;NSM;;;;;N;;;;;
+0360;COMBINING DOUBLE TILDE;Mn;234;NSM;;;;;N;;;;;
+0361;COMBINING DOUBLE INVERTED BREVE;Mn;234;NSM;;;;;N;;;;;
+0362;COMBINING DOUBLE RIGHTWARDS ARROW BELOW;Mn;233;NSM;;;;;N;;;;;
+0374;GREEK NUMERAL SIGN;Sk;0;ON;02B9;;;;N;GREEK UPPER NUMERAL SIGN;Dexia keraia;;;
+0375;GREEK LOWER NUMERAL SIGN;Sk;0;ON;;;;;N;;Aristeri keraia;;;
+037A;GREEK YPOGEGRAMMENI;Lm;0;L;<compat> 0020 0345;;;;N;GREEK SPACING IOTA BELOW;;;;
+037E;GREEK QUESTION MARK;Po;0;ON;003B;;;;N;;Erotimatiko;;;
+0384;GREEK TONOS;Sk;0;ON;<compat> 0020 0301;;;;N;GREEK SPACING TONOS;;;;
+0385;GREEK DIALYTIKA TONOS;Sk;0;ON;00A8 0301;;;;N;GREEK SPACING DIAERESIS TONOS;;;;
+0386;GREEK CAPITAL LETTER ALPHA WITH TONOS;Lu;0;L;0391 0301;;;;N;GREEK CAPITAL LETTER ALPHA TONOS;;;03AC;
+0387;GREEK ANO TELEIA;Po;0;ON;00B7;;;;N;;;;;
+0388;GREEK CAPITAL LETTER EPSILON WITH TONOS;Lu;0;L;0395 0301;;;;N;GREEK CAPITAL LETTER EPSILON TONOS;;;03AD;
+0389;GREEK CAPITAL LETTER ETA WITH TONOS;Lu;0;L;0397 0301;;;;N;GREEK CAPITAL LETTER ETA TONOS;;;03AE;
+038A;GREEK CAPITAL LETTER IOTA WITH TONOS;Lu;0;L;0399 0301;;;;N;GREEK CAPITAL LETTER IOTA TONOS;;;03AF;
+038C;GREEK CAPITAL LETTER OMICRON WITH TONOS;Lu;0;L;039F 0301;;;;N;GREEK CAPITAL LETTER OMICRON TONOS;;;03CC;
+038E;GREEK CAPITAL LETTER UPSILON WITH TONOS;Lu;0;L;03A5 0301;;;;N;GREEK CAPITAL LETTER UPSILON TONOS;;;03CD;
+038F;GREEK CAPITAL LETTER OMEGA WITH TONOS;Lu;0;L;03A9 0301;;;;N;GREEK CAPITAL LETTER OMEGA TONOS;;;03CE;
+0390;GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS;Ll;0;L;03CA 0301;;;;N;GREEK SMALL LETTER IOTA DIAERESIS TONOS;;;;
+0391;GREEK CAPITAL LETTER ALPHA;Lu;0;L;;;;;N;;;;03B1;
+0392;GREEK CAPITAL LETTER BETA;Lu;0;L;;;;;N;;;;03B2;
+0393;GREEK CAPITAL LETTER GAMMA;Lu;0;L;;;;;N;;;;03B3;
+0394;GREEK CAPITAL LETTER DELTA;Lu;0;L;;;;;N;;;;03B4;
+0395;GREEK CAPITAL LETTER EPSILON;Lu;0;L;;;;;N;;;;03B5;
+0396;GREEK CAPITAL LETTER ZETA;Lu;0;L;;;;;N;;;;03B6;
+0397;GREEK CAPITAL LETTER ETA;Lu;0;L;;;;;N;;;;03B7;
+0398;GREEK CAPITAL LETTER THETA;Lu;0;L;;;;;N;;;;03B8;
+0399;GREEK CAPITAL LETTER IOTA;Lu;0;L;;;;;N;;;;03B9;
+039A;GREEK CAPITAL LETTER KAPPA;Lu;0;L;;;;;N;;;;03BA;
+039B;GREEK CAPITAL LETTER LAMDA;Lu;0;L;;;;;N;GREEK CAPITAL LETTER LAMBDA;;;03BB;
+039C;GREEK CAPITAL LETTER MU;Lu;0;L;;;;;N;;;;03BC;
+039D;GREEK CAPITAL LETTER NU;Lu;0;L;;;;;N;;;;03BD;
+039E;GREEK CAPITAL LETTER XI;Lu;0;L;;;;;N;;;;03BE;
+039F;GREEK CAPITAL LETTER OMICRON;Lu;0;L;;;;;N;;;;03BF;
+03A0;GREEK CAPITAL LETTER PI;Lu;0;L;;;;;N;;;;03C0;
+03A1;GREEK CAPITAL LETTER RHO;Lu;0;L;;;;;N;;;;03C1;
+03A3;GREEK CAPITAL LETTER SIGMA;Lu;0;L;;;;;N;;;;03C3;
+03A4;GREEK CAPITAL LETTER TAU;Lu;0;L;;;;;N;;;;03C4;
+03A5;GREEK CAPITAL LETTER UPSILON;Lu;0;L;;;;;N;;;;03C5;
+03A6;GREEK CAPITAL LETTER PHI;Lu;0;L;;;;;N;;;;03C6;
+03A7;GREEK CAPITAL LETTER CHI;Lu;0;L;;;;;N;;;;03C7;
+03A8;GREEK CAPITAL LETTER PSI;Lu;0;L;;;;;N;;;;03C8;
+03A9;GREEK CAPITAL LETTER OMEGA;Lu;0;L;;;;;N;;;;03C9;
+03AA;GREEK CAPITAL LETTER IOTA WITH DIALYTIKA;Lu;0;L;0399 0308;;;;N;GREEK CAPITAL LETTER IOTA DIAERESIS;;;03CA;
+03AB;GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA;Lu;0;L;03A5 0308;;;;N;GREEK CAPITAL LETTER UPSILON DIAERESIS;;;03CB;
+03AC;GREEK SMALL LETTER ALPHA WITH TONOS;Ll;0;L;03B1 0301;;;;N;GREEK SMALL LETTER ALPHA TONOS;;0386;;0386
+03AD;GREEK SMALL LETTER EPSILON WITH TONOS;Ll;0;L;03B5 0301;;;;N;GREEK SMALL LETTER EPSILON TONOS;;0388;;0388
+03AE;GREEK SMALL LETTER ETA WITH TONOS;Ll;0;L;03B7 0301;;;;N;GREEK SMALL LETTER ETA TONOS;;0389;;0389
+03AF;GREEK SMALL LETTER IOTA WITH TONOS;Ll;0;L;03B9 0301;;;;N;GREEK SMALL LETTER IOTA TONOS;;038A;;038A
+03B0;GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS;Ll;0;L;03CB 0301;;;;N;GREEK SMALL LETTER UPSILON DIAERESIS TONOS;;;;
+03B1;GREEK SMALL LETTER ALPHA;Ll;0;L;;;;;N;;;0391;;0391
+03B2;GREEK SMALL LETTER BETA;Ll;0;L;;;;;N;;;0392;;0392
+03B3;GREEK SMALL LETTER GAMMA;Ll;0;L;;;;;N;;;0393;;0393
+03B4;GREEK SMALL LETTER DELTA;Ll;0;L;;;;;N;;;0394;;0394
+03B5;GREEK SMALL LETTER EPSILON;Ll;0;L;;;;;N;;;0395;;0395
+03B6;GREEK SMALL LETTER ZETA;Ll;0;L;;;;;N;;;0396;;0396
+03B7;GREEK SMALL LETTER ETA;Ll;0;L;;;;;N;;;0397;;0397
+03B8;GREEK SMALL LETTER THETA;Ll;0;L;;;;;N;;;0398;;0398
+03B9;GREEK SMALL LETTER IOTA;Ll;0;L;;;;;N;;;0399;;0399
+03BA;GREEK SMALL LETTER KAPPA;Ll;0;L;;;;;N;;;039A;;039A
+03BB;GREEK SMALL LETTER LAMDA;Ll;0;L;;;;;N;GREEK SMALL LETTER LAMBDA;;039B;;039B
+03BC;GREEK SMALL LETTER MU;Ll;0;L;;;;;N;;;039C;;039C
+03BD;GREEK SMALL LETTER NU;Ll;0;L;;;;;N;;;039D;;039D
+03BE;GREEK SMALL LETTER XI;Ll;0;L;;;;;N;;;039E;;039E
+03BF;GREEK SMALL LETTER OMICRON;Ll;0;L;;;;;N;;;039F;;039F
+03C0;GREEK SMALL LETTER PI;Ll;0;L;;;;;N;;;03A0;;03A0
+03C1;GREEK SMALL LETTER RHO;Ll;0;L;;;;;N;;;03A1;;03A1
+03C2;GREEK SMALL LETTER FINAL SIGMA;Ll;0;L;;;;;N;;;03A3;;03A3
+03C3;GREEK SMALL LETTER SIGMA;Ll;0;L;;;;;N;;;03A3;;03A3
+03C4;GREEK SMALL LETTER TAU;Ll;0;L;;;;;N;;;03A4;;03A4
+03C5;GREEK SMALL LETTER UPSILON;Ll;0;L;;;;;N;;;03A5;;03A5
+03C6;GREEK SMALL LETTER PHI;Ll;0;L;;;;;N;;;03A6;;03A6
+03C7;GREEK SMALL LETTER CHI;Ll;0;L;;;;;N;;;03A7;;03A7
+03C8;GREEK SMALL LETTER PSI;Ll;0;L;;;;;N;;;03A8;;03A8
+03C9;GREEK SMALL LETTER OMEGA;Ll;0;L;;;;;N;;;03A9;;03A9
+03CA;GREEK SMALL LETTER IOTA WITH DIALYTIKA;Ll;0;L;03B9 0308;;;;N;GREEK SMALL LETTER IOTA DIAERESIS;;03AA;;03AA
+03CB;GREEK SMALL LETTER UPSILON WITH DIALYTIKA;Ll;0;L;03C5 0308;;;;N;GREEK SMALL LETTER UPSILON DIAERESIS;;03AB;;03AB
+03CC;GREEK SMALL LETTER OMICRON WITH TONOS;Ll;0;L;03BF 0301;;;;N;GREEK SMALL LETTER OMICRON TONOS;;038C;;038C
+03CD;GREEK SMALL LETTER UPSILON WITH TONOS;Ll;0;L;03C5 0301;;;;N;GREEK SMALL LETTER UPSILON TONOS;;038E;;038E
+03CE;GREEK SMALL LETTER OMEGA WITH TONOS;Ll;0;L;03C9 0301;;;;N;GREEK SMALL LETTER OMEGA TONOS;;038F;;038F
+03D0;GREEK BETA SYMBOL;Ll;0;L;<compat> 03B2;;;;N;GREEK SMALL LETTER CURLED BETA;;0392;;0392
+03D1;GREEK THETA SYMBOL;Ll;0;L;<compat> 03B8;;;;N;GREEK SMALL LETTER SCRIPT THETA;;0398;;0398
+03D2;GREEK UPSILON WITH HOOK SYMBOL;Lu;0;L;<compat> 03A5;;;;N;GREEK CAPITAL LETTER UPSILON HOOK;;;;
+03D3;GREEK UPSILON WITH ACUTE AND HOOK SYMBOL;Lu;0;L;03D2 0301;;;;N;GREEK CAPITAL LETTER UPSILON HOOK TONOS;;;;
+03D4;GREEK UPSILON WITH DIAERESIS AND HOOK SYMBOL;Lu;0;L;03D2 0308;;;;N;GREEK CAPITAL LETTER UPSILON HOOK DIAERESIS;;;;
+03D5;GREEK PHI SYMBOL;Ll;0;L;<compat> 03C6;;;;N;GREEK SMALL LETTER SCRIPT PHI;;03A6;;03A6
+03D6;GREEK PI SYMBOL;Ll;0;L;<compat> 03C0;;;;N;GREEK SMALL LETTER OMEGA PI;;03A0;;03A0
+03D7;GREEK KAI SYMBOL;Ll;0;L;;;;;N;;;;;
+03DA;GREEK LETTER STIGMA;Lu;0;L;;;;;N;GREEK CAPITAL LETTER STIGMA;;;03DB;
+03DB;GREEK SMALL LETTER STIGMA;Ll;0;L;;;;;N;;;03DA;;03DA
+03DC;GREEK LETTER DIGAMMA;Lu;0;L;;;;;N;GREEK CAPITAL LETTER DIGAMMA;;;03DD;
+03DD;GREEK SMALL LETTER DIGAMMA;Ll;0;L;;;;;N;;;03DC;;03DC
+03DE;GREEK LETTER KOPPA;Lu;0;L;;;;;N;GREEK CAPITAL LETTER KOPPA;;;03DF;
+03DF;GREEK SMALL LETTER KOPPA;Ll;0;L;;;;;N;;;03DE;;03DE
+03E0;GREEK LETTER SAMPI;Lu;0;L;;;;;N;GREEK CAPITAL LETTER SAMPI;;;03E1;
+03E1;GREEK SMALL LETTER SAMPI;Ll;0;L;;;;;N;;;03E0;;03E0
+03E2;COPTIC CAPITAL LETTER SHEI;Lu;0;L;;;;;N;GREEK CAPITAL LETTER SHEI;;;03E3;
+03E3;COPTIC SMALL LETTER SHEI;Ll;0;L;;;;;N;GREEK SMALL LETTER SHEI;;03E2;;03E2
+03E4;COPTIC CAPITAL LETTER FEI;Lu;0;L;;;;;N;GREEK CAPITAL LETTER FEI;;;03E5;
+03E5;COPTIC SMALL LETTER FEI;Ll;0;L;;;;;N;GREEK SMALL LETTER FEI;;03E4;;03E4
+03E6;COPTIC CAPITAL LETTER KHEI;Lu;0;L;;;;;N;GREEK CAPITAL LETTER KHEI;;;03E7;
+03E7;COPTIC SMALL LETTER KHEI;Ll;0;L;;;;;N;GREEK SMALL LETTER KHEI;;03E6;;03E6
+03E8;COPTIC CAPITAL LETTER HORI;Lu;0;L;;;;;N;GREEK CAPITAL LETTER HORI;;;03E9;
+03E9;COPTIC SMALL LETTER HORI;Ll;0;L;;;;;N;GREEK SMALL LETTER HORI;;03E8;;03E8
+03EA;COPTIC CAPITAL LETTER GANGIA;Lu;0;L;;;;;N;GREEK CAPITAL LETTER GANGIA;;;03EB;
+03EB;COPTIC SMALL LETTER GANGIA;Ll;0;L;;;;;N;GREEK SMALL LETTER GANGIA;;03EA;;03EA
+03EC;COPTIC CAPITAL LETTER SHIMA;Lu;0;L;;;;;N;GREEK CAPITAL LETTER SHIMA;;;03ED;
+03ED;COPTIC SMALL LETTER SHIMA;Ll;0;L;;;;;N;GREEK SMALL LETTER SHIMA;;03EC;;03EC
+03EE;COPTIC CAPITAL LETTER DEI;Lu;0;L;;;;;N;GREEK CAPITAL LETTER DEI;;;03EF;
+03EF;COPTIC SMALL LETTER DEI;Ll;0;L;;;;;N;GREEK SMALL LETTER DEI;;03EE;;03EE
+03F0;GREEK KAPPA SYMBOL;Ll;0;L;<compat> 03BA;;;;N;GREEK SMALL LETTER SCRIPT KAPPA;;039A;;039A
+03F1;GREEK RHO SYMBOL;Ll;0;L;<compat> 03C1;;;;N;GREEK SMALL LETTER TAILED RHO;;03A1;;03A1
+03F2;GREEK LUNATE SIGMA SYMBOL;Ll;0;L;<compat> 03C2;;;;N;GREEK SMALL LETTER LUNATE SIGMA;;03A3;;03A3
+03F3;GREEK LETTER YOT;Ll;0;L;;;;;N;;;;;
+03F4;GREEK CAPITAL THETA SYMBOL;Lu;0;L;<compat> 0398;;;;N;;;;03B8;
+03F5;GREEK LUNATE EPSILON SYMBOL;Ll;0;L;<compat> 03B5;;;;N;;;0395;;0395
+0400;CYRILLIC CAPITAL LETTER IE WITH GRAVE;Lu;0;L;0415 0300;;;;N;;;;0450;
+0401;CYRILLIC CAPITAL LETTER IO;Lu;0;L;0415 0308;;;;N;;;;0451;
+0402;CYRILLIC CAPITAL LETTER DJE;Lu;0;L;;;;;N;;Serbocroatian;;0452;
+0403;CYRILLIC CAPITAL LETTER GJE;Lu;0;L;0413 0301;;;;N;;;;0453;
+0404;CYRILLIC CAPITAL LETTER UKRAINIAN IE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER E;;;0454;
+0405;CYRILLIC CAPITAL LETTER DZE;Lu;0;L;;;;;N;;;;0455;
+0406;CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER I;;;0456;
+0407;CYRILLIC CAPITAL LETTER YI;Lu;0;L;0406 0308;;;;N;;Ukrainian;;0457;
+0408;CYRILLIC CAPITAL LETTER JE;Lu;0;L;;;;;N;;;;0458;
+0409;CYRILLIC CAPITAL LETTER LJE;Lu;0;L;;;;;N;;;;0459;
+040A;CYRILLIC CAPITAL LETTER NJE;Lu;0;L;;;;;N;;;;045A;
+040B;CYRILLIC CAPITAL LETTER TSHE;Lu;0;L;;;;;N;;Serbocroatian;;045B;
+040C;CYRILLIC CAPITAL LETTER KJE;Lu;0;L;041A 0301;;;;N;;;;045C;
+040D;CYRILLIC CAPITAL LETTER I WITH GRAVE;Lu;0;L;0418 0300;;;;N;;;;045D;
+040E;CYRILLIC CAPITAL LETTER SHORT U;Lu;0;L;0423 0306;;;;N;;Byelorussian;;045E;
+040F;CYRILLIC CAPITAL LETTER DZHE;Lu;0;L;;;;;N;;;;045F;
+0410;CYRILLIC CAPITAL LETTER A;Lu;0;L;;;;;N;;;;0430;
+0411;CYRILLIC CAPITAL LETTER BE;Lu;0;L;;;;;N;;;;0431;
+0412;CYRILLIC CAPITAL LETTER VE;Lu;0;L;;;;;N;;;;0432;
+0413;CYRILLIC CAPITAL LETTER GHE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER GE;;;0433;
+0414;CYRILLIC CAPITAL LETTER DE;Lu;0;L;;;;;N;;;;0434;
+0415;CYRILLIC CAPITAL LETTER IE;Lu;0;L;;;;;N;;;;0435;
+0416;CYRILLIC CAPITAL LETTER ZHE;Lu;0;L;;;;;N;;;;0436;
+0417;CYRILLIC CAPITAL LETTER ZE;Lu;0;L;;;;;N;;;;0437;
+0418;CYRILLIC CAPITAL LETTER I;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER II;;;0438;
+0419;CYRILLIC CAPITAL LETTER SHORT I;Lu;0;L;0418 0306;;;;N;CYRILLIC CAPITAL LETTER SHORT II;;;0439;
+041A;CYRILLIC CAPITAL LETTER KA;Lu;0;L;;;;;N;;;;043A;
+041B;CYRILLIC CAPITAL LETTER EL;Lu;0;L;;;;;N;;;;043B;
+041C;CYRILLIC CAPITAL LETTER EM;Lu;0;L;;;;;N;;;;043C;
+041D;CYRILLIC CAPITAL LETTER EN;Lu;0;L;;;;;N;;;;043D;
+041E;CYRILLIC CAPITAL LETTER O;Lu;0;L;;;;;N;;;;043E;
+041F;CYRILLIC CAPITAL LETTER PE;Lu;0;L;;;;;N;;;;043F;
+0420;CYRILLIC CAPITAL LETTER ER;Lu;0;L;;;;;N;;;;0440;
+0421;CYRILLIC CAPITAL LETTER ES;Lu;0;L;;;;;N;;;;0441;
+0422;CYRILLIC CAPITAL LETTER TE;Lu;0;L;;;;;N;;;;0442;
+0423;CYRILLIC CAPITAL LETTER U;Lu;0;L;;;;;N;;;;0443;
+0424;CYRILLIC CAPITAL LETTER EF;Lu;0;L;;;;;N;;;;0444;
+0425;CYRILLIC CAPITAL LETTER HA;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER KHA;;;0445;
+0426;CYRILLIC CAPITAL LETTER TSE;Lu;0;L;;;;;N;;;;0446;
+0427;CYRILLIC CAPITAL LETTER CHE;Lu;0;L;;;;;N;;;;0447;
+0428;CYRILLIC CAPITAL LETTER SHA;Lu;0;L;;;;;N;;;;0448;
+0429;CYRILLIC CAPITAL LETTER SHCHA;Lu;0;L;;;;;N;;;;0449;
+042A;CYRILLIC CAPITAL LETTER HARD SIGN;Lu;0;L;;;;;N;;;;044A;
+042B;CYRILLIC CAPITAL LETTER YERU;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER YERI;;;044B;
+042C;CYRILLIC CAPITAL LETTER SOFT SIGN;Lu;0;L;;;;;N;;;;044C;
+042D;CYRILLIC CAPITAL LETTER E;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER REVERSED E;;;044D;
+042E;CYRILLIC CAPITAL LETTER YU;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER IU;;;044E;
+042F;CYRILLIC CAPITAL LETTER YA;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER IA;;;044F;
+0430;CYRILLIC SMALL LETTER A;Ll;0;L;;;;;N;;;0410;;0410
+0431;CYRILLIC SMALL LETTER BE;Ll;0;L;;;;;N;;;0411;;0411
+0432;CYRILLIC SMALL LETTER VE;Ll;0;L;;;;;N;;;0412;;0412
+0433;CYRILLIC SMALL LETTER GHE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER GE;;0413;;0413
+0434;CYRILLIC SMALL LETTER DE;Ll;0;L;;;;;N;;;0414;;0414
+0435;CYRILLIC SMALL LETTER IE;Ll;0;L;;;;;N;;;0415;;0415
+0436;CYRILLIC SMALL LETTER ZHE;Ll;0;L;;;;;N;;;0416;;0416
+0437;CYRILLIC SMALL LETTER ZE;Ll;0;L;;;;;N;;;0417;;0417
+0438;CYRILLIC SMALL LETTER I;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER II;;0418;;0418
+0439;CYRILLIC SMALL LETTER SHORT I;Ll;0;L;0438 0306;;;;N;CYRILLIC SMALL LETTER SHORT II;;0419;;0419
+043A;CYRILLIC SMALL LETTER KA;Ll;0;L;;;;;N;;;041A;;041A
+043B;CYRILLIC SMALL LETTER EL;Ll;0;L;;;;;N;;;041B;;041B
+043C;CYRILLIC SMALL LETTER EM;Ll;0;L;;;;;N;;;041C;;041C
+043D;CYRILLIC SMALL LETTER EN;Ll;0;L;;;;;N;;;041D;;041D
+043E;CYRILLIC SMALL LETTER O;Ll;0;L;;;;;N;;;041E;;041E
+043F;CYRILLIC SMALL LETTER PE;Ll;0;L;;;;;N;;;041F;;041F
+0440;CYRILLIC SMALL LETTER ER;Ll;0;L;;;;;N;;;0420;;0420
+0441;CYRILLIC SMALL LETTER ES;Ll;0;L;;;;;N;;;0421;;0421
+0442;CYRILLIC SMALL LETTER TE;Ll;0;L;;;;;N;;;0422;;0422
+0443;CYRILLIC SMALL LETTER U;Ll;0;L;;;;;N;;;0423;;0423
+0444;CYRILLIC SMALL LETTER EF;Ll;0;L;;;;;N;;;0424;;0424
+0445;CYRILLIC SMALL LETTER HA;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER KHA;;0425;;0425
+0446;CYRILLIC SMALL LETTER TSE;Ll;0;L;;;;;N;;;0426;;0426
+0447;CYRILLIC SMALL LETTER CHE;Ll;0;L;;;;;N;;;0427;;0427
+0448;CYRILLIC SMALL LETTER SHA;Ll;0;L;;;;;N;;;0428;;0428
+0449;CYRILLIC SMALL LETTER SHCHA;Ll;0;L;;;;;N;;;0429;;0429
+044A;CYRILLIC SMALL LETTER HARD SIGN;Ll;0;L;;;;;N;;;042A;;042A
+044B;CYRILLIC SMALL LETTER YERU;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER YERI;;042B;;042B
+044C;CYRILLIC SMALL LETTER SOFT SIGN;Ll;0;L;;;;;N;;;042C;;042C
+044D;CYRILLIC SMALL LETTER E;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER REVERSED E;;042D;;042D
+044E;CYRILLIC SMALL LETTER YU;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER IU;;042E;;042E
+044F;CYRILLIC SMALL LETTER YA;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER IA;;042F;;042F
+0450;CYRILLIC SMALL LETTER IE WITH GRAVE;Ll;0;L;0435 0300;;;;N;;;0400;;0400
+0451;CYRILLIC SMALL LETTER IO;Ll;0;L;0435 0308;;;;N;;;0401;;0401
+0452;CYRILLIC SMALL LETTER DJE;Ll;0;L;;;;;N;;Serbocroatian;0402;;0402
+0453;CYRILLIC SMALL LETTER GJE;Ll;0;L;0433 0301;;;;N;;;0403;;0403
+0454;CYRILLIC SMALL LETTER UKRAINIAN IE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER E;;0404;;0404
+0455;CYRILLIC SMALL LETTER DZE;Ll;0;L;;;;;N;;;0405;;0405
+0456;CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER I;;0406;;0406
+0457;CYRILLIC SMALL LETTER YI;Ll;0;L;0456 0308;;;;N;;Ukrainian;0407;;0407
+0458;CYRILLIC SMALL LETTER JE;Ll;0;L;;;;;N;;;0408;;0408
+0459;CYRILLIC SMALL LETTER LJE;Ll;0;L;;;;;N;;;0409;;0409
+045A;CYRILLIC SMALL LETTER NJE;Ll;0;L;;;;;N;;;040A;;040A
+045B;CYRILLIC SMALL LETTER TSHE;Ll;0;L;;;;;N;;Serbocroatian;040B;;040B
+045C;CYRILLIC SMALL LETTER KJE;Ll;0;L;043A 0301;;;;N;;;040C;;040C
+045D;CYRILLIC SMALL LETTER I WITH GRAVE;Ll;0;L;0438 0300;;;;N;;;040D;;040D
+045E;CYRILLIC SMALL LETTER SHORT U;Ll;0;L;0443 0306;;;;N;;Byelorussian;040E;;040E
+045F;CYRILLIC SMALL LETTER DZHE;Ll;0;L;;;;;N;;;040F;;040F
+0460;CYRILLIC CAPITAL LETTER OMEGA;Lu;0;L;;;;;N;;;;0461;
+0461;CYRILLIC SMALL LETTER OMEGA;Ll;0;L;;;;;N;;;0460;;0460
+0462;CYRILLIC CAPITAL LETTER YAT;Lu;0;L;;;;;N;;;;0463;
+0463;CYRILLIC SMALL LETTER YAT;Ll;0;L;;;;;N;;;0462;;0462
+0464;CYRILLIC CAPITAL LETTER IOTIFIED E;Lu;0;L;;;;;N;;;;0465;
+0465;CYRILLIC SMALL LETTER IOTIFIED E;Ll;0;L;;;;;N;;;0464;;0464
+0466;CYRILLIC CAPITAL LETTER LITTLE YUS;Lu;0;L;;;;;N;;;;0467;
+0467;CYRILLIC SMALL LETTER LITTLE YUS;Ll;0;L;;;;;N;;;0466;;0466
+0468;CYRILLIC CAPITAL LETTER IOTIFIED LITTLE YUS;Lu;0;L;;;;;N;;;;0469;
+0469;CYRILLIC SMALL LETTER IOTIFIED LITTLE YUS;Ll;0;L;;;;;N;;;0468;;0468
+046A;CYRILLIC CAPITAL LETTER BIG YUS;Lu;0;L;;;;;N;;;;046B;
+046B;CYRILLIC SMALL LETTER BIG YUS;Ll;0;L;;;;;N;;;046A;;046A
+046C;CYRILLIC CAPITAL LETTER IOTIFIED BIG YUS;Lu;0;L;;;;;N;;;;046D;
+046D;CYRILLIC SMALL LETTER IOTIFIED BIG YUS;Ll;0;L;;;;;N;;;046C;;046C
+046E;CYRILLIC CAPITAL LETTER KSI;Lu;0;L;;;;;N;;;;046F;
+046F;CYRILLIC SMALL LETTER KSI;Ll;0;L;;;;;N;;;046E;;046E
+0470;CYRILLIC CAPITAL LETTER PSI;Lu;0;L;;;;;N;;;;0471;
+0471;CYRILLIC SMALL LETTER PSI;Ll;0;L;;;;;N;;;0470;;0470
+0472;CYRILLIC CAPITAL LETTER FITA;Lu;0;L;;;;;N;;;;0473;
+0473;CYRILLIC SMALL LETTER FITA;Ll;0;L;;;;;N;;;0472;;0472
+0474;CYRILLIC CAPITAL LETTER IZHITSA;Lu;0;L;;;;;N;;;;0475;
+0475;CYRILLIC SMALL LETTER IZHITSA;Ll;0;L;;;;;N;;;0474;;0474
+0476;CYRILLIC CAPITAL LETTER IZHITSA WITH DOUBLE GRAVE ACCENT;Lu;0;L;0474 030F;;;;N;CYRILLIC CAPITAL LETTER IZHITSA DOUBLE GRAVE;;;0477;
+0477;CYRILLIC SMALL LETTER IZHITSA WITH DOUBLE GRAVE ACCENT;Ll;0;L;0475 030F;;;;N;CYRILLIC SMALL LETTER IZHITSA DOUBLE GRAVE;;0476;;0476
+0478;CYRILLIC CAPITAL LETTER UK;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER UK DIGRAPH;;;0479;
+0479;CYRILLIC SMALL LETTER UK;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER UK DIGRAPH;;0478;;0478
+047A;CYRILLIC CAPITAL LETTER ROUND OMEGA;Lu;0;L;;;;;N;;;;047B;
+047B;CYRILLIC SMALL LETTER ROUND OMEGA;Ll;0;L;;;;;N;;;047A;;047A
+047C;CYRILLIC CAPITAL LETTER OMEGA WITH TITLO;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER OMEGA TITLO;;;047D;
+047D;CYRILLIC SMALL LETTER OMEGA WITH TITLO;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER OMEGA TITLO;;047C;;047C
+047E;CYRILLIC CAPITAL LETTER OT;Lu;0;L;;;;;N;;;;047F;
+047F;CYRILLIC SMALL LETTER OT;Ll;0;L;;;;;N;;;047E;;047E
+0480;CYRILLIC CAPITAL LETTER KOPPA;Lu;0;L;;;;;N;;;;0481;
+0481;CYRILLIC SMALL LETTER KOPPA;Ll;0;L;;;;;N;;;0480;;0480
+0482;CYRILLIC THOUSANDS SIGN;So;0;L;;;;;N;;;;;
+0483;COMBINING CYRILLIC TITLO;Mn;230;NSM;;;;;N;CYRILLIC NON-SPACING TITLO;;;;
+0484;COMBINING CYRILLIC PALATALIZATION;Mn;230;NSM;;;;;N;CYRILLIC NON-SPACING PALATALIZATION;;;;
+0485;COMBINING CYRILLIC DASIA PNEUMATA;Mn;230;NSM;;;;;N;CYRILLIC NON-SPACING DASIA PNEUMATA;;;;
+0486;COMBINING CYRILLIC PSILI PNEUMATA;Mn;230;NSM;;;;;N;CYRILLIC NON-SPACING PSILI PNEUMATA;;;;
+0488;COMBINING CYRILLIC HUNDRED THOUSANDS SIGN;Me;0;NSM;;;;;N;;;;;
+0489;COMBINING CYRILLIC MILLIONS SIGN;Me;0;NSM;;;;;N;;;;;
+048C;CYRILLIC CAPITAL LETTER SEMISOFT SIGN;Lu;0;L;;;;;N;;;;048D;
+048D;CYRILLIC SMALL LETTER SEMISOFT SIGN;Ll;0;L;;;;;N;;;048C;;048C
+048E;CYRILLIC CAPITAL LETTER ER WITH TICK;Lu;0;L;;;;;N;;;;048F;
+048F;CYRILLIC SMALL LETTER ER WITH TICK;Ll;0;L;;;;;N;;;048E;;048E
+0490;CYRILLIC CAPITAL LETTER GHE WITH UPTURN;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER GE WITH UPTURN;;;0491;
+0491;CYRILLIC SMALL LETTER GHE WITH UPTURN;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER GE WITH UPTURN;;0490;;0490
+0492;CYRILLIC CAPITAL LETTER GHE WITH STROKE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER GE BAR;;;0493;
+0493;CYRILLIC SMALL LETTER GHE WITH STROKE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER GE BAR;;0492;;0492
+0494;CYRILLIC CAPITAL LETTER GHE WITH MIDDLE HOOK;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER GE HOOK;;;0495;
+0495;CYRILLIC SMALL LETTER GHE WITH MIDDLE HOOK;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER GE HOOK;;0494;;0494
+0496;CYRILLIC CAPITAL LETTER ZHE WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER ZHE WITH RIGHT DESCENDER;;;0497;
+0497;CYRILLIC SMALL LETTER ZHE WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER ZHE WITH RIGHT DESCENDER;;0496;;0496
+0498;CYRILLIC CAPITAL LETTER ZE WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER ZE CEDILLA;;;0499;
+0499;CYRILLIC SMALL LETTER ZE WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER ZE CEDILLA;;0498;;0498
+049A;CYRILLIC CAPITAL LETTER KA WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER KA WITH RIGHT DESCENDER;;;049B;
+049B;CYRILLIC SMALL LETTER KA WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER KA WITH RIGHT DESCENDER;;049A;;049A
+049C;CYRILLIC CAPITAL LETTER KA WITH VERTICAL STROKE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER KA VERTICAL BAR;;;049D;
+049D;CYRILLIC SMALL LETTER KA WITH VERTICAL STROKE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER KA VERTICAL BAR;;049C;;049C
+049E;CYRILLIC CAPITAL LETTER KA WITH STROKE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER KA BAR;;;049F;
+049F;CYRILLIC SMALL LETTER KA WITH STROKE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER KA BAR;;049E;;049E
+04A0;CYRILLIC CAPITAL LETTER BASHKIR KA;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER REVERSED GE KA;;;04A1;
+04A1;CYRILLIC SMALL LETTER BASHKIR KA;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER REVERSED GE KA;;04A0;;04A0
+04A2;CYRILLIC CAPITAL LETTER EN WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER EN WITH RIGHT DESCENDER;;;04A3;
+04A3;CYRILLIC SMALL LETTER EN WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER EN WITH RIGHT DESCENDER;;04A2;;04A2
+04A4;CYRILLIC CAPITAL LIGATURE EN GHE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER EN GE;;;04A5;
+04A5;CYRILLIC SMALL LIGATURE EN GHE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER EN GE;;04A4;;04A4
+04A6;CYRILLIC CAPITAL LETTER PE WITH MIDDLE HOOK;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER PE HOOK;Abkhasian;;04A7;
+04A7;CYRILLIC SMALL LETTER PE WITH MIDDLE HOOK;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER PE HOOK;Abkhasian;04A6;;04A6
+04A8;CYRILLIC CAPITAL LETTER ABKHASIAN HA;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER O HOOK;;;04A9;
+04A9;CYRILLIC SMALL LETTER ABKHASIAN HA;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER O HOOK;;04A8;;04A8
+04AA;CYRILLIC CAPITAL LETTER ES WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER ES CEDILLA;;;04AB;
+04AB;CYRILLIC SMALL LETTER ES WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER ES CEDILLA;;04AA;;04AA
+04AC;CYRILLIC CAPITAL LETTER TE WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER TE WITH RIGHT DESCENDER;;;04AD;
+04AD;CYRILLIC SMALL LETTER TE WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER TE WITH RIGHT DESCENDER;;04AC;;04AC
+04AE;CYRILLIC CAPITAL LETTER STRAIGHT U;Lu;0;L;;;;;N;;;;04AF;
+04AF;CYRILLIC SMALL LETTER STRAIGHT U;Ll;0;L;;;;;N;;;04AE;;04AE
+04B0;CYRILLIC CAPITAL LETTER STRAIGHT U WITH STROKE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER STRAIGHT U BAR;;;04B1;
+04B1;CYRILLIC SMALL LETTER STRAIGHT U WITH STROKE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER STRAIGHT U BAR;;04B0;;04B0
+04B2;CYRILLIC CAPITAL LETTER HA WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER KHA WITH RIGHT DESCENDER;;;04B3;
+04B3;CYRILLIC SMALL LETTER HA WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER KHA WITH RIGHT DESCENDER;;04B2;;04B2
+04B4;CYRILLIC CAPITAL LIGATURE TE TSE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER TE TSE;Abkhasian;;04B5;
+04B5;CYRILLIC SMALL LIGATURE TE TSE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER TE TSE;Abkhasian;04B4;;04B4
+04B6;CYRILLIC CAPITAL LETTER CHE WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER CHE WITH RIGHT DESCENDER;;;04B7;
+04B7;CYRILLIC SMALL LETTER CHE WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER CHE WITH RIGHT DESCENDER;;04B6;;04B6
+04B8;CYRILLIC CAPITAL LETTER CHE WITH VERTICAL STROKE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER CHE VERTICAL BAR;;;04B9;
+04B9;CYRILLIC SMALL LETTER CHE WITH VERTICAL STROKE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER CHE VERTICAL BAR;;04B8;;04B8
+04BA;CYRILLIC CAPITAL LETTER SHHA;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER H;;;04BB;
+04BB;CYRILLIC SMALL LETTER SHHA;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER H;;04BA;;04BA
+04BC;CYRILLIC CAPITAL LETTER ABKHASIAN CHE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER IE HOOK;;;04BD;
+04BD;CYRILLIC SMALL LETTER ABKHASIAN CHE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER IE HOOK;;04BC;;04BC
+04BE;CYRILLIC CAPITAL LETTER ABKHASIAN CHE WITH DESCENDER;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER IE HOOK OGONEK;;;04BF;
+04BF;CYRILLIC SMALL LETTER ABKHASIAN CHE WITH DESCENDER;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER IE HOOK OGONEK;;04BE;;04BE
+04C0;CYRILLIC LETTER PALOCHKA;Lu;0;L;;;;;N;CYRILLIC LETTER I;;;;
+04C1;CYRILLIC CAPITAL LETTER ZHE WITH BREVE;Lu;0;L;0416 0306;;;;N;CYRILLIC CAPITAL LETTER SHORT ZHE;;;04C2;
+04C2;CYRILLIC SMALL LETTER ZHE WITH BREVE;Ll;0;L;0436 0306;;;;N;CYRILLIC SMALL LETTER SHORT ZHE;;04C1;;04C1
+04C3;CYRILLIC CAPITAL LETTER KA WITH HOOK;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER KA HOOK;;;04C4;
+04C4;CYRILLIC SMALL LETTER KA WITH HOOK;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER KA HOOK;;04C3;;04C3
+04C7;CYRILLIC CAPITAL LETTER EN WITH HOOK;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER EN HOOK;;;04C8;
+04C8;CYRILLIC SMALL LETTER EN WITH HOOK;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER EN HOOK;;04C7;;04C7
+04CB;CYRILLIC CAPITAL LETTER KHAKASSIAN CHE;Lu;0;L;;;;;N;CYRILLIC CAPITAL LETTER CHE WITH LEFT DESCENDER;;;04CC;
+04CC;CYRILLIC SMALL LETTER KHAKASSIAN CHE;Ll;0;L;;;;;N;CYRILLIC SMALL LETTER CHE WITH LEFT DESCENDER;;04CB;;04CB
+04D0;CYRILLIC CAPITAL LETTER A WITH BREVE;Lu;0;L;0410 0306;;;;N;;;;04D1;
+04D1;CYRILLIC SMALL LETTER A WITH BREVE;Ll;0;L;0430 0306;;;;N;;;04D0;;04D0
+04D2;CYRILLIC CAPITAL LETTER A WITH DIAERESIS;Lu;0;L;0410 0308;;;;N;;;;04D3;
+04D3;CYRILLIC SMALL LETTER A WITH DIAERESIS;Ll;0;L;0430 0308;;;;N;;;04D2;;04D2
+04D4;CYRILLIC CAPITAL LIGATURE A IE;Lu;0;L;;;;;N;;;;04D5;
+04D5;CYRILLIC SMALL LIGATURE A IE;Ll;0;L;;;;;N;;;04D4;;04D4
+04D6;CYRILLIC CAPITAL LETTER IE WITH BREVE;Lu;0;L;0415 0306;;;;N;;;;04D7;
+04D7;CYRILLIC SMALL LETTER IE WITH BREVE;Ll;0;L;0435 0306;;;;N;;;04D6;;04D6
+04D8;CYRILLIC CAPITAL LETTER SCHWA;Lu;0;L;;;;;N;;;;04D9;
+04D9;CYRILLIC SMALL LETTER SCHWA;Ll;0;L;;;;;N;;;04D8;;04D8
+04DA;CYRILLIC CAPITAL LETTER SCHWA WITH DIAERESIS;Lu;0;L;04D8 0308;;;;N;;;;04DB;
+04DB;CYRILLIC SMALL LETTER SCHWA WITH DIAERESIS;Ll;0;L;04D9 0308;;;;N;;;04DA;;04DA
+04DC;CYRILLIC CAPITAL LETTER ZHE WITH DIAERESIS;Lu;0;L;0416 0308;;;;N;;;;04DD;
+04DD;CYRILLIC SMALL LETTER ZHE WITH DIAERESIS;Ll;0;L;0436 0308;;;;N;;;04DC;;04DC
+04DE;CYRILLIC CAPITAL LETTER ZE WITH DIAERESIS;Lu;0;L;0417 0308;;;;N;;;;04DF;
+04DF;CYRILLIC SMALL LETTER ZE WITH DIAERESIS;Ll;0;L;0437 0308;;;;N;;;04DE;;04DE
+04E0;CYRILLIC CAPITAL LETTER ABKHASIAN DZE;Lu;0;L;;;;;N;;;;04E1;
+04E1;CYRILLIC SMALL LETTER ABKHASIAN DZE;Ll;0;L;;;;;N;;;04E0;;04E0
+04E2;CYRILLIC CAPITAL LETTER I WITH MACRON;Lu;0;L;0418 0304;;;;N;;;;04E3;
+04E3;CYRILLIC SMALL LETTER I WITH MACRON;Ll;0;L;0438 0304;;;;N;;;04E2;;04E2
+04E4;CYRILLIC CAPITAL LETTER I WITH DIAERESIS;Lu;0;L;0418 0308;;;;N;;;;04E5;
+04E5;CYRILLIC SMALL LETTER I WITH DIAERESIS;Ll;0;L;0438 0308;;;;N;;;04E4;;04E4
+04E6;CYRILLIC CAPITAL LETTER O WITH DIAERESIS;Lu;0;L;041E 0308;;;;N;;;;04E7;
+04E7;CYRILLIC SMALL LETTER O WITH DIAERESIS;Ll;0;L;043E 0308;;;;N;;;04E6;;04E6
+04E8;CYRILLIC CAPITAL LETTER BARRED O;Lu;0;L;;;;;N;;;;04E9;
+04E9;CYRILLIC SMALL LETTER BARRED O;Ll;0;L;;;;;N;;;04E8;;04E8
+04EA;CYRILLIC CAPITAL LETTER BARRED O WITH DIAERESIS;Lu;0;L;04E8 0308;;;;N;;;;04EB;
+04EB;CYRILLIC SMALL LETTER BARRED O WITH DIAERESIS;Ll;0;L;04E9 0308;;;;N;;;04EA;;04EA
+04EC;CYRILLIC CAPITAL LETTER E WITH DIAERESIS;Lu;0;L;042D 0308;;;;N;;;;04ED;
+04ED;CYRILLIC SMALL LETTER E WITH DIAERESIS;Ll;0;L;044D 0308;;;;N;;;04EC;;04EC
+04EE;CYRILLIC CAPITAL LETTER U WITH MACRON;Lu;0;L;0423 0304;;;;N;;;;04EF;
+04EF;CYRILLIC SMALL LETTER U WITH MACRON;Ll;0;L;0443 0304;;;;N;;;04EE;;04EE
+04F0;CYRILLIC CAPITAL LETTER U WITH DIAERESIS;Lu;0;L;0423 0308;;;;N;;;;04F1;
+04F1;CYRILLIC SMALL LETTER U WITH DIAERESIS;Ll;0;L;0443 0308;;;;N;;;04F0;;04F0
+04F2;CYRILLIC CAPITAL LETTER U WITH DOUBLE ACUTE;Lu;0;L;0423 030B;;;;N;;;;04F3;
+04F3;CYRILLIC SMALL LETTER U WITH DOUBLE ACUTE;Ll;0;L;0443 030B;;;;N;;;04F2;;04F2
+04F4;CYRILLIC CAPITAL LETTER CHE WITH DIAERESIS;Lu;0;L;0427 0308;;;;N;;;;04F5;
+04F5;CYRILLIC SMALL LETTER CHE WITH DIAERESIS;Ll;0;L;0447 0308;;;;N;;;04F4;;04F4
+04F8;CYRILLIC CAPITAL LETTER YERU WITH DIAERESIS;Lu;0;L;042B 0308;;;;N;;;;04F9;
+04F9;CYRILLIC SMALL LETTER YERU WITH DIAERESIS;Ll;0;L;044B 0308;;;;N;;;04F8;;04F8
+0531;ARMENIAN CAPITAL LETTER AYB;Lu;0;L;;;;;N;;;;0561;
+0532;ARMENIAN CAPITAL LETTER BEN;Lu;0;L;;;;;N;;;;0562;
+0533;ARMENIAN CAPITAL LETTER GIM;Lu;0;L;;;;;N;;;;0563;
+0534;ARMENIAN CAPITAL LETTER DA;Lu;0;L;;;;;N;;;;0564;
+0535;ARMENIAN CAPITAL LETTER ECH;Lu;0;L;;;;;N;;;;0565;
+0536;ARMENIAN CAPITAL LETTER ZA;Lu;0;L;;;;;N;;;;0566;
+0537;ARMENIAN CAPITAL LETTER EH;Lu;0;L;;;;;N;;;;0567;
+0538;ARMENIAN CAPITAL LETTER ET;Lu;0;L;;;;;N;;;;0568;
+0539;ARMENIAN CAPITAL LETTER TO;Lu;0;L;;;;;N;;;;0569;
+053A;ARMENIAN CAPITAL LETTER ZHE;Lu;0;L;;;;;N;;;;056A;
+053B;ARMENIAN CAPITAL LETTER INI;Lu;0;L;;;;;N;;;;056B;
+053C;ARMENIAN CAPITAL LETTER LIWN;Lu;0;L;;;;;N;;;;056C;
+053D;ARMENIAN CAPITAL LETTER XEH;Lu;0;L;;;;;N;;;;056D;
+053E;ARMENIAN CAPITAL LETTER CA;Lu;0;L;;;;;N;;;;056E;
+053F;ARMENIAN CAPITAL LETTER KEN;Lu;0;L;;;;;N;;;;056F;
+0540;ARMENIAN CAPITAL LETTER HO;Lu;0;L;;;;;N;;;;0570;
+0541;ARMENIAN CAPITAL LETTER JA;Lu;0;L;;;;;N;;;;0571;
+0542;ARMENIAN CAPITAL LETTER GHAD;Lu;0;L;;;;;N;ARMENIAN CAPITAL LETTER LAD;;;0572;
+0543;ARMENIAN CAPITAL LETTER CHEH;Lu;0;L;;;;;N;;;;0573;
+0544;ARMENIAN CAPITAL LETTER MEN;Lu;0;L;;;;;N;;;;0574;
+0545;ARMENIAN CAPITAL LETTER YI;Lu;0;L;;;;;N;;;;0575;
+0546;ARMENIAN CAPITAL LETTER NOW;Lu;0;L;;;;;N;;;;0576;
+0547;ARMENIAN CAPITAL LETTER SHA;Lu;0;L;;;;;N;;;;0577;
+0548;ARMENIAN CAPITAL LETTER VO;Lu;0;L;;;;;N;;;;0578;
+0549;ARMENIAN CAPITAL LETTER CHA;Lu;0;L;;;;;N;;;;0579;
+054A;ARMENIAN CAPITAL LETTER PEH;Lu;0;L;;;;;N;;;;057A;
+054B;ARMENIAN CAPITAL LETTER JHEH;Lu;0;L;;;;;N;;;;057B;
+054C;ARMENIAN CAPITAL LETTER RA;Lu;0;L;;;;;N;;;;057C;
+054D;ARMENIAN CAPITAL LETTER SEH;Lu;0;L;;;;;N;;;;057D;
+054E;ARMENIAN CAPITAL LETTER VEW;Lu;0;L;;;;;N;;;;057E;
+054F;ARMENIAN CAPITAL LETTER TIWN;Lu;0;L;;;;;N;;;;057F;
+0550;ARMENIAN CAPITAL LETTER REH;Lu;0;L;;;;;N;;;;0580;
+0551;ARMENIAN CAPITAL LETTER CO;Lu;0;L;;;;;N;;;;0581;
+0552;ARMENIAN CAPITAL LETTER YIWN;Lu;0;L;;;;;N;;;;0582;
+0553;ARMENIAN CAPITAL LETTER PIWR;Lu;0;L;;;;;N;;;;0583;
+0554;ARMENIAN CAPITAL LETTER KEH;Lu;0;L;;;;;N;;;;0584;
+0555;ARMENIAN CAPITAL LETTER OH;Lu;0;L;;;;;N;;;;0585;
+0556;ARMENIAN CAPITAL LETTER FEH;Lu;0;L;;;;;N;;;;0586;
+0559;ARMENIAN MODIFIER LETTER LEFT HALF RING;Lm;0;L;;;;;N;;;;;
+055A;ARMENIAN APOSTROPHE;Po;0;L;;;;;N;ARMENIAN MODIFIER LETTER RIGHT HALF RING;;;;
+055B;ARMENIAN EMPHASIS MARK;Po;0;L;;;;;N;;;;;
+055C;ARMENIAN EXCLAMATION MARK;Po;0;L;;;;;N;;;;;
+055D;ARMENIAN COMMA;Po;0;L;;;;;N;;;;;
+055E;ARMENIAN QUESTION MARK;Po;0;L;;;;;N;;;;;
+055F;ARMENIAN ABBREVIATION MARK;Po;0;L;;;;;N;;;;;
+0561;ARMENIAN SMALL LETTER AYB;Ll;0;L;;;;;N;;;0531;;0531
+0562;ARMENIAN SMALL LETTER BEN;Ll;0;L;;;;;N;;;0532;;0532
+0563;ARMENIAN SMALL LETTER GIM;Ll;0;L;;;;;N;;;0533;;0533
+0564;ARMENIAN SMALL LETTER DA;Ll;0;L;;;;;N;;;0534;;0534
+0565;ARMENIAN SMALL LETTER ECH;Ll;0;L;;;;;N;;;0535;;0535
+0566;ARMENIAN SMALL LETTER ZA;Ll;0;L;;;;;N;;;0536;;0536
+0567;ARMENIAN SMALL LETTER EH;Ll;0;L;;;;;N;;;0537;;0537
+0568;ARMENIAN SMALL LETTER ET;Ll;0;L;;;;;N;;;0538;;0538
+0569;ARMENIAN SMALL LETTER TO;Ll;0;L;;;;;N;;;0539;;0539
+056A;ARMENIAN SMALL LETTER ZHE;Ll;0;L;;;;;N;;;053A;;053A
+056B;ARMENIAN SMALL LETTER INI;Ll;0;L;;;;;N;;;053B;;053B
+056C;ARMENIAN SMALL LETTER LIWN;Ll;0;L;;;;;N;;;053C;;053C
+056D;ARMENIAN SMALL LETTER XEH;Ll;0;L;;;;;N;;;053D;;053D
+056E;ARMENIAN SMALL LETTER CA;Ll;0;L;;;;;N;;;053E;;053E
+056F;ARMENIAN SMALL LETTER KEN;Ll;0;L;;;;;N;;;053F;;053F
+0570;ARMENIAN SMALL LETTER HO;Ll;0;L;;;;;N;;;0540;;0540
+0571;ARMENIAN SMALL LETTER JA;Ll;0;L;;;;;N;;;0541;;0541
+0572;ARMENIAN SMALL LETTER GHAD;Ll;0;L;;;;;N;ARMENIAN SMALL LETTER LAD;;0542;;0542
+0573;ARMENIAN SMALL LETTER CHEH;Ll;0;L;;;;;N;;;0543;;0543
+0574;ARMENIAN SMALL LETTER MEN;Ll;0;L;;;;;N;;;0544;;0544
+0575;ARMENIAN SMALL LETTER YI;Ll;0;L;;;;;N;;;0545;;0545
+0576;ARMENIAN SMALL LETTER NOW;Ll;0;L;;;;;N;;;0546;;0546
+0577;ARMENIAN SMALL LETTER SHA;Ll;0;L;;;;;N;;;0547;;0547
+0578;ARMENIAN SMALL LETTER VO;Ll;0;L;;;;;N;;;0548;;0548
+0579;ARMENIAN SMALL LETTER CHA;Ll;0;L;;;;;N;;;0549;;0549
+057A;ARMENIAN SMALL LETTER PEH;Ll;0;L;;;;;N;;;054A;;054A
+057B;ARMENIAN SMALL LETTER JHEH;Ll;0;L;;;;;N;;;054B;;054B
+057C;ARMENIAN SMALL LETTER RA;Ll;0;L;;;;;N;;;054C;;054C
+057D;ARMENIAN SMALL LETTER SEH;Ll;0;L;;;;;N;;;054D;;054D
+057E;ARMENIAN SMALL LETTER VEW;Ll;0;L;;;;;N;;;054E;;054E
+057F;ARMENIAN SMALL LETTER TIWN;Ll;0;L;;;;;N;;;054F;;054F
+0580;ARMENIAN SMALL LETTER REH;Ll;0;L;;;;;N;;;0550;;0550
+0581;ARMENIAN SMALL LETTER CO;Ll;0;L;;;;;N;;;0551;;0551
+0582;ARMENIAN SMALL LETTER YIWN;Ll;0;L;;;;;N;;;0552;;0552
+0583;ARMENIAN SMALL LETTER PIWR;Ll;0;L;;;;;N;;;0553;;0553
+0584;ARMENIAN SMALL LETTER KEH;Ll;0;L;;;;;N;;;0554;;0554
+0585;ARMENIAN SMALL LETTER OH;Ll;0;L;;;;;N;;;0555;;0555
+0586;ARMENIAN SMALL LETTER FEH;Ll;0;L;;;;;N;;;0556;;0556
+0587;ARMENIAN SMALL LIGATURE ECH YIWN;Ll;0;L;<compat> 0565 0582;;;;N;;;;;
+0589;ARMENIAN FULL STOP;Po;0;L;;;;;N;ARMENIAN PERIOD;;;;
+058A;ARMENIAN HYPHEN;Pd;0;ON;;;;;N;;;;;
+0591;HEBREW ACCENT ETNAHTA;Mn;220;NSM;;;;;N;;;;;
+0592;HEBREW ACCENT SEGOL;Mn;230;NSM;;;;;N;;;;;
+0593;HEBREW ACCENT SHALSHELET;Mn;230;NSM;;;;;N;;;;;
+0594;HEBREW ACCENT ZAQEF QATAN;Mn;230;NSM;;;;;N;;;;;
+0595;HEBREW ACCENT ZAQEF GADOL;Mn;230;NSM;;;;;N;;;;;
+0596;HEBREW ACCENT TIPEHA;Mn;220;NSM;;;;;N;;*;;;
+0597;HEBREW ACCENT REVIA;Mn;230;NSM;;;;;N;;;;;
+0598;HEBREW ACCENT ZARQA;Mn;230;NSM;;;;;N;;*;;;
+0599;HEBREW ACCENT PASHTA;Mn;230;NSM;;;;;N;;;;;
+059A;HEBREW ACCENT YETIV;Mn;222;NSM;;;;;N;;;;;
+059B;HEBREW ACCENT TEVIR;Mn;220;NSM;;;;;N;;;;;
+059C;HEBREW ACCENT GERESH;Mn;230;NSM;;;;;N;;;;;
+059D;HEBREW ACCENT GERESH MUQDAM;Mn;230;NSM;;;;;N;;;;;
+059E;HEBREW ACCENT GERSHAYIM;Mn;230;NSM;;;;;N;;;;;
+059F;HEBREW ACCENT QARNEY PARA;Mn;230;NSM;;;;;N;;;;;
+05A0;HEBREW ACCENT TELISHA GEDOLA;Mn;230;NSM;;;;;N;;;;;
+05A1;HEBREW ACCENT PAZER;Mn;230;NSM;;;;;N;;;;;
+05A3;HEBREW ACCENT MUNAH;Mn;220;NSM;;;;;N;;;;;
+05A4;HEBREW ACCENT MAHAPAKH;Mn;220;NSM;;;;;N;;;;;
+05A5;HEBREW ACCENT MERKHA;Mn;220;NSM;;;;;N;;*;;;
+05A6;HEBREW ACCENT MERKHA KEFULA;Mn;220;NSM;;;;;N;;;;;
+05A7;HEBREW ACCENT DARGA;Mn;220;NSM;;;;;N;;;;;
+05A8;HEBREW ACCENT QADMA;Mn;230;NSM;;;;;N;;*;;;
+05A9;HEBREW ACCENT TELISHA QETANA;Mn;230;NSM;;;;;N;;;;;
+05AA;HEBREW ACCENT YERAH BEN YOMO;Mn;220;NSM;;;;;N;;*;;;
+05AB;HEBREW ACCENT OLE;Mn;230;NSM;;;;;N;;;;;
+05AC;HEBREW ACCENT ILUY;Mn;230;NSM;;;;;N;;;;;
+05AD;HEBREW ACCENT DEHI;Mn;222;NSM;;;;;N;;;;;
+05AE;HEBREW ACCENT ZINOR;Mn;228;NSM;;;;;N;;;;;
+05AF;HEBREW MARK MASORA CIRCLE;Mn;230;NSM;;;;;N;;;;;
+05B0;HEBREW POINT SHEVA;Mn;10;NSM;;;;;N;;;;;
+05B1;HEBREW POINT HATAF SEGOL;Mn;11;NSM;;;;;N;;;;;
+05B2;HEBREW POINT HATAF PATAH;Mn;12;NSM;;;;;N;;;;;
+05B3;HEBREW POINT HATAF QAMATS;Mn;13;NSM;;;;;N;;;;;
+05B4;HEBREW POINT HIRIQ;Mn;14;NSM;;;;;N;;;;;
+05B5;HEBREW POINT TSERE;Mn;15;NSM;;;;;N;;;;;
+05B6;HEBREW POINT SEGOL;Mn;16;NSM;;;;;N;;;;;
+05B7;HEBREW POINT PATAH;Mn;17;NSM;;;;;N;;;;;
+05B8;HEBREW POINT QAMATS;Mn;18;NSM;;;;;N;;;;;
+05B9;HEBREW POINT HOLAM;Mn;19;NSM;;;;;N;;;;;
+05BB;HEBREW POINT QUBUTS;Mn;20;NSM;;;;;N;;;;;
+05BC;HEBREW POINT DAGESH OR MAPIQ;Mn;21;NSM;;;;;N;HEBREW POINT DAGESH;or shuruq;;;
+05BD;HEBREW POINT METEG;Mn;22;NSM;;;;;N;;*;;;
+05BE;HEBREW PUNCTUATION MAQAF;Po;0;R;;;;;N;;;;;
+05BF;HEBREW POINT RAFE;Mn;23;NSM;;;;;N;;;;;
+05C0;HEBREW PUNCTUATION PASEQ;Po;0;R;;;;;N;HEBREW POINT PASEQ;*;;;
+05C1;HEBREW POINT SHIN DOT;Mn;24;NSM;;;;;N;;;;;
+05C2;HEBREW POINT SIN DOT;Mn;25;NSM;;;;;N;;;;;
+05C3;HEBREW PUNCTUATION SOF PASUQ;Po;0;R;;;;;N;;*;;;
+05C4;HEBREW MARK UPPER DOT;Mn;230;NSM;;;;;N;;;;;
+05D0;HEBREW LETTER ALEF;Lo;0;R;;;;;N;;;;;
+05D1;HEBREW LETTER BET;Lo;0;R;;;;;N;;;;;
+05D2;HEBREW LETTER GIMEL;Lo;0;R;;;;;N;;;;;
+05D3;HEBREW LETTER DALET;Lo;0;R;;;;;N;;;;;
+05D4;HEBREW LETTER HE;Lo;0;R;;;;;N;;;;;
+05D5;HEBREW LETTER VAV;Lo;0;R;;;;;N;;;;;
+05D6;HEBREW LETTER ZAYIN;Lo;0;R;;;;;N;;;;;
+05D7;HEBREW LETTER HET;Lo;0;R;;;;;N;;;;;
+05D8;HEBREW LETTER TET;Lo;0;R;;;;;N;;;;;
+05D9;HEBREW LETTER YOD;Lo;0;R;;;;;N;;;;;
+05DA;HEBREW LETTER FINAL KAF;Lo;0;R;;;;;N;;;;;
+05DB;HEBREW LETTER KAF;Lo;0;R;;;;;N;;;;;
+05DC;HEBREW LETTER LAMED;Lo;0;R;;;;;N;;;;;
+05DD;HEBREW LETTER FINAL MEM;Lo;0;R;;;;;N;;;;;
+05DE;HEBREW LETTER MEM;Lo;0;R;;;;;N;;;;;
+05DF;HEBREW LETTER FINAL NUN;Lo;0;R;;;;;N;;;;;
+05E0;HEBREW LETTER NUN;Lo;0;R;;;;;N;;;;;
+05E1;HEBREW LETTER SAMEKH;Lo;0;R;;;;;N;;;;;
+05E2;HEBREW LETTER AYIN;Lo;0;R;;;;;N;;;;;
+05E3;HEBREW LETTER FINAL PE;Lo;0;R;;;;;N;;;;;
+05E4;HEBREW LETTER PE;Lo;0;R;;;;;N;;;;;
+05E5;HEBREW LETTER FINAL TSADI;Lo;0;R;;;;;N;;;;;
+05E6;HEBREW LETTER TSADI;Lo;0;R;;;;;N;;;;;
+05E7;HEBREW LETTER QOF;Lo;0;R;;;;;N;;;;;
+05E8;HEBREW LETTER RESH;Lo;0;R;;;;;N;;;;;
+05E9;HEBREW LETTER SHIN;Lo;0;R;;;;;N;;;;;
+05EA;HEBREW LETTER TAV;Lo;0;R;;;;;N;;;;;
+05F0;HEBREW LIGATURE YIDDISH DOUBLE VAV;Lo;0;R;;;;;N;HEBREW LETTER DOUBLE VAV;;;;
+05F1;HEBREW LIGATURE YIDDISH VAV YOD;Lo;0;R;;;;;N;HEBREW LETTER VAV YOD;;;;
+05F2;HEBREW LIGATURE YIDDISH DOUBLE YOD;Lo;0;R;;;;;N;HEBREW LETTER DOUBLE YOD;;;;
+05F3;HEBREW PUNCTUATION GERESH;Po;0;R;;;;;N;;;;;
+05F4;HEBREW PUNCTUATION GERSHAYIM;Po;0;R;;;;;N;;;;;
+060C;ARABIC COMMA;Po;0;CS;;;;;N;;;;;
+061B;ARABIC SEMICOLON;Po;0;AL;;;;;N;;;;;
+061F;ARABIC QUESTION MARK;Po;0;AL;;;;;N;;;;;
+0621;ARABIC LETTER HAMZA;Lo;0;AL;;;;;N;ARABIC LETTER HAMZAH;;;;
+0622;ARABIC LETTER ALEF WITH MADDA ABOVE;Lo;0;AL;0627 0653;;;;N;ARABIC LETTER MADDAH ON ALEF;;;;
+0623;ARABIC LETTER ALEF WITH HAMZA ABOVE;Lo;0;AL;0627 0654;;;;N;ARABIC LETTER HAMZAH ON ALEF;;;;
+0624;ARABIC LETTER WAW WITH HAMZA ABOVE;Lo;0;AL;0648 0654;;;;N;ARABIC LETTER HAMZAH ON WAW;;;;
+0625;ARABIC LETTER ALEF WITH HAMZA BELOW;Lo;0;AL;0627 0655;;;;N;ARABIC LETTER HAMZAH UNDER ALEF;;;;
+0626;ARABIC LETTER YEH WITH HAMZA ABOVE;Lo;0;AL;064A 0654;;;;N;ARABIC LETTER HAMZAH ON YA;;;;
+0627;ARABIC LETTER ALEF;Lo;0;AL;;;;;N;;;;;
+0628;ARABIC LETTER BEH;Lo;0;AL;;;;;N;ARABIC LETTER BAA;;;;
+0629;ARABIC LETTER TEH MARBUTA;Lo;0;AL;;;;;N;ARABIC LETTER TAA MARBUTAH;;;;
+062A;ARABIC LETTER TEH;Lo;0;AL;;;;;N;ARABIC LETTER TAA;;;;
+062B;ARABIC LETTER THEH;Lo;0;AL;;;;;N;ARABIC LETTER THAA;;;;
+062C;ARABIC LETTER JEEM;Lo;0;AL;;;;;N;;;;;
+062D;ARABIC LETTER HAH;Lo;0;AL;;;;;N;ARABIC LETTER HAA;;;;
+062E;ARABIC LETTER KHAH;Lo;0;AL;;;;;N;ARABIC LETTER KHAA;;;;
+062F;ARABIC LETTER DAL;Lo;0;AL;;;;;N;;;;;
+0630;ARABIC LETTER THAL;Lo;0;AL;;;;;N;;;;;
+0631;ARABIC LETTER REH;Lo;0;AL;;;;;N;ARABIC LETTER RA;;;;
+0632;ARABIC LETTER ZAIN;Lo;0;AL;;;;;N;;;;;
+0633;ARABIC LETTER SEEN;Lo;0;AL;;;;;N;;;;;
+0634;ARABIC LETTER SHEEN;Lo;0;AL;;;;;N;;;;;
+0635;ARABIC LETTER SAD;Lo;0;AL;;;;;N;;;;;
+0636;ARABIC LETTER DAD;Lo;0;AL;;;;;N;;;;;
+0637;ARABIC LETTER TAH;Lo;0;AL;;;;;N;;;;;
+0638;ARABIC LETTER ZAH;Lo;0;AL;;;;;N;ARABIC LETTER DHAH;;;;
+0639;ARABIC LETTER AIN;Lo;0;AL;;;;;N;;;;;
+063A;ARABIC LETTER GHAIN;Lo;0;AL;;;;;N;;;;;
+0640;ARABIC TATWEEL;Lm;0;AL;;;;;N;;;;;
+0641;ARABIC LETTER FEH;Lo;0;AL;;;;;N;ARABIC LETTER FA;;;;
+0642;ARABIC LETTER QAF;Lo;0;AL;;;;;N;;;;;
+0643;ARABIC LETTER KAF;Lo;0;AL;;;;;N;ARABIC LETTER CAF;;;;
+0644;ARABIC LETTER LAM;Lo;0;AL;;;;;N;;;;;
+0645;ARABIC LETTER MEEM;Lo;0;AL;;;;;N;;;;;
+0646;ARABIC LETTER NOON;Lo;0;AL;;;;;N;;;;;
+0647;ARABIC LETTER HEH;Lo;0;AL;;;;;N;ARABIC LETTER HA;;;;
+0648;ARABIC LETTER WAW;Lo;0;AL;;;;;N;;;;;
+0649;ARABIC LETTER ALEF MAKSURA;Lo;0;AL;;;;;N;ARABIC LETTER ALEF MAQSURAH;;;;
+064A;ARABIC LETTER YEH;Lo;0;AL;;;;;N;ARABIC LETTER YA;;;;
+064B;ARABIC FATHATAN;Mn;27;NSM;;;;;N;;;;;
+064C;ARABIC DAMMATAN;Mn;28;NSM;;;;;N;;;;;
+064D;ARABIC KASRATAN;Mn;29;NSM;;;;;N;;;;;
+064E;ARABIC FATHA;Mn;30;NSM;;;;;N;ARABIC FATHAH;;;;
+064F;ARABIC DAMMA;Mn;31;NSM;;;;;N;ARABIC DAMMAH;;;;
+0650;ARABIC KASRA;Mn;32;NSM;;;;;N;ARABIC KASRAH;;;;
+0651;ARABIC SHADDA;Mn;33;NSM;;;;;N;ARABIC SHADDAH;;;;
+0652;ARABIC SUKUN;Mn;34;NSM;;;;;N;;;;;
+0653;ARABIC MADDAH ABOVE;Mn;230;NSM;;;;;N;;;;;
+0654;ARABIC HAMZA ABOVE;Mn;230;NSM;;;;;N;;;;;
+0655;ARABIC HAMZA BELOW;Mn;220;NSM;;;;;N;;;;;
+0660;ARABIC-INDIC DIGIT ZERO;Nd;0;AN;;0;0;0;N;;;;;
+0661;ARABIC-INDIC DIGIT ONE;Nd;0;AN;;1;1;1;N;;;;;
+0662;ARABIC-INDIC DIGIT TWO;Nd;0;AN;;2;2;2;N;;;;;
+0663;ARABIC-INDIC DIGIT THREE;Nd;0;AN;;3;3;3;N;;;;;
+0664;ARABIC-INDIC DIGIT FOUR;Nd;0;AN;;4;4;4;N;;;;;
+0665;ARABIC-INDIC DIGIT FIVE;Nd;0;AN;;5;5;5;N;;;;;
+0666;ARABIC-INDIC DIGIT SIX;Nd;0;AN;;6;6;6;N;;;;;
+0667;ARABIC-INDIC DIGIT SEVEN;Nd;0;AN;;7;7;7;N;;;;;
+0668;ARABIC-INDIC DIGIT EIGHT;Nd;0;AN;;8;8;8;N;;;;;
+0669;ARABIC-INDIC DIGIT NINE;Nd;0;AN;;9;9;9;N;;;;;
+066A;ARABIC PERCENT SIGN;Po;0;ET;;;;;N;;;;;
+066B;ARABIC DECIMAL SEPARATOR;Po;0;AN;;;;;N;;;;;
+066C;ARABIC THOUSANDS SEPARATOR;Po;0;AN;;;;;N;;;;;
+066D;ARABIC FIVE POINTED STAR;Po;0;AL;;;;;N;;;;;
+0670;ARABIC LETTER SUPERSCRIPT ALEF;Mn;35;NSM;;;;;N;ARABIC ALEF ABOVE;;;;
+0671;ARABIC LETTER ALEF WASLA;Lo;0;AL;;;;;N;ARABIC LETTER HAMZAT WASL ON ALEF;;;;
+0672;ARABIC LETTER ALEF WITH WAVY HAMZA ABOVE;Lo;0;AL;;;;;N;ARABIC LETTER WAVY HAMZAH ON ALEF;;;;
+0673;ARABIC LETTER ALEF WITH WAVY HAMZA BELOW;Lo;0;AL;;;;;N;ARABIC LETTER WAVY HAMZAH UNDER ALEF;;;;
+0674;ARABIC LETTER HIGH HAMZA;Lo;0;AL;;;;;N;ARABIC LETTER HIGH HAMZAH;;;;
+0675;ARABIC LETTER HIGH HAMZA ALEF;Lo;0;AL;<compat> 0627 0674;;;;N;ARABIC LETTER HIGH HAMZAH ALEF;;;;
+0676;ARABIC LETTER HIGH HAMZA WAW;Lo;0;AL;<compat> 0648 0674;;;;N;ARABIC LETTER HIGH HAMZAH WAW;;;;
+0677;ARABIC LETTER U WITH HAMZA ABOVE;Lo;0;AL;<compat> 06C7 0674;;;;N;ARABIC LETTER HIGH HAMZAH WAW WITH DAMMAH;;;;
+0678;ARABIC LETTER HIGH HAMZA YEH;Lo;0;AL;<compat> 064A 0674;;;;N;ARABIC LETTER HIGH HAMZAH YA;;;;
+0679;ARABIC LETTER TTEH;Lo;0;AL;;;;;N;ARABIC LETTER TAA WITH SMALL TAH;;;;
+067A;ARABIC LETTER TTEHEH;Lo;0;AL;;;;;N;ARABIC LETTER TAA WITH TWO DOTS VERTICAL ABOVE;;;;
+067B;ARABIC LETTER BEEH;Lo;0;AL;;;;;N;ARABIC LETTER BAA WITH TWO DOTS VERTICAL BELOW;;;;
+067C;ARABIC LETTER TEH WITH RING;Lo;0;AL;;;;;N;ARABIC LETTER TAA WITH RING;;;;
+067D;ARABIC LETTER TEH WITH THREE DOTS ABOVE DOWNWARDS;Lo;0;AL;;;;;N;ARABIC LETTER TAA WITH THREE DOTS ABOVE DOWNWARD;;;;
+067E;ARABIC LETTER PEH;Lo;0;AL;;;;;N;ARABIC LETTER TAA WITH THREE DOTS BELOW;;;;
+067F;ARABIC LETTER TEHEH;Lo;0;AL;;;;;N;ARABIC LETTER TAA WITH FOUR DOTS ABOVE;;;;
+0680;ARABIC LETTER BEHEH;Lo;0;AL;;;;;N;ARABIC LETTER BAA WITH FOUR DOTS BELOW;;;;
+0681;ARABIC LETTER HAH WITH HAMZA ABOVE;Lo;0;AL;;;;;N;ARABIC LETTER HAMZAH ON HAA;;;;
+0682;ARABIC LETTER HAH WITH TWO DOTS VERTICAL ABOVE;Lo;0;AL;;;;;N;ARABIC LETTER HAA WITH TWO DOTS VERTICAL ABOVE;;;;
+0683;ARABIC LETTER NYEH;Lo;0;AL;;;;;N;ARABIC LETTER HAA WITH MIDDLE TWO DOTS;;;;
+0684;ARABIC LETTER DYEH;Lo;0;AL;;;;;N;ARABIC LETTER HAA WITH MIDDLE TWO DOTS VERTICAL;;;;
+0685;ARABIC LETTER HAH WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;ARABIC LETTER HAA WITH THREE DOTS ABOVE;;;;
+0686;ARABIC LETTER TCHEH;Lo;0;AL;;;;;N;ARABIC LETTER HAA WITH MIDDLE THREE DOTS DOWNWARD;;;;
+0687;ARABIC LETTER TCHEHEH;Lo;0;AL;;;;;N;ARABIC LETTER HAA WITH MIDDLE FOUR DOTS;;;;
+0688;ARABIC LETTER DDAL;Lo;0;AL;;;;;N;ARABIC LETTER DAL WITH SMALL TAH;;;;
+0689;ARABIC LETTER DAL WITH RING;Lo;0;AL;;;;;N;;;;;
+068A;ARABIC LETTER DAL WITH DOT BELOW;Lo;0;AL;;;;;N;;;;;
+068B;ARABIC LETTER DAL WITH DOT BELOW AND SMALL TAH;Lo;0;AL;;;;;N;;;;;
+068C;ARABIC LETTER DAHAL;Lo;0;AL;;;;;N;ARABIC LETTER DAL WITH TWO DOTS ABOVE;;;;
+068D;ARABIC LETTER DDAHAL;Lo;0;AL;;;;;N;ARABIC LETTER DAL WITH TWO DOTS BELOW;;;;
+068E;ARABIC LETTER DUL;Lo;0;AL;;;;;N;ARABIC LETTER DAL WITH THREE DOTS ABOVE;;;;
+068F;ARABIC LETTER DAL WITH THREE DOTS ABOVE DOWNWARDS;Lo;0;AL;;;;;N;ARABIC LETTER DAL WITH THREE DOTS ABOVE DOWNWARD;;;;
+0690;ARABIC LETTER DAL WITH FOUR DOTS ABOVE;Lo;0;AL;;;;;N;;;;;
+0691;ARABIC LETTER RREH;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH SMALL TAH;;;;
+0692;ARABIC LETTER REH WITH SMALL V;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH SMALL V;;;;
+0693;ARABIC LETTER REH WITH RING;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH RING;;;;
+0694;ARABIC LETTER REH WITH DOT BELOW;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH DOT BELOW;;;;
+0695;ARABIC LETTER REH WITH SMALL V BELOW;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH SMALL V BELOW;;;;
+0696;ARABIC LETTER REH WITH DOT BELOW AND DOT ABOVE;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH DOT BELOW AND DOT ABOVE;;;;
+0697;ARABIC LETTER REH WITH TWO DOTS ABOVE;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH TWO DOTS ABOVE;;;;
+0698;ARABIC LETTER JEH;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH THREE DOTS ABOVE;;;;
+0699;ARABIC LETTER REH WITH FOUR DOTS ABOVE;Lo;0;AL;;;;;N;ARABIC LETTER RA WITH FOUR DOTS ABOVE;;;;
+069A;ARABIC LETTER SEEN WITH DOT BELOW AND DOT ABOVE;Lo;0;AL;;;;;N;;;;;
+069B;ARABIC LETTER SEEN WITH THREE DOTS BELOW;Lo;0;AL;;;;;N;;;;;
+069C;ARABIC LETTER SEEN WITH THREE DOTS BELOW AND THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;;
+069D;ARABIC LETTER SAD WITH TWO DOTS BELOW;Lo;0;AL;;;;;N;;;;;
+069E;ARABIC LETTER SAD WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;;
+069F;ARABIC LETTER TAH WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;;
+06A0;ARABIC LETTER AIN WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;;
+06A1;ARABIC LETTER DOTLESS FEH;Lo;0;AL;;;;;N;ARABIC LETTER DOTLESS FA;;;;
+06A2;ARABIC LETTER FEH WITH DOT MOVED BELOW;Lo;0;AL;;;;;N;ARABIC LETTER FA WITH DOT MOVED BELOW;;;;
+06A3;ARABIC LETTER FEH WITH DOT BELOW;Lo;0;AL;;;;;N;ARABIC LETTER FA WITH DOT BELOW;;;;
+06A4;ARABIC LETTER VEH;Lo;0;AL;;;;;N;ARABIC LETTER FA WITH THREE DOTS ABOVE;;;;
+06A5;ARABIC LETTER FEH WITH THREE DOTS BELOW;Lo;0;AL;;;;;N;ARABIC LETTER FA WITH THREE DOTS BELOW;;;;
+06A6;ARABIC LETTER PEHEH;Lo;0;AL;;;;;N;ARABIC LETTER FA WITH FOUR DOTS ABOVE;;;;
+06A7;ARABIC LETTER QAF WITH DOT ABOVE;Lo;0;AL;;;;;N;;;;;
+06A8;ARABIC LETTER QAF WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;;
+06A9;ARABIC LETTER KEHEH;Lo;0;AL;;;;;N;ARABIC LETTER OPEN CAF;;;;
+06AA;ARABIC LETTER SWASH KAF;Lo;0;AL;;;;;N;ARABIC LETTER SWASH CAF;;;;
+06AB;ARABIC LETTER KAF WITH RING;Lo;0;AL;;;;;N;ARABIC LETTER CAF WITH RING;;;;
+06AC;ARABIC LETTER KAF WITH DOT ABOVE;Lo;0;AL;;;;;N;ARABIC LETTER CAF WITH DOT ABOVE;;;;
+06AD;ARABIC LETTER NG;Lo;0;AL;;;;;N;ARABIC LETTER CAF WITH THREE DOTS ABOVE;;;;
+06AE;ARABIC LETTER KAF WITH THREE DOTS BELOW;Lo;0;AL;;;;;N;ARABIC LETTER CAF WITH THREE DOTS BELOW;;;;
+06AF;ARABIC LETTER GAF;Lo;0;AL;;;;;N;;*;;;
+06B0;ARABIC LETTER GAF WITH RING;Lo;0;AL;;;;;N;;;;;
+06B1;ARABIC LETTER NGOEH;Lo;0;AL;;;;;N;ARABIC LETTER GAF WITH TWO DOTS ABOVE;;;;
+06B2;ARABIC LETTER GAF WITH TWO DOTS BELOW;Lo;0;AL;;;;;N;;;;;
+06B3;ARABIC LETTER GUEH;Lo;0;AL;;;;;N;ARABIC LETTER GAF WITH TWO DOTS VERTICAL BELOW;;;;
+06B4;ARABIC LETTER GAF WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;;
+06B5;ARABIC LETTER LAM WITH SMALL V;Lo;0;AL;;;;;N;;;;;
+06B6;ARABIC LETTER LAM WITH DOT ABOVE;Lo;0;AL;;;;;N;;;;;
+06B7;ARABIC LETTER LAM WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;;
+06B8;ARABIC LETTER LAM WITH THREE DOTS BELOW;Lo;0;AL;;;;;N;;;;;
+06B9;ARABIC LETTER NOON WITH DOT BELOW;Lo;0;AL;;;;;N;;;;;
+06BA;ARABIC LETTER NOON GHUNNA;Lo;0;AL;;;;;N;ARABIC LETTER DOTLESS NOON;;;;
+06BB;ARABIC LETTER RNOON;Lo;0;AL;;;;;N;ARABIC LETTER DOTLESS NOON WITH SMALL TAH;;;;
+06BC;ARABIC LETTER NOON WITH RING;Lo;0;AL;;;;;N;;;;;
+06BD;ARABIC LETTER NOON WITH THREE DOTS ABOVE;Lo;0;AL;;;;;N;;;;;
+06BE;ARABIC LETTER HEH DOACHASHMEE;Lo;0;AL;;;;;N;ARABIC LETTER KNOTTED HA;;;;
+06BF;ARABIC LETTER TCHEH WITH DOT ABOVE;Lo;0;AL;;;;;N;;;;;
+06C0;ARABIC LETTER HEH WITH YEH ABOVE;Lo;0;AL;06D5 0654;;;;N;ARABIC LETTER HAMZAH ON HA;;;;
+06C1;ARABIC LETTER HEH GOAL;Lo;0;AL;;;;;N;ARABIC LETTER HA GOAL;;;;
+06C2;ARABIC LETTER HEH GOAL WITH HAMZA ABOVE;Lo;0;AL;06C1 0654;;;;N;ARABIC LETTER HAMZAH ON HA GOAL;;;;
+06C3;ARABIC LETTER TEH MARBUTA GOAL;Lo;0;AL;;;;;N;ARABIC LETTER TAA MARBUTAH GOAL;;;;
+06C4;ARABIC LETTER WAW WITH RING;Lo;0;AL;;;;;N;;;;;
+06C5;ARABIC LETTER KIRGHIZ OE;Lo;0;AL;;;;;N;ARABIC LETTER WAW WITH BAR;;;;
+06C6;ARABIC LETTER OE;Lo;0;AL;;;;;N;ARABIC LETTER WAW WITH SMALL V;;;;
+06C7;ARABIC LETTER U;Lo;0;AL;;;;;N;ARABIC LETTER WAW WITH DAMMAH;;;;
+06C8;ARABIC LETTER YU;Lo;0;AL;;;;;N;ARABIC LETTER WAW WITH ALEF ABOVE;;;;
+06C9;ARABIC LETTER KIRGHIZ YU;Lo;0;AL;;;;;N;ARABIC LETTER WAW WITH INVERTED SMALL V;;;;
+06CA;ARABIC LETTER WAW WITH TWO DOTS ABOVE;Lo;0;AL;;;;;N;;;;;
+06CB;ARABIC LETTER VE;Lo;0;AL;;;;;N;ARABIC LETTER WAW WITH THREE DOTS ABOVE;;;;
+06CC;ARABIC LETTER FARSI YEH;Lo;0;AL;;;;;N;ARABIC LETTER DOTLESS YA;;;;
+06CD;ARABIC LETTER YEH WITH TAIL;Lo;0;AL;;;;;N;ARABIC LETTER YA WITH TAIL;;;;
+06CE;ARABIC LETTER YEH WITH SMALL V;Lo;0;AL;;;;;N;ARABIC LETTER YA WITH SMALL V;;;;
+06CF;ARABIC LETTER WAW WITH DOT ABOVE;Lo;0;AL;;;;;N;;;;;
+06D0;ARABIC LETTER E;Lo;0;AL;;;;;N;ARABIC LETTER YA WITH TWO DOTS VERTICAL BELOW;*;;;
+06D1;ARABIC LETTER YEH WITH THREE DOTS BELOW;Lo;0;AL;;;;;N;ARABIC LETTER YA WITH THREE DOTS BELOW;;;;
+06D2;ARABIC LETTER YEH BARREE;Lo;0;AL;;;;;N;ARABIC LETTER YA BARREE;;;;
+06D3;ARABIC LETTER YEH BARREE WITH HAMZA ABOVE;Lo;0;AL;06D2 0654;;;;N;ARABIC LETTER HAMZAH ON YA BARREE;;;;
+06D4;ARABIC FULL STOP;Po;0;AL;;;;;N;ARABIC PERIOD;;;;
+06D5;ARABIC LETTER AE;Lo;0;AL;;;;;N;;;;;
+06D6;ARABIC SMALL HIGH LIGATURE SAD WITH LAM WITH ALEF MAKSURA;Mn;230;NSM;;;;;N;;;;;
+06D7;ARABIC SMALL HIGH LIGATURE QAF WITH LAM WITH ALEF MAKSURA;Mn;230;NSM;;;;;N;;;;;
+06D8;ARABIC SMALL HIGH MEEM INITIAL FORM;Mn;230;NSM;;;;;N;;;;;
+06D9;ARABIC SMALL HIGH LAM ALEF;Mn;230;NSM;;;;;N;;;;;
+06DA;ARABIC SMALL HIGH JEEM;Mn;230;NSM;;;;;N;;;;;
+06DB;ARABIC SMALL HIGH THREE DOTS;Mn;230;NSM;;;;;N;;;;;
+06DC;ARABIC SMALL HIGH SEEN;Mn;230;NSM;;;;;N;;;;;
+06DD;ARABIC END OF AYAH;Me;0;NSM;;;;;N;;;;;
+06DE;ARABIC START OF RUB EL HIZB;Me;0;NSM;;;;;N;;;;;
+06DF;ARABIC SMALL HIGH ROUNDED ZERO;Mn;230;NSM;;;;;N;;;;;
+06E0;ARABIC SMALL HIGH UPRIGHT RECTANGULAR ZERO;Mn;230;NSM;;;;;N;;;;;
+06E1;ARABIC SMALL HIGH DOTLESS HEAD OF KHAH;Mn;230;NSM;;;;;N;;;;;
+06E2;ARABIC SMALL HIGH MEEM ISOLATED FORM;Mn;230;NSM;;;;;N;;;;;
+06E3;ARABIC SMALL LOW SEEN;Mn;220;NSM;;;;;N;;;;;
+06E4;ARABIC SMALL HIGH MADDA;Mn;230;NSM;;;;;N;;;;;
+06E5;ARABIC SMALL WAW;Lm;0;AL;;;;;N;;;;;
+06E6;ARABIC SMALL YEH;Lm;0;AL;;;;;N;;;;;
+06E7;ARABIC SMALL HIGH YEH;Mn;230;NSM;;;;;N;;;;;
+06E8;ARABIC SMALL HIGH NOON;Mn;230;NSM;;;;;N;;;;;
+06E9;ARABIC PLACE OF SAJDAH;So;0;ON;;;;;N;;;;;
+06EA;ARABIC EMPTY CENTRE LOW STOP;Mn;220;NSM;;;;;N;;;;;
+06EB;ARABIC EMPTY CENTRE HIGH STOP;Mn;230;NSM;;;;;N;;;;;
+06EC;ARABIC ROUNDED HIGH STOP WITH FILLED CENTRE;Mn;230;NSM;;;;;N;;;;;
+06ED;ARABIC SMALL LOW MEEM;Mn;220;NSM;;;;;N;;;;;
+06F0;EXTENDED ARABIC-INDIC DIGIT ZERO;Nd;0;EN;;0;0;0;N;EASTERN ARABIC-INDIC DIGIT ZERO;;;;
+06F1;EXTENDED ARABIC-INDIC DIGIT ONE;Nd;0;EN;;1;1;1;N;EASTERN ARABIC-INDIC DIGIT ONE;;;;
+06F2;EXTENDED ARABIC-INDIC DIGIT TWO;Nd;0;EN;;2;2;2;N;EASTERN ARABIC-INDIC DIGIT TWO;;;;
+06F3;EXTENDED ARABIC-INDIC DIGIT THREE;Nd;0;EN;;3;3;3;N;EASTERN ARABIC-INDIC DIGIT THREE;;;;
+06F4;EXTENDED ARABIC-INDIC DIGIT FOUR;Nd;0;EN;;4;4;4;N;EASTERN ARABIC-INDIC DIGIT FOUR;;;;
+06F5;EXTENDED ARABIC-INDIC DIGIT FIVE;Nd;0;EN;;5;5;5;N;EASTERN ARABIC-INDIC DIGIT FIVE;;;;
+06F6;EXTENDED ARABIC-INDIC DIGIT SIX;Nd;0;EN;;6;6;6;N;EASTERN ARABIC-INDIC DIGIT SIX;;;;
+06F7;EXTENDED ARABIC-INDIC DIGIT SEVEN;Nd;0;EN;;7;7;7;N;EASTERN ARABIC-INDIC DIGIT SEVEN;;;;
+06F8;EXTENDED ARABIC-INDIC DIGIT EIGHT;Nd;0;EN;;8;8;8;N;EASTERN ARABIC-INDIC DIGIT EIGHT;;;;
+06F9;EXTENDED ARABIC-INDIC DIGIT NINE;Nd;0;EN;;9;9;9;N;EASTERN ARABIC-INDIC DIGIT NINE;;;;
+06FA;ARABIC LETTER SHEEN WITH DOT BELOW;Lo;0;AL;;;;;N;;;;;
+06FB;ARABIC LETTER DAD WITH DOT BELOW;Lo;0;AL;;;;;N;;;;;
+06FC;ARABIC LETTER GHAIN WITH DOT BELOW;Lo;0;AL;;;;;N;;;;;
+06FD;ARABIC SIGN SINDHI AMPERSAND;So;0;AL;;;;;N;;;;;
+06FE;ARABIC SIGN SINDHI POSTPOSITION MEN;So;0;AL;;;;;N;;;;;
+0700;SYRIAC END OF PARAGRAPH;Po;0;AL;;;;;N;;;;;
+0701;SYRIAC SUPRALINEAR FULL STOP;Po;0;AL;;;;;N;;;;;
+0702;SYRIAC SUBLINEAR FULL STOP;Po;0;AL;;;;;N;;;;;
+0703;SYRIAC SUPRALINEAR COLON;Po;0;AL;;;;;N;;;;;
+0704;SYRIAC SUBLINEAR COLON;Po;0;AL;;;;;N;;;;;
+0705;SYRIAC HORIZONTAL COLON;Po;0;AL;;;;;N;;;;;
+0706;SYRIAC COLON SKEWED LEFT;Po;0;AL;;;;;N;;;;;
+0707;SYRIAC COLON SKEWED RIGHT;Po;0;AL;;;;;N;;;;;
+0708;SYRIAC SUPRALINEAR COLON SKEWED LEFT;Po;0;AL;;;;;N;;;;;
+0709;SYRIAC SUBLINEAR COLON SKEWED RIGHT;Po;0;AL;;;;;N;;;;;
+070A;SYRIAC CONTRACTION;Po;0;AL;;;;;N;;;;;
+070B;SYRIAC HARKLEAN OBELUS;Po;0;AL;;;;;N;;;;;
+070C;SYRIAC HARKLEAN METOBELUS;Po;0;AL;;;;;N;;;;;
+070D;SYRIAC HARKLEAN ASTERISCUS;Po;0;AL;;;;;N;;;;;
+070F;SYRIAC ABBREVIATION MARK;Cf;0;BN;;;;;N;;;;;
+0710;SYRIAC LETTER ALAPH;Lo;0;AL;;;;;N;;;;;
+0711;SYRIAC LETTER SUPERSCRIPT ALAPH;Mn;36;NSM;;;;;N;;;;;
+0712;SYRIAC LETTER BETH;Lo;0;AL;;;;;N;;;;;
+0713;SYRIAC LETTER GAMAL;Lo;0;AL;;;;;N;;;;;
+0714;SYRIAC LETTER GAMAL GARSHUNI;Lo;0;AL;;;;;N;;;;;
+0715;SYRIAC LETTER DALATH;Lo;0;AL;;;;;N;;;;;
+0716;SYRIAC LETTER DOTLESS DALATH RISH;Lo;0;AL;;;;;N;;;;;
+0717;SYRIAC LETTER HE;Lo;0;AL;;;;;N;;;;;
+0718;SYRIAC LETTER WAW;Lo;0;AL;;;;;N;;;;;
+0719;SYRIAC LETTER ZAIN;Lo;0;AL;;;;;N;;;;;
+071A;SYRIAC LETTER HETH;Lo;0;AL;;;;;N;;;;;
+071B;SYRIAC LETTER TETH;Lo;0;AL;;;;;N;;;;;
+071C;SYRIAC LETTER TETH GARSHUNI;Lo;0;AL;;;;;N;;;;;
+071D;SYRIAC LETTER YUDH;Lo;0;AL;;;;;N;;;;;
+071E;SYRIAC LETTER YUDH HE;Lo;0;AL;;;;;N;;;;;
+071F;SYRIAC LETTER KAPH;Lo;0;AL;;;;;N;;;;;
+0720;SYRIAC LETTER LAMADH;Lo;0;AL;;;;;N;;;;;
+0721;SYRIAC LETTER MIM;Lo;0;AL;;;;;N;;;;;
+0722;SYRIAC LETTER NUN;Lo;0;AL;;;;;N;;;;;
+0723;SYRIAC LETTER SEMKATH;Lo;0;AL;;;;;N;;;;;
+0724;SYRIAC LETTER FINAL SEMKATH;Lo;0;AL;;;;;N;;;;;
+0725;SYRIAC LETTER E;Lo;0;AL;;;;;N;;;;;
+0726;SYRIAC LETTER PE;Lo;0;AL;;;;;N;;;;;
+0727;SYRIAC LETTER REVERSED PE;Lo;0;AL;;;;;N;;;;;
+0728;SYRIAC LETTER SADHE;Lo;0;AL;;;;;N;;;;;
+0729;SYRIAC LETTER QAPH;Lo;0;AL;;;;;N;;;;;
+072A;SYRIAC LETTER RISH;Lo;0;AL;;;;;N;;;;;
+072B;SYRIAC LETTER SHIN;Lo;0;AL;;;;;N;;;;;
+072C;SYRIAC LETTER TAW;Lo;0;AL;;;;;N;;;;;
+0730;SYRIAC PTHAHA ABOVE;Mn;230;NSM;;;;;N;;;;;
+0731;SYRIAC PTHAHA BELOW;Mn;220;NSM;;;;;N;;;;;
+0732;SYRIAC PTHAHA DOTTED;Mn;230;NSM;;;;;N;;;;;
+0733;SYRIAC ZQAPHA ABOVE;Mn;230;NSM;;;;;N;;;;;
+0734;SYRIAC ZQAPHA BELOW;Mn;220;NSM;;;;;N;;;;;
+0735;SYRIAC ZQAPHA DOTTED;Mn;230;NSM;;;;;N;;;;;
+0736;SYRIAC RBASA ABOVE;Mn;230;NSM;;;;;N;;;;;
+0737;SYRIAC RBASA BELOW;Mn;220;NSM;;;;;N;;;;;
+0738;SYRIAC DOTTED ZLAMA HORIZONTAL;Mn;220;NSM;;;;;N;;;;;
+0739;SYRIAC DOTTED ZLAMA ANGULAR;Mn;220;NSM;;;;;N;;;;;
+073A;SYRIAC HBASA ABOVE;Mn;230;NSM;;;;;N;;;;;
+073B;SYRIAC HBASA BELOW;Mn;220;NSM;;;;;N;;;;;
+073C;SYRIAC HBASA-ESASA DOTTED;Mn;220;NSM;;;;;N;;;;;
+073D;SYRIAC ESASA ABOVE;Mn;230;NSM;;;;;N;;;;;
+073E;SYRIAC ESASA BELOW;Mn;220;NSM;;;;;N;;;;;
+073F;SYRIAC RWAHA;Mn;230;NSM;;;;;N;;;;;
+0740;SYRIAC FEMININE DOT;Mn;230;NSM;;;;;N;;;;;
+0741;SYRIAC QUSHSHAYA;Mn;230;NSM;;;;;N;;;;;
+0742;SYRIAC RUKKAKHA;Mn;220;NSM;;;;;N;;;;;
+0743;SYRIAC TWO VERTICAL DOTS ABOVE;Mn;230;NSM;;;;;N;;;;;
+0744;SYRIAC TWO VERTICAL DOTS BELOW;Mn;220;NSM;;;;;N;;;;;
+0745;SYRIAC THREE DOTS ABOVE;Mn;230;NSM;;;;;N;;;;;
+0746;SYRIAC THREE DOTS BELOW;Mn;220;NSM;;;;;N;;;;;
+0747;SYRIAC OBLIQUE LINE ABOVE;Mn;230;NSM;;;;;N;;;;;
+0748;SYRIAC OBLIQUE LINE BELOW;Mn;220;NSM;;;;;N;;;;;
+0749;SYRIAC MUSIC;Mn;230;NSM;;;;;N;;;;;
+074A;SYRIAC BARREKH;Mn;230;NSM;;;;;N;;;;;
+0780;THAANA LETTER HAA;Lo;0;AL;;;;;N;;;;;
+0781;THAANA LETTER SHAVIYANI;Lo;0;AL;;;;;N;;;;;
+0782;THAANA LETTER NOONU;Lo;0;AL;;;;;N;;;;;
+0783;THAANA LETTER RAA;Lo;0;AL;;;;;N;;;;;
+0784;THAANA LETTER BAA;Lo;0;AL;;;;;N;;;;;
+0785;THAANA LETTER LHAVIYANI;Lo;0;AL;;;;;N;;;;;
+0786;THAANA LETTER KAAFU;Lo;0;AL;;;;;N;;;;;
+0787;THAANA LETTER ALIFU;Lo;0;AL;;;;;N;;;;;
+0788;THAANA LETTER VAAVU;Lo;0;AL;;;;;N;;;;;
+0789;THAANA LETTER MEEMU;Lo;0;AL;;;;;N;;;;;
+078A;THAANA LETTER FAAFU;Lo;0;AL;;;;;N;;;;;
+078B;THAANA LETTER DHAALU;Lo;0;AL;;;;;N;;;;;
+078C;THAANA LETTER THAA;Lo;0;AL;;;;;N;;;;;
+078D;THAANA LETTER LAAMU;Lo;0;AL;;;;;N;;;;;
+078E;THAANA LETTER GAAFU;Lo;0;AL;;;;;N;;;;;
+078F;THAANA LETTER GNAVIYANI;Lo;0;AL;;;;;N;;;;;
+0790;THAANA LETTER SEENU;Lo;0;AL;;;;;N;;;;;
+0791;THAANA LETTER DAVIYANI;Lo;0;AL;;;;;N;;;;;
+0792;THAANA LETTER ZAVIYANI;Lo;0;AL;;;;;N;;;;;
+0793;THAANA LETTER TAVIYANI;Lo;0;AL;;;;;N;;;;;
+0794;THAANA LETTER YAA;Lo;0;AL;;;;;N;;;;;
+0795;THAANA LETTER PAVIYANI;Lo;0;AL;;;;;N;;;;;
+0796;THAANA LETTER JAVIYANI;Lo;0;AL;;;;;N;;;;;
+0797;THAANA LETTER CHAVIYANI;Lo;0;AL;;;;;N;;;;;
+0798;THAANA LETTER TTAA;Lo;0;AL;;;;;N;;;;;
+0799;THAANA LETTER HHAA;Lo;0;AL;;;;;N;;;;;
+079A;THAANA LETTER KHAA;Lo;0;AL;;;;;N;;;;;
+079B;THAANA LETTER THAALU;Lo;0;AL;;;;;N;;;;;
+079C;THAANA LETTER ZAA;Lo;0;AL;;;;;N;;;;;
+079D;THAANA LETTER SHEENU;Lo;0;AL;;;;;N;;;;;
+079E;THAANA LETTER SAADHU;Lo;0;AL;;;;;N;;;;;
+079F;THAANA LETTER DAADHU;Lo;0;AL;;;;;N;;;;;
+07A0;THAANA LETTER TO;Lo;0;AL;;;;;N;;;;;
+07A1;THAANA LETTER ZO;Lo;0;AL;;;;;N;;;;;
+07A2;THAANA LETTER AINU;Lo;0;AL;;;;;N;;;;;
+07A3;THAANA LETTER GHAINU;Lo;0;AL;;;;;N;;;;;
+07A4;THAANA LETTER QAAFU;Lo;0;AL;;;;;N;;;;;
+07A5;THAANA LETTER WAAVU;Lo;0;AL;;;;;N;;;;;
+07A6;THAANA ABAFILI;Mn;0;NSM;;;;;N;;;;;
+07A7;THAANA AABAAFILI;Mn;0;NSM;;;;;N;;;;;
+07A8;THAANA IBIFILI;Mn;0;NSM;;;;;N;;;;;
+07A9;THAANA EEBEEFILI;Mn;0;NSM;;;;;N;;;;;
+07AA;THAANA UBUFILI;Mn;0;NSM;;;;;N;;;;;
+07AB;THAANA OOBOOFILI;Mn;0;NSM;;;;;N;;;;;
+07AC;THAANA EBEFILI;Mn;0;NSM;;;;;N;;;;;
+07AD;THAANA EYBEYFILI;Mn;0;NSM;;;;;N;;;;;
+07AE;THAANA OBOFILI;Mn;0;NSM;;;;;N;;;;;
+07AF;THAANA OABOAFILI;Mn;0;NSM;;;;;N;;;;;
+07B0;THAANA SUKUN;Mn;0;NSM;;;;;N;;;;;
+0901;DEVANAGARI SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;;
+0902;DEVANAGARI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;;
+0903;DEVANAGARI SIGN VISARGA;Mc;0;L;;;;;N;;;;;
+0905;DEVANAGARI LETTER A;Lo;0;L;;;;;N;;;;;
+0906;DEVANAGARI LETTER AA;Lo;0;L;;;;;N;;;;;
+0907;DEVANAGARI LETTER I;Lo;0;L;;;;;N;;;;;
+0908;DEVANAGARI LETTER II;Lo;0;L;;;;;N;;;;;
+0909;DEVANAGARI LETTER U;Lo;0;L;;;;;N;;;;;
+090A;DEVANAGARI LETTER UU;Lo;0;L;;;;;N;;;;;
+090B;DEVANAGARI LETTER VOCALIC R;Lo;0;L;;;;;N;;;;;
+090C;DEVANAGARI LETTER VOCALIC L;Lo;0;L;;;;;N;;;;;
+090D;DEVANAGARI LETTER CANDRA E;Lo;0;L;;;;;N;;;;;
+090E;DEVANAGARI LETTER SHORT E;Lo;0;L;;;;;N;;;;;
+090F;DEVANAGARI LETTER E;Lo;0;L;;;;;N;;;;;
+0910;DEVANAGARI LETTER AI;Lo;0;L;;;;;N;;;;;
+0911;DEVANAGARI LETTER CANDRA O;Lo;0;L;;;;;N;;;;;
+0912;DEVANAGARI LETTER SHORT O;Lo;0;L;;;;;N;;;;;
+0913;DEVANAGARI LETTER O;Lo;0;L;;;;;N;;;;;
+0914;DEVANAGARI LETTER AU;Lo;0;L;;;;;N;;;;;
+0915;DEVANAGARI LETTER KA;Lo;0;L;;;;;N;;;;;
+0916;DEVANAGARI LETTER KHA;Lo;0;L;;;;;N;;;;;
+0917;DEVANAGARI LETTER GA;Lo;0;L;;;;;N;;;;;
+0918;DEVANAGARI LETTER GHA;Lo;0;L;;;;;N;;;;;
+0919;DEVANAGARI LETTER NGA;Lo;0;L;;;;;N;;;;;
+091A;DEVANAGARI LETTER CA;Lo;0;L;;;;;N;;;;;
+091B;DEVANAGARI LETTER CHA;Lo;0;L;;;;;N;;;;;
+091C;DEVANAGARI LETTER JA;Lo;0;L;;;;;N;;;;;
+091D;DEVANAGARI LETTER JHA;Lo;0;L;;;;;N;;;;;
+091E;DEVANAGARI LETTER NYA;Lo;0;L;;;;;N;;;;;
+091F;DEVANAGARI LETTER TTA;Lo;0;L;;;;;N;;;;;
+0920;DEVANAGARI LETTER TTHA;Lo;0;L;;;;;N;;;;;
+0921;DEVANAGARI LETTER DDA;Lo;0;L;;;;;N;;;;;
+0922;DEVANAGARI LETTER DDHA;Lo;0;L;;;;;N;;;;;
+0923;DEVANAGARI LETTER NNA;Lo;0;L;;;;;N;;;;;
+0924;DEVANAGARI LETTER TA;Lo;0;L;;;;;N;;;;;
+0925;DEVANAGARI LETTER THA;Lo;0;L;;;;;N;;;;;
+0926;DEVANAGARI LETTER DA;Lo;0;L;;;;;N;;;;;
+0927;DEVANAGARI LETTER DHA;Lo;0;L;;;;;N;;;;;
+0928;DEVANAGARI LETTER NA;Lo;0;L;;;;;N;;;;;
+0929;DEVANAGARI LETTER NNNA;Lo;0;L;0928 093C;;;;N;;;;;
+092A;DEVANAGARI LETTER PA;Lo;0;L;;;;;N;;;;;
+092B;DEVANAGARI LETTER PHA;Lo;0;L;;;;;N;;;;;
+092C;DEVANAGARI LETTER BA;Lo;0;L;;;;;N;;;;;
+092D;DEVANAGARI LETTER BHA;Lo;0;L;;;;;N;;;;;
+092E;DEVANAGARI LETTER MA;Lo;0;L;;;;;N;;;;;
+092F;DEVANAGARI LETTER YA;Lo;0;L;;;;;N;;;;;
+0930;DEVANAGARI LETTER RA;Lo;0;L;;;;;N;;;;;
+0931;DEVANAGARI LETTER RRA;Lo;0;L;0930 093C;;;;N;;;;;
+0932;DEVANAGARI LETTER LA;Lo;0;L;;;;;N;;;;;
+0933;DEVANAGARI LETTER LLA;Lo;0;L;;;;;N;;;;;
+0934;DEVANAGARI LETTER LLLA;Lo;0;L;0933 093C;;;;N;;;;;
+0935;DEVANAGARI LETTER VA;Lo;0;L;;;;;N;;;;;
+0936;DEVANAGARI LETTER SHA;Lo;0;L;;;;;N;;;;;
+0937;DEVANAGARI LETTER SSA;Lo;0;L;;;;;N;;;;;
+0938;DEVANAGARI LETTER SA;Lo;0;L;;;;;N;;;;;
+0939;DEVANAGARI LETTER HA;Lo;0;L;;;;;N;;;;;
+093C;DEVANAGARI SIGN NUKTA;Mn;7;NSM;;;;;N;;;;;
+093D;DEVANAGARI SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;;
+093E;DEVANAGARI VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;
+093F;DEVANAGARI VOWEL SIGN I;Mc;0;L;;;;;N;;;;;
+0940;DEVANAGARI VOWEL SIGN II;Mc;0;L;;;;;N;;;;;
+0941;DEVANAGARI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;
+0942;DEVANAGARI VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;;
+0943;DEVANAGARI VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;;
+0944;DEVANAGARI VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;;
+0945;DEVANAGARI VOWEL SIGN CANDRA E;Mn;0;NSM;;;;;N;;;;;
+0946;DEVANAGARI VOWEL SIGN SHORT E;Mn;0;NSM;;;;;N;;;;;
+0947;DEVANAGARI VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;;
+0948;DEVANAGARI VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;;
+0949;DEVANAGARI VOWEL SIGN CANDRA O;Mc;0;L;;;;;N;;;;;
+094A;DEVANAGARI VOWEL SIGN SHORT O;Mc;0;L;;;;;N;;;;;
+094B;DEVANAGARI VOWEL SIGN O;Mc;0;L;;;;;N;;;;;
+094C;DEVANAGARI VOWEL SIGN AU;Mc;0;L;;;;;N;;;;;
+094D;DEVANAGARI SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;;
+0950;DEVANAGARI OM;Lo;0;L;;;;;N;;;;;
+0951;DEVANAGARI STRESS SIGN UDATTA;Mn;230;NSM;;;;;N;;;;;
+0952;DEVANAGARI STRESS SIGN ANUDATTA;Mn;220;NSM;;;;;N;;;;;
+0953;DEVANAGARI GRAVE ACCENT;Mn;230;NSM;;;;;N;;;;;
+0954;DEVANAGARI ACUTE ACCENT;Mn;230;NSM;;;;;N;;;;;
+0958;DEVANAGARI LETTER QA;Lo;0;L;0915 093C;;;;N;;;;;
+0959;DEVANAGARI LETTER KHHA;Lo;0;L;0916 093C;;;;N;;;;;
+095A;DEVANAGARI LETTER GHHA;Lo;0;L;0917 093C;;;;N;;;;;
+095B;DEVANAGARI LETTER ZA;Lo;0;L;091C 093C;;;;N;;;;;
+095C;DEVANAGARI LETTER DDDHA;Lo;0;L;0921 093C;;;;N;;;;;
+095D;DEVANAGARI LETTER RHA;Lo;0;L;0922 093C;;;;N;;;;;
+095E;DEVANAGARI LETTER FA;Lo;0;L;092B 093C;;;;N;;;;;
+095F;DEVANAGARI LETTER YYA;Lo;0;L;092F 093C;;;;N;;;;;
+0960;DEVANAGARI LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;;
+0961;DEVANAGARI LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;;
+0962;DEVANAGARI VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;;
+0963;DEVANAGARI VOWEL SIGN VOCALIC LL;Mn;0;NSM;;;;;N;;;;;
+0964;DEVANAGARI DANDA;Po;0;L;;;;;N;;;;;
+0965;DEVANAGARI DOUBLE DANDA;Po;0;L;;;;;N;;;;;
+0966;DEVANAGARI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+0967;DEVANAGARI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+0968;DEVANAGARI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+0969;DEVANAGARI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+096A;DEVANAGARI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+096B;DEVANAGARI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+096C;DEVANAGARI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+096D;DEVANAGARI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+096E;DEVANAGARI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+096F;DEVANAGARI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+0970;DEVANAGARI ABBREVIATION SIGN;Po;0;L;;;;;N;;;;;
+0981;BENGALI SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;;
+0982;BENGALI SIGN ANUSVARA;Mc;0;L;;;;;N;;;;;
+0983;BENGALI SIGN VISARGA;Mc;0;L;;;;;N;;;;;
+0985;BENGALI LETTER A;Lo;0;L;;;;;N;;;;;
+0986;BENGALI LETTER AA;Lo;0;L;;;;;N;;;;;
+0987;BENGALI LETTER I;Lo;0;L;;;;;N;;;;;
+0988;BENGALI LETTER II;Lo;0;L;;;;;N;;;;;
+0989;BENGALI LETTER U;Lo;0;L;;;;;N;;;;;
+098A;BENGALI LETTER UU;Lo;0;L;;;;;N;;;;;
+098B;BENGALI LETTER VOCALIC R;Lo;0;L;;;;;N;;;;;
+098C;BENGALI LETTER VOCALIC L;Lo;0;L;;;;;N;;;;;
+098F;BENGALI LETTER E;Lo;0;L;;;;;N;;;;;
+0990;BENGALI LETTER AI;Lo;0;L;;;;;N;;;;;
+0993;BENGALI LETTER O;Lo;0;L;;;;;N;;;;;
+0994;BENGALI LETTER AU;Lo;0;L;;;;;N;;;;;
+0995;BENGALI LETTER KA;Lo;0;L;;;;;N;;;;;
+0996;BENGALI LETTER KHA;Lo;0;L;;;;;N;;;;;
+0997;BENGALI LETTER GA;Lo;0;L;;;;;N;;;;;
+0998;BENGALI LETTER GHA;Lo;0;L;;;;;N;;;;;
+0999;BENGALI LETTER NGA;Lo;0;L;;;;;N;;;;;
+099A;BENGALI LETTER CA;Lo;0;L;;;;;N;;;;;
+099B;BENGALI LETTER CHA;Lo;0;L;;;;;N;;;;;
+099C;BENGALI LETTER JA;Lo;0;L;;;;;N;;;;;
+099D;BENGALI LETTER JHA;Lo;0;L;;;;;N;;;;;
+099E;BENGALI LETTER NYA;Lo;0;L;;;;;N;;;;;
+099F;BENGALI LETTER TTA;Lo;0;L;;;;;N;;;;;
+09A0;BENGALI LETTER TTHA;Lo;0;L;;;;;N;;;;;
+09A1;BENGALI LETTER DDA;Lo;0;L;;;;;N;;;;;
+09A2;BENGALI LETTER DDHA;Lo;0;L;;;;;N;;;;;
+09A3;BENGALI LETTER NNA;Lo;0;L;;;;;N;;;;;
+09A4;BENGALI LETTER TA;Lo;0;L;;;;;N;;;;;
+09A5;BENGALI LETTER THA;Lo;0;L;;;;;N;;;;;
+09A6;BENGALI LETTER DA;Lo;0;L;;;;;N;;;;;
+09A7;BENGALI LETTER DHA;Lo;0;L;;;;;N;;;;;
+09A8;BENGALI LETTER NA;Lo;0;L;;;;;N;;;;;
+09AA;BENGALI LETTER PA;Lo;0;L;;;;;N;;;;;
+09AB;BENGALI LETTER PHA;Lo;0;L;;;;;N;;;;;
+09AC;BENGALI LETTER BA;Lo;0;L;;;;;N;;;;;
+09AD;BENGALI LETTER BHA;Lo;0;L;;;;;N;;;;;
+09AE;BENGALI LETTER MA;Lo;0;L;;;;;N;;;;;
+09AF;BENGALI LETTER YA;Lo;0;L;;;;;N;;;;;
+09B0;BENGALI LETTER RA;Lo;0;L;;;;;N;;;;;
+09B2;BENGALI LETTER LA;Lo;0;L;;;;;N;;;;;
+09B6;BENGALI LETTER SHA;Lo;0;L;;;;;N;;;;;
+09B7;BENGALI LETTER SSA;Lo;0;L;;;;;N;;;;;
+09B8;BENGALI LETTER SA;Lo;0;L;;;;;N;;;;;
+09B9;BENGALI LETTER HA;Lo;0;L;;;;;N;;;;;
+09BC;BENGALI SIGN NUKTA;Mn;7;NSM;;;;;N;;;;;
+09BE;BENGALI VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;
+09BF;BENGALI VOWEL SIGN I;Mc;0;L;;;;;N;;;;;
+09C0;BENGALI VOWEL SIGN II;Mc;0;L;;;;;N;;;;;
+09C1;BENGALI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;
+09C2;BENGALI VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;;
+09C3;BENGALI VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;;
+09C4;BENGALI VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;;
+09C7;BENGALI VOWEL SIGN E;Mc;0;L;;;;;N;;;;;
+09C8;BENGALI VOWEL SIGN AI;Mc;0;L;;;;;N;;;;;
+09CB;BENGALI VOWEL SIGN O;Mc;0;L;09C7 09BE;;;;N;;;;;
+09CC;BENGALI VOWEL SIGN AU;Mc;0;L;09C7 09D7;;;;N;;;;;
+09CD;BENGALI SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;;
+09D7;BENGALI AU LENGTH MARK;Mc;0;L;;;;;N;;;;;
+09DC;BENGALI LETTER RRA;Lo;0;L;09A1 09BC;;;;N;;;;;
+09DD;BENGALI LETTER RHA;Lo;0;L;09A2 09BC;;;;N;;;;;
+09DF;BENGALI LETTER YYA;Lo;0;L;09AF 09BC;;;;N;;;;;
+09E0;BENGALI LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;;
+09E1;BENGALI LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;;
+09E2;BENGALI VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;;
+09E3;BENGALI VOWEL SIGN VOCALIC LL;Mn;0;NSM;;;;;N;;;;;
+09E6;BENGALI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+09E7;BENGALI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+09E8;BENGALI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+09E9;BENGALI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+09EA;BENGALI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+09EB;BENGALI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+09EC;BENGALI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+09ED;BENGALI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+09EE;BENGALI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+09EF;BENGALI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+09F0;BENGALI LETTER RA WITH MIDDLE DIAGONAL;Lo;0;L;;;;;N;;Assamese;;;
+09F1;BENGALI LETTER RA WITH LOWER DIAGONAL;Lo;0;L;;;;;N;BENGALI LETTER VA WITH LOWER DIAGONAL;Assamese;;;
+09F2;BENGALI RUPEE MARK;Sc;0;ET;;;;;N;;;;;
+09F3;BENGALI RUPEE SIGN;Sc;0;ET;;;;;N;;;;;
+09F4;BENGALI CURRENCY NUMERATOR ONE;No;0;L;;;;1;N;;;;;
+09F5;BENGALI CURRENCY NUMERATOR TWO;No;0;L;;;;2;N;;;;;
+09F6;BENGALI CURRENCY NUMERATOR THREE;No;0;L;;;;3;N;;;;;
+09F7;BENGALI CURRENCY NUMERATOR FOUR;No;0;L;;;;4;N;;;;;
+09F8;BENGALI CURRENCY NUMERATOR ONE LESS THAN THE DENOMINATOR;No;0;L;;;;;N;;;;;
+09F9;BENGALI CURRENCY DENOMINATOR SIXTEEN;No;0;L;;;;16;N;;;;;
+09FA;BENGALI ISSHAR;So;0;L;;;;;N;;;;;
+0A02;GURMUKHI SIGN BINDI;Mn;0;NSM;;;;;N;;;;;
+0A05;GURMUKHI LETTER A;Lo;0;L;;;;;N;;;;;
+0A06;GURMUKHI LETTER AA;Lo;0;L;;;;;N;;;;;
+0A07;GURMUKHI LETTER I;Lo;0;L;;;;;N;;;;;
+0A08;GURMUKHI LETTER II;Lo;0;L;;;;;N;;;;;
+0A09;GURMUKHI LETTER U;Lo;0;L;;;;;N;;;;;
+0A0A;GURMUKHI LETTER UU;Lo;0;L;;;;;N;;;;;
+0A0F;GURMUKHI LETTER EE;Lo;0;L;;;;;N;;;;;
+0A10;GURMUKHI LETTER AI;Lo;0;L;;;;;N;;;;;
+0A13;GURMUKHI LETTER OO;Lo;0;L;;;;;N;;;;;
+0A14;GURMUKHI LETTER AU;Lo;0;L;;;;;N;;;;;
+0A15;GURMUKHI LETTER KA;Lo;0;L;;;;;N;;;;;
+0A16;GURMUKHI LETTER KHA;Lo;0;L;;;;;N;;;;;
+0A17;GURMUKHI LETTER GA;Lo;0;L;;;;;N;;;;;
+0A18;GURMUKHI LETTER GHA;Lo;0;L;;;;;N;;;;;
+0A19;GURMUKHI LETTER NGA;Lo;0;L;;;;;N;;;;;
+0A1A;GURMUKHI LETTER CA;Lo;0;L;;;;;N;;;;;
+0A1B;GURMUKHI LETTER CHA;Lo;0;L;;;;;N;;;;;
+0A1C;GURMUKHI LETTER JA;Lo;0;L;;;;;N;;;;;
+0A1D;GURMUKHI LETTER JHA;Lo;0;L;;;;;N;;;;;
+0A1E;GURMUKHI LETTER NYA;Lo;0;L;;;;;N;;;;;
+0A1F;GURMUKHI LETTER TTA;Lo;0;L;;;;;N;;;;;
+0A20;GURMUKHI LETTER TTHA;Lo;0;L;;;;;N;;;;;
+0A21;GURMUKHI LETTER DDA;Lo;0;L;;;;;N;;;;;
+0A22;GURMUKHI LETTER DDHA;Lo;0;L;;;;;N;;;;;
+0A23;GURMUKHI LETTER NNA;Lo;0;L;;;;;N;;;;;
+0A24;GURMUKHI LETTER TA;Lo;0;L;;;;;N;;;;;
+0A25;GURMUKHI LETTER THA;Lo;0;L;;;;;N;;;;;
+0A26;GURMUKHI LETTER DA;Lo;0;L;;;;;N;;;;;
+0A27;GURMUKHI LETTER DHA;Lo;0;L;;;;;N;;;;;
+0A28;GURMUKHI LETTER NA;Lo;0;L;;;;;N;;;;;
+0A2A;GURMUKHI LETTER PA;Lo;0;L;;;;;N;;;;;
+0A2B;GURMUKHI LETTER PHA;Lo;0;L;;;;;N;;;;;
+0A2C;GURMUKHI LETTER BA;Lo;0;L;;;;;N;;;;;
+0A2D;GURMUKHI LETTER BHA;Lo;0;L;;;;;N;;;;;
+0A2E;GURMUKHI LETTER MA;Lo;0;L;;;;;N;;;;;
+0A2F;GURMUKHI LETTER YA;Lo;0;L;;;;;N;;;;;
+0A30;GURMUKHI LETTER RA;Lo;0;L;;;;;N;;;;;
+0A32;GURMUKHI LETTER LA;Lo;0;L;;;;;N;;;;;
+0A33;GURMUKHI LETTER LLA;Lo;0;L;0A32 0A3C;;;;N;;;;;
+0A35;GURMUKHI LETTER VA;Lo;0;L;;;;;N;;;;;
+0A36;GURMUKHI LETTER SHA;Lo;0;L;0A38 0A3C;;;;N;;;;;
+0A38;GURMUKHI LETTER SA;Lo;0;L;;;;;N;;;;;
+0A39;GURMUKHI LETTER HA;Lo;0;L;;;;;N;;;;;
+0A3C;GURMUKHI SIGN NUKTA;Mn;7;NSM;;;;;N;;;;;
+0A3E;GURMUKHI VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;
+0A3F;GURMUKHI VOWEL SIGN I;Mc;0;L;;;;;N;;;;;
+0A40;GURMUKHI VOWEL SIGN II;Mc;0;L;;;;;N;;;;;
+0A41;GURMUKHI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;
+0A42;GURMUKHI VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;;
+0A47;GURMUKHI VOWEL SIGN EE;Mn;0;NSM;;;;;N;;;;;
+0A48;GURMUKHI VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;;
+0A4B;GURMUKHI VOWEL SIGN OO;Mn;0;NSM;;;;;N;;;;;
+0A4C;GURMUKHI VOWEL SIGN AU;Mn;0;NSM;;;;;N;;;;;
+0A4D;GURMUKHI SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;;
+0A59;GURMUKHI LETTER KHHA;Lo;0;L;0A16 0A3C;;;;N;;;;;
+0A5A;GURMUKHI LETTER GHHA;Lo;0;L;0A17 0A3C;;;;N;;;;;
+0A5B;GURMUKHI LETTER ZA;Lo;0;L;0A1C 0A3C;;;;N;;;;;
+0A5C;GURMUKHI LETTER RRA;Lo;0;L;;;;;N;;;;;
+0A5E;GURMUKHI LETTER FA;Lo;0;L;0A2B 0A3C;;;;N;;;;;
+0A66;GURMUKHI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+0A67;GURMUKHI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+0A68;GURMUKHI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+0A69;GURMUKHI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+0A6A;GURMUKHI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+0A6B;GURMUKHI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+0A6C;GURMUKHI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+0A6D;GURMUKHI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+0A6E;GURMUKHI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+0A6F;GURMUKHI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+0A70;GURMUKHI TIPPI;Mn;0;NSM;;;;;N;;;;;
+0A71;GURMUKHI ADDAK;Mn;0;NSM;;;;;N;;;;;
+0A72;GURMUKHI IRI;Lo;0;L;;;;;N;;;;;
+0A73;GURMUKHI URA;Lo;0;L;;;;;N;;;;;
+0A74;GURMUKHI EK ONKAR;Lo;0;L;;;;;N;;;;;
+0A81;GUJARATI SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;;
+0A82;GUJARATI SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;;
+0A83;GUJARATI SIGN VISARGA;Mc;0;L;;;;;N;;;;;
+0A85;GUJARATI LETTER A;Lo;0;L;;;;;N;;;;;
+0A86;GUJARATI LETTER AA;Lo;0;L;;;;;N;;;;;
+0A87;GUJARATI LETTER I;Lo;0;L;;;;;N;;;;;
+0A88;GUJARATI LETTER II;Lo;0;L;;;;;N;;;;;
+0A89;GUJARATI LETTER U;Lo;0;L;;;;;N;;;;;
+0A8A;GUJARATI LETTER UU;Lo;0;L;;;;;N;;;;;
+0A8B;GUJARATI LETTER VOCALIC R;Lo;0;L;;;;;N;;;;;
+0A8D;GUJARATI VOWEL CANDRA E;Lo;0;L;;;;;N;;;;;
+0A8F;GUJARATI LETTER E;Lo;0;L;;;;;N;;;;;
+0A90;GUJARATI LETTER AI;Lo;0;L;;;;;N;;;;;
+0A91;GUJARATI VOWEL CANDRA O;Lo;0;L;;;;;N;;;;;
+0A93;GUJARATI LETTER O;Lo;0;L;;;;;N;;;;;
+0A94;GUJARATI LETTER AU;Lo;0;L;;;;;N;;;;;
+0A95;GUJARATI LETTER KA;Lo;0;L;;;;;N;;;;;
+0A96;GUJARATI LETTER KHA;Lo;0;L;;;;;N;;;;;
+0A97;GUJARATI LETTER GA;Lo;0;L;;;;;N;;;;;
+0A98;GUJARATI LETTER GHA;Lo;0;L;;;;;N;;;;;
+0A99;GUJARATI LETTER NGA;Lo;0;L;;;;;N;;;;;
+0A9A;GUJARATI LETTER CA;Lo;0;L;;;;;N;;;;;
+0A9B;GUJARATI LETTER CHA;Lo;0;L;;;;;N;;;;;
+0A9C;GUJARATI LETTER JA;Lo;0;L;;;;;N;;;;;
+0A9D;GUJARATI LETTER JHA;Lo;0;L;;;;;N;;;;;
+0A9E;GUJARATI LETTER NYA;Lo;0;L;;;;;N;;;;;
+0A9F;GUJARATI LETTER TTA;Lo;0;L;;;;;N;;;;;
+0AA0;GUJARATI LETTER TTHA;Lo;0;L;;;;;N;;;;;
+0AA1;GUJARATI LETTER DDA;Lo;0;L;;;;;N;;;;;
+0AA2;GUJARATI LETTER DDHA;Lo;0;L;;;;;N;;;;;
+0AA3;GUJARATI LETTER NNA;Lo;0;L;;;;;N;;;;;
+0AA4;GUJARATI LETTER TA;Lo;0;L;;;;;N;;;;;
+0AA5;GUJARATI LETTER THA;Lo;0;L;;;;;N;;;;;
+0AA6;GUJARATI LETTER DA;Lo;0;L;;;;;N;;;;;
+0AA7;GUJARATI LETTER DHA;Lo;0;L;;;;;N;;;;;
+0AA8;GUJARATI LETTER NA;Lo;0;L;;;;;N;;;;;
+0AAA;GUJARATI LETTER PA;Lo;0;L;;;;;N;;;;;
+0AAB;GUJARATI LETTER PHA;Lo;0;L;;;;;N;;;;;
+0AAC;GUJARATI LETTER BA;Lo;0;L;;;;;N;;;;;
+0AAD;GUJARATI LETTER BHA;Lo;0;L;;;;;N;;;;;
+0AAE;GUJARATI LETTER MA;Lo;0;L;;;;;N;;;;;
+0AAF;GUJARATI LETTER YA;Lo;0;L;;;;;N;;;;;
+0AB0;GUJARATI LETTER RA;Lo;0;L;;;;;N;;;;;
+0AB2;GUJARATI LETTER LA;Lo;0;L;;;;;N;;;;;
+0AB3;GUJARATI LETTER LLA;Lo;0;L;;;;;N;;;;;
+0AB5;GUJARATI LETTER VA;Lo;0;L;;;;;N;;;;;
+0AB6;GUJARATI LETTER SHA;Lo;0;L;;;;;N;;;;;
+0AB7;GUJARATI LETTER SSA;Lo;0;L;;;;;N;;;;;
+0AB8;GUJARATI LETTER SA;Lo;0;L;;;;;N;;;;;
+0AB9;GUJARATI LETTER HA;Lo;0;L;;;;;N;;;;;
+0ABC;GUJARATI SIGN NUKTA;Mn;7;NSM;;;;;N;;;;;
+0ABD;GUJARATI SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;;
+0ABE;GUJARATI VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;
+0ABF;GUJARATI VOWEL SIGN I;Mc;0;L;;;;;N;;;;;
+0AC0;GUJARATI VOWEL SIGN II;Mc;0;L;;;;;N;;;;;
+0AC1;GUJARATI VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;
+0AC2;GUJARATI VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;;
+0AC3;GUJARATI VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;;
+0AC4;GUJARATI VOWEL SIGN VOCALIC RR;Mn;0;NSM;;;;;N;;;;;
+0AC5;GUJARATI VOWEL SIGN CANDRA E;Mn;0;NSM;;;;;N;;;;;
+0AC7;GUJARATI VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;;
+0AC8;GUJARATI VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;;
+0AC9;GUJARATI VOWEL SIGN CANDRA O;Mc;0;L;;;;;N;;;;;
+0ACB;GUJARATI VOWEL SIGN O;Mc;0;L;;;;;N;;;;;
+0ACC;GUJARATI VOWEL SIGN AU;Mc;0;L;;;;;N;;;;;
+0ACD;GUJARATI SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;;
+0AD0;GUJARATI OM;Lo;0;L;;;;;N;;;;;
+0AE0;GUJARATI LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;;
+0AE6;GUJARATI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+0AE7;GUJARATI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+0AE8;GUJARATI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+0AE9;GUJARATI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+0AEA;GUJARATI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+0AEB;GUJARATI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+0AEC;GUJARATI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+0AED;GUJARATI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+0AEE;GUJARATI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+0AEF;GUJARATI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+0B01;ORIYA SIGN CANDRABINDU;Mn;0;NSM;;;;;N;;;;;
+0B02;ORIYA SIGN ANUSVARA;Mc;0;L;;;;;N;;;;;
+0B03;ORIYA SIGN VISARGA;Mc;0;L;;;;;N;;;;;
+0B05;ORIYA LETTER A;Lo;0;L;;;;;N;;;;;
+0B06;ORIYA LETTER AA;Lo;0;L;;;;;N;;;;;
+0B07;ORIYA LETTER I;Lo;0;L;;;;;N;;;;;
+0B08;ORIYA LETTER II;Lo;0;L;;;;;N;;;;;
+0B09;ORIYA LETTER U;Lo;0;L;;;;;N;;;;;
+0B0A;ORIYA LETTER UU;Lo;0;L;;;;;N;;;;;
+0B0B;ORIYA LETTER VOCALIC R;Lo;0;L;;;;;N;;;;;
+0B0C;ORIYA LETTER VOCALIC L;Lo;0;L;;;;;N;;;;;
+0B0F;ORIYA LETTER E;Lo;0;L;;;;;N;;;;;
+0B10;ORIYA LETTER AI;Lo;0;L;;;;;N;;;;;
+0B13;ORIYA LETTER O;Lo;0;L;;;;;N;;;;;
+0B14;ORIYA LETTER AU;Lo;0;L;;;;;N;;;;;
+0B15;ORIYA LETTER KA;Lo;0;L;;;;;N;;;;;
+0B16;ORIYA LETTER KHA;Lo;0;L;;;;;N;;;;;
+0B17;ORIYA LETTER GA;Lo;0;L;;;;;N;;;;;
+0B18;ORIYA LETTER GHA;Lo;0;L;;;;;N;;;;;
+0B19;ORIYA LETTER NGA;Lo;0;L;;;;;N;;;;;
+0B1A;ORIYA LETTER CA;Lo;0;L;;;;;N;;;;;
+0B1B;ORIYA LETTER CHA;Lo;0;L;;;;;N;;;;;
+0B1C;ORIYA LETTER JA;Lo;0;L;;;;;N;;;;;
+0B1D;ORIYA LETTER JHA;Lo;0;L;;;;;N;;;;;
+0B1E;ORIYA LETTER NYA;Lo;0;L;;;;;N;;;;;
+0B1F;ORIYA LETTER TTA;Lo;0;L;;;;;N;;;;;
+0B20;ORIYA LETTER TTHA;Lo;0;L;;;;;N;;;;;
+0B21;ORIYA LETTER DDA;Lo;0;L;;;;;N;;;;;
+0B22;ORIYA LETTER DDHA;Lo;0;L;;;;;N;;;;;
+0B23;ORIYA LETTER NNA;Lo;0;L;;;;;N;;;;;
+0B24;ORIYA LETTER TA;Lo;0;L;;;;;N;;;;;
+0B25;ORIYA LETTER THA;Lo;0;L;;;;;N;;;;;
+0B26;ORIYA LETTER DA;Lo;0;L;;;;;N;;;;;
+0B27;ORIYA LETTER DHA;Lo;0;L;;;;;N;;;;;
+0B28;ORIYA LETTER NA;Lo;0;L;;;;;N;;;;;
+0B2A;ORIYA LETTER PA;Lo;0;L;;;;;N;;;;;
+0B2B;ORIYA LETTER PHA;Lo;0;L;;;;;N;;;;;
+0B2C;ORIYA LETTER BA;Lo;0;L;;;;;N;;;;;
+0B2D;ORIYA LETTER BHA;Lo;0;L;;;;;N;;;;;
+0B2E;ORIYA LETTER MA;Lo;0;L;;;;;N;;;;;
+0B2F;ORIYA LETTER YA;Lo;0;L;;;;;N;;;;;
+0B30;ORIYA LETTER RA;Lo;0;L;;;;;N;;;;;
+0B32;ORIYA LETTER LA;Lo;0;L;;;;;N;;;;;
+0B33;ORIYA LETTER LLA;Lo;0;L;;;;;N;;;;;
+0B36;ORIYA LETTER SHA;Lo;0;L;;;;;N;;;;;
+0B37;ORIYA LETTER SSA;Lo;0;L;;;;;N;;;;;
+0B38;ORIYA LETTER SA;Lo;0;L;;;;;N;;;;;
+0B39;ORIYA LETTER HA;Lo;0;L;;;;;N;;;;;
+0B3C;ORIYA SIGN NUKTA;Mn;7;NSM;;;;;N;;;;;
+0B3D;ORIYA SIGN AVAGRAHA;Lo;0;L;;;;;N;;;;;
+0B3E;ORIYA VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;
+0B3F;ORIYA VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;;
+0B40;ORIYA VOWEL SIGN II;Mc;0;L;;;;;N;;;;;
+0B41;ORIYA VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;
+0B42;ORIYA VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;;
+0B43;ORIYA VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;;
+0B47;ORIYA VOWEL SIGN E;Mc;0;L;;;;;N;;;;;
+0B48;ORIYA VOWEL SIGN AI;Mc;0;L;0B47 0B56;;;;N;;;;;
+0B4B;ORIYA VOWEL SIGN O;Mc;0;L;0B47 0B3E;;;;N;;;;;
+0B4C;ORIYA VOWEL SIGN AU;Mc;0;L;0B47 0B57;;;;N;;;;;
+0B4D;ORIYA SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;;
+0B56;ORIYA AI LENGTH MARK;Mn;0;NSM;;;;;N;;;;;
+0B57;ORIYA AU LENGTH MARK;Mc;0;L;;;;;N;;;;;
+0B5C;ORIYA LETTER RRA;Lo;0;L;0B21 0B3C;;;;N;;;;;
+0B5D;ORIYA LETTER RHA;Lo;0;L;0B22 0B3C;;;;N;;;;;
+0B5F;ORIYA LETTER YYA;Lo;0;L;;;;;N;;;;;
+0B60;ORIYA LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;;
+0B61;ORIYA LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;;
+0B66;ORIYA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+0B67;ORIYA DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+0B68;ORIYA DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+0B69;ORIYA DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+0B6A;ORIYA DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+0B6B;ORIYA DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+0B6C;ORIYA DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+0B6D;ORIYA DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+0B6E;ORIYA DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+0B6F;ORIYA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+0B70;ORIYA ISSHAR;So;0;L;;;;;N;;;;;
+0B82;TAMIL SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;;
+0B83;TAMIL SIGN VISARGA;Mc;0;L;;;;;N;;;;;
+0B85;TAMIL LETTER A;Lo;0;L;;;;;N;;;;;
+0B86;TAMIL LETTER AA;Lo;0;L;;;;;N;;;;;
+0B87;TAMIL LETTER I;Lo;0;L;;;;;N;;;;;
+0B88;TAMIL LETTER II;Lo;0;L;;;;;N;;;;;
+0B89;TAMIL LETTER U;Lo;0;L;;;;;N;;;;;
+0B8A;TAMIL LETTER UU;Lo;0;L;;;;;N;;;;;
+0B8E;TAMIL LETTER E;Lo;0;L;;;;;N;;;;;
+0B8F;TAMIL LETTER EE;Lo;0;L;;;;;N;;;;;
+0B90;TAMIL LETTER AI;Lo;0;L;;;;;N;;;;;
+0B92;TAMIL LETTER O;Lo;0;L;;;;;N;;;;;
+0B93;TAMIL LETTER OO;Lo;0;L;;;;;N;;;;;
+0B94;TAMIL LETTER AU;Lo;0;L;0B92 0BD7;;;;N;;;;;
+0B95;TAMIL LETTER KA;Lo;0;L;;;;;N;;;;;
+0B99;TAMIL LETTER NGA;Lo;0;L;;;;;N;;;;;
+0B9A;TAMIL LETTER CA;Lo;0;L;;;;;N;;;;;
+0B9C;TAMIL LETTER JA;Lo;0;L;;;;;N;;;;;
+0B9E;TAMIL LETTER NYA;Lo;0;L;;;;;N;;;;;
+0B9F;TAMIL LETTER TTA;Lo;0;L;;;;;N;;;;;
+0BA3;TAMIL LETTER NNA;Lo;0;L;;;;;N;;;;;
+0BA4;TAMIL LETTER TA;Lo;0;L;;;;;N;;;;;
+0BA8;TAMIL LETTER NA;Lo;0;L;;;;;N;;;;;
+0BA9;TAMIL LETTER NNNA;Lo;0;L;;;;;N;;;;;
+0BAA;TAMIL LETTER PA;Lo;0;L;;;;;N;;;;;
+0BAE;TAMIL LETTER MA;Lo;0;L;;;;;N;;;;;
+0BAF;TAMIL LETTER YA;Lo;0;L;;;;;N;;;;;
+0BB0;TAMIL LETTER RA;Lo;0;L;;;;;N;;;;;
+0BB1;TAMIL LETTER RRA;Lo;0;L;;;;;N;;;;;
+0BB2;TAMIL LETTER LA;Lo;0;L;;;;;N;;;;;
+0BB3;TAMIL LETTER LLA;Lo;0;L;;;;;N;;;;;
+0BB4;TAMIL LETTER LLLA;Lo;0;L;;;;;N;;;;;
+0BB5;TAMIL LETTER VA;Lo;0;L;;;;;N;;;;;
+0BB7;TAMIL LETTER SSA;Lo;0;L;;;;;N;;;;;
+0BB8;TAMIL LETTER SA;Lo;0;L;;;;;N;;;;;
+0BB9;TAMIL LETTER HA;Lo;0;L;;;;;N;;;;;
+0BBE;TAMIL VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;
+0BBF;TAMIL VOWEL SIGN I;Mc;0;L;;;;;N;;;;;
+0BC0;TAMIL VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;;
+0BC1;TAMIL VOWEL SIGN U;Mc;0;L;;;;;N;;;;;
+0BC2;TAMIL VOWEL SIGN UU;Mc;0;L;;;;;N;;;;;
+0BC6;TAMIL VOWEL SIGN E;Mc;0;L;;;;;N;;;;;
+0BC7;TAMIL VOWEL SIGN EE;Mc;0;L;;;;;N;;;;;
+0BC8;TAMIL VOWEL SIGN AI;Mc;0;L;;;;;N;;;;;
+0BCA;TAMIL VOWEL SIGN O;Mc;0;L;0BC6 0BBE;;;;N;;;;;
+0BCB;TAMIL VOWEL SIGN OO;Mc;0;L;0BC7 0BBE;;;;N;;;;;
+0BCC;TAMIL VOWEL SIGN AU;Mc;0;L;0BC6 0BD7;;;;N;;;;;
+0BCD;TAMIL SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;;
+0BD7;TAMIL AU LENGTH MARK;Mc;0;L;;;;;N;;;;;
+0BE7;TAMIL DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+0BE8;TAMIL DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+0BE9;TAMIL DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+0BEA;TAMIL DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+0BEB;TAMIL DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+0BEC;TAMIL DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+0BED;TAMIL DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+0BEE;TAMIL DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+0BEF;TAMIL DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+0BF0;TAMIL NUMBER TEN;No;0;L;;;;10;N;;;;;
+0BF1;TAMIL NUMBER ONE HUNDRED;No;0;L;;;;100;N;;;;;
+0BF2;TAMIL NUMBER ONE THOUSAND;No;0;L;;;;1000;N;;;;;
+0C01;TELUGU SIGN CANDRABINDU;Mc;0;L;;;;;N;;;;;
+0C02;TELUGU SIGN ANUSVARA;Mc;0;L;;;;;N;;;;;
+0C03;TELUGU SIGN VISARGA;Mc;0;L;;;;;N;;;;;
+0C05;TELUGU LETTER A;Lo;0;L;;;;;N;;;;;
+0C06;TELUGU LETTER AA;Lo;0;L;;;;;N;;;;;
+0C07;TELUGU LETTER I;Lo;0;L;;;;;N;;;;;
+0C08;TELUGU LETTER II;Lo;0;L;;;;;N;;;;;
+0C09;TELUGU LETTER U;Lo;0;L;;;;;N;;;;;
+0C0A;TELUGU LETTER UU;Lo;0;L;;;;;N;;;;;
+0C0B;TELUGU LETTER VOCALIC R;Lo;0;L;;;;;N;;;;;
+0C0C;TELUGU LETTER VOCALIC L;Lo;0;L;;;;;N;;;;;
+0C0E;TELUGU LETTER E;Lo;0;L;;;;;N;;;;;
+0C0F;TELUGU LETTER EE;Lo;0;L;;;;;N;;;;;
+0C10;TELUGU LETTER AI;Lo;0;L;;;;;N;;;;;
+0C12;TELUGU LETTER O;Lo;0;L;;;;;N;;;;;
+0C13;TELUGU LETTER OO;Lo;0;L;;;;;N;;;;;
+0C14;TELUGU LETTER AU;Lo;0;L;;;;;N;;;;;
+0C15;TELUGU LETTER KA;Lo;0;L;;;;;N;;;;;
+0C16;TELUGU LETTER KHA;Lo;0;L;;;;;N;;;;;
+0C17;TELUGU LETTER GA;Lo;0;L;;;;;N;;;;;
+0C18;TELUGU LETTER GHA;Lo;0;L;;;;;N;;;;;
+0C19;TELUGU LETTER NGA;Lo;0;L;;;;;N;;;;;
+0C1A;TELUGU LETTER CA;Lo;0;L;;;;;N;;;;;
+0C1B;TELUGU LETTER CHA;Lo;0;L;;;;;N;;;;;
+0C1C;TELUGU LETTER JA;Lo;0;L;;;;;N;;;;;
+0C1D;TELUGU LETTER JHA;Lo;0;L;;;;;N;;;;;
+0C1E;TELUGU LETTER NYA;Lo;0;L;;;;;N;;;;;
+0C1F;TELUGU LETTER TTA;Lo;0;L;;;;;N;;;;;
+0C20;TELUGU LETTER TTHA;Lo;0;L;;;;;N;;;;;
+0C21;TELUGU LETTER DDA;Lo;0;L;;;;;N;;;;;
+0C22;TELUGU LETTER DDHA;Lo;0;L;;;;;N;;;;;
+0C23;TELUGU LETTER NNA;Lo;0;L;;;;;N;;;;;
+0C24;TELUGU LETTER TA;Lo;0;L;;;;;N;;;;;
+0C25;TELUGU LETTER THA;Lo;0;L;;;;;N;;;;;
+0C26;TELUGU LETTER DA;Lo;0;L;;;;;N;;;;;
+0C27;TELUGU LETTER DHA;Lo;0;L;;;;;N;;;;;
+0C28;TELUGU LETTER NA;Lo;0;L;;;;;N;;;;;
+0C2A;TELUGU LETTER PA;Lo;0;L;;;;;N;;;;;
+0C2B;TELUGU LETTER PHA;Lo;0;L;;;;;N;;;;;
+0C2C;TELUGU LETTER BA;Lo;0;L;;;;;N;;;;;
+0C2D;TELUGU LETTER BHA;Lo;0;L;;;;;N;;;;;
+0C2E;TELUGU LETTER MA;Lo;0;L;;;;;N;;;;;
+0C2F;TELUGU LETTER YA;Lo;0;L;;;;;N;;;;;
+0C30;TELUGU LETTER RA;Lo;0;L;;;;;N;;;;;
+0C31;TELUGU LETTER RRA;Lo;0;L;;;;;N;;;;;
+0C32;TELUGU LETTER LA;Lo;0;L;;;;;N;;;;;
+0C33;TELUGU LETTER LLA;Lo;0;L;;;;;N;;;;;
+0C35;TELUGU LETTER VA;Lo;0;L;;;;;N;;;;;
+0C36;TELUGU LETTER SHA;Lo;0;L;;;;;N;;;;;
+0C37;TELUGU LETTER SSA;Lo;0;L;;;;;N;;;;;
+0C38;TELUGU LETTER SA;Lo;0;L;;;;;N;;;;;
+0C39;TELUGU LETTER HA;Lo;0;L;;;;;N;;;;;
+0C3E;TELUGU VOWEL SIGN AA;Mn;0;NSM;;;;;N;;;;;
+0C3F;TELUGU VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;;
+0C40;TELUGU VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;;
+0C41;TELUGU VOWEL SIGN U;Mc;0;L;;;;;N;;;;;
+0C42;TELUGU VOWEL SIGN UU;Mc;0;L;;;;;N;;;;;
+0C43;TELUGU VOWEL SIGN VOCALIC R;Mc;0;L;;;;;N;;;;;
+0C44;TELUGU VOWEL SIGN VOCALIC RR;Mc;0;L;;;;;N;;;;;
+0C46;TELUGU VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;;
+0C47;TELUGU VOWEL SIGN EE;Mn;0;NSM;;;;;N;;;;;
+0C48;TELUGU VOWEL SIGN AI;Mn;0;NSM;0C46 0C56;;;;N;;;;;
+0C4A;TELUGU VOWEL SIGN O;Mn;0;NSM;;;;;N;;;;;
+0C4B;TELUGU VOWEL SIGN OO;Mn;0;NSM;;;;;N;;;;;
+0C4C;TELUGU VOWEL SIGN AU;Mn;0;NSM;;;;;N;;;;;
+0C4D;TELUGU SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;;
+0C55;TELUGU LENGTH MARK;Mn;84;NSM;;;;;N;;;;;
+0C56;TELUGU AI LENGTH MARK;Mn;91;NSM;;;;;N;;;;;
+0C60;TELUGU LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;;
+0C61;TELUGU LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;;
+0C66;TELUGU DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+0C67;TELUGU DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+0C68;TELUGU DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+0C69;TELUGU DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+0C6A;TELUGU DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+0C6B;TELUGU DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+0C6C;TELUGU DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+0C6D;TELUGU DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+0C6E;TELUGU DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+0C6F;TELUGU DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+0C82;KANNADA SIGN ANUSVARA;Mc;0;L;;;;;N;;;;;
+0C83;KANNADA SIGN VISARGA;Mc;0;L;;;;;N;;;;;
+0C85;KANNADA LETTER A;Lo;0;L;;;;;N;;;;;
+0C86;KANNADA LETTER AA;Lo;0;L;;;;;N;;;;;
+0C87;KANNADA LETTER I;Lo;0;L;;;;;N;;;;;
+0C88;KANNADA LETTER II;Lo;0;L;;;;;N;;;;;
+0C89;KANNADA LETTER U;Lo;0;L;;;;;N;;;;;
+0C8A;KANNADA LETTER UU;Lo;0;L;;;;;N;;;;;
+0C8B;KANNADA LETTER VOCALIC R;Lo;0;L;;;;;N;;;;;
+0C8C;KANNADA LETTER VOCALIC L;Lo;0;L;;;;;N;;;;;
+0C8E;KANNADA LETTER E;Lo;0;L;;;;;N;;;;;
+0C8F;KANNADA LETTER EE;Lo;0;L;;;;;N;;;;;
+0C90;KANNADA LETTER AI;Lo;0;L;;;;;N;;;;;
+0C92;KANNADA LETTER O;Lo;0;L;;;;;N;;;;;
+0C93;KANNADA LETTER OO;Lo;0;L;;;;;N;;;;;
+0C94;KANNADA LETTER AU;Lo;0;L;;;;;N;;;;;
+0C95;KANNADA LETTER KA;Lo;0;L;;;;;N;;;;;
+0C96;KANNADA LETTER KHA;Lo;0;L;;;;;N;;;;;
+0C97;KANNADA LETTER GA;Lo;0;L;;;;;N;;;;;
+0C98;KANNADA LETTER GHA;Lo;0;L;;;;;N;;;;;
+0C99;KANNADA LETTER NGA;Lo;0;L;;;;;N;;;;;
+0C9A;KANNADA LETTER CA;Lo;0;L;;;;;N;;;;;
+0C9B;KANNADA LETTER CHA;Lo;0;L;;;;;N;;;;;
+0C9C;KANNADA LETTER JA;Lo;0;L;;;;;N;;;;;
+0C9D;KANNADA LETTER JHA;Lo;0;L;;;;;N;;;;;
+0C9E;KANNADA LETTER NYA;Lo;0;L;;;;;N;;;;;
+0C9F;KANNADA LETTER TTA;Lo;0;L;;;;;N;;;;;
+0CA0;KANNADA LETTER TTHA;Lo;0;L;;;;;N;;;;;
+0CA1;KANNADA LETTER DDA;Lo;0;L;;;;;N;;;;;
+0CA2;KANNADA LETTER DDHA;Lo;0;L;;;;;N;;;;;
+0CA3;KANNADA LETTER NNA;Lo;0;L;;;;;N;;;;;
+0CA4;KANNADA LETTER TA;Lo;0;L;;;;;N;;;;;
+0CA5;KANNADA LETTER THA;Lo;0;L;;;;;N;;;;;
+0CA6;KANNADA LETTER DA;Lo;0;L;;;;;N;;;;;
+0CA7;KANNADA LETTER DHA;Lo;0;L;;;;;N;;;;;
+0CA8;KANNADA LETTER NA;Lo;0;L;;;;;N;;;;;
+0CAA;KANNADA LETTER PA;Lo;0;L;;;;;N;;;;;
+0CAB;KANNADA LETTER PHA;Lo;0;L;;;;;N;;;;;
+0CAC;KANNADA LETTER BA;Lo;0;L;;;;;N;;;;;
+0CAD;KANNADA LETTER BHA;Lo;0;L;;;;;N;;;;;
+0CAE;KANNADA LETTER MA;Lo;0;L;;;;;N;;;;;
+0CAF;KANNADA LETTER YA;Lo;0;L;;;;;N;;;;;
+0CB0;KANNADA LETTER RA;Lo;0;L;;;;;N;;;;;
+0CB1;KANNADA LETTER RRA;Lo;0;L;;;;;N;;;;;
+0CB2;KANNADA LETTER LA;Lo;0;L;;;;;N;;;;;
+0CB3;KANNADA LETTER LLA;Lo;0;L;;;;;N;;;;;
+0CB5;KANNADA LETTER VA;Lo;0;L;;;;;N;;;;;
+0CB6;KANNADA LETTER SHA;Lo;0;L;;;;;N;;;;;
+0CB7;KANNADA LETTER SSA;Lo;0;L;;;;;N;;;;;
+0CB8;KANNADA LETTER SA;Lo;0;L;;;;;N;;;;;
+0CB9;KANNADA LETTER HA;Lo;0;L;;;;;N;;;;;
+0CBE;KANNADA VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;
+0CBF;KANNADA VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;;
+0CC0;KANNADA VOWEL SIGN II;Mc;0;L;0CBF 0CD5;;;;N;;;;;
+0CC1;KANNADA VOWEL SIGN U;Mc;0;L;;;;;N;;;;;
+0CC2;KANNADA VOWEL SIGN UU;Mc;0;L;;;;;N;;;;;
+0CC3;KANNADA VOWEL SIGN VOCALIC R;Mc;0;L;;;;;N;;;;;
+0CC4;KANNADA VOWEL SIGN VOCALIC RR;Mc;0;L;;;;;N;;;;;
+0CC6;KANNADA VOWEL SIGN E;Mn;0;NSM;;;;;N;;;;;
+0CC7;KANNADA VOWEL SIGN EE;Mc;0;L;0CC6 0CD5;;;;N;;;;;
+0CC8;KANNADA VOWEL SIGN AI;Mc;0;L;0CC6 0CD6;;;;N;;;;;
+0CCA;KANNADA VOWEL SIGN O;Mc;0;L;0CC6 0CC2;;;;N;;;;;
+0CCB;KANNADA VOWEL SIGN OO;Mc;0;L;0CCA 0CD5;;;;N;;;;;
+0CCC;KANNADA VOWEL SIGN AU;Mn;0;NSM;;;;;N;;;;;
+0CCD;KANNADA SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;;
+0CD5;KANNADA LENGTH MARK;Mc;0;L;;;;;N;;;;;
+0CD6;KANNADA AI LENGTH MARK;Mc;0;L;;;;;N;;;;;
+0CDE;KANNADA LETTER FA;Lo;0;L;;;;;N;;;;;
+0CE0;KANNADA LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;;
+0CE1;KANNADA LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;;
+0CE6;KANNADA DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+0CE7;KANNADA DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+0CE8;KANNADA DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+0CE9;KANNADA DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+0CEA;KANNADA DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+0CEB;KANNADA DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+0CEC;KANNADA DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+0CED;KANNADA DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+0CEE;KANNADA DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+0CEF;KANNADA DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+0D02;MALAYALAM SIGN ANUSVARA;Mc;0;L;;;;;N;;;;;
+0D03;MALAYALAM SIGN VISARGA;Mc;0;L;;;;;N;;;;;
+0D05;MALAYALAM LETTER A;Lo;0;L;;;;;N;;;;;
+0D06;MALAYALAM LETTER AA;Lo;0;L;;;;;N;;;;;
+0D07;MALAYALAM LETTER I;Lo;0;L;;;;;N;;;;;
+0D08;MALAYALAM LETTER II;Lo;0;L;;;;;N;;;;;
+0D09;MALAYALAM LETTER U;Lo;0;L;;;;;N;;;;;
+0D0A;MALAYALAM LETTER UU;Lo;0;L;;;;;N;;;;;
+0D0B;MALAYALAM LETTER VOCALIC R;Lo;0;L;;;;;N;;;;;
+0D0C;MALAYALAM LETTER VOCALIC L;Lo;0;L;;;;;N;;;;;
+0D0E;MALAYALAM LETTER E;Lo;0;L;;;;;N;;;;;
+0D0F;MALAYALAM LETTER EE;Lo;0;L;;;;;N;;;;;
+0D10;MALAYALAM LETTER AI;Lo;0;L;;;;;N;;;;;
+0D12;MALAYALAM LETTER O;Lo;0;L;;;;;N;;;;;
+0D13;MALAYALAM LETTER OO;Lo;0;L;;;;;N;;;;;
+0D14;MALAYALAM LETTER AU;Lo;0;L;;;;;N;;;;;
+0D15;MALAYALAM LETTER KA;Lo;0;L;;;;;N;;;;;
+0D16;MALAYALAM LETTER KHA;Lo;0;L;;;;;N;;;;;
+0D17;MALAYALAM LETTER GA;Lo;0;L;;;;;N;;;;;
+0D18;MALAYALAM LETTER GHA;Lo;0;L;;;;;N;;;;;
+0D19;MALAYALAM LETTER NGA;Lo;0;L;;;;;N;;;;;
+0D1A;MALAYALAM LETTER CA;Lo;0;L;;;;;N;;;;;
+0D1B;MALAYALAM LETTER CHA;Lo;0;L;;;;;N;;;;;
+0D1C;MALAYALAM LETTER JA;Lo;0;L;;;;;N;;;;;
+0D1D;MALAYALAM LETTER JHA;Lo;0;L;;;;;N;;;;;
+0D1E;MALAYALAM LETTER NYA;Lo;0;L;;;;;N;;;;;
+0D1F;MALAYALAM LETTER TTA;Lo;0;L;;;;;N;;;;;
+0D20;MALAYALAM LETTER TTHA;Lo;0;L;;;;;N;;;;;
+0D21;MALAYALAM LETTER DDA;Lo;0;L;;;;;N;;;;;
+0D22;MALAYALAM LETTER DDHA;Lo;0;L;;;;;N;;;;;
+0D23;MALAYALAM LETTER NNA;Lo;0;L;;;;;N;;;;;
+0D24;MALAYALAM LETTER TA;Lo;0;L;;;;;N;;;;;
+0D25;MALAYALAM LETTER THA;Lo;0;L;;;;;N;;;;;
+0D26;MALAYALAM LETTER DA;Lo;0;L;;;;;N;;;;;
+0D27;MALAYALAM LETTER DHA;Lo;0;L;;;;;N;;;;;
+0D28;MALAYALAM LETTER NA;Lo;0;L;;;;;N;;;;;
+0D2A;MALAYALAM LETTER PA;Lo;0;L;;;;;N;;;;;
+0D2B;MALAYALAM LETTER PHA;Lo;0;L;;;;;N;;;;;
+0D2C;MALAYALAM LETTER BA;Lo;0;L;;;;;N;;;;;
+0D2D;MALAYALAM LETTER BHA;Lo;0;L;;;;;N;;;;;
+0D2E;MALAYALAM LETTER MA;Lo;0;L;;;;;N;;;;;
+0D2F;MALAYALAM LETTER YA;Lo;0;L;;;;;N;;;;;
+0D30;MALAYALAM LETTER RA;Lo;0;L;;;;;N;;;;;
+0D31;MALAYALAM LETTER RRA;Lo;0;L;;;;;N;;;;;
+0D32;MALAYALAM LETTER LA;Lo;0;L;;;;;N;;;;;
+0D33;MALAYALAM LETTER LLA;Lo;0;L;;;;;N;;;;;
+0D34;MALAYALAM LETTER LLLA;Lo;0;L;;;;;N;;;;;
+0D35;MALAYALAM LETTER VA;Lo;0;L;;;;;N;;;;;
+0D36;MALAYALAM LETTER SHA;Lo;0;L;;;;;N;;;;;
+0D37;MALAYALAM LETTER SSA;Lo;0;L;;;;;N;;;;;
+0D38;MALAYALAM LETTER SA;Lo;0;L;;;;;N;;;;;
+0D39;MALAYALAM LETTER HA;Lo;0;L;;;;;N;;;;;
+0D3E;MALAYALAM VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;
+0D3F;MALAYALAM VOWEL SIGN I;Mc;0;L;;;;;N;;;;;
+0D40;MALAYALAM VOWEL SIGN II;Mc;0;L;;;;;N;;;;;
+0D41;MALAYALAM VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;
+0D42;MALAYALAM VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;;
+0D43;MALAYALAM VOWEL SIGN VOCALIC R;Mn;0;NSM;;;;;N;;;;;
+0D46;MALAYALAM VOWEL SIGN E;Mc;0;L;;;;;N;;;;;
+0D47;MALAYALAM VOWEL SIGN EE;Mc;0;L;;;;;N;;;;;
+0D48;MALAYALAM VOWEL SIGN AI;Mc;0;L;;;;;N;;;;;
+0D4A;MALAYALAM VOWEL SIGN O;Mc;0;L;0D46 0D3E;;;;N;;;;;
+0D4B;MALAYALAM VOWEL SIGN OO;Mc;0;L;0D47 0D3E;;;;N;;;;;
+0D4C;MALAYALAM VOWEL SIGN AU;Mc;0;L;0D46 0D57;;;;N;;;;;
+0D4D;MALAYALAM SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;;
+0D57;MALAYALAM AU LENGTH MARK;Mc;0;L;;;;;N;;;;;
+0D60;MALAYALAM LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;;
+0D61;MALAYALAM LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;;
+0D66;MALAYALAM DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+0D67;MALAYALAM DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+0D68;MALAYALAM DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+0D69;MALAYALAM DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+0D6A;MALAYALAM DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+0D6B;MALAYALAM DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+0D6C;MALAYALAM DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+0D6D;MALAYALAM DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+0D6E;MALAYALAM DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+0D6F;MALAYALAM DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+0D82;SINHALA SIGN ANUSVARAYA;Mc;0;L;;;;;N;;;;;
+0D83;SINHALA SIGN VISARGAYA;Mc;0;L;;;;;N;;;;;
+0D85;SINHALA LETTER AYANNA;Lo;0;L;;;;;N;;;;;
+0D86;SINHALA LETTER AAYANNA;Lo;0;L;;;;;N;;;;;
+0D87;SINHALA LETTER AEYANNA;Lo;0;L;;;;;N;;;;;
+0D88;SINHALA LETTER AEEYANNA;Lo;0;L;;;;;N;;;;;
+0D89;SINHALA LETTER IYANNA;Lo;0;L;;;;;N;;;;;
+0D8A;SINHALA LETTER IIYANNA;Lo;0;L;;;;;N;;;;;
+0D8B;SINHALA LETTER UYANNA;Lo;0;L;;;;;N;;;;;
+0D8C;SINHALA LETTER UUYANNA;Lo;0;L;;;;;N;;;;;
+0D8D;SINHALA LETTER IRUYANNA;Lo;0;L;;;;;N;;;;;
+0D8E;SINHALA LETTER IRUUYANNA;Lo;0;L;;;;;N;;;;;
+0D8F;SINHALA LETTER ILUYANNA;Lo;0;L;;;;;N;;;;;
+0D90;SINHALA LETTER ILUUYANNA;Lo;0;L;;;;;N;;;;;
+0D91;SINHALA LETTER EYANNA;Lo;0;L;;;;;N;;;;;
+0D92;SINHALA LETTER EEYANNA;Lo;0;L;;;;;N;;;;;
+0D93;SINHALA LETTER AIYANNA;Lo;0;L;;;;;N;;;;;
+0D94;SINHALA LETTER OYANNA;Lo;0;L;;;;;N;;;;;
+0D95;SINHALA LETTER OOYANNA;Lo;0;L;;;;;N;;;;;
+0D96;SINHALA LETTER AUYANNA;Lo;0;L;;;;;N;;;;;
+0D9A;SINHALA LETTER ALPAPRAANA KAYANNA;Lo;0;L;;;;;N;;;;;
+0D9B;SINHALA LETTER MAHAAPRAANA KAYANNA;Lo;0;L;;;;;N;;;;;
+0D9C;SINHALA LETTER ALPAPRAANA GAYANNA;Lo;0;L;;;;;N;;;;;
+0D9D;SINHALA LETTER MAHAAPRAANA GAYANNA;Lo;0;L;;;;;N;;;;;
+0D9E;SINHALA LETTER KANTAJA NAASIKYAYA;Lo;0;L;;;;;N;;;;;
+0D9F;SINHALA LETTER SANYAKA GAYANNA;Lo;0;L;;;;;N;;;;;
+0DA0;SINHALA LETTER ALPAPRAANA CAYANNA;Lo;0;L;;;;;N;;;;;
+0DA1;SINHALA LETTER MAHAAPRAANA CAYANNA;Lo;0;L;;;;;N;;;;;
+0DA2;SINHALA LETTER ALPAPRAANA JAYANNA;Lo;0;L;;;;;N;;;;;
+0DA3;SINHALA LETTER MAHAAPRAANA JAYANNA;Lo;0;L;;;;;N;;;;;
+0DA4;SINHALA LETTER TAALUJA NAASIKYAYA;Lo;0;L;;;;;N;;;;;
+0DA5;SINHALA LETTER TAALUJA SANYOOGA NAAKSIKYAYA;Lo;0;L;;;;;N;;;;;
+0DA6;SINHALA LETTER SANYAKA JAYANNA;Lo;0;L;;;;;N;;;;;
+0DA7;SINHALA LETTER ALPAPRAANA TTAYANNA;Lo;0;L;;;;;N;;;;;
+0DA8;SINHALA LETTER MAHAAPRAANA TTAYANNA;Lo;0;L;;;;;N;;;;;
+0DA9;SINHALA LETTER ALPAPRAANA DDAYANNA;Lo;0;L;;;;;N;;;;;
+0DAA;SINHALA LETTER MAHAAPRAANA DDAYANNA;Lo;0;L;;;;;N;;;;;
+0DAB;SINHALA LETTER MUURDHAJA NAYANNA;Lo;0;L;;;;;N;;;;;
+0DAC;SINHALA LETTER SANYAKA DDAYANNA;Lo;0;L;;;;;N;;;;;
+0DAD;SINHALA LETTER ALPAPRAANA TAYANNA;Lo;0;L;;;;;N;;;;;
+0DAE;SINHALA LETTER MAHAAPRAANA TAYANNA;Lo;0;L;;;;;N;;;;;
+0DAF;SINHALA LETTER ALPAPRAANA DAYANNA;Lo;0;L;;;;;N;;;;;
+0DB0;SINHALA LETTER MAHAAPRAANA DAYANNA;Lo;0;L;;;;;N;;;;;
+0DB1;SINHALA LETTER DANTAJA NAYANNA;Lo;0;L;;;;;N;;;;;
+0DB3;SINHALA LETTER SANYAKA DAYANNA;Lo;0;L;;;;;N;;;;;
+0DB4;SINHALA LETTER ALPAPRAANA PAYANNA;Lo;0;L;;;;;N;;;;;
+0DB5;SINHALA LETTER MAHAAPRAANA PAYANNA;Lo;0;L;;;;;N;;;;;
+0DB6;SINHALA LETTER ALPAPRAANA BAYANNA;Lo;0;L;;;;;N;;;;;
+0DB7;SINHALA LETTER MAHAAPRAANA BAYANNA;Lo;0;L;;;;;N;;;;;
+0DB8;SINHALA LETTER MAYANNA;Lo;0;L;;;;;N;;;;;
+0DB9;SINHALA LETTER AMBA BAYANNA;Lo;0;L;;;;;N;;;;;
+0DBA;SINHALA LETTER YAYANNA;Lo;0;L;;;;;N;;;;;
+0DBB;SINHALA LETTER RAYANNA;Lo;0;L;;;;;N;;;;;
+0DBD;SINHALA LETTER DANTAJA LAYANNA;Lo;0;L;;;;;N;;;;;
+0DC0;SINHALA LETTER VAYANNA;Lo;0;L;;;;;N;;;;;
+0DC1;SINHALA LETTER TAALUJA SAYANNA;Lo;0;L;;;;;N;;;;;
+0DC2;SINHALA LETTER MUURDHAJA SAYANNA;Lo;0;L;;;;;N;;;;;
+0DC3;SINHALA LETTER DANTAJA SAYANNA;Lo;0;L;;;;;N;;;;;
+0DC4;SINHALA LETTER HAYANNA;Lo;0;L;;;;;N;;;;;
+0DC5;SINHALA LETTER MUURDHAJA LAYANNA;Lo;0;L;;;;;N;;;;;
+0DC6;SINHALA LETTER FAYANNA;Lo;0;L;;;;;N;;;;;
+0DCA;SINHALA SIGN AL-LAKUNA;Mn;9;NSM;;;;;N;;;;;
+0DCF;SINHALA VOWEL SIGN AELA-PILLA;Mc;0;L;;;;;N;;;;;
+0DD0;SINHALA VOWEL SIGN KETTI AEDA-PILLA;Mc;0;L;;;;;N;;;;;
+0DD1;SINHALA VOWEL SIGN DIGA AEDA-PILLA;Mc;0;L;;;;;N;;;;;
+0DD2;SINHALA VOWEL SIGN KETTI IS-PILLA;Mn;0;NSM;;;;;N;;;;;
+0DD3;SINHALA VOWEL SIGN DIGA IS-PILLA;Mn;0;NSM;;;;;N;;;;;
+0DD4;SINHALA VOWEL SIGN KETTI PAA-PILLA;Mn;0;NSM;;;;;N;;;;;
+0DD6;SINHALA VOWEL SIGN DIGA PAA-PILLA;Mn;0;NSM;;;;;N;;;;;
+0DD8;SINHALA VOWEL SIGN GAETTA-PILLA;Mc;0;L;;;;;N;;;;;
+0DD9;SINHALA VOWEL SIGN KOMBUVA;Mc;0;L;;;;;N;;;;;
+0DDA;SINHALA VOWEL SIGN DIGA KOMBUVA;Mc;0;L;0DD9 0DCA;;;;N;;;;;
+0DDB;SINHALA VOWEL SIGN KOMBU DEKA;Mc;0;L;;;;;N;;;;;
+0DDC;SINHALA VOWEL SIGN KOMBUVA HAA AELA-PILLA;Mc;0;L;0DD9 0DCF;;;;N;;;;;
+0DDD;SINHALA VOWEL SIGN KOMBUVA HAA DIGA AELA-PILLA;Mc;0;L;0DDC 0DCA;;;;N;;;;;
+0DDE;SINHALA VOWEL SIGN KOMBUVA HAA GAYANUKITTA;Mc;0;L;0DD9 0DDF;;;;N;;;;;
+0DDF;SINHALA VOWEL SIGN GAYANUKITTA;Mc;0;L;;;;;N;;;;;
+0DF2;SINHALA VOWEL SIGN DIGA GAETTA-PILLA;Mc;0;L;;;;;N;;;;;
+0DF3;SINHALA VOWEL SIGN DIGA GAYANUKITTA;Mc;0;L;;;;;N;;;;;
+0DF4;SINHALA PUNCTUATION KUNDDALIYA;Po;0;L;;;;;N;;;;;
+0E01;THAI CHARACTER KO KAI;Lo;0;L;;;;;N;THAI LETTER KO KAI;;;;
+0E02;THAI CHARACTER KHO KHAI;Lo;0;L;;;;;N;THAI LETTER KHO KHAI;;;;
+0E03;THAI CHARACTER KHO KHUAT;Lo;0;L;;;;;N;THAI LETTER KHO KHUAT;;;;
+0E04;THAI CHARACTER KHO KHWAI;Lo;0;L;;;;;N;THAI LETTER KHO KHWAI;;;;
+0E05;THAI CHARACTER KHO KHON;Lo;0;L;;;;;N;THAI LETTER KHO KHON;;;;
+0E06;THAI CHARACTER KHO RAKHANG;Lo;0;L;;;;;N;THAI LETTER KHO RAKHANG;;;;
+0E07;THAI CHARACTER NGO NGU;Lo;0;L;;;;;N;THAI LETTER NGO NGU;;;;
+0E08;THAI CHARACTER CHO CHAN;Lo;0;L;;;;;N;THAI LETTER CHO CHAN;;;;
+0E09;THAI CHARACTER CHO CHING;Lo;0;L;;;;;N;THAI LETTER CHO CHING;;;;
+0E0A;THAI CHARACTER CHO CHANG;Lo;0;L;;;;;N;THAI LETTER CHO CHANG;;;;
+0E0B;THAI CHARACTER SO SO;Lo;0;L;;;;;N;THAI LETTER SO SO;;;;
+0E0C;THAI CHARACTER CHO CHOE;Lo;0;L;;;;;N;THAI LETTER CHO CHOE;;;;
+0E0D;THAI CHARACTER YO YING;Lo;0;L;;;;;N;THAI LETTER YO YING;;;;
+0E0E;THAI CHARACTER DO CHADA;Lo;0;L;;;;;N;THAI LETTER DO CHADA;;;;
+0E0F;THAI CHARACTER TO PATAK;Lo;0;L;;;;;N;THAI LETTER TO PATAK;;;;
+0E10;THAI CHARACTER THO THAN;Lo;0;L;;;;;N;THAI LETTER THO THAN;;;;
+0E11;THAI CHARACTER THO NANGMONTHO;Lo;0;L;;;;;N;THAI LETTER THO NANGMONTHO;;;;
+0E12;THAI CHARACTER THO PHUTHAO;Lo;0;L;;;;;N;THAI LETTER THO PHUTHAO;;;;
+0E13;THAI CHARACTER NO NEN;Lo;0;L;;;;;N;THAI LETTER NO NEN;;;;
+0E14;THAI CHARACTER DO DEK;Lo;0;L;;;;;N;THAI LETTER DO DEK;;;;
+0E15;THAI CHARACTER TO TAO;Lo;0;L;;;;;N;THAI LETTER TO TAO;;;;
+0E16;THAI CHARACTER THO THUNG;Lo;0;L;;;;;N;THAI LETTER THO THUNG;;;;
+0E17;THAI CHARACTER THO THAHAN;Lo;0;L;;;;;N;THAI LETTER THO THAHAN;;;;
+0E18;THAI CHARACTER THO THONG;Lo;0;L;;;;;N;THAI LETTER THO THONG;;;;
+0E19;THAI CHARACTER NO NU;Lo;0;L;;;;;N;THAI LETTER NO NU;;;;
+0E1A;THAI CHARACTER BO BAIMAI;Lo;0;L;;;;;N;THAI LETTER BO BAIMAI;;;;
+0E1B;THAI CHARACTER PO PLA;Lo;0;L;;;;;N;THAI LETTER PO PLA;;;;
+0E1C;THAI CHARACTER PHO PHUNG;Lo;0;L;;;;;N;THAI LETTER PHO PHUNG;;;;
+0E1D;THAI CHARACTER FO FA;Lo;0;L;;;;;N;THAI LETTER FO FA;;;;
+0E1E;THAI CHARACTER PHO PHAN;Lo;0;L;;;;;N;THAI LETTER PHO PHAN;;;;
+0E1F;THAI CHARACTER FO FAN;Lo;0;L;;;;;N;THAI LETTER FO FAN;;;;
+0E20;THAI CHARACTER PHO SAMPHAO;Lo;0;L;;;;;N;THAI LETTER PHO SAMPHAO;;;;
+0E21;THAI CHARACTER MO MA;Lo;0;L;;;;;N;THAI LETTER MO MA;;;;
+0E22;THAI CHARACTER YO YAK;Lo;0;L;;;;;N;THAI LETTER YO YAK;;;;
+0E23;THAI CHARACTER RO RUA;Lo;0;L;;;;;N;THAI LETTER RO RUA;;;;
+0E24;THAI CHARACTER RU;Lo;0;L;;;;;N;THAI LETTER RU;;;;
+0E25;THAI CHARACTER LO LING;Lo;0;L;;;;;N;THAI LETTER LO LING;;;;
+0E26;THAI CHARACTER LU;Lo;0;L;;;;;N;THAI LETTER LU;;;;
+0E27;THAI CHARACTER WO WAEN;Lo;0;L;;;;;N;THAI LETTER WO WAEN;;;;
+0E28;THAI CHARACTER SO SALA;Lo;0;L;;;;;N;THAI LETTER SO SALA;;;;
+0E29;THAI CHARACTER SO RUSI;Lo;0;L;;;;;N;THAI LETTER SO RUSI;;;;
+0E2A;THAI CHARACTER SO SUA;Lo;0;L;;;;;N;THAI LETTER SO SUA;;;;
+0E2B;THAI CHARACTER HO HIP;Lo;0;L;;;;;N;THAI LETTER HO HIP;;;;
+0E2C;THAI CHARACTER LO CHULA;Lo;0;L;;;;;N;THAI LETTER LO CHULA;;;;
+0E2D;THAI CHARACTER O ANG;Lo;0;L;;;;;N;THAI LETTER O ANG;;;;
+0E2E;THAI CHARACTER HO NOKHUK;Lo;0;L;;;;;N;THAI LETTER HO NOK HUK;;;;
+0E2F;THAI CHARACTER PAIYANNOI;Lo;0;L;;;;;N;THAI PAI YAN NOI;paiyan noi;;;
+0E30;THAI CHARACTER SARA A;Lo;0;L;;;;;N;THAI VOWEL SIGN SARA A;;;;
+0E31;THAI CHARACTER MAI HAN-AKAT;Mn;0;NSM;;;;;N;THAI VOWEL SIGN MAI HAN-AKAT;;;;
+0E32;THAI CHARACTER SARA AA;Lo;0;L;;;;;N;THAI VOWEL SIGN SARA AA;;;;
+0E33;THAI CHARACTER SARA AM;Lo;0;L;<compat> 0E4D 0E32;;;;N;THAI VOWEL SIGN SARA AM;;;;
+0E34;THAI CHARACTER SARA I;Mn;0;NSM;;;;;N;THAI VOWEL SIGN SARA I;;;;
+0E35;THAI CHARACTER SARA II;Mn;0;NSM;;;;;N;THAI VOWEL SIGN SARA II;;;;
+0E36;THAI CHARACTER SARA UE;Mn;0;NSM;;;;;N;THAI VOWEL SIGN SARA UE;;;;
+0E37;THAI CHARACTER SARA UEE;Mn;0;NSM;;;;;N;THAI VOWEL SIGN SARA UEE;sara uue;;;
+0E38;THAI CHARACTER SARA U;Mn;103;NSM;;;;;N;THAI VOWEL SIGN SARA U;;;;
+0E39;THAI CHARACTER SARA UU;Mn;103;NSM;;;;;N;THAI VOWEL SIGN SARA UU;;;;
+0E3A;THAI CHARACTER PHINTHU;Mn;9;NSM;;;;;N;THAI VOWEL SIGN PHINTHU;;;;
+0E3F;THAI CURRENCY SYMBOL BAHT;Sc;0;ET;;;;;N;THAI BAHT SIGN;;;;
+0E40;THAI CHARACTER SARA E;Lo;0;L;;;;;N;THAI VOWEL SIGN SARA E;;;;
+0E41;THAI CHARACTER SARA AE;Lo;0;L;;;;;N;THAI VOWEL SIGN SARA AE;;;;
+0E42;THAI CHARACTER SARA O;Lo;0;L;;;;;N;THAI VOWEL SIGN SARA O;;;;
+0E43;THAI CHARACTER SARA AI MAIMUAN;Lo;0;L;;;;;N;THAI VOWEL SIGN SARA MAI MUAN;sara ai mai muan;;;
+0E44;THAI CHARACTER SARA AI MAIMALAI;Lo;0;L;;;;;N;THAI VOWEL SIGN SARA MAI MALAI;sara ai mai malai;;;
+0E45;THAI CHARACTER LAKKHANGYAO;Lo;0;L;;;;;N;THAI LAK KHANG YAO;lakkhang yao;;;
+0E46;THAI CHARACTER MAIYAMOK;Lm;0;L;;;;;N;THAI MAI YAMOK;mai yamok;;;
+0E47;THAI CHARACTER MAITAIKHU;Mn;0;NSM;;;;;N;THAI VOWEL SIGN MAI TAI KHU;mai taikhu;;;
+0E48;THAI CHARACTER MAI EK;Mn;107;NSM;;;;;N;THAI TONE MAI EK;;;;
+0E49;THAI CHARACTER MAI THO;Mn;107;NSM;;;;;N;THAI TONE MAI THO;;;;
+0E4A;THAI CHARACTER MAI TRI;Mn;107;NSM;;;;;N;THAI TONE MAI TRI;;;;
+0E4B;THAI CHARACTER MAI CHATTAWA;Mn;107;NSM;;;;;N;THAI TONE MAI CHATTAWA;;;;
+0E4C;THAI CHARACTER THANTHAKHAT;Mn;0;NSM;;;;;N;THAI THANTHAKHAT;;;;
+0E4D;THAI CHARACTER NIKHAHIT;Mn;0;NSM;;;;;N;THAI NIKKHAHIT;nikkhahit;;;
+0E4E;THAI CHARACTER YAMAKKAN;Mn;0;NSM;;;;;N;THAI YAMAKKAN;;;;
+0E4F;THAI CHARACTER FONGMAN;Po;0;L;;;;;N;THAI FONGMAN;;;;
+0E50;THAI DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+0E51;THAI DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+0E52;THAI DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+0E53;THAI DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+0E54;THAI DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+0E55;THAI DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+0E56;THAI DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+0E57;THAI DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+0E58;THAI DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+0E59;THAI DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+0E5A;THAI CHARACTER ANGKHANKHU;Po;0;L;;;;;N;THAI ANGKHANKHU;;;;
+0E5B;THAI CHARACTER KHOMUT;Po;0;L;;;;;N;THAI KHOMUT;;;;
+0E81;LAO LETTER KO;Lo;0;L;;;;;N;;;;;
+0E82;LAO LETTER KHO SUNG;Lo;0;L;;;;;N;;;;;
+0E84;LAO LETTER KHO TAM;Lo;0;L;;;;;N;;;;;
+0E87;LAO LETTER NGO;Lo;0;L;;;;;N;;;;;
+0E88;LAO LETTER CO;Lo;0;L;;;;;N;;;;;
+0E8A;LAO LETTER SO TAM;Lo;0;L;;;;;N;;;;;
+0E8D;LAO LETTER NYO;Lo;0;L;;;;;N;;;;;
+0E94;LAO LETTER DO;Lo;0;L;;;;;N;;;;;
+0E95;LAO LETTER TO;Lo;0;L;;;;;N;;;;;
+0E96;LAO LETTER THO SUNG;Lo;0;L;;;;;N;;;;;
+0E97;LAO LETTER THO TAM;Lo;0;L;;;;;N;;;;;
+0E99;LAO LETTER NO;Lo;0;L;;;;;N;;;;;
+0E9A;LAO LETTER BO;Lo;0;L;;;;;N;;;;;
+0E9B;LAO LETTER PO;Lo;0;L;;;;;N;;;;;
+0E9C;LAO LETTER PHO SUNG;Lo;0;L;;;;;N;;;;;
+0E9D;LAO LETTER FO TAM;Lo;0;L;;;;;N;;;;;
+0E9E;LAO LETTER PHO TAM;Lo;0;L;;;;;N;;;;;
+0E9F;LAO LETTER FO SUNG;Lo;0;L;;;;;N;;;;;
+0EA1;LAO LETTER MO;Lo;0;L;;;;;N;;;;;
+0EA2;LAO LETTER YO;Lo;0;L;;;;;N;;;;;
+0EA3;LAO LETTER LO LING;Lo;0;L;;;;;N;;;;;
+0EA5;LAO LETTER LO LOOT;Lo;0;L;;;;;N;;;;;
+0EA7;LAO LETTER WO;Lo;0;L;;;;;N;;;;;
+0EAA;LAO LETTER SO SUNG;Lo;0;L;;;;;N;;;;;
+0EAB;LAO LETTER HO SUNG;Lo;0;L;;;;;N;;;;;
+0EAD;LAO LETTER O;Lo;0;L;;;;;N;;;;;
+0EAE;LAO LETTER HO TAM;Lo;0;L;;;;;N;;;;;
+0EAF;LAO ELLIPSIS;Lo;0;L;;;;;N;;;;;
+0EB0;LAO VOWEL SIGN A;Lo;0;L;;;;;N;;;;;
+0EB1;LAO VOWEL SIGN MAI KAN;Mn;0;NSM;;;;;N;;;;;
+0EB2;LAO VOWEL SIGN AA;Lo;0;L;;;;;N;;;;;
+0EB3;LAO VOWEL SIGN AM;Lo;0;L;<compat> 0ECD 0EB2;;;;N;;;;;
+0EB4;LAO VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;;
+0EB5;LAO VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;;
+0EB6;LAO VOWEL SIGN Y;Mn;0;NSM;;;;;N;;;;;
+0EB7;LAO VOWEL SIGN YY;Mn;0;NSM;;;;;N;;;;;
+0EB8;LAO VOWEL SIGN U;Mn;118;NSM;;;;;N;;;;;
+0EB9;LAO VOWEL SIGN UU;Mn;118;NSM;;;;;N;;;;;
+0EBB;LAO VOWEL SIGN MAI KON;Mn;0;NSM;;;;;N;;;;;
+0EBC;LAO SEMIVOWEL SIGN LO;Mn;0;NSM;;;;;N;;;;;
+0EBD;LAO SEMIVOWEL SIGN NYO;Lo;0;L;;;;;N;;;;;
+0EC0;LAO VOWEL SIGN E;Lo;0;L;;;;;N;;;;;
+0EC1;LAO VOWEL SIGN EI;Lo;0;L;;;;;N;;;;;
+0EC2;LAO VOWEL SIGN O;Lo;0;L;;;;;N;;;;;
+0EC3;LAO VOWEL SIGN AY;Lo;0;L;;;;;N;;;;;
+0EC4;LAO VOWEL SIGN AI;Lo;0;L;;;;;N;;;;;
+0EC6;LAO KO LA;Lm;0;L;;;;;N;;;;;
+0EC8;LAO TONE MAI EK;Mn;122;NSM;;;;;N;;;;;
+0EC9;LAO TONE MAI THO;Mn;122;NSM;;;;;N;;;;;
+0ECA;LAO TONE MAI TI;Mn;122;NSM;;;;;N;;;;;
+0ECB;LAO TONE MAI CATAWA;Mn;122;NSM;;;;;N;;;;;
+0ECC;LAO CANCELLATION MARK;Mn;0;NSM;;;;;N;;;;;
+0ECD;LAO NIGGAHITA;Mn;0;NSM;;;;;N;;;;;
+0ED0;LAO DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+0ED1;LAO DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+0ED2;LAO DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+0ED3;LAO DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+0ED4;LAO DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+0ED5;LAO DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+0ED6;LAO DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+0ED7;LAO DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+0ED8;LAO DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+0ED9;LAO DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+0EDC;LAO HO NO;Lo;0;L;<compat> 0EAB 0E99;;;;N;;;;;
+0EDD;LAO HO MO;Lo;0;L;<compat> 0EAB 0EA1;;;;N;;;;;
+0F00;TIBETAN SYLLABLE OM;Lo;0;L;;;;;N;;;;;
+0F01;TIBETAN MARK GTER YIG MGO TRUNCATED A;So;0;L;;;;;N;;ter yik go a thung;;;
+0F02;TIBETAN MARK GTER YIG MGO -UM RNAM BCAD MA;So;0;L;;;;;N;;ter yik go wum nam chey ma;;;
+0F03;TIBETAN MARK GTER YIG MGO -UM GTER TSHEG MA;So;0;L;;;;;N;;ter yik go wum ter tsek ma;;;
+0F04;TIBETAN MARK INITIAL YIG MGO MDUN MA;Po;0;L;;;;;N;TIBETAN SINGLE ORNAMENT;yik go dun ma;;;
+0F05;TIBETAN MARK CLOSING YIG MGO SGAB MA;Po;0;L;;;;;N;;yik go kab ma;;;
+0F06;TIBETAN MARK CARET YIG MGO PHUR SHAD MA;Po;0;L;;;;;N;;yik go pur shey ma;;;
+0F07;TIBETAN MARK YIG MGO TSHEG SHAD MA;Po;0;L;;;;;N;;yik go tsek shey ma;;;
+0F08;TIBETAN MARK SBRUL SHAD;Po;0;L;;;;;N;TIBETAN RGYANSHAD;drul shey;;;
+0F09;TIBETAN MARK BSKUR YIG MGO;Po;0;L;;;;;N;;kur yik go;;;
+0F0A;TIBETAN MARK BKA- SHOG YIG MGO;Po;0;L;;;;;N;;ka sho yik go;;;
+0F0B;TIBETAN MARK INTERSYLLABIC TSHEG;Po;0;L;;;;;N;TIBETAN TSEG;tsek;;;
+0F0C;TIBETAN MARK DELIMITER TSHEG BSTAR;Po;0;L;<noBreak> 0F0B;;;;N;;tsek tar;;;
+0F0D;TIBETAN MARK SHAD;Po;0;L;;;;;N;TIBETAN SHAD;shey;;;
+0F0E;TIBETAN MARK NYIS SHAD;Po;0;L;;;;;N;TIBETAN DOUBLE SHAD;nyi shey;;;
+0F0F;TIBETAN MARK TSHEG SHAD;Po;0;L;;;;;N;;tsek shey;;;
+0F10;TIBETAN MARK NYIS TSHEG SHAD;Po;0;L;;;;;N;;nyi tsek shey;;;
+0F11;TIBETAN MARK RIN CHEN SPUNGS SHAD;Po;0;L;;;;;N;TIBETAN RINCHANPHUNGSHAD;rinchen pung shey;;;
+0F12;TIBETAN MARK RGYA GRAM SHAD;Po;0;L;;;;;N;;gya tram shey;;;
+0F13;TIBETAN MARK CARET -DZUD RTAGS ME LONG CAN;So;0;L;;;;;N;;dzu ta me long chen;;;
+0F14;TIBETAN MARK GTER TSHEG;So;0;L;;;;;N;TIBETAN COMMA;ter tsek;;;
+0F15;TIBETAN LOGOTYPE SIGN CHAD RTAGS;So;0;L;;;;;N;;che ta;;;
+0F16;TIBETAN LOGOTYPE SIGN LHAG RTAGS;So;0;L;;;;;N;;hlak ta;;;
+0F17;TIBETAN ASTROLOGICAL SIGN SGRA GCAN -CHAR RTAGS;So;0;L;;;;;N;;trachen char ta;;;
+0F18;TIBETAN ASTROLOGICAL SIGN -KHYUD PA;Mn;220;NSM;;;;;N;;kyu pa;;;
+0F19;TIBETAN ASTROLOGICAL SIGN SDONG TSHUGS;Mn;220;NSM;;;;;N;;dong tsu;;;
+0F1A;TIBETAN SIGN RDEL DKAR GCIG;So;0;L;;;;;N;;deka chig;;;
+0F1B;TIBETAN SIGN RDEL DKAR GNYIS;So;0;L;;;;;N;;deka nyi;;;
+0F1C;TIBETAN SIGN RDEL DKAR GSUM;So;0;L;;;;;N;;deka sum;;;
+0F1D;TIBETAN SIGN RDEL NAG GCIG;So;0;L;;;;;N;;dena chig;;;
+0F1E;TIBETAN SIGN RDEL NAG GNYIS;So;0;L;;;;;N;;dena nyi;;;
+0F1F;TIBETAN SIGN RDEL DKAR RDEL NAG;So;0;L;;;;;N;;deka dena;;;
+0F20;TIBETAN DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+0F21;TIBETAN DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+0F22;TIBETAN DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+0F23;TIBETAN DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+0F24;TIBETAN DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+0F25;TIBETAN DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+0F26;TIBETAN DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+0F27;TIBETAN DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+0F28;TIBETAN DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+0F29;TIBETAN DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+0F2A;TIBETAN DIGIT HALF ONE;No;0;L;;;;1/2;N;;;;;
+0F2B;TIBETAN DIGIT HALF TWO;No;0;L;;;;3/2;N;;;;;
+0F2C;TIBETAN DIGIT HALF THREE;No;0;L;;;;5/2;N;;;;;
+0F2D;TIBETAN DIGIT HALF FOUR;No;0;L;;;;7/2;N;;;;;
+0F2E;TIBETAN DIGIT HALF FIVE;No;0;L;;;;9/2;N;;;;;
+0F2F;TIBETAN DIGIT HALF SIX;No;0;L;;;;11/2;N;;;;;
+0F30;TIBETAN DIGIT HALF SEVEN;No;0;L;;;;13/2;N;;;;;
+0F31;TIBETAN DIGIT HALF EIGHT;No;0;L;;;;15/2;N;;;;;
+0F32;TIBETAN DIGIT HALF NINE;No;0;L;;;;17/2;N;;;;;
+0F33;TIBETAN DIGIT HALF ZERO;No;0;L;;;;-1/2;N;;;;;
+0F34;TIBETAN MARK BSDUS RTAGS;So;0;L;;;;;N;;du ta;;;
+0F35;TIBETAN MARK NGAS BZUNG NYI ZLA;Mn;220;NSM;;;;;N;TIBETAN HONORIFIC UNDER RING;nge zung nyi da;;;
+0F36;TIBETAN MARK CARET -DZUD RTAGS BZHI MIG CAN;So;0;L;;;;;N;;dzu ta shi mig chen;;;
+0F37;TIBETAN MARK NGAS BZUNG SGOR RTAGS;Mn;220;NSM;;;;;N;TIBETAN UNDER RING;nge zung gor ta;;;
+0F38;TIBETAN MARK CHE MGO;So;0;L;;;;;N;;che go;;;
+0F39;TIBETAN MARK TSA -PHRU;Mn;216;NSM;;;;;N;TIBETAN LENITION MARK;tsa tru;;;
+0F3A;TIBETAN MARK GUG RTAGS GYON;Ps;0;ON;;;;;N;;gug ta yun;;;
+0F3B;TIBETAN MARK GUG RTAGS GYAS;Pe;0;ON;;;;;N;;gug ta ye;;;
+0F3C;TIBETAN MARK ANG KHANG GYON;Ps;0;ON;;;;;N;TIBETAN LEFT BRACE;ang kang yun;;;
+0F3D;TIBETAN MARK ANG KHANG GYAS;Pe;0;ON;;;;;N;TIBETAN RIGHT BRACE;ang kang ye;;;
+0F3E;TIBETAN SIGN YAR TSHES;Mc;0;L;;;;;N;;yar tse;;;
+0F3F;TIBETAN SIGN MAR TSHES;Mc;0;L;;;;;N;;mar tse;;;
+0F40;TIBETAN LETTER KA;Lo;0;L;;;;;N;;;;;
+0F41;TIBETAN LETTER KHA;Lo;0;L;;;;;N;;;;;
+0F42;TIBETAN LETTER GA;Lo;0;L;;;;;N;;;;;
+0F43;TIBETAN LETTER GHA;Lo;0;L;0F42 0FB7;;;;N;;;;;
+0F44;TIBETAN LETTER NGA;Lo;0;L;;;;;N;;;;;
+0F45;TIBETAN LETTER CA;Lo;0;L;;;;;N;;;;;
+0F46;TIBETAN LETTER CHA;Lo;0;L;;;;;N;;;;;
+0F47;TIBETAN LETTER JA;Lo;0;L;;;;;N;;;;;
+0F49;TIBETAN LETTER NYA;Lo;0;L;;;;;N;;;;;
+0F4A;TIBETAN LETTER TTA;Lo;0;L;;;;;N;TIBETAN LETTER REVERSED TA;;;;
+0F4B;TIBETAN LETTER TTHA;Lo;0;L;;;;;N;TIBETAN LETTER REVERSED THA;;;;
+0F4C;TIBETAN LETTER DDA;Lo;0;L;;;;;N;TIBETAN LETTER REVERSED DA;;;;
+0F4D;TIBETAN LETTER DDHA;Lo;0;L;0F4C 0FB7;;;;N;;;;;
+0F4E;TIBETAN LETTER NNA;Lo;0;L;;;;;N;TIBETAN LETTER REVERSED NA;;;;
+0F4F;TIBETAN LETTER TA;Lo;0;L;;;;;N;;;;;
+0F50;TIBETAN LETTER THA;Lo;0;L;;;;;N;;;;;
+0F51;TIBETAN LETTER DA;Lo;0;L;;;;;N;;;;;
+0F52;TIBETAN LETTER DHA;Lo;0;L;0F51 0FB7;;;;N;;;;;
+0F53;TIBETAN LETTER NA;Lo;0;L;;;;;N;;;;;
+0F54;TIBETAN LETTER PA;Lo;0;L;;;;;N;;;;;
+0F55;TIBETAN LETTER PHA;Lo;0;L;;;;;N;;;;;
+0F56;TIBETAN LETTER BA;Lo;0;L;;;;;N;;;;;
+0F57;TIBETAN LETTER BHA;Lo;0;L;0F56 0FB7;;;;N;;;;;
+0F58;TIBETAN LETTER MA;Lo;0;L;;;;;N;;;;;
+0F59;TIBETAN LETTER TSA;Lo;0;L;;;;;N;;;;;
+0F5A;TIBETAN LETTER TSHA;Lo;0;L;;;;;N;;;;;
+0F5B;TIBETAN LETTER DZA;Lo;0;L;;;;;N;;;;;
+0F5C;TIBETAN LETTER DZHA;Lo;0;L;0F5B 0FB7;;;;N;;;;;
+0F5D;TIBETAN LETTER WA;Lo;0;L;;;;;N;;;;;
+0F5E;TIBETAN LETTER ZHA;Lo;0;L;;;;;N;;;;;
+0F5F;TIBETAN LETTER ZA;Lo;0;L;;;;;N;;;;;
+0F60;TIBETAN LETTER -A;Lo;0;L;;;;;N;TIBETAN LETTER AA;;;;
+0F61;TIBETAN LETTER YA;Lo;0;L;;;;;N;;;;;
+0F62;TIBETAN LETTER RA;Lo;0;L;;;;;N;;*;;;
+0F63;TIBETAN LETTER LA;Lo;0;L;;;;;N;;;;;
+0F64;TIBETAN LETTER SHA;Lo;0;L;;;;;N;;;;;
+0F65;TIBETAN LETTER SSA;Lo;0;L;;;;;N;TIBETAN LETTER REVERSED SHA;;;;
+0F66;TIBETAN LETTER SA;Lo;0;L;;;;;N;;;;;
+0F67;TIBETAN LETTER HA;Lo;0;L;;;;;N;;;;;
+0F68;TIBETAN LETTER A;Lo;0;L;;;;;N;;;;;
+0F69;TIBETAN LETTER KSSA;Lo;0;L;0F40 0FB5;;;;N;;;;;
+0F6A;TIBETAN LETTER FIXED-FORM RA;Lo;0;L;;;;;N;;*;;;
+0F71;TIBETAN VOWEL SIGN AA;Mn;129;NSM;;;;;N;;;;;
+0F72;TIBETAN VOWEL SIGN I;Mn;130;NSM;;;;;N;;;;;
+0F73;TIBETAN VOWEL SIGN II;Mn;0;NSM;0F71 0F72;;;;N;;;;;
+0F74;TIBETAN VOWEL SIGN U;Mn;132;NSM;;;;;N;;;;;
+0F75;TIBETAN VOWEL SIGN UU;Mn;0;NSM;0F71 0F74;;;;N;;;;;
+0F76;TIBETAN VOWEL SIGN VOCALIC R;Mn;0;NSM;0FB2 0F80;;;;N;;;;;
+0F77;TIBETAN VOWEL SIGN VOCALIC RR;Mn;0;NSM;<compat> 0FB2 0F81;;;;N;;;;;
+0F78;TIBETAN VOWEL SIGN VOCALIC L;Mn;0;NSM;0FB3 0F80;;;;N;;;;;
+0F79;TIBETAN VOWEL SIGN VOCALIC LL;Mn;0;NSM;<compat> 0FB3 0F81;;;;N;;;;;
+0F7A;TIBETAN VOWEL SIGN E;Mn;130;NSM;;;;;N;;;;;
+0F7B;TIBETAN VOWEL SIGN EE;Mn;130;NSM;;;;;N;TIBETAN VOWEL SIGN AI;;;;
+0F7C;TIBETAN VOWEL SIGN O;Mn;130;NSM;;;;;N;;;;;
+0F7D;TIBETAN VOWEL SIGN OO;Mn;130;NSM;;;;;N;TIBETAN VOWEL SIGN AU;;;;
+0F7E;TIBETAN SIGN RJES SU NGA RO;Mn;0;NSM;;;;;N;TIBETAN ANUSVARA;je su nga ro;;;
+0F7F;TIBETAN SIGN RNAM BCAD;Mc;0;L;;;;;N;TIBETAN VISARGA;nam chey;;;
+0F80;TIBETAN VOWEL SIGN REVERSED I;Mn;130;NSM;;;;;N;TIBETAN VOWEL SIGN SHORT I;;;;
+0F81;TIBETAN VOWEL SIGN REVERSED II;Mn;0;NSM;0F71 0F80;;;;N;;;;;
+0F82;TIBETAN SIGN NYI ZLA NAA DA;Mn;230;NSM;;;;;N;TIBETAN CANDRABINDU WITH ORNAMENT;nyi da na da;;;
+0F83;TIBETAN SIGN SNA LDAN;Mn;230;NSM;;;;;N;TIBETAN CANDRABINDU;nan de;;;
+0F84;TIBETAN MARK HALANTA;Mn;9;NSM;;;;;N;TIBETAN VIRAMA;;;;
+0F85;TIBETAN MARK PALUTA;Po;0;L;;;;;N;TIBETAN CHUCHENYIGE;;;;
+0F86;TIBETAN SIGN LCI RTAGS;Mn;230;NSM;;;;;N;;ji ta;;;
+0F87;TIBETAN SIGN YANG RTAGS;Mn;230;NSM;;;;;N;;yang ta;;;
+0F88;TIBETAN SIGN LCE TSA CAN;Lo;0;L;;;;;N;;che tsa chen;;;
+0F89;TIBETAN SIGN MCHU CAN;Lo;0;L;;;;;N;;chu chen;;;
+0F8A;TIBETAN SIGN GRU CAN RGYINGS;Lo;0;L;;;;;N;;tru chen ging;;;
+0F8B;TIBETAN SIGN GRU MED RGYINGS;Lo;0;L;;;;;N;;tru me ging;;;
+0F90;TIBETAN SUBJOINED LETTER KA;Mn;0;NSM;;;;;N;;;;;
+0F91;TIBETAN SUBJOINED LETTER KHA;Mn;0;NSM;;;;;N;;;;;
+0F92;TIBETAN SUBJOINED LETTER GA;Mn;0;NSM;;;;;N;;;;;
+0F93;TIBETAN SUBJOINED LETTER GHA;Mn;0;NSM;0F92 0FB7;;;;N;;;;;
+0F94;TIBETAN SUBJOINED LETTER NGA;Mn;0;NSM;;;;;N;;;;;
+0F95;TIBETAN SUBJOINED LETTER CA;Mn;0;NSM;;;;;N;;;;;
+0F96;TIBETAN SUBJOINED LETTER CHA;Mn;0;NSM;;;;;N;;;;;
+0F97;TIBETAN SUBJOINED LETTER JA;Mn;0;NSM;;;;;N;;;;;
+0F99;TIBETAN SUBJOINED LETTER NYA;Mn;0;NSM;;;;;N;;;;;
+0F9A;TIBETAN SUBJOINED LETTER TTA;Mn;0;NSM;;;;;N;;;;;
+0F9B;TIBETAN SUBJOINED LETTER TTHA;Mn;0;NSM;;;;;N;;;;;
+0F9C;TIBETAN SUBJOINED LETTER DDA;Mn;0;NSM;;;;;N;;;;;
+0F9D;TIBETAN SUBJOINED LETTER DDHA;Mn;0;NSM;0F9C 0FB7;;;;N;;;;;
+0F9E;TIBETAN SUBJOINED LETTER NNA;Mn;0;NSM;;;;;N;;;;;
+0F9F;TIBETAN SUBJOINED LETTER TA;Mn;0;NSM;;;;;N;;;;;
+0FA0;TIBETAN SUBJOINED LETTER THA;Mn;0;NSM;;;;;N;;;;;
+0FA1;TIBETAN SUBJOINED LETTER DA;Mn;0;NSM;;;;;N;;;;;
+0FA2;TIBETAN SUBJOINED LETTER DHA;Mn;0;NSM;0FA1 0FB7;;;;N;;;;;
+0FA3;TIBETAN SUBJOINED LETTER NA;Mn;0;NSM;;;;;N;;;;;
+0FA4;TIBETAN SUBJOINED LETTER PA;Mn;0;NSM;;;;;N;;;;;
+0FA5;TIBETAN SUBJOINED LETTER PHA;Mn;0;NSM;;;;;N;;;;;
+0FA6;TIBETAN SUBJOINED LETTER BA;Mn;0;NSM;;;;;N;;;;;
+0FA7;TIBETAN SUBJOINED LETTER BHA;Mn;0;NSM;0FA6 0FB7;;;;N;;;;;
+0FA8;TIBETAN SUBJOINED LETTER MA;Mn;0;NSM;;;;;N;;;;;
+0FA9;TIBETAN SUBJOINED LETTER TSA;Mn;0;NSM;;;;;N;;;;;
+0FAA;TIBETAN SUBJOINED LETTER TSHA;Mn;0;NSM;;;;;N;;;;;
+0FAB;TIBETAN SUBJOINED LETTER DZA;Mn;0;NSM;;;;;N;;;;;
+0FAC;TIBETAN SUBJOINED LETTER DZHA;Mn;0;NSM;0FAB 0FB7;;;;N;;;;;
+0FAD;TIBETAN SUBJOINED LETTER WA;Mn;0;NSM;;;;;N;;*;;;
+0FAE;TIBETAN SUBJOINED LETTER ZHA;Mn;0;NSM;;;;;N;;;;;
+0FAF;TIBETAN SUBJOINED LETTER ZA;Mn;0;NSM;;;;;N;;;;;
+0FB0;TIBETAN SUBJOINED LETTER -A;Mn;0;NSM;;;;;N;;;;;
+0FB1;TIBETAN SUBJOINED LETTER YA;Mn;0;NSM;;;;;N;;*;;;
+0FB2;TIBETAN SUBJOINED LETTER RA;Mn;0;NSM;;;;;N;;*;;;
+0FB3;TIBETAN SUBJOINED LETTER LA;Mn;0;NSM;;;;;N;;;;;
+0FB4;TIBETAN SUBJOINED LETTER SHA;Mn;0;NSM;;;;;N;;;;;
+0FB5;TIBETAN SUBJOINED LETTER SSA;Mn;0;NSM;;;;;N;;;;;
+0FB6;TIBETAN SUBJOINED LETTER SA;Mn;0;NSM;;;;;N;;;;;
+0FB7;TIBETAN SUBJOINED LETTER HA;Mn;0;NSM;;;;;N;;;;;
+0FB8;TIBETAN SUBJOINED LETTER A;Mn;0;NSM;;;;;N;;;;;
+0FB9;TIBETAN SUBJOINED LETTER KSSA;Mn;0;NSM;0F90 0FB5;;;;N;;;;;
+0FBA;TIBETAN SUBJOINED LETTER FIXED-FORM WA;Mn;0;NSM;;;;;N;;*;;;
+0FBB;TIBETAN SUBJOINED LETTER FIXED-FORM YA;Mn;0;NSM;;;;;N;;*;;;
+0FBC;TIBETAN SUBJOINED LETTER FIXED-FORM RA;Mn;0;NSM;;;;;N;;*;;;
+0FBE;TIBETAN KU RU KHA;So;0;L;;;;;N;;kuruka;;;
+0FBF;TIBETAN KU RU KHA BZHI MIG CAN;So;0;L;;;;;N;;kuruka shi mik chen;;;
+0FC0;TIBETAN CANTILLATION SIGN HEAVY BEAT;So;0;L;;;;;N;;;;;
+0FC1;TIBETAN CANTILLATION SIGN LIGHT BEAT;So;0;L;;;;;N;;;;;
+0FC2;TIBETAN CANTILLATION SIGN CANG TE-U;So;0;L;;;;;N;;chang tyu;;;
+0FC3;TIBETAN CANTILLATION SIGN SBUB -CHAL;So;0;L;;;;;N;;bub chey;;;
+0FC4;TIBETAN SYMBOL DRIL BU;So;0;L;;;;;N;;drilbu;;;
+0FC5;TIBETAN SYMBOL RDO RJE;So;0;L;;;;;N;;dorje;;;
+0FC6;TIBETAN SYMBOL PADMA GDAN;Mn;220;NSM;;;;;N;;pema den;;;
+0FC7;TIBETAN SYMBOL RDO RJE RGYA GRAM;So;0;L;;;;;N;;dorje gya dram;;;
+0FC8;TIBETAN SYMBOL PHUR PA;So;0;L;;;;;N;;phurba;;;
+0FC9;TIBETAN SYMBOL NOR BU;So;0;L;;;;;N;;norbu;;;
+0FCA;TIBETAN SYMBOL NOR BU NYIS -KHYIL;So;0;L;;;;;N;;norbu nyi khyi;;;
+0FCB;TIBETAN SYMBOL NOR BU GSUM -KHYIL;So;0;L;;;;;N;;norbu sum khyi;;;
+0FCC;TIBETAN SYMBOL NOR BU BZHI -KHYIL;So;0;L;;;;;N;;norbu shi khyi;;;
+0FCF;TIBETAN SIGN RDEL NAG GSUM;So;0;L;;;;;N;;dena sum;;;
+1000;MYANMAR LETTER KA;Lo;0;L;;;;;N;;;;;
+1001;MYANMAR LETTER KHA;Lo;0;L;;;;;N;;;;;
+1002;MYANMAR LETTER GA;Lo;0;L;;;;;N;;;;;
+1003;MYANMAR LETTER GHA;Lo;0;L;;;;;N;;;;;
+1004;MYANMAR LETTER NGA;Lo;0;L;;;;;N;;;;;
+1005;MYANMAR LETTER CA;Lo;0;L;;;;;N;;;;;
+1006;MYANMAR LETTER CHA;Lo;0;L;;;;;N;;;;;
+1007;MYANMAR LETTER JA;Lo;0;L;;;;;N;;;;;
+1008;MYANMAR LETTER JHA;Lo;0;L;;;;;N;;;;;
+1009;MYANMAR LETTER NYA;Lo;0;L;;;;;N;;;;;
+100A;MYANMAR LETTER NNYA;Lo;0;L;;;;;N;;;;;
+100B;MYANMAR LETTER TTA;Lo;0;L;;;;;N;;;;;
+100C;MYANMAR LETTER TTHA;Lo;0;L;;;;;N;;;;;
+100D;MYANMAR LETTER DDA;Lo;0;L;;;;;N;;;;;
+100E;MYANMAR LETTER DDHA;Lo;0;L;;;;;N;;;;;
+100F;MYANMAR LETTER NNA;Lo;0;L;;;;;N;;;;;
+1010;MYANMAR LETTER TA;Lo;0;L;;;;;N;;;;;
+1011;MYANMAR LETTER THA;Lo;0;L;;;;;N;;;;;
+1012;MYANMAR LETTER DA;Lo;0;L;;;;;N;;;;;
+1013;MYANMAR LETTER DHA;Lo;0;L;;;;;N;;;;;
+1014;MYANMAR LETTER NA;Lo;0;L;;;;;N;;;;;
+1015;MYANMAR LETTER PA;Lo;0;L;;;;;N;;;;;
+1016;MYANMAR LETTER PHA;Lo;0;L;;;;;N;;;;;
+1017;MYANMAR LETTER BA;Lo;0;L;;;;;N;;;;;
+1018;MYANMAR LETTER BHA;Lo;0;L;;;;;N;;;;;
+1019;MYANMAR LETTER MA;Lo;0;L;;;;;N;;;;;
+101A;MYANMAR LETTER YA;Lo;0;L;;;;;N;;;;;
+101B;MYANMAR LETTER RA;Lo;0;L;;;;;N;;;;;
+101C;MYANMAR LETTER LA;Lo;0;L;;;;;N;;;;;
+101D;MYANMAR LETTER WA;Lo;0;L;;;;;N;;;;;
+101E;MYANMAR LETTER SA;Lo;0;L;;;;;N;;;;;
+101F;MYANMAR LETTER HA;Lo;0;L;;;;;N;;;;;
+1020;MYANMAR LETTER LLA;Lo;0;L;;;;;N;;;;;
+1021;MYANMAR LETTER A;Lo;0;L;;;;;N;;;;;
+1023;MYANMAR LETTER I;Lo;0;L;;;;;N;;;;;
+1024;MYANMAR LETTER II;Lo;0;L;;;;;N;;;;;
+1025;MYANMAR LETTER U;Lo;0;L;;;;;N;;;;;
+1026;MYANMAR LETTER UU;Lo;0;L;1025 102E;;;;N;;;;;
+1027;MYANMAR LETTER E;Lo;0;L;;;;;N;;;;;
+1029;MYANMAR LETTER O;Lo;0;L;;;;;N;;;;;
+102A;MYANMAR LETTER AU;Lo;0;L;;;;;N;;;;;
+102C;MYANMAR VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;
+102D;MYANMAR VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;;
+102E;MYANMAR VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;;
+102F;MYANMAR VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;
+1030;MYANMAR VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;;
+1031;MYANMAR VOWEL SIGN E;Mc;0;L;;;;;N;;;;;
+1032;MYANMAR VOWEL SIGN AI;Mn;0;NSM;;;;;N;;;;;
+1036;MYANMAR SIGN ANUSVARA;Mn;0;NSM;;;;;N;;;;;
+1037;MYANMAR SIGN DOT BELOW;Mn;7;NSM;;;;;N;;;;;
+1038;MYANMAR SIGN VISARGA;Mc;0;L;;;;;N;;;;;
+1039;MYANMAR SIGN VIRAMA;Mn;9;NSM;;;;;N;;;;;
+1040;MYANMAR DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+1041;MYANMAR DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+1042;MYANMAR DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+1043;MYANMAR DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+1044;MYANMAR DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+1045;MYANMAR DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+1046;MYANMAR DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+1047;MYANMAR DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+1048;MYANMAR DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+1049;MYANMAR DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+104A;MYANMAR SIGN LITTLE SECTION;Po;0;L;;;;;N;;;;;
+104B;MYANMAR SIGN SECTION;Po;0;L;;;;;N;;;;;
+104C;MYANMAR SYMBOL LOCATIVE;Po;0;L;;;;;N;;;;;
+104D;MYANMAR SYMBOL COMPLETED;Po;0;L;;;;;N;;;;;
+104E;MYANMAR SYMBOL AFOREMENTIONED;Po;0;L;;;;;N;;;;;
+104F;MYANMAR SYMBOL GENITIVE;Po;0;L;;;;;N;;;;;
+1050;MYANMAR LETTER SHA;Lo;0;L;;;;;N;;;;;
+1051;MYANMAR LETTER SSA;Lo;0;L;;;;;N;;;;;
+1052;MYANMAR LETTER VOCALIC R;Lo;0;L;;;;;N;;;;;
+1053;MYANMAR LETTER VOCALIC RR;Lo;0;L;;;;;N;;;;;
+1054;MYANMAR LETTER VOCALIC L;Lo;0;L;;;;;N;;;;;
+1055;MYANMAR LETTER VOCALIC LL;Lo;0;L;;;;;N;;;;;
+1056;MYANMAR VOWEL SIGN VOCALIC R;Mc;0;L;;;;;N;;;;;
+1057;MYANMAR VOWEL SIGN VOCALIC RR;Mc;0;L;;;;;N;;;;;
+1058;MYANMAR VOWEL SIGN VOCALIC L;Mn;0;NSM;;;;;N;;;;;
+1059;MYANMAR VOWEL SIGN VOCALIC LL;Mn;0;NSM;;;;;N;;;;;
+10A0;GEORGIAN CAPITAL LETTER AN;Lu;0;L;;;;;N;;Khutsuri;;;
+10A1;GEORGIAN CAPITAL LETTER BAN;Lu;0;L;;;;;N;;Khutsuri;;;
+10A2;GEORGIAN CAPITAL LETTER GAN;Lu;0;L;;;;;N;;Khutsuri;;;
+10A3;GEORGIAN CAPITAL LETTER DON;Lu;0;L;;;;;N;;Khutsuri;;;
+10A4;GEORGIAN CAPITAL LETTER EN;Lu;0;L;;;;;N;;Khutsuri;;;
+10A5;GEORGIAN CAPITAL LETTER VIN;Lu;0;L;;;;;N;;Khutsuri;;;
+10A6;GEORGIAN CAPITAL LETTER ZEN;Lu;0;L;;;;;N;;Khutsuri;;;
+10A7;GEORGIAN CAPITAL LETTER TAN;Lu;0;L;;;;;N;;Khutsuri;;;
+10A8;GEORGIAN CAPITAL LETTER IN;Lu;0;L;;;;;N;;Khutsuri;;;
+10A9;GEORGIAN CAPITAL LETTER KAN;Lu;0;L;;;;;N;;Khutsuri;;;
+10AA;GEORGIAN CAPITAL LETTER LAS;Lu;0;L;;;;;N;;Khutsuri;;;
+10AB;GEORGIAN CAPITAL LETTER MAN;Lu;0;L;;;;;N;;Khutsuri;;;
+10AC;GEORGIAN CAPITAL LETTER NAR;Lu;0;L;;;;;N;;Khutsuri;;;
+10AD;GEORGIAN CAPITAL LETTER ON;Lu;0;L;;;;;N;;Khutsuri;;;
+10AE;GEORGIAN CAPITAL LETTER PAR;Lu;0;L;;;;;N;;Khutsuri;;;
+10AF;GEORGIAN CAPITAL LETTER ZHAR;Lu;0;L;;;;;N;;Khutsuri;;;
+10B0;GEORGIAN CAPITAL LETTER RAE;Lu;0;L;;;;;N;;Khutsuri;;;
+10B1;GEORGIAN CAPITAL LETTER SAN;Lu;0;L;;;;;N;;Khutsuri;;;
+10B2;GEORGIAN CAPITAL LETTER TAR;Lu;0;L;;;;;N;;Khutsuri;;;
+10B3;GEORGIAN CAPITAL LETTER UN;Lu;0;L;;;;;N;;Khutsuri;;;
+10B4;GEORGIAN CAPITAL LETTER PHAR;Lu;0;L;;;;;N;;Khutsuri;;;
+10B5;GEORGIAN CAPITAL LETTER KHAR;Lu;0;L;;;;;N;;Khutsuri;;;
+10B6;GEORGIAN CAPITAL LETTER GHAN;Lu;0;L;;;;;N;;Khutsuri;;;
+10B7;GEORGIAN CAPITAL LETTER QAR;Lu;0;L;;;;;N;;Khutsuri;;;
+10B8;GEORGIAN CAPITAL LETTER SHIN;Lu;0;L;;;;;N;;Khutsuri;;;
+10B9;GEORGIAN CAPITAL LETTER CHIN;Lu;0;L;;;;;N;;Khutsuri;;;
+10BA;GEORGIAN CAPITAL LETTER CAN;Lu;0;L;;;;;N;;Khutsuri;;;
+10BB;GEORGIAN CAPITAL LETTER JIL;Lu;0;L;;;;;N;;Khutsuri;;;
+10BC;GEORGIAN CAPITAL LETTER CIL;Lu;0;L;;;;;N;;Khutsuri;;;
+10BD;GEORGIAN CAPITAL LETTER CHAR;Lu;0;L;;;;;N;;Khutsuri;;;
+10BE;GEORGIAN CAPITAL LETTER XAN;Lu;0;L;;;;;N;;Khutsuri;;;
+10BF;GEORGIAN CAPITAL LETTER JHAN;Lu;0;L;;;;;N;;Khutsuri;;;
+10C0;GEORGIAN CAPITAL LETTER HAE;Lu;0;L;;;;;N;;Khutsuri;;;
+10C1;GEORGIAN CAPITAL LETTER HE;Lu;0;L;;;;;N;;Khutsuri;;;
+10C2;GEORGIAN CAPITAL LETTER HIE;Lu;0;L;;;;;N;;Khutsuri;;;
+10C3;GEORGIAN CAPITAL LETTER WE;Lu;0;L;;;;;N;;Khutsuri;;;
+10C4;GEORGIAN CAPITAL LETTER HAR;Lu;0;L;;;;;N;;Khutsuri;;;
+10C5;GEORGIAN CAPITAL LETTER HOE;Lu;0;L;;;;;N;;Khutsuri;;;
+10D0;GEORGIAN LETTER AN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER AN;;;;
+10D1;GEORGIAN LETTER BAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER BAN;;;;
+10D2;GEORGIAN LETTER GAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER GAN;;;;
+10D3;GEORGIAN LETTER DON;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER DON;;;;
+10D4;GEORGIAN LETTER EN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER EN;;;;
+10D5;GEORGIAN LETTER VIN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER VIN;;;;
+10D6;GEORGIAN LETTER ZEN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER ZEN;;;;
+10D7;GEORGIAN LETTER TAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER TAN;;;;
+10D8;GEORGIAN LETTER IN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER IN;;;;
+10D9;GEORGIAN LETTER KAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER KAN;;;;
+10DA;GEORGIAN LETTER LAS;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER LAS;;;;
+10DB;GEORGIAN LETTER MAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER MAN;;;;
+10DC;GEORGIAN LETTER NAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER NAR;;;;
+10DD;GEORGIAN LETTER ON;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER ON;;;;
+10DE;GEORGIAN LETTER PAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER PAR;;;;
+10DF;GEORGIAN LETTER ZHAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER ZHAR;;;;
+10E0;GEORGIAN LETTER RAE;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER RAE;;;;
+10E1;GEORGIAN LETTER SAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER SAN;;;;
+10E2;GEORGIAN LETTER TAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER TAR;;;;
+10E3;GEORGIAN LETTER UN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER UN;;;;
+10E4;GEORGIAN LETTER PHAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER PHAR;;;;
+10E5;GEORGIAN LETTER KHAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER KHAR;;;;
+10E6;GEORGIAN LETTER GHAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER GHAN;;;;
+10E7;GEORGIAN LETTER QAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER QAR;;;;
+10E8;GEORGIAN LETTER SHIN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER SHIN;;;;
+10E9;GEORGIAN LETTER CHIN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER CHIN;;;;
+10EA;GEORGIAN LETTER CAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER CAN;;;;
+10EB;GEORGIAN LETTER JIL;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER JIL;;;;
+10EC;GEORGIAN LETTER CIL;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER CIL;;;;
+10ED;GEORGIAN LETTER CHAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER CHAR;;;;
+10EE;GEORGIAN LETTER XAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER XAN;;;;
+10EF;GEORGIAN LETTER JHAN;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER JHAN;;;;
+10F0;GEORGIAN LETTER HAE;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER HAE;;;;
+10F1;GEORGIAN LETTER HE;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER HE;;;;
+10F2;GEORGIAN LETTER HIE;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER HIE;;;;
+10F3;GEORGIAN LETTER WE;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER WE;;;;
+10F4;GEORGIAN LETTER HAR;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER HAR;;;;
+10F5;GEORGIAN LETTER HOE;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER HOE;;;;
+10F6;GEORGIAN LETTER FI;Lo;0;L;;;;;N;GEORGIAN SMALL LETTER FI;;;;
+10FB;GEORGIAN PARAGRAPH SEPARATOR;Po;0;L;;;;;N;;;;;
+1100;HANGUL CHOSEONG KIYEOK;Lo;0;L;;;;;N;;g *;;;
+1101;HANGUL CHOSEONG SSANGKIYEOK;Lo;0;L;;;;;N;;gg *;;;
+1102;HANGUL CHOSEONG NIEUN;Lo;0;L;;;;;N;;n *;;;
+1103;HANGUL CHOSEONG TIKEUT;Lo;0;L;;;;;N;;d *;;;
+1104;HANGUL CHOSEONG SSANGTIKEUT;Lo;0;L;;;;;N;;dd *;;;
+1105;HANGUL CHOSEONG RIEUL;Lo;0;L;;;;;N;;r *;;;
+1106;HANGUL CHOSEONG MIEUM;Lo;0;L;;;;;N;;m *;;;
+1107;HANGUL CHOSEONG PIEUP;Lo;0;L;;;;;N;;b *;;;
+1108;HANGUL CHOSEONG SSANGPIEUP;Lo;0;L;;;;;N;;bb *;;;
+1109;HANGUL CHOSEONG SIOS;Lo;0;L;;;;;N;;s *;;;
+110A;HANGUL CHOSEONG SSANGSIOS;Lo;0;L;;;;;N;;ss *;;;
+110B;HANGUL CHOSEONG IEUNG;Lo;0;L;;;;;N;;;;;
+110C;HANGUL CHOSEONG CIEUC;Lo;0;L;;;;;N;;j *;;;
+110D;HANGUL CHOSEONG SSANGCIEUC;Lo;0;L;;;;;N;;jj *;;;
+110E;HANGUL CHOSEONG CHIEUCH;Lo;0;L;;;;;N;;c *;;;
+110F;HANGUL CHOSEONG KHIEUKH;Lo;0;L;;;;;N;;k *;;;
+1110;HANGUL CHOSEONG THIEUTH;Lo;0;L;;;;;N;;t *;;;
+1111;HANGUL CHOSEONG PHIEUPH;Lo;0;L;;;;;N;;p *;;;
+1112;HANGUL CHOSEONG HIEUH;Lo;0;L;;;;;N;;h *;;;
+1113;HANGUL CHOSEONG NIEUN-KIYEOK;Lo;0;L;;;;;N;;;;;
+1114;HANGUL CHOSEONG SSANGNIEUN;Lo;0;L;;;;;N;;;;;
+1115;HANGUL CHOSEONG NIEUN-TIKEUT;Lo;0;L;;;;;N;;;;;
+1116;HANGUL CHOSEONG NIEUN-PIEUP;Lo;0;L;;;;;N;;;;;
+1117;HANGUL CHOSEONG TIKEUT-KIYEOK;Lo;0;L;;;;;N;;;;;
+1118;HANGUL CHOSEONG RIEUL-NIEUN;Lo;0;L;;;;;N;;;;;
+1119;HANGUL CHOSEONG SSANGRIEUL;Lo;0;L;;;;;N;;;;;
+111A;HANGUL CHOSEONG RIEUL-HIEUH;Lo;0;L;;;;;N;;;;;
+111B;HANGUL CHOSEONG KAPYEOUNRIEUL;Lo;0;L;;;;;N;;;;;
+111C;HANGUL CHOSEONG MIEUM-PIEUP;Lo;0;L;;;;;N;;;;;
+111D;HANGUL CHOSEONG KAPYEOUNMIEUM;Lo;0;L;;;;;N;;;;;
+111E;HANGUL CHOSEONG PIEUP-KIYEOK;Lo;0;L;;;;;N;;;;;
+111F;HANGUL CHOSEONG PIEUP-NIEUN;Lo;0;L;;;;;N;;;;;
+1120;HANGUL CHOSEONG PIEUP-TIKEUT;Lo;0;L;;;;;N;;;;;
+1121;HANGUL CHOSEONG PIEUP-SIOS;Lo;0;L;;;;;N;;;;;
+1122;HANGUL CHOSEONG PIEUP-SIOS-KIYEOK;Lo;0;L;;;;;N;;;;;
+1123;HANGUL CHOSEONG PIEUP-SIOS-TIKEUT;Lo;0;L;;;;;N;;;;;
+1124;HANGUL CHOSEONG PIEUP-SIOS-PIEUP;Lo;0;L;;;;;N;;;;;
+1125;HANGUL CHOSEONG PIEUP-SSANGSIOS;Lo;0;L;;;;;N;;;;;
+1126;HANGUL CHOSEONG PIEUP-SIOS-CIEUC;Lo;0;L;;;;;N;;;;;
+1127;HANGUL CHOSEONG PIEUP-CIEUC;Lo;0;L;;;;;N;;;;;
+1128;HANGUL CHOSEONG PIEUP-CHIEUCH;Lo;0;L;;;;;N;;;;;
+1129;HANGUL CHOSEONG PIEUP-THIEUTH;Lo;0;L;;;;;N;;;;;
+112A;HANGUL CHOSEONG PIEUP-PHIEUPH;Lo;0;L;;;;;N;;;;;
+112B;HANGUL CHOSEONG KAPYEOUNPIEUP;Lo;0;L;;;;;N;;;;;
+112C;HANGUL CHOSEONG KAPYEOUNSSANGPIEUP;Lo;0;L;;;;;N;;;;;
+112D;HANGUL CHOSEONG SIOS-KIYEOK;Lo;0;L;;;;;N;;;;;
+112E;HANGUL CHOSEONG SIOS-NIEUN;Lo;0;L;;;;;N;;;;;
+112F;HANGUL CHOSEONG SIOS-TIKEUT;Lo;0;L;;;;;N;;;;;
+1130;HANGUL CHOSEONG SIOS-RIEUL;Lo;0;L;;;;;N;;;;;
+1131;HANGUL CHOSEONG SIOS-MIEUM;Lo;0;L;;;;;N;;;;;
+1132;HANGUL CHOSEONG SIOS-PIEUP;Lo;0;L;;;;;N;;;;;
+1133;HANGUL CHOSEONG SIOS-PIEUP-KIYEOK;Lo;0;L;;;;;N;;;;;
+1134;HANGUL CHOSEONG SIOS-SSANGSIOS;Lo;0;L;;;;;N;;;;;
+1135;HANGUL CHOSEONG SIOS-IEUNG;Lo;0;L;;;;;N;;;;;
+1136;HANGUL CHOSEONG SIOS-CIEUC;Lo;0;L;;;;;N;;;;;
+1137;HANGUL CHOSEONG SIOS-CHIEUCH;Lo;0;L;;;;;N;;;;;
+1138;HANGUL CHOSEONG SIOS-KHIEUKH;Lo;0;L;;;;;N;;;;;
+1139;HANGUL CHOSEONG SIOS-THIEUTH;Lo;0;L;;;;;N;;;;;
+113A;HANGUL CHOSEONG SIOS-PHIEUPH;Lo;0;L;;;;;N;;;;;
+113B;HANGUL CHOSEONG SIOS-HIEUH;Lo;0;L;;;;;N;;;;;
+113C;HANGUL CHOSEONG CHITUEUMSIOS;Lo;0;L;;;;;N;;;;;
+113D;HANGUL CHOSEONG CHITUEUMSSANGSIOS;Lo;0;L;;;;;N;;;;;
+113E;HANGUL CHOSEONG CEONGCHIEUMSIOS;Lo;0;L;;;;;N;;;;;
+113F;HANGUL CHOSEONG CEONGCHIEUMSSANGSIOS;Lo;0;L;;;;;N;;;;;
+1140;HANGUL CHOSEONG PANSIOS;Lo;0;L;;;;;N;;;;;
+1141;HANGUL CHOSEONG IEUNG-KIYEOK;Lo;0;L;;;;;N;;;;;
+1142;HANGUL CHOSEONG IEUNG-TIKEUT;Lo;0;L;;;;;N;;;;;
+1143;HANGUL CHOSEONG IEUNG-MIEUM;Lo;0;L;;;;;N;;;;;
+1144;HANGUL CHOSEONG IEUNG-PIEUP;Lo;0;L;;;;;N;;;;;
+1145;HANGUL CHOSEONG IEUNG-SIOS;Lo;0;L;;;;;N;;;;;
+1146;HANGUL CHOSEONG IEUNG-PANSIOS;Lo;0;L;;;;;N;;;;;
+1147;HANGUL CHOSEONG SSANGIEUNG;Lo;0;L;;;;;N;;;;;
+1148;HANGUL CHOSEONG IEUNG-CIEUC;Lo;0;L;;;;;N;;;;;
+1149;HANGUL CHOSEONG IEUNG-CHIEUCH;Lo;0;L;;;;;N;;;;;
+114A;HANGUL CHOSEONG IEUNG-THIEUTH;Lo;0;L;;;;;N;;;;;
+114B;HANGUL CHOSEONG IEUNG-PHIEUPH;Lo;0;L;;;;;N;;;;;
+114C;HANGUL CHOSEONG YESIEUNG;Lo;0;L;;;;;N;;;;;
+114D;HANGUL CHOSEONG CIEUC-IEUNG;Lo;0;L;;;;;N;;;;;
+114E;HANGUL CHOSEONG CHITUEUMCIEUC;Lo;0;L;;;;;N;;;;;
+114F;HANGUL CHOSEONG CHITUEUMSSANGCIEUC;Lo;0;L;;;;;N;;;;;
+1150;HANGUL CHOSEONG CEONGCHIEUMCIEUC;Lo;0;L;;;;;N;;;;;
+1151;HANGUL CHOSEONG CEONGCHIEUMSSANGCIEUC;Lo;0;L;;;;;N;;;;;
+1152;HANGUL CHOSEONG CHIEUCH-KHIEUKH;Lo;0;L;;;;;N;;;;;
+1153;HANGUL CHOSEONG CHIEUCH-HIEUH;Lo;0;L;;;;;N;;;;;
+1154;HANGUL CHOSEONG CHITUEUMCHIEUCH;Lo;0;L;;;;;N;;;;;
+1155;HANGUL CHOSEONG CEONGCHIEUMCHIEUCH;Lo;0;L;;;;;N;;;;;
+1156;HANGUL CHOSEONG PHIEUPH-PIEUP;Lo;0;L;;;;;N;;;;;
+1157;HANGUL CHOSEONG KAPYEOUNPHIEUPH;Lo;0;L;;;;;N;;;;;
+1158;HANGUL CHOSEONG SSANGHIEUH;Lo;0;L;;;;;N;;;;;
+1159;HANGUL CHOSEONG YEORINHIEUH;Lo;0;L;;;;;N;;;;;
+115F;HANGUL CHOSEONG FILLER;Lo;0;L;;;;;N;;;;;
+1160;HANGUL JUNGSEONG FILLER;Lo;0;L;;;;;N;;;;;
+1161;HANGUL JUNGSEONG A;Lo;0;L;;;;;N;;;;;
+1162;HANGUL JUNGSEONG AE;Lo;0;L;;;;;N;;;;;
+1163;HANGUL JUNGSEONG YA;Lo;0;L;;;;;N;;;;;
+1164;HANGUL JUNGSEONG YAE;Lo;0;L;;;;;N;;;;;
+1165;HANGUL JUNGSEONG EO;Lo;0;L;;;;;N;;;;;
+1166;HANGUL JUNGSEONG E;Lo;0;L;;;;;N;;;;;
+1167;HANGUL JUNGSEONG YEO;Lo;0;L;;;;;N;;;;;
+1168;HANGUL JUNGSEONG YE;Lo;0;L;;;;;N;;;;;
+1169;HANGUL JUNGSEONG O;Lo;0;L;;;;;N;;;;;
+116A;HANGUL JUNGSEONG WA;Lo;0;L;;;;;N;;;;;
+116B;HANGUL JUNGSEONG WAE;Lo;0;L;;;;;N;;;;;
+116C;HANGUL JUNGSEONG OE;Lo;0;L;;;;;N;;;;;
+116D;HANGUL JUNGSEONG YO;Lo;0;L;;;;;N;;;;;
+116E;HANGUL JUNGSEONG U;Lo;0;L;;;;;N;;;;;
+116F;HANGUL JUNGSEONG WEO;Lo;0;L;;;;;N;;;;;
+1170;HANGUL JUNGSEONG WE;Lo;0;L;;;;;N;;;;;
+1171;HANGUL JUNGSEONG WI;Lo;0;L;;;;;N;;;;;
+1172;HANGUL JUNGSEONG YU;Lo;0;L;;;;;N;;;;;
+1173;HANGUL JUNGSEONG EU;Lo;0;L;;;;;N;;;;;
+1174;HANGUL JUNGSEONG YI;Lo;0;L;;;;;N;;;;;
+1175;HANGUL JUNGSEONG I;Lo;0;L;;;;;N;;;;;
+1176;HANGUL JUNGSEONG A-O;Lo;0;L;;;;;N;;;;;
+1177;HANGUL JUNGSEONG A-U;Lo;0;L;;;;;N;;;;;
+1178;HANGUL JUNGSEONG YA-O;Lo;0;L;;;;;N;;;;;
+1179;HANGUL JUNGSEONG YA-YO;Lo;0;L;;;;;N;;;;;
+117A;HANGUL JUNGSEONG EO-O;Lo;0;L;;;;;N;;;;;
+117B;HANGUL JUNGSEONG EO-U;Lo;0;L;;;;;N;;;;;
+117C;HANGUL JUNGSEONG EO-EU;Lo;0;L;;;;;N;;;;;
+117D;HANGUL JUNGSEONG YEO-O;Lo;0;L;;;;;N;;;;;
+117E;HANGUL JUNGSEONG YEO-U;Lo;0;L;;;;;N;;;;;
+117F;HANGUL JUNGSEONG O-EO;Lo;0;L;;;;;N;;;;;
+1180;HANGUL JUNGSEONG O-E;Lo;0;L;;;;;N;;;;;
+1181;HANGUL JUNGSEONG O-YE;Lo;0;L;;;;;N;;;;;
+1182;HANGUL JUNGSEONG O-O;Lo;0;L;;;;;N;;;;;
+1183;HANGUL JUNGSEONG O-U;Lo;0;L;;;;;N;;;;;
+1184;HANGUL JUNGSEONG YO-YA;Lo;0;L;;;;;N;;;;;
+1185;HANGUL JUNGSEONG YO-YAE;Lo;0;L;;;;;N;;;;;
+1186;HANGUL JUNGSEONG YO-YEO;Lo;0;L;;;;;N;;;;;
+1187;HANGUL JUNGSEONG YO-O;Lo;0;L;;;;;N;;;;;
+1188;HANGUL JUNGSEONG YO-I;Lo;0;L;;;;;N;;;;;
+1189;HANGUL JUNGSEONG U-A;Lo;0;L;;;;;N;;;;;
+118A;HANGUL JUNGSEONG U-AE;Lo;0;L;;;;;N;;;;;
+118B;HANGUL JUNGSEONG U-EO-EU;Lo;0;L;;;;;N;;;;;
+118C;HANGUL JUNGSEONG U-YE;Lo;0;L;;;;;N;;;;;
+118D;HANGUL JUNGSEONG U-U;Lo;0;L;;;;;N;;;;;
+118E;HANGUL JUNGSEONG YU-A;Lo;0;L;;;;;N;;;;;
+118F;HANGUL JUNGSEONG YU-EO;Lo;0;L;;;;;N;;;;;
+1190;HANGUL JUNGSEONG YU-E;Lo;0;L;;;;;N;;;;;
+1191;HANGUL JUNGSEONG YU-YEO;Lo;0;L;;;;;N;;;;;
+1192;HANGUL JUNGSEONG YU-YE;Lo;0;L;;;;;N;;;;;
+1193;HANGUL JUNGSEONG YU-U;Lo;0;L;;;;;N;;;;;
+1194;HANGUL JUNGSEONG YU-I;Lo;0;L;;;;;N;;;;;
+1195;HANGUL JUNGSEONG EU-U;Lo;0;L;;;;;N;;;;;
+1196;HANGUL JUNGSEONG EU-EU;Lo;0;L;;;;;N;;;;;
+1197;HANGUL JUNGSEONG YI-U;Lo;0;L;;;;;N;;;;;
+1198;HANGUL JUNGSEONG I-A;Lo;0;L;;;;;N;;;;;
+1199;HANGUL JUNGSEONG I-YA;Lo;0;L;;;;;N;;;;;
+119A;HANGUL JUNGSEONG I-O;Lo;0;L;;;;;N;;;;;
+119B;HANGUL JUNGSEONG I-U;Lo;0;L;;;;;N;;;;;
+119C;HANGUL JUNGSEONG I-EU;Lo;0;L;;;;;N;;;;;
+119D;HANGUL JUNGSEONG I-ARAEA;Lo;0;L;;;;;N;;;;;
+119E;HANGUL JUNGSEONG ARAEA;Lo;0;L;;;;;N;;;;;
+119F;HANGUL JUNGSEONG ARAEA-EO;Lo;0;L;;;;;N;;;;;
+11A0;HANGUL JUNGSEONG ARAEA-U;Lo;0;L;;;;;N;;;;;
+11A1;HANGUL JUNGSEONG ARAEA-I;Lo;0;L;;;;;N;;;;;
+11A2;HANGUL JUNGSEONG SSANGARAEA;Lo;0;L;;;;;N;;;;;
+11A8;HANGUL JONGSEONG KIYEOK;Lo;0;L;;;;;N;;g *;;;
+11A9;HANGUL JONGSEONG SSANGKIYEOK;Lo;0;L;;;;;N;;gg *;;;
+11AA;HANGUL JONGSEONG KIYEOK-SIOS;Lo;0;L;;;;;N;;gs *;;;
+11AB;HANGUL JONGSEONG NIEUN;Lo;0;L;;;;;N;;n *;;;
+11AC;HANGUL JONGSEONG NIEUN-CIEUC;Lo;0;L;;;;;N;;nj *;;;
+11AD;HANGUL JONGSEONG NIEUN-HIEUH;Lo;0;L;;;;;N;;nh *;;;
+11AE;HANGUL JONGSEONG TIKEUT;Lo;0;L;;;;;N;;d *;;;
+11AF;HANGUL JONGSEONG RIEUL;Lo;0;L;;;;;N;;l *;;;
+11B0;HANGUL JONGSEONG RIEUL-KIYEOK;Lo;0;L;;;;;N;;lg *;;;
+11B1;HANGUL JONGSEONG RIEUL-MIEUM;Lo;0;L;;;;;N;;lm *;;;
+11B2;HANGUL JONGSEONG RIEUL-PIEUP;Lo;0;L;;;;;N;;lb *;;;
+11B3;HANGUL JONGSEONG RIEUL-SIOS;Lo;0;L;;;;;N;;ls *;;;
+11B4;HANGUL JONGSEONG RIEUL-THIEUTH;Lo;0;L;;;;;N;;lt *;;;
+11B5;HANGUL JONGSEONG RIEUL-PHIEUPH;Lo;0;L;;;;;N;;lp *;;;
+11B6;HANGUL JONGSEONG RIEUL-HIEUH;Lo;0;L;;;;;N;;lh *;;;
+11B7;HANGUL JONGSEONG MIEUM;Lo;0;L;;;;;N;;m *;;;
+11B8;HANGUL JONGSEONG PIEUP;Lo;0;L;;;;;N;;b *;;;
+11B9;HANGUL JONGSEONG PIEUP-SIOS;Lo;0;L;;;;;N;;bs *;;;
+11BA;HANGUL JONGSEONG SIOS;Lo;0;L;;;;;N;;s *;;;
+11BB;HANGUL JONGSEONG SSANGSIOS;Lo;0;L;;;;;N;;ss *;;;
+11BC;HANGUL JONGSEONG IEUNG;Lo;0;L;;;;;N;;ng *;;;
+11BD;HANGUL JONGSEONG CIEUC;Lo;0;L;;;;;N;;j *;;;
+11BE;HANGUL JONGSEONG CHIEUCH;Lo;0;L;;;;;N;;c *;;;
+11BF;HANGUL JONGSEONG KHIEUKH;Lo;0;L;;;;;N;;k *;;;
+11C0;HANGUL JONGSEONG THIEUTH;Lo;0;L;;;;;N;;t *;;;
+11C1;HANGUL JONGSEONG PHIEUPH;Lo;0;L;;;;;N;;p *;;;
+11C2;HANGUL JONGSEONG HIEUH;Lo;0;L;;;;;N;;h *;;;
+11C3;HANGUL JONGSEONG KIYEOK-RIEUL;Lo;0;L;;;;;N;;;;;
+11C4;HANGUL JONGSEONG KIYEOK-SIOS-KIYEOK;Lo;0;L;;;;;N;;;;;
+11C5;HANGUL JONGSEONG NIEUN-KIYEOK;Lo;0;L;;;;;N;;;;;
+11C6;HANGUL JONGSEONG NIEUN-TIKEUT;Lo;0;L;;;;;N;;;;;
+11C7;HANGUL JONGSEONG NIEUN-SIOS;Lo;0;L;;;;;N;;;;;
+11C8;HANGUL JONGSEONG NIEUN-PANSIOS;Lo;0;L;;;;;N;;;;;
+11C9;HANGUL JONGSEONG NIEUN-THIEUTH;Lo;0;L;;;;;N;;;;;
+11CA;HANGUL JONGSEONG TIKEUT-KIYEOK;Lo;0;L;;;;;N;;;;;
+11CB;HANGUL JONGSEONG TIKEUT-RIEUL;Lo;0;L;;;;;N;;;;;
+11CC;HANGUL JONGSEONG RIEUL-KIYEOK-SIOS;Lo;0;L;;;;;N;;;;;
+11CD;HANGUL JONGSEONG RIEUL-NIEUN;Lo;0;L;;;;;N;;;;;
+11CE;HANGUL JONGSEONG RIEUL-TIKEUT;Lo;0;L;;;;;N;;;;;
+11CF;HANGUL JONGSEONG RIEUL-TIKEUT-HIEUH;Lo;0;L;;;;;N;;;;;
+11D0;HANGUL JONGSEONG SSANGRIEUL;Lo;0;L;;;;;N;;;;;
+11D1;HANGUL JONGSEONG RIEUL-MIEUM-KIYEOK;Lo;0;L;;;;;N;;;;;
+11D2;HANGUL JONGSEONG RIEUL-MIEUM-SIOS;Lo;0;L;;;;;N;;;;;
+11D3;HANGUL JONGSEONG RIEUL-PIEUP-SIOS;Lo;0;L;;;;;N;;;;;
+11D4;HANGUL JONGSEONG RIEUL-PIEUP-HIEUH;Lo;0;L;;;;;N;;;;;
+11D5;HANGUL JONGSEONG RIEUL-KAPYEOUNPIEUP;Lo;0;L;;;;;N;;;;;
+11D6;HANGUL JONGSEONG RIEUL-SSANGSIOS;Lo;0;L;;;;;N;;;;;
+11D7;HANGUL JONGSEONG RIEUL-PANSIOS;Lo;0;L;;;;;N;;;;;
+11D8;HANGUL JONGSEONG RIEUL-KHIEUKH;Lo;0;L;;;;;N;;;;;
+11D9;HANGUL JONGSEONG RIEUL-YEORINHIEUH;Lo;0;L;;;;;N;;;;;
+11DA;HANGUL JONGSEONG MIEUM-KIYEOK;Lo;0;L;;;;;N;;;;;
+11DB;HANGUL JONGSEONG MIEUM-RIEUL;Lo;0;L;;;;;N;;;;;
+11DC;HANGUL JONGSEONG MIEUM-PIEUP;Lo;0;L;;;;;N;;;;;
+11DD;HANGUL JONGSEONG MIEUM-SIOS;Lo;0;L;;;;;N;;;;;
+11DE;HANGUL JONGSEONG MIEUM-SSANGSIOS;Lo;0;L;;;;;N;;;;;
+11DF;HANGUL JONGSEONG MIEUM-PANSIOS;Lo;0;L;;;;;N;;;;;
+11E0;HANGUL JONGSEONG MIEUM-CHIEUCH;Lo;0;L;;;;;N;;;;;
+11E1;HANGUL JONGSEONG MIEUM-HIEUH;Lo;0;L;;;;;N;;;;;
+11E2;HANGUL JONGSEONG KAPYEOUNMIEUM;Lo;0;L;;;;;N;;;;;
+11E3;HANGUL JONGSEONG PIEUP-RIEUL;Lo;0;L;;;;;N;;;;;
+11E4;HANGUL JONGSEONG PIEUP-PHIEUPH;Lo;0;L;;;;;N;;;;;
+11E5;HANGUL JONGSEONG PIEUP-HIEUH;Lo;0;L;;;;;N;;;;;
+11E6;HANGUL JONGSEONG KAPYEOUNPIEUP;Lo;0;L;;;;;N;;;;;
+11E7;HANGUL JONGSEONG SIOS-KIYEOK;Lo;0;L;;;;;N;;;;;
+11E8;HANGUL JONGSEONG SIOS-TIKEUT;Lo;0;L;;;;;N;;;;;
+11E9;HANGUL JONGSEONG SIOS-RIEUL;Lo;0;L;;;;;N;;;;;
+11EA;HANGUL JONGSEONG SIOS-PIEUP;Lo;0;L;;;;;N;;;;;
+11EB;HANGUL JONGSEONG PANSIOS;Lo;0;L;;;;;N;;;;;
+11EC;HANGUL JONGSEONG IEUNG-KIYEOK;Lo;0;L;;;;;N;;;;;
+11ED;HANGUL JONGSEONG IEUNG-SSANGKIYEOK;Lo;0;L;;;;;N;;;;;
+11EE;HANGUL JONGSEONG SSANGIEUNG;Lo;0;L;;;;;N;;;;;
+11EF;HANGUL JONGSEONG IEUNG-KHIEUKH;Lo;0;L;;;;;N;;;;;
+11F0;HANGUL JONGSEONG YESIEUNG;Lo;0;L;;;;;N;;;;;
+11F1;HANGUL JONGSEONG YESIEUNG-SIOS;Lo;0;L;;;;;N;;;;;
+11F2;HANGUL JONGSEONG YESIEUNG-PANSIOS;Lo;0;L;;;;;N;;;;;
+11F3;HANGUL JONGSEONG PHIEUPH-PIEUP;Lo;0;L;;;;;N;;;;;
+11F4;HANGUL JONGSEONG KAPYEOUNPHIEUPH;Lo;0;L;;;;;N;;;;;
+11F5;HANGUL JONGSEONG HIEUH-NIEUN;Lo;0;L;;;;;N;;;;;
+11F6;HANGUL JONGSEONG HIEUH-RIEUL;Lo;0;L;;;;;N;;;;;
+11F7;HANGUL JONGSEONG HIEUH-MIEUM;Lo;0;L;;;;;N;;;;;
+11F8;HANGUL JONGSEONG HIEUH-PIEUP;Lo;0;L;;;;;N;;;;;
+11F9;HANGUL JONGSEONG YEORINHIEUH;Lo;0;L;;;;;N;;;;;
+1200;ETHIOPIC SYLLABLE HA;Lo;0;L;;;;;N;;;;;
+1201;ETHIOPIC SYLLABLE HU;Lo;0;L;;;;;N;;;;;
+1202;ETHIOPIC SYLLABLE HI;Lo;0;L;;;;;N;;;;;
+1203;ETHIOPIC SYLLABLE HAA;Lo;0;L;;;;;N;;;;;
+1204;ETHIOPIC SYLLABLE HEE;Lo;0;L;;;;;N;;;;;
+1205;ETHIOPIC SYLLABLE HE;Lo;0;L;;;;;N;;;;;
+1206;ETHIOPIC SYLLABLE HO;Lo;0;L;;;;;N;;;;;
+1208;ETHIOPIC SYLLABLE LA;Lo;0;L;;;;;N;;;;;
+1209;ETHIOPIC SYLLABLE LU;Lo;0;L;;;;;N;;;;;
+120A;ETHIOPIC SYLLABLE LI;Lo;0;L;;;;;N;;;;;
+120B;ETHIOPIC SYLLABLE LAA;Lo;0;L;;;;;N;;;;;
+120C;ETHIOPIC SYLLABLE LEE;Lo;0;L;;;;;N;;;;;
+120D;ETHIOPIC SYLLABLE LE;Lo;0;L;;;;;N;;;;;
+120E;ETHIOPIC SYLLABLE LO;Lo;0;L;;;;;N;;;;;
+120F;ETHIOPIC SYLLABLE LWA;Lo;0;L;;;;;N;;;;;
+1210;ETHIOPIC SYLLABLE HHA;Lo;0;L;;;;;N;;;;;
+1211;ETHIOPIC SYLLABLE HHU;Lo;0;L;;;;;N;;;;;
+1212;ETHIOPIC SYLLABLE HHI;Lo;0;L;;;;;N;;;;;
+1213;ETHIOPIC SYLLABLE HHAA;Lo;0;L;;;;;N;;;;;
+1214;ETHIOPIC SYLLABLE HHEE;Lo;0;L;;;;;N;;;;;
+1215;ETHIOPIC SYLLABLE HHE;Lo;0;L;;;;;N;;;;;
+1216;ETHIOPIC SYLLABLE HHO;Lo;0;L;;;;;N;;;;;
+1217;ETHIOPIC SYLLABLE HHWA;Lo;0;L;;;;;N;;;;;
+1218;ETHIOPIC SYLLABLE MA;Lo;0;L;;;;;N;;;;;
+1219;ETHIOPIC SYLLABLE MU;Lo;0;L;;;;;N;;;;;
+121A;ETHIOPIC SYLLABLE MI;Lo;0;L;;;;;N;;;;;
+121B;ETHIOPIC SYLLABLE MAA;Lo;0;L;;;;;N;;;;;
+121C;ETHIOPIC SYLLABLE MEE;Lo;0;L;;;;;N;;;;;
+121D;ETHIOPIC SYLLABLE ME;Lo;0;L;;;;;N;;;;;
+121E;ETHIOPIC SYLLABLE MO;Lo;0;L;;;;;N;;;;;
+121F;ETHIOPIC SYLLABLE MWA;Lo;0;L;;;;;N;;;;;
+1220;ETHIOPIC SYLLABLE SZA;Lo;0;L;;;;;N;;;;;
+1221;ETHIOPIC SYLLABLE SZU;Lo;0;L;;;;;N;;;;;
+1222;ETHIOPIC SYLLABLE SZI;Lo;0;L;;;;;N;;;;;
+1223;ETHIOPIC SYLLABLE SZAA;Lo;0;L;;;;;N;;;;;
+1224;ETHIOPIC SYLLABLE SZEE;Lo;0;L;;;;;N;;;;;
+1225;ETHIOPIC SYLLABLE SZE;Lo;0;L;;;;;N;;;;;
+1226;ETHIOPIC SYLLABLE SZO;Lo;0;L;;;;;N;;;;;
+1227;ETHIOPIC SYLLABLE SZWA;Lo;0;L;;;;;N;;;;;
+1228;ETHIOPIC SYLLABLE RA;Lo;0;L;;;;;N;;;;;
+1229;ETHIOPIC SYLLABLE RU;Lo;0;L;;;;;N;;;;;
+122A;ETHIOPIC SYLLABLE RI;Lo;0;L;;;;;N;;;;;
+122B;ETHIOPIC SYLLABLE RAA;Lo;0;L;;;;;N;;;;;
+122C;ETHIOPIC SYLLABLE REE;Lo;0;L;;;;;N;;;;;
+122D;ETHIOPIC SYLLABLE RE;Lo;0;L;;;;;N;;;;;
+122E;ETHIOPIC SYLLABLE RO;Lo;0;L;;;;;N;;;;;
+122F;ETHIOPIC SYLLABLE RWA;Lo;0;L;;;;;N;;;;;
+1230;ETHIOPIC SYLLABLE SA;Lo;0;L;;;;;N;;;;;
+1231;ETHIOPIC SYLLABLE SU;Lo;0;L;;;;;N;;;;;
+1232;ETHIOPIC SYLLABLE SI;Lo;0;L;;;;;N;;;;;
+1233;ETHIOPIC SYLLABLE SAA;Lo;0;L;;;;;N;;;;;
+1234;ETHIOPIC SYLLABLE SEE;Lo;0;L;;;;;N;;;;;
+1235;ETHIOPIC SYLLABLE SE;Lo;0;L;;;;;N;;;;;
+1236;ETHIOPIC SYLLABLE SO;Lo;0;L;;;;;N;;;;;
+1237;ETHIOPIC SYLLABLE SWA;Lo;0;L;;;;;N;;;;;
+1238;ETHIOPIC SYLLABLE SHA;Lo;0;L;;;;;N;;;;;
+1239;ETHIOPIC SYLLABLE SHU;Lo;0;L;;;;;N;;;;;
+123A;ETHIOPIC SYLLABLE SHI;Lo;0;L;;;;;N;;;;;
+123B;ETHIOPIC SYLLABLE SHAA;Lo;0;L;;;;;N;;;;;
+123C;ETHIOPIC SYLLABLE SHEE;Lo;0;L;;;;;N;;;;;
+123D;ETHIOPIC SYLLABLE SHE;Lo;0;L;;;;;N;;;;;
+123E;ETHIOPIC SYLLABLE SHO;Lo;0;L;;;;;N;;;;;
+123F;ETHIOPIC SYLLABLE SHWA;Lo;0;L;;;;;N;;;;;
+1240;ETHIOPIC SYLLABLE QA;Lo;0;L;;;;;N;;;;;
+1241;ETHIOPIC SYLLABLE QU;Lo;0;L;;;;;N;;;;;
+1242;ETHIOPIC SYLLABLE QI;Lo;0;L;;;;;N;;;;;
+1243;ETHIOPIC SYLLABLE QAA;Lo;0;L;;;;;N;;;;;
+1244;ETHIOPIC SYLLABLE QEE;Lo;0;L;;;;;N;;;;;
+1245;ETHIOPIC SYLLABLE QE;Lo;0;L;;;;;N;;;;;
+1246;ETHIOPIC SYLLABLE QO;Lo;0;L;;;;;N;;;;;
+1248;ETHIOPIC SYLLABLE QWA;Lo;0;L;;;;;N;;;;;
+124A;ETHIOPIC SYLLABLE QWI;Lo;0;L;;;;;N;;;;;
+124B;ETHIOPIC SYLLABLE QWAA;Lo;0;L;;;;;N;;;;;
+124C;ETHIOPIC SYLLABLE QWEE;Lo;0;L;;;;;N;;;;;
+124D;ETHIOPIC SYLLABLE QWE;Lo;0;L;;;;;N;;;;;
+1250;ETHIOPIC SYLLABLE QHA;Lo;0;L;;;;;N;;;;;
+1251;ETHIOPIC SYLLABLE QHU;Lo;0;L;;;;;N;;;;;
+1252;ETHIOPIC SYLLABLE QHI;Lo;0;L;;;;;N;;;;;
+1253;ETHIOPIC SYLLABLE QHAA;Lo;0;L;;;;;N;;;;;
+1254;ETHIOPIC SYLLABLE QHEE;Lo;0;L;;;;;N;;;;;
+1255;ETHIOPIC SYLLABLE QHE;Lo;0;L;;;;;N;;;;;
+1256;ETHIOPIC SYLLABLE QHO;Lo;0;L;;;;;N;;;;;
+1258;ETHIOPIC SYLLABLE QHWA;Lo;0;L;;;;;N;;;;;
+125A;ETHIOPIC SYLLABLE QHWI;Lo;0;L;;;;;N;;;;;
+125B;ETHIOPIC SYLLABLE QHWAA;Lo;0;L;;;;;N;;;;;
+125C;ETHIOPIC SYLLABLE QHWEE;Lo;0;L;;;;;N;;;;;
+125D;ETHIOPIC SYLLABLE QHWE;Lo;0;L;;;;;N;;;;;
+1260;ETHIOPIC SYLLABLE BA;Lo;0;L;;;;;N;;;;;
+1261;ETHIOPIC SYLLABLE BU;Lo;0;L;;;;;N;;;;;
+1262;ETHIOPIC SYLLABLE BI;Lo;0;L;;;;;N;;;;;
+1263;ETHIOPIC SYLLABLE BAA;Lo;0;L;;;;;N;;;;;
+1264;ETHIOPIC SYLLABLE BEE;Lo;0;L;;;;;N;;;;;
+1265;ETHIOPIC SYLLABLE BE;Lo;0;L;;;;;N;;;;;
+1266;ETHIOPIC SYLLABLE BO;Lo;0;L;;;;;N;;;;;
+1267;ETHIOPIC SYLLABLE BWA;Lo;0;L;;;;;N;;;;;
+1268;ETHIOPIC SYLLABLE VA;Lo;0;L;;;;;N;;;;;
+1269;ETHIOPIC SYLLABLE VU;Lo;0;L;;;;;N;;;;;
+126A;ETHIOPIC SYLLABLE VI;Lo;0;L;;;;;N;;;;;
+126B;ETHIOPIC SYLLABLE VAA;Lo;0;L;;;;;N;;;;;
+126C;ETHIOPIC SYLLABLE VEE;Lo;0;L;;;;;N;;;;;
+126D;ETHIOPIC SYLLABLE VE;Lo;0;L;;;;;N;;;;;
+126E;ETHIOPIC SYLLABLE VO;Lo;0;L;;;;;N;;;;;
+126F;ETHIOPIC SYLLABLE VWA;Lo;0;L;;;;;N;;;;;
+1270;ETHIOPIC SYLLABLE TA;Lo;0;L;;;;;N;;;;;
+1271;ETHIOPIC SYLLABLE TU;Lo;0;L;;;;;N;;;;;
+1272;ETHIOPIC SYLLABLE TI;Lo;0;L;;;;;N;;;;;
+1273;ETHIOPIC SYLLABLE TAA;Lo;0;L;;;;;N;;;;;
+1274;ETHIOPIC SYLLABLE TEE;Lo;0;L;;;;;N;;;;;
+1275;ETHIOPIC SYLLABLE TE;Lo;0;L;;;;;N;;;;;
+1276;ETHIOPIC SYLLABLE TO;Lo;0;L;;;;;N;;;;;
+1277;ETHIOPIC SYLLABLE TWA;Lo;0;L;;;;;N;;;;;
+1278;ETHIOPIC SYLLABLE CA;Lo;0;L;;;;;N;;;;;
+1279;ETHIOPIC SYLLABLE CU;Lo;0;L;;;;;N;;;;;
+127A;ETHIOPIC SYLLABLE CI;Lo;0;L;;;;;N;;;;;
+127B;ETHIOPIC SYLLABLE CAA;Lo;0;L;;;;;N;;;;;
+127C;ETHIOPIC SYLLABLE CEE;Lo;0;L;;;;;N;;;;;
+127D;ETHIOPIC SYLLABLE CE;Lo;0;L;;;;;N;;;;;
+127E;ETHIOPIC SYLLABLE CO;Lo;0;L;;;;;N;;;;;
+127F;ETHIOPIC SYLLABLE CWA;Lo;0;L;;;;;N;;;;;
+1280;ETHIOPIC SYLLABLE XA;Lo;0;L;;;;;N;;;;;
+1281;ETHIOPIC SYLLABLE XU;Lo;0;L;;;;;N;;;;;
+1282;ETHIOPIC SYLLABLE XI;Lo;0;L;;;;;N;;;;;
+1283;ETHIOPIC SYLLABLE XAA;Lo;0;L;;;;;N;;;;;
+1284;ETHIOPIC SYLLABLE XEE;Lo;0;L;;;;;N;;;;;
+1285;ETHIOPIC SYLLABLE XE;Lo;0;L;;;;;N;;;;;
+1286;ETHIOPIC SYLLABLE XO;Lo;0;L;;;;;N;;;;;
+1288;ETHIOPIC SYLLABLE XWA;Lo;0;L;;;;;N;;;;;
+128A;ETHIOPIC SYLLABLE XWI;Lo;0;L;;;;;N;;;;;
+128B;ETHIOPIC SYLLABLE XWAA;Lo;0;L;;;;;N;;;;;
+128C;ETHIOPIC SYLLABLE XWEE;Lo;0;L;;;;;N;;;;;
+128D;ETHIOPIC SYLLABLE XWE;Lo;0;L;;;;;N;;;;;
+1290;ETHIOPIC SYLLABLE NA;Lo;0;L;;;;;N;;;;;
+1291;ETHIOPIC SYLLABLE NU;Lo;0;L;;;;;N;;;;;
+1292;ETHIOPIC SYLLABLE NI;Lo;0;L;;;;;N;;;;;
+1293;ETHIOPIC SYLLABLE NAA;Lo;0;L;;;;;N;;;;;
+1294;ETHIOPIC SYLLABLE NEE;Lo;0;L;;;;;N;;;;;
+1295;ETHIOPIC SYLLABLE NE;Lo;0;L;;;;;N;;;;;
+1296;ETHIOPIC SYLLABLE NO;Lo;0;L;;;;;N;;;;;
+1297;ETHIOPIC SYLLABLE NWA;Lo;0;L;;;;;N;;;;;
+1298;ETHIOPIC SYLLABLE NYA;Lo;0;L;;;;;N;;;;;
+1299;ETHIOPIC SYLLABLE NYU;Lo;0;L;;;;;N;;;;;
+129A;ETHIOPIC SYLLABLE NYI;Lo;0;L;;;;;N;;;;;
+129B;ETHIOPIC SYLLABLE NYAA;Lo;0;L;;;;;N;;;;;
+129C;ETHIOPIC SYLLABLE NYEE;Lo;0;L;;;;;N;;;;;
+129D;ETHIOPIC SYLLABLE NYE;Lo;0;L;;;;;N;;;;;
+129E;ETHIOPIC SYLLABLE NYO;Lo;0;L;;;;;N;;;;;
+129F;ETHIOPIC SYLLABLE NYWA;Lo;0;L;;;;;N;;;;;
+12A0;ETHIOPIC SYLLABLE GLOTTAL A;Lo;0;L;;;;;N;;;;;
+12A1;ETHIOPIC SYLLABLE GLOTTAL U;Lo;0;L;;;;;N;;;;;
+12A2;ETHIOPIC SYLLABLE GLOTTAL I;Lo;0;L;;;;;N;;;;;
+12A3;ETHIOPIC SYLLABLE GLOTTAL AA;Lo;0;L;;;;;N;;;;;
+12A4;ETHIOPIC SYLLABLE GLOTTAL EE;Lo;0;L;;;;;N;;;;;
+12A5;ETHIOPIC SYLLABLE GLOTTAL E;Lo;0;L;;;;;N;;;;;
+12A6;ETHIOPIC SYLLABLE GLOTTAL O;Lo;0;L;;;;;N;;;;;
+12A7;ETHIOPIC SYLLABLE GLOTTAL WA;Lo;0;L;;;;;N;;;;;
+12A8;ETHIOPIC SYLLABLE KA;Lo;0;L;;;;;N;;;;;
+12A9;ETHIOPIC SYLLABLE KU;Lo;0;L;;;;;N;;;;;
+12AA;ETHIOPIC SYLLABLE KI;Lo;0;L;;;;;N;;;;;
+12AB;ETHIOPIC SYLLABLE KAA;Lo;0;L;;;;;N;;;;;
+12AC;ETHIOPIC SYLLABLE KEE;Lo;0;L;;;;;N;;;;;
+12AD;ETHIOPIC SYLLABLE KE;Lo;0;L;;;;;N;;;;;
+12AE;ETHIOPIC SYLLABLE KO;Lo;0;L;;;;;N;;;;;
+12B0;ETHIOPIC SYLLABLE KWA;Lo;0;L;;;;;N;;;;;
+12B2;ETHIOPIC SYLLABLE KWI;Lo;0;L;;;;;N;;;;;
+12B3;ETHIOPIC SYLLABLE KWAA;Lo;0;L;;;;;N;;;;;
+12B4;ETHIOPIC SYLLABLE KWEE;Lo;0;L;;;;;N;;;;;
+12B5;ETHIOPIC SYLLABLE KWE;Lo;0;L;;;;;N;;;;;
+12B8;ETHIOPIC SYLLABLE KXA;Lo;0;L;;;;;N;;;;;
+12B9;ETHIOPIC SYLLABLE KXU;Lo;0;L;;;;;N;;;;;
+12BA;ETHIOPIC SYLLABLE KXI;Lo;0;L;;;;;N;;;;;
+12BB;ETHIOPIC SYLLABLE KXAA;Lo;0;L;;;;;N;;;;;
+12BC;ETHIOPIC SYLLABLE KXEE;Lo;0;L;;;;;N;;;;;
+12BD;ETHIOPIC SYLLABLE KXE;Lo;0;L;;;;;N;;;;;
+12BE;ETHIOPIC SYLLABLE KXO;Lo;0;L;;;;;N;;;;;
+12C0;ETHIOPIC SYLLABLE KXWA;Lo;0;L;;;;;N;;;;;
+12C2;ETHIOPIC SYLLABLE KXWI;Lo;0;L;;;;;N;;;;;
+12C3;ETHIOPIC SYLLABLE KXWAA;Lo;0;L;;;;;N;;;;;
+12C4;ETHIOPIC SYLLABLE KXWEE;Lo;0;L;;;;;N;;;;;
+12C5;ETHIOPIC SYLLABLE KXWE;Lo;0;L;;;;;N;;;;;
+12C8;ETHIOPIC SYLLABLE WA;Lo;0;L;;;;;N;;;;;
+12C9;ETHIOPIC SYLLABLE WU;Lo;0;L;;;;;N;;;;;
+12CA;ETHIOPIC SYLLABLE WI;Lo;0;L;;;;;N;;;;;
+12CB;ETHIOPIC SYLLABLE WAA;Lo;0;L;;;;;N;;;;;
+12CC;ETHIOPIC SYLLABLE WEE;Lo;0;L;;;;;N;;;;;
+12CD;ETHIOPIC SYLLABLE WE;Lo;0;L;;;;;N;;;;;
+12CE;ETHIOPIC SYLLABLE WO;Lo;0;L;;;;;N;;;;;
+12D0;ETHIOPIC SYLLABLE PHARYNGEAL A;Lo;0;L;;;;;N;;;;;
+12D1;ETHIOPIC SYLLABLE PHARYNGEAL U;Lo;0;L;;;;;N;;;;;
+12D2;ETHIOPIC SYLLABLE PHARYNGEAL I;Lo;0;L;;;;;N;;;;;
+12D3;ETHIOPIC SYLLABLE PHARYNGEAL AA;Lo;0;L;;;;;N;;;;;
+12D4;ETHIOPIC SYLLABLE PHARYNGEAL EE;Lo;0;L;;;;;N;;;;;
+12D5;ETHIOPIC SYLLABLE PHARYNGEAL E;Lo;0;L;;;;;N;;;;;
+12D6;ETHIOPIC SYLLABLE PHARYNGEAL O;Lo;0;L;;;;;N;;;;;
+12D8;ETHIOPIC SYLLABLE ZA;Lo;0;L;;;;;N;;;;;
+12D9;ETHIOPIC SYLLABLE ZU;Lo;0;L;;;;;N;;;;;
+12DA;ETHIOPIC SYLLABLE ZI;Lo;0;L;;;;;N;;;;;
+12DB;ETHIOPIC SYLLABLE ZAA;Lo;0;L;;;;;N;;;;;
+12DC;ETHIOPIC SYLLABLE ZEE;Lo;0;L;;;;;N;;;;;
+12DD;ETHIOPIC SYLLABLE ZE;Lo;0;L;;;;;N;;;;;
+12DE;ETHIOPIC SYLLABLE ZO;Lo;0;L;;;;;N;;;;;
+12DF;ETHIOPIC SYLLABLE ZWA;Lo;0;L;;;;;N;;;;;
+12E0;ETHIOPIC SYLLABLE ZHA;Lo;0;L;;;;;N;;;;;
+12E1;ETHIOPIC SYLLABLE ZHU;Lo;0;L;;;;;N;;;;;
+12E2;ETHIOPIC SYLLABLE ZHI;Lo;0;L;;;;;N;;;;;
+12E3;ETHIOPIC SYLLABLE ZHAA;Lo;0;L;;;;;N;;;;;
+12E4;ETHIOPIC SYLLABLE ZHEE;Lo;0;L;;;;;N;;;;;
+12E5;ETHIOPIC SYLLABLE ZHE;Lo;0;L;;;;;N;;;;;
+12E6;ETHIOPIC SYLLABLE ZHO;Lo;0;L;;;;;N;;;;;
+12E7;ETHIOPIC SYLLABLE ZHWA;Lo;0;L;;;;;N;;;;;
+12E8;ETHIOPIC SYLLABLE YA;Lo;0;L;;;;;N;;;;;
+12E9;ETHIOPIC SYLLABLE YU;Lo;0;L;;;;;N;;;;;
+12EA;ETHIOPIC SYLLABLE YI;Lo;0;L;;;;;N;;;;;
+12EB;ETHIOPIC SYLLABLE YAA;Lo;0;L;;;;;N;;;;;
+12EC;ETHIOPIC SYLLABLE YEE;Lo;0;L;;;;;N;;;;;
+12ED;ETHIOPIC SYLLABLE YE;Lo;0;L;;;;;N;;;;;
+12EE;ETHIOPIC SYLLABLE YO;Lo;0;L;;;;;N;;;;;
+12F0;ETHIOPIC SYLLABLE DA;Lo;0;L;;;;;N;;;;;
+12F1;ETHIOPIC SYLLABLE DU;Lo;0;L;;;;;N;;;;;
+12F2;ETHIOPIC SYLLABLE DI;Lo;0;L;;;;;N;;;;;
+12F3;ETHIOPIC SYLLABLE DAA;Lo;0;L;;;;;N;;;;;
+12F4;ETHIOPIC SYLLABLE DEE;Lo;0;L;;;;;N;;;;;
+12F5;ETHIOPIC SYLLABLE DE;Lo;0;L;;;;;N;;;;;
+12F6;ETHIOPIC SYLLABLE DO;Lo;0;L;;;;;N;;;;;
+12F7;ETHIOPIC SYLLABLE DWA;Lo;0;L;;;;;N;;;;;
+12F8;ETHIOPIC SYLLABLE DDA;Lo;0;L;;;;;N;;;;;
+12F9;ETHIOPIC SYLLABLE DDU;Lo;0;L;;;;;N;;;;;
+12FA;ETHIOPIC SYLLABLE DDI;Lo;0;L;;;;;N;;;;;
+12FB;ETHIOPIC SYLLABLE DDAA;Lo;0;L;;;;;N;;;;;
+12FC;ETHIOPIC SYLLABLE DDEE;Lo;0;L;;;;;N;;;;;
+12FD;ETHIOPIC SYLLABLE DDE;Lo;0;L;;;;;N;;;;;
+12FE;ETHIOPIC SYLLABLE DDO;Lo;0;L;;;;;N;;;;;
+12FF;ETHIOPIC SYLLABLE DDWA;Lo;0;L;;;;;N;;;;;
+1300;ETHIOPIC SYLLABLE JA;Lo;0;L;;;;;N;;;;;
+1301;ETHIOPIC SYLLABLE JU;Lo;0;L;;;;;N;;;;;
+1302;ETHIOPIC SYLLABLE JI;Lo;0;L;;;;;N;;;;;
+1303;ETHIOPIC SYLLABLE JAA;Lo;0;L;;;;;N;;;;;
+1304;ETHIOPIC SYLLABLE JEE;Lo;0;L;;;;;N;;;;;
+1305;ETHIOPIC SYLLABLE JE;Lo;0;L;;;;;N;;;;;
+1306;ETHIOPIC SYLLABLE JO;Lo;0;L;;;;;N;;;;;
+1307;ETHIOPIC SYLLABLE JWA;Lo;0;L;;;;;N;;;;;
+1308;ETHIOPIC SYLLABLE GA;Lo;0;L;;;;;N;;;;;
+1309;ETHIOPIC SYLLABLE GU;Lo;0;L;;;;;N;;;;;
+130A;ETHIOPIC SYLLABLE GI;Lo;0;L;;;;;N;;;;;
+130B;ETHIOPIC SYLLABLE GAA;Lo;0;L;;;;;N;;;;;
+130C;ETHIOPIC SYLLABLE GEE;Lo;0;L;;;;;N;;;;;
+130D;ETHIOPIC SYLLABLE GE;Lo;0;L;;;;;N;;;;;
+130E;ETHIOPIC SYLLABLE GO;Lo;0;L;;;;;N;;;;;
+1310;ETHIOPIC SYLLABLE GWA;Lo;0;L;;;;;N;;;;;
+1312;ETHIOPIC SYLLABLE GWI;Lo;0;L;;;;;N;;;;;
+1313;ETHIOPIC SYLLABLE GWAA;Lo;0;L;;;;;N;;;;;
+1314;ETHIOPIC SYLLABLE GWEE;Lo;0;L;;;;;N;;;;;
+1315;ETHIOPIC SYLLABLE GWE;Lo;0;L;;;;;N;;;;;
+1318;ETHIOPIC SYLLABLE GGA;Lo;0;L;;;;;N;;;;;
+1319;ETHIOPIC SYLLABLE GGU;Lo;0;L;;;;;N;;;;;
+131A;ETHIOPIC SYLLABLE GGI;Lo;0;L;;;;;N;;;;;
+131B;ETHIOPIC SYLLABLE GGAA;Lo;0;L;;;;;N;;;;;
+131C;ETHIOPIC SYLLABLE GGEE;Lo;0;L;;;;;N;;;;;
+131D;ETHIOPIC SYLLABLE GGE;Lo;0;L;;;;;N;;;;;
+131E;ETHIOPIC SYLLABLE GGO;Lo;0;L;;;;;N;;;;;
+1320;ETHIOPIC SYLLABLE THA;Lo;0;L;;;;;N;;;;;
+1321;ETHIOPIC SYLLABLE THU;Lo;0;L;;;;;N;;;;;
+1322;ETHIOPIC SYLLABLE THI;Lo;0;L;;;;;N;;;;;
+1323;ETHIOPIC SYLLABLE THAA;Lo;0;L;;;;;N;;;;;
+1324;ETHIOPIC SYLLABLE THEE;Lo;0;L;;;;;N;;;;;
+1325;ETHIOPIC SYLLABLE THE;Lo;0;L;;;;;N;;;;;
+1326;ETHIOPIC SYLLABLE THO;Lo;0;L;;;;;N;;;;;
+1327;ETHIOPIC SYLLABLE THWA;Lo;0;L;;;;;N;;;;;
+1328;ETHIOPIC SYLLABLE CHA;Lo;0;L;;;;;N;;;;;
+1329;ETHIOPIC SYLLABLE CHU;Lo;0;L;;;;;N;;;;;
+132A;ETHIOPIC SYLLABLE CHI;Lo;0;L;;;;;N;;;;;
+132B;ETHIOPIC SYLLABLE CHAA;Lo;0;L;;;;;N;;;;;
+132C;ETHIOPIC SYLLABLE CHEE;Lo;0;L;;;;;N;;;;;
+132D;ETHIOPIC SYLLABLE CHE;Lo;0;L;;;;;N;;;;;
+132E;ETHIOPIC SYLLABLE CHO;Lo;0;L;;;;;N;;;;;
+132F;ETHIOPIC SYLLABLE CHWA;Lo;0;L;;;;;N;;;;;
+1330;ETHIOPIC SYLLABLE PHA;Lo;0;L;;;;;N;;;;;
+1331;ETHIOPIC SYLLABLE PHU;Lo;0;L;;;;;N;;;;;
+1332;ETHIOPIC SYLLABLE PHI;Lo;0;L;;;;;N;;;;;
+1333;ETHIOPIC SYLLABLE PHAA;Lo;0;L;;;;;N;;;;;
+1334;ETHIOPIC SYLLABLE PHEE;Lo;0;L;;;;;N;;;;;
+1335;ETHIOPIC SYLLABLE PHE;Lo;0;L;;;;;N;;;;;
+1336;ETHIOPIC SYLLABLE PHO;Lo;0;L;;;;;N;;;;;
+1337;ETHIOPIC SYLLABLE PHWA;Lo;0;L;;;;;N;;;;;
+1338;ETHIOPIC SYLLABLE TSA;Lo;0;L;;;;;N;;;;;
+1339;ETHIOPIC SYLLABLE TSU;Lo;0;L;;;;;N;;;;;
+133A;ETHIOPIC SYLLABLE TSI;Lo;0;L;;;;;N;;;;;
+133B;ETHIOPIC SYLLABLE TSAA;Lo;0;L;;;;;N;;;;;
+133C;ETHIOPIC SYLLABLE TSEE;Lo;0;L;;;;;N;;;;;
+133D;ETHIOPIC SYLLABLE TSE;Lo;0;L;;;;;N;;;;;
+133E;ETHIOPIC SYLLABLE TSO;Lo;0;L;;;;;N;;;;;
+133F;ETHIOPIC SYLLABLE TSWA;Lo;0;L;;;;;N;;;;;
+1340;ETHIOPIC SYLLABLE TZA;Lo;0;L;;;;;N;;;;;
+1341;ETHIOPIC SYLLABLE TZU;Lo;0;L;;;;;N;;;;;
+1342;ETHIOPIC SYLLABLE TZI;Lo;0;L;;;;;N;;;;;
+1343;ETHIOPIC SYLLABLE TZAA;Lo;0;L;;;;;N;;;;;
+1344;ETHIOPIC SYLLABLE TZEE;Lo;0;L;;;;;N;;;;;
+1345;ETHIOPIC SYLLABLE TZE;Lo;0;L;;;;;N;;;;;
+1346;ETHIOPIC SYLLABLE TZO;Lo;0;L;;;;;N;;;;;
+1348;ETHIOPIC SYLLABLE FA;Lo;0;L;;;;;N;;;;;
+1349;ETHIOPIC SYLLABLE FU;Lo;0;L;;;;;N;;;;;
+134A;ETHIOPIC SYLLABLE FI;Lo;0;L;;;;;N;;;;;
+134B;ETHIOPIC SYLLABLE FAA;Lo;0;L;;;;;N;;;;;
+134C;ETHIOPIC SYLLABLE FEE;Lo;0;L;;;;;N;;;;;
+134D;ETHIOPIC SYLLABLE FE;Lo;0;L;;;;;N;;;;;
+134E;ETHIOPIC SYLLABLE FO;Lo;0;L;;;;;N;;;;;
+134F;ETHIOPIC SYLLABLE FWA;Lo;0;L;;;;;N;;;;;
+1350;ETHIOPIC SYLLABLE PA;Lo;0;L;;;;;N;;;;;
+1351;ETHIOPIC SYLLABLE PU;Lo;0;L;;;;;N;;;;;
+1352;ETHIOPIC SYLLABLE PI;Lo;0;L;;;;;N;;;;;
+1353;ETHIOPIC SYLLABLE PAA;Lo;0;L;;;;;N;;;;;
+1354;ETHIOPIC SYLLABLE PEE;Lo;0;L;;;;;N;;;;;
+1355;ETHIOPIC SYLLABLE PE;Lo;0;L;;;;;N;;;;;
+1356;ETHIOPIC SYLLABLE PO;Lo;0;L;;;;;N;;;;;
+1357;ETHIOPIC SYLLABLE PWA;Lo;0;L;;;;;N;;;;;
+1358;ETHIOPIC SYLLABLE RYA;Lo;0;L;;;;;N;;;;;
+1359;ETHIOPIC SYLLABLE MYA;Lo;0;L;;;;;N;;;;;
+135A;ETHIOPIC SYLLABLE FYA;Lo;0;L;;;;;N;;;;;
+1361;ETHIOPIC WORDSPACE;Po;0;L;;;;;N;;;;;
+1362;ETHIOPIC FULL STOP;Po;0;L;;;;;N;;;;;
+1363;ETHIOPIC COMMA;Po;0;L;;;;;N;;;;;
+1364;ETHIOPIC SEMICOLON;Po;0;L;;;;;N;;;;;
+1365;ETHIOPIC COLON;Po;0;L;;;;;N;;;;;
+1366;ETHIOPIC PREFACE COLON;Po;0;L;;;;;N;;;;;
+1367;ETHIOPIC QUESTION MARK;Po;0;L;;;;;N;;;;;
+1368;ETHIOPIC PARAGRAPH SEPARATOR;Po;0;L;;;;;N;;;;;
+1369;ETHIOPIC DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+136A;ETHIOPIC DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+136B;ETHIOPIC DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+136C;ETHIOPIC DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+136D;ETHIOPIC DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+136E;ETHIOPIC DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+136F;ETHIOPIC DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+1370;ETHIOPIC DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+1371;ETHIOPIC DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+1372;ETHIOPIC NUMBER TEN;No;0;L;;;;10;N;;;;;
+1373;ETHIOPIC NUMBER TWENTY;No;0;L;;;;20;N;;;;;
+1374;ETHIOPIC NUMBER THIRTY;No;0;L;;;;30;N;;;;;
+1375;ETHIOPIC NUMBER FORTY;No;0;L;;;;40;N;;;;;
+1376;ETHIOPIC NUMBER FIFTY;No;0;L;;;;50;N;;;;;
+1377;ETHIOPIC NUMBER SIXTY;No;0;L;;;;60;N;;;;;
+1378;ETHIOPIC NUMBER SEVENTY;No;0;L;;;;70;N;;;;;
+1379;ETHIOPIC NUMBER EIGHTY;No;0;L;;;;80;N;;;;;
+137A;ETHIOPIC NUMBER NINETY;No;0;L;;;;90;N;;;;;
+137B;ETHIOPIC NUMBER HUNDRED;No;0;L;;;;100;N;;;;;
+137C;ETHIOPIC NUMBER TEN THOUSAND;No;0;L;;;;10000;N;;;;;
+13A0;CHEROKEE LETTER A;Lo;0;L;;;;;N;;;;;
+13A1;CHEROKEE LETTER E;Lo;0;L;;;;;N;;;;;
+13A2;CHEROKEE LETTER I;Lo;0;L;;;;;N;;;;;
+13A3;CHEROKEE LETTER O;Lo;0;L;;;;;N;;;;;
+13A4;CHEROKEE LETTER U;Lo;0;L;;;;;N;;;;;
+13A5;CHEROKEE LETTER V;Lo;0;L;;;;;N;;;;;
+13A6;CHEROKEE LETTER GA;Lo;0;L;;;;;N;;;;;
+13A7;CHEROKEE LETTER KA;Lo;0;L;;;;;N;;;;;
+13A8;CHEROKEE LETTER GE;Lo;0;L;;;;;N;;;;;
+13A9;CHEROKEE LETTER GI;Lo;0;L;;;;;N;;;;;
+13AA;CHEROKEE LETTER GO;Lo;0;L;;;;;N;;;;;
+13AB;CHEROKEE LETTER GU;Lo;0;L;;;;;N;;;;;
+13AC;CHEROKEE LETTER GV;Lo;0;L;;;;;N;;;;;
+13AD;CHEROKEE LETTER HA;Lo;0;L;;;;;N;;;;;
+13AE;CHEROKEE LETTER HE;Lo;0;L;;;;;N;;;;;
+13AF;CHEROKEE LETTER HI;Lo;0;L;;;;;N;;;;;
+13B0;CHEROKEE LETTER HO;Lo;0;L;;;;;N;;;;;
+13B1;CHEROKEE LETTER HU;Lo;0;L;;;;;N;;;;;
+13B2;CHEROKEE LETTER HV;Lo;0;L;;;;;N;;;;;
+13B3;CHEROKEE LETTER LA;Lo;0;L;;;;;N;;;;;
+13B4;CHEROKEE LETTER LE;Lo;0;L;;;;;N;;;;;
+13B5;CHEROKEE LETTER LI;Lo;0;L;;;;;N;;;;;
+13B6;CHEROKEE LETTER LO;Lo;0;L;;;;;N;;;;;
+13B7;CHEROKEE LETTER LU;Lo;0;L;;;;;N;;;;;
+13B8;CHEROKEE LETTER LV;Lo;0;L;;;;;N;;;;;
+13B9;CHEROKEE LETTER MA;Lo;0;L;;;;;N;;;;;
+13BA;CHEROKEE LETTER ME;Lo;0;L;;;;;N;;;;;
+13BB;CHEROKEE LETTER MI;Lo;0;L;;;;;N;;;;;
+13BC;CHEROKEE LETTER MO;Lo;0;L;;;;;N;;;;;
+13BD;CHEROKEE LETTER MU;Lo;0;L;;;;;N;;;;;
+13BE;CHEROKEE LETTER NA;Lo;0;L;;;;;N;;;;;
+13BF;CHEROKEE LETTER HNA;Lo;0;L;;;;;N;;;;;
+13C0;CHEROKEE LETTER NAH;Lo;0;L;;;;;N;;;;;
+13C1;CHEROKEE LETTER NE;Lo;0;L;;;;;N;;;;;
+13C2;CHEROKEE LETTER NI;Lo;0;L;;;;;N;;;;;
+13C3;CHEROKEE LETTER NO;Lo;0;L;;;;;N;;;;;
+13C4;CHEROKEE LETTER NU;Lo;0;L;;;;;N;;;;;
+13C5;CHEROKEE LETTER NV;Lo;0;L;;;;;N;;;;;
+13C6;CHEROKEE LETTER QUA;Lo;0;L;;;;;N;;;;;
+13C7;CHEROKEE LETTER QUE;Lo;0;L;;;;;N;;;;;
+13C8;CHEROKEE LETTER QUI;Lo;0;L;;;;;N;;;;;
+13C9;CHEROKEE LETTER QUO;Lo;0;L;;;;;N;;;;;
+13CA;CHEROKEE LETTER QUU;Lo;0;L;;;;;N;;;;;
+13CB;CHEROKEE LETTER QUV;Lo;0;L;;;;;N;;;;;
+13CC;CHEROKEE LETTER SA;Lo;0;L;;;;;N;;;;;
+13CD;CHEROKEE LETTER S;Lo;0;L;;;;;N;;;;;
+13CE;CHEROKEE LETTER SE;Lo;0;L;;;;;N;;;;;
+13CF;CHEROKEE LETTER SI;Lo;0;L;;;;;N;;;;;
+13D0;CHEROKEE LETTER SO;Lo;0;L;;;;;N;;;;;
+13D1;CHEROKEE LETTER SU;Lo;0;L;;;;;N;;;;;
+13D2;CHEROKEE LETTER SV;Lo;0;L;;;;;N;;;;;
+13D3;CHEROKEE LETTER DA;Lo;0;L;;;;;N;;;;;
+13D4;CHEROKEE LETTER TA;Lo;0;L;;;;;N;;;;;
+13D5;CHEROKEE LETTER DE;Lo;0;L;;;;;N;;;;;
+13D6;CHEROKEE LETTER TE;Lo;0;L;;;;;N;;;;;
+13D7;CHEROKEE LETTER DI;Lo;0;L;;;;;N;;;;;
+13D8;CHEROKEE LETTER TI;Lo;0;L;;;;;N;;;;;
+13D9;CHEROKEE LETTER DO;Lo;0;L;;;;;N;;;;;
+13DA;CHEROKEE LETTER DU;Lo;0;L;;;;;N;;;;;
+13DB;CHEROKEE LETTER DV;Lo;0;L;;;;;N;;;;;
+13DC;CHEROKEE LETTER DLA;Lo;0;L;;;;;N;;;;;
+13DD;CHEROKEE LETTER TLA;Lo;0;L;;;;;N;;;;;
+13DE;CHEROKEE LETTER TLE;Lo;0;L;;;;;N;;;;;
+13DF;CHEROKEE LETTER TLI;Lo;0;L;;;;;N;;;;;
+13E0;CHEROKEE LETTER TLO;Lo;0;L;;;;;N;;;;;
+13E1;CHEROKEE LETTER TLU;Lo;0;L;;;;;N;;;;;
+13E2;CHEROKEE LETTER TLV;Lo;0;L;;;;;N;;;;;
+13E3;CHEROKEE LETTER TSA;Lo;0;L;;;;;N;;;;;
+13E4;CHEROKEE LETTER TSE;Lo;0;L;;;;;N;;;;;
+13E5;CHEROKEE LETTER TSI;Lo;0;L;;;;;N;;;;;
+13E6;CHEROKEE LETTER TSO;Lo;0;L;;;;;N;;;;;
+13E7;CHEROKEE LETTER TSU;Lo;0;L;;;;;N;;;;;
+13E8;CHEROKEE LETTER TSV;Lo;0;L;;;;;N;;;;;
+13E9;CHEROKEE LETTER WA;Lo;0;L;;;;;N;;;;;
+13EA;CHEROKEE LETTER WE;Lo;0;L;;;;;N;;;;;
+13EB;CHEROKEE LETTER WI;Lo;0;L;;;;;N;;;;;
+13EC;CHEROKEE LETTER WO;Lo;0;L;;;;;N;;;;;
+13ED;CHEROKEE LETTER WU;Lo;0;L;;;;;N;;;;;
+13EE;CHEROKEE LETTER WV;Lo;0;L;;;;;N;;;;;
+13EF;CHEROKEE LETTER YA;Lo;0;L;;;;;N;;;;;
+13F0;CHEROKEE LETTER YE;Lo;0;L;;;;;N;;;;;
+13F1;CHEROKEE LETTER YI;Lo;0;L;;;;;N;;;;;
+13F2;CHEROKEE LETTER YO;Lo;0;L;;;;;N;;;;;
+13F3;CHEROKEE LETTER YU;Lo;0;L;;;;;N;;;;;
+13F4;CHEROKEE LETTER YV;Lo;0;L;;;;;N;;;;;
+1401;CANADIAN SYLLABICS E;Lo;0;L;;;;;N;;;;;
+1402;CANADIAN SYLLABICS AAI;Lo;0;L;;;;;N;;;;;
+1403;CANADIAN SYLLABICS I;Lo;0;L;;;;;N;;;;;
+1404;CANADIAN SYLLABICS II;Lo;0;L;;;;;N;;;;;
+1405;CANADIAN SYLLABICS O;Lo;0;L;;;;;N;;;;;
+1406;CANADIAN SYLLABICS OO;Lo;0;L;;;;;N;;;;;
+1407;CANADIAN SYLLABICS Y-CREE OO;Lo;0;L;;;;;N;;;;;
+1408;CANADIAN SYLLABICS CARRIER EE;Lo;0;L;;;;;N;;;;;
+1409;CANADIAN SYLLABICS CARRIER I;Lo;0;L;;;;;N;;;;;
+140A;CANADIAN SYLLABICS A;Lo;0;L;;;;;N;;;;;
+140B;CANADIAN SYLLABICS AA;Lo;0;L;;;;;N;;;;;
+140C;CANADIAN SYLLABICS WE;Lo;0;L;;;;;N;;;;;
+140D;CANADIAN SYLLABICS WEST-CREE WE;Lo;0;L;;;;;N;;;;;
+140E;CANADIAN SYLLABICS WI;Lo;0;L;;;;;N;;;;;
+140F;CANADIAN SYLLABICS WEST-CREE WI;Lo;0;L;;;;;N;;;;;
+1410;CANADIAN SYLLABICS WII;Lo;0;L;;;;;N;;;;;
+1411;CANADIAN SYLLABICS WEST-CREE WII;Lo;0;L;;;;;N;;;;;
+1412;CANADIAN SYLLABICS WO;Lo;0;L;;;;;N;;;;;
+1413;CANADIAN SYLLABICS WEST-CREE WO;Lo;0;L;;;;;N;;;;;
+1414;CANADIAN SYLLABICS WOO;Lo;0;L;;;;;N;;;;;
+1415;CANADIAN SYLLABICS WEST-CREE WOO;Lo;0;L;;;;;N;;;;;
+1416;CANADIAN SYLLABICS NASKAPI WOO;Lo;0;L;;;;;N;;;;;
+1417;CANADIAN SYLLABICS WA;Lo;0;L;;;;;N;;;;;
+1418;CANADIAN SYLLABICS WEST-CREE WA;Lo;0;L;;;;;N;;;;;
+1419;CANADIAN SYLLABICS WAA;Lo;0;L;;;;;N;;;;;
+141A;CANADIAN SYLLABICS WEST-CREE WAA;Lo;0;L;;;;;N;;;;;
+141B;CANADIAN SYLLABICS NASKAPI WAA;Lo;0;L;;;;;N;;;;;
+141C;CANADIAN SYLLABICS AI;Lo;0;L;;;;;N;;;;;
+141D;CANADIAN SYLLABICS Y-CREE W;Lo;0;L;;;;;N;;;;;
+141E;CANADIAN SYLLABICS GLOTTAL STOP;Lo;0;L;;;;;N;;;;;
+141F;CANADIAN SYLLABICS FINAL ACUTE;Lo;0;L;;;;;N;;;;;
+1420;CANADIAN SYLLABICS FINAL GRAVE;Lo;0;L;;;;;N;;;;;
+1421;CANADIAN SYLLABICS FINAL BOTTOM HALF RING;Lo;0;L;;;;;N;;;;;
+1422;CANADIAN SYLLABICS FINAL TOP HALF RING;Lo;0;L;;;;;N;;;;;
+1423;CANADIAN SYLLABICS FINAL RIGHT HALF RING;Lo;0;L;;;;;N;;;;;
+1424;CANADIAN SYLLABICS FINAL RING;Lo;0;L;;;;;N;;;;;
+1425;CANADIAN SYLLABICS FINAL DOUBLE ACUTE;Lo;0;L;;;;;N;;;;;
+1426;CANADIAN SYLLABICS FINAL DOUBLE SHORT VERTICAL STROKES;Lo;0;L;;;;;N;;;;;
+1427;CANADIAN SYLLABICS FINAL MIDDLE DOT;Lo;0;L;;;;;N;;;;;
+1428;CANADIAN SYLLABICS FINAL SHORT HORIZONTAL STROKE;Lo;0;L;;;;;N;;;;;
+1429;CANADIAN SYLLABICS FINAL PLUS;Lo;0;L;;;;;N;;;;;
+142A;CANADIAN SYLLABICS FINAL DOWN TACK;Lo;0;L;;;;;N;;;;;
+142B;CANADIAN SYLLABICS EN;Lo;0;L;;;;;N;;;;;
+142C;CANADIAN SYLLABICS IN;Lo;0;L;;;;;N;;;;;
+142D;CANADIAN SYLLABICS ON;Lo;0;L;;;;;N;;;;;
+142E;CANADIAN SYLLABICS AN;Lo;0;L;;;;;N;;;;;
+142F;CANADIAN SYLLABICS PE;Lo;0;L;;;;;N;;;;;
+1430;CANADIAN SYLLABICS PAAI;Lo;0;L;;;;;N;;;;;
+1431;CANADIAN SYLLABICS PI;Lo;0;L;;;;;N;;;;;
+1432;CANADIAN SYLLABICS PII;Lo;0;L;;;;;N;;;;;
+1433;CANADIAN SYLLABICS PO;Lo;0;L;;;;;N;;;;;
+1434;CANADIAN SYLLABICS POO;Lo;0;L;;;;;N;;;;;
+1435;CANADIAN SYLLABICS Y-CREE POO;Lo;0;L;;;;;N;;;;;
+1436;CANADIAN SYLLABICS CARRIER HEE;Lo;0;L;;;;;N;;;;;
+1437;CANADIAN SYLLABICS CARRIER HI;Lo;0;L;;;;;N;;;;;
+1438;CANADIAN SYLLABICS PA;Lo;0;L;;;;;N;;;;;
+1439;CANADIAN SYLLABICS PAA;Lo;0;L;;;;;N;;;;;
+143A;CANADIAN SYLLABICS PWE;Lo;0;L;;;;;N;;;;;
+143B;CANADIAN SYLLABICS WEST-CREE PWE;Lo;0;L;;;;;N;;;;;
+143C;CANADIAN SYLLABICS PWI;Lo;0;L;;;;;N;;;;;
+143D;CANADIAN SYLLABICS WEST-CREE PWI;Lo;0;L;;;;;N;;;;;
+143E;CANADIAN SYLLABICS PWII;Lo;0;L;;;;;N;;;;;
+143F;CANADIAN SYLLABICS WEST-CREE PWII;Lo;0;L;;;;;N;;;;;
+1440;CANADIAN SYLLABICS PWO;Lo;0;L;;;;;N;;;;;
+1441;CANADIAN SYLLABICS WEST-CREE PWO;Lo;0;L;;;;;N;;;;;
+1442;CANADIAN SYLLABICS PWOO;Lo;0;L;;;;;N;;;;;
+1443;CANADIAN SYLLABICS WEST-CREE PWOO;Lo;0;L;;;;;N;;;;;
+1444;CANADIAN SYLLABICS PWA;Lo;0;L;;;;;N;;;;;
+1445;CANADIAN SYLLABICS WEST-CREE PWA;Lo;0;L;;;;;N;;;;;
+1446;CANADIAN SYLLABICS PWAA;Lo;0;L;;;;;N;;;;;
+1447;CANADIAN SYLLABICS WEST-CREE PWAA;Lo;0;L;;;;;N;;;;;
+1448;CANADIAN SYLLABICS Y-CREE PWAA;Lo;0;L;;;;;N;;;;;
+1449;CANADIAN SYLLABICS P;Lo;0;L;;;;;N;;;;;
+144A;CANADIAN SYLLABICS WEST-CREE P;Lo;0;L;;;;;N;;;;;
+144B;CANADIAN SYLLABICS CARRIER H;Lo;0;L;;;;;N;;;;;
+144C;CANADIAN SYLLABICS TE;Lo;0;L;;;;;N;;;;;
+144D;CANADIAN SYLLABICS TAAI;Lo;0;L;;;;;N;;;;;
+144E;CANADIAN SYLLABICS TI;Lo;0;L;;;;;N;;;;;
+144F;CANADIAN SYLLABICS TII;Lo;0;L;;;;;N;;;;;
+1450;CANADIAN SYLLABICS TO;Lo;0;L;;;;;N;;;;;
+1451;CANADIAN SYLLABICS TOO;Lo;0;L;;;;;N;;;;;
+1452;CANADIAN SYLLABICS Y-CREE TOO;Lo;0;L;;;;;N;;;;;
+1453;CANADIAN SYLLABICS CARRIER DEE;Lo;0;L;;;;;N;;;;;
+1454;CANADIAN SYLLABICS CARRIER DI;Lo;0;L;;;;;N;;;;;
+1455;CANADIAN SYLLABICS TA;Lo;0;L;;;;;N;;;;;
+1456;CANADIAN SYLLABICS TAA;Lo;0;L;;;;;N;;;;;
+1457;CANADIAN SYLLABICS TWE;Lo;0;L;;;;;N;;;;;
+1458;CANADIAN SYLLABICS WEST-CREE TWE;Lo;0;L;;;;;N;;;;;
+1459;CANADIAN SYLLABICS TWI;Lo;0;L;;;;;N;;;;;
+145A;CANADIAN SYLLABICS WEST-CREE TWI;Lo;0;L;;;;;N;;;;;
+145B;CANADIAN SYLLABICS TWII;Lo;0;L;;;;;N;;;;;
+145C;CANADIAN SYLLABICS WEST-CREE TWII;Lo;0;L;;;;;N;;;;;
+145D;CANADIAN SYLLABICS TWO;Lo;0;L;;;;;N;;;;;
+145E;CANADIAN SYLLABICS WEST-CREE TWO;Lo;0;L;;;;;N;;;;;
+145F;CANADIAN SYLLABICS TWOO;Lo;0;L;;;;;N;;;;;
+1460;CANADIAN SYLLABICS WEST-CREE TWOO;Lo;0;L;;;;;N;;;;;
+1461;CANADIAN SYLLABICS TWA;Lo;0;L;;;;;N;;;;;
+1462;CANADIAN SYLLABICS WEST-CREE TWA;Lo;0;L;;;;;N;;;;;
+1463;CANADIAN SYLLABICS TWAA;Lo;0;L;;;;;N;;;;;
+1464;CANADIAN SYLLABICS WEST-CREE TWAA;Lo;0;L;;;;;N;;;;;
+1465;CANADIAN SYLLABICS NASKAPI TWAA;Lo;0;L;;;;;N;;;;;
+1466;CANADIAN SYLLABICS T;Lo;0;L;;;;;N;;;;;
+1467;CANADIAN SYLLABICS TTE;Lo;0;L;;;;;N;;;;;
+1468;CANADIAN SYLLABICS TTI;Lo;0;L;;;;;N;;;;;
+1469;CANADIAN SYLLABICS TTO;Lo;0;L;;;;;N;;;;;
+146A;CANADIAN SYLLABICS TTA;Lo;0;L;;;;;N;;;;;
+146B;CANADIAN SYLLABICS KE;Lo;0;L;;;;;N;;;;;
+146C;CANADIAN SYLLABICS KAAI;Lo;0;L;;;;;N;;;;;
+146D;CANADIAN SYLLABICS KI;Lo;0;L;;;;;N;;;;;
+146E;CANADIAN SYLLABICS KII;Lo;0;L;;;;;N;;;;;
+146F;CANADIAN SYLLABICS KO;Lo;0;L;;;;;N;;;;;
+1470;CANADIAN SYLLABICS KOO;Lo;0;L;;;;;N;;;;;
+1471;CANADIAN SYLLABICS Y-CREE KOO;Lo;0;L;;;;;N;;;;;
+1472;CANADIAN SYLLABICS KA;Lo;0;L;;;;;N;;;;;
+1473;CANADIAN SYLLABICS KAA;Lo;0;L;;;;;N;;;;;
+1474;CANADIAN SYLLABICS KWE;Lo;0;L;;;;;N;;;;;
+1475;CANADIAN SYLLABICS WEST-CREE KWE;Lo;0;L;;;;;N;;;;;
+1476;CANADIAN SYLLABICS KWI;Lo;0;L;;;;;N;;;;;
+1477;CANADIAN SYLLABICS WEST-CREE KWI;Lo;0;L;;;;;N;;;;;
+1478;CANADIAN SYLLABICS KWII;Lo;0;L;;;;;N;;;;;
+1479;CANADIAN SYLLABICS WEST-CREE KWII;Lo;0;L;;;;;N;;;;;
+147A;CANADIAN SYLLABICS KWO;Lo;0;L;;;;;N;;;;;
+147B;CANADIAN SYLLABICS WEST-CREE KWO;Lo;0;L;;;;;N;;;;;
+147C;CANADIAN SYLLABICS KWOO;Lo;0;L;;;;;N;;;;;
+147D;CANADIAN SYLLABICS WEST-CREE KWOO;Lo;0;L;;;;;N;;;;;
+147E;CANADIAN SYLLABICS KWA;Lo;0;L;;;;;N;;;;;
+147F;CANADIAN SYLLABICS WEST-CREE KWA;Lo;0;L;;;;;N;;;;;
+1480;CANADIAN SYLLABICS KWAA;Lo;0;L;;;;;N;;;;;
+1481;CANADIAN SYLLABICS WEST-CREE KWAA;Lo;0;L;;;;;N;;;;;
+1482;CANADIAN SYLLABICS NASKAPI KWAA;Lo;0;L;;;;;N;;;;;
+1483;CANADIAN SYLLABICS K;Lo;0;L;;;;;N;;;;;
+1484;CANADIAN SYLLABICS KW;Lo;0;L;;;;;N;;;;;
+1485;CANADIAN SYLLABICS SOUTH-SLAVEY KEH;Lo;0;L;;;;;N;;;;;
+1486;CANADIAN SYLLABICS SOUTH-SLAVEY KIH;Lo;0;L;;;;;N;;;;;
+1487;CANADIAN SYLLABICS SOUTH-SLAVEY KOH;Lo;0;L;;;;;N;;;;;
+1488;CANADIAN SYLLABICS SOUTH-SLAVEY KAH;Lo;0;L;;;;;N;;;;;
+1489;CANADIAN SYLLABICS CE;Lo;0;L;;;;;N;;;;;
+148A;CANADIAN SYLLABICS CAAI;Lo;0;L;;;;;N;;;;;
+148B;CANADIAN SYLLABICS CI;Lo;0;L;;;;;N;;;;;
+148C;CANADIAN SYLLABICS CII;Lo;0;L;;;;;N;;;;;
+148D;CANADIAN SYLLABICS CO;Lo;0;L;;;;;N;;;;;
+148E;CANADIAN SYLLABICS COO;Lo;0;L;;;;;N;;;;;
+148F;CANADIAN SYLLABICS Y-CREE COO;Lo;0;L;;;;;N;;;;;
+1490;CANADIAN SYLLABICS CA;Lo;0;L;;;;;N;;;;;
+1491;CANADIAN SYLLABICS CAA;Lo;0;L;;;;;N;;;;;
+1492;CANADIAN SYLLABICS CWE;Lo;0;L;;;;;N;;;;;
+1493;CANADIAN SYLLABICS WEST-CREE CWE;Lo;0;L;;;;;N;;;;;
+1494;CANADIAN SYLLABICS CWI;Lo;0;L;;;;;N;;;;;
+1495;CANADIAN SYLLABICS WEST-CREE CWI;Lo;0;L;;;;;N;;;;;
+1496;CANADIAN SYLLABICS CWII;Lo;0;L;;;;;N;;;;;
+1497;CANADIAN SYLLABICS WEST-CREE CWII;Lo;0;L;;;;;N;;;;;
+1498;CANADIAN SYLLABICS CWO;Lo;0;L;;;;;N;;;;;
+1499;CANADIAN SYLLABICS WEST-CREE CWO;Lo;0;L;;;;;N;;;;;
+149A;CANADIAN SYLLABICS CWOO;Lo;0;L;;;;;N;;;;;
+149B;CANADIAN SYLLABICS WEST-CREE CWOO;Lo;0;L;;;;;N;;;;;
+149C;CANADIAN SYLLABICS CWA;Lo;0;L;;;;;N;;;;;
+149D;CANADIAN SYLLABICS WEST-CREE CWA;Lo;0;L;;;;;N;;;;;
+149E;CANADIAN SYLLABICS CWAA;Lo;0;L;;;;;N;;;;;
+149F;CANADIAN SYLLABICS WEST-CREE CWAA;Lo;0;L;;;;;N;;;;;
+14A0;CANADIAN SYLLABICS NASKAPI CWAA;Lo;0;L;;;;;N;;;;;
+14A1;CANADIAN SYLLABICS C;Lo;0;L;;;;;N;;;;;
+14A2;CANADIAN SYLLABICS SAYISI TH;Lo;0;L;;;;;N;;;;;
+14A3;CANADIAN SYLLABICS ME;Lo;0;L;;;;;N;;;;;
+14A4;CANADIAN SYLLABICS MAAI;Lo;0;L;;;;;N;;;;;
+14A5;CANADIAN SYLLABICS MI;Lo;0;L;;;;;N;;;;;
+14A6;CANADIAN SYLLABICS MII;Lo;0;L;;;;;N;;;;;
+14A7;CANADIAN SYLLABICS MO;Lo;0;L;;;;;N;;;;;
+14A8;CANADIAN SYLLABICS MOO;Lo;0;L;;;;;N;;;;;
+14A9;CANADIAN SYLLABICS Y-CREE MOO;Lo;0;L;;;;;N;;;;;
+14AA;CANADIAN SYLLABICS MA;Lo;0;L;;;;;N;;;;;
+14AB;CANADIAN SYLLABICS MAA;Lo;0;L;;;;;N;;;;;
+14AC;CANADIAN SYLLABICS MWE;Lo;0;L;;;;;N;;;;;
+14AD;CANADIAN SYLLABICS WEST-CREE MWE;Lo;0;L;;;;;N;;;;;
+14AE;CANADIAN SYLLABICS MWI;Lo;0;L;;;;;N;;;;;
+14AF;CANADIAN SYLLABICS WEST-CREE MWI;Lo;0;L;;;;;N;;;;;
+14B0;CANADIAN SYLLABICS MWII;Lo;0;L;;;;;N;;;;;
+14B1;CANADIAN SYLLABICS WEST-CREE MWII;Lo;0;L;;;;;N;;;;;
+14B2;CANADIAN SYLLABICS MWO;Lo;0;L;;;;;N;;;;;
+14B3;CANADIAN SYLLABICS WEST-CREE MWO;Lo;0;L;;;;;N;;;;;
+14B4;CANADIAN SYLLABICS MWOO;Lo;0;L;;;;;N;;;;;
+14B5;CANADIAN SYLLABICS WEST-CREE MWOO;Lo;0;L;;;;;N;;;;;
+14B6;CANADIAN SYLLABICS MWA;Lo;0;L;;;;;N;;;;;
+14B7;CANADIAN SYLLABICS WEST-CREE MWA;Lo;0;L;;;;;N;;;;;
+14B8;CANADIAN SYLLABICS MWAA;Lo;0;L;;;;;N;;;;;
+14B9;CANADIAN SYLLABICS WEST-CREE MWAA;Lo;0;L;;;;;N;;;;;
+14BA;CANADIAN SYLLABICS NASKAPI MWAA;Lo;0;L;;;;;N;;;;;
+14BB;CANADIAN SYLLABICS M;Lo;0;L;;;;;N;;;;;
+14BC;CANADIAN SYLLABICS WEST-CREE M;Lo;0;L;;;;;N;;;;;
+14BD;CANADIAN SYLLABICS MH;Lo;0;L;;;;;N;;;;;
+14BE;CANADIAN SYLLABICS ATHAPASCAN M;Lo;0;L;;;;;N;;;;;
+14BF;CANADIAN SYLLABICS SAYISI M;Lo;0;L;;;;;N;;;;;
+14C0;CANADIAN SYLLABICS NE;Lo;0;L;;;;;N;;;;;
+14C1;CANADIAN SYLLABICS NAAI;Lo;0;L;;;;;N;;;;;
+14C2;CANADIAN SYLLABICS NI;Lo;0;L;;;;;N;;;;;
+14C3;CANADIAN SYLLABICS NII;Lo;0;L;;;;;N;;;;;
+14C4;CANADIAN SYLLABICS NO;Lo;0;L;;;;;N;;;;;
+14C5;CANADIAN SYLLABICS NOO;Lo;0;L;;;;;N;;;;;
+14C6;CANADIAN SYLLABICS Y-CREE NOO;Lo;0;L;;;;;N;;;;;
+14C7;CANADIAN SYLLABICS NA;Lo;0;L;;;;;N;;;;;
+14C8;CANADIAN SYLLABICS NAA;Lo;0;L;;;;;N;;;;;
+14C9;CANADIAN SYLLABICS NWE;Lo;0;L;;;;;N;;;;;
+14CA;CANADIAN SYLLABICS WEST-CREE NWE;Lo;0;L;;;;;N;;;;;
+14CB;CANADIAN SYLLABICS NWA;Lo;0;L;;;;;N;;;;;
+14CC;CANADIAN SYLLABICS WEST-CREE NWA;Lo;0;L;;;;;N;;;;;
+14CD;CANADIAN SYLLABICS NWAA;Lo;0;L;;;;;N;;;;;
+14CE;CANADIAN SYLLABICS WEST-CREE NWAA;Lo;0;L;;;;;N;;;;;
+14CF;CANADIAN SYLLABICS NASKAPI NWAA;Lo;0;L;;;;;N;;;;;
+14D0;CANADIAN SYLLABICS N;Lo;0;L;;;;;N;;;;;
+14D1;CANADIAN SYLLABICS CARRIER NG;Lo;0;L;;;;;N;;;;;
+14D2;CANADIAN SYLLABICS NH;Lo;0;L;;;;;N;;;;;
+14D3;CANADIAN SYLLABICS LE;Lo;0;L;;;;;N;;;;;
+14D4;CANADIAN SYLLABICS LAAI;Lo;0;L;;;;;N;;;;;
+14D5;CANADIAN SYLLABICS LI;Lo;0;L;;;;;N;;;;;
+14D6;CANADIAN SYLLABICS LII;Lo;0;L;;;;;N;;;;;
+14D7;CANADIAN SYLLABICS LO;Lo;0;L;;;;;N;;;;;
+14D8;CANADIAN SYLLABICS LOO;Lo;0;L;;;;;N;;;;;
+14D9;CANADIAN SYLLABICS Y-CREE LOO;Lo;0;L;;;;;N;;;;;
+14DA;CANADIAN SYLLABICS LA;Lo;0;L;;;;;N;;;;;
+14DB;CANADIAN SYLLABICS LAA;Lo;0;L;;;;;N;;;;;
+14DC;CANADIAN SYLLABICS LWE;Lo;0;L;;;;;N;;;;;
+14DD;CANADIAN SYLLABICS WEST-CREE LWE;Lo;0;L;;;;;N;;;;;
+14DE;CANADIAN SYLLABICS LWI;Lo;0;L;;;;;N;;;;;
+14DF;CANADIAN SYLLABICS WEST-CREE LWI;Lo;0;L;;;;;N;;;;;
+14E0;CANADIAN SYLLABICS LWII;Lo;0;L;;;;;N;;;;;
+14E1;CANADIAN SYLLABICS WEST-CREE LWII;Lo;0;L;;;;;N;;;;;
+14E2;CANADIAN SYLLABICS LWO;Lo;0;L;;;;;N;;;;;
+14E3;CANADIAN SYLLABICS WEST-CREE LWO;Lo;0;L;;;;;N;;;;;
+14E4;CANADIAN SYLLABICS LWOO;Lo;0;L;;;;;N;;;;;
+14E5;CANADIAN SYLLABICS WEST-CREE LWOO;Lo;0;L;;;;;N;;;;;
+14E6;CANADIAN SYLLABICS LWA;Lo;0;L;;;;;N;;;;;
+14E7;CANADIAN SYLLABICS WEST-CREE LWA;Lo;0;L;;;;;N;;;;;
+14E8;CANADIAN SYLLABICS LWAA;Lo;0;L;;;;;N;;;;;
+14E9;CANADIAN SYLLABICS WEST-CREE LWAA;Lo;0;L;;;;;N;;;;;
+14EA;CANADIAN SYLLABICS L;Lo;0;L;;;;;N;;;;;
+14EB;CANADIAN SYLLABICS WEST-CREE L;Lo;0;L;;;;;N;;;;;
+14EC;CANADIAN SYLLABICS MEDIAL L;Lo;0;L;;;;;N;;;;;
+14ED;CANADIAN SYLLABICS SE;Lo;0;L;;;;;N;;;;;
+14EE;CANADIAN SYLLABICS SAAI;Lo;0;L;;;;;N;;;;;
+14EF;CANADIAN SYLLABICS SI;Lo;0;L;;;;;N;;;;;
+14F0;CANADIAN SYLLABICS SII;Lo;0;L;;;;;N;;;;;
+14F1;CANADIAN SYLLABICS SO;Lo;0;L;;;;;N;;;;;
+14F2;CANADIAN SYLLABICS SOO;Lo;0;L;;;;;N;;;;;
+14F3;CANADIAN SYLLABICS Y-CREE SOO;Lo;0;L;;;;;N;;;;;
+14F4;CANADIAN SYLLABICS SA;Lo;0;L;;;;;N;;;;;
+14F5;CANADIAN SYLLABICS SAA;Lo;0;L;;;;;N;;;;;
+14F6;CANADIAN SYLLABICS SWE;Lo;0;L;;;;;N;;;;;
+14F7;CANADIAN SYLLABICS WEST-CREE SWE;Lo;0;L;;;;;N;;;;;
+14F8;CANADIAN SYLLABICS SWI;Lo;0;L;;;;;N;;;;;
+14F9;CANADIAN SYLLABICS WEST-CREE SWI;Lo;0;L;;;;;N;;;;;
+14FA;CANADIAN SYLLABICS SWII;Lo;0;L;;;;;N;;;;;
+14FB;CANADIAN SYLLABICS WEST-CREE SWII;Lo;0;L;;;;;N;;;;;
+14FC;CANADIAN SYLLABICS SWO;Lo;0;L;;;;;N;;;;;
+14FD;CANADIAN SYLLABICS WEST-CREE SWO;Lo;0;L;;;;;N;;;;;
+14FE;CANADIAN SYLLABICS SWOO;Lo;0;L;;;;;N;;;;;
+14FF;CANADIAN SYLLABICS WEST-CREE SWOO;Lo;0;L;;;;;N;;;;;
+1500;CANADIAN SYLLABICS SWA;Lo;0;L;;;;;N;;;;;
+1501;CANADIAN SYLLABICS WEST-CREE SWA;Lo;0;L;;;;;N;;;;;
+1502;CANADIAN SYLLABICS SWAA;Lo;0;L;;;;;N;;;;;
+1503;CANADIAN SYLLABICS WEST-CREE SWAA;Lo;0;L;;;;;N;;;;;
+1504;CANADIAN SYLLABICS NASKAPI SWAA;Lo;0;L;;;;;N;;;;;
+1505;CANADIAN SYLLABICS S;Lo;0;L;;;;;N;;;;;
+1506;CANADIAN SYLLABICS ATHAPASCAN S;Lo;0;L;;;;;N;;;;;
+1507;CANADIAN SYLLABICS SW;Lo;0;L;;;;;N;;;;;
+1508;CANADIAN SYLLABICS BLACKFOOT S;Lo;0;L;;;;;N;;;;;
+1509;CANADIAN SYLLABICS MOOSE-CREE SK;Lo;0;L;;;;;N;;;;;
+150A;CANADIAN SYLLABICS NASKAPI SKW;Lo;0;L;;;;;N;;;;;
+150B;CANADIAN SYLLABICS NASKAPI S-W;Lo;0;L;;;;;N;;;;;
+150C;CANADIAN SYLLABICS NASKAPI SPWA;Lo;0;L;;;;;N;;;;;
+150D;CANADIAN SYLLABICS NASKAPI STWA;Lo;0;L;;;;;N;;;;;
+150E;CANADIAN SYLLABICS NASKAPI SKWA;Lo;0;L;;;;;N;;;;;
+150F;CANADIAN SYLLABICS NASKAPI SCWA;Lo;0;L;;;;;N;;;;;
+1510;CANADIAN SYLLABICS SHE;Lo;0;L;;;;;N;;;;;
+1511;CANADIAN SYLLABICS SHI;Lo;0;L;;;;;N;;;;;
+1512;CANADIAN SYLLABICS SHII;Lo;0;L;;;;;N;;;;;
+1513;CANADIAN SYLLABICS SHO;Lo;0;L;;;;;N;;;;;
+1514;CANADIAN SYLLABICS SHOO;Lo;0;L;;;;;N;;;;;
+1515;CANADIAN SYLLABICS SHA;Lo;0;L;;;;;N;;;;;
+1516;CANADIAN SYLLABICS SHAA;Lo;0;L;;;;;N;;;;;
+1517;CANADIAN SYLLABICS SHWE;Lo;0;L;;;;;N;;;;;
+1518;CANADIAN SYLLABICS WEST-CREE SHWE;Lo;0;L;;;;;N;;;;;
+1519;CANADIAN SYLLABICS SHWI;Lo;0;L;;;;;N;;;;;
+151A;CANADIAN SYLLABICS WEST-CREE SHWI;Lo;0;L;;;;;N;;;;;
+151B;CANADIAN SYLLABICS SHWII;Lo;0;L;;;;;N;;;;;
+151C;CANADIAN SYLLABICS WEST-CREE SHWII;Lo;0;L;;;;;N;;;;;
+151D;CANADIAN SYLLABICS SHWO;Lo;0;L;;;;;N;;;;;
+151E;CANADIAN SYLLABICS WEST-CREE SHWO;Lo;0;L;;;;;N;;;;;
+151F;CANADIAN SYLLABICS SHWOO;Lo;0;L;;;;;N;;;;;
+1520;CANADIAN SYLLABICS WEST-CREE SHWOO;Lo;0;L;;;;;N;;;;;
+1521;CANADIAN SYLLABICS SHWA;Lo;0;L;;;;;N;;;;;
+1522;CANADIAN SYLLABICS WEST-CREE SHWA;Lo;0;L;;;;;N;;;;;
+1523;CANADIAN SYLLABICS SHWAA;Lo;0;L;;;;;N;;;;;
+1524;CANADIAN SYLLABICS WEST-CREE SHWAA;Lo;0;L;;;;;N;;;;;
+1525;CANADIAN SYLLABICS SH;Lo;0;L;;;;;N;;;;;
+1526;CANADIAN SYLLABICS YE;Lo;0;L;;;;;N;;;;;
+1527;CANADIAN SYLLABICS YAAI;Lo;0;L;;;;;N;;;;;
+1528;CANADIAN SYLLABICS YI;Lo;0;L;;;;;N;;;;;
+1529;CANADIAN SYLLABICS YII;Lo;0;L;;;;;N;;;;;
+152A;CANADIAN SYLLABICS YO;Lo;0;L;;;;;N;;;;;
+152B;CANADIAN SYLLABICS YOO;Lo;0;L;;;;;N;;;;;
+152C;CANADIAN SYLLABICS Y-CREE YOO;Lo;0;L;;;;;N;;;;;
+152D;CANADIAN SYLLABICS YA;Lo;0;L;;;;;N;;;;;
+152E;CANADIAN SYLLABICS YAA;Lo;0;L;;;;;N;;;;;
+152F;CANADIAN SYLLABICS YWE;Lo;0;L;;;;;N;;;;;
+1530;CANADIAN SYLLABICS WEST-CREE YWE;Lo;0;L;;;;;N;;;;;
+1531;CANADIAN SYLLABICS YWI;Lo;0;L;;;;;N;;;;;
+1532;CANADIAN SYLLABICS WEST-CREE YWI;Lo;0;L;;;;;N;;;;;
+1533;CANADIAN SYLLABICS YWII;Lo;0;L;;;;;N;;;;;
+1534;CANADIAN SYLLABICS WEST-CREE YWII;Lo;0;L;;;;;N;;;;;
+1535;CANADIAN SYLLABICS YWO;Lo;0;L;;;;;N;;;;;
+1536;CANADIAN SYLLABICS WEST-CREE YWO;Lo;0;L;;;;;N;;;;;
+1537;CANADIAN SYLLABICS YWOO;Lo;0;L;;;;;N;;;;;
+1538;CANADIAN SYLLABICS WEST-CREE YWOO;Lo;0;L;;;;;N;;;;;
+1539;CANADIAN SYLLABICS YWA;Lo;0;L;;;;;N;;;;;
+153A;CANADIAN SYLLABICS WEST-CREE YWA;Lo;0;L;;;;;N;;;;;
+153B;CANADIAN SYLLABICS YWAA;Lo;0;L;;;;;N;;;;;
+153C;CANADIAN SYLLABICS WEST-CREE YWAA;Lo;0;L;;;;;N;;;;;
+153D;CANADIAN SYLLABICS NASKAPI YWAA;Lo;0;L;;;;;N;;;;;
+153E;CANADIAN SYLLABICS Y;Lo;0;L;;;;;N;;;;;
+153F;CANADIAN SYLLABICS BIBLE-CREE Y;Lo;0;L;;;;;N;;;;;
+1540;CANADIAN SYLLABICS WEST-CREE Y;Lo;0;L;;;;;N;;;;;
+1541;CANADIAN SYLLABICS SAYISI YI;Lo;0;L;;;;;N;;;;;
+1542;CANADIAN SYLLABICS RE;Lo;0;L;;;;;N;;;;;
+1543;CANADIAN SYLLABICS R-CREE RE;Lo;0;L;;;;;N;;;;;
+1544;CANADIAN SYLLABICS WEST-CREE LE;Lo;0;L;;;;;N;;;;;
+1545;CANADIAN SYLLABICS RAAI;Lo;0;L;;;;;N;;;;;
+1546;CANADIAN SYLLABICS RI;Lo;0;L;;;;;N;;;;;
+1547;CANADIAN SYLLABICS RII;Lo;0;L;;;;;N;;;;;
+1548;CANADIAN SYLLABICS RO;Lo;0;L;;;;;N;;;;;
+1549;CANADIAN SYLLABICS ROO;Lo;0;L;;;;;N;;;;;
+154A;CANADIAN SYLLABICS WEST-CREE LO;Lo;0;L;;;;;N;;;;;
+154B;CANADIAN SYLLABICS RA;Lo;0;L;;;;;N;;;;;
+154C;CANADIAN SYLLABICS RAA;Lo;0;L;;;;;N;;;;;
+154D;CANADIAN SYLLABICS WEST-CREE LA;Lo;0;L;;;;;N;;;;;
+154E;CANADIAN SYLLABICS RWAA;Lo;0;L;;;;;N;;;;;
+154F;CANADIAN SYLLABICS WEST-CREE RWAA;Lo;0;L;;;;;N;;;;;
+1550;CANADIAN SYLLABICS R;Lo;0;L;;;;;N;;;;;
+1551;CANADIAN SYLLABICS WEST-CREE R;Lo;0;L;;;;;N;;;;;
+1552;CANADIAN SYLLABICS MEDIAL R;Lo;0;L;;;;;N;;;;;
+1553;CANADIAN SYLLABICS FE;Lo;0;L;;;;;N;;;;;
+1554;CANADIAN SYLLABICS FAAI;Lo;0;L;;;;;N;;;;;
+1555;CANADIAN SYLLABICS FI;Lo;0;L;;;;;N;;;;;
+1556;CANADIAN SYLLABICS FII;Lo;0;L;;;;;N;;;;;
+1557;CANADIAN SYLLABICS FO;Lo;0;L;;;;;N;;;;;
+1558;CANADIAN SYLLABICS FOO;Lo;0;L;;;;;N;;;;;
+1559;CANADIAN SYLLABICS FA;Lo;0;L;;;;;N;;;;;
+155A;CANADIAN SYLLABICS FAA;Lo;0;L;;;;;N;;;;;
+155B;CANADIAN SYLLABICS FWAA;Lo;0;L;;;;;N;;;;;
+155C;CANADIAN SYLLABICS WEST-CREE FWAA;Lo;0;L;;;;;N;;;;;
+155D;CANADIAN SYLLABICS F;Lo;0;L;;;;;N;;;;;
+155E;CANADIAN SYLLABICS THE;Lo;0;L;;;;;N;;;;;
+155F;CANADIAN SYLLABICS N-CREE THE;Lo;0;L;;;;;N;;;;;
+1560;CANADIAN SYLLABICS THI;Lo;0;L;;;;;N;;;;;
+1561;CANADIAN SYLLABICS N-CREE THI;Lo;0;L;;;;;N;;;;;
+1562;CANADIAN SYLLABICS THII;Lo;0;L;;;;;N;;;;;
+1563;CANADIAN SYLLABICS N-CREE THII;Lo;0;L;;;;;N;;;;;
+1564;CANADIAN SYLLABICS THO;Lo;0;L;;;;;N;;;;;
+1565;CANADIAN SYLLABICS THOO;Lo;0;L;;;;;N;;;;;
+1566;CANADIAN SYLLABICS THA;Lo;0;L;;;;;N;;;;;
+1567;CANADIAN SYLLABICS THAA;Lo;0;L;;;;;N;;;;;
+1568;CANADIAN SYLLABICS THWAA;Lo;0;L;;;;;N;;;;;
+1569;CANADIAN SYLLABICS WEST-CREE THWAA;Lo;0;L;;;;;N;;;;;
+156A;CANADIAN SYLLABICS TH;Lo;0;L;;;;;N;;;;;
+156B;CANADIAN SYLLABICS TTHE;Lo;0;L;;;;;N;;;;;
+156C;CANADIAN SYLLABICS TTHI;Lo;0;L;;;;;N;;;;;
+156D;CANADIAN SYLLABICS TTHO;Lo;0;L;;;;;N;;;;;
+156E;CANADIAN SYLLABICS TTHA;Lo;0;L;;;;;N;;;;;
+156F;CANADIAN SYLLABICS TTH;Lo;0;L;;;;;N;;;;;
+1570;CANADIAN SYLLABICS TYE;Lo;0;L;;;;;N;;;;;
+1571;CANADIAN SYLLABICS TYI;Lo;0;L;;;;;N;;;;;
+1572;CANADIAN SYLLABICS TYO;Lo;0;L;;;;;N;;;;;
+1573;CANADIAN SYLLABICS TYA;Lo;0;L;;;;;N;;;;;
+1574;CANADIAN SYLLABICS NUNAVIK HE;Lo;0;L;;;;;N;;;;;
+1575;CANADIAN SYLLABICS NUNAVIK HI;Lo;0;L;;;;;N;;;;;
+1576;CANADIAN SYLLABICS NUNAVIK HII;Lo;0;L;;;;;N;;;;;
+1577;CANADIAN SYLLABICS NUNAVIK HO;Lo;0;L;;;;;N;;;;;
+1578;CANADIAN SYLLABICS NUNAVIK HOO;Lo;0;L;;;;;N;;;;;
+1579;CANADIAN SYLLABICS NUNAVIK HA;Lo;0;L;;;;;N;;;;;
+157A;CANADIAN SYLLABICS NUNAVIK HAA;Lo;0;L;;;;;N;;;;;
+157B;CANADIAN SYLLABICS NUNAVIK H;Lo;0;L;;;;;N;;;;;
+157C;CANADIAN SYLLABICS NUNAVUT H;Lo;0;L;;;;;N;;;;;
+157D;CANADIAN SYLLABICS HK;Lo;0;L;;;;;N;;;;;
+157E;CANADIAN SYLLABICS QAAI;Lo;0;L;;;;;N;;;;;
+157F;CANADIAN SYLLABICS QI;Lo;0;L;;;;;N;;;;;
+1580;CANADIAN SYLLABICS QII;Lo;0;L;;;;;N;;;;;
+1581;CANADIAN SYLLABICS QO;Lo;0;L;;;;;N;;;;;
+1582;CANADIAN SYLLABICS QOO;Lo;0;L;;;;;N;;;;;
+1583;CANADIAN SYLLABICS QA;Lo;0;L;;;;;N;;;;;
+1584;CANADIAN SYLLABICS QAA;Lo;0;L;;;;;N;;;;;
+1585;CANADIAN SYLLABICS Q;Lo;0;L;;;;;N;;;;;
+1586;CANADIAN SYLLABICS TLHE;Lo;0;L;;;;;N;;;;;
+1587;CANADIAN SYLLABICS TLHI;Lo;0;L;;;;;N;;;;;
+1588;CANADIAN SYLLABICS TLHO;Lo;0;L;;;;;N;;;;;
+1589;CANADIAN SYLLABICS TLHA;Lo;0;L;;;;;N;;;;;
+158A;CANADIAN SYLLABICS WEST-CREE RE;Lo;0;L;;;;;N;;;;;
+158B;CANADIAN SYLLABICS WEST-CREE RI;Lo;0;L;;;;;N;;;;;
+158C;CANADIAN SYLLABICS WEST-CREE RO;Lo;0;L;;;;;N;;;;;
+158D;CANADIAN SYLLABICS WEST-CREE RA;Lo;0;L;;;;;N;;;;;
+158E;CANADIAN SYLLABICS NGAAI;Lo;0;L;;;;;N;;;;;
+158F;CANADIAN SYLLABICS NGI;Lo;0;L;;;;;N;;;;;
+1590;CANADIAN SYLLABICS NGII;Lo;0;L;;;;;N;;;;;
+1591;CANADIAN SYLLABICS NGO;Lo;0;L;;;;;N;;;;;
+1592;CANADIAN SYLLABICS NGOO;Lo;0;L;;;;;N;;;;;
+1593;CANADIAN SYLLABICS NGA;Lo;0;L;;;;;N;;;;;
+1594;CANADIAN SYLLABICS NGAA;Lo;0;L;;;;;N;;;;;
+1595;CANADIAN SYLLABICS NG;Lo;0;L;;;;;N;;;;;
+1596;CANADIAN SYLLABICS NNG;Lo;0;L;;;;;N;;;;;
+1597;CANADIAN SYLLABICS SAYISI SHE;Lo;0;L;;;;;N;;;;;
+1598;CANADIAN SYLLABICS SAYISI SHI;Lo;0;L;;;;;N;;;;;
+1599;CANADIAN SYLLABICS SAYISI SHO;Lo;0;L;;;;;N;;;;;
+159A;CANADIAN SYLLABICS SAYISI SHA;Lo;0;L;;;;;N;;;;;
+159B;CANADIAN SYLLABICS WOODS-CREE THE;Lo;0;L;;;;;N;;;;;
+159C;CANADIAN SYLLABICS WOODS-CREE THI;Lo;0;L;;;;;N;;;;;
+159D;CANADIAN SYLLABICS WOODS-CREE THO;Lo;0;L;;;;;N;;;;;
+159E;CANADIAN SYLLABICS WOODS-CREE THA;Lo;0;L;;;;;N;;;;;
+159F;CANADIAN SYLLABICS WOODS-CREE TH;Lo;0;L;;;;;N;;;;;
+15A0;CANADIAN SYLLABICS LHI;Lo;0;L;;;;;N;;;;;
+15A1;CANADIAN SYLLABICS LHII;Lo;0;L;;;;;N;;;;;
+15A2;CANADIAN SYLLABICS LHO;Lo;0;L;;;;;N;;;;;
+15A3;CANADIAN SYLLABICS LHOO;Lo;0;L;;;;;N;;;;;
+15A4;CANADIAN SYLLABICS LHA;Lo;0;L;;;;;N;;;;;
+15A5;CANADIAN SYLLABICS LHAA;Lo;0;L;;;;;N;;;;;
+15A6;CANADIAN SYLLABICS LH;Lo;0;L;;;;;N;;;;;
+15A7;CANADIAN SYLLABICS TH-CREE THE;Lo;0;L;;;;;N;;;;;
+15A8;CANADIAN SYLLABICS TH-CREE THI;Lo;0;L;;;;;N;;;;;
+15A9;CANADIAN SYLLABICS TH-CREE THII;Lo;0;L;;;;;N;;;;;
+15AA;CANADIAN SYLLABICS TH-CREE THO;Lo;0;L;;;;;N;;;;;
+15AB;CANADIAN SYLLABICS TH-CREE THOO;Lo;0;L;;;;;N;;;;;
+15AC;CANADIAN SYLLABICS TH-CREE THA;Lo;0;L;;;;;N;;;;;
+15AD;CANADIAN SYLLABICS TH-CREE THAA;Lo;0;L;;;;;N;;;;;
+15AE;CANADIAN SYLLABICS TH-CREE TH;Lo;0;L;;;;;N;;;;;
+15AF;CANADIAN SYLLABICS AIVILIK B;Lo;0;L;;;;;N;;;;;
+15B0;CANADIAN SYLLABICS BLACKFOOT E;Lo;0;L;;;;;N;;;;;
+15B1;CANADIAN SYLLABICS BLACKFOOT I;Lo;0;L;;;;;N;;;;;
+15B2;CANADIAN SYLLABICS BLACKFOOT O;Lo;0;L;;;;;N;;;;;
+15B3;CANADIAN SYLLABICS BLACKFOOT A;Lo;0;L;;;;;N;;;;;
+15B4;CANADIAN SYLLABICS BLACKFOOT WE;Lo;0;L;;;;;N;;;;;
+15B5;CANADIAN SYLLABICS BLACKFOOT WI;Lo;0;L;;;;;N;;;;;
+15B6;CANADIAN SYLLABICS BLACKFOOT WO;Lo;0;L;;;;;N;;;;;
+15B7;CANADIAN SYLLABICS BLACKFOOT WA;Lo;0;L;;;;;N;;;;;
+15B8;CANADIAN SYLLABICS BLACKFOOT NE;Lo;0;L;;;;;N;;;;;
+15B9;CANADIAN SYLLABICS BLACKFOOT NI;Lo;0;L;;;;;N;;;;;
+15BA;CANADIAN SYLLABICS BLACKFOOT NO;Lo;0;L;;;;;N;;;;;
+15BB;CANADIAN SYLLABICS BLACKFOOT NA;Lo;0;L;;;;;N;;;;;
+15BC;CANADIAN SYLLABICS BLACKFOOT KE;Lo;0;L;;;;;N;;;;;
+15BD;CANADIAN SYLLABICS BLACKFOOT KI;Lo;0;L;;;;;N;;;;;
+15BE;CANADIAN SYLLABICS BLACKFOOT KO;Lo;0;L;;;;;N;;;;;
+15BF;CANADIAN SYLLABICS BLACKFOOT KA;Lo;0;L;;;;;N;;;;;
+15C0;CANADIAN SYLLABICS SAYISI HE;Lo;0;L;;;;;N;;;;;
+15C1;CANADIAN SYLLABICS SAYISI HI;Lo;0;L;;;;;N;;;;;
+15C2;CANADIAN SYLLABICS SAYISI HO;Lo;0;L;;;;;N;;;;;
+15C3;CANADIAN SYLLABICS SAYISI HA;Lo;0;L;;;;;N;;;;;
+15C4;CANADIAN SYLLABICS CARRIER GHU;Lo;0;L;;;;;N;;;;;
+15C5;CANADIAN SYLLABICS CARRIER GHO;Lo;0;L;;;;;N;;;;;
+15C6;CANADIAN SYLLABICS CARRIER GHE;Lo;0;L;;;;;N;;;;;
+15C7;CANADIAN SYLLABICS CARRIER GHEE;Lo;0;L;;;;;N;;;;;
+15C8;CANADIAN SYLLABICS CARRIER GHI;Lo;0;L;;;;;N;;;;;
+15C9;CANADIAN SYLLABICS CARRIER GHA;Lo;0;L;;;;;N;;;;;
+15CA;CANADIAN SYLLABICS CARRIER RU;Lo;0;L;;;;;N;;;;;
+15CB;CANADIAN SYLLABICS CARRIER RO;Lo;0;L;;;;;N;;;;;
+15CC;CANADIAN SYLLABICS CARRIER RE;Lo;0;L;;;;;N;;;;;
+15CD;CANADIAN SYLLABICS CARRIER REE;Lo;0;L;;;;;N;;;;;
+15CE;CANADIAN SYLLABICS CARRIER RI;Lo;0;L;;;;;N;;;;;
+15CF;CANADIAN SYLLABICS CARRIER RA;Lo;0;L;;;;;N;;;;;
+15D0;CANADIAN SYLLABICS CARRIER WU;Lo;0;L;;;;;N;;;;;
+15D1;CANADIAN SYLLABICS CARRIER WO;Lo;0;L;;;;;N;;;;;
+15D2;CANADIAN SYLLABICS CARRIER WE;Lo;0;L;;;;;N;;;;;
+15D3;CANADIAN SYLLABICS CARRIER WEE;Lo;0;L;;;;;N;;;;;
+15D4;CANADIAN SYLLABICS CARRIER WI;Lo;0;L;;;;;N;;;;;
+15D5;CANADIAN SYLLABICS CARRIER WA;Lo;0;L;;;;;N;;;;;
+15D6;CANADIAN SYLLABICS CARRIER HWU;Lo;0;L;;;;;N;;;;;
+15D7;CANADIAN SYLLABICS CARRIER HWO;Lo;0;L;;;;;N;;;;;
+15D8;CANADIAN SYLLABICS CARRIER HWE;Lo;0;L;;;;;N;;;;;
+15D9;CANADIAN SYLLABICS CARRIER HWEE;Lo;0;L;;;;;N;;;;;
+15DA;CANADIAN SYLLABICS CARRIER HWI;Lo;0;L;;;;;N;;;;;
+15DB;CANADIAN SYLLABICS CARRIER HWA;Lo;0;L;;;;;N;;;;;
+15DC;CANADIAN SYLLABICS CARRIER THU;Lo;0;L;;;;;N;;;;;
+15DD;CANADIAN SYLLABICS CARRIER THO;Lo;0;L;;;;;N;;;;;
+15DE;CANADIAN SYLLABICS CARRIER THE;Lo;0;L;;;;;N;;;;;
+15DF;CANADIAN SYLLABICS CARRIER THEE;Lo;0;L;;;;;N;;;;;
+15E0;CANADIAN SYLLABICS CARRIER THI;Lo;0;L;;;;;N;;;;;
+15E1;CANADIAN SYLLABICS CARRIER THA;Lo;0;L;;;;;N;;;;;
+15E2;CANADIAN SYLLABICS CARRIER TTU;Lo;0;L;;;;;N;;;;;
+15E3;CANADIAN SYLLABICS CARRIER TTO;Lo;0;L;;;;;N;;;;;
+15E4;CANADIAN SYLLABICS CARRIER TTE;Lo;0;L;;;;;N;;;;;
+15E5;CANADIAN SYLLABICS CARRIER TTEE;Lo;0;L;;;;;N;;;;;
+15E6;CANADIAN SYLLABICS CARRIER TTI;Lo;0;L;;;;;N;;;;;
+15E7;CANADIAN SYLLABICS CARRIER TTA;Lo;0;L;;;;;N;;;;;
+15E8;CANADIAN SYLLABICS CARRIER PU;Lo;0;L;;;;;N;;;;;
+15E9;CANADIAN SYLLABICS CARRIER PO;Lo;0;L;;;;;N;;;;;
+15EA;CANADIAN SYLLABICS CARRIER PE;Lo;0;L;;;;;N;;;;;
+15EB;CANADIAN SYLLABICS CARRIER PEE;Lo;0;L;;;;;N;;;;;
+15EC;CANADIAN SYLLABICS CARRIER PI;Lo;0;L;;;;;N;;;;;
+15ED;CANADIAN SYLLABICS CARRIER PA;Lo;0;L;;;;;N;;;;;
+15EE;CANADIAN SYLLABICS CARRIER P;Lo;0;L;;;;;N;;;;;
+15EF;CANADIAN SYLLABICS CARRIER GU;Lo;0;L;;;;;N;;;;;
+15F0;CANADIAN SYLLABICS CARRIER GO;Lo;0;L;;;;;N;;;;;
+15F1;CANADIAN SYLLABICS CARRIER GE;Lo;0;L;;;;;N;;;;;
+15F2;CANADIAN SYLLABICS CARRIER GEE;Lo;0;L;;;;;N;;;;;
+15F3;CANADIAN SYLLABICS CARRIER GI;Lo;0;L;;;;;N;;;;;
+15F4;CANADIAN SYLLABICS CARRIER GA;Lo;0;L;;;;;N;;;;;
+15F5;CANADIAN SYLLABICS CARRIER KHU;Lo;0;L;;;;;N;;;;;
+15F6;CANADIAN SYLLABICS CARRIER KHO;Lo;0;L;;;;;N;;;;;
+15F7;CANADIAN SYLLABICS CARRIER KHE;Lo;0;L;;;;;N;;;;;
+15F8;CANADIAN SYLLABICS CARRIER KHEE;Lo;0;L;;;;;N;;;;;
+15F9;CANADIAN SYLLABICS CARRIER KHI;Lo;0;L;;;;;N;;;;;
+15FA;CANADIAN SYLLABICS CARRIER KHA;Lo;0;L;;;;;N;;;;;
+15FB;CANADIAN SYLLABICS CARRIER KKU;Lo;0;L;;;;;N;;;;;
+15FC;CANADIAN SYLLABICS CARRIER KKO;Lo;0;L;;;;;N;;;;;
+15FD;CANADIAN SYLLABICS CARRIER KKE;Lo;0;L;;;;;N;;;;;
+15FE;CANADIAN SYLLABICS CARRIER KKEE;Lo;0;L;;;;;N;;;;;
+15FF;CANADIAN SYLLABICS CARRIER KKI;Lo;0;L;;;;;N;;;;;
+1600;CANADIAN SYLLABICS CARRIER KKA;Lo;0;L;;;;;N;;;;;
+1601;CANADIAN SYLLABICS CARRIER KK;Lo;0;L;;;;;N;;;;;
+1602;CANADIAN SYLLABICS CARRIER NU;Lo;0;L;;;;;N;;;;;
+1603;CANADIAN SYLLABICS CARRIER NO;Lo;0;L;;;;;N;;;;;
+1604;CANADIAN SYLLABICS CARRIER NE;Lo;0;L;;;;;N;;;;;
+1605;CANADIAN SYLLABICS CARRIER NEE;Lo;0;L;;;;;N;;;;;
+1606;CANADIAN SYLLABICS CARRIER NI;Lo;0;L;;;;;N;;;;;
+1607;CANADIAN SYLLABICS CARRIER NA;Lo;0;L;;;;;N;;;;;
+1608;CANADIAN SYLLABICS CARRIER MU;Lo;0;L;;;;;N;;;;;
+1609;CANADIAN SYLLABICS CARRIER MO;Lo;0;L;;;;;N;;;;;
+160A;CANADIAN SYLLABICS CARRIER ME;Lo;0;L;;;;;N;;;;;
+160B;CANADIAN SYLLABICS CARRIER MEE;Lo;0;L;;;;;N;;;;;
+160C;CANADIAN SYLLABICS CARRIER MI;Lo;0;L;;;;;N;;;;;
+160D;CANADIAN SYLLABICS CARRIER MA;Lo;0;L;;;;;N;;;;;
+160E;CANADIAN SYLLABICS CARRIER YU;Lo;0;L;;;;;N;;;;;
+160F;CANADIAN SYLLABICS CARRIER YO;Lo;0;L;;;;;N;;;;;
+1610;CANADIAN SYLLABICS CARRIER YE;Lo;0;L;;;;;N;;;;;
+1611;CANADIAN SYLLABICS CARRIER YEE;Lo;0;L;;;;;N;;;;;
+1612;CANADIAN SYLLABICS CARRIER YI;Lo;0;L;;;;;N;;;;;
+1613;CANADIAN SYLLABICS CARRIER YA;Lo;0;L;;;;;N;;;;;
+1614;CANADIAN SYLLABICS CARRIER JU;Lo;0;L;;;;;N;;;;;
+1615;CANADIAN SYLLABICS SAYISI JU;Lo;0;L;;;;;N;;;;;
+1616;CANADIAN SYLLABICS CARRIER JO;Lo;0;L;;;;;N;;;;;
+1617;CANADIAN SYLLABICS CARRIER JE;Lo;0;L;;;;;N;;;;;
+1618;CANADIAN SYLLABICS CARRIER JEE;Lo;0;L;;;;;N;;;;;
+1619;CANADIAN SYLLABICS CARRIER JI;Lo;0;L;;;;;N;;;;;
+161A;CANADIAN SYLLABICS SAYISI JI;Lo;0;L;;;;;N;;;;;
+161B;CANADIAN SYLLABICS CARRIER JA;Lo;0;L;;;;;N;;;;;
+161C;CANADIAN SYLLABICS CARRIER JJU;Lo;0;L;;;;;N;;;;;
+161D;CANADIAN SYLLABICS CARRIER JJO;Lo;0;L;;;;;N;;;;;
+161E;CANADIAN SYLLABICS CARRIER JJE;Lo;0;L;;;;;N;;;;;
+161F;CANADIAN SYLLABICS CARRIER JJEE;Lo;0;L;;;;;N;;;;;
+1620;CANADIAN SYLLABICS CARRIER JJI;Lo;0;L;;;;;N;;;;;
+1621;CANADIAN SYLLABICS CARRIER JJA;Lo;0;L;;;;;N;;;;;
+1622;CANADIAN SYLLABICS CARRIER LU;Lo;0;L;;;;;N;;;;;
+1623;CANADIAN SYLLABICS CARRIER LO;Lo;0;L;;;;;N;;;;;
+1624;CANADIAN SYLLABICS CARRIER LE;Lo;0;L;;;;;N;;;;;
+1625;CANADIAN SYLLABICS CARRIER LEE;Lo;0;L;;;;;N;;;;;
+1626;CANADIAN SYLLABICS CARRIER LI;Lo;0;L;;;;;N;;;;;
+1627;CANADIAN SYLLABICS CARRIER LA;Lo;0;L;;;;;N;;;;;
+1628;CANADIAN SYLLABICS CARRIER DLU;Lo;0;L;;;;;N;;;;;
+1629;CANADIAN SYLLABICS CARRIER DLO;Lo;0;L;;;;;N;;;;;
+162A;CANADIAN SYLLABICS CARRIER DLE;Lo;0;L;;;;;N;;;;;
+162B;CANADIAN SYLLABICS CARRIER DLEE;Lo;0;L;;;;;N;;;;;
+162C;CANADIAN SYLLABICS CARRIER DLI;Lo;0;L;;;;;N;;;;;
+162D;CANADIAN SYLLABICS CARRIER DLA;Lo;0;L;;;;;N;;;;;
+162E;CANADIAN SYLLABICS CARRIER LHU;Lo;0;L;;;;;N;;;;;
+162F;CANADIAN SYLLABICS CARRIER LHO;Lo;0;L;;;;;N;;;;;
+1630;CANADIAN SYLLABICS CARRIER LHE;Lo;0;L;;;;;N;;;;;
+1631;CANADIAN SYLLABICS CARRIER LHEE;Lo;0;L;;;;;N;;;;;
+1632;CANADIAN SYLLABICS CARRIER LHI;Lo;0;L;;;;;N;;;;;
+1633;CANADIAN SYLLABICS CARRIER LHA;Lo;0;L;;;;;N;;;;;
+1634;CANADIAN SYLLABICS CARRIER TLHU;Lo;0;L;;;;;N;;;;;
+1635;CANADIAN SYLLABICS CARRIER TLHO;Lo;0;L;;;;;N;;;;;
+1636;CANADIAN SYLLABICS CARRIER TLHE;Lo;0;L;;;;;N;;;;;
+1637;CANADIAN SYLLABICS CARRIER TLHEE;Lo;0;L;;;;;N;;;;;
+1638;CANADIAN SYLLABICS CARRIER TLHI;Lo;0;L;;;;;N;;;;;
+1639;CANADIAN SYLLABICS CARRIER TLHA;Lo;0;L;;;;;N;;;;;
+163A;CANADIAN SYLLABICS CARRIER TLU;Lo;0;L;;;;;N;;;;;
+163B;CANADIAN SYLLABICS CARRIER TLO;Lo;0;L;;;;;N;;;;;
+163C;CANADIAN SYLLABICS CARRIER TLE;Lo;0;L;;;;;N;;;;;
+163D;CANADIAN SYLLABICS CARRIER TLEE;Lo;0;L;;;;;N;;;;;
+163E;CANADIAN SYLLABICS CARRIER TLI;Lo;0;L;;;;;N;;;;;
+163F;CANADIAN SYLLABICS CARRIER TLA;Lo;0;L;;;;;N;;;;;
+1640;CANADIAN SYLLABICS CARRIER ZU;Lo;0;L;;;;;N;;;;;
+1641;CANADIAN SYLLABICS CARRIER ZO;Lo;0;L;;;;;N;;;;;
+1642;CANADIAN SYLLABICS CARRIER ZE;Lo;0;L;;;;;N;;;;;
+1643;CANADIAN SYLLABICS CARRIER ZEE;Lo;0;L;;;;;N;;;;;
+1644;CANADIAN SYLLABICS CARRIER ZI;Lo;0;L;;;;;N;;;;;
+1645;CANADIAN SYLLABICS CARRIER ZA;Lo;0;L;;;;;N;;;;;
+1646;CANADIAN SYLLABICS CARRIER Z;Lo;0;L;;;;;N;;;;;
+1647;CANADIAN SYLLABICS CARRIER INITIAL Z;Lo;0;L;;;;;N;;;;;
+1648;CANADIAN SYLLABICS CARRIER DZU;Lo;0;L;;;;;N;;;;;
+1649;CANADIAN SYLLABICS CARRIER DZO;Lo;0;L;;;;;N;;;;;
+164A;CANADIAN SYLLABICS CARRIER DZE;Lo;0;L;;;;;N;;;;;
+164B;CANADIAN SYLLABICS CARRIER DZEE;Lo;0;L;;;;;N;;;;;
+164C;CANADIAN SYLLABICS CARRIER DZI;Lo;0;L;;;;;N;;;;;
+164D;CANADIAN SYLLABICS CARRIER DZA;Lo;0;L;;;;;N;;;;;
+164E;CANADIAN SYLLABICS CARRIER SU;Lo;0;L;;;;;N;;;;;
+164F;CANADIAN SYLLABICS CARRIER SO;Lo;0;L;;;;;N;;;;;
+1650;CANADIAN SYLLABICS CARRIER SE;Lo;0;L;;;;;N;;;;;
+1651;CANADIAN SYLLABICS CARRIER SEE;Lo;0;L;;;;;N;;;;;
+1652;CANADIAN SYLLABICS CARRIER SI;Lo;0;L;;;;;N;;;;;
+1653;CANADIAN SYLLABICS CARRIER SA;Lo;0;L;;;;;N;;;;;
+1654;CANADIAN SYLLABICS CARRIER SHU;Lo;0;L;;;;;N;;;;;
+1655;CANADIAN SYLLABICS CARRIER SHO;Lo;0;L;;;;;N;;;;;
+1656;CANADIAN SYLLABICS CARRIER SHE;Lo;0;L;;;;;N;;;;;
+1657;CANADIAN SYLLABICS CARRIER SHEE;Lo;0;L;;;;;N;;;;;
+1658;CANADIAN SYLLABICS CARRIER SHI;Lo;0;L;;;;;N;;;;;
+1659;CANADIAN SYLLABICS CARRIER SHA;Lo;0;L;;;;;N;;;;;
+165A;CANADIAN SYLLABICS CARRIER SH;Lo;0;L;;;;;N;;;;;
+165B;CANADIAN SYLLABICS CARRIER TSU;Lo;0;L;;;;;N;;;;;
+165C;CANADIAN SYLLABICS CARRIER TSO;Lo;0;L;;;;;N;;;;;
+165D;CANADIAN SYLLABICS CARRIER TSE;Lo;0;L;;;;;N;;;;;
+165E;CANADIAN SYLLABICS CARRIER TSEE;Lo;0;L;;;;;N;;;;;
+165F;CANADIAN SYLLABICS CARRIER TSI;Lo;0;L;;;;;N;;;;;
+1660;CANADIAN SYLLABICS CARRIER TSA;Lo;0;L;;;;;N;;;;;
+1661;CANADIAN SYLLABICS CARRIER CHU;Lo;0;L;;;;;N;;;;;
+1662;CANADIAN SYLLABICS CARRIER CHO;Lo;0;L;;;;;N;;;;;
+1663;CANADIAN SYLLABICS CARRIER CHE;Lo;0;L;;;;;N;;;;;
+1664;CANADIAN SYLLABICS CARRIER CHEE;Lo;0;L;;;;;N;;;;;
+1665;CANADIAN SYLLABICS CARRIER CHI;Lo;0;L;;;;;N;;;;;
+1666;CANADIAN SYLLABICS CARRIER CHA;Lo;0;L;;;;;N;;;;;
+1667;CANADIAN SYLLABICS CARRIER TTSU;Lo;0;L;;;;;N;;;;;
+1668;CANADIAN SYLLABICS CARRIER TTSO;Lo;0;L;;;;;N;;;;;
+1669;CANADIAN SYLLABICS CARRIER TTSE;Lo;0;L;;;;;N;;;;;
+166A;CANADIAN SYLLABICS CARRIER TTSEE;Lo;0;L;;;;;N;;;;;
+166B;CANADIAN SYLLABICS CARRIER TTSI;Lo;0;L;;;;;N;;;;;
+166C;CANADIAN SYLLABICS CARRIER TTSA;Lo;0;L;;;;;N;;;;;
+166D;CANADIAN SYLLABICS CHI SIGN;Po;0;L;;;;;N;;;;;
+166E;CANADIAN SYLLABICS FULL STOP;Po;0;L;;;;;N;;;;;
+166F;CANADIAN SYLLABICS QAI;Lo;0;L;;;;;N;;;;;
+1670;CANADIAN SYLLABICS NGAI;Lo;0;L;;;;;N;;;;;
+1671;CANADIAN SYLLABICS NNGI;Lo;0;L;;;;;N;;;;;
+1672;CANADIAN SYLLABICS NNGII;Lo;0;L;;;;;N;;;;;
+1673;CANADIAN SYLLABICS NNGO;Lo;0;L;;;;;N;;;;;
+1674;CANADIAN SYLLABICS NNGOO;Lo;0;L;;;;;N;;;;;
+1675;CANADIAN SYLLABICS NNGA;Lo;0;L;;;;;N;;;;;
+1676;CANADIAN SYLLABICS NNGAA;Lo;0;L;;;;;N;;;;;
+1680;OGHAM SPACE MARK;Zs;0;WS;;;;;N;;;;;
+1681;OGHAM LETTER BEITH;Lo;0;L;;;;;N;;;;;
+1682;OGHAM LETTER LUIS;Lo;0;L;;;;;N;;;;;
+1683;OGHAM LETTER FEARN;Lo;0;L;;;;;N;;;;;
+1684;OGHAM LETTER SAIL;Lo;0;L;;;;;N;;;;;
+1685;OGHAM LETTER NION;Lo;0;L;;;;;N;;;;;
+1686;OGHAM LETTER UATH;Lo;0;L;;;;;N;;;;;
+1687;OGHAM LETTER DAIR;Lo;0;L;;;;;N;;;;;
+1688;OGHAM LETTER TINNE;Lo;0;L;;;;;N;;;;;
+1689;OGHAM LETTER COLL;Lo;0;L;;;;;N;;;;;
+168A;OGHAM LETTER CEIRT;Lo;0;L;;;;;N;;;;;
+168B;OGHAM LETTER MUIN;Lo;0;L;;;;;N;;;;;
+168C;OGHAM LETTER GORT;Lo;0;L;;;;;N;;;;;
+168D;OGHAM LETTER NGEADAL;Lo;0;L;;;;;N;;;;;
+168E;OGHAM LETTER STRAIF;Lo;0;L;;;;;N;;;;;
+168F;OGHAM LETTER RUIS;Lo;0;L;;;;;N;;;;;
+1690;OGHAM LETTER AILM;Lo;0;L;;;;;N;;;;;
+1691;OGHAM LETTER ONN;Lo;0;L;;;;;N;;;;;
+1692;OGHAM LETTER UR;Lo;0;L;;;;;N;;;;;
+1693;OGHAM LETTER EADHADH;Lo;0;L;;;;;N;;;;;
+1694;OGHAM LETTER IODHADH;Lo;0;L;;;;;N;;;;;
+1695;OGHAM LETTER EABHADH;Lo;0;L;;;;;N;;;;;
+1696;OGHAM LETTER OR;Lo;0;L;;;;;N;;;;;
+1697;OGHAM LETTER UILLEANN;Lo;0;L;;;;;N;;;;;
+1698;OGHAM LETTER IFIN;Lo;0;L;;;;;N;;;;;
+1699;OGHAM LETTER EAMHANCHOLL;Lo;0;L;;;;;N;;;;;
+169A;OGHAM LETTER PEITH;Lo;0;L;;;;;N;;;;;
+169B;OGHAM FEATHER MARK;Ps;0;ON;;;;;N;;;;;
+169C;OGHAM REVERSED FEATHER MARK;Pe;0;ON;;;;;N;;;;;
+16A0;RUNIC LETTER FEHU FEOH FE F;Lo;0;L;;;;;N;;;;;
+16A1;RUNIC LETTER V;Lo;0;L;;;;;N;;;;;
+16A2;RUNIC LETTER URUZ UR U;Lo;0;L;;;;;N;;;;;
+16A3;RUNIC LETTER YR;Lo;0;L;;;;;N;;;;;
+16A4;RUNIC LETTER Y;Lo;0;L;;;;;N;;;;;
+16A5;RUNIC LETTER W;Lo;0;L;;;;;N;;;;;
+16A6;RUNIC LETTER THURISAZ THURS THORN;Lo;0;L;;;;;N;;;;;
+16A7;RUNIC LETTER ETH;Lo;0;L;;;;;N;;;;;
+16A8;RUNIC LETTER ANSUZ A;Lo;0;L;;;;;N;;;;;
+16A9;RUNIC LETTER OS O;Lo;0;L;;;;;N;;;;;
+16AA;RUNIC LETTER AC A;Lo;0;L;;;;;N;;;;;
+16AB;RUNIC LETTER AESC;Lo;0;L;;;;;N;;;;;
+16AC;RUNIC LETTER LONG-BRANCH-OSS O;Lo;0;L;;;;;N;;;;;
+16AD;RUNIC LETTER SHORT-TWIG-OSS O;Lo;0;L;;;;;N;;;;;
+16AE;RUNIC LETTER O;Lo;0;L;;;;;N;;;;;
+16AF;RUNIC LETTER OE;Lo;0;L;;;;;N;;;;;
+16B0;RUNIC LETTER ON;Lo;0;L;;;;;N;;;;;
+16B1;RUNIC LETTER RAIDO RAD REID R;Lo;0;L;;;;;N;;;;;
+16B2;RUNIC LETTER KAUNA;Lo;0;L;;;;;N;;;;;
+16B3;RUNIC LETTER CEN;Lo;0;L;;;;;N;;;;;
+16B4;RUNIC LETTER KAUN K;Lo;0;L;;;;;N;;;;;
+16B5;RUNIC LETTER G;Lo;0;L;;;;;N;;;;;
+16B6;RUNIC LETTER ENG;Lo;0;L;;;;;N;;;;;
+16B7;RUNIC LETTER GEBO GYFU G;Lo;0;L;;;;;N;;;;;
+16B8;RUNIC LETTER GAR;Lo;0;L;;;;;N;;;;;
+16B9;RUNIC LETTER WUNJO WYNN W;Lo;0;L;;;;;N;;;;;
+16BA;RUNIC LETTER HAGLAZ H;Lo;0;L;;;;;N;;;;;
+16BB;RUNIC LETTER HAEGL H;Lo;0;L;;;;;N;;;;;
+16BC;RUNIC LETTER LONG-BRANCH-HAGALL H;Lo;0;L;;;;;N;;;;;
+16BD;RUNIC LETTER SHORT-TWIG-HAGALL H;Lo;0;L;;;;;N;;;;;
+16BE;RUNIC LETTER NAUDIZ NYD NAUD N;Lo;0;L;;;;;N;;;;;
+16BF;RUNIC LETTER SHORT-TWIG-NAUD N;Lo;0;L;;;;;N;;;;;
+16C0;RUNIC LETTER DOTTED-N;Lo;0;L;;;;;N;;;;;
+16C1;RUNIC LETTER ISAZ IS ISS I;Lo;0;L;;;;;N;;;;;
+16C2;RUNIC LETTER E;Lo;0;L;;;;;N;;;;;
+16C3;RUNIC LETTER JERAN J;Lo;0;L;;;;;N;;;;;
+16C4;RUNIC LETTER GER;Lo;0;L;;;;;N;;;;;
+16C5;RUNIC LETTER LONG-BRANCH-AR AE;Lo;0;L;;;;;N;;;;;
+16C6;RUNIC LETTER SHORT-TWIG-AR A;Lo;0;L;;;;;N;;;;;
+16C7;RUNIC LETTER IWAZ EOH;Lo;0;L;;;;;N;;;;;
+16C8;RUNIC LETTER PERTHO PEORTH P;Lo;0;L;;;;;N;;;;;
+16C9;RUNIC LETTER ALGIZ EOLHX;Lo;0;L;;;;;N;;;;;
+16CA;RUNIC LETTER SOWILO S;Lo;0;L;;;;;N;;;;;
+16CB;RUNIC LETTER SIGEL LONG-BRANCH-SOL S;Lo;0;L;;;;;N;;;;;
+16CC;RUNIC LETTER SHORT-TWIG-SOL S;Lo;0;L;;;;;N;;;;;
+16CD;RUNIC LETTER C;Lo;0;L;;;;;N;;;;;
+16CE;RUNIC LETTER Z;Lo;0;L;;;;;N;;;;;
+16CF;RUNIC LETTER TIWAZ TIR TYR T;Lo;0;L;;;;;N;;;;;
+16D0;RUNIC LETTER SHORT-TWIG-TYR T;Lo;0;L;;;;;N;;;;;
+16D1;RUNIC LETTER D;Lo;0;L;;;;;N;;;;;
+16D2;RUNIC LETTER BERKANAN BEORC BJARKAN B;Lo;0;L;;;;;N;;;;;
+16D3;RUNIC LETTER SHORT-TWIG-BJARKAN B;Lo;0;L;;;;;N;;;;;
+16D4;RUNIC LETTER DOTTED-P;Lo;0;L;;;;;N;;;;;
+16D5;RUNIC LETTER OPEN-P;Lo;0;L;;;;;N;;;;;
+16D6;RUNIC LETTER EHWAZ EH E;Lo;0;L;;;;;N;;;;;
+16D7;RUNIC LETTER MANNAZ MAN M;Lo;0;L;;;;;N;;;;;
+16D8;RUNIC LETTER LONG-BRANCH-MADR M;Lo;0;L;;;;;N;;;;;
+16D9;RUNIC LETTER SHORT-TWIG-MADR M;Lo;0;L;;;;;N;;;;;
+16DA;RUNIC LETTER LAUKAZ LAGU LOGR L;Lo;0;L;;;;;N;;;;;
+16DB;RUNIC LETTER DOTTED-L;Lo;0;L;;;;;N;;;;;
+16DC;RUNIC LETTER INGWAZ;Lo;0;L;;;;;N;;;;;
+16DD;RUNIC LETTER ING;Lo;0;L;;;;;N;;;;;
+16DE;RUNIC LETTER DAGAZ DAEG D;Lo;0;L;;;;;N;;;;;
+16DF;RUNIC LETTER OTHALAN ETHEL O;Lo;0;L;;;;;N;;;;;
+16E0;RUNIC LETTER EAR;Lo;0;L;;;;;N;;;;;
+16E1;RUNIC LETTER IOR;Lo;0;L;;;;;N;;;;;
+16E2;RUNIC LETTER CWEORTH;Lo;0;L;;;;;N;;;;;
+16E3;RUNIC LETTER CALC;Lo;0;L;;;;;N;;;;;
+16E4;RUNIC LETTER CEALC;Lo;0;L;;;;;N;;;;;
+16E5;RUNIC LETTER STAN;Lo;0;L;;;;;N;;;;;
+16E6;RUNIC LETTER LONG-BRANCH-YR;Lo;0;L;;;;;N;;;;;
+16E7;RUNIC LETTER SHORT-TWIG-YR;Lo;0;L;;;;;N;;;;;
+16E8;RUNIC LETTER ICELANDIC-YR;Lo;0;L;;;;;N;;;;;
+16E9;RUNIC LETTER Q;Lo;0;L;;;;;N;;;;;
+16EA;RUNIC LETTER X;Lo;0;L;;;;;N;;;;;
+16EB;RUNIC SINGLE PUNCTUATION;Po;0;L;;;;;N;;;;;
+16EC;RUNIC MULTIPLE PUNCTUATION;Po;0;L;;;;;N;;;;;
+16ED;RUNIC CROSS PUNCTUATION;Po;0;L;;;;;N;;;;;
+16EE;RUNIC ARLAUG SYMBOL;Nl;0;L;;;;17;N;;golden number 17;;;
+16EF;RUNIC TVIMADUR SYMBOL;Nl;0;L;;;;18;N;;golden number 18;;;
+16F0;RUNIC BELGTHOR SYMBOL;Nl;0;L;;;;19;N;;golden number 19;;;
+1780;KHMER LETTER KA;Lo;0;L;;;;;N;;;;;
+1781;KHMER LETTER KHA;Lo;0;L;;;;;N;;;;;
+1782;KHMER LETTER KO;Lo;0;L;;;;;N;;;;;
+1783;KHMER LETTER KHO;Lo;0;L;;;;;N;;;;;
+1784;KHMER LETTER NGO;Lo;0;L;;;;;N;;;;;
+1785;KHMER LETTER CA;Lo;0;L;;;;;N;;;;;
+1786;KHMER LETTER CHA;Lo;0;L;;;;;N;;;;;
+1787;KHMER LETTER CO;Lo;0;L;;;;;N;;;;;
+1788;KHMER LETTER CHO;Lo;0;L;;;;;N;;;;;
+1789;KHMER LETTER NYO;Lo;0;L;;;;;N;;;;;
+178A;KHMER LETTER DA;Lo;0;L;;;;;N;;;;;
+178B;KHMER LETTER TTHA;Lo;0;L;;;;;N;;;;;
+178C;KHMER LETTER DO;Lo;0;L;;;;;N;;;;;
+178D;KHMER LETTER TTHO;Lo;0;L;;;;;N;;;;;
+178E;KHMER LETTER NNO;Lo;0;L;;;;;N;;;;;
+178F;KHMER LETTER TA;Lo;0;L;;;;;N;;;;;
+1790;KHMER LETTER THA;Lo;0;L;;;;;N;;;;;
+1791;KHMER LETTER TO;Lo;0;L;;;;;N;;;;;
+1792;KHMER LETTER THO;Lo;0;L;;;;;N;;;;;
+1793;KHMER LETTER NO;Lo;0;L;;;;;N;;;;;
+1794;KHMER LETTER BA;Lo;0;L;;;;;N;;;;;
+1795;KHMER LETTER PHA;Lo;0;L;;;;;N;;;;;
+1796;KHMER LETTER PO;Lo;0;L;;;;;N;;;;;
+1797;KHMER LETTER PHO;Lo;0;L;;;;;N;;;;;
+1798;KHMER LETTER MO;Lo;0;L;;;;;N;;;;;
+1799;KHMER LETTER YO;Lo;0;L;;;;;N;;;;;
+179A;KHMER LETTER RO;Lo;0;L;;;;;N;;;;;
+179B;KHMER LETTER LO;Lo;0;L;;;;;N;;;;;
+179C;KHMER LETTER VO;Lo;0;L;;;;;N;;;;;
+179D;KHMER LETTER SHA;Lo;0;L;;;;;N;;;;;
+179E;KHMER LETTER SSO;Lo;0;L;;;;;N;;;;;
+179F;KHMER LETTER SA;Lo;0;L;;;;;N;;;;;
+17A0;KHMER LETTER HA;Lo;0;L;;;;;N;;;;;
+17A1;KHMER LETTER LA;Lo;0;L;;;;;N;;;;;
+17A2;KHMER LETTER QA;Lo;0;L;;;;;N;;;;;
+17A3;KHMER INDEPENDENT VOWEL QAQ;Lo;0;L;;;;;N;;;;;
+17A4;KHMER INDEPENDENT VOWEL QAA;Lo;0;L;;;;;N;;;;;
+17A5;KHMER INDEPENDENT VOWEL QI;Lo;0;L;;;;;N;;;;;
+17A6;KHMER INDEPENDENT VOWEL QII;Lo;0;L;;;;;N;;;;;
+17A7;KHMER INDEPENDENT VOWEL QU;Lo;0;L;;;;;N;;;;;
+17A8;KHMER INDEPENDENT VOWEL QUK;Lo;0;L;;;;;N;;;;;
+17A9;KHMER INDEPENDENT VOWEL QUU;Lo;0;L;;;;;N;;;;;
+17AA;KHMER INDEPENDENT VOWEL QUUV;Lo;0;L;;;;;N;;;;;
+17AB;KHMER INDEPENDENT VOWEL RY;Lo;0;L;;;;;N;;;;;
+17AC;KHMER INDEPENDENT VOWEL RYY;Lo;0;L;;;;;N;;;;;
+17AD;KHMER INDEPENDENT VOWEL LY;Lo;0;L;;;;;N;;;;;
+17AE;KHMER INDEPENDENT VOWEL LYY;Lo;0;L;;;;;N;;;;;
+17AF;KHMER INDEPENDENT VOWEL QE;Lo;0;L;;;;;N;;;;;
+17B0;KHMER INDEPENDENT VOWEL QAI;Lo;0;L;;;;;N;;;;;
+17B1;KHMER INDEPENDENT VOWEL QOO TYPE ONE;Lo;0;L;;;;;N;;;;;
+17B2;KHMER INDEPENDENT VOWEL QOO TYPE TWO;Lo;0;L;;;;;N;;;;;
+17B3;KHMER INDEPENDENT VOWEL QAU;Lo;0;L;;;;;N;;;;;
+17B4;KHMER VOWEL INHERENT AQ;Mc;0;L;;;;;N;;;;;
+17B5;KHMER VOWEL INHERENT AA;Mc;0;L;;;;;N;;;;;
+17B6;KHMER VOWEL SIGN AA;Mc;0;L;;;;;N;;;;;
+17B7;KHMER VOWEL SIGN I;Mn;0;NSM;;;;;N;;;;;
+17B8;KHMER VOWEL SIGN II;Mn;0;NSM;;;;;N;;;;;
+17B9;KHMER VOWEL SIGN Y;Mn;0;NSM;;;;;N;;;;;
+17BA;KHMER VOWEL SIGN YY;Mn;0;NSM;;;;;N;;;;;
+17BB;KHMER VOWEL SIGN U;Mn;0;NSM;;;;;N;;;;;
+17BC;KHMER VOWEL SIGN UU;Mn;0;NSM;;;;;N;;;;;
+17BD;KHMER VOWEL SIGN UA;Mn;0;NSM;;;;;N;;;;;
+17BE;KHMER VOWEL SIGN OE;Mc;0;L;;;;;N;;;;;
+17BF;KHMER VOWEL SIGN YA;Mc;0;L;;;;;N;;;;;
+17C0;KHMER VOWEL SIGN IE;Mc;0;L;;;;;N;;;;;
+17C1;KHMER VOWEL SIGN E;Mc;0;L;;;;;N;;;;;
+17C2;KHMER VOWEL SIGN AE;Mc;0;L;;;;;N;;;;;
+17C3;KHMER VOWEL SIGN AI;Mc;0;L;;;;;N;;;;;
+17C4;KHMER VOWEL SIGN OO;Mc;0;L;;;;;N;;;;;
+17C5;KHMER VOWEL SIGN AU;Mc;0;L;;;;;N;;;;;
+17C6;KHMER SIGN NIKAHIT;Mn;0;NSM;;;;;N;;;;;
+17C7;KHMER SIGN REAHMUK;Mc;0;L;;;;;N;;;;;
+17C8;KHMER SIGN YUUKALEAPINTU;Mc;0;L;;;;;N;;;;;
+17C9;KHMER SIGN MUUSIKATOAN;Mn;0;NSM;;;;;N;;;;;
+17CA;KHMER SIGN TRIISAP;Mn;0;NSM;;;;;N;;;;;
+17CB;KHMER SIGN BANTOC;Mn;0;NSM;;;;;N;;;;;
+17CC;KHMER SIGN ROBAT;Mn;0;NSM;;;;;N;;;;;
+17CD;KHMER SIGN TOANDAKHIAT;Mn;0;NSM;;;;;N;;;;;
+17CE;KHMER SIGN KAKABAT;Mn;0;NSM;;;;;N;;;;;
+17CF;KHMER SIGN AHSDA;Mn;0;NSM;;;;;N;;;;;
+17D0;KHMER SIGN SAMYOK SANNYA;Mn;0;NSM;;;;;N;;;;;
+17D1;KHMER SIGN VIRIAM;Mn;0;NSM;;;;;N;;;;;
+17D2;KHMER SIGN COENG;Mn;9;NSM;;;;;N;;;;;
+17D3;KHMER SIGN BATHAMASAT;Mn;0;NSM;;;;;N;;;;;
+17D4;KHMER SIGN KHAN;Po;0;L;;;;;N;;;;;
+17D5;KHMER SIGN BARIYOOSAN;Po;0;L;;;;;N;;;;;
+17D6;KHMER SIGN CAMNUC PII KUUH;Po;0;L;;;;;N;;;;;
+17D7;KHMER SIGN LEK TOO;Po;0;L;;;;;N;;;;;
+17D8;KHMER SIGN BEYYAL;Po;0;L;;;;;N;;;;;
+17D9;KHMER SIGN PHNAEK MUAN;Po;0;L;;;;;N;;;;;
+17DA;KHMER SIGN KOOMUUT;Po;0;L;;;;;N;;;;;
+17DB;KHMER CURRENCY SYMBOL RIEL;Sc;0;ET;;;;;N;;;;;
+17DC;KHMER SIGN AVAKRAHASANYA;Po;0;L;;;;;N;;;;;
+17E0;KHMER DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+17E1;KHMER DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+17E2;KHMER DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+17E3;KHMER DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+17E4;KHMER DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+17E5;KHMER DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+17E6;KHMER DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+17E7;KHMER DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+17E8;KHMER DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+17E9;KHMER DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+1800;MONGOLIAN BIRGA;Po;0;ON;;;;;N;;;;;
+1801;MONGOLIAN ELLIPSIS;Po;0;ON;;;;;N;;;;;
+1802;MONGOLIAN COMMA;Po;0;ON;;;;;N;;;;;
+1803;MONGOLIAN FULL STOP;Po;0;ON;;;;;N;;;;;
+1804;MONGOLIAN COLON;Po;0;ON;;;;;N;;;;;
+1805;MONGOLIAN FOUR DOTS;Po;0;ON;;;;;N;;;;;
+1806;MONGOLIAN TODO SOFT HYPHEN;Pd;0;ON;;;;;N;;;;;
+1807;MONGOLIAN SIBE SYLLABLE BOUNDARY MARKER;Po;0;ON;;;;;N;;;;;
+1808;MONGOLIAN MANCHU COMMA;Po;0;ON;;;;;N;;;;;
+1809;MONGOLIAN MANCHU FULL STOP;Po;0;ON;;;;;N;;;;;
+180A;MONGOLIAN NIRUGU;Po;0;ON;;;;;N;;;;;
+180B;MONGOLIAN FREE VARIATION SELECTOR ONE;Cf;0;BN;;;;;N;;;;;
+180C;MONGOLIAN FREE VARIATION SELECTOR TWO;Cf;0;BN;;;;;N;;;;;
+180D;MONGOLIAN FREE VARIATION SELECTOR THREE;Cf;0;BN;;;;;N;;;;;
+180E;MONGOLIAN VOWEL SEPARATOR;Cf;0;BN;;;;;N;;;;;
+1810;MONGOLIAN DIGIT ZERO;Nd;0;L;;0;0;0;N;;;;;
+1811;MONGOLIAN DIGIT ONE;Nd;0;L;;1;1;1;N;;;;;
+1812;MONGOLIAN DIGIT TWO;Nd;0;L;;2;2;2;N;;;;;
+1813;MONGOLIAN DIGIT THREE;Nd;0;L;;3;3;3;N;;;;;
+1814;MONGOLIAN DIGIT FOUR;Nd;0;L;;4;4;4;N;;;;;
+1815;MONGOLIAN DIGIT FIVE;Nd;0;L;;5;5;5;N;;;;;
+1816;MONGOLIAN DIGIT SIX;Nd;0;L;;6;6;6;N;;;;;
+1817;MONGOLIAN DIGIT SEVEN;Nd;0;L;;7;7;7;N;;;;;
+1818;MONGOLIAN DIGIT EIGHT;Nd;0;L;;8;8;8;N;;;;;
+1819;MONGOLIAN DIGIT NINE;Nd;0;L;;9;9;9;N;;;;;
+1820;MONGOLIAN LETTER A;Lo;0;L;;;;;N;;;;;
+1821;MONGOLIAN LETTER E;Lo;0;L;;;;;N;;;;;
+1822;MONGOLIAN LETTER I;Lo;0;L;;;;;N;;;;;
+1823;MONGOLIAN LETTER O;Lo;0;L;;;;;N;;;;;
+1824;MONGOLIAN LETTER U;Lo;0;L;;;;;N;;;;;
+1825;MONGOLIAN LETTER OE;Lo;0;L;;;;;N;;;;;
+1826;MONGOLIAN LETTER UE;Lo;0;L;;;;;N;;;;;
+1827;MONGOLIAN LETTER EE;Lo;0;L;;;;;N;;;;;
+1828;MONGOLIAN LETTER NA;Lo;0;L;;;;;N;;;;;
+1829;MONGOLIAN LETTER ANG;Lo;0;L;;;;;N;;;;;
+182A;MONGOLIAN LETTER BA;Lo;0;L;;;;;N;;;;;
+182B;MONGOLIAN LETTER PA;Lo;0;L;;;;;N;;;;;
+182C;MONGOLIAN LETTER QA;Lo;0;L;;;;;N;;;;;
+182D;MONGOLIAN LETTER GA;Lo;0;L;;;;;N;;;;;
+182E;MONGOLIAN LETTER MA;Lo;0;L;;;;;N;;;;;
+182F;MONGOLIAN LETTER LA;Lo;0;L;;;;;N;;;;;
+1830;MONGOLIAN LETTER SA;Lo;0;L;;;;;N;;;;;
+1831;MONGOLIAN LETTER SHA;Lo;0;L;;;;;N;;;;;
+1832;MONGOLIAN LETTER TA;Lo;0;L;;;;;N;;;;;
+1833;MONGOLIAN LETTER DA;Lo;0;L;;;;;N;;;;;
+1834;MONGOLIAN LETTER CHA;Lo;0;L;;;;;N;;;;;
+1835;MONGOLIAN LETTER JA;Lo;0;L;;;;;N;;;;;
+1836;MONGOLIAN LETTER YA;Lo;0;L;;;;;N;;;;;
+1837;MONGOLIAN LETTER RA;Lo;0;L;;;;;N;;;;;
+1838;MONGOLIAN LETTER WA;Lo;0;L;;;;;N;;;;;
+1839;MONGOLIAN LETTER FA;Lo;0;L;;;;;N;;;;;
+183A;MONGOLIAN LETTER KA;Lo;0;L;;;;;N;;;;;
+183B;MONGOLIAN LETTER KHA;Lo;0;L;;;;;N;;;;;
+183C;MONGOLIAN LETTER TSA;Lo;0;L;;;;;N;;;;;
+183D;MONGOLIAN LETTER ZA;Lo;0;L;;;;;N;;;;;
+183E;MONGOLIAN LETTER HAA;Lo;0;L;;;;;N;;;;;
+183F;MONGOLIAN LETTER ZRA;Lo;0;L;;;;;N;;;;;
+1840;MONGOLIAN LETTER LHA;Lo;0;L;;;;;N;;;;;
+1841;MONGOLIAN LETTER ZHI;Lo;0;L;;;;;N;;;;;
+1842;MONGOLIAN LETTER CHI;Lo;0;L;;;;;N;;;;;
+1843;MONGOLIAN LETTER TODO LONG VOWEL SIGN;Lm;0;L;;;;;N;;;;;
+1844;MONGOLIAN LETTER TODO E;Lo;0;L;;;;;N;;;;;
+1845;MONGOLIAN LETTER TODO I;Lo;0;L;;;;;N;;;;;
+1846;MONGOLIAN LETTER TODO O;Lo;0;L;;;;;N;;;;;
+1847;MONGOLIAN LETTER TODO U;Lo;0;L;;;;;N;;;;;
+1848;MONGOLIAN LETTER TODO OE;Lo;0;L;;;;;N;;;;;
+1849;MONGOLIAN LETTER TODO UE;Lo;0;L;;;;;N;;;;;
+184A;MONGOLIAN LETTER TODO ANG;Lo;0;L;;;;;N;;;;;
+184B;MONGOLIAN LETTER TODO BA;Lo;0;L;;;;;N;;;;;
+184C;MONGOLIAN LETTER TODO PA;Lo;0;L;;;;;N;;;;;
+184D;MONGOLIAN LETTER TODO QA;Lo;0;L;;;;;N;;;;;
+184E;MONGOLIAN LETTER TODO GA;Lo;0;L;;;;;N;;;;;
+184F;MONGOLIAN LETTER TODO MA;Lo;0;L;;;;;N;;;;;
+1850;MONGOLIAN LETTER TODO TA;Lo;0;L;;;;;N;;;;;
+1851;MONGOLIAN LETTER TODO DA;Lo;0;L;;;;;N;;;;;
+1852;MONGOLIAN LETTER TODO CHA;Lo;0;L;;;;;N;;;;;
+1853;MONGOLIAN LETTER TODO JA;Lo;0;L;;;;;N;;;;;
+1854;MONGOLIAN LETTER TODO TSA;Lo;0;L;;;;;N;;;;;
+1855;MONGOLIAN LETTER TODO YA;Lo;0;L;;;;;N;;;;;
+1856;MONGOLIAN LETTER TODO WA;Lo;0;L;;;;;N;;;;;
+1857;MONGOLIAN LETTER TODO KA;Lo;0;L;;;;;N;;;;;
+1858;MONGOLIAN LETTER TODO GAA;Lo;0;L;;;;;N;;;;;
+1859;MONGOLIAN LETTER TODO HAA;Lo;0;L;;;;;N;;;;;
+185A;MONGOLIAN LETTER TODO JIA;Lo;0;L;;;;;N;;;;;
+185B;MONGOLIAN LETTER TODO NIA;Lo;0;L;;;;;N;;;;;
+185C;MONGOLIAN LETTER TODO DZA;Lo;0;L;;;;;N;;;;;
+185D;MONGOLIAN LETTER SIBE E;Lo;0;L;;;;;N;;;;;
+185E;MONGOLIAN LETTER SIBE I;Lo;0;L;;;;;N;;;;;
+185F;MONGOLIAN LETTER SIBE IY;Lo;0;L;;;;;N;;;;;
+1860;MONGOLIAN LETTER SIBE UE;Lo;0;L;;;;;N;;;;;
+1861;MONGOLIAN LETTER SIBE U;Lo;0;L;;;;;N;;;;;
+1862;MONGOLIAN LETTER SIBE ANG;Lo;0;L;;;;;N;;;;;
+1863;MONGOLIAN LETTER SIBE KA;Lo;0;L;;;;;N;;;;;
+1864;MONGOLIAN LETTER SIBE GA;Lo;0;L;;;;;N;;;;;
+1865;MONGOLIAN LETTER SIBE HA;Lo;0;L;;;;;N;;;;;
+1866;MONGOLIAN LETTER SIBE PA;Lo;0;L;;;;;N;;;;;
+1867;MONGOLIAN LETTER SIBE SHA;Lo;0;L;;;;;N;;;;;
+1868;MONGOLIAN LETTER SIBE TA;Lo;0;L;;;;;N;;;;;
+1869;MONGOLIAN LETTER SIBE DA;Lo;0;L;;;;;N;;;;;
+186A;MONGOLIAN LETTER SIBE JA;Lo;0;L;;;;;N;;;;;
+186B;MONGOLIAN LETTER SIBE FA;Lo;0;L;;;;;N;;;;;
+186C;MONGOLIAN LETTER SIBE GAA;Lo;0;L;;;;;N;;;;;
+186D;MONGOLIAN LETTER SIBE HAA;Lo;0;L;;;;;N;;;;;
+186E;MONGOLIAN LETTER SIBE TSA;Lo;0;L;;;;;N;;;;;
+186F;MONGOLIAN LETTER SIBE ZA;Lo;0;L;;;;;N;;;;;
+1870;MONGOLIAN LETTER SIBE RAA;Lo;0;L;;;;;N;;;;;
+1871;MONGOLIAN LETTER SIBE CHA;Lo;0;L;;;;;N;;;;;
+1872;MONGOLIAN LETTER SIBE ZHA;Lo;0;L;;;;;N;;;;;
+1873;MONGOLIAN LETTER MANCHU I;Lo;0;L;;;;;N;;;;;
+1874;MONGOLIAN LETTER MANCHU KA;Lo;0;L;;;;;N;;;;;
+1875;MONGOLIAN LETTER MANCHU RA;Lo;0;L;;;;;N;;;;;
+1876;MONGOLIAN LETTER MANCHU FA;Lo;0;L;;;;;N;;;;;
+1877;MONGOLIAN LETTER MANCHU ZHA;Lo;0;L;;;;;N;;;;;
+1880;MONGOLIAN LETTER ALI GALI ANUSVARA ONE;Lo;0;L;;;;;N;;;;;
+1881;MONGOLIAN LETTER ALI GALI VISARGA ONE;Lo;0;L;;;;;N;;;;;
+1882;MONGOLIAN LETTER ALI GALI DAMARU;Lo;0;L;;;;;N;;;;;
+1883;MONGOLIAN LETTER ALI GALI UBADAMA;Lo;0;L;;;;;N;;;;;
+1884;MONGOLIAN LETTER ALI GALI INVERTED UBADAMA;Lo;0;L;;;;;N;;;;;
+1885;MONGOLIAN LETTER ALI GALI BALUDA;Lo;0;L;;;;;N;;;;;
+1886;MONGOLIAN LETTER ALI GALI THREE BALUDA;Lo;0;L;;;;;N;;;;;
+1887;MONGOLIAN LETTER ALI GALI A;Lo;0;L;;;;;N;;;;;
+1888;MONGOLIAN LETTER ALI GALI I;Lo;0;L;;;;;N;;;;;
+1889;MONGOLIAN LETTER ALI GALI KA;Lo;0;L;;;;;N;;;;;
+188A;MONGOLIAN LETTER ALI GALI NGA;Lo;0;L;;;;;N;;;;;
+188B;MONGOLIAN LETTER ALI GALI CA;Lo;0;L;;;;;N;;;;;
+188C;MONGOLIAN LETTER ALI GALI TTA;Lo;0;L;;;;;N;;;;;
+188D;MONGOLIAN LETTER ALI GALI TTHA;Lo;0;L;;;;;N;;;;;
+188E;MONGOLIAN LETTER ALI GALI DDA;Lo;0;L;;;;;N;;;;;
+188F;MONGOLIAN LETTER ALI GALI NNA;Lo;0;L;;;;;N;;;;;
+1890;MONGOLIAN LETTER ALI GALI TA;Lo;0;L;;;;;N;;;;;
+1891;MONGOLIAN LETTER ALI GALI DA;Lo;0;L;;;;;N;;;;;
+1892;MONGOLIAN LETTER ALI GALI PA;Lo;0;L;;;;;N;;;;;
+1893;MONGOLIAN LETTER ALI GALI PHA;Lo;0;L;;;;;N;;;;;
+1894;MONGOLIAN LETTER ALI GALI SSA;Lo;0;L;;;;;N;;;;;
+1895;MONGOLIAN LETTER ALI GALI ZHA;Lo;0;L;;;;;N;;;;;
+1896;MONGOLIAN LETTER ALI GALI ZA;Lo;0;L;;;;;N;;;;;
+1897;MONGOLIAN LETTER ALI GALI AH;Lo;0;L;;;;;N;;;;;
+1898;MONGOLIAN LETTER TODO ALI GALI TA;Lo;0;L;;;;;N;;;;;
+1899;MONGOLIAN LETTER TODO ALI GALI ZHA;Lo;0;L;;;;;N;;;;;
+189A;MONGOLIAN LETTER MANCHU ALI GALI GHA;Lo;0;L;;;;;N;;;;;
+189B;MONGOLIAN LETTER MANCHU ALI GALI NGA;Lo;0;L;;;;;N;;;;;
+189C;MONGOLIAN LETTER MANCHU ALI GALI CA;Lo;0;L;;;;;N;;;;;
+189D;MONGOLIAN LETTER MANCHU ALI GALI JHA;Lo;0;L;;;;;N;;;;;
+189E;MONGOLIAN LETTER MANCHU ALI GALI TTA;Lo;0;L;;;;;N;;;;;
+189F;MONGOLIAN LETTER MANCHU ALI GALI DDHA;Lo;0;L;;;;;N;;;;;
+18A0;MONGOLIAN LETTER MANCHU ALI GALI TA;Lo;0;L;;;;;N;;;;;
+18A1;MONGOLIAN LETTER MANCHU ALI GALI DHA;Lo;0;L;;;;;N;;;;;
+18A2;MONGOLIAN LETTER MANCHU ALI GALI SSA;Lo;0;L;;;;;N;;;;;
+18A3;MONGOLIAN LETTER MANCHU ALI GALI CYA;Lo;0;L;;;;;N;;;;;
+18A4;MONGOLIAN LETTER MANCHU ALI GALI ZHA;Lo;0;L;;;;;N;;;;;
+18A5;MONGOLIAN LETTER MANCHU ALI GALI ZA;Lo;0;L;;;;;N;;;;;
+18A6;MONGOLIAN LETTER ALI GALI HALF U;Lo;0;L;;;;;N;;;;;
+18A7;MONGOLIAN LETTER ALI GALI HALF YA;Lo;0;L;;;;;N;;;;;
+18A8;MONGOLIAN LETTER MANCHU ALI GALI BHA;Lo;0;L;;;;;N;;;;;
+18A9;MONGOLIAN LETTER ALI GALI DAGALGA;Mn;228;NSM;;;;;N;;;;;
+1E00;LATIN CAPITAL LETTER A WITH RING BELOW;Lu;0;L;0041 0325;;;;N;;;;1E01;
+1E01;LATIN SMALL LETTER A WITH RING BELOW;Ll;0;L;0061 0325;;;;N;;;1E00;;1E00
+1E02;LATIN CAPITAL LETTER B WITH DOT ABOVE;Lu;0;L;0042 0307;;;;N;;;;1E03;
+1E03;LATIN SMALL LETTER B WITH DOT ABOVE;Ll;0;L;0062 0307;;;;N;;;1E02;;1E02
+1E04;LATIN CAPITAL LETTER B WITH DOT BELOW;Lu;0;L;0042 0323;;;;N;;;;1E05;
+1E05;LATIN SMALL LETTER B WITH DOT BELOW;Ll;0;L;0062 0323;;;;N;;;1E04;;1E04
+1E06;LATIN CAPITAL LETTER B WITH LINE BELOW;Lu;0;L;0042 0331;;;;N;;;;1E07;
+1E07;LATIN SMALL LETTER B WITH LINE BELOW;Ll;0;L;0062 0331;;;;N;;;1E06;;1E06
+1E08;LATIN CAPITAL LETTER C WITH CEDILLA AND ACUTE;Lu;0;L;00C7 0301;;;;N;;;;1E09;
+1E09;LATIN SMALL LETTER C WITH CEDILLA AND ACUTE;Ll;0;L;00E7 0301;;;;N;;;1E08;;1E08
+1E0A;LATIN CAPITAL LETTER D WITH DOT ABOVE;Lu;0;L;0044 0307;;;;N;;;;1E0B;
+1E0B;LATIN SMALL LETTER D WITH DOT ABOVE;Ll;0;L;0064 0307;;;;N;;;1E0A;;1E0A
+1E0C;LATIN CAPITAL LETTER D WITH DOT BELOW;Lu;0;L;0044 0323;;;;N;;;;1E0D;
+1E0D;LATIN SMALL LETTER D WITH DOT BELOW;Ll;0;L;0064 0323;;;;N;;;1E0C;;1E0C
+1E0E;LATIN CAPITAL LETTER D WITH LINE BELOW;Lu;0;L;0044 0331;;;;N;;;;1E0F;
+1E0F;LATIN SMALL LETTER D WITH LINE BELOW;Ll;0;L;0064 0331;;;;N;;;1E0E;;1E0E
+1E10;LATIN CAPITAL LETTER D WITH CEDILLA;Lu;0;L;0044 0327;;;;N;;;;1E11;
+1E11;LATIN SMALL LETTER D WITH CEDILLA;Ll;0;L;0064 0327;;;;N;;;1E10;;1E10
+1E12;LATIN CAPITAL LETTER D WITH CIRCUMFLEX BELOW;Lu;0;L;0044 032D;;;;N;;;;1E13;
+1E13;LATIN SMALL LETTER D WITH CIRCUMFLEX BELOW;Ll;0;L;0064 032D;;;;N;;;1E12;;1E12
+1E14;LATIN CAPITAL LETTER E WITH MACRON AND GRAVE;Lu;0;L;0112 0300;;;;N;;;;1E15;
+1E15;LATIN SMALL LETTER E WITH MACRON AND GRAVE;Ll;0;L;0113 0300;;;;N;;;1E14;;1E14
+1E16;LATIN CAPITAL LETTER E WITH MACRON AND ACUTE;Lu;0;L;0112 0301;;;;N;;;;1E17;
+1E17;LATIN SMALL LETTER E WITH MACRON AND ACUTE;Ll;0;L;0113 0301;;;;N;;;1E16;;1E16
+1E18;LATIN CAPITAL LETTER E WITH CIRCUMFLEX BELOW;Lu;0;L;0045 032D;;;;N;;;;1E19;
+1E19;LATIN SMALL LETTER E WITH CIRCUMFLEX BELOW;Ll;0;L;0065 032D;;;;N;;;1E18;;1E18
+1E1A;LATIN CAPITAL LETTER E WITH TILDE BELOW;Lu;0;L;0045 0330;;;;N;;;;1E1B;
+1E1B;LATIN SMALL LETTER E WITH TILDE BELOW;Ll;0;L;0065 0330;;;;N;;;1E1A;;1E1A
+1E1C;LATIN CAPITAL LETTER E WITH CEDILLA AND BREVE;Lu;0;L;0228 0306;;;;N;;;;1E1D;
+1E1D;LATIN SMALL LETTER E WITH CEDILLA AND BREVE;Ll;0;L;0229 0306;;;;N;;;1E1C;;1E1C
+1E1E;LATIN CAPITAL LETTER F WITH DOT ABOVE;Lu;0;L;0046 0307;;;;N;;;;1E1F;
+1E1F;LATIN SMALL LETTER F WITH DOT ABOVE;Ll;0;L;0066 0307;;;;N;;;1E1E;;1E1E
+1E20;LATIN CAPITAL LETTER G WITH MACRON;Lu;0;L;0047 0304;;;;N;;;;1E21;
+1E21;LATIN SMALL LETTER G WITH MACRON;Ll;0;L;0067 0304;;;;N;;;1E20;;1E20
+1E22;LATIN CAPITAL LETTER H WITH DOT ABOVE;Lu;0;L;0048 0307;;;;N;;;;1E23;
+1E23;LATIN SMALL LETTER H WITH DOT ABOVE;Ll;0;L;0068 0307;;;;N;;;1E22;;1E22
+1E24;LATIN CAPITAL LETTER H WITH DOT BELOW;Lu;0;L;0048 0323;;;;N;;;;1E25;
+1E25;LATIN SMALL LETTER H WITH DOT BELOW;Ll;0;L;0068 0323;;;;N;;;1E24;;1E24
+1E26;LATIN CAPITAL LETTER H WITH DIAERESIS;Lu;0;L;0048 0308;;;;N;;;;1E27;
+1E27;LATIN SMALL LETTER H WITH DIAERESIS;Ll;0;L;0068 0308;;;;N;;;1E26;;1E26
+1E28;LATIN CAPITAL LETTER H WITH CEDILLA;Lu;0;L;0048 0327;;;;N;;;;1E29;
+1E29;LATIN SMALL LETTER H WITH CEDILLA;Ll;0;L;0068 0327;;;;N;;;1E28;;1E28
+1E2A;LATIN CAPITAL LETTER H WITH BREVE BELOW;Lu;0;L;0048 032E;;;;N;;;;1E2B;
+1E2B;LATIN SMALL LETTER H WITH BREVE BELOW;Ll;0;L;0068 032E;;;;N;;;1E2A;;1E2A
+1E2C;LATIN CAPITAL LETTER I WITH TILDE BELOW;Lu;0;L;0049 0330;;;;N;;;;1E2D;
+1E2D;LATIN SMALL LETTER I WITH TILDE BELOW;Ll;0;L;0069 0330;;;;N;;;1E2C;;1E2C
+1E2E;LATIN CAPITAL LETTER I WITH DIAERESIS AND ACUTE;Lu;0;L;00CF 0301;;;;N;;;;1E2F;
+1E2F;LATIN SMALL LETTER I WITH DIAERESIS AND ACUTE;Ll;0;L;00EF 0301;;;;N;;;1E2E;;1E2E
+1E30;LATIN CAPITAL LETTER K WITH ACUTE;Lu;0;L;004B 0301;;;;N;;;;1E31;
+1E31;LATIN SMALL LETTER K WITH ACUTE;Ll;0;L;006B 0301;;;;N;;;1E30;;1E30
+1E32;LATIN CAPITAL LETTER K WITH DOT BELOW;Lu;0;L;004B 0323;;;;N;;;;1E33;
+1E33;LATIN SMALL LETTER K WITH DOT BELOW;Ll;0;L;006B 0323;;;;N;;;1E32;;1E32
+1E34;LATIN CAPITAL LETTER K WITH LINE BELOW;Lu;0;L;004B 0331;;;;N;;;;1E35;
+1E35;LATIN SMALL LETTER K WITH LINE BELOW;Ll;0;L;006B 0331;;;;N;;;1E34;;1E34
+1E36;LATIN CAPITAL LETTER L WITH DOT BELOW;Lu;0;L;004C 0323;;;;N;;;;1E37;
+1E37;LATIN SMALL LETTER L WITH DOT BELOW;Ll;0;L;006C 0323;;;;N;;;1E36;;1E36
+1E38;LATIN CAPITAL LETTER L WITH DOT BELOW AND MACRON;Lu;0;L;1E36 0304;;;;N;;;;1E39;
+1E39;LATIN SMALL LETTER L WITH DOT BELOW AND MACRON;Ll;0;L;1E37 0304;;;;N;;;1E38;;1E38
+1E3A;LATIN CAPITAL LETTER L WITH LINE BELOW;Lu;0;L;004C 0331;;;;N;;;;1E3B;
+1E3B;LATIN SMALL LETTER L WITH LINE BELOW;Ll;0;L;006C 0331;;;;N;;;1E3A;;1E3A
+1E3C;LATIN CAPITAL LETTER L WITH CIRCUMFLEX BELOW;Lu;0;L;004C 032D;;;;N;;;;1E3D;
+1E3D;LATIN SMALL LETTER L WITH CIRCUMFLEX BELOW;Ll;0;L;006C 032D;;;;N;;;1E3C;;1E3C
+1E3E;LATIN CAPITAL LETTER M WITH ACUTE;Lu;0;L;004D 0301;;;;N;;;;1E3F;
+1E3F;LATIN SMALL LETTER M WITH ACUTE;Ll;0;L;006D 0301;;;;N;;;1E3E;;1E3E
+1E40;LATIN CAPITAL LETTER M WITH DOT ABOVE;Lu;0;L;004D 0307;;;;N;;;;1E41;
+1E41;LATIN SMALL LETTER M WITH DOT ABOVE;Ll;0;L;006D 0307;;;;N;;;1E40;;1E40
+1E42;LATIN CAPITAL LETTER M WITH DOT BELOW;Lu;0;L;004D 0323;;;;N;;;;1E43;
+1E43;LATIN SMALL LETTER M WITH DOT BELOW;Ll;0;L;006D 0323;;;;N;;;1E42;;1E42
+1E44;LATIN CAPITAL LETTER N WITH DOT ABOVE;Lu;0;L;004E 0307;;;;N;;;;1E45;
+1E45;LATIN SMALL LETTER N WITH DOT ABOVE;Ll;0;L;006E 0307;;;;N;;;1E44;;1E44
+1E46;LATIN CAPITAL LETTER N WITH DOT BELOW;Lu;0;L;004E 0323;;;;N;;;;1E47;
+1E47;LATIN SMALL LETTER N WITH DOT BELOW;Ll;0;L;006E 0323;;;;N;;;1E46;;1E46
+1E48;LATIN CAPITAL LETTER N WITH LINE BELOW;Lu;0;L;004E 0331;;;;N;;;;1E49;
+1E49;LATIN SMALL LETTER N WITH LINE BELOW;Ll;0;L;006E 0331;;;;N;;;1E48;;1E48
+1E4A;LATIN CAPITAL LETTER N WITH CIRCUMFLEX BELOW;Lu;0;L;004E 032D;;;;N;;;;1E4B;
+1E4B;LATIN SMALL LETTER N WITH CIRCUMFLEX BELOW;Ll;0;L;006E 032D;;;;N;;;1E4A;;1E4A
+1E4C;LATIN CAPITAL LETTER O WITH TILDE AND ACUTE;Lu;0;L;00D5 0301;;;;N;;;;1E4D;
+1E4D;LATIN SMALL LETTER O WITH TILDE AND ACUTE;Ll;0;L;00F5 0301;;;;N;;;1E4C;;1E4C
+1E4E;LATIN CAPITAL LETTER O WITH TILDE AND DIAERESIS;Lu;0;L;00D5 0308;;;;N;;;;1E4F;
+1E4F;LATIN SMALL LETTER O WITH TILDE AND DIAERESIS;Ll;0;L;00F5 0308;;;;N;;;1E4E;;1E4E
+1E50;LATIN CAPITAL LETTER O WITH MACRON AND GRAVE;Lu;0;L;014C 0300;;;;N;;;;1E51;
+1E51;LATIN SMALL LETTER O WITH MACRON AND GRAVE;Ll;0;L;014D 0300;;;;N;;;1E50;;1E50
+1E52;LATIN CAPITAL LETTER O WITH MACRON AND ACUTE;Lu;0;L;014C 0301;;;;N;;;;1E53;
+1E53;LATIN SMALL LETTER O WITH MACRON AND ACUTE;Ll;0;L;014D 0301;;;;N;;;1E52;;1E52
+1E54;LATIN CAPITAL LETTER P WITH ACUTE;Lu;0;L;0050 0301;;;;N;;;;1E55;
+1E55;LATIN SMALL LETTER P WITH ACUTE;Ll;0;L;0070 0301;;;;N;;;1E54;;1E54
+1E56;LATIN CAPITAL LETTER P WITH DOT ABOVE;Lu;0;L;0050 0307;;;;N;;;;1E57;
+1E57;LATIN SMALL LETTER P WITH DOT ABOVE;Ll;0;L;0070 0307;;;;N;;;1E56;;1E56
+1E58;LATIN CAPITAL LETTER R WITH DOT ABOVE;Lu;0;L;0052 0307;;;;N;;;;1E59;
+1E59;LATIN SMALL LETTER R WITH DOT ABOVE;Ll;0;L;0072 0307;;;;N;;;1E58;;1E58
+1E5A;LATIN CAPITAL LETTER R WITH DOT BELOW;Lu;0;L;0052 0323;;;;N;;;;1E5B;
+1E5B;LATIN SMALL LETTER R WITH DOT BELOW;Ll;0;L;0072 0323;;;;N;;;1E5A;;1E5A
+1E5C;LATIN CAPITAL LETTER R WITH DOT BELOW AND MACRON;Lu;0;L;1E5A 0304;;;;N;;;;1E5D;
+1E5D;LATIN SMALL LETTER R WITH DOT BELOW AND MACRON;Ll;0;L;1E5B 0304;;;;N;;;1E5C;;1E5C
+1E5E;LATIN CAPITAL LETTER R WITH LINE BELOW;Lu;0;L;0052 0331;;;;N;;;;1E5F;
+1E5F;LATIN SMALL LETTER R WITH LINE BELOW;Ll;0;L;0072 0331;;;;N;;;1E5E;;1E5E
+1E60;LATIN CAPITAL LETTER S WITH DOT ABOVE;Lu;0;L;0053 0307;;;;N;;;;1E61;
+1E61;LATIN SMALL LETTER S WITH DOT ABOVE;Ll;0;L;0073 0307;;;;N;;;1E60;;1E60
+1E62;LATIN CAPITAL LETTER S WITH DOT BELOW;Lu;0;L;0053 0323;;;;N;;;;1E63;
+1E63;LATIN SMALL LETTER S WITH DOT BELOW;Ll;0;L;0073 0323;;;;N;;;1E62;;1E62
+1E64;LATIN CAPITAL LETTER S WITH ACUTE AND DOT ABOVE;Lu;0;L;015A 0307;;;;N;;;;1E65;
+1E65;LATIN SMALL LETTER S WITH ACUTE AND DOT ABOVE;Ll;0;L;015B 0307;;;;N;;;1E64;;1E64
+1E66;LATIN CAPITAL LETTER S WITH CARON AND DOT ABOVE;Lu;0;L;0160 0307;;;;N;;;;1E67;
+1E67;LATIN SMALL LETTER S WITH CARON AND DOT ABOVE;Ll;0;L;0161 0307;;;;N;;;1E66;;1E66
+1E68;LATIN CAPITAL LETTER S WITH DOT BELOW AND DOT ABOVE;Lu;0;L;1E62 0307;;;;N;;;;1E69;
+1E69;LATIN SMALL LETTER S WITH DOT BELOW AND DOT ABOVE;Ll;0;L;1E63 0307;;;;N;;;1E68;;1E68
+1E6A;LATIN CAPITAL LETTER T WITH DOT ABOVE;Lu;0;L;0054 0307;;;;N;;;;1E6B;
+1E6B;LATIN SMALL LETTER T WITH DOT ABOVE;Ll;0;L;0074 0307;;;;N;;;1E6A;;1E6A
+1E6C;LATIN CAPITAL LETTER T WITH DOT BELOW;Lu;0;L;0054 0323;;;;N;;;;1E6D;
+1E6D;LATIN SMALL LETTER T WITH DOT BELOW;Ll;0;L;0074 0323;;;;N;;;1E6C;;1E6C
+1E6E;LATIN CAPITAL LETTER T WITH LINE BELOW;Lu;0;L;0054 0331;;;;N;;;;1E6F;
+1E6F;LATIN SMALL LETTER T WITH LINE BELOW;Ll;0;L;0074 0331;;;;N;;;1E6E;;1E6E
+1E70;LATIN CAPITAL LETTER T WITH CIRCUMFLEX BELOW;Lu;0;L;0054 032D;;;;N;;;;1E71;
+1E71;LATIN SMALL LETTER T WITH CIRCUMFLEX BELOW;Ll;0;L;0074 032D;;;;N;;;1E70;;1E70
+1E72;LATIN CAPITAL LETTER U WITH DIAERESIS BELOW;Lu;0;L;0055 0324;;;;N;;;;1E73;
+1E73;LATIN SMALL LETTER U WITH DIAERESIS BELOW;Ll;0;L;0075 0324;;;;N;;;1E72;;1E72
+1E74;LATIN CAPITAL LETTER U WITH TILDE BELOW;Lu;0;L;0055 0330;;;;N;;;;1E75;
+1E75;LATIN SMALL LETTER U WITH TILDE BELOW;Ll;0;L;0075 0330;;;;N;;;1E74;;1E74
+1E76;LATIN CAPITAL LETTER U WITH CIRCUMFLEX BELOW;Lu;0;L;0055 032D;;;;N;;;;1E77;
+1E77;LATIN SMALL LETTER U WITH CIRCUMFLEX BELOW;Ll;0;L;0075 032D;;;;N;;;1E76;;1E76
+1E78;LATIN CAPITAL LETTER U WITH TILDE AND ACUTE;Lu;0;L;0168 0301;;;;N;;;;1E79;
+1E79;LATIN SMALL LETTER U WITH TILDE AND ACUTE;Ll;0;L;0169 0301;;;;N;;;1E78;;1E78
+1E7A;LATIN CAPITAL LETTER U WITH MACRON AND DIAERESIS;Lu;0;L;016A 0308;;;;N;;;;1E7B;
+1E7B;LATIN SMALL LETTER U WITH MACRON AND DIAERESIS;Ll;0;L;016B 0308;;;;N;;;1E7A;;1E7A
+1E7C;LATIN CAPITAL LETTER V WITH TILDE;Lu;0;L;0056 0303;;;;N;;;;1E7D;
+1E7D;LATIN SMALL LETTER V WITH TILDE;Ll;0;L;0076 0303;;;;N;;;1E7C;;1E7C
+1E7E;LATIN CAPITAL LETTER V WITH DOT BELOW;Lu;0;L;0056 0323;;;;N;;;;1E7F;
+1E7F;LATIN SMALL LETTER V WITH DOT BELOW;Ll;0;L;0076 0323;;;;N;;;1E7E;;1E7E
+1E80;LATIN CAPITAL LETTER W WITH GRAVE;Lu;0;L;0057 0300;;;;N;;;;1E81;
+1E81;LATIN SMALL LETTER W WITH GRAVE;Ll;0;L;0077 0300;;;;N;;;1E80;;1E80
+1E82;LATIN CAPITAL LETTER W WITH ACUTE;Lu;0;L;0057 0301;;;;N;;;;1E83;
+1E83;LATIN SMALL LETTER W WITH ACUTE;Ll;0;L;0077 0301;;;;N;;;1E82;;1E82
+1E84;LATIN CAPITAL LETTER W WITH DIAERESIS;Lu;0;L;0057 0308;;;;N;;;;1E85;
+1E85;LATIN SMALL LETTER W WITH DIAERESIS;Ll;0;L;0077 0308;;;;N;;;1E84;;1E84
+1E86;LATIN CAPITAL LETTER W WITH DOT ABOVE;Lu;0;L;0057 0307;;;;N;;;;1E87;
+1E87;LATIN SMALL LETTER W WITH DOT ABOVE;Ll;0;L;0077 0307;;;;N;;;1E86;;1E86
+1E88;LATIN CAPITAL LETTER W WITH DOT BELOW;Lu;0;L;0057 0323;;;;N;;;;1E89;
+1E89;LATIN SMALL LETTER W WITH DOT BELOW;Ll;0;L;0077 0323;;;;N;;;1E88;;1E88
+1E8A;LATIN CAPITAL LETTER X WITH DOT ABOVE;Lu;0;L;0058 0307;;;;N;;;;1E8B;
+1E8B;LATIN SMALL LETTER X WITH DOT ABOVE;Ll;0;L;0078 0307;;;;N;;;1E8A;;1E8A
+1E8C;LATIN CAPITAL LETTER X WITH DIAERESIS;Lu;0;L;0058 0308;;;;N;;;;1E8D;
+1E8D;LATIN SMALL LETTER X WITH DIAERESIS;Ll;0;L;0078 0308;;;;N;;;1E8C;;1E8C
+1E8E;LATIN CAPITAL LETTER Y WITH DOT ABOVE;Lu;0;L;0059 0307;;;;N;;;;1E8F;
+1E8F;LATIN SMALL LETTER Y WITH DOT ABOVE;Ll;0;L;0079 0307;;;;N;;;1E8E;;1E8E
+1E90;LATIN CAPITAL LETTER Z WITH CIRCUMFLEX;Lu;0;L;005A 0302;;;;N;;;;1E91;
+1E91;LATIN SMALL LETTER Z WITH CIRCUMFLEX;Ll;0;L;007A 0302;;;;N;;;1E90;;1E90
+1E92;LATIN CAPITAL LETTER Z WITH DOT BELOW;Lu;0;L;005A 0323;;;;N;;;;1E93;
+1E93;LATIN SMALL LETTER Z WITH DOT BELOW;Ll;0;L;007A 0323;;;;N;;;1E92;;1E92
+1E94;LATIN CAPITAL LETTER Z WITH LINE BELOW;Lu;0;L;005A 0331;;;;N;;;;1E95;
+1E95;LATIN SMALL LETTER Z WITH LINE BELOW;Ll;0;L;007A 0331;;;;N;;;1E94;;1E94
+1E96;LATIN SMALL LETTER H WITH LINE BELOW;Ll;0;L;0068 0331;;;;N;;;;;
+1E97;LATIN SMALL LETTER T WITH DIAERESIS;Ll;0;L;0074 0308;;;;N;;;;;
+1E98;LATIN SMALL LETTER W WITH RING ABOVE;Ll;0;L;0077 030A;;;;N;;;;;
+1E99;LATIN SMALL LETTER Y WITH RING ABOVE;Ll;0;L;0079 030A;;;;N;;;;;
+1E9A;LATIN SMALL LETTER A WITH RIGHT HALF RING;Ll;0;L;<compat> 0061 02BE;;;;N;;;;;
+1E9B;LATIN SMALL LETTER LONG S WITH DOT ABOVE;Ll;0;L;017F 0307;;;;N;;;1E60;;1E60
+1EA0;LATIN CAPITAL LETTER A WITH DOT BELOW;Lu;0;L;0041 0323;;;;N;;;;1EA1;
+1EA1;LATIN SMALL LETTER A WITH DOT BELOW;Ll;0;L;0061 0323;;;;N;;;1EA0;;1EA0
+1EA2;LATIN CAPITAL LETTER A WITH HOOK ABOVE;Lu;0;L;0041 0309;;;;N;;;;1EA3;
+1EA3;LATIN SMALL LETTER A WITH HOOK ABOVE;Ll;0;L;0061 0309;;;;N;;;1EA2;;1EA2
+1EA4;LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND ACUTE;Lu;0;L;00C2 0301;;;;N;;;;1EA5;
+1EA5;LATIN SMALL LETTER A WITH CIRCUMFLEX AND ACUTE;Ll;0;L;00E2 0301;;;;N;;;1EA4;;1EA4
+1EA6;LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND GRAVE;Lu;0;L;00C2 0300;;;;N;;;;1EA7;
+1EA7;LATIN SMALL LETTER A WITH CIRCUMFLEX AND GRAVE;Ll;0;L;00E2 0300;;;;N;;;1EA6;;1EA6
+1EA8;LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE;Lu;0;L;00C2 0309;;;;N;;;;1EA9;
+1EA9;LATIN SMALL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE;Ll;0;L;00E2 0309;;;;N;;;1EA8;;1EA8
+1EAA;LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND TILDE;Lu;0;L;00C2 0303;;;;N;;;;1EAB;
+1EAB;LATIN SMALL LETTER A WITH CIRCUMFLEX AND TILDE;Ll;0;L;00E2 0303;;;;N;;;1EAA;;1EAA
+1EAC;LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND DOT BELOW;Lu;0;L;1EA0 0302;;;;N;;;;1EAD;
+1EAD;LATIN SMALL LETTER A WITH CIRCUMFLEX AND DOT BELOW;Ll;0;L;1EA1 0302;;;;N;;;1EAC;;1EAC
+1EAE;LATIN CAPITAL LETTER A WITH BREVE AND ACUTE;Lu;0;L;0102 0301;;;;N;;;;1EAF;
+1EAF;LATIN SMALL LETTER A WITH BREVE AND ACUTE;Ll;0;L;0103 0301;;;;N;;;1EAE;;1EAE
+1EB0;LATIN CAPITAL LETTER A WITH BREVE AND GRAVE;Lu;0;L;0102 0300;;;;N;;;;1EB1;
+1EB1;LATIN SMALL LETTER A WITH BREVE AND GRAVE;Ll;0;L;0103 0300;;;;N;;;1EB0;;1EB0
+1EB2;LATIN CAPITAL LETTER A WITH BREVE AND HOOK ABOVE;Lu;0;L;0102 0309;;;;N;;;;1EB3;
+1EB3;LATIN SMALL LETTER A WITH BREVE AND HOOK ABOVE;Ll;0;L;0103 0309;;;;N;;;1EB2;;1EB2
+1EB4;LATIN CAPITAL LETTER A WITH BREVE AND TILDE;Lu;0;L;0102 0303;;;;N;;;;1EB5;
+1EB5;LATIN SMALL LETTER A WITH BREVE AND TILDE;Ll;0;L;0103 0303;;;;N;;;1EB4;;1EB4
+1EB6;LATIN CAPITAL LETTER A WITH BREVE AND DOT BELOW;Lu;0;L;1EA0 0306;;;;N;;;;1EB7;
+1EB7;LATIN SMALL LETTER A WITH BREVE AND DOT BELOW;Ll;0;L;1EA1 0306;;;;N;;;1EB6;;1EB6
+1EB8;LATIN CAPITAL LETTER E WITH DOT BELOW;Lu;0;L;0045 0323;;;;N;;;;1EB9;
+1EB9;LATIN SMALL LETTER E WITH DOT BELOW;Ll;0;L;0065 0323;;;;N;;;1EB8;;1EB8
+1EBA;LATIN CAPITAL LETTER E WITH HOOK ABOVE;Lu;0;L;0045 0309;;;;N;;;;1EBB;
+1EBB;LATIN SMALL LETTER E WITH HOOK ABOVE;Ll;0;L;0065 0309;;;;N;;;1EBA;;1EBA
+1EBC;LATIN CAPITAL LETTER E WITH TILDE;Lu;0;L;0045 0303;;;;N;;;;1EBD;
+1EBD;LATIN SMALL LETTER E WITH TILDE;Ll;0;L;0065 0303;;;;N;;;1EBC;;1EBC
+1EBE;LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND ACUTE;Lu;0;L;00CA 0301;;;;N;;;;1EBF;
+1EBF;LATIN SMALL LETTER E WITH CIRCUMFLEX AND ACUTE;Ll;0;L;00EA 0301;;;;N;;;1EBE;;1EBE
+1EC0;LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND GRAVE;Lu;0;L;00CA 0300;;;;N;;;;1EC1;
+1EC1;LATIN SMALL LETTER E WITH CIRCUMFLEX AND GRAVE;Ll;0;L;00EA 0300;;;;N;;;1EC0;;1EC0
+1EC2;LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE;Lu;0;L;00CA 0309;;;;N;;;;1EC3;
+1EC3;LATIN SMALL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE;Ll;0;L;00EA 0309;;;;N;;;1EC2;;1EC2
+1EC4;LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND TILDE;Lu;0;L;00CA 0303;;;;N;;;;1EC5;
+1EC5;LATIN SMALL LETTER E WITH CIRCUMFLEX AND TILDE;Ll;0;L;00EA 0303;;;;N;;;1EC4;;1EC4
+1EC6;LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND DOT BELOW;Lu;0;L;1EB8 0302;;;;N;;;;1EC7;
+1EC7;LATIN SMALL LETTER E WITH CIRCUMFLEX AND DOT BELOW;Ll;0;L;1EB9 0302;;;;N;;;1EC6;;1EC6
+1EC8;LATIN CAPITAL LETTER I WITH HOOK ABOVE;Lu;0;L;0049 0309;;;;N;;;;1EC9;
+1EC9;LATIN SMALL LETTER I WITH HOOK ABOVE;Ll;0;L;0069 0309;;;;N;;;1EC8;;1EC8
+1ECA;LATIN CAPITAL LETTER I WITH DOT BELOW;Lu;0;L;0049 0323;;;;N;;;;1ECB;
+1ECB;LATIN SMALL LETTER I WITH DOT BELOW;Ll;0;L;0069 0323;;;;N;;;1ECA;;1ECA
+1ECC;LATIN CAPITAL LETTER O WITH DOT BELOW;Lu;0;L;004F 0323;;;;N;;;;1ECD;
+1ECD;LATIN SMALL LETTER O WITH DOT BELOW;Ll;0;L;006F 0323;;;;N;;;1ECC;;1ECC
+1ECE;LATIN CAPITAL LETTER O WITH HOOK ABOVE;Lu;0;L;004F 0309;;;;N;;;;1ECF;
+1ECF;LATIN SMALL LETTER O WITH HOOK ABOVE;Ll;0;L;006F 0309;;;;N;;;1ECE;;1ECE
+1ED0;LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND ACUTE;Lu;0;L;00D4 0301;;;;N;;;;1ED1;
+1ED1;LATIN SMALL LETTER O WITH CIRCUMFLEX AND ACUTE;Ll;0;L;00F4 0301;;;;N;;;1ED0;;1ED0
+1ED2;LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND GRAVE;Lu;0;L;00D4 0300;;;;N;;;;1ED3;
+1ED3;LATIN SMALL LETTER O WITH CIRCUMFLEX AND GRAVE;Ll;0;L;00F4 0300;;;;N;;;1ED2;;1ED2
+1ED4;LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE;Lu;0;L;00D4 0309;;;;N;;;;1ED5;
+1ED5;LATIN SMALL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE;Ll;0;L;00F4 0309;;;;N;;;1ED4;;1ED4
+1ED6;LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND TILDE;Lu;0;L;00D4 0303;;;;N;;;;1ED7;
+1ED7;LATIN SMALL LETTER O WITH CIRCUMFLEX AND TILDE;Ll;0;L;00F4 0303;;;;N;;;1ED6;;1ED6
+1ED8;LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND DOT BELOW;Lu;0;L;1ECC 0302;;;;N;;;;1ED9;
+1ED9;LATIN SMALL LETTER O WITH CIRCUMFLEX AND DOT BELOW;Ll;0;L;1ECD 0302;;;;N;;;1ED8;;1ED8
+1EDA;LATIN CAPITAL LETTER O WITH HORN AND ACUTE;Lu;0;L;01A0 0301;;;;N;;;;1EDB;
+1EDB;LATIN SMALL LETTER O WITH HORN AND ACUTE;Ll;0;L;01A1 0301;;;;N;;;1EDA;;1EDA
+1EDC;LATIN CAPITAL LETTER O WITH HORN AND GRAVE;Lu;0;L;01A0 0300;;;;N;;;;1EDD;
+1EDD;LATIN SMALL LETTER O WITH HORN AND GRAVE;Ll;0;L;01A1 0300;;;;N;;;1EDC;;1EDC
+1EDE;LATIN CAPITAL LETTER O WITH HORN AND HOOK ABOVE;Lu;0;L;01A0 0309;;;;N;;;;1EDF;
+1EDF;LATIN SMALL LETTER O WITH HORN AND HOOK ABOVE;Ll;0;L;01A1 0309;;;;N;;;1EDE;;1EDE
+1EE0;LATIN CAPITAL LETTER O WITH HORN AND TILDE;Lu;0;L;01A0 0303;;;;N;;;;1EE1;
+1EE1;LATIN SMALL LETTER O WITH HORN AND TILDE;Ll;0;L;01A1 0303;;;;N;;;1EE0;;1EE0
+1EE2;LATIN CAPITAL LETTER O WITH HORN AND DOT BELOW;Lu;0;L;01A0 0323;;;;N;;;;1EE3;
+1EE3;LATIN SMALL LETTER O WITH HORN AND DOT BELOW;Ll;0;L;01A1 0323;;;;N;;;1EE2;;1EE2
+1EE4;LATIN CAPITAL LETTER U WITH DOT BELOW;Lu;0;L;0055 0323;;;;N;;;;1EE5;
+1EE5;LATIN SMALL LETTER U WITH DOT BELOW;Ll;0;L;0075 0323;;;;N;;;1EE4;;1EE4
+1EE6;LATIN CAPITAL LETTER U WITH HOOK ABOVE;Lu;0;L;0055 0309;;;;N;;;;1EE7;
+1EE7;LATIN SMALL LETTER U WITH HOOK ABOVE;Ll;0;L;0075 0309;;;;N;;;1EE6;;1EE6
+1EE8;LATIN CAPITAL LETTER U WITH HORN AND ACUTE;Lu;0;L;01AF 0301;;;;N;;;;1EE9;
+1EE9;LATIN SMALL LETTER U WITH HORN AND ACUTE;Ll;0;L;01B0 0301;;;;N;;;1EE8;;1EE8
+1EEA;LATIN CAPITAL LETTER U WITH HORN AND GRAVE;Lu;0;L;01AF 0300;;;;N;;;;1EEB;
+1EEB;LATIN SMALL LETTER U WITH HORN AND GRAVE;Ll;0;L;01B0 0300;;;;N;;;1EEA;;1EEA
+1EEC;LATIN CAPITAL LETTER U WITH HORN AND HOOK ABOVE;Lu;0;L;01AF 0309;;;;N;;;;1EED;
+1EED;LATIN SMALL LETTER U WITH HORN AND HOOK ABOVE;Ll;0;L;01B0 0309;;;;N;;;1EEC;;1EEC
+1EEE;LATIN CAPITAL LETTER U WITH HORN AND TILDE;Lu;0;L;01AF 0303;;;;N;;;;1EEF;
+1EEF;LATIN SMALL LETTER U WITH HORN AND TILDE;Ll;0;L;01B0 0303;;;;N;;;1EEE;;1EEE
+1EF0;LATIN CAPITAL LETTER U WITH HORN AND DOT BELOW;Lu;0;L;01AF 0323;;;;N;;;;1EF1;
+1EF1;LATIN SMALL LETTER U WITH HORN AND DOT BELOW;Ll;0;L;01B0 0323;;;;N;;;1EF0;;1EF0
+1EF2;LATIN CAPITAL LETTER Y WITH GRAVE;Lu;0;L;0059 0300;;;;N;;;;1EF3;
+1EF3;LATIN SMALL LETTER Y WITH GRAVE;Ll;0;L;0079 0300;;;;N;;;1EF2;;1EF2
+1EF4;LATIN CAPITAL LETTER Y WITH DOT BELOW;Lu;0;L;0059 0323;;;;N;;;;1EF5;
+1EF5;LATIN SMALL LETTER Y WITH DOT BELOW;Ll;0;L;0079 0323;;;;N;;;1EF4;;1EF4
+1EF6;LATIN CAPITAL LETTER Y WITH HOOK ABOVE;Lu;0;L;0059 0309;;;;N;;;;1EF7;
+1EF7;LATIN SMALL LETTER Y WITH HOOK ABOVE;Ll;0;L;0079 0309;;;;N;;;1EF6;;1EF6
+1EF8;LATIN CAPITAL LETTER Y WITH TILDE;Lu;0;L;0059 0303;;;;N;;;;1EF9;
+1EF9;LATIN SMALL LETTER Y WITH TILDE;Ll;0;L;0079 0303;;;;N;;;1EF8;;1EF8
+1F00;GREEK SMALL LETTER ALPHA WITH PSILI;Ll;0;L;03B1 0313;;;;N;;;1F08;;1F08
+1F01;GREEK SMALL LETTER ALPHA WITH DASIA;Ll;0;L;03B1 0314;;;;N;;;1F09;;1F09
+1F02;GREEK SMALL LETTER ALPHA WITH PSILI AND VARIA;Ll;0;L;1F00 0300;;;;N;;;1F0A;;1F0A
+1F03;GREEK SMALL LETTER ALPHA WITH DASIA AND VARIA;Ll;0;L;1F01 0300;;;;N;;;1F0B;;1F0B
+1F04;GREEK SMALL LETTER ALPHA WITH PSILI AND OXIA;Ll;0;L;1F00 0301;;;;N;;;1F0C;;1F0C
+1F05;GREEK SMALL LETTER ALPHA WITH DASIA AND OXIA;Ll;0;L;1F01 0301;;;;N;;;1F0D;;1F0D
+1F06;GREEK SMALL LETTER ALPHA WITH PSILI AND PERISPOMENI;Ll;0;L;1F00 0342;;;;N;;;1F0E;;1F0E
+1F07;GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI;Ll;0;L;1F01 0342;;;;N;;;1F0F;;1F0F
+1F08;GREEK CAPITAL LETTER ALPHA WITH PSILI;Lu;0;L;0391 0313;;;;N;;;;1F00;
+1F09;GREEK CAPITAL LETTER ALPHA WITH DASIA;Lu;0;L;0391 0314;;;;N;;;;1F01;
+1F0A;GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA;Lu;0;L;1F08 0300;;;;N;;;;1F02;
+1F0B;GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA;Lu;0;L;1F09 0300;;;;N;;;;1F03;
+1F0C;GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA;Lu;0;L;1F08 0301;;;;N;;;;1F04;
+1F0D;GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA;Lu;0;L;1F09 0301;;;;N;;;;1F05;
+1F0E;GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI;Lu;0;L;1F08 0342;;;;N;;;;1F06;
+1F0F;GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI;Lu;0;L;1F09 0342;;;;N;;;;1F07;
+1F10;GREEK SMALL LETTER EPSILON WITH PSILI;Ll;0;L;03B5 0313;;;;N;;;1F18;;1F18
+1F11;GREEK SMALL LETTER EPSILON WITH DASIA;Ll;0;L;03B5 0314;;;;N;;;1F19;;1F19
+1F12;GREEK SMALL LETTER EPSILON WITH PSILI AND VARIA;Ll;0;L;1F10 0300;;;;N;;;1F1A;;1F1A
+1F13;GREEK SMALL LETTER EPSILON WITH DASIA AND VARIA;Ll;0;L;1F11 0300;;;;N;;;1F1B;;1F1B
+1F14;GREEK SMALL LETTER EPSILON WITH PSILI AND OXIA;Ll;0;L;1F10 0301;;;;N;;;1F1C;;1F1C
+1F15;GREEK SMALL LETTER EPSILON WITH DASIA AND OXIA;Ll;0;L;1F11 0301;;;;N;;;1F1D;;1F1D
+1F18;GREEK CAPITAL LETTER EPSILON WITH PSILI;Lu;0;L;0395 0313;;;;N;;;;1F10;
+1F19;GREEK CAPITAL LETTER EPSILON WITH DASIA;Lu;0;L;0395 0314;;;;N;;;;1F11;
+1F1A;GREEK CAPITAL LETTER EPSILON WITH PSILI AND VARIA;Lu;0;L;1F18 0300;;;;N;;;;1F12;
+1F1B;GREEK CAPITAL LETTER EPSILON WITH DASIA AND VARIA;Lu;0;L;1F19 0300;;;;N;;;;1F13;
+1F1C;GREEK CAPITAL LETTER EPSILON WITH PSILI AND OXIA;Lu;0;L;1F18 0301;;;;N;;;;1F14;
+1F1D;GREEK CAPITAL LETTER EPSILON WITH DASIA AND OXIA;Lu;0;L;1F19 0301;;;;N;;;;1F15;
+1F20;GREEK SMALL LETTER ETA WITH PSILI;Ll;0;L;03B7 0313;;;;N;;;1F28;;1F28
+1F21;GREEK SMALL LETTER ETA WITH DASIA;Ll;0;L;03B7 0314;;;;N;;;1F29;;1F29
+1F22;GREEK SMALL LETTER ETA WITH PSILI AND VARIA;Ll;0;L;1F20 0300;;;;N;;;1F2A;;1F2A
+1F23;GREEK SMALL LETTER ETA WITH DASIA AND VARIA;Ll;0;L;1F21 0300;;;;N;;;1F2B;;1F2B
+1F24;GREEK SMALL LETTER ETA WITH PSILI AND OXIA;Ll;0;L;1F20 0301;;;;N;;;1F2C;;1F2C
+1F25;GREEK SMALL LETTER ETA WITH DASIA AND OXIA;Ll;0;L;1F21 0301;;;;N;;;1F2D;;1F2D
+1F26;GREEK SMALL LETTER ETA WITH PSILI AND PERISPOMENI;Ll;0;L;1F20 0342;;;;N;;;1F2E;;1F2E
+1F27;GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI;Ll;0;L;1F21 0342;;;;N;;;1F2F;;1F2F
+1F28;GREEK CAPITAL LETTER ETA WITH PSILI;Lu;0;L;0397 0313;;;;N;;;;1F20;
+1F29;GREEK CAPITAL LETTER ETA WITH DASIA;Lu;0;L;0397 0314;;;;N;;;;1F21;
+1F2A;GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA;Lu;0;L;1F28 0300;;;;N;;;;1F22;
+1F2B;GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA;Lu;0;L;1F29 0300;;;;N;;;;1F23;
+1F2C;GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA;Lu;0;L;1F28 0301;;;;N;;;;1F24;
+1F2D;GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA;Lu;0;L;1F29 0301;;;;N;;;;1F25;
+1F2E;GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI;Lu;0;L;1F28 0342;;;;N;;;;1F26;
+1F2F;GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI;Lu;0;L;1F29 0342;;;;N;;;;1F27;
+1F30;GREEK SMALL LETTER IOTA WITH PSILI;Ll;0;L;03B9 0313;;;;N;;;1F38;;1F38
+1F31;GREEK SMALL LETTER IOTA WITH DASIA;Ll;0;L;03B9 0314;;;;N;;;1F39;;1F39
+1F32;GREEK SMALL LETTER IOTA WITH PSILI AND VARIA;Ll;0;L;1F30 0300;;;;N;;;1F3A;;1F3A
+1F33;GREEK SMALL LETTER IOTA WITH DASIA AND VARIA;Ll;0;L;1F31 0300;;;;N;;;1F3B;;1F3B
+1F34;GREEK SMALL LETTER IOTA WITH PSILI AND OXIA;Ll;0;L;1F30 0301;;;;N;;;1F3C;;1F3C
+1F35;GREEK SMALL LETTER IOTA WITH DASIA AND OXIA;Ll;0;L;1F31 0301;;;;N;;;1F3D;;1F3D
+1F36;GREEK SMALL LETTER IOTA WITH PSILI AND PERISPOMENI;Ll;0;L;1F30 0342;;;;N;;;1F3E;;1F3E
+1F37;GREEK SMALL LETTER IOTA WITH DASIA AND PERISPOMENI;Ll;0;L;1F31 0342;;;;N;;;1F3F;;1F3F
+1F38;GREEK CAPITAL LETTER IOTA WITH PSILI;Lu;0;L;0399 0313;;;;N;;;;1F30;
+1F39;GREEK CAPITAL LETTER IOTA WITH DASIA;Lu;0;L;0399 0314;;;;N;;;;1F31;
+1F3A;GREEK CAPITAL LETTER IOTA WITH PSILI AND VARIA;Lu;0;L;1F38 0300;;;;N;;;;1F32;
+1F3B;GREEK CAPITAL LETTER IOTA WITH DASIA AND VARIA;Lu;0;L;1F39 0300;;;;N;;;;1F33;
+1F3C;GREEK CAPITAL LETTER IOTA WITH PSILI AND OXIA;Lu;0;L;1F38 0301;;;;N;;;;1F34;
+1F3D;GREEK CAPITAL LETTER IOTA WITH DASIA AND OXIA;Lu;0;L;1F39 0301;;;;N;;;;1F35;
+1F3E;GREEK CAPITAL LETTER IOTA WITH PSILI AND PERISPOMENI;Lu;0;L;1F38 0342;;;;N;;;;1F36;
+1F3F;GREEK CAPITAL LETTER IOTA WITH DASIA AND PERISPOMENI;Lu;0;L;1F39 0342;;;;N;;;;1F37;
+1F40;GREEK SMALL LETTER OMICRON WITH PSILI;Ll;0;L;03BF 0313;;;;N;;;1F48;;1F48
+1F41;GREEK SMALL LETTER OMICRON WITH DASIA;Ll;0;L;03BF 0314;;;;N;;;1F49;;1F49
+1F42;GREEK SMALL LETTER OMICRON WITH PSILI AND VARIA;Ll;0;L;1F40 0300;;;;N;;;1F4A;;1F4A
+1F43;GREEK SMALL LETTER OMICRON WITH DASIA AND VARIA;Ll;0;L;1F41 0300;;;;N;;;1F4B;;1F4B
+1F44;GREEK SMALL LETTER OMICRON WITH PSILI AND OXIA;Ll;0;L;1F40 0301;;;;N;;;1F4C;;1F4C
+1F45;GREEK SMALL LETTER OMICRON WITH DASIA AND OXIA;Ll;0;L;1F41 0301;;;;N;;;1F4D;;1F4D
+1F48;GREEK CAPITAL LETTER OMICRON WITH PSILI;Lu;0;L;039F 0313;;;;N;;;;1F40;
+1F49;GREEK CAPITAL LETTER OMICRON WITH DASIA;Lu;0;L;039F 0314;;;;N;;;;1F41;
+1F4A;GREEK CAPITAL LETTER OMICRON WITH PSILI AND VARIA;Lu;0;L;1F48 0300;;;;N;;;;1F42;
+1F4B;GREEK CAPITAL LETTER OMICRON WITH DASIA AND VARIA;Lu;0;L;1F49 0300;;;;N;;;;1F43;
+1F4C;GREEK CAPITAL LETTER OMICRON WITH PSILI AND OXIA;Lu;0;L;1F48 0301;;;;N;;;;1F44;
+1F4D;GREEK CAPITAL LETTER OMICRON WITH DASIA AND OXIA;Lu;0;L;1F49 0301;;;;N;;;;1F45;
+1F50;GREEK SMALL LETTER UPSILON WITH PSILI;Ll;0;L;03C5 0313;;;;N;;;;;
+1F51;GREEK SMALL LETTER UPSILON WITH DASIA;Ll;0;L;03C5 0314;;;;N;;;1F59;;1F59
+1F52;GREEK SMALL LETTER UPSILON WITH PSILI AND VARIA;Ll;0;L;1F50 0300;;;;N;;;;;
+1F53;GREEK SMALL LETTER UPSILON WITH DASIA AND VARIA;Ll;0;L;1F51 0300;;;;N;;;1F5B;;1F5B
+1F54;GREEK SMALL LETTER UPSILON WITH PSILI AND OXIA;Ll;0;L;1F50 0301;;;;N;;;;;
+1F55;GREEK SMALL LETTER UPSILON WITH DASIA AND OXIA;Ll;0;L;1F51 0301;;;;N;;;1F5D;;1F5D
+1F56;GREEK SMALL LETTER UPSILON WITH PSILI AND PERISPOMENI;Ll;0;L;1F50 0342;;;;N;;;;;
+1F57;GREEK SMALL LETTER UPSILON WITH DASIA AND PERISPOMENI;Ll;0;L;1F51 0342;;;;N;;;1F5F;;1F5F
+1F59;GREEK CAPITAL LETTER UPSILON WITH DASIA;Lu;0;L;03A5 0314;;;;N;;;;1F51;
+1F5B;GREEK CAPITAL LETTER UPSILON WITH DASIA AND VARIA;Lu;0;L;1F59 0300;;;;N;;;;1F53;
+1F5D;GREEK CAPITAL LETTER UPSILON WITH DASIA AND OXIA;Lu;0;L;1F59 0301;;;;N;;;;1F55;
+1F5F;GREEK CAPITAL LETTER UPSILON WITH DASIA AND PERISPOMENI;Lu;0;L;1F59 0342;;;;N;;;;1F57;
+1F60;GREEK SMALL LETTER OMEGA WITH PSILI;Ll;0;L;03C9 0313;;;;N;;;1F68;;1F68
+1F61;GREEK SMALL LETTER OMEGA WITH DASIA;Ll;0;L;03C9 0314;;;;N;;;1F69;;1F69
+1F62;GREEK SMALL LETTER OMEGA WITH PSILI AND VARIA;Ll;0;L;1F60 0300;;;;N;;;1F6A;;1F6A
+1F63;GREEK SMALL LETTER OMEGA WITH DASIA AND VARIA;Ll;0;L;1F61 0300;;;;N;;;1F6B;;1F6B
+1F64;GREEK SMALL LETTER OMEGA WITH PSILI AND OXIA;Ll;0;L;1F60 0301;;;;N;;;1F6C;;1F6C
+1F65;GREEK SMALL LETTER OMEGA WITH DASIA AND OXIA;Ll;0;L;1F61 0301;;;;N;;;1F6D;;1F6D
+1F66;GREEK SMALL LETTER OMEGA WITH PSILI AND PERISPOMENI;Ll;0;L;1F60 0342;;;;N;;;1F6E;;1F6E
+1F67;GREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI;Ll;0;L;1F61 0342;;;;N;;;1F6F;;1F6F
+1F68;GREEK CAPITAL LETTER OMEGA WITH PSILI;Lu;0;L;03A9 0313;;;;N;;;;1F60;
+1F69;GREEK CAPITAL LETTER OMEGA WITH DASIA;Lu;0;L;03A9 0314;;;;N;;;;1F61;
+1F6A;GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA;Lu;0;L;1F68 0300;;;;N;;;;1F62;
+1F6B;GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA;Lu;0;L;1F69 0300;;;;N;;;;1F63;
+1F6C;GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA;Lu;0;L;1F68 0301;;;;N;;;;1F64;
+1F6D;GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA;Lu;0;L;1F69 0301;;;;N;;;;1F65;
+1F6E;GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI;Lu;0;L;1F68 0342;;;;N;;;;1F66;
+1F6F;GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI;Lu;0;L;1F69 0342;;;;N;;;;1F67;
+1F70;GREEK SMALL LETTER ALPHA WITH VARIA;Ll;0;L;03B1 0300;;;;N;;;1FBA;;1FBA
+1F71;GREEK SMALL LETTER ALPHA WITH OXIA;Ll;0;L;03AC;;;;N;;;1FBB;;1FBB
+1F72;GREEK SMALL LETTER EPSILON WITH VARIA;Ll;0;L;03B5 0300;;;;N;;;1FC8;;1FC8
+1F73;GREEK SMALL LETTER EPSILON WITH OXIA;Ll;0;L;03AD;;;;N;;;1FC9;;1FC9
+1F74;GREEK SMALL LETTER ETA WITH VARIA;Ll;0;L;03B7 0300;;;;N;;;1FCA;;1FCA
+1F75;GREEK SMALL LETTER ETA WITH OXIA;Ll;0;L;03AE;;;;N;;;1FCB;;1FCB
+1F76;GREEK SMALL LETTER IOTA WITH VARIA;Ll;0;L;03B9 0300;;;;N;;;1FDA;;1FDA
+1F77;GREEK SMALL LETTER IOTA WITH OXIA;Ll;0;L;03AF;;;;N;;;1FDB;;1FDB
+1F78;GREEK SMALL LETTER OMICRON WITH VARIA;Ll;0;L;03BF 0300;;;;N;;;1FF8;;1FF8
+1F79;GREEK SMALL LETTER OMICRON WITH OXIA;Ll;0;L;03CC;;;;N;;;1FF9;;1FF9
+1F7A;GREEK SMALL LETTER UPSILON WITH VARIA;Ll;0;L;03C5 0300;;;;N;;;1FEA;;1FEA
+1F7B;GREEK SMALL LETTER UPSILON WITH OXIA;Ll;0;L;03CD;;;;N;;;1FEB;;1FEB
+1F7C;GREEK SMALL LETTER OMEGA WITH VARIA;Ll;0;L;03C9 0300;;;;N;;;1FFA;;1FFA
+1F7D;GREEK SMALL LETTER OMEGA WITH OXIA;Ll;0;L;03CE;;;;N;;;1FFB;;1FFB
+1F80;GREEK SMALL LETTER ALPHA WITH PSILI AND YPOGEGRAMMENI;Ll;0;L;1F00 0345;;;;N;;;1F88;;1F88
+1F81;GREEK SMALL LETTER ALPHA WITH DASIA AND YPOGEGRAMMENI;Ll;0;L;1F01 0345;;;;N;;;1F89;;1F89
+1F82;GREEK SMALL LETTER ALPHA WITH PSILI AND VARIA AND YPOGEGRAMMENI;Ll;0;L;1F02 0345;;;;N;;;1F8A;;1F8A
+1F83;GREEK SMALL LETTER ALPHA WITH DASIA AND VARIA AND YPOGEGRAMMENI;Ll;0;L;1F03 0345;;;;N;;;1F8B;;1F8B
+1F84;GREEK SMALL LETTER ALPHA WITH PSILI AND OXIA AND YPOGEGRAMMENI;Ll;0;L;1F04 0345;;;;N;;;1F8C;;1F8C
+1F85;GREEK SMALL LETTER ALPHA WITH DASIA AND OXIA AND YPOGEGRAMMENI;Ll;0;L;1F05 0345;;;;N;;;1F8D;;1F8D
+1F86;GREEK SMALL LETTER ALPHA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1F06 0345;;;;N;;;1F8E;;1F8E
+1F87;GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1F07 0345;;;;N;;;1F8F;;1F8F
+1F88;GREEK CAPITAL LETTER ALPHA WITH PSILI AND PROSGEGRAMMENI;Lt;0;L;1F08 0345;;;;N;;;;1F80;
+1F89;GREEK CAPITAL LETTER ALPHA WITH DASIA AND PROSGEGRAMMENI;Lt;0;L;1F09 0345;;;;N;;;;1F81;
+1F8A;GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA AND PROSGEGRAMMENI;Lt;0;L;1F0A 0345;;;;N;;;;1F82;
+1F8B;GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA AND PROSGEGRAMMENI;Lt;0;L;1F0B 0345;;;;N;;;;1F83;
+1F8C;GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA AND PROSGEGRAMMENI;Lt;0;L;1F0C 0345;;;;N;;;;1F84;
+1F8D;GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA AND PROSGEGRAMMENI;Lt;0;L;1F0D 0345;;;;N;;;;1F85;
+1F8E;GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI;Lt;0;L;1F0E 0345;;;;N;;;;1F86;
+1F8F;GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI;Lt;0;L;1F0F 0345;;;;N;;;;1F87;
+1F90;GREEK SMALL LETTER ETA WITH PSILI AND YPOGEGRAMMENI;Ll;0;L;1F20 0345;;;;N;;;1F98;;1F98
+1F91;GREEK SMALL LETTER ETA WITH DASIA AND YPOGEGRAMMENI;Ll;0;L;1F21 0345;;;;N;;;1F99;;1F99
+1F92;GREEK SMALL LETTER ETA WITH PSILI AND VARIA AND YPOGEGRAMMENI;Ll;0;L;1F22 0345;;;;N;;;1F9A;;1F9A
+1F93;GREEK SMALL LETTER ETA WITH DASIA AND VARIA AND YPOGEGRAMMENI;Ll;0;L;1F23 0345;;;;N;;;1F9B;;1F9B
+1F94;GREEK SMALL LETTER ETA WITH PSILI AND OXIA AND YPOGEGRAMMENI;Ll;0;L;1F24 0345;;;;N;;;1F9C;;1F9C
+1F95;GREEK SMALL LETTER ETA WITH DASIA AND OXIA AND YPOGEGRAMMENI;Ll;0;L;1F25 0345;;;;N;;;1F9D;;1F9D
+1F96;GREEK SMALL LETTER ETA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1F26 0345;;;;N;;;1F9E;;1F9E
+1F97;GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1F27 0345;;;;N;;;1F9F;;1F9F
+1F98;GREEK CAPITAL LETTER ETA WITH PSILI AND PROSGEGRAMMENI;Lt;0;L;1F28 0345;;;;N;;;;1F90;
+1F99;GREEK CAPITAL LETTER ETA WITH DASIA AND PROSGEGRAMMENI;Lt;0;L;1F29 0345;;;;N;;;;1F91;
+1F9A;GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA AND PROSGEGRAMMENI;Lt;0;L;1F2A 0345;;;;N;;;;1F92;
+1F9B;GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA AND PROSGEGRAMMENI;Lt;0;L;1F2B 0345;;;;N;;;;1F93;
+1F9C;GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA AND PROSGEGRAMMENI;Lt;0;L;1F2C 0345;;;;N;;;;1F94;
+1F9D;GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA AND PROSGEGRAMMENI;Lt;0;L;1F2D 0345;;;;N;;;;1F95;
+1F9E;GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI;Lt;0;L;1F2E 0345;;;;N;;;;1F96;
+1F9F;GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI;Lt;0;L;1F2F 0345;;;;N;;;;1F97;
+1FA0;GREEK SMALL LETTER OMEGA WITH PSILI AND YPOGEGRAMMENI;Ll;0;L;1F60 0345;;;;N;;;1FA8;;1FA8
+1FA1;GREEK SMALL LETTER OMEGA WITH DASIA AND YPOGEGRAMMENI;Ll;0;L;1F61 0345;;;;N;;;1FA9;;1FA9
+1FA2;GREEK SMALL LETTER OMEGA WITH PSILI AND VARIA AND YPOGEGRAMMENI;Ll;0;L;1F62 0345;;;;N;;;1FAA;;1FAA
+1FA3;GREEK SMALL LETTER OMEGA WITH DASIA AND VARIA AND YPOGEGRAMMENI;Ll;0;L;1F63 0345;;;;N;;;1FAB;;1FAB
+1FA4;GREEK SMALL LETTER OMEGA WITH PSILI AND OXIA AND YPOGEGRAMMENI;Ll;0;L;1F64 0345;;;;N;;;1FAC;;1FAC
+1FA5;GREEK SMALL LETTER OMEGA WITH DASIA AND OXIA AND YPOGEGRAMMENI;Ll;0;L;1F65 0345;;;;N;;;1FAD;;1FAD
+1FA6;GREEK SMALL LETTER OMEGA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1F66 0345;;;;N;;;1FAE;;1FAE
+1FA7;GREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1F67 0345;;;;N;;;1FAF;;1FAF
+1FA8;GREEK CAPITAL LETTER OMEGA WITH PSILI AND PROSGEGRAMMENI;Lt;0;L;1F68 0345;;;;N;;;;1FA0;
+1FA9;GREEK CAPITAL LETTER OMEGA WITH DASIA AND PROSGEGRAMMENI;Lt;0;L;1F69 0345;;;;N;;;;1FA1;
+1FAA;GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA AND PROSGEGRAMMENI;Lt;0;L;1F6A 0345;;;;N;;;;1FA2;
+1FAB;GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA AND PROSGEGRAMMENI;Lt;0;L;1F6B 0345;;;;N;;;;1FA3;
+1FAC;GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA AND PROSGEGRAMMENI;Lt;0;L;1F6C 0345;;;;N;;;;1FA4;
+1FAD;GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA AND PROSGEGRAMMENI;Lt;0;L;1F6D 0345;;;;N;;;;1FA5;
+1FAE;GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI;Lt;0;L;1F6E 0345;;;;N;;;;1FA6;
+1FAF;GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI;Lt;0;L;1F6F 0345;;;;N;;;;1FA7;
+1FB0;GREEK SMALL LETTER ALPHA WITH VRACHY;Ll;0;L;03B1 0306;;;;N;;;1FB8;;1FB8
+1FB1;GREEK SMALL LETTER ALPHA WITH MACRON;Ll;0;L;03B1 0304;;;;N;;;1FB9;;1FB9
+1FB2;GREEK SMALL LETTER ALPHA WITH VARIA AND YPOGEGRAMMENI;Ll;0;L;1F70 0345;;;;N;;;;;
+1FB3;GREEK SMALL LETTER ALPHA WITH YPOGEGRAMMENI;Ll;0;L;03B1 0345;;;;N;;;1FBC;;1FBC
+1FB4;GREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENI;Ll;0;L;03AC 0345;;;;N;;;;;
+1FB6;GREEK SMALL LETTER ALPHA WITH PERISPOMENI;Ll;0;L;03B1 0342;;;;N;;;;;
+1FB7;GREEK SMALL LETTER ALPHA WITH PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1FB6 0345;;;;N;;;;;
+1FB8;GREEK CAPITAL LETTER ALPHA WITH VRACHY;Lu;0;L;0391 0306;;;;N;;;;1FB0;
+1FB9;GREEK CAPITAL LETTER ALPHA WITH MACRON;Lu;0;L;0391 0304;;;;N;;;;1FB1;
+1FBA;GREEK CAPITAL LETTER ALPHA WITH VARIA;Lu;0;L;0391 0300;;;;N;;;;1F70;
+1FBB;GREEK CAPITAL LETTER ALPHA WITH OXIA;Lu;0;L;0386;;;;N;;;;1F71;
+1FBC;GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI;Lt;0;L;0391 0345;;;;N;;;;1FB3;
+1FBD;GREEK KORONIS;Sk;0;ON;<compat> 0020 0313;;;;N;;;;;
+1FBE;GREEK PROSGEGRAMMENI;Ll;0;L;03B9;;;;N;;;0399;;0399
+1FBF;GREEK PSILI;Sk;0;ON;<compat> 0020 0313;;;;N;;;;;
+1FC0;GREEK PERISPOMENI;Sk;0;ON;<compat> 0020 0342;;;;N;;;;;
+1FC1;GREEK DIALYTIKA AND PERISPOMENI;Sk;0;ON;00A8 0342;;;;N;;;;;
+1FC2;GREEK SMALL LETTER ETA WITH VARIA AND YPOGEGRAMMENI;Ll;0;L;1F74 0345;;;;N;;;;;
+1FC3;GREEK SMALL LETTER ETA WITH YPOGEGRAMMENI;Ll;0;L;03B7 0345;;;;N;;;1FCC;;1FCC
+1FC4;GREEK SMALL LETTER ETA WITH OXIA AND YPOGEGRAMMENI;Ll;0;L;03AE 0345;;;;N;;;;;
+1FC6;GREEK SMALL LETTER ETA WITH PERISPOMENI;Ll;0;L;03B7 0342;;;;N;;;;;
+1FC7;GREEK SMALL LETTER ETA WITH PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1FC6 0345;;;;N;;;;;
+1FC8;GREEK CAPITAL LETTER EPSILON WITH VARIA;Lu;0;L;0395 0300;;;;N;;;;1F72;
+1FC9;GREEK CAPITAL LETTER EPSILON WITH OXIA;Lu;0;L;0388;;;;N;;;;1F73;
+1FCA;GREEK CAPITAL LETTER ETA WITH VARIA;Lu;0;L;0397 0300;;;;N;;;;1F74;
+1FCB;GREEK CAPITAL LETTER ETA WITH OXIA;Lu;0;L;0389;;;;N;;;;1F75;
+1FCC;GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI;Lt;0;L;0397 0345;;;;N;;;;1FC3;
+1FCD;GREEK PSILI AND VARIA;Sk;0;ON;1FBF 0300;;;;N;;;;;
+1FCE;GREEK PSILI AND OXIA;Sk;0;ON;1FBF 0301;;;;N;;;;;
+1FCF;GREEK PSILI AND PERISPOMENI;Sk;0;ON;1FBF 0342;;;;N;;;;;
+1FD0;GREEK SMALL LETTER IOTA WITH VRACHY;Ll;0;L;03B9 0306;;;;N;;;1FD8;;1FD8
+1FD1;GREEK SMALL LETTER IOTA WITH MACRON;Ll;0;L;03B9 0304;;;;N;;;1FD9;;1FD9
+1FD2;GREEK SMALL LETTER IOTA WITH DIALYTIKA AND VARIA;Ll;0;L;03CA 0300;;;;N;;;;;
+1FD3;GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA;Ll;0;L;0390;;;;N;;;;;
+1FD6;GREEK SMALL LETTER IOTA WITH PERISPOMENI;Ll;0;L;03B9 0342;;;;N;;;;;
+1FD7;GREEK SMALL LETTER IOTA WITH DIALYTIKA AND PERISPOMENI;Ll;0;L;03CA 0342;;;;N;;;;;
+1FD8;GREEK CAPITAL LETTER IOTA WITH VRACHY;Lu;0;L;0399 0306;;;;N;;;;1FD0;
+1FD9;GREEK CAPITAL LETTER IOTA WITH MACRON;Lu;0;L;0399 0304;;;;N;;;;1FD1;
+1FDA;GREEK CAPITAL LETTER IOTA WITH VARIA;Lu;0;L;0399 0300;;;;N;;;;1F76;
+1FDB;GREEK CAPITAL LETTER IOTA WITH OXIA;Lu;0;L;038A;;;;N;;;;1F77;
+1FDD;GREEK DASIA AND VARIA;Sk;0;ON;1FFE 0300;;;;N;;;;;
+1FDE;GREEK DASIA AND OXIA;Sk;0;ON;1FFE 0301;;;;N;;;;;
+1FDF;GREEK DASIA AND PERISPOMENI;Sk;0;ON;1FFE 0342;;;;N;;;;;
+1FE0;GREEK SMALL LETTER UPSILON WITH VRACHY;Ll;0;L;03C5 0306;;;;N;;;1FE8;;1FE8
+1FE1;GREEK SMALL LETTER UPSILON WITH MACRON;Ll;0;L;03C5 0304;;;;N;;;1FE9;;1FE9
+1FE2;GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND VARIA;Ll;0;L;03CB 0300;;;;N;;;;;
+1FE3;GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND OXIA;Ll;0;L;03B0;;;;N;;;;;
+1FE4;GREEK SMALL LETTER RHO WITH PSILI;Ll;0;L;03C1 0313;;;;N;;;;;
+1FE5;GREEK SMALL LETTER RHO WITH DASIA;Ll;0;L;03C1 0314;;;;N;;;1FEC;;1FEC
+1FE6;GREEK SMALL LETTER UPSILON WITH PERISPOMENI;Ll;0;L;03C5 0342;;;;N;;;;;
+1FE7;GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND PERISPOMENI;Ll;0;L;03CB 0342;;;;N;;;;;
+1FE8;GREEK CAPITAL LETTER UPSILON WITH VRACHY;Lu;0;L;03A5 0306;;;;N;;;;1FE0;
+1FE9;GREEK CAPITAL LETTER UPSILON WITH MACRON;Lu;0;L;03A5 0304;;;;N;;;;1FE1;
+1FEA;GREEK CAPITAL LETTER UPSILON WITH VARIA;Lu;0;L;03A5 0300;;;;N;;;;1F7A;
+1FEB;GREEK CAPITAL LETTER UPSILON WITH OXIA;Lu;0;L;038E;;;;N;;;;1F7B;
+1FEC;GREEK CAPITAL LETTER RHO WITH DASIA;Lu;0;L;03A1 0314;;;;N;;;;1FE5;
+1FED;GREEK DIALYTIKA AND VARIA;Sk;0;ON;00A8 0300;;;;N;;;;;
+1FEE;GREEK DIALYTIKA AND OXIA;Sk;0;ON;0385;;;;N;;;;;
+1FEF;GREEK VARIA;Sk;0;ON;0060;;;;N;;;;;
+1FF2;GREEK SMALL LETTER OMEGA WITH VARIA AND YPOGEGRAMMENI;Ll;0;L;1F7C 0345;;;;N;;;;;
+1FF3;GREEK SMALL LETTER OMEGA WITH YPOGEGRAMMENI;Ll;0;L;03C9 0345;;;;N;;;1FFC;;1FFC
+1FF4;GREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENI;Ll;0;L;03CE 0345;;;;N;;;;;
+1FF6;GREEK SMALL LETTER OMEGA WITH PERISPOMENI;Ll;0;L;03C9 0342;;;;N;;;;;
+1FF7;GREEK SMALL LETTER OMEGA WITH PERISPOMENI AND YPOGEGRAMMENI;Ll;0;L;1FF6 0345;;;;N;;;;;
+1FF8;GREEK CAPITAL LETTER OMICRON WITH VARIA;Lu;0;L;039F 0300;;;;N;;;;1F78;
+1FF9;GREEK CAPITAL LETTER OMICRON WITH OXIA;Lu;0;L;038C;;;;N;;;;1F79;
+1FFA;GREEK CAPITAL LETTER OMEGA WITH VARIA;Lu;0;L;03A9 0300;;;;N;;;;1F7C;
+1FFB;GREEK CAPITAL LETTER OMEGA WITH OXIA;Lu;0;L;038F;;;;N;;;;1F7D;
+1FFC;GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI;Lt;0;L;03A9 0345;;;;N;;;;1FF3;
+1FFD;GREEK OXIA;Sk;0;ON;00B4;;;;N;;;;;
+1FFE;GREEK DASIA;Sk;0;ON;<compat> 0020 0314;;;;N;;;;;
+2000;EN QUAD;Zs;0;WS;2002;;;;N;;;;;
+2001;EM QUAD;Zs;0;WS;2003;;;;N;;;;;
+2002;EN SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
+2003;EM SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
+2004;THREE-PER-EM SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
+2005;FOUR-PER-EM SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
+2006;SIX-PER-EM SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
+2007;FIGURE SPACE;Zs;0;WS;<noBreak> 0020;;;;N;;;;;
+2008;PUNCTUATION SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
+2009;THIN SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
+200A;HAIR SPACE;Zs;0;WS;<compat> 0020;;;;N;;;;;
+200B;ZERO WIDTH SPACE;Zs;0;BN;;;;;N;;;;;
+200C;ZERO WIDTH NON-JOINER;Cf;0;BN;;;;;N;;;;;
+200D;ZERO WIDTH JOINER;Cf;0;BN;;;;;N;;;;;
+200E;LEFT-TO-RIGHT MARK;Cf;0;L;;;;;N;;;;;
+200F;RIGHT-TO-LEFT MARK;Cf;0;R;;;;;N;;;;;
+2010;HYPHEN;Pd;0;ON;;;;;N;;;;;
+2011;NON-BREAKING HYPHEN;Pd;0;ON;<noBreak> 2010;;;;N;;;;;
+2012;FIGURE DASH;Pd;0;ON;;;;;N;;;;;
+2013;EN DASH;Pd;0;ON;;;;;N;;;;;
+2014;EM DASH;Pd;0;ON;;;;;N;;;;;
+2015;HORIZONTAL BAR;Pd;0;ON;;;;;N;QUOTATION DASH;;;;
+2016;DOUBLE VERTICAL LINE;Po;0;ON;;;;;N;DOUBLE VERTICAL BAR;;;;
+2017;DOUBLE LOW LINE;Po;0;ON;<compat> 0020 0333;;;;N;SPACING DOUBLE UNDERSCORE;;;;
+2018;LEFT SINGLE QUOTATION MARK;Pi;0;ON;;;;;N;SINGLE TURNED COMMA QUOTATION MARK;;;;
+2019;RIGHT SINGLE QUOTATION MARK;Pf;0;ON;;;;;N;SINGLE COMMA QUOTATION MARK;;;;
+201A;SINGLE LOW-9 QUOTATION MARK;Ps;0;ON;;;;;N;LOW SINGLE COMMA QUOTATION MARK;;;;
+201B;SINGLE HIGH-REVERSED-9 QUOTATION MARK;Pi;0;ON;;;;;N;SINGLE REVERSED COMMA QUOTATION MARK;;;;
+201C;LEFT DOUBLE QUOTATION MARK;Pi;0;ON;;;;;N;DOUBLE TURNED COMMA QUOTATION MARK;;;;
+201D;RIGHT DOUBLE QUOTATION MARK;Pf;0;ON;;;;;N;DOUBLE COMMA QUOTATION MARK;;;;
+201E;DOUBLE LOW-9 QUOTATION MARK;Ps;0;ON;;;;;N;LOW DOUBLE COMMA QUOTATION MARK;;;;
+201F;DOUBLE HIGH-REVERSED-9 QUOTATION MARK;Pi;0;ON;;;;;N;DOUBLE REVERSED COMMA QUOTATION MARK;;;;
+2020;DAGGER;Po;0;ON;;;;;N;;;;;
+2021;DOUBLE DAGGER;Po;0;ON;;;;;N;;;;;
+2022;BULLET;Po;0;ON;;;;;N;;;;;
+2023;TRIANGULAR BULLET;Po;0;ON;;;;;N;;;;;
+2024;ONE DOT LEADER;Po;0;ON;<compat> 002E;;;;N;;;;;
+2025;TWO DOT LEADER;Po;0;ON;<compat> 002E 002E;;;;N;;;;;
+2026;HORIZONTAL ELLIPSIS;Po;0;ON;<compat> 002E 002E 002E;;;;N;;;;;
+2027;HYPHENATION POINT;Po;0;ON;;;;;N;;;;;
+2028;LINE SEPARATOR;Zl;0;WS;;;;;N;;;;;
+2029;PARAGRAPH SEPARATOR;Zp;0;B;;;;;N;;;;;
+202A;LEFT-TO-RIGHT EMBEDDING;Cf;0;LRE;;;;;N;;;;;
+202B;RIGHT-TO-LEFT EMBEDDING;Cf;0;RLE;;;;;N;;;;;
+202C;POP DIRECTIONAL FORMATTING;Cf;0;PDF;;;;;N;;;;;
+202D;LEFT-TO-RIGHT OVERRIDE;Cf;0;LRO;;;;;N;;;;;
+202E;RIGHT-TO-LEFT OVERRIDE;Cf;0;RLO;;;;;N;;;;;
+202F;NARROW NO-BREAK SPACE;Zs;0;WS;<noBreak> 0020;;;;N;;;;;
+2030;PER MILLE SIGN;Po;0;ET;;;;;N;;;;;
+2031;PER TEN THOUSAND SIGN;Po;0;ET;;;;;N;;;;;
+2032;PRIME;Po;0;ET;;;;;N;;;;;
+2033;DOUBLE PRIME;Po;0;ET;<compat> 2032 2032;;;;N;;;;;
+2034;TRIPLE PRIME;Po;0;ET;<compat> 2032 2032 2032;;;;N;;;;;
+2035;REVERSED PRIME;Po;0;ON;;;;;N;;;;;
+2036;REVERSED DOUBLE PRIME;Po;0;ON;<compat> 2035 2035;;;;N;;;;;
+2037;REVERSED TRIPLE PRIME;Po;0;ON;<compat> 2035 2035 2035;;;;N;;;;;
+2038;CARET;Po;0;ON;;;;;N;;;;;
+2039;SINGLE LEFT-POINTING ANGLE QUOTATION MARK;Pi;0;ON;;;;;Y;LEFT POINTING SINGLE GUILLEMET;;;;
+203A;SINGLE RIGHT-POINTING ANGLE QUOTATION MARK;Pf;0;ON;;;;;Y;RIGHT POINTING SINGLE GUILLEMET;;;;
+203B;REFERENCE MARK;Po;0;ON;;;;;N;;;;;
+203C;DOUBLE EXCLAMATION MARK;Po;0;ON;<compat> 0021 0021;;;;N;;;;;
+203D;INTERROBANG;Po;0;ON;;;;;N;;;;;
+203E;OVERLINE;Po;0;ON;<compat> 0020 0305;;;;N;SPACING OVERSCORE;;;;
+203F;UNDERTIE;Pc;0;ON;;;;;N;;Enotikon;;;
+2040;CHARACTER TIE;Pc;0;ON;;;;;N;;;;;
+2041;CARET INSERTION POINT;Po;0;ON;;;;;N;;;;;
+2042;ASTERISM;Po;0;ON;;;;;N;;;;;
+2043;HYPHEN BULLET;Po;0;ON;;;;;N;;;;;
+2044;FRACTION SLASH;Sm;0;ON;;;;;N;;;;;
+2045;LEFT SQUARE BRACKET WITH QUILL;Ps;0;ON;;;;;Y;;;;;
+2046;RIGHT SQUARE BRACKET WITH QUILL;Pe;0;ON;;;;;Y;;;;;
+2048;QUESTION EXCLAMATION MARK;Po;0;ON;<compat> 003F 0021;;;;N;;;;;
+2049;EXCLAMATION QUESTION MARK;Po;0;ON;<compat> 0021 003F;;;;N;;;;;
+204A;TIRONIAN SIGN ET;Po;0;ON;;;;;N;;;;;
+204B;REVERSED PILCROW SIGN;Po;0;ON;;;;;N;;;;;
+204C;BLACK LEFTWARDS BULLET;Po;0;ON;;;;;N;;;;;
+204D;BLACK RIGHTWARDS BULLET;Po;0;ON;;;;;N;;;;;
+206A;INHIBIT SYMMETRIC SWAPPING;Cf;0;BN;;;;;N;;;;;
+206B;ACTIVATE SYMMETRIC SWAPPING;Cf;0;BN;;;;;N;;;;;
+206C;INHIBIT ARABIC FORM SHAPING;Cf;0;BN;;;;;N;;;;;
+206D;ACTIVATE ARABIC FORM SHAPING;Cf;0;BN;;;;;N;;;;;
+206E;NATIONAL DIGIT SHAPES;Cf;0;BN;;;;;N;;;;;
+206F;NOMINAL DIGIT SHAPES;Cf;0;BN;;;;;N;;;;;
+2070;SUPERSCRIPT ZERO;No;0;EN;<super> 0030;0;0;0;N;SUPERSCRIPT DIGIT ZERO;;;;
+2074;SUPERSCRIPT FOUR;No;0;EN;<super> 0034;4;4;4;N;SUPERSCRIPT DIGIT FOUR;;;;
+2075;SUPERSCRIPT FIVE;No;0;EN;<super> 0035;5;5;5;N;SUPERSCRIPT DIGIT FIVE;;;;
+2076;SUPERSCRIPT SIX;No;0;EN;<super> 0036;6;6;6;N;SUPERSCRIPT DIGIT SIX;;;;
+2077;SUPERSCRIPT SEVEN;No;0;EN;<super> 0037;7;7;7;N;SUPERSCRIPT DIGIT SEVEN;;;;
+2078;SUPERSCRIPT EIGHT;No;0;EN;<super> 0038;8;8;8;N;SUPERSCRIPT DIGIT EIGHT;;;;
+2079;SUPERSCRIPT NINE;No;0;EN;<super> 0039;9;9;9;N;SUPERSCRIPT DIGIT NINE;;;;
+207A;SUPERSCRIPT PLUS SIGN;Sm;0;ET;<super> 002B;;;;N;;;;;
+207B;SUPERSCRIPT MINUS;Sm;0;ET;<super> 2212;;;;N;SUPERSCRIPT HYPHEN-MINUS;;;;
+207C;SUPERSCRIPT EQUALS SIGN;Sm;0;ON;<super> 003D;;;;N;;;;;
+207D;SUPERSCRIPT LEFT PARENTHESIS;Ps;0;ON;<super> 0028;;;;Y;SUPERSCRIPT OPENING PARENTHESIS;;;;
+207E;SUPERSCRIPT RIGHT PARENTHESIS;Pe;0;ON;<super> 0029;;;;Y;SUPERSCRIPT CLOSING PARENTHESIS;;;;
+207F;SUPERSCRIPT LATIN SMALL LETTER N;Ll;0;L;<super> 006E;;;;N;;;;;
+2080;SUBSCRIPT ZERO;No;0;EN;<sub> 0030;0;0;0;N;SUBSCRIPT DIGIT ZERO;;;;
+2081;SUBSCRIPT ONE;No;0;EN;<sub> 0031;1;1;1;N;SUBSCRIPT DIGIT ONE;;;;
+2082;SUBSCRIPT TWO;No;0;EN;<sub> 0032;2;2;2;N;SUBSCRIPT DIGIT TWO;;;;
+2083;SUBSCRIPT THREE;No;0;EN;<sub> 0033;3;3;3;N;SUBSCRIPT DIGIT THREE;;;;
+2084;SUBSCRIPT FOUR;No;0;EN;<sub> 0034;4;4;4;N;SUBSCRIPT DIGIT FOUR;;;;
+2085;SUBSCRIPT FIVE;No;0;EN;<sub> 0035;5;5;5;N;SUBSCRIPT DIGIT FIVE;;;;
+2086;SUBSCRIPT SIX;No;0;EN;<sub> 0036;6;6;6;N;SUBSCRIPT DIGIT SIX;;;;
+2087;SUBSCRIPT SEVEN;No;0;EN;<sub> 0037;7;7;7;N;SUBSCRIPT DIGIT SEVEN;;;;
+2088;SUBSCRIPT EIGHT;No;0;EN;<sub> 0038;8;8;8;N;SUBSCRIPT DIGIT EIGHT;;;;
+2089;SUBSCRIPT NINE;No;0;EN;<sub> 0039;9;9;9;N;SUBSCRIPT DIGIT NINE;;;;
+208A;SUBSCRIPT PLUS SIGN;Sm;0;ET;<sub> 002B;;;;N;;;;;
+208B;SUBSCRIPT MINUS;Sm;0;ET;<sub> 2212;;;;N;SUBSCRIPT HYPHEN-MINUS;;;;
+208C;SUBSCRIPT EQUALS SIGN;Sm;0;ON;<sub> 003D;;;;N;;;;;
+208D;SUBSCRIPT LEFT PARENTHESIS;Ps;0;ON;<sub> 0028;;;;Y;SUBSCRIPT OPENING PARENTHESIS;;;;
+208E;SUBSCRIPT RIGHT PARENTHESIS;Pe;0;ON;<sub> 0029;;;;Y;SUBSCRIPT CLOSING PARENTHESIS;;;;
+20A0;EURO-CURRENCY SIGN;Sc;0;ET;;;;;N;;;;;
+20A1;COLON SIGN;Sc;0;ET;;;;;N;;;;;
+20A2;CRUZEIRO SIGN;Sc;0;ET;;;;;N;;;;;
+20A3;FRENCH FRANC SIGN;Sc;0;ET;;;;;N;;;;;
+20A4;LIRA SIGN;Sc;0;ET;;;;;N;;;;;
+20A5;MILL SIGN;Sc;0;ET;;;;;N;;;;;
+20A6;NAIRA SIGN;Sc;0;ET;;;;;N;;;;;
+20A7;PESETA SIGN;Sc;0;ET;;;;;N;;;;;
+20A8;RUPEE SIGN;Sc;0;ET;<compat> 0052 0073;;;;N;;;;;
+20A9;WON SIGN;Sc;0;ET;;;;;N;;;;;
+20AA;NEW SHEQEL SIGN;Sc;0;ET;;;;;N;;;;;
+20AB;DONG SIGN;Sc;0;ET;;;;;N;;;;;
+20AC;EURO SIGN;Sc;0;ET;;;;;N;;;;;
+20AD;KIP SIGN;Sc;0;ET;;;;;N;;;;;
+20AE;TUGRIK SIGN;Sc;0;ET;;;;;N;;;;;
+20AF;DRACHMA SIGN;Sc;0;ET;;;;;N;;;;;
+20D0;COMBINING LEFT HARPOON ABOVE;Mn;230;NSM;;;;;N;NON-SPACING LEFT HARPOON ABOVE;;;;
+20D1;COMBINING RIGHT HARPOON ABOVE;Mn;230;NSM;;;;;N;NON-SPACING RIGHT HARPOON ABOVE;;;;
+20D2;COMBINING LONG VERTICAL LINE OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING LONG VERTICAL BAR OVERLAY;;;;
+20D3;COMBINING SHORT VERTICAL LINE OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING SHORT VERTICAL BAR OVERLAY;;;;
+20D4;COMBINING ANTICLOCKWISE ARROW ABOVE;Mn;230;NSM;;;;;N;NON-SPACING ANTICLOCKWISE ARROW ABOVE;;;;
+20D5;COMBINING CLOCKWISE ARROW ABOVE;Mn;230;NSM;;;;;N;NON-SPACING CLOCKWISE ARROW ABOVE;;;;
+20D6;COMBINING LEFT ARROW ABOVE;Mn;230;NSM;;;;;N;NON-SPACING LEFT ARROW ABOVE;;;;
+20D7;COMBINING RIGHT ARROW ABOVE;Mn;230;NSM;;;;;N;NON-SPACING RIGHT ARROW ABOVE;;;;
+20D8;COMBINING RING OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING RING OVERLAY;;;;
+20D9;COMBINING CLOCKWISE RING OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING CLOCKWISE RING OVERLAY;;;;
+20DA;COMBINING ANTICLOCKWISE RING OVERLAY;Mn;1;NSM;;;;;N;NON-SPACING ANTICLOCKWISE RING OVERLAY;;;;
+20DB;COMBINING THREE DOTS ABOVE;Mn;230;NSM;;;;;N;NON-SPACING THREE DOTS ABOVE;;;;
+20DC;COMBINING FOUR DOTS ABOVE;Mn;230;NSM;;;;;N;NON-SPACING FOUR DOTS ABOVE;;;;
+20DD;COMBINING ENCLOSING CIRCLE;Me;0;NSM;;;;;N;ENCLOSING CIRCLE;;;;
+20DE;COMBINING ENCLOSING SQUARE;Me;0;NSM;;;;;N;ENCLOSING SQUARE;;;;
+20DF;COMBINING ENCLOSING DIAMOND;Me;0;NSM;;;;;N;ENCLOSING DIAMOND;;;;
+20E0;COMBINING ENCLOSING CIRCLE BACKSLASH;Me;0;NSM;;;;;N;ENCLOSING CIRCLE SLASH;;;;
+20E1;COMBINING LEFT RIGHT ARROW ABOVE;Mn;230;NSM;;;;;N;NON-SPACING LEFT RIGHT ARROW ABOVE;;;;
+20E2;COMBINING ENCLOSING SCREEN;Me;0;NSM;;;;;N;;;;;
+20E3;COMBINING ENCLOSING KEYCAP;Me;0;NSM;;;;;N;;;;;
+2100;ACCOUNT OF;So;0;ON;<compat> 0061 002F 0063;;;;N;;;;;
+2101;ADDRESSED TO THE SUBJECT;So;0;ON;<compat> 0061 002F 0073;;;;N;;;;;
+2102;DOUBLE-STRUCK CAPITAL C;Lu;0;L;<font> 0043;;;;N;DOUBLE-STRUCK C;;;;
+2103;DEGREE CELSIUS;So;0;ON;<compat> 00B0 0043;;;;N;DEGREES CENTIGRADE;;;;
+2104;CENTRE LINE SYMBOL;So;0;ON;;;;;N;C L SYMBOL;;;;
+2105;CARE OF;So;0;ON;<compat> 0063 002F 006F;;;;N;;;;;
+2106;CADA UNA;So;0;ON;<compat> 0063 002F 0075;;;;N;;;;;
+2107;EULER CONSTANT;Lu;0;L;<compat> 0190;;;;N;EULERS;;;;
+2108;SCRUPLE;So;0;ON;;;;;N;;;;;
+2109;DEGREE FAHRENHEIT;So;0;ON;<compat> 00B0 0046;;;;N;DEGREES FAHRENHEIT;;;;
+210A;SCRIPT SMALL G;Ll;0;L;<font> 0067;;;;N;;;;;
+210B;SCRIPT CAPITAL H;Lu;0;L;<font> 0048;;;;N;SCRIPT H;;;;
+210C;BLACK-LETTER CAPITAL H;Lu;0;L;<font> 0048;;;;N;BLACK-LETTER H;;;;
+210D;DOUBLE-STRUCK CAPITAL H;Lu;0;L;<font> 0048;;;;N;DOUBLE-STRUCK H;;;;
+210E;PLANCK CONSTANT;Ll;0;L;<font> 0068;;;;N;;;;;
+210F;PLANCK CONSTANT OVER TWO PI;Ll;0;L;<font> 0127;;;;N;PLANCK CONSTANT OVER 2 PI;;;;
+2110;SCRIPT CAPITAL I;Lu;0;L;<font> 0049;;;;N;SCRIPT I;;;;
+2111;BLACK-LETTER CAPITAL I;Lu;0;L;<font> 0049;;;;N;BLACK-LETTER I;;;;
+2112;SCRIPT CAPITAL L;Lu;0;L;<font> 004C;;;;N;SCRIPT L;;;;
+2113;SCRIPT SMALL L;Ll;0;L;<font> 006C;;;;N;;;;;
+2114;L B BAR SYMBOL;So;0;ON;;;;;N;;;;;
+2115;DOUBLE-STRUCK CAPITAL N;Lu;0;L;<font> 004E;;;;N;DOUBLE-STRUCK N;;;;
+2116;NUMERO SIGN;So;0;ON;<compat> 004E 006F;;;;N;NUMERO;;;;
+2117;SOUND RECORDING COPYRIGHT;So;0;ON;;;;;N;;;;;
+2118;SCRIPT CAPITAL P;So;0;ON;;;;;N;SCRIPT P;;;;
+2119;DOUBLE-STRUCK CAPITAL P;Lu;0;L;<font> 0050;;;;N;DOUBLE-STRUCK P;;;;
+211A;DOUBLE-STRUCK CAPITAL Q;Lu;0;L;<font> 0051;;;;N;DOUBLE-STRUCK Q;;;;
+211B;SCRIPT CAPITAL R;Lu;0;L;<font> 0052;;;;N;SCRIPT R;;;;
+211C;BLACK-LETTER CAPITAL R;Lu;0;L;<font> 0052;;;;N;BLACK-LETTER R;;;;
+211D;DOUBLE-STRUCK CAPITAL R;Lu;0;L;<font> 0052;;;;N;DOUBLE-STRUCK R;;;;
+211E;PRESCRIPTION TAKE;So;0;ON;;;;;N;;;;;
+211F;RESPONSE;So;0;ON;;;;;N;;;;;
+2120;SERVICE MARK;So;0;ON;<super> 0053 004D;;;;N;;;;;
+2121;TELEPHONE SIGN;So;0;ON;<compat> 0054 0045 004C;;;;N;T E L SYMBOL;;;;
+2122;TRADE MARK SIGN;So;0;ON;<super> 0054 004D;;;;N;TRADEMARK;;;;
+2123;VERSICLE;So;0;ON;;;;;N;;;;;
+2124;DOUBLE-STRUCK CAPITAL Z;Lu;0;L;<font> 005A;;;;N;DOUBLE-STRUCK Z;;;;
+2125;OUNCE SIGN;So;0;ON;;;;;N;OUNCE;;;;
+2126;OHM SIGN;Lu;0;L;03A9;;;;N;OHM;;;03C9;
+2127;INVERTED OHM SIGN;So;0;ON;;;;;N;MHO;;;;
+2128;BLACK-LETTER CAPITAL Z;Lu;0;L;<font> 005A;;;;N;BLACK-LETTER Z;;;;
+2129;TURNED GREEK SMALL LETTER IOTA;So;0;ON;;;;;N;;;;;
+212A;KELVIN SIGN;Lu;0;L;004B;;;;N;DEGREES KELVIN;;;006B;
+212B;ANGSTROM SIGN;Lu;0;L;00C5;;;;N;ANGSTROM UNIT;;;00E5;
+212C;SCRIPT CAPITAL B;Lu;0;L;<font> 0042;;;;N;SCRIPT B;;;;
+212D;BLACK-LETTER CAPITAL C;Lu;0;L;<font> 0043;;;;N;BLACK-LETTER C;;;;
+212E;ESTIMATED SYMBOL;So;0;ET;;;;;N;;;;;
+212F;SCRIPT SMALL E;Ll;0;L;<font> 0065;;;;N;;;;;
+2130;SCRIPT CAPITAL E;Lu;0;L;<font> 0045;;;;N;SCRIPT E;;;;
+2131;SCRIPT CAPITAL F;Lu;0;L;<font> 0046;;;;N;SCRIPT F;;;;
+2132;TURNED CAPITAL F;So;0;ON;;;;;N;TURNED F;;;;
+2133;SCRIPT CAPITAL M;Lu;0;L;<font> 004D;;;;N;SCRIPT M;;;;
+2134;SCRIPT SMALL O;Ll;0;L;<font> 006F;;;;N;;;;;
+2135;ALEF SYMBOL;Lo;0;L;<compat> 05D0;;;;N;FIRST TRANSFINITE CARDINAL;;;;
+2136;BET SYMBOL;Lo;0;L;<compat> 05D1;;;;N;SECOND TRANSFINITE CARDINAL;;;;
+2137;GIMEL SYMBOL;Lo;0;L;<compat> 05D2;;;;N;THIRD TRANSFINITE CARDINAL;;;;
+2138;DALET SYMBOL;Lo;0;L;<compat> 05D3;;;;N;FOURTH TRANSFINITE CARDINAL;;;;
+2139;INFORMATION SOURCE;Ll;0;L;<font> 0069;;;;N;;;;;
+213A;ROTATED CAPITAL Q;So;0;ON;;;;;N;;;;;
+2153;VULGAR FRACTION ONE THIRD;No;0;ON;<fraction> 0031 2044 0033;;;1/3;N;FRACTION ONE THIRD;;;;
+2154;VULGAR FRACTION TWO THIRDS;No;0;ON;<fraction> 0032 2044 0033;;;2/3;N;FRACTION TWO THIRDS;;;;
+2155;VULGAR FRACTION ONE FIFTH;No;0;ON;<fraction> 0031 2044 0035;;;1/5;N;FRACTION ONE FIFTH;;;;
+2156;VULGAR FRACTION TWO FIFTHS;No;0;ON;<fraction> 0032 2044 0035;;;2/5;N;FRACTION TWO FIFTHS;;;;
+2157;VULGAR FRACTION THREE FIFTHS;No;0;ON;<fraction> 0033 2044 0035;;;3/5;N;FRACTION THREE FIFTHS;;;;
+2158;VULGAR FRACTION FOUR FIFTHS;No;0;ON;<fraction> 0034 2044 0035;;;4/5;N;FRACTION FOUR FIFTHS;;;;
+2159;VULGAR FRACTION ONE SIXTH;No;0;ON;<fraction> 0031 2044 0036;;;1/6;N;FRACTION ONE SIXTH;;;;
+215A;VULGAR FRACTION FIVE SIXTHS;No;0;ON;<fraction> 0035 2044 0036;;;5/6;N;FRACTION FIVE SIXTHS;;;;
+215B;VULGAR FRACTION ONE EIGHTH;No;0;ON;<fraction> 0031 2044 0038;;;1/8;N;FRACTION ONE EIGHTH;;;;
+215C;VULGAR FRACTION THREE EIGHTHS;No;0;ON;<fraction> 0033 2044 0038;;;3/8;N;FRACTION THREE EIGHTHS;;;;
+215D;VULGAR FRACTION FIVE EIGHTHS;No;0;ON;<fraction> 0035 2044 0038;;;5/8;N;FRACTION FIVE EIGHTHS;;;;
+215E;VULGAR FRACTION SEVEN EIGHTHS;No;0;ON;<fraction> 0037 2044 0038;;;7/8;N;FRACTION SEVEN EIGHTHS;;;;
+215F;FRACTION NUMERATOR ONE;No;0;ON;<fraction> 0031 2044;;;1;N;;;;;
+2160;ROMAN NUMERAL ONE;Nl;0;L;<compat> 0049;;;1;N;;;;2170;
+2161;ROMAN NUMERAL TWO;Nl;0;L;<compat> 0049 0049;;;2;N;;;;2171;
+2162;ROMAN NUMERAL THREE;Nl;0;L;<compat> 0049 0049 0049;;;3;N;;;;2172;
+2163;ROMAN NUMERAL FOUR;Nl;0;L;<compat> 0049 0056;;;4;N;;;;2173;
+2164;ROMAN NUMERAL FIVE;Nl;0;L;<compat> 0056;;;5;N;;;;2174;
+2165;ROMAN NUMERAL SIX;Nl;0;L;<compat> 0056 0049;;;6;N;;;;2175;
+2166;ROMAN NUMERAL SEVEN;Nl;0;L;<compat> 0056 0049 0049;;;7;N;;;;2176;
+2167;ROMAN NUMERAL EIGHT;Nl;0;L;<compat> 0056 0049 0049 0049;;;8;N;;;;2177;
+2168;ROMAN NUMERAL NINE;Nl;0;L;<compat> 0049 0058;;;9;N;;;;2178;
+2169;ROMAN NUMERAL TEN;Nl;0;L;<compat> 0058;;;10;N;;;;2179;
+216A;ROMAN NUMERAL ELEVEN;Nl;0;L;<compat> 0058 0049;;;11;N;;;;217A;
+216B;ROMAN NUMERAL TWELVE;Nl;0;L;<compat> 0058 0049 0049;;;12;N;;;;217B;
+216C;ROMAN NUMERAL FIFTY;Nl;0;L;<compat> 004C;;;50;N;;;;217C;
+216D;ROMAN NUMERAL ONE HUNDRED;Nl;0;L;<compat> 0043;;;100;N;;;;217D;
+216E;ROMAN NUMERAL FIVE HUNDRED;Nl;0;L;<compat> 0044;;;500;N;;;;217E;
+216F;ROMAN NUMERAL ONE THOUSAND;Nl;0;L;<compat> 004D;;;1000;N;;;;217F;
+2170;SMALL ROMAN NUMERAL ONE;Nl;0;L;<compat> 0069;;;1;N;;;2160;;2160
+2171;SMALL ROMAN NUMERAL TWO;Nl;0;L;<compat> 0069 0069;;;2;N;;;2161;;2161
+2172;SMALL ROMAN NUMERAL THREE;Nl;0;L;<compat> 0069 0069 0069;;;3;N;;;2162;;2162
+2173;SMALL ROMAN NUMERAL FOUR;Nl;0;L;<compat> 0069 0076;;;4;N;;;2163;;2163
+2174;SMALL ROMAN NUMERAL FIVE;Nl;0;L;<compat> 0076;;;5;N;;;2164;;2164
+2175;SMALL ROMAN NUMERAL SIX;Nl;0;L;<compat> 0076 0069;;;6;N;;;2165;;2165
+2176;SMALL ROMAN NUMERAL SEVEN;Nl;0;L;<compat> 0076 0069 0069;;;7;N;;;2166;;2166
+2177;SMALL ROMAN NUMERAL EIGHT;Nl;0;L;<compat> 0076 0069 0069 0069;;;8;N;;;2167;;2167
+2178;SMALL ROMAN NUMERAL NINE;Nl;0;L;<compat> 0069 0078;;;9;N;;;2168;;2168
+2179;SMALL ROMAN NUMERAL TEN;Nl;0;L;<compat> 0078;;;10;N;;;2169;;2169
+217A;SMALL ROMAN NUMERAL ELEVEN;Nl;0;L;<compat> 0078 0069;;;11;N;;;216A;;216A
+217B;SMALL ROMAN NUMERAL TWELVE;Nl;0;L;<compat> 0078 0069 0069;;;12;N;;;216B;;216B
+217C;SMALL ROMAN NUMERAL FIFTY;Nl;0;L;<compat> 006C;;;50;N;;;216C;;216C
+217D;SMALL ROMAN NUMERAL ONE HUNDRED;Nl;0;L;<compat> 0063;;;100;N;;;216D;;216D
+217E;SMALL ROMAN NUMERAL FIVE HUNDRED;Nl;0;L;<compat> 0064;;;500;N;;;216E;;216E
+217F;SMALL ROMAN NUMERAL ONE THOUSAND;Nl;0;L;<compat> 006D;;;1000;N;;;216F;;216F
+2180;ROMAN NUMERAL ONE THOUSAND C D;Nl;0;L;;;;1000;N;;;;;
+2181;ROMAN NUMERAL FIVE THOUSAND;Nl;0;L;;;;5000;N;;;;;
+2182;ROMAN NUMERAL TEN THOUSAND;Nl;0;L;;;;10000;N;;;;;
+2183;ROMAN NUMERAL REVERSED ONE HUNDRED;Nl;0;L;;;;;N;;;;;
+2190;LEFTWARDS ARROW;Sm;0;ON;;;;;N;LEFT ARROW;;;;
+2191;UPWARDS ARROW;Sm;0;ON;;;;;N;UP ARROW;;;;
+2192;RIGHTWARDS ARROW;Sm;0;ON;;;;;N;RIGHT ARROW;;;;
+2193;DOWNWARDS ARROW;Sm;0;ON;;;;;N;DOWN ARROW;;;;
+2194;LEFT RIGHT ARROW;Sm;0;ON;;;;;N;;;;;
+2195;UP DOWN ARROW;So;0;ON;;;;;N;;;;;
+2196;NORTH WEST ARROW;So;0;ON;;;;;N;UPPER LEFT ARROW;;;;
+2197;NORTH EAST ARROW;So;0;ON;;;;;N;UPPER RIGHT ARROW;;;;
+2198;SOUTH EAST ARROW;So;0;ON;;;;;N;LOWER RIGHT ARROW;;;;
+2199;SOUTH WEST ARROW;So;0;ON;;;;;N;LOWER LEFT ARROW;;;;
+219A;LEFTWARDS ARROW WITH STROKE;Sm;0;ON;2190 0338;;;;N;LEFT ARROW WITH STROKE;;;;
+219B;RIGHTWARDS ARROW WITH STROKE;Sm;0;ON;2192 0338;;;;N;RIGHT ARROW WITH STROKE;;;;
+219C;LEFTWARDS WAVE ARROW;So;0;ON;;;;;N;LEFT WAVE ARROW;;;;
+219D;RIGHTWARDS WAVE ARROW;So;0;ON;;;;;N;RIGHT WAVE ARROW;;;;
+219E;LEFTWARDS TWO HEADED ARROW;So;0;ON;;;;;N;LEFT TWO HEADED ARROW;;;;
+219F;UPWARDS TWO HEADED ARROW;So;0;ON;;;;;N;UP TWO HEADED ARROW;;;;
+21A0;RIGHTWARDS TWO HEADED ARROW;Sm;0;ON;;;;;N;RIGHT TWO HEADED ARROW;;;;
+21A1;DOWNWARDS TWO HEADED ARROW;So;0;ON;;;;;N;DOWN TWO HEADED ARROW;;;;
+21A2;LEFTWARDS ARROW WITH TAIL;So;0;ON;;;;;N;LEFT ARROW WITH TAIL;;;;
+21A3;RIGHTWARDS ARROW WITH TAIL;Sm;0;ON;;;;;N;RIGHT ARROW WITH TAIL;;;;
+21A4;LEFTWARDS ARROW FROM BAR;So;0;ON;;;;;N;LEFT ARROW FROM BAR;;;;
+21A5;UPWARDS ARROW FROM BAR;So;0;ON;;;;;N;UP ARROW FROM BAR;;;;
+21A6;RIGHTWARDS ARROW FROM BAR;Sm;0;ON;;;;;N;RIGHT ARROW FROM BAR;;;;
+21A7;DOWNWARDS ARROW FROM BAR;So;0;ON;;;;;N;DOWN ARROW FROM BAR;;;;
+21A8;UP DOWN ARROW WITH BASE;So;0;ON;;;;;N;;;;;
+21A9;LEFTWARDS ARROW WITH HOOK;So;0;ON;;;;;N;LEFT ARROW WITH HOOK;;;;
+21AA;RIGHTWARDS ARROW WITH HOOK;So;0;ON;;;;;N;RIGHT ARROW WITH HOOK;;;;
+21AB;LEFTWARDS ARROW WITH LOOP;So;0;ON;;;;;N;LEFT ARROW WITH LOOP;;;;
+21AC;RIGHTWARDS ARROW WITH LOOP;So;0;ON;;;;;N;RIGHT ARROW WITH LOOP;;;;
+21AD;LEFT RIGHT WAVE ARROW;So;0;ON;;;;;N;;;;;
+21AE;LEFT RIGHT ARROW WITH STROKE;Sm;0;ON;2194 0338;;;;N;;;;;
+21AF;DOWNWARDS ZIGZAG ARROW;So;0;ON;;;;;N;DOWN ZIGZAG ARROW;;;;
+21B0;UPWARDS ARROW WITH TIP LEFTWARDS;So;0;ON;;;;;N;UP ARROW WITH TIP LEFT;;;;
+21B1;UPWARDS ARROW WITH TIP RIGHTWARDS;So;0;ON;;;;;N;UP ARROW WITH TIP RIGHT;;;;
+21B2;DOWNWARDS ARROW WITH TIP LEFTWARDS;So;0;ON;;;;;N;DOWN ARROW WITH TIP LEFT;;;;
+21B3;DOWNWARDS ARROW WITH TIP RIGHTWARDS;So;0;ON;;;;;N;DOWN ARROW WITH TIP RIGHT;;;;
+21B4;RIGHTWARDS ARROW WITH CORNER DOWNWARDS;So;0;ON;;;;;N;RIGHT ARROW WITH CORNER DOWN;;;;
+21B5;DOWNWARDS ARROW WITH CORNER LEFTWARDS;So;0;ON;;;;;N;DOWN ARROW WITH CORNER LEFT;;;;
+21B6;ANTICLOCKWISE TOP SEMICIRCLE ARROW;So;0;ON;;;;;N;;;;;
+21B7;CLOCKWISE TOP SEMICIRCLE ARROW;So;0;ON;;;;;N;;;;;
+21B8;NORTH WEST ARROW TO LONG BAR;So;0;ON;;;;;N;UPPER LEFT ARROW TO LONG BAR;;;;
+21B9;LEFTWARDS ARROW TO BAR OVER RIGHTWARDS ARROW TO BAR;So;0;ON;;;;;N;LEFT ARROW TO BAR OVER RIGHT ARROW TO BAR;;;;
+21BA;ANTICLOCKWISE OPEN CIRCLE ARROW;So;0;ON;;;;;N;;;;;
+21BB;CLOCKWISE OPEN CIRCLE ARROW;So;0;ON;;;;;N;;;;;
+21BC;LEFTWARDS HARPOON WITH BARB UPWARDS;So;0;ON;;;;;N;LEFT HARPOON WITH BARB UP;;;;
+21BD;LEFTWARDS HARPOON WITH BARB DOWNWARDS;So;0;ON;;;;;N;LEFT HARPOON WITH BARB DOWN;;;;
+21BE;UPWARDS HARPOON WITH BARB RIGHTWARDS;So;0;ON;;;;;N;UP HARPOON WITH BARB RIGHT;;;;
+21BF;UPWARDS HARPOON WITH BARB LEFTWARDS;So;0;ON;;;;;N;UP HARPOON WITH BARB LEFT;;;;
+21C0;RIGHTWARDS HARPOON WITH BARB UPWARDS;So;0;ON;;;;;N;RIGHT HARPOON WITH BARB UP;;;;
+21C1;RIGHTWARDS HARPOON WITH BARB DOWNWARDS;So;0;ON;;;;;N;RIGHT HARPOON WITH BARB DOWN;;;;
+21C2;DOWNWARDS HARPOON WITH BARB RIGHTWARDS;So;0;ON;;;;;N;DOWN HARPOON WITH BARB RIGHT;;;;
+21C3;DOWNWARDS HARPOON WITH BARB LEFTWARDS;So;0;ON;;;;;N;DOWN HARPOON WITH BARB LEFT;;;;
+21C4;RIGHTWARDS ARROW OVER LEFTWARDS ARROW;So;0;ON;;;;;N;RIGHT ARROW OVER LEFT ARROW;;;;
+21C5;UPWARDS ARROW LEFTWARDS OF DOWNWARDS ARROW;So;0;ON;;;;;N;UP ARROW LEFT OF DOWN ARROW;;;;
+21C6;LEFTWARDS ARROW OVER RIGHTWARDS ARROW;So;0;ON;;;;;N;LEFT ARROW OVER RIGHT ARROW;;;;
+21C7;LEFTWARDS PAIRED ARROWS;So;0;ON;;;;;N;LEFT PAIRED ARROWS;;;;
+21C8;UPWARDS PAIRED ARROWS;So;0;ON;;;;;N;UP PAIRED ARROWS;;;;
+21C9;RIGHTWARDS PAIRED ARROWS;So;0;ON;;;;;N;RIGHT PAIRED ARROWS;;;;
+21CA;DOWNWARDS PAIRED ARROWS;So;0;ON;;;;;N;DOWN PAIRED ARROWS;;;;
+21CB;LEFTWARDS HARPOON OVER RIGHTWARDS HARPOON;So;0;ON;;;;;N;LEFT HARPOON OVER RIGHT HARPOON;;;;
+21CC;RIGHTWARDS HARPOON OVER LEFTWARDS HARPOON;So;0;ON;;;;;N;RIGHT HARPOON OVER LEFT HARPOON;;;;
+21CD;LEFTWARDS DOUBLE ARROW WITH STROKE;So;0;ON;21D0 0338;;;;N;LEFT DOUBLE ARROW WITH STROKE;;;;
+21CE;LEFT RIGHT DOUBLE ARROW WITH STROKE;Sm;0;ON;21D4 0338;;;;N;;;;;
+21CF;RIGHTWARDS DOUBLE ARROW WITH STROKE;Sm;0;ON;21D2 0338;;;;N;RIGHT DOUBLE ARROW WITH STROKE;;;;
+21D0;LEFTWARDS DOUBLE ARROW;So;0;ON;;;;;N;LEFT DOUBLE ARROW;;;;
+21D1;UPWARDS DOUBLE ARROW;So;0;ON;;;;;N;UP DOUBLE ARROW;;;;
+21D2;RIGHTWARDS DOUBLE ARROW;Sm;0;ON;;;;;N;RIGHT DOUBLE ARROW;;;;
+21D3;DOWNWARDS DOUBLE ARROW;So;0;ON;;;;;N;DOWN DOUBLE ARROW;;;;
+21D4;LEFT RIGHT DOUBLE ARROW;Sm;0;ON;;;;;N;;;;;
+21D5;UP DOWN DOUBLE ARROW;So;0;ON;;;;;N;;;;;
+21D6;NORTH WEST DOUBLE ARROW;So;0;ON;;;;;N;UPPER LEFT DOUBLE ARROW;;;;
+21D7;NORTH EAST DOUBLE ARROW;So;0;ON;;;;;N;UPPER RIGHT DOUBLE ARROW;;;;
+21D8;SOUTH EAST DOUBLE ARROW;So;0;ON;;;;;N;LOWER RIGHT DOUBLE ARROW;;;;
+21D9;SOUTH WEST DOUBLE ARROW;So;0;ON;;;;;N;LOWER LEFT DOUBLE ARROW;;;;
+21DA;LEFTWARDS TRIPLE ARROW;So;0;ON;;;;;N;LEFT TRIPLE ARROW;;;;
+21DB;RIGHTWARDS TRIPLE ARROW;So;0;ON;;;;;N;RIGHT TRIPLE ARROW;;;;
+21DC;LEFTWARDS SQUIGGLE ARROW;So;0;ON;;;;;N;LEFT SQUIGGLE ARROW;;;;
+21DD;RIGHTWARDS SQUIGGLE ARROW;So;0;ON;;;;;N;RIGHT SQUIGGLE ARROW;;;;
+21DE;UPWARDS ARROW WITH DOUBLE STROKE;So;0;ON;;;;;N;UP ARROW WITH DOUBLE STROKE;;;;
+21DF;DOWNWARDS ARROW WITH DOUBLE STROKE;So;0;ON;;;;;N;DOWN ARROW WITH DOUBLE STROKE;;;;
+21E0;LEFTWARDS DASHED ARROW;So;0;ON;;;;;N;LEFT DASHED ARROW;;;;
+21E1;UPWARDS DASHED ARROW;So;0;ON;;;;;N;UP DASHED ARROW;;;;
+21E2;RIGHTWARDS DASHED ARROW;So;0;ON;;;;;N;RIGHT DASHED ARROW;;;;
+21E3;DOWNWARDS DASHED ARROW;So;0;ON;;;;;N;DOWN DASHED ARROW;;;;
+21E4;LEFTWARDS ARROW TO BAR;So;0;ON;;;;;N;LEFT ARROW TO BAR;;;;
+21E5;RIGHTWARDS ARROW TO BAR;So;0;ON;;;;;N;RIGHT ARROW TO BAR;;;;
+21E6;LEFTWARDS WHITE ARROW;So;0;ON;;;;;N;WHITE LEFT ARROW;;;;
+21E7;UPWARDS WHITE ARROW;So;0;ON;;;;;N;WHITE UP ARROW;;;;
+21E8;RIGHTWARDS WHITE ARROW;So;0;ON;;;;;N;WHITE RIGHT ARROW;;;;
+21E9;DOWNWARDS WHITE ARROW;So;0;ON;;;;;N;WHITE DOWN ARROW;;;;
+21EA;UPWARDS WHITE ARROW FROM BAR;So;0;ON;;;;;N;WHITE UP ARROW FROM BAR;;;;
+21EB;UPWARDS WHITE ARROW ON PEDESTAL;So;0;ON;;;;;N;;;;;
+21EC;UPWARDS WHITE ARROW ON PEDESTAL WITH HORIZONTAL BAR;So;0;ON;;;;;N;;;;;
+21ED;UPWARDS WHITE ARROW ON PEDESTAL WITH VERTICAL BAR;So;0;ON;;;;;N;;;;;
+21EE;UPWARDS WHITE DOUBLE ARROW;So;0;ON;;;;;N;;;;;
+21EF;UPWARDS WHITE DOUBLE ARROW ON PEDESTAL;So;0;ON;;;;;N;;;;;
+21F0;RIGHTWARDS WHITE ARROW FROM WALL;So;0;ON;;;;;N;;;;;
+21F1;NORTH WEST ARROW TO CORNER;So;0;ON;;;;;N;;;;;
+21F2;SOUTH EAST ARROW TO CORNER;So;0;ON;;;;;N;;;;;
+21F3;UP DOWN WHITE ARROW;So;0;ON;;;;;N;;;;;
+2200;FOR ALL;Sm;0;ON;;;;;N;;;;;
+2201;COMPLEMENT;Sm;0;ON;;;;;Y;;;;;
+2202;PARTIAL DIFFERENTIAL;Sm;0;ON;;;;;Y;;;;;
+2203;THERE EXISTS;Sm;0;ON;;;;;Y;;;;;
+2204;THERE DOES NOT EXIST;Sm;0;ON;2203 0338;;;;Y;;;;;
+2205;EMPTY SET;Sm;0;ON;;;;;N;;;;;
+2206;INCREMENT;Sm;0;ON;;;;;N;;;;;
+2207;NABLA;Sm;0;ON;;;;;N;;;;;
+2208;ELEMENT OF;Sm;0;ON;;;;;Y;;;;;
+2209;NOT AN ELEMENT OF;Sm;0;ON;2208 0338;;;;Y;;;;;
+220A;SMALL ELEMENT OF;Sm;0;ON;;;;;Y;;;;;
+220B;CONTAINS AS MEMBER;Sm;0;ON;;;;;Y;;;;;
+220C;DOES NOT CONTAIN AS MEMBER;Sm;0;ON;220B 0338;;;;Y;;;;;
+220D;SMALL CONTAINS AS MEMBER;Sm;0;ON;;;;;Y;;;;;
+220E;END OF PROOF;Sm;0;ON;;;;;N;;;;;
+220F;N-ARY PRODUCT;Sm;0;ON;;;;;N;;;;;
+2210;N-ARY COPRODUCT;Sm;0;ON;;;;;N;;;;;
+2211;N-ARY SUMMATION;Sm;0;ON;;;;;Y;;;;;
+2212;MINUS SIGN;Sm;0;ET;;;;;N;;;;;
+2213;MINUS-OR-PLUS SIGN;Sm;0;ET;;;;;N;;;;;
+2214;DOT PLUS;Sm;0;ON;;;;;N;;;;;
+2215;DIVISION SLASH;Sm;0;ON;;;;;Y;;;;;
+2216;SET MINUS;Sm;0;ON;;;;;Y;;;;;
+2217;ASTERISK OPERATOR;Sm;0;ON;;;;;N;;;;;
+2218;RING OPERATOR;Sm;0;ON;;;;;N;;;;;
+2219;BULLET OPERATOR;Sm;0;ON;;;;;N;;;;;
+221A;SQUARE ROOT;Sm;0;ON;;;;;Y;;;;;
+221B;CUBE ROOT;Sm;0;ON;;;;;Y;;;;;
+221C;FOURTH ROOT;Sm;0;ON;;;;;Y;;;;;
+221D;PROPORTIONAL TO;Sm;0;ON;;;;;Y;;;;;
+221E;INFINITY;Sm;0;ON;;;;;N;;;;;
+221F;RIGHT ANGLE;Sm;0;ON;;;;;Y;;;;;
+2220;ANGLE;Sm;0;ON;;;;;Y;;;;;
+2221;MEASURED ANGLE;Sm;0;ON;;;;;Y;;;;;
+2222;SPHERICAL ANGLE;Sm;0;ON;;;;;Y;;;;;
+2223;DIVIDES;Sm;0;ON;;;;;N;;;;;
+2224;DOES NOT DIVIDE;Sm;0;ON;2223 0338;;;;Y;;;;;
+2225;PARALLEL TO;Sm;0;ON;;;;;N;;;;;
+2226;NOT PARALLEL TO;Sm;0;ON;2225 0338;;;;Y;;;;;
+2227;LOGICAL AND;Sm;0;ON;;;;;N;;;;;
+2228;LOGICAL OR;Sm;0;ON;;;;;N;;;;;
+2229;INTERSECTION;Sm;0;ON;;;;;N;;;;;
+222A;UNION;Sm;0;ON;;;;;N;;;;;
+222B;INTEGRAL;Sm;0;ON;;;;;Y;;;;;
+222C;DOUBLE INTEGRAL;Sm;0;ON;<compat> 222B 222B;;;;Y;;;;;
+222D;TRIPLE INTEGRAL;Sm;0;ON;<compat> 222B 222B 222B;;;;Y;;;;;
+222E;CONTOUR INTEGRAL;Sm;0;ON;;;;;Y;;;;;
+222F;SURFACE INTEGRAL;Sm;0;ON;<compat> 222E 222E;;;;Y;;;;;
+2230;VOLUME INTEGRAL;Sm;0;ON;<compat> 222E 222E 222E;;;;Y;;;;;
+2231;CLOCKWISE INTEGRAL;Sm;0;ON;;;;;Y;;;;;
+2232;CLOCKWISE CONTOUR INTEGRAL;Sm;0;ON;;;;;Y;;;;;
+2233;ANTICLOCKWISE CONTOUR INTEGRAL;Sm;0;ON;;;;;Y;;;;;
+2234;THEREFORE;Sm;0;ON;;;;;N;;;;;
+2235;BECAUSE;Sm;0;ON;;;;;N;;;;;
+2236;RATIO;Sm;0;ON;;;;;N;;;;;
+2237;PROPORTION;Sm;0;ON;;;;;N;;;;;
+2238;DOT MINUS;Sm;0;ON;;;;;N;;;;;
+2239;EXCESS;Sm;0;ON;;;;;Y;;;;;
+223A;GEOMETRIC PROPORTION;Sm;0;ON;;;;;N;;;;;
+223B;HOMOTHETIC;Sm;0;ON;;;;;Y;;;;;
+223C;TILDE OPERATOR;Sm;0;ON;;;;;Y;;;;;
+223D;REVERSED TILDE;Sm;0;ON;;;;;Y;;lazy S;;;
+223E;INVERTED LAZY S;Sm;0;ON;;;;;Y;;;;;
+223F;SINE WAVE;Sm;0;ON;;;;;Y;;;;;
+2240;WREATH PRODUCT;Sm;0;ON;;;;;Y;;;;;
+2241;NOT TILDE;Sm;0;ON;223C 0338;;;;Y;;;;;
+2242;MINUS TILDE;Sm;0;ON;;;;;Y;;;;;
+2243;ASYMPTOTICALLY EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2244;NOT ASYMPTOTICALLY EQUAL TO;Sm;0;ON;2243 0338;;;;Y;;;;;
+2245;APPROXIMATELY EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2246;APPROXIMATELY BUT NOT ACTUALLY EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2247;NEITHER APPROXIMATELY NOR ACTUALLY EQUAL TO;Sm;0;ON;2245 0338;;;;Y;;;;;
+2248;ALMOST EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2249;NOT ALMOST EQUAL TO;Sm;0;ON;2248 0338;;;;Y;;;;;
+224A;ALMOST EQUAL OR EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+224B;TRIPLE TILDE;Sm;0;ON;;;;;Y;;;;;
+224C;ALL EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+224D;EQUIVALENT TO;Sm;0;ON;;;;;N;;;;;
+224E;GEOMETRICALLY EQUIVALENT TO;Sm;0;ON;;;;;N;;;;;
+224F;DIFFERENCE BETWEEN;Sm;0;ON;;;;;N;;;;;
+2250;APPROACHES THE LIMIT;Sm;0;ON;;;;;N;;;;;
+2251;GEOMETRICALLY EQUAL TO;Sm;0;ON;;;;;N;;;;;
+2252;APPROXIMATELY EQUAL TO OR THE IMAGE OF;Sm;0;ON;;;;;Y;;;;;
+2253;IMAGE OF OR APPROXIMATELY EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2254;COLON EQUALS;Sm;0;ON;;;;;Y;COLON EQUAL;;;;
+2255;EQUALS COLON;Sm;0;ON;;;;;Y;EQUAL COLON;;;;
+2256;RING IN EQUAL TO;Sm;0;ON;;;;;N;;;;;
+2257;RING EQUAL TO;Sm;0;ON;;;;;N;;;;;
+2258;CORRESPONDS TO;Sm;0;ON;;;;;N;;;;;
+2259;ESTIMATES;Sm;0;ON;;;;;N;;;;;
+225A;EQUIANGULAR TO;Sm;0;ON;;;;;N;;;;;
+225B;STAR EQUALS;Sm;0;ON;;;;;N;;;;;
+225C;DELTA EQUAL TO;Sm;0;ON;;;;;N;;;;;
+225D;EQUAL TO BY DEFINITION;Sm;0;ON;;;;;N;;;;;
+225E;MEASURED BY;Sm;0;ON;;;;;N;;;;;
+225F;QUESTIONED EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2260;NOT EQUAL TO;Sm;0;ON;003D 0338;;;;Y;;;;;
+2261;IDENTICAL TO;Sm;0;ON;;;;;N;;;;;
+2262;NOT IDENTICAL TO;Sm;0;ON;2261 0338;;;;Y;;;;;
+2263;STRICTLY EQUIVALENT TO;Sm;0;ON;;;;;N;;;;;
+2264;LESS-THAN OR EQUAL TO;Sm;0;ON;;;;;Y;LESS THAN OR EQUAL TO;;;;
+2265;GREATER-THAN OR EQUAL TO;Sm;0;ON;;;;;Y;GREATER THAN OR EQUAL TO;;;;
+2266;LESS-THAN OVER EQUAL TO;Sm;0;ON;;;;;Y;LESS THAN OVER EQUAL TO;;;;
+2267;GREATER-THAN OVER EQUAL TO;Sm;0;ON;;;;;Y;GREATER THAN OVER EQUAL TO;;;;
+2268;LESS-THAN BUT NOT EQUAL TO;Sm;0;ON;;;;;Y;LESS THAN BUT NOT EQUAL TO;;;;
+2269;GREATER-THAN BUT NOT EQUAL TO;Sm;0;ON;;;;;Y;GREATER THAN BUT NOT EQUAL TO;;;;
+226A;MUCH LESS-THAN;Sm;0;ON;;;;;Y;MUCH LESS THAN;;;;
+226B;MUCH GREATER-THAN;Sm;0;ON;;;;;Y;MUCH GREATER THAN;;;;
+226C;BETWEEN;Sm;0;ON;;;;;N;;;;;
+226D;NOT EQUIVALENT TO;Sm;0;ON;224D 0338;;;;N;;;;;
+226E;NOT LESS-THAN;Sm;0;ON;003C 0338;;;;Y;NOT LESS THAN;;;;
+226F;NOT GREATER-THAN;Sm;0;ON;003E 0338;;;;Y;NOT GREATER THAN;;;;
+2270;NEITHER LESS-THAN NOR EQUAL TO;Sm;0;ON;2264 0338;;;;Y;NEITHER LESS THAN NOR EQUAL TO;;;;
+2271;NEITHER GREATER-THAN NOR EQUAL TO;Sm;0;ON;2265 0338;;;;Y;NEITHER GREATER THAN NOR EQUAL TO;;;;
+2272;LESS-THAN OR EQUIVALENT TO;Sm;0;ON;;;;;Y;LESS THAN OR EQUIVALENT TO;;;;
+2273;GREATER-THAN OR EQUIVALENT TO;Sm;0;ON;;;;;Y;GREATER THAN OR EQUIVALENT TO;;;;
+2274;NEITHER LESS-THAN NOR EQUIVALENT TO;Sm;0;ON;2272 0338;;;;Y;NEITHER LESS THAN NOR EQUIVALENT TO;;;;
+2275;NEITHER GREATER-THAN NOR EQUIVALENT TO;Sm;0;ON;2273 0338;;;;Y;NEITHER GREATER THAN NOR EQUIVALENT TO;;;;
+2276;LESS-THAN OR GREATER-THAN;Sm;0;ON;;;;;Y;LESS THAN OR GREATER THAN;;;;
+2277;GREATER-THAN OR LESS-THAN;Sm;0;ON;;;;;Y;GREATER THAN OR LESS THAN;;;;
+2278;NEITHER LESS-THAN NOR GREATER-THAN;Sm;0;ON;2276 0338;;;;Y;NEITHER LESS THAN NOR GREATER THAN;;;;
+2279;NEITHER GREATER-THAN NOR LESS-THAN;Sm;0;ON;2277 0338;;;;Y;NEITHER GREATER THAN NOR LESS THAN;;;;
+227A;PRECEDES;Sm;0;ON;;;;;Y;;;;;
+227B;SUCCEEDS;Sm;0;ON;;;;;Y;;;;;
+227C;PRECEDES OR EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+227D;SUCCEEDS OR EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+227E;PRECEDES OR EQUIVALENT TO;Sm;0;ON;;;;;Y;;;;;
+227F;SUCCEEDS OR EQUIVALENT TO;Sm;0;ON;;;;;Y;;;;;
+2280;DOES NOT PRECEDE;Sm;0;ON;227A 0338;;;;Y;;;;;
+2281;DOES NOT SUCCEED;Sm;0;ON;227B 0338;;;;Y;;;;;
+2282;SUBSET OF;Sm;0;ON;;;;;Y;;;;;
+2283;SUPERSET OF;Sm;0;ON;;;;;Y;;;;;
+2284;NOT A SUBSET OF;Sm;0;ON;2282 0338;;;;Y;;;;;
+2285;NOT A SUPERSET OF;Sm;0;ON;2283 0338;;;;Y;;;;;
+2286;SUBSET OF OR EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2287;SUPERSET OF OR EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2288;NEITHER A SUBSET OF NOR EQUAL TO;Sm;0;ON;2286 0338;;;;Y;;;;;
+2289;NEITHER A SUPERSET OF NOR EQUAL TO;Sm;0;ON;2287 0338;;;;Y;;;;;
+228A;SUBSET OF WITH NOT EQUAL TO;Sm;0;ON;;;;;Y;SUBSET OF OR NOT EQUAL TO;;;;
+228B;SUPERSET OF WITH NOT EQUAL TO;Sm;0;ON;;;;;Y;SUPERSET OF OR NOT EQUAL TO;;;;
+228C;MULTISET;Sm;0;ON;;;;;Y;;;;;
+228D;MULTISET MULTIPLICATION;Sm;0;ON;;;;;N;;;;;
+228E;MULTISET UNION;Sm;0;ON;;;;;N;;;;;
+228F;SQUARE IMAGE OF;Sm;0;ON;;;;;Y;;;;;
+2290;SQUARE ORIGINAL OF;Sm;0;ON;;;;;Y;;;;;
+2291;SQUARE IMAGE OF OR EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2292;SQUARE ORIGINAL OF OR EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+2293;SQUARE CAP;Sm;0;ON;;;;;N;;;;;
+2294;SQUARE CUP;Sm;0;ON;;;;;N;;;;;
+2295;CIRCLED PLUS;Sm;0;ON;;;;;N;;;;;
+2296;CIRCLED MINUS;Sm;0;ON;;;;;N;;;;;
+2297;CIRCLED TIMES;Sm;0;ON;;;;;N;;;;;
+2298;CIRCLED DIVISION SLASH;Sm;0;ON;;;;;Y;;;;;
+2299;CIRCLED DOT OPERATOR;Sm;0;ON;;;;;N;;;;;
+229A;CIRCLED RING OPERATOR;Sm;0;ON;;;;;N;;;;;
+229B;CIRCLED ASTERISK OPERATOR;Sm;0;ON;;;;;N;;;;;
+229C;CIRCLED EQUALS;Sm;0;ON;;;;;N;;;;;
+229D;CIRCLED DASH;Sm;0;ON;;;;;N;;;;;
+229E;SQUARED PLUS;Sm;0;ON;;;;;N;;;;;
+229F;SQUARED MINUS;Sm;0;ON;;;;;N;;;;;
+22A0;SQUARED TIMES;Sm;0;ON;;;;;N;;;;;
+22A1;SQUARED DOT OPERATOR;Sm;0;ON;;;;;N;;;;;
+22A2;RIGHT TACK;Sm;0;ON;;;;;Y;;;;;
+22A3;LEFT TACK;Sm;0;ON;;;;;Y;;;;;
+22A4;DOWN TACK;Sm;0;ON;;;;;N;;;;;
+22A5;UP TACK;Sm;0;ON;;;;;N;;;;;
+22A6;ASSERTION;Sm;0;ON;;;;;Y;;;;;
+22A7;MODELS;Sm;0;ON;;;;;Y;;;;;
+22A8;TRUE;Sm;0;ON;;;;;Y;;;;;
+22A9;FORCES;Sm;0;ON;;;;;Y;;;;;
+22AA;TRIPLE VERTICAL BAR RIGHT TURNSTILE;Sm;0;ON;;;;;Y;;;;;
+22AB;DOUBLE VERTICAL BAR DOUBLE RIGHT TURNSTILE;Sm;0;ON;;;;;Y;;;;;
+22AC;DOES NOT PROVE;Sm;0;ON;22A2 0338;;;;Y;;;;;
+22AD;NOT TRUE;Sm;0;ON;22A8 0338;;;;Y;;;;;
+22AE;DOES NOT FORCE;Sm;0;ON;22A9 0338;;;;Y;;;;;
+22AF;NEGATED DOUBLE VERTICAL BAR DOUBLE RIGHT TURNSTILE;Sm;0;ON;22AB 0338;;;;Y;;;;;
+22B0;PRECEDES UNDER RELATION;Sm;0;ON;;;;;Y;;;;;
+22B1;SUCCEEDS UNDER RELATION;Sm;0;ON;;;;;Y;;;;;
+22B2;NORMAL SUBGROUP OF;Sm;0;ON;;;;;Y;;;;;
+22B3;CONTAINS AS NORMAL SUBGROUP;Sm;0;ON;;;;;Y;;;;;
+22B4;NORMAL SUBGROUP OF OR EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+22B5;CONTAINS AS NORMAL SUBGROUP OR EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+22B6;ORIGINAL OF;Sm;0;ON;;;;;Y;;;;;
+22B7;IMAGE OF;Sm;0;ON;;;;;Y;;;;;
+22B8;MULTIMAP;Sm;0;ON;;;;;Y;;;;;
+22B9;HERMITIAN CONJUGATE MATRIX;Sm;0;ON;;;;;N;;;;;
+22BA;INTERCALATE;Sm;0;ON;;;;;N;;;;;
+22BB;XOR;Sm;0;ON;;;;;N;;;;;
+22BC;NAND;Sm;0;ON;;;;;N;;;;;
+22BD;NOR;Sm;0;ON;;;;;N;;;;;
+22BE;RIGHT ANGLE WITH ARC;Sm;0;ON;;;;;Y;;;;;
+22BF;RIGHT TRIANGLE;Sm;0;ON;;;;;Y;;;;;
+22C0;N-ARY LOGICAL AND;Sm;0;ON;;;;;N;;;;;
+22C1;N-ARY LOGICAL OR;Sm;0;ON;;;;;N;;;;;
+22C2;N-ARY INTERSECTION;Sm;0;ON;;;;;N;;;;;
+22C3;N-ARY UNION;Sm;0;ON;;;;;N;;;;;
+22C4;DIAMOND OPERATOR;Sm;0;ON;;;;;N;;;;;
+22C5;DOT OPERATOR;Sm;0;ON;;;;;N;;;;;
+22C6;STAR OPERATOR;Sm;0;ON;;;;;N;;;;;
+22C7;DIVISION TIMES;Sm;0;ON;;;;;N;;;;;
+22C8;BOWTIE;Sm;0;ON;;;;;N;;;;;
+22C9;LEFT NORMAL FACTOR SEMIDIRECT PRODUCT;Sm;0;ON;;;;;Y;;;;;
+22CA;RIGHT NORMAL FACTOR SEMIDIRECT PRODUCT;Sm;0;ON;;;;;Y;;;;;
+22CB;LEFT SEMIDIRECT PRODUCT;Sm;0;ON;;;;;Y;;;;;
+22CC;RIGHT SEMIDIRECT PRODUCT;Sm;0;ON;;;;;Y;;;;;
+22CD;REVERSED TILDE EQUALS;Sm;0;ON;;;;;Y;;;;;
+22CE;CURLY LOGICAL OR;Sm;0;ON;;;;;N;;;;;
+22CF;CURLY LOGICAL AND;Sm;0;ON;;;;;N;;;;;
+22D0;DOUBLE SUBSET;Sm;0;ON;;;;;Y;;;;;
+22D1;DOUBLE SUPERSET;Sm;0;ON;;;;;Y;;;;;
+22D2;DOUBLE INTERSECTION;Sm;0;ON;;;;;N;;;;;
+22D3;DOUBLE UNION;Sm;0;ON;;;;;N;;;;;
+22D4;PITCHFORK;Sm;0;ON;;;;;N;;;;;
+22D5;EQUAL AND PARALLEL TO;Sm;0;ON;;;;;N;;;;;
+22D6;LESS-THAN WITH DOT;Sm;0;ON;;;;;Y;LESS THAN WITH DOT;;;;
+22D7;GREATER-THAN WITH DOT;Sm;0;ON;;;;;Y;GREATER THAN WITH DOT;;;;
+22D8;VERY MUCH LESS-THAN;Sm;0;ON;;;;;Y;VERY MUCH LESS THAN;;;;
+22D9;VERY MUCH GREATER-THAN;Sm;0;ON;;;;;Y;VERY MUCH GREATER THAN;;;;
+22DA;LESS-THAN EQUAL TO OR GREATER-THAN;Sm;0;ON;;;;;Y;LESS THAN EQUAL TO OR GREATER THAN;;;;
+22DB;GREATER-THAN EQUAL TO OR LESS-THAN;Sm;0;ON;;;;;Y;GREATER THAN EQUAL TO OR LESS THAN;;;;
+22DC;EQUAL TO OR LESS-THAN;Sm;0;ON;;;;;Y;EQUAL TO OR LESS THAN;;;;
+22DD;EQUAL TO OR GREATER-THAN;Sm;0;ON;;;;;Y;EQUAL TO OR GREATER THAN;;;;
+22DE;EQUAL TO OR PRECEDES;Sm;0;ON;;;;;Y;;;;;
+22DF;EQUAL TO OR SUCCEEDS;Sm;0;ON;;;;;Y;;;;;
+22E0;DOES NOT PRECEDE OR EQUAL;Sm;0;ON;227C 0338;;;;Y;;;;;
+22E1;DOES NOT SUCCEED OR EQUAL;Sm;0;ON;227D 0338;;;;Y;;;;;
+22E2;NOT SQUARE IMAGE OF OR EQUAL TO;Sm;0;ON;2291 0338;;;;Y;;;;;
+22E3;NOT SQUARE ORIGINAL OF OR EQUAL TO;Sm;0;ON;2292 0338;;;;Y;;;;;
+22E4;SQUARE IMAGE OF OR NOT EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+22E5;SQUARE ORIGINAL OF OR NOT EQUAL TO;Sm;0;ON;;;;;Y;;;;;
+22E6;LESS-THAN BUT NOT EQUIVALENT TO;Sm;0;ON;;;;;Y;LESS THAN BUT NOT EQUIVALENT TO;;;;
+22E7;GREATER-THAN BUT NOT EQUIVALENT TO;Sm;0;ON;;;;;Y;GREATER THAN BUT NOT EQUIVALENT TO;;;;
+22E8;PRECEDES BUT NOT EQUIVALENT TO;Sm;0;ON;;;;;Y;;;;;
+22E9;SUCCEEDS BUT NOT EQUIVALENT TO;Sm;0;ON;;;;;Y;;;;;
+22EA;NOT NORMAL SUBGROUP OF;Sm;0;ON;22B2 0338;;;;Y;;;;;
+22EB;DOES NOT CONTAIN AS NORMAL SUBGROUP;Sm;0;ON;22B3 0338;;;;Y;;;;;
+22EC;NOT NORMAL SUBGROUP OF OR EQUAL TO;Sm;0;ON;22B4 0338;;;;Y;;;;;
+22ED;DOES NOT CONTAIN AS NORMAL SUBGROUP OR EQUAL;Sm;0;ON;22B5 0338;;;;Y;;;;;
+22EE;VERTICAL ELLIPSIS;Sm;0;ON;;;;;N;;;;;
+22EF;MIDLINE HORIZONTAL ELLIPSIS;Sm;0;ON;;;;;N;;;;;
+22F0;UP RIGHT DIAGONAL ELLIPSIS;Sm;0;ON;;;;;Y;;;;;
+22F1;DOWN RIGHT DIAGONAL ELLIPSIS;Sm;0;ON;;;;;Y;;;;;
+2300;DIAMETER SIGN;So;0;ON;;;;;N;;;;;
+2301;ELECTRIC ARROW;So;0;ON;;;;;N;;;;;
+2302;HOUSE;So;0;ON;;;;;N;;;;;
+2303;UP ARROWHEAD;So;0;ON;;;;;N;;;;;
+2304;DOWN ARROWHEAD;So;0;ON;;;;;N;;;;;
+2305;PROJECTIVE;So;0;ON;;;;;N;;;;;
+2306;PERSPECTIVE;So;0;ON;;;;;N;;;;;
+2307;WAVY LINE;So;0;ON;;;;;N;;;;;
+2308;LEFT CEILING;Sm;0;ON;;;;;Y;;;;;
+2309;RIGHT CEILING;Sm;0;ON;;;;;Y;;;;;
+230A;LEFT FLOOR;Sm;0;ON;;;;;Y;;;;;
+230B;RIGHT FLOOR;Sm;0;ON;;;;;Y;;;;;
+230C;BOTTOM RIGHT CROP;So;0;ON;;;;;N;;;;;
+230D;BOTTOM LEFT CROP;So;0;ON;;;;;N;;;;;
+230E;TOP RIGHT CROP;So;0;ON;;;;;N;;;;;
+230F;TOP LEFT CROP;So;0;ON;;;;;N;;;;;
+2310;REVERSED NOT SIGN;So;0;ON;;;;;N;;;;;
+2311;SQUARE LOZENGE;So;0;ON;;;;;N;;;;;
+2312;ARC;So;0;ON;;;;;N;;;;;
+2313;SEGMENT;So;0;ON;;;;;N;;;;;
+2314;SECTOR;So;0;ON;;;;;N;;;;;
+2315;TELEPHONE RECORDER;So;0;ON;;;;;N;;;;;
+2316;POSITION INDICATOR;So;0;ON;;;;;N;;;;;
+2317;VIEWDATA SQUARE;So;0;ON;;;;;N;;;;;
+2318;PLACE OF INTEREST SIGN;So;0;ON;;;;;N;COMMAND KEY;;;;
+2319;TURNED NOT SIGN;So;0;ON;;;;;N;;;;;
+231A;WATCH;So;0;ON;;;;;N;;;;;
+231B;HOURGLASS;So;0;ON;;;;;N;;;;;
+231C;TOP LEFT CORNER;So;0;ON;;;;;N;;;;;
+231D;TOP RIGHT CORNER;So;0;ON;;;;;N;;;;;
+231E;BOTTOM LEFT CORNER;So;0;ON;;;;;N;;;;;
+231F;BOTTOM RIGHT CORNER;So;0;ON;;;;;N;;;;;
+2320;TOP HALF INTEGRAL;Sm;0;ON;;;;;Y;;;;;
+2321;BOTTOM HALF INTEGRAL;Sm;0;ON;;;;;Y;;;;;
+2322;FROWN;So;0;ON;;;;;N;;;;;
+2323;SMILE;So;0;ON;;;;;N;;;;;
+2324;UP ARROWHEAD BETWEEN TWO HORIZONTAL BARS;So;0;ON;;;;;N;ENTER KEY;;;;
+2325;OPTION KEY;So;0;ON;;;;;N;;;;;
+2326;ERASE TO THE RIGHT;So;0;ON;;;;;N;DELETE TO THE RIGHT KEY;;;;
+2327;X IN A RECTANGLE BOX;So;0;ON;;;;;N;CLEAR KEY;;;;
+2328;KEYBOARD;So;0;ON;;;;;N;;;;;
+2329;LEFT-POINTING ANGLE BRACKET;Ps;0;ON;3008;;;;Y;BRA;;;;
+232A;RIGHT-POINTING ANGLE BRACKET;Pe;0;ON;3009;;;;Y;KET;;;;
+232B;ERASE TO THE LEFT;So;0;ON;;;;;N;DELETE TO THE LEFT KEY;;;;
+232C;BENZENE RING;So;0;ON;;;;;N;;;;;
+232D;CYLINDRICITY;So;0;ON;;;;;N;;;;;
+232E;ALL AROUND-PROFILE;So;0;ON;;;;;N;;;;;
+232F;SYMMETRY;So;0;ON;;;;;N;;;;;
+2330;TOTAL RUNOUT;So;0;ON;;;;;N;;;;;
+2331;DIMENSION ORIGIN;So;0;ON;;;;;N;;;;;
+2332;CONICAL TAPER;So;0;ON;;;;;N;;;;;
+2333;SLOPE;So;0;ON;;;;;N;;;;;
+2334;COUNTERBORE;So;0;ON;;;;;N;;;;;
+2335;COUNTERSINK;So;0;ON;;;;;N;;;;;
+2336;APL FUNCTIONAL SYMBOL I-BEAM;So;0;L;;;;;N;;;;;
+2337;APL FUNCTIONAL SYMBOL SQUISH QUAD;So;0;L;;;;;N;;;;;
+2338;APL FUNCTIONAL SYMBOL QUAD EQUAL;So;0;L;;;;;N;;;;;
+2339;APL FUNCTIONAL SYMBOL QUAD DIVIDE;So;0;L;;;;;N;;;;;
+233A;APL FUNCTIONAL SYMBOL QUAD DIAMOND;So;0;L;;;;;N;;;;;
+233B;APL FUNCTIONAL SYMBOL QUAD JOT;So;0;L;;;;;N;;;;;
+233C;APL FUNCTIONAL SYMBOL QUAD CIRCLE;So;0;L;;;;;N;;;;;
+233D;APL FUNCTIONAL SYMBOL CIRCLE STILE;So;0;L;;;;;N;;;;;
+233E;APL FUNCTIONAL SYMBOL CIRCLE JOT;So;0;L;;;;;N;;;;;
+233F;APL FUNCTIONAL SYMBOL SLASH BAR;So;0;L;;;;;N;;;;;
+2340;APL FUNCTIONAL SYMBOL BACKSLASH BAR;So;0;L;;;;;N;;;;;
+2341;APL FUNCTIONAL SYMBOL QUAD SLASH;So;0;L;;;;;N;;;;;
+2342;APL FUNCTIONAL SYMBOL QUAD BACKSLASH;So;0;L;;;;;N;;;;;
+2343;APL FUNCTIONAL SYMBOL QUAD LESS-THAN;So;0;L;;;;;N;;;;;
+2344;APL FUNCTIONAL SYMBOL QUAD GREATER-THAN;So;0;L;;;;;N;;;;;
+2345;APL FUNCTIONAL SYMBOL LEFTWARDS VANE;So;0;L;;;;;N;;;;;
+2346;APL FUNCTIONAL SYMBOL RIGHTWARDS VANE;So;0;L;;;;;N;;;;;
+2347;APL FUNCTIONAL SYMBOL QUAD LEFTWARDS ARROW;So;0;L;;;;;N;;;;;
+2348;APL FUNCTIONAL SYMBOL QUAD RIGHTWARDS ARROW;So;0;L;;;;;N;;;;;
+2349;APL FUNCTIONAL SYMBOL CIRCLE BACKSLASH;So;0;L;;;;;N;;;;;
+234A;APL FUNCTIONAL SYMBOL DOWN TACK UNDERBAR;So;0;L;;;;;N;;*;;;
+234B;APL FUNCTIONAL SYMBOL DELTA STILE;So;0;L;;;;;N;;;;;
+234C;APL FUNCTIONAL SYMBOL QUAD DOWN CARET;So;0;L;;;;;N;;;;;
+234D;APL FUNCTIONAL SYMBOL QUAD DELTA;So;0;L;;;;;N;;;;;
+234E;APL FUNCTIONAL SYMBOL DOWN TACK JOT;So;0;L;;;;;N;;*;;;
+234F;APL FUNCTIONAL SYMBOL UPWARDS VANE;So;0;L;;;;;N;;;;;
+2350;APL FUNCTIONAL SYMBOL QUAD UPWARDS ARROW;So;0;L;;;;;N;;;;;
+2351;APL FUNCTIONAL SYMBOL UP TACK OVERBAR;So;0;L;;;;;N;;*;;;
+2352;APL FUNCTIONAL SYMBOL DEL STILE;So;0;L;;;;;N;;;;;
+2353;APL FUNCTIONAL SYMBOL QUAD UP CARET;So;0;L;;;;;N;;;;;
+2354;APL FUNCTIONAL SYMBOL QUAD DEL;So;0;L;;;;;N;;;;;
+2355;APL FUNCTIONAL SYMBOL UP TACK JOT;So;0;L;;;;;N;;*;;;
+2356;APL FUNCTIONAL SYMBOL DOWNWARDS VANE;So;0;L;;;;;N;;;;;
+2357;APL FUNCTIONAL SYMBOL QUAD DOWNWARDS ARROW;So;0;L;;;;;N;;;;;
+2358;APL FUNCTIONAL SYMBOL QUOTE UNDERBAR;So;0;L;;;;;N;;;;;
+2359;APL FUNCTIONAL SYMBOL DELTA UNDERBAR;So;0;L;;;;;N;;;;;
+235A;APL FUNCTIONAL SYMBOL DIAMOND UNDERBAR;So;0;L;;;;;N;;;;;
+235B;APL FUNCTIONAL SYMBOL JOT UNDERBAR;So;0;L;;;;;N;;;;;
+235C;APL FUNCTIONAL SYMBOL CIRCLE UNDERBAR;So;0;L;;;;;N;;;;;
+235D;APL FUNCTIONAL SYMBOL UP SHOE JOT;So;0;L;;;;;N;;;;;
+235E;APL FUNCTIONAL SYMBOL QUOTE QUAD;So;0;L;;;;;N;;;;;
+235F;APL FUNCTIONAL SYMBOL CIRCLE STAR;So;0;L;;;;;N;;;;;
+2360;APL FUNCTIONAL SYMBOL QUAD COLON;So;0;L;;;;;N;;;;;
+2361;APL FUNCTIONAL SYMBOL UP TACK DIAERESIS;So;0;L;;;;;N;;*;;;
+2362;APL FUNCTIONAL SYMBOL DEL DIAERESIS;So;0;L;;;;;N;;;;;
+2363;APL FUNCTIONAL SYMBOL STAR DIAERESIS;So;0;L;;;;;N;;;;;
+2364;APL FUNCTIONAL SYMBOL JOT DIAERESIS;So;0;L;;;;;N;;;;;
+2365;APL FUNCTIONAL SYMBOL CIRCLE DIAERESIS;So;0;L;;;;;N;;;;;
+2366;APL FUNCTIONAL SYMBOL DOWN SHOE STILE;So;0;L;;;;;N;;;;;
+2367;APL FUNCTIONAL SYMBOL LEFT SHOE STILE;So;0;L;;;;;N;;;;;
+2368;APL FUNCTIONAL SYMBOL TILDE DIAERESIS;So;0;L;;;;;N;;;;;
+2369;APL FUNCTIONAL SYMBOL GREATER-THAN DIAERESIS;So;0;L;;;;;N;;;;;
+236A;APL FUNCTIONAL SYMBOL COMMA BAR;So;0;L;;;;;N;;;;;
+236B;APL FUNCTIONAL SYMBOL DEL TILDE;So;0;L;;;;;N;;;;;
+236C;APL FUNCTIONAL SYMBOL ZILDE;So;0;L;;;;;N;;;;;
+236D;APL FUNCTIONAL SYMBOL STILE TILDE;So;0;L;;;;;N;;;;;
+236E;APL FUNCTIONAL SYMBOL SEMICOLON UNDERBAR;So;0;L;;;;;N;;;;;
+236F;APL FUNCTIONAL SYMBOL QUAD NOT EQUAL;So;0;L;;;;;N;;;;;
+2370;APL FUNCTIONAL SYMBOL QUAD QUESTION;So;0;L;;;;;N;;;;;
+2371;APL FUNCTIONAL SYMBOL DOWN CARET TILDE;So;0;L;;;;;N;;;;;
+2372;APL FUNCTIONAL SYMBOL UP CARET TILDE;So;0;L;;;;;N;;;;;
+2373;APL FUNCTIONAL SYMBOL IOTA;So;0;L;;;;;N;;;;;
+2374;APL FUNCTIONAL SYMBOL RHO;So;0;L;;;;;N;;;;;
+2375;APL FUNCTIONAL SYMBOL OMEGA;So;0;L;;;;;N;;;;;
+2376;APL FUNCTIONAL SYMBOL ALPHA UNDERBAR;So;0;L;;;;;N;;;;;
+2377;APL FUNCTIONAL SYMBOL EPSILON UNDERBAR;So;0;L;;;;;N;;;;;
+2378;APL FUNCTIONAL SYMBOL IOTA UNDERBAR;So;0;L;;;;;N;;;;;
+2379;APL FUNCTIONAL SYMBOL OMEGA UNDERBAR;So;0;L;;;;;N;;;;;
+237A;APL FUNCTIONAL SYMBOL ALPHA;So;0;L;;;;;N;;;;;
+237B;NOT CHECK MARK;So;0;ON;;;;;N;;;;;
+237D;SHOULDERED OPEN BOX;So;0;ON;;;;;N;;;;;
+237E;BELL SYMBOL;So;0;ON;;;;;N;;;;;
+237F;VERTICAL LINE WITH MIDDLE DOT;So;0;ON;;;;;N;;;;;
+2380;INSERTION SYMBOL;So;0;ON;;;;;N;;;;;
+2381;CONTINUOUS UNDERLINE SYMBOL;So;0;ON;;;;;N;;;;;
+2382;DISCONTINUOUS UNDERLINE SYMBOL;So;0;ON;;;;;N;;;;;
+2383;EMPHASIS SYMBOL;So;0;ON;;;;;N;;;;;
+2384;COMPOSITION SYMBOL;So;0;ON;;;;;N;;;;;
+2385;WHITE SQUARE WITH CENTRE VERTICAL LINE;So;0;ON;;;;;N;;;;;
+2386;ENTER SYMBOL;So;0;ON;;;;;N;;;;;
+2387;ALTERNATIVE KEY SYMBOL;So;0;ON;;;;;N;;;;;
+2388;HELM SYMBOL;So;0;ON;;;;;N;;;;;
+2389;CIRCLED HORIZONTAL BAR WITH NOTCH;So;0;ON;;;;;N;;pause;;;
+238A;CIRCLED TRIANGLE DOWN;So;0;ON;;;;;N;;break;;;
+238B;BROKEN CIRCLE WITH NORTHWEST ARROW;So;0;ON;;;;;N;;escape;;;
+238C;UNDO SYMBOL;So;0;ON;;;;;N;;;;;
+238D;MONOSTABLE SYMBOL;So;0;ON;;;;;N;;;;;
+238E;HYSTERESIS SYMBOL;So;0;ON;;;;;N;;;;;
+238F;OPEN-CIRCUIT-OUTPUT H-TYPE SYMBOL;So;0;ON;;;;;N;;;;;
+2390;OPEN-CIRCUIT-OUTPUT L-TYPE SYMBOL;So;0;ON;;;;;N;;;;;
+2391;PASSIVE-PULL-DOWN-OUTPUT SYMBOL;So;0;ON;;;;;N;;;;;
+2392;PASSIVE-PULL-UP-OUTPUT SYMBOL;So;0;ON;;;;;N;;;;;
+2393;DIRECT CURRENT SYMBOL FORM TWO;So;0;ON;;;;;N;;;;;
+2394;SOFTWARE-FUNCTION SYMBOL;So;0;ON;;;;;N;;;;;
+2395;APL FUNCTIONAL SYMBOL QUAD;So;0;L;;;;;N;;;;;
+2396;DECIMAL SEPARATOR KEY SYMBOL;So;0;ON;;;;;N;;;;;
+2397;PREVIOUS PAGE;So;0;ON;;;;;N;;;;;
+2398;NEXT PAGE;So;0;ON;;;;;N;;;;;
+2399;PRINT SCREEN SYMBOL;So;0;ON;;;;;N;;;;;
+239A;CLEAR SCREEN SYMBOL;So;0;ON;;;;;N;;;;;
+2400;SYMBOL FOR NULL;So;0;ON;;;;;N;GRAPHIC FOR NULL;;;;
+2401;SYMBOL FOR START OF HEADING;So;0;ON;;;;;N;GRAPHIC FOR START OF HEADING;;;;
+2402;SYMBOL FOR START OF TEXT;So;0;ON;;;;;N;GRAPHIC FOR START OF TEXT;;;;
+2403;SYMBOL FOR END OF TEXT;So;0;ON;;;;;N;GRAPHIC FOR END OF TEXT;;;;
+2404;SYMBOL FOR END OF TRANSMISSION;So;0;ON;;;;;N;GRAPHIC FOR END OF TRANSMISSION;;;;
+2405;SYMBOL FOR ENQUIRY;So;0;ON;;;;;N;GRAPHIC FOR ENQUIRY;;;;
+2406;SYMBOL FOR ACKNOWLEDGE;So;0;ON;;;;;N;GRAPHIC FOR ACKNOWLEDGE;;;;
+2407;SYMBOL FOR BELL;So;0;ON;;;;;N;GRAPHIC FOR BELL;;;;
+2408;SYMBOL FOR BACKSPACE;So;0;ON;;;;;N;GRAPHIC FOR BACKSPACE;;;;
+2409;SYMBOL FOR HORIZONTAL TABULATION;So;0;ON;;;;;N;GRAPHIC FOR HORIZONTAL TABULATION;;;;
+240A;SYMBOL FOR LINE FEED;So;0;ON;;;;;N;GRAPHIC FOR LINE FEED;;;;
+240B;SYMBOL FOR VERTICAL TABULATION;So;0;ON;;;;;N;GRAPHIC FOR VERTICAL TABULATION;;;;
+240C;SYMBOL FOR FORM FEED;So;0;ON;;;;;N;GRAPHIC FOR FORM FEED;;;;
+240D;SYMBOL FOR CARRIAGE RETURN;So;0;ON;;;;;N;GRAPHIC FOR CARRIAGE RETURN;;;;
+240E;SYMBOL FOR SHIFT OUT;So;0;ON;;;;;N;GRAPHIC FOR SHIFT OUT;;;;
+240F;SYMBOL FOR SHIFT IN;So;0;ON;;;;;N;GRAPHIC FOR SHIFT IN;;;;
+2410;SYMBOL FOR DATA LINK ESCAPE;So;0;ON;;;;;N;GRAPHIC FOR DATA LINK ESCAPE;;;;
+2411;SYMBOL FOR DEVICE CONTROL ONE;So;0;ON;;;;;N;GRAPHIC FOR DEVICE CONTROL ONE;;;;
+2412;SYMBOL FOR DEVICE CONTROL TWO;So;0;ON;;;;;N;GRAPHIC FOR DEVICE CONTROL TWO;;;;
+2413;SYMBOL FOR DEVICE CONTROL THREE;So;0;ON;;;;;N;GRAPHIC FOR DEVICE CONTROL THREE;;;;
+2414;SYMBOL FOR DEVICE CONTROL FOUR;So;0;ON;;;;;N;GRAPHIC FOR DEVICE CONTROL FOUR;;;;
+2415;SYMBOL FOR NEGATIVE ACKNOWLEDGE;So;0;ON;;;;;N;GRAPHIC FOR NEGATIVE ACKNOWLEDGE;;;;
+2416;SYMBOL FOR SYNCHRONOUS IDLE;So;0;ON;;;;;N;GRAPHIC FOR SYNCHRONOUS IDLE;;;;
+2417;SYMBOL FOR END OF TRANSMISSION BLOCK;So;0;ON;;;;;N;GRAPHIC FOR END OF TRANSMISSION BLOCK;;;;
+2418;SYMBOL FOR CANCEL;So;0;ON;;;;;N;GRAPHIC FOR CANCEL;;;;
+2419;SYMBOL FOR END OF MEDIUM;So;0;ON;;;;;N;GRAPHIC FOR END OF MEDIUM;;;;
+241A;SYMBOL FOR SUBSTITUTE;So;0;ON;;;;;N;GRAPHIC FOR SUBSTITUTE;;;;
+241B;SYMBOL FOR ESCAPE;So;0;ON;;;;;N;GRAPHIC FOR ESCAPE;;;;
+241C;SYMBOL FOR FILE SEPARATOR;So;0;ON;;;;;N;GRAPHIC FOR FILE SEPARATOR;;;;
+241D;SYMBOL FOR GROUP SEPARATOR;So;0;ON;;;;;N;GRAPHIC FOR GROUP SEPARATOR;;;;
+241E;SYMBOL FOR RECORD SEPARATOR;So;0;ON;;;;;N;GRAPHIC FOR RECORD SEPARATOR;;;;
+241F;SYMBOL FOR UNIT SEPARATOR;So;0;ON;;;;;N;GRAPHIC FOR UNIT SEPARATOR;;;;
+2420;SYMBOL FOR SPACE;So;0;ON;;;;;N;GRAPHIC FOR SPACE;;;;
+2421;SYMBOL FOR DELETE;So;0;ON;;;;;N;GRAPHIC FOR DELETE;;;;
+2422;BLANK SYMBOL;So;0;ON;;;;;N;BLANK;;;;
+2423;OPEN BOX;So;0;ON;;;;;N;;;;;
+2424;SYMBOL FOR NEWLINE;So;0;ON;;;;;N;GRAPHIC FOR NEWLINE;;;;
+2425;SYMBOL FOR DELETE FORM TWO;So;0;ON;;;;;N;;;;;
+2426;SYMBOL FOR SUBSTITUTE FORM TWO;So;0;ON;;;;;N;;;;;
+2440;OCR HOOK;So;0;ON;;;;;N;;;;;
+2441;OCR CHAIR;So;0;ON;;;;;N;;;;;
+2442;OCR FORK;So;0;ON;;;;;N;;;;;
+2443;OCR INVERTED FORK;So;0;ON;;;;;N;;;;;
+2444;OCR BELT BUCKLE;So;0;ON;;;;;N;;;;;
+2445;OCR BOW TIE;So;0;ON;;;;;N;;;;;
+2446;OCR BRANCH BANK IDENTIFICATION;So;0;ON;;;;;N;;;;;
+2447;OCR AMOUNT OF CHECK;So;0;ON;;;;;N;;;;;
+2448;OCR DASH;So;0;ON;;;;;N;;;;;
+2449;OCR CUSTOMER ACCOUNT NUMBER;So;0;ON;;;;;N;;;;;
+244A;OCR DOUBLE BACKSLASH;So;0;ON;;;;;N;;;;;
+2460;CIRCLED DIGIT ONE;No;0;EN;<circle> 0031;;1;1;N;;;;;
+2461;CIRCLED DIGIT TWO;No;0;EN;<circle> 0032;;2;2;N;;;;;
+2462;CIRCLED DIGIT THREE;No;0;EN;<circle> 0033;;3;3;N;;;;;
+2463;CIRCLED DIGIT FOUR;No;0;EN;<circle> 0034;;4;4;N;;;;;
+2464;CIRCLED DIGIT FIVE;No;0;EN;<circle> 0035;;5;5;N;;;;;
+2465;CIRCLED DIGIT SIX;No;0;EN;<circle> 0036;;6;6;N;;;;;
+2466;CIRCLED DIGIT SEVEN;No;0;EN;<circle> 0037;;7;7;N;;;;;
+2467;CIRCLED DIGIT EIGHT;No;0;EN;<circle> 0038;;8;8;N;;;;;
+2468;CIRCLED DIGIT NINE;No;0;EN;<circle> 0039;;9;9;N;;;;;
+2469;CIRCLED NUMBER TEN;No;0;EN;<circle> 0031 0030;;;10;N;;;;;
+246A;CIRCLED NUMBER ELEVEN;No;0;EN;<circle> 0031 0031;;;11;N;;;;;
+246B;CIRCLED NUMBER TWELVE;No;0;EN;<circle> 0031 0032;;;12;N;;;;;
+246C;CIRCLED NUMBER THIRTEEN;No;0;EN;<circle> 0031 0033;;;13;N;;;;;
+246D;CIRCLED NUMBER FOURTEEN;No;0;EN;<circle> 0031 0034;;;14;N;;;;;
+246E;CIRCLED NUMBER FIFTEEN;No;0;EN;<circle> 0031 0035;;;15;N;;;;;
+246F;CIRCLED NUMBER SIXTEEN;No;0;EN;<circle> 0031 0036;;;16;N;;;;;
+2470;CIRCLED NUMBER SEVENTEEN;No;0;EN;<circle> 0031 0037;;;17;N;;;;;
+2471;CIRCLED NUMBER EIGHTEEN;No;0;EN;<circle> 0031 0038;;;18;N;;;;;
+2472;CIRCLED NUMBER NINETEEN;No;0;EN;<circle> 0031 0039;;;19;N;;;;;
+2473;CIRCLED NUMBER TWENTY;No;0;EN;<circle> 0032 0030;;;20;N;;;;;
+2474;PARENTHESIZED DIGIT ONE;No;0;EN;<compat> 0028 0031 0029;;1;1;N;;;;;
+2475;PARENTHESIZED DIGIT TWO;No;0;EN;<compat> 0028 0032 0029;;2;2;N;;;;;
+2476;PARENTHESIZED DIGIT THREE;No;0;EN;<compat> 0028 0033 0029;;3;3;N;;;;;
+2477;PARENTHESIZED DIGIT FOUR;No;0;EN;<compat> 0028 0034 0029;;4;4;N;;;;;
+2478;PARENTHESIZED DIGIT FIVE;No;0;EN;<compat> 0028 0035 0029;;5;5;N;;;;;
+2479;PARENTHESIZED DIGIT SIX;No;0;EN;<compat> 0028 0036 0029;;6;6;N;;;;;
+247A;PARENTHESIZED DIGIT SEVEN;No;0;EN;<compat> 0028 0037 0029;;7;7;N;;;;;
+247B;PARENTHESIZED DIGIT EIGHT;No;0;EN;<compat> 0028 0038 0029;;8;8;N;;;;;
+247C;PARENTHESIZED DIGIT NINE;No;0;EN;<compat> 0028 0039 0029;;9;9;N;;;;;
+247D;PARENTHESIZED NUMBER TEN;No;0;EN;<compat> 0028 0031 0030 0029;;;10;N;;;;;
+247E;PARENTHESIZED NUMBER ELEVEN;No;0;EN;<compat> 0028 0031 0031 0029;;;11;N;;;;;
+247F;PARENTHESIZED NUMBER TWELVE;No;0;EN;<compat> 0028 0031 0032 0029;;;12;N;;;;;
+2480;PARENTHESIZED NUMBER THIRTEEN;No;0;EN;<compat> 0028 0031 0033 0029;;;13;N;;;;;
+2481;PARENTHESIZED NUMBER FOURTEEN;No;0;EN;<compat> 0028 0031 0034 0029;;;14;N;;;;;
+2482;PARENTHESIZED NUMBER FIFTEEN;No;0;EN;<compat> 0028 0031 0035 0029;;;15;N;;;;;
+2483;PARENTHESIZED NUMBER SIXTEEN;No;0;EN;<compat> 0028 0031 0036 0029;;;16;N;;;;;
+2484;PARENTHESIZED NUMBER SEVENTEEN;No;0;EN;<compat> 0028 0031 0037 0029;;;17;N;;;;;
+2485;PARENTHESIZED NUMBER EIGHTEEN;No;0;EN;<compat> 0028 0031 0038 0029;;;18;N;;;;;
+2486;PARENTHESIZED NUMBER NINETEEN;No;0;EN;<compat> 0028 0031 0039 0029;;;19;N;;;;;
+2487;PARENTHESIZED NUMBER TWENTY;No;0;EN;<compat> 0028 0032 0030 0029;;;20;N;;;;;
+2488;DIGIT ONE FULL STOP;No;0;EN;<compat> 0031 002E;;1;1;N;DIGIT ONE PERIOD;;;;
+2489;DIGIT TWO FULL STOP;No;0;EN;<compat> 0032 002E;;2;2;N;DIGIT TWO PERIOD;;;;
+248A;DIGIT THREE FULL STOP;No;0;EN;<compat> 0033 002E;;3;3;N;DIGIT THREE PERIOD;;;;
+248B;DIGIT FOUR FULL STOP;No;0;EN;<compat> 0034 002E;;4;4;N;DIGIT FOUR PERIOD;;;;
+248C;DIGIT FIVE FULL STOP;No;0;EN;<compat> 0035 002E;;5;5;N;DIGIT FIVE PERIOD;;;;
+248D;DIGIT SIX FULL STOP;No;0;EN;<compat> 0036 002E;;6;6;N;DIGIT SIX PERIOD;;;;
+248E;DIGIT SEVEN FULL STOP;No;0;EN;<compat> 0037 002E;;7;7;N;DIGIT SEVEN PERIOD;;;;
+248F;DIGIT EIGHT FULL STOP;No;0;EN;<compat> 0038 002E;;8;8;N;DIGIT EIGHT PERIOD;;;;
+2490;DIGIT NINE FULL STOP;No;0;EN;<compat> 0039 002E;;9;9;N;DIGIT NINE PERIOD;;;;
+2491;NUMBER TEN FULL STOP;No;0;EN;<compat> 0031 0030 002E;;;10;N;NUMBER TEN PERIOD;;;;
+2492;NUMBER ELEVEN FULL STOP;No;0;EN;<compat> 0031 0031 002E;;;11;N;NUMBER ELEVEN PERIOD;;;;
+2493;NUMBER TWELVE FULL STOP;No;0;EN;<compat> 0031 0032 002E;;;12;N;NUMBER TWELVE PERIOD;;;;
+2494;NUMBER THIRTEEN FULL STOP;No;0;EN;<compat> 0031 0033 002E;;;13;N;NUMBER THIRTEEN PERIOD;;;;
+2495;NUMBER FOURTEEN FULL STOP;No;0;EN;<compat> 0031 0034 002E;;;14;N;NUMBER FOURTEEN PERIOD;;;;
+2496;NUMBER FIFTEEN FULL STOP;No;0;EN;<compat> 0031 0035 002E;;;15;N;NUMBER FIFTEEN PERIOD;;;;
+2497;NUMBER SIXTEEN FULL STOP;No;0;EN;<compat> 0031 0036 002E;;;16;N;NUMBER SIXTEEN PERIOD;;;;
+2498;NUMBER SEVENTEEN FULL STOP;No;0;EN;<compat> 0031 0037 002E;;;17;N;NUMBER SEVENTEEN PERIOD;;;;
+2499;NUMBER EIGHTEEN FULL STOP;No;0;EN;<compat> 0031 0038 002E;;;18;N;NUMBER EIGHTEEN PERIOD;;;;
+249A;NUMBER NINETEEN FULL STOP;No;0;EN;<compat> 0031 0039 002E;;;19;N;NUMBER NINETEEN PERIOD;;;;
+249B;NUMBER TWENTY FULL STOP;No;0;EN;<compat> 0032 0030 002E;;;20;N;NUMBER TWENTY PERIOD;;;;
+249C;PARENTHESIZED LATIN SMALL LETTER A;So;0;L;<compat> 0028 0061 0029;;;;N;;;;;
+249D;PARENTHESIZED LATIN SMALL LETTER B;So;0;L;<compat> 0028 0062 0029;;;;N;;;;;
+249E;PARENTHESIZED LATIN SMALL LETTER C;So;0;L;<compat> 0028 0063 0029;;;;N;;;;;
+249F;PARENTHESIZED LATIN SMALL LETTER D;So;0;L;<compat> 0028 0064 0029;;;;N;;;;;
+24A0;PARENTHESIZED LATIN SMALL LETTER E;So;0;L;<compat> 0028 0065 0029;;;;N;;;;;
+24A1;PARENTHESIZED LATIN SMALL LETTER F;So;0;L;<compat> 0028 0066 0029;;;;N;;;;;
+24A2;PARENTHESIZED LATIN SMALL LETTER G;So;0;L;<compat> 0028 0067 0029;;;;N;;;;;
+24A3;PARENTHESIZED LATIN SMALL LETTER H;So;0;L;<compat> 0028 0068 0029;;;;N;;;;;
+24A4;PARENTHESIZED LATIN SMALL LETTER I;So;0;L;<compat> 0028 0069 0029;;;;N;;;;;
+24A5;PARENTHESIZED LATIN SMALL LETTER J;So;0;L;<compat> 0028 006A 0029;;;;N;;;;;
+24A6;PARENTHESIZED LATIN SMALL LETTER K;So;0;L;<compat> 0028 006B 0029;;;;N;;;;;
+24A7;PARENTHESIZED LATIN SMALL LETTER L;So;0;L;<compat> 0028 006C 0029;;;;N;;;;;
+24A8;PARENTHESIZED LATIN SMALL LETTER M;So;0;L;<compat> 0028 006D 0029;;;;N;;;;;
+24A9;PARENTHESIZED LATIN SMALL LETTER N;So;0;L;<compat> 0028 006E 0029;;;;N;;;;;
+24AA;PARENTHESIZED LATIN SMALL LETTER O;So;0;L;<compat> 0028 006F 0029;;;;N;;;;;
+24AB;PARENTHESIZED LATIN SMALL LETTER P;So;0;L;<compat> 0028 0070 0029;;;;N;;;;;
+24AC;PARENTHESIZED LATIN SMALL LETTER Q;So;0;L;<compat> 0028 0071 0029;;;;N;;;;;
+24AD;PARENTHESIZED LATIN SMALL LETTER R;So;0;L;<compat> 0028 0072 0029;;;;N;;;;;
+24AE;PARENTHESIZED LATIN SMALL LETTER S;So;0;L;<compat> 0028 0073 0029;;;;N;;;;;
+24AF;PARENTHESIZED LATIN SMALL LETTER T;So;0;L;<compat> 0028 0074 0029;;;;N;;;;;
+24B0;PARENTHESIZED LATIN SMALL LETTER U;So;0;L;<compat> 0028 0075 0029;;;;N;;;;;
+24B1;PARENTHESIZED LATIN SMALL LETTER V;So;0;L;<compat> 0028 0076 0029;;;;N;;;;;
+24B2;PARENTHESIZED LATIN SMALL LETTER W;So;0;L;<compat> 0028 0077 0029;;;;N;;;;;
+24B3;PARENTHESIZED LATIN SMALL LETTER X;So;0;L;<compat> 0028 0078 0029;;;;N;;;;;
+24B4;PARENTHESIZED LATIN SMALL LETTER Y;So;0;L;<compat> 0028 0079 0029;;;;N;;;;;
+24B5;PARENTHESIZED LATIN SMALL LETTER Z;So;0;L;<compat> 0028 007A 0029;;;;N;;;;;
+24B6;CIRCLED LATIN CAPITAL LETTER A;So;0;L;<circle> 0041;;;;N;;;;24D0;
+24B7;CIRCLED LATIN CAPITAL LETTER B;So;0;L;<circle> 0042;;;;N;;;;24D1;
+24B8;CIRCLED LATIN CAPITAL LETTER C;So;0;L;<circle> 0043;;;;N;;;;24D2;
+24B9;CIRCLED LATIN CAPITAL LETTER D;So;0;L;<circle> 0044;;;;N;;;;24D3;
+24BA;CIRCLED LATIN CAPITAL LETTER E;So;0;L;<circle> 0045;;;;N;;;;24D4;
+24BB;CIRCLED LATIN CAPITAL LETTER F;So;0;L;<circle> 0046;;;;N;;;;24D5;
+24BC;CIRCLED LATIN CAPITAL LETTER G;So;0;L;<circle> 0047;;;;N;;;;24D6;
+24BD;CIRCLED LATIN CAPITAL LETTER H;So;0;L;<circle> 0048;;;;N;;;;24D7;
+24BE;CIRCLED LATIN CAPITAL LETTER I;So;0;L;<circle> 0049;;;;N;;;;24D8;
+24BF;CIRCLED LATIN CAPITAL LETTER J;So;0;L;<circle> 004A;;;;N;;;;24D9;
+24C0;CIRCLED LATIN CAPITAL LETTER K;So;0;L;<circle> 004B;;;;N;;;;24DA;
+24C1;CIRCLED LATIN CAPITAL LETTER L;So;0;L;<circle> 004C;;;;N;;;;24DB;
+24C2;CIRCLED LATIN CAPITAL LETTER M;So;0;L;<circle> 004D;;;;N;;;;24DC;
+24C3;CIRCLED LATIN CAPITAL LETTER N;So;0;L;<circle> 004E;;;;N;;;;24DD;
+24C4;CIRCLED LATIN CAPITAL LETTER O;So;0;L;<circle> 004F;;;;N;;;;24DE;
+24C5;CIRCLED LATIN CAPITAL LETTER P;So;0;L;<circle> 0050;;;;N;;;;24DF;
+24C6;CIRCLED LATIN CAPITAL LETTER Q;So;0;L;<circle> 0051;;;;N;;;;24E0;
+24C7;CIRCLED LATIN CAPITAL LETTER R;So;0;L;<circle> 0052;;;;N;;;;24E1;
+24C8;CIRCLED LATIN CAPITAL LETTER S;So;0;L;<circle> 0053;;;;N;;;;24E2;
+24C9;CIRCLED LATIN CAPITAL LETTER T;So;0;L;<circle> 0054;;;;N;;;;24E3;
+24CA;CIRCLED LATIN CAPITAL LETTER U;So;0;L;<circle> 0055;;;;N;;;;24E4;
+24CB;CIRCLED LATIN CAPITAL LETTER V;So;0;L;<circle> 0056;;;;N;;;;24E5;
+24CC;CIRCLED LATIN CAPITAL LETTER W;So;0;L;<circle> 0057;;;;N;;;;24E6;
+24CD;CIRCLED LATIN CAPITAL LETTER X;So;0;L;<circle> 0058;;;;N;;;;24E7;
+24CE;CIRCLED LATIN CAPITAL LETTER Y;So;0;L;<circle> 0059;;;;N;;;;24E8;
+24CF;CIRCLED LATIN CAPITAL LETTER Z;So;0;L;<circle> 005A;;;;N;;;;24E9;
+24D0;CIRCLED LATIN SMALL LETTER A;So;0;L;<circle> 0061;;;;N;;;24B6;;24B6
+24D1;CIRCLED LATIN SMALL LETTER B;So;0;L;<circle> 0062;;;;N;;;24B7;;24B7
+24D2;CIRCLED LATIN SMALL LETTER C;So;0;L;<circle> 0063;;;;N;;;24B8;;24B8
+24D3;CIRCLED LATIN SMALL LETTER D;So;0;L;<circle> 0064;;;;N;;;24B9;;24B9
+24D4;CIRCLED LATIN SMALL LETTER E;So;0;L;<circle> 0065;;;;N;;;24BA;;24BA
+24D5;CIRCLED LATIN SMALL LETTER F;So;0;L;<circle> 0066;;;;N;;;24BB;;24BB
+24D6;CIRCLED LATIN SMALL LETTER G;So;0;L;<circle> 0067;;;;N;;;24BC;;24BC
+24D7;CIRCLED LATIN SMALL LETTER H;So;0;L;<circle> 0068;;;;N;;;24BD;;24BD
+24D8;CIRCLED LATIN SMALL LETTER I;So;0;L;<circle> 0069;;;;N;;;24BE;;24BE
+24D9;CIRCLED LATIN SMALL LETTER J;So;0;L;<circle> 006A;;;;N;;;24BF;;24BF
+24DA;CIRCLED LATIN SMALL LETTER K;So;0;L;<circle> 006B;;;;N;;;24C0;;24C0
+24DB;CIRCLED LATIN SMALL LETTER L;So;0;L;<circle> 006C;;;;N;;;24C1;;24C1
+24DC;CIRCLED LATIN SMALL LETTER M;So;0;L;<circle> 006D;;;;N;;;24C2;;24C2
+24DD;CIRCLED LATIN SMALL LETTER N;So;0;L;<circle> 006E;;;;N;;;24C3;;24C3
+24DE;CIRCLED LATIN SMALL LETTER O;So;0;L;<circle> 006F;;;;N;;;24C4;;24C4
+24DF;CIRCLED LATIN SMALL LETTER P;So;0;L;<circle> 0070;;;;N;;;24C5;;24C5
+24E0;CIRCLED LATIN SMALL LETTER Q;So;0;L;<circle> 0071;;;;N;;;24C6;;24C6
+24E1;CIRCLED LATIN SMALL LETTER R;So;0;L;<circle> 0072;;;;N;;;24C7;;24C7
+24E2;CIRCLED LATIN SMALL LETTER S;So;0;L;<circle> 0073;;;;N;;;24C8;;24C8
+24E3;CIRCLED LATIN SMALL LETTER T;So;0;L;<circle> 0074;;;;N;;;24C9;;24C9
+24E4;CIRCLED LATIN SMALL LETTER U;So;0;L;<circle> 0075;;;;N;;;24CA;;24CA
+24E5;CIRCLED LATIN SMALL LETTER V;So;0;L;<circle> 0076;;;;N;;;24CB;;24CB
+24E6;CIRCLED LATIN SMALL LETTER W;So;0;L;<circle> 0077;;;;N;;;24CC;;24CC
+24E7;CIRCLED LATIN SMALL LETTER X;So;0;L;<circle> 0078;;;;N;;;24CD;;24CD
+24E8;CIRCLED LATIN SMALL LETTER Y;So;0;L;<circle> 0079;;;;N;;;24CE;;24CE
+24E9;CIRCLED LATIN SMALL LETTER Z;So;0;L;<circle> 007A;;;;N;;;24CF;;24CF
+24EA;CIRCLED DIGIT ZERO;No;0;EN;<circle> 0030;;0;0;N;;;;;
+2500;BOX DRAWINGS LIGHT HORIZONTAL;So;0;ON;;;;;N;FORMS LIGHT HORIZONTAL;;;;
+2501;BOX DRAWINGS HEAVY HORIZONTAL;So;0;ON;;;;;N;FORMS HEAVY HORIZONTAL;;;;
+2502;BOX DRAWINGS LIGHT VERTICAL;So;0;ON;;;;;N;FORMS LIGHT VERTICAL;;;;
+2503;BOX DRAWINGS HEAVY VERTICAL;So;0;ON;;;;;N;FORMS HEAVY VERTICAL;;;;
+2504;BOX DRAWINGS LIGHT TRIPLE DASH HORIZONTAL;So;0;ON;;;;;N;FORMS LIGHT TRIPLE DASH HORIZONTAL;;;;
+2505;BOX DRAWINGS HEAVY TRIPLE DASH HORIZONTAL;So;0;ON;;;;;N;FORMS HEAVY TRIPLE DASH HORIZONTAL;;;;
+2506;BOX DRAWINGS LIGHT TRIPLE DASH VERTICAL;So;0;ON;;;;;N;FORMS LIGHT TRIPLE DASH VERTICAL;;;;
+2507;BOX DRAWINGS HEAVY TRIPLE DASH VERTICAL;So;0;ON;;;;;N;FORMS HEAVY TRIPLE DASH VERTICAL;;;;
+2508;BOX DRAWINGS LIGHT QUADRUPLE DASH HORIZONTAL;So;0;ON;;;;;N;FORMS LIGHT QUADRUPLE DASH HORIZONTAL;;;;
+2509;BOX DRAWINGS HEAVY QUADRUPLE DASH HORIZONTAL;So;0;ON;;;;;N;FORMS HEAVY QUADRUPLE DASH HORIZONTAL;;;;
+250A;BOX DRAWINGS LIGHT QUADRUPLE DASH VERTICAL;So;0;ON;;;;;N;FORMS LIGHT QUADRUPLE DASH VERTICAL;;;;
+250B;BOX DRAWINGS HEAVY QUADRUPLE DASH VERTICAL;So;0;ON;;;;;N;FORMS HEAVY QUADRUPLE DASH VERTICAL;;;;
+250C;BOX DRAWINGS LIGHT DOWN AND RIGHT;So;0;ON;;;;;N;FORMS LIGHT DOWN AND RIGHT;;;;
+250D;BOX DRAWINGS DOWN LIGHT AND RIGHT HEAVY;So;0;ON;;;;;N;FORMS DOWN LIGHT AND RIGHT HEAVY;;;;
+250E;BOX DRAWINGS DOWN HEAVY AND RIGHT LIGHT;So;0;ON;;;;;N;FORMS DOWN HEAVY AND RIGHT LIGHT;;;;
+250F;BOX DRAWINGS HEAVY DOWN AND RIGHT;So;0;ON;;;;;N;FORMS HEAVY DOWN AND RIGHT;;;;
+2510;BOX DRAWINGS LIGHT DOWN AND LEFT;So;0;ON;;;;;N;FORMS LIGHT DOWN AND LEFT;;;;
+2511;BOX DRAWINGS DOWN LIGHT AND LEFT HEAVY;So;0;ON;;;;;N;FORMS DOWN LIGHT AND LEFT HEAVY;;;;
+2512;BOX DRAWINGS DOWN HEAVY AND LEFT LIGHT;So;0;ON;;;;;N;FORMS DOWN HEAVY AND LEFT LIGHT;;;;
+2513;BOX DRAWINGS HEAVY DOWN AND LEFT;So;0;ON;;;;;N;FORMS HEAVY DOWN AND LEFT;;;;
+2514;BOX DRAWINGS LIGHT UP AND RIGHT;So;0;ON;;;;;N;FORMS LIGHT UP AND RIGHT;;;;
+2515;BOX DRAWINGS UP LIGHT AND RIGHT HEAVY;So;0;ON;;;;;N;FORMS UP LIGHT AND RIGHT HEAVY;;;;
+2516;BOX DRAWINGS UP HEAVY AND RIGHT LIGHT;So;0;ON;;;;;N;FORMS UP HEAVY AND RIGHT LIGHT;;;;
+2517;BOX DRAWINGS HEAVY UP AND RIGHT;So;0;ON;;;;;N;FORMS HEAVY UP AND RIGHT;;;;
+2518;BOX DRAWINGS LIGHT UP AND LEFT;So;0;ON;;;;;N;FORMS LIGHT UP AND LEFT;;;;
+2519;BOX DRAWINGS UP LIGHT AND LEFT HEAVY;So;0;ON;;;;;N;FORMS UP LIGHT AND LEFT HEAVY;;;;
+251A;BOX DRAWINGS UP HEAVY AND LEFT LIGHT;So;0;ON;;;;;N;FORMS UP HEAVY AND LEFT LIGHT;;;;
+251B;BOX DRAWINGS HEAVY UP AND LEFT;So;0;ON;;;;;N;FORMS HEAVY UP AND LEFT;;;;
+251C;BOX DRAWINGS LIGHT VERTICAL AND RIGHT;So;0;ON;;;;;N;FORMS LIGHT VERTICAL AND RIGHT;;;;
+251D;BOX DRAWINGS VERTICAL LIGHT AND RIGHT HEAVY;So;0;ON;;;;;N;FORMS VERTICAL LIGHT AND RIGHT HEAVY;;;;
+251E;BOX DRAWINGS UP HEAVY AND RIGHT DOWN LIGHT;So;0;ON;;;;;N;FORMS UP HEAVY AND RIGHT DOWN LIGHT;;;;
+251F;BOX DRAWINGS DOWN HEAVY AND RIGHT UP LIGHT;So;0;ON;;;;;N;FORMS DOWN HEAVY AND RIGHT UP LIGHT;;;;
+2520;BOX DRAWINGS VERTICAL HEAVY AND RIGHT LIGHT;So;0;ON;;;;;N;FORMS VERTICAL HEAVY AND RIGHT LIGHT;;;;
+2521;BOX DRAWINGS DOWN LIGHT AND RIGHT UP HEAVY;So;0;ON;;;;;N;FORMS DOWN LIGHT AND RIGHT UP HEAVY;;;;
+2522;BOX DRAWINGS UP LIGHT AND RIGHT DOWN HEAVY;So;0;ON;;;;;N;FORMS UP LIGHT AND RIGHT DOWN HEAVY;;;;
+2523;BOX DRAWINGS HEAVY VERTICAL AND RIGHT;So;0;ON;;;;;N;FORMS HEAVY VERTICAL AND RIGHT;;;;
+2524;BOX DRAWINGS LIGHT VERTICAL AND LEFT;So;0;ON;;;;;N;FORMS LIGHT VERTICAL AND LEFT;;;;
+2525;BOX DRAWINGS VERTICAL LIGHT AND LEFT HEAVY;So;0;ON;;;;;N;FORMS VERTICAL LIGHT AND LEFT HEAVY;;;;
+2526;BOX DRAWINGS UP HEAVY AND LEFT DOWN LIGHT;So;0;ON;;;;;N;FORMS UP HEAVY AND LEFT DOWN LIGHT;;;;
+2527;BOX DRAWINGS DOWN HEAVY AND LEFT UP LIGHT;So;0;ON;;;;;N;FORMS DOWN HEAVY AND LEFT UP LIGHT;;;;
+2528;BOX DRAWINGS VERTICAL HEAVY AND LEFT LIGHT;So;0;ON;;;;;N;FORMS VERTICAL HEAVY AND LEFT LIGHT;;;;
+2529;BOX DRAWINGS DOWN LIGHT AND LEFT UP HEAVY;So;0;ON;;;;;N;FORMS DOWN LIGHT AND LEFT UP HEAVY;;;;
+252A;BOX DRAWINGS UP LIGHT AND LEFT DOWN HEAVY;So;0;ON;;;;;N;FORMS UP LIGHT AND LEFT DOWN HEAVY;;;;
+252B;BOX DRAWINGS HEAVY VERTICAL AND LEFT;So;0;ON;;;;;N;FORMS HEAVY VERTICAL AND LEFT;;;;
+252C;BOX DRAWINGS LIGHT DOWN AND HORIZONTAL;So;0;ON;;;;;N;FORMS LIGHT DOWN AND HORIZONTAL;;;;
+252D;BOX DRAWINGS LEFT HEAVY AND RIGHT DOWN LIGHT;So;0;ON;;;;;N;FORMS LEFT HEAVY AND RIGHT DOWN LIGHT;;;;
+252E;BOX DRAWINGS RIGHT HEAVY AND LEFT DOWN LIGHT;So;0;ON;;;;;N;FORMS RIGHT HEAVY AND LEFT DOWN LIGHT;;;;
+252F;BOX DRAWINGS DOWN LIGHT AND HORIZONTAL HEAVY;So;0;ON;;;;;N;FORMS DOWN LIGHT AND HORIZONTAL HEAVY;;;;
+2530;BOX DRAWINGS DOWN HEAVY AND HORIZONTAL LIGHT;So;0;ON;;;;;N;FORMS DOWN HEAVY AND HORIZONTAL LIGHT;;;;
+2531;BOX DRAWINGS RIGHT LIGHT AND LEFT DOWN HEAVY;So;0;ON;;;;;N;FORMS RIGHT LIGHT AND LEFT DOWN HEAVY;;;;
+2532;BOX DRAWINGS LEFT LIGHT AND RIGHT DOWN HEAVY;So;0;ON;;;;;N;FORMS LEFT LIGHT AND RIGHT DOWN HEAVY;;;;
+2533;BOX DRAWINGS HEAVY DOWN AND HORIZONTAL;So;0;ON;;;;;N;FORMS HEAVY DOWN AND HORIZONTAL;;;;
+2534;BOX DRAWINGS LIGHT UP AND HORIZONTAL;So;0;ON;;;;;N;FORMS LIGHT UP AND HORIZONTAL;;;;
+2535;BOX DRAWINGS LEFT HEAVY AND RIGHT UP LIGHT;So;0;ON;;;;;N;FORMS LEFT HEAVY AND RIGHT UP LIGHT;;;;
+2536;BOX DRAWINGS RIGHT HEAVY AND LEFT UP LIGHT;So;0;ON;;;;;N;FORMS RIGHT HEAVY AND LEFT UP LIGHT;;;;
+2537;BOX DRAWINGS UP LIGHT AND HORIZONTAL HEAVY;So;0;ON;;;;;N;FORMS UP LIGHT AND HORIZONTAL HEAVY;;;;
+2538;BOX DRAWINGS UP HEAVY AND HORIZONTAL LIGHT;So;0;ON;;;;;N;FORMS UP HEAVY AND HORIZONTAL LIGHT;;;;
+2539;BOX DRAWINGS RIGHT LIGHT AND LEFT UP HEAVY;So;0;ON;;;;;N;FORMS RIGHT LIGHT AND LEFT UP HEAVY;;;;
+253A;BOX DRAWINGS LEFT LIGHT AND RIGHT UP HEAVY;So;0;ON;;;;;N;FORMS LEFT LIGHT AND RIGHT UP HEAVY;;;;
+253B;BOX DRAWINGS HEAVY UP AND HORIZONTAL;So;0;ON;;;;;N;FORMS HEAVY UP AND HORIZONTAL;;;;
+253C;BOX DRAWINGS LIGHT VERTICAL AND HORIZONTAL;So;0;ON;;;;;N;FORMS LIGHT VERTICAL AND HORIZONTAL;;;;
+253D;BOX DRAWINGS LEFT HEAVY AND RIGHT VERTICAL LIGHT;So;0;ON;;;;;N;FORMS LEFT HEAVY AND RIGHT VERTICAL LIGHT;;;;
+253E;BOX DRAWINGS RIGHT HEAVY AND LEFT VERTICAL LIGHT;So;0;ON;;;;;N;FORMS RIGHT HEAVY AND LEFT VERTICAL LIGHT;;;;
+253F;BOX DRAWINGS VERTICAL LIGHT AND HORIZONTAL HEAVY;So;0;ON;;;;;N;FORMS VERTICAL LIGHT AND HORIZONTAL HEAVY;;;;
+2540;BOX DRAWINGS UP HEAVY AND DOWN HORIZONTAL LIGHT;So;0;ON;;;;;N;FORMS UP HEAVY AND DOWN HORIZONTAL LIGHT;;;;
+2541;BOX DRAWINGS DOWN HEAVY AND UP HORIZONTAL LIGHT;So;0;ON;;;;;N;FORMS DOWN HEAVY AND UP HORIZONTAL LIGHT;;;;
+2542;BOX DRAWINGS VERTICAL HEAVY AND HORIZONTAL LIGHT;So;0;ON;;;;;N;FORMS VERTICAL HEAVY AND HORIZONTAL LIGHT;;;;
+2543;BOX DRAWINGS LEFT UP HEAVY AND RIGHT DOWN LIGHT;So;0;ON;;;;;N;FORMS LEFT UP HEAVY AND RIGHT DOWN LIGHT;;;;
+2544;BOX DRAWINGS RIGHT UP HEAVY AND LEFT DOWN LIGHT;So;0;ON;;;;;N;FORMS RIGHT UP HEAVY AND LEFT DOWN LIGHT;;;;
+2545;BOX DRAWINGS LEFT DOWN HEAVY AND RIGHT UP LIGHT;So;0;ON;;;;;N;FORMS LEFT DOWN HEAVY AND RIGHT UP LIGHT;;;;
+2546;BOX DRAWINGS RIGHT DOWN HEAVY AND LEFT UP LIGHT;So;0;ON;;;;;N;FORMS RIGHT DOWN HEAVY AND LEFT UP LIGHT;;;;
+2547;BOX DRAWINGS DOWN LIGHT AND UP HORIZONTAL HEAVY;So;0;ON;;;;;N;FORMS DOWN LIGHT AND UP HORIZONTAL HEAVY;;;;
+2548;BOX DRAWINGS UP LIGHT AND DOWN HORIZONTAL HEAVY;So;0;ON;;;;;N;FORMS UP LIGHT AND DOWN HORIZONTAL HEAVY;;;;
+2549;BOX DRAWINGS RIGHT LIGHT AND LEFT VERTICAL HEAVY;So;0;ON;;;;;N;FORMS RIGHT LIGHT AND LEFT VERTICAL HEAVY;;;;
+254A;BOX DRAWINGS LEFT LIGHT AND RIGHT VERTICAL HEAVY;So;0;ON;;;;;N;FORMS LEFT LIGHT AND RIGHT VERTICAL HEAVY;;;;
+254B;BOX DRAWINGS HEAVY VERTICAL AND HORIZONTAL;So;0;ON;;;;;N;FORMS HEAVY VERTICAL AND HORIZONTAL;;;;
+254C;BOX DRAWINGS LIGHT DOUBLE DASH HORIZONTAL;So;0;ON;;;;;N;FORMS LIGHT DOUBLE DASH HORIZONTAL;;;;
+254D;BOX DRAWINGS HEAVY DOUBLE DASH HORIZONTAL;So;0;ON;;;;;N;FORMS HEAVY DOUBLE DASH HORIZONTAL;;;;
+254E;BOX DRAWINGS LIGHT DOUBLE DASH VERTICAL;So;0;ON;;;;;N;FORMS LIGHT DOUBLE DASH VERTICAL;;;;
+254F;BOX DRAWINGS HEAVY DOUBLE DASH VERTICAL;So;0;ON;;;;;N;FORMS HEAVY DOUBLE DASH VERTICAL;;;;
+2550;BOX DRAWINGS DOUBLE HORIZONTAL;So;0;ON;;;;;N;FORMS DOUBLE HORIZONTAL;;;;
+2551;BOX DRAWINGS DOUBLE VERTICAL;So;0;ON;;;;;N;FORMS DOUBLE VERTICAL;;;;
+2552;BOX DRAWINGS DOWN SINGLE AND RIGHT DOUBLE;So;0;ON;;;;;N;FORMS DOWN SINGLE AND RIGHT DOUBLE;;;;
+2553;BOX DRAWINGS DOWN DOUBLE AND RIGHT SINGLE;So;0;ON;;;;;N;FORMS DOWN DOUBLE AND RIGHT SINGLE;;;;
+2554;BOX DRAWINGS DOUBLE DOWN AND RIGHT;So;0;ON;;;;;N;FORMS DOUBLE DOWN AND RIGHT;;;;
+2555;BOX DRAWINGS DOWN SINGLE AND LEFT DOUBLE;So;0;ON;;;;;N;FORMS DOWN SINGLE AND LEFT DOUBLE;;;;
+2556;BOX DRAWINGS DOWN DOUBLE AND LEFT SINGLE;So;0;ON;;;;;N;FORMS DOWN DOUBLE AND LEFT SINGLE;;;;
+2557;BOX DRAWINGS DOUBLE DOWN AND LEFT;So;0;ON;;;;;N;FORMS DOUBLE DOWN AND LEFT;;;;
+2558;BOX DRAWINGS UP SINGLE AND RIGHT DOUBLE;So;0;ON;;;;;N;FORMS UP SINGLE AND RIGHT DOUBLE;;;;
+2559;BOX DRAWINGS UP DOUBLE AND RIGHT SINGLE;So;0;ON;;;;;N;FORMS UP DOUBLE AND RIGHT SINGLE;;;;
+255A;BOX DRAWINGS DOUBLE UP AND RIGHT;So;0;ON;;;;;N;FORMS DOUBLE UP AND RIGHT;;;;
+255B;BOX DRAWINGS UP SINGLE AND LEFT DOUBLE;So;0;ON;;;;;N;FORMS UP SINGLE AND LEFT DOUBLE;;;;
+255C;BOX DRAWINGS UP DOUBLE AND LEFT SINGLE;So;0;ON;;;;;N;FORMS UP DOUBLE AND LEFT SINGLE;;;;
+255D;BOX DRAWINGS DOUBLE UP AND LEFT;So;0;ON;;;;;N;FORMS DOUBLE UP AND LEFT;;;;
+255E;BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE;So;0;ON;;;;;N;FORMS VERTICAL SINGLE AND RIGHT DOUBLE;;;;
+255F;BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE;So;0;ON;;;;;N;FORMS VERTICAL DOUBLE AND RIGHT SINGLE;;;;
+2560;BOX DRAWINGS DOUBLE VERTICAL AND RIGHT;So;0;ON;;;;;N;FORMS DOUBLE VERTICAL AND RIGHT;;;;
+2561;BOX DRAWINGS VERTICAL SINGLE AND LEFT DOUBLE;So;0;ON;;;;;N;FORMS VERTICAL SINGLE AND LEFT DOUBLE;;;;
+2562;BOX DRAWINGS VERTICAL DOUBLE AND LEFT SINGLE;So;0;ON;;;;;N;FORMS VERTICAL DOUBLE AND LEFT SINGLE;;;;
+2563;BOX DRAWINGS DOUBLE VERTICAL AND LEFT;So;0;ON;;;;;N;FORMS DOUBLE VERTICAL AND LEFT;;;;
+2564;BOX DRAWINGS DOWN SINGLE AND HORIZONTAL DOUBLE;So;0;ON;;;;;N;FORMS DOWN SINGLE AND HORIZONTAL DOUBLE;;;;
+2565;BOX DRAWINGS DOWN DOUBLE AND HORIZONTAL SINGLE;So;0;ON;;;;;N;FORMS DOWN DOUBLE AND HORIZONTAL SINGLE;;;;
+2566;BOX DRAWINGS DOUBLE DOWN AND HORIZONTAL;So;0;ON;;;;;N;FORMS DOUBLE DOWN AND HORIZONTAL;;;;
+2567;BOX DRAWINGS UP SINGLE AND HORIZONTAL DOUBLE;So;0;ON;;;;;N;FORMS UP SINGLE AND HORIZONTAL DOUBLE;;;;
+2568;BOX DRAWINGS UP DOUBLE AND HORIZONTAL SINGLE;So;0;ON;;;;;N;FORMS UP DOUBLE AND HORIZONTAL SINGLE;;;;
+2569;BOX DRAWINGS DOUBLE UP AND HORIZONTAL;So;0;ON;;;;;N;FORMS DOUBLE UP AND HORIZONTAL;;;;
+256A;BOX DRAWINGS VERTICAL SINGLE AND HORIZONTAL DOUBLE;So;0;ON;;;;;N;FORMS VERTICAL SINGLE AND HORIZONTAL DOUBLE;;;;
+256B;BOX DRAWINGS VERTICAL DOUBLE AND HORIZONTAL SINGLE;So;0;ON;;;;;N;FORMS VERTICAL DOUBLE AND HORIZONTAL SINGLE;;;;
+256C;BOX DRAWINGS DOUBLE VERTICAL AND HORIZONTAL;So;0;ON;;;;;N;FORMS DOUBLE VERTICAL AND HORIZONTAL;;;;
+256D;BOX DRAWINGS LIGHT ARC DOWN AND RIGHT;So;0;ON;;;;;N;FORMS LIGHT ARC DOWN AND RIGHT;;;;
+256E;BOX DRAWINGS LIGHT ARC DOWN AND LEFT;So;0;ON;;;;;N;FORMS LIGHT ARC DOWN AND LEFT;;;;
+256F;BOX DRAWINGS LIGHT ARC UP AND LEFT;So;0;ON;;;;;N;FORMS LIGHT ARC UP AND LEFT;;;;
+2570;BOX DRAWINGS LIGHT ARC UP AND RIGHT;So;0;ON;;;;;N;FORMS LIGHT ARC UP AND RIGHT;;;;
+2571;BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT;So;0;ON;;;;;N;FORMS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT;;;;
+2572;BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT;So;0;ON;;;;;N;FORMS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT;;;;
+2573;BOX DRAWINGS LIGHT DIAGONAL CROSS;So;0;ON;;;;;N;FORMS LIGHT DIAGONAL CROSS;;;;
+2574;BOX DRAWINGS LIGHT LEFT;So;0;ON;;;;;N;FORMS LIGHT LEFT;;;;
+2575;BOX DRAWINGS LIGHT UP;So;0;ON;;;;;N;FORMS LIGHT UP;;;;
+2576;BOX DRAWINGS LIGHT RIGHT;So;0;ON;;;;;N;FORMS LIGHT RIGHT;;;;
+2577;BOX DRAWINGS LIGHT DOWN;So;0;ON;;;;;N;FORMS LIGHT DOWN;;;;
+2578;BOX DRAWINGS HEAVY LEFT;So;0;ON;;;;;N;FORMS HEAVY LEFT;;;;
+2579;BOX DRAWINGS HEAVY UP;So;0;ON;;;;;N;FORMS HEAVY UP;;;;
+257A;BOX DRAWINGS HEAVY RIGHT;So;0;ON;;;;;N;FORMS HEAVY RIGHT;;;;
+257B;BOX DRAWINGS HEAVY DOWN;So;0;ON;;;;;N;FORMS HEAVY DOWN;;;;
+257C;BOX DRAWINGS LIGHT LEFT AND HEAVY RIGHT;So;0;ON;;;;;N;FORMS LIGHT LEFT AND HEAVY RIGHT;;;;
+257D;BOX DRAWINGS LIGHT UP AND HEAVY DOWN;So;0;ON;;;;;N;FORMS LIGHT UP AND HEAVY DOWN;;;;
+257E;BOX DRAWINGS HEAVY LEFT AND LIGHT RIGHT;So;0;ON;;;;;N;FORMS HEAVY LEFT AND LIGHT RIGHT;;;;
+257F;BOX DRAWINGS HEAVY UP AND LIGHT DOWN;So;0;ON;;;;;N;FORMS HEAVY UP AND LIGHT DOWN;;;;
+2580;UPPER HALF BLOCK;So;0;ON;;;;;N;;;;;
+2581;LOWER ONE EIGHTH BLOCK;So;0;ON;;;;;N;;;;;
+2582;LOWER ONE QUARTER BLOCK;So;0;ON;;;;;N;;;;;
+2583;LOWER THREE EIGHTHS BLOCK;So;0;ON;;;;;N;;;;;
+2584;LOWER HALF BLOCK;So;0;ON;;;;;N;;;;;
+2585;LOWER FIVE EIGHTHS BLOCK;So;0;ON;;;;;N;;;;;
+2586;LOWER THREE QUARTERS BLOCK;So;0;ON;;;;;N;LOWER THREE QUARTER BLOCK;;;;
+2587;LOWER SEVEN EIGHTHS BLOCK;So;0;ON;;;;;N;;;;;
+2588;FULL BLOCK;So;0;ON;;;;;N;;;;;
+2589;LEFT SEVEN EIGHTHS BLOCK;So;0;ON;;;;;N;;;;;
+258A;LEFT THREE QUARTERS BLOCK;So;0;ON;;;;;N;LEFT THREE QUARTER BLOCK;;;;
+258B;LEFT FIVE EIGHTHS BLOCK;So;0;ON;;;;;N;;;;;
+258C;LEFT HALF BLOCK;So;0;ON;;;;;N;;;;;
+258D;LEFT THREE EIGHTHS BLOCK;So;0;ON;;;;;N;;;;;
+258E;LEFT ONE QUARTER BLOCK;So;0;ON;;;;;N;;;;;
+258F;LEFT ONE EIGHTH BLOCK;So;0;ON;;;;;N;;;;;
+2590;RIGHT HALF BLOCK;So;0;ON;;;;;N;;;;;
+2591;LIGHT SHADE;So;0;ON;;;;;N;;;;;
+2592;MEDIUM SHADE;So;0;ON;;;;;N;;;;;
+2593;DARK SHADE;So;0;ON;;;;;N;;;;;
+2594;UPPER ONE EIGHTH BLOCK;So;0;ON;;;;;N;;;;;
+2595;RIGHT ONE EIGHTH BLOCK;So;0;ON;;;;;N;;;;;
+25A0;BLACK SQUARE;So;0;ON;;;;;N;;;;;
+25A1;WHITE SQUARE;So;0;ON;;;;;N;;;;;
+25A2;WHITE SQUARE WITH ROUNDED CORNERS;So;0;ON;;;;;N;;;;;
+25A3;WHITE SQUARE CONTAINING BLACK SMALL SQUARE;So;0;ON;;;;;N;;;;;
+25A4;SQUARE WITH HORIZONTAL FILL;So;0;ON;;;;;N;;;;;
+25A5;SQUARE WITH VERTICAL FILL;So;0;ON;;;;;N;;;;;
+25A6;SQUARE WITH ORTHOGONAL CROSSHATCH FILL;So;0;ON;;;;;N;;;;;
+25A7;SQUARE WITH UPPER LEFT TO LOWER RIGHT FILL;So;0;ON;;;;;N;;;;;
+25A8;SQUARE WITH UPPER RIGHT TO LOWER LEFT FILL;So;0;ON;;;;;N;;;;;
+25A9;SQUARE WITH DIAGONAL CROSSHATCH FILL;So;0;ON;;;;;N;;;;;
+25AA;BLACK SMALL SQUARE;So;0;ON;;;;;N;;;;;
+25AB;WHITE SMALL SQUARE;So;0;ON;;;;;N;;;;;
+25AC;BLACK RECTANGLE;So;0;ON;;;;;N;;;;;
+25AD;WHITE RECTANGLE;So;0;ON;;;;;N;;;;;
+25AE;BLACK VERTICAL RECTANGLE;So;0;ON;;;;;N;;;;;
+25AF;WHITE VERTICAL RECTANGLE;So;0;ON;;;;;N;;;;;
+25B0;BLACK PARALLELOGRAM;So;0;ON;;;;;N;;;;;
+25B1;WHITE PARALLELOGRAM;So;0;ON;;;;;N;;;;;
+25B2;BLACK UP-POINTING TRIANGLE;So;0;ON;;;;;N;BLACK UP POINTING TRIANGLE;;;;
+25B3;WHITE UP-POINTING TRIANGLE;So;0;ON;;;;;N;WHITE UP POINTING TRIANGLE;;;;
+25B4;BLACK UP-POINTING SMALL TRIANGLE;So;0;ON;;;;;N;BLACK UP POINTING SMALL TRIANGLE;;;;
+25B5;WHITE UP-POINTING SMALL TRIANGLE;So;0;ON;;;;;N;WHITE UP POINTING SMALL TRIANGLE;;;;
+25B6;BLACK RIGHT-POINTING TRIANGLE;So;0;ON;;;;;N;BLACK RIGHT POINTING TRIANGLE;;;;
+25B7;WHITE RIGHT-POINTING TRIANGLE;Sm;0;ON;;;;;N;WHITE RIGHT POINTING TRIANGLE;;;;
+25B8;BLACK RIGHT-POINTING SMALL TRIANGLE;So;0;ON;;;;;N;BLACK RIGHT POINTING SMALL TRIANGLE;;;;
+25B9;WHITE RIGHT-POINTING SMALL TRIANGLE;So;0;ON;;;;;N;WHITE RIGHT POINTING SMALL TRIANGLE;;;;
+25BA;BLACK RIGHT-POINTING POINTER;So;0;ON;;;;;N;BLACK RIGHT POINTING POINTER;;;;
+25BB;WHITE RIGHT-POINTING POINTER;So;0;ON;;;;;N;WHITE RIGHT POINTING POINTER;;;;
+25BC;BLACK DOWN-POINTING TRIANGLE;So;0;ON;;;;;N;BLACK DOWN POINTING TRIANGLE;;;;
+25BD;WHITE DOWN-POINTING TRIANGLE;So;0;ON;;;;;N;WHITE DOWN POINTING TRIANGLE;;;;
+25BE;BLACK DOWN-POINTING SMALL TRIANGLE;So;0;ON;;;;;N;BLACK DOWN POINTING SMALL TRIANGLE;;;;
+25BF;WHITE DOWN-POINTING SMALL TRIANGLE;So;0;ON;;;;;N;WHITE DOWN POINTING SMALL TRIANGLE;;;;
+25C0;BLACK LEFT-POINTING TRIANGLE;So;0;ON;;;;;N;BLACK LEFT POINTING TRIANGLE;;;;
+25C1;WHITE LEFT-POINTING TRIANGLE;Sm;0;ON;;;;;N;WHITE LEFT POINTING TRIANGLE;;;;
+25C2;BLACK LEFT-POINTING SMALL TRIANGLE;So;0;ON;;;;;N;BLACK LEFT POINTING SMALL TRIANGLE;;;;
+25C3;WHITE LEFT-POINTING SMALL TRIANGLE;So;0;ON;;;;;N;WHITE LEFT POINTING SMALL TRIANGLE;;;;
+25C4;BLACK LEFT-POINTING POINTER;So;0;ON;;;;;N;BLACK LEFT POINTING POINTER;;;;
+25C5;WHITE LEFT-POINTING POINTER;So;0;ON;;;;;N;WHITE LEFT POINTING POINTER;;;;
+25C6;BLACK DIAMOND;So;0;ON;;;;;N;;;;;
+25C7;WHITE DIAMOND;So;0;ON;;;;;N;;;;;
+25C8;WHITE DIAMOND CONTAINING BLACK SMALL DIAMOND;So;0;ON;;;;;N;;;;;
+25C9;FISHEYE;So;0;ON;;;;;N;;;;;
+25CA;LOZENGE;So;0;ON;;;;;N;;;;;
+25CB;WHITE CIRCLE;So;0;ON;;;;;N;;;;;
+25CC;DOTTED CIRCLE;So;0;ON;;;;;N;;;;;
+25CD;CIRCLE WITH VERTICAL FILL;So;0;ON;;;;;N;;;;;
+25CE;BULLSEYE;So;0;ON;;;;;N;;;;;
+25CF;BLACK CIRCLE;So;0;ON;;;;;N;;;;;
+25D0;CIRCLE WITH LEFT HALF BLACK;So;0;ON;;;;;N;;;;;
+25D1;CIRCLE WITH RIGHT HALF BLACK;So;0;ON;;;;;N;;;;;
+25D2;CIRCLE WITH LOWER HALF BLACK;So;0;ON;;;;;N;;;;;
+25D3;CIRCLE WITH UPPER HALF BLACK;So;0;ON;;;;;N;;;;;
+25D4;CIRCLE WITH UPPER RIGHT QUADRANT BLACK;So;0;ON;;;;;N;;;;;
+25D5;CIRCLE WITH ALL BUT UPPER LEFT QUADRANT BLACK;So;0;ON;;;;;N;;;;;
+25D6;LEFT HALF BLACK CIRCLE;So;0;ON;;;;;N;;;;;
+25D7;RIGHT HALF BLACK CIRCLE;So;0;ON;;;;;N;;;;;
+25D8;INVERSE BULLET;So;0;ON;;;;;N;;;;;
+25D9;INVERSE WHITE CIRCLE;So;0;ON;;;;;N;;;;;
+25DA;UPPER HALF INVERSE WHITE CIRCLE;So;0;ON;;;;;N;;;;;
+25DB;LOWER HALF INVERSE WHITE CIRCLE;So;0;ON;;;;;N;;;;;
+25DC;UPPER LEFT QUADRANT CIRCULAR ARC;So;0;ON;;;;;N;;;;;
+25DD;UPPER RIGHT QUADRANT CIRCULAR ARC;So;0;ON;;;;;N;;;;;
+25DE;LOWER RIGHT QUADRANT CIRCULAR ARC;So;0;ON;;;;;N;;;;;
+25DF;LOWER LEFT QUADRANT CIRCULAR ARC;So;0;ON;;;;;N;;;;;
+25E0;UPPER HALF CIRCLE;So;0;ON;;;;;N;;;;;
+25E1;LOWER HALF CIRCLE;So;0;ON;;;;;N;;;;;
+25E2;BLACK LOWER RIGHT TRIANGLE;So;0;ON;;;;;N;;;;;
+25E3;BLACK LOWER LEFT TRIANGLE;So;0;ON;;;;;N;;;;;
+25E4;BLACK UPPER LEFT TRIANGLE;So;0;ON;;;;;N;;;;;
+25E5;BLACK UPPER RIGHT TRIANGLE;So;0;ON;;;;;N;;;;;
+25E6;WHITE BULLET;So;0;ON;;;;;N;;;;;
+25E7;SQUARE WITH LEFT HALF BLACK;So;0;ON;;;;;N;;;;;
+25E8;SQUARE WITH RIGHT HALF BLACK;So;0;ON;;;;;N;;;;;
+25E9;SQUARE WITH UPPER LEFT DIAGONAL HALF BLACK;So;0;ON;;;;;N;;;;;
+25EA;SQUARE WITH LOWER RIGHT DIAGONAL HALF BLACK;So;0;ON;;;;;N;;;;;
+25EB;WHITE SQUARE WITH VERTICAL BISECTING LINE;So;0;ON;;;;;N;;;;;
+25EC;WHITE UP-POINTING TRIANGLE WITH DOT;So;0;ON;;;;;N;WHITE UP POINTING TRIANGLE WITH DOT;;;;
+25ED;UP-POINTING TRIANGLE WITH LEFT HALF BLACK;So;0;ON;;;;;N;UP POINTING TRIANGLE WITH LEFT HALF BLACK;;;;
+25EE;UP-POINTING TRIANGLE WITH RIGHT HALF BLACK;So;0;ON;;;;;N;UP POINTING TRIANGLE WITH RIGHT HALF BLACK;;;;
+25EF;LARGE CIRCLE;So;0;ON;;;;;N;;;;;
+25F0;WHITE SQUARE WITH UPPER LEFT QUADRANT;So;0;ON;;;;;N;;;;;
+25F1;WHITE SQUARE WITH LOWER LEFT QUADRANT;So;0;ON;;;;;N;;;;;
+25F2;WHITE SQUARE WITH LOWER RIGHT QUADRANT;So;0;ON;;;;;N;;;;;
+25F3;WHITE SQUARE WITH UPPER RIGHT QUADRANT;So;0;ON;;;;;N;;;;;
+25F4;WHITE CIRCLE WITH UPPER LEFT QUADRANT;So;0;ON;;;;;N;;;;;
+25F5;WHITE CIRCLE WITH LOWER LEFT QUADRANT;So;0;ON;;;;;N;;;;;
+25F6;WHITE CIRCLE WITH LOWER RIGHT QUADRANT;So;0;ON;;;;;N;;;;;
+25F7;WHITE CIRCLE WITH UPPER RIGHT QUADRANT;So;0;ON;;;;;N;;;;;
+2600;BLACK SUN WITH RAYS;So;0;ON;;;;;N;;;;;
+2601;CLOUD;So;0;ON;;;;;N;;;;;
+2602;UMBRELLA;So;0;ON;;;;;N;;;;;
+2603;SNOWMAN;So;0;ON;;;;;N;;;;;
+2604;COMET;So;0;ON;;;;;N;;;;;
+2605;BLACK STAR;So;0;ON;;;;;N;;;;;
+2606;WHITE STAR;So;0;ON;;;;;N;;;;;
+2607;LIGHTNING;So;0;ON;;;;;N;;;;;
+2608;THUNDERSTORM;So;0;ON;;;;;N;;;;;
+2609;SUN;So;0;ON;;;;;N;;;;;
+260A;ASCENDING NODE;So;0;ON;;;;;N;;;;;
+260B;DESCENDING NODE;So;0;ON;;;;;N;;;;;
+260C;CONJUNCTION;So;0;ON;;;;;N;;;;;
+260D;OPPOSITION;So;0;ON;;;;;N;;;;;
+260E;BLACK TELEPHONE;So;0;ON;;;;;N;;;;;
+260F;WHITE TELEPHONE;So;0;ON;;;;;N;;;;;
+2610;BALLOT BOX;So;0;ON;;;;;N;;;;;
+2611;BALLOT BOX WITH CHECK;So;0;ON;;;;;N;;;;;
+2612;BALLOT BOX WITH X;So;0;ON;;;;;N;;;;;
+2613;SALTIRE;So;0;ON;;;;;N;;;;;
+2619;REVERSED ROTATED FLORAL HEART BULLET;So;0;ON;;;;;N;;;;;
+261A;BLACK LEFT POINTING INDEX;So;0;ON;;;;;N;;;;;
+261B;BLACK RIGHT POINTING INDEX;So;0;ON;;;;;N;;;;;
+261C;WHITE LEFT POINTING INDEX;So;0;ON;;;;;N;;;;;
+261D;WHITE UP POINTING INDEX;So;0;ON;;;;;N;;;;;
+261E;WHITE RIGHT POINTING INDEX;So;0;ON;;;;;N;;;;;
+261F;WHITE DOWN POINTING INDEX;So;0;ON;;;;;N;;;;;
+2620;SKULL AND CROSSBONES;So;0;ON;;;;;N;;;;;
+2621;CAUTION SIGN;So;0;ON;;;;;N;;;;;
+2622;RADIOACTIVE SIGN;So;0;ON;;;;;N;;;;;
+2623;BIOHAZARD SIGN;So;0;ON;;;;;N;;;;;
+2624;CADUCEUS;So;0;ON;;;;;N;;;;;
+2625;ANKH;So;0;ON;;;;;N;;;;;
+2626;ORTHODOX CROSS;So;0;ON;;;;;N;;;;;
+2627;CHI RHO;So;0;ON;;;;;N;;;;;
+2628;CROSS OF LORRAINE;So;0;ON;;;;;N;;;;;
+2629;CROSS OF JERUSALEM;So;0;ON;;;;;N;;;;;
+262A;STAR AND CRESCENT;So;0;ON;;;;;N;;;;;
+262B;FARSI SYMBOL;So;0;ON;;;;;N;SYMBOL OF IRAN;;;;
+262C;ADI SHAKTI;So;0;ON;;;;;N;;;;;
+262D;HAMMER AND SICKLE;So;0;ON;;;;;N;;;;;
+262E;PEACE SYMBOL;So;0;ON;;;;;N;;;;;
+262F;YIN YANG;So;0;ON;;;;;N;;;;;
+2630;TRIGRAM FOR HEAVEN;So;0;ON;;;;;N;;;;;
+2631;TRIGRAM FOR LAKE;So;0;ON;;;;;N;;;;;
+2632;TRIGRAM FOR FIRE;So;0;ON;;;;;N;;;;;
+2633;TRIGRAM FOR THUNDER;So;0;ON;;;;;N;;;;;
+2634;TRIGRAM FOR WIND;So;0;ON;;;;;N;;;;;
+2635;TRIGRAM FOR WATER;So;0;ON;;;;;N;;;;;
+2636;TRIGRAM FOR MOUNTAIN;So;0;ON;;;;;N;;;;;
+2637;TRIGRAM FOR EARTH;So;0;ON;;;;;N;;;;;
+2638;WHEEL OF DHARMA;So;0;ON;;;;;N;;;;;
+2639;WHITE FROWNING FACE;So;0;ON;;;;;N;;;;;
+263A;WHITE SMILING FACE;So;0;ON;;;;;N;;;;;
+263B;BLACK SMILING FACE;So;0;ON;;;;;N;;;;;
+263C;WHITE SUN WITH RAYS;So;0;ON;;;;;N;;;;;
+263D;FIRST QUARTER MOON;So;0;ON;;;;;N;;;;;
+263E;LAST QUARTER MOON;So;0;ON;;;;;N;;;;;
+263F;MERCURY;So;0;ON;;;;;N;;;;;
+2640;FEMALE SIGN;So;0;ON;;;;;N;;;;;
+2641;EARTH;So;0;ON;;;;;N;;;;;
+2642;MALE SIGN;So;0;ON;;;;;N;;;;;
+2643;JUPITER;So;0;ON;;;;;N;;;;;
+2644;SATURN;So;0;ON;;;;;N;;;;;
+2645;URANUS;So;0;ON;;;;;N;;;;;
+2646;NEPTUNE;So;0;ON;;;;;N;;;;;
+2647;PLUTO;So;0;ON;;;;;N;;;;;
+2648;ARIES;So;0;ON;;;;;N;;;;;
+2649;TAURUS;So;0;ON;;;;;N;;;;;
+264A;GEMINI;So;0;ON;;;;;N;;;;;
+264B;CANCER;So;0;ON;;;;;N;;;;;
+264C;LEO;So;0;ON;;;;;N;;;;;
+264D;VIRGO;So;0;ON;;;;;N;;;;;
+264E;LIBRA;So;0;ON;;;;;N;;;;;
+264F;SCORPIUS;So;0;ON;;;;;N;;;;;
+2650;SAGITTARIUS;So;0;ON;;;;;N;;;;;
+2651;CAPRICORN;So;0;ON;;;;;N;;;;;
+2652;AQUARIUS;So;0;ON;;;;;N;;;;;
+2653;PISCES;So;0;ON;;;;;N;;;;;
+2654;WHITE CHESS KING;So;0;ON;;;;;N;;;;;
+2655;WHITE CHESS QUEEN;So;0;ON;;;;;N;;;;;
+2656;WHITE CHESS ROOK;So;0;ON;;;;;N;;;;;
+2657;WHITE CHESS BISHOP;So;0;ON;;;;;N;;;;;
+2658;WHITE CHESS KNIGHT;So;0;ON;;;;;N;;;;;
+2659;WHITE CHESS PAWN;So;0;ON;;;;;N;;;;;
+265A;BLACK CHESS KING;So;0;ON;;;;;N;;;;;
+265B;BLACK CHESS QUEEN;So;0;ON;;;;;N;;;;;
+265C;BLACK CHESS ROOK;So;0;ON;;;;;N;;;;;
+265D;BLACK CHESS BISHOP;So;0;ON;;;;;N;;;;;
+265E;BLACK CHESS KNIGHT;So;0;ON;;;;;N;;;;;
+265F;BLACK CHESS PAWN;So;0;ON;;;;;N;;;;;
+2660;BLACK SPADE SUIT;So;0;ON;;;;;N;;;;;
+2661;WHITE HEART SUIT;So;0;ON;;;;;N;;;;;
+2662;WHITE DIAMOND SUIT;So;0;ON;;;;;N;;;;;
+2663;BLACK CLUB SUIT;So;0;ON;;;;;N;;;;;
+2664;WHITE SPADE SUIT;So;0;ON;;;;;N;;;;;
+2665;BLACK HEART SUIT;So;0;ON;;;;;N;;;;;
+2666;BLACK DIAMOND SUIT;So;0;ON;;;;;N;;;;;
+2667;WHITE CLUB SUIT;So;0;ON;;;;;N;;;;;
+2668;HOT SPRINGS;So;0;ON;;;;;N;;;;;
+2669;QUARTER NOTE;So;0;ON;;;;;N;;;;;
+266A;EIGHTH NOTE;So;0;ON;;;;;N;;;;;
+266B;BEAMED EIGHTH NOTES;So;0;ON;;;;;N;BARRED EIGHTH NOTES;;;;
+266C;BEAMED SIXTEENTH NOTES;So;0;ON;;;;;N;BARRED SIXTEENTH NOTES;;;;
+266D;MUSIC FLAT SIGN;So;0;ON;;;;;N;FLAT;;;;
+266E;MUSIC NATURAL SIGN;So;0;ON;;;;;N;NATURAL;;;;
+266F;MUSIC SHARP SIGN;Sm;0;ON;;;;;N;SHARP;;;;
+2670;WEST SYRIAC CROSS;So;0;ON;;;;;N;;;;;
+2671;EAST SYRIAC CROSS;So;0;ON;;;;;N;;;;;
+2701;UPPER BLADE SCISSORS;So;0;ON;;;;;N;;;;;
+2702;BLACK SCISSORS;So;0;ON;;;;;N;;;;;
+2703;LOWER BLADE SCISSORS;So;0;ON;;;;;N;;;;;
+2704;WHITE SCISSORS;So;0;ON;;;;;N;;;;;
+2706;TELEPHONE LOCATION SIGN;So;0;ON;;;;;N;;;;;
+2707;TAPE DRIVE;So;0;ON;;;;;N;;;;;
+2708;AIRPLANE;So;0;ON;;;;;N;;;;;
+2709;ENVELOPE;So;0;ON;;;;;N;;;;;
+270C;VICTORY HAND;So;0;ON;;;;;N;;;;;
+270D;WRITING HAND;So;0;ON;;;;;N;;;;;
+270E;LOWER RIGHT PENCIL;So;0;ON;;;;;N;;;;;
+270F;PENCIL;So;0;ON;;;;;N;;;;;
+2710;UPPER RIGHT PENCIL;So;0;ON;;;;;N;;;;;
+2711;WHITE NIB;So;0;ON;;;;;N;;;;;
+2712;BLACK NIB;So;0;ON;;;;;N;;;;;
+2713;CHECK MARK;So;0;ON;;;;;N;;;;;
+2714;HEAVY CHECK MARK;So;0;ON;;;;;N;;;;;
+2715;MULTIPLICATION X;So;0;ON;;;;;N;;;;;
+2716;HEAVY MULTIPLICATION X;So;0;ON;;;;;N;;;;;
+2717;BALLOT X;So;0;ON;;;;;N;;;;;
+2718;HEAVY BALLOT X;So;0;ON;;;;;N;;;;;
+2719;OUTLINED GREEK CROSS;So;0;ON;;;;;N;;;;;
+271A;HEAVY GREEK CROSS;So;0;ON;;;;;N;;;;;
+271B;OPEN CENTRE CROSS;So;0;ON;;;;;N;OPEN CENTER CROSS;;;;
+271C;HEAVY OPEN CENTRE CROSS;So;0;ON;;;;;N;HEAVY OPEN CENTER CROSS;;;;
+271D;LATIN CROSS;So;0;ON;;;;;N;;;;;
+271E;SHADOWED WHITE LATIN CROSS;So;0;ON;;;;;N;;;;;
+271F;OUTLINED LATIN CROSS;So;0;ON;;;;;N;;;;;
+2720;MALTESE CROSS;So;0;ON;;;;;N;;;;;
+2721;STAR OF DAVID;So;0;ON;;;;;N;;;;;
+2722;FOUR TEARDROP-SPOKED ASTERISK;So;0;ON;;;;;N;;;;;
+2723;FOUR BALLOON-SPOKED ASTERISK;So;0;ON;;;;;N;;;;;
+2724;HEAVY FOUR BALLOON-SPOKED ASTERISK;So;0;ON;;;;;N;;;;;
+2725;FOUR CLUB-SPOKED ASTERISK;So;0;ON;;;;;N;;;;;
+2726;BLACK FOUR POINTED STAR;So;0;ON;;;;;N;;;;;
+2727;WHITE FOUR POINTED STAR;So;0;ON;;;;;N;;;;;
+2729;STRESS OUTLINED WHITE STAR;So;0;ON;;;;;N;;;;;
+272A;CIRCLED WHITE STAR;So;0;ON;;;;;N;;;;;
+272B;OPEN CENTRE BLACK STAR;So;0;ON;;;;;N;OPEN CENTER BLACK STAR;;;;
+272C;BLACK CENTRE WHITE STAR;So;0;ON;;;;;N;BLACK CENTER WHITE STAR;;;;
+272D;OUTLINED BLACK STAR;So;0;ON;;;;;N;;;;;
+272E;HEAVY OUTLINED BLACK STAR;So;0;ON;;;;;N;;;;;
+272F;PINWHEEL STAR;So;0;ON;;;;;N;;;;;
+2730;SHADOWED WHITE STAR;So;0;ON;;;;;N;;;;;
+2731;HEAVY ASTERISK;So;0;ON;;;;;N;;;;;
+2732;OPEN CENTRE ASTERISK;So;0;ON;;;;;N;OPEN CENTER ASTERISK;;;;
+2733;EIGHT SPOKED ASTERISK;So;0;ON;;;;;N;;;;;
+2734;EIGHT POINTED BLACK STAR;So;0;ON;;;;;N;;;;;
+2735;EIGHT POINTED PINWHEEL STAR;So;0;ON;;;;;N;;;;;
+2736;SIX POINTED BLACK STAR;So;0;ON;;;;;N;;;;;
+2737;EIGHT POINTED RECTILINEAR BLACK STAR;So;0;ON;;;;;N;;;;;
+2738;HEAVY EIGHT POINTED RECTILINEAR BLACK STAR;So;0;ON;;;;;N;;;;;
+2739;TWELVE POINTED BLACK STAR;So;0;ON;;;;;N;;;;;
+273A;SIXTEEN POINTED ASTERISK;So;0;ON;;;;;N;;;;;
+273B;TEARDROP-SPOKED ASTERISK;So;0;ON;;;;;N;;;;;
+273C;OPEN CENTRE TEARDROP-SPOKED ASTERISK;So;0;ON;;;;;N;OPEN CENTER TEARDROP-SPOKED ASTERISK;;;;
+273D;HEAVY TEARDROP-SPOKED ASTERISK;So;0;ON;;;;;N;;;;;
+273E;SIX PETALLED BLACK AND WHITE FLORETTE;So;0;ON;;;;;N;;;;;
+273F;BLACK FLORETTE;So;0;ON;;;;;N;;;;;
+2740;WHITE FLORETTE;So;0;ON;;;;;N;;;;;
+2741;EIGHT PETALLED OUTLINED BLACK FLORETTE;So;0;ON;;;;;N;;;;;
+2742;CIRCLED OPEN CENTRE EIGHT POINTED STAR;So;0;ON;;;;;N;CIRCLED OPEN CENTER EIGHT POINTED STAR;;;;
+2743;HEAVY TEARDROP-SPOKED PINWHEEL ASTERISK;So;0;ON;;;;;N;;;;;
+2744;SNOWFLAKE;So;0;ON;;;;;N;;;;;
+2745;TIGHT TRIFOLIATE SNOWFLAKE;So;0;ON;;;;;N;;;;;
+2746;HEAVY CHEVRON SNOWFLAKE;So;0;ON;;;;;N;;;;;
+2747;SPARKLE;So;0;ON;;;;;N;;;;;
+2748;HEAVY SPARKLE;So;0;ON;;;;;N;;;;;
+2749;BALLOON-SPOKED ASTERISK;So;0;ON;;;;;N;;;;;
+274A;EIGHT TEARDROP-SPOKED PROPELLER ASTERISK;So;0;ON;;;;;N;;;;;
+274B;HEAVY EIGHT TEARDROP-SPOKED PROPELLER ASTERISK;So;0;ON;;;;;N;;;;;
+274D;SHADOWED WHITE CIRCLE;So;0;ON;;;;;N;;;;;
+274F;LOWER RIGHT DROP-SHADOWED WHITE SQUARE;So;0;ON;;;;;N;;;;;
+2750;UPPER RIGHT DROP-SHADOWED WHITE SQUARE;So;0;ON;;;;;N;;;;;
+2751;LOWER RIGHT SHADOWED WHITE SQUARE;So;0;ON;;;;;N;;;;;
+2752;UPPER RIGHT SHADOWED WHITE SQUARE;So;0;ON;;;;;N;;;;;
+2756;BLACK DIAMOND MINUS WHITE X;So;0;ON;;;;;N;;;;;
+2758;LIGHT VERTICAL BAR;So;0;ON;;;;;N;;;;;
+2759;MEDIUM VERTICAL BAR;So;0;ON;;;;;N;;;;;
+275A;HEAVY VERTICAL BAR;So;0;ON;;;;;N;;;;;
+275B;HEAVY SINGLE TURNED COMMA QUOTATION MARK ORNAMENT;So;0;ON;;;;;N;;;;;
+275C;HEAVY SINGLE COMMA QUOTATION MARK ORNAMENT;So;0;ON;;;;;N;;;;;
+275D;HEAVY DOUBLE TURNED COMMA QUOTATION MARK ORNAMENT;So;0;ON;;;;;N;;;;;
+275E;HEAVY DOUBLE COMMA QUOTATION MARK ORNAMENT;So;0;ON;;;;;N;;;;;
+2761;CURVED STEM PARAGRAPH SIGN ORNAMENT;So;0;ON;;;;;N;;;;;
+2762;HEAVY EXCLAMATION MARK ORNAMENT;So;0;ON;;;;;N;;;;;
+2763;HEAVY HEART EXCLAMATION MARK ORNAMENT;So;0;ON;;;;;N;;;;;
+2764;HEAVY BLACK HEART;So;0;ON;;;;;N;;;;;
+2765;ROTATED HEAVY BLACK HEART BULLET;So;0;ON;;;;;N;;;;;
+2766;FLORAL HEART;So;0;ON;;;;;N;;;;;
+2767;ROTATED FLORAL HEART BULLET;So;0;ON;;;;;N;;;;;
+2776;DINGBAT NEGATIVE CIRCLED DIGIT ONE;No;0;ON;;;1;1;N;INVERSE CIRCLED DIGIT ONE;;;;
+2777;DINGBAT NEGATIVE CIRCLED DIGIT TWO;No;0;ON;;;2;2;N;INVERSE CIRCLED DIGIT TWO;;;;
+2778;DINGBAT NEGATIVE CIRCLED DIGIT THREE;No;0;ON;;;3;3;N;INVERSE CIRCLED DIGIT THREE;;;;
+2779;DINGBAT NEGATIVE CIRCLED DIGIT FOUR;No;0;ON;;;4;4;N;INVERSE CIRCLED DIGIT FOUR;;;;
+277A;DINGBAT NEGATIVE CIRCLED DIGIT FIVE;No;0;ON;;;5;5;N;INVERSE CIRCLED DIGIT FIVE;;;;
+277B;DINGBAT NEGATIVE CIRCLED DIGIT SIX;No;0;ON;;;6;6;N;INVERSE CIRCLED DIGIT SIX;;;;
+277C;DINGBAT NEGATIVE CIRCLED DIGIT SEVEN;No;0;ON;;;7;7;N;INVERSE CIRCLED DIGIT SEVEN;;;;
+277D;DINGBAT NEGATIVE CIRCLED DIGIT EIGHT;No;0;ON;;;8;8;N;INVERSE CIRCLED DIGIT EIGHT;;;;
+277E;DINGBAT NEGATIVE CIRCLED DIGIT NINE;No;0;ON;;;9;9;N;INVERSE CIRCLED DIGIT NINE;;;;
+277F;DINGBAT NEGATIVE CIRCLED NUMBER TEN;No;0;ON;;;;10;N;INVERSE CIRCLED NUMBER TEN;;;;
+2780;DINGBAT CIRCLED SANS-SERIF DIGIT ONE;No;0;ON;;;1;1;N;CIRCLED SANS-SERIF DIGIT ONE;;;;
+2781;DINGBAT CIRCLED SANS-SERIF DIGIT TWO;No;0;ON;;;2;2;N;CIRCLED SANS-SERIF DIGIT TWO;;;;
+2782;DINGBAT CIRCLED SANS-SERIF DIGIT THREE;No;0;ON;;;3;3;N;CIRCLED SANS-SERIF DIGIT THREE;;;;
+2783;DINGBAT CIRCLED SANS-SERIF DIGIT FOUR;No;0;ON;;;4;4;N;CIRCLED SANS-SERIF DIGIT FOUR;;;;
+2784;DINGBAT CIRCLED SANS-SERIF DIGIT FIVE;No;0;ON;;;5;5;N;CIRCLED SANS-SERIF DIGIT FIVE;;;;
+2785;DINGBAT CIRCLED SANS-SERIF DIGIT SIX;No;0;ON;;;6;6;N;CIRCLED SANS-SERIF DIGIT SIX;;;;
+2786;DINGBAT CIRCLED SANS-SERIF DIGIT SEVEN;No;0;ON;;;7;7;N;CIRCLED SANS-SERIF DIGIT SEVEN;;;;
+2787;DINGBAT CIRCLED SANS-SERIF DIGIT EIGHT;No;0;ON;;;8;8;N;CIRCLED SANS-SERIF DIGIT EIGHT;;;;
+2788;DINGBAT CIRCLED SANS-SERIF DIGIT NINE;No;0;ON;;;9;9;N;CIRCLED SANS-SERIF DIGIT NINE;;;;
+2789;DINGBAT CIRCLED SANS-SERIF NUMBER TEN;No;0;ON;;;;10;N;CIRCLED SANS-SERIF NUMBER TEN;;;;
+278A;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT ONE;No;0;ON;;;1;1;N;INVERSE CIRCLED SANS-SERIF DIGIT ONE;;;;
+278B;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT TWO;No;0;ON;;;2;2;N;INVERSE CIRCLED SANS-SERIF DIGIT TWO;;;;
+278C;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT THREE;No;0;ON;;;3;3;N;INVERSE CIRCLED SANS-SERIF DIGIT THREE;;;;
+278D;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT FOUR;No;0;ON;;;4;4;N;INVERSE CIRCLED SANS-SERIF DIGIT FOUR;;;;
+278E;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT FIVE;No;0;ON;;;5;5;N;INVERSE CIRCLED SANS-SERIF DIGIT FIVE;;;;
+278F;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT SIX;No;0;ON;;;6;6;N;INVERSE CIRCLED SANS-SERIF DIGIT SIX;;;;
+2790;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT SEVEN;No;0;ON;;;7;7;N;INVERSE CIRCLED SANS-SERIF DIGIT SEVEN;;;;
+2791;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT EIGHT;No;0;ON;;;8;8;N;INVERSE CIRCLED SANS-SERIF DIGIT EIGHT;;;;
+2792;DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT NINE;No;0;ON;;;9;9;N;INVERSE CIRCLED SANS-SERIF DIGIT NINE;;;;
+2793;DINGBAT NEGATIVE CIRCLED SANS-SERIF NUMBER TEN;No;0;ON;;;;10;N;INVERSE CIRCLED SANS-SERIF NUMBER TEN;;;;
+2794;HEAVY WIDE-HEADED RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY WIDE-HEADED RIGHT ARROW;;;;
+2798;HEAVY SOUTH EAST ARROW;So;0;ON;;;;;N;HEAVY LOWER RIGHT ARROW;;;;
+2799;HEAVY RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY RIGHT ARROW;;;;
+279A;HEAVY NORTH EAST ARROW;So;0;ON;;;;;N;HEAVY UPPER RIGHT ARROW;;;;
+279B;DRAFTING POINT RIGHTWARDS ARROW;So;0;ON;;;;;N;DRAFTING POINT RIGHT ARROW;;;;
+279C;HEAVY ROUND-TIPPED RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY ROUND-TIPPED RIGHT ARROW;;;;
+279D;TRIANGLE-HEADED RIGHTWARDS ARROW;So;0;ON;;;;;N;TRIANGLE-HEADED RIGHT ARROW;;;;
+279E;HEAVY TRIANGLE-HEADED RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY TRIANGLE-HEADED RIGHT ARROW;;;;
+279F;DASHED TRIANGLE-HEADED RIGHTWARDS ARROW;So;0;ON;;;;;N;DASHED TRIANGLE-HEADED RIGHT ARROW;;;;
+27A0;HEAVY DASHED TRIANGLE-HEADED RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY DASHED TRIANGLE-HEADED RIGHT ARROW;;;;
+27A1;BLACK RIGHTWARDS ARROW;So;0;ON;;;;;N;BLACK RIGHT ARROW;;;;
+27A2;THREE-D TOP-LIGHTED RIGHTWARDS ARROWHEAD;So;0;ON;;;;;N;THREE-D TOP-LIGHTED RIGHT ARROWHEAD;;;;
+27A3;THREE-D BOTTOM-LIGHTED RIGHTWARDS ARROWHEAD;So;0;ON;;;;;N;THREE-D BOTTOM-LIGHTED RIGHT ARROWHEAD;;;;
+27A4;BLACK RIGHTWARDS ARROWHEAD;So;0;ON;;;;;N;BLACK RIGHT ARROWHEAD;;;;
+27A5;HEAVY BLACK CURVED DOWNWARDS AND RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY BLACK CURVED DOWN AND RIGHT ARROW;;;;
+27A6;HEAVY BLACK CURVED UPWARDS AND RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY BLACK CURVED UP AND RIGHT ARROW;;;;
+27A7;SQUAT BLACK RIGHTWARDS ARROW;So;0;ON;;;;;N;SQUAT BLACK RIGHT ARROW;;;;
+27A8;HEAVY CONCAVE-POINTED BLACK RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY CONCAVE-POINTED BLACK RIGHT ARROW;;;;
+27A9;RIGHT-SHADED WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;RIGHT-SHADED WHITE RIGHT ARROW;;;;
+27AA;LEFT-SHADED WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;LEFT-SHADED WHITE RIGHT ARROW;;;;
+27AB;BACK-TILTED SHADOWED WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;BACK-TILTED SHADOWED WHITE RIGHT ARROW;;;;
+27AC;FRONT-TILTED SHADOWED WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;FRONT-TILTED SHADOWED WHITE RIGHT ARROW;;;;
+27AD;HEAVY LOWER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY LOWER RIGHT-SHADOWED WHITE RIGHT ARROW;;;;
+27AE;HEAVY UPPER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY UPPER RIGHT-SHADOWED WHITE RIGHT ARROW;;;;
+27AF;NOTCHED LOWER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;NOTCHED LOWER RIGHT-SHADOWED WHITE RIGHT ARROW;;;;
+27B1;NOTCHED UPPER RIGHT-SHADOWED WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;NOTCHED UPPER RIGHT-SHADOWED WHITE RIGHT ARROW;;;;
+27B2;CIRCLED HEAVY WHITE RIGHTWARDS ARROW;So;0;ON;;;;;N;CIRCLED HEAVY WHITE RIGHT ARROW;;;;
+27B3;WHITE-FEATHERED RIGHTWARDS ARROW;So;0;ON;;;;;N;WHITE-FEATHERED RIGHT ARROW;;;;
+27B4;BLACK-FEATHERED SOUTH EAST ARROW;So;0;ON;;;;;N;BLACK-FEATHERED LOWER RIGHT ARROW;;;;
+27B5;BLACK-FEATHERED RIGHTWARDS ARROW;So;0;ON;;;;;N;BLACK-FEATHERED RIGHT ARROW;;;;
+27B6;BLACK-FEATHERED NORTH EAST ARROW;So;0;ON;;;;;N;BLACK-FEATHERED UPPER RIGHT ARROW;;;;
+27B7;HEAVY BLACK-FEATHERED SOUTH EAST ARROW;So;0;ON;;;;;N;HEAVY BLACK-FEATHERED LOWER RIGHT ARROW;;;;
+27B8;HEAVY BLACK-FEATHERED RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY BLACK-FEATHERED RIGHT ARROW;;;;
+27B9;HEAVY BLACK-FEATHERED NORTH EAST ARROW;So;0;ON;;;;;N;HEAVY BLACK-FEATHERED UPPER RIGHT ARROW;;;;
+27BA;TEARDROP-BARBED RIGHTWARDS ARROW;So;0;ON;;;;;N;TEARDROP-BARBED RIGHT ARROW;;;;
+27BB;HEAVY TEARDROP-SHANKED RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY TEARDROP-SHANKED RIGHT ARROW;;;;
+27BC;WEDGE-TAILED RIGHTWARDS ARROW;So;0;ON;;;;;N;WEDGE-TAILED RIGHT ARROW;;;;
+27BD;HEAVY WEDGE-TAILED RIGHTWARDS ARROW;So;0;ON;;;;;N;HEAVY WEDGE-TAILED RIGHT ARROW;;;;
+27BE;OPEN-OUTLINED RIGHTWARDS ARROW;So;0;ON;;;;;N;OPEN-OUTLINED RIGHT ARROW;;;;
+2800;BRAILLE PATTERN BLANK;So;0;ON;;;;;N;;;;;
+2801;BRAILLE PATTERN DOTS-1;So;0;ON;;;;;N;;;;;
+2802;BRAILLE PATTERN DOTS-2;So;0;ON;;;;;N;;;;;
+2803;BRAILLE PATTERN DOTS-12;So;0;ON;;;;;N;;;;;
+2804;BRAILLE PATTERN DOTS-3;So;0;ON;;;;;N;;;;;
+2805;BRAILLE PATTERN DOTS-13;So;0;ON;;;;;N;;;;;
+2806;BRAILLE PATTERN DOTS-23;So;0;ON;;;;;N;;;;;
+2807;BRAILLE PATTERN DOTS-123;So;0;ON;;;;;N;;;;;
+2808;BRAILLE PATTERN DOTS-4;So;0;ON;;;;;N;;;;;
+2809;BRAILLE PATTERN DOTS-14;So;0;ON;;;;;N;;;;;
+280A;BRAILLE PATTERN DOTS-24;So;0;ON;;;;;N;;;;;
+280B;BRAILLE PATTERN DOTS-124;So;0;ON;;;;;N;;;;;
+280C;BRAILLE PATTERN DOTS-34;So;0;ON;;;;;N;;;;;
+280D;BRAILLE PATTERN DOTS-134;So;0;ON;;;;;N;;;;;
+280E;BRAILLE PATTERN DOTS-234;So;0;ON;;;;;N;;;;;
+280F;BRAILLE PATTERN DOTS-1234;So;0;ON;;;;;N;;;;;
+2810;BRAILLE PATTERN DOTS-5;So;0;ON;;;;;N;;;;;
+2811;BRAILLE PATTERN DOTS-15;So;0;ON;;;;;N;;;;;
+2812;BRAILLE PATTERN DOTS-25;So;0;ON;;;;;N;;;;;
+2813;BRAILLE PATTERN DOTS-125;So;0;ON;;;;;N;;;;;
+2814;BRAILLE PATTERN DOTS-35;So;0;ON;;;;;N;;;;;
+2815;BRAILLE PATTERN DOTS-135;So;0;ON;;;;;N;;;;;
+2816;BRAILLE PATTERN DOTS-235;So;0;ON;;;;;N;;;;;
+2817;BRAILLE PATTERN DOTS-1235;So;0;ON;;;;;N;;;;;
+2818;BRAILLE PATTERN DOTS-45;So;0;ON;;;;;N;;;;;
+2819;BRAILLE PATTERN DOTS-145;So;0;ON;;;;;N;;;;;
+281A;BRAILLE PATTERN DOTS-245;So;0;ON;;;;;N;;;;;
+281B;BRAILLE PATTERN DOTS-1245;So;0;ON;;;;;N;;;;;
+281C;BRAILLE PATTERN DOTS-345;So;0;ON;;;;;N;;;;;
+281D;BRAILLE PATTERN DOTS-1345;So;0;ON;;;;;N;;;;;
+281E;BRAILLE PATTERN DOTS-2345;So;0;ON;;;;;N;;;;;
+281F;BRAILLE PATTERN DOTS-12345;So;0;ON;;;;;N;;;;;
+2820;BRAILLE PATTERN DOTS-6;So;0;ON;;;;;N;;;;;
+2821;BRAILLE PATTERN DOTS-16;So;0;ON;;;;;N;;;;;
+2822;BRAILLE PATTERN DOTS-26;So;0;ON;;;;;N;;;;;
+2823;BRAILLE PATTERN DOTS-126;So;0;ON;;;;;N;;;;;
+2824;BRAILLE PATTERN DOTS-36;So;0;ON;;;;;N;;;;;
+2825;BRAILLE PATTERN DOTS-136;So;0;ON;;;;;N;;;;;
+2826;BRAILLE PATTERN DOTS-236;So;0;ON;;;;;N;;;;;
+2827;BRAILLE PATTERN DOTS-1236;So;0;ON;;;;;N;;;;;
+2828;BRAILLE PATTERN DOTS-46;So;0;ON;;;;;N;;;;;
+2829;BRAILLE PATTERN DOTS-146;So;0;ON;;;;;N;;;;;
+282A;BRAILLE PATTERN DOTS-246;So;0;ON;;;;;N;;;;;
+282B;BRAILLE PATTERN DOTS-1246;So;0;ON;;;;;N;;;;;
+282C;BRAILLE PATTERN DOTS-346;So;0;ON;;;;;N;;;;;
+282D;BRAILLE PATTERN DOTS-1346;So;0;ON;;;;;N;;;;;
+282E;BRAILLE PATTERN DOTS-2346;So;0;ON;;;;;N;;;;;
+282F;BRAILLE PATTERN DOTS-12346;So;0;ON;;;;;N;;;;;
+2830;BRAILLE PATTERN DOTS-56;So;0;ON;;;;;N;;;;;
+2831;BRAILLE PATTERN DOTS-156;So;0;ON;;;;;N;;;;;
+2832;BRAILLE PATTERN DOTS-256;So;0;ON;;;;;N;;;;;
+2833;BRAILLE PATTERN DOTS-1256;So;0;ON;;;;;N;;;;;
+2834;BRAILLE PATTERN DOTS-356;So;0;ON;;;;;N;;;;;
+2835;BRAILLE PATTERN DOTS-1356;So;0;ON;;;;;N;;;;;
+2836;BRAILLE PATTERN DOTS-2356;So;0;ON;;;;;N;;;;;
+2837;BRAILLE PATTERN DOTS-12356;So;0;ON;;;;;N;;;;;
+2838;BRAILLE PATTERN DOTS-456;So;0;ON;;;;;N;;;;;
+2839;BRAILLE PATTERN DOTS-1456;So;0;ON;;;;;N;;;;;
+283A;BRAILLE PATTERN DOTS-2456;So;0;ON;;;;;N;;;;;
+283B;BRAILLE PATTERN DOTS-12456;So;0;ON;;;;;N;;;;;
+283C;BRAILLE PATTERN DOTS-3456;So;0;ON;;;;;N;;;;;
+283D;BRAILLE PATTERN DOTS-13456;So;0;ON;;;;;N;;;;;
+283E;BRAILLE PATTERN DOTS-23456;So;0;ON;;;;;N;;;;;
+283F;BRAILLE PATTERN DOTS-123456;So;0;ON;;;;;N;;;;;
+2840;BRAILLE PATTERN DOTS-7;So;0;ON;;;;;N;;;;;
+2841;BRAILLE PATTERN DOTS-17;So;0;ON;;;;;N;;;;;
+2842;BRAILLE PATTERN DOTS-27;So;0;ON;;;;;N;;;;;
+2843;BRAILLE PATTERN DOTS-127;So;0;ON;;;;;N;;;;;
+2844;BRAILLE PATTERN DOTS-37;So;0;ON;;;;;N;;;;;
+2845;BRAILLE PATTERN DOTS-137;So;0;ON;;;;;N;;;;;
+2846;BRAILLE PATTERN DOTS-237;So;0;ON;;;;;N;;;;;
+2847;BRAILLE PATTERN DOTS-1237;So;0;ON;;;;;N;;;;;
+2848;BRAILLE PATTERN DOTS-47;So;0;ON;;;;;N;;;;;
+2849;BRAILLE PATTERN DOTS-147;So;0;ON;;;;;N;;;;;
+284A;BRAILLE PATTERN DOTS-247;So;0;ON;;;;;N;;;;;
+284B;BRAILLE PATTERN DOTS-1247;So;0;ON;;;;;N;;;;;
+284C;BRAILLE PATTERN DOTS-347;So;0;ON;;;;;N;;;;;
+284D;BRAILLE PATTERN DOTS-1347;So;0;ON;;;;;N;;;;;
+284E;BRAILLE PATTERN DOTS-2347;So;0;ON;;;;;N;;;;;
+284F;BRAILLE PATTERN DOTS-12347;So;0;ON;;;;;N;;;;;
+2850;BRAILLE PATTERN DOTS-57;So;0;ON;;;;;N;;;;;
+2851;BRAILLE PATTERN DOTS-157;So;0;ON;;;;;N;;;;;
+2852;BRAILLE PATTERN DOTS-257;So;0;ON;;;;;N;;;;;
+2853;BRAILLE PATTERN DOTS-1257;So;0;ON;;;;;N;;;;;
+2854;BRAILLE PATTERN DOTS-357;So;0;ON;;;;;N;;;;;
+2855;BRAILLE PATTERN DOTS-1357;So;0;ON;;;;;N;;;;;
+2856;BRAILLE PATTERN DOTS-2357;So;0;ON;;;;;N;;;;;
+2857;BRAILLE PATTERN DOTS-12357;So;0;ON;;;;;N;;;;;
+2858;BRAILLE PATTERN DOTS-457;So;0;ON;;;;;N;;;;;
+2859;BRAILLE PATTERN DOTS-1457;So;0;ON;;;;;N;;;;;
+285A;BRAILLE PATTERN DOTS-2457;So;0;ON;;;;;N;;;;;
+285B;BRAILLE PATTERN DOTS-12457;So;0;ON;;;;;N;;;;;
+285C;BRAILLE PATTERN DOTS-3457;So;0;ON;;;;;N;;;;;
+285D;BRAILLE PATTERN DOTS-13457;So;0;ON;;;;;N;;;;;
+285E;BRAILLE PATTERN DOTS-23457;So;0;ON;;;;;N;;;;;
+285F;BRAILLE PATTERN DOTS-123457;So;0;ON;;;;;N;;;;;
+2860;BRAILLE PATTERN DOTS-67;So;0;ON;;;;;N;;;;;
+2861;BRAILLE PATTERN DOTS-167;So;0;ON;;;;;N;;;;;
+2862;BRAILLE PATTERN DOTS-267;So;0;ON;;;;;N;;;;;
+2863;BRAILLE PATTERN DOTS-1267;So;0;ON;;;;;N;;;;;
+2864;BRAILLE PATTERN DOTS-367;So;0;ON;;;;;N;;;;;
+2865;BRAILLE PATTERN DOTS-1367;So;0;ON;;;;;N;;;;;
+2866;BRAILLE PATTERN DOTS-2367;So;0;ON;;;;;N;;;;;
+2867;BRAILLE PATTERN DOTS-12367;So;0;ON;;;;;N;;;;;
+2868;BRAILLE PATTERN DOTS-467;So;0;ON;;;;;N;;;;;
+2869;BRAILLE PATTERN DOTS-1467;So;0;ON;;;;;N;;;;;
+286A;BRAILLE PATTERN DOTS-2467;So;0;ON;;;;;N;;;;;
+286B;BRAILLE PATTERN DOTS-12467;So;0;ON;;;;;N;;;;;
+286C;BRAILLE PATTERN DOTS-3467;So;0;ON;;;;;N;;;;;
+286D;BRAILLE PATTERN DOTS-13467;So;0;ON;;;;;N;;;;;
+286E;BRAILLE PATTERN DOTS-23467;So;0;ON;;;;;N;;;;;
+286F;BRAILLE PATTERN DOTS-123467;So;0;ON;;;;;N;;;;;
+2870;BRAILLE PATTERN DOTS-567;So;0;ON;;;;;N;;;;;
+2871;BRAILLE PATTERN DOTS-1567;So;0;ON;;;;;N;;;;;
+2872;BRAILLE PATTERN DOTS-2567;So;0;ON;;;;;N;;;;;
+2873;BRAILLE PATTERN DOTS-12567;So;0;ON;;;;;N;;;;;
+2874;BRAILLE PATTERN DOTS-3567;So;0;ON;;;;;N;;;;;
+2875;BRAILLE PATTERN DOTS-13567;So;0;ON;;;;;N;;;;;
+2876;BRAILLE PATTERN DOTS-23567;So;0;ON;;;;;N;;;;;
+2877;BRAILLE PATTERN DOTS-123567;So;0;ON;;;;;N;;;;;
+2878;BRAILLE PATTERN DOTS-4567;So;0;ON;;;;;N;;;;;
+2879;BRAILLE PATTERN DOTS-14567;So;0;ON;;;;;N;;;;;
+287A;BRAILLE PATTERN DOTS-24567;So;0;ON;;;;;N;;;;;
+287B;BRAILLE PATTERN DOTS-124567;So;0;ON;;;;;N;;;;;
+287C;BRAILLE PATTERN DOTS-34567;So;0;ON;;;;;N;;;;;
+287D;BRAILLE PATTERN DOTS-134567;So;0;ON;;;;;N;;;;;
+287E;BRAILLE PATTERN DOTS-234567;So;0;ON;;;;;N;;;;;
+287F;BRAILLE PATTERN DOTS-1234567;So;0;ON;;;;;N;;;;;
+2880;BRAILLE PATTERN DOTS-8;So;0;ON;;;;;N;;;;;
+2881;BRAILLE PATTERN DOTS-18;So;0;ON;;;;;N;;;;;
+2882;BRAILLE PATTERN DOTS-28;So;0;ON;;;;;N;;;;;
+2883;BRAILLE PATTERN DOTS-128;So;0;ON;;;;;N;;;;;
+2884;BRAILLE PATTERN DOTS-38;So;0;ON;;;;;N;;;;;
+2885;BRAILLE PATTERN DOTS-138;So;0;ON;;;;;N;;;;;
+2886;BRAILLE PATTERN DOTS-238;So;0;ON;;;;;N;;;;;
+2887;BRAILLE PATTERN DOTS-1238;So;0;ON;;;;;N;;;;;
+2888;BRAILLE PATTERN DOTS-48;So;0;ON;;;;;N;;;;;
+2889;BRAILLE PATTERN DOTS-148;So;0;ON;;;;;N;;;;;
+288A;BRAILLE PATTERN DOTS-248;So;0;ON;;;;;N;;;;;
+288B;BRAILLE PATTERN DOTS-1248;So;0;ON;;;;;N;;;;;
+288C;BRAILLE PATTERN DOTS-348;So;0;ON;;;;;N;;;;;
+288D;BRAILLE PATTERN DOTS-1348;So;0;ON;;;;;N;;;;;
+288E;BRAILLE PATTERN DOTS-2348;So;0;ON;;;;;N;;;;;
+288F;BRAILLE PATTERN DOTS-12348;So;0;ON;;;;;N;;;;;
+2890;BRAILLE PATTERN DOTS-58;So;0;ON;;;;;N;;;;;
+2891;BRAILLE PATTERN DOTS-158;So;0;ON;;;;;N;;;;;
+2892;BRAILLE PATTERN DOTS-258;So;0;ON;;;;;N;;;;;
+2893;BRAILLE PATTERN DOTS-1258;So;0;ON;;;;;N;;;;;
+2894;BRAILLE PATTERN DOTS-358;So;0;ON;;;;;N;;;;;
+2895;BRAILLE PATTERN DOTS-1358;So;0;ON;;;;;N;;;;;
+2896;BRAILLE PATTERN DOTS-2358;So;0;ON;;;;;N;;;;;
+2897;BRAILLE PATTERN DOTS-12358;So;0;ON;;;;;N;;;;;
+2898;BRAILLE PATTERN DOTS-458;So;0;ON;;;;;N;;;;;
+2899;BRAILLE PATTERN DOTS-1458;So;0;ON;;;;;N;;;;;
+289A;BRAILLE PATTERN DOTS-2458;So;0;ON;;;;;N;;;;;
+289B;BRAILLE PATTERN DOTS-12458;So;0;ON;;;;;N;;;;;
+289C;BRAILLE PATTERN DOTS-3458;So;0;ON;;;;;N;;;;;
+289D;BRAILLE PATTERN DOTS-13458;So;0;ON;;;;;N;;;;;
+289E;BRAILLE PATTERN DOTS-23458;So;0;ON;;;;;N;;;;;
+289F;BRAILLE PATTERN DOTS-123458;So;0;ON;;;;;N;;;;;
+28A0;BRAILLE PATTERN DOTS-68;So;0;ON;;;;;N;;;;;
+28A1;BRAILLE PATTERN DOTS-168;So;0;ON;;;;;N;;;;;
+28A2;BRAILLE PATTERN DOTS-268;So;0;ON;;;;;N;;;;;
+28A3;BRAILLE PATTERN DOTS-1268;So;0;ON;;;;;N;;;;;
+28A4;BRAILLE PATTERN DOTS-368;So;0;ON;;;;;N;;;;;
+28A5;BRAILLE PATTERN DOTS-1368;So;0;ON;;;;;N;;;;;
+28A6;BRAILLE PATTERN DOTS-2368;So;0;ON;;;;;N;;;;;
+28A7;BRAILLE PATTERN DOTS-12368;So;0;ON;;;;;N;;;;;
+28A8;BRAILLE PATTERN DOTS-468;So;0;ON;;;;;N;;;;;
+28A9;BRAILLE PATTERN DOTS-1468;So;0;ON;;;;;N;;;;;
+28AA;BRAILLE PATTERN DOTS-2468;So;0;ON;;;;;N;;;;;
+28AB;BRAILLE PATTERN DOTS-12468;So;0;ON;;;;;N;;;;;
+28AC;BRAILLE PATTERN DOTS-3468;So;0;ON;;;;;N;;;;;
+28AD;BRAILLE PATTERN DOTS-13468;So;0;ON;;;;;N;;;;;
+28AE;BRAILLE PATTERN DOTS-23468;So;0;ON;;;;;N;;;;;
+28AF;BRAILLE PATTERN DOTS-123468;So;0;ON;;;;;N;;;;;
+28B0;BRAILLE PATTERN DOTS-568;So;0;ON;;;;;N;;;;;
+28B1;BRAILLE PATTERN DOTS-1568;So;0;ON;;;;;N;;;;;
+28B2;BRAILLE PATTERN DOTS-2568;So;0;ON;;;;;N;;;;;
+28B3;BRAILLE PATTERN DOTS-12568;So;0;ON;;;;;N;;;;;
+28B4;BRAILLE PATTERN DOTS-3568;So;0;ON;;;;;N;;;;;
+28B5;BRAILLE PATTERN DOTS-13568;So;0;ON;;;;;N;;;;;
+28B6;BRAILLE PATTERN DOTS-23568;So;0;ON;;;;;N;;;;;
+28B7;BRAILLE PATTERN DOTS-123568;So;0;ON;;;;;N;;;;;
+28B8;BRAILLE PATTERN DOTS-4568;So;0;ON;;;;;N;;;;;
+28B9;BRAILLE PATTERN DOTS-14568;So;0;ON;;;;;N;;;;;
+28BA;BRAILLE PATTERN DOTS-24568;So;0;ON;;;;;N;;;;;
+28BB;BRAILLE PATTERN DOTS-124568;So;0;ON;;;;;N;;;;;
+28BC;BRAILLE PATTERN DOTS-34568;So;0;ON;;;;;N;;;;;
+28BD;BRAILLE PATTERN DOTS-134568;So;0;ON;;;;;N;;;;;
+28BE;BRAILLE PATTERN DOTS-234568;So;0;ON;;;;;N;;;;;
+28BF;BRAILLE PATTERN DOTS-1234568;So;0;ON;;;;;N;;;;;
+28C0;BRAILLE PATTERN DOTS-78;So;0;ON;;;;;N;;;;;
+28C1;BRAILLE PATTERN DOTS-178;So;0;ON;;;;;N;;;;;
+28C2;BRAILLE PATTERN DOTS-278;So;0;ON;;;;;N;;;;;
+28C3;BRAILLE PATTERN DOTS-1278;So;0;ON;;;;;N;;;;;
+28C4;BRAILLE PATTERN DOTS-378;So;0;ON;;;;;N;;;;;
+28C5;BRAILLE PATTERN DOTS-1378;So;0;ON;;;;;N;;;;;
+28C6;BRAILLE PATTERN DOTS-2378;So;0;ON;;;;;N;;;;;
+28C7;BRAILLE PATTERN DOTS-12378;So;0;ON;;;;;N;;;;;
+28C8;BRAILLE PATTERN DOTS-478;So;0;ON;;;;;N;;;;;
+28C9;BRAILLE PATTERN DOTS-1478;So;0;ON;;;;;N;;;;;
+28CA;BRAILLE PATTERN DOTS-2478;So;0;ON;;;;;N;;;;;
+28CB;BRAILLE PATTERN DOTS-12478;So;0;ON;;;;;N;;;;;
+28CC;BRAILLE PATTERN DOTS-3478;So;0;ON;;;;;N;;;;;
+28CD;BRAILLE PATTERN DOTS-13478;So;0;ON;;;;;N;;;;;
+28CE;BRAILLE PATTERN DOTS-23478;So;0;ON;;;;;N;;;;;
+28CF;BRAILLE PATTERN DOTS-123478;So;0;ON;;;;;N;;;;;
+28D0;BRAILLE PATTERN DOTS-578;So;0;ON;;;;;N;;;;;
+28D1;BRAILLE PATTERN DOTS-1578;So;0;ON;;;;;N;;;;;
+28D2;BRAILLE PATTERN DOTS-2578;So;0;ON;;;;;N;;;;;
+28D3;BRAILLE PATTERN DOTS-12578;So;0;ON;;;;;N;;;;;
+28D4;BRAILLE PATTERN DOTS-3578;So;0;ON;;;;;N;;;;;
+28D5;BRAILLE PATTERN DOTS-13578;So;0;ON;;;;;N;;;;;
+28D6;BRAILLE PATTERN DOTS-23578;So;0;ON;;;;;N;;;;;
+28D7;BRAILLE PATTERN DOTS-123578;So;0;ON;;;;;N;;;;;
+28D8;BRAILLE PATTERN DOTS-4578;So;0;ON;;;;;N;;;;;
+28D9;BRAILLE PATTERN DOTS-14578;So;0;ON;;;;;N;;;;;
+28DA;BRAILLE PATTERN DOTS-24578;So;0;ON;;;;;N;;;;;
+28DB;BRAILLE PATTERN DOTS-124578;So;0;ON;;;;;N;;;;;
+28DC;BRAILLE PATTERN DOTS-34578;So;0;ON;;;;;N;;;;;
+28DD;BRAILLE PATTERN DOTS-134578;So;0;ON;;;;;N;;;;;
+28DE;BRAILLE PATTERN DOTS-234578;So;0;ON;;;;;N;;;;;
+28DF;BRAILLE PATTERN DOTS-1234578;So;0;ON;;;;;N;;;;;
+28E0;BRAILLE PATTERN DOTS-678;So;0;ON;;;;;N;;;;;
+28E1;BRAILLE PATTERN DOTS-1678;So;0;ON;;;;;N;;;;;
+28E2;BRAILLE PATTERN DOTS-2678;So;0;ON;;;;;N;;;;;
+28E3;BRAILLE PATTERN DOTS-12678;So;0;ON;;;;;N;;;;;
+28E4;BRAILLE PATTERN DOTS-3678;So;0;ON;;;;;N;;;;;
+28E5;BRAILLE PATTERN DOTS-13678;So;0;ON;;;;;N;;;;;
+28E6;BRAILLE PATTERN DOTS-23678;So;0;ON;;;;;N;;;;;
+28E7;BRAILLE PATTERN DOTS-123678;So;0;ON;;;;;N;;;;;
+28E8;BRAILLE PATTERN DOTS-4678;So;0;ON;;;;;N;;;;;
+28E9;BRAILLE PATTERN DOTS-14678;So;0;ON;;;;;N;;;;;
+28EA;BRAILLE PATTERN DOTS-24678;So;0;ON;;;;;N;;;;;
+28EB;BRAILLE PATTERN DOTS-124678;So;0;ON;;;;;N;;;;;
+28EC;BRAILLE PATTERN DOTS-34678;So;0;ON;;;;;N;;;;;
+28ED;BRAILLE PATTERN DOTS-134678;So;0;ON;;;;;N;;;;;
+28EE;BRAILLE PATTERN DOTS-234678;So;0;ON;;;;;N;;;;;
+28EF;BRAILLE PATTERN DOTS-1234678;So;0;ON;;;;;N;;;;;
+28F0;BRAILLE PATTERN DOTS-5678;So;0;ON;;;;;N;;;;;
+28F1;BRAILLE PATTERN DOTS-15678;So;0;ON;;;;;N;;;;;
+28F2;BRAILLE PATTERN DOTS-25678;So;0;ON;;;;;N;;;;;
+28F3;BRAILLE PATTERN DOTS-125678;So;0;ON;;;;;N;;;;;
+28F4;BRAILLE PATTERN DOTS-35678;So;0;ON;;;;;N;;;;;
+28F5;BRAILLE PATTERN DOTS-135678;So;0;ON;;;;;N;;;;;
+28F6;BRAILLE PATTERN DOTS-235678;So;0;ON;;;;;N;;;;;
+28F7;BRAILLE PATTERN DOTS-1235678;So;0;ON;;;;;N;;;;;
+28F8;BRAILLE PATTERN DOTS-45678;So;0;ON;;;;;N;;;;;
+28F9;BRAILLE PATTERN DOTS-145678;So;0;ON;;;;;N;;;;;
+28FA;BRAILLE PATTERN DOTS-245678;So;0;ON;;;;;N;;;;;
+28FB;BRAILLE PATTERN DOTS-1245678;So;0;ON;;;;;N;;;;;
+28FC;BRAILLE PATTERN DOTS-345678;So;0;ON;;;;;N;;;;;
+28FD;BRAILLE PATTERN DOTS-1345678;So;0;ON;;;;;N;;;;;
+28FE;BRAILLE PATTERN DOTS-2345678;So;0;ON;;;;;N;;;;;
+28FF;BRAILLE PATTERN DOTS-12345678;So;0;ON;;;;;N;;;;;
+2E80;CJK RADICAL REPEAT;So;0;ON;;;;;N;;;;;
+2E81;CJK RADICAL CLIFF;So;0;ON;;;;;N;;;;;
+2E82;CJK RADICAL SECOND ONE;So;0;ON;;;;;N;;;;;
+2E83;CJK RADICAL SECOND TWO;So;0;ON;;;;;N;;;;;
+2E84;CJK RADICAL SECOND THREE;So;0;ON;;;;;N;;;;;
+2E85;CJK RADICAL PERSON;So;0;ON;;;;;N;;;;;
+2E86;CJK RADICAL BOX;So;0;ON;;;;;N;;;;;
+2E87;CJK RADICAL TABLE;So;0;ON;;;;;N;;;;;
+2E88;CJK RADICAL KNIFE ONE;So;0;ON;;;;;N;;;;;
+2E89;CJK RADICAL KNIFE TWO;So;0;ON;;;;;N;;;;;
+2E8A;CJK RADICAL DIVINATION;So;0;ON;;;;;N;;;;;
+2E8B;CJK RADICAL SEAL;So;0;ON;;;;;N;;;;;
+2E8C;CJK RADICAL SMALL ONE;So;0;ON;;;;;N;;;;;
+2E8D;CJK RADICAL SMALL TWO;So;0;ON;;;;;N;;;;;
+2E8E;CJK RADICAL LAME ONE;So;0;ON;;;;;N;;;;;
+2E8F;CJK RADICAL LAME TWO;So;0;ON;;;;;N;;;;;
+2E90;CJK RADICAL LAME THREE;So;0;ON;;;;;N;;;;;
+2E91;CJK RADICAL LAME FOUR;So;0;ON;;;;;N;;;;;
+2E92;CJK RADICAL SNAKE;So;0;ON;;;;;N;;;;;
+2E93;CJK RADICAL THREAD;So;0;ON;;;;;N;;;;;
+2E94;CJK RADICAL SNOUT ONE;So;0;ON;;;;;N;;;;;
+2E95;CJK RADICAL SNOUT TWO;So;0;ON;;;;;N;;;;;
+2E96;CJK RADICAL HEART ONE;So;0;ON;;;;;N;;;;;
+2E97;CJK RADICAL HEART TWO;So;0;ON;;;;;N;;;;;
+2E98;CJK RADICAL HAND;So;0;ON;;;;;N;;;;;
+2E99;CJK RADICAL RAP;So;0;ON;;;;;N;;;;;
+2E9B;CJK RADICAL CHOKE;So;0;ON;;;;;N;;;;;
+2E9C;CJK RADICAL SUN;So;0;ON;;;;;N;;;;;
+2E9D;CJK RADICAL MOON;So;0;ON;;;;;N;;;;;
+2E9E;CJK RADICAL DEATH;So;0;ON;;;;;N;;;;;
+2E9F;CJK RADICAL MOTHER;So;0;ON;<compat> 6BCD;;;;N;;;;;
+2EA0;CJK RADICAL CIVILIAN;So;0;ON;;;;;N;;;;;
+2EA1;CJK RADICAL WATER ONE;So;0;ON;;;;;N;;;;;
+2EA2;CJK RADICAL WATER TWO;So;0;ON;;;;;N;;;;;
+2EA3;CJK RADICAL FIRE;So;0;ON;;;;;N;;;;;
+2EA4;CJK RADICAL PAW ONE;So;0;ON;;;;;N;;;;;
+2EA5;CJK RADICAL PAW TWO;So;0;ON;;;;;N;;;;;
+2EA6;CJK RADICAL SIMPLIFIED HALF TREE TRUNK;So;0;ON;;;;;N;;;;;
+2EA7;CJK RADICAL COW;So;0;ON;;;;;N;;;;;
+2EA8;CJK RADICAL DOG;So;0;ON;;;;;N;;;;;
+2EA9;CJK RADICAL JADE;So;0;ON;;;;;N;;;;;
+2EAA;CJK RADICAL BOLT OF CLOTH;So;0;ON;;;;;N;;;;;
+2EAB;CJK RADICAL EYE;So;0;ON;;;;;N;;;;;
+2EAC;CJK RADICAL SPIRIT ONE;So;0;ON;;;;;N;;;;;
+2EAD;CJK RADICAL SPIRIT TWO;So;0;ON;;;;;N;;;;;
+2EAE;CJK RADICAL BAMBOO;So;0;ON;;;;;N;;;;;
+2EAF;CJK RADICAL SILK;So;0;ON;;;;;N;;;;;
+2EB0;CJK RADICAL C-SIMPLIFIED SILK;So;0;ON;;;;;N;;;;;
+2EB1;CJK RADICAL NET ONE;So;0;ON;;;;;N;;;;;
+2EB2;CJK RADICAL NET TWO;So;0;ON;;;;;N;;;;;
+2EB3;CJK RADICAL NET THREE;So;0;ON;;;;;N;;;;;
+2EB4;CJK RADICAL NET FOUR;So;0;ON;;;;;N;;;;;
+2EB5;CJK RADICAL MESH;So;0;ON;;;;;N;;;;;
+2EB6;CJK RADICAL SHEEP;So;0;ON;;;;;N;;;;;
+2EB7;CJK RADICAL RAM;So;0;ON;;;;;N;;;;;
+2EB8;CJK RADICAL EWE;So;0;ON;;;;;N;;;;;
+2EB9;CJK RADICAL OLD;So;0;ON;;;;;N;;;;;
+2EBA;CJK RADICAL BRUSH ONE;So;0;ON;;;;;N;;;;;
+2EBB;CJK RADICAL BRUSH TWO;So;0;ON;;;;;N;;;;;
+2EBC;CJK RADICAL MEAT;So;0;ON;;;;;N;;;;;
+2EBD;CJK RADICAL MORTAR;So;0;ON;;;;;N;;;;;
+2EBE;CJK RADICAL GRASS ONE;So;0;ON;;;;;N;;;;;
+2EBF;CJK RADICAL GRASS TWO;So;0;ON;;;;;N;;;;;
+2EC0;CJK RADICAL GRASS THREE;So;0;ON;;;;;N;;;;;
+2EC1;CJK RADICAL TIGER;So;0;ON;;;;;N;;;;;
+2EC2;CJK RADICAL CLOTHES;So;0;ON;;;;;N;;;;;
+2EC3;CJK RADICAL WEST ONE;So;0;ON;;;;;N;;;;;
+2EC4;CJK RADICAL WEST TWO;So;0;ON;;;;;N;;;;;
+2EC5;CJK RADICAL C-SIMPLIFIED SEE;So;0;ON;;;;;N;;;;;
+2EC6;CJK RADICAL SIMPLIFIED HORN;So;0;ON;;;;;N;;;;;
+2EC7;CJK RADICAL HORN;So;0;ON;;;;;N;;;;;
+2EC8;CJK RADICAL C-SIMPLIFIED SPEECH;So;0;ON;;;;;N;;;;;
+2EC9;CJK RADICAL C-SIMPLIFIED SHELL;So;0;ON;;;;;N;;;;;
+2ECA;CJK RADICAL FOOT;So;0;ON;;;;;N;;;;;
+2ECB;CJK RADICAL C-SIMPLIFIED CART;So;0;ON;;;;;N;;;;;
+2ECC;CJK RADICAL SIMPLIFIED WALK;So;0;ON;;;;;N;;;;;
+2ECD;CJK RADICAL WALK ONE;So;0;ON;;;;;N;;;;;
+2ECE;CJK RADICAL WALK TWO;So;0;ON;;;;;N;;;;;
+2ECF;CJK RADICAL CITY;So;0;ON;;;;;N;;;;;
+2ED0;CJK RADICAL C-SIMPLIFIED GOLD;So;0;ON;;;;;N;;;;;
+2ED1;CJK RADICAL LONG ONE;So;0;ON;;;;;N;;;;;
+2ED2;CJK RADICAL LONG TWO;So;0;ON;;;;;N;;;;;
+2ED3;CJK RADICAL C-SIMPLIFIED LONG;So;0;ON;;;;;N;;;;;
+2ED4;CJK RADICAL C-SIMPLIFIED GATE;So;0;ON;;;;;N;;;;;
+2ED5;CJK RADICAL MOUND ONE;So;0;ON;;;;;N;;;;;
+2ED6;CJK RADICAL MOUND TWO;So;0;ON;;;;;N;;;;;
+2ED7;CJK RADICAL RAIN;So;0;ON;;;;;N;;;;;
+2ED8;CJK RADICAL BLUE;So;0;ON;;;;;N;;;;;
+2ED9;CJK RADICAL C-SIMPLIFIED TANNED LEATHER;So;0;ON;;;;;N;;;;;
+2EDA;CJK RADICAL C-SIMPLIFIED LEAF;So;0;ON;;;;;N;;;;;
+2EDB;CJK RADICAL C-SIMPLIFIED WIND;So;0;ON;;;;;N;;;;;
+2EDC;CJK RADICAL C-SIMPLIFIED FLY;So;0;ON;;;;;N;;;;;
+2EDD;CJK RADICAL EAT ONE;So;0;ON;;;;;N;;;;;
+2EDE;CJK RADICAL EAT TWO;So;0;ON;;;;;N;;;;;
+2EDF;CJK RADICAL EAT THREE;So;0;ON;;;;;N;;;;;
+2EE0;CJK RADICAL C-SIMPLIFIED EAT;So;0;ON;;;;;N;;;;;
+2EE1;CJK RADICAL HEAD;So;0;ON;;;;;N;;;;;
+2EE2;CJK RADICAL C-SIMPLIFIED HORSE;So;0;ON;;;;;N;;;;;
+2EE3;CJK RADICAL BONE;So;0;ON;;;;;N;;;;;
+2EE4;CJK RADICAL GHOST;So;0;ON;;;;;N;;;;;
+2EE5;CJK RADICAL C-SIMPLIFIED FISH;So;0;ON;;;;;N;;;;;
+2EE6;CJK RADICAL C-SIMPLIFIED BIRD;So;0;ON;;;;;N;;;;;
+2EE7;CJK RADICAL C-SIMPLIFIED SALT;So;0;ON;;;;;N;;;;;
+2EE8;CJK RADICAL SIMPLIFIED WHEAT;So;0;ON;;;;;N;;;;;
+2EE9;CJK RADICAL SIMPLIFIED YELLOW;So;0;ON;;;;;N;;;;;
+2EEA;CJK RADICAL C-SIMPLIFIED FROG;So;0;ON;;;;;N;;;;;
+2EEB;CJK RADICAL J-SIMPLIFIED EVEN;So;0;ON;;;;;N;;;;;
+2EEC;CJK RADICAL C-SIMPLIFIED EVEN;So;0;ON;;;;;N;;;;;
+2EED;CJK RADICAL J-SIMPLIFIED TOOTH;So;0;ON;;;;;N;;;;;
+2EEE;CJK RADICAL C-SIMPLIFIED TOOTH;So;0;ON;;;;;N;;;;;
+2EEF;CJK RADICAL J-SIMPLIFIED DRAGON;So;0;ON;;;;;N;;;;;
+2EF0;CJK RADICAL C-SIMPLIFIED DRAGON;So;0;ON;;;;;N;;;;;
+2EF1;CJK RADICAL TURTLE;So;0;ON;;;;;N;;;;;
+2EF2;CJK RADICAL J-SIMPLIFIED TURTLE;So;0;ON;;;;;N;;;;;
+2EF3;CJK RADICAL C-SIMPLIFIED TURTLE;So;0;ON;<compat> 9F9F;;;;N;;;;;
+2F00;KANGXI RADICAL ONE;So;0;ON;<compat> 4E00;;;;N;;;;;
+2F01;KANGXI RADICAL LINE;So;0;ON;<compat> 4E28;;;;N;;;;;
+2F02;KANGXI RADICAL DOT;So;0;ON;<compat> 4E36;;;;N;;;;;
+2F03;KANGXI RADICAL SLASH;So;0;ON;<compat> 4E3F;;;;N;;;;;
+2F04;KANGXI RADICAL SECOND;So;0;ON;<compat> 4E59;;;;N;;;;;
+2F05;KANGXI RADICAL HOOK;So;0;ON;<compat> 4E85;;;;N;;;;;
+2F06;KANGXI RADICAL TWO;So;0;ON;<compat> 4E8C;;;;N;;;;;
+2F07;KANGXI RADICAL LID;So;0;ON;<compat> 4EA0;;;;N;;;;;
+2F08;KANGXI RADICAL MAN;So;0;ON;<compat> 4EBA;;;;N;;;;;
+2F09;KANGXI RADICAL LEGS;So;0;ON;<compat> 513F;;;;N;;;;;
+2F0A;KANGXI RADICAL ENTER;So;0;ON;<compat> 5165;;;;N;;;;;
+2F0B;KANGXI RADICAL EIGHT;So;0;ON;<compat> 516B;;;;N;;;;;
+2F0C;KANGXI RADICAL DOWN BOX;So;0;ON;<compat> 5182;;;;N;;;;;
+2F0D;KANGXI RADICAL COVER;So;0;ON;<compat> 5196;;;;N;;;;;
+2F0E;KANGXI RADICAL ICE;So;0;ON;<compat> 51AB;;;;N;;;;;
+2F0F;KANGXI RADICAL TABLE;So;0;ON;<compat> 51E0;;;;N;;;;;
+2F10;KANGXI RADICAL OPEN BOX;So;0;ON;<compat> 51F5;;;;N;;;;;
+2F11;KANGXI RADICAL KNIFE;So;0;ON;<compat> 5200;;;;N;;;;;
+2F12;KANGXI RADICAL POWER;So;0;ON;<compat> 529B;;;;N;;;;;
+2F13;KANGXI RADICAL WRAP;So;0;ON;<compat> 52F9;;;;N;;;;;
+2F14;KANGXI RADICAL SPOON;So;0;ON;<compat> 5315;;;;N;;;;;
+2F15;KANGXI RADICAL RIGHT OPEN BOX;So;0;ON;<compat> 531A;;;;N;;;;;
+2F16;KANGXI RADICAL HIDING ENCLOSURE;So;0;ON;<compat> 5338;;;;N;;;;;
+2F17;KANGXI RADICAL TEN;So;0;ON;<compat> 5341;;;;N;;;;;
+2F18;KANGXI RADICAL DIVINATION;So;0;ON;<compat> 535C;;;;N;;;;;
+2F19;KANGXI RADICAL SEAL;So;0;ON;<compat> 5369;;;;N;;;;;
+2F1A;KANGXI RADICAL CLIFF;So;0;ON;<compat> 5382;;;;N;;;;;
+2F1B;KANGXI RADICAL PRIVATE;So;0;ON;<compat> 53B6;;;;N;;;;;
+2F1C;KANGXI RADICAL AGAIN;So;0;ON;<compat> 53C8;;;;N;;;;;
+2F1D;KANGXI RADICAL MOUTH;So;0;ON;<compat> 53E3;;;;N;;;;;
+2F1E;KANGXI RADICAL ENCLOSURE;So;0;ON;<compat> 56D7;;;;N;;;;;
+2F1F;KANGXI RADICAL EARTH;So;0;ON;<compat> 571F;;;;N;;;;;
+2F20;KANGXI RADICAL SCHOLAR;So;0;ON;<compat> 58EB;;;;N;;;;;
+2F21;KANGXI RADICAL GO;So;0;ON;<compat> 5902;;;;N;;;;;
+2F22;KANGXI RADICAL GO SLOWLY;So;0;ON;<compat> 590A;;;;N;;;;;
+2F23;KANGXI RADICAL EVENING;So;0;ON;<compat> 5915;;;;N;;;;;
+2F24;KANGXI RADICAL BIG;So;0;ON;<compat> 5927;;;;N;;;;;
+2F25;KANGXI RADICAL WOMAN;So;0;ON;<compat> 5973;;;;N;;;;;
+2F26;KANGXI RADICAL CHILD;So;0;ON;<compat> 5B50;;;;N;;;;;
+2F27;KANGXI RADICAL ROOF;So;0;ON;<compat> 5B80;;;;N;;;;;
+2F28;KANGXI RADICAL INCH;So;0;ON;<compat> 5BF8;;;;N;;;;;
+2F29;KANGXI RADICAL SMALL;So;0;ON;<compat> 5C0F;;;;N;;;;;
+2F2A;KANGXI RADICAL LAME;So;0;ON;<compat> 5C22;;;;N;;;;;
+2F2B;KANGXI RADICAL CORPSE;So;0;ON;<compat> 5C38;;;;N;;;;;
+2F2C;KANGXI RADICAL SPROUT;So;0;ON;<compat> 5C6E;;;;N;;;;;
+2F2D;KANGXI RADICAL MOUNTAIN;So;0;ON;<compat> 5C71;;;;N;;;;;
+2F2E;KANGXI RADICAL RIVER;So;0;ON;<compat> 5DDB;;;;N;;;;;
+2F2F;KANGXI RADICAL WORK;So;0;ON;<compat> 5DE5;;;;N;;;;;
+2F30;KANGXI RADICAL ONESELF;So;0;ON;<compat> 5DF1;;;;N;;;;;
+2F31;KANGXI RADICAL TURBAN;So;0;ON;<compat> 5DFE;;;;N;;;;;
+2F32;KANGXI RADICAL DRY;So;0;ON;<compat> 5E72;;;;N;;;;;
+2F33;KANGXI RADICAL SHORT THREAD;So;0;ON;<compat> 5E7A;;;;N;;;;;
+2F34;KANGXI RADICAL DOTTED CLIFF;So;0;ON;<compat> 5E7F;;;;N;;;;;
+2F35;KANGXI RADICAL LONG STRIDE;So;0;ON;<compat> 5EF4;;;;N;;;;;
+2F36;KANGXI RADICAL TWO HANDS;So;0;ON;<compat> 5EFE;;;;N;;;;;
+2F37;KANGXI RADICAL SHOOT;So;0;ON;<compat> 5F0B;;;;N;;;;;
+2F38;KANGXI RADICAL BOW;So;0;ON;<compat> 5F13;;;;N;;;;;
+2F39;KANGXI RADICAL SNOUT;So;0;ON;<compat> 5F50;;;;N;;;;;
+2F3A;KANGXI RADICAL BRISTLE;So;0;ON;<compat> 5F61;;;;N;;;;;
+2F3B;KANGXI RADICAL STEP;So;0;ON;<compat> 5F73;;;;N;;;;;
+2F3C;KANGXI RADICAL HEART;So;0;ON;<compat> 5FC3;;;;N;;;;;
+2F3D;KANGXI RADICAL HALBERD;So;0;ON;<compat> 6208;;;;N;;;;;
+2F3E;KANGXI RADICAL DOOR;So;0;ON;<compat> 6236;;;;N;;;;;
+2F3F;KANGXI RADICAL HAND;So;0;ON;<compat> 624B;;;;N;;;;;
+2F40;KANGXI RADICAL BRANCH;So;0;ON;<compat> 652F;;;;N;;;;;
+2F41;KANGXI RADICAL RAP;So;0;ON;<compat> 6534;;;;N;;;;;
+2F42;KANGXI RADICAL SCRIPT;So;0;ON;<compat> 6587;;;;N;;;;;
+2F43;KANGXI RADICAL DIPPER;So;0;ON;<compat> 6597;;;;N;;;;;
+2F44;KANGXI RADICAL AXE;So;0;ON;<compat> 65A4;;;;N;;;;;
+2F45;KANGXI RADICAL SQUARE;So;0;ON;<compat> 65B9;;;;N;;;;;
+2F46;KANGXI RADICAL NOT;So;0;ON;<compat> 65E0;;;;N;;;;;
+2F47;KANGXI RADICAL SUN;So;0;ON;<compat> 65E5;;;;N;;;;;
+2F48;KANGXI RADICAL SAY;So;0;ON;<compat> 66F0;;;;N;;;;;
+2F49;KANGXI RADICAL MOON;So;0;ON;<compat> 6708;;;;N;;;;;
+2F4A;KANGXI RADICAL TREE;So;0;ON;<compat> 6728;;;;N;;;;;
+2F4B;KANGXI RADICAL LACK;So;0;ON;<compat> 6B20;;;;N;;;;;
+2F4C;KANGXI RADICAL STOP;So;0;ON;<compat> 6B62;;;;N;;;;;
+2F4D;KANGXI RADICAL DEATH;So;0;ON;<compat> 6B79;;;;N;;;;;
+2F4E;KANGXI RADICAL WEAPON;So;0;ON;<compat> 6BB3;;;;N;;;;;
+2F4F;KANGXI RADICAL DO NOT;So;0;ON;<compat> 6BCB;;;;N;;;;;
+2F50;KANGXI RADICAL COMPARE;So;0;ON;<compat> 6BD4;;;;N;;;;;
+2F51;KANGXI RADICAL FUR;So;0;ON;<compat> 6BDB;;;;N;;;;;
+2F52;KANGXI RADICAL CLAN;So;0;ON;<compat> 6C0F;;;;N;;;;;
+2F53;KANGXI RADICAL STEAM;So;0;ON;<compat> 6C14;;;;N;;;;;
+2F54;KANGXI RADICAL WATER;So;0;ON;<compat> 6C34;;;;N;;;;;
+2F55;KANGXI RADICAL FIRE;So;0;ON;<compat> 706B;;;;N;;;;;
+2F56;KANGXI RADICAL CLAW;So;0;ON;<compat> 722A;;;;N;;;;;
+2F57;KANGXI RADICAL FATHER;So;0;ON;<compat> 7236;;;;N;;;;;
+2F58;KANGXI RADICAL DOUBLE X;So;0;ON;<compat> 723B;;;;N;;;;;
+2F59;KANGXI RADICAL HALF TREE TRUNK;So;0;ON;<compat> 723F;;;;N;;;;;
+2F5A;KANGXI RADICAL SLICE;So;0;ON;<compat> 7247;;;;N;;;;;
+2F5B;KANGXI RADICAL FANG;So;0;ON;<compat> 7259;;;;N;;;;;
+2F5C;KANGXI RADICAL COW;So;0;ON;<compat> 725B;;;;N;;;;;
+2F5D;KANGXI RADICAL DOG;So;0;ON;<compat> 72AC;;;;N;;;;;
+2F5E;KANGXI RADICAL PROFOUND;So;0;ON;<compat> 7384;;;;N;;;;;
+2F5F;KANGXI RADICAL JADE;So;0;ON;<compat> 7389;;;;N;;;;;
+2F60;KANGXI RADICAL MELON;So;0;ON;<compat> 74DC;;;;N;;;;;
+2F61;KANGXI RADICAL TILE;So;0;ON;<compat> 74E6;;;;N;;;;;
+2F62;KANGXI RADICAL SWEET;So;0;ON;<compat> 7518;;;;N;;;;;
+2F63;KANGXI RADICAL LIFE;So;0;ON;<compat> 751F;;;;N;;;;;
+2F64;KANGXI RADICAL USE;So;0;ON;<compat> 7528;;;;N;;;;;
+2F65;KANGXI RADICAL FIELD;So;0;ON;<compat> 7530;;;;N;;;;;
+2F66;KANGXI RADICAL BOLT OF CLOTH;So;0;ON;<compat> 758B;;;;N;;;;;
+2F67;KANGXI RADICAL SICKNESS;So;0;ON;<compat> 7592;;;;N;;;;;
+2F68;KANGXI RADICAL DOTTED TENT;So;0;ON;<compat> 7676;;;;N;;;;;
+2F69;KANGXI RADICAL WHITE;So;0;ON;<compat> 767D;;;;N;;;;;
+2F6A;KANGXI RADICAL SKIN;So;0;ON;<compat> 76AE;;;;N;;;;;
+2F6B;KANGXI RADICAL DISH;So;0;ON;<compat> 76BF;;;;N;;;;;
+2F6C;KANGXI RADICAL EYE;So;0;ON;<compat> 76EE;;;;N;;;;;
+2F6D;KANGXI RADICAL SPEAR;So;0;ON;<compat> 77DB;;;;N;;;;;
+2F6E;KANGXI RADICAL ARROW;So;0;ON;<compat> 77E2;;;;N;;;;;
+2F6F;KANGXI RADICAL STONE;So;0;ON;<compat> 77F3;;;;N;;;;;
+2F70;KANGXI RADICAL SPIRIT;So;0;ON;<compat> 793A;;;;N;;;;;
+2F71;KANGXI RADICAL TRACK;So;0;ON;<compat> 79B8;;;;N;;;;;
+2F72;KANGXI RADICAL GRAIN;So;0;ON;<compat> 79BE;;;;N;;;;;
+2F73;KANGXI RADICAL CAVE;So;0;ON;<compat> 7A74;;;;N;;;;;
+2F74;KANGXI RADICAL STAND;So;0;ON;<compat> 7ACB;;;;N;;;;;
+2F75;KANGXI RADICAL BAMBOO;So;0;ON;<compat> 7AF9;;;;N;;;;;
+2F76;KANGXI RADICAL RICE;So;0;ON;<compat> 7C73;;;;N;;;;;
+2F77;KANGXI RADICAL SILK;So;0;ON;<compat> 7CF8;;;;N;;;;;
+2F78;KANGXI RADICAL JAR;So;0;ON;<compat> 7F36;;;;N;;;;;
+2F79;KANGXI RADICAL NET;So;0;ON;<compat> 7F51;;;;N;;;;;
+2F7A;KANGXI RADICAL SHEEP;So;0;ON;<compat> 7F8A;;;;N;;;;;
+2F7B;KANGXI RADICAL FEATHER;So;0;ON;<compat> 7FBD;;;;N;;;;;
+2F7C;KANGXI RADICAL OLD;So;0;ON;<compat> 8001;;;;N;;;;;
+2F7D;KANGXI RADICAL AND;So;0;ON;<compat> 800C;;;;N;;;;;
+2F7E;KANGXI RADICAL PLOW;So;0;ON;<compat> 8012;;;;N;;;;;
+2F7F;KANGXI RADICAL EAR;So;0;ON;<compat> 8033;;;;N;;;;;
+2F80;KANGXI RADICAL BRUSH;So;0;ON;<compat> 807F;;;;N;;;;;
+2F81;KANGXI RADICAL MEAT;So;0;ON;<compat> 8089;;;;N;;;;;
+2F82;KANGXI RADICAL MINISTER;So;0;ON;<compat> 81E3;;;;N;;;;;
+2F83;KANGXI RADICAL SELF;So;0;ON;<compat> 81EA;;;;N;;;;;
+2F84;KANGXI RADICAL ARRIVE;So;0;ON;<compat> 81F3;;;;N;;;;;
+2F85;KANGXI RADICAL MORTAR;So;0;ON;<compat> 81FC;;;;N;;;;;
+2F86;KANGXI RADICAL TONGUE;So;0;ON;<compat> 820C;;;;N;;;;;
+2F87;KANGXI RADICAL OPPOSE;So;0;ON;<compat> 821B;;;;N;;;;;
+2F88;KANGXI RADICAL BOAT;So;0;ON;<compat> 821F;;;;N;;;;;
+2F89;KANGXI RADICAL STOPPING;So;0;ON;<compat> 826E;;;;N;;;;;
+2F8A;KANGXI RADICAL COLOR;So;0;ON;<compat> 8272;;;;N;;;;;
+2F8B;KANGXI RADICAL GRASS;So;0;ON;<compat> 8278;;;;N;;;;;
+2F8C;KANGXI RADICAL TIGER;So;0;ON;<compat> 864D;;;;N;;;;;
+2F8D;KANGXI RADICAL INSECT;So;0;ON;<compat> 866B;;;;N;;;;;
+2F8E;KANGXI RADICAL BLOOD;So;0;ON;<compat> 8840;;;;N;;;;;
+2F8F;KANGXI RADICAL WALK ENCLOSURE;So;0;ON;<compat> 884C;;;;N;;;;;
+2F90;KANGXI RADICAL CLOTHES;So;0;ON;<compat> 8863;;;;N;;;;;
+2F91;KANGXI RADICAL WEST;So;0;ON;<compat> 897E;;;;N;;;;;
+2F92;KANGXI RADICAL SEE;So;0;ON;<compat> 898B;;;;N;;;;;
+2F93;KANGXI RADICAL HORN;So;0;ON;<compat> 89D2;;;;N;;;;;
+2F94;KANGXI RADICAL SPEECH;So;0;ON;<compat> 8A00;;;;N;;;;;
+2F95;KANGXI RADICAL VALLEY;So;0;ON;<compat> 8C37;;;;N;;;;;
+2F96;KANGXI RADICAL BEAN;So;0;ON;<compat> 8C46;;;;N;;;;;
+2F97;KANGXI RADICAL PIG;So;0;ON;<compat> 8C55;;;;N;;;;;
+2F98;KANGXI RADICAL BADGER;So;0;ON;<compat> 8C78;;;;N;;;;;
+2F99;KANGXI RADICAL SHELL;So;0;ON;<compat> 8C9D;;;;N;;;;;
+2F9A;KANGXI RADICAL RED;So;0;ON;<compat> 8D64;;;;N;;;;;
+2F9B;KANGXI RADICAL RUN;So;0;ON;<compat> 8D70;;;;N;;;;;
+2F9C;KANGXI RADICAL FOOT;So;0;ON;<compat> 8DB3;;;;N;;;;;
+2F9D;KANGXI RADICAL BODY;So;0;ON;<compat> 8EAB;;;;N;;;;;
+2F9E;KANGXI RADICAL CART;So;0;ON;<compat> 8ECA;;;;N;;;;;
+2F9F;KANGXI RADICAL BITTER;So;0;ON;<compat> 8F9B;;;;N;;;;;
+2FA0;KANGXI RADICAL MORNING;So;0;ON;<compat> 8FB0;;;;N;;;;;
+2FA1;KANGXI RADICAL WALK;So;0;ON;<compat> 8FB5;;;;N;;;;;
+2FA2;KANGXI RADICAL CITY;So;0;ON;<compat> 9091;;;;N;;;;;
+2FA3;KANGXI RADICAL WINE;So;0;ON;<compat> 9149;;;;N;;;;;
+2FA4;KANGXI RADICAL DISTINGUISH;So;0;ON;<compat> 91C6;;;;N;;;;;
+2FA5;KANGXI RADICAL VILLAGE;So;0;ON;<compat> 91CC;;;;N;;;;;
+2FA6;KANGXI RADICAL GOLD;So;0;ON;<compat> 91D1;;;;N;;;;;
+2FA7;KANGXI RADICAL LONG;So;0;ON;<compat> 9577;;;;N;;;;;
+2FA8;KANGXI RADICAL GATE;So;0;ON;<compat> 9580;;;;N;;;;;
+2FA9;KANGXI RADICAL MOUND;So;0;ON;<compat> 961C;;;;N;;;;;
+2FAA;KANGXI RADICAL SLAVE;So;0;ON;<compat> 96B6;;;;N;;;;;
+2FAB;KANGXI RADICAL SHORT TAILED BIRD;So;0;ON;<compat> 96B9;;;;N;;;;;
+2FAC;KANGXI RADICAL RAIN;So;0;ON;<compat> 96E8;;;;N;;;;;
+2FAD;KANGXI RADICAL BLUE;So;0;ON;<compat> 9751;;;;N;;;;;
+2FAE;KANGXI RADICAL WRONG;So;0;ON;<compat> 975E;;;;N;;;;;
+2FAF;KANGXI RADICAL FACE;So;0;ON;<compat> 9762;;;;N;;;;;
+2FB0;KANGXI RADICAL LEATHER;So;0;ON;<compat> 9769;;;;N;;;;;
+2FB1;KANGXI RADICAL TANNED LEATHER;So;0;ON;<compat> 97CB;;;;N;;;;;
+2FB2;KANGXI RADICAL LEEK;So;0;ON;<compat> 97ED;;;;N;;;;;
+2FB3;KANGXI RADICAL SOUND;So;0;ON;<compat> 97F3;;;;N;;;;;
+2FB4;KANGXI RADICAL LEAF;So;0;ON;<compat> 9801;;;;N;;;;;
+2FB5;KANGXI RADICAL WIND;So;0;ON;<compat> 98A8;;;;N;;;;;
+2FB6;KANGXI RADICAL FLY;So;0;ON;<compat> 98DB;;;;N;;;;;
+2FB7;KANGXI RADICAL EAT;So;0;ON;<compat> 98DF;;;;N;;;;;
+2FB8;KANGXI RADICAL HEAD;So;0;ON;<compat> 9996;;;;N;;;;;
+2FB9;KANGXI RADICAL FRAGRANT;So;0;ON;<compat> 9999;;;;N;;;;;
+2FBA;KANGXI RADICAL HORSE;So;0;ON;<compat> 99AC;;;;N;;;;;
+2FBB;KANGXI RADICAL BONE;So;0;ON;<compat> 9AA8;;;;N;;;;;
+2FBC;KANGXI RADICAL TALL;So;0;ON;<compat> 9AD8;;;;N;;;;;
+2FBD;KANGXI RADICAL HAIR;So;0;ON;<compat> 9ADF;;;;N;;;;;
+2FBE;KANGXI RADICAL FIGHT;So;0;ON;<compat> 9B25;;;;N;;;;;
+2FBF;KANGXI RADICAL SACRIFICIAL WINE;So;0;ON;<compat> 9B2F;;;;N;;;;;
+2FC0;KANGXI RADICAL CAULDRON;So;0;ON;<compat> 9B32;;;;N;;;;;
+2FC1;KANGXI RADICAL GHOST;So;0;ON;<compat> 9B3C;;;;N;;;;;
+2FC2;KANGXI RADICAL FISH;So;0;ON;<compat> 9B5A;;;;N;;;;;
+2FC3;KANGXI RADICAL BIRD;So;0;ON;<compat> 9CE5;;;;N;;;;;
+2FC4;KANGXI RADICAL SALT;So;0;ON;<compat> 9E75;;;;N;;;;;
+2FC5;KANGXI RADICAL DEER;So;0;ON;<compat> 9E7F;;;;N;;;;;
+2FC6;KANGXI RADICAL WHEAT;So;0;ON;<compat> 9EA5;;;;N;;;;;
+2FC7;KANGXI RADICAL HEMP;So;0;ON;<compat> 9EBB;;;;N;;;;;
+2FC8;KANGXI RADICAL YELLOW;So;0;ON;<compat> 9EC3;;;;N;;;;;
+2FC9;KANGXI RADICAL MILLET;So;0;ON;<compat> 9ECD;;;;N;;;;;
+2FCA;KANGXI RADICAL BLACK;So;0;ON;<compat> 9ED1;;;;N;;;;;
+2FCB;KANGXI RADICAL EMBROIDERY;So;0;ON;<compat> 9EF9;;;;N;;;;;
+2FCC;KANGXI RADICAL FROG;So;0;ON;<compat> 9EFD;;;;N;;;;;
+2FCD;KANGXI RADICAL TRIPOD;So;0;ON;<compat> 9F0E;;;;N;;;;;
+2FCE;KANGXI RADICAL DRUM;So;0;ON;<compat> 9F13;;;;N;;;;;
+2FCF;KANGXI RADICAL RAT;So;0;ON;<compat> 9F20;;;;N;;;;;
+2FD0;KANGXI RADICAL NOSE;So;0;ON;<compat> 9F3B;;;;N;;;;;
+2FD1;KANGXI RADICAL EVEN;So;0;ON;<compat> 9F4A;;;;N;;;;;
+2FD2;KANGXI RADICAL TOOTH;So;0;ON;<compat> 9F52;;;;N;;;;;
+2FD3;KANGXI RADICAL DRAGON;So;0;ON;<compat> 9F8D;;;;N;;;;;
+2FD4;KANGXI RADICAL TURTLE;So;0;ON;<compat> 9F9C;;;;N;;;;;
+2FD5;KANGXI RADICAL FLUTE;So;0;ON;<compat> 9FA0;;;;N;;;;;
+2FF0;IDEOGRAPHIC DESCRIPTION CHARACTER LEFT TO RIGHT;So;0;ON;;;;;N;;;;;
+2FF1;IDEOGRAPHIC DESCRIPTION CHARACTER ABOVE TO BELOW;So;0;ON;;;;;N;;;;;
+2FF2;IDEOGRAPHIC DESCRIPTION CHARACTER LEFT TO MIDDLE AND RIGHT;So;0;ON;;;;;N;;;;;
+2FF3;IDEOGRAPHIC DESCRIPTION CHARACTER ABOVE TO MIDDLE AND BELOW;So;0;ON;;;;;N;;;;;
+2FF4;IDEOGRAPHIC DESCRIPTION CHARACTER FULL SURROUND;So;0;ON;;;;;N;;;;;
+2FF5;IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM ABOVE;So;0;ON;;;;;N;;;;;
+2FF6;IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM BELOW;So;0;ON;;;;;N;;;;;
+2FF7;IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM LEFT;So;0;ON;;;;;N;;;;;
+2FF8;IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM UPPER LEFT;So;0;ON;;;;;N;;;;;
+2FF9;IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM UPPER RIGHT;So;0;ON;;;;;N;;;;;
+2FFA;IDEOGRAPHIC DESCRIPTION CHARACTER SURROUND FROM LOWER LEFT;So;0;ON;;;;;N;;;;;
+2FFB;IDEOGRAPHIC DESCRIPTION CHARACTER OVERLAID;So;0;ON;;;;;N;;;;;
+3000;IDEOGRAPHIC SPACE;Zs;0;WS;<wide> 0020;;;;N;;;;;
+3001;IDEOGRAPHIC COMMA;Po;0;ON;;;;;N;;;;;
+3002;IDEOGRAPHIC FULL STOP;Po;0;ON;;;;;N;IDEOGRAPHIC PERIOD;;;;
+3003;DITTO MARK;Po;0;ON;;;;;N;;;;;
+3004;JAPANESE INDUSTRIAL STANDARD SYMBOL;So;0;ON;;;;;N;;;;;
+3005;IDEOGRAPHIC ITERATION MARK;Lm;0;L;;;;;N;;;;;
+3006;IDEOGRAPHIC CLOSING MARK;Lo;0;L;;;;;N;;;;;
+3007;IDEOGRAPHIC NUMBER ZERO;Nl;0;L;;;;0;N;;;;;
+3008;LEFT ANGLE BRACKET;Ps;0;ON;;;;;Y;OPENING ANGLE BRACKET;;;;
+3009;RIGHT ANGLE BRACKET;Pe;0;ON;;;;;Y;CLOSING ANGLE BRACKET;;;;
+300A;LEFT DOUBLE ANGLE BRACKET;Ps;0;ON;;;;;Y;OPENING DOUBLE ANGLE BRACKET;;;;
+300B;RIGHT DOUBLE ANGLE BRACKET;Pe;0;ON;;;;;Y;CLOSING DOUBLE ANGLE BRACKET;;;;
+300C;LEFT CORNER BRACKET;Ps;0;ON;;;;;Y;OPENING CORNER BRACKET;;;;
+300D;RIGHT CORNER BRACKET;Pe;0;ON;;;;;Y;CLOSING CORNER BRACKET;;;;
+300E;LEFT WHITE CORNER BRACKET;Ps;0;ON;;;;;Y;OPENING WHITE CORNER BRACKET;;;;
+300F;RIGHT WHITE CORNER BRACKET;Pe;0;ON;;;;;Y;CLOSING WHITE CORNER BRACKET;;;;
+3010;LEFT BLACK LENTICULAR BRACKET;Ps;0;ON;;;;;Y;OPENING BLACK LENTICULAR BRACKET;;;;
+3011;RIGHT BLACK LENTICULAR BRACKET;Pe;0;ON;;;;;Y;CLOSING BLACK LENTICULAR BRACKET;;;;
+3012;POSTAL MARK;So;0;ON;;;;;N;;;;;
+3013;GETA MARK;So;0;ON;;;;;N;;;;;
+3014;LEFT TORTOISE SHELL BRACKET;Ps;0;ON;;;;;Y;OPENING TORTOISE SHELL BRACKET;;;;
+3015;RIGHT TORTOISE SHELL BRACKET;Pe;0;ON;;;;;Y;CLOSING TORTOISE SHELL BRACKET;;;;
+3016;LEFT WHITE LENTICULAR BRACKET;Ps;0;ON;;;;;Y;OPENING WHITE LENTICULAR BRACKET;;;;
+3017;RIGHT WHITE LENTICULAR BRACKET;Pe;0;ON;;;;;Y;CLOSING WHITE LENTICULAR BRACKET;;;;
+3018;LEFT WHITE TORTOISE SHELL BRACKET;Ps;0;ON;;;;;Y;OPENING WHITE TORTOISE SHELL BRACKET;;;;
+3019;RIGHT WHITE TORTOISE SHELL BRACKET;Pe;0;ON;;;;;Y;CLOSING WHITE TORTOISE SHELL BRACKET;;;;
+301A;LEFT WHITE SQUARE BRACKET;Ps;0;ON;;;;;Y;OPENING WHITE SQUARE BRACKET;;;;
+301B;RIGHT WHITE SQUARE BRACKET;Pe;0;ON;;;;;Y;CLOSING WHITE SQUARE BRACKET;;;;
+301C;WAVE DASH;Pd;0;ON;;;;;N;;;;;
+301D;REVERSED DOUBLE PRIME QUOTATION MARK;Ps;0;ON;;;;;N;;;;;
+301E;DOUBLE PRIME QUOTATION MARK;Pe;0;ON;;;;;N;;;;;
+301F;LOW DOUBLE PRIME QUOTATION MARK;Pe;0;ON;;;;;N;;;;;
+3020;POSTAL MARK FACE;So;0;ON;;;;;N;;;;;
+3021;HANGZHOU NUMERAL ONE;Nl;0;L;;;;1;N;;;;;
+3022;HANGZHOU NUMERAL TWO;Nl;0;L;;;;2;N;;;;;
+3023;HANGZHOU NUMERAL THREE;Nl;0;L;;;;3;N;;;;;
+3024;HANGZHOU NUMERAL FOUR;Nl;0;L;;;;4;N;;;;;
+3025;HANGZHOU NUMERAL FIVE;Nl;0;L;;;;5;N;;;;;
+3026;HANGZHOU NUMERAL SIX;Nl;0;L;;;;6;N;;;;;
+3027;HANGZHOU NUMERAL SEVEN;Nl;0;L;;;;7;N;;;;;
+3028;HANGZHOU NUMERAL EIGHT;Nl;0;L;;;;8;N;;;;;
+3029;HANGZHOU NUMERAL NINE;Nl;0;L;;;;9;N;;;;;
+302A;IDEOGRAPHIC LEVEL TONE MARK;Mn;218;NSM;;;;;N;;;;;
+302B;IDEOGRAPHIC RISING TONE MARK;Mn;228;NSM;;;;;N;;;;;
+302C;IDEOGRAPHIC DEPARTING TONE MARK;Mn;232;NSM;;;;;N;;;;;
+302D;IDEOGRAPHIC ENTERING TONE MARK;Mn;222;NSM;;;;;N;;;;;
+302E;HANGUL SINGLE DOT TONE MARK;Mn;224;NSM;;;;;N;;;;;
+302F;HANGUL DOUBLE DOT TONE MARK;Mn;224;NSM;;;;;N;;;;;
+3030;WAVY DASH;Pd;0;ON;;;;;N;;;;;
+3031;VERTICAL KANA REPEAT MARK;Lm;0;L;;;;;N;;;;;
+3032;VERTICAL KANA REPEAT WITH VOICED SOUND MARK;Lm;0;L;;;;;N;;;;;
+3033;VERTICAL KANA REPEAT MARK UPPER HALF;Lm;0;L;;;;;N;;;;;
+3034;VERTICAL KANA REPEAT WITH VOICED SOUND MARK UPPER HALF;Lm;0;L;;;;;N;;;;;
+3035;VERTICAL KANA REPEAT MARK LOWER HALF;Lm;0;L;;;;;N;;;;;
+3036;CIRCLED POSTAL MARK;So;0;ON;<compat> 3012;;;;N;;;;;
+3037;IDEOGRAPHIC TELEGRAPH LINE FEED SEPARATOR SYMBOL;So;0;ON;;;;;N;;;;;
+3038;HANGZHOU NUMERAL TEN;Nl;0;L;<compat> 5341;;;10;N;;;;;
+3039;HANGZHOU NUMERAL TWENTY;Nl;0;L;<compat> 5344;;;20;N;;;;;
+303A;HANGZHOU NUMERAL THIRTY;Nl;0;L;<compat> 5345;;;30;N;;;;;
+303E;IDEOGRAPHIC VARIATION INDICATOR;So;0;ON;;;;;N;;;;;
+303F;IDEOGRAPHIC HALF FILL SPACE;So;0;ON;;;;;N;;;;;
+3041;HIRAGANA LETTER SMALL A;Lo;0;L;;;;;N;;;;;
+3042;HIRAGANA LETTER A;Lo;0;L;;;;;N;;;;;
+3043;HIRAGANA LETTER SMALL I;Lo;0;L;;;;;N;;;;;
+3044;HIRAGANA LETTER I;Lo;0;L;;;;;N;;;;;
+3045;HIRAGANA LETTER SMALL U;Lo;0;L;;;;;N;;;;;
+3046;HIRAGANA LETTER U;Lo;0;L;;;;;N;;;;;
+3047;HIRAGANA LETTER SMALL E;Lo;0;L;;;;;N;;;;;
+3048;HIRAGANA LETTER E;Lo;0;L;;;;;N;;;;;
+3049;HIRAGANA LETTER SMALL O;Lo;0;L;;;;;N;;;;;
+304A;HIRAGANA LETTER O;Lo;0;L;;;;;N;;;;;
+304B;HIRAGANA LETTER KA;Lo;0;L;;;;;N;;;;;
+304C;HIRAGANA LETTER GA;Lo;0;L;304B 3099;;;;N;;;;;
+304D;HIRAGANA LETTER KI;Lo;0;L;;;;;N;;;;;
+304E;HIRAGANA LETTER GI;Lo;0;L;304D 3099;;;;N;;;;;
+304F;HIRAGANA LETTER KU;Lo;0;L;;;;;N;;;;;
+3050;HIRAGANA LETTER GU;Lo;0;L;304F 3099;;;;N;;;;;
+3051;HIRAGANA LETTER KE;Lo;0;L;;;;;N;;;;;
+3052;HIRAGANA LETTER GE;Lo;0;L;3051 3099;;;;N;;;;;
+3053;HIRAGANA LETTER KO;Lo;0;L;;;;;N;;;;;
+3054;HIRAGANA LETTER GO;Lo;0;L;3053 3099;;;;N;;;;;
+3055;HIRAGANA LETTER SA;Lo;0;L;;;;;N;;;;;
+3056;HIRAGANA LETTER ZA;Lo;0;L;3055 3099;;;;N;;;;;
+3057;HIRAGANA LETTER SI;Lo;0;L;;;;;N;;;;;
+3058;HIRAGANA LETTER ZI;Lo;0;L;3057 3099;;;;N;;;;;
+3059;HIRAGANA LETTER SU;Lo;0;L;;;;;N;;;;;
+305A;HIRAGANA LETTER ZU;Lo;0;L;3059 3099;;;;N;;;;;
+305B;HIRAGANA LETTER SE;Lo;0;L;;;;;N;;;;;
+305C;HIRAGANA LETTER ZE;Lo;0;L;305B 3099;;;;N;;;;;
+305D;HIRAGANA LETTER SO;Lo;0;L;;;;;N;;;;;
+305E;HIRAGANA LETTER ZO;Lo;0;L;305D 3099;;;;N;;;;;
+305F;HIRAGANA LETTER TA;Lo;0;L;;;;;N;;;;;
+3060;HIRAGANA LETTER DA;Lo;0;L;305F 3099;;;;N;;;;;
+3061;HIRAGANA LETTER TI;Lo;0;L;;;;;N;;;;;
+3062;HIRAGANA LETTER DI;Lo;0;L;3061 3099;;;;N;;;;;
+3063;HIRAGANA LETTER SMALL TU;Lo;0;L;;;;;N;;;;;
+3064;HIRAGANA LETTER TU;Lo;0;L;;;;;N;;;;;
+3065;HIRAGANA LETTER DU;Lo;0;L;3064 3099;;;;N;;;;;
+3066;HIRAGANA LETTER TE;Lo;0;L;;;;;N;;;;;
+3067;HIRAGANA LETTER DE;Lo;0;L;3066 3099;;;;N;;;;;
+3068;HIRAGANA LETTER TO;Lo;0;L;;;;;N;;;;;
+3069;HIRAGANA LETTER DO;Lo;0;L;3068 3099;;;;N;;;;;
+306A;HIRAGANA LETTER NA;Lo;0;L;;;;;N;;;;;
+306B;HIRAGANA LETTER NI;Lo;0;L;;;;;N;;;;;
+306C;HIRAGANA LETTER NU;Lo;0;L;;;;;N;;;;;
+306D;HIRAGANA LETTER NE;Lo;0;L;;;;;N;;;;;
+306E;HIRAGANA LETTER NO;Lo;0;L;;;;;N;;;;;
+306F;HIRAGANA LETTER HA;Lo;0;L;;;;;N;;;;;
+3070;HIRAGANA LETTER BA;Lo;0;L;306F 3099;;;;N;;;;;
+3071;HIRAGANA LETTER PA;Lo;0;L;306F 309A;;;;N;;;;;
+3072;HIRAGANA LETTER HI;Lo;0;L;;;;;N;;;;;
+3073;HIRAGANA LETTER BI;Lo;0;L;3072 3099;;;;N;;;;;
+3074;HIRAGANA LETTER PI;Lo;0;L;3072 309A;;;;N;;;;;
+3075;HIRAGANA LETTER HU;Lo;0;L;;;;;N;;;;;
+3076;HIRAGANA LETTER BU;Lo;0;L;3075 3099;;;;N;;;;;
+3077;HIRAGANA LETTER PU;Lo;0;L;3075 309A;;;;N;;;;;
+3078;HIRAGANA LETTER HE;Lo;0;L;;;;;N;;;;;
+3079;HIRAGANA LETTER BE;Lo;0;L;3078 3099;;;;N;;;;;
+307A;HIRAGANA LETTER PE;Lo;0;L;3078 309A;;;;N;;;;;
+307B;HIRAGANA LETTER HO;Lo;0;L;;;;;N;;;;;
+307C;HIRAGANA LETTER BO;Lo;0;L;307B 3099;;;;N;;;;;
+307D;HIRAGANA LETTER PO;Lo;0;L;307B 309A;;;;N;;;;;
+307E;HIRAGANA LETTER MA;Lo;0;L;;;;;N;;;;;
+307F;HIRAGANA LETTER MI;Lo;0;L;;;;;N;;;;;
+3080;HIRAGANA LETTER MU;Lo;0;L;;;;;N;;;;;
+3081;HIRAGANA LETTER ME;Lo;0;L;;;;;N;;;;;
+3082;HIRAGANA LETTER MO;Lo;0;L;;;;;N;;;;;
+3083;HIRAGANA LETTER SMALL YA;Lo;0;L;;;;;N;;;;;
+3084;HIRAGANA LETTER YA;Lo;0;L;;;;;N;;;;;
+3085;HIRAGANA LETTER SMALL YU;Lo;0;L;;;;;N;;;;;
+3086;HIRAGANA LETTER YU;Lo;0;L;;;;;N;;;;;
+3087;HIRAGANA LETTER SMALL YO;Lo;0;L;;;;;N;;;;;
+3088;HIRAGANA LETTER YO;Lo;0;L;;;;;N;;;;;
+3089;HIRAGANA LETTER RA;Lo;0;L;;;;;N;;;;;
+308A;HIRAGANA LETTER RI;Lo;0;L;;;;;N;;;;;
+308B;HIRAGANA LETTER RU;Lo;0;L;;;;;N;;;;;
+308C;HIRAGANA LETTER RE;Lo;0;L;;;;;N;;;;;
+308D;HIRAGANA LETTER RO;Lo;0;L;;;;;N;;;;;
+308E;HIRAGANA LETTER SMALL WA;Lo;0;L;;;;;N;;;;;
+308F;HIRAGANA LETTER WA;Lo;0;L;;;;;N;;;;;
+3090;HIRAGANA LETTER WI;Lo;0;L;;;;;N;;;;;
+3091;HIRAGANA LETTER WE;Lo;0;L;;;;;N;;;;;
+3092;HIRAGANA LETTER WO;Lo;0;L;;;;;N;;;;;
+3093;HIRAGANA LETTER N;Lo;0;L;;;;;N;;;;;
+3094;HIRAGANA LETTER VU;Lo;0;L;3046 3099;;;;N;;;;;
+3099;COMBINING KATAKANA-HIRAGANA VOICED SOUND MARK;Mn;8;NSM;;;;;N;NON-SPACING KATAKANA-HIRAGANA VOICED SOUND MARK;;;;
+309A;COMBINING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK;Mn;8;NSM;;;;;N;NON-SPACING KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK;;;;
+309B;KATAKANA-HIRAGANA VOICED SOUND MARK;Sk;0;ON;<compat> 0020 3099;;;;N;;;;;
+309C;KATAKANA-HIRAGANA SEMI-VOICED SOUND MARK;Sk;0;ON;<compat> 0020 309A;;;;N;;;;;
+309D;HIRAGANA ITERATION MARK;Lm;0;L;;;;;N;;;;;
+309E;HIRAGANA VOICED ITERATION MARK;Lm;0;L;309D 3099;;;;N;;;;;
+30A1;KATAKANA LETTER SMALL A;Lo;0;L;;;;;N;;;;;
+30A2;KATAKANA LETTER A;Lo;0;L;;;;;N;;;;;
+30A3;KATAKANA LETTER SMALL I;Lo;0;L;;;;;N;;;;;
+30A4;KATAKANA LETTER I;Lo;0;L;;;;;N;;;;;
+30A5;KATAKANA LETTER SMALL U;Lo;0;L;;;;;N;;;;;
+30A6;KATAKANA LETTER U;Lo;0;L;;;;;N;;;;;
+30A7;KATAKANA LETTER SMALL E;Lo;0;L;;;;;N;;;;;
+30A8;KATAKANA LETTER E;Lo;0;L;;;;;N;;;;;
+30A9;KATAKANA LETTER SMALL O;Lo;0;L;;;;;N;;;;;
+30AA;KATAKANA LETTER O;Lo;0;L;;;;;N;;;;;
+30AB;KATAKANA LETTER KA;Lo;0;L;;;;;N;;;;;
+30AC;KATAKANA LETTER GA;Lo;0;L;30AB 3099;;;;N;;;;;
+30AD;KATAKANA LETTER KI;Lo;0;L;;;;;N;;;;;
+30AE;KATAKANA LETTER GI;Lo;0;L;30AD 3099;;;;N;;;;;
+30AF;KATAKANA LETTER KU;Lo;0;L;;;;;N;;;;;
+30B0;KATAKANA LETTER GU;Lo;0;L;30AF 3099;;;;N;;;;;
+30B1;KATAKANA LETTER KE;Lo;0;L;;;;;N;;;;;
+30B2;KATAKANA LETTER GE;Lo;0;L;30B1 3099;;;;N;;;;;
+30B3;KATAKANA LETTER KO;Lo;0;L;;;;;N;;;;;
+30B4;KATAKANA LETTER GO;Lo;0;L;30B3 3099;;;;N;;;;;
+30B5;KATAKANA LETTER SA;Lo;0;L;;;;;N;;;;;
+30B6;KATAKANA LETTER ZA;Lo;0;L;30B5 3099;;;;N;;;;;
+30B7;KATAKANA LETTER SI;Lo;0;L;;;;;N;;;;;
+30B8;KATAKANA LETTER ZI;Lo;0;L;30B7 3099;;;;N;;;;;
+30B9;KATAKANA LETTER SU;Lo;0;L;;;;;N;;;;;
+30BA;KATAKANA LETTER ZU;Lo;0;L;30B9 3099;;;;N;;;;;
+30BB;KATAKANA LETTER SE;Lo;0;L;;;;;N;;;;;
+30BC;KATAKANA LETTER ZE;Lo;0;L;30BB 3099;;;;N;;;;;
+30BD;KATAKANA LETTER SO;Lo;0;L;;;;;N;;;;;
+30BE;KATAKANA LETTER ZO;Lo;0;L;30BD 3099;;;;N;;;;;
+30BF;KATAKANA LETTER TA;Lo;0;L;;;;;N;;;;;
+30C0;KATAKANA LETTER DA;Lo;0;L;30BF 3099;;;;N;;;;;
+30C1;KATAKANA LETTER TI;Lo;0;L;;;;;N;;;;;
+30C2;KATAKANA LETTER DI;Lo;0;L;30C1 3099;;;;N;;;;;
+30C3;KATAKANA LETTER SMALL TU;Lo;0;L;;;;;N;;;;;
+30C4;KATAKANA LETTER TU;Lo;0;L;;;;;N;;;;;
+30C5;KATAKANA LETTER DU;Lo;0;L;30C4 3099;;;;N;;;;;
+30C6;KATAKANA LETTER TE;Lo;0;L;;;;;N;;;;;
+30C7;KATAKANA LETTER DE;Lo;0;L;30C6 3099;;;;N;;;;;
+30C8;KATAKANA LETTER TO;Lo;0;L;;;;;N;;;;;
+30C9;KATAKANA LETTER DO;Lo;0;L;30C8 3099;;;;N;;;;;
+30CA;KATAKANA LETTER NA;Lo;0;L;;;;;N;;;;;
+30CB;KATAKANA LETTER NI;Lo;0;L;;;;;N;;;;;
+30CC;KATAKANA LETTER NU;Lo;0;L;;;;;N;;;;;
+30CD;KATAKANA LETTER NE;Lo;0;L;;;;;N;;;;;
+30CE;KATAKANA LETTER NO;Lo;0;L;;;;;N;;;;;
+30CF;KATAKANA LETTER HA;Lo;0;L;;;;;N;;;;;
+30D0;KATAKANA LETTER BA;Lo;0;L;30CF 3099;;;;N;;;;;
+30D1;KATAKANA LETTER PA;Lo;0;L;30CF 309A;;;;N;;;;;
+30D2;KATAKANA LETTER HI;Lo;0;L;;;;;N;;;;;
+30D3;KATAKANA LETTER BI;Lo;0;L;30D2 3099;;;;N;;;;;
+30D4;KATAKANA LETTER PI;Lo;0;L;30D2 309A;;;;N;;;;;
+30D5;KATAKANA LETTER HU;Lo;0;L;;;;;N;;;;;
+30D6;KATAKANA LETTER BU;Lo;0;L;30D5 3099;;;;N;;;;;
+30D7;KATAKANA LETTER PU;Lo;0;L;30D5 309A;;;;N;;;;;
+30D8;KATAKANA LETTER HE;Lo;0;L;;;;;N;;;;;
+30D9;KATAKANA LETTER BE;Lo;0;L;30D8 3099;;;;N;;;;;
+30DA;KATAKANA LETTER PE;Lo;0;L;30D8 309A;;;;N;;;;;
+30DB;KATAKANA LETTER HO;Lo;0;L;;;;;N;;;;;
+30DC;KATAKANA LETTER BO;Lo;0;L;30DB 3099;;;;N;;;;;
+30DD;KATAKANA LETTER PO;Lo;0;L;30DB 309A;;;;N;;;;;
+30DE;KATAKANA LETTER MA;Lo;0;L;;;;;N;;;;;
+30DF;KATAKANA LETTER MI;Lo;0;L;;;;;N;;;;;
+30E0;KATAKANA LETTER MU;Lo;0;L;;;;;N;;;;;
+30E1;KATAKANA LETTER ME;Lo;0;L;;;;;N;;;;;
+30E2;KATAKANA LETTER MO;Lo;0;L;;;;;N;;;;;
+30E3;KATAKANA LETTER SMALL YA;Lo;0;L;;;;;N;;;;;
+30E4;KATAKANA LETTER YA;Lo;0;L;;;;;N;;;;;
+30E5;KATAKANA LETTER SMALL YU;Lo;0;L;;;;;N;;;;;
+30E6;KATAKANA LETTER YU;Lo;0;L;;;;;N;;;;;
+30E7;KATAKANA LETTER SMALL YO;Lo;0;L;;;;;N;;;;;
+30E8;KATAKANA LETTER YO;Lo;0;L;;;;;N;;;;;
+30E9;KATAKANA LETTER RA;Lo;0;L;;;;;N;;;;;
+30EA;KATAKANA LETTER RI;Lo;0;L;;;;;N;;;;;
+30EB;KATAKANA LETTER RU;Lo;0;L;;;;;N;;;;;
+30EC;KATAKANA LETTER RE;Lo;0;L;;;;;N;;;;;
+30ED;KATAKANA LETTER RO;Lo;0;L;;;;;N;;;;;
+30EE;KATAKANA LETTER SMALL WA;Lo;0;L;;;;;N;;;;;
+30EF;KATAKANA LETTER WA;Lo;0;L;;;;;N;;;;;
+30F0;KATAKANA LETTER WI;Lo;0;L;;;;;N;;;;;
+30F1;KATAKANA LETTER WE;Lo;0;L;;;;;N;;;;;
+30F2;KATAKANA LETTER WO;Lo;0;L;;;;;N;;;;;
+30F3;KATAKANA LETTER N;Lo;0;L;;;;;N;;;;;
+30F4;KATAKANA LETTER VU;Lo;0;L;30A6 3099;;;;N;;;;;
+30F5;KATAKANA LETTER SMALL KA;Lo;0;L;;;;;N;;;;;
+30F6;KATAKANA LETTER SMALL KE;Lo;0;L;;;;;N;;;;;
+30F7;KATAKANA LETTER VA;Lo;0;L;30EF 3099;;;;N;;;;;
+30F8;KATAKANA LETTER VI;Lo;0;L;30F0 3099;;;;N;;;;;
+30F9;KATAKANA LETTER VE;Lo;0;L;30F1 3099;;;;N;;;;;
+30FA;KATAKANA LETTER VO;Lo;0;L;30F2 3099;;;;N;;;;;
+30FB;KATAKANA MIDDLE DOT;Pc;0;ON;;;;;N;;;;;
+30FC;KATAKANA-HIRAGANA PROLONGED SOUND MARK;Lm;0;L;;;;;N;;;;;
+30FD;KATAKANA ITERATION MARK;Lm;0;L;;;;;N;;;;;
+30FE;KATAKANA VOICED ITERATION MARK;Lm;0;L;30FD 3099;;;;N;;;;;
+3105;BOPOMOFO LETTER B;Lo;0;L;;;;;N;;;;;
+3106;BOPOMOFO LETTER P;Lo;0;L;;;;;N;;;;;
+3107;BOPOMOFO LETTER M;Lo;0;L;;;;;N;;;;;
+3108;BOPOMOFO LETTER F;Lo;0;L;;;;;N;;;;;
+3109;BOPOMOFO LETTER D;Lo;0;L;;;;;N;;;;;
+310A;BOPOMOFO LETTER T;Lo;0;L;;;;;N;;;;;
+310B;BOPOMOFO LETTER N;Lo;0;L;;;;;N;;;;;
+310C;BOPOMOFO LETTER L;Lo;0;L;;;;;N;;;;;
+310D;BOPOMOFO LETTER G;Lo;0;L;;;;;N;;;;;
+310E;BOPOMOFO LETTER K;Lo;0;L;;;;;N;;;;;
+310F;BOPOMOFO LETTER H;Lo;0;L;;;;;N;;;;;
+3110;BOPOMOFO LETTER J;Lo;0;L;;;;;N;;;;;
+3111;BOPOMOFO LETTER Q;Lo;0;L;;;;;N;;;;;
+3112;BOPOMOFO LETTER X;Lo;0;L;;;;;N;;;;;
+3113;BOPOMOFO LETTER ZH;Lo;0;L;;;;;N;;;;;
+3114;BOPOMOFO LETTER CH;Lo;0;L;;;;;N;;;;;
+3115;BOPOMOFO LETTER SH;Lo;0;L;;;;;N;;;;;
+3116;BOPOMOFO LETTER R;Lo;0;L;;;;;N;;;;;
+3117;BOPOMOFO LETTER Z;Lo;0;L;;;;;N;;;;;
+3118;BOPOMOFO LETTER C;Lo;0;L;;;;;N;;;;;
+3119;BOPOMOFO LETTER S;Lo;0;L;;;;;N;;;;;
+311A;BOPOMOFO LETTER A;Lo;0;L;;;;;N;;;;;
+311B;BOPOMOFO LETTER O;Lo;0;L;;;;;N;;;;;
+311C;BOPOMOFO LETTER E;Lo;0;L;;;;;N;;;;;
+311D;BOPOMOFO LETTER EH;Lo;0;L;;;;;N;;;;;
+311E;BOPOMOFO LETTER AI;Lo;0;L;;;;;N;;;;;
+311F;BOPOMOFO LETTER EI;Lo;0;L;;;;;N;;;;;
+3120;BOPOMOFO LETTER AU;Lo;0;L;;;;;N;;;;;
+3121;BOPOMOFO LETTER OU;Lo;0;L;;;;;N;;;;;
+3122;BOPOMOFO LETTER AN;Lo;0;L;;;;;N;;;;;
+3123;BOPOMOFO LETTER EN;Lo;0;L;;;;;N;;;;;
+3124;BOPOMOFO LETTER ANG;Lo;0;L;;;;;N;;;;;
+3125;BOPOMOFO LETTER ENG;Lo;0;L;;;;;N;;;;;
+3126;BOPOMOFO LETTER ER;Lo;0;L;;;;;N;;;;;
+3127;BOPOMOFO LETTER I;Lo;0;L;;;;;N;;;;;
+3128;BOPOMOFO LETTER U;Lo;0;L;;;;;N;;;;;
+3129;BOPOMOFO LETTER IU;Lo;0;L;;;;;N;;;;;
+312A;BOPOMOFO LETTER V;Lo;0;L;;;;;N;;;;;
+312B;BOPOMOFO LETTER NG;Lo;0;L;;;;;N;;;;;
+312C;BOPOMOFO LETTER GN;Lo;0;L;;;;;N;;;;;
+3131;HANGUL LETTER KIYEOK;Lo;0;L;<compat> 1100;;;;N;HANGUL LETTER GIYEOG;;;;
+3132;HANGUL LETTER SSANGKIYEOK;Lo;0;L;<compat> 1101;;;;N;HANGUL LETTER SSANG GIYEOG;;;;
+3133;HANGUL LETTER KIYEOK-SIOS;Lo;0;L;<compat> 11AA;;;;N;HANGUL LETTER GIYEOG SIOS;;;;
+3134;HANGUL LETTER NIEUN;Lo;0;L;<compat> 1102;;;;N;;;;;
+3135;HANGUL LETTER NIEUN-CIEUC;Lo;0;L;<compat> 11AC;;;;N;HANGUL LETTER NIEUN JIEUJ;;;;
+3136;HANGUL LETTER NIEUN-HIEUH;Lo;0;L;<compat> 11AD;;;;N;HANGUL LETTER NIEUN HIEUH;;;;
+3137;HANGUL LETTER TIKEUT;Lo;0;L;<compat> 1103;;;;N;HANGUL LETTER DIGEUD;;;;
+3138;HANGUL LETTER SSANGTIKEUT;Lo;0;L;<compat> 1104;;;;N;HANGUL LETTER SSANG DIGEUD;;;;
+3139;HANGUL LETTER RIEUL;Lo;0;L;<compat> 1105;;;;N;HANGUL LETTER LIEUL;;;;
+313A;HANGUL LETTER RIEUL-KIYEOK;Lo;0;L;<compat> 11B0;;;;N;HANGUL LETTER LIEUL GIYEOG;;;;
+313B;HANGUL LETTER RIEUL-MIEUM;Lo;0;L;<compat> 11B1;;;;N;HANGUL LETTER LIEUL MIEUM;;;;
+313C;HANGUL LETTER RIEUL-PIEUP;Lo;0;L;<compat> 11B2;;;;N;HANGUL LETTER LIEUL BIEUB;;;;
+313D;HANGUL LETTER RIEUL-SIOS;Lo;0;L;<compat> 11B3;;;;N;HANGUL LETTER LIEUL SIOS;;;;
+313E;HANGUL LETTER RIEUL-THIEUTH;Lo;0;L;<compat> 11B4;;;;N;HANGUL LETTER LIEUL TIEUT;;;;
+313F;HANGUL LETTER RIEUL-PHIEUPH;Lo;0;L;<compat> 11B5;;;;N;HANGUL LETTER LIEUL PIEUP;;;;
+3140;HANGUL LETTER RIEUL-HIEUH;Lo;0;L;<compat> 111A;;;;N;HANGUL LETTER LIEUL HIEUH;;;;
+3141;HANGUL LETTER MIEUM;Lo;0;L;<compat> 1106;;;;N;;;;;
+3142;HANGUL LETTER PIEUP;Lo;0;L;<compat> 1107;;;;N;HANGUL LETTER BIEUB;;;;
+3143;HANGUL LETTER SSANGPIEUP;Lo;0;L;<compat> 1108;;;;N;HANGUL LETTER SSANG BIEUB;;;;
+3144;HANGUL LETTER PIEUP-SIOS;Lo;0;L;<compat> 1121;;;;N;HANGUL LETTER BIEUB SIOS;;;;
+3145;HANGUL LETTER SIOS;Lo;0;L;<compat> 1109;;;;N;;;;;
+3146;HANGUL LETTER SSANGSIOS;Lo;0;L;<compat> 110A;;;;N;HANGUL LETTER SSANG SIOS;;;;
+3147;HANGUL LETTER IEUNG;Lo;0;L;<compat> 110B;;;;N;;;;;
+3148;HANGUL LETTER CIEUC;Lo;0;L;<compat> 110C;;;;N;HANGUL LETTER JIEUJ;;;;
+3149;HANGUL LETTER SSANGCIEUC;Lo;0;L;<compat> 110D;;;;N;HANGUL LETTER SSANG JIEUJ;;;;
+314A;HANGUL LETTER CHIEUCH;Lo;0;L;<compat> 110E;;;;N;HANGUL LETTER CIEUC;;;;
+314B;HANGUL LETTER KHIEUKH;Lo;0;L;<compat> 110F;;;;N;HANGUL LETTER KIYEOK;;;;
+314C;HANGUL LETTER THIEUTH;Lo;0;L;<compat> 1110;;;;N;HANGUL LETTER TIEUT;;;;
+314D;HANGUL LETTER PHIEUPH;Lo;0;L;<compat> 1111;;;;N;HANGUL LETTER PIEUP;;;;
+314E;HANGUL LETTER HIEUH;Lo;0;L;<compat> 1112;;;;N;;;;;
+314F;HANGUL LETTER A;Lo;0;L;<compat> 1161;;;;N;;;;;
+3150;HANGUL LETTER AE;Lo;0;L;<compat> 1162;;;;N;;;;;
+3151;HANGUL LETTER YA;Lo;0;L;<compat> 1163;;;;N;;;;;
+3152;HANGUL LETTER YAE;Lo;0;L;<compat> 1164;;;;N;;;;;
+3153;HANGUL LETTER EO;Lo;0;L;<compat> 1165;;;;N;;;;;
+3154;HANGUL LETTER E;Lo;0;L;<compat> 1166;;;;N;;;;;
+3155;HANGUL LETTER YEO;Lo;0;L;<compat> 1167;;;;N;;;;;
+3156;HANGUL LETTER YE;Lo;0;L;<compat> 1168;;;;N;;;;;
+3157;HANGUL LETTER O;Lo;0;L;<compat> 1169;;;;N;;;;;
+3158;HANGUL LETTER WA;Lo;0;L;<compat> 116A;;;;N;;;;;
+3159;HANGUL LETTER WAE;Lo;0;L;<compat> 116B;;;;N;;;;;
+315A;HANGUL LETTER OE;Lo;0;L;<compat> 116C;;;;N;;;;;
+315B;HANGUL LETTER YO;Lo;0;L;<compat> 116D;;;;N;;;;;
+315C;HANGUL LETTER U;Lo;0;L;<compat> 116E;;;;N;;;;;
+315D;HANGUL LETTER WEO;Lo;0;L;<compat> 116F;;;;N;;;;;
+315E;HANGUL LETTER WE;Lo;0;L;<compat> 1170;;;;N;;;;;
+315F;HANGUL LETTER WI;Lo;0;L;<compat> 1171;;;;N;;;;;
+3160;HANGUL LETTER YU;Lo;0;L;<compat> 1172;;;;N;;;;;
+3161;HANGUL LETTER EU;Lo;0;L;<compat> 1173;;;;N;;;;;
+3162;HANGUL LETTER YI;Lo;0;L;<compat> 1174;;;;N;;;;;
+3163;HANGUL LETTER I;Lo;0;L;<compat> 1175;;;;N;;;;;
+3164;HANGUL FILLER;Lo;0;L;<compat> 1160;;;;N;HANGUL CAE OM;;;;
+3165;HANGUL LETTER SSANGNIEUN;Lo;0;L;<compat> 1114;;;;N;HANGUL LETTER SSANG NIEUN;;;;
+3166;HANGUL LETTER NIEUN-TIKEUT;Lo;0;L;<compat> 1115;;;;N;HANGUL LETTER NIEUN DIGEUD;;;;
+3167;HANGUL LETTER NIEUN-SIOS;Lo;0;L;<compat> 11C7;;;;N;HANGUL LETTER NIEUN SIOS;;;;
+3168;HANGUL LETTER NIEUN-PANSIOS;Lo;0;L;<compat> 11C8;;;;N;HANGUL LETTER NIEUN BAN CHI EUM;;;;
+3169;HANGUL LETTER RIEUL-KIYEOK-SIOS;Lo;0;L;<compat> 11CC;;;;N;HANGUL LETTER LIEUL GIYEOG SIOS;;;;
+316A;HANGUL LETTER RIEUL-TIKEUT;Lo;0;L;<compat> 11CE;;;;N;HANGUL LETTER LIEUL DIGEUD;;;;
+316B;HANGUL LETTER RIEUL-PIEUP-SIOS;Lo;0;L;<compat> 11D3;;;;N;HANGUL LETTER LIEUL BIEUB SIOS;;;;
+316C;HANGUL LETTER RIEUL-PANSIOS;Lo;0;L;<compat> 11D7;;;;N;HANGUL LETTER LIEUL BAN CHI EUM;;;;
+316D;HANGUL LETTER RIEUL-YEORINHIEUH;Lo;0;L;<compat> 11D9;;;;N;HANGUL LETTER LIEUL YEOLIN HIEUH;;;;
+316E;HANGUL LETTER MIEUM-PIEUP;Lo;0;L;<compat> 111C;;;;N;HANGUL LETTER MIEUM BIEUB;;;;
+316F;HANGUL LETTER MIEUM-SIOS;Lo;0;L;<compat> 11DD;;;;N;HANGUL LETTER MIEUM SIOS;;;;
+3170;HANGUL LETTER MIEUM-PANSIOS;Lo;0;L;<compat> 11DF;;;;N;HANGUL LETTER BIEUB BAN CHI EUM;;;;
+3171;HANGUL LETTER KAPYEOUNMIEUM;Lo;0;L;<compat> 111D;;;;N;HANGUL LETTER MIEUM SUN GYEONG EUM;;;;
+3172;HANGUL LETTER PIEUP-KIYEOK;Lo;0;L;<compat> 111E;;;;N;HANGUL LETTER BIEUB GIYEOG;;;;
+3173;HANGUL LETTER PIEUP-TIKEUT;Lo;0;L;<compat> 1120;;;;N;HANGUL LETTER BIEUB DIGEUD;;;;
+3174;HANGUL LETTER PIEUP-SIOS-KIYEOK;Lo;0;L;<compat> 1122;;;;N;HANGUL LETTER BIEUB SIOS GIYEOG;;;;
+3175;HANGUL LETTER PIEUP-SIOS-TIKEUT;Lo;0;L;<compat> 1123;;;;N;HANGUL LETTER BIEUB SIOS DIGEUD;;;;
+3176;HANGUL LETTER PIEUP-CIEUC;Lo;0;L;<compat> 1127;;;;N;HANGUL LETTER BIEUB JIEUJ;;;;
+3177;HANGUL LETTER PIEUP-THIEUTH;Lo;0;L;<compat> 1129;;;;N;HANGUL LETTER BIEUB TIEUT;;;;
+3178;HANGUL LETTER KAPYEOUNPIEUP;Lo;0;L;<compat> 112B;;;;N;HANGUL LETTER BIEUB SUN GYEONG EUM;;;;
+3179;HANGUL LETTER KAPYEOUNSSANGPIEUP;Lo;0;L;<compat> 112C;;;;N;HANGUL LETTER SSANG BIEUB SUN GYEONG EUM;;;;
+317A;HANGUL LETTER SIOS-KIYEOK;Lo;0;L;<compat> 112D;;;;N;HANGUL LETTER SIOS GIYEOG;;;;
+317B;HANGUL LETTER SIOS-NIEUN;Lo;0;L;<compat> 112E;;;;N;HANGUL LETTER SIOS NIEUN;;;;
+317C;HANGUL LETTER SIOS-TIKEUT;Lo;0;L;<compat> 112F;;;;N;HANGUL LETTER SIOS DIGEUD;;;;
+317D;HANGUL LETTER SIOS-PIEUP;Lo;0;L;<compat> 1132;;;;N;HANGUL LETTER SIOS BIEUB;;;;
+317E;HANGUL LETTER SIOS-CIEUC;Lo;0;L;<compat> 1136;;;;N;HANGUL LETTER SIOS JIEUJ;;;;
+317F;HANGUL LETTER PANSIOS;Lo;0;L;<compat> 1140;;;;N;HANGUL LETTER BAN CHI EUM;;;;
+3180;HANGUL LETTER SSANGIEUNG;Lo;0;L;<compat> 1147;;;;N;HANGUL LETTER SSANG IEUNG;;;;
+3181;HANGUL LETTER YESIEUNG;Lo;0;L;<compat> 114C;;;;N;HANGUL LETTER NGIEUNG;;;;
+3182;HANGUL LETTER YESIEUNG-SIOS;Lo;0;L;<compat> 11F1;;;;N;HANGUL LETTER NGIEUNG SIOS;;;;
+3183;HANGUL LETTER YESIEUNG-PANSIOS;Lo;0;L;<compat> 11F2;;;;N;HANGUL LETTER NGIEUNG BAN CHI EUM;;;;
+3184;HANGUL LETTER KAPYEOUNPHIEUPH;Lo;0;L;<compat> 1157;;;;N;HANGUL LETTER PIEUP SUN GYEONG EUM;;;;
+3185;HANGUL LETTER SSANGHIEUH;Lo;0;L;<compat> 1158;;;;N;HANGUL LETTER SSANG HIEUH;;;;
+3186;HANGUL LETTER YEORINHIEUH;Lo;0;L;<compat> 1159;;;;N;HANGUL LETTER YEOLIN HIEUH;;;;
+3187;HANGUL LETTER YO-YA;Lo;0;L;<compat> 1184;;;;N;HANGUL LETTER YOYA;;;;
+3188;HANGUL LETTER YO-YAE;Lo;0;L;<compat> 1185;;;;N;HANGUL LETTER YOYAE;;;;
+3189;HANGUL LETTER YO-I;Lo;0;L;<compat> 1188;;;;N;HANGUL LETTER YOI;;;;
+318A;HANGUL LETTER YU-YEO;Lo;0;L;<compat> 1191;;;;N;HANGUL LETTER YUYEO;;;;
+318B;HANGUL LETTER YU-YE;Lo;0;L;<compat> 1192;;;;N;HANGUL LETTER YUYE;;;;
+318C;HANGUL LETTER YU-I;Lo;0;L;<compat> 1194;;;;N;HANGUL LETTER YUI;;;;
+318D;HANGUL LETTER ARAEA;Lo;0;L;<compat> 119E;;;;N;HANGUL LETTER ALAE A;;;;
+318E;HANGUL LETTER ARAEAE;Lo;0;L;<compat> 11A1;;;;N;HANGUL LETTER ALAE AE;;;;
+3190;IDEOGRAPHIC ANNOTATION LINKING MARK;So;0;L;;;;;N;KANBUN TATETEN;Kanbun Tateten;;;
+3191;IDEOGRAPHIC ANNOTATION REVERSE MARK;So;0;L;;;;;N;KAERITEN RE;Kaeriten;;;
+3192;IDEOGRAPHIC ANNOTATION ONE MARK;No;0;L;<super> 4E00;;;1;N;KAERITEN ITI;Kaeriten;;;
+3193;IDEOGRAPHIC ANNOTATION TWO MARK;No;0;L;<super> 4E8C;;;2;N;KAERITEN NI;Kaeriten;;;
+3194;IDEOGRAPHIC ANNOTATION THREE MARK;No;0;L;<super> 4E09;;;3;N;KAERITEN SAN;Kaeriten;;;
+3195;IDEOGRAPHIC ANNOTATION FOUR MARK;No;0;L;<super> 56DB;;;4;N;KAERITEN SI;Kaeriten;;;
+3196;IDEOGRAPHIC ANNOTATION TOP MARK;So;0;L;<super> 4E0A;;;;N;KAERITEN ZYOU;Kaeriten;;;
+3197;IDEOGRAPHIC ANNOTATION MIDDLE MARK;So;0;L;<super> 4E2D;;;;N;KAERITEN TYUU;Kaeriten;;;
+3198;IDEOGRAPHIC ANNOTATION BOTTOM MARK;So;0;L;<super> 4E0B;;;;N;KAERITEN GE;Kaeriten;;;
+3199;IDEOGRAPHIC ANNOTATION FIRST MARK;So;0;L;<super> 7532;;;;N;KAERITEN KOU;Kaeriten;;;
+319A;IDEOGRAPHIC ANNOTATION SECOND MARK;So;0;L;<super> 4E59;;;;N;KAERITEN OTU;Kaeriten;;;
+319B;IDEOGRAPHIC ANNOTATION THIRD MARK;So;0;L;<super> 4E19;;;;N;KAERITEN HEI;Kaeriten;;;
+319C;IDEOGRAPHIC ANNOTATION FOURTH MARK;So;0;L;<super> 4E01;;;;N;KAERITEN TEI;Kaeriten;;;
+319D;IDEOGRAPHIC ANNOTATION HEAVEN MARK;So;0;L;<super> 5929;;;;N;KAERITEN TEN;Kaeriten;;;
+319E;IDEOGRAPHIC ANNOTATION EARTH MARK;So;0;L;<super> 5730;;;;N;KAERITEN TI;Kaeriten;;;
+319F;IDEOGRAPHIC ANNOTATION MAN MARK;So;0;L;<super> 4EBA;;;;N;KAERITEN ZIN;Kaeriten;;;
+31A0;BOPOMOFO LETTER BU;Lo;0;L;;;;;N;;;;;
+31A1;BOPOMOFO LETTER ZI;Lo;0;L;;;;;N;;;;;
+31A2;BOPOMOFO LETTER JI;Lo;0;L;;;;;N;;;;;
+31A3;BOPOMOFO LETTER GU;Lo;0;L;;;;;N;;;;;
+31A4;BOPOMOFO LETTER EE;Lo;0;L;;;;;N;;;;;
+31A5;BOPOMOFO LETTER ENN;Lo;0;L;;;;;N;;;;;
+31A6;BOPOMOFO LETTER OO;Lo;0;L;;;;;N;;;;;
+31A7;BOPOMOFO LETTER ONN;Lo;0;L;;;;;N;;;;;
+31A8;BOPOMOFO LETTER IR;Lo;0;L;;;;;N;;;;;
+31A9;BOPOMOFO LETTER ANN;Lo;0;L;;;;;N;;;;;
+31AA;BOPOMOFO LETTER INN;Lo;0;L;;;;;N;;;;;
+31AB;BOPOMOFO LETTER UNN;Lo;0;L;;;;;N;;;;;
+31AC;BOPOMOFO LETTER IM;Lo;0;L;;;;;N;;;;;
+31AD;BOPOMOFO LETTER NGG;Lo;0;L;;;;;N;;;;;
+31AE;BOPOMOFO LETTER AINN;Lo;0;L;;;;;N;;;;;
+31AF;BOPOMOFO LETTER AUNN;Lo;0;L;;;;;N;;;;;
+31B0;BOPOMOFO LETTER AM;Lo;0;L;;;;;N;;;;;
+31B1;BOPOMOFO LETTER OM;Lo;0;L;;;;;N;;;;;
+31B2;BOPOMOFO LETTER ONG;Lo;0;L;;;;;N;;;;;
+31B3;BOPOMOFO LETTER INNN;Lo;0;L;;;;;N;;;;;
+31B4;BOPOMOFO FINAL LETTER P;Lo;0;L;;;;;N;;;;;
+31B5;BOPOMOFO FINAL LETTER T;Lo;0;L;;;;;N;;;;;
+31B6;BOPOMOFO FINAL LETTER K;Lo;0;L;;;;;N;;;;;
+31B7;BOPOMOFO FINAL LETTER H;Lo;0;L;;;;;N;;;;;
+3200;PARENTHESIZED HANGUL KIYEOK;So;0;L;<compat> 0028 1100 0029;;;;N;PARENTHESIZED HANGUL GIYEOG;;;;
+3201;PARENTHESIZED HANGUL NIEUN;So;0;L;<compat> 0028 1102 0029;;;;N;;;;;
+3202;PARENTHESIZED HANGUL TIKEUT;So;0;L;<compat> 0028 1103 0029;;;;N;PARENTHESIZED HANGUL DIGEUD;;;;
+3203;PARENTHESIZED HANGUL RIEUL;So;0;L;<compat> 0028 1105 0029;;;;N;PARENTHESIZED HANGUL LIEUL;;;;
+3204;PARENTHESIZED HANGUL MIEUM;So;0;L;<compat> 0028 1106 0029;;;;N;;;;;
+3205;PARENTHESIZED HANGUL PIEUP;So;0;L;<compat> 0028 1107 0029;;;;N;PARENTHESIZED HANGUL BIEUB;;;;
+3206;PARENTHESIZED HANGUL SIOS;So;0;L;<compat> 0028 1109 0029;;;;N;;;;;
+3207;PARENTHESIZED HANGUL IEUNG;So;0;L;<compat> 0028 110B 0029;;;;N;;;;;
+3208;PARENTHESIZED HANGUL CIEUC;So;0;L;<compat> 0028 110C 0029;;;;N;PARENTHESIZED HANGUL JIEUJ;;;;
+3209;PARENTHESIZED HANGUL CHIEUCH;So;0;L;<compat> 0028 110E 0029;;;;N;PARENTHESIZED HANGUL CIEUC;;;;
+320A;PARENTHESIZED HANGUL KHIEUKH;So;0;L;<compat> 0028 110F 0029;;;;N;PARENTHESIZED HANGUL KIYEOK;;;;
+320B;PARENTHESIZED HANGUL THIEUTH;So;0;L;<compat> 0028 1110 0029;;;;N;PARENTHESIZED HANGUL TIEUT;;;;
+320C;PARENTHESIZED HANGUL PHIEUPH;So;0;L;<compat> 0028 1111 0029;;;;N;PARENTHESIZED HANGUL PIEUP;;;;
+320D;PARENTHESIZED HANGUL HIEUH;So;0;L;<compat> 0028 1112 0029;;;;N;;;;;
+320E;PARENTHESIZED HANGUL KIYEOK A;So;0;L;<compat> 0028 1100 1161 0029;;;;N;PARENTHESIZED HANGUL GA;;;;
+320F;PARENTHESIZED HANGUL NIEUN A;So;0;L;<compat> 0028 1102 1161 0029;;;;N;PARENTHESIZED HANGUL NA;;;;
+3210;PARENTHESIZED HANGUL TIKEUT A;So;0;L;<compat> 0028 1103 1161 0029;;;;N;PARENTHESIZED HANGUL DA;;;;
+3211;PARENTHESIZED HANGUL RIEUL A;So;0;L;<compat> 0028 1105 1161 0029;;;;N;PARENTHESIZED HANGUL LA;;;;
+3212;PARENTHESIZED HANGUL MIEUM A;So;0;L;<compat> 0028 1106 1161 0029;;;;N;PARENTHESIZED HANGUL MA;;;;
+3213;PARENTHESIZED HANGUL PIEUP A;So;0;L;<compat> 0028 1107 1161 0029;;;;N;PARENTHESIZED HANGUL BA;;;;
+3214;PARENTHESIZED HANGUL SIOS A;So;0;L;<compat> 0028 1109 1161 0029;;;;N;PARENTHESIZED HANGUL SA;;;;
+3215;PARENTHESIZED HANGUL IEUNG A;So;0;L;<compat> 0028 110B 1161 0029;;;;N;PARENTHESIZED HANGUL A;;;;
+3216;PARENTHESIZED HANGUL CIEUC A;So;0;L;<compat> 0028 110C 1161 0029;;;;N;PARENTHESIZED HANGUL JA;;;;
+3217;PARENTHESIZED HANGUL CHIEUCH A;So;0;L;<compat> 0028 110E 1161 0029;;;;N;PARENTHESIZED HANGUL CA;;;;
+3218;PARENTHESIZED HANGUL KHIEUKH A;So;0;L;<compat> 0028 110F 1161 0029;;;;N;PARENTHESIZED HANGUL KA;;;;
+3219;PARENTHESIZED HANGUL THIEUTH A;So;0;L;<compat> 0028 1110 1161 0029;;;;N;PARENTHESIZED HANGUL TA;;;;
+321A;PARENTHESIZED HANGUL PHIEUPH A;So;0;L;<compat> 0028 1111 1161 0029;;;;N;PARENTHESIZED HANGUL PA;;;;
+321B;PARENTHESIZED HANGUL HIEUH A;So;0;L;<compat> 0028 1112 1161 0029;;;;N;PARENTHESIZED HANGUL HA;;;;
+321C;PARENTHESIZED HANGUL CIEUC U;So;0;L;<compat> 0028 110C 116E 0029;;;;N;PARENTHESIZED HANGUL JU;;;;
+3220;PARENTHESIZED IDEOGRAPH ONE;No;0;L;<compat> 0028 4E00 0029;;;1;N;;;;;
+3221;PARENTHESIZED IDEOGRAPH TWO;No;0;L;<compat> 0028 4E8C 0029;;;2;N;;;;;
+3222;PARENTHESIZED IDEOGRAPH THREE;No;0;L;<compat> 0028 4E09 0029;;;3;N;;;;;
+3223;PARENTHESIZED IDEOGRAPH FOUR;No;0;L;<compat> 0028 56DB 0029;;;4;N;;;;;
+3224;PARENTHESIZED IDEOGRAPH FIVE;No;0;L;<compat> 0028 4E94 0029;;;5;N;;;;;
+3225;PARENTHESIZED IDEOGRAPH SIX;No;0;L;<compat> 0028 516D 0029;;;6;N;;;;;
+3226;PARENTHESIZED IDEOGRAPH SEVEN;No;0;L;<compat> 0028 4E03 0029;;;7;N;;;;;
+3227;PARENTHESIZED IDEOGRAPH EIGHT;No;0;L;<compat> 0028 516B 0029;;;8;N;;;;;
+3228;PARENTHESIZED IDEOGRAPH NINE;No;0;L;<compat> 0028 4E5D 0029;;;9;N;;;;;
+3229;PARENTHESIZED IDEOGRAPH TEN;No;0;L;<compat> 0028 5341 0029;;;10;N;;;;;
+322A;PARENTHESIZED IDEOGRAPH MOON;So;0;L;<compat> 0028 6708 0029;;;;N;;;;;
+322B;PARENTHESIZED IDEOGRAPH FIRE;So;0;L;<compat> 0028 706B 0029;;;;N;;;;;
+322C;PARENTHESIZED IDEOGRAPH WATER;So;0;L;<compat> 0028 6C34 0029;;;;N;;;;;
+322D;PARENTHESIZED IDEOGRAPH WOOD;So;0;L;<compat> 0028 6728 0029;;;;N;;;;;
+322E;PARENTHESIZED IDEOGRAPH METAL;So;0;L;<compat> 0028 91D1 0029;;;;N;;;;;
+322F;PARENTHESIZED IDEOGRAPH EARTH;So;0;L;<compat> 0028 571F 0029;;;;N;;;;;
+3230;PARENTHESIZED IDEOGRAPH SUN;So;0;L;<compat> 0028 65E5 0029;;;;N;;;;;
+3231;PARENTHESIZED IDEOGRAPH STOCK;So;0;L;<compat> 0028 682A 0029;;;;N;;;;;
+3232;PARENTHESIZED IDEOGRAPH HAVE;So;0;L;<compat> 0028 6709 0029;;;;N;;;;;
+3233;PARENTHESIZED IDEOGRAPH SOCIETY;So;0;L;<compat> 0028 793E 0029;;;;N;;;;;
+3234;PARENTHESIZED IDEOGRAPH NAME;So;0;L;<compat> 0028 540D 0029;;;;N;;;;;
+3235;PARENTHESIZED IDEOGRAPH SPECIAL;So;0;L;<compat> 0028 7279 0029;;;;N;;;;;
+3236;PARENTHESIZED IDEOGRAPH FINANCIAL;So;0;L;<compat> 0028 8CA1 0029;;;;N;;;;;
+3237;PARENTHESIZED IDEOGRAPH CONGRATULATION;So;0;L;<compat> 0028 795D 0029;;;;N;;;;;
+3238;PARENTHESIZED IDEOGRAPH LABOR;So;0;L;<compat> 0028 52B4 0029;;;;N;;;;;
+3239;PARENTHESIZED IDEOGRAPH REPRESENT;So;0;L;<compat> 0028 4EE3 0029;;;;N;;;;;
+323A;PARENTHESIZED IDEOGRAPH CALL;So;0;L;<compat> 0028 547C 0029;;;;N;;;;;
+323B;PARENTHESIZED IDEOGRAPH STUDY;So;0;L;<compat> 0028 5B66 0029;;;;N;;;;;
+323C;PARENTHESIZED IDEOGRAPH SUPERVISE;So;0;L;<compat> 0028 76E3 0029;;;;N;;;;;
+323D;PARENTHESIZED IDEOGRAPH ENTERPRISE;So;0;L;<compat> 0028 4F01 0029;;;;N;;;;;
+323E;PARENTHESIZED IDEOGRAPH RESOURCE;So;0;L;<compat> 0028 8CC7 0029;;;;N;;;;;
+323F;PARENTHESIZED IDEOGRAPH ALLIANCE;So;0;L;<compat> 0028 5354 0029;;;;N;;;;;
+3240;PARENTHESIZED IDEOGRAPH FESTIVAL;So;0;L;<compat> 0028 796D 0029;;;;N;;;;;
+3241;PARENTHESIZED IDEOGRAPH REST;So;0;L;<compat> 0028 4F11 0029;;;;N;;;;;
+3242;PARENTHESIZED IDEOGRAPH SELF;So;0;L;<compat> 0028 81EA 0029;;;;N;;;;;
+3243;PARENTHESIZED IDEOGRAPH REACH;So;0;L;<compat> 0028 81F3 0029;;;;N;;;;;
+3260;CIRCLED HANGUL KIYEOK;So;0;L;<circle> 1100;;;;N;CIRCLED HANGUL GIYEOG;;;;
+3261;CIRCLED HANGUL NIEUN;So;0;L;<circle> 1102;;;;N;;;;;
+3262;CIRCLED HANGUL TIKEUT;So;0;L;<circle> 1103;;;;N;CIRCLED HANGUL DIGEUD;;;;
+3263;CIRCLED HANGUL RIEUL;So;0;L;<circle> 1105;;;;N;CIRCLED HANGUL LIEUL;;;;
+3264;CIRCLED HANGUL MIEUM;So;0;L;<circle> 1106;;;;N;;;;;
+3265;CIRCLED HANGUL PIEUP;So;0;L;<circle> 1107;;;;N;CIRCLED HANGUL BIEUB;;;;
+3266;CIRCLED HANGUL SIOS;So;0;L;<circle> 1109;;;;N;;;;;
+3267;CIRCLED HANGUL IEUNG;So;0;L;<circle> 110B;;;;N;;;;;
+3268;CIRCLED HANGUL CIEUC;So;0;L;<circle> 110C;;;;N;CIRCLED HANGUL JIEUJ;;;;
+3269;CIRCLED HANGUL CHIEUCH;So;0;L;<circle> 110E;;;;N;CIRCLED HANGUL CIEUC;;;;
+326A;CIRCLED HANGUL KHIEUKH;So;0;L;<circle> 110F;;;;N;CIRCLED HANGUL KIYEOK;;;;
+326B;CIRCLED HANGUL THIEUTH;So;0;L;<circle> 1110;;;;N;CIRCLED HANGUL TIEUT;;;;
+326C;CIRCLED HANGUL PHIEUPH;So;0;L;<circle> 1111;;;;N;CIRCLED HANGUL PIEUP;;;;
+326D;CIRCLED HANGUL HIEUH;So;0;L;<circle> 1112;;;;N;;;;;
+326E;CIRCLED HANGUL KIYEOK A;So;0;L;<circle> 1100 1161;;;;N;CIRCLED HANGUL GA;;;;
+326F;CIRCLED HANGUL NIEUN A;So;0;L;<circle> 1102 1161;;;;N;CIRCLED HANGUL NA;;;;
+3270;CIRCLED HANGUL TIKEUT A;So;0;L;<circle> 1103 1161;;;;N;CIRCLED HANGUL DA;;;;
+3271;CIRCLED HANGUL RIEUL A;So;0;L;<circle> 1105 1161;;;;N;CIRCLED HANGUL LA;;;;
+3272;CIRCLED HANGUL MIEUM A;So;0;L;<circle> 1106 1161;;;;N;CIRCLED HANGUL MA;;;;
+3273;CIRCLED HANGUL PIEUP A;So;0;L;<circle> 1107 1161;;;;N;CIRCLED HANGUL BA;;;;
+3274;CIRCLED HANGUL SIOS A;So;0;L;<circle> 1109 1161;;;;N;CIRCLED HANGUL SA;;;;
+3275;CIRCLED HANGUL IEUNG A;So;0;L;<circle> 110B 1161;;;;N;CIRCLED HANGUL A;;;;
+3276;CIRCLED HANGUL CIEUC A;So;0;L;<circle> 110C 1161;;;;N;CIRCLED HANGUL JA;;;;
+3277;CIRCLED HANGUL CHIEUCH A;So;0;L;<circle> 110E 1161;;;;N;CIRCLED HANGUL CA;;;;
+3278;CIRCLED HANGUL KHIEUKH A;So;0;L;<circle> 110F 1161;;;;N;CIRCLED HANGUL KA;;;;
+3279;CIRCLED HANGUL THIEUTH A;So;0;L;<circle> 1110 1161;;;;N;CIRCLED HANGUL TA;;;;
+327A;CIRCLED HANGUL PHIEUPH A;So;0;L;<circle> 1111 1161;;;;N;CIRCLED HANGUL PA;;;;
+327B;CIRCLED HANGUL HIEUH A;So;0;L;<circle> 1112 1161;;;;N;CIRCLED HANGUL HA;;;;
+327F;KOREAN STANDARD SYMBOL;So;0;L;;;;;N;;;;;
+3280;CIRCLED IDEOGRAPH ONE;No;0;L;<circle> 4E00;;;1;N;;;;;
+3281;CIRCLED IDEOGRAPH TWO;No;0;L;<circle> 4E8C;;;2;N;;;;;
+3282;CIRCLED IDEOGRAPH THREE;No;0;L;<circle> 4E09;;;3;N;;;;;
+3283;CIRCLED IDEOGRAPH FOUR;No;0;L;<circle> 56DB;;;4;N;;;;;
+3284;CIRCLED IDEOGRAPH FIVE;No;0;L;<circle> 4E94;;;5;N;;;;;
+3285;CIRCLED IDEOGRAPH SIX;No;0;L;<circle> 516D;;;6;N;;;;;
+3286;CIRCLED IDEOGRAPH SEVEN;No;0;L;<circle> 4E03;;;7;N;;;;;
+3287;CIRCLED IDEOGRAPH EIGHT;No;0;L;<circle> 516B;;;8;N;;;;;
+3288;CIRCLED IDEOGRAPH NINE;No;0;L;<circle> 4E5D;;;9;N;;;;;
+3289;CIRCLED IDEOGRAPH TEN;No;0;L;<circle> 5341;;;10;N;;;;;
+328A;CIRCLED IDEOGRAPH MOON;So;0;L;<circle> 6708;;;;N;;;;;
+328B;CIRCLED IDEOGRAPH FIRE;So;0;L;<circle> 706B;;;;N;;;;;
+328C;CIRCLED IDEOGRAPH WATER;So;0;L;<circle> 6C34;;;;N;;;;;
+328D;CIRCLED IDEOGRAPH WOOD;So;0;L;<circle> 6728;;;;N;;;;;
+328E;CIRCLED IDEOGRAPH METAL;So;0;L;<circle> 91D1;;;;N;;;;;
+328F;CIRCLED IDEOGRAPH EARTH;So;0;L;<circle> 571F;;;;N;;;;;
+3290;CIRCLED IDEOGRAPH SUN;So;0;L;<circle> 65E5;;;;N;;;;;
+3291;CIRCLED IDEOGRAPH STOCK;So;0;L;<circle> 682A;;;;N;;;;;
+3292;CIRCLED IDEOGRAPH HAVE;So;0;L;<circle> 6709;;;;N;;;;;
+3293;CIRCLED IDEOGRAPH SOCIETY;So;0;L;<circle> 793E;;;;N;;;;;
+3294;CIRCLED IDEOGRAPH NAME;So;0;L;<circle> 540D;;;;N;;;;;
+3295;CIRCLED IDEOGRAPH SPECIAL;So;0;L;<circle> 7279;;;;N;;;;;
+3296;CIRCLED IDEOGRAPH FINANCIAL;So;0;L;<circle> 8CA1;;;;N;;;;;
+3297;CIRCLED IDEOGRAPH CONGRATULATION;So;0;L;<circle> 795D;;;;N;;;;;
+3298;CIRCLED IDEOGRAPH LABOR;So;0;L;<circle> 52B4;;;;N;;;;;
+3299;CIRCLED IDEOGRAPH SECRET;So;0;L;<circle> 79D8;;;;N;;;;;
+329A;CIRCLED IDEOGRAPH MALE;So;0;L;<circle> 7537;;;;N;;;;;
+329B;CIRCLED IDEOGRAPH FEMALE;So;0;L;<circle> 5973;;;;N;;;;;
+329C;CIRCLED IDEOGRAPH SUITABLE;So;0;L;<circle> 9069;;;;N;;;;;
+329D;CIRCLED IDEOGRAPH EXCELLENT;So;0;L;<circle> 512A;;;;N;;;;;
+329E;CIRCLED IDEOGRAPH PRINT;So;0;L;<circle> 5370;;;;N;;;;;
+329F;CIRCLED IDEOGRAPH ATTENTION;So;0;L;<circle> 6CE8;;;;N;;;;;
+32A0;CIRCLED IDEOGRAPH ITEM;So;0;L;<circle> 9805;;;;N;;;;;
+32A1;CIRCLED IDEOGRAPH REST;So;0;L;<circle> 4F11;;;;N;;;;;
+32A2;CIRCLED IDEOGRAPH COPY;So;0;L;<circle> 5199;;;;N;;;;;
+32A3;CIRCLED IDEOGRAPH CORRECT;So;0;L;<circle> 6B63;;;;N;;;;;
+32A4;CIRCLED IDEOGRAPH HIGH;So;0;L;<circle> 4E0A;;;;N;;;;;
+32A5;CIRCLED IDEOGRAPH CENTRE;So;0;L;<circle> 4E2D;;;;N;CIRCLED IDEOGRAPH CENTER;;;;
+32A6;CIRCLED IDEOGRAPH LOW;So;0;L;<circle> 4E0B;;;;N;;;;;
+32A7;CIRCLED IDEOGRAPH LEFT;So;0;L;<circle> 5DE6;;;;N;;;;;
+32A8;CIRCLED IDEOGRAPH RIGHT;So;0;L;<circle> 53F3;;;;N;;;;;
+32A9;CIRCLED IDEOGRAPH MEDICINE;So;0;L;<circle> 533B;;;;N;;;;;
+32AA;CIRCLED IDEOGRAPH RELIGION;So;0;L;<circle> 5B97;;;;N;;;;;
+32AB;CIRCLED IDEOGRAPH STUDY;So;0;L;<circle> 5B66;;;;N;;;;;
+32AC;CIRCLED IDEOGRAPH SUPERVISE;So;0;L;<circle> 76E3;;;;N;;;;;
+32AD;CIRCLED IDEOGRAPH ENTERPRISE;So;0;L;<circle> 4F01;;;;N;;;;;
+32AE;CIRCLED IDEOGRAPH RESOURCE;So;0;L;<circle> 8CC7;;;;N;;;;;
+32AF;CIRCLED IDEOGRAPH ALLIANCE;So;0;L;<circle> 5354;;;;N;;;;;
+32B0;CIRCLED IDEOGRAPH NIGHT;So;0;L;<circle> 591C;;;;N;;;;;
+32C0;IDEOGRAPHIC TELEGRAPH SYMBOL FOR JANUARY;So;0;L;<compat> 0031 6708;;;;N;;;;;
+32C1;IDEOGRAPHIC TELEGRAPH SYMBOL FOR FEBRUARY;So;0;L;<compat> 0032 6708;;;;N;;;;;
+32C2;IDEOGRAPHIC TELEGRAPH SYMBOL FOR MARCH;So;0;L;<compat> 0033 6708;;;;N;;;;;
+32C3;IDEOGRAPHIC TELEGRAPH SYMBOL FOR APRIL;So;0;L;<compat> 0034 6708;;;;N;;;;;
+32C4;IDEOGRAPHIC TELEGRAPH SYMBOL FOR MAY;So;0;L;<compat> 0035 6708;;;;N;;;;;
+32C5;IDEOGRAPHIC TELEGRAPH SYMBOL FOR JUNE;So;0;L;<compat> 0036 6708;;;;N;;;;;
+32C6;IDEOGRAPHIC TELEGRAPH SYMBOL FOR JULY;So;0;L;<compat> 0037 6708;;;;N;;;;;
+32C7;IDEOGRAPHIC TELEGRAPH SYMBOL FOR AUGUST;So;0;L;<compat> 0038 6708;;;;N;;;;;
+32C8;IDEOGRAPHIC TELEGRAPH SYMBOL FOR SEPTEMBER;So;0;L;<compat> 0039 6708;;;;N;;;;;
+32C9;IDEOGRAPHIC TELEGRAPH SYMBOL FOR OCTOBER;So;0;L;<compat> 0031 0030 6708;;;;N;;;;;
+32CA;IDEOGRAPHIC TELEGRAPH SYMBOL FOR NOVEMBER;So;0;L;<compat> 0031 0031 6708;;;;N;;;;;
+32CB;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DECEMBER;So;0;L;<compat> 0031 0032 6708;;;;N;;;;;
+32D0;CIRCLED KATAKANA A;So;0;L;<circle> 30A2;;;;N;;;;;
+32D1;CIRCLED KATAKANA I;So;0;L;<circle> 30A4;;;;N;;;;;
+32D2;CIRCLED KATAKANA U;So;0;L;<circle> 30A6;;;;N;;;;;
+32D3;CIRCLED KATAKANA E;So;0;L;<circle> 30A8;;;;N;;;;;
+32D4;CIRCLED KATAKANA O;So;0;L;<circle> 30AA;;;;N;;;;;
+32D5;CIRCLED KATAKANA KA;So;0;L;<circle> 30AB;;;;N;;;;;
+32D6;CIRCLED KATAKANA KI;So;0;L;<circle> 30AD;;;;N;;;;;
+32D7;CIRCLED KATAKANA KU;So;0;L;<circle> 30AF;;;;N;;;;;
+32D8;CIRCLED KATAKANA KE;So;0;L;<circle> 30B1;;;;N;;;;;
+32D9;CIRCLED KATAKANA KO;So;0;L;<circle> 30B3;;;;N;;;;;
+32DA;CIRCLED KATAKANA SA;So;0;L;<circle> 30B5;;;;N;;;;;
+32DB;CIRCLED KATAKANA SI;So;0;L;<circle> 30B7;;;;N;;;;;
+32DC;CIRCLED KATAKANA SU;So;0;L;<circle> 30B9;;;;N;;;;;
+32DD;CIRCLED KATAKANA SE;So;0;L;<circle> 30BB;;;;N;;;;;
+32DE;CIRCLED KATAKANA SO;So;0;L;<circle> 30BD;;;;N;;;;;
+32DF;CIRCLED KATAKANA TA;So;0;L;<circle> 30BF;;;;N;;;;;
+32E0;CIRCLED KATAKANA TI;So;0;L;<circle> 30C1;;;;N;;;;;
+32E1;CIRCLED KATAKANA TU;So;0;L;<circle> 30C4;;;;N;;;;;
+32E2;CIRCLED KATAKANA TE;So;0;L;<circle> 30C6;;;;N;;;;;
+32E3;CIRCLED KATAKANA TO;So;0;L;<circle> 30C8;;;;N;;;;;
+32E4;CIRCLED KATAKANA NA;So;0;L;<circle> 30CA;;;;N;;;;;
+32E5;CIRCLED KATAKANA NI;So;0;L;<circle> 30CB;;;;N;;;;;
+32E6;CIRCLED KATAKANA NU;So;0;L;<circle> 30CC;;;;N;;;;;
+32E7;CIRCLED KATAKANA NE;So;0;L;<circle> 30CD;;;;N;;;;;
+32E8;CIRCLED KATAKANA NO;So;0;L;<circle> 30CE;;;;N;;;;;
+32E9;CIRCLED KATAKANA HA;So;0;L;<circle> 30CF;;;;N;;;;;
+32EA;CIRCLED KATAKANA HI;So;0;L;<circle> 30D2;;;;N;;;;;
+32EB;CIRCLED KATAKANA HU;So;0;L;<circle> 30D5;;;;N;;;;;
+32EC;CIRCLED KATAKANA HE;So;0;L;<circle> 30D8;;;;N;;;;;
+32ED;CIRCLED KATAKANA HO;So;0;L;<circle> 30DB;;;;N;;;;;
+32EE;CIRCLED KATAKANA MA;So;0;L;<circle> 30DE;;;;N;;;;;
+32EF;CIRCLED KATAKANA MI;So;0;L;<circle> 30DF;;;;N;;;;;
+32F0;CIRCLED KATAKANA MU;So;0;L;<circle> 30E0;;;;N;;;;;
+32F1;CIRCLED KATAKANA ME;So;0;L;<circle> 30E1;;;;N;;;;;
+32F2;CIRCLED KATAKANA MO;So;0;L;<circle> 30E2;;;;N;;;;;
+32F3;CIRCLED KATAKANA YA;So;0;L;<circle> 30E4;;;;N;;;;;
+32F4;CIRCLED KATAKANA YU;So;0;L;<circle> 30E6;;;;N;;;;;
+32F5;CIRCLED KATAKANA YO;So;0;L;<circle> 30E8;;;;N;;;;;
+32F6;CIRCLED KATAKANA RA;So;0;L;<circle> 30E9;;;;N;;;;;
+32F7;CIRCLED KATAKANA RI;So;0;L;<circle> 30EA;;;;N;;;;;
+32F8;CIRCLED KATAKANA RU;So;0;L;<circle> 30EB;;;;N;;;;;
+32F9;CIRCLED KATAKANA RE;So;0;L;<circle> 30EC;;;;N;;;;;
+32FA;CIRCLED KATAKANA RO;So;0;L;<circle> 30ED;;;;N;;;;;
+32FB;CIRCLED KATAKANA WA;So;0;L;<circle> 30EF;;;;N;;;;;
+32FC;CIRCLED KATAKANA WI;So;0;L;<circle> 30F0;;;;N;;;;;
+32FD;CIRCLED KATAKANA WE;So;0;L;<circle> 30F1;;;;N;;;;;
+32FE;CIRCLED KATAKANA WO;So;0;L;<circle> 30F2;;;;N;;;;;
+3300;SQUARE APAATO;So;0;L;<square> 30A2 30D1 30FC 30C8;;;;N;SQUARED APAATO;;;;
+3301;SQUARE ARUHUA;So;0;L;<square> 30A2 30EB 30D5 30A1;;;;N;SQUARED ARUHUA;;;;
+3302;SQUARE ANPEA;So;0;L;<square> 30A2 30F3 30DA 30A2;;;;N;SQUARED ANPEA;;;;
+3303;SQUARE AARU;So;0;L;<square> 30A2 30FC 30EB;;;;N;SQUARED AARU;;;;
+3304;SQUARE ININGU;So;0;L;<square> 30A4 30CB 30F3 30B0;;;;N;SQUARED ININGU;;;;
+3305;SQUARE INTI;So;0;L;<square> 30A4 30F3 30C1;;;;N;SQUARED INTI;;;;
+3306;SQUARE UON;So;0;L;<square> 30A6 30A9 30F3;;;;N;SQUARED UON;;;;
+3307;SQUARE ESUKUUDO;So;0;L;<square> 30A8 30B9 30AF 30FC 30C9;;;;N;SQUARED ESUKUUDO;;;;
+3308;SQUARE EEKAA;So;0;L;<square> 30A8 30FC 30AB 30FC;;;;N;SQUARED EEKAA;;;;
+3309;SQUARE ONSU;So;0;L;<square> 30AA 30F3 30B9;;;;N;SQUARED ONSU;;;;
+330A;SQUARE OOMU;So;0;L;<square> 30AA 30FC 30E0;;;;N;SQUARED OOMU;;;;
+330B;SQUARE KAIRI;So;0;L;<square> 30AB 30A4 30EA;;;;N;SQUARED KAIRI;;;;
+330C;SQUARE KARATTO;So;0;L;<square> 30AB 30E9 30C3 30C8;;;;N;SQUARED KARATTO;;;;
+330D;SQUARE KARORII;So;0;L;<square> 30AB 30ED 30EA 30FC;;;;N;SQUARED KARORII;;;;
+330E;SQUARE GARON;So;0;L;<square> 30AC 30ED 30F3;;;;N;SQUARED GARON;;;;
+330F;SQUARE GANMA;So;0;L;<square> 30AC 30F3 30DE;;;;N;SQUARED GANMA;;;;
+3310;SQUARE GIGA;So;0;L;<square> 30AE 30AC;;;;N;SQUARED GIGA;;;;
+3311;SQUARE GINII;So;0;L;<square> 30AE 30CB 30FC;;;;N;SQUARED GINII;;;;
+3312;SQUARE KYURII;So;0;L;<square> 30AD 30E5 30EA 30FC;;;;N;SQUARED KYURII;;;;
+3313;SQUARE GIRUDAA;So;0;L;<square> 30AE 30EB 30C0 30FC;;;;N;SQUARED GIRUDAA;;;;
+3314;SQUARE KIRO;So;0;L;<square> 30AD 30ED;;;;N;SQUARED KIRO;;;;
+3315;SQUARE KIROGURAMU;So;0;L;<square> 30AD 30ED 30B0 30E9 30E0;;;;N;SQUARED KIROGURAMU;;;;
+3316;SQUARE KIROMEETORU;So;0;L;<square> 30AD 30ED 30E1 30FC 30C8 30EB;;;;N;SQUARED KIROMEETORU;;;;
+3317;SQUARE KIROWATTO;So;0;L;<square> 30AD 30ED 30EF 30C3 30C8;;;;N;SQUARED KIROWATTO;;;;
+3318;SQUARE GURAMU;So;0;L;<square> 30B0 30E9 30E0;;;;N;SQUARED GURAMU;;;;
+3319;SQUARE GURAMUTON;So;0;L;<square> 30B0 30E9 30E0 30C8 30F3;;;;N;SQUARED GURAMUTON;;;;
+331A;SQUARE KURUZEIRO;So;0;L;<square> 30AF 30EB 30BC 30A4 30ED;;;;N;SQUARED KURUZEIRO;;;;
+331B;SQUARE KUROONE;So;0;L;<square> 30AF 30ED 30FC 30CD;;;;N;SQUARED KUROONE;;;;
+331C;SQUARE KEESU;So;0;L;<square> 30B1 30FC 30B9;;;;N;SQUARED KEESU;;;;
+331D;SQUARE KORUNA;So;0;L;<square> 30B3 30EB 30CA;;;;N;SQUARED KORUNA;;;;
+331E;SQUARE KOOPO;So;0;L;<square> 30B3 30FC 30DD;;;;N;SQUARED KOOPO;;;;
+331F;SQUARE SAIKURU;So;0;L;<square> 30B5 30A4 30AF 30EB;;;;N;SQUARED SAIKURU;;;;
+3320;SQUARE SANTIIMU;So;0;L;<square> 30B5 30F3 30C1 30FC 30E0;;;;N;SQUARED SANTIIMU;;;;
+3321;SQUARE SIRINGU;So;0;L;<square> 30B7 30EA 30F3 30B0;;;;N;SQUARED SIRINGU;;;;
+3322;SQUARE SENTI;So;0;L;<square> 30BB 30F3 30C1;;;;N;SQUARED SENTI;;;;
+3323;SQUARE SENTO;So;0;L;<square> 30BB 30F3 30C8;;;;N;SQUARED SENTO;;;;
+3324;SQUARE DAASU;So;0;L;<square> 30C0 30FC 30B9;;;;N;SQUARED DAASU;;;;
+3325;SQUARE DESI;So;0;L;<square> 30C7 30B7;;;;N;SQUARED DESI;;;;
+3326;SQUARE DORU;So;0;L;<square> 30C9 30EB;;;;N;SQUARED DORU;;;;
+3327;SQUARE TON;So;0;L;<square> 30C8 30F3;;;;N;SQUARED TON;;;;
+3328;SQUARE NANO;So;0;L;<square> 30CA 30CE;;;;N;SQUARED NANO;;;;
+3329;SQUARE NOTTO;So;0;L;<square> 30CE 30C3 30C8;;;;N;SQUARED NOTTO;;;;
+332A;SQUARE HAITU;So;0;L;<square> 30CF 30A4 30C4;;;;N;SQUARED HAITU;;;;
+332B;SQUARE PAASENTO;So;0;L;<square> 30D1 30FC 30BB 30F3 30C8;;;;N;SQUARED PAASENTO;;;;
+332C;SQUARE PAATU;So;0;L;<square> 30D1 30FC 30C4;;;;N;SQUARED PAATU;;;;
+332D;SQUARE BAARERU;So;0;L;<square> 30D0 30FC 30EC 30EB;;;;N;SQUARED BAARERU;;;;
+332E;SQUARE PIASUTORU;So;0;L;<square> 30D4 30A2 30B9 30C8 30EB;;;;N;SQUARED PIASUTORU;;;;
+332F;SQUARE PIKURU;So;0;L;<square> 30D4 30AF 30EB;;;;N;SQUARED PIKURU;;;;
+3330;SQUARE PIKO;So;0;L;<square> 30D4 30B3;;;;N;SQUARED PIKO;;;;
+3331;SQUARE BIRU;So;0;L;<square> 30D3 30EB;;;;N;SQUARED BIRU;;;;
+3332;SQUARE HUARADDO;So;0;L;<square> 30D5 30A1 30E9 30C3 30C9;;;;N;SQUARED HUARADDO;;;;
+3333;SQUARE HUIITO;So;0;L;<square> 30D5 30A3 30FC 30C8;;;;N;SQUARED HUIITO;;;;
+3334;SQUARE BUSSYERU;So;0;L;<square> 30D6 30C3 30B7 30A7 30EB;;;;N;SQUARED BUSSYERU;;;;
+3335;SQUARE HURAN;So;0;L;<square> 30D5 30E9 30F3;;;;N;SQUARED HURAN;;;;
+3336;SQUARE HEKUTAARU;So;0;L;<square> 30D8 30AF 30BF 30FC 30EB;;;;N;SQUARED HEKUTAARU;;;;
+3337;SQUARE PESO;So;0;L;<square> 30DA 30BD;;;;N;SQUARED PESO;;;;
+3338;SQUARE PENIHI;So;0;L;<square> 30DA 30CB 30D2;;;;N;SQUARED PENIHI;;;;
+3339;SQUARE HERUTU;So;0;L;<square> 30D8 30EB 30C4;;;;N;SQUARED HERUTU;;;;
+333A;SQUARE PENSU;So;0;L;<square> 30DA 30F3 30B9;;;;N;SQUARED PENSU;;;;
+333B;SQUARE PEEZI;So;0;L;<square> 30DA 30FC 30B8;;;;N;SQUARED PEEZI;;;;
+333C;SQUARE BEETA;So;0;L;<square> 30D9 30FC 30BF;;;;N;SQUARED BEETA;;;;
+333D;SQUARE POINTO;So;0;L;<square> 30DD 30A4 30F3 30C8;;;;N;SQUARED POINTO;;;;
+333E;SQUARE BORUTO;So;0;L;<square> 30DC 30EB 30C8;;;;N;SQUARED BORUTO;;;;
+333F;SQUARE HON;So;0;L;<square> 30DB 30F3;;;;N;SQUARED HON;;;;
+3340;SQUARE PONDO;So;0;L;<square> 30DD 30F3 30C9;;;;N;SQUARED PONDO;;;;
+3341;SQUARE HOORU;So;0;L;<square> 30DB 30FC 30EB;;;;N;SQUARED HOORU;;;;
+3342;SQUARE HOON;So;0;L;<square> 30DB 30FC 30F3;;;;N;SQUARED HOON;;;;
+3343;SQUARE MAIKURO;So;0;L;<square> 30DE 30A4 30AF 30ED;;;;N;SQUARED MAIKURO;;;;
+3344;SQUARE MAIRU;So;0;L;<square> 30DE 30A4 30EB;;;;N;SQUARED MAIRU;;;;
+3345;SQUARE MAHHA;So;0;L;<square> 30DE 30C3 30CF;;;;N;SQUARED MAHHA;;;;
+3346;SQUARE MARUKU;So;0;L;<square> 30DE 30EB 30AF;;;;N;SQUARED MARUKU;;;;
+3347;SQUARE MANSYON;So;0;L;<square> 30DE 30F3 30B7 30E7 30F3;;;;N;SQUARED MANSYON;;;;
+3348;SQUARE MIKURON;So;0;L;<square> 30DF 30AF 30ED 30F3;;;;N;SQUARED MIKURON;;;;
+3349;SQUARE MIRI;So;0;L;<square> 30DF 30EA;;;;N;SQUARED MIRI;;;;
+334A;SQUARE MIRIBAARU;So;0;L;<square> 30DF 30EA 30D0 30FC 30EB;;;;N;SQUARED MIRIBAARU;;;;
+334B;SQUARE MEGA;So;0;L;<square> 30E1 30AC;;;;N;SQUARED MEGA;;;;
+334C;SQUARE MEGATON;So;0;L;<square> 30E1 30AC 30C8 30F3;;;;N;SQUARED MEGATON;;;;
+334D;SQUARE MEETORU;So;0;L;<square> 30E1 30FC 30C8 30EB;;;;N;SQUARED MEETORU;;;;
+334E;SQUARE YAADO;So;0;L;<square> 30E4 30FC 30C9;;;;N;SQUARED YAADO;;;;
+334F;SQUARE YAARU;So;0;L;<square> 30E4 30FC 30EB;;;;N;SQUARED YAARU;;;;
+3350;SQUARE YUAN;So;0;L;<square> 30E6 30A2 30F3;;;;N;SQUARED YUAN;;;;
+3351;SQUARE RITTORU;So;0;L;<square> 30EA 30C3 30C8 30EB;;;;N;SQUARED RITTORU;;;;
+3352;SQUARE RIRA;So;0;L;<square> 30EA 30E9;;;;N;SQUARED RIRA;;;;
+3353;SQUARE RUPII;So;0;L;<square> 30EB 30D4 30FC;;;;N;SQUARED RUPII;;;;
+3354;SQUARE RUUBURU;So;0;L;<square> 30EB 30FC 30D6 30EB;;;;N;SQUARED RUUBURU;;;;
+3355;SQUARE REMU;So;0;L;<square> 30EC 30E0;;;;N;SQUARED REMU;;;;
+3356;SQUARE RENTOGEN;So;0;L;<square> 30EC 30F3 30C8 30B2 30F3;;;;N;SQUARED RENTOGEN;;;;
+3357;SQUARE WATTO;So;0;L;<square> 30EF 30C3 30C8;;;;N;SQUARED WATTO;;;;
+3358;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR ZERO;So;0;L;<compat> 0030 70B9;;;;N;;;;;
+3359;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR ONE;So;0;L;<compat> 0031 70B9;;;;N;;;;;
+335A;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWO;So;0;L;<compat> 0032 70B9;;;;N;;;;;
+335B;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR THREE;So;0;L;<compat> 0033 70B9;;;;N;;;;;
+335C;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR FOUR;So;0;L;<compat> 0034 70B9;;;;N;;;;;
+335D;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR FIVE;So;0;L;<compat> 0035 70B9;;;;N;;;;;
+335E;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR SIX;So;0;L;<compat> 0036 70B9;;;;N;;;;;
+335F;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR SEVEN;So;0;L;<compat> 0037 70B9;;;;N;;;;;
+3360;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR EIGHT;So;0;L;<compat> 0038 70B9;;;;N;;;;;
+3361;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR NINE;So;0;L;<compat> 0039 70B9;;;;N;;;;;
+3362;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TEN;So;0;L;<compat> 0031 0030 70B9;;;;N;;;;;
+3363;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR ELEVEN;So;0;L;<compat> 0031 0031 70B9;;;;N;;;;;
+3364;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWELVE;So;0;L;<compat> 0031 0032 70B9;;;;N;;;;;
+3365;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR THIRTEEN;So;0;L;<compat> 0031 0033 70B9;;;;N;;;;;
+3366;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR FOURTEEN;So;0;L;<compat> 0031 0034 70B9;;;;N;;;;;
+3367;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR FIFTEEN;So;0;L;<compat> 0031 0035 70B9;;;;N;;;;;
+3368;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR SIXTEEN;So;0;L;<compat> 0031 0036 70B9;;;;N;;;;;
+3369;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR SEVENTEEN;So;0;L;<compat> 0031 0037 70B9;;;;N;;;;;
+336A;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR EIGHTEEN;So;0;L;<compat> 0031 0038 70B9;;;;N;;;;;
+336B;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR NINETEEN;So;0;L;<compat> 0031 0039 70B9;;;;N;;;;;
+336C;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY;So;0;L;<compat> 0032 0030 70B9;;;;N;;;;;
+336D;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY-ONE;So;0;L;<compat> 0032 0031 70B9;;;;N;;;;;
+336E;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY-TWO;So;0;L;<compat> 0032 0032 70B9;;;;N;;;;;
+336F;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY-THREE;So;0;L;<compat> 0032 0033 70B9;;;;N;;;;;
+3370;IDEOGRAPHIC TELEGRAPH SYMBOL FOR HOUR TWENTY-FOUR;So;0;L;<compat> 0032 0034 70B9;;;;N;;;;;
+3371;SQUARE HPA;So;0;L;<square> 0068 0050 0061;;;;N;;;;;
+3372;SQUARE DA;So;0;L;<square> 0064 0061;;;;N;;;;;
+3373;SQUARE AU;So;0;L;<square> 0041 0055;;;;N;;;;;
+3374;SQUARE BAR;So;0;L;<square> 0062 0061 0072;;;;N;;;;;
+3375;SQUARE OV;So;0;L;<square> 006F 0056;;;;N;;;;;
+3376;SQUARE PC;So;0;L;<square> 0070 0063;;;;N;;;;;
+337B;SQUARE ERA NAME HEISEI;So;0;L;<square> 5E73 6210;;;;N;SQUARED TWO IDEOGRAPHS ERA NAME HEISEI;;;;
+337C;SQUARE ERA NAME SYOUWA;So;0;L;<square> 662D 548C;;;;N;SQUARED TWO IDEOGRAPHS ERA NAME SYOUWA;;;;
+337D;SQUARE ERA NAME TAISYOU;So;0;L;<square> 5927 6B63;;;;N;SQUARED TWO IDEOGRAPHS ERA NAME TAISYOU;;;;
+337E;SQUARE ERA NAME MEIZI;So;0;L;<square> 660E 6CBB;;;;N;SQUARED TWO IDEOGRAPHS ERA NAME MEIZI;;;;
+337F;SQUARE CORPORATION;So;0;L;<square> 682A 5F0F 4F1A 793E;;;;N;SQUARED FOUR IDEOGRAPHS CORPORATION;;;;
+3380;SQUARE PA AMPS;So;0;L;<square> 0070 0041;;;;N;SQUARED PA AMPS;;;;
+3381;SQUARE NA;So;0;L;<square> 006E 0041;;;;N;SQUARED NA;;;;
+3382;SQUARE MU A;So;0;L;<square> 03BC 0041;;;;N;SQUARED MU A;;;;
+3383;SQUARE MA;So;0;L;<square> 006D 0041;;;;N;SQUARED MA;;;;
+3384;SQUARE KA;So;0;L;<square> 006B 0041;;;;N;SQUARED KA;;;;
+3385;SQUARE KB;So;0;L;<square> 004B 0042;;;;N;SQUARED KB;;;;
+3386;SQUARE MB;So;0;L;<square> 004D 0042;;;;N;SQUARED MB;;;;
+3387;SQUARE GB;So;0;L;<square> 0047 0042;;;;N;SQUARED GB;;;;
+3388;SQUARE CAL;So;0;L;<square> 0063 0061 006C;;;;N;SQUARED CAL;;;;
+3389;SQUARE KCAL;So;0;L;<square> 006B 0063 0061 006C;;;;N;SQUARED KCAL;;;;
+338A;SQUARE PF;So;0;L;<square> 0070 0046;;;;N;SQUARED PF;;;;
+338B;SQUARE NF;So;0;L;<square> 006E 0046;;;;N;SQUARED NF;;;;
+338C;SQUARE MU F;So;0;L;<square> 03BC 0046;;;;N;SQUARED MU F;;;;
+338D;SQUARE MU G;So;0;L;<square> 03BC 0067;;;;N;SQUARED MU G;;;;
+338E;SQUARE MG;So;0;L;<square> 006D 0067;;;;N;SQUARED MG;;;;
+338F;SQUARE KG;So;0;L;<square> 006B 0067;;;;N;SQUARED KG;;;;
+3390;SQUARE HZ;So;0;L;<square> 0048 007A;;;;N;SQUARED HZ;;;;
+3391;SQUARE KHZ;So;0;L;<square> 006B 0048 007A;;;;N;SQUARED KHZ;;;;
+3392;SQUARE MHZ;So;0;L;<square> 004D 0048 007A;;;;N;SQUARED MHZ;;;;
+3393;SQUARE GHZ;So;0;L;<square> 0047 0048 007A;;;;N;SQUARED GHZ;;;;
+3394;SQUARE THZ;So;0;L;<square> 0054 0048 007A;;;;N;SQUARED THZ;;;;
+3395;SQUARE MU L;So;0;L;<square> 03BC 2113;;;;N;SQUARED MU L;;;;
+3396;SQUARE ML;So;0;L;<square> 006D 2113;;;;N;SQUARED ML;;;;
+3397;SQUARE DL;So;0;L;<square> 0064 2113;;;;N;SQUARED DL;;;;
+3398;SQUARE KL;So;0;L;<square> 006B 2113;;;;N;SQUARED KL;;;;
+3399;SQUARE FM;So;0;L;<square> 0066 006D;;;;N;SQUARED FM;;;;
+339A;SQUARE NM;So;0;L;<square> 006E 006D;;;;N;SQUARED NM;;;;
+339B;SQUARE MU M;So;0;L;<square> 03BC 006D;;;;N;SQUARED MU M;;;;
+339C;SQUARE MM;So;0;L;<square> 006D 006D;;;;N;SQUARED MM;;;;
+339D;SQUARE CM;So;0;L;<square> 0063 006D;;;;N;SQUARED CM;;;;
+339E;SQUARE KM;So;0;L;<square> 006B 006D;;;;N;SQUARED KM;;;;
+339F;SQUARE MM SQUARED;So;0;L;<square> 006D 006D 00B2;;;;N;SQUARED MM SQUARED;;;;
+33A0;SQUARE CM SQUARED;So;0;L;<square> 0063 006D 00B2;;;;N;SQUARED CM SQUARED;;;;
+33A1;SQUARE M SQUARED;So;0;L;<square> 006D 00B2;;;;N;SQUARED M SQUARED;;;;
+33A2;SQUARE KM SQUARED;So;0;L;<square> 006B 006D 00B2;;;;N;SQUARED KM SQUARED;;;;
+33A3;SQUARE MM CUBED;So;0;L;<square> 006D 006D 00B3;;;;N;SQUARED MM CUBED;;;;
+33A4;SQUARE CM CUBED;So;0;L;<square> 0063 006D 00B3;;;;N;SQUARED CM CUBED;;;;
+33A5;SQUARE M CUBED;So;0;L;<square> 006D 00B3;;;;N;SQUARED M CUBED;;;;
+33A6;SQUARE KM CUBED;So;0;L;<square> 006B 006D 00B3;;;;N;SQUARED KM CUBED;;;;
+33A7;SQUARE M OVER S;So;0;L;<square> 006D 2215 0073;;;;N;SQUARED M OVER S;;;;
+33A8;SQUARE M OVER S SQUARED;So;0;L;<square> 006D 2215 0073 00B2;;;;N;SQUARED M OVER S SQUARED;;;;
+33A9;SQUARE PA;So;0;L;<square> 0050 0061;;;;N;SQUARED PA;;;;
+33AA;SQUARE KPA;So;0;L;<square> 006B 0050 0061;;;;N;SQUARED KPA;;;;
+33AB;SQUARE MPA;So;0;L;<square> 004D 0050 0061;;;;N;SQUARED MPA;;;;
+33AC;SQUARE GPA;So;0;L;<square> 0047 0050 0061;;;;N;SQUARED GPA;;;;
+33AD;SQUARE RAD;So;0;L;<square> 0072 0061 0064;;;;N;SQUARED RAD;;;;
+33AE;SQUARE RAD OVER S;So;0;L;<square> 0072 0061 0064 2215 0073;;;;N;SQUARED RAD OVER S;;;;
+33AF;SQUARE RAD OVER S SQUARED;So;0;L;<square> 0072 0061 0064 2215 0073 00B2;;;;N;SQUARED RAD OVER S SQUARED;;;;
+33B0;SQUARE PS;So;0;L;<square> 0070 0073;;;;N;SQUARED PS;;;;
+33B1;SQUARE NS;So;0;L;<square> 006E 0073;;;;N;SQUARED NS;;;;
+33B2;SQUARE MU S;So;0;L;<square> 03BC 0073;;;;N;SQUARED MU S;;;;
+33B3;SQUARE MS;So;0;L;<square> 006D 0073;;;;N;SQUARED MS;;;;
+33B4;SQUARE PV;So;0;L;<square> 0070 0056;;;;N;SQUARED PV;;;;
+33B5;SQUARE NV;So;0;L;<square> 006E 0056;;;;N;SQUARED NV;;;;
+33B6;SQUARE MU V;So;0;L;<square> 03BC 0056;;;;N;SQUARED MU V;;;;
+33B7;SQUARE MV;So;0;L;<square> 006D 0056;;;;N;SQUARED MV;;;;
+33B8;SQUARE KV;So;0;L;<square> 006B 0056;;;;N;SQUARED KV;;;;
+33B9;SQUARE MV MEGA;So;0;L;<square> 004D 0056;;;;N;SQUARED MV MEGA;;;;
+33BA;SQUARE PW;So;0;L;<square> 0070 0057;;;;N;SQUARED PW;;;;
+33BB;SQUARE NW;So;0;L;<square> 006E 0057;;;;N;SQUARED NW;;;;
+33BC;SQUARE MU W;So;0;L;<square> 03BC 0057;;;;N;SQUARED MU W;;;;
+33BD;SQUARE MW;So;0;L;<square> 006D 0057;;;;N;SQUARED MW;;;;
+33BE;SQUARE KW;So;0;L;<square> 006B 0057;;;;N;SQUARED KW;;;;
+33BF;SQUARE MW MEGA;So;0;L;<square> 004D 0057;;;;N;SQUARED MW MEGA;;;;
+33C0;SQUARE K OHM;So;0;L;<square> 006B 03A9;;;;N;SQUARED K OHM;;;;
+33C1;SQUARE M OHM;So;0;L;<square> 004D 03A9;;;;N;SQUARED M OHM;;;;
+33C2;SQUARE AM;So;0;L;<square> 0061 002E 006D 002E;;;;N;SQUARED AM;;;;
+33C3;SQUARE BQ;So;0;L;<square> 0042 0071;;;;N;SQUARED BQ;;;;
+33C4;SQUARE CC;So;0;L;<square> 0063 0063;;;;N;SQUARED CC;;;;
+33C5;SQUARE CD;So;0;L;<square> 0063 0064;;;;N;SQUARED CD;;;;
+33C6;SQUARE C OVER KG;So;0;L;<square> 0043 2215 006B 0067;;;;N;SQUARED C OVER KG;;;;
+33C7;SQUARE CO;So;0;L;<square> 0043 006F 002E;;;;N;SQUARED CO;;;;
+33C8;SQUARE DB;So;0;L;<square> 0064 0042;;;;N;SQUARED DB;;;;
+33C9;SQUARE GY;So;0;L;<square> 0047 0079;;;;N;SQUARED GY;;;;
+33CA;SQUARE HA;So;0;L;<square> 0068 0061;;;;N;SQUARED HA;;;;
+33CB;SQUARE HP;So;0;L;<square> 0048 0050;;;;N;SQUARED HP;;;;
+33CC;SQUARE IN;So;0;L;<square> 0069 006E;;;;N;SQUARED IN;;;;
+33CD;SQUARE KK;So;0;L;<square> 004B 004B;;;;N;SQUARED KK;;;;
+33CE;SQUARE KM CAPITAL;So;0;L;<square> 004B 004D;;;;N;SQUARED KM CAPITAL;;;;
+33CF;SQUARE KT;So;0;L;<square> 006B 0074;;;;N;SQUARED KT;;;;
+33D0;SQUARE LM;So;0;L;<square> 006C 006D;;;;N;SQUARED LM;;;;
+33D1;SQUARE LN;So;0;L;<square> 006C 006E;;;;N;SQUARED LN;;;;
+33D2;SQUARE LOG;So;0;L;<square> 006C 006F 0067;;;;N;SQUARED LOG;;;;
+33D3;SQUARE LX;So;0;L;<square> 006C 0078;;;;N;SQUARED LX;;;;
+33D4;SQUARE MB SMALL;So;0;L;<square> 006D 0062;;;;N;SQUARED MB SMALL;;;;
+33D5;SQUARE MIL;So;0;L;<square> 006D 0069 006C;;;;N;SQUARED MIL;;;;
+33D6;SQUARE MOL;So;0;L;<square> 006D 006F 006C;;;;N;SQUARED MOL;;;;
+33D7;SQUARE PH;So;0;L;<square> 0050 0048;;;;N;SQUARED PH;;;;
+33D8;SQUARE PM;So;0;L;<square> 0070 002E 006D 002E;;;;N;SQUARED PM;;;;
+33D9;SQUARE PPM;So;0;L;<square> 0050 0050 004D;;;;N;SQUARED PPM;;;;
+33DA;SQUARE PR;So;0;L;<square> 0050 0052;;;;N;SQUARED PR;;;;
+33DB;SQUARE SR;So;0;L;<square> 0073 0072;;;;N;SQUARED SR;;;;
+33DC;SQUARE SV;So;0;L;<square> 0053 0076;;;;N;SQUARED SV;;;;
+33DD;SQUARE WB;So;0;L;<square> 0057 0062;;;;N;SQUARED WB;;;;
+33E0;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY ONE;So;0;L;<compat> 0031 65E5;;;;N;;;;;
+33E1;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWO;So;0;L;<compat> 0032 65E5;;;;N;;;;;
+33E2;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY THREE;So;0;L;<compat> 0033 65E5;;;;N;;;;;
+33E3;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY FOUR;So;0;L;<compat> 0034 65E5;;;;N;;;;;
+33E4;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY FIVE;So;0;L;<compat> 0035 65E5;;;;N;;;;;
+33E5;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY SIX;So;0;L;<compat> 0036 65E5;;;;N;;;;;
+33E6;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY SEVEN;So;0;L;<compat> 0037 65E5;;;;N;;;;;
+33E7;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY EIGHT;So;0;L;<compat> 0038 65E5;;;;N;;;;;
+33E8;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY NINE;So;0;L;<compat> 0039 65E5;;;;N;;;;;
+33E9;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TEN;So;0;L;<compat> 0031 0030 65E5;;;;N;;;;;
+33EA;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY ELEVEN;So;0;L;<compat> 0031 0031 65E5;;;;N;;;;;
+33EB;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWELVE;So;0;L;<compat> 0031 0032 65E5;;;;N;;;;;
+33EC;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY THIRTEEN;So;0;L;<compat> 0031 0033 65E5;;;;N;;;;;
+33ED;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY FOURTEEN;So;0;L;<compat> 0031 0034 65E5;;;;N;;;;;
+33EE;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY FIFTEEN;So;0;L;<compat> 0031 0035 65E5;;;;N;;;;;
+33EF;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY SIXTEEN;So;0;L;<compat> 0031 0036 65E5;;;;N;;;;;
+33F0;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY SEVENTEEN;So;0;L;<compat> 0031 0037 65E5;;;;N;;;;;
+33F1;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY EIGHTEEN;So;0;L;<compat> 0031 0038 65E5;;;;N;;;;;
+33F2;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY NINETEEN;So;0;L;<compat> 0031 0039 65E5;;;;N;;;;;
+33F3;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY;So;0;L;<compat> 0032 0030 65E5;;;;N;;;;;
+33F4;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-ONE;So;0;L;<compat> 0032 0031 65E5;;;;N;;;;;
+33F5;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-TWO;So;0;L;<compat> 0032 0032 65E5;;;;N;;;;;
+33F6;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-THREE;So;0;L;<compat> 0032 0033 65E5;;;;N;;;;;
+33F7;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-FOUR;So;0;L;<compat> 0032 0034 65E5;;;;N;;;;;
+33F8;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-FIVE;So;0;L;<compat> 0032 0035 65E5;;;;N;;;;;
+33F9;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-SIX;So;0;L;<compat> 0032 0036 65E5;;;;N;;;;;
+33FA;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-SEVEN;So;0;L;<compat> 0032 0037 65E5;;;;N;;;;;
+33FB;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-EIGHT;So;0;L;<compat> 0032 0038 65E5;;;;N;;;;;
+33FC;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY TWENTY-NINE;So;0;L;<compat> 0032 0039 65E5;;;;N;;;;;
+33FD;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY THIRTY;So;0;L;<compat> 0033 0030 65E5;;;;N;;;;;
+33FE;IDEOGRAPHIC TELEGRAPH SYMBOL FOR DAY THIRTY-ONE;So;0;L;<compat> 0033 0031 65E5;;;;N;;;;;
+3400;<CJK Ideograph Extension A, First>;Lo;0;L;;;;;N;;;;;
+4DB5;<CJK Ideograph Extension A, Last>;Lo;0;L;;;;;N;;;;;
+4E00;<CJK Ideograph, First>;Lo;0;L;;;;;N;;;;;
+9FA5;<CJK Ideograph, Last>;Lo;0;L;;;;;N;;;;;
+A000;YI SYLLABLE IT;Lo;0;L;;;;;N;;;;;
+A001;YI SYLLABLE IX;Lo;0;L;;;;;N;;;;;
+A002;YI SYLLABLE I;Lo;0;L;;;;;N;;;;;
+A003;YI SYLLABLE IP;Lo;0;L;;;;;N;;;;;
+A004;YI SYLLABLE IET;Lo;0;L;;;;;N;;;;;
+A005;YI SYLLABLE IEX;Lo;0;L;;;;;N;;;;;
+A006;YI SYLLABLE IE;Lo;0;L;;;;;N;;;;;
+A007;YI SYLLABLE IEP;Lo;0;L;;;;;N;;;;;
+A008;YI SYLLABLE AT;Lo;0;L;;;;;N;;;;;
+A009;YI SYLLABLE AX;Lo;0;L;;;;;N;;;;;
+A00A;YI SYLLABLE A;Lo;0;L;;;;;N;;;;;
+A00B;YI SYLLABLE AP;Lo;0;L;;;;;N;;;;;
+A00C;YI SYLLABLE UOX;Lo;0;L;;;;;N;;;;;
+A00D;YI SYLLABLE UO;Lo;0;L;;;;;N;;;;;
+A00E;YI SYLLABLE UOP;Lo;0;L;;;;;N;;;;;
+A00F;YI SYLLABLE OT;Lo;0;L;;;;;N;;;;;
+A010;YI SYLLABLE OX;Lo;0;L;;;;;N;;;;;
+A011;YI SYLLABLE O;Lo;0;L;;;;;N;;;;;
+A012;YI SYLLABLE OP;Lo;0;L;;;;;N;;;;;
+A013;YI SYLLABLE EX;Lo;0;L;;;;;N;;;;;
+A014;YI SYLLABLE E;Lo;0;L;;;;;N;;;;;
+A015;YI SYLLABLE WU;Lo;0;L;;;;;N;;;;;
+A016;YI SYLLABLE BIT;Lo;0;L;;;;;N;;;;;
+A017;YI SYLLABLE BIX;Lo;0;L;;;;;N;;;;;
+A018;YI SYLLABLE BI;Lo;0;L;;;;;N;;;;;
+A019;YI SYLLABLE BIP;Lo;0;L;;;;;N;;;;;
+A01A;YI SYLLABLE BIET;Lo;0;L;;;;;N;;;;;
+A01B;YI SYLLABLE BIEX;Lo;0;L;;;;;N;;;;;
+A01C;YI SYLLABLE BIE;Lo;0;L;;;;;N;;;;;
+A01D;YI SYLLABLE BIEP;Lo;0;L;;;;;N;;;;;
+A01E;YI SYLLABLE BAT;Lo;0;L;;;;;N;;;;;
+A01F;YI SYLLABLE BAX;Lo;0;L;;;;;N;;;;;
+A020;YI SYLLABLE BA;Lo;0;L;;;;;N;;;;;
+A021;YI SYLLABLE BAP;Lo;0;L;;;;;N;;;;;
+A022;YI SYLLABLE BUOX;Lo;0;L;;;;;N;;;;;
+A023;YI SYLLABLE BUO;Lo;0;L;;;;;N;;;;;
+A024;YI SYLLABLE BUOP;Lo;0;L;;;;;N;;;;;
+A025;YI SYLLABLE BOT;Lo;0;L;;;;;N;;;;;
+A026;YI SYLLABLE BOX;Lo;0;L;;;;;N;;;;;
+A027;YI SYLLABLE BO;Lo;0;L;;;;;N;;;;;
+A028;YI SYLLABLE BOP;Lo;0;L;;;;;N;;;;;
+A029;YI SYLLABLE BEX;Lo;0;L;;;;;N;;;;;
+A02A;YI SYLLABLE BE;Lo;0;L;;;;;N;;;;;
+A02B;YI SYLLABLE BEP;Lo;0;L;;;;;N;;;;;
+A02C;YI SYLLABLE BUT;Lo;0;L;;;;;N;;;;;
+A02D;YI SYLLABLE BUX;Lo;0;L;;;;;N;;;;;
+A02E;YI SYLLABLE BU;Lo;0;L;;;;;N;;;;;
+A02F;YI SYLLABLE BUP;Lo;0;L;;;;;N;;;;;
+A030;YI SYLLABLE BURX;Lo;0;L;;;;;N;;;;;
+A031;YI SYLLABLE BUR;Lo;0;L;;;;;N;;;;;
+A032;YI SYLLABLE BYT;Lo;0;L;;;;;N;;;;;
+A033;YI SYLLABLE BYX;Lo;0;L;;;;;N;;;;;
+A034;YI SYLLABLE BY;Lo;0;L;;;;;N;;;;;
+A035;YI SYLLABLE BYP;Lo;0;L;;;;;N;;;;;
+A036;YI SYLLABLE BYRX;Lo;0;L;;;;;N;;;;;
+A037;YI SYLLABLE BYR;Lo;0;L;;;;;N;;;;;
+A038;YI SYLLABLE PIT;Lo;0;L;;;;;N;;;;;
+A039;YI SYLLABLE PIX;Lo;0;L;;;;;N;;;;;
+A03A;YI SYLLABLE PI;Lo;0;L;;;;;N;;;;;
+A03B;YI SYLLABLE PIP;Lo;0;L;;;;;N;;;;;
+A03C;YI SYLLABLE PIEX;Lo;0;L;;;;;N;;;;;
+A03D;YI SYLLABLE PIE;Lo;0;L;;;;;N;;;;;
+A03E;YI SYLLABLE PIEP;Lo;0;L;;;;;N;;;;;
+A03F;YI SYLLABLE PAT;Lo;0;L;;;;;N;;;;;
+A040;YI SYLLABLE PAX;Lo;0;L;;;;;N;;;;;
+A041;YI SYLLABLE PA;Lo;0;L;;;;;N;;;;;
+A042;YI SYLLABLE PAP;Lo;0;L;;;;;N;;;;;
+A043;YI SYLLABLE PUOX;Lo;0;L;;;;;N;;;;;
+A044;YI SYLLABLE PUO;Lo;0;L;;;;;N;;;;;
+A045;YI SYLLABLE PUOP;Lo;0;L;;;;;N;;;;;
+A046;YI SYLLABLE POT;Lo;0;L;;;;;N;;;;;
+A047;YI SYLLABLE POX;Lo;0;L;;;;;N;;;;;
+A048;YI SYLLABLE PO;Lo;0;L;;;;;N;;;;;
+A049;YI SYLLABLE POP;Lo;0;L;;;;;N;;;;;
+A04A;YI SYLLABLE PUT;Lo;0;L;;;;;N;;;;;
+A04B;YI SYLLABLE PUX;Lo;0;L;;;;;N;;;;;
+A04C;YI SYLLABLE PU;Lo;0;L;;;;;N;;;;;
+A04D;YI SYLLABLE PUP;Lo;0;L;;;;;N;;;;;
+A04E;YI SYLLABLE PURX;Lo;0;L;;;;;N;;;;;
+A04F;YI SYLLABLE PUR;Lo;0;L;;;;;N;;;;;
+A050;YI SYLLABLE PYT;Lo;0;L;;;;;N;;;;;
+A051;YI SYLLABLE PYX;Lo;0;L;;;;;N;;;;;
+A052;YI SYLLABLE PY;Lo;0;L;;;;;N;;;;;
+A053;YI SYLLABLE PYP;Lo;0;L;;;;;N;;;;;
+A054;YI SYLLABLE PYRX;Lo;0;L;;;;;N;;;;;
+A055;YI SYLLABLE PYR;Lo;0;L;;;;;N;;;;;
+A056;YI SYLLABLE BBIT;Lo;0;L;;;;;N;;;;;
+A057;YI SYLLABLE BBIX;Lo;0;L;;;;;N;;;;;
+A058;YI SYLLABLE BBI;Lo;0;L;;;;;N;;;;;
+A059;YI SYLLABLE BBIP;Lo;0;L;;;;;N;;;;;
+A05A;YI SYLLABLE BBIET;Lo;0;L;;;;;N;;;;;
+A05B;YI SYLLABLE BBIEX;Lo;0;L;;;;;N;;;;;
+A05C;YI SYLLABLE BBIE;Lo;0;L;;;;;N;;;;;
+A05D;YI SYLLABLE BBIEP;Lo;0;L;;;;;N;;;;;
+A05E;YI SYLLABLE BBAT;Lo;0;L;;;;;N;;;;;
+A05F;YI SYLLABLE BBAX;Lo;0;L;;;;;N;;;;;
+A060;YI SYLLABLE BBA;Lo;0;L;;;;;N;;;;;
+A061;YI SYLLABLE BBAP;Lo;0;L;;;;;N;;;;;
+A062;YI SYLLABLE BBUOX;Lo;0;L;;;;;N;;;;;
+A063;YI SYLLABLE BBUO;Lo;0;L;;;;;N;;;;;
+A064;YI SYLLABLE BBUOP;Lo;0;L;;;;;N;;;;;
+A065;YI SYLLABLE BBOT;Lo;0;L;;;;;N;;;;;
+A066;YI SYLLABLE BBOX;Lo;0;L;;;;;N;;;;;
+A067;YI SYLLABLE BBO;Lo;0;L;;;;;N;;;;;
+A068;YI SYLLABLE BBOP;Lo;0;L;;;;;N;;;;;
+A069;YI SYLLABLE BBEX;Lo;0;L;;;;;N;;;;;
+A06A;YI SYLLABLE BBE;Lo;0;L;;;;;N;;;;;
+A06B;YI SYLLABLE BBEP;Lo;0;L;;;;;N;;;;;
+A06C;YI SYLLABLE BBUT;Lo;0;L;;;;;N;;;;;
+A06D;YI SYLLABLE BBUX;Lo;0;L;;;;;N;;;;;
+A06E;YI SYLLABLE BBU;Lo;0;L;;;;;N;;;;;
+A06F;YI SYLLABLE BBUP;Lo;0;L;;;;;N;;;;;
+A070;YI SYLLABLE BBURX;Lo;0;L;;;;;N;;;;;
+A071;YI SYLLABLE BBUR;Lo;0;L;;;;;N;;;;;
+A072;YI SYLLABLE BBYT;Lo;0;L;;;;;N;;;;;
+A073;YI SYLLABLE BBYX;Lo;0;L;;;;;N;;;;;
+A074;YI SYLLABLE BBY;Lo;0;L;;;;;N;;;;;
+A075;YI SYLLABLE BBYP;Lo;0;L;;;;;N;;;;;
+A076;YI SYLLABLE NBIT;Lo;0;L;;;;;N;;;;;
+A077;YI SYLLABLE NBIX;Lo;0;L;;;;;N;;;;;
+A078;YI SYLLABLE NBI;Lo;0;L;;;;;N;;;;;
+A079;YI SYLLABLE NBIP;Lo;0;L;;;;;N;;;;;
+A07A;YI SYLLABLE NBIEX;Lo;0;L;;;;;N;;;;;
+A07B;YI SYLLABLE NBIE;Lo;0;L;;;;;N;;;;;
+A07C;YI SYLLABLE NBIEP;Lo;0;L;;;;;N;;;;;
+A07D;YI SYLLABLE NBAT;Lo;0;L;;;;;N;;;;;
+A07E;YI SYLLABLE NBAX;Lo;0;L;;;;;N;;;;;
+A07F;YI SYLLABLE NBA;Lo;0;L;;;;;N;;;;;
+A080;YI SYLLABLE NBAP;Lo;0;L;;;;;N;;;;;
+A081;YI SYLLABLE NBOT;Lo;0;L;;;;;N;;;;;
+A082;YI SYLLABLE NBOX;Lo;0;L;;;;;N;;;;;
+A083;YI SYLLABLE NBO;Lo;0;L;;;;;N;;;;;
+A084;YI SYLLABLE NBOP;Lo;0;L;;;;;N;;;;;
+A085;YI SYLLABLE NBUT;Lo;0;L;;;;;N;;;;;
+A086;YI SYLLABLE NBUX;Lo;0;L;;;;;N;;;;;
+A087;YI SYLLABLE NBU;Lo;0;L;;;;;N;;;;;
+A088;YI SYLLABLE NBUP;Lo;0;L;;;;;N;;;;;
+A089;YI SYLLABLE NBURX;Lo;0;L;;;;;N;;;;;
+A08A;YI SYLLABLE NBUR;Lo;0;L;;;;;N;;;;;
+A08B;YI SYLLABLE NBYT;Lo;0;L;;;;;N;;;;;
+A08C;YI SYLLABLE NBYX;Lo;0;L;;;;;N;;;;;
+A08D;YI SYLLABLE NBY;Lo;0;L;;;;;N;;;;;
+A08E;YI SYLLABLE NBYP;Lo;0;L;;;;;N;;;;;
+A08F;YI SYLLABLE NBYRX;Lo;0;L;;;;;N;;;;;
+A090;YI SYLLABLE NBYR;Lo;0;L;;;;;N;;;;;
+A091;YI SYLLABLE HMIT;Lo;0;L;;;;;N;;;;;
+A092;YI SYLLABLE HMIX;Lo;0;L;;;;;N;;;;;
+A093;YI SYLLABLE HMI;Lo;0;L;;;;;N;;;;;
+A094;YI SYLLABLE HMIP;Lo;0;L;;;;;N;;;;;
+A095;YI SYLLABLE HMIEX;Lo;0;L;;;;;N;;;;;
+A096;YI SYLLABLE HMIE;Lo;0;L;;;;;N;;;;;
+A097;YI SYLLABLE HMIEP;Lo;0;L;;;;;N;;;;;
+A098;YI SYLLABLE HMAT;Lo;0;L;;;;;N;;;;;
+A099;YI SYLLABLE HMAX;Lo;0;L;;;;;N;;;;;
+A09A;YI SYLLABLE HMA;Lo;0;L;;;;;N;;;;;
+A09B;YI SYLLABLE HMAP;Lo;0;L;;;;;N;;;;;
+A09C;YI SYLLABLE HMUOX;Lo;0;L;;;;;N;;;;;
+A09D;YI SYLLABLE HMUO;Lo;0;L;;;;;N;;;;;
+A09E;YI SYLLABLE HMUOP;Lo;0;L;;;;;N;;;;;
+A09F;YI SYLLABLE HMOT;Lo;0;L;;;;;N;;;;;
+A0A0;YI SYLLABLE HMOX;Lo;0;L;;;;;N;;;;;
+A0A1;YI SYLLABLE HMO;Lo;0;L;;;;;N;;;;;
+A0A2;YI SYLLABLE HMOP;Lo;0;L;;;;;N;;;;;
+A0A3;YI SYLLABLE HMUT;Lo;0;L;;;;;N;;;;;
+A0A4;YI SYLLABLE HMUX;Lo;0;L;;;;;N;;;;;
+A0A5;YI SYLLABLE HMU;Lo;0;L;;;;;N;;;;;
+A0A6;YI SYLLABLE HMUP;Lo;0;L;;;;;N;;;;;
+A0A7;YI SYLLABLE HMURX;Lo;0;L;;;;;N;;;;;
+A0A8;YI SYLLABLE HMUR;Lo;0;L;;;;;N;;;;;
+A0A9;YI SYLLABLE HMYX;Lo;0;L;;;;;N;;;;;
+A0AA;YI SYLLABLE HMY;Lo;0;L;;;;;N;;;;;
+A0AB;YI SYLLABLE HMYP;Lo;0;L;;;;;N;;;;;
+A0AC;YI SYLLABLE HMYRX;Lo;0;L;;;;;N;;;;;
+A0AD;YI SYLLABLE HMYR;Lo;0;L;;;;;N;;;;;
+A0AE;YI SYLLABLE MIT;Lo;0;L;;;;;N;;;;;
+A0AF;YI SYLLABLE MIX;Lo;0;L;;;;;N;;;;;
+A0B0;YI SYLLABLE MI;Lo;0;L;;;;;N;;;;;
+A0B1;YI SYLLABLE MIP;Lo;0;L;;;;;N;;;;;
+A0B2;YI SYLLABLE MIEX;Lo;0;L;;;;;N;;;;;
+A0B3;YI SYLLABLE MIE;Lo;0;L;;;;;N;;;;;
+A0B4;YI SYLLABLE MIEP;Lo;0;L;;;;;N;;;;;
+A0B5;YI SYLLABLE MAT;Lo;0;L;;;;;N;;;;;
+A0B6;YI SYLLABLE MAX;Lo;0;L;;;;;N;;;;;
+A0B7;YI SYLLABLE MA;Lo;0;L;;;;;N;;;;;
+A0B8;YI SYLLABLE MAP;Lo;0;L;;;;;N;;;;;
+A0B9;YI SYLLABLE MUOT;Lo;0;L;;;;;N;;;;;
+A0BA;YI SYLLABLE MUOX;Lo;0;L;;;;;N;;;;;
+A0BB;YI SYLLABLE MUO;Lo;0;L;;;;;N;;;;;
+A0BC;YI SYLLABLE MUOP;Lo;0;L;;;;;N;;;;;
+A0BD;YI SYLLABLE MOT;Lo;0;L;;;;;N;;;;;
+A0BE;YI SYLLABLE MOX;Lo;0;L;;;;;N;;;;;
+A0BF;YI SYLLABLE MO;Lo;0;L;;;;;N;;;;;
+A0C0;YI SYLLABLE MOP;Lo;0;L;;;;;N;;;;;
+A0C1;YI SYLLABLE MEX;Lo;0;L;;;;;N;;;;;
+A0C2;YI SYLLABLE ME;Lo;0;L;;;;;N;;;;;
+A0C3;YI SYLLABLE MUT;Lo;0;L;;;;;N;;;;;
+A0C4;YI SYLLABLE MUX;Lo;0;L;;;;;N;;;;;
+A0C5;YI SYLLABLE MU;Lo;0;L;;;;;N;;;;;
+A0C6;YI SYLLABLE MUP;Lo;0;L;;;;;N;;;;;
+A0C7;YI SYLLABLE MURX;Lo;0;L;;;;;N;;;;;
+A0C8;YI SYLLABLE MUR;Lo;0;L;;;;;N;;;;;
+A0C9;YI SYLLABLE MYT;Lo;0;L;;;;;N;;;;;
+A0CA;YI SYLLABLE MYX;Lo;0;L;;;;;N;;;;;
+A0CB;YI SYLLABLE MY;Lo;0;L;;;;;N;;;;;
+A0CC;YI SYLLABLE MYP;Lo;0;L;;;;;N;;;;;
+A0CD;YI SYLLABLE FIT;Lo;0;L;;;;;N;;;;;
+A0CE;YI SYLLABLE FIX;Lo;0;L;;;;;N;;;;;
+A0CF;YI SYLLABLE FI;Lo;0;L;;;;;N;;;;;
+A0D0;YI SYLLABLE FIP;Lo;0;L;;;;;N;;;;;
+A0D1;YI SYLLABLE FAT;Lo;0;L;;;;;N;;;;;
+A0D2;YI SYLLABLE FAX;Lo;0;L;;;;;N;;;;;
+A0D3;YI SYLLABLE FA;Lo;0;L;;;;;N;;;;;
+A0D4;YI SYLLABLE FAP;Lo;0;L;;;;;N;;;;;
+A0D5;YI SYLLABLE FOX;Lo;0;L;;;;;N;;;;;
+A0D6;YI SYLLABLE FO;Lo;0;L;;;;;N;;;;;
+A0D7;YI SYLLABLE FOP;Lo;0;L;;;;;N;;;;;
+A0D8;YI SYLLABLE FUT;Lo;0;L;;;;;N;;;;;
+A0D9;YI SYLLABLE FUX;Lo;0;L;;;;;N;;;;;
+A0DA;YI SYLLABLE FU;Lo;0;L;;;;;N;;;;;
+A0DB;YI SYLLABLE FUP;Lo;0;L;;;;;N;;;;;
+A0DC;YI SYLLABLE FURX;Lo;0;L;;;;;N;;;;;
+A0DD;YI SYLLABLE FUR;Lo;0;L;;;;;N;;;;;
+A0DE;YI SYLLABLE FYT;Lo;0;L;;;;;N;;;;;
+A0DF;YI SYLLABLE FYX;Lo;0;L;;;;;N;;;;;
+A0E0;YI SYLLABLE FY;Lo;0;L;;;;;N;;;;;
+A0E1;YI SYLLABLE FYP;Lo;0;L;;;;;N;;;;;
+A0E2;YI SYLLABLE VIT;Lo;0;L;;;;;N;;;;;
+A0E3;YI SYLLABLE VIX;Lo;0;L;;;;;N;;;;;
+A0E4;YI SYLLABLE VI;Lo;0;L;;;;;N;;;;;
+A0E5;YI SYLLABLE VIP;Lo;0;L;;;;;N;;;;;
+A0E6;YI SYLLABLE VIET;Lo;0;L;;;;;N;;;;;
+A0E7;YI SYLLABLE VIEX;Lo;0;L;;;;;N;;;;;
+A0E8;YI SYLLABLE VIE;Lo;0;L;;;;;N;;;;;
+A0E9;YI SYLLABLE VIEP;Lo;0;L;;;;;N;;;;;
+A0EA;YI SYLLABLE VAT;Lo;0;L;;;;;N;;;;;
+A0EB;YI SYLLABLE VAX;Lo;0;L;;;;;N;;;;;
+A0EC;YI SYLLABLE VA;Lo;0;L;;;;;N;;;;;
+A0ED;YI SYLLABLE VAP;Lo;0;L;;;;;N;;;;;
+A0EE;YI SYLLABLE VOT;Lo;0;L;;;;;N;;;;;
+A0EF;YI SYLLABLE VOX;Lo;0;L;;;;;N;;;;;
+A0F0;YI SYLLABLE VO;Lo;0;L;;;;;N;;;;;
+A0F1;YI SYLLABLE VOP;Lo;0;L;;;;;N;;;;;
+A0F2;YI SYLLABLE VEX;Lo;0;L;;;;;N;;;;;
+A0F3;YI SYLLABLE VEP;Lo;0;L;;;;;N;;;;;
+A0F4;YI SYLLABLE VUT;Lo;0;L;;;;;N;;;;;
+A0F5;YI SYLLABLE VUX;Lo;0;L;;;;;N;;;;;
+A0F6;YI SYLLABLE VU;Lo;0;L;;;;;N;;;;;
+A0F7;YI SYLLABLE VUP;Lo;0;L;;;;;N;;;;;
+A0F8;YI SYLLABLE VURX;Lo;0;L;;;;;N;;;;;
+A0F9;YI SYLLABLE VUR;Lo;0;L;;;;;N;;;;;
+A0FA;YI SYLLABLE VYT;Lo;0;L;;;;;N;;;;;
+A0FB;YI SYLLABLE VYX;Lo;0;L;;;;;N;;;;;
+A0FC;YI SYLLABLE VY;Lo;0;L;;;;;N;;;;;
+A0FD;YI SYLLABLE VYP;Lo;0;L;;;;;N;;;;;
+A0FE;YI SYLLABLE VYRX;Lo;0;L;;;;;N;;;;;
+A0FF;YI SYLLABLE VYR;Lo;0;L;;;;;N;;;;;
+A100;YI SYLLABLE DIT;Lo;0;L;;;;;N;;;;;
+A101;YI SYLLABLE DIX;Lo;0;L;;;;;N;;;;;
+A102;YI SYLLABLE DI;Lo;0;L;;;;;N;;;;;
+A103;YI SYLLABLE DIP;Lo;0;L;;;;;N;;;;;
+A104;YI SYLLABLE DIEX;Lo;0;L;;;;;N;;;;;
+A105;YI SYLLABLE DIE;Lo;0;L;;;;;N;;;;;
+A106;YI SYLLABLE DIEP;Lo;0;L;;;;;N;;;;;
+A107;YI SYLLABLE DAT;Lo;0;L;;;;;N;;;;;
+A108;YI SYLLABLE DAX;Lo;0;L;;;;;N;;;;;
+A109;YI SYLLABLE DA;Lo;0;L;;;;;N;;;;;
+A10A;YI SYLLABLE DAP;Lo;0;L;;;;;N;;;;;
+A10B;YI SYLLABLE DUOX;Lo;0;L;;;;;N;;;;;
+A10C;YI SYLLABLE DUO;Lo;0;L;;;;;N;;;;;
+A10D;YI SYLLABLE DOT;Lo;0;L;;;;;N;;;;;
+A10E;YI SYLLABLE DOX;Lo;0;L;;;;;N;;;;;
+A10F;YI SYLLABLE DO;Lo;0;L;;;;;N;;;;;
+A110;YI SYLLABLE DOP;Lo;0;L;;;;;N;;;;;
+A111;YI SYLLABLE DEX;Lo;0;L;;;;;N;;;;;
+A112;YI SYLLABLE DE;Lo;0;L;;;;;N;;;;;
+A113;YI SYLLABLE DEP;Lo;0;L;;;;;N;;;;;
+A114;YI SYLLABLE DUT;Lo;0;L;;;;;N;;;;;
+A115;YI SYLLABLE DUX;Lo;0;L;;;;;N;;;;;
+A116;YI SYLLABLE DU;Lo;0;L;;;;;N;;;;;
+A117;YI SYLLABLE DUP;Lo;0;L;;;;;N;;;;;
+A118;YI SYLLABLE DURX;Lo;0;L;;;;;N;;;;;
+A119;YI SYLLABLE DUR;Lo;0;L;;;;;N;;;;;
+A11A;YI SYLLABLE TIT;Lo;0;L;;;;;N;;;;;
+A11B;YI SYLLABLE TIX;Lo;0;L;;;;;N;;;;;
+A11C;YI SYLLABLE TI;Lo;0;L;;;;;N;;;;;
+A11D;YI SYLLABLE TIP;Lo;0;L;;;;;N;;;;;
+A11E;YI SYLLABLE TIEX;Lo;0;L;;;;;N;;;;;
+A11F;YI SYLLABLE TIE;Lo;0;L;;;;;N;;;;;
+A120;YI SYLLABLE TIEP;Lo;0;L;;;;;N;;;;;
+A121;YI SYLLABLE TAT;Lo;0;L;;;;;N;;;;;
+A122;YI SYLLABLE TAX;Lo;0;L;;;;;N;;;;;
+A123;YI SYLLABLE TA;Lo;0;L;;;;;N;;;;;
+A124;YI SYLLABLE TAP;Lo;0;L;;;;;N;;;;;
+A125;YI SYLLABLE TUOT;Lo;0;L;;;;;N;;;;;
+A126;YI SYLLABLE TUOX;Lo;0;L;;;;;N;;;;;
+A127;YI SYLLABLE TUO;Lo;0;L;;;;;N;;;;;
+A128;YI SYLLABLE TUOP;Lo;0;L;;;;;N;;;;;
+A129;YI SYLLABLE TOT;Lo;0;L;;;;;N;;;;;
+A12A;YI SYLLABLE TOX;Lo;0;L;;;;;N;;;;;
+A12B;YI SYLLABLE TO;Lo;0;L;;;;;N;;;;;
+A12C;YI SYLLABLE TOP;Lo;0;L;;;;;N;;;;;
+A12D;YI SYLLABLE TEX;Lo;0;L;;;;;N;;;;;
+A12E;YI SYLLABLE TE;Lo;0;L;;;;;N;;;;;
+A12F;YI SYLLABLE TEP;Lo;0;L;;;;;N;;;;;
+A130;YI SYLLABLE TUT;Lo;0;L;;;;;N;;;;;
+A131;YI SYLLABLE TUX;Lo;0;L;;;;;N;;;;;
+A132;YI SYLLABLE TU;Lo;0;L;;;;;N;;;;;
+A133;YI SYLLABLE TUP;Lo;0;L;;;;;N;;;;;
+A134;YI SYLLABLE TURX;Lo;0;L;;;;;N;;;;;
+A135;YI SYLLABLE TUR;Lo;0;L;;;;;N;;;;;
+A136;YI SYLLABLE DDIT;Lo;0;L;;;;;N;;;;;
+A137;YI SYLLABLE DDIX;Lo;0;L;;;;;N;;;;;
+A138;YI SYLLABLE DDI;Lo;0;L;;;;;N;;;;;
+A139;YI SYLLABLE DDIP;Lo;0;L;;;;;N;;;;;
+A13A;YI SYLLABLE DDIEX;Lo;0;L;;;;;N;;;;;
+A13B;YI SYLLABLE DDIE;Lo;0;L;;;;;N;;;;;
+A13C;YI SYLLABLE DDIEP;Lo;0;L;;;;;N;;;;;
+A13D;YI SYLLABLE DDAT;Lo;0;L;;;;;N;;;;;
+A13E;YI SYLLABLE DDAX;Lo;0;L;;;;;N;;;;;
+A13F;YI SYLLABLE DDA;Lo;0;L;;;;;N;;;;;
+A140;YI SYLLABLE DDAP;Lo;0;L;;;;;N;;;;;
+A141;YI SYLLABLE DDUOX;Lo;0;L;;;;;N;;;;;
+A142;YI SYLLABLE DDUO;Lo;0;L;;;;;N;;;;;
+A143;YI SYLLABLE DDUOP;Lo;0;L;;;;;N;;;;;
+A144;YI SYLLABLE DDOT;Lo;0;L;;;;;N;;;;;
+A145;YI SYLLABLE DDOX;Lo;0;L;;;;;N;;;;;
+A146;YI SYLLABLE DDO;Lo;0;L;;;;;N;;;;;
+A147;YI SYLLABLE DDOP;Lo;0;L;;;;;N;;;;;
+A148;YI SYLLABLE DDEX;Lo;0;L;;;;;N;;;;;
+A149;YI SYLLABLE DDE;Lo;0;L;;;;;N;;;;;
+A14A;YI SYLLABLE DDEP;Lo;0;L;;;;;N;;;;;
+A14B;YI SYLLABLE DDUT;Lo;0;L;;;;;N;;;;;
+A14C;YI SYLLABLE DDUX;Lo;0;L;;;;;N;;;;;
+A14D;YI SYLLABLE DDU;Lo;0;L;;;;;N;;;;;
+A14E;YI SYLLABLE DDUP;Lo;0;L;;;;;N;;;;;
+A14F;YI SYLLABLE DDURX;Lo;0;L;;;;;N;;;;;
+A150;YI SYLLABLE DDUR;Lo;0;L;;;;;N;;;;;
+A151;YI SYLLABLE NDIT;Lo;0;L;;;;;N;;;;;
+A152;YI SYLLABLE NDIX;Lo;0;L;;;;;N;;;;;
+A153;YI SYLLABLE NDI;Lo;0;L;;;;;N;;;;;
+A154;YI SYLLABLE NDIP;Lo;0;L;;;;;N;;;;;
+A155;YI SYLLABLE NDIEX;Lo;0;L;;;;;N;;;;;
+A156;YI SYLLABLE NDIE;Lo;0;L;;;;;N;;;;;
+A157;YI SYLLABLE NDAT;Lo;0;L;;;;;N;;;;;
+A158;YI SYLLABLE NDAX;Lo;0;L;;;;;N;;;;;
+A159;YI SYLLABLE NDA;Lo;0;L;;;;;N;;;;;
+A15A;YI SYLLABLE NDAP;Lo;0;L;;;;;N;;;;;
+A15B;YI SYLLABLE NDOT;Lo;0;L;;;;;N;;;;;
+A15C;YI SYLLABLE NDOX;Lo;0;L;;;;;N;;;;;
+A15D;YI SYLLABLE NDO;Lo;0;L;;;;;N;;;;;
+A15E;YI SYLLABLE NDOP;Lo;0;L;;;;;N;;;;;
+A15F;YI SYLLABLE NDEX;Lo;0;L;;;;;N;;;;;
+A160;YI SYLLABLE NDE;Lo;0;L;;;;;N;;;;;
+A161;YI SYLLABLE NDEP;Lo;0;L;;;;;N;;;;;
+A162;YI SYLLABLE NDUT;Lo;0;L;;;;;N;;;;;
+A163;YI SYLLABLE NDUX;Lo;0;L;;;;;N;;;;;
+A164;YI SYLLABLE NDU;Lo;0;L;;;;;N;;;;;
+A165;YI SYLLABLE NDUP;Lo;0;L;;;;;N;;;;;
+A166;YI SYLLABLE NDURX;Lo;0;L;;;;;N;;;;;
+A167;YI SYLLABLE NDUR;Lo;0;L;;;;;N;;;;;
+A168;YI SYLLABLE HNIT;Lo;0;L;;;;;N;;;;;
+A169;YI SYLLABLE HNIX;Lo;0;L;;;;;N;;;;;
+A16A;YI SYLLABLE HNI;Lo;0;L;;;;;N;;;;;
+A16B;YI SYLLABLE HNIP;Lo;0;L;;;;;N;;;;;
+A16C;YI SYLLABLE HNIET;Lo;0;L;;;;;N;;;;;
+A16D;YI SYLLABLE HNIEX;Lo;0;L;;;;;N;;;;;
+A16E;YI SYLLABLE HNIE;Lo;0;L;;;;;N;;;;;
+A16F;YI SYLLABLE HNIEP;Lo;0;L;;;;;N;;;;;
+A170;YI SYLLABLE HNAT;Lo;0;L;;;;;N;;;;;
+A171;YI SYLLABLE HNAX;Lo;0;L;;;;;N;;;;;
+A172;YI SYLLABLE HNA;Lo;0;L;;;;;N;;;;;
+A173;YI SYLLABLE HNAP;Lo;0;L;;;;;N;;;;;
+A174;YI SYLLABLE HNUOX;Lo;0;L;;;;;N;;;;;
+A175;YI SYLLABLE HNUO;Lo;0;L;;;;;N;;;;;
+A176;YI SYLLABLE HNOT;Lo;0;L;;;;;N;;;;;
+A177;YI SYLLABLE HNOX;Lo;0;L;;;;;N;;;;;
+A178;YI SYLLABLE HNOP;Lo;0;L;;;;;N;;;;;
+A179;YI SYLLABLE HNEX;Lo;0;L;;;;;N;;;;;
+A17A;YI SYLLABLE HNE;Lo;0;L;;;;;N;;;;;
+A17B;YI SYLLABLE HNEP;Lo;0;L;;;;;N;;;;;
+A17C;YI SYLLABLE HNUT;Lo;0;L;;;;;N;;;;;
+A17D;YI SYLLABLE NIT;Lo;0;L;;;;;N;;;;;
+A17E;YI SYLLABLE NIX;Lo;0;L;;;;;N;;;;;
+A17F;YI SYLLABLE NI;Lo;0;L;;;;;N;;;;;
+A180;YI SYLLABLE NIP;Lo;0;L;;;;;N;;;;;
+A181;YI SYLLABLE NIEX;Lo;0;L;;;;;N;;;;;
+A182;YI SYLLABLE NIE;Lo;0;L;;;;;N;;;;;
+A183;YI SYLLABLE NIEP;Lo;0;L;;;;;N;;;;;
+A184;YI SYLLABLE NAX;Lo;0;L;;;;;N;;;;;
+A185;YI SYLLABLE NA;Lo;0;L;;;;;N;;;;;
+A186;YI SYLLABLE NAP;Lo;0;L;;;;;N;;;;;
+A187;YI SYLLABLE NUOX;Lo;0;L;;;;;N;;;;;
+A188;YI SYLLABLE NUO;Lo;0;L;;;;;N;;;;;
+A189;YI SYLLABLE NUOP;Lo;0;L;;;;;N;;;;;
+A18A;YI SYLLABLE NOT;Lo;0;L;;;;;N;;;;;
+A18B;YI SYLLABLE NOX;Lo;0;L;;;;;N;;;;;
+A18C;YI SYLLABLE NO;Lo;0;L;;;;;N;;;;;
+A18D;YI SYLLABLE NOP;Lo;0;L;;;;;N;;;;;
+A18E;YI SYLLABLE NEX;Lo;0;L;;;;;N;;;;;
+A18F;YI SYLLABLE NE;Lo;0;L;;;;;N;;;;;
+A190;YI SYLLABLE NEP;Lo;0;L;;;;;N;;;;;
+A191;YI SYLLABLE NUT;Lo;0;L;;;;;N;;;;;
+A192;YI SYLLABLE NUX;Lo;0;L;;;;;N;;;;;
+A193;YI SYLLABLE NU;Lo;0;L;;;;;N;;;;;
+A194;YI SYLLABLE NUP;Lo;0;L;;;;;N;;;;;
+A195;YI SYLLABLE NURX;Lo;0;L;;;;;N;;;;;
+A196;YI SYLLABLE NUR;Lo;0;L;;;;;N;;;;;
+A197;YI SYLLABLE HLIT;Lo;0;L;;;;;N;;;;;
+A198;YI SYLLABLE HLIX;Lo;0;L;;;;;N;;;;;
+A199;YI SYLLABLE HLI;Lo;0;L;;;;;N;;;;;
+A19A;YI SYLLABLE HLIP;Lo;0;L;;;;;N;;;;;
+A19B;YI SYLLABLE HLIEX;Lo;0;L;;;;;N;;;;;
+A19C;YI SYLLABLE HLIE;Lo;0;L;;;;;N;;;;;
+A19D;YI SYLLABLE HLIEP;Lo;0;L;;;;;N;;;;;
+A19E;YI SYLLABLE HLAT;Lo;0;L;;;;;N;;;;;
+A19F;YI SYLLABLE HLAX;Lo;0;L;;;;;N;;;;;
+A1A0;YI SYLLABLE HLA;Lo;0;L;;;;;N;;;;;
+A1A1;YI SYLLABLE HLAP;Lo;0;L;;;;;N;;;;;
+A1A2;YI SYLLABLE HLUOX;Lo;0;L;;;;;N;;;;;
+A1A3;YI SYLLABLE HLUO;Lo;0;L;;;;;N;;;;;
+A1A4;YI SYLLABLE HLUOP;Lo;0;L;;;;;N;;;;;
+A1A5;YI SYLLABLE HLOX;Lo;0;L;;;;;N;;;;;
+A1A6;YI SYLLABLE HLO;Lo;0;L;;;;;N;;;;;
+A1A7;YI SYLLABLE HLOP;Lo;0;L;;;;;N;;;;;
+A1A8;YI SYLLABLE HLEX;Lo;0;L;;;;;N;;;;;
+A1A9;YI SYLLABLE HLE;Lo;0;L;;;;;N;;;;;
+A1AA;YI SYLLABLE HLEP;Lo;0;L;;;;;N;;;;;
+A1AB;YI SYLLABLE HLUT;Lo;0;L;;;;;N;;;;;
+A1AC;YI SYLLABLE HLUX;Lo;0;L;;;;;N;;;;;
+A1AD;YI SYLLABLE HLU;Lo;0;L;;;;;N;;;;;
+A1AE;YI SYLLABLE HLUP;Lo;0;L;;;;;N;;;;;
+A1AF;YI SYLLABLE HLURX;Lo;0;L;;;;;N;;;;;
+A1B0;YI SYLLABLE HLUR;Lo;0;L;;;;;N;;;;;
+A1B1;YI SYLLABLE HLYT;Lo;0;L;;;;;N;;;;;
+A1B2;YI SYLLABLE HLYX;Lo;0;L;;;;;N;;;;;
+A1B3;YI SYLLABLE HLY;Lo;0;L;;;;;N;;;;;
+A1B4;YI SYLLABLE HLYP;Lo;0;L;;;;;N;;;;;
+A1B5;YI SYLLABLE HLYRX;Lo;0;L;;;;;N;;;;;
+A1B6;YI SYLLABLE HLYR;Lo;0;L;;;;;N;;;;;
+A1B7;YI SYLLABLE LIT;Lo;0;L;;;;;N;;;;;
+A1B8;YI SYLLABLE LIX;Lo;0;L;;;;;N;;;;;
+A1B9;YI SYLLABLE LI;Lo;0;L;;;;;N;;;;;
+A1BA;YI SYLLABLE LIP;Lo;0;L;;;;;N;;;;;
+A1BB;YI SYLLABLE LIET;Lo;0;L;;;;;N;;;;;
+A1BC;YI SYLLABLE LIEX;Lo;0;L;;;;;N;;;;;
+A1BD;YI SYLLABLE LIE;Lo;0;L;;;;;N;;;;;
+A1BE;YI SYLLABLE LIEP;Lo;0;L;;;;;N;;;;;
+A1BF;YI SYLLABLE LAT;Lo;0;L;;;;;N;;;;;
+A1C0;YI SYLLABLE LAX;Lo;0;L;;;;;N;;;;;
+A1C1;YI SYLLABLE LA;Lo;0;L;;;;;N;;;;;
+A1C2;YI SYLLABLE LAP;Lo;0;L;;;;;N;;;;;
+A1C3;YI SYLLABLE LUOT;Lo;0;L;;;;;N;;;;;
+A1C4;YI SYLLABLE LUOX;Lo;0;L;;;;;N;;;;;
+A1C5;YI SYLLABLE LUO;Lo;0;L;;;;;N;;;;;
+A1C6;YI SYLLABLE LUOP;Lo;0;L;;;;;N;;;;;
+A1C7;YI SYLLABLE LOT;Lo;0;L;;;;;N;;;;;
+A1C8;YI SYLLABLE LOX;Lo;0;L;;;;;N;;;;;
+A1C9;YI SYLLABLE LO;Lo;0;L;;;;;N;;;;;
+A1CA;YI SYLLABLE LOP;Lo;0;L;;;;;N;;;;;
+A1CB;YI SYLLABLE LEX;Lo;0;L;;;;;N;;;;;
+A1CC;YI SYLLABLE LE;Lo;0;L;;;;;N;;;;;
+A1CD;YI SYLLABLE LEP;Lo;0;L;;;;;N;;;;;
+A1CE;YI SYLLABLE LUT;Lo;0;L;;;;;N;;;;;
+A1CF;YI SYLLABLE LUX;Lo;0;L;;;;;N;;;;;
+A1D0;YI SYLLABLE LU;Lo;0;L;;;;;N;;;;;
+A1D1;YI SYLLABLE LUP;Lo;0;L;;;;;N;;;;;
+A1D2;YI SYLLABLE LURX;Lo;0;L;;;;;N;;;;;
+A1D3;YI SYLLABLE LUR;Lo;0;L;;;;;N;;;;;
+A1D4;YI SYLLABLE LYT;Lo;0;L;;;;;N;;;;;
+A1D5;YI SYLLABLE LYX;Lo;0;L;;;;;N;;;;;
+A1D6;YI SYLLABLE LY;Lo;0;L;;;;;N;;;;;
+A1D7;YI SYLLABLE LYP;Lo;0;L;;;;;N;;;;;
+A1D8;YI SYLLABLE LYRX;Lo;0;L;;;;;N;;;;;
+A1D9;YI SYLLABLE LYR;Lo;0;L;;;;;N;;;;;
+A1DA;YI SYLLABLE GIT;Lo;0;L;;;;;N;;;;;
+A1DB;YI SYLLABLE GIX;Lo;0;L;;;;;N;;;;;
+A1DC;YI SYLLABLE GI;Lo;0;L;;;;;N;;;;;
+A1DD;YI SYLLABLE GIP;Lo;0;L;;;;;N;;;;;
+A1DE;YI SYLLABLE GIET;Lo;0;L;;;;;N;;;;;
+A1DF;YI SYLLABLE GIEX;Lo;0;L;;;;;N;;;;;
+A1E0;YI SYLLABLE GIE;Lo;0;L;;;;;N;;;;;
+A1E1;YI SYLLABLE GIEP;Lo;0;L;;;;;N;;;;;
+A1E2;YI SYLLABLE GAT;Lo;0;L;;;;;N;;;;;
+A1E3;YI SYLLABLE GAX;Lo;0;L;;;;;N;;;;;
+A1E4;YI SYLLABLE GA;Lo;0;L;;;;;N;;;;;
+A1E5;YI SYLLABLE GAP;Lo;0;L;;;;;N;;;;;
+A1E6;YI SYLLABLE GUOT;Lo;0;L;;;;;N;;;;;
+A1E7;YI SYLLABLE GUOX;Lo;0;L;;;;;N;;;;;
+A1E8;YI SYLLABLE GUO;Lo;0;L;;;;;N;;;;;
+A1E9;YI SYLLABLE GUOP;Lo;0;L;;;;;N;;;;;
+A1EA;YI SYLLABLE GOT;Lo;0;L;;;;;N;;;;;
+A1EB;YI SYLLABLE GOX;Lo;0;L;;;;;N;;;;;
+A1EC;YI SYLLABLE GO;Lo;0;L;;;;;N;;;;;
+A1ED;YI SYLLABLE GOP;Lo;0;L;;;;;N;;;;;
+A1EE;YI SYLLABLE GET;Lo;0;L;;;;;N;;;;;
+A1EF;YI SYLLABLE GEX;Lo;0;L;;;;;N;;;;;
+A1F0;YI SYLLABLE GE;Lo;0;L;;;;;N;;;;;
+A1F1;YI SYLLABLE GEP;Lo;0;L;;;;;N;;;;;
+A1F2;YI SYLLABLE GUT;Lo;0;L;;;;;N;;;;;
+A1F3;YI SYLLABLE GUX;Lo;0;L;;;;;N;;;;;
+A1F4;YI SYLLABLE GU;Lo;0;L;;;;;N;;;;;
+A1F5;YI SYLLABLE GUP;Lo;0;L;;;;;N;;;;;
+A1F6;YI SYLLABLE GURX;Lo;0;L;;;;;N;;;;;
+A1F7;YI SYLLABLE GUR;Lo;0;L;;;;;N;;;;;
+A1F8;YI SYLLABLE KIT;Lo;0;L;;;;;N;;;;;
+A1F9;YI SYLLABLE KIX;Lo;0;L;;;;;N;;;;;
+A1FA;YI SYLLABLE KI;Lo;0;L;;;;;N;;;;;
+A1FB;YI SYLLABLE KIP;Lo;0;L;;;;;N;;;;;
+A1FC;YI SYLLABLE KIEX;Lo;0;L;;;;;N;;;;;
+A1FD;YI SYLLABLE KIE;Lo;0;L;;;;;N;;;;;
+A1FE;YI SYLLABLE KIEP;Lo;0;L;;;;;N;;;;;
+A1FF;YI SYLLABLE KAT;Lo;0;L;;;;;N;;;;;
+A200;YI SYLLABLE KAX;Lo;0;L;;;;;N;;;;;
+A201;YI SYLLABLE KA;Lo;0;L;;;;;N;;;;;
+A202;YI SYLLABLE KAP;Lo;0;L;;;;;N;;;;;
+A203;YI SYLLABLE KUOX;Lo;0;L;;;;;N;;;;;
+A204;YI SYLLABLE KUO;Lo;0;L;;;;;N;;;;;
+A205;YI SYLLABLE KUOP;Lo;0;L;;;;;N;;;;;
+A206;YI SYLLABLE KOT;Lo;0;L;;;;;N;;;;;
+A207;YI SYLLABLE KOX;Lo;0;L;;;;;N;;;;;
+A208;YI SYLLABLE KO;Lo;0;L;;;;;N;;;;;
+A209;YI SYLLABLE KOP;Lo;0;L;;;;;N;;;;;
+A20A;YI SYLLABLE KET;Lo;0;L;;;;;N;;;;;
+A20B;YI SYLLABLE KEX;Lo;0;L;;;;;N;;;;;
+A20C;YI SYLLABLE KE;Lo;0;L;;;;;N;;;;;
+A20D;YI SYLLABLE KEP;Lo;0;L;;;;;N;;;;;
+A20E;YI SYLLABLE KUT;Lo;0;L;;;;;N;;;;;
+A20F;YI SYLLABLE KUX;Lo;0;L;;;;;N;;;;;
+A210;YI SYLLABLE KU;Lo;0;L;;;;;N;;;;;
+A211;YI SYLLABLE KUP;Lo;0;L;;;;;N;;;;;
+A212;YI SYLLABLE KURX;Lo;0;L;;;;;N;;;;;
+A213;YI SYLLABLE KUR;Lo;0;L;;;;;N;;;;;
+A214;YI SYLLABLE GGIT;Lo;0;L;;;;;N;;;;;
+A215;YI SYLLABLE GGIX;Lo;0;L;;;;;N;;;;;
+A216;YI SYLLABLE GGI;Lo;0;L;;;;;N;;;;;
+A217;YI SYLLABLE GGIEX;Lo;0;L;;;;;N;;;;;
+A218;YI SYLLABLE GGIE;Lo;0;L;;;;;N;;;;;
+A219;YI SYLLABLE GGIEP;Lo;0;L;;;;;N;;;;;
+A21A;YI SYLLABLE GGAT;Lo;0;L;;;;;N;;;;;
+A21B;YI SYLLABLE GGAX;Lo;0;L;;;;;N;;;;;
+A21C;YI SYLLABLE GGA;Lo;0;L;;;;;N;;;;;
+A21D;YI SYLLABLE GGAP;Lo;0;L;;;;;N;;;;;
+A21E;YI SYLLABLE GGUOT;Lo;0;L;;;;;N;;;;;
+A21F;YI SYLLABLE GGUOX;Lo;0;L;;;;;N;;;;;
+A220;YI SYLLABLE GGUO;Lo;0;L;;;;;N;;;;;
+A221;YI SYLLABLE GGUOP;Lo;0;L;;;;;N;;;;;
+A222;YI SYLLABLE GGOT;Lo;0;L;;;;;N;;;;;
+A223;YI SYLLABLE GGOX;Lo;0;L;;;;;N;;;;;
+A224;YI SYLLABLE GGO;Lo;0;L;;;;;N;;;;;
+A225;YI SYLLABLE GGOP;Lo;0;L;;;;;N;;;;;
+A226;YI SYLLABLE GGET;Lo;0;L;;;;;N;;;;;
+A227;YI SYLLABLE GGEX;Lo;0;L;;;;;N;;;;;
+A228;YI SYLLABLE GGE;Lo;0;L;;;;;N;;;;;
+A229;YI SYLLABLE GGEP;Lo;0;L;;;;;N;;;;;
+A22A;YI SYLLABLE GGUT;Lo;0;L;;;;;N;;;;;
+A22B;YI SYLLABLE GGUX;Lo;0;L;;;;;N;;;;;
+A22C;YI SYLLABLE GGU;Lo;0;L;;;;;N;;;;;
+A22D;YI SYLLABLE GGUP;Lo;0;L;;;;;N;;;;;
+A22E;YI SYLLABLE GGURX;Lo;0;L;;;;;N;;;;;
+A22F;YI SYLLABLE GGUR;Lo;0;L;;;;;N;;;;;
+A230;YI SYLLABLE MGIEX;Lo;0;L;;;;;N;;;;;
+A231;YI SYLLABLE MGIE;Lo;0;L;;;;;N;;;;;
+A232;YI SYLLABLE MGAT;Lo;0;L;;;;;N;;;;;
+A233;YI SYLLABLE MGAX;Lo;0;L;;;;;N;;;;;
+A234;YI SYLLABLE MGA;Lo;0;L;;;;;N;;;;;
+A235;YI SYLLABLE MGAP;Lo;0;L;;;;;N;;;;;
+A236;YI SYLLABLE MGUOX;Lo;0;L;;;;;N;;;;;
+A237;YI SYLLABLE MGUO;Lo;0;L;;;;;N;;;;;
+A238;YI SYLLABLE MGUOP;Lo;0;L;;;;;N;;;;;
+A239;YI SYLLABLE MGOT;Lo;0;L;;;;;N;;;;;
+A23A;YI SYLLABLE MGOX;Lo;0;L;;;;;N;;;;;
+A23B;YI SYLLABLE MGO;Lo;0;L;;;;;N;;;;;
+A23C;YI SYLLABLE MGOP;Lo;0;L;;;;;N;;;;;
+A23D;YI SYLLABLE MGEX;Lo;0;L;;;;;N;;;;;
+A23E;YI SYLLABLE MGE;Lo;0;L;;;;;N;;;;;
+A23F;YI SYLLABLE MGEP;Lo;0;L;;;;;N;;;;;
+A240;YI SYLLABLE MGUT;Lo;0;L;;;;;N;;;;;
+A241;YI SYLLABLE MGUX;Lo;0;L;;;;;N;;;;;
+A242;YI SYLLABLE MGU;Lo;0;L;;;;;N;;;;;
+A243;YI SYLLABLE MGUP;Lo;0;L;;;;;N;;;;;
+A244;YI SYLLABLE MGURX;Lo;0;L;;;;;N;;;;;
+A245;YI SYLLABLE MGUR;Lo;0;L;;;;;N;;;;;
+A246;YI SYLLABLE HXIT;Lo;0;L;;;;;N;;;;;
+A247;YI SYLLABLE HXIX;Lo;0;L;;;;;N;;;;;
+A248;YI SYLLABLE HXI;Lo;0;L;;;;;N;;;;;
+A249;YI SYLLABLE HXIP;Lo;0;L;;;;;N;;;;;
+A24A;YI SYLLABLE HXIET;Lo;0;L;;;;;N;;;;;
+A24B;YI SYLLABLE HXIEX;Lo;0;L;;;;;N;;;;;
+A24C;YI SYLLABLE HXIE;Lo;0;L;;;;;N;;;;;
+A24D;YI SYLLABLE HXIEP;Lo;0;L;;;;;N;;;;;
+A24E;YI SYLLABLE HXAT;Lo;0;L;;;;;N;;;;;
+A24F;YI SYLLABLE HXAX;Lo;0;L;;;;;N;;;;;
+A250;YI SYLLABLE HXA;Lo;0;L;;;;;N;;;;;
+A251;YI SYLLABLE HXAP;Lo;0;L;;;;;N;;;;;
+A252;YI SYLLABLE HXUOT;Lo;0;L;;;;;N;;;;;
+A253;YI SYLLABLE HXUOX;Lo;0;L;;;;;N;;;;;
+A254;YI SYLLABLE HXUO;Lo;0;L;;;;;N;;;;;
+A255;YI SYLLABLE HXUOP;Lo;0;L;;;;;N;;;;;
+A256;YI SYLLABLE HXOT;Lo;0;L;;;;;N;;;;;
+A257;YI SYLLABLE HXOX;Lo;0;L;;;;;N;;;;;
+A258;YI SYLLABLE HXO;Lo;0;L;;;;;N;;;;;
+A259;YI SYLLABLE HXOP;Lo;0;L;;;;;N;;;;;
+A25A;YI SYLLABLE HXEX;Lo;0;L;;;;;N;;;;;
+A25B;YI SYLLABLE HXE;Lo;0;L;;;;;N;;;;;
+A25C;YI SYLLABLE HXEP;Lo;0;L;;;;;N;;;;;
+A25D;YI SYLLABLE NGIEX;Lo;0;L;;;;;N;;;;;
+A25E;YI SYLLABLE NGIE;Lo;0;L;;;;;N;;;;;
+A25F;YI SYLLABLE NGIEP;Lo;0;L;;;;;N;;;;;
+A260;YI SYLLABLE NGAT;Lo;0;L;;;;;N;;;;;
+A261;YI SYLLABLE NGAX;Lo;0;L;;;;;N;;;;;
+A262;YI SYLLABLE NGA;Lo;0;L;;;;;N;;;;;
+A263;YI SYLLABLE NGAP;Lo;0;L;;;;;N;;;;;
+A264;YI SYLLABLE NGUOT;Lo;0;L;;;;;N;;;;;
+A265;YI SYLLABLE NGUOX;Lo;0;L;;;;;N;;;;;
+A266;YI SYLLABLE NGUO;Lo;0;L;;;;;N;;;;;
+A267;YI SYLLABLE NGOT;Lo;0;L;;;;;N;;;;;
+A268;YI SYLLABLE NGOX;Lo;0;L;;;;;N;;;;;
+A269;YI SYLLABLE NGO;Lo;0;L;;;;;N;;;;;
+A26A;YI SYLLABLE NGOP;Lo;0;L;;;;;N;;;;;
+A26B;YI SYLLABLE NGEX;Lo;0;L;;;;;N;;;;;
+A26C;YI SYLLABLE NGE;Lo;0;L;;;;;N;;;;;
+A26D;YI SYLLABLE NGEP;Lo;0;L;;;;;N;;;;;
+A26E;YI SYLLABLE HIT;Lo;0;L;;;;;N;;;;;
+A26F;YI SYLLABLE HIEX;Lo;0;L;;;;;N;;;;;
+A270;YI SYLLABLE HIE;Lo;0;L;;;;;N;;;;;
+A271;YI SYLLABLE HAT;Lo;0;L;;;;;N;;;;;
+A272;YI SYLLABLE HAX;Lo;0;L;;;;;N;;;;;
+A273;YI SYLLABLE HA;Lo;0;L;;;;;N;;;;;
+A274;YI SYLLABLE HAP;Lo;0;L;;;;;N;;;;;
+A275;YI SYLLABLE HUOT;Lo;0;L;;;;;N;;;;;
+A276;YI SYLLABLE HUOX;Lo;0;L;;;;;N;;;;;
+A277;YI SYLLABLE HUO;Lo;0;L;;;;;N;;;;;
+A278;YI SYLLABLE HUOP;Lo;0;L;;;;;N;;;;;
+A279;YI SYLLABLE HOT;Lo;0;L;;;;;N;;;;;
+A27A;YI SYLLABLE HOX;Lo;0;L;;;;;N;;;;;
+A27B;YI SYLLABLE HO;Lo;0;L;;;;;N;;;;;
+A27C;YI SYLLABLE HOP;Lo;0;L;;;;;N;;;;;
+A27D;YI SYLLABLE HEX;Lo;0;L;;;;;N;;;;;
+A27E;YI SYLLABLE HE;Lo;0;L;;;;;N;;;;;
+A27F;YI SYLLABLE HEP;Lo;0;L;;;;;N;;;;;
+A280;YI SYLLABLE WAT;Lo;0;L;;;;;N;;;;;
+A281;YI SYLLABLE WAX;Lo;0;L;;;;;N;;;;;
+A282;YI SYLLABLE WA;Lo;0;L;;;;;N;;;;;
+A283;YI SYLLABLE WAP;Lo;0;L;;;;;N;;;;;
+A284;YI SYLLABLE WUOX;Lo;0;L;;;;;N;;;;;
+A285;YI SYLLABLE WUO;Lo;0;L;;;;;N;;;;;
+A286;YI SYLLABLE WUOP;Lo;0;L;;;;;N;;;;;
+A287;YI SYLLABLE WOX;Lo;0;L;;;;;N;;;;;
+A288;YI SYLLABLE WO;Lo;0;L;;;;;N;;;;;
+A289;YI SYLLABLE WOP;Lo;0;L;;;;;N;;;;;
+A28A;YI SYLLABLE WEX;Lo;0;L;;;;;N;;;;;
+A28B;YI SYLLABLE WE;Lo;0;L;;;;;N;;;;;
+A28C;YI SYLLABLE WEP;Lo;0;L;;;;;N;;;;;
+A28D;YI SYLLABLE ZIT;Lo;0;L;;;;;N;;;;;
+A28E;YI SYLLABLE ZIX;Lo;0;L;;;;;N;;;;;
+A28F;YI SYLLABLE ZI;Lo;0;L;;;;;N;;;;;
+A290;YI SYLLABLE ZIP;Lo;0;L;;;;;N;;;;;
+A291;YI SYLLABLE ZIEX;Lo;0;L;;;;;N;;;;;
+A292;YI SYLLABLE ZIE;Lo;0;L;;;;;N;;;;;
+A293;YI SYLLABLE ZIEP;Lo;0;L;;;;;N;;;;;
+A294;YI SYLLABLE ZAT;Lo;0;L;;;;;N;;;;;
+A295;YI SYLLABLE ZAX;Lo;0;L;;;;;N;;;;;
+A296;YI SYLLABLE ZA;Lo;0;L;;;;;N;;;;;
+A297;YI SYLLABLE ZAP;Lo;0;L;;;;;N;;;;;
+A298;YI SYLLABLE ZUOX;Lo;0;L;;;;;N;;;;;
+A299;YI SYLLABLE ZUO;Lo;0;L;;;;;N;;;;;
+A29A;YI SYLLABLE ZUOP;Lo;0;L;;;;;N;;;;;
+A29B;YI SYLLABLE ZOT;Lo;0;L;;;;;N;;;;;
+A29C;YI SYLLABLE ZOX;Lo;0;L;;;;;N;;;;;
+A29D;YI SYLLABLE ZO;Lo;0;L;;;;;N;;;;;
+A29E;YI SYLLABLE ZOP;Lo;0;L;;;;;N;;;;;
+A29F;YI SYLLABLE ZEX;Lo;0;L;;;;;N;;;;;
+A2A0;YI SYLLABLE ZE;Lo;0;L;;;;;N;;;;;
+A2A1;YI SYLLABLE ZEP;Lo;0;L;;;;;N;;;;;
+A2A2;YI SYLLABLE ZUT;Lo;0;L;;;;;N;;;;;
+A2A3;YI SYLLABLE ZUX;Lo;0;L;;;;;N;;;;;
+A2A4;YI SYLLABLE ZU;Lo;0;L;;;;;N;;;;;
+A2A5;YI SYLLABLE ZUP;Lo;0;L;;;;;N;;;;;
+A2A6;YI SYLLABLE ZURX;Lo;0;L;;;;;N;;;;;
+A2A7;YI SYLLABLE ZUR;Lo;0;L;;;;;N;;;;;
+A2A8;YI SYLLABLE ZYT;Lo;0;L;;;;;N;;;;;
+A2A9;YI SYLLABLE ZYX;Lo;0;L;;;;;N;;;;;
+A2AA;YI SYLLABLE ZY;Lo;0;L;;;;;N;;;;;
+A2AB;YI SYLLABLE ZYP;Lo;0;L;;;;;N;;;;;
+A2AC;YI SYLLABLE ZYRX;Lo;0;L;;;;;N;;;;;
+A2AD;YI SYLLABLE ZYR;Lo;0;L;;;;;N;;;;;
+A2AE;YI SYLLABLE CIT;Lo;0;L;;;;;N;;;;;
+A2AF;YI SYLLABLE CIX;Lo;0;L;;;;;N;;;;;
+A2B0;YI SYLLABLE CI;Lo;0;L;;;;;N;;;;;
+A2B1;YI SYLLABLE CIP;Lo;0;L;;;;;N;;;;;
+A2B2;YI SYLLABLE CIET;Lo;0;L;;;;;N;;;;;
+A2B3;YI SYLLABLE CIEX;Lo;0;L;;;;;N;;;;;
+A2B4;YI SYLLABLE CIE;Lo;0;L;;;;;N;;;;;
+A2B5;YI SYLLABLE CIEP;Lo;0;L;;;;;N;;;;;
+A2B6;YI SYLLABLE CAT;Lo;0;L;;;;;N;;;;;
+A2B7;YI SYLLABLE CAX;Lo;0;L;;;;;N;;;;;
+A2B8;YI SYLLABLE CA;Lo;0;L;;;;;N;;;;;
+A2B9;YI SYLLABLE CAP;Lo;0;L;;;;;N;;;;;
+A2BA;YI SYLLABLE CUOX;Lo;0;L;;;;;N;;;;;
+A2BB;YI SYLLABLE CUO;Lo;0;L;;;;;N;;;;;
+A2BC;YI SYLLABLE CUOP;Lo;0;L;;;;;N;;;;;
+A2BD;YI SYLLABLE COT;Lo;0;L;;;;;N;;;;;
+A2BE;YI SYLLABLE COX;Lo;0;L;;;;;N;;;;;
+A2BF;YI SYLLABLE CO;Lo;0;L;;;;;N;;;;;
+A2C0;YI SYLLABLE COP;Lo;0;L;;;;;N;;;;;
+A2C1;YI SYLLABLE CEX;Lo;0;L;;;;;N;;;;;
+A2C2;YI SYLLABLE CE;Lo;0;L;;;;;N;;;;;
+A2C3;YI SYLLABLE CEP;Lo;0;L;;;;;N;;;;;
+A2C4;YI SYLLABLE CUT;Lo;0;L;;;;;N;;;;;
+A2C5;YI SYLLABLE CUX;Lo;0;L;;;;;N;;;;;
+A2C6;YI SYLLABLE CU;Lo;0;L;;;;;N;;;;;
+A2C7;YI SYLLABLE CUP;Lo;0;L;;;;;N;;;;;
+A2C8;YI SYLLABLE CURX;Lo;0;L;;;;;N;;;;;
+A2C9;YI SYLLABLE CUR;Lo;0;L;;;;;N;;;;;
+A2CA;YI SYLLABLE CYT;Lo;0;L;;;;;N;;;;;
+A2CB;YI SYLLABLE CYX;Lo;0;L;;;;;N;;;;;
+A2CC;YI SYLLABLE CY;Lo;0;L;;;;;N;;;;;
+A2CD;YI SYLLABLE CYP;Lo;0;L;;;;;N;;;;;
+A2CE;YI SYLLABLE CYRX;Lo;0;L;;;;;N;;;;;
+A2CF;YI SYLLABLE CYR;Lo;0;L;;;;;N;;;;;
+A2D0;YI SYLLABLE ZZIT;Lo;0;L;;;;;N;;;;;
+A2D1;YI SYLLABLE ZZIX;Lo;0;L;;;;;N;;;;;
+A2D2;YI SYLLABLE ZZI;Lo;0;L;;;;;N;;;;;
+A2D3;YI SYLLABLE ZZIP;Lo;0;L;;;;;N;;;;;
+A2D4;YI SYLLABLE ZZIET;Lo;0;L;;;;;N;;;;;
+A2D5;YI SYLLABLE ZZIEX;Lo;0;L;;;;;N;;;;;
+A2D6;YI SYLLABLE ZZIE;Lo;0;L;;;;;N;;;;;
+A2D7;YI SYLLABLE ZZIEP;Lo;0;L;;;;;N;;;;;
+A2D8;YI SYLLABLE ZZAT;Lo;0;L;;;;;N;;;;;
+A2D9;YI SYLLABLE ZZAX;Lo;0;L;;;;;N;;;;;
+A2DA;YI SYLLABLE ZZA;Lo;0;L;;;;;N;;;;;
+A2DB;YI SYLLABLE ZZAP;Lo;0;L;;;;;N;;;;;
+A2DC;YI SYLLABLE ZZOX;Lo;0;L;;;;;N;;;;;
+A2DD;YI SYLLABLE ZZO;Lo;0;L;;;;;N;;;;;
+A2DE;YI SYLLABLE ZZOP;Lo;0;L;;;;;N;;;;;
+A2DF;YI SYLLABLE ZZEX;Lo;0;L;;;;;N;;;;;
+A2E0;YI SYLLABLE ZZE;Lo;0;L;;;;;N;;;;;
+A2E1;YI SYLLABLE ZZEP;Lo;0;L;;;;;N;;;;;
+A2E2;YI SYLLABLE ZZUX;Lo;0;L;;;;;N;;;;;
+A2E3;YI SYLLABLE ZZU;Lo;0;L;;;;;N;;;;;
+A2E4;YI SYLLABLE ZZUP;Lo;0;L;;;;;N;;;;;
+A2E5;YI SYLLABLE ZZURX;Lo;0;L;;;;;N;;;;;
+A2E6;YI SYLLABLE ZZUR;Lo;0;L;;;;;N;;;;;
+A2E7;YI SYLLABLE ZZYT;Lo;0;L;;;;;N;;;;;
+A2E8;YI SYLLABLE ZZYX;Lo;0;L;;;;;N;;;;;
+A2E9;YI SYLLABLE ZZY;Lo;0;L;;;;;N;;;;;
+A2EA;YI SYLLABLE ZZYP;Lo;0;L;;;;;N;;;;;
+A2EB;YI SYLLABLE ZZYRX;Lo;0;L;;;;;N;;;;;
+A2EC;YI SYLLABLE ZZYR;Lo;0;L;;;;;N;;;;;
+A2ED;YI SYLLABLE NZIT;Lo;0;L;;;;;N;;;;;
+A2EE;YI SYLLABLE NZIX;Lo;0;L;;;;;N;;;;;
+A2EF;YI SYLLABLE NZI;Lo;0;L;;;;;N;;;;;
+A2F0;YI SYLLABLE NZIP;Lo;0;L;;;;;N;;;;;
+A2F1;YI SYLLABLE NZIEX;Lo;0;L;;;;;N;;;;;
+A2F2;YI SYLLABLE NZIE;Lo;0;L;;;;;N;;;;;
+A2F3;YI SYLLABLE NZIEP;Lo;0;L;;;;;N;;;;;
+A2F4;YI SYLLABLE NZAT;Lo;0;L;;;;;N;;;;;
+A2F5;YI SYLLABLE NZAX;Lo;0;L;;;;;N;;;;;
+A2F6;YI SYLLABLE NZA;Lo;0;L;;;;;N;;;;;
+A2F7;YI SYLLABLE NZAP;Lo;0;L;;;;;N;;;;;
+A2F8;YI SYLLABLE NZUOX;Lo;0;L;;;;;N;;;;;
+A2F9;YI SYLLABLE NZUO;Lo;0;L;;;;;N;;;;;
+A2FA;YI SYLLABLE NZOX;Lo;0;L;;;;;N;;;;;
+A2FB;YI SYLLABLE NZOP;Lo;0;L;;;;;N;;;;;
+A2FC;YI SYLLABLE NZEX;Lo;0;L;;;;;N;;;;;
+A2FD;YI SYLLABLE NZE;Lo;0;L;;;;;N;;;;;
+A2FE;YI SYLLABLE NZUX;Lo;0;L;;;;;N;;;;;
+A2FF;YI SYLLABLE NZU;Lo;0;L;;;;;N;;;;;
+A300;YI SYLLABLE NZUP;Lo;0;L;;;;;N;;;;;
+A301;YI SYLLABLE NZURX;Lo;0;L;;;;;N;;;;;
+A302;YI SYLLABLE NZUR;Lo;0;L;;;;;N;;;;;
+A303;YI SYLLABLE NZYT;Lo;0;L;;;;;N;;;;;
+A304;YI SYLLABLE NZYX;Lo;0;L;;;;;N;;;;;
+A305;YI SYLLABLE NZY;Lo;0;L;;;;;N;;;;;
+A306;YI SYLLABLE NZYP;Lo;0;L;;;;;N;;;;;
+A307;YI SYLLABLE NZYRX;Lo;0;L;;;;;N;;;;;
+A308;YI SYLLABLE NZYR;Lo;0;L;;;;;N;;;;;
+A309;YI SYLLABLE SIT;Lo;0;L;;;;;N;;;;;
+A30A;YI SYLLABLE SIX;Lo;0;L;;;;;N;;;;;
+A30B;YI SYLLABLE SI;Lo;0;L;;;;;N;;;;;
+A30C;YI SYLLABLE SIP;Lo;0;L;;;;;N;;;;;
+A30D;YI SYLLABLE SIEX;Lo;0;L;;;;;N;;;;;
+A30E;YI SYLLABLE SIE;Lo;0;L;;;;;N;;;;;
+A30F;YI SYLLABLE SIEP;Lo;0;L;;;;;N;;;;;
+A310;YI SYLLABLE SAT;Lo;0;L;;;;;N;;;;;
+A311;YI SYLLABLE SAX;Lo;0;L;;;;;N;;;;;
+A312;YI SYLLABLE SA;Lo;0;L;;;;;N;;;;;
+A313;YI SYLLABLE SAP;Lo;0;L;;;;;N;;;;;
+A314;YI SYLLABLE SUOX;Lo;0;L;;;;;N;;;;;
+A315;YI SYLLABLE SUO;Lo;0;L;;;;;N;;;;;
+A316;YI SYLLABLE SUOP;Lo;0;L;;;;;N;;;;;
+A317;YI SYLLABLE SOT;Lo;0;L;;;;;N;;;;;
+A318;YI SYLLABLE SOX;Lo;0;L;;;;;N;;;;;
+A319;YI SYLLABLE SO;Lo;0;L;;;;;N;;;;;
+A31A;YI SYLLABLE SOP;Lo;0;L;;;;;N;;;;;
+A31B;YI SYLLABLE SEX;Lo;0;L;;;;;N;;;;;
+A31C;YI SYLLABLE SE;Lo;0;L;;;;;N;;;;;
+A31D;YI SYLLABLE SEP;Lo;0;L;;;;;N;;;;;
+A31E;YI SYLLABLE SUT;Lo;0;L;;;;;N;;;;;
+A31F;YI SYLLABLE SUX;Lo;0;L;;;;;N;;;;;
+A320;YI SYLLABLE SU;Lo;0;L;;;;;N;;;;;
+A321;YI SYLLABLE SUP;Lo;0;L;;;;;N;;;;;
+A322;YI SYLLABLE SURX;Lo;0;L;;;;;N;;;;;
+A323;YI SYLLABLE SUR;Lo;0;L;;;;;N;;;;;
+A324;YI SYLLABLE SYT;Lo;0;L;;;;;N;;;;;
+A325;YI SYLLABLE SYX;Lo;0;L;;;;;N;;;;;
+A326;YI SYLLABLE SY;Lo;0;L;;;;;N;;;;;
+A327;YI SYLLABLE SYP;Lo;0;L;;;;;N;;;;;
+A328;YI SYLLABLE SYRX;Lo;0;L;;;;;N;;;;;
+A329;YI SYLLABLE SYR;Lo;0;L;;;;;N;;;;;
+A32A;YI SYLLABLE SSIT;Lo;0;L;;;;;N;;;;;
+A32B;YI SYLLABLE SSIX;Lo;0;L;;;;;N;;;;;
+A32C;YI SYLLABLE SSI;Lo;0;L;;;;;N;;;;;
+A32D;YI SYLLABLE SSIP;Lo;0;L;;;;;N;;;;;
+A32E;YI SYLLABLE SSIEX;Lo;0;L;;;;;N;;;;;
+A32F;YI SYLLABLE SSIE;Lo;0;L;;;;;N;;;;;
+A330;YI SYLLABLE SSIEP;Lo;0;L;;;;;N;;;;;
+A331;YI SYLLABLE SSAT;Lo;0;L;;;;;N;;;;;
+A332;YI SYLLABLE SSAX;Lo;0;L;;;;;N;;;;;
+A333;YI SYLLABLE SSA;Lo;0;L;;;;;N;;;;;
+A334;YI SYLLABLE SSAP;Lo;0;L;;;;;N;;;;;
+A335;YI SYLLABLE SSOT;Lo;0;L;;;;;N;;;;;
+A336;YI SYLLABLE SSOX;Lo;0;L;;;;;N;;;;;
+A337;YI SYLLABLE SSO;Lo;0;L;;;;;N;;;;;
+A338;YI SYLLABLE SSOP;Lo;0;L;;;;;N;;;;;
+A339;YI SYLLABLE SSEX;Lo;0;L;;;;;N;;;;;
+A33A;YI SYLLABLE SSE;Lo;0;L;;;;;N;;;;;
+A33B;YI SYLLABLE SSEP;Lo;0;L;;;;;N;;;;;
+A33C;YI SYLLABLE SSUT;Lo;0;L;;;;;N;;;;;
+A33D;YI SYLLABLE SSUX;Lo;0;L;;;;;N;;;;;
+A33E;YI SYLLABLE SSU;Lo;0;L;;;;;N;;;;;
+A33F;YI SYLLABLE SSUP;Lo;0;L;;;;;N;;;;;
+A340;YI SYLLABLE SSYT;Lo;0;L;;;;;N;;;;;
+A341;YI SYLLABLE SSYX;Lo;0;L;;;;;N;;;;;
+A342;YI SYLLABLE SSY;Lo;0;L;;;;;N;;;;;
+A343;YI SYLLABLE SSYP;Lo;0;L;;;;;N;;;;;
+A344;YI SYLLABLE SSYRX;Lo;0;L;;;;;N;;;;;
+A345;YI SYLLABLE SSYR;Lo;0;L;;;;;N;;;;;
+A346;YI SYLLABLE ZHAT;Lo;0;L;;;;;N;;;;;
+A347;YI SYLLABLE ZHAX;Lo;0;L;;;;;N;;;;;
+A348;YI SYLLABLE ZHA;Lo;0;L;;;;;N;;;;;
+A349;YI SYLLABLE ZHAP;Lo;0;L;;;;;N;;;;;
+A34A;YI SYLLABLE ZHUOX;Lo;0;L;;;;;N;;;;;
+A34B;YI SYLLABLE ZHUO;Lo;0;L;;;;;N;;;;;
+A34C;YI SYLLABLE ZHUOP;Lo;0;L;;;;;N;;;;;
+A34D;YI SYLLABLE ZHOT;Lo;0;L;;;;;N;;;;;
+A34E;YI SYLLABLE ZHOX;Lo;0;L;;;;;N;;;;;
+A34F;YI SYLLABLE ZHO;Lo;0;L;;;;;N;;;;;
+A350;YI SYLLABLE ZHOP;Lo;0;L;;;;;N;;;;;
+A351;YI SYLLABLE ZHET;Lo;0;L;;;;;N;;;;;
+A352;YI SYLLABLE ZHEX;Lo;0;L;;;;;N;;;;;
+A353;YI SYLLABLE ZHE;Lo;0;L;;;;;N;;;;;
+A354;YI SYLLABLE ZHEP;Lo;0;L;;;;;N;;;;;
+A355;YI SYLLABLE ZHUT;Lo;0;L;;;;;N;;;;;
+A356;YI SYLLABLE ZHUX;Lo;0;L;;;;;N;;;;;
+A357;YI SYLLABLE ZHU;Lo;0;L;;;;;N;;;;;
+A358;YI SYLLABLE ZHUP;Lo;0;L;;;;;N;;;;;
+A359;YI SYLLABLE ZHURX;Lo;0;L;;;;;N;;;;;
+A35A;YI SYLLABLE ZHUR;Lo;0;L;;;;;N;;;;;
+A35B;YI SYLLABLE ZHYT;Lo;0;L;;;;;N;;;;;
+A35C;YI SYLLABLE ZHYX;Lo;0;L;;;;;N;;;;;
+A35D;YI SYLLABLE ZHY;Lo;0;L;;;;;N;;;;;
+A35E;YI SYLLABLE ZHYP;Lo;0;L;;;;;N;;;;;
+A35F;YI SYLLABLE ZHYRX;Lo;0;L;;;;;N;;;;;
+A360;YI SYLLABLE ZHYR;Lo;0;L;;;;;N;;;;;
+A361;YI SYLLABLE CHAT;Lo;0;L;;;;;N;;;;;
+A362;YI SYLLABLE CHAX;Lo;0;L;;;;;N;;;;;
+A363;YI SYLLABLE CHA;Lo;0;L;;;;;N;;;;;
+A364;YI SYLLABLE CHAP;Lo;0;L;;;;;N;;;;;
+A365;YI SYLLABLE CHUOT;Lo;0;L;;;;;N;;;;;
+A366;YI SYLLABLE CHUOX;Lo;0;L;;;;;N;;;;;
+A367;YI SYLLABLE CHUO;Lo;0;L;;;;;N;;;;;
+A368;YI SYLLABLE CHUOP;Lo;0;L;;;;;N;;;;;
+A369;YI SYLLABLE CHOT;Lo;0;L;;;;;N;;;;;
+A36A;YI SYLLABLE CHOX;Lo;0;L;;;;;N;;;;;
+A36B;YI SYLLABLE CHO;Lo;0;L;;;;;N;;;;;
+A36C;YI SYLLABLE CHOP;Lo;0;L;;;;;N;;;;;
+A36D;YI SYLLABLE CHET;Lo;0;L;;;;;N;;;;;
+A36E;YI SYLLABLE CHEX;Lo;0;L;;;;;N;;;;;
+A36F;YI SYLLABLE CHE;Lo;0;L;;;;;N;;;;;
+A370;YI SYLLABLE CHEP;Lo;0;L;;;;;N;;;;;
+A371;YI SYLLABLE CHUX;Lo;0;L;;;;;N;;;;;
+A372;YI SYLLABLE CHU;Lo;0;L;;;;;N;;;;;
+A373;YI SYLLABLE CHUP;Lo;0;L;;;;;N;;;;;
+A374;YI SYLLABLE CHURX;Lo;0;L;;;;;N;;;;;
+A375;YI SYLLABLE CHUR;Lo;0;L;;;;;N;;;;;
+A376;YI SYLLABLE CHYT;Lo;0;L;;;;;N;;;;;
+A377;YI SYLLABLE CHYX;Lo;0;L;;;;;N;;;;;
+A378;YI SYLLABLE CHY;Lo;0;L;;;;;N;;;;;
+A379;YI SYLLABLE CHYP;Lo;0;L;;;;;N;;;;;
+A37A;YI SYLLABLE CHYRX;Lo;0;L;;;;;N;;;;;
+A37B;YI SYLLABLE CHYR;Lo;0;L;;;;;N;;;;;
+A37C;YI SYLLABLE RRAX;Lo;0;L;;;;;N;;;;;
+A37D;YI SYLLABLE RRA;Lo;0;L;;;;;N;;;;;
+A37E;YI SYLLABLE RRUOX;Lo;0;L;;;;;N;;;;;
+A37F;YI SYLLABLE RRUO;Lo;0;L;;;;;N;;;;;
+A380;YI SYLLABLE RROT;Lo;0;L;;;;;N;;;;;
+A381;YI SYLLABLE RROX;Lo;0;L;;;;;N;;;;;
+A382;YI SYLLABLE RRO;Lo;0;L;;;;;N;;;;;
+A383;YI SYLLABLE RROP;Lo;0;L;;;;;N;;;;;
+A384;YI SYLLABLE RRET;Lo;0;L;;;;;N;;;;;
+A385;YI SYLLABLE RREX;Lo;0;L;;;;;N;;;;;
+A386;YI SYLLABLE RRE;Lo;0;L;;;;;N;;;;;
+A387;YI SYLLABLE RREP;Lo;0;L;;;;;N;;;;;
+A388;YI SYLLABLE RRUT;Lo;0;L;;;;;N;;;;;
+A389;YI SYLLABLE RRUX;Lo;0;L;;;;;N;;;;;
+A38A;YI SYLLABLE RRU;Lo;0;L;;;;;N;;;;;
+A38B;YI SYLLABLE RRUP;Lo;0;L;;;;;N;;;;;
+A38C;YI SYLLABLE RRURX;Lo;0;L;;;;;N;;;;;
+A38D;YI SYLLABLE RRUR;Lo;0;L;;;;;N;;;;;
+A38E;YI SYLLABLE RRYT;Lo;0;L;;;;;N;;;;;
+A38F;YI SYLLABLE RRYX;Lo;0;L;;;;;N;;;;;
+A390;YI SYLLABLE RRY;Lo;0;L;;;;;N;;;;;
+A391;YI SYLLABLE RRYP;Lo;0;L;;;;;N;;;;;
+A392;YI SYLLABLE RRYRX;Lo;0;L;;;;;N;;;;;
+A393;YI SYLLABLE RRYR;Lo;0;L;;;;;N;;;;;
+A394;YI SYLLABLE NRAT;Lo;0;L;;;;;N;;;;;
+A395;YI SYLLABLE NRAX;Lo;0;L;;;;;N;;;;;
+A396;YI SYLLABLE NRA;Lo;0;L;;;;;N;;;;;
+A397;YI SYLLABLE NRAP;Lo;0;L;;;;;N;;;;;
+A398;YI SYLLABLE NROX;Lo;0;L;;;;;N;;;;;
+A399;YI SYLLABLE NRO;Lo;0;L;;;;;N;;;;;
+A39A;YI SYLLABLE NROP;Lo;0;L;;;;;N;;;;;
+A39B;YI SYLLABLE NRET;Lo;0;L;;;;;N;;;;;
+A39C;YI SYLLABLE NREX;Lo;0;L;;;;;N;;;;;
+A39D;YI SYLLABLE NRE;Lo;0;L;;;;;N;;;;;
+A39E;YI SYLLABLE NREP;Lo;0;L;;;;;N;;;;;
+A39F;YI SYLLABLE NRUT;Lo;0;L;;;;;N;;;;;
+A3A0;YI SYLLABLE NRUX;Lo;0;L;;;;;N;;;;;
+A3A1;YI SYLLABLE NRU;Lo;0;L;;;;;N;;;;;
+A3A2;YI SYLLABLE NRUP;Lo;0;L;;;;;N;;;;;
+A3A3;YI SYLLABLE NRURX;Lo;0;L;;;;;N;;;;;
+A3A4;YI SYLLABLE NRUR;Lo;0;L;;;;;N;;;;;
+A3A5;YI SYLLABLE NRYT;Lo;0;L;;;;;N;;;;;
+A3A6;YI SYLLABLE NRYX;Lo;0;L;;;;;N;;;;;
+A3A7;YI SYLLABLE NRY;Lo;0;L;;;;;N;;;;;
+A3A8;YI SYLLABLE NRYP;Lo;0;L;;;;;N;;;;;
+A3A9;YI SYLLABLE NRYRX;Lo;0;L;;;;;N;;;;;
+A3AA;YI SYLLABLE NRYR;Lo;0;L;;;;;N;;;;;
+A3AB;YI SYLLABLE SHAT;Lo;0;L;;;;;N;;;;;
+A3AC;YI SYLLABLE SHAX;Lo;0;L;;;;;N;;;;;
+A3AD;YI SYLLABLE SHA;Lo;0;L;;;;;N;;;;;
+A3AE;YI SYLLABLE SHAP;Lo;0;L;;;;;N;;;;;
+A3AF;YI SYLLABLE SHUOX;Lo;0;L;;;;;N;;;;;
+A3B0;YI SYLLABLE SHUO;Lo;0;L;;;;;N;;;;;
+A3B1;YI SYLLABLE SHUOP;Lo;0;L;;;;;N;;;;;
+A3B2;YI SYLLABLE SHOT;Lo;0;L;;;;;N;;;;;
+A3B3;YI SYLLABLE SHOX;Lo;0;L;;;;;N;;;;;
+A3B4;YI SYLLABLE SHO;Lo;0;L;;;;;N;;;;;
+A3B5;YI SYLLABLE SHOP;Lo;0;L;;;;;N;;;;;
+A3B6;YI SYLLABLE SHET;Lo;0;L;;;;;N;;;;;
+A3B7;YI SYLLABLE SHEX;Lo;0;L;;;;;N;;;;;
+A3B8;YI SYLLABLE SHE;Lo;0;L;;;;;N;;;;;
+A3B9;YI SYLLABLE SHEP;Lo;0;L;;;;;N;;;;;
+A3BA;YI SYLLABLE SHUT;Lo;0;L;;;;;N;;;;;
+A3BB;YI SYLLABLE SHUX;Lo;0;L;;;;;N;;;;;
+A3BC;YI SYLLABLE SHU;Lo;0;L;;;;;N;;;;;
+A3BD;YI SYLLABLE SHUP;Lo;0;L;;;;;N;;;;;
+A3BE;YI SYLLABLE SHURX;Lo;0;L;;;;;N;;;;;
+A3BF;YI SYLLABLE SHUR;Lo;0;L;;;;;N;;;;;
+A3C0;YI SYLLABLE SHYT;Lo;0;L;;;;;N;;;;;
+A3C1;YI SYLLABLE SHYX;Lo;0;L;;;;;N;;;;;
+A3C2;YI SYLLABLE SHY;Lo;0;L;;;;;N;;;;;
+A3C3;YI SYLLABLE SHYP;Lo;0;L;;;;;N;;;;;
+A3C4;YI SYLLABLE SHYRX;Lo;0;L;;;;;N;;;;;
+A3C5;YI SYLLABLE SHYR;Lo;0;L;;;;;N;;;;;
+A3C6;YI SYLLABLE RAT;Lo;0;L;;;;;N;;;;;
+A3C7;YI SYLLABLE RAX;Lo;0;L;;;;;N;;;;;
+A3C8;YI SYLLABLE RA;Lo;0;L;;;;;N;;;;;
+A3C9;YI SYLLABLE RAP;Lo;0;L;;;;;N;;;;;
+A3CA;YI SYLLABLE RUOX;Lo;0;L;;;;;N;;;;;
+A3CB;YI SYLLABLE RUO;Lo;0;L;;;;;N;;;;;
+A3CC;YI SYLLABLE RUOP;Lo;0;L;;;;;N;;;;;
+A3CD;YI SYLLABLE ROT;Lo;0;L;;;;;N;;;;;
+A3CE;YI SYLLABLE ROX;Lo;0;L;;;;;N;;;;;
+A3CF;YI SYLLABLE RO;Lo;0;L;;;;;N;;;;;
+A3D0;YI SYLLABLE ROP;Lo;0;L;;;;;N;;;;;
+A3D1;YI SYLLABLE REX;Lo;0;L;;;;;N;;;;;
+A3D2;YI SYLLABLE RE;Lo;0;L;;;;;N;;;;;
+A3D3;YI SYLLABLE REP;Lo;0;L;;;;;N;;;;;
+A3D4;YI SYLLABLE RUT;Lo;0;L;;;;;N;;;;;
+A3D5;YI SYLLABLE RUX;Lo;0;L;;;;;N;;;;;
+A3D6;YI SYLLABLE RU;Lo;0;L;;;;;N;;;;;
+A3D7;YI SYLLABLE RUP;Lo;0;L;;;;;N;;;;;
+A3D8;YI SYLLABLE RURX;Lo;0;L;;;;;N;;;;;
+A3D9;YI SYLLABLE RUR;Lo;0;L;;;;;N;;;;;
+A3DA;YI SYLLABLE RYT;Lo;0;L;;;;;N;;;;;
+A3DB;YI SYLLABLE RYX;Lo;0;L;;;;;N;;;;;
+A3DC;YI SYLLABLE RY;Lo;0;L;;;;;N;;;;;
+A3DD;YI SYLLABLE RYP;Lo;0;L;;;;;N;;;;;
+A3DE;YI SYLLABLE RYRX;Lo;0;L;;;;;N;;;;;
+A3DF;YI SYLLABLE RYR;Lo;0;L;;;;;N;;;;;
+A3E0;YI SYLLABLE JIT;Lo;0;L;;;;;N;;;;;
+A3E1;YI SYLLABLE JIX;Lo;0;L;;;;;N;;;;;
+A3E2;YI SYLLABLE JI;Lo;0;L;;;;;N;;;;;
+A3E3;YI SYLLABLE JIP;Lo;0;L;;;;;N;;;;;
+A3E4;YI SYLLABLE JIET;Lo;0;L;;;;;N;;;;;
+A3E5;YI SYLLABLE JIEX;Lo;0;L;;;;;N;;;;;
+A3E6;YI SYLLABLE JIE;Lo;0;L;;;;;N;;;;;
+A3E7;YI SYLLABLE JIEP;Lo;0;L;;;;;N;;;;;
+A3E8;YI SYLLABLE JUOT;Lo;0;L;;;;;N;;;;;
+A3E9;YI SYLLABLE JUOX;Lo;0;L;;;;;N;;;;;
+A3EA;YI SYLLABLE JUO;Lo;0;L;;;;;N;;;;;
+A3EB;YI SYLLABLE JUOP;Lo;0;L;;;;;N;;;;;
+A3EC;YI SYLLABLE JOT;Lo;0;L;;;;;N;;;;;
+A3ED;YI SYLLABLE JOX;Lo;0;L;;;;;N;;;;;
+A3EE;YI SYLLABLE JO;Lo;0;L;;;;;N;;;;;
+A3EF;YI SYLLABLE JOP;Lo;0;L;;;;;N;;;;;
+A3F0;YI SYLLABLE JUT;Lo;0;L;;;;;N;;;;;
+A3F1;YI SYLLABLE JUX;Lo;0;L;;;;;N;;;;;
+A3F2;YI SYLLABLE JU;Lo;0;L;;;;;N;;;;;
+A3F3;YI SYLLABLE JUP;Lo;0;L;;;;;N;;;;;
+A3F4;YI SYLLABLE JURX;Lo;0;L;;;;;N;;;;;
+A3F5;YI SYLLABLE JUR;Lo;0;L;;;;;N;;;;;
+A3F6;YI SYLLABLE JYT;Lo;0;L;;;;;N;;;;;
+A3F7;YI SYLLABLE JYX;Lo;0;L;;;;;N;;;;;
+A3F8;YI SYLLABLE JY;Lo;0;L;;;;;N;;;;;
+A3F9;YI SYLLABLE JYP;Lo;0;L;;;;;N;;;;;
+A3FA;YI SYLLABLE JYRX;Lo;0;L;;;;;N;;;;;
+A3FB;YI SYLLABLE JYR;Lo;0;L;;;;;N;;;;;
+A3FC;YI SYLLABLE QIT;Lo;0;L;;;;;N;;;;;
+A3FD;YI SYLLABLE QIX;Lo;0;L;;;;;N;;;;;
+A3FE;YI SYLLABLE QI;Lo;0;L;;;;;N;;;;;
+A3FF;YI SYLLABLE QIP;Lo;0;L;;;;;N;;;;;
+A400;YI SYLLABLE QIET;Lo;0;L;;;;;N;;;;;
+A401;YI SYLLABLE QIEX;Lo;0;L;;;;;N;;;;;
+A402;YI SYLLABLE QIE;Lo;0;L;;;;;N;;;;;
+A403;YI SYLLABLE QIEP;Lo;0;L;;;;;N;;;;;
+A404;YI SYLLABLE QUOT;Lo;0;L;;;;;N;;;;;
+A405;YI SYLLABLE QUOX;Lo;0;L;;;;;N;;;;;
+A406;YI SYLLABLE QUO;Lo;0;L;;;;;N;;;;;
+A407;YI SYLLABLE QUOP;Lo;0;L;;;;;N;;;;;
+A408;YI SYLLABLE QOT;Lo;0;L;;;;;N;;;;;
+A409;YI SYLLABLE QOX;Lo;0;L;;;;;N;;;;;
+A40A;YI SYLLABLE QO;Lo;0;L;;;;;N;;;;;
+A40B;YI SYLLABLE QOP;Lo;0;L;;;;;N;;;;;
+A40C;YI SYLLABLE QUT;Lo;0;L;;;;;N;;;;;
+A40D;YI SYLLABLE QUX;Lo;0;L;;;;;N;;;;;
+A40E;YI SYLLABLE QU;Lo;0;L;;;;;N;;;;;
+A40F;YI SYLLABLE QUP;Lo;0;L;;;;;N;;;;;
+A410;YI SYLLABLE QURX;Lo;0;L;;;;;N;;;;;
+A411;YI SYLLABLE QUR;Lo;0;L;;;;;N;;;;;
+A412;YI SYLLABLE QYT;Lo;0;L;;;;;N;;;;;
+A413;YI SYLLABLE QYX;Lo;0;L;;;;;N;;;;;
+A414;YI SYLLABLE QY;Lo;0;L;;;;;N;;;;;
+A415;YI SYLLABLE QYP;Lo;0;L;;;;;N;;;;;
+A416;YI SYLLABLE QYRX;Lo;0;L;;;;;N;;;;;
+A417;YI SYLLABLE QYR;Lo;0;L;;;;;N;;;;;
+A418;YI SYLLABLE JJIT;Lo;0;L;;;;;N;;;;;
+A419;YI SYLLABLE JJIX;Lo;0;L;;;;;N;;;;;
+A41A;YI SYLLABLE JJI;Lo;0;L;;;;;N;;;;;
+A41B;YI SYLLABLE JJIP;Lo;0;L;;;;;N;;;;;
+A41C;YI SYLLABLE JJIET;Lo;0;L;;;;;N;;;;;
+A41D;YI SYLLABLE JJIEX;Lo;0;L;;;;;N;;;;;
+A41E;YI SYLLABLE JJIE;Lo;0;L;;;;;N;;;;;
+A41F;YI SYLLABLE JJIEP;Lo;0;L;;;;;N;;;;;
+A420;YI SYLLABLE JJUOX;Lo;0;L;;;;;N;;;;;
+A421;YI SYLLABLE JJUO;Lo;0;L;;;;;N;;;;;
+A422;YI SYLLABLE JJUOP;Lo;0;L;;;;;N;;;;;
+A423;YI SYLLABLE JJOT;Lo;0;L;;;;;N;;;;;
+A424;YI SYLLABLE JJOX;Lo;0;L;;;;;N;;;;;
+A425;YI SYLLABLE JJO;Lo;0;L;;;;;N;;;;;
+A426;YI SYLLABLE JJOP;Lo;0;L;;;;;N;;;;;
+A427;YI SYLLABLE JJUT;Lo;0;L;;;;;N;;;;;
+A428;YI SYLLABLE JJUX;Lo;0;L;;;;;N;;;;;
+A429;YI SYLLABLE JJU;Lo;0;L;;;;;N;;;;;
+A42A;YI SYLLABLE JJUP;Lo;0;L;;;;;N;;;;;
+A42B;YI SYLLABLE JJURX;Lo;0;L;;;;;N;;;;;
+A42C;YI SYLLABLE JJUR;Lo;0;L;;;;;N;;;;;
+A42D;YI SYLLABLE JJYT;Lo;0;L;;;;;N;;;;;
+A42E;YI SYLLABLE JJYX;Lo;0;L;;;;;N;;;;;
+A42F;YI SYLLABLE JJY;Lo;0;L;;;;;N;;;;;
+A430;YI SYLLABLE JJYP;Lo;0;L;;;;;N;;;;;
+A431;YI SYLLABLE NJIT;Lo;0;L;;;;;N;;;;;
+A432;YI SYLLABLE NJIX;Lo;0;L;;;;;N;;;;;
+A433;YI SYLLABLE NJI;Lo;0;L;;;;;N;;;;;
+A434;YI SYLLABLE NJIP;Lo;0;L;;;;;N;;;;;
+A435;YI SYLLABLE NJIET;Lo;0;L;;;;;N;;;;;
+A436;YI SYLLABLE NJIEX;Lo;0;L;;;;;N;;;;;
+A437;YI SYLLABLE NJIE;Lo;0;L;;;;;N;;;;;
+A438;YI SYLLABLE NJIEP;Lo;0;L;;;;;N;;;;;
+A439;YI SYLLABLE NJUOX;Lo;0;L;;;;;N;;;;;
+A43A;YI SYLLABLE NJUO;Lo;0;L;;;;;N;;;;;
+A43B;YI SYLLABLE NJOT;Lo;0;L;;;;;N;;;;;
+A43C;YI SYLLABLE NJOX;Lo;0;L;;;;;N;;;;;
+A43D;YI SYLLABLE NJO;Lo;0;L;;;;;N;;;;;
+A43E;YI SYLLABLE NJOP;Lo;0;L;;;;;N;;;;;
+A43F;YI SYLLABLE NJUX;Lo;0;L;;;;;N;;;;;
+A440;YI SYLLABLE NJU;Lo;0;L;;;;;N;;;;;
+A441;YI SYLLABLE NJUP;Lo;0;L;;;;;N;;;;;
+A442;YI SYLLABLE NJURX;Lo;0;L;;;;;N;;;;;
+A443;YI SYLLABLE NJUR;Lo;0;L;;;;;N;;;;;
+A444;YI SYLLABLE NJYT;Lo;0;L;;;;;N;;;;;
+A445;YI SYLLABLE NJYX;Lo;0;L;;;;;N;;;;;
+A446;YI SYLLABLE NJY;Lo;0;L;;;;;N;;;;;
+A447;YI SYLLABLE NJYP;Lo;0;L;;;;;N;;;;;
+A448;YI SYLLABLE NJYRX;Lo;0;L;;;;;N;;;;;
+A449;YI SYLLABLE NJYR;Lo;0;L;;;;;N;;;;;
+A44A;YI SYLLABLE NYIT;Lo;0;L;;;;;N;;;;;
+A44B;YI SYLLABLE NYIX;Lo;0;L;;;;;N;;;;;
+A44C;YI SYLLABLE NYI;Lo;0;L;;;;;N;;;;;
+A44D;YI SYLLABLE NYIP;Lo;0;L;;;;;N;;;;;
+A44E;YI SYLLABLE NYIET;Lo;0;L;;;;;N;;;;;
+A44F;YI SYLLABLE NYIEX;Lo;0;L;;;;;N;;;;;
+A450;YI SYLLABLE NYIE;Lo;0;L;;;;;N;;;;;
+A451;YI SYLLABLE NYIEP;Lo;0;L;;;;;N;;;;;
+A452;YI SYLLABLE NYUOX;Lo;0;L;;;;;N;;;;;
+A453;YI SYLLABLE NYUO;Lo;0;L;;;;;N;;;;;
+A454;YI SYLLABLE NYUOP;Lo;0;L;;;;;N;;;;;
+A455;YI SYLLABLE NYOT;Lo;0;L;;;;;N;;;;;
+A456;YI SYLLABLE NYOX;Lo;0;L;;;;;N;;;;;
+A457;YI SYLLABLE NYO;Lo;0;L;;;;;N;;;;;
+A458;YI SYLLABLE NYOP;Lo;0;L;;;;;N;;;;;
+A459;YI SYLLABLE NYUT;Lo;0;L;;;;;N;;;;;
+A45A;YI SYLLABLE NYUX;Lo;0;L;;;;;N;;;;;
+A45B;YI SYLLABLE NYU;Lo;0;L;;;;;N;;;;;
+A45C;YI SYLLABLE NYUP;Lo;0;L;;;;;N;;;;;
+A45D;YI SYLLABLE XIT;Lo;0;L;;;;;N;;;;;
+A45E;YI SYLLABLE XIX;Lo;0;L;;;;;N;;;;;
+A45F;YI SYLLABLE XI;Lo;0;L;;;;;N;;;;;
+A460;YI SYLLABLE XIP;Lo;0;L;;;;;N;;;;;
+A461;YI SYLLABLE XIET;Lo;0;L;;;;;N;;;;;
+A462;YI SYLLABLE XIEX;Lo;0;L;;;;;N;;;;;
+A463;YI SYLLABLE XIE;Lo;0;L;;;;;N;;;;;
+A464;YI SYLLABLE XIEP;Lo;0;L;;;;;N;;;;;
+A465;YI SYLLABLE XUOX;Lo;0;L;;;;;N;;;;;
+A466;YI SYLLABLE XUO;Lo;0;L;;;;;N;;;;;
+A467;YI SYLLABLE XOT;Lo;0;L;;;;;N;;;;;
+A468;YI SYLLABLE XOX;Lo;0;L;;;;;N;;;;;
+A469;YI SYLLABLE XO;Lo;0;L;;;;;N;;;;;
+A46A;YI SYLLABLE XOP;Lo;0;L;;;;;N;;;;;
+A46B;YI SYLLABLE XYT;Lo;0;L;;;;;N;;;;;
+A46C;YI SYLLABLE XYX;Lo;0;L;;;;;N;;;;;
+A46D;YI SYLLABLE XY;Lo;0;L;;;;;N;;;;;
+A46E;YI SYLLABLE XYP;Lo;0;L;;;;;N;;;;;
+A46F;YI SYLLABLE XYRX;Lo;0;L;;;;;N;;;;;
+A470;YI SYLLABLE XYR;Lo;0;L;;;;;N;;;;;
+A471;YI SYLLABLE YIT;Lo;0;L;;;;;N;;;;;
+A472;YI SYLLABLE YIX;Lo;0;L;;;;;N;;;;;
+A473;YI SYLLABLE YI;Lo;0;L;;;;;N;;;;;
+A474;YI SYLLABLE YIP;Lo;0;L;;;;;N;;;;;
+A475;YI SYLLABLE YIET;Lo;0;L;;;;;N;;;;;
+A476;YI SYLLABLE YIEX;Lo;0;L;;;;;N;;;;;
+A477;YI SYLLABLE YIE;Lo;0;L;;;;;N;;;;;
+A478;YI SYLLABLE YIEP;Lo;0;L;;;;;N;;;;;
+A479;YI SYLLABLE YUOT;Lo;0;L;;;;;N;;;;;
+A47A;YI SYLLABLE YUOX;Lo;0;L;;;;;N;;;;;
+A47B;YI SYLLABLE YUO;Lo;0;L;;;;;N;;;;;
+A47C;YI SYLLABLE YUOP;Lo;0;L;;;;;N;;;;;
+A47D;YI SYLLABLE YOT;Lo;0;L;;;;;N;;;;;
+A47E;YI SYLLABLE YOX;Lo;0;L;;;;;N;;;;;
+A47F;YI SYLLABLE YO;Lo;0;L;;;;;N;;;;;
+A480;YI SYLLABLE YOP;Lo;0;L;;;;;N;;;;;
+A481;YI SYLLABLE YUT;Lo;0;L;;;;;N;;;;;
+A482;YI SYLLABLE YUX;Lo;0;L;;;;;N;;;;;
+A483;YI SYLLABLE YU;Lo;0;L;;;;;N;;;;;
+A484;YI SYLLABLE YUP;Lo;0;L;;;;;N;;;;;
+A485;YI SYLLABLE YURX;Lo;0;L;;;;;N;;;;;
+A486;YI SYLLABLE YUR;Lo;0;L;;;;;N;;;;;
+A487;YI SYLLABLE YYT;Lo;0;L;;;;;N;;;;;
+A488;YI SYLLABLE YYX;Lo;0;L;;;;;N;;;;;
+A489;YI SYLLABLE YY;Lo;0;L;;;;;N;;;;;
+A48A;YI SYLLABLE YYP;Lo;0;L;;;;;N;;;;;
+A48B;YI SYLLABLE YYRX;Lo;0;L;;;;;N;;;;;
+A48C;YI SYLLABLE YYR;Lo;0;L;;;;;N;;;;;
+A490;YI RADICAL QOT;So;0;ON;;;;;N;;;;;
+A491;YI RADICAL LI;So;0;ON;;;;;N;;;;;
+A492;YI RADICAL KIT;So;0;ON;;;;;N;;;;;
+A493;YI RADICAL NYIP;So;0;ON;;;;;N;;;;;
+A494;YI RADICAL CYP;So;0;ON;;;;;N;;;;;
+A495;YI RADICAL SSI;So;0;ON;;;;;N;;;;;
+A496;YI RADICAL GGOP;So;0;ON;;;;;N;;;;;
+A497;YI RADICAL GEP;So;0;ON;;;;;N;;;;;
+A498;YI RADICAL MI;So;0;ON;;;;;N;;;;;
+A499;YI RADICAL HXIT;So;0;ON;;;;;N;;;;;
+A49A;YI RADICAL LYR;So;0;ON;;;;;N;;;;;
+A49B;YI RADICAL BBUT;So;0;ON;;;;;N;;;;;
+A49C;YI RADICAL MOP;So;0;ON;;;;;N;;;;;
+A49D;YI RADICAL YO;So;0;ON;;;;;N;;;;;
+A49E;YI RADICAL PUT;So;0;ON;;;;;N;;;;;
+A49F;YI RADICAL HXUO;So;0;ON;;;;;N;;;;;
+A4A0;YI RADICAL TAT;So;0;ON;;;;;N;;;;;
+A4A1;YI RADICAL GA;So;0;ON;;;;;N;;;;;
+A4A4;YI RADICAL DDUR;So;0;ON;;;;;N;;;;;
+A4A5;YI RADICAL BUR;So;0;ON;;;;;N;;;;;
+A4A6;YI RADICAL GGUO;So;0;ON;;;;;N;;;;;
+A4A7;YI RADICAL NYOP;So;0;ON;;;;;N;;;;;
+A4A8;YI RADICAL TU;So;0;ON;;;;;N;;;;;
+A4A9;YI RADICAL OP;So;0;ON;;;;;N;;;;;
+A4AA;YI RADICAL JJUT;So;0;ON;;;;;N;;;;;
+A4AB;YI RADICAL ZOT;So;0;ON;;;;;N;;;;;
+A4AC;YI RADICAL PYT;So;0;ON;;;;;N;;;;;
+A4AD;YI RADICAL HMO;So;0;ON;;;;;N;;;;;
+A4AE;YI RADICAL YIT;So;0;ON;;;;;N;;;;;
+A4AF;YI RADICAL VUR;So;0;ON;;;;;N;;;;;
+A4B0;YI RADICAL SHY;So;0;ON;;;;;N;;;;;
+A4B1;YI RADICAL VEP;So;0;ON;;;;;N;;;;;
+A4B2;YI RADICAL ZA;So;0;ON;;;;;N;;;;;
+A4B3;YI RADICAL JO;So;0;ON;;;;;N;;;;;
+A4B5;YI RADICAL JJY;So;0;ON;;;;;N;;;;;
+A4B6;YI RADICAL GOT;So;0;ON;;;;;N;;;;;
+A4B7;YI RADICAL JJIE;So;0;ON;;;;;N;;;;;
+A4B8;YI RADICAL WO;So;0;ON;;;;;N;;;;;
+A4B9;YI RADICAL DU;So;0;ON;;;;;N;;;;;
+A4BA;YI RADICAL SHUR;So;0;ON;;;;;N;;;;;
+A4BB;YI RADICAL LIE;So;0;ON;;;;;N;;;;;
+A4BC;YI RADICAL CY;So;0;ON;;;;;N;;;;;
+A4BD;YI RADICAL CUOP;So;0;ON;;;;;N;;;;;
+A4BE;YI RADICAL CIP;So;0;ON;;;;;N;;;;;
+A4BF;YI RADICAL HXOP;So;0;ON;;;;;N;;;;;
+A4C0;YI RADICAL SHAT;So;0;ON;;;;;N;;;;;
+A4C2;YI RADICAL SHOP;So;0;ON;;;;;N;;;;;
+A4C3;YI RADICAL CHE;So;0;ON;;;;;N;;;;;
+A4C4;YI RADICAL ZZIET;So;0;ON;;;;;N;;;;;
+A4C6;YI RADICAL KE;So;0;ON;;;;;N;;;;;
+AC00;<Hangul Syllable, First>;Lo;0;L;;;;;N;;;;;
+D7A3;<Hangul Syllable, Last>;Lo;0;L;;;;;N;;;;;
+D800;<Non Private Use High Surrogate, First>;Cs;0;L;;;;;N;;;;;
+DB7F;<Non Private Use High Surrogate, Last>;Cs;0;L;;;;;N;;;;;
+DB80;<Private Use High Surrogate, First>;Cs;0;L;;;;;N;;;;;
+DBFF;<Private Use High Surrogate, Last>;Cs;0;L;;;;;N;;;;;
+DC00;<Low Surrogate, First>;Cs;0;L;;;;;N;;;;;
+DFFF;<Low Surrogate, Last>;Cs;0;L;;;;;N;;;;;
+E000;<Private Use, First>;Co;0;L;;;;;N;;;;;
+F8FF;<Private Use, Last>;Co;0;L;;;;;N;;;;;
+F900;CJK COMPATIBILITY IDEOGRAPH-F900;Lo;0;L;8C48;;;;N;;;;;
+F901;CJK COMPATIBILITY IDEOGRAPH-F901;Lo;0;L;66F4;;;;N;;;;;
+F902;CJK COMPATIBILITY IDEOGRAPH-F902;Lo;0;L;8ECA;;;;N;;;;;
+F903;CJK COMPATIBILITY IDEOGRAPH-F903;Lo;0;L;8CC8;;;;N;;;;;
+F904;CJK COMPATIBILITY IDEOGRAPH-F904;Lo;0;L;6ED1;;;;N;;;;;
+F905;CJK COMPATIBILITY IDEOGRAPH-F905;Lo;0;L;4E32;;;;N;;;;;
+F906;CJK COMPATIBILITY IDEOGRAPH-F906;Lo;0;L;53E5;;;;N;;;;;
+F907;CJK COMPATIBILITY IDEOGRAPH-F907;Lo;0;L;9F9C;;;;N;;;;;
+F908;CJK COMPATIBILITY IDEOGRAPH-F908;Lo;0;L;9F9C;;;;N;;;;;
+F909;CJK COMPATIBILITY IDEOGRAPH-F909;Lo;0;L;5951;;;;N;;;;;
+F90A;CJK COMPATIBILITY IDEOGRAPH-F90A;Lo;0;L;91D1;;;;N;;;;;
+F90B;CJK COMPATIBILITY IDEOGRAPH-F90B;Lo;0;L;5587;;;;N;;;;;
+F90C;CJK COMPATIBILITY IDEOGRAPH-F90C;Lo;0;L;5948;;;;N;;;;;
+F90D;CJK COMPATIBILITY IDEOGRAPH-F90D;Lo;0;L;61F6;;;;N;;;;;
+F90E;CJK COMPATIBILITY IDEOGRAPH-F90E;Lo;0;L;7669;;;;N;;;;;
+F90F;CJK COMPATIBILITY IDEOGRAPH-F90F;Lo;0;L;7F85;;;;N;;;;;
+F910;CJK COMPATIBILITY IDEOGRAPH-F910;Lo;0;L;863F;;;;N;;;;;
+F911;CJK COMPATIBILITY IDEOGRAPH-F911;Lo;0;L;87BA;;;;N;;;;;
+F912;CJK COMPATIBILITY IDEOGRAPH-F912;Lo;0;L;88F8;;;;N;;;;;
+F913;CJK COMPATIBILITY IDEOGRAPH-F913;Lo;0;L;908F;;;;N;;;;;
+F914;CJK COMPATIBILITY IDEOGRAPH-F914;Lo;0;L;6A02;;;;N;;;;;
+F915;CJK COMPATIBILITY IDEOGRAPH-F915;Lo;0;L;6D1B;;;;N;;;;;
+F916;CJK COMPATIBILITY IDEOGRAPH-F916;Lo;0;L;70D9;;;;N;;;;;
+F917;CJK COMPATIBILITY IDEOGRAPH-F917;Lo;0;L;73DE;;;;N;;;;;
+F918;CJK COMPATIBILITY IDEOGRAPH-F918;Lo;0;L;843D;;;;N;;;;;
+F919;CJK COMPATIBILITY IDEOGRAPH-F919;Lo;0;L;916A;;;;N;;;;;
+F91A;CJK COMPATIBILITY IDEOGRAPH-F91A;Lo;0;L;99F1;;;;N;;;;;
+F91B;CJK COMPATIBILITY IDEOGRAPH-F91B;Lo;0;L;4E82;;;;N;;;;;
+F91C;CJK COMPATIBILITY IDEOGRAPH-F91C;Lo;0;L;5375;;;;N;;;;;
+F91D;CJK COMPATIBILITY IDEOGRAPH-F91D;Lo;0;L;6B04;;;;N;;;;;
+F91E;CJK COMPATIBILITY IDEOGRAPH-F91E;Lo;0;L;721B;;;;N;;;;;
+F91F;CJK COMPATIBILITY IDEOGRAPH-F91F;Lo;0;L;862D;;;;N;;;;;
+F920;CJK COMPATIBILITY IDEOGRAPH-F920;Lo;0;L;9E1E;;;;N;;;;;
+F921;CJK COMPATIBILITY IDEOGRAPH-F921;Lo;0;L;5D50;;;;N;;;;;
+F922;CJK COMPATIBILITY IDEOGRAPH-F922;Lo;0;L;6FEB;;;;N;;;;;
+F923;CJK COMPATIBILITY IDEOGRAPH-F923;Lo;0;L;85CD;;;;N;;;;;
+F924;CJK COMPATIBILITY IDEOGRAPH-F924;Lo;0;L;8964;;;;N;;;;;
+F925;CJK COMPATIBILITY IDEOGRAPH-F925;Lo;0;L;62C9;;;;N;;;;;
+F926;CJK COMPATIBILITY IDEOGRAPH-F926;Lo;0;L;81D8;;;;N;;;;;
+F927;CJK COMPATIBILITY IDEOGRAPH-F927;Lo;0;L;881F;;;;N;;;;;
+F928;CJK COMPATIBILITY IDEOGRAPH-F928;Lo;0;L;5ECA;;;;N;;;;;
+F929;CJK COMPATIBILITY IDEOGRAPH-F929;Lo;0;L;6717;;;;N;;;;;
+F92A;CJK COMPATIBILITY IDEOGRAPH-F92A;Lo;0;L;6D6A;;;;N;;;;;
+F92B;CJK COMPATIBILITY IDEOGRAPH-F92B;Lo;0;L;72FC;;;;N;;;;;
+F92C;CJK COMPATIBILITY IDEOGRAPH-F92C;Lo;0;L;90CE;;;;N;;;;;
+F92D;CJK COMPATIBILITY IDEOGRAPH-F92D;Lo;0;L;4F86;;;;N;;;;;
+F92E;CJK COMPATIBILITY IDEOGRAPH-F92E;Lo;0;L;51B7;;;;N;;;;;
+F92F;CJK COMPATIBILITY IDEOGRAPH-F92F;Lo;0;L;52DE;;;;N;;;;;
+F930;CJK COMPATIBILITY IDEOGRAPH-F930;Lo;0;L;64C4;;;;N;;;;;
+F931;CJK COMPATIBILITY IDEOGRAPH-F931;Lo;0;L;6AD3;;;;N;;;;;
+F932;CJK COMPATIBILITY IDEOGRAPH-F932;Lo;0;L;7210;;;;N;;;;;
+F933;CJK COMPATIBILITY IDEOGRAPH-F933;Lo;0;L;76E7;;;;N;;;;;
+F934;CJK COMPATIBILITY IDEOGRAPH-F934;Lo;0;L;8001;;;;N;;;;;
+F935;CJK COMPATIBILITY IDEOGRAPH-F935;Lo;0;L;8606;;;;N;;;;;
+F936;CJK COMPATIBILITY IDEOGRAPH-F936;Lo;0;L;865C;;;;N;;;;;
+F937;CJK COMPATIBILITY IDEOGRAPH-F937;Lo;0;L;8DEF;;;;N;;;;;
+F938;CJK COMPATIBILITY IDEOGRAPH-F938;Lo;0;L;9732;;;;N;;;;;
+F939;CJK COMPATIBILITY IDEOGRAPH-F939;Lo;0;L;9B6F;;;;N;;;;;
+F93A;CJK COMPATIBILITY IDEOGRAPH-F93A;Lo;0;L;9DFA;;;;N;;;;;
+F93B;CJK COMPATIBILITY IDEOGRAPH-F93B;Lo;0;L;788C;;;;N;;;;;
+F93C;CJK COMPATIBILITY IDEOGRAPH-F93C;Lo;0;L;797F;;;;N;;;;;
+F93D;CJK COMPATIBILITY IDEOGRAPH-F93D;Lo;0;L;7DA0;;;;N;;;;;
+F93E;CJK COMPATIBILITY IDEOGRAPH-F93E;Lo;0;L;83C9;;;;N;;;;;
+F93F;CJK COMPATIBILITY IDEOGRAPH-F93F;Lo;0;L;9304;;;;N;;;;;
+F940;CJK COMPATIBILITY IDEOGRAPH-F940;Lo;0;L;9E7F;;;;N;;;;;
+F941;CJK COMPATIBILITY IDEOGRAPH-F941;Lo;0;L;8AD6;;;;N;;;;;
+F942;CJK COMPATIBILITY IDEOGRAPH-F942;Lo;0;L;58DF;;;;N;;;;;
+F943;CJK COMPATIBILITY IDEOGRAPH-F943;Lo;0;L;5F04;;;;N;;;;;
+F944;CJK COMPATIBILITY IDEOGRAPH-F944;Lo;0;L;7C60;;;;N;;;;;
+F945;CJK COMPATIBILITY IDEOGRAPH-F945;Lo;0;L;807E;;;;N;;;;;
+F946;CJK COMPATIBILITY IDEOGRAPH-F946;Lo;0;L;7262;;;;N;;;;;
+F947;CJK COMPATIBILITY IDEOGRAPH-F947;Lo;0;L;78CA;;;;N;;;;;
+F948;CJK COMPATIBILITY IDEOGRAPH-F948;Lo;0;L;8CC2;;;;N;;;;;
+F949;CJK COMPATIBILITY IDEOGRAPH-F949;Lo;0;L;96F7;;;;N;;;;;
+F94A;CJK COMPATIBILITY IDEOGRAPH-F94A;Lo;0;L;58D8;;;;N;;;;;
+F94B;CJK COMPATIBILITY IDEOGRAPH-F94B;Lo;0;L;5C62;;;;N;;;;;
+F94C;CJK COMPATIBILITY IDEOGRAPH-F94C;Lo;0;L;6A13;;;;N;;;;;
+F94D;CJK COMPATIBILITY IDEOGRAPH-F94D;Lo;0;L;6DDA;;;;N;;;;;
+F94E;CJK COMPATIBILITY IDEOGRAPH-F94E;Lo;0;L;6F0F;;;;N;;;;;
+F94F;CJK COMPATIBILITY IDEOGRAPH-F94F;Lo;0;L;7D2F;;;;N;;;;;
+F950;CJK COMPATIBILITY IDEOGRAPH-F950;Lo;0;L;7E37;;;;N;;;;;
+F951;CJK COMPATIBILITY IDEOGRAPH-F951;Lo;0;L;96FB;;;;N;;;;;
+F952;CJK COMPATIBILITY IDEOGRAPH-F952;Lo;0;L;52D2;;;;N;;;;;
+F953;CJK COMPATIBILITY IDEOGRAPH-F953;Lo;0;L;808B;;;;N;;;;;
+F954;CJK COMPATIBILITY IDEOGRAPH-F954;Lo;0;L;51DC;;;;N;;;;;
+F955;CJK COMPATIBILITY IDEOGRAPH-F955;Lo;0;L;51CC;;;;N;;;;;
+F956;CJK COMPATIBILITY IDEOGRAPH-F956;Lo;0;L;7A1C;;;;N;;;;;
+F957;CJK COMPATIBILITY IDEOGRAPH-F957;Lo;0;L;7DBE;;;;N;;;;;
+F958;CJK COMPATIBILITY IDEOGRAPH-F958;Lo;0;L;83F1;;;;N;;;;;
+F959;CJK COMPATIBILITY IDEOGRAPH-F959;Lo;0;L;9675;;;;N;;;;;
+F95A;CJK COMPATIBILITY IDEOGRAPH-F95A;Lo;0;L;8B80;;;;N;;;;;
+F95B;CJK COMPATIBILITY IDEOGRAPH-F95B;Lo;0;L;62CF;;;;N;;;;;
+F95C;CJK COMPATIBILITY IDEOGRAPH-F95C;Lo;0;L;6A02;;;;N;;;;;
+F95D;CJK COMPATIBILITY IDEOGRAPH-F95D;Lo;0;L;8AFE;;;;N;;;;;
+F95E;CJK COMPATIBILITY IDEOGRAPH-F95E;Lo;0;L;4E39;;;;N;;;;;
+F95F;CJK COMPATIBILITY IDEOGRAPH-F95F;Lo;0;L;5BE7;;;;N;;;;;
+F960;CJK COMPATIBILITY IDEOGRAPH-F960;Lo;0;L;6012;;;;N;;;;;
+F961;CJK COMPATIBILITY IDEOGRAPH-F961;Lo;0;L;7387;;;;N;;;;;
+F962;CJK COMPATIBILITY IDEOGRAPH-F962;Lo;0;L;7570;;;;N;;;;;
+F963;CJK COMPATIBILITY IDEOGRAPH-F963;Lo;0;L;5317;;;;N;;;;;
+F964;CJK COMPATIBILITY IDEOGRAPH-F964;Lo;0;L;78FB;;;;N;;;;;
+F965;CJK COMPATIBILITY IDEOGRAPH-F965;Lo;0;L;4FBF;;;;N;;;;;
+F966;CJK COMPATIBILITY IDEOGRAPH-F966;Lo;0;L;5FA9;;;;N;;;;;
+F967;CJK COMPATIBILITY IDEOGRAPH-F967;Lo;0;L;4E0D;;;;N;;;;;
+F968;CJK COMPATIBILITY IDEOGRAPH-F968;Lo;0;L;6CCC;;;;N;;;;;
+F969;CJK COMPATIBILITY IDEOGRAPH-F969;Lo;0;L;6578;;;;N;;;;;
+F96A;CJK COMPATIBILITY IDEOGRAPH-F96A;Lo;0;L;7D22;;;;N;;;;;
+F96B;CJK COMPATIBILITY IDEOGRAPH-F96B;Lo;0;L;53C3;;;;N;;;;;
+F96C;CJK COMPATIBILITY IDEOGRAPH-F96C;Lo;0;L;585E;;;;N;;;;;
+F96D;CJK COMPATIBILITY IDEOGRAPH-F96D;Lo;0;L;7701;;;;N;;;;;
+F96E;CJK COMPATIBILITY IDEOGRAPH-F96E;Lo;0;L;8449;;;;N;;;;;
+F96F;CJK COMPATIBILITY IDEOGRAPH-F96F;Lo;0;L;8AAA;;;;N;;;;;
+F970;CJK COMPATIBILITY IDEOGRAPH-F970;Lo;0;L;6BBA;;;;N;;;;;
+F971;CJK COMPATIBILITY IDEOGRAPH-F971;Lo;0;L;8FB0;;;;N;;;;;
+F972;CJK COMPATIBILITY IDEOGRAPH-F972;Lo;0;L;6C88;;;;N;;;;;
+F973;CJK COMPATIBILITY IDEOGRAPH-F973;Lo;0;L;62FE;;;;N;;;;;
+F974;CJK COMPATIBILITY IDEOGRAPH-F974;Lo;0;L;82E5;;;;N;;;;;
+F975;CJK COMPATIBILITY IDEOGRAPH-F975;Lo;0;L;63A0;;;;N;;;;;
+F976;CJK COMPATIBILITY IDEOGRAPH-F976;Lo;0;L;7565;;;;N;;;;;
+F977;CJK COMPATIBILITY IDEOGRAPH-F977;Lo;0;L;4EAE;;;;N;;;;;
+F978;CJK COMPATIBILITY IDEOGRAPH-F978;Lo;0;L;5169;;;;N;;;;;
+F979;CJK COMPATIBILITY IDEOGRAPH-F979;Lo;0;L;51C9;;;;N;;;;;
+F97A;CJK COMPATIBILITY IDEOGRAPH-F97A;Lo;0;L;6881;;;;N;;;;;
+F97B;CJK COMPATIBILITY IDEOGRAPH-F97B;Lo;0;L;7CE7;;;;N;;;;;
+F97C;CJK COMPATIBILITY IDEOGRAPH-F97C;Lo;0;L;826F;;;;N;;;;;
+F97D;CJK COMPATIBILITY IDEOGRAPH-F97D;Lo;0;L;8AD2;;;;N;;;;;
+F97E;CJK COMPATIBILITY IDEOGRAPH-F97E;Lo;0;L;91CF;;;;N;;;;;
+F97F;CJK COMPATIBILITY IDEOGRAPH-F97F;Lo;0;L;52F5;;;;N;;;;;
+F980;CJK COMPATIBILITY IDEOGRAPH-F980;Lo;0;L;5442;;;;N;;;;;
+F981;CJK COMPATIBILITY IDEOGRAPH-F981;Lo;0;L;5973;;;;N;;;;;
+F982;CJK COMPATIBILITY IDEOGRAPH-F982;Lo;0;L;5EEC;;;;N;;;;;
+F983;CJK COMPATIBILITY IDEOGRAPH-F983;Lo;0;L;65C5;;;;N;;;;;
+F984;CJK COMPATIBILITY IDEOGRAPH-F984;Lo;0;L;6FFE;;;;N;;;;;
+F985;CJK COMPATIBILITY IDEOGRAPH-F985;Lo;0;L;792A;;;;N;;;;;
+F986;CJK COMPATIBILITY IDEOGRAPH-F986;Lo;0;L;95AD;;;;N;;;;;
+F987;CJK COMPATIBILITY IDEOGRAPH-F987;Lo;0;L;9A6A;;;;N;;;;;
+F988;CJK COMPATIBILITY IDEOGRAPH-F988;Lo;0;L;9E97;;;;N;;;;;
+F989;CJK COMPATIBILITY IDEOGRAPH-F989;Lo;0;L;9ECE;;;;N;;;;;
+F98A;CJK COMPATIBILITY IDEOGRAPH-F98A;Lo;0;L;529B;;;;N;;;;;
+F98B;CJK COMPATIBILITY IDEOGRAPH-F98B;Lo;0;L;66C6;;;;N;;;;;
+F98C;CJK COMPATIBILITY IDEOGRAPH-F98C;Lo;0;L;6B77;;;;N;;;;;
+F98D;CJK COMPATIBILITY IDEOGRAPH-F98D;Lo;0;L;8F62;;;;N;;;;;
+F98E;CJK COMPATIBILITY IDEOGRAPH-F98E;Lo;0;L;5E74;;;;N;;;;;
+F98F;CJK COMPATIBILITY IDEOGRAPH-F98F;Lo;0;L;6190;;;;N;;;;;
+F990;CJK COMPATIBILITY IDEOGRAPH-F990;Lo;0;L;6200;;;;N;;;;;
+F991;CJK COMPATIBILITY IDEOGRAPH-F991;Lo;0;L;649A;;;;N;;;;;
+F992;CJK COMPATIBILITY IDEOGRAPH-F992;Lo;0;L;6F23;;;;N;;;;;
+F993;CJK COMPATIBILITY IDEOGRAPH-F993;Lo;0;L;7149;;;;N;;;;;
+F994;CJK COMPATIBILITY IDEOGRAPH-F994;Lo;0;L;7489;;;;N;;;;;
+F995;CJK COMPATIBILITY IDEOGRAPH-F995;Lo;0;L;79CA;;;;N;;;;;
+F996;CJK COMPATIBILITY IDEOGRAPH-F996;Lo;0;L;7DF4;;;;N;;;;;
+F997;CJK COMPATIBILITY IDEOGRAPH-F997;Lo;0;L;806F;;;;N;;;;;
+F998;CJK COMPATIBILITY IDEOGRAPH-F998;Lo;0;L;8F26;;;;N;;;;;
+F999;CJK COMPATIBILITY IDEOGRAPH-F999;Lo;0;L;84EE;;;;N;;;;;
+F99A;CJK COMPATIBILITY IDEOGRAPH-F99A;Lo;0;L;9023;;;;N;;;;;
+F99B;CJK COMPATIBILITY IDEOGRAPH-F99B;Lo;0;L;934A;;;;N;;;;;
+F99C;CJK COMPATIBILITY IDEOGRAPH-F99C;Lo;0;L;5217;;;;N;;;;;
+F99D;CJK COMPATIBILITY IDEOGRAPH-F99D;Lo;0;L;52A3;;;;N;;;;;
+F99E;CJK COMPATIBILITY IDEOGRAPH-F99E;Lo;0;L;54BD;;;;N;;;;;
+F99F;CJK COMPATIBILITY IDEOGRAPH-F99F;Lo;0;L;70C8;;;;N;;;;;
+F9A0;CJK COMPATIBILITY IDEOGRAPH-F9A0;Lo;0;L;88C2;;;;N;;;;;
+F9A1;CJK COMPATIBILITY IDEOGRAPH-F9A1;Lo;0;L;8AAA;;;;N;;;;;
+F9A2;CJK COMPATIBILITY IDEOGRAPH-F9A2;Lo;0;L;5EC9;;;;N;;;;;
+F9A3;CJK COMPATIBILITY IDEOGRAPH-F9A3;Lo;0;L;5FF5;;;;N;;;;;
+F9A4;CJK COMPATIBILITY IDEOGRAPH-F9A4;Lo;0;L;637B;;;;N;;;;;
+F9A5;CJK COMPATIBILITY IDEOGRAPH-F9A5;Lo;0;L;6BAE;;;;N;;;;;
+F9A6;CJK COMPATIBILITY IDEOGRAPH-F9A6;Lo;0;L;7C3E;;;;N;;;;;
+F9A7;CJK COMPATIBILITY IDEOGRAPH-F9A7;Lo;0;L;7375;;;;N;;;;;
+F9A8;CJK COMPATIBILITY IDEOGRAPH-F9A8;Lo;0;L;4EE4;;;;N;;;;;
+F9A9;CJK COMPATIBILITY IDEOGRAPH-F9A9;Lo;0;L;56F9;;;;N;;;;;
+F9AA;CJK COMPATIBILITY IDEOGRAPH-F9AA;Lo;0;L;5BE7;;;;N;;;;;
+F9AB;CJK COMPATIBILITY IDEOGRAPH-F9AB;Lo;0;L;5DBA;;;;N;;;;;
+F9AC;CJK COMPATIBILITY IDEOGRAPH-F9AC;Lo;0;L;601C;;;;N;;;;;
+F9AD;CJK COMPATIBILITY IDEOGRAPH-F9AD;Lo;0;L;73B2;;;;N;;;;;
+F9AE;CJK COMPATIBILITY IDEOGRAPH-F9AE;Lo;0;L;7469;;;;N;;;;;
+F9AF;CJK COMPATIBILITY IDEOGRAPH-F9AF;Lo;0;L;7F9A;;;;N;;;;;
+F9B0;CJK COMPATIBILITY IDEOGRAPH-F9B0;Lo;0;L;8046;;;;N;;;;;
+F9B1;CJK COMPATIBILITY IDEOGRAPH-F9B1;Lo;0;L;9234;;;;N;;;;;
+F9B2;CJK COMPATIBILITY IDEOGRAPH-F9B2;Lo;0;L;96F6;;;;N;;;;;
+F9B3;CJK COMPATIBILITY IDEOGRAPH-F9B3;Lo;0;L;9748;;;;N;;;;;
+F9B4;CJK COMPATIBILITY IDEOGRAPH-F9B4;Lo;0;L;9818;;;;N;;;;;
+F9B5;CJK COMPATIBILITY IDEOGRAPH-F9B5;Lo;0;L;4F8B;;;;N;;;;;
+F9B6;CJK COMPATIBILITY IDEOGRAPH-F9B6;Lo;0;L;79AE;;;;N;;;;;
+F9B7;CJK COMPATIBILITY IDEOGRAPH-F9B7;Lo;0;L;91B4;;;;N;;;;;
+F9B8;CJK COMPATIBILITY IDEOGRAPH-F9B8;Lo;0;L;96B8;;;;N;;;;;
+F9B9;CJK COMPATIBILITY IDEOGRAPH-F9B9;Lo;0;L;60E1;;;;N;;;;;
+F9BA;CJK COMPATIBILITY IDEOGRAPH-F9BA;Lo;0;L;4E86;;;;N;;;;;
+F9BB;CJK COMPATIBILITY IDEOGRAPH-F9BB;Lo;0;L;50DA;;;;N;;;;;
+F9BC;CJK COMPATIBILITY IDEOGRAPH-F9BC;Lo;0;L;5BEE;;;;N;;;;;
+F9BD;CJK COMPATIBILITY IDEOGRAPH-F9BD;Lo;0;L;5C3F;;;;N;;;;;
+F9BE;CJK COMPATIBILITY IDEOGRAPH-F9BE;Lo;0;L;6599;;;;N;;;;;
+F9BF;CJK COMPATIBILITY IDEOGRAPH-F9BF;Lo;0;L;6A02;;;;N;;;;;
+F9C0;CJK COMPATIBILITY IDEOGRAPH-F9C0;Lo;0;L;71CE;;;;N;;;;;
+F9C1;CJK COMPATIBILITY IDEOGRAPH-F9C1;Lo;0;L;7642;;;;N;;;;;
+F9C2;CJK COMPATIBILITY IDEOGRAPH-F9C2;Lo;0;L;84FC;;;;N;;;;;
+F9C3;CJK COMPATIBILITY IDEOGRAPH-F9C3;Lo;0;L;907C;;;;N;;;;;
+F9C4;CJK COMPATIBILITY IDEOGRAPH-F9C4;Lo;0;L;9F8D;;;;N;;;;;
+F9C5;CJK COMPATIBILITY IDEOGRAPH-F9C5;Lo;0;L;6688;;;;N;;;;;
+F9C6;CJK COMPATIBILITY IDEOGRAPH-F9C6;Lo;0;L;962E;;;;N;;;;;
+F9C7;CJK COMPATIBILITY IDEOGRAPH-F9C7;Lo;0;L;5289;;;;N;;;;;
+F9C8;CJK COMPATIBILITY IDEOGRAPH-F9C8;Lo;0;L;677B;;;;N;;;;;
+F9C9;CJK COMPATIBILITY IDEOGRAPH-F9C9;Lo;0;L;67F3;;;;N;;;;;
+F9CA;CJK COMPATIBILITY IDEOGRAPH-F9CA;Lo;0;L;6D41;;;;N;;;;;
+F9CB;CJK COMPATIBILITY IDEOGRAPH-F9CB;Lo;0;L;6E9C;;;;N;;;;;
+F9CC;CJK COMPATIBILITY IDEOGRAPH-F9CC;Lo;0;L;7409;;;;N;;;;;
+F9CD;CJK COMPATIBILITY IDEOGRAPH-F9CD;Lo;0;L;7559;;;;N;;;;;
+F9CE;CJK COMPATIBILITY IDEOGRAPH-F9CE;Lo;0;L;786B;;;;N;;;;;
+F9CF;CJK COMPATIBILITY IDEOGRAPH-F9CF;Lo;0;L;7D10;;;;N;;;;;
+F9D0;CJK COMPATIBILITY IDEOGRAPH-F9D0;Lo;0;L;985E;;;;N;;;;;
+F9D1;CJK COMPATIBILITY IDEOGRAPH-F9D1;Lo;0;L;516D;;;;N;;;;;
+F9D2;CJK COMPATIBILITY IDEOGRAPH-F9D2;Lo;0;L;622E;;;;N;;;;;
+F9D3;CJK COMPATIBILITY IDEOGRAPH-F9D3;Lo;0;L;9678;;;;N;;;;;
+F9D4;CJK COMPATIBILITY IDEOGRAPH-F9D4;Lo;0;L;502B;;;;N;;;;;
+F9D5;CJK COMPATIBILITY IDEOGRAPH-F9D5;Lo;0;L;5D19;;;;N;;;;;
+F9D6;CJK COMPATIBILITY IDEOGRAPH-F9D6;Lo;0;L;6DEA;;;;N;;;;;
+F9D7;CJK COMPATIBILITY IDEOGRAPH-F9D7;Lo;0;L;8F2A;;;;N;;;;;
+F9D8;CJK COMPATIBILITY IDEOGRAPH-F9D8;Lo;0;L;5F8B;;;;N;;;;;
+F9D9;CJK COMPATIBILITY IDEOGRAPH-F9D9;Lo;0;L;6144;;;;N;;;;;
+F9DA;CJK COMPATIBILITY IDEOGRAPH-F9DA;Lo;0;L;6817;;;;N;;;;;
+F9DB;CJK COMPATIBILITY IDEOGRAPH-F9DB;Lo;0;L;7387;;;;N;;;;;
+F9DC;CJK COMPATIBILITY IDEOGRAPH-F9DC;Lo;0;L;9686;;;;N;;;;;
+F9DD;CJK COMPATIBILITY IDEOGRAPH-F9DD;Lo;0;L;5229;;;;N;;;;;
+F9DE;CJK COMPATIBILITY IDEOGRAPH-F9DE;Lo;0;L;540F;;;;N;;;;;
+F9DF;CJK COMPATIBILITY IDEOGRAPH-F9DF;Lo;0;L;5C65;;;;N;;;;;
+F9E0;CJK COMPATIBILITY IDEOGRAPH-F9E0;Lo;0;L;6613;;;;N;;;;;
+F9E1;CJK COMPATIBILITY IDEOGRAPH-F9E1;Lo;0;L;674E;;;;N;;;;;
+F9E2;CJK COMPATIBILITY IDEOGRAPH-F9E2;Lo;0;L;68A8;;;;N;;;;;
+F9E3;CJK COMPATIBILITY IDEOGRAPH-F9E3;Lo;0;L;6CE5;;;;N;;;;;
+F9E4;CJK COMPATIBILITY IDEOGRAPH-F9E4;Lo;0;L;7406;;;;N;;;;;
+F9E5;CJK COMPATIBILITY IDEOGRAPH-F9E5;Lo;0;L;75E2;;;;N;;;;;
+F9E6;CJK COMPATIBILITY IDEOGRAPH-F9E6;Lo;0;L;7F79;;;;N;;;;;
+F9E7;CJK COMPATIBILITY IDEOGRAPH-F9E7;Lo;0;L;88CF;;;;N;;;;;
+F9E8;CJK COMPATIBILITY IDEOGRAPH-F9E8;Lo;0;L;88E1;;;;N;;;;;
+F9E9;CJK COMPATIBILITY IDEOGRAPH-F9E9;Lo;0;L;91CC;;;;N;;;;;
+F9EA;CJK COMPATIBILITY IDEOGRAPH-F9EA;Lo;0;L;96E2;;;;N;;;;;
+F9EB;CJK COMPATIBILITY IDEOGRAPH-F9EB;Lo;0;L;533F;;;;N;;;;;
+F9EC;CJK COMPATIBILITY IDEOGRAPH-F9EC;Lo;0;L;6EBA;;;;N;;;;;
+F9ED;CJK COMPATIBILITY IDEOGRAPH-F9ED;Lo;0;L;541D;;;;N;;;;;
+F9EE;CJK COMPATIBILITY IDEOGRAPH-F9EE;Lo;0;L;71D0;;;;N;;;;;
+F9EF;CJK COMPATIBILITY IDEOGRAPH-F9EF;Lo;0;L;7498;;;;N;;;;;
+F9F0;CJK COMPATIBILITY IDEOGRAPH-F9F0;Lo;0;L;85FA;;;;N;;;;;
+F9F1;CJK COMPATIBILITY IDEOGRAPH-F9F1;Lo;0;L;96A3;;;;N;;;;;
+F9F2;CJK COMPATIBILITY IDEOGRAPH-F9F2;Lo;0;L;9C57;;;;N;;;;;
+F9F3;CJK COMPATIBILITY IDEOGRAPH-F9F3;Lo;0;L;9E9F;;;;N;;;;;
+F9F4;CJK COMPATIBILITY IDEOGRAPH-F9F4;Lo;0;L;6797;;;;N;;;;;
+F9F5;CJK COMPATIBILITY IDEOGRAPH-F9F5;Lo;0;L;6DCB;;;;N;;;;;
+F9F6;CJK COMPATIBILITY IDEOGRAPH-F9F6;Lo;0;L;81E8;;;;N;;;;;
+F9F7;CJK COMPATIBILITY IDEOGRAPH-F9F7;Lo;0;L;7ACB;;;;N;;;;;
+F9F8;CJK COMPATIBILITY IDEOGRAPH-F9F8;Lo;0;L;7B20;;;;N;;;;;
+F9F9;CJK COMPATIBILITY IDEOGRAPH-F9F9;Lo;0;L;7C92;;;;N;;;;;
+F9FA;CJK COMPATIBILITY IDEOGRAPH-F9FA;Lo;0;L;72C0;;;;N;;;;;
+F9FB;CJK COMPATIBILITY IDEOGRAPH-F9FB;Lo;0;L;7099;;;;N;;;;;
+F9FC;CJK COMPATIBILITY IDEOGRAPH-F9FC;Lo;0;L;8B58;;;;N;;;;;
+F9FD;CJK COMPATIBILITY IDEOGRAPH-F9FD;Lo;0;L;4EC0;;;;N;;;;;
+F9FE;CJK COMPATIBILITY IDEOGRAPH-F9FE;Lo;0;L;8336;;;;N;;;;;
+F9FF;CJK COMPATIBILITY IDEOGRAPH-F9FF;Lo;0;L;523A;;;;N;;;;;
+FA00;CJK COMPATIBILITY IDEOGRAPH-FA00;Lo;0;L;5207;;;;N;;;;;
+FA01;CJK COMPATIBILITY IDEOGRAPH-FA01;Lo;0;L;5EA6;;;;N;;;;;
+FA02;CJK COMPATIBILITY IDEOGRAPH-FA02;Lo;0;L;62D3;;;;N;;;;;
+FA03;CJK COMPATIBILITY IDEOGRAPH-FA03;Lo;0;L;7CD6;;;;N;;;;;
+FA04;CJK COMPATIBILITY IDEOGRAPH-FA04;Lo;0;L;5B85;;;;N;;;;;
+FA05;CJK COMPATIBILITY IDEOGRAPH-FA05;Lo;0;L;6D1E;;;;N;;;;;
+FA06;CJK COMPATIBILITY IDEOGRAPH-FA06;Lo;0;L;66B4;;;;N;;;;;
+FA07;CJK COMPATIBILITY IDEOGRAPH-FA07;Lo;0;L;8F3B;;;;N;;;;;
+FA08;CJK COMPATIBILITY IDEOGRAPH-FA08;Lo;0;L;884C;;;;N;;;;;
+FA09;CJK COMPATIBILITY IDEOGRAPH-FA09;Lo;0;L;964D;;;;N;;;;;
+FA0A;CJK COMPATIBILITY IDEOGRAPH-FA0A;Lo;0;L;898B;;;;N;;;;;
+FA0B;CJK COMPATIBILITY IDEOGRAPH-FA0B;Lo;0;L;5ED3;;;;N;;;;;
+FA0C;CJK COMPATIBILITY IDEOGRAPH-FA0C;Lo;0;L;5140;;;;N;;;;;
+FA0D;CJK COMPATIBILITY IDEOGRAPH-FA0D;Lo;0;L;55C0;;;;N;;;;;
+FA0E;CJK COMPATIBILITY IDEOGRAPH-FA0E;Lo;0;L;;;;;N;;;;;
+FA0F;CJK COMPATIBILITY IDEOGRAPH-FA0F;Lo;0;L;;;;;N;;;;;
+FA10;CJK COMPATIBILITY IDEOGRAPH-FA10;Lo;0;L;585A;;;;N;;;;;
+FA11;CJK COMPATIBILITY IDEOGRAPH-FA11;Lo;0;L;;;;;N;;;;;
+FA12;CJK COMPATIBILITY IDEOGRAPH-FA12;Lo;0;L;6674;;;;N;;;;;
+FA13;CJK COMPATIBILITY IDEOGRAPH-FA13;Lo;0;L;;;;;N;;;;;
+FA14;CJK COMPATIBILITY IDEOGRAPH-FA14;Lo;0;L;;;;;N;;;;;
+FA15;CJK COMPATIBILITY IDEOGRAPH-FA15;Lo;0;L;51DE;;;;N;;;;;
+FA16;CJK COMPATIBILITY IDEOGRAPH-FA16;Lo;0;L;732A;;;;N;;;;;
+FA17;CJK COMPATIBILITY IDEOGRAPH-FA17;Lo;0;L;76CA;;;;N;;;;;
+FA18;CJK COMPATIBILITY IDEOGRAPH-FA18;Lo;0;L;793C;;;;N;;;;;
+FA19;CJK COMPATIBILITY IDEOGRAPH-FA19;Lo;0;L;795E;;;;N;;;;;
+FA1A;CJK COMPATIBILITY IDEOGRAPH-FA1A;Lo;0;L;7965;;;;N;;;;;
+FA1B;CJK COMPATIBILITY IDEOGRAPH-FA1B;Lo;0;L;798F;;;;N;;;;;
+FA1C;CJK COMPATIBILITY IDEOGRAPH-FA1C;Lo;0;L;9756;;;;N;;;;;
+FA1D;CJK COMPATIBILITY IDEOGRAPH-FA1D;Lo;0;L;7CBE;;;;N;;;;;
+FA1E;CJK COMPATIBILITY IDEOGRAPH-FA1E;Lo;0;L;7FBD;;;;N;;;;;
+FA1F;CJK COMPATIBILITY IDEOGRAPH-FA1F;Lo;0;L;;;;;N;;*;;;
+FA20;CJK COMPATIBILITY IDEOGRAPH-FA20;Lo;0;L;8612;;;;N;;;;;
+FA21;CJK COMPATIBILITY IDEOGRAPH-FA21;Lo;0;L;;;;;N;;;;;
+FA22;CJK COMPATIBILITY IDEOGRAPH-FA22;Lo;0;L;8AF8;;;;N;;;;;
+FA23;CJK COMPATIBILITY IDEOGRAPH-FA23;Lo;0;L;;;;;N;;*;;;
+FA24;CJK COMPATIBILITY IDEOGRAPH-FA24;Lo;0;L;;;;;N;;;;;
+FA25;CJK COMPATIBILITY IDEOGRAPH-FA25;Lo;0;L;9038;;;;N;;;;;
+FA26;CJK COMPATIBILITY IDEOGRAPH-FA26;Lo;0;L;90FD;;;;N;;;;;
+FA27;CJK COMPATIBILITY IDEOGRAPH-FA27;Lo;0;L;;;;;N;;;;;
+FA28;CJK COMPATIBILITY IDEOGRAPH-FA28;Lo;0;L;;;;;N;;;;;
+FA29;CJK COMPATIBILITY IDEOGRAPH-FA29;Lo;0;L;;;;;N;;;;;
+FA2A;CJK COMPATIBILITY IDEOGRAPH-FA2A;Lo;0;L;98EF;;;;N;;;;;
+FA2B;CJK COMPATIBILITY IDEOGRAPH-FA2B;Lo;0;L;98FC;;;;N;;;;;
+FA2C;CJK COMPATIBILITY IDEOGRAPH-FA2C;Lo;0;L;9928;;;;N;;;;;
+FA2D;CJK COMPATIBILITY IDEOGRAPH-FA2D;Lo;0;L;9DB4;;;;N;;;;;
+FB00;LATIN SMALL LIGATURE FF;Ll;0;L;<compat> 0066 0066;;;;N;;;;;
+FB01;LATIN SMALL LIGATURE FI;Ll;0;L;<compat> 0066 0069;;;;N;;;;;
+FB02;LATIN SMALL LIGATURE FL;Ll;0;L;<compat> 0066 006C;;;;N;;;;;
+FB03;LATIN SMALL LIGATURE FFI;Ll;0;L;<compat> 0066 0066 0069;;;;N;;;;;
+FB04;LATIN SMALL LIGATURE FFL;Ll;0;L;<compat> 0066 0066 006C;;;;N;;;;;
+FB05;LATIN SMALL LIGATURE LONG S T;Ll;0;L;<compat> 017F 0074;;;;N;;;;;
+FB06;LATIN SMALL LIGATURE ST;Ll;0;L;<compat> 0073 0074;;;;N;;;;;
+FB13;ARMENIAN SMALL LIGATURE MEN NOW;Ll;0;L;<compat> 0574 0576;;;;N;;;;;
+FB14;ARMENIAN SMALL LIGATURE MEN ECH;Ll;0;L;<compat> 0574 0565;;;;N;;;;;
+FB15;ARMENIAN SMALL LIGATURE MEN INI;Ll;0;L;<compat> 0574 056B;;;;N;;;;;
+FB16;ARMENIAN SMALL LIGATURE VEW NOW;Ll;0;L;<compat> 057E 0576;;;;N;;;;;
+FB17;ARMENIAN SMALL LIGATURE MEN XEH;Ll;0;L;<compat> 0574 056D;;;;N;;;;;
+FB1D;HEBREW LETTER YOD WITH HIRIQ;Lo;0;R;05D9 05B4;;;;N;;;;;
+FB1E;HEBREW POINT JUDEO-SPANISH VARIKA;Mn;26;NSM;;;;;N;HEBREW POINT VARIKA;;;;
+FB1F;HEBREW LIGATURE YIDDISH YOD YOD PATAH;Lo;0;R;05F2 05B7;;;;N;;;;;
+FB20;HEBREW LETTER ALTERNATIVE AYIN;Lo;0;R;<font> 05E2;;;;N;;;;;
+FB21;HEBREW LETTER WIDE ALEF;Lo;0;R;<font> 05D0;;;;N;;;;;
+FB22;HEBREW LETTER WIDE DALET;Lo;0;R;<font> 05D3;;;;N;;;;;
+FB23;HEBREW LETTER WIDE HE;Lo;0;R;<font> 05D4;;;;N;;;;;
+FB24;HEBREW LETTER WIDE KAF;Lo;0;R;<font> 05DB;;;;N;;;;;
+FB25;HEBREW LETTER WIDE LAMED;Lo;0;R;<font> 05DC;;;;N;;;;;
+FB26;HEBREW LETTER WIDE FINAL MEM;Lo;0;R;<font> 05DD;;;;N;;;;;
+FB27;HEBREW LETTER WIDE RESH;Lo;0;R;<font> 05E8;;;;N;;;;;
+FB28;HEBREW LETTER WIDE TAV;Lo;0;R;<font> 05EA;;;;N;;;;;
+FB29;HEBREW LETTER ALTERNATIVE PLUS SIGN;Sm;0;ET;<font> 002B;;;;N;;;;;
+FB2A;HEBREW LETTER SHIN WITH SHIN DOT;Lo;0;R;05E9 05C1;;;;N;;;;;
+FB2B;HEBREW LETTER SHIN WITH SIN DOT;Lo;0;R;05E9 05C2;;;;N;;;;;
+FB2C;HEBREW LETTER SHIN WITH DAGESH AND SHIN DOT;Lo;0;R;FB49 05C1;;;;N;;;;;
+FB2D;HEBREW LETTER SHIN WITH DAGESH AND SIN DOT;Lo;0;R;FB49 05C2;;;;N;;;;;
+FB2E;HEBREW LETTER ALEF WITH PATAH;Lo;0;R;05D0 05B7;;;;N;;;;;
+FB2F;HEBREW LETTER ALEF WITH QAMATS;Lo;0;R;05D0 05B8;;;;N;;;;;
+FB30;HEBREW LETTER ALEF WITH MAPIQ;Lo;0;R;05D0 05BC;;;;N;;;;;
+FB31;HEBREW LETTER BET WITH DAGESH;Lo;0;R;05D1 05BC;;;;N;;;;;
+FB32;HEBREW LETTER GIMEL WITH DAGESH;Lo;0;R;05D2 05BC;;;;N;;;;;
+FB33;HEBREW LETTER DALET WITH DAGESH;Lo;0;R;05D3 05BC;;;;N;;;;;
+FB34;HEBREW LETTER HE WITH MAPIQ;Lo;0;R;05D4 05BC;;;;N;;;;;
+FB35;HEBREW LETTER VAV WITH DAGESH;Lo;0;R;05D5 05BC;;;;N;;;;;
+FB36;HEBREW LETTER ZAYIN WITH DAGESH;Lo;0;R;05D6 05BC;;;;N;;;;;
+FB38;HEBREW LETTER TET WITH DAGESH;Lo;0;R;05D8 05BC;;;;N;;;;;
+FB39;HEBREW LETTER YOD WITH DAGESH;Lo;0;R;05D9 05BC;;;;N;;;;;
+FB3A;HEBREW LETTER FINAL KAF WITH DAGESH;Lo;0;R;05DA 05BC;;;;N;;;;;
+FB3B;HEBREW LETTER KAF WITH DAGESH;Lo;0;R;05DB 05BC;;;;N;;;;;
+FB3C;HEBREW LETTER LAMED WITH DAGESH;Lo;0;R;05DC 05BC;;;;N;;;;;
+FB3E;HEBREW LETTER MEM WITH DAGESH;Lo;0;R;05DE 05BC;;;;N;;;;;
+FB40;HEBREW LETTER NUN WITH DAGESH;Lo;0;R;05E0 05BC;;;;N;;;;;
+FB41;HEBREW LETTER SAMEKH WITH DAGESH;Lo;0;R;05E1 05BC;;;;N;;;;;
+FB43;HEBREW LETTER FINAL PE WITH DAGESH;Lo;0;R;05E3 05BC;;;;N;;;;;
+FB44;HEBREW LETTER PE WITH DAGESH;Lo;0;R;05E4 05BC;;;;N;;;;;
+FB46;HEBREW LETTER TSADI WITH DAGESH;Lo;0;R;05E6 05BC;;;;N;;;;;
+FB47;HEBREW LETTER QOF WITH DAGESH;Lo;0;R;05E7 05BC;;;;N;;;;;
+FB48;HEBREW LETTER RESH WITH DAGESH;Lo;0;R;05E8 05BC;;;;N;;;;;
+FB49;HEBREW LETTER SHIN WITH DAGESH;Lo;0;R;05E9 05BC;;;;N;;;;;
+FB4A;HEBREW LETTER TAV WITH DAGESH;Lo;0;R;05EA 05BC;;;;N;;;;;
+FB4B;HEBREW LETTER VAV WITH HOLAM;Lo;0;R;05D5 05B9;;;;N;;;;;
+FB4C;HEBREW LETTER BET WITH RAFE;Lo;0;R;05D1 05BF;;;;N;;;;;
+FB4D;HEBREW LETTER KAF WITH RAFE;Lo;0;R;05DB 05BF;;;;N;;;;;
+FB4E;HEBREW LETTER PE WITH RAFE;Lo;0;R;05E4 05BF;;;;N;;;;;
+FB4F;HEBREW LIGATURE ALEF LAMED;Lo;0;R;<compat> 05D0 05DC;;;;N;;;;;
+FB50;ARABIC LETTER ALEF WASLA ISOLATED FORM;Lo;0;AL;<isolated> 0671;;;;N;;;;;
+FB51;ARABIC LETTER ALEF WASLA FINAL FORM;Lo;0;AL;<final> 0671;;;;N;;;;;
+FB52;ARABIC LETTER BEEH ISOLATED FORM;Lo;0;AL;<isolated> 067B;;;;N;;;;;
+FB53;ARABIC LETTER BEEH FINAL FORM;Lo;0;AL;<final> 067B;;;;N;;;;;
+FB54;ARABIC LETTER BEEH INITIAL FORM;Lo;0;AL;<initial> 067B;;;;N;;;;;
+FB55;ARABIC LETTER BEEH MEDIAL FORM;Lo;0;AL;<medial> 067B;;;;N;;;;;
+FB56;ARABIC LETTER PEH ISOLATED FORM;Lo;0;AL;<isolated> 067E;;;;N;;;;;
+FB57;ARABIC LETTER PEH FINAL FORM;Lo;0;AL;<final> 067E;;;;N;;;;;
+FB58;ARABIC LETTER PEH INITIAL FORM;Lo;0;AL;<initial> 067E;;;;N;;;;;
+FB59;ARABIC LETTER PEH MEDIAL FORM;Lo;0;AL;<medial> 067E;;;;N;;;;;
+FB5A;ARABIC LETTER BEHEH ISOLATED FORM;Lo;0;AL;<isolated> 0680;;;;N;;;;;
+FB5B;ARABIC LETTER BEHEH FINAL FORM;Lo;0;AL;<final> 0680;;;;N;;;;;
+FB5C;ARABIC LETTER BEHEH INITIAL FORM;Lo;0;AL;<initial> 0680;;;;N;;;;;
+FB5D;ARABIC LETTER BEHEH MEDIAL FORM;Lo;0;AL;<medial> 0680;;;;N;;;;;
+FB5E;ARABIC LETTER TTEHEH ISOLATED FORM;Lo;0;AL;<isolated> 067A;;;;N;;;;;
+FB5F;ARABIC LETTER TTEHEH FINAL FORM;Lo;0;AL;<final> 067A;;;;N;;;;;
+FB60;ARABIC LETTER TTEHEH INITIAL FORM;Lo;0;AL;<initial> 067A;;;;N;;;;;
+FB61;ARABIC LETTER TTEHEH MEDIAL FORM;Lo;0;AL;<medial> 067A;;;;N;;;;;
+FB62;ARABIC LETTER TEHEH ISOLATED FORM;Lo;0;AL;<isolated> 067F;;;;N;;;;;
+FB63;ARABIC LETTER TEHEH FINAL FORM;Lo;0;AL;<final> 067F;;;;N;;;;;
+FB64;ARABIC LETTER TEHEH INITIAL FORM;Lo;0;AL;<initial> 067F;;;;N;;;;;
+FB65;ARABIC LETTER TEHEH MEDIAL FORM;Lo;0;AL;<medial> 067F;;;;N;;;;;
+FB66;ARABIC LETTER TTEH ISOLATED FORM;Lo;0;AL;<isolated> 0679;;;;N;;;;;
+FB67;ARABIC LETTER TTEH FINAL FORM;Lo;0;AL;<final> 0679;;;;N;;;;;
+FB68;ARABIC LETTER TTEH INITIAL FORM;Lo;0;AL;<initial> 0679;;;;N;;;;;
+FB69;ARABIC LETTER TTEH MEDIAL FORM;Lo;0;AL;<medial> 0679;;;;N;;;;;
+FB6A;ARABIC LETTER VEH ISOLATED FORM;Lo;0;AL;<isolated> 06A4;;;;N;;;;;
+FB6B;ARABIC LETTER VEH FINAL FORM;Lo;0;AL;<final> 06A4;;;;N;;;;;
+FB6C;ARABIC LETTER VEH INITIAL FORM;Lo;0;AL;<initial> 06A4;;;;N;;;;;
+FB6D;ARABIC LETTER VEH MEDIAL FORM;Lo;0;AL;<medial> 06A4;;;;N;;;;;
+FB6E;ARABIC LETTER PEHEH ISOLATED FORM;Lo;0;AL;<isolated> 06A6;;;;N;;;;;
+FB6F;ARABIC LETTER PEHEH FINAL FORM;Lo;0;AL;<final> 06A6;;;;N;;;;;
+FB70;ARABIC LETTER PEHEH INITIAL FORM;Lo;0;AL;<initial> 06A6;;;;N;;;;;
+FB71;ARABIC LETTER PEHEH MEDIAL FORM;Lo;0;AL;<medial> 06A6;;;;N;;;;;
+FB72;ARABIC LETTER DYEH ISOLATED FORM;Lo;0;AL;<isolated> 0684;;;;N;;;;;
+FB73;ARABIC LETTER DYEH FINAL FORM;Lo;0;AL;<final> 0684;;;;N;;;;;
+FB74;ARABIC LETTER DYEH INITIAL FORM;Lo;0;AL;<initial> 0684;;;;N;;;;;
+FB75;ARABIC LETTER DYEH MEDIAL FORM;Lo;0;AL;<medial> 0684;;;;N;;;;;
+FB76;ARABIC LETTER NYEH ISOLATED FORM;Lo;0;AL;<isolated> 0683;;;;N;;;;;
+FB77;ARABIC LETTER NYEH FINAL FORM;Lo;0;AL;<final> 0683;;;;N;;;;;
+FB78;ARABIC LETTER NYEH INITIAL FORM;Lo;0;AL;<initial> 0683;;;;N;;;;;
+FB79;ARABIC LETTER NYEH MEDIAL FORM;Lo;0;AL;<medial> 0683;;;;N;;;;;
+FB7A;ARABIC LETTER TCHEH ISOLATED FORM;Lo;0;AL;<isolated> 0686;;;;N;;;;;
+FB7B;ARABIC LETTER TCHEH FINAL FORM;Lo;0;AL;<final> 0686;;;;N;;;;;
+FB7C;ARABIC LETTER TCHEH INITIAL FORM;Lo;0;AL;<initial> 0686;;;;N;;;;;
+FB7D;ARABIC LETTER TCHEH MEDIAL FORM;Lo;0;AL;<medial> 0686;;;;N;;;;;
+FB7E;ARABIC LETTER TCHEHEH ISOLATED FORM;Lo;0;AL;<isolated> 0687;;;;N;;;;;
+FB7F;ARABIC LETTER TCHEHEH FINAL FORM;Lo;0;AL;<final> 0687;;;;N;;;;;
+FB80;ARABIC LETTER TCHEHEH INITIAL FORM;Lo;0;AL;<initial> 0687;;;;N;;;;;
+FB81;ARABIC LETTER TCHEHEH MEDIAL FORM;Lo;0;AL;<medial> 0687;;;;N;;;;;
+FB82;ARABIC LETTER DDAHAL ISOLATED FORM;Lo;0;AL;<isolated> 068D;;;;N;;;;;
+FB83;ARABIC LETTER DDAHAL FINAL FORM;Lo;0;AL;<final> 068D;;;;N;;;;;
+FB84;ARABIC LETTER DAHAL ISOLATED FORM;Lo;0;AL;<isolated> 068C;;;;N;;;;;
+FB85;ARABIC LETTER DAHAL FINAL FORM;Lo;0;AL;<final> 068C;;;;N;;;;;
+FB86;ARABIC LETTER DUL ISOLATED FORM;Lo;0;AL;<isolated> 068E;;;;N;;;;;
+FB87;ARABIC LETTER DUL FINAL FORM;Lo;0;AL;<final> 068E;;;;N;;;;;
+FB88;ARABIC LETTER DDAL ISOLATED FORM;Lo;0;AL;<isolated> 0688;;;;N;;;;;
+FB89;ARABIC LETTER DDAL FINAL FORM;Lo;0;AL;<final> 0688;;;;N;;;;;
+FB8A;ARABIC LETTER JEH ISOLATED FORM;Lo;0;AL;<isolated> 0698;;;;N;;;;;
+FB8B;ARABIC LETTER JEH FINAL FORM;Lo;0;AL;<final> 0698;;;;N;;;;;
+FB8C;ARABIC LETTER RREH ISOLATED FORM;Lo;0;AL;<isolated> 0691;;;;N;;;;;
+FB8D;ARABIC LETTER RREH FINAL FORM;Lo;0;AL;<final> 0691;;;;N;;;;;
+FB8E;ARABIC LETTER KEHEH ISOLATED FORM;Lo;0;AL;<isolated> 06A9;;;;N;;;;;
+FB8F;ARABIC LETTER KEHEH FINAL FORM;Lo;0;AL;<final> 06A9;;;;N;;;;;
+FB90;ARABIC LETTER KEHEH INITIAL FORM;Lo;0;AL;<initial> 06A9;;;;N;;;;;
+FB91;ARABIC LETTER KEHEH MEDIAL FORM;Lo;0;AL;<medial> 06A9;;;;N;;;;;
+FB92;ARABIC LETTER GAF ISOLATED FORM;Lo;0;AL;<isolated> 06AF;;;;N;;;;;
+FB93;ARABIC LETTER GAF FINAL FORM;Lo;0;AL;<final> 06AF;;;;N;;;;;
+FB94;ARABIC LETTER GAF INITIAL FORM;Lo;0;AL;<initial> 06AF;;;;N;;;;;
+FB95;ARABIC LETTER GAF MEDIAL FORM;Lo;0;AL;<medial> 06AF;;;;N;;;;;
+FB96;ARABIC LETTER GUEH ISOLATED FORM;Lo;0;AL;<isolated> 06B3;;;;N;;;;;
+FB97;ARABIC LETTER GUEH FINAL FORM;Lo;0;AL;<final> 06B3;;;;N;;;;;
+FB98;ARABIC LETTER GUEH INITIAL FORM;Lo;0;AL;<initial> 06B3;;;;N;;;;;
+FB99;ARABIC LETTER GUEH MEDIAL FORM;Lo;0;AL;<medial> 06B3;;;;N;;;;;
+FB9A;ARABIC LETTER NGOEH ISOLATED FORM;Lo;0;AL;<isolated> 06B1;;;;N;;;;;
+FB9B;ARABIC LETTER NGOEH FINAL FORM;Lo;0;AL;<final> 06B1;;;;N;;;;;
+FB9C;ARABIC LETTER NGOEH INITIAL FORM;Lo;0;AL;<initial> 06B1;;;;N;;;;;
+FB9D;ARABIC LETTER NGOEH MEDIAL FORM;Lo;0;AL;<medial> 06B1;;;;N;;;;;
+FB9E;ARABIC LETTER NOON GHUNNA ISOLATED FORM;Lo;0;AL;<isolated> 06BA;;;;N;;;;;
+FB9F;ARABIC LETTER NOON GHUNNA FINAL FORM;Lo;0;AL;<final> 06BA;;;;N;;;;;
+FBA0;ARABIC LETTER RNOON ISOLATED FORM;Lo;0;AL;<isolated> 06BB;;;;N;;;;;
+FBA1;ARABIC LETTER RNOON FINAL FORM;Lo;0;AL;<final> 06BB;;;;N;;;;;
+FBA2;ARABIC LETTER RNOON INITIAL FORM;Lo;0;AL;<initial> 06BB;;;;N;;;;;
+FBA3;ARABIC LETTER RNOON MEDIAL FORM;Lo;0;AL;<medial> 06BB;;;;N;;;;;
+FBA4;ARABIC LETTER HEH WITH YEH ABOVE ISOLATED FORM;Lo;0;AL;<isolated> 06C0;;;;N;;;;;
+FBA5;ARABIC LETTER HEH WITH YEH ABOVE FINAL FORM;Lo;0;AL;<final> 06C0;;;;N;;;;;
+FBA6;ARABIC LETTER HEH GOAL ISOLATED FORM;Lo;0;AL;<isolated> 06C1;;;;N;;;;;
+FBA7;ARABIC LETTER HEH GOAL FINAL FORM;Lo;0;AL;<final> 06C1;;;;N;;;;;
+FBA8;ARABIC LETTER HEH GOAL INITIAL FORM;Lo;0;AL;<initial> 06C1;;;;N;;;;;
+FBA9;ARABIC LETTER HEH GOAL MEDIAL FORM;Lo;0;AL;<medial> 06C1;;;;N;;;;;
+FBAA;ARABIC LETTER HEH DOACHASHMEE ISOLATED FORM;Lo;0;AL;<isolated> 06BE;;;;N;;;;;
+FBAB;ARABIC LETTER HEH DOACHASHMEE FINAL FORM;Lo;0;AL;<final> 06BE;;;;N;;;;;
+FBAC;ARABIC LETTER HEH DOACHASHMEE INITIAL FORM;Lo;0;AL;<initial> 06BE;;;;N;;;;;
+FBAD;ARABIC LETTER HEH DOACHASHMEE MEDIAL FORM;Lo;0;AL;<medial> 06BE;;;;N;;;;;
+FBAE;ARABIC LETTER YEH BARREE ISOLATED FORM;Lo;0;AL;<isolated> 06D2;;;;N;;;;;
+FBAF;ARABIC LETTER YEH BARREE FINAL FORM;Lo;0;AL;<final> 06D2;;;;N;;;;;
+FBB0;ARABIC LETTER YEH BARREE WITH HAMZA ABOVE ISOLATED FORM;Lo;0;AL;<isolated> 06D3;;;;N;;;;;
+FBB1;ARABIC LETTER YEH BARREE WITH HAMZA ABOVE FINAL FORM;Lo;0;AL;<final> 06D3;;;;N;;;;;
+FBD3;ARABIC LETTER NG ISOLATED FORM;Lo;0;AL;<isolated> 06AD;;;;N;;;;;
+FBD4;ARABIC LETTER NG FINAL FORM;Lo;0;AL;<final> 06AD;;;;N;;;;;
+FBD5;ARABIC LETTER NG INITIAL FORM;Lo;0;AL;<initial> 06AD;;;;N;;;;;
+FBD6;ARABIC LETTER NG MEDIAL FORM;Lo;0;AL;<medial> 06AD;;;;N;;;;;
+FBD7;ARABIC LETTER U ISOLATED FORM;Lo;0;AL;<isolated> 06C7;;;;N;;;;;
+FBD8;ARABIC LETTER U FINAL FORM;Lo;0;AL;<final> 06C7;;;;N;;;;;
+FBD9;ARABIC LETTER OE ISOLATED FORM;Lo;0;AL;<isolated> 06C6;;;;N;;;;;
+FBDA;ARABIC LETTER OE FINAL FORM;Lo;0;AL;<final> 06C6;;;;N;;;;;
+FBDB;ARABIC LETTER YU ISOLATED FORM;Lo;0;AL;<isolated> 06C8;;;;N;;;;;
+FBDC;ARABIC LETTER YU FINAL FORM;Lo;0;AL;<final> 06C8;;;;N;;;;;
+FBDD;ARABIC LETTER U WITH HAMZA ABOVE ISOLATED FORM;Lo;0;AL;<isolated> 0677;;;;N;;;;;
+FBDE;ARABIC LETTER VE ISOLATED FORM;Lo;0;AL;<isolated> 06CB;;;;N;;;;;
+FBDF;ARABIC LETTER VE FINAL FORM;Lo;0;AL;<final> 06CB;;;;N;;;;;
+FBE0;ARABIC LETTER KIRGHIZ OE ISOLATED FORM;Lo;0;AL;<isolated> 06C5;;;;N;;;;;
+FBE1;ARABIC LETTER KIRGHIZ OE FINAL FORM;Lo;0;AL;<final> 06C5;;;;N;;;;;
+FBE2;ARABIC LETTER KIRGHIZ YU ISOLATED FORM;Lo;0;AL;<isolated> 06C9;;;;N;;;;;
+FBE3;ARABIC LETTER KIRGHIZ YU FINAL FORM;Lo;0;AL;<final> 06C9;;;;N;;;;;
+FBE4;ARABIC LETTER E ISOLATED FORM;Lo;0;AL;<isolated> 06D0;;;;N;;;;;
+FBE5;ARABIC LETTER E FINAL FORM;Lo;0;AL;<final> 06D0;;;;N;;;;;
+FBE6;ARABIC LETTER E INITIAL FORM;Lo;0;AL;<initial> 06D0;;;;N;;;;;
+FBE7;ARABIC LETTER E MEDIAL FORM;Lo;0;AL;<medial> 06D0;;;;N;;;;;
+FBE8;ARABIC LETTER UIGHUR KAZAKH KIRGHIZ ALEF MAKSURA INITIAL FORM;Lo;0;AL;<initial> 0649;;;;N;;;;;
+FBE9;ARABIC LETTER UIGHUR KAZAKH KIRGHIZ ALEF MAKSURA MEDIAL FORM;Lo;0;AL;<medial> 0649;;;;N;;;;;
+FBEA;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ALEF ISOLATED FORM;Lo;0;AL;<isolated> 0626 0627;;;;N;;;;;
+FBEB;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ALEF FINAL FORM;Lo;0;AL;<final> 0626 0627;;;;N;;;;;
+FBEC;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH AE ISOLATED FORM;Lo;0;AL;<isolated> 0626 06D5;;;;N;;;;;
+FBED;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH AE FINAL FORM;Lo;0;AL;<final> 0626 06D5;;;;N;;;;;
+FBEE;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH WAW ISOLATED FORM;Lo;0;AL;<isolated> 0626 0648;;;;N;;;;;
+FBEF;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH WAW FINAL FORM;Lo;0;AL;<final> 0626 0648;;;;N;;;;;
+FBF0;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH U ISOLATED FORM;Lo;0;AL;<isolated> 0626 06C7;;;;N;;;;;
+FBF1;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH U FINAL FORM;Lo;0;AL;<final> 0626 06C7;;;;N;;;;;
+FBF2;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH OE ISOLATED FORM;Lo;0;AL;<isolated> 0626 06C6;;;;N;;;;;
+FBF3;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH OE FINAL FORM;Lo;0;AL;<final> 0626 06C6;;;;N;;;;;
+FBF4;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH YU ISOLATED FORM;Lo;0;AL;<isolated> 0626 06C8;;;;N;;;;;
+FBF5;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH YU FINAL FORM;Lo;0;AL;<final> 0626 06C8;;;;N;;;;;
+FBF6;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH E ISOLATED FORM;Lo;0;AL;<isolated> 0626 06D0;;;;N;;;;;
+FBF7;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH E FINAL FORM;Lo;0;AL;<final> 0626 06D0;;;;N;;;;;
+FBF8;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH E INITIAL FORM;Lo;0;AL;<initial> 0626 06D0;;;;N;;;;;
+FBF9;ARABIC LIGATURE UIGHUR KIRGHIZ YEH WITH HAMZA ABOVE WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0626 0649;;;;N;;;;;
+FBFA;ARABIC LIGATURE UIGHUR KIRGHIZ YEH WITH HAMZA ABOVE WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0626 0649;;;;N;;;;;
+FBFB;ARABIC LIGATURE UIGHUR KIRGHIZ YEH WITH HAMZA ABOVE WITH ALEF MAKSURA INITIAL FORM;Lo;0;AL;<initial> 0626 0649;;;;N;;;;;
+FBFC;ARABIC LETTER FARSI YEH ISOLATED FORM;Lo;0;AL;<isolated> 06CC;;;;N;;;;;
+FBFD;ARABIC LETTER FARSI YEH FINAL FORM;Lo;0;AL;<final> 06CC;;;;N;;;;;
+FBFE;ARABIC LETTER FARSI YEH INITIAL FORM;Lo;0;AL;<initial> 06CC;;;;N;;;;;
+FBFF;ARABIC LETTER FARSI YEH MEDIAL FORM;Lo;0;AL;<medial> 06CC;;;;N;;;;;
+FC00;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 0626 062C;;;;N;;;;;
+FC01;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0626 062D;;;;N;;;;;
+FC02;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0626 0645;;;;N;;;;;
+FC03;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0626 0649;;;;N;;;;;
+FC04;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0626 064A;;;;N;;;;;
+FC05;ARABIC LIGATURE BEH WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 0628 062C;;;;N;;;;;
+FC06;ARABIC LIGATURE BEH WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0628 062D;;;;N;;;;;
+FC07;ARABIC LIGATURE BEH WITH KHAH ISOLATED FORM;Lo;0;AL;<isolated> 0628 062E;;;;N;;;;;
+FC08;ARABIC LIGATURE BEH WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0628 0645;;;;N;;;;;
+FC09;ARABIC LIGATURE BEH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0628 0649;;;;N;;;;;
+FC0A;ARABIC LIGATURE BEH WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0628 064A;;;;N;;;;;
+FC0B;ARABIC LIGATURE TEH WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 062A 062C;;;;N;;;;;
+FC0C;ARABIC LIGATURE TEH WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 062A 062D;;;;N;;;;;
+FC0D;ARABIC LIGATURE TEH WITH KHAH ISOLATED FORM;Lo;0;AL;<isolated> 062A 062E;;;;N;;;;;
+FC0E;ARABIC LIGATURE TEH WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 062A 0645;;;;N;;;;;
+FC0F;ARABIC LIGATURE TEH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 062A 0649;;;;N;;;;;
+FC10;ARABIC LIGATURE TEH WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 062A 064A;;;;N;;;;;
+FC11;ARABIC LIGATURE THEH WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 062B 062C;;;;N;;;;;
+FC12;ARABIC LIGATURE THEH WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 062B 0645;;;;N;;;;;
+FC13;ARABIC LIGATURE THEH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 062B 0649;;;;N;;;;;
+FC14;ARABIC LIGATURE THEH WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 062B 064A;;;;N;;;;;
+FC15;ARABIC LIGATURE JEEM WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 062C 062D;;;;N;;;;;
+FC16;ARABIC LIGATURE JEEM WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 062C 0645;;;;N;;;;;
+FC17;ARABIC LIGATURE HAH WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 062D 062C;;;;N;;;;;
+FC18;ARABIC LIGATURE HAH WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 062D 0645;;;;N;;;;;
+FC19;ARABIC LIGATURE KHAH WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 062E 062C;;;;N;;;;;
+FC1A;ARABIC LIGATURE KHAH WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 062E 062D;;;;N;;;;;
+FC1B;ARABIC LIGATURE KHAH WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 062E 0645;;;;N;;;;;
+FC1C;ARABIC LIGATURE SEEN WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 0633 062C;;;;N;;;;;
+FC1D;ARABIC LIGATURE SEEN WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0633 062D;;;;N;;;;;
+FC1E;ARABIC LIGATURE SEEN WITH KHAH ISOLATED FORM;Lo;0;AL;<isolated> 0633 062E;;;;N;;;;;
+FC1F;ARABIC LIGATURE SEEN WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0633 0645;;;;N;;;;;
+FC20;ARABIC LIGATURE SAD WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0635 062D;;;;N;;;;;
+FC21;ARABIC LIGATURE SAD WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0635 0645;;;;N;;;;;
+FC22;ARABIC LIGATURE DAD WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 0636 062C;;;;N;;;;;
+FC23;ARABIC LIGATURE DAD WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0636 062D;;;;N;;;;;
+FC24;ARABIC LIGATURE DAD WITH KHAH ISOLATED FORM;Lo;0;AL;<isolated> 0636 062E;;;;N;;;;;
+FC25;ARABIC LIGATURE DAD WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0636 0645;;;;N;;;;;
+FC26;ARABIC LIGATURE TAH WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0637 062D;;;;N;;;;;
+FC27;ARABIC LIGATURE TAH WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0637 0645;;;;N;;;;;
+FC28;ARABIC LIGATURE ZAH WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0638 0645;;;;N;;;;;
+FC29;ARABIC LIGATURE AIN WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 0639 062C;;;;N;;;;;
+FC2A;ARABIC LIGATURE AIN WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0639 0645;;;;N;;;;;
+FC2B;ARABIC LIGATURE GHAIN WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 063A 062C;;;;N;;;;;
+FC2C;ARABIC LIGATURE GHAIN WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 063A 0645;;;;N;;;;;
+FC2D;ARABIC LIGATURE FEH WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 0641 062C;;;;N;;;;;
+FC2E;ARABIC LIGATURE FEH WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0641 062D;;;;N;;;;;
+FC2F;ARABIC LIGATURE FEH WITH KHAH ISOLATED FORM;Lo;0;AL;<isolated> 0641 062E;;;;N;;;;;
+FC30;ARABIC LIGATURE FEH WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0641 0645;;;;N;;;;;
+FC31;ARABIC LIGATURE FEH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0641 0649;;;;N;;;;;
+FC32;ARABIC LIGATURE FEH WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0641 064A;;;;N;;;;;
+FC33;ARABIC LIGATURE QAF WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0642 062D;;;;N;;;;;
+FC34;ARABIC LIGATURE QAF WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0642 0645;;;;N;;;;;
+FC35;ARABIC LIGATURE QAF WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0642 0649;;;;N;;;;;
+FC36;ARABIC LIGATURE QAF WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0642 064A;;;;N;;;;;
+FC37;ARABIC LIGATURE KAF WITH ALEF ISOLATED FORM;Lo;0;AL;<isolated> 0643 0627;;;;N;;;;;
+FC38;ARABIC LIGATURE KAF WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 0643 062C;;;;N;;;;;
+FC39;ARABIC LIGATURE KAF WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0643 062D;;;;N;;;;;
+FC3A;ARABIC LIGATURE KAF WITH KHAH ISOLATED FORM;Lo;0;AL;<isolated> 0643 062E;;;;N;;;;;
+FC3B;ARABIC LIGATURE KAF WITH LAM ISOLATED FORM;Lo;0;AL;<isolated> 0643 0644;;;;N;;;;;
+FC3C;ARABIC LIGATURE KAF WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0643 0645;;;;N;;;;;
+FC3D;ARABIC LIGATURE KAF WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0643 0649;;;;N;;;;;
+FC3E;ARABIC LIGATURE KAF WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0643 064A;;;;N;;;;;
+FC3F;ARABIC LIGATURE LAM WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 0644 062C;;;;N;;;;;
+FC40;ARABIC LIGATURE LAM WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0644 062D;;;;N;;;;;
+FC41;ARABIC LIGATURE LAM WITH KHAH ISOLATED FORM;Lo;0;AL;<isolated> 0644 062E;;;;N;;;;;
+FC42;ARABIC LIGATURE LAM WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0644 0645;;;;N;;;;;
+FC43;ARABIC LIGATURE LAM WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0644 0649;;;;N;;;;;
+FC44;ARABIC LIGATURE LAM WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0644 064A;;;;N;;;;;
+FC45;ARABIC LIGATURE MEEM WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 0645 062C;;;;N;;;;;
+FC46;ARABIC LIGATURE MEEM WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0645 062D;;;;N;;;;;
+FC47;ARABIC LIGATURE MEEM WITH KHAH ISOLATED FORM;Lo;0;AL;<isolated> 0645 062E;;;;N;;;;;
+FC48;ARABIC LIGATURE MEEM WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0645 0645;;;;N;;;;;
+FC49;ARABIC LIGATURE MEEM WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0645 0649;;;;N;;;;;
+FC4A;ARABIC LIGATURE MEEM WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0645 064A;;;;N;;;;;
+FC4B;ARABIC LIGATURE NOON WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 0646 062C;;;;N;;;;;
+FC4C;ARABIC LIGATURE NOON WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0646 062D;;;;N;;;;;
+FC4D;ARABIC LIGATURE NOON WITH KHAH ISOLATED FORM;Lo;0;AL;<isolated> 0646 062E;;;;N;;;;;
+FC4E;ARABIC LIGATURE NOON WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0646 0645;;;;N;;;;;
+FC4F;ARABIC LIGATURE NOON WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0646 0649;;;;N;;;;;
+FC50;ARABIC LIGATURE NOON WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0646 064A;;;;N;;;;;
+FC51;ARABIC LIGATURE HEH WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 0647 062C;;;;N;;;;;
+FC52;ARABIC LIGATURE HEH WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0647 0645;;;;N;;;;;
+FC53;ARABIC LIGATURE HEH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0647 0649;;;;N;;;;;
+FC54;ARABIC LIGATURE HEH WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0647 064A;;;;N;;;;;
+FC55;ARABIC LIGATURE YEH WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 064A 062C;;;;N;;;;;
+FC56;ARABIC LIGATURE YEH WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 064A 062D;;;;N;;;;;
+FC57;ARABIC LIGATURE YEH WITH KHAH ISOLATED FORM;Lo;0;AL;<isolated> 064A 062E;;;;N;;;;;
+FC58;ARABIC LIGATURE YEH WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 064A 0645;;;;N;;;;;
+FC59;ARABIC LIGATURE YEH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 064A 0649;;;;N;;;;;
+FC5A;ARABIC LIGATURE YEH WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 064A 064A;;;;N;;;;;
+FC5B;ARABIC LIGATURE THAL WITH SUPERSCRIPT ALEF ISOLATED FORM;Lo;0;AL;<isolated> 0630 0670;;;;N;;;;;
+FC5C;ARABIC LIGATURE REH WITH SUPERSCRIPT ALEF ISOLATED FORM;Lo;0;AL;<isolated> 0631 0670;;;;N;;;;;
+FC5D;ARABIC LIGATURE ALEF MAKSURA WITH SUPERSCRIPT ALEF ISOLATED FORM;Lo;0;AL;<isolated> 0649 0670;;;;N;;;;;
+FC5E;ARABIC LIGATURE SHADDA WITH DAMMATAN ISOLATED FORM;Lo;0;AL;<isolated> 0020 064C 0651;;;;N;;;;;
+FC5F;ARABIC LIGATURE SHADDA WITH KASRATAN ISOLATED FORM;Lo;0;AL;<isolated> 0020 064D 0651;;;;N;;;;;
+FC60;ARABIC LIGATURE SHADDA WITH FATHA ISOLATED FORM;Lo;0;AL;<isolated> 0020 064E 0651;;;;N;;;;;
+FC61;ARABIC LIGATURE SHADDA WITH DAMMA ISOLATED FORM;Lo;0;AL;<isolated> 0020 064F 0651;;;;N;;;;;
+FC62;ARABIC LIGATURE SHADDA WITH KASRA ISOLATED FORM;Lo;0;AL;<isolated> 0020 0650 0651;;;;N;;;;;
+FC63;ARABIC LIGATURE SHADDA WITH SUPERSCRIPT ALEF ISOLATED FORM;Lo;0;AL;<isolated> 0020 0651 0670;;;;N;;;;;
+FC64;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH REH FINAL FORM;Lo;0;AL;<final> 0626 0631;;;;N;;;;;
+FC65;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ZAIN FINAL FORM;Lo;0;AL;<final> 0626 0632;;;;N;;;;;
+FC66;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH MEEM FINAL FORM;Lo;0;AL;<final> 0626 0645;;;;N;;;;;
+FC67;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH NOON FINAL FORM;Lo;0;AL;<final> 0626 0646;;;;N;;;;;
+FC68;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0626 0649;;;;N;;;;;
+FC69;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH YEH FINAL FORM;Lo;0;AL;<final> 0626 064A;;;;N;;;;;
+FC6A;ARABIC LIGATURE BEH WITH REH FINAL FORM;Lo;0;AL;<final> 0628 0631;;;;N;;;;;
+FC6B;ARABIC LIGATURE BEH WITH ZAIN FINAL FORM;Lo;0;AL;<final> 0628 0632;;;;N;;;;;
+FC6C;ARABIC LIGATURE BEH WITH MEEM FINAL FORM;Lo;0;AL;<final> 0628 0645;;;;N;;;;;
+FC6D;ARABIC LIGATURE BEH WITH NOON FINAL FORM;Lo;0;AL;<final> 0628 0646;;;;N;;;;;
+FC6E;ARABIC LIGATURE BEH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0628 0649;;;;N;;;;;
+FC6F;ARABIC LIGATURE BEH WITH YEH FINAL FORM;Lo;0;AL;<final> 0628 064A;;;;N;;;;;
+FC70;ARABIC LIGATURE TEH WITH REH FINAL FORM;Lo;0;AL;<final> 062A 0631;;;;N;;;;;
+FC71;ARABIC LIGATURE TEH WITH ZAIN FINAL FORM;Lo;0;AL;<final> 062A 0632;;;;N;;;;;
+FC72;ARABIC LIGATURE TEH WITH MEEM FINAL FORM;Lo;0;AL;<final> 062A 0645;;;;N;;;;;
+FC73;ARABIC LIGATURE TEH WITH NOON FINAL FORM;Lo;0;AL;<final> 062A 0646;;;;N;;;;;
+FC74;ARABIC LIGATURE TEH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 062A 0649;;;;N;;;;;
+FC75;ARABIC LIGATURE TEH WITH YEH FINAL FORM;Lo;0;AL;<final> 062A 064A;;;;N;;;;;
+FC76;ARABIC LIGATURE THEH WITH REH FINAL FORM;Lo;0;AL;<final> 062B 0631;;;;N;;;;;
+FC77;ARABIC LIGATURE THEH WITH ZAIN FINAL FORM;Lo;0;AL;<final> 062B 0632;;;;N;;;;;
+FC78;ARABIC LIGATURE THEH WITH MEEM FINAL FORM;Lo;0;AL;<final> 062B 0645;;;;N;;;;;
+FC79;ARABIC LIGATURE THEH WITH NOON FINAL FORM;Lo;0;AL;<final> 062B 0646;;;;N;;;;;
+FC7A;ARABIC LIGATURE THEH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 062B 0649;;;;N;;;;;
+FC7B;ARABIC LIGATURE THEH WITH YEH FINAL FORM;Lo;0;AL;<final> 062B 064A;;;;N;;;;;
+FC7C;ARABIC LIGATURE FEH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0641 0649;;;;N;;;;;
+FC7D;ARABIC LIGATURE FEH WITH YEH FINAL FORM;Lo;0;AL;<final> 0641 064A;;;;N;;;;;
+FC7E;ARABIC LIGATURE QAF WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0642 0649;;;;N;;;;;
+FC7F;ARABIC LIGATURE QAF WITH YEH FINAL FORM;Lo;0;AL;<final> 0642 064A;;;;N;;;;;
+FC80;ARABIC LIGATURE KAF WITH ALEF FINAL FORM;Lo;0;AL;<final> 0643 0627;;;;N;;;;;
+FC81;ARABIC LIGATURE KAF WITH LAM FINAL FORM;Lo;0;AL;<final> 0643 0644;;;;N;;;;;
+FC82;ARABIC LIGATURE KAF WITH MEEM FINAL FORM;Lo;0;AL;<final> 0643 0645;;;;N;;;;;
+FC83;ARABIC LIGATURE KAF WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0643 0649;;;;N;;;;;
+FC84;ARABIC LIGATURE KAF WITH YEH FINAL FORM;Lo;0;AL;<final> 0643 064A;;;;N;;;;;
+FC85;ARABIC LIGATURE LAM WITH MEEM FINAL FORM;Lo;0;AL;<final> 0644 0645;;;;N;;;;;
+FC86;ARABIC LIGATURE LAM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0644 0649;;;;N;;;;;
+FC87;ARABIC LIGATURE LAM WITH YEH FINAL FORM;Lo;0;AL;<final> 0644 064A;;;;N;;;;;
+FC88;ARABIC LIGATURE MEEM WITH ALEF FINAL FORM;Lo;0;AL;<final> 0645 0627;;;;N;;;;;
+FC89;ARABIC LIGATURE MEEM WITH MEEM FINAL FORM;Lo;0;AL;<final> 0645 0645;;;;N;;;;;
+FC8A;ARABIC LIGATURE NOON WITH REH FINAL FORM;Lo;0;AL;<final> 0646 0631;;;;N;;;;;
+FC8B;ARABIC LIGATURE NOON WITH ZAIN FINAL FORM;Lo;0;AL;<final> 0646 0632;;;;N;;;;;
+FC8C;ARABIC LIGATURE NOON WITH MEEM FINAL FORM;Lo;0;AL;<final> 0646 0645;;;;N;;;;;
+FC8D;ARABIC LIGATURE NOON WITH NOON FINAL FORM;Lo;0;AL;<final> 0646 0646;;;;N;;;;;
+FC8E;ARABIC LIGATURE NOON WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0646 0649;;;;N;;;;;
+FC8F;ARABIC LIGATURE NOON WITH YEH FINAL FORM;Lo;0;AL;<final> 0646 064A;;;;N;;;;;
+FC90;ARABIC LIGATURE ALEF MAKSURA WITH SUPERSCRIPT ALEF FINAL FORM;Lo;0;AL;<final> 0649 0670;;;;N;;;;;
+FC91;ARABIC LIGATURE YEH WITH REH FINAL FORM;Lo;0;AL;<final> 064A 0631;;;;N;;;;;
+FC92;ARABIC LIGATURE YEH WITH ZAIN FINAL FORM;Lo;0;AL;<final> 064A 0632;;;;N;;;;;
+FC93;ARABIC LIGATURE YEH WITH MEEM FINAL FORM;Lo;0;AL;<final> 064A 0645;;;;N;;;;;
+FC94;ARABIC LIGATURE YEH WITH NOON FINAL FORM;Lo;0;AL;<final> 064A 0646;;;;N;;;;;
+FC95;ARABIC LIGATURE YEH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 064A 0649;;;;N;;;;;
+FC96;ARABIC LIGATURE YEH WITH YEH FINAL FORM;Lo;0;AL;<final> 064A 064A;;;;N;;;;;
+FC97;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0626 062C;;;;N;;;;;
+FC98;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0626 062D;;;;N;;;;;
+FC99;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0626 062E;;;;N;;;;;
+FC9A;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0626 0645;;;;N;;;;;
+FC9B;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH HEH INITIAL FORM;Lo;0;AL;<initial> 0626 0647;;;;N;;;;;
+FC9C;ARABIC LIGATURE BEH WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0628 062C;;;;N;;;;;
+FC9D;ARABIC LIGATURE BEH WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0628 062D;;;;N;;;;;
+FC9E;ARABIC LIGATURE BEH WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0628 062E;;;;N;;;;;
+FC9F;ARABIC LIGATURE BEH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0628 0645;;;;N;;;;;
+FCA0;ARABIC LIGATURE BEH WITH HEH INITIAL FORM;Lo;0;AL;<initial> 0628 0647;;;;N;;;;;
+FCA1;ARABIC LIGATURE TEH WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 062A 062C;;;;N;;;;;
+FCA2;ARABIC LIGATURE TEH WITH HAH INITIAL FORM;Lo;0;AL;<initial> 062A 062D;;;;N;;;;;
+FCA3;ARABIC LIGATURE TEH WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 062A 062E;;;;N;;;;;
+FCA4;ARABIC LIGATURE TEH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 062A 0645;;;;N;;;;;
+FCA5;ARABIC LIGATURE TEH WITH HEH INITIAL FORM;Lo;0;AL;<initial> 062A 0647;;;;N;;;;;
+FCA6;ARABIC LIGATURE THEH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 062B 0645;;;;N;;;;;
+FCA7;ARABIC LIGATURE JEEM WITH HAH INITIAL FORM;Lo;0;AL;<initial> 062C 062D;;;;N;;;;;
+FCA8;ARABIC LIGATURE JEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 062C 0645;;;;N;;;;;
+FCA9;ARABIC LIGATURE HAH WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 062D 062C;;;;N;;;;;
+FCAA;ARABIC LIGATURE HAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 062D 0645;;;;N;;;;;
+FCAB;ARABIC LIGATURE KHAH WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 062E 062C;;;;N;;;;;
+FCAC;ARABIC LIGATURE KHAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 062E 0645;;;;N;;;;;
+FCAD;ARABIC LIGATURE SEEN WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0633 062C;;;;N;;;;;
+FCAE;ARABIC LIGATURE SEEN WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0633 062D;;;;N;;;;;
+FCAF;ARABIC LIGATURE SEEN WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0633 062E;;;;N;;;;;
+FCB0;ARABIC LIGATURE SEEN WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0633 0645;;;;N;;;;;
+FCB1;ARABIC LIGATURE SAD WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0635 062D;;;;N;;;;;
+FCB2;ARABIC LIGATURE SAD WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0635 062E;;;;N;;;;;
+FCB3;ARABIC LIGATURE SAD WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0635 0645;;;;N;;;;;
+FCB4;ARABIC LIGATURE DAD WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0636 062C;;;;N;;;;;
+FCB5;ARABIC LIGATURE DAD WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0636 062D;;;;N;;;;;
+FCB6;ARABIC LIGATURE DAD WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0636 062E;;;;N;;;;;
+FCB7;ARABIC LIGATURE DAD WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0636 0645;;;;N;;;;;
+FCB8;ARABIC LIGATURE TAH WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0637 062D;;;;N;;;;;
+FCB9;ARABIC LIGATURE ZAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0638 0645;;;;N;;;;;
+FCBA;ARABIC LIGATURE AIN WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0639 062C;;;;N;;;;;
+FCBB;ARABIC LIGATURE AIN WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0639 0645;;;;N;;;;;
+FCBC;ARABIC LIGATURE GHAIN WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 063A 062C;;;;N;;;;;
+FCBD;ARABIC LIGATURE GHAIN WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 063A 0645;;;;N;;;;;
+FCBE;ARABIC LIGATURE FEH WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0641 062C;;;;N;;;;;
+FCBF;ARABIC LIGATURE FEH WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0641 062D;;;;N;;;;;
+FCC0;ARABIC LIGATURE FEH WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0641 062E;;;;N;;;;;
+FCC1;ARABIC LIGATURE FEH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0641 0645;;;;N;;;;;
+FCC2;ARABIC LIGATURE QAF WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0642 062D;;;;N;;;;;
+FCC3;ARABIC LIGATURE QAF WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0642 0645;;;;N;;;;;
+FCC4;ARABIC LIGATURE KAF WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0643 062C;;;;N;;;;;
+FCC5;ARABIC LIGATURE KAF WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0643 062D;;;;N;;;;;
+FCC6;ARABIC LIGATURE KAF WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0643 062E;;;;N;;;;;
+FCC7;ARABIC LIGATURE KAF WITH LAM INITIAL FORM;Lo;0;AL;<initial> 0643 0644;;;;N;;;;;
+FCC8;ARABIC LIGATURE KAF WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0643 0645;;;;N;;;;;
+FCC9;ARABIC LIGATURE LAM WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0644 062C;;;;N;;;;;
+FCCA;ARABIC LIGATURE LAM WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0644 062D;;;;N;;;;;
+FCCB;ARABIC LIGATURE LAM WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0644 062E;;;;N;;;;;
+FCCC;ARABIC LIGATURE LAM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0644 0645;;;;N;;;;;
+FCCD;ARABIC LIGATURE LAM WITH HEH INITIAL FORM;Lo;0;AL;<initial> 0644 0647;;;;N;;;;;
+FCCE;ARABIC LIGATURE MEEM WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0645 062C;;;;N;;;;;
+FCCF;ARABIC LIGATURE MEEM WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0645 062D;;;;N;;;;;
+FCD0;ARABIC LIGATURE MEEM WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0645 062E;;;;N;;;;;
+FCD1;ARABIC LIGATURE MEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0645 0645;;;;N;;;;;
+FCD2;ARABIC LIGATURE NOON WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0646 062C;;;;N;;;;;
+FCD3;ARABIC LIGATURE NOON WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0646 062D;;;;N;;;;;
+FCD4;ARABIC LIGATURE NOON WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0646 062E;;;;N;;;;;
+FCD5;ARABIC LIGATURE NOON WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0646 0645;;;;N;;;;;
+FCD6;ARABIC LIGATURE NOON WITH HEH INITIAL FORM;Lo;0;AL;<initial> 0646 0647;;;;N;;;;;
+FCD7;ARABIC LIGATURE HEH WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0647 062C;;;;N;;;;;
+FCD8;ARABIC LIGATURE HEH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0647 0645;;;;N;;;;;
+FCD9;ARABIC LIGATURE HEH WITH SUPERSCRIPT ALEF INITIAL FORM;Lo;0;AL;<initial> 0647 0670;;;;N;;;;;
+FCDA;ARABIC LIGATURE YEH WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 064A 062C;;;;N;;;;;
+FCDB;ARABIC LIGATURE YEH WITH HAH INITIAL FORM;Lo;0;AL;<initial> 064A 062D;;;;N;;;;;
+FCDC;ARABIC LIGATURE YEH WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 064A 062E;;;;N;;;;;
+FCDD;ARABIC LIGATURE YEH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 064A 0645;;;;N;;;;;
+FCDE;ARABIC LIGATURE YEH WITH HEH INITIAL FORM;Lo;0;AL;<initial> 064A 0647;;;;N;;;;;
+FCDF;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH MEEM MEDIAL FORM;Lo;0;AL;<medial> 0626 0645;;;;N;;;;;
+FCE0;ARABIC LIGATURE YEH WITH HAMZA ABOVE WITH HEH MEDIAL FORM;Lo;0;AL;<medial> 0626 0647;;;;N;;;;;
+FCE1;ARABIC LIGATURE BEH WITH MEEM MEDIAL FORM;Lo;0;AL;<medial> 0628 0645;;;;N;;;;;
+FCE2;ARABIC LIGATURE BEH WITH HEH MEDIAL FORM;Lo;0;AL;<medial> 0628 0647;;;;N;;;;;
+FCE3;ARABIC LIGATURE TEH WITH MEEM MEDIAL FORM;Lo;0;AL;<medial> 062A 0645;;;;N;;;;;
+FCE4;ARABIC LIGATURE TEH WITH HEH MEDIAL FORM;Lo;0;AL;<medial> 062A 0647;;;;N;;;;;
+FCE5;ARABIC LIGATURE THEH WITH MEEM MEDIAL FORM;Lo;0;AL;<medial> 062B 0645;;;;N;;;;;
+FCE6;ARABIC LIGATURE THEH WITH HEH MEDIAL FORM;Lo;0;AL;<medial> 062B 0647;;;;N;;;;;
+FCE7;ARABIC LIGATURE SEEN WITH MEEM MEDIAL FORM;Lo;0;AL;<medial> 0633 0645;;;;N;;;;;
+FCE8;ARABIC LIGATURE SEEN WITH HEH MEDIAL FORM;Lo;0;AL;<medial> 0633 0647;;;;N;;;;;
+FCE9;ARABIC LIGATURE SHEEN WITH MEEM MEDIAL FORM;Lo;0;AL;<medial> 0634 0645;;;;N;;;;;
+FCEA;ARABIC LIGATURE SHEEN WITH HEH MEDIAL FORM;Lo;0;AL;<medial> 0634 0647;;;;N;;;;;
+FCEB;ARABIC LIGATURE KAF WITH LAM MEDIAL FORM;Lo;0;AL;<medial> 0643 0644;;;;N;;;;;
+FCEC;ARABIC LIGATURE KAF WITH MEEM MEDIAL FORM;Lo;0;AL;<medial> 0643 0645;;;;N;;;;;
+FCED;ARABIC LIGATURE LAM WITH MEEM MEDIAL FORM;Lo;0;AL;<medial> 0644 0645;;;;N;;;;;
+FCEE;ARABIC LIGATURE NOON WITH MEEM MEDIAL FORM;Lo;0;AL;<medial> 0646 0645;;;;N;;;;;
+FCEF;ARABIC LIGATURE NOON WITH HEH MEDIAL FORM;Lo;0;AL;<medial> 0646 0647;;;;N;;;;;
+FCF0;ARABIC LIGATURE YEH WITH MEEM MEDIAL FORM;Lo;0;AL;<medial> 064A 0645;;;;N;;;;;
+FCF1;ARABIC LIGATURE YEH WITH HEH MEDIAL FORM;Lo;0;AL;<medial> 064A 0647;;;;N;;;;;
+FCF2;ARABIC LIGATURE SHADDA WITH FATHA MEDIAL FORM;Lo;0;AL;<medial> 0640 064E 0651;;;;N;;;;;
+FCF3;ARABIC LIGATURE SHADDA WITH DAMMA MEDIAL FORM;Lo;0;AL;<medial> 0640 064F 0651;;;;N;;;;;
+FCF4;ARABIC LIGATURE SHADDA WITH KASRA MEDIAL FORM;Lo;0;AL;<medial> 0640 0650 0651;;;;N;;;;;
+FCF5;ARABIC LIGATURE TAH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0637 0649;;;;N;;;;;
+FCF6;ARABIC LIGATURE TAH WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0637 064A;;;;N;;;;;
+FCF7;ARABIC LIGATURE AIN WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0639 0649;;;;N;;;;;
+FCF8;ARABIC LIGATURE AIN WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0639 064A;;;;N;;;;;
+FCF9;ARABIC LIGATURE GHAIN WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 063A 0649;;;;N;;;;;
+FCFA;ARABIC LIGATURE GHAIN WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 063A 064A;;;;N;;;;;
+FCFB;ARABIC LIGATURE SEEN WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0633 0649;;;;N;;;;;
+FCFC;ARABIC LIGATURE SEEN WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0633 064A;;;;N;;;;;
+FCFD;ARABIC LIGATURE SHEEN WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0634 0649;;;;N;;;;;
+FCFE;ARABIC LIGATURE SHEEN WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0634 064A;;;;N;;;;;
+FCFF;ARABIC LIGATURE HAH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 062D 0649;;;;N;;;;;
+FD00;ARABIC LIGATURE HAH WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 062D 064A;;;;N;;;;;
+FD01;ARABIC LIGATURE JEEM WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 062C 0649;;;;N;;;;;
+FD02;ARABIC LIGATURE JEEM WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 062C 064A;;;;N;;;;;
+FD03;ARABIC LIGATURE KHAH WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 062E 0649;;;;N;;;;;
+FD04;ARABIC LIGATURE KHAH WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 062E 064A;;;;N;;;;;
+FD05;ARABIC LIGATURE SAD WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0635 0649;;;;N;;;;;
+FD06;ARABIC LIGATURE SAD WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0635 064A;;;;N;;;;;
+FD07;ARABIC LIGATURE DAD WITH ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0636 0649;;;;N;;;;;
+FD08;ARABIC LIGATURE DAD WITH YEH ISOLATED FORM;Lo;0;AL;<isolated> 0636 064A;;;;N;;;;;
+FD09;ARABIC LIGATURE SHEEN WITH JEEM ISOLATED FORM;Lo;0;AL;<isolated> 0634 062C;;;;N;;;;;
+FD0A;ARABIC LIGATURE SHEEN WITH HAH ISOLATED FORM;Lo;0;AL;<isolated> 0634 062D;;;;N;;;;;
+FD0B;ARABIC LIGATURE SHEEN WITH KHAH ISOLATED FORM;Lo;0;AL;<isolated> 0634 062E;;;;N;;;;;
+FD0C;ARABIC LIGATURE SHEEN WITH MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0634 0645;;;;N;;;;;
+FD0D;ARABIC LIGATURE SHEEN WITH REH ISOLATED FORM;Lo;0;AL;<isolated> 0634 0631;;;;N;;;;;
+FD0E;ARABIC LIGATURE SEEN WITH REH ISOLATED FORM;Lo;0;AL;<isolated> 0633 0631;;;;N;;;;;
+FD0F;ARABIC LIGATURE SAD WITH REH ISOLATED FORM;Lo;0;AL;<isolated> 0635 0631;;;;N;;;;;
+FD10;ARABIC LIGATURE DAD WITH REH ISOLATED FORM;Lo;0;AL;<isolated> 0636 0631;;;;N;;;;;
+FD11;ARABIC LIGATURE TAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0637 0649;;;;N;;;;;
+FD12;ARABIC LIGATURE TAH WITH YEH FINAL FORM;Lo;0;AL;<final> 0637 064A;;;;N;;;;;
+FD13;ARABIC LIGATURE AIN WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0639 0649;;;;N;;;;;
+FD14;ARABIC LIGATURE AIN WITH YEH FINAL FORM;Lo;0;AL;<final> 0639 064A;;;;N;;;;;
+FD15;ARABIC LIGATURE GHAIN WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 063A 0649;;;;N;;;;;
+FD16;ARABIC LIGATURE GHAIN WITH YEH FINAL FORM;Lo;0;AL;<final> 063A 064A;;;;N;;;;;
+FD17;ARABIC LIGATURE SEEN WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0633 0649;;;;N;;;;;
+FD18;ARABIC LIGATURE SEEN WITH YEH FINAL FORM;Lo;0;AL;<final> 0633 064A;;;;N;;;;;
+FD19;ARABIC LIGATURE SHEEN WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0634 0649;;;;N;;;;;
+FD1A;ARABIC LIGATURE SHEEN WITH YEH FINAL FORM;Lo;0;AL;<final> 0634 064A;;;;N;;;;;
+FD1B;ARABIC LIGATURE HAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 062D 0649;;;;N;;;;;
+FD1C;ARABIC LIGATURE HAH WITH YEH FINAL FORM;Lo;0;AL;<final> 062D 064A;;;;N;;;;;
+FD1D;ARABIC LIGATURE JEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 062C 0649;;;;N;;;;;
+FD1E;ARABIC LIGATURE JEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 062C 064A;;;;N;;;;;
+FD1F;ARABIC LIGATURE KHAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 062E 0649;;;;N;;;;;
+FD20;ARABIC LIGATURE KHAH WITH YEH FINAL FORM;Lo;0;AL;<final> 062E 064A;;;;N;;;;;
+FD21;ARABIC LIGATURE SAD WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0635 0649;;;;N;;;;;
+FD22;ARABIC LIGATURE SAD WITH YEH FINAL FORM;Lo;0;AL;<final> 0635 064A;;;;N;;;;;
+FD23;ARABIC LIGATURE DAD WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0636 0649;;;;N;;;;;
+FD24;ARABIC LIGATURE DAD WITH YEH FINAL FORM;Lo;0;AL;<final> 0636 064A;;;;N;;;;;
+FD25;ARABIC LIGATURE SHEEN WITH JEEM FINAL FORM;Lo;0;AL;<final> 0634 062C;;;;N;;;;;
+FD26;ARABIC LIGATURE SHEEN WITH HAH FINAL FORM;Lo;0;AL;<final> 0634 062D;;;;N;;;;;
+FD27;ARABIC LIGATURE SHEEN WITH KHAH FINAL FORM;Lo;0;AL;<final> 0634 062E;;;;N;;;;;
+FD28;ARABIC LIGATURE SHEEN WITH MEEM FINAL FORM;Lo;0;AL;<final> 0634 0645;;;;N;;;;;
+FD29;ARABIC LIGATURE SHEEN WITH REH FINAL FORM;Lo;0;AL;<final> 0634 0631;;;;N;;;;;
+FD2A;ARABIC LIGATURE SEEN WITH REH FINAL FORM;Lo;0;AL;<final> 0633 0631;;;;N;;;;;
+FD2B;ARABIC LIGATURE SAD WITH REH FINAL FORM;Lo;0;AL;<final> 0635 0631;;;;N;;;;;
+FD2C;ARABIC LIGATURE DAD WITH REH FINAL FORM;Lo;0;AL;<final> 0636 0631;;;;N;;;;;
+FD2D;ARABIC LIGATURE SHEEN WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0634 062C;;;;N;;;;;
+FD2E;ARABIC LIGATURE SHEEN WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0634 062D;;;;N;;;;;
+FD2F;ARABIC LIGATURE SHEEN WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0634 062E;;;;N;;;;;
+FD30;ARABIC LIGATURE SHEEN WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0634 0645;;;;N;;;;;
+FD31;ARABIC LIGATURE SEEN WITH HEH INITIAL FORM;Lo;0;AL;<initial> 0633 0647;;;;N;;;;;
+FD32;ARABIC LIGATURE SHEEN WITH HEH INITIAL FORM;Lo;0;AL;<initial> 0634 0647;;;;N;;;;;
+FD33;ARABIC LIGATURE TAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0637 0645;;;;N;;;;;
+FD34;ARABIC LIGATURE SEEN WITH JEEM MEDIAL FORM;Lo;0;AL;<medial> 0633 062C;;;;N;;;;;
+FD35;ARABIC LIGATURE SEEN WITH HAH MEDIAL FORM;Lo;0;AL;<medial> 0633 062D;;;;N;;;;;
+FD36;ARABIC LIGATURE SEEN WITH KHAH MEDIAL FORM;Lo;0;AL;<medial> 0633 062E;;;;N;;;;;
+FD37;ARABIC LIGATURE SHEEN WITH JEEM MEDIAL FORM;Lo;0;AL;<medial> 0634 062C;;;;N;;;;;
+FD38;ARABIC LIGATURE SHEEN WITH HAH MEDIAL FORM;Lo;0;AL;<medial> 0634 062D;;;;N;;;;;
+FD39;ARABIC LIGATURE SHEEN WITH KHAH MEDIAL FORM;Lo;0;AL;<medial> 0634 062E;;;;N;;;;;
+FD3A;ARABIC LIGATURE TAH WITH MEEM MEDIAL FORM;Lo;0;AL;<medial> 0637 0645;;;;N;;;;;
+FD3B;ARABIC LIGATURE ZAH WITH MEEM MEDIAL FORM;Lo;0;AL;<medial> 0638 0645;;;;N;;;;;
+FD3C;ARABIC LIGATURE ALEF WITH FATHATAN FINAL FORM;Lo;0;AL;<final> 0627 064B;;;;N;;;;;
+FD3D;ARABIC LIGATURE ALEF WITH FATHATAN ISOLATED FORM;Lo;0;AL;<isolated> 0627 064B;;;;N;;;;;
+FD3E;ORNATE LEFT PARENTHESIS;Ps;0;ON;;;;;N;;;;;
+FD3F;ORNATE RIGHT PARENTHESIS;Pe;0;ON;;;;;N;;;;;
+FD50;ARABIC LIGATURE TEH WITH JEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 062A 062C 0645;;;;N;;;;;
+FD51;ARABIC LIGATURE TEH WITH HAH WITH JEEM FINAL FORM;Lo;0;AL;<final> 062A 062D 062C;;;;N;;;;;
+FD52;ARABIC LIGATURE TEH WITH HAH WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 062A 062D 062C;;;;N;;;;;
+FD53;ARABIC LIGATURE TEH WITH HAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 062A 062D 0645;;;;N;;;;;
+FD54;ARABIC LIGATURE TEH WITH KHAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 062A 062E 0645;;;;N;;;;;
+FD55;ARABIC LIGATURE TEH WITH MEEM WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 062A 0645 062C;;;;N;;;;;
+FD56;ARABIC LIGATURE TEH WITH MEEM WITH HAH INITIAL FORM;Lo;0;AL;<initial> 062A 0645 062D;;;;N;;;;;
+FD57;ARABIC LIGATURE TEH WITH MEEM WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 062A 0645 062E;;;;N;;;;;
+FD58;ARABIC LIGATURE JEEM WITH MEEM WITH HAH FINAL FORM;Lo;0;AL;<final> 062C 0645 062D;;;;N;;;;;
+FD59;ARABIC LIGATURE JEEM WITH MEEM WITH HAH INITIAL FORM;Lo;0;AL;<initial> 062C 0645 062D;;;;N;;;;;
+FD5A;ARABIC LIGATURE HAH WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 062D 0645 064A;;;;N;;;;;
+FD5B;ARABIC LIGATURE HAH WITH MEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 062D 0645 0649;;;;N;;;;;
+FD5C;ARABIC LIGATURE SEEN WITH HAH WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0633 062D 062C;;;;N;;;;;
+FD5D;ARABIC LIGATURE SEEN WITH JEEM WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0633 062C 062D;;;;N;;;;;
+FD5E;ARABIC LIGATURE SEEN WITH JEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0633 062C 0649;;;;N;;;;;
+FD5F;ARABIC LIGATURE SEEN WITH MEEM WITH HAH FINAL FORM;Lo;0;AL;<final> 0633 0645 062D;;;;N;;;;;
+FD60;ARABIC LIGATURE SEEN WITH MEEM WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0633 0645 062D;;;;N;;;;;
+FD61;ARABIC LIGATURE SEEN WITH MEEM WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0633 0645 062C;;;;N;;;;;
+FD62;ARABIC LIGATURE SEEN WITH MEEM WITH MEEM FINAL FORM;Lo;0;AL;<final> 0633 0645 0645;;;;N;;;;;
+FD63;ARABIC LIGATURE SEEN WITH MEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0633 0645 0645;;;;N;;;;;
+FD64;ARABIC LIGATURE SAD WITH HAH WITH HAH FINAL FORM;Lo;0;AL;<final> 0635 062D 062D;;;;N;;;;;
+FD65;ARABIC LIGATURE SAD WITH HAH WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0635 062D 062D;;;;N;;;;;
+FD66;ARABIC LIGATURE SAD WITH MEEM WITH MEEM FINAL FORM;Lo;0;AL;<final> 0635 0645 0645;;;;N;;;;;
+FD67;ARABIC LIGATURE SHEEN WITH HAH WITH MEEM FINAL FORM;Lo;0;AL;<final> 0634 062D 0645;;;;N;;;;;
+FD68;ARABIC LIGATURE SHEEN WITH HAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0634 062D 0645;;;;N;;;;;
+FD69;ARABIC LIGATURE SHEEN WITH JEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 0634 062C 064A;;;;N;;;;;
+FD6A;ARABIC LIGATURE SHEEN WITH MEEM WITH KHAH FINAL FORM;Lo;0;AL;<final> 0634 0645 062E;;;;N;;;;;
+FD6B;ARABIC LIGATURE SHEEN WITH MEEM WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0634 0645 062E;;;;N;;;;;
+FD6C;ARABIC LIGATURE SHEEN WITH MEEM WITH MEEM FINAL FORM;Lo;0;AL;<final> 0634 0645 0645;;;;N;;;;;
+FD6D;ARABIC LIGATURE SHEEN WITH MEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0634 0645 0645;;;;N;;;;;
+FD6E;ARABIC LIGATURE DAD WITH HAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0636 062D 0649;;;;N;;;;;
+FD6F;ARABIC LIGATURE DAD WITH KHAH WITH MEEM FINAL FORM;Lo;0;AL;<final> 0636 062E 0645;;;;N;;;;;
+FD70;ARABIC LIGATURE DAD WITH KHAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0636 062E 0645;;;;N;;;;;
+FD71;ARABIC LIGATURE TAH WITH MEEM WITH HAH FINAL FORM;Lo;0;AL;<final> 0637 0645 062D;;;;N;;;;;
+FD72;ARABIC LIGATURE TAH WITH MEEM WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0637 0645 062D;;;;N;;;;;
+FD73;ARABIC LIGATURE TAH WITH MEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0637 0645 0645;;;;N;;;;;
+FD74;ARABIC LIGATURE TAH WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 0637 0645 064A;;;;N;;;;;
+FD75;ARABIC LIGATURE AIN WITH JEEM WITH MEEM FINAL FORM;Lo;0;AL;<final> 0639 062C 0645;;;;N;;;;;
+FD76;ARABIC LIGATURE AIN WITH MEEM WITH MEEM FINAL FORM;Lo;0;AL;<final> 0639 0645 0645;;;;N;;;;;
+FD77;ARABIC LIGATURE AIN WITH MEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0639 0645 0645;;;;N;;;;;
+FD78;ARABIC LIGATURE AIN WITH MEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0639 0645 0649;;;;N;;;;;
+FD79;ARABIC LIGATURE GHAIN WITH MEEM WITH MEEM FINAL FORM;Lo;0;AL;<final> 063A 0645 0645;;;;N;;;;;
+FD7A;ARABIC LIGATURE GHAIN WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 063A 0645 064A;;;;N;;;;;
+FD7B;ARABIC LIGATURE GHAIN WITH MEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 063A 0645 0649;;;;N;;;;;
+FD7C;ARABIC LIGATURE FEH WITH KHAH WITH MEEM FINAL FORM;Lo;0;AL;<final> 0641 062E 0645;;;;N;;;;;
+FD7D;ARABIC LIGATURE FEH WITH KHAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0641 062E 0645;;;;N;;;;;
+FD7E;ARABIC LIGATURE QAF WITH MEEM WITH HAH FINAL FORM;Lo;0;AL;<final> 0642 0645 062D;;;;N;;;;;
+FD7F;ARABIC LIGATURE QAF WITH MEEM WITH MEEM FINAL FORM;Lo;0;AL;<final> 0642 0645 0645;;;;N;;;;;
+FD80;ARABIC LIGATURE LAM WITH HAH WITH MEEM FINAL FORM;Lo;0;AL;<final> 0644 062D 0645;;;;N;;;;;
+FD81;ARABIC LIGATURE LAM WITH HAH WITH YEH FINAL FORM;Lo;0;AL;<final> 0644 062D 064A;;;;N;;;;;
+FD82;ARABIC LIGATURE LAM WITH HAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0644 062D 0649;;;;N;;;;;
+FD83;ARABIC LIGATURE LAM WITH JEEM WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0644 062C 062C;;;;N;;;;;
+FD84;ARABIC LIGATURE LAM WITH JEEM WITH JEEM FINAL FORM;Lo;0;AL;<final> 0644 062C 062C;;;;N;;;;;
+FD85;ARABIC LIGATURE LAM WITH KHAH WITH MEEM FINAL FORM;Lo;0;AL;<final> 0644 062E 0645;;;;N;;;;;
+FD86;ARABIC LIGATURE LAM WITH KHAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0644 062E 0645;;;;N;;;;;
+FD87;ARABIC LIGATURE LAM WITH MEEM WITH HAH FINAL FORM;Lo;0;AL;<final> 0644 0645 062D;;;;N;;;;;
+FD88;ARABIC LIGATURE LAM WITH MEEM WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0644 0645 062D;;;;N;;;;;
+FD89;ARABIC LIGATURE MEEM WITH HAH WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0645 062D 062C;;;;N;;;;;
+FD8A;ARABIC LIGATURE MEEM WITH HAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0645 062D 0645;;;;N;;;;;
+FD8B;ARABIC LIGATURE MEEM WITH HAH WITH YEH FINAL FORM;Lo;0;AL;<final> 0645 062D 064A;;;;N;;;;;
+FD8C;ARABIC LIGATURE MEEM WITH JEEM WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0645 062C 062D;;;;N;;;;;
+FD8D;ARABIC LIGATURE MEEM WITH JEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0645 062C 0645;;;;N;;;;;
+FD8E;ARABIC LIGATURE MEEM WITH KHAH WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0645 062E 062C;;;;N;;;;;
+FD8F;ARABIC LIGATURE MEEM WITH KHAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0645 062E 0645;;;;N;;;;;
+FD92;ARABIC LIGATURE MEEM WITH JEEM WITH KHAH INITIAL FORM;Lo;0;AL;<initial> 0645 062C 062E;;;;N;;;;;
+FD93;ARABIC LIGATURE HEH WITH MEEM WITH JEEM INITIAL FORM;Lo;0;AL;<initial> 0647 0645 062C;;;;N;;;;;
+FD94;ARABIC LIGATURE HEH WITH MEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0647 0645 0645;;;;N;;;;;
+FD95;ARABIC LIGATURE NOON WITH HAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0646 062D 0645;;;;N;;;;;
+FD96;ARABIC LIGATURE NOON WITH HAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0646 062D 0649;;;;N;;;;;
+FD97;ARABIC LIGATURE NOON WITH JEEM WITH MEEM FINAL FORM;Lo;0;AL;<final> 0646 062C 0645;;;;N;;;;;
+FD98;ARABIC LIGATURE NOON WITH JEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0646 062C 0645;;;;N;;;;;
+FD99;ARABIC LIGATURE NOON WITH JEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0646 062C 0649;;;;N;;;;;
+FD9A;ARABIC LIGATURE NOON WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 0646 0645 064A;;;;N;;;;;
+FD9B;ARABIC LIGATURE NOON WITH MEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0646 0645 0649;;;;N;;;;;
+FD9C;ARABIC LIGATURE YEH WITH MEEM WITH MEEM FINAL FORM;Lo;0;AL;<final> 064A 0645 0645;;;;N;;;;;
+FD9D;ARABIC LIGATURE YEH WITH MEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 064A 0645 0645;;;;N;;;;;
+FD9E;ARABIC LIGATURE BEH WITH KHAH WITH YEH FINAL FORM;Lo;0;AL;<final> 0628 062E 064A;;;;N;;;;;
+FD9F;ARABIC LIGATURE TEH WITH JEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 062A 062C 064A;;;;N;;;;;
+FDA0;ARABIC LIGATURE TEH WITH JEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 062A 062C 0649;;;;N;;;;;
+FDA1;ARABIC LIGATURE TEH WITH KHAH WITH YEH FINAL FORM;Lo;0;AL;<final> 062A 062E 064A;;;;N;;;;;
+FDA2;ARABIC LIGATURE TEH WITH KHAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 062A 062E 0649;;;;N;;;;;
+FDA3;ARABIC LIGATURE TEH WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 062A 0645 064A;;;;N;;;;;
+FDA4;ARABIC LIGATURE TEH WITH MEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 062A 0645 0649;;;;N;;;;;
+FDA5;ARABIC LIGATURE JEEM WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 062C 0645 064A;;;;N;;;;;
+FDA6;ARABIC LIGATURE JEEM WITH HAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 062C 062D 0649;;;;N;;;;;
+FDA7;ARABIC LIGATURE JEEM WITH MEEM WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 062C 0645 0649;;;;N;;;;;
+FDA8;ARABIC LIGATURE SEEN WITH KHAH WITH ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0633 062E 0649;;;;N;;;;;
+FDA9;ARABIC LIGATURE SAD WITH HAH WITH YEH FINAL FORM;Lo;0;AL;<final> 0635 062D 064A;;;;N;;;;;
+FDAA;ARABIC LIGATURE SHEEN WITH HAH WITH YEH FINAL FORM;Lo;0;AL;<final> 0634 062D 064A;;;;N;;;;;
+FDAB;ARABIC LIGATURE DAD WITH HAH WITH YEH FINAL FORM;Lo;0;AL;<final> 0636 062D 064A;;;;N;;;;;
+FDAC;ARABIC LIGATURE LAM WITH JEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 0644 062C 064A;;;;N;;;;;
+FDAD;ARABIC LIGATURE LAM WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 0644 0645 064A;;;;N;;;;;
+FDAE;ARABIC LIGATURE YEH WITH HAH WITH YEH FINAL FORM;Lo;0;AL;<final> 064A 062D 064A;;;;N;;;;;
+FDAF;ARABIC LIGATURE YEH WITH JEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 064A 062C 064A;;;;N;;;;;
+FDB0;ARABIC LIGATURE YEH WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 064A 0645 064A;;;;N;;;;;
+FDB1;ARABIC LIGATURE MEEM WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 0645 0645 064A;;;;N;;;;;
+FDB2;ARABIC LIGATURE QAF WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 0642 0645 064A;;;;N;;;;;
+FDB3;ARABIC LIGATURE NOON WITH HAH WITH YEH FINAL FORM;Lo;0;AL;<final> 0646 062D 064A;;;;N;;;;;
+FDB4;ARABIC LIGATURE QAF WITH MEEM WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0642 0645 062D;;;;N;;;;;
+FDB5;ARABIC LIGATURE LAM WITH HAH WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0644 062D 0645;;;;N;;;;;
+FDB6;ARABIC LIGATURE AIN WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 0639 0645 064A;;;;N;;;;;
+FDB7;ARABIC LIGATURE KAF WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 0643 0645 064A;;;;N;;;;;
+FDB8;ARABIC LIGATURE NOON WITH JEEM WITH HAH INITIAL FORM;Lo;0;AL;<initial> 0646 062C 062D;;;;N;;;;;
+FDB9;ARABIC LIGATURE MEEM WITH KHAH WITH YEH FINAL FORM;Lo;0;AL;<final> 0645 062E 064A;;;;N;;;;;
+FDBA;ARABIC LIGATURE LAM WITH JEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0644 062C 0645;;;;N;;;;;
+FDBB;ARABIC LIGATURE KAF WITH MEEM WITH MEEM FINAL FORM;Lo;0;AL;<final> 0643 0645 0645;;;;N;;;;;
+FDBC;ARABIC LIGATURE LAM WITH JEEM WITH MEEM FINAL FORM;Lo;0;AL;<final> 0644 062C 0645;;;;N;;;;;
+FDBD;ARABIC LIGATURE NOON WITH JEEM WITH HAH FINAL FORM;Lo;0;AL;<final> 0646 062C 062D;;;;N;;;;;
+FDBE;ARABIC LIGATURE JEEM WITH HAH WITH YEH FINAL FORM;Lo;0;AL;<final> 062C 062D 064A;;;;N;;;;;
+FDBF;ARABIC LIGATURE HAH WITH JEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 062D 062C 064A;;;;N;;;;;
+FDC0;ARABIC LIGATURE MEEM WITH JEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 0645 062C 064A;;;;N;;;;;
+FDC1;ARABIC LIGATURE FEH WITH MEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 0641 0645 064A;;;;N;;;;;
+FDC2;ARABIC LIGATURE BEH WITH HAH WITH YEH FINAL FORM;Lo;0;AL;<final> 0628 062D 064A;;;;N;;;;;
+FDC3;ARABIC LIGATURE KAF WITH MEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0643 0645 0645;;;;N;;;;;
+FDC4;ARABIC LIGATURE AIN WITH JEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0639 062C 0645;;;;N;;;;;
+FDC5;ARABIC LIGATURE SAD WITH MEEM WITH MEEM INITIAL FORM;Lo;0;AL;<initial> 0635 0645 0645;;;;N;;;;;
+FDC6;ARABIC LIGATURE SEEN WITH KHAH WITH YEH FINAL FORM;Lo;0;AL;<final> 0633 062E 064A;;;;N;;;;;
+FDC7;ARABIC LIGATURE NOON WITH JEEM WITH YEH FINAL FORM;Lo;0;AL;<final> 0646 062C 064A;;;;N;;;;;
+FDF0;ARABIC LIGATURE SALLA USED AS KORANIC STOP SIGN ISOLATED FORM;Lo;0;AL;<isolated> 0635 0644 06D2;;;;N;;;;;
+FDF1;ARABIC LIGATURE QALA USED AS KORANIC STOP SIGN ISOLATED FORM;Lo;0;AL;<isolated> 0642 0644 06D2;;;;N;;;;;
+FDF2;ARABIC LIGATURE ALLAH ISOLATED FORM;Lo;0;AL;<isolated> 0627 0644 0644 0647;;;;N;;;;;
+FDF3;ARABIC LIGATURE AKBAR ISOLATED FORM;Lo;0;AL;<isolated> 0627 0643 0628 0631;;;;N;;;;;
+FDF4;ARABIC LIGATURE MOHAMMAD ISOLATED FORM;Lo;0;AL;<isolated> 0645 062D 0645 062F;;;;N;;;;;
+FDF5;ARABIC LIGATURE SALAM ISOLATED FORM;Lo;0;AL;<isolated> 0635 0644 0639 0645;;;;N;;;;;
+FDF6;ARABIC LIGATURE RASOUL ISOLATED FORM;Lo;0;AL;<isolated> 0631 0633 0648 0644;;;;N;;;;;
+FDF7;ARABIC LIGATURE ALAYHE ISOLATED FORM;Lo;0;AL;<isolated> 0639 0644 064A 0647;;;;N;;;;;
+FDF8;ARABIC LIGATURE WASALLAM ISOLATED FORM;Lo;0;AL;<isolated> 0648 0633 0644 0645;;;;N;;;;;
+FDF9;ARABIC LIGATURE SALLA ISOLATED FORM;Lo;0;AL;<isolated> 0635 0644 0649;;;;N;;;;;
+FDFA;ARABIC LIGATURE SALLALLAHOU ALAYHE WASALLAM;Lo;0;AL;<isolated> 0635 0644 0649 0020 0627 0644 0644 0647 0020 0639 0644 064A 0647 0020 0648 0633 0644 0645;;;;N;ARABIC LETTER SALLALLAHOU ALAYHE WASALLAM;;;;
+FDFB;ARABIC LIGATURE JALLAJALALOUHOU;Lo;0;AL;<isolated> 062C 0644 0020 062C 0644 0627 0644 0647;;;;N;ARABIC LETTER JALLAJALALOUHOU;;;;
+FE20;COMBINING LIGATURE LEFT HALF;Mn;230;NSM;;;;;N;;;;;
+FE21;COMBINING LIGATURE RIGHT HALF;Mn;230;NSM;;;;;N;;;;;
+FE22;COMBINING DOUBLE TILDE LEFT HALF;Mn;230;NSM;;;;;N;;;;;
+FE23;COMBINING DOUBLE TILDE RIGHT HALF;Mn;230;NSM;;;;;N;;;;;
+FE30;PRESENTATION FORM FOR VERTICAL TWO DOT LEADER;Po;0;ON;<vertical> 2025;;;;N;GLYPH FOR VERTICAL TWO DOT LEADER;;;;
+FE31;PRESENTATION FORM FOR VERTICAL EM DASH;Pd;0;ON;<vertical> 2014;;;;N;GLYPH FOR VERTICAL EM DASH;;;;
+FE32;PRESENTATION FORM FOR VERTICAL EN DASH;Pd;0;ON;<vertical> 2013;;;;N;GLYPH FOR VERTICAL EN DASH;;;;
+FE33;PRESENTATION FORM FOR VERTICAL LOW LINE;Pc;0;ON;<vertical> 005F;;;;N;GLYPH FOR VERTICAL SPACING UNDERSCORE;;;;
+FE34;PRESENTATION FORM FOR VERTICAL WAVY LOW LINE;Pc;0;ON;<vertical> 005F;;;;N;GLYPH FOR VERTICAL SPACING WAVY UNDERSCORE;;;;
+FE35;PRESENTATION FORM FOR VERTICAL LEFT PARENTHESIS;Ps;0;ON;<vertical> 0028;;;;N;GLYPH FOR VERTICAL OPENING PARENTHESIS;;;;
+FE36;PRESENTATION FORM FOR VERTICAL RIGHT PARENTHESIS;Pe;0;ON;<vertical> 0029;;;;N;GLYPH FOR VERTICAL CLOSING PARENTHESIS;;;;
+FE37;PRESENTATION FORM FOR VERTICAL LEFT CURLY BRACKET;Ps;0;ON;<vertical> 007B;;;;N;GLYPH FOR VERTICAL OPENING CURLY BRACKET;;;;
+FE38;PRESENTATION FORM FOR VERTICAL RIGHT CURLY BRACKET;Pe;0;ON;<vertical> 007D;;;;N;GLYPH FOR VERTICAL CLOSING CURLY BRACKET;;;;
+FE39;PRESENTATION FORM FOR VERTICAL LEFT TORTOISE SHELL BRACKET;Ps;0;ON;<vertical> 3014;;;;N;GLYPH FOR VERTICAL OPENING TORTOISE SHELL BRACKET;;;;
+FE3A;PRESENTATION FORM FOR VERTICAL RIGHT TORTOISE SHELL BRACKET;Pe;0;ON;<vertical> 3015;;;;N;GLYPH FOR VERTICAL CLOSING TORTOISE SHELL BRACKET;;;;
+FE3B;PRESENTATION FORM FOR VERTICAL LEFT BLACK LENTICULAR BRACKET;Ps;0;ON;<vertical> 3010;;;;N;GLYPH FOR VERTICAL OPENING BLACK LENTICULAR BRACKET;;;;
+FE3C;PRESENTATION FORM FOR VERTICAL RIGHT BLACK LENTICULAR BRACKET;Pe;0;ON;<vertical> 3011;;;;N;GLYPH FOR VERTICAL CLOSING BLACK LENTICULAR BRACKET;;;;
+FE3D;PRESENTATION FORM FOR VERTICAL LEFT DOUBLE ANGLE BRACKET;Ps;0;ON;<vertical> 300A;;;;N;GLYPH FOR VERTICAL OPENING DOUBLE ANGLE BRACKET;;;;
+FE3E;PRESENTATION FORM FOR VERTICAL RIGHT DOUBLE ANGLE BRACKET;Pe;0;ON;<vertical> 300B;;;;N;GLYPH FOR VERTICAL CLOSING DOUBLE ANGLE BRACKET;;;;
+FE3F;PRESENTATION FORM FOR VERTICAL LEFT ANGLE BRACKET;Ps;0;ON;<vertical> 3008;;;;N;GLYPH FOR VERTICAL OPENING ANGLE BRACKET;;;;
+FE40;PRESENTATION FORM FOR VERTICAL RIGHT ANGLE BRACKET;Pe;0;ON;<vertical> 3009;;;;N;GLYPH FOR VERTICAL CLOSING ANGLE BRACKET;;;;
+FE41;PRESENTATION FORM FOR VERTICAL LEFT CORNER BRACKET;Ps;0;ON;<vertical> 300C;;;;N;GLYPH FOR VERTICAL OPENING CORNER BRACKET;;;;
+FE42;PRESENTATION FORM FOR VERTICAL RIGHT CORNER BRACKET;Pe;0;ON;<vertical> 300D;;;;N;GLYPH FOR VERTICAL CLOSING CORNER BRACKET;;;;
+FE43;PRESENTATION FORM FOR VERTICAL LEFT WHITE CORNER BRACKET;Ps;0;ON;<vertical> 300E;;;;N;GLYPH FOR VERTICAL OPENING WHITE CORNER BRACKET;;;;
+FE44;PRESENTATION FORM FOR VERTICAL RIGHT WHITE CORNER BRACKET;Pe;0;ON;<vertical> 300F;;;;N;GLYPH FOR VERTICAL CLOSING WHITE CORNER BRACKET;;;;
+FE49;DASHED OVERLINE;Po;0;ON;<compat> 203E;;;;N;SPACING DASHED OVERSCORE;;;;
+FE4A;CENTRELINE OVERLINE;Po;0;ON;<compat> 203E;;;;N;SPACING CENTERLINE OVERSCORE;;;;
+FE4B;WAVY OVERLINE;Po;0;ON;<compat> 203E;;;;N;SPACING WAVY OVERSCORE;;;;
+FE4C;DOUBLE WAVY OVERLINE;Po;0;ON;<compat> 203E;;;;N;SPACING DOUBLE WAVY OVERSCORE;;;;
+FE4D;DASHED LOW LINE;Pc;0;ON;<compat> 005F;;;;N;SPACING DASHED UNDERSCORE;;;;
+FE4E;CENTRELINE LOW LINE;Pc;0;ON;<compat> 005F;;;;N;SPACING CENTERLINE UNDERSCORE;;;;
+FE4F;WAVY LOW LINE;Pc;0;ON;<compat> 005F;;;;N;SPACING WAVY UNDERSCORE;;;;
+FE50;SMALL COMMA;Po;0;CS;<small> 002C;;;;N;;;;;
+FE51;SMALL IDEOGRAPHIC COMMA;Po;0;ON;<small> 3001;;;;N;;;;;
+FE52;SMALL FULL STOP;Po;0;CS;<small> 002E;;;;N;SMALL PERIOD;;;;
+FE54;SMALL SEMICOLON;Po;0;ON;<small> 003B;;;;N;;;;;
+FE55;SMALL COLON;Po;0;CS;<small> 003A;;;;N;;;;;
+FE56;SMALL QUESTION MARK;Po;0;ON;<small> 003F;;;;N;;;;;
+FE57;SMALL EXCLAMATION MARK;Po;0;ON;<small> 0021;;;;N;;;;;
+FE58;SMALL EM DASH;Pd;0;ON;<small> 2014;;;;N;;;;;
+FE59;SMALL LEFT PARENTHESIS;Ps;0;ON;<small> 0028;;;;N;SMALL OPENING PARENTHESIS;;;;
+FE5A;SMALL RIGHT PARENTHESIS;Pe;0;ON;<small> 0029;;;;N;SMALL CLOSING PARENTHESIS;;;;
+FE5B;SMALL LEFT CURLY BRACKET;Ps;0;ON;<small> 007B;;;;N;SMALL OPENING CURLY BRACKET;;;;
+FE5C;SMALL RIGHT CURLY BRACKET;Pe;0;ON;<small> 007D;;;;N;SMALL CLOSING CURLY BRACKET;;;;
+FE5D;SMALL LEFT TORTOISE SHELL BRACKET;Ps;0;ON;<small> 3014;;;;N;SMALL OPENING TORTOISE SHELL BRACKET;;;;
+FE5E;SMALL RIGHT TORTOISE SHELL BRACKET;Pe;0;ON;<small> 3015;;;;N;SMALL CLOSING TORTOISE SHELL BRACKET;;;;
+FE5F;SMALL NUMBER SIGN;Po;0;ET;<small> 0023;;;;N;;;;;
+FE60;SMALL AMPERSAND;Po;0;ON;<small> 0026;;;;N;;;;;
+FE61;SMALL ASTERISK;Po;0;ON;<small> 002A;;;;N;;;;;
+FE62;SMALL PLUS SIGN;Sm;0;ET;<small> 002B;;;;N;;;;;
+FE63;SMALL HYPHEN-MINUS;Pd;0;ET;<small> 002D;;;;N;;;;;
+FE64;SMALL LESS-THAN SIGN;Sm;0;ON;<small> 003C;;;;N;;;;;
+FE65;SMALL GREATER-THAN SIGN;Sm;0;ON;<small> 003E;;;;N;;;;;
+FE66;SMALL EQUALS SIGN;Sm;0;ON;<small> 003D;;;;N;;;;;
+FE68;SMALL REVERSE SOLIDUS;Po;0;ON;<small> 005C;;;;N;SMALL BACKSLASH;;;;
+FE69;SMALL DOLLAR SIGN;Sc;0;ET;<small> 0024;;;;N;;;;;
+FE6A;SMALL PERCENT SIGN;Po;0;ET;<small> 0025;;;;N;;;;;
+FE6B;SMALL COMMERCIAL AT;Po;0;ON;<small> 0040;;;;N;;;;;
+FE70;ARABIC FATHATAN ISOLATED FORM;Lo;0;AL;<isolated> 0020 064B;;;;N;ARABIC SPACING FATHATAN;;;;
+FE71;ARABIC TATWEEL WITH FATHATAN ABOVE;Lo;0;AL;<medial> 0640 064B;;;;N;ARABIC FATHATAN ON TATWEEL;;;;
+FE72;ARABIC DAMMATAN ISOLATED FORM;Lo;0;AL;<isolated> 0020 064C;;;;N;ARABIC SPACING DAMMATAN;;;;
+FE74;ARABIC KASRATAN ISOLATED FORM;Lo;0;AL;<isolated> 0020 064D;;;;N;ARABIC SPACING KASRATAN;;;;
+FE76;ARABIC FATHA ISOLATED FORM;Lo;0;AL;<isolated> 0020 064E;;;;N;ARABIC SPACING FATHAH;;;;
+FE77;ARABIC FATHA MEDIAL FORM;Lo;0;AL;<medial> 0640 064E;;;;N;ARABIC FATHAH ON TATWEEL;;;;
+FE78;ARABIC DAMMA ISOLATED FORM;Lo;0;AL;<isolated> 0020 064F;;;;N;ARABIC SPACING DAMMAH;;;;
+FE79;ARABIC DAMMA MEDIAL FORM;Lo;0;AL;<medial> 0640 064F;;;;N;ARABIC DAMMAH ON TATWEEL;;;;
+FE7A;ARABIC KASRA ISOLATED FORM;Lo;0;AL;<isolated> 0020 0650;;;;N;ARABIC SPACING KASRAH;;;;
+FE7B;ARABIC KASRA MEDIAL FORM;Lo;0;AL;<medial> 0640 0650;;;;N;ARABIC KASRAH ON TATWEEL;;;;
+FE7C;ARABIC SHADDA ISOLATED FORM;Lo;0;AL;<isolated> 0020 0651;;;;N;ARABIC SPACING SHADDAH;;;;
+FE7D;ARABIC SHADDA MEDIAL FORM;Lo;0;AL;<medial> 0640 0651;;;;N;ARABIC SHADDAH ON TATWEEL;;;;
+FE7E;ARABIC SUKUN ISOLATED FORM;Lo;0;AL;<isolated> 0020 0652;;;;N;ARABIC SPACING SUKUN;;;;
+FE7F;ARABIC SUKUN MEDIAL FORM;Lo;0;AL;<medial> 0640 0652;;;;N;ARABIC SUKUN ON TATWEEL;;;;
+FE80;ARABIC LETTER HAMZA ISOLATED FORM;Lo;0;AL;<isolated> 0621;;;;N;GLYPH FOR ISOLATE ARABIC HAMZAH;;;;
+FE81;ARABIC LETTER ALEF WITH MADDA ABOVE ISOLATED FORM;Lo;0;AL;<isolated> 0622;;;;N;GLYPH FOR ISOLATE ARABIC MADDAH ON ALEF;;;;
+FE82;ARABIC LETTER ALEF WITH MADDA ABOVE FINAL FORM;Lo;0;AL;<final> 0622;;;;N;GLYPH FOR FINAL ARABIC MADDAH ON ALEF;;;;
+FE83;ARABIC LETTER ALEF WITH HAMZA ABOVE ISOLATED FORM;Lo;0;AL;<isolated> 0623;;;;N;GLYPH FOR ISOLATE ARABIC HAMZAH ON ALEF;;;;
+FE84;ARABIC LETTER ALEF WITH HAMZA ABOVE FINAL FORM;Lo;0;AL;<final> 0623;;;;N;GLYPH FOR FINAL ARABIC HAMZAH ON ALEF;;;;
+FE85;ARABIC LETTER WAW WITH HAMZA ABOVE ISOLATED FORM;Lo;0;AL;<isolated> 0624;;;;N;GLYPH FOR ISOLATE ARABIC HAMZAH ON WAW;;;;
+FE86;ARABIC LETTER WAW WITH HAMZA ABOVE FINAL FORM;Lo;0;AL;<final> 0624;;;;N;GLYPH FOR FINAL ARABIC HAMZAH ON WAW;;;;
+FE87;ARABIC LETTER ALEF WITH HAMZA BELOW ISOLATED FORM;Lo;0;AL;<isolated> 0625;;;;N;GLYPH FOR ISOLATE ARABIC HAMZAH UNDER ALEF;;;;
+FE88;ARABIC LETTER ALEF WITH HAMZA BELOW FINAL FORM;Lo;0;AL;<final> 0625;;;;N;GLYPH FOR FINAL ARABIC HAMZAH UNDER ALEF;;;;
+FE89;ARABIC LETTER YEH WITH HAMZA ABOVE ISOLATED FORM;Lo;0;AL;<isolated> 0626;;;;N;GLYPH FOR ISOLATE ARABIC HAMZAH ON YA;;;;
+FE8A;ARABIC LETTER YEH WITH HAMZA ABOVE FINAL FORM;Lo;0;AL;<final> 0626;;;;N;GLYPH FOR FINAL ARABIC HAMZAH ON YA;;;;
+FE8B;ARABIC LETTER YEH WITH HAMZA ABOVE INITIAL FORM;Lo;0;AL;<initial> 0626;;;;N;GLYPH FOR INITIAL ARABIC HAMZAH ON YA;;;;
+FE8C;ARABIC LETTER YEH WITH HAMZA ABOVE MEDIAL FORM;Lo;0;AL;<medial> 0626;;;;N;GLYPH FOR MEDIAL ARABIC HAMZAH ON YA;;;;
+FE8D;ARABIC LETTER ALEF ISOLATED FORM;Lo;0;AL;<isolated> 0627;;;;N;GLYPH FOR ISOLATE ARABIC ALEF;;;;
+FE8E;ARABIC LETTER ALEF FINAL FORM;Lo;0;AL;<final> 0627;;;;N;GLYPH FOR FINAL ARABIC ALEF;;;;
+FE8F;ARABIC LETTER BEH ISOLATED FORM;Lo;0;AL;<isolated> 0628;;;;N;GLYPH FOR ISOLATE ARABIC BAA;;;;
+FE90;ARABIC LETTER BEH FINAL FORM;Lo;0;AL;<final> 0628;;;;N;GLYPH FOR FINAL ARABIC BAA;;;;
+FE91;ARABIC LETTER BEH INITIAL FORM;Lo;0;AL;<initial> 0628;;;;N;GLYPH FOR INITIAL ARABIC BAA;;;;
+FE92;ARABIC LETTER BEH MEDIAL FORM;Lo;0;AL;<medial> 0628;;;;N;GLYPH FOR MEDIAL ARABIC BAA;;;;
+FE93;ARABIC LETTER TEH MARBUTA ISOLATED FORM;Lo;0;AL;<isolated> 0629;;;;N;GLYPH FOR ISOLATE ARABIC TAA MARBUTAH;;;;
+FE94;ARABIC LETTER TEH MARBUTA FINAL FORM;Lo;0;AL;<final> 0629;;;;N;GLYPH FOR FINAL ARABIC TAA MARBUTAH;;;;
+FE95;ARABIC LETTER TEH ISOLATED FORM;Lo;0;AL;<isolated> 062A;;;;N;GLYPH FOR ISOLATE ARABIC TAA;;;;
+FE96;ARABIC LETTER TEH FINAL FORM;Lo;0;AL;<final> 062A;;;;N;GLYPH FOR FINAL ARABIC TAA;;;;
+FE97;ARABIC LETTER TEH INITIAL FORM;Lo;0;AL;<initial> 062A;;;;N;GLYPH FOR INITIAL ARABIC TAA;;;;
+FE98;ARABIC LETTER TEH MEDIAL FORM;Lo;0;AL;<medial> 062A;;;;N;GLYPH FOR MEDIAL ARABIC TAA;;;;
+FE99;ARABIC LETTER THEH ISOLATED FORM;Lo;0;AL;<isolated> 062B;;;;N;GLYPH FOR ISOLATE ARABIC THAA;;;;
+FE9A;ARABIC LETTER THEH FINAL FORM;Lo;0;AL;<final> 062B;;;;N;GLYPH FOR FINAL ARABIC THAA;;;;
+FE9B;ARABIC LETTER THEH INITIAL FORM;Lo;0;AL;<initial> 062B;;;;N;GLYPH FOR INITIAL ARABIC THAA;;;;
+FE9C;ARABIC LETTER THEH MEDIAL FORM;Lo;0;AL;<medial> 062B;;;;N;GLYPH FOR MEDIAL ARABIC THAA;;;;
+FE9D;ARABIC LETTER JEEM ISOLATED FORM;Lo;0;AL;<isolated> 062C;;;;N;GLYPH FOR ISOLATE ARABIC JEEM;;;;
+FE9E;ARABIC LETTER JEEM FINAL FORM;Lo;0;AL;<final> 062C;;;;N;GLYPH FOR FINAL ARABIC JEEM;;;;
+FE9F;ARABIC LETTER JEEM INITIAL FORM;Lo;0;AL;<initial> 062C;;;;N;GLYPH FOR INITIAL ARABIC JEEM;;;;
+FEA0;ARABIC LETTER JEEM MEDIAL FORM;Lo;0;AL;<medial> 062C;;;;N;GLYPH FOR MEDIAL ARABIC JEEM;;;;
+FEA1;ARABIC LETTER HAH ISOLATED FORM;Lo;0;AL;<isolated> 062D;;;;N;GLYPH FOR ISOLATE ARABIC HAA;;;;
+FEA2;ARABIC LETTER HAH FINAL FORM;Lo;0;AL;<final> 062D;;;;N;GLYPH FOR FINAL ARABIC HAA;;;;
+FEA3;ARABIC LETTER HAH INITIAL FORM;Lo;0;AL;<initial> 062D;;;;N;GLYPH FOR INITIAL ARABIC HAA;;;;
+FEA4;ARABIC LETTER HAH MEDIAL FORM;Lo;0;AL;<medial> 062D;;;;N;GLYPH FOR MEDIAL ARABIC HAA;;;;
+FEA5;ARABIC LETTER KHAH ISOLATED FORM;Lo;0;AL;<isolated> 062E;;;;N;GLYPH FOR ISOLATE ARABIC KHAA;;;;
+FEA6;ARABIC LETTER KHAH FINAL FORM;Lo;0;AL;<final> 062E;;;;N;GLYPH FOR FINAL ARABIC KHAA;;;;
+FEA7;ARABIC LETTER KHAH INITIAL FORM;Lo;0;AL;<initial> 062E;;;;N;GLYPH FOR INITIAL ARABIC KHAA;;;;
+FEA8;ARABIC LETTER KHAH MEDIAL FORM;Lo;0;AL;<medial> 062E;;;;N;GLYPH FOR MEDIAL ARABIC KHAA;;;;
+FEA9;ARABIC LETTER DAL ISOLATED FORM;Lo;0;AL;<isolated> 062F;;;;N;GLYPH FOR ISOLATE ARABIC DAL;;;;
+FEAA;ARABIC LETTER DAL FINAL FORM;Lo;0;AL;<final> 062F;;;;N;GLYPH FOR FINAL ARABIC DAL;;;;
+FEAB;ARABIC LETTER THAL ISOLATED FORM;Lo;0;AL;<isolated> 0630;;;;N;GLYPH FOR ISOLATE ARABIC THAL;;;;
+FEAC;ARABIC LETTER THAL FINAL FORM;Lo;0;AL;<final> 0630;;;;N;GLYPH FOR FINAL ARABIC THAL;;;;
+FEAD;ARABIC LETTER REH ISOLATED FORM;Lo;0;AL;<isolated> 0631;;;;N;GLYPH FOR ISOLATE ARABIC RA;;;;
+FEAE;ARABIC LETTER REH FINAL FORM;Lo;0;AL;<final> 0631;;;;N;GLYPH FOR FINAL ARABIC RA;;;;
+FEAF;ARABIC LETTER ZAIN ISOLATED FORM;Lo;0;AL;<isolated> 0632;;;;N;GLYPH FOR ISOLATE ARABIC ZAIN;;;;
+FEB0;ARABIC LETTER ZAIN FINAL FORM;Lo;0;AL;<final> 0632;;;;N;GLYPH FOR FINAL ARABIC ZAIN;;;;
+FEB1;ARABIC LETTER SEEN ISOLATED FORM;Lo;0;AL;<isolated> 0633;;;;N;GLYPH FOR ISOLATE ARABIC SEEN;;;;
+FEB2;ARABIC LETTER SEEN FINAL FORM;Lo;0;AL;<final> 0633;;;;N;GLYPH FOR FINAL ARABIC SEEN;;;;
+FEB3;ARABIC LETTER SEEN INITIAL FORM;Lo;0;AL;<initial> 0633;;;;N;GLYPH FOR INITIAL ARABIC SEEN;;;;
+FEB4;ARABIC LETTER SEEN MEDIAL FORM;Lo;0;AL;<medial> 0633;;;;N;GLYPH FOR MEDIAL ARABIC SEEN;;;;
+FEB5;ARABIC LETTER SHEEN ISOLATED FORM;Lo;0;AL;<isolated> 0634;;;;N;GLYPH FOR ISOLATE ARABIC SHEEN;;;;
+FEB6;ARABIC LETTER SHEEN FINAL FORM;Lo;0;AL;<final> 0634;;;;N;GLYPH FOR FINAL ARABIC SHEEN;;;;
+FEB7;ARABIC LETTER SHEEN INITIAL FORM;Lo;0;AL;<initial> 0634;;;;N;GLYPH FOR INITIAL ARABIC SHEEN;;;;
+FEB8;ARABIC LETTER SHEEN MEDIAL FORM;Lo;0;AL;<medial> 0634;;;;N;GLYPH FOR MEDIAL ARABIC SHEEN;;;;
+FEB9;ARABIC LETTER SAD ISOLATED FORM;Lo;0;AL;<isolated> 0635;;;;N;GLYPH FOR ISOLATE ARABIC SAD;;;;
+FEBA;ARABIC LETTER SAD FINAL FORM;Lo;0;AL;<final> 0635;;;;N;GLYPH FOR FINAL ARABIC SAD;;;;
+FEBB;ARABIC LETTER SAD INITIAL FORM;Lo;0;AL;<initial> 0635;;;;N;GLYPH FOR INITIAL ARABIC SAD;;;;
+FEBC;ARABIC LETTER SAD MEDIAL FORM;Lo;0;AL;<medial> 0635;;;;N;GLYPH FOR MEDIAL ARABIC SAD;;;;
+FEBD;ARABIC LETTER DAD ISOLATED FORM;Lo;0;AL;<isolated> 0636;;;;N;GLYPH FOR ISOLATE ARABIC DAD;;;;
+FEBE;ARABIC LETTER DAD FINAL FORM;Lo;0;AL;<final> 0636;;;;N;GLYPH FOR FINAL ARABIC DAD;;;;
+FEBF;ARABIC LETTER DAD INITIAL FORM;Lo;0;AL;<initial> 0636;;;;N;GLYPH FOR INITIAL ARABIC DAD;;;;
+FEC0;ARABIC LETTER DAD MEDIAL FORM;Lo;0;AL;<medial> 0636;;;;N;GLYPH FOR MEDIAL ARABIC DAD;;;;
+FEC1;ARABIC LETTER TAH ISOLATED FORM;Lo;0;AL;<isolated> 0637;;;;N;GLYPH FOR ISOLATE ARABIC TAH;;;;
+FEC2;ARABIC LETTER TAH FINAL FORM;Lo;0;AL;<final> 0637;;;;N;GLYPH FOR FINAL ARABIC TAH;;;;
+FEC3;ARABIC LETTER TAH INITIAL FORM;Lo;0;AL;<initial> 0637;;;;N;GLYPH FOR INITIAL ARABIC TAH;;;;
+FEC4;ARABIC LETTER TAH MEDIAL FORM;Lo;0;AL;<medial> 0637;;;;N;GLYPH FOR MEDIAL ARABIC TAH;;;;
+FEC5;ARABIC LETTER ZAH ISOLATED FORM;Lo;0;AL;<isolated> 0638;;;;N;GLYPH FOR ISOLATE ARABIC DHAH;;;;
+FEC6;ARABIC LETTER ZAH FINAL FORM;Lo;0;AL;<final> 0638;;;;N;GLYPH FOR FINAL ARABIC DHAH;;;;
+FEC7;ARABIC LETTER ZAH INITIAL FORM;Lo;0;AL;<initial> 0638;;;;N;GLYPH FOR INITIAL ARABIC DHAH;;;;
+FEC8;ARABIC LETTER ZAH MEDIAL FORM;Lo;0;AL;<medial> 0638;;;;N;GLYPH FOR MEDIAL ARABIC DHAH;;;;
+FEC9;ARABIC LETTER AIN ISOLATED FORM;Lo;0;AL;<isolated> 0639;;;;N;GLYPH FOR ISOLATE ARABIC AIN;;;;
+FECA;ARABIC LETTER AIN FINAL FORM;Lo;0;AL;<final> 0639;;;;N;GLYPH FOR FINAL ARABIC AIN;;;;
+FECB;ARABIC LETTER AIN INITIAL FORM;Lo;0;AL;<initial> 0639;;;;N;GLYPH FOR INITIAL ARABIC AIN;;;;
+FECC;ARABIC LETTER AIN MEDIAL FORM;Lo;0;AL;<medial> 0639;;;;N;GLYPH FOR MEDIAL ARABIC AIN;;;;
+FECD;ARABIC LETTER GHAIN ISOLATED FORM;Lo;0;AL;<isolated> 063A;;;;N;GLYPH FOR ISOLATE ARABIC GHAIN;;;;
+FECE;ARABIC LETTER GHAIN FINAL FORM;Lo;0;AL;<final> 063A;;;;N;GLYPH FOR FINAL ARABIC GHAIN;;;;
+FECF;ARABIC LETTER GHAIN INITIAL FORM;Lo;0;AL;<initial> 063A;;;;N;GLYPH FOR INITIAL ARABIC GHAIN;;;;
+FED0;ARABIC LETTER GHAIN MEDIAL FORM;Lo;0;AL;<medial> 063A;;;;N;GLYPH FOR MEDIAL ARABIC GHAIN;;;;
+FED1;ARABIC LETTER FEH ISOLATED FORM;Lo;0;AL;<isolated> 0641;;;;N;GLYPH FOR ISOLATE ARABIC FA;;;;
+FED2;ARABIC LETTER FEH FINAL FORM;Lo;0;AL;<final> 0641;;;;N;GLYPH FOR FINAL ARABIC FA;;;;
+FED3;ARABIC LETTER FEH INITIAL FORM;Lo;0;AL;<initial> 0641;;;;N;GLYPH FOR INITIAL ARABIC FA;;;;
+FED4;ARABIC LETTER FEH MEDIAL FORM;Lo;0;AL;<medial> 0641;;;;N;GLYPH FOR MEDIAL ARABIC FA;;;;
+FED5;ARABIC LETTER QAF ISOLATED FORM;Lo;0;AL;<isolated> 0642;;;;N;GLYPH FOR ISOLATE ARABIC QAF;;;;
+FED6;ARABIC LETTER QAF FINAL FORM;Lo;0;AL;<final> 0642;;;;N;GLYPH FOR FINAL ARABIC QAF;;;;
+FED7;ARABIC LETTER QAF INITIAL FORM;Lo;0;AL;<initial> 0642;;;;N;GLYPH FOR INITIAL ARABIC QAF;;;;
+FED8;ARABIC LETTER QAF MEDIAL FORM;Lo;0;AL;<medial> 0642;;;;N;GLYPH FOR MEDIAL ARABIC QAF;;;;
+FED9;ARABIC LETTER KAF ISOLATED FORM;Lo;0;AL;<isolated> 0643;;;;N;GLYPH FOR ISOLATE ARABIC CAF;;;;
+FEDA;ARABIC LETTER KAF FINAL FORM;Lo;0;AL;<final> 0643;;;;N;GLYPH FOR FINAL ARABIC CAF;;;;
+FEDB;ARABIC LETTER KAF INITIAL FORM;Lo;0;AL;<initial> 0643;;;;N;GLYPH FOR INITIAL ARABIC CAF;;;;
+FEDC;ARABIC LETTER KAF MEDIAL FORM;Lo;0;AL;<medial> 0643;;;;N;GLYPH FOR MEDIAL ARABIC CAF;;;;
+FEDD;ARABIC LETTER LAM ISOLATED FORM;Lo;0;AL;<isolated> 0644;;;;N;GLYPH FOR ISOLATE ARABIC LAM;;;;
+FEDE;ARABIC LETTER LAM FINAL FORM;Lo;0;AL;<final> 0644;;;;N;GLYPH FOR FINAL ARABIC LAM;;;;
+FEDF;ARABIC LETTER LAM INITIAL FORM;Lo;0;AL;<initial> 0644;;;;N;GLYPH FOR INITIAL ARABIC LAM;;;;
+FEE0;ARABIC LETTER LAM MEDIAL FORM;Lo;0;AL;<medial> 0644;;;;N;GLYPH FOR MEDIAL ARABIC LAM;;;;
+FEE1;ARABIC LETTER MEEM ISOLATED FORM;Lo;0;AL;<isolated> 0645;;;;N;GLYPH FOR ISOLATE ARABIC MEEM;;;;
+FEE2;ARABIC LETTER MEEM FINAL FORM;Lo;0;AL;<final> 0645;;;;N;GLYPH FOR FINAL ARABIC MEEM;;;;
+FEE3;ARABIC LETTER MEEM INITIAL FORM;Lo;0;AL;<initial> 0645;;;;N;GLYPH FOR INITIAL ARABIC MEEM;;;;
+FEE4;ARABIC LETTER MEEM MEDIAL FORM;Lo;0;AL;<medial> 0645;;;;N;GLYPH FOR MEDIAL ARABIC MEEM;;;;
+FEE5;ARABIC LETTER NOON ISOLATED FORM;Lo;0;AL;<isolated> 0646;;;;N;GLYPH FOR ISOLATE ARABIC NOON;;;;
+FEE6;ARABIC LETTER NOON FINAL FORM;Lo;0;AL;<final> 0646;;;;N;GLYPH FOR FINAL ARABIC NOON;;;;
+FEE7;ARABIC LETTER NOON INITIAL FORM;Lo;0;AL;<initial> 0646;;;;N;GLYPH FOR INITIAL ARABIC NOON;;;;
+FEE8;ARABIC LETTER NOON MEDIAL FORM;Lo;0;AL;<medial> 0646;;;;N;GLYPH FOR MEDIAL ARABIC NOON;;;;
+FEE9;ARABIC LETTER HEH ISOLATED FORM;Lo;0;AL;<isolated> 0647;;;;N;GLYPH FOR ISOLATE ARABIC HA;;;;
+FEEA;ARABIC LETTER HEH FINAL FORM;Lo;0;AL;<final> 0647;;;;N;GLYPH FOR FINAL ARABIC HA;;;;
+FEEB;ARABIC LETTER HEH INITIAL FORM;Lo;0;AL;<initial> 0647;;;;N;GLYPH FOR INITIAL ARABIC HA;;;;
+FEEC;ARABIC LETTER HEH MEDIAL FORM;Lo;0;AL;<medial> 0647;;;;N;GLYPH FOR MEDIAL ARABIC HA;;;;
+FEED;ARABIC LETTER WAW ISOLATED FORM;Lo;0;AL;<isolated> 0648;;;;N;GLYPH FOR ISOLATE ARABIC WAW;;;;
+FEEE;ARABIC LETTER WAW FINAL FORM;Lo;0;AL;<final> 0648;;;;N;GLYPH FOR FINAL ARABIC WAW;;;;
+FEEF;ARABIC LETTER ALEF MAKSURA ISOLATED FORM;Lo;0;AL;<isolated> 0649;;;;N;GLYPH FOR ISOLATE ARABIC ALEF MAQSURAH;;;;
+FEF0;ARABIC LETTER ALEF MAKSURA FINAL FORM;Lo;0;AL;<final> 0649;;;;N;GLYPH FOR FINAL ARABIC ALEF MAQSURAH;;;;
+FEF1;ARABIC LETTER YEH ISOLATED FORM;Lo;0;AL;<isolated> 064A;;;;N;GLYPH FOR ISOLATE ARABIC YA;;;;
+FEF2;ARABIC LETTER YEH FINAL FORM;Lo;0;AL;<final> 064A;;;;N;GLYPH FOR FINAL ARABIC YA;;;;
+FEF3;ARABIC LETTER YEH INITIAL FORM;Lo;0;AL;<initial> 064A;;;;N;GLYPH FOR INITIAL ARABIC YA;;;;
+FEF4;ARABIC LETTER YEH MEDIAL FORM;Lo;0;AL;<medial> 064A;;;;N;GLYPH FOR MEDIAL ARABIC YA;;;;
+FEF5;ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE ISOLATED FORM;Lo;0;AL;<isolated> 0644 0622;;;;N;GLYPH FOR ISOLATE ARABIC MADDAH ON LIGATURE LAM ALEF;;;;
+FEF6;ARABIC LIGATURE LAM WITH ALEF WITH MADDA ABOVE FINAL FORM;Lo;0;AL;<final> 0644 0622;;;;N;GLYPH FOR FINAL ARABIC MADDAH ON LIGATURE LAM ALEF;;;;
+FEF7;ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE ISOLATED FORM;Lo;0;AL;<isolated> 0644 0623;;;;N;GLYPH FOR ISOLATE ARABIC HAMZAH ON LIGATURE LAM ALEF;;;;
+FEF8;ARABIC LIGATURE LAM WITH ALEF WITH HAMZA ABOVE FINAL FORM;Lo;0;AL;<final> 0644 0623;;;;N;GLYPH FOR FINAL ARABIC HAMZAH ON LIGATURE LAM ALEF;;;;
+FEF9;ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW ISOLATED FORM;Lo;0;AL;<isolated> 0644 0625;;;;N;GLYPH FOR ISOLATE ARABIC HAMZAH UNDER LIGATURE LAM ALEF;;;;
+FEFA;ARABIC LIGATURE LAM WITH ALEF WITH HAMZA BELOW FINAL FORM;Lo;0;AL;<final> 0644 0625;;;;N;GLYPH FOR FINAL ARABIC HAMZAH UNDER LIGATURE LAM ALEF;;;;
+FEFB;ARABIC LIGATURE LAM WITH ALEF ISOLATED FORM;Lo;0;AL;<isolated> 0644 0627;;;;N;GLYPH FOR ISOLATE ARABIC LIGATURE LAM ALEF;;;;
+FEFC;ARABIC LIGATURE LAM WITH ALEF FINAL FORM;Lo;0;AL;<final> 0644 0627;;;;N;GLYPH FOR FINAL ARABIC LIGATURE LAM ALEF;;;;
+FEFF;ZERO WIDTH NO-BREAK SPACE;Cf;0;BN;;;;;N;BYTE ORDER MARK;;;;
+FF01;FULLWIDTH EXCLAMATION MARK;Po;0;ON;<wide> 0021;;;;N;;;;;
+FF02;FULLWIDTH QUOTATION MARK;Po;0;ON;<wide> 0022;;;;N;;;;;
+FF03;FULLWIDTH NUMBER SIGN;Po;0;ET;<wide> 0023;;;;N;;;;;
+FF04;FULLWIDTH DOLLAR SIGN;Sc;0;ET;<wide> 0024;;;;N;;;;;
+FF05;FULLWIDTH PERCENT SIGN;Po;0;ET;<wide> 0025;;;;N;;;;;
+FF06;FULLWIDTH AMPERSAND;Po;0;ON;<wide> 0026;;;;N;;;;;
+FF07;FULLWIDTH APOSTROPHE;Po;0;ON;<wide> 0027;;;;N;;;;;
+FF08;FULLWIDTH LEFT PARENTHESIS;Ps;0;ON;<wide> 0028;;;;N;FULLWIDTH OPENING PARENTHESIS;;;;
+FF09;FULLWIDTH RIGHT PARENTHESIS;Pe;0;ON;<wide> 0029;;;;N;FULLWIDTH CLOSING PARENTHESIS;;;;
+FF0A;FULLWIDTH ASTERISK;Po;0;ON;<wide> 002A;;;;N;;;;;
+FF0B;FULLWIDTH PLUS SIGN;Sm;0;ET;<wide> 002B;;;;N;;;;;
+FF0C;FULLWIDTH COMMA;Po;0;CS;<wide> 002C;;;;N;;;;;
+FF0D;FULLWIDTH HYPHEN-MINUS;Pd;0;ET;<wide> 002D;;;;N;;;;;
+FF0E;FULLWIDTH FULL STOP;Po;0;CS;<wide> 002E;;;;N;FULLWIDTH PERIOD;;;;
+FF0F;FULLWIDTH SOLIDUS;Po;0;ES;<wide> 002F;;;;N;FULLWIDTH SLASH;;;;
+FF10;FULLWIDTH DIGIT ZERO;Nd;0;EN;<wide> 0030;0;0;0;N;;;;;
+FF11;FULLWIDTH DIGIT ONE;Nd;0;EN;<wide> 0031;1;1;1;N;;;;;
+FF12;FULLWIDTH DIGIT TWO;Nd;0;EN;<wide> 0032;2;2;2;N;;;;;
+FF13;FULLWIDTH DIGIT THREE;Nd;0;EN;<wide> 0033;3;3;3;N;;;;;
+FF14;FULLWIDTH DIGIT FOUR;Nd;0;EN;<wide> 0034;4;4;4;N;;;;;
+FF15;FULLWIDTH DIGIT FIVE;Nd;0;EN;<wide> 0035;5;5;5;N;;;;;
+FF16;FULLWIDTH DIGIT SIX;Nd;0;EN;<wide> 0036;6;6;6;N;;;;;
+FF17;FULLWIDTH DIGIT SEVEN;Nd;0;EN;<wide> 0037;7;7;7;N;;;;;
+FF18;FULLWIDTH DIGIT EIGHT;Nd;0;EN;<wide> 0038;8;8;8;N;;;;;
+FF19;FULLWIDTH DIGIT NINE;Nd;0;EN;<wide> 0039;9;9;9;N;;;;;
+FF1A;FULLWIDTH COLON;Po;0;CS;<wide> 003A;;;;N;;;;;
+FF1B;FULLWIDTH SEMICOLON;Po;0;ON;<wide> 003B;;;;N;;;;;
+FF1C;FULLWIDTH LESS-THAN SIGN;Sm;0;ON;<wide> 003C;;;;N;;;;;
+FF1D;FULLWIDTH EQUALS SIGN;Sm;0;ON;<wide> 003D;;;;N;;;;;
+FF1E;FULLWIDTH GREATER-THAN SIGN;Sm;0;ON;<wide> 003E;;;;N;;;;;
+FF1F;FULLWIDTH QUESTION MARK;Po;0;ON;<wide> 003F;;;;N;;;;;
+FF20;FULLWIDTH COMMERCIAL AT;Po;0;ON;<wide> 0040;;;;N;;;;;
+FF21;FULLWIDTH LATIN CAPITAL LETTER A;Lu;0;L;<wide> 0041;;;;N;;;;FF41;
+FF22;FULLWIDTH LATIN CAPITAL LETTER B;Lu;0;L;<wide> 0042;;;;N;;;;FF42;
+FF23;FULLWIDTH LATIN CAPITAL LETTER C;Lu;0;L;<wide> 0043;;;;N;;;;FF43;
+FF24;FULLWIDTH LATIN CAPITAL LETTER D;Lu;0;L;<wide> 0044;;;;N;;;;FF44;
+FF25;FULLWIDTH LATIN CAPITAL LETTER E;Lu;0;L;<wide> 0045;;;;N;;;;FF45;
+FF26;FULLWIDTH LATIN CAPITAL LETTER F;Lu;0;L;<wide> 0046;;;;N;;;;FF46;
+FF27;FULLWIDTH LATIN CAPITAL LETTER G;Lu;0;L;<wide> 0047;;;;N;;;;FF47;
+FF28;FULLWIDTH LATIN CAPITAL LETTER H;Lu;0;L;<wide> 0048;;;;N;;;;FF48;
+FF29;FULLWIDTH LATIN CAPITAL LETTER I;Lu;0;L;<wide> 0049;;;;N;;;;FF49;
+FF2A;FULLWIDTH LATIN CAPITAL LETTER J;Lu;0;L;<wide> 004A;;;;N;;;;FF4A;
+FF2B;FULLWIDTH LATIN CAPITAL LETTER K;Lu;0;L;<wide> 004B;;;;N;;;;FF4B;
+FF2C;FULLWIDTH LATIN CAPITAL LETTER L;Lu;0;L;<wide> 004C;;;;N;;;;FF4C;
+FF2D;FULLWIDTH LATIN CAPITAL LETTER M;Lu;0;L;<wide> 004D;;;;N;;;;FF4D;
+FF2E;FULLWIDTH LATIN CAPITAL LETTER N;Lu;0;L;<wide> 004E;;;;N;;;;FF4E;
+FF2F;FULLWIDTH LATIN CAPITAL LETTER O;Lu;0;L;<wide> 004F;;;;N;;;;FF4F;
+FF30;FULLWIDTH LATIN CAPITAL LETTER P;Lu;0;L;<wide> 0050;;;;N;;;;FF50;
+FF31;FULLWIDTH LATIN CAPITAL LETTER Q;Lu;0;L;<wide> 0051;;;;N;;;;FF51;
+FF32;FULLWIDTH LATIN CAPITAL LETTER R;Lu;0;L;<wide> 0052;;;;N;;;;FF52;
+FF33;FULLWIDTH LATIN CAPITAL LETTER S;Lu;0;L;<wide> 0053;;;;N;;;;FF53;
+FF34;FULLWIDTH LATIN CAPITAL LETTER T;Lu;0;L;<wide> 0054;;;;N;;;;FF54;
+FF35;FULLWIDTH LATIN CAPITAL LETTER U;Lu;0;L;<wide> 0055;;;;N;;;;FF55;
+FF36;FULLWIDTH LATIN CAPITAL LETTER V;Lu;0;L;<wide> 0056;;;;N;;;;FF56;
+FF37;FULLWIDTH LATIN CAPITAL LETTER W;Lu;0;L;<wide> 0057;;;;N;;;;FF57;
+FF38;FULLWIDTH LATIN CAPITAL LETTER X;Lu;0;L;<wide> 0058;;;;N;;;;FF58;
+FF39;FULLWIDTH LATIN CAPITAL LETTER Y;Lu;0;L;<wide> 0059;;;;N;;;;FF59;
+FF3A;FULLWIDTH LATIN CAPITAL LETTER Z;Lu;0;L;<wide> 005A;;;;N;;;;FF5A;
+FF3B;FULLWIDTH LEFT SQUARE BRACKET;Ps;0;ON;<wide> 005B;;;;N;FULLWIDTH OPENING SQUARE BRACKET;;;;
+FF3C;FULLWIDTH REVERSE SOLIDUS;Po;0;ON;<wide> 005C;;;;N;FULLWIDTH BACKSLASH;;;;
+FF3D;FULLWIDTH RIGHT SQUARE BRACKET;Pe;0;ON;<wide> 005D;;;;N;FULLWIDTH CLOSING SQUARE BRACKET;;;;
+FF3E;FULLWIDTH CIRCUMFLEX ACCENT;Sk;0;ON;<wide> 005E;;;;N;FULLWIDTH SPACING CIRCUMFLEX;;;;
+FF3F;FULLWIDTH LOW LINE;Pc;0;ON;<wide> 005F;;;;N;FULLWIDTH SPACING UNDERSCORE;;;;
+FF40;FULLWIDTH GRAVE ACCENT;Sk;0;ON;<wide> 0060;;;;N;FULLWIDTH SPACING GRAVE;;;;
+FF41;FULLWIDTH LATIN SMALL LETTER A;Ll;0;L;<wide> 0061;;;;N;;;FF21;;FF21
+FF42;FULLWIDTH LATIN SMALL LETTER B;Ll;0;L;<wide> 0062;;;;N;;;FF22;;FF22
+FF43;FULLWIDTH LATIN SMALL LETTER C;Ll;0;L;<wide> 0063;;;;N;;;FF23;;FF23
+FF44;FULLWIDTH LATIN SMALL LETTER D;Ll;0;L;<wide> 0064;;;;N;;;FF24;;FF24
+FF45;FULLWIDTH LATIN SMALL LETTER E;Ll;0;L;<wide> 0065;;;;N;;;FF25;;FF25
+FF46;FULLWIDTH LATIN SMALL LETTER F;Ll;0;L;<wide> 0066;;;;N;;;FF26;;FF26
+FF47;FULLWIDTH LATIN SMALL LETTER G;Ll;0;L;<wide> 0067;;;;N;;;FF27;;FF27
+FF48;FULLWIDTH LATIN SMALL LETTER H;Ll;0;L;<wide> 0068;;;;N;;;FF28;;FF28
+FF49;FULLWIDTH LATIN SMALL LETTER I;Ll;0;L;<wide> 0069;;;;N;;;FF29;;FF29
+FF4A;FULLWIDTH LATIN SMALL LETTER J;Ll;0;L;<wide> 006A;;;;N;;;FF2A;;FF2A
+FF4B;FULLWIDTH LATIN SMALL LETTER K;Ll;0;L;<wide> 006B;;;;N;;;FF2B;;FF2B
+FF4C;FULLWIDTH LATIN SMALL LETTER L;Ll;0;L;<wide> 006C;;;;N;;;FF2C;;FF2C
+FF4D;FULLWIDTH LATIN SMALL LETTER M;Ll;0;L;<wide> 006D;;;;N;;;FF2D;;FF2D
+FF4E;FULLWIDTH LATIN SMALL LETTER N;Ll;0;L;<wide> 006E;;;;N;;;FF2E;;FF2E
+FF4F;FULLWIDTH LATIN SMALL LETTER O;Ll;0;L;<wide> 006F;;;;N;;;FF2F;;FF2F
+FF50;FULLWIDTH LATIN SMALL LETTER P;Ll;0;L;<wide> 0070;;;;N;;;FF30;;FF30
+FF51;FULLWIDTH LATIN SMALL LETTER Q;Ll;0;L;<wide> 0071;;;;N;;;FF31;;FF31
+FF52;FULLWIDTH LATIN SMALL LETTER R;Ll;0;L;<wide> 0072;;;;N;;;FF32;;FF32
+FF53;FULLWIDTH LATIN SMALL LETTER S;Ll;0;L;<wide> 0073;;;;N;;;FF33;;FF33
+FF54;FULLWIDTH LATIN SMALL LETTER T;Ll;0;L;<wide> 0074;;;;N;;;FF34;;FF34
+FF55;FULLWIDTH LATIN SMALL LETTER U;Ll;0;L;<wide> 0075;;;;N;;;FF35;;FF35
+FF56;FULLWIDTH LATIN SMALL LETTER V;Ll;0;L;<wide> 0076;;;;N;;;FF36;;FF36
+FF57;FULLWIDTH LATIN SMALL LETTER W;Ll;0;L;<wide> 0077;;;;N;;;FF37;;FF37
+FF58;FULLWIDTH LATIN SMALL LETTER X;Ll;0;L;<wide> 0078;;;;N;;;FF38;;FF38
+FF59;FULLWIDTH LATIN SMALL LETTER Y;Ll;0;L;<wide> 0079;;;;N;;;FF39;;FF39
+FF5A;FULLWIDTH LATIN SMALL LETTER Z;Ll;0;L;<wide> 007A;;;;N;;;FF3A;;FF3A
+FF5B;FULLWIDTH LEFT CURLY BRACKET;Ps;0;ON;<wide> 007B;;;;N;FULLWIDTH OPENING CURLY BRACKET;;;;
+FF5C;FULLWIDTH VERTICAL LINE;Sm;0;ON;<wide> 007C;;;;N;FULLWIDTH VERTICAL BAR;;;;
+FF5D;FULLWIDTH RIGHT CURLY BRACKET;Pe;0;ON;<wide> 007D;;;;N;FULLWIDTH CLOSING CURLY BRACKET;;;;
+FF5E;FULLWIDTH TILDE;Sm;0;ON;<wide> 007E;;;;N;FULLWIDTH SPACING TILDE;;;;
+FF61;HALFWIDTH IDEOGRAPHIC FULL STOP;Po;0;ON;<narrow> 3002;;;;N;HALFWIDTH IDEOGRAPHIC PERIOD;;;;
+FF62;HALFWIDTH LEFT CORNER BRACKET;Ps;0;ON;<narrow> 300C;;;;N;HALFWIDTH OPENING CORNER BRACKET;;;;
+FF63;HALFWIDTH RIGHT CORNER BRACKET;Pe;0;ON;<narrow> 300D;;;;N;HALFWIDTH CLOSING CORNER BRACKET;;;;
+FF64;HALFWIDTH IDEOGRAPHIC COMMA;Po;0;ON;<narrow> 3001;;;;N;;;;;
+FF65;HALFWIDTH KATAKANA MIDDLE DOT;Pc;0;ON;<narrow> 30FB;;;;N;;;;;
+FF66;HALFWIDTH KATAKANA LETTER WO;Lo;0;L;<narrow> 30F2;;;;N;;;;;
+FF67;HALFWIDTH KATAKANA LETTER SMALL A;Lo;0;L;<narrow> 30A1;;;;N;;;;;
+FF68;HALFWIDTH KATAKANA LETTER SMALL I;Lo;0;L;<narrow> 30A3;;;;N;;;;;
+FF69;HALFWIDTH KATAKANA LETTER SMALL U;Lo;0;L;<narrow> 30A5;;;;N;;;;;
+FF6A;HALFWIDTH KATAKANA LETTER SMALL E;Lo;0;L;<narrow> 30A7;;;;N;;;;;
+FF6B;HALFWIDTH KATAKANA LETTER SMALL O;Lo;0;L;<narrow> 30A9;;;;N;;;;;
+FF6C;HALFWIDTH KATAKANA LETTER SMALL YA;Lo;0;L;<narrow> 30E3;;;;N;;;;;
+FF6D;HALFWIDTH KATAKANA LETTER SMALL YU;Lo;0;L;<narrow> 30E5;;;;N;;;;;
+FF6E;HALFWIDTH KATAKANA LETTER SMALL YO;Lo;0;L;<narrow> 30E7;;;;N;;;;;
+FF6F;HALFWIDTH KATAKANA LETTER SMALL TU;Lo;0;L;<narrow> 30C3;;;;N;;;;;
+FF70;HALFWIDTH KATAKANA-HIRAGANA PROLONGED SOUND MARK;Lm;0;L;<narrow> 30FC;;;;N;;;;;
+FF71;HALFWIDTH KATAKANA LETTER A;Lo;0;L;<narrow> 30A2;;;;N;;;;;
+FF72;HALFWIDTH KATAKANA LETTER I;Lo;0;L;<narrow> 30A4;;;;N;;;;;
+FF73;HALFWIDTH KATAKANA LETTER U;Lo;0;L;<narrow> 30A6;;;;N;;;;;
+FF74;HALFWIDTH KATAKANA LETTER E;Lo;0;L;<narrow> 30A8;;;;N;;;;;
+FF75;HALFWIDTH KATAKANA LETTER O;Lo;0;L;<narrow> 30AA;;;;N;;;;;
+FF76;HALFWIDTH KATAKANA LETTER KA;Lo;0;L;<narrow> 30AB;;;;N;;;;;
+FF77;HALFWIDTH KATAKANA LETTER KI;Lo;0;L;<narrow> 30AD;;;;N;;;;;
+FF78;HALFWIDTH KATAKANA LETTER KU;Lo;0;L;<narrow> 30AF;;;;N;;;;;
+FF79;HALFWIDTH KATAKANA LETTER KE;Lo;0;L;<narrow> 30B1;;;;N;;;;;
+FF7A;HALFWIDTH KATAKANA LETTER KO;Lo;0;L;<narrow> 30B3;;;;N;;;;;
+FF7B;HALFWIDTH KATAKANA LETTER SA;Lo;0;L;<narrow> 30B5;;;;N;;;;;
+FF7C;HALFWIDTH KATAKANA LETTER SI;Lo;0;L;<narrow> 30B7;;;;N;;;;;
+FF7D;HALFWIDTH KATAKANA LETTER SU;Lo;0;L;<narrow> 30B9;;;;N;;;;;
+FF7E;HALFWIDTH KATAKANA LETTER SE;Lo;0;L;<narrow> 30BB;;;;N;;;;;
+FF7F;HALFWIDTH KATAKANA LETTER SO;Lo;0;L;<narrow> 30BD;;;;N;;;;;
+FF80;HALFWIDTH KATAKANA LETTER TA;Lo;0;L;<narrow> 30BF;;;;N;;;;;
+FF81;HALFWIDTH KATAKANA LETTER TI;Lo;0;L;<narrow> 30C1;;;;N;;;;;
+FF82;HALFWIDTH KATAKANA LETTER TU;Lo;0;L;<narrow> 30C4;;;;N;;;;;
+FF83;HALFWIDTH KATAKANA LETTER TE;Lo;0;L;<narrow> 30C6;;;;N;;;;;
+FF84;HALFWIDTH KATAKANA LETTER TO;Lo;0;L;<narrow> 30C8;;;;N;;;;;
+FF85;HALFWIDTH KATAKANA LETTER NA;Lo;0;L;<narrow> 30CA;;;;N;;;;;
+FF86;HALFWIDTH KATAKANA LETTER NI;Lo;0;L;<narrow> 30CB;;;;N;;;;;
+FF87;HALFWIDTH KATAKANA LETTER NU;Lo;0;L;<narrow> 30CC;;;;N;;;;;
+FF88;HALFWIDTH KATAKANA LETTER NE;Lo;0;L;<narrow> 30CD;;;;N;;;;;
+FF89;HALFWIDTH KATAKANA LETTER NO;Lo;0;L;<narrow> 30CE;;;;N;;;;;
+FF8A;HALFWIDTH KATAKANA LETTER HA;Lo;0;L;<narrow> 30CF;;;;N;;;;;
+FF8B;HALFWIDTH KATAKANA LETTER HI;Lo;0;L;<narrow> 30D2;;;;N;;;;;
+FF8C;HALFWIDTH KATAKANA LETTER HU;Lo;0;L;<narrow> 30D5;;;;N;;;;;
+FF8D;HALFWIDTH KATAKANA LETTER HE;Lo;0;L;<narrow> 30D8;;;;N;;;;;
+FF8E;HALFWIDTH KATAKANA LETTER HO;Lo;0;L;<narrow> 30DB;;;;N;;;;;
+FF8F;HALFWIDTH KATAKANA LETTER MA;Lo;0;L;<narrow> 30DE;;;;N;;;;;
+FF90;HALFWIDTH KATAKANA LETTER MI;Lo;0;L;<narrow> 30DF;;;;N;;;;;
+FF91;HALFWIDTH KATAKANA LETTER MU;Lo;0;L;<narrow> 30E0;;;;N;;;;;
+FF92;HALFWIDTH KATAKANA LETTER ME;Lo;0;L;<narrow> 30E1;;;;N;;;;;
+FF93;HALFWIDTH KATAKANA LETTER MO;Lo;0;L;<narrow> 30E2;;;;N;;;;;
+FF94;HALFWIDTH KATAKANA LETTER YA;Lo;0;L;<narrow> 30E4;;;;N;;;;;
+FF95;HALFWIDTH KATAKANA LETTER YU;Lo;0;L;<narrow> 30E6;;;;N;;;;;
+FF96;HALFWIDTH KATAKANA LETTER YO;Lo;0;L;<narrow> 30E8;;;;N;;;;;
+FF97;HALFWIDTH KATAKANA LETTER RA;Lo;0;L;<narrow> 30E9;;;;N;;;;;
+FF98;HALFWIDTH KATAKANA LETTER RI;Lo;0;L;<narrow> 30EA;;;;N;;;;;
+FF99;HALFWIDTH KATAKANA LETTER RU;Lo;0;L;<narrow> 30EB;;;;N;;;;;
+FF9A;HALFWIDTH KATAKANA LETTER RE;Lo;0;L;<narrow> 30EC;;;;N;;;;;
+FF9B;HALFWIDTH KATAKANA LETTER RO;Lo;0;L;<narrow> 30ED;;;;N;;;;;
+FF9C;HALFWIDTH KATAKANA LETTER WA;Lo;0;L;<narrow> 30EF;;;;N;;;;;
+FF9D;HALFWIDTH KATAKANA LETTER N;Lo;0;L;<narrow> 30F3;;;;N;;;;;
+FF9E;HALFWIDTH KATAKANA VOICED SOUND MARK;Lm;0;L;<narrow> 3099;;;;N;;halfwidth katakana-hiragana voiced sound mark;;;
+FF9F;HALFWIDTH KATAKANA SEMI-VOICED SOUND MARK;Lm;0;L;<narrow> 309A;;;;N;;halfwidth katakana-hiragana semi-voiced sound mark;;;
+FFA0;HALFWIDTH HANGUL FILLER;Lo;0;L;<narrow> 3164;;;;N;HALFWIDTH HANGUL CAE OM;;;;
+FFA1;HALFWIDTH HANGUL LETTER KIYEOK;Lo;0;L;<narrow> 3131;;;;N;HALFWIDTH HANGUL LETTER GIYEOG;;;;
+FFA2;HALFWIDTH HANGUL LETTER SSANGKIYEOK;Lo;0;L;<narrow> 3132;;;;N;HALFWIDTH HANGUL LETTER SSANG GIYEOG;;;;
+FFA3;HALFWIDTH HANGUL LETTER KIYEOK-SIOS;Lo;0;L;<narrow> 3133;;;;N;HALFWIDTH HANGUL LETTER GIYEOG SIOS;;;;
+FFA4;HALFWIDTH HANGUL LETTER NIEUN;Lo;0;L;<narrow> 3134;;;;N;;;;;
+FFA5;HALFWIDTH HANGUL LETTER NIEUN-CIEUC;Lo;0;L;<narrow> 3135;;;;N;HALFWIDTH HANGUL LETTER NIEUN JIEUJ;;;;
+FFA6;HALFWIDTH HANGUL LETTER NIEUN-HIEUH;Lo;0;L;<narrow> 3136;;;;N;HALFWIDTH HANGUL LETTER NIEUN HIEUH;;;;
+FFA7;HALFWIDTH HANGUL LETTER TIKEUT;Lo;0;L;<narrow> 3137;;;;N;HALFWIDTH HANGUL LETTER DIGEUD;;;;
+FFA8;HALFWIDTH HANGUL LETTER SSANGTIKEUT;Lo;0;L;<narrow> 3138;;;;N;HALFWIDTH HANGUL LETTER SSANG DIGEUD;;;;
+FFA9;HALFWIDTH HANGUL LETTER RIEUL;Lo;0;L;<narrow> 3139;;;;N;HALFWIDTH HANGUL LETTER LIEUL;;;;
+FFAA;HALFWIDTH HANGUL LETTER RIEUL-KIYEOK;Lo;0;L;<narrow> 313A;;;;N;HALFWIDTH HANGUL LETTER LIEUL GIYEOG;;;;
+FFAB;HALFWIDTH HANGUL LETTER RIEUL-MIEUM;Lo;0;L;<narrow> 313B;;;;N;HALFWIDTH HANGUL LETTER LIEUL MIEUM;;;;
+FFAC;HALFWIDTH HANGUL LETTER RIEUL-PIEUP;Lo;0;L;<narrow> 313C;;;;N;HALFWIDTH HANGUL LETTER LIEUL BIEUB;;;;
+FFAD;HALFWIDTH HANGUL LETTER RIEUL-SIOS;Lo;0;L;<narrow> 313D;;;;N;HALFWIDTH HANGUL LETTER LIEUL SIOS;;;;
+FFAE;HALFWIDTH HANGUL LETTER RIEUL-THIEUTH;Lo;0;L;<narrow> 313E;;;;N;HALFWIDTH HANGUL LETTER LIEUL TIEUT;;;;
+FFAF;HALFWIDTH HANGUL LETTER RIEUL-PHIEUPH;Lo;0;L;<narrow> 313F;;;;N;HALFWIDTH HANGUL LETTER LIEUL PIEUP;;;;
+FFB0;HALFWIDTH HANGUL LETTER RIEUL-HIEUH;Lo;0;L;<narrow> 3140;;;;N;HALFWIDTH HANGUL LETTER LIEUL HIEUH;;;;
+FFB1;HALFWIDTH HANGUL LETTER MIEUM;Lo;0;L;<narrow> 3141;;;;N;;;;;
+FFB2;HALFWIDTH HANGUL LETTER PIEUP;Lo;0;L;<narrow> 3142;;;;N;HALFWIDTH HANGUL LETTER BIEUB;;;;
+FFB3;HALFWIDTH HANGUL LETTER SSANGPIEUP;Lo;0;L;<narrow> 3143;;;;N;HALFWIDTH HANGUL LETTER SSANG BIEUB;;;;
+FFB4;HALFWIDTH HANGUL LETTER PIEUP-SIOS;Lo;0;L;<narrow> 3144;;;;N;HALFWIDTH HANGUL LETTER BIEUB SIOS;;;;
+FFB5;HALFWIDTH HANGUL LETTER SIOS;Lo;0;L;<narrow> 3145;;;;N;;;;;
+FFB6;HALFWIDTH HANGUL LETTER SSANGSIOS;Lo;0;L;<narrow> 3146;;;;N;HALFWIDTH HANGUL LETTER SSANG SIOS;;;;
+FFB7;HALFWIDTH HANGUL LETTER IEUNG;Lo;0;L;<narrow> 3147;;;;N;;;;;
+FFB8;HALFWIDTH HANGUL LETTER CIEUC;Lo;0;L;<narrow> 3148;;;;N;HALFWIDTH HANGUL LETTER JIEUJ;;;;
+FFB9;HALFWIDTH HANGUL LETTER SSANGCIEUC;Lo;0;L;<narrow> 3149;;;;N;HALFWIDTH HANGUL LETTER SSANG JIEUJ;;;;
+FFBA;HALFWIDTH HANGUL LETTER CHIEUCH;Lo;0;L;<narrow> 314A;;;;N;HALFWIDTH HANGUL LETTER CIEUC;;;;
+FFBB;HALFWIDTH HANGUL LETTER KHIEUKH;Lo;0;L;<narrow> 314B;;;;N;HALFWIDTH HANGUL LETTER KIYEOK;;;;
+FFBC;HALFWIDTH HANGUL LETTER THIEUTH;Lo;0;L;<narrow> 314C;;;;N;HALFWIDTH HANGUL LETTER TIEUT;;;;
+FFBD;HALFWIDTH HANGUL LETTER PHIEUPH;Lo;0;L;<narrow> 314D;;;;N;HALFWIDTH HANGUL LETTER PIEUP;;;;
+FFBE;HALFWIDTH HANGUL LETTER HIEUH;Lo;0;L;<narrow> 314E;;;;N;;;;;
+FFC2;HALFWIDTH HANGUL LETTER A;Lo;0;L;<narrow> 314F;;;;N;;;;;
+FFC3;HALFWIDTH HANGUL LETTER AE;Lo;0;L;<narrow> 3150;;;;N;;;;;
+FFC4;HALFWIDTH HANGUL LETTER YA;Lo;0;L;<narrow> 3151;;;;N;;;;;
+FFC5;HALFWIDTH HANGUL LETTER YAE;Lo;0;L;<narrow> 3152;;;;N;;;;;
+FFC6;HALFWIDTH HANGUL LETTER EO;Lo;0;L;<narrow> 3153;;;;N;;;;;
+FFC7;HALFWIDTH HANGUL LETTER E;Lo;0;L;<narrow> 3154;;;;N;;;;;
+FFCA;HALFWIDTH HANGUL LETTER YEO;Lo;0;L;<narrow> 3155;;;;N;;;;;
+FFCB;HALFWIDTH HANGUL LETTER YE;Lo;0;L;<narrow> 3156;;;;N;;;;;
+FFCC;HALFWIDTH HANGUL LETTER O;Lo;0;L;<narrow> 3157;;;;N;;;;;
+FFCD;HALFWIDTH HANGUL LETTER WA;Lo;0;L;<narrow> 3158;;;;N;;;;;
+FFCE;HALFWIDTH HANGUL LETTER WAE;Lo;0;L;<narrow> 3159;;;;N;;;;;
+FFCF;HALFWIDTH HANGUL LETTER OE;Lo;0;L;<narrow> 315A;;;;N;;;;;
+FFD2;HALFWIDTH HANGUL LETTER YO;Lo;0;L;<narrow> 315B;;;;N;;;;;
+FFD3;HALFWIDTH HANGUL LETTER U;Lo;0;L;<narrow> 315C;;;;N;;;;;
+FFD4;HALFWIDTH HANGUL LETTER WEO;Lo;0;L;<narrow> 315D;;;;N;;;;;
+FFD5;HALFWIDTH HANGUL LETTER WE;Lo;0;L;<narrow> 315E;;;;N;;;;;
+FFD6;HALFWIDTH HANGUL LETTER WI;Lo;0;L;<narrow> 315F;;;;N;;;;;
+FFD7;HALFWIDTH HANGUL LETTER YU;Lo;0;L;<narrow> 3160;;;;N;;;;;
+FFDA;HALFWIDTH HANGUL LETTER EU;Lo;0;L;<narrow> 3161;;;;N;;;;;
+FFDB;HALFWIDTH HANGUL LETTER YI;Lo;0;L;<narrow> 3162;;;;N;;;;;
+FFDC;HALFWIDTH HANGUL LETTER I;Lo;0;L;<narrow> 3163;;;;N;;;;;
+FFE0;FULLWIDTH CENT SIGN;Sc;0;ET;<wide> 00A2;;;;N;;;;;
+FFE1;FULLWIDTH POUND SIGN;Sc;0;ET;<wide> 00A3;;;;N;;;;;
+FFE2;FULLWIDTH NOT SIGN;Sm;0;ON;<wide> 00AC;;;;N;;;;;
+FFE3;FULLWIDTH MACRON;Sk;0;ON;<wide> 00AF;;;;N;FULLWIDTH SPACING MACRON;*;;;
+FFE4;FULLWIDTH BROKEN BAR;So;0;ON;<wide> 00A6;;;;N;FULLWIDTH BROKEN VERTICAL BAR;;;;
+FFE5;FULLWIDTH YEN SIGN;Sc;0;ET;<wide> 00A5;;;;N;;;;;
+FFE6;FULLWIDTH WON SIGN;Sc;0;ET;<wide> 20A9;;;;N;;;;;
+FFE8;HALFWIDTH FORMS LIGHT VERTICAL;So;0;ON;<narrow> 2502;;;;N;;;;;
+FFE9;HALFWIDTH LEFTWARDS ARROW;Sm;0;ON;<narrow> 2190;;;;N;;;;;
+FFEA;HALFWIDTH UPWARDS ARROW;Sm;0;ON;<narrow> 2191;;;;N;;;;;
+FFEB;HALFWIDTH RIGHTWARDS ARROW;Sm;0;ON;<narrow> 2192;;;;N;;;;;
+FFEC;HALFWIDTH DOWNWARDS ARROW;Sm;0;ON;<narrow> 2193;;;;N;;;;;
+FFED;HALFWIDTH BLACK SQUARE;So;0;ON;<narrow> 25A0;;;;N;;;;;
+FFEE;HALFWIDTH WHITE CIRCLE;So;0;ON;<narrow> 25CB;;;;N;;;;;
+FFF9;INTERLINEAR ANNOTATION ANCHOR;Cf;0;BN;;;;;N;;;;;
+FFFA;INTERLINEAR ANNOTATION SEPARATOR;Cf;0;BN;;;;;N;;;;;
+FFFB;INTERLINEAR ANNOTATION TERMINATOR;Cf;0;BN;;;;;N;;;;;
+FFFC;OBJECT REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
+FFFD;REPLACEMENT CHARACTER;So;0;ON;;;;;N;;;;;
+10300;OLD ITALIC LETTER A;Lo;0;L;;;;;N;;;;;
+10301;OLD ITALIC LETTER BE;Lo;0;L;;;;;N;;;;;
+10302;OLD ITALIC LETTER KE;Lo;0;L;;;;;N;;;;;
+10303;OLD ITALIC LETTER DE;Lo;0;L;;;;;N;;;;;
+10304;OLD ITALIC LETTER E;Lo;0;L;;;;;N;;;;;
+10305;OLD ITALIC LETTER VE;Lo;0;L;;;;;N;;;;;
+10306;OLD ITALIC LETTER ZE;Lo;0;L;;;;;N;;;;;
+10307;OLD ITALIC LETTER HE;Lo;0;L;;;;;N;;;;;
+10308;OLD ITALIC LETTER THE;Lo;0;L;;;;;N;;;;;
+10309;OLD ITALIC LETTER I;Lo;0;L;;;;;N;;;;;
+1030A;OLD ITALIC LETTER KA;Lo;0;L;;;;;N;;;;;
+1030B;OLD ITALIC LETTER EL;Lo;0;L;;;;;N;;;;;
+1030C;OLD ITALIC LETTER EM;Lo;0;L;;;;;N;;;;;
+1030D;OLD ITALIC LETTER EN;Lo;0;L;;;;;N;;;;;
+1030E;OLD ITALIC LETTER ESH;Lo;0;L;;;;;N;;;;;
+1030F;OLD ITALIC LETTER O;Lo;0;L;;;;;N;;Faliscan;;;
+10310;OLD ITALIC LETTER PE;Lo;0;L;;;;;N;;;;;
+10311;OLD ITALIC LETTER SHE;Lo;0;L;;;;;N;;;;;
+10312;OLD ITALIC LETTER KU;Lo;0;L;;;;;N;;;;;
+10313;OLD ITALIC LETTER ER;Lo;0;L;;;;;N;;;;;
+10314;OLD ITALIC LETTER ES;Lo;0;L;;;;;N;;;;;
+10315;OLD ITALIC LETTER TE;Lo;0;L;;;;;N;;;;;
+10316;OLD ITALIC LETTER U;Lo;0;L;;;;;N;;;;;
+10317;OLD ITALIC LETTER EKS;Lo;0;L;;;;;N;;Faliscan;;;
+10318;OLD ITALIC LETTER PHE;Lo;0;L;;;;;N;;;;;
+10319;OLD ITALIC LETTER KHE;Lo;0;L;;;;;N;;;;;
+1031A;OLD ITALIC LETTER EF;Lo;0;L;;;;;N;;;;;
+1031B;OLD ITALIC LETTER ERS;Lo;0;L;;;;;N;;Umbrian;;;
+1031C;OLD ITALIC LETTER CHE;Lo;0;L;;;;;N;;Umbrian;;;
+1031D;OLD ITALIC LETTER II;Lo;0;L;;;;;N;;Oscan;;;
+1031E;OLD ITALIC LETTER UU;Lo;0;L;;;;;N;;Oscan;;;
+10320;OLD ITALIC NUMERAL ONE;No;0;L;;;;1;N;;;;;
+10321;OLD ITALIC NUMERAL FIVE;No;0;L;;;;5;N;;;;;
+10322;OLD ITALIC NUMERAL TEN;No;0;L;;;;10;N;;;;;
+10323;OLD ITALIC NUMERAL FIFTY;No;0;L;;;;50;N;;;;;
+10330;GOTHIC LETTER AHSA;Lo;0;L;;;;;N;;;;;
+10331;GOTHIC LETTER BAIRKAN;Lo;0;L;;;;;N;;;;;
+10332;GOTHIC LETTER GIBA;Lo;0;L;;;;;N;;;;;
+10333;GOTHIC LETTER DAGS;Lo;0;L;;;;;N;;;;;
+10334;GOTHIC LETTER AIHVUS;Lo;0;L;;;;;N;;;;;
+10335;GOTHIC LETTER QAIRTHRA;Lo;0;L;;;;;N;;;;;
+10336;GOTHIC LETTER IUJA;Lo;0;L;;;;;N;;;;;
+10337;GOTHIC LETTER HAGL;Lo;0;L;;;;;N;;;;;
+10338;GOTHIC LETTER THIUTH;Lo;0;L;;;;;N;;;;;
+10339;GOTHIC LETTER EIS;Lo;0;L;;;;;N;;;;;
+1033A;GOTHIC LETTER KUSMA;Lo;0;L;;;;;N;;;;;
+1033B;GOTHIC LETTER LAGUS;Lo;0;L;;;;;N;;;;;
+1033C;GOTHIC LETTER MANNA;Lo;0;L;;;;;N;;;;;
+1033D;GOTHIC LETTER NAUTHS;Lo;0;L;;;;;N;;;;;
+1033E;GOTHIC LETTER JER;Lo;0;L;;;;;N;;;;;
+1033F;GOTHIC LETTER URUS;Lo;0;L;;;;;N;;;;;
+10340;GOTHIC LETTER PAIRTHRA;Lo;0;L;;;;;N;;;;;
+10341;GOTHIC LETTER NINETY;Lo;0;L;;;;;N;;;;;
+10342;GOTHIC LETTER RAIDA;Lo;0;L;;;;;N;;;;;
+10343;GOTHIC LETTER SAUIL;Lo;0;L;;;;;N;;;;;
+10344;GOTHIC LETTER TEIWS;Lo;0;L;;;;;N;;;;;
+10345;GOTHIC LETTER WINJA;Lo;0;L;;;;;N;;;;;
+10346;GOTHIC LETTER FAIHU;Lo;0;L;;;;;N;;;;;
+10347;GOTHIC LETTER IGGWS;Lo;0;L;;;;;N;;;;;
+10348;GOTHIC LETTER HWAIR;Lo;0;L;;;;;N;;;;;
+10349;GOTHIC LETTER OTHAL;Lo;0;L;;;;;N;;;;;
+1034A;GOTHIC LETTER NINE HUNDRED;Nl;0;L;;;;;N;;;;;
+10400;DESERET CAPITAL LETTER LONG I;Lu;0;L;;;;;N;;;;10428;
+10401;DESERET CAPITAL LETTER LONG E;Lu;0;L;;;;;N;;;;10429;
+10402;DESERET CAPITAL LETTER LONG A;Lu;0;L;;;;;N;;;;1042A;
+10403;DESERET CAPITAL LETTER LONG AH;Lu;0;L;;;;;N;;;;1042B;
+10404;DESERET CAPITAL LETTER LONG O;Lu;0;L;;;;;N;;;;1042C;
+10405;DESERET CAPITAL LETTER LONG OO;Lu;0;L;;;;;N;;;;1042D;
+10406;DESERET CAPITAL LETTER SHORT I;Lu;0;L;;;;;N;;;;1042E;
+10407;DESERET CAPITAL LETTER SHORT E;Lu;0;L;;;;;N;;;;1042F;
+10408;DESERET CAPITAL LETTER SHORT A;Lu;0;L;;;;;N;;;;10430;
+10409;DESERET CAPITAL LETTER SHORT AH;Lu;0;L;;;;;N;;;;10431;
+1040A;DESERET CAPITAL LETTER SHORT O;Lu;0;L;;;;;N;;;;10432;
+1040B;DESERET CAPITAL LETTER SHORT OO;Lu;0;L;;;;;N;;;;10433;
+1040C;DESERET CAPITAL LETTER AY;Lu;0;L;;;;;N;;;;10434;
+1040D;DESERET CAPITAL LETTER OW;Lu;0;L;;;;;N;;;;10435;
+1040E;DESERET CAPITAL LETTER WU;Lu;0;L;;;;;N;;;;10436;
+1040F;DESERET CAPITAL LETTER YEE;Lu;0;L;;;;;N;;;;10437;
+10410;DESERET CAPITAL LETTER H;Lu;0;L;;;;;N;;;;10438;
+10411;DESERET CAPITAL LETTER PEE;Lu;0;L;;;;;N;;;;10439;
+10412;DESERET CAPITAL LETTER BEE;Lu;0;L;;;;;N;;;;1043A;
+10413;DESERET CAPITAL LETTER TEE;Lu;0;L;;;;;N;;;;1043B;
+10414;DESERET CAPITAL LETTER DEE;Lu;0;L;;;;;N;;;;1043C;
+10415;DESERET CAPITAL LETTER CHEE;Lu;0;L;;;;;N;;;;1043D;
+10416;DESERET CAPITAL LETTER JEE;Lu;0;L;;;;;N;;;;1043E;
+10417;DESERET CAPITAL LETTER KAY;Lu;0;L;;;;;N;;;;1043F;
+10418;DESERET CAPITAL LETTER GAY;Lu;0;L;;;;;N;;;;10440;
+10419;DESERET CAPITAL LETTER EF;Lu;0;L;;;;;N;;;;10441;
+1041A;DESERET CAPITAL LETTER VEE;Lu;0;L;;;;;N;;;;10442;
+1041B;DESERET CAPITAL LETTER ETH;Lu;0;L;;;;;N;;;;10443;
+1041C;DESERET CAPITAL LETTER THEE;Lu;0;L;;;;;N;;;;10444;
+1041D;DESERET CAPITAL LETTER ES;Lu;0;L;;;;;N;;;;10445;
+1041E;DESERET CAPITAL LETTER ZEE;Lu;0;L;;;;;N;;;;10446;
+1041F;DESERET CAPITAL LETTER ESH;Lu;0;L;;;;;N;;;;10447;
+10420;DESERET CAPITAL LETTER ZHEE;Lu;0;L;;;;;N;;;;10448;
+10421;DESERET CAPITAL LETTER ER;Lu;0;L;;;;;N;;;;10449;
+10422;DESERET CAPITAL LETTER EL;Lu;0;L;;;;;N;;;;1044A;
+10423;DESERET CAPITAL LETTER EM;Lu;0;L;;;;;N;;;;1044B;
+10424;DESERET CAPITAL LETTER EN;Lu;0;L;;;;;N;;;;1044C;
+10425;DESERET CAPITAL LETTER ENG;Lu;0;L;;;;;N;;;;1044D;
+10428;DESERET SMALL LETTER LONG I;Ll;0;L;;;;;N;;;10400;;10400
+10429;DESERET SMALL LETTER LONG E;Ll;0;L;;;;;N;;;10401;;10401
+1042A;DESERET SMALL LETTER LONG A;Ll;0;L;;;;;N;;;10402;;10402
+1042B;DESERET SMALL LETTER LONG AH;Ll;0;L;;;;;N;;;10403;;10403
+1042C;DESERET SMALL LETTER LONG O;Ll;0;L;;;;;N;;;10404;;10404
+1042D;DESERET SMALL LETTER LONG OO;Ll;0;L;;;;;N;;;10405;;10405
+1042E;DESERET SMALL LETTER SHORT I;Ll;0;L;;;;;N;;;10406;;10406
+1042F;DESERET SMALL LETTER SHORT E;Ll;0;L;;;;;N;;;10407;;10407
+10430;DESERET SMALL LETTER SHORT A;Ll;0;L;;;;;N;;;10408;;10408
+10431;DESERET SMALL LETTER SHORT AH;Ll;0;L;;;;;N;;;10409;;10409
+10432;DESERET SMALL LETTER SHORT O;Ll;0;L;;;;;N;;;1040A;;1040A
+10433;DESERET SMALL LETTER SHORT OO;Ll;0;L;;;;;N;;;1040B;;1040B
+10434;DESERET SMALL LETTER AY;Ll;0;L;;;;;N;;;1040C;;1040C
+10435;DESERET SMALL LETTER OW;Ll;0;L;;;;;N;;;1040D;;1040D
+10436;DESERET SMALL LETTER WU;Ll;0;L;;;;;N;;;1040E;;1040E
+10437;DESERET SMALL LETTER YEE;Ll;0;L;;;;;N;;;1040F;;1040F
+10438;DESERET SMALL LETTER H;Ll;0;L;;;;;N;;;10410;;10410
+10439;DESERET SMALL LETTER PEE;Ll;0;L;;;;;N;;;10411;;10411
+1043A;DESERET SMALL LETTER BEE;Ll;0;L;;;;;N;;;10412;;10412
+1043B;DESERET SMALL LETTER TEE;Ll;0;L;;;;;N;;;10413;;10413
+1043C;DESERET SMALL LETTER DEE;Ll;0;L;;;;;N;;;10414;;10414
+1043D;DESERET SMALL LETTER CHEE;Ll;0;L;;;;;N;;;10415;;10415
+1043E;DESERET SMALL LETTER JEE;Ll;0;L;;;;;N;;;10416;;10416
+1043F;DESERET SMALL LETTER KAY;Ll;0;L;;;;;N;;;10417;;10417
+10440;DESERET SMALL LETTER GAY;Ll;0;L;;;;;N;;;10418;;10418
+10441;DESERET SMALL LETTER EF;Ll;0;L;;;;;N;;;10419;;10419
+10442;DESERET SMALL LETTER VEE;Ll;0;L;;;;;N;;;1041A;;1041A
+10443;DESERET SMALL LETTER ETH;Ll;0;L;;;;;N;;;1041B;;1041B
+10444;DESERET SMALL LETTER THEE;Ll;0;L;;;;;N;;;1041C;;1041C
+10445;DESERET SMALL LETTER ES;Ll;0;L;;;;;N;;;1041D;;1041D
+10446;DESERET SMALL LETTER ZEE;Ll;0;L;;;;;N;;;1041E;;1041E
+10447;DESERET SMALL LETTER ESH;Ll;0;L;;;;;N;;;1041F;;1041F
+10448;DESERET SMALL LETTER ZHEE;Ll;0;L;;;;;N;;;10420;;10420
+10449;DESERET SMALL LETTER ER;Ll;0;L;;;;;N;;;10421;;10421
+1044A;DESERET SMALL LETTER EL;Ll;0;L;;;;;N;;;10422;;10422
+1044B;DESERET SMALL LETTER EM;Ll;0;L;;;;;N;;;10423;;10423
+1044C;DESERET SMALL LETTER EN;Ll;0;L;;;;;N;;;10424;;10424
+1044D;DESERET SMALL LETTER ENG;Ll;0;L;;;;;N;;;10425;;10425
+1D000;BYZANTINE MUSICAL SYMBOL PSILI;So;0;L;;;;;N;;;;;
+1D001;BYZANTINE MUSICAL SYMBOL DASEIA;So;0;L;;;;;N;;;;;
+1D002;BYZANTINE MUSICAL SYMBOL PERISPOMENI;So;0;L;;;;;N;;;;;
+1D003;BYZANTINE MUSICAL SYMBOL OXEIA EKFONITIKON;So;0;L;;;;;N;;;;;
+1D004;BYZANTINE MUSICAL SYMBOL OXEIA DIPLI;So;0;L;;;;;N;;;;;
+1D005;BYZANTINE MUSICAL SYMBOL VAREIA EKFONITIKON;So;0;L;;;;;N;;;;;
+1D006;BYZANTINE MUSICAL SYMBOL VAREIA DIPLI;So;0;L;;;;;N;;;;;
+1D007;BYZANTINE MUSICAL SYMBOL KATHISTI;So;0;L;;;;;N;;;;;
+1D008;BYZANTINE MUSICAL SYMBOL SYRMATIKI;So;0;L;;;;;N;;;;;
+1D009;BYZANTINE MUSICAL SYMBOL PARAKLITIKI;So;0;L;;;;;N;;;;;
+1D00A;BYZANTINE MUSICAL SYMBOL YPOKRISIS;So;0;L;;;;;N;;;;;
+1D00B;BYZANTINE MUSICAL SYMBOL YPOKRISIS DIPLI;So;0;L;;;;;N;;;;;
+1D00C;BYZANTINE MUSICAL SYMBOL KREMASTI;So;0;L;;;;;N;;;;;
+1D00D;BYZANTINE MUSICAL SYMBOL APESO EKFONITIKON;So;0;L;;;;;N;;;;;
+1D00E;BYZANTINE MUSICAL SYMBOL EXO EKFONITIKON;So;0;L;;;;;N;;;;;
+1D00F;BYZANTINE MUSICAL SYMBOL TELEIA;So;0;L;;;;;N;;;;;
+1D010;BYZANTINE MUSICAL SYMBOL KENTIMATA;So;0;L;;;;;N;;;;;
+1D011;BYZANTINE MUSICAL SYMBOL APOSTROFOS;So;0;L;;;;;N;;;;;
+1D012;BYZANTINE MUSICAL SYMBOL APOSTROFOS DIPLI;So;0;L;;;;;N;;;;;
+1D013;BYZANTINE MUSICAL SYMBOL SYNEVMA;So;0;L;;;;;N;;;;;
+1D014;BYZANTINE MUSICAL SYMBOL THITA;So;0;L;;;;;N;;;;;
+1D015;BYZANTINE MUSICAL SYMBOL OLIGON ARCHAION;So;0;L;;;;;N;;;;;
+1D016;BYZANTINE MUSICAL SYMBOL GORGON ARCHAION;So;0;L;;;;;N;;;;;
+1D017;BYZANTINE MUSICAL SYMBOL PSILON;So;0;L;;;;;N;;;;;
+1D018;BYZANTINE MUSICAL SYMBOL CHAMILON;So;0;L;;;;;N;;;;;
+1D019;BYZANTINE MUSICAL SYMBOL VATHY;So;0;L;;;;;N;;;;;
+1D01A;BYZANTINE MUSICAL SYMBOL ISON ARCHAION;So;0;L;;;;;N;;;;;
+1D01B;BYZANTINE MUSICAL SYMBOL KENTIMA ARCHAION;So;0;L;;;;;N;;;;;
+1D01C;BYZANTINE MUSICAL SYMBOL KENTIMATA ARCHAION;So;0;L;;;;;N;;;;;
+1D01D;BYZANTINE MUSICAL SYMBOL SAXIMATA;So;0;L;;;;;N;;;;;
+1D01E;BYZANTINE MUSICAL SYMBOL PARICHON;So;0;L;;;;;N;;;;;
+1D01F;BYZANTINE MUSICAL SYMBOL STAVROS APODEXIA;So;0;L;;;;;N;;;;;
+1D020;BYZANTINE MUSICAL SYMBOL OXEIAI ARCHAION;So;0;L;;;;;N;;;;;
+1D021;BYZANTINE MUSICAL SYMBOL VAREIAI ARCHAION;So;0;L;;;;;N;;;;;
+1D022;BYZANTINE MUSICAL SYMBOL APODERMA ARCHAION;So;0;L;;;;;N;;;;;
+1D023;BYZANTINE MUSICAL SYMBOL APOTHEMA;So;0;L;;;;;N;;;;;
+1D024;BYZANTINE MUSICAL SYMBOL KLASMA;So;0;L;;;;;N;;;;;
+1D025;BYZANTINE MUSICAL SYMBOL REVMA;So;0;L;;;;;N;;;;;
+1D026;BYZANTINE MUSICAL SYMBOL PIASMA ARCHAION;So;0;L;;;;;N;;;;;
+1D027;BYZANTINE MUSICAL SYMBOL TINAGMA;So;0;L;;;;;N;;;;;
+1D028;BYZANTINE MUSICAL SYMBOL ANATRICHISMA;So;0;L;;;;;N;;;;;
+1D029;BYZANTINE MUSICAL SYMBOL SEISMA;So;0;L;;;;;N;;;;;
+1D02A;BYZANTINE MUSICAL SYMBOL SYNAGMA ARCHAION;So;0;L;;;;;N;;;;;
+1D02B;BYZANTINE MUSICAL SYMBOL SYNAGMA META STAVROU;So;0;L;;;;;N;;;;;
+1D02C;BYZANTINE MUSICAL SYMBOL OYRANISMA ARCHAION;So;0;L;;;;;N;;;;;
+1D02D;BYZANTINE MUSICAL SYMBOL THEMA;So;0;L;;;;;N;;;;;
+1D02E;BYZANTINE MUSICAL SYMBOL LEMOI;So;0;L;;;;;N;;;;;
+1D02F;BYZANTINE MUSICAL SYMBOL DYO;So;0;L;;;;;N;;;;;
+1D030;BYZANTINE MUSICAL SYMBOL TRIA;So;0;L;;;;;N;;;;;
+1D031;BYZANTINE MUSICAL SYMBOL TESSERA;So;0;L;;;;;N;;;;;
+1D032;BYZANTINE MUSICAL SYMBOL KRATIMATA;So;0;L;;;;;N;;;;;
+1D033;BYZANTINE MUSICAL SYMBOL APESO EXO NEO;So;0;L;;;;;N;;;;;
+1D034;BYZANTINE MUSICAL SYMBOL FTHORA ARCHAION;So;0;L;;;;;N;;;;;
+1D035;BYZANTINE MUSICAL SYMBOL IMIFTHORA;So;0;L;;;;;N;;;;;
+1D036;BYZANTINE MUSICAL SYMBOL TROMIKON ARCHAION;So;0;L;;;;;N;;;;;
+1D037;BYZANTINE MUSICAL SYMBOL KATAVA TROMIKON;So;0;L;;;;;N;;;;;
+1D038;BYZANTINE MUSICAL SYMBOL PELASTON;So;0;L;;;;;N;;;;;
+1D039;BYZANTINE MUSICAL SYMBOL PSIFISTON;So;0;L;;;;;N;;;;;
+1D03A;BYZANTINE MUSICAL SYMBOL KONTEVMA;So;0;L;;;;;N;;;;;
+1D03B;BYZANTINE MUSICAL SYMBOL CHOREVMA ARCHAION;So;0;L;;;;;N;;;;;
+1D03C;BYZANTINE MUSICAL SYMBOL RAPISMA;So;0;L;;;;;N;;;;;
+1D03D;BYZANTINE MUSICAL SYMBOL PARAKALESMA ARCHAION;So;0;L;;;;;N;;;;;
+1D03E;BYZANTINE MUSICAL SYMBOL PARAKLITIKI ARCHAION;So;0;L;;;;;N;;;;;
+1D03F;BYZANTINE MUSICAL SYMBOL ICHADIN;So;0;L;;;;;N;;;;;
+1D040;BYZANTINE MUSICAL SYMBOL NANA;So;0;L;;;;;N;;;;;
+1D041;BYZANTINE MUSICAL SYMBOL PETASMA;So;0;L;;;;;N;;;;;
+1D042;BYZANTINE MUSICAL SYMBOL KONTEVMA ALLO;So;0;L;;;;;N;;;;;
+1D043;BYZANTINE MUSICAL SYMBOL TROMIKON ALLO;So;0;L;;;;;N;;;;;
+1D044;BYZANTINE MUSICAL SYMBOL STRAGGISMATA;So;0;L;;;;;N;;;;;
+1D045;BYZANTINE MUSICAL SYMBOL GRONTHISMATA;So;0;L;;;;;N;;;;;
+1D046;BYZANTINE MUSICAL SYMBOL ISON NEO;So;0;L;;;;;N;;;;;
+1D047;BYZANTINE MUSICAL SYMBOL OLIGON NEO;So;0;L;;;;;N;;;;;
+1D048;BYZANTINE MUSICAL SYMBOL OXEIA NEO;So;0;L;;;;;N;;;;;
+1D049;BYZANTINE MUSICAL SYMBOL PETASTI;So;0;L;;;;;N;;;;;
+1D04A;BYZANTINE MUSICAL SYMBOL KOUFISMA;So;0;L;;;;;N;;;;;
+1D04B;BYZANTINE MUSICAL SYMBOL PETASTOKOUFISMA;So;0;L;;;;;N;;;;;
+1D04C;BYZANTINE MUSICAL SYMBOL KRATIMOKOUFISMA;So;0;L;;;;;N;;;;;
+1D04D;BYZANTINE MUSICAL SYMBOL PELASTON NEO;So;0;L;;;;;N;;;;;
+1D04E;BYZANTINE MUSICAL SYMBOL KENTIMATA NEO ANO;So;0;L;;;;;N;;;;;
+1D04F;BYZANTINE MUSICAL SYMBOL KENTIMA NEO ANO;So;0;L;;;;;N;;;;;
+1D050;BYZANTINE MUSICAL SYMBOL YPSILI;So;0;L;;;;;N;;;;;
+1D051;BYZANTINE MUSICAL SYMBOL APOSTROFOS NEO;So;0;L;;;;;N;;;;;
+1D052;BYZANTINE MUSICAL SYMBOL APOSTROFOI SYNDESMOS NEO;So;0;L;;;;;N;;;;;
+1D053;BYZANTINE MUSICAL SYMBOL YPORROI;So;0;L;;;;;N;;;;;
+1D054;BYZANTINE MUSICAL SYMBOL KRATIMOYPORROON;So;0;L;;;;;N;;;;;
+1D055;BYZANTINE MUSICAL SYMBOL ELAFRON;So;0;L;;;;;N;;;;;
+1D056;BYZANTINE MUSICAL SYMBOL CHAMILI;So;0;L;;;;;N;;;;;
+1D057;BYZANTINE MUSICAL SYMBOL MIKRON ISON;So;0;L;;;;;N;;;;;
+1D058;BYZANTINE MUSICAL SYMBOL VAREIA NEO;So;0;L;;;;;N;;;;;
+1D059;BYZANTINE MUSICAL SYMBOL PIASMA NEO;So;0;L;;;;;N;;;;;
+1D05A;BYZANTINE MUSICAL SYMBOL PSIFISTON NEO;So;0;L;;;;;N;;;;;
+1D05B;BYZANTINE MUSICAL SYMBOL OMALON;So;0;L;;;;;N;;;;;
+1D05C;BYZANTINE MUSICAL SYMBOL ANTIKENOMA;So;0;L;;;;;N;;;;;
+1D05D;BYZANTINE MUSICAL SYMBOL LYGISMA;So;0;L;;;;;N;;;;;
+1D05E;BYZANTINE MUSICAL SYMBOL PARAKLITIKI NEO;So;0;L;;;;;N;;;;;
+1D05F;BYZANTINE MUSICAL SYMBOL PARAKALESMA NEO;So;0;L;;;;;N;;;;;
+1D060;BYZANTINE MUSICAL SYMBOL ETERON PARAKALESMA;So;0;L;;;;;N;;;;;
+1D061;BYZANTINE MUSICAL SYMBOL KYLISMA;So;0;L;;;;;N;;;;;
+1D062;BYZANTINE MUSICAL SYMBOL ANTIKENOKYLISMA;So;0;L;;;;;N;;;;;
+1D063;BYZANTINE MUSICAL SYMBOL TROMIKON NEO;So;0;L;;;;;N;;;;;
+1D064;BYZANTINE MUSICAL SYMBOL EKSTREPTON;So;0;L;;;;;N;;;;;
+1D065;BYZANTINE MUSICAL SYMBOL SYNAGMA NEO;So;0;L;;;;;N;;;;;
+1D066;BYZANTINE MUSICAL SYMBOL SYRMA;So;0;L;;;;;N;;;;;
+1D067;BYZANTINE MUSICAL SYMBOL CHOREVMA NEO;So;0;L;;;;;N;;;;;
+1D068;BYZANTINE MUSICAL SYMBOL EPEGERMA;So;0;L;;;;;N;;;;;
+1D069;BYZANTINE MUSICAL SYMBOL SEISMA NEO;So;0;L;;;;;N;;;;;
+1D06A;BYZANTINE MUSICAL SYMBOL XIRON KLASMA;So;0;L;;;;;N;;;;;
+1D06B;BYZANTINE MUSICAL SYMBOL TROMIKOPSIFISTON;So;0;L;;;;;N;;;;;
+1D06C;BYZANTINE MUSICAL SYMBOL PSIFISTOLYGISMA;So;0;L;;;;;N;;;;;
+1D06D;BYZANTINE MUSICAL SYMBOL TROMIKOLYGISMA;So;0;L;;;;;N;;;;;
+1D06E;BYZANTINE MUSICAL SYMBOL TROMIKOPARAKALESMA;So;0;L;;;;;N;;;;;
+1D06F;BYZANTINE MUSICAL SYMBOL PSIFISTOPARAKALESMA;So;0;L;;;;;N;;;;;
+1D070;BYZANTINE MUSICAL SYMBOL TROMIKOSYNAGMA;So;0;L;;;;;N;;;;;
+1D071;BYZANTINE MUSICAL SYMBOL PSIFISTOSYNAGMA;So;0;L;;;;;N;;;;;
+1D072;BYZANTINE MUSICAL SYMBOL GORGOSYNTHETON;So;0;L;;;;;N;;;;;
+1D073;BYZANTINE MUSICAL SYMBOL ARGOSYNTHETON;So;0;L;;;;;N;;;;;
+1D074;BYZANTINE MUSICAL SYMBOL ETERON ARGOSYNTHETON;So;0;L;;;;;N;;;;;
+1D075;BYZANTINE MUSICAL SYMBOL OYRANISMA NEO;So;0;L;;;;;N;;;;;
+1D076;BYZANTINE MUSICAL SYMBOL THEMATISMOS ESO;So;0;L;;;;;N;;;;;
+1D077;BYZANTINE MUSICAL SYMBOL THEMATISMOS EXO;So;0;L;;;;;N;;;;;
+1D078;BYZANTINE MUSICAL SYMBOL THEMA APLOUN;So;0;L;;;;;N;;;;;
+1D079;BYZANTINE MUSICAL SYMBOL THES KAI APOTHES;So;0;L;;;;;N;;;;;
+1D07A;BYZANTINE MUSICAL SYMBOL KATAVASMA;So;0;L;;;;;N;;;;;
+1D07B;BYZANTINE MUSICAL SYMBOL ENDOFONON;So;0;L;;;;;N;;;;;
+1D07C;BYZANTINE MUSICAL SYMBOL YFEN KATO;So;0;L;;;;;N;;;;;
+1D07D;BYZANTINE MUSICAL SYMBOL YFEN ANO;So;0;L;;;;;N;;;;;
+1D07E;BYZANTINE MUSICAL SYMBOL STAVROS;So;0;L;;;;;N;;;;;
+1D07F;BYZANTINE MUSICAL SYMBOL KLASMA ANO;So;0;L;;;;;N;;;;;
+1D080;BYZANTINE MUSICAL SYMBOL DIPLI ARCHAION;So;0;L;;;;;N;;;;;
+1D081;BYZANTINE MUSICAL SYMBOL KRATIMA ARCHAION;So;0;L;;;;;N;;;;;
+1D082;BYZANTINE MUSICAL SYMBOL KRATIMA ALLO;So;0;L;;;;;N;;;;;
+1D083;BYZANTINE MUSICAL SYMBOL KRATIMA NEO;So;0;L;;;;;N;;;;;
+1D084;BYZANTINE MUSICAL SYMBOL APODERMA NEO;So;0;L;;;;;N;;;;;
+1D085;BYZANTINE MUSICAL SYMBOL APLI;So;0;L;;;;;N;;;;;
+1D086;BYZANTINE MUSICAL SYMBOL DIPLI;So;0;L;;;;;N;;;;;
+1D087;BYZANTINE MUSICAL SYMBOL TRIPLI;So;0;L;;;;;N;;;;;
+1D088;BYZANTINE MUSICAL SYMBOL TETRAPLI;So;0;L;;;;;N;;;;;
+1D089;BYZANTINE MUSICAL SYMBOL KORONIS;So;0;L;;;;;N;;;;;
+1D08A;BYZANTINE MUSICAL SYMBOL LEIMMA ENOS CHRONOU;So;0;L;;;;;N;;;;;
+1D08B;BYZANTINE MUSICAL SYMBOL LEIMMA DYO CHRONON;So;0;L;;;;;N;;;;;
+1D08C;BYZANTINE MUSICAL SYMBOL LEIMMA TRION CHRONON;So;0;L;;;;;N;;;;;
+1D08D;BYZANTINE MUSICAL SYMBOL LEIMMA TESSARON CHRONON;So;0;L;;;;;N;;;;;
+1D08E;BYZANTINE MUSICAL SYMBOL LEIMMA IMISEOS CHRONOU;So;0;L;;;;;N;;;;;
+1D08F;BYZANTINE MUSICAL SYMBOL GORGON NEO ANO;So;0;L;;;;;N;;;;;
+1D090;BYZANTINE MUSICAL SYMBOL GORGON PARESTIGMENON ARISTERA;So;0;L;;;;;N;;;;;
+1D091;BYZANTINE MUSICAL SYMBOL GORGON PARESTIGMENON DEXIA;So;0;L;;;;;N;;;;;
+1D092;BYZANTINE MUSICAL SYMBOL DIGORGON;So;0;L;;;;;N;;;;;
+1D093;BYZANTINE MUSICAL SYMBOL DIGORGON PARESTIGMENON ARISTERA KATO;So;0;L;;;;;N;;;;;
+1D094;BYZANTINE MUSICAL SYMBOL DIGORGON PARESTIGMENON ARISTERA ANO;So;0;L;;;;;N;;;;;
+1D095;BYZANTINE MUSICAL SYMBOL DIGORGON PARESTIGMENON DEXIA;So;0;L;;;;;N;;;;;
+1D096;BYZANTINE MUSICAL SYMBOL TRIGORGON;So;0;L;;;;;N;;;;;
+1D097;BYZANTINE MUSICAL SYMBOL ARGON;So;0;L;;;;;N;;;;;
+1D098;BYZANTINE MUSICAL SYMBOL IMIDIARGON;So;0;L;;;;;N;;;;;
+1D099;BYZANTINE MUSICAL SYMBOL DIARGON;So;0;L;;;;;N;;;;;
+1D09A;BYZANTINE MUSICAL SYMBOL AGOGI POLI ARGI;So;0;L;;;;;N;;;;;
+1D09B;BYZANTINE MUSICAL SYMBOL AGOGI ARGOTERI;So;0;L;;;;;N;;;;;
+1D09C;BYZANTINE MUSICAL SYMBOL AGOGI ARGI;So;0;L;;;;;N;;;;;
+1D09D;BYZANTINE MUSICAL SYMBOL AGOGI METRIA;So;0;L;;;;;N;;;;;
+1D09E;BYZANTINE MUSICAL SYMBOL AGOGI MESI;So;0;L;;;;;N;;;;;
+1D09F;BYZANTINE MUSICAL SYMBOL AGOGI GORGI;So;0;L;;;;;N;;;;;
+1D0A0;BYZANTINE MUSICAL SYMBOL AGOGI GORGOTERI;So;0;L;;;;;N;;;;;
+1D0A1;BYZANTINE MUSICAL SYMBOL AGOGI POLI GORGI;So;0;L;;;;;N;;;;;
+1D0A2;BYZANTINE MUSICAL SYMBOL MARTYRIA PROTOS ICHOS;So;0;L;;;;;N;;;;;
+1D0A3;BYZANTINE MUSICAL SYMBOL MARTYRIA ALLI PROTOS ICHOS;So;0;L;;;;;N;;;;;
+1D0A4;BYZANTINE MUSICAL SYMBOL MARTYRIA DEYTEROS ICHOS;So;0;L;;;;;N;;;;;
+1D0A5;BYZANTINE MUSICAL SYMBOL MARTYRIA ALLI DEYTEROS ICHOS;So;0;L;;;;;N;;;;;
+1D0A6;BYZANTINE MUSICAL SYMBOL MARTYRIA TRITOS ICHOS;So;0;L;;;;;N;;;;;
+1D0A7;BYZANTINE MUSICAL SYMBOL MARTYRIA TRIFONIAS;So;0;L;;;;;N;;;;;
+1D0A8;BYZANTINE MUSICAL SYMBOL MARTYRIA TETARTOS ICHOS;So;0;L;;;;;N;;;;;
+1D0A9;BYZANTINE MUSICAL SYMBOL MARTYRIA TETARTOS LEGETOS ICHOS;So;0;L;;;;;N;;;;;
+1D0AA;BYZANTINE MUSICAL SYMBOL MARTYRIA LEGETOS ICHOS;So;0;L;;;;;N;;;;;
+1D0AB;BYZANTINE MUSICAL SYMBOL MARTYRIA PLAGIOS ICHOS;So;0;L;;;;;N;;;;;
+1D0AC;BYZANTINE MUSICAL SYMBOL ISAKIA TELOUS ICHIMATOS;So;0;L;;;;;N;;;;;
+1D0AD;BYZANTINE MUSICAL SYMBOL APOSTROFOI TELOUS ICHIMATOS;So;0;L;;;;;N;;;;;
+1D0AE;BYZANTINE MUSICAL SYMBOL FANEROSIS TETRAFONIAS;So;0;L;;;;;N;;;;;
+1D0AF;BYZANTINE MUSICAL SYMBOL FANEROSIS MONOFONIAS;So;0;L;;;;;N;;;;;
+1D0B0;BYZANTINE MUSICAL SYMBOL FANEROSIS DIFONIAS;So;0;L;;;;;N;;;;;
+1D0B1;BYZANTINE MUSICAL SYMBOL MARTYRIA VARYS ICHOS;So;0;L;;;;;N;;;;;
+1D0B2;BYZANTINE MUSICAL SYMBOL MARTYRIA PROTOVARYS ICHOS;So;0;L;;;;;N;;;;;
+1D0B3;BYZANTINE MUSICAL SYMBOL MARTYRIA PLAGIOS TETARTOS ICHOS;So;0;L;;;;;N;;;;;
+1D0B4;BYZANTINE MUSICAL SYMBOL GORTHMIKON N APLOUN;So;0;L;;;;;N;;;;;
+1D0B5;BYZANTINE MUSICAL SYMBOL GORTHMIKON N DIPLOUN;So;0;L;;;;;N;;;;;
+1D0B6;BYZANTINE MUSICAL SYMBOL ENARXIS KAI FTHORA VOU;So;0;L;;;;;N;;;;;
+1D0B7;BYZANTINE MUSICAL SYMBOL IMIFONON;So;0;L;;;;;N;;;;;
+1D0B8;BYZANTINE MUSICAL SYMBOL IMIFTHORON;So;0;L;;;;;N;;;;;
+1D0B9;BYZANTINE MUSICAL SYMBOL FTHORA ARCHAION DEYTEROU ICHOU;So;0;L;;;;;N;;;;;
+1D0BA;BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI PA;So;0;L;;;;;N;;;;;
+1D0BB;BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI NANA;So;0;L;;;;;N;;;;;
+1D0BC;BYZANTINE MUSICAL SYMBOL FTHORA NAOS ICHOS;So;0;L;;;;;N;;;;;
+1D0BD;BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI DI;So;0;L;;;;;N;;;;;
+1D0BE;BYZANTINE MUSICAL SYMBOL FTHORA SKLIRON DIATONON DI;So;0;L;;;;;N;;;;;
+1D0BF;BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI KE;So;0;L;;;;;N;;;;;
+1D0C0;BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI ZO;So;0;L;;;;;N;;;;;
+1D0C1;BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI NI KATO;So;0;L;;;;;N;;;;;
+1D0C2;BYZANTINE MUSICAL SYMBOL FTHORA DIATONIKI NI ANO;So;0;L;;;;;N;;;;;
+1D0C3;BYZANTINE MUSICAL SYMBOL FTHORA MALAKON CHROMA DIFONIAS;So;0;L;;;;;N;;;;;
+1D0C4;BYZANTINE MUSICAL SYMBOL FTHORA MALAKON CHROMA MONOFONIAS;So;0;L;;;;;N;;;;;
+1D0C5;BYZANTINE MUSICAL SYMBOL FHTORA SKLIRON CHROMA VASIS;So;0;L;;;;;N;;;;;
+1D0C6;BYZANTINE MUSICAL SYMBOL FTHORA SKLIRON CHROMA SYNAFI;So;0;L;;;;;N;;;;;
+1D0C7;BYZANTINE MUSICAL SYMBOL FTHORA NENANO;So;0;L;;;;;N;;;;;
+1D0C8;BYZANTINE MUSICAL SYMBOL CHROA ZYGOS;So;0;L;;;;;N;;;;;
+1D0C9;BYZANTINE MUSICAL SYMBOL CHROA KLITON;So;0;L;;;;;N;;;;;
+1D0CA;BYZANTINE MUSICAL SYMBOL CHROA SPATHI;So;0;L;;;;;N;;;;;
+1D0CB;BYZANTINE MUSICAL SYMBOL FTHORA I YFESIS TETARTIMORION;So;0;L;;;;;N;;;;;
+1D0CC;BYZANTINE MUSICAL SYMBOL FTHORA ENARMONIOS ANTIFONIA;So;0;L;;;;;N;;;;;
+1D0CD;BYZANTINE MUSICAL SYMBOL YFESIS TRITIMORION;So;0;L;;;;;N;;;;;
+1D0CE;BYZANTINE MUSICAL SYMBOL DIESIS TRITIMORION;So;0;L;;;;;N;;;;;
+1D0CF;BYZANTINE MUSICAL SYMBOL DIESIS TETARTIMORION;So;0;L;;;;;N;;;;;
+1D0D0;BYZANTINE MUSICAL SYMBOL DIESIS APLI DYO DODEKATA;So;0;L;;;;;N;;;;;
+1D0D1;BYZANTINE MUSICAL SYMBOL DIESIS MONOGRAMMOS TESSERA DODEKATA;So;0;L;;;;;N;;;;;
+1D0D2;BYZANTINE MUSICAL SYMBOL DIESIS DIGRAMMOS EX DODEKATA;So;0;L;;;;;N;;;;;
+1D0D3;BYZANTINE MUSICAL SYMBOL DIESIS TRIGRAMMOS OKTO DODEKATA;So;0;L;;;;;N;;;;;
+1D0D4;BYZANTINE MUSICAL SYMBOL YFESIS APLI DYO DODEKATA;So;0;L;;;;;N;;;;;
+1D0D5;BYZANTINE MUSICAL SYMBOL YFESIS MONOGRAMMOS TESSERA DODEKATA;So;0;L;;;;;N;;;;;
+1D0D6;BYZANTINE MUSICAL SYMBOL YFESIS DIGRAMMOS EX DODEKATA;So;0;L;;;;;N;;;;;
+1D0D7;BYZANTINE MUSICAL SYMBOL YFESIS TRIGRAMMOS OKTO DODEKATA;So;0;L;;;;;N;;;;;
+1D0D8;BYZANTINE MUSICAL SYMBOL GENIKI DIESIS;So;0;L;;;;;N;;;;;
+1D0D9;BYZANTINE MUSICAL SYMBOL GENIKI YFESIS;So;0;L;;;;;N;;;;;
+1D0DA;BYZANTINE MUSICAL SYMBOL DIASTOLI APLI MIKRI;So;0;L;;;;;N;;;;;
+1D0DB;BYZANTINE MUSICAL SYMBOL DIASTOLI APLI MEGALI;So;0;L;;;;;N;;;;;
+1D0DC;BYZANTINE MUSICAL SYMBOL DIASTOLI DIPLI;So;0;L;;;;;N;;;;;
+1D0DD;BYZANTINE MUSICAL SYMBOL DIASTOLI THESEOS;So;0;L;;;;;N;;;;;
+1D0DE;BYZANTINE MUSICAL SYMBOL SIMANSIS THESEOS;So;0;L;;;;;N;;;;;
+1D0DF;BYZANTINE MUSICAL SYMBOL SIMANSIS THESEOS DISIMOU;So;0;L;;;;;N;;;;;
+1D0E0;BYZANTINE MUSICAL SYMBOL SIMANSIS THESEOS TRISIMOU;So;0;L;;;;;N;;;;;
+1D0E1;BYZANTINE MUSICAL SYMBOL SIMANSIS THESEOS TETRASIMOU;So;0;L;;;;;N;;;;;
+1D0E2;BYZANTINE MUSICAL SYMBOL SIMANSIS ARSEOS;So;0;L;;;;;N;;;;;
+1D0E3;BYZANTINE MUSICAL SYMBOL SIMANSIS ARSEOS DISIMOU;So;0;L;;;;;N;;;;;
+1D0E4;BYZANTINE MUSICAL SYMBOL SIMANSIS ARSEOS TRISIMOU;So;0;L;;;;;N;;;;;
+1D0E5;BYZANTINE MUSICAL SYMBOL SIMANSIS ARSEOS TETRASIMOU;So;0;L;;;;;N;;;;;
+1D0E6;BYZANTINE MUSICAL SYMBOL DIGRAMMA GG;So;0;L;;;;;N;;;;;
+1D0E7;BYZANTINE MUSICAL SYMBOL DIFTOGGOS OU;So;0;L;;;;;N;;;;;
+1D0E8;BYZANTINE MUSICAL SYMBOL STIGMA;So;0;L;;;;;N;;;;;
+1D0E9;BYZANTINE MUSICAL SYMBOL ARKTIKO PA;So;0;L;;;;;N;;;;;
+1D0EA;BYZANTINE MUSICAL SYMBOL ARKTIKO VOU;So;0;L;;;;;N;;;;;
+1D0EB;BYZANTINE MUSICAL SYMBOL ARKTIKO GA;So;0;L;;;;;N;;;;;
+1D0EC;BYZANTINE MUSICAL SYMBOL ARKTIKO DI;So;0;L;;;;;N;;;;;
+1D0ED;BYZANTINE MUSICAL SYMBOL ARKTIKO KE;So;0;L;;;;;N;;;;;
+1D0EE;BYZANTINE MUSICAL SYMBOL ARKTIKO ZO;So;0;L;;;;;N;;;;;
+1D0EF;BYZANTINE MUSICAL SYMBOL ARKTIKO NI;So;0;L;;;;;N;;;;;
+1D0F0;BYZANTINE MUSICAL SYMBOL KENTIMATA NEO MESO;So;0;L;;;;;N;;;;;
+1D0F1;BYZANTINE MUSICAL SYMBOL KENTIMA NEO MESO;So;0;L;;;;;N;;;;;
+1D0F2;BYZANTINE MUSICAL SYMBOL KENTIMATA NEO KATO;So;0;L;;;;;N;;;;;
+1D0F3;BYZANTINE MUSICAL SYMBOL KENTIMA NEO KATO;So;0;L;;;;;N;;;;;
+1D0F4;BYZANTINE MUSICAL SYMBOL KLASMA KATO;So;0;L;;;;;N;;;;;
+1D0F5;BYZANTINE MUSICAL SYMBOL GORGON NEO KATO;So;0;L;;;;;N;;;;;
+1D100;MUSICAL SYMBOL SINGLE BARLINE;So;0;L;;;;;N;;;;;
+1D101;MUSICAL SYMBOL DOUBLE BARLINE;So;0;L;;;;;N;;;;;
+1D102;MUSICAL SYMBOL FINAL BARLINE;So;0;L;;;;;N;;;;;
+1D103;MUSICAL SYMBOL REVERSE FINAL BARLINE;So;0;L;;;;;N;;;;;
+1D104;MUSICAL SYMBOL DASHED BARLINE;So;0;L;;;;;N;;;;;
+1D105;MUSICAL SYMBOL SHORT BARLINE;So;0;L;;;;;N;;;;;
+1D106;MUSICAL SYMBOL LEFT REPEAT SIGN;So;0;L;;;;;N;;;;;
+1D107;MUSICAL SYMBOL RIGHT REPEAT SIGN;So;0;L;;;;;N;;;;;
+1D108;MUSICAL SYMBOL REPEAT DOTS;So;0;L;;;;;N;;;;;
+1D109;MUSICAL SYMBOL DAL SEGNO;So;0;L;;;;;N;;;;;
+1D10A;MUSICAL SYMBOL DA CAPO;So;0;L;;;;;N;;;;;
+1D10B;MUSICAL SYMBOL SEGNO;So;0;L;;;;;N;;;;;
+1D10C;MUSICAL SYMBOL CODA;So;0;L;;;;;N;;;;;
+1D10D;MUSICAL SYMBOL REPEATED FIGURE-1;So;0;L;;;;;N;;;;;
+1D10E;MUSICAL SYMBOL REPEATED FIGURE-2;So;0;L;;;;;N;;;;;
+1D10F;MUSICAL SYMBOL REPEATED FIGURE-3;So;0;L;;;;;N;;;;;
+1D110;MUSICAL SYMBOL FERMATA;So;0;L;;;;;N;;;;;
+1D111;MUSICAL SYMBOL FERMATA BELOW;So;0;L;;;;;N;;;;;
+1D112;MUSICAL SYMBOL BREATH MARK;So;0;L;;;;;N;;;;;
+1D113;MUSICAL SYMBOL CAESURA;So;0;L;;;;;N;;;;;
+1D114;MUSICAL SYMBOL BRACE;So;0;L;;;;;N;;;;;
+1D115;MUSICAL SYMBOL BRACKET;So;0;L;;;;;N;;;;;
+1D116;MUSICAL SYMBOL ONE-LINE STAFF;So;0;L;;;;;N;;;;;
+1D117;MUSICAL SYMBOL TWO-LINE STAFF;So;0;L;;;;;N;;;;;
+1D118;MUSICAL SYMBOL THREE-LINE STAFF;So;0;L;;;;;N;;;;;
+1D119;MUSICAL SYMBOL FOUR-LINE STAFF;So;0;L;;;;;N;;;;;
+1D11A;MUSICAL SYMBOL FIVE-LINE STAFF;So;0;L;;;;;N;;;;;
+1D11B;MUSICAL SYMBOL SIX-LINE STAFF;So;0;L;;;;;N;;;;;
+1D11C;MUSICAL SYMBOL SIX-STRING FRETBOARD;So;0;L;;;;;N;;;;;
+1D11D;MUSICAL SYMBOL FOUR-STRING FRETBOARD;So;0;L;;;;;N;;;;;
+1D11E;MUSICAL SYMBOL G CLEF;So;0;L;;;;;N;;;;;
+1D11F;MUSICAL SYMBOL G CLEF OTTAVA ALTA;So;0;L;;;;;N;;;;;
+1D120;MUSICAL SYMBOL G CLEF OTTAVA BASSA;So;0;L;;;;;N;;;;;
+1D121;MUSICAL SYMBOL C CLEF;So;0;L;;;;;N;;;;;
+1D122;MUSICAL SYMBOL F CLEF;So;0;L;;;;;N;;;;;
+1D123;MUSICAL SYMBOL F CLEF OTTAVA ALTA;So;0;L;;;;;N;;;;;
+1D124;MUSICAL SYMBOL F CLEF OTTAVA BASSA;So;0;L;;;;;N;;;;;
+1D125;MUSICAL SYMBOL DRUM CLEF-1;So;0;L;;;;;N;;;;;
+1D126;MUSICAL SYMBOL DRUM CLEF-2;So;0;L;;;;;N;;;;;
+1D12A;MUSICAL SYMBOL DOUBLE SHARP;So;0;L;;;;;N;;;;;
+1D12B;MUSICAL SYMBOL DOUBLE FLAT;So;0;L;;;;;N;;;;;
+1D12C;MUSICAL SYMBOL FLAT UP;So;0;L;;;;;N;;;;;
+1D12D;MUSICAL SYMBOL FLAT DOWN;So;0;L;;;;;N;;;;;
+1D12E;MUSICAL SYMBOL NATURAL UP;So;0;L;;;;;N;;;;;
+1D12F;MUSICAL SYMBOL NATURAL DOWN;So;0;L;;;;;N;;;;;
+1D130;MUSICAL SYMBOL SHARP UP;So;0;L;;;;;N;;;;;
+1D131;MUSICAL SYMBOL SHARP DOWN;So;0;L;;;;;N;;;;;
+1D132;MUSICAL SYMBOL QUARTER TONE SHARP;So;0;L;;;;;N;;;;;
+1D133;MUSICAL SYMBOL QUARTER TONE FLAT;So;0;L;;;;;N;;;;;
+1D134;MUSICAL SYMBOL COMMON TIME;So;0;L;;;;;N;;;;;
+1D135;MUSICAL SYMBOL CUT TIME;So;0;L;;;;;N;;;;;
+1D136;MUSICAL SYMBOL OTTAVA ALTA;So;0;L;;;;;N;;;;;
+1D137;MUSICAL SYMBOL OTTAVA BASSA;So;0;L;;;;;N;;;;;
+1D138;MUSICAL SYMBOL QUINDICESIMA ALTA;So;0;L;;;;;N;;;;;
+1D139;MUSICAL SYMBOL QUINDICESIMA BASSA;So;0;L;;;;;N;;;;;
+1D13A;MUSICAL SYMBOL MULTI REST;So;0;L;;;;;N;;;;;
+1D13B;MUSICAL SYMBOL WHOLE REST;So;0;L;;;;;N;;;;;
+1D13C;MUSICAL SYMBOL HALF REST;So;0;L;;;;;N;;;;;
+1D13D;MUSICAL SYMBOL QUARTER REST;So;0;L;;;;;N;;;;;
+1D13E;MUSICAL SYMBOL EIGHTH REST;So;0;L;;;;;N;;;;;
+1D13F;MUSICAL SYMBOL SIXTEENTH REST;So;0;L;;;;;N;;;;;
+1D140;MUSICAL SYMBOL THIRTY-SECOND REST;So;0;L;;;;;N;;;;;
+1D141;MUSICAL SYMBOL SIXTY-FOURTH REST;So;0;L;;;;;N;;;;;
+1D142;MUSICAL SYMBOL ONE HUNDRED TWENTY-EIGHTH REST;So;0;L;;;;;N;;;;;
+1D143;MUSICAL SYMBOL X NOTEHEAD;So;0;L;;;;;N;;;;;
+1D144;MUSICAL SYMBOL PLUS NOTEHEAD;So;0;L;;;;;N;;;;;
+1D145;MUSICAL SYMBOL CIRCLE X NOTEHEAD;So;0;L;;;;;N;;;;;
+1D146;MUSICAL SYMBOL SQUARE NOTEHEAD WHITE;So;0;L;;;;;N;;;;;
+1D147;MUSICAL SYMBOL SQUARE NOTEHEAD BLACK;So;0;L;;;;;N;;;;;
+1D148;MUSICAL SYMBOL TRIANGLE NOTEHEAD UP WHITE;So;0;L;;;;;N;;;;;
+1D149;MUSICAL SYMBOL TRIANGLE NOTEHEAD UP BLACK;So;0;L;;;;;N;;;;;
+1D14A;MUSICAL SYMBOL TRIANGLE NOTEHEAD LEFT WHITE;So;0;L;;;;;N;;;;;
+1D14B;MUSICAL SYMBOL TRIANGLE NOTEHEAD LEFT BLACK;So;0;L;;;;;N;;;;;
+1D14C;MUSICAL SYMBOL TRIANGLE NOTEHEAD RIGHT WHITE;So;0;L;;;;;N;;;;;
+1D14D;MUSICAL SYMBOL TRIANGLE NOTEHEAD RIGHT BLACK;So;0;L;;;;;N;;;;;
+1D14E;MUSICAL SYMBOL TRIANGLE NOTEHEAD DOWN WHITE;So;0;L;;;;;N;;;;;
+1D14F;MUSICAL SYMBOL TRIANGLE NOTEHEAD DOWN BLACK;So;0;L;;;;;N;;;;;
+1D150;MUSICAL SYMBOL TRIANGLE NOTEHEAD UP RIGHT WHITE;So;0;L;;;;;N;;;;;
+1D151;MUSICAL SYMBOL TRIANGLE NOTEHEAD UP RIGHT BLACK;So;0;L;;;;;N;;;;;
+1D152;MUSICAL SYMBOL MOON NOTEHEAD WHITE;So;0;L;;;;;N;;;;;
+1D153;MUSICAL SYMBOL MOON NOTEHEAD BLACK;So;0;L;;;;;N;;;;;
+1D154;MUSICAL SYMBOL TRIANGLE-ROUND NOTEHEAD DOWN WHITE;So;0;L;;;;;N;;;;;
+1D155;MUSICAL SYMBOL TRIANGLE-ROUND NOTEHEAD DOWN BLACK;So;0;L;;;;;N;;;;;
+1D156;MUSICAL SYMBOL PARENTHESIS NOTEHEAD;So;0;L;;;;;N;;;;;
+1D157;MUSICAL SYMBOL VOID NOTEHEAD;So;0;L;;;;;N;;;;;
+1D158;MUSICAL SYMBOL NOTEHEAD BLACK;So;0;L;;;;;N;;;;;
+1D159;MUSICAL SYMBOL NULL NOTEHEAD;So;0;L;;;;;N;;;;;
+1D15A;MUSICAL SYMBOL CLUSTER NOTEHEAD WHITE;So;0;L;;;;;N;;;;;
+1D15B;MUSICAL SYMBOL CLUSTER NOTEHEAD BLACK;So;0;L;;;;;N;;;;;
+1D15C;MUSICAL SYMBOL BREVE;So;0;L;;;;;N;;;;;
+1D15D;MUSICAL SYMBOL WHOLE NOTE;So;0;L;;;;;N;;;;;
+1D15E;MUSICAL SYMBOL HALF NOTE;So;0;L;1D157 1D165;;;;N;;;;;
+1D15F;MUSICAL SYMBOL QUARTER NOTE;So;0;L;1D158 1D165;;;;N;;;;;
+1D160;MUSICAL SYMBOL EIGHTH NOTE;So;0;L;1D15F 1D16E;;;;N;;;;;
+1D161;MUSICAL SYMBOL SIXTEENTH NOTE;So;0;L;1D15F 1D16F;;;;N;;;;;
+1D162;MUSICAL SYMBOL THIRTY-SECOND NOTE;So;0;L;1D15F 1D170;;;;N;;;;;
+1D163;MUSICAL SYMBOL SIXTY-FOURTH NOTE;So;0;L;1D15F 1D171;;;;N;;;;;
+1D164;MUSICAL SYMBOL ONE HUNDRED TWENTY-EIGHTH NOTE;So;0;L;1D15F 1D172;;;;N;;;;;
+1D165;MUSICAL SYMBOL COMBINING STEM;Mc;216;L;;;;;N;;;;;
+1D166;MUSICAL SYMBOL COMBINING SPRECHGESANG STEM;Mc;216;L;;;;;N;;;;;
+1D167;MUSICAL SYMBOL COMBINING TREMOLO-1;Mn;1;NSM;;;;;N;;;;;
+1D168;MUSICAL SYMBOL COMBINING TREMOLO-2;Mn;1;NSM;;;;;N;;;;;
+1D169;MUSICAL SYMBOL COMBINING TREMOLO-3;Mn;1;NSM;;;;;N;;;;;
+1D16A;MUSICAL SYMBOL FINGERED TREMOLO-1;So;0;L;;;;;N;;;;;
+1D16B;MUSICAL SYMBOL FINGERED TREMOLO-2;So;0;L;;;;;N;;;;;
+1D16C;MUSICAL SYMBOL FINGERED TREMOLO-3;So;0;L;;;;;N;;;;;
+1D16D;MUSICAL SYMBOL COMBINING AUGMENTATION DOT;Mc;226;L;;;;;N;;;;;
+1D16E;MUSICAL SYMBOL COMBINING FLAG-1;Mc;216;L;;;;;N;;;;;
+1D16F;MUSICAL SYMBOL COMBINING FLAG-2;Mc;216;L;;;;;N;;;;;
+1D170;MUSICAL SYMBOL COMBINING FLAG-3;Mc;216;L;;;;;N;;;;;
+1D171;MUSICAL SYMBOL COMBINING FLAG-4;Mc;216;L;;;;;N;;;;;
+1D172;MUSICAL SYMBOL COMBINING FLAG-5;Mc;216;L;;;;;N;;;;;
+1D173;MUSICAL SYMBOL BEGIN BEAM;Cf;0;BN;;;;;N;;;;;
+1D174;MUSICAL SYMBOL END BEAM;Cf;0;BN;;;;;N;;;;;
+1D175;MUSICAL SYMBOL BEGIN TIE;Cf;0;BN;;;;;N;;;;;
+1D176;MUSICAL SYMBOL END TIE;Cf;0;BN;;;;;N;;;;;
+1D177;MUSICAL SYMBOL BEGIN SLUR;Cf;0;BN;;;;;N;;;;;
+1D178;MUSICAL SYMBOL END SLUR;Cf;0;BN;;;;;N;;;;;
+1D179;MUSICAL SYMBOL BEGIN PHRASE;Cf;0;BN;;;;;N;;;;;
+1D17A;MUSICAL SYMBOL END PHRASE;Cf;0;BN;;;;;N;;;;;
+1D17B;MUSICAL SYMBOL COMBINING ACCENT;Mn;220;NSM;;;;;N;;;;;
+1D17C;MUSICAL SYMBOL COMBINING STACCATO;Mn;220;NSM;;;;;N;;;;;
+1D17D;MUSICAL SYMBOL COMBINING TENUTO;Mn;220;NSM;;;;;N;;;;;
+1D17E;MUSICAL SYMBOL COMBINING STACCATISSIMO;Mn;220;NSM;;;;;N;;;;;
+1D17F;MUSICAL SYMBOL COMBINING MARCATO;Mn;220;NSM;;;;;N;;;;;
+1D180;MUSICAL SYMBOL COMBINING MARCATO-STACCATO;Mn;220;NSM;;;;;N;;;;;
+1D181;MUSICAL SYMBOL COMBINING ACCENT-STACCATO;Mn;220;NSM;;;;;N;;;;;
+1D182;MUSICAL SYMBOL COMBINING LOURE;Mn;220;NSM;;;;;N;;;;;
+1D183;MUSICAL SYMBOL ARPEGGIATO UP;So;0;L;;;;;N;;;;;
+1D184;MUSICAL SYMBOL ARPEGGIATO DOWN;So;0;L;;;;;N;;;;;
+1D185;MUSICAL SYMBOL COMBINING DOIT;Mn;230;NSM;;;;;N;;;;;
+1D186;MUSICAL SYMBOL COMBINING RIP;Mn;230;NSM;;;;;N;;;;;
+1D187;MUSICAL SYMBOL COMBINING FLIP;Mn;230;NSM;;;;;N;;;;;
+1D188;MUSICAL SYMBOL COMBINING SMEAR;Mn;230;NSM;;;;;N;;;;;
+1D189;MUSICAL SYMBOL COMBINING BEND;Mn;230;NSM;;;;;N;;;;;
+1D18A;MUSICAL SYMBOL COMBINING DOUBLE TONGUE;Mn;220;NSM;;;;;N;;;;;
+1D18B;MUSICAL SYMBOL COMBINING TRIPLE TONGUE;Mn;220;NSM;;;;;N;;;;;
+1D18C;MUSICAL SYMBOL RINFORZANDO;So;0;L;;;;;N;;;;;
+1D18D;MUSICAL SYMBOL SUBITO;So;0;L;;;;;N;;;;;
+1D18E;MUSICAL SYMBOL Z;So;0;L;;;;;N;;;;;
+1D18F;MUSICAL SYMBOL PIANO;So;0;L;;;;;N;;;;;
+1D190;MUSICAL SYMBOL MEZZO;So;0;L;;;;;N;;;;;
+1D191;MUSICAL SYMBOL FORTE;So;0;L;;;;;N;;;;;
+1D192;MUSICAL SYMBOL CRESCENDO;So;0;L;;;;;N;;;;;
+1D193;MUSICAL SYMBOL DECRESCENDO;So;0;L;;;;;N;;;;;
+1D194;MUSICAL SYMBOL GRACE NOTE SLASH;So;0;L;;;;;N;;;;;
+1D195;MUSICAL SYMBOL GRACE NOTE NO SLASH;So;0;L;;;;;N;;;;;
+1D196;MUSICAL SYMBOL TR;So;0;L;;;;;N;;;;;
+1D197;MUSICAL SYMBOL TURN;So;0;L;;;;;N;;;;;
+1D198;MUSICAL SYMBOL INVERTED TURN;So;0;L;;;;;N;;;;;
+1D199;MUSICAL SYMBOL TURN SLASH;So;0;L;;;;;N;;;;;
+1D19A;MUSICAL SYMBOL TURN UP;So;0;L;;;;;N;;;;;
+1D19B;MUSICAL SYMBOL ORNAMENT STROKE-1;So;0;L;;;;;N;;;;;
+1D19C;MUSICAL SYMBOL ORNAMENT STROKE-2;So;0;L;;;;;N;;;;;
+1D19D;MUSICAL SYMBOL ORNAMENT STROKE-3;So;0;L;;;;;N;;;;;
+1D19E;MUSICAL SYMBOL ORNAMENT STROKE-4;So;0;L;;;;;N;;;;;
+1D19F;MUSICAL SYMBOL ORNAMENT STROKE-5;So;0;L;;;;;N;;;;;
+1D1A0;MUSICAL SYMBOL ORNAMENT STROKE-6;So;0;L;;;;;N;;;;;
+1D1A1;MUSICAL SYMBOL ORNAMENT STROKE-7;So;0;L;;;;;N;;;;;
+1D1A2;MUSICAL SYMBOL ORNAMENT STROKE-8;So;0;L;;;;;N;;;;;
+1D1A3;MUSICAL SYMBOL ORNAMENT STROKE-9;So;0;L;;;;;N;;;;;
+1D1A4;MUSICAL SYMBOL ORNAMENT STROKE-10;So;0;L;;;;;N;;;;;
+1D1A5;MUSICAL SYMBOL ORNAMENT STROKE-11;So;0;L;;;;;N;;;;;
+1D1A6;MUSICAL SYMBOL HAUPTSTIMME;So;0;L;;;;;N;;;;;
+1D1A7;MUSICAL SYMBOL NEBENSTIMME;So;0;L;;;;;N;;;;;
+1D1A8;MUSICAL SYMBOL END OF STIMME;So;0;L;;;;;N;;;;;
+1D1A9;MUSICAL SYMBOL DEGREE SLASH;So;0;L;;;;;N;;;;;
+1D1AA;MUSICAL SYMBOL COMBINING DOWN BOW;Mn;230;NSM;;;;;N;;;;;
+1D1AB;MUSICAL SYMBOL COMBINING UP BOW;Mn;230;NSM;;;;;N;;;;;
+1D1AC;MUSICAL SYMBOL COMBINING HARMONIC;Mn;230;NSM;;;;;N;;;;;
+1D1AD;MUSICAL SYMBOL COMBINING SNAP PIZZICATO;Mn;230;NSM;;;;;N;;;;;
+1D1AE;MUSICAL SYMBOL PEDAL MARK;So;0;L;;;;;N;;;;;
+1D1AF;MUSICAL SYMBOL PEDAL UP MARK;So;0;L;;;;;N;;;;;
+1D1B0;MUSICAL SYMBOL HALF PEDAL MARK;So;0;L;;;;;N;;;;;
+1D1B1;MUSICAL SYMBOL GLISSANDO UP;So;0;L;;;;;N;;;;;
+1D1B2;MUSICAL SYMBOL GLISSANDO DOWN;So;0;L;;;;;N;;;;;
+1D1B3;MUSICAL SYMBOL WITH FINGERNAILS;So;0;L;;;;;N;;;;;
+1D1B4;MUSICAL SYMBOL DAMP;So;0;L;;;;;N;;;;;
+1D1B5;MUSICAL SYMBOL DAMP ALL;So;0;L;;;;;N;;;;;
+1D1B6;MUSICAL SYMBOL MAXIMA;So;0;L;;;;;N;;;;;
+1D1B7;MUSICAL SYMBOL LONGA;So;0;L;;;;;N;;;;;
+1D1B8;MUSICAL SYMBOL BREVIS;So;0;L;;;;;N;;;;;
+1D1B9;MUSICAL SYMBOL SEMIBREVIS WHITE;So;0;L;;;;;N;;;;;
+1D1BA;MUSICAL SYMBOL SEMIBREVIS BLACK;So;0;L;;;;;N;;;;;
+1D1BB;MUSICAL SYMBOL MINIMA;So;0;L;1D1B9 1D165;;;;N;;;;;
+1D1BC;MUSICAL SYMBOL MINIMA BLACK;So;0;L;1D1BA 1D165;;;;N;;;;;
+1D1BD;MUSICAL SYMBOL SEMIMINIMA WHITE;So;0;L;1D1BB 1D16E;;;;N;;;;;
+1D1BE;MUSICAL SYMBOL SEMIMINIMA BLACK;So;0;L;1D1BC 1D16E;;;;N;;;;;
+1D1BF;MUSICAL SYMBOL FUSA WHITE;So;0;L;1D1BB 1D16F;;;;N;;;;;
+1D1C0;MUSICAL SYMBOL FUSA BLACK;So;0;L;1D1BC 1D16F;;;;N;;;;;
+1D1C1;MUSICAL SYMBOL LONGA PERFECTA REST;So;0;L;;;;;N;;;;;
+1D1C2;MUSICAL SYMBOL LONGA IMPERFECTA REST;So;0;L;;;;;N;;;;;
+1D1C3;MUSICAL SYMBOL BREVIS REST;So;0;L;;;;;N;;;;;
+1D1C4;MUSICAL SYMBOL SEMIBREVIS REST;So;0;L;;;;;N;;;;;
+1D1C5;MUSICAL SYMBOL MINIMA REST;So;0;L;;;;;N;;;;;
+1D1C6;MUSICAL SYMBOL SEMIMINIMA REST;So;0;L;;;;;N;;;;;
+1D1C7;MUSICAL SYMBOL TEMPUS PERFECTUM CUM PROLATIONE PERFECTA;So;0;L;;;;;N;;;;;
+1D1C8;MUSICAL SYMBOL TEMPUS PERFECTUM CUM PROLATIONE IMPERFECTA;So;0;L;;;;;N;;;;;
+1D1C9;MUSICAL SYMBOL TEMPUS PERFECTUM CUM PROLATIONE PERFECTA DIMINUTION-1;So;0;L;;;;;N;;;;;
+1D1CA;MUSICAL SYMBOL TEMPUS IMPERFECTUM CUM PROLATIONE PERFECTA;So;0;L;;;;;N;;;;;
+1D1CB;MUSICAL SYMBOL TEMPUS IMPERFECTUM CUM PROLATIONE IMPERFECTA;So;0;L;;;;;N;;;;;
+1D1CC;MUSICAL SYMBOL TEMPUS IMPERFECTUM CUM PROLATIONE IMPERFECTA DIMINUTION-1;So;0;L;;;;;N;;;;;
+1D1CD;MUSICAL SYMBOL TEMPUS IMPERFECTUM CUM PROLATIONE IMPERFECTA DIMINUTION-2;So;0;L;;;;;N;;;;;
+1D1CE;MUSICAL SYMBOL TEMPUS IMPERFECTUM CUM PROLATIONE IMPERFECTA DIMINUTION-3;So;0;L;;;;;N;;;;;
+1D1CF;MUSICAL SYMBOL CROIX;So;0;L;;;;;N;;;;;
+1D1D0;MUSICAL SYMBOL GREGORIAN C CLEF;So;0;L;;;;;N;;;;;
+1D1D1;MUSICAL SYMBOL GREGORIAN F CLEF;So;0;L;;;;;N;;;;;
+1D1D2;MUSICAL SYMBOL SQUARE B;So;0;L;;;;;N;;;;;
+1D1D3;MUSICAL SYMBOL VIRGA;So;0;L;;;;;N;;;;;
+1D1D4;MUSICAL SYMBOL PODATUS;So;0;L;;;;;N;;;;;
+1D1D5;MUSICAL SYMBOL CLIVIS;So;0;L;;;;;N;;;;;
+1D1D6;MUSICAL SYMBOL SCANDICUS;So;0;L;;;;;N;;;;;
+1D1D7;MUSICAL SYMBOL CLIMACUS;So;0;L;;;;;N;;;;;
+1D1D8;MUSICAL SYMBOL TORCULUS;So;0;L;;;;;N;;;;;
+1D1D9;MUSICAL SYMBOL PORRECTUS;So;0;L;;;;;N;;;;;
+1D1DA;MUSICAL SYMBOL PORRECTUS FLEXUS;So;0;L;;;;;N;;;;;
+1D1DB;MUSICAL SYMBOL SCANDICUS FLEXUS;So;0;L;;;;;N;;;;;
+1D1DC;MUSICAL SYMBOL TORCULUS RESUPINUS;So;0;L;;;;;N;;;;;
+1D1DD;MUSICAL SYMBOL PES SUBPUNCTIS;So;0;L;;;;;N;;;;;
+1D400;MATHEMATICAL BOLD CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;;
+1D401;MATHEMATICAL BOLD CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;;
+1D402;MATHEMATICAL BOLD CAPITAL C;Lu;0;L;<font> 0043;;;;N;;;;;
+1D403;MATHEMATICAL BOLD CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;;
+1D404;MATHEMATICAL BOLD CAPITAL E;Lu;0;L;<font> 0045;;;;N;;;;;
+1D405;MATHEMATICAL BOLD CAPITAL F;Lu;0;L;<font> 0046;;;;N;;;;;
+1D406;MATHEMATICAL BOLD CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;;
+1D407;MATHEMATICAL BOLD CAPITAL H;Lu;0;L;<font> 0048;;;;N;;;;;
+1D408;MATHEMATICAL BOLD CAPITAL I;Lu;0;L;<font> 0049;;;;N;;;;;
+1D409;MATHEMATICAL BOLD CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;;
+1D40A;MATHEMATICAL BOLD CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;;
+1D40B;MATHEMATICAL BOLD CAPITAL L;Lu;0;L;<font> 004C;;;;N;;;;;
+1D40C;MATHEMATICAL BOLD CAPITAL M;Lu;0;L;<font> 004D;;;;N;;;;;
+1D40D;MATHEMATICAL BOLD CAPITAL N;Lu;0;L;<font> 004E;;;;N;;;;;
+1D40E;MATHEMATICAL BOLD CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;;
+1D40F;MATHEMATICAL BOLD CAPITAL P;Lu;0;L;<font> 0050;;;;N;;;;;
+1D410;MATHEMATICAL BOLD CAPITAL Q;Lu;0;L;<font> 0051;;;;N;;;;;
+1D411;MATHEMATICAL BOLD CAPITAL R;Lu;0;L;<font> 0052;;;;N;;;;;
+1D412;MATHEMATICAL BOLD CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;;
+1D413;MATHEMATICAL BOLD CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;;
+1D414;MATHEMATICAL BOLD CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;;
+1D415;MATHEMATICAL BOLD CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;;
+1D416;MATHEMATICAL BOLD CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;;
+1D417;MATHEMATICAL BOLD CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;;
+1D418;MATHEMATICAL BOLD CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;;
+1D419;MATHEMATICAL BOLD CAPITAL Z;Lu;0;L;<font> 005A;;;;N;;;;;
+1D41A;MATHEMATICAL BOLD SMALL A;Ll;0;L;<font> 0061;;;;N;;;;;
+1D41B;MATHEMATICAL BOLD SMALL B;Ll;0;L;<font> 0062;;;;N;;;;;
+1D41C;MATHEMATICAL BOLD SMALL C;Ll;0;L;<font> 0063;;;;N;;;;;
+1D41D;MATHEMATICAL BOLD SMALL D;Ll;0;L;<font> 0064;;;;N;;;;;
+1D41E;MATHEMATICAL BOLD SMALL E;Ll;0;L;<font> 0065;;;;N;;;;;
+1D41F;MATHEMATICAL BOLD SMALL F;Ll;0;L;<font> 0066;;;;N;;;;;
+1D420;MATHEMATICAL BOLD SMALL G;Ll;0;L;<font> 0067;;;;N;;;;;
+1D421;MATHEMATICAL BOLD SMALL H;Ll;0;L;<font> 0068;;;;N;;;;;
+1D422;MATHEMATICAL BOLD SMALL I;Ll;0;L;<font> 0069;;;;N;;;;;
+1D423;MATHEMATICAL BOLD SMALL J;Ll;0;L;<font> 006A;;;;N;;;;;
+1D424;MATHEMATICAL BOLD SMALL K;Ll;0;L;<font> 006B;;;;N;;;;;
+1D425;MATHEMATICAL BOLD SMALL L;Ll;0;L;<font> 006C;;;;N;;;;;
+1D426;MATHEMATICAL BOLD SMALL M;Ll;0;L;<font> 006D;;;;N;;;;;
+1D427;MATHEMATICAL BOLD SMALL N;Ll;0;L;<font> 006E;;;;N;;;;;
+1D428;MATHEMATICAL BOLD SMALL O;Ll;0;L;<font> 006F;;;;N;;;;;
+1D429;MATHEMATICAL BOLD SMALL P;Ll;0;L;<font> 0070;;;;N;;;;;
+1D42A;MATHEMATICAL BOLD SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;;
+1D42B;MATHEMATICAL BOLD SMALL R;Ll;0;L;<font> 0072;;;;N;;;;;
+1D42C;MATHEMATICAL BOLD SMALL S;Ll;0;L;<font> 0073;;;;N;;;;;
+1D42D;MATHEMATICAL BOLD SMALL T;Ll;0;L;<font> 0074;;;;N;;;;;
+1D42E;MATHEMATICAL BOLD SMALL U;Ll;0;L;<font> 0075;;;;N;;;;;
+1D42F;MATHEMATICAL BOLD SMALL V;Ll;0;L;<font> 0076;;;;N;;;;;
+1D430;MATHEMATICAL BOLD SMALL W;Ll;0;L;<font> 0077;;;;N;;;;;
+1D431;MATHEMATICAL BOLD SMALL X;Ll;0;L;<font> 0078;;;;N;;;;;
+1D432;MATHEMATICAL BOLD SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;;
+1D433;MATHEMATICAL BOLD SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;;
+1D434;MATHEMATICAL ITALIC CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;;
+1D435;MATHEMATICAL ITALIC CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;;
+1D436;MATHEMATICAL ITALIC CAPITAL C;Lu;0;L;<font> 0043;;;;N;;;;;
+1D437;MATHEMATICAL ITALIC CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;;
+1D438;MATHEMATICAL ITALIC CAPITAL E;Lu;0;L;<font> 0045;;;;N;;;;;
+1D439;MATHEMATICAL ITALIC CAPITAL F;Lu;0;L;<font> 0046;;;;N;;;;;
+1D43A;MATHEMATICAL ITALIC CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;;
+1D43B;MATHEMATICAL ITALIC CAPITAL H;Lu;0;L;<font> 0048;;;;N;;;;;
+1D43C;MATHEMATICAL ITALIC CAPITAL I;Lu;0;L;<font> 0049;;;;N;;;;;
+1D43D;MATHEMATICAL ITALIC CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;;
+1D43E;MATHEMATICAL ITALIC CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;;
+1D43F;MATHEMATICAL ITALIC CAPITAL L;Lu;0;L;<font> 004C;;;;N;;;;;
+1D440;MATHEMATICAL ITALIC CAPITAL M;Lu;0;L;<font> 004D;;;;N;;;;;
+1D441;MATHEMATICAL ITALIC CAPITAL N;Lu;0;L;<font> 004E;;;;N;;;;;
+1D442;MATHEMATICAL ITALIC CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;;
+1D443;MATHEMATICAL ITALIC CAPITAL P;Lu;0;L;<font> 0050;;;;N;;;;;
+1D444;MATHEMATICAL ITALIC CAPITAL Q;Lu;0;L;<font> 0051;;;;N;;;;;
+1D445;MATHEMATICAL ITALIC CAPITAL R;Lu;0;L;<font> 0052;;;;N;;;;;
+1D446;MATHEMATICAL ITALIC CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;;
+1D447;MATHEMATICAL ITALIC CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;;
+1D448;MATHEMATICAL ITALIC CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;;
+1D449;MATHEMATICAL ITALIC CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;;
+1D44A;MATHEMATICAL ITALIC CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;;
+1D44B;MATHEMATICAL ITALIC CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;;
+1D44C;MATHEMATICAL ITALIC CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;;
+1D44D;MATHEMATICAL ITALIC CAPITAL Z;Lu;0;L;<font> 005A;;;;N;;;;;
+1D44E;MATHEMATICAL ITALIC SMALL A;Ll;0;L;<font> 0061;;;;N;;;;;
+1D44F;MATHEMATICAL ITALIC SMALL B;Ll;0;L;<font> 0062;;;;N;;;;;
+1D450;MATHEMATICAL ITALIC SMALL C;Ll;0;L;<font> 0063;;;;N;;;;;
+1D451;MATHEMATICAL ITALIC SMALL D;Ll;0;L;<font> 0064;;;;N;;;;;
+1D452;MATHEMATICAL ITALIC SMALL E;Ll;0;L;<font> 0065;;;;N;;;;;
+1D453;MATHEMATICAL ITALIC SMALL F;Ll;0;L;<font> 0066;;;;N;;;;;
+1D454;MATHEMATICAL ITALIC SMALL G;Ll;0;L;<font> 0067;;;;N;;;;;
+1D456;MATHEMATICAL ITALIC SMALL I;Ll;0;L;<font> 0069;;;;N;;;;;
+1D457;MATHEMATICAL ITALIC SMALL J;Ll;0;L;<font> 006A;;;;N;;;;;
+1D458;MATHEMATICAL ITALIC SMALL K;Ll;0;L;<font> 006B;;;;N;;;;;
+1D459;MATHEMATICAL ITALIC SMALL L;Ll;0;L;<font> 006C;;;;N;;;;;
+1D45A;MATHEMATICAL ITALIC SMALL M;Ll;0;L;<font> 006D;;;;N;;;;;
+1D45B;MATHEMATICAL ITALIC SMALL N;Ll;0;L;<font> 006E;;;;N;;;;;
+1D45C;MATHEMATICAL ITALIC SMALL O;Ll;0;L;<font> 006F;;;;N;;;;;
+1D45D;MATHEMATICAL ITALIC SMALL P;Ll;0;L;<font> 0070;;;;N;;;;;
+1D45E;MATHEMATICAL ITALIC SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;;
+1D45F;MATHEMATICAL ITALIC SMALL R;Ll;0;L;<font> 0072;;;;N;;;;;
+1D460;MATHEMATICAL ITALIC SMALL S;Ll;0;L;<font> 0073;;;;N;;;;;
+1D461;MATHEMATICAL ITALIC SMALL T;Ll;0;L;<font> 0074;;;;N;;;;;
+1D462;MATHEMATICAL ITALIC SMALL U;Ll;0;L;<font> 0075;;;;N;;;;;
+1D463;MATHEMATICAL ITALIC SMALL V;Ll;0;L;<font> 0076;;;;N;;;;;
+1D464;MATHEMATICAL ITALIC SMALL W;Ll;0;L;<font> 0077;;;;N;;;;;
+1D465;MATHEMATICAL ITALIC SMALL X;Ll;0;L;<font> 0078;;;;N;;;;;
+1D466;MATHEMATICAL ITALIC SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;;
+1D467;MATHEMATICAL ITALIC SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;;
+1D468;MATHEMATICAL BOLD ITALIC CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;;
+1D469;MATHEMATICAL BOLD ITALIC CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;;
+1D46A;MATHEMATICAL BOLD ITALIC CAPITAL C;Lu;0;L;<font> 0043;;;;N;;;;;
+1D46B;MATHEMATICAL BOLD ITALIC CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;;
+1D46C;MATHEMATICAL BOLD ITALIC CAPITAL E;Lu;0;L;<font> 0045;;;;N;;;;;
+1D46D;MATHEMATICAL BOLD ITALIC CAPITAL F;Lu;0;L;<font> 0046;;;;N;;;;;
+1D46E;MATHEMATICAL BOLD ITALIC CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;;
+1D46F;MATHEMATICAL BOLD ITALIC CAPITAL H;Lu;0;L;<font> 0048;;;;N;;;;;
+1D470;MATHEMATICAL BOLD ITALIC CAPITAL I;Lu;0;L;<font> 0049;;;;N;;;;;
+1D471;MATHEMATICAL BOLD ITALIC CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;;
+1D472;MATHEMATICAL BOLD ITALIC CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;;
+1D473;MATHEMATICAL BOLD ITALIC CAPITAL L;Lu;0;L;<font> 004C;;;;N;;;;;
+1D474;MATHEMATICAL BOLD ITALIC CAPITAL M;Lu;0;L;<font> 004D;;;;N;;;;;
+1D475;MATHEMATICAL BOLD ITALIC CAPITAL N;Lu;0;L;<font> 004E;;;;N;;;;;
+1D476;MATHEMATICAL BOLD ITALIC CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;;
+1D477;MATHEMATICAL BOLD ITALIC CAPITAL P;Lu;0;L;<font> 0050;;;;N;;;;;
+1D478;MATHEMATICAL BOLD ITALIC CAPITAL Q;Lu;0;L;<font> 0051;;;;N;;;;;
+1D479;MATHEMATICAL BOLD ITALIC CAPITAL R;Lu;0;L;<font> 0052;;;;N;;;;;
+1D47A;MATHEMATICAL BOLD ITALIC CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;;
+1D47B;MATHEMATICAL BOLD ITALIC CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;;
+1D47C;MATHEMATICAL BOLD ITALIC CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;;
+1D47D;MATHEMATICAL BOLD ITALIC CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;;
+1D47E;MATHEMATICAL BOLD ITALIC CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;;
+1D47F;MATHEMATICAL BOLD ITALIC CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;;
+1D480;MATHEMATICAL BOLD ITALIC CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;;
+1D481;MATHEMATICAL BOLD ITALIC CAPITAL Z;Lu;0;L;<font> 005A;;;;N;;;;;
+1D482;MATHEMATICAL BOLD ITALIC SMALL A;Ll;0;L;<font> 0061;;;;N;;;;;
+1D483;MATHEMATICAL BOLD ITALIC SMALL B;Ll;0;L;<font> 0062;;;;N;;;;;
+1D484;MATHEMATICAL BOLD ITALIC SMALL C;Ll;0;L;<font> 0063;;;;N;;;;;
+1D485;MATHEMATICAL BOLD ITALIC SMALL D;Ll;0;L;<font> 0064;;;;N;;;;;
+1D486;MATHEMATICAL BOLD ITALIC SMALL E;Ll;0;L;<font> 0065;;;;N;;;;;
+1D487;MATHEMATICAL BOLD ITALIC SMALL F;Ll;0;L;<font> 0066;;;;N;;;;;
+1D488;MATHEMATICAL BOLD ITALIC SMALL G;Ll;0;L;<font> 0067;;;;N;;;;;
+1D489;MATHEMATICAL BOLD ITALIC SMALL H;Ll;0;L;<font> 0068;;;;N;;;;;
+1D48A;MATHEMATICAL BOLD ITALIC SMALL I;Ll;0;L;<font> 0069;;;;N;;;;;
+1D48B;MATHEMATICAL BOLD ITALIC SMALL J;Ll;0;L;<font> 006A;;;;N;;;;;
+1D48C;MATHEMATICAL BOLD ITALIC SMALL K;Ll;0;L;<font> 006B;;;;N;;;;;
+1D48D;MATHEMATICAL BOLD ITALIC SMALL L;Ll;0;L;<font> 006C;;;;N;;;;;
+1D48E;MATHEMATICAL BOLD ITALIC SMALL M;Ll;0;L;<font> 006D;;;;N;;;;;
+1D48F;MATHEMATICAL BOLD ITALIC SMALL N;Ll;0;L;<font> 006E;;;;N;;;;;
+1D490;MATHEMATICAL BOLD ITALIC SMALL O;Ll;0;L;<font> 006F;;;;N;;;;;
+1D491;MATHEMATICAL BOLD ITALIC SMALL P;Ll;0;L;<font> 0070;;;;N;;;;;
+1D492;MATHEMATICAL BOLD ITALIC SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;;
+1D493;MATHEMATICAL BOLD ITALIC SMALL R;Ll;0;L;<font> 0072;;;;N;;;;;
+1D494;MATHEMATICAL BOLD ITALIC SMALL S;Ll;0;L;<font> 0073;;;;N;;;;;
+1D495;MATHEMATICAL BOLD ITALIC SMALL T;Ll;0;L;<font> 0074;;;;N;;;;;
+1D496;MATHEMATICAL BOLD ITALIC SMALL U;Ll;0;L;<font> 0075;;;;N;;;;;
+1D497;MATHEMATICAL BOLD ITALIC SMALL V;Ll;0;L;<font> 0076;;;;N;;;;;
+1D498;MATHEMATICAL BOLD ITALIC SMALL W;Ll;0;L;<font> 0077;;;;N;;;;;
+1D499;MATHEMATICAL BOLD ITALIC SMALL X;Ll;0;L;<font> 0078;;;;N;;;;;
+1D49A;MATHEMATICAL BOLD ITALIC SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;;
+1D49B;MATHEMATICAL BOLD ITALIC SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;;
+1D49C;MATHEMATICAL SCRIPT CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;;
+1D49E;MATHEMATICAL SCRIPT CAPITAL C;Lu;0;L;<font> 0043;;;;N;;;;;
+1D49F;MATHEMATICAL SCRIPT CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;;
+1D4A2;MATHEMATICAL SCRIPT CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;;
+1D4A5;MATHEMATICAL SCRIPT CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;;
+1D4A6;MATHEMATICAL SCRIPT CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;;
+1D4A9;MATHEMATICAL SCRIPT CAPITAL N;Lu;0;L;<font> 004E;;;;N;;;;;
+1D4AA;MATHEMATICAL SCRIPT CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;;
+1D4AB;MATHEMATICAL SCRIPT CAPITAL P;Lu;0;L;<font> 0050;;;;N;;;;;
+1D4AC;MATHEMATICAL SCRIPT CAPITAL Q;Lu;0;L;<font> 0051;;;;N;;;;;
+1D4AE;MATHEMATICAL SCRIPT CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;;
+1D4AF;MATHEMATICAL SCRIPT CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;;
+1D4B0;MATHEMATICAL SCRIPT CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;;
+1D4B1;MATHEMATICAL SCRIPT CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;;
+1D4B2;MATHEMATICAL SCRIPT CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;;
+1D4B3;MATHEMATICAL SCRIPT CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;;
+1D4B4;MATHEMATICAL SCRIPT CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;;
+1D4B5;MATHEMATICAL SCRIPT CAPITAL Z;Lu;0;L;<font> 005A;;;;N;;;;;
+1D4B6;MATHEMATICAL SCRIPT SMALL A;Ll;0;L;<font> 0061;;;;N;;;;;
+1D4B7;MATHEMATICAL SCRIPT SMALL B;Ll;0;L;<font> 0062;;;;N;;;;;
+1D4B8;MATHEMATICAL SCRIPT SMALL C;Ll;0;L;<font> 0063;;;;N;;;;;
+1D4B9;MATHEMATICAL SCRIPT SMALL D;Ll;0;L;<font> 0064;;;;N;;;;;
+1D4BB;MATHEMATICAL SCRIPT SMALL F;Ll;0;L;<font> 0066;;;;N;;;;;
+1D4BD;MATHEMATICAL SCRIPT SMALL H;Ll;0;L;<font> 0068;;;;N;;;;;
+1D4BE;MATHEMATICAL SCRIPT SMALL I;Ll;0;L;<font> 0069;;;;N;;;;;
+1D4BF;MATHEMATICAL SCRIPT SMALL J;Ll;0;L;<font> 006A;;;;N;;;;;
+1D4C0;MATHEMATICAL SCRIPT SMALL K;Ll;0;L;<font> 006B;;;;N;;;;;
+1D4C2;MATHEMATICAL SCRIPT SMALL M;Ll;0;L;<font> 006D;;;;N;;;;;
+1D4C3;MATHEMATICAL SCRIPT SMALL N;Ll;0;L;<font> 006E;;;;N;;;;;
+1D4C5;MATHEMATICAL SCRIPT SMALL P;Ll;0;L;<font> 0070;;;;N;;;;;
+1D4C6;MATHEMATICAL SCRIPT SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;;
+1D4C7;MATHEMATICAL SCRIPT SMALL R;Ll;0;L;<font> 0072;;;;N;;;;;
+1D4C8;MATHEMATICAL SCRIPT SMALL S;Ll;0;L;<font> 0073;;;;N;;;;;
+1D4C9;MATHEMATICAL SCRIPT SMALL T;Ll;0;L;<font> 0074;;;;N;;;;;
+1D4CA;MATHEMATICAL SCRIPT SMALL U;Ll;0;L;<font> 0075;;;;N;;;;;
+1D4CB;MATHEMATICAL SCRIPT SMALL V;Ll;0;L;<font> 0076;;;;N;;;;;
+1D4CC;MATHEMATICAL SCRIPT SMALL W;Ll;0;L;<font> 0077;;;;N;;;;;
+1D4CD;MATHEMATICAL SCRIPT SMALL X;Ll;0;L;<font> 0078;;;;N;;;;;
+1D4CE;MATHEMATICAL SCRIPT SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;;
+1D4CF;MATHEMATICAL SCRIPT SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;;
+1D4D0;MATHEMATICAL BOLD SCRIPT CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;;
+1D4D1;MATHEMATICAL BOLD SCRIPT CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;;
+1D4D2;MATHEMATICAL BOLD SCRIPT CAPITAL C;Lu;0;L;<font> 0043;;;;N;;;;;
+1D4D3;MATHEMATICAL BOLD SCRIPT CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;;
+1D4D4;MATHEMATICAL BOLD SCRIPT CAPITAL E;Lu;0;L;<font> 0045;;;;N;;;;;
+1D4D5;MATHEMATICAL BOLD SCRIPT CAPITAL F;Lu;0;L;<font> 0046;;;;N;;;;;
+1D4D6;MATHEMATICAL BOLD SCRIPT CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;;
+1D4D7;MATHEMATICAL BOLD SCRIPT CAPITAL H;Lu;0;L;<font> 0048;;;;N;;;;;
+1D4D8;MATHEMATICAL BOLD SCRIPT CAPITAL I;Lu;0;L;<font> 0049;;;;N;;;;;
+1D4D9;MATHEMATICAL BOLD SCRIPT CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;;
+1D4DA;MATHEMATICAL BOLD SCRIPT CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;;
+1D4DB;MATHEMATICAL BOLD SCRIPT CAPITAL L;Lu;0;L;<font> 004C;;;;N;;;;;
+1D4DC;MATHEMATICAL BOLD SCRIPT CAPITAL M;Lu;0;L;<font> 004D;;;;N;;;;;
+1D4DD;MATHEMATICAL BOLD SCRIPT CAPITAL N;Lu;0;L;<font> 004E;;;;N;;;;;
+1D4DE;MATHEMATICAL BOLD SCRIPT CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;;
+1D4DF;MATHEMATICAL BOLD SCRIPT CAPITAL P;Lu;0;L;<font> 0050;;;;N;;;;;
+1D4E0;MATHEMATICAL BOLD SCRIPT CAPITAL Q;Lu;0;L;<font> 0051;;;;N;;;;;
+1D4E1;MATHEMATICAL BOLD SCRIPT CAPITAL R;Lu;0;L;<font> 0052;;;;N;;;;;
+1D4E2;MATHEMATICAL BOLD SCRIPT CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;;
+1D4E3;MATHEMATICAL BOLD SCRIPT CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;;
+1D4E4;MATHEMATICAL BOLD SCRIPT CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;;
+1D4E5;MATHEMATICAL BOLD SCRIPT CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;;
+1D4E6;MATHEMATICAL BOLD SCRIPT CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;;
+1D4E7;MATHEMATICAL BOLD SCRIPT CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;;
+1D4E8;MATHEMATICAL BOLD SCRIPT CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;;
+1D4E9;MATHEMATICAL BOLD SCRIPT CAPITAL Z;Lu;0;L;<font> 005A;;;;N;;;;;
+1D4EA;MATHEMATICAL BOLD SCRIPT SMALL A;Ll;0;L;<font> 0061;;;;N;;;;;
+1D4EB;MATHEMATICAL BOLD SCRIPT SMALL B;Ll;0;L;<font> 0062;;;;N;;;;;
+1D4EC;MATHEMATICAL BOLD SCRIPT SMALL C;Ll;0;L;<font> 0063;;;;N;;;;;
+1D4ED;MATHEMATICAL BOLD SCRIPT SMALL D;Ll;0;L;<font> 0064;;;;N;;;;;
+1D4EE;MATHEMATICAL BOLD SCRIPT SMALL E;Ll;0;L;<font> 0065;;;;N;;;;;
+1D4EF;MATHEMATICAL BOLD SCRIPT SMALL F;Ll;0;L;<font> 0066;;;;N;;;;;
+1D4F0;MATHEMATICAL BOLD SCRIPT SMALL G;Ll;0;L;<font> 0067;;;;N;;;;;
+1D4F1;MATHEMATICAL BOLD SCRIPT SMALL H;Ll;0;L;<font> 0068;;;;N;;;;;
+1D4F2;MATHEMATICAL BOLD SCRIPT SMALL I;Ll;0;L;<font> 0069;;;;N;;;;;
+1D4F3;MATHEMATICAL BOLD SCRIPT SMALL J;Ll;0;L;<font> 006A;;;;N;;;;;
+1D4F4;MATHEMATICAL BOLD SCRIPT SMALL K;Ll;0;L;<font> 006B;;;;N;;;;;
+1D4F5;MATHEMATICAL BOLD SCRIPT SMALL L;Ll;0;L;<font> 006C;;;;N;;;;;
+1D4F6;MATHEMATICAL BOLD SCRIPT SMALL M;Ll;0;L;<font> 006D;;;;N;;;;;
+1D4F7;MATHEMATICAL BOLD SCRIPT SMALL N;Ll;0;L;<font> 006E;;;;N;;;;;
+1D4F8;MATHEMATICAL BOLD SCRIPT SMALL O;Ll;0;L;<font> 006F;;;;N;;;;;
+1D4F9;MATHEMATICAL BOLD SCRIPT SMALL P;Ll;0;L;<font> 0070;;;;N;;;;;
+1D4FA;MATHEMATICAL BOLD SCRIPT SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;;
+1D4FB;MATHEMATICAL BOLD SCRIPT SMALL R;Ll;0;L;<font> 0072;;;;N;;;;;
+1D4FC;MATHEMATICAL BOLD SCRIPT SMALL S;Ll;0;L;<font> 0073;;;;N;;;;;
+1D4FD;MATHEMATICAL BOLD SCRIPT SMALL T;Ll;0;L;<font> 0074;;;;N;;;;;
+1D4FE;MATHEMATICAL BOLD SCRIPT SMALL U;Ll;0;L;<font> 0075;;;;N;;;;;
+1D4FF;MATHEMATICAL BOLD SCRIPT SMALL V;Ll;0;L;<font> 0076;;;;N;;;;;
+1D500;MATHEMATICAL BOLD SCRIPT SMALL W;Ll;0;L;<font> 0077;;;;N;;;;;
+1D501;MATHEMATICAL BOLD SCRIPT SMALL X;Ll;0;L;<font> 0078;;;;N;;;;;
+1D502;MATHEMATICAL BOLD SCRIPT SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;;
+1D503;MATHEMATICAL BOLD SCRIPT SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;;
+1D504;MATHEMATICAL FRAKTUR CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;;
+1D505;MATHEMATICAL FRAKTUR CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;;
+1D507;MATHEMATICAL FRAKTUR CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;;
+1D508;MATHEMATICAL FRAKTUR CAPITAL E;Lu;0;L;<font> 0045;;;;N;;;;;
+1D509;MATHEMATICAL FRAKTUR CAPITAL F;Lu;0;L;<font> 0046;;;;N;;;;;
+1D50A;MATHEMATICAL FRAKTUR CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;;
+1D50D;MATHEMATICAL FRAKTUR CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;;
+1D50E;MATHEMATICAL FRAKTUR CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;;
+1D50F;MATHEMATICAL FRAKTUR CAPITAL L;Lu;0;L;<font> 004C;;;;N;;;;;
+1D510;MATHEMATICAL FRAKTUR CAPITAL M;Lu;0;L;<font> 004D;;;;N;;;;;
+1D511;MATHEMATICAL FRAKTUR CAPITAL N;Lu;0;L;<font> 004E;;;;N;;;;;
+1D512;MATHEMATICAL FRAKTUR CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;;
+1D513;MATHEMATICAL FRAKTUR CAPITAL P;Lu;0;L;<font> 0050;;;;N;;;;;
+1D514;MATHEMATICAL FRAKTUR CAPITAL Q;Lu;0;L;<font> 0051;;;;N;;;;;
+1D516;MATHEMATICAL FRAKTUR CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;;
+1D517;MATHEMATICAL FRAKTUR CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;;
+1D518;MATHEMATICAL FRAKTUR CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;;
+1D519;MATHEMATICAL FRAKTUR CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;;
+1D51A;MATHEMATICAL FRAKTUR CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;;
+1D51B;MATHEMATICAL FRAKTUR CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;;
+1D51C;MATHEMATICAL FRAKTUR CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;;
+1D51E;MATHEMATICAL FRAKTUR SMALL A;Ll;0;L;<font> 0061;;;;N;;;;;
+1D51F;MATHEMATICAL FRAKTUR SMALL B;Ll;0;L;<font> 0062;;;;N;;;;;
+1D520;MATHEMATICAL FRAKTUR SMALL C;Ll;0;L;<font> 0063;;;;N;;;;;
+1D521;MATHEMATICAL FRAKTUR SMALL D;Ll;0;L;<font> 0064;;;;N;;;;;
+1D522;MATHEMATICAL FRAKTUR SMALL E;Ll;0;L;<font> 0065;;;;N;;;;;
+1D523;MATHEMATICAL FRAKTUR SMALL F;Ll;0;L;<font> 0066;;;;N;;;;;
+1D524;MATHEMATICAL FRAKTUR SMALL G;Ll;0;L;<font> 0067;;;;N;;;;;
+1D525;MATHEMATICAL FRAKTUR SMALL H;Ll;0;L;<font> 0068;;;;N;;;;;
+1D526;MATHEMATICAL FRAKTUR SMALL I;Ll;0;L;<font> 0069;;;;N;;;;;
+1D527;MATHEMATICAL FRAKTUR SMALL J;Ll;0;L;<font> 006A;;;;N;;;;;
+1D528;MATHEMATICAL FRAKTUR SMALL K;Ll;0;L;<font> 006B;;;;N;;;;;
+1D529;MATHEMATICAL FRAKTUR SMALL L;Ll;0;L;<font> 006C;;;;N;;;;;
+1D52A;MATHEMATICAL FRAKTUR SMALL M;Ll;0;L;<font> 006D;;;;N;;;;;
+1D52B;MATHEMATICAL FRAKTUR SMALL N;Ll;0;L;<font> 006E;;;;N;;;;;
+1D52C;MATHEMATICAL FRAKTUR SMALL O;Ll;0;L;<font> 006F;;;;N;;;;;
+1D52D;MATHEMATICAL FRAKTUR SMALL P;Ll;0;L;<font> 0070;;;;N;;;;;
+1D52E;MATHEMATICAL FRAKTUR SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;;
+1D52F;MATHEMATICAL FRAKTUR SMALL R;Ll;0;L;<font> 0072;;;;N;;;;;
+1D530;MATHEMATICAL FRAKTUR SMALL S;Ll;0;L;<font> 0073;;;;N;;;;;
+1D531;MATHEMATICAL FRAKTUR SMALL T;Ll;0;L;<font> 0074;;;;N;;;;;
+1D532;MATHEMATICAL FRAKTUR SMALL U;Ll;0;L;<font> 0075;;;;N;;;;;
+1D533;MATHEMATICAL FRAKTUR SMALL V;Ll;0;L;<font> 0076;;;;N;;;;;
+1D534;MATHEMATICAL FRAKTUR SMALL W;Ll;0;L;<font> 0077;;;;N;;;;;
+1D535;MATHEMATICAL FRAKTUR SMALL X;Ll;0;L;<font> 0078;;;;N;;;;;
+1D536;MATHEMATICAL FRAKTUR SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;;
+1D537;MATHEMATICAL FRAKTUR SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;;
+1D538;MATHEMATICAL DOUBLE-STRUCK CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;;
+1D539;MATHEMATICAL DOUBLE-STRUCK CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;;
+1D53B;MATHEMATICAL DOUBLE-STRUCK CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;;
+1D53C;MATHEMATICAL DOUBLE-STRUCK CAPITAL E;Lu;0;L;<font> 0045;;;;N;;;;;
+1D53D;MATHEMATICAL DOUBLE-STRUCK CAPITAL F;Lu;0;L;<font> 0046;;;;N;;;;;
+1D53E;MATHEMATICAL DOUBLE-STRUCK CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;;
+1D540;MATHEMATICAL DOUBLE-STRUCK CAPITAL I;Lu;0;L;<font> 0049;;;;N;;;;;
+1D541;MATHEMATICAL DOUBLE-STRUCK CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;;
+1D542;MATHEMATICAL DOUBLE-STRUCK CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;;
+1D543;MATHEMATICAL DOUBLE-STRUCK CAPITAL L;Lu;0;L;<font> 004C;;;;N;;;;;
+1D544;MATHEMATICAL DOUBLE-STRUCK CAPITAL M;Lu;0;L;<font> 004D;;;;N;;;;;
+1D546;MATHEMATICAL DOUBLE-STRUCK CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;;
+1D54A;MATHEMATICAL DOUBLE-STRUCK CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;;
+1D54B;MATHEMATICAL DOUBLE-STRUCK CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;;
+1D54C;MATHEMATICAL DOUBLE-STRUCK CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;;
+1D54D;MATHEMATICAL DOUBLE-STRUCK CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;;
+1D54E;MATHEMATICAL DOUBLE-STRUCK CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;;
+1D54F;MATHEMATICAL DOUBLE-STRUCK CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;;
+1D550;MATHEMATICAL DOUBLE-STRUCK CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;;
+1D552;MATHEMATICAL DOUBLE-STRUCK SMALL A;Ll;0;L;<font> 0061;;;;N;;;;;
+1D553;MATHEMATICAL DOUBLE-STRUCK SMALL B;Ll;0;L;<font> 0062;;;;N;;;;;
+1D554;MATHEMATICAL DOUBLE-STRUCK SMALL C;Ll;0;L;<font> 0063;;;;N;;;;;
+1D555;MATHEMATICAL DOUBLE-STRUCK SMALL D;Ll;0;L;<font> 0064;;;;N;;;;;
+1D556;MATHEMATICAL DOUBLE-STRUCK SMALL E;Ll;0;L;<font> 0065;;;;N;;;;;
+1D557;MATHEMATICAL DOUBLE-STRUCK SMALL F;Ll;0;L;<font> 0066;;;;N;;;;;
+1D558;MATHEMATICAL DOUBLE-STRUCK SMALL G;Ll;0;L;<font> 0067;;;;N;;;;;
+1D559;MATHEMATICAL DOUBLE-STRUCK SMALL H;Ll;0;L;<font> 0068;;;;N;;;;;
+1D55A;MATHEMATICAL DOUBLE-STRUCK SMALL I;Ll;0;L;<font> 0069;;;;N;;;;;
+1D55B;MATHEMATICAL DOUBLE-STRUCK SMALL J;Ll;0;L;<font> 006A;;;;N;;;;;
+1D55C;MATHEMATICAL DOUBLE-STRUCK SMALL K;Ll;0;L;<font> 006B;;;;N;;;;;
+1D55D;MATHEMATICAL DOUBLE-STRUCK SMALL L;Ll;0;L;<font> 006C;;;;N;;;;;
+1D55E;MATHEMATICAL DOUBLE-STRUCK SMALL M;Ll;0;L;<font> 006D;;;;N;;;;;
+1D55F;MATHEMATICAL DOUBLE-STRUCK SMALL N;Ll;0;L;<font> 006E;;;;N;;;;;
+1D560;MATHEMATICAL DOUBLE-STRUCK SMALL O;Ll;0;L;<font> 006F;;;;N;;;;;
+1D561;MATHEMATICAL DOUBLE-STRUCK SMALL P;Ll;0;L;<font> 0070;;;;N;;;;;
+1D562;MATHEMATICAL DOUBLE-STRUCK SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;;
+1D563;MATHEMATICAL DOUBLE-STRUCK SMALL R;Ll;0;L;<font> 0072;;;;N;;;;;
+1D564;MATHEMATICAL DOUBLE-STRUCK SMALL S;Ll;0;L;<font> 0073;;;;N;;;;;
+1D565;MATHEMATICAL DOUBLE-STRUCK SMALL T;Ll;0;L;<font> 0074;;;;N;;;;;
+1D566;MATHEMATICAL DOUBLE-STRUCK SMALL U;Ll;0;L;<font> 0075;;;;N;;;;;
+1D567;MATHEMATICAL DOUBLE-STRUCK SMALL V;Ll;0;L;<font> 0076;;;;N;;;;;
+1D568;MATHEMATICAL DOUBLE-STRUCK SMALL W;Ll;0;L;<font> 0077;;;;N;;;;;
+1D569;MATHEMATICAL DOUBLE-STRUCK SMALL X;Ll;0;L;<font> 0078;;;;N;;;;;
+1D56A;MATHEMATICAL DOUBLE-STRUCK SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;;
+1D56B;MATHEMATICAL DOUBLE-STRUCK SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;;
+1D56C;MATHEMATICAL BOLD FRAKTUR CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;;
+1D56D;MATHEMATICAL BOLD FRAKTUR CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;;
+1D56E;MATHEMATICAL BOLD FRAKTUR CAPITAL C;Lu;0;L;<font> 0043;;;;N;;;;;
+1D56F;MATHEMATICAL BOLD FRAKTUR CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;;
+1D570;MATHEMATICAL BOLD FRAKTUR CAPITAL E;Lu;0;L;<font> 0045;;;;N;;;;;
+1D571;MATHEMATICAL BOLD FRAKTUR CAPITAL F;Lu;0;L;<font> 0046;;;;N;;;;;
+1D572;MATHEMATICAL BOLD FRAKTUR CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;;
+1D573;MATHEMATICAL BOLD FRAKTUR CAPITAL H;Lu;0;L;<font> 0048;;;;N;;;;;
+1D574;MATHEMATICAL BOLD FRAKTUR CAPITAL I;Lu;0;L;<font> 0049;;;;N;;;;;
+1D575;MATHEMATICAL BOLD FRAKTUR CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;;
+1D576;MATHEMATICAL BOLD FRAKTUR CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;;
+1D577;MATHEMATICAL BOLD FRAKTUR CAPITAL L;Lu;0;L;<font> 004C;;;;N;;;;;
+1D578;MATHEMATICAL BOLD FRAKTUR CAPITAL M;Lu;0;L;<font> 004D;;;;N;;;;;
+1D579;MATHEMATICAL BOLD FRAKTUR CAPITAL N;Lu;0;L;<font> 004E;;;;N;;;;;
+1D57A;MATHEMATICAL BOLD FRAKTUR CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;;
+1D57B;MATHEMATICAL BOLD FRAKTUR CAPITAL P;Lu;0;L;<font> 0050;;;;N;;;;;
+1D57C;MATHEMATICAL BOLD FRAKTUR CAPITAL Q;Lu;0;L;<font> 0051;;;;N;;;;;
+1D57D;MATHEMATICAL BOLD FRAKTUR CAPITAL R;Lu;0;L;<font> 0052;;;;N;;;;;
+1D57E;MATHEMATICAL BOLD FRAKTUR CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;;
+1D57F;MATHEMATICAL BOLD FRAKTUR CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;;
+1D580;MATHEMATICAL BOLD FRAKTUR CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;;
+1D581;MATHEMATICAL BOLD FRAKTUR CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;;
+1D582;MATHEMATICAL BOLD FRAKTUR CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;;
+1D583;MATHEMATICAL BOLD FRAKTUR CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;;
+1D584;MATHEMATICAL BOLD FRAKTUR CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;;
+1D585;MATHEMATICAL BOLD FRAKTUR CAPITAL Z;Lu;0;L;<font> 005A;;;;N;;;;;
+1D586;MATHEMATICAL BOLD FRAKTUR SMALL A;Ll;0;L;<font> 0061;;;;N;;;;;
+1D587;MATHEMATICAL BOLD FRAKTUR SMALL B;Ll;0;L;<font> 0062;;;;N;;;;;
+1D588;MATHEMATICAL BOLD FRAKTUR SMALL C;Ll;0;L;<font> 0063;;;;N;;;;;
+1D589;MATHEMATICAL BOLD FRAKTUR SMALL D;Ll;0;L;<font> 0064;;;;N;;;;;
+1D58A;MATHEMATICAL BOLD FRAKTUR SMALL E;Ll;0;L;<font> 0065;;;;N;;;;;
+1D58B;MATHEMATICAL BOLD FRAKTUR SMALL F;Ll;0;L;<font> 0066;;;;N;;;;;
+1D58C;MATHEMATICAL BOLD FRAKTUR SMALL G;Ll;0;L;<font> 0067;;;;N;;;;;
+1D58D;MATHEMATICAL BOLD FRAKTUR SMALL H;Ll;0;L;<font> 0068;;;;N;;;;;
+1D58E;MATHEMATICAL BOLD FRAKTUR SMALL I;Ll;0;L;<font> 0069;;;;N;;;;;
+1D58F;MATHEMATICAL BOLD FRAKTUR SMALL J;Ll;0;L;<font> 006A;;;;N;;;;;
+1D590;MATHEMATICAL BOLD FRAKTUR SMALL K;Ll;0;L;<font> 006B;;;;N;;;;;
+1D591;MATHEMATICAL BOLD FRAKTUR SMALL L;Ll;0;L;<font> 006C;;;;N;;;;;
+1D592;MATHEMATICAL BOLD FRAKTUR SMALL M;Ll;0;L;<font> 006D;;;;N;;;;;
+1D593;MATHEMATICAL BOLD FRAKTUR SMALL N;Ll;0;L;<font> 006E;;;;N;;;;;
+1D594;MATHEMATICAL BOLD FRAKTUR SMALL O;Ll;0;L;<font> 006F;;;;N;;;;;
+1D595;MATHEMATICAL BOLD FRAKTUR SMALL P;Ll;0;L;<font> 0070;;;;N;;;;;
+1D596;MATHEMATICAL BOLD FRAKTUR SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;;
+1D597;MATHEMATICAL BOLD FRAKTUR SMALL R;Ll;0;L;<font> 0072;;;;N;;;;;
+1D598;MATHEMATICAL BOLD FRAKTUR SMALL S;Ll;0;L;<font> 0073;;;;N;;;;;
+1D599;MATHEMATICAL BOLD FRAKTUR SMALL T;Ll;0;L;<font> 0074;;;;N;;;;;
+1D59A;MATHEMATICAL BOLD FRAKTUR SMALL U;Ll;0;L;<font> 0075;;;;N;;;;;
+1D59B;MATHEMATICAL BOLD FRAKTUR SMALL V;Ll;0;L;<font> 0076;;;;N;;;;;
+1D59C;MATHEMATICAL BOLD FRAKTUR SMALL W;Ll;0;L;<font> 0077;;;;N;;;;;
+1D59D;MATHEMATICAL BOLD FRAKTUR SMALL X;Ll;0;L;<font> 0078;;;;N;;;;;
+1D59E;MATHEMATICAL BOLD FRAKTUR SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;;
+1D59F;MATHEMATICAL BOLD FRAKTUR SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;;
+1D5A0;MATHEMATICAL SANS-SERIF CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;;
+1D5A1;MATHEMATICAL SANS-SERIF CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;;
+1D5A2;MATHEMATICAL SANS-SERIF CAPITAL C;Lu;0;L;<font> 0043;;;;N;;;;;
+1D5A3;MATHEMATICAL SANS-SERIF CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;;
+1D5A4;MATHEMATICAL SANS-SERIF CAPITAL E;Lu;0;L;<font> 0045;;;;N;;;;;
+1D5A5;MATHEMATICAL SANS-SERIF CAPITAL F;Lu;0;L;<font> 0046;;;;N;;;;;
+1D5A6;MATHEMATICAL SANS-SERIF CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;;
+1D5A7;MATHEMATICAL SANS-SERIF CAPITAL H;Lu;0;L;<font> 0048;;;;N;;;;;
+1D5A8;MATHEMATICAL SANS-SERIF CAPITAL I;Lu;0;L;<font> 0049;;;;N;;;;;
+1D5A9;MATHEMATICAL SANS-SERIF CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;;
+1D5AA;MATHEMATICAL SANS-SERIF CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;;
+1D5AB;MATHEMATICAL SANS-SERIF CAPITAL L;Lu;0;L;<font> 004C;;;;N;;;;;
+1D5AC;MATHEMATICAL SANS-SERIF CAPITAL M;Lu;0;L;<font> 004D;;;;N;;;;;
+1D5AD;MATHEMATICAL SANS-SERIF CAPITAL N;Lu;0;L;<font> 004E;;;;N;;;;;
+1D5AE;MATHEMATICAL SANS-SERIF CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;;
+1D5AF;MATHEMATICAL SANS-SERIF CAPITAL P;Lu;0;L;<font> 0050;;;;N;;;;;
+1D5B0;MATHEMATICAL SANS-SERIF CAPITAL Q;Lu;0;L;<font> 0051;;;;N;;;;;
+1D5B1;MATHEMATICAL SANS-SERIF CAPITAL R;Lu;0;L;<font> 0052;;;;N;;;;;
+1D5B2;MATHEMATICAL SANS-SERIF CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;;
+1D5B3;MATHEMATICAL SANS-SERIF CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;;
+1D5B4;MATHEMATICAL SANS-SERIF CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;;
+1D5B5;MATHEMATICAL SANS-SERIF CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;;
+1D5B6;MATHEMATICAL SANS-SERIF CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;;
+1D5B7;MATHEMATICAL SANS-SERIF CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;;
+1D5B8;MATHEMATICAL SANS-SERIF CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;;
+1D5B9;MATHEMATICAL SANS-SERIF CAPITAL Z;Lu;0;L;<font> 005A;;;;N;;;;;
+1D5BA;MATHEMATICAL SANS-SERIF SMALL A;Ll;0;L;<font> 0061;;;;N;;;;;
+1D5BB;MATHEMATICAL SANS-SERIF SMALL B;Ll;0;L;<font> 0062;;;;N;;;;;
+1D5BC;MATHEMATICAL SANS-SERIF SMALL C;Ll;0;L;<font> 0063;;;;N;;;;;
+1D5BD;MATHEMATICAL SANS-SERIF SMALL D;Ll;0;L;<font> 0064;;;;N;;;;;
+1D5BE;MATHEMATICAL SANS-SERIF SMALL E;Ll;0;L;<font> 0065;;;;N;;;;;
+1D5BF;MATHEMATICAL SANS-SERIF SMALL F;Ll;0;L;<font> 0066;;;;N;;;;;
+1D5C0;MATHEMATICAL SANS-SERIF SMALL G;Ll;0;L;<font> 0067;;;;N;;;;;
+1D5C1;MATHEMATICAL SANS-SERIF SMALL H;Ll;0;L;<font> 0068;;;;N;;;;;
+1D5C2;MATHEMATICAL SANS-SERIF SMALL I;Ll;0;L;<font> 0069;;;;N;;;;;
+1D5C3;MATHEMATICAL SANS-SERIF SMALL J;Ll;0;L;<font> 006A;;;;N;;;;;
+1D5C4;MATHEMATICAL SANS-SERIF SMALL K;Ll;0;L;<font> 006B;;;;N;;;;;
+1D5C5;MATHEMATICAL SANS-SERIF SMALL L;Ll;0;L;<font> 006C;;;;N;;;;;
+1D5C6;MATHEMATICAL SANS-SERIF SMALL M;Ll;0;L;<font> 006D;;;;N;;;;;
+1D5C7;MATHEMATICAL SANS-SERIF SMALL N;Ll;0;L;<font> 006E;;;;N;;;;;
+1D5C8;MATHEMATICAL SANS-SERIF SMALL O;Ll;0;L;<font> 006F;;;;N;;;;;
+1D5C9;MATHEMATICAL SANS-SERIF SMALL P;Ll;0;L;<font> 0070;;;;N;;;;;
+1D5CA;MATHEMATICAL SANS-SERIF SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;;
+1D5CB;MATHEMATICAL SANS-SERIF SMALL R;Ll;0;L;<font> 0072;;;;N;;;;;
+1D5CC;MATHEMATICAL SANS-SERIF SMALL S;Ll;0;L;<font> 0073;;;;N;;;;;
+1D5CD;MATHEMATICAL SANS-SERIF SMALL T;Ll;0;L;<font> 0074;;;;N;;;;;
+1D5CE;MATHEMATICAL SANS-SERIF SMALL U;Ll;0;L;<font> 0075;;;;N;;;;;
+1D5CF;MATHEMATICAL SANS-SERIF SMALL V;Ll;0;L;<font> 0076;;;;N;;;;;
+1D5D0;MATHEMATICAL SANS-SERIF SMALL W;Ll;0;L;<font> 0077;;;;N;;;;;
+1D5D1;MATHEMATICAL SANS-SERIF SMALL X;Ll;0;L;<font> 0078;;;;N;;;;;
+1D5D2;MATHEMATICAL SANS-SERIF SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;;
+1D5D3;MATHEMATICAL SANS-SERIF SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;;
+1D5D4;MATHEMATICAL SANS-SERIF BOLD CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;;
+1D5D5;MATHEMATICAL SANS-SERIF BOLD CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;;
+1D5D6;MATHEMATICAL SANS-SERIF BOLD CAPITAL C;Lu;0;L;<font> 0043;;;;N;;;;;
+1D5D7;MATHEMATICAL SANS-SERIF BOLD CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;;
+1D5D8;MATHEMATICAL SANS-SERIF BOLD CAPITAL E;Lu;0;L;<font> 0045;;;;N;;;;;
+1D5D9;MATHEMATICAL SANS-SERIF BOLD CAPITAL F;Lu;0;L;<font> 0046;;;;N;;;;;
+1D5DA;MATHEMATICAL SANS-SERIF BOLD CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;;
+1D5DB;MATHEMATICAL SANS-SERIF BOLD CAPITAL H;Lu;0;L;<font> 0048;;;;N;;;;;
+1D5DC;MATHEMATICAL SANS-SERIF BOLD CAPITAL I;Lu;0;L;<font> 0049;;;;N;;;;;
+1D5DD;MATHEMATICAL SANS-SERIF BOLD CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;;
+1D5DE;MATHEMATICAL SANS-SERIF BOLD CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;;
+1D5DF;MATHEMATICAL SANS-SERIF BOLD CAPITAL L;Lu;0;L;<font> 004C;;;;N;;;;;
+1D5E0;MATHEMATICAL SANS-SERIF BOLD CAPITAL M;Lu;0;L;<font> 004D;;;;N;;;;;
+1D5E1;MATHEMATICAL SANS-SERIF BOLD CAPITAL N;Lu;0;L;<font> 004E;;;;N;;;;;
+1D5E2;MATHEMATICAL SANS-SERIF BOLD CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;;
+1D5E3;MATHEMATICAL SANS-SERIF BOLD CAPITAL P;Lu;0;L;<font> 0050;;;;N;;;;;
+1D5E4;MATHEMATICAL SANS-SERIF BOLD CAPITAL Q;Lu;0;L;<font> 0051;;;;N;;;;;
+1D5E5;MATHEMATICAL SANS-SERIF BOLD CAPITAL R;Lu;0;L;<font> 0052;;;;N;;;;;
+1D5E6;MATHEMATICAL SANS-SERIF BOLD CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;;
+1D5E7;MATHEMATICAL SANS-SERIF BOLD CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;;
+1D5E8;MATHEMATICAL SANS-SERIF BOLD CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;;
+1D5E9;MATHEMATICAL SANS-SERIF BOLD CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;;
+1D5EA;MATHEMATICAL SANS-SERIF BOLD CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;;
+1D5EB;MATHEMATICAL SANS-SERIF BOLD CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;;
+1D5EC;MATHEMATICAL SANS-SERIF BOLD CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;;
+1D5ED;MATHEMATICAL SANS-SERIF BOLD CAPITAL Z;Lu;0;L;<font> 005A;;;;N;;;;;
+1D5EE;MATHEMATICAL SANS-SERIF BOLD SMALL A;Ll;0;L;<font> 0061;;;;N;;;;;
+1D5EF;MATHEMATICAL SANS-SERIF BOLD SMALL B;Ll;0;L;<font> 0062;;;;N;;;;;
+1D5F0;MATHEMATICAL SANS-SERIF BOLD SMALL C;Ll;0;L;<font> 0063;;;;N;;;;;
+1D5F1;MATHEMATICAL SANS-SERIF BOLD SMALL D;Ll;0;L;<font> 0064;;;;N;;;;;
+1D5F2;MATHEMATICAL SANS-SERIF BOLD SMALL E;Ll;0;L;<font> 0065;;;;N;;;;;
+1D5F3;MATHEMATICAL SANS-SERIF BOLD SMALL F;Ll;0;L;<font> 0066;;;;N;;;;;
+1D5F4;MATHEMATICAL SANS-SERIF BOLD SMALL G;Ll;0;L;<font> 0067;;;;N;;;;;
+1D5F5;MATHEMATICAL SANS-SERIF BOLD SMALL H;Ll;0;L;<font> 0068;;;;N;;;;;
+1D5F6;MATHEMATICAL SANS-SERIF BOLD SMALL I;Ll;0;L;<font> 0069;;;;N;;;;;
+1D5F7;MATHEMATICAL SANS-SERIF BOLD SMALL J;Ll;0;L;<font> 006A;;;;N;;;;;
+1D5F8;MATHEMATICAL SANS-SERIF BOLD SMALL K;Ll;0;L;<font> 006B;;;;N;;;;;
+1D5F9;MATHEMATICAL SANS-SERIF BOLD SMALL L;Ll;0;L;<font> 006C;;;;N;;;;;
+1D5FA;MATHEMATICAL SANS-SERIF BOLD SMALL M;Ll;0;L;<font> 006D;;;;N;;;;;
+1D5FB;MATHEMATICAL SANS-SERIF BOLD SMALL N;Ll;0;L;<font> 006E;;;;N;;;;;
+1D5FC;MATHEMATICAL SANS-SERIF BOLD SMALL O;Ll;0;L;<font> 006F;;;;N;;;;;
+1D5FD;MATHEMATICAL SANS-SERIF BOLD SMALL P;Ll;0;L;<font> 0070;;;;N;;;;;
+1D5FE;MATHEMATICAL SANS-SERIF BOLD SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;;
+1D5FF;MATHEMATICAL SANS-SERIF BOLD SMALL R;Ll;0;L;<font> 0072;;;;N;;;;;
+1D600;MATHEMATICAL SANS-SERIF BOLD SMALL S;Ll;0;L;<font> 0073;;;;N;;;;;
+1D601;MATHEMATICAL SANS-SERIF BOLD SMALL T;Ll;0;L;<font> 0074;;;;N;;;;;
+1D602;MATHEMATICAL SANS-SERIF BOLD SMALL U;Ll;0;L;<font> 0075;;;;N;;;;;
+1D603;MATHEMATICAL SANS-SERIF BOLD SMALL V;Ll;0;L;<font> 0076;;;;N;;;;;
+1D604;MATHEMATICAL SANS-SERIF BOLD SMALL W;Ll;0;L;<font> 0077;;;;N;;;;;
+1D605;MATHEMATICAL SANS-SERIF BOLD SMALL X;Ll;0;L;<font> 0078;;;;N;;;;;
+1D606;MATHEMATICAL SANS-SERIF BOLD SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;;
+1D607;MATHEMATICAL SANS-SERIF BOLD SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;;
+1D608;MATHEMATICAL SANS-SERIF ITALIC CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;;
+1D609;MATHEMATICAL SANS-SERIF ITALIC CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;;
+1D60A;MATHEMATICAL SANS-SERIF ITALIC CAPITAL C;Lu;0;L;<font> 0043;;;;N;;;;;
+1D60B;MATHEMATICAL SANS-SERIF ITALIC CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;;
+1D60C;MATHEMATICAL SANS-SERIF ITALIC CAPITAL E;Lu;0;L;<font> 0045;;;;N;;;;;
+1D60D;MATHEMATICAL SANS-SERIF ITALIC CAPITAL F;Lu;0;L;<font> 0046;;;;N;;;;;
+1D60E;MATHEMATICAL SANS-SERIF ITALIC CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;;
+1D60F;MATHEMATICAL SANS-SERIF ITALIC CAPITAL H;Lu;0;L;<font> 0048;;;;N;;;;;
+1D610;MATHEMATICAL SANS-SERIF ITALIC CAPITAL I;Lu;0;L;<font> 0049;;;;N;;;;;
+1D611;MATHEMATICAL SANS-SERIF ITALIC CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;;
+1D612;MATHEMATICAL SANS-SERIF ITALIC CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;;
+1D613;MATHEMATICAL SANS-SERIF ITALIC CAPITAL L;Lu;0;L;<font> 004C;;;;N;;;;;
+1D614;MATHEMATICAL SANS-SERIF ITALIC CAPITAL M;Lu;0;L;<font> 004D;;;;N;;;;;
+1D615;MATHEMATICAL SANS-SERIF ITALIC CAPITAL N;Lu;0;L;<font> 004E;;;;N;;;;;
+1D616;MATHEMATICAL SANS-SERIF ITALIC CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;;
+1D617;MATHEMATICAL SANS-SERIF ITALIC CAPITAL P;Lu;0;L;<font> 0050;;;;N;;;;;
+1D618;MATHEMATICAL SANS-SERIF ITALIC CAPITAL Q;Lu;0;L;<font> 0051;;;;N;;;;;
+1D619;MATHEMATICAL SANS-SERIF ITALIC CAPITAL R;Lu;0;L;<font> 0052;;;;N;;;;;
+1D61A;MATHEMATICAL SANS-SERIF ITALIC CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;;
+1D61B;MATHEMATICAL SANS-SERIF ITALIC CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;;
+1D61C;MATHEMATICAL SANS-SERIF ITALIC CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;;
+1D61D;MATHEMATICAL SANS-SERIF ITALIC CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;;
+1D61E;MATHEMATICAL SANS-SERIF ITALIC CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;;
+1D61F;MATHEMATICAL SANS-SERIF ITALIC CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;;
+1D620;MATHEMATICAL SANS-SERIF ITALIC CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;;
+1D621;MATHEMATICAL SANS-SERIF ITALIC CAPITAL Z;Lu;0;L;<font> 005A;;;;N;;;;;
+1D622;MATHEMATICAL SANS-SERIF ITALIC SMALL A;Ll;0;L;<font> 0061;;;;N;;;;;
+1D623;MATHEMATICAL SANS-SERIF ITALIC SMALL B;Ll;0;L;<font> 0062;;;;N;;;;;
+1D624;MATHEMATICAL SANS-SERIF ITALIC SMALL C;Ll;0;L;<font> 0063;;;;N;;;;;
+1D625;MATHEMATICAL SANS-SERIF ITALIC SMALL D;Ll;0;L;<font> 0064;;;;N;;;;;
+1D626;MATHEMATICAL SANS-SERIF ITALIC SMALL E;Ll;0;L;<font> 0065;;;;N;;;;;
+1D627;MATHEMATICAL SANS-SERIF ITALIC SMALL F;Ll;0;L;<font> 0066;;;;N;;;;;
+1D628;MATHEMATICAL SANS-SERIF ITALIC SMALL G;Ll;0;L;<font> 0067;;;;N;;;;;
+1D629;MATHEMATICAL SANS-SERIF ITALIC SMALL H;Ll;0;L;<font> 0068;;;;N;;;;;
+1D62A;MATHEMATICAL SANS-SERIF ITALIC SMALL I;Ll;0;L;<font> 0069;;;;N;;;;;
+1D62B;MATHEMATICAL SANS-SERIF ITALIC SMALL J;Ll;0;L;<font> 006A;;;;N;;;;;
+1D62C;MATHEMATICAL SANS-SERIF ITALIC SMALL K;Ll;0;L;<font> 006B;;;;N;;;;;
+1D62D;MATHEMATICAL SANS-SERIF ITALIC SMALL L;Ll;0;L;<font> 006C;;;;N;;;;;
+1D62E;MATHEMATICAL SANS-SERIF ITALIC SMALL M;Ll;0;L;<font> 006D;;;;N;;;;;
+1D62F;MATHEMATICAL SANS-SERIF ITALIC SMALL N;Ll;0;L;<font> 006E;;;;N;;;;;
+1D630;MATHEMATICAL SANS-SERIF ITALIC SMALL O;Ll;0;L;<font> 006F;;;;N;;;;;
+1D631;MATHEMATICAL SANS-SERIF ITALIC SMALL P;Ll;0;L;<font> 0070;;;;N;;;;;
+1D632;MATHEMATICAL SANS-SERIF ITALIC SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;;
+1D633;MATHEMATICAL SANS-SERIF ITALIC SMALL R;Ll;0;L;<font> 0072;;;;N;;;;;
+1D634;MATHEMATICAL SANS-SERIF ITALIC SMALL S;Ll;0;L;<font> 0073;;;;N;;;;;
+1D635;MATHEMATICAL SANS-SERIF ITALIC SMALL T;Ll;0;L;<font> 0074;;;;N;;;;;
+1D636;MATHEMATICAL SANS-SERIF ITALIC SMALL U;Ll;0;L;<font> 0075;;;;N;;;;;
+1D637;MATHEMATICAL SANS-SERIF ITALIC SMALL V;Ll;0;L;<font> 0076;;;;N;;;;;
+1D638;MATHEMATICAL SANS-SERIF ITALIC SMALL W;Ll;0;L;<font> 0077;;;;N;;;;;
+1D639;MATHEMATICAL SANS-SERIF ITALIC SMALL X;Ll;0;L;<font> 0078;;;;N;;;;;
+1D63A;MATHEMATICAL SANS-SERIF ITALIC SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;;
+1D63B;MATHEMATICAL SANS-SERIF ITALIC SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;;
+1D63C;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;;
+1D63D;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;;
+1D63E;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL C;Lu;0;L;<font> 0043;;;;N;;;;;
+1D63F;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;;
+1D640;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL E;Lu;0;L;<font> 0045;;;;N;;;;;
+1D641;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL F;Lu;0;L;<font> 0046;;;;N;;;;;
+1D642;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;;
+1D643;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL H;Lu;0;L;<font> 0048;;;;N;;;;;
+1D644;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL I;Lu;0;L;<font> 0049;;;;N;;;;;
+1D645;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;;
+1D646;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;;
+1D647;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL L;Lu;0;L;<font> 004C;;;;N;;;;;
+1D648;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL M;Lu;0;L;<font> 004D;;;;N;;;;;
+1D649;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL N;Lu;0;L;<font> 004E;;;;N;;;;;
+1D64A;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;;
+1D64B;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL P;Lu;0;L;<font> 0050;;;;N;;;;;
+1D64C;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL Q;Lu;0;L;<font> 0051;;;;N;;;;;
+1D64D;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL R;Lu;0;L;<font> 0052;;;;N;;;;;
+1D64E;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;;
+1D64F;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;;
+1D650;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;;
+1D651;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;;
+1D652;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;;
+1D653;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;;
+1D654;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;;
+1D655;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL Z;Lu;0;L;<font> 005A;;;;N;;;;;
+1D656;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL A;Ll;0;L;<font> 0061;;;;N;;;;;
+1D657;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL B;Ll;0;L;<font> 0062;;;;N;;;;;
+1D658;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL C;Ll;0;L;<font> 0063;;;;N;;;;;
+1D659;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL D;Ll;0;L;<font> 0064;;;;N;;;;;
+1D65A;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL E;Ll;0;L;<font> 0065;;;;N;;;;;
+1D65B;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL F;Ll;0;L;<font> 0066;;;;N;;;;;
+1D65C;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL G;Ll;0;L;<font> 0067;;;;N;;;;;
+1D65D;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL H;Ll;0;L;<font> 0068;;;;N;;;;;
+1D65E;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL I;Ll;0;L;<font> 0069;;;;N;;;;;
+1D65F;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL J;Ll;0;L;<font> 006A;;;;N;;;;;
+1D660;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL K;Ll;0;L;<font> 006B;;;;N;;;;;
+1D661;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL L;Ll;0;L;<font> 006C;;;;N;;;;;
+1D662;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL M;Ll;0;L;<font> 006D;;;;N;;;;;
+1D663;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL N;Ll;0;L;<font> 006E;;;;N;;;;;
+1D664;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL O;Ll;0;L;<font> 006F;;;;N;;;;;
+1D665;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL P;Ll;0;L;<font> 0070;;;;N;;;;;
+1D666;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;;
+1D667;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL R;Ll;0;L;<font> 0072;;;;N;;;;;
+1D668;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL S;Ll;0;L;<font> 0073;;;;N;;;;;
+1D669;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL T;Ll;0;L;<font> 0074;;;;N;;;;;
+1D66A;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL U;Ll;0;L;<font> 0075;;;;N;;;;;
+1D66B;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL V;Ll;0;L;<font> 0076;;;;N;;;;;
+1D66C;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL W;Ll;0;L;<font> 0077;;;;N;;;;;
+1D66D;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL X;Ll;0;L;<font> 0078;;;;N;;;;;
+1D66E;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;;
+1D66F;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;;
+1D670;MATHEMATICAL MONOSPACE CAPITAL A;Lu;0;L;<font> 0041;;;;N;;;;;
+1D671;MATHEMATICAL MONOSPACE CAPITAL B;Lu;0;L;<font> 0042;;;;N;;;;;
+1D672;MATHEMATICAL MONOSPACE CAPITAL C;Lu;0;L;<font> 0043;;;;N;;;;;
+1D673;MATHEMATICAL MONOSPACE CAPITAL D;Lu;0;L;<font> 0044;;;;N;;;;;
+1D674;MATHEMATICAL MONOSPACE CAPITAL E;Lu;0;L;<font> 0045;;;;N;;;;;
+1D675;MATHEMATICAL MONOSPACE CAPITAL F;Lu;0;L;<font> 0046;;;;N;;;;;
+1D676;MATHEMATICAL MONOSPACE CAPITAL G;Lu;0;L;<font> 0047;;;;N;;;;;
+1D677;MATHEMATICAL MONOSPACE CAPITAL H;Lu;0;L;<font> 0048;;;;N;;;;;
+1D678;MATHEMATICAL MONOSPACE CAPITAL I;Lu;0;L;<font> 0049;;;;N;;;;;
+1D679;MATHEMATICAL MONOSPACE CAPITAL J;Lu;0;L;<font> 004A;;;;N;;;;;
+1D67A;MATHEMATICAL MONOSPACE CAPITAL K;Lu;0;L;<font> 004B;;;;N;;;;;
+1D67B;MATHEMATICAL MONOSPACE CAPITAL L;Lu;0;L;<font> 004C;;;;N;;;;;
+1D67C;MATHEMATICAL MONOSPACE CAPITAL M;Lu;0;L;<font> 004D;;;;N;;;;;
+1D67D;MATHEMATICAL MONOSPACE CAPITAL N;Lu;0;L;<font> 004E;;;;N;;;;;
+1D67E;MATHEMATICAL MONOSPACE CAPITAL O;Lu;0;L;<font> 004F;;;;N;;;;;
+1D67F;MATHEMATICAL MONOSPACE CAPITAL P;Lu;0;L;<font> 0050;;;;N;;;;;
+1D680;MATHEMATICAL MONOSPACE CAPITAL Q;Lu;0;L;<font> 0051;;;;N;;;;;
+1D681;MATHEMATICAL MONOSPACE CAPITAL R;Lu;0;L;<font> 0052;;;;N;;;;;
+1D682;MATHEMATICAL MONOSPACE CAPITAL S;Lu;0;L;<font> 0053;;;;N;;;;;
+1D683;MATHEMATICAL MONOSPACE CAPITAL T;Lu;0;L;<font> 0054;;;;N;;;;;
+1D684;MATHEMATICAL MONOSPACE CAPITAL U;Lu;0;L;<font> 0055;;;;N;;;;;
+1D685;MATHEMATICAL MONOSPACE CAPITAL V;Lu;0;L;<font> 0056;;;;N;;;;;
+1D686;MATHEMATICAL MONOSPACE CAPITAL W;Lu;0;L;<font> 0057;;;;N;;;;;
+1D687;MATHEMATICAL MONOSPACE CAPITAL X;Lu;0;L;<font> 0058;;;;N;;;;;
+1D688;MATHEMATICAL MONOSPACE CAPITAL Y;Lu;0;L;<font> 0059;;;;N;;;;;
+1D689;MATHEMATICAL MONOSPACE CAPITAL Z;Lu;0;L;<font> 005A;;;;N;;;;;
+1D68A;MATHEMATICAL MONOSPACE SMALL A;Ll;0;L;<font> 0061;;;;N;;;;;
+1D68B;MATHEMATICAL MONOSPACE SMALL B;Ll;0;L;<font> 0062;;;;N;;;;;
+1D68C;MATHEMATICAL MONOSPACE SMALL C;Ll;0;L;<font> 0063;;;;N;;;;;
+1D68D;MATHEMATICAL MONOSPACE SMALL D;Ll;0;L;<font> 0064;;;;N;;;;;
+1D68E;MATHEMATICAL MONOSPACE SMALL E;Ll;0;L;<font> 0065;;;;N;;;;;
+1D68F;MATHEMATICAL MONOSPACE SMALL F;Ll;0;L;<font> 0066;;;;N;;;;;
+1D690;MATHEMATICAL MONOSPACE SMALL G;Ll;0;L;<font> 0067;;;;N;;;;;
+1D691;MATHEMATICAL MONOSPACE SMALL H;Ll;0;L;<font> 0068;;;;N;;;;;
+1D692;MATHEMATICAL MONOSPACE SMALL I;Ll;0;L;<font> 0069;;;;N;;;;;
+1D693;MATHEMATICAL MONOSPACE SMALL J;Ll;0;L;<font> 006A;;;;N;;;;;
+1D694;MATHEMATICAL MONOSPACE SMALL K;Ll;0;L;<font> 006B;;;;N;;;;;
+1D695;MATHEMATICAL MONOSPACE SMALL L;Ll;0;L;<font> 006C;;;;N;;;;;
+1D696;MATHEMATICAL MONOSPACE SMALL M;Ll;0;L;<font> 006D;;;;N;;;;;
+1D697;MATHEMATICAL MONOSPACE SMALL N;Ll;0;L;<font> 006E;;;;N;;;;;
+1D698;MATHEMATICAL MONOSPACE SMALL O;Ll;0;L;<font> 006F;;;;N;;;;;
+1D699;MATHEMATICAL MONOSPACE SMALL P;Ll;0;L;<font> 0070;;;;N;;;;;
+1D69A;MATHEMATICAL MONOSPACE SMALL Q;Ll;0;L;<font> 0071;;;;N;;;;;
+1D69B;MATHEMATICAL MONOSPACE SMALL R;Ll;0;L;<font> 0072;;;;N;;;;;
+1D69C;MATHEMATICAL MONOSPACE SMALL S;Ll;0;L;<font> 0073;;;;N;;;;;
+1D69D;MATHEMATICAL MONOSPACE SMALL T;Ll;0;L;<font> 0074;;;;N;;;;;
+1D69E;MATHEMATICAL MONOSPACE SMALL U;Ll;0;L;<font> 0075;;;;N;;;;;
+1D69F;MATHEMATICAL MONOSPACE SMALL V;Ll;0;L;<font> 0076;;;;N;;;;;
+1D6A0;MATHEMATICAL MONOSPACE SMALL W;Ll;0;L;<font> 0077;;;;N;;;;;
+1D6A1;MATHEMATICAL MONOSPACE SMALL X;Ll;0;L;<font> 0078;;;;N;;;;;
+1D6A2;MATHEMATICAL MONOSPACE SMALL Y;Ll;0;L;<font> 0079;;;;N;;;;;
+1D6A3;MATHEMATICAL MONOSPACE SMALL Z;Ll;0;L;<font> 007A;;;;N;;;;;
+1D6A8;MATHEMATICAL BOLD CAPITAL ALPHA;Lu;0;L;<font> 0391;;;;N;;;;;
+1D6A9;MATHEMATICAL BOLD CAPITAL BETA;Lu;0;L;<font> 0392;;;;N;;;;;
+1D6AA;MATHEMATICAL BOLD CAPITAL GAMMA;Lu;0;L;<font> 0393;;;;N;;;;;
+1D6AB;MATHEMATICAL BOLD CAPITAL DELTA;Lu;0;L;<font> 0394;;;;N;;;;;
+1D6AC;MATHEMATICAL BOLD CAPITAL EPSILON;Lu;0;L;<font> 0395;;;;N;;;;;
+1D6AD;MATHEMATICAL BOLD CAPITAL ZETA;Lu;0;L;<font> 0396;;;;N;;;;;
+1D6AE;MATHEMATICAL BOLD CAPITAL ETA;Lu;0;L;<font> 0397;;;;N;;;;;
+1D6AF;MATHEMATICAL BOLD CAPITAL THETA;Lu;0;L;<font> 0398;;;;N;;;;;
+1D6B0;MATHEMATICAL BOLD CAPITAL IOTA;Lu;0;L;<font> 0399;;;;N;;;;;
+1D6B1;MATHEMATICAL BOLD CAPITAL KAPPA;Lu;0;L;<font> 039A;;;;N;;;;;
+1D6B2;MATHEMATICAL BOLD CAPITAL LAMDA;Lu;0;L;<font> 039B;;;;N;;;;;
+1D6B3;MATHEMATICAL BOLD CAPITAL MU;Lu;0;L;<font> 039C;;;;N;;;;;
+1D6B4;MATHEMATICAL BOLD CAPITAL NU;Lu;0;L;<font> 039D;;;;N;;;;;
+1D6B5;MATHEMATICAL BOLD CAPITAL XI;Lu;0;L;<font> 039E;;;;N;;;;;
+1D6B6;MATHEMATICAL BOLD CAPITAL OMICRON;Lu;0;L;<font> 039F;;;;N;;;;;
+1D6B7;MATHEMATICAL BOLD CAPITAL PI;Lu;0;L;<font> 03A0;;;;N;;;;;
+1D6B8;MATHEMATICAL BOLD CAPITAL RHO;Lu;0;L;<font> 03A1;;;;N;;;;;
+1D6B9;MATHEMATICAL BOLD CAPITAL THETA SYMBOL;Lu;0;L;<font> 03F4;;;;N;;;;;
+1D6BA;MATHEMATICAL BOLD CAPITAL SIGMA;Lu;0;L;<font> 03A3;;;;N;;;;;
+1D6BB;MATHEMATICAL BOLD CAPITAL TAU;Lu;0;L;<font> 03A4;;;;N;;;;;
+1D6BC;MATHEMATICAL BOLD CAPITAL UPSILON;Lu;0;L;<font> 03A5;;;;N;;;;;
+1D6BD;MATHEMATICAL BOLD CAPITAL PHI;Lu;0;L;<font> 03A6;;;;N;;;;;
+1D6BE;MATHEMATICAL BOLD CAPITAL CHI;Lu;0;L;<font> 03A7;;;;N;;;;;
+1D6BF;MATHEMATICAL BOLD CAPITAL PSI;Lu;0;L;<font> 03A8;;;;N;;;;;
+1D6C0;MATHEMATICAL BOLD CAPITAL OMEGA;Lu;0;L;<font> 03A9;;;;N;;;;;
+1D6C1;MATHEMATICAL BOLD NABLA;Sm;0;L;<font> 2207;;;;N;;;;;
+1D6C2;MATHEMATICAL BOLD SMALL ALPHA;Ll;0;L;<font> 03B1;;;;N;;;;;
+1D6C3;MATHEMATICAL BOLD SMALL BETA;Ll;0;L;<font> 03B2;;;;N;;;;;
+1D6C4;MATHEMATICAL BOLD SMALL GAMMA;Ll;0;L;<font> 03B3;;;;N;;;;;
+1D6C5;MATHEMATICAL BOLD SMALL DELTA;Ll;0;L;<font> 03B4;;;;N;;;;;
+1D6C6;MATHEMATICAL BOLD SMALL EPSILON;Ll;0;L;<font> 03B5;;;;N;;;;;
+1D6C7;MATHEMATICAL BOLD SMALL ZETA;Ll;0;L;<font> 03B6;;;;N;;;;;
+1D6C8;MATHEMATICAL BOLD SMALL ETA;Ll;0;L;<font> 03B7;;;;N;;;;;
+1D6C9;MATHEMATICAL BOLD SMALL THETA;Ll;0;L;<font> 03B8;;;;N;;;;;
+1D6CA;MATHEMATICAL BOLD SMALL IOTA;Ll;0;L;<font> 03B9;;;;N;;;;;
+1D6CB;MATHEMATICAL BOLD SMALL KAPPA;Ll;0;L;<font> 03BA;;;;N;;;;;
+1D6CC;MATHEMATICAL BOLD SMALL LAMDA;Ll;0;L;<font> 03BB;;;;N;;;;;
+1D6CD;MATHEMATICAL BOLD SMALL MU;Ll;0;L;<font> 03BC;;;;N;;;;;
+1D6CE;MATHEMATICAL BOLD SMALL NU;Ll;0;L;<font> 03BD;;;;N;;;;;
+1D6CF;MATHEMATICAL BOLD SMALL XI;Ll;0;L;<font> 03BE;;;;N;;;;;
+1D6D0;MATHEMATICAL BOLD SMALL OMICRON;Ll;0;L;<font> 03BF;;;;N;;;;;
+1D6D1;MATHEMATICAL BOLD SMALL PI;Ll;0;L;<font> 03C0;;;;N;;;;;
+1D6D2;MATHEMATICAL BOLD SMALL RHO;Ll;0;L;<font> 03C1;;;;N;;;;;
+1D6D3;MATHEMATICAL BOLD SMALL FINAL SIGMA;Ll;0;L;<font> 03C2;;;;N;;;;;
+1D6D4;MATHEMATICAL BOLD SMALL SIGMA;Ll;0;L;<font> 03C3;;;;N;;;;;
+1D6D5;MATHEMATICAL BOLD SMALL TAU;Ll;0;L;<font> 03C4;;;;N;;;;;
+1D6D6;MATHEMATICAL BOLD SMALL UPSILON;Ll;0;L;<font> 03C5;;;;N;;;;;
+1D6D7;MATHEMATICAL BOLD SMALL PHI;Ll;0;L;<font> 03C6;;;;N;;;;;
+1D6D8;MATHEMATICAL BOLD SMALL CHI;Ll;0;L;<font> 03C7;;;;N;;;;;
+1D6D9;MATHEMATICAL BOLD SMALL PSI;Ll;0;L;<font> 03C8;;;;N;;;;;
+1D6DA;MATHEMATICAL BOLD SMALL OMEGA;Ll;0;L;<font> 03C9;;;;N;;;;;
+1D6DB;MATHEMATICAL BOLD PARTIAL DIFFERENTIAL;Sm;0;L;<font> 2202;;;;N;;;;;
+1D6DC;MATHEMATICAL BOLD EPSILON SYMBOL;Ll;0;L;<font> 03F5;;;;N;;;;;
+1D6DD;MATHEMATICAL BOLD THETA SYMBOL;Ll;0;L;<font> 03D1;;;;N;;;;;
+1D6DE;MATHEMATICAL BOLD KAPPA SYMBOL;Ll;0;L;<font> 03F0;;;;N;;;;;
+1D6DF;MATHEMATICAL BOLD PHI SYMBOL;Ll;0;L;<font> 03D5;;;;N;;;;;
+1D6E0;MATHEMATICAL BOLD RHO SYMBOL;Ll;0;L;<font> 03F1;;;;N;;;;;
+1D6E1;MATHEMATICAL BOLD PI SYMBOL;Ll;0;L;<font> 03D6;;;;N;;;;;
+1D6E2;MATHEMATICAL ITALIC CAPITAL ALPHA;Lu;0;L;<font> 0391;;;;N;;;;;
+1D6E3;MATHEMATICAL ITALIC CAPITAL BETA;Lu;0;L;<font> 0392;;;;N;;;;;
+1D6E4;MATHEMATICAL ITALIC CAPITAL GAMMA;Lu;0;L;<font> 0393;;;;N;;;;;
+1D6E5;MATHEMATICAL ITALIC CAPITAL DELTA;Lu;0;L;<font> 0394;;;;N;;;;;
+1D6E6;MATHEMATICAL ITALIC CAPITAL EPSILON;Lu;0;L;<font> 0395;;;;N;;;;;
+1D6E7;MATHEMATICAL ITALIC CAPITAL ZETA;Lu;0;L;<font> 0396;;;;N;;;;;
+1D6E8;MATHEMATICAL ITALIC CAPITAL ETA;Lu;0;L;<font> 0397;;;;N;;;;;
+1D6E9;MATHEMATICAL ITALIC CAPITAL THETA;Lu;0;L;<font> 0398;;;;N;;;;;
+1D6EA;MATHEMATICAL ITALIC CAPITAL IOTA;Lu;0;L;<font> 0399;;;;N;;;;;
+1D6EB;MATHEMATICAL ITALIC CAPITAL KAPPA;Lu;0;L;<font> 039A;;;;N;;;;;
+1D6EC;MATHEMATICAL ITALIC CAPITAL LAMDA;Lu;0;L;<font> 039B;;;;N;;;;;
+1D6ED;MATHEMATICAL ITALIC CAPITAL MU;Lu;0;L;<font> 039C;;;;N;;;;;
+1D6EE;MATHEMATICAL ITALIC CAPITAL NU;Lu;0;L;<font> 039D;;;;N;;;;;
+1D6EF;MATHEMATICAL ITALIC CAPITAL XI;Lu;0;L;<font> 039E;;;;N;;;;;
+1D6F0;MATHEMATICAL ITALIC CAPITAL OMICRON;Lu;0;L;<font> 039F;;;;N;;;;;
+1D6F1;MATHEMATICAL ITALIC CAPITAL PI;Lu;0;L;<font> 03A0;;;;N;;;;;
+1D6F2;MATHEMATICAL ITALIC CAPITAL RHO;Lu;0;L;<font> 03A1;;;;N;;;;;
+1D6F3;MATHEMATICAL ITALIC CAPITAL THETA SYMBOL;Lu;0;L;<font> 03F4;;;;N;;;;;
+1D6F4;MATHEMATICAL ITALIC CAPITAL SIGMA;Lu;0;L;<font> 03A3;;;;N;;;;;
+1D6F5;MATHEMATICAL ITALIC CAPITAL TAU;Lu;0;L;<font> 03A4;;;;N;;;;;
+1D6F6;MATHEMATICAL ITALIC CAPITAL UPSILON;Lu;0;L;<font> 03A5;;;;N;;;;;
+1D6F7;MATHEMATICAL ITALIC CAPITAL PHI;Lu;0;L;<font> 03A6;;;;N;;;;;
+1D6F8;MATHEMATICAL ITALIC CAPITAL CHI;Lu;0;L;<font> 03A7;;;;N;;;;;
+1D6F9;MATHEMATICAL ITALIC CAPITAL PSI;Lu;0;L;<font> 03A8;;;;N;;;;;
+1D6FA;MATHEMATICAL ITALIC CAPITAL OMEGA;Lu;0;L;<font> 03A9;;;;N;;;;;
+1D6FB;MATHEMATICAL ITALIC NABLA;Sm;0;L;<font> 2207;;;;N;;;;;
+1D6FC;MATHEMATICAL ITALIC SMALL ALPHA;Ll;0;L;<font> 03B1;;;;N;;;;;
+1D6FD;MATHEMATICAL ITALIC SMALL BETA;Ll;0;L;<font> 03B2;;;;N;;;;;
+1D6FE;MATHEMATICAL ITALIC SMALL GAMMA;Ll;0;L;<font> 03B3;;;;N;;;;;
+1D6FF;MATHEMATICAL ITALIC SMALL DELTA;Ll;0;L;<font> 03B4;;;;N;;;;;
+1D700;MATHEMATICAL ITALIC SMALL EPSILON;Ll;0;L;<font> 03B5;;;;N;;;;;
+1D701;MATHEMATICAL ITALIC SMALL ZETA;Ll;0;L;<font> 03B6;;;;N;;;;;
+1D702;MATHEMATICAL ITALIC SMALL ETA;Ll;0;L;<font> 03B7;;;;N;;;;;
+1D703;MATHEMATICAL ITALIC SMALL THETA;Ll;0;L;<font> 03B8;;;;N;;;;;
+1D704;MATHEMATICAL ITALIC SMALL IOTA;Ll;0;L;<font> 03B9;;;;N;;;;;
+1D705;MATHEMATICAL ITALIC SMALL KAPPA;Ll;0;L;<font> 03BA;;;;N;;;;;
+1D706;MATHEMATICAL ITALIC SMALL LAMDA;Ll;0;L;<font> 03BB;;;;N;;;;;
+1D707;MATHEMATICAL ITALIC SMALL MU;Ll;0;L;<font> 03BC;;;;N;;;;;
+1D708;MATHEMATICAL ITALIC SMALL NU;Ll;0;L;<font> 03BD;;;;N;;;;;
+1D709;MATHEMATICAL ITALIC SMALL XI;Ll;0;L;<font> 03BE;;;;N;;;;;
+1D70A;MATHEMATICAL ITALIC SMALL OMICRON;Ll;0;L;<font> 03BF;;;;N;;;;;
+1D70B;MATHEMATICAL ITALIC SMALL PI;Ll;0;L;<font> 03C0;;;;N;;;;;
+1D70C;MATHEMATICAL ITALIC SMALL RHO;Ll;0;L;<font> 03C1;;;;N;;;;;
+1D70D;MATHEMATICAL ITALIC SMALL FINAL SIGMA;Ll;0;L;<font> 03C2;;;;N;;;;;
+1D70E;MATHEMATICAL ITALIC SMALL SIGMA;Ll;0;L;<font> 03C3;;;;N;;;;;
+1D70F;MATHEMATICAL ITALIC SMALL TAU;Ll;0;L;<font> 03C4;;;;N;;;;;
+1D710;MATHEMATICAL ITALIC SMALL UPSILON;Ll;0;L;<font> 03C5;;;;N;;;;;
+1D711;MATHEMATICAL ITALIC SMALL PHI;Ll;0;L;<font> 03C6;;;;N;;;;;
+1D712;MATHEMATICAL ITALIC SMALL CHI;Ll;0;L;<font> 03C7;;;;N;;;;;
+1D713;MATHEMATICAL ITALIC SMALL PSI;Ll;0;L;<font> 03C8;;;;N;;;;;
+1D714;MATHEMATICAL ITALIC SMALL OMEGA;Ll;0;L;<font> 03C9;;;;N;;;;;
+1D715;MATHEMATICAL ITALIC PARTIAL DIFFERENTIAL;Sm;0;L;<font> 2202;;;;N;;;;;
+1D716;MATHEMATICAL ITALIC EPSILON SYMBOL;Ll;0;L;<font> 03F5;;;;N;;;;;
+1D717;MATHEMATICAL ITALIC THETA SYMBOL;Ll;0;L;<font> 03D1;;;;N;;;;;
+1D718;MATHEMATICAL ITALIC KAPPA SYMBOL;Ll;0;L;<font> 03F0;;;;N;;;;;
+1D719;MATHEMATICAL ITALIC PHI SYMBOL;Ll;0;L;<font> 03D5;;;;N;;;;;
+1D71A;MATHEMATICAL ITALIC RHO SYMBOL;Ll;0;L;<font> 03F1;;;;N;;;;;
+1D71B;MATHEMATICAL ITALIC PI SYMBOL;Ll;0;L;<font> 03D6;;;;N;;;;;
+1D71C;MATHEMATICAL BOLD ITALIC CAPITAL ALPHA;Lu;0;L;<font> 0391;;;;N;;;;;
+1D71D;MATHEMATICAL BOLD ITALIC CAPITAL BETA;Lu;0;L;<font> 0392;;;;N;;;;;
+1D71E;MATHEMATICAL BOLD ITALIC CAPITAL GAMMA;Lu;0;L;<font> 0393;;;;N;;;;;
+1D71F;MATHEMATICAL BOLD ITALIC CAPITAL DELTA;Lu;0;L;<font> 0394;;;;N;;;;;
+1D720;MATHEMATICAL BOLD ITALIC CAPITAL EPSILON;Lu;0;L;<font> 0395;;;;N;;;;;
+1D721;MATHEMATICAL BOLD ITALIC CAPITAL ZETA;Lu;0;L;<font> 0396;;;;N;;;;;
+1D722;MATHEMATICAL BOLD ITALIC CAPITAL ETA;Lu;0;L;<font> 0397;;;;N;;;;;
+1D723;MATHEMATICAL BOLD ITALIC CAPITAL THETA;Lu;0;L;<font> 0398;;;;N;;;;;
+1D724;MATHEMATICAL BOLD ITALIC CAPITAL IOTA;Lu;0;L;<font> 0399;;;;N;;;;;
+1D725;MATHEMATICAL BOLD ITALIC CAPITAL KAPPA;Lu;0;L;<font> 039A;;;;N;;;;;
+1D726;MATHEMATICAL BOLD ITALIC CAPITAL LAMDA;Lu;0;L;<font> 039B;;;;N;;;;;
+1D727;MATHEMATICAL BOLD ITALIC CAPITAL MU;Lu;0;L;<font> 039C;;;;N;;;;;
+1D728;MATHEMATICAL BOLD ITALIC CAPITAL NU;Lu;0;L;<font> 039D;;;;N;;;;;
+1D729;MATHEMATICAL BOLD ITALIC CAPITAL XI;Lu;0;L;<font> 039E;;;;N;;;;;
+1D72A;MATHEMATICAL BOLD ITALIC CAPITAL OMICRON;Lu;0;L;<font> 039F;;;;N;;;;;
+1D72B;MATHEMATICAL BOLD ITALIC CAPITAL PI;Lu;0;L;<font> 03A0;;;;N;;;;;
+1D72C;MATHEMATICAL BOLD ITALIC CAPITAL RHO;Lu;0;L;<font> 03A1;;;;N;;;;;
+1D72D;MATHEMATICAL BOLD ITALIC CAPITAL THETA SYMBOL;Lu;0;L;<font> 03F4;;;;N;;;;;
+1D72E;MATHEMATICAL BOLD ITALIC CAPITAL SIGMA;Lu;0;L;<font> 03A3;;;;N;;;;;
+1D72F;MATHEMATICAL BOLD ITALIC CAPITAL TAU;Lu;0;L;<font> 03A4;;;;N;;;;;
+1D730;MATHEMATICAL BOLD ITALIC CAPITAL UPSILON;Lu;0;L;<font> 03A5;;;;N;;;;;
+1D731;MATHEMATICAL BOLD ITALIC CAPITAL PHI;Lu;0;L;<font> 03A6;;;;N;;;;;
+1D732;MATHEMATICAL BOLD ITALIC CAPITAL CHI;Lu;0;L;<font> 03A7;;;;N;;;;;
+1D733;MATHEMATICAL BOLD ITALIC CAPITAL PSI;Lu;0;L;<font> 03A8;;;;N;;;;;
+1D734;MATHEMATICAL BOLD ITALIC CAPITAL OMEGA;Lu;0;L;<font> 03A9;;;;N;;;;;
+1D735;MATHEMATICAL BOLD ITALIC NABLA;Sm;0;L;<font> 2207;;;;N;;;;;
+1D736;MATHEMATICAL BOLD ITALIC SMALL ALPHA;Ll;0;L;<font> 03B1;;;;N;;;;;
+1D737;MATHEMATICAL BOLD ITALIC SMALL BETA;Ll;0;L;<font> 03B2;;;;N;;;;;
+1D738;MATHEMATICAL BOLD ITALIC SMALL GAMMA;Ll;0;L;<font> 03B3;;;;N;;;;;
+1D739;MATHEMATICAL BOLD ITALIC SMALL DELTA;Ll;0;L;<font> 03B4;;;;N;;;;;
+1D73A;MATHEMATICAL BOLD ITALIC SMALL EPSILON;Ll;0;L;<font> 03B5;;;;N;;;;;
+1D73B;MATHEMATICAL BOLD ITALIC SMALL ZETA;Ll;0;L;<font> 03B6;;;;N;;;;;
+1D73C;MATHEMATICAL BOLD ITALIC SMALL ETA;Ll;0;L;<font> 03B7;;;;N;;;;;
+1D73D;MATHEMATICAL BOLD ITALIC SMALL THETA;Ll;0;L;<font> 03B8;;;;N;;;;;
+1D73E;MATHEMATICAL BOLD ITALIC SMALL IOTA;Ll;0;L;<font> 03B9;;;;N;;;;;
+1D73F;MATHEMATICAL BOLD ITALIC SMALL KAPPA;Ll;0;L;<font> 03BA;;;;N;;;;;
+1D740;MATHEMATICAL BOLD ITALIC SMALL LAMDA;Ll;0;L;<font> 03BB;;;;N;;;;;
+1D741;MATHEMATICAL BOLD ITALIC SMALL MU;Ll;0;L;<font> 03BC;;;;N;;;;;
+1D742;MATHEMATICAL BOLD ITALIC SMALL NU;Ll;0;L;<font> 03BD;;;;N;;;;;
+1D743;MATHEMATICAL BOLD ITALIC SMALL XI;Ll;0;L;<font> 03BE;;;;N;;;;;
+1D744;MATHEMATICAL BOLD ITALIC SMALL OMICRON;Ll;0;L;<font> 03BF;;;;N;;;;;
+1D745;MATHEMATICAL BOLD ITALIC SMALL PI;Ll;0;L;<font> 03C0;;;;N;;;;;
+1D746;MATHEMATICAL BOLD ITALIC SMALL RHO;Ll;0;L;<font> 03C1;;;;N;;;;;
+1D747;MATHEMATICAL BOLD ITALIC SMALL FINAL SIGMA;Ll;0;L;<font> 03C2;;;;N;;;;;
+1D748;MATHEMATICAL BOLD ITALIC SMALL SIGMA;Ll;0;L;<font> 03C3;;;;N;;;;;
+1D749;MATHEMATICAL BOLD ITALIC SMALL TAU;Ll;0;L;<font> 03C4;;;;N;;;;;
+1D74A;MATHEMATICAL BOLD ITALIC SMALL UPSILON;Ll;0;L;<font> 03C5;;;;N;;;;;
+1D74B;MATHEMATICAL BOLD ITALIC SMALL PHI;Ll;0;L;<font> 03C6;;;;N;;;;;
+1D74C;MATHEMATICAL BOLD ITALIC SMALL CHI;Ll;0;L;<font> 03C7;;;;N;;;;;
+1D74D;MATHEMATICAL BOLD ITALIC SMALL PSI;Ll;0;L;<font> 03C8;;;;N;;;;;
+1D74E;MATHEMATICAL BOLD ITALIC SMALL OMEGA;Ll;0;L;<font> 03C9;;;;N;;;;;
+1D74F;MATHEMATICAL BOLD ITALIC PARTIAL DIFFERENTIAL;Sm;0;L;<font> 2202;;;;N;;;;;
+1D750;MATHEMATICAL BOLD ITALIC EPSILON SYMBOL;Ll;0;L;<font> 03F5;;;;N;;;;;
+1D751;MATHEMATICAL BOLD ITALIC THETA SYMBOL;Ll;0;L;<font> 03D1;;;;N;;;;;
+1D752;MATHEMATICAL BOLD ITALIC KAPPA SYMBOL;Ll;0;L;<font> 03F0;;;;N;;;;;
+1D753;MATHEMATICAL BOLD ITALIC PHI SYMBOL;Ll;0;L;<font> 03D5;;;;N;;;;;
+1D754;MATHEMATICAL BOLD ITALIC RHO SYMBOL;Ll;0;L;<font> 03F1;;;;N;;;;;
+1D755;MATHEMATICAL BOLD ITALIC PI SYMBOL;Ll;0;L;<font> 03D6;;;;N;;;;;
+1D756;MATHEMATICAL SANS-SERIF BOLD CAPITAL ALPHA;Lu;0;L;<font> 0391;;;;N;;;;;
+1D757;MATHEMATICAL SANS-SERIF BOLD CAPITAL BETA;Lu;0;L;<font> 0392;;;;N;;;;;
+1D758;MATHEMATICAL SANS-SERIF BOLD CAPITAL GAMMA;Lu;0;L;<font> 0393;;;;N;;;;;
+1D759;MATHEMATICAL SANS-SERIF BOLD CAPITAL DELTA;Lu;0;L;<font> 0394;;;;N;;;;;
+1D75A;MATHEMATICAL SANS-SERIF BOLD CAPITAL EPSILON;Lu;0;L;<font> 0395;;;;N;;;;;
+1D75B;MATHEMATICAL SANS-SERIF BOLD CAPITAL ZETA;Lu;0;L;<font> 0396;;;;N;;;;;
+1D75C;MATHEMATICAL SANS-SERIF BOLD CAPITAL ETA;Lu;0;L;<font> 0397;;;;N;;;;;
+1D75D;MATHEMATICAL SANS-SERIF BOLD CAPITAL THETA;Lu;0;L;<font> 0398;;;;N;;;;;
+1D75E;MATHEMATICAL SANS-SERIF BOLD CAPITAL IOTA;Lu;0;L;<font> 0399;;;;N;;;;;
+1D75F;MATHEMATICAL SANS-SERIF BOLD CAPITAL KAPPA;Lu;0;L;<font> 039A;;;;N;;;;;
+1D760;MATHEMATICAL SANS-SERIF BOLD CAPITAL LAMDA;Lu;0;L;<font> 039B;;;;N;;;;;
+1D761;MATHEMATICAL SANS-SERIF BOLD CAPITAL MU;Lu;0;L;<font> 039C;;;;N;;;;;
+1D762;MATHEMATICAL SANS-SERIF BOLD CAPITAL NU;Lu;0;L;<font> 039D;;;;N;;;;;
+1D763;MATHEMATICAL SANS-SERIF BOLD CAPITAL XI;Lu;0;L;<font> 039E;;;;N;;;;;
+1D764;MATHEMATICAL SANS-SERIF BOLD CAPITAL OMICRON;Lu;0;L;<font> 039F;;;;N;;;;;
+1D765;MATHEMATICAL SANS-SERIF BOLD CAPITAL PI;Lu;0;L;<font> 03A0;;;;N;;;;;
+1D766;MATHEMATICAL SANS-SERIF BOLD CAPITAL RHO;Lu;0;L;<font> 03A1;;;;N;;;;;
+1D767;MATHEMATICAL SANS-SERIF BOLD CAPITAL THETA SYMBOL;Lu;0;L;<font> 03F4;;;;N;;;;;
+1D768;MATHEMATICAL SANS-SERIF BOLD CAPITAL SIGMA;Lu;0;L;<font> 03A3;;;;N;;;;;
+1D769;MATHEMATICAL SANS-SERIF BOLD CAPITAL TAU;Lu;0;L;<font> 03A4;;;;N;;;;;
+1D76A;MATHEMATICAL SANS-SERIF BOLD CAPITAL UPSILON;Lu;0;L;<font> 03A5;;;;N;;;;;
+1D76B;MATHEMATICAL SANS-SERIF BOLD CAPITAL PHI;Lu;0;L;<font> 03A6;;;;N;;;;;
+1D76C;MATHEMATICAL SANS-SERIF BOLD CAPITAL CHI;Lu;0;L;<font> 03A7;;;;N;;;;;
+1D76D;MATHEMATICAL SANS-SERIF BOLD CAPITAL PSI;Lu;0;L;<font> 03A8;;;;N;;;;;
+1D76E;MATHEMATICAL SANS-SERIF BOLD CAPITAL OMEGA;Lu;0;L;<font> 03A9;;;;N;;;;;
+1D76F;MATHEMATICAL SANS-SERIF BOLD NABLA;Sm;0;L;<font> 2207;;;;N;;;;;
+1D770;MATHEMATICAL SANS-SERIF BOLD SMALL ALPHA;Ll;0;L;<font> 03B1;;;;N;;;;;
+1D771;MATHEMATICAL SANS-SERIF BOLD SMALL BETA;Ll;0;L;<font> 03B2;;;;N;;;;;
+1D772;MATHEMATICAL SANS-SERIF BOLD SMALL GAMMA;Ll;0;L;<font> 03B3;;;;N;;;;;
+1D773;MATHEMATICAL SANS-SERIF BOLD SMALL DELTA;Ll;0;L;<font> 03B4;;;;N;;;;;
+1D774;MATHEMATICAL SANS-SERIF BOLD SMALL EPSILON;Ll;0;L;<font> 03B5;;;;N;;;;;
+1D775;MATHEMATICAL SANS-SERIF BOLD SMALL ZETA;Ll;0;L;<font> 03B6;;;;N;;;;;
+1D776;MATHEMATICAL SANS-SERIF BOLD SMALL ETA;Ll;0;L;<font> 03B7;;;;N;;;;;
+1D777;MATHEMATICAL SANS-SERIF BOLD SMALL THETA;Ll;0;L;<font> 03B8;;;;N;;;;;
+1D778;MATHEMATICAL SANS-SERIF BOLD SMALL IOTA;Ll;0;L;<font> 03B9;;;;N;;;;;
+1D779;MATHEMATICAL SANS-SERIF BOLD SMALL KAPPA;Ll;0;L;<font> 03BA;;;;N;;;;;
+1D77A;MATHEMATICAL SANS-SERIF BOLD SMALL LAMDA;Ll;0;L;<font> 03BB;;;;N;;;;;
+1D77B;MATHEMATICAL SANS-SERIF BOLD SMALL MU;Ll;0;L;<font> 03BC;;;;N;;;;;
+1D77C;MATHEMATICAL SANS-SERIF BOLD SMALL NU;Ll;0;L;<font> 03BD;;;;N;;;;;
+1D77D;MATHEMATICAL SANS-SERIF BOLD SMALL XI;Ll;0;L;<font> 03BE;;;;N;;;;;
+1D77E;MATHEMATICAL SANS-SERIF BOLD SMALL OMICRON;Ll;0;L;<font> 03BF;;;;N;;;;;
+1D77F;MATHEMATICAL SANS-SERIF BOLD SMALL PI;Ll;0;L;<font> 03C0;;;;N;;;;;
+1D780;MATHEMATICAL SANS-SERIF BOLD SMALL RHO;Ll;0;L;<font> 03C1;;;;N;;;;;
+1D781;MATHEMATICAL SANS-SERIF BOLD SMALL FINAL SIGMA;Ll;0;L;<font> 03C2;;;;N;;;;;
+1D782;MATHEMATICAL SANS-SERIF BOLD SMALL SIGMA;Ll;0;L;<font> 03C3;;;;N;;;;;
+1D783;MATHEMATICAL SANS-SERIF BOLD SMALL TAU;Ll;0;L;<font> 03C4;;;;N;;;;;
+1D784;MATHEMATICAL SANS-SERIF BOLD SMALL UPSILON;Ll;0;L;<font> 03C5;;;;N;;;;;
+1D785;MATHEMATICAL SANS-SERIF BOLD SMALL PHI;Ll;0;L;<font> 03C6;;;;N;;;;;
+1D786;MATHEMATICAL SANS-SERIF BOLD SMALL CHI;Ll;0;L;<font> 03C7;;;;N;;;;;
+1D787;MATHEMATICAL SANS-SERIF BOLD SMALL PSI;Ll;0;L;<font> 03C8;;;;N;;;;;
+1D788;MATHEMATICAL SANS-SERIF BOLD SMALL OMEGA;Ll;0;L;<font> 03C9;;;;N;;;;;
+1D789;MATHEMATICAL SANS-SERIF BOLD PARTIAL DIFFERENTIAL;Sm;0;L;<font> 2202;;;;N;;;;;
+1D78A;MATHEMATICAL SANS-SERIF BOLD EPSILON SYMBOL;Ll;0;L;<font> 03F5;;;;N;;;;;
+1D78B;MATHEMATICAL SANS-SERIF BOLD THETA SYMBOL;Ll;0;L;<font> 03D1;;;;N;;;;;
+1D78C;MATHEMATICAL SANS-SERIF BOLD KAPPA SYMBOL;Ll;0;L;<font> 03F0;;;;N;;;;;
+1D78D;MATHEMATICAL SANS-SERIF BOLD PHI SYMBOL;Ll;0;L;<font> 03D5;;;;N;;;;;
+1D78E;MATHEMATICAL SANS-SERIF BOLD RHO SYMBOL;Ll;0;L;<font> 03F1;;;;N;;;;;
+1D78F;MATHEMATICAL SANS-SERIF BOLD PI SYMBOL;Ll;0;L;<font> 03D6;;;;N;;;;;
+1D790;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL ALPHA;Lu;0;L;<font> 0391;;;;N;;;;;
+1D791;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL BETA;Lu;0;L;<font> 0392;;;;N;;;;;
+1D792;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL GAMMA;Lu;0;L;<font> 0393;;;;N;;;;;
+1D793;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL DELTA;Lu;0;L;<font> 0394;;;;N;;;;;
+1D794;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL EPSILON;Lu;0;L;<font> 0395;;;;N;;;;;
+1D795;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL ZETA;Lu;0;L;<font> 0396;;;;N;;;;;
+1D796;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL ETA;Lu;0;L;<font> 0397;;;;N;;;;;
+1D797;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL THETA;Lu;0;L;<font> 0398;;;;N;;;;;
+1D798;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL IOTA;Lu;0;L;<font> 0399;;;;N;;;;;
+1D799;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL KAPPA;Lu;0;L;<font> 039A;;;;N;;;;;
+1D79A;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL LAMDA;Lu;0;L;<font> 039B;;;;N;;;;;
+1D79B;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL MU;Lu;0;L;<font> 039C;;;;N;;;;;
+1D79C;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL NU;Lu;0;L;<font> 039D;;;;N;;;;;
+1D79D;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL XI;Lu;0;L;<font> 039E;;;;N;;;;;
+1D79E;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL OMICRON;Lu;0;L;<font> 039F;;;;N;;;;;
+1D79F;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL PI;Lu;0;L;<font> 03A0;;;;N;;;;;
+1D7A0;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL RHO;Lu;0;L;<font> 03A1;;;;N;;;;;
+1D7A1;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL THETA SYMBOL;Lu;0;L;<font> 03F4;;;;N;;;;;
+1D7A2;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL SIGMA;Lu;0;L;<font> 03A3;;;;N;;;;;
+1D7A3;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL TAU;Lu;0;L;<font> 03A4;;;;N;;;;;
+1D7A4;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL UPSILON;Lu;0;L;<font> 03A5;;;;N;;;;;
+1D7A5;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL PHI;Lu;0;L;<font> 03A6;;;;N;;;;;
+1D7A6;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL CHI;Lu;0;L;<font> 03A7;;;;N;;;;;
+1D7A7;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL PSI;Lu;0;L;<font> 03A8;;;;N;;;;;
+1D7A8;MATHEMATICAL SANS-SERIF BOLD ITALIC CAPITAL OMEGA;Lu;0;L;<font> 03A9;;;;N;;;;;
+1D7A9;MATHEMATICAL SANS-SERIF BOLD ITALIC NABLA;Sm;0;L;<font> 2207;;;;N;;;;;
+1D7AA;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL ALPHA;Ll;0;L;<font> 03B1;;;;N;;;;;
+1D7AB;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL BETA;Ll;0;L;<font> 03B2;;;;N;;;;;
+1D7AC;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL GAMMA;Ll;0;L;<font> 03B3;;;;N;;;;;
+1D7AD;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL DELTA;Ll;0;L;<font> 03B4;;;;N;;;;;
+1D7AE;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL EPSILON;Ll;0;L;<font> 03B5;;;;N;;;;;
+1D7AF;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL ZETA;Ll;0;L;<font> 03B6;;;;N;;;;;
+1D7B0;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL ETA;Ll;0;L;<font> 03B7;;;;N;;;;;
+1D7B1;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL THETA;Ll;0;L;<font> 03B8;;;;N;;;;;
+1D7B2;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL IOTA;Ll;0;L;<font> 03B9;;;;N;;;;;
+1D7B3;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL KAPPA;Ll;0;L;<font> 03BA;;;;N;;;;;
+1D7B4;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL LAMDA;Ll;0;L;<font> 03BB;;;;N;;;;;
+1D7B5;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL MU;Ll;0;L;<font> 03BC;;;;N;;;;;
+1D7B6;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL NU;Ll;0;L;<font> 03BD;;;;N;;;;;
+1D7B7;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL XI;Ll;0;L;<font> 03BE;;;;N;;;;;
+1D7B8;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL OMICRON;Ll;0;L;<font> 03BF;;;;N;;;;;
+1D7B9;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL PI;Ll;0;L;<font> 03C0;;;;N;;;;;
+1D7BA;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL RHO;Ll;0;L;<font> 03C1;;;;N;;;;;
+1D7BB;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL FINAL SIGMA;Ll;0;L;<font> 03C2;;;;N;;;;;
+1D7BC;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL SIGMA;Ll;0;L;<font> 03C3;;;;N;;;;;
+1D7BD;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL TAU;Ll;0;L;<font> 03C4;;;;N;;;;;
+1D7BE;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL UPSILON;Ll;0;L;<font> 03C5;;;;N;;;;;
+1D7BF;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL PHI;Ll;0;L;<font> 03C6;;;;N;;;;;
+1D7C0;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL CHI;Ll;0;L;<font> 03C7;;;;N;;;;;
+1D7C1;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL PSI;Ll;0;L;<font> 03C8;;;;N;;;;;
+1D7C2;MATHEMATICAL SANS-SERIF BOLD ITALIC SMALL OMEGA;Ll;0;L;<font> 03C9;;;;N;;;;;
+1D7C3;MATHEMATICAL SANS-SERIF BOLD ITALIC PARTIAL DIFFERENTIAL;Sm;0;L;<font> 2202;;;;N;;;;;
+1D7C4;MATHEMATICAL SANS-SERIF BOLD ITALIC EPSILON SYMBOL;Ll;0;L;<font> 03F5;;;;N;;;;;
+1D7C5;MATHEMATICAL SANS-SERIF BOLD ITALIC THETA SYMBOL;Ll;0;L;<font> 03D1;;;;N;;;;;
+1D7C6;MATHEMATICAL SANS-SERIF BOLD ITALIC KAPPA SYMBOL;Ll;0;L;<font> 03F0;;;;N;;;;;
+1D7C7;MATHEMATICAL SANS-SERIF BOLD ITALIC PHI SYMBOL;Ll;0;L;<font> 03D5;;;;N;;;;;
+1D7C8;MATHEMATICAL SANS-SERIF BOLD ITALIC RHO SYMBOL;Ll;0;L;<font> 03F1;;;;N;;;;;
+1D7C9;MATHEMATICAL SANS-SERIF BOLD ITALIC PI SYMBOL;Ll;0;L;<font> 03D6;;;;N;;;;;
+1D7CE;MATHEMATICAL BOLD DIGIT ZERO;Nd;0;EN;<font> 0030;0;0;0;N;;;;;
+1D7CF;MATHEMATICAL BOLD DIGIT ONE;Nd;0;EN;<font> 0031;1;1;1;N;;;;;
+1D7D0;MATHEMATICAL BOLD DIGIT TWO;Nd;0;EN;<font> 0032;2;2;2;N;;;;;
+1D7D1;MATHEMATICAL BOLD DIGIT THREE;Nd;0;EN;<font> 0033;3;3;3;N;;;;;
+1D7D2;MATHEMATICAL BOLD DIGIT FOUR;Nd;0;EN;<font> 0034;4;4;4;N;;;;;
+1D7D3;MATHEMATICAL BOLD DIGIT FIVE;Nd;0;EN;<font> 0035;5;5;5;N;;;;;
+1D7D4;MATHEMATICAL BOLD DIGIT SIX;Nd;0;EN;<font> 0036;6;6;6;N;;;;;
+1D7D5;MATHEMATICAL BOLD DIGIT SEVEN;Nd;0;EN;<font> 0037;7;7;7;N;;;;;
+1D7D6;MATHEMATICAL BOLD DIGIT EIGHT;Nd;0;EN;<font> 0038;8;8;8;N;;;;;
+1D7D7;MATHEMATICAL BOLD DIGIT NINE;Nd;0;EN;<font> 0039;9;9;9;N;;;;;
+1D7D8;MATHEMATICAL DOUBLE-STRUCK DIGIT ZERO;Nd;0;EN;<font> 0030;0;0;0;N;;;;;
+1D7D9;MATHEMATICAL DOUBLE-STRUCK DIGIT ONE;Nd;0;EN;<font> 0031;1;1;1;N;;;;;
+1D7DA;MATHEMATICAL DOUBLE-STRUCK DIGIT TWO;Nd;0;EN;<font> 0032;2;2;2;N;;;;;
+1D7DB;MATHEMATICAL DOUBLE-STRUCK DIGIT THREE;Nd;0;EN;<font> 0033;3;3;3;N;;;;;
+1D7DC;MATHEMATICAL DOUBLE-STRUCK DIGIT FOUR;Nd;0;EN;<font> 0034;4;4;4;N;;;;;
+1D7DD;MATHEMATICAL DOUBLE-STRUCK DIGIT FIVE;Nd;0;EN;<font> 0035;5;5;5;N;;;;;
+1D7DE;MATHEMATICAL DOUBLE-STRUCK DIGIT SIX;Nd;0;EN;<font> 0036;6;6;6;N;;;;;
+1D7DF;MATHEMATICAL DOUBLE-STRUCK DIGIT SEVEN;Nd;0;EN;<font> 0037;7;7;7;N;;;;;
+1D7E0;MATHEMATICAL DOUBLE-STRUCK DIGIT EIGHT;Nd;0;EN;<font> 0038;8;8;8;N;;;;;
+1D7E1;MATHEMATICAL DOUBLE-STRUCK DIGIT NINE;Nd;0;EN;<font> 0039;9;9;9;N;;;;;
+1D7E2;MATHEMATICAL SANS-SERIF DIGIT ZERO;Nd;0;EN;<font> 0030;0;0;0;N;;;;;
+1D7E3;MATHEMATICAL SANS-SERIF DIGIT ONE;Nd;0;EN;<font> 0031;1;1;1;N;;;;;
+1D7E4;MATHEMATICAL SANS-SERIF DIGIT TWO;Nd;0;EN;<font> 0032;2;2;2;N;;;;;
+1D7E5;MATHEMATICAL SANS-SERIF DIGIT THREE;Nd;0;EN;<font> 0033;3;3;3;N;;;;;
+1D7E6;MATHEMATICAL SANS-SERIF DIGIT FOUR;Nd;0;EN;<font> 0034;4;4;4;N;;;;;
+1D7E7;MATHEMATICAL SANS-SERIF DIGIT FIVE;Nd;0;EN;<font> 0035;5;5;5;N;;;;;
+1D7E8;MATHEMATICAL SANS-SERIF DIGIT SIX;Nd;0;EN;<font> 0036;6;6;6;N;;;;;
+1D7E9;MATHEMATICAL SANS-SERIF DIGIT SEVEN;Nd;0;EN;<font> 0037;7;7;7;N;;;;;
+1D7EA;MATHEMATICAL SANS-SERIF DIGIT EIGHT;Nd;0;EN;<font> 0038;8;8;8;N;;;;;
+1D7EB;MATHEMATICAL SANS-SERIF DIGIT NINE;Nd;0;EN;<font> 0039;9;9;9;N;;;;;
+1D7EC;MATHEMATICAL SANS-SERIF BOLD DIGIT ZERO;Nd;0;EN;<font> 0030;0;0;0;N;;;;;
+1D7ED;MATHEMATICAL SANS-SERIF BOLD DIGIT ONE;Nd;0;EN;<font> 0031;1;1;1;N;;;;;
+1D7EE;MATHEMATICAL SANS-SERIF BOLD DIGIT TWO;Nd;0;EN;<font> 0032;2;2;2;N;;;;;
+1D7EF;MATHEMATICAL SANS-SERIF BOLD DIGIT THREE;Nd;0;EN;<font> 0033;3;3;3;N;;;;;
+1D7F0;MATHEMATICAL SANS-SERIF BOLD DIGIT FOUR;Nd;0;EN;<font> 0034;4;4;4;N;;;;;
+1D7F1;MATHEMATICAL SANS-SERIF BOLD DIGIT FIVE;Nd;0;EN;<font> 0035;5;5;5;N;;;;;
+1D7F2;MATHEMATICAL SANS-SERIF BOLD DIGIT SIX;Nd;0;EN;<font> 0036;6;6;6;N;;;;;
+1D7F3;MATHEMATICAL SANS-SERIF BOLD DIGIT SEVEN;Nd;0;EN;<font> 0037;7;7;7;N;;;;;
+1D7F4;MATHEMATICAL SANS-SERIF BOLD DIGIT EIGHT;Nd;0;EN;<font> 0038;8;8;8;N;;;;;
+1D7F5;MATHEMATICAL SANS-SERIF BOLD DIGIT NINE;Nd;0;EN;<font> 0039;9;9;9;N;;;;;
+1D7F6;MATHEMATICAL MONOSPACE DIGIT ZERO;Nd;0;EN;<font> 0030;0;0;0;N;;;;;
+1D7F7;MATHEMATICAL MONOSPACE DIGIT ONE;Nd;0;EN;<font> 0031;1;1;1;N;;;;;
+1D7F8;MATHEMATICAL MONOSPACE DIGIT TWO;Nd;0;EN;<font> 0032;2;2;2;N;;;;;
+1D7F9;MATHEMATICAL MONOSPACE DIGIT THREE;Nd;0;EN;<font> 0033;3;3;3;N;;;;;
+1D7FA;MATHEMATICAL MONOSPACE DIGIT FOUR;Nd;0;EN;<font> 0034;4;4;4;N;;;;;
+1D7FB;MATHEMATICAL MONOSPACE DIGIT FIVE;Nd;0;EN;<font> 0035;5;5;5;N;;;;;
+1D7FC;MATHEMATICAL MONOSPACE DIGIT SIX;Nd;0;EN;<font> 0036;6;6;6;N;;;;;
+1D7FD;MATHEMATICAL MONOSPACE DIGIT SEVEN;Nd;0;EN;<font> 0037;7;7;7;N;;;;;
+1D7FE;MATHEMATICAL MONOSPACE DIGIT EIGHT;Nd;0;EN;<font> 0038;8;8;8;N;;;;;
+1D7FF;MATHEMATICAL MONOSPACE DIGIT NINE;Nd;0;EN;<font> 0039;9;9;9;N;;;;;
+20000;<CJK Ideograph Extension B, First>;Lo;0;L;;;;;N;;;;;
+2A6D6;<CJK Ideograph Extension B, Last>;Lo;0;L;;;;;N;;;;;
+2F800;CJK COMPATIBILITY IDEOGRAPH-2F800;Lo;0;L;4E3D;;;;N;;;;;
+2F801;CJK COMPATIBILITY IDEOGRAPH-2F801;Lo;0;L;4E38;;;;N;;;;;
+2F802;CJK COMPATIBILITY IDEOGRAPH-2F802;Lo;0;L;4E41;;;;N;;;;;
+2F803;CJK COMPATIBILITY IDEOGRAPH-2F803;Lo;0;L;20122;;;;N;;;;;
+2F804;CJK COMPATIBILITY IDEOGRAPH-2F804;Lo;0;L;4F60;;;;N;;;;;
+2F805;CJK COMPATIBILITY IDEOGRAPH-2F805;Lo;0;L;4FAE;;;;N;;;;;
+2F806;CJK COMPATIBILITY IDEOGRAPH-2F806;Lo;0;L;4FBB;;;;N;;;;;
+2F807;CJK COMPATIBILITY IDEOGRAPH-2F807;Lo;0;L;5002;;;;N;;;;;
+2F808;CJK COMPATIBILITY IDEOGRAPH-2F808;Lo;0;L;507A;;;;N;;;;;
+2F809;CJK COMPATIBILITY IDEOGRAPH-2F809;Lo;0;L;5099;;;;N;;;;;
+2F80A;CJK COMPATIBILITY IDEOGRAPH-2F80A;Lo;0;L;50E7;;;;N;;;;;
+2F80B;CJK COMPATIBILITY IDEOGRAPH-2F80B;Lo;0;L;50CF;;;;N;;;;;
+2F80C;CJK COMPATIBILITY IDEOGRAPH-2F80C;Lo;0;L;349E;;;;N;;;;;
+2F80D;CJK COMPATIBILITY IDEOGRAPH-2F80D;Lo;0;L;2063A;;;;N;;;;;
+2F80E;CJK COMPATIBILITY IDEOGRAPH-2F80E;Lo;0;L;514D;;;;N;;;;;
+2F80F;CJK COMPATIBILITY IDEOGRAPH-2F80F;Lo;0;L;5154;;;;N;;;;;
+2F810;CJK COMPATIBILITY IDEOGRAPH-2F810;Lo;0;L;5164;;;;N;;;;;
+2F811;CJK COMPATIBILITY IDEOGRAPH-2F811;Lo;0;L;5177;;;;N;;;;;
+2F812;CJK COMPATIBILITY IDEOGRAPH-2F812;Lo;0;L;2051C;;;;N;;;;;
+2F813;CJK COMPATIBILITY IDEOGRAPH-2F813;Lo;0;L;34B9;;;;N;;;;;
+2F814;CJK COMPATIBILITY IDEOGRAPH-2F814;Lo;0;L;5167;;;;N;;;;;
+2F815;CJK COMPATIBILITY IDEOGRAPH-2F815;Lo;0;L;518D;;;;N;;;;;
+2F816;CJK COMPATIBILITY IDEOGRAPH-2F816;Lo;0;L;2054B;;;;N;;;;;
+2F817;CJK COMPATIBILITY IDEOGRAPH-2F817;Lo;0;L;5197;;;;N;;;;;
+2F818;CJK COMPATIBILITY IDEOGRAPH-2F818;Lo;0;L;51A4;;;;N;;;;;
+2F819;CJK COMPATIBILITY IDEOGRAPH-2F819;Lo;0;L;4ECC;;;;N;;;;;
+2F81A;CJK COMPATIBILITY IDEOGRAPH-2F81A;Lo;0;L;51AC;;;;N;;;;;
+2F81B;CJK COMPATIBILITY IDEOGRAPH-2F81B;Lo;0;L;51B5;;;;N;;;;;
+2F81C;CJK COMPATIBILITY IDEOGRAPH-2F81C;Lo;0;L;291DF;;;;N;;;;;
+2F81D;CJK COMPATIBILITY IDEOGRAPH-2F81D;Lo;0;L;51F5;;;;N;;;;;
+2F81E;CJK COMPATIBILITY IDEOGRAPH-2F81E;Lo;0;L;5203;;;;N;;;;;
+2F81F;CJK COMPATIBILITY IDEOGRAPH-2F81F;Lo;0;L;34DF;;;;N;;;;;
+2F820;CJK COMPATIBILITY IDEOGRAPH-2F820;Lo;0;L;523B;;;;N;;;;;
+2F821;CJK COMPATIBILITY IDEOGRAPH-2F821;Lo;0;L;5246;;;;N;;;;;
+2F822;CJK COMPATIBILITY IDEOGRAPH-2F822;Lo;0;L;5272;;;;N;;;;;
+2F823;CJK COMPATIBILITY IDEOGRAPH-2F823;Lo;0;L;5277;;;;N;;;;;
+2F824;CJK COMPATIBILITY IDEOGRAPH-2F824;Lo;0;L;3515;;;;N;;;;;
+2F825;CJK COMPATIBILITY IDEOGRAPH-2F825;Lo;0;L;52C7;;;;N;;;;;
+2F826;CJK COMPATIBILITY IDEOGRAPH-2F826;Lo;0;L;52C9;;;;N;;;;;
+2F827;CJK COMPATIBILITY IDEOGRAPH-2F827;Lo;0;L;52E4;;;;N;;;;;
+2F828;CJK COMPATIBILITY IDEOGRAPH-2F828;Lo;0;L;52FA;;;;N;;;;;
+2F829;CJK COMPATIBILITY IDEOGRAPH-2F829;Lo;0;L;5305;;;;N;;;;;
+2F82A;CJK COMPATIBILITY IDEOGRAPH-2F82A;Lo;0;L;5306;;;;N;;;;;
+2F82B;CJK COMPATIBILITY IDEOGRAPH-2F82B;Lo;0;L;5317;;;;N;;;;;
+2F82C;CJK COMPATIBILITY IDEOGRAPH-2F82C;Lo;0;L;5349;;;;N;;;;;
+2F82D;CJK COMPATIBILITY IDEOGRAPH-2F82D;Lo;0;L;5351;;;;N;;;;;
+2F82E;CJK COMPATIBILITY IDEOGRAPH-2F82E;Lo;0;L;535A;;;;N;;;;;
+2F82F;CJK COMPATIBILITY IDEOGRAPH-2F82F;Lo;0;L;5373;;;;N;;;;;
+2F830;CJK COMPATIBILITY IDEOGRAPH-2F830;Lo;0;L;537D;;;;N;;;;;
+2F831;CJK COMPATIBILITY IDEOGRAPH-2F831;Lo;0;L;537F;;;;N;;;;;
+2F832;CJK COMPATIBILITY IDEOGRAPH-2F832;Lo;0;L;537F;;;;N;;;;;
+2F833;CJK COMPATIBILITY IDEOGRAPH-2F833;Lo;0;L;537F;;;;N;;;;;
+2F834;CJK COMPATIBILITY IDEOGRAPH-2F834;Lo;0;L;20A2C;;;;N;;;;;
+2F835;CJK COMPATIBILITY IDEOGRAPH-2F835;Lo;0;L;7070;;;;N;;;;;
+2F836;CJK COMPATIBILITY IDEOGRAPH-2F836;Lo;0;L;53CA;;;;N;;;;;
+2F837;CJK COMPATIBILITY IDEOGRAPH-2F837;Lo;0;L;53DF;;;;N;;;;;
+2F838;CJK COMPATIBILITY IDEOGRAPH-2F838;Lo;0;L;20B63;;;;N;;;;;
+2F839;CJK COMPATIBILITY IDEOGRAPH-2F839;Lo;0;L;53EB;;;;N;;;;;
+2F83A;CJK COMPATIBILITY IDEOGRAPH-2F83A;Lo;0;L;53F1;;;;N;;;;;
+2F83B;CJK COMPATIBILITY IDEOGRAPH-2F83B;Lo;0;L;5406;;;;N;;;;;
+2F83C;CJK COMPATIBILITY IDEOGRAPH-2F83C;Lo;0;L;549E;;;;N;;;;;
+2F83D;CJK COMPATIBILITY IDEOGRAPH-2F83D;Lo;0;L;5438;;;;N;;;;;
+2F83E;CJK COMPATIBILITY IDEOGRAPH-2F83E;Lo;0;L;5448;;;;N;;;;;
+2F83F;CJK COMPATIBILITY IDEOGRAPH-2F83F;Lo;0;L;5468;;;;N;;;;;
+2F840;CJK COMPATIBILITY IDEOGRAPH-2F840;Lo;0;L;54A2;;;;N;;;;;
+2F841;CJK COMPATIBILITY IDEOGRAPH-2F841;Lo;0;L;54F6;;;;N;;;;;
+2F842;CJK COMPATIBILITY IDEOGRAPH-2F842;Lo;0;L;5510;;;;N;;;;;
+2F843;CJK COMPATIBILITY IDEOGRAPH-2F843;Lo;0;L;5553;;;;N;;;;;
+2F844;CJK COMPATIBILITY IDEOGRAPH-2F844;Lo;0;L;5563;;;;N;;;;;
+2F845;CJK COMPATIBILITY IDEOGRAPH-2F845;Lo;0;L;5584;;;;N;;;;;
+2F846;CJK COMPATIBILITY IDEOGRAPH-2F846;Lo;0;L;5584;;;;N;;;;;
+2F847;CJK COMPATIBILITY IDEOGRAPH-2F847;Lo;0;L;5599;;;;N;;;;;
+2F848;CJK COMPATIBILITY IDEOGRAPH-2F848;Lo;0;L;55AB;;;;N;;;;;
+2F849;CJK COMPATIBILITY IDEOGRAPH-2F849;Lo;0;L;55B3;;;;N;;;;;
+2F84A;CJK COMPATIBILITY IDEOGRAPH-2F84A;Lo;0;L;55C2;;;;N;;;;;
+2F84B;CJK COMPATIBILITY IDEOGRAPH-2F84B;Lo;0;L;5716;;;;N;;;;;
+2F84C;CJK COMPATIBILITY IDEOGRAPH-2F84C;Lo;0;L;5606;;;;N;;;;;
+2F84D;CJK COMPATIBILITY IDEOGRAPH-2F84D;Lo;0;L;5717;;;;N;;;;;
+2F84E;CJK COMPATIBILITY IDEOGRAPH-2F84E;Lo;0;L;5651;;;;N;;;;;
+2F84F;CJK COMPATIBILITY IDEOGRAPH-2F84F;Lo;0;L;5674;;;;N;;;;;
+2F850;CJK COMPATIBILITY IDEOGRAPH-2F850;Lo;0;L;5207;;;;N;;;;;
+2F851;CJK COMPATIBILITY IDEOGRAPH-2F851;Lo;0;L;58EE;;;;N;;;;;
+2F852;CJK COMPATIBILITY IDEOGRAPH-2F852;Lo;0;L;57CE;;;;N;;;;;
+2F853;CJK COMPATIBILITY IDEOGRAPH-2F853;Lo;0;L;57F4;;;;N;;;;;
+2F854;CJK COMPATIBILITY IDEOGRAPH-2F854;Lo;0;L;580D;;;;N;;;;;
+2F855;CJK COMPATIBILITY IDEOGRAPH-2F855;Lo;0;L;578B;;;;N;;;;;
+2F856;CJK COMPATIBILITY IDEOGRAPH-2F856;Lo;0;L;5832;;;;N;;;;;
+2F857;CJK COMPATIBILITY IDEOGRAPH-2F857;Lo;0;L;5831;;;;N;;;;;
+2F858;CJK COMPATIBILITY IDEOGRAPH-2F858;Lo;0;L;58AC;;;;N;;;;;
+2F859;CJK COMPATIBILITY IDEOGRAPH-2F859;Lo;0;L;214E4;;;;N;;;;;
+2F85A;CJK COMPATIBILITY IDEOGRAPH-2F85A;Lo;0;L;58F2;;;;N;;;;;
+2F85B;CJK COMPATIBILITY IDEOGRAPH-2F85B;Lo;0;L;58F7;;;;N;;;;;
+2F85C;CJK COMPATIBILITY IDEOGRAPH-2F85C;Lo;0;L;5906;;;;N;;;;;
+2F85D;CJK COMPATIBILITY IDEOGRAPH-2F85D;Lo;0;L;591A;;;;N;;;;;
+2F85E;CJK COMPATIBILITY IDEOGRAPH-2F85E;Lo;0;L;5922;;;;N;;;;;
+2F85F;CJK COMPATIBILITY IDEOGRAPH-2F85F;Lo;0;L;5962;;;;N;;;;;
+2F860;CJK COMPATIBILITY IDEOGRAPH-2F860;Lo;0;L;216A8;;;;N;;;;;
+2F861;CJK COMPATIBILITY IDEOGRAPH-2F861;Lo;0;L;216EA;;;;N;;;;;
+2F862;CJK COMPATIBILITY IDEOGRAPH-2F862;Lo;0;L;59EC;;;;N;;;;;
+2F863;CJK COMPATIBILITY IDEOGRAPH-2F863;Lo;0;L;5A1B;;;;N;;;;;
+2F864;CJK COMPATIBILITY IDEOGRAPH-2F864;Lo;0;L;5A27;;;;N;;;;;
+2F865;CJK COMPATIBILITY IDEOGRAPH-2F865;Lo;0;L;59D8;;;;N;;;;;
+2F866;CJK COMPATIBILITY IDEOGRAPH-2F866;Lo;0;L;5A66;;;;N;;;;;
+2F867;CJK COMPATIBILITY IDEOGRAPH-2F867;Lo;0;L;36EE;;;;N;;;;;
+2F868;CJK COMPATIBILITY IDEOGRAPH-2F868;Lo;0;L;2136A;;;;N;;;;;
+2F869;CJK COMPATIBILITY IDEOGRAPH-2F869;Lo;0;L;5B08;;;;N;;;;;
+2F86A;CJK COMPATIBILITY IDEOGRAPH-2F86A;Lo;0;L;5B3E;;;;N;;;;;
+2F86B;CJK COMPATIBILITY IDEOGRAPH-2F86B;Lo;0;L;5B3E;;;;N;;;;;
+2F86C;CJK COMPATIBILITY IDEOGRAPH-2F86C;Lo;0;L;219C8;;;;N;;;;;
+2F86D;CJK COMPATIBILITY IDEOGRAPH-2F86D;Lo;0;L;5BC3;;;;N;;;;;
+2F86E;CJK COMPATIBILITY IDEOGRAPH-2F86E;Lo;0;L;5BD8;;;;N;;;;;
+2F86F;CJK COMPATIBILITY IDEOGRAPH-2F86F;Lo;0;L;5BE7;;;;N;;;;;
+2F870;CJK COMPATIBILITY IDEOGRAPH-2F870;Lo;0;L;5BF3;;;;N;;;;;
+2F871;CJK COMPATIBILITY IDEOGRAPH-2F871;Lo;0;L;21B18;;;;N;;;;;
+2F872;CJK COMPATIBILITY IDEOGRAPH-2F872;Lo;0;L;5BFF;;;;N;;;;;
+2F873;CJK COMPATIBILITY IDEOGRAPH-2F873;Lo;0;L;5C06;;;;N;;;;;
+2F874;CJK COMPATIBILITY IDEOGRAPH-2F874;Lo;0;L;5F33;;;;N;;;;;
+2F875;CJK COMPATIBILITY IDEOGRAPH-2F875;Lo;0;L;5C22;;;;N;;;;;
+2F876;CJK COMPATIBILITY IDEOGRAPH-2F876;Lo;0;L;3781;;;;N;;;;;
+2F877;CJK COMPATIBILITY IDEOGRAPH-2F877;Lo;0;L;5C60;;;;N;;;;;
+2F878;CJK COMPATIBILITY IDEOGRAPH-2F878;Lo;0;L;5C6E;;;;N;;;;;
+2F879;CJK COMPATIBILITY IDEOGRAPH-2F879;Lo;0;L;5CC0;;;;N;;;;;
+2F87A;CJK COMPATIBILITY IDEOGRAPH-2F87A;Lo;0;L;5C8D;;;;N;;;;;
+2F87B;CJK COMPATIBILITY IDEOGRAPH-2F87B;Lo;0;L;21DE4;;;;N;;;;;
+2F87C;CJK COMPATIBILITY IDEOGRAPH-2F87C;Lo;0;L;5D43;;;;N;;;;;
+2F87D;CJK COMPATIBILITY IDEOGRAPH-2F87D;Lo;0;L;21DE6;;;;N;;;;;
+2F87E;CJK COMPATIBILITY IDEOGRAPH-2F87E;Lo;0;L;5D6E;;;;N;;;;;
+2F87F;CJK COMPATIBILITY IDEOGRAPH-2F87F;Lo;0;L;5D6B;;;;N;;;;;
+2F880;CJK COMPATIBILITY IDEOGRAPH-2F880;Lo;0;L;5D7C;;;;N;;;;;
+2F881;CJK COMPATIBILITY IDEOGRAPH-2F881;Lo;0;L;5DE1;;;;N;;;;;
+2F882;CJK COMPATIBILITY IDEOGRAPH-2F882;Lo;0;L;5DE2;;;;N;;;;;
+2F883;CJK COMPATIBILITY IDEOGRAPH-2F883;Lo;0;L;382F;;;;N;;;;;
+2F884;CJK COMPATIBILITY IDEOGRAPH-2F884;Lo;0;L;5DFD;;;;N;;;;;
+2F885;CJK COMPATIBILITY IDEOGRAPH-2F885;Lo;0;L;5E28;;;;N;;;;;
+2F886;CJK COMPATIBILITY IDEOGRAPH-2F886;Lo;0;L;5E3D;;;;N;;;;;
+2F887;CJK COMPATIBILITY IDEOGRAPH-2F887;Lo;0;L;5E69;;;;N;;;;;
+2F888;CJK COMPATIBILITY IDEOGRAPH-2F888;Lo;0;L;3862;;;;N;;;;;
+2F889;CJK COMPATIBILITY IDEOGRAPH-2F889;Lo;0;L;22183;;;;N;;;;;
+2F88A;CJK COMPATIBILITY IDEOGRAPH-2F88A;Lo;0;L;387C;;;;N;;;;;
+2F88B;CJK COMPATIBILITY IDEOGRAPH-2F88B;Lo;0;L;5EB0;;;;N;;;;;
+2F88C;CJK COMPATIBILITY IDEOGRAPH-2F88C;Lo;0;L;5EB3;;;;N;;;;;
+2F88D;CJK COMPATIBILITY IDEOGRAPH-2F88D;Lo;0;L;5EB6;;;;N;;;;;
+2F88E;CJK COMPATIBILITY IDEOGRAPH-2F88E;Lo;0;L;5ECA;;;;N;;;;;
+2F88F;CJK COMPATIBILITY IDEOGRAPH-2F88F;Lo;0;L;2A392;;;;N;;;;;
+2F890;CJK COMPATIBILITY IDEOGRAPH-2F890;Lo;0;L;5EFE;;;;N;;;;;
+2F891;CJK COMPATIBILITY IDEOGRAPH-2F891;Lo;0;L;22331;;;;N;;;;;
+2F892;CJK COMPATIBILITY IDEOGRAPH-2F892;Lo;0;L;22331;;;;N;;;;;
+2F893;CJK COMPATIBILITY IDEOGRAPH-2F893;Lo;0;L;8201;;;;N;;;;;
+2F894;CJK COMPATIBILITY IDEOGRAPH-2F894;Lo;0;L;5F22;;;;N;;;;;
+2F895;CJK COMPATIBILITY IDEOGRAPH-2F895;Lo;0;L;5F22;;;;N;;;;;
+2F896;CJK COMPATIBILITY IDEOGRAPH-2F896;Lo;0;L;38C7;;;;N;;;;;
+2F897;CJK COMPATIBILITY IDEOGRAPH-2F897;Lo;0;L;232B8;;;;N;;;;;
+2F898;CJK COMPATIBILITY IDEOGRAPH-2F898;Lo;0;L;261DA;;;;N;;;;;
+2F899;CJK COMPATIBILITY IDEOGRAPH-2F899;Lo;0;L;5F62;;;;N;;;;;
+2F89A;CJK COMPATIBILITY IDEOGRAPH-2F89A;Lo;0;L;5F6B;;;;N;;;;;
+2F89B;CJK COMPATIBILITY IDEOGRAPH-2F89B;Lo;0;L;38E3;;;;N;;;;;
+2F89C;CJK COMPATIBILITY IDEOGRAPH-2F89C;Lo;0;L;5F9A;;;;N;;;;;
+2F89D;CJK COMPATIBILITY IDEOGRAPH-2F89D;Lo;0;L;5FCD;;;;N;;;;;
+2F89E;CJK COMPATIBILITY IDEOGRAPH-2F89E;Lo;0;L;5FD7;;;;N;;;;;
+2F89F;CJK COMPATIBILITY IDEOGRAPH-2F89F;Lo;0;L;5FF9;;;;N;;;;;
+2F8A0;CJK COMPATIBILITY IDEOGRAPH-2F8A0;Lo;0;L;6081;;;;N;;;;;
+2F8A1;CJK COMPATIBILITY IDEOGRAPH-2F8A1;Lo;0;L;393A;;;;N;;;;;
+2F8A2;CJK COMPATIBILITY IDEOGRAPH-2F8A2;Lo;0;L;391C;;;;N;;;;;
+2F8A3;CJK COMPATIBILITY IDEOGRAPH-2F8A3;Lo;0;L;6094;;;;N;;;;;
+2F8A4;CJK COMPATIBILITY IDEOGRAPH-2F8A4;Lo;0;L;226D4;;;;N;;;;;
+2F8A5;CJK COMPATIBILITY IDEOGRAPH-2F8A5;Lo;0;L;60C7;;;;N;;;;;
+2F8A6;CJK COMPATIBILITY IDEOGRAPH-2F8A6;Lo;0;L;6148;;;;N;;;;;
+2F8A7;CJK COMPATIBILITY IDEOGRAPH-2F8A7;Lo;0;L;614C;;;;N;;;;;
+2F8A8;CJK COMPATIBILITY IDEOGRAPH-2F8A8;Lo;0;L;614E;;;;N;;;;;
+2F8A9;CJK COMPATIBILITY IDEOGRAPH-2F8A9;Lo;0;L;614C;;;;N;;;;;
+2F8AA;CJK COMPATIBILITY IDEOGRAPH-2F8AA;Lo;0;L;617A;;;;N;;;;;
+2F8AB;CJK COMPATIBILITY IDEOGRAPH-2F8AB;Lo;0;L;618E;;;;N;;;;;
+2F8AC;CJK COMPATIBILITY IDEOGRAPH-2F8AC;Lo;0;L;61B2;;;;N;;;;;
+2F8AD;CJK COMPATIBILITY IDEOGRAPH-2F8AD;Lo;0;L;61A4;;;;N;;;;;
+2F8AE;CJK COMPATIBILITY IDEOGRAPH-2F8AE;Lo;0;L;61AF;;;;N;;;;;
+2F8AF;CJK COMPATIBILITY IDEOGRAPH-2F8AF;Lo;0;L;61DE;;;;N;;;;;
+2F8B0;CJK COMPATIBILITY IDEOGRAPH-2F8B0;Lo;0;L;61F2;;;;N;;;;;
+2F8B1;CJK COMPATIBILITY IDEOGRAPH-2F8B1;Lo;0;L;61F6;;;;N;;;;;
+2F8B2;CJK COMPATIBILITY IDEOGRAPH-2F8B2;Lo;0;L;6210;;;;N;;;;;
+2F8B3;CJK COMPATIBILITY IDEOGRAPH-2F8B3;Lo;0;L;621B;;;;N;;;;;
+2F8B4;CJK COMPATIBILITY IDEOGRAPH-2F8B4;Lo;0;L;625D;;;;N;;;;;
+2F8B5;CJK COMPATIBILITY IDEOGRAPH-2F8B5;Lo;0;L;62B1;;;;N;;;;;
+2F8B6;CJK COMPATIBILITY IDEOGRAPH-2F8B6;Lo;0;L;62D4;;;;N;;;;;
+2F8B7;CJK COMPATIBILITY IDEOGRAPH-2F8B7;Lo;0;L;6350;;;;N;;;;;
+2F8B8;CJK COMPATIBILITY IDEOGRAPH-2F8B8;Lo;0;L;22B0C;;;;N;;;;;
+2F8B9;CJK COMPATIBILITY IDEOGRAPH-2F8B9;Lo;0;L;633D;;;;N;;;;;
+2F8BA;CJK COMPATIBILITY IDEOGRAPH-2F8BA;Lo;0;L;62FC;;;;N;;;;;
+2F8BB;CJK COMPATIBILITY IDEOGRAPH-2F8BB;Lo;0;L;6368;;;;N;;;;;
+2F8BC;CJK COMPATIBILITY IDEOGRAPH-2F8BC;Lo;0;L;6383;;;;N;;;;;
+2F8BD;CJK COMPATIBILITY IDEOGRAPH-2F8BD;Lo;0;L;63E4;;;;N;;;;;
+2F8BE;CJK COMPATIBILITY IDEOGRAPH-2F8BE;Lo;0;L;22BF1;;;;N;;;;;
+2F8BF;CJK COMPATIBILITY IDEOGRAPH-2F8BF;Lo;0;L;6422;;;;N;;;;;
+2F8C0;CJK COMPATIBILITY IDEOGRAPH-2F8C0;Lo;0;L;63C5;;;;N;;;;;
+2F8C1;CJK COMPATIBILITY IDEOGRAPH-2F8C1;Lo;0;L;63A9;;;;N;;;;;
+2F8C2;CJK COMPATIBILITY IDEOGRAPH-2F8C2;Lo;0;L;3A2E;;;;N;;;;;
+2F8C3;CJK COMPATIBILITY IDEOGRAPH-2F8C3;Lo;0;L;6469;;;;N;;;;;
+2F8C4;CJK COMPATIBILITY IDEOGRAPH-2F8C4;Lo;0;L;647E;;;;N;;;;;
+2F8C5;CJK COMPATIBILITY IDEOGRAPH-2F8C5;Lo;0;L;649D;;;;N;;;;;
+2F8C6;CJK COMPATIBILITY IDEOGRAPH-2F8C6;Lo;0;L;6477;;;;N;;;;;
+2F8C7;CJK COMPATIBILITY IDEOGRAPH-2F8C7;Lo;0;L;3A6C;;;;N;;;;;
+2F8C8;CJK COMPATIBILITY IDEOGRAPH-2F8C8;Lo;0;L;654F;;;;N;;;;;
+2F8C9;CJK COMPATIBILITY IDEOGRAPH-2F8C9;Lo;0;L;656C;;;;N;;;;;
+2F8CA;CJK COMPATIBILITY IDEOGRAPH-2F8CA;Lo;0;L;2300A;;;;N;;;;;
+2F8CB;CJK COMPATIBILITY IDEOGRAPH-2F8CB;Lo;0;L;65E3;;;;N;;;;;
+2F8CC;CJK COMPATIBILITY IDEOGRAPH-2F8CC;Lo;0;L;66F8;;;;N;;;;;
+2F8CD;CJK COMPATIBILITY IDEOGRAPH-2F8CD;Lo;0;L;6649;;;;N;;;;;
+2F8CE;CJK COMPATIBILITY IDEOGRAPH-2F8CE;Lo;0;L;3B19;;;;N;;;;;
+2F8CF;CJK COMPATIBILITY IDEOGRAPH-2F8CF;Lo;0;L;6691;;;;N;;;;;
+2F8D0;CJK COMPATIBILITY IDEOGRAPH-2F8D0;Lo;0;L;3B08;;;;N;;;;;
+2F8D1;CJK COMPATIBILITY IDEOGRAPH-2F8D1;Lo;0;L;3AE4;;;;N;;;;;
+2F8D2;CJK COMPATIBILITY IDEOGRAPH-2F8D2;Lo;0;L;5192;;;;N;;;;;
+2F8D3;CJK COMPATIBILITY IDEOGRAPH-2F8D3;Lo;0;L;5195;;;;N;;;;;
+2F8D4;CJK COMPATIBILITY IDEOGRAPH-2F8D4;Lo;0;L;6700;;;;N;;;;;
+2F8D5;CJK COMPATIBILITY IDEOGRAPH-2F8D5;Lo;0;L;669C;;;;N;;;;;
+2F8D6;CJK COMPATIBILITY IDEOGRAPH-2F8D6;Lo;0;L;80AD;;;;N;;;;;
+2F8D7;CJK COMPATIBILITY IDEOGRAPH-2F8D7;Lo;0;L;43D9;;;;N;;;;;
+2F8D8;CJK COMPATIBILITY IDEOGRAPH-2F8D8;Lo;0;L;6717;;;;N;;;;;
+2F8D9;CJK COMPATIBILITY IDEOGRAPH-2F8D9;Lo;0;L;671B;;;;N;;;;;
+2F8DA;CJK COMPATIBILITY IDEOGRAPH-2F8DA;Lo;0;L;6721;;;;N;;;;;
+2F8DB;CJK COMPATIBILITY IDEOGRAPH-2F8DB;Lo;0;L;675E;;;;N;;;;;
+2F8DC;CJK COMPATIBILITY IDEOGRAPH-2F8DC;Lo;0;L;6753;;;;N;;;;;
+2F8DD;CJK COMPATIBILITY IDEOGRAPH-2F8DD;Lo;0;L;233C3;;;;N;;;;;
+2F8DE;CJK COMPATIBILITY IDEOGRAPH-2F8DE;Lo;0;L;3B49;;;;N;;;;;
+2F8DF;CJK COMPATIBILITY IDEOGRAPH-2F8DF;Lo;0;L;67FA;;;;N;;;;;
+2F8E0;CJK COMPATIBILITY IDEOGRAPH-2F8E0;Lo;0;L;6785;;;;N;;;;;
+2F8E1;CJK COMPATIBILITY IDEOGRAPH-2F8E1;Lo;0;L;6852;;;;N;;;;;
+2F8E2;CJK COMPATIBILITY IDEOGRAPH-2F8E2;Lo;0;L;6885;;;;N;;;;;
+2F8E3;CJK COMPATIBILITY IDEOGRAPH-2F8E3;Lo;0;L;2346D;;;;N;;;;;
+2F8E4;CJK COMPATIBILITY IDEOGRAPH-2F8E4;Lo;0;L;688E;;;;N;;;;;
+2F8E5;CJK COMPATIBILITY IDEOGRAPH-2F8E5;Lo;0;L;681F;;;;N;;;;;
+2F8E6;CJK COMPATIBILITY IDEOGRAPH-2F8E6;Lo;0;L;6914;;;;N;;;;;
+2F8E7;CJK COMPATIBILITY IDEOGRAPH-2F8E7;Lo;0;L;3B9D;;;;N;;;;;
+2F8E8;CJK COMPATIBILITY IDEOGRAPH-2F8E8;Lo;0;L;6942;;;;N;;;;;
+2F8E9;CJK COMPATIBILITY IDEOGRAPH-2F8E9;Lo;0;L;69A3;;;;N;;;;;
+2F8EA;CJK COMPATIBILITY IDEOGRAPH-2F8EA;Lo;0;L;69EA;;;;N;;;;;
+2F8EB;CJK COMPATIBILITY IDEOGRAPH-2F8EB;Lo;0;L;6AA8;;;;N;;;;;
+2F8EC;CJK COMPATIBILITY IDEOGRAPH-2F8EC;Lo;0;L;236A3;;;;N;;;;;
+2F8ED;CJK COMPATIBILITY IDEOGRAPH-2F8ED;Lo;0;L;6ADB;;;;N;;;;;
+2F8EE;CJK COMPATIBILITY IDEOGRAPH-2F8EE;Lo;0;L;3C18;;;;N;;;;;
+2F8EF;CJK COMPATIBILITY IDEOGRAPH-2F8EF;Lo;0;L;6B21;;;;N;;;;;
+2F8F0;CJK COMPATIBILITY IDEOGRAPH-2F8F0;Lo;0;L;238A7;;;;N;;;;;
+2F8F1;CJK COMPATIBILITY IDEOGRAPH-2F8F1;Lo;0;L;6B54;;;;N;;;;;
+2F8F2;CJK COMPATIBILITY IDEOGRAPH-2F8F2;Lo;0;L;3C4E;;;;N;;;;;
+2F8F3;CJK COMPATIBILITY IDEOGRAPH-2F8F3;Lo;0;L;6B72;;;;N;;;;;
+2F8F4;CJK COMPATIBILITY IDEOGRAPH-2F8F4;Lo;0;L;6B9F;;;;N;;;;;
+2F8F5;CJK COMPATIBILITY IDEOGRAPH-2F8F5;Lo;0;L;6BBA;;;;N;;;;;
+2F8F6;CJK COMPATIBILITY IDEOGRAPH-2F8F6;Lo;0;L;6BBB;;;;N;;;;;
+2F8F7;CJK COMPATIBILITY IDEOGRAPH-2F8F7;Lo;0;L;23A8D;;;;N;;;;;
+2F8F8;CJK COMPATIBILITY IDEOGRAPH-2F8F8;Lo;0;L;21D0B;;;;N;;;;;
+2F8F9;CJK COMPATIBILITY IDEOGRAPH-2F8F9;Lo;0;L;23AFA;;;;N;;;;;
+2F8FA;CJK COMPATIBILITY IDEOGRAPH-2F8FA;Lo;0;L;6C4E;;;;N;;;;;
+2F8FB;CJK COMPATIBILITY IDEOGRAPH-2F8FB;Lo;0;L;23CBC;;;;N;;;;;
+2F8FC;CJK COMPATIBILITY IDEOGRAPH-2F8FC;Lo;0;L;6CBF;;;;N;;;;;
+2F8FD;CJK COMPATIBILITY IDEOGRAPH-2F8FD;Lo;0;L;6CCD;;;;N;;;;;
+2F8FE;CJK COMPATIBILITY IDEOGRAPH-2F8FE;Lo;0;L;6C67;;;;N;;;;;
+2F8FF;CJK COMPATIBILITY IDEOGRAPH-2F8FF;Lo;0;L;6D16;;;;N;;;;;
+2F900;CJK COMPATIBILITY IDEOGRAPH-2F900;Lo;0;L;6D3E;;;;N;;;;;
+2F901;CJK COMPATIBILITY IDEOGRAPH-2F901;Lo;0;L;6D77;;;;N;;;;;
+2F902;CJK COMPATIBILITY IDEOGRAPH-2F902;Lo;0;L;6D41;;;;N;;;;;
+2F903;CJK COMPATIBILITY IDEOGRAPH-2F903;Lo;0;L;6D69;;;;N;;;;;
+2F904;CJK COMPATIBILITY IDEOGRAPH-2F904;Lo;0;L;6D78;;;;N;;;;;
+2F905;CJK COMPATIBILITY IDEOGRAPH-2F905;Lo;0;L;6D85;;;;N;;;;;
+2F906;CJK COMPATIBILITY IDEOGRAPH-2F906;Lo;0;L;23D1E;;;;N;;;;;
+2F907;CJK COMPATIBILITY IDEOGRAPH-2F907;Lo;0;L;6D34;;;;N;;;;;
+2F908;CJK COMPATIBILITY IDEOGRAPH-2F908;Lo;0;L;6E2F;;;;N;;;;;
+2F909;CJK COMPATIBILITY IDEOGRAPH-2F909;Lo;0;L;6E6E;;;;N;;;;;
+2F90A;CJK COMPATIBILITY IDEOGRAPH-2F90A;Lo;0;L;3D33;;;;N;;;;;
+2F90B;CJK COMPATIBILITY IDEOGRAPH-2F90B;Lo;0;L;6ECB;;;;N;;;;;
+2F90C;CJK COMPATIBILITY IDEOGRAPH-2F90C;Lo;0;L;6EC7;;;;N;;;;;
+2F90D;CJK COMPATIBILITY IDEOGRAPH-2F90D;Lo;0;L;23ED1;;;;N;;;;;
+2F90E;CJK COMPATIBILITY IDEOGRAPH-2F90E;Lo;0;L;6DF9;;;;N;;;;;
+2F90F;CJK COMPATIBILITY IDEOGRAPH-2F90F;Lo;0;L;6F6E;;;;N;;;;;
+2F910;CJK COMPATIBILITY IDEOGRAPH-2F910;Lo;0;L;23F5E;;;;N;;;;;
+2F911;CJK COMPATIBILITY IDEOGRAPH-2F911;Lo;0;L;23F8E;;;;N;;;;;
+2F912;CJK COMPATIBILITY IDEOGRAPH-2F912;Lo;0;L;6FC6;;;;N;;;;;
+2F913;CJK COMPATIBILITY IDEOGRAPH-2F913;Lo;0;L;7039;;;;N;;;;;
+2F914;CJK COMPATIBILITY IDEOGRAPH-2F914;Lo;0;L;701E;;;;N;;;;;
+2F915;CJK COMPATIBILITY IDEOGRAPH-2F915;Lo;0;L;701B;;;;N;;;;;
+2F916;CJK COMPATIBILITY IDEOGRAPH-2F916;Lo;0;L;3D96;;;;N;;;;;
+2F917;CJK COMPATIBILITY IDEOGRAPH-2F917;Lo;0;L;704A;;;;N;;;;;
+2F918;CJK COMPATIBILITY IDEOGRAPH-2F918;Lo;0;L;707D;;;;N;;;;;
+2F919;CJK COMPATIBILITY IDEOGRAPH-2F919;Lo;0;L;7077;;;;N;;;;;
+2F91A;CJK COMPATIBILITY IDEOGRAPH-2F91A;Lo;0;L;70AD;;;;N;;;;;
+2F91B;CJK COMPATIBILITY IDEOGRAPH-2F91B;Lo;0;L;20525;;;;N;;;;;
+2F91C;CJK COMPATIBILITY IDEOGRAPH-2F91C;Lo;0;L;7145;;;;N;;;;;
+2F91D;CJK COMPATIBILITY IDEOGRAPH-2F91D;Lo;0;L;24263;;;;N;;;;;
+2F91E;CJK COMPATIBILITY IDEOGRAPH-2F91E;Lo;0;L;719C;;;;N;;;;;
+2F91F;CJK COMPATIBILITY IDEOGRAPH-2F91F;Lo;0;L;43AB;;;;N;;;;;
+2F920;CJK COMPATIBILITY IDEOGRAPH-2F920;Lo;0;L;7228;;;;N;;;;;
+2F921;CJK COMPATIBILITY IDEOGRAPH-2F921;Lo;0;L;7235;;;;N;;;;;
+2F922;CJK COMPATIBILITY IDEOGRAPH-2F922;Lo;0;L;7250;;;;N;;;;;
+2F923;CJK COMPATIBILITY IDEOGRAPH-2F923;Lo;0;L;24608;;;;N;;;;;
+2F924;CJK COMPATIBILITY IDEOGRAPH-2F924;Lo;0;L;7280;;;;N;;;;;
+2F925;CJK COMPATIBILITY IDEOGRAPH-2F925;Lo;0;L;7295;;;;N;;;;;
+2F926;CJK COMPATIBILITY IDEOGRAPH-2F926;Lo;0;L;24735;;;;N;;;;;
+2F927;CJK COMPATIBILITY IDEOGRAPH-2F927;Lo;0;L;24814;;;;N;;;;;
+2F928;CJK COMPATIBILITY IDEOGRAPH-2F928;Lo;0;L;737A;;;;N;;;;;
+2F929;CJK COMPATIBILITY IDEOGRAPH-2F929;Lo;0;L;738B;;;;N;;;;;
+2F92A;CJK COMPATIBILITY IDEOGRAPH-2F92A;Lo;0;L;3EAC;;;;N;;;;;
+2F92B;CJK COMPATIBILITY IDEOGRAPH-2F92B;Lo;0;L;73A5;;;;N;;;;;
+2F92C;CJK COMPATIBILITY IDEOGRAPH-2F92C;Lo;0;L;3EB8;;;;N;;;;;
+2F92D;CJK COMPATIBILITY IDEOGRAPH-2F92D;Lo;0;L;3EB8;;;;N;;;;;
+2F92E;CJK COMPATIBILITY IDEOGRAPH-2F92E;Lo;0;L;7447;;;;N;;;;;
+2F92F;CJK COMPATIBILITY IDEOGRAPH-2F92F;Lo;0;L;745C;;;;N;;;;;
+2F930;CJK COMPATIBILITY IDEOGRAPH-2F930;Lo;0;L;7471;;;;N;;;;;
+2F931;CJK COMPATIBILITY IDEOGRAPH-2F931;Lo;0;L;7485;;;;N;;;;;
+2F932;CJK COMPATIBILITY IDEOGRAPH-2F932;Lo;0;L;74CA;;;;N;;;;;
+2F933;CJK COMPATIBILITY IDEOGRAPH-2F933;Lo;0;L;3F1B;;;;N;;;;;
+2F934;CJK COMPATIBILITY IDEOGRAPH-2F934;Lo;0;L;7524;;;;N;;;;;
+2F935;CJK COMPATIBILITY IDEOGRAPH-2F935;Lo;0;L;24C36;;;;N;;;;;
+2F936;CJK COMPATIBILITY IDEOGRAPH-2F936;Lo;0;L;753E;;;;N;;;;;
+2F937;CJK COMPATIBILITY IDEOGRAPH-2F937;Lo;0;L;24C92;;;;N;;;;;
+2F938;CJK COMPATIBILITY IDEOGRAPH-2F938;Lo;0;L;7570;;;;N;;;;;
+2F939;CJK COMPATIBILITY IDEOGRAPH-2F939;Lo;0;L;2219F;;;;N;;;;;
+2F93A;CJK COMPATIBILITY IDEOGRAPH-2F93A;Lo;0;L;7610;;;;N;;;;;
+2F93B;CJK COMPATIBILITY IDEOGRAPH-2F93B;Lo;0;L;24FA1;;;;N;;;;;
+2F93C;CJK COMPATIBILITY IDEOGRAPH-2F93C;Lo;0;L;24FB8;;;;N;;;;;
+2F93D;CJK COMPATIBILITY IDEOGRAPH-2F93D;Lo;0;L;25044;;;;N;;;;;
+2F93E;CJK COMPATIBILITY IDEOGRAPH-2F93E;Lo;0;L;3FFC;;;;N;;;;;
+2F93F;CJK COMPATIBILITY IDEOGRAPH-2F93F;Lo;0;L;4008;;;;N;;;;;
+2F940;CJK COMPATIBILITY IDEOGRAPH-2F940;Lo;0;L;76F4;;;;N;;;;;
+2F941;CJK COMPATIBILITY IDEOGRAPH-2F941;Lo;0;L;250F3;;;;N;;;;;
+2F942;CJK COMPATIBILITY IDEOGRAPH-2F942;Lo;0;L;250F2;;;;N;;;;;
+2F943;CJK COMPATIBILITY IDEOGRAPH-2F943;Lo;0;L;25119;;;;N;;;;;
+2F944;CJK COMPATIBILITY IDEOGRAPH-2F944;Lo;0;L;25133;;;;N;;;;;
+2F945;CJK COMPATIBILITY IDEOGRAPH-2F945;Lo;0;L;771E;;;;N;;;;;
+2F946;CJK COMPATIBILITY IDEOGRAPH-2F946;Lo;0;L;771F;;;;N;;;;;
+2F947;CJK COMPATIBILITY IDEOGRAPH-2F947;Lo;0;L;771F;;;;N;;;;;
+2F948;CJK COMPATIBILITY IDEOGRAPH-2F948;Lo;0;L;774A;;;;N;;;;;
+2F949;CJK COMPATIBILITY IDEOGRAPH-2F949;Lo;0;L;4039;;;;N;;;;;
+2F94A;CJK COMPATIBILITY IDEOGRAPH-2F94A;Lo;0;L;778B;;;;N;;;;;
+2F94B;CJK COMPATIBILITY IDEOGRAPH-2F94B;Lo;0;L;4046;;;;N;;;;;
+2F94C;CJK COMPATIBILITY IDEOGRAPH-2F94C;Lo;0;L;4096;;;;N;;;;;
+2F94D;CJK COMPATIBILITY IDEOGRAPH-2F94D;Lo;0;L;2541D;;;;N;;;;;
+2F94E;CJK COMPATIBILITY IDEOGRAPH-2F94E;Lo;0;L;784E;;;;N;;;;;
+2F94F;CJK COMPATIBILITY IDEOGRAPH-2F94F;Lo;0;L;788C;;;;N;;;;;
+2F950;CJK COMPATIBILITY IDEOGRAPH-2F950;Lo;0;L;78CC;;;;N;;;;;
+2F951;CJK COMPATIBILITY IDEOGRAPH-2F951;Lo;0;L;40E3;;;;N;;;;;
+2F952;CJK COMPATIBILITY IDEOGRAPH-2F952;Lo;0;L;25626;;;;N;;;;;
+2F953;CJK COMPATIBILITY IDEOGRAPH-2F953;Lo;0;L;7956;;;;N;;;;;
+2F954;CJK COMPATIBILITY IDEOGRAPH-2F954;Lo;0;L;2569A;;;;N;;;;;
+2F955;CJK COMPATIBILITY IDEOGRAPH-2F955;Lo;0;L;256C5;;;;N;;;;;
+2F956;CJK COMPATIBILITY IDEOGRAPH-2F956;Lo;0;L;798F;;;;N;;;;;
+2F957;CJK COMPATIBILITY IDEOGRAPH-2F957;Lo;0;L;79EB;;;;N;;;;;
+2F958;CJK COMPATIBILITY IDEOGRAPH-2F958;Lo;0;L;412F;;;;N;;;;;
+2F959;CJK COMPATIBILITY IDEOGRAPH-2F959;Lo;0;L;7A40;;;;N;;;;;
+2F95A;CJK COMPATIBILITY IDEOGRAPH-2F95A;Lo;0;L;7A4A;;;;N;;;;;
+2F95B;CJK COMPATIBILITY IDEOGRAPH-2F95B;Lo;0;L;7A4F;;;;N;;;;;
+2F95C;CJK COMPATIBILITY IDEOGRAPH-2F95C;Lo;0;L;2597C;;;;N;;;;;
+2F95D;CJK COMPATIBILITY IDEOGRAPH-2F95D;Lo;0;L;25AA7;;;;N;;;;;
+2F95E;CJK COMPATIBILITY IDEOGRAPH-2F95E;Lo;0;L;25AA7;;;;N;;;;;
+2F95F;CJK COMPATIBILITY IDEOGRAPH-2F95F;Lo;0;L;7AAE;;;;N;;;;;
+2F960;CJK COMPATIBILITY IDEOGRAPH-2F960;Lo;0;L;4202;;;;N;;;;;
+2F961;CJK COMPATIBILITY IDEOGRAPH-2F961;Lo;0;L;25BAB;;;;N;;;;;
+2F962;CJK COMPATIBILITY IDEOGRAPH-2F962;Lo;0;L;7BC6;;;;N;;;;;
+2F963;CJK COMPATIBILITY IDEOGRAPH-2F963;Lo;0;L;7BC9;;;;N;;;;;
+2F964;CJK COMPATIBILITY IDEOGRAPH-2F964;Lo;0;L;4227;;;;N;;;;;
+2F965;CJK COMPATIBILITY IDEOGRAPH-2F965;Lo;0;L;25C80;;;;N;;;;;
+2F966;CJK COMPATIBILITY IDEOGRAPH-2F966;Lo;0;L;7CD2;;;;N;;;;;
+2F967;CJK COMPATIBILITY IDEOGRAPH-2F967;Lo;0;L;42A0;;;;N;;;;;
+2F968;CJK COMPATIBILITY IDEOGRAPH-2F968;Lo;0;L;7CE8;;;;N;;;;;
+2F969;CJK COMPATIBILITY IDEOGRAPH-2F969;Lo;0;L;7CE3;;;;N;;;;;
+2F96A;CJK COMPATIBILITY IDEOGRAPH-2F96A;Lo;0;L;7D00;;;;N;;;;;
+2F96B;CJK COMPATIBILITY IDEOGRAPH-2F96B;Lo;0;L;25F86;;;;N;;;;;
+2F96C;CJK COMPATIBILITY IDEOGRAPH-2F96C;Lo;0;L;7D63;;;;N;;;;;
+2F96D;CJK COMPATIBILITY IDEOGRAPH-2F96D;Lo;0;L;4301;;;;N;;;;;
+2F96E;CJK COMPATIBILITY IDEOGRAPH-2F96E;Lo;0;L;7DC7;;;;N;;;;;
+2F96F;CJK COMPATIBILITY IDEOGRAPH-2F96F;Lo;0;L;7E02;;;;N;;;;;
+2F970;CJK COMPATIBILITY IDEOGRAPH-2F970;Lo;0;L;7E45;;;;N;;;;;
+2F971;CJK COMPATIBILITY IDEOGRAPH-2F971;Lo;0;L;4334;;;;N;;;;;
+2F972;CJK COMPATIBILITY IDEOGRAPH-2F972;Lo;0;L;26228;;;;N;;;;;
+2F973;CJK COMPATIBILITY IDEOGRAPH-2F973;Lo;0;L;26247;;;;N;;;;;
+2F974;CJK COMPATIBILITY IDEOGRAPH-2F974;Lo;0;L;4359;;;;N;;;;;
+2F975;CJK COMPATIBILITY IDEOGRAPH-2F975;Lo;0;L;262D9;;;;N;;;;;
+2F976;CJK COMPATIBILITY IDEOGRAPH-2F976;Lo;0;L;7F7A;;;;N;;;;;
+2F977;CJK COMPATIBILITY IDEOGRAPH-2F977;Lo;0;L;2633E;;;;N;;;;;
+2F978;CJK COMPATIBILITY IDEOGRAPH-2F978;Lo;0;L;7F95;;;;N;;;;;
+2F979;CJK COMPATIBILITY IDEOGRAPH-2F979;Lo;0;L;7FFA;;;;N;;;;;
+2F97A;CJK COMPATIBILITY IDEOGRAPH-2F97A;Lo;0;L;8005;;;;N;;;;;
+2F97B;CJK COMPATIBILITY IDEOGRAPH-2F97B;Lo;0;L;264DA;;;;N;;;;;
+2F97C;CJK COMPATIBILITY IDEOGRAPH-2F97C;Lo;0;L;26523;;;;N;;;;;
+2F97D;CJK COMPATIBILITY IDEOGRAPH-2F97D;Lo;0;L;8060;;;;N;;;;;
+2F97E;CJK COMPATIBILITY IDEOGRAPH-2F97E;Lo;0;L;265A8;;;;N;;;;;
+2F97F;CJK COMPATIBILITY IDEOGRAPH-2F97F;Lo;0;L;8070;;;;N;;;;;
+2F980;CJK COMPATIBILITY IDEOGRAPH-2F980;Lo;0;L;2335F;;;;N;;;;;
+2F981;CJK COMPATIBILITY IDEOGRAPH-2F981;Lo;0;L;43D5;;;;N;;;;;
+2F982;CJK COMPATIBILITY IDEOGRAPH-2F982;Lo;0;L;80B2;;;;N;;;;;
+2F983;CJK COMPATIBILITY IDEOGRAPH-2F983;Lo;0;L;8103;;;;N;;;;;
+2F984;CJK COMPATIBILITY IDEOGRAPH-2F984;Lo;0;L;440B;;;;N;;;;;
+2F985;CJK COMPATIBILITY IDEOGRAPH-2F985;Lo;0;L;813E;;;;N;;;;;
+2F986;CJK COMPATIBILITY IDEOGRAPH-2F986;Lo;0;L;5AB5;;;;N;;;;;
+2F987;CJK COMPATIBILITY IDEOGRAPH-2F987;Lo;0;L;267A7;;;;N;;;;;
+2F988;CJK COMPATIBILITY IDEOGRAPH-2F988;Lo;0;L;267B5;;;;N;;;;;
+2F989;CJK COMPATIBILITY IDEOGRAPH-2F989;Lo;0;L;23393;;;;N;;;;;
+2F98A;CJK COMPATIBILITY IDEOGRAPH-2F98A;Lo;0;L;2339C;;;;N;;;;;
+2F98B;CJK COMPATIBILITY IDEOGRAPH-2F98B;Lo;0;L;8201;;;;N;;;;;
+2F98C;CJK COMPATIBILITY IDEOGRAPH-2F98C;Lo;0;L;8204;;;;N;;;;;
+2F98D;CJK COMPATIBILITY IDEOGRAPH-2F98D;Lo;0;L;8F9E;;;;N;;;;;
+2F98E;CJK COMPATIBILITY IDEOGRAPH-2F98E;Lo;0;L;446B;;;;N;;;;;
+2F98F;CJK COMPATIBILITY IDEOGRAPH-2F98F;Lo;0;L;8291;;;;N;;;;;
+2F990;CJK COMPATIBILITY IDEOGRAPH-2F990;Lo;0;L;828B;;;;N;;;;;
+2F991;CJK COMPATIBILITY IDEOGRAPH-2F991;Lo;0;L;829D;;;;N;;;;;
+2F992;CJK COMPATIBILITY IDEOGRAPH-2F992;Lo;0;L;52B3;;;;N;;;;;
+2F993;CJK COMPATIBILITY IDEOGRAPH-2F993;Lo;0;L;82B1;;;;N;;;;;
+2F994;CJK COMPATIBILITY IDEOGRAPH-2F994;Lo;0;L;82B3;;;;N;;;;;
+2F995;CJK COMPATIBILITY IDEOGRAPH-2F995;Lo;0;L;82BD;;;;N;;;;;
+2F996;CJK COMPATIBILITY IDEOGRAPH-2F996;Lo;0;L;82E6;;;;N;;;;;
+2F997;CJK COMPATIBILITY IDEOGRAPH-2F997;Lo;0;L;26B3C;;;;N;;;;;
+2F998;CJK COMPATIBILITY IDEOGRAPH-2F998;Lo;0;L;82E5;;;;N;;;;;
+2F999;CJK COMPATIBILITY IDEOGRAPH-2F999;Lo;0;L;831D;;;;N;;;;;
+2F99A;CJK COMPATIBILITY IDEOGRAPH-2F99A;Lo;0;L;8363;;;;N;;;;;
+2F99B;CJK COMPATIBILITY IDEOGRAPH-2F99B;Lo;0;L;83AD;;;;N;;;;;
+2F99C;CJK COMPATIBILITY IDEOGRAPH-2F99C;Lo;0;L;8323;;;;N;;;;;
+2F99D;CJK COMPATIBILITY IDEOGRAPH-2F99D;Lo;0;L;83BD;;;;N;;;;;
+2F99E;CJK COMPATIBILITY IDEOGRAPH-2F99E;Lo;0;L;83E7;;;;N;;;;;
+2F99F;CJK COMPATIBILITY IDEOGRAPH-2F99F;Lo;0;L;8457;;;;N;;;;;
+2F9A0;CJK COMPATIBILITY IDEOGRAPH-2F9A0;Lo;0;L;8353;;;;N;;;;;
+2F9A1;CJK COMPATIBILITY IDEOGRAPH-2F9A1;Lo;0;L;83CA;;;;N;;;;;
+2F9A2;CJK COMPATIBILITY IDEOGRAPH-2F9A2;Lo;0;L;83CC;;;;N;;;;;
+2F9A3;CJK COMPATIBILITY IDEOGRAPH-2F9A3;Lo;0;L;83DC;;;;N;;;;;
+2F9A4;CJK COMPATIBILITY IDEOGRAPH-2F9A4;Lo;0;L;26C36;;;;N;;;;;
+2F9A5;CJK COMPATIBILITY IDEOGRAPH-2F9A5;Lo;0;L;26D6B;;;;N;;;;;
+2F9A6;CJK COMPATIBILITY IDEOGRAPH-2F9A6;Lo;0;L;26CD5;;;;N;;;;;
+2F9A7;CJK COMPATIBILITY IDEOGRAPH-2F9A7;Lo;0;L;452B;;;;N;;;;;
+2F9A8;CJK COMPATIBILITY IDEOGRAPH-2F9A8;Lo;0;L;84F1;;;;N;;;;;
+2F9A9;CJK COMPATIBILITY IDEOGRAPH-2F9A9;Lo;0;L;84F3;;;;N;;;;;
+2F9AA;CJK COMPATIBILITY IDEOGRAPH-2F9AA;Lo;0;L;8516;;;;N;;;;;
+2F9AB;CJK COMPATIBILITY IDEOGRAPH-2F9AB;Lo;0;L;273CA;;;;N;;;;;
+2F9AC;CJK COMPATIBILITY IDEOGRAPH-2F9AC;Lo;0;L;8564;;;;N;;;;;
+2F9AD;CJK COMPATIBILITY IDEOGRAPH-2F9AD;Lo;0;L;26F2C;;;;N;;;;;
+2F9AE;CJK COMPATIBILITY IDEOGRAPH-2F9AE;Lo;0;L;455D;;;;N;;;;;
+2F9AF;CJK COMPATIBILITY IDEOGRAPH-2F9AF;Lo;0;L;4561;;;;N;;;;;
+2F9B0;CJK COMPATIBILITY IDEOGRAPH-2F9B0;Lo;0;L;26FB1;;;;N;;;;;
+2F9B1;CJK COMPATIBILITY IDEOGRAPH-2F9B1;Lo;0;L;270D2;;;;N;;;;;
+2F9B2;CJK COMPATIBILITY IDEOGRAPH-2F9B2;Lo;0;L;456B;;;;N;;;;;
+2F9B3;CJK COMPATIBILITY IDEOGRAPH-2F9B3;Lo;0;L;8650;;;;N;;;;;
+2F9B4;CJK COMPATIBILITY IDEOGRAPH-2F9B4;Lo;0;L;865C;;;;N;;;;;
+2F9B5;CJK COMPATIBILITY IDEOGRAPH-2F9B5;Lo;0;L;8667;;;;N;;;;;
+2F9B6;CJK COMPATIBILITY IDEOGRAPH-2F9B6;Lo;0;L;8669;;;;N;;;;;
+2F9B7;CJK COMPATIBILITY IDEOGRAPH-2F9B7;Lo;0;L;86A9;;;;N;;;;;
+2F9B8;CJK COMPATIBILITY IDEOGRAPH-2F9B8;Lo;0;L;8688;;;;N;;;;;
+2F9B9;CJK COMPATIBILITY IDEOGRAPH-2F9B9;Lo;0;L;870E;;;;N;;;;;
+2F9BA;CJK COMPATIBILITY IDEOGRAPH-2F9BA;Lo;0;L;86E2;;;;N;;;;;
+2F9BB;CJK COMPATIBILITY IDEOGRAPH-2F9BB;Lo;0;L;8779;;;;N;;;;;
+2F9BC;CJK COMPATIBILITY IDEOGRAPH-2F9BC;Lo;0;L;8728;;;;N;;;;;
+2F9BD;CJK COMPATIBILITY IDEOGRAPH-2F9BD;Lo;0;L;876B;;;;N;;;;;
+2F9BE;CJK COMPATIBILITY IDEOGRAPH-2F9BE;Lo;0;L;8786;;;;N;;;;;
+2F9BF;CJK COMPATIBILITY IDEOGRAPH-2F9BF;Lo;0;L;4D57;;;;N;;;;;
+2F9C0;CJK COMPATIBILITY IDEOGRAPH-2F9C0;Lo;0;L;87E1;;;;N;;;;;
+2F9C1;CJK COMPATIBILITY IDEOGRAPH-2F9C1;Lo;0;L;8801;;;;N;;;;;
+2F9C2;CJK COMPATIBILITY IDEOGRAPH-2F9C2;Lo;0;L;45F9;;;;N;;;;;
+2F9C3;CJK COMPATIBILITY IDEOGRAPH-2F9C3;Lo;0;L;8860;;;;N;;;;;
+2F9C4;CJK COMPATIBILITY IDEOGRAPH-2F9C4;Lo;0;L;8863;;;;N;;;;;
+2F9C5;CJK COMPATIBILITY IDEOGRAPH-2F9C5;Lo;0;L;27667;;;;N;;;;;
+2F9C6;CJK COMPATIBILITY IDEOGRAPH-2F9C6;Lo;0;L;88D7;;;;N;;;;;
+2F9C7;CJK COMPATIBILITY IDEOGRAPH-2F9C7;Lo;0;L;88DE;;;;N;;;;;
+2F9C8;CJK COMPATIBILITY IDEOGRAPH-2F9C8;Lo;0;L;4635;;;;N;;;;;
+2F9C9;CJK COMPATIBILITY IDEOGRAPH-2F9C9;Lo;0;L;88FA;;;;N;;;;;
+2F9CA;CJK COMPATIBILITY IDEOGRAPH-2F9CA;Lo;0;L;34BB;;;;N;;;;;
+2F9CB;CJK COMPATIBILITY IDEOGRAPH-2F9CB;Lo;0;L;278AE;;;;N;;;;;
+2F9CC;CJK COMPATIBILITY IDEOGRAPH-2F9CC;Lo;0;L;27966;;;;N;;;;;
+2F9CD;CJK COMPATIBILITY IDEOGRAPH-2F9CD;Lo;0;L;46BE;;;;N;;;;;
+2F9CE;CJK COMPATIBILITY IDEOGRAPH-2F9CE;Lo;0;L;46C7;;;;N;;;;;
+2F9CF;CJK COMPATIBILITY IDEOGRAPH-2F9CF;Lo;0;L;8AA0;;;;N;;;;;
+2F9D0;CJK COMPATIBILITY IDEOGRAPH-2F9D0;Lo;0;L;8AED;;;;N;;;;;
+2F9D1;CJK COMPATIBILITY IDEOGRAPH-2F9D1;Lo;0;L;8B8A;;;;N;;;;;
+2F9D2;CJK COMPATIBILITY IDEOGRAPH-2F9D2;Lo;0;L;8C55;;;;N;;;;;
+2F9D3;CJK COMPATIBILITY IDEOGRAPH-2F9D3;Lo;0;L;27CA8;;;;N;;;;;
+2F9D4;CJK COMPATIBILITY IDEOGRAPH-2F9D4;Lo;0;L;8CAB;;;;N;;;;;
+2F9D5;CJK COMPATIBILITY IDEOGRAPH-2F9D5;Lo;0;L;8CC1;;;;N;;;;;
+2F9D6;CJK COMPATIBILITY IDEOGRAPH-2F9D6;Lo;0;L;8D1B;;;;N;;;;;
+2F9D7;CJK COMPATIBILITY IDEOGRAPH-2F9D7;Lo;0;L;8D77;;;;N;;;;;
+2F9D8;CJK COMPATIBILITY IDEOGRAPH-2F9D8;Lo;0;L;27F2F;;;;N;;;;;
+2F9D9;CJK COMPATIBILITY IDEOGRAPH-2F9D9;Lo;0;L;20804;;;;N;;;;;
+2F9DA;CJK COMPATIBILITY IDEOGRAPH-2F9DA;Lo;0;L;8DCB;;;;N;;;;;
+2F9DB;CJK COMPATIBILITY IDEOGRAPH-2F9DB;Lo;0;L;8DBC;;;;N;;;;;
+2F9DC;CJK COMPATIBILITY IDEOGRAPH-2F9DC;Lo;0;L;8DF0;;;;N;;;;;
+2F9DD;CJK COMPATIBILITY IDEOGRAPH-2F9DD;Lo;0;L;208DE;;;;N;;;;;
+2F9DE;CJK COMPATIBILITY IDEOGRAPH-2F9DE;Lo;0;L;8ED4;;;;N;;;;;
+2F9DF;CJK COMPATIBILITY IDEOGRAPH-2F9DF;Lo;0;L;8F38;;;;N;;;;;
+2F9E0;CJK COMPATIBILITY IDEOGRAPH-2F9E0;Lo;0;L;285D2;;;;N;;;;;
+2F9E1;CJK COMPATIBILITY IDEOGRAPH-2F9E1;Lo;0;L;285ED;;;;N;;;;;
+2F9E2;CJK COMPATIBILITY IDEOGRAPH-2F9E2;Lo;0;L;9094;;;;N;;;;;
+2F9E3;CJK COMPATIBILITY IDEOGRAPH-2F9E3;Lo;0;L;90F1;;;;N;;;;;
+2F9E4;CJK COMPATIBILITY IDEOGRAPH-2F9E4;Lo;0;L;9111;;;;N;;;;;
+2F9E5;CJK COMPATIBILITY IDEOGRAPH-2F9E5;Lo;0;L;2872E;;;;N;;;;;
+2F9E6;CJK COMPATIBILITY IDEOGRAPH-2F9E6;Lo;0;L;911B;;;;N;;;;;
+2F9E7;CJK COMPATIBILITY IDEOGRAPH-2F9E7;Lo;0;L;9238;;;;N;;;;;
+2F9E8;CJK COMPATIBILITY IDEOGRAPH-2F9E8;Lo;0;L;92D7;;;;N;;;;;
+2F9E9;CJK COMPATIBILITY IDEOGRAPH-2F9E9;Lo;0;L;92D8;;;;N;;;;;
+2F9EA;CJK COMPATIBILITY IDEOGRAPH-2F9EA;Lo;0;L;927C;;;;N;;;;;
+2F9EB;CJK COMPATIBILITY IDEOGRAPH-2F9EB;Lo;0;L;93F9;;;;N;;;;;
+2F9EC;CJK COMPATIBILITY IDEOGRAPH-2F9EC;Lo;0;L;9415;;;;N;;;;;
+2F9ED;CJK COMPATIBILITY IDEOGRAPH-2F9ED;Lo;0;L;28BFA;;;;N;;;;;
+2F9EE;CJK COMPATIBILITY IDEOGRAPH-2F9EE;Lo;0;L;958B;;;;N;;;;;
+2F9EF;CJK COMPATIBILITY IDEOGRAPH-2F9EF;Lo;0;L;4995;;;;N;;;;;
+2F9F0;CJK COMPATIBILITY IDEOGRAPH-2F9F0;Lo;0;L;95B7;;;;N;;;;;
+2F9F1;CJK COMPATIBILITY IDEOGRAPH-2F9F1;Lo;0;L;28D77;;;;N;;;;;
+2F9F2;CJK COMPATIBILITY IDEOGRAPH-2F9F2;Lo;0;L;49E6;;;;N;;;;;
+2F9F3;CJK COMPATIBILITY IDEOGRAPH-2F9F3;Lo;0;L;96C3;;;;N;;;;;
+2F9F4;CJK COMPATIBILITY IDEOGRAPH-2F9F4;Lo;0;L;5DB2;;;;N;;;;;
+2F9F5;CJK COMPATIBILITY IDEOGRAPH-2F9F5;Lo;0;L;9723;;;;N;;;;;
+2F9F6;CJK COMPATIBILITY IDEOGRAPH-2F9F6;Lo;0;L;29145;;;;N;;;;;
+2F9F7;CJK COMPATIBILITY IDEOGRAPH-2F9F7;Lo;0;L;2921A;;;;N;;;;;
+2F9F8;CJK COMPATIBILITY IDEOGRAPH-2F9F8;Lo;0;L;4A6E;;;;N;;;;;
+2F9F9;CJK COMPATIBILITY IDEOGRAPH-2F9F9;Lo;0;L;4A76;;;;N;;;;;
+2F9FA;CJK COMPATIBILITY IDEOGRAPH-2F9FA;Lo;0;L;97E0;;;;N;;;;;
+2F9FB;CJK COMPATIBILITY IDEOGRAPH-2F9FB;Lo;0;L;2940A;;;;N;;;;;
+2F9FC;CJK COMPATIBILITY IDEOGRAPH-2F9FC;Lo;0;L;4AB2;;;;N;;;;;
+2F9FD;CJK COMPATIBILITY IDEOGRAPH-2F9FD;Lo;0;L;29496;;;;N;;;;;
+2F9FE;CJK COMPATIBILITY IDEOGRAPH-2F9FE;Lo;0;L;980B;;;;N;;;;;
+2F9FF;CJK COMPATIBILITY IDEOGRAPH-2F9FF;Lo;0;L;980B;;;;N;;;;;
+2FA00;CJK COMPATIBILITY IDEOGRAPH-2FA00;Lo;0;L;9829;;;;N;;;;;
+2FA01;CJK COMPATIBILITY IDEOGRAPH-2FA01;Lo;0;L;295B6;;;;N;;;;;
+2FA02;CJK COMPATIBILITY IDEOGRAPH-2FA02;Lo;0;L;98E2;;;;N;;;;;
+2FA03;CJK COMPATIBILITY IDEOGRAPH-2FA03;Lo;0;L;4B33;;;;N;;;;;
+2FA04;CJK COMPATIBILITY IDEOGRAPH-2FA04;Lo;0;L;9929;;;;N;;;;;
+2FA05;CJK COMPATIBILITY IDEOGRAPH-2FA05;Lo;0;L;99A7;;;;N;;;;;
+2FA06;CJK COMPATIBILITY IDEOGRAPH-2FA06;Lo;0;L;99C2;;;;N;;;;;
+2FA07;CJK COMPATIBILITY IDEOGRAPH-2FA07;Lo;0;L;99FE;;;;N;;;;;
+2FA08;CJK COMPATIBILITY IDEOGRAPH-2FA08;Lo;0;L;4BCE;;;;N;;;;;
+2FA09;CJK COMPATIBILITY IDEOGRAPH-2FA09;Lo;0;L;29B30;;;;N;;;;;
+2FA0A;CJK COMPATIBILITY IDEOGRAPH-2FA0A;Lo;0;L;9B12;;;;N;;;;;
+2FA0B;CJK COMPATIBILITY IDEOGRAPH-2FA0B;Lo;0;L;9C40;;;;N;;;;;
+2FA0C;CJK COMPATIBILITY IDEOGRAPH-2FA0C;Lo;0;L;9CFD;;;;N;;;;;
+2FA0D;CJK COMPATIBILITY IDEOGRAPH-2FA0D;Lo;0;L;4CCE;;;;N;;;;;
+2FA0E;CJK COMPATIBILITY IDEOGRAPH-2FA0E;Lo;0;L;4CED;;;;N;;;;;
+2FA0F;CJK COMPATIBILITY IDEOGRAPH-2FA0F;Lo;0;L;9D67;;;;N;;;;;
+2FA10;CJK COMPATIBILITY IDEOGRAPH-2FA10;Lo;0;L;2A0CE;;;;N;;;;;
+2FA11;CJK COMPATIBILITY IDEOGRAPH-2FA11;Lo;0;L;4CF8;;;;N;;;;;
+2FA12;CJK COMPATIBILITY IDEOGRAPH-2FA12;Lo;0;L;2A105;;;;N;;;;;
+2FA13;CJK COMPATIBILITY IDEOGRAPH-2FA13;Lo;0;L;2A20E;;;;N;;;;;
+2FA14;CJK COMPATIBILITY IDEOGRAPH-2FA14;Lo;0;L;2A291;;;;N;;;;;
+2FA15;CJK COMPATIBILITY IDEOGRAPH-2FA15;Lo;0;L;9EBB;;;;N;;;;;
+2FA16;CJK COMPATIBILITY IDEOGRAPH-2FA16;Lo;0;L;4D56;;;;N;;;;;
+2FA17;CJK COMPATIBILITY IDEOGRAPH-2FA17;Lo;0;L;9EF9;;;;N;;;;;
+2FA18;CJK COMPATIBILITY IDEOGRAPH-2FA18;Lo;0;L;9EFE;;;;N;;;;;
+2FA19;CJK COMPATIBILITY IDEOGRAPH-2FA19;Lo;0;L;9F05;;;;N;;;;;
+2FA1A;CJK COMPATIBILITY IDEOGRAPH-2FA1A;Lo;0;L;9F0F;;;;N;;;;;
+2FA1B;CJK COMPATIBILITY IDEOGRAPH-2FA1B;Lo;0;L;9F16;;;;N;;;;;
+2FA1C;CJK COMPATIBILITY IDEOGRAPH-2FA1C;Lo;0;L;9F3B;;;;N;;;;;
+2FA1D;CJK COMPATIBILITY IDEOGRAPH-2FA1D;Lo;0;L;2A600;;;;N;;;;;
+E0001;LANGUAGE TAG;Cf;0;BN;;;;;N;;;;;
+E0020;TAG SPACE;Cf;0;BN;;;;;N;;;;;
+E0021;TAG EXCLAMATION MARK;Cf;0;BN;;;;;N;;;;;
+E0022;TAG QUOTATION MARK;Cf;0;BN;;;;;N;;;;;
+E0023;TAG NUMBER SIGN;Cf;0;BN;;;;;N;;;;;
+E0024;TAG DOLLAR SIGN;Cf;0;BN;;;;;N;;;;;
+E0025;TAG PERCENT SIGN;Cf;0;BN;;;;;N;;;;;
+E0026;TAG AMPERSAND;Cf;0;BN;;;;;N;;;;;
+E0027;TAG APOSTROPHE;Cf;0;BN;;;;;N;;;;;
+E0028;TAG LEFT PARENTHESIS;Cf;0;BN;;;;;N;;;;;
+E0029;TAG RIGHT PARENTHESIS;Cf;0;BN;;;;;N;;;;;
+E002A;TAG ASTERISK;Cf;0;BN;;;;;N;;;;;
+E002B;TAG PLUS SIGN;Cf;0;BN;;;;;N;;;;;
+E002C;TAG COMMA;Cf;0;BN;;;;;N;;;;;
+E002D;TAG HYPHEN-MINUS;Cf;0;BN;;;;;N;;;;;
+E002E;TAG FULL STOP;Cf;0;BN;;;;;N;;;;;
+E002F;TAG SOLIDUS;Cf;0;BN;;;;;N;;;;;
+E0030;TAG DIGIT ZERO;Cf;0;BN;;;;;N;;;;;
+E0031;TAG DIGIT ONE;Cf;0;BN;;;;;N;;;;;
+E0032;TAG DIGIT TWO;Cf;0;BN;;;;;N;;;;;
+E0033;TAG DIGIT THREE;Cf;0;BN;;;;;N;;;;;
+E0034;TAG DIGIT FOUR;Cf;0;BN;;;;;N;;;;;
+E0035;TAG DIGIT FIVE;Cf;0;BN;;;;;N;;;;;
+E0036;TAG DIGIT SIX;Cf;0;BN;;;;;N;;;;;
+E0037;TAG DIGIT SEVEN;Cf;0;BN;;;;;N;;;;;
+E0038;TAG DIGIT EIGHT;Cf;0;BN;;;;;N;;;;;
+E0039;TAG DIGIT NINE;Cf;0;BN;;;;;N;;;;;
+E003A;TAG COLON;Cf;0;BN;;;;;N;;;;;
+E003B;TAG SEMICOLON;Cf;0;BN;;;;;N;;;;;
+E003C;TAG LESS-THAN SIGN;Cf;0;BN;;;;;N;;;;;
+E003D;TAG EQUALS SIGN;Cf;0;BN;;;;;N;;;;;
+E003E;TAG GREATER-THAN SIGN;Cf;0;BN;;;;;N;;;;;
+E003F;TAG QUESTION MARK;Cf;0;BN;;;;;N;;;;;
+E0040;TAG COMMERCIAL AT;Cf;0;BN;;;;;N;;;;;
+E0041;TAG LATIN CAPITAL LETTER A;Cf;0;BN;;;;;N;;;;;
+E0042;TAG LATIN CAPITAL LETTER B;Cf;0;BN;;;;;N;;;;;
+E0043;TAG LATIN CAPITAL LETTER C;Cf;0;BN;;;;;N;;;;;
+E0044;TAG LATIN CAPITAL LETTER D;Cf;0;BN;;;;;N;;;;;
+E0045;TAG LATIN CAPITAL LETTER E;Cf;0;BN;;;;;N;;;;;
+E0046;TAG LATIN CAPITAL LETTER F;Cf;0;BN;;;;;N;;;;;
+E0047;TAG LATIN CAPITAL LETTER G;Cf;0;BN;;;;;N;;;;;
+E0048;TAG LATIN CAPITAL LETTER H;Cf;0;BN;;;;;N;;;;;
+E0049;TAG LATIN CAPITAL LETTER I;Cf;0;BN;;;;;N;;;;;
+E004A;TAG LATIN CAPITAL LETTER J;Cf;0;BN;;;;;N;;;;;
+E004B;TAG LATIN CAPITAL LETTER K;Cf;0;BN;;;;;N;;;;;
+E004C;TAG LATIN CAPITAL LETTER L;Cf;0;BN;;;;;N;;;;;
+E004D;TAG LATIN CAPITAL LETTER M;Cf;0;BN;;;;;N;;;;;
+E004E;TAG LATIN CAPITAL LETTER N;Cf;0;BN;;;;;N;;;;;
+E004F;TAG LATIN CAPITAL LETTER O;Cf;0;BN;;;;;N;;;;;
+E0050;TAG LATIN CAPITAL LETTER P;Cf;0;BN;;;;;N;;;;;
+E0051;TAG LATIN CAPITAL LETTER Q;Cf;0;BN;;;;;N;;;;;
+E0052;TAG LATIN CAPITAL LETTER R;Cf;0;BN;;;;;N;;;;;
+E0053;TAG LATIN CAPITAL LETTER S;Cf;0;BN;;;;;N;;;;;
+E0054;TAG LATIN CAPITAL LETTER T;Cf;0;BN;;;;;N;;;;;
+E0055;TAG LATIN CAPITAL LETTER U;Cf;0;BN;;;;;N;;;;;
+E0056;TAG LATIN CAPITAL LETTER V;Cf;0;BN;;;;;N;;;;;
+E0057;TAG LATIN CAPITAL LETTER W;Cf;0;BN;;;;;N;;;;;
+E0058;TAG LATIN CAPITAL LETTER X;Cf;0;BN;;;;;N;;;;;
+E0059;TAG LATIN CAPITAL LETTER Y;Cf;0;BN;;;;;N;;;;;
+E005A;TAG LATIN CAPITAL LETTER Z;Cf;0;BN;;;;;N;;;;;
+E005B;TAG LEFT SQUARE BRACKET;Cf;0;BN;;;;;N;;;;;
+E005C;TAG REVERSE SOLIDUS;Cf;0;BN;;;;;N;;;;;
+E005D;TAG RIGHT SQUARE BRACKET;Cf;0;BN;;;;;N;;;;;
+E005E;TAG CIRCUMFLEX ACCENT;Cf;0;BN;;;;;N;;;;;
+E005F;TAG LOW LINE;Cf;0;BN;;;;;N;;;;;
+E0060;TAG GRAVE ACCENT;Cf;0;BN;;;;;N;;;;;
+E0061;TAG LATIN SMALL LETTER A;Cf;0;BN;;;;;N;;;;;
+E0062;TAG LATIN SMALL LETTER B;Cf;0;BN;;;;;N;;;;;
+E0063;TAG LATIN SMALL LETTER C;Cf;0;BN;;;;;N;;;;;
+E0064;TAG LATIN SMALL LETTER D;Cf;0;BN;;;;;N;;;;;
+E0065;TAG LATIN SMALL LETTER E;Cf;0;BN;;;;;N;;;;;
+E0066;TAG LATIN SMALL LETTER F;Cf;0;BN;;;;;N;;;;;
+E0067;TAG LATIN SMALL LETTER G;Cf;0;BN;;;;;N;;;;;
+E0068;TAG LATIN SMALL LETTER H;Cf;0;BN;;;;;N;;;;;
+E0069;TAG LATIN SMALL LETTER I;Cf;0;BN;;;;;N;;;;;
+E006A;TAG LATIN SMALL LETTER J;Cf;0;BN;;;;;N;;;;;
+E006B;TAG LATIN SMALL LETTER K;Cf;0;BN;;;;;N;;;;;
+E006C;TAG LATIN SMALL LETTER L;Cf;0;BN;;;;;N;;;;;
+E006D;TAG LATIN SMALL LETTER M;Cf;0;BN;;;;;N;;;;;
+E006E;TAG LATIN SMALL LETTER N;Cf;0;BN;;;;;N;;;;;
+E006F;TAG LATIN SMALL LETTER O;Cf;0;BN;;;;;N;;;;;
+E0070;TAG LATIN SMALL LETTER P;Cf;0;BN;;;;;N;;;;;
+E0071;TAG LATIN SMALL LETTER Q;Cf;0;BN;;;;;N;;;;;
+E0072;TAG LATIN SMALL LETTER R;Cf;0;BN;;;;;N;;;;;
+E0073;TAG LATIN SMALL LETTER S;Cf;0;BN;;;;;N;;;;;
+E0074;TAG LATIN SMALL LETTER T;Cf;0;BN;;;;;N;;;;;
+E0075;TAG LATIN SMALL LETTER U;Cf;0;BN;;;;;N;;;;;
+E0076;TAG LATIN SMALL LETTER V;Cf;0;BN;;;;;N;;;;;
+E0077;TAG LATIN SMALL LETTER W;Cf;0;BN;;;;;N;;;;;
+E0078;TAG LATIN SMALL LETTER X;Cf;0;BN;;;;;N;;;;;
+E0079;TAG LATIN SMALL LETTER Y;Cf;0;BN;;;;;N;;;;;
+E007A;TAG LATIN SMALL LETTER Z;Cf;0;BN;;;;;N;;;;;
+E007B;TAG LEFT CURLY BRACKET;Cf;0;BN;;;;;N;;;;;
+E007C;TAG VERTICAL LINE;Cf;0;BN;;;;;N;;;;;
+E007D;TAG RIGHT CURLY BRACKET;Cf;0;BN;;;;;N;;;;;
+E007E;TAG TILDE;Cf;0;BN;;;;;N;;;;;
+E007F;CANCEL TAG;Cf;0;BN;;;;;N;;;;;
+F0000;<Plane 15 Private Use, First>;Co;0;L;;;;;N;;;;;
+FFFFD;<Plane 15 Private Use, Last>;Co;0;L;;;;;N;;;;;
+100000;<Plane 16 Private Use, First>;Co;0;L;;;;;N;;;;;
+10FFFD;<Plane 16 Private Use, Last>;Co;0;L;;;;;N;;;;;
+
+
diff --git a/src/pal/src/locale/unicode.cpp b/src/pal/src/locale/unicode.cpp
new file mode 100644
index 0000000000..3c119744b0
--- /dev/null
+++ b/src/pal/src/locale/unicode.cpp
@@ -0,0 +1,1026 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+unicode.cpp
+
+Abstract:
+
+Implementation of all functions related to Unicode support
+
+Revision History:
+
+
+
+--*/
+
+#include "pal/thread.hpp"
+
+#include "pal/palinternal.h"
+#include "pal/unicode_data.h"
+#include "pal/dbgmsg.h"
+#include "pal/file.h"
+#include "pal/utf8.h"
+#include "pal/locale.h"
+#include "pal/cruntime.h"
+#include "pal/stackstring.hpp"
+
+#if !(HAVE_PTHREAD_RWLOCK_T || HAVE_COREFOUNDATION)
+#error Either pthread rwlocks or Core Foundation are required for Unicode support
+#endif /* !(HAVE_PTHREAD_RWLOCK_T || HAVE_COREFOUNDATION) */
+
+#include <pthread.h>
+#include <locale.h>
+#ifndef __APPLE__
+#include <libintl.h>
+#endif // __APPLE__
+#include <errno.h>
+#if HAVE_COREFOUNDATION
+#include <corefoundation/corefoundation.h>
+#endif // HAVE_COREFOUNDATION
+
+#include <debugmacrosext.h>
+
+using namespace CorUnix;
+
+SET_DEFAULT_DEBUG_CHANNEL(UNICODE);
+
+#if HAVE_COREFOUNDATION
+
+static CP_MAPPING CP_TO_NATIVE_TABLE[] = {
+ { 65001, kCFStringEncodingUTF8, 4, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
+ { 1252, kCFStringEncodingWindowsLatin1, 1, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
+ { 1251, kCFStringEncodingWindowsCyrillic, 1, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
+ { 1253, kCFStringEncodingWindowsGreek, 1, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
+ { 1254, kCFStringEncodingWindowsLatin5, 1, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
+ { 1258, kCFStringEncodingWindowsVietnamese, 1, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
+ { 932, kCFStringEncodingDOSJapanese, 2, { 129, 159, 224, 252, 0, 0, 0, 0, 0, 0, 0, 0 } },
+ { 949, kCFStringEncodingDOSKorean, 2, { 129, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
+ { 950, kCFStringEncodingDOSChineseTrad, 2, { 129, 254, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } }
+};
+
+#else // HAVE_COREFOUNDATION
+
+static const CP_MAPPING CP_TO_NATIVE_TABLE[] = {
+ { 65001, "utf8", 4, { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } }
+};
+
+#endif // HAVE_COREFOUNDATION
+
+// We hardcode the system's default codepage to be UTF-8.
+// There are several reasons for this:
+// - On OSX, HFS+ file names are encoded as UTF-8.
+// - On OSX, When writing strings to the console, the Terminal.app will interpret them as UTF-8.
+// - We want Ansi marshalling to mean marshal to UTF-8 on Mac and Linux
+static const UINT PAL_ACP = 65001;
+
+#if !HAVE_COREFOUNDATION
+/*++
+Function:
+UnicodeDataComp
+This is the comparison function used by the bsearch function to search
+for unicode characters in the UnicodeData array.
+
+Parameter:
+pnKey
+The unicode character value to search for.
+elem
+A pointer to a UnicodeDataRec.
+
+Return value:
+<0 if pnKey < elem->nUnicodeValue
+0 if pnKey == elem->nUnicodeValue
+>0 if pnKey > elem->nUnicodeValue
+--*/
+static int UnicodeDataComp(const void *pnKey, const void *elem)
+{
+ WCHAR uValue = ((UnicodeDataRec*)elem)->nUnicodeValue;
+ WORD rangeValue = ((UnicodeDataRec*)elem)->rangeValue;
+
+ if (*((INT*)pnKey) < uValue)
+ {
+ return -1;
+ }
+ else
+ {
+ if (*((INT*)pnKey) > (uValue + rangeValue))
+ {
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+}
+
+/*++
+Function:
+GetUnicodeData
+This function is used to get information about a Unicode character.
+
+Parameters:
+nUnicodeValue
+The numeric value of the Unicode character to get information about.
+pDataRec
+The UnicodeDataRec to fill in with the data for the Unicode character.
+
+Return value:
+TRUE if the Unicode character was found.
+
+--*/
+BOOL GetUnicodeData(INT nUnicodeValue, UnicodeDataRec *pDataRec)
+{
+ BOOL bRet;
+ if (nUnicodeValue <= UNICODE_DATA_DIRECT_ACCESS)
+ {
+ *pDataRec = UnicodeData[nUnicodeValue];
+ bRet = TRUE;
+ }
+ else
+ {
+ UnicodeDataRec *dataRec;
+ INT nNumOfChars = UNICODE_DATA_SIZE;
+ dataRec = (UnicodeDataRec *) bsearch(&nUnicodeValue, UnicodeData, nNumOfChars,
+ sizeof(UnicodeDataRec), UnicodeDataComp);
+ if (dataRec == NULL)
+ {
+ bRet = FALSE;
+ }
+ else
+ {
+ bRet = TRUE;
+ *pDataRec = *dataRec;
+ }
+ }
+ return bRet;
+}
+#endif /* !HAVE_COREFOUNDATION */
+
+/*++
+Function:
+CODEPAGEGetData
+
+ IN UINT CodePage - The code page the caller
+ is attempting to retrieve data on.
+
+ Returns a pointer to structure, NULL otherwise.
+--*/
+const CP_MAPPING *
+CODEPAGEGetData( IN UINT CodePage )
+{
+ UINT nSize = sizeof( CP_TO_NATIVE_TABLE ) / sizeof( CP_TO_NATIVE_TABLE[ 0 ] );
+ UINT nIndex = 0;
+
+ if ( CP_ACP == CodePage )
+ {
+ CodePage = PAL_ACP;
+ }
+
+ /* checking if the CodePage is ACP and returning true if so */
+ while (nIndex < nSize)
+ {
+ if ( ( CP_TO_NATIVE_TABLE[ nIndex ] ).nCodePage == CodePage )
+ {
+ return &(CP_TO_NATIVE_TABLE[ nIndex ]);
+ }
+ nIndex++;
+ }
+ return NULL;
+}
+
+#if HAVE_COREFOUNDATION
+/*++
+Function :
+
+CODEPAGECPToCFStringEncoding - Gets the CFStringEncoding for
+the given codepage.
+
+Returns the CFStringEncoding for the given codepage.
+--*/
+CFStringEncoding CODEPAGECPToCFStringEncoding(UINT codepage)
+{
+ const CP_MAPPING *cp_mapping = CODEPAGEGetData(codepage);
+ if (cp_mapping == NULL)
+ {
+ return kCFStringEncodingInvalidId;
+ }
+ else
+ {
+ return cp_mapping->nCFEncoding;
+ }
+}
+#endif // HAVE_COREFOUNDATION
+
+/*++
+Function:
+CharNextA
+
+Parameters
+
+lpsz
+[in] Pointer to a character in a null-terminated string.
+
+Return Values
+
+A pointer to the next character in the string, or to the terminating null character if at the end of the string, indicates success.
+
+If lpsz points to the terminating null character, the return value is equal to lpsz.
+
+See MSDN doc.
+--*/
+LPSTR
+PALAPI
+CharNextA(
+ IN LPCSTR lpsz)
+{
+ LPSTR pRet;
+ PERF_ENTRY(CharNextA);
+ ENTRY("CharNextA (lpsz=%p (%s))\n", lpsz?lpsz:NULL, lpsz?lpsz:NULL);
+
+ pRet = CharNextExA(GetACP(), lpsz, 0);
+
+ LOGEXIT ("CharNextA returns LPSTR %p\n", pRet);
+ PERF_EXIT(CharNextA);
+ return pRet;
+}
+
+
+/*++
+Function:
+CharNextExA
+
+See MSDN doc.
+--*/
+LPSTR
+PALAPI
+CharNextExA(
+ IN WORD CodePage,
+ IN LPCSTR lpCurrentChar,
+ IN DWORD dwFlags)
+{
+ LPSTR pRet = (LPSTR) lpCurrentChar;
+
+ PERF_ENTRY(CharNextExA);
+ ENTRY("CharNextExA (CodePage=%hu, lpCurrentChar=%p (%s), dwFlags=%#x)\n",
+ CodePage, lpCurrentChar?lpCurrentChar:"NULL", lpCurrentChar?lpCurrentChar:"NULL", dwFlags);
+
+ if ((lpCurrentChar != NULL) && (*lpCurrentChar != 0))
+ {
+ pRet += (*(lpCurrentChar+1) != 0) &&
+ IsDBCSLeadByteEx(CodePage, *lpCurrentChar) ? 2 : 1;
+ }
+
+ LOGEXIT("CharNextExA returns LPSTR:%p (%s)\n", pRet, pRet);
+ PERF_EXIT(CharNextExA);
+ return pRet;
+}
+
+
+
+/*++
+Function:
+AreFileApisANSI
+
+The AreFileApisANSI function determines whether the file I/O functions
+are using the ANSI or OEM character set code page. This function is
+useful for 8-bit console input and output operations.
+
+Return Values
+
+If the set of file I/O functions is using the ANSI code page, the return value is nonzero.
+
+If the set of file I/O functions is using the OEM code page, the return value is zero.
+
+In the ROTOR version we always return true since there is no concept
+of OEM code pages.
+
+--*/
+BOOL
+PALAPI
+AreFileApisANSI(
+ VOID)
+{
+ PERF_ENTRY(AreFileApisANSI);
+ ENTRY("AreFileApisANSI ()\n");
+
+ LOGEXIT("AreFileApisANSI returns BOOL TRUE\n");
+ PERF_EXIT(AreFileApisANSI);
+ return TRUE;
+}
+
+
+/*++
+Function:
+GetConsoleCP
+
+See MSDN doc.
+--*/
+UINT
+PALAPI
+GetConsoleCP(
+ VOID)
+{
+ UINT nRet = 0;
+ PERF_ENTRY(GetConsoleCP);
+ ENTRY("GetConsoleCP()\n");
+
+ nRet = GetACP();
+
+ LOGEXIT("GetConsoleCP returns UINT %d\n", nRet );
+ PERF_EXIT(GetConsoleCP);
+ return nRet;
+}
+
+/*++
+Function:
+GetConsoleOutputCP
+
+See MSDN doc.
+--*/
+UINT
+PALAPI
+GetConsoleOutputCP(
+ VOID)
+{
+ UINT nRet = 0;
+ PERF_ENTRY(GetConsoleOutputCP);
+ ENTRY("GetConsoleOutputCP()\n");
+ nRet = GetACP();
+ LOGEXIT("GetConsoleOutputCP returns UINT %d \n", nRet );
+ PERF_EXIT(GetConsoleOutputCP);
+ return nRet;
+}
+
+
+/*++
+Function:
+IsValidCodePage
+
+See MSDN doc.
+
+Notes :
+"pseudo code pages", like CP_ACP, aren't considered 'valid' in this context.
+CP_UTF7 and CP_UTF8, however, *are* considered valid code pages, even though
+MSDN fails to mention them in the IsValidCodePage entry.
+Note : CP_UTF7 support isn't required for Rotor
+--*/
+BOOL
+PALAPI
+IsValidCodePage(
+ IN UINT CodePage)
+{
+ BOOL retval = FALSE;
+
+ PERF_ENTRY(IsValidCodePage);
+ ENTRY("IsValidCodePage(%d)\n", CodePage );
+
+ switch(CodePage)
+ {
+ case CP_ACP : /* fall through */
+ case CP_OEMCP : /* fall through */
+ case CP_MACCP : /* fall through */
+ case CP_THREAD_ACP:
+ /* 'pseudo code pages' : not valid */
+ retval = FALSE;
+ break;
+ case CP_UTF7:
+ /* valid in Win32, but not supported in Rotor */
+ retval = FALSE;
+ break;
+ case CP_UTF8:
+ /* valid, but not part of CODEPAGEGetData's tables */
+ retval = TRUE;
+ break;
+ default:
+ retval = (NULL != CODEPAGEGetData( CodePage ));
+ break;
+ }
+
+ LOGEXIT("IsValidCodePage returns BOOL %d\n",retval);
+ PERF_EXIT(IsValidCodePage);
+ return retval;
+}
+
+#if ENABLE_DOWNLEVEL_FOR_NLS
+/*++
+Function:
+GetStringTypeEx
+
+See MSDN doc.
+--*/
+BOOL
+PALAPI
+GetStringTypeExW(
+ IN LCID Locale,
+ IN DWORD dwInfoType,
+ IN LPCWSTR lpSrcStr,
+ IN int cchSrc,
+ OUT LPWORD lpCharType)
+{
+
+
+ int i = 0;
+#if !HAVE_COREFOUNDATION
+ UnicodeDataRec unicodeDataRec;
+#endif /* !HAVE_COREFOUNDATION */
+ BOOL bRet = TRUE;
+ wchar_t wcstr ;
+ PERF_ENTRY(GetStringTypeExW);
+ ENTRY("GetStringTypeExW(Locale=%#x, dwInfoType=%#x, lpSrcStr=%p (%S), "
+ "cchSrc=%d, lpCharType=%p)\n",
+ Locale, dwInfoType, lpSrcStr?lpSrcStr:W16_NULLSTRING, lpSrcStr?lpSrcStr:W16_NULLSTRING, cchSrc, lpCharType);
+
+ if((Locale != LOCALE_USER_DEFAULT)||(dwInfoType != CT_CTYPE1)
+ || (cchSrc != 1) || (lpSrcStr == (LPCWSTR)lpCharType))
+ {
+ ASSERT("One of the input parameters is invalid\n");
+ SetLastError(ERROR_INVALID_PARAMETER);
+ bRet = FALSE;
+ goto GetStringTypeExExit;
+ }
+
+
+ /*
+ * get length if needed...
+ */
+ if(cchSrc == -1)
+ {
+ cchSrc = PAL_wcslen(lpSrcStr);
+ }
+
+ /*
+ * Loop through each character of the source string and update
+ * lpCharType accordingly.
+ */
+ for(i = 0; i < cchSrc; i++)
+ {
+ wcstr = lpSrcStr[i];
+#if HAVE_COREFOUNDATION
+ lpCharType[i] = 0;
+ if (PAL_iswlower(wcstr))
+ {
+ lpCharType[i] |= C1_LOWER;
+ }
+ if (PAL_iswupper(wcstr))
+ {
+ lpCharType[i] |= C1_UPPER;
+ }
+ if (PAL_iswalpha(wcstr))
+ {
+ lpCharType[i] |= C1_ALPHA;
+ }
+ if (PAL_iswdigit(wcstr))
+ {
+ lpCharType[i] |= C1_DIGIT;
+ }
+ if (PAL_iswspace(wcstr))
+ {
+ lpCharType[i] |= C1_SPACE;
+ }
+ if (PAL_iswblank(wcstr))
+ {
+ lpCharType[i] |= C1_BLANK;
+ }
+ if (PAL_iswcntrl(wcstr))
+ {
+ lpCharType[i] |= C1_CNTRL;
+ }
+ if (PAL_iswpunct(wcstr))
+ {
+ lpCharType[i] |= C1_PUNCT;
+ }
+#else /* HAVE_COREFOUNDATION */
+ /*
+ * Get the unicode data record for that character.
+ */
+ if(GetUnicodeData(wcstr, &unicodeDataRec))
+ {
+ lpCharType[i] = unicodeDataRec.C1_TYPE_FLAGS;
+ }
+ else
+ {
+ lpCharType[i] = 0;
+ }
+#endif /* HAVE_COREFOUNDATION */
+ }
+
+ GetStringTypeExExit:
+ LOGEXIT("GetStringTypeEx returns BOOL %d\n", bRet);
+ PERF_EXIT(GetStringTypeExW);
+ return bRet;
+}
+#endif // ENABLE_DOWNLEVEL_FOR_NLS
+
+/*++
+Function:
+GetCPInfo
+
+See MSDN doc.
+--*/
+BOOL
+PALAPI
+GetCPInfo(
+ IN UINT CodePage,
+ OUT LPCPINFO lpCPInfo)
+{
+ const CP_MAPPING * lpStruct = NULL;
+ BOOL bRet = FALSE;
+
+ PERF_ENTRY(GetCPInfo);
+ ENTRY("GetCPInfo(CodePage=%hu, lpCPInfo=%p)\n", CodePage, lpCPInfo);
+
+ /*check if the input code page is valid*/
+ if( CP_ACP != CodePage && !IsValidCodePage( CodePage ) )
+ {
+ /* error, invalid argument */
+ ERROR("CodePage(%d) parameter is invalid\n",CodePage);
+ SetLastError( ERROR_INVALID_PARAMETER );
+ goto done;
+ }
+
+ /*check if the lpCPInfo parameter is valid. */
+ if( !lpCPInfo )
+ {
+ /* error, invalid argument */
+ ERROR("lpCPInfo cannot be NULL\n" );
+ SetLastError( ERROR_INVALID_PARAMETER );
+ goto done;
+ }
+
+ if ( NULL != ( lpStruct = CODEPAGEGetData( CodePage ) ) )
+ {
+ lpCPInfo->MaxCharSize = lpStruct->nMaxByteSize;;
+ memcpy( lpCPInfo->LeadByte, lpStruct->LeadByte , MAX_LEADBYTES );
+
+ /* Don't need to be set, according to the spec. */
+ memset( lpCPInfo->DefaultChar, '?', MAX_DEFAULTCHAR );
+
+ bRet = TRUE;
+ }
+
+done:
+ LOGEXIT("GetCPInfo returns BOOL %d \n",bRet);
+ PERF_EXIT(GetCPInfo);
+ return bRet;
+}
+
+
+/*++
+Function:
+GetACP
+
+See MSDN doc.
+--*/
+UINT
+PALAPI
+GetACP(VOID)
+{
+ PERF_ENTRY(GetACP);
+ ENTRY("GetACP(VOID)\n");
+
+ LOGEXIT("GetACP returning UINT %d\n", PAL_ACP );
+ PERF_EXIT(GetACP);
+
+ return PAL_ACP;
+}
+
+
+/*++
+Function:
+IsDBCSLeadByteEx
+
+See MSDN doc.
+--*/
+BOOL
+PALAPI
+IsDBCSLeadByteEx(
+ IN UINT CodePage,
+ IN BYTE TestChar)
+{
+ CPINFO cpinfo;
+ SIZE_T i;
+ BOOL bRet = FALSE;
+
+ PERF_ENTRY(IsDBCSLeadByteEx);
+ ENTRY("IsDBCSLeadByteEx(CodePage=%#x, TestChar=%d)\n", CodePage, TestChar);
+
+ /* Get the lead byte info with respect to the given codepage*/
+ if( !GetCPInfo( CodePage, &cpinfo ) )
+ {
+ ERROR("Error CodePage(%#x) parameter is invalid\n", CodePage );
+ SetLastError( ERROR_INVALID_PARAMETER );
+ goto done;
+ }
+
+ for( i=0; i < sizeof(cpinfo.LeadByte)/sizeof(cpinfo.LeadByte[0]); i += 2 )
+ {
+ if( 0 == cpinfo.LeadByte[ i ] )
+ {
+ goto done;
+ }
+
+ /*check if the given char is in one of the lead byte ranges*/
+ if( cpinfo.LeadByte[i] <= TestChar && TestChar<= cpinfo.LeadByte[i+1] )
+ {
+ bRet = TRUE;
+ goto done;
+ }
+ }
+done:
+ LOGEXIT("IsDBCSLeadByteEx returns BOOL %d\n",bRet);
+ PERF_EXIT(IsDBCSLeadByteEx);
+ return bRet;
+}
+
+/*++
+Function:
+IsDBCSLeadByte
+
+See MSDN doc.
+--*/
+BOOL
+PALAPI
+IsDBCSLeadByte(
+ IN BYTE TestChar)
+{
+ // UNIXTODO: Implement this!
+ ERROR("Needs Implementation!!!");
+ return FALSE;
+}
+
+/*++
+Function:
+MultiByteToWideChar
+
+See MSDN doc.
+
+--*/
+int
+PALAPI
+MultiByteToWideChar(
+ IN UINT CodePage,
+ IN DWORD dwFlags,
+ IN LPCSTR lpMultiByteStr,
+ IN int cbMultiByte,
+ OUT LPWSTR lpWideCharStr,
+ IN int cchWideChar)
+{
+ INT retval =0;
+#if HAVE_COREFOUNDATION
+ CFStringRef cfString = NULL;
+ CFStringEncoding cfEncoding;
+ int bytesToConvert;
+#endif /* HAVE_COREFOUNDATION */
+
+ PERF_ENTRY(MultiByteToWideChar);
+ ENTRY("MultiByteToWideChar(CodePage=%u, dwFlags=%#x, lpMultiByteStr=%p (%s),"
+ " cbMultiByte=%d, lpWideCharStr=%p, cchWideChar=%d)\n",
+ CodePage, dwFlags, lpMultiByteStr?lpMultiByteStr:"NULL", lpMultiByteStr?lpMultiByteStr:"NULL",
+ cbMultiByte, lpWideCharStr, cchWideChar);
+
+ if (dwFlags & ~(MB_ERR_INVALID_CHARS | MB_PRECOMPOSED))
+ {
+ ASSERT("Error dwFlags(0x%x) parameter is invalid\n", dwFlags);
+ SetLastError(ERROR_INVALID_FLAGS);
+ goto EXIT;
+ }
+
+ if ( (cbMultiByte == 0) || (cchWideChar < 0) ||
+ (lpMultiByteStr == NULL) ||
+ ((cchWideChar != 0) &&
+ ((lpWideCharStr == NULL) ||
+ (lpMultiByteStr == (LPSTR)lpWideCharStr))) )
+ {
+ ERROR("Error lpMultiByteStr parameters are invalid\n");
+ SetLastError(ERROR_INVALID_PARAMETER);
+ goto EXIT;
+ }
+
+ // Use UTF8ToUnicode on all systems, since it replaces
+ // invalid characters and Core Foundation doesn't do that.
+ if (CodePage == CP_UTF8 || (CodePage == CP_ACP && GetACP() == CP_UTF8))
+ {
+ if (cbMultiByte <= -1)
+ {
+ cbMultiByte = strlen(lpMultiByteStr) + 1;
+ }
+
+ retval = UTF8ToUnicode(lpMultiByteStr, cbMultiByte, lpWideCharStr, cchWideChar, dwFlags);
+ goto EXIT;
+ }
+
+#if !HAVE_COREFOUNDATION
+ ERROR( "This code page is not in the system.\n" );
+ SetLastError( ERROR_INVALID_PARAMETER );
+ goto EXIT;
+#else /* !HAVE_COREFOUNDATION */
+ bytesToConvert = cbMultiByte;
+ if (bytesToConvert == -1)
+ {
+ /* Plus one for the trailing '\0', which will end up
+ * in the CFString. */
+ bytesToConvert = strlen(lpMultiByteStr) + 1;
+ }
+
+ cfEncoding = CODEPAGECPToCFStringEncoding(CodePage);
+ if (cfEncoding == kCFStringEncodingInvalidId)
+ {
+ ERROR( "This code page is not in the system.\n" );
+ SetLastError( ERROR_INVALID_PARAMETER );
+ goto EXIT;
+ }
+
+ cfString = CFStringCreateWithBytes(kCFAllocatorDefault, (UInt8*)lpMultiByteStr,
+ bytesToConvert, cfEncoding, TRUE);
+ if (cfString == NULL)
+ {
+ ERROR( "Failed to convert the string to the specified encoding.\n" );
+ SetLastError( ERROR_NO_UNICODE_TRANSLATION );
+ goto EXIT;
+ }
+
+ if (cchWideChar != 0)
+ {
+ /* Do the conversion. */
+ CFIndex length = CFStringGetLength(cfString);
+ if (length > cchWideChar)
+ {
+ ERROR("Error insufficient buffer\n");
+ SetLastError(ERROR_INSUFFICIENT_BUFFER);
+ retval = 0;
+ goto ReleaseString;
+ }
+ CFStringGetCharacters(cfString, CFRangeMake(0, length),
+ (UniChar*)lpWideCharStr);
+ retval = length;
+ }
+ else
+ {
+ /* Just return the number of wide characters needed. */
+ retval = CFStringGetLength(cfString);
+ }
+
+ReleaseString:
+ if (cfString != NULL)
+ {
+ CFRelease(cfString);
+ }
+#endif /* !HAVE_COREFOUNDATION */
+
+EXIT:
+
+ LOGEXIT("MultiByteToWideChar returns %d.\n",retval);
+ PERF_EXIT(MultiByteToWideChar);
+ return retval;
+}
+
+
+/*++
+Function:
+WideCharToMultiByte
+
+See MSDN doc.
+
+--*/
+int
+PALAPI
+WideCharToMultiByte(
+ IN UINT CodePage,
+ IN DWORD dwFlags,
+ IN LPCWSTR lpWideCharStr,
+ IN int cchWideChar,
+ OUT LPSTR lpMultiByteStr,
+ IN int cbMultiByte,
+ IN LPCSTR lpDefaultChar,
+ OUT LPBOOL lpUsedDefaultChar)
+{
+ INT retval =0;
+ char defaultChar = '?';
+ BOOL usedDefaultChar = FALSE;
+#if HAVE_COREFOUNDATION
+ CFStringRef cfString = NULL;
+ CFStringEncoding cfEncoding;
+ int charsToConvert;
+ CFIndex charsConverted;
+ CFIndex bytesConverted;
+#endif /* !HAVE_COREFOUNDATION */
+
+ PERF_ENTRY(WideCharToMultiByte);
+ ENTRY("WideCharToMultiByte(CodePage=%u, dwFlags=%#x, lpWideCharStr=%p (%S), "
+ "cchWideChar=%d, lpMultiByteStr=%p, cbMultiByte=%d, "
+ "lpDefaultChar=%p, lpUsedDefaultChar=%p)\n",
+ CodePage, dwFlags, lpWideCharStr?lpWideCharStr:W16_NULLSTRING, lpWideCharStr?lpWideCharStr:W16_NULLSTRING,
+ cchWideChar, lpMultiByteStr, cbMultiByte,
+ lpDefaultChar, lpUsedDefaultChar);
+
+ if (dwFlags & ~WC_NO_BEST_FIT_CHARS)
+ {
+ ERROR("dwFlags %d invalid\n", dwFlags);
+ SetLastError(ERROR_INVALID_FLAGS);
+ goto EXIT;
+ }
+
+ // No special action is needed for WC_NO_BEST_FIT_CHARS. The default
+ // behavior of this API on Unix is not to find the best fit for a unicode
+ // character that does not map directly into a code point in the given
+ // code page. The best fit functionality is not available in wctomb on Unix
+ // and is better left unimplemented for security reasons anyway.
+
+ if ((cchWideChar < -1) || (cbMultiByte < 0) ||
+ (lpWideCharStr == NULL) ||
+ ((cbMultiByte != 0) &&
+ ((lpMultiByteStr == NULL) ||
+ (lpWideCharStr == (LPWSTR)lpMultiByteStr))) )
+ {
+ ERROR("Error lpWideCharStr parameters are invalid\n");
+ SetLastError(ERROR_INVALID_PARAMETER);
+ goto EXIT;
+ }
+
+ if (lpDefaultChar != NULL)
+ {
+ defaultChar = *lpDefaultChar;
+ }
+
+ // Use UnicodeToUTF8 on all systems because we use
+ // UTF8ToUnicode in MultiByteToWideChar() on all systems.
+ if (CodePage == CP_UTF8 || (CodePage == CP_ACP && GetACP() == CP_UTF8))
+ {
+ if (cchWideChar == -1)
+ {
+ cchWideChar = PAL_wcslen(lpWideCharStr) + 1;
+ }
+ retval = UnicodeToUTF8(lpWideCharStr, cchWideChar, lpMultiByteStr, cbMultiByte);
+ goto EXIT;
+ }
+
+#if HAVE_COREFOUNDATION
+ charsToConvert = cchWideChar;
+ if (charsToConvert == -1)
+ {
+ LPCWSTR ptr = lpWideCharStr;
+
+ charsToConvert = 0;
+ while(*ptr++ != 0)
+ {
+ charsToConvert++;
+ }
+ charsToConvert++; /* For the terminating '\0' */
+ }
+
+ cfEncoding = CODEPAGECPToCFStringEncoding(CodePage);
+ if (cfEncoding == kCFStringEncodingInvalidId)
+ {
+ ERROR( "This code page is not in the system.\n" );
+ SetLastError(ERROR_INVALID_PARAMETER);
+ goto EXIT;
+ }
+
+ cfString = CFStringCreateWithCharacters(kCFAllocatorDefault,
+ (const UniChar*)lpWideCharStr, charsToConvert);
+ if (cfString == NULL)
+ {
+ ERROR("CFString creation failed.\n");
+ SetLastError(ERROR_INVALID_PARAMETER);
+ goto EXIT;
+ }
+
+ if (cbMultiByte == 0)
+ {
+ lpMultiByteStr = NULL;
+ }
+ charsConverted = CFStringGetBytes(cfString,
+ CFRangeMake(0, charsToConvert),
+ cfEncoding, '?', TRUE, (UInt8*)lpMultiByteStr,
+ cbMultiByte, &bytesConverted);
+ if (charsConverted != charsToConvert)
+ {
+ if (lpMultiByteStr != NULL)
+ {
+ // CFStringGetBytes can fail due to an insufficient buffer or for
+ // other reasons. We need to check if we're out of buffer space.
+ charsConverted = CFStringGetBytes(cfString,
+ CFRangeMake(0, charsToConvert),
+ cfEncoding, '?', TRUE, NULL,
+ 0, &bytesConverted);
+ if (cbMultiByte < bytesConverted)
+ {
+ ERROR("Insufficient buffer for CFStringGetBytes.\n");
+ SetLastError(ERROR_INSUFFICIENT_BUFFER);
+ goto ReleaseString;
+ }
+ }
+ ERROR("Not all characters were converted.\n");
+ SetLastError(ERROR_INVALID_PARAMETER);
+ goto ReleaseString;
+ }
+ retval = bytesConverted;
+
+ReleaseString:
+ if (cfString != NULL)
+ {
+ CFRelease(cfString);
+ }
+#else /*HAVE_COREFOUNDATION */
+ ERROR( "This code page is not in the system.\n" );
+ SetLastError( ERROR_INVALID_PARAMETER );
+ goto EXIT;
+#endif /* HAVE_COREFOUNDATION */
+
+EXIT:
+
+ if ( lpUsedDefaultChar != NULL )
+ {
+ *lpUsedDefaultChar = usedDefaultChar;
+ }
+
+ /* Flag the cases when WC_NO_BEST_FIT_CHARS was not specified
+ * but we found characters that had to be replaced with default
+ * characters. Note that Windows would have attempted to find
+ * best fit characters under these conditions and that could pose
+ * a security risk.
+ */
+ _ASSERT_MSG((dwFlags & WC_NO_BEST_FIT_CHARS) || !usedDefaultChar,
+ "WideCharToMultiByte found a string which doesn't round trip: (%p)%S "
+ "and WC_NO_BEST_FIT_CHARS was not specified\n",
+ lpWideCharStr, lpWideCharStr);
+
+ LOGEXIT("WideCharToMultiByte returns INT %d\n", retval);
+ PERF_EXIT(WideCharToMultiByte);
+ return retval;
+}
+
+extern char * g_szCoreCLRPath;
+
+/*++
+Function :
+
+PAL_BindResources - bind the resource domain to the path where the coreclr resides
+
+Returns TRUE if it succeeded, FALSE if it failed due to OOM
+--*/
+BOOL
+PALAPI
+PAL_BindResources(IN LPCSTR lpDomain)
+{
+#ifndef __APPLE__
+ _ASSERTE(g_szCoreCLRPath != NULL);
+ char * coreCLRDirectoryPath;
+ PathCharString coreCLRDirectoryPathPS;
+ int len = strlen(g_szCoreCLRPath);
+ coreCLRDirectoryPath = coreCLRDirectoryPathPS.OpenStringBuffer(len);
+ if (NULL == coreCLRDirectoryPath)
+ {
+ return FALSE;
+ }
+ DWORD size = FILEGetDirectoryFromFullPathA(g_szCoreCLRPath, len, coreCLRDirectoryPath);
+ coreCLRDirectoryPathPS.CloseBuffer(size);
+
+ LPCSTR boundPath = bindtextdomain(lpDomain, coreCLRDirectoryPath);
+
+ return boundPath != NULL;
+#else // __APPLE__
+ // UNIXTODO: Implement for OSX if necessary
+ return TRUE;
+#endif // __APPLE__
+}
+
+/*++
+Function :
+
+PAL_GetResourceString - get localized string for a specified resource.
+The string that is passed in should be the English string, since it
+will be returned if an appropriately localized version is not found.
+
+Returns number of characters retrieved, 0 if it failed.
+--*/
+int
+PALAPI
+PAL_GetResourceString(
+ IN LPCSTR lpDomain,
+ IN LPCSTR lpResourceStr,
+ OUT LPWSTR lpWideCharStr,
+ IN int cchWideChar
+ )
+{
+#ifndef __APPLE__
+ // NOTE: dgettext returns the key if it fails to locate the appropriate
+ // resource. In our case, that will be the English string.
+ LPCSTR resourceString = dgettext(lpDomain, lpResourceStr);
+#else // __APPLE__
+ // UNIXTODO: Implement for OSX using the native localization API
+
+ // This is a temporary solution until we add the real native resource support.
+ LPCSTR resourceString = lpResourceStr;
+#endif // __APPLE__
+
+ int length = strlen(resourceString);
+ return UTF8ToUnicode(lpResourceStr, length + 1, lpWideCharStr, cchWideChar, 0);
+}
diff --git a/src/pal/src/locale/unicode_data.cpp b/src/pal/src/locale/unicode_data.cpp
new file mode 100644
index 0000000000..f9ba166f11
--- /dev/null
+++ b/src/pal/src/locale/unicode_data.cpp
@@ -0,0 +1,1852 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ locale/unicode_data.c
+
+Abstract:
+
+ Data definitions.
+
+
+
+--*/
+
+#include "pal/unicode_data.h"
+
+#if !HAVE_COREFOUNDATION
+
+CONST UnicodeDataRec UnicodeData[] = {
+
+
+{ 0x0000, 0x0020, 0x0000, 0 },
+{ 0x0001, 0x0020, 0x0000, 0 },
+{ 0x0002, 0x0020, 0x0000, 0 },
+{ 0x0003, 0x0020, 0x0000, 0 },
+{ 0x0004, 0x0020, 0x0000, 0 },
+{ 0x0005, 0x0020, 0x0000, 0 },
+{ 0x0006, 0x0020, 0x0000, 0 },
+{ 0x0007, 0x0020, 0x0000, 0 },
+{ 0x0008, 0x0020, 0x0000, 0 },
+{ 0x0009, 0x0068, 0x0000, 0 },
+{ 0x000a, 0x0028, 0x0000, 0 },
+{ 0x000b, 0x0028, 0x0000, 0 },
+{ 0x000c, 0x0028, 0x0000, 0 },
+{ 0x000d, 0x0028, 0x0000, 0 },
+{ 0x000e, 0x0020, 0x0000, 0 },
+{ 0x000f, 0x0020, 0x0000, 0 },
+{ 0x0010, 0x0020, 0x0000, 0 },
+{ 0x0011, 0x0020, 0x0000, 0 },
+{ 0x0012, 0x0020, 0x0000, 0 },
+{ 0x0013, 0x0020, 0x0000, 0 },
+{ 0x0014, 0x0020, 0x0000, 0 },
+{ 0x0015, 0x0020, 0x0000, 0 },
+{ 0x0016, 0x0020, 0x0000, 0 },
+{ 0x0017, 0x0020, 0x0000, 0 },
+{ 0x0018, 0x0020, 0x0000, 0 },
+{ 0x0019, 0x0020, 0x0000, 0 },
+{ 0x001a, 0x0020, 0x0000, 0 },
+{ 0x001b, 0x0020, 0x0000, 0 },
+{ 0x001c, 0x0020, 0x0000, 0 },
+{ 0x001d, 0x0020, 0x0000, 0 },
+{ 0x001e, 0x0020, 0x0000, 0 },
+{ 0x001f, 0x0020, 0x0000, 0 },
+{ 0x0020, 0x0048, 0x0000, 0 },
+{ 0x0021, 0x0010, 0x0000, 0 },
+{ 0x0022, 0x0010, 0x0000, 0 },
+{ 0x0023, 0x0010, 0x0000, 0 },
+{ 0x0024, 0x0010, 0x0000, 0 },
+{ 0x0025, 0x0010, 0x0000, 0 },
+{ 0x0026, 0x0010, 0x0000, 0 },
+{ 0x0027, 0x0010, 0x0000, 0 },
+{ 0x0028, 0x0010, 0x0000, 0 },
+{ 0x0029, 0x0010, 0x0000, 0 },
+{ 0x002a, 0x0010, 0x0000, 0 },
+{ 0x002b, 0x0010, 0x0000, 0 },
+{ 0x002c, 0x0010, 0x0000, 0 },
+{ 0x002d, 0x0010, 0x0000, 0 },
+{ 0x002e, 0x0010, 0x0000, 0 },
+{ 0x002f, 0x0010, 0x0000, 0 },
+{ 0x0030, 0x0084, 0x0000, 0 },
+{ 0x0031, 0x0084, 0x0000, 0 },
+{ 0x0032, 0x0084, 0x0000, 0 },
+{ 0x0033, 0x0084, 0x0000, 0 },
+{ 0x0034, 0x0084, 0x0000, 0 },
+{ 0x0035, 0x0084, 0x0000, 0 },
+{ 0x0036, 0x0084, 0x0000, 0 },
+{ 0x0037, 0x0084, 0x0000, 0 },
+{ 0x0038, 0x0084, 0x0000, 0 },
+{ 0x0039, 0x0084, 0x0000, 0 },
+{ 0x003a, 0x0010, 0x0000, 0 },
+{ 0x003b, 0x0010, 0x0000, 0 },
+{ 0x003c, 0x0010, 0x0000, 0 },
+{ 0x003d, 0x0010, 0x0000, 0 },
+{ 0x003e, 0x0010, 0x0000, 0 },
+{ 0x003f, 0x0010, 0x0000, 0 },
+{ 0x0040, 0x0010, 0x0000, 0 },
+{ 0x0041, 0x0181, 0x0061, 0 },
+{ 0x0042, 0x0181, 0x0062, 0 },
+{ 0x0043, 0x0181, 0x0063, 0 },
+{ 0x0044, 0x0181, 0x0064, 0 },
+{ 0x0045, 0x0181, 0x0065, 0 },
+{ 0x0046, 0x0181, 0x0066, 0 },
+{ 0x0047, 0x0101, 0x0067, 0 },
+{ 0x0048, 0x0101, 0x0068, 0 },
+{ 0x0049, 0x0101, 0x0069, 0 },
+{ 0x004a, 0x0101, 0x006a, 0 },
+{ 0x004b, 0x0101, 0x006b, 0 },
+{ 0x004c, 0x0101, 0x006c, 0 },
+{ 0x004d, 0x0101, 0x006d, 0 },
+{ 0x004e, 0x0101, 0x006e, 0 },
+{ 0x004f, 0x0101, 0x006f, 0 },
+{ 0x0050, 0x0101, 0x0070, 0 },
+{ 0x0051, 0x0101, 0x0071, 0 },
+{ 0x0052, 0x0101, 0x0072, 0 },
+{ 0x0053, 0x0101, 0x0073, 0 },
+{ 0x0054, 0x0101, 0x0074, 0 },
+{ 0x0055, 0x0101, 0x0075, 0 },
+{ 0x0056, 0x0101, 0x0076, 0 },
+{ 0x0057, 0x0101, 0x0077, 0 },
+{ 0x0058, 0x0101, 0x0078, 0 },
+{ 0x0059, 0x0101, 0x0079, 0 },
+{ 0x005a, 0x0101, 0x007a, 0 },
+{ 0x005b, 0x0010, 0x0000, 0 },
+{ 0x005c, 0x0010, 0x0000, 0 },
+{ 0x005d, 0x0010, 0x0000, 0 },
+{ 0x005e, 0x0010, 0x0000, 0 },
+{ 0x005f, 0x0010, 0x0000, 0 },
+{ 0x0060, 0x0010, 0x0000, 0 },
+{ 0x0061, 0x0182, 0x0041, 0 },
+{ 0x0062, 0x0182, 0x0042, 0 },
+{ 0x0063, 0x0182, 0x0043, 0 },
+{ 0x0064, 0x0182, 0x0044, 0 },
+{ 0x0065, 0x0182, 0x0045, 0 },
+{ 0x0066, 0x0182, 0x0046, 0 },
+{ 0x0067, 0x0102, 0x0047, 0 },
+{ 0x0068, 0x0102, 0x0048, 0 },
+{ 0x0069, 0x0102, 0x0049, 0 },
+{ 0x006a, 0x0102, 0x004a, 0 },
+{ 0x006b, 0x0102, 0x004b, 0 },
+{ 0x006c, 0x0102, 0x004c, 0 },
+{ 0x006d, 0x0102, 0x004d, 0 },
+{ 0x006e, 0x0102, 0x004e, 0 },
+{ 0x006f, 0x0102, 0x004f, 0 },
+{ 0x0070, 0x0102, 0x0050, 0 },
+{ 0x0071, 0x0102, 0x0051, 0 },
+{ 0x0072, 0x0102, 0x0052, 0 },
+{ 0x0073, 0x0102, 0x0053, 0 },
+{ 0x0074, 0x0102, 0x0054, 0 },
+{ 0x0075, 0x0102, 0x0055, 0 },
+{ 0x0076, 0x0102, 0x0056, 0 },
+{ 0x0077, 0x0102, 0x0057, 0 },
+{ 0x0078, 0x0102, 0x0058, 0 },
+{ 0x0079, 0x0102, 0x0059, 0 },
+{ 0x007a, 0x0102, 0x005a, 0 },
+{ 0x007b, 0x0010, 0x0000, 0 },
+{ 0x007c, 0x0010, 0x0000, 0 },
+{ 0x007d, 0x0010, 0x0000, 0 },
+{ 0x007e, 0x0010, 0x0000, 0 },
+{ 0x007f, 0x0020, 0x0000, 0 },
+{ 0x0080, 0x0020, 0x0000, 0 },
+{ 0x0081, 0x0020, 0x0000, 0 },
+{ 0x0082, 0x0020, 0x0000, 0 },
+{ 0x0083, 0x0020, 0x0000, 0 },
+{ 0x0084, 0x0020, 0x0000, 0 },
+{ 0x0085, 0x0020, 0x0000, 0 },
+{ 0x0086, 0x0020, 0x0000, 0 },
+{ 0x0087, 0x0020, 0x0000, 0 },
+{ 0x0088, 0x0020, 0x0000, 0 },
+{ 0x0089, 0x0020, 0x0000, 0 },
+{ 0x008a, 0x0020, 0x0000, 0 },
+{ 0x008b, 0x0020, 0x0000, 0 },
+{ 0x008c, 0x0020, 0x0000, 0 },
+{ 0x008d, 0x0020, 0x0000, 0 },
+{ 0x008e, 0x0020, 0x0000, 0 },
+{ 0x008f, 0x0020, 0x0000, 0 },
+{ 0x0090, 0x0020, 0x0000, 0 },
+{ 0x0091, 0x0020, 0x0000, 0 },
+{ 0x0092, 0x0020, 0x0000, 0 },
+{ 0x0093, 0x0020, 0x0000, 0 },
+{ 0x0094, 0x0020, 0x0000, 0 },
+{ 0x0095, 0x0020, 0x0000, 0 },
+{ 0x0096, 0x0020, 0x0000, 0 },
+{ 0x0097, 0x0020, 0x0000, 0 },
+{ 0x0098, 0x0020, 0x0000, 0 },
+{ 0x0099, 0x0020, 0x0000, 0 },
+{ 0x009a, 0x0020, 0x0000, 0 },
+{ 0x009b, 0x0020, 0x0000, 0 },
+{ 0x009c, 0x0020, 0x0000, 0 },
+{ 0x009d, 0x0020, 0x0000, 0 },
+{ 0x009e, 0x0020, 0x0000, 0 },
+{ 0x009f, 0x0020, 0x0000, 0 },
+{ 0x00a0, 0x0048, 0x0000, 0 },
+{ 0x00a1, 0x0010, 0x0000, 0 },
+{ 0x00a2, 0x0010, 0x0000, 0 },
+{ 0x00a3, 0x0010, 0x0000, 0 },
+{ 0x00a4, 0x0010, 0x0000, 0 },
+{ 0x00a5, 0x0010, 0x0000, 0 },
+{ 0x00a6, 0x0010, 0x0000, 0 },
+{ 0x00a7, 0x0010, 0x0000, 0 },
+{ 0x00a8, 0x0010, 0x0000, 0 },
+{ 0x00a9, 0x0010, 0x0000, 0 },
+{ 0x00aa, 0x0010, 0x0000, 0 },
+{ 0x00ab, 0x0010, 0x0000, 0 },
+{ 0x00ac, 0x0010, 0x0000, 0 },
+{ 0x00ad, 0x0010, 0x0000, 0 },
+{ 0x00ae, 0x0010, 0x0000, 0 },
+{ 0x00af, 0x0010, 0x0000, 0 },
+{ 0x00b0, 0x0010, 0x0000, 0 },
+{ 0x00b1, 0x0010, 0x0000, 0 },
+{ 0x00b2, 0x0014, 0x0000, 0 },
+{ 0x00b3, 0x0014, 0x0000, 0 },
+{ 0x00b4, 0x0010, 0x0000, 0 },
+{ 0x00b5, 0x0010, 0x0000, 0 },
+{ 0x00b6, 0x0010, 0x0000, 0 },
+{ 0x00b7, 0x0010, 0x0000, 0 },
+{ 0x00b8, 0x0010, 0x0000, 0 },
+{ 0x00b9, 0x0014, 0x0000, 0 },
+{ 0x00ba, 0x0010, 0x0000, 0 },
+{ 0x00bb, 0x0010, 0x0000, 0 },
+{ 0x00bc, 0x0010, 0x0000, 0 },
+{ 0x00bd, 0x0010, 0x0000, 0 },
+{ 0x00be, 0x0010, 0x0000, 0 },
+{ 0x00bf, 0x0010, 0x0000, 0 },
+{ 0x00c0, 0x0101, 0x0000, 0 },
+{ 0x00c1, 0x0101, 0x0000, 0 },
+{ 0x00c2, 0x0101, 0x0000, 0 },
+{ 0x00c3, 0x0101, 0x0000, 0 },
+{ 0x00c4, 0x0101, 0x0000, 0 },
+{ 0x00c5, 0x0101, 0x0000, 0 },
+{ 0x00c6, 0x0101, 0x0000, 0 },
+{ 0x00c7, 0x0101, 0x0000, 0 },
+{ 0x00c8, 0x0101, 0x0000, 0 },
+{ 0x00c9, 0x0101, 0x0000, 0 },
+{ 0x00ca, 0x0101, 0x0000, 0 },
+{ 0x00cb, 0x0101, 0x0000, 0 },
+{ 0x00cc, 0x0101, 0x0000, 0 },
+{ 0x00cd, 0x0101, 0x0000, 0 },
+{ 0x00ce, 0x0101, 0x0000, 0 },
+{ 0x00cf, 0x0101, 0x0000, 0 },
+{ 0x00d0, 0x0101, 0x0000, 0 },
+{ 0x00d1, 0x0101, 0x0000, 0 },
+{ 0x00d2, 0x0101, 0x0000, 0 },
+{ 0x00d3, 0x0101, 0x0000, 0 },
+{ 0x00d4, 0x0101, 0x0000, 0 },
+{ 0x00d5, 0x0101, 0x0000, 0 },
+{ 0x00d6, 0x0101, 0x0000, 0 },
+{ 0x00d7, 0x0010, 0x0000, 0 },
+{ 0x00d8, 0x0101, 0x0000, 0 },
+{ 0x00d9, 0x0101, 0x0000, 0 },
+{ 0x00da, 0x0101, 0x0000, 0 },
+{ 0x00db, 0x0101, 0x0000, 0 },
+{ 0x00dc, 0x0101, 0x0000, 0 },
+{ 0x00dd, 0x0101, 0x0000, 0 },
+{ 0x00de, 0x0101, 0x0000, 0 },
+{ 0x00df, 0x0102, 0x0000, 0 },
+{ 0x00e0, 0x0102, 0x0000, 0 },
+{ 0x00e1, 0x0102, 0x0000, 0 },
+{ 0x00e2, 0x0102, 0x0000, 0 },
+{ 0x00e3, 0x0102, 0x0000, 0 },
+{ 0x00e4, 0x0102, 0x0000, 0 },
+{ 0x00e5, 0x0102, 0x0000, 0 },
+{ 0x00e6, 0x0102, 0x0000, 0 },
+{ 0x00e7, 0x0102, 0x0000, 0 },
+{ 0x00e8, 0x0102, 0x0000, 0 },
+{ 0x00e9, 0x0102, 0x0000, 0 },
+{ 0x00ea, 0x0102, 0x0000, 0 },
+{ 0x00eb, 0x0102, 0x0000, 0 },
+{ 0x00ec, 0x0102, 0x0000, 0 },
+{ 0x00ed, 0x0102, 0x0000, 0 },
+{ 0x00ee, 0x0102, 0x0000, 0 },
+{ 0x00ef, 0x0102, 0x0000, 0 },
+{ 0x00f0, 0x0102, 0x0000, 0 },
+{ 0x00f1, 0x0102, 0x0000, 0 },
+{ 0x00f2, 0x0102, 0x0000, 0 },
+{ 0x00f3, 0x0102, 0x0000, 0 },
+{ 0x00f4, 0x0102, 0x0000, 0 },
+{ 0x00f5, 0x0102, 0x0000, 0 },
+{ 0x00f6, 0x0102, 0x0000, 0 },
+{ 0x00f7, 0x0010, 0x0000, 0 },
+{ 0x00f8, 0x0102, 0x0000, 0 },
+{ 0x00f9, 0x0102, 0x0000, 0 },
+{ 0x00fa, 0x0102, 0x0000, 0 },
+{ 0x00fb, 0x0102, 0x0000, 0 },
+{ 0x00fc, 0x0102, 0x0000, 0 },
+{ 0x00fd, 0x0102, 0x0000, 0 },
+{ 0x00fe, 0x0102, 0x0000, 0 },
+{ 0x00ff, 0x0102, 0x0000, 0 },
+{ 0x0100, 0x0101, 0x0100, 0 },
+{ 0x0101, 0x0102, 0x0101, 0 },
+{ 0x0102, 0x0101, 0x0102, 0 },
+{ 0x0103, 0x0102, 0x0103, 0 },
+{ 0x0104, 0x0101, 0x0104, 0 },
+{ 0x0105, 0x0102, 0x0105, 0 },
+{ 0x0106, 0x0101, 0x0106, 0 },
+{ 0x0107, 0x0102, 0x0107, 0 },
+{ 0x0108, 0x0101, 0x0108, 0 },
+{ 0x0109, 0x0102, 0x0109, 0 },
+{ 0x010a, 0x0101, 0x010a, 0 },
+{ 0x010b, 0x0102, 0x010b, 0 },
+{ 0x010c, 0x0101, 0x010c, 0 },
+{ 0x010d, 0x0102, 0x010d, 0 },
+{ 0x010e, 0x0101, 0x010e, 0 },
+{ 0x010f, 0x0102, 0x010f, 0 },
+{ 0x0110, 0x0101, 0x0110, 0 },
+{ 0x0111, 0x0102, 0x0111, 0 },
+{ 0x0112, 0x0101, 0x0112, 0 },
+{ 0x0113, 0x0102, 0x0113, 0 },
+{ 0x0114, 0x0101, 0x0114, 0 },
+{ 0x0115, 0x0102, 0x0115, 0 },
+{ 0x0116, 0x0101, 0x0116, 0 },
+{ 0x0117, 0x0102, 0x0117, 0 },
+{ 0x0118, 0x0101, 0x0118, 0 },
+{ 0x0119, 0x0102, 0x0119, 0 },
+{ 0x011a, 0x0101, 0x011a, 0 },
+{ 0x011b, 0x0102, 0x011b, 0 },
+{ 0x011c, 0x0101, 0x011c, 0 },
+{ 0x011d, 0x0102, 0x011d, 0 },
+{ 0x011e, 0x0101, 0x011e, 0 },
+{ 0x011f, 0x0102, 0x011f, 0 },
+{ 0x0120, 0x0101, 0x0120, 0 },
+{ 0x0121, 0x0102, 0x0121, 0 },
+{ 0x0122, 0x0101, 0x0122, 0 },
+{ 0x0123, 0x0102, 0x0123, 0 },
+{ 0x0124, 0x0101, 0x0124, 0 },
+{ 0x0125, 0x0102, 0x0125, 0 },
+{ 0x0126, 0x0101, 0x0126, 0 },
+{ 0x0127, 0x0102, 0x0127, 0 },
+{ 0x0128, 0x0101, 0x0128, 0 },
+{ 0x0129, 0x0102, 0x0129, 0 },
+{ 0x012a, 0x0101, 0x012a, 0 },
+{ 0x012b, 0x0102, 0x012b, 0 },
+{ 0x012c, 0x0101, 0x012c, 0 },
+{ 0x012d, 0x0102, 0x012d, 0 },
+{ 0x012e, 0x0101, 0x012e, 0 },
+{ 0x012f, 0x0102, 0x012f, 0 },
+{ 0x0130, 0x0101, 0x0130, 0 },
+{ 0x0131, 0x0102, 0x0131, 0 },
+{ 0x0132, 0x0101, 0x0132, 0 },
+{ 0x0133, 0x0102, 0x0133, 0 },
+{ 0x0134, 0x0101, 0x0134, 0 },
+{ 0x0135, 0x0102, 0x0135, 0 },
+{ 0x0136, 0x0101, 0x0136, 0 },
+{ 0x0137, 0x0102, 0x0137, 0 },
+{ 0x0138, 0x0102, 0x0138, 0 },
+{ 0x0139, 0x0101, 0x0139, 0 },
+{ 0x013a, 0x0102, 0x013a, 0 },
+{ 0x013b, 0x0101, 0x013b, 0 },
+{ 0x013c, 0x0102, 0x013c, 0 },
+{ 0x013d, 0x0101, 0x013d, 0 },
+{ 0x013e, 0x0102, 0x013e, 0 },
+{ 0x013f, 0x0101, 0x013f, 0 },
+{ 0x0140, 0x0102, 0x0140, 0 },
+{ 0x0141, 0x0101, 0x0141, 0 },
+{ 0x0142, 0x0102, 0x0142, 0 },
+{ 0x0143, 0x0101, 0x0143, 0 },
+{ 0x0144, 0x0102, 0x0144, 0 },
+{ 0x0145, 0x0101, 0x0145, 0 },
+{ 0x0146, 0x0102, 0x0146, 0 },
+{ 0x0147, 0x0101, 0x0147, 0 },
+{ 0x0148, 0x0102, 0x0148, 0 },
+{ 0x0149, 0x0102, 0x0149, 0 },
+{ 0x014a, 0x0101, 0x014a, 0 },
+{ 0x014b, 0x0102, 0x014b, 0 },
+{ 0x014c, 0x0101, 0x014c, 0 },
+{ 0x014d, 0x0102, 0x014d, 0 },
+{ 0x014e, 0x0101, 0x014e, 0 },
+{ 0x014f, 0x0102, 0x014f, 0 },
+{ 0x0150, 0x0101, 0x0150, 0 },
+{ 0x0151, 0x0102, 0x0151, 0 },
+{ 0x0152, 0x0101, 0x0152, 0 },
+{ 0x0153, 0x0102, 0x0153, 0 },
+{ 0x0154, 0x0101, 0x0154, 0 },
+{ 0x0155, 0x0102, 0x0155, 0 },
+{ 0x0156, 0x0101, 0x0156, 0 },
+{ 0x0157, 0x0102, 0x0157, 0 },
+{ 0x0158, 0x0101, 0x0158, 0 },
+{ 0x0159, 0x0102, 0x0159, 0 },
+{ 0x015a, 0x0101, 0x015a, 0 },
+{ 0x015b, 0x0102, 0x015b, 0 },
+{ 0x015c, 0x0101, 0x015c, 0 },
+{ 0x015d, 0x0102, 0x015d, 0 },
+{ 0x015e, 0x0101, 0x015e, 0 },
+{ 0x015f, 0x0102, 0x015f, 0 },
+{ 0x0160, 0x0101, 0x0160, 0 },
+{ 0x0161, 0x0102, 0x0161, 0 },
+{ 0x0162, 0x0101, 0x0162, 0 },
+{ 0x0163, 0x0102, 0x0163, 0 },
+{ 0x0164, 0x0101, 0x0164, 0 },
+{ 0x0165, 0x0102, 0x0165, 0 },
+{ 0x0166, 0x0101, 0x0166, 0 },
+{ 0x0167, 0x0102, 0x0167, 0 },
+{ 0x0168, 0x0101, 0x0168, 0 },
+{ 0x0169, 0x0102, 0x0169, 0 },
+{ 0x016a, 0x0101, 0x016a, 0 },
+{ 0x016b, 0x0102, 0x016b, 0 },
+{ 0x016c, 0x0101, 0x016c, 0 },
+{ 0x016d, 0x0102, 0x016d, 0 },
+{ 0x016e, 0x0101, 0x016e, 0 },
+{ 0x016f, 0x0102, 0x016f, 0 },
+{ 0x0170, 0x0101, 0x0170, 0 },
+{ 0x0171, 0x0102, 0x0171, 0 },
+{ 0x0172, 0x0101, 0x0172, 0 },
+{ 0x0173, 0x0102, 0x0173, 0 },
+{ 0x0174, 0x0101, 0x0174, 0 },
+{ 0x0175, 0x0102, 0x0175, 0 },
+{ 0x0176, 0x0101, 0x0176, 0 },
+{ 0x0177, 0x0102, 0x0177, 0 },
+{ 0x0178, 0x0101, 0x0178, 0 },
+{ 0x0179, 0x0101, 0x0179, 0 },
+{ 0x017a, 0x0102, 0x017a, 0 },
+{ 0x017b, 0x0101, 0x017b, 0 },
+{ 0x017c, 0x0102, 0x017c, 0 },
+{ 0x017d, 0x0101, 0x017d, 0 },
+{ 0x017e, 0x0102, 0x017e, 0 },
+{ 0x017f, 0x0102, 0x017f, 0 },
+{ 0x0180, 0x0102, 0x0180, 0 },
+{ 0x0181, 0x0101, 0x0181, 0 },
+{ 0x0182, 0x0101, 0x0182, 0 },
+{ 0x0183, 0x0102, 0x0183, 0 },
+{ 0x0184, 0x0101, 0x0184, 0 },
+{ 0x0185, 0x0102, 0x0185, 0 },
+{ 0x0186, 0x0101, 0x0186, 0 },
+{ 0x0187, 0x0101, 0x0187, 0 },
+{ 0x0188, 0x0102, 0x0188, 0 },
+{ 0x0189, 0x0101, 0x0189, 0 },
+{ 0x018a, 0x0101, 0x018a, 0 },
+{ 0x018b, 0x0101, 0x018b, 0 },
+{ 0x018c, 0x0102, 0x018c, 0 },
+{ 0x018d, 0x0102, 0x018d, 0 },
+{ 0x018e, 0x0101, 0x018e, 0 },
+{ 0x018f, 0x0101, 0x018f, 0 },
+{ 0x0190, 0x0101, 0x0190, 0 },
+{ 0x0191, 0x0101, 0x0191, 0 },
+{ 0x0192, 0x0112, 0x0192, 0 },
+{ 0x0193, 0x0101, 0x0193, 0 },
+{ 0x0194, 0x0101, 0x0194, 0 },
+{ 0x0195, 0x0102, 0x0195, 0 },
+{ 0x0196, 0x0101, 0x0196, 0 },
+{ 0x0197, 0x0101, 0x0197, 0 },
+{ 0x0198, 0x0101, 0x0198, 0 },
+{ 0x0199, 0x0102, 0x0199, 0 },
+{ 0x019a, 0x0102, 0x019a, 0 },
+{ 0x019b, 0x0102, 0x019b, 0 },
+{ 0x019c, 0x0101, 0x019c, 0 },
+{ 0x019d, 0x0101, 0x019d, 0 },
+{ 0x019e, 0x0102, 0x019e, 0 },
+{ 0x019f, 0x0101, 0x019f, 0 },
+{ 0x01a0, 0x0101, 0x01a0, 0 },
+{ 0x01a1, 0x0102, 0x01a1, 0 },
+{ 0x01a2, 0x0101, 0x01a2, 0 },
+{ 0x01a3, 0x0102, 0x01a3, 0 },
+{ 0x01a4, 0x0101, 0x01a4, 0 },
+{ 0x01a5, 0x0102, 0x01a5, 0 },
+{ 0x01a6, 0x0100, 0x0000, 0 },
+{ 0x01a7, 0x0101, 0x01a7, 0 },
+{ 0x01a8, 0x0102, 0x01a8, 0 },
+{ 0x01a9, 0x0101, 0x01a9, 0 },
+{ 0x01aa, 0x0100, 0x0000, 0 },
+{ 0x01ab, 0x0102, 0x01ab, 0 },
+{ 0x01ac, 0x0101, 0x01ac, 0 },
+{ 0x01ad, 0x0102, 0x01ad, 0 },
+{ 0x01ae, 0x0101, 0x01ae, 0 },
+{ 0x01af, 0x0101, 0x01af, 0 },
+{ 0x01b0, 0x0102, 0x01b0, 0 },
+{ 0x01b1, 0x0101, 0x01b1, 0 },
+{ 0x01b2, 0x0101, 0x01b2, 0 },
+{ 0x01b3, 0x0101, 0x01b3, 0 },
+{ 0x01b4, 0x0102, 0x01b4, 0 },
+{ 0x01b5, 0x0101, 0x01b5, 0 },
+{ 0x01b6, 0x0102, 0x01b6, 0 },
+{ 0x01b7, 0x0101, 0x01b7, 0 },
+{ 0x01b8, 0x0101, 0x01b8, 0 },
+{ 0x01b9, 0x0102, 0x01b9, 0 },
+{ 0x01ba, 0x0102, 0x01ba, 0 },
+{ 0x01bb, 0x0100, 0x0000, 0 },
+{ 0x01bc, 0x0101, 0x01bc, 0 },
+{ 0x01bd, 0x0102, 0x01bd, 0 },
+{ 0x01be, 0x0100, 0x0000, 5 },
+{ 0x01c4, 0x0101, 0x01c4, 0 },
+{ 0x01c5, 0x0103, 0x01c5, 0 },
+{ 0x01c6, 0x0102, 0x01c6, 0 },
+{ 0x01c7, 0x0101, 0x01c7, 0 },
+{ 0x01c8, 0x0103, 0x01c8, 0 },
+{ 0x01c9, 0x0102, 0x01c9, 0 },
+{ 0x01ca, 0x0101, 0x01ca, 0 },
+{ 0x01cb, 0x0103, 0x01cb, 0 },
+{ 0x01cc, 0x0102, 0x01cc, 0 },
+{ 0x01cd, 0x0101, 0x01cd, 0 },
+{ 0x01ce, 0x0102, 0x01ce, 0 },
+{ 0x01cf, 0x0101, 0x01cf, 0 },
+{ 0x01d0, 0x0102, 0x01d0, 0 },
+{ 0x01d1, 0x0101, 0x01d1, 0 },
+{ 0x01d2, 0x0102, 0x01d2, 0 },
+{ 0x01d3, 0x0101, 0x01d3, 0 },
+{ 0x01d4, 0x0102, 0x01d4, 0 },
+{ 0x01d5, 0x0101, 0x01d5, 0 },
+{ 0x01d6, 0x0102, 0x01d6, 0 },
+{ 0x01d7, 0x0101, 0x01d7, 0 },
+{ 0x01d8, 0x0102, 0x01d8, 0 },
+{ 0x01d9, 0x0101, 0x01d9, 0 },
+{ 0x01da, 0x0102, 0x01da, 0 },
+{ 0x01db, 0x0101, 0x01db, 0 },
+{ 0x01dc, 0x0102, 0x01dc, 0 },
+{ 0x01dd, 0x0102, 0x01dd, 0 },
+{ 0x01de, 0x0101, 0x01de, 0 },
+{ 0x01df, 0x0102, 0x01df, 0 },
+{ 0x01e0, 0x0101, 0x01e0, 0 },
+{ 0x01e1, 0x0102, 0x01e1, 0 },
+{ 0x01e2, 0x0101, 0x01e2, 0 },
+{ 0x01e3, 0x0102, 0x01e3, 0 },
+{ 0x01e4, 0x0101, 0x01e4, 0 },
+{ 0x01e5, 0x0102, 0x01e5, 0 },
+{ 0x01e6, 0x0101, 0x01e6, 0 },
+{ 0x01e7, 0x0102, 0x01e7, 0 },
+{ 0x01e8, 0x0101, 0x01e8, 0 },
+{ 0x01e9, 0x0102, 0x01e9, 0 },
+{ 0x01ea, 0x0101, 0x01ea, 0 },
+{ 0x01eb, 0x0102, 0x01eb, 0 },
+{ 0x01ec, 0x0101, 0x01ec, 0 },
+{ 0x01ed, 0x0102, 0x01ed, 0 },
+{ 0x01ee, 0x0101, 0x01ee, 0 },
+{ 0x01ef, 0x0102, 0x01ef, 0 },
+{ 0x01f0, 0x0102, 0x01f0, 0 },
+{ 0x01f1, 0x0101, 0x01f1, 0 },
+{ 0x01f2, 0x0103, 0x01f2, 0 },
+{ 0x01f3, 0x0102, 0x01f3, 0 },
+{ 0x01f4, 0x0101, 0x01f4, 0 },
+{ 0x01f5, 0x0102, 0x01f5, 0 },
+{ 0x01fa, 0x0101, 0x01fa, 0 },
+{ 0x01fb, 0x0102, 0x01fb, 0 },
+{ 0x01fc, 0x0101, 0x01fc, 0 },
+{ 0x01fd, 0x0102, 0x01fd, 0 },
+{ 0x01fe, 0x0101, 0x01fe, 0 },
+{ 0x01ff, 0x0102, 0x01ff, 0 },
+{ 0x0200, 0x0101, 0x0200, 0 },
+{ 0x0201, 0x0102, 0x0201, 0 },
+{ 0x0202, 0x0101, 0x0202, 0 },
+{ 0x0203, 0x0102, 0x0203, 0 },
+{ 0x0204, 0x0101, 0x0204, 0 },
+{ 0x0205, 0x0102, 0x0205, 0 },
+{ 0x0206, 0x0101, 0x0206, 0 },
+{ 0x0207, 0x0102, 0x0207, 0 },
+{ 0x0208, 0x0101, 0x0208, 0 },
+{ 0x0209, 0x0102, 0x0209, 0 },
+{ 0x020a, 0x0101, 0x020a, 0 },
+{ 0x020b, 0x0102, 0x020b, 0 },
+{ 0x020c, 0x0101, 0x020c, 0 },
+{ 0x020d, 0x0102, 0x020d, 0 },
+{ 0x020e, 0x0101, 0x020e, 0 },
+{ 0x020f, 0x0102, 0x020f, 0 },
+{ 0x0210, 0x0101, 0x0210, 0 },
+{ 0x0211, 0x0102, 0x0211, 0 },
+{ 0x0212, 0x0101, 0x0212, 0 },
+{ 0x0213, 0x0102, 0x0213, 0 },
+{ 0x0214, 0x0101, 0x0214, 0 },
+{ 0x0215, 0x0102, 0x0215, 0 },
+{ 0x0216, 0x0101, 0x0216, 0 },
+{ 0x0217, 0x0102, 0x0217, 0 },
+{ 0x0250, 0x0102, 0x0250, 0 },
+{ 0x0251, 0x0102, 0x0251, 0 },
+{ 0x0252, 0x0102, 0x0252, 0 },
+{ 0x0253, 0x0102, 0x0253, 0 },
+{ 0x0254, 0x0102, 0x0254, 0 },
+{ 0x0255, 0x0102, 0x0255, 0 },
+{ 0x0256, 0x0102, 0x0256, 0 },
+{ 0x0257, 0x0102, 0x0257, 0 },
+{ 0x0258, 0x0102, 0x0258, 0 },
+{ 0x0259, 0x0102, 0x0259, 0 },
+{ 0x025a, 0x0102, 0x025a, 0 },
+{ 0x025b, 0x0102, 0x025b, 0 },
+{ 0x025c, 0x0102, 0x025c, 0 },
+{ 0x025d, 0x0102, 0x025d, 0 },
+{ 0x025e, 0x0102, 0x025e, 0 },
+{ 0x025f, 0x0102, 0x025f, 0 },
+{ 0x0260, 0x0102, 0x0260, 0 },
+{ 0x0261, 0x0102, 0x0261, 0 },
+{ 0x0262, 0x0100, 0x0000, 0 },
+{ 0x0263, 0x0102, 0x0263, 0 },
+{ 0x0264, 0x0102, 0x0264, 0 },
+{ 0x0265, 0x0102, 0x0265, 0 },
+{ 0x0266, 0x0102, 0x0266, 0 },
+{ 0x0267, 0x0102, 0x0267, 0 },
+{ 0x0268, 0x0102, 0x0268, 0 },
+{ 0x0269, 0x0102, 0x0269, 0 },
+{ 0x026a, 0x0100, 0x0000, 0 },
+{ 0x026b, 0x0102, 0x026b, 0 },
+{ 0x026c, 0x0102, 0x026c, 0 },
+{ 0x026d, 0x0102, 0x026d, 0 },
+{ 0x026e, 0x0102, 0x026e, 0 },
+{ 0x026f, 0x0102, 0x026f, 0 },
+{ 0x0270, 0x0102, 0x0270, 0 },
+{ 0x0271, 0x0102, 0x0271, 0 },
+{ 0x0272, 0x0102, 0x0272, 0 },
+{ 0x0273, 0x0102, 0x0273, 0 },
+{ 0x0274, 0x0100, 0x0000, 0 },
+{ 0x0275, 0x0102, 0x0275, 0 },
+{ 0x0276, 0x0100, 0x0000, 0 },
+{ 0x0277, 0x0102, 0x0277, 0 },
+{ 0x0278, 0x0102, 0x0278, 0 },
+{ 0x0279, 0x0102, 0x0279, 0 },
+{ 0x027a, 0x0102, 0x027a, 0 },
+{ 0x027b, 0x0102, 0x027b, 0 },
+{ 0x027c, 0x0102, 0x027c, 0 },
+{ 0x027d, 0x0102, 0x027d, 0 },
+{ 0x027e, 0x0102, 0x027e, 0 },
+{ 0x027f, 0x0102, 0x027f, 0 },
+{ 0x0280, 0x0100, 0x0000, 1 },
+{ 0x0282, 0x0102, 0x0282, 0 },
+{ 0x0283, 0x0102, 0x0283, 0 },
+{ 0x0284, 0x0102, 0x0284, 0 },
+{ 0x0285, 0x0102, 0x0285, 0 },
+{ 0x0286, 0x0102, 0x0286, 0 },
+{ 0x0287, 0x0102, 0x0287, 0 },
+{ 0x0288, 0x0102, 0x0288, 0 },
+{ 0x0289, 0x0102, 0x0289, 0 },
+{ 0x028a, 0x0102, 0x028a, 0 },
+{ 0x028b, 0x0102, 0x028b, 0 },
+{ 0x028c, 0x0102, 0x028c, 0 },
+{ 0x028d, 0x0102, 0x028d, 0 },
+{ 0x028e, 0x0102, 0x028e, 0 },
+{ 0x028f, 0x0100, 0x0000, 0 },
+{ 0x0290, 0x0102, 0x0290, 0 },
+{ 0x0291, 0x0102, 0x0291, 0 },
+{ 0x0292, 0x0102, 0x0292, 0 },
+{ 0x0293, 0x0102, 0x0293, 0 },
+{ 0x0294, 0x0100, 0x0000, 5 },
+{ 0x029a, 0x0102, 0x029a, 0 },
+{ 0x029b, 0x0100, 0x0000, 1 },
+{ 0x029d, 0x0102, 0x029d, 0 },
+{ 0x029e, 0x0102, 0x029e, 0 },
+{ 0x029f, 0x0100, 0x0000, 0 },
+{ 0x02a0, 0x0102, 0x02a0, 0 },
+{ 0x02a1, 0x0100, 0x0000, 1 },
+{ 0x02a3, 0x0102, 0x02a3, 0 },
+{ 0x02a4, 0x0102, 0x02a4, 0 },
+{ 0x02a5, 0x0102, 0x02a5, 0 },
+{ 0x02a6, 0x0102, 0x02a6, 0 },
+{ 0x02a7, 0x0102, 0x02a7, 0 },
+{ 0x02a8, 0x0102, 0x02a8, 0 },
+{ 0x02b0, 0x0010, 0x0000, 134 },
+{ 0x0386, 0x0101, 0x0386, 0 },
+{ 0x0387, 0x0010, 0x0000, 0 },
+{ 0x0388, 0x0101, 0x0388, 0 },
+{ 0x0389, 0x0101, 0x0389, 0 },
+{ 0x038a, 0x0101, 0x038a, 0 },
+{ 0x038c, 0x0101, 0x038c, 0 },
+{ 0x038e, 0x0101, 0x038e, 0 },
+{ 0x038f, 0x0101, 0x038f, 0 },
+{ 0x0390, 0x0102, 0x0390, 0 },
+{ 0x0391, 0x0101, 0x0391, 0 },
+{ 0x0392, 0x0101, 0x0392, 0 },
+{ 0x0393, 0x0101, 0x0393, 0 },
+{ 0x0394, 0x0101, 0x0394, 0 },
+{ 0x0395, 0x0101, 0x0395, 0 },
+{ 0x0396, 0x0101, 0x0396, 0 },
+{ 0x0397, 0x0101, 0x0397, 0 },
+{ 0x0398, 0x0101, 0x0398, 0 },
+{ 0x0399, 0x0101, 0x0399, 0 },
+{ 0x039a, 0x0101, 0x039a, 0 },
+{ 0x039b, 0x0101, 0x039b, 0 },
+{ 0x039c, 0x0101, 0x039c, 0 },
+{ 0x039d, 0x0101, 0x039d, 0 },
+{ 0x039e, 0x0101, 0x039e, 0 },
+{ 0x039f, 0x0101, 0x039f, 0 },
+{ 0x03a0, 0x0101, 0x03a0, 0 },
+{ 0x03a1, 0x0101, 0x03a1, 0 },
+{ 0x03a3, 0x0101, 0x03a3, 0 },
+{ 0x03a4, 0x0101, 0x03a4, 0 },
+{ 0x03a5, 0x0101, 0x03a5, 0 },
+{ 0x03a6, 0x0101, 0x03a6, 0 },
+{ 0x03a7, 0x0101, 0x03a7, 0 },
+{ 0x03a8, 0x0101, 0x03a8, 0 },
+{ 0x03a9, 0x0101, 0x03a9, 0 },
+{ 0x03aa, 0x0101, 0x03aa, 0 },
+{ 0x03ab, 0x0101, 0x03ab, 0 },
+{ 0x03ac, 0x0102, 0x03ac, 0 },
+{ 0x03ad, 0x0102, 0x03ad, 0 },
+{ 0x03ae, 0x0102, 0x03ae, 0 },
+{ 0x03af, 0x0102, 0x03af, 0 },
+{ 0x03b0, 0x0102, 0x03b0, 0 },
+{ 0x03b1, 0x0102, 0x03b1, 0 },
+{ 0x03b2, 0x0102, 0x03b2, 0 },
+{ 0x03b3, 0x0102, 0x03b3, 0 },
+{ 0x03b4, 0x0102, 0x03b4, 0 },
+{ 0x03b5, 0x0102, 0x03b5, 0 },
+{ 0x03b6, 0x0102, 0x03b6, 0 },
+{ 0x03b7, 0x0102, 0x03b7, 0 },
+{ 0x03b8, 0x0102, 0x03b8, 0 },
+{ 0x03b9, 0x0102, 0x03b9, 0 },
+{ 0x03ba, 0x0102, 0x03ba, 0 },
+{ 0x03bb, 0x0102, 0x03bb, 0 },
+{ 0x03bc, 0x0102, 0x03bc, 0 },
+{ 0x03bd, 0x0102, 0x03bd, 0 },
+{ 0x03be, 0x0102, 0x03be, 0 },
+{ 0x03bf, 0x0102, 0x03bf, 0 },
+{ 0x03c0, 0x0102, 0x03c0, 0 },
+{ 0x03c1, 0x0102, 0x03c1, 0 },
+{ 0x03c2, 0x0102, 0x03c2, 0 },
+{ 0x03c3, 0x0102, 0x03c3, 0 },
+{ 0x03c4, 0x0102, 0x03c4, 0 },
+{ 0x03c5, 0x0102, 0x03c5, 0 },
+{ 0x03c6, 0x0102, 0x03c6, 0 },
+{ 0x03c7, 0x0102, 0x03c7, 0 },
+{ 0x03c8, 0x0102, 0x03c8, 0 },
+{ 0x03c9, 0x0102, 0x03c9, 0 },
+{ 0x03ca, 0x0102, 0x03ca, 0 },
+{ 0x03cb, 0x0102, 0x03cb, 0 },
+{ 0x03cc, 0x0102, 0x03cc, 0 },
+{ 0x03cd, 0x0102, 0x03cd, 0 },
+{ 0x03ce, 0x0102, 0x03ce, 0 },
+{ 0x03d0, 0x0102, 0x03d0, 0 },
+{ 0x03d1, 0x0102, 0x03d1, 0 },
+{ 0x03d2, 0x0101, 0x03d2, 0 },
+{ 0x03d3, 0x0101, 0x03d3, 0 },
+{ 0x03d4, 0x0101, 0x03d4, 0 },
+{ 0x03d5, 0x0102, 0x03d5, 0 },
+{ 0x03d6, 0x0102, 0x03d6, 0 },
+{ 0x03da, 0x0101, 0x03da, 0 },
+{ 0x03dc, 0x0101, 0x03dc, 0 },
+{ 0x03de, 0x0101, 0x03de, 0 },
+{ 0x03e0, 0x0101, 0x03e0, 0 },
+{ 0x03e2, 0x0101, 0x03e2, 0 },
+{ 0x03e3, 0x0102, 0x03e3, 0 },
+{ 0x03e4, 0x0101, 0x03e4, 0 },
+{ 0x03e5, 0x0102, 0x03e5, 0 },
+{ 0x03e6, 0x0101, 0x03e6, 0 },
+{ 0x03e7, 0x0102, 0x03e7, 0 },
+{ 0x03e8, 0x0101, 0x03e8, 0 },
+{ 0x03e9, 0x0102, 0x03e9, 0 },
+{ 0x03ea, 0x0101, 0x03ea, 0 },
+{ 0x03eb, 0x0102, 0x03eb, 0 },
+{ 0x03ec, 0x0101, 0x03ec, 0 },
+{ 0x03ed, 0x0102, 0x03ed, 0 },
+{ 0x03ee, 0x0101, 0x03ee, 0 },
+{ 0x03ef, 0x0102, 0x03ef, 0 },
+{ 0x03f0, 0x0102, 0x03f0, 0 },
+{ 0x03f1, 0x0102, 0x03f1, 0 },
+{ 0x03f2, 0x0102, 0x03f2, 0 },
+{ 0x03f3, 0x0102, 0x03f3, 0 },
+{ 0x0401, 0x0101, 0x0401, 0 },
+{ 0x0402, 0x0101, 0x0402, 0 },
+{ 0x0403, 0x0101, 0x0403, 0 },
+{ 0x0404, 0x0101, 0x0404, 0 },
+{ 0x0405, 0x0101, 0x0405, 0 },
+{ 0x0406, 0x0101, 0x0406, 0 },
+{ 0x0407, 0x0101, 0x0407, 0 },
+{ 0x0408, 0x0101, 0x0408, 0 },
+{ 0x0409, 0x0101, 0x0409, 0 },
+{ 0x040a, 0x0101, 0x040a, 0 },
+{ 0x040b, 0x0101, 0x040b, 0 },
+{ 0x040c, 0x0101, 0x040c, 0 },
+{ 0x040e, 0x0101, 0x040e, 0 },
+{ 0x040f, 0x0101, 0x040f, 0 },
+{ 0x0410, 0x0101, 0x0410, 0 },
+{ 0x0411, 0x0101, 0x0411, 0 },
+{ 0x0412, 0x0101, 0x0412, 0 },
+{ 0x0413, 0x0101, 0x0413, 0 },
+{ 0x0414, 0x0101, 0x0414, 0 },
+{ 0x0415, 0x0101, 0x0415, 0 },
+{ 0x0416, 0x0101, 0x0416, 0 },
+{ 0x0417, 0x0101, 0x0417, 0 },
+{ 0x0418, 0x0101, 0x0418, 0 },
+{ 0x0419, 0x0101, 0x0419, 0 },
+{ 0x041a, 0x0101, 0x041a, 0 },
+{ 0x041b, 0x0101, 0x041b, 0 },
+{ 0x041c, 0x0101, 0x041c, 0 },
+{ 0x041d, 0x0101, 0x041d, 0 },
+{ 0x041e, 0x0101, 0x041e, 0 },
+{ 0x041f, 0x0101, 0x041f, 0 },
+{ 0x0420, 0x0101, 0x0420, 0 },
+{ 0x0421, 0x0101, 0x0421, 0 },
+{ 0x0422, 0x0101, 0x0422, 0 },
+{ 0x0423, 0x0101, 0x0423, 0 },
+{ 0x0424, 0x0101, 0x0424, 0 },
+{ 0x0425, 0x0101, 0x0425, 0 },
+{ 0x0426, 0x0101, 0x0426, 0 },
+{ 0x0427, 0x0101, 0x0427, 0 },
+{ 0x0428, 0x0101, 0x0428, 0 },
+{ 0x0429, 0x0101, 0x0429, 0 },
+{ 0x042a, 0x0101, 0x042a, 0 },
+{ 0x042b, 0x0101, 0x042b, 0 },
+{ 0x042c, 0x0101, 0x042c, 0 },
+{ 0x042d, 0x0101, 0x042d, 0 },
+{ 0x042e, 0x0101, 0x042e, 0 },
+{ 0x042f, 0x0101, 0x042f, 0 },
+{ 0x0430, 0x0102, 0x0430, 0 },
+{ 0x0431, 0x0102, 0x0431, 0 },
+{ 0x0432, 0x0102, 0x0432, 0 },
+{ 0x0433, 0x0102, 0x0433, 0 },
+{ 0x0434, 0x0102, 0x0434, 0 },
+{ 0x0435, 0x0102, 0x0435, 0 },
+{ 0x0436, 0x0102, 0x0436, 0 },
+{ 0x0437, 0x0102, 0x0437, 0 },
+{ 0x0438, 0x0102, 0x0438, 0 },
+{ 0x0439, 0x0102, 0x0439, 0 },
+{ 0x043a, 0x0102, 0x043a, 0 },
+{ 0x043b, 0x0102, 0x043b, 0 },
+{ 0x043c, 0x0102, 0x043c, 0 },
+{ 0x043d, 0x0102, 0x043d, 0 },
+{ 0x043e, 0x0102, 0x043e, 0 },
+{ 0x043f, 0x0102, 0x043f, 0 },
+{ 0x0440, 0x0102, 0x0440, 0 },
+{ 0x0441, 0x0102, 0x0441, 0 },
+{ 0x0442, 0x0102, 0x0442, 0 },
+{ 0x0443, 0x0102, 0x0443, 0 },
+{ 0x0444, 0x0102, 0x0444, 0 },
+{ 0x0445, 0x0102, 0x0445, 0 },
+{ 0x0446, 0x0102, 0x0446, 0 },
+{ 0x0447, 0x0102, 0x0447, 0 },
+{ 0x0448, 0x0102, 0x0448, 0 },
+{ 0x0449, 0x0102, 0x0449, 0 },
+{ 0x044a, 0x0102, 0x044a, 0 },
+{ 0x044b, 0x0102, 0x044b, 0 },
+{ 0x044c, 0x0102, 0x044c, 0 },
+{ 0x044d, 0x0102, 0x044d, 0 },
+{ 0x044e, 0x0102, 0x044e, 0 },
+{ 0x044f, 0x0102, 0x044f, 0 },
+{ 0x0451, 0x0102, 0x0451, 0 },
+{ 0x0452, 0x0102, 0x0452, 0 },
+{ 0x0453, 0x0102, 0x0453, 0 },
+{ 0x0454, 0x0102, 0x0454, 0 },
+{ 0x0455, 0x0102, 0x0455, 0 },
+{ 0x0456, 0x0102, 0x0456, 0 },
+{ 0x0457, 0x0102, 0x0457, 0 },
+{ 0x0458, 0x0102, 0x0458, 0 },
+{ 0x0459, 0x0102, 0x0459, 0 },
+{ 0x045a, 0x0102, 0x045a, 0 },
+{ 0x045b, 0x0102, 0x045b, 0 },
+{ 0x045c, 0x0102, 0x045c, 0 },
+{ 0x045e, 0x0102, 0x045e, 0 },
+{ 0x045f, 0x0102, 0x045f, 0 },
+{ 0x0460, 0x0101, 0x0460, 0 },
+{ 0x0461, 0x0102, 0x0461, 0 },
+{ 0x0462, 0x0101, 0x0462, 0 },
+{ 0x0463, 0x0102, 0x0463, 0 },
+{ 0x0464, 0x0101, 0x0464, 0 },
+{ 0x0465, 0x0102, 0x0465, 0 },
+{ 0x0466, 0x0101, 0x0466, 0 },
+{ 0x0467, 0x0102, 0x0467, 0 },
+{ 0x0468, 0x0101, 0x0468, 0 },
+{ 0x0469, 0x0102, 0x0469, 0 },
+{ 0x046a, 0x0101, 0x046a, 0 },
+{ 0x046b, 0x0102, 0x046b, 0 },
+{ 0x046c, 0x0101, 0x046c, 0 },
+{ 0x046d, 0x0102, 0x046d, 0 },
+{ 0x046e, 0x0101, 0x046e, 0 },
+{ 0x046f, 0x0102, 0x046f, 0 },
+{ 0x0470, 0x0101, 0x0470, 0 },
+{ 0x0471, 0x0102, 0x0471, 0 },
+{ 0x0472, 0x0101, 0x0472, 0 },
+{ 0x0473, 0x0102, 0x0473, 0 },
+{ 0x0474, 0x0101, 0x0474, 0 },
+{ 0x0475, 0x0102, 0x0475, 0 },
+{ 0x0476, 0x0101, 0x0476, 0 },
+{ 0x0477, 0x0102, 0x0477, 0 },
+{ 0x0478, 0x0101, 0x0478, 0 },
+{ 0x0479, 0x0102, 0x0479, 0 },
+{ 0x047a, 0x0101, 0x047a, 0 },
+{ 0x047b, 0x0102, 0x047b, 0 },
+{ 0x047c, 0x0101, 0x047c, 0 },
+{ 0x047d, 0x0102, 0x047d, 0 },
+{ 0x047e, 0x0101, 0x047e, 0 },
+{ 0x047f, 0x0102, 0x047f, 0 },
+{ 0x0480, 0x0101, 0x0480, 0 },
+{ 0x0481, 0x0102, 0x0481, 0 },
+{ 0x0482, 0x0010, 0x0000, 4 },
+{ 0x0490, 0x0101, 0x0490, 0 },
+{ 0x0491, 0x0102, 0x0491, 0 },
+{ 0x0492, 0x0101, 0x0492, 0 },
+{ 0x0493, 0x0102, 0x0493, 0 },
+{ 0x0494, 0x0101, 0x0494, 0 },
+{ 0x0495, 0x0102, 0x0495, 0 },
+{ 0x0496, 0x0101, 0x0496, 0 },
+{ 0x0497, 0x0102, 0x0497, 0 },
+{ 0x0498, 0x0101, 0x0498, 0 },
+{ 0x0499, 0x0102, 0x0499, 0 },
+{ 0x049a, 0x0101, 0x049a, 0 },
+{ 0x049b, 0x0102, 0x049b, 0 },
+{ 0x049c, 0x0101, 0x049c, 0 },
+{ 0x049d, 0x0102, 0x049d, 0 },
+{ 0x049e, 0x0101, 0x049e, 0 },
+{ 0x049f, 0x0102, 0x049f, 0 },
+{ 0x04a0, 0x0101, 0x04a0, 0 },
+{ 0x04a1, 0x0102, 0x04a1, 0 },
+{ 0x04a2, 0x0101, 0x04a2, 0 },
+{ 0x04a3, 0x0102, 0x04a3, 0 },
+{ 0x04a4, 0x0101, 0x04a4, 0 },
+{ 0x04a5, 0x0102, 0x04a5, 0 },
+{ 0x04a6, 0x0101, 0x04a6, 0 },
+{ 0x04a7, 0x0102, 0x04a7, 0 },
+{ 0x04a8, 0x0101, 0x04a8, 0 },
+{ 0x04a9, 0x0102, 0x04a9, 0 },
+{ 0x04aa, 0x0101, 0x04aa, 0 },
+{ 0x04ab, 0x0102, 0x04ab, 0 },
+{ 0x04ac, 0x0101, 0x04ac, 0 },
+{ 0x04ad, 0x0102, 0x04ad, 0 },
+{ 0x04ae, 0x0101, 0x04ae, 0 },
+{ 0x04af, 0x0102, 0x04af, 0 },
+{ 0x04b0, 0x0101, 0x04b0, 0 },
+{ 0x04b1, 0x0102, 0x04b1, 0 },
+{ 0x04b2, 0x0101, 0x04b2, 0 },
+{ 0x04b3, 0x0102, 0x04b3, 0 },
+{ 0x04b4, 0x0101, 0x04b4, 0 },
+{ 0x04b5, 0x0102, 0x04b5, 0 },
+{ 0x04b6, 0x0101, 0x04b6, 0 },
+{ 0x04b7, 0x0102, 0x04b7, 0 },
+{ 0x04b8, 0x0101, 0x04b8, 0 },
+{ 0x04b9, 0x0102, 0x04b9, 0 },
+{ 0x04ba, 0x0101, 0x04ba, 0 },
+{ 0x04bb, 0x0102, 0x04bb, 0 },
+{ 0x04bc, 0x0101, 0x04bc, 0 },
+{ 0x04bd, 0x0102, 0x04bd, 0 },
+{ 0x04be, 0x0101, 0x04be, 0 },
+{ 0x04bf, 0x0102, 0x04bf, 0 },
+{ 0x04c0, 0x0100, 0x0000, 0 },
+{ 0x04c1, 0x0101, 0x04c1, 0 },
+{ 0x04c2, 0x0102, 0x04c2, 0 },
+{ 0x04c3, 0x0101, 0x04c3, 0 },
+{ 0x04c4, 0x0102, 0x04c4, 0 },
+{ 0x04c7, 0x0101, 0x04c7, 0 },
+{ 0x04c8, 0x0102, 0x04c8, 0 },
+{ 0x04cb, 0x0101, 0x04cb, 0 },
+{ 0x04cc, 0x0102, 0x04cc, 0 },
+{ 0x04d0, 0x0101, 0x04d0, 0 },
+{ 0x04d1, 0x0102, 0x04d1, 0 },
+{ 0x04d2, 0x0101, 0x04d2, 0 },
+{ 0x04d3, 0x0102, 0x04d3, 0 },
+{ 0x04d4, 0x0101, 0x04d4, 0 },
+{ 0x04d5, 0x0102, 0x04d5, 0 },
+{ 0x04d6, 0x0101, 0x04d6, 0 },
+{ 0x04d7, 0x0102, 0x04d7, 0 },
+{ 0x04d8, 0x0101, 0x04d8, 0 },
+{ 0x04d9, 0x0102, 0x04d9, 0 },
+{ 0x04da, 0x0101, 0x04da, 0 },
+{ 0x04db, 0x0102, 0x04db, 0 },
+{ 0x04dc, 0x0101, 0x04dc, 0 },
+{ 0x04dd, 0x0102, 0x04dd, 0 },
+{ 0x04de, 0x0101, 0x04de, 0 },
+{ 0x04df, 0x0102, 0x04df, 0 },
+{ 0x04e0, 0x0101, 0x04e0, 0 },
+{ 0x04e1, 0x0102, 0x04e1, 0 },
+{ 0x04e2, 0x0101, 0x04e2, 0 },
+{ 0x04e3, 0x0102, 0x04e3, 0 },
+{ 0x04e4, 0x0101, 0x04e4, 0 },
+{ 0x04e5, 0x0102, 0x04e5, 0 },
+{ 0x04e6, 0x0101, 0x04e6, 0 },
+{ 0x04e7, 0x0102, 0x04e7, 0 },
+{ 0x04e8, 0x0101, 0x04e8, 0 },
+{ 0x04e9, 0x0102, 0x04e9, 0 },
+{ 0x04ea, 0x0101, 0x04ea, 0 },
+{ 0x04eb, 0x0102, 0x04eb, 0 },
+{ 0x04ee, 0x0101, 0x04ee, 0 },
+{ 0x04ef, 0x0102, 0x04ef, 0 },
+{ 0x04f0, 0x0101, 0x04f0, 0 },
+{ 0x04f1, 0x0102, 0x04f1, 0 },
+{ 0x04f2, 0x0101, 0x04f2, 0 },
+{ 0x04f3, 0x0102, 0x04f3, 0 },
+{ 0x04f4, 0x0101, 0x04f4, 0 },
+{ 0x04f5, 0x0102, 0x04f5, 0 },
+{ 0x04f8, 0x0101, 0x04f8, 0 },
+{ 0x04f9, 0x0102, 0x04f9, 0 },
+{ 0x0531, 0x0101, 0x0531, 0 },
+{ 0x0532, 0x0101, 0x0532, 0 },
+{ 0x0533, 0x0101, 0x0533, 0 },
+{ 0x0534, 0x0101, 0x0534, 0 },
+{ 0x0535, 0x0101, 0x0535, 0 },
+{ 0x0536, 0x0101, 0x0536, 0 },
+{ 0x0537, 0x0101, 0x0537, 0 },
+{ 0x0538, 0x0101, 0x0538, 0 },
+{ 0x0539, 0x0101, 0x0539, 0 },
+{ 0x053a, 0x0101, 0x053a, 0 },
+{ 0x053b, 0x0101, 0x053b, 0 },
+{ 0x053c, 0x0101, 0x053c, 0 },
+{ 0x053d, 0x0101, 0x053d, 0 },
+{ 0x053e, 0x0101, 0x053e, 0 },
+{ 0x053f, 0x0101, 0x053f, 0 },
+{ 0x0540, 0x0101, 0x0540, 0 },
+{ 0x0541, 0x0101, 0x0541, 0 },
+{ 0x0542, 0x0101, 0x0542, 0 },
+{ 0x0543, 0x0101, 0x0543, 0 },
+{ 0x0544, 0x0101, 0x0544, 0 },
+{ 0x0545, 0x0101, 0x0545, 0 },
+{ 0x0546, 0x0101, 0x0546, 0 },
+{ 0x0547, 0x0101, 0x0547, 0 },
+{ 0x0548, 0x0101, 0x0548, 0 },
+{ 0x0549, 0x0101, 0x0549, 0 },
+{ 0x054a, 0x0101, 0x054a, 0 },
+{ 0x054b, 0x0101, 0x054b, 0 },
+{ 0x054c, 0x0101, 0x054c, 0 },
+{ 0x054d, 0x0101, 0x054d, 0 },
+{ 0x054e, 0x0101, 0x054e, 0 },
+{ 0x054f, 0x0101, 0x054f, 0 },
+{ 0x0550, 0x0101, 0x0550, 0 },
+{ 0x0551, 0x0101, 0x0551, 0 },
+{ 0x0552, 0x0101, 0x0552, 0 },
+{ 0x0553, 0x0101, 0x0553, 0 },
+{ 0x0554, 0x0101, 0x0554, 0 },
+{ 0x0555, 0x0101, 0x0555, 0 },
+{ 0x0556, 0x0101, 0x0556, 0 },
+{ 0x0559, 0x0010, 0x0000, 6 },
+{ 0x0561, 0x0102, 0x0561, 0 },
+{ 0x0562, 0x0102, 0x0562, 0 },
+{ 0x0563, 0x0102, 0x0563, 0 },
+{ 0x0564, 0x0102, 0x0564, 0 },
+{ 0x0565, 0x0102, 0x0565, 0 },
+{ 0x0566, 0x0102, 0x0566, 0 },
+{ 0x0567, 0x0102, 0x0567, 0 },
+{ 0x0568, 0x0102, 0x0568, 0 },
+{ 0x0569, 0x0102, 0x0569, 0 },
+{ 0x056a, 0x0102, 0x056a, 0 },
+{ 0x056b, 0x0102, 0x056b, 0 },
+{ 0x056c, 0x0102, 0x056c, 0 },
+{ 0x056d, 0x0102, 0x056d, 0 },
+{ 0x056e, 0x0102, 0x056e, 0 },
+{ 0x056f, 0x0102, 0x056f, 0 },
+{ 0x0570, 0x0102, 0x0570, 0 },
+{ 0x0571, 0x0102, 0x0571, 0 },
+{ 0x0572, 0x0102, 0x0572, 0 },
+{ 0x0573, 0x0102, 0x0573, 0 },
+{ 0x0574, 0x0102, 0x0574, 0 },
+{ 0x0575, 0x0102, 0x0575, 0 },
+{ 0x0576, 0x0102, 0x0576, 0 },
+{ 0x0577, 0x0102, 0x0577, 0 },
+{ 0x0578, 0x0102, 0x0578, 0 },
+{ 0x0579, 0x0102, 0x0579, 0 },
+{ 0x057a, 0x0102, 0x057a, 0 },
+{ 0x057b, 0x0102, 0x057b, 0 },
+{ 0x057c, 0x0102, 0x057c, 0 },
+{ 0x057d, 0x0102, 0x057d, 0 },
+{ 0x057e, 0x0102, 0x057e, 0 },
+{ 0x057f, 0x0102, 0x057f, 0 },
+{ 0x0580, 0x0102, 0x0580, 0 },
+{ 0x0581, 0x0102, 0x0581, 0 },
+{ 0x0582, 0x0102, 0x0582, 0 },
+{ 0x0583, 0x0102, 0x0583, 0 },
+{ 0x0584, 0x0102, 0x0584, 0 },
+{ 0x0585, 0x0102, 0x0585, 0 },
+{ 0x0586, 0x0102, 0x0586, 0 },
+{ 0x0587, 0x0102, 0x0587, 0 },
+{ 0x0589, 0x0010, 0x0000, 51 },
+{ 0x05d0, 0x0100, 0x0000, 29 },
+{ 0x05f3, 0x0010, 0x0000, 4 },
+{ 0x0621, 0x0100, 0x0000, 25 },
+{ 0x0640, 0x0010, 0x0000, 0 },
+{ 0x0641, 0x0100, 0x0000, 9 },
+{ 0x064b, 0x0010, 0x0000, 7 },
+{ 0x0660, 0x0004, 0x0000, 9 },
+{ 0x066a, 0x0010, 0x0000, 4 },
+{ 0x0671, 0x0100, 0x0000, 94 },
+{ 0x06d4, 0x0010, 0x0000, 0 },
+{ 0x06d5, 0x0100, 0x0000, 0 },
+{ 0x06d6, 0x0010, 0x0000, 23 },
+{ 0x06f0, 0x0004, 0x0000, 9 },
+{ 0x0901, 0x0010, 0x0000, 2 },
+{ 0x0905, 0x0100, 0x0000, 52 },
+{ 0x093c, 0x0010, 0x0000, 22 },
+{ 0x0958, 0x0100, 0x0000, 9 },
+{ 0x0962, 0x0010, 0x0000, 3 },
+{ 0x0966, 0x0004, 0x0000, 9 },
+{ 0x0970, 0x0010, 0x0000, 3 },
+{ 0x0985, 0x0100, 0x0000, 43 },
+{ 0x09bc, 0x0010, 0x0000, 13 },
+{ 0x09dc, 0x0100, 0x0000, 4 },
+{ 0x09e2, 0x0010, 0x0000, 1 },
+{ 0x09e6, 0x0004, 0x0000, 9 },
+{ 0x09f0, 0x0100, 0x0000, 1 },
+{ 0x09f2, 0x0010, 0x0000, 9 },
+{ 0x0a05, 0x0100, 0x0000, 42 },
+{ 0x0a3c, 0x0010, 0x0000, 10 },
+{ 0x0a59, 0x0100, 0x0000, 4 },
+{ 0x0a66, 0x0004, 0x0000, 9 },
+{ 0x0a70, 0x0010, 0x0000, 7 },
+{ 0x0a85, 0x0100, 0x0000, 46 },
+{ 0x0abc, 0x0010, 0x0000, 16 },
+{ 0x0ae0, 0x0100, 0x0000, 0 },
+{ 0x0ae6, 0x0004, 0x0000, 9 },
+{ 0x0b01, 0x0010, 0x0000, 2 },
+{ 0x0b05, 0x0100, 0x0000, 44 },
+{ 0x0b3c, 0x0010, 0x0000, 14 },
+{ 0x0b5c, 0x0100, 0x0000, 4 },
+{ 0x0b66, 0x0004, 0x0000, 9 },
+{ 0x0b70, 0x0010, 0x0000, 2 },
+{ 0x0b85, 0x0100, 0x0000, 33 },
+{ 0x0bbe, 0x0010, 0x0000, 12 },
+{ 0x0be7, 0x0004, 0x0000, 11 },
+{ 0x0c01, 0x0010, 0x0000, 2 },
+{ 0x0c05, 0x0100, 0x0000, 48 },
+{ 0x0c3e, 0x0010, 0x0000, 15 },
+{ 0x0c60, 0x0100, 0x0000, 1 },
+{ 0x0c66, 0x0004, 0x0000, 9 },
+{ 0x0c82, 0x0010, 0x0000, 1 },
+{ 0x0c85, 0x0100, 0x0000, 48 },
+{ 0x0cbe, 0x0010, 0x0000, 15 },
+{ 0x0cde, 0x0100, 0x0000, 2 },
+{ 0x0ce6, 0x0004, 0x0000, 9 },
+{ 0x0d02, 0x0010, 0x0000, 1 },
+{ 0x0d05, 0x0100, 0x0000, 49 },
+{ 0x0d3e, 0x0010, 0x0000, 13 },
+{ 0x0d60, 0x0100, 0x0000, 1 },
+{ 0x0d66, 0x0004, 0x0000, 9 },
+{ 0x0e01, 0x0100, 0x0000, 57 },
+{ 0x0e3f, 0x0010, 0x0000, 0 },
+{ 0x0e40, 0x0100, 0x0000, 14 },
+{ 0x0e4f, 0x0010, 0x0000, 0 },
+{ 0x0e50, 0x0004, 0x0000, 9 },
+{ 0x0e5a, 0x0010, 0x0000, 1 },
+{ 0x0e81, 0x0100, 0x0000, 26 },
+{ 0x0eaf, 0x0010, 0x0000, 25 },
+{ 0x0ed0, 0x0004, 0x0000, 9 },
+{ 0x0edc, 0x0100, 0x0000, 1 },
+{ 0x0f00, 0x0010, 0x0000, 31 },
+{ 0x0f20, 0x0004, 0x0000, 19 },
+{ 0x0f34, 0x0010, 0x0000, 11 },
+{ 0x0f40, 0x0100, 0x0000, 40 },
+{ 0x0f71, 0x0010, 0x0000, 26 },
+{ 0x0f90, 0x0100, 0x0000, 35 },
+{ 0x10a0, 0x0101, 0x10a0, 0 },
+{ 0x10a1, 0x0101, 0x10a1, 0 },
+{ 0x10a2, 0x0101, 0x10a2, 0 },
+{ 0x10a3, 0x0101, 0x10a3, 0 },
+{ 0x10a4, 0x0101, 0x10a4, 0 },
+{ 0x10a5, 0x0101, 0x10a5, 0 },
+{ 0x10a6, 0x0101, 0x10a6, 0 },
+{ 0x10a7, 0x0101, 0x10a7, 0 },
+{ 0x10a8, 0x0101, 0x10a8, 0 },
+{ 0x10a9, 0x0101, 0x10a9, 0 },
+{ 0x10aa, 0x0101, 0x10aa, 0 },
+{ 0x10ab, 0x0101, 0x10ab, 0 },
+{ 0x10ac, 0x0101, 0x10ac, 0 },
+{ 0x10ad, 0x0101, 0x10ad, 0 },
+{ 0x10ae, 0x0101, 0x10ae, 0 },
+{ 0x10af, 0x0101, 0x10af, 0 },
+{ 0x10b0, 0x0101, 0x10b0, 0 },
+{ 0x10b1, 0x0101, 0x10b1, 0 },
+{ 0x10b2, 0x0101, 0x10b2, 0 },
+{ 0x10b3, 0x0101, 0x10b3, 0 },
+{ 0x10b4, 0x0101, 0x10b4, 0 },
+{ 0x10b5, 0x0101, 0x10b5, 0 },
+{ 0x10b6, 0x0101, 0x10b6, 0 },
+{ 0x10b7, 0x0101, 0x10b7, 0 },
+{ 0x10b8, 0x0101, 0x10b8, 0 },
+{ 0x10b9, 0x0101, 0x10b9, 0 },
+{ 0x10ba, 0x0101, 0x10ba, 0 },
+{ 0x10bb, 0x0101, 0x10bb, 0 },
+{ 0x10bc, 0x0101, 0x10bc, 0 },
+{ 0x10bd, 0x0101, 0x10bd, 0 },
+{ 0x10be, 0x0101, 0x10be, 0 },
+{ 0x10bf, 0x0101, 0x10bf, 0 },
+{ 0x10c0, 0x0101, 0x10c0, 0 },
+{ 0x10c1, 0x0101, 0x10c1, 0 },
+{ 0x10c2, 0x0101, 0x10c2, 0 },
+{ 0x10c3, 0x0101, 0x10c3, 0 },
+{ 0x10c4, 0x0101, 0x10c4, 0 },
+{ 0x10c5, 0x0101, 0x10c5, 0 },
+{ 0x10d0, 0x0102, 0x10d0, 0 },
+{ 0x10d1, 0x0102, 0x10d1, 0 },
+{ 0x10d2, 0x0102, 0x10d2, 0 },
+{ 0x10d3, 0x0102, 0x10d3, 0 },
+{ 0x10d4, 0x0102, 0x10d4, 0 },
+{ 0x10d5, 0x0102, 0x10d5, 0 },
+{ 0x10d6, 0x0102, 0x10d6, 0 },
+{ 0x10d7, 0x0102, 0x10d7, 0 },
+{ 0x10d8, 0x0102, 0x10d8, 0 },
+{ 0x10d9, 0x0102, 0x10d9, 0 },
+{ 0x10da, 0x0102, 0x10da, 0 },
+{ 0x10db, 0x0102, 0x10db, 0 },
+{ 0x10dc, 0x0102, 0x10dc, 0 },
+{ 0x10dd, 0x0102, 0x10dd, 0 },
+{ 0x10de, 0x0102, 0x10de, 0 },
+{ 0x10df, 0x0102, 0x10df, 0 },
+{ 0x10e0, 0x0102, 0x10e0, 0 },
+{ 0x10e1, 0x0102, 0x10e1, 0 },
+{ 0x10e2, 0x0102, 0x10e2, 0 },
+{ 0x10e3, 0x0102, 0x10e3, 0 },
+{ 0x10e4, 0x0102, 0x10e4, 0 },
+{ 0x10e5, 0x0102, 0x10e5, 0 },
+{ 0x10e6, 0x0102, 0x10e6, 0 },
+{ 0x10e7, 0x0102, 0x10e7, 0 },
+{ 0x10e8, 0x0102, 0x10e8, 0 },
+{ 0x10e9, 0x0102, 0x10e9, 0 },
+{ 0x10ea, 0x0102, 0x10ea, 0 },
+{ 0x10eb, 0x0102, 0x10eb, 0 },
+{ 0x10ec, 0x0102, 0x10ec, 0 },
+{ 0x10ed, 0x0102, 0x10ed, 0 },
+{ 0x10ee, 0x0102, 0x10ee, 0 },
+{ 0x10ef, 0x0102, 0x10ef, 0 },
+{ 0x10f0, 0x0102, 0x10f0, 0 },
+{ 0x10f1, 0x0102, 0x10f1, 0 },
+{ 0x10f2, 0x0102, 0x10f2, 0 },
+{ 0x10f3, 0x0102, 0x10f3, 0 },
+{ 0x10f4, 0x0102, 0x10f4, 0 },
+{ 0x10f5, 0x0102, 0x10f5, 0 },
+{ 0x10f6, 0x0102, 0x10f6, 0 },
+{ 0x10fb, 0x0010, 0x0000, 0 },
+{ 0x1100, 0x0100, 0x0000, 239 },
+{ 0x1e00, 0x0101, 0x1e00, 0 },
+{ 0x1e01, 0x0102, 0x1e01, 0 },
+{ 0x1e02, 0x0101, 0x1e02, 0 },
+{ 0x1e03, 0x0102, 0x1e03, 0 },
+{ 0x1e04, 0x0101, 0x1e04, 0 },
+{ 0x1e05, 0x0102, 0x1e05, 0 },
+{ 0x1e06, 0x0101, 0x1e06, 0 },
+{ 0x1e07, 0x0102, 0x1e07, 0 },
+{ 0x1e08, 0x0101, 0x1e08, 0 },
+{ 0x1e09, 0x0102, 0x1e09, 0 },
+{ 0x1e0a, 0x0101, 0x1e0a, 0 },
+{ 0x1e0b, 0x0102, 0x1e0b, 0 },
+{ 0x1e0c, 0x0101, 0x1e0c, 0 },
+{ 0x1e0d, 0x0102, 0x1e0d, 0 },
+{ 0x1e0e, 0x0101, 0x1e0e, 0 },
+{ 0x1e0f, 0x0102, 0x1e0f, 0 },
+{ 0x1e10, 0x0101, 0x1e10, 0 },
+{ 0x1e11, 0x0102, 0x1e11, 0 },
+{ 0x1e12, 0x0101, 0x1e12, 0 },
+{ 0x1e13, 0x0102, 0x1e13, 0 },
+{ 0x1e14, 0x0101, 0x1e14, 0 },
+{ 0x1e15, 0x0102, 0x1e15, 0 },
+{ 0x1e16, 0x0101, 0x1e16, 0 },
+{ 0x1e17, 0x0102, 0x1e17, 0 },
+{ 0x1e18, 0x0101, 0x1e18, 0 },
+{ 0x1e19, 0x0102, 0x1e19, 0 },
+{ 0x1e1a, 0x0101, 0x1e1a, 0 },
+{ 0x1e1b, 0x0102, 0x1e1b, 0 },
+{ 0x1e1c, 0x0101, 0x1e1c, 0 },
+{ 0x1e1d, 0x0102, 0x1e1d, 0 },
+{ 0x1e1e, 0x0101, 0x1e1e, 0 },
+{ 0x1e1f, 0x0102, 0x1e1f, 0 },
+{ 0x1e20, 0x0101, 0x1e20, 0 },
+{ 0x1e21, 0x0102, 0x1e21, 0 },
+{ 0x1e22, 0x0101, 0x1e22, 0 },
+{ 0x1e23, 0x0102, 0x1e23, 0 },
+{ 0x1e24, 0x0101, 0x1e24, 0 },
+{ 0x1e25, 0x0102, 0x1e25, 0 },
+{ 0x1e26, 0x0101, 0x1e26, 0 },
+{ 0x1e27, 0x0102, 0x1e27, 0 },
+{ 0x1e28, 0x0101, 0x1e28, 0 },
+{ 0x1e29, 0x0102, 0x1e29, 0 },
+{ 0x1e2a, 0x0101, 0x1e2a, 0 },
+{ 0x1e2b, 0x0102, 0x1e2b, 0 },
+{ 0x1e2c, 0x0101, 0x1e2c, 0 },
+{ 0x1e2d, 0x0102, 0x1e2d, 0 },
+{ 0x1e2e, 0x0101, 0x1e2e, 0 },
+{ 0x1e2f, 0x0102, 0x1e2f, 0 },
+{ 0x1e30, 0x0101, 0x1e30, 0 },
+{ 0x1e31, 0x0102, 0x1e31, 0 },
+{ 0x1e32, 0x0101, 0x1e32, 0 },
+{ 0x1e33, 0x0102, 0x1e33, 0 },
+{ 0x1e34, 0x0101, 0x1e34, 0 },
+{ 0x1e35, 0x0102, 0x1e35, 0 },
+{ 0x1e36, 0x0101, 0x1e36, 0 },
+{ 0x1e37, 0x0102, 0x1e37, 0 },
+{ 0x1e38, 0x0101, 0x1e38, 0 },
+{ 0x1e39, 0x0102, 0x1e39, 0 },
+{ 0x1e3a, 0x0101, 0x1e3a, 0 },
+{ 0x1e3b, 0x0102, 0x1e3b, 0 },
+{ 0x1e3c, 0x0101, 0x1e3c, 0 },
+{ 0x1e3d, 0x0102, 0x1e3d, 0 },
+{ 0x1e3e, 0x0101, 0x1e3e, 0 },
+{ 0x1e3f, 0x0102, 0x1e3f, 0 },
+{ 0x1e40, 0x0101, 0x1e40, 0 },
+{ 0x1e41, 0x0102, 0x1e41, 0 },
+{ 0x1e42, 0x0101, 0x1e42, 0 },
+{ 0x1e43, 0x0102, 0x1e43, 0 },
+{ 0x1e44, 0x0101, 0x1e44, 0 },
+{ 0x1e45, 0x0102, 0x1e45, 0 },
+{ 0x1e46, 0x0101, 0x1e46, 0 },
+{ 0x1e47, 0x0102, 0x1e47, 0 },
+{ 0x1e48, 0x0101, 0x1e48, 0 },
+{ 0x1e49, 0x0102, 0x1e49, 0 },
+{ 0x1e4a, 0x0101, 0x1e4a, 0 },
+{ 0x1e4b, 0x0102, 0x1e4b, 0 },
+{ 0x1e4c, 0x0101, 0x1e4c, 0 },
+{ 0x1e4d, 0x0102, 0x1e4d, 0 },
+{ 0x1e4e, 0x0101, 0x1e4e, 0 },
+{ 0x1e4f, 0x0102, 0x1e4f, 0 },
+{ 0x1e50, 0x0101, 0x1e50, 0 },
+{ 0x1e51, 0x0102, 0x1e51, 0 },
+{ 0x1e52, 0x0101, 0x1e52, 0 },
+{ 0x1e53, 0x0102, 0x1e53, 0 },
+{ 0x1e54, 0x0101, 0x1e54, 0 },
+{ 0x1e55, 0x0102, 0x1e55, 0 },
+{ 0x1e56, 0x0101, 0x1e56, 0 },
+{ 0x1e57, 0x0102, 0x1e57, 0 },
+{ 0x1e58, 0x0101, 0x1e58, 0 },
+{ 0x1e59, 0x0102, 0x1e59, 0 },
+{ 0x1e5a, 0x0101, 0x1e5a, 0 },
+{ 0x1e5b, 0x0102, 0x1e5b, 0 },
+{ 0x1e5c, 0x0101, 0x1e5c, 0 },
+{ 0x1e5d, 0x0102, 0x1e5d, 0 },
+{ 0x1e5e, 0x0101, 0x1e5e, 0 },
+{ 0x1e5f, 0x0102, 0x1e5f, 0 },
+{ 0x1e60, 0x0101, 0x1e60, 0 },
+{ 0x1e61, 0x0102, 0x1e61, 0 },
+{ 0x1e62, 0x0101, 0x1e62, 0 },
+{ 0x1e63, 0x0102, 0x1e63, 0 },
+{ 0x1e64, 0x0101, 0x1e64, 0 },
+{ 0x1e65, 0x0102, 0x1e65, 0 },
+{ 0x1e66, 0x0101, 0x1e66, 0 },
+{ 0x1e67, 0x0102, 0x1e67, 0 },
+{ 0x1e68, 0x0101, 0x1e68, 0 },
+{ 0x1e69, 0x0102, 0x1e69, 0 },
+{ 0x1e6a, 0x0101, 0x1e6a, 0 },
+{ 0x1e6b, 0x0102, 0x1e6b, 0 },
+{ 0x1e6c, 0x0101, 0x1e6c, 0 },
+{ 0x1e6d, 0x0102, 0x1e6d, 0 },
+{ 0x1e6e, 0x0101, 0x1e6e, 0 },
+{ 0x1e6f, 0x0102, 0x1e6f, 0 },
+{ 0x1e70, 0x0101, 0x1e70, 0 },
+{ 0x1e71, 0x0102, 0x1e71, 0 },
+{ 0x1e72, 0x0101, 0x1e72, 0 },
+{ 0x1e73, 0x0102, 0x1e73, 0 },
+{ 0x1e74, 0x0101, 0x1e74, 0 },
+{ 0x1e75, 0x0102, 0x1e75, 0 },
+{ 0x1e76, 0x0101, 0x1e76, 0 },
+{ 0x1e77, 0x0102, 0x1e77, 0 },
+{ 0x1e78, 0x0101, 0x1e78, 0 },
+{ 0x1e79, 0x0102, 0x1e79, 0 },
+{ 0x1e7a, 0x0101, 0x1e7a, 0 },
+{ 0x1e7b, 0x0102, 0x1e7b, 0 },
+{ 0x1e7c, 0x0101, 0x1e7c, 0 },
+{ 0x1e7d, 0x0102, 0x1e7d, 0 },
+{ 0x1e7e, 0x0101, 0x1e7e, 0 },
+{ 0x1e7f, 0x0102, 0x1e7f, 0 },
+{ 0x1e80, 0x0101, 0x1e80, 0 },
+{ 0x1e81, 0x0102, 0x1e81, 0 },
+{ 0x1e82, 0x0101, 0x1e82, 0 },
+{ 0x1e83, 0x0102, 0x1e83, 0 },
+{ 0x1e84, 0x0101, 0x1e84, 0 },
+{ 0x1e85, 0x0102, 0x1e85, 0 },
+{ 0x1e86, 0x0101, 0x1e86, 0 },
+{ 0x1e87, 0x0102, 0x1e87, 0 },
+{ 0x1e88, 0x0101, 0x1e88, 0 },
+{ 0x1e89, 0x0102, 0x1e89, 0 },
+{ 0x1e8a, 0x0101, 0x1e8a, 0 },
+{ 0x1e8b, 0x0102, 0x1e8b, 0 },
+{ 0x1e8c, 0x0101, 0x1e8c, 0 },
+{ 0x1e8d, 0x0102, 0x1e8d, 0 },
+{ 0x1e8e, 0x0101, 0x1e8e, 0 },
+{ 0x1e8f, 0x0102, 0x1e8f, 0 },
+{ 0x1e90, 0x0101, 0x1e90, 0 },
+{ 0x1e91, 0x0102, 0x1e91, 0 },
+{ 0x1e92, 0x0101, 0x1e92, 0 },
+{ 0x1e93, 0x0102, 0x1e93, 0 },
+{ 0x1e94, 0x0101, 0x1e94, 0 },
+{ 0x1e95, 0x0102, 0x1e95, 0 },
+{ 0x1e96, 0x0102, 0x1e96, 0 },
+{ 0x1e97, 0x0102, 0x1e97, 0 },
+{ 0x1e98, 0x0102, 0x1e98, 0 },
+{ 0x1e99, 0x0102, 0x1e99, 0 },
+{ 0x1e9a, 0x0102, 0x1e9a, 0 },
+{ 0x1e9b, 0x0102, 0x1e9b, 0 },
+{ 0x1ea0, 0x0101, 0x1ea0, 0 },
+{ 0x1ea1, 0x0102, 0x1ea1, 0 },
+{ 0x1ea2, 0x0101, 0x1ea2, 0 },
+{ 0x1ea3, 0x0102, 0x1ea3, 0 },
+{ 0x1ea4, 0x0101, 0x1ea4, 0 },
+{ 0x1ea5, 0x0102, 0x1ea5, 0 },
+{ 0x1ea6, 0x0101, 0x1ea6, 0 },
+{ 0x1ea7, 0x0102, 0x1ea7, 0 },
+{ 0x1ea8, 0x0101, 0x1ea8, 0 },
+{ 0x1ea9, 0x0102, 0x1ea9, 0 },
+{ 0x1eaa, 0x0101, 0x1eaa, 0 },
+{ 0x1eab, 0x0102, 0x1eab, 0 },
+{ 0x1eac, 0x0101, 0x1eac, 0 },
+{ 0x1ead, 0x0102, 0x1ead, 0 },
+{ 0x1eae, 0x0101, 0x1eae, 0 },
+{ 0x1eaf, 0x0102, 0x1eaf, 0 },
+{ 0x1eb0, 0x0101, 0x1eb0, 0 },
+{ 0x1eb1, 0x0102, 0x1eb1, 0 },
+{ 0x1eb2, 0x0101, 0x1eb2, 0 },
+{ 0x1eb3, 0x0102, 0x1eb3, 0 },
+{ 0x1eb4, 0x0101, 0x1eb4, 0 },
+{ 0x1eb5, 0x0102, 0x1eb5, 0 },
+{ 0x1eb6, 0x0101, 0x1eb6, 0 },
+{ 0x1eb7, 0x0102, 0x1eb7, 0 },
+{ 0x1eb8, 0x0101, 0x1eb8, 0 },
+{ 0x1eb9, 0x0102, 0x1eb9, 0 },
+{ 0x1eba, 0x0101, 0x1eba, 0 },
+{ 0x1ebb, 0x0102, 0x1ebb, 0 },
+{ 0x1ebc, 0x0101, 0x1ebc, 0 },
+{ 0x1ebd, 0x0102, 0x1ebd, 0 },
+{ 0x1ebe, 0x0101, 0x1ebe, 0 },
+{ 0x1ebf, 0x0102, 0x1ebf, 0 },
+{ 0x1ec0, 0x0101, 0x1ec0, 0 },
+{ 0x1ec1, 0x0102, 0x1ec1, 0 },
+{ 0x1ec2, 0x0101, 0x1ec2, 0 },
+{ 0x1ec3, 0x0102, 0x1ec3, 0 },
+{ 0x1ec4, 0x0101, 0x1ec4, 0 },
+{ 0x1ec5, 0x0102, 0x1ec5, 0 },
+{ 0x1ec6, 0x0101, 0x1ec6, 0 },
+{ 0x1ec7, 0x0102, 0x1ec7, 0 },
+{ 0x1ec8, 0x0101, 0x1ec8, 0 },
+{ 0x1ec9, 0x0102, 0x1ec9, 0 },
+{ 0x1eca, 0x0101, 0x1eca, 0 },
+{ 0x1ecb, 0x0102, 0x1ecb, 0 },
+{ 0x1ecc, 0x0101, 0x1ecc, 0 },
+{ 0x1ecd, 0x0102, 0x1ecd, 0 },
+{ 0x1ece, 0x0101, 0x1ece, 0 },
+{ 0x1ecf, 0x0102, 0x1ecf, 0 },
+{ 0x1ed0, 0x0101, 0x1ed0, 0 },
+{ 0x1ed1, 0x0102, 0x1ed1, 0 },
+{ 0x1ed2, 0x0101, 0x1ed2, 0 },
+{ 0x1ed3, 0x0102, 0x1ed3, 0 },
+{ 0x1ed4, 0x0101, 0x1ed4, 0 },
+{ 0x1ed5, 0x0102, 0x1ed5, 0 },
+{ 0x1ed6, 0x0101, 0x1ed6, 0 },
+{ 0x1ed7, 0x0102, 0x1ed7, 0 },
+{ 0x1ed8, 0x0101, 0x1ed8, 0 },
+{ 0x1ed9, 0x0102, 0x1ed9, 0 },
+{ 0x1eda, 0x0101, 0x1eda, 0 },
+{ 0x1edb, 0x0102, 0x1edb, 0 },
+{ 0x1edc, 0x0101, 0x1edc, 0 },
+{ 0x1edd, 0x0102, 0x1edd, 0 },
+{ 0x1ede, 0x0101, 0x1ede, 0 },
+{ 0x1edf, 0x0102, 0x1edf, 0 },
+{ 0x1ee0, 0x0101, 0x1ee0, 0 },
+{ 0x1ee1, 0x0102, 0x1ee1, 0 },
+{ 0x1ee2, 0x0101, 0x1ee2, 0 },
+{ 0x1ee3, 0x0102, 0x1ee3, 0 },
+{ 0x1ee4, 0x0101, 0x1ee4, 0 },
+{ 0x1ee5, 0x0102, 0x1ee5, 0 },
+{ 0x1ee6, 0x0101, 0x1ee6, 0 },
+{ 0x1ee7, 0x0102, 0x1ee7, 0 },
+{ 0x1ee8, 0x0101, 0x1ee8, 0 },
+{ 0x1ee9, 0x0102, 0x1ee9, 0 },
+{ 0x1eea, 0x0101, 0x1eea, 0 },
+{ 0x1eeb, 0x0102, 0x1eeb, 0 },
+{ 0x1eec, 0x0101, 0x1eec, 0 },
+{ 0x1eed, 0x0102, 0x1eed, 0 },
+{ 0x1eee, 0x0101, 0x1eee, 0 },
+{ 0x1eef, 0x0102, 0x1eef, 0 },
+{ 0x1ef0, 0x0101, 0x1ef0, 0 },
+{ 0x1ef1, 0x0102, 0x1ef1, 0 },
+{ 0x1ef2, 0x0101, 0x1ef2, 0 },
+{ 0x1ef3, 0x0102, 0x1ef3, 0 },
+{ 0x1ef4, 0x0101, 0x1ef4, 0 },
+{ 0x1ef5, 0x0102, 0x1ef5, 0 },
+{ 0x1ef6, 0x0101, 0x1ef6, 0 },
+{ 0x1ef7, 0x0102, 0x1ef7, 0 },
+{ 0x1ef8, 0x0101, 0x1ef8, 0 },
+{ 0x1ef9, 0x0102, 0x1ef9, 0 },
+{ 0x1f00, 0x0102, 0x1f00, 0 },
+{ 0x1f01, 0x0102, 0x1f01, 0 },
+{ 0x1f02, 0x0102, 0x1f02, 0 },
+{ 0x1f03, 0x0102, 0x1f03, 0 },
+{ 0x1f04, 0x0102, 0x1f04, 0 },
+{ 0x1f05, 0x0102, 0x1f05, 0 },
+{ 0x1f06, 0x0102, 0x1f06, 0 },
+{ 0x1f07, 0x0102, 0x1f07, 0 },
+{ 0x1f08, 0x0101, 0x1f08, 0 },
+{ 0x1f09, 0x0101, 0x1f09, 0 },
+{ 0x1f0a, 0x0101, 0x1f0a, 0 },
+{ 0x1f0b, 0x0101, 0x1f0b, 0 },
+{ 0x1f0c, 0x0101, 0x1f0c, 0 },
+{ 0x1f0d, 0x0101, 0x1f0d, 0 },
+{ 0x1f0e, 0x0101, 0x1f0e, 0 },
+{ 0x1f0f, 0x0101, 0x1f0f, 0 },
+{ 0x1f10, 0x0102, 0x1f10, 0 },
+{ 0x1f11, 0x0102, 0x1f11, 0 },
+{ 0x1f12, 0x0102, 0x1f12, 0 },
+{ 0x1f13, 0x0102, 0x1f13, 0 },
+{ 0x1f14, 0x0102, 0x1f14, 0 },
+{ 0x1f15, 0x0102, 0x1f15, 0 },
+{ 0x1f18, 0x0101, 0x1f18, 0 },
+{ 0x1f19, 0x0101, 0x1f19, 0 },
+{ 0x1f1a, 0x0101, 0x1f1a, 0 },
+{ 0x1f1b, 0x0101, 0x1f1b, 0 },
+{ 0x1f1c, 0x0101, 0x1f1c, 0 },
+{ 0x1f1d, 0x0101, 0x1f1d, 0 },
+{ 0x1f20, 0x0102, 0x1f20, 0 },
+{ 0x1f21, 0x0102, 0x1f21, 0 },
+{ 0x1f22, 0x0102, 0x1f22, 0 },
+{ 0x1f23, 0x0102, 0x1f23, 0 },
+{ 0x1f24, 0x0102, 0x1f24, 0 },
+{ 0x1f25, 0x0102, 0x1f25, 0 },
+{ 0x1f26, 0x0102, 0x1f26, 0 },
+{ 0x1f27, 0x0102, 0x1f27, 0 },
+{ 0x1f28, 0x0101, 0x1f28, 0 },
+{ 0x1f29, 0x0101, 0x1f29, 0 },
+{ 0x1f2a, 0x0101, 0x1f2a, 0 },
+{ 0x1f2b, 0x0101, 0x1f2b, 0 },
+{ 0x1f2c, 0x0101, 0x1f2c, 0 },
+{ 0x1f2d, 0x0101, 0x1f2d, 0 },
+{ 0x1f2e, 0x0101, 0x1f2e, 0 },
+{ 0x1f2f, 0x0101, 0x1f2f, 0 },
+{ 0x1f30, 0x0102, 0x1f30, 0 },
+{ 0x1f31, 0x0102, 0x1f31, 0 },
+{ 0x1f32, 0x0102, 0x1f32, 0 },
+{ 0x1f33, 0x0102, 0x1f33, 0 },
+{ 0x1f34, 0x0102, 0x1f34, 0 },
+{ 0x1f35, 0x0102, 0x1f35, 0 },
+{ 0x1f36, 0x0102, 0x1f36, 0 },
+{ 0x1f37, 0x0102, 0x1f37, 0 },
+{ 0x1f38, 0x0101, 0x1f38, 0 },
+{ 0x1f39, 0x0101, 0x1f39, 0 },
+{ 0x1f3a, 0x0101, 0x1f3a, 0 },
+{ 0x1f3b, 0x0101, 0x1f3b, 0 },
+{ 0x1f3c, 0x0101, 0x1f3c, 0 },
+{ 0x1f3d, 0x0101, 0x1f3d, 0 },
+{ 0x1f3e, 0x0101, 0x1f3e, 0 },
+{ 0x1f3f, 0x0101, 0x1f3f, 0 },
+{ 0x1f40, 0x0102, 0x1f40, 0 },
+{ 0x1f41, 0x0102, 0x1f41, 0 },
+{ 0x1f42, 0x0102, 0x1f42, 0 },
+{ 0x1f43, 0x0102, 0x1f43, 0 },
+{ 0x1f44, 0x0102, 0x1f44, 0 },
+{ 0x1f45, 0x0102, 0x1f45, 0 },
+{ 0x1f48, 0x0101, 0x1f48, 0 },
+{ 0x1f49, 0x0101, 0x1f49, 0 },
+{ 0x1f4a, 0x0101, 0x1f4a, 0 },
+{ 0x1f4b, 0x0101, 0x1f4b, 0 },
+{ 0x1f4c, 0x0101, 0x1f4c, 0 },
+{ 0x1f4d, 0x0101, 0x1f4d, 0 },
+{ 0x1f50, 0x0102, 0x1f50, 0 },
+{ 0x1f51, 0x0102, 0x1f51, 0 },
+{ 0x1f52, 0x0102, 0x1f52, 0 },
+{ 0x1f53, 0x0102, 0x1f53, 0 },
+{ 0x1f54, 0x0102, 0x1f54, 0 },
+{ 0x1f55, 0x0102, 0x1f55, 0 },
+{ 0x1f56, 0x0102, 0x1f56, 0 },
+{ 0x1f57, 0x0102, 0x1f57, 0 },
+{ 0x1f59, 0x0101, 0x1f59, 0 },
+{ 0x1f5b, 0x0101, 0x1f5b, 0 },
+{ 0x1f5d, 0x0101, 0x1f5d, 0 },
+{ 0x1f5f, 0x0101, 0x1f5f, 0 },
+{ 0x1f60, 0x0102, 0x1f60, 0 },
+{ 0x1f61, 0x0102, 0x1f61, 0 },
+{ 0x1f62, 0x0102, 0x1f62, 0 },
+{ 0x1f63, 0x0102, 0x1f63, 0 },
+{ 0x1f64, 0x0102, 0x1f64, 0 },
+{ 0x1f65, 0x0102, 0x1f65, 0 },
+{ 0x1f66, 0x0102, 0x1f66, 0 },
+{ 0x1f67, 0x0102, 0x1f67, 0 },
+{ 0x1f68, 0x0101, 0x1f68, 0 },
+{ 0x1f69, 0x0101, 0x1f69, 0 },
+{ 0x1f6a, 0x0101, 0x1f6a, 0 },
+{ 0x1f6b, 0x0101, 0x1f6b, 0 },
+{ 0x1f6c, 0x0101, 0x1f6c, 0 },
+{ 0x1f6d, 0x0101, 0x1f6d, 0 },
+{ 0x1f6e, 0x0101, 0x1f6e, 0 },
+{ 0x1f6f, 0x0101, 0x1f6f, 0 },
+{ 0x1f70, 0x0102, 0x1f70, 0 },
+{ 0x1f71, 0x0102, 0x1f71, 0 },
+{ 0x1f72, 0x0102, 0x1f72, 0 },
+{ 0x1f73, 0x0102, 0x1f73, 0 },
+{ 0x1f74, 0x0102, 0x1f74, 0 },
+{ 0x1f75, 0x0102, 0x1f75, 0 },
+{ 0x1f76, 0x0102, 0x1f76, 0 },
+{ 0x1f77, 0x0102, 0x1f77, 0 },
+{ 0x1f78, 0x0102, 0x1f78, 0 },
+{ 0x1f79, 0x0102, 0x1f79, 0 },
+{ 0x1f7a, 0x0102, 0x1f7a, 0 },
+{ 0x1f7b, 0x0102, 0x1f7b, 0 },
+{ 0x1f7c, 0x0102, 0x1f7c, 0 },
+{ 0x1f7d, 0x0102, 0x1f7d, 0 },
+{ 0x1f80, 0x0102, 0x1f80, 0 },
+{ 0x1f81, 0x0102, 0x1f81, 0 },
+{ 0x1f82, 0x0102, 0x1f82, 0 },
+{ 0x1f83, 0x0102, 0x1f83, 0 },
+{ 0x1f84, 0x0102, 0x1f84, 0 },
+{ 0x1f85, 0x0102, 0x1f85, 0 },
+{ 0x1f86, 0x0102, 0x1f86, 0 },
+{ 0x1f87, 0x0102, 0x1f87, 0 },
+{ 0x1f88, 0x0101, 0x1f88, 0 },
+{ 0x1f89, 0x0101, 0x1f89, 0 },
+{ 0x1f8a, 0x0101, 0x1f8a, 0 },
+{ 0x1f8b, 0x0101, 0x1f8b, 0 },
+{ 0x1f8c, 0x0101, 0x1f8c, 0 },
+{ 0x1f8d, 0x0101, 0x1f8d, 0 },
+{ 0x1f8e, 0x0101, 0x1f8e, 0 },
+{ 0x1f8f, 0x0101, 0x1f8f, 0 },
+{ 0x1f90, 0x0102, 0x1f90, 0 },
+{ 0x1f91, 0x0102, 0x1f91, 0 },
+{ 0x1f92, 0x0102, 0x1f92, 0 },
+{ 0x1f93, 0x0102, 0x1f93, 0 },
+{ 0x1f94, 0x0102, 0x1f94, 0 },
+{ 0x1f95, 0x0102, 0x1f95, 0 },
+{ 0x1f96, 0x0102, 0x1f96, 0 },
+{ 0x1f97, 0x0102, 0x1f97, 0 },
+{ 0x1f98, 0x0101, 0x1f98, 0 },
+{ 0x1f99, 0x0101, 0x1f99, 0 },
+{ 0x1f9a, 0x0101, 0x1f9a, 0 },
+{ 0x1f9b, 0x0101, 0x1f9b, 0 },
+{ 0x1f9c, 0x0101, 0x1f9c, 0 },
+{ 0x1f9d, 0x0101, 0x1f9d, 0 },
+{ 0x1f9e, 0x0101, 0x1f9e, 0 },
+{ 0x1f9f, 0x0101, 0x1f9f, 0 },
+{ 0x1fa0, 0x0102, 0x1fa0, 0 },
+{ 0x1fa1, 0x0102, 0x1fa1, 0 },
+{ 0x1fa2, 0x0102, 0x1fa2, 0 },
+{ 0x1fa3, 0x0102, 0x1fa3, 0 },
+{ 0x1fa4, 0x0102, 0x1fa4, 0 },
+{ 0x1fa5, 0x0102, 0x1fa5, 0 },
+{ 0x1fa6, 0x0102, 0x1fa6, 0 },
+{ 0x1fa7, 0x0102, 0x1fa7, 0 },
+{ 0x1fa8, 0x0101, 0x1fa8, 0 },
+{ 0x1fa9, 0x0101, 0x1fa9, 0 },
+{ 0x1faa, 0x0101, 0x1faa, 0 },
+{ 0x1fab, 0x0101, 0x1fab, 0 },
+{ 0x1fac, 0x0101, 0x1fac, 0 },
+{ 0x1fad, 0x0101, 0x1fad, 0 },
+{ 0x1fae, 0x0101, 0x1fae, 0 },
+{ 0x1faf, 0x0101, 0x1faf, 0 },
+{ 0x1fb0, 0x0102, 0x1fb0, 0 },
+{ 0x1fb1, 0x0102, 0x1fb1, 0 },
+{ 0x1fb2, 0x0102, 0x1fb2, 0 },
+{ 0x1fb3, 0x0102, 0x1fb3, 0 },
+{ 0x1fb4, 0x0102, 0x1fb4, 0 },
+{ 0x1fb6, 0x0102, 0x1fb6, 0 },
+{ 0x1fb7, 0x0102, 0x1fb7, 0 },
+{ 0x1fb8, 0x0101, 0x1fb8, 0 },
+{ 0x1fb9, 0x0101, 0x1fb9, 0 },
+{ 0x1fba, 0x0101, 0x1fba, 0 },
+{ 0x1fbb, 0x0101, 0x1fbb, 0 },
+{ 0x1fbc, 0x0101, 0x1fbc, 0 },
+{ 0x1fbd, 0x0010, 0x0000, 4 },
+{ 0x1fc2, 0x0102, 0x1fc2, 0 },
+{ 0x1fc3, 0x0102, 0x1fc3, 0 },
+{ 0x1fc4, 0x0102, 0x1fc4, 0 },
+{ 0x1fc6, 0x0102, 0x1fc6, 0 },
+{ 0x1fc7, 0x0102, 0x1fc7, 0 },
+{ 0x1fc8, 0x0101, 0x1fc8, 0 },
+{ 0x1fc9, 0x0101, 0x1fc9, 0 },
+{ 0x1fca, 0x0101, 0x1fca, 0 },
+{ 0x1fcb, 0x0101, 0x1fcb, 0 },
+{ 0x1fcc, 0x0101, 0x1fcc, 0 },
+{ 0x1fcd, 0x0010, 0x0000, 2 },
+{ 0x1fd0, 0x0102, 0x1fd0, 0 },
+{ 0x1fd1, 0x0102, 0x1fd1, 0 },
+{ 0x1fd2, 0x0102, 0x1fd2, 0 },
+{ 0x1fd3, 0x0102, 0x1fd3, 0 },
+{ 0x1fd6, 0x0102, 0x1fd6, 0 },
+{ 0x1fd7, 0x0102, 0x1fd7, 0 },
+{ 0x1fd8, 0x0101, 0x1fd8, 0 },
+{ 0x1fd9, 0x0101, 0x1fd9, 0 },
+{ 0x1fda, 0x0101, 0x1fda, 0 },
+{ 0x1fdb, 0x0101, 0x1fdb, 0 },
+{ 0x1fdd, 0x0010, 0x0000, 2 },
+{ 0x1fe0, 0x0102, 0x1fe0, 0 },
+{ 0x1fe1, 0x0102, 0x1fe1, 0 },
+{ 0x1fe2, 0x0102, 0x1fe2, 0 },
+{ 0x1fe3, 0x0102, 0x1fe3, 0 },
+{ 0x1fe4, 0x0102, 0x1fe4, 0 },
+{ 0x1fe5, 0x0102, 0x1fe5, 0 },
+{ 0x1fe6, 0x0102, 0x1fe6, 0 },
+{ 0x1fe7, 0x0102, 0x1fe7, 0 },
+{ 0x1fe8, 0x0101, 0x1fe8, 0 },
+{ 0x1fe9, 0x0101, 0x1fe9, 0 },
+{ 0x1fea, 0x0101, 0x1fea, 0 },
+{ 0x1feb, 0x0101, 0x1feb, 0 },
+{ 0x1fec, 0x0101, 0x1fec, 0 },
+{ 0x1fed, 0x0010, 0x0000, 2 },
+{ 0x1ff2, 0x0102, 0x1ff2, 0 },
+{ 0x1ff3, 0x0102, 0x1ff3, 0 },
+{ 0x1ff4, 0x0102, 0x1ff4, 0 },
+{ 0x1ff6, 0x0102, 0x1ff6, 0 },
+{ 0x1ff7, 0x0102, 0x1ff7, 0 },
+{ 0x1ff8, 0x0101, 0x1ff8, 0 },
+{ 0x1ff9, 0x0101, 0x1ff9, 0 },
+{ 0x1ffa, 0x0101, 0x1ffa, 0 },
+{ 0x1ffb, 0x0101, 0x1ffb, 0 },
+{ 0x1ffc, 0x0101, 0x1ffc, 0 },
+{ 0x1ffd, 0x0010, 0x0000, 1 },
+{ 0x2000, 0x0018, 0x0000, 11 },
+{ 0x200c, 0x0030, 0x0000, 3 },
+{ 0x2010, 0x0010, 0x0000, 23 },
+{ 0x2028, 0x0030, 0x0000, 6 },
+{ 0x2030, 0x0010, 0x0000, 22 },
+{ 0x206a, 0x0030, 0x0000, 5 },
+{ 0x2070, 0x0004, 0x0000, 6 },
+{ 0x207a, 0x0010, 0x0000, 5 },
+{ 0x2080, 0x0004, 0x0000, 9 },
+{ 0x208a, 0x0010, 0x0000, 703 },
+{ 0x249c, 0x0112, 0x249c, 0 },
+{ 0x249d, 0x0112, 0x249d, 0 },
+{ 0x249e, 0x0112, 0x249e, 0 },
+{ 0x249f, 0x0112, 0x249f, 0 },
+{ 0x24a0, 0x0112, 0x24a0, 0 },
+{ 0x24a1, 0x0112, 0x24a1, 0 },
+{ 0x24a2, 0x0112, 0x24a2, 0 },
+{ 0x24a3, 0x0112, 0x24a3, 0 },
+{ 0x24a4, 0x0112, 0x24a4, 0 },
+{ 0x24a5, 0x0112, 0x24a5, 0 },
+{ 0x24a6, 0x0112, 0x24a6, 0 },
+{ 0x24a7, 0x0112, 0x24a7, 0 },
+{ 0x24a8, 0x0112, 0x24a8, 0 },
+{ 0x24a9, 0x0112, 0x24a9, 0 },
+{ 0x24aa, 0x0112, 0x24aa, 0 },
+{ 0x24ab, 0x0112, 0x24ab, 0 },
+{ 0x24ac, 0x0112, 0x24ac, 0 },
+{ 0x24ad, 0x0112, 0x24ad, 0 },
+{ 0x24ae, 0x0112, 0x24ae, 0 },
+{ 0x24af, 0x0112, 0x24af, 0 },
+{ 0x24b0, 0x0112, 0x24b0, 0 },
+{ 0x24b1, 0x0112, 0x24b1, 0 },
+{ 0x24b2, 0x0112, 0x24b2, 0 },
+{ 0x24b3, 0x0112, 0x24b3, 0 },
+{ 0x24b4, 0x0112, 0x24b4, 0 },
+{ 0x24b5, 0x0112, 0x24b5, 0 },
+{ 0x24b6, 0x0111, 0x24b6, 0 },
+{ 0x24b7, 0x0111, 0x24b7, 0 },
+{ 0x24b8, 0x0111, 0x24b8, 0 },
+{ 0x24b9, 0x0111, 0x24b9, 0 },
+{ 0x24ba, 0x0111, 0x24ba, 0 },
+{ 0x24bb, 0x0111, 0x24bb, 0 },
+{ 0x24bc, 0x0111, 0x24bc, 0 },
+{ 0x24bd, 0x0111, 0x24bd, 0 },
+{ 0x24be, 0x0111, 0x24be, 0 },
+{ 0x24bf, 0x0111, 0x24bf, 0 },
+{ 0x24c0, 0x0111, 0x24c0, 0 },
+{ 0x24c1, 0x0111, 0x24c1, 0 },
+{ 0x24c2, 0x0111, 0x24c2, 0 },
+{ 0x24c3, 0x0111, 0x24c3, 0 },
+{ 0x24c4, 0x0111, 0x24c4, 0 },
+{ 0x24c5, 0x0111, 0x24c5, 0 },
+{ 0x24c6, 0x0111, 0x24c6, 0 },
+{ 0x24c7, 0x0111, 0x24c7, 0 },
+{ 0x24c8, 0x0111, 0x24c8, 0 },
+{ 0x24c9, 0x0111, 0x24c9, 0 },
+{ 0x24ca, 0x0111, 0x24ca, 0 },
+{ 0x24cb, 0x0111, 0x24cb, 0 },
+{ 0x24cc, 0x0111, 0x24cc, 0 },
+{ 0x24cd, 0x0111, 0x24cd, 0 },
+{ 0x24ce, 0x0111, 0x24ce, 0 },
+{ 0x24cf, 0x0111, 0x24cf, 0 },
+{ 0x24d0, 0x0112, 0x24d0, 0 },
+{ 0x24d1, 0x0112, 0x24d1, 0 },
+{ 0x24d2, 0x0112, 0x24d2, 0 },
+{ 0x24d3, 0x0112, 0x24d3, 0 },
+{ 0x24d4, 0x0112, 0x24d4, 0 },
+{ 0x24d5, 0x0112, 0x24d5, 0 },
+{ 0x24d6, 0x0112, 0x24d6, 0 },
+{ 0x24d7, 0x0112, 0x24d7, 0 },
+{ 0x24d8, 0x0112, 0x24d8, 0 },
+{ 0x24d9, 0x0112, 0x24d9, 0 },
+{ 0x24da, 0x0112, 0x24da, 0 },
+{ 0x24db, 0x0112, 0x24db, 0 },
+{ 0x24dc, 0x0112, 0x24dc, 0 },
+{ 0x24dd, 0x0112, 0x24dd, 0 },
+{ 0x24de, 0x0112, 0x24de, 0 },
+{ 0x24df, 0x0112, 0x24df, 0 },
+{ 0x24e0, 0x0112, 0x24e0, 0 },
+{ 0x24e1, 0x0112, 0x24e1, 0 },
+{ 0x24e2, 0x0112, 0x24e2, 0 },
+{ 0x24e3, 0x0112, 0x24e3, 0 },
+{ 0x24e4, 0x0112, 0x24e4, 0 },
+{ 0x24e5, 0x0112, 0x24e5, 0 },
+{ 0x24e6, 0x0112, 0x24e6, 0 },
+{ 0x24e7, 0x0112, 0x24e7, 0 },
+{ 0x24e8, 0x0112, 0x24e8, 0 },
+{ 0x24e9, 0x0112, 0x24e9, 0 },
+{ 0x24ea, 0x0010, 0x0000, 496 },
+{ 0x3000, 0x0048, 0x0000, 0 },
+{ 0x3001, 0x0010, 0x0000, 3 },
+{ 0x3005, 0x0110, 0x0000, 0 },
+{ 0x3006, 0x0010, 0x0000, 0 },
+{ 0x3007, 0x0110, 0x0000, 0 },
+{ 0x3008, 0x0010, 0x0000, 48 },
+{ 0x3041, 0x0100, 0x0000, 83 },
+{ 0x3099, 0x0010, 0x0000, 1 },
+{ 0x309b, 0x0110, 0x0000, 3 },
+{ 0x30a1, 0x0100, 0x0000, 89 },
+{ 0x30fb, 0x0010, 0x0000, 0 },
+{ 0x30fc, 0x0110, 0x0000, 2 },
+{ 0x3105, 0x0100, 0x0000, 133 },
+{ 0x3190, 0x0010, 0x0000, 466 },
+{ 0x4e00, 0x0100, 0x0000, 32375 },
+{ 0xfb00, 0x0102, 0xfb00, 0 },
+{ 0xfb01, 0x0102, 0xfb01, 0 },
+{ 0xfb02, 0x0102, 0xfb02, 0 },
+{ 0xfb03, 0x0102, 0xfb03, 0 },
+{ 0xfb04, 0x0102, 0xfb04, 0 },
+{ 0xfb05, 0x0102, 0xfb05, 0 },
+{ 0xfb06, 0x0102, 0xfb06, 0 },
+{ 0xfb13, 0x0102, 0xfb13, 0 },
+{ 0xfb14, 0x0102, 0xfb14, 0 },
+{ 0xfb15, 0x0102, 0xfb15, 0 },
+{ 0xfb16, 0x0102, 0xfb16, 0 },
+{ 0xfb17, 0x0102, 0xfb17, 0 },
+{ 0xfb1e, 0x0010, 0x0000, 0 },
+{ 0xfb1f, 0x0100, 0x0000, 504 },
+{ 0xfd3e, 0x0010, 0x0000, 1 },
+{ 0xfd50, 0x0100, 0x0000, 129 },
+{ 0xfe20, 0x0010, 0x0000, 71 },
+{ 0xfe80, 0x0110, 0x0000, 124 },
+{ 0xfeff, 0x0048, 0x0000, 0 },
+{ 0xff01, 0x0010, 0x0000, 14 },
+{ 0xff10, 0x0084, 0x0000, 9 },
+{ 0xff1a, 0x0010, 0x0000, 6 },
+{ 0xff21, 0x0181, 0xff21, 0 },
+{ 0xff22, 0x0181, 0xff22, 0 },
+{ 0xff23, 0x0181, 0xff23, 0 },
+{ 0xff24, 0x0181, 0xff24, 0 },
+{ 0xff25, 0x0181, 0xff25, 0 },
+{ 0xff26, 0x0181, 0xff26, 0 },
+{ 0xff27, 0x0101, 0xff27, 0 },
+{ 0xff28, 0x0101, 0xff28, 0 },
+{ 0xff29, 0x0101, 0xff29, 0 },
+{ 0xff2a, 0x0101, 0xff2a, 0 },
+{ 0xff2b, 0x0101, 0xff2b, 0 },
+{ 0xff2c, 0x0101, 0xff2c, 0 },
+{ 0xff2d, 0x0101, 0xff2d, 0 },
+{ 0xff2e, 0x0101, 0xff2e, 0 },
+{ 0xff2f, 0x0101, 0xff2f, 0 },
+{ 0xff30, 0x0101, 0xff30, 0 },
+{ 0xff31, 0x0101, 0xff31, 0 },
+{ 0xff32, 0x0101, 0xff32, 0 },
+{ 0xff33, 0x0101, 0xff33, 0 },
+{ 0xff34, 0x0101, 0xff34, 0 },
+{ 0xff35, 0x0101, 0xff35, 0 },
+{ 0xff36, 0x0101, 0xff36, 0 },
+{ 0xff37, 0x0101, 0xff37, 0 },
+{ 0xff38, 0x0101, 0xff38, 0 },
+{ 0xff39, 0x0101, 0xff39, 0 },
+{ 0xff3a, 0x0101, 0xff3a, 0 },
+{ 0xff3b, 0x0010, 0x0000, 5 },
+{ 0xff41, 0x0182, 0xff41, 0 },
+{ 0xff42, 0x0182, 0xff42, 0 },
+{ 0xff43, 0x0182, 0xff43, 0 },
+{ 0xff44, 0x0182, 0xff44, 0 },
+{ 0xff45, 0x0182, 0xff45, 0 },
+{ 0xff46, 0x0182, 0xff46, 0 },
+{ 0xff47, 0x0102, 0xff47, 0 },
+{ 0xff48, 0x0102, 0xff48, 0 },
+{ 0xff49, 0x0102, 0xff49, 0 },
+{ 0xff4a, 0x0102, 0xff4a, 0 },
+{ 0xff4b, 0x0102, 0xff4b, 0 },
+{ 0xff4c, 0x0102, 0xff4c, 0 },
+{ 0xff4d, 0x0102, 0xff4d, 0 },
+{ 0xff4e, 0x0102, 0xff4e, 0 },
+{ 0xff4f, 0x0102, 0xff4f, 0 },
+{ 0xff50, 0x0102, 0xff50, 0 },
+{ 0xff51, 0x0102, 0xff51, 0 },
+{ 0xff52, 0x0102, 0xff52, 0 },
+{ 0xff53, 0x0102, 0xff53, 0 },
+{ 0xff54, 0x0102, 0xff54, 0 },
+{ 0xff55, 0x0102, 0xff55, 0 },
+{ 0xff56, 0x0102, 0xff56, 0 },
+{ 0xff57, 0x0102, 0xff57, 0 },
+{ 0xff58, 0x0102, 0xff58, 0 },
+{ 0xff59, 0x0102, 0xff59, 0 },
+{ 0xff5a, 0x0102, 0xff5a, 0 },
+{ 0xff5b, 0x0010, 0x0000, 8 },
+{ 0xff66, 0x0100, 0x0000, 9 },
+{ 0xff70, 0x0110, 0x0000, 0 },
+{ 0xff71, 0x0100, 0x0000, 44 },
+{ 0xff9e, 0x0110, 0x0000, 1 },
+{ 0xffa0, 0x0010, 0x0000, 0 },
+{ 0xffa1, 0x0100, 0x0000, 50 },
+{ 0xffe0, 0x0010, 0x0000, 13 },
+};
+
+CONST UINT UNICODE_DATA_SIZE = sizeof(UnicodeData)/sizeof(UnicodeDataRec);
+CONST UINT UNICODE_DATA_DIRECT_ACCESS = 256;
+
+#endif // !HAVE_COREFOUNDATION
diff --git a/src/pal/src/locale/utf8.cpp b/src/pal/src/locale/utf8.cpp
new file mode 100644
index 0000000000..87493a9673
--- /dev/null
+++ b/src/pal/src/locale/utf8.cpp
@@ -0,0 +1,2904 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ unicode/utf8.c
+
+Abstract:
+ Functions to encode and decode UTF-8 strings. This is a port of the C# version from mscorlib.
+
+Revision History:
+
+
+
+--*/
+
+#include "pal/utf8.h"
+
+#define FASTLOOP
+
+struct CharUnicodeInfo
+{
+ static const WCHAR HIGH_SURROGATE_START = 0xd800;
+ static const WCHAR HIGH_SURROGATE_END = 0xdbff;
+ static const WCHAR LOW_SURROGATE_START = 0xdc00;
+ static const WCHAR LOW_SURROGATE_END = 0xdfff;
+};
+
+struct Char
+{
+ // Test if the wide character is a high surrogate
+ static bool IsHighSurrogate(const WCHAR c)
+ {
+ return (c & 0xFC00) == CharUnicodeInfo::HIGH_SURROGATE_START;
+ }
+
+ // Test if the wide character is a low surrogate
+ static bool IsLowSurrogate(const WCHAR c)
+ {
+ return (c & 0xFC00) == CharUnicodeInfo::LOW_SURROGATE_START;
+ }
+
+ // Test if the wide character is a low surrogate
+ static bool IsSurrogate(const WCHAR c)
+ {
+ return (c & 0xF800) == CharUnicodeInfo::HIGH_SURROGATE_START;
+ }
+
+ // Test if the wide character is a high surrogate
+ static bool IsHighSurrogate(const WCHAR* s, int index)
+ {
+ return IsHighSurrogate(s[index]);
+ }
+
+ // Test if the wide character is a low surrogate
+ static bool IsLowSurrogate(const WCHAR* s, int index)
+ {
+ return IsLowSurrogate(s[index]);
+ }
+
+ // Test if the wide character is a low surrogate
+ static bool IsSurrogate(const WCHAR* s, int index)
+ {
+ return IsSurrogate(s[index]);
+ }
+};
+
+class ArgumentException
+{
+
+public:
+ ArgumentException(LPCSTR message)
+ {
+ }
+
+ ArgumentException(LPCSTR message, LPCSTR argName)
+ {
+ }
+};
+
+class ArgumentNullException : public ArgumentException
+{
+public:
+ ArgumentNullException(LPCSTR argName)
+ : ArgumentException("Argument is NULL", argName)
+ {
+
+ }
+};
+
+class ArgumentOutOfRangeException : public ArgumentException
+{
+public:
+ ArgumentOutOfRangeException(LPCSTR argName, LPCSTR message)
+ : ArgumentException(message, argName)
+ {
+
+ }
+};
+
+class InsufficientBufferException : public ArgumentException
+{
+public:
+ InsufficientBufferException(LPCSTR message, LPCSTR argName)
+ : ArgumentException(message, argName)
+ {
+
+ }
+};
+
+class Contract
+{
+public:
+ static void Assert(bool cond, LPCSTR str)
+ {
+ if (!cond)
+ {
+ throw ArgumentException(str);
+ }
+ }
+
+ static void EndContractBlock()
+ {
+ }
+};
+
+class DecoderFallbackException : public ArgumentException
+{
+ BYTE *bytesUnknown;
+ int index;
+
+public:
+ DecoderFallbackException(
+ LPCSTR message, BYTE bytesUnknown[], int index) : ArgumentException(message)
+ {
+ this->bytesUnknown = bytesUnknown;
+ this->index = index;
+ }
+
+ BYTE *BytesUnknown()
+ {
+ return (bytesUnknown);
+ }
+
+ int GetIndex()
+ {
+ return index;
+ }
+};
+
+class DecoderFallbackBuffer;
+
+class DecoderFallback
+{
+public:
+
+ // Fallback
+ //
+ // Return the appropriate unicode string alternative to the character that need to fall back.
+
+ virtual DecoderFallbackBuffer* CreateFallbackBuffer() = 0;
+
+ // Maximum number of characters that this instance of this fallback could return
+
+ virtual int GetMaxCharCount() = 0;
+};
+
+class DecoderReplacementFallback : public DecoderFallback
+{
+ // Our variables
+ WCHAR strDefault[2];
+ int strDefaultLength;
+
+public:
+ // Construction. Default replacement fallback uses no best fit and ? replacement string
+ DecoderReplacementFallback() : DecoderReplacementFallback(W("?"))
+ {
+ }
+
+ DecoderReplacementFallback(const WCHAR* replacement)
+ {
+ // Must not be null
+ if (replacement == nullptr)
+ throw ArgumentNullException("replacement");
+ Contract::EndContractBlock();
+
+ // Make sure it doesn't have bad surrogate pairs
+ bool bFoundHigh = false;
+ int replacementLength = PAL_wcslen((const WCHAR *)replacement);
+ for (int i = 0; i < replacementLength; i++)
+ {
+ // Found a surrogate?
+ if (Char::IsSurrogate(replacement, i))
+ {
+ // High or Low?
+ if (Char::IsHighSurrogate(replacement, i))
+ {
+ // if already had a high one, stop
+ if (bFoundHigh)
+ break; // break & throw at the bFoundHIgh below
+ bFoundHigh = true;
+ }
+ else
+ {
+ // Low, did we have a high?
+ if (!bFoundHigh)
+ {
+ // Didn't have one, make if fail when we stop
+ bFoundHigh = true;
+ break;
+ }
+
+ // Clear flag
+ bFoundHigh = false;
+ }
+ }
+ // If last was high we're in trouble (not surrogate so not low surrogate, so break)
+ else if (bFoundHigh)
+ break;
+ }
+ if (bFoundHigh)
+ throw ArgumentException("String 'replacement' contains invalid Unicode code points.", "replacement");
+
+ wcscpy_s(strDefault, sizeof(strDefault), replacement);
+ strDefaultLength = replacementLength;
+ }
+
+ WCHAR* GetDefaultString()
+ {
+ return strDefault;
+ }
+
+ virtual DecoderFallbackBuffer* CreateFallbackBuffer();
+
+ // Maximum number of characters that this instance of this fallback could return
+ virtual int GetMaxCharCount()
+ {
+ return strDefaultLength;
+ }
+};
+
+class DecoderFallbackBuffer
+{
+ friend class UTF8Encoding;
+ // Most implimentations will probably need an implimenation-specific constructor
+
+ // internal methods that cannot be overriden that let us do our fallback thing
+ // These wrap the internal methods so that we can check for people doing stuff that's incorrect
+
+public:
+ virtual bool Fallback(BYTE bytesUnknown[], int index, int size) = 0;
+
+ // Get next character
+ virtual WCHAR GetNextChar() = 0;
+
+ //Back up a character
+ virtual bool MovePrevious() = 0;
+
+ // How many chars left in this fallback?
+ virtual int GetRemaining() = 0;
+
+ // Clear the buffer
+ virtual void Reset()
+ {
+ while (GetNextChar() != (WCHAR)0);
+ }
+
+ // Internal items to help us figure out what we're doing as far as error messages, etc.
+ // These help us with our performance and messages internally
+protected:
+ BYTE* byteStart;
+ WCHAR* charEnd;
+
+ // Internal reset
+ void InternalReset()
+ {
+ byteStart = nullptr;
+ Reset();
+ }
+
+ // Set the above values
+ // This can't be part of the constructor because EncoderFallbacks would have to know how to impliment these.
+ void InternalInitialize(BYTE* byteStart, WCHAR* charEnd)
+ {
+ this->byteStart = byteStart;
+ this->charEnd = charEnd;
+ }
+
+ // Fallback the current byte by sticking it into the remaining char buffer.
+ // This can only be called by our encodings (other have to use the public fallback methods), so
+ // we can use our DecoderNLS here too (except we don't).
+ // Returns true if we are successful, false if we can't fallback the character (no buffer space)
+ // So caller needs to throw buffer space if return false.
+ // Right now this has both bytes and bytes[], since we might have extra bytes, hence the
+ // array, and we might need the index, hence the byte*
+ // Don't touch ref chars unless we succeed
+ virtual bool InternalFallback(BYTE bytes[], BYTE* pBytes, WCHAR** chars, int size)
+ {
+
+ Contract::Assert(byteStart != nullptr, "[DecoderFallback.InternalFallback]Used InternalFallback without calling InternalInitialize");
+
+ // See if there's a fallback character and we have an output buffer then copy our string.
+ if (this->Fallback(bytes, (int)(pBytes - byteStart - size), size))
+ {
+ // Copy the chars to our output
+ WCHAR ch;
+ WCHAR* charTemp = *chars;
+ bool bHighSurrogate = false;
+ while ((ch = GetNextChar()) != 0)
+ {
+ // Make sure no mixed up surrogates
+ if (Char::IsSurrogate(ch))
+ {
+ if (Char::IsHighSurrogate(ch))
+ {
+ // High Surrogate
+ if (bHighSurrogate)
+ throw ArgumentException("String 'chars' contains invalid Unicode code points.");
+ bHighSurrogate = true;
+ }
+ else
+ {
+ // Low surrogate
+ if (bHighSurrogate == false)
+ throw ArgumentException("String 'chars' contains invalid Unicode code points.");
+ bHighSurrogate = false;
+ }
+ }
+
+ if (charTemp >= charEnd)
+ {
+ // No buffer space
+ return false;
+ }
+
+ *(charTemp++) = ch;
+ }
+
+ // Need to make sure that bHighSurrogate isn't true
+ if (bHighSurrogate)
+ throw ArgumentException("String 'chars' contains invalid Unicode code points.");
+
+ // Now we aren't going to be false, so its OK to update chars
+ chars = &charTemp;
+ }
+
+ return true;
+ }
+
+ // This version just counts the fallback and doesn't actually copy anything.
+ virtual int InternalFallback(BYTE bytes[], BYTE* pBytes, int size)
+ // Right now this has both bytes[] and BYTE* bytes, since we might have extra bytes, hence the
+ // array, and we might need the index, hence the byte*
+ {
+
+ Contract::Assert(byteStart != nullptr, "[DecoderFallback.InternalFallback]Used InternalFallback without calling InternalInitialize");
+
+ // See if there's a fallback character and we have an output buffer then copy our string.
+ if (this->Fallback(bytes, (int)(pBytes - byteStart - size), size))
+ {
+ int count = 0;
+
+ WCHAR ch;
+ bool bHighSurrogate = false;
+ while ((ch = GetNextChar()) != 0)
+ {
+ // Make sure no mixed up surrogates
+ if (Char::IsSurrogate(ch))
+ {
+ if (Char::IsHighSurrogate(ch))
+ {
+ // High Surrogate
+ if (bHighSurrogate)
+ throw ArgumentException("String 'chars' contains invalid Unicode code points.");
+ bHighSurrogate = true;
+ }
+ else
+ {
+ // Low surrogate
+ if (bHighSurrogate == false)
+ throw ArgumentException("String 'chars' contains invalid Unicode code points.");
+ bHighSurrogate = false;
+ }
+ }
+
+ count++;
+ }
+
+ // Need to make sure that bHighSurrogate isn't true
+ if (bHighSurrogate)
+ throw ArgumentException("String 'chars' contains invalid Unicode code points.");
+
+ return count;
+ }
+
+ // If no fallback return 0
+ return 0;
+ }
+
+ // private helper methods
+ void ThrowLastBytesRecursive(BYTE bytesUnknown[])
+ {
+ throw ArgumentException("Recursive fallback not allowed");
+ }
+};
+
+class DecoderReplacementFallbackBuffer : public DecoderFallbackBuffer
+{
+ // Store our default string
+ WCHAR strDefault[4];
+ int strDefaultLength;
+ int fallbackCount = -1;
+ int fallbackIndex = -1;
+
+public:
+ // Construction
+ DecoderReplacementFallbackBuffer(DecoderReplacementFallback* fallback)
+ {
+ // 2X in case we're a surrogate pair
+ wcscpy_s(strDefault, sizeof(strDefault), fallback->GetDefaultString());
+ wcscat_s(strDefault, sizeof(strDefault), fallback->GetDefaultString());
+ strDefaultLength = 2 * PAL_wcslen((const WCHAR *)fallback->GetDefaultString());
+
+ }
+
+ // Fallback Methods
+ virtual bool Fallback(BYTE bytesUnknown[], int index, int size)
+ {
+ // We expect no previous fallback in our buffer
+ // We can't call recursively but others might (note, we don't test on last char!!!)
+ if (fallbackCount >= 1)
+ {
+ ThrowLastBytesRecursive(bytesUnknown);
+ }
+
+ // Go ahead and get our fallback
+ if (strDefaultLength == 0)
+ return false;
+
+ fallbackCount = strDefaultLength;
+ fallbackIndex = -1;
+
+ return true;
+ }
+
+ virtual WCHAR GetNextChar()
+ {
+ // We want it to get < 0 because == 0 means that the current/last character is a fallback
+ // and we need to detect recursion. We could have a flag but we already have this counter.
+ fallbackCount--;
+ fallbackIndex++;
+
+ // Do we have anything left? 0 is now last fallback char, negative is nothing left
+ if (fallbackCount < 0)
+ return '\0';
+
+ // Need to get it out of the buffer.
+ // Make sure it didn't wrap from the fast count-- path
+ if (fallbackCount == INT_MAX)
+ {
+ fallbackCount = -1;
+ return '\0';
+ }
+
+ // Now make sure its in the expected range
+ Contract::Assert(fallbackIndex < strDefaultLength && fallbackIndex >= 0,
+ "Index exceeds buffer range");
+
+ return strDefault[fallbackIndex];
+ }
+
+ virtual bool MovePrevious()
+ {
+ // Back up one, only if we just processed the last character (or earlier)
+ if (fallbackCount >= -1 && fallbackIndex >= 0)
+ {
+ fallbackIndex--;
+ fallbackCount++;
+ return true;
+ }
+
+ // Return false 'cause we couldn't do it.
+ return false;
+ }
+
+ // How many characters left to output?
+ virtual int GetRemaining()
+ {
+ // Our count is 0 for 1 character left.
+ return (fallbackCount < 0) ? 0 : fallbackCount;
+ }
+
+ // Clear the buffer
+ virtual void Reset()
+ {
+ fallbackCount = -1;
+ fallbackIndex = -1;
+ byteStart = nullptr;
+ }
+
+ // This version just counts the fallback and doesn't actually copy anything.
+ virtual int InternalFallback(BYTE bytes[], BYTE* pBytes, int size)
+ // Right now this has both bytes and bytes[], since we might have extra bytes, hence the
+ // array, and we might need the index, hence the byte*
+ {
+ // return our replacement string Length
+ return strDefaultLength;
+ }
+};
+
+class DecoderExceptionFallbackBuffer : public DecoderFallbackBuffer
+{
+public:
+ DecoderExceptionFallbackBuffer()
+ {
+ }
+
+ virtual bool Fallback(BYTE bytesUnknown[], int index, int size)
+ {
+ throw DecoderFallbackException(
+ "Unable to translate UTF-8 character to Unicode", bytesUnknown, index);
+ }
+
+ virtual WCHAR GetNextChar()
+ {
+ return 0;
+ }
+
+ virtual bool MovePrevious()
+ {
+ // Exception fallback doesn't have anywhere to back up to.
+ return false;
+ }
+
+ // Exceptions are always empty
+ virtual int GetRemaining()
+ {
+ return 0;
+ }
+
+};
+
+class DecoderExceptionFallback : public DecoderFallback
+{
+ // Construction
+public:
+ DecoderExceptionFallback()
+ {
+ }
+
+ virtual DecoderFallbackBuffer* CreateFallbackBuffer()
+ {
+ return new DecoderExceptionFallbackBuffer();
+ }
+
+ // Maximum number of characters that this instance of this fallback could return
+ virtual int GetMaxCharCount()
+ {
+ return 0;
+ }
+};
+
+DecoderFallbackBuffer* DecoderReplacementFallback::CreateFallbackBuffer()
+{
+ return new DecoderReplacementFallbackBuffer(this);
+}
+
+class EncoderFallbackException : public ArgumentException
+{
+ WCHAR charUnknown;
+ WCHAR charUnknownHigh;
+ WCHAR charUnknownLow;
+ int index;
+
+public:
+ EncoderFallbackException(
+ LPCSTR message, WCHAR charUnknown, int index) : ArgumentException(message)
+ {
+ this->charUnknown = charUnknown;
+ this->index = index;
+ }
+
+ EncoderFallbackException(
+ LPCSTR message, WCHAR charUnknownHigh, WCHAR charUnknownLow, int index) : ArgumentException(message)
+ {
+ if (!Char::IsHighSurrogate(charUnknownHigh))
+ {
+ throw ArgumentOutOfRangeException("charUnknownHigh",
+ "Argument out of range 0xD800..0xDBFF");
+ }
+ if (!Char::IsLowSurrogate(charUnknownLow))
+ {
+ throw ArgumentOutOfRangeException("charUnknownLow",
+ "Argument out of range 0xDC00..0xDFFF");
+ }
+ Contract::EndContractBlock();
+
+ this->charUnknownHigh = charUnknownHigh;
+ this->charUnknownLow = charUnknownLow;
+ this->index = index;
+ }
+
+ WCHAR GetCharUnknown()
+ {
+ return (charUnknown);
+ }
+
+ WCHAR GetCharUnknownHigh()
+ {
+ return (charUnknownHigh);
+ }
+
+ WCHAR GetCharUnknownLow()
+ {
+ return (charUnknownLow);
+ }
+
+ int GetIndex()
+ {
+ return index;
+ }
+
+ // Return true if the unknown character is a surrogate pair.
+ bool IsUnknownSurrogate()
+ {
+ return (charUnknownHigh != '\0');
+ }
+};
+
+class EncoderFallbackBuffer;
+
+class EncoderFallback
+{
+public:
+
+ // Fallback
+ //
+ // Return the appropriate unicode string alternative to the character that need to fall back.
+
+ virtual EncoderFallbackBuffer* CreateFallbackBuffer() = 0;
+
+ // Maximum number of characters that this instance of this fallback could return
+ virtual int GetMaxCharCount() = 0;
+};
+
+class EncoderReplacementFallback : public EncoderFallback
+{
+ // Our variables
+ WCHAR strDefault[2];
+ int strDefaultLength;
+
+public:
+ // Construction. Default replacement fallback uses no best fit and ? replacement string
+ EncoderReplacementFallback() : EncoderReplacementFallback(W("?"))
+ {
+ }
+
+ EncoderReplacementFallback(const WCHAR* replacement)
+ {
+ // Must not be null
+ if (replacement == nullptr)
+ throw ArgumentNullException("replacement");
+ Contract::EndContractBlock();
+
+ // Make sure it doesn't have bad surrogate pairs
+ bool bFoundHigh = false;
+ int replacementLength = PAL_wcslen((const WCHAR *)replacement);
+ for (int i = 0; i < replacementLength; i++)
+ {
+ // Found a surrogate?
+ if (Char::IsSurrogate(replacement, i))
+ {
+ // High or Low?
+ if (Char::IsHighSurrogate(replacement, i))
+ {
+ // if already had a high one, stop
+ if (bFoundHigh)
+ break; // break & throw at the bFoundHIgh below
+ bFoundHigh = true;
+ }
+ else
+ {
+ // Low, did we have a high?
+ if (!bFoundHigh)
+ {
+ // Didn't have one, make if fail when we stop
+ bFoundHigh = true;
+ break;
+ }
+
+ // Clear flag
+ bFoundHigh = false;
+ }
+ }
+ // If last was high we're in trouble (not surrogate so not low surrogate, so break)
+ else if (bFoundHigh)
+ break;
+ }
+ if (bFoundHigh)
+ throw ArgumentException("String 'replacement' contains invalid Unicode code points.", "replacement");
+
+ wcscpy_s(strDefault, sizeof(strDefault), replacement);
+ strDefaultLength = replacementLength;
+ }
+
+ WCHAR* GetDefaultString()
+ {
+ return strDefault;
+ }
+
+ virtual EncoderFallbackBuffer* CreateFallbackBuffer();
+
+ // Maximum number of characters that this instance of this fallback could return
+ virtual int GetMaxCharCount()
+ {
+ return strDefaultLength;
+ }
+};
+
+class EncoderFallbackBuffer
+{
+ friend class UTF8Encoding;
+ // Most implementations will probably need an implemenation-specific constructor
+
+ // Public methods that cannot be overriden that let us do our fallback thing
+ // These wrap the internal methods so that we can check for people doing stuff that is incorrect
+
+public:
+ virtual bool Fallback(WCHAR charUnknown, int index) = 0;
+
+ virtual bool Fallback(WCHAR charUnknownHigh, WCHAR charUnknownLow, int index) = 0;
+
+ // Get next character
+ virtual WCHAR GetNextChar() = 0;
+
+ // Back up a character
+ virtual bool MovePrevious() = 0;
+
+ // How many chars left in this fallback?
+ virtual int GetRemaining() = 0;
+
+ // Not sure if this should be public or not.
+ // Clear the buffer
+ virtual void Reset()
+ {
+ while (GetNextChar() != (WCHAR)0);
+ }
+
+ // Internal items to help us figure out what we're doing as far as error messages, etc.
+ // These help us with our performance and messages internally
+protected:
+ WCHAR* charStart;
+ WCHAR* charEnd;
+ bool setEncoder;
+ bool bUsedEncoder;
+ bool bFallingBack = false;
+ int iRecursionCount = 0;
+ static const int iMaxRecursion = 250;
+
+ // Internal Reset
+ // For example, what if someone fails a conversion and wants to reset one of our fallback buffers?
+ void InternalReset()
+ {
+ charStart = nullptr;
+ bFallingBack = false;
+ iRecursionCount = 0;
+ Reset();
+ }
+
+ // Set the above values
+ // This can't be part of the constructor because EncoderFallbacks would have to know how to impliment these.
+ void InternalInitialize(WCHAR* charStart, WCHAR* charEnd, bool setEncoder)
+ {
+ this->charStart = charStart;
+ this->charEnd = charEnd;
+ this->setEncoder = setEncoder;
+ this->bUsedEncoder = false;
+ this->bFallingBack = false;
+ this->iRecursionCount = 0;
+ }
+
+ WCHAR InternalGetNextChar()
+ {
+ WCHAR ch = GetNextChar();
+ bFallingBack = (ch != 0);
+ if (ch == 0) iRecursionCount = 0;
+ return ch;
+ }
+
+ // Fallback the current character using the remaining buffer and encoder if necessary
+ // This can only be called by our encodings (other have to use the public fallback methods), so
+ // we can use our EncoderNLS here too.
+ // setEncoder is true if we're calling from a GetBytes method, false if we're calling from a GetByteCount
+ //
+ // Note that this could also change the contents of this->encoder, which is the same
+ // object that the caller is using, so the caller could mess up the encoder for us
+ // if they aren't careful.
+ virtual bool InternalFallback(WCHAR ch, WCHAR** chars)
+ {
+ // Shouldn't have null charStart
+ Contract::Assert(charStart != nullptr,
+ "[EncoderFallback.InternalFallbackBuffer]Fallback buffer is not initialized");
+
+ // Get our index, remember chars was preincremented to point at next char, so have to -1
+ int index = (int)(*chars - charStart) - 1;
+
+ // See if it was a high surrogate
+ if (Char::IsHighSurrogate(ch))
+ {
+ // See if there's a low surrogate to go with it
+ if (*chars >= this->charEnd)
+ {
+ // Nothing left in input buffer
+ // No input, return 0
+ }
+ else
+ {
+ // Might have a low surrogate
+ WCHAR cNext = **chars;
+ if (Char::IsLowSurrogate(cNext))
+ {
+ // If already falling back then fail
+ if (bFallingBack && iRecursionCount++ > iMaxRecursion)
+ ThrowLastCharRecursive(ch, cNext);
+
+ // Next is a surrogate, add it as surrogate pair, and increment chars
+ (*chars)++;
+ bFallingBack = Fallback(ch, cNext, index);
+ return bFallingBack;
+ }
+
+ // Next isn't a low surrogate, just fallback the high surrogate
+ }
+ }
+
+ // If already falling back then fail
+ if (bFallingBack && iRecursionCount++ > iMaxRecursion)
+ ThrowLastCharRecursive((int)ch);
+
+ // Fall back our char
+ bFallingBack = Fallback(ch, index);
+
+ return bFallingBack;
+ }
+
+ // private helper methods
+ void ThrowLastCharRecursive(WCHAR highSurrogate, WCHAR lowSurrogate)
+ {
+ // Throw it, using our complete character
+ throw ArgumentException("Recursive fallback not allowed", "chars");
+ }
+
+ void ThrowLastCharRecursive(int utf32Char)
+ {
+ throw ArgumentException("Recursive fallback not allowed", "chars");
+ }
+
+};
+
+class EncoderReplacementFallbackBuffer : public EncoderFallbackBuffer
+{
+ // Store our default string
+ WCHAR strDefault[4];
+ int strDefaultLength;
+ int fallbackCount = -1;
+ int fallbackIndex = -1;
+public:
+ // Construction
+ EncoderReplacementFallbackBuffer(EncoderReplacementFallback* fallback)
+ {
+ // 2X in case we're a surrogate pair
+ wcscpy_s(strDefault, sizeof(strDefault), fallback->GetDefaultString());
+ wcscat_s(strDefault, sizeof(strDefault), fallback->GetDefaultString());
+ strDefaultLength = 2 * PAL_wcslen((const WCHAR *)fallback->GetDefaultString());
+
+ }
+
+ // Fallback Methods
+ virtual bool Fallback(WCHAR charUnknown, int index)
+ {
+ // If we had a buffer already we're being recursive, throw, it's probably at the suspect
+ // character in our array.
+ if (fallbackCount >= 1)
+ {
+ // If we're recursive we may still have something in our buffer that makes this a surrogate
+ if (Char::IsHighSurrogate(charUnknown) && fallbackCount >= 0 &&
+ Char::IsLowSurrogate(strDefault[fallbackIndex + 1]))
+ ThrowLastCharRecursive(charUnknown, strDefault[fallbackIndex + 1]);
+
+ // Nope, just one character
+ ThrowLastCharRecursive((int)charUnknown);
+ }
+
+ // Go ahead and get our fallback
+ // Divide by 2 because we aren't a surrogate pair
+ fallbackCount = strDefaultLength / 2;
+ fallbackIndex = -1;
+
+ return fallbackCount != 0;
+ }
+
+ virtual bool Fallback(WCHAR charUnknownHigh, WCHAR charUnknownLow, int index)
+ {
+ // Double check input surrogate pair
+ if (!Char::IsHighSurrogate(charUnknownHigh))
+ throw ArgumentOutOfRangeException("charUnknownHigh",
+ "Argument out of range 0xD800..0xDBFF");
+
+ if (!Char::IsLowSurrogate(charUnknownLow))
+ throw ArgumentOutOfRangeException("charUnknownLow",
+ "Argument out of range 0xDC00..0xDFFF");
+ Contract::EndContractBlock();
+
+ // If we had a buffer already we're being recursive, throw, it's probably at the suspect
+ // character in our array.
+ if (fallbackCount >= 1)
+ ThrowLastCharRecursive(charUnknownHigh, charUnknownLow);
+
+ // Go ahead and get our fallback
+ fallbackCount = strDefaultLength;
+ fallbackIndex = -1;
+
+ return fallbackCount != 0;
+ }
+
+ virtual WCHAR GetNextChar()
+ {
+ // We want it to get < 0 because == 0 means that the current/last character is a fallback
+ // and we need to detect recursion. We could have a flag but we already have this counter.
+ fallbackCount--;
+ fallbackIndex++;
+
+ // Do we have anything left? 0 is now last fallback char, negative is nothing left
+ if (fallbackCount < 0)
+ return '\0';
+
+ // Need to get it out of the buffer.
+ // Make sure it didn't wrap from the fast count-- path
+ if (fallbackCount == INT_MAX)
+ {
+ fallbackCount = -1;
+ return '\0';
+ }
+
+ // Now make sure its in the expected range
+ Contract::Assert(fallbackIndex < strDefaultLength && fallbackIndex >= 0,
+ "Index exceeds buffer range");
+
+ return strDefault[fallbackIndex];
+ }
+
+ virtual bool MovePrevious()
+ {
+ // Back up one, only if we just processed the last character (or earlier)
+ if (fallbackCount >= -1 && fallbackIndex >= 0)
+ {
+ fallbackIndex--;
+ fallbackCount++;
+ return true;
+ }
+
+ // Return false 'cause we couldn't do it.
+ return false;
+ }
+
+ // How many characters left to output?
+ virtual int GetRemaining()
+ {
+ // Our count is 0 for 1 character left.
+ return (fallbackCount < 0) ? 0 : fallbackCount;
+ }
+
+ // Clear the buffer
+ virtual void Reset()
+ {
+ fallbackCount = -1;
+ fallbackIndex = 0;
+ charStart = nullptr;
+ bFallingBack = false;
+ }
+};
+
+class EncoderExceptionFallbackBuffer : public EncoderFallbackBuffer
+{
+public:
+ EncoderExceptionFallbackBuffer()
+ {
+ }
+
+ virtual bool Fallback(WCHAR charUnknown, int index)
+ {
+ // Fall back our char
+ throw EncoderFallbackException("Unable to translate Unicode character to UTF-8", charUnknown, index);
+ }
+
+ virtual bool Fallback(WCHAR charUnknownHigh, WCHAR charUnknownLow, int index)
+ {
+ if (!Char::IsHighSurrogate(charUnknownHigh))
+ {
+ throw ArgumentOutOfRangeException("charUnknownHigh",
+ "Argument out of range 0xD800..0xDBFF");
+ }
+ if (!Char::IsLowSurrogate(charUnknownLow))
+ {
+ throw ArgumentOutOfRangeException("charUnknownLow",
+ "Argument out of range 0xDC00..0xDFFF");
+ }
+ Contract::EndContractBlock();
+
+ //int iTemp = Char::ConvertToUtf32(charUnknownHigh, charUnknownLow);
+
+ // Fall back our char
+ throw EncoderFallbackException(
+ "Unable to translate Unicode character to UTF-8", charUnknownHigh, charUnknownLow, index);
+ }
+
+ virtual WCHAR GetNextChar()
+ {
+ return 0;
+ }
+
+ virtual bool MovePrevious()
+ {
+ // Exception fallback doesn't have anywhere to back up to.
+ return false;
+ }
+
+ // Exceptions are always empty
+ virtual int GetRemaining()
+ {
+ return 0;
+ }
+};
+
+class EncoderExceptionFallback : public EncoderFallback
+{
+ // Construction
+public:
+ EncoderExceptionFallback()
+ {
+ }
+
+ virtual EncoderFallbackBuffer* CreateFallbackBuffer()
+ {
+ return new EncoderExceptionFallbackBuffer();
+ }
+
+ // Maximum number of characters that this instance of this fallback could return
+ virtual int GetMaxCharCount()
+ {
+ return 0;
+ }
+};
+
+EncoderFallbackBuffer* EncoderReplacementFallback::CreateFallbackBuffer()
+{
+ return new EncoderReplacementFallbackBuffer(this);
+}
+
+class UTF8Encoding
+{
+ EncoderFallback* encoderFallback;
+ // Instances of the two possible fallbacks. The constructor parameter
+ // determines which one to use.
+ EncoderReplacementFallback encoderReplacementFallback;
+ EncoderExceptionFallback encoderExceptionFallback;
+
+ DecoderFallback* decoderFallback;
+ // Instances of the two possible fallbacks. The constructor parameter
+ // determines which one to use.
+ DecoderReplacementFallback decoderReplacementFallback;
+ DecoderExceptionFallback decoderExceptionFallback;
+
+ bool InRange(WCHAR c, WCHAR begin, WCHAR end)
+ {
+ return begin <= c && c <= end;
+ }
+
+ size_t PtrDiff(void* ptr1, void* ptr2)
+ {
+ return (BYTE*)ptr2 - (BYTE*)ptr1;
+ }
+
+ void ThrowBytesOverflow()
+ {
+ // Special message to include fallback type in case fallback's GetMaxCharCount is broken
+ // This happens if user has implimented an encoder fallback with a broken GetMaxCharCount
+ throw InsufficientBufferException("The output byte buffer is too small to contain the encoded data", "bytes");
+ }
+
+ void ThrowBytesOverflow(bool nothingEncoded)
+ {
+ // Special message to include fallback type in case fallback's GetMaxCharCount is broken
+ // This happens if user has implimented an encoder fallback with a broken GetMaxCharCount
+ if (nothingEncoded){
+ ThrowBytesOverflow();
+ }
+ }
+
+ void ThrowCharsOverflow()
+ {
+ // Special message to include fallback type in case fallback's GetMaxCharCount is broken
+ // This happens if user has implimented a decoder fallback with a broken GetMaxCharCount
+ throw InsufficientBufferException("The output char buffer is too small to contain the encoded data", "chars");
+ }
+
+ void ThrowCharsOverflow(bool nothingEncoded)
+ {
+ // Special message to include fallback type in case fallback's GetMaxCharCount is broken
+ // This happens if user has implimented an decoder fallback with a broken GetMaxCharCount
+ if (nothingEncoded){
+ ThrowCharsOverflow();
+ }
+ }
+
+ int FallbackInvalidByteSequence(BYTE* pSrc, int ch, DecoderFallbackBuffer *fallback)
+ {
+ // Get our byte[]
+ BYTE *bytesUnknown;
+ int size = GetBytesUnknown(pSrc, ch, &bytesUnknown);
+
+ // Do the actual fallback
+ int count = fallback->InternalFallback(bytesUnknown, pSrc, size);
+
+ // # of fallback chars expected.
+ // Note that we only get here for "long" sequences, and have already unreserved
+ // the count that we prereserved for the input bytes
+ return count;
+ }
+
+ int GetBytesUnknown(BYTE* pSrc, int ch, BYTE **bytesUnknown)
+ {
+ int size;
+ BYTE bytes[3];
+
+ // See if it was a plain char
+ // (have to check >= 0 because we have all sorts of wierd bit flags)
+ if (ch < 0x100 && ch >= 0)
+ {
+ pSrc--;
+ bytes[0] = (BYTE)ch;
+ size = 1;
+ }
+ // See if its an unfinished 2 byte sequence
+ else if ((ch & (SupplimentarySeq | ThreeByteSeq)) == 0)
+ {
+ pSrc--;
+ bytes[0] = (BYTE)((ch & 0x1F) | 0xc0);
+ size = 1;
+ }
+ // So now we're either 2nd byte of 3 or 4 byte sequence or
+ // we hit a non-trail byte or we ran out of space for 3rd byte of 4 byte sequence
+ // 1st check if its a 4 byte sequence
+ else if ((ch & SupplimentarySeq) != 0)
+ {
+ // 3rd byte of 4 byte sequence?
+ if ((ch & (FinalByte >> 6)) != 0)
+ {
+ // 3rd byte of 4 byte sequence
+ pSrc -= 3;
+ bytes[0] = (BYTE)(((ch >> 12) & 0x07) | 0xF0);
+ bytes[1] = (BYTE)(((ch >> 6) & 0x3F) | 0x80);
+ bytes[2] = (BYTE)(((ch)& 0x3F) | 0x80);
+ size = 3;
+ }
+ else if ((ch & (FinalByte >> 12)) != 0)
+ {
+ // 2nd byte of a 4 byte sequence
+ pSrc -= 2;
+ bytes[0] = (BYTE)(((ch >> 6) & 0x07) | 0xF0);
+ bytes[1] = (BYTE)(((ch)& 0x3F) | 0x80);
+ size = 2;
+ }
+ else
+ {
+ // 4th byte of a 4 byte sequence
+ pSrc--;
+ bytes[0] = (BYTE)(((ch)& 0x07) | 0xF0);
+ size = 1;
+ }
+ }
+ else
+ {
+ // 2nd byte of 3 byte sequence?
+ if ((ch & (FinalByte >> 6)) != 0)
+ {
+ // So its 2nd byte of a 3 byte sequence
+ pSrc -= 2;
+ bytes[0] = (BYTE)(((ch >> 6) & 0x0F) | 0xE0);
+ bytes[1] = (BYTE)(((ch)& 0x3F) | 0x80);
+ size = 2;
+ }
+ else
+ {
+ // 1st byte of a 3 byte sequence
+ pSrc--;
+ bytes[0] = (BYTE)(((ch)& 0x0F) | 0xE0);
+ size = 1;
+ }
+ }
+
+ *bytesUnknown = bytes;
+ return size;
+ }
+
+public:
+
+ UTF8Encoding(bool isThrowException)
+ : encoderReplacementFallback(W("\xFFFD"))
+ {
+ if (isThrowException)
+ {
+ encoderFallback = &encoderExceptionFallback;
+ decoderFallback = &decoderExceptionFallback;
+ }
+ else
+ {
+ encoderFallback = &encoderReplacementFallback;
+ decoderFallback = &decoderReplacementFallback;
+ }
+ }
+
+ // These are bitmasks used to maintain the state in the decoder. They occupy the higher bits
+ // while the actual character is being built in the lower bits. They are shifted together
+ // with the actual bits of the character.
+
+ // bits 30 & 31 are used for pending bits fixup
+ const int FinalByte = 1 << 29;
+ const int SupplimentarySeq = 1 << 28;
+ const int ThreeByteSeq = 1 << 27;
+
+ int GetCharCount(BYTE* bytes, int count)
+ {
+ Contract::Assert(bytes != nullptr, "[UTF8Encoding.GetCharCount]bytes!=nullptr");
+ Contract::Assert(count >= 0, "[UTF8Encoding.GetCharCount]count >=0");
+
+ // Initialize stuff
+ BYTE *pSrc = bytes;
+ BYTE *pEnd = pSrc + count;
+
+ // Start by assuming we have as many as count, charCount always includes the adjustment
+ // for the character being decoded
+ int charCount = count;
+ int ch = 0;
+ DecoderFallbackBuffer *fallback = nullptr;
+
+ for (;;)
+ {
+ // SLOWLOOP: does all range checks, handles all special cases, but it is slow
+ if (pSrc >= pEnd) {
+ break;
+ }
+
+ // read next byte. The JIT optimization seems to be getting confused when
+ // compiling "ch = *pSrc++;", so rather use "ch = *pSrc; pSrc++;" instead
+ int cha = *pSrc;
+
+ if (ch == 0) {
+ // no pending bits
+ goto ReadChar;
+ }
+
+ pSrc++;
+
+ // we are expecting to see trailing bytes like 10vvvvvv
+ if ((cha & 0xC0) != 0x80) {
+ // This can be a valid starting byte for another UTF8 byte sequence, so let's put
+ // the current byte back, and try to see if this is a valid byte for another UTF8 byte sequence
+ pSrc--;
+ charCount += (ch >> 30);
+ goto InvalidByteSequence;
+ }
+
+ // fold in the new byte
+ ch = (ch << 6) | (cha & 0x3F);
+
+ if ((ch & FinalByte) == 0) {
+ Contract::Assert((ch & (SupplimentarySeq | ThreeByteSeq)) != 0,
+ "[UTF8Encoding.GetChars]Invariant volation");
+
+ if ((ch & SupplimentarySeq) != 0) {
+ if ((ch & (FinalByte >> 6)) != 0) {
+ // this is 3rd byte (of 4 byte supplimentary) - nothing to do
+ continue;
+ }
+
+ // 2nd byte, check for non-shortest form of supplimentary char and the valid
+ // supplimentary characters in range 0x010000 - 0x10FFFF at the same time
+ if (!InRange(ch & 0x1F0, 0x10, 0x100)) {
+ goto InvalidByteSequence;
+ }
+ }
+ else {
+ // Must be 2nd byte of a 3-byte sequence
+ // check for non-shortest form of 3 byte seq
+ if ((ch & (0x1F << 5)) == 0 || // non-shortest form
+ (ch & (0xF800 >> 6)) == (0xD800 >> 6)) // illegal individually encoded surrogate
+ {
+ goto InvalidByteSequence;
+ }
+ }
+ continue;
+ }
+
+ // ready to punch
+
+ // adjust for surrogates in non-shortest form
+ if ((ch & (SupplimentarySeq | 0x1F0000)) == SupplimentarySeq) {
+ charCount--;
+ }
+ goto EncodeChar;
+
+ InvalidByteSequence:
+ // this code fragment should be close to the gotos referencing it
+ // Have to do fallback for invalid bytes
+ if (fallback == nullptr)
+ {
+ fallback = decoderFallback->CreateFallbackBuffer();
+ fallback->InternalInitialize(bytes, nullptr);
+ }
+ charCount += FallbackInvalidByteSequence(pSrc, ch, fallback);
+
+ ch = 0;
+ continue;
+
+ ReadChar:
+ ch = *pSrc;
+ pSrc++;
+
+ ProcessChar:
+ if (ch > 0x7F) {
+ // If its > 0x7F, its start of a new multi-byte sequence
+
+ // Long sequence, so unreserve our char.
+ charCount--;
+
+ // bit 6 has to be non-zero for start of multibyte chars.
+ if ((ch & 0x40) == 0) {
+ // Unexpected trail byte
+ goto InvalidByteSequence;
+ }
+
+ // start a new long code
+ if ((ch & 0x20) != 0) {
+ if ((ch & 0x10) != 0) {
+ // 4 byte encoding - supplimentary character (2 surrogates)
+
+ ch &= 0x0F;
+
+ // check that bit 4 is zero and the valid supplimentary character
+ // range 0x000000 - 0x10FFFF at the same time
+ if (ch > 0x04) {
+ ch |= 0xf0;
+ goto InvalidByteSequence;
+ }
+
+ // Add bit flags so that when we check new characters & rotate we'll be flagged correctly.
+ // Final byte flag, count fix if we don't make final byte & supplimentary sequence flag.
+ ch |= (FinalByte >> 3 * 6) | // Final byte is 3 more bytes from now
+ (1 << 30) | // If it dies on next byte we'll need an extra char
+ (3 << (30 - 2 * 6)) | // If it dies on last byte we'll need to subtract a char
+ (SupplimentarySeq) | (SupplimentarySeq >> 6) |
+ (SupplimentarySeq >> 2 * 6) | (SupplimentarySeq >> 3 * 6);
+
+ // Our character count will be 2 characters for these 4 bytes, so subtract another char
+ charCount--;
+ }
+ else {
+ // 3 byte encoding
+ // Add bit flags so that when we check new characters & rotate we'll be flagged correctly.
+ ch = (ch & 0x0F) | ((FinalByte >> 2 * 6) | (1 << 30) |
+ (ThreeByteSeq) | (ThreeByteSeq >> 6) | (ThreeByteSeq >> 2 * 6));
+
+ // We'll expect 1 character for these 3 bytes, so subtract another char.
+ charCount--;
+ }
+ }
+ else {
+ // 2 byte encoding
+
+ ch &= 0x1F;
+
+ // check for non-shortest form
+ if (ch <= 1) {
+ ch |= 0xc0;
+ goto InvalidByteSequence;
+ }
+
+ // Add bit flags so we'll be flagged correctly
+ ch |= (FinalByte >> 6);
+ }
+ continue;
+ }
+
+ EncodeChar:
+
+#ifdef FASTLOOP
+ int availableBytes = PtrDiff(pEnd, pSrc);
+
+ // don't fall into the fast decoding loop if we don't have enough bytes
+ if (availableBytes <= 13) {
+ // try to get over the remainder of the ascii characters fast though
+ BYTE* pLocalEnd = pEnd; // hint to get pLocalEnd enregistered
+ while (pSrc < pLocalEnd) {
+ ch = *pSrc;
+ pSrc++;
+
+ if (ch > 0x7F)
+ goto ProcessChar;
+ }
+ // we are done
+ ch = 0;
+ break;
+ }
+
+ // To compute the upper bound, assume that all characters are ASCII characters at this point,
+ // the boundary will be decreased for every non-ASCII character we encounter
+ // Also, we need 7 chars reserve for the unrolled ansi decoding loop and for decoding of multibyte sequences
+ BYTE *pStop = pSrc + availableBytes - 7;
+
+ while (pSrc < pStop) {
+ ch = *pSrc;
+ pSrc++;
+
+ if (ch > 0x7F) {
+ goto LongCode;
+ }
+
+ // get pSrc 2-byte aligned
+ if (((int)pSrc & 0x1) != 0) {
+ ch = *pSrc;
+ pSrc++;
+ if (ch > 0x7F) {
+ goto LongCode;
+ }
+ }
+
+ // get pSrc 4-byte aligned
+ if (((int)pSrc & 0x2) != 0) {
+ ch = *(USHORT*)pSrc;
+ if ((ch & 0x8080) != 0) {
+ goto LongCodeWithMask16;
+ }
+ pSrc += 2;
+ }
+
+
+ // Run 8 + 8 characters at a time!
+ while (pSrc < pStop) {
+ ch = *(int*)pSrc;
+ int chb = *(int*)(pSrc + 4);
+ if (((ch | chb) & (int)0x80808080) != 0) {
+ goto LongCodeWithMask32;
+ }
+ pSrc += 8;
+
+ // This is a really small loop - unroll it
+ if (pSrc >= pStop)
+ break;
+
+ ch = *(int*)pSrc;
+ chb = *(int*)(pSrc + 4);
+ if (((ch | chb) & (int)0x80808080) != 0) {
+ goto LongCodeWithMask32;
+ }
+ pSrc += 8;
+ }
+ break;
+
+#if BIGENDIAN
+ LongCodeWithMask32 :
+ // be careful about the sign extension
+ ch = (int)(((uint)ch) >> 16);
+ LongCodeWithMask16:
+ ch = (int)(((uint)ch) >> 8);
+#else // BIGENDIAN
+ LongCodeWithMask32:
+ LongCodeWithMask16:
+ ch &= 0xFF;
+#endif // BIGENDIAN
+ pSrc++;
+ if (ch <= 0x7F) {
+ continue;
+ }
+
+ LongCode:
+ int chc = *pSrc;
+ pSrc++;
+
+ if (
+ // bit 6 has to be zero
+ (ch & 0x40) == 0 ||
+ // we are expecting to see trailing bytes like 10vvvvvv
+ (chc & 0xC0) != 0x80)
+ {
+ goto BadLongCode;
+ }
+
+ chc &= 0x3F;
+
+ // start a new long code
+ if ((ch & 0x20) != 0) {
+
+ // fold the first two bytes together
+ chc |= (ch & 0x0F) << 6;
+
+ if ((ch & 0x10) != 0) {
+ // 4 byte encoding - surrogate
+ ch = *pSrc;
+ if (
+ // check that bit 4 is zero, the non-shortest form of surrogate
+ // and the valid surrogate range 0x000000 - 0x10FFFF at the same time
+ !InRange(chc >> 4, 0x01, 0x10) ||
+ // we are expecting to see trailing bytes like 10vvvvvv
+ (ch & 0xC0) != 0x80)
+ {
+ goto BadLongCode;
+ }
+
+ chc = (chc << 6) | (ch & 0x3F);
+
+ ch = *(pSrc + 1);
+ // we are expecting to see trailing bytes like 10vvvvvv
+ if ((ch & 0xC0) != 0x80) {
+ goto BadLongCode;
+ }
+ pSrc += 2;
+
+ // extra byte
+ charCount--;
+ }
+ else {
+ // 3 byte encoding
+ ch = *pSrc;
+ if (
+ // check for non-shortest form of 3 byte seq
+ (chc & (0x1F << 5)) == 0 ||
+ // Can't have surrogates here.
+ (chc & (0xF800 >> 6)) == (0xD800 >> 6) ||
+ // we are expecting to see trailing bytes like 10vvvvvv
+ (ch & 0xC0) != 0x80)
+ {
+ goto BadLongCode;
+ }
+ pSrc++;
+
+ // extra byte
+ charCount--;
+ }
+ }
+ else {
+ // 2 byte encoding
+
+ // check for non-shortest form
+ if ((ch & 0x1E) == 0) {
+ goto BadLongCode;
+ }
+ }
+
+ // extra byte
+ charCount--;
+ }
+#endif // FASTLOOP
+
+ // no pending bits at this point
+ ch = 0;
+ continue;
+
+ BadLongCode:
+ pSrc -= 2;
+ ch = 0;
+ continue;
+ }
+
+ // May have a problem if we have to flush
+ if (ch != 0)
+ {
+ // We were already adjusting for these, so need to unadjust
+ charCount += (ch >> 30);
+ // Have to do fallback for invalid bytes
+ if (fallback == nullptr)
+ {
+ fallback = decoderFallback->CreateFallbackBuffer();
+ fallback->InternalInitialize(bytes, nullptr);
+ }
+ charCount += FallbackInvalidByteSequence(pSrc, ch, fallback);
+ }
+
+ // Shouldn't have anything in fallback buffer for GetCharCount
+ // (don't have to check m_throwOnOverflow for count)
+ Contract::Assert(fallback == nullptr || fallback->GetRemaining() == 0,
+ "[UTF8Encoding.GetCharCount]Expected empty fallback buffer at end");
+
+ return charCount;
+
+ }
+
+ int GetChars(BYTE* bytes, int byteCount, WCHAR* chars, int charCount)
+ {
+ Contract::Assert(chars != nullptr, "[UTF8Encoding.GetChars]chars!=nullptr");
+ Contract::Assert(byteCount >= 0, "[UTF8Encoding.GetChars]byteCount >=0");
+ Contract::Assert(charCount >= 0, "[UTF8Encoding.GetChars]charCount >=0");
+ Contract::Assert(bytes != nullptr, "[UTF8Encoding.GetChars]bytes!=nullptr");
+
+ BYTE *pSrc = bytes;
+ WCHAR *pTarget = chars;
+
+ BYTE *pEnd = pSrc + byteCount;
+ WCHAR *pAllocatedBufferEnd = pTarget + charCount;
+
+ int ch = 0;
+
+ DecoderFallbackBuffer *fallback = nullptr;
+
+ for (;;)
+ {
+ // SLOWLOOP: does all range checks, handles all special cases, but it is slow
+
+ if (pSrc >= pEnd) {
+ break;
+ }
+
+ // read next byte. The JIT optimization seems to be getting confused when
+ // compiling "ch = *pSrc++;", so rather use "ch = *pSrc; pSrc++;" instead
+ int cha = *pSrc;
+
+ if (ch == 0) {
+ // no pending bits
+ goto ReadChar;
+ }
+
+ pSrc++;
+
+ // we are expecting to see trailing bytes like 10vvvvvv
+ if ((cha & 0xC0) != 0x80) {
+ // This can be a valid starting byte for another UTF8 byte sequence, so let's put
+ // the current byte back, and try to see if this is a valid byte for another UTF8 byte sequence
+ pSrc--;
+ goto InvalidByteSequence;
+ }
+
+ // fold in the new byte
+ ch = (ch << 6) | (cha & 0x3F);
+
+ if ((ch & FinalByte) == 0) {
+ // Not at last byte yet
+ Contract::Assert((ch & (SupplimentarySeq | ThreeByteSeq)) != 0,
+ "[UTF8Encoding.GetChars]Invariant volation");
+
+ if ((ch & SupplimentarySeq) != 0) {
+ // Its a 4-byte supplimentary sequence
+ if ((ch & (FinalByte >> 6)) != 0) {
+ // this is 3rd byte of 4 byte sequence - nothing to do
+ continue;
+ }
+
+ // 2nd byte of 4 bytes
+ // check for non-shortest form of surrogate and the valid surrogate
+ // range 0x000000 - 0x10FFFF at the same time
+ if (!InRange(ch & 0x1F0, 0x10, 0x100)) {
+ goto InvalidByteSequence;
+ }
+ }
+ else {
+ // Must be 2nd byte of a 3-byte sequence
+ // check for non-shortest form of 3 byte seq
+ if ((ch & (0x1F << 5)) == 0 || // non-shortest form
+ (ch & (0xF800 >> 6)) == (0xD800 >> 6)) // illegal individually encoded surrogate
+ {
+ goto InvalidByteSequence;
+ }
+ }
+ continue;
+ }
+
+ // ready to punch
+
+ // surrogate in shortest form?
+ // Might be possible to get rid of this? Already did non-shortest check for 4-byte sequence when reading 2nd byte?
+ if ((ch & (SupplimentarySeq | 0x1F0000)) > SupplimentarySeq) {
+ // let the range check for the second char throw the exception
+ if (pTarget < pAllocatedBufferEnd) {
+ *pTarget = (WCHAR)(((ch >> 10) & 0x7FF) +
+ (SHORT)((CharUnicodeInfo::HIGH_SURROGATE_START - (0x10000 >> 10))));
+ pTarget++;
+
+ ch = (ch & 0x3FF) +
+ (int)(CharUnicodeInfo::LOW_SURROGATE_START);
+ }
+ }
+
+ goto EncodeChar;
+
+ InvalidByteSequence:
+ // this code fragment should be close to the gotos referencing it
+ // Have to do fallback for invalid bytes
+ if (fallback == nullptr)
+ {
+ fallback = decoderFallback->CreateFallbackBuffer();
+ fallback->InternalInitialize(bytes, pAllocatedBufferEnd);
+ }
+ // This'll back us up the appropriate # of bytes if we didn't get anywhere
+ if (!FallbackInvalidByteSequence(pSrc, ch, fallback))
+ {
+ // Ran out of buffer space
+ // Need to throw an exception?
+ Contract::Assert(pSrc >= bytes || pTarget == chars,
+ "[UTF8Encoding.GetChars]Expected to throw or remain in byte buffer after fallback");
+ fallback->InternalReset();
+ ThrowCharsOverflow(pTarget == chars);
+ ch = 0;
+ break;
+ }
+ Contract::Assert(pSrc >= bytes,
+ "[UTF8Encoding.GetChars]Expected invalid byte sequence to have remained within the byte array");
+ ch = 0;
+ continue;
+
+ ReadChar:
+ ch = *pSrc;
+ pSrc++;
+
+ ProcessChar:
+ if (ch > 0x7F) {
+ // If its > 0x7F, its start of a new multi-byte sequence
+
+ // bit 6 has to be non-zero
+ if ((ch & 0x40) == 0) {
+ goto InvalidByteSequence;
+ }
+
+ // start a new long code
+ if ((ch & 0x20) != 0) {
+ if ((ch & 0x10) != 0) {
+ // 4 byte encoding - supplimentary character (2 surrogates)
+
+ ch &= 0x0F;
+
+ // check that bit 4 is zero and the valid supplimentary character
+ // range 0x000000 - 0x10FFFF at the same time
+ if (ch > 0x04) {
+ ch |= 0xf0;
+ goto InvalidByteSequence;
+ }
+
+ ch |= (FinalByte >> 3 * 6) | (1 << 30) | (3 << (30 - 2 * 6)) |
+ (SupplimentarySeq) | (SupplimentarySeq >> 6) |
+ (SupplimentarySeq >> 2 * 6) | (SupplimentarySeq >> 3 * 6);
+ }
+ else {
+ // 3 byte encoding
+ ch = (ch & 0x0F) | ((FinalByte >> 2 * 6) | (1 << 30) |
+ (ThreeByteSeq) | (ThreeByteSeq >> 6) | (ThreeByteSeq >> 2 * 6));
+ }
+ }
+ else {
+ // 2 byte encoding
+
+ ch &= 0x1F;
+
+ // check for non-shortest form
+ if (ch <= 1) {
+ ch |= 0xc0;
+ goto InvalidByteSequence;
+ }
+
+ ch |= (FinalByte >> 6);
+ }
+ continue;
+ }
+
+ EncodeChar:
+ // write the pending character
+ if (pTarget >= pAllocatedBufferEnd)
+ {
+ // Fix chars so we make sure to throw if we didn't output anything
+ ch &= 0x1fffff;
+ if (ch > 0x7f)
+ {
+ if (ch > 0x7ff)
+ {
+ if (ch >= CharUnicodeInfo::LOW_SURROGATE_START &&
+ ch <= CharUnicodeInfo::LOW_SURROGATE_END)
+ {
+ pSrc--; // It was 4 bytes
+ pTarget--; // 1 was stored already, but we can't remember 1/2, so back up
+ }
+ else if (ch > 0xffff)
+ {
+ pSrc--; // It was 4 bytes, nothing was stored
+ }
+ pSrc--; // It was at least 3 bytes
+ }
+ pSrc--; // It was at least 2 bytes
+ }
+ pSrc--;
+
+ // Throw that we don't have enough room (pSrc could be < chars if we had started to process
+ // a 4 byte sequence alredy)
+ Contract::Assert(pSrc >= bytes || pTarget == chars,
+ "[UTF8Encoding.GetChars]Expected pSrc to be within input buffer or throw due to no output]");
+ ThrowCharsOverflow(pTarget == chars);
+
+ // Don't store ch in decoder, we already backed up to its start
+ ch = 0;
+
+ // Didn't throw, just use this buffer size.
+ break;
+ }
+ *pTarget = (WCHAR)ch;
+ pTarget++;
+
+#ifdef FASTLOOP
+ int availableChars = PtrDiff(pAllocatedBufferEnd, pTarget);
+ int availableBytes = PtrDiff(pEnd, pSrc);
+
+ // don't fall into the fast decoding loop if we don't have enough bytes
+ // Test for availableChars is done because pStop would be <= pTarget.
+ if (availableBytes <= 13) {
+ // we may need as many as 1 character per byte
+ if (availableChars < availableBytes) {
+ // not enough output room. no pending bits at this point
+ ch = 0;
+ continue;
+ }
+
+ // try to get over the remainder of the ascii characters fast though
+ BYTE* pLocalEnd = pEnd; // hint to get pLocalEnd enregistered
+ while (pSrc < pLocalEnd) {
+ ch = *pSrc;
+ pSrc++;
+
+ if (ch > 0x7F)
+ goto ProcessChar;
+
+ *pTarget = (char)ch;
+ pTarget++;
+ }
+ // we are done
+ ch = 0;
+ break;
+ }
+
+ // we may need as many as 1 character per byte, so reduce the byte count if necessary.
+ // If availableChars is too small, pStop will be before pTarget and we won't do fast loop.
+ if (availableChars < availableBytes) {
+ availableBytes = availableChars;
+ }
+
+ // To compute the upper bound, assume that all characters are ASCII characters at this point,
+ // the boundary will be decreased for every non-ASCII character we encounter
+ // Also, we need 7 chars reserve for the unrolled ansi decoding loop and for decoding of multibyte sequences
+ WCHAR *pStop = pTarget + availableBytes - 7;
+
+ while (pTarget < pStop) {
+ ch = *pSrc;
+ pSrc++;
+
+ if (ch > 0x7F) {
+ goto LongCode;
+ }
+ *pTarget = (WCHAR)ch;
+ pTarget++;
+
+ // get pSrc to be 2-byte aligned
+ if ((((int)pSrc) & 0x1) != 0) {
+ ch = *pSrc;
+ pSrc++;
+ if (ch > 0x7F) {
+ goto LongCode;
+ }
+ *pTarget = (char)ch;
+ pTarget++;
+ }
+
+ // get pSrc to be 4-byte aligned
+ if ((((int)pSrc) & 0x2) != 0) {
+ ch = *(USHORT*)pSrc;
+ if ((ch & 0x8080) != 0) {
+ goto LongCodeWithMask16;
+ }
+
+ // Unfortunately, this is endianess sensitive
+#if BIGENDIAN
+ *pTarget = (WCHAR)((ch >> 8) & 0x7F);
+ pSrc += 2;
+ *(pTarget + 1) = (WCHAR)(ch & 0x7F);
+ pTarget += 2;
+#else // BIGENDIAN
+ *pTarget = (WCHAR)(ch & 0x7F);
+ pSrc += 2;
+ *(pTarget + 1) = (WCHAR)((ch >> 8) & 0x7F);
+ pTarget += 2;
+#endif // BIGENDIAN
+ }
+
+ // Run 8 characters at a time!
+ while (pTarget < pStop) {
+ ch = *(int*)pSrc;
+ int chb = *(int*)(pSrc + 4);
+ if (((ch | chb) & (int)0x80808080) != 0) {
+ goto LongCodeWithMask32;
+ }
+
+ // Unfortunately, this is endianess sensitive
+#if BIGENDIAN
+ *pTarget = (WCHAR)((ch >> 24) & 0x7F);
+ *(pTarget + 1) = (WCHAR)((ch >> 16) & 0x7F);
+ *(pTarget + 2) = (WCHAR)((ch >> 8) & 0x7F);
+ *(pTarget + 3) = (WCHAR)(ch & 0x7F);
+ pSrc += 8;
+ *(pTarget + 4) = (WCHAR)((chb >> 24) & 0x7F);
+ *(pTarget + 5) = (WCHAR)((chb >> 16) & 0x7F);
+ *(pTarget + 6) = (WCHAR)((chb >> 8) & 0x7F);
+ *(pTarget + 7) = (WCHAR)(chb & 0x7F);
+ pTarget += 8;
+#else // BIGENDIAN
+ *pTarget = (WCHAR)(ch & 0x7F);
+ *(pTarget + 1) = (WCHAR)((ch >> 8) & 0x7F);
+ *(pTarget + 2) = (WCHAR)((ch >> 16) & 0x7F);
+ *(pTarget + 3) = (WCHAR)((ch >> 24) & 0x7F);
+ pSrc += 8;
+ *(pTarget + 4) = (WCHAR)(chb & 0x7F);
+ *(pTarget + 5) = (WCHAR)((chb >> 8) & 0x7F);
+ *(pTarget + 6) = (WCHAR)((chb >> 16) & 0x7F);
+ *(pTarget + 7) = (WCHAR)((chb >> 24) & 0x7F);
+ pTarget += 8;
+#endif // BIGENDIAN
+ }
+ break;
+
+#if BIGENDIAN
+ LongCodeWithMask32 :
+ // be careful about the sign extension
+ ch = (int)(((uint)ch) >> 16);
+ LongCodeWithMask16:
+ ch = (int)(((uint)ch) >> 8);
+#else // BIGENDIAN
+ LongCodeWithMask32:
+ LongCodeWithMask16:
+ ch &= 0xFF;
+#endif // BIGENDIAN
+ pSrc++;
+ if (ch <= 0x7F) {
+ *pTarget = (WCHAR)ch;
+ pTarget++;
+ continue;
+ }
+
+ LongCode:
+ int chc = *pSrc;
+ pSrc++;
+
+ if (
+ // bit 6 has to be zero
+ (ch & 0x40) == 0 ||
+ // we are expecting to see trailing bytes like 10vvvvvv
+ (chc & 0xC0) != 0x80)
+ {
+ goto BadLongCode;
+ }
+
+ chc &= 0x3F;
+
+ // start a new long code
+ if ((ch & 0x20) != 0) {
+
+ // fold the first two bytes together
+ chc |= (ch & 0x0F) << 6;
+
+ if ((ch & 0x10) != 0) {
+ // 4 byte encoding - surrogate
+ ch = *pSrc;
+ if (
+ // check that bit 4 is zero, the non-shortest form of surrogate
+ // and the valid surrogate range 0x000000 - 0x10FFFF at the same time
+ !InRange(chc >> 4, 0x01, 0x10) ||
+ // we are expecting to see trailing bytes like 10vvvvvv
+ (ch & 0xC0) != 0x80)
+ {
+ goto BadLongCode;
+ }
+
+ chc = (chc << 6) | (ch & 0x3F);
+
+ ch = *(pSrc + 1);
+ // we are expecting to see trailing bytes like 10vvvvvv
+ if ((ch & 0xC0) != 0x80) {
+ goto BadLongCode;
+ }
+ pSrc += 2;
+
+ ch = (chc << 6) | (ch & 0x3F);
+
+ *pTarget = (char)(((ch >> 10) & 0x7FF) +
+ (SHORT)(CharUnicodeInfo::HIGH_SURROGATE_START - (0x10000 >> 10)));
+ pTarget++;
+
+ ch = (ch & 0x3FF) +
+ (SHORT)(CharUnicodeInfo::LOW_SURROGATE_START);
+
+ // extra byte, we're already planning 2 chars for 2 of these bytes,
+ // but the big loop is testing the target against pStop, so we need
+ // to subtract 2 more or we risk overrunning the input. Subtract
+ // one here and one below.
+ pStop--;
+ }
+ else {
+ // 3 byte encoding
+ ch = *pSrc;
+ if (
+ // check for non-shortest form of 3 byte seq
+ (chc & (0x1F << 5)) == 0 ||
+ // Can't have surrogates here.
+ (chc & (0xF800 >> 6)) == (0xD800 >> 6) ||
+ // we are expecting to see trailing bytes like 10vvvvvv
+ (ch & 0xC0) != 0x80)
+ {
+ goto BadLongCode;
+ }
+ pSrc++;
+
+ ch = (chc << 6) | (ch & 0x3F);
+
+ // extra byte, we're only expecting 1 char for each of these 3 bytes,
+ // but the loop is testing the target (not source) against pStop, so
+ // we need to subtract 2 more or we risk overrunning the input.
+ // Subtract 1 here and one more below
+ pStop--;
+ }
+ }
+ else {
+ // 2 byte encoding
+
+ ch &= 0x1F;
+
+ // check for non-shortest form
+ if (ch <= 1) {
+ goto BadLongCode;
+ }
+ ch = (ch << 6) | chc;
+ }
+
+ *pTarget = (WCHAR)ch;
+ pTarget++;
+
+ // extra byte, we're only expecting 1 char for each of these 2 bytes,
+ // but the loop is testing the target (not source) against pStop.
+ // subtract an extra count from pStop so that we don't overrun the input.
+ pStop--;
+ }
+#endif // FASTLOOP
+
+ Contract::Assert(pTarget <= pAllocatedBufferEnd, "[UTF8Encoding.GetChars]pTarget <= pAllocatedBufferEnd");
+
+ // no pending bits at this point
+ ch = 0;
+ continue;
+
+ BadLongCode:
+ pSrc -= 2;
+ ch = 0;
+ continue;
+ }
+
+ if (ch != 0)
+ {
+ // Have to do fallback for invalid bytes
+ if (fallback == nullptr)
+ {
+ fallback = decoderFallback->CreateFallbackBuffer();
+ fallback->InternalInitialize(bytes, pAllocatedBufferEnd);
+ }
+
+ // This'll back us up the appropriate # of bytes if we didn't get anywhere
+ if (!FallbackInvalidByteSequence(pSrc, ch, fallback))
+ {
+ Contract::Assert(pSrc >= bytes || pTarget == chars,
+ "[UTF8Encoding.GetChars]Expected to throw or remain in byte buffer while flushing");
+
+ // Ran out of buffer space
+ // Need to throw an exception?
+ fallback->InternalReset();
+ ThrowCharsOverflow(pTarget == chars);
+ }
+ Contract::Assert(pSrc >= bytes,
+ "[UTF8Encoding.GetChars]Expected flushing invalid byte sequence to have remained within the byte array");
+ ch = 0;
+ }
+
+ // Shouldn't have anything in fallback buffer for GetChars
+ // (don't have to check m_throwOnOverflow for chars)
+ Contract::Assert(fallback == nullptr || fallback->GetRemaining() == 0,
+ "[UTF8Encoding.GetChars]Expected empty fallback buffer at end");
+
+ return PtrDiff(pTarget, chars);
+ }
+
+ int GetBytes(WCHAR* chars, int charCount, BYTE* bytes, int byteCount)
+ {
+ Contract::Assert(chars != nullptr, "[UTF8Encoding.GetBytes]chars!=nullptr");
+ Contract::Assert(byteCount >= 0, "[UTF8Encoding.GetBytes]byteCount >=0");
+ Contract::Assert(charCount >= 0, "[UTF8Encoding.GetBytes]charCount >=0");
+ Contract::Assert(bytes != nullptr, "[UTF8Encoding.GetBytes]bytes!=nullptr");
+
+ // For fallback we may need a fallback buffer.
+ // We wait to initialize it though in case we don't have any broken input unicode
+ EncoderFallbackBuffer* fallbackBuffer = nullptr;
+ WCHAR *pSrc = chars;
+ BYTE *pTarget = bytes;
+
+ WCHAR *pEnd = pSrc + charCount;
+ BYTE *pAllocatedBufferEnd = pTarget + byteCount;
+
+ int ch = 0;
+
+ // assume that JIT will enregister pSrc, pTarget and ch
+
+ for (;;) {
+ // SLOWLOOP: does all range checks, handles all special cases, but it is slow
+
+ if (pSrc >= pEnd) {
+
+ if (ch == 0) {
+ // Check if there's anything left to get out of the fallback buffer
+ ch = fallbackBuffer != nullptr ? fallbackBuffer->InternalGetNextChar() : 0;
+ if (ch > 0) {
+ goto ProcessChar;
+ }
+ }
+ else {
+ // Case of leftover surrogates in the fallback buffer
+ if (fallbackBuffer != nullptr && fallbackBuffer->bFallingBack) {
+ Contract::Assert(ch >= 0xD800 && ch <= 0xDBFF,
+ "[UTF8Encoding.GetBytes]expected high surrogate"); //, not 0x" + ((int)ch).ToString("X4", CultureInfo.InvariantCulture));
+
+ int cha = ch;
+
+ ch = fallbackBuffer->InternalGetNextChar();
+
+ if (InRange(ch, CharUnicodeInfo::LOW_SURROGATE_START, CharUnicodeInfo::LOW_SURROGATE_END)) {
+ ch = ch + (cha << 10) + (0x10000 - CharUnicodeInfo::LOW_SURROGATE_START - (CharUnicodeInfo::HIGH_SURROGATE_START << 10));
+ goto EncodeChar;
+ }
+ else if (ch > 0){
+ goto ProcessChar;
+ }
+ else {
+ break;
+ }
+ }
+ }
+
+ // attempt to encode the partial surrogate (will fail or ignore)
+ if (ch > 0)
+ goto EncodeChar;
+
+ // We're done
+ break;
+ }
+
+ if (ch > 0) {
+ // We have a high surrogate left over from a previous loop.
+ Contract::Assert(ch >= 0xD800 && ch <= 0xDBFF,
+ "[UTF8Encoding.GetBytes]expected high surrogate");//, not 0x" + ((int)ch).ToString("X4", CultureInfo.InvariantCulture));
+
+ // use separate helper variables for local contexts so that the jit optimizations
+ // won't get confused about the variable lifetimes
+ int cha = *pSrc;
+
+ // In previous byte, we encountered a high surrogate, so we are expecting a low surrogate here.
+ // if (IsLowSurrogate(cha)) {
+ if (InRange(cha, CharUnicodeInfo::LOW_SURROGATE_START, CharUnicodeInfo::LOW_SURROGATE_END)) {
+ ch = cha + (ch << 10) +
+ (0x10000
+ - CharUnicodeInfo::LOW_SURROGATE_START
+ - (CharUnicodeInfo::HIGH_SURROGATE_START << 10));
+
+ pSrc++;
+ }
+ // else ch is still high surrogate and encoding will fail
+
+ // attempt to encode the surrogate or partial surrogate
+ goto EncodeChar;
+ }
+
+ // If we've used a fallback, then we have to check for it
+ if (fallbackBuffer != nullptr)
+ {
+ ch = fallbackBuffer->InternalGetNextChar();
+ if (ch > 0) goto ProcessChar;
+ }
+
+ // read next char. The JIT optimization seems to be getting confused when
+ // compiling "ch = *pSrc++;", so rather use "ch = *pSrc; pSrc++;" instead
+ ch = *pSrc;
+ pSrc++;
+
+ ProcessChar:
+ if (InRange(ch, CharUnicodeInfo::HIGH_SURROGATE_START, CharUnicodeInfo::HIGH_SURROGATE_END)) {
+ continue;
+ }
+ // either good char or partial surrogate
+
+ EncodeChar:
+ // throw exception on partial surrogate if necessary
+ if (InRange(ch, CharUnicodeInfo::HIGH_SURROGATE_START, CharUnicodeInfo::LOW_SURROGATE_END))
+ {
+ // Lone surrogates aren't allowed, we have to do fallback for them
+ // Have to make a fallback buffer if we don't have one
+ if (fallbackBuffer == nullptr)
+ {
+ // wait on fallbacks if we can
+ // For fallback we may need a fallback buffer
+ fallbackBuffer = encoderFallback->CreateFallbackBuffer();
+
+ // Set our internal fallback interesting things.
+ fallbackBuffer->InternalInitialize(chars, pEnd, true);
+ }
+
+ // Do our fallback. Actually we already know its a mixed up surrogate,
+ // so the ref pSrc isn't gonna do anything.
+ fallbackBuffer->InternalFallback((WCHAR)ch, &pSrc);
+
+ // Ignore it if we don't throw
+ ch = 0;
+ continue;
+ }
+
+ // Count bytes needed
+ int bytesNeeded = 1;
+ if (ch > 0x7F) {
+ if (ch > 0x7FF) {
+ if (ch > 0xFFFF) {
+ bytesNeeded++; // 4 bytes (surrogate pair)
+ }
+ bytesNeeded++; // 3 bytes (800-FFFF)
+ }
+ bytesNeeded++; // 2 bytes (80-7FF)
+ }
+
+ if (pTarget > pAllocatedBufferEnd - bytesNeeded) {
+ // Left over surrogate from last time will cause pSrc == chars, so we'll throw
+ if (fallbackBuffer != nullptr && fallbackBuffer->bFallingBack)
+ {
+ fallbackBuffer->MovePrevious(); // Didn't use this fallback char
+ if (ch > 0xFFFF)
+ fallbackBuffer->MovePrevious(); // Was surrogate, didn't use 2nd part either
+ }
+ else
+ {
+ pSrc--; // Didn't use this char
+ if (ch > 0xFFFF)
+ pSrc--; // Was surrogate, didn't use 2nd part either
+ }
+ Contract::Assert(pSrc >= chars || pTarget == bytes,
+ "[UTF8Encoding.GetBytes]Expected pSrc to be within buffer or to throw with insufficient room.");
+ ThrowBytesOverflow(pTarget == bytes); // Throw if we must
+ ch = 0; // Nothing left over (we backed up to start of pair if supplimentary)
+ break;
+ }
+
+ if (ch <= 0x7F) {
+ *pTarget = (BYTE)ch;
+ }
+ else {
+ // use separate helper variables for local contexts so that the jit optimizations
+ // won't get confused about the variable lifetimes
+ int chb;
+ if (ch <= 0x7FF) {
+ // 2 BYTE encoding
+ chb = (BYTE)(0xC0 | (ch >> 6));
+ }
+ else
+ {
+ if (ch <= 0xFFFF) {
+ chb = (BYTE)(0xE0 | (ch >> 12));
+ }
+ else
+ {
+ *pTarget = (BYTE)(0xF0 | (ch >> 18));
+ pTarget++;
+
+ chb = 0x80 | ((ch >> 12) & 0x3F);
+ }
+ *pTarget = (BYTE)chb;
+ pTarget++;
+
+ chb = 0x80 | ((ch >> 6) & 0x3F);
+ }
+ *pTarget = (BYTE)chb;
+ pTarget++;
+
+ *pTarget = (BYTE)0x80 | (ch & 0x3F);
+ }
+ pTarget++;
+
+
+#ifdef FASTLOOP
+ // If still have fallback don't do fast loop
+ if (fallbackBuffer != nullptr && (ch = fallbackBuffer->InternalGetNextChar()) != 0)
+ goto ProcessChar;
+
+ int availableChars = PtrDiff(pEnd, pSrc);
+ int availableBytes = PtrDiff(pAllocatedBufferEnd, pTarget);
+
+ // don't fall into the fast decoding loop if we don't have enough characters
+ // Note that if we don't have enough bytes, pStop will prevent us from entering the fast loop.
+ if (availableChars <= 13) {
+ // we are hoping for 1 BYTE per char
+ if (availableBytes < availableChars) {
+ // not enough output room. no pending bits at this point
+ ch = 0;
+ continue;
+ }
+
+ // try to get over the remainder of the ascii characters fast though
+ WCHAR* pLocalEnd = pEnd; // hint to get pLocalEnd enregistered
+ while (pSrc < pLocalEnd) {
+ ch = *pSrc;
+ pSrc++;
+
+ // Not ASCII, need more than 1 BYTE per char
+ if (ch > 0x7F)
+ goto ProcessChar;
+
+ *pTarget = (BYTE)ch;
+ pTarget++;
+ }
+ // we are done, let ch be 0 to clear encoder
+ ch = 0;
+ break;
+ }
+
+ // we need at least 1 BYTE per character, but Convert might allow us to convert
+ // only part of the input, so try as much as we can. Reduce charCount if necessary
+ if (availableBytes < availableChars)
+ {
+ availableChars = availableBytes;
+ }
+
+ // FASTLOOP:
+ // - optimistic range checks
+ // - fallbacks to the slow loop for all special cases, exception throwing, etc.
+
+ // To compute the upper bound, assume that all characters are ASCII characters at this point,
+ // the boundary will be decreased for every non-ASCII character we encounter
+ // Also, we need 5 chars reserve for the unrolled ansi decoding loop and for decoding of surrogates
+ // If there aren't enough bytes for the output, then pStop will be <= pSrc and will bypass the loop.
+ WCHAR *pStop = pSrc + availableChars - 5;
+
+ while (pSrc < pStop) {
+ ch = *pSrc;
+ pSrc++;
+
+ if (ch > 0x7F) {
+ goto LongCode;
+ }
+ *pTarget = (BYTE)ch;
+ pTarget++;
+
+ // get pSrc aligned
+ if (((size_t)pSrc & 0x2) != 0) {
+ ch = *pSrc;
+ pSrc++;
+ if (ch > 0x7F) {
+ goto LongCode;
+ }
+ *pTarget = (BYTE)ch;
+ pTarget++;
+ }
+
+ // Run 4 characters at a time!
+ while (pSrc < pStop) {
+ ch = *(int*)pSrc;
+ int chc = *(int*)(pSrc + 2);
+ if (((ch | chc) & (int)0xFF80FF80) != 0) {
+ goto LongCodeWithMask;
+ }
+
+ // Unfortunately, this is endianess sensitive
+#if BIGENDIAN
+ *pTarget = (BYTE)(ch >> 16);
+ *(pTarget + 1) = (BYTE)ch;
+ pSrc += 4;
+ *(pTarget + 2) = (BYTE)(chc >> 16);
+ *(pTarget + 3) = (BYTE)chc;
+ pTarget += 4;
+#else // BIGENDIAN
+ *pTarget = (BYTE)ch;
+ *(pTarget + 1) = (BYTE)(ch >> 16);
+ pSrc += 4;
+ *(pTarget + 2) = (BYTE)chc;
+ *(pTarget + 3) = (BYTE)(chc >> 16);
+ pTarget += 4;
+#endif // BIGENDIAN
+ }
+ continue;
+
+ LongCodeWithMask:
+#if BIGENDIAN
+ // be careful about the sign extension
+ ch = (int)(((uint)ch) >> 16);
+#else // BIGENDIAN
+ ch = (WCHAR)ch;
+#endif // BIGENDIAN
+ pSrc++;
+
+ if (ch > 0x7F) {
+ goto LongCode;
+ }
+ *pTarget = (BYTE)ch;
+ pTarget++;
+ continue;
+
+ LongCode:
+ // use separate helper variables for slow and fast loop so that the jit optimizations
+ // won't get confused about the variable lifetimes
+ int chd;
+ if (ch <= 0x7FF) {
+ // 2 BYTE encoding
+ chd = 0xC0 | (ch >> 6);
+ }
+ else {
+ if (!InRange(ch, CharUnicodeInfo::HIGH_SURROGATE_START, CharUnicodeInfo::LOW_SURROGATE_END)) {
+ // 3 BYTE encoding
+ chd = 0xE0 | (ch >> 12);
+ }
+ else
+ {
+ // 4 BYTE encoding - high surrogate + low surrogate
+ if (ch > CharUnicodeInfo::HIGH_SURROGATE_END) {
+ // low without high -> bad, try again in slow loop
+ pSrc -= 1;
+ break;
+ }
+
+ chd = *pSrc;
+ pSrc++;
+
+ // if (!IsLowSurrogate(chd)) {
+ if (!InRange(chd, CharUnicodeInfo::LOW_SURROGATE_START, CharUnicodeInfo::LOW_SURROGATE_END)) {
+ // high not followed by low -> bad, try again in slow loop
+ pSrc -= 2;
+ break;
+ }
+
+ ch = chd + (ch << 10) +
+ (0x10000
+ - CharUnicodeInfo::LOW_SURROGATE_START
+ - (CharUnicodeInfo::HIGH_SURROGATE_START << 10));
+
+ *pTarget = (BYTE)(0xF0 | (ch >> 18));
+ // pStop - this BYTE is compensated by the second surrogate character
+ // 2 input chars require 4 output bytes. 2 have been anticipated already
+ // and 2 more will be accounted for by the 2 pStop-- calls below.
+ pTarget++;
+
+ chd = 0x80 | ((ch >> 12) & 0x3F);
+ }
+ *pTarget = (BYTE)chd;
+ pStop--; // 3 BYTE sequence for 1 char, so need pStop-- and the one below too.
+ pTarget++;
+
+ chd = 0x80 | ((ch >> 6) & 0x3F);
+ }
+ *pTarget = (BYTE)chd;
+ pStop--; // 2 BYTE sequence for 1 char so need pStop--.
+ pTarget++;
+
+ *pTarget = (BYTE)(0x80 | (ch & 0x3F));
+ // pStop - this BYTE is already included
+ pTarget++;
+ }
+
+ Contract::Assert(pTarget <= pAllocatedBufferEnd, "[UTF8Encoding.GetBytes]pTarget <= pAllocatedBufferEnd");
+
+#endif // FASTLOOP
+
+ // no pending char at this point
+ ch = 0;
+ }
+
+ return (int)(pTarget - bytes);
+ }
+
+ int GetByteCount(WCHAR *chars, int count)
+ {
+ // For fallback we may need a fallback buffer.
+ // We wait to initialize it though in case we don't have any broken input unicode
+ EncoderFallbackBuffer* fallbackBuffer = nullptr;
+ WCHAR *pSrc = chars;
+ WCHAR *pEnd = pSrc + count;
+
+ // Start by assuming we have as many as count
+ int byteCount = count;
+
+ int ch = 0;
+
+ for (;;) {
+ // SLOWLOOP: does all range checks, handles all special cases, but it is slow
+ if (pSrc >= pEnd) {
+
+ if (ch == 0) {
+ // Unroll any fallback that happens at the end
+ ch = fallbackBuffer != nullptr ? fallbackBuffer->InternalGetNextChar() : 0;
+ if (ch > 0) {
+ byteCount++;
+ goto ProcessChar;
+ }
+ }
+ else {
+ // Case of surrogates in the fallback.
+ if (fallbackBuffer != nullptr && fallbackBuffer->bFallingBack) {
+ Contract::Assert(ch >= 0xD800 && ch <= 0xDBFF,
+ "[UTF8Encoding.GetBytes]expected high surrogate");// , not 0x" + ((int)ch).ToString("X4", CultureInfo.InvariantCulture));
+
+ ch = fallbackBuffer->InternalGetNextChar();
+ byteCount++;
+
+ if (InRange(ch, CharUnicodeInfo::LOW_SURROGATE_START, CharUnicodeInfo::LOW_SURROGATE_END)) {
+ ch = 0xfffd;
+ byteCount++;
+ goto EncodeChar;
+ }
+ else if (ch > 0){
+ goto ProcessChar;
+ }
+ else {
+ byteCount--; // ignore last one.
+ break;
+ }
+ }
+ }
+
+ if (ch <= 0) {
+ break;
+ }
+
+ // attempt to encode the partial surrogate (will fallback or ignore it), it'll also subtract 1.
+ byteCount++;
+ goto EncodeChar;
+ }
+
+ if (ch > 0) {
+ Contract::Assert(ch >= 0xD800 && ch <= 0xDBFF,
+ "[UTF8Encoding.GetBytes]expected high surrogate"); // , not 0x" + ((int)ch).ToString("X4", CultureInfo.InvariantCulture));
+
+ // use separate helper variables for local contexts so that the jit optimizations
+ // won't get confused about the variable lifetimes
+ int cha = *pSrc;
+
+ // count the pending surrogate
+ byteCount++;
+
+ // In previous byte, we encountered a high surrogate, so we are expecting a low surrogate here.
+ // if (IsLowSurrogate(cha)) {
+ if (InRange(cha, CharUnicodeInfo::LOW_SURROGATE_START, CharUnicodeInfo::LOW_SURROGATE_END)) {
+ // Don't need a real # because we're just counting, anything > 0x7ff ('cept surrogate) will do.
+ ch = 0xfffd;
+ // ch = cha + (ch << 10) +
+ // (0x10000
+ // - CharUnicodeInfo::LOW_SURROGATE_START
+ // - (CharUnicodeInfo::HIGH_SURROGATE_START << 10) );
+
+ // Use this next char
+ pSrc++;
+ }
+ // else ch is still high surrogate and encoding will fail (so don't add count)
+
+ // attempt to encode the surrogate or partial surrogate
+ goto EncodeChar;
+ }
+
+ // If we've used a fallback, then we have to check for it
+ if (fallbackBuffer != nullptr)
+ {
+ ch = fallbackBuffer->InternalGetNextChar();
+ if (ch > 0)
+ {
+ // We have an extra byte we weren't expecting.
+ byteCount++;
+ goto ProcessChar;
+ }
+ }
+
+ // read next char. The JIT optimization seems to be getting confused when
+ // compiling "ch = *pSrc++;", so rather use "ch = *pSrc; pSrc++;" instead
+ ch = *pSrc;
+ pSrc++;
+
+ ProcessChar:
+ if (InRange(ch, CharUnicodeInfo::HIGH_SURROGATE_START, CharUnicodeInfo::HIGH_SURROGATE_END)) {
+ // we will count this surrogate next time around
+ byteCount--;
+ continue;
+ }
+ // either good char or partial surrogate
+
+ EncodeChar:
+ // throw exception on partial surrogate if necessary
+ if (InRange(ch, CharUnicodeInfo::HIGH_SURROGATE_START, CharUnicodeInfo::LOW_SURROGATE_END))
+ {
+ // Lone surrogates aren't allowed
+ // Have to make a fallback buffer if we don't have one
+ if (fallbackBuffer == nullptr)
+ {
+ // wait on fallbacks if we can
+ // For fallback we may need a fallback buffer
+ fallbackBuffer = encoderFallback->CreateFallbackBuffer();
+
+ // Set our internal fallback interesting things.
+ fallbackBuffer->InternalInitialize(chars, chars + count, false);
+ }
+
+ // Do our fallback. Actually we already know its a mixed up surrogate,
+ // so the ref pSrc isn't gonna do anything.
+ fallbackBuffer->InternalFallback((WCHAR)ch, &pSrc);
+
+ // Ignore it if we don't throw (we had preallocated this ch)
+ byteCount--;
+ ch = 0;
+ continue;
+ }
+
+ // Count them
+ if (ch > 0x7F) {
+ if (ch > 0x7FF) {
+ // the extra surrogate byte was compensated by the second surrogate character
+ // (2 surrogates make 4 bytes. We've already counted 2 bytes, 1 per char)
+ byteCount++;
+ }
+ byteCount++;
+ }
+
+#if WIN64
+ // check for overflow
+ if (byteCount < 0) {
+ break;
+ }
+#endif
+
+#ifdef FASTLOOP
+ // If still have fallback don't do fast loop
+ if (fallbackBuffer != nullptr && (ch = fallbackBuffer->InternalGetNextChar()) != 0)
+ {
+ // We're reserving 1 byte for each char by default
+ byteCount++;
+ goto ProcessChar;
+ }
+
+ int availableChars = PtrDiff(pEnd, pSrc);
+
+ // don't fall into the fast decoding loop if we don't have enough characters
+ if (availableChars <= 13) {
+ // try to get over the remainder of the ascii characters fast though
+ WCHAR* pLocalEnd = pEnd; // hint to get pLocalEnd enregistered
+ while (pSrc < pLocalEnd) {
+ ch = *pSrc;
+ pSrc++;
+ if (ch > 0x7F)
+ goto ProcessChar;
+ }
+
+ // we are done
+ break;
+ }
+
+#if WIN64
+ // make sure that we won't get a silent overflow inside the fast loop
+ // (Fall out to slow loop if we have this many characters)
+ availableChars &= 0x0FFFFFFF;
+#endif
+
+ // To compute the upper bound, assume that all characters are ASCII characters at this point,
+ // the boundary will be decreased for every non-ASCII character we encounter
+ // Also, we need 3 + 4 chars reserve for the unrolled ansi decoding loop and for decoding of surrogates
+ WCHAR *pStop = pSrc + availableChars - (3 + 4);
+
+ while (pSrc < pStop) {
+ ch = *pSrc;
+ pSrc++;
+
+ if (ch > 0x7F) // Not ASCII
+ {
+ if (ch > 0x7FF) // Not 2 Byte
+ {
+ if ((ch & 0xF800) == 0xD800) // See if its a Surrogate
+ goto LongCode;
+ byteCount++;
+ }
+ byteCount++;
+ }
+
+ // get pSrc aligned
+ if (((int)pSrc & 0x2) != 0) {
+ ch = *pSrc;
+ pSrc++;
+ if (ch > 0x7F) // Not ASCII
+ {
+ if (ch > 0x7FF) // Not 2 Byte
+ {
+ if ((ch & 0xF800) == 0xD800) // See if its a Surrogate
+ goto LongCode;
+ byteCount++;
+ }
+ byteCount++;
+ }
+ }
+
+ // Run 2 * 4 characters at a time!
+ while (pSrc < pStop) {
+ ch = *(int*)pSrc;
+ int chc = *(int*)(pSrc + 2);
+ if (((ch | chc) & (int)0xFF80FF80) != 0) // See if not ASCII
+ {
+ if (((ch | chc) & (int)0xF800F800) != 0) // See if not 2 Byte
+ {
+ goto LongCodeWithMask;
+ }
+
+
+ if ((ch & (int)0xFF800000) != 0) // Actually 0x07800780 is all we care about (4 bits)
+ byteCount++;
+ if ((ch & (int)0xFF80) != 0)
+ byteCount++;
+ if ((chc & (int)0xFF800000) != 0)
+ byteCount++;
+ if ((chc & (int)0xFF80) != 0)
+ byteCount++;
+ }
+ pSrc += 4;
+
+ ch = *(int*)pSrc;
+ chc = *(int*)(pSrc + 2);
+ if (((ch | chc) & (int)0xFF80FF80) != 0) // See if not ASCII
+ {
+ if (((ch | chc) & (int)0xF800F800) != 0) // See if not 2 Byte
+ {
+ goto LongCodeWithMask;
+ }
+
+ if ((ch & (int)0xFF800000) != 0)
+ byteCount++;
+ if ((ch & (int)0xFF80) != 0)
+ byteCount++;
+ if ((chc & (int)0xFF800000) != 0)
+ byteCount++;
+ if ((chc & (int)0xFF80) != 0)
+ byteCount++;
+ }
+ pSrc += 4;
+ }
+ break;
+
+ LongCodeWithMask:
+#if BIGENDIAN
+ // be careful about the sign extension
+ ch = (int)(((uint)ch) >> 16);
+#else // BIGENDIAN
+ ch = (WCHAR)ch;
+#endif // BIGENDIAN
+ pSrc++;
+
+ if (ch <= 0x7F) {
+ continue;
+ }
+
+ LongCode:
+ // use separate helper variables for slow and fast loop so that the jit optimizations
+ // won't get confused about the variable lifetimes
+ if (ch > 0x7FF) {
+ if (InRange(ch, CharUnicodeInfo::HIGH_SURROGATE_START, CharUnicodeInfo::LOW_SURROGATE_END)) {
+ // 4 byte encoding - high surrogate + low surrogate
+
+ int chd = *pSrc;
+ if (
+ ch > CharUnicodeInfo::HIGH_SURROGATE_END ||
+ !InRange(chd, CharUnicodeInfo::LOW_SURROGATE_START, CharUnicodeInfo::LOW_SURROGATE_END))
+ {
+ // Back up and drop out to slow loop to figure out error
+ pSrc--;
+ break;
+ }
+ pSrc++;
+
+ // byteCount - this byte is compensated by the second surrogate character
+ }
+ byteCount++;
+ }
+ byteCount++;
+
+ // byteCount - the last byte is already included
+ }
+#endif // FASTLOOP
+
+ // no pending char at this point
+ ch = 0;
+ }
+
+#if WIN64
+ // check for overflow
+ if (byteCount < 0) {
+ throw ArgumentException("Conversion buffer overflow.");
+ }
+#endif
+
+ Contract::Assert(fallbackBuffer == nullptr || fallbackBuffer->GetRemaining() == 0,
+ "[UTF8Encoding.GetByteCount]Expected Empty fallback buffer");
+
+ return byteCount;
+ }
+
+};
+
+
+////////////////////////////////////////////////////////////////////////////
+//
+// UTF8ToUnicode
+//
+// Maps a UTF-8 character string to its wide character string counterpart.
+//
+////////////////////////////////////////////////////////////////////////////
+
+int UTF8ToUnicode(
+ LPCSTR lpSrcStr,
+ int cchSrc,
+ LPWSTR lpDestStr,
+ int cchDest,
+ DWORD dwFlags
+ )
+{
+ int ret;
+ UTF8Encoding enc(dwFlags & MB_ERR_INVALID_CHARS);
+ try {
+ ret = enc.GetCharCount((BYTE*)lpSrcStr, cchSrc);
+ if (cchDest){
+ if (ret > cchDest){
+ SetLastError(ERROR_INSUFFICIENT_BUFFER);
+ ret = 0;
+ }
+ enc.GetChars((BYTE*)lpSrcStr, cchSrc, (WCHAR*)lpDestStr, ret);
+ }
+ }
+ catch (const InsufficientBufferException& e){
+ SetLastError(ERROR_INSUFFICIENT_BUFFER);
+ return 0;
+ }
+ catch (const DecoderFallbackException& e){
+ SetLastError(ERROR_NO_UNICODE_TRANSLATION);
+ return 0;
+ }
+ catch (const ArgumentException& e){
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return 0;
+ }
+ return ret;
+}
+
+////////////////////////////////////////////////////////////////////////////
+//
+// UnicodeToUTF8
+//
+// Maps a Unicode character string to its UTF-8 string counterpart.
+//
+////////////////////////////////////////////////////////////////////////////
+
+int UnicodeToUTF8(
+ LPCWSTR lpSrcStr,
+ int cchSrc,
+ LPSTR lpDestStr,
+ int cchDest)
+{
+ int ret;
+ UTF8Encoding enc(false);
+ try{
+ ret = enc.GetByteCount((WCHAR*)lpSrcStr, cchSrc);
+ if (cchDest){
+ if (ret > cchDest){
+ SetLastError(ERROR_INSUFFICIENT_BUFFER);
+ ret = 0;
+ }
+ enc.GetBytes((WCHAR*)lpSrcStr, cchSrc, (BYTE*)lpDestStr, ret);
+ }
+ }
+ catch (const InsufficientBufferException& e){
+ SetLastError(ERROR_INSUFFICIENT_BUFFER);
+ return 0;
+ }
+ catch (const EncoderFallbackException& e){
+ SetLastError(ERROR_NO_UNICODE_TRANSLATION);
+ return 0;
+ }
+ catch (const ArgumentException& e){
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return 0;
+ }
+ return ret;
+}
diff --git a/src/pal/src/map/common.cpp b/src/pal/src/map/common.cpp
new file mode 100644
index 0000000000..a030c3b384
--- /dev/null
+++ b/src/pal/src/map/common.cpp
@@ -0,0 +1,66 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ common.c
+
+Abstract:
+
+ Implementation of the common mapping functions.
+
+
+
+--*/
+
+#include "pal/palinternal.h"
+#include "pal/dbgmsg.h"
+
+#include "common.h"
+
+#include <sys/mman.h>
+
+SET_DEFAULT_DEBUG_CHANNEL(VIRTUAL);
+
+/*****
+ *
+ * W32toUnixAccessControl( DWORD ) - Maps Win32 to Unix memory access controls .
+ *
+ */
+INT W32toUnixAccessControl( IN DWORD flProtect )
+{
+ INT MemAccessControl = 0;
+
+ switch ( flProtect & 0xff )
+ {
+ case PAGE_READONLY :
+ MemAccessControl = PROT_READ;
+ break;
+ case PAGE_READWRITE :
+ MemAccessControl = PROT_READ | PROT_WRITE;
+ break;
+ case PAGE_EXECUTE_READWRITE:
+ MemAccessControl = PROT_EXEC | PROT_READ | PROT_WRITE;
+ break;
+ case PAGE_EXECUTE :
+ MemAccessControl = PROT_EXEC;
+ break;
+ case PAGE_EXECUTE_READ :
+ MemAccessControl = PROT_EXEC | PROT_READ;
+ break;
+ case PAGE_NOACCESS :
+ MemAccessControl = PROT_NONE;
+ break;
+
+ default:
+ MemAccessControl = 0;
+ ERROR( "Incorrect or no protection flags specified.\n" );
+ break;
+ }
+ return MemAccessControl;
+}
diff --git a/src/pal/src/map/common.h b/src/pal/src/map/common.h
new file mode 100644
index 0000000000..68d8fc6ae2
--- /dev/null
+++ b/src/pal/src/map/common.h
@@ -0,0 +1,43 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ include/pal/common.h
+
+Abstract:
+ Header file for common helper functions in the map module.
+
+
+
+--*/
+
+#ifndef __COMMON_H_
+#define __COMMON_H_
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/*****
+ *
+ * W32toUnixAccessControl( DWORD ) - Maps Win32 to Unix memory access controls .
+ *
+ */
+INT W32toUnixAccessControl( IN DWORD flProtect );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __COMMON_H_ */
+
+
+
+
diff --git a/src/pal/src/map/map.cpp b/src/pal/src/map/map.cpp
new file mode 100644
index 0000000000..f3ec47b846
--- /dev/null
+++ b/src/pal/src/map/map.cpp
@@ -0,0 +1,2749 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ map.cpp
+
+Abstract:
+
+ Implementation of file mapping API.
+
+
+
+--*/
+
+
+#include "pal/palinternal.h"
+#include "pal/dbgmsg.h"
+#include "pal/init.h"
+#include "pal/critsect.h"
+#include "pal/virtual.h"
+#include "pal/environ.h"
+#include "common.h"
+#include "pal/map.hpp"
+#include "pal/thread.hpp"
+#include "pal/file.hpp"
+#include "pal/malloc.hpp"
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "rt/ntimage.h"
+#include <pal_endian.h>
+
+using namespace CorUnix;
+
+SET_DEFAULT_DEBUG_CHANNEL(VIRTUAL);
+
+//
+// The mapping critical section guards access to the list
+// of currently mapped views. If a thread needs to access
+// both this critical section and the data for an object
+// it must acquire the object data first. That is, a thread
+// cannot acquire any other locks after taking hold of
+// this critical section.
+//
+
+CRITICAL_SECTION mapping_critsec;
+LIST_ENTRY MappedViewList;
+
+#ifndef CORECLR
+static PAL_ERROR MAPCreateTempFile(CPalThread *, PINT, PSZ);
+#endif // !CORECLR
+static PAL_ERROR MAPGrowLocalFile(INT, UINT);
+static PMAPPED_VIEW_LIST MAPGetViewForAddress( LPCVOID );
+static PAL_ERROR MAPDesiredAccessAllowed( DWORD, DWORD, DWORD );
+
+static INT MAPProtectionToFileOpenFlags( DWORD );
+static BOOL MAPIsRequestPermissible( DWORD, CFileProcessLocalData * );
+static BOOL MAPContainsInvalidFlags( DWORD );
+static DWORD MAPConvertProtectToAccess( DWORD );
+static INT MAPFileMapToMmapFlags( DWORD );
+static DWORD MAPMmapProtToAccessFlags( int prot );
+#if ONE_SHARED_MAPPING_PER_FILEREGION_PER_PROCESS
+static NativeMapHolder * NewNativeMapHolder(CPalThread *pThread, LPVOID address, SIZE_T size,
+ SIZE_T offset, long init_ref_count);
+static LONG NativeMapHolderAddRef(NativeMapHolder * thisPMH);
+static LONG NativeMapHolderRelease(CPalThread *pThread, NativeMapHolder * thisPMH);
+static PMAPPED_VIEW_LIST FindSharedMappingReplacement(CPalThread *pThread, dev_t deviceNum, ino_t inodeNum,
+ SIZE_T size, SIZE_T offset);
+#endif
+
+static PAL_ERROR
+MAPRecordMapping(
+ IPalObject *pMappingObject,
+ void *pPEBaseAddress,
+ void *addr,
+ size_t len,
+ int prot
+ );
+
+static PAL_ERROR
+MAPmmapAndRecord(
+ IPalObject *pMappingObject,
+ void *pPEBaseAddress,
+ void *addr,
+ size_t len,
+ int prot,
+ int flags,
+ int fd,
+ off_t offset,
+ LPVOID *ppvBaseAddress
+ );
+
+#if !HAVE_MMAP_DEV_ZERO
+/* We need MAP_ANON. However on some platforms like HP-UX, it is defined as MAP_ANONYMOUS */
+#if !defined(MAP_ANON) && defined(MAP_ANONYMOUS)
+#define MAP_ANON MAP_ANONYMOUS
+#endif
+#endif
+
+void
+FileMappingCleanupRoutine(
+ CPalThread *pThread,
+ IPalObject *pObjectToCleanup,
+ bool fShutdown,
+ bool fCleanupSharedState
+ );
+
+PAL_ERROR
+FileMappingInitializationRoutine(
+ CPalThread *pThread,
+ CObjectType *pObjectType,
+ void *pImmutableData,
+ void *pSharedData,
+ void *pProcessLocalData
+ );
+
+CObjectType CorUnix::otFileMapping(
+ otiFileMapping,
+ FileMappingCleanupRoutine,
+ FileMappingInitializationRoutine,
+ sizeof(CFileMappingImmutableData),
+ sizeof(CFileMappingProcessLocalData),
+ 0,
+ PAGE_READWRITE | PAGE_READONLY | PAGE_WRITECOPY,
+ CObjectType::SecuritySupported,
+ CObjectType::SecurityInfoNotPersisted,
+ CObjectType::UnnamedObject,
+ CObjectType::LocalDuplicationOnly,
+ CObjectType::UnwaitableObject,
+ CObjectType::SignalingNotApplicable,
+ CObjectType::ThreadReleaseNotApplicable,
+ CObjectType::OwnershipNotApplicable
+ );
+
+CAllowedObjectTypes aotFileMapping(otiFileMapping);
+
+void
+FileMappingCleanupRoutine(
+ CPalThread *pThread,
+ IPalObject *pObjectToCleanup,
+ bool fShutdown,
+ bool fCleanupSharedState
+ )
+{
+ PAL_ERROR palError = NO_ERROR;
+ CFileMappingImmutableData *pImmutableData = NULL;
+ CFileMappingProcessLocalData *pLocalData = NULL;
+ IDataLock *pLocalDataLock = NULL;
+ bool fDataChanged = FALSE;
+
+ if (TRUE == fCleanupSharedState)
+ {
+ //
+ // If we created a temporary file to back this mapping we need
+ // to unlink it now
+ //
+
+ palError = pObjectToCleanup->GetImmutableData(
+ reinterpret_cast<void**>(&pImmutableData)
+ );
+
+ if (NO_ERROR != palError)
+ {
+ ASSERT("Unable to obtain immutable data for object to be reclaimed");
+ return;
+ }
+
+ if (pImmutableData->bPALCreatedTempFile)
+ {
+ unlink(pImmutableData->szFileName);
+ }
+ }
+
+ if (FALSE == fShutdown)
+ {
+ //
+ // We only need to close the object's descriptor if we're not
+ // shutting down
+ //
+
+ palError = pObjectToCleanup->GetProcessLocalData(
+ pThread,
+ WriteLock,
+ &pLocalDataLock,
+ reinterpret_cast<void**>(&pLocalData)
+ );
+
+ if (NO_ERROR != palError)
+ {
+ ASSERT("Unable to obtain process local data for object to be reclaimed");
+ return;
+ }
+
+ if (-1 != pLocalData->UnixFd)
+ {
+ close(pLocalData->UnixFd);
+ pLocalData->UnixFd = -1;
+ fDataChanged = TRUE;
+ }
+
+ pLocalDataLock->ReleaseLock(pThread, fDataChanged);
+ }
+
+ //
+ // Why don't we need to deal with any views that may have been created
+ // from this mapping? If the process is shutting down then there's nothing
+ // that we need to take care of, as the OS will remove the underlying
+ // mappings when the process goes away. If we're not shutting down then
+ // there's no way for a view to exist against this mapping, since each
+ // view holds a reference against the mapping object.
+ //
+}
+
+PAL_ERROR
+FileMappingInitializationRoutine(
+ CPalThread *pThread,
+ CObjectType *pObjectType,
+ void *pvImmutableData,
+ void *pvSharedData,
+ void *pvProcessLocalData
+ )
+{
+ PAL_ERROR palError = NO_ERROR;
+
+ CFileMappingImmutableData *pImmutableData =
+ reinterpret_cast<CFileMappingImmutableData *>(pvImmutableData);
+ CFileMappingProcessLocalData *pProcessLocalData =
+ reinterpret_cast<CFileMappingProcessLocalData *>(pvProcessLocalData);
+
+ pProcessLocalData->UnixFd = InternalOpen(
+ pImmutableData->szFileName,
+ MAPProtectionToFileOpenFlags(pImmutableData->flProtect)
+ );
+
+ if (-1 == pProcessLocalData->UnixFd)
+ {
+ palError = ERROR_INTERNAL_ERROR;
+ goto ExitFileMappingInitializationRoutine;
+ }
+
+#if ONE_SHARED_MAPPING_PER_FILEREGION_PER_PROCESS
+ struct stat st;
+
+ if (0 == fstat(pProcessLocalData->UnixFd, &st))
+ {
+ pProcessLocalData->MappedFileDevNum = st.st_dev;
+ pProcessLocalData->MappedFileInodeNum = st.st_ino;
+ }
+ else
+ {
+ ERROR("Couldn't get inode info for fd=%d to be stored in mapping object\n", pProcessLocalData->UnixFd);
+ }
+#endif
+
+ExitFileMappingInitializationRoutine:
+
+ return palError;
+}
+
+/*++
+Function:
+ CreateFileMappingA
+
+Note:
+ File mapping are used to do inter-process communication.
+
+See MSDN doc.
+--*/
+HANDLE
+PALAPI
+CreateFileMappingA(
+ IN HANDLE hFile,
+ IN LPSECURITY_ATTRIBUTES lpFileMappingAttributes,
+ IN DWORD flProtect,
+ IN DWORD dwMaximumSizeHigh,
+ IN DWORD dwMaximumSizeLow,
+ IN LPCSTR lpName)
+{
+ HANDLE hFileMapping = NULL;
+ CPalThread *pThread = NULL;
+ PAL_ERROR palError = NO_ERROR;
+
+ PERF_ENTRY(CreateFileMappingA);
+ ENTRY("CreateFileMappingA(hFile=%p, lpAttributes=%p, flProtect=%#x, "
+ "dwMaxSizeH=%d, dwMaxSizeL=%d, lpName=%p (%s))\n",
+ hFile, lpFileMappingAttributes, flProtect,
+ dwMaximumSizeHigh, dwMaximumSizeLow,
+ lpName?lpName:"NULL",
+ lpName?lpName:"NULL");
+
+ pThread = InternalGetCurrentThread();
+
+ if (lpName != nullptr)
+ {
+ ASSERT("lpName: Cross-process named objects are not supported in PAL");
+ palError = ERROR_NOT_SUPPORTED;
+ }
+ else
+ {
+ palError = InternalCreateFileMapping(
+ pThread,
+ hFile,
+ lpFileMappingAttributes,
+ flProtect,
+ dwMaximumSizeHigh,
+ dwMaximumSizeLow,
+ NULL,
+ &hFileMapping
+ );
+ }
+
+
+ //
+ // We always need to set last error, even on success:
+ // we need to protect ourselves from the situation
+ // where last error is set to ERROR_ALREADY_EXISTS on
+ // entry to the function
+ //
+
+ pThread->SetLastError(palError);
+
+ LOGEXIT( "CreateFileMappingA returns HANDLE %p. \n", hFileMapping );
+ PERF_EXIT(CreateFileMappingA);
+ return hFileMapping;
+}
+
+/*++
+Function:
+ CreateFileMappingW
+
+Note:
+ File mapping are used to do inter-process communication.
+
+See MSDN doc.
+--*/
+HANDLE
+PALAPI
+CreateFileMappingW(
+ IN HANDLE hFile,
+ IN LPSECURITY_ATTRIBUTES lpFileMappingAttributes,
+ IN DWORD flProtect,
+ IN DWORD dwMaximumSizeHigh,
+ IN DWORD dwMaximumSizeLow,
+ IN LPCWSTR lpName)
+{
+ HANDLE hFileMapping = NULL;
+ CPalThread *pThread = NULL;
+ PAL_ERROR palError = NO_ERROR;
+
+ PERF_ENTRY(CreateFileMappingW);
+ ENTRY("CreateFileMappingW(hFile=%p, lpAttributes=%p, flProtect=%#x, "
+ "dwMaxSizeH=%u, dwMaxSizeL=%u, lpName=%p (%S))\n",
+ hFile, lpFileMappingAttributes, flProtect, dwMaximumSizeHigh,
+ dwMaximumSizeLow, lpName?lpName:W16_NULLSTRING, lpName?lpName:W16_NULLSTRING);
+
+ pThread = InternalGetCurrentThread();
+
+ palError = InternalCreateFileMapping(
+ pThread,
+ hFile,
+ lpFileMappingAttributes,
+ flProtect,
+ dwMaximumSizeHigh,
+ dwMaximumSizeLow,
+ lpName,
+ &hFileMapping
+ );
+
+ //
+ // We always need to set last error, even on success:
+ // we need to protect ourselves from the situation
+ // where last error is set to ERROR_ALREADY_EXISTS on
+ // entry to the function
+ //
+
+ pThread->SetLastError(palError);
+
+ LOGEXIT( "CreateFileMappingW returning %p .\n", hFileMapping );
+ PERF_EXIT(CreateFileMappingW);
+ return hFileMapping;
+}
+
+PAL_ERROR
+CorUnix::InternalCreateFileMapping(
+ CPalThread *pThread,
+ HANDLE hFile,
+ LPSECURITY_ATTRIBUTES lpFileMappingAttributes,
+ DWORD flProtect,
+ DWORD dwMaximumSizeHigh,
+ DWORD dwMaximumSizeLow,
+ LPCWSTR lpName,
+ HANDLE *phMapping
+ )
+{
+ CObjectAttributes objectAttributes(lpName, lpFileMappingAttributes);
+ PAL_ERROR palError = NO_ERROR;
+ IPalObject *pMapping = NULL;
+ IPalObject *pRegisteredMapping = NULL;
+ CFileMappingProcessLocalData *pLocalData = NULL;
+ IDataLock *pLocalDataLock = NULL;
+ CFileMappingImmutableData *pImmutableData = NULL;
+ IPalObject *pFileObject = NULL;
+ CFileProcessLocalData *pFileLocalData = NULL;
+ IDataLock *pFileLocalDataLock = NULL;
+
+ struct stat UnixFileInformation;
+ INT UnixFd = -1;
+ BOOL bPALCreatedTempFile = FALSE;
+ UINT nFileSize = 0;
+
+ //
+ // Validate parameters
+ //
+
+ if (lpName != nullptr)
+ {
+ ASSERT("lpName: Cross-process named objects are not supported in PAL");
+ palError = ERROR_NOT_SUPPORTED;
+ goto ExitInternalCreateFileMapping;
+ }
+
+ if (0 != dwMaximumSizeHigh)
+ {
+ ASSERT("dwMaximumSizeHigh is always 0.\n");
+ palError = ERROR_INVALID_PARAMETER;
+ goto ExitInternalCreateFileMapping;
+ }
+
+ if (PAGE_READWRITE != flProtect
+ && PAGE_READONLY != flProtect
+ && PAGE_WRITECOPY != flProtect)
+ {
+ ASSERT( "invalid flProtect %#x, acceptable values are PAGE_READONLY "
+ "(%#x), PAGE_READWRITE (%#x) and PAGE_WRITECOPY (%#x).\n",
+ flProtect, PAGE_READONLY, PAGE_READWRITE, PAGE_WRITECOPY );
+ palError = ERROR_INVALID_PARAMETER;
+ goto ExitInternalCreateFileMapping;
+ }
+
+ if (hFile == INVALID_HANDLE_VALUE && 0 == dwMaximumSizeLow)
+ {
+ ERROR( "If hFile is INVALID_HANDLE_VALUE, then you must specify a size.\n" );
+ palError = ERROR_INVALID_PARAMETER;
+ goto ExitInternalCreateFileMapping;
+ }
+
+ if (hFile != INVALID_HANDLE_VALUE && NULL != lpName)
+ {
+ ASSERT( "If hFile is not -1, then lpName must be NULL.\n" );
+ palError = ERROR_INVALID_PARAMETER;
+ goto ExitInternalCreateFileMapping;
+ }
+
+ palError = g_pObjectManager->AllocateObject(
+ pThread,
+ &otFileMapping,
+ &objectAttributes,
+ &pMapping
+ );
+
+ if (NO_ERROR != palError)
+ {
+ goto ExitInternalCreateFileMapping;
+ }
+
+ palError = pMapping->GetImmutableData(reinterpret_cast<void**>(&pImmutableData));
+ if (NO_ERROR != palError)
+ {
+ goto ExitInternalCreateFileMapping;
+ }
+
+ if (hFile == INVALID_HANDLE_VALUE
+#ifndef CORECLR
+ && NULL == lpName
+#endif // !CORECLR
+ )
+ {
+ //
+ // Note: this path is what prevents us supporting the
+ // duplication of file mapping objects across processes, since
+ // there is no backing file that the other process can open. We can
+ // avoid this restriction by always using a temp backing file for
+ // anonymous mappings.
+ //
+
+ /* Anonymous mapped files. */
+ if (strcpy_s(pImmutableData->szFileName, sizeof(pImmutableData->szFileName), "/dev/zero") != SAFECRT_SUCCESS)
+ {
+ ERROR( "strcpy_s failed!\n" );
+ palError = ERROR_INTERNAL_ERROR;
+ goto ExitInternalCreateFileMapping;
+ }
+
+#if HAVE_MMAP_DEV_ZERO
+
+ UnixFd = InternalOpen(pImmutableData->szFileName, O_RDWR);
+ if ( -1 == UnixFd )
+ {
+ ERROR( "Unable to open the file.\n");
+ palError = ERROR_INTERNAL_ERROR;
+ goto ExitInternalCreateFileMapping;
+ }
+
+#else //!HAVE_MMAP_DEV_ZERO
+
+ UnixFd = -1; /* will pass MAP_ANON to mmap() instead */
+
+#endif //!HAVE_MMAP_DEV_ZERO
+
+ }
+ else
+ {
+ if ( hFile != INVALID_HANDLE_VALUE )
+ {
+ palError = g_pObjectManager->ReferenceObjectByHandle(
+ pThread,
+ hFile,
+ &aotFile,
+ GENERIC_READ,
+ &pFileObject
+ );
+
+ if (NO_ERROR != palError)
+ {
+ ERROR("Unable to obtain file data.\n");
+ palError = ERROR_INVALID_PARAMETER;
+ goto ExitInternalCreateFileMapping;
+ }
+
+ palError = pFileObject->GetProcessLocalData(
+ pThread,
+ ReadLock,
+ &pFileLocalDataLock,
+ reinterpret_cast<void**>(&pFileLocalData)
+ );
+
+ if (NO_ERROR != palError)
+ {
+ goto ExitInternalCreateFileMapping;
+ }
+
+ /* We need to check to ensure flProtect jives with
+ the permission on the file handle */
+ if (!MAPIsRequestPermissible(flProtect, pFileLocalData))
+ {
+ ERROR("File handle does not have the correct "
+ "permissions to create mapping\n" );
+ palError = ERROR_ACCESS_DENIED;
+ if (NULL != pFileLocalDataLock)
+ {
+ pFileLocalDataLock->ReleaseLock(pThread, FALSE);
+ }
+ goto ExitInternalCreateFileMapping;
+ }
+
+ //
+ // TODO: technically, the file mapping object should hold
+ // a reference to the passed in file object. This implementation
+ // only keeps the underlying native file structure (i.e., what
+ // the duplicated descriptors point to) open. There may be a risk
+ // here pertaining to the file lock information that the PAL must
+ // maintain (e.g,. if the passed in handle is closed immediately
+ // after the file mapping is opened then the lock information will
+ // be released, since we're not doing anything to keep it alive
+ // here).
+ //
+ // Having a direct reference to the underlying file object adds
+ // some complication, especially in cross-process cases. We may
+ // want to consider adding a reference to the PAL's file lock
+ // information, though...
+ //
+
+ UnixFd = dup(pFileLocalData->unix_fd);
+ if (-1 == UnixFd)
+ {
+ ERROR( "Unable to duplicate the Unix file descriptor!\n" );
+ palError = ERROR_INTERNAL_ERROR;
+ if (NULL != pFileLocalDataLock)
+ {
+ pFileLocalDataLock->ReleaseLock(pThread, FALSE);
+ }
+ goto ExitInternalCreateFileMapping;
+ }
+
+ if (strcpy_s(pImmutableData->szFileName, sizeof(pImmutableData->szFileName), pFileLocalData->unix_filename) != SAFECRT_SUCCESS)
+ {
+ ERROR( "strcpy_s failed!\n" );
+ palError = ERROR_INTERNAL_ERROR;
+ if (NULL != pFileLocalDataLock)
+ {
+ pFileLocalDataLock->ReleaseLock(pThread, FALSE);
+ }
+ goto ExitInternalCreateFileMapping;
+ }
+
+ if (NULL != pFileLocalDataLock)
+ {
+ pFileLocalDataLock->ReleaseLock(pThread, FALSE);
+ }
+ }
+ else
+ {
+#ifndef CORECLR
+ TRACE( "INVALID_HANDLE_VALUE was the hFile, time to try to create a "
+ "temporary file" );
+
+ /* Create a temporary file on the filesystem in order to be
+ shared across processes. */
+ palError = MAPCreateTempFile(pThread, &UnixFd, pImmutableData->szFileName);
+ if (NO_ERROR != palError)
+ {
+ ERROR("Unable to create the temporary file.\n");
+ goto ExitInternalCreateFileMapping;
+ }
+ bPALCreatedTempFile = TRUE;
+#else // !CORECLR
+ ASSERT("should not get here\n");
+ palError = ERROR_INTERNAL_ERROR;
+ goto ExitInternalCreateFileMapping;
+#endif // !CORECLR
+ }
+
+ if (-1 == fstat(UnixFd, &UnixFileInformation))
+ {
+ ASSERT("fstat() failed for this reason %s.\n", strerror(errno));
+ palError = ERROR_INTERNAL_ERROR;
+ goto ExitInternalCreateFileMapping;
+ }
+
+ if ( 0 == UnixFileInformation.st_size &&
+ 0 == dwMaximumSizeHigh && 0 == dwMaximumSizeLow )
+ {
+ ERROR( "The file cannot be a zero length file.\n" );
+ palError = ERROR_FILE_INVALID;
+ goto ExitInternalCreateFileMapping;
+ }
+
+ if ( INVALID_HANDLE_VALUE != hFile &&
+ dwMaximumSizeLow > (DWORD) UnixFileInformation.st_size &&
+ ( PAGE_READONLY == flProtect || PAGE_WRITECOPY == flProtect ) )
+ {
+ /* In this situation, Windows returns an error, because the
+ permissions requested do not allow growing the file */
+ ERROR( "The file cannot be grown do to the map's permissions.\n" );
+ palError = ERROR_NOT_ENOUGH_MEMORY;
+ goto ExitInternalCreateFileMapping;
+ }
+
+ if ( (DWORD) UnixFileInformation.st_size < dwMaximumSizeLow )
+ {
+ TRACE( "Growing the size of file on disk to match requested size.\n" );
+
+ /* Need to grow the file on disk to match size. */
+ palError = MAPGrowLocalFile(UnixFd, dwMaximumSizeLow);
+ if (NO_ERROR != palError)
+ {
+ ERROR( "Unable to grow the file on disk.\n" );
+ goto ExitInternalCreateFileMapping;
+ }
+ }
+ }
+
+ nFileSize = ( 0 == dwMaximumSizeLow && 0 == dwMaximumSizeHigh ) ?
+ UnixFileInformation.st_size : dwMaximumSizeLow;
+
+ pImmutableData->MaxSize = nFileSize;
+ pImmutableData->flProtect = flProtect;
+ pImmutableData->bPALCreatedTempFile = bPALCreatedTempFile;
+ pImmutableData->dwDesiredAccessWhenOpened = MAPConvertProtectToAccess(flProtect);
+
+
+ //
+ // The local data isn't grabbed / modified until here so that we don't
+ // need to worry ourselves with locking issues with the passed in
+ // file handle -- all operations concerning the file handle are completed
+ // before we deal with the lock for the new object.
+ //
+
+ palError = pMapping->GetProcessLocalData(
+ pThread,
+ WriteLock,
+ &pLocalDataLock,
+ reinterpret_cast<void**>(&pLocalData)
+ );
+
+ if (NO_ERROR != palError)
+ {
+ goto ExitInternalCreateFileMapping;
+ }
+
+ pLocalData->UnixFd = UnixFd;
+
+#if ONE_SHARED_MAPPING_PER_FILEREGION_PER_PROCESS
+ if (-1 == UnixFd)
+ {
+ pLocalData->MappedFileDevNum = (dev_t)-1; /* there is no standard NO_DEV */
+ pLocalData->MappedFileInodeNum = NO_INO;
+ }
+ else
+ {
+ struct stat st;
+
+ if (0 == fstat(UnixFd, &st))
+ {
+ pLocalData->MappedFileDevNum = st.st_dev;
+ pLocalData->MappedFileInodeNum = st.st_ino;
+ }
+ else
+ {
+ ERROR("Couldn't get inode info for fd=%d to be stored in mapping object\n", UnixFd);
+ palError = ERROR_INTERNAL_ERROR;
+ goto ExitInternalCreateFileMapping;
+ }
+ }
+#endif
+
+ pLocalDataLock->ReleaseLock(pThread, TRUE);
+ pLocalDataLock = NULL;
+
+ palError = g_pObjectManager->RegisterObject(
+ pThread,
+ pMapping,
+ &aotFileMapping,
+ flProtect, // TODO: is flProtect really an access right?
+ phMapping,
+ &pRegisteredMapping
+ );
+
+ //
+ // pMapping is invalidated by the call to RegisterObject, so NULL it
+ // out here to ensure that we don't try to release a reference on
+ // it down the line. This also ensures that we won't attempt to release
+ // any data associated with the mapping object here, as if any cleanup is
+ // necessary due to a failure in RegisterObject (which includes another
+ // object by the same name already existing) the cleanup will take place
+ // when that routine releases the reference to pMapping.
+ //
+
+ pMapping = NULL;
+
+ExitInternalCreateFileMapping:
+
+ if (NULL != pLocalDataLock)
+ {
+ pLocalDataLock->ReleaseLock(
+ pThread,
+ TRUE
+ );
+ }
+
+ if (NULL != pMapping)
+ {
+ pMapping->ReleaseReference(pThread);
+
+ if (bPALCreatedTempFile)
+ {
+ unlink(pImmutableData->szFileName);
+ }
+
+ if (-1 != UnixFd)
+ {
+ close(UnixFd);
+ }
+ }
+
+ if (NULL != pRegisteredMapping)
+ {
+ pRegisteredMapping->ReleaseReference(pThread);
+ }
+
+ if (NULL != pFileObject)
+ {
+ pFileObject->ReleaseReference(pThread);
+ }
+
+ return palError;
+}
+
+/*++
+Function:
+ OpenFileMappingA
+
+See MSDN doc.
+--*/
+HANDLE
+PALAPI
+OpenFileMappingA(
+ IN DWORD dwDesiredAccess,
+ IN BOOL bInheritHandle,
+ IN LPCSTR lpName)
+{
+ HANDLE hFileMapping = NULL;
+ CPalThread *pThread = NULL;
+ PAL_ERROR palError = NO_ERROR;
+
+ PERF_ENTRY(OpenFileMappingA);
+ ENTRY("OpenFileMappingA(dwDesiredAccess=%u, bInheritHandle=%d, lpName=%p (%s)\n",
+ dwDesiredAccess, bInheritHandle, lpName?lpName:"NULL", lpName?lpName:"NULL");
+
+ pThread = InternalGetCurrentThread();
+
+ if (lpName == nullptr)
+ {
+ ERROR("name is NULL\n");
+ palError = ERROR_INVALID_PARAMETER;
+ }
+ else
+ {
+ ASSERT("lpName: Cross-process named objects are not supported in PAL");
+ palError = ERROR_NOT_SUPPORTED;
+ }
+
+ if (NO_ERROR != palError)
+ {
+ pThread->SetLastError(palError);
+ }
+ LOGEXIT( "OpenFileMappingA returning %p\n", hFileMapping );
+ PERF_EXIT(OpenFileMappingA);
+ return hFileMapping;
+}
+
+
+/*++
+Function:
+ OpenFileMappingW
+
+See MSDN doc.
+--*/
+HANDLE
+PALAPI
+OpenFileMappingW(
+ IN DWORD dwDesiredAccess,
+ IN BOOL bInheritHandle,
+ IN LPCWSTR lpName)
+{
+ HANDLE hFileMapping = NULL;
+ PAL_ERROR palError = NO_ERROR;
+ CPalThread *pThread = NULL;
+
+ PERF_ENTRY(OpenFileMappingW);
+ ENTRY("OpenFileMappingW(dwDesiredAccess=%#x, bInheritHandle=%d, lpName=%p (%S)\n",
+ dwDesiredAccess, bInheritHandle, lpName?lpName:W16_NULLSTRING, lpName?lpName:W16_NULLSTRING);
+
+ pThread = InternalGetCurrentThread();
+
+ /* validate parameters */
+ if (lpName == nullptr)
+ {
+ ERROR("name is NULL\n");
+ palError = ERROR_INVALID_PARAMETER;
+ }
+ else
+ {
+ ASSERT("lpName: Cross-process named objects are not supported in PAL");
+ palError = ERROR_NOT_SUPPORTED;
+ }
+
+ if (NO_ERROR != palError)
+ {
+ pThread->SetLastError(palError);
+ }
+ LOGEXIT("OpenFileMappingW returning %p.\n", hFileMapping);
+ PERF_EXIT(OpenFileMappingW);
+ return hFileMapping;
+}
+
+PAL_ERROR
+CorUnix::InternalOpenFileMapping(
+ CPalThread *pThread,
+ DWORD dwDesiredAccess,
+ BOOL bInheritHandle,
+ LPCWSTR lpName,
+ HANDLE *phMapping
+ )
+{
+ PAL_ERROR palError = NO_ERROR;
+ IPalObject *pFileMapping = NULL;
+ CPalString sObjectName(lpName);
+
+ if ( MAPContainsInvalidFlags( dwDesiredAccess ) )
+ {
+ ASSERT( "dwDesiredAccess can be one or more of FILE_MAP_READ, "
+ "FILE_MAP_WRITE, FILE_MAP_COPY or FILE_MAP_ALL_ACCESS.\n" );
+ palError = ERROR_INVALID_PARAMETER;
+ goto ExitInternalOpenFileMapping;
+ }
+
+ palError = g_pObjectManager->LocateObject(
+ pThread,
+ &sObjectName,
+ &aotFileMapping,
+ &pFileMapping
+ );
+
+ if (NO_ERROR != palError)
+ {
+ goto ExitInternalOpenFileMapping;
+ }
+
+ palError = g_pObjectManager->ObtainHandleForObject(
+ pThread,
+ pFileMapping,
+ dwDesiredAccess,
+ bInheritHandle,
+ NULL,
+ phMapping
+ );
+
+ if (NO_ERROR != palError)
+ {
+ goto ExitInternalOpenFileMapping;
+ }
+
+ExitInternalOpenFileMapping:
+
+ if (NULL != pFileMapping)
+ {
+ pFileMapping->ReleaseReference(pThread);
+ }
+
+ return palError;
+}
+
+/*++
+Function:
+ MapViewOfFile
+
+ Limitations: 1) Currently file mappings are supported only at file
+ offset 0.
+ 2) Some platforms (specifically HP-UX) do not support
+ multiple simultaneous shared mapping of the same file
+ region in the same process. On these platforms, in case
+ we are asked for a new view completely contained in an
+ existing one, we return an address within the existing
+ mapping. In case the new requested view is overlapping
+ with the existing one, but not contained in it, the
+ mapping is impossible, and MapViewOfFile will fail.
+ Since currently the mappings are supported only at file
+ offset 0, MapViewOfFile will succeed if the new view
+ is equal or smaller of the existing one, and the address
+ returned will be the same address of the existing
+ mapping.
+ Since the underlying mapping is always the same, all
+ the shared views of the same file region will share the
+ same protection, i.e. they will have the largest
+ protection requested. If any mapping asked for a
+ read-write access, all the read-only mappings of the
+ same region will silently get a read-write access to
+ it.
+
+See MSDN doc.
+--*/
+LPVOID
+PALAPI
+MapViewOfFile(
+ IN HANDLE hFileMappingObject,
+ IN DWORD dwDesiredAccess,
+ IN DWORD dwFileOffsetHigh,
+ IN DWORD dwFileOffsetLow,
+ IN SIZE_T dwNumberOfBytesToMap)
+{
+ PAL_ERROR palError = NO_ERROR;
+ CPalThread *pThread = NULL;
+ LPVOID pvMappedBaseAddress = NULL;
+
+ PERF_ENTRY(MapViewOfFile);
+ ENTRY("MapViewOfFile(hFileMapping=%p, dwDesiredAccess=%u, "
+ "dwFileOffsetH=%u, dwFileOffsetL=%u, dwNumberOfBytes=%u)\n",
+ hFileMappingObject, dwDesiredAccess, dwFileOffsetHigh,
+ dwFileOffsetLow, dwNumberOfBytesToMap);
+
+ pThread = InternalGetCurrentThread();
+
+ palError = InternalMapViewOfFile(
+ pThread,
+ hFileMappingObject,
+ dwDesiredAccess,
+ dwFileOffsetHigh,
+ dwFileOffsetLow,
+ dwNumberOfBytesToMap,
+ &pvMappedBaseAddress
+ );
+
+ if (NO_ERROR != palError)
+ {
+ pThread->SetLastError(palError);
+ }
+
+ LOGEXIT( "MapViewOfFile returning %p.\n", pvMappedBaseAddress );
+ PERF_EXIT(MapViewOfFile);
+ return pvMappedBaseAddress;
+}
+
+LPVOID
+PALAPI
+MapViewOfFileEx(
+ IN HANDLE hFileMappingObject,
+ IN DWORD dwDesiredAccess,
+ IN DWORD dwFileOffsetHigh,
+ IN DWORD dwFileOffsetLow,
+ IN SIZE_T dwNumberOfBytesToMap,
+ IN LPVOID lpBaseAddress)
+{
+ PAL_ERROR palError = NO_ERROR;
+ CPalThread *pThread = NULL;
+ LPVOID pvMappedBaseAddress = NULL;
+
+ PERF_ENTRY(MapViewOfFileEx);
+ ENTRY("MapViewOfFileEx(hFileMapping=%p, dwDesiredAccess=%u, "
+ "dwFileOffsetH=%u, dwFileOffsetL=%u, dwNumberOfBytes=%u, lpBaseAddress=%p)\n",
+ hFileMappingObject, dwDesiredAccess, dwFileOffsetHigh,
+ dwFileOffsetLow, dwNumberOfBytesToMap, lpBaseAddress);
+
+ pThread = InternalGetCurrentThread();
+
+ if (lpBaseAddress == NULL)
+ {
+ palError = InternalMapViewOfFile(
+ pThread,
+ hFileMappingObject,
+ dwDesiredAccess,
+ dwFileOffsetHigh,
+ dwFileOffsetLow,
+ dwNumberOfBytesToMap,
+ &pvMappedBaseAddress
+ );
+
+ if (NO_ERROR != palError)
+ {
+ pThread->SetLastError(palError);
+ }
+ }
+ else
+ {
+ // TODO: Figure out if we can support mapping at a specific address on Linux.
+ pThread->SetLastError(ERROR_INVALID_PARAMETER);
+ }
+
+ LOGEXIT( "MapViewOfFileEx returning %p.\n", pvMappedBaseAddress );
+ PERF_EXIT(MapViewOfFileEx);
+ return pvMappedBaseAddress;
+}
+
+/*++
+Function:
+ FlushViewOfFile
+
+See MSDN doc.
+--*/
+BOOL
+PALAPI
+FlushViewOfFile(
+ IN LPVOID lpBaseAddress,
+ IN SIZE_T dwNumberOfBytesToFlush)
+{
+ PAL_ERROR palError = NO_ERROR;
+ CPalThread *pThread = NULL;
+ PMAPPED_VIEW_LIST pView = NULL;
+ BOOL fResult = TRUE;
+
+ PERF_ENTRY(FlushViewOfFile);
+ ENTRY("FlushViewOfFile(lpBaseAddress=%p, dwNumberOfBytesToFlush=%u)\n",
+ lpBaseAddress, dwNumberOfBytesToFlush);
+
+ pThread = InternalGetCurrentThread();
+
+ InternalEnterCriticalSection(pThread, &mapping_critsec);
+
+ pView = MAPGetViewForAddress(lpBaseAddress);
+ if (NULL == pView)
+ {
+ ERROR("lpBaseAddress has to be the address returned by MapViewOfFile[Ex]");
+ palError = ERROR_INVALID_HANDLE;
+ goto Exit;
+ }
+
+ if (dwNumberOfBytesToFlush == 0)
+ {
+ dwNumberOfBytesToFlush = pView->NumberOfBytesToMap;
+ }
+
+ // <ROTORTODO>we should only use MS_SYNC if the file has been opened
+ // with FILE_FLAG_WRITE_THROUGH
+ if (msync(lpBaseAddress, dwNumberOfBytesToFlush, MS_SYNC) == -1)
+ {
+ if (errno == EINVAL)
+ {
+ WARN("msync failed; %s\n", strerror(errno));
+ palError = ERROR_INVALID_PARAMETER;
+ }
+ else if (errno == EIO)
+ {
+ WARN("msync failed; %s\n", strerror(errno));
+ palError = ERROR_WRITE_FAULT;
+ }
+ else
+ {
+ ERROR("msync failed; %s\n", strerror(errno));
+ palError = ERROR_INTERNAL_ERROR;
+ }
+ }
+
+Exit:
+ InternalLeaveCriticalSection(pThread, &mapping_critsec);
+
+ if (NO_ERROR != palError)
+ {
+ fResult = FALSE;
+ pThread->SetLastError(palError);
+ }
+
+ LOGEXIT("FlushViewOfFile returning %d.\n", fResult);
+ PERF_EXIT(FlushViewOfFile);
+ return fResult;
+}
+
+
+/*++
+Function:
+ UnmapViewOfFile
+
+See MSDN doc.
+--*/
+BOOL
+PALAPI
+UnmapViewOfFile(
+ IN LPCVOID lpBaseAddress)
+{
+ PAL_ERROR palError;
+ CPalThread *pThread;
+
+ PERF_ENTRY(UnmapViewOfFile);
+ ENTRY("UnmapViewOfFile(lpBaseAddress=%p)\n", lpBaseAddress);
+
+ pThread = InternalGetCurrentThread();
+
+ palError = InternalUnmapViewOfFile(pThread, lpBaseAddress);
+
+ if (NO_ERROR != palError)
+ {
+ pThread->SetLastError(palError);
+ }
+
+ LOGEXIT( "UnmapViewOfFile returning %s.\n", (NO_ERROR == palError) ? "TRUE" : "FALSE" );
+ PERF_EXIT(UnmapViewOfFile);
+ return (NO_ERROR == palError);
+}
+
+PAL_ERROR
+CorUnix::InternalMapViewOfFile(
+ CPalThread *pThread,
+ HANDLE hFileMappingObject,
+ DWORD dwDesiredAccess,
+ DWORD dwFileOffsetHigh,
+ DWORD dwFileOffsetLow,
+ SIZE_T dwNumberOfBytesToMap,
+ LPVOID *ppvBaseAddress
+ )
+{
+ PAL_ERROR palError = NO_ERROR;
+ IPalObject *pMappingObject = NULL;
+ CFileMappingImmutableData *pImmutableData = NULL;
+ CFileMappingProcessLocalData *pProcessLocalData = NULL;
+ IDataLock *pProcessLocalDataLock = NULL;
+#if ONE_SHARED_MAPPING_PER_FILEREGION_PER_PROCESS
+ PMAPPED_VIEW_LIST pReusedMapping = NULL;
+#endif
+ LPVOID pvBaseAddress = NULL;
+
+ /* Sanity checks */
+ if ( MAPContainsInvalidFlags( dwDesiredAccess ) )
+ {
+ ASSERT( "dwDesiredAccess can be one of FILE_MAP_WRITE, FILE_MAP_READ,"
+ " FILE_MAP_COPY or FILE_MAP_ALL_ACCESS.\n" );
+ palError = ERROR_INVALID_PARAMETER;
+ goto InternalMapViewOfFileExit;
+ }
+
+ if ( 0 != dwFileOffsetHigh || 0 != dwFileOffsetLow )
+ {
+ ASSERT( "dwFileOffsetHigh and dwFileOffsetLow are always 0.\n" );
+ palError = ERROR_INVALID_PARAMETER;
+ goto InternalMapViewOfFileExit;
+ }
+
+ palError = g_pObjectManager->ReferenceObjectByHandle(
+ pThread,
+ hFileMappingObject,
+ &aotFileMapping,
+ dwDesiredAccess,
+ &pMappingObject
+ );
+
+ if (NO_ERROR != palError)
+ {
+ ERROR( "Unable to reference handle %p.\n",hFileMappingObject );
+ goto InternalMapViewOfFileExit;
+ }
+
+ palError = pMappingObject->GetImmutableData(
+ reinterpret_cast<void**>(&pImmutableData)
+ );
+
+ if (NO_ERROR != palError)
+ {
+ ERROR( "Unable to obtain object immutable data");
+ goto InternalMapViewOfFileExit;
+ }
+
+ palError = pMappingObject->GetProcessLocalData(
+ pThread,
+ ReadLock,
+ &pProcessLocalDataLock,
+ reinterpret_cast<void**>(&pProcessLocalData)
+ );
+
+ if (NO_ERROR != palError)
+ {
+ ERROR( "Unable to obtain object process local data");
+ goto InternalMapViewOfFileExit;
+ }
+
+ /* If dwNumberOfBytesToMap is 0, we need to map the entire file.
+ * mmap doesn't do the same thing as Windows in that case, though,
+ * so we use the file size instead. */
+ if (0 == dwNumberOfBytesToMap)
+ {
+ dwNumberOfBytesToMap = pImmutableData->MaxSize;
+ }
+
+ palError = MAPDesiredAccessAllowed(
+ pImmutableData->flProtect,
+ dwDesiredAccess,
+ pImmutableData->dwDesiredAccessWhenOpened
+ );
+
+ if (NO_ERROR != palError)
+ {
+ goto InternalMapViewOfFileExit;
+ }
+
+ InternalEnterCriticalSection(pThread, &mapping_critsec);
+
+ if (FILE_MAP_COPY == dwDesiredAccess)
+ {
+ int flags = MAP_PRIVATE;
+
+#if !HAVE_MMAP_DEV_ZERO
+ if (pProcessLocalData->UnixFd == -1)
+ {
+ flags |= MAP_ANON;
+ }
+#endif
+ pvBaseAddress = mmap(
+ NULL,
+ dwNumberOfBytesToMap,
+ PROT_READ|PROT_WRITE,
+ flags,
+ pProcessLocalData->UnixFd,
+ 0
+ );
+ }
+ else
+ {
+ INT prot = MAPFileMapToMmapFlags(dwDesiredAccess);
+ if (prot != -1)
+ {
+ int flags = MAP_SHARED;
+
+#if !HAVE_MMAP_DEV_ZERO
+ if (pProcessLocalData->UnixFd == -1)
+ {
+ flags |= MAP_ANON;
+ }
+#endif
+
+ pvBaseAddress = mmap(
+ NULL,
+ dwNumberOfBytesToMap,
+ prot,
+ flags,
+ pProcessLocalData->UnixFd,
+ 0
+ );
+
+#if ONE_SHARED_MAPPING_PER_FILEREGION_PER_PROCESS
+ if ((MAP_FAILED == pvBaseAddress) && (ENOMEM == errno))
+ {
+ /* Search in list of MAPPED_MEMORY_INFO for a shared mapping
+ with the same inode number
+ */
+ TRACE("Mmap() failed with errno=ENOMEM probably for multiple mapping "
+ "limitation. Searching for a replacement among existing mappings\n");
+
+ pReusedMapping = FindSharedMappingReplacement(
+ pThread,
+ pProcessLocalData->MappedFileDevNum,
+ pProcessLocalData->MappedFileInodeNum,
+ dwNumberOfBytesToMap,
+ 0
+ );
+
+ if (pReusedMapping)
+ {
+ int ret;
+
+ TRACE("Mapping @ %p {sz=%d offs=%d} fully "
+ "contains the requested one {sz=%d offs=%d}: reusing it\n",
+ pReusedMapping->pNMHolder->address,
+ (int)pReusedMapping->pNMHolder->size,
+ (int)pReusedMapping->pNMHolder->offset,
+ dwNumberOfBytesToMap, 0);
+
+ /* Let's check the mapping's current protection */
+ ret = mprotect(pReusedMapping->pNMHolder->address,
+ pReusedMapping->pNMHolder->size,
+ prot | PROT_CHECK);
+ if (0 != ret)
+ {
+ /* We need to raise the protection to the desired
+ one. That will give write access to any read-only
+ mapping sharing this native mapping, but there is
+ no way around this problem on systems that do not
+ allow more than one mapping per file region, per
+ process */
+ TRACE("Raising protections on mapping @ %p to 0x%x\n",
+ pReusedMapping->pNMHolder->address, prot);
+ ret = mprotect(pReusedMapping->pNMHolder->address,
+ pReusedMapping->pNMHolder->size,
+ prot);
+ }
+
+ if (ret != 0)
+ {
+ ERROR( "Failed setting protections on reused mapping\n");
+
+ NativeMapHolderRelease(pThread, pReusedMapping->pNMHolder);
+ free(pReusedMapping);
+ pReusedMapping = NULL;
+ }
+ }
+ }
+#endif // ONE_SHARED_MAPPING_PER_FILEREGION_PER_PROCESS
+ }
+ else
+ {
+ ASSERT( "MapFileMapToMmapFlags failed!\n" );
+ palError = ERROR_INTERNAL_ERROR;
+ goto InternalMapViewOfFileLeaveCriticalSection;
+ }
+ }
+
+ if (MAP_FAILED == pvBaseAddress
+#if ONE_SHARED_MAPPING_PER_FILEREGION_PER_PROCESS
+ && (pReusedMapping == NULL)
+#endif // ONE_SHARED_MAPPING_PER_FILEREGION_PER_PROCESS
+ )
+ {
+ ERROR( "mmap failed with code %s.\n", strerror( errno ) );
+ palError = ERROR_NOT_ENOUGH_MEMORY;
+ goto InternalMapViewOfFileLeaveCriticalSection;
+
+ }
+
+#if ONE_SHARED_MAPPING_PER_FILEREGION_PER_PROCESS
+ if (pReusedMapping != NULL)
+ {
+ //
+ // Add a reference to the file mapping object the reused mapping
+ // points to (note that it may be different than the object this
+ // call was actually made against) and add the view to the global
+ // list. All other initialization took place in
+ // FindSharedMappingReplacement
+ //
+
+ pvBaseAddress = pReusedMapping->lpAddress;
+ pReusedMapping->pFileMapping->AddReference();
+ InsertTailList(&MappedViewList, &pReusedMapping->Link);
+ }
+ else
+#endif // ONE_SHARED_MAPPING_PER_FILEREGION_PER_PROCESS
+ {
+ //
+ // Allocate and fill out a new view structure, and add it to
+ // the global list.
+ //
+
+ PMAPPED_VIEW_LIST pNewView = (PMAPPED_VIEW_LIST)InternalMalloc(sizeof(*pNewView));
+ if (NULL != pNewView)
+ {
+ pNewView->lpAddress = pvBaseAddress;
+ pNewView->NumberOfBytesToMap = dwNumberOfBytesToMap;
+ pNewView->dwDesiredAccess = dwDesiredAccess;
+ pNewView->pFileMapping = pMappingObject;
+ pNewView->pFileMapping->AddReference();
+ pNewView->lpPEBaseAddress = 0;
+ InsertTailList(&MappedViewList, &pNewView->Link);
+
+#if ONE_SHARED_MAPPING_PER_FILEREGION_PER_PROCESS
+ pNewView->MappedFileDevNum = pProcessLocalData->MappedFileDevNum;
+ pNewView->MappedFileInodeNum = pProcessLocalData->MappedFileInodeNum;
+
+ pNewView->pNMHolder = NewNativeMapHolder(
+ pThread,
+ pvBaseAddress,
+ dwNumberOfBytesToMap,
+ 0,
+ 1
+ );
+
+ if (NULL == pNewView->pNMHolder)
+ {
+ pNewView->pFileMapping->ReleaseReference(pThread);
+ RemoveEntryList(&pNewView->Link);
+ free(pNewView);
+ palError = ERROR_INTERNAL_ERROR;
+ }
+#endif // ONE_SHARED_MAPPING_PER_FILEREGION_PER_PROCESS
+ }
+ else
+ {
+ palError = ERROR_INTERNAL_ERROR;
+ }
+
+ if (NO_ERROR != palError)
+ {
+ if (-1 == munmap(pvBaseAddress, dwNumberOfBytesToMap))
+ {
+ ERROR("Unable to unmap the file. Expect trouble.\n");
+ goto InternalMapViewOfFileLeaveCriticalSection;
+ }
+ }
+ }
+
+ if (NO_ERROR == palError)
+ {
+ TRACE( "Added %p to the list.\n", pvBaseAddress );
+ *ppvBaseAddress = pvBaseAddress;
+ }
+
+InternalMapViewOfFileLeaveCriticalSection:
+
+ InternalLeaveCriticalSection(pThread, &mapping_critsec);
+
+InternalMapViewOfFileExit:
+
+ if (NULL != pProcessLocalDataLock)
+ {
+ pProcessLocalDataLock->ReleaseLock(pThread, FALSE);
+ }
+
+ if (NULL != pMappingObject)
+ {
+ pMappingObject->ReleaseReference(pThread);
+ }
+
+ return palError;
+}
+
+
+PAL_ERROR
+CorUnix::InternalUnmapViewOfFile(
+ CPalThread *pThread,
+ LPCVOID lpBaseAddress
+ )
+{
+ PAL_ERROR palError = NO_ERROR;
+ PMAPPED_VIEW_LIST pView = NULL;
+ IPalObject *pMappingObject = NULL;
+
+ InternalEnterCriticalSection(pThread, &mapping_critsec);
+
+ pView = MAPGetViewForAddress(lpBaseAddress);
+ if (NULL == pView)
+ {
+ ERROR("lpBaseAddress has to be the address returned by MapViewOfFile[Ex]");
+ palError = ERROR_INVALID_HANDLE;
+ goto InternalUnmapViewOfFileExit;
+ }
+
+#if ONE_SHARED_MAPPING_PER_FILEREGION_PER_PROCESS
+ NativeMapHolderRelease(pThread, pView->pNMHolder);
+ pView->pNMHolder = NULL;
+#else
+ if (-1 == munmap((LPVOID)lpBaseAddress, pView->NumberOfBytesToMap))
+ {
+ ASSERT( "Unable to unmap the memory. Error=%s.\n",
+ strerror( errno ) );
+ palError = ERROR_INTERNAL_ERROR;
+
+ //
+ // Even if the unmap fails we want to continue removing the
+ // info for this view
+ //
+ }
+#endif
+
+ RemoveEntryList(&pView->Link);
+ pMappingObject = pView->pFileMapping;
+ free(pView);
+
+InternalUnmapViewOfFileExit:
+
+ InternalLeaveCriticalSection(pThread, &mapping_critsec);
+
+ //
+ // We can't dereference the file mapping object until after
+ // we've released the mapping critical section, since it may
+ // start going down its cleanup path and we don't want to make
+ // any assumptions as to what locks that might grab...
+ //
+
+ if (NULL != pMappingObject)
+ {
+ pMappingObject->ReleaseReference(pThread);
+ }
+
+ return palError;
+}
+
+/*++
+Function :
+ MAPInitialize
+
+ Initialize the critical sections.
+
+Return value:
+ TRUE if initialization succeeded
+ FALSE otherwise
+--*/
+BOOL
+MAPInitialize( void )
+{
+ TRACE( "Initialising the critical section.\n" );
+
+ InternalInitializeCriticalSection(&mapping_critsec);
+
+ InitializeListHead(&MappedViewList);
+
+ return TRUE;
+}
+
+/*++
+Function :
+ MAPCleanup
+
+ Deletes the critical sections. And all other necessary cleanup.
+
+Note:
+ This function is called after the handle manager is stopped. So
+ there shouldn't be any call that will cause an access to the handle
+ manager.
+
+--*/
+void MAPCleanup( void )
+{
+ TRACE( "Deleting the critical section.\n" );
+ InternalDeleteCriticalSection(&mapping_critsec);
+}
+
+/*++
+Function :
+ MAPGetViewForAddress
+
+ Returns the mapped view (if any) that is based at the passed in address.
+
+ Callers to this function must hold mapping_critsec
+--*/
+static PMAPPED_VIEW_LIST MAPGetViewForAddress( LPCVOID lpAddress )
+{
+ if ( NULL == lpAddress )
+ {
+ ERROR( "lpAddress cannot be NULL\n" );
+ return NULL;
+ }
+
+ for(LIST_ENTRY *pLink = MappedViewList.Flink;
+ pLink != &MappedViewList;
+ pLink = pLink->Flink)
+ {
+ PMAPPED_VIEW_LIST pView = CONTAINING_RECORD(pLink, MAPPED_VIEW_LIST, Link);
+
+ if (pView->lpAddress == lpAddress)
+ {
+ return pView;
+ }
+ }
+
+ WARN( "No match found.\n" );
+
+ return NULL;
+}
+
+/*++
+Function :
+
+ MAPDesiredAccessAllowed
+
+ Determines if desired access is allowed based on the protection state.
+
+ if dwDesiredAccess conflicts with flProtect then the error is
+ ERROR_INVALID_PARAMETER, if the dwDesiredAccess conflicts with
+ dwDesiredAccessWhenOpened, then the error code is ERROR_ACCESS_DENIED
+--*/
+static PAL_ERROR MAPDesiredAccessAllowed( DWORD flProtect,
+ DWORD dwUserDesiredAccess,
+ DWORD dwDesiredAccessWhenOpened )
+{
+ TRACE( "flProtect=%d, dwUserDesiredAccess=%d, dwDesiredAccessWhenOpened=%d\n",
+ flProtect, dwUserDesiredAccess, dwDesiredAccessWhenOpened );
+
+ /* check flProtect parameters*/
+ if ( FILE_MAP_READ!= dwUserDesiredAccess && PAGE_READONLY == flProtect )
+ {
+ ERROR( "map object is read-only, can't map a view with write access\n");
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ if ( FILE_MAP_WRITE == dwUserDesiredAccess && PAGE_READWRITE != flProtect )
+ {
+ ERROR( "map object not open read-write, can't map a view with write "
+ "access.\n" );
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ if ( FILE_MAP_COPY == dwUserDesiredAccess && PAGE_WRITECOPY != flProtect )
+ {
+ ERROR( "map object not open for copy-on-write, can't map copy-on-write "
+ "view.\n" );
+ return ERROR_INVALID_PARAMETER;
+ }
+
+ /* Check to see we don't confict with the desired access we
+ opened the mapping object with. */
+ if ( ( dwUserDesiredAccess == FILE_MAP_READ ) &&
+ !( ( dwDesiredAccessWhenOpened == FILE_MAP_READ ) ||
+ ( dwDesiredAccessWhenOpened == FILE_MAP_ALL_ACCESS ) ) )
+ {
+ ERROR( "dwDesiredAccess conflict : read access requested, object not "
+ "opened with read access.\n" );
+ return ERROR_ACCESS_DENIED;
+ }
+ if ( ( dwUserDesiredAccess & FILE_MAP_WRITE ) &&
+ !( ( dwDesiredAccessWhenOpened == FILE_MAP_WRITE ) ||
+ ( dwDesiredAccessWhenOpened == FILE_MAP_ALL_ACCESS ) ) )
+ {
+ ERROR( "dwDesiredAccess conflict : write access requested, object not "
+ "opened with write access.\n" );
+ return ERROR_ACCESS_DENIED;
+ }
+ if ( ( dwUserDesiredAccess == FILE_MAP_COPY ) &&
+ !( dwDesiredAccessWhenOpened == FILE_MAP_COPY ) )
+ {
+ ERROR( "dwDesiredAccess conflict : copy-on-write access requested, "
+ "object not opened with copy-on-write access.\n" );
+ return ERROR_ACCESS_DENIED;
+ }
+
+ return NO_ERROR;
+}
+
+/*++
+Function :
+ MAPConvertProtectToAccess
+
+ Converts the PAGE_READONLY type flags to FILE_MAP_READ flags.
+
+--*/
+static DWORD MAPConvertProtectToAccess( DWORD flProtect )
+{
+ if ( PAGE_READONLY == flProtect )
+ {
+ return FILE_MAP_READ;
+ }
+ if ( PAGE_READWRITE == flProtect )
+ {
+ return FILE_MAP_ALL_ACCESS;
+ }
+ if ( PAGE_WRITECOPY == flProtect )
+ {
+ return FILE_MAP_COPY;
+ }
+
+ ASSERT( "Unknown flag for flProtect. This line "
+ "should not have been executed.\n " );
+ return (DWORD) -1;
+}
+
+/*++
+Function :
+ MAPConvertAccessToProtect
+
+ Converts the FILE_MAP_READ type flags to PAGE_READONLY flags.
+ Currently, this function only deals with the access flags recognized as valid
+ by MAPContainsInvalidFlags().
+
+--*/
+static DWORD MAPConvertAccessToProtect(DWORD flAccess)
+{
+ if (flAccess == FILE_MAP_ALL_ACCESS)
+ {
+ return PAGE_READWRITE;
+ }
+ else if ((flAccess == FILE_MAP_COPY) || (flAccess == FILE_MAP_WRITE))
+ {
+ return PAGE_WRITECOPY;
+ }
+ else if (flAccess == FILE_MAP_READ)
+ {
+ return PAGE_READONLY;
+ }
+ else if (flAccess == 0)
+ {
+ return PAGE_NOACCESS;
+ }
+
+ ASSERT("Unknown flag for flAccess.\n");
+ return (DWORD) -1;
+}
+
+/*++
+Function :
+ MAPFileMapToMmapFlags
+
+ Converts the mapping flags to unix protection flags.
+--*/
+static INT MAPFileMapToMmapFlags( DWORD flags )
+{
+ if ( FILE_MAP_READ == flags )
+ {
+ TRACE( "FILE_MAP_READ\n" );
+ return PROT_READ;
+ }
+ else if ( FILE_MAP_WRITE == flags )
+ {
+ TRACE( "FILE_MAP_WRITE\n" );
+ /* The limitation of x86 archetecture
+ means you cant have writable but not readable
+ page. In Windows maps of FILE_MAP_WRITE can still be
+ read from. */
+ return PROT_WRITE | PROT_READ;
+ }
+ else if ( (FILE_MAP_READ|FILE_MAP_WRITE) == flags )
+ {
+ TRACE( "FILE_MAP_READ|FILE_MAP_WRITE\n" );
+ return PROT_READ | PROT_WRITE;
+ }
+ else if( FILE_MAP_COPY == flags)
+ {
+ TRACE( "FILE_MAP_COPY\n");
+ return PROT_READ | PROT_WRITE;
+ }
+
+ ASSERT( "Unknown flag. This line should not have been executed.\n" );
+ return -1;
+}
+
+/*++
+Function :
+ MAPMmapProtToAccessFlags
+
+ Converts unix protection flags to file access flags.
+ We ignore PROT_EXEC.
+--*/
+static DWORD MAPMmapProtToAccessFlags( int prot )
+{
+ DWORD flAccess = 0; // default: no access
+
+ if (PROT_NONE == prot)
+ {
+ flAccess = 0;
+ }
+ else if ( ((PROT_READ | PROT_WRITE) & prot) == (PROT_READ | PROT_WRITE) )
+ {
+ flAccess = FILE_MAP_ALL_ACCESS;
+ }
+ else if ( (PROT_WRITE & prot) == PROT_WRITE )
+ {
+ flAccess = FILE_MAP_WRITE;
+ }
+ else if ( (PROT_READ & prot) == PROT_READ )
+ {
+ flAccess = FILE_MAP_READ;
+ }
+ else
+ {
+ ASSERT( "Unknown Unix protection flag\n" );
+ }
+
+ return flAccess;
+}
+
+/*++
+Function :
+
+ MAPGrowLocalFile
+
+ Grows the file on disk to match the specified size.
+
+--*/
+static PAL_ERROR MAPGrowLocalFile( INT UnixFD, UINT NewSize )
+{
+ PAL_ERROR palError = NO_ERROR;
+ INT TruncateRetVal = -1;
+ struct stat FileInfo;
+ TRACE( "Entered MapGrowLocalFile (UnixFD=%d,NewSize%d)\n", UnixFD, NewSize );
+
+ //
+ // TODO: can we add configure flags to model the behavior of ftruncate
+ // among our various target platforms? How much would that actually gain
+ // us?
+ //
+
+ /* ftruncate is a standard function, but the behavior of enlarging files is
+ non-standard. So I will try to enlarge a file, and if that fails try the
+ less efficent way.*/
+ TruncateRetVal = ftruncate( UnixFD, NewSize );
+ fstat( UnixFD, &FileInfo );
+
+ if ( TruncateRetVal != 0 || FileInfo.st_size != (int) NewSize )
+ {
+ INT OrigSize;
+ CONST UINT BUFFER_SIZE = 128;
+ BYTE buf[BUFFER_SIZE];
+ UINT x = 0;
+ UINT CurrentPosition = 0;
+
+ TRACE( "Trying the less efficent way.\n" );
+
+ CurrentPosition = lseek( UnixFD, 0, SEEK_CUR );
+ OrigSize = lseek( UnixFD, 0, SEEK_END );
+ if ( OrigSize == -1 )
+ {
+ ERROR( "Unable to locate the EOF marker. Reason=%s\n",
+ strerror( errno ) );
+ palError = ERROR_INTERNAL_ERROR;
+ goto done;
+ }
+
+ if (NewSize <= (UINT) OrigSize)
+ {
+ return TRUE;
+ }
+
+ memset( buf, 0, BUFFER_SIZE );
+
+ for ( x = 0; x < NewSize - OrigSize - BUFFER_SIZE; x += BUFFER_SIZE )
+ {
+ if ( write( UnixFD, (LPVOID)buf, BUFFER_SIZE ) == -1 )
+ {
+ ERROR( "Unable to grow the file. Reason=%s\n", strerror( errno ) );
+ if((errno == ENOSPC) || (errno == EDQUOT))
+ {
+ palError = ERROR_DISK_FULL;
+ }
+ else
+ {
+ palError = ERROR_INTERNAL_ERROR;
+ }
+ goto done;
+ }
+ }
+ /* Catch any left overs. */
+ if ( x != NewSize )
+ {
+ if ( write( UnixFD, (LPVOID)buf, NewSize - OrigSize - x) == -1 )
+ {
+ ERROR( "Unable to grow the file. Reason=%s\n", strerror( errno ) );
+ if((errno == ENOSPC) || (errno == EDQUOT))
+ {
+ palError = ERROR_DISK_FULL;
+ }
+ else
+ {
+ palError = ERROR_INTERNAL_ERROR;
+ }
+ goto done;
+ }
+ }
+
+ /* restore the file pointer position */
+ lseek( UnixFD, CurrentPosition, SEEK_SET );
+ }
+
+done:
+ return palError;
+}
+
+/*++
+Function :
+ MAPContainsInvalidFlags
+
+ Checks that only valid flags are in the parameter.
+
+--*/
+static BOOL MAPContainsInvalidFlags( DWORD flags )
+{
+
+ if ( (flags == FILE_MAP_READ) ||
+ (flags == FILE_MAP_WRITE) ||
+ (flags == FILE_MAP_ALL_ACCESS) ||
+ (flags == FILE_MAP_COPY) )
+ {
+ return FALSE;
+ }
+ else
+ {
+ return TRUE;
+ }
+}
+
+/*++
+Function :
+ MAPProtectionToFileOpenFlags
+
+ Converts the PAGE_* flags to the O_* flags.
+
+ Returns the file open flags.
+--*/
+static INT MAPProtectionToFileOpenFlags( DWORD flProtect )
+{
+ INT retVal = 0;
+ switch(flProtect)
+ {
+ case PAGE_READONLY:
+ retVal = O_RDONLY;
+ break;
+ case PAGE_READWRITE:
+ retVal = O_RDWR;
+ break;
+ case PAGE_WRITECOPY:
+ retVal = O_RDONLY;
+ break;
+ default:
+ ASSERT("unexpected flProtect value %#x\n", flProtect);
+ retVal = 0;
+ break;
+ }
+ return retVal;
+}
+
+/*++
+Function :
+
+ MAPIsRequestPermissible
+
+ DWORD flProtect - The requested file mapping protection .
+ file * pFileStruct - The file structure containing all the information.
+
+--*/
+static BOOL MAPIsRequestPermissible( DWORD flProtect, CFileProcessLocalData * pFileLocalData )
+{
+ if ( ( (flProtect == PAGE_READONLY || flProtect == PAGE_WRITECOPY) &&
+ (pFileLocalData->open_flags_deviceaccessonly == TRUE ||
+ pFileLocalData->open_flags & O_WRONLY) )
+ )
+ {
+ /*
+ * PAGE_READONLY or PAGE_WRITECOPY access to a file must at least be
+ * readable. Contrary to what MSDN says, PAGE_WRITECOPY
+ * only needs to be readable.
+ */
+ return FALSE;
+ }
+ else if ( flProtect == PAGE_READWRITE && !(pFileLocalData->open_flags & O_RDWR) )
+ {
+ /*
+ * PAGE_READWRITE access to a file needs to be readable and writable
+ */
+ return FALSE;
+ }
+ else
+ {
+ /* Action is permissible */
+ return TRUE;
+ }
+}
+
+// returns TRUE if we have information about the specified address
+BOOL MAPGetRegionInfo(LPVOID lpAddress,
+ PMEMORY_BASIC_INFORMATION lpBuffer)
+{
+ BOOL fFound = FALSE;
+ CPalThread * pThread = InternalGetCurrentThread();
+
+ InternalEnterCriticalSection(pThread, &mapping_critsec);
+
+ for(LIST_ENTRY *pLink = MappedViewList.Flink;
+ pLink != &MappedViewList;
+ pLink = pLink->Flink)
+ {
+ UINT MappedSize;
+ VOID * real_map_addr;
+ SIZE_T real_map_sz;
+ PMAPPED_VIEW_LIST pView = CONTAINING_RECORD(pLink, MAPPED_VIEW_LIST, Link);
+
+#if ONE_SHARED_MAPPING_PER_FILEREGION_PER_PROCESS
+ real_map_addr = pView->pNMHolder->address;
+ real_map_sz = pView->pNMHolder->size;
+#else
+ real_map_addr = pView->lpAddress;
+ real_map_sz = pView->NumberOfBytesToMap;
+#endif
+
+ MappedSize = ((real_map_sz-1) & ~VIRTUAL_PAGE_MASK) + VIRTUAL_PAGE_SIZE;
+ if ( real_map_addr <= lpAddress &&
+ (VOID *)((UINT_PTR)real_map_addr+MappedSize) > lpAddress )
+ {
+ if (lpBuffer)
+ {
+ SIZE_T regionSize = MappedSize + (UINT_PTR) real_map_addr -
+ ((UINT_PTR) lpAddress & ~VIRTUAL_PAGE_MASK);
+
+ lpBuffer->BaseAddress = lpAddress;
+ lpBuffer->AllocationProtect = 0;
+ lpBuffer->RegionSize = regionSize;
+ lpBuffer->State = MEM_COMMIT;
+ lpBuffer->Protect = MAPConvertAccessToProtect(pView->dwDesiredAccess);
+ lpBuffer->Type = MEM_MAPPED;
+ }
+
+ fFound = TRUE;
+ break;
+ }
+ }
+
+ InternalLeaveCriticalSection(pThread, &mapping_critsec);
+
+ return fFound;
+}
+
+#if ONE_SHARED_MAPPING_PER_FILEREGION_PER_PROCESS
+
+//
+// Callers of FindSharedMappingReplacement must hold mapping_critsec
+//
+
+static PMAPPED_VIEW_LIST FindSharedMappingReplacement(
+ CPalThread *pThread,
+ dev_t deviceNum,
+ ino_t inodeNum,
+ SIZE_T size,
+ SIZE_T offset)
+{
+ PMAPPED_VIEW_LIST pNewView = NULL;
+
+ if (size == 0)
+ {
+ ERROR("Mapping size cannot be NULL\n");
+ return NULL;
+ }
+
+ for (LIST_ENTRY *pLink = MappedViewList.Flink;
+ pLink != &MappedViewList;
+ pLink = pLink->Flink)
+ {
+ PMAPPED_VIEW_LIST pView = CONTAINING_RECORD(pLink, MAPPED_VIEW_LIST, Link);
+
+ if (pView->MappedFileDevNum != deviceNum
+ || pView->MappedFileInodeNum != inodeNum
+ || pView->dwDesiredAccess == FILE_MAP_COPY)
+ {
+ continue;
+ }
+
+ //
+ // This is a shared mapping for the same indoe / device. Now, check
+ // to see if it overlaps with the range for the new view
+ //
+
+ SIZE_T real_map_offs = pView->pNMHolder->offset;
+ SIZE_T real_map_sz = pView->pNMHolder->size;
+
+ if (real_map_offs <= offset
+ && real_map_offs+real_map_sz >= offset)
+ {
+ //
+ // The views overlap. Even if this view is not reusable for the
+ // new once the search is over, as on
+ // ONE_SHARED_MAPPING_PER_FILEREGION_PER_PROCESS systems there
+ // cannot be shared mappings of two overlapping regions of the
+ // same file, in the same process. Therefore, whether this view
+ // is reusable or not we cannot mmap the requested region of
+ // the specified file.
+ //
+
+ if (real_map_offs+real_map_sz >= offset+size)
+ {
+ /* The new desired mapping is fully contained in the
+ one just found: we can reuse this one */
+
+ pNewView = (PMAPPED_VIEW_LIST)InternalMalloc(sizeof(MAPPED_VIEW_LIST));
+ if (pNewView)
+ {
+ memcpy(pNewView, pView, sizeof(*pNewView));
+ NativeMapHolderAddRef(pNewView->pNMHolder);
+ pNewView->lpAddress = (VOID*)((CHAR*)pNewView->pNMHolder->address +
+ offset - pNewView->pNMHolder->offset);
+ pNewView->NumberOfBytesToMap = size;
+ }
+ else
+ {
+ ERROR("No memory for new MAPPED_VIEW_LIST node\n");
+ }
+ }
+
+ break;
+ }
+ }
+
+ TRACE ("FindSharedMappingReplacement returning %p\n", pNewView);
+ return pNewView;
+}
+
+static NativeMapHolder * NewNativeMapHolder(CPalThread *pThread, LPVOID address, SIZE_T size,
+ SIZE_T offset, long init_ref_count)
+{
+ NativeMapHolder * pThisMapHolder;
+
+ if (init_ref_count < 0)
+ {
+ ASSERT("Negative initial reference count for new map holder\n");
+ return NULL;
+ }
+
+ pThisMapHolder =
+ (NativeMapHolder *)InternalMalloc(sizeof(NativeMapHolder));
+
+ if (pThisMapHolder)
+ {
+ pThisMapHolder->ref_count = init_ref_count;
+ pThisMapHolder->address = address;
+ pThisMapHolder->size = size;
+ pThisMapHolder->offset = offset;
+ }
+
+ return pThisMapHolder;
+}
+
+static LONG NativeMapHolderAddRef(NativeMapHolder * thisNMH)
+{
+ LONG ret = InterlockedIncrement(&thisNMH->ref_count);
+ return ret;
+}
+
+static LONG NativeMapHolderRelease(CPalThread *pThread, NativeMapHolder * thisNMH)
+{
+ LONG ret = InterlockedDecrement(&thisNMH->ref_count);
+ if (ret == 0)
+ {
+ if (-1 == munmap(thisNMH->address, thisNMH->size))
+ {
+ ASSERT( "Unable to unmap memory. Error=%s.\n",
+ strerror( errno ) );
+ }
+ else
+ {
+ TRACE( "Successfully unmapped %p (size=%lu)\n",
+ thisNMH->address, (unsigned long)thisNMH->size);
+ }
+ free (thisNMH);
+ }
+ else if (ret < 0)
+ {
+ ASSERT( "Negative reference count for map holder %p"
+ " {address=%p, size=%lu}\n", thisNMH->address,
+ (unsigned long)thisNMH->size);
+ }
+
+ return ret;
+}
+
+#endif // ONE_SHARED_MAPPING_PER_FILEREGION_PER_PROCESS
+
+// Record a mapping in the MappedViewList list.
+// This call assumes the mapping_critsec has already been taken.
+static PAL_ERROR
+MAPRecordMapping(
+ IPalObject *pMappingObject,
+ void *pPEBaseAddress,
+ void *addr,
+ size_t len,
+ int prot
+ )
+{
+ if (pPEBaseAddress == NULL)
+ {
+ return ERROR_INTERNAL_ERROR;
+ }
+
+ PAL_ERROR palError = NO_ERROR;
+ PMAPPED_VIEW_LIST pNewView;
+ pNewView = (PMAPPED_VIEW_LIST)InternalMalloc(sizeof(*pNewView));
+ if (NULL != pNewView)
+ {
+ pNewView->lpAddress = addr;
+ pNewView->NumberOfBytesToMap = len;
+ pNewView->dwDesiredAccess = MAPMmapProtToAccessFlags(prot);
+ pMappingObject->AddReference();
+ pNewView->pFileMapping = pMappingObject;
+ pNewView->lpPEBaseAddress = pPEBaseAddress;
+ InsertTailList(&MappedViewList, &pNewView->Link);
+
+ TRACE_(LOADER)("Added address %p, size 0x%x, to the mapped file list.\n", addr, len);
+ }
+ else
+ {
+ palError = ERROR_INTERNAL_ERROR;
+ }
+
+ return palError;
+}
+
+// Do the actual mmap() call, and record the mapping in the MappedViewList list.
+// This call assumes the mapping_critsec has already been taken.
+static PAL_ERROR
+MAPmmapAndRecord(
+ IPalObject *pMappingObject,
+ void *pPEBaseAddress,
+ void *addr,
+ size_t len,
+ int prot,
+ int flags,
+ int fd,
+ off_t offset,
+ LPVOID *ppvBaseAddress
+ )
+{
+ _ASSERTE(pPEBaseAddress != NULL);
+
+ PAL_ERROR palError = NO_ERROR;
+ LPVOID pvBaseAddress = NULL;
+
+ pvBaseAddress = mmap(addr, len, prot, flags, fd, offset);
+ if (MAP_FAILED == pvBaseAddress)
+ {
+ ERROR_(LOADER)( "mmap failed with code %d: %s.\n", errno, strerror( errno ) );
+ palError = FILEGetLastErrorFromErrno();
+ }
+ else
+ {
+ palError = MAPRecordMapping(pMappingObject, pPEBaseAddress, pvBaseAddress, len, prot);
+ if (NO_ERROR != palError)
+ {
+ if (-1 == munmap(pvBaseAddress, len))
+ {
+ ERROR_(LOADER)("Unable to unmap the file. Expect trouble.\n");
+ }
+ }
+ else
+ {
+ *ppvBaseAddress = pvBaseAddress;
+ }
+ }
+
+ return palError;
+}
+
+/*++
+ MAPMapPEFile -
+
+ Map a PE format file into memory like Windows LoadLibrary() would do.
+ Doesn't apply base relocations if the function is relocated.
+
+Parameters:
+ IN hFile - file to map
+
+Return value:
+ non-NULL - the base address of the mapped image
+ NULL - error, with last error set.
+--*/
+
+void * MAPMapPEFile(HANDLE hFile)
+{
+ PAL_ERROR palError = 0;
+ IPalObject *pFileObject = NULL;
+ IDataLock *pLocalDataLock = NULL;
+ CFileProcessLocalData *pLocalData = NULL;
+ CPalThread *pThread = InternalGetCurrentThread();
+ void * loadedBase = NULL;
+ IMAGE_DOS_HEADER * loadedHeader = NULL;
+ void * retval;
+#if _DEBUG
+ bool forceRelocs = false;
+ char* envVar;
+#endif
+
+ ENTRY("MAPMapPEFile (hFile=%p)\n", hFile);
+
+ //Step 0: Verify values, find internal pal data structures.
+ if (INVALID_HANDLE_VALUE == hFile)
+ {
+ ERROR_(LOADER)( "Invalid file handle\n" );
+ palError = ERROR_INVALID_HANDLE;
+ goto done;
+ }
+
+ palError = g_pObjectManager->ReferenceObjectByHandle(
+ pThread,
+ hFile,
+ &aotFile,
+ GENERIC_READ,
+ &pFileObject
+ );
+ if (NO_ERROR != palError)
+ {
+ ERROR_(LOADER)( "ReferenceObjectByHandle failed\n" );
+ goto done;
+ }
+
+ palError = pFileObject->GetProcessLocalData(
+ pThread,
+ ReadLock,
+ &pLocalDataLock,
+ reinterpret_cast<void**>(&pLocalData)
+ );
+ if (NO_ERROR != palError)
+ {
+ ERROR_(LOADER)( "GetProcessLocalData failed\n" );
+ goto done;
+ }
+
+ int fd;
+ fd = pLocalData->unix_fd;
+ //Step 1: Read the PE headers and reserve enough space for the whole image somewhere.
+ IMAGE_DOS_HEADER dosHeader;
+ IMAGE_NT_HEADERS ntHeader;
+ errno = 0;
+ if (0 != lseek(fd, 0, SEEK_SET))
+ {
+ palError = FILEGetLastErrorFromErrno();
+ ERROR_(LOADER)( "lseek failed\n" );
+ goto done;
+ }
+ if (sizeof(dosHeader) != read(fd, &dosHeader, sizeof(dosHeader)))
+ {
+ palError = FILEGetLastErrorFromErrno();
+ ERROR_(LOADER)( "reading dos header failed\n" );
+ goto done;
+ }
+ if (dosHeader.e_lfanew != lseek(fd, dosHeader.e_lfanew, SEEK_SET))
+ {
+ palError = FILEGetLastErrorFromErrno();
+ goto done;
+ }
+ if (sizeof(ntHeader) != read(fd, &ntHeader, sizeof(ntHeader)))
+ {
+ palError = FILEGetLastErrorFromErrno();
+ goto done;
+ }
+
+ if ((VAL16(IMAGE_DOS_SIGNATURE) != VAL16(dosHeader.e_magic))
+ || (VAL32(IMAGE_NT_SIGNATURE) != VAL32(ntHeader.Signature))
+ || (VAL16(IMAGE_NT_OPTIONAL_HDR_MAGIC) != VAL16(ntHeader.OptionalHeader.Magic) ) )
+ {
+ ERROR_(LOADER)( "Magic number mismatch\n" );
+ palError = ERROR_INVALID_PARAMETER;
+ goto done;
+ }
+
+ //this code requires that the file alignment be the same as the page alignment
+ if (ntHeader.OptionalHeader.FileAlignment < VIRTUAL_PAGE_SIZE)
+ {
+ ERROR_(LOADER)( "Optional header file alignment is bad\n" );
+ palError = ERROR_INVALID_PARAMETER;
+ goto done;
+ }
+
+ //This doesn't read the entire NT header (the optional header technically has a variable length. But I
+ //don't need more directories.
+
+ //I now know how big the file is. Reserve enough address space for the whole thing. Try to get the
+ //preferred base. Create the intial mapping as "no access". We'll use that for the guard pages in the
+ //"holes" between sections.
+ SIZE_T preferredBase, virtualSize;
+ preferredBase = ntHeader.OptionalHeader.ImageBase;
+ virtualSize = ntHeader.OptionalHeader.SizeOfImage;
+
+ // Validate the image header
+ if ( (preferredBase == 0)
+ || (virtualSize == 0)
+ || (preferredBase + virtualSize < preferredBase) // Does the image overflow?
+ )
+ {
+ ERROR_(LOADER)( "image is corrupt\n" );
+ palError = ERROR_INVALID_PARAMETER;
+ goto done;
+ }
+
+#if _DEBUG
+ envVar = EnvironGetenv("PAL_ForceRelocs");
+ if (envVar)
+ {
+ if (strlen(envVar) > 0)
+ {
+ forceRelocs = true;
+ TRACE_(LOADER)("Forcing rebase of image\n");
+ }
+
+ free(envVar);
+ }
+
+ void * pForceRelocBase;
+ pForceRelocBase = NULL;
+ if (forceRelocs)
+ {
+ //if we're forcing relocs, create an anonymous mapping at the preferred base. Only create the
+ //mapping if we can create it at the specified address.
+ pForceRelocBase = mmap( (void*)preferredBase, VIRTUAL_PAGE_SIZE, PROT_NONE, MAP_ANON|MAP_FIXED|MAP_PRIVATE, -1, 0 );
+ if (pForceRelocBase == MAP_FAILED)
+ {
+ TRACE_(LOADER)("Attempt to take preferred base of %p to force relocation failed\n", (void*)preferredBase);
+ forceRelocs = false;
+ }
+ else if ((void*)preferredBase != pForceRelocBase)
+ {
+ TRACE_(LOADER)("Attempt to take preferred base of %p to force relocation failed; actually got %p\n", (void*)preferredBase, pForceRelocBase);
+ }
+ }
+#endif // _DEBUG
+
+ // The first mmap mapping covers the entire file but just reserves space. Subsequent mappings cover
+ // individual parts of the file, and actually map pages in. Note that according to the mmap() man page, "A
+ // successful mmap deletes any previous mapping in the allocated address range." Also, "If a MAP_FIXED
+ // request is successful, the mapping established by mmap() replaces any previous mappings for the process' pages
+ // in the range from addr to addr + len." Thus, we will record a series of mappings here, one for the header
+ // and each of the sections, as well as all the space between them that we give PROT_NONE protections.
+
+ // We're going to start adding mappings to the mapping list, so take the critical section
+ InternalEnterCriticalSection(pThread, &mapping_critsec);
+
+#if !defined(_AMD64_)
+ loadedBase = mmap((void*)preferredBase, virtualSize, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
+#else // defined(_AMD64_)
+ // First try to reserve virtual memory using ExecutableAllcator. This allows all PE images to be
+ // near each other and close to the coreclr library which also allows the runtime to generate
+ // more efficient code (by avoiding usage of jump stubs).
+ loadedBase = ReserveMemoryFromExecutableAllocator(pThread, virtualSize);
+ if (loadedBase == NULL)
+ {
+ // MAC64 requires we pass MAP_SHARED (or MAP_PRIVATE) flags - otherwise, the call is failed.
+ // Refer to mmap documentation at http://www.manpagez.com/man/2/mmap/ for details.
+ loadedBase = mmap((void*)preferredBase, virtualSize, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0);
+ }
+#endif // !defined(_AMD64_)
+
+ if (MAP_FAILED == loadedBase)
+ {
+ ERROR_(LOADER)( "mmap failed with code %d: %s.\n", errno, strerror( errno ) );
+ palError = FILEGetLastErrorFromErrno();
+ loadedBase = NULL; // clear it so we don't try to use it during clean-up
+ goto doneReleaseMappingCriticalSection;
+ }
+
+ // All subsequent mappings of the PE file will be in the range [loadedBase, loadedBase + virtualSize)
+
+#if _DEBUG
+ if (forceRelocs)
+ {
+ _ASSERTE(((SIZE_T)loadedBase) != preferredBase);
+ munmap(pForceRelocBase, VIRTUAL_PAGE_SIZE); // now that we've forced relocation, let the original address mapping go
+ }
+ if (((SIZE_T)loadedBase) != preferredBase)
+ {
+ TRACE_(LOADER)("Image rebased from preferredBase of %p to loadedBase of %p\n", preferredBase, loadedBase);
+ }
+ else
+ {
+ TRACE_(LOADER)("Image loaded at preferred base %p\n", loadedBase);
+ }
+#endif // _DEBUG
+
+ //we have now reserved memory (potentially we got rebased). Walk the PE sections and map each part
+ //separately.
+
+ size_t headerSize;
+ headerSize = VIRTUAL_PAGE_SIZE; // if there are lots of sections, this could be wrong
+
+ //first, map the PE header to the first page in the image. Get pointers to the section headers
+ palError = MAPmmapAndRecord(pFileObject, loadedBase,
+ loadedBase, headerSize, PROT_READ, MAP_FILE|MAP_PRIVATE|MAP_FIXED, fd, 0,
+ (void**)&loadedHeader);
+ if (NO_ERROR != palError)
+ {
+ ERROR_(LOADER)( "mmap of PE header failed\n" );
+ goto doneReleaseMappingCriticalSection;
+ }
+
+ TRACE_(LOADER)("PE header loaded @ %p\n", loadedHeader);
+ _ASSERTE(loadedHeader == loadedBase); // we already preallocated the space, and we used MAP_FIXED, so we should have gotten this address
+ IMAGE_SECTION_HEADER * firstSection;
+ firstSection = (IMAGE_SECTION_HEADER*)(((char *)loadedHeader)
+ + loadedHeader->e_lfanew
+ + offsetof(IMAGE_NT_HEADERS, OptionalHeader)
+ + VAL16(ntHeader.FileHeader.SizeOfOptionalHeader));
+ unsigned numSections;
+ numSections = ntHeader.FileHeader.NumberOfSections;
+
+ // Validation
+ char* sectionHeaderEnd;
+ sectionHeaderEnd = (char*)firstSection + numSections * sizeof(IMAGE_SECTION_HEADER);
+ if ( ((void*)firstSection < loadedBase)
+ || ((char*)firstSection > sectionHeaderEnd)
+ || (sectionHeaderEnd > (char*)loadedBase + virtualSize)
+ )
+ {
+ ERROR_(LOADER)( "image is corrupt\n" );
+ palError = ERROR_INVALID_PARAMETER;
+ goto doneReleaseMappingCriticalSection;
+ }
+
+ void* prevSectionBase;
+ prevSectionBase = loadedBase; // the first "section" for our purposes is the header
+ size_t prevSectionSizeInMemory;
+ prevSectionSizeInMemory = headerSize;
+ for (unsigned i = 0; i < numSections; ++i)
+ {
+ //for each section, map the section of the file to the correct virtual offset. Gather the
+ //protection bits from the PE file and convert them to the correct mmap PROT_* flags.
+ void * sectionData;
+ int prot = 0;
+ IMAGE_SECTION_HEADER &currentHeader = firstSection[i];
+
+ void* sectionBase = (char*)loadedBase + currentHeader.VirtualAddress;
+
+ // Validate the section header
+ if ( (sectionBase < loadedBase) // Did computing the section base overflow?
+ || ((char*)sectionBase + currentHeader.SizeOfRawData < (char*)sectionBase) // Does the section overflow?
+ || ((char*)sectionBase + currentHeader.SizeOfRawData > (char*)loadedBase + virtualSize) // Does the section extend past the end of the image as the header stated?
+ || ((char*)prevSectionBase + prevSectionSizeInMemory > sectionBase) // Does this section overlap the previous one?
+ )
+ {
+ ERROR_(LOADER)( "section %d is corrupt\n", i );
+ palError = ERROR_INVALID_PARAMETER;
+ goto doneReleaseMappingCriticalSection;
+ }
+ if (currentHeader.Misc.VirtualSize > currentHeader.SizeOfRawData)
+ {
+ ERROR_(LOADER)( "no support for zero-padded sections, section %d\n", i );
+ palError = ERROR_INVALID_PARAMETER;
+ goto doneReleaseMappingCriticalSection;
+ }
+
+ // Is there space between the previous section and this one? If so, add a PROT_NONE mapping to cover it.
+ if ((char*)prevSectionBase + prevSectionSizeInMemory < sectionBase)
+ {
+ char* gapBase = (char*)prevSectionBase + prevSectionSizeInMemory;
+ palError = MAPRecordMapping(pFileObject,
+ loadedBase,
+ (void*)gapBase,
+ (char*)sectionBase - gapBase,
+ PROT_NONE);
+ if (NO_ERROR != palError)
+ {
+ ERROR_(LOADER)( "recording gap section before section %d failed\n", i );
+ goto doneReleaseMappingCriticalSection;
+ }
+ }
+
+ //Don't discard these sections. We need them to verify PE files
+ //if (currentHeader.Characteristics & IMAGE_SCN_MEM_DISCARDABLE)
+ // continue;
+ if (currentHeader.Characteristics & IMAGE_SCN_MEM_EXECUTE)
+ prot |= PROT_EXEC;
+ if (currentHeader.Characteristics & IMAGE_SCN_MEM_READ)
+ prot |= PROT_READ;
+ if (currentHeader.Characteristics & IMAGE_SCN_MEM_WRITE)
+ prot |= PROT_WRITE;
+
+ palError = MAPmmapAndRecord(pFileObject, loadedBase,
+ sectionBase,
+ currentHeader.SizeOfRawData,
+ prot,
+ MAP_FILE|MAP_PRIVATE|MAP_FIXED,
+ fd,
+ currentHeader.PointerToRawData,
+ &sectionData);
+ if (NO_ERROR != palError)
+ {
+ ERROR_(LOADER)( "mmap of section %d failed\n", i );
+ goto doneReleaseMappingCriticalSection;
+ }
+
+#if _DEBUG
+ {
+ // Ensure null termination of section name (which is allowed to not be null terminated if exactly 8 characters long)
+ char sectionName[9];
+ sectionName[8] = '\0';
+ memcpy(sectionName, currentHeader.Name, sizeof(currentHeader.Name));
+ TRACE_(LOADER)("Section %d '%s' (header @ %p) loaded @ %p (RVA: 0x%x, SizeOfRawData: 0x%x, PointerToRawData: 0x%x)\n",
+ i, sectionName, &currentHeader, sectionData, currentHeader.VirtualAddress, currentHeader.SizeOfRawData, currentHeader.PointerToRawData);
+ }
+#endif // _DEBUG
+
+ prevSectionBase = sectionBase;
+ prevSectionSizeInMemory = (currentHeader.SizeOfRawData + VIRTUAL_PAGE_MASK) & ~VIRTUAL_PAGE_MASK; // round up to page boundary
+ }
+
+ // Is there space after the last section and before the end of the mapped image? If so, add a PROT_NONE mapping to cover it.
+ char* imageEnd;
+ imageEnd = (char*)loadedBase + virtualSize; // actually, points just after the mapped end
+ if ((char*)prevSectionBase + prevSectionSizeInMemory < imageEnd)
+ {
+ char* gapBase = (char*)prevSectionBase + prevSectionSizeInMemory;
+ palError = MAPRecordMapping(pFileObject,
+ loadedBase,
+ (void*)gapBase,
+ imageEnd - gapBase,
+ PROT_NONE);
+ if (NO_ERROR != palError)
+ {
+ ERROR_(LOADER)( "recording end of image gap section failed\n" );
+ goto doneReleaseMappingCriticalSection;
+ }
+ }
+
+ palError = ERROR_SUCCESS;
+
+doneReleaseMappingCriticalSection:
+
+ InternalLeaveCriticalSection(pThread, &mapping_critsec);
+
+done:
+
+ if (NULL != pLocalDataLock)
+ {
+ pLocalDataLock->ReleaseLock(pThread, FALSE);
+ }
+
+ if (NULL != pFileObject)
+ {
+ pFileObject->ReleaseReference(pThread);
+ }
+
+ if (palError == ERROR_SUCCESS)
+ {
+ retval = loadedBase;
+ LOGEXIT("MAPMapPEFile returns %p\n", retval);
+ }
+ else
+ {
+ retval = NULL;
+ LOGEXIT("MAPMapPEFile error: %d\n", palError);
+
+ // If we had an error, and had mapped anything, we need to unmap it
+ if (loadedBase != NULL)
+ {
+ MAPUnmapPEFile(loadedBase);
+ }
+ }
+ return retval;
+}
+
+/*++
+Function :
+ MAPUnmapPEFile - unmap a PE file, and remove it from the recorded list of PE files mapped
+
+ returns TRUE if successful, FALSE otherwise
+--*/
+BOOL MAPUnmapPEFile(LPCVOID lpAddress)
+{
+ TRACE_(LOADER)("MAPUnmapPEFile(lpAddress=%p)\n", lpAddress);
+
+ if ( NULL == lpAddress )
+ {
+ ERROR_(LOADER)( "lpAddress cannot be NULL\n" );
+ return FALSE;
+ }
+
+ BOOL retval = TRUE;
+ CPalThread * pThread = InternalGetCurrentThread();
+ InternalEnterCriticalSection(pThread, &mapping_critsec);
+ PLIST_ENTRY pLink, pLinkNext, pLinkLocal = NULL;
+ unsigned nPESections = 0;
+
+ // Look through the entire MappedViewList for all mappings associated with the
+ // PE file with base address 'lpAddress'. We want to unmap all the memory
+ // and then release the file mapping object. Unfortunately, based on the comment
+ // in CorUnix::InternalUnmapViewOfFile(), we can't release the file mapping object
+ // while within the mapping critical section. So, we unlink all the elements from the
+ // main list while in the critical section, and then run through this local list
+ // doing the real work after releasing the main list critical section. The order
+ // of the unmapping doesn't matter, so we don't fully set all the list link pointers,
+ // only a minimal set.
+
+ for(pLink = MappedViewList.Flink;
+ pLink != &MappedViewList;
+ pLink = pLinkNext)
+ {
+ pLinkNext = pLink->Flink;
+ PMAPPED_VIEW_LIST pView = CONTAINING_RECORD(pLink, MAPPED_VIEW_LIST, Link);
+
+ if (pView->lpPEBaseAddress == lpAddress) // this entry is associated with the PE file
+ {
+ ++nPESections; // for debugging, check that we see at least one
+
+ RemoveEntryList(&pView->Link);
+ pView->Link.Flink = pLinkLocal; // the local list is singly-linked, NULL terminated
+ pLinkLocal = &pView->Link;
+ }
+ }
+
+#if _DEBUG
+ if (nPESections == 0)
+ {
+ ERROR_(LOADER)( "MAPUnmapPEFile called to unmap a file that was not in the PE file mapping list\n" );
+ }
+#endif // _DEBUG
+
+ InternalLeaveCriticalSection(pThread, &mapping_critsec);
+
+ // Now, outside the critical section, do the actual unmapping work
+
+ for(pLink = pLinkLocal;
+ pLink != NULL;
+ pLink = pLinkNext)
+ {
+ pLinkNext = pLink->Flink;
+ PMAPPED_VIEW_LIST pView = CONTAINING_RECORD(pLink, MAPPED_VIEW_LIST, Link);
+
+ // remove pView mapping from the list
+ if (-1 == munmap(pView->lpAddress, pView->NumberOfBytesToMap))
+ {
+ // Emit an error message in a trace, but continue trying to do the rest
+ ERROR_(LOADER)("Unable to unmap the file. Expect trouble.\n");
+ retval = FALSE;
+ }
+
+ IPalObject* pFileObject = pView->pFileMapping;
+ if (NULL != pFileObject)
+ {
+ pFileObject->ReleaseReference(pThread);
+ }
+ free(pView); // this leaves pLink dangling
+ }
+
+ TRACE_(LOADER)("MAPUnmapPEFile returning %d\n", retval);
+ return retval;
+}
diff --git a/src/pal/src/map/virtual.cpp b/src/pal/src/map/virtual.cpp
new file mode 100644
index 0000000000..4b5209642c
--- /dev/null
+++ b/src/pal/src/map/virtual.cpp
@@ -0,0 +1,2064 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ virtual.cpp
+
+Abstract:
+
+ Implementation of virtual memory management functions.
+
+
+
+--*/
+
+#include "pal/thread.hpp"
+#include "pal/cs.hpp"
+#include "pal/malloc.hpp"
+#include "pal/file.hpp"
+#include "pal/seh.hpp"
+#include "pal/dbgmsg.h"
+#include "pal/virtual.h"
+#include "pal/map.h"
+#include "pal/init.h"
+#include "common.h"
+
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <limits.h>
+
+#if HAVE_VM_ALLOCATE
+#include <mach/vm_map.h>
+#include <mach/mach_init.h>
+#endif // HAVE_VM_ALLOCATE
+
+using namespace CorUnix;
+
+SET_DEFAULT_DEBUG_CHANNEL(VIRTUAL);
+
+CRITICAL_SECTION virtual_critsec;
+
+// The first node in our list of allocated blocks.
+static PCMI pVirtualMemory;
+
+/* We need MAP_ANON. However on some platforms like HP-UX, it is defined as MAP_ANONYMOUS */
+#if !defined(MAP_ANON) && defined(MAP_ANONYMOUS)
+#define MAP_ANON MAP_ANONYMOUS
+#endif
+
+/*++
+Function:
+ ReserveVirtualMemory()
+
+ Helper function that is used by Virtual* APIs and ExecutableMemoryAllocator
+ to reserve virtual memory from the OS.
+
+--*/
+static LPVOID ReserveVirtualMemory(
+ IN CPalThread *pthrCurrent, /* Currently executing thread */
+ IN LPVOID lpAddress, /* Region to reserve or commit */
+ IN SIZE_T dwSize); /* Size of Region */
+
+
+// A memory allocator that allocates memory from a pre-reserved region
+// of virtual memory that is located near the CoreCLR library.
+static ExecutableMemoryAllocator g_executableMemoryAllocator;
+
+//
+//
+// Virtual Memory Logging
+//
+// We maintain a lightweight in-memory circular buffer recording virtual
+// memory operations so that we can better diagnose failures and crashes
+// caused by one of these operations mishandling memory in some way.
+//
+//
+namespace VirtualMemoryLogging
+{
+ // Specifies the operation being logged
+ enum class VirtualOperation
+ {
+ Allocate = 0x10,
+ Reserve = 0x20,
+ Commit = 0x30,
+ Decommit = 0x40,
+ Release = 0x50,
+ };
+
+ // Indicates that the attempted operation has failed
+ const DWORD FailedOperationMarker = 0x80000000;
+
+ // An entry in the in-memory log
+ struct LogRecord
+ {
+ LONG RecordId;
+ DWORD Operation;
+ LPVOID CurrentThread;
+ LPVOID RequestedAddress;
+ LPVOID ReturnedAddress;
+ SIZE_T Size;
+ DWORD AllocationType;
+ DWORD Protect;
+ };
+
+ // Maximum number of records in the in-memory log
+ const LONG MaxRecords = 128;
+
+ // Buffer used to store the logged data
+ volatile LogRecord logRecords[MaxRecords];
+
+ // Current record number. Use (recordNumber % MaxRecords) to determine
+ // the current position in the circular buffer.
+ volatile LONG recordNumber = 0;
+
+ // Record an entry in the in-memory log
+ void LogVaOperation(
+ IN VirtualOperation operation,
+ IN LPVOID requestedAddress,
+ IN SIZE_T size,
+ IN DWORD flAllocationType,
+ IN DWORD flProtect,
+ IN LPVOID returnedAddress,
+ IN BOOL result)
+ {
+ LONG i = InterlockedIncrement(&recordNumber) - 1;
+ LogRecord* curRec = (LogRecord*)&logRecords[i % MaxRecords];
+
+ curRec->RecordId = i;
+ curRec->CurrentThread = (LPVOID)pthread_self();
+ curRec->RequestedAddress = requestedAddress;
+ curRec->ReturnedAddress = returnedAddress;
+ curRec->Size = size;
+ curRec->AllocationType = flAllocationType;
+ curRec->Protect = flProtect;
+ curRec->Operation = static_cast<DWORD>(operation) | (result ? 0 : FailedOperationMarker);
+ }
+}
+
+/*++
+Function:
+ VIRTUALInitialize()
+
+ Initializes this section's critical section.
+
+Return value:
+ TRUE if initialization succeeded
+ FALSE otherwise.
+
+--*/
+extern "C"
+BOOL
+VIRTUALInitialize(bool initializeExecutableMemoryAllocator)
+{
+ TRACE("Initializing the Virtual Critical Sections. \n");
+
+ InternalInitializeCriticalSection(&virtual_critsec);
+
+ pVirtualMemory = NULL;
+
+ if (initializeExecutableMemoryAllocator)
+ {
+ g_executableMemoryAllocator.Initialize();
+ }
+
+ return TRUE;
+}
+
+/***
+ *
+ * VIRTUALCleanup()
+ * Deletes this section's critical section.
+ *
+ */
+extern "C"
+void VIRTUALCleanup()
+{
+ PCMI pEntry;
+ PCMI pTempEntry;
+ CPalThread * pthrCurrent = InternalGetCurrentThread();
+
+ InternalEnterCriticalSection(pthrCurrent, &virtual_critsec);
+
+ // Clean up the allocated memory.
+ pEntry = pVirtualMemory;
+ while ( pEntry )
+ {
+ WARN( "The memory at %d was not freed through a call to VirtualFree.\n",
+ pEntry->startBoundary );
+ free(pEntry->pAllocState);
+ free(pEntry->pProtectionState );
+ pTempEntry = pEntry;
+ pEntry = pEntry->pNext;
+ free(pTempEntry );
+ }
+ pVirtualMemory = NULL;
+
+ InternalLeaveCriticalSection(pthrCurrent, &virtual_critsec);
+
+ TRACE( "Deleting the Virtual Critical Sections. \n" );
+ DeleteCriticalSection( &virtual_critsec );
+}
+
+/***
+ *
+ * VIRTUALContainsInvalidProtectionFlags()
+ * Returns TRUE if an invalid flag is specified. FALSE otherwise.
+ */
+static BOOL VIRTUALContainsInvalidProtectionFlags( IN DWORD flProtect )
+{
+ if ( ( flProtect & ~( PAGE_NOACCESS | PAGE_READONLY |
+ PAGE_READWRITE | PAGE_EXECUTE | PAGE_EXECUTE_READ |
+ PAGE_EXECUTE_READWRITE ) ) != 0 )
+ {
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+
+
+/****
+ *
+ * VIRTUALIsPageCommitted
+ *
+ * SIZE_T nBitToRetrieve - Which page to check.
+ *
+ * Returns TRUE if committed, FALSE otherwise.
+ *
+ */
+static BOOL VIRTUALIsPageCommitted( SIZE_T nBitToRetrieve, CONST PCMI pInformation )
+{
+ SIZE_T nByteOffset = 0;
+ UINT nBitOffset = 0;
+ UINT byteMask = 0;
+
+ if ( !pInformation )
+ {
+ ERROR( "pInformation was NULL!\n" );
+ return FALSE;
+ }
+
+ nByteOffset = nBitToRetrieve / CHAR_BIT;
+ nBitOffset = nBitToRetrieve % CHAR_BIT;
+
+ byteMask = 1 << nBitOffset;
+
+ if ( pInformation->pAllocState[ nByteOffset ] & byteMask )
+ {
+ return TRUE;
+ }
+ else
+ {
+ return FALSE;
+ }
+}
+
+/*********
+ *
+ * VIRTUALGetAllocationType
+ *
+ * IN SIZE_T Index - The page within the range to retrieve
+ * the state for.
+ *
+ * IN pInformation - The virtual memory object.
+ *
+ */
+static INT VIRTUALGetAllocationType( SIZE_T Index, CONST PCMI pInformation )
+{
+ if ( VIRTUALIsPageCommitted( Index, pInformation ) )
+ {
+ return MEM_COMMIT;
+ }
+ else
+ {
+ return MEM_RESERVE;
+ }
+}
+
+/****
+ *
+ * VIRTUALSetPageBits
+ *
+ * IN UINT nStatus - Bit set / reset [0: reset, any other value: set].
+ * IN SIZE_T nStartingBit - The bit to set.
+ *
+ * IN SIZE_T nNumberOfBits - The range of bits to set.
+ * IN BYTE* pBitArray - A pointer the array to be manipulated.
+ *
+ * Returns TRUE on success, FALSE otherwise.
+ * Turn on/off memory status bits.
+ *
+ */
+static BOOL VIRTUALSetPageBits ( UINT nStatus, SIZE_T nStartingBit,
+ SIZE_T nNumberOfBits, BYTE * pBitArray )
+{
+ /* byte masks for optimized modification of partial bytes (changing less
+ than 8 bits in a single byte). note that bits are treated in little
+ endian order : value 1 is bit 0; value 128 is bit 7. in the binary
+ representations below, bit 0 is on the right */
+
+ /* start masks : for modifying bits >= n while preserving bits < n.
+ example : if nStartignBit%8 is 3, then bits 0, 1, 2 remain unchanged
+ while bits 3..7 are changed; startmasks[3] can be used for this. */
+ static const BYTE startmasks[8] = {
+ 0xff, /* start at 0 : 1111 1111 */
+ 0xfe, /* start at 1 : 1111 1110 */
+ 0xfc, /* start at 2 : 1111 1100 */
+ 0xf8, /* start at 3 : 1111 1000 */
+ 0xf0, /* start at 4 : 1111 0000 */
+ 0xe0, /* start at 5 : 1110 0000 */
+ 0xc0, /* start at 6 : 1100 0000 */
+ 0x80 /* start at 7 : 1000 0000 */
+ };
+
+ /* end masks : for modifying bits <= n while preserving bits > n.
+ example : if the last bit to change is 5, then bits 6 & 7 stay unchanged
+ while bits 1..5 are changed; endmasks[5] can be used for this. */
+ static const BYTE endmasks[8] = {
+ 0x01, /* end at 0 : 0000 0001 */
+ 0x03, /* end at 1 : 0000 0011 */
+ 0x07, /* end at 2 : 0000 0111 */
+ 0x0f, /* end at 3 : 0000 1111 */
+ 0x1f, /* end at 4 : 0001 1111 */
+ 0x3f, /* end at 5 : 0011 1111 */
+ 0x7f, /* end at 6 : 0111 1111 */
+ 0xff /* end at 7 : 1111 1111 */
+ };
+ /* last example : if only the middle of a byte must be changed, both start
+ and end masks can be combined (bitwise AND) to obtain the correct mask.
+ if we want to change bits 2 to 4 :
+ startmasks[2] : 0xfc 1111 1100 (change 2,3,4,5,6,7)
+ endmasks[4]: 0x1f 0001 1111 (change 0,1,2,3,4)
+ bitwise AND : 0x1c 0001 1100 (change 2,3,4)
+ */
+
+ BYTE byte_mask;
+ SIZE_T nLastBit;
+ SIZE_T nFirstByte;
+ SIZE_T nLastByte;
+ SIZE_T nFullBytes;
+
+ TRACE( "VIRTUALSetPageBits( nStatus = %d, nStartingBit = %d, "
+ "nNumberOfBits = %d, pBitArray = 0x%p )\n",
+ nStatus, nStartingBit, nNumberOfBits, pBitArray );
+
+ if ( 0 == nNumberOfBits )
+ {
+ ERROR( "nNumberOfBits was 0!\n" );
+ return FALSE;
+ }
+
+ nLastBit = nStartingBit+nNumberOfBits-1;
+ nFirstByte = nStartingBit / 8;
+ nLastByte = nLastBit / 8;
+
+ /* handle partial first byte (if any) */
+ if(0 != (nStartingBit % 8))
+ {
+ byte_mask = startmasks[nStartingBit % 8];
+
+ /* if 1st byte is the only changing byte, combine endmask to preserve
+ trailing bits (see 3rd example above) */
+ if( nLastByte == nFirstByte)
+ {
+ byte_mask &= endmasks[nLastBit % 8];
+ }
+
+ /* byte_mask contains 1 for bits to change, 0 for bits to leave alone */
+ if(0 == nStatus)
+ {
+ /* bits to change must be set to 0 : invert byte_mask (giving 0 for
+ bits to change), use bitwise AND */
+ pBitArray[nFirstByte] &= ~byte_mask;
+ }
+ else
+ {
+ /* bits to change must be set to 1 : use bitwise OR */
+ pBitArray[nFirstByte] |= byte_mask;
+ }
+
+ /* stop right away if only 1 byte is being modified */
+ if(nLastByte == nFirstByte)
+ {
+ return TRUE;
+ }
+
+ /* we're done with the 1st byte; skip over it */
+ nFirstByte++;
+ }
+
+ /* number of bytes to change, excluding the last byte (handled separately)*/
+ nFullBytes = nLastByte - nFirstByte;
+
+ if(0 != nFullBytes)
+ {
+ // Turn off/on dirty bits
+ memset( &(pBitArray[nFirstByte]), (0 == nStatus) ? 0 : 0xFF, nFullBytes );
+ }
+
+ /* handle last (possibly partial) byte */
+ byte_mask = endmasks[nLastBit % 8];
+
+ /* byte_mask contains 1 for bits to change, 0 for bits to leave alone */
+ if(0 == nStatus)
+ {
+ /* bits to change must be set to 0 : invert byte_mask (giving 0 for
+ bits to change), use bitwise AND */
+ pBitArray[nLastByte] &= ~byte_mask;
+ }
+ else
+ {
+ /* bits to change must be set to 1 : use bitwise OR */
+ pBitArray[nLastByte] |= byte_mask;
+ }
+
+ return TRUE;
+}
+
+/****
+ *
+ * VIRTUALSetAllocState
+ *
+ * IN UINT nAction - Which action to perform.
+ * IN SIZE_T nStartingBit - The bit to set.
+ *
+ * IN SIZE_T nNumberOfBits - The range of bits to set.
+ * IN PCMI pStateArray - A pointer the array to be manipulated.
+ *
+ * Returns TRUE on success, FALSE otherwise.
+ * Turn bit on to indicate committed, turn bit off to indicate reserved.
+ *
+ */
+static BOOL VIRTUALSetAllocState( UINT nAction, SIZE_T nStartingBit,
+ SIZE_T nNumberOfBits, CONST PCMI pInformation )
+{
+ TRACE( "VIRTUALSetAllocState( nAction = %d, nStartingBit = %d, "
+ "nNumberOfBits = %d, pStateArray = 0x%p )\n",
+ nAction, nStartingBit, nNumberOfBits, pInformation );
+
+ if ( !pInformation )
+ {
+ ERROR( "pInformation was invalid!\n" );
+ return FALSE;
+ }
+
+ return VIRTUALSetPageBits((MEM_COMMIT == nAction) ? 1 : 0, nStartingBit,
+ nNumberOfBits, pInformation->pAllocState);
+}
+
+/****
+ *
+ * VIRTUALFindRegionInformation( )
+ *
+ * IN UINT_PTR address - The address to look for.
+ *
+ * Returns the PCMI if found, NULL otherwise.
+ */
+static PCMI VIRTUALFindRegionInformation( IN UINT_PTR address )
+{
+ PCMI pEntry = NULL;
+
+ TRACE( "VIRTUALFindRegionInformation( %#x )\n", address );
+
+ pEntry = pVirtualMemory;
+
+ while( pEntry )
+ {
+ if ( pEntry->startBoundary > address )
+ {
+ /* Gone past the possible location in the list. */
+ pEntry = NULL;
+ break;
+ }
+ if ( pEntry->startBoundary + pEntry->memSize > address )
+ {
+ break;
+ }
+
+ pEntry = pEntry->pNext;
+ }
+ return pEntry;
+}
+
+/*++
+Function :
+
+ VIRTUALReleaseMemory
+
+ Removes a PCMI entry from the list.
+
+ Returns true on success. FALSE otherwise.
+--*/
+static BOOL VIRTUALReleaseMemory( PCMI pMemoryToBeReleased )
+{
+ BOOL bRetVal = TRUE;
+
+ if ( !pMemoryToBeReleased )
+ {
+ ASSERT( "Invalid pointer.\n" );
+ return FALSE;
+ }
+
+ if ( pMemoryToBeReleased == pVirtualMemory )
+ {
+ /* This is either the first entry, or the only entry. */
+ pVirtualMemory = pMemoryToBeReleased->pNext;
+ if ( pMemoryToBeReleased->pNext )
+ {
+ pMemoryToBeReleased->pNext->pPrevious = NULL;
+ }
+ }
+ else /* Could be anywhere in the list. */
+ {
+ /* Delete the entry from the linked list. */
+ if ( pMemoryToBeReleased->pPrevious )
+ {
+ pMemoryToBeReleased->pPrevious->pNext = pMemoryToBeReleased->pNext;
+ }
+
+ if ( pMemoryToBeReleased->pNext )
+ {
+ pMemoryToBeReleased->pNext->pPrevious = pMemoryToBeReleased->pPrevious;
+ }
+ }
+
+ free( pMemoryToBeReleased->pAllocState );
+ pMemoryToBeReleased->pAllocState = NULL;
+
+ free( pMemoryToBeReleased->pProtectionState );
+ pMemoryToBeReleased->pProtectionState = NULL;
+
+ free( pMemoryToBeReleased );
+ pMemoryToBeReleased = NULL;
+
+ return bRetVal;
+}
+
+/****
+ * VIRTUALConvertWinFlags() -
+ * Converts win32 protection flags to
+ * internal VIRTUAL flags.
+ *
+ */
+static BYTE VIRTUALConvertWinFlags( IN DWORD flProtect )
+{
+ BYTE MemAccessControl = 0;
+
+ switch ( flProtect & 0xff )
+ {
+ case PAGE_NOACCESS :
+ MemAccessControl = VIRTUAL_NOACCESS;
+ break;
+ case PAGE_READONLY :
+ MemAccessControl = VIRTUAL_READONLY;
+ break;
+ case PAGE_READWRITE :
+ MemAccessControl = VIRTUAL_READWRITE;
+ break;
+ case PAGE_EXECUTE :
+ MemAccessControl = VIRTUAL_EXECUTE;
+ break;
+ case PAGE_EXECUTE_READ :
+ MemAccessControl = VIRTUAL_EXECUTE_READ;
+ break;
+ case PAGE_EXECUTE_READWRITE:
+ MemAccessControl = VIRTUAL_EXECUTE_READWRITE;
+ break;
+
+ default :
+ MemAccessControl = 0;
+ ERROR( "Incorrect or no protection flags specified.\n" );
+ break;
+ }
+ return MemAccessControl;
+}
+
+/****
+ * VIRTUALConvertVirtualFlags() -
+ * Converts internal virtual protection
+ * flags to their win32 counterparts.
+ */
+static DWORD VIRTUALConvertVirtualFlags( IN BYTE VirtualProtect )
+{
+ DWORD MemAccessControl = 0;
+
+ if ( VirtualProtect == VIRTUAL_READONLY )
+ {
+ MemAccessControl = PAGE_READONLY;
+ }
+ else if ( VirtualProtect == VIRTUAL_READWRITE )
+ {
+ MemAccessControl = PAGE_READWRITE;
+ }
+ else if ( VirtualProtect == VIRTUAL_EXECUTE_READWRITE )
+ {
+ MemAccessControl = PAGE_EXECUTE_READWRITE;
+ }
+ else if ( VirtualProtect == VIRTUAL_EXECUTE_READ )
+ {
+ MemAccessControl = PAGE_EXECUTE_READ;
+ }
+ else if ( VirtualProtect == VIRTUAL_EXECUTE )
+ {
+ MemAccessControl = PAGE_EXECUTE;
+ }
+ else if ( VirtualProtect == VIRTUAL_NOACCESS )
+ {
+ MemAccessControl = PAGE_NOACCESS;
+ }
+
+ else
+ {
+ MemAccessControl = 0;
+ ERROR( "Incorrect or no protection flags specified.\n" );
+ }
+ return MemAccessControl;
+}
+
+/***
+ * Displays the linked list.
+ *
+ */
+#if defined _DEBUG
+static void VIRTUALDisplayList( void )
+{
+ if (!DBG_ENABLED(DLI_TRACE, defdbgchan))
+ return;
+
+ PCMI p;
+ SIZE_T count;
+ SIZE_T index;
+ CPalThread * pthrCurrent = InternalGetCurrentThread();
+
+ InternalEnterCriticalSection(pthrCurrent, &virtual_critsec);
+
+ p = pVirtualMemory;
+ count = 0;
+ while ( p ) {
+
+ DBGOUT( "Entry %d : \n", count );
+ DBGOUT( "\t startBoundary %#x \n", p->startBoundary );
+ DBGOUT( "\t memSize %d \n", p->memSize );
+
+ DBGOUT( "\t pAllocState " );
+ for ( index = 0; index < p->memSize / VIRTUAL_PAGE_SIZE; index++)
+ {
+ DBGOUT( "[%d] ", VIRTUALGetAllocationType( index, p ) );
+ }
+ DBGOUT( "\t pProtectionState " );
+ for ( index = 0; index < p->memSize / VIRTUAL_PAGE_SIZE; index++ )
+ {
+ DBGOUT( "[%d] ", (UINT)p->pProtectionState[ index ] );
+ }
+ DBGOUT( "\n" );
+ DBGOUT( "\t accessProtection %d \n", p->accessProtection );
+ DBGOUT( "\t allocationType %d \n", p->allocationType );
+ DBGOUT( "\t pNext %p \n", p->pNext );
+ DBGOUT( "\t pLast %p \n", p->pPrevious );
+
+ count++;
+ p = p->pNext;
+ }
+
+ InternalLeaveCriticalSection(pthrCurrent, &virtual_critsec);
+}
+#endif
+
+#ifdef DEBUG
+void VerifyRightEntry(PCMI pEntry)
+{
+ volatile PCMI pRight = pEntry->pNext;
+ SIZE_T endAddress;
+ if (pRight != nullptr)
+ {
+ endAddress = ((SIZE_T)pEntry->startBoundary) + pEntry->memSize;
+ _ASSERTE(endAddress <= (SIZE_T)pRight->startBoundary);
+ }
+}
+
+void VerifyLeftEntry(PCMI pEntry)
+{
+ volatile PCMI pLeft = pEntry->pPrevious;
+ SIZE_T endAddress;
+ if (pLeft != NULL)
+ {
+ endAddress = ((SIZE_T)pLeft->startBoundary) + pLeft->memSize;
+ _ASSERTE(endAddress <= (SIZE_T)pEntry->startBoundary);
+ }
+}
+#endif // DEBUG
+
+/****
+ * VIRTUALStoreAllocationInfo()
+ *
+ * Stores the allocation information in the linked list.
+ * NOTE: The caller must own the critical section.
+ */
+static BOOL VIRTUALStoreAllocationInfo(
+ IN UINT_PTR startBoundary, /* Start of the region. */
+ IN SIZE_T memSize, /* Size of the region. */
+ IN DWORD flAllocationType, /* Allocation Types. */
+ IN DWORD flProtection ) /* Protections flags on the memory. */
+{
+ PCMI pNewEntry = nullptr;
+ PCMI pMemInfo = nullptr;
+ SIZE_T nBufferSize = 0;
+
+ if ((memSize & VIRTUAL_PAGE_MASK) != 0)
+ {
+ ERROR("The memory size was not a multiple of the page size. \n");
+ return FALSE;
+ }
+
+ if (!(pNewEntry = (PCMI)InternalMalloc(sizeof(*pNewEntry))))
+ {
+ ERROR( "Unable to allocate memory for the structure.\n");
+ return FALSE;
+ }
+
+ pNewEntry->startBoundary = startBoundary;
+ pNewEntry->memSize = memSize;
+ pNewEntry->allocationType = flAllocationType;
+ pNewEntry->accessProtection = flProtection;
+
+ nBufferSize = memSize / VIRTUAL_PAGE_SIZE / CHAR_BIT;
+ if ((memSize / VIRTUAL_PAGE_SIZE) % CHAR_BIT != 0)
+ {
+ nBufferSize++;
+ }
+
+ pNewEntry->pAllocState = (BYTE*)InternalMalloc(nBufferSize);
+ pNewEntry->pProtectionState = (BYTE*)InternalMalloc((memSize / VIRTUAL_PAGE_SIZE));
+
+ if (pNewEntry->pAllocState && pNewEntry->pProtectionState)
+ {
+ /* Set the intial allocation state, and initial allocation protection. */
+ VIRTUALSetAllocState(MEM_RESERVE, 0, nBufferSize * CHAR_BIT, pNewEntry);
+ memset(pNewEntry->pProtectionState,
+ VIRTUALConvertWinFlags(flProtection),
+ memSize / VIRTUAL_PAGE_SIZE);
+ }
+ else
+ {
+ ERROR( "Unable to allocate memory for the structure.\n");
+
+ if (pNewEntry->pProtectionState) free(pNewEntry->pProtectionState);
+ pNewEntry->pProtectionState = nullptr;
+
+ if (pNewEntry->pAllocState) free(pNewEntry->pAllocState);
+ pNewEntry->pAllocState = nullptr;
+
+ free(pNewEntry);
+ pNewEntry = nullptr;
+
+ return FALSE;
+ }
+
+ pMemInfo = pVirtualMemory;
+
+ if (pMemInfo && pMemInfo->startBoundary < startBoundary)
+ {
+ /* Look for the correct insert point */
+ TRACE("Looking for the correct insert location.\n");
+ while (pMemInfo->pNext && (pMemInfo->pNext->startBoundary < startBoundary))
+ {
+ pMemInfo = pMemInfo->pNext;
+ }
+
+ pNewEntry->pNext = pMemInfo->pNext;
+ pNewEntry->pPrevious = pMemInfo;
+
+ if (pNewEntry->pNext)
+ {
+ pNewEntry->pNext->pPrevious = pNewEntry;
+ }
+
+ pMemInfo->pNext = pNewEntry;
+ }
+ else
+ {
+ /* This is the first entry in the list. */
+ pNewEntry->pNext = pMemInfo;
+ pNewEntry->pPrevious = nullptr;
+
+ if (pNewEntry->pNext)
+ {
+ pNewEntry->pNext->pPrevious = pNewEntry;
+ }
+
+ pVirtualMemory = pNewEntry ;
+ }
+
+#ifdef DEBUG
+ VerifyRightEntry(pNewEntry);
+ VerifyLeftEntry(pNewEntry);
+#endif // DEBUG
+
+ return TRUE;
+}
+
+/******
+ *
+ * VIRTUALReserveMemory() - Helper function that actually reserves the memory.
+ *
+ * NOTE: I call SetLastError in here, because many different error states
+ * exists, and that would be very complicated to work around.
+ *
+ */
+static LPVOID VIRTUALReserveMemory(
+ IN CPalThread *pthrCurrent, /* Currently executing thread */
+ IN LPVOID lpAddress, /* Region to reserve or commit */
+ IN SIZE_T dwSize, /* Size of Region */
+ IN DWORD flAllocationType, /* Type of allocation */
+ IN DWORD flProtect) /* Type of access protection */
+{
+ LPVOID pRetVal = NULL;
+ UINT_PTR StartBoundary;
+ SIZE_T MemSize;
+
+ TRACE( "Reserving the memory now..\n");
+
+ // First, figure out where we're trying to reserve the memory and
+ // how much we need. On most systems, requests to mmap must be
+ // page-aligned and at multiples of the page size.
+ StartBoundary = (UINT_PTR)lpAddress & ~BOUNDARY_64K;
+ /* Add the sizes, and round down to the nearest page boundary. */
+ MemSize = ( ((UINT_PTR)lpAddress + dwSize + VIRTUAL_PAGE_MASK) & ~VIRTUAL_PAGE_MASK ) -
+ StartBoundary;
+
+ InternalEnterCriticalSection(pthrCurrent, &virtual_critsec);
+
+ // If this is a request for special executable (JIT'ed) memory then, first of all,
+ // try to get memory from the executable memory allocator to satisfy the request.
+ if (((flAllocationType & MEM_RESERVE_EXECUTABLE) != 0) && (lpAddress == NULL))
+ {
+ pRetVal = g_executableMemoryAllocator.AllocateMemory(MemSize);
+ }
+
+ if (pRetVal == NULL)
+ {
+ // Try to reserve memory from the OS
+ pRetVal = ReserveVirtualMemory(pthrCurrent, (LPVOID)StartBoundary, MemSize);
+ }
+
+ if (pRetVal != NULL)
+ {
+ if ( !lpAddress )
+ {
+ /* Compute the real values instead of the null values. */
+ StartBoundary = (UINT_PTR)pRetVal & ~VIRTUAL_PAGE_MASK;
+ MemSize = ( ((UINT_PTR)pRetVal + dwSize + VIRTUAL_PAGE_MASK) & ~VIRTUAL_PAGE_MASK ) -
+ StartBoundary;
+ }
+
+ if ( !VIRTUALStoreAllocationInfo( StartBoundary, MemSize,
+ flAllocationType, flProtect ) )
+ {
+ ASSERT( "Unable to store the structure in the list.\n");
+ pthrCurrent->SetLastError( ERROR_INTERNAL_ERROR );
+ munmap( pRetVal, MemSize );
+ pRetVal = NULL;
+ }
+ }
+
+ LogVaOperation(
+ VirtualMemoryLogging::VirtualOperation::Reserve,
+ lpAddress,
+ dwSize,
+ flAllocationType,
+ flProtect,
+ pRetVal,
+ pRetVal != NULL);
+
+ InternalLeaveCriticalSection(pthrCurrent, &virtual_critsec);
+ return pRetVal;
+}
+
+/******
+ *
+ * ReserveVirtualMemory() - Helper function that is used by Virtual* APIs
+ * and ExecutableMemoryAllocator to reserve virtual memory from the OS.
+ *
+ */
+static LPVOID ReserveVirtualMemory(
+ IN CPalThread *pthrCurrent, /* Currently executing thread */
+ IN LPVOID lpAddress, /* Region to reserve or commit */
+ IN SIZE_T dwSize) /* Size of Region */
+{
+ UINT_PTR StartBoundary = (UINT_PTR)lpAddress;
+ SIZE_T MemSize = dwSize;
+
+ TRACE( "Reserving the memory now.\n");
+
+ // Most platforms will only commit memory if it is dirtied,
+ // so this should not consume too much swap space.
+ int mmapFlags = 0;
+
+#if HAVE_VM_ALLOCATE
+ // Allocate with vm_allocate first, then map at the fixed address.
+ int result = vm_allocate(mach_task_self(),
+ &StartBoundary,
+ MemSize,
+ ((LPVOID) StartBoundary != nullptr) ? FALSE : TRUE);
+
+ if (result != KERN_SUCCESS)
+ {
+ ERROR("vm_allocate failed to allocated the requested region!\n");
+ pthrCurrent->SetLastError(ERROR_INVALID_ADDRESS);
+ return nullptr;
+ }
+
+ mmapFlags |= MAP_FIXED;
+#endif // HAVE_VM_ALLOCATE
+
+ mmapFlags |= MAP_ANON | MAP_PRIVATE;
+
+ LPVOID pRetVal = mmap((LPVOID) StartBoundary,
+ MemSize,
+ PROT_NONE,
+ mmapFlags,
+ -1 /* fd */,
+ 0 /* offset */);
+
+ if (pRetVal == MAP_FAILED)
+ {
+ ERROR( "Failed due to insufficient memory.\n" );
+
+#if HAVE_VM_ALLOCATE
+ vm_deallocate(mach_task_self(), StartBoundary, MemSize);
+#endif // HAVE_VM_ALLOCATE
+
+ pthrCurrent->SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ return nullptr;
+ }
+
+ /* Check to see if the region is what we asked for. */
+ if (lpAddress != nullptr && StartBoundary != (UINT_PTR)pRetVal)
+ {
+ ERROR("We did not get the region we asked for from mmap!\n");
+ pthrCurrent->SetLastError(ERROR_INVALID_ADDRESS);
+ munmap(pRetVal, MemSize);
+ return nullptr;
+ }
+
+#if MMAP_ANON_IGNORES_PROTECTION
+ if (mprotect(pRetVal, MemSize, PROT_NONE) != 0)
+ {
+ ERROR("mprotect failed to protect the region!\n");
+ pthrCurrent->SetLastError(ERROR_INVALID_ADDRESS);
+ munmap(pRetVal, MemSize);
+ return nullptr;
+ }
+#endif // MMAP_ANON_IGNORES_PROTECTION
+
+ return pRetVal;
+}
+
+/******
+ *
+ * VIRTUALCommitMemory() - Helper function that actually commits the memory.
+ *
+ * NOTE: I call SetLastError in here, because many different error states
+ * exists, and that would be very complicated to work around.
+ *
+ */
+static LPVOID
+VIRTUALCommitMemory(
+ IN CPalThread *pthrCurrent, /* Currently executing thread */
+ IN LPVOID lpAddress, /* Region to reserve or commit */
+ IN SIZE_T dwSize, /* Size of Region */
+ IN DWORD flAllocationType, /* Type of allocation */
+ IN DWORD flProtect) /* Type of access protection */
+{
+ UINT_PTR StartBoundary = 0;
+ SIZE_T MemSize = 0;
+ PCMI pInformation = 0;
+ LPVOID pRetVal = NULL;
+ BOOL IsLocallyReserved = FALSE;
+ SIZE_T totalPages;
+ INT allocationType, curAllocationType;
+ INT protectionState, curProtectionState;
+ SIZE_T initialRunStart;
+ SIZE_T runStart;
+ SIZE_T runLength;
+ SIZE_T index;
+ INT nProtect;
+ INT vProtect;
+
+ if ( lpAddress )
+ {
+ StartBoundary = (UINT_PTR)lpAddress & ~VIRTUAL_PAGE_MASK;
+ /* Add the sizes, and round down to the nearest page boundary. */
+ MemSize = ( ((UINT_PTR)lpAddress + dwSize + VIRTUAL_PAGE_MASK) & ~VIRTUAL_PAGE_MASK ) -
+ StartBoundary;
+ }
+ else
+ {
+ MemSize = ( dwSize + VIRTUAL_PAGE_MASK ) & ~VIRTUAL_PAGE_MASK;
+ }
+
+ /* See if we have already reserved this memory. */
+ pInformation = VIRTUALFindRegionInformation( StartBoundary );
+
+ if ( !pInformation )
+ {
+ /* According to the new MSDN docs, if MEM_COMMIT is specified,
+ and the memory is not reserved, you reserve and then commit.
+ */
+ LPVOID pReservedMemory =
+ VIRTUALReserveMemory( pthrCurrent, lpAddress, dwSize,
+ flAllocationType, flProtect );
+
+ TRACE( "Reserve and commit the memory!\n " );
+
+ if ( pReservedMemory )
+ {
+ /* Re-align the addresses and try again to find the memory. */
+ StartBoundary = (UINT_PTR)pReservedMemory & ~VIRTUAL_PAGE_MASK;
+ MemSize = ( ((UINT_PTR)pReservedMemory + dwSize + VIRTUAL_PAGE_MASK)
+ & ~VIRTUAL_PAGE_MASK ) - StartBoundary;
+
+ pInformation = VIRTUALFindRegionInformation( StartBoundary );
+
+ if ( !pInformation )
+ {
+ ASSERT( "Unable to locate the region information.\n" );
+ pthrCurrent->SetLastError( ERROR_INTERNAL_ERROR );
+ pRetVal = NULL;
+ goto done;
+ }
+ IsLocallyReserved = TRUE;
+ }
+ else
+ {
+ ERROR( "Unable to reserve the memory.\n" );
+ /* Don't set last error here, it will already be set. */
+ pRetVal = NULL;
+ goto done;
+ }
+ }
+
+ TRACE( "Committing the memory now..\n");
+
+ // Pages that aren't already committed need to be committed. Pages that
+ // are committed don't need to be committed, but they might need to have
+ // their permissions changed.
+ // To get this right, we find runs of pages with similar states and
+ // permissions. If a run is not committed, we commit it and then set
+ // its permissions. If a run is committed but has different permissions
+ // from what we're trying to set, we set its permissions. Finally,
+ // if a run is already committed and has the right permissions,
+ // we don't need to do anything to it.
+
+ totalPages = MemSize / VIRTUAL_PAGE_SIZE;
+ runStart = (StartBoundary - pInformation->startBoundary) /
+ VIRTUAL_PAGE_SIZE; // Page index
+ initialRunStart = runStart;
+ allocationType = VIRTUALGetAllocationType(runStart, pInformation);
+ protectionState = pInformation->pProtectionState[runStart];
+ curAllocationType = allocationType;
+ curProtectionState = protectionState;
+ runLength = 1;
+ nProtect = W32toUnixAccessControl(flProtect);
+ vProtect = VIRTUALConvertWinFlags(flProtect);
+
+ if (totalPages > pInformation->memSize / VIRTUAL_PAGE_SIZE - runStart)
+ {
+ ERROR("Trying to commit beyond the end of the region!\n");
+ goto error;
+ }
+
+ while(runStart < initialRunStart + totalPages)
+ {
+ // Find the next run of pages
+ for(index = runStart + 1; index < initialRunStart + totalPages;
+ index++)
+ {
+ curAllocationType = VIRTUALGetAllocationType(index, pInformation);
+ curProtectionState = pInformation->pProtectionState[index];
+ if (curAllocationType != allocationType ||
+ curProtectionState != protectionState)
+ {
+ break;
+ }
+ runLength++;
+ }
+
+ StartBoundary = pInformation->startBoundary + runStart * VIRTUAL_PAGE_SIZE;
+ MemSize = runLength * VIRTUAL_PAGE_SIZE;
+
+ if (allocationType != MEM_COMMIT)
+ {
+ // Commit the pages
+ if (mprotect((void *) StartBoundary, MemSize, PROT_WRITE | PROT_READ) != 0)
+ {
+ ERROR("mprotect() failed! Error(%d)=%s\n", errno, strerror(errno));
+ goto error;
+ }
+
+ VIRTUALSetAllocState(MEM_COMMIT, runStart, runLength, pInformation);
+
+ if (nProtect == (PROT_WRITE | PROT_READ))
+ {
+ // Handle this case specially so we don't bother
+ // mprotect'ing the region.
+ memset(pInformation->pProtectionState + runStart,
+ vProtect, runLength);
+ }
+
+ protectionState = VIRTUAL_READWRITE;
+ }
+
+ if (protectionState != vProtect)
+ {
+ // Change permissions.
+ if (mprotect((void *) StartBoundary, MemSize, nProtect) != -1)
+ {
+ memset(pInformation->pProtectionState + runStart,
+ vProtect, runLength);
+ }
+ else
+ {
+ ERROR("mprotect() failed! Error(%d)=%s\n",
+ errno, strerror(errno));
+ goto error;
+ }
+ }
+
+ runStart = index;
+ runLength = 1;
+ allocationType = curAllocationType;
+ protectionState = curProtectionState;
+ }
+
+ pRetVal = (void *) (pInformation->startBoundary + initialRunStart * VIRTUAL_PAGE_SIZE);
+ goto done;
+
+error:
+ if ( flAllocationType & MEM_RESERVE || IsLocallyReserved )
+ {
+ munmap( pRetVal, MemSize );
+ if ( VIRTUALReleaseMemory( pInformation ) == FALSE )
+ {
+ ASSERT( "Unable to remove the PCMI entry from the list.\n" );
+ pthrCurrent->SetLastError( ERROR_INTERNAL_ERROR );
+ pRetVal = NULL;
+ goto done;
+ }
+ pInformation = NULL;
+ pRetVal = NULL;
+ }
+
+done:
+
+ LogVaOperation(
+ VirtualMemoryLogging::VirtualOperation::Commit,
+ lpAddress,
+ dwSize,
+ flAllocationType,
+ flProtect,
+ pRetVal,
+ pRetVal != NULL);
+
+ return pRetVal;
+}
+
+/*++
+Function:
+ VirtualAlloc
+
+Note:
+ MEM_TOP_DOWN, MEM_PHYSICAL, MEM_WRITE_WATCH are not supported.
+ Unsupported flags are ignored.
+
+ Page size on i386 is set to 4k.
+
+See MSDN doc.
+--*/
+LPVOID
+PALAPI
+VirtualAlloc(
+ IN LPVOID lpAddress, /* Region to reserve or commit */
+ IN SIZE_T dwSize, /* Size of Region */
+ IN DWORD flAllocationType, /* Type of allocation */
+ IN DWORD flProtect) /* Type of access protection */
+{
+ LPVOID pRetVal = NULL;
+ CPalThread *pthrCurrent;
+
+ PERF_ENTRY(VirtualAlloc);
+ ENTRY("VirtualAlloc(lpAddress=%p, dwSize=%u, flAllocationType=%#x, \
+ flProtect=%#x)\n", lpAddress, dwSize, flAllocationType, flProtect);
+
+ pthrCurrent = InternalGetCurrentThread();
+
+ if ( ( flAllocationType & MEM_WRITE_WATCH ) != 0 )
+ {
+ pthrCurrent->SetLastError( ERROR_INVALID_PARAMETER );
+ goto done;
+ }
+
+ /* Test for un-supported flags. */
+ if ( ( flAllocationType & ~( MEM_COMMIT | MEM_RESERVE | MEM_TOP_DOWN | MEM_RESERVE_EXECUTABLE ) ) != 0 )
+ {
+ ASSERT( "flAllocationType can be one, or any combination of MEM_COMMIT, \
+ MEM_RESERVE, MEM_TOP_DOWN, or MEM_RESERVE_EXECUTABLE.\n" );
+ pthrCurrent->SetLastError( ERROR_INVALID_PARAMETER );
+ goto done;
+ }
+ if ( VIRTUALContainsInvalidProtectionFlags( flProtect ) )
+ {
+ ASSERT( "flProtect can be one of PAGE_READONLY, PAGE_READWRITE, or \
+ PAGE_EXECUTE_READWRITE || PAGE_NOACCESS. \n" );
+
+ pthrCurrent->SetLastError( ERROR_INVALID_PARAMETER );
+ goto done;
+ }
+ if ( flAllocationType & MEM_TOP_DOWN )
+ {
+ WARN( "Ignoring the allocation flag MEM_TOP_DOWN.\n" );
+ }
+
+ LogVaOperation(
+ VirtualMemoryLogging::VirtualOperation::Allocate,
+ lpAddress,
+ dwSize,
+ flAllocationType,
+ flProtect,
+ NULL,
+ TRUE);
+
+ if ( flAllocationType & MEM_RESERVE )
+ {
+ InternalEnterCriticalSection(pthrCurrent, &virtual_critsec);
+ pRetVal = VIRTUALReserveMemory( pthrCurrent, lpAddress, dwSize, flAllocationType, flProtect );
+ InternalLeaveCriticalSection(pthrCurrent, &virtual_critsec);
+
+ if ( !pRetVal )
+ {
+ /* Error messages are already displayed, just leave. */
+ goto done;
+ }
+ }
+
+ if ( flAllocationType & MEM_COMMIT )
+ {
+ InternalEnterCriticalSection(pthrCurrent, &virtual_critsec);
+ if ( pRetVal != NULL )
+ {
+ /* We are reserving and committing. */
+ pRetVal = VIRTUALCommitMemory( pthrCurrent, pRetVal, dwSize,
+ flAllocationType, flProtect );
+ }
+ else
+ {
+ /* Just a commit. */
+ pRetVal = VIRTUALCommitMemory( pthrCurrent, lpAddress, dwSize,
+ flAllocationType, flProtect );
+ }
+ InternalLeaveCriticalSection(pthrCurrent, &virtual_critsec);
+ }
+
+done:
+#if defined _DEBUG
+ VIRTUALDisplayList();
+#endif
+ LOGEXIT("VirtualAlloc returning %p\n ", pRetVal );
+ PERF_EXIT(VirtualAlloc);
+ return pRetVal;
+}
+
+
+/*++
+Function:
+ VirtualFree
+
+See MSDN doc.
+--*/
+BOOL
+PALAPI
+VirtualFree(
+ IN LPVOID lpAddress, /* Address of region. */
+ IN SIZE_T dwSize, /* Size of region. */
+ IN DWORD dwFreeType ) /* Operation type. */
+{
+ BOOL bRetVal = TRUE;
+ CPalThread *pthrCurrent;
+
+ PERF_ENTRY(VirtualFree);
+ ENTRY("VirtualFree(lpAddress=%p, dwSize=%u, dwFreeType=%#x)\n",
+ lpAddress, dwSize, dwFreeType);
+
+ pthrCurrent = InternalGetCurrentThread();
+ InternalEnterCriticalSection(pthrCurrent, &virtual_critsec);
+
+ /* Sanity Checks. */
+ if ( !lpAddress )
+ {
+ ERROR( "lpAddress cannot be NULL. You must specify the base address of\
+ regions to be de-committed. \n" );
+ pthrCurrent->SetLastError( ERROR_INVALID_ADDRESS );
+ bRetVal = FALSE;
+ goto VirtualFreeExit;
+ }
+
+ if ( !( dwFreeType & MEM_RELEASE ) && !(dwFreeType & MEM_DECOMMIT ) )
+ {
+ ERROR( "dwFreeType must contain one of the following: \
+ MEM_RELEASE or MEM_DECOMMIT\n" );
+ pthrCurrent->SetLastError( ERROR_INVALID_PARAMETER );
+ bRetVal = FALSE;
+ goto VirtualFreeExit;
+ }
+ /* You cannot release and decommit in one call.*/
+ if ( dwFreeType & MEM_RELEASE && dwFreeType & MEM_DECOMMIT )
+ {
+ ERROR( "MEM_RELEASE cannot be combined with MEM_DECOMMIT.\n" );
+ bRetVal = FALSE;
+ goto VirtualFreeExit;
+ }
+
+ if ( dwFreeType & MEM_DECOMMIT )
+ {
+ UINT_PTR StartBoundary = 0;
+ SIZE_T MemSize = 0;
+
+ if ( dwSize == 0 )
+ {
+ ERROR( "dwSize cannot be 0. \n" );
+ pthrCurrent->SetLastError( ERROR_INVALID_PARAMETER );
+ bRetVal = FALSE;
+ goto VirtualFreeExit;
+ }
+ /*
+ * A two byte range straddling 2 pages caues both pages to be either
+ * released or decommitted. So round the dwSize up to the next page
+ * boundary and round the lpAddress down to the next page boundary.
+ */
+ MemSize = (((UINT_PTR)(dwSize) + ((UINT_PTR)(lpAddress) & VIRTUAL_PAGE_MASK)
+ + VIRTUAL_PAGE_MASK) & ~VIRTUAL_PAGE_MASK);
+
+ StartBoundary = (UINT_PTR)lpAddress & ~VIRTUAL_PAGE_MASK;
+
+ PCMI pUnCommittedMem;
+ pUnCommittedMem = VIRTUALFindRegionInformation( StartBoundary );
+ if (!pUnCommittedMem)
+ {
+ ASSERT( "Unable to locate the region information.\n" );
+ pthrCurrent->SetLastError( ERROR_INTERNAL_ERROR );
+ bRetVal = FALSE;
+ goto VirtualFreeExit;
+ }
+
+ TRACE( "Un-committing the following page(s) %d to %d.\n",
+ StartBoundary, MemSize );
+
+ // Explicitly calling mmap instead of mprotect here makes it
+ // that much more clear to the operating system that we no
+ // longer need these pages.
+ if ( mmap( (LPVOID)StartBoundary, MemSize, PROT_NONE,
+ MAP_FIXED | MAP_ANON | MAP_PRIVATE, -1, 0 ) != MAP_FAILED )
+ {
+#if (MMAP_ANON_IGNORES_PROTECTION)
+ if (mprotect((LPVOID) StartBoundary, MemSize, PROT_NONE) != 0)
+ {
+ ASSERT("mprotect failed to protect the region!\n");
+ pthrCurrent->SetLastError(ERROR_INTERNAL_ERROR);
+ munmap((LPVOID) StartBoundary, MemSize);
+ bRetVal = FALSE;
+ goto VirtualFreeExit;
+ }
+#endif // MMAP_ANON_IGNORES_PROTECTION
+
+ SIZE_T index = 0;
+ SIZE_T nNumOfPagesToChange = 0;
+
+ /* We can now commit this memory by calling VirtualAlloc().*/
+ index = (StartBoundary - pUnCommittedMem->startBoundary) / VIRTUAL_PAGE_SIZE;
+
+ nNumOfPagesToChange = MemSize / VIRTUAL_PAGE_SIZE;
+ VIRTUALSetAllocState( MEM_RESERVE, index,
+ nNumOfPagesToChange, pUnCommittedMem );
+
+ goto VirtualFreeExit;
+ }
+ else
+ {
+ ASSERT( "mmap() returned an abnormal value.\n" );
+ bRetVal = FALSE;
+ pthrCurrent->SetLastError( ERROR_INTERNAL_ERROR );
+ goto VirtualFreeExit;
+ }
+ }
+
+ if ( dwFreeType & MEM_RELEASE )
+ {
+ PCMI pMemoryToBeReleased =
+ VIRTUALFindRegionInformation( (UINT_PTR)lpAddress );
+
+ if ( !pMemoryToBeReleased )
+ {
+ ERROR( "lpAddress must be the base address returned by VirtualAlloc.\n" );
+ pthrCurrent->SetLastError( ERROR_INVALID_ADDRESS );
+ bRetVal = FALSE;
+ goto VirtualFreeExit;
+ }
+ if ( dwSize != 0 )
+ {
+ ERROR( "dwSize must be 0 if you are releasing the memory.\n" );
+ pthrCurrent->SetLastError( ERROR_INVALID_PARAMETER );
+ bRetVal = FALSE;
+ goto VirtualFreeExit;
+ }
+
+ TRACE( "Releasing the following memory %d to %d.\n",
+ pMemoryToBeReleased->startBoundary, pMemoryToBeReleased->memSize );
+
+ if ( munmap( (LPVOID)pMemoryToBeReleased->startBoundary,
+ pMemoryToBeReleased->memSize ) == 0 )
+ {
+ if ( VIRTUALReleaseMemory( pMemoryToBeReleased ) == FALSE )
+ {
+ ASSERT( "Unable to remove the PCMI entry from the list.\n" );
+ pthrCurrent->SetLastError( ERROR_INTERNAL_ERROR );
+ bRetVal = FALSE;
+ goto VirtualFreeExit;
+ }
+ pMemoryToBeReleased = NULL;
+ }
+ else
+ {
+ ASSERT( "Unable to unmap the memory, munmap() returned an abnormal value.\n" );
+ pthrCurrent->SetLastError( ERROR_INTERNAL_ERROR );
+ bRetVal = FALSE;
+ goto VirtualFreeExit;
+ }
+ }
+
+VirtualFreeExit:
+
+ LogVaOperation(
+ (dwFreeType & MEM_DECOMMIT) ? VirtualMemoryLogging::VirtualOperation::Decommit
+ : VirtualMemoryLogging::VirtualOperation::Release,
+ lpAddress,
+ dwSize,
+ dwFreeType,
+ 0,
+ NULL,
+ bRetVal);
+
+ InternalLeaveCriticalSection(pthrCurrent, &virtual_critsec);
+ LOGEXIT( "VirtualFree returning %s.\n", bRetVal == TRUE ? "TRUE" : "FALSE" );
+ PERF_EXIT(VirtualFree);
+ return bRetVal;
+}
+
+
+/*++
+Function:
+ VirtualProtect
+
+See MSDN doc.
+--*/
+BOOL
+PALAPI
+VirtualProtect(
+ IN LPVOID lpAddress,
+ IN SIZE_T dwSize,
+ IN DWORD flNewProtect,
+ OUT PDWORD lpflOldProtect)
+{
+ BOOL bRetVal = FALSE;
+ PCMI pEntry = NULL;
+ SIZE_T MemSize = 0;
+ UINT_PTR StartBoundary = 0;
+ SIZE_T Index = 0;
+ SIZE_T NumberOfPagesToChange = 0;
+ SIZE_T OffSet = 0;
+ CPalThread * pthrCurrent;
+
+ PERF_ENTRY(VirtualProtect);
+ ENTRY("VirtualProtect(lpAddress=%p, dwSize=%u, flNewProtect=%#x, "
+ "flOldProtect=%p)\n",
+ lpAddress, dwSize, flNewProtect, lpflOldProtect);
+
+ pthrCurrent = InternalGetCurrentThread();
+ InternalEnterCriticalSection(pthrCurrent, &virtual_critsec);
+
+ StartBoundary = (UINT_PTR)lpAddress & ~VIRTUAL_PAGE_MASK;
+ MemSize = (((UINT_PTR)(dwSize) + ((UINT_PTR)(lpAddress) & VIRTUAL_PAGE_MASK)
+ + VIRTUAL_PAGE_MASK) & ~VIRTUAL_PAGE_MASK);
+
+ if ( VIRTUALContainsInvalidProtectionFlags( flNewProtect ) )
+ {
+ ASSERT( "flProtect can be one of PAGE_NOACCESS, PAGE_READONLY, "
+ "PAGE_READWRITE, PAGE_EXECUTE, PAGE_EXECUTE_READ "
+ ", or PAGE_EXECUTE_READWRITE. \n" );
+ SetLastError( ERROR_INVALID_PARAMETER );
+ goto ExitVirtualProtect;
+ }
+
+ if ( !lpflOldProtect)
+ {
+ ERROR( "lpflOldProtect was invalid.\n" );
+ SetLastError( ERROR_NOACCESS );
+ goto ExitVirtualProtect;
+ }
+
+ pEntry = VIRTUALFindRegionInformation( StartBoundary );
+ if ( NULL != pEntry )
+ {
+ /* See if the pages are committed. */
+ Index = OffSet = StartBoundary - pEntry->startBoundary == 0 ?
+ 0 : ( StartBoundary - pEntry->startBoundary ) / VIRTUAL_PAGE_SIZE;
+ NumberOfPagesToChange = MemSize / VIRTUAL_PAGE_SIZE;
+
+ TRACE( "Number of pages to check %d, starting page %d \n", NumberOfPagesToChange, Index );
+
+ for ( ; Index < NumberOfPagesToChange; Index++ )
+ {
+ if ( !VIRTUALIsPageCommitted( Index, pEntry ) )
+ {
+ ERROR( "You can only change the protection attributes"
+ " on committed memory.\n" )
+ SetLastError( ERROR_INVALID_ADDRESS );
+ goto ExitVirtualProtect;
+ }
+ }
+ }
+
+ if ( 0 == mprotect( (LPVOID)StartBoundary, MemSize,
+ W32toUnixAccessControl( flNewProtect ) ) )
+ {
+ /* Reset the access protection. */
+ TRACE( "Number of pages to change %d, starting page %d \n",
+ NumberOfPagesToChange, OffSet );
+ /*
+ * Set the old protection flags. We only use the first flag, so
+ * if there were several regions with each with different flags only the
+ * first region's protection flag will be returned.
+ */
+ if ( pEntry )
+ {
+ *lpflOldProtect =
+ VIRTUALConvertVirtualFlags( pEntry->pProtectionState[ OffSet ] );
+
+ memset( pEntry->pProtectionState + OffSet,
+ VIRTUALConvertWinFlags( flNewProtect ),
+ NumberOfPagesToChange );
+ }
+ else
+ {
+ *lpflOldProtect = PAGE_EXECUTE_READWRITE;
+ }
+ bRetVal = TRUE;
+ }
+ else
+ {
+ ERROR( "%s\n", strerror( errno ) );
+ if ( errno == EINVAL )
+ {
+ SetLastError( ERROR_INVALID_ADDRESS );
+ }
+ else if ( errno == EACCES )
+ {
+ SetLastError( ERROR_INVALID_ACCESS );
+ }
+ }
+ExitVirtualProtect:
+ InternalLeaveCriticalSection(pthrCurrent, &virtual_critsec);
+
+#if defined _DEBUG
+ VIRTUALDisplayList();
+#endif
+ LOGEXIT( "VirtualProtect returning %s.\n", bRetVal == TRUE ? "TRUE" : "FALSE" );
+ PERF_EXIT(VirtualProtect);
+ return bRetVal;
+}
+
+#if HAVE_VM_ALLOCATE
+//---------------------------------------------------------------------------------------
+//
+// Convert a vm_prot_t flag on the Mach kernel to the corresponding memory protection on Windows.
+//
+// Arguments:
+// protection - Mach protection to be converted
+//
+// Return Value:
+// Return the corresponding memory protection on Windows (e.g. PAGE_READ_WRITE, etc.)
+//
+
+static DWORD VirtualMapMachProtectToWinProtect(vm_prot_t protection)
+{
+ if (protection & VM_PROT_READ)
+ {
+ if (protection & VM_PROT_WRITE)
+ {
+ if (protection & VM_PROT_EXECUTE)
+ {
+ return PAGE_EXECUTE_READWRITE;
+ }
+ else
+ {
+ return PAGE_READWRITE;
+ }
+ }
+ else
+ {
+ if (protection & VM_PROT_EXECUTE)
+ {
+ return PAGE_EXECUTE_READ;
+ }
+ else
+ {
+ return PAGE_READONLY;
+ }
+ }
+ }
+ else
+ {
+ if (protection & VM_PROT_WRITE)
+ {
+ if (protection & VM_PROT_EXECUTE)
+ {
+ return PAGE_EXECUTE_WRITECOPY;
+ }
+ else
+ {
+ return PAGE_WRITECOPY;
+ }
+ }
+ else
+ {
+ if (protection & VM_PROT_EXECUTE)
+ {
+ return PAGE_EXECUTE;
+ }
+ else
+ {
+ return PAGE_NOACCESS;
+ }
+ }
+ }
+}
+
+static void VM_ALLOCATE_VirtualQuery(LPCVOID lpAddress, PMEMORY_BASIC_INFORMATION lpBuffer)
+{
+ kern_return_t MachRet;
+ vm_address_t vm_address;
+ vm_size_t vm_size;
+ vm_region_flavor_t vm_flavor;
+ mach_msg_type_number_t infoCnt;
+ mach_port_t object_name;
+#ifdef BIT64
+ vm_region_basic_info_data_64_t info;
+ infoCnt = VM_REGION_BASIC_INFO_COUNT_64;
+ vm_flavor = VM_REGION_BASIC_INFO_64;
+#else
+ vm_region_basic_info_data_t info;
+ infoCnt = VM_REGION_BASIC_INFO_COUNT;
+ vm_flavor = VM_REGION_BASIC_INFO;
+#endif
+
+ vm_address = (vm_address_t)lpAddress;
+#ifdef BIT64
+ MachRet = vm_region_64(
+#else
+ MachRet = vm_region(
+#endif
+ mach_task_self(),
+ &vm_address,
+ &vm_size,
+ vm_flavor,
+ (vm_region_info_t)&info,
+ &infoCnt,
+ &object_name);
+ if (MachRet != KERN_SUCCESS) {
+ return;
+ }
+
+ if (vm_address > (vm_address_t)lpAddress) {
+ /* lpAddress was pointing into a free region */
+ lpBuffer->State = MEM_FREE;
+ return;
+ }
+
+ lpBuffer->BaseAddress = (PVOID)vm_address;
+
+ // We don't actually have any information on the Mach kernel which maps to AllocationProtect.
+ lpBuffer->AllocationProtect = VM_PROT_NONE;
+
+ lpBuffer->RegionSize = (SIZE_T)vm_size;
+
+ if (info.reserved)
+ {
+ lpBuffer->State = MEM_RESERVE;
+ }
+ else
+ {
+ lpBuffer->State = MEM_COMMIT;
+ }
+
+ lpBuffer->Protect = VirtualMapMachProtectToWinProtect(info.protection);
+
+ /* Note that if a mapped region and a private region are adjacent, this
+ will return MEM_PRIVATE but the region size will span
+ both the mapped and private regions. */
+ if (!info.shared)
+ {
+ lpBuffer->Type = MEM_PRIVATE;
+ }
+ else
+ {
+ // What should this be? It's either MEM_MAPPED or MEM_IMAGE, but without an image list,
+ // we can't determine which one it is.
+ lpBuffer->Type = MEM_MAPPED;
+ }
+}
+#endif // HAVE_VM_ALLOCATE
+
+/*++
+Function:
+ VirtualQuery
+
+See MSDN doc.
+--*/
+SIZE_T
+PALAPI
+VirtualQuery(
+ IN LPCVOID lpAddress,
+ OUT PMEMORY_BASIC_INFORMATION lpBuffer,
+ IN SIZE_T dwLength)
+{
+ PCMI pEntry = NULL;
+ UINT_PTR StartBoundary = 0;
+ CPalThread * pthrCurrent;
+
+ PERF_ENTRY(VirtualQuery);
+ ENTRY("VirtualQuery(lpAddress=%p, lpBuffer=%p, dwLength=%u)\n",
+ lpAddress, lpBuffer, dwLength);
+
+ pthrCurrent = InternalGetCurrentThread();
+ InternalEnterCriticalSection(pthrCurrent, &virtual_critsec);
+
+ if ( !lpBuffer)
+ {
+ ERROR( "lpBuffer has to be a valid pointer.\n" );
+ pthrCurrent->SetLastError( ERROR_NOACCESS );
+ goto ExitVirtualQuery;
+ }
+ if ( dwLength < sizeof( *lpBuffer ) )
+ {
+ ERROR( "dwLength cannot be smaller then the size of *lpBuffer.\n" );
+ pthrCurrent->SetLastError( ERROR_BAD_LENGTH );
+ goto ExitVirtualQuery;
+ }
+
+ StartBoundary = (UINT_PTR)lpAddress & ~VIRTUAL_PAGE_MASK;
+
+#if MMAP_IGNORES_HINT
+ // Make sure we have memory to map before we try to query it.
+ VIRTUALGetBackingFile(pthrCurrent);
+
+ // If we're suballocating, claim that any memory that isn't in our
+ // suballocated block is already allocated. This keeps callers from
+ // using these results to try to allocate those blocks and failing.
+ if (StartBoundary < (UINT_PTR) gBackingBaseAddress ||
+ StartBoundary >= (UINT_PTR) gBackingBaseAddress + BACKING_FILE_SIZE)
+ {
+ if (StartBoundary < (UINT_PTR) gBackingBaseAddress)
+ {
+ lpBuffer->RegionSize = (UINT_PTR) gBackingBaseAddress - StartBoundary;
+ }
+ else
+ {
+ lpBuffer->RegionSize = -StartBoundary;
+ }
+ lpBuffer->BaseAddress = (void *) StartBoundary;
+ lpBuffer->State = MEM_COMMIT;
+ lpBuffer->Type = MEM_MAPPED;
+ lpBuffer->AllocationProtect = 0;
+ lpBuffer->Protect = 0;
+ goto ExitVirtualQuery;
+ }
+#endif // MMAP_IGNORES_HINT
+
+ /* Find the entry. */
+ pEntry = VIRTUALFindRegionInformation( StartBoundary );
+
+ if ( !pEntry )
+ {
+ /* Can't find a match, or no list present. */
+ /* Next, looking for this region in file maps */
+ if (!MAPGetRegionInfo((LPVOID)StartBoundary, lpBuffer))
+ {
+ // When all else fails, call vm_region() if it's available.
+
+ // Initialize the State to be MEM_FREE, in which case AllocationBase, AllocationProtect,
+ // Protect, and Type are all undefined.
+ lpBuffer->BaseAddress = (LPVOID)StartBoundary;
+ lpBuffer->RegionSize = 0;
+ lpBuffer->State = MEM_FREE;
+#if HAVE_VM_ALLOCATE
+ VM_ALLOCATE_VirtualQuery(lpAddress, lpBuffer);
+#endif
+ }
+ }
+ else
+ {
+ /* Starting page. */
+ SIZE_T Index = ( StartBoundary - pEntry->startBoundary ) / VIRTUAL_PAGE_SIZE;
+
+ /* Attributes to check for. */
+ BYTE AccessProtection = pEntry->pProtectionState[ Index ];
+ INT AllocationType = VIRTUALGetAllocationType( Index, pEntry );
+ SIZE_T RegionSize = 0;
+
+ TRACE( "Index = %d, Number of Pages = %d. \n",
+ Index, pEntry->memSize / VIRTUAL_PAGE_SIZE );
+
+ while ( Index < pEntry->memSize / VIRTUAL_PAGE_SIZE &&
+ VIRTUALGetAllocationType( Index, pEntry ) == AllocationType &&
+ pEntry->pProtectionState[ Index ] == AccessProtection )
+ {
+ RegionSize += VIRTUAL_PAGE_SIZE;
+ Index++;
+ }
+
+ TRACE( "RegionSize = %d.\n", RegionSize );
+
+ /* Fill the structure.*/
+ lpBuffer->AllocationProtect = pEntry->accessProtection;
+ lpBuffer->BaseAddress = (LPVOID)StartBoundary;
+
+ lpBuffer->Protect = AllocationType == MEM_COMMIT ?
+ VIRTUALConvertVirtualFlags( AccessProtection ) : 0;
+
+ lpBuffer->RegionSize = RegionSize;
+ lpBuffer->State =
+ ( AllocationType == MEM_COMMIT ? MEM_COMMIT : MEM_RESERVE );
+ WARN( "Ignoring lpBuffer->Type. \n" );
+ }
+
+ExitVirtualQuery:
+
+ InternalLeaveCriticalSection(pthrCurrent, &virtual_critsec);
+
+ LOGEXIT( "VirtualQuery returning %d.\n", sizeof( *lpBuffer ) );
+ PERF_EXIT(VirtualQuery);
+ return sizeof( *lpBuffer );
+}
+
+/*++
+Function:
+ GetWriteWatch
+
+See MSDN doc.
+--*/
+UINT
+PALAPI
+GetWriteWatch(
+ IN DWORD dwFlags,
+ IN PVOID lpBaseAddress,
+ IN SIZE_T dwRegionSize,
+ OUT PVOID *lpAddresses,
+ IN OUT PULONG_PTR lpdwCount,
+ OUT PULONG lpdwGranularity
+)
+{
+ // TODO: implement this method
+ *lpAddresses = NULL;
+ *lpdwCount = 0;
+ // Until it is implemented, return non-zero value as an indicator of failure
+ return 1;
+}
+
+/*++
+Function:
+ ResetWriteWatch
+
+See MSDN doc.
+--*/
+UINT
+PALAPI
+ResetWriteWatch(
+ IN LPVOID lpBaseAddress,
+ IN SIZE_T dwRegionSize
+)
+{
+ // TODO: implement this method
+ // Until it is implemented, return non-zero value as an indicator of failure
+ return 1;
+}
+
+/*++
+Function :
+ ReserveMemoryFromExecutableAllocator
+
+ This function is used to reserve a region of virual memory (not commited)
+ that is located close to the coreclr library. The memory comes from the virtual
+ address range that is managed by ExecutableMemoryAllocator.
+--*/
+void* ReserveMemoryFromExecutableAllocator(CPalThread* pThread, SIZE_T allocationSize)
+{
+ InternalEnterCriticalSection(pThread, &virtual_critsec);
+ void* mem = g_executableMemoryAllocator.AllocateMemory(allocationSize);
+ InternalLeaveCriticalSection(pThread, &virtual_critsec);
+
+ return mem;
+}
+
+/*++
+Function:
+ ExecutableMemoryAllocator::Initialize()
+
+ This function initializes the allocator. It should be called early during process startup
+ (when process address space is pretty much empty) in order to have a chance to reserve
+ sufficient amount of memory that is close to the coreclr library.
+
+--*/
+void ExecutableMemoryAllocator::Initialize()
+{
+ m_startAddress = NULL;
+ m_nextFreeAddress = NULL;
+ m_totalSizeOfReservedMemory = 0;
+ m_remainingReservedMemory = 0;
+
+ // Enable the executable memory allocator on 64-bit platforms only
+ // because 32-bit platforms have limited amount of virtual address space.
+#ifdef BIT64
+ TryReserveInitialMemory();
+#endif // BIT64
+
+}
+
+/*++
+Function:
+ ExecutableMemoryAllocator::TryReserveInitialMemory()
+
+ This function is called during PAL initialization. It opportunistically tries to reserve
+ a large chunk of virtual memory that can be later used to store JIT'ed code.\
+
+--*/
+void ExecutableMemoryAllocator::TryReserveInitialMemory()
+{
+ CPalThread* pthrCurrent = InternalGetCurrentThread();
+ int32_t sizeOfAllocation = MaxExecutableMemorySize;
+ int32_t startAddressIncrement;
+ UINT_PTR startAddress;
+ UINT_PTR coreclrLoadAddress;
+ const int32_t MemoryProbingIncrement = 128 * 1024 * 1024;
+
+ // Try to find and reserve an available region of virtual memory that is located
+ // within 2GB range (defined by the MaxExecutableMemorySize constant) from the
+ // location of the coreclr library.
+ // Potentially, as a possible future improvement, we can get precise information
+ // about available memory ranges by parsing data from '/proc/self/maps'.
+ // But since this code is called early during process startup, the user address space
+ // is pretty much empty so the simple algorithm that is implemented below is sufficient
+ // for this purpose.
+
+ // First of all, we need to determine the current address of libcoreclr. Please note that depending on
+ // the OS implementation, the library is usually loaded either at the end or at the start of the user
+ // address space. If the library is loaded at low addresses then try to reserve memory above libcoreclr
+ // (thus avoiding reserving memory below 4GB; besides some operating systems do not allow that).
+ // If libcoreclr is loaded at high addresses then try to reserve memory below its location.
+ coreclrLoadAddress = (UINT_PTR)PAL_GetSymbolModuleBase((void*)VirtualAlloc);
+ if ((coreclrLoadAddress < 0xFFFFFFFF) || ((coreclrLoadAddress - MaxExecutableMemorySize) < 0xFFFFFFFF))
+ {
+ // Try to allocate above the location of libcoreclr
+ startAddress = coreclrLoadAddress + CoreClrLibrarySize;
+ startAddressIncrement = MemoryProbingIncrement;
+ }
+ else
+ {
+ // Try to allocate below the location of libcoreclr
+ startAddress = coreclrLoadAddress - MaxExecutableMemorySize;
+ startAddressIncrement = 0;
+ }
+
+ // Do actual memory reservation.
+ do
+ {
+ m_startAddress = ReserveVirtualMemory(pthrCurrent, (void*)startAddress, sizeOfAllocation);
+ if (m_startAddress != NULL)
+ {
+ // Memory has been successfully reserved.
+ m_totalSizeOfReservedMemory = sizeOfAllocation;
+
+ // Randomize the location at which we start allocating from the reserved memory range.
+ int32_t randomOffset = GenerateRandomStartOffset();
+ m_nextFreeAddress = (void*)(((UINT_PTR)m_startAddress) + randomOffset);
+ m_remainingReservedMemory = sizeOfAllocation - randomOffset;
+ break;
+ }
+
+ // Try to allocate a smaller region
+ sizeOfAllocation -= MemoryProbingIncrement;
+ startAddress += startAddressIncrement;
+
+ } while (sizeOfAllocation >= MemoryProbingIncrement);
+}
+
+/*++
+Function:
+ ExecutableMemoryAllocator::AllocateMemory
+
+ This function attempts to allocate the requested amount of memory from its reserved virtual
+ address space. The function will return NULL if the allocation request cannot
+ be satisfied by the memory that is currently available in the allocator.
+
+ Note: This function MUST be called with the virtual_critsec lock held.
+
+--*/
+void* ExecutableMemoryAllocator::AllocateMemory(SIZE_T allocationSize)
+{
+ void* allocatedMemory = NULL;
+
+ // Allocation size must be in multiples of the virtual page size.
+ _ASSERTE((allocationSize & VIRTUAL_PAGE_MASK) == 0);
+
+ // The code below assumes that the caller owns the virtual_critsec lock.
+ // So the calculations are not done in thread-safe manner.
+ if ((allocationSize > 0) && (allocationSize <= m_remainingReservedMemory))
+ {
+ allocatedMemory = m_nextFreeAddress;
+ m_nextFreeAddress = (void*)(((UINT_PTR)m_nextFreeAddress) + allocationSize);
+ m_remainingReservedMemory -= allocationSize;
+
+ }
+
+ return allocatedMemory;
+}
+
+/*++
+Function:
+ ExecutableMemoryAllocator::GenerateRandomStartOffset()
+
+ This function returns a random offset (in multiples of the virtual page size)
+ at which the allocator should start allocating memory from its reserved memory range.
+
+--*/
+int32_t ExecutableMemoryAllocator::GenerateRandomStartOffset()
+{
+ int32_t pageCount;
+ const int32_t MaxStartPageOffset = 64;
+
+ // This code is similar to what coreclr runtime does on Windows.
+ // It generates a random number of pages to skip between 0...MaxStartPageOffset.
+ srandom(time(NULL));
+ pageCount = (int32_t)(MaxStartPageOffset * (int64_t)random() / RAND_MAX);
+
+ return pageCount * VIRTUAL_PAGE_SIZE;
+}
diff --git a/src/pal/src/memory/heap.cpp b/src/pal/src/memory/heap.cpp
new file mode 100644
index 0000000000..5757da83b7
--- /dev/null
+++ b/src/pal/src/memory/heap.cpp
@@ -0,0 +1,389 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ heap.c
+
+Abstract:
+
+ Implementation of heap memory management functions.
+
+Revision History:
+
+
+
+--*/
+
+#include "pal/palinternal.h"
+#include "pal/dbgmsg.h"
+#include "pal/handlemgr.hpp"
+#include "pal/corunix.hpp"
+#include <errno.h>
+using namespace CorUnix;
+
+SET_DEFAULT_DEBUG_CHANNEL(MEM);
+
+// In safemath.h, Template SafeInt uses macro _ASSERTE, which need to use variable
+// defdbgchan defined by SET_DEFAULT_DEBUG_CHANNEL. Therefore, the include statement
+// should be placed after the SET_DEFAULT_DEBUG_CHANNEL(MEM)
+#include <safemath.h>
+
+#ifndef __APPLE__
+#define DUMMY_HEAP 0x01020304
+#endif // __APPLE__
+
+/*++
+Function:
+ RtlMoveMemory
+
+See MSDN doc.
+--*/
+VOID
+PALAPI
+RtlMoveMemory(
+ IN PVOID Destination,
+ IN CONST VOID *Source,
+ IN SIZE_T Length)
+{
+ PERF_ENTRY(RtlMoveMemory);
+ ENTRY("RtlMoveMemory(Destination:%p, Source:%p, Length:%d)\n",
+ Destination, Source, Length);
+
+ memmove(Destination, Source, Length);
+
+ LOGEXIT("RtlMoveMemory returning\n");
+ PERF_EXIT(RtlMoveMemory);
+}
+
+/*++
+Function:
+ RtlZeroMemory
+
+See MSDN doc.
+--*/
+VOID
+PALAPI
+RtlZeroMemory(
+ PVOID Destination,
+ SIZE_T Length
+)
+{
+ PERF_ENTRY(RtlZeroMemory);
+ ENTRY("RtlZeroMemory(Destination:%p, Length:%x)\n", Destination, Length);
+
+ memset(Destination, 0, Length);
+
+ LOGEXIT("RtlZeroMemory returning.\n");
+ PERF_EXIT(RtlZeroMemory);
+}
+
+/*++
+Function:
+ HeapCreate
+
+See MSDN doc.
+--*/
+HANDLE
+PALAPI
+HeapCreate(
+ IN DWORD flOptions,
+ IN SIZE_T dwInitialSize,
+ IN SIZE_T dwMaximumSize)
+{
+ HANDLE ret = INVALID_HANDLE_VALUE;
+ PERF_ENTRY(HeapCreate);
+ ENTRY("HeapCreate(flOptions=%#x, dwInitialSize=%u, dwMaximumSize=%u)\n",
+ flOptions, dwInitialSize, dwMaximumSize);
+#ifdef __APPLE__
+ if ((flOptions & 0x40005) != 0)
+ {
+ ERROR("Invalid flOptions\n");
+ SetLastError(ERROR_INVALID_PARAMETER);
+ }
+ else if (flOptions != 0)
+ {
+ ERROR("No support for flOptions\n");
+ SetLastError(ERROR_INVALID_PARAMETER);
+ }
+ else if (dwMaximumSize)
+ {
+ ERROR("Zone implementation does not support a max size\n");
+ SetLastError(ERROR_INVALID_PARAMETER);
+ }
+ else
+ {
+ ret = (HANDLE)malloc_create_zone(dwInitialSize, 0 /* flags */);
+ }
+
+#else // __APPLE__
+ ret = (HANDLE)DUMMY_HEAP;
+#endif // __APPLE__
+
+ LOGEXIT("HeapCreate returning HANDLE %p\n", ret);
+ PERF_EXIT(HeapCreate);
+ return ret;
+}
+
+
+/*++
+Function:
+ GetProcessHeap
+
+See MSDN doc.
+--*/
+HANDLE
+PALAPI
+GetProcessHeap(
+ VOID)
+{
+ HANDLE ret;
+
+ PERF_ENTRY(GetProcessHeap);
+ ENTRY("GetProcessHeap()\n");
+
+#ifdef __APPLE__
+#if HEAP_HANDLES_ARE_REAL_HANDLES
+#error
+#else
+ malloc_zone_t *pZone = malloc_default_zone();
+ ret = (HANDLE)pZone;
+#endif // HEAP_HANDLES_ARE_REAL_HANDLES
+#else
+ ret = (HANDLE) DUMMY_HEAP;
+#endif
+
+ LOGEXIT("GetProcessHeap returning HANDLE %p\n", ret);
+ PERF_EXIT(GetProcessHeap);
+ return ret;
+}
+
+/*++
+Function:
+ HeapAlloc
+
+Abstract
+ Implemented as wrapper over malloc
+
+See MSDN doc.
+--*/
+LPVOID
+PALAPI
+HeapAlloc(
+ IN HANDLE hHeap,
+ IN DWORD dwFlags,
+ IN SIZE_T numberOfBytes)
+{
+ BYTE *pMem;
+
+ PERF_ENTRY(HeapAlloc);
+ ENTRY("HeapAlloc (hHeap=%p, dwFlags=%#x, numberOfBytes=%u)\n",
+ hHeap, dwFlags, numberOfBytes);
+
+#ifdef __APPLE__
+ if (hHeap == NULL)
+#else // __APPLE__
+ if (hHeap != (HANDLE) DUMMY_HEAP)
+#endif // __APPLE__ else
+ {
+ ERROR("Invalid heap handle\n");
+ SetLastError(ERROR_INVALID_PARAMETER);
+ LOGEXIT("HeapAlloc returning NULL\n");
+ PERF_EXIT(HeapAlloc);
+ return NULL;
+ }
+
+ if ((dwFlags != 0) && (dwFlags != HEAP_ZERO_MEMORY))
+ {
+ ASSERT("Invalid parameter dwFlags=%#x\n", dwFlags);
+ SetLastError(ERROR_INVALID_PARAMETER);
+ LOGEXIT("HeapAlloc returning NULL\n");
+ PERF_EXIT(HeapAlloc);
+ return NULL;
+ }
+
+#ifdef __APPLE__
+ // This is patterned off of InternalMalloc in malloc.cpp.
+ {
+ pMem = (BYTE *)malloc_zone_malloc((malloc_zone_t *)hHeap, numberOfBytes);
+ }
+#else // __APPLE__
+ pMem = (BYTE *) PAL_malloc(numberOfBytes);
+#endif // __APPLE__ else
+
+ if (pMem == NULL)
+ {
+ ERROR("Not enough memory\n");
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ LOGEXIT("HeapAlloc returning NULL\n");
+ PERF_EXIT(HeapAlloc);
+ return NULL;
+ }
+
+ /* If the HEAP_ZERO_MEMORY flag is set initialize to zero */
+ if (dwFlags == HEAP_ZERO_MEMORY)
+ {
+ memset(pMem, 0, numberOfBytes);
+ }
+
+ LOGEXIT("HeapAlloc returning LPVOID %p\n", pMem);
+ PERF_EXIT(HeapAlloc);
+ return (pMem);
+}
+
+
+/*++
+Function:
+ HeapFree
+
+Abstract
+ Implemented as wrapper over free
+
+See MSDN doc.
+--*/
+BOOL
+PALAPI
+HeapFree(
+ IN HANDLE hHeap,
+ IN DWORD dwFlags,
+ IN LPVOID lpMem)
+{
+ BOOL bRetVal = FALSE;
+
+ PERF_ENTRY(HeapFree);
+ ENTRY("HeapFree (hHeap=%p, dwFlags = %#x, lpMem=%p)\n",
+ hHeap, dwFlags, lpMem);
+
+#ifdef __APPLE__
+ if (hHeap == NULL)
+#else // __APPLE__
+ if (hHeap != (HANDLE) DUMMY_HEAP)
+#endif // __APPLE__ else
+ {
+ ERROR("Invalid heap handle\n");
+ SetLastError(ERROR_INVALID_PARAMETER);
+ goto done;
+ }
+
+ if (dwFlags != 0)
+ {
+ ASSERT("Invalid parameter dwFlags=%#x\n", dwFlags);
+ SetLastError(ERROR_INVALID_PARAMETER);
+ goto done;
+ }
+
+ if (!lpMem)
+ {
+ bRetVal = TRUE;
+ goto done;
+ }
+
+ bRetVal = TRUE;
+#ifdef __APPLE__
+ {
+ malloc_zone_free((malloc_zone_t *)hHeap, lpMem);
+ }
+#else // __APPLE__
+ PAL_free (lpMem);
+#endif // __APPLE__ else
+
+done:
+ LOGEXIT( "HeapFree returning BOOL %d\n", bRetVal );
+ PERF_EXIT(HeapFree);
+ return bRetVal;
+}
+
+
+/*++
+Function:
+ HeapReAlloc
+
+Abstract
+ Implemented as wrapper over realloc
+
+See MSDN doc.
+--*/
+LPVOID
+PALAPI
+HeapReAlloc(
+ IN HANDLE hHeap,
+ IN DWORD dwFlags,
+ IN LPVOID lpmem,
+ IN SIZE_T numberOfBytes)
+{
+ BYTE *pMem = NULL;
+
+ PERF_ENTRY(HeapReAlloc);
+ ENTRY("HeapReAlloc (hHeap=%p, dwFlags=%#x, lpmem=%p, numberOfBytes=%u)\n",
+ hHeap, dwFlags, lpmem, numberOfBytes);
+
+#ifdef __APPLE__
+ if (hHeap == NULL)
+#else // __APPLE__
+ if (hHeap != (HANDLE)DUMMY_HEAP)
+#endif // __APPLE__ else
+ {
+ ASSERT("Invalid heap handle\n");
+ SetLastError(ERROR_INVALID_HANDLE);
+ goto done;
+ }
+
+ if ((dwFlags != 0))
+ {
+ ASSERT("Invalid parameter dwFlags=%#x\n", dwFlags);
+ SetLastError(ERROR_INVALID_PARAMETER);
+ goto done;
+ }
+
+ if (lpmem == NULL)
+ {
+ WARN("NULL memory pointer to realloc. Do not do anything.\n");
+ /* set LastError back to zero. this appears to be an undocumented
+ behavior in Windows, in doesn't cost much to match it */
+ SetLastError(0);
+ goto done;
+ }
+
+ if(numberOfBytes == 0)
+ {
+ // PAL's realloc behaves like free for a requested size of zero bytes. Force a nonzero size to get a valid pointer.
+ numberOfBytes = 1;
+ }
+
+#ifdef __APPLE__
+ // This is patterned off of InternalRealloc in malloc.cpp.
+ {
+ pMem = (BYTE *) malloc_zone_realloc((malloc_zone_t *)hHeap, lpmem, numberOfBytes);
+ }
+#else // __APPLE__
+ pMem = (BYTE *) PAL_realloc(lpmem, numberOfBytes);
+#endif // __APPLE__ else
+
+ if (pMem == NULL)
+ {
+ ERROR("Not enough memory\n");
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ goto done;
+ }
+
+done:
+ LOGEXIT("HeapReAlloc returns LPVOID %p\n", pMem);
+ PERF_EXIT(HeapReAlloc);
+ return pMem;
+}
+
+BOOL
+PALAPI
+HeapSetInformation(
+ IN OPTIONAL HANDLE HeapHandle,
+ IN HEAP_INFORMATION_CLASS HeapInformationClass,
+ IN PVOID HeapInformation,
+ IN SIZE_T HeapInformationLength)
+{
+ return TRUE;
+}
diff --git a/src/pal/src/memory/local.cpp b/src/pal/src/memory/local.cpp
new file mode 100644
index 0000000000..3a0f40f8c4
--- /dev/null
+++ b/src/pal/src/memory/local.cpp
@@ -0,0 +1,141 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ local.c
+
+Abstract:
+
+ Implementation of local memory management functions.
+
+Revision History:
+
+
+
+--*/
+
+#include "pal/palinternal.h"
+#include "pal/dbgmsg.h"
+
+
+SET_DEFAULT_DEBUG_CHANNEL(MEM);
+
+static
+int
+AllocFlagsToHeapAllocFlags (IN UINT AllocFlags,
+ OUT PUINT pHeapallocFlags)
+{
+ int success = 1;
+ UINT newFlags = 0, flags = AllocFlags;
+ if (flags & LMEM_ZEROINIT) {
+ newFlags |= HEAP_ZERO_MEMORY;
+ flags &= ~LMEM_ZEROINIT;
+ }
+ if (flags != 0) {
+ ASSERT("Invalid parameter AllocFlags=0x%x\n", AllocFlags);
+ SetLastError(ERROR_INVALID_PARAMETER);
+ success = 0;
+ }
+ if (success) {
+ *pHeapallocFlags = newFlags;
+ }
+ return success;
+}
+
+
+
+/*++
+Function:
+ LocalAlloc
+
+See MSDN doc.
+--*/
+HLOCAL
+PALAPI
+LocalAlloc(
+ IN UINT uFlags,
+ IN SIZE_T uBytes)
+{
+ LPVOID lpRetVal = NULL;
+ PERF_ENTRY(LocalAlloc);
+ ENTRY("LocalAlloc (uFlags=%#x, uBytes=%u)\n", uFlags, uBytes);
+
+ if (!AllocFlagsToHeapAllocFlags (uFlags, &uFlags)) {
+ goto done;
+ }
+
+ lpRetVal = HeapAlloc( GetProcessHeap(), uFlags, uBytes );
+
+done:
+ LOGEXIT( "LocalAlloc returning %p.\n", lpRetVal );
+ PERF_EXIT(LocalAlloc);
+ return (HLOCAL) lpRetVal;
+}
+
+/*++
+Function:
+LocalReAlloc
+
+See MSDN doc.
+--*/
+HLOCAL
+PALAPI
+LocalReAlloc(
+ IN HLOCAL hMem,
+ IN SIZE_T uBytes,
+ IN UINT uFlags)
+{
+ LPVOID lpRetVal = NULL;
+ PERF_ENTRY(LocalReAlloc);
+ ENTRY("LocalReAlloc (hMem=%p, uBytes=%u, uFlags=%#x)\n", hMem, uBytes, uFlags);
+
+ if (uFlags != LMEM_MOVEABLE) {
+ // Currently valid iff uFlags is LMEM_MOVEABLE
+ ASSERT("Invalid parameter uFlags=0x%x\n", uFlags);
+ SetLastError(ERROR_INVALID_PARAMETER);
+ goto done;
+ }
+ uFlags = 0;
+
+ lpRetVal = HeapReAlloc(GetProcessHeap(), uFlags, hMem, uBytes);
+
+done:
+ LOGEXIT("LocalReAlloc returning %p.\n", lpRetVal);
+ PERF_EXIT(LocalReAlloc);
+ return (HLOCAL)lpRetVal;
+}
+
+/*++
+Function:
+ LocalFree
+
+See MSDN doc.
+--*/
+HLOCAL
+PALAPI
+LocalFree(
+ IN HLOCAL hMem)
+{
+ BOOL bRetVal = FALSE;
+ PERF_ENTRY(LocalFree);
+ ENTRY("LocalFree (hmem=%p)\n", hMem);
+
+ if ( hMem )
+ {
+ bRetVal = HeapFree( GetProcessHeap(), 0, hMem );
+ }
+ else
+ {
+ bRetVal = TRUE;
+ }
+
+ LOGEXIT( "LocalFree returning %p.\n", bRetVal == TRUE ? (HLOCAL)NULL : hMem );
+ PERF_EXIT(LocalFree);
+ return bRetVal == TRUE ? (HLOCAL)NULL : hMem;
+}
diff --git a/src/pal/src/misc/dbgmsg.cpp b/src/pal/src/misc/dbgmsg.cpp
new file mode 100644
index 0000000000..488e61494e
--- /dev/null
+++ b/src/pal/src/misc/dbgmsg.cpp
@@ -0,0 +1,968 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ misc/dbgmsg.cpp
+
+Abstract:
+ Implementation of Debug Message utilies. Relay channel information,
+ output functions, etc.
+
+
+
+--*/
+
+/* PAL headers */
+
+#include "pal/thread.hpp"
+#include "pal/malloc.hpp"
+#include "pal/file.hpp"
+
+#include "config.h"
+#include "pal/dbgmsg.h"
+#include "pal/cruntime.h"
+#include "pal/critsect.h"
+#include "pal/file.h"
+#include "pal/environ.h"
+
+/* standard headers */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h> /* for pthread_self */
+#include <errno.h>
+#include <dirent.h>
+#include <dlfcn.h>
+
+/* <stdarg.h> needs to be included after "palinternal.h" to avoid name
+ collision for va_start and va_end */
+#include <stdarg.h>
+
+using namespace CorUnix;
+
+/* append mode file I/O is safer */
+#define _PAL_APPEND_DBG_OUTPUT_
+
+#if defined(_PAL_APPEND_DBG_OUTPUT_)
+static const char FOPEN_FLAGS[] = "at";
+#else
+static const char FOPEN_FLAGS[] = "wt";
+#endif
+
+/* number of ENTRY nesting levels to indicate with a '.' */
+#define MAX_NESTING 50
+
+/* size of output buffer (arbitrary) */
+#define DBG_BUFFER_SIZE 20000
+
+/* global and static variables */
+
+LPCWSTR W16_NULLSTRING = (LPCWSTR) "N\0U\0L\0L\0\0";
+
+DWORD dbg_channel_flags[DCI_LAST];
+BOOL g_Dbg_asserts_enabled;
+
+/* we must use stdio functions directly rather that rely on PAL functions for
+ output, because those functions do tracing and we need to avoid recursion */
+FILE *output_file = NULL;
+
+/* master switch for debug channel enablement, to be modified by debugger */
+Volatile<BOOL> dbg_master_switch = TRUE;
+
+
+static const char *dbg_channel_names[]=
+{
+ "PAL",
+ "LOADER",
+ "HANDLE",
+ "SHMEM",
+ "PROCESS",
+ "THREAD",
+ "EXCEPT",
+ "CRT",
+ "UNICODE",
+ "ARCH",
+ "SYNC",
+ "FILE",
+ "VIRTUAL",
+ "MEM",
+ "SOCKET",
+ "DEBUG",
+ "LOCALE",
+ "MISC",
+ "MUTEX",
+ "CRITSEC",
+ "POLL",
+ "CRYPT",
+ "SHFOLDER"
+#ifdef FEATURE_PAL_SXS
+ , "SXS"
+#endif // FEATURE_PAL_SXS
+};
+
+static const char *dbg_level_names[]=
+{
+ "ENTRY",
+ "TRACE",
+ "WARN",
+ "ERROR",
+ "ASSERT",
+ "EXIT"
+};
+
+static const char ENV_FILE[]="PAL_API_TRACING";
+static const char ENV_CHANNELS[]="PAL_DBG_CHANNELS";
+static const char ENV_ASSERTS[]="PAL_DISABLE_ASSERTS";
+static const char ENV_ENTRY_LEVELS[]="PAL_API_LEVELS";
+
+/* per-thread storage for ENTRY tracing level */
+static pthread_key_t entry_level_key;
+
+/* entry level limitation */
+static int max_entry_level;
+
+/* character to use for ENTRY indentation */
+static const char INDENT_CHAR = '.';
+
+static BOOL DBG_get_indent(DBG_LEVEL_ID level, const char *format,
+ char *indent_string);
+
+static CRITICAL_SECTION fprintf_crit_section;
+
+/* Function definitions */
+
+/*++
+Function :
+ DBG_init_channels
+
+ Parse environment variables PAL_DBG_CHANNELS and PAL_API_TRACING for debug
+ channel settings; initialize static variables.
+
+ (no parameters, no return value)
+--*/
+BOOL DBG_init_channels(void)
+{
+ INT i;
+ LPSTR env_string;
+ LPSTR env_workstring;
+ LPSTR env_pcache;
+ LPSTR entry_ptr;
+ LPSTR level_ptr;
+ CHAR plus_or_minus;
+ DWORD flag_mask = 0;
+ int ret;
+
+ InternalInitializeCriticalSection(&fprintf_crit_section);
+
+ /* output only asserts by default [only affects no-vararg-support case; if
+ we have varargs, these flags aren't even checked for ASSERTs] */
+ for(i=0;i<DCI_LAST;i++)
+ dbg_channel_flags[i]=1<<DLI_ASSERT;
+
+ /* parse PAL_DBG_CHANNELS environment variable */
+
+ env_string = EnvironGetenv(ENV_CHANNELS);
+ env_pcache = env_workstring = env_string;
+
+ while(env_workstring)
+ {
+ entry_ptr=env_workstring;
+
+ /* find beginning of next entry */
+ while((*entry_ptr != '\0') &&(*entry_ptr != '+') && (*entry_ptr != '-'))
+ {
+ entry_ptr++;
+ }
+
+ /* break if end of string is reached */
+ if(*entry_ptr == '\0')
+ {
+ break;
+ }
+
+ plus_or_minus=*entry_ptr++;
+
+ /* find end of entry; if strchr returns NULL, we have reached the end
+ of the string and we will leave the loop at the end of this pass. */
+ env_workstring=strchr(entry_ptr,':');
+
+ /* NULL-terminate entry, make env_string point to rest of string */
+ if(env_workstring)
+ {
+ *env_workstring++='\0';
+ }
+
+ /* find period that separates channel name from level name */
+ level_ptr=strchr(entry_ptr,'.');
+
+ /* an entry with no period is illegal : ignore it */
+ if(!level_ptr)
+ {
+ continue;
+ }
+ /* NULL-terminate channel name, make level_ptr point to the level name */
+ *level_ptr++='\0';
+
+ /* build the flag mask based on requested level */
+
+ /* if "all" level is specified, we want to open/close all levels at
+ once, so mask is either all ones or all zeroes */
+ if(!strcmp(level_ptr,"all"))
+ {
+ if(plus_or_minus=='+')
+ {
+ flag_mask=0xFFFF; /* OR this to open all levels */
+ }
+ else
+ {
+ flag_mask=0; /* AND this to close all levels*/
+ }
+ }
+ else
+ {
+ for(i=0;i<DLI_LAST;i++)
+ {
+ if(!strcmp(level_ptr,dbg_level_names[i]))
+ {
+ if(plus_or_minus=='+')
+ {
+ flag_mask=1<<i; /* OR this to open the level */
+ }
+ else
+ {
+ flag_mask=~(1<<i); /* AND this to close the level */
+ }
+ break;
+ }
+ }
+ /* didn't find a matching level : skip it. */
+ if(i==DLI_LAST)
+ {
+ continue;
+ }
+ }
+
+ /* Set EXIT and ENTRY channels to be identical */
+ if(!(flag_mask & (1<<DLI_ENTRY)))
+ {
+ flag_mask = flag_mask & (~(1<<DLI_EXIT));
+ }
+ else
+ {
+ flag_mask = flag_mask | (1<<DLI_EXIT);
+ }
+
+ /* apply the flag mask to the specified channel */
+
+ /* if "all" channel is specified, apply mask to all channels */
+ if(!strcmp(entry_ptr,"all"))
+ {
+ if(plus_or_minus=='+')
+ {
+ for(i=0;i<DCI_LAST;i++)
+ {
+ dbg_channel_flags[i] |= flag_mask; /* OR to open levels*/
+ }
+ }
+ else
+ {
+ for(i=0;i<DCI_LAST;i++)
+ {
+ dbg_channel_flags[i] &= flag_mask; /* AND to close levels */
+ }
+ }
+ }
+ else
+ {
+ for(i=0;i<DCI_LAST;i++)
+ {
+ if(!strcmp(entry_ptr,dbg_channel_names[i]))
+ {
+ if(plus_or_minus=='+')
+ {
+ dbg_channel_flags[i] |= flag_mask;
+ }
+ else
+ {
+ dbg_channel_flags[i] &= flag_mask;
+ }
+
+ break;
+ }
+ }
+ /* ignore the entry if the channel name is unknown */
+ }
+ /* done processing this entry; on to the next. */
+ }
+ PAL_free(env_pcache);
+
+ /* select output file */
+ env_string = EnvironGetenv(ENV_FILE);
+ if(env_string && *env_string!='\0')
+ {
+ if(!strcmp(env_string, "stderr"))
+ {
+ output_file = stderr;
+ }
+ else if(!strcmp(env_string, "stdout"))
+ {
+ output_file = stdout;
+ }
+ else
+ {
+ output_file = fopen(env_string,FOPEN_FLAGS);
+
+ /* if file can't be opened, default to stderr */
+ if(!output_file)
+ {
+ output_file = stderr;
+ fprintf(stderr, "Can't open %s for writing : debug messages "
+ "will go to stderr. Check your PAL_API_TRACING "
+ "variable!\n", env_string);
+ }
+ }
+ }
+ else
+ {
+ output_file = stderr; /* output to stderr by default */
+ }
+
+ if(env_string)
+ {
+ PAL_free(env_string);
+ }
+
+ /* see if we need to disable assertions */
+ env_string = EnvironGetenv(ENV_ASSERTS);
+ if(env_string && 0 == strcmp(env_string,"1"))
+ {
+ g_Dbg_asserts_enabled = FALSE;
+ }
+ else
+ {
+ g_Dbg_asserts_enabled = TRUE;
+ }
+
+ if(env_string)
+ {
+ PAL_free(env_string);
+ }
+
+ /* select ENTRY level limitation */
+ env_string = EnvironGetenv(ENV_ENTRY_LEVELS);
+ if(env_string)
+ {
+ max_entry_level = atoi(env_string);
+ PAL_free(env_string);
+ }
+ else
+ {
+ max_entry_level = 1;
+ }
+
+ /* if necessary, allocate TLS key for entry nesting level */
+ if(0 != max_entry_level)
+ {
+ if ((ret = pthread_key_create(&entry_level_key,NULL)) != 0)
+ {
+ fprintf(stderr, "ERROR : pthread_key_create() failed error:%d (%s)\n",
+ ret, strerror(ret));
+ DeleteCriticalSection(&fprintf_crit_section);;
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+/*++
+Function :
+ DBG_close_channels
+
+ Stop outputting debug messages by closing the associated file.
+
+ (no parameters, no return value)
+--*/
+void DBG_close_channels()
+{
+ if(output_file && output_file != stderr && output_file != stdout)
+ {
+ if (fclose(output_file) != 0)
+ {
+ fprintf(stderr, "ERROR : fclose() failed errno:%d (%s)\n",
+ errno, strerror(errno));
+ }
+ }
+
+ output_file = NULL;
+
+ DeleteCriticalSection(&fprintf_crit_section);
+
+ /* if necessary, release TLS key for entry nesting level */
+ if(0 != max_entry_level)
+ {
+ int retval;
+
+ retval = pthread_key_delete(entry_level_key);
+ if(0 != retval)
+ {
+ fprintf(stderr, "ERROR : pthread_key_delete() returned %d! (%s)\n",
+ retval, strerror(retval));
+ }
+ }
+}
+
+
+#ifdef FEATURE_PAL_SXS
+static const void *DBG_get_module_id()
+{
+ static const void *s_module_id = NULL;
+ if (s_module_id == NULL)
+ {
+ Dl_info dl_info;
+ if (dladdr((void *) DBG_get_module_id, &dl_info) == 0 || dl_info.dli_sname == NULL)
+ {
+ s_module_id = (void *) -1;
+ }
+ else
+ {
+ s_module_id = dl_info.dli_fbase;
+ }
+ }
+ return s_module_id;
+}
+
+#define MODULE_ID DBG_get_module_id,
+#define MODULE_FORMAT "-%p"
+#else
+#define MODULE_ID
+#define MODULE_FORMAT
+#endif // FEATURE_PAL_SXS
+
+
+/*++
+Function :
+ DBG_printf_gcc
+
+ Internal function for debug channels; don't use.
+ This function outputs a complete debug message, including the function name.
+
+Parameters :
+ DBG_CHANNEL_ID channel : debug channel to use
+ DBG_LEVEL_ID level : debug message level
+ BOOL bHeader : whether or not to output message header (thread id, etc)
+ LPSTR function : current function
+ LPSTR file : current file
+ INT line : line number
+ LPSTR format, ... : standard printf parameter list.
+
+Return Value :
+ always 1.
+
+Notes :
+ This version is for gnu compilers that support variable-argument macros
+ and the __FUNCTION__ pseudo-macro.
+
+--*/
+int DBG_printf_gcc(DBG_CHANNEL_ID channel, DBG_LEVEL_ID level, BOOL bHeader,
+ LPCSTR function, LPCSTR file, INT line, LPCSTR format, ...)
+{
+ CHAR *buffer = (CHAR*)alloca(DBG_BUFFER_SIZE);
+ CHAR indent[MAX_NESTING+1];
+ LPSTR buffer_ptr;
+ INT output_size;
+ va_list args;
+ void *thread_id;
+ int old_errno = 0;
+ CPalThread *pthrCurrent = InternalGetCurrentThread();
+
+ old_errno = errno;
+
+ if(!DBG_get_indent(level, format, indent))
+ {
+ return 1;
+ }
+
+ thread_id = (void *)THREADSilentGetCurrentThreadId();
+
+ if(bHeader)
+ {
+ /* Print file instead of function name for ENTRY messages, because those
+ already include the function name */
+ /* also print file name for ASSERTs, to match Win32 behavior */
+ if( DLI_ENTRY == level || DLI_ASSERT == level || DLI_EXIT == level)
+ {
+ output_size=snprintf(buffer, DBG_BUFFER_SIZE,
+ "{%p" MODULE_FORMAT "} %-5s [%-7s] at %s.%d: ",
+ thread_id, MODULE_ID
+ dbg_level_names[level], dbg_channel_names[channel], file, line);
+ }
+ else
+ {
+ output_size=snprintf(buffer, DBG_BUFFER_SIZE,
+ "{%p" MODULE_FORMAT "} %-5s [%-7s] at %s.%d: ",
+ thread_id, MODULE_ID
+ dbg_level_names[level], dbg_channel_names[channel], function, line);
+ }
+
+ if(output_size + 1 > DBG_BUFFER_SIZE)
+ {
+ fprintf(stderr, "ERROR : buffer overflow in DBG_printf_gcc");
+ return 1;
+ }
+
+ buffer_ptr=buffer+output_size;
+ }
+ else
+ {
+ buffer_ptr = buffer;
+ output_size = 0;
+ }
+
+ va_start(args, format);
+
+ output_size+=Silent_PAL_vsnprintf(buffer_ptr, DBG_BUFFER_SIZE-output_size,
+ format, args);
+ va_end(args);
+
+ if( output_size > DBG_BUFFER_SIZE )
+ {
+ fprintf(stderr, "ERROR : buffer overflow in DBG_printf_gcc");
+ }
+
+ /* Use a Critical section before calling printf code to
+ avoid holding a libc lock while another thread is calling
+ SuspendThread on this one. */
+
+ InternalEnterCriticalSection(pthrCurrent, &fprintf_crit_section);
+ fprintf( output_file, "%s%s", indent, buffer );
+ InternalLeaveCriticalSection(pthrCurrent, &fprintf_crit_section);
+
+ /* flush the output to file */
+ if ( fflush(output_file) != 0 )
+ {
+ fprintf(stderr, "ERROR : fflush() failed errno:%d (%s)\n",
+ errno, strerror(errno));
+ }
+
+ // Some systems support displaying a GUI dialog. We attempt this only for asserts.
+ if ( level == DLI_ASSERT )
+ PAL_DisplayDialog("PAL ASSERT", buffer);
+
+ if ( old_errno != errno )
+ {
+ fprintf( stderr,"ERROR: errno changed by DBG_printf_gcc\n" );
+ errno = old_errno;
+ }
+
+ return 1;
+}
+
+/*++
+Function :
+ DBG_printf_c99
+
+ Internal function for debug channels; don't use.
+ This function outputs a complete debug message, without function name.
+
+Parameters :
+ DBG_CHANNEL_ID channel : debug channel to use
+ DBG_LEVEL_ID level : debug message level
+ BOOL bHeader : whether or not to output message header (thread id, etc)
+ LPSTR file : current file
+ INT line : line number
+ LPSTR format, ... : standard printf parameter list.
+
+Return Value :
+ always 1.
+
+Notes :
+ This version is for compilers that support the C99 flavor of
+ variable-argument macros but not the gnu flavor, and do not support the
+ __FUNCTION__ pseudo-macro.
+
+--*/
+int DBG_printf_c99(DBG_CHANNEL_ID channel, DBG_LEVEL_ID level, BOOL bHeader,
+ LPSTR file, INT line, LPSTR format, ...)
+{
+ CHAR *buffer = (CHAR*)alloca(DBG_BUFFER_SIZE);
+ CHAR indent[MAX_NESTING+1];
+ LPSTR buffer_ptr;
+ INT output_size;
+ va_list args;
+ static INT call_count=0;
+ void *thread_id;
+ int old_errno = 0;
+ CPalThread *pthrCurrent = InternalGetCurrentThread();
+
+ old_errno = errno;
+
+ if(!DBG_get_indent(level, format, indent))
+ {
+ return 1;
+ }
+
+ thread_id= (void *)THREADSilentGetCurrentThreadId();
+
+ if(bHeader)
+ {
+ output_size=snprintf(buffer, DBG_BUFFER_SIZE,
+ "{%p" MODULE_FORMAT "} %-5s [%-7s] at %s.%d: ", thread_id, MODULE_ID
+ dbg_level_names[level], dbg_channel_names[channel],
+ file, line);
+
+ if(output_size + 1 > DBG_BUFFER_SIZE)
+ {
+ fprintf(stderr, "ERROR : buffer overflow in DBG_printf_gcc");
+ return 1;
+ }
+
+ buffer_ptr=buffer+output_size;
+ }
+ else
+ {
+ output_size = 0;
+ buffer_ptr = buffer;
+ }
+
+ va_start(args, format);
+ output_size+=Silent_PAL_vsnprintf(buffer_ptr, DBG_BUFFER_SIZE-output_size,
+ format, args);
+ va_end(args);
+
+ if(output_size>DBG_BUFFER_SIZE)
+ fprintf(stderr, "ERROR : buffer overflow in DBG_printf_c99");
+
+ /* Use a Critical section before calling printf code to
+ avoid holding a libc lock while another thread is calling
+ SuspendThread on this one. */
+
+ InternalEnterCriticalSection(pthrCurrent, &fprintf_crit_section);
+ fprintf( output_file, "%s", buffer );
+ InternalLeaveCriticalSection(pthrCurrent, &fprintf_crit_section);
+
+ /* flush the output to file every once in a while */
+ call_count++;
+ if(call_count>5)
+ {
+ call_count=0;
+ if ( fflush(output_file) != 0 )
+ {
+ fprintf(stderr, "ERROR : fflush() failed errno:%d (%s)\n",
+ errno, strerror(errno));
+ }
+ }
+
+ if ( old_errno != errno )
+ {
+ fprintf( stderr, "ERROR: DBG_printf_c99 changed the errno.\n" );
+ errno = old_errno;
+ }
+
+ return 1;
+}
+
+/*++
+Function :
+ DBG_get_indent
+
+ generate an indentation string to be used for message output
+
+Parameters :
+ DBG_LEVEL_ID level : level of message (DLI_ENTRY, etc)
+ const char *format : printf format string of message
+ char *indent_string : destination for indentation string
+
+Return value :
+ TRUE if output can proceed, FALSE otherwise
+
+Notes:
+As a side-effect, this function updates the ENTRY nesting level for the current
+thread : it decrements it if 'format' contains the string 'return', increments
+it otherwise (but only if 'level' is DLI_ENTRY). The function will return
+FALSE if the current nesting level is beyond our treshold (max_nesting_level);
+it always returns TRUE for other message levels
+--*/
+static BOOL DBG_get_indent(DBG_LEVEL_ID level, const char *format,
+ char *indent_string)
+{
+ int ret;
+
+ /* determine whether to output an ENTRY line */
+ if(DLI_ENTRY == level||DLI_EXIT == level)
+ {
+ if(0 != max_entry_level)
+ {
+ INT_PTR nesting;
+
+ /* Determine if this is an entry or an
+ exit */
+ if(DLI_EXIT == level)
+ {
+ nesting = (INT_PTR) pthread_getspecific(entry_level_key);
+ /* avoid going negative */
+ if(nesting != 0)
+ {
+ nesting--;
+ if ((ret = pthread_setspecific(entry_level_key,
+ (LPVOID)nesting)) != 0)
+ {
+ fprintf(stderr, "ERROR : pthread_setspecific() failed "
+ "error:%d (%s)\n", ret, strerror(ret));
+ }
+ }
+ }
+ else
+ {
+ nesting = (INT_PTR) pthread_getspecific(entry_level_key);
+
+ if ((ret = pthread_setspecific(entry_level_key,
+ (LPVOID)(nesting+1))) != 0)
+ {
+ fprintf(stderr, "ERROR : pthread_setspecific() failed "
+ "error:%d (%s)\n", ret, strerror(ret));
+ }
+ }
+
+ /* see if we're past the level treshold */
+ if(nesting >= max_entry_level)
+ {
+ return FALSE;
+ }
+
+ /* generate indentation string */
+ if(MAX_NESTING < nesting)
+ {
+ nesting = MAX_NESTING;
+ }
+ memset(indent_string,INDENT_CHAR ,nesting);
+ indent_string[nesting] = '\0';
+ }
+ else
+ {
+ indent_string[0] = '\0';
+ }
+ }
+ else
+ {
+ indent_string[0] = '\0';
+ }
+ return TRUE;
+}
+
+/*++
+Function :
+ DBG_change_entrylevel
+
+ retrieve current ENTRY nesting level and [optionnally] modify it
+
+Parameters :
+ int new_level : value to which the nesting level must be set, or -1
+
+Return value :
+ nesting level at the time the function was called
+
+Notes:
+if new_level is -1, the nesting level will not be modified
+--*/
+int DBG_change_entrylevel(int new_level)
+{
+ int old_level;
+ int ret;
+
+ if(0 == max_entry_level)
+ {
+ return 0;
+ }
+ old_level = PtrToInt(pthread_getspecific(entry_level_key));
+ if(-1 != new_level)
+ {
+ if ((ret = pthread_setspecific(entry_level_key,(LPVOID)(IntToPtr(new_level)))) != 0)
+ {
+ fprintf(stderr, "ERROR : pthread_setspecific() failed "
+ "error:%d (%s)\n", ret, strerror(ret));
+ }
+ }
+ return old_level;
+}
+
+#if _DEBUG && defined(__APPLE__)
+/*++
+Function:
+ DBG_ShouldCheckStackAlignment
+
+ Wires up stack alignment checks (debug builds only)
+--*/
+static const char * PAL_CHECK_ALIGNMENT_MODE = "PAL_CheckAlignmentMode";
+enum CheckAlignmentMode
+{
+ // special value to indicate we've not initialized yet
+ CheckAlignment_Uninitialized = -1,
+
+ CheckAlignment_Off = 0,
+ CheckAlignment_On = 1,
+
+ CheckAlignment_Default = CheckAlignment_On
+};
+
+bool DBG_ShouldCheckStackAlignment()
+{
+ static CheckAlignmentMode caMode = CheckAlignment_Uninitialized;
+
+ if (caMode == CheckAlignment_Uninitialized)
+ {
+ char* checkAlignmentSettings;
+ bool shouldFreeCheckAlignmentSettings = false;
+ if (palEnvironment == nullptr)
+ {
+ // This function might be called before the PAL environment is initialized.
+ // In this case, use the system getenv instead.
+ checkAlignmentSettings = ::getenv(PAL_CHECK_ALIGNMENT_MODE);
+ }
+ else
+ {
+ checkAlignmentSettings = EnvironGetenv(PAL_CHECK_ALIGNMENT_MODE);
+ shouldFreeCheckAlignmentSettings = true;
+ }
+
+ caMode = checkAlignmentSettings ?
+ (CheckAlignmentMode)atoi(checkAlignmentSettings) : CheckAlignment_Default;
+
+ if (checkAlignmentSettings && shouldFreeCheckAlignmentSettings)
+ {
+ free(checkAlignmentSettings);
+ }
+ }
+
+ return caMode == CheckAlignment_On;
+}
+#endif // _DEBUG && __APPLE__
+
+#ifdef __APPLE__
+#include "CoreFoundation/CFUserNotification.h"
+#include "CoreFoundation/CFString.h"
+#include "Security/AuthSession.h"
+
+static const char * PAL_DISPLAY_DIALOG = "PAL_DisplayDialog";
+enum DisplayDialogMode
+{
+ DisplayDialog_Uninitialized = -1,
+
+ DisplayDialog_Suppress = 0,
+ DisplayDialog_Show = 1,
+
+ DisplayDialog_Default = DisplayDialog_Suppress,
+};
+
+/*++
+Function :
+ PAL_DisplayDialog
+
+ Display a simple modal dialog with an alert icon and a single OK button. Caller supplies the title of the
+ dialog and the main text. The dialog is displayed only if the PAL_DisplayDialog environment
+ variable is set to the value "1" and the session has access to the display.
+
+--*/
+void PAL_DisplayDialog(const char *szTitle, const char *szText)
+{
+ static DisplayDialogMode dispDialog = DisplayDialog_Uninitialized;
+
+ if (dispDialog == DisplayDialog_Uninitialized)
+ {
+ char* displayDialog = EnvironGetenv(PAL_DISPLAY_DIALOG);
+ if (displayDialog)
+ {
+ int i = atoi(displayDialog);
+ free(displayDialog);
+
+ switch (i)
+ {
+ case 0:
+ dispDialog = DisplayDialog_Suppress;
+ break;
+
+ case 1:
+ dispDialog = DisplayDialog_Show;
+ break;
+
+ default:
+ // Asserting here would just be re-entrant. :/
+ dispDialog = DisplayDialog_Default;
+ break;
+ }
+ }
+ else
+ dispDialog = DisplayDialog_Default;
+
+ if (dispDialog == DisplayDialog_Show)
+ {
+ // We may not be allowed to show.
+ OSStatus osstatus;
+ SecuritySessionId secSession;
+ SessionAttributeBits secSessionInfo;
+
+ osstatus = SessionGetInfo(callerSecuritySession, &secSession, &secSessionInfo);
+ if (noErr != osstatus || (secSessionInfo & sessionHasGraphicAccess) == 0)
+ dispDialog = DisplayDialog_Suppress;
+ }
+ }
+
+ if (dispDialog == DisplayDialog_Suppress)
+ return;
+
+ CFStringRef cfsTitle = CFStringCreateWithCString(kCFAllocatorDefault,
+ szTitle,
+ kCFStringEncodingUTF8);
+ if (cfsTitle != NULL)
+ {
+ CFStringRef cfsText = CFStringCreateWithCString(kCFAllocatorDefault,
+ szText,
+ kCFStringEncodingUTF8);
+ if (cfsText != NULL)
+ {
+ CFOptionFlags response;
+ CFUserNotificationDisplayAlert(0, // Never time-out, wait for user to hit 'OK'
+ 0, // No flags
+ NULL, // Default icon
+ NULL, // Default sound
+ NULL, // No-localization support for text
+ cfsTitle, // Title for dialog
+ cfsText, // The actual alert text
+ NULL, // Default default button title ('OK')
+ NULL, // No alternate button
+ NULL, // No third button
+ &response); // User's response (discarded)
+ CFRelease(cfsText);
+ }
+ CFRelease(cfsTitle);
+ }
+}
+
+/*++
+Function :
+ PAL_DisplayDialogFormatted
+
+ As above but takes a printf-style format string and insertion values to form the main text.
+
+--*/
+void PAL_DisplayDialogFormatted(const char *szTitle, const char *szTextFormat, ...)
+{
+ va_list args;
+
+ va_start(args, szTextFormat);
+
+ const int cchBuffer = 4096;
+ char *szBuffer = (char*)alloca(cchBuffer);
+ PAL__vsnprintf(szBuffer, cchBuffer, szTextFormat, args);
+ PAL_DisplayDialog(szTitle, szBuffer);
+
+ va_end(args);
+}
+#endif // __APPLE__
diff --git a/src/pal/src/misc/environ.cpp b/src/pal/src/misc/environ.cpp
new file mode 100644
index 0000000000..fed7b69f38
--- /dev/null
+++ b/src/pal/src/misc/environ.cpp
@@ -0,0 +1,1096 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ environ.cpp
+
+Abstract:
+
+ Implementation of functions manipulating environment variables.
+
+Revision History:
+
+
+
+--*/
+
+#include "pal/palinternal.h"
+#include "pal/critsect.h"
+#include "pal/dbgmsg.h"
+#include "pal/environ.h"
+#include "pal/malloc.hpp"
+
+#if HAVE_CRT_EXTERNS_H
+#include <crt_externs.h>
+#endif
+
+#include <stdlib.h>
+
+using namespace CorUnix;
+
+SET_DEFAULT_DEBUG_CHANNEL(MISC);
+
+char **palEnvironment = nullptr;
+int palEnvironmentCount = 0;
+int palEnvironmentCapacity = 0;
+
+CRITICAL_SECTION gcsEnvironment;
+
+/*++
+Function:
+ GetEnvironmentVariableA
+
+The GetEnvironmentVariable function retrieves the value of the
+specified variable from the environment block of the calling
+process. The value is in the form of a null-terminated string of
+characters.
+
+Parameters
+
+lpName
+ [in] Pointer to a null-terminated string that specifies the environment variable.
+lpBuffer
+ [out] Pointer to a buffer to receive the value of the specified environment variable.
+nSize
+ [in] Specifies the size, in TCHARs, of the buffer pointed to by the lpBuffer parameter.
+
+Return Values
+
+If the function succeeds, the return value is the number of TCHARs
+stored into the buffer pointed to by lpBuffer, not including the
+terminating null character.
+
+If the specified environment variable name was not found in the
+environment block for the current process, the return value is zero.
+
+If the buffer pointed to by lpBuffer is not large enough, the return
+value is the buffer size, in TCHARs, required to hold the value string
+and its terminating null character.
+
+--*/
+DWORD
+PALAPI
+GetEnvironmentVariableA(
+ IN LPCSTR lpName,
+ OUT LPSTR lpBuffer,
+ IN DWORD nSize)
+{
+ char *value;
+ DWORD dwRet = 0;
+
+ PERF_ENTRY(GetEnvironmentVariableA);
+ ENTRY("GetEnvironmentVariableA(lpName=%p (%s), lpBuffer=%p, nSize=%u)\n",
+ lpName ? lpName : "NULL",
+ lpName ? lpName : "NULL", lpBuffer, nSize);
+
+ CPalThread * pthrCurrent = InternalGetCurrentThread();
+
+ if (lpName == nullptr)
+ {
+ ERROR("lpName is null\n");
+ SetLastError(ERROR_INVALID_PARAMETER);
+ goto done;
+ }
+
+ if (lpName[0] == 0)
+ {
+ TRACE("lpName is an empty string\n", lpName);
+ SetLastError(ERROR_ENVVAR_NOT_FOUND);
+ goto done;
+ }
+
+ if (strchr(lpName, '=') != nullptr)
+ {
+ // GetEnvironmentVariable doesn't permit '=' in variable names.
+ value = nullptr;
+ }
+ else
+ {
+ // Enter the environment critical section so that we can safely get
+ // the environment variable value without EnvironGetenv making an
+ // intermediate copy. We will just copy the string to the output
+ // buffer anyway, so just stay in the critical section until then.
+ InternalEnterCriticalSection(pthrCurrent, &gcsEnvironment);
+
+ value = EnvironGetenv(lpName, /* copyValue */ FALSE);
+
+ if (value != nullptr)
+ {
+ DWORD valueLength = strlen(value);
+ if (valueLength < nSize)
+ {
+ strcpy_s(lpBuffer, nSize, value);
+ dwRet = valueLength;
+ }
+ else
+ {
+ dwRet = valueLength + 1;
+ }
+
+ SetLastError(ERROR_SUCCESS);
+ }
+
+ InternalLeaveCriticalSection(pthrCurrent, &gcsEnvironment);
+ }
+
+ if (value == nullptr)
+ {
+ TRACE("%s is not found\n", lpName);
+ SetLastError(ERROR_ENVVAR_NOT_FOUND);
+ }
+
+done:
+
+ LOGEXIT("GetEnvironmentVariableA returns DWORD 0x%x\n", dwRet);
+ PERF_EXIT(GetEnvironmentVariableA);
+ return dwRet;
+}
+
+/*++
+Function:
+ GetEnvironmentVariableW
+
+See MSDN doc.
+--*/
+DWORD
+PALAPI
+GetEnvironmentVariableW(
+ IN LPCWSTR lpName,
+ OUT LPWSTR lpBuffer,
+ IN DWORD nSize)
+{
+ CHAR *inBuff = nullptr;
+ CHAR *outBuff = nullptr;
+ INT inBuffSize;
+ DWORD size = 0;
+
+ PERF_ENTRY(GetEnvironmentVariableW);
+ ENTRY("GetEnvironmentVariableW(lpName=%p (%S), lpBuffer=%p, nSize=%u)\n",
+ lpName ? lpName : W16_NULLSTRING,
+ lpName ? lpName : W16_NULLSTRING, lpBuffer, nSize);
+
+ inBuffSize = WideCharToMultiByte(CP_ACP, 0, lpName, -1,
+ inBuff, 0, nullptr, nullptr);
+ if (0 == inBuffSize)
+ {
+ ERROR("lpName has to be a valid parameter\n");
+ SetLastError(ERROR_INVALID_PARAMETER);
+ goto done;
+ }
+
+ inBuff = (CHAR *)PAL_malloc(inBuffSize);
+ if (inBuff == nullptr)
+ {
+ ERROR("malloc failed\n");
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ goto done;
+ }
+
+ if (nSize)
+ {
+ outBuff = (CHAR *)PAL_malloc(nSize*2);
+ if (outBuff == nullptr)
+ {
+ ERROR("malloc failed\n");
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ goto done;
+ }
+ }
+
+ if (0 == WideCharToMultiByte(CP_ACP, 0, lpName, -1, inBuff,
+ inBuffSize, nullptr, nullptr))
+ {
+ ASSERT("WideCharToMultiByte failed!\n");
+ SetLastError(ERROR_INTERNAL_ERROR);
+ goto done;
+ }
+
+ size = GetEnvironmentVariableA(inBuff, outBuff, nSize);
+ if (size > nSize)
+ {
+ TRACE("Insufficient buffer\n");
+ }
+ else if (size == 0)
+ {
+ // handle error in GetEnvironmentVariableA
+ }
+ else
+ {
+ size = MultiByteToWideChar(CP_ACP, 0, outBuff, -1, lpBuffer, nSize);
+ if (0 != size)
+ {
+ // -1 for the null.
+ size--;
+ }
+ else
+ {
+ ASSERT("MultiByteToWideChar failed!\n");
+ SetLastError(ERROR_INTERNAL_ERROR);
+ size = 0;
+ *lpBuffer = '\0';
+ }
+ }
+
+done:
+ PAL_free(outBuff);
+ PAL_free(inBuff);
+
+ LOGEXIT("GetEnvironmentVariableW returns DWORD 0x%x\n", size);
+ PERF_EXIT(GetEnvironmentVariableW);
+
+ return size;
+}
+
+/*++
+Function:
+ SetEnvironmentVariableW
+
+The SetEnvironmentVariable function sets the value of an environment
+variable for the current process.
+
+Parameters
+
+lpName
+ [in] Pointer to a null-terminated string that specifies the
+ environment variable whose value is being set. The operating
+ system creates the environment variable if it does not exist
+ and lpValue is not null.
+lpValue
+ [in] Pointer to a null-terminated string containing the new
+ value of the specified environment variable. If this parameter
+ is null, the variable is deleted from the current process's
+ environment.
+
+Return Values
+
+If the function succeeds, the return value is nonzero.
+
+If the function fails, the return value is zero. To get extended error
+information, call GetLastError.
+
+Remarks
+
+This function has no effect on the system environment variables or the
+environment variables of other processes.
+
+--*/
+BOOL
+PALAPI
+SetEnvironmentVariableW(
+ IN LPCWSTR lpName,
+ IN LPCWSTR lpValue)
+{
+ PCHAR name = nullptr;
+ PCHAR value = nullptr;
+ INT nameSize = 0;
+ INT valueSize = 0;
+ BOOL bRet = FALSE;
+
+ PERF_ENTRY(SetEnvironmentVariableW);
+ ENTRY("SetEnvironmentVariableW(lpName=%p (%S), lpValue=%p (%S))\n",
+ lpName?lpName:W16_NULLSTRING,
+ lpName?lpName:W16_NULLSTRING, lpValue?lpValue:W16_NULLSTRING, lpValue?lpValue:W16_NULLSTRING);
+
+ if ((nameSize = WideCharToMultiByte(CP_ACP, 0, lpName, -1, name, 0,
+ nullptr, nullptr)) == 0)
+ {
+ ERROR("WideCharToMultiByte failed\n");
+ SetLastError(ERROR_INVALID_PARAMETER);
+ goto done;
+ }
+
+ name = (PCHAR)PAL_malloc(sizeof(CHAR)* nameSize);
+ if (name == nullptr)
+ {
+ ERROR("malloc failed\n");
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ goto done;
+ }
+
+ if (0 == WideCharToMultiByte(CP_ACP, 0, lpName, -1,
+ name, nameSize, nullptr, nullptr))
+ {
+ ASSERT("WideCharToMultiByte returned 0\n");
+ SetLastError(ERROR_INTERNAL_ERROR);
+ goto done;
+ }
+
+ if (lpValue != nullptr)
+ {
+ if ((valueSize = WideCharToMultiByte(CP_ACP, 0, lpValue, -1, value,
+ 0, nullptr, nullptr)) == 0)
+ {
+ ERROR("WideCharToMultiByte failed\n");
+ SetLastError(ERROR_INVALID_PARAMETER);
+ goto done;
+ }
+
+ value = (PCHAR)PAL_malloc(sizeof(CHAR)*valueSize);
+
+ if (value == nullptr)
+ {
+ ERROR("malloc failed\n");
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ goto done;
+ }
+
+ if (0 == WideCharToMultiByte(CP_ACP, 0, lpValue, -1,
+ value, valueSize, nullptr, nullptr))
+ {
+ ASSERT("WideCharToMultiByte failed\n");
+ SetLastError( ERROR_INTERNAL_ERROR );
+ goto done;
+ }
+ }
+
+ bRet = SetEnvironmentVariableA(name, value);
+done:
+ PAL_free(value);
+ PAL_free(name);
+
+ LOGEXIT("SetEnvironmentVariableW returning BOOL %d\n", bRet);
+ PERF_EXIT(SetEnvironmentVariableW);
+ return bRet;
+}
+
+/*++
+Function:
+ GetEnvironmentStringsW
+
+The GetEnvironmentStrings function retrieves the environment block for
+the current process.
+
+Parameters
+
+This function has no parameters.
+
+Return Values
+
+The return value is a pointer to an environment block for the current process.
+
+Remarks
+
+The GetEnvironmentStrings function returns a pointer to the
+environment block of the calling process. This should be treated as a
+read-only block; do not modify it directly. Instead, use the
+GetEnvironmentVariable and SetEnvironmentVariable functions to
+retrieve or change the environment variables within this block. When
+the block is no longer needed, it should be freed by calling
+FreeEnvironmentStrings.
+
+--*/
+LPWSTR
+PALAPI
+GetEnvironmentStringsW(
+ VOID)
+{
+ WCHAR *wenviron = nullptr, *tempEnviron;
+ int i, len, envNum;
+
+ PERF_ENTRY(GetEnvironmentStringsW);
+ ENTRY("GetEnvironmentStringsW()\n");
+
+ CPalThread * pthrCurrent = InternalGetCurrentThread();
+ InternalEnterCriticalSection(pthrCurrent, &gcsEnvironment);
+
+ envNum = 0;
+ len = 0;
+
+ /* get total length of the bytes that we need to allocate */
+ for (i = 0; palEnvironment[i] != 0; i++)
+ {
+ len = MultiByteToWideChar(CP_ACP, 0, palEnvironment[i], -1, wenviron, 0);
+ envNum += len;
+ }
+
+ wenviron = (WCHAR *)PAL_malloc(sizeof(WCHAR)* (envNum + 1));
+ if (wenviron == nullptr)
+ {
+ ERROR("malloc failed\n");
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ goto EXIT;
+ }
+
+ len = 0;
+ tempEnviron = wenviron;
+ for (i = 0; palEnvironment[i] != 0; i++)
+ {
+ len = MultiByteToWideChar(CP_ACP, 0, palEnvironment[i], -1, tempEnviron, envNum);
+ tempEnviron += len;
+ envNum -= len;
+ }
+
+ *tempEnviron = 0; /* Put an extra null at the end */
+
+ EXIT:
+ InternalLeaveCriticalSection(pthrCurrent, &gcsEnvironment);
+
+ LOGEXIT("GetEnvironmentStringsW returning %p\n", wenviron);
+ PERF_EXIT(GetEnvironmentStringsW);
+ return wenviron;
+}
+
+/*++
+Function:
+ GetEnvironmentStringsA
+
+See GetEnvironmentStringsW.
+
+--*/
+LPSTR
+PALAPI
+GetEnvironmentStringsA(
+ VOID)
+{
+ char *environ = nullptr, *tempEnviron;
+ int i, len, envNum;
+
+ PERF_ENTRY(GetEnvironmentStringsA);
+ ENTRY("GetEnvironmentStringsA()\n");
+
+ CPalThread * pthrCurrent = InternalGetCurrentThread();
+ InternalEnterCriticalSection(pthrCurrent, &gcsEnvironment);
+
+ envNum = 0;
+ len = 0;
+
+ /* get total length of the bytes that we need to allocate */
+ for (i = 0; palEnvironment[i] != 0; i++)
+ {
+ len = strlen(palEnvironment[i]) + 1;
+ envNum += len;
+ }
+
+ environ = (char *)PAL_malloc(envNum + 1);
+ if (environ == nullptr)
+ {
+ ERROR("malloc failed\n");
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ goto EXIT;
+ }
+
+ len = 0;
+ tempEnviron = environ;
+ for (i = 0; palEnvironment[i] != 0; i++)
+ {
+ len = strlen(palEnvironment[i]) + 1;
+ memcpy(tempEnviron, palEnvironment[i], len);
+ tempEnviron += len;
+ envNum -= len;
+ }
+
+ *tempEnviron = 0; /* Put an extra null at the end */
+
+ EXIT:
+ InternalLeaveCriticalSection(pthrCurrent, &gcsEnvironment);
+
+ LOGEXIT("GetEnvironmentStringsA returning %p\n", environ);
+ PERF_EXIT(GetEnvironmentStringsA);
+ return environ;
+}
+
+/*++
+Function:
+ FreeEnvironmentStringsW
+
+The FreeEnvironmentStrings function frees a block of environment strings.
+
+Parameters
+
+lpszEnvironmentBlock [in] Pointer to a block of environment strings. The pointer to
+ the block must be obtained by calling the
+ GetEnvironmentStrings function.
+
+Return Values
+
+If the function succeeds, the return value is nonzero. If the
+function fails, the return value is zero. To get extended error
+information, call GetLastError.
+
+Remarks
+
+When GetEnvironmentStrings is called, it allocates memory for a block
+of environment strings. When the block is no longer needed, it should
+be freed by calling FreeEnvironmentStrings.
+
+--*/
+BOOL
+PALAPI
+FreeEnvironmentStringsW(
+ IN LPWSTR lpValue)
+{
+ PERF_ENTRY(FreeEnvironmentStringsW);
+ ENTRY("FreeEnvironmentStringsW(lpValue=%p (%S))\n", lpValue ? lpValue : W16_NULLSTRING, lpValue ? lpValue : W16_NULLSTRING);
+
+ if (lpValue != nullptr)
+ {
+ PAL_free(lpValue);
+ }
+
+ LOGEXIT("FreeEnvironmentStringW returning BOOL TRUE\n");
+ PERF_EXIT(FreeEnvironmentStringsW);
+ return TRUE;
+}
+
+/*++
+Function:
+ FreeEnvironmentStringsA
+
+See FreeEnvironmentStringsW.
+
+--*/
+BOOL
+PALAPI
+FreeEnvironmentStringsA(
+ IN LPSTR lpValue)
+{
+ PERF_ENTRY(FreeEnvironmentStringsA);
+ ENTRY("FreeEnvironmentStringsA(lpValue=%p (%s))\n", lpValue ? lpValue : "NULL", lpValue ? lpValue : "NULL");
+
+ if (lpValue != nullptr)
+ {
+ PAL_free(lpValue);
+ }
+
+ LOGEXIT("FreeEnvironmentStringA returning BOOL TRUE\n");
+ PERF_EXIT(FreeEnvironmentStringsA);
+ return TRUE;
+}
+
+/*++
+Function:
+ SetEnvironmentVariableA
+
+The SetEnvironmentVariable function sets the value of an environment
+variable for the current process.
+
+Parameters
+
+lpName
+ [in] Pointer to a null-terminated string that specifies the
+ environment variable whose value is being set. The operating
+ system creates the environment variable if it does not exist
+ and lpValue is not null.
+lpValue
+ [in] Pointer to a null-terminated string containing the new
+ value of the specified environment variable. If this parameter
+ is null, the variable is deleted from the current process's
+ environment.
+
+Return Values
+
+If the function succeeds, the return value is nonzero.
+
+If the function fails, the return value is zero. To get extended error
+information, call GetLastError.
+
+Remarks
+
+This function has no effect on the system environment variables or the
+environment variables of other processes.
+
+--*/
+BOOL
+PALAPI
+SetEnvironmentVariableA(
+ IN LPCSTR lpName,
+ IN LPCSTR lpValue)
+{
+
+ BOOL bRet = FALSE;
+ int nResult =0;
+ PERF_ENTRY(SetEnvironmentVariableA);
+ ENTRY("SetEnvironmentVariableA(lpName=%p (%s), lpValue=%p (%s))\n",
+ lpName ? lpName : "NULL", lpName ? lpName : "NULL",
+ lpValue ? lpValue : "NULL", lpValue ? lpValue : "NULL");
+
+ // exit if the input variable name is null
+ if ((lpName == nullptr) || (lpName[0] == 0))
+ {
+ ERROR("lpName is null\n");
+ goto done;
+ }
+
+ /* check if the input value is null and if so
+ * check if the input name is valid and delete
+ * the variable name from process environment */
+ if (lpValue == nullptr)
+ {
+ // We tell EnvironGetenv not to bother with making a copy of the
+ // value since we're not going to use it for anything interesting
+ // apart from checking whether it's null.
+ if ((lpValue = EnvironGetenv(lpName, /* copyValue */ FALSE)) == nullptr)
+ {
+ ERROR("Couldn't find environment variable (%s)\n", lpName);
+ SetLastError(ERROR_ENVVAR_NOT_FOUND);
+ goto done;
+ }
+
+ EnvironUnsetenv(lpName);
+ }
+ else
+ {
+ // All the conditions are met. Set the variable.
+ int iLen = strlen(lpName) + strlen(lpValue) + 2;
+ LPSTR string = (LPSTR) PAL_malloc(iLen);
+ if (string == nullptr)
+ {
+ bRet = FALSE;
+ ERROR("Unable to allocate memory\n");
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ goto done;
+ }
+
+ sprintf_s(string, iLen, "%s=%s", lpName, lpValue);
+ nResult = EnvironPutenv(string, FALSE) ? 0 : -1;
+
+ PAL_free(string);
+ string = nullptr;
+
+ // If EnvironPutenv returns FALSE, it almost certainly failed to allocate memory.
+ if (nResult == -1)
+ {
+ bRet = FALSE;
+ ERROR("Unable to allocate memory\n");
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ goto done;
+ }
+ }
+
+ bRet = TRUE;
+
+done:
+ LOGEXIT("SetEnvironmentVariableA returning BOOL %d\n", bRet);
+ PERF_EXIT(SetEnvironmentVariableA);
+ return bRet;
+}
+
+/*++
+Function:
+ ResizeEnvironment
+
+Resizes the PAL environment buffer.
+
+Parameters
+
+ newSize
+ [in] New size of palEnvironment
+
+Return Values
+
+ TRUE on success, FALSE otherwise
+
+--*/
+BOOL ResizeEnvironment(int newSize)
+{
+ CPalThread * pthrCurrent = InternalGetCurrentThread();
+ InternalEnterCriticalSection(pthrCurrent, &gcsEnvironment);
+
+ BOOL ret = FALSE;
+ if (newSize >= palEnvironmentCount)
+ {
+ // If palEnvironment is null, realloc acts like malloc.
+ char **newEnvironment = (char**)realloc(palEnvironment, newSize * sizeof(char *));
+ if (newEnvironment != nullptr)
+ {
+ // realloc succeeded, so set palEnvironment to what it returned.
+ palEnvironment = newEnvironment;
+ palEnvironmentCapacity = newSize;
+ ret = TRUE;
+ }
+ }
+ else
+ {
+ ASSERT("ResizeEnvironment: newSize < current palEnvironmentCount!\n");
+ }
+
+ InternalLeaveCriticalSection(pthrCurrent, &gcsEnvironment);
+ return ret;
+}
+
+/*++
+Function:
+ EnvironUnsetenv
+
+Remove the environment variable with the given name from the PAL version
+of the environment if it exists.
+
+Parameters
+
+ name
+ [in] Name of variable to unset.
+
+--*/
+void EnvironUnsetenv(const char *name)
+{
+ int nameLength = strlen(name);
+
+ CPalThread * pthrCurrent = InternalGetCurrentThread();
+ InternalEnterCriticalSection(pthrCurrent, &gcsEnvironment);
+
+ for (int i = 0; palEnvironment[i] != nullptr; ++i)
+ {
+ const char *equalsSignPosition = strchr(palEnvironment[i], '=');
+ if (equalsSignPosition == nullptr)
+ {
+ equalsSignPosition = palEnvironment[i] + strlen(palEnvironment[i]);
+ }
+
+ // Check whether the name of this variable has the same length as the one
+ // we're looking for before proceeding to compare them.
+ if (equalsSignPosition - palEnvironment[i] == nameLength)
+ {
+ if (memcmp(name, palEnvironment[i], nameLength) == 0)
+ {
+ // Free the string we're removing.
+ free(palEnvironment[i]);
+
+ // Move the last environment variable pointer here.
+ palEnvironment[i] = palEnvironment[palEnvironmentCount - 1];
+ palEnvironment[palEnvironmentCount - 1] = nullptr;
+
+ palEnvironmentCount--;
+ }
+ }
+ }
+
+ InternalLeaveCriticalSection(pthrCurrent, &gcsEnvironment);
+}
+
+/*++
+Function:
+ EnvironPutenv
+
+Add the environment variable string provided to the PAL version
+of the environment.
+
+Parameters
+
+ entry
+ [in] The variable string to add. Should be in the format
+ "name=value", where value might be empty (see below).
+ deleteIfEmpty
+ [in] If this is TRUE, "name=" will unset the 'name' variable.
+
+Return Values
+
+ TRUE on success, FALSE otherwise
+
+--*/
+BOOL EnvironPutenv(const char* entry, BOOL deleteIfEmpty)
+{
+ BOOL result = FALSE;
+
+ bool fOwningCS = false;
+
+ CPalThread * pthrCurrent = InternalGetCurrentThread();
+
+ const char *equalsSignPosition = strchr(entry, '=');
+ if (equalsSignPosition == entry || equalsSignPosition == nullptr)
+ {
+ // "=foo" and "foo" have no meaning
+ return FALSE;
+ }
+
+ char* copy = strdup(entry);
+ if (copy == nullptr)
+ {
+ return FALSE;
+ }
+
+ int nameLength = equalsSignPosition - entry;
+
+ if (equalsSignPosition[1] == '\0' && deleteIfEmpty)
+ {
+ // "foo=" removes foo from the environment in _putenv() on Windows.
+ // The same string can result from a call to SetEnvironmentVariable()
+ // with the empty string as the value, but in that case we want to
+ // set the variable's value to "". deleteIfEmpty will be FALSE in
+ // that case.
+
+ // Change '=' to '\0'
+ copy[nameLength] = '\0';
+
+ EnvironUnsetenv(copy);
+ free(copy);
+
+ result = TRUE;
+ }
+ else
+ {
+ // See if we are replacing an item or adding one.
+
+ InternalEnterCriticalSection(pthrCurrent, &gcsEnvironment);
+ fOwningCS = true;
+
+ int i;
+ for (i = 0; palEnvironment[i] != nullptr; i++)
+ {
+ const char *existingEquals = strchr(palEnvironment[i], '=');
+ if (existingEquals == nullptr)
+ {
+ // The PAL screens out malformed strings, but the strings which
+ // came from the system during initialization might not have the
+ // equals sign. We treat the entire string as a name in that case.
+ existingEquals = palEnvironment[i] + strlen(palEnvironment[i]);
+ }
+
+ if (existingEquals - palEnvironment[i] == nameLength)
+ {
+ if (memcmp(entry, palEnvironment[i], nameLength) == 0)
+ {
+ free(palEnvironment[i]);
+ palEnvironment[i] = copy;
+
+ result = TRUE;
+ break;
+ }
+ }
+ }
+
+ if (palEnvironment[i] == nullptr)
+ {
+ _ASSERTE(i < palEnvironmentCapacity);
+ if (i == (palEnvironmentCapacity - 1))
+ {
+ // We found the first null, but it's the last element in our environment
+ // block. We need more space in our environment, so let's double its size.
+ int resizeRet = ResizeEnvironment(palEnvironmentCapacity * 2);
+ if (resizeRet != TRUE)
+ {
+ free(copy);
+ goto done;
+ }
+ }
+
+ _ASSERTE(copy != nullptr);
+ palEnvironment[i] = copy;
+ palEnvironment[i + 1] = nullptr;
+ palEnvironmentCount++;
+
+ result = TRUE;
+ }
+ }
+done:
+
+ if (fOwningCS)
+ {
+ InternalLeaveCriticalSection(pthrCurrent, &gcsEnvironment);
+ }
+
+ return result;
+}
+
+/*++
+Function:
+ EnvironGetenv
+
+Get the value of environment variable with the given name.
+
+Parameters
+
+ name
+ [in] The name of the environment variable to get.
+ copyValue
+ [in] If this is TRUE, the function will make a copy of the
+ value and return a pointer to that. Otherwise, it will
+ return a pointer to the value in the PAL environment
+ directly. Calling this function with copyValue set to
+ FALSE is therefore unsafe without taking special pre-
+ cautions since the pointer may point to garbage later.
+
+Return Value
+
+ A pointer to the value of the environment variable if it exists,
+ or nullptr otherwise.
+
+--*/
+char* EnvironGetenv(const char* name, BOOL copyValue)
+{
+ char *retValue = nullptr;
+
+ CPalThread * pthrCurrent = InternalGetCurrentThread();
+ InternalEnterCriticalSection(pthrCurrent, &gcsEnvironment);
+
+ int nameLength = strlen(name);
+ for (int i = 0; palEnvironment[i] != nullptr; ++i)
+ {
+ if (strlen(palEnvironment[i]) < nameLength)
+ {
+ continue;
+ }
+
+ if (memcmp(palEnvironment[i], name, nameLength) == 0)
+ {
+ char *equalsSignPosition = palEnvironment[i] + nameLength;
+
+ // If this is one of the variables which has no equals sign, we
+ // treat the whole thing as name, so the value is an empty string.
+ if (*equalsSignPosition == '\0')
+ {
+ retValue = (char *)"";
+ break;
+ }
+ else if (*equalsSignPosition == '=')
+ {
+ retValue = equalsSignPosition + 1;
+ break;
+ }
+ }
+ }
+
+ if ((retValue != nullptr) && copyValue)
+ {
+ retValue = strdup(retValue);
+ }
+
+ InternalLeaveCriticalSection(pthrCurrent, &gcsEnvironment);
+ return retValue;
+}
+
+/*++
+Function:
+ EnvironGetSystemEnvironment
+
+Get a pointer to the array of pointers representing the process's
+environment.
+
+See 'man environ' for details.
+
+Return Value
+
+ A pointer to the environment.
+
+--*/
+char** EnvironGetSystemEnvironment()
+{
+ char** sysEnviron;
+
+#if HAVE__NSGETENVIRON
+ sysEnviron = *(_NSGetEnviron());
+#else // HAVE__NSGETENVIRON
+ extern char **environ;
+ sysEnviron = environ;
+#endif // HAVE__NSGETENVIRON
+
+ return sysEnviron;
+}
+
+/*++
+Function:
+ EnvironInitialize
+
+Initialization function called from PAL_Initialize.
+
+Note: This is called before debug channels are initialized, so it
+ cannot use debug tracing calls.
+--*/
+BOOL
+EnvironInitialize(void)
+{
+ BOOL ret = FALSE;
+
+ InternalInitializeCriticalSection(&gcsEnvironment);
+
+ CPalThread * pthrCurrent = InternalGetCurrentThread();
+ InternalEnterCriticalSection(pthrCurrent, &gcsEnvironment);
+
+ char** sourceEnviron = EnvironGetSystemEnvironment();
+
+ int variableCount = 0;
+ while (sourceEnviron[variableCount] != nullptr)
+ variableCount++;
+
+ palEnvironmentCount = 0;
+
+ // We need to decide how much space to allocate. Since we need enough
+ // space for all of the 'n' current environment variables, but we don't
+ // know how many more there will be, we will initially make room for
+ // '2n' variables. If even more are added, we will resize again.
+ // If there are no variables, we will still make room for 1 entry to
+ // store a nullptr there.
+ int initialSize = (variableCount == 0) ? 1 : variableCount * 2;
+
+ ret = ResizeEnvironment(initialSize);
+ if (ret == TRUE)
+ {
+ _ASSERTE(palEnvironment != nullptr);
+ for (int i = 0; i < variableCount; ++i)
+ {
+ palEnvironment[i] = strdup(sourceEnviron[i]);
+ palEnvironmentCount++;
+ }
+
+ // Set the entry after the last variable to null to indicate the end.
+ palEnvironment[variableCount] = nullptr;
+ }
+
+ InternalLeaveCriticalSection(pthrCurrent, &gcsEnvironment);
+ return ret;
+}
+
+/*++
+
+Function : _putenv.
+
+See MSDN for more details.
+
+Note: The BSD implementation can cause
+ memory leaks. See man pages for more details.
+--*/
+int
+__cdecl
+_putenv( const char * envstring )
+{
+ int ret = -1;
+
+ PERF_ENTRY(_putenv);
+ ENTRY( "_putenv( %p (%s) )\n", envstring ? envstring : "NULL", envstring ? envstring : "NULL") ;
+
+ if (envstring != nullptr)
+ {
+ ret = EnvironPutenv(envstring, TRUE) ? 0 : -1;
+ }
+ else
+ {
+ ERROR( "_putenv() called with NULL envstring!\n");
+ }
+
+ LOGEXIT( "_putenv returning %d\n", ret);
+ PERF_EXIT(_putenv);
+ return ret;
+}
+
+/*++
+
+Function : PAL_getenv
+
+See MSDN for more details.
+--*/
+char * __cdecl PAL_getenv(const char *varname)
+{
+ char *retval;
+
+ PERF_ENTRY(getenv);
+ ENTRY("getenv (%p (%s))\n", varname ? varname : "NULL", varname ? varname : "NULL");
+
+ if (strcmp(varname, "") == 0)
+ {
+ ERROR("getenv called with a empty variable name\n");
+ LOGEXIT("getenv returning NULL\n");
+ PERF_EXIT(getenv);
+ return(NULL);
+ }
+
+ retval = EnvironGetenv(varname);
+
+ LOGEXIT("getenv returning %p\n", retval);
+ PERF_EXIT(getenv);
+ return(retval);
+}
diff --git a/src/pal/src/misc/error.cpp b/src/pal/src/misc/error.cpp
new file mode 100644
index 0000000000..cb483885d5
--- /dev/null
+++ b/src/pal/src/misc/error.cpp
@@ -0,0 +1,126 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ error.c
+
+Abstract:
+
+ Implementation of Error management functions.
+
+Revision History:
+
+
+
+--*/
+
+#include "pal/thread.hpp"
+#include "pal/dbgmsg.h"
+
+using namespace CorUnix;
+
+SET_DEFAULT_DEBUG_CHANNEL(MISC);
+
+/*++
+Function:
+ SetErrorMode
+
+The SetErrorMode function controls whether the system will handle the
+specified types of serious errors, or whether the process will handle
+them.
+
+Parameters
+
+uMode
+ [in] Specifies the process error mode. This parameter can be one or more of the following values.
+
+ Value Action
+ 0 Use the system default, which is to display all error dialog boxes.
+ SEM_FAILCRITICALERRORS The system does not display the critical-error-handler message box. Instead,
+ the system sends the error to the calling process.
+ SEM_NOOPENFILEERRORBOX The system does not display a message box when it fails to find a file. Instead,
+ the error is returned to the calling process.
+
+Return Values
+
+The return value is the previous state of the error-mode bit flags.
+
+--*/
+UINT
+PALAPI
+SetErrorMode(
+ IN UINT uMode)
+{
+ PERF_ENTRY(SetErrorMode);
+ ENTRY("SetErrorMode (uMode=%#x)\n", uMode);
+
+ LOGEXIT("SetErrorMode returns UINT 0\n");
+ PERF_EXIT(SetErrorMode);
+ return 0;
+}
+
+
+/*++
+Function:
+ GetLastError
+
+GetLastError
+
+The GetLastError function retrieves the calling thread's last-error
+code value. The last-error code is maintained on a per-thread
+basis. Multiple threads do not overwrite each other's last-error code.
+
+Parameters
+
+This function has no parameters.
+
+Return Values
+
+The return value is the calling thread's last-error code
+value. Functions set this value by calling the SetLastError
+function. The Return Value section of each reference page notes the
+conditions under which the function sets the last-error code.
+
+--*/
+DWORD
+PALAPI
+GetLastError(
+ VOID)
+{
+ return CPalThread::GetLastError();
+}
+
+
+
+/*++
+Function:
+ SetLastError
+
+SetLastError
+
+The SetLastError function sets the last-error code for the calling thread.
+
+Parameters
+
+dwErrCode
+ [in] Specifies the last-error code for the thread.
+
+Return Values
+
+This function does not return a value.
+
+--*/
+VOID
+PALAPI
+SetLastError(
+ IN DWORD dwErrCode)
+{
+ CPalThread::SetLastError(dwErrCode);
+}
+
diff --git a/src/pal/src/misc/errorstrings.cpp b/src/pal/src/misc/errorstrings.cpp
new file mode 100644
index 0000000000..22443114ee
--- /dev/null
+++ b/src/pal/src/misc/errorstrings.cpp
@@ -0,0 +1,172 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ errorstrings.cpp
+
+Abstract:
+
+ Conversion of PAL error code to string
+
+Revision History:
+
+
+
+--*/
+
+#include "pal/palinternal.h"
+#include "errorstrings.h"
+
+struct ErrorString
+{
+ DWORD code;
+ LPCWSTR const string;
+};
+
+ErrorString palErrorStrings[] =
+{
+ { ERROR_SUCCESS, W("The operation completed successfully.\n") },
+ { ERROR_INVALID_FUNCTION, W("Incorrect function.\n") },
+ { ERROR_FILE_NOT_FOUND, W("The system cannot find the file specified.\n") },
+ { ERROR_PATH_NOT_FOUND, W("The system cannot find the path specified.\n") },
+ { ERROR_TOO_MANY_OPEN_FILES, W("The system cannot open the file.\n") },
+ { ERROR_ACCESS_DENIED, W("Access is denied.\n") },
+ { ERROR_INVALID_HANDLE, W("The handle is invalid.\n") },
+ { ERROR_NOT_ENOUGH_MEMORY, W("Not enough storage is available to process this command.\n") },
+ { ERROR_BAD_ENVIRONMENT, W("The environment is incorrect.\n") },
+ { ERROR_BAD_FORMAT, W("An attempt was made to load a program with an incorrect format.\n") },
+ { ERROR_INVALID_ACCESS, W("The access code is invalid.\n") },
+ { ERROR_INVALID_DATA, W("The data is invalid.\n") },
+ { ERROR_OUTOFMEMORY, W("Not enough storage is available to complete this operation.\n") },
+ { ERROR_INVALID_DRIVE, W("The system cannot find the drive specified.\n") },
+ { ERROR_NO_MORE_FILES, W("There are no more files.\n") },
+ { ERROR_WRITE_PROTECT, W("The media is write protected.\n") },
+ { ERROR_NOT_READY, W("The device is not ready.\n") },
+ { ERROR_BAD_COMMAND, W("The device does not recognize the command.\n") },
+ { ERROR_BAD_LENGTH, W("The program issued a command but the command length is incorrect.\n") },
+ { ERROR_WRITE_FAULT, W("The system cannot write to the specified device.\n") },
+ { ERROR_READ_FAULT, W("The system cannot read from the specified device.\n") },
+ { ERROR_GEN_FAILURE, W("A device attached to the system is not functioning.\n") },
+ { ERROR_SHARING_VIOLATION, W("The process cannot access the file because it is being used by another process.\n") },
+ { ERROR_LOCK_VIOLATION, W("The process cannot access the file because another process has locked a portion of the file.\n") },
+ { ERROR_SHARING_BUFFER_EXCEEDED, W("Too many files opened for sharing.\n") },
+ { ERROR_HANDLE_EOF, W("Reached the end of the file.\n") },
+ { ERROR_HANDLE_DISK_FULL, W("The disk is full.\n") },
+ { ERROR_NOT_SUPPORTED, W("The request is not supported.\n") },
+ { ERROR_DUP_NAME, W("A duplicate name exists on the network.\n") },
+ { ERROR_BAD_NETPATH, W("The network path was not found.\n") },
+ { ERROR_DEV_NOT_EXIST, W("The specified network resource or device is no longer available.\n") },
+ { ERROR_BAD_NET_NAME, W("The network name cannot be found.\n") },
+ { ERROR_FILE_EXISTS, W("The file exists.\n") },
+ { ERROR_CANNOT_MAKE, W("The directory or file cannot be created.\n") },
+ { ERROR_INVALID_PARAMETER, W("The parameter is incorrect.\n") },
+ { ERROR_NET_WRITE_FAULT, W("A write fault occurred on the network.\n") },
+ { ERROR_DRIVE_LOCKED, W("The disk is in use or locked by another process.\n") },
+ { ERROR_BROKEN_PIPE, W("The pipe has been ended.\n") },
+ { ERROR_OPEN_FAILED, W("The system cannot open the device or file specified.\n") },
+ { ERROR_BUFFER_OVERFLOW, W("The file name is too long.\n") },
+ { ERROR_DISK_FULL, W("There is not enough space on the disk.\n") },
+ { ERROR_CALL_NOT_IMPLEMENTED, W("This function is not supported on this system.\n") },
+ { ERROR_SEM_TIMEOUT, W("The semaphore timeout period has expired.\n") },
+ { ERROR_INSUFFICIENT_BUFFER, W("The data area passed to a system call is too small.\n") },
+ { ERROR_INVALID_NAME, W("The filename, directory name, or volume label syntax is incorrect.\n") },
+ { ERROR_MOD_NOT_FOUND, W("The specified module could not be found.\n") },
+ { ERROR_PROC_NOT_FOUND, W("The specified procedure could not be found.\n") },
+ { ERROR_WAIT_NO_CHILDREN, W("There are no child processes to wait for.\n") },
+ { ERROR_NEGATIVE_SEEK, W("An attempt was made to move the file pointer before the beginning of the file.\n") },
+ { ERROR_SEEK_ON_DEVICE, W("The file pointer cannot be set on the specified device or file.\n") },
+ { ERROR_DIR_NOT_EMPTY, W("The directory is not empty.\n") },
+ { ERROR_SIGNAL_REFUSED, W("The recipient process has refused the signal.\n") },
+ { ERROR_NOT_LOCKED, W("The segment is already unlocked.\n") },
+ { ERROR_BAD_PATHNAME, W("The specified path is invalid.\n") },
+ { ERROR_BUSY, W("The requested resource is in use.\n") },
+ { ERROR_INVALID_ORDINAL, W("The operating system cannot run %1.\n") },
+ { ERROR_ALREADY_EXISTS, W("Cannot create a file when that file already exists.\n") },
+ { ERROR_INVALID_EXE_SIGNATURE, W("Cannot run %1 in Win32 mode.\n") },
+ { ERROR_EXE_MARKED_INVALID, W("The operating system cannot run %1.\n") },
+ { ERROR_BAD_EXE_FORMAT, W("%1 is not a valid Win32 application.\n") },
+ { ERROR_ENVVAR_NOT_FOUND, W("The system could not find the environment option that was entered.\n") },
+ { ERROR_FILENAME_EXCED_RANGE, W("The filename or extension is too long.\n") },
+ { ERROR_PIPE_BUSY, W("All pipe instances are busy.\n") },
+ { ERROR_NO_DATA, W("The pipe is being closed\n")},
+ { ERROR_MORE_DATA, W("More data is available.\n") },
+ { ERROR_NO_MORE_ITEMS, W("No more data is available.\n") },
+ { ERROR_DIRECTORY, W("The directory name is invalid.\n") },
+ { ERROR_NOT_OWNER, W("Attempt to release mutex not owned by caller.\n") },
+ { ERROR_PARTIAL_COPY, W("Only part of a ReadProcessMemory or WriteProcessMemory request was completed.\n") },
+ { ERROR_INVALID_ADDRESS, W("Attempt to access invalid address.\n") },
+ { ERROR_ARITHMETIC_OVERFLOW, W("Arithmetic result exceeded 32 bits.\n") },
+ { ERROR_OPERATION_ABORTED, W("The I/O operation has been aborted because of either a thread exit or an application request.\n") },
+ { ERROR_IO_INCOMPLETE, W("Overlapped I/O event is not in a signaled state.\n") },
+ { ERROR_IO_PENDING, W("Overlapped I/O operation is in progress.\n") },
+ { ERROR_NOACCESS, W("Invalid access to memory location.\n") },
+ { ERROR_STACK_OVERFLOW, W("Recursion too deep; the stack overflowed.\n") },
+ { ERROR_INVALID_FLAGS, W("Invalid flags.\n") },
+ { ERROR_UNRECOGNIZED_VOLUME, W("The volume does not contain a recognized file system.\nPlease make sure that all required file system drivers are loaded and that the volume is not corrupted.\n") },
+ { ERROR_FILE_INVALID, W("The volume for a file has been externally altered so that the opened file is no longer valid.\n") },
+ { ERROR_PROCESS_ABORTED, W("The process terminated unexpectedly.\n") },
+ { ERROR_NO_UNICODE_TRANSLATION, W("No mapping for the Unicode character exists in the target multi-byte code page.\n") },
+ { ERROR_DLL_INIT_FAILED, W("A dynamic link library (DLL) initialization routine failed.\n") },
+ { ERROR_IO_DEVICE, W("The request could not be performed because of an I/O device error.\n") },
+ { ERROR_DISK_OPERATION_FAILED, W("While accessing the hard disk, a disk operation failed even after retries.\n") },
+ { ERROR_POSSIBLE_DEADLOCK, W("A potential deadlock condition has been detected.\n") },
+ { ERROR_TOO_MANY_LINKS, W("An attempt was made to create more links on a file than the file system supports.\n") },
+ { ERROR_INVALID_DLL, W("One of the library files needed to run this application is damaged.\n") },
+ { ERROR_DLL_NOT_FOUND, W("One of the library files needed to run this application cannot be found.\n") },
+ { ERROR_NOT_FOUND, W("Element not found.\n") },
+ { ERROR_CANCELLED, W("The operation was canceled by the user.\n") },
+ { ERROR_NOT_AUTHENTICATED, W("The operation being requested was not performed because the user has not been authenticated.\n") },
+ { ERROR_INTERNAL_ERROR, W("An internal error occurred.\n") },
+ { ERROR_FILE_CORRUPT, W("The file or directory is corrupted and unreadable.\n") },
+ { ERROR_DISK_CORRUPT, W("The disk structure is corrupted and unreadable.\n") },
+ { ERROR_WRONG_TARGET_NAME, W("Logon Failure: The target account name is incorrect.\n") },
+ { ERROR_NO_SYSTEM_RESOURCES, W("Insufficient system resources exist to complete the requested service.\n") },
+ { ERROR_COMMITMENT_LIMIT, W("The paging file is too small for this operation to complete.\n") },
+ { ERROR_TIMEOUT, W("This operation returned because the timeout period expired.\n") },
+ { ERROR_EVENTLOG_FILE_CORRUPT, W("The event log file is corrupted.\n") },
+ { ERROR_LOG_FILE_FULL, W("The event log file is full.\n") },
+ { ERROR_UNSUPPORTED_TYPE, W("Data of this type is not supported.\n") },
+ { RPC_S_INVALID_VERS_OPTION, W("The version option is invalid.\n") },
+ { ERROR_RESOURCE_DATA_NOT_FOUND, W("The specified image file did not contain a resource section.\n") },
+ { ERROR_RESOURCE_LANG_NOT_FOUND, W("The specified resource language ID cannot be found in the image file.\n") },
+ { ERROR_TAG_NOT_PRESENT, W("A required tag is not present.\n") }
+};
+
+int CompareErrorStrings(const void *a, const void *b)
+{
+ DWORD codeA = ((ErrorString *)a)->code;
+ DWORD codeB = ((ErrorString *)b)->code;
+
+ if (codeA < codeB)
+ {
+ return -1;
+ }
+ else if (codeA == codeB)
+ {
+ return 0;
+ }
+ else
+ {
+ return 1;
+ }
+}
+
+LPCWSTR GetPalErrorString(DWORD code)
+{
+ // Search the sorted set of resources for the ID we're interested in.
+ ErrorString searchEntry = {code, NULL};
+ ErrorString *stringEntry = (ErrorString *)bsearch(
+ &searchEntry,
+ palErrorStrings,
+ sizeof(palErrorStrings) / sizeof(palErrorStrings[0]),
+ sizeof(ErrorString),
+ CompareErrorStrings);
+
+ return (stringEntry != NULL) ? stringEntry->string : NULL;
+}
diff --git a/src/pal/src/misc/errorstrings.h b/src/pal/src/misc/errorstrings.h
new file mode 100644
index 0000000000..d24f025e32
--- /dev/null
+++ b/src/pal/src/misc/errorstrings.h
@@ -0,0 +1,10 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#ifndef _ERRORSTRINGS_H_
+#define _ERRORSTRINGS_H_
+
+LPCWSTR GetPalErrorString(DWORD code);
+
+#endif // _ERRORSTRINGS_H_
diff --git a/src/pal/src/misc/eventlog.cpp b/src/pal/src/misc/eventlog.cpp
new file mode 100644
index 0000000000..9eb67ffb1c
--- /dev/null
+++ b/src/pal/src/misc/eventlog.cpp
@@ -0,0 +1,423 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ eventlog.cpp
+
+Abstract:
+
+ (Rudimentary) implementation of Event Log.
+
+ Defaults to BSD syslog. On Mac OS X, uses the superior asl.
+
+ Caviats:
+ * Neither are real handles that you can lock. If that is necessary, the
+ PAL handle functionality can be used.
+ * Neither are kept in a table so that if you ask for the same event source
+ twice, you get the same handle.
+ * The resource file is not consulted, so we just print out the replacement
+ strings. Fortunately, for the CLR, there's the resources just have the single
+ replacement string.
+
+Revision History:
+
+ 5/21/09 -- initial
+
+
+
+--*/
+
+#include "pal/malloc.hpp"
+#include "pal/dbgmsg.h"
+
+#ifdef __APPLE__
+#define USE_ASL
+#endif // __APPLE__
+
+#ifdef USE_ASL
+#include <asl.h>
+#else // USE_ASL
+#include <syslog.h>
+#endif // USE_ASL else
+
+using namespace CorUnix;
+
+SET_DEFAULT_DEBUG_CHANNEL(MISC);
+
+HANDLE
+PALAPI
+RegisterEventSourceA (
+ IN OPTIONAL LPCSTR lpUNCServerName,
+ IN LPCSTR lpSourceName
+ )
+{
+ HANDLE hRet = INVALID_HANDLE_VALUE;
+
+ PERF_ENTRY(RegisterEventSourceA);
+ ENTRY("RegisterEventSourceA(lpUNCServerName=%p (%s), lpSourceName=%p (%s))\n",
+ lpUNCServerName, lpUNCServerName?lpUNCServerName:"NULL",
+ lpSourceName, lpSourceName?lpSourceName:"NULL");
+
+ if (NULL != lpUNCServerName)
+ {
+ SetLastError(ERROR_NOT_SUPPORTED);
+ return hRet;
+ }
+
+ if (NULL == lpSourceName)
+ {
+ ERROR("lpSourceName has to be a valid parameter\n");
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return hRet;
+ }
+
+#ifdef USE_ASL
+ // In asl parlance, the EventSource handle is an aslclient; it's not
+ // guaranteed to be the same as a different call to this with the same
+ // source name.
+ aslclient asl = asl_open(lpSourceName, NULL /* facility */, 0 /* opts */);
+ hRet = (HANDLE)asl;
+#else // USE_ASL
+ // In syslog parlance, the EventSource handle is just a string name
+ // representing the source.
+ size_t sizeSyslogHandle = strlen(lpSourceName) + 1;
+ char *syslogHandle = (char *)PAL_malloc(sizeSyslogHandle);
+ if (syslogHandle)
+ {
+ strcpy_s(syslogHandle, sizeSyslogHandle, lpSourceName);
+ hRet = (HANDLE)syslogHandle;
+ }
+#endif // USE_ASL else
+
+ if (INVALID_HANDLE_VALUE == hRet)
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+
+ LOGEXIT("RegisterEventSourceA returns %p\n", hRet);
+ PERF_EXIT(RegisterEventSourceA);
+ return hRet;
+}
+
+HANDLE
+PALAPI
+RegisterEventSourceW (
+ IN OPTIONAL LPCWSTR lpUNCServerName,
+ IN LPCWSTR lpSourceName
+ )
+{
+ HANDLE hRet = INVALID_HANDLE_VALUE;
+ int size;
+ CHAR *inBuff = NULL;
+
+ PERF_ENTRY(RegisterEventSourceW);
+ ENTRY("RegisterEventSourceW(lpUNCServerName=%p (%S), lpSourceName=%p (%S))\n",
+ lpUNCServerName, lpUNCServerName?lpUNCServerName:W16_NULLSTRING,
+ lpSourceName, lpSourceName?lpSourceName:W16_NULLSTRING);
+
+ if (NULL != lpUNCServerName)
+ {
+ SetLastError(ERROR_NOT_SUPPORTED);
+ return hRet;
+ }
+
+ size = WideCharToMultiByte(CP_ACP, 0, lpSourceName, -1, NULL, 0, NULL, NULL);
+
+ if (0 == size)
+ {
+ ERROR("lpSourceName has to be a valid parameter\n");
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return hRet;
+ }
+ inBuff = (CHAR *)PAL_malloc(size);
+ if (NULL == inBuff)
+ {
+ ERROR("malloc failed\n");
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ return hRet;
+ }
+
+ if (0 == WideCharToMultiByte(CP_ACP, 0, lpSourceName, -1, inBuff, size, NULL, NULL))
+ {
+ ASSERT( "WideCharToMultiByte failed!\n" );
+ SetLastError(ERROR_INTERNAL_ERROR);
+ goto done;
+ }
+
+ hRet = RegisterEventSourceA(NULL, inBuff);
+
+done:
+ PAL_free(inBuff);
+
+ LOGEXIT("RegisterEventSourceW returns %p\n", hRet);
+ PERF_EXIT(RegisterEventSourceW);
+ return hRet;
+}
+
+BOOL
+PALAPI
+DeregisterEventSource (
+ IN HANDLE hEventLog
+ )
+{
+ BOOL bRet = FALSE;
+
+ PERF_ENTRY(DeregisterEventSource)
+ ENTRY("DeregisterEventSource(hEventLog=%p)\n", hEventLog);
+
+ if (INVALID_HANDLE_VALUE == hEventLog ||
+ NULL == hEventLog)
+ {
+ SetLastError(ERROR_INVALID_HANDLE);
+ goto done;
+ }
+
+#ifdef USE_ASL
+ asl_close((aslclient)hEventLog);
+#else // USE_ASL
+ PAL_free(hEventLog);
+#endif // USE_ASL else
+
+ bRet = TRUE;
+
+done:
+
+ LOGEXIT("DeregisterEventSource returns BOOL %d\n", bRet);
+ PERF_EXIT(DeregisterEventSource);
+ return bRet;
+}
+
+BOOL
+PALAPI
+ReportEventA (
+ IN HANDLE hEventLog,
+ IN WORD wType,
+ IN WORD wCategory,
+ IN DWORD dwEventID,
+ IN OPTIONAL PSID lpUserSid,
+ IN WORD wNumStrings,
+ IN DWORD dwDataSize,
+ IN OPTIONAL LPCSTR *lpStrings,
+ IN OPTIONAL LPVOID lpRawData
+ )
+{
+ BOOL bRet = FALSE;
+
+ PERF_ENTRY(ReportEventA);
+ ENTRY("ReportEventA(hEventLog=%p, wType=0x%hx, wCategory=0x%hx, dwEventID=0x%x, "
+ "lpUserSid=%p, wNumStrings=%hu, dwDataSize=%u, lpStrings=%p, lpRawData=%p)\n",
+ hEventLog, wType, wCategory, dwEventID, lpUserSid, wNumStrings, dwDataSize,
+ lpStrings, lpRawData);
+
+ if (INVALID_HANDLE_VALUE == hEventLog)
+ {
+ ERROR("hEventLog has to be a valid parameter\n");
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return bRet;
+ }
+
+ if (wNumStrings > 0 && NULL == lpStrings)
+ {
+ ERROR("lpStrings has to be a valid parameter if wNumStrings is non-zero\n");
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return bRet;
+ }
+
+ if (NULL != lpUserSid || 0 != dwDataSize || 1 != wNumStrings)
+ {
+ SetLastError(ERROR_NOT_SUPPORTED);
+ return bRet;
+ }
+
+#ifdef USE_ASL
+ int level;
+ switch (wType)
+ {
+ case EVENTLOG_SUCCESS:
+ case EVENTLOG_AUDIT_SUCCESS:
+ level = ASL_LEVEL_NOTICE;
+ break;
+
+ case EVENTLOG_INFORMATION_TYPE:
+ level = ASL_LEVEL_INFO;
+ break;
+
+ case EVENTLOG_ERROR_TYPE:
+ case EVENTLOG_AUDIT_FAILURE:
+ level = ASL_LEVEL_ERR;
+ break;
+
+ case EVENTLOG_WARNING_TYPE:
+ level = ASL_LEVEL_WARNING;
+ break;
+
+ default:
+ ERROR("Unknown RecordEvent type.\n");
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return bRet;
+ }
+
+ aslmsg msg;
+ msg = asl_new(ASL_TYPE_MSG);
+ int aslRet;
+
+ if (msg)
+ {
+ char szNumber[11];
+
+ sprintf_s(szNumber, sizeof(szNumber) / sizeof(*szNumber), "%hu", wCategory);
+ aslRet = asl_set(msg, "Category", szNumber);
+ if (aslRet != 0)
+ WARN("Could not set Category %s on aslmsg (%p)", szNumber, msg);
+ sprintf_s(szNumber, sizeof(szNumber) / sizeof(*szNumber), "%u", dwEventID);
+ aslRet = asl_set(msg, "EventID", szNumber);
+ if (aslRet != 0)
+ WARN("Could not set EventID %s on aslmsg (%p)", szNumber, msg);
+
+ aslRet = asl_log((aslclient)hEventLog, msg, level, "%s", lpStrings[0]);
+
+ asl_free(msg);
+ }
+ else
+ {
+ // Yikes, fall back to worse syslog behavior due to low mem or asl issue.
+ aslRet = asl_log((aslclient)hEventLog, NULL, level, "[%hx:%x] %s", wCategory, dwEventID, lpStrings[0]);
+ }
+
+ if (aslRet != 0)
+ SetLastError(ERROR_INTERNAL_ERROR);
+ else
+ bRet = TRUE;
+#else // USE_ASL
+ int priority;
+ switch (wType)
+ {
+ case EVENTLOG_SUCCESS:
+ case EVENTLOG_AUDIT_SUCCESS:
+ case EVENTLOG_INFORMATION_TYPE:
+ priority = LOG_INFO;
+ break;
+
+ case EVENTLOG_ERROR_TYPE:
+ case EVENTLOG_AUDIT_FAILURE:
+ priority = LOG_ERR;
+ break;
+
+ case EVENTLOG_WARNING_TYPE:
+ priority = LOG_WARNING;
+ break;
+
+ default:
+ ERROR("Unknown RecordEvent type.\n");
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return bRet;
+ }
+
+ openlog((char *)hEventLog, LOG_CONS | LOG_PID, LOG_USER);
+
+ syslog(priority, "[%hx:%x] %s", wCategory, dwEventID, lpStrings[0]);
+
+ closelog();
+
+ bRet = TRUE;
+#endif // USE_ASL else
+
+ LOGEXIT("ReportEventA returns BOOL %d\n", bRet);
+ PERF_EXIT(ReportEventA);
+ return bRet;
+}
+
+BOOL
+PALAPI
+ReportEventW (
+ IN HANDLE hEventLog,
+ IN WORD wType,
+ IN WORD wCategory,
+ IN DWORD dwEventID,
+ IN OPTIONAL PSID lpUserSid,
+ IN WORD wNumStrings,
+ IN DWORD dwDataSize,
+ IN OPTIONAL LPCWSTR *lpStrings,
+ IN OPTIONAL LPVOID lpRawData
+ )
+{
+ BOOL bRet = FALSE;
+ LPCSTR *lpMBStrings = NULL;
+
+ PERF_ENTRY(ReportEventW);
+ ENTRY("ReportEventW(hEventLog=%p, wType=0x%hx, wCategory=0x%hx, dwEventID=0x%x, "
+ "lpUserSid=%p, wNumStrings=%hu, dwDataSize=%u, lpStrings=%p, lpRawData=%p)\n",
+ hEventLog, wType, wCategory, dwEventID, lpUserSid, wNumStrings, dwDataSize,
+ lpStrings, lpRawData);
+
+ if (wNumStrings > 0 && NULL == lpStrings)
+ {
+ ERROR("lpStrings has to be a valid parameter if wNumStrings is non-zero\n");
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return bRet;
+ }
+
+ if (wNumStrings > 0)
+ {
+ lpMBStrings = (LPCSTR *)PAL_malloc(wNumStrings * sizeof(CHAR *));
+ if (!lpMBStrings)
+ {
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ return bRet;
+ }
+
+ for (WORD iString = 0; iString < wNumStrings; iString++)
+ {
+ int size;
+ bool fConverted;
+ CHAR *sz;
+
+ size = WideCharToMultiByte(CP_ACP, 0, lpStrings[iString], -1, NULL, 0, NULL, NULL);
+ if (0 == size)
+ {
+ ERROR("lpStrings[%d] has to be a valid parameter\n", iString);
+ SetLastError(ERROR_INVALID_PARAMETER);
+ wNumStrings = iString; // so that free only frees earlier converted lpStrings.
+ goto done;
+ }
+
+ sz = (LPSTR)PAL_malloc(size);
+ if (!sz)
+ {
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ wNumStrings = iString; // so that free only frees earlier converted lpStrings.
+ goto done;
+ }
+ fConverted = (0 != WideCharToMultiByte(CP_ACP, 0, lpStrings[iString], -1,
+ sz, size, NULL, NULL));
+ lpMBStrings[iString] = sz; // no const-cast needed.
+ if (!fConverted)
+ {
+ ASSERT("WideCharToMultiByte failed!\n");
+ SetLastError(ERROR_INTERNAL_ERROR);
+ wNumStrings = iString + 1; // so that free only frees earlier converted lpStrings.
+ goto done;
+ }
+ }
+ }
+
+ bRet = ReportEventA(hEventLog, wType, wCategory, dwEventID, lpUserSid, wNumStrings,
+ dwDataSize, lpMBStrings, lpRawData);
+
+done:
+
+ if (wNumStrings > 0)
+ {
+ for (WORD iString = 0; iString < wNumStrings; iString++)
+ PAL_free((PVOID)lpMBStrings[iString]);
+ PAL_free(lpMBStrings);
+ }
+
+ LOGEXIT("ReportEventW returns BOOL %d\n", bRet);
+ PERF_EXIT(ReportEventW);
+ return bRet;
+}
diff --git a/src/pal/src/misc/fmtmessage.cpp b/src/pal/src/misc/fmtmessage.cpp
new file mode 100644
index 0000000000..46e0af6e0d
--- /dev/null
+++ b/src/pal/src/misc/fmtmessage.cpp
@@ -0,0 +1,701 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ fmtmessage.c
+
+Abstract:
+
+ Implementation of FormatMessage function.
+
+Revision History:
+
+
+
+--*/
+
+#include "pal/palinternal.h"
+#include "pal/dbgmsg.h"
+#include "pal/unicode_data.h"
+#include "pal/critsect.h"
+#include "pal/module.h"
+#include "pal/misc.h"
+
+#include "pal/printfcpp.hpp"
+
+#include "errorstrings.h"
+
+#include <stdarg.h>
+#if NEED_DLCOMPAT
+#include "dlcompat.h"
+#else // NEED_DLCOMPAT
+#include <dlfcn.h>
+#endif // NEED_DLCOMPAT
+#include <errno.h>
+
+SET_DEFAULT_DEBUG_CHANNEL(MISC);
+
+/* Defines */
+
+#define MAX_ERROR_STRING_LENGTH 32
+
+/*++
+Function:
+
+ FMTMSG_GetMessageString
+
+Returns the message as a wide string.
+--*/
+static LPWSTR FMTMSG_GetMessageString( DWORD dwErrCode )
+{
+ TRACE("Entered FMTMSG_GetMessageString\n");
+
+ LPCWSTR lpErrorString = GetPalErrorString(dwErrCode);
+ int allocChars;
+
+ if (lpErrorString != NULL)
+ {
+ allocChars = PAL_wcslen(lpErrorString) + 1;
+ }
+ else
+ {
+ allocChars = MAX_ERROR_STRING_LENGTH + 1;
+ }
+
+ LPWSTR lpRetVal = (LPWSTR)LocalAlloc(LMEM_FIXED, allocChars * sizeof(WCHAR));
+
+ if (lpRetVal)
+ {
+ if (lpErrorString != NULL)
+ {
+ PAL_wcscpy(lpRetVal, lpErrorString);
+ }
+ else
+ {
+ swprintf_s(lpRetVal, MAX_ERROR_STRING_LENGTH, W("Error %u"), dwErrCode);
+ }
+ }
+ else
+ {
+ ERROR("Unable to allocate memory.\n");
+ }
+
+ return lpRetVal;
+}
+
+/*++
+
+Function :
+
+ FMTMSG__watoi
+
+ Converts a wide string repersentation of an integer number
+ into a interger number.
+
+ Returns a integer number, or 0 on failure. 0 is not a valid number
+ for FormatMessage inserts.
+
+--*/
+static INT FMTMSG__watoi( LPWSTR str )
+{
+ CONST UINT MAX_NUMBER_LENGTH = 3;
+ CHAR buf[ MAX_NUMBER_LENGTH ];
+ INT nRetVal = 0;
+
+ nRetVal = WideCharToMultiByte( CP_ACP, 0, str, -1, buf,
+ MAX_NUMBER_LENGTH, NULL, 0 );
+
+ if ( nRetVal != 0 )
+ {
+ return atoi( buf );
+ }
+ else
+ {
+ ERROR( "Unable to convert the string to a number.\n" );
+ return 0;
+ }
+}
+
+/* Adds the character to the working string. */
+#define _ADD_TO_STRING( c ) \
+{\
+ TRACE( "Adding %c to the string.\n", (CHAR)c );\
+ *lpWorkingString = c;\
+ lpWorkingString++;\
+ nCount++;\
+}
+
+/* Grows the buffer. */
+#define _GROW_BUFFER() \
+{\
+ if ( bIsLocalAlloced ) \
+ { \
+ LPWSTR lpTemp = NULL; \
+ UINT NumOfBytes = 0; \
+ nSize *= 2; \
+ NumOfBytes = nSize * sizeof( WCHAR ); \
+ lpTemp = static_cast<WCHAR *>( LocalAlloc( LMEM_FIXED, NumOfBytes ) ); \
+ TRACE( "Growing the buffer.\n" );\
+ \
+ if ( !lpTemp ) \
+ { \
+ ERROR( "Out of buffer\n" ); \
+ SetLastError( ERROR_NOT_ENOUGH_MEMORY ); \
+ nCount = 0; \
+ lpWorkingString = NULL; \
+ goto exit; \
+ } \
+ \
+ *lpWorkingString = '\0';\
+ PAL_wcscpy( lpTemp, lpReturnString );\
+ LocalFree( lpReturnString ); \
+ lpWorkingString = lpReturnString = lpTemp; \
+ lpWorkingString += nCount; \
+ } \
+ else \
+ { \
+ WARN( "Out of buffer.\n" ); \
+ SetLastError( ERROR_INSUFFICIENT_BUFFER ); \
+ nCount = 0; \
+ lpWorkingString = NULL; \
+ goto exit; \
+ } \
+}
+/* Adds a character to the working string. This is a safer version
+of _ADD_TO_STRING, as we will resize the buffer if necessary. */
+#define _CHECKED_ADD_TO_STRING( c ) \
+{\
+ if ( nCount+1 == nSize ) \
+ {\
+ _GROW_BUFFER();\
+ } \
+ _ADD_TO_STRING( c );\
+}
+
+
+/*++
+Function :
+
+ FMTMSG_ProcessPrintf
+
+ Processes the printf formatters based on the format.
+
+ Returns the LPWSTR string, or NULL on failure.
+*/
+
+static LPWSTR FMTMSG_ProcessPrintf( wchar_t c ,
+ LPWSTR lpPrintfString,
+ LPWSTR lpInsertString)
+{
+ LPWSTR lpBuffer = NULL;
+ LPWSTR lpBuffer2 = NULL;
+ LPWSTR lpFormat = NULL;
+#if _DEBUG
+ // small size for _DEBUG to exercise buffer reallocation logic
+ int tmpSize = 4;
+#else
+ int tmpSize = 64;
+#endif
+ UINT nFormatLength = 0;
+ int nBufferLength = 0;
+
+ TRACE( "FMTMSG_ProcessPrintf( %C, %S, %S )\n", c,
+ lpPrintfString, lpInsertString );
+
+ switch ( c )
+ {
+ case 'e' :
+ /* Fall through */
+ case 'E' :
+ /* Fall through */
+ case 'f' :
+ /* Fall through */
+ case 'g' :
+ /* Fall through */
+ case 'G' :
+ ERROR( "%%%c is not supported by FormatMessage.\n", c );
+ SetLastError( ERROR_INVALID_PARAMETER );
+ return NULL;
+ }
+
+ nFormatLength = PAL_wcslen( lpPrintfString ) + 2; /* Need to count % AND NULL */
+ lpFormat = (LPWSTR)PAL_malloc( nFormatLength * sizeof( WCHAR ) );
+ if ( !lpFormat )
+ {
+ ERROR( "Unable to allocate memory.\n" );
+ SetLastError( ERROR_NOT_ENOUGH_MEMORY );
+ return NULL;
+ }
+ /* Create the format string. */
+ memset( lpFormat, 0, nFormatLength * sizeof(WCHAR) );
+ *lpFormat = '%';
+
+ PAL_wcscat( lpFormat, lpPrintfString );
+
+ lpBuffer = (LPWSTR) PAL_malloc(tmpSize*sizeof(WCHAR));
+
+ /* try until the buffer is big enough */
+ while (TRUE)
+ {
+ if (!lpBuffer)
+ {
+ ERROR("Unable to allocate memory\n");
+ SetLastError( ERROR_NOT_ENOUGH_MEMORY );
+ PAL_free(lpFormat);
+ return NULL;
+ }
+ nBufferLength = _snwprintf_s( lpBuffer, tmpSize, tmpSize,
+ lpFormat, lpInsertString);
+
+ if ((nBufferLength >= 0) && (nBufferLength != tmpSize))
+ {
+ break; /* succeeded */
+ }
+ else
+ {
+ tmpSize *= 2;
+ lpBuffer2 = static_cast<WCHAR *>(
+ PAL_realloc(lpBuffer, tmpSize*sizeof(WCHAR)));
+ if (lpBuffer2 == NULL)
+ PAL_free(lpBuffer);
+ lpBuffer = lpBuffer2;
+ }
+ }
+
+ PAL_free( lpFormat );
+ lpFormat = NULL;
+
+ return lpBuffer;
+}
+
+/*++
+Function:
+ FormatMessageW
+
+See MSDN doc.
+--*/
+DWORD
+PALAPI
+FormatMessageW(
+ IN DWORD dwFlags,
+ IN LPCVOID lpSource,
+ IN DWORD dwMessageId,
+ IN DWORD dwLanguageId,
+ OUT LPWSTR lpBuffer,
+ IN DWORD nSize,
+ IN va_list *Arguments)
+{
+ BOOL bIgnoreInserts = FALSE;
+ BOOL bIsVaList = TRUE;
+ BOOL bIsLocalAlloced = FALSE;
+ LPWSTR lpSourceString = NULL;
+ UINT nCount = 0;
+ LPWSTR lpReturnString = NULL;
+ LPWSTR lpWorkingString = NULL;
+
+
+ PERF_ENTRY(FormatMessageW);
+ ENTRY( "FormatMessageW(dwFlags=%#x, lpSource=%p, dwMessageId=%#x, "
+ "dwLanguageId=%#x, lpBuffer=%p, nSize=%u, va_list=%p)\n",
+ dwFlags, lpSource, dwMessageId, dwLanguageId, lpBuffer, nSize,
+ Arguments);
+
+ /* Sanity checks. */
+ if ( dwFlags & FORMAT_MESSAGE_FROM_STRING && !lpSource )
+ {
+ /* This behavior is different then in Windows.
+ Windows would just crash.*/
+ ERROR( "lpSource cannot be NULL.\n" );
+ SetLastError( ERROR_INVALID_PARAMETER );
+ goto exit;
+ }
+
+ if ( !(dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER ) && !lpBuffer )
+ {
+ /* This behavior is different then in Windows.
+ Windows would just crash.*/
+ ERROR( "lpBuffer cannot be NULL, if "
+ " FORMAT_MESSAGE_ALLOCATE_BUFFER is not specified.\n" );
+ SetLastError( ERROR_INVALID_PARAMETER );
+ goto exit;
+ }
+
+ if ( ( dwFlags & FORMAT_MESSAGE_FROM_STRING ) &&
+ ( dwFlags & FORMAT_MESSAGE_FROM_SYSTEM ) )
+ {
+ ERROR( "These flags cannot co-exist. You can either "
+ "specify FORMAT_MESSAGE_FROM_STRING, or "
+ "FORMAT_MESSAGE_FROM_SYSTEM.\n" );
+ SetLastError( ERROR_INVALID_PARAMETER );
+ goto exit;
+ }
+
+ if ( !( dwFlags & FORMAT_MESSAGE_FROM_STRING ) &&
+ ( dwLanguageId != 0
+#if ENABLE_DOWNLEVEL_FOR_NLS
+ && dwLanguageId != MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT )
+#endif
+ ) )
+ {
+ ERROR( "Invalid language indentifier.\n" );
+ SetLastError( ERROR_RESOURCE_LANG_NOT_FOUND );
+ goto exit;
+ }
+
+ /* Parameter processing. */
+ if ( dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER )
+ {
+ TRACE( "Allocated %d TCHARs. Don't forget to call LocalFree to "
+ "free the memory when done.\n", nSize );
+ bIsLocalAlloced = TRUE;
+ }
+
+ if ( dwFlags & FORMAT_MESSAGE_IGNORE_INSERTS )
+ {
+ bIgnoreInserts = TRUE;
+ }
+
+ if ( dwFlags & FORMAT_MESSAGE_ARGUMENT_ARRAY )
+ {
+ if ( !Arguments && !bIgnoreInserts )
+ {
+ ERROR( "The va_list cannot be NULL.\n" );
+ SetLastError( ERROR_INVALID_PARAMETER );
+ goto exit;
+ }
+ else
+ {
+ bIsVaList = FALSE;
+ }
+ }
+
+ if ( dwFlags & FORMAT_MESSAGE_FROM_STRING )
+ {
+ lpSourceString = (LPWSTR)lpSource;
+ }
+ else if ( dwFlags & FORMAT_MESSAGE_FROM_SYSTEM )
+ {
+ if ((dwMessageId & 0xFFFF0000) == 0x80070000)
+ {
+ // This message has been produced by HRESULT_FROM_WIN32. Undo its work.
+ dwMessageId &= 0xFFFF;
+ }
+
+ lpWorkingString = lpReturnString =
+ FMTMSG_GetMessageString( dwMessageId );
+
+ if ( !lpWorkingString )
+ {
+ ERROR( "Unable to find the message %d.\n", dwMessageId );
+ SetLastError( ERROR_INTERNAL_ERROR );
+ nCount = 0;
+ goto exit;
+ }
+
+ nCount = PAL_wcslen( lpWorkingString );
+
+ if ( !bIsLocalAlloced && nCount > nSize )
+ {
+ ERROR( "Insufficient buffer.\n" );
+ SetLastError( ERROR_INSUFFICIENT_BUFFER );
+ lpWorkingString = NULL;
+ nCount = 0;
+ goto exit;
+ }
+ if ( !lpWorkingString )
+ {
+ ERROR( "Invalid error indentifier.\n" );
+ SetLastError( ERROR_INVALID_ADDRESS );
+ }
+ goto exit;
+ }
+ else
+ {
+ ERROR( "Unknown flag.\n" );
+ SetLastError( ERROR_INVALID_PARAMETER );
+ goto exit;
+ }
+
+ if ( nSize == 0 && bIsLocalAlloced )
+ {
+ nSize = 1;
+ }
+
+ lpWorkingString = static_cast<WCHAR *>(
+ LocalAlloc( LMEM_FIXED, nSize * sizeof( WCHAR ) ) );
+ if ( !lpWorkingString )
+ {
+ ERROR( "Unable to allocate memory for the working string.\n" );
+ SetLastError( ERROR_INSUFFICIENT_BUFFER );
+ goto exit;
+ }
+
+
+ /* Process the string. */
+ lpReturnString = lpWorkingString;
+ while ( *lpSourceString )
+ {
+ if ( *lpSourceString == '%' && !bIgnoreInserts )
+ {
+ lpSourceString++;
+ /* Escape sequences. */
+ if ( *lpSourceString == '0' )
+ {
+ /* Terminates a message without a newline character. */
+ *lpWorkingString = '\0';
+ goto exit;
+ }
+ else if ( PAL_iswdigit( *lpSourceString ) )
+ {
+ /* Get the insert number. */
+ WCHAR Number[] = { '\0', '\0', '\0' };
+ SIZE_T Index = 0;
+
+ Number[ 0 ] = *lpSourceString;
+ lpSourceString++;
+
+ if ( PAL_iswdigit( *lpSourceString ) )
+ {
+ Number[ 1 ] = *lpSourceString;
+ lpSourceString++;
+ if ( PAL_iswdigit( *lpSourceString ) )
+ {
+ ERROR( "Invalid insert indentifier.\n" );
+ SetLastError( ERROR_INVALID_PARAMETER );
+ lpWorkingString = NULL;
+ nCount = 0;
+ goto exit;
+ }
+ }
+ Index = FMTMSG__watoi( Number );
+ if ( Index == 0 )
+ {
+ ERROR( "Invalid insert indentifier.\n" );
+ SetLastError( ERROR_INVALID_PARAMETER );
+ lpWorkingString = NULL;
+ nCount = 0;
+ goto exit;
+ }
+ if ( *lpSourceString == '!' )
+ {
+ LPWSTR lpInsertString = NULL;
+ LPWSTR lpPrintfString = NULL;
+ LPWSTR lpStartOfFormattedString = NULL;
+ UINT nPrintfLength = 0;
+ LPWSTR lpFormattedString = NULL;
+ UINT nFormattedLength = 0;
+
+ if ( !bIsVaList )
+ {
+ lpInsertString = ((LPWSTR*)Arguments)[ Index - 1 ];
+ }
+ else
+ {
+ va_list TheArgs;
+
+ va_copy(TheArgs, *Arguments);
+ UINT i = 0;
+ for ( ; i < Index; i++ )
+ {
+ lpInsertString = va_arg( TheArgs, LPWSTR );
+ }
+ }
+
+ /* Calculate the length, and extract the printf string.*/
+ lpSourceString++;
+ {
+ LPWSTR p = PAL_wcschr( lpSourceString, '!' );
+
+ if ( NULL == p )
+ {
+ nPrintfLength = 0;
+ }
+ else
+ {
+ nPrintfLength = p - lpSourceString;
+ }
+ }
+
+ lpPrintfString =
+ (LPWSTR)PAL_malloc( ( nPrintfLength + 1 ) * sizeof( WCHAR ) );
+
+ if ( !lpPrintfString )
+ {
+ ERROR( "Unable to allocate memory.\n" );
+ SetLastError( ERROR_NOT_ENOUGH_MEMORY );
+ lpWorkingString = NULL;
+ nCount = 0;
+ goto exit;
+ }
+
+ PAL_wcsncpy( lpPrintfString, lpSourceString, nPrintfLength );
+ *( lpPrintfString + nPrintfLength ) = '\0';
+
+ lpStartOfFormattedString = lpFormattedString =
+ FMTMSG_ProcessPrintf( *lpPrintfString,
+ lpPrintfString,
+ lpInsertString);
+
+ if ( !lpFormattedString )
+ {
+ ERROR( "Unable to process the format string.\n" );
+ /* Function will set the error code. */
+ PAL_free( lpPrintfString );
+ lpWorkingString = NULL;
+ goto exit;
+ }
+
+
+ nFormattedLength = PAL_wcslen( lpFormattedString );
+
+ /* Append the processed printf string into the working string */
+ while ( *lpFormattedString )
+ {
+ _CHECKED_ADD_TO_STRING( *lpFormattedString );
+ lpFormattedString++;
+ }
+
+ lpSourceString += nPrintfLength + 1;
+ PAL_free( lpPrintfString );
+ PAL_free( lpStartOfFormattedString );
+ lpPrintfString = lpFormattedString = NULL;
+ }
+ else
+ {
+ /* The printf format string defaults to 's'.*/
+ LPWSTR lpInsert = NULL;
+
+ if ( !bIsVaList )
+ {
+ lpInsert = ((LPWSTR*)Arguments)[Index - 1];
+ }
+ else
+ {
+ va_list TheArgs;
+ va_copy(TheArgs, *Arguments);
+ UINT i = 0;
+ for ( ; i < Index; i++ )
+ {
+ lpInsert = va_arg( TheArgs, LPWSTR );
+ }
+ }
+
+ while ( *lpInsert )
+ {
+ _CHECKED_ADD_TO_STRING( *lpInsert );
+ lpInsert++;
+ }
+ }
+ }
+ /* Format specifiers. */
+ else if ( *lpSourceString == '%' )
+ {
+ _CHECKED_ADD_TO_STRING( '%' );
+ lpSourceString++;
+ }
+ else if ( *lpSourceString == 'n' )
+ {
+ /* Hard line break. */
+ _CHECKED_ADD_TO_STRING( '\n' );
+ lpSourceString++;
+ }
+ else if ( *lpSourceString == '.' )
+ {
+ _CHECKED_ADD_TO_STRING( '.' );
+ lpSourceString++;
+ }
+ else if ( *lpSourceString == '!' )
+ {
+ _CHECKED_ADD_TO_STRING( '!' );
+ lpSourceString++;
+ }
+ else if ( !*lpSourceString )
+ {
+ ERROR( "Invalid parameter.\n" );
+ SetLastError( ERROR_INVALID_PARAMETER );
+ lpWorkingString = NULL;
+ nCount = 0;
+ goto exit;
+ }
+ else /* Append the character. */
+ {
+ _CHECKED_ADD_TO_STRING( *lpSourceString );
+ lpSourceString++;
+ }
+ }/* END if ( *lpSourceString == '%' ) */
+ else
+ {
+ /* In Windows if FormatMessage is called with ignore inserts,
+ then FormatMessage strips %1!s! down to %1, since string is the
+ default. */
+ if ( bIgnoreInserts && *lpSourceString == '!' &&
+ *( lpSourceString + 1 ) == 's' )
+ {
+ LPWSTR lpLastBang = PAL_wcschr( lpSourceString + 1, '!' );
+
+ if ( lpLastBang && ( 2 == lpLastBang - lpSourceString ) )
+ {
+ lpSourceString = lpLastBang + 1;
+ }
+ else
+ {
+ ERROR( "Mal-formed string\n" );
+ SetLastError( ERROR_INVALID_PARAMETER );
+ lpWorkingString = NULL;
+ nCount = 0;
+ goto exit;
+ }
+ }
+ else
+ {
+ /* Append to the string. */
+ _CHECKED_ADD_TO_STRING( *lpSourceString );
+ lpSourceString++;
+ }
+ }
+ }
+
+ /* Terminate the message. */
+ _CHECKED_ADD_TO_STRING( '\0' );
+ /* NULL does not count. */
+ nCount--;
+
+exit: /* Function clean-up and exit. */
+ if ( lpWorkingString )
+ {
+ if ( bIsLocalAlloced )
+ {
+ TRACE( "Assigning the buffer to the pointer.\n" );
+ // when FORMAT_MESSAGE_ALLOCATE_BUFFER is specified, nSize
+ // does not specify the size of lpBuffer, rather it specifies
+ // the minimum size of the string
+ // as such we have to blindly assume that lpBuffer has enough space to
+ // store PVOID
+ // might cause a prefast warning, but there is no good way to suppress it yet
+ _ASSERTE(dwFlags & FORMAT_MESSAGE_ALLOCATE_BUFFER);
+ *((LPVOID*)lpBuffer) = (LPVOID)lpReturnString;
+ }
+ else /* Only delete lpReturnString if the caller has their own buffer.*/
+ {
+ TRACE( "Copying the string into the buffer.\n" );
+ PAL_wcsncpy( lpBuffer, lpReturnString, nCount + 1 );
+ LocalFree( lpReturnString );
+ }
+ }
+ else /* Error, something occurred. */
+ {
+ if ( lpReturnString )
+ {
+ LocalFree( lpReturnString );
+ }
+ }
+ LOGEXIT( "FormatMessageW returns %d.\n", nCount );
+ PERF_EXIT(FormatMessageW);
+ return nCount;
+}
diff --git a/src/pal/src/misc/identity.cpp b/src/pal/src/misc/identity.cpp
new file mode 100644
index 0000000000..e983b1265c
--- /dev/null
+++ b/src/pal/src/misc/identity.cpp
@@ -0,0 +1,410 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+misc/identity.cpp
+
+Abstract:
+
+Implementation of GetComputerNameW and GetUserNameW functions.
+
+
+
+--*/
+
+#include "pal/palinternal.h"
+#include "pal/dbgmsg.h"
+#include "pal/misc.h"
+#include "pal/thread.hpp"
+#include "pal/identity.hpp"
+#include "pal/malloc.hpp"
+
+#include <pwd.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+
+#if HAVE_SYSCONF && defined(_SC_GETPW_R_SIZE_MAX)
+#include <limits.h> // for INT_MAX
+#endif
+
+using namespace CorUnix;
+
+SET_DEFAULT_DEBUG_CHANNEL(MISC);
+
+#if HAVE_GETPWUID_R
+
+#define DEFAULT_PASSWORD_BUFFER_SIZE 1024
+static DWORD dwInitialPasswdBufferSize = DEFAULT_PASSWORD_BUFFER_SIZE;
+
+#else // HAVE_GETPWUID_R
+
+static CRITICAL_SECTION identity_critsec;
+
+#endif // HAVE_GETPWUID_R
+
+
+/*++
+Function:
+ IdentityInitialize
+
+Intitialization function called from PAL_Initialize.
+Initializes the critical section for the case when thread-safe
+getpwuid_r is not available.
+
+--*/
+BOOL
+IdentityInitialize(void)
+{
+#if HAVE_GETPWUID_R
+
+#if HAVE_SYSCONF && defined(_SC_GETPW_R_SIZE_MAX)
+ long lBufferSize = 0;
+ lBufferSize = sysconf(_SC_GETPW_R_SIZE_MAX);
+
+ if ((long)INT_MAX < lBufferSize)
+ {
+ ERROR("sysconf(_SC_GETPW_R_SIZE_MAX) returns %ld which is > INT_MAX (%u)\n",
+ lBufferSize, INT_MAX);
+ return FALSE;
+ }
+
+ if (0 >= (int)(lBufferSize))
+ {
+ WARN("sysconf(_SC_GETPW_R_SIZE_MAX) returns %ld, using %u as the buffer size instead\n",
+ lBufferSize, dwInitialPasswdBufferSize);
+ }
+ else
+ {
+ TRACE("sysconf(_SC_GETPW_R_SIZE_MAX) returns %ld\n", lBufferSize);
+ dwInitialPasswdBufferSize = (DWORD)lBufferSize;
+ }
+
+#endif // HAVE_SYSCONF && _SC_GETPW_R_SIZE_MAX
+
+#else // HAVE_GETPWUID_R
+
+ InternalInitializeCriticalSection(&identity_critsec);
+
+#endif // HAVE_GETPWUID_R
+
+ return TRUE;
+}
+
+
+/*++
+Function:
+ IdentityCleanup
+
+Termination function called from PAL_Terminate.
+Deletes the critical section for the case when thread-safe
+getpwuid_r is not available.
+
+--*/
+void
+IdentityCleanup(void)
+{
+#if !HAVE_GETPWUID_R
+ InternalDeleteCriticalSection(&identity_critsec);
+#endif
+}
+
+/*++
+Function:
+ GetUserNameW
+
+Uses getpwuid_r to get the user name and if it's not available uses
+getpwuid (with the safety of a critical section). See MSDN for functional spec.
+
+--*/
+PALIMPORT
+BOOL
+PALAPI
+GetUserNameW(
+ OUT LPWSTR lpBuffer, // address of name buffer
+ IN OUT LPDWORD nSize ) // address of size of name buffer
+{
+ BOOL fRet = FALSE;
+ struct passwd *pPasswd = NULL;
+ char *szUserName = NULL;
+ DWORD cwchLen = 0;
+ int iEuid = -1;
+ int iRet = -1;
+ CPalThread *pPalThread = InternalGetCurrentThread();
+
+#if HAVE_GETPWUID_R
+
+ char *pchBuffer = NULL;
+ DWORD dwBufLen = 0;
+ struct passwd sPasswd;
+
+#endif // HAVE_GETPWUID_R
+
+ PERF_ENTRY(GetUserNameW);
+ ENTRY("GetUserNameW(lpBuffer = %p, nSize = %p (%d)\n",
+ lpBuffer, nSize, nSize?*nSize:0);
+
+ iEuid = geteuid();
+
+ if (NULL == lpBuffer || NULL == nSize)
+ {
+ ERROR("lpBuffer == NULL or nSize == NULL");
+ pPalThread->SetLastError(ERROR_INVALID_PARAMETER);
+ goto done;
+ }
+
+#if HAVE_GETPWUID_R
+
+ dwBufLen = dwInitialPasswdBufferSize;
+
+ while (NULL == pPasswd)
+ {
+ pchBuffer = (char*) PAL_malloc(sizeof(pchBuffer[0]) * dwBufLen);
+ if (NULL == pchBuffer)
+ {
+ pPalThread->SetLastError(ERROR_OUTOFMEMORY);
+ goto done;
+ }
+
+ iRet = InternalGetpwuid_r(pPalThread, iEuid, &sPasswd, pchBuffer, dwBufLen, &pPasswd);
+ if (0 != iRet)
+ {
+ WARN("getpwuid_r(%d) returns %d for a buffer size of %d, error string is %s\n",
+ iEuid, iRet, dwBufLen, strerror(iRet));
+
+ if (ERANGE == iRet) // need a bigger buffer
+ {
+ PAL_free(pchBuffer);
+ pchBuffer = NULL;
+ pPasswd = NULL;
+ dwBufLen *= 2; // double the buffer
+ continue; // try again
+ }
+
+ pPalThread->SetLastError(ERROR_INTERNAL_ERROR);
+ goto done;
+ }
+
+ // Unfortunately, HPUX returns success and result = NULL even when the buffer size is small
+ // (instead of returning ERANGE error). But, since we are using either
+ // sysconf(_SC_GETPW_R_SIZE_MAX) or the HP recommended value of 1024, buffer should always
+ // be big enough for getpwuid_r.
+
+ if (NULL == pPasswd || NULL == pPasswd->pw_name)
+ {
+ // No matching entry found! something failed somewhere.
+ ERROR("getpwuid_r(%d) returned %p with name NULL!\n", iEuid, pPasswd);
+ pPalThread->SetLastError(ERROR_INTERNAL_ERROR);
+ goto done;
+ }
+ }
+
+ szUserName = pPasswd->pw_name;
+
+#else // HAVE_GETPWUID_R
+
+ InternalEnterCriticalSection(pPalThread, &identity_critsec);
+ pPasswd = getpwuid(iEuid);
+
+ if ((NULL == pPasswd) || (NULL == pPasswd->pw_name))
+ {
+ InternalLeaveCriticalSection(pPalThread, &identity_critsec);
+ ERROR("getpwuid(%d) returned %p with name NULL! error (%d) is %s\n",
+ iEuid, pPasswd, errno, strerror(errno));
+ pPalThread->SetLastError(ERROR_INTERNAL_ERROR);
+ goto done;
+ }
+
+ // make a copy so that we can modify it
+ szUserName = strdup(pPasswd->pw_name);
+ if (NULL == szUserName)
+ {
+ InternalLeaveCriticalSection(pPalThread, &identity_critsec);
+ pPalThread->SetLastError(ERROR_OUTOFMEMORY);
+ goto done;
+ }
+
+ InternalLeaveCriticalSection(pPalThread, &identity_critsec);
+#endif // HAVE_GETPWUID_R
+
+ // truncate the user name if it exceeds the maximum allowed limit
+ if (strlen(szUserName) > UNLEN)
+ {
+ szUserName[UNLEN] = '\0';
+ }
+
+ // Copy from pPasswd->pw_name
+ cwchLen = MultiByteToWideChar(CP_ACP, 0, szUserName, -1, lpBuffer, *nSize);
+ if (0 == cwchLen)
+ {
+ ERROR ("MultiByteToWideChar failed with error %d when trying to convert the username "
+ "%s to wide char\n", pPalThread->GetLastError(), szUserName);
+ if (ERROR_INSUFFICIENT_BUFFER == pPalThread->GetLastError())
+ {
+ // Find the required size (including NULL)
+ cwchLen = MultiByteToWideChar(CP_ACP, 0, szUserName, -1, NULL, 0);
+ if (0 == cwchLen)
+ {
+ ERROR ("MultiByteToWideChar failed with error %d when trying to find the size of "
+ "%s in wide chars\n", pPalThread->GetLastError(), szUserName);
+ pPalThread->SetLastError(ERROR_INTERNAL_ERROR);
+ }
+ else
+ {
+ // Update the required size
+ *nSize = cwchLen;
+ pPalThread->SetLastError(ERROR_MORE_DATA);
+ }
+ }
+ goto done;
+ }
+
+ *nSize = cwchLen;
+ fRet = TRUE;
+
+done:
+#if HAVE_GETPWUID_R
+ if (NULL != pchBuffer)
+ {
+ PAL_free(pchBuffer);
+ }
+#else // HAVE_GETPWUID_R
+ if (NULL != szUserName)
+ {
+ PAL_free(szUserName);
+ }
+#endif // HAVE_GETPWUID_R
+
+ LOGEXIT("GetUserNameW returning BOOL %d\n", fRet);
+ PERF_EXIT(GetUserNameW);
+ return fRet;
+}
+
+#ifndef MAXHOSTNAMELEN
+// AIX doesn't have MAXHOSTNAMELEN, it recommends using 256
+#define MAXHOSTNAMELEN 256
+#endif // MAXHOSTNAMELEN
+
+/*++
+Function:
+ GetComputerNameW
+
+Uses gethostname to get the computer name. See MSDN for functional spec.
+
+--*/
+PALIMPORT
+BOOL
+PALAPI
+GetComputerNameW(
+ OUT LPWSTR lpBuffer, // address of name buffer
+ IN OUT LPDWORD nSize) // address of size of name buffer
+{
+ BOOL fRet = FALSE;
+ char szHostName[MAXHOSTNAMELEN+1];
+ char *pchDot = NULL;
+ DWORD cwchLen = 0;
+ CPalThread *pPalThread = InternalGetCurrentThread();
+
+ PERF_ENTRY(GetComputerNameW);
+ ENTRY("GetComputerNameW(lpBuffer = %p, nSize = %p (%d)\n",
+ lpBuffer, nSize, nSize?*nSize:0);
+
+ if (NULL == lpBuffer || NULL == nSize)
+ {
+ ERROR("lpBuffer == NULL or nSize == NULL");
+ pPalThread->SetLastError(ERROR_INVALID_PARAMETER);
+ goto done;
+ }
+
+ if (0 != gethostname(szHostName, sizeof(szHostName)/sizeof(szHostName[0])))
+ {
+ ERROR("gethostname failed with error (%d) %s\n", errno, strerror(errno));
+ pPalThread->SetLastError(ERROR_INTERNAL_ERROR);
+ goto done;
+ }
+
+ // Null terminate the string
+ szHostName[sizeof(szHostName)/sizeof(szHostName[0])-1] = '\0';
+
+ // some OSes return the hostname with the domain name included.
+ // We want to return only the host part of the name (see the spec for
+ // more details
+ pchDot = strchr(szHostName, '.');
+ if (NULL != pchDot)
+ {
+ *pchDot = '\0'; // remove the domain name info
+ }
+
+ // copy the hostname (including NULL character)
+ cwchLen = MultiByteToWideChar(CP_ACP, 0, szHostName, -1, lpBuffer, *nSize);
+ if (0 == cwchLen)
+ {
+ ERROR ("MultiByteToWideChar failed with error %d when trying to convert the hostname "
+ "%s to wide char\n", pPalThread->GetLastError(), szHostName);
+ if (ERROR_INSUFFICIENT_BUFFER == pPalThread->GetLastError())
+ {
+ // Find the required size (including NULL)
+ cwchLen = MultiByteToWideChar(CP_ACP, 0, szHostName, -1, NULL, 0);
+ if (0 == cwchLen)
+ {
+ ERROR ("MultiByteToWideChar failed with error %d when trying to find the size of "
+ "%s in wide chars\n", pPalThread->GetLastError(), szHostName);
+ pPalThread->SetLastError(ERROR_INTERNAL_ERROR);
+ }
+ else
+ {
+ // Update the required size
+ *nSize = cwchLen - 1; // don't include the NULL
+ pPalThread->SetLastError(ERROR_BUFFER_OVERFLOW);
+ }
+ }
+ goto done;
+ }
+
+ *nSize = cwchLen - 1; // don't include the NULL
+ fRet = TRUE;
+
+done:
+ LOGEXIT("GetComputerNameW returning BOOL %d\n", fRet);
+ PERF_EXIT(GetComputerNameW);
+ return fRet;
+}
+
+#if HAVE_GETPWUID_R
+/*++
+Function:
+ InternalGetpwuid_r
+
+Suspension safe wrapper for getpwuid_r
+--*/
+int
+CorUnix::InternalGetpwuid_r(
+ CPalThread *pPalThread,
+ uid_t uid,
+ struct passwd *pPasswd,
+ char *pchBuffer,
+ size_t nBufSize,
+ struct passwd **ppResult
+ )
+{
+ int iError = 0;
+
+ iError = getpwuid_r(uid, pPasswd, pchBuffer, nBufSize, ppResult);
+
+#if GETPWUID_R_SETS_ERRNO
+ if (0 != iError)
+ {
+ iError = errno; // some systems (AIX) sets errno instead of returning error
+ }
+#endif // GETPWUID_R_SETS_ERRNO
+
+ return iError;
+}
+#endif // HAVE_GETPWUID_R
diff --git a/src/pal/src/misc/miscpalapi.cpp b/src/pal/src/misc/miscpalapi.cpp
new file mode 100644
index 0000000000..0e1234401e
--- /dev/null
+++ b/src/pal/src/misc/miscpalapi.cpp
@@ -0,0 +1,381 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ miscpalapi.c
+
+Abstract:
+
+ Implementation misc PAL APIs
+
+Revision History:
+
+
+
+--*/
+
+#include "pal/palinternal.h"
+#include "pal/dbgmsg.h"
+#include "pal/file.h"
+#include "pal/process.h"
+#include "pal/module.h"
+#include "pal/malloc.hpp"
+#include "pal/stackstring.hpp"
+
+#include <errno.h>
+#include <unistd.h>
+#include <time.h>
+#include <pthread.h>
+#include <dlfcn.h>
+
+#if HAVE_BSD_UUID_H
+#include <uuid.h>
+#elif HAVE_LIBUUID_H
+#include <uuid/uuid.h>
+#endif
+
+#include <pal_endian.h>
+
+#ifdef __APPLE__
+#include <mach-o/dyld.h>
+#endif // __APPLE__
+
+SET_DEFAULT_DEBUG_CHANNEL(MISC);
+
+static const char RANDOM_DEVICE_NAME[] ="/dev/random";
+static const char URANDOM_DEVICE_NAME[]="/dev/urandom";
+
+/*++
+
+Function :
+
+ PAL_GetPALDirectoryW
+
+ Returns the fully qualified path name
+ where the PALL DLL was loaded from.
+
+ On failure it returns FALSE and sets the
+ proper LastError code.
+
+--*/
+BOOL
+PAL_GetPALDirectoryW(PathWCharString& lpDirectoryName)
+{
+ LPCWSTR lpFullPathAndName = NULL;
+ LPCWSTR lpEndPoint = NULL;
+ BOOL bRet = FALSE;
+
+ PERF_ENTRY(PAL_GetPALDirectoryW);
+
+ MODSTRUCT *module = LOADGetPalLibrary();
+ if (!module)
+ {
+ SetLastError(ERROR_INTERNAL_ERROR);
+ goto EXIT;
+ }
+ lpFullPathAndName = module->lib_name;
+ if (lpFullPathAndName == NULL)
+ {
+ SetLastError(ERROR_INTERNAL_ERROR);
+ goto EXIT;
+ }
+ lpEndPoint = PAL_wcsrchr( lpFullPathAndName, '/' );
+ if ( lpEndPoint )
+ {
+ /* The path that we return is required to have
+ the trailing slash on the end.*/
+ lpEndPoint++;
+
+
+ if(!lpDirectoryName.Set(lpFullPathAndName,lpEndPoint - lpFullPathAndName))
+ {
+ ASSERT( "The buffer was not large enough.\n" );
+ SetLastError( ERROR_INSUFFICIENT_BUFFER );
+ goto EXIT;
+ }
+
+ bRet = TRUE;
+ }
+ else
+ {
+ ASSERT( "Unable to determine the path.\n" );
+ /* Error path, should not be executed. */
+ SetLastError( ERROR_INTERNAL_ERROR );
+ }
+
+EXIT:
+ PERF_EXIT(PAL_GetPALDirectoryW);
+ return bRet;
+}
+
+BOOL
+PAL_GetPALDirectoryA(PathCharString& lpDirectoryName)
+{
+ BOOL bRet;
+ PathWCharString directory;
+
+ PERF_ENTRY(PAL_GetPALDirectoryA);
+
+ bRet = PAL_GetPALDirectoryW(directory);
+
+ if (bRet)
+ {
+
+ int length = WideCharToMultiByte(CP_ACP, 0, directory.GetString(), -1, NULL, 0, NULL, 0);
+ LPSTR DirectoryName = lpDirectoryName.OpenStringBuffer(length);
+ if (NULL == DirectoryName)
+ {
+ SetLastError( ERROR_INSUFFICIENT_BUFFER );
+ bRet = FALSE;
+ }
+
+ length = WideCharToMultiByte(CP_ACP, 0, directory.GetString(), -1, DirectoryName, length, NULL, 0);
+
+ if (0 == length)
+ {
+ bRet = FALSE;
+ length++;
+ }
+
+ lpDirectoryName.CloseBuffer(length - 1);
+ }
+
+ PERF_EXIT(PAL_GetPALDirectoryA);
+ return bRet;
+}
+
+/*++
+
+Function :
+
+ PAL_GetPALDirectoryW
+
+ Returns the fully qualified path name
+ where the PALL DLL was loaded from.
+
+ On failure it returns FALSE and sets the
+ proper LastError code.
+
+See rotor_pal.doc for more details.
+
+--*/
+PALIMPORT
+BOOL
+PALAPI
+PAL_GetPALDirectoryW( OUT LPWSTR lpDirectoryName, IN OUT UINT* cchDirectoryName )
+{
+ PathWCharString directory;
+ BOOL bRet;
+ PERF_ENTRY(PAL_GetPALDirectoryW);
+ ENTRY( "PAL_GetPALDirectoryW( %p, %d )\n", lpDirectoryName, *cchDirectoryName );
+
+ bRet = PAL_GetPALDirectoryW(directory);
+
+ if (bRet) {
+
+ if (directory.GetCount() > *cchDirectoryName)
+ {
+ SetLastError( ERROR_INSUFFICIENT_BUFFER );
+ bRet = FALSE;
+ }
+ else
+ {
+ PAL_wcscpy(lpDirectoryName, directory.GetString());
+ }
+
+ *cchDirectoryName = directory.GetCount();
+ }
+
+ LOGEXIT( "PAL_GetPALDirectoryW returns BOOL %d.\n", bRet);
+ PERF_EXIT(PAL_GetPALDirectoryW);
+ return bRet;
+
+}
+
+PALIMPORT
+BOOL
+PALAPI
+PAL_GetPALDirectoryA(
+ OUT LPSTR lpDirectoryName,
+ IN UINT* cchDirectoryName)
+{
+ BOOL bRet;
+ PathCharString directory;
+
+ PERF_ENTRY(PAL_GetPALDirectoryA);
+ ENTRY( "PAL_GetPALDirectoryA( %p, %d )\n", lpDirectoryName, *cchDirectoryName );
+
+ bRet = PAL_GetPALDirectoryA(directory);
+
+ if (bRet)
+ {
+ if (directory.GetCount() > *cchDirectoryName)
+ {
+ SetLastError( ERROR_INSUFFICIENT_BUFFER );
+ bRet = FALSE;
+ *cchDirectoryName = directory.GetCount();
+ }
+ else if (strcpy_s(lpDirectoryName, directory.GetCount(), directory.GetString()) == SAFECRT_SUCCESS)
+ {
+ }
+ else
+ {
+ bRet = FALSE;
+ }
+ }
+
+ LOGEXIT( "PAL_GetPALDirectoryA returns BOOL %d.\n", bRet);
+ PERF_EXIT(PAL_GetPALDirectoryA);
+ return bRet;
+}
+
+BOOL
+PALAPI
+PAL_Random(
+ IN BOOL bStrong,
+ IN OUT LPVOID lpBuffer,
+ IN DWORD dwLength)
+{
+ int rand_des = -1;
+ BOOL bRet = FALSE;
+ DWORD i;
+ char buf;
+ long num = 0;
+ static BOOL sMissingDevRandom;
+ static BOOL sMissingDevURandom;
+ static BOOL sInitializedMRand;
+
+ PERF_ENTRY(PAL_Random);
+ ENTRY("PAL_Random(bStrong=%d, lpBuffer=%p, dwLength=%d)\n",
+ bStrong, lpBuffer, dwLength);
+
+ i = 0;
+
+ if (bStrong == TRUE && i < dwLength && !sMissingDevRandom)
+ {
+ // request non-blocking access to avoid hangs if the /dev/random is exhausted
+ // or just simply broken
+ if ((rand_des = PAL__open(RANDOM_DEVICE_NAME, O_RDONLY | O_NONBLOCK)) == -1)
+ {
+ if (errno == ENOENT)
+ {
+ sMissingDevRandom = TRUE;
+ }
+ else
+ {
+ ASSERT("PAL__open() failed, errno:%d (%s)\n", errno, strerror(errno));
+ }
+
+ // Back off and try /dev/urandom.
+ }
+ else
+ {
+ for( ; i < dwLength; i++)
+ {
+ if (read(rand_des, &buf, 1) < 1)
+ {
+ // the /dev/random pool has been exhausted. Fall back
+ // to /dev/urandom for the remainder of the buffer.
+ break;
+ }
+
+ *(((BYTE*)lpBuffer) + i) ^= buf;
+ }
+
+ close(rand_des);
+ }
+ }
+
+ if (i < dwLength && !sMissingDevURandom)
+ {
+ if ((rand_des = PAL__open(URANDOM_DEVICE_NAME, O_RDONLY)) == -1)
+ {
+ if (errno == ENOENT)
+ {
+ sMissingDevURandom = TRUE;
+ }
+ else
+ {
+ ASSERT("PAL__open() failed, errno:%d (%s)\n", errno, strerror(errno));
+ }
+
+ // Back off and try mrand48.
+ }
+ else
+ {
+ for( ; i < dwLength; i++)
+ {
+ if (read(rand_des, &buf, 1) < 1)
+ {
+ // Fall back to srand48 for the remainder of the buffer.
+ break;
+ }
+
+ *(((BYTE*)lpBuffer) + i) ^= buf;
+ }
+
+ close(rand_des);
+ }
+ }
+
+ if (!sInitializedMRand)
+ {
+ srand48(time(NULL));
+ sInitializedMRand = TRUE;
+ }
+
+ // always xor srand48 over the whole buffer to get some randomness
+ // in case /dev/random is not really random
+
+ for(i = 0; i < dwLength; i++)
+ {
+ if (i % sizeof(long) == 0) {
+ num = mrand48();
+ }
+
+ *(((BYTE*)lpBuffer) + i) ^= num;
+ num >>= 8;
+ }
+
+ bRet = TRUE;
+
+ LOGEXIT("PAL_Random returns %d\n", bRet);
+ PERF_EXIT(PAL_Random);
+ return bRet;
+}
+
+HRESULT
+PALAPI
+CoCreateGuid(OUT GUID * pguid)
+{
+#if HAVE_BSD_UUID_H
+ uuid_t uuid;
+ uint32_t status;
+ uuid_create(&uuid, &status);
+ if (status != uuid_s_ok)
+ {
+ ASSERT("Unexpected uuid_create failure (status=%u)\n", status);
+ PROCAbort();
+ }
+
+ // Encode the uuid with little endian.
+ uuid_enc_le(pguid, &uuid);
+#elif HAVE_LIBUUID_H
+ uuid_generate_random(*(uuid_t*)pguid);
+
+ // Change the byte order of the Data1, 2 and 3, since the uuid_generate_random
+ // generates them with big endian while GUIDS need to have them in little endian.
+ pguid->Data1 = SWAP32(pguid->Data1);
+ pguid->Data2 = SWAP16(pguid->Data2);
+ pguid->Data3 = SWAP16(pguid->Data3);
+#else
+ #error Don't know how to generate UUID on this platform
+#endif
+ return 0;
+}
diff --git a/src/pal/src/misc/msgbox.cpp b/src/pal/src/misc/msgbox.cpp
new file mode 100644
index 0000000000..b3041b1422
--- /dev/null
+++ b/src/pal/src/misc/msgbox.cpp
@@ -0,0 +1,416 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ msgbox.c
+
+Abstract:
+
+ Implementation of Message Box.
+
+
+
+--*/
+
+#include "pal/palinternal.h"
+#include "pal/critsect.h"
+#include "pal/dbgmsg.h"
+#include "pal/misc.h"
+
+#include <syslog.h>
+
+SET_DEFAULT_DEBUG_CHANNEL(MISC);
+
+CRITICAL_SECTION msgbox_critsec;
+
+
+/*++
+Function :
+ MsgBoxInitialize
+
+ Initialize the critical sections.
+
+Return value:
+ TRUE if initialize succeeded
+ FALSE otherwise
+
+--*/
+BOOL
+MsgBoxInitialize( void )
+{
+ TRACE( "Initialising the critical section.\n" );
+ InternalInitializeCriticalSection(&msgbox_critsec);
+
+ return TRUE;
+}
+
+/*++
+Function :
+ MsgBoxCleanup
+
+ Deletes the critical sections.
+
+--*/
+void MsgBoxCleanup( void )
+{
+ TRACE( "Deleting the critical section.\n" );
+ DeleteCriticalSection( &msgbox_critsec );
+}
+
+
+
+#ifdef __APPLE__
+#include "CoreFoundation/CFUserNotification.h"
+#include "CoreFoundation/CFString.h"
+#include "Security/AuthSession.h"
+#endif // __APPLE__
+
+
+/*++
+Function:
+ MessageBoxW
+
+This is a small subset of MessageBox that simply logs a message to the
+system logging facility and returns. A typical log entry will look
+like:
+
+May 23 15:48:10 rice example1: MessageBox: Caption: Error Text
+
+Note:
+ hWnd should always be NULL.
+
+See MSDN doc.
+--*/
+int
+PALAPI
+MessageBoxW(
+ IN LPVOID hWnd,
+ IN LPCWSTR lpText,
+ IN LPCWSTR lpCaption,
+ IN UINT uType)
+{
+ CHAR *text = NULL;
+ CHAR *caption = NULL;
+ INT len = 0;
+ INT rc = 0;
+
+ PERF_ENTRY(MessageBoxW);
+ ENTRY( "MessageBoxW (hWnd=%p, lpText=%p (%S), lpCaption=%p (%S), uType=%#x)\n",
+ hWnd, lpText?lpText:W16_NULLSTRING, lpText?lpText:W16_NULLSTRING,
+ lpCaption?lpCaption:W16_NULLSTRING,
+ lpCaption?lpCaption:W16_NULLSTRING, uType );
+
+ if (hWnd != NULL)
+ {
+ ASSERT("hWnd != NULL");
+ }
+
+ if(lpText)
+ {
+ len = WideCharToMultiByte(CP_ACP, 0, lpText, -1, NULL, 0, NULL, NULL);
+ if(len)
+ {
+ text = (LPSTR)PAL_malloc(len);
+ if(!text)
+ {
+ ERROR("malloc() failed!\n");
+ SetLastError( ERROR_NOT_ENOUGH_MEMORY );
+ goto error;
+ }
+ if( !WideCharToMultiByte( CP_ACP, 0, lpText, -1, text, len,
+ NULL, NULL))
+ {
+ ASSERT("WideCharToMultiByte failure\n");
+ SetLastError( ERROR_INTERNAL_ERROR );
+ goto error;
+ }
+ }
+ else
+ {
+ ASSERT("WideCharToMultiByte failure\n");
+ SetLastError( ERROR_INTERNAL_ERROR );
+ goto error;
+ }
+ }
+ else
+ {
+ WARN("No message text\n");
+
+ if (NULL == (text = PAL__strdup("(no message text)")))
+ {
+ ASSERT("strdup() failed\n");
+ SetLastError( ERROR_INTERNAL_ERROR );
+ goto error;
+ }
+ }
+ if (lpCaption)
+ {
+ len = WideCharToMultiByte( CP_ACP, 0, lpCaption, -1, NULL, 0,
+ NULL, NULL);
+ if(len)
+ {
+ caption = (CHAR*)PAL_malloc(len);
+ if(!caption)
+ {
+ ERROR("malloc() failed!\n");
+ SetLastError( ERROR_NOT_ENOUGH_MEMORY );
+ goto error;
+ }
+ if( !WideCharToMultiByte( CP_ACP, 0, lpCaption, -1, caption, len,
+ NULL, NULL))
+ {
+ ASSERT("WideCharToMultiByte failure\n");
+ SetLastError( ERROR_INTERNAL_ERROR );
+ goto error;
+ }
+ }
+ else
+ {
+ ASSERT("WideCharToMultiByte failure\n");
+ SetLastError( ERROR_INTERNAL_ERROR );
+ goto error;
+ }
+ }
+ else
+ {
+ if (NULL == (caption = PAL__strdup("Error")))
+ {
+ ERROR("strdup() failed\n");
+ SetLastError( ERROR_NOT_ENOUGH_MEMORY );
+ goto error;
+ }
+ }
+
+ rc = MessageBoxA(hWnd, text, caption, uType);
+
+error:
+ PAL_free(caption);
+ PAL_free(text);
+
+
+ LOGEXIT("MessageBoxW returns %d\n", rc);
+ PERF_EXIT(MessageBoxW);
+ return rc;
+}
+
+
+/*++
+Function:
+ MessageBoxA
+
+This is a small subset of MessageBox that simply logs a message to the
+system logging facility and returns. A typical log entry will look
+like:
+
+May 23 15:48:10 rice example1: MessageBox: Caption: Error Text
+
+Note:
+ hWnd should always be NULL.
+
+See MSDN doc.
+--*/
+int
+PALAPI
+MessageBoxA(
+ IN LPVOID hWnd,
+ IN LPCSTR lpText,
+ IN LPCSTR lpCaption,
+ IN UINT uType)
+{
+ INT rc = 0;
+
+ PERF_ENTRY(MessageBoxA);
+ ENTRY( "MessageBoxA (hWnd=%p, lpText=%p (%s), lpCaption=%p (%s), uType=%#x)\n",
+ hWnd, lpText?lpText:"NULL", lpText?lpText:"NULL",
+ lpCaption?lpCaption:"NULL",
+ lpCaption?lpCaption:"NULL", uType );
+
+ if (hWnd != NULL)
+ {
+ ASSERT("hWnd != NULL");
+ }
+
+ if (lpText == NULL)
+ {
+ WARN("No message text\n");
+
+ lpText = "(no message text)";
+ }
+
+ if (lpCaption == NULL)
+ {
+ lpCaption = "Error";
+ }
+
+ if (uType & MB_DEFMASK)
+ {
+ WARN("No support for alternate default buttons.\n");
+ }
+
+ /* set default status based on the type of button */
+ switch(uType & MB_TYPEMASK)
+ {
+ case MB_OK:
+ rc = IDOK;
+ break;
+
+ case MB_ABORTRETRYIGNORE:
+ rc = IDABORT;
+ break;
+
+ case MB_YESNO:
+ rc = IDNO;
+ break;
+
+ case MB_OKCANCEL :
+ rc = IDCANCEL;
+ break;
+
+ case MB_RETRYCANCEL :
+ rc = IDCANCEL;
+ break;
+
+ default:
+ ASSERT("Bad uType");
+ rc = IDOK;
+ break;
+ }
+
+ PALCEnterCriticalSection( &msgbox_critsec);
+
+#ifdef __APPLE__
+ OSStatus osstatus;
+
+ SecuritySessionId secSession;
+ SessionAttributeBits secSessionInfo;
+
+ osstatus = SessionGetInfo(callerSecuritySession, &secSession, &secSessionInfo);
+ if (noErr == osstatus && (secSessionInfo & sessionHasGraphicAccess) != 0)
+ {
+ CFStringRef cfsTitle = CFStringCreateWithCString(kCFAllocatorDefault, lpCaption, kCFStringEncodingUTF8);
+ CFStringRef cfsText = CFStringCreateWithCString(kCFAllocatorDefault, lpText, kCFStringEncodingUTF8);
+ CFStringRef cfsButton1 = NULL;
+ CFStringRef cfsButton2 = NULL;
+ CFStringRef cfsButton3 = NULL;
+ CFOptionFlags alertFlags = 0;
+ CFOptionFlags response;
+
+ switch (uType & MB_TYPEMASK)
+ {
+ case MB_OK:
+ // Nothing needed; since if all the buttons are null, a stock "OK" is used.
+ break;
+
+ case MB_ABORTRETRYIGNORE:
+ // Localization? Would be needed if this were used outside of debugging.
+ cfsButton1 = CFSTR("Abort");
+ cfsButton2 = CFSTR("Retry");
+ cfsButton3 = CFSTR("Ignore");
+ alertFlags = kCFUserNotificationCautionAlertLevel;
+ break;
+
+ case MB_YESNO:
+ cfsButton1 = CFSTR("Yes");
+ cfsButton2 = CFSTR("No");
+ break;
+
+ case MB_OKCANCEL:
+ cfsButton1 = CFSTR("OK");
+ cfsButton2 = CFSTR("Cancel");
+ break;
+
+ case MB_RETRYCANCEL:
+ cfsButton1 = CFSTR("Retry");
+ cfsButton2 = CFSTR("Cancel");
+ break;
+ }
+
+ CFUserNotificationDisplayAlert(0 /* no time out */, alertFlags, NULL /* iconURL */,
+ NULL /* soundURL */, NULL /* localizationURL */, cfsTitle, cfsText, cfsButton1,
+ cfsButton2, cfsButton3, &response);
+
+ switch (uType & MB_TYPEMASK)
+ {
+ case MB_OK:
+ break;
+
+ case MB_ABORTRETRYIGNORE:
+ switch (response)
+ {
+ case kCFUserNotificationDefaultResponse:
+ rc = IDABORT;
+ break;
+ case kCFUserNotificationAlternateResponse:
+ rc = IDRETRY;
+ break;
+ case kCFUserNotificationOtherResponse:
+ rc = IDIGNORE;
+ break;
+ }
+ break;
+
+ case MB_YESNO:
+ switch (response)
+ {
+ case kCFUserNotificationDefaultResponse:
+ rc = IDYES;
+ break;
+ case kCFUserNotificationAlternateResponse:
+ rc = IDNO;
+ break;
+ }
+ break;
+
+ case MB_OKCANCEL:
+ switch (response)
+ {
+ case kCFUserNotificationDefaultResponse:
+ rc = IDOK;
+ break;
+ case kCFUserNotificationAlternateResponse:
+ rc = IDCANCEL;
+ break;
+ }
+ break;
+
+ case MB_RETRYCANCEL:
+ switch (response)
+ {
+ case kCFUserNotificationDefaultResponse:
+ rc = IDRETRY;
+ break;
+ case kCFUserNotificationAlternateResponse:
+ rc = IDCANCEL;
+ break;
+ }
+ break;
+ }
+ }
+ else
+ {
+ // We're not in a login session, e.g., running via ssh, and so bringing
+ // up a message box would be bad form.
+ fprintf ( stderr, "MessageBox: %s: %s", lpCaption, lpText );
+ syslog(LOG_USER|LOG_ERR, "MessageBox: %s: %s", lpCaption, lpText);
+ }
+#else // __APPLE__
+ fprintf ( stderr, "MessageBox: %s: %s", lpCaption, lpText );
+ syslog(LOG_USER|LOG_ERR, "MessageBox: %s: %s", lpCaption, lpText);
+
+ // Some systems support displaying a GUI dialog. (This will suspend the current thread until they hit the
+ // 'OK' button and allow a debugger to be attached).
+ PAL_DisplayDialog(lpCaption, lpText);
+#endif // __APPLE__ else
+
+ PALCLeaveCriticalSection( &msgbox_critsec);
+
+ LOGEXIT("MessageBoxA returns %d\n", rc);
+ PERF_EXIT(MessageBoxA);
+ return rc;
+}
diff --git a/src/pal/src/misc/perftrace.cpp b/src/pal/src/misc/perftrace.cpp
new file mode 100644
index 0000000000..d4fba3367a
--- /dev/null
+++ b/src/pal/src/misc/perftrace.cpp
@@ -0,0 +1,1522 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ misc/perftrace.c
+
+Abstract:
+ Implementation of PAL Performance trace utilities.
+
+
+
+--*/
+
+/* PAL headers */
+
+
+
+#ifdef PAL_PERF
+
+#ifndef PLATFORM_UNIX
+/* PAL Headers */
+#include "perftrace.h"
+
+/* Standard Headers */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#define snprintf _snprintf
+#define MiscGetenv getenv
+#define pthread_getspecific TlsGetValue
+#define THREADSilentGetCurrentThreadId GetCurrentThreadId
+#define getpid GetCurrentProcessId
+#define PAL_fgets fgets // on Windows, we want fgets.
+#define PAL_fwrite fwrite // on Windows, we want fwrite.
+#define PAL_fseek fseek // on Windows, we want fseek.
+
+#else
+/* PAL Headers */
+#include "pal/palinternal.h"
+#include "pal/perftrace.h"
+#include "pal/dbgmsg.h"
+#include "pal/cruntime.h"
+#include "pal/misc.h"
+
+/* Standard headers */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <pthread.h> /* for pthread_self */
+#include <dirent.h>
+#include <unistd.h>
+
+SET_DEFAULT_DEBUG_CHANNEL(MISC);
+#endif //End of PLATFORM_UNIX
+
+
+#define PAL_PERF_MAX_LOGLINE 0x400 /* 1K */
+#define PAL_PERF_MAX_INPUT 0x1000 /* 4k for single line of input file */
+#define PAL_PERF_MAX_FUNCTION_NAME 128 /* any one want a function name longer than 127 bytes? */
+#define PAL_PERF_PROFILE_BUFFER_SIZE 0x400000 /* 4M */
+#define PAL_PERF_BUFFER_FULL (PAL_PERF_PROFILE_BUFFER_SIZE - PAL_PERF_MAX_LOGLINE ) /* (Buffer size - 1K) */
+
+typedef struct _pal_perf_api_info
+{
+ ULONGLONG entries; /* number of PERF_ENTRY calls for an API function */
+ ULONGLONG counter; /* number of PERF_EXIT calls for an API function */
+ ULONGLONG min_duration; /* Minimum duration in CPU clock ticks in an API function */
+ ULONGLONG max_duration; /* Maximum duration in CPU clock ticks in an API function */
+ ULONGLONG sum_duration; /* Sum of duration*/
+ double sum_of_square_duration; /* Sum of square of durations */
+ DWORD *histograms; /* An array to store the histogram of an API execution cpu ticks. */
+} pal_perf_api_info;
+
+
+typedef struct _pal_perf_thread_info
+{
+ DWORD threadId;
+ pal_perf_api_info * api_table;
+ char * pal_write_buf;
+ DWORD buf_offset;
+ BOOL profile_enabled;
+ ULONGLONG start_ticks;
+ ULONGLONG total_duration;
+} pal_perf_thread_info;
+
+typedef struct _pal_thread_list_node
+{
+ pal_perf_thread_info * thread_info;
+ struct _pal_thread_list_node * next;
+
+} pal_thread_list_node;
+
+typedef struct _pal_perf_program_info
+{
+ char command_line[PAL_PERF_MAX_LOGLINE];
+ char exe_path[PAL_PERF_MAX_LOGLINE];
+ char hostname[PAL_PERF_MAX_FUNCTION_NAME];
+ double cpu_clock_frequency;
+ ULONGLONG start_ticks;
+ ULONGLONG elapsed_time; /* Duration in CPU clock ticks of the program */
+ ULONGLONG total_duration; /* Total CPU clock ticks of all the threads */
+ ULONGLONG pal_duration; /* Total CPU clock ticks spent inside PAL */
+
+#ifndef PLATFORM_UNIX
+ DWORD process_id;
+#else
+ pid_t process_id;
+#endif
+ char start_time[32]; /* must be at least 26 characters */
+} pal_perf_program_info;
+
+#ifndef PLATFORM_UNIX
+typedef FILE PERF_FILE;
+#define PERF_FILEFN(x) x
+#else
+typedef PAL_FILE PERF_FILE;
+#define PERF_FILEFN(x) PAL_ ## x
+#endif
+
+static ULONGLONG PERFGetTicks();
+static double PERFComputeStandardDeviation(pal_perf_api_info *api);
+static void PERFPrintProgramHeaderInfo(PERF_FILE * hFile, BOOL completedExecution);
+static BOOL PERFInitProgramInfo(LPWSTR command_line, LPWSTR exe_path);
+static BOOL PERFReadSetting( );
+static void PERFLogFileName(PathCharString * destFileString, const char *fileName, const char *suffix, int max_length);
+static void PERFlushAllLogs();
+static int PERFWriteCounters(pal_perf_api_info * table);
+static BOOL PERFFlushLog(pal_perf_thread_info * local_buffer, BOOL output_header);
+static void PERFUpdateApiInfo(pal_perf_api_info *api, ULONGLONG duration);
+static char * PERFIsValidPath( const char * path );
+static char * PERFIsValidFile( const char * path, const char * file);
+
+typedef char PAL_API_NAME[PAL_PERF_MAX_FUNCTION_NAME];
+
+static PAL_API_NAME API_list[PAL_API_NUMBER] ;
+static pal_perf_program_info program_info;
+
+#ifndef PLATFORM_UNIX
+static DWORD PERF_tlsTableKey=0 ;
+#else
+static pthread_key_t PERF_tlsTableKey=0 ;
+#endif
+
+static pal_thread_list_node * process_pal_thread_list=NULL;
+static BOOL pal_profile_on=FALSE;
+static BOOL pal_perf_enabled=FALSE;
+static char * pal_function_map=NULL;
+static char * perf_default_path=NULL;
+static char * traced_apis_file=NULL;
+static char * enabledapis_path=NULL;
+static char * profile_log_path=NULL;
+static char * profile_summary_log_name=NULL;
+static char * profile_time_log_name=NULL;
+static BOOL summary_only=FALSE;
+static BOOL nested_tracing=FALSE;
+static BOOL calibrate=FALSE;
+
+/* If report_only_called_apis is TRUE,
+ those PAL APIs with no function entry or exit
+ will not be shown in the PAL perf summary file. */
+static BOOL report_only_called_apis=FALSE;
+
+/* If the wait_for_startup is TRUE, process profiling
+ will not start until the application
+ has called PAL_EnableProcessProfile(). */
+static BOOL wait_for_startup=FALSE;
+
+/* The size of a PAL API execution CPU ticks histogram, i.e.,
+ Number of categories of frequency distrubution of PAL API
+ execution CPU ticks.*/
+static DWORD pal_perf_histogram_size = 0;
+
+/* The step size in CPU ticks of each category of the
+ PAL API execution CPU ticks histogram.*/
+static DWORD pal_perf_histogram_step = 100;
+
+static const char PAL_PERF_TRACING[]="PAL_PERF_TRACING";
+static const char PAL_DEFAULT_PATH[]="PAL_PERF_DEFAULT_PATH";
+static const char PAL_PERF_TRACEDAPIS_PATH[]="PAL_PERF_TRACEDAPIS_FILE";
+static const char PAL_PERF_LOG_PATH[]="PAL_PERF_LOG_PATH";
+static const char PAL_PERF_SUMMARY_LOG_NAME[]="PAL_PERF_SUMMARY_LOG_NAME";
+static const char PAL_PERF_TIME_LOG_NAME[]="PAL_PERF_TIME_LOG_NAME";
+static const char PAL_PERF_ENABLED_APIS_PATH[]="PAL_PERF_ENABLEDAPIS_FILE";
+static const char PAL_SUMMARY_FLAG[]="PAL_PERF_SUMMARY_ONLY";
+static const char PAL_PERF_NESTED_TRACING[]="PAL_PERF_NESTED_TRACING";
+static const char PAL_PERF_CALIBRATE[]="PAL_PERF_CALIBRATE";
+static const char PAL_PERF_REPORT_ONLY_CALLED_APIS[]="PAL_PERF_REPORT_ONLY_CALLED_APIS";
+static const char PAL_PERF_WAIT_FOR_STARTUP[]="PAL_PERF_WAIT_FOR_STARTUP";
+static const char PAL_PERF_HISTOGRAM_SIZE[]="PAL_PERF_HISTOGRAM_SIZE";
+static const char PAL_PERF_HISTOGRAM_STEP[]="PAL_PERF_HISTOGRAM_STEP";
+static const char traced_apis_filename[]="PerfTracedAPIs.txt";
+static const char perf_enabled_filename[]="AllPerfEnabledAPIs.txt";
+#ifndef PLATFORM_UNIX
+static const char PATH_SEPARATOR[] = "\\";
+#else
+static const char PATH_SEPARATOR[] = "/";
+#endif
+
+
+
+#ifndef PLATFORM_UNIX
+#define LLFORMAT "%I64u"
+#else
+#define LLFORMAT "%llu"
+#endif
+
+static
+ULONGLONG
+PERFGetTicks(){
+#ifdef _X86_ // for BSD and Windows.
+ unsigned long a, d;
+ #ifdef _MSC_VER
+ __asm{
+ rdtsc
+ mov a, eax
+ mov d, edx
+ }
+ #else
+ #undef volatile
+ asm volatile("rdtsc":"=a" (a), "=d" (d));
+ #define volatile DoNotUseVolatileKeyword
+ #endif
+ return ((ULONGLONG)((unsigned int)(d)) << 32) | (unsigned int)(a);
+#else
+#ifdef __sparc__
+ return (ULONGLONG)gethrtime();
+#else
+ return 0; // on non-BSD and non-Windows, we'll return 0 for now.
+#endif // __sparc__
+#endif // _X86_
+}
+
+static
+double
+PERFComputeStandardDeviation(pal_perf_api_info *api)
+{
+ double n;
+ double sum_of_variance;
+ if (api->counter <= 1)
+ return 0.0;
+ n = (double) api->counter;
+ // Calculates standard deviation based on the entire population given as arguments.
+ // Same as stdevp in Excel.
+ sum_of_variance = (n*api->sum_of_square_duration) - (api->sum_duration*api->sum_duration);
+ if (sum_of_variance <= 0.0)
+ return 0.0;
+ return sqrt(sum_of_variance/(n*n));
+}
+
+
+static
+void
+PERFPrintProgramHeaderInfo(PERF_FILE * hFile, BOOL completedExecution)
+{
+ ULONGLONG etime = 0;
+ ULONGLONG ttime = 0;
+ ULONGLONG ptime = 0;
+ if (completedExecution) {
+ etime = program_info.elapsed_time;
+ ttime = program_info.total_duration;
+ ptime = program_info.pal_duration;
+ }
+ PERF_FILEFN(fprintf)(hFile,"#LOG\tversion=1.00\n");
+
+ PERF_FILEFN(fprintf)(hFile, "#MACHINE\thostname=%s\tcpu_clock_frequency=%g\n", program_info.hostname,
+ program_info.cpu_clock_frequency);
+ PERF_FILEFN(fprintf)(hFile, "#PROCESS\tprocess_id=%d\ttotal_latency=" LLFORMAT "\tthread_times=" LLFORMAT "\tpal_time=" LLFORMAT "\texe_path=%s\tcommand_line=%s\tstart_time=%s",
+ program_info.process_id, etime, ttime, ptime,
+ program_info.exe_path,program_info.command_line,program_info.start_time);
+}
+
+static
+BOOL
+PERFInitProgramInfo(LPWSTR command_line, LPWSTR exe_path)
+{
+ ULONGLONG start_tick;
+#ifndef PLATFORM_UNIX
+ time_t tv;
+#else
+ struct timeval tv;
+#endif
+
+ if (WideCharToMultiByte(CP_ACP, 0, command_line, -1,
+ program_info.command_line, PAL_PERF_MAX_LOGLINE-1, NULL, NULL) == 0)
+ return FALSE;
+ if (WideCharToMultiByte(CP_ACP, 0, exe_path, -1,
+ program_info.exe_path, PAL_PERF_MAX_LOGLINE-1, NULL, NULL) == 0)
+ return FALSE;
+
+ gethostname(program_info.hostname, PAL_PERF_MAX_FUNCTION_NAME);
+ program_info.process_id = getpid();
+
+#ifndef PLATFORM_UNIX
+ time( &tv );
+ strcpy(program_info.start_time, ctime( &tv ));
+#else
+ gettimeofday(&tv, NULL);
+ ctime_r(&tv.tv_sec, program_info.start_time);
+#endif
+
+ // estimate the cpu clock cycles
+ start_tick = PERFGetTicks();
+ if (start_tick != 0)
+ {
+#ifndef PLATFORM_UNIX
+ Sleep(1000); //Sleep on Windows takes milliseconds as argument
+#else
+ sleep(1);
+#endif
+ program_info.cpu_clock_frequency = (double) (PERFGetTicks() - start_tick);
+ }
+ else
+ {
+ program_info.cpu_clock_frequency = 0.0;
+ }
+
+ program_info.start_ticks = 0;
+ program_info.elapsed_time = 0;
+ program_info.total_duration = 0;
+ program_info.pal_duration = 0;
+
+ return TRUE;
+}
+
+static
+void
+PERFCalibrationFunction()
+{
+ PERF_ENTRY(CalibrationFunction);
+ PERF_EXIT(CalibrationFunction);
+}
+
+void
+PERFCalibrate(const char* msg)
+{
+ ULONGLONG start_tick, cal_ticks;
+ int i=0;
+ int cal_length=100000;
+
+ if (calibrate) {
+ start_tick = PERFGetTicks();
+ for(i=0; i<cal_length; i++)
+ {
+ PERFCalibrationFunction();
+ }
+ cal_ticks = PERFGetTicks() - start_tick;
+ printf("%s: %g\n", msg, (double)(cal_ticks/cal_length));
+ }
+}
+
+BOOL
+PERFInitialize(LPWSTR command_line, LPWSTR exe_path)
+{
+ BOOL bRead;
+ BOOL ret = TRUE;
+
+ // Check if PAL Perf should be disabled
+ char *pal_perf_tracing_env = MiscGetenv(PAL_PERF_TRACING);
+ if ( pal_perf_tracing_env == NULL || strlen(pal_perf_tracing_env) == 0)
+ {
+ pal_perf_enabled = FALSE;
+ return TRUE;
+ }
+ else
+ {
+ pal_perf_enabled = TRUE;
+ }
+ if (!PERFInitProgramInfo(command_line, exe_path))
+ return FALSE;
+
+ pal_profile_on = FALSE; // turn it off until we setup everything.
+ // allocate the TLS index for structures
+#ifndef PLATFORM_UNIX
+ if( ( PERF_tlsTableKey = TlsAlloc() ) == -1 )
+ ret = FALSE;
+#else
+ if( pthread_key_create(&PERF_tlsTableKey , NULL) != 0 )
+ ret = FALSE;
+#endif
+
+ if( ret == TRUE )
+ {
+ pal_function_map = (char*)PAL_malloc(PAL_API_NUMBER);
+ if(pal_function_map != NULL)
+ {
+ bRead = PERFReadSetting( ); // we don't quit even we failed to read the file.
+ ret = TRUE;
+ }
+ /* free the index in TLS */
+ else
+ {
+
+#ifndef PLATFORM_UNIX
+ TlsFree(PERF_tlsTableKey );
+#else
+ pthread_key_delete(PERF_tlsTableKey );
+#endif
+ ret = FALSE;
+ }
+ }
+
+ PERFCalibrate("Overhead when profiling is disabled process-wide");
+
+ return ret;
+}
+
+
+void PERFTerminate( )
+{
+ static LONG pal_perf_terminated = FALSE;
+
+ if (!pal_perf_enabled || wait_for_startup)
+ return;
+
+ // make sure PERFTerminate is called only once
+ if (InterlockedCompareExchange(&pal_perf_terminated, TRUE, FALSE))
+ return;
+
+ PERFlushAllLogs();
+#ifndef PLATFORM_UNIX
+ TlsFree(PERF_tlsTableKey );
+#else
+ pthread_key_delete(PERF_tlsTableKey );
+#endif
+ PAL_free(pal_function_map);
+}
+
+
+BOOL PERFAllocThreadInfo( )
+{
+ pal_perf_api_info * apiTable = NULL;
+ pal_thread_list_node * node = NULL;
+ pal_perf_thread_info * local_info = NULL;
+ char * log_buf = NULL;
+ int i;
+ BOOL ret = TRUE;
+
+ if (!pal_perf_enabled)
+ return TRUE;
+
+ /* The memory allocated per thread for PAL perf tracing is never freed until PAL_Terminate
+ is called in the current implementation. If the test program keeps creating new threads,
+ memory resources could be exhausted. If this ever becomes a problem, the memory allocated
+ per thread should be freed when a thread exits. */
+
+ node = ( pal_thread_list_node * )PAL_malloc(sizeof(pal_thread_list_node));
+ if(node == NULL)
+ {
+ ret = FALSE;
+ goto PERFAllocThreadInfoExit;
+ }
+
+ local_info = (pal_perf_thread_info *)PAL_malloc(sizeof(pal_perf_thread_info));
+ if (local_info == NULL)
+ {
+ ret = FALSE;
+ goto PERFAllocThreadInfoExit;
+ }
+
+ apiTable = (pal_perf_api_info *)PAL_malloc( PAL_API_NUMBER * sizeof(pal_perf_api_info));
+ if (apiTable == NULL)
+ {
+ ret = FALSE;
+ goto PERFAllocThreadInfoExit;
+ }
+
+ node->thread_info = local_info;
+ local_info->api_table=apiTable;
+ local_info->threadId = THREADSilentGetCurrentThreadId();
+
+ for (i = 0; i < PAL_API_NUMBER; i++)
+ {
+ apiTable[i].entries = 0;
+ apiTable[i].counter = 0;
+ apiTable[i].min_duration = _UI64_MAX;
+ apiTable[i].max_duration = 0;
+ apiTable[i].sum_duration = 0;
+ apiTable[i].sum_of_square_duration = 0.0;
+ if (pal_perf_histogram_size > 0)
+ {
+ apiTable[i].histograms = (DWORD *)PAL_malloc(pal_perf_histogram_size*sizeof(DWORD));
+ if (apiTable[i].histograms == NULL)
+ {
+ ret = FALSE;
+ goto PERFAllocThreadInfoExit;
+ }
+ memset(apiTable[i].histograms, 0, pal_perf_histogram_size*sizeof(DWORD));
+ }
+ else
+ {
+ apiTable[i].histograms = NULL;
+ }
+ }
+
+ log_buf = (char * )PAL_malloc( PAL_PERF_PROFILE_BUFFER_SIZE );
+
+ if(log_buf == NULL)
+ {
+ ret = FALSE;
+ goto PERFAllocThreadInfoExit;
+ }
+
+ local_info->pal_write_buf=log_buf;
+ local_info->buf_offset = 0;
+ local_info->profile_enabled = FALSE;
+ local_info->total_duration = 0;
+ local_info->start_ticks = 0;
+ memset(log_buf, 0, PAL_PERF_PROFILE_BUFFER_SIZE);
+
+#ifndef PLATFORM_UNIX
+ if ( TlsSetValue(PERF_tlsTableKey, local_info) == 0)
+ ret = FALSE;
+#else
+ if (pthread_setspecific(PERF_tlsTableKey, local_info) != 0)
+ ret = FALSE;
+#endif
+
+PERFAllocThreadInfoExit:
+ if (ret == TRUE)
+ {
+ node->next = process_pal_thread_list;
+ process_pal_thread_list = node;
+ PERFFlushLog(local_info, TRUE);
+ }
+ else
+ {
+ if (node != NULL)
+ {
+ PAL_free(node);
+ }
+ if (local_info != NULL)
+ {
+ PAL_free(local_info);
+ }
+ if (apiTable != NULL)
+ {
+ for (i = 0; i < PAL_API_NUMBER; i++)
+ {
+ if (apiTable[i].histograms != NULL)
+ {
+ PAL_free(apiTable[i].histograms);
+ }
+ }
+ PAL_free(apiTable);
+ }
+ if (log_buf != NULL)
+ {
+ PAL_free(log_buf);
+ }
+ }
+ return ret;
+}
+
+static
+void
+PERFUpdateProgramInfo(pal_perf_thread_info* local_info)
+{
+ int i;
+
+ if (!local_info) return;
+
+ // add the elapsed time to the program's total
+ if (local_info->total_duration == 0)
+ {
+ // this thread did not go through PERFDisableThreadProfile code
+ // so compute the total elapsed time for the thread here
+ local_info->total_duration = PERFGetTicks() - local_info->start_ticks;
+ }
+ program_info.total_duration += local_info->total_duration;
+
+ // Add up all the time spent in PAL
+ if (local_info->api_table) {
+ for(i=0; i<PAL_API_NUMBER; i++) {
+ program_info.pal_duration += local_info->api_table[i].sum_duration;
+ }
+ }
+}
+
+
+static
+void
+PERFlushAllLogs( )
+{
+ pal_thread_list_node * current, * node;
+ pal_perf_api_info * table1, *table0;
+ int i;
+ node = process_pal_thread_list;
+ if(node == NULL || node->thread_info == NULL || node->thread_info->api_table == NULL ) // should not come here
+ {
+ return ;
+ }
+ process_pal_thread_list = process_pal_thread_list->next;
+ table0 = node->thread_info->api_table;
+
+ PERFUpdateProgramInfo(node->thread_info);
+
+ while(process_pal_thread_list)
+ {
+ current=process_pal_thread_list;
+ process_pal_thread_list = process_pal_thread_list->next;
+ if (current->thread_info)
+ {
+ if (current->thread_info->api_table)
+ {
+ table1 = current->thread_info->api_table;
+ for(i=0;i<PAL_API_NUMBER;i++)
+ {
+ DWORD j;
+ if (table1[i].counter == 0)
+ {
+ continue;
+ }
+ for (j = 0; j < pal_perf_histogram_size; j++)
+ {
+ table0[i].histograms[j] += table1[i].histograms[j];
+ }
+ table0[i].entries += table1[i].entries;
+ table0[i].counter += table1[i].counter;
+ if (table0[i].min_duration > table1[i].min_duration)
+ table0[i].min_duration = table1[i].min_duration;
+ if (table0[i].max_duration < table1[i].max_duration)
+ table0[i].max_duration = table1[i].max_duration;
+ table0[i].sum_duration += table1[i].sum_duration;
+ table0[i].sum_of_square_duration += table1[i].sum_of_square_duration;
+ }
+ PERFUpdateProgramInfo(current->thread_info);
+ if (table1->histograms != NULL)
+ {
+ PAL_free(table1->histograms);
+ }
+ PAL_free(table1);
+ }
+ PERFFlushLog(current->thread_info, FALSE);
+ PAL_free(current->thread_info->pal_write_buf);
+ PAL_free(current->thread_info);
+ }
+ PAL_free(current);
+ }
+ PERFWriteCounters(table0);
+ if (table0->histograms != NULL)
+ {
+ PAL_free(table0->histograms);
+ }
+ PAL_free(table0);
+ PERFFlushLog(node->thread_info, FALSE);
+ PAL_free(node->thread_info->pal_write_buf);
+ PAL_free(node->thread_info);
+ PAL_free(node);
+}
+
+static
+void
+PERFLogFileName(PathCharString& destFileString, const char *fileName, const char *suffix)
+{
+ const char *dir_path;
+ CPalThread* pThread = InternalGetCurrentThread();
+ dir_path = (profile_log_path == NULL) ? "." : profile_log_path;
+
+ destFileString.Append(dir_path, strlen(dir_path));
+ destFileString.Append(PATH_SEPARATOR, strlen(PATH_SEPARATOR));
+ if (fileName != NULL)
+ {
+ destFileString.Append(fileName, strlen(fileName));
+ }
+ else
+ {
+ char buffer[33];
+ char* process_id = itoa(program_info.process_id, buffer, 10);
+ destFileString.Append(process_id, strlen(process_id));
+ destFileString.Append("_", 1);
+
+ char* current_thread = itoa(THREADSilentGetCurrentThreadId(),buffer, 10);
+ destFileString.Append(current_thread, strlen( current_thread));
+ destFileString.Append(suffix, strlen(suffix));
+ }
+
+}
+
+static
+int
+PERFWriteCounters( pal_perf_api_info * table )
+{
+ PathCharString fileName;
+ pal_perf_api_info * off;
+ PERF_FILE * hFile;
+ int i;
+
+ off = table;
+
+ PERFLogFileName(fileName, profile_summary_log_name, "_perf_summary.log");
+ hFile = PERF_FILEFN(fopen)(fileName, "a+");
+ if(hFile != NULL)
+ {
+ PERFPrintProgramHeaderInfo(hFile, TRUE);
+ PERF_FILEFN(fprintf)(hFile,"#api_name\tapi_id\tperf_entries\tperf_exits\tsum_of_latency\tmin_latency\tmax_latency\tstd_dev_latency\tsum_of_square_latency\n");
+ for(i=0;i<PAL_API_NUMBER;i++)
+ {
+ double dev;
+ ULONGLONG min_duration;
+
+ min_duration = (off->min_duration == _UI64_MAX) ? 0 : off->min_duration;
+ if (off->counter >= 1)
+ {
+ dev = PERFComputeStandardDeviation(off);
+ }
+ else
+ {
+ dev = 0.0;
+ }
+
+ if (off->counter > 0 || !report_only_called_apis)
+ {
+ PERF_FILEFN(fprintf)(hFile,"%s\t%d\t" LLFORMAT "\t" LLFORMAT "\t" LLFORMAT "\t" LLFORMAT "\t" LLFORMAT "\t%g\t%g\n",
+ API_list[i], i, off->entries, off->counter,off->sum_duration,
+ min_duration, off->max_duration, dev, off->sum_of_square_duration);
+ }
+
+ off++;
+ }
+ }
+ else
+ {
+ return -1;
+ }
+ PERF_FILEFN(fclose)(hFile);
+
+ if (pal_perf_histogram_size > 0)
+ {
+ off = table;
+ PERFLogFileName(fileName, profile_summary_log_name, "_perf_summary.hist");
+ hFile = PERF_FILEFN(fopen)(fileName, "a+");
+
+ if (hFile != NULL)
+ {
+ DWORD j;
+ PERF_FILEFN(fprintf)(hFile,"#api_name\tapi_id");
+ for (j = 0; j < pal_perf_histogram_size; j++)
+ {
+ PERF_FILEFN(fprintf)(hFile, "\t%d", j*pal_perf_histogram_step);
+ }
+ PERF_FILEFN(fprintf)(hFile, "\n");
+
+ for(i = 0; i < PAL_API_NUMBER; i++)
+ {
+ if (off->counter > 0)
+ {
+ PERF_FILEFN(fprintf)(hFile,"%s\t%d", API_list[i], i);
+
+ for (j = 0; j < pal_perf_histogram_size; j++)
+ {
+ PERF_FILEFN(fprintf)(hFile, "\t%d", off->histograms[j]);
+ }
+
+ PERF_FILEFN(fprintf)(hFile, "\n");
+ }
+
+ off++;
+ }
+ }
+ else
+ {
+ return -1;
+ }
+ PERF_FILEFN(fclose)(hFile);
+ }
+
+ return 0;
+}
+
+static
+BOOL
+PERFReadSetting( )
+{
+ // this function is not safe right now.
+ //more code is required to deal with corrupted input file.
+ BOOL ret;
+ unsigned int index;
+ char line[PAL_PERF_MAX_INPUT];
+ char * ptr;
+ char function_name[PAL_PERF_MAX_FUNCTION_NAME]; //no function can be longer than 127 bytes.
+
+ char * file_name_buf;
+ PathCharString file_name_bufPS;
+ char * input_file_name;
+ char * summary_flag_env;
+ char * nested_tracing_env;
+ char * calibrate_env;
+ char * report_only_called_apis_env;
+ char * wait_for_startup_env;
+ char * pal_perf_histogram_size_env;
+ char * pal_perf_histogram_step_env;
+
+#ifdef PLATFORM_UNIX
+ PAL_FILE * hFile;
+#else
+ FILE * hFile;
+#endif
+
+ if((pal_function_map == NULL) || (PAL_API_NUMBER < 0) )
+ {
+ // should not be here.
+ }
+
+ /* do some env setting here */
+ summary_flag_env = MiscGetenv(PAL_SUMMARY_FLAG);
+ if (summary_flag_env == NULL || strlen(summary_flag_env) == 0)
+ {
+ summary_only = FALSE;
+ }
+ else
+ {
+ summary_only = TRUE;
+ }
+ nested_tracing_env = MiscGetenv(PAL_PERF_NESTED_TRACING);
+ if (nested_tracing_env == NULL || strlen(nested_tracing_env) == 0)
+ {
+ nested_tracing = FALSE;
+ }
+ else
+ {
+ nested_tracing = TRUE;
+ }
+
+ calibrate_env = MiscGetenv(PAL_PERF_CALIBRATE);
+ if (calibrate_env == NULL || strlen(calibrate_env) == 0)
+ {
+ calibrate = FALSE;
+ }
+ else
+ {
+ calibrate = TRUE;
+ }
+
+ report_only_called_apis_env = MiscGetenv(PAL_PERF_REPORT_ONLY_CALLED_APIS);
+ if (report_only_called_apis_env == NULL || strlen(report_only_called_apis_env) == 0)
+ {
+ report_only_called_apis = FALSE;
+ }
+ else
+ {
+ report_only_called_apis = TRUE;
+ }
+
+ wait_for_startup_env = MiscGetenv(PAL_PERF_WAIT_FOR_STARTUP);
+ if (wait_for_startup_env == NULL || strlen(wait_for_startup_env) == 0)
+ {
+ wait_for_startup = FALSE;
+ }
+ else
+ {
+ wait_for_startup = TRUE;
+ }
+
+ pal_perf_histogram_size_env = MiscGetenv(PAL_PERF_HISTOGRAM_SIZE);
+ if (pal_perf_histogram_size_env != NULL && strlen(pal_perf_histogram_size_env) > 0)
+ {
+ long value;
+ char *endptr;
+ value = strtol(pal_perf_histogram_size_env, &endptr, 10);
+ if (value > 0)
+ {
+ pal_perf_histogram_size = (DWORD) value;
+ }
+ }
+
+ pal_perf_histogram_step_env = MiscGetenv(PAL_PERF_HISTOGRAM_STEP);
+ if (pal_perf_histogram_step_env != NULL && strlen(pal_perf_histogram_step_env) > 0)
+ {
+ long value;
+ char *endptr;
+ value = strtol(pal_perf_histogram_step_env, &endptr, 10);
+ if (value > 0)
+ {
+ pal_perf_histogram_step = (DWORD) value;
+ }
+ }
+
+ traced_apis_file = PERFIsValidFile("", MiscGetenv(PAL_PERF_TRACEDAPIS_PATH));
+ enabledapis_path = PERFIsValidFile("", MiscGetenv(PAL_PERF_ENABLED_APIS_PATH));
+ profile_log_path = PERFIsValidPath(MiscGetenv(PAL_PERF_LOG_PATH));
+ perf_default_path = PERFIsValidPath( MiscGetenv(PAL_DEFAULT_PATH));
+ profile_summary_log_name = MiscGetenv(PAL_PERF_SUMMARY_LOG_NAME);
+ if (profile_summary_log_name != NULL && strlen(profile_summary_log_name) == 0)
+ profile_summary_log_name = NULL;
+ profile_time_log_name = MiscGetenv(PAL_PERF_TIME_LOG_NAME);
+ if (profile_time_log_name != NULL && strlen(profile_time_log_name) == 0)
+ profile_time_log_name = NULL;
+
+ if( traced_apis_file == NULL)
+ {
+ if(perf_default_path==NULL)
+ {
+ ret=FALSE;
+ input_file_name = NULL;
+ }
+ else
+ {
+ if( PERFIsValidFile(perf_default_path,traced_apis_filename))
+ {
+ int length = strlen(perf_default_path) + strlen(PATH_SEPARATOR) + strlen(traced_apis_filename);
+ file_name_buf = file_name_bufPS.OpenStringBuffer(length);
+ if ((strcpy_s(file_name_buf, file_name_bufPS.GetSizeOf(), perf_default_path) != SAFECRT_SUCCESS) ||
+ (strcat_s(file_name_buf, file_name_bufPS.GetSizeOf(), PATH_SEPARATOR) != SAFECRT_SUCCESS) ||
+ (strcat_s(file_name_buf, file_name_bufPS.GetSizeOf(), traced_apis_filename) != SAFECRT_SUCCESS))
+ {
+ file_name_bufPS.CloseBuffer(0);
+ ret = FALSE;
+ input_file_name = NULL;
+ }
+ else
+ {
+ file_name_bufPS.CloseBuffer(length);
+ input_file_name = file_name_buf;
+ }
+ }
+ else
+ {
+ ret = FALSE;
+ input_file_name=NULL;
+ }
+ }
+ }
+ else
+ {
+ input_file_name=traced_apis_file;
+ }
+
+ if(input_file_name)
+ {
+#ifdef PLATFORM_UNIX
+ hFile = PAL_fopen(input_file_name, "r+");
+#else
+ hFile = fopen(input_file_name, "r+");
+#endif
+ if ( hFile == NULL )
+ {
+ memset(pal_function_map, 1, PAL_API_NUMBER);
+ ret = FALSE;
+ }
+ else
+ {
+ memset(pal_function_map, 0, PAL_API_NUMBER);
+
+ PAL_fseek(hFile, 0L, SEEK_SET);
+
+ /* Read a line of data from file: */
+ while ( PAL_fgets(line, PAL_PERF_MAX_INPUT, hFile) != NULL )
+ {
+ if(strlen(line)==0)
+ continue;
+ ptr = strchr( line, '#');
+ if( ptr )
+ continue;
+ sscanf_s(line, "%s %u", function_name,&index);
+
+ if( index >= PAL_API_NUMBER)
+ {
+ // some code here to deal with incorrect index.
+ // use function name to cover it.
+ }
+ else if(pal_function_map[index]==1)
+ {
+ // some code here to deal with conflict index.
+ // use function name to cover it.
+ }
+ else
+ {
+ pal_function_map[index]=1;
+ }
+
+ }
+
+#ifdef PLATFORM_UNIX
+ PAL_fclose(hFile);
+#else
+ fclose(hFile);
+#endif
+ ret = TRUE;
+ }
+ }
+ else
+ {
+ memset(pal_function_map, 1, PAL_API_NUMBER);
+ ret = FALSE;
+ }
+
+ if( enabledapis_path == NULL)
+ {
+ if(perf_default_path==NULL)
+ {
+ input_file_name = NULL;
+ }
+ else
+ {
+ if( PERFIsValidFile(perf_default_path,perf_enabled_filename))
+ {
+ if ((strcpy_s(file_name_buf, sizeof(file_name_buf), perf_default_path) != SAFECRT_SUCCESS) ||
+ (strcat_s(file_name_buf, sizeof(file_name_buf), PATH_SEPARATOR) != SAFECRT_SUCCESS) ||
+ (strcat_s(file_name_buf, sizeof(file_name_buf), perf_enabled_filename) != SAFECRT_SUCCESS))
+ {
+ ret = FALSE;
+ input_file_name = NULL;
+ }
+ else
+ {
+ input_file_name = file_name_buf;
+ }
+ }
+ else
+ {
+ input_file_name=NULL;
+ }
+ }
+ }
+ else
+ {
+ input_file_name=enabledapis_path;
+ }
+
+ if(input_file_name == NULL)
+ {
+ return ret;
+ }
+
+#ifdef PLATFORM_UNIX
+ hFile = PAL_fopen(input_file_name, "r+");
+#else
+ hFile = fopen(input_file_name, "r+");
+#endif
+
+ if ( hFile != NULL )
+ {
+ PAL_fseek(hFile, 0L, SEEK_SET);
+
+ /* Read a line of data from file: */
+ while (PAL_fgets(line, PAL_PERF_MAX_INPUT, hFile) != NULL)
+ {
+ if(strlen(line)==0)
+ continue;
+ ptr = strchr( line, '#');
+ if( ptr )
+ continue;
+ sscanf_s(line, "%s %u", function_name,&index);
+
+ if( index >= PAL_API_NUMBER)
+ {
+ // some code here to deal with incorrect index.
+ // use function name to cover it.
+ continue;
+ }
+
+ if (strcpy_s(API_list[index], sizeof(API_list[index]), function_name) != SAFECRT_SUCCESS)
+ {
+ ret = FALSE;
+ break;
+ }
+ }
+
+#ifdef PLATFORM_UNIX
+ PAL_fclose(hFile);
+#else
+ fclose(hFile);
+#endif
+ }
+
+ return ret;
+
+}
+
+
+static
+BOOL
+PERFFlushLog(pal_perf_thread_info * local_info, BOOL output_header)
+{
+ BOOL ret = FALSE;
+ PathCharString fileName;
+ int nWrittenBytes = 0;
+ PERF_FILE * hFile;
+
+ if (summary_only)
+ return TRUE;
+
+ PERFLogFileName(fileName, profile_time_log_name, "_perf_time.log");
+
+ hFile = PERF_FILEFN(fopen)(fileName, "a+");
+
+ if(hFile)
+ {
+ if (output_header)
+ {
+ PERFPrintProgramHeaderInfo(hFile, FALSE);
+ }
+ if (local_info->buf_offset > 0)
+ {
+ nWrittenBytes = PERF_FILEFN(fwrite)(local_info->pal_write_buf, local_info->buf_offset, 1, hFile);
+ if (nWrittenBytes < 1)
+ {
+ ERROR("fwrite() failed with errno == %d\n", errno);
+ return ret;
+ }
+ local_info->buf_offset = 0;
+ }
+ PERF_FILEFN(fclose)(hFile);
+ ret = TRUE;
+ }
+
+ return ret;
+}
+
+void
+PERFLogFunctionEntry(unsigned int pal_api_id, ULONGLONG *pal_perf_start_tick )
+{
+ pal_perf_thread_info * local_info=NULL;
+ pal_perf_api_info * table;
+ char * write_buf;
+ __int32 buf_off;
+ short bufused = 0;
+
+
+#ifndef PLATFORM_UNIX
+ DWORD tv;
+ DWORD last_error;
+ last_error = GetLastError();
+#else
+ struct timeval tv;
+#endif
+
+
+ if(!pal_perf_enabled || pal_function_map==NULL || !pal_profile_on ) // haven't initialize, just quit.
+ return;
+
+ if( pal_function_map[pal_api_id] )
+ {
+ local_info= (pal_perf_thread_info * )pthread_getspecific(PERF_tlsTableKey);
+
+ if (local_info==NULL )
+ {
+ return;
+ }
+ if ( !local_info->profile_enabled ) /* prevent recursion. */
+ {
+ return;
+ }
+ // turn on this flag before call any other functions
+ local_info->profile_enabled = FALSE;
+ table = local_info->api_table;
+ table[pal_api_id].entries++;
+
+ if(!summary_only)
+ {
+ write_buf = (local_info->pal_write_buf);
+ if(local_info->buf_offset >= PAL_PERF_BUFFER_FULL)
+ {
+ PERFFlushLog(local_info, FALSE);
+ }
+
+#ifndef PLATFORM_UNIX
+ tv = GetTickCount();
+#else
+ gettimeofday(&tv, NULL);
+#endif
+
+ buf_off = local_info->buf_offset;
+
+#ifndef PLATFORM_UNIX
+ bufused = snprintf(&write_buf[buf_off], PAL_PERF_MAX_LOGLINE, "----> %d %lu entry.\n", pal_api_id, tv );
+#else
+ bufused = snprintf(&write_buf[buf_off], PAL_PERF_MAX_LOGLINE, "----> %d %lu %06u entry.\n", pal_api_id, tv.tv_sec, tv.tv_usec );
+#endif
+ local_info->buf_offset += bufused;
+ }
+ if(nested_tracing)
+ local_info->profile_enabled = TRUE;
+ *pal_perf_start_tick = PERFGetTicks();
+ }
+#ifndef PLATFORM_UNIX
+ SetLastError( last_error );
+#endif
+ return;
+}
+
+static
+void
+PERFUpdateApiInfo(pal_perf_api_info *api, ULONGLONG duration)
+{
+ DWORD iBucket;
+
+ api->counter++;
+ if (api->min_duration > duration)
+ api->min_duration = duration;
+ if (api->max_duration < duration)
+ api->max_duration = duration;
+ api->sum_duration += duration;
+ api->sum_of_square_duration += (double) duration * (double)duration;
+
+ if (pal_perf_histogram_size > 0)
+ {
+ iBucket = (DWORD)(duration / pal_perf_histogram_step);
+ if (iBucket >= pal_perf_histogram_size)
+ {
+ iBucket = pal_perf_histogram_size - 1;
+ }
+ api->histograms[iBucket]++;
+ }
+
+}
+
+void
+PERFLogFunctionExit(unsigned int pal_api_id, ULONGLONG *pal_perf_start_tick )
+{
+
+ pal_perf_thread_info * local_info;
+ char * buf;
+ short bufused = 0;
+ DWORD off;
+ ULONGLONG duration = 0;
+#ifndef PLATFORM_UNIX
+ DWORD timev;
+ DWORD last_error;
+ last_error = GetLastError();
+#else
+ struct timeval timev;
+
+#endif
+
+ if(!pal_perf_enabled || (pal_function_map == NULL) || !pal_profile_on ) // haven't initiallize yet, just quit.
+ return;
+
+ if (*pal_perf_start_tick != 0)
+ {
+ duration = PERFGetTicks() - *pal_perf_start_tick;
+ }
+ else
+ {
+ return; // pal_perf_start_tick == 0 indicates that we exited PERFLogFunctionEntry before getting the ticks.
+ }
+
+ if( pal_function_map[pal_api_id] )
+ {
+ local_info = (pal_perf_thread_info*)pthread_getspecific(PERF_tlsTableKey);
+
+ if (NULL == local_info ){
+ return;
+ }
+ PERFUpdateApiInfo(&local_info->api_table[pal_api_id], duration);
+ *pal_perf_start_tick = 0;
+
+ if(summary_only)
+ {
+ local_info->profile_enabled = TRUE;
+#ifndef PLATFORM_UNIX
+ SetLastError( last_error );
+#endif
+ return;
+ }
+
+#ifndef PLATFORM_UNIX
+ timev = GetTickCount();
+#else
+ gettimeofday(&timev, NULL);
+#endif
+
+ buf = local_info->pal_write_buf;
+ if(local_info->buf_offset >= PAL_PERF_BUFFER_FULL)
+ {
+ PERFFlushLog(local_info, FALSE);
+ }
+ off = local_info->buf_offset;
+
+#ifndef PLATFORM_UNIX
+ bufused = snprintf(&buf[off], PAL_PERF_MAX_LOGLINE, "<---- %d %lu exit. \n", pal_api_id, timev);
+#else
+ bufused = snprintf(&buf[off], PAL_PERF_MAX_LOGLINE, "<---- %d %lu %06u exit. \n", pal_api_id, timev.tv_sec, timev.tv_usec );
+#endif
+ local_info->buf_offset += bufused;
+ local_info->profile_enabled = TRUE;
+ }
+#ifndef PLATFORM_UNIX
+ SetLastError( last_error );
+#endif
+ return;
+}
+
+void
+PERFNoLatencyProfileEntry(unsigned int pal_api_id )
+{
+ pal_perf_thread_info * local_info=NULL;
+ pal_perf_api_info * table;
+#ifndef PLATFORM_UNIX
+ DWORD last_error;
+ last_error = GetLastError();
+#endif
+
+ if(!pal_perf_enabled || pal_function_map==NULL || !pal_profile_on ) // haven't initialize, just quit.
+ return;
+ if( pal_function_map[pal_api_id] )
+ {
+ local_info= (pal_perf_thread_info * )pthread_getspecific(PERF_tlsTableKey);
+ if (local_info==NULL )
+ {
+#ifndef PLATFORM_UNIX
+ SetLastError( last_error );
+#endif
+ return;
+ }
+ else{
+ table = local_info->api_table;
+ table[pal_api_id].entries++;
+ }
+ }
+#ifndef PLATFORM_UNIX
+ SetLastError( last_error );
+#endif
+ return;
+}
+
+
+void
+PERFEnableThreadProfile(BOOL isInternal)
+{
+ pal_perf_thread_info * local_info;
+#ifndef PLATFORM_UNIX
+ DWORD last_error;
+ last_error = GetLastError();
+#endif
+ if (!pal_perf_enabled)
+ return;
+ if (NULL != (local_info = (pal_perf_thread_info*)pthread_getspecific(PERF_tlsTableKey)))
+ {
+ if (!isInternal || nested_tracing) {
+ local_info->profile_enabled = TRUE;
+ local_info->start_ticks = PERFGetTicks();
+ }
+ }
+#ifndef PLATFORM_UNIX
+ SetLastError( last_error );
+#endif
+}
+
+
+void
+PERFDisableThreadProfile(BOOL isInternal)
+{
+ pal_perf_thread_info * local_info;
+#ifndef PLATFORM_UNIX
+ DWORD last_error;
+ last_error = GetLastError();
+#endif
+ if (!pal_perf_enabled)
+ return;
+ if (NULL != (local_info = (pal_perf_thread_info*)pthread_getspecific(PERF_tlsTableKey)))
+ {
+ if (!isInternal || nested_tracing) {
+ local_info->profile_enabled = FALSE;
+ local_info->total_duration = PERFGetTicks() - local_info->start_ticks;
+ }
+ }
+#ifndef PLATFORM_UNIX
+ SetLastError( last_error );
+#endif
+}
+
+
+void
+PERFEnableProcessProfile( )
+{
+ if (!pal_perf_enabled || wait_for_startup)
+ return;
+ pal_profile_on = TRUE;
+ PERFCalibrate("Overhead when profiling is disabled temporarily for a thread");
+ // record the cpu clock ticks at the beginning of the profiling.
+ program_info.start_ticks = PERFGetTicks();
+}
+
+
+void
+PERFDisableProcessProfile( )
+{
+ if (!pal_perf_enabled)
+ return;
+ pal_profile_on = FALSE;
+ // compute the total program duration in cpu clock ticks.
+ if (program_info.start_ticks != 0)
+ {
+ program_info.elapsed_time += (PERFGetTicks() - program_info.start_ticks);
+ program_info.start_ticks = 0;
+ }
+}
+
+BOOL
+PERFIsProcessProfileEnabled( )
+{
+ return pal_profile_on;
+}
+
+static
+char *
+PERFIsValidPath( const char * path )
+{
+#ifndef PLATFORM_UNIX
+ DWORD result;
+#else
+ DIR * dir;
+#endif
+
+ if(( path==NULL) || (strlen(path)==0))
+ return NULL;
+
+#ifndef PLATFORM_UNIX
+ result = GetFileAttributesA( path );
+ if ((result != INVALID_FILE_ATTRIBUTES) && (result & FILE_ATTRIBUTE_DIRECTORY))
+ {
+ return ((char *) path );
+ }
+#else
+ dir = opendir(path);
+ if( dir!=NULL)
+ {
+ closedir(dir);
+ return ((char *)path);
+ }
+#endif
+ return NULL;
+}
+
+static
+char *
+PERFIsValidFile( const char * path, const char * file)
+{
+ FILE * hFile;
+ char * temp;
+ PathCharString tempPS;
+
+ if(file==NULL || strlen(file)==0)
+ return NULL;
+
+ if ( strcmp(path, "") )
+ {
+ int length = strlen(path) + strlen(PATH_SEPARATOR) + strlen(file);
+ temp = tempPS.OpenStringBuffer(length);
+ if ((strcpy_s(temp, sizeof(temp), path) != SAFECRT_SUCCESS) ||
+ (strcat_s(temp, sizeof(temp), PATH_SEPARATOR) != SAFECRT_SUCCESS) ||
+ (strcat_s(temp, sizeof(temp), file) != SAFECRT_SUCCESS))
+ {
+ tempPS.CloseBuffer(0);
+ return NULL;
+ }
+
+ tempPS.CloseBuffer(length);
+ hFile = fopen(temp, "r");
+ }
+ else
+ {
+ hFile = fopen(file, "r");
+ }
+
+ if(hFile)
+ {
+ fclose(hFile);
+ return ((char *) file);
+ }
+ else
+ return NULL;
+
+}
+
+PALIMPORT
+VOID
+PALAPI
+PAL_EnableProcessProfile(VOID)
+{
+ wait_for_startup = FALSE;
+ pal_profile_on = TRUE;
+ PERFEnableProcessProfile();
+}
+
+PALIMPORT
+VOID
+PALAPI
+PAL_DisableProcessProfile(VOID)
+{
+ pal_profile_on = FALSE;
+ PERFDisableProcessProfile();
+}
+
+PALIMPORT
+BOOL
+PALAPI
+PAL_IsProcessProfileEnabled(VOID)
+{
+ return PERFIsProcessProfileEnabled();
+}
+
+PALIMPORT
+INT64
+PALAPI
+PAL_GetCpuTickCount(VOID)
+{
+ return PERFGetTicks();
+}
+
+#ifndef PLATFORM_UNIX
+#undef snprintf
+#undef MiscGetenv
+#undef pthread_key_t
+#undef pthread_getspecific
+#endif /* ifndef PLATFORM_UNIX definitions */
+
+#endif /* PAL_PERF */
+
+
+
+
diff --git a/src/pal/src/misc/strutil.cpp b/src/pal/src/misc/strutil.cpp
new file mode 100644
index 0000000000..f00b4fde8e
--- /dev/null
+++ b/src/pal/src/misc/strutil.cpp
@@ -0,0 +1,96 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ strutil.cpp
+
+Abstract:
+ Various string-related utility functions
+
+
+
+--*/
+
+#include "pal/corunix.hpp"
+#include "pal/thread.hpp"
+#include "pal/malloc.hpp"
+#include "pal/dbgmsg.h"
+
+SET_DEFAULT_DEBUG_CHANNEL(PAL);
+
+using namespace CorUnix;
+
+/*++
+Function:
+ CPalString::CopyString
+
+ Copies a CPalString into a new (empty) instance, allocating buffer space
+ as necessary
+
+Parameters:
+ psSource -- the string to copy from
+--*/
+
+PAL_ERROR
+CPalString::CopyString(
+ CPalString *psSource
+ )
+{
+ PAL_ERROR palError = NO_ERROR;
+
+ _ASSERTE(NULL != psSource);
+ _ASSERTE(NULL == m_pwsz);
+ _ASSERTE(0 == m_dwStringLength);
+ _ASSERTE(0 == m_dwMaxLength);
+
+ if (0 != psSource->GetStringLength())
+ {
+ _ASSERTE(psSource->GetMaxLength() > psSource->GetStringLength());
+
+ WCHAR *pwsz = reinterpret_cast<WCHAR*>(
+ InternalMalloc(psSource->GetMaxLength() * sizeof(WCHAR))
+ );
+
+ if (NULL != pwsz)
+ {
+ _ASSERTE(NULL != psSource->GetString());
+
+ CopyMemory(
+ pwsz,
+ psSource->GetString(),
+ psSource->GetMaxLength() * sizeof(WCHAR)
+ );
+
+ m_pwsz = pwsz;
+ m_dwStringLength = psSource->GetStringLength();
+ m_dwMaxLength = psSource->GetMaxLength();
+ }
+ else
+ {
+ palError = ERROR_OUTOFMEMORY;
+ }
+ }
+
+ return palError;
+}
+
+/*++
+Function:
+ CPalString::FreeBuffer
+
+ Frees the contained string buffer
+
+--*/
+
+void
+CPalString::FreeBuffer()
+{
+ _ASSERTE(NULL != m_pwsz);
+ free(const_cast<WCHAR*>(m_pwsz));
+}
diff --git a/src/pal/src/misc/sysinfo.cpp b/src/pal/src/misc/sysinfo.cpp
new file mode 100644
index 0000000000..515ccf1cdb
--- /dev/null
+++ b/src/pal/src/misc/sysinfo.cpp
@@ -0,0 +1,363 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ sysinfo.c
+
+Abstract:
+
+ Implements GetSystemInfo.
+
+Revision History:
+
+
+
+--*/
+
+#include "pal/palinternal.h"
+
+#include <sched.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/types.h>
+#if HAVE_SYSCTL
+#include <sys/sysctl.h>
+#elif !HAVE_SYSCONF
+#error Either sysctl or sysconf is required for GetSystemInfo.
+#endif
+
+#include <sys/param.h>
+
+#if HAVE_SYS_VMPARAM_H
+#include <sys/vmparam.h>
+#endif // HAVE_SYS_VMPARAM_H
+
+#if HAVE_MACH_VM_TYPES_H
+#include <mach/vm_types.h>
+#endif // HAVE_MACH_VM_TYPES_H
+
+#if HAVE_MACH_VM_PARAM_H
+#include <mach/vm_param.h>
+#endif // HAVE_MACH_VM_PARAM_H
+
+#if HAVE_MACHINE_VMPARAM_H
+#include <machine/vmparam.h>
+#endif // HAVE_MACHINE_VMPARAM_H
+
+#if defined(_TARGET_MAC64)
+#include <mach/vm_statistics.h>
+#include <mach/mach_types.h>
+#include <mach/mach_init.h>
+#include <mach/mach_host.h>
+#endif // defined(_TARGET_MAC64)
+
+// On some platforms sys/user.h ends up defining _DEBUG; if so
+// remove the definition before including the header and put
+// back our definition afterwards
+#if USER_H_DEFINES_DEBUG
+#define OLD_DEBUG _DEBUG
+#undef _DEBUG
+#endif
+#include <sys/user.h>
+#if USER_H_DEFINES_DEBUG
+#undef _DEBUG
+#define _DEBUG OLD_DEBUG
+#undef OLD_DEBUG
+#endif
+
+#include "pal/dbgmsg.h"
+
+
+SET_DEFAULT_DEBUG_CHANNEL(MISC);
+
+#if defined(_HPUX_) && ( defined (_IA64_) || defined (__hppa__) )
+#include <sys/pstat.h>
+#include <sys/vmparam.h>
+#endif
+
+#ifndef __APPLE__
+#if HAVE_SYSCONF && HAVE__SC_AVPHYS_PAGES
+#define SYSCONF_PAGES _SC_AVPHYS_PAGES
+#elif HAVE_SYSCONF && HAVE__SC_PHYS_PAGES
+#define SYSCONF_PAGES _SC_PHYS_PAGES
+#else
+#error Dont know how to get page-size on this architecture!
+#endif
+#endif // __APPLE__
+
+
+/*++
+Function:
+ GetSystemInfo
+
+GetSystemInfo
+
+The GetSystemInfo function returns information about the current system.
+
+Parameters
+
+lpSystemInfo
+ [out] Pointer to a SYSTEM_INFO structure that receives the information.
+
+Return Values
+
+This function does not return a value.
+
+Note:
+ fields returned by this function are:
+ dwNumberOfProcessors
+ dwPageSize
+Others are set to zero.
+
+--*/
+VOID
+PALAPI
+GetSystemInfo(
+ OUT LPSYSTEM_INFO lpSystemInfo)
+{
+ int nrcpus = 0;
+ long pagesize;
+
+ PERF_ENTRY(GetSystemInfo);
+ ENTRY("GetSystemInfo (lpSystemInfo=%p)\n", lpSystemInfo);
+
+ pagesize = getpagesize();
+
+ lpSystemInfo->wProcessorArchitecture_PAL_Undefined = 0;
+ lpSystemInfo->wReserved_PAL_Undefined = 0;
+ lpSystemInfo->dwPageSize = pagesize;
+ lpSystemInfo->dwActiveProcessorMask_PAL_Undefined = 0;
+
+#if HAVE_SYSCONF
+#if defined(_HPUX_) && ( defined (_IA64_) || defined (__hppa__) )
+ struct pst_dynamic psd;
+ if (pstat_getdynamic(&psd, sizeof(psd), (size_t)1, 0) != -1) {
+ nrcpus = psd.psd_proc_cnt;
+ }
+ else {
+ ASSERT("pstat_getdynamic failed (%d)\n", errno);
+ }
+
+#else // !__hppa__
+ nrcpus = sysconf(_SC_NPROCESSORS_ONLN);
+ if (nrcpus < 1)
+ {
+ ASSERT("sysconf failed for _SC_NPROCESSORS_ONLN (%d)\n", errno);
+ }
+#endif // __hppa__
+#elif HAVE_SYSCTL
+ int rc;
+ size_t sz;
+ int mib[2];
+
+ sz = sizeof(nrcpus);
+ mib[0] = CTL_HW;
+ mib[1] = HW_NCPU;
+ rc = sysctl(mib, 2, &nrcpus, &sz, NULL, 0);
+ if (rc != 0)
+ {
+ ASSERT("sysctl failed for HW_NCPU (%d)\n", errno);
+ }
+#endif // HAVE_SYSCONF
+
+ TRACE("dwNumberOfProcessors=%d\n", nrcpus);
+ lpSystemInfo->dwNumberOfProcessors = nrcpus;
+
+#ifdef VM_MAXUSER_ADDRESS
+ lpSystemInfo->lpMaximumApplicationAddress = (PVOID) VM_MAXUSER_ADDRESS;
+#elif defined(__sun__) || defined(_AIX) || defined(__hppa__) || ( defined (_IA64_) && defined (_HPUX_) ) || defined(__linux__)
+ lpSystemInfo->lpMaximumApplicationAddress = (PVOID) -1;
+#elif defined(USERLIMIT)
+ lpSystemInfo->lpMaximumApplicationAddress = (PVOID) USERLIMIT;
+#elif defined(_WIN64)
+#if defined(USRSTACK64)
+ lpSystemInfo->lpMaximumApplicationAddress = (PVOID) USRSTACK64;
+#else // !USRSTACK64
+#error How come USRSTACK64 is not defined for 64bit?
+#endif // USRSTACK64
+#elif defined(USRSTACK)
+ lpSystemInfo->lpMaximumApplicationAddress = (PVOID) USRSTACK;
+#else
+#error The maximum application address is not known on this platform.
+#endif
+
+ lpSystemInfo->lpMinimumApplicationAddress = (PVOID) pagesize;
+
+ lpSystemInfo->dwProcessorType_PAL_Undefined = 0;
+
+ lpSystemInfo->dwAllocationGranularity = pagesize;
+
+ lpSystemInfo->wProcessorLevel_PAL_Undefined = 0;
+ lpSystemInfo->wProcessorRevision_PAL_Undefined = 0;
+
+ LOGEXIT("GetSystemInfo returns VOID\n");
+ PERF_EXIT(GetSystemInfo);
+}
+
+/*++
+Function:
+ GlobalMemoryStatusEx
+
+GlobalMemoryStatusEx
+
+Retrieves information about the system's current usage of both physical and virtual memory.
+
+Return Values
+
+This function returns a BOOL to indicate its success status.
+
+--*/
+BOOL
+PALAPI
+GlobalMemoryStatusEx(
+ IN OUT LPMEMORYSTATUSEX lpBuffer)
+{
+
+ PERF_ENTRY(GlobalMemoryStatusEx);
+ ENTRY("GlobalMemoryStatusEx (lpBuffer=%p)\n", lpBuffer);
+
+ lpBuffer->dwMemoryLoad = 0;
+ lpBuffer->ullTotalPhys = 0;
+ lpBuffer->ullAvailPhys = 0;
+ lpBuffer->ullTotalPageFile = 0;
+ lpBuffer->ullAvailPageFile = 0;
+ lpBuffer->ullTotalVirtual = 0;
+ lpBuffer->ullAvailVirtual = 0;
+ lpBuffer->ullAvailExtendedVirtual = 0;
+
+ BOOL fRetVal = FALSE;
+
+ // Get the physical memory size
+#if HAVE_SYSCONF && HAVE__SC_PHYS_PAGES
+ int64_t physical_memory;
+
+ // Get the Physical memory size
+ physical_memory = sysconf( _SC_PHYS_PAGES ) * sysconf( _SC_PAGE_SIZE );
+ lpBuffer->ullTotalPhys = (DWORDLONG)physical_memory;
+ fRetVal = TRUE;
+#elif HAVE_SYSCTL
+ int mib[2];
+ int64_t physical_memory;
+ size_t length;
+
+ // Get the Physical memory size
+ mib[0] = CTL_HW;
+ mib[1] = HW_MEMSIZE;
+ length = sizeof(INT64);
+ int rc = sysctl(mib, 2, &physical_memory, &length, NULL, 0);
+ if (rc != 0)
+ {
+ ASSERT("sysctl failed for HW_MEMSIZE (%d)\n", errno);
+ }
+ else
+ {
+ lpBuffer->ullTotalPhys = (DWORDLONG)physical_memory;
+ fRetVal = TRUE;
+ }
+#elif // HAVE_SYSINFO
+ // TODO: implement getting memory details via sysinfo. On Linux, it provides swap file details that
+ // we can use to fill in the xxxPageFile members.
+
+#endif // HAVE_SYSCONF
+
+ // Get the physical memory in use - from it, we can get the physical memory available.
+ // We do this only when we have the total physical memory available.
+ if (lpBuffer->ullTotalPhys > 0)
+ {
+#ifndef __APPLE__
+ lpBuffer->ullAvailPhys = sysconf(SYSCONF_PAGES) * sysconf(_SC_PAGE_SIZE);
+ INT64 used_memory = lpBuffer->ullTotalPhys - lpBuffer->ullAvailPhys;
+ lpBuffer->dwMemoryLoad = (DWORD)((used_memory * 100) / lpBuffer->ullTotalPhys);
+#else
+ vm_size_t page_size;
+ mach_port_t mach_port;
+ mach_msg_type_number_t count;
+ vm_statistics_data_t vm_stats;
+ mach_port = mach_host_self();
+ count = sizeof(vm_stats) / sizeof(natural_t);
+ if (KERN_SUCCESS == host_page_size(mach_port, &page_size))
+ {
+ if (KERN_SUCCESS == host_statistics(mach_port, HOST_VM_INFO, (host_info_t)&vm_stats, &count))
+ {
+ lpBuffer->ullAvailPhys = (int64_t)vm_stats.free_count * (int64_t)page_size;
+ INT64 used_memory = ((INT64)vm_stats.active_count + (INT64)vm_stats.inactive_count + (INT64)vm_stats.wire_count) * (INT64)page_size;
+ lpBuffer->dwMemoryLoad = (DWORD)((used_memory * 100) / lpBuffer->ullTotalPhys);
+ }
+ }
+ mach_port_deallocate(mach_task_self(), mach_port);
+#endif // __APPLE__
+ }
+
+ // There is no API to get the total virtual address space size on
+ // Unix, so we use a constant value representing 128TB, which is
+ // the approximate size of total user virtual address space on
+ // the currently supported Unix systems.
+ static const UINT64 _128TB = (1ull << 47);
+ lpBuffer->ullTotalVirtual = _128TB;
+ lpBuffer->ullAvailVirtual = lpBuffer->ullAvailPhys;
+
+ LOGEXIT("GlobalMemoryStatusEx returns %d\n", fRetVal);
+ PERF_EXIT(GlobalMemoryStatusEx);
+
+ return fRetVal;
+}
+
+PALIMPORT
+DWORD
+PALAPI
+GetCurrentProcessorNumber()
+{
+#if HAVE_SCHED_GETCPU
+ return sched_getcpu();
+#else //HAVE_SCHED_GETCPU
+ return -1;
+#endif //HAVE_SCHED_GETCPU
+}
+
+BOOL
+PALAPI
+PAL_HasGetCurrentProcessorNumber()
+{
+ return HAVE_SCHED_GETCPU;
+}
+
+DWORD
+PALAPI
+PAL_GetLogicalCpuCountFromOS()
+{
+ DWORD numLogicalCores = 0;
+
+#if HAVE_SYSCONF
+ numLogicalCores = sysconf(_SC_NPROCESSORS_ONLN);
+#endif
+
+ return numLogicalCores;
+}
+
+size_t
+PALAPI
+PAL_GetLogicalProcessorCacheSizeFromOS()
+{
+ size_t cacheSize = 0;
+
+#ifdef _SC_LEVEL1_DCACHE_SIZE
+ cacheSize = max(cacheSize, sysconf(_SC_LEVEL1_DCACHE_SIZE));
+#endif
+#ifdef _SC_LEVEL2_CACHE_SIZE
+ cacheSize = max(cacheSize, sysconf(_SC_LEVEL2_CACHE_SIZE));
+#endif
+#ifdef _SC_LEVEL3_CACHE_SIZE
+ cacheSize = max(cacheSize, sysconf(_SC_LEVEL3_CACHE_SIZE));
+#endif
+#ifdef _SC_LEVEL4_CACHE_SIZE
+ cacheSize = max(cacheSize, sysconf(_SC_LEVEL4_CACHE_SIZE));
+#endif
+
+ return cacheSize;
+}
diff --git a/src/pal/src/misc/time.cpp b/src/pal/src/misc/time.cpp
new file mode 100644
index 0000000000..918f92a90f
--- /dev/null
+++ b/src/pal/src/misc/time.cpp
@@ -0,0 +1,396 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ time.c
+
+Abstract:
+
+ Implementation of time related WIN API functions.
+
+
+
+--*/
+
+#include "pal/palinternal.h"
+#include "pal/dbgmsg.h"
+#include "pal/misc.h"
+
+#include <time.h>
+#include <sys/time.h>
+#include <errno.h>
+#include <string.h>
+#include <sched.h>
+
+#if HAVE_MACH_ABSOLUTE_TIME
+#include <mach/mach_time.h>
+static mach_timebase_info_data_t s_TimebaseInfo;
+#endif
+
+using namespace CorUnix;
+
+SET_DEFAULT_DEBUG_CHANNEL(MISC);
+
+/*++
+Function :
+TIMEInitialize
+
+Initialize all Time-related stuff related
+
+(no parameters)
+
+Return value :
+TRUE if Time support initialization succeeded
+FALSE otherwise
+--*/
+BOOL TIMEInitialize(void)
+{
+#if HAVE_MACH_ABSOLUTE_TIME
+ kern_return_t machRet;
+ if ((machRet = mach_timebase_info(&s_TimebaseInfo)) != KERN_SUCCESS)
+ {
+ ASSERT("mach_timebase_info() failed: %s\n", mach_error_string(machRet));
+ return FALSE;
+ }
+#endif
+
+ return TRUE;
+}
+
+
+/*++
+Function:
+ GetSystemTime
+
+The GetSystemTime function retrieves the current system date and
+time. The system time is expressed in Coordinated Universal Time
+(UTC).
+
+Parameters
+
+lpSystemTime
+ [out] Pointer to a SYSTEMTIME structure to receive the current system date and time.
+
+Return Values
+
+This function does not return a value.
+
+--*/
+VOID
+PALAPI
+GetSystemTime(
+ OUT LPSYSTEMTIME lpSystemTime)
+{
+ time_t tt;
+#if HAVE_GMTIME_R
+ struct tm ut;
+#endif /* HAVE_GMTIME_R */
+ struct tm *utPtr;
+ struct timeval timeval;
+ int timeofday_retval;
+
+ PERF_ENTRY(GetSystemTime);
+ ENTRY("GetSystemTime (lpSystemTime=%p)\n", lpSystemTime);
+
+ tt = time(NULL);
+
+ /* We can't get millisecond resolution from time(), so we get it from
+ gettimeofday() */
+ timeofday_retval = gettimeofday(&timeval,NULL);
+
+#if HAVE_GMTIME_R
+ utPtr = &ut;
+ if (gmtime_r(&tt, utPtr) == NULL)
+#else /* HAVE_GMTIME_R */
+ if ((utPtr = gmtime(&tt)) == NULL)
+#endif /* HAVE_GMTIME_R */
+ {
+ ASSERT("gmtime() failed; errno is %d (%s)\n", errno, strerror(errno));
+ goto EXIT;
+ }
+
+ lpSystemTime->wYear = 1900 + utPtr->tm_year;
+ lpSystemTime->wMonth = utPtr->tm_mon + 1;
+ lpSystemTime->wDayOfWeek = utPtr->tm_wday;
+ lpSystemTime->wDay = utPtr->tm_mday;
+ lpSystemTime->wHour = utPtr->tm_hour;
+ lpSystemTime->wMinute = utPtr->tm_min;
+ lpSystemTime->wSecond = utPtr->tm_sec;
+
+ if(-1 == timeofday_retval)
+ {
+ ASSERT("gettimeofday() failed; errno is %d (%s)\n",
+ errno, strerror(errno));
+ lpSystemTime->wMilliseconds = 0;
+ }
+ else
+ {
+ int old_seconds;
+ int new_seconds;
+
+ lpSystemTime->wMilliseconds = timeval.tv_usec/tccMillieSecondsToMicroSeconds;
+
+ old_seconds = utPtr->tm_sec;
+ new_seconds = timeval.tv_sec%60;
+
+ /* just in case we reached the next second in the interval between
+ time() and gettimeofday() */
+ if( old_seconds!=new_seconds )
+ {
+ TRACE("crossed seconds boundary; setting milliseconds to 999\n");
+ lpSystemTime->wMilliseconds = 999;
+ }
+ }
+EXIT:
+ LOGEXIT("GetSystemTime returns void\n");
+ PERF_EXIT(GetSystemTime);
+}
+
+/*++
+Function:
+ GetTickCount
+
+The GetTickCount function retrieves the number of milliseconds that
+have elapsed since the system was started. It is limited to the
+resolution of the system timer. To obtain the system timer resolution,
+use the GetSystemTimeAdjustment function.
+
+Parameters
+
+This function has no parameters.
+
+Return Values
+
+The return value is the number of milliseconds that have elapsed since
+the system was started.
+
+In the ROTOR implementation the return value is the elapsed time since
+the start of the epoch.
+
+--*/
+DWORD
+PALAPI
+GetTickCount(
+ VOID)
+{
+ DWORD retval = 0;
+ PERF_ENTRY(GetTickCount);
+ ENTRY("GetTickCount ()\n");
+
+ // Get the 64-bit count from GetTickCount64 and truncate the results.
+ retval = (DWORD) GetTickCount64();
+
+ LOGEXIT("GetTickCount returns DWORD %u\n", retval);
+ PERF_EXIT(GetTickCount);
+ return retval;
+}
+
+BOOL
+PALAPI
+QueryPerformanceCounter(
+ OUT LARGE_INTEGER *lpPerformanceCount
+ )
+{
+ BOOL retval = TRUE;
+
+ PERF_ENTRY(QueryPerformanceCounter);
+ ENTRY("QueryPerformanceCounter()\n");
+ do
+#if HAVE_CLOCK_MONOTONIC
+ {
+ struct timespec ts;
+ if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0)
+ {
+ ASSERT("clock_gettime(CLOCK_MONOTONIC) failed; errno is %d (%s)\n", errno, strerror(errno));
+ retval = FALSE;
+ break;
+ }
+ lpPerformanceCount->QuadPart =
+ (LONGLONG)ts.tv_sec * (LONGLONG)tccSecondsToNanoSeconds + (LONGLONG)ts.tv_nsec;
+ }
+#elif HAVE_MACH_ABSOLUTE_TIME
+ {
+ lpPerformanceCount->QuadPart = (LONGLONG)mach_absolute_time();
+ }
+#elif HAVE_GETHRTIME
+ {
+ lpPerformanceCount->QuadPart = (LONGLONG)gethrtime();
+ }
+#elif HAVE_READ_REAL_TIME
+ {
+ timebasestruct_t tb;
+ read_real_time(&tb, TIMEBASE_SZ);
+ if (time_base_to_time(&tb, TIMEBASE_SZ) != 0)
+ {
+ ASSERT("time_base_to_time() failed; errno is %d (%s)\n", errno, strerror(errno));
+ retval = FALSE;
+ break;
+ }
+ lpPerformanceCount->QuadPart =
+ (LONGLONG)tb.tb_high * (LONGLONG)tccSecondsToNanoSeconds + (LONGLONG)tb.tb_low;
+ }
+#else
+ {
+ struct timeval tv;
+ if (gettimeofday(&tv, NULL) == -1)
+ {
+ ASSERT("gettimeofday() failed; errno is %d (%s)\n", errno, strerror(errno));
+ retval = FALSE;
+ break;
+ }
+ lpPerformanceCount->QuadPart =
+ (LONGLONG)tv.tv_sec * (LONGLONG)tccSecondsToMicroSeconds + (LONGLONG)tv.tv_usec;
+ }
+#endif // HAVE_CLOCK_MONOTONIC
+ while (false);
+
+ LOGEXIT("QueryPerformanceCounter\n");
+ PERF_EXIT(QueryPerformanceCounter);
+ return retval;
+}
+
+BOOL
+PALAPI
+QueryPerformanceFrequency(
+ OUT LARGE_INTEGER *lpFrequency
+ )
+{
+ BOOL retval = TRUE;
+ PERF_ENTRY(QueryPerformanceFrequency);
+ ENTRY("QueryPerformanceFrequency()\n");
+#if HAVE_GETHRTIME || HAVE_READ_REAL_TIME || HAVE_CLOCK_MONOTONIC
+ lpFrequency->QuadPart = (LONGLONG)tccSecondsToNanoSeconds;
+#elif HAVE_MACH_ABSOLUTE_TIME
+ // use denom == 0 to indicate that s_TimebaseInfo is uninitialised.
+ if (s_TimebaseInfo.denom == 0)
+ {
+ ASSERT("s_TimebaseInfo is uninitialized.\n");
+ retval = FALSE;
+ }
+ else
+ {
+ lpFrequency->QuadPart = (LONGLONG)tccSecondsToNanoSeconds * ((LONGLONG)s_TimebaseInfo.denom / (LONGLONG)s_TimebaseInfo.numer);
+ }
+#else
+ lpFrequency->QuadPart = (LONGLONG)tccSecondsToMicroSeconds;
+#endif // HAVE_GETHRTIME || HAVE_READ_REAL_TIME || HAVE_CLOCK_MONOTONIC
+ LOGEXIT("QueryPerformanceFrequency\n");
+ PERF_EXIT(QueryPerformanceFrequency);
+ return retval;
+}
+
+/*++
+Function:
+ QueryThreadCycleTime
+
+Puts the execution time (in nanoseconds) for the thread pointed to by ThreadHandle, into the unsigned long
+pointed to by CycleTime. ThreadHandle must refer to the current thread. Returns TRUE on success, FALSE on
+failure.
+--*/
+
+BOOL
+PALAPI
+QueryThreadCycleTime(
+ IN HANDLE ThreadHandle,
+ OUT PULONG64 CycleTime
+ )
+{
+
+ ULONG64 calcTime;
+ FILETIME kernelTime, userTime;
+ BOOL retval = TRUE;
+
+ if(!GetThreadTimesInternal(ThreadHandle, &kernelTime, &userTime))
+ {
+ ASSERT("Could not get cycle time for current thread");
+ retval = FALSE;
+ goto EXIT;
+ }
+
+ calcTime = ((ULONG64)kernelTime.dwHighDateTime << 32);
+ calcTime += (ULONG64)kernelTime.dwLowDateTime;
+ calcTime += ((ULONG64)userTime.dwHighDateTime << 32);
+ calcTime += (ULONG64)userTime.dwLowDateTime;
+ *CycleTime = calcTime;
+
+EXIT:
+ return retval;
+}
+
+/*++
+Function:
+ GetTickCount64
+
+Returns a 64-bit tick count with a millisecond resolution. It tries its best
+to return monotonically increasing counts and avoid being affected by changes
+to the system clock (either due to drift or due to explicit changes to system
+time).
+--*/
+PALAPI
+ULONGLONG
+GetTickCount64()
+{
+ ULONGLONG retval = 0;
+
+#if HAVE_CLOCK_MONOTONIC_COARSE || HAVE_CLOCK_MONOTONIC
+ {
+ clockid_t clockType =
+#if HAVE_CLOCK_MONOTONIC_COARSE
+ CLOCK_MONOTONIC_COARSE; // good enough resolution, fastest speed
+#else
+ CLOCK_MONOTONIC;
+#endif
+ struct timespec ts;
+ if (clock_gettime(clockType, &ts) != 0)
+ {
+ ASSERT("clock_gettime(CLOCK_MONOTONIC*) failed; errno is %d (%s)\n", errno, strerror(errno));
+ goto EXIT;
+ }
+ retval = (ts.tv_sec * tccSecondsToMillieSeconds)+(ts.tv_nsec / tccMillieSecondsToNanoSeconds);
+ }
+#elif HAVE_MACH_ABSOLUTE_TIME
+ {
+ // use denom == 0 to indicate that s_TimebaseInfo is uninitialised.
+ if (s_TimebaseInfo.denom == 0)
+ {
+ ASSERT("s_TimebaseInfo is uninitialized.\n");
+ goto EXIT;
+ }
+ retval = (mach_absolute_time() * s_TimebaseInfo.numer / s_TimebaseInfo.denom) / tccMillieSecondsToNanoSeconds;
+ }
+#elif HAVE_GETHRTIME
+ {
+ retval = (ULONGLONG)(gethrtime() / tccMillieSecondsToNanoSeconds);
+ }
+#elif HAVE_READ_REAL_TIME
+ {
+ timebasestruct_t tb;
+ read_real_time(&tb, TIMEBASE_SZ);
+ if (time_base_to_time(&tb, TIMEBASE_SZ) != 0)
+ {
+ ASSERT("time_base_to_time() failed; errno is %d (%s)\n", errno, strerror(errno));
+ goto EXIT;
+ }
+ retval = (tb.tb_high * tccSecondsToMillieSeconds)+(tb.tb_low / tccMillieSecondsToNanoSeconds);
+ }
+#else
+ {
+ struct timeval tv;
+ if (gettimeofday(&tv, NULL) == -1)
+ {
+ ASSERT("gettimeofday() failed; errno is %d (%s)\n", errno, strerror(errno));
+ goto EXIT;
+ }
+ retval = (tv.tv_sec * tccSecondsToMillieSeconds) + (tv.tv_usec / tccMillieSecondsToMicroSeconds);
+ }
+#endif // HAVE_CLOCK_MONOTONIC
+EXIT:
+ return retval;
+}
+
diff --git a/src/pal/src/misc/tracepointprovider.cpp b/src/pal/src/misc/tracepointprovider.cpp
new file mode 100644
index 0000000000..8d20266688
--- /dev/null
+++ b/src/pal/src/misc/tracepointprovider.cpp
@@ -0,0 +1,109 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+Module Name:
+
+ tracepointprovider.cpp
+
+Abstract:
+
+ Trace point provider support
+
+Revision History:
+
+--*/
+
+#include "pal/palinternal.h"
+#include "pal/dbgmsg.h"
+#include "pal/file.h"
+#include "pal/process.h"
+#include "pal/module.h"
+#include "pal/malloc.hpp"
+#include "pal/stackstring.hpp"
+
+#include <errno.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <dlfcn.h>
+
+SET_DEFAULT_DEBUG_CHANNEL(MISC);
+
+/*++
+
+Initialization logic for LTTng tracepoint providers.
+
+--*/
+#if defined(__linux__)
+
+static const char tpLibName[] = "libcoreclrtraceptprovider.so";
+
+
+/*++
+
+NOTE: PAL_InitializeTracing MUST NOT depend on anything in the PAL itself
+as it is called prior to PAL initialization.
+
+Constructor priority is set to 200, which allows for constructors to
+guarantee that they run before or after this constructor by setting
+their priority appropriately.
+
+Priority values must be greater than 100. The lower the value,
+the higher the priority.
+
+--*/
+__attribute__((__unused__))
+__attribute__((constructor (200)))
+static void
+PAL_InitializeTracing(void)
+{
+ // Get the path to the currently executing shared object (libcoreclr.so).
+ Dl_info info;
+ int succeeded = dladdr((void *)PAL_InitializeTracing, &info);
+ if(!succeeded)
+ {
+ return;
+ }
+
+ // Copy the path and modify the shared object name to be the tracepoint provider.
+ PathCharString tpProvPath;
+ int pathLen = strlen(info.dli_fname);
+
+ // Find the length of the full path without the shared object name, including the trailing slash.
+ int lastTrailingSlashLen = -1;
+ for(int i=pathLen-1; i>=0; i--)
+ {
+ if(info.dli_fname[i] == '/')
+ {
+ lastTrailingSlashLen = i+1;
+ break;
+ }
+ }
+
+ // Make sure we found the last trailing slash.
+ if(lastTrailingSlashLen == -1)
+ {
+ return;
+ }
+
+ SIZE_T tpLibNameLen = strlen(tpLibName);
+
+ if( !tpProvPath.Reserve(tpLibNameLen + lastTrailingSlashLen) ||
+ // Copy the path without the shared object name.
+ !tpProvPath.Append(info.dli_fname, lastTrailingSlashLen) ||
+ // Append the shared object name for the tracepoint provider.
+ !tpProvPath.Append(tpLibName, tpLibNameLen))
+ {
+ return;
+ }
+
+
+
+ // Load the tracepoint provider.
+ // It's OK if this fails - that just means that tracing dependencies aren't available.
+ dlopen(tpProvPath, RTLD_NOW | RTLD_GLOBAL);
+}
+
+#endif
diff --git a/src/pal/src/misc/utils.cpp b/src/pal/src/misc/utils.cpp
new file mode 100644
index 0000000000..1e333d19ac
--- /dev/null
+++ b/src/pal/src/misc/utils.cpp
@@ -0,0 +1,320 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ misc/utils.c
+
+Abstract:
+
+ Miscellaneous helper functions for the PAL, which don't fit anywhere else
+
+
+
+--*/
+
+#include "pal/palinternal.h"
+#if HAVE_VM_ALLOCATE
+#include <mach/message.h>
+#endif //HAVE_VM_ALLOCATE
+
+#include "pal/utils.h"
+#include "pal/dbgmsg.h"
+#include "pal/file.h"
+
+#include <errno.h>
+#include <string.h>
+
+
+SET_DEFAULT_DEBUG_CHANNEL(MISC);
+
+// In safemath.h, Template SafeInt uses macro _ASSERTE, which need to use variable
+// defdbgchan defined by SET_DEFAULT_DEBUG_CHANNEL. Therefore, the include statement
+// should be placed after the SET_DEFAULT_DEBUG_CHANNEL(MISC)
+#include <safemath.h>
+
+/*++
+Function:
+ UTIL_inverse_wcspbrk
+
+ Opposite of wcspbrk : searches a string for the first character NOT in the
+ given set
+
+Parameters :
+ LPWSTR lpwstr : string to search
+ LPCWSTR charset : list of characters to search for
+
+Return value :
+ pointer to first character of lpwstr that isn't in the set
+ NULL if all characters are in the set
+--*/
+LPWSTR UTIL_inverse_wcspbrk(LPWSTR lpwstr, LPCWSTR charset)
+{
+ while(*lpwstr)
+ {
+ if(NULL == PAL_wcschr(charset,*lpwstr))
+ {
+ return lpwstr;
+ }
+ lpwstr++;
+ }
+ return NULL;
+}
+
+
+/*++
+Function :
+ UTIL_IsReadOnlyBitsSet
+
+ Takes a struct stat *
+ Returns true if the file is read only,
+--*/
+BOOL UTIL_IsReadOnlyBitsSet( struct stat * stat_data )
+{
+ BOOL bRetVal = FALSE;
+
+ /* Check for read permissions. */
+ if ( stat_data->st_uid == geteuid() )
+ {
+ /* The process owner is the file owner as well. */
+ if ( ( stat_data->st_mode & S_IRUSR ) && !( stat_data->st_mode & S_IWUSR ) )
+ {
+ bRetVal = TRUE;
+ }
+ }
+ else if ( stat_data->st_gid == getegid() )
+ {
+ /* The process's owner is in the same group as the file's owner. */
+ if ( ( stat_data->st_mode & S_IRGRP ) && !( stat_data->st_mode & S_IWGRP ) )
+ {
+ bRetVal = TRUE;
+ }
+ }
+ else
+ {
+ /* Check the other bits to see who can access the file. */
+ if ( ( stat_data->st_mode & S_IROTH ) && !( stat_data->st_mode & S_IWOTH ) )
+ {
+ bRetVal = TRUE;
+ }
+ }
+
+ return bRetVal;
+}
+
+/*++
+Function :
+ UTIL_IsExecuteBitsSet
+
+ Takes a struct stat *
+ Returns true if the file is executable,
+--*/
+BOOL UTIL_IsExecuteBitsSet( struct stat * stat_data )
+{
+ BOOL bRetVal = FALSE;
+
+ if ( (stat_data->st_mode & S_IFMT) == S_IFDIR )
+ {
+ return FALSE;
+ }
+
+ /* Check for read permissions. */
+ if ( stat_data->st_uid == geteuid() )
+ {
+ /* The process owner is the file owner as well. */
+ if ( ( stat_data->st_mode & S_IXUSR ) )
+ {
+ bRetVal = TRUE;
+ }
+ }
+ else if ( stat_data->st_gid == getegid() )
+ {
+ /* The process's owner is in the same group as the file's owner. */
+ if ( ( stat_data->st_mode & S_IXGRP ) )
+ {
+ bRetVal = TRUE;
+ }
+ }
+ else
+ {
+ /* Check the other bits to see who can access the file. */
+ if ( ( stat_data->st_mode & S_IXOTH ) )
+ {
+ bRetVal = TRUE;
+ }
+ }
+
+ return bRetVal;
+}
+
+/*++
+Function :
+ UTIL_WCToMB_Alloc
+
+ Converts a wide string to a multibyte string, allocating the required buffer
+
+Parameters :
+ LPCWSTR lpWideCharStr : string to convert
+ int cchWideChar : number of wide characters to convert
+ (-1 to convert a complete null-termnated string)
+
+Return Value :
+ newly allocated buffer containing the converted string. Conversion is
+ performed using CP_ACP. Buffer is allocated with malloc(), release it
+ with free().
+ In case if failure, LastError will be set.
+--*/
+LPSTR UTIL_WCToMB_Alloc(LPCWSTR lpWideCharStr, int cchWideChar)
+{
+ int length;
+ LPSTR lpMultiByteStr;
+
+ /* get required buffer length */
+ length = WideCharToMultiByte(CP_ACP, 0, lpWideCharStr, cchWideChar,
+ NULL, 0, NULL, NULL);
+ if(0 == length)
+ {
+ ERROR("WCToMB error; GetLastError returns %#x", GetLastError());
+ return NULL;
+ }
+
+ /* allocate required buffer */
+ lpMultiByteStr = (LPSTR)PAL_malloc(length);
+ if(NULL == lpMultiByteStr)
+ {
+ ERROR("malloc() failed! errno is %d (%s)\n", errno,strerror(errno));
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ return NULL;
+ }
+
+ /* convert into allocated buffer */
+ length = WideCharToMultiByte(CP_ACP, 0, lpWideCharStr, cchWideChar,
+ lpMultiByteStr, length, NULL, NULL);
+ if(0 == length)
+ {
+ ASSERT("WCToMB error; GetLastError returns %#x\n", GetLastError());
+ PAL_free(lpMultiByteStr);
+ return NULL;
+ }
+ return lpMultiByteStr;
+}
+
+/*++
+Function :
+ UTIL_MBToWC_Alloc
+
+ Converts a multibyte string to a wide string, allocating the required buffer
+
+Parameters :
+ LPCSTR lpMultiByteStr : string to convert
+ int cbMultiByte : number of bytes to convert
+ (-1 to convert a complete null-termnated string)
+
+Return Value :
+ newly allocated buffer containing the converted string. Conversion is
+ performed using CP_ACP. Buffer is allocated with malloc(), release it
+ with free().
+ In case if failure, LastError will be set.
+--*/
+LPWSTR UTIL_MBToWC_Alloc(LPCSTR lpMultiByteStr, int cbMultiByte)
+{
+ int length;
+ LPWSTR lpWideCharStr;
+
+ /* get required buffer length */
+ length = MultiByteToWideChar(CP_ACP, 0, lpMultiByteStr, cbMultiByte,
+ NULL, 0);
+ if(0 == length)
+ {
+ ERROR("MBToWC error; GetLastError returns %#x", GetLastError());
+ return NULL;
+ }
+
+ /* allocate required buffer */
+ size_t fullsize;
+ if (!ClrSafeInt<size_t>::multiply(length,sizeof(WCHAR),fullsize))
+ {
+ ERROR("integer overflow! length = %d , sizeof(WCHAR) = (%d)\n", length,sizeof(WCHAR) );
+ SetLastError(ERROR_ARITHMETIC_OVERFLOW);
+ return NULL;
+ }
+
+ lpWideCharStr = (LPWSTR)PAL_malloc(fullsize);
+ if(NULL == lpWideCharStr)
+ {
+ ERROR("malloc() failed! errno is %d (%s)\n", errno,strerror(errno));
+ SetLastError(FILEGetLastErrorFromErrno());
+ return NULL;
+ }
+
+ /* convert into allocated buffer */
+ length = MultiByteToWideChar(CP_ACP, 0, lpMultiByteStr, cbMultiByte,
+ lpWideCharStr, length);
+ if(0 >= length)
+ {
+ ASSERT("MCToMB error; GetLastError returns %#x\n", GetLastError());
+ PAL_free(lpWideCharStr);
+ return NULL;
+ }
+ return lpWideCharStr;
+}
+
+#if HAVE_VM_ALLOCATE
+/*++
+Function:
+ UTIL_MachErrorToPalError
+
+ Maps a Mach kern_return_t to a Win32 error code.
+--*/
+DWORD UTIL_MachErrorToPalError(kern_return_t MachReturn)
+{
+ switch (MachReturn)
+ {
+ case KERN_SUCCESS:
+ return ERROR_SUCCESS;
+
+ case KERN_NO_ACCESS:
+ case KERN_INVALID_CAPABILITY:
+ return ERROR_ACCESS_DENIED;
+
+ case KERN_TERMINATED:
+ return ERROR_INVALID_HANDLE;
+
+ case KERN_INVALID_ADDRESS:
+ return ERROR_INVALID_ADDRESS;
+
+ case KERN_NO_SPACE:
+ return ERROR_NOT_ENOUGH_MEMORY;
+
+ case KERN_INVALID_ARGUMENT:
+ return ERROR_INVALID_PARAMETER;
+
+ default:
+ ASSERT("Unknown kern_return_t value %d - reporting ERROR_INTERNAL_ERROR\n", MachReturn);
+ return ERROR_INTERNAL_ERROR;
+ }
+}
+
+/*++
+Function:
+ UTIL_SetLastErrorFromMach
+
+ Sets Win32 LastError according to the argument Mach kern_return_t value,
+ provided it indicates an error. If the argument indicates success, does
+ not modify LastError.
+--*/
+void UTIL_SetLastErrorFromMach(kern_return_t MachReturn)
+{
+ DWORD palError = UTIL_MachErrorToPalError(MachReturn);
+ if (palError != ERROR_SUCCESS)
+ {
+ SetLastError(palError);
+ }
+}
+#endif //HAVE_VM_ALLOCATE
+
diff --git a/src/pal/src/misc/version.cpp b/src/pal/src/misc/version.cpp
new file mode 100644
index 0000000000..7a9f90a320
--- /dev/null
+++ b/src/pal/src/misc/version.cpp
@@ -0,0 +1,119 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ version.c
+
+Abstract:
+
+ Implementation of functions for getting platform.OS versions.
+
+Revision History:
+
+
+
+--*/
+
+#include "pal/palinternal.h"
+#include "pal/dbgmsg.h"
+
+SET_DEFAULT_DEBUG_CHANNEL(MISC);
+
+/*++
+Function:
+ GetVersionExA
+
+
+
+GetVersionEx
+
+The GetVersionEx function obtains extended information about the
+version of the operating system that is currently running.
+
+Parameters
+
+lpVersionInfo
+ [in/out] Pointer to an OSVERSIONINFO data structure that the
+ function fills with operating system version information.
+
+ Before calling the GetVersionEx function, set the
+ dwOSVersionInfoSize member of the OSVERSIONINFO data structure
+ to sizeof(OSVERSIONINFO).
+
+Return Values
+
+If the function succeeds, the return value is a nonzero value.
+
+If the function fails, the return value is zero. To get extended error
+information, call GetLastError. The function fails if you specify an
+invalid value for the dwOSVersionInfoSize member of the OSVERSIONINFO
+structure.
+
+--*/
+BOOL
+PALAPI
+GetVersionExA(
+ IN OUT LPOSVERSIONINFOA lpVersionInformation)
+{
+ BOOL bRet = TRUE;
+ PERF_ENTRY(GetVersionExA);
+ ENTRY("GetVersionExA (lpVersionInformation=%p)\n", lpVersionInformation);
+
+ if (lpVersionInformation->dwOSVersionInfoSize == sizeof(OSVERSIONINFOA))
+ {
+ lpVersionInformation->dwMajorVersion = 5; /* same as WIN2000 */
+ lpVersionInformation->dwMinorVersion = 0; /* same as WIN2000 */
+ lpVersionInformation->dwBuildNumber = 0;
+ lpVersionInformation->dwPlatformId = VER_PLATFORM_UNIX;
+ lpVersionInformation->szCSDVersion[0] = '\0'; /* no service pack */
+ }
+ else
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ bRet = FALSE;
+ }
+ LOGEXIT("GetVersionExA returning BOOL %d\n", bRet);
+ PERF_EXIT(GetVersionExA);
+ return bRet;
+}
+
+
+/*++
+Function:
+ GetVersionExW
+
+See GetVersionExA
+--*/
+BOOL
+PALAPI
+GetVersionExW(
+ IN OUT LPOSVERSIONINFOW lpVersionInformation)
+{
+ BOOL bRet = TRUE;
+
+ PERF_ENTRY(GetVersionExW);
+ ENTRY("GetVersionExW (lpVersionInformation=%p)\n", lpVersionInformation);
+
+ if (lpVersionInformation->dwOSVersionInfoSize == sizeof(OSVERSIONINFOW))
+ {
+ lpVersionInformation->dwMajorVersion = 5; /* same as WIN2000 */
+ lpVersionInformation->dwMinorVersion = 0; /* same as WIN2000 */
+ lpVersionInformation->dwBuildNumber = 0;
+ lpVersionInformation->dwPlatformId = VER_PLATFORM_UNIX;
+ lpVersionInformation->szCSDVersion[0] = '\0'; /* no service pack */
+ }
+ else
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ bRet = FALSE;
+ }
+ LOGEXIT("GetVersionExW returning BOOL %d\n", bRet);
+ PERF_EXIT(GetVersionExW);
+ return bRet;
+}
diff --git a/src/pal/src/objmgr/palobjbase.cpp b/src/pal/src/objmgr/palobjbase.cpp
new file mode 100644
index 0000000000..27842f6d97
--- /dev/null
+++ b/src/pal/src/objmgr/palobjbase.cpp
@@ -0,0 +1,359 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ palobjbase.cpp
+
+Abstract:
+ PAL object base class
+
+
+
+--*/
+
+#include "palobjbase.hpp"
+#include "pal/malloc.hpp"
+#include "pal/dbgmsg.h"
+
+SET_DEFAULT_DEBUG_CHANNEL(PAL);
+
+using namespace CorUnix;
+
+CObjectType* CObjectType::s_rgotIdMapping[ObjectTypeIdCount];
+
+/*++
+Function:
+ CPalObjectBase::Initialize
+
+ Performs possibly-failing initialization for a newly-constructed
+ object
+
+Parameters:
+ pthr -- thread data for calling thread
+ poa -- the object attributes (e.g., name) for the object
+--*/
+
+PAL_ERROR
+CPalObjectBase::Initialize(
+ CPalThread *pthr,
+ CObjectAttributes *poa
+ )
+{
+ PAL_ERROR palError = NO_ERROR;
+
+ _ASSERTE(NULL != pthr);
+ _ASSERTE(NULL != poa);
+
+ ENTRY("CPalObjectBase::Initialize"
+ "(this = %p, pthr = %p, poa = %p)\n",
+ this,
+ pthr,
+ poa
+ );
+
+ if (0 != m_pot->GetImmutableDataSize())
+ {
+ m_pvImmutableData = InternalMalloc(m_pot->GetImmutableDataSize());
+ if (NULL != m_pvImmutableData)
+ {
+ ZeroMemory(m_pvImmutableData, m_pot->GetImmutableDataSize());
+ }
+ else
+ {
+ ERROR("Unable to allocate immutable data\n");
+ palError = ERROR_OUTOFMEMORY;
+ goto IntializeExit;
+ }
+ }
+
+ if (0 != m_pot->GetProcessLocalDataSize())
+ {
+ palError = m_sdlLocalData.Initialize();
+ if (NO_ERROR != palError)
+ {
+ ERROR("Unable to initialize local data lock!\n");
+ goto IntializeExit;
+ }
+
+ m_pvLocalData = InternalMalloc(m_pot->GetProcessLocalDataSize());
+ if (NULL != m_pvLocalData)
+ {
+ ZeroMemory(m_pvLocalData, m_pot->GetProcessLocalDataSize());
+ }
+ else
+ {
+ ERROR("Unable to allocate local data\n");
+ palError = ERROR_OUTOFMEMORY;
+ goto IntializeExit;
+ }
+ }
+
+ if (0 != poa->sObjectName.GetStringLength())
+ {
+ palError = m_oa.sObjectName.CopyString(&poa->sObjectName);
+ }
+
+IntializeExit:
+
+ LOGEXIT("CPalObjectBase::Initialize returns %d\n", palError);
+
+ return palError;
+}
+
+/*++
+Function:
+ CPalObjectBase::GetObjectType
+
+ Returns the type of the object
+--*/
+
+CObjectType *
+CPalObjectBase::GetObjectType(
+ VOID
+ )
+{
+ ENTRY("CPalObjectBase::GetObjectType(this = %p)\n", this);
+ LOGEXIT("CPalObjectBase::GetObjectType returns %p\n", m_pot);
+
+ return m_pot;
+}
+
+/*++
+Function:
+ CPalObjectBase::GetObjectAttributes
+
+ Returns the attributes of the object
+--*/
+
+CObjectAttributes *
+CPalObjectBase::GetObjectAttributes(
+ VOID
+ )
+{
+ ENTRY("CPalObjectBase::GetObjectAttributes(this = %p)\n", this);
+ LOGEXIT("CPalObjectBase::GetObjectAttributes returns %p\n", &m_oa);
+
+ return &m_oa;
+}
+
+/*++
+Function:
+ CPalObjectBase::GetImmutableData
+
+ Provides the caller access to the object's immutable data (if any)
+
+Parameters:
+ ppvImmutableData -- on success, receives a pointer to the object's
+ immutable data
+--*/
+
+PAL_ERROR
+CPalObjectBase::GetImmutableData(
+ void **ppvImmutableData // OUT
+ )
+{
+ _ASSERTE(NULL != ppvImmutableData);
+
+ ENTRY("CPalObjectBase::GetImmutableData"
+ "(this = %p, ppvImmutableData = %p)\n",
+ this,
+ ppvImmutableData
+ );
+
+ _ASSERTE(0 < m_pot->GetImmutableDataSize());
+
+ *ppvImmutableData = m_pvImmutableData;
+
+ LOGEXIT("CPalObjectBase::GetImmutableData returns %d\n", NO_ERROR);
+
+ return NO_ERROR;
+}
+
+/*++
+Function:
+ CPalObjectBase::GetProcessLocalData
+
+ Provides the caller access to the object's local data (if any)
+
+Parameters:
+ pthr -- thread data for calling thread
+ eLockRequest -- specifies if the caller desires a read lock or a
+ write lock on the data (currently ignored)
+ ppDataLock -- on success, receives a pointer to the data lock instance
+ for the local data
+ ppvProcssLocalData -- on success, receives a pointer to the local data
+--*/
+
+PAL_ERROR
+CPalObjectBase::GetProcessLocalData(
+ CPalThread *pthr,
+ LockType eLockRequest,
+ IDataLock **ppDataLock, // OUT
+ void **ppvProcessLocalData // OUT
+ )
+{
+ _ASSERTE(NULL != pthr);
+ _ASSERTE(ReadLock == eLockRequest || WriteLock == eLockRequest);
+ _ASSERTE(NULL != ppDataLock);
+ _ASSERTE(NULL != ppvProcessLocalData);
+
+ ENTRY("CPalObjectBase::GetProcessLocalData"
+ "(this = %p, pthr = %p, eLockRequest = %d, ppDataLock = %p,"
+ " ppvProcessLocalData = %p)\n",
+ this,
+ pthr,
+ eLockRequest,
+ ppDataLock,
+ ppvProcessLocalData
+ );
+
+ _ASSERTE(0 < m_pot->GetProcessLocalDataSize());
+
+ m_sdlLocalData.AcquireLock(pthr, ppDataLock);
+ *ppvProcessLocalData = m_pvLocalData;
+
+ LOGEXIT("CPalObjectBase::GetProcessLocalData returns %d\n", NO_ERROR);
+
+ return NO_ERROR;
+}
+
+/*++
+Function:
+ CPalObjectBase::AddReference
+
+ Increments the object's reference count. The updated count is returned
+ for diagnostic purposes only
+--*/
+
+DWORD
+CPalObjectBase::AddReference(
+ void
+ )
+{
+ LONG lRefCount;
+
+ ENTRY("CPalObjectBase::AddReference(this = %p)\n", this);
+
+ _ASSERTE(m_lRefCount > 0);
+ lRefCount = InterlockedIncrement(&m_lRefCount);
+
+ LOGEXIT("CPalObjectBase::AddReference returns %d\n", lRefCount);
+
+ return lRefCount;
+}
+
+/*++
+Function:
+ CPalObjectBase::ReleaseReference
+
+ Decrements the object's reference count. The updated count is returned
+ for diagnostic purposes only
+
+Parameters:
+ pthr -- thread data for calling thread
+--*/
+
+DWORD
+CPalObjectBase::ReleaseReference(
+ CPalThread *pthr
+ )
+{
+ LONG lRefCount;
+
+ _ASSERTE(NULL != pthr);
+
+ ENTRY("CPalObjectBase::ReleaseReference"
+ "(this = %p, pthr = %p)\n",
+ this,
+ pthr
+ );
+
+ AcquireObjectDestructionLock(pthr);
+
+ _ASSERTE(m_lRefCount > 0);
+
+ //
+ // Even though object destruction takes place under a lock
+ // we still need to use an interlocked decrement, as AddRef
+ // operates lock free
+ //
+
+ lRefCount = InterlockedDecrement(&m_lRefCount);
+
+ if (0 == lRefCount)
+ {
+ bool fCleanupSharedState = ReleaseObjectDestructionLock(pthr, TRUE);
+
+ //
+ // We need to do two things with the calling thread data here:
+ // 1) store it in m_pthrCleanup so it is available to the destructors
+ // 2) Add a reference to it before starting any cleanup, and release
+ // that reference afterwords.
+ //
+ // Step 2 is necessary when we're cleaning up the thread object that
+ // represents the calling thread -- it ensures that the thread data
+ // is available throughout the entire cleanup process.
+ //
+
+ m_pthrCleanup = pthr;
+ pthr->AddThreadReference();
+
+ if (NULL != m_pot->GetObjectCleanupRoutine())
+ {
+ (*m_pot->GetObjectCleanupRoutine())(
+ pthr,
+ static_cast<IPalObject*>(this),
+ FALSE,
+ fCleanupSharedState
+ );
+ }
+
+ InternalDelete(this);
+
+ pthr->ReleaseThreadReference();
+ }
+ else
+ {
+ ReleaseObjectDestructionLock(pthr, FALSE);
+ }
+
+ LOGEXIT("CPalObjectBase::ReleaseReference returns %d\n", lRefCount);
+
+ return lRefCount;
+}
+
+/*++
+Function:
+ CPalObjectBase::~CPalObjectBase
+
+ Object destructor
+--*/
+
+CPalObjectBase::~CPalObjectBase()
+{
+ ENTRY("CPalObjectBase::~CPalObjectBase(this = %p)\n", this);
+
+ if (NULL != m_pvImmutableData)
+ {
+ free(m_pvImmutableData);
+ }
+
+ if (NULL != m_pvLocalData)
+ {
+ free(m_pvLocalData);
+ }
+
+ if (NULL != m_oa.sObjectName.GetString())
+ {
+ m_oa.sObjectName.FreeBuffer();
+ }
+
+ LOGEXIT("CPalObjectBase::~CPalObjectBase\n");
+}
+
diff --git a/src/pal/src/objmgr/palobjbase.hpp b/src/pal/src/objmgr/palobjbase.hpp
new file mode 100644
index 0000000000..4a7f4ac3ed
--- /dev/null
+++ b/src/pal/src/objmgr/palobjbase.hpp
@@ -0,0 +1,191 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ palobjbase.hpp
+
+Abstract:
+ PAL object base class
+
+
+
+--*/
+
+#ifndef _PALOBJBASE_HPP_
+#define _PALOBJBASE_HPP_
+
+#include "pal/corunix.hpp"
+#include "pal/cs.hpp"
+#include "pal/thread.hpp"
+
+namespace CorUnix
+{
+ class CSimpleDataLock : IDataLock
+ {
+ private:
+
+ CRITICAL_SECTION m_cs;
+ bool m_fInitialized;
+
+ public:
+
+ CSimpleDataLock()
+ :
+ m_fInitialized(FALSE)
+ {
+ };
+
+ virtual ~CSimpleDataLock()
+ {
+ if (m_fInitialized)
+ {
+ InternalDeleteCriticalSection(&m_cs);
+ }
+ };
+
+ PAL_ERROR
+ Initialize(
+ void
+ )
+ {
+ PAL_ERROR palError = NO_ERROR;
+
+ InternalInitializeCriticalSection(&m_cs);
+ m_fInitialized = TRUE;
+
+ return palError;
+ };
+
+ void
+ AcquireLock(
+ CPalThread *pthr,
+ IDataLock **pDataLock
+ )
+ {
+ InternalEnterCriticalSection(pthr, &m_cs);
+ *pDataLock = static_cast<IDataLock*>(this);
+ };
+
+ virtual
+ void
+ ReleaseLock(
+ CPalThread *pthr,
+ bool fDataChanged
+ )
+ {
+ InternalLeaveCriticalSection(pthr, &m_cs);
+ };
+
+ };
+
+ class CPalObjectBase : public IPalObject
+ {
+ template <class T> friend void InternalDelete(T *p);
+
+ protected:
+
+ LONG m_lRefCount;
+
+ VOID *m_pvImmutableData;
+ VOID *m_pvLocalData;
+
+ CObjectType *m_pot;
+ CObjectAttributes m_oa;
+
+ CSimpleDataLock m_sdlLocalData;
+
+ //
+ // The thread that initiated object cleanup
+ //
+
+ CPalThread *m_pthrCleanup;
+
+ virtual ~CPalObjectBase();
+
+ virtual
+ void
+ AcquireObjectDestructionLock(
+ CPalThread *pthr
+ ) = 0;
+
+ virtual
+ bool
+ ReleaseObjectDestructionLock(
+ CPalThread *pthr,
+ bool fDestructionPending
+ ) = 0;
+
+ public:
+
+ CPalObjectBase(
+ CObjectType *pot
+ )
+ :
+ m_lRefCount(1),
+ m_pvImmutableData(NULL),
+ m_pvLocalData(NULL),
+ m_pot(pot),
+ m_pthrCleanup(NULL)
+ {
+ };
+
+ virtual
+ PAL_ERROR
+ Initialize(
+ CPalThread *pthr,
+ CObjectAttributes *poa
+ );
+
+ //
+ // IPalObject routines
+ //
+
+ virtual
+ CObjectType *
+ GetObjectType(
+ VOID
+ );
+
+ virtual
+ CObjectAttributes *
+ GetObjectAttributes(
+ VOID
+ );
+
+ virtual
+ PAL_ERROR
+ GetImmutableData(
+ void **ppvImmutableData // OUT
+ );
+
+ virtual
+ PAL_ERROR
+ GetProcessLocalData(
+ CPalThread *pthr, // IN, OPTIONAL
+ LockType eLockRequest,
+ IDataLock **ppDataLock, // OUT
+ void **ppvProcessLocalData // OUT
+ );
+
+ virtual
+ DWORD
+ AddReference(
+ void
+ );
+
+ virtual
+ DWORD
+ ReleaseReference(
+ CPalThread *pthr
+ );
+ };
+}
+
+#endif // _PALOBJBASE_HPP_
+
diff --git a/src/pal/src/objmgr/shmobject.cpp b/src/pal/src/objmgr/shmobject.cpp
new file mode 100644
index 0000000000..1435d5d734
--- /dev/null
+++ b/src/pal/src/objmgr/shmobject.cpp
@@ -0,0 +1,1471 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ shmobject.hpp
+
+Abstract:
+ Shared memory based object
+
+
+
+--*/
+
+#include "shmobject.hpp"
+#include "pal/malloc.hpp"
+#include "pal/cs.hpp"
+#include "pal/dbgmsg.h"
+
+#include <stddef.h>
+
+SET_DEFAULT_DEBUG_CHANNEL(PAL);
+
+using namespace CorUnix;
+
+/*++
+Function:
+ CSharedMemoryObject::Initialize
+
+ Performs possibly-failing initialization for a newly-constructed
+ object
+
+Parameters:
+ pthr -- thread data for calling thread
+ poa -- the object attributes (e.g., name) for the object
+--*/
+
+PAL_ERROR
+CSharedMemoryObject::Initialize(
+ CPalThread *pthr,
+ CObjectAttributes *poa
+ )
+{
+ PAL_ERROR palError = NO_ERROR;
+ SHMObjData *psmod = NULL;
+
+ _ASSERTE(NULL != pthr);
+ _ASSERTE(NULL != poa);
+
+ ENTRY("CSharedMemoryObject::Initialize"
+ "(this = %p, pthr = %p, poa = %p)\n",
+ this,
+ pthr,
+ poa
+ );
+
+ palError = CPalObjectBase::Initialize(pthr, poa);
+ if (NO_ERROR != palError)
+ {
+ goto InitializeExit;
+ }
+
+ //
+ // If this is a named object it needs to go into the shared domain;
+ // otherwise it remains local
+ //
+
+ if (0 != m_oa.sObjectName.GetStringLength())
+ {
+ m_ObjectDomain = SharedObject;
+
+ palError = AllocateSharedDataItems(&m_shmod, &psmod);
+ if (NO_ERROR != palError || NULL == psmod)
+ {
+ goto InitializeExit;
+ }
+ }
+
+ if (0 != m_pot->GetSharedDataSize())
+ {
+ if (SharedObject == m_ObjectDomain)
+ {
+ //
+ // Map the shared data into our address space
+ //
+ if (NULL == psmod)
+ {
+ ASSERT("psmod should not be NULL");
+ palError = ERROR_INTERNAL_ERROR;
+ goto InitializeExit;
+ }
+
+ m_pvSharedData = SHMPTR_TO_TYPED_PTR(VOID, psmod->shmObjSharedData);
+ if (NULL == m_pvSharedData)
+ {
+ ASSERT("Unable to map shared data area\n");
+ palError = ERROR_INTERNAL_ERROR;
+ goto InitializeExit;
+ }
+ }
+ else
+ {
+ //
+ // Initialize the local shared data lock.
+ //
+
+ palError = m_sdlSharedData.Initialize();
+ if (NO_ERROR != palError)
+ {
+ ERROR("Failure initializing m_sdlSharedData\n");
+ goto InitializeExit;
+ }
+
+ //
+ // Allocate local memory to hold the shared data
+ //
+
+ m_pvSharedData = InternalMalloc(m_pot->GetSharedDataSize());
+ if (NULL == m_pvSharedData)
+ {
+ ERROR("Failure allocating m_pvSharedData (local copy)\n");
+ palError = ERROR_OUTOFMEMORY;
+ goto InitializeExit;
+ }
+ }
+
+ ZeroMemory(m_pvSharedData, m_pot->GetSharedDataSize());
+ }
+
+
+InitializeExit:
+
+ LOGEXIT("CSharedMemoryObject::Initalize returns %d\n", palError);
+
+ return palError;
+}
+
+/*++
+Function:
+ CSharedMemoryObject::InitializeFromExistingSharedData
+
+ Performs possibly-failing initialization for a newly-constructed
+ object that is to represent an existing object (i.e., importing
+ a shared object into this process)
+
+ The shared memory lock must be held when calling this method
+
+Parameters:
+ pthr -- thread data for calling thread
+ poa -- the object attributes for the object
+--*/
+
+PAL_ERROR
+CSharedMemoryObject::InitializeFromExistingSharedData(
+ CPalThread *pthr,
+ CObjectAttributes *poa
+ )
+{
+ PAL_ERROR palError = NO_ERROR;
+ SHMObjData *psmod = NULL;
+
+ _ASSERTE(NULL != pthr);
+ _ASSERTE(NULL != poa);
+
+ ENTRY("CSharedMemoryObject::InitializeFromExistingSharedData"
+ "(this = %p, pthr = %p, poa = %p)\n",
+ this,
+ pthr,
+ poa
+ );
+
+ //
+ // This object is obviously shared...
+ //
+
+ m_ObjectDomain = SharedObject;
+
+ _ASSERTE(SHMNULL != m_shmod);
+
+ psmod = SHMPTR_TO_TYPED_PTR(SHMObjData, m_shmod);
+ if (NULL == psmod)
+ {
+ ASSERT("Unable to map shared object data\n");
+ palError = ERROR_INTERNAL_ERROR;
+ goto InitializeFromExistingSharedDataExit;
+ }
+
+ //
+ // When we're being called on the duplicate handle path the passed
+ // in object attributes likely won't have an object name in it.
+ // If there is an object name in the shared data place that in the
+ // object attributs so that the constructed object has a local copy
+ // of the name
+ //
+
+ if (0 == poa->sObjectName.GetStringLength()
+ && 0 != psmod->dwNameLength)
+ {
+ WCHAR *wsz;
+
+ wsz = SHMPTR_TO_TYPED_PTR(WCHAR, psmod->shmObjName);
+ if (NULL != wsz)
+ {
+ poa->sObjectName.SetStringWithLength(wsz, psmod->dwNameLength);
+ }
+ else
+ {
+ ASSERT("Unable to map object name\n");
+ palError = ERROR_INTERNAL_ERROR;
+ goto InitializeFromExistingSharedDataExit;
+ }
+ }
+#if _DEBUG
+ else if (0 != psmod->dwNameLength)
+ {
+ WCHAR *wsz;
+
+ //
+ // Verify that the names are consistent
+ //
+
+ wsz = SHMPTR_TO_TYPED_PTR(WCHAR, psmod->shmObjName);
+ _ASSERTE(NULL != wsz);
+ _ASSERTE(0 == PAL_wcscmp(wsz, poa->sObjectName.GetString()));
+ }
+#endif // debug
+
+ palError = CPalObjectBase::Initialize(pthr, poa);
+ if (NO_ERROR != palError)
+ {
+ goto InitializeFromExistingSharedDataExit;
+ }
+
+ if (SHMNULL != psmod->shmObjImmutableData)
+ {
+ VOID *pv = SHMPTR_TO_TYPED_PTR(VOID, psmod->shmObjImmutableData);
+ if (NULL != pv)
+ {
+ memcpy(m_pvImmutableData, pv, m_pot->GetImmutableDataSize());
+ }
+ else
+ {
+ ASSERT("Unable to map object immutable data\n");
+ palError = ERROR_INTERNAL_ERROR;
+ goto InitializeFromExistingSharedDataExit;
+ }
+ }
+
+ if (SHMNULL != psmod->shmObjSharedData)
+ {
+ m_pvSharedData = SHMPTR_TO_TYPED_PTR(VOID, psmod->shmObjSharedData);
+ if (NULL == m_pvSharedData)
+ {
+ ASSERT("Unable to map object shared data\n");
+ palError = ERROR_INTERNAL_ERROR;
+ goto InitializeFromExistingSharedDataExit;
+ }
+ }
+
+ if (NULL != m_pot->GetObjectInitRoutine())
+ {
+ palError = (*m_pot->GetObjectInitRoutine())(
+ pthr,
+ m_pot,
+ m_pvImmutableData,
+ m_pvSharedData,
+ m_pvLocalData
+ );
+ }
+
+InitializeFromExistingSharedDataExit:
+
+ LOGEXIT("CSharedMemoryObject::InitalizeFromExistingSharedData returns %d\n", palError);
+
+ return palError;
+}
+
+/*++
+Function:
+ CSharedMemoryObject::AllocatedSharedDataItems
+
+ Allocates and initialiazes the shared memory structures necessary to make an
+ object available to other processes
+
+Parameters:
+ pshmObjData -- on success, receives the shared memory pointer for the
+ shared memory object data
+ ppsmod -- on success, receives the locally-mapped pointer for the shared
+ memory object data
+--*/
+
+PAL_ERROR
+CSharedMemoryObject::AllocateSharedDataItems(
+ SHMPTR *pshmObjData,
+ SHMObjData **ppsmod
+ )
+{
+ PAL_ERROR palError = NO_ERROR;
+ SHMPTR shmod = SHMNULL;
+ SHMObjData *psmod = NULL;
+
+ _ASSERTE(NULL != pshmObjData);
+ _ASSERTE(NULL != ppsmod);
+
+ ENTRY("CSharedMemoryObject::AllocateSharedDataItems"
+ "(this = %p, pshmObjData = %p, ppsmod = %p)\n",
+ this,
+ pshmObjData,
+ ppsmod
+ );
+
+ //
+ // We're about to make a number of shared memory allocations,
+ // so grab the lock for the entirety of the routine.
+ //
+
+ SHMLock();
+
+ shmod = SHMalloc(sizeof(SHMObjData));
+ if (SHMNULL == shmod)
+ {
+ ERROR("Unable to allocate m_shmod for new object\n");
+ palError = ERROR_OUTOFMEMORY;
+ goto AllocateSharedDataItemsExit;
+ }
+
+ psmod = SHMPTR_TO_TYPED_PTR(SHMObjData, shmod);
+ _ASSERTE(NULL != psmod);
+
+ ZeroMemory(psmod, sizeof(*psmod));
+
+ psmod->eTypeId = m_pot->GetId();
+ psmod->lProcessRefCount = 1;
+
+ if (0 != m_oa.sObjectName.GetStringLength())
+ {
+ psmod->dwNameLength = m_oa.sObjectName.GetStringLength();
+ psmod->shmObjName = SHMWStrDup(m_oa.sObjectName.GetString());
+ if (SHMNULL == psmod->shmObjName)
+ {
+ ERROR("Unable to allocate psmod->shmObjName for new object\n");
+ palError = ERROR_OUTOFMEMORY;
+ goto AllocateSharedDataItemsExit;
+ }
+ }
+
+ if (0 != m_pot->GetImmutableDataSize())
+ {
+ //
+ // The shared copy of the object's immutable data will be initialized
+ // by CSharedMemoryObjectManager::RegisterObject or PromoteSharedData
+ //
+
+ psmod->shmObjImmutableData = SHMalloc(m_pot->GetImmutableDataSize());
+ if (SHMNULL == psmod->shmObjImmutableData)
+ {
+ ERROR("Unable to allocate psmod->shmObjImmutableData for new object\n");
+ palError = ERROR_OUTOFMEMORY;
+ goto AllocateSharedDataItemsExit;
+ }
+ }
+
+ if (0 != m_pot->GetSharedDataSize())
+ {
+ psmod->shmObjSharedData = SHMalloc(m_pot->GetSharedDataSize());
+ if (SHMNULL == psmod->shmObjSharedData)
+ {
+ ERROR("Unable to allocate psmod->shmObjSharedData for new object\n");
+ palError = ERROR_OUTOFMEMORY;
+ goto AllocateSharedDataItemsExit;
+ }
+ }
+
+ *pshmObjData = shmod;
+ *ppsmod = psmod;
+
+AllocateSharedDataItemsExit:
+
+ if (NO_ERROR != palError && SHMNULL != shmod)
+ {
+ FreeSharedDataAreas(shmod);
+ }
+
+ SHMRelease();
+
+ LOGEXIT("CSharedMemoryObject::AllocateSharedDataItems returns %d\n", palError);
+
+ return palError;
+}
+
+/*++
+Function:
+ CSharedMemoryObject::FreeSharedDataItems
+
+ Frees the shared memory structures referenced by the provided shared
+ memory pointer
+
+Parameters:
+ shmObjData -- shared memory pointer to the structures to free
+--*/
+
+// static
+void
+CSharedMemoryObject::FreeSharedDataAreas(
+ SHMPTR shmObjData
+ )
+{
+ SHMObjData *psmod;
+
+ _ASSERTE(SHMNULL != shmObjData);
+
+ ENTRY("CSharedMemoryObject::FreeSharedDataAreas"
+ "(shmObjData = %p)\n",
+ shmObjData
+ );
+
+ SHMLock();
+
+ psmod = SHMPTR_TO_TYPED_PTR(SHMObjData, shmObjData);
+ _ASSERTE(NULL != psmod);
+
+ if (SHMNULL != psmod->shmObjImmutableData)
+ {
+ SHMfree(psmod->shmObjImmutableData);
+ }
+
+ if (SHMNULL != psmod->shmObjSharedData)
+ {
+ SHMfree(psmod->shmObjSharedData);
+ }
+
+ if (SHMNULL != psmod->shmObjName)
+ {
+ SHMfree(psmod->shmObjName);
+ }
+
+ SHMfree(shmObjData);
+
+ SHMRelease();
+
+ LOGEXIT("CSharedMemoryObject::FreeSharedDataAreas\n");
+}
+
+/*++
+Function:
+ CSharedMemoryObject::PromoteShjaredData
+
+ Copies the object's state into the passed-in shared data structures
+
+Parameters:
+ shmObjData -- shared memory pointer for the shared memory object data
+ psmod -- locally-mapped pointer for the shared memory object data
+--*/
+
+void
+CSharedMemoryObject::PromoteSharedData(
+ SHMPTR shmObjData,
+ SHMObjData *psmod
+ )
+{
+ _ASSERTE(SHMNULL != shmObjData);
+ _ASSERTE(NULL != psmod);
+
+ ENTRY("CSharedMemoryObject::PromoteSharedData"
+ "(this = %p, shmObjData = %p, psmod = %p)\n",
+ this,
+ shmObjData,
+ psmod);
+
+ //
+ // psmod has been zero-inited, so we don't need to worry about
+ // shmPrevObj, shmNextObj, fAddedToList, shmObjName, dwNameLength,
+ // or pvSynchData
+ //
+
+ psmod->lProcessRefCount = 1;
+ psmod->eTypeId = m_pot->GetId();
+
+ if (0 != m_pot->GetImmutableDataSize())
+ {
+ void *pvImmutableData;
+
+ pvImmutableData = SHMPTR_TO_TYPED_PTR(void, psmod->shmObjImmutableData);
+ _ASSERTE(NULL != pvImmutableData);
+
+ CopyMemory(
+ pvImmutableData,
+ m_pvImmutableData,
+ m_pot->GetImmutableDataSize()
+ );
+ }
+
+ if (0 != m_pot->GetSharedDataSize())
+ {
+ void *pvSharedData;
+
+ pvSharedData = SHMPTR_TO_TYPED_PTR(void, psmod->shmObjSharedData);
+ _ASSERTE(NULL != pvSharedData);
+
+ CopyMemory(
+ pvSharedData,
+ m_pvSharedData,
+ m_pot->GetSharedDataSize()
+ );
+
+ free(m_pvSharedData);
+ m_pvSharedData = pvSharedData;
+ }
+
+ m_shmod = shmObjData;
+
+ LOGEXIT("CSharedMemoryObject::PromoteSharedData\n");
+}
+
+/*++
+Function:
+ CSharedMemoryObject::EnsureObjectIsShared
+
+ If this object is not yet in the shared domain allocate the necessary
+ shared memory structures for it and copy the object's data into those
+ structures
+
+Parameters:
+ pthr -- thread data for the calling thread
+--*/
+
+PAL_ERROR
+CSharedMemoryObject::EnsureObjectIsShared(
+ CPalThread *pthr
+ )
+{
+ PAL_ERROR palError = NO_ERROR;
+ IDataLock *pDataLock = NULL;
+ SHMPTR shmObjData;
+ SHMObjData *psmod;
+
+ _ASSERTE(NULL != pthr);
+
+ ENTRY("CSharedMemoryObject::EnsureObjectIsShared"
+ "(this = %p, pthr = %p)\n",
+ this,
+ pthr
+ );
+
+ //
+ // Grab the shared memory lock and check if the object is already
+ // shared
+ //
+
+ SHMLock();
+
+ if (SharedObject == m_ObjectDomain)
+ {
+ goto EnsureObjectIsSharedExit;
+ }
+
+ //
+ // Grab the local shared data lock, if necessary
+ //
+
+ if (0 != m_pot->GetSharedDataSize())
+ {
+ m_sdlSharedData.AcquireLock(pthr, &pDataLock);
+ }
+
+ //
+ // Allocate the necessary shared data areas
+ //
+
+ palError = AllocateSharedDataItems(&shmObjData, &psmod);
+ if (NO_ERROR != palError)
+ {
+ goto EnsureObjectIsSharedExit;
+ }
+
+ //
+ // Promote the object's data and set the domain to shared
+ //
+
+ PromoteSharedData(shmObjData, psmod);
+ m_ObjectDomain = SharedObject;
+
+EnsureObjectIsSharedExit:
+
+ if (NULL != pDataLock)
+ {
+ pDataLock->ReleaseLock(pthr, TRUE);
+ }
+
+ SHMRelease();
+
+ LOGEXIT("CSharedMemoryObject::EnsureObjectIsShared returns %d\n", palError);
+
+ return palError;
+}
+
+/*++
+Function:
+ CSharedMemoryObject::CleanupForProcessShutdown
+
+ Cleanup routine called by the object manager when shutting down
+
+Parameters:
+ pthr -- thread data for the calling thread
+--*/
+
+void
+CSharedMemoryObject::CleanupForProcessShutdown(
+ CPalThread *pthr
+ )
+{
+ bool fCleanupSharedState;
+
+ _ASSERTE(NULL != pthr);
+
+ ENTRY("CSharedMemoryObject::CleanupForProcessShutdown"
+ "(this = %p, pthr = %p)\n",
+ this,
+ pthr
+ );
+
+ fCleanupSharedState = DereferenceSharedData();
+
+ if (NULL != m_pot->GetObjectCleanupRoutine())
+ {
+ (*m_pot->GetObjectCleanupRoutine())(
+ pthr,
+ static_cast<IPalObject*>(this),
+ TRUE,
+ fCleanupSharedState
+ );
+ }
+
+ //
+ // We need to do two things with the calling thread data here:
+ // 1) store it in m_pthrCleanup so it is available to the destructors
+ // 2) Add a reference to it before starting any cleanup, and release
+ // that reference afterwords.
+ //
+ // Step 2 is necessary when we're cleaning up the thread object that
+ // represents the calling thread -- it ensures that the thread data
+ // is available throughout the entire cleanup process.
+ //
+
+ m_pthrCleanup = pthr;
+ pthr->AddThreadReference();
+
+ InternalDelete(this);
+
+ pthr->ReleaseThreadReference();
+
+ LOGEXIT("CSharedMemoryObject::CleanupForProcessShutdown\n");
+}
+
+/*++
+Function:
+ CSharedMemoryObject::AcquiteObjectDestructionLock
+
+ Acquires the lock that must be held when decrementing the object's
+ reference count (and, if the count drops to 0, while removing the
+ object from the object manager's lists).
+
+Parameters:
+ pthr -- thread data for the calling thread
+--*/
+
+void
+CSharedMemoryObject::AcquireObjectDestructionLock(
+ CPalThread *pthr
+ )
+{
+ _ASSERTE(NULL != pthr);
+
+ ENTRY("CSharedMemoryObject::AcquireObjectDestructionLock"
+ "(this = %p, pthr = $p)\n",
+ this,
+ pthr
+ );
+
+ InternalEnterCriticalSection(pthr, m_pcsObjListLock);
+
+ LOGEXIT("CSharedMemoryObject::AcquireObjectDestructionLock\n");
+}
+
+/*++
+Function:
+ CSharedMemoryObject::ReleaseObjectDestructionLock
+
+ Releases the lock acquired by AcquireObjectDestructionLock
+
+Parameters:
+ pthr -- thread data for the calling thread
+ fDestructionPending -- if TRUE, the reference count for this
+ object has dropped to 0; the object will be destroyed after
+ this routine returns
+--*/
+
+bool
+CSharedMemoryObject::ReleaseObjectDestructionLock(
+ CPalThread *pthr,
+ bool fDestructionPending
+ )
+{
+ bool fCleanupSharedState = FALSE;
+
+ _ASSERTE(NULL != pthr);
+
+ ENTRY("CSharedMemoryObject::ReleaseObjectDestructionLock"
+ "(this = %p, pthr = %p, fDestructionPending = %d\n",
+ this,
+ pthr,
+ fDestructionPending
+ );
+
+ if (fDestructionPending)
+ {
+ RemoveEntryList(&m_le);
+ fCleanupSharedState = DereferenceSharedData();
+ }
+
+ InternalLeaveCriticalSection(pthr, m_pcsObjListLock);
+
+ LOGEXIT("CSharedMemoryObject::ReleaseObjectDestructionLock returns %d\n",
+ fCleanupSharedState
+ );
+
+ return fCleanupSharedState;
+}
+
+/*++
+Function:
+ CSharedMemoryObject::DereferenceSharedData
+
+ Called to decrement the global refcount (i.e., the count of
+ the number of processes that have reference to the object) when
+ the local reference to the object is being destroyed.
+
+Return value:
+ Returns TRUE if this process needs to clean up the object's shared
+ data (i.e., the global refcount has dropped to 0, or the object
+ is in the local domain)
+--*/
+
+bool
+CSharedMemoryObject::DereferenceSharedData()
+{
+ LONG fSharedDataAlreadDereferenced;
+
+ ENTRY("CSharedMemoryObject::DereferenceSharedData(this = %p)\n", this);
+
+ fSharedDataAlreadDereferenced = InterlockedExchange(
+ &m_fSharedDataDereferenced,
+ TRUE
+ );
+
+ if (!fSharedDataAlreadDereferenced)
+ {
+ if (SHMNULL != m_shmod)
+ {
+ SHMObjData *psmod;
+
+ SHMLock();
+
+ psmod = SHMPTR_TO_TYPED_PTR(SHMObjData, m_shmod);
+ _ASSERTE(NULL != psmod);
+
+ psmod->lProcessRefCount -= 1;
+ if (0 == psmod->lProcessRefCount)
+ {
+ //
+ // No other process is using this object, so remove
+ // it from the shared memory named object list (if it
+ // had been added to it). The final cleanup will happen
+ // in the object's destructor
+ //
+
+ m_fDeleteSharedData = TRUE;
+
+ if (psmod->fAddedToList)
+ {
+ //
+ // This object better have a name...
+ //
+
+ _ASSERTE(0 != psmod->dwNameLength);
+
+ if (SHMNULL != psmod->shmPrevObj)
+ {
+ SHMObjData *psmodPrevious = SHMPTR_TO_TYPED_PTR(SHMObjData, psmod->shmPrevObj);
+ _ASSERTE(NULL != psmodPrevious);
+
+ psmodPrevious->shmNextObj = psmod->shmNextObj;
+ }
+ else
+ {
+ //
+ // This object is the head of the shared memory named object
+ // list -- reset that pointer now
+ //
+
+ if (!SHMSetInfo(SIID_NAMED_OBJECTS, psmod->shmNextObj))
+ {
+ ASSERT("Failed to set shared named object list head");
+ }
+ }
+
+ if (SHMNULL != psmod->shmNextObj)
+ {
+ SHMObjData *psmodNext = SHMPTR_TO_TYPED_PTR(SHMObjData, psmod->shmNextObj);
+ _ASSERTE(NULL != psmodNext);
+
+ psmodNext->shmPrevObj = psmod->shmPrevObj;
+ }
+ }
+#if _DEBUG
+ else
+ {
+ _ASSERTE(SHMNULL == psmod->shmPrevObj);
+ _ASSERTE(SHMNULL == psmod->shmNextObj);
+ }
+#endif
+ }
+
+ SHMRelease();
+ }
+ else if (ProcessLocalObject == m_ObjectDomain)
+ {
+ //
+ // If the object is local the shared data needs to be
+ // deleted by definition
+ //
+
+ m_fDeleteSharedData = TRUE;
+ }
+ }
+ else
+ {
+ ASSERT("Multiple calls to DereferenceSharedData\n");
+ }
+
+ LOGEXIT("CSharedMemoryObject::DereferenceSharedData returns %d\n",
+ m_fDeleteSharedData
+ );
+
+ return m_fDeleteSharedData;
+}
+
+/*++
+Function:
+ CSharedMemoryObject::~CSharedMemoryObject
+
+ Destructor; should only be called from ReleaseReference
+--*/
+
+CSharedMemoryObject::~CSharedMemoryObject()
+{
+ ENTRY("CSharedMemoryObject::~CSharedMemoryObject(this = %p)\n", this);
+
+ if (!m_fSharedDataDereferenced)
+ {
+ ASSERT("DereferenceSharedData not called before object destructor -- delete called directly?\n");
+ DereferenceSharedData();
+ }
+
+ if (NULL != m_pvSharedData && ProcessLocalObject == m_ObjectDomain)
+ {
+ free(m_pvSharedData);
+ }
+ else if (SHMNULL != m_shmod && m_fDeleteSharedData)
+ {
+ FreeSharedDataAreas(m_shmod);
+ }
+
+ LOGEXIT("CSharedMemoryObject::~CSharedMemoryObject\n");
+}
+
+//
+// C++ standard, 18.1.5 - offsetof requires a POD (plain old data) struct or
+// union. Since offsetof is a macro, gcc doesn't actually check for improper
+// use of offsetof, it keys off of the -> from NULL (which is also invalid for
+// non-POD types by 18.1.5)
+//
+// As we have numerous examples of this behavior in our codebase,
+// making an offsetof which doesn't use 0.
+//
+// PAL_safe_offsetof is a version of offsetof that protects against an
+// overridden operator&
+//
+
+#define PAL_safe_offsetof(s,m) ((size_t)((ptrdiff_t)&(char&)(((s *)64)->m))-64)
+
+/*++
+Function:
+ CSharedMemoryObject::GetObjectFromListLink
+
+ Given a list link returns the object that contains it. Since m_le is
+ protected the caller cannot perform this computation directly
+
+Parameters:
+ ple -- the list entry to obtain the object for
+--*/
+
+// static
+CSharedMemoryObject*
+CSharedMemoryObject::GetObjectFromListLink(PLIST_ENTRY ple)
+{
+ CSharedMemoryObject *pshmo;
+
+ _ASSERTE(NULL != ple);
+
+ ENTRY("CSharedMemoryObject::GetObjectFromListLink(ple = %p)\n", ple);
+
+ //
+ // Ideally we'd use CONTAINING_RECORD here, but it uses offsetof (see above
+ // comment
+ //
+
+ pshmo = reinterpret_cast<CSharedMemoryObject*>(
+ reinterpret_cast<size_t>(ple) - PAL_safe_offsetof(CSharedMemoryObject, m_le)
+ );
+
+ _ASSERTE(ple == &pshmo->m_le);
+
+ LOGEXIT("CSharedMemoryObject::GetObjectFromListLink returns %p\n", pshmo);
+
+ return pshmo;
+}
+
+/*++
+Function:
+ CSharedMemoryObject::GetSharedData
+
+ Provides the caller access to the object's shared data (if any)
+
+Parameters:
+ pthr -- thread data for calling thread
+ eLockRequest -- specifies if the caller desires a read lock or a
+ write lock on the data (currently ignored)
+ ppDataLock -- on success, receives a pointer to the data lock instance
+ for the shared data
+ ppvProcssSharedData -- on success, receives a pointer to the shared data
+--*/
+
+PAL_ERROR
+CSharedMemoryObject::GetSharedData(
+ CPalThread *pthr,
+ LockType eLockRequest,
+ IDataLock **ppDataLock, // OUT
+ void **ppvSharedData // OUT
+ )
+{
+ IDataLock *pDataLock;
+
+ _ASSERTE(NULL != pthr);
+ _ASSERTE(ReadLock == eLockRequest || WriteLock == eLockRequest);
+ _ASSERTE(NULL != ppDataLock);
+ _ASSERTE(NULL != ppvSharedData);
+
+ ENTRY("CSharedMemoryObject::GetSharedData"
+ "(this = %p, pthr = %p, eLockRequest = %d, ppDataLock = %p,"
+ " ppvSharedData = %p)\n",
+ this,
+ pthr,
+ eLockRequest,
+ ppDataLock,
+ ppvSharedData
+ );
+
+ _ASSERTE(0 < m_pot->GetSharedDataSize());
+
+ if (ProcessLocalObject == m_ObjectDomain)
+ {
+ //
+ // We need to grab the local shared data lock and re-check
+ // the object's domain, as there's a chance the object might
+ // have been promoted after we made the above check but before
+ // we grabbed the lock
+ //
+
+ m_sdlSharedData.AcquireLock(pthr, &pDataLock);
+
+ if (SharedObject == m_ObjectDomain)
+ {
+ pDataLock->ReleaseLock(pthr, FALSE);
+ m_ssmlSharedData.AcquireLock(pthr, &pDataLock);
+ }
+ }
+ else
+ {
+ //
+ // A shared object can never transition back to local,
+ // so there's no need to recheck the domain on this path
+ //
+
+ m_ssmlSharedData.AcquireLock(pthr, &pDataLock);
+ }
+
+ *ppDataLock = pDataLock;
+ *ppvSharedData = m_pvSharedData;
+
+ LOGEXIT("CSharedMemoryObject::GetSharedData returns %d\n", NO_ERROR);
+
+ return NO_ERROR;
+}
+
+/*++
+Function:
+ CSharedMemoryObject::GetSynchStateController
+
+ Obtain a synchronization state controller for this object. Should
+ never be called.
+
+Parameters:
+ pthr -- thread data for calling thread
+ ppStateController -- on success, receives a pointer to the state controller
+ instance
+--*/
+
+PAL_ERROR
+CSharedMemoryObject::GetSynchStateController(
+ CPalThread *pthr,
+ ISynchStateController **ppStateController // OUT
+ )
+{
+ _ASSERTE(NULL != pthr);
+ _ASSERTE(NULL != ppStateController);
+
+ //
+ // This is not a waitable object!
+ //
+
+ ASSERT("Attempt to obtain a synch state controller on a non-waitable object\n");
+ return ERROR_INVALID_HANDLE;
+}
+
+/*++
+Function:
+ CSharedMemoryObject::GetSynchWaitController
+
+ Obtain a synchronization wait controller for this object. Should
+ never be called.
+
+Parameters:
+ pthr -- thread data for calling thread
+ ppWaitController -- on success, receives a pointer to the wait controller
+ instance
+--*/
+
+PAL_ERROR
+CSharedMemoryObject::GetSynchWaitController(
+ CPalThread *pthr,
+ ISynchWaitController **ppWaitController // OUT
+ )
+{
+ _ASSERTE(NULL != pthr);
+ _ASSERTE(NULL != ppWaitController);
+
+ //
+ // This is not a waitable object!!!
+ //
+
+ ASSERT("Attempt to obtain a synch wait controller on a non-waitable object\n");
+ return ERROR_INVALID_HANDLE;
+}
+
+/*++
+Function:
+ CSharedMemoryObject::GetObjectDomain
+
+ Returns the object's domain (local or shared)
+
+--*/
+
+ObjectDomain
+CSharedMemoryObject::GetObjectDomain(
+ void
+ )
+{
+ TRACE("CSharedMemoryObject::GetObjectDomain(this = %p)\n", this);
+ LOGEXIT("CSharedMemoryObject::GetObjectDomain returns %d\n", m_ObjectDomain);
+
+ return m_ObjectDomain;
+}
+
+/*++
+Function:
+ CSharedMemoryObject::GetObjectSynchData
+
+ Obtain the synchronization data for this object. Should
+ never be called.
+
+Parameters:
+ ppvSynchData -- on success, receives a pointer to the object's synch data
+--*/
+
+PAL_ERROR
+CSharedMemoryObject::GetObjectSynchData(
+ VOID **ppvSynchData // OUT
+ )
+{
+ _ASSERTE(NULL != ppvSynchData);
+
+ //
+ // This is not a waitable object!!!
+ //
+
+ ASSERT("Attempt to obtain a synch data for a non-waitable object\n");
+ return ERROR_INVALID_HANDLE;
+}
+
+/*++
+Function:
+ CSharedMemoryWaitableObject::Initialize
+
+ Performs possibly-failing initialization for a newly-constructed
+ object
+
+Parameters:
+ pthr -- thread data for calling thread
+ poa -- the object attributes (e.g., name) for the object
+--*/
+
+PAL_ERROR
+CSharedMemoryWaitableObject::Initialize(
+ CPalThread *pthr,
+ CObjectAttributes *poa
+ )
+{
+ PAL_ERROR palError = NO_ERROR;
+
+ _ASSERTE(NULL != pthr);
+ _ASSERTE(NULL != poa);
+
+ ENTRY("CSharedMemoryWaitableObject::Initialize"
+ "(this = %p, pthr = %p, poa = %p)\n",
+ this,
+ pthr,
+ poa
+ );
+
+ palError = CSharedMemoryObject::Initialize(pthr, poa);
+ if (NO_ERROR != palError)
+ {
+ goto InitializeExit;
+ }
+
+ //
+ // Sanity check the passed in object type
+ //
+
+ _ASSERTE(CObjectType::WaitableObject == m_pot->GetSynchronizationSupport());
+
+ palError = g_pSynchronizationManager->AllocateObjectSynchData(
+ m_pot,
+ m_ObjectDomain,
+ &m_pvSynchData
+ );
+
+ if (NO_ERROR == palError && SharedObject == m_ObjectDomain)
+ {
+ SHMObjData *pshmod = SHMPTR_TO_TYPED_PTR(SHMObjData, m_shmod);
+ _ASSERTE(NULL != pshmod);
+
+ pshmod->pvSynchData = m_pvSynchData;
+ }
+
+InitializeExit:
+
+ LOGEXIT("CSharedMemoryWaitableObject::Initialize returns %d\n", palError);
+
+ return palError;
+}
+
+/*++
+Function:
+ CSharedMemoryWaitableObject::EnsureObjectIsShared
+
+ If this object is not yet in the shared domain allocate the necessary
+ shared memory structures for it and copy the object's data into those
+ structures
+
+Parameters:
+ pthr -- thread data for the calling thread
+--*/
+
+PAL_ERROR
+CSharedMemoryWaitableObject::EnsureObjectIsShared(
+ CPalThread *pthr
+ )
+{
+ PAL_ERROR palError = NO_ERROR;
+ IDataLock *pDataLock = NULL;
+ SHMPTR shmObjData = SHMNULL;
+ SHMObjData *psmod;
+ VOID *pvSharedSynchData;
+
+ _ASSERTE(NULL != pthr);
+
+ ENTRY("CSharedMemoryWaitableObject::EnsureObjectIsShared"
+ "(this = %p, pthr = %p)\n",
+ this,
+ pthr
+ );
+
+ //
+ // First, grab the process synchronization lock and check
+ // if the object is already shared
+ //
+
+ g_pSynchronizationManager->AcquireProcessLock(pthr);
+
+ if (SharedObject == m_ObjectDomain)
+ {
+ goto EnsureObjectIsSharedExitNoSHMLockRelease;
+ }
+
+ //
+ // Grab the necessary locks
+ //
+
+ SHMLock();
+
+ if (0 != m_pot->GetSharedDataSize())
+ {
+ m_sdlSharedData.AcquireLock(pthr, &pDataLock);
+ }
+
+ //
+ // Allocate the necessary shared data areas
+ //
+
+ palError = AllocateSharedDataItems(&shmObjData, &psmod);
+ if (NO_ERROR != palError)
+ {
+ goto EnsureObjectIsSharedExit;
+ }
+
+ //
+ // Promote the object's synchronization data
+ //
+
+ palError = g_pSynchronizationManager->PromoteObjectSynchData(
+ pthr,
+ m_pvSynchData,
+ &pvSharedSynchData
+ );
+
+ if (NO_ERROR != palError)
+ {
+ goto EnsureObjectIsSharedExit;
+ }
+
+ m_pvSynchData = pvSharedSynchData;
+ psmod->pvSynchData = pvSharedSynchData;
+
+ //
+ // Promote the object's data and set the domain to shared
+ //
+
+ PromoteSharedData(shmObjData, psmod);
+ m_ObjectDomain = SharedObject;
+
+EnsureObjectIsSharedExit:
+
+ if (NULL != pDataLock)
+ {
+ pDataLock->ReleaseLock(pthr, TRUE);
+ }
+
+ SHMRelease();
+
+EnsureObjectIsSharedExitNoSHMLockRelease:
+
+ g_pSynchronizationManager->ReleaseProcessLock(pthr);
+
+ if (NO_ERROR != palError && SHMNULL != shmObjData)
+ {
+ //
+ // Since shmObjdData is local to this function there's no
+ // need to continue to hold the promotion locks when
+ // freeing the allocated data on error
+ //
+
+ FreeSharedDataAreas(shmObjData);
+ }
+
+ LOGEXIT("CSharedMemoryWaitableObject::EnsureObjectIsShared returns %d\n",
+ palError
+ );
+
+ return palError;
+}
+
+/*++
+Function:
+ CSharedMemoryWaitableObject::~CSharedMemoryWaitableObject
+
+ Destructor; should only be called from ReleaseReference
+--*/
+
+CSharedMemoryWaitableObject::~CSharedMemoryWaitableObject()
+{
+ ENTRY("CSharedMemoryWaitableObject::~CSharedMemoryWaitableObject"
+ "(this = %p)\n",
+ this
+ );
+
+ if (!m_fSharedDataDereferenced)
+ {
+ ASSERT("DereferenceSharedData not called before object destructor -- delete called directly?\n");
+ DereferenceSharedData();
+ }
+
+ if (NULL != m_pvSynchData && m_fDeleteSharedData)
+ {
+ g_pSynchronizationManager->FreeObjectSynchData(
+ m_pot,
+ m_ObjectDomain,
+ m_pvSynchData
+ );
+ }
+
+ LOGEXIT("CSharedMemoryWaitableObject::~CSharedMemoryWaitableObject\n");
+}
+
+/*++
+Function:
+ CSharedMemoryWaitableObject::GetSynchStateController
+
+ Obtain a synchronization state controller for this object.
+
+Parameters:
+ pthr -- thread data for calling thread
+ ppStateController -- on success, receives a pointer to the state controller
+ instance
+--*/
+
+PAL_ERROR
+CSharedMemoryWaitableObject::GetSynchStateController(
+ CPalThread *pthr, // IN, OPTIONAL
+ ISynchStateController **ppStateController // OUT
+ )
+{
+ PAL_ERROR palError = NO_ERROR;
+
+ _ASSERTE(NULL != pthr);
+ _ASSERTE(NULL != ppStateController);
+
+ ENTRY("CSharedMemoryWaitableObject::GetSynchStateController"
+ "(this = %p, pthr = %p, ppStateController = %p",
+ this,
+ pthr,
+ ppStateController
+ );
+
+ //
+ // We need to grab the local synch lock before creating the controller
+ // (otherwise we could get promoted after passing in our parameters)
+ //
+
+ g_pSynchronizationManager->AcquireProcessLock(pthr);
+
+ palError = g_pSynchronizationManager->CreateSynchStateController(
+ pthr,
+ m_pot,
+ m_pvSynchData,
+ m_ObjectDomain,
+ ppStateController
+ );
+
+ g_pSynchronizationManager->ReleaseProcessLock(pthr);
+
+ LOGEXIT("CSharedMemoryWaitableObject::GetSynchStateController returns %d\n",
+ palError
+ );
+
+ return palError;
+}
+
+/*++
+Function:
+ CSharedMemoryWaitableObject::GetSynchWaitController
+
+ Obtain a synchronization wait controller for this object.
+
+Parameters:
+ pthr -- thread data for calling thread
+ ppWaitController -- on success, receives a pointer to the wait controller
+ instance
+--*/
+
+PAL_ERROR
+CSharedMemoryWaitableObject::GetSynchWaitController(
+ CPalThread *pthr, // IN, OPTIONAL
+ ISynchWaitController **ppWaitController // OUT
+ )
+{
+ PAL_ERROR palError = NO_ERROR;
+
+ _ASSERTE(NULL != pthr);
+ _ASSERTE(NULL != ppWaitController);
+
+ ENTRY("CSharedMemoryWaitableObject::GetSynchWaitController"
+ "(this = %p, pthr = %p, ppWaitController = %p",
+ this,
+ pthr,
+ ppWaitController
+ );
+
+ //
+ // We need to grab the local synch lock before creating the controller
+ // (otherwise we could get promoted after passing in our parameters)
+ //
+
+ g_pSynchronizationManager->AcquireProcessLock(pthr);
+
+ palError = g_pSynchronizationManager->CreateSynchWaitController(
+ pthr,
+ m_pot,
+ m_pvSynchData,
+ m_ObjectDomain,
+ ppWaitController
+ );
+
+ g_pSynchronizationManager->ReleaseProcessLock(pthr);
+
+ LOGEXIT("CSharedMemoryWaitableObject::GetSynchWaitController returns %d\n",
+ palError
+ );
+
+ return palError;
+}
+
+/*++
+Function:
+ CSharedMemoryWaitableObject::GetObjectSynchData
+
+ Obtain the synchronization data for this object. This method should only
+ be called by the synchronization manager
+
+Parameters:
+ ppvSynchData -- on success, receives a pointer to the object's synch data
+--*/
+
+PAL_ERROR
+CSharedMemoryWaitableObject::GetObjectSynchData(
+ VOID **ppvSynchData // OUT
+ )
+{
+ _ASSERTE(NULL != ppvSynchData);
+
+ ENTRY("CSharedMemoryWaitableObject::GetObjectSynchData"
+ "(this = %p, ppvSynchData = %p)\n",
+ this,
+ ppvSynchData
+ );
+
+ *ppvSynchData = m_pvSynchData;
+
+ LOGEXIT("CSharedMemoryWaitableObject::GetObjectSynchData returns %d\n",
+ NO_ERROR
+ );
+
+ return NO_ERROR;
+}
+
diff --git a/src/pal/src/objmgr/shmobject.hpp b/src/pal/src/objmgr/shmobject.hpp
new file mode 100644
index 0000000000..addfda52cc
--- /dev/null
+++ b/src/pal/src/objmgr/shmobject.hpp
@@ -0,0 +1,391 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ shmobject.hpp
+
+Abstract:
+ Shared memory based object
+
+
+
+--*/
+
+#ifndef _PAL_SHMOBJECT_HPP
+#define _PAL_SHMOBJECT_HPP
+
+#include "palobjbase.hpp"
+#include "pal/shm.hpp"
+
+extern "C"
+{
+#include "pal/list.h"
+}
+
+namespace CorUnix
+{
+ class CSimpleSharedMemoryLock : public IDataLock
+ {
+ public:
+
+ void
+ AcquireLock(
+ CPalThread *pthr,
+ IDataLock **ppDataLock
+ )
+ {
+ SHMLock();
+ *ppDataLock = static_cast<IDataLock*>(this);
+ };
+
+ virtual
+ void
+ ReleaseLock(
+ CPalThread *pthr,
+ bool fDataChanged
+ )
+ {
+ SHMRelease();
+ };
+ };
+
+ typedef struct _SHMObjData
+ {
+ SHMPTR shmPrevObj;
+ SHMPTR shmNextObj;
+ BOOL fAddedToList;
+
+ SHMPTR shmObjName;
+ SHMPTR shmObjImmutableData;
+ SHMPTR shmObjSharedData;
+
+ LONG lProcessRefCount;
+ DWORD dwNameLength;
+
+ PalObjectTypeId eTypeId;
+
+ PVOID pvSynchData;
+ } SHMObjData;
+
+ class CSharedMemoryObject : public CPalObjectBase
+ {
+ template <class T> friend void InternalDelete(T *p);
+
+ protected:
+
+ //
+ // Entry on the process's named or anonymous object list
+ //
+
+ LIST_ENTRY m_le;
+
+ //
+ // The lock that guards access to that list
+ //
+
+ CRITICAL_SECTION *m_pcsObjListLock;
+
+ //
+ // The SHMObjData for this object, protected by the
+ // shared memory lock.
+ //
+
+ SHMPTR m_shmod;
+
+ //
+ // The shared data (i.e., m_shmObjData->shmObjSharedData)
+ // for this object, mapped into this process. This will be
+ // NULL if m_pot->dwSharedDataSize is 0. Access to this data
+ // is controlled by m_ssmlSharedData when m_ObjectDomain is
+ // SharedObject, and m_sdlSharedData when it is ProcessLocalObject.
+ //
+
+ VOID *m_pvSharedData;
+
+ CSimpleSharedMemoryLock m_ssmlSharedData;
+ CSimpleDataLock m_sdlSharedData;
+
+ //
+ // Is this object process local or shared?
+ //
+
+ ObjectDomain m_ObjectDomain;
+
+ //
+ // m_fSharedDataDereferenced will be TRUE if DereferenceSharedData
+ // has already been called. (N.B. -- this is a LONG instead of a bool
+ // because it is passed to InterlockedExchange). If the shared data blob
+ // should be freed in the object's destructor (i.e., SHMfree should be
+ // called on the appropriate SHMPTRs) DereferenceSharedData will
+ // set m_fDeleteSharedData to TRUE.
+ //
+
+ LONG m_fSharedDataDereferenced;
+ LONG m_fDeleteSharedData;
+
+ PAL_ERROR
+ AllocateSharedDataItems(
+ SHMPTR *pshmObjData,
+ SHMObjData **ppsmod
+ );
+
+ static
+ void
+ FreeSharedDataAreas(
+ SHMPTR shmObjData
+ );
+
+ void
+ PromoteSharedData(
+ SHMPTR shmObjData,
+ SHMObjData *psmod
+ );
+
+ bool
+ DereferenceSharedData();
+
+ virtual
+ void
+ AcquireObjectDestructionLock(
+ CPalThread *pthr
+ );
+
+ virtual
+ bool
+ ReleaseObjectDestructionLock(
+ CPalThread *pthr,
+ bool fDestructionPending
+ );
+
+ virtual ~CSharedMemoryObject();
+
+ public:
+
+ //
+ // Constructor used for new object
+ //
+
+ CSharedMemoryObject(
+ CObjectType *pot,
+ CRITICAL_SECTION *pcsObjListLock
+ )
+ :
+ CPalObjectBase(pot),
+ m_pcsObjListLock(pcsObjListLock),
+ m_shmod(SHMNULL),
+ m_pvSharedData(NULL),
+ m_ObjectDomain(ProcessLocalObject),
+ m_fSharedDataDereferenced(FALSE),
+ m_fDeleteSharedData(FALSE)
+ {
+ InitializeListHead(&m_le);
+ };
+
+ //
+ // Constructor used to import a shared object into this process. The
+ // shared memory lock must be held when calling this contstructor
+ //
+
+ CSharedMemoryObject(
+ CObjectType *pot,
+ CRITICAL_SECTION *pcsObjListLock,
+ SHMPTR shmSharedObjectData,
+ SHMObjData *psmod,
+ bool fAddRefSharedData
+ )
+ :
+ CPalObjectBase(pot),
+ m_pcsObjListLock(pcsObjListLock),
+ m_shmod(shmSharedObjectData),
+ m_pvSharedData(NULL),
+ m_ObjectDomain(SharedObject),
+ m_fSharedDataDereferenced(FALSE),
+ m_fDeleteSharedData(FALSE)
+ {
+ InitializeListHead(&m_le);
+ if (fAddRefSharedData)
+ {
+ psmod->lProcessRefCount += 1;
+ }
+ };
+
+ virtual
+ PAL_ERROR
+ Initialize(
+ CPalThread *pthr,
+ CObjectAttributes *poa
+ );
+
+ virtual
+ PAL_ERROR
+ InitializeFromExistingSharedData(
+ CPalThread *pthr,
+ CObjectAttributes *poa
+ );
+
+ virtual
+ PAL_ERROR
+ EnsureObjectIsShared(
+ CPalThread *pthr
+ );
+
+ void
+ CleanupForProcessShutdown(
+ CPalThread *pthr
+ );
+
+ SHMPTR
+ GetShmObjData(
+ void
+ )
+ {
+ return m_shmod;
+ };
+
+ PLIST_ENTRY
+ GetObjectListLink(
+ void
+ )
+ {
+ return &m_le;
+ }
+
+ //
+ // Clients of this object -- in particular, CSharedMemoryObjectManager
+ // -- can't use CONTAINING_RECORD directly, since they don't have
+ // access to m_Link.
+ //
+
+ static
+ CSharedMemoryObject*
+ GetObjectFromListLink(PLIST_ENTRY pLink);
+
+ //
+ // IPalObject routines
+ //
+
+ virtual
+ PAL_ERROR
+ GetSharedData(
+ CPalThread *pthr,
+ LockType eLockRequest,
+ IDataLock **ppDataLock,
+ void **ppvSharedData
+ );
+
+ virtual
+ PAL_ERROR
+ GetSynchStateController(
+ CPalThread *pthr,
+ ISynchStateController **ppStateController
+ );
+
+ virtual
+ PAL_ERROR
+ GetSynchWaitController(
+ CPalThread *pthr,
+ ISynchWaitController **ppWaitController
+ );
+
+ virtual
+ ObjectDomain
+ GetObjectDomain(
+ void
+ );
+
+ virtual
+ PAL_ERROR
+ GetObjectSynchData(
+ VOID **ppvSynchData
+ );
+
+ };
+
+ class CSharedMemoryWaitableObject : public CSharedMemoryObject
+ {
+ template <class T> friend void InternalDelete(T *p);
+
+ protected:
+
+ VOID *m_pvSynchData;
+
+ virtual ~CSharedMemoryWaitableObject();
+
+ public:
+
+ CSharedMemoryWaitableObject(
+ CObjectType *pot,
+ CRITICAL_SECTION *pcsObjListLock
+ )
+ :
+ CSharedMemoryObject(pot, pcsObjListLock),
+ m_pvSynchData(NULL)
+ {
+ };
+
+ //
+ // Constructor used to import a shared object into this process. The
+ // shared memory lock must be held when calling this contstructor
+ //
+
+ CSharedMemoryWaitableObject(
+ CObjectType *pot,
+ CRITICAL_SECTION *pcsObjListLock,
+ SHMPTR shmSharedObjectData,
+ SHMObjData *psmod,
+ bool fAddRefSharedData
+ )
+ :
+ CSharedMemoryObject(pot, pcsObjListLock, shmSharedObjectData, psmod, fAddRefSharedData),
+ m_pvSynchData(psmod->pvSynchData)
+ {
+ };
+
+ virtual
+ PAL_ERROR
+ Initialize(
+ CPalThread *pthr,
+ CObjectAttributes *poa
+ );
+
+ virtual
+ PAL_ERROR
+ EnsureObjectIsShared(
+ CPalThread *pthr
+ );
+
+ //
+ // IPalObject routines
+ //
+
+ virtual
+ PAL_ERROR
+ GetSynchStateController(
+ CPalThread *pthr,
+ ISynchStateController **ppStateController
+ );
+
+ virtual
+ PAL_ERROR
+ GetSynchWaitController(
+ CPalThread *pthr,
+ ISynchWaitController **ppWaitController
+ );
+
+ virtual
+ PAL_ERROR
+ GetObjectSynchData(
+ VOID **ppvSynchData
+ );
+ };
+
+}
+
+#endif // _PAL_SHMOBJECT_HPP
+
diff --git a/src/pal/src/objmgr/shmobjectmanager.cpp b/src/pal/src/objmgr/shmobjectmanager.cpp
new file mode 100644
index 0000000000..42754216f1
--- /dev/null
+++ b/src/pal/src/objmgr/shmobjectmanager.cpp
@@ -0,0 +1,1567 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ shmobjectmgr.cpp
+
+Abstract:
+ Shared memory based object manager
+
+
+
+--*/
+
+#include "shmobjectmanager.hpp"
+#include "shmobject.hpp"
+#include "pal/cs.hpp"
+#include "pal/thread.hpp"
+#include "pal/procobj.hpp"
+#include "pal/dbgmsg.h"
+
+SET_DEFAULT_DEBUG_CHANNEL(PAL);
+
+#include "pal/corunix.inl"
+
+using namespace CorUnix;
+
+IPalObjectManager * CorUnix::g_pObjectManager;
+
+static
+PAL_ERROR
+CheckObjectTypeAndRights(
+ IPalObject *pobj,
+ CAllowedObjectTypes *paot,
+ DWORD dwRightsGranted,
+ DWORD dwRightsRequired
+ );
+
+/*++
+Function:
+ CSharedMemoryObjectManager::Initialize
+
+ Performs (possibly failing) startup tasks for the object manager
+
+Parameters:
+ None
+--*/
+
+PAL_ERROR
+CSharedMemoryObjectManager::Initialize(
+ void
+ )
+{
+ PAL_ERROR palError = NO_ERROR;
+
+ ENTRY("CSharedMemoryObjectManager::Initialize (this=%p)\n", this);
+
+ InitializeListHead(&m_leNamedObjects);
+ InitializeListHead(&m_leAnonymousObjects);
+
+ InternalInitializeCriticalSection(&m_csListLock);
+ m_fListLockInitialized = TRUE;
+
+ palError = m_HandleManager.Initialize();
+
+ LOGEXIT("CSharedMemoryObjectManager::Initialize returns %d", palError);
+
+ return palError;
+}
+
+/*++
+Function:
+ CSharedMemoryObjectManager::Shutdown
+
+ Cleans up the object manager. This routine will call cleanup routines
+ for all objects referenced by this process. After this routine is called
+ no attempt should be made to access an IPalObject.
+
+Parameters:
+ pthr -- thread data for calling thread
+--*/
+
+PAL_ERROR
+CSharedMemoryObjectManager::Shutdown(
+ CPalThread *pthr
+ )
+{
+ PLIST_ENTRY ple;
+ CSharedMemoryObject *pshmobj;
+
+ _ASSERTE(NULL != pthr);
+
+ ENTRY("CSharedMemoryObjectManager::Shutdown (this=%p, pthr=%p)\n",
+ this,
+ pthr
+ );
+
+ InternalEnterCriticalSection(pthr, &m_csListLock);
+ SHMLock();
+
+ while (!IsListEmpty(&m_leAnonymousObjects))
+ {
+ ple = RemoveTailList(&m_leAnonymousObjects);
+ pshmobj = CSharedMemoryObject::GetObjectFromListLink(ple);
+ pshmobj->CleanupForProcessShutdown(pthr);
+ }
+
+ while (!IsListEmpty(&m_leNamedObjects))
+ {
+ ple = RemoveTailList(&m_leNamedObjects);
+ pshmobj = CSharedMemoryObject::GetObjectFromListLink(ple);
+ pshmobj->CleanupForProcessShutdown(pthr);
+ }
+
+ SHMRelease();
+ InternalLeaveCriticalSection(pthr, &m_csListLock);
+
+ LOGEXIT("CSharedMemoryObjectManager::Shutdown returns %d\n", NO_ERROR);
+
+ return NO_ERROR;
+}
+
+/*++
+Function:
+ CSharedMemoryObjectManager::AllocateObject
+
+ Allocates a new object instance of the specified type.
+
+Parameters:
+ pthr -- thread data for calling thread
+ pot -- type of object to allocate
+ poa -- attributes (name and SD) of object to allocate
+ ppobjNew -- on success, receives a reference to the new object
+--*/
+
+PAL_ERROR
+CSharedMemoryObjectManager::AllocateObject(
+ CPalThread *pthr,
+ CObjectType *pot,
+ CObjectAttributes *poa,
+ IPalObject **ppobjNew // OUT
+ )
+{
+ PAL_ERROR palError = NO_ERROR;
+ CSharedMemoryObject *pshmobj = NULL;
+
+ _ASSERTE(NULL != pthr);
+ _ASSERTE(NULL != pot);
+ _ASSERTE(NULL != poa);
+ _ASSERTE(NULL != ppobjNew);
+
+ ENTRY("CSharedMemoryObjectManager::AllocateObject "
+ "(this=%p, pthr=%p, pot=%p, poa=%p, ppobjNew=%p)\n",
+ this,
+ pthr,
+ pot,
+ poa,
+ ppobjNew
+ );
+
+ if (CObjectType::WaitableObject == pot->GetSynchronizationSupport())
+ {
+ pshmobj = InternalNew<CSharedMemoryWaitableObject>(pot, &m_csListLock);
+ }
+ else
+ {
+ pshmobj = InternalNew<CSharedMemoryObject>(pot, &m_csListLock);
+ }
+
+ if (NULL != pshmobj)
+ {
+ palError = pshmobj->Initialize(pthr, poa);
+ if (NO_ERROR == palError)
+ {
+ *ppobjNew = static_cast<IPalObject*>(pshmobj);
+ }
+ }
+ else
+ {
+ ERROR("Unable to allocate pshmobj\n");
+ palError = ERROR_OUTOFMEMORY;
+ }
+
+ LOGEXIT("CSharedMemoryObjectManager::AllocateObject returns %d\n", palError);
+ return palError;
+}
+
+/*++
+Function:
+ CSharedMemoryObjectManager::RegisterObject
+
+ Registers a newly-allocated object instance. If the object to be registered
+ has a name, and a previously registered object has the same name the new
+ object will not be registered.
+
+Distinguished return values:
+ ERROR_ALREADY_EXISTS -- an object of a compatible type was already registered
+ with the specified name
+ ERROR_INVALID_HANDLE -- an object of an incompatible type was already
+ registered with the specified name
+
+Parameters:
+ pthr -- thread data for calling thread
+ pobjToRegister -- the object instance to register. This routine will always
+ call ReleaseReference on this instance
+ paot -- object types that are compatible with the new object instance
+ dwRightsRequested -- requested access rights for the returned handle (ignored)
+ pHandle -- on success, receives a handle to the registered object
+ ppobjRegistered -- on success, receives a reference to the registered object
+ instance.
+--*/
+
+PAL_ERROR
+CSharedMemoryObjectManager::RegisterObject(
+ CPalThread *pthr,
+ IPalObject *pobjToRegister,
+ CAllowedObjectTypes *paot,
+ DWORD dwRightsRequested,
+ HANDLE *pHandle, // OUT
+ IPalObject **ppobjRegistered // OUT
+ )
+{
+ PAL_ERROR palError = NO_ERROR;
+ CSharedMemoryObject *pshmobj = static_cast<CSharedMemoryObject*>(pobjToRegister);
+ SHMObjData *psmodNew = NULL;
+ CObjectAttributes *poa;
+ CObjectType *potObj;
+ IPalObject *pobjExisting;
+ BOOL fInherit = FALSE;
+ BOOL fShared = FALSE;
+
+ _ASSERTE(NULL != pthr);
+ _ASSERTE(NULL != pobjToRegister);
+ _ASSERTE(NULL != paot);
+ _ASSERTE(NULL != pHandle);
+ _ASSERTE(NULL != ppobjRegistered);
+
+ ENTRY("CSharedMemoryObjectManager::RegisterObject "
+ "(this=%p, pthr=%p, pobjToRegister=%p, paot=%p, "
+ "dwRightsRequested=%d, pHandle=%p, ppobjRegistered=%p)\n",
+ this,
+ pthr,
+ pobjToRegister,
+ paot,
+ dwRightsRequested,
+ pHandle,
+ ppobjRegistered
+ );
+
+ poa = pobjToRegister->GetObjectAttributes();
+ _ASSERTE(NULL != poa);
+
+ if (NULL != poa->pSecurityAttributes)
+ {
+ fInherit = poa->pSecurityAttributes->bInheritHandle;
+ }
+
+ potObj = pobjToRegister->GetObjectType();
+ fShared = (SharedObject == pshmobj->GetObjectDomain());
+
+ InternalEnterCriticalSection(pthr, &m_csListLock);
+
+ if (fShared)
+ {
+ //
+ // We only need to acquire the shared memory lock if this
+ // object is actually shared.
+ //
+
+ SHMLock();
+ }
+
+ if (0 != poa->sObjectName.GetStringLength())
+ {
+ SHMPTR shmObjectListHead = SHMNULL;
+
+ //
+ // The object must be shared
+ //
+
+ _ASSERTE(fShared);
+
+ //
+ // Check if an object by this name alredy exists
+ //
+
+ palError = LocateObject(
+ pthr,
+ &poa->sObjectName,
+ paot,
+ &pobjExisting
+ );
+
+ if (NO_ERROR == palError)
+ {
+ //
+ // Obtain a new handle to the existing object
+ //
+
+ palError = ObtainHandleForObject(
+ pthr,
+ pobjExisting,
+ dwRightsRequested,
+ fInherit,
+ NULL,
+ pHandle
+ );
+
+ if (NO_ERROR == palError)
+ {
+ //
+ // Transfer object reference to out param
+ //
+
+ *ppobjRegistered = pobjExisting;
+ palError = ERROR_ALREADY_EXISTS;
+ }
+ else
+ {
+ pobjExisting->ReleaseReference(pthr);
+ }
+
+ goto RegisterObjectExit;
+ }
+ else if (ERROR_INVALID_NAME != palError)
+ {
+ //
+ // Something different than an object not found error
+ // occurred. This is most likely due to a type conflict.
+ //
+
+ goto RegisterObjectExit;
+ }
+
+ //
+ // Insert the object on the named object lists
+ //
+
+ InsertTailList(&m_leNamedObjects, pshmobj->GetObjectListLink());
+
+ psmodNew = SHMPTR_TO_TYPED_PTR(SHMObjData, pshmobj->GetShmObjData());
+ if (NULL == psmodNew)
+ {
+ ASSERT("Failure to map shared object data\n");
+ palError = ERROR_INTERNAL_ERROR;
+ goto RegisterObjectExit;
+ }
+
+ shmObjectListHead = SHMGetInfo(SIID_NAMED_OBJECTS);
+ if (SHMNULL != shmObjectListHead)
+ {
+ SHMObjData *psmodListHead;
+
+ psmodListHead = SHMPTR_TO_TYPED_PTR(SHMObjData, shmObjectListHead);
+ if (NULL != psmodListHead)
+ {
+ psmodNew->shmNextObj = shmObjectListHead;
+ psmodListHead->shmPrevObj = pshmobj->GetShmObjData();
+ }
+ else
+ {
+ ASSERT("Failure to map shared object data\n");
+ palError = ERROR_INTERNAL_ERROR;
+ goto RegisterObjectExit;
+ }
+ }
+
+ psmodNew->fAddedToList = TRUE;
+
+ if (!SHMSetInfo(SIID_NAMED_OBJECTS, pshmobj->GetShmObjData()))
+ {
+ ASSERT("Failed to set shared named object list head\n");
+ palError = ERROR_INTERNAL_ERROR;
+ goto RegisterObjectExit;
+ }
+ }
+ else
+ {
+ //
+ // Place the object on the anonymous object list
+ //
+
+ InsertTailList(&m_leAnonymousObjects, pshmobj->GetObjectListLink());
+ }
+
+ //
+ // Hoist the object's immutable data (if any) into shared memory if
+ // the object is shared
+ //
+
+ if (fShared && 0 != potObj->GetImmutableDataSize())
+ {
+ VOID *pvImmutableData;
+ SHMObjData *psmod;
+
+ palError = pobjToRegister->GetImmutableData(&pvImmutableData);
+ if (NO_ERROR != palError)
+ {
+ ASSERT("Failure to obtain object immutable data\n");
+ goto RegisterObjectExit;
+ }
+
+ psmod = SHMPTR_TO_TYPED_PTR(SHMObjData, pshmobj->GetShmObjData());
+ if (NULL != psmod)
+ {
+ VOID *pvSharedImmutableData =
+ SHMPTR_TO_TYPED_PTR(VOID, psmod->shmObjImmutableData);
+
+ if (NULL != pvSharedImmutableData)
+ {
+ CopyMemory(
+ pvSharedImmutableData,
+ pvImmutableData,
+ potObj->GetImmutableDataSize()
+ );
+ }
+ else
+ {
+ ASSERT("Failure to map psmod->shmObjImmutableData\n");
+ palError = ERROR_INTERNAL_ERROR;
+ goto RegisterObjectExit;
+ }
+ }
+ else
+ {
+ ASSERT("Failure to map pshmobj->GetShmObjData()\n");
+ palError = ERROR_INTERNAL_ERROR;
+ goto RegisterObjectExit;
+ }
+ }
+
+ //
+ // Obtain a handle for the new object
+ //
+
+ palError = ObtainHandleForObject(
+ pthr,
+ pobjToRegister,
+ dwRightsRequested,
+ fInherit,
+ NULL,
+ pHandle
+ );
+
+ if (NO_ERROR == palError)
+ {
+ //
+ // Transfer pobjToRegister reference to out param
+ //
+
+ *ppobjRegistered = pobjToRegister;
+ pobjToRegister = NULL;
+ }
+
+RegisterObjectExit:
+
+ if (fShared)
+ {
+ SHMRelease();
+ }
+
+ InternalLeaveCriticalSection(pthr, &m_csListLock);
+
+ if (NULL != pobjToRegister)
+ {
+ pobjToRegister->ReleaseReference(pthr);
+ }
+
+ LOGEXIT("CSharedMemoryObjectManager::RegisterObject return %d\n", palError);
+
+ return palError;
+}
+
+/*++
+Function:
+ CSharedMemoryObjectManager::LocateObject
+
+ Search for a previously registered object with a give name and type
+
+Distinguished return values:
+ ERROR_INVALID_NAME -- no object with the specified name was previously
+ registered
+ ERROR_INVALID_HANDLE -- an object with the specified name was previously
+ registered, but its type is not compatible
+
+Parameters:
+ pthr -- thread data for calling thread
+ psObjectToLocate -- the name of the object to locate
+ paot -- acceptable types for the object
+ ppobj -- on success, receives a reference to the object instance
+--*/
+
+PAL_ERROR
+CSharedMemoryObjectManager::LocateObject(
+ CPalThread *pthr,
+ CPalString *psObjectToLocate,
+ CAllowedObjectTypes *paot,
+ IPalObject **ppobj // OUT
+ )
+{
+ PAL_ERROR palError = NO_ERROR;
+ IPalObject *pobjExisting = NULL;
+ SHMPTR shmSharedObjectData = SHMNULL;
+ SHMPTR shmObjectListEntry = SHMNULL;
+ SHMObjData *psmod = NULL;
+ LPWSTR pwsz = NULL;
+
+ _ASSERTE(NULL != pthr);
+ _ASSERTE(NULL != psObjectToLocate);
+ _ASSERTE(NULL != psObjectToLocate->GetString());
+ _ASSERTE(PAL_wcslen(psObjectToLocate->GetString()) == psObjectToLocate->GetStringLength());
+ _ASSERTE(NULL != ppobj);
+
+ ENTRY("CSharedMemoryObjectManager::LocateObject "
+ "(this=%p, pthr=%p, psObjectToLocate=%p, paot=%p, "
+ "ppobj=%p)\n",
+ this,
+ pthr,
+ psObjectToLocate,
+ paot,
+ ppobj
+ );
+
+ TRACE("Searching for object name %S\n", psObjectToLocate->GetString());
+
+ InternalEnterCriticalSection(pthr, &m_csListLock);
+
+ //
+ // Search the local named object list for this object
+ //
+
+ for (PLIST_ENTRY ple = m_leNamedObjects.Flink;
+ ple != &m_leNamedObjects;
+ ple = ple->Flink)
+ {
+ CObjectAttributes *poa;
+ CSharedMemoryObject *pshmobj =
+ CSharedMemoryObject::GetObjectFromListLink(ple);
+
+ poa = pshmobj->GetObjectAttributes();
+ _ASSERTE(NULL != poa);
+
+ if (poa->sObjectName.GetStringLength() != psObjectToLocate->GetStringLength())
+ {
+ continue;
+ }
+
+ if (0 != PAL_wcscmp(poa->sObjectName.GetString(), psObjectToLocate->GetString()))
+ {
+ continue;
+ }
+
+ //
+ // This object has the name we're looking for
+ //
+
+ pobjExisting = static_cast<IPalObject*>(pshmobj);
+ break;
+ }
+
+ if (NULL != pobjExisting)
+ {
+ //
+ // Validate the located object's type
+ //
+
+ if (paot->IsTypeAllowed(
+ pobjExisting->GetObjectType()->GetId()
+ ))
+ {
+ TRACE("Local object exists with compatible type\n");
+
+ //
+ // Add a reference to the found object
+ //
+
+ pobjExisting->AddReference();
+ *ppobj = pobjExisting;
+ }
+ else
+ {
+ TRACE("Local object exists w/ incompatible type\n");
+ palError = ERROR_INVALID_HANDLE;
+ }
+
+ goto LocateObjectExit;
+ }
+
+ //
+ // Search the shared memory named object list for a matching object
+ //
+
+ SHMLock();
+
+ shmObjectListEntry = SHMGetInfo(SIID_NAMED_OBJECTS);
+ while (SHMNULL != shmObjectListEntry)
+ {
+ psmod = SHMPTR_TO_TYPED_PTR(SHMObjData, shmObjectListEntry);
+ if (NULL != psmod)
+ {
+ if (psmod->dwNameLength == psObjectToLocate->GetStringLength())
+ {
+ pwsz = SHMPTR_TO_TYPED_PTR(WCHAR, psmod->shmObjName);
+ if (NULL != pwsz)
+ {
+ if (0 == PAL_wcscmp(pwsz, psObjectToLocate->GetString()))
+ {
+ //
+ // This is the object we were looking for.
+ //
+
+ shmSharedObjectData = shmObjectListEntry;
+ break;
+ }
+ }
+ else
+ {
+ ASSERT("Unable to map psmod->shmObjName\n");
+ break;
+ }
+ }
+
+ shmObjectListEntry = psmod->shmNextObj;
+ }
+ else
+ {
+ ASSERT("Unable to map shmObjectListEntry\n");
+ break;
+ }
+ }
+
+ if (SHMNULL != shmSharedObjectData)
+ {
+ CSharedMemoryObject *pshmobj = NULL;
+ CObjectAttributes oa(pwsz, NULL);
+
+ //
+ // Check if the type is allowed
+ //
+
+ if (!paot->IsTypeAllowed(psmod->eTypeId))
+ {
+ TRACE("Remote object exists w/ incompatible type\n");
+ palError = ERROR_INVALID_HANDLE;
+ goto LocateObjectExitSHMRelease;
+ }
+
+ //
+ // Get the local instance of the CObjectType
+ //
+
+ CObjectType *pot = CObjectType::GetObjectTypeById(psmod->eTypeId);
+ if (NULL == pot)
+ {
+ ASSERT("Invalid object type ID in shared memory info\n");
+ goto LocateObjectExitSHMRelease;
+ }
+
+ TRACE("Remote object exists compatible type -- importing\n");
+
+ //
+ // Create the local state for the shared object
+ //
+
+ palError = ImportSharedObjectIntoProcess(
+ pthr,
+ pot,
+ &oa,
+ shmSharedObjectData,
+ psmod,
+ TRUE,
+ &pshmobj
+ );
+
+ if (NO_ERROR == palError)
+ {
+ *ppobj = static_cast<IPalObject*>(pshmobj);
+ }
+ else
+ {
+ ERROR("Failure initializing object from shared data\n");
+ goto LocateObjectExitSHMRelease;
+ }
+
+ }
+ else
+ {
+ //
+ // The object was not found
+ //
+
+ palError = ERROR_INVALID_NAME;
+ }
+
+LocateObjectExitSHMRelease:
+
+ SHMRelease();
+
+LocateObjectExit:
+
+ InternalLeaveCriticalSection(pthr, &m_csListLock);
+
+ LOGEXIT("CSharedMemoryObjectManager::LocateObject returns %d\n", palError);
+
+ return palError;
+}
+
+/*++
+Function:
+ CSharedMemoryObjectManager::ObtainHandleForObject
+
+ Allocated a new handle for an object
+
+Parameters:
+ pthr -- thread data for calling thread
+ pobj -- the object to allocate a handle for
+ dwRightsRequired -- the access rights to grant the handle; currently ignored
+ fInheritHandle -- true if the handle is inheritable; ignored for all but file
+ objects that represent pipes
+ pProcessForHandle -- the process the handle is to be used from; currently
+ must be NULL
+ pNewHandle -- on success, receives the newly allocated handle
+--*/
+
+PAL_ERROR
+CSharedMemoryObjectManager::ObtainHandleForObject(
+ CPalThread *pthr,
+ IPalObject *pobj,
+ DWORD dwRightsRequested,
+ bool fInheritHandle,
+ IPalProcess *pProcessForHandle, // IN, OPTIONAL
+ HANDLE *pNewHandle // OUT
+ )
+{
+ PAL_ERROR palError = NO_ERROR;
+
+ _ASSERTE(NULL != pthr);
+ _ASSERTE(NULL != pobj);
+ _ASSERTE(NULL != pNewHandle);
+
+ ENTRY("CSharedMemoryObjectManager::ObtainHandleForObject "
+ "(this=%p, pthr=%p, pobj=%p, dwRightsRequested=%d, "
+ "fInheritHandle=%p, pProcessForHandle=%p, pNewHandle=%p)\n",
+ this,
+ pthr,
+ pobj,
+ dwRightsRequested,
+ fInheritHandle,
+ pProcessForHandle,
+ pNewHandle
+ );
+
+ if (NULL != pProcessForHandle)
+ {
+ //
+ // Not yet supported
+ //
+
+ ASSERT("Caller to ObtainHandleForObject provided a process\n");
+ return ERROR_CALL_NOT_IMPLEMENTED;
+ }
+
+ palError = m_HandleManager.AllocateHandle(
+ pthr,
+ pobj,
+ dwRightsRequested,
+ fInheritHandle,
+ pNewHandle
+ );
+
+ LOGEXIT("CSharedMemoryObjectManager::ObtainHandleForObject return %d\n", palError);
+
+ return palError;
+}
+
+/*++
+Function:
+ CSharedMemoryObjectManager::RevokeHandle
+
+ Removes a handle from the process's handle table, which in turn releases
+ the handle's reference on the object instance it refers to
+
+Parameters:
+ pthr -- thread data for calling thread
+ hHandleToRevoke -- the handle to revoke
+--*/
+
+PAL_ERROR
+CSharedMemoryObjectManager::RevokeHandle(
+ CPalThread *pthr,
+ HANDLE hHandleToRevoke
+ )
+{
+ PAL_ERROR palError = NO_ERROR;
+
+ _ASSERTE(NULL != pthr);
+
+ ENTRY("CSharedMemoryObjectManager::RevokeHandle "
+ "(this=%p, pthr=%p, hHandleToRevoke=%p)\n",
+ this,
+ pthr,
+ hHandleToRevoke
+ );
+
+ palError = m_HandleManager.FreeHandle(pthr, hHandleToRevoke);
+
+ LOGEXIT("CSharedMemoryObjectManager::RevokeHandle returns %d\n", palError);
+
+ return palError;
+}
+
+/*++
+Function:
+ CSharedMemoryObjectManager::ReferenceObjectByHandle
+
+ Returns a referenced object instance that a handle refers to
+
+Parameters:
+ pthr -- thread data for calling thread
+ hHandleToReference -- the handle to reference
+ paot -- acceptable types for the underlying object
+ dwRightsRequired -- the access rights that the handle must have been
+ granted; currently ignored
+ ppobj -- on success, receives a reference to the object instance
+--*/
+
+PAL_ERROR
+CSharedMemoryObjectManager::ReferenceObjectByHandle(
+ CPalThread *pthr,
+ HANDLE hHandleToReference,
+ CAllowedObjectTypes *paot,
+ DWORD dwRightsRequired,
+ IPalObject **ppobj // OUT
+ )
+{
+ PAL_ERROR palError;
+ DWORD dwRightsGranted;
+ IPalObject *pobj;
+
+ _ASSERTE(NULL != pthr);
+ _ASSERTE(NULL != paot);
+ _ASSERTE(NULL != ppobj);
+
+ ENTRY("CSharedMemoryObjectManager::ReferenceObjectByHandle "
+ "(this=%p, pthr=%p, hHandleToReference=%p, paot=%p, "
+ "dwRightsRequired=%d, ppobj=%p)\n",
+ this,
+ pthr,
+ hHandleToReference,
+ paot,
+ dwRightsRequired,
+ ppobj
+ );
+
+ palError = m_HandleManager.GetObjectFromHandle(
+ pthr,
+ hHandleToReference,
+ &dwRightsGranted,
+ &pobj
+ );
+
+ if (NO_ERROR == palError)
+ {
+ palError = CheckObjectTypeAndRights(
+ pobj,
+ paot,
+ dwRightsGranted,
+ dwRightsRequired
+ );
+
+ if (NO_ERROR == palError)
+ {
+ //
+ // Transfer object reference to out parameter
+ //
+
+ *ppobj = pobj;
+ }
+ else
+ {
+ pobj->ReleaseReference(pthr);
+ }
+ }
+
+ LOGEXIT("CSharedMemoryObjectManager::ReferenceObjectByHandle returns %d\n",
+ palError
+ );
+
+ return palError;
+}
+
+/*++
+Function:
+ CSharedMemoryObjectManager::ReferenceObjectByHandleArray
+
+ Returns the referenced object instances that an array of handles
+ refer to.
+
+Parameters:
+ pthr -- thread data for calling thread
+ rgHandlesToReference -- the array of handles to reference
+ dwHandleCount -- the number of handles in the arrayu
+ paot -- acceptable types for the underlying objects
+ dwRightsRequired -- the access rights that the handles must have been
+ granted; currently ignored
+ rgpobjs -- on success, receives references to the object instances; will
+ be empty on failures
+--*/
+
+PAL_ERROR
+CSharedMemoryObjectManager::ReferenceMultipleObjectsByHandleArray(
+ CPalThread *pthr,
+ HANDLE rghHandlesToReference[],
+ DWORD dwHandleCount,
+ CAllowedObjectTypes *paot,
+ DWORD dwRightsRequired,
+ IPalObject *rgpobjs[] // OUT (caller allocated)
+ )
+{
+ PAL_ERROR palError = NO_ERROR;
+ IPalObject *pobj = NULL;
+ DWORD dwRightsGranted;
+ DWORD dw;
+
+ _ASSERTE(NULL != pthr);
+ _ASSERTE(NULL != rghHandlesToReference);
+ _ASSERTE(0 < dwHandleCount);
+ _ASSERTE(NULL != paot);
+ _ASSERTE(NULL != rgpobjs);
+
+ ENTRY("CSharedMemoryObjectManager::ReferenceMultipleObjectsByHandleArray "
+ "(this=%p, pthr=%p, rghHandlesToReference=%p, dwHandleCount=%d, "
+ "pAllowedTyped=%d, dwRightsRequired=%d, rgpobjs=%p)\n",
+ this,
+ pthr,
+ rghHandlesToReference,
+ dwHandleCount,
+ paot,
+ dwRightsRequired,
+ rgpobjs
+ );
+
+ m_HandleManager.Lock(pthr);
+
+ for (dw = 0; dw < dwHandleCount; dw += 1)
+ {
+ palError = m_HandleManager.GetObjectFromHandle(
+ pthr,
+ rghHandlesToReference[dw],
+ &dwRightsGranted,
+ &pobj
+ );
+
+ if (NO_ERROR == palError)
+ {
+ palError = CheckObjectTypeAndRights(
+ pobj,
+ paot,
+ dwRightsGranted,
+ dwRightsRequired
+ );
+
+ if (NO_ERROR == palError)
+ {
+ //
+ // Transfer reference to out array
+ //
+
+ rgpobjs[dw] = pobj;
+ pobj = NULL;
+ }
+ }
+
+ if (NO_ERROR != palError)
+ {
+ break;
+ }
+ }
+
+ //
+ // The handle manager lock must be released before releasing
+ // any object references, as ReleaseReference will acquire
+ // the object manager list lock (which needs to be acquired before
+ // the handle manager lock)
+ //
+
+ m_HandleManager.Unlock(pthr);
+
+ if (NO_ERROR != palError)
+ {
+ //
+ // dw's current value is the failing index, so we want
+ // to free from dw - 1.
+ //
+
+ while (dw > 0)
+ {
+ rgpobjs[--dw]->ReleaseReference(pthr);
+ }
+
+ if (NULL != pobj)
+ {
+ pobj->ReleaseReference(pthr);
+ }
+ }
+
+ LOGEXIT("CSharedMemoryObjectManager::ReferenceMultipleObjectsByHandleArray"
+ " returns %d\n",
+ palError
+ );
+
+ return palError;
+}
+
+/*++
+Function:
+ CSharedMemoryObjectManager::ReferenceObjectByForeignHandle
+
+ Returns a referenced object instance that a handle belongin to
+ another process refers to; currently unimplemented
+
+Parameters:
+ pthr -- thread data for calling thread
+ hForeignHandle -- the handle to reference
+ pForeignProcess -- the process that hForeignHandle belongs to
+ paot -- acceptable types for the underlying object
+ dwRightsRequired -- the access rights that the handle must have been
+ granted; currently ignored
+ ppobj -- on success, receives a reference to the object instance
+--*/
+
+PAL_ERROR
+CSharedMemoryObjectManager::ReferenceObjectByForeignHandle(
+ CPalThread *pthr,
+ HANDLE hForeignHandle,
+ IPalProcess *pForeignProcess,
+ CAllowedObjectTypes *paot,
+ DWORD dwRightsRequired,
+ IPalObject **ppobj // OUT
+ )
+{
+ //
+ // Not implemented for basic shared memory object manager --
+ // requires an IPC channel. (For the shared memory object manager
+ // PAL_LocalHandleToRemote and PAL_RemoteHandleToLocal must still
+ // be used...)
+ //
+
+ ASSERT("ReferenceObjectByForeignHandle not yet supported\n");
+ return ERROR_CALL_NOT_IMPLEMENTED;
+}
+
+/*++
+Function:
+ CSharedMemoryObjectManager::ImportSharedObjectIntoProcess
+
+ Takes an object's shared memory data and from it creates the
+ necessary in-process structures for the object
+
+Parameters:
+ pthr -- thread data for calling thread
+ pot -- the object's type
+ poa -- attributes for the object
+ shmSharedObjectData -- the shared memory pointer for the object's shared
+ data
+ psmod -- the shared memory data for the object, mapped into this process's
+ address space
+ fAddRefSharedData -- if TRUE, we need to add to the shared data reference
+ count
+ ppshmobj -- on success, receives a pointer to the newly created local
+ object instance
+--*/
+
+PAL_ERROR
+CSharedMemoryObjectManager::ImportSharedObjectIntoProcess(
+ CPalThread *pthr,
+ CObjectType *pot,
+ CObjectAttributes *poa,
+ SHMPTR shmSharedObjectData,
+ SHMObjData *psmod,
+ bool fAddRefSharedData,
+ CSharedMemoryObject **ppshmobj
+ )
+{
+ PAL_ERROR palError = NO_ERROR;
+ CSharedMemoryObject *pshmobj;
+ PLIST_ENTRY pleObjectList;
+
+ _ASSERTE(NULL != pthr);
+ _ASSERTE(NULL != pot);
+ _ASSERTE(NULL != poa);
+ _ASSERTE(SHMNULL != shmSharedObjectData);
+ _ASSERTE(NULL != psmod);
+ _ASSERTE(NULL != ppshmobj);
+
+ ENTRY("CSharedMemoryObjectManager::ImportSharedObjectIntoProcess(pthr=%p, "
+ "pot=%p, poa=%p, shmSharedObjectData=%p, psmod=%p, fAddRefSharedData=%d, "
+ "ppshmobj=%p)\n",
+ pthr,
+ pot,
+ poa,
+ shmSharedObjectData,
+ psmod,
+ fAddRefSharedData,
+ ppshmobj
+ );
+
+ if (CObjectType::WaitableObject == pot->GetSynchronizationSupport())
+ {
+ pshmobj = InternalNew<CSharedMemoryWaitableObject>(pot,
+ &m_csListLock,
+ shmSharedObjectData,
+ psmod,
+ fAddRefSharedData);
+ }
+ else
+ {
+ pshmobj = InternalNew<CSharedMemoryObject>(pot,
+ &m_csListLock,
+ shmSharedObjectData,
+ psmod,
+ fAddRefSharedData);
+ }
+
+ if (NULL != pshmobj)
+ {
+ palError = pshmobj->InitializeFromExistingSharedData(pthr, poa);
+ if (NO_ERROR == palError)
+ {
+ if (0 != psmod->dwNameLength)
+ {
+ pleObjectList = &m_leNamedObjects;
+ }
+ else
+ {
+ pleObjectList = &m_leAnonymousObjects;
+ }
+
+ InsertTailList(pleObjectList, pshmobj->GetObjectListLink());
+ }
+ else
+ {
+ goto ImportSharedObjectIntoProcessExit;
+ }
+ }
+ else
+ {
+ ERROR("Unable to alllocate new object\n");
+ palError = ERROR_OUTOFMEMORY;
+ goto ImportSharedObjectIntoProcessExit;
+ }
+
+ *ppshmobj = pshmobj;
+
+ImportSharedObjectIntoProcessExit:
+
+ LOGEXIT("CSharedMemoryObjectManager::ImportSharedObjectIntoProcess returns %d\n", palError);
+
+ return palError;
+}
+
+static PalObjectTypeId RemotableObjectTypes[] =
+ {otiManualResetEvent, otiAutoResetEvent, otiMutex, otiProcess};
+
+static CAllowedObjectTypes aotRemotable(
+ RemotableObjectTypes,
+ sizeof(RemotableObjectTypes) / sizeof(RemotableObjectTypes[0])
+ );
+
+/*++
+Function:
+ PAL_LocalHandleToRemote
+
+ Returns a "remote handle" that may be passed to another process.
+
+Parameters:
+ hLocal -- the handle to generate a "remote handle" for
+--*/
+
+PALIMPORT
+RHANDLE
+PALAPI
+PAL_LocalHandleToRemote(IN HANDLE hLocal)
+{
+ PAL_ERROR palError = NO_ERROR;
+ CPalThread *pthr;
+ IPalObject *pobj = NULL;
+ CSharedMemoryObject *pshmobj;
+ SHMObjData *psmod = NULL;
+ RHANDLE hRemote = reinterpret_cast<RHANDLE>(INVALID_HANDLE_VALUE);
+
+ PERF_ENTRY(PAL_LocalHandleToRemote);
+ ENTRY("PAL_LocalHandleToRemote( hLocal=0x%lx )\n", hLocal);
+
+ pthr = InternalGetCurrentThread();
+
+ if (!HandleIsSpecial(hLocal))
+ {
+ palError = g_pObjectManager->ReferenceObjectByHandle(
+ pthr,
+ hLocal,
+ &aotRemotable,
+ 0,
+ &pobj
+ );
+
+ if (NO_ERROR != palError)
+ {
+ goto PAL_LocalHandleToRemoteExitNoLockRelease;
+ }
+ }
+ else if (hPseudoCurrentProcess == hLocal)
+ {
+ pobj = g_pobjProcess;
+ pobj->AddReference();
+ }
+ else
+ {
+ ASSERT("Invalid special handle type passed to PAL_LocalHandleToRemote\n");
+ palError = ERROR_INVALID_HANDLE;
+ goto PAL_LocalHandleToRemoteExitNoLockRelease;
+ }
+
+ pshmobj = static_cast<CSharedMemoryObject*>(pobj);
+
+ //
+ // Make sure that the object is shared
+ //
+
+ palError = pshmobj->EnsureObjectIsShared(pthr);
+ if (NO_ERROR != palError)
+ {
+ ERROR("Failure %d promoting object\n", palError);
+ goto PAL_LocalHandleToRemoteExitNoLockRelease;
+ }
+
+ SHMLock();
+
+ psmod = SHMPTR_TO_TYPED_PTR(SHMObjData, pshmobj->GetShmObjData());
+ if (NULL != psmod)
+ {
+ //
+ // Bump up the process ref count by 1. The receiving process will not
+ // increase the ref count when it converts the remote handle to
+ // local.
+ //
+
+ psmod->lProcessRefCount += 1;
+
+ //
+ // The remote handle is simply the SHMPTR for the SHMObjData
+ //
+
+ hRemote = reinterpret_cast<RHANDLE>(pshmobj->GetShmObjData());
+ }
+ else
+ {
+ ASSERT("Unable to map shared object data\n");
+ palError = ERROR_INTERNAL_ERROR;
+ goto PAL_LocalHandleToRemoteExit;
+ }
+
+PAL_LocalHandleToRemoteExit:
+
+ SHMRelease();
+
+PAL_LocalHandleToRemoteExitNoLockRelease:
+
+ if (NULL != pobj)
+ {
+ pobj->ReleaseReference(pthr);
+ }
+
+ if (NO_ERROR != palError)
+ {
+ pthr->SetLastError(palError);
+ }
+
+ LOGEXIT("PAL_LocalHandleToRemote returns RHANDLE 0x%lx\n", hRemote);
+ PERF_EXIT(PAL_LocalHandleToRemote);
+ return hRemote;
+}
+
+/*++
+Function:
+ CSharedMemoryObjectManager::ConvertRemoteHandleToLocal
+
+ Given a "remote handle" creates a local handle that refers
+ to the desired object. (Unlike PAL_RemoteHandleToLocal this method
+ needs to access internal object manager state, so it's a member function.)
+
+Parameters:
+ pthr -- thread data for calling thread
+ rhRemote -- the remote handle
+ phLocal -- on success, receives the local handle
+--*/
+
+PAL_ERROR
+CSharedMemoryObjectManager::ConvertRemoteHandleToLocal(
+ CPalThread *pthr,
+ RHANDLE rhRemote,
+ HANDLE *phLocal
+ )
+{
+ PAL_ERROR palError = NO_ERROR;
+ SHMObjData *psmod;
+ CSharedMemoryObject *pshmobj = NULL;
+ PLIST_ENTRY pleObjectList;
+
+ _ASSERTE(NULL != pthr);
+ _ASSERTE(NULL != phLocal);
+
+ ENTRY("CSharedMemoryObjectManager::ConvertRemoteHandleToLocal "
+ "(this=%p, pthr=%p, rhRemote=%p, phLocal=%p)\n",
+ this,
+ pthr,
+ rhRemote,
+ phLocal
+ );
+
+ if (rhRemote == NULL || rhRemote == INVALID_HANDLE_VALUE)
+ {
+ palError = ERROR_INVALID_HANDLE;
+ goto ConvertRemoteHandleToLocalExitNoLockRelease;
+ }
+
+ InternalEnterCriticalSection(pthr, &m_csListLock);
+ SHMLock();
+
+ //
+ // The remote handle is really a shared memory pointer to the
+ // SHMObjData for the object.
+ //
+
+ psmod = SHMPTR_TO_TYPED_PTR(SHMObjData, reinterpret_cast<SHMPTR>(rhRemote));
+ if (NULL == psmod)
+ {
+ ERROR("Invalid remote handle\n");
+ palError = ERROR_INVALID_HANDLE;
+ goto ConvertRemoteHandleToLocalExit;
+ }
+
+ //
+ // Check to see if a local reference for this object already
+ // exists
+ //
+
+ if (0 != psmod->dwNameLength)
+ {
+ pleObjectList = &m_leNamedObjects;
+ }
+ else
+ {
+ pleObjectList = &m_leAnonymousObjects;
+ }
+
+ for (PLIST_ENTRY ple = pleObjectList->Flink;
+ ple != pleObjectList;
+ ple = ple->Flink)
+ {
+ pshmobj = CSharedMemoryObject::GetObjectFromListLink(ple);
+
+ if (SharedObject == pshmobj->GetObjectDomain()
+ && reinterpret_cast<SHMPTR>(rhRemote) == pshmobj->GetShmObjData())
+ {
+ TRACE("Object for remote handle already present in this process\n");
+
+ //
+ // PAL_LocalHandleToRemote bumped up the process refcount on the
+ // object. Since this process already had a reference to the object
+ // we need to decrement that reference now...
+ //
+
+ psmod->lProcessRefCount -= 1;
+ _ASSERTE(0 < psmod->lProcessRefCount);
+
+ //
+ // We also need to add a reference to the object (since ReleaseReference
+ // gets called below)
+ //
+
+ pshmobj->AddReference();
+
+ break;
+ }
+
+ pshmobj = NULL;
+ }
+
+ if (NULL == pshmobj)
+ {
+ CObjectType *pot;
+ CObjectAttributes oa;
+
+ //
+ // Get the local instance of the CObjectType
+ //
+
+ pot = CObjectType::GetObjectTypeById(psmod->eTypeId);
+ if (NULL == pot)
+ {
+ ASSERT("Invalid object type ID in shared memory info\n");
+ goto ConvertRemoteHandleToLocalExit;
+ }
+
+ //
+ // Create the local state for the shared object
+ //
+
+ palError = ImportSharedObjectIntoProcess(
+ pthr,
+ pot,
+ &oa,
+ reinterpret_cast<SHMPTR>(rhRemote),
+ psmod,
+ FALSE,
+ &pshmobj
+ );
+
+ if (NO_ERROR != palError)
+ {
+ goto ConvertRemoteHandleToLocalExit;
+ }
+ }
+
+ //
+ // Finally, allocate a local handle for the object
+ //
+
+ palError = ObtainHandleForObject(
+ pthr,
+ pshmobj,
+ 0,
+ FALSE,
+ NULL,
+ phLocal
+ );
+
+ConvertRemoteHandleToLocalExit:
+
+ SHMRelease();
+ InternalLeaveCriticalSection(pthr, &m_csListLock);
+
+ConvertRemoteHandleToLocalExitNoLockRelease:
+
+ if (NULL != pshmobj)
+ {
+ pshmobj->ReleaseReference(pthr);
+ }
+
+ LOGEXIT("CSharedMemoryObjectManager::ConvertRemoteHandleToLocal returns %d\n", palError);
+
+ return palError;
+}
+
+/*++
+Function:
+ PAL_RemoteHandleToLocal
+
+ Given a "remote handle", return a local handle that refers to the
+ specified process. Calls
+ SharedMemoryObjectManager::ConvertRemoteHandleToLocal to do the actual
+ work
+
+Parameters:
+ rhRemote -- the "remote handle" to convert to a local handle
+--*/
+
+PALIMPORT
+HANDLE
+PALAPI
+PAL_RemoteHandleToLocal(IN RHANDLE rhRemote)
+{
+ PAL_ERROR palError = NO_ERROR;
+ CPalThread *pthr;
+ HANDLE hLocal = INVALID_HANDLE_VALUE;
+
+ PERF_ENTRY(PAL_RemoteHandleToLocal);
+ ENTRY("PAL_RemoteHandleToLocal( hRemote=0x%lx )\n", rhRemote);
+
+ pthr = InternalGetCurrentThread();
+
+ palError = static_cast<CSharedMemoryObjectManager*>(g_pObjectManager)->ConvertRemoteHandleToLocal(
+ pthr,
+ rhRemote,
+ &hLocal
+ );
+
+ if (NO_ERROR != palError)
+ {
+ pthr->SetLastError(palError);
+ }
+
+ LOGEXIT("PAL_RemoteHandleToLocal returns HANDLE 0x%lx\n", hLocal);
+ PERF_EXIT(PAL_RemoteHandleToLocal);
+ return hLocal;
+}
+
+/*++
+Function:
+ CheckObjectTypeAndRights
+
+ Helper routine that determines if:
+ 1) An object instance is of a specified type
+ 2) A set of granted access rights satisfies the required access rights
+ (currently ignored)
+
+Parameters:
+ pobj -- the object instance whose type is to be checked
+ paot -- the acceptable type for the object instance
+ dwRightsGranted -- the granted access rights (ignored)
+ dwRightsRequired -- the required access rights (ignored)
+--*/
+
+static
+PAL_ERROR
+CheckObjectTypeAndRights(
+ IPalObject *pobj,
+ CAllowedObjectTypes *paot,
+ DWORD dwRightsGranted,
+ DWORD dwRightsRequired
+ )
+{
+ PAL_ERROR palError = NO_ERROR;
+
+ _ASSERTE(NULL != pobj);
+ _ASSERTE(NULL != paot);
+
+ ENTRY("CheckObjectTypeAndRights (pobj=%p, paot=%p, "
+ "dwRightsGranted=%d, dwRightsRequired=%d)\n",
+ pobj,
+ paot,
+ dwRightsGranted,
+ dwRightsRequired
+ );
+
+ if (paot->IsTypeAllowed(pobj->GetObjectType()->GetId()))
+ {
+#ifdef ENFORCE_OBJECT_ACCESS_RIGHTS
+
+ //
+ // This is where the access right check would occur if Win32 object
+ // security were supported.
+ //
+
+ if ((dwRightsRequired & dwRightsGranted) != dwRightsRequired)
+ {
+ palError = ERROR_ACCESS_DENIED;
+ }
+#endif
+ }
+ else
+ {
+ palError = ERROR_INVALID_HANDLE;
+ }
+
+ LOGEXIT("CheckObjectTypeAndRights returns %d\n", palError);
+
+ return palError;
+}
+
+
diff --git a/src/pal/src/objmgr/shmobjectmanager.hpp b/src/pal/src/objmgr/shmobjectmanager.hpp
new file mode 100644
index 0000000000..fbde872eeb
--- /dev/null
+++ b/src/pal/src/objmgr/shmobjectmanager.hpp
@@ -0,0 +1,167 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ shmobjectmanager.hpp
+
+Abstract:
+ Shared memory based object manager
+
+
+
+--*/
+
+#ifndef _PAL_SHMOBJECTMANAGER_HPP_
+#define _PAL_SHMOBJECTMANAGER_HPP_
+
+#include "pal/corunix.hpp"
+#include "pal/handlemgr.hpp"
+#include "pal/list.h"
+#include "shmobject.hpp"
+
+namespace CorUnix
+{
+ class CSharedMemoryObjectManager : public IPalObjectManager
+ {
+ protected:
+
+ CRITICAL_SECTION m_csListLock;
+ bool m_fListLockInitialized;
+ LIST_ENTRY m_leNamedObjects;
+ LIST_ENTRY m_leAnonymousObjects;
+
+ CSimpleHandleManager m_HandleManager;
+
+ PAL_ERROR
+ ImportSharedObjectIntoProcess(
+ CPalThread *pthr,
+ CObjectType *pot,
+ CObjectAttributes *poa,
+ SHMPTR shmSharedObjectData,
+ SHMObjData *psmod,
+ bool fAddRefSharedData,
+ CSharedMemoryObject **ppshmobj
+ );
+
+ public:
+
+ CSharedMemoryObjectManager()
+ :
+ m_fListLockInitialized(FALSE)
+ {
+ };
+
+ virtual ~CSharedMemoryObjectManager()
+ {
+ };
+
+ PAL_ERROR
+ Initialize(
+ void
+ );
+
+ PAL_ERROR
+ Shutdown(
+ CPalThread *pthr
+ );
+
+ PAL_ERROR
+ ConvertRemoteHandleToLocal(
+ CPalThread *pthr,
+ RHANDLE rhRemote,
+ HANDLE *phLocal
+ );
+
+ //
+ // IPalObjectManager routines
+ //
+
+ virtual
+ PAL_ERROR
+ AllocateObject(
+ CPalThread *pthr,
+ CObjectType *pot,
+ CObjectAttributes *poa,
+ IPalObject **ppobjNew
+ );
+
+ virtual
+ PAL_ERROR
+ RegisterObject(
+ CPalThread *pthr,
+ IPalObject *pobjToRegister,
+ CAllowedObjectTypes *paot,
+ DWORD dwRightsRequested,
+ HANDLE *pHandle,
+ IPalObject **ppobjRegistered
+ );
+
+ virtual
+ PAL_ERROR
+ LocateObject(
+ CPalThread *pthr,
+ CPalString *psObjectToLocate,
+ CAllowedObjectTypes *paot,
+ IPalObject **ppobj
+ );
+
+ virtual
+ PAL_ERROR
+ ObtainHandleForObject(
+ CPalThread *pthr,
+ IPalObject *pobj,
+ DWORD dwRightsRequested,
+ bool fInheritHandle,
+ IPalProcess *pProcessForHandle, // IN, OPTIONAL
+ HANDLE *pNewHandle
+ );
+
+ virtual
+ PAL_ERROR
+ RevokeHandle(
+ CPalThread *pthr,
+ HANDLE hHandleToRevoke
+ );
+
+ virtual
+ PAL_ERROR
+ ReferenceObjectByHandle(
+ CPalThread *pthr,
+ HANDLE hHandleToReference,
+ CAllowedObjectTypes *paot,
+ DWORD dwRightsRequired,
+ IPalObject **ppobj
+ );
+
+ virtual
+ PAL_ERROR
+ ReferenceMultipleObjectsByHandleArray(
+ CPalThread *pthr,
+ HANDLE rghHandlesToReference[],
+ DWORD dwHandleCount,
+ CAllowedObjectTypes *paot,
+ DWORD dwRightsRequired,
+ IPalObject *rgpobjs[]
+ );
+
+ virtual
+ PAL_ERROR
+ ReferenceObjectByForeignHandle(
+ CPalThread *pthr,
+ HANDLE hForeignHandle,
+ IPalProcess *pForeignProcess,
+ CAllowedObjectTypes *paot,
+ DWORD dwRightsRequired,
+ IPalObject **ppobj
+ );
+ };
+}
+
+#endif // _PAL_SHMOBJECTMANAGER_HPP_
+
diff --git a/src/pal/src/poll/fakepoll.cpp b/src/pal/src/poll/fakepoll.cpp
new file mode 100644
index 0000000000..ac531413ae
--- /dev/null
+++ b/src/pal/src/poll/fakepoll.cpp
@@ -0,0 +1,133 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+// fakepoll.h
+// poll using select
+// Warning: a call to this poll() takes about 4K of stack space.
+
+// Greg Parker gparker@cs.stanford.edu December 2000
+// This code is in the public domain and may be copied or modified without
+// permission.
+
+// Located at <http://www.sealiesoftware.com/fakepoll.h>.
+
+
+
+#include "pal/palinternal.h"
+#include "pal/fakepoll.h"
+#include "pal/dbgmsg.h"
+#include <errno.h>
+#include <string.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <unistd.h>
+
+SET_DEFAULT_DEBUG_CHANNEL(POLL);
+
+int poll(struct pollfd *pollSet, int pollCount, int pollTimeout)
+{
+ struct timeval tv;
+ struct timeval *tvp;
+ fd_set readFDs, writeFDs, exceptFDs;
+ fd_set *readp, *writep, *exceptp;
+ struct pollfd *pollEnd, *p;
+ int selected;
+ int result;
+ int maxFD;
+
+ if (!pollSet) {
+ pollEnd = NULL;
+ readp = NULL;
+ writep = NULL;
+ exceptp = NULL;
+ maxFD = 0;
+ }
+ else {
+ pollEnd = pollSet + pollCount;
+ readp = &readFDs;
+ writep = &writeFDs;
+ exceptp = &exceptFDs;
+
+ FD_ZERO(readp);
+ FD_ZERO(writep);
+ FD_ZERO(exceptp);
+
+ // Find the biggest fd in the poll set
+ maxFD = 0;
+ for (p = pollSet; p < pollEnd; p++) {
+ if (p->fd > maxFD) maxFD = p->fd;
+ }
+
+ if (maxFD >= FD_SETSIZE) {
+ // At least one fd is too big
+ errno = EINVAL;
+ return -1;
+ }
+
+ // Transcribe flags from the poll set to the fd sets
+ for (p = pollSet; p < pollEnd; p++) {
+ if (p->fd < 0) {
+ // Negative fd checks nothing and always reports zero
+ } else {
+ if (p->events & POLLIN) FD_SET(p->fd, readp);
+ if (p->events & POLLOUT) FD_SET(p->fd, writep);
+ if (p->events != 0) FD_SET(p->fd, exceptp);
+ // POLLERR is never set coming in; poll() always reports errors.
+ // But don't report if we're not listening to anything at all.
+ }
+ }
+ }
+
+ // poll timeout is in milliseconds. Convert to struct timeval.
+ // poll timeout == -1 : wait forever : select timeout of NULL
+ // poll timeout == 0 : return immediately : select timeout of zero
+ if (pollTimeout >= 0) {
+ tv.tv_sec = pollTimeout / 1000;
+ tv.tv_usec = (pollTimeout % 1000) * 1000;
+ tvp = &tv;
+ } else {
+ tvp = NULL;
+ }
+
+ selected = select(maxFD+1, readp, writep, exceptp, tvp);
+
+ if (selected < 0) {
+ // Error during select
+ result = -1;
+ }
+ else if (selected > 0) {
+ // Select found something
+ // Transcribe result from fd sets to poll set.
+ // Also count the number of selected fds. poll returns the
+ // number of ready fds; select returns the number of bits set.
+ int polled = 0;
+ for (p = pollSet; p < pollEnd; p++) {
+ p->revents = 0;
+ if (p->fd > -1) {
+ // Check p->events before setting p->revents. If we
+ // have multiple pollfds with the same fd, we want to
+ // set the appropriate revents value for each pollfd.
+ if (FD_ISSET(p->fd, readp) && (p->events & POLLIN))
+ p->revents |= POLLIN;
+ if (FD_ISSET(p->fd, writep) && (p->events & POLLOUT))
+ p->revents |= POLLOUT;
+ if (FD_ISSET(p->fd, exceptp) && (p->events != 0))
+ p->revents |= POLLERR;
+ if (p->revents) polled++;
+ }
+ }
+ result = polled;
+ }
+ else {
+ // selected == 0, select timed out before anything happened
+ // Clear all result bits and return zero.
+ for (p = pollSet; p < pollEnd; p++) {
+ p->revents = 0;
+ }
+ result = 0;
+ }
+
+ return result;
+}
diff --git a/src/pal/src/safecrt/cruntime.h b/src/pal/src/safecrt/cruntime.h
new file mode 100644
index 0000000000..cdad474e53
--- /dev/null
+++ b/src/pal/src/safecrt/cruntime.h
@@ -0,0 +1,98 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*cruntime.h - definitions specific to the target operating system and hardware
+*
+
+*
+*Purpose:
+* This header file contains widely used definitions specific to the
+* host operating system and hardware. It is included by every C source
+* and most every other header file.
+*
+* [Internal]
+*
+****/
+
+#if _MSC_VER > 1000
+#pragma once
+#endif /* _MSC_VER > 1000 */
+
+#ifndef _INC_CRUNTIME
+#define _INC_CRUNTIME
+
+#ifndef _CRTBLD
+/*
+ * This is an internal C runtime header file. It is used when building
+ * the C runtimes only. It is not to be used as a public header file.
+ */
+#error ERROR: Use of C runtime library internal header file.
+#endif /* _CRTBLD */
+
+#if defined (_SYSCRT) && defined (_WIN64)
+#define _USE_OLD_STDCPP 1
+#endif /* defined (_SYSCRT) && defined (_WIN64) */
+
+#if !defined (UNALIGNED)
+#if defined (_M_IA64) || defined (_M_AMD64)
+#define UNALIGNED __unaligned
+#else /* defined (_M_IA64) || defined (_M_AMD64) */
+#define UNALIGNED
+#endif /* defined (_M_IA64) || defined (_M_AMD64) */
+#endif /* !defined (UNALIGNED) */
+
+#ifdef _M_IX86
+/*
+ * 386/486
+ */
+#define REG1 register
+#define REG2 register
+#define REG3 register
+#define REG4
+#define REG5
+#define REG6
+#define REG7
+#define REG8
+#define REG9
+
+#elif defined (_M_IA64) || defined (_M_AMD64)
+/*
+ * IA64
+ */
+#define REG1 register
+#define REG2 register
+#define REG3 register
+#define REG4 register
+#define REG5 register
+#define REG6 register
+#define REG7 register
+#define REG8 register
+#define REG9 register
+
+#else /* defined (_M_IA64) || defined (_M_AMD64) */
+
+#pragma message ("Machine register set not defined")
+
+/*
+ * Unknown machine
+ */
+
+#define REG1
+#define REG2
+#define REG3
+#define REG4
+#define REG5
+#define REG6
+#define REG7
+#define REG8
+#define REG9
+
+#endif /* defined (_M_IA64) || defined (_M_AMD64) */
+
+/*
+ * Are the macro definitions below still needed in this file?
+ */
+
+#endif /* _INC_CRUNTIME */
diff --git a/src/pal/src/safecrt/input.inl b/src/pal/src/safecrt/input.inl
new file mode 100644
index 0000000000..eaad174ff5
--- /dev/null
+++ b/src/pal/src/safecrt/input.inl
@@ -0,0 +1,1314 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*input.c - C formatted input, used by scanf, etc.
+*
+
+*
+*Purpose:
+* defines _input() to do formatted input; called from scanf(),
+* etc. functions. This module defines _cscanf() instead when
+* CPRFLAG is defined. The file cscanf.c defines that symbol
+* and then includes this file in order to implement _cscanf().
+*
+*Note:
+* this file is included in safecrt.lib build directly, plese refer
+* to safecrt_[w]input_s.c
+*
+*******************************************************************************/
+
+
+#define ALLOW_RANGE /* enable "%[a-z]"-style scansets */
+
+
+/* temporary work-around for compiler without 64-bit support */
+
+#ifndef _INTEGRAL_MAX_BITS
+#define _INTEGRAL_MAX_BITS 64
+#endif /* _INTEGRAL_MAX_BITS */
+
+// typedef __int64_t __int64;
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#define UNALIGNED
+
+#define _BEGIN_SECURE_CRT_DEPRECATION_DISABLE
+#define _END_SECURE_CRT_DEPRECATION_DISABLE
+
+#define _CVTBUFSIZE (309+40) /* # of digits in max. dp value + slop */
+
+//#include <cruntime.h>
+//#include <stdio.h>
+//#include <ctype.h>
+//#include <cvt.h>
+//#include <conio.h>
+//#include <stdarg.h>
+//#include <string.h>
+//#include <internal.h>
+//#include <fltintrn.h>
+//#include <malloc.h>
+//#include <locale.h>
+//#include <mtdll.h>
+//#include <stdlib.h>
+//#include <setlocal.h>
+//#include <dbgint.h>
+
+//#ifndef _INC_INTERNAL_SAFECRT
+//#include <internal_securecrt.h>
+//#endif /* _INC_INTERNAL_SAFECRT */
+
+//#ifdef _MBCS
+//#undef _MBCS
+//#endif /* _MBCS */
+//#include <tchar.h>
+
+#define _MBTOWC(x,y,z) _minimal_chartowchar( x, y )
+
+#define _istspace(x) isspace((unsigned char)x)
+
+#define _malloc_crt PAL_malloc
+#define _realloc_crt PAL_realloc
+#define _free_crt PAL_free
+
+#define _FASSIGN(flag, argument, number, dec_point, locale) _safecrt_fassign((flag), (argument), (number))
+#define _WFASSIGN(flag, argument, number, dec_point, locale) _safecrt_wfassign((flag), (argument), (number))
+
+#if defined (UNICODE)
+#define ALLOC_TABLE 1
+#else /* defined (UNICODE) */
+#define ALLOC_TABLE 0
+#endif /* defined (UNICODE) */
+
+#define HEXTODEC(chr) _hextodec(chr)
+
+#define LEFT_BRACKET ('[' | ('a' - 'A')) /* 'lowercase' version */
+
+static int __cdecl _hextodec(_TCHAR);
+#ifdef CPRFLAG
+
+#define INC() (++charcount, _inc())
+#define UN_INC(chr) (--charcount, _un_inc(chr))
+#define EAT_WHITE() _whiteout(&charcount)
+
+static int __cdecl _inc(void);
+static void __cdecl _un_inc(int);
+static int __cdecl _whiteout(int *);
+
+#else /* CPRFLAG */
+
+#define INC() (++charcount, _inc(stream))
+#define UN_INC(chr) (--charcount, _un_inc(chr, stream))
+#define EAT_WHITE() _whiteout(&charcount, stream)
+
+static int __cdecl _inc(miniFILE *);
+static void __cdecl _un_inc(int, miniFILE *);
+static int __cdecl _whiteout(int *, miniFILE *);
+
+#endif /* CPRFLAG */
+
+#ifndef _UNICODE
+#define _ISDIGIT(chr) isdigit((unsigned char)chr)
+#define _ISXDIGIT(chr) isxdigit((unsigned char)chr)
+#else /* _UNICODE */
+#define _ISDIGIT(chr) ( !(chr & 0xff00) && isdigit( ((chr) & 0x00ff) ) )
+#define _ISXDIGIT(chr) ( !(chr & 0xff00) && isxdigit( ((chr) & 0x00ff) ) )
+#endif /* _UNICODE */
+
+#define MUL10(x) ( (((x)<<2) + (x))<<1 )
+
+
+#define LONGLONG_IS_INT64 1 /* 1 means long long is same as int64
+ 0 means long long is same as long */
+
+/***
+* int __check_float_string(size_t,size_t *, _TCHAR**, _TCHAR*, int*)
+*
+* Purpose:
+* Check if there is enough space insert onemore character in the given
+* block, if not then allocate more memory.
+*
+* Return:
+* FALSE if more memory needed and the reallocation failed.
+*
+*******************************************************************************/
+
+static int __check_float_string(size_t nFloatStrUsed,
+ size_t *pnFloatStrSz,
+ _TCHAR **pFloatStr,
+ _TCHAR *floatstring,
+ int *pmalloc_FloatStrFlag)
+{
+ void *tmpPointer;
+ _ASSERTE(nFloatStrUsed<=(*pnFloatStrSz));
+ if (nFloatStrUsed==(*pnFloatStrSz))
+ {
+ size_t newSize;
+
+ // Will (*pnFloatStrSz) * 2 * sizeof(_TCHAR) overflow?
+ if ( *pnFloatStrSz > (SIZE_T_MAX / 2 / sizeof(_TCHAR)))
+ {
+ return FALSE;
+ }
+
+ newSize = *pnFloatStrSz * 2 * sizeof(_TCHAR);
+
+ if ((*pFloatStr)==floatstring)
+ {
+ if (((*pFloatStr)=(_TCHAR *)_malloc_crt(newSize))==NULL)
+ {
+ return FALSE;
+ }
+
+ (*pmalloc_FloatStrFlag)=1;
+
+ memcpy((*pFloatStr),floatstring,(*pnFloatStrSz)*sizeof(_TCHAR));
+ (*pnFloatStrSz)*=2;
+ }
+ else
+ {
+ if ((tmpPointer=(_TCHAR *)_realloc_crt((*pFloatStr), newSize))==NULL)
+ {
+ return FALSE;
+ }
+ (*pFloatStr)=(_TCHAR *)(tmpPointer);
+ (*pnFloatStrSz)*=2;
+ }
+ }
+ return TRUE;
+}
+
+
+#define ASCII 32 /* # of bytes needed to hold 256 bits */
+
+#define SCAN_SHORT 0 /* also for FLOAT */
+#define SCAN_LONG 1 /* also for DOUBLE */
+#define SCAN_L_DOUBLE 2 /* only for LONG DOUBLE */
+
+#define SCAN_NEAR 0
+#define SCAN_FAR 1
+
+#ifndef _UNICODE
+#define TABLESIZE ASCII
+#else /* _UNICODE */
+#define TABLESIZE (ASCII * 256)
+#endif /* _UNICODE */
+
+
+/***
+*int _input(stream, format, arglist), static int input(format, arglist)
+*
+*Purpose:
+* get input items (data items or literal matches) from the input stream
+* and assign them if appropriate to the items thru the arglist. this
+* function is intended for internal library use only, not for the user
+*
+* The _input entry point is for the normal scanf() functions
+* The input entry point is used when compiling for _cscanf() [CPRFLAF
+* defined] and is a static function called only by _cscanf() -- reads from
+* console.
+*
+* This code also defines _input_s, which works differently for %c, %s & %[.
+* For these, _input_s first picks up the next argument from the variable
+* argument list & uses it as the maximum size of the character array pointed
+* to by the next argument in the list.
+*
+*Entry:
+* FILE *stream - file to read from
+* char *format - format string to determine the data to read
+* arglist - list of pointer to data items
+*
+*Exit:
+* returns number of items assigned and fills in data items
+* returns EOF if error or EOF found on stream before 1st data item matched
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+ #define _INTRN_LOCALE_CONV( x ) localeconv()
+
+#ifndef _UNICODE
+ int __cdecl __tinput_s (miniFILE* stream, const _TUCHAR* format, va_list arglist)
+#else
+ int __cdecl __twinput_s (miniFILE* stream, const _TUCHAR* format, va_list arglist)
+#endif /* _UNICODE */
+{
+ _TCHAR floatstring[_CVTBUFSIZE + 1];
+ _TCHAR *pFloatStr=floatstring;
+ size_t nFloatStrUsed=0;
+ size_t nFloatStrSz=sizeof(floatstring)/sizeof(floatstring[0]);
+ int malloc_FloatStrFlag=0;
+
+ unsigned long number; /* temp hold-value */
+#if ALLOC_TABLE
+ char *table = NULL; /* which chars allowed for %[] */
+ int malloc_flag = 0; /* is "table" allocated on the heap? */
+#else /* ALLOC_TABLE */
+ char AsciiTable[TABLESIZE];
+ char *table = AsciiTable;
+#endif /* ALLOC_TABLE */
+
+#if _INTEGRAL_MAX_BITS >= 64
+ uint64_t num64 = 0LL; /* temp for 64-bit integers */
+#endif /* _INTEGRAL_MAX_BITS >= 64 */
+ void *pointer=NULL; /* points to user data receptacle */
+ void *start; /* indicate non-empty string */
+
+
+#ifndef _UNICODE
+ wchar_t wctemp=L'\0';
+#endif /* _UNICODE */
+ _TUCHAR *scanptr; /* for building "table" data */
+ int ch = 0;
+ int charcount; /* total number of chars read */
+ int comchr; /* holds designator type */
+ int count; /* return value. # of assignments */
+
+ int started; /* indicate good number */
+ int width; /* width of field */
+ int widthset; /* user has specified width */
+#ifdef _SECURE_SCANF
+ size_t array_width = 0;
+ size_t original_array_width = 0;
+ int enomem = 0;
+ int format_error = FALSE;
+#endif /* _SECURE_SCANF */
+
+/* Neither coerceshort nor farone are need for the 386 */
+
+
+ char done_flag; /* general purpose loop monitor */
+ char longone; /* 0 = SHORT, 1 = LONG, 2 = L_DOUBLE */
+#if _INTEGRAL_MAX_BITS >= 64
+ int integer64; /* 1 for 64-bit integer, 0 otherwise */
+#endif /* _INTEGRAL_MAX_BITS >= 64 */
+ signed char widechar; /* -1 = char, 0 = ????, 1 = wchar_t */
+ char reject; /* %[^ABC] instead of %[ABC] */
+ char negative; /* flag for '-' detected */
+ char suppress; /* don't assign anything */
+ char match; /* flag: !0 if any fields matched */
+ va_list arglistsave; /* save arglist value */
+
+ char fl_wchar_arg; /* flags wide char/string argument */
+
+ _TCHAR decimal;
+
+
+ _TUCHAR rngch;
+ _TUCHAR last;
+ _TUCHAR prevchar;
+ _TCHAR tch;
+
+ _VALIDATE_RETURN( (format != NULL), EINVAL, EOF);
+
+#ifndef CPRFLAG
+ _VALIDATE_RETURN( (stream != NULL), EINVAL, EOF);
+#endif /* CPRFLAG */
+
+ /*
+ count = # fields assigned
+ charcount = # chars read
+ match = flag indicating if any fields were matched
+
+ [Note that we need both count and match. For example, a field
+ may match a format but have assignments suppressed. In this case,
+ match will get set, but 'count' will still equal 0. We need to
+ distinguish 'match vs no-match' when terminating due to EOF.]
+ */
+
+ count = charcount = match = 0;
+
+ while (*format) {
+
+ if (_istspace((_TUCHAR)*format)) {
+
+ UN_INC(EAT_WHITE()); /* put first non-space char back */
+
+ do {
+ tch = *++format;
+ } while (_istspace((_TUCHAR)tch));
+
+ continue;
+
+ }
+
+ if (_T('%') == *format) {
+
+ number = 0;
+ prevchar = 0;
+ width = widthset = started = 0;
+#ifdef _SECURE_SCANF
+ original_array_width = array_width = 0;
+ enomem = 0;
+#endif /* _SECURE_SCANF */
+ fl_wchar_arg = done_flag = suppress = negative = reject = 0;
+ widechar = 0;
+
+ longone = 1;
+
+#if _INTEGRAL_MAX_BITS >= 64
+ integer64 = 0;
+#endif /* _INTEGRAL_MAX_BITS >= 64 */
+
+ while (!done_flag) {
+
+ comchr = *++format;
+ if (_ISDIGIT((_TUCHAR)comchr)) {
+ ++widthset;
+ width = MUL10(width) + (comchr - _T('0'));
+ } else
+ switch (comchr) {
+ case _T('F') :
+ case _T('N') : /* no way to push NEAR in large model */
+ break; /* NEAR is default in small model */
+ case _T('h') :
+ /* set longone to 0 */
+ --longone;
+ --widechar; /* set widechar = -1 */
+ break;
+
+#if _INTEGRAL_MAX_BITS >= 64
+ case _T('I'):
+ if ( (*(format + 1) == _T('6')) &&
+ (*(format + 2) == _T('4')) )
+ {
+ format += 2;
+ ++integer64;
+ num64 = 0;
+ break;
+ }
+ else if ( (*(format + 1) == _T('3')) &&
+ (*(format + 2) == _T('2')) )
+ {
+ format += 2;
+ break;
+ }
+ else if ( (*(format + 1) == _T('d')) ||
+ (*(format + 1) == _T('i')) ||
+ (*(format + 1) == _T('o')) ||
+ (*(format + 1) == _T('x')) ||
+ (*(format + 1) == _T('X')) )
+ {
+ if (sizeof(void*) == sizeof(__int64))
+ {
+ ++integer64;
+ num64 = 0;
+ }
+ break;
+ }
+ if (sizeof(void*) == sizeof(__int64))
+ {
+ ++integer64;
+ num64 = 0;
+ }
+ goto DEFAULT_LABEL;
+#endif /* _INTEGRAL_MAX_BITS >= 64 */
+
+ case _T('L') :
+ /* ++longone; */
+ ++longone;
+ break;
+
+ case _T('q'):
+ ++integer64;
+ num64 = 0;
+ break;
+
+ case _T('l') :
+ if (*(format + 1) == _T('l'))
+ {
+ ++format;
+#ifdef LONGLONG_IS_INT64
+ ++integer64;
+ num64 = 0;
+ break;
+#else /* LONGLONG_IS_INT64 */
+ ++longone;
+ /* NOBREAK */
+#endif /* LONGLONG_IS_INT64 */
+ }
+ else
+ {
+ ++longone;
+ /* NOBREAK */
+ }
+ case _T('w') :
+ ++widechar; /* set widechar = 1 */
+ break;
+
+ case _T('*') :
+ ++suppress;
+ break;
+
+ default:
+DEFAULT_LABEL:
+ ++done_flag;
+ break;
+ }
+ }
+
+ if (!suppress) {
+ va_copy(arglistsave, arglist);
+ pointer = va_arg(arglist,void *);
+ } else {
+ pointer = NULL; // doesn't matter what value we use here - we're only using it as a flag
+ }
+
+ done_flag = 0;
+
+ if (!widechar) { /* use case if not explicitly specified */
+ if ((*format == _T('S')) || (*format == _T('C')))
+#ifdef _UNICODE
+ --widechar;
+ else
+ ++widechar;
+#else /* _UNICODE */
+ ++widechar;
+ else
+ --widechar;
+#endif /* _UNICODE */
+ }
+
+ /* switch to lowercase to allow %E,%G, and to
+ keep the switch table small */
+
+ comchr = *format | (_T('a') - _T('A'));
+
+ if (_T('n') != comchr)
+ {
+ if (_T('c') != comchr && LEFT_BRACKET != comchr)
+ ch = EAT_WHITE();
+ else
+ ch = INC();
+ }
+
+ if (_T('n') != comchr)
+ {
+ if (_TEOF == ch)
+ goto error_return;
+ }
+
+ if (!widthset || width) {
+
+#ifdef _SECURE_SCANF
+ if(!suppress && (comchr == _T('c') || comchr == _T('s') || comchr == LEFT_BRACKET)) {
+
+ va_copy(arglist, arglistsave);
+
+ /* Reinitialize pointer to point to the array to which we write the input */
+ pointer = va_arg(arglist, void*);
+
+ va_copy(arglistsave, arglist);
+
+ /* Get the next argument - size of the array in characters */
+#ifdef _WIN64
+ original_array_width = array_width = (size_t)(va_arg(arglist, unsigned int));
+#else /* _WIN64 */
+ original_array_width = array_width = va_arg(arglist, size_t);
+#endif /* _WIN64 */
+
+ if(array_width < 1) {
+ if (widechar > 0)
+ *(wchar_t UNALIGNED *)pointer = L'\0';
+ else
+ *(char *)pointer = '\0';
+
+ errno = ENOMEM;
+
+ goto error_return;
+ }
+ }
+#endif /* _SECURE_SCANF */
+ switch(comchr) {
+
+ case _T('c'):
+ /* case _T('C'): */
+ if (!widthset) {
+ ++widthset;
+ ++width;
+ }
+ if (widechar > 0)
+ fl_wchar_arg++;
+ goto scanit;
+
+
+ case _T('s'):
+ /* case _T('S'): */
+ if(widechar > 0)
+ fl_wchar_arg++;
+ goto scanit;
+
+
+ case LEFT_BRACKET : /* scanset */
+ if (widechar>0)
+ fl_wchar_arg++;
+ scanptr = (_TUCHAR *)(++format);
+
+ if (_T('^') == *scanptr) {
+ ++scanptr;
+ --reject; /* set reject to 255 */
+ }
+
+ /* Allocate "table" on first %[] spec */
+#if ALLOC_TABLE
+ if (table == NULL) {
+ table = (char*)_malloc_crt(TABLESIZE);
+ if ( table == NULL)
+ goto error_return;
+ malloc_flag = 1;
+ }
+#endif /* ALLOC_TABLE */
+ memset(table, 0, TABLESIZE);
+
+
+ if (LEFT_BRACKET == comchr)
+ if (_T(']') == *scanptr) {
+ prevchar = _T(']');
+ ++scanptr;
+
+ table[ _T(']') >> 3] = 1 << (_T(']') & 7);
+
+ }
+
+ while (_T(']') != *scanptr) {
+
+ rngch = *scanptr++;
+
+ if (_T('-') != rngch ||
+ !prevchar || /* first char */
+ _T(']') == *scanptr) /* last char */
+
+ table[(prevchar = rngch) >> 3] |= 1 << (rngch & 7);
+
+ else { /* handle a-z type set */
+
+ rngch = *scanptr++; /* get end of range */
+
+ if (prevchar < rngch) /* %[a-z] */
+ last = rngch;
+ else { /* %[z-a] */
+ last = prevchar;
+ prevchar = rngch;
+ }
+ for (rngch = prevchar; rngch <= last; ++rngch)
+ table[rngch >> 3] |= 1 << (rngch & 7);
+
+ prevchar = 0;
+
+ }
+ }
+
+
+ if (!*scanptr)
+ goto error_return; /* trunc'd format string */
+
+ /* scanset completed. Now read string */
+
+ if (LEFT_BRACKET == comchr)
+ format = scanptr;
+
+scanit:
+ start = pointer;
+
+ /*
+ * execute the format directive. that is, scan input
+ * characters until the directive is fulfilled, eof
+ * is reached, or a non-matching character is
+ * encountered.
+ *
+ * it is important not to get the next character
+ * unless that character needs to be tested! other-
+ * wise, reads from line-buffered devices (e.g.,
+ * scanf()) would require an extra, spurious, newline
+ * if the first newline completes the current format
+ * directive.
+ */
+ UN_INC(ch);
+
+#ifdef _SECURE_SCANF
+ /* One element is needed for '\0' for %s & %[ */
+ if(comchr != _T('c')) {
+ --array_width;
+ }
+#endif /* _SECURE_SCANF */
+ while ( !widthset || width-- ) {
+
+ ch = INC();
+ if (
+#ifndef CPRFLAG
+ (_TEOF != ch) &&
+#endif /* CPRFLAG */
+ // char conditions
+ ( ( comchr == _T('c')) ||
+ // string conditions !isspace()
+ ( ( comchr == _T('s') &&
+ (!(ch >= _T('\t') && ch <= _T('\r')) &&
+ ch != _T(' ')))) ||
+ // BRACKET conditions
+ ( (comchr == LEFT_BRACKET) &&
+ ((table[ch >> 3] ^ reject) & (1 << (ch & 7)))
+ )
+ )
+ )
+ {
+ if (!suppress) {
+#ifdef _SECURE_SCANF
+ if(!array_width) {
+ /* We have exhausted the user's buffer */
+
+ enomem = 1;
+ break;
+ }
+#endif /* _SECURE_SCANF */
+#ifndef _UNICODE
+ if (fl_wchar_arg) {
+ wctemp = L'?';
+ char temp[2];
+ temp[0] = (char) ch;
+#if 0 // we are not supporting multibyte input strings
+ if (isleadbyte((unsigned char)ch))
+ {
+ temp[1] = (char) INC();
+ }
+#endif /* 0 */
+ _MBTOWC(&wctemp, temp, MB_CUR_MAX);
+ *(wchar_t UNALIGNED *)pointer = wctemp;
+ /* just copy L'?' if mbtowc fails, errno is set by mbtowc */
+ pointer = (wchar_t *)pointer + 1;
+#ifdef _SECURE_SCANF
+ --array_width;
+#endif /* _SECURE_SCANF */
+ } else
+#else /* _UNICODE */
+ if (fl_wchar_arg) {
+ *(wchar_t UNALIGNED *)pointer = ch;
+ pointer = (wchar_t *)pointer + 1;
+#ifdef _SECURE_SCANF
+ --array_width;
+#endif /* _SECURE_SCANF */
+ } else
+#endif /* _UNICODE */
+ {
+#ifndef _UNICODE
+ *(char *)pointer = (char)ch;
+ pointer = (char *)pointer + 1;
+#ifdef _SECURE_SCANF
+ --array_width;
+#endif /* _SECURE_SCANF */
+#else /* _UNICODE */
+ int temp = 0;
+#ifndef _SECURE_SCANF
+ /* convert wide to multibyte */
+ if (_ERRCHECK_EINVAL_ERANGE(wctomb_s(&temp, (char *)pointer, MB_LEN_MAX, ch)) == 0)
+ {
+ /* do nothing if wctomb fails, errno will be set to EILSEQ */
+ pointer = (char *)pointer + temp;
+ }
+#else /* _SECURE_SCANF */
+ /* convert wide to multibyte */
+ if (array_width >= ((size_t)MB_CUR_MAX))
+ {
+_BEGIN_SECURE_CRT_DEPRECATION_DISABLE
+ temp = wctomb((char *)pointer, ch);
+_END_SECURE_CRT_DEPRECATION_DISABLE
+ }
+ else
+ {
+ char tmpbuf[MB_LEN_MAX];
+_BEGIN_SECURE_CRT_DEPRECATION_DISABLE
+ temp = wctomb(tmpbuf, ch);
+_END_SECURE_CRT_DEPRECATION_DISABLE
+ if (temp > 0 && ((size_t)temp) > array_width)
+ {
+ /* We have exhausted the user's buffer */
+ enomem = 1;
+ break;
+ }
+ memcpy(pointer, tmpbuf, temp);
+ }
+ if (temp > 0)
+ {
+ /* do nothing if wctomb fails, errno will be set to EILSEQ */
+ pointer = (char *)pointer + temp;
+ array_width -= temp;
+ }
+#endif /* _SECURE_SCANF */
+#endif /* _UNICODE */
+ }
+ } /* suppress */
+ else {
+ /* just indicate a match */
+ start = (_TCHAR *)start + 1;
+ }
+ }
+ else {
+ UN_INC(ch);
+ break;
+ }
+ }
+
+ /* make sure something has been matched and, if
+ assignment is not suppressed, null-terminate
+ output string if comchr != c */
+
+#ifdef _SECURE_SCANF
+ if(enomem) {
+ errno = ENOMEM;
+ /* In case of error, blank out the input buffer */
+ if (fl_wchar_arg)
+ {
+ _RESET_STRING(((wchar_t UNALIGNED *)start), original_array_width);
+ }
+ else
+ {
+ _RESET_STRING(((char *)start), original_array_width);
+ }
+
+ goto error_return;
+ }
+#endif /* _SECURE_SCANF */
+
+ if (start != pointer) {
+ if (!suppress) {
+ ++count;
+ if ('c' != comchr) /* null-terminate strings */
+ {
+ if (fl_wchar_arg)
+ {
+ *(wchar_t UNALIGNED *)pointer = L'\0';
+#ifdef _SECURE_SCANF
+ _FILL_STRING(((wchar_t UNALIGNED *)start), original_array_width,
+ ((wchar_t UNALIGNED *)pointer - (wchar_t UNALIGNED *)start + 1))
+#endif /* _SECURE_SCANF */
+ }
+ else
+ {
+ *(char *)pointer = '\0';
+#ifdef _SECURE_SCANF
+ _FILL_STRING(((char *)start), original_array_width,
+ ((char *)pointer - (char *)start + 1))
+#endif /* _SECURE_SCANF */
+ }
+ }
+ }
+ else
+ {
+ // supress set, do nothing
+ }
+ }
+ else
+ goto error_return;
+
+ break;
+
+ case _T('i') : /* could be d, o, or x */
+
+ comchr = _T('d'); /* use as default */
+
+ case _T('x'):
+
+ if (_T('-') == ch) {
+ ++negative;
+
+ goto x_incwidth;
+
+ } else if (_T('+') == ch) {
+x_incwidth:
+ if (!--width && widthset)
+ ++done_flag;
+ else
+ ch = INC();
+ }
+
+ if (_T('0') == ch) {
+
+ if (_T('x') == (_TCHAR)(ch = INC()) || _T('X') == (_TCHAR)ch) {
+ ch = INC();
+ if (widthset) {
+ width -= 2;
+ if (width < 1)
+ ++done_flag;
+ }
+ comchr = _T('x');
+ } else {
+ ++started;
+ if (_T('x') != comchr) {
+ if (widthset && !--width)
+ ++done_flag;
+ comchr = _T('o');
+ }
+ else {
+ /* scanning a hex number that starts */
+ /* with a 0. push back the character */
+ /* currently in ch and restore the 0 */
+ UN_INC(ch);
+ ch = _T('0');
+ }
+ }
+ }
+ goto getnum;
+
+ /* NOTREACHED */
+
+ case _T('p') :
+ /* force %hp to be treated as %p */
+ longone = 1;
+#ifdef _WIN64
+ /* force %p to be 64 bit in WIN64 */
+ ++integer64;
+ num64 = 0;
+#endif /* _WIN64 */
+ case _T('o') :
+ case _T('u') :
+ case _T('d') :
+
+ if (_T('-') == ch) {
+ ++negative;
+
+ goto d_incwidth;
+
+ } else if (_T('+') == ch) {
+d_incwidth:
+ if (!--width && widthset)
+ ++done_flag;
+ else
+ ch = INC();
+ }
+
+getnum:
+#if _INTEGRAL_MAX_BITS >= 64
+ if ( integer64 ) {
+
+ while (!done_flag) {
+
+ if (_T('x') == comchr || _T('p') == comchr)
+
+ if (_ISXDIGIT(ch)) {
+ num64 <<= 4;
+ ch = _hextodec(ch);
+ }
+ else
+ ++done_flag;
+
+ else if (_ISDIGIT(ch))
+
+ if (_T('o') == comchr)
+ if (_T('8') > ch)
+ num64 <<= 3;
+ else {
+ ++done_flag;
+ }
+ else /* _T('d') == comchr */
+ num64 = MUL10(num64);
+
+ else
+ ++done_flag;
+
+ if (!done_flag) {
+ ++started;
+ num64 += ch - _T('0');
+
+ if (widthset && !--width)
+ ++done_flag;
+ else
+ ch = INC();
+ } else
+ UN_INC(ch);
+
+ } /* end of WHILE loop */
+
+ if (negative)
+ num64 = (uint64_t )(-(__int64)num64);
+ }
+ else {
+#endif /* _INTEGRAL_MAX_BITS >= 64 */
+ while (!done_flag) {
+
+ if (_T('x') == comchr || _T('p') == comchr)
+
+ if (_ISXDIGIT(ch)) {
+ number = (number << 4);
+ ch = _hextodec(ch);
+ }
+ else
+ ++done_flag;
+
+ else if (_ISDIGIT(ch))
+
+ if (_T('o') == comchr)
+ if (_T('8') > ch)
+ number = (number << 3);
+ else {
+ ++done_flag;
+ }
+ else /* _T('d') == comchr */
+ number = MUL10(number);
+
+ else
+ ++done_flag;
+
+ if (!done_flag) {
+ ++started;
+ number += ch - _T('0');
+
+ if (widthset && !--width)
+ ++done_flag;
+ else
+ ch = INC();
+ } else
+ UN_INC(ch);
+
+ } /* end of WHILE loop */
+
+ if (negative)
+ number = (unsigned long)(-(long)number);
+#if _INTEGRAL_MAX_BITS >= 64
+ }
+#endif /* _INTEGRAL_MAX_BITS >= 64 */
+ if (_T('F')==comchr) /* expected ':' in long pointer */
+ started = 0;
+
+ if (started)
+ if (!suppress) {
+
+ ++count;
+assign_num:
+#if _INTEGRAL_MAX_BITS >= 64
+ if ( integer64 )
+ *(__int64 UNALIGNED *)pointer = ( uint64_t )num64;
+ else
+#endif /* _INTEGRAL_MAX_BITS >= 64 */
+ if (longone)
+ *(int UNALIGNED *)pointer = (unsigned int)number;
+ else
+ *(short UNALIGNED *)pointer = (unsigned short)number;
+
+ } else /*NULL*/;
+ else
+ goto error_return;
+
+ break;
+
+ case _T('n') : /* char count, don't inc return value */
+ number = charcount;
+ if(!suppress)
+ goto assign_num; /* found in number code above */
+ break;
+
+
+ case _T('e') :
+ /* case _T('E') : */
+ case _T('f') :
+ case _T('g') : /* scan a float */
+ /* case _T('G') : */
+ nFloatStrUsed=0;
+
+ if (_T('-') == ch) {
+ pFloatStr[nFloatStrUsed++] = _T('-');
+ goto f_incwidth;
+
+ } else if (_T('+') == ch) {
+f_incwidth:
+ --width;
+ ch = INC();
+ }
+
+ if (!widthset) /* must watch width */
+ width = -1;
+
+
+ /* now get integral part */
+
+ while (_ISDIGIT(ch) && width--) {
+ ++started;
+ pFloatStr[nFloatStrUsed++] = (char)ch;
+ if (__check_float_string(nFloatStrUsed,
+ &nFloatStrSz,
+ &pFloatStr,
+ floatstring,
+ &malloc_FloatStrFlag
+ )==FALSE) {
+ goto error_return;
+ }
+ ch = INC();
+ }
+
+#ifdef _UNICODE
+ /* convert decimal point to wide-char */
+ /* if mbtowc fails (should never happen), we use L'.' */
+ decimal = L'.';
+ _MBTOWC(&decimal, _INTRN_LOCALE_CONV(_loc_update)->decimal_point, MB_CUR_MAX);
+#else /* _UNICODE */
+
+ decimal=*((_INTRN_LOCALE_CONV(_loc_update))->decimal_point);
+#endif /* _UNICODE */
+
+ /* now check for decimal */
+ if (decimal == (char)ch && width--) {
+ ch = INC();
+ pFloatStr[nFloatStrUsed++] = decimal;
+ if (__check_float_string(nFloatStrUsed,
+ &nFloatStrSz,
+ &pFloatStr,
+ floatstring,
+ &malloc_FloatStrFlag
+ )==FALSE) {
+ goto error_return;
+ }
+
+ while (_ISDIGIT(ch) && width--) {
+ ++started;
+ pFloatStr[nFloatStrUsed++] = (_TCHAR)ch;
+ if (__check_float_string(nFloatStrUsed,
+ &nFloatStrSz,
+ &pFloatStr,
+ floatstring,
+ &malloc_FloatStrFlag
+ )==FALSE) {
+ goto error_return;
+ }
+ ch = INC();
+ }
+ }
+
+ /* now check for exponent */
+
+ if (started && (_T('e') == ch || _T('E') == ch) && width--) {
+ pFloatStr[nFloatStrUsed++] = _T('e');
+ if (__check_float_string(nFloatStrUsed,
+ &nFloatStrSz,
+ &pFloatStr,
+ floatstring,
+ &malloc_FloatStrFlag
+ )==FALSE) {
+ goto error_return;
+ }
+
+ if (_T('-') == (ch = INC())) {
+
+ pFloatStr[nFloatStrUsed++] = _T('-');
+ if (__check_float_string(nFloatStrUsed,
+ &nFloatStrSz,
+ &pFloatStr,
+ floatstring,
+ &malloc_FloatStrFlag
+ )==FALSE) {
+ goto error_return;
+ }
+ goto f_incwidth2;
+
+ } else if (_T('+') == ch) {
+f_incwidth2:
+ if (!width--)
+ ++width;
+ else
+ ch = INC();
+ }
+
+
+ while (_ISDIGIT(ch) && width--) {
+ ++started;
+ pFloatStr[nFloatStrUsed++] = (_TCHAR)ch;
+ if (__check_float_string(nFloatStrUsed,
+ &nFloatStrSz,
+ &pFloatStr,
+ floatstring,
+ &malloc_FloatStrFlag
+ )==FALSE) {
+ goto error_return;
+ }
+ ch = INC();
+ }
+
+ }
+
+ UN_INC(ch);
+
+ if (started)
+ if (!suppress) {
+ ++count;
+ pFloatStr[nFloatStrUsed]= _T('\0');
+#ifdef _UNICODE
+ _WFASSIGN( longone-1, pointer, pFloatStr, (char)decimal, _loc_update.GetLocaleT());
+#else /* _UNICODE */
+ _FASSIGN( longone-1, pointer, pFloatStr, (char)decimal, _loc_update.GetLocaleT());
+#endif /* _UNICODE */
+ } else /*NULL */;
+ else
+ goto error_return;
+
+ break;
+
+
+ default: /* either found '%' or something else */
+
+ if ((int)*format != (int)ch) {
+ UN_INC(ch);
+#ifdef _SECURE_SCANF
+ /* error_return ASSERT's if format_error is true */
+ format_error = TRUE;
+#endif /* _SECURE_SCANF */
+ goto error_return;
+ }
+ else
+ match--; /* % found, compensate for inc below */
+
+ if (!suppress)
+ va_copy(arglist, arglistsave);
+
+ } /* SWITCH */
+
+ match++; /* matched a format field - set flag */
+
+ } /* WHILE (width) */
+
+ else { /* zero-width field in format string */
+ UN_INC(ch); /* check for input error */
+ goto error_return;
+ }
+
+ ++format; /* skip to next char */
+
+ } else /* ('%' != *format) */
+ {
+
+ if ((int)*format++ != (int)(ch = INC()))
+ {
+ UN_INC(ch);
+ goto error_return;
+ }
+#if 0 // we are not supporting multibyte input strings
+#ifndef _UNICODE
+ if (isleadbyte((unsigned char)ch))
+ {
+ int ch2;
+ if ((int)*format++ != (ch2=INC()))
+ {
+ UN_INC(ch2);
+ UN_INC(ch);
+ goto error_return;
+ }
+
+ --charcount; /* only count as one character read */
+ }
+#endif /* _UNICODE */
+#endif
+ }
+
+#ifndef CPRFLAG
+ if ( (_TEOF == ch) && ((*format != _T('%')) || (*(format + 1) != _T('n'))) )
+ break;
+#endif /* CPRFLAG */
+
+ } /* WHILE (*format) */
+
+error_return:
+#if ALLOC_TABLE
+ if (malloc_flag == 1)
+ {
+ _free_crt(table);
+ }
+#endif /* ALLOC_TABLE */
+ if (malloc_FloatStrFlag == 1)
+ {
+ _free_crt(pFloatStr);
+ }
+
+#ifndef CPRFLAG
+ if (_TEOF == ch)
+ /* If any fields were matched or assigned, return count */
+ return ( (count || match) ? count : EOF);
+ else
+#endif /* CPRFLAG */
+#ifdef _SECURE_SCANF
+ if(format_error == TRUE) {
+ _VALIDATE_RETURN( ("Invalid Input Format" && 0), EINVAL, count);
+ }
+#endif /* _SECURE_SCANF */
+ return count;
+
+}
+
+/* _hextodec() returns a value of 0-15 and expects a char 0-9, a-f, A-F */
+/* _inc() is the one place where we put the actual getc code. */
+/* _whiteout() returns the first non-blank character, as defined by isspace() */
+
+static int __cdecl _hextodec ( _TCHAR chr)
+{
+ return _ISDIGIT(chr) ? chr : (chr & ~(_T('a') - _T('A'))) - _T('A') + 10 + _T('0');
+}
+
+#ifdef CPRFLAG
+
+static int __cdecl _inc(void)
+{
+ return (_gettche_nolock());
+}
+
+static void __cdecl _un_inc(int chr)
+{
+ if (_TEOF != chr) {
+ _ungettch_nolock(chr);
+ }
+}
+
+static int __cdecl _whiteout(REG1 int* counter)
+{
+ REG2 int ch;
+
+ do
+ {
+ ++*counter;
+ ch = _inc();
+
+ if (ch == _TEOF)
+ {
+ break;
+ }
+ }
+ while(_istspace((_TUCHAR)ch));
+ return ch;
+}
+
+#else /* CPRFLAG */
+
+static int __cdecl _inc(miniFILE* fileptr)
+{
+ return (_gettc_nolock(fileptr));
+}
+
+static void __cdecl _un_inc(int chr, miniFILE* fileptr)
+{
+ if (_TEOF != chr) {
+ _ungettc_nolock(chr,fileptr);
+ }
+}
+
+static int __cdecl _whiteout(int* counter, miniFILE* fileptr)
+{
+ int ch;
+
+ do
+ {
+ ++*counter;
+ ch = _inc(fileptr);
+
+ if (ch == _TEOF)
+ {
+ break;
+ }
+ }
+ while(_istspace((_TUCHAR)ch));
+ return ch;
+}
+
+#endif /* CPRFLAG */
diff --git a/src/pal/src/safecrt/internal.h b/src/pal/src/safecrt/internal.h
new file mode 100644
index 0000000000..f4220c2b68
--- /dev/null
+++ b/src/pal/src/safecrt/internal.h
@@ -0,0 +1,1097 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*internal.h - contains declarations of internal routines and variables
+*
+
+*
+*Purpose:
+* Declares routines and variables used internally by the C run-time.
+*
+* [Internal]
+*
+****/
+
+#if _MSC_VER > 1000
+#pragma once
+#endif /* _MSC_VER > 1000 */
+
+#ifndef _INC_INTERNAL
+#define _INC_INTERNAL
+
+#include <crtdefs.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+#include <cruntime.h>
+#include <limits.h>
+
+/*
+ * Conditionally include windows.h to pick up the definition of
+ * CRITICAL_SECTION.
+ */
+#include <windows.h>
+
+#ifdef _MSC_VER
+#pragma pack(push,_CRT_PACKING)
+#endif /* _MSC_VER */
+
+/* Define function types used in several startup sources */
+
+typedef void (__cdecl *_PVFV)(void);
+typedef int (__cdecl *_PIFV)(void);
+typedef void (__cdecl *_PVFI)(int);
+
+#if _MSC_VER >= 1400 && defined(_M_CEE)
+typedef const void* (__clrcall *_PVFVM)(void);
+typedef int (__clrcall *_PIFVM)(void);
+typedef void (__clrcall *_CPVFV)(void);
+#endif /* _MSC_VER >= 1400 && defined(_M_CEE) */
+
+#if defined (_M_CEE_PURE) || (defined (_DLL) && defined (_M_IX86))
+/* Retained for compatibility with VC++ 5.0 and earlier versions */
+_CRTIMP int * __cdecl __p__commode(void);
+#endif /* defined (_M_CEE_PURE) || (defined (_DLL) && defined (_M_IX86)) */
+#if defined (SPECIAL_CRTEXE) && defined (_DLL)
+ extern int _commode;
+#else /* defined (SPECIAL_CRTEXE) && defined (_DLL) */
+#ifndef _M_CEE_PURE
+_CRTIMP extern int _commode;
+#else /* _M_CEE_PURE */
+#define _commode (*__p___commode())
+#endif /* _M_CEE_PURE */
+#endif /* defined (SPECIAL_CRTEXE) && defined (_DLL) */
+
+#define __IOINFO_TM_ANSI 0 /* Regular Text */
+#define __IOINFO_TM_UTF8 1 /* UTF8 Encoded */
+#define __IOINFO_TM_UTF16LE 2 /* UTF16 Little Endian Encoded */
+
+/*
+ * Control structure for lowio file handles
+ */
+typedef struct {
+ intptr_t osfhnd; /* underlying OS file HANDLE */
+ char osfile; /* attributes of file (e.g., open in text mode?) */
+ char pipech; /* one char buffer for handles opened on pipes */
+ int lockinitflag;
+ CRITICAL_SECTION lock;
+#ifndef _SAFECRT_IMPL
+ /* Not used in the safecrt downlevel. We do not define them, so we cannot use them accidentally */
+ char textmode : 7; /* __IOINFO_TM_ANSI or __IOINFO_TM_UTF8 or __IOINFO_TM_UTF16LE */
+ char unicode : 1; /* Was the file opened as unicode? */
+ char pipech2[2]; /* 2 more peak ahead chars for UNICODE mode */
+#endif /* _SAFECRT_IMPL */
+ } ioinfo;
+
+/*
+ * Definition of IOINFO_L2E, the log base 2 of the number of elements in each
+ * array of ioinfo structs.
+ */
+#define IOINFO_L2E 5
+
+/*
+ * Definition of IOINFO_ARRAY_ELTS, the number of elements in ioinfo array
+ */
+#define IOINFO_ARRAY_ELTS (1 << IOINFO_L2E)
+
+/*
+ * Definition of IOINFO_ARRAYS, maximum number of supported ioinfo arrays.
+ */
+#define IOINFO_ARRAYS 64
+
+#define _NHANDLE_ (IOINFO_ARRAYS * IOINFO_ARRAY_ELTS)
+
+#define _TZ_STRINGS_SIZE 64
+
+/*
+ * Access macros for getting at an ioinfo struct and its fields from a
+ * file handle
+ */
+#define _pioinfo(i) ( __pioinfo[(i) >> IOINFO_L2E] + ((i) & (IOINFO_ARRAY_ELTS - \
+ 1)) )
+#define _osfhnd(i) ( _pioinfo(i)->osfhnd )
+
+#define _osfile(i) ( _pioinfo(i)->osfile )
+
+#define _pipech(i) ( _pioinfo(i)->pipech )
+
+#define _pipech2(i) ( _pioinfo(i)->pipech2 )
+
+#define _textmode(i) ( _pioinfo(i)->textmode )
+
+#define _tm_unicode(i) ( _pioinfo(i)->unicode )
+
+/*
+ * Safer versions of the above macros. Currently, only _osfile_safe is
+ * used.
+ */
+#define _pioinfo_safe(i) ( (((i) != -1) && ((i) != -2)) ? _pioinfo(i) : &__badioinfo )
+
+#define _osfhnd_safe(i) ( _pioinfo_safe(i)->osfhnd )
+
+#define _osfile_safe(i) ( _pioinfo_safe(i)->osfile )
+
+#define _pipech_safe(i) ( _pioinfo_safe(i)->pipech )
+
+#define _pipech2_safe(i) ( _pioinfo_safe(i)->pipech2 )
+
+#ifdef _SAFECRT_IMPL
+/* safecrt does not have support for textmode, so we always return __IOINFO_TM_ANSI */
+#define _textmode_safe(i) __IOINFO_TM_ANSI
+#define _tm_unicode_safe(i) 0
+#else /* _SAFECRT_IMPL */
+#define _textmode_safe(i) ( _pioinfo_safe(i)->textmode )
+#define _tm_unicode_safe(i) ( _pioinfo_safe(i)->unicode )
+#endif /* _SAFECRT_IMPL */
+
+#ifndef _M_CEE_PURE
+#ifdef _SAFECRT_IMPL
+/* We need to get this from the downlevel DLL, even when we build safecrt.lib */
+extern __declspec(dllimport) ioinfo __badioinfo;
+extern __declspec(dllimport) ioinfo * __pioinfo[];
+#else /* _SAFECRT_IMPL */
+/*
+ * Special, static ioinfo structure used only for more graceful handling
+ * of a C file handle value of -1 (results from common errors at the stdio
+ * level).
+ */
+extern _CRTIMP ioinfo __badioinfo;
+
+/*
+ * Array of arrays of control structures for lowio files.
+ */
+extern _CRTIMP ioinfo * __pioinfo[];
+#endif /* _SAFECRT_IMPL */
+#endif /* _M_CEE_PURE */
+
+/*
+ * Current number of allocated ioinfo structures (_NHANDLE_ is the upper
+ * limit).
+ */
+extern int _nhandle;
+
+int __cdecl _alloc_osfhnd(void);
+int __cdecl _free_osfhnd(int);
+int __cdecl _set_osfhnd(int, intptr_t);
+
+/*
+ fileno for stdout, stdin & stderr when there is no console
+*/
+#define _NO_CONSOLE_FILENO (intptr_t)-2
+
+
+extern const char __dnames[];
+extern const char __mnames[];
+
+extern int _days[];
+extern int _lpdays[];
+
+extern __time32_t __cdecl __loctotime32_t(int, int, int, int, int, int, int);
+extern __time64_t __cdecl __loctotime64_t(int, int, int, int, int, int, int);
+
+#ifdef _TM_DEFINED
+extern int __cdecl _isindst(__in struct tm * _Time);
+#endif /* _TM_DEFINED */
+
+extern void __cdecl __tzset(void);
+
+extern int __cdecl _validdrive(unsigned);
+
+/*
+ * If we are only interested in years between 1901 and 2099, we could use this:
+ *
+ * #define IS_LEAP_YEAR(y) (y % 4 == 0)
+ */
+
+#define IS_LEAP_YEAR(y) (((y) % 4 == 0 && (y) % 100 != 0) || (y) % 400 == 0)
+
+/*
+ * get the buffer used by gmtime
+ */
+struct tm * __cdecl __getgmtimebuf ();
+
+/*
+ * This variable is in the C start-up; the length must be kept synchronized
+ * It is used by the *cenvarg.c modules
+ */
+
+extern char _acfinfo[]; /* "_C_FILE_INFO=" */
+
+#define CFI_LENGTH 12 /* "_C_FILE_INFO" is 12 bytes long */
+
+
+/*
+ * stdio internals
+ */
+#ifndef _FILE_DEFINED
+struct _iobuf {
+ char *_ptr;
+ int _cnt;
+ char *_base;
+ int _flag;
+ int _file;
+ int _charbuf;
+ int _bufsiz;
+ char *_tmpfname;
+ };
+typedef struct _iobuf FILE;
+#define _FILE_DEFINED
+#endif /* _FILE_DEFINED */
+
+#if !defined (_FILEX_DEFINED) && defined (_WINDOWS_)
+
+/*
+ * Variation of FILE type used for the dynamically allocated portion of
+ * __piob[]. For single thread, _FILEX is the same as FILE. For multithread
+ * models, _FILEX has two fields: the FILE struct and the CRITICAL_SECTION
+ * struct used to serialize access to the FILE.
+ */
+
+typedef struct {
+ FILE f;
+ CRITICAL_SECTION lock;
+ } _FILEX;
+
+
+#define _FILEX_DEFINED
+#endif /* !defined (_FILEX_DEFINED) && defined (_WINDOWS_) */
+
+/*
+ * Number of entries supported in the array pointed to by __piob[]. That is,
+ * the number of stdio-level files which may be open simultaneously. This
+ * is normally set to _NSTREAM_ by the stdio initialization code.
+ */
+extern int _nstream;
+
+/*
+ * Pointer to the array of pointers to FILE/_FILEX structures that are used
+ * to manage stdio-level files.
+ */
+extern void **__piob;
+
+FILE * __cdecl _getstream(void);
+FILE * __cdecl _openfile(__in_z const char * _Filename, __in_z const char * _Mode, __in int _ShFlag, __out FILE * _File);
+FILE * __cdecl _wopenfile(__in_z const wchar_t * _Filename, __in_z const wchar_t * _Mode, __in int _ShFlag, __out FILE * _File);
+void __cdecl _getbuf(__out FILE * _File);
+int __cdecl _filwbuf (__inout FILE * _File);
+int __cdecl _flswbuf(__in int _Ch, __inout FILE * _File);
+void __cdecl _freebuf(__inout FILE * _File);
+int __cdecl _stbuf(__inout FILE * _File);
+void __cdecl _ftbuf(int _Flag, __inout FILE * _File);
+
+#ifdef _SAFECRT_IMPL
+
+int __cdecl _output(__inout FILE * _File, __in_z __format_string const char *_Format, va_list _ArgList);
+int __cdecl _woutput(__inout FILE * _File, __in_z __format_string const wchar_t *_Format, va_list _ArgList);
+int __cdecl _output_s(__inout FILE * _File, __in_z __format_string const char *_Format, va_list _ArgList);
+int __cdecl _output_p(__inout FILE * _File, __in_z __format_string const char *_Format, va_list _ArgList);
+int __cdecl _woutput_s(__inout FILE * _File, __in_z __format_string const wchar_t *_Format, va_list _ArgList);
+int __cdecl _woutput_p(__inout FILE * _File, __in_z __format_string const wchar_t *_Format, va_list _ArgList);
+typedef int (*OUTPUTFN)(FILE *, const char *, va_list);
+typedef int (*WOUTPUTFN)(FILE *, const wchar_t *, va_list);
+
+#else /* _SAFECRT_IMPL */
+
+int __cdecl _output_l(__inout FILE * _File, __in_z __format_string const char *_Format, __in_opt _locale_t _Locale, va_list _ArgList);
+int __cdecl _woutput_l(__inout FILE * _File, __in_z __format_string const wchar_t *_Format, __in_opt _locale_t _Locale, va_list _ArgList);
+int __cdecl _output_s_l(__inout FILE * _File, __in_z __format_string const char *_Format, __in_opt _locale_t _Locale, va_list _ArgList);
+int __cdecl _output_p_l(__inout FILE * _File, __in_z __format_string const char *_Format, __in_opt _locale_t _Locale, va_list _ArgList);
+int __cdecl _woutput_s_l(__inout FILE * _File, __in_z __format_string const wchar_t *_Format, __in_opt _locale_t _Locale, va_list _ArgList);
+int __cdecl _woutput_p_l(__inout FILE * _File, __in_z __format_string const wchar_t *_Format, __in_opt _locale_t _Locale, va_list _ArgList);
+typedef int (*OUTPUTFN)(__inout FILE * _File, const char *, _locale_t, va_list);
+typedef int (*WOUTPUTFN)(__inout FILE * _File, const wchar_t *, _locale_t, va_list);
+
+#endif /* _SAFECRT_IMPL */
+
+#ifdef _SAFECRT_IMPL
+
+int __cdecl _input(__in FILE * _File, __in_z __format_string const unsigned char * _Format, va_list _ArgList);
+int __cdecl _winput(__in FILE * _File, __in_z __format_string const wchar_t * _Format, va_list _ArgList);
+int __cdecl _input_s(__in FILE * _File, __in_z __format_string const unsigned char * _Format, va_list _ArgList);
+int __cdecl _winput_s(__in FILE * _File, __in_z __format_string const wchar_t * _Format, va_list _ArgList);
+typedef int (*INPUTFN)(FILE *, const unsigned char *, va_list);
+typedef int (*WINPUTFN)(FILE *, const wchar_t *, va_list);
+
+#else /* _SAFECRT_IMPL */
+
+int __cdecl _input_l(__inout FILE * _File, __in_z __format_string const unsigned char *, __in_opt _locale_t _Locale, va_list _ArgList);
+int __cdecl _winput_l(__inout FILE * _File, __in_z __format_string const wchar_t *, __in_opt _locale_t _Locale, va_list _ArgList);
+int __cdecl _input_s_l(__inout FILE * _File, __in_z __format_string const unsigned char *, __in_opt _locale_t _Locale, va_list _ArgList);
+int __cdecl _winput_s_l(__inout FILE * _File, __in_z __format_string const wchar_t *, __in_opt _locale_t _Locale, va_list _ArgList);
+typedef int (*INPUTFN)(FILE *, const unsigned char *, _locale_t, va_list);
+typedef int (*WINPUTFN)(FILE *, const wchar_t *, _locale_t, va_list);
+
+#ifdef _UNICODE
+#define TINPUTFN WINPUTFN
+#else /* _UNICODE */
+#define TINPUTFN INPUTFN
+#endif /* _UNICODE */
+
+#endif /* _SAFECRT_IMPL */
+
+int __cdecl _flush(__inout FILE * _File);
+void __cdecl _endstdio(void);
+
+errno_t __cdecl _sopen_helper(__in_z const char * _Filename,
+ __in int _OFlag, __in int _ShFlag, __in int _PMode,
+ __out int * _PFileHandle, int _BSecure);
+errno_t __cdecl _wsopen_helper(__in_z const wchar_t * _Filename,
+ __in int _OFlag, __in int _ShFlag, __in int _PMode,
+ __out int * _PFileHandle, int _BSecure);
+
+#ifndef CRTDLL
+extern int _cflush;
+#endif /* CRTDLL */
+
+extern unsigned int _tempoff;
+
+extern unsigned int _old_pfxlen;
+
+extern int _umaskval; /* the umask value */
+
+extern char _pipech[]; /* pipe lookahead */
+
+extern char _exitflag; /* callable termination flag */
+
+extern int _C_Termination_Done; /* termination done flag */
+
+char * __cdecl _getpath(__in_z const char * _Src, __out_ecount_z(_SizeInChars) char * _Dst, __in size_t _SizeInChars);
+wchar_t * __cdecl _wgetpath(__in_z const wchar_t * _Src, __out_ecount_z(_SizeInWords) wchar_t * _Dst, __in size_t _SizeInWords);
+
+extern int _dowildcard; /* flag to enable argv[] wildcard expansion */
+
+#ifndef _PNH_DEFINED
+typedef int (__cdecl * _PNH)( size_t );
+#define _PNH_DEFINED
+#endif /* _PNH_DEFINED */
+
+#if _MSC_VER >= 1400 && defined(_M_CEE)
+#ifndef __MPNH_DEFINED
+typedef int (__clrcall * __MPNH)( size_t );
+#define __MPNH_DEFINED
+#endif /* __MPNH_DEFINED */
+#endif /* _MSC_VER >= 1400 && defined(_M_CEE) */
+
+
+/* calls the currently installed new handler */
+int __cdecl _callnewh(__in size_t _Size);
+
+extern int _newmode; /* malloc new() handler mode */
+
+/* pointer to initial environment block that is passed to [w]main */
+#ifndef _M_CEE_PURE
+extern _CRTIMP wchar_t **__winitenv;
+extern _CRTIMP char **__initenv;
+#endif /* _M_CEE_PURE */
+
+/* _calloca helper */
+#define _calloca(count, size) ((count<=0 || size<=0 || ((((size_t)_HEAP_MAXREQ) / ((size_t)count)) < ((size_t)size)))? NULL : _malloca(count * size))
+
+/* startup set values */
+extern char *_aenvptr; /* environment ptr */
+extern wchar_t *_wenvptr; /* wide environment ptr */
+
+/* command line */
+
+#if defined (_DLL)
+_CRTIMP char ** __cdecl __p__acmdln(void);
+_CRTIMP wchar_t ** __cdecl __p__wcmdln(void);
+#endif /* defined (_DLL) */
+#ifndef _M_CEE_PURE
+_CRTIMP extern char *_acmdln;
+_CRTIMP extern wchar_t *_wcmdln;
+#else /* _M_CEE_PURE */
+#define _acmdln (*__p__acmdln())
+#define _wcmdln (*__p__wcmdln())
+#endif /* _M_CEE_PURE */
+
+/*
+ * prototypes for internal startup functions
+ */
+int __cdecl _cwild(void); /* wild.c */
+int __cdecl _wcwild(void); /* wwild.c */
+int __cdecl _mtinit(void); /* tidtable.c */
+void __cdecl _mtterm(void); /* tidtable.c */
+int __cdecl _mtinitlocks(void); /* mlock.c */
+void __cdecl _mtdeletelocks(void); /* mlock.c */
+int __cdecl _mtinitlocknum(int); /* mlock.c */
+
+/* Wrapper for InitializeCriticalSection API, with default spin count */
+int __cdecl __crtInitCritSecAndSpinCount(PCRITICAL_SECTION, DWORD);
+#define _CRT_SPINCOUNT 4000
+
+/*
+ * C source build only!!!!
+ *
+ * more prototypes for internal startup functions
+ */
+void __cdecl _amsg_exit(int); /* crt0.c */
+void __cdecl __crtExitProcess(int); /* crt0dat.c */
+void __cdecl __crtCorExitProcess(int); /* crt0dat.c */
+void __cdecl __crtdll_callstaticterminators(void); /* crt0dat.c */
+
+/*
+_cinit now allows the caller to suppress floating point precision init
+This allows the DLLs that use the CRT to not initialise FP precision,
+allowing the EXE's setting to persist even when a DLL is loaded
+*/
+int __cdecl _cinit(int /* initFloatingPrecision */); /* crt0dat.c */
+void __cdecl __doinits(void); /* astart.asm */
+void __cdecl __doterms(void); /* astart.asm */
+void __cdecl __dopreterms(void); /* astart.asm */
+void __cdecl _FF_MSGBANNER(void);
+void __cdecl _fpmath(int /*initPrecision*/);
+void __cdecl _fpclear(void);
+void __cdecl _fptrap(void); /* crt0fp.c */
+int __cdecl _heap_init(int);
+void __cdecl _heap_term(void);
+void __cdecl _heap_abort(void);
+void __cdecl __initconin(void); /* initcon.c */
+void __cdecl __initconout(void); /* initcon.c */
+int __cdecl _ioinit(void); /* crt0.c, crtlib.c */
+void __cdecl _ioterm(void); /* crt0.c, crtlib.c */
+char * __cdecl _GET_RTERRMSG(int);
+void __cdecl _NMSG_WRITE(int);
+int __CRTDECL _setargv(void); /* setargv.c, stdargv.c */
+int __CRTDECL __setargv(void); /* stdargv.c */
+int __CRTDECL _wsetargv(void); /* wsetargv.c, wstdargv.c */
+int __CRTDECL __wsetargv(void); /* wstdargv.c */
+int __cdecl _setenvp(void); /* stdenvp.c */
+int __cdecl _wsetenvp(void); /* wstdenvp.c */
+void __cdecl __setmbctable(unsigned int); /* mbctype.c */
+
+#ifdef MRTDLL
+_MRTIMP int __cdecl _onexit_process(_CPVFV);
+_MRTIMP int __cdecl _onexit_app_domain(_CPVFV);
+#endif /* MRTDLL */
+
+#ifdef _MBCS
+int __cdecl __initmbctable(void); /* mbctype.c */
+#endif /* _MBCS */
+
+#ifndef _MANAGED_MAIN
+int __CRTDECL main(__in int _Argc, __in_ecount_z(_Argc) char ** _Argv, __in_z char ** _Env);
+int __CRTDECL wmain(__in int _Argc, __in_ecount_z(_Argc) wchar_t ** _Argv, __in_z wchar_t ** _Env);
+#endif /* _MANAGED_MAIN */
+
+/* helper functions for wide/multibyte environment conversion */
+int __cdecl __mbtow_environ (void);
+int __cdecl __wtomb_environ (void);
+
+/* These two functions take a char ** for the environment option
+ At some point during their execution, they take ownership of the
+ memory block passed in using option. At this point, they
+ NULL out the incoming char * / wchar_t * to ensure there is no
+ double-free
+*/
+int __cdecl __crtsetenv (__deref_inout_opt char ** _POption, __in const int _Primary);
+int __cdecl __crtwsetenv (__deref_inout_opt wchar_t ** _POption, __in const int _Primary);
+
+#ifndef _M_CEE_PURE
+_CRTIMP extern void (__cdecl * _aexit_rtn)(int);
+#endif /* _M_CEE_PURE */
+
+#if defined (_DLL) || defined (CRTDLL)
+
+#ifndef _STARTUP_INFO_DEFINED
+typedef struct
+{
+ int newmode;
+} _startupinfo;
+#define _STARTUP_INFO_DEFINED
+#endif /* _STARTUP_INFO_DEFINED */
+
+_CRTIMP int __cdecl __getmainargs(__out int * _Argc, __deref_out_ecount(*_Argc) char *** _Argv,
+ __deref_out_opt char *** _Env, __in int _DoWildCard,
+ __in _startupinfo * _StartInfo);
+
+_CRTIMP int __cdecl __wgetmainargs(__out int * _Argc, __deref_out_ecount(*_Argc)wchar_t *** _Argv,
+ __deref_out_opt wchar_t *** _Env, __in int _DoWildCard,
+ __in _startupinfo * _StartInfo);
+
+#endif /* defined (_DLL) || defined (CRTDLL) */
+
+/*
+ * Prototype, variables and constants which determine how error messages are
+ * written out.
+ */
+#define _UNKNOWN_APP 0
+#define _CONSOLE_APP 1
+#define _GUI_APP 2
+
+extern int __app_type;
+
+#if !defined (_M_CEE_PURE)
+
+extern Volatile<void*> __native_startup_lock;
+
+#define __NO_REASON UINT_MAX
+extern Volatile<unsigned int> __native_dllmain_reason;
+extern Volatile<unsigned int> __native_vcclrit_reason;
+
+#if defined (__cplusplus)
+
+#pragma warning(push)
+#pragma warning(disable: 4483)
+#if _MSC_FULL_VER >= 140050415
+#define _NATIVE_STARTUP_NAMESPACE __identifier("<CrtImplementationDetails>")
+#else /* _MSC_FULL_VER >= 140050415 */
+#define _NATIVE_STARTUP_NAMESPACE __CrtImplementationDetails
+#endif /* _MSC_FULL_VER >= 140050415 */
+
+namespace _NATIVE_STARTUP_NAMESPACE
+{
+ class NativeDll
+ {
+ private:
+ static const unsigned int ProcessDetach = 0;
+ static const unsigned int ProcessAttach = 1;
+ static const unsigned int ThreadAttach = 2;
+ static const unsigned int ThreadDetach = 3;
+ static const unsigned int ProcessVerifier = 4;
+
+ public:
+
+ inline static bool IsInDllMain()
+ {
+ return (__native_dllmain_reason != __NO_REASON);
+ }
+
+ inline static bool IsInProcessAttach()
+ {
+ return (__native_dllmain_reason == ProcessAttach);
+ }
+
+ inline static bool IsInProcessDetach()
+ {
+ return (__native_dllmain_reason == ProcessDetach);
+ }
+
+ inline static bool IsInVcclrit()
+ {
+ return (__native_vcclrit_reason != __NO_REASON);
+ }
+
+ inline static bool IsSafeForManagedCode()
+ {
+ if (!IsInDllMain())
+ {
+ return true;
+ }
+
+ if (IsInVcclrit())
+ {
+ return true;
+ }
+
+ return !IsInProcessAttach() && !IsInProcessDetach();
+ }
+ };
+}
+#pragma warning(pop)
+
+#endif /* defined (__cplusplus) */
+
+#endif /* !defined (_M_CEE_PURE) */
+
+extern int __error_mode;
+
+_CRTIMP void __cdecl __set_app_type(int);
+#if defined (CRTDLL) && !defined (_SYSCRT)
+/*
+ * All these function pointer are used for creating global state of CRT
+ * functions. Either all of them will be set or all of them will be NULL
+ */
+typedef void (__cdecl *_set_app_type_function)(int);
+typedef int (__cdecl *_get_app_type_function)();
+extern _set_app_type_function __set_app_type_server;
+extern _get_app_type_function __get_app_type_server;
+#endif /* defined (CRTDLL) && !defined (_SYSCRT) */
+
+/*
+ * C source build only!!!!
+ *
+ * map Win32 errors into Xenix errno values -- for modules written in C
+ */
+_CRTIMP void __cdecl _dosmaperr(unsigned long);
+extern int __cdecl _get_errno_from_oserr(unsigned long);
+
+/*
+ * internal routines used by the exec/spawn functions
+ */
+
+extern intptr_t __cdecl _dospawn(__in int _Mode, __in_z_opt const char * _Name, __inout_z char * _Cmd, __in_z_opt char * _Env);
+extern intptr_t __cdecl _wdospawn(__in int _Mode, __in_z_opt const wchar_t * _Name, __inout_z wchar_t * _Cmd, __in_z_opt wchar_t * _Env);
+extern int __cdecl _cenvarg(__in_z const char * const * _Argv, __in_z_opt const char * const * _Env,
+ __deref_out_opt char ** _ArgBlk, __deref_out_opt char ** _EnvBlk, __in_z const char *_Name);
+extern int __cdecl _wcenvarg(__in_z const wchar_t * const * _Argv, __in_z_opt const wchar_t * const * _Env,
+ __deref_out_opt wchar_t ** _ArgBlk, __deref_out_opt wchar_t ** _EnvBlk, __in_z const wchar_t * _Name);
+#ifndef _M_IX86
+extern char ** _capture_argv(__in va_list *, __in_z const char * _FirstArg, __out_ecount_z(_MaxCount) char ** _Static_argv, __in size_t _MaxCount);
+extern wchar_t ** _wcapture_argv(__in va_list *, __in_z const wchar_t * _FirstArg, __out_ecount_z(_MaxCount) wchar_t ** _Static_argv, __in size_t _MaxCount);
+#endif /* _M_IX86 */
+
+/*
+ * internal routine used by the abort
+ */
+
+extern _PHNDLR __cdecl __get_sigabrt(void);
+
+/*
+ * Type from ntdef.h
+ */
+
+typedef LONG NTSTATUS;
+
+/*
+ * Exception code used in _invalid_parameter
+ */
+
+#ifndef STATUS_INVALID_PARAMETER
+#define STATUS_INVALID_PARAMETER ((NTSTATUS)0xC000000DL)
+#endif /* STATUS_INVALID_PARAMETER */
+
+/*
+ * Exception code used for abort and _CALL_REPORTFAULT
+ */
+
+#ifndef STATUS_FATAL_APP_EXIT
+#define STATUS_FATAL_APP_EXIT ((NTSTATUS)0x40000015L)
+#endif /* STATUS_FATAL_APP_EXIT */
+
+/*
+ * Validate functions
+ */
+#include <crtdbg.h> /* _ASSERTE */
+#include <errno.h>
+
+#define __STR2WSTR(str) L##str
+
+#define _STR2WSTR(str) __STR2WSTR(str)
+
+#define __FILEW__ _STR2WSTR(__FILE__)
+#define __FUNCTIONW__ _STR2WSTR(__FUNCTION__)
+
+/* We completely fill the buffer only in debug (see _SECURECRT__FILL_STRING
+ * and _SECURECRT__FILL_BYTE macros).
+ */
+#if !defined (_SECURECRT_FILL_BUFFER)
+#ifdef _DEBUG
+#define _SECURECRT_FILL_BUFFER 1
+#else /* _DEBUG */
+#define _SECURECRT_FILL_BUFFER 0
+#endif /* _DEBUG */
+#endif /* !defined (_SECURECRT_FILL_BUFFER) */
+
+#ifndef _SAFECRT_IMPL
+/* _invalid_parameter is already defined in safecrt.h and safecrt.lib */
+#if !defined (_NATIVE_WCHAR_T_DEFINED) && defined (_M_CEE_PURE)
+extern "C++"
+#endif /* !defined (_NATIVE_WCHAR_T_DEFINED) && defined (_M_CEE_PURE) */
+_CRTIMP
+#endif /* _SAFECRT_IMPL */
+void __cdecl _invalid_parameter(__in_z_opt const wchar_t *, __in_z_opt const wchar_t *, __in_z_opt const wchar_t *, unsigned int, uintptr_t);
+
+#if !defined (_NATIVE_WCHAR_T_DEFINED) && defined (_M_CEE_PURE)
+extern "C++"
+#endif /* !defined (_NATIVE_WCHAR_T_DEFINED) && defined (_M_CEE_PURE) */
+_CRTIMP
+void __cdecl _invoke_watson(__in_z_opt const wchar_t *, __in_z_opt const wchar_t *, __in_z_opt const wchar_t *, unsigned int, uintptr_t);
+
+#ifndef _DEBUG
+#if !defined (_NATIVE_WCHAR_T_DEFINED) && defined (_M_CEE_PURE)
+extern "C++"
+#endif /* !defined (_NATIVE_WCHAR_T_DEFINED) && defined (_M_CEE_PURE) */
+_CRTIMP
+void __cdecl _invalid_parameter_noinfo(void);
+#endif /* _DEBUG */
+
+/* Invoke Watson if _ExpressionError is not 0; otherwise simply return _EspressionError */
+__forceinline
+void _invoke_watson_if_error(
+ errno_t _ExpressionError,
+ const wchar_t *_Expression,
+ const wchar_t *_Function,
+ const wchar_t *_File,
+ unsigned int _Line,
+ uintptr_t _Reserved
+ )
+{
+ if (_ExpressionError == 0)
+ {
+ return;
+ }
+ _invoke_watson(_Expression, _Function, _File, _Line, _Reserved);
+}
+
+/* Invoke Watson if _ExpressionError is not 0 and equal to _ErrorValue1 or _ErrorValue2; otherwise simply return _EspressionError */
+__forceinline
+errno_t _invoke_watson_if_oneof(
+ errno_t _ExpressionError,
+ errno_t _ErrorValue1,
+ errno_t _ErrorValue2,
+ const wchar_t *_Expression,
+ const wchar_t *_Function,
+ const wchar_t *_File,
+ unsigned int _Line,
+ uintptr_t _Reserved
+ )
+{
+ if (_ExpressionError == 0 || (_ExpressionError != _ErrorValue1 && _ExpressionError != _ErrorValue2))
+ {
+ return _ExpressionError;
+ }
+ _invoke_watson(_Expression, _Function, _File, _Line, _Reserved);
+ return _ExpressionError;
+}
+
+/*
+ * Assert in debug builds.
+ * set errno and return
+ *
+ */
+#ifdef _DEBUG
+#define _CALL_INVALID_PARAMETER_FUNC(funcname, expr) funcname(expr, __FUNCTIONW__, __FILEW__, __LINE__, 0)
+#define _INVOKE_WATSON_IF_ERROR(expr) _invoke_watson_if_error((expr), __STR2WSTR(#expr), __FUNCTIONW__, __FILEW__, __LINE__, 0)
+#define _INVOKE_WATSON_IF_ONEOF(expr, errvalue1, errvalue2) _invoke_watson_if_oneof(expr, (errvalue1), (errvalue2), __STR2WSTR(#expr), __FUNCTIONW__, __FILEW__, __LINE__, 0)
+#else /* _DEBUG */
+#define _CALL_INVALID_PARAMETER_FUNC(funcname, expr) funcname(NULL, NULL, NULL, 0, 0)
+#define _INVOKE_WATSON_IF_ERROR(expr) _invoke_watson_if_error(expr, NULL, NULL, NULL, 0, 0)
+#define _INVOKE_WATSON_IF_ONEOF(expr, errvalue1, errvalue2) _invoke_watson_if_oneof((expr), (errvalue1), (errvalue2), NULL, NULL, NULL, 0, 0)
+#endif /* _DEBUG */
+
+#define _INVALID_PARAMETER(expr) _CALL_INVALID_PARAMETER_FUNC(_invalid_parameter, expr)
+
+#define _VALIDATE_RETURN_VOID( expr, errorcode ) \
+ { \
+ int _Expr_val=!!(expr); \
+ _ASSERT_EXPR( ( _Expr_val ), _CRT_WIDE(#expr) ); \
+ if ( !( _Expr_val ) ) \
+ { \
+ errno = errorcode; \
+ _INVALID_PARAMETER(_CRT_WIDE(#expr)); \
+ return; \
+ } \
+ }
+
+/*
+ * Assert in debug builds.
+ * set errno and return value
+ */
+
+#ifndef _VALIDATE_RETURN
+#define _VALIDATE_RETURN( expr, errorcode, retexpr ) \
+ { \
+ int _Expr_val=!!(expr); \
+ _ASSERT_EXPR( ( _Expr_val ), _CRT_WIDE(#expr) ); \
+ if ( !( _Expr_val ) ) \
+ { \
+ errno = errorcode; \
+ _INVALID_PARAMETER(_CRT_WIDE(#expr) ); \
+ return ( retexpr ); \
+ } \
+ }
+#endif /* _VALIDATE_RETURN */
+
+#ifndef _VALIDATE_RETURN_NOEXC
+#define _VALIDATE_RETURN_NOEXC( expr, errorcode, retexpr ) \
+ { \
+ if ( !(expr) ) \
+ { \
+ errno = errorcode; \
+ return ( retexpr ); \
+ } \
+ }
+#endif /* _VALIDATE_RETURN_NOEXC */
+
+/*
+ * Assert in debug builds.
+ * set errno and set retval for later usage
+ */
+
+#define _VALIDATE_SETRET( expr, errorcode, retval, retexpr ) \
+ { \
+ int _Expr_val=!!(expr); \
+ _ASSERT_EXPR( ( _Expr_val ), _CRT_WIDE(#expr) ); \
+ if ( !( _Expr_val ) ) \
+ { \
+ errno = errorcode; \
+ _INVALID_PARAMETER(_CRT_WIDE(#expr)); \
+ retval=( retexpr ); \
+ } \
+ }
+
+#define _CHECK_FH_RETURN( handle, errorcode, retexpr ) \
+ { \
+ if(handle == _NO_CONSOLE_FILENO) \
+ { \
+ errno = errorcode; \
+ return ( retexpr ); \
+ } \
+ }
+
+/*
+ We use _VALIDATE_STREAM_ANSI_RETURN to ensure that ANSI file operations(
+ fprintf etc) aren't called on files opened as UNICODE. We do this check
+ only if it's an actual FILE pointer & not a string
+*/
+
+#define _VALIDATE_STREAM_ANSI_RETURN( stream, errorcode, retexpr ) \
+ { \
+ FILE *_Stream=stream; \
+ _VALIDATE_RETURN(( (_Stream->_flag & _IOSTRG) || \
+ ( (_textmode_safe(_fileno(_Stream)) == __IOINFO_TM_ANSI) && \
+ !_tm_unicode_safe(_fileno(_Stream)))), \
+ errorcode, retexpr) \
+ }
+
+/*
+ We use _VALIDATE_STREAM_ANSI_SETRET to ensure that ANSI file operations(
+ fprintf etc) aren't called on files opened as UNICODE. We do this check
+ only if it's an actual FILE pointer & not a string. It doesn't actually return
+ immediately
+*/
+
+#define _VALIDATE_STREAM_ANSI_SETRET( stream, errorcode, retval, retexpr) \
+ { \
+ FILE *_Stream=stream; \
+ _VALIDATE_SETRET(( (_Stream->_flag & _IOSTRG) || \
+ ( (_textmode_safe(_fileno(_Stream)) == __IOINFO_TM_ANSI) && \
+ !_tm_unicode_safe(_fileno(_Stream)))), \
+ errorcode, retval, retexpr) \
+ }
+
+/*
+ * Assert in debug builds.
+ * Return value (do not set errno)
+ */
+
+#define _VALIDATE_RETURN_NOERRNO( expr, retexpr ) \
+ { \
+ int _Expr_val=!!(expr); \
+ _ASSERT_EXPR( ( _Expr_val ), _CRT_WIDE(#expr) ); \
+ if ( !( _Expr_val ) ) \
+ { \
+ _INVALID_PARAMETER(_CRT_WIDE(#expr)); \
+ return ( retexpr ); \
+ } \
+ }
+
+/*
+ * Assert in debug builds.
+ * set errno and return errorcode
+ */
+
+#define _VALIDATE_RETURN_ERRCODE( expr, errorcode ) \
+ { \
+ int _Expr_val=!!(expr); \
+ _ASSERT_EXPR( ( _Expr_val ), _CRT_WIDE(#expr) ); \
+ if ( !( _Expr_val ) ) \
+ { \
+ errno = errorcode; \
+ _INVALID_PARAMETER(_CRT_WIDE(#expr)); \
+ return ( errorcode ); \
+ } \
+ }
+
+#define _VALIDATE_RETURN_ERRCODE_NOEXC( expr, errorcode ) \
+ { \
+ if (!(expr)) \
+ { \
+ errno = errorcode; \
+ return ( errorcode ); \
+ } \
+ }
+
+#define _VALIDATE_CLEAR_OSSERR_RETURN( expr, errorcode, retexpr ) \
+ { \
+ int _Expr_val=!!(expr); \
+ _ASSERT_EXPR( ( _Expr_val ), _CRT_WIDE(#expr) ); \
+ if ( !( _Expr_val ) ) \
+ { \
+ _doserrno = 0L; \
+ errno = errorcode; \
+ _INVALID_PARAMETER(_CRT_WIDE(#expr) ); \
+ return ( retexpr ); \
+ } \
+ }
+
+#define _CHECK_FH_CLEAR_OSSERR_RETURN( handle, errorcode, retexpr ) \
+ { \
+ if(handle == _NO_CONSOLE_FILENO) \
+ { \
+ _doserrno = 0L; \
+ errno = errorcode; \
+ return ( retexpr ); \
+ } \
+ }
+
+#define _VALIDATE_CLEAR_OSSERR_RETURN_ERRCODE( expr, errorcode ) \
+ { \
+ int _Expr_val=!!(expr); \
+ _ASSERT_EXPR( ( _Expr_val ), _CRT_WIDE(#expr) ); \
+ if ( !( _Expr_val ) ) \
+ { \
+ _doserrno = 0L; \
+ errno = errorcode; \
+ _INVALID_PARAMETER(_CRT_WIDE(#expr)); \
+ return ( errorcode ); \
+ } \
+ }
+
+#define _CHECK_FH_CLEAR_OSSERR_RETURN_ERRCODE( handle, retexpr ) \
+ { \
+ if(handle == _NO_CONSOLE_FILENO) \
+ { \
+ _doserrno = 0L; \
+ return ( retexpr ); \
+ } \
+ }
+
+#ifdef _DEBUG
+extern size_t __crtDebugFillThreshold;
+#endif /* _DEBUG */
+
+#if !defined (_SECURECRT_FILL_BUFFER_THRESHOLD)
+#ifdef _DEBUG
+#define _SECURECRT_FILL_BUFFER_THRESHOLD __crtDebugFillThreshold
+#else /* _DEBUG */
+#define _SECURECRT_FILL_BUFFER_THRESHOLD ((size_t)0)
+#endif /* _DEBUG */
+#endif /* !defined (_SECURECRT_FILL_BUFFER_THRESHOLD) */
+
+#if _SECURECRT_FILL_BUFFER
+#define _SECURECRT__FILL_STRING(_String, _Size, _Offset) \
+ if ((_Size) != ((size_t)-1) && (_Size) != INT_MAX && \
+ ((size_t)(_Offset)) < (_Size)) \
+ { \
+ memset((_String) + (_Offset), \
+ _SECURECRT_FILL_BUFFER_PATTERN, \
+ (_SECURECRT_FILL_BUFFER_THRESHOLD < ((size_t)((_Size) - (_Offset))) ? \
+ _SECURECRT_FILL_BUFFER_THRESHOLD : \
+ ((_Size) - (_Offset))) * sizeof(*(_String))); \
+ }
+#else /* _SECURECRT_FILL_BUFFER */
+#define _SECURECRT__FILL_STRING(_String, _Size, _Offset)
+#endif /* _SECURECRT_FILL_BUFFER */
+
+#if _SECURECRT_FILL_BUFFER
+#define _SECURECRT__FILL_BYTE(_Position) \
+ if (_SECURECRT_FILL_BUFFER_THRESHOLD > 0) \
+ { \
+ (_Position) = _SECURECRT_FILL_BUFFER_PATTERN; \
+ }
+#else /* _SECURECRT_FILL_BUFFER */
+#define _SECURECRT__FILL_BYTE(_Position)
+#endif /* _SECURECRT_FILL_BUFFER */
+
+#ifdef __cplusplus
+#define _REDIRECT_TO_L_VERSION_FUNC_PROLOGUE extern "C"
+#else /* __cplusplus */
+#define _REDIRECT_TO_L_VERSION_FUNC_PROLOGUE
+#endif /* __cplusplus */
+
+/* helper macros to redirect an mbs function to the corresponding _l version */
+#define _REDIRECT_TO_L_VERSION_1(_ReturnType, _FunctionName, _Type1) \
+ _REDIRECT_TO_L_VERSION_FUNC_PROLOGUE \
+ _ReturnType __cdecl _FunctionName(_Type1 _Arg1) \
+ { \
+ return _FunctionName##_l(_Arg1, NULL); \
+ }
+
+#define _REDIRECT_TO_L_VERSION_2(_ReturnType, _FunctionName, _Type1, _Type2) \
+ _REDIRECT_TO_L_VERSION_FUNC_PROLOGUE \
+ _ReturnType __cdecl _FunctionName(_Type1 _Arg1, _Type2 _Arg2) \
+ { \
+ return _FunctionName##_l(_Arg1, _Arg2, NULL); \
+ }
+
+#define _REDIRECT_TO_L_VERSION_3(_ReturnType, _FunctionName, _Type1, _Type2, _Type3) \
+ _REDIRECT_TO_L_VERSION_FUNC_PROLOGUE \
+ _ReturnType __cdecl _FunctionName(_Type1 _Arg1, _Type2 _Arg2, _Type3 _Arg3) \
+ { \
+ return _FunctionName##_l(_Arg1, _Arg2, _Arg3, NULL); \
+ }
+
+#define _REDIRECT_TO_L_VERSION_4(_ReturnType, _FunctionName, _Type1, _Type2, _Type3, _Type4) \
+ _REDIRECT_TO_L_VERSION_FUNC_PROLOGUE \
+ _ReturnType __cdecl _FunctionName(_Type1 _Arg1, _Type2 _Arg2, _Type3 _Arg3, _Type4 _Arg4) \
+ { \
+ return _FunctionName##_l(_Arg1, _Arg2, _Arg3, _Arg4, NULL); \
+ }
+
+#define _REDIRECT_TO_L_VERSION_5(_ReturnType, _FunctionName, _Type1, _Type2, _Type3, _Type4, _Type5) \
+ _REDIRECT_TO_L_VERSION_FUNC_PROLOGUE \
+ _ReturnType __cdecl _FunctionName(_Type1 _Arg1, _Type2 _Arg2, _Type3 _Arg3, _Type4 _Arg4, _Type5 _Arg5) \
+ { \
+ return _FunctionName##_l(_Arg1, _Arg2, _Arg3, _Arg4, _Arg5, NULL); \
+ }
+
+#define _REDIRECT_TO_L_VERSION_6(_ReturnType, _FunctionName, _Type1, _Type2, _Type3, _Type4, _Type5, _Type6) \
+ _REDIRECT_TO_L_VERSION_FUNC_PROLOGUE \
+ _ReturnType __cdecl _FunctionName(_Type1 _Arg1, _Type2 _Arg2, _Type3 _Arg3, _Type4 _Arg4, _Type5 _Arg5, _Type6 _Arg6) \
+ { \
+ return _FunctionName##_l(_Arg1, _Arg2, _Arg3, _Arg4, _Arg5, _Arg6, NULL); \
+ }
+
+/* internal helper functions for encoding and decoding pointers */
+void __cdecl _init_pointers();
+_CRTIMP void * __cdecl _encode_pointer(void *);
+_CRTIMP void * __cdecl _encoded_null();
+_CRTIMP void * __cdecl _decode_pointer(void *);
+
+/* internal helper function for communicating with the debugger */
+BOOL DebuggerKnownHandle();
+
+/* Macros to simplify the use of Secure CRT in the CRT itself.
+ * We should use [_BEGIN/_END]_SECURE_CRT_DEPRECATION_DISABLE sparingly.
+ */
+#define _BEGIN_SECURE_CRT_DEPRECATION_DISABLE \
+ __pragma(warning(push)) \
+ __pragma(warning(disable:4996))
+
+#define _END_SECURE_CRT_DEPRECATION_DISABLE \
+ __pragma(warning(pop))
+
+#define _ERRCHECK(e) \
+ _INVOKE_WATSON_IF_ERROR(e)
+
+#define _ERRCHECK_EINVAL(e) \
+ _INVOKE_WATSON_IF_ONEOF(e, EINVAL, EINVAL)
+
+#define _ERRCHECK_EINVAL_ERANGE(e) \
+ _INVOKE_WATSON_IF_ONEOF(e, EINVAL, ERANGE)
+
+#define _ERRCHECK_SPRINTF(_PrintfCall) \
+ { \
+ errno_t _SaveErrno = errno; \
+ errno = 0; \
+ if ( ( _PrintfCall ) < 0) \
+ { \
+ _ERRCHECK_EINVAL_ERANGE(errno); \
+ } \
+ errno = _SaveErrno; \
+ }
+
+/* internal helper function to access environment variable in read-only mode */
+const wchar_t * __cdecl _wgetenv_helper_nolock(const wchar_t *);
+const char * __cdecl _getenv_helper_nolock(const char *);
+
+/* internal helper routines used to query a PE image header. */
+BOOL __cdecl _ValidateImageBase(PBYTE pImageBase);
+PIMAGE_SECTION_HEADER __cdecl _FindPESection(PBYTE pImageBase, DWORD_PTR rva);
+BOOL __cdecl _IsNonwritableInCurrentImage(PBYTE pTarget);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#ifdef _MSC_VER
+#pragma pack(pop)
+#endif /* _MSC_VER */
+
+#endif /* _INC_INTERNAL */
diff --git a/src/pal/src/safecrt/internal_securecrt.h b/src/pal/src/safecrt/internal_securecrt.h
new file mode 100644
index 0000000000..c38bc4613b
--- /dev/null
+++ b/src/pal/src/safecrt/internal_securecrt.h
@@ -0,0 +1,292 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*internal_securecrt.h - contains declarations of internal routines and variables for securecrt
+*
+
+*
+*Purpose:
+* Declares routines and variables used internally in the SecureCRT implementation.
+* In this include file we define the macros needed to implement the secure functions
+* inlined in the *.inl files like tcscpy_s.inl, etc.
+* Note that this file is used for the CRT implementation, while internal_safecrt is used
+* to build the downlevel library safecrt.lib.
+*
+* [Internal]
+*
+****/
+
+#pragma once
+
+#ifndef _INC_INTERNAL_SECURECRT
+#define _INC_INTERNAL_SECURECRT
+
+/* more VS specific goodness */
+#define __out_ecount_z( x )
+#define __out_ecount( x )
+#define __in_opt
+#define __in_z_opt
+#define __out_ecount_z_opt( x )
+#define __in_z
+#define __in
+
+/*
+ * The original SafeCRT implemention allows runtine control over buffer checking.
+ * For now we'll key this off the debug flag.
+ */
+#ifdef _DEBUG
+ #define _CrtGetCheckCount() ((int)1)
+#else
+ #define _CrtGetCheckCount() ((int)0)
+#endif
+
+/* Assert message and Invalid parameter */
+#ifdef _DEBUG
+ #define _ASSERT_EXPR( val, exp ) \
+ { \
+ if ( ( val ) == 0 ) \
+ { \
+ if ( sMBUSafeCRTAssertFunc != NULL ) \
+ { \
+ ( *sMBUSafeCRTAssertFunc )( #exp, "SafeCRT assert failed", __FILE__, __LINE__ ); \
+ } \
+ } \
+ }
+ #define _INVALID_PARAMETER( exp ) _ASSERT_EXPR( 0, exp )
+ #define _ASSERTE( exp ) _ASSERT_EXPR( exp, exp )
+#else
+ #define _ASSERT_EXPR( val, expr )
+ #define _INVALID_PARAMETER( exp )
+ #define _ASSERTE( exp )
+#endif
+
+/* _TRUNCATE */
+#if !defined (_TRUNCATE)
+#define _TRUNCATE ((size_t)-1)
+#endif /* !defined (_TRUNCATE) */
+
+/* #include <internal.h> */
+
+#define _VALIDATE_RETURN_VOID( expr, errorcode ) \
+ { \
+ int _Expr_val=!!(expr); \
+ _ASSERT_EXPR( ( _Expr_val ), #expr ); \
+ if ( !( _Expr_val ) ) \
+ { \
+ errno = errorcode; \
+ _INVALID_PARAMETER(#expr); \
+ return; \
+ } \
+ }
+
+/*
+ * Assert in debug builds.
+ * set errno and return value
+ */
+
+#ifndef _VALIDATE_RETURN
+#define _VALIDATE_RETURN( expr, errorcode, retexpr ) \
+ { \
+ int _Expr_val=!!(expr); \
+ _ASSERT_EXPR( ( _Expr_val ), #expr ); \
+ if ( !( _Expr_val ) ) \
+ { \
+ errno = errorcode; \
+ _INVALID_PARAMETER(#expr ); \
+ return ( retexpr ); \
+ } \
+ }
+#endif /* _VALIDATE_RETURN */
+
+#ifndef _VALIDATE_RETURN_NOEXC
+#define _VALIDATE_RETURN_NOEXC( expr, errorcode, retexpr ) \
+ { \
+ if ( !(expr) ) \
+ { \
+ errno = errorcode; \
+ return ( retexpr ); \
+ } \
+ }
+#endif /* _VALIDATE_RETURN_NOEXC */
+
+/*
+ * Assert in debug builds.
+ * set errno and return errorcode
+ */
+
+#define _VALIDATE_RETURN_ERRCODE( expr, errorcode ) \
+ { \
+ int _Expr_val=!!(expr); \
+ _ASSERT_EXPR( ( _Expr_val ), _CRT_WIDE(#expr) ); \
+ if ( !( _Expr_val ) ) \
+ { \
+ errno = errorcode; \
+ _INVALID_PARAMETER(_CRT_WIDE(#expr)); \
+ return ( errorcode ); \
+ } \
+ }
+
+/* We completely fill the buffer only in debug (see _SECURECRT__FILL_STRING
+ * and _SECURECRT__FILL_BYTE macros).
+ */
+#if !defined (_SECURECRT_FILL_BUFFER)
+#ifdef _DEBUG
+#define _SECURECRT_FILL_BUFFER 1
+#else /* _DEBUG */
+#define _SECURECRT_FILL_BUFFER 0
+#endif /* _DEBUG */
+#endif /* !defined (_SECURECRT_FILL_BUFFER) */
+
+/* _SECURECRT_FILL_BUFFER_PATTERN is the same as _bNoMansLandFill */
+#define _SECURECRT_FILL_BUFFER_PATTERN 0xFD
+
+#if !defined (_SECURECRT_FILL_BUFFER_THRESHOLD)
+#ifdef _DEBUG
+#define _SECURECRT_FILL_BUFFER_THRESHOLD ((size_t)8)
+#else /* _DEBUG */
+#define _SECURECRT_FILL_BUFFER_THRESHOLD ((size_t)0)
+#endif /* _DEBUG */
+#endif /* !defined (_SECURECRT_FILL_BUFFER_THRESHOLD) */
+
+#if _SECURECRT_FILL_BUFFER
+#define _SECURECRT__FILL_STRING(_String, _Size, _Offset) \
+ if ((_Size) != ((size_t)-1) && (_Size) != INT_MAX && \
+ ((size_t)(_Offset)) < (_Size)) \
+ { \
+ memset((_String) + (_Offset), \
+ _SECURECRT_FILL_BUFFER_PATTERN, \
+ (_SECURECRT_FILL_BUFFER_THRESHOLD < ((size_t)((_Size) - (_Offset))) ? \
+ _SECURECRT_FILL_BUFFER_THRESHOLD : \
+ ((_Size) - (_Offset))) * sizeof(*(_String))); \
+ }
+#else /* _SECURECRT_FILL_BUFFER */
+#define _SECURECRT__FILL_STRING(_String, _Size, _Offset)
+#endif /* _SECURECRT_FILL_BUFFER */
+
+#if _SECURECRT_FILL_BUFFER
+#define _SECURECRT__FILL_BYTE(_Position) \
+ if (_SECURECRT_FILL_BUFFER_THRESHOLD > 0) \
+ { \
+ (_Position) = _SECURECRT_FILL_BUFFER_PATTERN; \
+ }
+#else /* _SECURECRT_FILL_BUFFER */
+#define _SECURECRT__FILL_BYTE(_Position)
+#endif /* _SECURECRT_FILL_BUFFER */
+
+/* string resetting */
+#define _FILL_STRING _SECURECRT__FILL_STRING
+
+#define _FILL_BYTE _SECURECRT__FILL_BYTE
+
+#define _RESET_STRING(_String, _Size) \
+ { \
+ *(_String) = 0; \
+ _FILL_STRING((_String), (_Size), 1); \
+ }
+
+/* validations */
+#define _VALIDATE_STRING_ERROR(_String, _Size, _Ret) \
+ _VALIDATE_RETURN((_String) != NULL && (_Size) > 0, EINVAL, (_Ret))
+
+#define _VALIDATE_STRING(_String, _Size) \
+ _VALIDATE_STRING_ERROR((_String), (_Size), EINVAL)
+
+#define _VALIDATE_POINTER_ERROR_RETURN(_Pointer, _ErrorCode, _Ret) \
+ _VALIDATE_RETURN((_Pointer) != NULL, (_ErrorCode), (_Ret))
+
+#define _VALIDATE_POINTER_ERROR(_Pointer, _Ret) \
+ _VALIDATE_POINTER_ERROR_RETURN((_Pointer), EINVAL, (_Ret))
+
+#define _VALIDATE_POINTER(_Pointer) \
+ _VALIDATE_POINTER_ERROR((_Pointer), EINVAL)
+
+#define _VALIDATE_CONDITION_ERROR_RETURN(_Condition, _ErrorCode, _Ret) \
+ _VALIDATE_RETURN((_Condition), (_ErrorCode), (_Ret))
+
+#define _VALIDATE_CONDITION_ERROR(_Condition, _Ret) \
+ _VALIDATE_CONDITION_ERROR_RETURN((_Condition), EINVAL, (_Ret))
+
+#define _VALIDATE_POINTER_RESET_STRING_ERROR(_Pointer, _String, _Size, _Ret) \
+ if ((_Pointer) == NULL) \
+ { \
+ _RESET_STRING((_String), (_Size)); \
+ _VALIDATE_POINTER_ERROR_RETURN((_Pointer), EINVAL, (_Ret)) \
+ }
+
+#define _VALIDATE_POINTER_RESET_STRING(_Pointer, _String, _Size) \
+ _VALIDATE_POINTER_RESET_STRING_ERROR((_Pointer), (_String), (_Size), EINVAL)
+
+#define _RETURN_BUFFER_TOO_SMALL_ERROR(_String, _Size, _Ret) \
+ _VALIDATE_RETURN(("Buffer is too small" && 0), ERANGE, _Ret)
+
+#define _RETURN_BUFFER_TOO_SMALL(_String, _Size) \
+ _RETURN_BUFFER_TOO_SMALL_ERROR((_String), (_Size), ERANGE)
+
+#define _RETURN_DEST_NOT_NULL_TERMINATED(_String, _Size) \
+ _VALIDATE_RETURN(("String is not null terminated" && 0), EINVAL, EINVAL)
+
+#define _RETURN_EINVAL \
+ _VALIDATE_RETURN(("Invalid parameter" && 0), EINVAL, EINVAL)
+
+#define _RETURN_ERROR(_Msg, _Ret) \
+ _VALIDATE_RETURN(((_Msg), 0), EINVAL, _Ret)
+
+/* returns without calling _invalid_parameter */
+#define _RETURN_NO_ERROR \
+ return 0
+
+/* Note that _RETURN_TRUNCATE does not set errno */
+#define _RETURN_TRUNCATE \
+ return STRUNCATE
+
+#define _SET_MBCS_ERROR \
+ (errno = EILSEQ)
+
+#define _RETURN_MBCS_ERROR \
+ return _SET_MBCS_ERROR
+
+/* locale dependent */
+#define _LOCALE_ARG \
+ _LocInfo
+
+#define _LOCALE_ARG_DECL \
+ _locale_t _LOCALE_ARG
+
+#define _LOCALE_UPDATE \
+ _LocaleUpdate _LocUpdate(_LOCALE_ARG)
+
+#define _ISMBBLEAD(_Character) \
+ _ismbblead_l((_Character), _LocUpdate.GetLocaleT())
+
+#define _MBSDEC(_String, _Current) \
+ _mbsdec((_String), (_Current))
+
+#define _ISMBBLEADPREFIX(_Result, _StringStart, _BytePtr) \
+ { \
+ unsigned char *_Tmp_VAR, *_StringStart_VAR, *_BytePtr_VAR; \
+ \
+ _StringStart_VAR = (_StringStart); \
+ _BytePtr_VAR = (_BytePtr); \
+ _Tmp_VAR = _BytePtr_VAR; \
+ while ((_Tmp_VAR >= _StringStart_VAR) && _ISMBBLEAD(*_Tmp_VAR)) \
+ { \
+ _Tmp_VAR--; \
+ } \
+ (_Result) = ((_BytePtr_VAR - _Tmp_VAR) & 1) != 0; \
+ }
+
+#define _LOCALE_SHORTCUT_TEST \
+ _LocUpdate.GetLocaleT()->mbcinfo->ismbcodepage == 0
+
+#define _USE_LOCALE_ARG 1
+
+/* misc */
+#define _ASSIGN_IF_NOT_NULL(_Pointer, _Value) \
+ if ((_Pointer) != NULL) \
+ { \
+ *(_Pointer) = (_Value); \
+ }
+
+#endif /* _INC_INTERNAL_SECURECRT */
diff --git a/src/pal/src/safecrt/makepath_s.c b/src/pal/src/safecrt/makepath_s.c
new file mode 100644
index 0000000000..4342685b9c
--- /dev/null
+++ b/src/pal/src/safecrt/makepath_s.c
@@ -0,0 +1,31 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*makepath_s.c - create path name from components
+*
+
+*
+*Purpose:
+* To provide support for creation of full path names from components
+*
+*******************************************************************************/
+
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include "internal_securecrt.h"
+
+#include "mbusafecrt_internal.h"
+
+#define _FUNC_PROLOGUE
+#define _FUNC_NAME _makepath_s
+#define _CHAR char
+#define _DEST _Dst
+#define _SIZE _SizeInBytes
+#define _T(_Character) _Character
+
+#define _MBS_SUPPORT 0
+
+#include "tmakepath_s.inl"
diff --git a/src/pal/src/safecrt/mbusafecrt.c b/src/pal/src/safecrt/mbusafecrt.c
new file mode 100644
index 0000000000..ca853d9269
--- /dev/null
+++ b/src/pal/src/safecrt/mbusafecrt.c
@@ -0,0 +1,254 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+* mbusafecrt.c - implementaion of support functions and data for MBUSafeCRT
+*
+
+*
+* Purpose:
+* This file contains the implementation of support functions and
+* data for MBUSafeCRT declared in mbusafecrt.h and mbusafecrt_internal.h.
+****/
+
+#include "pal/palinternal.h"
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+
+#include "mbusafecrt_internal.h"
+
+/* global data */
+tSafeCRT_AssertFuncPtr sMBUSafeCRTAssertFunc = NULL;
+
+/***
+* MBUSafeCRTSetAssertFunc - Set the function called when an assert fails.
+****/
+
+void MBUSafeCRTSetAssertFunc( tSafeCRT_AssertFuncPtr inAssertFuncPtr )
+{
+ /* set it */
+ sMBUSafeCRTAssertFunc = inAssertFuncPtr;
+}
+
+/***
+* _putc_nolock - putc for the miniFILE stream.
+****/
+
+int _putc_nolock( char inChar, miniFILE* inStream )
+{
+ int returnValue = EOF;
+
+ inStream->_cnt -= sizeof( char );
+
+ if ( ( inStream->_cnt ) >= 0 )
+ {
+ *( inStream->_ptr ) = inChar;
+ inStream->_ptr += sizeof( char );
+ returnValue = ( int )inChar;
+ }
+
+ return returnValue;
+}
+
+/***
+* _putwc_nolock - putwc for the miniFILE stream.
+****/
+
+int _putwc_nolock( wchar_t inChar, miniFILE* inStream )
+{
+ int returnValue = WEOF;
+
+ inStream->_cnt -= sizeof( wchar_t );
+
+ if ( ( inStream->_cnt ) >= 0 )
+ {
+ *( ( wchar_t* )( inStream->_ptr ) ) = inChar;
+ inStream->_ptr += sizeof( wchar_t );
+ returnValue = ( int )inChar;
+ }
+
+ return returnValue;
+}
+
+/***
+* _getc_nolock - getc for the miniFILE stream.
+****/
+
+int _getc_nolock( miniFILE* inStream )
+{
+ int returnValue = EOF;
+
+ if ( ( inStream->_cnt ) >= ( int )( sizeof( char ) ) )
+ {
+ inStream->_cnt -= sizeof( char );
+ returnValue = ( int )( *( inStream->_ptr ) );
+ inStream->_ptr += sizeof( char );
+ }
+
+ return returnValue;
+}
+
+/***
+* _getwc_nolock - getc for the miniFILE stream.
+****/
+
+int _getwc_nolock( miniFILE* inStream )
+{
+ int returnValue = EOF;
+
+ if ( ( inStream->_cnt ) >= ( int )( sizeof( wchar_t ) ) )
+ {
+ inStream->_cnt -= sizeof( wchar_t );
+ returnValue = ( int )( *( ( wchar_t* )( inStream->_ptr ) ) );
+ inStream->_ptr += sizeof( wchar_t );
+ }
+
+ return returnValue;
+}
+
+/***
+* _ungetc_nolock - ungetc for the miniFILE stream.
+****/
+
+int _ungetc_nolock( char inChar, miniFILE* inStream )
+{
+ int returnValue = EOF;
+
+ if ( ( size_t )( ( inStream->_ptr ) - ( inStream->_base ) ) >= ( sizeof( char ) ) )
+ {
+ inStream->_cnt += sizeof( char );
+ inStream->_ptr -= sizeof( char );
+ return ( int )inChar;
+ }
+
+ return returnValue;
+}
+
+/***
+* _ungetwc_nolock - ungetwc for the miniFILE stream.
+****/
+
+int _ungetwc_nolock( wchar_t inChar, miniFILE* inStream )
+{
+ int returnValue = WEOF;
+
+ if ( ( size_t )( ( inStream->_ptr ) - ( inStream->_base ) ) >= ( sizeof( wchar_t ) ) )
+ {
+ inStream->_cnt += sizeof( wchar_t );
+ inStream->_ptr -= sizeof( wchar_t );
+ returnValue = ( unsigned short )inChar;
+ }
+
+ return returnValue;
+}
+
+
+/***
+* _safecrt_cfltcvt - convert a float to an ascii string.
+* Uses sprintf - this usage is OK.
+****/
+
+/* routine used for floating-point output */
+#define FORMATSIZE 30
+
+#define _snprintf snprintf
+
+// taken from output.inl
+#define FL_ALTERNATE 0x00080 /* alternate form requested */
+
+errno_t _safecrt_cfltcvt(double *arg, char *buffer, size_t sizeInBytes, int type, int precision, int flags)
+{
+ char format[FORMATSIZE];
+ size_t formatlen = 0;
+ int retvalue;
+
+ if (flags & 1)
+ {
+ type -= 'a' - 'A';
+ }
+ formatlen = 0;
+ format[formatlen++] = '%';
+ if (flags & FL_ALTERNATE)
+ {
+ format[formatlen++] = '#';
+ }
+ format[formatlen++] = '.';
+ _itoa_s(precision, format + formatlen, FORMATSIZE - formatlen, 10);
+ formatlen = strlen(format);
+ format[formatlen++] = (char)type;
+ format[formatlen] = 0;
+
+ buffer[sizeInBytes - 1] = 0;
+ retvalue = _snprintf(buffer, sizeInBytes, format, *arg);
+ if (buffer[sizeInBytes - 1] != 0 || retvalue <= 0)
+ {
+ buffer[0] = 0;
+ return EINVAL;
+ }
+ return 0;
+}
+
+
+/***
+* _safecrt_fassign - convert a string into a float or double.
+****/
+
+void _safecrt_fassign(int flag, void* argument, char* number )
+{
+ if ( flag != 0 ) // double
+ {
+ double dblValue = 0.0;
+ (void)sscanf( number, "%lf", &dblValue );
+ *( ( double* )argument ) = dblValue;
+ }
+ else // float
+ {
+ float fltValue = 0.0;
+ (void)sscanf( number, "%f", &fltValue );
+ *( ( float* )argument ) = fltValue;
+ }
+}
+
+
+/***
+* _safecrt_wfassign - convert a wchar_t string into a float or double.
+****/
+
+void _safecrt_wfassign(int flag, void* argument, wchar_t* number )
+{
+ // We cannot use system functions for this - they
+ // assume that wchar_t is four bytes, while we assume
+ // two. So, we need to convert to a regular char string
+ // without using any system functions. To do this,
+ // we'll assume that the numbers are in the 0-9 range and
+ // do a simple conversion.
+
+ char* numberAsChars = ( char* )number;
+ int position = 0;
+
+ // do the convert
+ while ( number[ position ] != 0 )
+ {
+ numberAsChars[ position ] = ( char )( number[ position ] & 0x00FF );
+ position++;
+ }
+ numberAsChars[ position ] = ( char )( number[ position ] & 0x00FF );
+
+ // call the normal char version
+ _safecrt_fassign( flag, argument, numberAsChars );
+}
+
+
+/***
+* _minimal_chartowchar - do a simple char to wchar conversion.
+****/
+
+int _minimal_chartowchar( wchar_t* outWChar, const char* inChar )
+{
+ *outWChar = ( wchar_t )( ( unsigned short )( ( unsigned char )( *inChar ) ) );
+ return 1;
+}
+
+
diff --git a/src/pal/src/safecrt/mbusafecrt_internal.h b/src/pal/src/safecrt/mbusafecrt_internal.h
new file mode 100644
index 0000000000..9a3aa1ca90
--- /dev/null
+++ b/src/pal/src/safecrt/mbusafecrt_internal.h
@@ -0,0 +1,88 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+* mbusafecrt_internal.h - internal declarations for SafeCRT functions
+*
+
+*
+* Purpose:
+* This file contains the internal declarations SafeCRT
+* functions ported to MacOS. These are the safe versions of
+* functions standard functions banned by SWI
+****/
+
+/* shields! */
+
+#ifndef MBUSAFECRT_INTERNAL_H
+#define MBUSAFECRT_INTERNAL_H
+
+#include "pal_char16.h"
+#include "pal_mstypes.h"
+
+typedef __builtin_va_list va_list;
+
+// The ifdef below are to accommodate Unix build
+// that complains about them being declared in stdarg.h already.
+#ifndef va_start
+#define va_start __builtin_va_start
+#endif
+#ifndef va_end
+#define va_end __builtin_va_end
+#endif
+
+#include "mbusafecrt.h"
+
+#ifdef EOF
+#undef EOF
+#endif
+#define EOF -1
+
+#ifdef WEOF
+#undef WEOF
+#endif
+#define WEOF -1
+
+#define CASSERT(p) extern int sanity_check_dummy[1+((!(p))*(-2))];
+
+extern tSafeCRT_AssertFuncPtr sMBUSafeCRTAssertFunc;
+
+typedef struct miniFILE_struct
+{
+ char* _ptr;
+ int _cnt;
+ char* _base;
+ int _flag;
+} miniFILE;
+
+#define _IOSTRG 1
+#define _IOWRT 2
+#define _IOREAD 4
+#define _IOMYBUF 8
+
+int _putc_nolock( char inChar, miniFILE* inStream );
+int _putwc_nolock( wchar_t inChar, miniFILE* inStream );
+int _getc_nolock( miniFILE* inStream );
+int _getwc_nolock( miniFILE* inStream );
+int _ungetc_nolock( char inChar, miniFILE* inStream );
+int _ungetwc_nolock( wchar_t inChar, miniFILE* inStream );
+
+errno_t _safecrt_cfltcvt(double *arg, char *buffer, size_t sizeInBytes, int type, int precision, int flags);
+
+void _safecrt_fassign(int flag, void* argument, char * number );
+void _safecrt_wfassign(int flag, void* argument, wchar_t * number );
+
+int _minimal_chartowchar( wchar_t* outWChar, const char* inChar );
+
+int _output_s( miniFILE* outfile, const char* _Format, va_list _ArgList);
+int _woutput_s( miniFILE* outfile, const wchar_t* _Format, va_list _ArgList);
+int _output( miniFILE *outfile, const char* _Format, va_list _ArgList);
+
+int _soutput_s( char *_Dst, size_t _Size, const char *_Format, va_list _ArgList );
+int _swoutput_s( wchar_t *_Dst, size_t _Size, const wchar_t *_Format, va_list _ArgList );
+
+int __tinput_s( miniFILE* inFile, const unsigned char * inFormat, va_list inArgList );
+int __twinput_s( miniFILE* inFile, const wchar_t * inFormat, va_list inArgList );
+
+#endif /* MBUSAFECRT_INTERNAL_H */
diff --git a/src/pal/src/safecrt/memcpy_s.c b/src/pal/src/safecrt/memcpy_s.c
new file mode 100644
index 0000000000..27aeb79665
--- /dev/null
+++ b/src/pal/src/safecrt/memcpy_s.c
@@ -0,0 +1,82 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*memcpy_s.c - contains memcpy_s routine
+*
+
+*
+*Purpose:
+* memcpy_s() copies a source memory buffer to a destination buffer.
+* Overlapping buffers are not treated specially, so propagation may occur.
+*
+*Revision History:
+* 10-07-03 AC Module created.
+* 03-10-04 AC Return ERANGE when buffer is too small
+* 01-14-05 AC Prefast (espx) fixes
+*
+*******************************************************************************/
+
+#include <string.h>
+#include <errno.h>
+#include <assert.h>
+#include "internal_securecrt.h"
+#include "mbusafecrt_internal.h"
+
+/***
+*memcpy_s - Copy source buffer to destination buffer
+*
+*Purpose:
+* memcpy_s() copies a source memory buffer to a destination memory buffer.
+* This routine does NOT recognize overlapping buffers, and thus can lead
+* to propagation.
+*
+* For cases where propagation must be avoided, memmove_s() must be used.
+*
+*Entry:
+* void *dst = pointer to destination buffer
+* size_t sizeInBytes = size in bytes of the destination buffer
+* const void *src = pointer to source buffer
+* size_t count = number of bytes to copy
+*
+*Exit:
+* Returns 0 if everything is ok, else return the error code.
+*
+*Exceptions:
+* Input parameters are validated. Refer to the validation section of the function.
+* On error, the error code is returned and the destination buffer is zeroed.
+*
+*******************************************************************************/
+
+errno_t __cdecl memcpy_s(
+ void * dst,
+ size_t sizeInBytes,
+ const void * src,
+ size_t count
+)
+{
+ if (count == 0)
+ {
+ /* nothing to do */
+ return 0;
+ }
+
+ /* validation section */
+ _VALIDATE_RETURN_ERRCODE(dst != NULL, EINVAL);
+ if (src == NULL || sizeInBytes < count)
+ {
+ /* zeroes the destination buffer */
+ memset(dst, 0, sizeInBytes);
+
+ _VALIDATE_RETURN_ERRCODE(src != NULL, EINVAL);
+ _VALIDATE_RETURN_ERRCODE(sizeInBytes >= count, ERANGE);
+ /* useless, but prefast is confused */
+ return EINVAL;
+ }
+
+ UINT_PTR x = (UINT_PTR)dst, y = (UINT_PTR)src;
+ assert((x + count <= y) || (y + count <= x));
+ memcpy(dst, src, count);
+ return 0;
+}
diff --git a/src/pal/src/safecrt/memmove_s.c b/src/pal/src/safecrt/memmove_s.c
new file mode 100644
index 0000000000..a0ae5f7ea6
--- /dev/null
+++ b/src/pal/src/safecrt/memmove_s.c
@@ -0,0 +1,69 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*memmove_s.c - contains memmove_s routine
+*
+
+*
+*Purpose:
+* memmove_s() copies a source memory buffer to a destination buffer.
+* Overlapping buffers are treated specially, to avoid propagation.
+*
+*Revision History:
+* 10-07-03 AC Module created.
+* 03-10-04 AC Return ERANGE when buffer is too small
+*
+*******************************************************************************/
+
+#include <string.h>
+#include <errno.h>
+#include "internal_securecrt.h"
+#include "mbusafecrt_internal.h"
+
+/***
+*memmove - Copy source buffer to destination buffer
+*
+*Purpose:
+* memmove() copies a source memory buffer to a destination memory buffer.
+* This routine recognize overlapping buffers to avoid propagation.
+*
+* For cases where propagation is not a problem, memcpy_s() can be used.
+*
+*Entry:
+* void *dst = pointer to destination buffer
+* size_t sizeInBytes = size in bytes of the destination buffer
+* const void *src = pointer to source buffer
+* size_t count = number of bytes to copy
+*
+*Exit:
+* Returns 0 if everything is ok, else return the error code.
+*
+*Exceptions:
+* Input parameters are validated. Refer to the validation section of the function.
+* On error, the error code is returned. Nothing is written to the destination buffer.
+*
+*******************************************************************************/
+
+errno_t __cdecl memmove_s(
+ void * dst,
+ size_t sizeInBytes,
+ const void * src,
+ size_t count
+)
+{
+ if (count == 0)
+ {
+ /* nothing to do */
+ return 0;
+ }
+
+ /* validation section */
+ _VALIDATE_RETURN_ERRCODE(dst != NULL, EINVAL);
+ _VALIDATE_RETURN_ERRCODE(src != NULL, EINVAL);
+ _VALIDATE_RETURN_ERRCODE(sizeInBytes >= count, ERANGE);
+
+ memmove(dst, src, count);
+ return 0;
+}
diff --git a/src/pal/src/safecrt/output.inl b/src/pal/src/safecrt/output.inl
new file mode 100644
index 0000000000..ae0692efc5
--- /dev/null
+++ b/src/pal/src/safecrt/output.inl
@@ -0,0 +1,1624 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*output.c - printf style output to a FILE
+*
+
+*
+*Purpose:
+* This file contains the code that does all the work for the
+* printf family of functions. It should not be called directly, only
+* by the *printf functions. We don't make any assumtions about the
+* sizes of ints, longs, shorts, or long doubles, but if types do overlap,
+* we also try to be efficient. We do assume that pointers are the same
+* size as either ints or longs.
+* If CPRFLAG is defined, defines _cprintf instead.
+* **** DOESN'T CURRENTLY DO MTHREAD LOCKING ****
+*
+*Note:
+* this file is included in safecrt.lib build directly, plese refer
+* to safecrt_[w]output_s.c
+*
+*******************************************************************************/
+
+
+//typedef __int64_t __int64;
+
+
+#define FORMAT_VALIDATIONS
+
+typedef double _CRT_DOUBLE;
+
+//typedef int* intptr_t;
+
+/*
+Buffer size required to be passed to _gcvt, fcvt and other fp conversion routines
+*/
+#define _CVTBUFSIZE (309+40) /* # of digits in max. dp value + slop */
+
+/* temporary work-around for compiler without 64-bit support */
+#ifndef _INTEGRAL_MAX_BITS
+#define _INTEGRAL_MAX_BITS 64
+#endif /* _INTEGRAL_MAX_BITS */
+
+//#include <mtdll.h>
+//#include <cruntime.h>
+//#include <limits.h>
+//#include <string.h>
+//#include <stddef.h>
+//#include <crtdefs.h>
+//#include <stdio.h>
+//#include <stdarg.h>
+//#include <cvt.h>
+//#include <conio.h>
+//#include <internal.h>
+//#include <fltintrn.h>
+//#include <stdlib.h>
+//#include <ctype.h>
+//#include <dbgint.h>
+//#include <setlocal.h>
+
+#define _MBTOWC(x,y,z) _minimal_chartowchar( x, y )
+
+#ifndef _WCTOMB_S
+#define _WCTOMB_S wctomb_s
+#endif /* _WCTOMB_S */
+
+#undef _malloc_crt
+#define _malloc_crt malloc
+
+#undef _free_crt
+#define _free_crt free
+
+/* Wrapper for _output_s so that we do not expose FILE in the _output_s signature.
+ * Always ensure null-termination. Returns the number of written chars, not including the terminating null.
+ * Returns -1 if something went wrong during the formatting (in _output_s), e.g. mbcs conversions.
+ * Returns -2 if the string has been truncated.
+ * _output_s calls _invalid_parameter (and returns -1, possibly) if the format string is malformed.
+ */
+#ifndef _UNICODE
+int __cdecl _soutput_s(char *_Dst, size_t _Size, const char *_Format, va_list _ArgList)
+#else /* _UNICODE */
+int __cdecl _swoutput_s(wchar_t *_Dst, size_t _Size, const wchar_t *_Format, va_list _ArgList)
+#endif /* _UNICODE */
+{
+ miniFILE stream;
+ miniFILE *outfile = &stream;
+ int written = -1;
+
+ /* validation section */
+#ifndef _UNICODE
+ if(_Size==SIZE_MAX)
+ {
+ /* user is attempting to make us unbounded, but we don't fit that much */
+ outfile->_cnt = INT_MAX;
+ }
+ else
+ {
+ _VALIDATE_RETURN(_Size <= INT_MAX, EINVAL, -1);
+ outfile->_cnt = (int)_Size;
+ }
+ outfile->_ptr = outfile->_base = _Dst;
+#else /* _UNICODE */
+ if(_Size==SIZE_MAX)
+ {
+ /* user is attempting to make us unbounded, but we don't fit that much */
+ outfile->_cnt = INT_MAX;
+ }
+ else if(_Size>(INT_MAX/sizeof(wchar_t)))
+ {
+ /* we can't represent the amount of output the user asked for */
+ _VALIDATE_RETURN( 0 /* FALSE */, EINVAL, -1 );
+ }
+ else
+ {
+ outfile->_cnt = (int)(_Size*sizeof(wchar_t));
+ }
+ outfile->_ptr = outfile->_base = (char*)_Dst;
+#endif /* _UNICODE */
+ outfile->_flag = _IOWRT | _IOSTRG;
+
+#ifndef _UNICODE
+ written = _output_s(outfile, _Format, _ArgList);
+#else /* _UNICODE */
+ written = _woutput_s(outfile, _Format, _ArgList);
+#endif /* _UNICODE */
+ _Dst[_Size - 1] = 0;
+ if (written < 0)
+ {
+ if (outfile->_cnt < 0)
+ {
+ /* the buffer was too small; we return -2 to indicate truncation */
+ return -2;
+ }
+ /* otherwise, something else failed: we reset the string and we return */
+ if (_Dst != NULL && _Size > 0)
+ {
+ *_Dst = 0;
+ }
+ return written;
+ }
+
+#ifndef _UNICODE
+ if ((_putc_nolock('\0', outfile) != EOF))
+#else /* _UNICODE */
+ if ((_putc_nolock('\0', outfile) != EOF) && (_putc_nolock('\0', outfile) != EOF))
+#endif /* _UNICODE */
+ {
+ return written;
+ }
+ /* the last putc failed, so it means there is not enough space in the buffer */
+ return -2;
+}
+
+
+#ifndef _CFLTCVT
+#define _CFLTCVT _cfltcvt
+#endif /* _CFLTCVT */
+
+#ifndef _CLDCVT
+#define _CLDCVT _cldcvt
+#endif /* _CLDCVT */
+
+#ifdef _MBCS
+#undef _MBCS
+#endif /* _MBCS */
+//#include <tchar.h>
+
+/* this macro defines a function which is private and as fast as possible: */
+/* for example, in C 6.0, it might be static _fastcall <type> near. */
+#define LOCAL(x) static x __cdecl
+
+/* int/long/short/pointer sizes */
+
+/* the following should be set depending on the sizes of various types */
+#if __LP64__
+ #define LONG_IS_INT 0
+ CASSERT(sizeof(long) > sizeof(int));
+#else
+ #define LONG_IS_INT 1 /* 1 means long is same size as int */
+ CASSERT(sizeof(long) == sizeof(int));
+#endif
+
+#define SHORT_IS_INT 0 /* 1 means short is same size as int */
+#define LONGLONG_IS_INT64 1 /* 1 means long long is same as int64 */
+#if defined (_WIN64)
+ #define PTR_IS_INT 0 /* 1 means ptr is same size as int */
+ CASSERT(sizeof(void *) != sizeof(int));
+ #if __LP64__
+ #define PTR_IS_LONG 1 /* 1 means ptr is same size as long */
+ CASSERT(sizeof(void *) == sizeof(long));
+ #else
+ #define PTR_IS_LONG 0 /* 1 means ptr is same size as long */
+ CASSERT(sizeof(void *) != sizeof(long));
+ #endif
+ #define PTR_IS_INT64 1 /* 1 means ptr is same size as int64 */
+ CASSERT(sizeof(void *) == sizeof(int64_t));
+#else /* defined (_WIN64) */
+ #define PTR_IS_INT 1 /* 1 means ptr is same size as int */
+ CASSERT(sizeof(void *) == sizeof(int));
+ #define PTR_IS_LONG 1 /* 1 means ptr is same size as long */
+ CASSERT(sizeof(void *) == sizeof(long));
+ #define PTR_IS_INT64 0 /* 1 means ptr is same size as int64 */
+ CASSERT(sizeof(void *) != sizeof(int64_t));
+#endif /* defined (_WIN64) */
+
+/* CONSTANTS */
+
+/* size of conversion buffer (ANSI-specified minimum is 509) */
+
+#define BUFFERSIZE 512
+#define MAXPRECISION BUFFERSIZE
+
+#if BUFFERSIZE < _CVTBUFSIZE + 6
+/*
+ * Buffer needs to be big enough for default minimum precision
+ * when converting floating point needs bigger buffer, and malloc
+ * fails
+ */
+#error Conversion buffer too small for max double.
+#endif /* BUFFERSIZE < _CVTBUFSIZE + 6 */
+
+/* flag definitions */
+#define FL_SIGN 0x00001 /* put plus or minus in front */
+#define FL_SIGNSP 0x00002 /* put space or minus in front */
+#define FL_LEFT 0x00004 /* left justify */
+#define FL_LEADZERO 0x00008 /* pad with leading zeros */
+#define FL_LONG 0x00010 /* long value given */
+#define FL_SHORT 0x00020 /* short value given */
+#define FL_SIGNED 0x00040 /* signed data given */
+#define FL_ALTERNATE 0x00080 /* alternate form requested */
+#define FL_NEGATIVE 0x00100 /* value is negative */
+#define FL_FORCEOCTAL 0x00200 /* force leading '0' for octals */
+#define FL_LONGDOUBLE 0x00400 /* long double value given */
+#define FL_WIDECHAR 0x00800 /* wide characters */
+#define FL_LONGLONG 0x01000 /* long long value given */
+#define FL_I64 0x08000 /* __int64 value given */
+
+/* state definitions */
+enum STATE {
+ ST_NORMAL, /* normal state; outputting literal chars */
+ ST_PERCENT, /* just read '%' */
+ ST_FLAG, /* just read flag character */
+ ST_WIDTH, /* just read width specifier */
+ ST_DOT, /* just read '.' */
+ ST_PRECIS, /* just read precision specifier */
+ ST_SIZE, /* just read size specifier */
+ ST_TYPE /* just read type specifier */
+#ifdef FORMAT_VALIDATIONS
+ ,ST_INVALID /* Invalid format */
+#endif /* FORMAT_VALIDATIONS */
+
+};
+
+#ifdef FORMAT_VALIDATIONS
+#define NUMSTATES (ST_INVALID + 1)
+#else /* FORMAT_VALIDATIONS */
+#define NUMSTATES (ST_TYPE + 1)
+#endif /* FORMAT_VALIDATIONS */
+
+/* character type values */
+enum CHARTYPE {
+ CH_OTHER, /* character with no special meaning */
+ CH_PERCENT, /* '%' */
+ CH_DOT, /* '.' */
+ CH_STAR, /* '*' */
+ CH_ZERO, /* '0' */
+ CH_DIGIT, /* '1'..'9' */
+ CH_FLAG, /* ' ', '+', '-', '#' */
+ CH_SIZE, /* 'h', 'l', 'L', 'N', 'F', 'w' */
+ CH_TYPE /* type specifying character */
+};
+
+/* static data (read only, since we are re-entrant) */
+//#if defined (_UNICODE) || defined (CPRFLAG) || defined (FORMAT_VALIDATIONS)
+//extern const char __nullstring[]; /* string to print on null ptr */
+//extern const wchar_t __wnullstring[]; /* string to print on null ptr */
+//#else /* defined (_UNICODE) || defined (CPRFLAG) || defined (FORMAT_VALIDATIONS) */
+static const char __nullstring[] = "(null)"; /* string to print on null ptr */
+static const wchar_t __wnullstring[] = {'(', 'n', 'u', 'l', 'l', ')', '\0'};/* string to print on null ptr */
+//#endif /* defined (_UNICODE) || defined (CPRFLAG) || defined (FORMAT_VALIDATIONS) */
+
+/* The state table. This table is actually two tables combined into one. */
+/* The lower nybble of each byte gives the character class of any */
+/* character; while the uper nybble of the byte gives the next state */
+/* to enter. See the macros below the table for details. */
+/* */
+/* The table is generated by maketabc.c -- use this program to make */
+/* changes. */
+
+#ifndef FORMAT_VALIDATIONS
+
+//#if defined (_UNICODE) || defined (CPRFLAG)
+//extern const char __lookuptable[];
+//#else /* defined (_UNICODE) || defined (CPRFLAG) */
+extern const char __lookuptable[] = {
+ /* ' ' */ 0x06,
+ /* '!' */ 0x00,
+ /* '"' */ 0x00,
+ /* '#' */ 0x06,
+ /* '$' */ 0x00,
+ /* '%' */ 0x01,
+ /* '&' */ 0x00,
+ /* ''' */ 0x00,
+ /* '(' */ 0x10,
+ /* ')' */ 0x00,
+ /* '*' */ 0x03,
+ /* '+' */ 0x06,
+ /* ',' */ 0x00,
+ /* '-' */ 0x06,
+ /* '.' */ 0x02,
+ /* '/' */ 0x10,
+ /* '0' */ 0x04,
+ /* '1' */ 0x45,
+ /* '2' */ 0x45,
+ /* '3' */ 0x45,
+ /* '4' */ 0x05,
+ /* '5' */ 0x05,
+ /* '6' */ 0x05,
+ /* '7' */ 0x05,
+ /* '8' */ 0x05,
+ /* '9' */ 0x35,
+ /* ':' */ 0x30,
+ /* ';' */ 0x00,
+ /* '<' */ 0x50,
+ /* '=' */ 0x00,
+ /* '>' */ 0x00,
+ /* '?' */ 0x00,
+ /* '@' */ 0x00,
+ /* 'A' */ 0x20, // Disable %A format
+ /* 'B' */ 0x20,
+ /* 'C' */ 0x38,
+ /* 'D' */ 0x50,
+ /* 'E' */ 0x58,
+ /* 'F' */ 0x07,
+ /* 'G' */ 0x08,
+ /* 'H' */ 0x00,
+ /* 'I' */ 0x37,
+ /* 'J' */ 0x30,
+ /* 'K' */ 0x30,
+ /* 'L' */ 0x57,
+ /* 'M' */ 0x50,
+ /* 'N' */ 0x07,
+ /* 'O' */ 0x00,
+ /* 'P' */ 0x00,
+ /* 'Q' */ 0x20,
+ /* 'R' */ 0x20,
+ /* 'S' */ 0x08,
+ /* 'T' */ 0x00,
+ /* 'U' */ 0x00,
+ /* 'V' */ 0x00,
+ /* 'W' */ 0x00,
+ /* 'X' */ 0x08,
+ /* 'Y' */ 0x60,
+ /* 'Z' */ 0x68,
+ /* '[' */ 0x60,
+ /* '\' */ 0x60,
+ /* ']' */ 0x60,
+ /* '^' */ 0x60,
+ /* '_' */ 0x00,
+ /* '`' */ 0x00,
+ /* 'a' */ 0x70, // Disable %a format
+ /* 'b' */ 0x70,
+ /* 'c' */ 0x78,
+ /* 'd' */ 0x78,
+ /* 'e' */ 0x78,
+ /* 'f' */ 0x78,
+ /* 'g' */ 0x08,
+ /* 'h' */ 0x07,
+ /* 'i' */ 0x08,
+ /* 'j' */ 0x00,
+ /* 'k' */ 0x00,
+ /* 'l' */ 0x07,
+ /* 'm' */ 0x00,
+ /* 'n' */ 0x00, // Disable %n format
+ /* 'o' */ 0x08,
+ /* 'p' */ 0x08,
+ /* 'q' */ 0x00,
+ /* 'r' */ 0x00,
+ /* 's' */ 0x08,
+ /* 't' */ 0x00,
+ /* 'u' */ 0x08,
+ /* 'v' */ 0x00,
+ /* 'w' */ 0x07,
+ /* 'x' */ 0x08
+};
+
+//#endif /* defined (_UNICODE) || defined (CPRFLAG) */
+
+#else /* FORMAT_VALIDATIONS */
+
+//#if defined (_UNICODE) || defined (CPRFLAG)
+//extern const unsigned char __lookuptable_s[];
+//#else /* defined (_UNICODE) || defined (CPRFLAG) */
+static const unsigned char __lookuptable_s[] = {
+ /* ' ' */ 0x06,
+ /* '!' */ 0x80,
+ /* '"' */ 0x80,
+ /* '#' */ 0x86,
+ /* '$' */ 0x80,
+ /* '%' */ 0x81,
+ /* '&' */ 0x80,
+ /* ''' */ 0x00,
+ /* '(' */ 0x00,
+ /* ')' */ 0x10,
+ /* '*' */ 0x03,
+ /* '+' */ 0x86,
+ /* ',' */ 0x80,
+ /* '-' */ 0x86,
+ /* '.' */ 0x82,
+ /* '/' */ 0x80,
+ /* '0' */ 0x14,
+ /* '1' */ 0x05,
+ /* '2' */ 0x05,
+ /* '3' */ 0x45,
+ /* '4' */ 0x45,
+ /* '5' */ 0x45,
+ /* '6' */ 0x85,
+ /* '7' */ 0x85,
+ /* '8' */ 0x85,
+ /* '9' */ 0x05,
+ /* ':' */ 0x00,
+ /* ';' */ 0x00,
+ /* '<' */ 0x30,
+ /* '=' */ 0x30,
+ /* '>' */ 0x80,
+ /* '?' */ 0x50,
+ /* '@' */ 0x80,
+ /* 'A' */ 0x80, // Disable %A format
+ /* 'B' */ 0x00,
+ /* 'C' */ 0x08,
+ /* 'D' */ 0x00,
+ /* 'E' */ 0x28,
+ /* 'F' */ 0x27,
+ /* 'G' */ 0x38,
+ /* 'H' */ 0x50,
+ /* 'I' */ 0x57,
+ /* 'J' */ 0x80,
+ /* 'K' */ 0x00,
+ /* 'L' */ 0x07,
+ /* 'M' */ 0x00,
+ /* 'N' */ 0x37,
+ /* 'O' */ 0x30,
+ /* 'P' */ 0x30,
+ /* 'Q' */ 0x50,
+ /* 'R' */ 0x50,
+ /* 'S' */ 0x88,
+ /* 'T' */ 0x00,
+ /* 'U' */ 0x00,
+ /* 'V' */ 0x00,
+ /* 'W' */ 0x20,
+ /* 'X' */ 0x28,
+ /* 'Y' */ 0x80,
+ /* 'Z' */ 0x88,
+ /* '[' */ 0x80,
+ /* '\' */ 0x80,
+ /* ']' */ 0x00,
+ /* '^' */ 0x00,
+ /* '_' */ 0x00,
+ /* '`' */ 0x60,
+ /* 'a' */ 0x60, // Disable %a format
+ /* 'b' */ 0x60,
+ /* 'c' */ 0x68,
+ /* 'd' */ 0x68,
+ /* 'e' */ 0x68,
+ /* 'f' */ 0x08,
+ /* 'g' */ 0x08,
+ /* 'h' */ 0x07,
+ /* 'i' */ 0x78,
+ /* 'j' */ 0x70,
+ /* 'k' */ 0x70,
+ /* 'l' */ 0x77,
+ /* 'm' */ 0x70,
+ /* 'n' */ 0x70,
+ /* 'o' */ 0x08,
+ /* 'p' */ 0x08,
+ /* 'q' */ 0x00,
+ /* 'r' */ 0x00,
+ /* 's' */ 0x08,
+ /* 't' */ 0x00,
+ /* 'u' */ 0x08,
+ /* 'v' */ 0x00,
+ /* 'w' */ 0x07,
+ /* 'x' */ 0x08
+};
+//#endif /* defined (_UNICODE) || defined (CPRFLAG) */
+
+#endif /* FORMAT_VALIDATIONS */
+
+#define FIND_CHAR_CLASS(lookuptbl, c) \
+ ((c) < _T(' ') || (c) > _T('x') ? \
+ CH_OTHER \
+ : \
+ (enum CHARTYPE)(lookuptbl[(c)-_T(' ')] & 0xF))
+
+#define FIND_NEXT_STATE(lookuptbl, class, state) \
+ (enum STATE)(lookuptbl[(class) * NUMSTATES + (state)] >> 4)
+
+/*
+ * Note: CPRFLAG and _UNICODE cases are currently mutually exclusive.
+ */
+
+/* prototypes */
+
+#ifdef CPRFLAG
+
+#define WRITE_CHAR(ch, pnw) write_char(ch, pnw)
+#define WRITE_MULTI_CHAR(ch, num, pnw) write_multi_char(ch, num, pnw)
+#define WRITE_STRING(s, len, pnw) write_string(s, len, pnw)
+
+LOCAL(void) write_char(_TCHAR ch, int *pnumwritten);
+LOCAL(void) write_multi_char(_TCHAR ch, int num, int *pnumwritten);
+LOCAL(void) write_string(const _TCHAR *string, int len, int *numwritten);
+
+#else /* CPRFLAG */
+
+#define WRITE_CHAR(ch, pnw) write_char(ch, stream, pnw)
+#define WRITE_MULTI_CHAR(ch, num, pnw) write_multi_char(ch, num, stream, pnw)
+#define WRITE_STRING(s, len, pnw) write_string(s, len, stream, pnw)
+
+LOCAL(void) write_char(_TCHAR ch, miniFILE *f, int *pnumwritten);
+LOCAL(void) write_multi_char(_TCHAR ch, int num, miniFILE *f, int *pnumwritten);
+LOCAL(void) write_string(const _TCHAR *string, int len, miniFILE *f, int *numwritten);
+
+#endif /* CPRFLAG */
+
+#define get_int_arg(list) va_arg(*list, int)
+#define get_long_arg(list) va_arg(*list, long)
+#define get_long_long_arg(list) va_arg(*list, long long)
+#define get_int64_arg(list) va_arg(*list, __int64)
+#define get_crtdouble_arg(list) va_arg(*list, _CRT_DOUBLE)
+#define get_ptr_arg(list) va_arg(*list, void *)
+
+#ifdef CPRFLAG
+LOCAL(int) output(const _TCHAR *, _locale_t , va_list);
+_CRTIMP int __cdecl _vtcprintf_l (const _TCHAR *, _locale_t, va_list);
+_CRTIMP int __cdecl _vtcprintf_s_l (const _TCHAR *, _locale_t, va_list);
+_CRTIMP int __cdecl _vtcprintf_p_l (const _TCHAR *, _locale_t, va_list);
+
+
+/***
+*int _cprintf(format, arglist) - write formatted output directly to console
+*
+*Purpose:
+* Writes formatted data like printf, but uses console I/O functions.
+*
+*Entry:
+* char *format - format string to determine data formats
+* arglist - list of POINTERS to where to put data
+*
+*Exit:
+* returns number of characters written
+*
+*Exceptions:
+*
+*******************************************************************************/
+#ifndef FORMAT_VALIDATIONS
+_CRTIMP int __cdecl _tcprintf_l (
+ const _TCHAR * format,
+ _locale_t plocinfo,
+ ...
+ )
+#else /* FORMAT_VALIDATIONS */
+_CRTIMP int __cdecl _tcprintf_s_l (
+ const _TCHAR * format,
+ _locale_t plocinfo,
+ ...
+ )
+#endif /* FORMAT_VALIDATIONS */
+
+{
+ int ret;
+ va_list arglist;
+ va_start(arglist, plocinfo);
+
+#ifndef FORMAT_VALIDATIONS
+ ret = _vtcprintf_l(format, plocinfo, arglist);
+#else /* FORMAT_VALIDATIONS */
+ ret = _vtcprintf_s_l(format, plocinfo, arglist);
+
+#endif /* FORMAT_VALIDATIONS */
+
+ va_end(arglist);
+
+ return ret;
+}
+
+#ifndef FORMAT_VALIDATIONS
+_CRTIMP int __cdecl _tcprintf (
+ const _TCHAR * format,
+ ...
+ )
+#else /* FORMAT_VALIDATIONS */
+_CRTIMP int __cdecl _tcprintf_s (
+ const _TCHAR * format,
+ ...
+ )
+#endif /* FORMAT_VALIDATIONS */
+
+{
+ int ret;
+ va_list arglist;
+
+ va_start(arglist, format);
+
+#ifndef FORMAT_VALIDATIONS
+ ret = _vtcprintf_l(format, NULL, arglist);
+#else /* FORMAT_VALIDATIONS */
+ ret = _vtcprintf_s_l(format, NULL, arglist);
+
+#endif /* FORMAT_VALIDATIONS */
+
+ va_end(arglist);
+
+ return ret;
+}
+
+#endif /* CPRFLAG */
+
+
+/***
+*int _output(stream, format, argptr), static int output(format, argptr)
+*
+*Purpose:
+* Output performs printf style output onto a stream. It is called by
+* printf/fprintf/sprintf/vprintf/vfprintf/vsprintf to so the dirty
+* work. In multi-thread situations, _output assumes that the given
+* stream is already locked.
+*
+* Algorithm:
+* The format string is parsed by using a finite state automaton
+* based on the current state and the current character read from
+* the format string. Thus, looping is on a per-character basis,
+* not a per conversion specifier basis. Once the format specififying
+* character is read, output is performed.
+*
+*Entry:
+* FILE *stream - stream for output
+* char *format - printf style format string
+* va_list argptr - pointer to list of subsidiary arguments
+*
+*Exit:
+* Returns the number of characters written, or -1 if an output error
+* occurs.
+*ifdef _UNICODE
+* The wide-character flavour returns the number of wide-characters written.
+*endif
+*
+*Exceptions:
+*
+*******************************************************************************/
+#ifdef CPRFLAG
+#ifndef FORMAT_VALIDATIONS
+_CRTIMP int __cdecl _vtcprintf (
+ const _TCHAR *format,
+ va_list argptr
+ )
+{
+ return _vtcprintf_l(format, NULL, argptr);
+}
+
+#else /* FORMAT_VALIDATIONS */
+_CRTIMP int __cdecl _vtcprintf_s (
+ const _TCHAR *format,
+ va_list argptr
+ )
+{
+ return _vtcprintf_s_l(format, NULL, argptr);
+}
+
+#endif /* FORMAT_VALIDATIONS */
+#endif /* CPRFLAG */
+
+#ifdef CPRFLAG
+#ifndef FORMAT_VALIDATIONS
+_CRTIMP int __cdecl _vtcprintf_l (
+#else /* FORMAT_VALIDATIONS */
+_CRTIMP int __cdecl _vtcprintf_s_l (
+#endif /* FORMAT_VALIDATIONS */
+#else /* CPRFLAG */
+
+#ifdef _UNICODE
+#ifndef FORMAT_VALIDATIONS
+int __cdecl _woutput (
+ miniFILE *stream,
+#else /* FORMAT_VALIDATIONS */
+int __cdecl _woutput_s (
+ miniFILE *stream,
+#endif /* FORMAT_VALIDATIONS */
+#else /* _UNICODE */
+#ifndef FORMAT_VALIDATIONS
+int __cdecl _output (
+ miniFILE *stream,
+#else /* FORMAT_VALIDATIONS */
+ int __cdecl _output_s (
+ miniFILE *stream,
+
+#endif /* FORMAT_VALIDATIONS */
+#endif /* _UNICODE */
+
+#endif /* CPRFLAG */
+ const _TCHAR *format,
+ va_list argptr
+ )
+{
+ int hexadd=0; /* offset to add to number to get 'a'..'f' */
+ TCHAR ch; /* character just read */
+ int flags=0; /* flag word -- see #defines above for flag values */
+ enum STATE state; /* current state */
+ enum CHARTYPE chclass; /* class of current character */
+ int radix; /* current conversion radix */
+ int charsout; /* characters currently written so far, -1 = IO error */
+ int fldwidth = 0; /* selected field width -- 0 means default */
+ int precision = 0; /* selected precision -- -1 means default */
+ TCHAR prefix[2]; /* numeric prefix -- up to two characters */
+ int prefixlen=0; /* length of prefix -- 0 means no prefix */
+ int capexp = 0; /* non-zero = 'E' exponent signifient, zero = 'e' */
+ int no_output=0; /* non-zero = prodcue no output for this specifier */
+ union {
+ const char *sz; /* pointer text to be printed, not zero terminated */
+ const wchar_t *wz;
+ } text;
+
+ int textlen; /* length of the text in bytes/wchars to be printed.
+ textlen is in multibyte or wide chars if _UNICODE */
+ union {
+ char sz[BUFFERSIZE];
+#ifdef _UNICODE
+ wchar_t wz[BUFFERSIZE];
+#endif /* _UNICODE */
+ } buffer;
+ wchar_t wchar; /* temp wchar_t */
+ int buffersize; /* size of text.sz (used only for the call to _cfltcvt) */
+ int bufferiswide=0; /* non-zero = buffer contains wide chars already */
+
+#ifndef CPRFLAG
+ _VALIDATE_RETURN( (stream != NULL), EINVAL, -1);
+#endif /* CPRFLAG */
+ _VALIDATE_RETURN( (format != NULL), EINVAL, -1);
+
+ charsout = 0; /* no characters written yet */
+ textlen = 0; /* no text yet */
+ state = ST_NORMAL; /* starting state */
+ buffersize = 0;
+
+ /* main loop -- loop while format character exist and no I/O errors */
+ while ((ch = *format++) != _T('\0') && charsout >= 0) {
+#ifndef FORMAT_VALIDATIONS
+ chclass = FIND_CHAR_CLASS(__lookuptable, ch); /* find character class */
+ state = FIND_NEXT_STATE(__lookuptable, chclass, state); /* find next state */
+#else /* FORMAT_VALIDATIONS */
+ chclass = FIND_CHAR_CLASS(__lookuptable_s, ch); /* find character class */
+ state = FIND_NEXT_STATE(__lookuptable_s, chclass, state); /* find next state */
+
+ _VALIDATE_RETURN((state != ST_INVALID), EINVAL, -1);
+
+#endif /* FORMAT_VALIDATIONS */
+
+ /* execute code for each state */
+ switch (state) {
+
+ case ST_NORMAL:
+
+ NORMAL_STATE:
+
+ /* normal state -- just write character */
+#ifdef _UNICODE
+ bufferiswide = 1;
+#else /* _UNICODE */
+ bufferiswide = 0;
+#endif /* _UNICODE */
+ WRITE_CHAR(ch, &charsout);
+ break;
+
+ case ST_PERCENT:
+ /* set default value of conversion parameters */
+ prefixlen = fldwidth = no_output = capexp = 0;
+ flags = 0;
+ precision = -1;
+ bufferiswide = 0; /* default */
+ break;
+
+ case ST_FLAG:
+ /* set flag based on which flag character */
+ switch (ch) {
+ case _T('-'):
+ flags |= FL_LEFT; /* '-' => left justify */
+ break;
+ case _T('+'):
+ flags |= FL_SIGN; /* '+' => force sign indicator */
+ break;
+ case _T(' '):
+ flags |= FL_SIGNSP; /* ' ' => force sign or space */
+ break;
+ case _T('#'):
+ flags |= FL_ALTERNATE; /* '#' => alternate form */
+ break;
+ case _T('0'):
+ flags |= FL_LEADZERO; /* '0' => pad with leading zeros */
+ break;
+ }
+ break;
+
+ case ST_WIDTH:
+ /* update width value */
+ if (ch == _T('*')) {
+ /* get width from arg list */
+ fldwidth = get_int_arg(&argptr);
+ if (fldwidth < 0) {
+ /* ANSI says neg fld width means '-' flag and pos width */
+ flags |= FL_LEFT;
+ fldwidth = -fldwidth;
+ }
+ }
+ else {
+ /* add digit to current field width */
+ fldwidth = fldwidth * 10 + (ch - _T('0'));
+ }
+ break;
+
+ case ST_DOT:
+ /* zero the precision, since dot with no number means 0
+ not default, according to ANSI */
+ precision = 0;
+ break;
+
+ case ST_PRECIS:
+ /* update precison value */
+ if (ch == _T('*')) {
+ /* get precision from arg list */
+ precision = get_int_arg(&argptr);
+ if (precision < 0)
+ precision = -1; /* neg precision means default */
+ }
+ else {
+ /* add digit to current precision */
+ precision = precision * 10 + (ch - _T('0'));
+ }
+ break;
+
+ case ST_SIZE:
+ /* just read a size specifier, set the flags based on it */
+ switch (ch) {
+ case _T('l'):
+ /*
+ * In order to handle the ll case, we depart from the
+ * simple deterministic state machine.
+ */
+ if (*format == _T('l'))
+ {
+ ++format;
+ flags |= FL_LONGLONG; /* 'll' => long long */
+ }
+ else
+ {
+ flags |= FL_LONG; /* 'l' => long int or wchar_t */
+ }
+ break;
+
+ case _T('I'):
+ /*
+ * In order to handle the I, I32, and I64 size modifiers, we
+ * depart from the simple deterministic state machine. The
+ * code below scans for characters following the 'I',
+ * and defaults to 64 bit on WIN64 and 32 bit on WIN32
+ */
+#if PTR_IS_INT64
+ flags |= FL_I64; /* 'I' => __int64 on WIN64 systems */
+#endif /* PTR_IS_INT64 */
+ if ( (*format == _T('6')) && (*(format + 1) == _T('4')) )
+ {
+ format += 2;
+ flags |= FL_I64; /* I64 => __int64 */
+ }
+ else if ( (*format == _T('3')) && (*(format + 1) == _T('2')) )
+ {
+ format += 2;
+ flags &= ~FL_I64; /* I32 => __int32 */
+ }
+ else if ( (*format == _T('d')) ||
+ (*format == _T('i')) ||
+ (*format == _T('o')) ||
+ (*format == _T('u')) ||
+ (*format == _T('x')) ||
+ (*format == _T('X')) )
+ {
+ /*
+ * Nothing further needed. %Id (et al) is
+ * handled just like %d, except that it defaults to 64 bits
+ * on WIN64. Fall through to the next iteration.
+ */
+ }
+ else {
+ state = ST_NORMAL;
+ goto NORMAL_STATE;
+ }
+ break;
+
+ case _T('h'):
+ flags |= FL_SHORT; /* 'h' => short int or char */
+ break;
+
+ case _T('w'):
+ flags |= FL_WIDECHAR; /* 'w' => wide character */
+ break;
+
+ }
+ break;
+
+ case ST_TYPE:
+ /* we have finally read the actual type character, so we */
+ /* now format and "print" the output. We use a big switch */
+ /* statement that sets 'text' to point to the text that should */
+ /* be printed, and 'textlen' to the length of this text. */
+ /* Common code later on takes care of justifying it and */
+ /* other miscellaneous chores. Note that cases share code, */
+ /* in particular, all integer formatting is done in one place. */
+ /* Look at those funky goto statements! */
+
+ switch (ch) {
+
+ case _T('C'): /* ISO wide character */
+ if (!(flags & (FL_SHORT|FL_LONG|FL_WIDECHAR)))
+#ifdef _UNICODE
+ flags |= FL_SHORT;
+#else /* _UNICODE */
+ flags |= FL_WIDECHAR; /* ISO std. */
+#endif /* _UNICODE */
+ /* fall into 'c' case */
+
+ case _T('c'): {
+ /* print a single character specified by int argument */
+#ifdef _UNICODE
+ bufferiswide = 1;
+ wchar = (wchar_t) get_int_arg(&argptr);
+ if (flags & FL_SHORT) {
+ /* format multibyte character */
+ /* this is an extension of ANSI */
+ char tempchar[2];
+ {
+ tempchar[0] = (char)(wchar & 0x00ff);
+ tempchar[1] = '\0';
+ }
+
+ if (_MBTOWC(buffer.wz,tempchar, MB_CUR_MAX) < 0)
+ {
+ /* ignore if conversion was unsuccessful */
+ no_output = 1;
+ }
+ } else {
+ buffer.wz[0] = wchar;
+ }
+ text.wz = buffer.wz;
+ textlen = 1; /* print just a single character */
+#else /* _UNICODE */
+ if (flags & (FL_LONG|FL_WIDECHAR)) {
+ wchar = (wchar_t) get_int_arg(&argptr);
+ no_output = 1;
+ } else {
+ /* format multibyte character */
+ /* this is an extension of ANSI */
+ unsigned short temp;
+ wchar = (wchar_t)get_int_arg(&argptr);
+ temp = (unsigned short)wchar;
+ {
+ buffer.sz[0] = (char) temp;
+ textlen = 1;
+ }
+ }
+ text.sz = buffer.sz;
+#endif /* _UNICODE */
+ }
+ break;
+
+ case _T('Z'): {
+ /* print a Counted String */
+ struct _count_string {
+ short Length;
+ short MaximumLength;
+ char *Buffer;
+ } *pstr;
+
+ pstr = (struct _count_string *)get_ptr_arg(&argptr);
+ if (pstr == NULL || pstr->Buffer == NULL) {
+ /* null ptr passed, use special string */
+ text.sz = __nullstring;
+ textlen = (int)strlen(text.sz);
+ } else {
+ if (flags & FL_WIDECHAR) {
+ text.wz = (wchar_t *)pstr->Buffer;
+ textlen = pstr->Length / (int)sizeof(wchar_t);
+ bufferiswide = 1;
+ } else {
+ bufferiswide = 0;
+ text.sz = pstr->Buffer;
+ textlen = pstr->Length;
+ }
+ }
+ }
+ break;
+
+ case _T('S'): /* ISO wide character string */
+#ifndef _UNICODE
+ if (!(flags & (FL_SHORT|FL_LONG|FL_WIDECHAR)))
+ flags |= FL_WIDECHAR;
+#else /* _UNICODE */
+ if (!(flags & (FL_SHORT|FL_LONG|FL_WIDECHAR)))
+ flags |= FL_SHORT;
+#endif /* _UNICODE */
+
+ case _T('s'): {
+ /* print a string -- */
+ /* ANSI rules on how much of string to print: */
+ /* all if precision is default, */
+ /* min(precision, length) if precision given. */
+ /* prints '(null)' if a null string is passed */
+
+ int i;
+ const char *p; /* temps */
+ const wchar_t *pwch;
+
+ /* At this point it is tempting to use strlen(), but */
+ /* if a precision is specified, we're not allowed to */
+ /* scan past there, because there might be no null */
+ /* at all. Thus, we must do our own scan. */
+
+ i = (precision == -1) ? INT_MAX : precision;
+ text.sz = (char *)get_ptr_arg(&argptr);
+
+ /* scan for null upto i characters */
+#ifdef _UNICODE
+ if (flags & FL_SHORT) {
+ if (text.sz == NULL) /* NULL passed, use special string */
+ text.sz = __nullstring;
+ p = text.sz;
+ for (textlen=0; textlen<i && *p; textlen++) {
+ ++p;
+ }
+ /* textlen now contains length in multibyte chars */
+ } else {
+ if (text.wz == NULL) /* NULL passed, use special string */
+ text.wz = __wnullstring;
+ bufferiswide = 1;
+ pwch = text.wz;
+ while (i-- && *pwch)
+ ++pwch;
+ textlen = (int)(pwch - text.wz); /* in wchar_ts */
+ /* textlen now contains length in wide chars */
+ }
+#else /* _UNICODE */
+ if (flags & (FL_LONG|FL_WIDECHAR)) {
+ if (text.wz == NULL) /* NULL passed, use special string */
+ text.wz = __wnullstring;
+ bufferiswide = 1;
+ pwch = text.wz;
+ while ( i-- && *pwch )
+ ++pwch;
+ textlen = (int)(pwch - text.wz);
+ /* textlen now contains length in wide chars */
+ } else {
+ if (text.sz == NULL) /* NULL passed, use special string */
+ text.sz = __nullstring;
+ p = text.sz;
+ while (i-- && *p)
+ ++p;
+ textlen = (int)(p - text.sz); /* length of the string */
+ }
+
+#endif /* _UNICODE */
+ }
+ break;
+
+
+ case _T('n'): {
+ /* write count of characters seen so far into */
+ /* short/int/long thru ptr read from args */
+
+ void *p; /* temp */
+
+ p = get_ptr_arg(&argptr);
+
+ /* %n is disabled */
+ _VALIDATE_RETURN(("'n' format specifier disabled" && 0), EINVAL, -1);
+ break;
+
+ /* store chars out into short/long/int depending on flags */
+#if !LONG_IS_INT
+ if (flags & FL_LONG)
+ *(long *)p = charsout;
+ else
+#endif /* !LONG_IS_INT */
+
+#if !SHORT_IS_INT
+ if (flags & FL_SHORT)
+ *(short *)p = (short) charsout;
+ else
+#endif /* !SHORT_IS_INT */
+ *(int *)p = charsout;
+
+ no_output = 1; /* force no output */
+ }
+ break;
+
+ case _T('E'):
+ case _T('G'):
+ case _T('A'):
+ capexp = 1; /* capitalize exponent */
+ ch += _T('a') - _T('A'); /* convert format char to lower */
+ /* DROP THROUGH */
+ case _T('e'):
+ case _T('f'):
+ case _T('g'):
+ case _T('a'): {
+ /* floating point conversion -- we call cfltcvt routines */
+ /* to do the work for us. */
+ flags |= FL_SIGNED; /* floating point is signed conversion */
+ text.sz = buffer.sz; /* put result in buffer */
+ buffersize = BUFFERSIZE;
+
+ /* compute the precision value */
+ if (precision < 0)
+ precision = 6; /* default precision: 6 */
+ else if (precision == 0 && ch == _T('g'))
+ precision = 1; /* ANSI specified */
+ else if (precision > MAXPRECISION)
+ precision = MAXPRECISION;
+
+ if (precision > BUFFERSIZE - _CVTBUFSIZE) {
+ /* cap precision further */
+ precision = BUFFERSIZE - _CVTBUFSIZE;
+ }
+
+ /* for safecrt, we pass along the FL_ALTERNATE flag to _safecrt_cfltcvt */
+ if (flags & FL_ALTERNATE)
+ {
+ capexp |= FL_ALTERNATE;
+ }
+
+ _CRT_DOUBLE tmp;
+ tmp=va_arg(argptr, _CRT_DOUBLE);
+ /* Note: assumes ch is in ASCII range */
+ /* In safecrt, we provide a special version of _cfltcvt which internally calls printf (see safecrt_output_s.c) */
+ _CFLTCVT(&tmp, buffer.sz, buffersize, (char)ch, precision, capexp);
+
+ /* check if result was negative, save '-' for later */
+ /* and point to positive part (this is for '0' padding) */
+ if (*text.sz == '-') {
+ flags |= FL_NEGATIVE;
+ ++text.sz;
+ }
+
+ textlen = (int)strlen(text.sz); /* compute length of text */
+ }
+ break;
+
+ case _T('d'):
+ case _T('i'):
+ /* signed decimal output */
+ flags |= FL_SIGNED;
+ radix = 10;
+ goto COMMON_INT;
+
+ case _T('u'):
+ radix = 10;
+ goto COMMON_INT;
+
+ case _T('p'):
+ /* write a pointer -- this is like an integer or long */
+ /* except we force precision to pad with zeros and */
+ /* output in big hex. */
+
+ precision = 2 * sizeof(void *); /* number of hex digits needed */
+#if PTR_IS_INT64
+ flags |= FL_I64; /* assume we're converting an int64 */
+#elif !PTR_IS_INT
+ flags |= FL_LONG; /* assume we're converting a long */
+#endif /* !PTR_IS_INT */
+ /* DROP THROUGH to hex formatting */
+
+ case _T('X'):
+ /* unsigned upper hex output */
+ hexadd = _T('A') - _T('9') - 1; /* set hexadd for uppercase hex */
+ goto COMMON_HEX;
+
+ case _T('x'):
+ /* unsigned lower hex output */
+ hexadd = _T('a') - _T('9') - 1; /* set hexadd for lowercase hex */
+ /* DROP THROUGH TO COMMON_HEX */
+
+ COMMON_HEX:
+ radix = 16;
+ if (flags & FL_ALTERNATE) {
+ /* alternate form means '0x' prefix */
+ prefix[0] = _T('0');
+ prefix[1] = (TCHAR)(_T('x') - _T('a') + _T('9') + 1 + hexadd); /* 'x' or 'X' */
+ prefixlen = 2;
+ }
+ goto COMMON_INT;
+
+ case _T('o'):
+ /* unsigned octal output */
+ radix = 8;
+ if (flags & FL_ALTERNATE) {
+ /* alternate form means force a leading 0 */
+ flags |= FL_FORCEOCTAL;
+ }
+ /* DROP THROUGH to COMMON_INT */
+
+ COMMON_INT: {
+ /* This is the general integer formatting routine. */
+ /* Basically, we get an argument, make it positive */
+ /* if necessary, and convert it according to the */
+ /* correct radix, setting text and textlen */
+ /* appropriately. */
+
+#if _INTEGRAL_MAX_BITS >= 64
+ uint64_t number; /* number to convert */
+ int digit; /* ascii value of digit */
+ __int64 l; /* temp long value */
+#else /* _INTEGRAL_MAX_BITS >= 64 */
+ unsigned long number; /* number to convert */
+ int digit; /* ascii value of digit */
+ long l; /* temp long value */
+#endif /* _INTEGRAL_MAX_BITS >= 64 */
+
+ /* 1. read argument into l, sign extend as needed */
+#if _INTEGRAL_MAX_BITS >= 64
+ if (flags & FL_I64)
+ l = get_int64_arg(&argptr);
+ else
+#endif /* _INTEGRAL_MAX_BITS >= 64 */
+
+ if (flags & FL_LONGLONG)
+ l = get_long_long_arg(&argptr);
+
+ else
+
+#if !LONG_IS_INT
+ if (flags & FL_LONG)
+ l = get_long_arg(&argptr);
+ else
+#endif /* !LONG_IS_INT */
+
+#if !SHORT_IS_INT
+ if (flags & FL_SHORT) {
+ if (flags & FL_SIGNED)
+ l = (short) get_int_arg(&argptr); /* sign extend */
+ else
+ l = (unsigned short) get_int_arg(&argptr); /* zero-extend*/
+
+ } else
+#endif /* !SHORT_IS_INT */
+ {
+ if (flags & FL_SIGNED)
+ l = get_int_arg(&argptr); /* sign extend */
+ else
+ l = (unsigned int) get_int_arg(&argptr); /* zero-extend*/
+ }
+
+ /* 2. check for negative; copy into number */
+ if ( (flags & FL_SIGNED) && l < 0) {
+ number = -l;
+ flags |= FL_NEGATIVE; /* remember negative sign */
+ } else {
+ number = l;
+ }
+
+#if _INTEGRAL_MAX_BITS >= 64
+ if ( (flags & FL_I64) == 0 && (flags & FL_LONGLONG) == 0 ) {
+ /*
+ * Unless printing a full 64-bit value, insure values
+ * here are not in cananical longword format to prevent
+ * the sign extended upper 32-bits from being printed.
+ */
+ number &= 0xffffffff;
+ }
+#endif /* _INTEGRAL_MAX_BITS >= 64 */
+
+ /* 3. check precision value for default; non-default */
+ /* turns off 0 flag, according to ANSI. */
+ if (precision < 0)
+ precision = 1; /* default precision */
+ else {
+ flags &= ~FL_LEADZERO;
+ if (precision > MAXPRECISION)
+ precision = MAXPRECISION;
+ }
+
+ /* 4. Check if data is 0; if so, turn off hex prefix */
+ if (number == 0)
+ prefixlen = 0;
+
+ /* 5. Convert data to ASCII -- note if precision is zero */
+ /* and number is zero, we get no digits at all. */
+
+ char *sz;
+ sz = &buffer.sz[BUFFERSIZE-1]; /* last digit at end of buffer */
+
+ while (precision-- > 0 || number != 0) {
+ digit = (int)(number % radix) + '0';
+ number /= radix; /* reduce number */
+ if (digit > '9') {
+ /* a hex digit, make it a letter */
+ digit += hexadd;
+ }
+ *sz-- = (char)digit; /* store the digit */
+ }
+
+ textlen = (int)((char *)&buffer.sz[BUFFERSIZE-1] - sz); /* compute length of number */
+ ++sz; /* text points to first digit now */
+
+
+ /* 6. Force a leading zero if FORCEOCTAL flag set */
+ if ((flags & FL_FORCEOCTAL) && (textlen == 0 || sz[0] != '0')) {
+ *--sz = '0';
+ ++textlen; /* add a zero */
+ }
+
+ text.sz = sz;
+ }
+ break;
+ }
+
+
+ /* At this point, we have done the specific conversion, and */
+ /* 'text' points to text to print; 'textlen' is length. Now we */
+ /* justify it, put on prefixes, leading zeros, and then */
+ /* print it. */
+
+ if (!no_output) {
+ int padding; /* amount of padding, negative means zero */
+
+ if (flags & FL_SIGNED) {
+ if (flags & FL_NEGATIVE) {
+ /* prefix is a '-' */
+ prefix[0] = _T('-');
+ prefixlen = 1;
+ }
+ else if (flags & FL_SIGN) {
+ /* prefix is '+' */
+ prefix[0] = _T('+');
+ prefixlen = 1;
+ }
+ else if (flags & FL_SIGNSP) {
+ /* prefix is ' ' */
+ prefix[0] = _T(' ');
+ prefixlen = 1;
+ }
+ }
+
+ /* calculate amount of padding -- might be negative, */
+ /* but this will just mean zero */
+ padding = fldwidth - textlen - prefixlen;
+
+ /* put out the padding, prefix, and text, in the correct order */
+
+ if (!(flags & (FL_LEFT | FL_LEADZERO))) {
+ /* pad on left with blanks */
+ WRITE_MULTI_CHAR(_T(' '), padding, &charsout);
+ }
+
+ /* write prefix */
+ WRITE_STRING(prefix, prefixlen, &charsout);
+
+ if ((flags & FL_LEADZERO) && !(flags & FL_LEFT)) {
+ /* write leading zeros */
+ WRITE_MULTI_CHAR(_T('0'), padding, &charsout);
+ }
+
+ /* write text */
+#ifndef _UNICODE
+ if (bufferiswide && (textlen > 0)) {
+ charsout = -1;
+ } else {
+ WRITE_STRING(text.sz, textlen, &charsout);
+ }
+#else /* _UNICODE */
+ if (!bufferiswide && textlen > 0) {
+ const char *p;
+ int retval = 0;
+ int count;
+
+ p = text.sz;
+ count = textlen;
+ while (count-- > 0) {
+ retval = _MBTOWC(&wchar, p, MB_CUR_MAX);
+ if (retval <= 0) {
+ charsout = -1;
+ break;
+ }
+ WRITE_CHAR(wchar, &charsout);
+ p += retval;
+ }
+ } else {
+ WRITE_STRING(text.wz, textlen, &charsout);
+ }
+#endif /* _UNICODE */
+
+ if (charsout >= 0 && (flags & FL_LEFT)) {
+ /* pad on right with blanks */
+ WRITE_MULTI_CHAR(_T(' '), padding, &charsout);
+ }
+
+ /* we're done! */
+ }
+ break;
+ case ST_INVALID:
+ _VALIDATE_RETURN(0 /* FALSE */, EINVAL, -1);
+ break;
+ }
+ }
+
+#ifdef FORMAT_VALIDATIONS
+ /* The format string shouldn't be incomplete - i.e. when we are finished
+ with the format string, the last thing we should have encountered
+ should have been a regular char to be output or a type specifier. Else
+ the format string was incomplete */
+ _VALIDATE_RETURN(((state == ST_NORMAL) || (state == ST_TYPE)), EINVAL, -1);
+#endif /* FORMAT_VALIDATIONS */
+
+ return charsout; /* return value = number of characters written */
+}
+
+/*
+ * Future Optimizations for swprintf:
+ * - Don't free the memory used for converting the buffer to wide chars.
+ * Use realloc if the memory is not sufficient. Free it at the end.
+ */
+
+/***
+*void write_char(char ch, int *pnumwritten)
+*ifdef _UNICODE
+*void write_char(wchar_t ch, FILE *f, int *pnumwritten)
+*endif
+*void write_char(char ch, FILE *f, int *pnumwritten)
+*
+*Purpose:
+* Writes a single character to the given file/console. If no error occurs,
+* then *pnumwritten is incremented; otherwise, *pnumwritten is set
+* to -1.
+*
+*Entry:
+* _TCHAR ch - character to write
+* FILE *f - file to write to
+* int *pnumwritten - pointer to integer to update with total chars written
+*
+*Exit:
+* No return value.
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+#ifdef CPRFLAG
+
+LOCAL(void) write_char (
+ _TCHAR ch,
+ int *pnumwritten
+ )
+{
+#ifdef _UNICODE
+ if (_putwch_nolock(ch) == WEOF)
+#else /* _UNICODE */
+ if (_putch_nolock(ch) == EOF)
+#endif /* _UNICODE */
+ *pnumwritten = -1;
+ else
+ ++(*pnumwritten);
+}
+
+#else /* CPRFLAG */
+
+LOCAL(void) write_char (
+ _TCHAR ch,
+ miniFILE *f,
+ int *pnumwritten
+ )
+{
+ if ( (f->_flag & _IOSTRG) && f->_base == NULL)
+ {
+ ++(*pnumwritten);
+ return;
+ }
+#ifdef _UNICODE
+ if (_putwc_nolock(ch, f) == WEOF)
+#else /* _UNICODE */
+ if (_putc_nolock(ch, f) == EOF)
+#endif /* _UNICODE */
+ *pnumwritten = -1;
+ else
+ ++(*pnumwritten);
+}
+
+#endif /* CPRFLAG */
+
+/***
+*void write_multi_char(char ch, int num, int *pnumwritten)
+*ifdef _UNICODE
+*void write_multi_char(wchar_t ch, int num, FILE *f, int *pnumwritten)
+*endif
+*void write_multi_char(char ch, int num, FILE *f, int *pnumwritten)
+*
+*Purpose:
+* Writes num copies of a character to the given file/console. If no error occurs,
+* then *pnumwritten is incremented by num; otherwise, *pnumwritten is set
+* to -1. If num is negative, it is treated as zero.
+*
+*Entry:
+* _TCHAR ch - character to write
+* int num - number of times to write the characters
+* FILE *f - file to write to
+* int *pnumwritten - pointer to integer to update with total chars written
+*
+*Exit:
+* No return value.
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+#ifdef CPRFLAG
+LOCAL(void) write_multi_char (
+ _TCHAR ch,
+ int num,
+ int *pnumwritten
+ )
+{
+ while (num-- > 0) {
+ write_char(ch, pnumwritten);
+ if (*pnumwritten == -1)
+ break;
+ }
+}
+
+#else /* CPRFLAG */
+
+LOCAL(void) write_multi_char (
+ _TCHAR ch,
+ int num,
+ miniFILE *f,
+ int *pnumwritten
+ )
+{
+ while (num-- > 0) {
+ write_char(ch, f, pnumwritten);
+ if (*pnumwritten == -1)
+ break;
+ }
+}
+
+#endif /* CPRFLAG */
+
+/***
+*void write_string(const char *string, int len, int *pnumwritten)
+*void write_string(const char *string, int len, FILE *f, int *pnumwritten)
+*ifdef _UNICODE
+*void write_string(const wchar_t *string, int len, FILE *f, int *pnumwritten)
+*endif
+*
+*Purpose:
+* Writes a string of the given length to the given file. If no error occurs,
+* then *pnumwritten is incremented by len; otherwise, *pnumwritten is set
+* to -1. If len is negative, it is treated as zero.
+*
+*Entry:
+* _TCHAR *string - string to write (NOT null-terminated)
+* int len - length of string
+* FILE *f - file to write to
+* int *pnumwritten - pointer to integer to update with total chars written
+*
+*Exit:
+* No return value.
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+#ifdef CPRFLAG
+
+LOCAL(void) write_string (
+ const _TCHAR *string,
+ int len,
+ int *pnumwritten
+ )
+{
+ while (len-- > 0) {
+ write_char(*string++, pnumwritten);
+ if (*pnumwritten == -1)
+ {
+ if (errno == EILSEQ)
+ write_char(_T('?'), pnumwritten);
+ else
+ break;
+ }
+ }
+}
+
+#else /* CPRFLAG */
+
+LOCAL(void) write_string (
+ const _TCHAR *string,
+ int len,
+ miniFILE *f,
+ int *pnumwritten
+ )
+{
+ if ( (f->_flag & _IOSTRG) && f->_base == NULL)
+ {
+ (*pnumwritten) += len;
+ return;
+ }
+ while (len-- > 0) {
+ write_char(*string++, f, pnumwritten);
+ if (*pnumwritten == -1)
+ {
+ if (errno == EILSEQ)
+ write_char(_T('?'), f, pnumwritten);
+ else
+ break;
+ }
+ }
+}
+#endif /* CPRFLAG */
diff --git a/src/pal/src/safecrt/safecrt_input_s.c b/src/pal/src/safecrt/safecrt_input_s.c
new file mode 100644
index 0000000000..6ba607c669
--- /dev/null
+++ b/src/pal/src/safecrt/safecrt_input_s.c
@@ -0,0 +1,46 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*safecrt_input_s.c - implementation of the _input family for safecrt.lib
+*
+
+*
+*Purpose:
+* This file contains the implementation of the _input family for safecrt.lib.
+*
+*Revision History:
+* 07/19/04 AC Created
+*
+****/
+
+#define _SAFECRT_IMPL
+#define _SECURE_SCANF
+
+#include "pal/palinternal.h"
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <locale.h>
+#include <stdarg.h>
+#include <inttypes.h>
+
+#include "internal_securecrt.h"
+
+#include "mbusafecrt_internal.h"
+
+#define _TCHAR CRT_TCHAR
+#define TCHAR CRTTCHAR
+
+typedef char _TCHAR;
+typedef char TCHAR;
+typedef unsigned char _TUCHAR;
+#define _T(x) x
+#define _TEOF EOF
+
+#define _gettc_nolock(x) _getc_nolock(x)
+#define _ungettc_nolock(x,y) _ungetc_nolock(x,y)
+
+#include "input.inl"
diff --git a/src/pal/src/safecrt/safecrt_output_l.c b/src/pal/src/safecrt/safecrt_output_l.c
new file mode 100644
index 0000000000..d6844f4f8b
--- /dev/null
+++ b/src/pal/src/safecrt/safecrt_output_l.c
@@ -0,0 +1,1467 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*safecrt_output_l.c - implementation of the _output family for safercrt.lib
+*
+
+*
+*Purpose:
+* This file contains the implementation of the _output family for safercrt.lib.
+*
+*Revision History:
+* 07-08-04 SJ Stub module created.
+* 07-13-04 AC Added support for floating-point types.
+* 07-29-04 AC Added macros for a safecrt version of mctowc and wctomb, which target ntdll.dll or msvcrt.dll
+* based on the _NTSUBSET_ #define
+* 09-24-04 MSL Prefix disallow NULL deref
+*
+****/
+
+#define _SAFECRT_IMPL
+
+#define __STDC_LIMIT_MACROS
+#include "pal/palinternal.h"
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <inttypes.h>
+#include "internal_securecrt.h"
+
+#include "mbusafecrt_internal.h"
+
+#define _CFLTCVT _safecrt_cfltcvt
+
+//typedef __int64_t __int64;
+typedef double _CRT_DOUBLE;
+typedef char _TCHAR;
+typedef char TCHAR;
+#define _T(x) x
+/*
+Buffer size required to be passed to _gcvt, fcvt and other fp conversion routines
+*/
+#define _CVTBUFSIZE (309+40) /* # of digits in max. dp value + slop */
+
+//------------------------------------------------------------------------------
+// This code was taken from the 'ouput.c' file located in Visual Studio 8 (i.e. 2005)
+// in the '\Microsoft Visual Studio 8\VC\crt\src' directory. It was moved into
+// this file to support only the '_output' function used by _vscprintf() in vsprintf.c
+// UNUSED / NON-RELEVANT PORTIONS OF THE CODE HAVE BEEN REMOVED - do not try and
+// use it to generate any other safecrt 'output' functions
+//
+// Noteable modifications
+// - changed FILE to miniFILE (defined in mbusafecrt_internal.h)
+// - removed _soutput_s - it was unused in this case and conflicted with output.inl
+// - changed #define SHORT_IS_INT to true varargs promotes shorts to ints in GCC
+// - removed definition of __lookuptable_s when using FORMAT_VALIDATIONS, we don't use them
+
+// 7/03/07 - Created by Stephen Shaw (steshaw)
+//------------------------------------------------------------------------------
+
+
+/* temporary work-around for compiler without 64-bit support */
+#ifndef _INTEGRAL_MAX_BITS
+#define _INTEGRAL_MAX_BITS 64
+#endif /* _INTEGRAL_MAX_BITS */
+
+#include <limits.h>
+#include <string.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#define _MBTOWC(x,y,z) _minimal_chartowchar( x, y )
+
+#undef _malloc_crt
+#define _malloc_crt malloc
+
+#undef _free_crt
+#define _free_crt free
+
+// SNIP -srs 7/3/07
+
+#ifndef _CFLTCVT
+#define _CFLTCVT _cfltcvt
+#endif /* _CFLTCVT */
+
+#ifndef _CLDCVT
+#define _CLDCVT _cldcvt
+#endif /* _CLDCVT */
+
+#ifdef _MBCS
+#undef _MBCS
+#endif /* _MBCS */
+//#include <tchar.h>
+
+/* this macro defines a function which is private and as fast as possible: */
+/* for example, in C 6.0, it might be static _fastcall <type> near. */
+#define LOCAL(x) static x __cdecl
+
+/* int/long/short/pointer sizes */
+
+/* the following should be set depending on the sizes of various types */
+#if __LP64__
+ #define LONG_IS_INT 0
+ CASSERT(sizeof(long) > sizeof(int));
+#else
+ #define LONG_IS_INT 1 /* 1 means long is same size as int */
+ CASSERT(sizeof(long) == sizeof(int));
+#endif
+
+// GCC: short is not int, but GCC promotes va_arg to int
+#define SHORT_IS_INT 1
+
+#define LONGLONG_IS_INT64 1 /* 1 means long long is same as int64 */
+ CASSERT(sizeof(long long) == sizeof(int64_t));
+
+#if defined (_WIN64)
+ #define PTR_IS_INT 0 /* 1 means ptr is same size as int */
+ CASSERT(sizeof(void *) != sizeof(int));
+ #if __LP64__
+ #define PTR_IS_LONG 1 /* 1 means ptr is same size as long */
+ CASSERT(sizeof(void *) == sizeof(long));
+ #else
+ #define PTR_IS_LONG 0 /* 1 means ptr is same size as long */
+ CASSERT(sizeof(void *) != sizeof(long));
+ #endif
+ #define PTR_IS_INT64 1 /* 1 means ptr is same size as int64 */
+ CASSERT(sizeof(void *) == sizeof(int64_t));
+#else /* defined (_WIN64) */
+ #define PTR_IS_INT 1 /* 1 means ptr is same size as int */
+ CASSERT(sizeof(void *) == sizeof(int));
+ #define PTR_IS_LONG 1 /* 1 means ptr is same size as long */
+ CASSERT(sizeof(void *) == sizeof(long));
+ #define PTR_IS_INT64 0 /* 1 means ptr is same size as int64 */
+ CASSERT(sizeof(void *) != sizeof(int64_t));
+#endif /* defined (_WIN64) */
+
+/* CONSTANTS */
+
+/* size of conversion buffer (ANSI-specified minimum is 509) */
+
+#define BUFFERSIZE 512
+#define MAXPRECISION BUFFERSIZE
+
+#if BUFFERSIZE < _CVTBUFSIZE + 6
+/*
+ * Buffer needs to be big enough for default minimum precision
+ * when converting floating point needs bigger buffer, and malloc
+ * fails
+ */
+#error Conversion buffer too small for max double.
+#endif /* BUFFERSIZE < _CVTBUFSIZE + 6 */
+
+/* flag definitions */
+#define FL_SIGN 0x00001 /* put plus or minus in front */
+#define FL_SIGNSP 0x00002 /* put space or minus in front */
+#define FL_LEFT 0x00004 /* left justify */
+#define FL_LEADZERO 0x00008 /* pad with leading zeros */
+#define FL_LONG 0x00010 /* long value given */
+#define FL_SHORT 0x00020 /* short value given */
+#define FL_SIGNED 0x00040 /* signed data given */
+#define FL_ALTERNATE 0x00080 /* alternate form requested */
+#define FL_NEGATIVE 0x00100 /* value is negative */
+#define FL_FORCEOCTAL 0x00200 /* force leading '0' for octals */
+#define FL_LONGDOUBLE 0x00400 /* long double value given */
+#define FL_WIDECHAR 0x00800 /* wide characters */
+#define FL_LONGLONG 0x01000 /* long long value given */
+#define FL_I64 0x08000 /* __int64 value given */
+
+/* state definitions */
+enum STATE {
+ ST_NORMAL, /* normal state; outputting literal chars */
+ ST_PERCENT, /* just read '%' */
+ ST_FLAG, /* just read flag character */
+ ST_WIDTH, /* just read width specifier */
+ ST_DOT, /* just read '.' */
+ ST_PRECIS, /* just read precision specifier */
+ ST_SIZE, /* just read size specifier */
+ ST_TYPE /* just read type specifier */
+#ifdef FORMAT_VALIDATIONS
+ ,ST_INVALID /* Invalid format */
+#endif /* FORMAT_VALIDATIONS */
+
+};
+
+#ifdef FORMAT_VALIDATIONS
+#define NUMSTATES (ST_INVALID + 1)
+#else /* FORMAT_VALIDATIONS */
+#define NUMSTATES (ST_TYPE + 1)
+#endif /* FORMAT_VALIDATIONS */
+
+/* character type values */
+enum CHARTYPE {
+ CH_OTHER, /* character with no special meaning */
+ CH_PERCENT, /* '%' */
+ CH_DOT, /* '.' */
+ CH_STAR, /* '*' */
+ CH_ZERO, /* '0' */
+ CH_DIGIT, /* '1'..'9' */
+ CH_FLAG, /* ' ', '+', '-', '#' */
+ CH_SIZE, /* 'h', 'l', 'L', 'N', 'F', 'w' */
+ CH_TYPE /* type specifying character */
+};
+
+/* static data (read only, since we are re-entrant) */
+#if defined (_UNICODE) || defined (CPRFLAG) || defined (FORMAT_VALIDATIONS)
+extern const char __nullstring[]; /* string to print on null ptr */
+extern const wchar_t __wnullstring[]; /* string to print on null ptr */
+#else /* defined (_UNICODE) || defined (CPRFLAG) || defined (FORMAT_VALIDATIONS) */
+static const char __nullstring[] = "(null)"; /* string to print on null ptr */
+static const wchar_t __wnullstring[] = { '(', 'n', 'u', 'l', 'l', ')', '\0' };/* string to print on null ptr */
+#endif /* defined (_UNICODE) || defined (CPRFLAG) || defined (FORMAT_VALIDATIONS) */
+
+/* The state table. This table is actually two tables combined into one. */
+/* The lower nybble of each byte gives the character class of any */
+/* character; while the uper nybble of the byte gives the next state */
+/* to enter. See the macros below the table for details. */
+/* */
+/* The table is generated by maketabc.c -- use this program to make */
+/* changes. */
+
+#ifndef FORMAT_VALIDATIONS
+#if defined (_UNICODE) || defined (CPRFLAG)
+extern const char __lookuptable[];
+#else /* defined (_UNICODE) || defined (CPRFLAG) */
+//extern const char __lookuptable[] = {
+const char __lookuptable[] = {
+ /* ' ' */ 0x06,
+ /* '!' */ 0x00,
+ /* '"' */ 0x00,
+ /* '#' */ 0x06,
+ /* '$' */ 0x00,
+ /* '%' */ 0x01,
+ /* '&' */ 0x00,
+ /* ''' */ 0x00,
+ /* '(' */ 0x10,
+ /* ')' */ 0x00,
+ /* '*' */ 0x03,
+ /* '+' */ 0x06,
+ /* ',' */ 0x00,
+ /* '-' */ 0x06,
+ /* '.' */ 0x02,
+ /* '/' */ 0x10,
+ /* '0' */ 0x04,
+ /* '1' */ 0x45,
+ /* '2' */ 0x45,
+ /* '3' */ 0x45,
+ /* '4' */ 0x05,
+ /* '5' */ 0x05,
+ /* '6' */ 0x05,
+ /* '7' */ 0x05,
+ /* '8' */ 0x05,
+ /* '9' */ 0x35,
+ /* ':' */ 0x30,
+ /* ';' */ 0x00,
+ /* '<' */ 0x50,
+ /* '=' */ 0x00,
+ /* '>' */ 0x00,
+ /* '?' */ 0x00,
+ /* '@' */ 0x00,
+ /* 'A' */ 0x20, // Disable %A format
+ /* 'B' */ 0x20,
+ /* 'C' */ 0x38,
+ /* 'D' */ 0x50,
+ /* 'E' */ 0x58,
+ /* 'F' */ 0x07,
+ /* 'G' */ 0x08,
+ /* 'H' */ 0x00,
+ /* 'I' */ 0x37,
+ /* 'J' */ 0x30,
+ /* 'K' */ 0x30,
+ /* 'L' */ 0x57,
+ /* 'M' */ 0x50,
+ /* 'N' */ 0x07,
+ /* 'O' */ 0x00,
+ /* 'P' */ 0x00,
+ /* 'Q' */ 0x20,
+ /* 'R' */ 0x20,
+ /* 'S' */ 0x08,
+ /* 'T' */ 0x00,
+ /* 'U' */ 0x00,
+ /* 'V' */ 0x00,
+ /* 'W' */ 0x00,
+ /* 'X' */ 0x08,
+ /* 'Y' */ 0x60,
+ /* 'Z' */ 0x68,
+ /* '[' */ 0x60,
+ /* '\' */ 0x60,
+ /* ']' */ 0x60,
+ /* '^' */ 0x60,
+ /* '_' */ 0x00,
+ /* '`' */ 0x00,
+ /* 'a' */ 0x70, // Disable %a format
+ /* 'b' */ 0x70,
+ /* 'c' */ 0x78,
+ /* 'd' */ 0x78,
+ /* 'e' */ 0x78,
+ /* 'f' */ 0x78,
+ /* 'g' */ 0x08,
+ /* 'h' */ 0x07,
+ /* 'i' */ 0x08,
+ /* 'j' */ 0x00,
+ /* 'k' */ 0x00,
+ /* 'l' */ 0x07,
+ /* 'm' */ 0x00,
+ /* 'n' */ 0x00, // Disable %n format
+ /* 'o' */ 0x08,
+ /* 'p' */ 0x08,
+ /* 'q' */ 0x00,
+ /* 'r' */ 0x00,
+ /* 's' */ 0x08,
+ /* 't' */ 0x00,
+ /* 'u' */ 0x08,
+ /* 'v' */ 0x00,
+ /* 'w' */ 0x07,
+ /* 'x' */ 0x08
+};
+
+#endif /* defined (_UNICODE) || defined (CPRFLAG) */
+
+#else /* FORMAT_VALIDATIONS */
+// SNIP -srs 7/3/07
+#error code has been removed
+#endif /* FORMAT_VALIDATIONS */
+
+#define FIND_CHAR_CLASS(lookuptbl, c) \
+ ((c) < _T(' ') || (c) > _T('x') ? \
+ CH_OTHER \
+ : \
+ (enum CHARTYPE)(lookuptbl[(c)-_T(' ')] & 0xF))
+
+#define FIND_NEXT_STATE(lookuptbl, class, state) \
+ (enum STATE)(lookuptbl[(class) * NUMSTATES + (state)] >> 4)
+
+/*
+ * Note: CPRFLAG and _UNICODE cases are currently mutually exclusive.
+ */
+
+/* prototypes */
+
+#ifdef CPRFLAG
+
+#define WRITE_CHAR(ch, pnw) write_char(ch, pnw)
+#define WRITE_MULTI_CHAR(ch, num, pnw) write_multi_char(ch, num, pnw)
+#define WRITE_STRING(s, len, pnw) write_string(s, len, pnw)
+#define WRITE_WSTRING(s, len, pnw) write_wstring(s, len, pnw)
+
+LOCAL(void) write_char(_TCHAR ch, int *pnumwritten);
+LOCAL(void) write_multi_char(_TCHAR ch, int num, int *pnumwritten);
+LOCAL(void) write_string(const _TCHAR *string, int len, int *numwritten);
+LOCAL(void) write_wstring(const wchar_t *string, int len, int *numwritten);
+
+#else /* CPRFLAG */
+
+#define WRITE_CHAR(ch, pnw) write_char(ch, stream, pnw)
+#define WRITE_MULTI_CHAR(ch, num, pnw) write_multi_char(ch, num, stream, pnw)
+#define WRITE_STRING(s, len, pnw) write_string(s, len, stream, pnw)
+#define WRITE_WSTRING(s, len, pnw) write_wstring(s, len, stream, pnw)
+
+LOCAL(void) write_char(_TCHAR ch, miniFILE *f, int *pnumwritten);
+LOCAL(void) write_multi_char(_TCHAR ch, int num, miniFILE *f, int *pnumwritten);
+LOCAL(void) write_string(const _TCHAR *string, int len, miniFILE *f, int *numwritten);
+//LOCAL(void) write_wstring(const wchar_t *string, int len, miniFILE *f, int *numwritten);
+
+#endif /* CPRFLAG */
+
+#define get_short_arg(list) va_arg(*list, int) // GCC promotes va_arg shorts into int values
+#define get_int_arg(list) va_arg(*list, int)
+#define get_long_arg(list) va_arg(*list, long)
+#define get_long_long_arg(list) va_arg(*list, long long)
+#define get_int64_arg(list) va_arg(*list, __int64)
+#define get_crtdouble_arg(list) va_arg(*list, _CRT_DOUBLE)
+#define get_ptr_arg(list) va_arg(*list, void *)
+
+#ifdef CPRFLAG
+LOCAL(int) output(const _TCHAR *, _locale_t , va_list);
+_CRTIMP int __cdecl _vtcprintf_l (const _TCHAR *, _locale_t, va_list);
+_CRTIMP int __cdecl _vtcprintf_s_l (const _TCHAR *, _locale_t, va_list);
+_CRTIMP int __cdecl _vtcprintf_p_l (const _TCHAR *, _locale_t, va_list);
+
+
+/***
+*int _cprintf(format, arglist) - write formatted output directly to console
+*
+*Purpose:
+* Writes formatted data like printf, but uses console I/O functions.
+*
+*Entry:
+* char *format - format string to determine data formats
+* arglist - list of POINTERS to where to put data
+*
+*Exit:
+* returns number of characters written
+*
+*Exceptions:
+*
+*******************************************************************************/
+#ifndef FORMAT_VALIDATIONS
+_CRTIMP int __cdecl _tcprintf_l (
+ const _TCHAR * format,
+ _locale_t plocinfo,
+ ...
+ )
+#else /* FORMAT_VALIDATIONS */
+_CRTIMP int __cdecl _tcprintf_s_l (
+ const _TCHAR * format,
+ _locale_t plocinfo,
+ ...
+ )
+#endif /* FORMAT_VALIDATIONS */
+
+{
+ int ret;
+ va_list arglist;
+ va_start(arglist, plocinfo);
+
+#ifndef FORMAT_VALIDATIONS
+ ret = _vtcprintf_l(format, plocinfo, arglist);
+#else /* FORMAT_VALIDATIONS */
+ ret = _vtcprintf_s_l(format, plocinfo, arglist);
+
+#endif /* FORMAT_VALIDATIONS */
+
+ va_end(arglist);
+
+ return ret;
+}
+
+#ifndef FORMAT_VALIDATIONS
+_CRTIMP int __cdecl _tcprintf (
+ const _TCHAR * format,
+ ...
+ )
+#else /* FORMAT_VALIDATIONS */
+_CRTIMP int __cdecl _tcprintf_s (
+ const _TCHAR * format,
+ ...
+ )
+#endif /* FORMAT_VALIDATIONS */
+
+{
+ int ret;
+ va_list arglist;
+
+ va_start(arglist, format);
+
+#ifndef FORMAT_VALIDATIONS
+ ret = _vtcprintf_l(format, NULL, arglist);
+#else /* FORMAT_VALIDATIONS */
+ ret = _vtcprintf_s_l(format, NULL, arglist);
+
+#endif /* FORMAT_VALIDATIONS */
+
+ va_end(arglist);
+
+ return ret;
+}
+
+#endif /* CPRFLAG */
+
+
+/***
+*int _output(stream, format, argptr), static int output(format, argptr)
+*
+*Purpose:
+* Output performs printf style output onto a stream. It is called by
+* printf/fprintf/sprintf/vprintf/vfprintf/vsprintf to so the dirty
+* work. In multi-thread situations, _output assumes that the given
+* stream is already locked.
+*
+* Algorithm:
+* The format string is parsed by using a finite state automaton
+* based on the current state and the current character read from
+* the format string. Thus, looping is on a per-character basis,
+* not a per conversion specifier basis. Once the format specififying
+* character is read, output is performed.
+*
+*Entry:
+* FILE *stream - stream for output
+* char *format - printf style format string
+* va_list argptr - pointer to list of subsidiary arguments
+*
+*Exit:
+* Returns the number of characters written, or -1 if an output error
+* occurs.
+*ifdef _UNICODE
+* The wide-character flavour returns the number of wide-characters written.
+*endif
+*
+*Exceptions:
+*
+*******************************************************************************/
+#ifdef CPRFLAG
+#ifndef FORMAT_VALIDATIONS
+_CRTIMP int __cdecl _vtcprintf (
+ const _TCHAR *format,
+ va_list argptr
+ )
+{
+ return _vtcprintf_l(format, NULL, argptr);
+}
+
+#else /* FORMAT_VALIDATIONS */
+_CRTIMP int __cdecl _vtcprintf_s (
+ const _TCHAR *format,
+ va_list argptr
+ )
+{
+ return _vtcprintf_s_l(format, NULL, argptr);
+}
+
+#endif /* FORMAT_VALIDATIONS */
+#endif /* CPRFLAG */
+
+#ifdef CPRFLAG
+#ifndef FORMAT_VALIDATIONS
+_CRTIMP int __cdecl _vtcprintf_l (
+#else /* FORMAT_VALIDATIONS */
+_CRTIMP int __cdecl _vtcprintf_s_l (
+#endif /* FORMAT_VALIDATIONS */
+#else /* CPRFLAG */
+
+#ifdef _UNICODE
+#ifndef FORMAT_VALIDATIONS
+int __cdecl _woutput (
+ miniFILE *stream,
+#else /* FORMAT_VALIDATIONS */
+int __cdecl _woutput_s (
+ miniFILE *stream,
+#endif /* FORMAT_VALIDATIONS */
+#else /* _UNICODE */
+#ifndef FORMAT_VALIDATIONS
+int __cdecl _output (
+ miniFILE *stream,
+#else /* FORMAT_VALIDATIONS */
+ int __cdecl _output_s (
+ miniFILE *stream,
+
+#endif /* FORMAT_VALIDATIONS */
+#endif /* _UNICODE */
+
+#endif /* CPRFLAG */
+ const _TCHAR *format,
+ va_list argptr
+ )
+{
+ int hexadd=0; /* offset to add to number to get 'a'..'f' */
+ TCHAR ch; /* character just read */
+ int flags=0; /* flag word -- see #defines above for flag values */
+ enum STATE state; /* current state */
+ enum CHARTYPE chclass; /* class of current character */
+ int radix; /* current conversion radix */
+ int charsout; /* characters currently written so far, -1 = IO error */
+ int fldwidth = 0; /* selected field width -- 0 means default */
+ int precision = 0; /* selected precision -- -1 means default */
+ TCHAR prefix[2]; /* numeric prefix -- up to two characters */
+ int prefixlen=0; /* length of prefix -- 0 means no prefix */
+ int capexp = 0; /* non-zero = 'E' exponent signifient, zero = 'e' */
+ int no_output=0; /* non-zero = prodcue no output for this specifier */
+ union {
+ const char *sz; /* pointer text to be printed, not zero terminated */
+ const wchar_t *wz;
+ } text;
+
+ int textlen; /* length of the text in bytes/wchars to be printed.
+ textlen is in multibyte or wide chars if _UNICODE */
+ union {
+ char sz[BUFFERSIZE];
+#ifdef _UNICODE
+ wchar_t wz[BUFFERSIZE];
+#endif /* _UNICODE */
+ } buffer;
+ wchar_t wchar; /* temp wchar_t */
+ int buffersize; /* size of text.sz (used only for the call to _cfltcvt) */
+ int bufferiswide=0; /* non-zero = buffer contains wide chars already */
+
+#ifndef CPRFLAG
+ _VALIDATE_RETURN( (stream != NULL), EINVAL, -1);
+#endif /* CPRFLAG */
+ _VALIDATE_RETURN( (format != NULL), EINVAL, -1);
+
+ charsout = 0; /* no characters written yet */
+ textlen = 0; /* no text yet */
+ state = ST_NORMAL; /* starting state */
+ buffersize = 0;
+
+ /* main loop -- loop while format character exist and no I/O errors */
+ while ((ch = *format++) != _T('\0') && charsout >= 0) {
+#ifndef FORMAT_VALIDATIONS
+ chclass = FIND_CHAR_CLASS(__lookuptable, ch); /* find character class */
+ state = FIND_NEXT_STATE(__lookuptable, chclass, state); /* find next state */
+#else /* FORMAT_VALIDATIONS */
+ chclass = FIND_CHAR_CLASS(__lookuptable_s, ch); /* find character class */
+ state = FIND_NEXT_STATE(__lookuptable_s, chclass, state); /* find next state */
+
+ _VALIDATE_RETURN((state != ST_INVALID), EINVAL, -1);
+
+#endif /* FORMAT_VALIDATIONS */
+
+ /* execute code for each state */
+ switch (state) {
+
+ case ST_NORMAL:
+
+ NORMAL_STATE:
+
+ /* normal state -- just write character */
+#ifdef _UNICODE
+ bufferiswide = 1;
+#else /* _UNICODE */
+ bufferiswide = 0;
+#endif /* _UNICODE */
+ WRITE_CHAR(ch, &charsout);
+ break;
+
+ case ST_PERCENT:
+ /* set default value of conversion parameters */
+ prefixlen = fldwidth = no_output = capexp = 0;
+ flags = 0;
+ precision = -1;
+ bufferiswide = 0; /* default */
+ break;
+
+ case ST_FLAG:
+ /* set flag based on which flag character */
+ switch (ch) {
+ case _T('-'):
+ flags |= FL_LEFT; /* '-' => left justify */
+ break;
+ case _T('+'):
+ flags |= FL_SIGN; /* '+' => force sign indicator */
+ break;
+ case _T(' '):
+ flags |= FL_SIGNSP; /* ' ' => force sign or space */
+ break;
+ case _T('#'):
+ flags |= FL_ALTERNATE; /* '#' => alternate form */
+ break;
+ case _T('0'):
+ flags |= FL_LEADZERO; /* '0' => pad with leading zeros */
+ break;
+ }
+ break;
+
+ case ST_WIDTH:
+ /* update width value */
+ if (ch == _T('*')) {
+ /* get width from arg list */
+ fldwidth = get_int_arg(&argptr);
+ if (fldwidth < 0) {
+ /* ANSI says neg fld width means '-' flag and pos width */
+ flags |= FL_LEFT;
+ fldwidth = -fldwidth;
+ }
+ }
+ else {
+ /* add digit to current field width */
+ fldwidth = fldwidth * 10 + (ch - _T('0'));
+ }
+ break;
+
+ case ST_DOT:
+ /* zero the precision, since dot with no number means 0
+ not default, according to ANSI */
+ precision = 0;
+ break;
+
+ case ST_PRECIS:
+ /* update precison value */
+ if (ch == _T('*')) {
+ /* get precision from arg list */
+ precision = get_int_arg(&argptr);
+ if (precision < 0)
+ precision = -1; /* neg precision means default */
+ }
+ else {
+ /* add digit to current precision */
+ precision = precision * 10 + (ch - _T('0'));
+ }
+ break;
+
+ case ST_SIZE:
+ /* just read a size specifier, set the flags based on it */
+ switch (ch) {
+ case _T('l'):
+ /*
+ * In order to handle the ll case, we depart from the
+ * simple deterministic state machine.
+ */
+ if (*format == _T('l'))
+ {
+ ++format;
+ flags |= FL_LONGLONG; /* 'll' => long long */
+ }
+ else
+ {
+ flags |= FL_LONG; /* 'l' => long int or wchar_t */
+ }
+ break;
+
+ case _T('I'):
+ /*
+ * In order to handle the I, I32, and I64 size modifiers, we
+ * depart from the simple deterministic state machine. The
+ * code below scans for characters following the 'I',
+ * and defaults to 64 bit on WIN64 and 32 bit on WIN32
+ */
+#if PTR_IS_INT64
+ flags |= FL_I64; /* 'I' => __int64 on WIN64 systems */
+#endif /* PTR_IS_INT64 */
+ if ( (*format == _T('6')) && (*(format + 1) == _T('4')) )
+ {
+ format += 2;
+ flags |= FL_I64; /* I64 => __int64 */
+ }
+ else if ( (*format == _T('3')) && (*(format + 1) == _T('2')) )
+ {
+ format += 2;
+ flags &= ~FL_I64; /* I32 => __int32 */
+ }
+ else if ( (*format == _T('d')) ||
+ (*format == _T('i')) ||
+ (*format == _T('o')) ||
+ (*format == _T('u')) ||
+ (*format == _T('x')) ||
+ (*format == _T('X')) )
+ {
+ /*
+ * Nothing further needed. %Id (et al) is
+ * handled just like %d, except that it defaults to 64 bits
+ * on WIN64. Fall through to the next iteration.
+ */
+ }
+ else {
+ state = ST_NORMAL;
+ goto NORMAL_STATE;
+ }
+ break;
+
+ case _T('h'):
+ flags |= FL_SHORT; /* 'h' => short int or char */
+ break;
+
+ case _T('w'):
+ flags |= FL_WIDECHAR; /* 'w' => wide character */
+ break;
+
+ }
+ break;
+
+ case ST_TYPE:
+ /* we have finally read the actual type character, so we */
+ /* now format and "print" the output. We use a big switch */
+ /* statement that sets 'text' to point to the text that should */
+ /* be printed, and 'textlen' to the length of this text. */
+ /* Common code later on takes care of justifying it and */
+ /* other miscellaneous chores. Note that cases share code, */
+ /* in particular, all integer formatting is done in one place. */
+ /* Look at those funky goto statements! */
+
+ switch (ch) {
+
+ case _T('C'): /* ISO wide character */
+ if (!(flags & (FL_SHORT|FL_LONG|FL_WIDECHAR)))
+#ifdef _UNICODE
+ flags |= FL_SHORT;
+#else /* _UNICODE */
+ flags |= FL_WIDECHAR; /* ISO std. */
+#endif /* _UNICODE */
+ /* fall into 'c' case */
+
+ case _T('c'): {
+ /* print a single character specified by int argument */
+#ifdef _UNICODE
+ bufferiswide = 1;
+ wchar = (wchar_t) get_int_arg(&argptr);
+ if (flags & FL_SHORT) {
+ /* format multibyte character */
+ /* this is an extension of ANSI */
+ char tempchar[2];
+ {
+ tempchar[0] = (char)(wchar & 0x00ff);
+ tempchar[1] = '\0';
+ }
+
+ if (_MBTOWC(buffer.wz,tempchar, MB_CUR_MAX) < 0)
+ {
+ /* ignore if conversion was unsuccessful */
+ no_output = 1;
+ }
+ } else {
+ buffer.wz[0] = wchar;
+ }
+ text.wz = buffer.wz;
+ textlen = 1; /* print just a single character */
+#else /* _UNICODE */
+ if (flags & (FL_LONG|FL_WIDECHAR)) {
+ wchar = (wchar_t) get_short_arg(&argptr);
+ no_output = 1;
+ } else {
+ /* format multibyte character */
+ /* this is an extension of ANSI */
+ unsigned short temp;
+ wchar = (wchar_t)get_int_arg(&argptr);
+ temp = (unsigned short)wchar;
+ {
+ buffer.sz[0] = (char) temp;
+ textlen = 1;
+ }
+ }
+ text.sz = buffer.sz;
+#endif /* _UNICODE */
+ }
+ break;
+
+ case _T('Z'): {
+ /* print a Counted String */
+ struct _count_string {
+ short Length;
+ short MaximumLength;
+ char *Buffer;
+ } *pstr;
+
+ pstr = (struct _count_string *)get_ptr_arg(&argptr);
+ if (pstr == NULL || pstr->Buffer == NULL) {
+ /* null ptr passed, use special string */
+ text.sz = __nullstring;
+ textlen = (int)strlen(text.sz);
+ } else {
+ if (flags & FL_WIDECHAR) {
+ text.wz = (wchar_t *)pstr->Buffer;
+ textlen = pstr->Length / (int)sizeof(wchar_t);
+ bufferiswide = 1;
+ } else {
+ bufferiswide = 0;
+ text.sz = pstr->Buffer;
+ textlen = pstr->Length;
+ }
+ }
+ }
+ break;
+
+ case _T('S'): /* ISO wide character string */
+#ifndef _UNICODE
+ if (!(flags & (FL_SHORT|FL_LONG|FL_WIDECHAR)))
+ flags |= FL_WIDECHAR;
+#else /* _UNICODE */
+ if (!(flags & (FL_SHORT|FL_LONG|FL_WIDECHAR)))
+ flags |= FL_SHORT;
+#endif /* _UNICODE */
+
+ case _T('s'): {
+ /* print a string -- */
+ /* ANSI rules on how much of string to print: */
+ /* all if precision is default, */
+ /* min(precision, length) if precision given. */
+ /* prints '(null)' if a null string is passed */
+
+ int i;
+ const char *p; /* temps */
+ const wchar_t *pwch;
+
+ /* At this point it is tempting to use strlen(), but */
+ /* if a precision is specified, we're not allowed to */
+ /* scan past there, because there might be no null */
+ /* at all. Thus, we must do our own scan. */
+
+ i = (precision == -1) ? INT_MAX : precision;
+ text.sz = (char *)get_ptr_arg(&argptr);
+
+ /* scan for null upto i characters */
+#ifdef _UNICODE
+ if (flags & FL_SHORT) {
+ if (text.sz == NULL) /* NULL passed, use special string */
+ text.sz = __nullstring;
+ p = text.sz;
+ for (textlen=0; textlen<i && *p; textlen++) {
+ ++p;
+ }
+ /* textlen now contains length in multibyte chars */
+ } else {
+ if (text.wz == NULL) /* NULL passed, use special string */
+ text.wz = __wnullstring;
+ bufferiswide = 1;
+ pwch = text.wz;
+ while (i-- && *pwch)
+ ++pwch;
+ textlen = (int)(pwch - text.wz); /* in wchar_ts */
+ /* textlen now contains length in wide chars */
+ }
+#else /* _UNICODE */
+ if (flags & (FL_LONG|FL_WIDECHAR)) {
+ if (text.wz == NULL) /* NULL passed, use special string */
+ text.wz = __wnullstring;
+ bufferiswide = 1;
+ pwch = text.wz;
+ while ( i-- && *pwch )
+ ++pwch;
+ textlen = (int)(pwch - text.wz);
+ /* textlen now contains length in wide chars */
+ } else {
+ if (text.sz == NULL) /* NULL passed, use special string */
+ text.sz = __nullstring;
+ p = text.sz;
+ while (i-- && *p)
+ ++p;
+ textlen = (int)(p - text.sz); /* length of the string */
+ }
+
+#endif /* _UNICODE */
+ }
+ break;
+
+
+ case _T('n'): {
+ /* write count of characters seen so far into */
+ /* short/int/long thru ptr read from args */
+
+ void *p; /* temp */
+
+ p = get_ptr_arg(&argptr);
+
+ /* %n is disabled */
+ _VALIDATE_RETURN(("'n' format specifier disabled" && 0), EINVAL, -1);
+ break;
+
+ /* store chars out into short/long/int depending on flags */
+#if !LONG_IS_INT
+ if (flags & FL_LONG)
+ *(long *)p = charsout;
+ else
+#endif /* !LONG_IS_INT */
+
+#if !SHORT_IS_INT
+ if (flags & FL_SHORT)
+ *(short *)p = (short) charsout;
+ else
+#endif /* !SHORT_IS_INT */
+ *(int *)p = charsout;
+
+ no_output = 1; /* force no output */
+ }
+ break;
+
+ case _T('E'):
+ case _T('G'):
+ case _T('A'):
+ capexp = 1; /* capitalize exponent */
+ ch += _T('a') - _T('A'); /* convert format char to lower */
+ /* DROP THROUGH */
+ case _T('e'):
+ case _T('f'):
+ case _T('g'):
+ case _T('a'): {
+ /* floating point conversion -- we call cfltcvt routines */
+ /* to do the work for us. */
+ flags |= FL_SIGNED; /* floating point is signed conversion */
+ text.sz = buffer.sz; /* put result in buffer */
+ buffersize = BUFFERSIZE;
+
+ /* compute the precision value */
+ if (precision < 0)
+ precision = 6; /* default precision: 6 */
+ else if (precision == 0 && ch == _T('g'))
+ precision = 1; /* ANSI specified */
+ else if (precision > MAXPRECISION)
+ precision = MAXPRECISION;
+
+ if (precision > BUFFERSIZE - _CVTBUFSIZE) {
+ precision = BUFFERSIZE - _CVTBUFSIZE;
+ }
+
+ /* for safecrt, we pass along the FL_ALTERNATE flag to _safecrt_cfltcvt */
+ if (flags & FL_ALTERNATE)
+ {
+ capexp |= FL_ALTERNATE;
+ }
+
+ _CRT_DOUBLE tmp;
+ tmp=va_arg(argptr, _CRT_DOUBLE);
+ /* Note: assumes ch is in ASCII range */
+ /* In safecrt, we provide a special version of _cfltcvt which internally calls printf (see safecrt_output_s.c) */
+ _CFLTCVT(&tmp, buffer.sz, buffersize, (char)ch, precision, capexp);
+
+ /* check if result was negative, save '-' for later */
+ /* and point to positive part (this is for '0' padding) */
+ if (*text.sz == '-') {
+ flags |= FL_NEGATIVE;
+ ++text.sz;
+ }
+
+ textlen = (int)strlen(text.sz); /* compute length of text */
+ }
+ break;
+
+ case _T('d'):
+ case _T('i'):
+ /* signed decimal output */
+ flags |= FL_SIGNED;
+ radix = 10;
+ goto COMMON_INT;
+
+ case _T('u'):
+ radix = 10;
+ goto COMMON_INT;
+
+ case _T('p'):
+ /* write a pointer -- this is like an integer or long */
+ /* except we force precision to pad with zeros and */
+ /* output in big hex. */
+
+ precision = 2 * sizeof(void *); /* number of hex digits needed */
+#if PTR_IS_INT64
+ flags |= FL_I64; /* assume we're converting an int64 */
+#elif !PTR_IS_INT
+ flags |= FL_LONG; /* assume we're converting a long */
+#endif /* !PTR_IS_INT */
+ /* DROP THROUGH to hex formatting */
+
+ case _T('X'):
+ /* unsigned upper hex output */
+ hexadd = _T('A') - _T('9') - 1; /* set hexadd for uppercase hex */
+ goto COMMON_HEX;
+
+ case _T('x'):
+ /* unsigned lower hex output */
+ hexadd = _T('a') - _T('9') - 1; /* set hexadd for lowercase hex */
+ /* DROP THROUGH TO COMMON_HEX */
+
+ COMMON_HEX:
+ radix = 16;
+ if (flags & FL_ALTERNATE) {
+ /* alternate form means '0x' prefix */
+ prefix[0] = _T('0');
+ prefix[1] = (TCHAR)(_T('x') - _T('a') + _T('9') + 1 + hexadd); /* 'x' or 'X' */
+ prefixlen = 2;
+ }
+ goto COMMON_INT;
+
+ case _T('o'):
+ /* unsigned octal output */
+ radix = 8;
+ if (flags & FL_ALTERNATE) {
+ /* alternate form means force a leading 0 */
+ flags |= FL_FORCEOCTAL;
+ }
+ /* DROP THROUGH to COMMON_INT */
+
+ COMMON_INT: {
+ /* This is the general integer formatting routine. */
+ /* Basically, we get an argument, make it positive */
+ /* if necessary, and convert it according to the */
+ /* correct radix, setting text and textlen */
+ /* appropriately. */
+
+#if _INTEGRAL_MAX_BITS >= 64
+// unsigned __int64 number; /* number to convert */
+ uint64_t number; /* number to convert */
+ int digit; /* ascii value of digit */
+ __int64 l; /* temp long value */
+#else /* _INTEGRAL_MAX_BITS >= 64 */
+ unsigned long number; /* number to convert */
+ int digit; /* ascii value of digit */
+ long l; /* temp long value */
+#endif /* _INTEGRAL_MAX_BITS >= 64 */
+
+ /* 1. read argument into l, sign extend as needed */
+#if _INTEGRAL_MAX_BITS >= 64
+ if (flags & FL_I64)
+ l = get_int64_arg(&argptr);
+ else
+#endif /* _INTEGRAL_MAX_BITS >= 64 */
+
+ if (flags & FL_LONGLONG)
+ l = get_long_long_arg(&argptr);
+ else
+
+#if !LONG_IS_INT
+ if (flags & FL_LONG)
+ l = get_long_arg(&argptr);
+ else
+#endif /* !LONG_IS_INT */
+
+#if !SHORT_IS_INT
+ if (flags & FL_SHORT) {
+ if (flags & FL_SIGNED)
+ l = (short) get_int_arg(&argptr); /* sign extend */
+ else
+ l = (unsigned short) get_int_arg(&argptr); /* zero-extend*/
+
+ } else
+#endif /* !SHORT_IS_INT */
+ {
+ if (flags & FL_SIGNED)
+ l = get_int_arg(&argptr); /* sign extend */
+ else
+ l = (unsigned int) get_int_arg(&argptr); /* zero-extend*/
+
+ }
+
+ /* 2. check for negative; copy into number */
+ if ( (flags & FL_SIGNED) && l < 0) {
+ number = -l;
+ flags |= FL_NEGATIVE; /* remember negative sign */
+ } else {
+ number = l;
+ }
+
+#if _INTEGRAL_MAX_BITS >= 64
+ if ( (flags & FL_I64) == 0 && (flags & FL_LONGLONG) == 0 ) {
+ /*
+ * Unless printing a full 64-bit value, insure values
+ * here are not in cananical longword format to prevent
+ * the sign extended upper 32-bits from being printed.
+ */
+ number &= 0xffffffff;
+ }
+#endif /* _INTEGRAL_MAX_BITS >= 64 */
+
+ /* 3. check precision value for default; non-default */
+ /* turns off 0 flag, according to ANSI. */
+ if (precision < 0)
+ precision = 1; /* default precision */
+ else {
+ flags &= ~FL_LEADZERO;
+ if (precision > MAXPRECISION)
+ precision = MAXPRECISION;
+ }
+
+ /* 4. Check if data is 0; if so, turn off hex prefix */
+ if (number == 0)
+ prefixlen = 0;
+
+ /* 5. Convert data to ASCII -- note if precision is zero */
+ /* and number is zero, we get no digits at all. */
+
+ char *sz;
+ sz = &buffer.sz[BUFFERSIZE-1]; /* last digit at end of buffer */
+
+ while (precision-- > 0 || number != 0) {
+ digit = (int)(number % radix) + '0';
+ number /= radix; /* reduce number */
+ if (digit > '9') {
+ /* a hex digit, make it a letter */
+ digit += hexadd;
+ }
+ *sz-- = (char)digit; /* store the digit */
+ }
+
+ textlen = (int)((char *)&buffer.sz[BUFFERSIZE-1] - sz); /* compute length of number */
+ ++sz; /* text points to first digit now */
+
+
+ /* 6. Force a leading zero if FORCEOCTAL flag set */
+ if ((flags & FL_FORCEOCTAL) && (textlen == 0 || sz[0] != '0')) {
+ *--sz = '0';
+ ++textlen; /* add a zero */
+ }
+
+ text.sz = sz;
+ }
+ break;
+ }
+
+
+ /* At this point, we have done the specific conversion, and */
+ /* 'text' points to text to print; 'textlen' is length. Now we */
+ /* justify it, put on prefixes, leading zeros, and then */
+ /* print it. */
+
+ if (!no_output) {
+ int padding; /* amount of padding, negative means zero */
+
+ if (flags & FL_SIGNED) {
+ if (flags & FL_NEGATIVE) {
+ /* prefix is a '-' */
+ prefix[0] = _T('-');
+ prefixlen = 1;
+ }
+ else if (flags & FL_SIGN) {
+ /* prefix is '+' */
+ prefix[0] = _T('+');
+ prefixlen = 1;
+ }
+ else if (flags & FL_SIGNSP) {
+ /* prefix is ' ' */
+ prefix[0] = _T(' ');
+ prefixlen = 1;
+ }
+ }
+
+ /* calculate amount of padding -- might be negative, */
+ /* but this will just mean zero */
+ padding = fldwidth - textlen - prefixlen;
+
+ /* put out the padding, prefix, and text, in the correct order */
+
+ if (!(flags & (FL_LEFT | FL_LEADZERO))) {
+ /* pad on left with blanks */
+ WRITE_MULTI_CHAR(_T(' '), padding, &charsout);
+ }
+
+ /* write prefix */
+ WRITE_STRING(prefix, prefixlen, &charsout);
+
+ if ((flags & FL_LEADZERO) && !(flags & FL_LEFT)) {
+ /* write leading zeros */
+ WRITE_MULTI_CHAR(_T('0'), padding, &charsout);
+ }
+
+ /* write text */
+#ifndef _UNICODE
+ if (bufferiswide && (textlen > 0)) {
+ charsout = -1;
+ } else {
+ WRITE_STRING(text.sz, textlen, &charsout);
+ }
+#else /* _UNICODE */
+ if (!bufferiswide && textlen > 0) {
+ char *p;
+ int retval = 0
+ int count;
+
+ p = text.sz;
+ count = textlen;
+ while (count-- > 0) {
+ retval = _MBTOWC(&wchar, p, MB_CUR_MAX);
+ if (retval <= 0) {
+ charsout = -1;
+ break;
+ }
+ WRITE_CHAR(wchar, &charsout);
+ p += retval;
+ }
+ } else {
+ WRITE_STRING(text.wz, textlen, &charsout);
+ }
+#endif /* _UNICODE */
+
+ if (charsout >= 0 && (flags & FL_LEFT)) {
+ /* pad on right with blanks */
+ WRITE_MULTI_CHAR(_T(' '), padding, &charsout);
+ }
+
+ /* we're done! */
+ }
+ break;
+ }
+ }
+
+#ifdef FORMAT_VALIDATIONS
+ /* The format string shouldn't be incomplete - i.e. when we are finished
+ with the format string, the last thing we should have encountered
+ should have been a regular char to be output or a type specifier. Else
+ the format string was incomplete */
+ _VALIDATE_RETURN(((state == ST_NORMAL) || (state == ST_TYPE)), EINVAL, -1);
+#endif /* FORMAT_VALIDATIONS */
+
+ return charsout; /* return value = number of characters written */
+}
+
+/*
+ * Future Optimizations for swprintf:
+ * - Don't free the memory used for converting the buffer to wide chars.
+ * Use realloc if the memory is not sufficient. Free it at the end.
+ */
+
+/***
+*void write_char(char ch, int *pnumwritten)
+*ifdef _UNICODE
+*void write_char(wchar_t ch, FILE *f, int *pnumwritten)
+*endif
+*void write_char(char ch, FILE *f, int *pnumwritten)
+*
+*Purpose:
+* Writes a single character to the given file/console. If no error occurs,
+* then *pnumwritten is incremented; otherwise, *pnumwritten is set
+* to -1.
+*
+*Entry:
+* _TCHAR ch - character to write
+* FILE *f - file to write to
+* int *pnumwritten - pointer to integer to update with total chars written
+*
+*Exit:
+* No return value.
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+#ifdef CPRFLAG
+
+LOCAL(void) write_char (
+ _TCHAR ch,
+ int *pnumwritten
+ )
+{
+#ifdef _UNICODE
+ if (_putwch_nolock(ch) == WEOF)
+#else /* _UNICODE */
+ if (_putch_nolock(ch) == EOF)
+#endif /* _UNICODE */
+ *pnumwritten = -1;
+ else
+ ++(*pnumwritten);
+}
+
+#else /* CPRFLAG */
+
+LOCAL(void) write_char (
+ _TCHAR ch,
+ miniFILE *f,
+ int *pnumwritten
+ )
+{
+ if ( (f->_flag & _IOSTRG) && f->_base == NULL)
+ {
+ ++(*pnumwritten);
+ return;
+ }
+#ifdef _UNICODE
+ if (_putwc_nolock(ch, f) == WEOF)
+#else /* _UNICODE */
+ if (_putc_nolock(ch, f) == EOF)
+#endif /* _UNICODE */
+ *pnumwritten = -1;
+ else
+ ++(*pnumwritten);
+}
+
+#endif /* CPRFLAG */
+
+/***
+*void write_multi_char(char ch, int num, int *pnumwritten)
+*ifdef _UNICODE
+*void write_multi_char(wchar_t ch, int num, FILE *f, int *pnumwritten)
+*endif
+*void write_multi_char(char ch, int num, FILE *f, int *pnumwritten)
+*
+*Purpose:
+* Writes num copies of a character to the given file/console. If no error occurs,
+* then *pnumwritten is incremented by num; otherwise, *pnumwritten is set
+* to -1. If num is negative, it is treated as zero.
+*
+*Entry:
+* _TCHAR ch - character to write
+* int num - number of times to write the characters
+* FILE *f - file to write to
+* int *pnumwritten - pointer to integer to update with total chars written
+*
+*Exit:
+* No return value.
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+#ifdef CPRFLAG
+LOCAL(void) write_multi_char (
+ _TCHAR ch,
+ int num,
+ int *pnumwritten
+ )
+{
+ while (num-- > 0) {
+ write_char(ch, pnumwritten);
+ if (*pnumwritten == -1)
+ break;
+ }
+}
+
+#else /* CPRFLAG */
+
+LOCAL(void) write_multi_char (
+ _TCHAR ch,
+ int num,
+ miniFILE *f,
+ int *pnumwritten
+ )
+{
+ while (num-- > 0) {
+ write_char(ch, f, pnumwritten);
+ if (*pnumwritten == -1)
+ break;
+ }
+}
+
+#endif /* CPRFLAG */
+
+/***
+*void write_string(const char *string, int len, int *pnumwritten)
+*void write_string(const char *string, int len, FILE *f, int *pnumwritten)
+*ifdef _UNICODE
+*void write_string(const wchar_t *string, int len, FILE *f, int *pnumwritten)
+*endif
+*void write_wstring(const wchar_t *string, int len, int *pnumwritten)
+*void write_wstring(const wchar_t *string, int len, FILE *f, int *pnumwritten)
+*
+*Purpose:
+* Writes a string of the given length to the given file. If no error occurs,
+* then *pnumwritten is incremented by len; otherwise, *pnumwritten is set
+* to -1. If len is negative, it is treated as zero.
+*
+*Entry:
+* _TCHAR *string - string to write (NOT null-terminated)
+* int len - length of string
+* FILE *f - file to write to
+* int *pnumwritten - pointer to integer to update with total chars written
+*
+*Exit:
+* No return value.
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+#ifdef CPRFLAG
+
+LOCAL(void) write_string (
+ const _TCHAR *string,
+ int len,
+ int *pnumwritten
+ )
+{
+ while (len-- > 0) {
+ write_char(*string++, pnumwritten);
+ if (*pnumwritten == -1)
+ {
+ if (errno == EILSEQ)
+ write_char(_T('?'), pnumwritten);
+ else
+ break;
+ }
+ }
+}
+
+#else /* CPRFLAG */
+
+LOCAL(void) write_string (
+ const _TCHAR *string,
+ int len,
+ miniFILE *f,
+ int *pnumwritten
+ )
+{
+ if ( (f->_flag & _IOSTRG) && f->_base == NULL)
+ {
+ (*pnumwritten) += len;
+ return;
+ }
+ while (len-- > 0) {
+ write_char(*string++, f, pnumwritten);
+ if (*pnumwritten == -1)
+ {
+ if (errno == EILSEQ)
+ write_char(_T('?'), f, pnumwritten);
+ else
+ break;
+ }
+ }
+}
+#endif /* CPRFLAG */
diff --git a/src/pal/src/safecrt/safecrt_output_s.c b/src/pal/src/safecrt/safecrt_output_s.c
new file mode 100644
index 0000000000..c3e7f91404
--- /dev/null
+++ b/src/pal/src/safecrt/safecrt_output_s.c
@@ -0,0 +1,46 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*safecrt_output_s.c - implementation of the _output family for safercrt.lib
+*
+
+*
+*Purpose:
+* This file contains the implementation of the _output family for safercrt.lib.
+*
+*Revision History:
+* 07-08-04 SJ Stub module created.
+* 07-13-04 AC Added support for floating-point types.
+* 07-29-04 AC Added macros for a safecrt version of mctowc and wctomb, which target ntdll.dll or msvcrt.dll
+* based on the _NTSUBSET_ #define
+* 09-24-04 MSL Prefix disallow NULL deref
+*
+****/
+
+#define _SAFECRT_IMPL
+
+#define __STDC_LIMIT_MACROS
+#include "pal/palinternal.h"
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <inttypes.h>
+#include "internal_securecrt.h"
+
+#include "mbusafecrt_internal.h"
+
+#define FORMAT_VALIDATIONS
+#define _CFLTCVT _safecrt_cfltcvt
+
+#define _TCHAR CRT_TCHAR
+#define TCHAR CRTTCHAR
+
+typedef char _TCHAR;
+typedef char TCHAR;
+#define _T(x) x
+
+#include "output.inl"
diff --git a/src/pal/src/safecrt/safecrt_winput_s.c b/src/pal/src/safecrt/safecrt_winput_s.c
new file mode 100644
index 0000000000..17a621781b
--- /dev/null
+++ b/src/pal/src/safecrt/safecrt_winput_s.c
@@ -0,0 +1,55 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*safecrt_winput_s.c - implementation of the _winput family for safecrt.lib
+*
+
+*
+*Purpose:
+* This file contains the implementation of the _winput family for safecrt.lib.
+*
+*Revision History:
+* 07/19/04 AC Created
+*
+****/
+
+
+#ifndef _UNICODE /* CRT flag */
+#define _UNICODE 1
+#endif
+
+#ifndef UNICODE /* NT flag */
+#define UNICODE 1
+#endif
+
+#define _SAFECRT_IMPL
+#define _SECURE_SCANF
+
+#include "pal/palinternal.h"
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <locale.h>
+#include <stdarg.h>
+#include <inttypes.h>
+#include "internal_securecrt.h"
+
+#include "mbusafecrt_internal.h"
+
+#define _TCHAR CRT_TCHAR
+#define TCHAR CRTTCHAR
+
+typedef wchar_t _TCHAR;
+typedef wchar_t TCHAR;
+typedef wchar_t _TUCHAR;
+#define _T(x) x
+#define _TEOF WEOF
+
+#define _gettc_nolock(x) _getwc_nolock(x)
+#define _ungettc_nolock(x,y) _ungetwc_nolock(x,y)
+
+#include "input.inl"
+
diff --git a/src/pal/src/safecrt/safecrt_woutput_s.c b/src/pal/src/safecrt/safecrt_woutput_s.c
new file mode 100644
index 0000000000..52fe9400d5
--- /dev/null
+++ b/src/pal/src/safecrt/safecrt_woutput_s.c
@@ -0,0 +1,59 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*safecrt_woutput_s.c - implementation of the _woutput family for safercrt.lib
+*
+
+*
+*Purpose:
+* This file contains the implementation of the _woutput family for safercrt.lib.
+*
+*Revision History:
+* 07-08-04 SJ Stub module created.
+* 07-13-04 AC Added support for floating-point types.
+* 07-29-04 AC Added macros for a safecrt version of mctowc and wctomb, which target ntdll.dll or msvcrt.dll
+* based on the _NTSUBSET_ #define
+*
+****/
+
+#define _SAFECRT_IMPL
+
+#define __STDC_LIMIT_MACROS
+
+#include "pal/palinternal.h"
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <inttypes.h>
+#include "internal_securecrt.h"
+
+#include "mbusafecrt_internal.h"
+
+#ifndef _UNICODE /* CRT flag */
+#define _UNICODE 1
+#endif
+
+#ifndef UNICODE /* NT flag */
+#define UNICODE 1
+#endif
+
+#define FORMAT_VALIDATIONS
+#if defined(_NTSUBSET_)
+#define _MBTOWC _safecrt_mbtowc
+#endif
+#define _WCTOMB_S _safecrt_wctomb_s
+#define _CFLTCVT _safecrt_cfltcvt
+#define _CLDCVT _safecrt_cldcvt
+
+#define _TCHAR CRT_TCHAR
+#define TCHAR CRTTCHAR
+
+typedef wchar_t _TCHAR;
+typedef wchar_t TCHAR;
+#define _T(x) L##x
+
+#include "output.inl"
diff --git a/src/pal/src/safecrt/snprintf.c b/src/pal/src/safecrt/snprintf.c
new file mode 100644
index 0000000000..c892d1a9b6
--- /dev/null
+++ b/src/pal/src/safecrt/snprintf.c
@@ -0,0 +1,18 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*snprintf.c - "Count" version of sprintf
+*
+
+*
+*Purpose:
+* The _snprintf() flavor takes a count argument that is
+* the max number of bytes that should be written to the
+* user's buffer.
+*
+*******************************************************************************/
+
+#define _COUNT_ 1
+#include "sprintf.c"
diff --git a/src/pal/src/safecrt/splitpath_s.c b/src/pal/src/safecrt/splitpath_s.c
new file mode 100644
index 0000000000..cb8a364550
--- /dev/null
+++ b/src/pal/src/safecrt/splitpath_s.c
@@ -0,0 +1,31 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*splitpath_s.c - break down path name into components
+*
+
+*
+*Purpose:
+* To provide support for accessing the individual components of an
+* arbitrary path name
+*
+*******************************************************************************/
+
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include "internal_securecrt.h"
+
+#include "mbusafecrt_internal.h"
+
+#define _FUNC_PROLOGUE
+#define _FUNC_NAME _splitpath_s
+#define _CHAR char
+#define _TCSNCPY_S strncpy_s
+#define _T(_Character) _Character
+
+#define _MBS_SUPPORT 0
+
+#include "tsplitpath_s.inl"
diff --git a/src/pal/src/safecrt/sprintf.c b/src/pal/src/safecrt/sprintf.c
new file mode 100644
index 0000000000..5454179f8d
--- /dev/null
+++ b/src/pal/src/safecrt/sprintf.c
@@ -0,0 +1,98 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*sprintf.c - print formatted to string
+*
+
+*
+*Purpose:
+* defines sprintf() and _snprintf() - print formatted data to string
+*
+*******************************************************************************/
+
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include "internal_securecrt.h"
+
+#include "mbusafecrt_internal.h"
+
+
+/***
+*ifndef _COUNT_
+*int sprintf(string, format, ...) - print formatted data to string
+*else
+*int _snprintf(string, cnt, format, ...) - print formatted data to string
+*endif
+*
+*Purpose:
+* Prints formatted data to the using the format string to
+* format data and getting as many arguments as called for
+* Sets up a FILE so file i/o operations can be used, make
+* string look like a huge buffer to it, but _flsbuf will
+* refuse to flush it if it fills up. Appends '\0' to make
+* it a true string. _output does the real work here
+*
+* Allocate the 'fake' _iob[] entry statically instead of on
+* the stack so that other routines can assume that _iob[]
+* entries are in are in DGROUP and, thus, are near.
+*
+*ifdef _COUNT_
+* The _snprintf() flavor takes a count argument that is
+* the max number of bytes that should be written to the
+* user's buffer.
+*endif
+*
+* Multi-thread: (1) Since there is no stream, this routine must
+* never try to get the stream lock (i.e., there is no stream
+* lock either). (2) Also, since there is only one statically
+* allocated 'fake' iob, we must lock/unlock to prevent collisions.
+*
+*Entry:
+* char *string - pointer to place to put output
+*ifdef _COUNT_
+* size_t count - max number of bytes to put in buffer
+*endif
+* char *format - format string to control data format/number
+* of arguments followed by list of arguments, number and type
+* controlled by format string
+*
+*Exit:
+* returns number of characters printed
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+int sprintf_s (
+ char *string,
+ size_t sizeInBytes,
+ const char *format,
+ ...
+ )
+{
+ int ret;
+ va_list arglist;
+ va_start(arglist, format);
+ ret = _vsprintf_s(string, sizeInBytes, format, arglist);
+ va_end(arglist);
+ return ret;
+}
+
+int _snprintf_s (
+ char *string,
+ size_t sizeInBytes,
+ size_t count,
+ const char *format,
+ ...
+ )
+{
+ int ret;
+ va_list arglist;
+ va_start(arglist, format);
+ ret = _vsnprintf_s(string, sizeInBytes, count, format, arglist);
+ va_end(arglist);
+ return ret;
+}
diff --git a/src/pal/src/safecrt/sscanf.c b/src/pal/src/safecrt/sscanf.c
new file mode 100644
index 0000000000..94b5148875
--- /dev/null
+++ b/src/pal/src/safecrt/sscanf.c
@@ -0,0 +1,249 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*sscanf.c - read formatted data from string
+*
+
+*
+*Purpose:
+* defines scanf() - reads formatted data from string
+*
+*******************************************************************************/
+
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include "internal_securecrt.h"
+
+#include "mbusafecrt_internal.h"
+
+typedef int (*INPUTFN)(miniFILE *, const unsigned char*, va_list);
+typedef int (*WINPUTFN)(miniFILE *, const unsigned short*, va_list);
+
+
+/***
+*static int v[nw]scan_fn([w]inputfn, string, [count], format, ...)
+*
+*Purpose:
+* this is a helper function which is called by the other functions
+* in this file - sscanf/swscanf/snscanf etc. It calls either _(w)input or
+* _(w)input_s depending on the first parameter.
+*
+*******************************************************************************/
+
+static int __cdecl vscan_fn (
+ INPUTFN inputfn,
+ const char *string,
+ const char *format,
+ va_list arglist
+ )
+{
+ miniFILE str;
+ miniFILE *infile = &str;
+ int retval;
+ size_t count = strlen(string);
+
+ _VALIDATE_RETURN( (string != NULL), EINVAL, EOF);
+ _VALIDATE_RETURN( (format != NULL), EINVAL, EOF);
+
+ infile->_flag = _IOREAD|_IOSTRG|_IOMYBUF;
+ infile->_ptr = infile->_base = (char *) string;
+
+ if(count>(INT_MAX/sizeof(char)))
+ {
+ /* old-style functions allow any large value to mean unbounded */
+ infile->_cnt = INT_MAX;
+ }
+ else
+ {
+ infile->_cnt = (int)count*sizeof(char);
+ }
+
+ retval = (inputfn(infile, ( const unsigned char* )format, arglist));
+
+ return(retval);
+}
+
+static int __cdecl vnscan_fn (
+ INPUTFN inputfn,
+ const char *string,
+ size_t count,
+ const char *format,
+ va_list arglist
+ )
+{
+ miniFILE str;
+ miniFILE *infile = &str;
+ int retval;
+ size_t length = strlen(string);
+
+ _VALIDATE_RETURN( (string != NULL), EINVAL, EOF);
+ _VALIDATE_RETURN( (format != NULL), EINVAL, EOF);
+
+ infile->_flag = _IOREAD|_IOSTRG|_IOMYBUF;
+ infile->_ptr = infile->_base = (char *) string;
+
+ if ( count > length )
+ {
+ count = length;
+ }
+
+ if(count>(INT_MAX/sizeof(char)))
+ {
+ /* old-style functions allow any large value to mean unbounded */
+ infile->_cnt = INT_MAX;
+ }
+ else
+ {
+ infile->_cnt = (int)count*sizeof(char);
+ }
+
+ retval = (inputfn(infile, ( const unsigned char* )format, arglist));
+
+ return(retval);
+}
+
+static int __cdecl vwscan_fn (
+ WINPUTFN inputfn,
+ const wchar_t *string,
+ const wchar_t *format,
+ va_list arglist
+ )
+{
+ miniFILE str;
+ miniFILE *infile = &str;
+ int retval;
+ size_t count = wcsnlen(string, INT_MAX);
+
+ _VALIDATE_RETURN( (string != NULL), EINVAL, EOF);
+ _VALIDATE_RETURN( (format != NULL), EINVAL, EOF);
+
+ infile->_flag = _IOREAD|_IOSTRG|_IOMYBUF;
+ infile->_ptr = infile->_base = (char *) string;
+
+ if(count>(INT_MAX/sizeof(wchar_t)))
+ {
+ /* old-style functions allow any large value to mean unbounded */
+ infile->_cnt = INT_MAX;
+ }
+ else
+ {
+ infile->_cnt = (int)count*sizeof(wchar_t);
+ }
+
+ retval = (inputfn(infile, format, arglist));
+
+ return(retval);
+}
+
+static int __cdecl vnwscan_fn (
+ WINPUTFN inputfn,
+ const wchar_t *string,
+ size_t count,
+ const wchar_t *format,
+ va_list arglist
+ )
+{
+ miniFILE str;
+ miniFILE *infile = &str;
+ int retval;
+ size_t length = wcsnlen(string, INT_MAX);
+
+ _VALIDATE_RETURN( (string != NULL), EINVAL, EOF);
+ _VALIDATE_RETURN( (format != NULL), EINVAL, EOF);
+
+ infile->_flag = _IOREAD|_IOSTRG|_IOMYBUF;
+ infile->_ptr = infile->_base = (char *) string;
+
+ if ( count > length )
+ {
+ count = length;
+ }
+
+ if(count>(INT_MAX/sizeof(wchar_t)))
+ {
+ /* old-style functions allow any large value to mean unbounded */
+ infile->_cnt = INT_MAX;
+ }
+ else
+ {
+ infile->_cnt = (int)count*sizeof(wchar_t);
+ }
+
+ retval = (inputfn(infile, format, arglist));
+
+ return(retval);
+}
+
+
+/***
+*int sscanf_s(string, format, ...)
+* Same as sscanf above except that it calls _input_s to do the real work.
+*
+*int snscanf_s(string, size, format, ...)
+* Same as snscanf above except that it calls _input_s to do the real work.
+*
+* _input_s has a size check for array parameters.
+*
+*******************************************************************************/
+
+int __cdecl sscanf_s (
+ const char *string,
+ const char *format,
+ ...
+ )
+{
+ int ret;
+ va_list arglist;
+ va_start(arglist, format);
+ ret = vscan_fn(__tinput_s, string, format, arglist);
+ va_end(arglist);
+ return ret;
+}
+
+int __cdecl _snscanf_s (
+ const char *string,
+ size_t count,
+ const char *format,
+ ...
+ )
+{
+ int ret;
+ va_list arglist;
+ va_start(arglist, format);
+ ret = vnscan_fn(__tinput_s, string, count, format, arglist);
+ va_end(arglist);
+ return ret;
+}
+
+int __cdecl swscanf_s (
+ const wchar_t *string,
+ const wchar_t *format,
+ ...
+ )
+{
+ int ret;
+ va_list arglist;
+ va_start(arglist, format);
+ ret = vwscan_fn(__twinput_s, string, format, arglist);
+ va_end(arglist);
+ return ret;
+}
+
+int __cdecl _snwscanf_s (
+ const wchar_t *string,
+ size_t count,
+ const wchar_t *format,
+ ...
+ )
+{
+ int ret;
+ va_list arglist;
+ va_start(arglist, format);
+ ret = vnwscan_fn(__twinput_s, string, count, format, arglist);
+ va_end(arglist);
+ return ret;
+}
+
diff --git a/src/pal/src/safecrt/strcat_s.c b/src/pal/src/safecrt/strcat_s.c
new file mode 100644
index 0000000000..4dc2332006
--- /dev/null
+++ b/src/pal/src/safecrt/strcat_s.c
@@ -0,0 +1,33 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*strcat_s.c - contains strcat_s()
+*
+
+*
+*Purpose:
+* strcat_s() concatenates (appends) a copy of the source string to the
+* end of the destination string.
+*
+*******************************************************************************/
+
+#define _SECURECRT_FILL_BUFFER 1
+#define _SECURECRT_FILL_BUFFER_THRESHOLD ((size_t)8)
+
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include "internal_securecrt.h"
+
+#include "mbusafecrt_internal.h"
+
+#define _FUNC_PROLOGUE
+#define _FUNC_NAME strcat_s
+#define _CHAR char
+#define _DEST _Dst
+#define _SIZE _SizeInBytes
+#define _SRC _Src
+
+#include "tcscat_s.inl"
diff --git a/src/pal/src/safecrt/strcpy_s.c b/src/pal/src/safecrt/strcpy_s.c
new file mode 100644
index 0000000000..821dbe85f6
--- /dev/null
+++ b/src/pal/src/safecrt/strcpy_s.c
@@ -0,0 +1,29 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*strcpy_s.c - contains strcpy_s()
+*
+
+*
+*Purpose:
+* strcpy_s() copies one string onto another.
+*
+*******************************************************************************/
+
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include "internal_securecrt.h"
+
+#include "mbusafecrt_internal.h"
+
+#define _FUNC_PROLOGUE
+#define _FUNC_NAME strcpy_s
+#define _CHAR char
+#define _DEST _Dst
+#define _SIZE _SizeInBytes
+#define _SRC _Src
+
+#include "tcscpy_s.inl"
diff --git a/src/pal/src/safecrt/strlen_s.c b/src/pal/src/safecrt/strlen_s.c
new file mode 100644
index 0000000000..34c1308d5c
--- /dev/null
+++ b/src/pal/src/safecrt/strlen_s.c
@@ -0,0 +1,58 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*strlen_s.c - contains strnlen() routine
+*
+
+*
+*Purpose:
+* strnlen returns the length of a null-terminated string,
+* not including the null byte itself, up to the specified max size
+*
+*******************************************************************************/
+
+
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include "internal_securecrt.h"
+
+#include "mbusafecrt_internal.h"
+
+/***
+*strnlen - return the length of a null-terminated string
+*
+*Purpose:
+* Finds the length in bytes of the given string, not including
+* the final null character. Only the first maxsize characters
+* are inspected: if the null character is not found, maxsize is
+* returned.
+*
+*Entry:
+* const char * str - string whose length is to be computed
+* size_t maxsize
+*
+*Exit:
+* Length of the string "str", exclusive of the final null byte, or
+* maxsize if the null character is not found.
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+size_t __cdecl strnlen(const char *str, size_t maxsize)
+{
+ size_t n;
+
+ /* Note that we do not check if str == NULL, because we do not
+ * return errno_t...
+ */
+
+ for (n = 0; n < maxsize && *str; n++, str++)
+ ;
+
+ return n;
+}
+
diff --git a/src/pal/src/safecrt/strncat_s.c b/src/pal/src/safecrt/strncat_s.c
new file mode 100644
index 0000000000..ef8c6cfc7f
--- /dev/null
+++ b/src/pal/src/safecrt/strncat_s.c
@@ -0,0 +1,31 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*strncat_s.c - append n chars of string to new string
+*
+
+*
+*Purpose:
+* defines strncat_s() - appends n characters of string onto
+* end of other string
+*
+*******************************************************************************/
+
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include "internal_securecrt.h"
+
+#include "mbusafecrt_internal.h"
+
+#define _FUNC_PROLOGUE
+#define _FUNC_NAME strncat_s
+#define _CHAR char
+#define _DEST _Dst
+#define _SIZE _SizeInBytes
+#define _SRC _Src
+#define _COUNT _Count
+
+#include "tcsncat_s.inl"
diff --git a/src/pal/src/safecrt/strncpy_s.c b/src/pal/src/safecrt/strncpy_s.c
new file mode 100644
index 0000000000..f819ebb6bb
--- /dev/null
+++ b/src/pal/src/safecrt/strncpy_s.c
@@ -0,0 +1,30 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*strncpy_s.c - copy at most n characters of string
+*
+
+*
+*Purpose:
+* defines strncpy_s() - copy at most n characters of string
+*
+*******************************************************************************/
+
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include "internal_securecrt.h"
+
+#include "mbusafecrt_internal.h"
+
+#define _FUNC_PROLOGUE
+#define _FUNC_NAME strncpy_s
+#define _CHAR char
+#define _DEST _Dst
+#define _SIZE _SizeInBytes
+#define _SRC _Src
+#define _COUNT _Count
+
+#include "tcsncpy_s.inl"
diff --git a/src/pal/src/safecrt/strtok_s.c b/src/pal/src/safecrt/strtok_s.c
new file mode 100644
index 0000000000..6f1c80633f
--- /dev/null
+++ b/src/pal/src/safecrt/strtok_s.c
@@ -0,0 +1,27 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*strtok_s.c - tokenize a string with given delimiters
+*
+
+*
+*Purpose:
+* defines strtok_s() - breaks string into series of token
+* via repeated calls.
+*
+*******************************************************************************/
+
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include "internal_securecrt.h"
+
+#include "mbusafecrt_internal.h"
+
+#define _FUNC_PROLOGUE
+#define _FUNC_NAME strtok_s
+#define _CHAR char
+
+#include "tcstok_s.inl"
diff --git a/src/pal/src/safecrt/swprintf.c b/src/pal/src/safecrt/swprintf.c
new file mode 100644
index 0000000000..75004eafe2
--- /dev/null
+++ b/src/pal/src/safecrt/swprintf.c
@@ -0,0 +1,120 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*swprintf.c - print formatted to string
+*
+*Purpose:
+* defines _swprintf(), _swprintf_c and _snwprintf() - print formatted data
+* to string
+*
+*******************************************************************************/
+
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include "internal_securecrt.h"
+
+#include "mbusafecrt_internal.h"
+
+/***
+*ifndef _COUNT_
+*int _swprintf(string, format, ...) - print formatted data to string
+*else
+*ifndef _SWPRINTFS_ERROR_RETURN_FIX
+*int _snwprintf(string, cnt, format, ...) - print formatted data to string
+*else
+*int _swprintf_c(string, cnt, format, ...) - print formatted data to string
+*endif
+*endif
+*
+*Purpose:
+* Prints formatted data to the using the format string to
+* format data and getting as many arguments as called for
+* Sets up a FILE so file i/o operations can be used, make
+* string look like a huge buffer to it, but _flsbuf will
+* refuse to flush it if it fills up. Appends '\0' to make
+* it a true string. _output does the real work here
+*
+* Allocate the 'fake' _iob[] entry statically instead of on
+* the stack so that other routines can assume that _iob[]
+* entries are in are in DGROUP and, thus, are near.
+*
+* We alias swprintf to _swprintf
+*
+*ifdef _COUNT_
+*ifndef _SWPRINTFS_ERROR_RETURN_FIX
+* The _snwprintf() flavor takes a count argument that is
+* the max number of wide characters that should be written to the
+* user's buffer.
+* We don't expose this function directly in the headers.
+*else
+* The _swprintf_c() flavor does the same thing as the _snwprintf
+* above, but, it also fixes a issue in the return value in the case
+* when there isn't enough space to write the null terminator
+* We don't fix this issue in _snwprintf because of backward
+* compatibility. In new code, however, _snwprintf is #defined to
+* _swprintf_c so users get the fix.
+*
+*endif
+*
+* Multi-thread: (1) Since there is no stream, this routine must
+* never try to get the stream lock (i.e., there is no stream
+* lock either). (2) Also, since there is only one statically
+* allocated 'fake' iob, we must lock/unlock to prevent collisions.
+*
+*Entry:
+* wchar_t *string - pointer to place to put output
+*ifdef _COUNT_
+* size_t count - max number of wide characters to put in buffer
+*endif
+* wchar_t *format - format string to control data format/number
+* of arguments followed by list of arguments, number and type
+* controlled by format string
+*
+*Exit:
+* returns number of wide characters printed
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+int __cdecl swprintf_s (
+ wchar_t *string,
+ size_t sizeInWords,
+ const wchar_t *format,
+ ...
+ )
+{
+ int ret;
+ va_list arglist;
+
+ va_start(arglist, format);
+
+ ret = _vswprintf_s(string, sizeInWords, format, arglist);
+
+ va_end(arglist);
+
+ return ret;
+}
+
+int __cdecl _snwprintf_s (
+ wchar_t *string,
+ size_t sizeInWords,
+ size_t count,
+ const wchar_t *format,
+ ...
+ )
+{
+ int ret;
+ va_list arglist;
+
+ va_start(arglist, format);
+
+ ret = _vsnwprintf_s(string, sizeInWords, count, format, arglist);
+
+ va_end(arglist);
+
+ return ret;
+}
diff --git a/src/pal/src/safecrt/tcscat_s.inl b/src/pal/src/safecrt/tcscat_s.inl
new file mode 100644
index 0000000000..b6fefdc0ae
--- /dev/null
+++ b/src/pal/src/safecrt/tcscat_s.inl
@@ -0,0 +1,51 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*tcscat_s.inl - general implementation of _tcscpy_s
+*
+
+*
+*Purpose:
+* This file contains the general algorithm for strcat_s and its variants.
+*
+****/
+
+_FUNC_PROLOGUE
+errno_t __cdecl _FUNC_NAME(_CHAR *_DEST, size_t _SIZE, const _CHAR *_SRC)
+{
+ _CHAR *p;
+ size_t available;
+
+ /* validation section */
+ _VALIDATE_STRING(_DEST, _SIZE);
+ _VALIDATE_POINTER_RESET_STRING(_SRC, _DEST, _SIZE);
+
+ p = _DEST;
+ available = _SIZE;
+ while (available > 0 && *p != 0)
+ {
+ p++;
+ available--;
+ }
+
+ if (available == 0)
+ {
+ _RESET_STRING(_DEST, _SIZE);
+ _RETURN_DEST_NOT_NULL_TERMINATED(_DEST, _SIZE);
+ }
+
+ while ((*p++ = *_SRC++) != 0 && --available > 0)
+ {
+ }
+
+ if (available == 0)
+ {
+ _RESET_STRING(_DEST, _SIZE);
+ _RETURN_BUFFER_TOO_SMALL(_DEST, _SIZE);
+ }
+ _FILL_STRING(_DEST, _SIZE, _SIZE - available + 1);
+ _RETURN_NO_ERROR;
+}
+
diff --git a/src/pal/src/safecrt/tcscpy_s.inl b/src/pal/src/safecrt/tcscpy_s.inl
new file mode 100644
index 0000000000..b1192d8ee7
--- /dev/null
+++ b/src/pal/src/safecrt/tcscpy_s.inl
@@ -0,0 +1,39 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*tcscpy_s.inl - general implementation of _tcscpy_s
+*
+
+*
+*Purpose:
+* This file contains the general algorithm for strcpy_s and its variants.
+*
+****/
+
+_FUNC_PROLOGUE
+errno_t __cdecl _FUNC_NAME(_CHAR *_DEST, size_t _SIZE, const _CHAR *_SRC)
+{
+ _CHAR *p;
+ size_t available;
+
+ /* validation section */
+ _VALIDATE_STRING(_DEST, _SIZE);
+ _VALIDATE_POINTER_RESET_STRING(_SRC, _DEST, _SIZE);
+
+ p = _DEST;
+ available = _SIZE;
+ while ((*p++ = *_SRC++) != 0 && --available > 0)
+ {
+ }
+
+ if (available == 0)
+ {
+ _RESET_STRING(_DEST, _SIZE);
+ _RETURN_BUFFER_TOO_SMALL(_DEST, _SIZE);
+ }
+ _FILL_STRING(_DEST, _SIZE, _SIZE - available + 1);
+ _RETURN_NO_ERROR;
+}
+
diff --git a/src/pal/src/safecrt/tcsncat_s.inl b/src/pal/src/safecrt/tcsncat_s.inl
new file mode 100644
index 0000000000..6de501767d
--- /dev/null
+++ b/src/pal/src/safecrt/tcsncat_s.inl
@@ -0,0 +1,81 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*tcsncat_s.inl - general implementation of _tcscpy_s
+*
+
+*
+*Purpose:
+* This file contains the general algorithm for strncat_s and its variants.
+*
+****/
+
+_FUNC_PROLOGUE
+errno_t __cdecl _FUNC_NAME(_CHAR *_DEST, size_t _SIZE, const _CHAR *_SRC, size_t _COUNT)
+{
+ _CHAR *p;
+ size_t available;
+
+ if (_COUNT == 0 && _DEST == NULL && _SIZE == 0)
+ {
+ /* this case is allowed; nothing to do */
+ _RETURN_NO_ERROR;
+ }
+
+ /* validation section */
+ _VALIDATE_STRING(_DEST, _SIZE);
+ if (_COUNT != 0)
+ {
+ _VALIDATE_POINTER_RESET_STRING(_SRC, _DEST, _SIZE);
+ }
+
+ p = _DEST;
+ available = _SIZE;
+ while (available > 0 && *p != 0)
+ {
+ p++;
+ available--;
+ }
+
+ if (available == 0)
+ {
+ _RESET_STRING(_DEST, _SIZE);
+ _RETURN_DEST_NOT_NULL_TERMINATED(_DEST, _SIZE);
+ }
+
+ if (_COUNT == _TRUNCATE)
+ {
+ while ((*p++ = *_SRC++) != 0 && --available > 0)
+ {
+ }
+ }
+ else
+ {
+ _ASSERT_EXPR((!_CrtGetCheckCount() || _COUNT < available), "Buffer is too small");
+
+ while (_COUNT > 0 && (*p++ = *_SRC++) != 0 && --available > 0)
+ {
+ _COUNT--;
+ }
+ if (_COUNT == 0)
+ {
+ *p = 0;
+ }
+ }
+
+ if (available == 0)
+ {
+ if (_COUNT == _TRUNCATE)
+ {
+ _DEST[_SIZE - 1] = 0;
+ _RETURN_TRUNCATE;
+ }
+ _RESET_STRING(_DEST, _SIZE);
+ _RETURN_BUFFER_TOO_SMALL(_DEST, _SIZE);
+ }
+ _FILL_STRING(_DEST, _SIZE, _SIZE - available + 1);
+ _RETURN_NO_ERROR;
+}
+
diff --git a/src/pal/src/safecrt/tcsncpy_s.inl b/src/pal/src/safecrt/tcsncpy_s.inl
new file mode 100644
index 0000000000..54a79a03e7
--- /dev/null
+++ b/src/pal/src/safecrt/tcsncpy_s.inl
@@ -0,0 +1,71 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*tcsncpy_s.inl - general implementation of _tcsncpy_s
+*
+
+*
+*Purpose:
+* This file contains the general algorithm for strncpy_s and its variants.
+*
+****/
+
+_FUNC_PROLOGUE
+errno_t __cdecl _FUNC_NAME(_CHAR *_DEST, size_t _SIZE, const _CHAR *_SRC, size_t _COUNT)
+{
+ _CHAR *p;
+ size_t available;
+
+ if (_COUNT == 0 && _DEST == NULL && _SIZE == 0)
+ {
+ /* this case is allowed; nothing to do */
+ _RETURN_NO_ERROR;
+ }
+
+ /* validation section */
+ _VALIDATE_STRING(_DEST, _SIZE);
+ if (_COUNT == 0)
+ {
+ /* notice that the source string pointer can be NULL in this case */
+ _RESET_STRING(_DEST, _SIZE);
+ _RETURN_NO_ERROR;
+ }
+ _VALIDATE_POINTER_RESET_STRING(_SRC, _DEST, _SIZE);
+
+ p = _DEST;
+ available = _SIZE;
+ if (_COUNT == _TRUNCATE)
+ {
+ while ((*p++ = *_SRC++) != 0 && --available > 0)
+ {
+ }
+ }
+ else
+ {
+ _ASSERT_EXPR((!_CrtGetCheckCount() || _COUNT < _SIZE), "Buffer is too small");
+
+ while ((*p++ = *_SRC++) != 0 && --available > 0 && --_COUNT > 0)
+ {
+ }
+ if (_COUNT == 0)
+ {
+ *p = 0;
+ }
+ }
+
+ if (available == 0)
+ {
+ if (_COUNT == _TRUNCATE)
+ {
+ _DEST[_SIZE - 1] = 0;
+ _RETURN_TRUNCATE;
+ }
+ _RESET_STRING(_DEST, _SIZE);
+ _RETURN_BUFFER_TOO_SMALL(_DEST, _SIZE);
+ }
+ _FILL_STRING(_DEST, _SIZE, _SIZE - available + 1);
+ _RETURN_NO_ERROR;
+}
+
diff --git a/src/pal/src/safecrt/tcstok_s.inl b/src/pal/src/safecrt/tcstok_s.inl
new file mode 100644
index 0000000000..29ca5c6858
--- /dev/null
+++ b/src/pal/src/safecrt/tcstok_s.inl
@@ -0,0 +1,71 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*tcstok_s.inl - general implementation of _tcstok_s
+*
+
+*
+*Purpose:
+* This file contains the general algorithm for strtok_s and its variants.
+*
+****/
+
+_FUNC_PROLOGUE
+_CHAR * __cdecl _FUNC_NAME(_CHAR *_String, const _CHAR *_Control, _CHAR **_Context)
+{
+ _CHAR *token;
+ const _CHAR *ctl;
+
+ /* validation section */
+ _VALIDATE_POINTER_ERROR_RETURN(_Context, EINVAL, NULL);
+ _VALIDATE_POINTER_ERROR_RETURN(_Control, EINVAL, NULL);
+ _VALIDATE_CONDITION_ERROR_RETURN(_String != NULL || *_Context != NULL, EINVAL, NULL);
+
+ /* If string==NULL, continue with previous string */
+ if (!_String)
+ {
+ _String = *_Context;
+ }
+
+ /* Find beginning of token (skip over leading delimiters). Note that
+ * there is no token iff this loop sets string to point to the terminal null. */
+ for ( ; *_String != 0 ; _String++)
+ {
+ for (ctl = _Control; *ctl != 0 && *ctl != *_String; ctl++)
+ ;
+ if (*ctl == 0)
+ {
+ break;
+ }
+ }
+
+ token = _String;
+
+ /* Find the end of the token. If it is not the end of the string,
+ * put a null there. */
+ for ( ; *_String != 0 ; _String++)
+ {
+ for (ctl = _Control; *ctl != 0 && *ctl != *_String; ctl++)
+ ;
+ if (*ctl != 0)
+ {
+ *_String++ = 0;
+ break;
+ }
+ }
+
+ /* Update the context */
+ *_Context = _String;
+
+ /* Determine if a token has been found. */
+ if (token == _String)
+ {
+ return NULL;
+ }
+ else
+ {
+ return token;
+ }
+}
diff --git a/src/pal/src/safecrt/tmakepath_s.inl b/src/pal/src/safecrt/tmakepath_s.inl
new file mode 100644
index 0000000000..34c4842c61
--- /dev/null
+++ b/src/pal/src/safecrt/tmakepath_s.inl
@@ -0,0 +1,116 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*tmakepath_s.inl - general implementation of _tmakepath_s
+*
+
+*
+*Purpose:
+* This file contains the general algorithm for _makepath_s and its variants.
+*
+*******************************************************************************/
+
+_FUNC_PROLOGUE
+errno_t __cdecl _FUNC_NAME(__out_ecount_z(_SIZE) _CHAR *_DEST, __in_opt size_t _SIZE, __in_z_opt const _CHAR *_Drive, __in_z_opt const _CHAR *_Dir, __in_z_opt const _CHAR *_Filename, __in_z_opt const _CHAR *_Ext)
+{
+ size_t written;
+ const _CHAR *p;
+ _CHAR *d;
+
+ /* validation section */
+ _VALIDATE_STRING(_DEST, _SIZE);
+
+ /* copy drive */
+ written = 0;
+ d = _DEST;
+ if (_Drive != NULL && *_Drive != 0)
+ {
+ written += 2;
+ if(written >= _SIZE)
+ {
+ goto error_return;
+ }
+ *d++ = *_Drive;
+ *d++ = _T(':');
+ }
+
+ /* copy dir */
+ p = _Dir;
+ if (p != NULL && *p != 0)
+ {
+ do {
+ if(++written >= _SIZE)
+ {
+ goto error_return;
+ }
+ *d++ = *p++;
+ } while (*p != 0);
+
+#if _MBS_SUPPORT
+ p = _MBSDEC(_Dir, p);
+#else /* _MBS_SUPPORT */
+ p = p - 1;
+#endif /* _MBS_SUPPORT */
+ if (*p != _T('/') && *p != _T('\\'))
+ {
+ if(++written >= _SIZE)
+ {
+ goto error_return;
+ }
+ *d++ = _T('\\');
+ }
+ }
+
+ /* copy fname */
+ p = _Filename;
+ if (p != NULL)
+ {
+ while (*p != 0)
+ {
+ if(++written >= _SIZE)
+ {
+ goto error_return;
+ }
+ *d++ = *p++;
+ }
+ }
+
+ /* copy extension; check to see if a '.' needs to be inserted */
+ p = _Ext;
+ if (p != NULL)
+ {
+ if (*p != 0 && *p != _T('.'))
+ {
+ if(++written >= _SIZE)
+ {
+ goto error_return;
+ }
+ *d++ = _T('.');
+ }
+ while (*p != 0)
+ {
+ if(++written >= _SIZE)
+ {
+ goto error_return;
+ }
+ *d++ = *p++;
+ }
+ }
+
+ if(++written > _SIZE)
+ {
+ goto error_return;
+ }
+ *d = 0;
+ _FILL_STRING(_DEST, _SIZE, written);
+ _RETURN_NO_ERROR;
+
+error_return:
+ _RESET_STRING(_DEST, _SIZE);
+ _RETURN_BUFFER_TOO_SMALL(_DEST, _SIZE);
+
+ /* should never happen, but compiler can't tell */
+ return EINVAL;
+}
diff --git a/src/pal/src/safecrt/tsplitpath_s.inl b/src/pal/src/safecrt/tsplitpath_s.inl
new file mode 100644
index 0000000000..3a14fa5900
--- /dev/null
+++ b/src/pal/src/safecrt/tsplitpath_s.inl
@@ -0,0 +1,280 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*tsplitpath_s.inl - general implementation of _tsplitpath_s
+*
+
+*
+*Purpose:
+* This file contains the general algorithm for _splitpath_s and its variants.
+*
+*******************************************************************************/
+
+_FUNC_PROLOGUE
+errno_t __cdecl _FUNC_NAME(
+ __in_z const _CHAR *_Path,
+ __out_ecount_z_opt(_DriveSize) _CHAR *_Drive, __in size_t _DriveSize,
+ __out_ecount_z_opt(_DirSize) _CHAR *_Dir, __in size_t _DirSize,
+ __out_ecount_z_opt(_FilenameSize) _CHAR *_Filename, __in size_t _FilenameSize,
+ __out_ecount_z_opt(_ExtSize) _CHAR *_Ext, __in size_t _ExtSize
+)
+{
+ const _CHAR *tmp;
+ const _CHAR *last_slash;
+ const _CHAR *dot;
+ int drive_set = 0;
+ size_t length = 0;
+ int bEinval = 0;
+
+ /* validation section */
+ if (_Path == NULL)
+ {
+ goto error_einval;
+ }
+ if ((_Drive == NULL && _DriveSize != 0) || (_Drive != NULL && _DriveSize == 0))
+ {
+ goto error_einval;
+ }
+ if ((_Dir == NULL && _DirSize != 0) || (_Dir != NULL && _DirSize == 0))
+ {
+ goto error_einval;
+ }
+ if ((_Filename == NULL && _FilenameSize != 0) || (_Filename != NULL && _FilenameSize == 0))
+ {
+ goto error_einval;
+ }
+ if ((_Ext == NULL && _ExtSize != 0) || (_Ext != NULL && _ExtSize == 0))
+ {
+ goto error_einval;
+ }
+
+ /* check if _Path begins with the longpath prefix */
+ if (_Path[0] == _T('\\') && _Path[1] == _T('\\') && _Path[2] == _T('?') && _Path[3] == _T('\\'))
+ {
+ _Path += 4;
+ }
+
+ /* extract drive letter and ':', if any */
+ if (!drive_set)
+ {
+// The CorUnix PAL is never built on Windows and thus, the code below
+// for the drive check is not required.
+#if 0
+ size_t skip = _MAX_DRIVE - 2;
+ tmp = _Path;
+ while (skip > 0 && *tmp != 0)
+ {
+ skip--;
+ tmp++;
+ }
+ if (*tmp == _T(':'))
+ {
+ if (_Drive != NULL)
+ {
+ if (_DriveSize < _MAX_DRIVE)
+ {
+ goto error_erange;
+ }
+ _TCSNCPY_S(_Drive, _DriveSize, _Path, _MAX_DRIVE - 1);
+ }
+ _Path = tmp + 1;
+ }
+ else
+#endif
+ {
+ if (_Drive != NULL)
+ {
+ _RESET_STRING(_Drive, _DriveSize);
+ }
+ }
+ }
+
+ /* extract path string, if any. _Path now points to the first character
+ * of the path, if any, or the filename or extension, if no path was
+ * specified. Scan ahead for the last occurence, if any, of a '/' or
+ * '\' path separator character. If none is found, there is no path.
+ * We will also note the last '.' character found, if any, to aid in
+ * handling the extension.
+ */
+ last_slash = NULL;
+ dot = NULL;
+ tmp = _Path;
+ for (; *tmp != 0; ++tmp)
+ {
+#if _MBS_SUPPORT
+#pragma warning(push)
+#pragma warning(disable:4127)
+ if (_ISMBBLEAD(*tmp))
+#pragma warning(pop)
+ {
+ tmp++;
+ }
+ else
+#endif /* _MBS_SUPPORT */
+ {
+ if (*tmp == _T('/') || *tmp == _T('\\'))
+ {
+ /* point to one beyond for later copy */
+ last_slash = tmp + 1;
+ }
+ else if (*tmp == _T('.'))
+ {
+ dot = tmp;
+ }
+ }
+ }
+
+ if (last_slash != NULL)
+ {
+ /* found a path - copy up through last_slash or max characters
+ * allowed, whichever is smaller
+ */
+ if (_Dir != NULL) {
+ length = (size_t)(last_slash - _Path);
+ if (_DirSize <= length)
+ {
+ goto error_erange;
+ }
+ _TCSNCPY_S(_Dir, _DirSize, _Path, length);
+
+ // Normalize the path seperator
+ int iIndex;
+ for(iIndex = 0; iIndex < length; iIndex++)
+ {
+ if (_Dir[iIndex] == _T('\\'))
+ {
+ _Dir[iIndex] = _T('/');
+ }
+ }
+ }
+ _Path = last_slash;
+ }
+ else
+ {
+ /* there is no path */
+ if (_Dir != NULL)
+ {
+ _RESET_STRING(_Dir, _DirSize);
+ }
+ }
+
+ /* extract file name and extension, if any. Path now points to the
+ * first character of the file name, if any, or the extension if no
+ * file name was given. Dot points to the '.' beginning the extension,
+ * if any.
+ */
+ if (dot != NULL && (dot >= _Path))
+ {
+ /* found the marker for an extension - copy the file name up to the '.' */
+ if (_Filename)
+ {
+ length = (size_t)(dot - _Path);
+ if (length == 0)
+ {
+ // At this time, dot will be equal to _Path if string is something like "/."
+ // since _path was set to last_slash, which in turn, was set to "tmp +1"
+ // where "tmp" is the location where "/" was found. See code above for
+ // clarification.
+ //
+ // For such cases, return the "." in filename buffer.
+ //
+ // Thus, if the length is zero, we know its a string like "/." and thus, we
+ // set length to 1 to get the "." in filename buffer.
+ length = 1;
+ }
+
+ if (_FilenameSize <= length)
+ {
+ goto error_erange;
+ }
+ _TCSNCPY_S(_Filename, _FilenameSize, _Path, length);
+ }
+
+ /* now we can get the extension - remember that tmp still points
+ * to the terminating NULL character of path.
+ */
+ if (_Ext)
+ {
+ // At this time, _Path is pointing to the character after the last slash found.
+ // (See comments and code above for clarification).
+ //
+ // Returns extension as empty string for strings like "/.".
+ if (dot > _Path)
+ {
+ length = (size_t)(tmp - dot);
+ if (_ExtSize <= length)
+ {
+ goto error_erange;
+ }
+
+ /* Since dot pointed to the ".", make sure we actually have an extension
+ like ".cmd" and not just ".", OR
+
+ Confirm that its a string like "/.." - for this, return the
+ second "." in the extension part.
+
+ However, for strings like "/myfile.", return empty string
+ in extension buffer.
+ */
+ int fIsDir = (*(dot-1) == _T('.'))?1:0;
+ if (length > 1 || (length == 1 && fIsDir == 1))
+ _TCSNCPY_S(_Ext, _ExtSize, dot, length);
+ else
+ _RESET_STRING(_Ext, _ExtSize);
+ }
+ else
+ _RESET_STRING(_Ext, _ExtSize);
+ }
+ }
+ else
+ {
+ /* found no extension, give empty extension and copy rest of
+ * string into fname.
+ */
+ if (_Filename)
+ {
+ length = (size_t)(tmp - _Path);
+ if (_FilenameSize <= length)
+ {
+ goto error_erange;
+ }
+ _TCSNCPY_S(_Filename, _FilenameSize, _Path, length);
+ }
+ if (_Ext)
+ {
+ _RESET_STRING(_Ext, _ExtSize);
+ }
+ }
+
+ _RETURN_NO_ERROR;
+
+error_einval:
+ bEinval = 1;
+
+error_erange:
+ if (_Drive != NULL && _DriveSize > 0)
+ {
+ _RESET_STRING(_Drive, _DriveSize);
+ }
+ if (_Dir != NULL && _DirSize > 0)
+ {
+ _RESET_STRING(_Dir, _DirSize);
+ }
+ if (_Filename != NULL && _FilenameSize > 0)
+ {
+ _RESET_STRING(_Filename, _FilenameSize);
+ }
+ if (_Ext != NULL && _ExtSize > 0)
+ {
+ _RESET_STRING(_Ext, _ExtSize);
+ }
+
+ _VALIDATE_POINTER(_Path);
+ if (bEinval)
+ {
+ _RETURN_EINVAL;
+ }
+ return (errno = ERANGE);
+}
diff --git a/src/pal/src/safecrt/vsprintf.c b/src/pal/src/safecrt/vsprintf.c
new file mode 100644
index 0000000000..4f2bd9fdeb
--- /dev/null
+++ b/src/pal/src/safecrt/vsprintf.c
@@ -0,0 +1,268 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*vsprintf.c - print formatted data into a string from var arg list
+*
+
+*
+*Purpose:
+* defines vsprintf(), _vsnprintf() and _vsnprintf_s() - print formatted output to
+* a string, get the data from an argument ptr instead of explicit
+* arguments.
+*
+*******************************************************************************/
+
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include "internal_securecrt.h"
+
+#include "mbusafecrt_internal.h"
+
+typedef int (*OUTPUTFN)(miniFILE *, const char *, va_list);
+
+static int _vsnprintf_helper( OUTPUTFN outfn, char *string, size_t count, const char *format, va_list ap );
+static int _vscprintf_helper ( OUTPUTFN outfn, const char *format, va_list ap);
+
+/***
+*ifndef _COUNT_
+*int vsprintf(string, format, ap) - print formatted data to string from arg ptr
+*else
+*int _vsnprintf(string, cnt, format, ap) - print formatted data to string from arg ptr
+*endif
+*
+*Purpose:
+* Prints formatted data, but to a string and gets data from an argument
+* pointer.
+* Sets up a FILE so file i/o operations can be used, make string look
+* like a huge buffer to it, but _flsbuf will refuse to flush it if it
+* fills up. Appends '\0' to make it a true string.
+*
+* Allocate the 'fake' _iob[] entryit statically instead of on
+* the stack so that other routines can assume that _iob[] entries are in
+* are in DGROUP and, thus, are near.
+*
+*ifdef _COUNT_
+* The _vsnprintf() flavor takes a count argument that is
+* the max number of bytes that should be written to the
+* user's buffer.
+*endif
+*
+* Multi-thread: (1) Since there is no stream, this routine must never try
+* to get the stream lock (i.e., there is no stream lock either). (2)
+* Also, since there is only one staticly allocated 'fake' iob, we must
+* lock/unlock to prevent collisions.
+*
+*Entry:
+* char *string - place to put destination string
+*ifdef _COUNT_
+* size_t count - max number of bytes to put in buffer
+*endif
+* char *format - format string, describes format of data
+* va_list ap - varargs argument pointer
+*
+*Exit:
+* returns number of characters in string
+* returns -2 if the string has been truncated (only in _vsnprintf_helper)
+* returns -1 in other error cases
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+int __cdecl _vsnprintf_helper (
+ OUTPUTFN outfn,
+ char *string,
+ size_t count,
+ const char *format,
+ va_list ap
+ )
+{
+ miniFILE str;
+ miniFILE *outfile = &str;
+ int retval;
+
+ _VALIDATE_RETURN( (format != NULL), EINVAL, -1);
+
+ _VALIDATE_RETURN( (count == 0) || (string != NULL), EINVAL, -1 );
+
+ if(count>INT_MAX)
+ {
+ /* old-style functions allow any large value to mean unbounded */
+ outfile->_cnt = INT_MAX;
+ }
+ else
+ {
+ outfile->_cnt = (int)count;
+ }
+
+ outfile->_flag = _IOWRT|_IOSTRG;
+ outfile->_ptr = outfile->_base = string;
+
+ retval = outfn(outfile, format, ap );
+
+ if ( string==NULL)
+ return(retval);
+
+ if((retval >= 0) && (_putc_nolock('\0',outfile) != EOF))
+ return(retval);
+
+ string[count - 1] = 0;
+
+ if (outfile->_cnt < 0)
+ {
+ /* the buffer was too small; we return -2 to indicate truncation */
+ return -2;
+ }
+ return -1;
+}
+
+int __cdecl _vsprintf_s (
+ char *string,
+ size_t sizeInBytes,
+ const char *format,
+ va_list ap
+ )
+{
+ int retvalue = -1;
+
+ /* validation section */
+ _VALIDATE_RETURN(format != NULL, EINVAL, -1);
+ _VALIDATE_RETURN(string != NULL && sizeInBytes > 0, EINVAL, -1);
+
+ retvalue = _vsnprintf_helper(_output_s, string, sizeInBytes, format, ap);
+ if (retvalue < 0)
+ {
+ string[0] = 0;
+ _SECURECRT__FILL_STRING(string, sizeInBytes, 1);
+ }
+ if (retvalue == -2)
+ {
+ _VALIDATE_RETURN(("Buffer too small" && 0), ERANGE, -1);
+ }
+ if (retvalue >= 0)
+ {
+ _SECURECRT__FILL_STRING(string, sizeInBytes, retvalue + 1);
+ }
+
+ return retvalue;
+}
+
+int __cdecl _vsnprintf_s (
+ char *string,
+ size_t sizeInBytes,
+ size_t count,
+ const char *format,
+ va_list ap
+ )
+{
+ int retvalue = -1;
+ errno_t save_errno = 0;
+
+ /* validation section */
+ _VALIDATE_RETURN(format != NULL, EINVAL, -1);
+ if (count == 0 && string == NULL && sizeInBytes == 0)
+ {
+ /* this case is allowed; nothing to do */
+ return 0;
+ }
+ _VALIDATE_RETURN(string != NULL && sizeInBytes > 0, EINVAL, -1);
+
+ if (sizeInBytes > count)
+ {
+ save_errno = errno;
+ retvalue = _vsnprintf_helper(_output_s, string, count + 1, format, ap);
+ if (retvalue == -2)
+ {
+ /* the string has been truncated, return -1 */
+ _SECURECRT__FILL_STRING(string, sizeInBytes, count + 1);
+ if (errno == ERANGE)
+ {
+ errno = save_errno;
+ }
+ return -1;
+ }
+ }
+ else /* sizeInBytes <= count */
+ {
+ save_errno = errno;
+ retvalue = _vsnprintf_helper(_output_s, string, sizeInBytes, format, ap);
+ string[sizeInBytes - 1] = 0;
+ /* we allow truncation if count == _TRUNCATE */
+ if (retvalue == -2 && count == _TRUNCATE)
+ {
+ if (errno == ERANGE)
+ {
+ errno = save_errno;
+ }
+ return -1;
+ }
+ }
+
+ if (retvalue < 0)
+ {
+ string[0] = 0;
+ _SECURECRT__FILL_STRING(string, sizeInBytes, 1);
+ if (retvalue == -2)
+ {
+ _VALIDATE_RETURN(("Buffer too small" && 0), ERANGE, -1);
+ }
+ return -1;
+ }
+
+ _SECURECRT__FILL_STRING(string, sizeInBytes, retvalue + 1);
+
+ return (retvalue < 0 ? -1 : retvalue);
+}
+
+/***
+* _vscprintf() - counts the number of character needed to print the formatted
+* data
+*
+*Purpose:
+* Counts the number of characters in the fotmatted data.
+*
+*Entry:
+* char *format - format string, describes format of data
+* va_list ap - varargs argument pointer
+*
+*Exit:
+* returns number of characters needed to print formatted data.
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+#ifndef _COUNT_
+
+int __cdecl _vscprintf_helper (
+ OUTPUTFN outfn,
+ const char *format,
+ va_list ap
+ )
+{
+ miniFILE str;
+ miniFILE *outfile = &str;
+ int retval;
+
+ _VALIDATE_RETURN( (format != NULL), EINVAL, -1);
+
+ outfile->_cnt = INT_MAX; //MAXSTR;
+ outfile->_flag = _IOWRT|_IOSTRG;
+ outfile->_ptr = outfile->_base = NULL;
+
+ retval = outfn(outfile, format, ap);
+ return(retval);
+}
+
+int __cdecl _vscprintf (
+ const char *format,
+ va_list ap
+ )
+{
+ return _vscprintf_helper(_output, format, ap);
+}
+
+#endif /* _COUNT_ */
diff --git a/src/pal/src/safecrt/vswprint.c b/src/pal/src/safecrt/vswprint.c
new file mode 100644
index 0000000000..77c79b8752
--- /dev/null
+++ b/src/pal/src/safecrt/vswprint.c
@@ -0,0 +1,282 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*vswprint.c - print formatted data into a string from var arg list
+*
+*Purpose:
+* defines vswprintf(), _vswprintf_c and _vsnwprintf() - print formatted output to
+* a string, get the data from an argument ptr instead of explicit
+* arguments.
+*
+*******************************************************************************/
+
+
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include "internal_securecrt.h"
+
+#include "mbusafecrt_internal.h"
+
+typedef int (*WOUTPUTFN)(miniFILE *, const wchar_t *, va_list);
+
+static int _vswprintf_helper( WOUTPUTFN outfn, wchar_t *string, size_t count, const wchar_t *format, va_list ap );
+static int _vscwprintf_helper (WOUTPUTFN outfn, const wchar_t *format, va_list ap );
+
+/***
+*ifndef _COUNT_
+*int _vswprintf(string, format, ap) - print formatted data to string from arg ptr
+*else
+*ifndef _SWPRINTFS_ERROR_RETURN_FIX
+*int _vsnwprintf(string, cnt, format, ap) - print formatted data to string from arg ptr
+*else
+*int _vswprintf_c(string, cnt, format, ...) - print formatted data to string
+*endif
+*endif
+*
+*Purpose:
+* Prints formatted data, but to a string and gets data from an argument
+* pointer.
+* Sets up a FILE so file i/o operations can be used, make string look
+* like a huge buffer to it, but _flsbuf will refuse to flush it if it
+* fills up. Appends '\0' to make it a true string.
+*
+* Allocate the 'fake' _iob[] entryit statically instead of on
+* the stack so that other routines can assume that _iob[] entries are in
+* are in DGROUP and, thus, are near.
+*
+*ifdef _COUNT_
+*ifndef _SWPRINTFS_ERROR_RETURN_FIX
+* The _vsnwprintf() flavor takes a count argument that is
+* the max number of bytes that should be written to the
+* user's buffer.
+* We don't expose this function directly in the headers.
+*else
+* The _vswprintf_c() flavor does the same thing as the _snwprintf
+* above, but, it also fixes an issue in the return value in the case
+* when there isn't enough space to write the null terminator
+* We don't fix this issue in _vsnwprintf because of backward
+* compatibility. In new code, however, _vsnwprintf is #defined to
+* _vswprintf_c so users get the fix.
+*
+*endif
+*
+* Multi-thread: (1) Since there is no stream, this routine must never try
+* to get the stream lock (i.e., there is no stream lock either). (2)
+* Also, since there is only one statically allocated 'fake' iob, we must
+* lock/unlock to prevent collisions.
+*
+*Entry:
+* wchar_t *string - place to put destination string
+*ifdef _COUNT_
+* size_t count - max number of bytes to put in buffer
+*endif
+* wchar_t *format - format string, describes format of data
+* va_list ap - varargs argument pointer
+*
+*Exit:
+* returns number of wide characters in string
+* returns -2 if the string has been truncated (only in _vsnprintf_helper)
+* returns -1 in other error cases
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+int __cdecl _vswprintf_helper (
+ WOUTPUTFN woutfn,
+ wchar_t *string,
+ size_t count,
+ const wchar_t *format,
+ va_list ap
+ )
+{
+ miniFILE str;
+ miniFILE *outfile = &str;
+ int retval;
+
+ _VALIDATE_RETURN( (format != NULL), EINVAL, -1);
+
+ _VALIDATE_RETURN( (count == 0) || (string != NULL), EINVAL, -1 );
+
+ outfile->_flag = _IOWRT|_IOSTRG;
+ outfile->_ptr = outfile->_base = (char *) string;
+
+ if(count>(INT_MAX/sizeof(wchar_t)))
+ {
+ /* old-style functions allow any large value to mean unbounded */
+ outfile->_cnt = INT_MAX;
+ }
+ else
+ {
+ outfile->_cnt = (int)(count*sizeof(wchar_t));
+ }
+
+ retval = woutfn(outfile, format, ap );
+
+ if(string==NULL)
+ {
+ return retval;
+ }
+
+ if((retval >= 0) && (_putc_nolock('\0',outfile) != EOF) && (_putc_nolock('\0',outfile) != EOF))
+ return(retval);
+
+ string[count - 1] = 0;
+ if (outfile->_cnt < 0)
+ {
+ /* the buffer was too small; we return -2 to indicate truncation */
+ return -2;
+ }
+ return -1;
+}
+
+int __cdecl _vswprintf_s (
+ wchar_t *string,
+ size_t sizeInWords,
+ const wchar_t *format,
+ va_list ap
+ )
+{
+ int retvalue = -1;
+
+ /* validation section */
+ _VALIDATE_RETURN(format != NULL, EINVAL, -1);
+ _VALIDATE_RETURN(string != NULL && sizeInWords > 0, EINVAL, -1);
+
+ retvalue = _vswprintf_helper(_woutput_s, string, sizeInWords, format, ap);
+ if (retvalue < 0)
+ {
+ string[0] = 0;
+ _SECURECRT__FILL_STRING(string, sizeInWords, 1);
+ }
+ if (retvalue == -2)
+ {
+ _VALIDATE_RETURN(("Buffer too small" && 0), ERANGE, -1);
+ }
+ if (retvalue >= 0)
+ {
+ _SECURECRT__FILL_STRING(string, sizeInWords, retvalue + 1);
+ }
+
+ return retvalue;
+}
+
+int __cdecl _vsnwprintf_s (
+ wchar_t *string,
+ size_t sizeInWords,
+ size_t count,
+ const wchar_t *format,
+ va_list ap
+ )
+{
+ int retvalue = -1;
+ errno_t save_errno = 0;
+
+ /* validation section */
+ _VALIDATE_RETURN(format != NULL, EINVAL, -1);
+ if (count == 0 && string == NULL && sizeInWords == 0)
+ {
+ /* this case is allowed; nothing to do */
+ return 0;
+ }
+ _VALIDATE_RETURN(string != NULL && sizeInWords > 0, EINVAL, -1);
+
+ if (sizeInWords > count)
+ {
+ save_errno = errno;
+ retvalue = _vswprintf_helper(_woutput_s, string, count + 1, format, ap);
+ if (retvalue == -2)
+ {
+ /* the string has been truncated, return -1 */
+ _SECURECRT__FILL_STRING(string, sizeInWords, count + 1);
+ if (errno == ERANGE)
+ {
+ errno = save_errno;
+ }
+ return -1;
+ }
+ }
+ else /* sizeInWords <= count */
+ {
+ save_errno = errno;
+ retvalue = _vswprintf_helper(_woutput_s, string, sizeInWords, format, ap);
+ string[sizeInWords - 1] = 0;
+ /* we allow truncation if count == _TRUNCATE */
+ if (retvalue == -2 && count == _TRUNCATE)
+ {
+ if (errno == ERANGE)
+ {
+ errno = save_errno;
+ }
+ return -1;
+ }
+ }
+
+ if (retvalue < 0)
+ {
+ string[0] = 0;
+ _SECURECRT__FILL_STRING(string, sizeInWords, 1);
+ if (retvalue == -2)
+ {
+ _VALIDATE_RETURN(("Buffer too small" && 0), ERANGE, -1);
+ }
+ return -1;
+ }
+
+ _SECURECRT__FILL_STRING(string, sizeInWords, retvalue + 1);
+
+ return (retvalue < 0 ? -1 : retvalue);
+}
+
+/***
+* _vscwprintf() - counts the number of character needed to print the formatted
+* data
+*
+*Purpose:
+* Counts the number of characters in the fotmatted data.
+*
+*Entry:
+* wchar_t *format - format string, describes format of data
+* va_list ap - varargs argument pointer
+*
+*Exit:
+* returns number of characters needed to print formatted data.
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+#ifndef _COUNT_
+
+int __cdecl _vscwprintf_helper (
+ WOUTPUTFN woutfn,
+ const wchar_t *format,
+ va_list ap
+ )
+{
+ miniFILE str;
+ miniFILE *outfile = &str;
+ int retval;
+
+ _VALIDATE_RETURN( (format != NULL), EINVAL, -1);
+
+ outfile->_cnt = INT_MAX; //MAXSTR;
+ outfile->_flag = _IOWRT|_IOSTRG;
+ outfile->_ptr = outfile->_base = NULL;
+
+ retval = woutfn(outfile, format, ap);
+ return(retval);
+}
+
+int __cdecl _vscwprintf (
+ const wchar_t *format,
+ va_list ap
+ )
+{
+ return _vscwprintf_helper(_woutput_s, format, ap);
+}
+
+#endif /* _COUNT_ */
diff --git a/src/pal/src/safecrt/wcscat_s.c b/src/pal/src/safecrt/wcscat_s.c
new file mode 100644
index 0000000000..06179888ff
--- /dev/null
+++ b/src/pal/src/safecrt/wcscat_s.c
@@ -0,0 +1,36 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*wcscat_s.c - contains wcscat_s()
+*
+
+*
+*Purpose:
+* wcscat_s() appends one wchar_t string onto another.
+*
+* wcscat() concatenates (appends) a copy of the source string to the
+* end of the destination string.
+* Strings are wide-character strings.
+*
+*******************************************************************************/
+
+#define _SECURECRT_FILL_BUFFER 1
+#define _SECURECRT_FILL_BUFFER_THRESHOLD ((size_t)8)
+
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include "internal_securecrt.h"
+
+#include "mbusafecrt_internal.h"
+
+#define _FUNC_PROLOGUE
+#define _FUNC_NAME wcscat_s
+#define _CHAR wchar_t
+#define _DEST _Dst
+#define _SIZE _SizeInBytes
+#define _SRC _Src
+
+#include "tcscat_s.inl"
diff --git a/src/pal/src/safecrt/wcscpy_s.c b/src/pal/src/safecrt/wcscpy_s.c
new file mode 100644
index 0000000000..4c60a81489
--- /dev/null
+++ b/src/pal/src/safecrt/wcscpy_s.c
@@ -0,0 +1,33 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*strcpy_s.c - contains wcscpy_s()
+*
+
+*
+*Purpose:
+* wcscpy_s() copies one string onto another.
+*
+*******************************************************************************/
+
+#define _SECURECRT_FILL_BUFFER 1
+#define _SECURECRT_FILL_BUFFER_THRESHOLD ((size_t)8)
+
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include "internal_securecrt.h"
+
+#include "mbusafecrt_internal.h"
+
+#define _FUNC_PROLOGUE
+#define _FUNC_NAME wcscpy_s
+#define _CHAR wchar_t
+#define _DEST _Dst
+#define _SIZE _SizeInWords
+#define _SRC _Src
+
+#include "tcscpy_s.inl"
+
diff --git a/src/pal/src/safecrt/wcslen_s.c b/src/pal/src/safecrt/wcslen_s.c
new file mode 100644
index 0000000000..4fd5371035
--- /dev/null
+++ b/src/pal/src/safecrt/wcslen_s.c
@@ -0,0 +1,58 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*wcslen_s.c - contains wcsnlen() routine
+*
+
+*
+*Purpose:
+* wcslen returns the length of a null-terminated wide-character string,
+* not including the null wchar_t itself.
+*
+*******************************************************************************/
+
+
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include "internal_securecrt.h"
+
+#include "mbusafecrt_internal.h"
+
+/***
+*wcsnlen - return the length of a null-terminated wide-character string
+*
+*Purpose:
+* Finds the length in bytes of the given string, not including
+* the final null character. Only the first maxsize characters
+* are inspected: if the null character is not found, maxsize is
+* returned.
+*
+*Entry:
+* const wchar_t * wcs - string whose length is to be computed
+* size_t maxsize
+*
+*Exit:
+* Length of the string "wcs", exclusive of the final null byte, or
+* maxsize if the null character is not found.
+*
+*Exceptions:
+*
+*******************************************************************************/
+
+size_t __cdecl wcsnlen(const wchar_t *wcs, size_t maxsize)
+{
+ size_t n;
+
+ /* Note that we do not check if s == NULL, because we do not
+ * return errno_t...
+ */
+
+ for (n = 0; n < maxsize && *wcs; n++, wcs++)
+ ;
+
+ return n;
+}
+
diff --git a/src/pal/src/safecrt/wcsncat_s.c b/src/pal/src/safecrt/wcsncat_s.c
new file mode 100644
index 0000000000..1ff39d55f3
--- /dev/null
+++ b/src/pal/src/safecrt/wcsncat_s.c
@@ -0,0 +1,35 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*wcsncat_s.c - append n chars of string to new string
+*
+
+*
+*Purpose:
+* defines wcsncat_s() - appends n characters of string onto
+* end of other string
+*
+*******************************************************************************/
+
+#define _SECURECRT_FILL_BUFFER 1
+#define _SECURECRT_FILL_BUFFER_THRESHOLD ((size_t)8)
+
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include "internal_securecrt.h"
+
+#include "mbusafecrt_internal.h"
+
+#define _FUNC_PROLOGUE
+#define _FUNC_NAME wcsncat_s
+#define _CHAR wchar_t
+#define _DEST _Dst
+#define _SIZE _SizeInWords
+#define _SRC _Src
+#define _COUNT _Count
+
+#include "tcsncat_s.inl"
+
diff --git a/src/pal/src/safecrt/wcsncpy_s.c b/src/pal/src/safecrt/wcsncpy_s.c
new file mode 100644
index 0000000000..7902ded43a
--- /dev/null
+++ b/src/pal/src/safecrt/wcsncpy_s.c
@@ -0,0 +1,34 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*wcsncpy_s.c - copy at most n characters of wide-character string
+*
+
+*
+*Purpose:
+* defines wcsncpy_s() - copy at most n characters of wchar_t string
+*
+*******************************************************************************/
+
+#define _SECURECRT_FILL_BUFFER 1
+#define _SECURECRT_FILL_BUFFER_THRESHOLD ((size_t)8)
+
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include "internal_securecrt.h"
+
+#include "mbusafecrt_internal.h"
+
+#define _FUNC_PROLOGUE
+#define _FUNC_NAME wcsncpy_s
+#define _CHAR wchar_t
+#define _DEST _Dst
+#define _SIZE _SizeInWords
+#define _SRC _Src
+#define _COUNT _Count
+
+#include "tcsncpy_s.inl"
+
diff --git a/src/pal/src/safecrt/wcstok_s.c b/src/pal/src/safecrt/wcstok_s.c
new file mode 100644
index 0000000000..c99b30c773
--- /dev/null
+++ b/src/pal/src/safecrt/wcstok_s.c
@@ -0,0 +1,27 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*wcstok_s.c - tokenize a wide-character string with given delimiters
+*
+
+*
+*Purpose:
+* defines wcstok_s() - breaks wide-character string into series of token
+* via repeated calls.
+*
+*******************************************************************************/
+
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include "internal_securecrt.h"
+
+#include "mbusafecrt_internal.h"
+
+#define _FUNC_PROLOGUE
+#define _FUNC_NAME wcstok_s
+#define _CHAR wchar_t
+
+#include "tcstok_s.inl"
diff --git a/src/pal/src/safecrt/wmakepath_s.c b/src/pal/src/safecrt/wmakepath_s.c
new file mode 100644
index 0000000000..35ab7d386e
--- /dev/null
+++ b/src/pal/src/safecrt/wmakepath_s.c
@@ -0,0 +1,30 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*wmakepath_s.c - create path name from components
+*
+
+*
+*Purpose:
+* To provide support for creation of full path names from components
+*
+*******************************************************************************/
+
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include "internal_securecrt.h"
+
+#include "mbusafecrt_internal.h"
+
+#define _FUNC_PROLOGUE
+#define _FUNC_NAME _wmakepath_s
+#define _CHAR wchar_t
+#define _DEST _Dst
+#define _SIZE _SizeInWords
+#define _T(_Character) L##_Character
+#define _MBS_SUPPORT 0
+
+#include "tmakepath_s.inl"
diff --git a/src/pal/src/safecrt/wsplitpath_s.c b/src/pal/src/safecrt/wsplitpath_s.c
new file mode 100644
index 0000000000..c7fb107803
--- /dev/null
+++ b/src/pal/src/safecrt/wsplitpath_s.c
@@ -0,0 +1,30 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*wsplitpath_s.c - break down path name into components
+*
+
+*
+*Purpose:
+* To provide support for accessing the individual components of an
+* arbitrary path name
+*
+*******************************************************************************/
+
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include "internal_securecrt.h"
+
+#include "mbusafecrt_internal.h"
+
+#define _FUNC_PROLOGUE
+#define _FUNC_NAME _wsplitpath_s
+#define _CHAR wchar_t
+#define _TCSNCPY_S wcsncpy_s
+#define _T(_Character) L##_Character
+#define _MBS_SUPPORT 0
+
+#include "tsplitpath_s.inl"
diff --git a/src/pal/src/safecrt/xtoa_s.c b/src/pal/src/safecrt/xtoa_s.c
new file mode 100644
index 0000000000..42cc5786d1
--- /dev/null
+++ b/src/pal/src/safecrt/xtoa_s.c
@@ -0,0 +1,29 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*strtok_s.c - tokenize a string with given delimiters
+*
+
+*
+*Purpose:
+* defines strtok_s() - breaks string into series of token
+* via repeated calls.
+*
+*******************************************************************************/
+
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include "internal_securecrt.h"
+
+#include "mbusafecrt_internal.h"
+
+//#define __int64 long long
+
+#define _SECURE_ITOA
+
+#define TCHAR char
+#define _T(x) x
+#include "xtox_s.inl"
diff --git a/src/pal/src/safecrt/xtow_s.c b/src/pal/src/safecrt/xtow_s.c
new file mode 100644
index 0000000000..7a02424c85
--- /dev/null
+++ b/src/pal/src/safecrt/xtow_s.c
@@ -0,0 +1,28 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*strtok_s.c - tokenize a string with given delimiters
+*
+
+*
+*Purpose:
+* defines strtok_s() - breaks string into series of token
+* via repeated calls.
+*
+*******************************************************************************/
+
+#include <string.h>
+#include <errno.h>
+#include <limits.h>
+#include "internal_securecrt.h"
+
+#include "mbusafecrt_internal.h"
+
+#define _SECURE_ITOA
+
+#define _UNICODE
+#define TCHAR wchar_t
+#define _T(x) L##x
+#include "xtox_s.inl"
diff --git a/src/pal/src/safecrt/xtox_s.inl b/src/pal/src/safecrt/xtox_s.inl
new file mode 100644
index 0000000000..e07d87adf5
--- /dev/null
+++ b/src/pal/src/safecrt/xtox_s.inl
@@ -0,0 +1,450 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/***
+*xtoa.c - convert integers/longs to ASCII string
+*
+
+*
+*Purpose:
+* The module has code to convert integers/longs to ASCII strings. See
+*
+*******************************************************************************/
+
+#ifdef _UNICODE
+#define xtox_s xtow_s
+#define _itox_s _itow_s
+#define _ltox_s _ltow_s
+#define _ultox_s _ultow_s
+#define x64tox_s x64tow_s
+#define _i64tox_s _i64tow_s
+#define _ui64tox_s _ui64tow_s
+#define xtox xtow
+#define _itox _itow
+#define _ltox _ltow
+#define _ultox _ultow
+#define x64tox x64tow
+#define _i64tox _i64tow
+#define _ui64tox _ui64tow
+#else /* _UNICODE */
+#define xtox_s xtoa_s
+#define _itox_s _itoa_s
+#define _ltox_s _ltoa_s
+#define _ultox_s _ultoa_s
+#define x64tox_s x64toa_s
+#define _i64tox_s _i64toa_s
+#define _ui64tox_s _ui64toa_s
+#define xtox xtoa
+#define _itox _itoa
+#define _ltox _ltoa
+#define _ultox _ultoa
+#define x64tox x64toa
+#define _i64tox _i64toa
+#define _ui64tox _ui64toa
+#endif /* _UNICODE */
+
+/***
+*char *_itoa_s, *_ltoa_s, *_ultoa_s(val, buf, sizeInTChars, radix) - convert binary int to ASCII
+* string
+*
+*Purpose:
+* Converts an int to a character string.
+*
+*Entry:
+* val - number to be converted (int, long or unsigned long)
+* char *buf - ptr to buffer to place result
+* size_t sizeInTChars - size of the destination buffer
+* int radix - base to convert into
+*
+*Exit:
+* Fills in space pointed to by buf with string result.
+* Returns the errno_t: err != 0 means that something went wrong, and
+* an empty string (buf[0] = 0) is returned.
+*
+*Exceptions:
+* Input parameters and buffer length are validated.
+* Refer to the validation section of the function.
+*
+*******************************************************************************/
+
+/* helper routine that does the main job. */
+#ifdef _SECURE_ITOA
+static errno_t __stdcall xtox_s
+ (
+ unsigned long val,
+ TCHAR *buf,
+ size_t sizeInTChars,
+ unsigned radix,
+ int is_neg
+ )
+#else /* _SECURE_ITOA */
+static void __stdcall xtox
+ (
+ unsigned long val,
+ TCHAR *buf,
+ unsigned radix,
+ int is_neg
+ )
+#endif /* _SECURE_ITOA */
+{
+ TCHAR *p; /* pointer to traverse string */
+ TCHAR *firstdig; /* pointer to first digit */
+ TCHAR temp; /* temp char */
+ unsigned digval; /* value of digit */
+#ifdef _SECURE_ITOA
+ size_t length; /* current length of the string */
+
+ /* validation section */
+ _VALIDATE_RETURN_ERRCODE(buf != NULL, EINVAL);
+ _VALIDATE_RETURN_ERRCODE(sizeInTChars > 0, EINVAL);
+ _RESET_STRING(buf, sizeInTChars);
+ _VALIDATE_RETURN_ERRCODE(sizeInTChars > (size_t)(is_neg ? 2 : 1), ERANGE);
+ _VALIDATE_RETURN_ERRCODE(2 <= radix && radix <= 36, EINVAL);
+ length = 0;
+
+#endif /* _SECURE_ITOA */
+ p = buf;
+
+ if (is_neg) {
+ /* negative, so output '-' and negate */
+ *p++ = _T('-');
+#ifdef _SECURE_ITOA
+ length++;
+#endif /* _SECURE_ITOA */
+ val = (unsigned long)(-(long)val);
+ }
+
+ firstdig = p; /* save pointer to first digit */
+
+ do {
+ digval = (unsigned) (val % radix);
+ val /= radix; /* get next digit */
+
+ /* convert to ascii and store */
+ if (digval > 9)
+ *p++ = (TCHAR) (digval - 10 + _T('a')); /* a letter */
+ else
+ *p++ = (TCHAR) (digval + _T('0')); /* a digit */
+#ifndef _SECURE_ITOA
+ } while (val > 0);
+#else /* _SECURE_ITOA */
+ length++;
+ } while (val > 0 && length < sizeInTChars);
+
+ /* Check for buffer overrun */
+ if (length >= sizeInTChars)
+ {
+ buf[0] = '\0';
+ _VALIDATE_RETURN_ERRCODE(length < sizeInTChars, ERANGE);
+ }
+#endif /* _SECURE_ITOA */
+ /* We now have the digit of the number in the buffer, but in reverse
+ order. Thus we reverse them now. */
+
+ *p-- = _T('\0'); /* terminate string; p points to last digit */
+
+ do {
+ temp = *p;
+ *p = *firstdig;
+ *firstdig = temp; /* swap *p and *firstdig */
+ --p;
+ ++firstdig; /* advance to next two digits */
+ } while (firstdig < p); /* repeat until halfway */
+#ifdef _SECURE_ITOA
+ return 0;
+#endif /* _SECURE_ITOA */
+}
+
+/* Actual functions just call conversion helper with neg flag set correctly,
+ and return pointer to buffer. */
+
+#ifdef _SECURE_ITOA
+errno_t __cdecl _itox_s (
+ int val,
+ TCHAR *buf,
+ size_t sizeInTChars,
+ int radix
+ )
+{
+ errno_t e = 0;
+
+ if (radix == 10 && val < 0)
+ e = xtox_s((unsigned long)val, buf, sizeInTChars, radix, 1);
+ else
+ e = xtox_s((unsigned long)(unsigned int)val, buf, sizeInTChars, radix, 0);
+
+ return e;
+}
+
+errno_t __cdecl _ltox_s (
+ long val,
+ TCHAR *buf,
+ size_t sizeInTChars,
+ int radix
+ )
+{
+ return xtox_s((unsigned long)val, buf, sizeInTChars, radix, (radix == 10 && val < 0));
+}
+
+errno_t __cdecl _ultox_s (
+ unsigned long val,
+ TCHAR *buf,
+ size_t sizeInTChars,
+ int radix
+ )
+{
+ return xtox_s(val, buf, sizeInTChars, radix, 0);
+}
+
+#else /* _SECURE_ITOA */
+
+/***
+*char *_itoa, *_ltoa, *_ultoa(val, buf, radix) - convert binary int to ASCII
+* string
+*
+*Purpose:
+* Converts an int to a character string.
+*
+*Entry:
+* val - number to be converted (int, long or unsigned long)
+* int radix - base to convert into
+* char *buf - ptr to buffer to place result
+*
+*Exit:
+* fills in space pointed to by buf with string result
+* returns a pointer to this buffer
+*
+*Exceptions:
+* Input parameters are validated. The buffer is assumed to be big enough to
+* contain the string. Refer to the validation section of the function.
+*
+*******************************************************************************/
+
+/* Actual functions just call conversion helper with neg flag set correctly,
+ and return pointer to buffer. */
+
+TCHAR * __cdecl _itox (
+ int val,
+ TCHAR *buf,
+ int radix
+ )
+{
+ if (radix == 10 && val < 0)
+ xtox((unsigned long)val, buf, radix, 1);
+ else
+ xtox((unsigned long)(unsigned int)val, buf, radix, 0);
+ return buf;
+}
+
+TCHAR * __cdecl _ltox (
+ long val,
+ TCHAR *buf,
+ int radix
+ )
+{
+ xtox((unsigned long)val, buf, radix, (radix == 10 && val < 0));
+ return buf;
+}
+
+TCHAR * __cdecl _ultox (
+ unsigned long val,
+ TCHAR *buf,
+ int radix
+ )
+{
+ xtox(val, buf, radix, 0);
+ return buf;
+}
+
+#endif /* _SECURE_ITOA */
+
+#ifndef _NO_INT64
+
+/***
+*char *_i64toa_s(val, buf, sizeInTChars, radix) - convert binary int to ASCII
+* string
+*
+*Purpose:
+* Converts an int64 to a character string.
+*
+*Entry:
+* val - number to be converted
+* char *buf - ptr to buffer to place result
+* size_t sizeInTChars - size of the destination buffer
+* int radix - base to convert into
+*
+*Exit:
+* Fills in space pointed to by buf with string result.
+* Returns the errno_t: err != 0 means that something went wrong, and
+* an empty string (buf[0] = 0) is returned.
+*
+*Exceptions:
+* Input parameters and buffer length are validated.
+* Refer to the validation section of the function.
+*
+*******************************************************************************/
+
+#ifdef _SECURE_ITOA
+static errno_t __fastcall x64tox_s
+ (/* stdcall is faster and smaller... Might as well use it for the helper. */
+ unsigned __int64 val,
+ TCHAR *buf,
+ size_t sizeInTChars,
+ unsigned radix,
+ int is_neg
+ )
+#else /* _SECURE_ITOA */
+static void __fastcall x64tox
+ (/* stdcall is faster and smaller... Might as well use it for the helper. */
+ unsigned __int64 val,
+ TCHAR *buf,
+ unsigned radix,
+ int is_neg
+ )
+#endif /* _SECURE_ITOA */
+{
+ TCHAR *p; /* pointer to traverse string */
+ TCHAR *firstdig; /* pointer to first digit */
+ TCHAR temp; /* temp char */
+ unsigned digval; /* value of digit */
+#ifdef _SECURE_ITOA
+ size_t length; /* current length of the string */
+
+ /* validation section */
+ _VALIDATE_RETURN_ERRCODE(buf != NULL, EINVAL);
+ _VALIDATE_RETURN_ERRCODE(sizeInTChars > 0, EINVAL);
+ _RESET_STRING(buf, sizeInTChars);
+ _VALIDATE_RETURN_ERRCODE(sizeInTChars > (size_t)(is_neg ? 2 : 1), ERANGE);
+ _VALIDATE_RETURN_ERRCODE(2 <= radix && radix <= 36, EINVAL);
+ length = 0;
+#endif /* _SECURE_ITOA */
+ p = buf;
+
+ if ( is_neg )
+ {
+ *p++ = _T('-'); /* negative, so output '-' and negate */
+#ifdef _SECURE_ITOA
+ length++;
+#endif /* _SECURE_ITOA */
+ val = (unsigned __int64)(-(__int64)val);
+ }
+
+ firstdig = p; /* save pointer to first digit */
+
+ do {
+ digval = (unsigned) (val % radix);
+ val /= radix; /* get next digit */
+
+ /* convert to ascii and store */
+ if (digval > 9)
+ *p++ = (TCHAR) (digval - 10 + _T('a')); /* a letter */
+ else
+ *p++ = (TCHAR) (digval + _T('0')); /* a digit */
+
+#ifndef _SECURE_ITOA
+ } while (val > 0);
+#else /* _SECURE_ITOA */
+ length++;
+ } while (val > 0 && length < sizeInTChars);
+
+ /* Check for buffer overrun */
+ if (length >= sizeInTChars)
+ {
+ buf[0] = '\0';
+ _VALIDATE_RETURN_ERRCODE(length < sizeInTChars, ERANGE);
+ }
+#endif /* _SECURE_ITOA */
+ /* We now have the digit of the number in the buffer, but in reverse
+ order. Thus we reverse them now. */
+
+ *p-- = _T('\0'); /* terminate string; p points to last digit */
+
+ do {
+ temp = *p;
+ *p = *firstdig;
+ *firstdig = temp; /* swap *p and *firstdig */
+ --p;
+ ++firstdig; /* advance to next two digits */
+ } while (firstdig < p); /* repeat until halfway */
+
+#ifdef _SECURE_ITOA
+ return 0;
+#endif /* _SECURE_ITOA */
+}
+
+#ifdef _SECURE_ITOA
+
+/* Actual functions just call conversion helper with neg flag set correctly,
+ and return pointer to buffer. */
+
+errno_t __cdecl _i64tox_s (
+ long long val,
+ TCHAR *buf,
+ size_t sizeInTChars,
+ int radix
+ )
+{
+ return x64tox_s((unsigned __int64)val, buf, sizeInTChars, radix, (radix == 10 && val < 0));
+}
+
+errno_t __cdecl _ui64tox_s (
+ unsigned long long val,
+ TCHAR *buf,
+ size_t sizeInTChars,
+ int radix
+ )
+{
+ return x64tox_s(val, buf, sizeInTChars, radix, 0);
+}
+
+#else /* _SECURE_ITOA */
+
+/***
+*char *_i64toa(val, buf, radix) - convert binary int to ASCII
+* string
+*
+*Purpose:
+* Converts an int64 to a character string.
+*
+*Entry:
+* val - number to be converted
+* int radix - base to convert into
+* char *buf - ptr to buffer to place result
+*
+*Exit:
+* fills in space pointed to by buf with string result
+* returns a pointer to this buffer
+*
+*Exceptions:
+* Input parameters are validated. The buffer is assumed to be big enough to
+* contain the string. Refer to the validation section of the function.
+*
+*******************************************************************************/
+
+/* Actual functions just call conversion helper with neg flag set correctly,
+ and return pointer to buffer. */
+
+TCHAR * __cdecl _i64tox (
+ __int64 val,
+ TCHAR *buf,
+ int radix
+ )
+{
+ x64tox((unsigned __int64)val, buf, radix, (radix == 10 && val < 0));
+ return buf;
+}
+
+TCHAR * __cdecl _ui64tox (
+ unsigned __int64 val,
+ TCHAR *buf,
+ int radix
+ )
+{
+ x64tox(val, buf, radix, 0);
+ return buf;
+}
+
+#endif /* _SECURE_ITOA */
+
+#endif /* _NO_INT64 */
diff --git a/src/pal/src/sharedmemory/sharedmemory.cpp b/src/pal/src/sharedmemory/sharedmemory.cpp
new file mode 100644
index 0000000000..7f25cae49e
--- /dev/null
+++ b/src/pal/src/sharedmemory/sharedmemory.cpp
@@ -0,0 +1,1136 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#include "pal/sharedmemory.h"
+
+#include "pal/dbgmsg.h"
+#include "pal/file.hpp"
+#include "pal/malloc.hpp"
+#include "pal/thread.hpp"
+#include "pal/virtual.h"
+
+#include <sys/file.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+using namespace CorUnix;
+
+SET_DEFAULT_DEBUG_CHANNEL(SHMEM);
+
+#include "pal/sharedmemory.inl"
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// AutoFreeBuffer
+
+AutoFreeBuffer::AutoFreeBuffer(void *buffer) : m_buffer(buffer), m_cancel(false)
+{
+}
+
+AutoFreeBuffer::~AutoFreeBuffer()
+{
+ if (!m_cancel && m_buffer != nullptr)
+ {
+ free(m_buffer);
+ }
+}
+
+void AutoFreeBuffer::Cancel()
+{
+ m_cancel = true;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// SharedMemoryException
+
+SharedMemoryException::SharedMemoryException(DWORD errorCode) : m_errorCode(errorCode)
+{
+}
+
+DWORD SharedMemoryException::GetErrorCode() const
+{
+ return m_errorCode;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// SharedMemoryHelpers
+
+const mode_t SharedMemoryHelpers::PermissionsMask_AllUsers_ReadWrite =
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
+const mode_t SharedMemoryHelpers::PermissionsMask_AllUsers_ReadWriteExecute =
+ PermissionsMask_AllUsers_ReadWrite | (S_IXUSR | S_IXGRP | S_IXOTH);
+const UINT32 SharedMemoryHelpers::InvalidProcessId = static_cast<UINT32>(-1);
+const SIZE_T SharedMemoryHelpers::InvalidThreadId = static_cast<SIZE_T>(-1);
+const UINT64 SharedMemoryHelpers::InvalidSharedThreadId = static_cast<UINT64>(-1);
+
+void *SharedMemoryHelpers::Alloc(SIZE_T byteCount)
+{
+ void *buffer = InternalMalloc(byteCount);
+ if (buffer == nullptr)
+ {
+ throw SharedMemoryException(static_cast<DWORD>(SharedMemoryError::OutOfMemory));
+ }
+ return buffer;
+}
+
+SIZE_T SharedMemoryHelpers::AlignDown(SIZE_T value, SIZE_T alignment)
+{
+ _ASSERTE((alignment & (alignment - 1)) == 0); // must be a power of 2
+ return value & ~(alignment - 1);
+}
+
+SIZE_T SharedMemoryHelpers::AlignUp(SIZE_T value, SIZE_T alignment)
+{
+ _ASSERTE((alignment & (alignment - 1)) == 0); // must be a power of 2
+ return AlignDown(value + (alignment - 1), alignment);
+}
+
+bool SharedMemoryHelpers::EnsureDirectoryExists(const char *path, bool isGlobalLockAcquired, bool createIfNotExist)
+{
+ _ASSERTE(path != nullptr);
+ _ASSERTE(SharedMemoryManager::IsCreationDeletionProcessLockAcquired());
+
+ // Check if the path already exists
+ struct stat statInfo;
+ int statResult = stat(path, &statInfo);
+ if (statResult != 0 && errno == ENOENT)
+ {
+ if (!createIfNotExist)
+ {
+ return false;
+ }
+
+ // The path does not exist, create the directory. The permissions mask passed to mkdir() is filtered by the process'
+ // permissions umask, so mkdir() may not set all of the requested permissions. We need to use chmod() to set the proper
+ // permissions. That creates a race when there is no global lock acquired when creating the directory. Another user's
+ // process may create the directory and this user's process may try to use it before the other process sets the full
+ // permissions. In that case, create a temporary directory first, set the permissions, and rename it to the actual
+ // directory name.
+
+ if (isGlobalLockAcquired)
+ {
+ if (mkdir(path, PermissionsMask_AllUsers_ReadWriteExecute) != 0)
+ {
+ throw SharedMemoryException(static_cast<DWORD>(SharedMemoryError::IO));
+ }
+ if (chmod(path, PermissionsMask_AllUsers_ReadWriteExecute) != 0)
+ {
+ rmdir(path);
+ throw SharedMemoryException(static_cast<DWORD>(SharedMemoryError::IO));
+ }
+ return true;
+ }
+
+ char tempPath[] = SHARED_MEMORY_UNIQUE_TEMP_NAME_TEMPLATE;
+ if (mkdtemp(tempPath) == nullptr)
+ {
+ throw SharedMemoryException(static_cast<DWORD>(SharedMemoryError::IO));
+ }
+ if (chmod(tempPath, PermissionsMask_AllUsers_ReadWriteExecute) != 0)
+ {
+ rmdir(tempPath);
+ throw SharedMemoryException(static_cast<DWORD>(SharedMemoryError::IO));
+ }
+ if (rename(tempPath, path) == 0)
+ {
+ return true;
+ }
+
+ // Another process may have beaten us to it. Delete the temp directory and continue to check the requested directory to
+ // see if it meets our needs.
+ rmdir(tempPath);
+ statResult = stat(path, &statInfo);
+ }
+
+ // If the path exists, check that it's a directory
+ if (statResult != 0 || !(statInfo.st_mode & S_IFDIR))
+ {
+ throw SharedMemoryException(static_cast<DWORD>(SharedMemoryError::IO));
+ }
+
+ // Check the directory's permissions and try to update them
+ if ((statInfo.st_mode & PermissionsMask_AllUsers_ReadWriteExecute) == PermissionsMask_AllUsers_ReadWriteExecute)
+ {
+ return true;
+ }
+ if (!createIfNotExist || chmod(path, PermissionsMask_AllUsers_ReadWriteExecute) != 0)
+ {
+ throw SharedMemoryException(static_cast<DWORD>(SharedMemoryError::IO));
+ }
+ return true;
+}
+
+int SharedMemoryHelpers::Open(LPCSTR path, int flags, mode_t mode)
+{
+ int openErrorCode;
+ do
+ {
+ int fileDescriptor = InternalOpen(path, flags, mode);
+ if (fileDescriptor != -1)
+ {
+ return fileDescriptor;
+ }
+ openErrorCode = errno;
+ } while (openErrorCode == EINTR);
+
+ switch (openErrorCode)
+ {
+ case ENOENT:
+ _ASSERTE(!(flags & O_CREAT));
+ errno = openErrorCode;
+ return -1;
+
+ case ENAMETOOLONG:
+ throw SharedMemoryException(static_cast<DWORD>(SharedMemoryError::NameTooLong));
+
+ case EMFILE:
+ case ENFILE:
+ case ENOMEM:
+ throw SharedMemoryException(static_cast<DWORD>(SharedMemoryError::OutOfMemory));
+
+ default:
+ throw SharedMemoryException(static_cast<DWORD>(SharedMemoryError::IO));
+ }
+}
+
+int SharedMemoryHelpers::OpenDirectory(LPCSTR path)
+{
+ _ASSERTE(path != nullptr);
+ _ASSERTE(path[0] != '\0');
+
+ int fileDescriptor = Open(path, O_RDONLY);
+ _ASSERTE(fileDescriptor != -1 || errno == ENOENT);
+ return fileDescriptor;
+}
+
+int SharedMemoryHelpers::CreateOrOpenFile(LPCSTR path, bool createIfNotExist, bool *createdRef)
+{
+ _ASSERTE(path != nullptr);
+ _ASSERTE(path[0] != '\0');
+
+ // Try to open the file
+ int openFlags = O_RDWR;
+ int fileDescriptor = Open(path, openFlags);
+ if (fileDescriptor != -1)
+ {
+ if (createdRef != nullptr)
+ {
+ *createdRef = false;
+ }
+ return fileDescriptor;
+ }
+ _ASSERTE(errno == ENOENT);
+ if (!createIfNotExist)
+ {
+ if (createdRef != nullptr)
+ {
+ *createdRef = false;
+ }
+ return -1;
+ }
+
+ // File does not exist, create the file
+ openFlags |= O_CREAT | O_EXCL;
+ fileDescriptor = Open(path, openFlags, PermissionsMask_AllUsers_ReadWrite);
+ _ASSERTE(fileDescriptor != -1);
+
+ // The permissions mask passed to open() is filtered by the process' permissions umask, so open() may not set all of
+ // the requested permissions. Use chmod() to set the proper permissions.
+ if (chmod(path, PermissionsMask_AllUsers_ReadWrite) != 0)
+ {
+ CloseFile(fileDescriptor);
+ unlink(path);
+ throw SharedMemoryException(static_cast<DWORD>(SharedMemoryError::IO));
+ }
+
+ if (createdRef != nullptr)
+ {
+ *createdRef = true;
+ }
+ return fileDescriptor;
+}
+
+void SharedMemoryHelpers::CloseFile(int fileDescriptor)
+{
+ _ASSERTE(fileDescriptor != -1);
+
+ int closeResult;
+ do
+ {
+ closeResult = close(fileDescriptor);
+ } while (closeResult != 0 && errno == EINTR);
+}
+
+SIZE_T SharedMemoryHelpers::GetFileSize(int fileDescriptor)
+{
+ _ASSERTE(fileDescriptor != -1);
+
+ off_t endOffset = lseek(fileDescriptor, 0, SEEK_END);
+ if (endOffset == static_cast<off_t>(-1) ||
+ lseek(fileDescriptor, 0, SEEK_SET) == static_cast<off_t>(-1))
+ {
+ throw SharedMemoryException(static_cast<DWORD>(SharedMemoryError::IO));
+ }
+ return endOffset;
+}
+
+void SharedMemoryHelpers::SetFileSize(int fileDescriptor, SIZE_T byteCount)
+{
+ _ASSERTE(fileDescriptor != -1);
+ _ASSERTE(static_cast<off_t>(byteCount) == byteCount);
+
+ while (true)
+ {
+ int ftruncateResult = ftruncate(fileDescriptor, static_cast<off_t>(byteCount));
+ if (ftruncateResult == 0)
+ {
+ break;
+ }
+ if (errno != EINTR)
+ {
+ throw SharedMemoryException(static_cast<DWORD>(SharedMemoryError::IO));
+ }
+ }
+}
+
+void *SharedMemoryHelpers::MemoryMapFile(int fileDescriptor, SIZE_T byteCount)
+{
+ _ASSERTE(fileDescriptor != -1);
+ _ASSERTE(byteCount > sizeof(SharedMemorySharedDataHeader));
+ _ASSERTE(AlignDown(byteCount, VIRTUAL_PAGE_SIZE) == byteCount);
+
+ void *sharedMemoryBuffer = mmap(nullptr, byteCount, PROT_READ | PROT_WRITE, MAP_SHARED, fileDescriptor, 0);
+ if (sharedMemoryBuffer != MAP_FAILED)
+ {
+ return sharedMemoryBuffer;
+ }
+ switch (errno)
+ {
+ case ENFILE:
+ case ENOMEM:
+ throw SharedMemoryException(static_cast<DWORD>(SharedMemoryError::OutOfMemory));
+
+ default:
+ throw SharedMemoryException(static_cast<DWORD>(SharedMemoryError::IO));
+ }
+}
+
+bool SharedMemoryHelpers::TryAcquireFileLock(int fileDescriptor, int operation)
+{
+ // A file lock is acquired once per file descriptor, so the caller will need to synchronize threads of this process
+
+ _ASSERTE(fileDescriptor != -1);
+ _ASSERTE(!(operation & LOCK_UN));
+
+ while (true)
+ {
+ if (flock(fileDescriptor, operation) == 0)
+ {
+ return true;
+ }
+
+ int flockError = errno;
+ switch (flockError)
+ {
+ case EWOULDBLOCK:
+ return false;
+
+ case EINTR:
+ continue;
+
+ default:
+ throw SharedMemoryException(static_cast<DWORD>(SharedMemoryError::OutOfMemory));
+ }
+ }
+}
+
+void SharedMemoryHelpers::ReleaseFileLock(int fileDescriptor)
+{
+ _ASSERTE(fileDescriptor != -1);
+
+ int flockResult;
+ do
+ {
+ flockResult = flock(fileDescriptor, LOCK_UN);
+ } while (flockResult != 0 && errno == EINTR);
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// SharedMemoryId
+
+SharedMemoryId::SharedMemoryId() : m_name(nullptr)
+{
+}
+
+SharedMemoryId::SharedMemoryId(LPCSTR name, SIZE_T nameCharCount, bool isSessionScope)
+ : m_name(name), m_nameCharCount(nameCharCount), m_isSessionScope(isSessionScope)
+{
+ _ASSERTE(name != nullptr);
+ _ASSERTE(nameCharCount != 0);
+ _ASSERTE(nameCharCount <= SHARED_MEMORY_MAX_FILE_NAME_CHAR_COUNT);
+ _ASSERTE(strlen(name) == nameCharCount);
+}
+
+SharedMemoryId::SharedMemoryId(LPCSTR name)
+{
+ _ASSERTE(name != nullptr);
+
+ // Look for "Global\" and "Local\" prefixes in the name, and determine the session ID
+ if (strncmp(name, "Global\\", 7) == 0)
+ {
+ m_isSessionScope = false;
+ name += _countof("Global\\") - 1;
+ }
+ else
+ {
+ if (strncmp(name, "Local\\", 6) == 0)
+ {
+ name += _countof("Local\\") - 1;
+ }
+ m_isSessionScope = true;
+ }
+ m_name = name;
+
+ m_nameCharCount = strlen(name);
+ if (m_nameCharCount == 0)
+ {
+ throw SharedMemoryException(static_cast<DWORD>(SharedMemoryError::NameEmpty));
+ }
+ if (m_nameCharCount > SHARED_MEMORY_MAX_FILE_NAME_CHAR_COUNT)
+ {
+ throw SharedMemoryException(static_cast<DWORD>(SharedMemoryError::NameTooLong));
+ }
+
+ // Look for invalid characters '\' and '/' in the name
+ for (SIZE_T i = 0; i < m_nameCharCount; ++i)
+ {
+ char c = name[i];
+ if (c == '\\' || c == '/')
+ {
+ throw SharedMemoryException(static_cast<DWORD>(SharedMemoryError::NameInvalid));
+ }
+ }
+}
+
+LPCSTR SharedMemoryId::GetName() const
+{
+ _ASSERTE(m_name != nullptr);
+ return m_name;
+}
+
+SIZE_T SharedMemoryId::GetNameCharCount() const
+{
+ _ASSERTE(m_name != nullptr);
+ return m_nameCharCount;
+}
+
+bool SharedMemoryId::IsSessionScope() const
+{
+ _ASSERTE(m_name != nullptr);
+ return m_isSessionScope;
+}
+
+bool SharedMemoryId::Equals(SharedMemoryId *other) const
+{
+ return
+ GetNameCharCount() == other->GetNameCharCount() &&
+ IsSessionScope() == other->IsSessionScope() &&
+ strcmp(GetName(), other->GetName()) == 0;
+}
+
+SIZE_T SharedMemoryId::AppendSessionDirectoryName(
+ char (&path)[SHARED_MEMORY_MAX_FILE_PATH_CHAR_COUNT + 1],
+ SIZE_T pathCharCount) const
+{
+ if (IsSessionScope())
+ {
+ pathCharCount = SharedMemoryHelpers::CopyString(path, pathCharCount, SHARED_MEMORY_SESSION_DIRECTORY_NAME_PREFIX);
+ pathCharCount = SharedMemoryHelpers::AppendUInt32String(path, pathCharCount, GetCurrentSessionId());
+ }
+ else
+ {
+ pathCharCount = SharedMemoryHelpers::CopyString(path, pathCharCount, SHARED_MEMORY_GLOBAL_DIRECTORY_NAME);
+ }
+
+ _ASSERTE(pathCharCount <= SHARED_MEMORY_MAX_FILE_PATH_CHAR_COUNT);
+ return pathCharCount;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// SharedMemorySharedDataHeader
+
+SIZE_T SharedMemorySharedDataHeader::DetermineTotalByteCount(SIZE_T dataByteCount)
+{
+ return SharedMemoryHelpers::AlignUp(sizeof(SharedMemorySharedDataHeader) + dataByteCount, VIRTUAL_PAGE_SIZE);
+}
+
+SharedMemorySharedDataHeader::SharedMemorySharedDataHeader(SharedMemoryType type, UINT8 version)
+ : m_type(type), m_version(version)
+{
+}
+
+SharedMemoryType SharedMemorySharedDataHeader::GetType() const
+{
+ return m_type;
+}
+
+UINT8 SharedMemorySharedDataHeader::GetVersion() const
+{
+ return m_version;
+}
+
+void *SharedMemorySharedDataHeader::GetData()
+{
+ return this + 1;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// SharedMemoryProcessDataHeader
+
+SharedMemoryProcessDataHeader *SharedMemoryProcessDataHeader::CreateOrOpen(
+ LPCSTR name,
+ SharedMemorySharedDataHeader requiredSharedDataHeader,
+ SIZE_T sharedDataByteCount,
+ bool createIfNotExist,
+ bool *createdRef)
+{
+ _ASSERTE(name != nullptr);
+ _ASSERTE(sharedDataByteCount != 0);
+ _ASSERTE(!createIfNotExist || createdRef != nullptr);
+ _ASSERTE(SharedMemoryManager::IsCreationDeletionProcessLockAcquired());
+ _ASSERTE(!SharedMemoryManager::IsCreationDeletionFileLockAcquired());
+
+ if (createdRef != nullptr)
+ {
+ *createdRef = false;
+ }
+
+ SharedMemoryId id(name);
+
+ struct AutoCleanup
+ {
+ bool m_acquiredCreationDeletionFileLock;
+ char *m_filePath;
+ SIZE_T m_sessionDirectoryPathCharCount;
+ bool m_createdFile;
+ int m_fileDescriptor;
+ bool m_acquiredFileLock;
+ void *m_mappedBuffer;
+ SIZE_T m_mappedBufferByteCount;
+ bool m_cancel;
+
+ AutoCleanup()
+ : m_acquiredCreationDeletionFileLock(false),
+ m_filePath(nullptr),
+ m_sessionDirectoryPathCharCount(0),
+ m_createdFile(false),
+ m_fileDescriptor(-1),
+ m_acquiredFileLock(false),
+ m_mappedBuffer(nullptr),
+ m_mappedBufferByteCount(0),
+ m_cancel(false)
+ {
+ }
+
+ ~AutoCleanup()
+ {
+ if (m_cancel)
+ {
+ return;
+ }
+
+ if (m_mappedBuffer != nullptr)
+ {
+ _ASSERTE(m_mappedBufferByteCount != 0);
+ munmap(m_mappedBuffer, m_mappedBufferByteCount);
+ }
+
+ if (m_acquiredFileLock)
+ {
+ _ASSERTE(m_fileDescriptor != -1);
+ SharedMemoryHelpers::ReleaseFileLock(m_fileDescriptor);
+ }
+
+ if (m_fileDescriptor != -1)
+ {
+ SharedMemoryHelpers::CloseFile(m_fileDescriptor);
+ }
+
+ if (m_createdFile)
+ {
+ _ASSERTE(m_filePath != nullptr);
+ unlink(m_filePath);
+ }
+
+ if (m_sessionDirectoryPathCharCount != 0)
+ {
+ _ASSERTE(m_filePath != nullptr);
+ m_filePath[m_sessionDirectoryPathCharCount] = '\0';
+ rmdir(m_filePath);
+ }
+
+ if (m_acquiredCreationDeletionFileLock)
+ {
+ SharedMemoryManager::ReleaseCreationDeletionFileLock();
+ }
+ }
+ } autoCleanup;
+
+ SharedMemoryProcessDataHeader *processDataHeader = SharedMemoryManager::FindProcessDataHeader(&id);
+ if (processDataHeader != nullptr)
+ {
+ _ASSERTE(
+ processDataHeader->GetSharedDataTotalByteCount() ==
+ SharedMemorySharedDataHeader::DetermineTotalByteCount(sharedDataByteCount));
+ processDataHeader->IncRefCount();
+ return processDataHeader;
+ }
+
+ SharedMemoryManager::AcquireCreationDeletionFileLock();
+ autoCleanup.m_acquiredCreationDeletionFileLock = true;
+
+ // Create the session directory
+ char filePath[SHARED_MEMORY_MAX_FILE_PATH_CHAR_COUNT + 1];
+ SIZE_T filePathCharCount = SharedMemoryHelpers::CopyString(filePath, 0, SHARED_MEMORY_SHARED_MEMORY_DIRECTORY_PATH);
+ filePath[filePathCharCount++] = '/';
+ filePathCharCount = id.AppendSessionDirectoryName(filePath, filePathCharCount);
+ if (!SharedMemoryHelpers::EnsureDirectoryExists(filePath, true /* isGlobalLockAcquired */, createIfNotExist))
+ {
+ _ASSERTE(!createIfNotExist);
+ return nullptr;
+ }
+ autoCleanup.m_filePath = filePath;
+ autoCleanup.m_sessionDirectoryPathCharCount = filePathCharCount;
+
+ // Create or open the shared memory file
+ filePath[filePathCharCount++] = '/';
+ filePathCharCount = SharedMemoryHelpers::CopyString(filePath, filePathCharCount, id.GetName(), id.GetNameCharCount());
+ bool createdFile;
+ int fileDescriptor = SharedMemoryHelpers::CreateOrOpenFile(filePath, createIfNotExist, &createdFile);
+ if (fileDescriptor == -1)
+ {
+ _ASSERTE(!createIfNotExist);
+ return nullptr;
+ }
+ autoCleanup.m_createdFile = createdFile;
+ autoCleanup.m_fileDescriptor = fileDescriptor;
+
+ bool clearContents = false;
+ if (!createdFile)
+ {
+ // A shared file lock on the shared memory file would be held by any process that has opened the same file. Try to take
+ // an exclusive lock on the file. Successfully acquiring an exclusive lock indicates that no process has a reference to
+ // the shared memory file, and this process can reinitialize its contents.
+ if (SharedMemoryHelpers::TryAcquireFileLock(fileDescriptor, LOCK_EX | LOCK_NB))
+ {
+ // The shared memory file is not being used, flag it as created so that its contents will be reinitialized
+ SharedMemoryHelpers::ReleaseFileLock(fileDescriptor);
+ autoCleanup.m_createdFile = true;
+ if (!createIfNotExist)
+ {
+ return nullptr;
+ }
+ createdFile = true;
+ clearContents = true;
+ }
+ }
+
+ // Set or validate the file length
+ SIZE_T sharedDataTotalByteCount = SharedMemorySharedDataHeader::DetermineTotalByteCount(sharedDataByteCount);
+ if (createdFile)
+ {
+ SharedMemoryHelpers::SetFileSize(fileDescriptor, sharedDataTotalByteCount);
+ }
+ else if (SharedMemoryHelpers::GetFileSize(fileDescriptor) != sharedDataTotalByteCount)
+ {
+ throw SharedMemoryException(static_cast<DWORD>(SharedMemoryError::HeaderMismatch));
+ }
+
+ // Acquire and hold a shared file lock on the shared memory file as long as it is open, to indicate that this process is
+ // using the file. An exclusive file lock is attempted above to detect whether the file contents are valid, for the case
+ // where a process crashes or is killed after the file is created. Since we already hold the creation/deletion locks, a
+ // non-blocking file lock should succeed.
+ if (!SharedMemoryHelpers::TryAcquireFileLock(fileDescriptor, LOCK_SH | LOCK_NB))
+ {
+ throw SharedMemoryException(static_cast<DWORD>(SharedMemoryError::IO));
+ }
+ autoCleanup.m_acquiredFileLock = true;
+
+ // Map the file into memory, and initialize or validate the header
+ void *mappedBuffer = SharedMemoryHelpers::MemoryMapFile(fileDescriptor, sharedDataTotalByteCount);
+ autoCleanup.m_mappedBuffer = mappedBuffer;
+ autoCleanup.m_mappedBufferByteCount = sharedDataTotalByteCount;
+ SharedMemorySharedDataHeader *sharedDataHeader;
+ if (createdFile)
+ {
+ if (clearContents)
+ {
+ memset(mappedBuffer, 0, sharedDataTotalByteCount);
+ }
+ sharedDataHeader = new(mappedBuffer) SharedMemorySharedDataHeader(requiredSharedDataHeader);
+ }
+ else
+ {
+ sharedDataHeader = reinterpret_cast<SharedMemorySharedDataHeader *>(mappedBuffer);
+ if (sharedDataHeader->GetType() != requiredSharedDataHeader.GetType() ||
+ sharedDataHeader->GetVersion() != requiredSharedDataHeader.GetVersion())
+ {
+ throw SharedMemoryException(static_cast<DWORD>(SharedMemoryError::HeaderMismatch));
+ }
+ }
+
+ // When *createdRef is true, the creation/deletion file lock will remain locked upon returning for the caller to initialize
+ // the shared data. The caller must release the file lock afterwards.
+ if (!createdFile)
+ {
+ autoCleanup.m_acquiredCreationDeletionFileLock = false;
+ SharedMemoryManager::ReleaseCreationDeletionFileLock();
+ }
+
+ processDataHeader = SharedMemoryProcessDataHeader::New(&id, fileDescriptor, sharedDataHeader, sharedDataTotalByteCount);
+
+ autoCleanup.m_cancel = true;
+ if (createdFile)
+ {
+ _ASSERTE(createIfNotExist);
+ _ASSERTE(createdRef != nullptr);
+ *createdRef = true;
+ }
+ return processDataHeader;
+}
+
+SharedMemoryProcessDataHeader *SharedMemoryProcessDataHeader::PalObject_GetProcessDataHeader(CorUnix::IPalObject *object)
+{
+ _ASSERTE(object != nullptr);
+ _ASSERTE(object->GetObjectType()->GetId() == otiNamedMutex);
+ _ASSERTE(object->GetObjectType()->GetImmutableDataSize() == sizeof(SharedMemoryProcessDataHeader *));
+
+ void *immutableDataBuffer;
+ PAL_ERROR errorCode = object->GetImmutableData(&immutableDataBuffer);
+ _ASSERTE(errorCode == NO_ERROR);
+ _ASSERTE(immutableDataBuffer != nullptr);
+ return *reinterpret_cast<SharedMemoryProcessDataHeader **>(immutableDataBuffer);
+}
+
+void SharedMemoryProcessDataHeader::PalObject_SetProcessDataHeader(
+ CorUnix::IPalObject *object,
+ SharedMemoryProcessDataHeader *processDataHeader)
+{
+ _ASSERTE(object != nullptr);
+ _ASSERTE(object->GetObjectType()->GetId() == otiNamedMutex);
+ _ASSERTE(object->GetObjectType()->GetImmutableDataSize() == sizeof(SharedMemoryProcessDataHeader *));
+ _ASSERTE(processDataHeader != nullptr);
+
+ void *immutableDataBuffer;
+ PAL_ERROR errorCode = object->GetImmutableData(&immutableDataBuffer);
+ _ASSERTE(errorCode == NO_ERROR);
+ _ASSERTE(immutableDataBuffer != nullptr);
+ *reinterpret_cast<SharedMemoryProcessDataHeader **>(immutableDataBuffer) = processDataHeader;
+}
+
+void SharedMemoryProcessDataHeader::PalObject_Close(
+ CPalThread *thread,
+ IPalObject *object,
+ bool isShuttingDown,
+ bool cleanUpPalSharedState)
+{
+ // This function's signature matches OBJECTCLEANUPROUTINE
+ _ASSERTE(thread != nullptr);
+ _ASSERTE(object != nullptr);
+ _ASSERTE(object->GetObjectType()->GetId() == otiNamedMutex);
+ _ASSERTE(object->GetObjectType()->GetImmutableDataSize() == sizeof(SharedMemoryProcessDataHeader *));
+
+ SharedMemoryProcessDataHeader *processDataHeader = PalObject_GetProcessDataHeader(object);
+ if (processDataHeader == nullptr)
+ {
+ // The object was created, but an error must have occurred before the process data was initialized
+ return;
+ }
+
+ SharedMemoryManager::AcquireCreationDeletionProcessLock();
+ processDataHeader->DecRefCount();
+ SharedMemoryManager::ReleaseCreationDeletionProcessLock();
+}
+
+SharedMemoryProcessDataHeader::SharedMemoryProcessDataHeader(
+ SharedMemoryId *id,
+ int fileDescriptor,
+ SharedMemorySharedDataHeader *sharedDataHeader,
+ SIZE_T sharedDataTotalByteCount)
+ :
+ m_refCount(1),
+ m_data(nullptr),
+ m_fileDescriptor(fileDescriptor),
+ m_sharedDataHeader(sharedDataHeader),
+ m_sharedDataTotalByteCount(sharedDataTotalByteCount),
+ m_nextInProcessDataHeaderList(nullptr)
+{
+ _ASSERTE(SharedMemoryManager::IsCreationDeletionProcessLockAcquired());
+ _ASSERTE(id != nullptr);
+ _ASSERTE(fileDescriptor != -1);
+ _ASSERTE(sharedDataHeader != nullptr);
+ _ASSERTE(sharedDataTotalByteCount > sizeof(SharedMemorySharedDataHeader));
+ _ASSERTE(SharedMemoryHelpers::AlignDown(sharedDataTotalByteCount, VIRTUAL_PAGE_SIZE) == sharedDataTotalByteCount);
+
+ // Copy the name and initialize the ID
+ char *nameCopy = reinterpret_cast<char *>(this + 1);
+ SIZE_T nameByteCount = id->GetNameCharCount() + 1;
+ memcpy_s(nameCopy, nameByteCount, id->GetName(), nameByteCount);
+ m_id = SharedMemoryId(nameCopy, id->GetNameCharCount(), id->IsSessionScope());
+
+ SharedMemoryManager::AddProcessDataHeader(this);
+}
+
+SharedMemoryProcessDataHeader *SharedMemoryProcessDataHeader::New(
+ SharedMemoryId *id,
+ int fileDescriptor,
+ SharedMemorySharedDataHeader *sharedDataHeader,
+ SIZE_T sharedDataTotalByteCount)
+{
+ _ASSERTE(id != nullptr);
+
+ // Allocate space for the header and a copy of the name
+ SIZE_T nameByteCount = id->GetNameCharCount() + 1;
+ SIZE_T totalByteCount = sizeof(SharedMemoryProcessDataHeader) + nameByteCount;
+ void *buffer = SharedMemoryHelpers::Alloc(totalByteCount);
+ AutoFreeBuffer autoFreeBuffer(buffer);
+ SharedMemoryProcessDataHeader *processDataHeader =
+ new(buffer) SharedMemoryProcessDataHeader(id, fileDescriptor, sharedDataHeader, sharedDataTotalByteCount);
+ autoFreeBuffer.Cancel();
+ return processDataHeader;
+}
+
+SharedMemoryProcessDataHeader::~SharedMemoryProcessDataHeader()
+{
+ _ASSERTE(m_refCount == 0);
+ Close();
+}
+
+void SharedMemoryProcessDataHeader::Close()
+{
+ _ASSERTE(SharedMemoryManager::IsCreationDeletionProcessLockAcquired());
+ _ASSERTE(!SharedMemoryManager::IsCreationDeletionFileLockAcquired());
+
+ // If the ref count is nonzero, we are shutting down the process abruptly without having closed some shared memory objects.
+ // There could still be threads running with active references to the shared memory object. So when the ref count is
+ // nonzero, don't clean up any object or global process-local state.
+ if (m_refCount == 0)
+ {
+ SharedMemoryManager::RemoveProcessDataHeader(this);
+ }
+
+ struct AutoReleaseCreationDeletionFileLock
+ {
+ bool m_acquired;
+
+ AutoReleaseCreationDeletionFileLock() : m_acquired(false)
+ {
+ }
+
+ ~AutoReleaseCreationDeletionFileLock()
+ {
+ if (m_acquired)
+ {
+ SharedMemoryManager::ReleaseCreationDeletionFileLock();
+ }
+ }
+ } autoReleaseCreationDeletionFileLock;
+
+ // A shared file lock on the shared memory file would be held by any process that has opened the same file. Try to take
+ // an exclusive lock on the file. Successfully acquiring an exclusive lock indicates that no process has a reference to
+ // the shared memory file, and this process can delete the file. File locks on the shared memory file are only ever acquired
+ // or released while holding the creation/deletion locks, so holding the creation/deletion locks while trying an exclusive
+ // lock on the shared memory file guarantees that another process cannot start using the shared memory file after this
+ // process has decided to delete the file.
+ bool releaseSharedData = false;
+ try
+ {
+ SharedMemoryManager::AcquireCreationDeletionFileLock();
+ autoReleaseCreationDeletionFileLock.m_acquired = true;
+
+ SharedMemoryHelpers::ReleaseFileLock(m_fileDescriptor);
+ if (SharedMemoryHelpers::TryAcquireFileLock(m_fileDescriptor, LOCK_EX | LOCK_NB))
+ {
+ SharedMemoryHelpers::ReleaseFileLock(m_fileDescriptor);
+ releaseSharedData = true;
+ }
+ }
+ catch (SharedMemoryException)
+ {
+ // Ignore the error, just don't release shared data
+ }
+
+ if (m_data != nullptr)
+ {
+ m_data->Close(m_refCount != 0 /* isAbruptShutdown */, releaseSharedData);
+ }
+
+ if (m_refCount == 0)
+ {
+ if (m_data != nullptr)
+ {
+ InternalDelete(m_data);
+ }
+
+ if (releaseSharedData)
+ {
+ m_sharedDataHeader->~SharedMemorySharedDataHeader();
+ }
+
+ munmap(m_sharedDataHeader, m_sharedDataTotalByteCount);
+ SharedMemoryHelpers::CloseFile(m_fileDescriptor);
+ }
+
+ if (!releaseSharedData)
+ {
+ return;
+ }
+
+ // Delete the shared memory file, and the session directory if it's not empty
+ char path[SHARED_MEMORY_MAX_FILE_PATH_CHAR_COUNT + 1];
+ SIZE_T sessionDirectoryPathCharCount = SharedMemoryHelpers::CopyString(path, 0, SHARED_MEMORY_SHARED_MEMORY_DIRECTORY_PATH);
+ path[sessionDirectoryPathCharCount++] = '/';
+ sessionDirectoryPathCharCount = m_id.AppendSessionDirectoryName(path, sessionDirectoryPathCharCount);
+ path[sessionDirectoryPathCharCount++] = '/';
+ SharedMemoryHelpers::CopyString(path, sessionDirectoryPathCharCount, m_id.GetName(), m_id.GetNameCharCount());
+ unlink(path);
+ path[sessionDirectoryPathCharCount] = '\0';
+ rmdir(path);
+}
+
+SharedMemoryId *SharedMemoryProcessDataHeader::GetId()
+{
+ return &m_id;
+}
+
+SharedMemoryProcessDataBase *SharedMemoryProcessDataHeader::GetData() const
+{
+ return m_data;
+}
+
+void SharedMemoryProcessDataHeader::SetData(SharedMemoryProcessDataBase *data)
+{
+ _ASSERTE(SharedMemoryManager::IsCreationDeletionProcessLockAcquired());
+ _ASSERTE(m_data == nullptr);
+ _ASSERTE(data != nullptr);
+
+ m_data = data;
+}
+
+SharedMemorySharedDataHeader *SharedMemoryProcessDataHeader::GetSharedDataHeader() const
+{
+ return m_sharedDataHeader;
+}
+
+SIZE_T SharedMemoryProcessDataHeader::GetSharedDataTotalByteCount() const
+{
+ return m_sharedDataTotalByteCount;
+}
+
+SharedMemoryProcessDataHeader *SharedMemoryProcessDataHeader::GetNextInProcessDataHeaderList() const
+{
+ _ASSERTE(SharedMemoryManager::IsCreationDeletionProcessLockAcquired());
+ return m_nextInProcessDataHeaderList;
+}
+
+void SharedMemoryProcessDataHeader::SetNextInProcessDataHeaderList(SharedMemoryProcessDataHeader *next)
+{
+ _ASSERTE(SharedMemoryManager::IsCreationDeletionProcessLockAcquired());
+ m_nextInProcessDataHeaderList = next;
+}
+
+void SharedMemoryProcessDataHeader::IncRefCount()
+{
+ _ASSERTE(SharedMemoryManager::IsCreationDeletionProcessLockAcquired());
+ _ASSERTE(m_refCount != 0);
+
+ ++m_refCount;
+}
+
+void SharedMemoryProcessDataHeader::DecRefCount()
+{
+ _ASSERTE(SharedMemoryManager::IsCreationDeletionProcessLockAcquired());
+ _ASSERTE(m_refCount != 0);
+
+ if (--m_refCount == 0)
+ {
+ InternalDelete(this);
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// SharedMemoryManager
+
+CRITICAL_SECTION SharedMemoryManager::s_creationDeletionProcessLock;
+int SharedMemoryManager::s_creationDeletionLockFileDescriptor = -1;
+
+SharedMemoryProcessDataHeader *SharedMemoryManager::s_processDataHeaderListHead = nullptr;
+
+#ifdef _DEBUG
+SIZE_T SharedMemoryManager::s_creationDeletionProcessLockOwnerThreadId = SharedMemoryHelpers::InvalidThreadId;
+SIZE_T SharedMemoryManager::s_creationDeletionFileLockOwnerThreadId = SharedMemoryHelpers::InvalidThreadId;
+#endif // _DEBUG
+
+void SharedMemoryManager::StaticInitialize()
+{
+ InitializeCriticalSection(&s_creationDeletionProcessLock);
+}
+
+void SharedMemoryManager::StaticClose()
+{
+ // This function could very well be running during abrupt shutdown, and there could still be user threads running.
+ // Synchronize the deletion, and don't remove or delete items in the linked list.
+ AcquireCreationDeletionProcessLock();
+ for (SharedMemoryProcessDataHeader *current = s_processDataHeaderListHead;
+ current != nullptr;
+ current = current->GetNextInProcessDataHeaderList())
+ {
+ current->Close();
+ }
+ ReleaseCreationDeletionProcessLock();
+
+ // This function could very well be running during abrupt shutdown, and there could still be user threads running. Don't
+ // delete the creation/deletion process lock, the process is shutting down anyway.
+}
+
+void SharedMemoryManager::AcquireCreationDeletionProcessLock()
+{
+ _ASSERTE(!IsCreationDeletionProcessLockAcquired());
+ _ASSERTE(!IsCreationDeletionFileLockAcquired());
+
+ EnterCriticalSection(&s_creationDeletionProcessLock);
+#ifdef _DEBUG
+ s_creationDeletionProcessLockOwnerThreadId = THREADSilentGetCurrentThreadId();
+#endif // _DEBUG
+}
+
+void SharedMemoryManager::ReleaseCreationDeletionProcessLock()
+{
+ _ASSERTE(IsCreationDeletionProcessLockAcquired());
+ _ASSERTE(!IsCreationDeletionFileLockAcquired());
+
+#ifdef _DEBUG
+ s_creationDeletionProcessLockOwnerThreadId = SharedMemoryHelpers::InvalidThreadId;
+#endif // _DEBUG
+ LeaveCriticalSection(&s_creationDeletionProcessLock);
+}
+
+void SharedMemoryManager::AcquireCreationDeletionFileLock()
+{
+ _ASSERTE(IsCreationDeletionProcessLockAcquired());
+ _ASSERTE(!IsCreationDeletionFileLockAcquired());
+
+ if (s_creationDeletionLockFileDescriptor == -1)
+ {
+ if (!SharedMemoryHelpers::EnsureDirectoryExists(
+ SHARED_MEMORY_TEMP_DIRECTORY_PATH,
+ false /* isGlobalLockAcquired */,
+ false /* createIfNotExist */))
+ {
+ throw SharedMemoryException(static_cast<DWORD>(SharedMemoryError::IO));
+ }
+ SharedMemoryHelpers::EnsureDirectoryExists(
+ SHARED_MEMORY_RUNTIME_TEMP_DIRECTORY_PATH,
+ false /* isGlobalLockAcquired */);
+ SharedMemoryHelpers::EnsureDirectoryExists(
+ SHARED_MEMORY_SHARED_MEMORY_DIRECTORY_PATH,
+ false /* isGlobalLockAcquired */);
+ s_creationDeletionLockFileDescriptor = SharedMemoryHelpers::OpenDirectory(SHARED_MEMORY_SHARED_MEMORY_DIRECTORY_PATH);
+ if (s_creationDeletionLockFileDescriptor == -1)
+ {
+ throw SharedMemoryException(static_cast<DWORD>(SharedMemoryError::IO));
+ }
+ }
+
+ bool acquiredFileLock = SharedMemoryHelpers::TryAcquireFileLock(s_creationDeletionLockFileDescriptor, LOCK_EX);
+ _ASSERTE(acquiredFileLock);
+#ifdef _DEBUG
+ s_creationDeletionFileLockOwnerThreadId = THREADSilentGetCurrentThreadId();
+#endif // _DEBUG
+}
+
+void SharedMemoryManager::ReleaseCreationDeletionFileLock()
+{
+ _ASSERTE(IsCreationDeletionProcessLockAcquired());
+ _ASSERTE(IsCreationDeletionFileLockAcquired());
+ _ASSERTE(s_creationDeletionLockFileDescriptor != -1);
+
+#ifdef _DEBUG
+ s_creationDeletionFileLockOwnerThreadId = SharedMemoryHelpers::InvalidThreadId;
+#endif // _DEBUG
+ SharedMemoryHelpers::ReleaseFileLock(s_creationDeletionLockFileDescriptor);
+}
+
+#ifdef _DEBUG
+bool SharedMemoryManager::IsCreationDeletionProcessLockAcquired()
+{
+ return s_creationDeletionProcessLockOwnerThreadId == THREADSilentGetCurrentThreadId();
+}
+
+bool SharedMemoryManager::IsCreationDeletionFileLockAcquired()
+{
+ return s_creationDeletionFileLockOwnerThreadId == THREADSilentGetCurrentThreadId();
+}
+#endif // _DEBUG
+
+void SharedMemoryManager::AddProcessDataHeader(SharedMemoryProcessDataHeader *processDataHeader)
+{
+ _ASSERTE(processDataHeader != nullptr);
+ _ASSERTE(IsCreationDeletionProcessLockAcquired());
+ _ASSERTE(processDataHeader->GetNextInProcessDataHeaderList() == nullptr);
+ _ASSERTE(FindProcessDataHeader(processDataHeader->GetId()) == nullptr);
+
+ processDataHeader->SetNextInProcessDataHeaderList(s_processDataHeaderListHead);
+ s_processDataHeaderListHead = processDataHeader;
+}
+
+void SharedMemoryManager::RemoveProcessDataHeader(SharedMemoryProcessDataHeader *processDataHeader)
+{
+ _ASSERTE(processDataHeader != nullptr);
+ _ASSERTE(IsCreationDeletionProcessLockAcquired());
+
+ if (s_processDataHeaderListHead == processDataHeader)
+ {
+ s_processDataHeaderListHead = processDataHeader->GetNextInProcessDataHeaderList();
+ processDataHeader->SetNextInProcessDataHeaderList(nullptr);
+ return;
+ }
+ for (SharedMemoryProcessDataHeader
+ *previous = s_processDataHeaderListHead,
+ *current = previous->GetNextInProcessDataHeaderList();
+ current != nullptr;
+ previous = current, current = current->GetNextInProcessDataHeaderList())
+ {
+ if (current == processDataHeader)
+ {
+ previous->SetNextInProcessDataHeaderList(current->GetNextInProcessDataHeaderList());
+ current->SetNextInProcessDataHeaderList(nullptr);
+ return;
+ }
+ }
+ _ASSERTE(false);
+}
+
+SharedMemoryProcessDataHeader *SharedMemoryManager::FindProcessDataHeader(SharedMemoryId *id)
+{
+ _ASSERTE(IsCreationDeletionProcessLockAcquired());
+
+ // TODO: Use a hash table
+ for (SharedMemoryProcessDataHeader *current = s_processDataHeaderListHead;
+ current != nullptr;
+ current = current->GetNextInProcessDataHeaderList())
+ {
+ if (current->GetId()->Equals(id))
+ {
+ return current;
+ }
+ }
+ return nullptr;
+}
diff --git a/src/pal/src/shmemory/shmemory.cpp b/src/pal/src/shmemory/shmemory.cpp
new file mode 100644
index 0000000000..42e06be834
--- /dev/null
+++ b/src/pal/src/shmemory/shmemory.cpp
@@ -0,0 +1,1734 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ shmemory/shmemory.c
+
+Abstract:
+
+ Implementation of shared memory infrastructure for IPC
+
+Issues :
+
+ Interprocess synchronization
+
+
+There doesn't seem to be ANY synchronization mechanism that will work
+inter-process AND be pthread-safe. FreeBSD's pthread implementation has no
+support for inter-process synchronization (PTHREAD_PROCESS_SHARED);
+"traditionnal" inter-process syncronization functions, on the other hand, are
+not pthread-aware, and thus will block entire processes instead of only the
+calling thread.
+
+From suggestions and information obtained on the freebsd-hackers mailing list,
+I have come up with 2 possible strategies to ensure serialized access to our
+shared memory region
+
+Note that the estimates of relative efficiency are wild guesses; my assumptions
+are that blocking entire processes is least efficient, busy wait somewhat
+better, and anything that does neither is preferable. However, the overhead of
+complex solutions is likely to have an important impact on performance
+
+Option 1 : very simple; possibly less efficient. in 2 words : "busy wait"
+Basically,
+
+while(InterlockedCompareExchange(spinlock_in_shared_memory, 1, 0)
+ sched_yield();
+
+In other words, if a value is 0, set it to 1; otherwise, try again until we
+succeed. use shed_yield to give the system a chance to schedule other threads
+while we wait. (once a thread succeeds at this, it does its work, then sets
+the value back to 0)
+One inconvenient : threads will not unblock in the order they are blocked;
+once a thread releases the mutex, whichever waiting thread is scheduled next
+will be unblocked. This is what is called the "thundering herd" problem, and in
+extreme cases, can lead to starvation
+Update : we'll set the spinlock to our PID instead of 1, that way we can find
+out if the lock is held by a dead process.
+
+Option 2 : possibly more efficient, much more complex, borders on
+"over-engineered". I'll explain it in stages, in the same way I deduced it.
+
+Option 2.1 : probably less efficient, reasonably simple. stop at step 2)
+
+1) The minimal, original idea was to use SysV semaphores for synchronization.
+This didn't work, because semaphores block the entire process, which can easily
+lead to deadlocks (thread 1 takes sem, thread 2 tries to take sem, blocks
+process, thread 1 is blocked and never releases sem)
+
+2) (this is option 2.1) Protect the use of the semaphores in critical sections.
+Enter the critical section before taking the semaphore, leave the section after
+releasing the semaphore. This ensures that 2 threads of the same process will
+never try to acquire the semaphore at the same time, which avoids deadlocks.
+However, the entire process still blocks if another process has the semaphore.
+Here, unblocking order should match blocking order (assuming the semaphores work
+properly); therefore, no risk of starvation.
+
+3) This is where it gets complicated. To avoid blocking whole processes, we
+can't use semaphores. One suggestion I got was to use multi-ended FIFOs, here's
+how it would work.
+
+-as in option 1, use InterlockedCompareExchange on a value in shared memory.
+-if this was not succesful (someone else has locked the shared memory), then :
+ -open a special FIFO for reading; try to read 1 byte. This will block until
+ someone writes to it, and *should* only block the current thread. (note :
+ more than one thread/process can open the same FIFO and block on read(),
+ in this case, only one gets woken up when someone writes to it.
+ *which* one is, again, not predictable; this may lead to starvation)
+ -once we are unblocked, we have the lock.
+-once we have the lock (either from Interlocked...() or from read()),
+ we can do our work
+-once the work is done, we open the FIFO for writing. this will fail if no one
+ is listening.
+-if no one is listening, release the lock by setting the shared memory value
+ back to 0
+-if someone is listening, write 1 byte to the FIFO to wake someone, then close
+ the FIFO. the value in shared memory will remain nonzero until a thread tries
+ to wake the next one and sees no one is listening.
+
+problem with this option : it is possible for a thread to call Interlocked...()
+BETWEEN the failed "open for write" attempt and the subsequent restoration of
+the SHM value back to zero. In this case, that thread will go to sleep and will
+not wake up until *another* thread asks for the lock, takes it and releases it.
+
+so to fix that, we come to step
+
+4) Instead of using InterlockedCompareExchange, use a SysV semaphore :
+-when taking the lock :
+ -take the semaphore
+ -try to take the lock (check if value is zero, change it to 1 if it is)
+ -if we fail : open FIFO for reading, release the semaphore, read() and block
+ -if we succeed : release the semaphore
+-when releasing the lock :
+ -take the semaphore
+ -open FIFO for write
+ -if we succeed, release semaphore, then write value
+ -if we fail, reset SHM value to 0, then release semaphore.
+
+Yes, using a SysV semaphore will block the whole process, but for a very short
+time (unlike option 2.1)
+problem with this : again, we get deadlocks if 2 threads from a single process
+try to take the semaphore. So like in option 2.1, we ave to wrap the semaphore
+usage in a critical section. (complex enough yet?)
+
+so the locking sequence becomes EnterCriticalSection - take semaphore - try to
+ lock - open FIFO - release semaphore - LeaveCriticalSection - read
+and the unlocking sequence becomes EnterCS - take sem - open FIFO - release
+ sem - LeaveCS - write
+
+Once again, the unblocking order probably won't match the blocking order.
+This could be fixed by using multiple FIFOs : waiting thread open their own
+personal FIFO, write the ID of their FIFO to another FIFO. The thread that wants
+to release the lock reads ID from that FIFO, determines which FIFO to open for
+writing and writes a byte to it. This way, whoever wrote its ID to the FIFO
+first will be first to awake. How's that for complexity?
+
+So to summarize, the options are
+1 - busy wait
+2.1 - semaphores + critical sections (whole process blocks)
+2 - semaphores + critical sections + FIFOs (minimal process blocking)
+2.2 - option 2 with multiple FIFOs (minimal process blocking, order preserved)
+
+Considering the overhead involved in options 2 & 2.2, it is our guess that
+option 1 may in fact be more efficient, and this is how we'll implement it for
+the moment. Note that other platforms may not present the same difficulties
+(i.e. other pthread implementations may support inter-process mutexes), and may
+be able to use a simpler, more efficient approach.
+
+B] Reliability.
+It is important for the shared memory implementation to be as foolproof as
+possible. Since more than one process will be able to modify the shared data,
+it becomes possible for one unstable process to destabilize the others. The
+simplest example is a process that dies while modifying shared memory : if
+it doesn't release its lock, we're in trouble. (this case will be taken care
+of by using PIDs in the spinlock; this we we can check if the locking process
+is still alive).
+
+
+
+--*/
+
+#include "config.h"
+#include "pal/palinternal.h"
+#include "pal/dbgmsg.h"
+#include "pal/shmemory.h"
+#include "pal/critsect.h"
+#include "pal/shmemory.h"
+#include "pal/init.h"
+#include "pal/process.h"
+#include "pal/misc.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#include <signal.h>
+#include <errno.h>
+#include <string.h>
+#include <sched.h>
+#include <pthread.h>
+
+#if HAVE_YIELD_SYSCALL
+#include <sys/syscall.h>
+#endif /* HAVE_YIELD_SYSCALL */
+
+SET_DEFAULT_DEBUG_CHANNEL(SHMEM);
+
+/* Macro-definitions **********************************************************/
+
+/* rounds 'val' up to be divisible by 'r'. 'r' must be a power of two. */
+#ifndef roundup
+#define roundup(val, r) ( ((val)+(r)-1) & ~( (r)-1 ) )
+#endif
+
+#define SEGMENT_NAME_SUFFIX_LENGTH 10
+
+#if defined(_DEBUG) && defined(_HPUX_)
+#define TRACK_SHMLOCK_OWNERSHIP
+#endif // _DEBUG && _HPUX_
+
+/*
+SHMPTR structure :
+High byte is SHM segment number
+Low bytes are offset in the segment
+ */
+#define SHMPTR_SEGMENT(shmptr) \
+ (((shmptr)>>24)&0xFF)
+
+#define SHMPTR_OFFSET(shmptr) \
+ ((shmptr)&0x00FFFFFF)
+
+#define MAKE_SHMPTR(segment,offset) \
+ ((SHMPTR)((((segment)&0xFF)<<24)|((offset)&0x00FFFFFF)))
+
+/*#define MAX_SEGMENTS 256*//*definition is now in shmemory.h*/
+
+/* Use MAP_NOSYNC to improve performance if it's available */
+#if defined(MAP_NOSYNC)
+#define MAPFLAGS MAP_NOSYNC|MAP_SHARED
+#else
+#define MAPFLAGS MAP_SHARED
+#endif
+
+
+/* Type definitions ***********************************************************/
+
+enum SHM_POOL_SIZES
+{
+ SPS_16 = 0, /* 16 bytes */
+ SPS_32, /* 32 bytes */
+ SPS_64, /* 64 bytes */
+ SPS_MAXPATHx2, /* 520 bytes, for long Unicode paths */
+
+ SPS_LAST
+};
+/* Block size associated to each SPS identifier */
+static const int block_sizes[SPS_LAST] = {16,32,64,roundup((MAX_LONGPATH+1)*2, sizeof(INT64))};
+
+/*
+SHM_POOL_INFO
+Description of a shared memory pool for a specific block size.
+
+Note on pool structure :
+first_free identifies the first available SHMPTR in the block. Free blocks are
+arranged in a linked list, each free block indicating the location of the next
+one. To walk the list, do something like this :
+SHMPTR *shmptr_ptr=(SHMPTR *)SHMPTR_TO_PTR(pool->first_free)
+while(shm_ptr)
+{
+ SHMPTR next = *shmptr_ptr;
+ shmptr_ptr = (SHMPTR *)SHMPTR_TO_PTR(next)
+}
+ */
+typedef struct
+{
+ int item_size; /* size of 1 block, in bytes */
+ int num_items; /* total number of blocks in the pool */
+ int free_items; /* number of unused items in the pool */
+ SHMPTR first_free; /* location of first available block in the pool */
+}SHM_POOL_INFO;
+
+/*
+SHM_SEGMENT_HEADER
+Description of a single shared memory segment
+
+Notes on segment names :
+next_semgent contains the string generated by mkstemp() when a new segment is
+generated. This allows processes to map segment files created by other
+processes. To get the file name of a segment file, concatenate
+"segment_name_prefix" and "next_segment".
+
+Notes on pool segments :
+Each segment is divided into one pool for each defined block size (SPS_*).
+These pools are linked with pools in other segment to form one large pool for
+each block size, so that SHMAlloc() doesn't have to search each segment to find
+an available block.
+the first_ and last_pool_blocks indicate the first and last block in a single
+segment for each block size. This allows SHMFree() to determine the size of a
+block by comparing its value with these boundaries. (note that within each
+segment, each pool is composed of a single contiguous block of memory)
+*/
+typedef struct
+{
+ Volatile<SHMPTR> first_pool_blocks[SPS_LAST];
+ Volatile<SHMPTR> last_pool_blocks[SPS_LAST];
+} SHM_SEGMENT_HEADER;
+
+/*
+SHM_FIRST_HEADER
+Global information about the shared memory system
+In addition to the standard SHM_SEGGMENT_HEADER, the first segment contains some
+information required to properly use the shared memory system.
+
+The spinlock is used to ensure that only one process accesses shared memory at
+the same time. A process can only take the spinlock if its contents is 0, and
+it takes the spinlock by placing its PID in it. (this allows a process to catch
+the special case where it tries to take a spinlock it already owns.
+
+The first_* members will contain the location of the first element in the
+various linked lists of shared information
+ */
+
+#ifdef TRACK_SHMLOCK_OWNERSHIP
+
+#define SHMLOCK_OWNERSHIP_HISTORY_ARRAY_SIZE 5
+
+#define CHECK_CANARIES(header) \
+ _ASSERTE(HeadSignature == header->dwHeadCanaries[0]); \
+ _ASSERTE(HeadSignature == header->dwHeadCanaries[1]); \
+ _ASSERTE(TailSignature == header->dwTailCanaries[0]); \
+ _ASSERTE(TailSignature == header->dwTailCanaries[1])
+
+typedef struct _pid_and_tid
+{
+ Volatile<pid_t> pid;
+ Volatile<pthread_t> tid;
+} pid_and_tid;
+
+const DWORD HeadSignature = 0x48454144;
+const DWORD TailSignature = 0x5441494C;
+
+#endif // TRACK_SHMLOCK_OWNERSHIP
+
+typedef struct
+{
+ SHM_SEGMENT_HEADER header;
+#ifdef TRACK_SHMLOCK_OWNERSHIP
+ Volatile<DWORD> dwHeadCanaries[2];
+#endif // TRACK_SHMLOCK_OWNERSHIP
+ Volatile<pid_t> spinlock;
+#ifdef TRACK_SHMLOCK_OWNERSHIP
+ Volatile<DWORD> dwTailCanaries[2];
+ pid_and_tid pidtidCurrentOwner;
+ pid_and_tid pidtidOwners[SHMLOCK_OWNERSHIP_HISTORY_ARRAY_SIZE];
+ Volatile<ULONG> ulOwnersIdx;
+#endif // TRACK_SHMLOCK_OWNERSHIP
+ SHM_POOL_INFO pools[SPS_LAST]; /* information about each memory pool */
+ Volatile<SHMPTR> shm_info[SIID_LAST]; /* basic blocks of shared information.*/
+} SHM_FIRST_HEADER;
+
+
+/* Static variables ***********************************************************/
+
+/* Critical section to ensure that only one thread at a time accesses shared
+memory. Rationale :
+-Using a spinlock means that processes must busy-wait for the lock to be
+ available. The critical section ensures taht only one thread will busy-wait,
+ while the rest are put to sleep.
+-Since the spinlock only contains a PID, it isn't possible to make a difference
+ between threads of the same process. This could be resolved by using 2
+ spinlocks, but this would introduce more busy-wait.
+*/
+static CRITICAL_SECTION shm_critsec;
+
+/* number of segments the current process knows about */
+int shm_numsegments;
+
+/* array containing the base address of each segment */
+Volatile<LPVOID> shm_segment_bases[MAX_SEGMENTS];
+
+/* number of locks the process currently holds (SHMLock calls without matching
+SHMRelease). Because we take the critical section while inside a
+SHMLock/SHMRelease pair, this is actually the number of locks held by a single
+thread. */
+static Volatile<LONG> lock_count;
+
+/* thread ID of thread holding the SHM lock. used for debugging purposes :
+ SHMGet/SetInfo will verify that the calling thread holds the lock */
+static Volatile<HANDLE> locking_thread;
+
+/* Constants ******************************************************************/
+
+/* size of a single segment : 256KB */
+static const int segment_size = 0x40000;
+
+/* Static function prototypes *************************************************/
+
+static SHMPTR SHMInitPool(SHMPTR first, int block_size, int pool_size,
+ SHM_POOL_INFO *pool);
+static SHMPTR SHMLinkPool(SHMPTR first, int block_size, int num_blocks);
+static BOOL SHMMapUnknownSegments(void);
+static BOOL SHMAddSegment(void);
+
+
+#define init_waste()
+#define log_waste(x,y)
+#define save_waste()
+
+/* Public function implementations ********************************************/
+
+/*++
+SHMInitialize
+
+Hook this process into the PAL shared memory system; initialize the shared
+memory if no other process has done it.
+
+--*/
+BOOL SHMInitialize(void)
+{
+ InternalInitializeCriticalSection(&shm_critsec);
+
+ init_waste();
+
+ int size;
+ SHM_FIRST_HEADER *header;
+ SHMPTR pool_start;
+ SHMPTR pool_end;
+ enum SHM_POOL_SIZES sps;
+
+ TRACE("Now initializing global shared memory system\n");
+
+ // Not really shared in CoreCLR; we don't try to talk to other CoreCLRs.
+ shm_segment_bases[0] = mmap(NULL, segment_size,PROT_READ|PROT_WRITE,
+ MAP_ANON|MAP_PRIVATE, -1, 0);
+ if(shm_segment_bases[0] == MAP_FAILED)
+ {
+ ERROR("mmap() failed; error is %d (%s)\n", errno, strerror(errno));
+ return FALSE;
+ }
+ TRACE("Mapped first SHM segment at %p\n",shm_segment_bases[0].Load());
+
+ /* Initialize first segment's header */
+ header = (SHM_FIRST_HEADER *)shm_segment_bases[0].Load();
+
+ InterlockedExchange((LONG *)&header->spinlock, 0);
+
+#ifdef TRACK_SHMLOCK_OWNERSHIP
+ header->dwHeadCanaries[0] = HeadSignature;
+ header->dwHeadCanaries[1] = HeadSignature;
+ header->dwTailCanaries[0] = TailSignature;
+ header->dwTailCanaries[1] = TailSignature;
+
+ // Check spinlock size
+ _ASSERTE(sizeof(DWORD) == sizeof(header->spinlock));
+ // Check spinlock alignment
+ _ASSERTE(0 == ((DWORD_PTR)&header->spinlock % (DWORD_PTR)sizeof(void *)));
+#endif // TRACK_SHMLOCK_OWNERSHIP
+
+#ifdef TRACK_SHMLOCK_OWNERSHIP
+ header->pidtidCurrentOwner.pid = 0;
+ header->pidtidCurrentOwner.tid = 0;
+ memset((void *)header->pidtidOwners, 0, sizeof(header->pidtidOwners));
+ header->ulOwnersIdx = 0;
+#endif // TRACK_SHMLOCK_OWNERSHIP
+
+ /* SHM information array starts with NULLs */
+ memset((void *)header->shm_info, 0, SIID_LAST*sizeof(SHMPTR));
+
+ /* Initialize memory pools */
+
+ /* first pool starts right after header */
+ pool_start = roundup(sizeof(SHM_FIRST_HEADER), sizeof(INT64));
+
+ /* Same size for each pool, ensuring alignment is correct */
+ size = ((segment_size-pool_start)/SPS_LAST) & ~(sizeof(INT64)-1);
+
+ for (sps = static_cast<SHM_POOL_SIZES>(0); sps < SPS_LAST;
+ sps = static_cast<SHM_POOL_SIZES>(sps + 1))
+ {
+ pool_end = SHMInitPool(pool_start, block_sizes[sps], size,
+ (SHM_POOL_INFO *)&header->pools[sps]);
+
+ if(pool_end ==0)
+ {
+ ERROR("SHMInitPool failed.\n");
+ munmap(shm_segment_bases[0],segment_size);
+ return FALSE;
+ }
+ /* save first and last element of each pool for this segment */
+ header->header.first_pool_blocks[sps] = pool_start;
+ header->header.last_pool_blocks[sps] = pool_end;
+
+ /* next pool starts immediately after this one */
+ pool_start +=size;
+ }
+
+ TRACE("Global shared memory initialization complete.\n");
+
+ shm_numsegments = 1;
+ lock_count = 0;
+ locking_thread = 0;
+
+ /* hook into all SHM segments */
+ if(!SHMMapUnknownSegments())
+ {
+ ERROR("Error while mapping segments!\n");
+ SHMCleanup();
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/*++
+SHMCleanup
+
+Release all shared memory resources held; remove ourselves from the list of
+registered processes, and remove all shared memory files if no process remains
+
+Note that this function does not use thread suspension wrapper for unlink and free
+because all thread objects are deleted before this function is called
+in PALCommonCleanup.
+
+--*/
+void SHMCleanup(void)
+{
+ SHM_FIRST_HEADER *header;
+ pid_t my_pid;
+
+ TRACE("Starting shared memory cleanup\n");
+
+ SHMLock();
+ SHMRelease();
+
+ /* We should not be holding the spinlock at this point. If we are, release
+ the spinlock. by setting it to 0 */
+ my_pid = gPID;
+ header = (SHM_FIRST_HEADER *)shm_segment_bases[0].Load();
+
+ _ASSERT_MSG(header->spinlock != my_pid,
+ "SHMCleanup called while the current process still owns the lock "
+ "[owner thread=%u, current thread: %u]\n",
+ locking_thread.Load(), THREADSilentGetCurrentThreadId());
+
+ /* Now for the interprocess stuff. */
+ DeleteCriticalSection(&shm_critsec);
+
+
+ /* Unmap memory segments */
+ while(shm_numsegments)
+ {
+ shm_numsegments--;
+ if ( -1 == munmap( shm_segment_bases[ shm_numsegments ],
+ segment_size ) )
+ {
+ ASSERT( "munmap() failed; errno is %d (%s).\n",
+ errno, strerror( errno ) );
+ }
+ }
+
+ save_waste();
+ TRACE("SHMCleanup complete!\n");
+}
+
+/*++
+SHMalloc
+
+Allocate a block of memory of the specified size
+
+Parameters :
+ size_t size : size of block required
+
+Return value :
+ A SHMPTR identifying the new block, or 0 on failure. Use SHMPTR_TO_PTR to
+ convert a SHMPTR into a useable pointer (but remember to lock the shared
+ memory first!)
+
+Notes :
+ SHMalloc will fail if the requested size is larger than a certain maximum.
+ At the moment, the maximum is 520 bytes (MAX_LONGPATH*2).
+--*/
+SHMPTR SHMalloc(size_t size)
+{
+ enum SHM_POOL_SIZES sps;
+ SHMPTR first_free;
+ SHMPTR next_free;
+ SHM_FIRST_HEADER *header;
+ SHMPTR *shmptr_ptr;
+
+ TRACE("SHMalloc() called; requested size is %u\n", size);
+
+ if(0 == size)
+ {
+ WARN("Got a request for a 0-byte block! returning 0\n");
+ return 0;
+ }
+
+ /* Find the first block size >= requested size */
+ for (sps = static_cast<SHM_POOL_SIZES>(0); sps < SPS_LAST;
+ sps = static_cast<SHM_POOL_SIZES>(sps + 1))
+ {
+ if (size <= static_cast<size_t>(block_sizes[sps]))
+ {
+ break;
+ }
+ }
+
+ /* If no block size is found, requested size was too large. */
+ if( SPS_LAST == sps )
+ {
+ ASSERT("Got request for shared memory block of %u bytes; maximum block "
+ "size is %d.\n", size, block_sizes[SPS_LAST-1]);
+ return 0;
+ }
+
+ TRACE("Best block size is %d (%d bytes wasted)\n",
+ block_sizes[sps], block_sizes[sps]-size );
+
+ log_waste(sps, block_sizes[sps]-size);
+
+ SHMLock();
+ header = (SHM_FIRST_HEADER *)shm_segment_bases[0].Load();
+
+ /* If there are no free items of the specified size left, it's time to
+ allocate a new shared memory segment.*/
+ if(header->pools[sps].free_items == 0)
+ {
+ TRACE("No blocks of %d bytes left; allocating new segment.\n",
+ block_sizes[sps]);
+ if(!SHMAddSegment())
+ {
+ ERROR("Unable to allocate new shared memory segment!\n");
+ SHMRelease();
+ return 0;
+ }
+ }
+
+ /* Remove the first free block from the pool */
+ first_free = header->pools[sps].first_free;
+ shmptr_ptr = static_cast<SHMPTR*>(SHMPTR_TO_PTR(first_free));
+
+ if( 0 == first_free )
+ {
+ ASSERT("First free block in %d-byte pool (%08x) was invalid!\n",
+ block_sizes[sps], first_free);
+ SHMRelease();
+ return 0;
+ }
+
+ /* the block "first_free" is the head of a linked list of free blocks;
+ take the next link in the list and set it as new head of list. */
+ next_free = *shmptr_ptr;
+ header->pools[sps].first_free = next_free;
+ header->pools[sps].free_items--;
+
+ /* make sure we're still in a sane state */
+ if(( 0 == header->pools[sps].free_items && 0 != next_free) ||
+ ( 0 != header->pools[sps].free_items && 0 == next_free))
+ {
+ ASSERT("free block count is %d, but next free block is %#x\n",
+ header->pools[sps].free_items, next_free);
+ /* assume all remaining blocks in the pool are corrupt */
+ header->pools[sps].first_free = 0;
+ header->pools[sps].free_items = 0;
+ }
+ else if (0 != next_free && 0 == SHMPTR_TO_PTR(next_free) )
+ {
+ ASSERT("Next free block (%#x) in %d-byte pool is invalid!\n",
+ next_free, block_sizes[sps]);
+ /* assume all remaining blocks in the pool are corrupt */
+ header->pools[sps].first_free = 0;
+ header->pools[sps].free_items = 0;
+ }
+
+ SHMRelease();
+
+ TRACE("Allocation successful; %d blocks of %d bytes left. Returning %08x\n",
+ header->pools[sps].free_items, block_sizes[sps], first_free);
+ return first_free;
+}
+
+/*++
+SHMfree
+
+Release a block of shared memory and put it back in the shared memory pool
+
+Parameters :
+ SHMPTR shmptr : identifier of block to release
+
+(no return value)
+--*/
+void SHMfree(SHMPTR shmptr)
+{
+ int segment;
+ int offset;
+ SHM_SEGMENT_HEADER *header;
+ SHM_FIRST_HEADER *first_header;
+ enum SHM_POOL_SIZES sps;
+ SHMPTR *shmptr_ptr;
+
+ if(0 == shmptr)
+ {
+ WARN("can't SHMfree() a NULL SHMPTR!\n");
+ return;
+ }
+ SHMLock();
+
+ TRACE("Releasing SHMPTR 0x%08x\n", shmptr);
+
+ shmptr_ptr = static_cast<SHMPTR*>(SHMPTR_TO_PTR(shmptr));
+
+ if(!shmptr_ptr)
+ {
+ ASSERT("Tried to free an invalid shared memory pointer 0x%08x\n", shmptr);
+ SHMRelease();
+ return;
+ }
+
+ /* note : SHMPTR_TO_PTR has already validated the segment/offset pair */
+ segment = SHMPTR_SEGMENT(shmptr);
+ header = (SHM_SEGMENT_HEADER *)shm_segment_bases[segment].Load();
+
+ /* Find out the size of this block. Each segment tells where are its first
+ and last blocks for each block size, so we simply need to check in which
+ interval the block fits */
+ for (sps = static_cast<SHM_POOL_SIZES>(0); sps < SPS_LAST;
+ sps = static_cast<SHM_POOL_SIZES>(sps + 1))
+ {
+ if(header->first_pool_blocks[sps]<=shmptr &&
+ header->last_pool_blocks[sps]>=shmptr)
+ {
+ break;
+ }
+ }
+
+ /* If we didn't find an interval, then the block doesn't really belong in
+ this segment (shouldn't happen, the offset check in SHMPTR_TO_PTR should
+ have caught this.) */
+ if(sps == SPS_LAST)
+ {
+ ASSERT("Shared memory pointer 0x%08x is out of bounds!\n", shmptr);
+ SHMRelease();
+ return;
+ }
+
+ TRACE("SHMPTR 0x%08x is a %d-byte block located in segment %d\n",
+ shmptr, block_sizes[sps], segment);
+
+ /* Determine the offset of this block (in bytes) relative to the first
+ block of the same size in this segment */
+ offset = shmptr - header->first_pool_blocks[sps];
+
+ /* Make sure that the offset is a multiple of the block size; otherwise,
+ this isn't a real SHMPTR */
+ if( 0 != ( offset % block_sizes[sps] ) )
+ {
+ ASSERT("Shared memory pointer 0x%08x is misaligned!\n", shmptr);
+ SHMRelease();
+ return;
+ }
+
+ /* Put the SHMPTR back in its pool. */
+ first_header = (SHM_FIRST_HEADER *)shm_segment_bases[0].Load();
+
+ /* first_free is the head of a linked list of free SHMPTRs. All we need to
+ do is make shmptr point to first_free, and set shmptr as the new head
+ of the list. */
+ *shmptr_ptr = first_header->pools[sps].first_free;
+ first_header->pools[sps].first_free = shmptr;
+ first_header->pools[sps].free_items++;
+
+ TRACE("SHMPTR 0x%08x released; there are now %d blocks of %d bytes "
+ "available\n", shmptr, first_header->pools[sps].free_items,
+ block_sizes[sps]);
+ SHMRelease();
+}
+
+/*++
+SHMLock
+
+Restrict shared memory access to the current thread of the current process
+
+(no parameters)
+
+Return value :
+ New lock count
+
+Notes :
+see comments at the declaration of shm_critsec for rationale of critical
+section usage
+--*/
+int SHMLock(void)
+{
+ /* Hold the critical section until the lock is released */
+ PALCEnterCriticalSection(&shm_critsec);
+
+ _ASSERTE((0 == lock_count && 0 == locking_thread) ||
+ (0 < lock_count && (HANDLE)pthread_self() == locking_thread));
+
+ if(lock_count == 0)
+ {
+ SHM_FIRST_HEADER *header;
+ pid_t my_pid, tmp_pid;
+ int spincount = 1;
+#ifdef TRACK_SHMLOCK_OWNERSHIP
+ ULONG ulIdx;
+#endif // TRACK_SHMLOCK_OWNERSHIP
+
+ TRACE("First-level SHM lock : taking spinlock\n");
+
+ header = (SHM_FIRST_HEADER *)shm_segment_bases[0].Load();
+
+ // Store the id of the current thread as the (only) one that is
+ // trying to grab the spinlock from the current process
+ locking_thread = (HANDLE)pthread_self();
+
+ my_pid = gPID;
+
+ while(TRUE)
+ {
+#ifdef TRACK_SHMLOCK_OWNERSHIP
+ _ASSERTE(0 != my_pid);
+ _ASSERTE(getpid() == my_pid);
+ _ASSERTE(my_pid != header->spinlock);
+ CHECK_CANARIES(header);
+#endif // TRACK_SHMLOCK_OWNERSHIP
+
+ //
+ // Try to grab the spinlock
+ //
+ tmp_pid = InterlockedCompareExchange((LONG *) &header->spinlock, my_pid,0);
+
+#ifdef TRACK_SHMLOCK_OWNERSHIP
+ CHECK_CANARIES(header);
+#endif // TRACK_SHMLOCK_OWNERSHIP
+
+#ifdef _HPUX_
+ //
+ // TODO: workaround for VSW # 381564
+ //
+ if (0 == tmp_pid && my_pid != header->spinlock)
+ {
+ ERROR("InterlockedCompareExchange returned the Comperand but "
+ "failed to store the Exchange value to the Destination: "
+ "looping again [my_pid=%u header->spinlock=%u tmp_pid=%u "
+ "spincount=%d locking_thread=%u]\n", (DWORD)my_pid,
+ (DWORD)header->spinlock, (DWORD)tmp_pid, (int)spincount,
+ (HANDLE)locking_thread);
+
+ // Keep looping
+ tmp_pid = 42;
+ }
+#endif // _HPUX_
+
+ if (0 == tmp_pid)
+ {
+ // Spinlock acquired: break out of the loop
+ break;
+ }
+
+ /* Check if lock holder is alive. If it isn't, we can reset the
+ spinlock and try to take it again. If it is, we have to wait.
+ We use "spincount" to do this check only every 8th time through
+ the loop, for performance reasons.*/
+ if( (0 == (spincount&0x7)) &&
+ (-1 == kill(tmp_pid,0)) &&
+ (errno == ESRCH))
+ {
+ TRACE("SHM spinlock owner (%08x) is dead; releasing its lock\n",
+ tmp_pid);
+
+ InterlockedCompareExchange((LONG *) &header->spinlock, 0, tmp_pid);
+ }
+ else
+ {
+ /* another process is holding the lock... we want to yield and
+ give the holder a chance to release the lock
+ The function sched_yield() only yields to a thread in the
+ current process; this doesn't help us much, anddoens't help
+ at all if there's only 1 thread. There doesn't seem to be
+ any clean way to force a yield to another process, but the
+ FreeBSD syscall "yield" does the job. We alternate between
+ both methods to give other threads of this process a chance
+ to run while we wait.
+ */
+#if HAVE_YIELD_SYSCALL
+ if(spincount&1)
+ {
+#endif /* HAVE_YIELD_SYSCALL */
+ sched_yield();
+#if HAVE_YIELD_SYSCALL
+ }
+ else
+ {
+ /* use the syscall first, since we know we'l need to yield
+ to another process eventually - the lock can't be held
+ by the current process, thanks to the critical section */
+ syscall(SYS_yield, 0);
+ }
+#endif /* HAVE_YIELD_SYSCALL */
+ }
+
+ // Increment spincount
+ spincount++;
+ }
+
+ _ASSERT_MSG(my_pid == header->spinlock,
+ "\n(my_pid = %u) != (header->spinlock = %u)\n"
+ "tmp_pid = %u\n"
+ "spincount = %d\n"
+ "locking_thread = %u\n",
+ (DWORD)my_pid, (DWORD)header->spinlock,
+ (DWORD)tmp_pid,
+ (int)spincount,
+ (HANDLE)locking_thread);
+
+#ifdef TRACK_SHMLOCK_OWNERSHIP
+ _ASSERTE(0 == header->pidtidCurrentOwner.pid);
+ _ASSERTE(0 == header->pidtidCurrentOwner.tid);
+
+ header->pidtidCurrentOwner.pid = my_pid;
+ header->pidtidCurrentOwner.tid = locking_thread;
+
+ ulIdx = header->ulOwnersIdx % (sizeof(header->pidtidOwners) / sizeof(header->pidtidOwners[0]));
+
+ header->pidtidOwners[ulIdx].pid = my_pid;
+ header->pidtidOwners[ulIdx].tid = locking_thread;
+
+ header->ulOwnersIdx += 1;
+#endif // TRACK_SHMLOCK_OWNERSHIP
+
+ }
+
+ lock_count++;
+ TRACE("SHM lock level is now %d\n", lock_count.Load());
+ return lock_count;
+}
+
+/*++
+SHMRelease
+
+Release a lock on shared memory taken with SHMLock.
+
+(no parameters)
+
+Return value :
+ New lock count
+
+--*/
+int SHMRelease(void)
+{
+ /* prevent a thread from releasing another thread's lock */
+ PALCEnterCriticalSection(&shm_critsec);
+
+ if(lock_count==0)
+ {
+ ASSERT("SHMRelease called without matching SHMLock!\n");
+ PALCLeaveCriticalSection(&shm_critsec);
+ return 0;
+ }
+
+ lock_count--;
+
+ _ASSERTE(lock_count >= 0);
+
+ /* If lock count is 0, this call matches the first Lock call; it's time to
+ set the spinlock back to 0. */
+ if(lock_count == 0)
+ {
+ SHM_FIRST_HEADER *header;
+ pid_t my_pid, tmp_pid;
+
+ TRACE("Releasing first-level SHM lock : resetting spinlock\n");
+
+ my_pid = gPID;
+
+ header = (SHM_FIRST_HEADER *)shm_segment_bases[0].Load();
+
+#ifdef TRACK_SHMLOCK_OWNERSHIP
+ CHECK_CANARIES(header);
+ _ASSERTE(0 != my_pid);
+ _ASSERTE(getpid() == my_pid);
+ _ASSERTE(my_pid == header->spinlock);
+ _ASSERTE(header->pidtidCurrentOwner.pid == my_pid);
+ _ASSERTE(pthread_self() == header->pidtidCurrentOwner.tid);
+ _ASSERTE((pthread_t)locking_thread == header->pidtidCurrentOwner.tid);
+
+ header->pidtidCurrentOwner.pid = 0;
+ header->pidtidCurrentOwner.tid = 0;
+#endif // TRACK_SHMLOCK_OWNERSHIP
+
+
+#ifdef _HPUX_
+ //
+ // TODO: workaround for VSW # 381564
+ //
+ do
+#endif // _HPUX_
+ {
+ /* Make sure we don't touch the spinlock if we don't own it. We're
+ supposed to own it if we get here, but just in case... */
+ tmp_pid = InterlockedCompareExchange((LONG *) &header->spinlock, 0, my_pid);
+
+ if (tmp_pid != my_pid)
+ {
+ ASSERT("Process 0x%08x tried to release spinlock owned by process "
+ "0x%08x! \n", my_pid, tmp_pid);
+ PALCLeaveCriticalSection(&shm_critsec);
+ return 0;
+ }
+ }
+#ifdef _HPUX_
+ //
+ // TODO: workaround for VSW # 381564
+ //
+ while (my_pid == header->spinlock);
+#endif // _HPUX_
+
+ /* indicate no thread (in this process) holds the SHM lock */
+ locking_thread = 0;
+
+#ifdef TRACK_SHMLOCK_OWNERSHIP
+ CHECK_CANARIES(header);
+#endif // TRACK_SHMLOCK_OWNERSHIP
+ }
+
+ TRACE("SHM lock level is now %d\n", lock_count.Load());
+
+ /* This matches the EnterCriticalSection from SHMRelease */
+ PALCLeaveCriticalSection(&shm_critsec);
+
+ /* This matches the EnterCriticalSection from SHMLock */
+ PALCLeaveCriticalSection(&shm_critsec);
+
+ return lock_count;
+}
+
+/*++
+SHMPtrToPtr
+
+Convert a SHMPTR value to a valid pointer within the address space of the
+current process
+
+Parameters :
+ SHMPTR shmptr : SHMPTR value to convert into a pointer
+
+Return value :
+ Address corresponding to the given SHMPTR, valid for the current process
+
+Notes :
+(see notes for SHMPTR_SEGMENT macro for details on SHMPTR structure)
+
+It is possible for the segment index to be greater than the known total number
+of segments (shm_numsegments); this means that the SHMPTR points to a memory
+block in a shared memory segment this process doesn't know about. In this case,
+we must obtain an address for that new segment and add it to our array
+(see SHMMapUnknownSegments for details)
+
+In the simplest case (no need to map new segments), there is no need to hold
+the lock, since we don't access any information that can change
+--*/
+LPVOID SHMPtrToPtr(SHMPTR shmptr)
+{
+ void *retval;
+ int segment;
+ int offset;
+
+ TRACE("Converting SHMPTR 0x%08x to a valid pointer...\n", shmptr);
+ if(!shmptr)
+ {
+ WARN("Got SHMPTR \"0\"; returning NULL pointer\n");
+ return NULL;
+ }
+
+ segment = SHMPTR_SEGMENT(shmptr);
+
+ /* If segment isn't known, it may have been added by another process. We
+ need to map all new segments into our address space. */
+ if(segment>= shm_numsegments)
+ {
+ TRACE("SHMPTR is in segment %d, we know only %d. We must now map all "
+ "unknowns.\n", segment, shm_numsegments);
+ SHMMapUnknownSegments();
+
+ /* if segment is still unknown, then it doesn't exist */
+ if(segment>=shm_numsegments)
+ {
+ ASSERT("Segment %d still unknown; returning NULL\n", segment);
+ return NULL;
+ }
+ TRACE("Segment %d found; continuing\n", segment);
+ }
+
+ /* Make sure the offset doesn't point outside the segment */
+ offset = SHMPTR_OFFSET(shmptr);
+ if(offset>=segment_size)
+ {
+ ASSERT("Offset %d is larger than segment size (%d)! returning NULL\n",
+ offset, segment_size);
+ return NULL;
+
+ }
+
+ /* Make sure the offset doesn't point in the segment's header */
+ if(segment == 0)
+ {
+ if (static_cast<size_t>(offset) < roundup(sizeof(SHM_FIRST_HEADER), sizeof(INT64)))
+ {
+ ASSERT("Offset %d is in segment header! returning NULL\n", offset);
+ return NULL;
+ }
+ }
+ else
+ {
+ if (static_cast<size_t>(offset) < sizeof(SHM_SEGMENT_HEADER))
+ {
+ ASSERT("Offset %d is in segment header! returning NULL\n", offset);
+ return NULL;
+ }
+ }
+
+ retval = shm_segment_bases[segment];
+ retval = static_cast<BYTE*>(retval) + offset;
+
+ TRACE("SHMPTR %#x is at offset %d in segment %d; maps to address %p\n",
+ shmptr, offset, segment, retval);
+ return retval;
+}
+
+
+/*++
+Function :
+ SHMGetInfo
+
+ Retrieve some information from shared memory
+
+Parameters :
+ SHM_INFO_ID element : identifier of element to retrieve
+
+Return value :
+ Value of specified element
+
+Notes :
+ The SHM lock should be held while manipulating shared memory
+--*/
+SHMPTR SHMGetInfo(SHM_INFO_ID element)
+{
+ SHM_FIRST_HEADER *header = NULL;
+ SHMPTR retval = 0;
+
+ if(element < 0 || element >= SIID_LAST)
+ {
+ ASSERT("Invalid SHM info element %d\n", element);
+ return 0;
+ }
+
+ /* verify that this thread holds the SHM lock. No race condition: if the
+ current thread is here, it can't be in SHMLock or SHMUnlock */
+ if( (HANDLE)pthread_self() != locking_thread )
+ {
+ ASSERT("SHMGetInfo called while thread does not hold the SHM lock!\n");
+ }
+
+ header = (SHM_FIRST_HEADER *)shm_segment_bases[0].Load();
+
+ retval = header->shm_info[element];
+
+ TRACE("SHM info element %d is %08x\n", element, retval );
+ return retval;
+}
+
+
+/*++
+Function :
+ SHMSetInfo
+
+ Place some information into shared memory
+
+Parameters :
+ SHM_INFO_ID element : identifier of element to save
+ SHMPTR value : new value of element
+
+Return value :
+ TRUE if successfull, FALSE otherwise.
+
+Notes :
+ The SHM lock should be held while manipulating shared memory
+--*/
+BOOL SHMSetInfo(SHM_INFO_ID element, SHMPTR value)
+{
+ SHM_FIRST_HEADER *header;
+
+ if(element < 0 || element >= SIID_LAST)
+ {
+ ASSERT("Invalid SHM info element %d\n", element);
+ return FALSE;
+ }
+
+ /* verify that this thread holds the SHM lock. No race condition: if the
+ current thread is here, it can't be in SHMLock or SHMUnlock */
+ if( (HANDLE)pthread_self() != locking_thread )
+ {
+ ASSERT("SHMGetInfo called while thread does not hold the SHM lock!\n");
+ }
+
+ header = (SHM_FIRST_HEADER*)shm_segment_bases[0].Load();
+
+ TRACE("Setting SHM info element %d to %08x; used to be %08x\n",
+ element, value, header->shm_info[element].Load() );
+
+ header->shm_info[element] = value;
+
+ return TRUE;
+}
+
+
+/* Static function implementations ********************************************/
+
+/*++
+SHMInitPool
+
+Perform one-time initialization for a shared memory pool.
+
+Parameters :
+ SHMPTR first : SHMPTR of first memory block in the pool
+ int block_size : size (in bytes) of a memory block in this pool
+ int pool_size : total size (in bytes) of this pool
+ SHM_POOL_INFO *pool : pointer to initialize with information about the pool
+
+Return value :
+ SHMPTR of last memory block in the pool
+
+Notes :
+This function is used to initialize the memory pools of the first SHM segment.
+In addition to creating a linked list of SHMPTRs, it initializes the given
+SHM_POOL_INFO based on the given information.
+--*/
+static SHMPTR SHMInitPool(SHMPTR first, int block_size, int pool_size,
+ SHM_POOL_INFO *pool)
+{
+ int num_blocks;
+ SHMPTR last;
+
+ TRACE("Initializing SHM pool for %d-byte blocks\n", block_size);
+
+ /* Number of memory blocks of size "block_size" that can fit in "pool_size"
+ bytes (rounded down) */
+ num_blocks = pool_size/block_size;
+
+ /* Create the initial linked list of free blocks */
+ last = SHMLinkPool(first, block_size, num_blocks);
+ if( 0 == last )
+ {
+ ERROR("Failed to create linked list of free blocks!\n");
+ return 0;
+ }
+
+ /* Initialize SHM_POOL_INFO */
+ pool->first_free = first;
+ pool->free_items = num_blocks;
+ pool->item_size = block_size;
+ pool->num_items = num_blocks;
+
+ TRACE("New SHM pool extends from SHMPTR 0x%08x to 0x%08x\n", first, last);
+ return last;
+}
+
+/*++
+SHMLinkPool
+
+Joins contiguous blocks of memory into a linked list..
+
+Parameters :
+ SHMPTR first : First SHMPTR in the memory pool; first link in the list
+ int block_size : size (in bytes) of the memory blocks
+ int num_blocks : number of contiguous blocks to link
+
+Return value :
+ SHMPTR of last memory block in the pool
+
+Notes :
+The linked list is created by saving the value of the next SHMPTR in the list
+in the memory location corresponding to the previous SHMPTR :
+*(SHMPTR *)SHMPTR_TO_PTR(previous) = previous + block_size
+--*/
+static SHMPTR SHMLinkPool(SHMPTR first, int block_size, int num_blocks)
+{
+ LPBYTE item_ptr;
+ SHMPTR *shmptr_ptr;
+ SHMPTR next_shmptr;
+ int i;
+
+ TRACE("Linking %d blocks of %d bytes, starting at 0x%08x\n",
+ num_blocks, block_size, first);
+
+ item_ptr = static_cast<LPBYTE>(
+ static_cast<LPBYTE>(shm_segment_bases[SHMPTR_SEGMENT(first)].Load()) +
+ (SHMPTR_OFFSET(first)));
+ next_shmptr = first/*+block_size*/;
+
+ /* Link blocks together */
+ for(i=0; i<num_blocks; i++)
+ {
+ next_shmptr += block_size;
+
+ /* item_ptr is char * (so we can increment with +=blocksize), we cast
+ it to a SHMPTR * and set its content to the next SHMPTR in the list*/
+ shmptr_ptr = (SHMPTR *)item_ptr;
+ *shmptr_ptr = next_shmptr;
+
+ item_ptr+=block_size;
+ }
+ /* Last SHMPTR in the list must point to NULL */
+ item_ptr-=block_size;
+ shmptr_ptr = (SHMPTR *)item_ptr;
+ *shmptr_ptr = 0;
+
+ /* Return SHMPTR of last element in the list */
+ next_shmptr -= block_size;
+
+ TRACE("New linked pool goes from 0x%08x to 0x%08x\n", first, next_shmptr);
+ return next_shmptr;
+}
+
+/*++
+SHMMapUnknownSegments
+
+Map into this process all SHM segments not yet mapped
+
+(no parameters)
+
+Return value :
+ TRUE on success, FALSE in case of error
+--*/
+static BOOL SHMMapUnknownSegments(void)
+{
+ return TRUE;
+}
+
+/*++
+SHMAddSegment
+
+Create a new SHM segment, map it into this process, initialize it, then link it
+to the other SHM segments
+
+(no parameters)
+
+Return value :
+ TRUE on success, FALSE in case of error
+
+Notes :
+ This function assumes the SHM lock is held.
+--*/
+static BOOL SHMAddSegment(void)
+{
+ LPVOID segment_base;
+ SHM_SEGMENT_HEADER *header;
+ SHM_FIRST_HEADER *first_header;
+ SHMPTR first_shmptr;
+ SHMPTR *shmptr_ptr;
+ int sps;
+ int used_size;
+ int new_size;
+ int current_pool_size;
+ int used_pool_size;
+ int new_pool_size;
+ int num_new_items;
+
+ /* Map all segments this process doesn't yet know about, so we link the new
+ segment at the right place */
+ if(!SHMMapUnknownSegments())
+ {
+ ERROR("SHMMapUnknownSegments failed!\n");
+ return FALSE;
+ }
+
+ /* Avoid overflowing */
+ if(shm_numsegments == MAX_SEGMENTS)
+ {
+ ERROR("Can't map more segments : maximum number (%d) reached!\n",
+ MAX_SEGMENTS);
+ return FALSE;
+ }
+
+ TRACE("Creating SHM segment #%d\n", shm_numsegments);
+
+ segment_base = mmap(NULL, segment_size, PROT_READ|PROT_WRITE,
+ MAP_ANON|MAP_PRIVATE,-1, 0);
+
+ if(segment_base == MAP_FAILED)
+ {
+ ERROR("mmap() failed! error is %d (%s)\n", errno, strerror(errno));
+ return FALSE;
+ }
+
+ shm_segment_bases[shm_numsegments] = segment_base;
+
+ /* Save name (well, suffix) of new segment in the header of the old last
+ segment, so that other processes know where it is. */
+ header = (SHM_SEGMENT_HEADER *)shm_segment_bases[shm_numsegments-1].Load();
+
+ /* Indicate that the new segment is the last one */
+ header = (SHM_SEGMENT_HEADER *)segment_base;
+
+ /* We're now ready to update our memory pools */
+
+ first_header = (SHM_FIRST_HEADER *)shm_segment_bases[0].Load();
+
+ /* Calculate total amount of used memory (in bytes) */
+ used_size = 0;
+ for(sps = 0; sps<SPS_LAST;sps++)
+ {
+ /* Add total size of this pool */
+ used_size += first_header->pools[sps].num_items*block_sizes[sps];
+
+ /* Remove unused size of this pool */
+ used_size -= first_header->pools[sps].free_items*block_sizes[sps];
+ }
+
+ /* Determine how to divide the new segment between the pools for the
+ different block sizes, then update the pool inforamtion accordingly
+ Allocation strategy :
+ 1) Calculate the proportion of used memory used by each pool
+ 2) Allocate this proportion of the new segment to each pool
+ */
+
+ /* Add the new segment to the total amount of SHM memory */
+ new_size = segment_size-roundup(sizeof(SHM_SEGMENT_HEADER), sizeof(INT64));
+
+ /* Calculate value of first SHMPTR in the new segment : segment is
+ shm_numsegments (not yet incremented); offset is the first byte after
+ the segment header */
+ first_shmptr = MAKE_SHMPTR(shm_numsegments,roundup(sizeof(SHM_SEGMENT_HEADER), sizeof(INT64)));
+
+ TRACE("Updating SHM pool information; Total memory used is %d bytes; "
+ "we are adding %d bytes\n", used_size, new_size);
+
+ /* We want to allocate at least 1 block of each size (to avoid adding
+ special cases everywhere). We remove the required space for these blocks
+ from the size used in the calculations, then add 1 to each block count */
+ for(sps=0;sps<SPS_LAST;sps++)
+ new_size -= block_sizes[sps];
+
+ /* Loop through all block sizes */
+ for(sps=0; sps<SPS_LAST; sps++)
+ {
+ TRACE("Now processing block size \"%d\"...\n", block_sizes[sps]);
+ /* amount of memory currently reserved for this block size */
+ current_pool_size = first_header->pools[sps].num_items*block_sizes[sps];
+
+ /* how much of that is actually used? */
+ used_pool_size = current_pool_size -
+ first_header->pools[sps].free_items*block_sizes[sps];
+
+ DBGOUT("%d bytes of %d bytes used (%d%%)\n", used_pool_size,
+ current_pool_size, (used_pool_size*100)/current_pool_size);
+
+ /* amount of memory we want to add to the pool for this block size :
+ amount used by this pool/total amount used * new segment's size */
+ new_pool_size = (((LONGLONG)used_pool_size)*new_size)/used_size;
+
+ DBGOUT("Allocating %d bytes of %d to %d-byte pool\n",
+ new_pool_size, new_size, block_sizes[sps]);
+
+ /* determine the number of blocks that can fit in the chosen amount */
+ num_new_items = new_pool_size/block_sizes[sps];
+
+ /* make sure we allocate at least 1 block of each size */
+ num_new_items +=1;
+
+ DBGOUT("Adding %d new blocks\n", num_new_items);
+
+ /* Save the first and last block of the current block size in the new
+ segment; join all blocks in between in a linked list */
+ header->first_pool_blocks[sps] = first_shmptr;
+ header->last_pool_blocks[sps] = SHMLinkPool(first_shmptr,
+ block_sizes[sps],
+ num_new_items);
+
+ /* Link the last block in the new linked list to the first block of the
+ old global linked list. We don't use SHMPTR_TO_PTR because the pool
+ data isn't updated yet */
+ shmptr_ptr = reinterpret_cast<SHMPTR*>(
+ static_cast<LPBYTE>(shm_segment_bases[SHMPTR_SEGMENT(header->last_pool_blocks[sps])].Load()) +
+ SHMPTR_OFFSET(header->last_pool_blocks[sps]));
+
+ *shmptr_ptr = first_header->pools[sps].first_free;
+
+ /* Save the first block of the new linked list as the new beginning of
+ the global linked list; the global list now contains all new blocks
+ AND all blocks that were already free */
+ first_header->pools[sps].first_free = header->first_pool_blocks[sps];
+
+ /* Update block counts to include new blocks */
+ first_header->pools[sps].free_items+=num_new_items;
+ first_header->pools[sps].num_items+=num_new_items;
+
+ DBGOUT("There are now %d %d-byte blocks, %d are free\n",
+ first_header->pools[sps].num_items, block_sizes[sps],
+ first_header->pools[sps].free_items);
+
+ /* Update first_shmptr to first byte after the new pool */
+ first_shmptr+=num_new_items*block_sizes[sps];
+ }
+ shm_numsegments++;
+
+ return TRUE;
+}
+
+/*++
+SHMStrDup
+
+Duplicates the string in shared memory.
+
+Returns the new address as SHMPTR on success.
+Returns (SHMPTR)NULL on failure.
+--*/
+SHMPTR SHMStrDup( LPCSTR string )
+{
+ UINT length = 0;
+ SHMPTR retVal = 0;
+
+ if ( string )
+ {
+ length = strlen( string );
+
+ retVal = SHMalloc( ++length );
+
+ if ( retVal != 0 )
+ {
+ LPVOID ptr = SHMPTR_TO_PTR( retVal );
+ _ASSERT_MSG(ptr != NULL, "SHMPTR_TO_PTR returned NULL.\n");
+ if (ptr != NULL)
+ {
+ memcpy( ptr, string, length );
+ }
+ else
+ {
+ // This code should never be reached. If a valid pointer
+ // is passed to SHMPTR_TO_PTR and NULL is returned, then
+ // there's a problem in either the macro, or the underlying
+ // call to SHMPtrToPtr. In case the impossible happens,
+ // though, free the memory and return NULL rather than
+ // returning uninitialized memory.
+ SHMfree( retVal );
+ retVal = NULL;
+ }
+ }
+ }
+ return retVal;
+}
+
+/*++
+SHMWStrDup
+
+Duplicates the wide string in shared memory.
+
+Returns the new address as SHMPTR on success.
+Returns (SHMPTR)NULL on failure.
+--*/
+SHMPTR SHMWStrDup( LPCWSTR string )
+{
+ UINT length = 0;
+ SHMPTR retVal = 0;
+
+ if ( string )
+ {
+ length = ( PAL_wcslen( string ) + 1 ) * sizeof( WCHAR );
+
+ retVal = SHMalloc( length );
+
+ if ( retVal != 0 )
+ {
+ LPVOID ptr = SHMPTR_TO_PTR(retVal);
+ _ASSERT_MSG(ptr != NULL, "SHMPTR_TO_PTR returned NULL.\n");
+ if (ptr != NULL)
+ {
+ memcpy( ptr, string, length );
+ }
+ else
+ {
+ // This code should never be reached. If a valid pointer
+ // is passed to SHMPTR_TO_PTR and NULL is returned, then
+ // there's a problem in either the macro, or the underlying
+ // call to SHMPtrToPtr. In case the impossible happens,
+ // though, free the memory and return NULL rather than
+ // returning uninitialized memory.
+ SHMfree( retVal );
+ retVal = NULL;
+ }
+ }
+ }
+ return retVal;
+}
+
+
+
+/*++
+SHMFindNamedObjectByName
+
+Searches for an object whose name matches the name and ID passed in.
+
+Returns a SHMPTR to its location in shared memory. If no object
+matches the name, the function returns NULL and sets pbNameExists to FALSE.
+If an object matches the name but is of a different type, the function
+returns NULL and sets pbNameExists to TRUE.
+
+--*/
+SHMPTR SHMFindNamedObjectByName( LPCWSTR lpName, SHM_NAMED_OBJECTS_ID oid,
+ BOOL *pbNameExists )
+{
+ PSHM_NAMED_OBJECTS pNamedObject = NULL;
+ SHMPTR shmNamedObject = 0;
+ LPWSTR object_name = NULL;
+
+ if(oid==SHM_NAMED_LAST)
+ {
+ ASSERT("Invalid named object type.\n");
+ return 0;
+ }
+
+ if (pbNameExists == NULL)
+ {
+ ASSERT("pbNameExists must be non-NULL.\n");
+ }
+
+ SHMLock();
+
+ *pbNameExists = FALSE;
+ shmNamedObject = SHMGetInfo( SIID_NAMED_OBJECTS );
+
+ TRACE( "Entering SHMFindNamedObjectByName looking for %S .\n",
+ lpName?lpName:W16_NULLSTRING );
+
+ while ( shmNamedObject )
+ {
+ pNamedObject = (PSHM_NAMED_OBJECTS)SHMPTR_TO_PTR( shmNamedObject );
+ if(NULL == pNamedObject)
+ {
+ ASSERT("Got invalid SHMPTR value; list of named objects is "
+ "corrupted.\n");
+ break;
+ }
+
+ if ( pNamedObject->ShmObjectName )
+ {
+ object_name = (LPWSTR)SHMPTR_TO_PTR( pNamedObject->ShmObjectName );
+ }
+
+ if ( object_name &&
+ PAL_wcscmp( lpName, object_name ) == 0 )
+ {
+ if(oid == pNamedObject->ObjectType)
+ {
+ TRACE( "Returning the kernel object %p.\n", pNamedObject );
+ }
+ else
+ {
+ shmNamedObject = 0;
+ *pbNameExists = TRUE;
+ }
+ goto Exit;
+ }
+ shmNamedObject = pNamedObject->ShmNext;
+ }
+
+ shmNamedObject = 0;
+ TRACE( "No matching kernel object was found.\n" );
+
+Exit:
+ SHMRelease();
+ return shmNamedObject;
+
+}
+
+/*++
+SHMRemoveNamedObject
+
+Removes the specified named object from the list
+
+No return.
+
+note : the caller is reponsible for releasing all associated memory
+--*/
+void SHMRemoveNamedObject( SHMPTR shmNamedObject )
+{
+ PSHM_NAMED_OBJECTS pshmLast = 0;
+ PSHM_NAMED_OBJECTS pshmCurrent = 0;
+
+ TRACE( "Entered SHMDeleteNamedObject shmNamedObject = %d\n", shmNamedObject );
+ SHMLock();
+
+ pshmCurrent =
+ (PSHM_NAMED_OBJECTS)SHMPTR_TO_PTR( SHMGetInfo( SIID_NAMED_OBJECTS ) );
+ pshmLast = pshmCurrent;
+
+ while ( pshmCurrent )
+ {
+ if ( pshmCurrent->ShmSelf == shmNamedObject )
+ {
+ TRACE( "Patching the list.\n" );
+
+ /* Patch the list, and delete the object. */
+ if ( pshmLast->ShmSelf == pshmCurrent->ShmSelf )
+ {
+ /* Either the first element or no elements left. */
+ SHMSetInfo( SIID_NAMED_OBJECTS, pshmCurrent->ShmNext );
+ }
+ else if ( (PSHM_NAMED_OBJECTS)SHMPTR_TO_PTR( pshmCurrent->ShmNext ) )
+ {
+ pshmLast->ShmNext = pshmCurrent->ShmNext;
+ }
+ else
+ {
+ /* Only one left. */
+ pshmLast->ShmNext = 0;
+ }
+
+ break;
+ }
+ else
+ {
+ pshmLast = pshmCurrent;
+ pshmCurrent = (PSHM_NAMED_OBJECTS)SHMPTR_TO_PTR( pshmCurrent->ShmNext );
+ }
+ }
+
+ SHMRelease();
+ return;
+}
+
+/*++ SHMAddNamedObject
+
+Adds the specified named object to the list.
+
+No return.
+--*/
+void SHMAddNamedObject( SHMPTR shmNewNamedObject )
+{
+ PSHM_NAMED_OBJECTS pshmNew = 0;
+
+ pshmNew = (PSHM_NAMED_OBJECTS)SHMPTR_TO_PTR( shmNewNamedObject );
+
+ if ( pshmNew == NULL )
+ {
+ ASSERT( "pshmNew should not be NULL\n" );
+ }
+
+ SHMLock();
+
+ pshmNew->ShmNext = SHMGetInfo( SIID_NAMED_OBJECTS );
+
+ if ( !SHMSetInfo( SIID_NAMED_OBJECTS, shmNewNamedObject ) )
+ {
+ ASSERT( "Unable to add the mapping object to shared memory.\n" );
+ }
+
+ SHMRelease();
+ return;
+}
diff --git a/src/pal/src/sync/cs.cpp b/src/pal/src/sync/cs.cpp
new file mode 100644
index 0000000000..530e467301
--- /dev/null
+++ b/src/pal/src/sync/cs.cpp
@@ -0,0 +1,1603 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// File:
+// cs.cpp
+//
+// Purpose:
+// Implementation of critical sections
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include "pal/thread.hpp"
+#include "pal/cs.hpp"
+#include "pal/malloc.hpp"
+#include "pal/list.h"
+#include "pal/dbgmsg.h"
+#include "pal/init.h"
+#include "pal/process.h"
+
+#include <sched.h>
+#include <pthread.h>
+
+using namespace CorUnix;
+
+//
+// Uncomment the following line to turn CS behavior from
+// unfair to fair lock
+//
+// #define PALCS_TRANSFER_OWNERSHIP_ON_RELEASE
+
+//
+// Uncomment the following line to enable simple mutex based CSs
+// Note: when MUTEX_BASED_CSS is defined, PALCS_TRANSFER_OWNERSHIP_ON_RELEASE
+// has no effect
+//
+// #define MUTEX_BASED_CSS
+
+//
+// Important notes on critical sections layout/semantics on Unix
+//
+// 1) The PAL_CRITICAL_SECTION structure below must match the size of the
+// CRITICAL_SECTION defined in pal.h. Besides the "windows part"
+// of both the structures must be identical.
+// 2) Both PAL_CRITICAL_SECTION and CRITICAL_SECTION currently do not match
+// the size of the Windows' CRITICAL_SECTION.
+// - From unmanaged code point of view, one should never make assumptions
+// on the size and layout of the CRITICAL_SECTION structure, and anyway
+// on Unix PAL's CRITICAL_SECTION extends the Windows one, so that some
+// assumptions may still work.
+// - From managed code point of view, one could try to interop directly
+// to unmanaged critical sections APIs (though that would be quite
+// meaningless). In order to do that, she would need to define a copy
+// of the CRITICAL_SECTION structure in his/her code, and that may lead
+// to access random data beyond the structure limit, if that managed
+// code is compiled on Unix.
+// In case such scenario should be supported, the current implementation
+// will have to be modified in a way to go back to the original Windows
+// CRITICAL_SECTION layout. That would require to dynamically allocate
+// the native data and use LockSemaphore as a pointer to it. The current
+// solution intentionally avoids that since an effort has been made to
+// make CSs objects completely independent from any other PAL subsystem,
+// so that they can be used during initialization and shutdown.
+// In case the "dynamically allocate native data" solution should be
+// implemented, CSs would acquire a dependency on memory allocation and
+// thread suspension subsystems, since the first contention on a specific
+// CS would trigger the native data allocation.
+// 3) The semantics of the LockCount field has not been kept compatible with
+// the Windows implementation.
+// Both on Windows and Unix the lower bit of LockCount indicates
+// whether or not the CS is locked (for both fair and unfair lock
+// solution), the second bit indicates whether or not currently there is a
+// waiter that has been awakened and that is trying to acquire the CS
+// (only unfair lock solution, unused in the fair one); starting from the
+// third bit, LockCount represents the number of waiter threads currently
+// waiting on the CS.
+// Windows, anyway, implements this semantics in negative logic, so that
+// an unlocked CS is represented by a LockCount == -1 (i.e. 0xFFFFFFFF,
+// all the bits set), while on Unix an unlocked CS has LockCount == 0.
+// Windows needs to use negative logic to support legacy code bad enough
+// to directly access CS's fields making the assumption that
+// LockCount == -1 means CS unlocked. Unix will not support that, and
+// it uses positive logic.
+// 4) The CRITICAL_SECTION_DEBUG_INFO layout on Unix is intentionally not
+// compatible with the Windows layout.
+// 5) For legacy code dependencies issues similar to those just described for
+// the LockCount field, Windows CS code maintains a per-process list of
+// debug info for all the CSs, both on debug and free/retail builds. On
+// Unix such a list is maintained only on debug builds, and no debug
+// info structure is allocated on free/retail builds
+//
+
+SET_DEFAULT_DEBUG_CHANNEL(CRITSEC);
+
+#ifdef TRACE_CS_LOGIC
+#define CS_TRACE TRACE
+#else
+#ifdef __GNUC__
+#define CS_TRACE(args...)
+#else
+#define CS_TRACE(...)
+#endif
+#endif // TRACE_CS_LOGIC
+
+//
+// Note: PALCS_LOCK_WAITER_INC must be 2 * PALCS_LOCK_AWAKENED_WAITER
+//
+#define PALCS_LOCK_INIT 0
+#define PALCS_LOCK_BIT 1
+#define PALCS_LOCK_AWAKENED_WAITER 2
+#define PALCS_LOCK_WAITER_INC 4
+
+#define PALCS_GETLBIT(val) ((int)(0!=(PALCS_LOCK_BIT&val)))
+#define PALCS_GETAWBIT(val) ((int)(0!=(PALCS_LOCK_AWAKENED_WAITER&val)))
+#define PALCS_GETWCOUNT(val) (val/PALCS_LOCK_WAITER_INC)
+
+enum PalCsInitState
+{
+ PalCsNotInitialized, // Critical section not initialized (InitializedCriticalSection
+ // has not yet been called, or DeleteCriticalsection has been
+ // called).
+ PalCsUserInitialized, // Critical section initialized from the user point of view,
+ // i.e. InitializedCriticalSection has been called.
+ PalCsFullyInitializing, // A thread found the CS locked, this is the first contention on
+ // this CS, and the thread is initializing the CS's native data.
+ PalCsFullyInitialized // Internal CS's native data has been fully initialized.
+};
+
+enum PalCsWaiterReturnState
+{
+ PalCsReturnWaiterAwakened,
+ PalCsWaiterDidntWait
+};
+
+struct _PAL_CRITICAL_SECTION; // fwd declaration
+
+typedef struct _CRITICAL_SECTION_DEBUG_INFO
+{
+ LIST_ENTRY Link;
+ struct _PAL_CRITICAL_SECTION * pOwnerCS;
+ Volatile<ULONG> lAcquireCount;
+ Volatile<ULONG> lEnterCount;
+ Volatile<LONG> lContentionCount;
+} CRITICAL_SECTION_DEBUG_INFO, *PCRITICAL_SECTION_DEBUG_INFO;
+
+typedef struct _PAL_CRITICAL_SECTION_NATIVE_DATA
+{
+ pthread_mutex_t mutex;
+ pthread_cond_t condition;
+ int iPredicate;
+} PAL_CRITICAL_SECTION_NATIVE_DATA, *PPAL_CRITICAL_SECTION_NATIVE_DATA;
+
+typedef struct _PAL_CRITICAL_SECTION {
+ // Windows part
+ PCRITICAL_SECTION_DEBUG_INFO DebugInfo;
+ Volatile<LONG> LockCount;
+ LONG RecursionCount;
+ SIZE_T OwningThread;
+ HANDLE LockSemaphore;
+ ULONG_PTR SpinCount;
+ // Private Unix part
+ BOOL fInternal;
+ Volatile<PalCsInitState> cisInitState;
+ PAL_CRITICAL_SECTION_NATIVE_DATA csndNativeData;
+} PAL_CRITICAL_SECTION, *PPAL_CRITICAL_SECTION, *LPPAL_CRITICAL_SECTION;
+
+#ifdef _DEBUG
+namespace CorUnix
+{
+ PAL_CRITICAL_SECTION g_csPALCSsListLock;
+ LIST_ENTRY g_PALCSList = { &g_PALCSList, &g_PALCSList};
+}
+#endif // _DEBUG
+
+#define ObtainCurrentThreadId(thread) ObtainCurrentThreadIdImpl(thread, __func__)
+static SIZE_T ObtainCurrentThreadIdImpl(CPalThread *pCurrentThread, const char *callingFuncName)
+{
+ SIZE_T threadId;
+ if(pCurrentThread)
+ {
+ threadId = pCurrentThread->GetThreadId();
+ _ASSERTE(threadId == THREADSilentGetCurrentThreadId());
+ }
+ else
+ {
+ threadId = THREADSilentGetCurrentThreadId();
+ CS_TRACE("Early %s, no pthread data, getting TID internally\n", callingFuncName);
+ }
+ _ASSERTE(0 != threadId);
+
+ return threadId;
+}
+
+
+/*++
+Function:
+ InitializeCriticalSection
+
+See MSDN doc.
+--*/
+void InitializeCriticalSection(LPCRITICAL_SECTION lpCriticalSection)
+{
+ PERF_ENTRY(InitializeCriticalSection);
+ ENTRY("InitializeCriticalSection(lpCriticalSection=%p)\n",
+ lpCriticalSection);
+
+ InternalInitializeCriticalSectionAndSpinCount(lpCriticalSection,
+ 0, false);
+
+ LOGEXIT("InitializeCriticalSection returns void\n");
+ PERF_EXIT(InitializeCriticalSection);
+}
+
+/*++
+Function:
+ InitializeCriticalSectionEx - Flags is ignored.
+
+See MSDN doc.
+--*/
+BOOL InitializeCriticalSectionEx(LPCRITICAL_SECTION lpCriticalSection, DWORD dwSpinCount, DWORD Flags)
+{
+ PERF_ENTRY(InitializeCriticalSection);
+ ENTRY("InitializeCriticalSectionEx(lpCriticalSection=%p, dwSpinCount=%d, Flags=%d)\n",
+ lpCriticalSection, dwSpinCount, Flags);
+
+ InternalInitializeCriticalSectionAndSpinCount(lpCriticalSection, dwSpinCount, false);
+
+ LOGEXIT("InitializeCriticalSectionEx returns TRUE\n");
+ PERF_EXIT(InitializeCriticalSection);
+ return true;
+}
+
+/*++
+Function:
+ InitializeCriticalSectionAndSpinCount
+
+See MSDN doc.
+--*/
+BOOL InitializeCriticalSectionAndSpinCount(LPCRITICAL_SECTION lpCriticalSection,
+ DWORD dwSpinCount)
+{
+ BOOL bRet = TRUE;
+ PERF_ENTRY(InitializeCriticalSectionAndSpinCount);
+ ENTRY("InitializeCriticalSectionAndSpinCount(lpCriticalSection=%p, "
+ "dwSpinCount=%u)\n", lpCriticalSection, dwSpinCount);
+
+ InternalInitializeCriticalSectionAndSpinCount(lpCriticalSection,
+ dwSpinCount, false);
+
+ LOGEXIT("InitializeCriticalSectionAndSpinCount returns BOOL %d\n",
+ bRet);
+ PERF_EXIT(InitializeCriticalSectionAndSpinCount);
+ return bRet;
+}
+
+/*++
+Function:
+ DeleteCriticalSection
+
+See MSDN doc.
+--*/
+void DeleteCriticalSection(LPCRITICAL_SECTION lpCriticalSection)
+{
+ PERF_ENTRY(DeleteCriticalSection);
+ ENTRY("DeleteCriticalSection(lpCriticalSection=%p)\n", lpCriticalSection);
+
+ InternalDeleteCriticalSection(lpCriticalSection);
+
+ LOGEXIT("DeleteCriticalSection returns void\n");
+ PERF_EXIT(DeleteCriticalSection);
+}
+
+/*++
+Function:
+ EnterCriticalSection
+
+See MSDN doc.
+--*/
+void EnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection)
+{
+ PERF_ENTRY(EnterCriticalSection);
+ ENTRY("EnterCriticalSection(lpCriticalSection=%p)\n", lpCriticalSection);
+
+ CPalThread * pThread = InternalGetCurrentThread();
+
+ InternalEnterCriticalSection(pThread, lpCriticalSection);
+
+ LOGEXIT("EnterCriticalSection returns void\n");
+ PERF_EXIT(EnterCriticalSection);
+}
+
+/*++
+Function:
+ TryEnterCriticalSection
+
+See MSDN doc.
+--*/
+BOOL TryEnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection)
+{
+ PERF_ENTRY(TryEnterCriticalSection);
+ ENTRY("TryEnterCriticalSection(lpCriticalSection=%p)\n", lpCriticalSection);
+
+ CPalThread * pThread = InternalGetCurrentThread();
+
+ bool fRet = InternalTryEnterCriticalSection(pThread,
+ lpCriticalSection);
+
+ LOGEXIT("TryEnterCriticalSection returns bool %d\n", (int)fRet);
+ PERF_EXIT(TryEnterCriticalSection);
+
+ return (BOOL)fRet;
+}
+
+/*++
+Function:
+ LeaveCriticalSection
+
+See MSDN doc.
+--*/
+VOID LeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection)
+{
+ PERF_ENTRY(LeaveCriticalSection);
+ ENTRY("LeaveCriticalSection(lpCriticalSection=%p)\n", lpCriticalSection);
+
+ CPalThread * pThread = InternalGetCurrentThread();
+
+ InternalLeaveCriticalSection(pThread, lpCriticalSection);
+
+ LOGEXIT("LeaveCriticalSection returns void\n");
+ PERF_EXIT(LeaveCriticalSection);
+}
+
+/*++
+Function:
+ InternalInitializeCriticalSection
+
+Initializes a critical section. It assumes the CS is an internal one,
+i.e. thread entering it will be marked unsafe for suspension
+--*/
+VOID InternalInitializeCriticalSection(CRITICAL_SECTION *pcs)
+{
+ InternalInitializeCriticalSectionAndSpinCount(pcs, 0, true);
+}
+
+/*++
+Function:
+ InternalDeleteCriticalSection
+
+Deletes a critical section
+--*/
+VOID InternalDeleteCriticalSection(
+ PCRITICAL_SECTION pCriticalSection)
+{
+ PAL_CRITICAL_SECTION * pPalCriticalSection =
+ reinterpret_cast<PAL_CRITICAL_SECTION*>(pCriticalSection);
+
+ _ASSERT_MSG(PalCsUserInitialized == pPalCriticalSection->cisInitState ||
+ PalCsFullyInitialized == pPalCriticalSection->cisInitState,
+ "CS %p is not initialized", pPalCriticalSection);
+
+#ifdef _DEBUG
+ CPalThread * pThread =
+ (PALIsThreadDataInitialized() ? GetCurrentPalThread() : NULL);
+
+ if (0 != pPalCriticalSection->LockCount)
+ {
+ SIZE_T tid;
+ tid = ObtainCurrentThreadId(pThread);
+ int iWaiterCount = (int)PALCS_GETWCOUNT(pPalCriticalSection->LockCount);
+
+ if (0 != (PALCS_LOCK_BIT & pPalCriticalSection->LockCount))
+ {
+ // CS is locked
+ if (tid != pPalCriticalSection->OwningThread)
+ {
+ // not owner
+ ASSERT("Thread tid=%u deleting a CS owned by thread tid=%u\n",
+ tid, pPalCriticalSection->OwningThread);
+ }
+ else
+ {
+ // owner
+ if (0 != iWaiterCount)
+ {
+ ERROR("Thread tid=%u is deleting a CS with %d threads waiting on it\n",
+ tid, iWaiterCount);
+ }
+ else
+ {
+ WARN("Thread tid=%u is deleting a critical section it still owns\n",
+ tid);
+ }
+ }
+ }
+ else
+ {
+ // CS is not locked
+ if (0 != iWaiterCount)
+ {
+ ERROR("Deleting a CS with %d threads waiting on it\n",
+ iWaiterCount);
+ }
+ else
+ {
+ ERROR("Thread tid=%u is deleting a critical section currently not "
+ "owned, but with one waiter awakened\n", tid);
+ }
+ }
+ }
+
+ if (NULL != pPalCriticalSection->DebugInfo)
+ {
+ if (pPalCriticalSection != &CorUnix::g_csPALCSsListLock)
+ {
+ InternalEnterCriticalSection(pThread,
+ reinterpret_cast<CRITICAL_SECTION*>(&g_csPALCSsListLock));
+ RemoveEntryList(&pPalCriticalSection->DebugInfo->Link);
+ InternalLeaveCriticalSection(pThread,
+ reinterpret_cast<CRITICAL_SECTION*>(&g_csPALCSsListLock));
+ }
+ else
+ {
+ RemoveEntryList(&pPalCriticalSection->DebugInfo->Link);
+ }
+
+#ifdef PAL_TRACK_CRITICAL_SECTIONS_DATA
+ LONG lVal, lNewVal;
+ Volatile<LONG> * plDest;
+
+ // Update delete count
+ InterlockedIncrement(pPalCriticalSection->fInternal ?
+ &g_lPALCSInternalDeleteCount : &g_lPALCSDeleteCount);
+
+ // Update acquire count
+ plDest = pPalCriticalSection->fInternal ?
+ &g_lPALCSInternalAcquireCount : &g_lPALCSAcquireCount;
+ do {
+ lVal = *plDest;
+ lNewVal = lVal + pPalCriticalSection->DebugInfo->lAcquireCount;
+ lNewVal = InterlockedCompareExchange(plDest, lNewVal, lVal);
+ } while (lVal != lNewVal);
+
+ // Update enter count
+ plDest = pPalCriticalSection->fInternal ?
+ &g_lPALCSInternalEnterCount : &g_lPALCSEnterCount;
+ do {
+ lVal = *plDest;
+ lNewVal = lVal + pPalCriticalSection->DebugInfo->lEnterCount;
+ lNewVal = InterlockedCompareExchange(plDest, lNewVal, lVal);
+ } while (lVal != lNewVal);
+
+ // Update contention count
+ plDest = pPalCriticalSection->fInternal ?
+ &g_lPALCSInternalContentionCount : &g_lPALCSContentionCount;
+ do {
+ lVal = *plDest;
+ lNewVal = lVal + pPalCriticalSection->DebugInfo->lContentionCount;
+ lNewVal = InterlockedCompareExchange(plDest, lNewVal, lVal);
+ } while (lVal != lNewVal);
+
+#endif // PAL_TRACK_CRITICAL_SECTIONS_DATA
+
+ InternalDelete(pPalCriticalSection->DebugInfo);
+ pPalCriticalSection->DebugInfo = NULL;
+ }
+#endif // _DEBUG
+
+ if (PalCsFullyInitialized == pPalCriticalSection->cisInitState)
+ {
+ int iRet;
+
+ // destroy condition
+ iRet = pthread_cond_destroy(&pPalCriticalSection->csndNativeData.condition);
+ _ASSERT_MSG(0 == iRet, "Failed destroying condition in CS @ %p "
+ "[err=%d]\n", pPalCriticalSection, iRet);
+
+ // destroy mutex
+ iRet = pthread_mutex_destroy(&pPalCriticalSection->csndNativeData.mutex);
+ _ASSERT_MSG(0 == iRet, "Failed destroying mutex in CS @ %p "
+ "[err=%d]\n", pPalCriticalSection, iRet);
+ }
+
+ // Reset critical section state
+ pPalCriticalSection->cisInitState = PalCsNotInitialized;
+}
+
+// The following PALCEnterCriticalSection and PALCLeaveCriticalSection
+// functions are intended to provide CorUnix's InternalEnterCriticalSection
+// and InternalLeaveCriticalSection functionalities to legacy C code,
+// which has no knowledge of CPalThread, classes and namespaces.
+
+/*++
+Function:
+ PALCEnterCriticalSection
+
+Provides CorUnix's InternalEnterCriticalSection functionality to legacy C code,
+which has no knowledge of CPalThread, classes and namespaces.
+--*/
+VOID PALCEnterCriticalSection(CRITICAL_SECTION * pcs)
+{
+ CPalThread * pThread =
+ (PALIsThreadDataInitialized() ? GetCurrentPalThread() : NULL);
+ CorUnix::InternalEnterCriticalSection(pThread, pcs);
+}
+
+/*++
+Function:
+ PALCLeaveCriticalSection
+
+Provides CorUnix's InternalLeaveCriticalSection functionality to legacy C code,
+which has no knowledge of CPalThread, classes and namespaces.
+--*/
+VOID PALCLeaveCriticalSection(CRITICAL_SECTION * pcs)
+{
+ CPalThread * pThread =
+ (PALIsThreadDataInitialized() ? GetCurrentPalThread() : NULL);
+ CorUnix::InternalLeaveCriticalSection(pThread, pcs);
+}
+
+namespace CorUnix
+{
+ static PalCsWaiterReturnState PALCS_WaitOnCS(
+ PAL_CRITICAL_SECTION * pPalCriticalSection,
+ LONG lInc);
+ static PAL_ERROR PALCS_DoActualWait(PAL_CRITICAL_SECTION * pPalCriticalSection);
+ static PAL_ERROR PALCS_WakeUpWaiter(PAL_CRITICAL_SECTION * pPalCriticalSection);
+ static bool PALCS_FullyInitialize(PAL_CRITICAL_SECTION * pPalCriticalSection);
+
+#ifdef _DEBUG
+ enum CSSubSysInitState
+ {
+ CSSubSysNotInitialzed,
+ CSSubSysInitializing,
+ CSSubSysInitialized
+ };
+ static Volatile<CSSubSysInitState> csssInitState = CSSubSysNotInitialzed;
+
+#ifdef PAL_TRACK_CRITICAL_SECTIONS_DATA
+ static Volatile<LONG> g_lPALCSInitializeCount = 0;
+ static Volatile<LONG> g_lPALCSDeleteCount = 0;
+ static Volatile<LONG> g_lPALCSAcquireCount = 0;
+ static Volatile<LONG> g_lPALCSEnterCount = 0;
+ static Volatile<LONG> g_lPALCSContentionCount = 0;
+ static Volatile<LONG> g_lPALCSInternalInitializeCount = 0;
+ static Volatile<LONG> g_lPALCSInternalDeleteCount = 0;
+ static Volatile<LONG> g_lPALCSInternalAcquireCount = 0;
+ static Volatile<LONG> g_lPALCSInternalEnterCount = 0;
+ static Volatile<LONG> g_lPALCSInternalContentionCount = 0;
+#endif // PAL_TRACK_CRITICAL_SECTIONS_DATA
+#endif // _DEBUG
+
+
+ /*++
+ Function:
+ CorUnix::CriticalSectionSubSysInitialize
+
+ Initializes CS subsystem
+ --*/
+ void CriticalSectionSubSysInitialize()
+ {
+ static_assert(sizeof(CRITICAL_SECTION) >= sizeof(PAL_CRITICAL_SECTION),
+ "PAL fatal internal error: sizeof(CRITICAL_SECTION) is "
+ "smaller than sizeof(PAL_CRITICAL_SECTION)");
+
+#ifdef _DEBUG
+ LONG lRet = InterlockedCompareExchange((LONG *)&csssInitState,
+ (LONG)CSSubSysInitializing,
+ (LONG)CSSubSysNotInitialzed);
+ if ((LONG)CSSubSysNotInitialzed == lRet)
+ {
+ InitializeListHead(&g_PALCSList);
+
+ InternalInitializeCriticalSectionAndSpinCount(
+ reinterpret_cast<CRITICAL_SECTION*>(&g_csPALCSsListLock),
+ 0, true);
+ InterlockedExchange((LONG *)&csssInitState,
+ (LONG)CSSubSysInitialized);
+ }
+ else
+ {
+ while (csssInitState != CSSubSysInitialized)
+ {
+ sched_yield();
+ }
+ }
+#endif // _DEBUG
+ }
+
+ /*++
+ Function:
+ CorUnix::InternalInitializeCriticalSectionAndSpinCount
+
+ Initializes a CS with the given spin count. If 'fInternal' is true
+ the CS will be treatead as an internal one for its whole lifetime,
+ i.e. any thread that will enter it will be marked as unsafe for
+ suspension as long as it holds the CS
+ --*/
+ void InternalInitializeCriticalSectionAndSpinCount(
+ PCRITICAL_SECTION pCriticalSection,
+ DWORD dwSpinCount,
+ bool fInternal)
+ {
+ PAL_CRITICAL_SECTION * pPalCriticalSection =
+ reinterpret_cast<PAL_CRITICAL_SECTION*>(pCriticalSection);
+
+#ifndef PALCS_TRANSFER_OWNERSHIP_ON_RELEASE
+ // Make sure bits are defined in a usable way
+ _ASSERTE(PALCS_LOCK_AWAKENED_WAITER * 2 == PALCS_LOCK_WAITER_INC);
+#endif // !PALCS_TRANSFER_OWNERSHIP_ON_RELEASE
+
+ // Make sure structure sizes are compatible
+ _ASSERTE(sizeof(CRITICAL_SECTION) >= sizeof(PAL_CRITICAL_SECTION));
+
+#ifdef _DEBUG
+ if (sizeof(CRITICAL_SECTION) > sizeof(PAL_CRITICAL_SECTION))
+ {
+ WARN("PAL_CS_NATIVE_DATA_SIZE appears to be defined to a value (%d) "
+ "larger than needed on this platform (%d).\n",
+ sizeof(CRITICAL_SECTION), sizeof(PAL_CRITICAL_SECTION));
+ }
+#endif // _DEBUG
+
+ // Init CS data
+ pPalCriticalSection->DebugInfo = NULL;
+ pPalCriticalSection->LockCount = 0;
+ pPalCriticalSection->RecursionCount = 0;
+ pPalCriticalSection->SpinCount = dwSpinCount;
+ pPalCriticalSection->OwningThread = NULL;
+ pPalCriticalSection->LockSemaphore = NULL;
+ pPalCriticalSection->fInternal = fInternal;
+
+#ifdef _DEBUG
+ CPalThread * pThread =
+ (PALIsThreadDataInitialized() ? GetCurrentPalThread() : NULL);
+
+ pPalCriticalSection->DebugInfo = InternalNew<CRITICAL_SECTION_DEBUG_INFO>();
+ _ASSERT_MSG(NULL != pPalCriticalSection->DebugInfo,
+ "Failed to allocate debug info for new CS\n");
+
+ // Init debug info data
+ pPalCriticalSection->DebugInfo->lAcquireCount = 0;
+ pPalCriticalSection->DebugInfo->lEnterCount = 0;
+ pPalCriticalSection->DebugInfo->lContentionCount = 0;
+ pPalCriticalSection->DebugInfo->pOwnerCS = pPalCriticalSection;
+
+ // Insert debug info struct in global list
+ if (pPalCriticalSection != &g_csPALCSsListLock)
+ {
+ InternalEnterCriticalSection(pThread,
+ reinterpret_cast<CRITICAL_SECTION*>(&g_csPALCSsListLock));
+ InsertTailList(&g_PALCSList, &pPalCriticalSection->DebugInfo->Link);
+ InternalLeaveCriticalSection(pThread,
+ reinterpret_cast<CRITICAL_SECTION*>(&g_csPALCSsListLock));
+ }
+ else
+ {
+ InsertTailList(&g_PALCSList, &pPalCriticalSection->DebugInfo->Link);
+ }
+
+#ifdef PAL_TRACK_CRITICAL_SECTIONS_DATA
+ InterlockedIncrement(fInternal ?
+ &g_lPALCSInternalInitializeCount : &g_lPALCSInitializeCount);
+#endif // PAL_TRACK_CRITICAL_SECTIONS_DATA
+#endif // _DEBUG
+
+ // Set initializazion state
+ pPalCriticalSection->cisInitState = PalCsUserInitialized;
+
+#ifdef MUTEX_BASED_CSS
+ bool fInit;
+ do
+ {
+ fInit = PALCS_FullyInitialize(pPalCriticalSection);
+ _ASSERTE(fInit);
+ } while (!fInit && 0 == sched_yield());
+
+ if (fInit)
+ {
+ // Set initializazion state
+ pPalCriticalSection->cisInitState = PalCsFullyInitialized;
+ }
+#endif // MUTEX_BASED_CSS
+ }
+
+#ifndef MUTEX_BASED_CSS
+ /*++
+ Function:
+ CorUnix::InternalEnterCriticalSection
+
+ Enters a CS, causing the thread to block if the CS is owned by
+ another thread
+ --*/
+ void InternalEnterCriticalSection(
+ CPalThread * pThread,
+ PCRITICAL_SECTION pCriticalSection)
+ {
+ PAL_CRITICAL_SECTION * pPalCriticalSection =
+ reinterpret_cast<PAL_CRITICAL_SECTION*>(pCriticalSection);
+
+ LONG lSpinCount;
+ LONG lVal, lNewVal;
+ LONG lBitsToChange, lWaitInc;
+ PalCsWaiterReturnState cwrs;
+ SIZE_T threadId;
+
+ _ASSERTE(PalCsNotInitialized != pPalCriticalSection->cisInitState);
+
+ threadId = ObtainCurrentThreadId(pThread);
+
+
+ // Check if the current thread already owns the CS
+ //
+ // Note: there is no need for this double check to be atomic. In fact
+ // if the first check fails, the second doesn't count (and it's not
+ // even executed). If the first one succeeds and the second one
+ // doesn't, it doesn't matter if LockCount has already changed by the
+ // time OwningThread is tested. Instead, if the first one succeeded,
+ // and the second also succeeds, LockCount cannot have changed in the
+ // meanwhile, since this is the owning thread and only the owning
+ // thread can change the lock bit when the CS is owned.
+ if ((pPalCriticalSection->LockCount & PALCS_LOCK_BIT) &&
+ (pPalCriticalSection->OwningThread == threadId))
+ {
+ pPalCriticalSection->RecursionCount += 1;
+#ifdef _DEBUG
+ if (NULL != pPalCriticalSection->DebugInfo)
+ {
+ pPalCriticalSection->DebugInfo->lEnterCount += 1;
+ }
+#endif // _DEBUG
+ goto IECS_exit;
+ }
+
+ // Set bits to change and waiter increment for an incoming thread
+ lBitsToChange = PALCS_LOCK_BIT;
+ lWaitInc = PALCS_LOCK_WAITER_INC;
+ lSpinCount = pPalCriticalSection->SpinCount;
+
+ while (TRUE)
+ {
+ // Either this is an incoming thread, and therefore lBitsToChange
+ // is just PALCS_LOCK_BIT, or this is an awakened waiter
+ _ASSERTE(PALCS_LOCK_BIT == lBitsToChange ||
+ (PALCS_LOCK_BIT | PALCS_LOCK_AWAKENED_WAITER) == lBitsToChange);
+
+ // Make sure the waiter increment is in a valid range
+ _ASSERTE(PALCS_LOCK_WAITER_INC == lWaitInc ||
+ PALCS_LOCK_AWAKENED_WAITER == lWaitInc);
+
+ do {
+ lVal = pPalCriticalSection->LockCount;
+
+ while (0 == (lVal & PALCS_LOCK_BIT))
+ {
+ // CS is not locked: try lo lock it
+
+ // Make sure that whether we are an incoming thread
+ // or the PALCS_LOCK_AWAKENED_WAITER bit is set
+ _ASSERTE((PALCS_LOCK_BIT == lBitsToChange) ||
+ (PALCS_LOCK_AWAKENED_WAITER & lVal));
+
+ lNewVal = lVal ^ lBitsToChange;
+
+ // Make sure we are actually trying to lock
+ _ASSERTE(lNewVal & PALCS_LOCK_BIT);
+
+ CS_TRACE("[ECS %p] Switching from {%d, %d, %d} to "
+ "{%d, %d, %d} ==>\n", pPalCriticalSection,
+ PALCS_GETWCOUNT(lVal), PALCS_GETAWBIT(lVal), PALCS_GETLBIT(lVal),
+ PALCS_GETWCOUNT(lNewVal), PALCS_GETAWBIT(lNewVal), PALCS_GETLBIT(lNewVal));
+
+ // Try to switch the value
+ lNewVal = InterlockedCompareExchange (&pPalCriticalSection->LockCount,
+ lNewVal, lVal);
+
+ CS_TRACE("[ECS %p] ==> %s LockCount={%d, %d, %d} "
+ "lVal={%d, %d, %d}\n", pPalCriticalSection,
+ (lNewVal == lVal) ? "OK" : "NO",
+ PALCS_GETWCOUNT(pPalCriticalSection->LockCount),
+ PALCS_GETAWBIT(pPalCriticalSection->LockCount),
+ PALCS_GETLBIT(pPalCriticalSection->LockCount),
+ PALCS_GETWCOUNT(lVal), PALCS_GETAWBIT(lVal), PALCS_GETLBIT(lVal));
+
+ if (lNewVal == lVal)
+ {
+ // CS successfully acquired
+ goto IECS_set_ownership;
+ }
+
+ // Acquisition failed, some thread raced with us;
+ // update value for next loop
+ lVal = lNewVal;
+ }
+
+ if (0 < lSpinCount)
+ {
+ sched_yield();
+ }
+ } while (0 <= --lSpinCount);
+
+ cwrs = PALCS_WaitOnCS(pPalCriticalSection, lWaitInc);
+
+ if (PalCsReturnWaiterAwakened == cwrs)
+ {
+#ifdef PALCS_TRANSFER_OWNERSHIP_ON_RELEASE
+ //
+ // Fair Critical Sections
+ //
+ // In the fair lock case, when a waiter wakes up the CS
+ // must be locked (i.e. ownership passed on to the waiter)
+ _ASSERTE(0 != (PALCS_LOCK_BIT & pPalCriticalSection->LockCount));
+
+ // CS successfully acquired
+ goto IECS_set_ownership;
+
+#else // PALCS_TRANSFER_OWNERSHIP_ON_RELEASE
+ //
+ // Unfair Critical Sections
+ //
+ _ASSERTE(PALCS_LOCK_AWAKENED_WAITER & pPalCriticalSection->LockCount);
+
+ lBitsToChange = PALCS_LOCK_BIT | PALCS_LOCK_AWAKENED_WAITER;
+ lWaitInc = PALCS_LOCK_AWAKENED_WAITER;
+#endif // PALCS_TRANSFER_OWNERSHIP_ON_RELEASE
+ }
+ }
+
+ IECS_set_ownership:
+ // Critical section acquired: set ownership data
+ pPalCriticalSection->OwningThread = threadId;
+ pPalCriticalSection->RecursionCount = 1;
+#ifdef _DEBUG
+ if (NULL != pPalCriticalSection->DebugInfo)
+ {
+ pPalCriticalSection->DebugInfo->lAcquireCount += 1;
+ pPalCriticalSection->DebugInfo->lEnterCount += 1;
+ }
+#endif // _DEBUG
+
+ IECS_exit:
+ return;
+ }
+
+ /*++
+ Function:
+ CorUnix::InternalLeaveCriticalSection
+
+ Leaves a currently owned CS
+ --*/
+ void InternalLeaveCriticalSection(CPalThread * pThread,
+ PCRITICAL_SECTION pCriticalSection)
+ {
+ PAL_CRITICAL_SECTION * pPalCriticalSection =
+ reinterpret_cast<PAL_CRITICAL_SECTION*>(pCriticalSection);
+ LONG lVal, lNewVal;
+
+#ifdef _DEBUG
+ SIZE_T threadId;
+
+ _ASSERTE(PalCsNotInitialized != pPalCriticalSection->cisInitState);
+
+ threadId = ObtainCurrentThreadId(pThread);
+ _ASSERTE(threadId == pPalCriticalSection->OwningThread);
+#endif // _DEBUG
+
+ _ASSERT_MSG(PALCS_LOCK_BIT & pPalCriticalSection->LockCount,
+ "Trying to release an unlocked CS\n");
+ _ASSERT_MSG(0 < pPalCriticalSection->RecursionCount,
+ "Trying to release an unlocked CS\n");
+
+ if (--pPalCriticalSection->RecursionCount > 0)
+ {
+ // Recursion was > 1, still owning the CS
+ goto ILCS_cs_exit;
+ }
+
+ // Reset CS ownership
+ pPalCriticalSection->OwningThread = NULL;
+
+ // Load the current LockCount value
+ lVal = pPalCriticalSection->LockCount;
+
+ while (true)
+ {
+ _ASSERT_MSG(0 != (PALCS_LOCK_BIT & lVal),
+ "Trying to release an unlocked CS\n");
+
+ // NB: In the fair lock case (PALCS_TRANSFER_OWNERSHIP_ON_RELEASE) the
+ // PALCS_LOCK_AWAKENED_WAITER bit is not used
+ if ( (PALCS_LOCK_BIT == lVal)
+#ifndef PALCS_TRANSFER_OWNERSHIP_ON_RELEASE
+ || (PALCS_LOCK_AWAKENED_WAITER & lVal)
+#endif // !PALCS_TRANSFER_OWNERSHIP_ON_RELEASE
+ )
+ {
+ // Whether there are no waiters (PALCS_LOCK_BIT == lVal)
+ // or a waiter has already been awakened, therefore we
+ // just need to reset the lock bit and return
+ lNewVal = lVal & ~PALCS_LOCK_BIT;
+ CS_TRACE("[LCS-UN %p] Switching from {%d, %d, %d} to "
+ "{%d, %d, %d} ==>\n", pPalCriticalSection,
+ PALCS_GETWCOUNT(lVal), PALCS_GETAWBIT(lVal), PALCS_GETLBIT(lVal),
+ PALCS_GETWCOUNT(lNewVal), PALCS_GETAWBIT(lNewVal), PALCS_GETLBIT(lNewVal));
+
+ lNewVal = InterlockedCompareExchange(&pPalCriticalSection->LockCount,
+ lNewVal, lVal);
+
+ CS_TRACE("[LCS-UN %p] ==> %s\n", pPalCriticalSection,
+ (lNewVal == lVal) ? "OK" : "NO");
+
+ if (lNewVal == lVal)
+ {
+ goto ILCS_cs_exit;
+ }
+ }
+ else
+ {
+ // There is at least one waiter, we need to wake it up
+
+#ifdef PALCS_TRANSFER_OWNERSHIP_ON_RELEASE
+ // Fair lock case: passing ownership on to the first waiter.
+ // Here we need only to decrement the waiters count. CS will
+ // remain locked and ownership will be passed to the waiter,
+ // which will take care of setting ownership data as soon as
+ // it wakes up
+ lNewVal = lVal - PALCS_LOCK_WAITER_INC;
+#else // PALCS_TRANSFER_OWNERSHIP_ON_RELEASE
+ // Unfair lock case: we need to atomically decrement the waiters
+ // count (we are about ot wake up one of them), set the
+ // "waiter awakened" bit and to reset the "CS locked" bit.
+ // Note that, since we know that at this time PALCS_LOCK_BIT
+ // is set and PALCS_LOCK_AWAKENED_WAITER is not set, none of
+ // the addenda will affect bits other than its target bit(s),
+ // i.e. PALCS_LOCK_BIT will not affect PALCS_LOCK_AWAKENED_WAITER,
+ // PALCS_LOCK_AWAKENED_WAITER will not affect the actual
+ // count of waiters, and the latter will not change the two
+ // former ones
+ lNewVal = lVal - PALCS_LOCK_WAITER_INC +
+ PALCS_LOCK_AWAKENED_WAITER - PALCS_LOCK_BIT;
+#endif // PALCS_TRANSFER_OWNERSHIP_ON_RELEASE
+ CS_TRACE("[LCS-CN %p] Switching from {%d, %d, %d} to {%d, %d, %d} ==>\n",
+ pPalCriticalSection,
+ PALCS_GETWCOUNT(lVal), PALCS_GETAWBIT(lVal), PALCS_GETLBIT(lVal),
+ PALCS_GETWCOUNT(lNewVal), PALCS_GETAWBIT(lNewVal), PALCS_GETLBIT(lNewVal));
+
+ lNewVal = InterlockedCompareExchange(&pPalCriticalSection->LockCount,
+ lNewVal, lVal);
+
+ CS_TRACE("[LCS-CN %p] ==> %s\n", pPalCriticalSection,
+ (lNewVal == lVal) ? "OK" : "NO");
+
+ if (lNewVal == lVal)
+ {
+ // Wake up the waiter
+ PALCS_WakeUpWaiter (pPalCriticalSection);
+
+#ifdef PALCS_TRANSFER_OWNERSHIP_ON_RELEASE
+ // In the fair lock case, we need to yield here to defeat
+ // the inherently unfair nature of the condition/predicate
+ // construct
+ sched_yield();
+#endif // PALCS_TRANSFER_OWNERSHIP_ON_RELEASE
+
+ goto ILCS_cs_exit;
+ }
+ }
+
+ // CS unlock failed due to race with another thread trying to
+ // register as waiter on it. We need to keep on looping. We
+ // intentionally do not yield here in order to reserve higher
+ // priority for the releasing thread.
+ //
+ // At this point lNewVal contains the latest LockCount value
+ // retrieved by one of the two InterlockedCompareExchange above;
+ // we can use this value as expected LockCount for the next loop,
+ // without the need to fetch it again.
+ lVal = lNewVal;
+ }
+
+ ILCS_cs_exit:
+ return;
+ }
+
+ /*++
+ Function:
+ CorUnix::InternalTryEnterCriticalSection
+
+ Tries to acquire a CS. It returns true on success, false if the CS is
+ locked by another thread
+ --*/
+ bool InternalTryEnterCriticalSection(
+ CPalThread * pThread,
+ PCRITICAL_SECTION pCriticalSection)
+ {
+ PAL_CRITICAL_SECTION * pPalCriticalSection =
+ reinterpret_cast<PAL_CRITICAL_SECTION*>(pCriticalSection);
+
+ LONG lNewVal;
+ SIZE_T threadId;
+ bool fRet = true;
+
+ _ASSERTE(PalCsNotInitialized != pPalCriticalSection->cisInitState);
+
+ threadId = ObtainCurrentThreadId(pThread);
+
+ lNewVal = InterlockedCompareExchange (&pPalCriticalSection->LockCount,
+ (LONG)PALCS_LOCK_BIT,
+ (LONG)PALCS_LOCK_INIT);
+ if (lNewVal == PALCS_LOCK_INIT)
+ {
+ // CS successfully acquired: setting ownership data
+ pPalCriticalSection->OwningThread = threadId;
+ pPalCriticalSection->RecursionCount = 1;
+#ifdef _DEBUG
+ if (NULL != pPalCriticalSection->DebugInfo)
+ {
+ pPalCriticalSection->DebugInfo->lAcquireCount += 1;
+ pPalCriticalSection->DebugInfo->lEnterCount += 1;
+ }
+#endif // _DEBUG
+
+ goto ITECS_exit;
+ }
+
+ // check if the current thread already owns the criticalSection
+ if ((lNewVal & PALCS_LOCK_BIT) &&
+ (pPalCriticalSection->OwningThread == threadId))
+ {
+ pPalCriticalSection->RecursionCount += 1;
+#ifdef _DEBUG
+ if (NULL != pPalCriticalSection->DebugInfo)
+ {
+ pPalCriticalSection->DebugInfo->lEnterCount += 1;
+ }
+#endif // _DEBUG
+
+ goto ITECS_exit;
+ }
+
+ // Failed to acquire the CS
+ fRet = false;
+
+ ITECS_exit:
+ return fRet;
+ }
+#endif // MUTEX_BASED_CSS
+
+ /*++
+ Function:
+ CorUnix::PALCS_FullyInitialize
+
+ Fully initializes a CS previously initialied true InitializeCriticalSection.
+ This method is called at the first contention on the target CS
+ --*/
+ bool PALCS_FullyInitialize(PAL_CRITICAL_SECTION * pPalCriticalSection)
+ {
+ LONG lVal, lNewVal;
+ bool fRet = true;
+
+ lVal = pPalCriticalSection->cisInitState;
+ if (PalCsFullyInitialized == lVal)
+ {
+ goto PCDI_exit;
+ }
+ if (PalCsUserInitialized == lVal)
+ {
+ int iRet;
+ lNewVal = (LONG)PalCsFullyInitializing;
+ lNewVal = InterlockedCompareExchange(
+ (LONG *)&pPalCriticalSection->cisInitState, lNewVal, lVal);
+ if (lNewVal != lVal)
+ {
+ if (PalCsFullyInitialized == lNewVal)
+ {
+ // Another thread did initialize this CS: we can
+ // safely return 'true'
+ goto PCDI_exit;
+ }
+
+ // Another thread is still initializing this CS: yield and
+ // spin by returning 'false'
+ sched_yield();
+ fRet = false;
+ goto PCDI_exit;
+ }
+
+ //
+ // Actual native initialization
+ //
+ // Mutex
+ iRet = pthread_mutex_init(&pPalCriticalSection->csndNativeData.mutex, NULL);
+ if (0 != iRet)
+ {
+ ASSERT("Failed initializing mutex in CS @ %p [err=%d]\n",
+ pPalCriticalSection, iRet);
+ pPalCriticalSection->cisInitState = PalCsUserInitialized;
+ fRet = false;
+ goto PCDI_exit;
+ }
+#ifndef MUTEX_BASED_CSS
+ // Condition
+ iRet = pthread_cond_init(&pPalCriticalSection->csndNativeData.condition, NULL);
+ if (0 != iRet)
+ {
+ ASSERT("Failed initializing condition in CS @ %p [err=%d]\n",
+ pPalCriticalSection, iRet);
+ pthread_mutex_destroy(&pPalCriticalSection->csndNativeData.mutex);
+ pPalCriticalSection->cisInitState = PalCsUserInitialized;
+ fRet = false;
+ goto PCDI_exit;
+ }
+ // Predicate
+ pPalCriticalSection->csndNativeData.iPredicate = 0;
+#endif
+
+ pPalCriticalSection->cisInitState = PalCsFullyInitialized;
+ }
+ else if (PalCsFullyInitializing == lVal)
+ {
+ // Another thread is still initializing this CS: yield and
+ // spin by returning 'false'
+ sched_yield();
+ fRet = false;
+ goto PCDI_exit;
+ }
+ else
+ {
+ ASSERT("CS %p is not initialized", pPalCriticalSection);
+ fRet = false;
+ goto PCDI_exit;
+ }
+
+ PCDI_exit:
+ return fRet;
+ }
+
+
+ /*++
+ Function:
+ CorUnix::PALCS_WaitOnCS
+
+ Waits on a CS owned by anothr thread. It returns PalCsReturnWaiterAwakened
+ if the thread actually waited on the CS and it has been awakened on CS
+ release. It returns PalCsWaiterDidntWait if another thread is currently
+ fully-initializing the CS and therefore the current thread couldn't wait
+ on it
+ --*/
+ PalCsWaiterReturnState PALCS_WaitOnCS(PAL_CRITICAL_SECTION * pPalCriticalSection,
+ LONG lInc)
+ {
+ DWORD lVal, lNewVal;
+ PAL_ERROR palErr = NO_ERROR;
+
+ if (PalCsFullyInitialized != pPalCriticalSection->cisInitState)
+ {
+ // First contention, the CS native wait support need to be
+ // initialized at this time
+ if (!PALCS_FullyInitialize(pPalCriticalSection))
+ {
+ // The current thread failed the full initialization of the CS,
+ // whether because another thread is race-initializing it, or
+ // there are no enough memory/resources at this time, or
+ // InitializeCriticalSection has never been called. By
+ // returning we will cause the thread to spin on CS trying
+ // again until the CS is initialized
+ return PalCsWaiterDidntWait;
+ }
+ }
+
+ // Make sure we have a valid waiter increment
+ _ASSERTE(PALCS_LOCK_WAITER_INC == lInc ||
+ PALCS_LOCK_AWAKENED_WAITER == lInc);
+
+ do {
+ lVal = pPalCriticalSection->LockCount;
+
+ // Make sure the waiter increment is compatible with the
+ // awakened waiter bit value
+ _ASSERTE(PALCS_LOCK_WAITER_INC == lInc ||
+ PALCS_LOCK_AWAKENED_WAITER & lVal);
+
+ if (0 == (lVal & PALCS_LOCK_BIT))
+ {
+ // the CS is no longer locked, let's bail out
+ return PalCsWaiterDidntWait;
+ }
+
+ lNewVal = lVal + lInc;
+
+ // Make sure that this thread was whether an incoming one or it
+ // was an awakened waiter and, in this case, we are now going to
+ // turn off the awakened waiter bit
+ _ASSERT_MSG(PALCS_LOCK_WAITER_INC == lInc ||
+ 0 == (PALCS_LOCK_AWAKENED_WAITER & lNewVal));
+
+ CS_TRACE("[WCS %p] Switching from {%d, %d, %d} to "
+ "{%d, %d, %d} ==> ", pPalCriticalSection,
+ PALCS_GETWCOUNT(lVal), PALCS_GETAWBIT(lVal), PALCS_GETLBIT(lVal),
+ PALCS_GETWCOUNT(lNewVal), PALCS_GETAWBIT(lNewVal), PALCS_GETLBIT(lNewVal));
+
+ lNewVal = InterlockedCompareExchange (&pPalCriticalSection->LockCount,
+ lNewVal, lVal);
+
+ CS_TRACE("[WCS %p] ==> %s\n", pPalCriticalSection,
+ (lNewVal == lVal) ? "OK" : "NO");
+
+ } while (lNewVal != lVal);
+
+#ifdef _DEBUG
+ if (NULL != pPalCriticalSection->DebugInfo)
+ {
+ pPalCriticalSection->DebugInfo->lContentionCount += 1;
+ }
+#endif // _DEBUG
+
+ // Do the actual native wait
+ palErr = PALCS_DoActualWait(pPalCriticalSection);
+ _ASSERT_MSG(NO_ERROR == palErr, "Native CS wait failed\n");
+
+ return PalCsReturnWaiterAwakened;
+ }
+
+ /*++
+ Function:
+ CorUnix::PALCS_DoActualWait
+
+ Performs the actual native wait on the CS
+ --*/
+ PAL_ERROR PALCS_DoActualWait(PAL_CRITICAL_SECTION * pPalCriticalSection)
+ {
+ int iRet;
+ PAL_ERROR palErr = NO_ERROR;
+
+ CS_TRACE("Trying to go to sleep [CS=%p]\n", pPalCriticalSection);
+
+ // Lock the mutex
+ iRet = pthread_mutex_lock(&pPalCriticalSection->csndNativeData.mutex);
+ if (0 != iRet)
+ {
+ palErr = ERROR_INTERNAL_ERROR;
+ goto PCDAW_exit;
+ }
+
+ CS_TRACE("Actually Going to sleep [CS=%p]\n", pPalCriticalSection);
+
+ while (0 == pPalCriticalSection->csndNativeData.iPredicate)
+ {
+ // Wait on the condition
+ iRet = pthread_cond_wait(&pPalCriticalSection->csndNativeData.condition,
+ &pPalCriticalSection->csndNativeData.mutex);
+
+ CS_TRACE("Got a signal on condition [pred=%d]!\n",
+ pPalCriticalSection->csndNativeData.iPredicate);
+ if (0 != iRet)
+ {
+ // Failed: unlock the mutex and bail out
+ ASSERT("Failed waiting on condition in CS %p [err=%d]\n",
+ pPalCriticalSection, iRet);
+ pthread_mutex_unlock(&pPalCriticalSection->csndNativeData.mutex);
+ palErr = ERROR_INTERNAL_ERROR;
+ goto PCDAW_exit;
+ }
+ }
+
+ // Reset the predicate
+ pPalCriticalSection->csndNativeData.iPredicate = 0;
+
+ // Unlock the mutex
+ iRet = pthread_mutex_unlock(&pPalCriticalSection->csndNativeData.mutex);
+ if (0 != iRet)
+ {
+ palErr = ERROR_INTERNAL_ERROR;
+ goto PCDAW_exit;
+ }
+
+ PCDAW_exit:
+
+ CS_TRACE("Just woken up [CS=%p]\n", pPalCriticalSection);
+
+ return palErr;
+ }
+
+ /*++
+ Function:
+ CorUnix::PALCS_WakeUpWaiter
+
+ Wakes up the first thread waiting on the CS
+ --*/
+ PAL_ERROR PALCS_WakeUpWaiter(PAL_CRITICAL_SECTION * pPalCriticalSection)
+ {
+ int iRet;
+ PAL_ERROR palErr = NO_ERROR;
+
+ _ASSERT_MSG(PalCsFullyInitialized == pPalCriticalSection->cisInitState,
+ "Trying to wake up a waiter on CS not fully initialized\n");
+
+ // Lock the mutex
+ iRet = pthread_mutex_lock(&pPalCriticalSection->csndNativeData.mutex);
+ if (0 != iRet)
+ {
+ palErr = ERROR_INTERNAL_ERROR;
+ goto PCWUW_exit;
+ }
+
+ // Set the predicate
+ pPalCriticalSection->csndNativeData.iPredicate = 1;
+
+ CS_TRACE("Signaling condition/predicate [pred=%d]!\n",
+ pPalCriticalSection->csndNativeData.iPredicate);
+
+ // Signal the condition
+ iRet = pthread_cond_signal(&pPalCriticalSection->csndNativeData.condition);
+ if (0 != iRet)
+ {
+ // Failed: set palErr, but continue in order to unlock
+ // the mutex anyway
+ ASSERT("Failed setting condition in CS %p [ret=%d]\n",
+ pPalCriticalSection, iRet);
+ palErr = ERROR_INTERNAL_ERROR;
+ }
+
+ // Unlock the mutex
+ iRet = pthread_mutex_unlock(&pPalCriticalSection->csndNativeData.mutex);
+ if (0 != iRet)
+ {
+ palErr = ERROR_INTERNAL_ERROR;
+ goto PCWUW_exit;
+ }
+
+ PCWUW_exit:
+ return palErr;
+ }
+
+#ifdef _DEBUG
+ /*++
+ Function:
+ CorUnix::PALCS_ReportStatisticalData
+
+ Report creation/acquisition/contention statistical data for the all the
+ CSs so far existed and no longer existing in the current process
+ --*/
+ void PALCS_ReportStatisticalData()
+ {
+#ifdef PAL_TRACK_CRITICAL_SECTIONS_DATA
+ CPalThread * pThread = InternalGetCurrentThread();
+
+ if (NULL == pThread) DebugBreak();
+
+ // Take the lock for the global list of CS debug infos
+ InternalEnterCriticalSection(pThread, (CRITICAL_SECTION*)&g_csPALCSsListLock);
+
+ LONG lPALCSInitializeCount = g_lPALCSInitializeCount;
+ LONG lPALCSDeleteCount = g_lPALCSDeleteCount;
+ LONG lPALCSAcquireCount = g_lPALCSAcquireCount;
+ LONG lPALCSEnterCount = g_lPALCSEnterCount;
+ LONG lPALCSContentionCount = g_lPALCSContentionCount;
+ LONG lPALCSInternalInitializeCount = g_lPALCSInternalInitializeCount;
+ LONG lPALCSInternalDeleteCount = g_lPALCSInternalDeleteCount;
+ LONG lPALCSInternalAcquireCount = g_lPALCSInternalAcquireCount;
+ LONG lPALCSInternalEnterCount = g_lPALCSInternalEnterCount;
+ LONG lPALCSInternalContentionCount = g_lPALCSInternalContentionCount;
+
+ PLIST_ENTRY pItem = g_PALCSList.Flink;
+ while (&g_PALCSList != pItem)
+ {
+ PCRITICAL_SECTION_DEBUG_INFO pDebugInfo =
+ (PCRITICAL_SECTION_DEBUG_INFO)pItem;
+
+ if (pDebugInfo->pOwnerCS->fInternal)
+ {
+ lPALCSInternalAcquireCount += pDebugInfo->lAcquireCount;
+ lPALCSInternalEnterCount += pDebugInfo->lEnterCount;
+ lPALCSInternalContentionCount += pDebugInfo->lContentionCount;
+ }
+ else
+ {
+ lPALCSAcquireCount += pDebugInfo->lAcquireCount;
+ lPALCSEnterCount += pDebugInfo->lEnterCount;
+ lPALCSContentionCount += pDebugInfo->lContentionCount;
+ }
+
+ pItem = pItem->Flink;
+ }
+
+ // Release the lock for the global list of CS debug infos
+ InternalLeaveCriticalSection(pThread, (CRITICAL_SECTION*)&g_csPALCSsListLock);
+
+ TRACE("Critical Sections Statistical Data:\n");
+ TRACE("{\n");
+ TRACE(" Client code CSs:\n");
+ TRACE(" {\n");
+ TRACE(" Initialize Count: %d\n", lPALCSInitializeCount);
+ TRACE(" Delete Count: %d\n", lPALCSDeleteCount);
+ TRACE(" Acquire Count: %d\n", lPALCSAcquireCount);
+ TRACE(" Enter Count: %d\n", lPALCSEnterCount);
+ TRACE(" Contention Count: %d\n", lPALCSContentionCount);
+ TRACE(" }\n");
+ TRACE(" Internal PAL CSs:\n");
+ TRACE(" {\n");
+ TRACE(" Initialize Count: %d\n", lPALCSInternalInitializeCount);
+ TRACE(" Delete Count: %d\n", lPALCSInternalDeleteCount);
+ TRACE(" Acquire Count: %d\n", lPALCSInternalAcquireCount);
+ TRACE(" Enter Count: %d\n", lPALCSInternalEnterCount);
+ TRACE(" Contention Count: %d\n", lPALCSInternalContentionCount);
+ TRACE(" }\n");
+ TRACE("}\n");
+#endif // PAL_TRACK_CRITICAL_SECTIONS_DATA
+ }
+
+ /*++
+ Function:
+ CorUnix::PALCS_DumpCSList
+
+ Dumps the list of all the CS currently existing in this process.
+ --*/
+ void PALCS_DumpCSList()
+ {
+ CPalThread * pThread = InternalGetCurrentThread();
+
+ // Take the lock for the global list of CS debug infos
+ InternalEnterCriticalSection(pThread, (CRITICAL_SECTION*)&g_csPALCSsListLock);
+
+ PLIST_ENTRY pItem = g_PALCSList.Flink;
+ while (&g_PALCSList != pItem)
+ {
+ PCRITICAL_SECTION_DEBUG_INFO pDebugInfo =
+ (PCRITICAL_SECTION_DEBUG_INFO)pItem;
+ PPAL_CRITICAL_SECTION pCS = pDebugInfo->pOwnerCS;
+
+ printf("CS @ %p \n"
+ "{\tDebugInfo = %p -> \n",
+ pCS, pDebugInfo);
+
+ printf("\t{\n\t\t[Link]\n\t\tpOwnerCS = %p\n"
+ "\t\tAcquireCount \t= %d\n"
+ "\t\tEnterCount \t= %d\n"
+ "\t\tContentionCount = %d\n",
+ pDebugInfo->pOwnerCS, pDebugInfo->lAcquireCount.Load(),
+ pDebugInfo->lEnterCount.Load(), pDebugInfo->lContentionCount.Load());
+ printf("\t}\n");
+
+ printf("\tLockCount \t= %#x\n"
+ "\tRecursionCount \t= %d\n"
+ "\tOwningThread \t= %p\n"
+ "\tLockSemaphore \t= %p\n"
+ "\tSpinCount \t= %u\n"
+ "\tfInternal \t= %d\n"
+ "\teInitState \t= %u\n"
+ "\tpNativeData \t= %p ->\n",
+ pCS->LockCount.Load(), pCS->RecursionCount, (void *)pCS->OwningThread,
+ pCS->LockSemaphore, (unsigned)pCS->SpinCount, (int)pCS->fInternal,
+ pCS->cisInitState.Load(), &pCS->csndNativeData);
+
+ printf("\t{\n\t\t[mutex]\n\t\t[condition]\n"
+ "\t\tPredicate \t= %d\n"
+ "\t}\n}\n",pCS->csndNativeData.iPredicate);
+
+ printf("}\n");
+
+ pItem = pItem->Flink;
+ }
+
+ // Release the lock for the global list of CS debug infos
+ InternalLeaveCriticalSection(pThread, (CRITICAL_SECTION*)&g_csPALCSsListLock);
+ }
+#endif // _DEBUG
+
+
+#if defined(MUTEX_BASED_CSS) || defined(_DEBUG)
+ /*++
+ Function:
+ CorUnix::InternalEnterCriticalSection
+
+ Enters a CS, causing the thread to block if the CS is owned by
+ another thread
+ --*/
+#ifdef MUTEX_BASED_CSS
+ void InternalEnterCriticalSection(
+ CPalThread * pThread,
+ PCRITICAL_SECTION pCriticalSection)
+#else // MUTEX_BASED_CSS
+ void MTX_InternalEnterCriticalSection(
+ CPalThread * pThread,
+ PCRITICAL_SECTION pCriticalSection)
+#endif // MUTEX_BASED_CSS
+
+ {
+ PAL_CRITICAL_SECTION * pPalCriticalSection =
+ reinterpret_cast<PAL_CRITICAL_SECTION*>(pCriticalSection);
+ int iRet;
+ SIZE_T threadId;
+
+ _ASSERTE(PalCsNotInitialized != pPalCriticalSection->cisInitState);
+
+ threadId = ObtainCurrentThreadId(pThread);
+
+ /* check if the current thread already owns the criticalSection */
+ if (pPalCriticalSection->OwningThread == threadId)
+ {
+ _ASSERTE(0 < pPalCriticalSection->RecursionCount);
+ pPalCriticalSection->RecursionCount += 1;
+ return;
+ }
+
+ iRet = pthread_mutex_lock(&pPalCriticalSection->csndNativeData.mutex);
+ _ASSERTE(0 == iRet);
+
+ pPalCriticalSection->OwningThread = threadId;
+ pPalCriticalSection->RecursionCount = 1;
+ }
+
+
+ /*++
+ Function:
+ CorUnix::InternalLeaveCriticalSection
+
+ Leaves a currently owned CS
+ --*/
+#ifdef MUTEX_BASED_CSS
+ void InternalLeaveCriticalSection(
+ CPalThread * pThread,
+ PCRITICAL_SECTION pCriticalSection)
+#else // MUTEX_BASED_CSS
+ void MTX_InternalLeaveCriticalSection(
+ CPalThread * pThread,
+ PCRITICAL_SECTION pCriticalSection)
+#endif // MUTEX_BASED_CSS
+ {
+ PAL_CRITICAL_SECTION * pPalCriticalSection =
+ reinterpret_cast<PAL_CRITICAL_SECTION*>(pCriticalSection);
+ int iRet;
+#ifdef _DEBUG
+ SIZE_T threadId;
+
+ _ASSERTE(PalCsNotInitialized != pPalCriticalSection->cisInitState);
+
+ threadId = ObtainCurrentThreadId(pThread);
+ _ASSERTE(threadId == pPalCriticalSection->OwningThread);
+
+ if (0 >= pPalCriticalSection->RecursionCount)
+ DebugBreak();
+
+ _ASSERTE(0 < pPalCriticalSection->RecursionCount);
+#endif // _DEBUG
+
+ if (0 < --pPalCriticalSection->RecursionCount)
+ return;
+
+ pPalCriticalSection->OwningThread = 0;
+
+ iRet = pthread_mutex_unlock(&pPalCriticalSection->csndNativeData.mutex);
+ _ASSERTE(0 == iRet);
+ }
+
+ /*++
+ Function:
+ CorUnix::InternalTryEnterCriticalSection
+
+ Tries to acquire a CS. It returns true on success, false if the CS is
+ locked by another thread
+ --*/
+#ifdef MUTEX_BASED_CSS
+ bool InternalTryEnterCriticalSection(
+ CPalThread * pThread,
+ PCRITICAL_SECTION pCriticalSection)
+#else // MUTEX_BASED_CSS
+ bool MTX_InternalTryEnterCriticalSection(
+ CPalThread * pThread,
+ PCRITICAL_SECTION pCriticalSection)
+#endif // MUTEX_BASED_CSS
+ {
+ PAL_CRITICAL_SECTION * pPalCriticalSection =
+ reinterpret_cast<PAL_CRITICAL_SECTION*>(pCriticalSection);
+ bool fRet;
+ SIZE_T threadId;
+
+ _ASSERTE(PalCsNotInitialized != pPalCriticalSection->cisInitState);
+
+ threadId = ObtainCurrentThreadId(pThread);
+
+ /* check if the current thread already owns the criticalSection */
+ if (pPalCriticalSection->OwningThread == threadId)
+ {
+ pPalCriticalSection->RecursionCount += 1;
+ fRet = true;
+ goto ITECS_exit;
+ }
+
+ fRet = (0 == pthread_mutex_trylock(&pPalCriticalSection->csndNativeData.mutex));
+
+ if (fRet)
+ {
+ pPalCriticalSection->OwningThread = threadId;
+ pPalCriticalSection->RecursionCount = 1;
+ }
+
+ ITECS_exit:
+ return fRet;
+ }
+#endif // MUTEX_BASED_CSS || _DEBUG
+}
diff --git a/src/pal/src/synchmgr/synchcontrollers.cpp b/src/pal/src/synchmgr/synchcontrollers.cpp
new file mode 100644
index 0000000000..f7df5ea364
--- /dev/null
+++ b/src/pal/src/synchmgr/synchcontrollers.cpp
@@ -0,0 +1,1976 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ synchcontrollers.cpp
+
+Abstract:
+ Implementation of Synchronization Controllers and related objects
+
+
+
+--*/
+
+#include "pal/dbgmsg.h"
+
+SET_DEFAULT_DEBUG_CHANNEL(SYNC); // some headers have code with asserts, so do this first
+
+#include "synchmanager.hpp"
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <sched.h>
+#include <errno.h>
+#include <limits.h>
+
+namespace CorUnix
+{
+#ifdef SYNCH_STATISTICS
+ LONG g_rglStatWaitCount[ObjectTypeIdCount] = { 0 };
+ LONG g_rglStatContentionCount[ObjectTypeIdCount] = { 0 };
+#endif // SYNCH_STATISTICS
+ ////////////////////////////
+ // //
+ // CSynchControllerBase //
+ // //
+ ////////////////////////////
+
+ /*++
+ Method:
+ CSynchControllerBase::Init
+
+ Initializes a generic controller
+ --*/
+ PAL_ERROR CSynchControllerBase::Init(
+ CPalThread * pthrCurrent,
+ ControllerType ctCtrlrType,
+ ObjectDomain odObjectDomain,
+ CObjectType *potObjectType,
+ CSynchData * psdSynchData,
+ WaitDomain wdWaitDomain)
+ {
+ VALIDATEOBJECT(psdSynchData);
+
+ _ASSERTE(InternalGetCurrentThread() == pthrCurrent);
+
+ // Initialize internal controller data
+ m_pthrOwner = pthrCurrent;
+ m_ctCtrlrType = ctCtrlrType;
+ m_odObjectDomain = odObjectDomain;
+ m_potObjectType = potObjectType;
+ m_psdSynchData = psdSynchData;
+ m_wdWaitDomain = wdWaitDomain;
+
+ // Add reference to target synch data
+ m_psdSynchData->AddRef();
+
+ // Acquire lock implied by the controller
+ CPalSynchronizationManager::AcquireLocalSynchLock(m_pthrOwner);
+ if (LocalWait != m_wdWaitDomain)
+ {
+ CPalSynchronizationManager::AcquireSharedSynchLock(m_pthrOwner);
+ }
+
+ return NO_ERROR;
+ }
+
+ /*++
+ Method:
+ CSynchControllerBase::Release
+
+ Releases a generic controller a return it to the appropriate cache
+ --*/
+ void CSynchControllerBase::Release()
+ {
+ VALIDATEOBJECT(m_psdSynchData);
+
+#ifdef _DEBUG
+ ThreadWaitInfo * ptwiWaitInfo =
+ CPalSynchronizationManager::GetThreadWaitInfo(m_pthrOwner);
+#endif // _DEBUG
+
+ CPalSynchronizationManager * pSynchManager =
+ CPalSynchronizationManager::GetInstance();
+
+ _ASSERTE(InternalGetCurrentThread() == m_pthrOwner);
+ _ASSERTE(ptwiWaitInfo->pthrOwner == m_pthrOwner);
+
+ // Release reference to target synch data
+ m_psdSynchData->Release(m_pthrOwner);
+
+ // Release lock implied by the controller
+ if (LocalWait != m_wdWaitDomain)
+ {
+ CPalSynchronizationManager::ReleaseSharedSynchLock(m_pthrOwner);
+ }
+ CPalSynchronizationManager::ReleaseLocalSynchLock(m_pthrOwner);
+
+ // Return controller to the appropriate cache
+ if (WaitController == m_ctCtrlrType)
+ {
+ // The cast here must be static_cast and not reinterpet_cast.
+ // In fact in general static_cast<CSynchWaitController*>(this) is
+ // equal to this-sizeof(void*), given that CSynchWaitController
+ // has a virtual table, while CSynchControllerBase doesn't.
+ pSynchManager->CacheAddWaitCtrlr(m_pthrOwner,
+ static_cast<CSynchWaitController*>(this));
+ }
+ else
+ {
+ // The cast here must be static_cast and not reinterpet_cast
+ pSynchManager->CacheAddStateCtrlr(m_pthrOwner,
+ static_cast<CSynchStateController*>(this));
+ }
+ }
+
+ ////////////////////////////
+ // //
+ // CSynchWaitController //
+ // //
+ ////////////////////////////
+
+ /*++
+ Method:
+ CSynchWaitController::CanThreadWaitWithoutBlocking
+
+ Returns whether or not the thread owning this controller can
+ wait on the target object without blocking (i.e. the objet is
+ signaled)
+ --*/
+ PAL_ERROR CSynchWaitController::CanThreadWaitWithoutBlocking(
+ bool * pfCanWaitWithoutBlocking,
+ bool * pfAbandoned)
+ {
+ VALIDATEOBJECT(m_psdSynchData);
+
+ bool fRetVal = false;
+
+ _ASSERTE(InternalGetCurrentThread() == m_pthrOwner);
+ _ASSERTE(NULL != pfCanWaitWithoutBlocking);
+ _ASSERTE(NULL != pfAbandoned);
+
+ fRetVal = m_psdSynchData->CanWaiterWaitWithoutBlocking(m_pthrOwner, pfAbandoned);
+
+ if(!fRetVal && otiProcess == m_psdSynchData->GetObjectTypeId())
+ {
+ // Note: if the target object is a process, here we need to check
+ // whether or not it has already exited. In fact, since currently
+ // we do not monitor a process status as long as there is no
+ // thread waiting on it, in general if the process already exited
+ // the process object is likely not to be signaled yet, therefore
+ // the above CanWaiterWaitWithoutBlocking call probably returned
+ // false, and, without the check below, that would cause the
+ // current thread to eventually go to sleep for a short time
+ // (until the worker thread notifies that the waited process has
+ // indeed exited), while it would not be necessary.
+ // As side effect that would cause a WaitForSingleObject with zero
+ // timeout to always return WAIT_TIMEOUT, even though the target
+ // process already exited. WaitForSingleObject with zero timeout
+ // is a common way to probe whether or not a process has already
+ // exited, and it is supposed to return WAIT_OBJECT_0 if the
+ // process exited, and WAIT_TIMEOUT if it is still active.
+ // In order to support this feature we need to check at this time
+ // whether or not the process has already exited.
+
+ CProcProcessLocalData * pProcLocalData = GetProcessLocalData();
+ DWORD dwExitCode = 0;
+ bool fIsActualExitCode = false;
+
+ _ASSERT_MSG(NULL != pProcLocalData,
+ "Process synch data pointer is missing\n");
+
+ if (NULL != pProcLocalData &&
+ CPalSynchronizationManager::HasProcessExited(pProcLocalData->dwProcessId,
+ &dwExitCode,
+ &fIsActualExitCode))
+ {
+ TRACE("Process pid=%u exited with %s exitcode=%u\n",
+ pProcLocalData->dwProcessId,
+ fIsActualExitCode ? "actual" : "guessed",
+ dwExitCode);
+
+ // Store the exit code in the process local data
+ if (fIsActualExitCode)
+ {
+ pProcLocalData->dwExitCode = dwExitCode;
+ }
+
+ // Set process status to PS_DONE
+ pProcLocalData->ps = PS_DONE;
+
+ // Set signal count
+ m_psdSynchData->SetSignalCount(1);
+
+ // Releasing all local waiters
+ // (see comments in DoMonitorProcesses)
+ m_psdSynchData->ReleaseAllLocalWaiters(m_pthrOwner);
+
+ fRetVal = true;
+ }
+ }
+
+ *pfCanWaitWithoutBlocking = fRetVal;
+ return NO_ERROR;
+ }
+
+ /*++
+ Method:
+ CSynchWaitController::ReleaseWaitingThreadWithoutBlocking
+
+ Performs all the steps needed to be done by the controller's owner
+ thread in order to wait on the target object without blocking
+ (e.g. modifying the object signal count accordingly with its
+ thread release semantics)
+ This method should be called only after having received positive
+ response from CanThreadWaitWithoutBlocking called on the same
+ controller.
+ --*/
+ PAL_ERROR CSynchWaitController::ReleaseWaitingThreadWithoutBlocking()
+ {
+ VALIDATEOBJECT(m_psdSynchData);
+
+ PAL_ERROR palErr = NO_ERROR;
+
+ _ASSERTE(InternalGetCurrentThread() == m_pthrOwner);
+
+ palErr = m_psdSynchData->ReleaseWaiterWithoutBlocking(m_pthrOwner, m_pthrOwner);
+
+#ifdef SYNCH_STATISTICS
+ if (NO_ERROR == palErr)
+ {
+ m_psdSynchData->IncrementStatWaitCount();
+ }
+#endif
+ return palErr;
+ }
+
+ /*++
+ Method:
+ CSynchWaitController::RegisterWaitingThread
+
+ Registers the controller's owner thread for waiting on the target
+ object
+ --*/
+ PAL_ERROR CSynchWaitController::RegisterWaitingThread(
+ WaitType wtWaitType,
+ DWORD dwIndex,
+ bool fAlertable)
+ {
+ VALIDATEOBJECT(m_psdSynchData);
+
+ PAL_ERROR palErr = NO_ERROR;
+ WaitingThreadsListNode * pwtlnNewNode = NULL;
+ SharedID shridNewNode = NULLSharedID;
+ ThreadWaitInfo * ptwiWaitInfo;
+ DWORD * pdwWaitState;
+ bool fSharedObject = (SharedObject == m_odObjectDomain);
+ bool fEarlyDeath = false;
+ bool fSynchDataRefd = false;
+ CPalSynchronizationManager * pSynchManager =
+ CPalSynchronizationManager::GetInstance();
+
+ _ASSERTE(InternalGetCurrentThread() == m_pthrOwner);
+
+ ptwiWaitInfo = CPalSynchronizationManager::GetThreadWaitInfo(
+ m_pthrOwner);
+
+ _ASSERTE(ptwiWaitInfo->pthrOwner == m_pthrOwner);
+
+ pdwWaitState = SharedIDToTypePointer(DWORD,
+ m_pthrOwner->synchronizationInfo.m_shridWaitAwakened);
+
+ if (fSharedObject)
+ {
+ shridNewNode = pSynchManager->CacheGetSharedWTListNode(m_pthrOwner);
+ pwtlnNewNode = SharedIDToTypePointer(WaitingThreadsListNode, shridNewNode);
+ }
+ else
+ {
+ pwtlnNewNode = pSynchManager->CacheGetLocalWTListNode(m_pthrOwner);
+ }
+
+ if (!pwtlnNewNode)
+ {
+ if (fSharedObject && (NULLSharedID != shridNewNode))
+ {
+ ASSERT("Bad Shared Memory ptr %p\n", shridNewNode);
+ palErr = ERROR_INTERNAL_ERROR;
+ }
+ else
+ {
+ ERROR("Out of memory\n");
+ palErr = ERROR_NOT_ENOUGH_MEMORY;
+ }
+ goto RWT_exit;
+ }
+
+ if (ptwiWaitInfo->lObjCount >= MAXIMUM_WAIT_OBJECTS)
+ {
+ ASSERT("Too many objects");
+ palErr = ERROR_INTERNAL_ERROR;
+ goto RWT_exit;
+ }
+
+ if (0 == ptwiWaitInfo->lObjCount)
+ {
+ ptwiWaitInfo->wtWaitType = wtWaitType;
+ ptwiWaitInfo->wdWaitDomain = m_wdWaitDomain;
+ }
+ else
+ {
+ _ASSERT_MSG(wtWaitType == ptwiWaitInfo->wtWaitType,
+ "Conflicting wait types in wait registration\n");
+
+ if (m_wdWaitDomain != ptwiWaitInfo->wdWaitDomain)
+ {
+ ptwiWaitInfo->wdWaitDomain = MixedWait;
+ }
+ }
+
+ pwtlnNewNode->shridSHRThis = NULLSharedID;
+ pwtlnNewNode->ptwiWaitInfo = ptwiWaitInfo;
+ pwtlnNewNode->dwObjIndex = dwIndex;
+ pwtlnNewNode->dwProcessId = gPID;
+ pwtlnNewNode->dwThreadId = m_pthrOwner->GetThreadId();
+ pwtlnNewNode->dwFlags = (MultipleObjectsWaitAll == wtWaitType) ?
+ WTLN_FLAG_WAIT_ALL : 0;
+ pwtlnNewNode->shridWaitingState = m_pthrOwner->synchronizationInfo.m_shridWaitAwakened;
+ if (fSharedObject)
+ {
+ pwtlnNewNode->dwFlags |= WTLN_FLAG_OWNER_OBJECT_IS_SHARED;
+ pwtlnNewNode->shridSHRThis = shridNewNode;
+ pwtlnNewNode->ptrOwnerObjSynchData.shrid = m_psdSynchData->GetSharedThis();
+ }
+ else
+ {
+ pwtlnNewNode->ptrOwnerObjSynchData.ptr = m_psdSynchData;
+ }
+
+ // AddRef the synch data (will be released in UnregisterWait)
+ m_psdSynchData->AddRef();
+ fSynchDataRefd = true;
+
+ ptwiWaitInfo->rgpWTLNodes[ptwiWaitInfo->lObjCount] = pwtlnNewNode;
+
+ if(otiProcess == m_psdSynchData->GetObjectTypeId())
+ {
+ CProcProcessLocalData * pProcLocalData = GetProcessLocalData();
+
+ if (NULL == pProcLocalData)
+ {
+ // Process local data pointer not set in the controller.
+ // This pointer is set in CSynchWaitController only when the
+ // wait controller for the object is created by calling
+ // GetSynchWaitControllersForObjects
+ ASSERT("Process synch data pointer is missing\n");
+ palErr = ERROR_INTERNAL_ERROR;
+ goto RWT_exit;
+ }
+
+ palErr = pSynchManager->RegisterProcessForMonitoring(m_pthrOwner,
+ m_psdSynchData,
+ m_pProcessObject,
+ pProcLocalData);
+ if (NO_ERROR != palErr)
+ {
+ goto RWT_exit;
+ }
+ }
+
+ if (0 == ptwiWaitInfo->lObjCount)
+ {
+ DWORD dwWaitState;
+
+ // Setting the thread in wait state
+ dwWaitState = (DWORD)(fAlertable ? TWS_ALERTABLE: TWS_WAITING);
+
+ TRACE("Switching my wait state [%p] from TWS_ACTIVE to %u \n",
+ pdwWaitState, dwWaitState);
+
+ dwWaitState = InterlockedCompareExchange(
+ (LONG *)pdwWaitState, (LONG)dwWaitState, TWS_ACTIVE);
+ if ((DWORD)TWS_ACTIVE != dwWaitState)
+ {
+ if ((DWORD)TWS_EARLYDEATH == dwWaitState)
+ {
+ // Process is terminating, this thread will soon be
+ // suspended (by SuspendOtherThreads).
+ WARN("Thread is about to get suspended by "
+ "TerminateProcess\n");
+
+ fEarlyDeath = true;
+ palErr = WAIT_FAILED;
+ }
+ else
+ {
+ ASSERT("Unexpected thread wait state %d\n", dwWaitState);
+ palErr = ERROR_INTERNAL_ERROR;
+ }
+ goto RWT_exit;
+ }
+ }
+
+ // Add new node to queue
+ if (fSharedObject)
+ {
+ m_psdSynchData->SharedWaiterEnqueue(shridNewNode);
+ ptwiWaitInfo->lSharedObjCount += 1;
+ }
+ else
+ {
+ m_psdSynchData->WaiterEnqueue(pwtlnNewNode);
+ }
+
+ // Succeeded: update object count
+ ptwiWaitInfo->lObjCount++;
+
+ RWT_exit:
+ if (palErr != NO_ERROR)
+ {
+ // Unregister any partial wait registration
+ pSynchManager->UnRegisterWait(m_pthrOwner, ptwiWaitInfo, fSharedObject);
+
+ if (fSynchDataRefd)
+ {
+ m_psdSynchData->Release(m_pthrOwner);
+ }
+ if ((fSharedObject) && (NULLSharedID != shridNewNode))
+ {
+ pSynchManager->CacheAddSharedWTListNode(m_pthrOwner, shridNewNode);
+ }
+ else if (NULL != pwtlnNewNode)
+ {
+ pSynchManager->CacheAddLocalWTListNode(m_pthrOwner, pwtlnNewNode);
+ }
+
+ if (fEarlyDeath)
+ {
+ // Early death detected, i.e. the process is about to exit.
+ // We need to completely release the synch lock(s) before
+ // going to sleep
+ LONG lLocalSynchLockCount;
+ LONG lSharedSynchLockCount;
+
+ lSharedSynchLockCount = CPalSynchronizationManager::ResetSharedSynchLock(m_pthrOwner);
+ lLocalSynchLockCount = CPalSynchronizationManager::ResetLocalSynchLock(m_pthrOwner);
+
+ _ASSERTE(0 < lLocalSynchLockCount);
+
+ // Sleep for ever
+ CPalSynchronizationManager::ThreadPrepareForShutdown();
+ }
+ }
+#ifdef SYNCH_STATISTICS
+ else
+ {
+ m_psdSynchData->IncrementStatWaitCount();
+ m_psdSynchData->IncrementStatContentionCount();
+ }
+#endif
+ return palErr;
+ }
+
+ /*++
+ Method:
+ CSynchWaitController::ReleaseController
+
+ Releases the current controller
+ --*/
+ void CSynchWaitController::ReleaseController()
+ {
+ VALIDATEOBJECT(m_psdSynchData);
+
+ _ASSERTE(InternalGetCurrentThread() == m_pthrOwner);
+
+ Release();
+ }
+
+ /*++
+ Method:
+ CSynchWaitController::GetProcessLocalData
+
+ Accessor Get method for process local data of the target object
+ --*/
+ CProcProcessLocalData * CSynchWaitController::GetProcessLocalData()
+ {
+ VALIDATEOBJECT(m_psdSynchData);
+
+ _ASSERTE(InternalGetCurrentThread() == m_pthrOwner);
+ _ASSERT_MSG(NULL != m_pProcLocalData,
+ "Pointer to process local data not yet initialized\n");
+
+ return m_pProcLocalData;
+ }
+
+ /*++
+ Method:
+ CSynchWaitController::SetProcessData
+
+ Accessor Set method for process local data of the target object
+ --*/
+ void CSynchWaitController::SetProcessData(IPalObject* pProcessObject, CProcProcessLocalData * pProcLocalData)
+ {
+ VALIDATEOBJECT(m_psdSynchData);
+
+ _ASSERTE(InternalGetCurrentThread() == m_pthrOwner);
+ _ASSERT_MSG(m_pProcessObject == nullptr, "SetProcessData should not be called more than once");
+ _ASSERT_MSG(pProcessObject != nullptr && pProcessObject->GetObjectType()->GetId() == otiProcess, "Invalid process object passed to SetProcessData");
+
+ m_pProcessObject = pProcessObject;
+ m_pProcLocalData = pProcLocalData;
+ }
+
+ /////////////////////////////
+ // //
+ // CSynchStateController //
+ // //
+ /////////////////////////////
+
+ /*++
+ Method:
+ CSynchStateController::GetSignalCount
+
+ Returns the current signal count of the target object
+ --*/
+ PAL_ERROR CSynchStateController::GetSignalCount(LONG *plSignalCount)
+ {
+ VALIDATEOBJECT(m_psdSynchData);
+
+ PAL_ERROR palErr = NO_ERROR;
+ LONG lCount = m_psdSynchData->GetSignalCount();
+
+ _ASSERTE(InternalGetCurrentThread() == m_pthrOwner);
+ _ASSERTE(NULL != plSignalCount);
+ _ASSERT_MSG(0 <= lCount,
+ "Internal error: negative signal count [signal count=%d]",
+ lCount);
+
+ *plSignalCount = lCount;
+ return palErr;
+ }
+
+ /*++
+ Method:
+ CSynchStateController::SetSignalCount
+
+ Sets the signal count of the target object, possibly triggering
+ waiting threads awakening.
+ --*/
+ PAL_ERROR CSynchStateController::SetSignalCount(LONG lNewCount)
+ {
+ VALIDATEOBJECT(m_psdSynchData);
+
+ _ASSERTE(InternalGetCurrentThread() == m_pthrOwner);
+ _ASSERTE(lNewCount >= 0);
+
+ m_psdSynchData->Signal(m_pthrOwner, lNewCount, false);
+
+ return NO_ERROR;
+ }
+
+ /*++
+ Method:
+ CSynchStateController::IncrementSignalCount
+
+ Increments the signal count of the target object, possibly triggering
+ waiting threads awakening.
+ --*/
+ PAL_ERROR CSynchStateController::IncrementSignalCount(
+ LONG lAmountToIncrement)
+ {
+ VALIDATEOBJECT(m_psdSynchData);
+
+ _ASSERTE(InternalGetCurrentThread() == m_pthrOwner);
+ _ASSERTE(lAmountToIncrement > 0);
+
+ LONG lOldCount = m_psdSynchData->GetSignalCount();
+ LONG lNewCount = lOldCount + lAmountToIncrement;
+
+ _ASSERT_MSG(lNewCount > lOldCount,
+ "Signal count increment %d would make current signal count %d to "
+ "wrap around\n", lAmountToIncrement, lOldCount);
+
+ m_psdSynchData->Signal(m_pthrOwner, lNewCount, false);
+
+ return NO_ERROR;
+ }
+
+ /*++
+ Method:
+ CSynchStateController::DecrementSignalCount
+
+ Decrements the signal count of the target object.
+ --*/
+ PAL_ERROR CSynchStateController::DecrementSignalCount(
+ LONG lAmountToDecrement)
+ {
+ VALIDATEOBJECT(m_psdSynchData);
+
+ _ASSERTE(InternalGetCurrentThread() == m_pthrOwner);
+ _ASSERTE(lAmountToDecrement > 0);
+
+ PAL_ERROR palErr = NO_ERROR;
+ LONG lCount = m_psdSynchData->GetSignalCount();
+ _ASSERTE(lAmountToDecrement <= lCount);
+
+ m_psdSynchData->SetSignalCount(lCount - lAmountToDecrement);
+
+ return palErr;
+ }
+
+ /*++
+ Method:
+ CSynchStateController::SetOwner
+
+ Sets the owner of the target object and initializes the ownership
+ count to 1 (for objects with tracked ownership).
+ --*/
+ PAL_ERROR CSynchStateController::SetOwner(CPalThread * pNewOwningThread)
+ {
+ VALIDATEOBJECT(m_psdSynchData);
+
+ PAL_ERROR palErr = NO_ERROR;
+
+ _ASSERTE(InternalGetCurrentThread() == m_pthrOwner);
+ _ASSERTE(NULL != pNewOwningThread);
+ _ASSERT_MSG(CObjectType::OwnershipTracked ==
+ m_potObjectType->GetOwnershipSemantics(),
+ "SetOwner called on an object without OwnershipTracked "
+ "semantics\n");
+
+ if (0 != m_psdSynchData->GetOwnershipCount())
+ {
+ ASSERT("Ownership count should be zero at this time\n");
+ palErr = ERROR_INTERNAL_ERROR;
+ goto SO_exit;
+ }
+
+ palErr = m_psdSynchData->AssignOwnershipToThread(m_pthrOwner,
+ pNewOwningThread);
+
+ _ASSERT_MSG(0 == m_psdSynchData->GetOwnershipCount() ||
+ 0 == m_psdSynchData->GetSignalCount(),
+ "Conflicting values for SignalCount [%d] and "
+ "OwnershipCount [%d]\n",
+ m_psdSynchData->GetOwnershipCount(),
+ m_psdSynchData->GetSignalCount());
+
+ SO_exit:
+ return palErr;
+ }
+
+ /*++
+ Method:
+ CSynchStateController::DecrementOwnershipCount
+
+ Decrements the ownership count of the target object possibly triggering
+ waiting threads awakening (for objects with tracked ownership).
+ --*/
+ PAL_ERROR CSynchStateController::DecrementOwnershipCount()
+ {
+ VALIDATEOBJECT(m_psdSynchData);
+
+ PAL_ERROR palErr = NO_ERROR;
+ LONG lOwnershipCount = m_psdSynchData->GetOwnershipCount();
+
+ _ASSERTE(InternalGetCurrentThread() == m_pthrOwner);
+ _ASSERT_MSG(CObjectType::OwnershipTracked ==
+ m_potObjectType->GetOwnershipSemantics(),
+ "Trying to decrement ownership count on an object with "
+ "ownership semantics other than OwnershipTracked\n");
+ _ASSERT_MSG(0 <= lOwnershipCount,
+ "Operation would make ownership count negative - object "
+ "should be owned at this time [ownership count=%d]\n",
+ lOwnershipCount);
+
+ if ( (1 > lOwnershipCount) ||
+ (m_psdSynchData->GetOwnerProcessID() != gPID) ||
+ (m_psdSynchData->GetOwnerThread() != m_pthrOwner) )
+ {
+ palErr = ERROR_NOT_OWNER;
+ goto DOC_exit;
+ }
+
+ lOwnershipCount--;
+ m_psdSynchData->SetOwnershipCount(lOwnershipCount);
+
+ if (0 == lOwnershipCount)
+ {
+ CPalSynchronizationManager * pSynchManager =
+ CPalSynchronizationManager::GetInstance();
+ OwnedObjectsListNode * pooln =
+ m_psdSynchData->GetOwnershipListNode();
+
+ _ASSERT_MSG(NULL != pooln,
+ "Null ownership node pointer in SynchData with ownership "
+ "semantics\n");
+ _ASSERT_MSG(m_psdSynchData == pooln->pPalObjSynchData,
+ "Corrupted ownership node\n");
+
+ // Object has been released
+ // Remove it from list of owned objs for current thread
+ m_pthrOwner->synchronizationInfo.RemoveObjectFromOwnedList(pooln);
+
+ // Release SynchData reference count implied by the ownership
+ // list node
+ m_psdSynchData->Release(m_pthrOwner);
+
+ // Return node to the cache
+ pSynchManager->CacheAddOwnedObjsListNode(m_pthrOwner, pooln);
+
+ // Reset ownership
+ m_psdSynchData->ResetOwnership();
+
+ // Signal it and trigger waiter thread awakening
+ m_psdSynchData->Signal(m_pthrOwner, 1, false);
+ }
+
+ DOC_exit:
+ return palErr;
+ }
+
+ /*++
+ Method:
+ CSynchStateController::ReleaseController
+
+ Releases the controller.
+ --*/
+ void CSynchStateController::ReleaseController(void)
+ {
+ VALIDATEOBJECT(m_psdSynchData);
+
+ _ASSERTE(InternalGetCurrentThread() == m_pthrOwner);
+
+ Release();
+ }
+
+ //////////////////
+ // //
+ // CSynchData //
+ // //
+ //////////////////
+
+ /*++
+ Method:
+ CSynchData::Release
+
+ Decremnt the reference count of the target synchdata and retrurns
+ it to the appropriate cache if the reference count reaches zero.
+ --*/
+ LONG CSynchData::Release(CPalThread * pthrCurrent)
+ {
+ VALIDATEOBJECT(this);
+
+ LONG lCount = InterlockedDecrement(&m_lRefCount);
+
+ _ASSERT_MSG(0 <= lCount,
+ "CSynchData %p with negative reference count [%d]\n",
+ this, lCount);
+
+ if (0 == lCount)
+ {
+ CPalSynchronizationManager * pSynchManager =
+ CPalSynchronizationManager::GetInstance();
+ bool fSharedObject = (SharedObject == m_odObjectDomain);
+
+ _ASSERT_MSG((fSharedObject && (NULLSharedID == m_ptrWTLHead.shrid)) ||
+ (!fSharedObject && (NULL == m_ptrWTLHead.ptr)),
+ "Final Release on CSynchData with threads still in "
+ "the waiting list\n");
+
+ TRACE("Disposing %s waitable object with SynchData @ "
+ "{shrid=%p, p=%p}\n",
+ (SharedObject == m_odObjectDomain) ? "shared" : "local",
+ (PVOID)m_shridThis, this);
+
+
+#ifdef SYNCH_STATISTICS
+ LONG lStatWaitCount = GetStatWaitCount();
+ LONG lStatContentionCount = GetStatContentionCount();
+ LONG lCount, lNewCount;
+
+ TRACE("Statistical data for SynchData of otiType=%u @ %p: WaitCount=%d "
+ "ContentionCount=%d\n", m_otiObjectTypeId, this, lStatWaitCount,
+ lStatContentionCount);
+
+ do {
+ lCount = g_rglStatWaitCount[m_otiObjectTypeId];
+ lNewCount = lCount + lStatWaitCount;
+ lNewCount = InterlockedCompareExchange(&(g_rglStatWaitCount[m_otiObjectTypeId]),
+ lNewCount, lCount);
+ } while (lCount != lNewCount);
+
+ lStatWaitCount = lNewCount;
+
+ do {
+ lCount = g_rglStatContentionCount[m_otiObjectTypeId];
+ lNewCount = lCount + lStatContentionCount;
+ lNewCount = InterlockedCompareExchange(&(g_rglStatContentionCount[m_otiObjectTypeId]),
+ lNewCount, lCount);
+ } while (lCount != lNewCount);
+
+ lStatContentionCount = lNewCount;
+
+ TRACE("Total current statistical data for otiType=%u objects: WaitCount=%d "
+ "ContentionCount=%d\n", m_otiObjectTypeId, lStatWaitCount,
+ lStatContentionCount);
+#endif // SYNCH_STATISTICS
+
+ if (fSharedObject)
+ {
+ pSynchManager->CacheAddSharedSynchData(pthrCurrent, m_shridThis);
+ }
+ else
+ {
+ pSynchManager->CacheAddLocalSynchData(pthrCurrent, this);
+ }
+ }
+
+ return lCount;
+ }
+
+ /*++
+ Method:
+ CSynchData::ReleaseWaiterWithoutBlocking
+
+ Performs all the steps needed to be done by the target thread in order
+ to wait without blocking on the object associated with the current
+ SynchData (e.g. modifying the object signal count accordingly with its
+ thread release semantics)
+
+ Note: this method must be called while holding the appropriate
+ synchronization locks (the local process synch lock if the target
+ object is local, both local and shared one if the object is shared).
+ --*/
+ PAL_ERROR CSynchData::ReleaseWaiterWithoutBlocking(
+ CPalThread * pthrCurrent,
+ CPalThread * pthrTarget)
+ {
+ VALIDATEOBJECT(this);
+
+ PAL_ERROR palErr = NO_ERROR;
+ CObjectType * potObjectType = GetObjectType();
+#ifdef _DEBUG
+ CObjectType::SignalingSemantics ssSignalingSemantics =
+ potObjectType->GetSignalingSemantics();
+#endif // _DEBUG
+ CObjectType::OwnershipSemantics osOwnershipSemantics =
+ potObjectType->GetOwnershipSemantics();
+ CObjectType::ThreadReleaseSemantics trsThreadReleaseSemantics =
+ potObjectType->GetThreadReleaseSemantics();
+ bool fReenteringObjWithOwnership = false;
+
+ _ASSERT_MSG(CObjectType::SignalingNotApplicable != ssSignalingSemantics,
+ "Signaling not applicable");
+ _ASSERT_MSG(CObjectType::ThreadReleaseNotApplicable !=
+ trsThreadReleaseSemantics,
+ "Thread releasing not applicable");
+ _ASSERT_MSG(CObjectType::SingleTransitionObject != ssSignalingSemantics ||
+ (CObjectType::ThreadReleaseHasNoSideEffects ==
+ trsThreadReleaseSemantics &&
+ CObjectType::NoOwner == osOwnershipSemantics),
+ "Conflicting object synchronization attributes "
+ "[SignalingSemantics=%u OwnershipSemantics=%u "
+ "ThreadReleaseSemantics=%u]\n", ssSignalingSemantics,
+ osOwnershipSemantics, trsThreadReleaseSemantics);
+
+ if (CObjectType::OwnershipTracked == osOwnershipSemantics &&
+ 0 < GetOwnershipCount())
+ {
+ // We are rentering an object with ownership: we need to skip
+ // the object unsignaling
+ fReenteringObjWithOwnership = true;
+ }
+
+ if (!fReenteringObjWithOwnership &&
+ CObjectType::ThreadReleaseAltersSignalCount == trsThreadReleaseSemantics)
+ {
+ _ASSERT_MSG(0 < GetSignalCount(),
+ "Internal error: operation would make signal count "
+ "negative - object should be signaled at this time "
+ "[signal count=%d]", GetSignalCount());
+ _ASSERT_MSG(CObjectType::OwnershipTracked != osOwnershipSemantics ||
+ 1 == GetSignalCount(),
+ "Ownable objects cannot have signal count greater "
+ "than zero [current SignalCount=%d]\n",
+ GetSignalCount());
+
+ // Unsignal the object
+ DecrementSignalCount();
+ }
+
+ if (CObjectType::OwnershipTracked == osOwnershipSemantics)
+ {
+ _ASSERT_MSG(0 == GetOwnershipCount() || 0 == GetSignalCount(),
+ "OwnershipCount and SignalCount with conflicting "
+ "values\n");
+
+ // Take ownership or increment ownership count.
+ // We do this after the object unsignaling to minimize possibilities
+ // of having both SignalCount and OwnershipCount greater than zero
+ // (see comment in AssignOwnershipToThread)
+ palErr = AssignOwnershipToThread(pthrCurrent, pthrTarget);
+
+ if (NO_ERROR != palErr)
+ {
+ ERROR("AssignOwnershipToThread failed with error %u; "
+ "ownership data on object with SynchData {shrid=%p p=%p} "
+ "may be corrupted\n", palErr, (void *)m_shridThis, this);
+ }
+ }
+
+#ifdef SYNCH_STATISTICS
+ if (NO_ERROR == palErr)
+ {
+ IncrementStatWaitCount();
+ }
+#endif
+ return palErr;
+
+ }
+
+ /*++
+ Method:
+ CSynchData::CanWaiterWaitWithoutBlocking
+
+ Returns whether or not the waiter thread can wait on the target object
+ without blocking (i.e. the objet is signaled)
+
+ Note: this method must be called while holding the appropriate
+ synchronization locks (the local process synch lock if the target
+ object is local, both local and shared one if the object is shared).
+ --*/
+ bool CSynchData::CanWaiterWaitWithoutBlocking(
+ CPalThread * pWaiterThread,
+ bool * pfAbandoned)
+ {
+ VALIDATEOBJECT(this);
+
+ bool fRetVal = (0 < GetSignalCount());
+ bool fAbandoned = false;
+ bool fOwnershipTracked = (CObjectType::OwnershipTracked ==
+ GetObjectType()->GetOwnershipSemantics());
+ if (fRetVal)
+ {
+ // Object signaled: thread can wait without blocking
+ if (fOwnershipTracked)
+ {
+ fAbandoned = IsAbandoned();
+ }
+
+ goto CWWWB_exit;
+ }
+
+ // Object not signaled: thread can wait without blocking only if the
+ // object is an ownable one, and it is owned by the current thread
+ if (fOwnershipTracked)
+ {
+ _ASSERT_MSG(0 < GetSignalCount() || 0 < GetOwnershipCount(),
+ "Objects with ownership must be either signaled or "
+ "owned by a thread\n");
+
+ if ((GetOwnerProcessID() == gPID) &&
+ (GetOwnerThread() == pWaiterThread) )
+ {
+ fRetVal = true;
+ goto CWWWB_exit;
+ }
+ }
+
+ CWWWB_exit:
+ *pfAbandoned = fAbandoned;
+ return fRetVal;
+ }
+
+ /*++
+ Method:
+ CSynchData::Signal
+
+ Sets the signal count of the object owning the target SynchData,
+ possibly triggering awakening of waiting threads.
+
+ Note: this method must be called while holding the appropriate
+ synchronization locks (the local process synch lock if the target
+ object is local, both local and shared one if the object is shared).
+ --*/
+ void CSynchData::Signal(
+ CPalThread * pthrCurrent,
+ LONG lSignalCount,
+ bool fWorkerThread)
+ {
+ VALIDATEOBJECT(this);
+
+ bool fThreadReleased = false;
+ bool fDelegatedSignaling = false;
+ bool fReleaseAltersSignalCount =
+ (CObjectType::ThreadReleaseAltersSignalCount ==
+ GetObjectType()->GetThreadReleaseSemantics());
+
+ _ASSERTE(0 <= lSignalCount);
+
+ // Preset the signal count to the new value, so that it can be used
+ // by ReleaseFirstWaiter when delegating signaling to another process
+ m_lSignalCount = lSignalCount;
+
+ while (m_lSignalCount > 0)
+ {
+ fThreadReleased = ReleaseFirstWaiter(pthrCurrent,
+ &fDelegatedSignaling,
+ fWorkerThread);
+ if (!fThreadReleased)
+ {
+ // No more threads to release: break out of the loop
+ // keeping the current signal count
+ break;
+ }
+ if (fReleaseAltersSignalCount)
+ {
+ // Adjust signal count
+ m_lSignalCount--;
+ }
+ if (fDelegatedSignaling)
+ {
+ // Object signaling has been delegated
+ m_lSignalCount = 0;
+ }
+ }
+
+ _ASSERT_MSG(CObjectType::OwnershipTracked !=
+ GetObjectType()->GetOwnershipSemantics() ||
+ 0 == GetOwnershipCount() || 0 == GetSignalCount(),
+ "Conflicting values for SignalCount [%d] and "
+ "OwnershipCount [%d]\n",
+ GetOwnershipCount(), GetSignalCount());
+
+ _ASSERT_MSG(otiMutex != m_otiObjectTypeId || m_lSignalCount <= 1,
+ "Mutex with invalid singal count\n");
+
+ return;
+ }
+
+ /*++
+ Method:
+ CSynchData::ReleaseFirstWaiter
+
+ Releases the first thread from the front of the list of waiting threads
+ whose wait is fully satisfied, possibly triggering remote awakening (if
+ the target thread lives in a different process) or object signaling
+ delegation (if the target thread lives in a different processing and it
+ is blocked on a wait-all).
+
+ Note: this method must be called while holding the appropriate
+ synchronization locks (the local process synch lock if the target
+ object is local, both local and shared one if the object is shared).
+ --*/
+ bool CSynchData::ReleaseFirstWaiter(
+ CPalThread * pthrCurrent,
+ bool * pfDelegated,
+ bool fWorkerThread)
+ {
+ PAL_ERROR palErr = NO_ERROR;
+ bool fSharedSynchLock = false;
+ bool fSharedObject = (SharedObject == GetObjectDomain());
+ bool fThreadAwakened = false;
+ bool fDelegatedSignaling = false;
+ DWORD * pdwWaitState;
+ DWORD dwObjIdx;
+ SharedID shridItem = NULLSharedID, shridNextItem = NULLSharedID;
+ WaitingThreadsListNode * pwtlnItem, * pwtlnNextItem;
+ DWORD dwPid = gPID;
+ CPalSynchronizationManager * pSynchManager =
+ CPalSynchronizationManager::GetInstance();
+
+ VALIDATEOBJECT(this);
+
+ *pfDelegated = false;
+
+ if (fSharedObject)
+ {
+ shridItem = GetWTLHeadShmPtr();
+ pwtlnItem = SharedIDToTypePointer(WaitingThreadsListNode, shridItem);
+ }
+ else
+ {
+ pwtlnItem = GetWTLHeadPtr();
+ }
+
+ while (pwtlnItem)
+ {
+ VALIDATEOBJECT(pwtlnItem);
+
+ WaitCompletionState wcsWaitCompletionState;
+ bool fWaitAll = (0 != (WTLN_FLAG_WAIT_ALL & pwtlnItem->dwFlags));
+ pdwWaitState = SharedIDToTypePointer(DWORD,
+ pwtlnItem->shridWaitingState);
+
+ if (fSharedObject)
+ {
+ shridNextItem = pwtlnItem->ptrNext.shrid;
+ pwtlnNextItem = SharedIDToTypePointer(WaitingThreadsListNode,
+ shridNextItem);
+ }
+ else
+ {
+ pwtlnNextItem = pwtlnItem->ptrNext.ptr;
+ }
+
+ if (fWaitAll)
+ {
+ // Wait All: we need to find out whether the wait is satisfied,
+ // or it is not, or if that cannot be determined from within
+ // this process (WaitMayBeSatisfied); in this case we need to
+ // delegate the object signaling to the process hosting the
+ // thread that owns the current target WaitingThreadsListNode
+
+ // If the target object is local (fSharedObject == false)
+ // we're probably not holding the shared lock.
+ // If the wait is not a LocalWait, it involves at least one
+ // shared object. If that is the case, at this time we need
+ // to grab the shared lock. In fact IsRestOfWaitAllSatisfied
+ // and UnsignalRestOfLocalAwakeningWaitAll must be called
+ // atomically to prevent that another thread living
+ // in a different process could race with us stealing the
+ // signaling from one of the objects involved in the wait-all.
+ //
+ // Note: pwtlnItem->ptwiWaitInfo is valid only if the target
+ // wait originates in the current process. Anyway in the
+ // following 'if' we don't need to check that since we are
+ // already making sure that the object is local (!fSharedObject).
+ // If a wait involves at least one object local to this process,
+ // it can only be a wait performed by a thread in the current
+ // process, therefore pwtlnItem->ptwiWaitInfo is valid.
+
+ _ASSERTE(fSharedObject || pwtlnItem->dwProcessId == gPID);
+
+ if (!fSharedSynchLock && !fSharedObject &&
+ LocalWait != pwtlnItem->ptwiWaitInfo->wdWaitDomain)
+ {
+ CPalSynchronizationManager::AcquireSharedSynchLock(pthrCurrent);
+ fSharedSynchLock = true;
+ }
+
+ // First check if the current target node is already marked for
+ // wait all check in progress, and in case skip it by setting
+ // wcsWaitCompletionState to WaitIsNotSatisfied
+ bool fMarkedForDelegatedObjectSingalingInProgress =
+ (0 != (WTLN_FLAG_DELEGATED_OBJECT_SIGNALING_IN_PROGRESS & pwtlnItem->dwFlags));
+
+ wcsWaitCompletionState =
+ fMarkedForDelegatedObjectSingalingInProgress ? WaitIsNotSatisfied :
+ IsRestOfWaitAllSatisfied(pwtlnItem);
+ }
+ else
+ {
+ // Normal Wait: the wait is satisfied by definition
+ wcsWaitCompletionState = WaitIsSatisfied;
+ }
+
+ if (WaitIsSatisfied == wcsWaitCompletionState)
+ {
+ //
+ // Target wait is satisfied
+ //
+ TRACE("Trying to switch wait state [%p] from WAIT/ALERTABLE "
+ "to ACTIVE for thread=%u\n",
+ pdwWaitState, pwtlnItem->dwThreadId);
+
+ if (CPalSynchronizationManager::InterlockedAwaken(pdwWaitState, FALSE))
+ {
+ TRACE("Succeeded switching wait state [%p] from WAIT/ALERTABLE "
+ "to TWS_ACTIVE for trhead=%u\n",
+ pdwWaitState, pwtlnItem->dwThreadId);
+
+ dwObjIdx = pwtlnItem->dwObjIndex;
+
+ if (dwPid == pwtlnItem->dwProcessId)
+ {
+ ///////////////////////////
+ //
+ // Local Thread Awakening
+ //
+ ///////////////////////////
+ ThreadWaitInfo * ptwiWaitInfo = pwtlnItem->ptwiWaitInfo;
+ bool fAbandoned = false;
+
+ if (CObjectType::OwnershipTracked ==
+ GetObjectType()->GetOwnershipSemantics())
+ {
+ // Get the abandoned status before resetting it by
+ // assigning ownership to target thread
+ fAbandoned = IsAbandoned();
+
+ // Assign ownership to target thread
+ // Note: This will cause both ownership count and
+ // signal count to be greater than zero at the
+ // same time; the signal count will be anyway
+ // decremented immediately by the caller
+ // CsynchData::Signal
+ palErr = AssignOwnershipToThread(pthrCurrent,
+ ptwiWaitInfo->pthrOwner);
+ if (NO_ERROR != palErr)
+ {
+ ERROR("Synch Worker: AssignOwnershipToThread "
+ "failed with error %u; ownership data on "
+ "object with SynchData %p may be "
+ "corrupted\n", palErr, this);
+ }
+ }
+
+ if (fWaitAll)
+ {
+ // Wait all satisfied: unsignal other objects
+ // involved in the wait
+ CPalSynchronizationManager::UnsignalRestOfLocalAwakeningWaitAll(
+ pthrCurrent,
+ ptwiWaitInfo->pthrOwner,
+ pwtlnItem,
+ this);
+ }
+
+ TRACE("Unregistering wait for thread %u and waking it up "
+ "[pdwWaitState=%p]\n", pwtlnItem->dwThreadId,
+ pdwWaitState);
+
+ // Unregister the wait
+ pSynchManager->UnRegisterWait(pthrCurrent,
+ ptwiWaitInfo,
+ fSharedObject || fSharedSynchLock);
+
+ // After UnRegisterWait pwtlnItem is invalid
+ pwtlnItem = NULL;
+
+ palErr = CPalSynchronizationManager::WakeUpLocalThread(
+ pthrCurrent,
+ ptwiWaitInfo->pthrOwner,
+ fAbandoned ? MutexAbondoned : WaitSucceeded,
+ dwObjIdx);
+
+ if (NO_ERROR != palErr)
+ {
+ ERROR("Failed to wakeup local thread %#x: "
+ "object signaling may be "
+ "lost\n", ptwiWaitInfo->pthrOwner->GetThreadId());
+ }
+ }
+ else
+ {
+ ///////////////////////////
+ //
+ // Remote Thread Awakening
+ //
+ ///////////////////////////
+
+ // Note: if we are here, this cannot be a wait-all
+ _ASSERT_MSG(!fWaitAll,
+ "Control should never reach this point if "
+ "target wait is a wait-all\n");
+
+ // Wake up remote thread
+ palErr = CPalSynchronizationManager::WakeUpRemoteThread(shridItem);
+
+ if (NO_ERROR != palErr)
+ {
+ ERROR("Failed to dispatch remote awakening cmd to "
+ "worker thread in process pid=%d to wake up"
+ "thread tid=%#x; object signaling may be "
+ "lost\n", pwtlnItem->dwProcessId,
+ pwtlnItem->dwThreadId);
+ }
+ }
+
+ // A thread has been awakened
+ fThreadAwakened = true;
+
+ // break out of the while loop
+ break;
+ }
+ }
+ else if (WaitMayBeSatisfied == wcsWaitCompletionState)
+ {
+ //////////////////////////////////////////
+ //
+ // Wait All with remote thread awakening
+ //
+ //////////////////////////////////////////
+
+ //
+ // We need to transfer the object signaling to the process
+ // hosting the target waiter thread
+ //
+
+ _ASSERT_MSG(fWaitAll,
+ "IsRestOfWaitAllSatisfied() apparently "
+ "returned -1 on a normal (non wait all) "
+ "wait\n");
+ _ASSERT_MSG(fSharedObject,
+ "About to delegate object signaling to a remote "
+ "process, but the signaled object is actually "
+ "local\n");
+
+ // Delegate object signaling to target process
+ palErr = CPalSynchronizationManager::DelegateSignalingToRemoteProcess(
+ pthrCurrent,
+ pwtlnItem->dwProcessId,
+ pwtlnItem->ptrOwnerObjSynchData.shrid);
+
+ TRACE("Delegating object signaling for SynchData shrid=%p\n",
+ (VOID *)pwtlnItem->ptrOwnerObjSynchData.shrid);
+
+ if (NO_ERROR == palErr)
+ {
+ // A remote thread will be awakened
+ // This will also cause the object to be unsignaled by the
+ // code calling ReleaseFirstWaiter before releasing the
+ // synch locks, so no other WaitForMultipleObjects
+ // involving the target object may race stealing this
+ // particuklar object signaling
+ fThreadAwakened = true;
+
+ fDelegatedSignaling = true;
+
+ // break out of the while loop
+ break;
+ }
+ else
+ {
+ ERROR("Failed to delegate object signaling to remote "
+ "process %d. Looking for another waiter.\n",
+ pwtlnItem->dwProcessId);
+
+ // Go on: a different target waiter will be selected
+ }
+ }
+
+ if (fWorkerThread && fWaitAll && (dwPid == pwtlnItem->dwProcessId))
+ {
+ // Mark the target wait for object signaling
+ CPalSynchronizationManager::MarkWaitForDelegatedObjectSignalingInProgress(
+ pthrCurrent,
+ pwtlnItem);
+ }
+
+ // Go to the next item
+ shridItem = shridNextItem;
+ pwtlnItem = pwtlnNextItem;
+ }
+
+ if (fDelegatedSignaling)
+ {
+ *pfDelegated = true;
+ }
+ else if (fWorkerThread)
+ {
+ // Reset 'delegated object signaling in progress' flags
+ CPalSynchronizationManager::UnmarkTWListForDelegatedObjectSignalingInProgress(
+ this);
+ }
+
+ if (fSharedSynchLock)
+ {
+ CPalSynchronizationManager::ReleaseSharedSynchLock(pthrCurrent);
+ }
+ return fThreadAwakened;
+ }
+
+ /*++
+ Method:
+ CSynchData::Signal
+
+ Releases all the threads waiting on this object and living in the current
+ process.
+
+ Note: this method must be called while holding the appropriate
+ synchronization locks (the local process synch lock if the target
+ object is local, both local and shared one if the object is shared).
+ --*/
+ LONG CSynchData::ReleaseAllLocalWaiters(
+ CPalThread * pthrCurrent)
+ {
+ PAL_ERROR palErr = NO_ERROR;
+ LONG lAwakenedCount = 0;
+ bool fSharedSynchLock = false;
+ bool fSharedObject = (SharedObject == GetObjectDomain());
+ DWORD * pdwWaitState;
+ DWORD dwObjIdx;
+ SharedID shridItem = NULLSharedID, shridNextItem = NULLSharedID;
+ WaitingThreadsListNode * pwtlnItem, * pwtlnNextItem;
+ DWORD dwPid = gPID;
+ CPalSynchronizationManager * pSynchManager =
+ CPalSynchronizationManager::GetInstance();
+
+ VALIDATEOBJECT(this);
+
+ if (fSharedObject)
+ {
+ shridItem = GetWTLHeadShmPtr();
+ pwtlnItem = SharedIDToTypePointer(WaitingThreadsListNode, shridItem);
+ }
+ else
+ {
+ pwtlnItem = GetWTLHeadPtr();
+ }
+
+ while (pwtlnItem)
+ {
+ VALIDATEOBJECT(pwtlnItem);
+
+ bool fWaitAll = (0 != (WTLN_FLAG_WAIT_ALL & pwtlnItem->dwFlags));
+ pdwWaitState = SharedIDToTypePointer(DWORD,
+ pwtlnItem->shridWaitingState);
+
+ if (fSharedObject)
+ {
+ shridNextItem = pwtlnItem->ptrNext.shrid;
+ pwtlnNextItem = SharedIDToTypePointer(WaitingThreadsListNode,
+ shridNextItem);
+ }
+ else
+ {
+ pwtlnNextItem = pwtlnItem->ptrNext.ptr;
+ }
+
+ // See note in similar spot in ReleaseFirstWaiter
+
+ _ASSERTE(fSharedObject || pwtlnItem->dwProcessId == gPID);
+
+ if (!fSharedSynchLock && !fSharedObject &&
+ LocalWait != pwtlnItem->ptwiWaitInfo->wdWaitDomain)
+ {
+ CPalSynchronizationManager::AcquireSharedSynchLock(pthrCurrent);
+ fSharedSynchLock = true;
+ }
+
+ if( dwPid == pwtlnItem->dwProcessId &&
+ (!fWaitAll || WaitIsSatisfied == IsRestOfWaitAllSatisfied(pwtlnItem)) )
+ {
+ //
+ // Target wait is satisfied
+ //
+ TRACE("Trying to switch wait state [%p] from WAIT/ALERTABLE "
+ "to ACTIVE for thread=%u\n",
+ pdwWaitState, pwtlnItem->dwThreadId);
+
+ if (CPalSynchronizationManager::InterlockedAwaken(pdwWaitState, FALSE))
+ {
+ TRACE("Succeeded switching wait state [%p] from WAIT/ALERTABLE "
+ "to TWS_ACTIVE for trhead=%u\n",
+ pdwWaitState, pwtlnItem->dwThreadId);
+
+ dwObjIdx = pwtlnItem->dwObjIndex;
+
+ ThreadWaitInfo * ptwiWaitInfo = pwtlnItem->ptwiWaitInfo;
+ bool fAbandoned = false;
+
+ if (CObjectType::OwnershipTracked ==
+ GetObjectType()->GetOwnershipSemantics())
+ {
+ // Get the abandoned status before resetting it by
+ // assigning ownership to target thread
+ fAbandoned = IsAbandoned();
+
+ // Assign ownership to target thread
+ palErr = AssignOwnershipToThread(pthrCurrent,
+ ptwiWaitInfo->pthrOwner);
+ if (NO_ERROR != palErr)
+ {
+ ERROR("Synch Worker: AssignOwnershipToThread "
+ "failed with error %u; ownership data on "
+ "object with SynchData %p may be "
+ "corrupted\n", palErr, this);
+ }
+ }
+
+ if (fWaitAll)
+ {
+ // Wait all satisfied: unsignal other objects
+ // involved in the wait
+ CPalSynchronizationManager::UnsignalRestOfLocalAwakeningWaitAll(
+ pthrCurrent,
+ ptwiWaitInfo->pthrOwner,
+ pwtlnItem,
+ this);
+ }
+
+ TRACE("Unregistering wait for thread %u and waking it up "
+ "[pdwWaitState=%p]\n", pwtlnItem->dwThreadId,
+ pdwWaitState);
+
+ // Unregister the wait
+ pSynchManager->UnRegisterWait(pthrCurrent,
+ ptwiWaitInfo,
+ fSharedObject || fSharedSynchLock);
+
+ // After UnRegisterWait pwtlnItem is invalid
+ pwtlnItem = NULL;
+
+ palErr = CPalSynchronizationManager::WakeUpLocalThread(
+ pthrCurrent,
+ ptwiWaitInfo->pthrOwner,
+ fAbandoned ? MutexAbondoned : WaitSucceeded,
+ dwObjIdx);
+
+ if (NO_ERROR != palErr)
+ {
+ ERROR("Failed to wakeup local thread %#x: "
+ "object signaling may be "
+ "lost\n", ptwiWaitInfo->pthrOwner->GetThreadId());
+ }
+ else
+ {
+ // A thread has been awakened
+ lAwakenedCount++;
+ }
+ }
+ }
+
+ // Go to the next item
+ shridItem = shridNextItem;
+ pwtlnItem = pwtlnNextItem;
+ }
+
+ if (fSharedSynchLock)
+ {
+ CPalSynchronizationManager::ReleaseSharedSynchLock(pthrCurrent);
+ }
+ return lAwakenedCount;
+ }
+
+ /*++
+ Method:
+ CSynchData::IsRestOfWaitAllSatisfied
+
+ Returns whether or not the current wait-all operation is fully satisfied,
+ assuming the current target object as signaled (i.e. whether or not all the
+ involved object, except the current one, are signaled).
+ It returns:
+ - WaitIsNotSatisfied if the wait-all is not fully satisfied.
+ - WaitIsSatisfied if the wait-all is fully satisfied.
+ - WaitMayBeSatisfied if the target thread lives in a different process and
+ therefore the wait may involve objects local to the remote process, and
+ as result is generally not possible to say whther or not the wait-all is
+ fully satisfied from the current process.
+
+ Note: this method must be called while holding the synchronization locks
+ appropriate to all the objects involved in the wait-all. If any
+ of the objects is shared, the caller must own both local and
+ shared synch locks; if no shared object is involved in the wait,
+ only the local synch lock is needed.
+ --*/
+ WaitCompletionState CSynchData::IsRestOfWaitAllSatisfied(
+ WaitingThreadsListNode * pwtlnNode)
+ {
+ int iSignaledOrOwnedObjCount = 0;
+ int iTgtCount = 0;
+ int i;
+ WaitCompletionState wcsWaitCompletionState = WaitIsNotSatisfied;
+ CSynchData * psdSynchDataItem = NULL;
+ ThreadWaitInfo * ptwiWaitInfo = NULL;
+
+ VALIDATEOBJECT(this);
+ VALIDATEOBJECT(pwtlnNode);
+
+ _ASSERT_MSG(0 != (WTLN_FLAG_WAIT_ALL & pwtlnNode->dwFlags),
+ "IsRestOfWaitAllSatisfied() called on a normal "
+ "(non wait all) wait");
+ _ASSERT_MSG((SharedObject == GetObjectDomain()) ==
+ (0 != (WTLN_FLAG_OWNER_OBJECT_IS_SHARED & pwtlnNode->dwFlags)),
+ "WTLN_FLAG_OWNER_OBJECT_IS_SHARED in WaitingThreadsListNode "
+ "not consistent with target object's domain\n");
+
+ if(gPID != pwtlnNode->dwProcessId)
+ {
+ ////////////////////////////
+ //
+ // Remote Thread Awakening
+ //
+ ////////////////////////////
+
+ // Cannot determine whether or not the wait all is satisfied from
+ // this process
+ wcsWaitCompletionState = WaitMayBeSatisfied;
+ goto IROWAS_exit;
+ }
+
+ ///////////////////////////
+ //
+ // Local Thread Awakening
+ //
+ ///////////////////////////
+
+ ptwiWaitInfo = pwtlnNode->ptwiWaitInfo;
+
+ iTgtCount = ptwiWaitInfo->lObjCount;
+ for (i=0; i < iTgtCount; i++)
+ {
+ WaitingThreadsListNode * pwtlnItem = ptwiWaitInfo->rgpWTLNodes[i];
+ bool fRetVal;
+ bool fIsAbandoned;
+
+ VALIDATEOBJECT(pwtlnItem);
+
+ if (0 != (WTLN_FLAG_OWNER_OBJECT_IS_SHARED & pwtlnItem->dwFlags))
+ {
+ psdSynchDataItem = SharedIDToTypePointer(CSynchData,
+ pwtlnItem->ptrOwnerObjSynchData.shrid);
+ }
+ else
+ {
+ psdSynchDataItem = pwtlnItem->ptrOwnerObjSynchData.ptr;
+ }
+
+ VALIDATEOBJECT(psdSynchDataItem);
+
+ if (pwtlnItem == pwtlnNode)
+ {
+ _ASSERT_MSG (this == psdSynchDataItem,
+ "pwtlnNode and pwtlnItem match, but this "
+ "and psdSynchDataItem don't\n");
+
+ // The target object (the one related to pwtlnNode) is counted as
+ // signaled/owned without checking it (also if it is not, as
+ // it normally happens when this method is called)
+ iSignaledOrOwnedObjCount++;
+ continue;
+ }
+
+ fRetVal = psdSynchDataItem->CanWaiterWaitWithoutBlocking(
+ ptwiWaitInfo->pthrOwner,
+ &fIsAbandoned);
+
+ if (fRetVal)
+ {
+ iSignaledOrOwnedObjCount++;
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ if (iSignaledOrOwnedObjCount < iTgtCount)
+ {
+ wcsWaitCompletionState = WaitIsNotSatisfied;
+ }
+ else
+ {
+ wcsWaitCompletionState = WaitIsSatisfied;
+ }
+
+ IROWAS_exit:
+ TRACE("IsRestOfWaitAllSatisfied() returning %u \n", wcsWaitCompletionState);
+
+ return wcsWaitCompletionState;
+ }
+
+
+ /*++
+ Method:
+ CSynchData::SetOwner
+
+ Blindly sets the thread whose CPalThread is passed as argument, as the
+ owner of the current object.
+ WARNING: this method discards any previous ownership data and does not
+ update the list of the object owned by the owner thread.
+
+ Note: this method must be called while holding the appropriate
+ synchronization locks (the local process synch lock if the target
+ object is local, both local and shared one if the object is shared).
+ --*/
+ void CSynchData::SetOwner(CPalThread * pOwnerThread)
+ {
+ VALIDATEOBJECT(this);
+
+ m_dwOwnerPid = gPID;
+ m_dwOwnerTid = pOwnerThread->GetThreadId();
+ m_pOwnerThread = pOwnerThread;
+ }
+
+ /*++
+ Method:
+ CSynchData::ResetOwnership
+
+ Resets current object's ownership data
+
+ Note: this method must be called while holding the appropriate
+ synchronization locks (the local process synch lock if the target
+ object is local, both local and shared one if the object is shared).
+ --*/
+ void CSynchData::ResetOwnership()
+ {
+ VALIDATEOBJECT(this);
+
+ m_lOwnershipCount = 0;
+ m_dwOwnerPid = 0;
+ m_dwOwnerTid = 0;
+ m_pOwnerThread = NULL;
+ m_poolnOwnedObjectListNode = NULL;
+ }
+
+ /*++
+ Method:
+ CSynchData::AssignOwnershipToThread
+
+ Assigns thw ownership of the current object to the target thread, performing
+ all the operations neede to mantain the correct status of ownership data,
+ also handling recursive object ownership acquisition
+
+ Note: this method must be called while holding the appropriate
+ synchronization locks (the local process synch lock if the target
+ object is local, both local and shared one if the object is shared).
+ --*/
+ PAL_ERROR CSynchData::AssignOwnershipToThread(
+ CPalThread * pthrCurrent,
+ CPalThread * pthrTarget)
+ {
+ // Note: when this method is called by ReleaseFirstWaiter there is
+ // a small time window in which both SignalCount and
+ // OwnershipCount can be greater than zero (which normally
+ // is illegal). Anyway that is fine since ReleaseFirstWaiter
+ // will restore the value right after, and such situation
+ // takes place while holding synchroniztion locks, so no
+ // other thread/process can access the object.
+
+ PAL_ERROR palErr = NO_ERROR;
+
+ _ASSERT_MSG(CObjectType::OwnershipTracked ==
+ GetObjectType()->GetOwnershipSemantics(),
+ "AssignOwnershipToThread called on a non-ownable "
+ "CSynchData [this=%p OwnershipSemantics=%u]\n", this,
+ GetObjectType()->GetOwnershipSemantics());
+
+
+ if (0 < m_lOwnershipCount)
+ {
+ //
+ // Object already owned, incrementing ownership count
+ //
+ _ASSERT_MSG(0 == GetSignalCount(),
+ "Conflicting OwnershipCount and SignalCount values\n");
+
+ _ASSERT_MSG(pthrTarget == m_pOwnerThread && gPID == m_dwOwnerPid,
+ "Attempting to assign ownership of CSynchData %p to "
+ "thread {pid=%#x tid=%#x} while it is currently owned "
+ "by thread {pid=%#x tid=%#x}\n", this,
+ gPID, pthrTarget->GetThreadId(),
+ m_dwOwnerPid, m_pOwnerThread->GetThreadId());
+
+ m_lOwnershipCount++;
+
+ TRACE("Incrementing ownership count for object with "
+ "SynchData %p owned by thread %#x [new count=%d]\n",
+ this, pthrTarget->GetThreadId(), m_lOwnershipCount);
+ }
+ else
+ {
+ //
+ // Acquiring currently not owned object
+ //
+ CPalSynchronizationManager * pSynchManager =
+ CPalSynchronizationManager::GetInstance();
+ OwnedObjectsListNode * pooln;
+
+ pooln = pSynchManager->CacheGetOwnedObjsListNode(pthrCurrent);
+ if (NULL == pooln)
+ {
+ ERROR("Out of memory while acquiring mutex ownership");
+ // In this case we bail out. It will result in no
+ // thread being awakend, which may cause deadlock,
+ // but it is anyway better than corrupting the
+ // ownership list
+ palErr = ERROR_NOT_ENOUGH_MEMORY;
+ goto AOTT_exit;
+ }
+
+ TRACE("Assigning ownable object with SynchData %p to "
+ "thread %#x\n",
+ this, pthrTarget->GetThreadId());
+
+ // Set ownership data
+ SetOwner(pthrTarget);
+ SetOwnershipListNode(pooln);
+ SetOwnershipCount(1);
+ SetAbandoned(false);
+
+ // Add object to list of owned objs for current thread
+ pooln->pPalObjSynchData = this;
+ AddRef();
+ pthrTarget->synchronizationInfo.AddObjectToOwnedList(pooln);
+ }
+
+ AOTT_exit:
+ return palErr;
+ }
+
+ /*++
+ Method:
+ CSynchData::WaiterEnqueue
+
+ Adds the WaitingThreadsListNode passed as argument at the end of the
+ list of WaitingThreadsListNode for the current object, representing
+ the threads waiting on the current object. The target SynchData is
+ assumed to be local to the current process
+
+ Note: this method must be called while holding the local process
+ synchronization lock.
+ --*/
+ void CSynchData::WaiterEnqueue(WaitingThreadsListNode * pwtlnNewNode)
+ {
+ VALIDATEOBJECT(this);
+ VALIDATEOBJECT(pwtlnNewNode);
+
+ _ASSERT_MSG(ProcessLocalObject == GetObjectDomain(),
+ "Trying to enqueue a WaitingThreadsListNode as local "
+ "on a shared object\n");
+ _ASSERT_MSG(0 == (WTLN_FLAG_OWNER_OBJECT_IS_SHARED & pwtlnNewNode->dwFlags),
+ "Trying to add a WaitingThreadsListNode marked as shared "
+ "as it was a local one\n");
+
+ WaitingThreadsListNode * pwtlnCurrLast = m_ptrWTLTail.ptr;
+
+ pwtlnNewNode->ptrNext.ptr = NULL;
+ if (NULL == pwtlnCurrLast)
+ {
+ _ASSERT_MSG(NULL == m_ptrWTLHead.ptr,
+ "Corrupted waiting list on local CSynchData @ %p\n",
+ this);
+
+ pwtlnNewNode->ptrPrev.ptr = NULL;
+ m_ptrWTLHead.ptr = pwtlnNewNode;
+ m_ptrWTLTail.ptr = pwtlnNewNode;
+ }
+ else
+ {
+ VALIDATEOBJECT(pwtlnCurrLast);
+
+ pwtlnNewNode->ptrPrev.ptr = pwtlnCurrLast;
+ pwtlnCurrLast->ptrNext.ptr = pwtlnNewNode;
+ m_ptrWTLTail.ptr = pwtlnNewNode;
+ }
+
+ m_ulcWaitingThreads += 1;
+
+ return;
+ }
+
+ /*++
+ Method:
+ CSynchData::SharedWaiterEnqueue
+
+ Adds the WaitingThreadsListNode passed as argument at the end of the
+ list of WaitingThreadsListNode for the current object, representing
+ the threads waiting on the current object. The target SynchData is
+ assumed to be shared among processes
+
+ Note: this method must be called while holding both local and shared
+ synchronization locks.
+ --*/
+ void CSynchData::SharedWaiterEnqueue(SharedID shridNewNode)
+ {
+ VALIDATEOBJECT(this);
+
+ _ASSERT_MSG(SharedObject == GetObjectDomain(),
+ "Trying to enqueue a WaitingThreadsListNode as shared "
+ "on a local object\n");
+
+ SharedID shridCurrLast;
+ WaitingThreadsListNode * pwtlnCurrLast, * pwtlnNewNode;
+
+ shridCurrLast = m_ptrWTLTail.shrid;
+ pwtlnCurrLast = SharedIDToTypePointer(WaitingThreadsListNode, shridCurrLast);
+ pwtlnNewNode = SharedIDToTypePointer(WaitingThreadsListNode, shridNewNode);
+
+ _ASSERT_MSG(1 == (WTLN_FLAG_OWNER_OBJECT_IS_SHARED & pwtlnNewNode->dwFlags),
+ "Trying to add a WaitingThreadsListNode marked as local "
+ "as it was a shared one\n");
+
+ VALIDATEOBJECT(pwtlnNewNode);
+
+ pwtlnNewNode->ptrNext.shrid = NULLSharedID;
+ if (NULL == pwtlnCurrLast)
+ {
+ _ASSERT_MSG(NULLSharedID == m_ptrWTLHead.shrid,
+ "Corrupted waiting list on shared CSynchData at "
+ "{shrid=%p, p=%p}\n", m_shridThis, this);
+
+ pwtlnNewNode->ptrPrev.shrid = NULLSharedID;
+ m_ptrWTLHead.shrid = shridNewNode;
+ m_ptrWTLTail.shrid = shridNewNode;
+ }
+ else
+ {
+ VALIDATEOBJECT(pwtlnCurrLast);
+
+ pwtlnNewNode->ptrPrev.shrid = shridCurrLast;
+ pwtlnCurrLast->ptrNext.shrid = shridNewNode;
+ m_ptrWTLTail.shrid = shridNewNode;
+ }
+
+ m_ulcWaitingThreads += 1;
+
+ return;
+ }
+
+#ifdef SYNCH_OBJECT_VALIDATION
+ CSynchData::~CSynchData()
+ {
+ ValidateObject(true);
+ InvalidateObject();
+ }
+ /*++
+ Method:
+ CSynchData::ValidateObject
+
+ Makes sure that the signature at the beginning and at the end of the
+ current object are those of a currently alive object (i.e. the object
+ has been constructed and does not appear to have been overwritten)
+ --*/
+ void CSynchData::ValidateObject(bool fDestructor)
+ {
+ TRACE("Verifying in-use CSynchData @ %p\n", this);
+ _ASSERT_MSG(HeadSignature == m_dwDebugHeadSignature,
+ "CSynchData header signature corruption [p=%p]", this);
+ _ASSERT_MSG(TailSignature == m_dwDebugTailSignature,
+ "CSynchData trailer signature corruption [p=%p]", this);
+ _ASSERT_MSG((fDestructor && 0 == m_lRefCount) ||
+ (!fDestructor && 0 < m_lRefCount),
+ "CSynchData %p with NULL reference count\n", this);
+ }
+ /*++
+ Method:
+ CSynchData::ValidateEmptyObject
+
+ Makes sure that the signature at the beginning and at the end of the
+ current object are not those of a currently alive object (i.e. the
+ object has not yet been constructed or it has alread been destructed)
+ --*/
+ void CSynchData::ValidateEmptyObject()
+ {
+ TRACE("Verifying empty CSynchData @ %p\n", this);
+ _ASSERT_MSG(HeadSignature != m_dwDebugHeadSignature,
+ "CSynchData header previously signed [p=%p]", this);
+ _ASSERT_MSG(TailSignature != m_dwDebugTailSignature,
+ "CSynchData trailer previously signed [p=%p]", this);
+ }
+ /*++
+ Method:
+ CSynchData::InvalidateObject
+
+ Turns signatures from alive object to destructed object
+ --*/
+ void CSynchData::InvalidateObject()
+ {
+ TRACE("Invalidating CSynchData @ %p\n", this);
+ m_dwDebugHeadSignature = EmptySignature;
+ m_dwDebugTailSignature = EmptySignature;
+ }
+#endif // SYNCH_OBJECT_VALIDATION
+}
+
diff --git a/src/pal/src/synchmgr/synchmanager.cpp b/src/pal/src/synchmgr/synchmanager.cpp
new file mode 100644
index 0000000000..473918cb68
--- /dev/null
+++ b/src/pal/src/synchmgr/synchmanager.cpp
@@ -0,0 +1,4556 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ synchmanager.cpp
+
+Abstract:
+ Implementation of Synchronization Manager and related objects
+
+
+
+--*/
+
+#include "pal/dbgmsg.h"
+
+SET_DEFAULT_DEBUG_CHANNEL(SYNC); // some headers have code with asserts, so do this first
+
+#include "synchmanager.hpp"
+#include "pal/file.hpp"
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <limits.h>
+#include <sched.h>
+#include <signal.h>
+#include <errno.h>
+#if HAVE_POLL
+#include <poll.h>
+#else
+#include "pal/fakepoll.h"
+#endif // HAVE_POLL
+
+// We use the synchronization manager's worker thread to handle
+// process termination requests. It does so by calling the
+// registered handler function.
+PTERMINATION_REQUEST_HANDLER g_terminationRequestHandler = NULL;
+
+// Set the handler for process termination requests.
+VOID PALAPI PAL_SetTerminationRequestHandler(
+ IN PTERMINATION_REQUEST_HANDLER terminationHandler)
+{
+ g_terminationRequestHandler = terminationHandler;
+}
+
+namespace CorUnix
+{
+ /////////////////////////////////
+ // //
+ // WaitingThreadsListNode //
+ // //
+ /////////////////////////////////
+#ifdef SYNCH_OBJECT_VALIDATION
+ _WaitingThreadsListNode::_WaitingThreadsListNode()
+ {
+ ValidateEmptyObject();
+ dwDebugHeadSignature = HeadSignature;
+ dwDebugTailSignature = TailSignature;
+ }
+ _WaitingThreadsListNode::~_WaitingThreadsListNode()
+ {
+ ValidateObject();
+ InvalidateObject();
+ }
+ void _WaitingThreadsListNode::ValidateObject()
+ {
+ TRACE("Verifying WaitingThreadsListNode @ %p\n", this);
+ _ASSERT_MSG(HeadSignature == dwDebugHeadSignature,
+ "WaitingThreadsListNode header signature corruption [p=%p]",
+ this);
+ _ASSERT_MSG(TailSignature == dwDebugTailSignature,
+ "WaitingThreadsListNode trailer signature corruption [p=%p]",
+ this);
+ }
+ void _WaitingThreadsListNode::ValidateEmptyObject()
+ {
+ _ASSERT_MSG(HeadSignature != dwDebugHeadSignature,
+ "WaitingThreadsListNode header previously signed [p=%p]",
+ this);
+ _ASSERT_MSG(TailSignature != dwDebugTailSignature,
+ "WaitingThreadsListNode trailer previously signed [p=%p]",
+ this);
+ }
+ void _WaitingThreadsListNode::InvalidateObject()
+ {
+ TRACE("Invalidating WaitingThreadsListNode @ %p\n", this);
+ dwDebugHeadSignature = EmptySignature;
+ dwDebugTailSignature = EmptySignature;
+ }
+#endif // SYNCH_OBJECT_VALIDATION
+
+ //////////////////////////////
+ // //
+ // CPalSynchMgrController //
+ // //
+ //////////////////////////////
+
+ /*++
+ Method:
+ CPalSynchMgrController::CreatePalSynchronizationManager
+
+ Creates the Synchronization Manager. It must be called once per process.
+ --*/
+ IPalSynchronizationManager * CPalSynchMgrController::CreatePalSynchronizationManager()
+ {
+ return CPalSynchronizationManager::CreatePalSynchronizationManager();
+ };
+
+ /*++
+ Method:
+ CPalSynchMgrController::StartWorker
+
+ Starts the Synchronization Manager's Worker Thread
+ --*/
+ PAL_ERROR CPalSynchMgrController::StartWorker(
+ CPalThread * pthrCurrent)
+ {
+ return CPalSynchronizationManager::StartWorker(pthrCurrent);
+ }
+
+ /*++
+ Method:
+ CPalSynchMgrController::PrepareForShutdown
+
+ This method performs the part of Synchronization Manager's shutdown that
+ needs to be carried out when core PAL subsystems are still active
+ --*/
+ PAL_ERROR CPalSynchMgrController::PrepareForShutdown()
+ {
+ return CPalSynchronizationManager::PrepareForShutdown();
+ }
+
+ //////////////////////////////////
+ // //
+ // CPalSynchronizationManager //
+ // //
+ //////////////////////////////////
+
+ IPalSynchronizationManager * g_pSynchronizationManager = NULL;
+
+ CPalSynchronizationManager * CPalSynchronizationManager::s_pObjSynchMgr = NULL;
+ Volatile<LONG> CPalSynchronizationManager::s_lInitStatus = SynchMgrStatusIdle;
+ CRITICAL_SECTION CPalSynchronizationManager::s_csSynchProcessLock;
+ CRITICAL_SECTION CPalSynchronizationManager::s_csMonitoredProcessesLock;
+
+ CPalSynchronizationManager::CPalSynchronizationManager()
+ : m_dwWorkerThreadTid(0),
+ m_pipoThread(NULL),
+ m_pthrWorker(NULL),
+ m_iProcessPipeRead(-1),
+ m_iProcessPipeWrite(-1),
+ m_pmplnMonitoredProcesses(NULL),
+ m_lMonitoredProcessesCount(0),
+ m_pmplnExitedNodes(NULL),
+ m_cacheWaitCtrlrs(CtrlrsCacheMaxSize),
+ m_cacheStateCtrlrs(CtrlrsCacheMaxSize),
+ m_cacheSynchData(SynchDataCacheMaxSize),
+ m_cacheSHRSynchData(SynchDataCacheMaxSize),
+ m_cacheWTListNodes(WTListNodeCacheMaxSize),
+ m_cacheSHRWTListNodes(WTListNodeCacheMaxSize),
+ m_cacheThreadApcInfoNodes(ApcInfoNodeCacheMaxSize),
+ m_cacheOwnedObjectsListNodes(OwnedObjectsListCacheMaxSize)
+ {
+#if HAVE_KQUEUE && !HAVE_BROKEN_FIFO_KEVENT
+ m_iKQueue = -1;
+ // Initialize data to 0 and flags to EV_EOF
+ EV_SET(&m_keProcessPipeEvent, 0, 0, EV_EOF, 0, 0, 0);
+#endif // HAVE_KQUEUE
+ }
+
+ CPalSynchronizationManager::~CPalSynchronizationManager()
+ {
+ }
+
+ /*++
+ Method:
+ CPalSynchronizationManager::BlockThread
+
+ Called by a thread to go to sleep for a wait or a sleep
+
+ NOTE: This method must must be called without holding any
+ synchronization lock (as well as other locks)
+ --*/
+ PAL_ERROR CPalSynchronizationManager::BlockThread(
+ CPalThread *pthrCurrent,
+ DWORD dwTimeout,
+ bool fAlertable,
+ bool fIsSleep,
+ ThreadWakeupReason *ptwrWakeupReason,
+ DWORD * pdwSignaledObject)
+ {
+ PAL_ERROR palErr = NO_ERROR;
+ ThreadWakeupReason twrWakeupReason = WaitFailed;
+ DWORD * pdwWaitState;
+ DWORD dwWaitState = 0;
+ DWORD dwSigObjIdx = 0;
+ bool fRaceAlerted = false;
+ bool fEarlyDeath = false;
+
+ pdwWaitState = SharedIDToTypePointer(DWORD,
+ pthrCurrent->synchronizationInfo.m_shridWaitAwakened);
+
+ _ASSERT_MSG(NULL != pdwWaitState,
+ "Got NULL pdwWaitState from m_shridWaitAwakened=%p\n",
+ (VOID *)pthrCurrent->synchronizationInfo.m_shridWaitAwakened);
+
+ if (fIsSleep)
+ {
+ // If fIsSleep is true we are being called by Sleep/SleepEx
+ // and we need to switch the wait state to TWS_WAITING or
+ // TWS_ALERTABLE (according to fAlertable)
+
+ if (fAlertable)
+ {
+ // If we are in alertable mode we need to grab the lock to
+ // make sure that no APC is queued right before the
+ // InterlockedCompareExchange.
+ // If there are APCs queued at this time, no native wakeup
+ // will be posted, so we need to skip the native wait
+
+ // Lock
+ AcquireLocalSynchLock(pthrCurrent);
+ AcquireSharedSynchLock(pthrCurrent);
+
+ if (AreAPCsPending(pthrCurrent))
+ {
+ // APCs have been queued when the thread wait status was
+ // still TWS_ACTIVE, therefore the queueing thread will not
+ // post any native wakeup: we need to skip the actual
+ // native wait
+ fRaceAlerted = true;
+ }
+ }
+
+ if (!fRaceAlerted)
+ {
+ // Setting the thread in wait state
+ dwWaitState = (DWORD)(fAlertable ? TWS_ALERTABLE : TWS_WAITING);
+
+ TRACE("Switching my wait state [%p] from TWS_ACTIVE to %u [current *pdwWaitState=%u]\n",
+ pdwWaitState, dwWaitState, *pdwWaitState);
+
+ dwWaitState = InterlockedCompareExchange((LONG *)pdwWaitState,
+ dwWaitState,
+ TWS_ACTIVE);
+
+ if ((DWORD)TWS_ACTIVE != dwWaitState)
+ {
+ if (fAlertable)
+ {
+ // Unlock
+ ReleaseSharedSynchLock(pthrCurrent);
+ ReleaseLocalSynchLock(pthrCurrent);
+ }
+
+ if ((DWORD)TWS_EARLYDEATH == dwWaitState)
+ {
+ // Process is terminating, this thread will soon be suspended (by SuspendOtherThreads).
+ WARN("Thread is about to get suspended by TerminateProcess\n");
+
+ fEarlyDeath = true;
+ palErr = WAIT_FAILED;
+ }
+ else
+ {
+ ASSERT("Unexpected thread wait state %u\n", dwWaitState);
+ palErr = ERROR_INTERNAL_ERROR;
+ }
+
+ goto BT_exit;
+ }
+ }
+
+ if (fAlertable)
+ {
+ // Unlock
+ ReleaseSharedSynchLock(pthrCurrent);
+ ReleaseLocalSynchLock(pthrCurrent);
+ }
+ }
+
+ if (fRaceAlerted)
+ {
+ twrWakeupReason = Alerted;
+ }
+ else
+ {
+ TRACE("Current thread is about to block for waiting\n");
+
+ palErr = ThreadNativeWait(
+ &pthrCurrent->synchronizationInfo.m_tnwdNativeData,
+ dwTimeout,
+ &twrWakeupReason,
+ &dwSigObjIdx);
+
+ if (NO_ERROR != palErr)
+ {
+ ERROR("ThreadNativeWait() failed [palErr=%d]\n", palErr);
+ twrWakeupReason = WaitFailed;
+ goto BT_exit;
+ }
+
+ TRACE("ThreadNativeWait returned {WakeupReason=%u "
+ "dwSigObjIdx=%u}\n", twrWakeupReason, dwSigObjIdx);
+ }
+
+ if (WaitTimeout == twrWakeupReason)
+ {
+ // timeout reached. set wait state back to 'active'
+ dwWaitState = (DWORD)(fAlertable ? TWS_ALERTABLE : TWS_WAITING);
+
+ TRACE("Current thread awakened for timeout: switching wait "
+ "state [%p] from %u to TWS_ACTIVE [current *pdwWaitState=%u]\n",
+ pdwWaitState, dwWaitState, *pdwWaitState);
+
+ DWORD dwOldWaitState = InterlockedCompareExchange(
+ (LONG *)pdwWaitState,
+ TWS_ACTIVE, (LONG)dwWaitState);
+
+ switch (dwOldWaitState)
+ {
+ case TWS_ACTIVE:
+ // We were already ACTIVE; someone decided to wake up this
+ // thread sometime between the moment the native wait
+ // timed out and here. Since the signaling side succeeded
+ // its InterlockedCompareExchange, it will signal the
+ // condition/predicate pair (we just raced overtaking it);
+ // therefore we need to clear the condition/predicate
+ // by waiting on it one more time.
+ // That will also cause this method to report a signal
+ // rather than a timeout.
+ // In the remote signaling scenario, this second wait
+ // also makes sure that the shared id passed over the
+ // process pipe is valid for the entire duration of time
+ // in which the worker thread deals with it
+ TRACE("Current thread already ACTIVE: a signaling raced "
+ "with the timeout: re-waiting natively to clear the "
+ "predicate\n");
+
+ palErr = ThreadNativeWait(
+ &pthrCurrent->synchronizationInfo.m_tnwdNativeData,
+ SecondNativeWaitTimeout,
+ &twrWakeupReason,
+ &dwSigObjIdx);
+
+ if (NO_ERROR != palErr)
+ {
+ ERROR("ThreadNativeWait() failed [palErr=%d]\n",
+ palErr);
+ twrWakeupReason = WaitFailed;
+ }
+
+ if (WaitTimeout == twrWakeupReason)
+ {
+ ERROR("Second native wait timed out\n");
+ }
+
+ break;
+ case TWS_EARLYDEATH:
+ // Thread is about to be suspended by TerminateProcess.
+ // Anyway, if the wait timed out, we still want to
+ // (try to) unregister the wait (especially if it
+ // involves shared objects)
+ WARN("Thread is about to be suspended by TerminateProcess\n");
+ fEarlyDeath = true;
+ palErr = WAIT_FAILED;
+ break;
+ case TWS_WAITING:
+ case TWS_ALERTABLE:
+ default:
+ _ASSERT_MSG(dwOldWaitState == dwWaitState,
+ "Unexpected wait status: actual=%u, expected=%u\n",
+ dwOldWaitState, dwWaitState);
+ break;
+ }
+ }
+
+ switch (twrWakeupReason)
+ {
+ case WaitTimeout:
+ {
+ // Awakened for timeout: we need to unregister the wait
+ ThreadWaitInfo * ptwiWaitInfo;
+
+ TRACE("Current thread awakened for timeout: unregistering the wait\n");
+
+ // Local lock
+ AcquireLocalSynchLock(pthrCurrent);
+
+ ptwiWaitInfo = GetThreadWaitInfo(pthrCurrent);
+
+ // Unregister the wait
+ // Note: UnRegisterWait will take care of grabbing the shared synch lock, if needed.
+ UnRegisterWait(pthrCurrent, ptwiWaitInfo, false);
+
+ // Unlock
+ ReleaseLocalSynchLock(pthrCurrent);
+
+ break;
+ }
+ case WaitSucceeded:
+ case MutexAbondoned:
+ *pdwSignaledObject = dwSigObjIdx;
+ break;
+ default:
+ // 'Alerted' and 'WaitFailed' go through this case
+ break;
+ }
+
+ // Set the returned wakeup reason
+ *ptwrWakeupReason = twrWakeupReason;
+
+ TRACE("Current thread is now active [WakeupReason=%u SigObjIdx=%u]\n",
+ twrWakeupReason, dwSigObjIdx);
+
+ _ASSERT_MSG(TWS_ACTIVE == VolatileLoad(pdwWaitState) ||
+ TWS_EARLYDEATH == VolatileLoad(pdwWaitState),
+ "Unexpected thread wait state %u\n", VolatileLoad(pdwWaitState));
+
+ BT_exit:
+ if (fEarlyDeath)
+ {
+ ThreadPrepareForShutdown();
+ }
+
+ return palErr;
+ }
+
+ PAL_ERROR CPalSynchronizationManager::ThreadNativeWait(
+ ThreadNativeWaitData * ptnwdNativeWaitData,
+ DWORD dwTimeout,
+ ThreadWakeupReason * ptwrWakeupReason,
+ DWORD * pdwSignaledObject)
+ {
+ PAL_ERROR palErr = NO_ERROR;
+ int iRet, iWaitRet = 0;
+ struct timespec tsAbsTmo;
+
+ TRACE("ThreadNativeWait(ptnwdNativeWaitData=%p, dwTimeout=%u, ...)\n",
+ ptnwdNativeWaitData, dwTimeout);
+
+ if (dwTimeout != INFINITE)
+ {
+ // Calculate absolute timeout
+ palErr = GetAbsoluteTimeout(dwTimeout, &tsAbsTmo);
+ if (NO_ERROR != palErr)
+ {
+ ERROR("Failed to convert timeout to absolute timeout\n");
+ goto TNW_exit;
+ }
+ }
+
+ // Lock the mutex
+ iRet = pthread_mutex_lock(&ptnwdNativeWaitData->mutex);
+ if (0 != iRet)
+ {
+ ERROR("Internal Error: cannot lock mutex\n");
+ palErr = ERROR_INTERNAL_ERROR;
+ *ptwrWakeupReason = WaitFailed;
+ goto TNW_exit;
+ }
+
+ while (FALSE == ptnwdNativeWaitData->iPred)
+ {
+ if (INFINITE == dwTimeout)
+ {
+ iWaitRet = pthread_cond_wait(&ptnwdNativeWaitData->cond,
+ &ptnwdNativeWaitData->mutex);
+ }
+ else
+ {
+ iWaitRet = pthread_cond_timedwait(&ptnwdNativeWaitData->cond,
+ &ptnwdNativeWaitData->mutex,
+ &tsAbsTmo);
+ }
+
+ if (ETIMEDOUT == iWaitRet)
+ {
+ _ASSERT_MSG(INFINITE != dwTimeout,
+ "Got ETIMEDOUT despite timeout being INFINITE\n");
+ break;
+ }
+ else if (0 != iWaitRet)
+ {
+ ERROR("pthread_cond_%swait returned %d [errno=%d (%s)]\n",
+ (INFINITE == dwTimeout) ? "" : "timed",
+ iWaitRet, errno, strerror(errno));
+ palErr = ERROR_INTERNAL_ERROR;
+ break;
+ }
+ }
+
+ // Reset the predicate
+ if (0 == iWaitRet)
+ {
+ // We don't want to reset the predicate if pthread_cond_timedwait
+ // timed out racing with a pthread_cond_signal. When
+ // pthread_cond_timedwait times out, it needs to grab the mutex
+ // before returning. At timeout time, it may happen that the
+ // signaling thread just grabbed the mutex, but it hasn't called
+ // pthread_cond_signal yet. In this scenario pthread_cond_timedwait
+ // will have to wait for the signaling side to release the mutex.
+ // As a result it will return with error timeout, but the predicate
+ // will be set. Since pthread_cond_timedwait timed out, the
+ // predicate value is intended for the next signal. In case of a
+ // object signaling racing with a wait timeout this predicate value
+ // will be picked up by the 'second native wait' (see comments in
+ // BlockThread).
+
+ ptnwdNativeWaitData->iPred = FALSE;
+ }
+
+ // Unlock the mutex
+ iRet = pthread_mutex_unlock(&ptnwdNativeWaitData->mutex);
+ if (0 != iRet)
+ {
+ ERROR("Cannot unlock mutex [err=%d]\n", iRet);
+ palErr = ERROR_INTERNAL_ERROR;
+ goto TNW_exit;
+ }
+
+ _ASSERT_MSG(ETIMEDOUT != iRet || INFINITE != dwTimeout, "Got timeout return code with INFINITE timeout\n");
+
+ if (0 == iWaitRet)
+ {
+ *ptwrWakeupReason = ptnwdNativeWaitData->twrWakeupReason;
+ *pdwSignaledObject = ptnwdNativeWaitData->dwObjectIndex;
+ }
+ else if (ETIMEDOUT == iWaitRet)
+ {
+ *ptwrWakeupReason = WaitTimeout;
+ }
+
+ TNW_exit:
+ TRACE("ThreadNativeWait: returning %u [WakeupReason=%u]\n", palErr, *ptwrWakeupReason);
+ return palErr;
+ }
+
+ /*++
+ Method:
+ CPalSynchronizationManager::AbandonObjectsOwnedByThread
+
+ This method is called by a thread at thread-exit time to abandon
+ any currently owned waitable object (mutexes). If pthrTarget is
+ different from pthrCurrent, AbandonObjectsOwnedByThread assumes
+ to be called whether by TerminateThread or at shutdown time. See
+ comments below for more details
+ --*/
+ PAL_ERROR CPalSynchronizationManager::AbandonObjectsOwnedByThread(
+ CPalThread * pthrCurrent,
+ CPalThread * pthrTarget)
+ {
+ PAL_ERROR palErr = NO_ERROR;
+ OwnedObjectsListNode * poolnItem;
+ bool fSharedSynchLock = false;
+ CThreadSynchronizationInfo * pSynchInfo = &pthrTarget->synchronizationInfo;
+ CPalSynchronizationManager * pSynchManager = GetInstance();
+
+ // Local lock
+ AcquireLocalSynchLock(pthrCurrent);
+
+ // Abandon owned objects
+ while (NULL != (poolnItem = pSynchInfo->RemoveFirstObjectFromOwnedList()))
+ {
+ CSynchData * psdSynchData = poolnItem->pPalObjSynchData;
+
+ _ASSERT_MSG(NULL != psdSynchData,
+ "NULL psdSynchData pointer in ownership list node\n");
+
+ VALIDATEOBJECT(psdSynchData);
+
+ TRACE("Abandoning object with SynchData at %p\n", psdSynchData);
+
+ if (!fSharedSynchLock &&
+ (SharedObject == psdSynchData->GetObjectDomain()))
+ {
+ AcquireSharedSynchLock(pthrCurrent);
+ fSharedSynchLock = true;
+ }
+
+ // Reset ownership data
+ psdSynchData->ResetOwnership();
+
+ // Set abandoned status; in case there is a thread to be released:
+ // - if the thread is local, ReleaseFirstWaiter will reset the
+ // abandoned status
+ // - if the thread is remote, the remote worker thread will use
+ // the value and reset it
+ psdSynchData->SetAbandoned(true);
+
+ // Signal the object and trigger thread awakening
+ psdSynchData->Signal(pthrCurrent, 1, false);
+
+ // Release reference to to SynchData
+ psdSynchData->Release(pthrCurrent);
+
+ // Return node to the cache
+ pSynchManager->m_cacheOwnedObjectsListNodes.Add(pthrCurrent, poolnItem);
+ }
+
+ // Abandon owned named mutexes
+ while (true)
+ {
+ NamedMutexProcessData *processData = pSynchInfo->RemoveFirstOwnedNamedMutex();
+ if (processData == nullptr)
+ {
+ break;
+ }
+ processData->Abandon();
+ }
+
+ if (pthrTarget != pthrCurrent)
+ {
+ // If the target thead is not the current one, we are being called
+ // at shutdown time, right before the target thread is suspended,
+ // or anyway the target thread is being terminated.
+ // In this case we switch its wait state to TWS_EARLYDEATH so that,
+ // if the thread is currently waiting/sleeping and it wakes up
+ // before shutdown code manage to suspend it, it will be rerouted
+ // to ThreadPrepareForShutdown (that will be done without holding
+ // any internal lock, in a way to accomodate shutdown time thread
+ // suspension).
+ // At this time we also unregister the wait, so no dummy nodes are
+ // left around on waiting objects.
+ // The TWS_EARLYDEATH wait-state will also prevent the thread from
+ // successfully registering for a possible new wait in the same
+ // time window.
+ LONG lTWState;
+ DWORD * pdwWaitState;
+
+ pdwWaitState = SharedIDToTypePointer(DWORD, pthrTarget->synchronizationInfo.m_shridWaitAwakened);
+ lTWState = InterlockedExchange((LONG *)pdwWaitState, TWS_EARLYDEATH);
+
+ if (( ((LONG)TWS_WAITING == lTWState) || ((LONG)TWS_ALERTABLE == lTWState) ) &&
+ (0 < pSynchInfo->m_twiWaitInfo.lObjCount))
+ {
+ // Unregister the wait
+ // Note: UnRegisterWait will take care of grabbing the shared synch lock, if needed.
+ UnRegisterWait(pthrCurrent, &pSynchInfo->m_twiWaitInfo, fSharedSynchLock);
+ }
+ }
+
+ // Unlock
+ if (fSharedSynchLock)
+ {
+ ReleaseSharedSynchLock(pthrCurrent);
+ fSharedSynchLock = false;
+ }
+
+ ReleaseLocalSynchLock(pthrCurrent);
+ DiscardAllPendingAPCs(pthrCurrent, pthrTarget);
+
+ return palErr;
+ }
+
+ /*++
+ Method:
+ CPalSynchronizationManager::GetSynchWaitControllersForObjects
+
+ Returns an array of wait controllers, one for each of the objects
+ in rgObjects
+ --*/
+ PAL_ERROR CPalSynchronizationManager::GetSynchWaitControllersForObjects(
+ CPalThread *pthrCurrent,
+ IPalObject *rgObjects[],
+ DWORD dwObjectCount,
+ ISynchWaitController * rgControllers[])
+ {
+ return GetSynchControllersForObjects(pthrCurrent,
+ rgObjects,
+ dwObjectCount,
+ (void **)rgControllers,
+ CSynchControllerBase::WaitController);
+ }
+
+ /*++
+ Method:
+ CPalSynchronizationManager::GetSynchStateControllersForObjects
+
+ Returns an array of state controllers, one for each of the objects
+ in rgObjects
+ --*/
+ PAL_ERROR CPalSynchronizationManager::GetSynchStateControllersForObjects(
+ CPalThread *pthrCurrent,
+ IPalObject *rgObjects[],
+ DWORD dwObjectCount,
+ ISynchStateController *rgControllers[])
+ {
+ return GetSynchControllersForObjects(pthrCurrent,
+ rgObjects,
+ dwObjectCount,
+ (void **)rgControllers,
+ CSynchControllerBase::StateController);
+ }
+
+ /*++
+ Method:
+ CPalSynchronizationManager::GetSynchControllersForObjects
+
+ Internal common implementation for GetSynchWaitControllersForObjects and
+ GetSynchStateControllersForObjects
+ --*/
+ PAL_ERROR CPalSynchronizationManager::GetSynchControllersForObjects(
+ CPalThread *pthrCurrent,
+ IPalObject *rgObjects[],
+ DWORD dwObjectCount,
+ void ** ppvControllers,
+ CSynchControllerBase::ControllerType ctCtrlrType)
+ {
+ PAL_ERROR palErr = NO_ERROR;
+ unsigned int uIdx, uCount = 0, uSharedObjectCount = 0;
+ WaitDomain wdWaitDomain = LocalWait;
+ CObjectType * potObjectType = NULL;
+ unsigned int uErrCleanupIdxFirstNotInitializedCtrlr = 0;
+ unsigned int uErrCleanupIdxLastCtrlr = 0;
+ bool fLocalSynchLock = false;
+
+ union
+ {
+ CSynchWaitController * pWaitCtrlrs[MAXIMUM_WAIT_OBJECTS];
+ CSynchStateController * pStateCtrlrs[MAXIMUM_WAIT_OBJECTS];
+ } Ctrlrs;
+
+ if ((dwObjectCount <= 0) || (dwObjectCount > MAXIMUM_WAIT_OBJECTS))
+ {
+ palErr = ERROR_INVALID_PARAMETER;
+ goto GSCFO_exit;
+ }
+
+ if (CSynchControllerBase::WaitController == ctCtrlrType)
+ {
+ uCount = (unsigned int)m_cacheWaitCtrlrs.Get(pthrCurrent,
+ dwObjectCount,
+ Ctrlrs.pWaitCtrlrs);
+ }
+ else
+ {
+ uCount = (unsigned int)m_cacheStateCtrlrs.Get(pthrCurrent,
+ dwObjectCount,
+ Ctrlrs.pStateCtrlrs);
+ }
+
+ if (uCount < dwObjectCount)
+ {
+ // We got less controllers (uCount) than we asked for (dwObjectCount),
+ // probably because of low memory.
+ // None of these controllers is initialized, so they must be all
+ // returned directly to the cache
+ uErrCleanupIdxLastCtrlr = uCount;
+
+ palErr = ERROR_NOT_ENOUGH_MEMORY;
+ goto GSCFO_error_cleanup;
+ }
+
+ //
+ // We need to acquire the local synch lock before evaluating object domains
+ //
+ AcquireLocalSynchLock(pthrCurrent);
+ fLocalSynchLock = true;
+
+ for (uIdx=0; uIdx<dwObjectCount; uIdx++)
+ {
+ if (SharedObject == rgObjects[uIdx]->GetObjectDomain())
+ {
+ ++uSharedObjectCount;
+ }
+
+ if (uSharedObjectCount > 0 && uSharedObjectCount <= uIdx)
+ {
+ wdWaitDomain = MixedWait;
+ break;
+ }
+ }
+
+ if (dwObjectCount == uSharedObjectCount)
+ {
+ wdWaitDomain = SharedWait;
+ }
+
+ for (uIdx=0;uIdx<dwObjectCount;uIdx++)
+ {
+ void * pvSData;
+ CSynchData * psdSynchData;
+ ObjectDomain odObjectDomain = rgObjects[uIdx]->GetObjectDomain();
+
+ palErr = rgObjects[uIdx]->GetObjectSynchData((void **)&pvSData);
+ if (NO_ERROR != palErr)
+ {
+ break;
+ }
+
+ psdSynchData = (SharedObject == odObjectDomain) ? SharedIDToTypePointer(
+ CSynchData, reinterpret_cast<SharedID>(pvSData)) :
+ static_cast<CSynchData *>(pvSData);
+
+ VALIDATEOBJECT(psdSynchData);
+
+ potObjectType = rgObjects[uIdx]->GetObjectType();
+
+ if (CSynchControllerBase::WaitController == ctCtrlrType)
+ {
+ Ctrlrs.pWaitCtrlrs[uIdx]->Init(pthrCurrent,
+ ctCtrlrType,
+ odObjectDomain,
+ potObjectType,
+ psdSynchData,
+ wdWaitDomain);
+ }
+ else
+ {
+ Ctrlrs.pStateCtrlrs[uIdx]->Init(pthrCurrent,
+ ctCtrlrType,
+ odObjectDomain,
+ potObjectType,
+ psdSynchData,
+ wdWaitDomain);
+ }
+
+ if (CSynchControllerBase::WaitController == ctCtrlrType &&
+ otiProcess == potObjectType->GetId())
+ {
+ CProcProcessLocalData * pProcLocData;
+ IDataLock * pDataLock;
+
+ palErr = rgObjects[uIdx]->GetProcessLocalData(
+ pthrCurrent,
+ ReadLock,
+ &pDataLock,
+ (void **)&pProcLocData);
+
+ if (NO_ERROR != palErr)
+ {
+ // In case of failure here, bail out of the loop, but
+ // keep track (by incrementing the counter 'uIdx') of the
+ // fact that this controller has already being initialized
+ // and therefore need to be Release'd rather than just
+ // returned to the cache
+ uIdx++;
+ break;
+ }
+
+ Ctrlrs.pWaitCtrlrs[uIdx]->SetProcessData(rgObjects[uIdx], pProcLocData);
+ pDataLock->ReleaseLock(pthrCurrent, false);
+ }
+ }
+ if (NO_ERROR != palErr)
+ {
+ // An error occurred while initializing the (uIdx+1)-th controller,
+ // i.e. the one at index uIdx; therefore the first uIdx controllers
+ // must be Release'd, while the remaining uCount-uIdx must be returned
+ // directly to the cache.
+ uErrCleanupIdxFirstNotInitializedCtrlr = uIdx;
+ uErrCleanupIdxLastCtrlr = dwObjectCount;
+
+ goto GSCFO_error_cleanup;
+ }
+
+ // Succeeded
+ if (CSynchControllerBase::WaitController == ctCtrlrType)
+ {
+ for (uIdx=0;uIdx<dwObjectCount;uIdx++)
+ {
+ // The multiple cast is NEEDED, though currently it does not
+ // change the value ot the pointer. Anyway, if in the future
+ // a virtual method should be added to the base class
+ // CSynchControllerBase, both derived classes would have two
+ // virtual tables, therefore a static cast from, for instance,
+ // a CSynchWaitController* to a ISynchWaitController* would
+ // return the given pointer incremented by the size of a
+ // generic pointer on the specific platform
+ ppvControllers[uIdx] = reinterpret_cast<void *>(
+ static_cast<ISynchWaitController *>(Ctrlrs.pWaitCtrlrs[uIdx]));
+ }
+ }
+ else
+ {
+ for (uIdx=0;uIdx<dwObjectCount;uIdx++)
+ {
+ // See comment above
+ ppvControllers[uIdx] = reinterpret_cast<void *>(
+ static_cast<ISynchStateController *>(Ctrlrs.pStateCtrlrs[uIdx]));
+ }
+ }
+
+ // Succeeded: skip error cleanup
+ goto GSCFO_exit;
+
+ GSCFO_error_cleanup:
+ if (CSynchControllerBase::WaitController == ctCtrlrType)
+ {
+ // Release already initialized wait controllers
+ for (uIdx=0; uIdx<uErrCleanupIdxFirstNotInitializedCtrlr; uIdx++)
+ {
+ Ctrlrs.pWaitCtrlrs[uIdx]->Release();
+ }
+
+ // Return to the cache not yet initialized wait controllers
+ for (uIdx=uErrCleanupIdxFirstNotInitializedCtrlr; uIdx<uErrCleanupIdxLastCtrlr; uIdx++)
+ {
+ m_cacheWaitCtrlrs.Add(pthrCurrent, Ctrlrs.pWaitCtrlrs[uIdx]);
+ }
+ }
+ else
+ {
+ // Release already initialized state controllers
+ for (uIdx=0; uIdx<uErrCleanupIdxFirstNotInitializedCtrlr; uIdx++)
+ {
+ Ctrlrs.pStateCtrlrs[uIdx]->Release();
+ }
+
+ // Return to the cache not yet initialized state controllers
+ for (uIdx=uErrCleanupIdxFirstNotInitializedCtrlr; uIdx<uErrCleanupIdxLastCtrlr; uIdx++)
+ {
+ m_cacheStateCtrlrs.Add(pthrCurrent, Ctrlrs.pStateCtrlrs[uIdx]);
+ }
+ }
+
+ GSCFO_exit:
+ if (fLocalSynchLock)
+ {
+ ReleaseLocalSynchLock(pthrCurrent);
+ }
+ return palErr;
+ }
+
+ /*++
+ Method:
+ CPalSynchronizationManager::AllocateObjectSynchData
+
+ Returns a new SynchData for an object of given type and domain
+ --*/
+ PAL_ERROR CPalSynchronizationManager::AllocateObjectSynchData(
+ CObjectType *potObjectType,
+ ObjectDomain odObjectDomain,
+ VOID **ppvSynchData)
+ {
+ PAL_ERROR palErr = NO_ERROR;
+ CSynchData * psdSynchData = NULL;
+ CPalThread * pthrCurrent = InternalGetCurrentThread();
+
+ if (SharedObject == odObjectDomain)
+ {
+ SharedID shridSynchData = m_cacheSHRSynchData.Get(pthrCurrent);
+ if (NULLSharedID == shridSynchData)
+ {
+ ERROR("Unable to allocate shared memory\n");
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ psdSynchData = SharedIDToTypePointer(CSynchData, shridSynchData);
+
+ VALIDATEOBJECT(psdSynchData);
+
+ _ASSERT_MSG(NULL != psdSynchData, "Bad shared memory pointer\n");
+
+ // Initialize waiting list pointers
+ psdSynchData->SetWTLHeadShrPtr(NULLSharedID);
+ psdSynchData->SetWTLTailShrPtr(NULLSharedID);
+
+ // Store shared pointer to this object
+ psdSynchData->SetSharedThis(shridSynchData);
+
+ *ppvSynchData = reinterpret_cast<void *>(shridSynchData);
+ }
+ else
+ {
+ psdSynchData = m_cacheSynchData.Get(pthrCurrent);
+ if (NULL == psdSynchData)
+ {
+ ERROR("Unable to allocate memory\n");
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ // Initialize waiting list pointers
+ psdSynchData->SetWTLHeadPtr(NULL);
+ psdSynchData->SetWTLTailPtr(NULL);
+
+ // Set shared this pointer to NULL
+ psdSynchData->SetSharedThis(NULLSharedID);
+
+ *ppvSynchData = static_cast<void *>(psdSynchData);
+ }
+
+ // Initialize object domain and object type;
+ psdSynchData->SetObjectDomain(odObjectDomain);
+ psdSynchData->SetObjectType(potObjectType);
+
+ return palErr;
+ }
+
+ /*++
+ Method:
+ CPalSynchronizationManager::FreeObjectSynchData
+
+ Called to return a no longer used SynchData to the Synchronization Manager.
+ The SynchData may actually survive this call, since it is a ref-counted
+ object and at FreeObjectSynchData time it may still be used from within
+ the Synchronization Manager itself (e.g. the worker thread).
+ --*/
+ void CPalSynchronizationManager::FreeObjectSynchData(
+ CObjectType *potObjectType,
+ ObjectDomain odObjectDomain,
+ VOID *pvSynchData)
+ {
+ CSynchData * psdSynchData;
+ CPalThread * pthrCurrent = InternalGetCurrentThread();
+
+ if (odObjectDomain == SharedObject)
+ {
+ psdSynchData = SharedIDToTypePointer(CSynchData,
+ reinterpret_cast<SharedID>(pvSynchData));
+
+ if (NULL == psdSynchData)
+ {
+ ASSERT("Bad shared memory pointer\n");
+ return;
+ }
+ }
+ else
+ {
+ psdSynchData = static_cast<CSynchData *>(pvSynchData);
+ }
+
+ psdSynchData->Release(pthrCurrent);
+ }
+
+ /*++
+ Method:
+ CPalSynchronizationManager::CreateSynchStateController
+
+ Creates a state controller for the given object
+ --*/
+ PAL_ERROR CPalSynchronizationManager::CreateSynchStateController(
+ CPalThread *pthrCurrent,
+ CObjectType *potObjectType,
+ VOID *pvSynchData,
+ ObjectDomain odObjectDomain,
+ ISynchStateController **ppStateController)
+ {
+ PAL_ERROR palErr = NO_ERROR;
+ CSynchStateController * pCtrlr = NULL;
+ WaitDomain wdWaitDomain = (SharedObject == odObjectDomain) ? SharedWait : LocalWait;
+ CSynchData * psdSynchData;
+
+ psdSynchData = (SharedObject == odObjectDomain) ? SharedIDToTypePointer(CSynchData, reinterpret_cast<SharedID>(pvSynchData))
+ : static_cast<CSynchData *>(pvSynchData);
+
+ VALIDATEOBJECT(psdSynchData);
+
+ pCtrlr = m_cacheStateCtrlrs.Get(pthrCurrent);
+ if (NULL == pCtrlr)
+ {
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ pCtrlr->Init(pthrCurrent,
+ CSynchControllerBase::StateController,
+ odObjectDomain,
+ potObjectType,
+ psdSynchData,
+ wdWaitDomain);
+
+ // Succeeded
+ *ppStateController = (ISynchStateController *)pCtrlr;
+
+ if (NO_ERROR != palErr)
+ {
+ m_cacheStateCtrlrs.Add(pthrCurrent, pCtrlr);
+ }
+
+ return palErr;
+ }
+
+ /*++
+ Method:
+ CPalSynchronizationManager::CreateSynchWaitController
+
+ Creates a wait controller for the given object
+ --*/
+ PAL_ERROR CPalSynchronizationManager::CreateSynchWaitController(
+ CPalThread *pthrCurrent,
+ CObjectType *potObjectType,
+ VOID *pvSynchData,
+ ObjectDomain odObjectDomain,
+ ISynchWaitController **ppWaitController)
+ {
+ CSynchWaitController * pCtrlr = NULL;
+ WaitDomain wdWaitDomain = (SharedObject == odObjectDomain) ? SharedWait : LocalWait;
+ CSynchData * psdSynchData;
+
+ psdSynchData = (SharedObject == odObjectDomain) ? SharedIDToTypePointer(
+ CSynchData, reinterpret_cast<SharedID>(pvSynchData)) :
+ static_cast<CSynchData *>(pvSynchData);
+
+ VALIDATEOBJECT(psdSynchData);
+
+ pCtrlr = m_cacheWaitCtrlrs.Get(pthrCurrent);
+ if (NULL == pCtrlr)
+ {
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ pCtrlr->Init(pthrCurrent,
+ CSynchControllerBase::WaitController,
+ odObjectDomain,
+ potObjectType,
+ psdSynchData,
+ wdWaitDomain);
+
+ // Succeeded
+ *ppWaitController = (ISynchWaitController *)pCtrlr;
+
+ return NO_ERROR;
+ }
+
+ /*++
+ Method:
+ CPalSynchronizationManager::QueueUserAPC
+
+ Internal implementation of QueueUserAPC
+ --*/
+ PAL_ERROR CPalSynchronizationManager::QueueUserAPC(CPalThread * pthrCurrent,
+ CPalThread * pthrTarget,
+ PAPCFUNC pfnAPC,
+ ULONG_PTR uptrData)
+ {
+ PAL_ERROR palErr = NO_ERROR;
+ ThreadApcInfoNode * ptainNode = NULL;
+ DWORD dwWaitState;
+ DWORD * pdwWaitState;
+ ThreadWaitInfo * pTargetTWInfo = GetThreadWaitInfo(pthrTarget);
+ bool fLocalSynchLock = false;
+ bool fSharedSynchLock = false;
+ bool fThreadLock = false;
+
+ ptainNode = m_cacheThreadApcInfoNodes.Get(pthrCurrent);
+ if (NULL == ptainNode)
+ {
+ ERROR("No memory for new APCs linked list entry\n");
+ palErr = ERROR_NOT_ENOUGH_MEMORY;
+ goto QUAPC_exit;
+ }
+
+ ptainNode->pfnAPC = pfnAPC;
+ ptainNode->pAPCData = uptrData;
+ ptainNode->pNext = NULL;
+
+ AcquireLocalSynchLock(pthrCurrent);
+ fLocalSynchLock = true;
+
+ if (LocalWait != pTargetTWInfo->wdWaitDomain)
+ {
+ AcquireSharedSynchLock(pthrCurrent);
+ fSharedSynchLock = true;
+ }
+
+ pthrTarget->Lock(pthrCurrent);
+ fThreadLock = true;
+
+ if (TS_DONE == pthrTarget->synchronizationInfo.GetThreadState())
+ {
+ ERROR("Thread %#x has terminated; can't queue an APC on it\n",
+ pthrTarget->GetThreadId());
+ palErr = ERROR_INVALID_PARAMETER;
+ goto QUAPC_exit;
+ }
+ pdwWaitState = SharedIDToTypePointer(DWORD,
+ pthrTarget->synchronizationInfo.m_shridWaitAwakened);
+ if (TWS_EARLYDEATH == VolatileLoad(pdwWaitState))
+ {
+ ERROR("Thread %#x is about to be suspended for process shutdwon, "
+ "can't queue an APC on it\n", pthrTarget->GetThreadId());
+ palErr = ERROR_INVALID_PARAMETER;
+ goto QUAPC_exit;
+ }
+
+ if (NULL == pthrTarget->apcInfo.m_ptainTail)
+ {
+ _ASSERT_MSG(NULL == pthrTarget->apcInfo.m_ptainHead, "Corrupted APC list\n");
+
+ pthrTarget->apcInfo.m_ptainHead = ptainNode;
+ pthrTarget->apcInfo.m_ptainTail = ptainNode;
+ }
+ else
+ {
+ pthrTarget->apcInfo.m_ptainTail->pNext = ptainNode;
+ pthrTarget->apcInfo.m_ptainTail = ptainNode;
+ }
+
+ // Set ptainNode to NULL so it won't be readded to the cache
+ ptainNode = NULL;
+
+ TRACE("APC %p with parameter %p added to APC queue\n", pfnAPC, uptrData);
+
+ dwWaitState = InterlockedCompareExchange((LONG *)pdwWaitState,
+ (LONG)TWS_ACTIVE,
+ (LONG)TWS_ALERTABLE);
+
+ // Release thread lock
+ pthrTarget->Unlock(pthrCurrent);
+ fThreadLock = false;
+
+ if (TWS_ALERTABLE == dwWaitState)
+ {
+ // Unregister the wait
+ UnRegisterWait(pthrCurrent, pTargetTWInfo, fSharedSynchLock);
+
+ // Wake up target thread
+ palErr = WakeUpLocalThread(
+ pthrCurrent,
+ pthrTarget,
+ Alerted,
+ 0);
+
+ if (NO_ERROR != palErr)
+ {
+ ERROR("Failed to wakeup local thread %#x for dispatching APCs [err=%u]\n",
+ pthrTarget->GetThreadId(), palErr);
+ }
+ }
+
+ QUAPC_exit:
+ if (fThreadLock)
+ {
+ pthrTarget->Unlock(pthrCurrent);
+ }
+
+ if (fSharedSynchLock)
+ {
+ ReleaseSharedSynchLock(pthrCurrent);
+ }
+
+ if (fLocalSynchLock)
+ {
+ ReleaseLocalSynchLock(pthrCurrent);
+ }
+
+ if (ptainNode)
+ {
+ m_cacheThreadApcInfoNodes.Add(pthrCurrent, ptainNode);
+ }
+
+ return palErr;
+ }
+
+ /*++
+ Method:
+ CPalSynchronizationManager::SendTerminationRequestToWorkerThread
+
+ Send a request to the worker thread to initiate process termination.
+ --*/
+ PAL_ERROR CPalSynchronizationManager::SendTerminationRequestToWorkerThread()
+ {
+ PAL_ERROR palErr = GetInstance()->WakeUpLocalWorkerThread(SynchWorkerCmdTerminationRequest);
+ if (palErr != NO_ERROR)
+ {
+ ERROR("Failed to wake up worker thread [errno=%d {%s%}]\n",
+ errno, strerror(errno));
+ palErr = ERROR_INTERNAL_ERROR;
+ }
+
+ return palErr;
+ }
+
+ /*++
+ Method:
+ CPalSynchronizationManager::AreAPCsPending
+
+ Returns 'true' if there are APCs currently pending for the target
+ thread (normally the current one)
+ --*/
+ bool CPalSynchronizationManager::AreAPCsPending(
+ CPalThread * pthrTarget)
+ {
+ // No need to lock here
+ return (NULL != pthrTarget->apcInfo.m_ptainHead);
+ }
+
+ /*++
+ Method:
+ CPalSynchronizationManager::DispatchPendingAPCs
+
+ Executes any pending APC for the current thread
+ --*/
+ PAL_ERROR CPalSynchronizationManager::DispatchPendingAPCs(
+ CPalThread * pthrCurrent)
+ {
+ ThreadApcInfoNode * ptainNode, * ptainLocalHead;
+ int iAPCsCalled = 0;
+
+ while (TRUE)
+ {
+ // Lock
+ pthrCurrent->Lock(pthrCurrent);
+ ptainLocalHead = pthrCurrent->apcInfo.m_ptainHead;
+ if (ptainLocalHead)
+ {
+ pthrCurrent->apcInfo.m_ptainHead = NULL;
+ pthrCurrent->apcInfo.m_ptainTail = NULL;
+ }
+
+ // Unlock
+ pthrCurrent->Unlock(pthrCurrent);
+
+ if (NULL == ptainLocalHead)
+ {
+ break;
+ }
+
+ while (ptainLocalHead)
+ {
+ ptainNode = ptainLocalHead;
+ ptainLocalHead = ptainNode->pNext;
+
+#if _ENABLE_DEBUG_MESSAGES_
+ // reset ENTRY nesting level back to zero while
+ // inside the callback ...
+ int iOldLevel = DBG_change_entrylevel(0);
+#endif /* _ENABLE_DEBUG_MESSAGES_ */
+
+ TRACE("Calling APC %p with parameter %#x\n",
+ ptainNode->pfnAPC, ptainNode->pfnAPC);
+
+ // Actual APC call
+ ptainNode->pfnAPC(ptainNode->pAPCData);
+
+#if _ENABLE_DEBUG_MESSAGES_
+ // ... and set nesting level back to what it was
+ DBG_change_entrylevel(iOldLevel);
+#endif /* _ENABLE_DEBUG_MESSAGES_ */
+
+ iAPCsCalled++;
+ m_cacheThreadApcInfoNodes.Add(pthrCurrent, ptainNode);
+ }
+ }
+
+ return (iAPCsCalled > 0) ? NO_ERROR : ERROR_NOT_FOUND;
+ }
+
+ /*++
+ Method:
+ CPalSynchronizationManager::DiscardAllPendingAPCs
+
+ Discards any pending APC for the target pthrTarget thread
+ --*/
+ void CPalSynchronizationManager::DiscardAllPendingAPCs(
+ CPalThread * pthrCurrent,
+ CPalThread * pthrTarget)
+ {
+ ThreadApcInfoNode * ptainNode, * ptainLocalHead;
+
+ // Lock
+ pthrTarget->Lock(pthrCurrent);
+ ptainLocalHead = pthrTarget->apcInfo.m_ptainHead;
+ if (ptainLocalHead)
+ {
+ pthrTarget->apcInfo.m_ptainHead = NULL;
+ pthrTarget->apcInfo.m_ptainTail = NULL;
+ }
+
+ // Unlock
+ pthrTarget->Unlock(pthrCurrent);
+
+ while (ptainLocalHead)
+ {
+ ptainNode = ptainLocalHead;
+ ptainLocalHead = ptainNode->pNext;
+
+ m_cacheThreadApcInfoNodes.Add(pthrCurrent, ptainNode);
+ }
+ }
+
+ /*++
+ Method:
+ CPalSynchronizationManager::CreatePalSynchronizationManager
+
+ Creates the Synchronization Manager.
+ Private method, it is called only by CPalSynchMgrController.
+ --*/
+ IPalSynchronizationManager * CPalSynchronizationManager::CreatePalSynchronizationManager()
+ {
+ if (s_pObjSynchMgr != NULL)
+ {
+ ASSERT("Multiple PAL Synchronization manager initializations\n");
+ return NULL;
+ }
+
+ Initialize();
+ return static_cast<IPalSynchronizationManager *>(s_pObjSynchMgr);
+ }
+
+ /*++
+ Method:
+ CPalSynchronizationManager::Initialize
+
+ Internal Synchronization Manager initialization
+ --*/
+ PAL_ERROR CPalSynchronizationManager::Initialize()
+ {
+ PAL_ERROR palErr = NO_ERROR;
+ LONG lInit;
+ CPalSynchronizationManager * pSynchManager = NULL;
+
+ lInit = InterlockedCompareExchange(&s_lInitStatus,
+ (LONG)SynchMgrStatusInitializing,
+ (LONG)SynchMgrStatusIdle);
+
+ if ((LONG)SynchMgrStatusIdle != lInit)
+ {
+ ASSERT("Synchronization Manager already being initialized");
+ palErr = ERROR_INTERNAL_ERROR;
+ goto I_exit;
+ }
+
+ InternalInitializeCriticalSection(&s_csSynchProcessLock);
+ InternalInitializeCriticalSection(&s_csMonitoredProcessesLock);
+
+ pSynchManager = InternalNew<CPalSynchronizationManager>();
+ if (NULL == pSynchManager)
+ {
+ ERROR("Failed to allocate memory for Synchronization Manager");
+ palErr = ERROR_NOT_ENOUGH_MEMORY;
+ goto I_exit;
+ }
+
+ if (!pSynchManager->CreateProcessPipe())
+ {
+ ERROR("Unable to create process pipe \n");
+ palErr = ERROR_OPEN_FAILED;
+ goto I_exit;
+ }
+
+ s_pObjSynchMgr = pSynchManager;
+
+ // Initialization was successful
+ g_pSynchronizationManager =
+ static_cast<IPalSynchronizationManager *>(pSynchManager);
+ s_lInitStatus = (LONG)SynchMgrStatusRunning;
+
+ I_exit:
+ if (NO_ERROR != palErr)
+ {
+ s_lInitStatus = (LONG)SynchMgrStatusError;
+ if (NULL != pSynchManager)
+ {
+ pSynchManager->ShutdownProcessPipe();
+ }
+
+ s_pObjSynchMgr = NULL;
+ g_pSynchronizationManager = NULL;
+ InternalDelete(pSynchManager);
+ }
+
+ return palErr;
+ }
+
+ /*++
+ Method:
+ CPalSynchronizationManager::StartWorker
+
+ Starts the Synchronization Manager's Worker Thread.
+ Private method, it is called only by CPalSynchMgrController.
+ --*/
+ PAL_ERROR CPalSynchronizationManager::StartWorker(
+ CPalThread * pthrCurrent)
+ {
+ PAL_ERROR palErr = NO_ERROR;
+ CPalSynchronizationManager * pSynchManager = GetInstance();
+
+ if ((NULL == pSynchManager) || ((LONG)SynchMgrStatusRunning != s_lInitStatus))
+ {
+ ERROR("Trying to to create worker thread in invalid state\n");
+ return ERROR_INTERNAL_ERROR;
+ }
+
+ HANDLE hWorkerThread = NULL;
+ palErr = InternalCreateThread(pthrCurrent,
+ NULL,
+ 0,
+ &WorkerThread,
+ (PVOID)pSynchManager,
+ 0,
+ PalWorkerThread,
+ &pSynchManager->m_dwWorkerThreadTid,
+ &hWorkerThread);
+
+ if (NO_ERROR == palErr)
+ {
+ palErr = InternalGetThreadDataFromHandle(pthrCurrent,
+ hWorkerThread,
+ 0,
+ &pSynchManager->m_pthrWorker,
+ &pSynchManager->m_pipoThread);
+ if (NO_ERROR != palErr)
+ {
+ ERROR("Unable to get worker thread data\n");
+ }
+ }
+ else
+ {
+ ERROR("Unable to create worker thread\n");
+ }
+
+ if (NULL != hWorkerThread)
+ {
+ CloseHandle(hWorkerThread);
+ }
+
+ return palErr;
+ }
+
+ /*++
+ Method:
+ CPalSynchronizationManager::PrepareForShutdown
+
+ This method performs the part of Synchronization Manager's shutdown that
+ needs to be carried out when core PAL subsystems are still active.
+ Private method, it is called only by CPalSynchMgrController.
+ --*/
+ PAL_ERROR CPalSynchronizationManager::PrepareForShutdown()
+ {
+ PAL_ERROR palErr = NO_ERROR;
+ CPalSynchronizationManager * pSynchManager = GetInstance();
+ CPalThread * pthrCurrent = InternalGetCurrentThread();
+ int iRet;
+ ThreadNativeWaitData * ptnwdWorkerThreadNativeData;
+ struct timespec tsAbsTmo = { 0, 0 };
+
+ LONG lInit = InterlockedCompareExchange(&s_lInitStatus,
+ (LONG)SynchMgrStatusShuttingDown, (LONG)SynchMgrStatusRunning);
+
+ if ((LONG)SynchMgrStatusRunning != lInit)
+ {
+ ASSERT("Unexpected initialization status found "
+ "in PrepareForShutdown [expected=%d current=%d]\n",
+ SynchMgrStatusRunning, lInit);
+ // We intentionally not set s_lInitStatus to SynchMgrStatusError
+ // cause this could interfere with a previous thread already
+ // executing shutdown
+ palErr = ERROR_INTERNAL_ERROR;
+ goto PFS_exit;
+ }
+
+ // Discard process monitoring for process waits
+ pSynchManager->DiscardMonitoredProcesses(pthrCurrent);
+
+ if (NULL == pSynchManager->m_pipoThread)
+ {
+ // If m_pipoThread is NULL here, that means that StartWorker has
+ // never been called. That may happen if PAL_Initialize fails
+ // sometime after having called CreatePalSynchronizationManager,
+ // but before calling StartWorker. Nothing else to do here.
+ goto PFS_exit;
+ }
+
+ palErr = pSynchManager->WakeUpLocalWorkerThread(SynchWorkerCmdShutdown);
+ if (NO_ERROR != palErr)
+ {
+ ERROR("Failed stopping worker thread [palErr=%u]\n", palErr);
+ s_lInitStatus = SynchMgrStatusError;
+ goto PFS_exit;
+ }
+
+ ptnwdWorkerThreadNativeData =
+ &pSynchManager->m_pthrWorker->synchronizationInfo.m_tnwdNativeData;
+
+ palErr = GetAbsoluteTimeout(WorkerThreadTerminationTimeout, &tsAbsTmo);
+ if (NO_ERROR != palErr)
+ {
+ ERROR("Failed to convert timeout to absolute timeout\n");
+ s_lInitStatus = SynchMgrStatusError;
+ goto PFS_exit;
+ }
+
+ // Using the worker thread's predicate/condition/mutex
+ // to wait for worker thread to be done
+ iRet = pthread_mutex_lock(&ptnwdWorkerThreadNativeData->mutex);
+ if (0 != iRet)
+ {
+ // pthread calls might fail if the shutdown is called
+ // from a signal handler. In this case just don't wait
+ // for the worker thread
+ ERROR("Cannot lock mutex [err=%d]\n", iRet);
+ palErr = ERROR_INTERNAL_ERROR;
+ s_lInitStatus = SynchMgrStatusError;
+ goto PFS_exit;
+ }
+
+ while (FALSE == ptnwdWorkerThreadNativeData->iPred)
+ {
+ iRet = pthread_cond_timedwait(&ptnwdWorkerThreadNativeData->cond,
+ &ptnwdWorkerThreadNativeData->mutex,
+ &tsAbsTmo);
+ if (0 != iRet)
+ {
+ if (ETIMEDOUT == iRet)
+ {
+ WARN("Timed out waiting for worker thread to exit "
+ "(tmo=%u ms)\n", WorkerThreadTerminationTimeout);
+ }
+ else
+ {
+ ERROR("pthread_cond_timedwait returned %d [errno=%d (%s)]\n",
+ iRet, errno, strerror(errno));
+ }
+ break;
+ }
+ }
+ if (0 == iRet)
+ {
+ ptnwdWorkerThreadNativeData->iPred = FALSE;
+ }
+ iRet = pthread_mutex_unlock(&ptnwdWorkerThreadNativeData->mutex);
+ if (0 != iRet)
+ {
+ ERROR("Cannot unlock mutex [err=%d]\n", iRet);
+ palErr = ERROR_INTERNAL_ERROR;
+ s_lInitStatus = SynchMgrStatusError;
+ goto PFS_exit;
+ }
+
+ PFS_exit:
+ if (NO_ERROR == palErr)
+ {
+ if (NULL != pSynchManager->m_pipoThread)
+ {
+ pSynchManager->m_pipoThread->ReleaseReference(pthrCurrent);
+
+ // After this release both m_pipoThread and m_pthrWorker
+ // are no longer valid
+ pSynchManager->m_pipoThread = NULL;
+ pSynchManager->m_pthrWorker = NULL;
+ }
+
+ // Ready for process shutdown
+ s_lInitStatus = SynchMgrStatusReadyForProcessShutDown;
+ }
+
+ return palErr;
+ }
+
+ // Entry point routine for the thread that initiates process termination.
+ DWORD TerminationRequestHandlingRoutine(LPVOID pArg)
+ {
+ // Call the termination request handler if one is registered.
+ if (g_terminationRequestHandler != NULL)
+ {
+ g_terminationRequestHandler();
+ }
+
+ return 0;
+ }
+
+ /*++
+ Method:
+ CPalSynchronizationManager::WorkerThread
+
+ Synchronization Manager's Worker Thread
+ --*/
+ DWORD PALAPI CPalSynchronizationManager::WorkerThread(LPVOID pArg)
+ {
+ PAL_ERROR palErr;
+ bool fShuttingDown = false;
+ bool fWorkerIsDone = false;
+ int iPollTimeout = INFTIM;
+ SynchWorkerCmd swcCmd;
+ ThreadWakeupReason twrWakeUpReason;
+ SharedID shridMarshaledData;
+ DWORD dwData;
+ CPalSynchronizationManager * pSynchManager =
+ reinterpret_cast<CPalSynchronizationManager*>(pArg);
+ CPalThread * pthrWorker = InternalGetCurrentThread();
+
+ while (!fWorkerIsDone)
+ {
+ LONG lProcessCount;
+
+ palErr = pSynchManager->ReadCmdFromProcessPipe(iPollTimeout,
+ &swcCmd,
+ &shridMarshaledData,
+ &dwData);
+ if (NO_ERROR != palErr)
+ {
+ ERROR("Received error %x from ReadCmdFromProcessPipe()\n",
+ palErr);
+ continue;
+ }
+ switch (swcCmd)
+ {
+ case SynchWorkerCmdTerminationRequest:
+ // This worker thread is being asked to initiate process termination
+
+ HANDLE hTerminationRequestHandlingThread;
+ palErr = InternalCreateThread(pthrWorker,
+ NULL,
+ 0,
+ &TerminationRequestHandlingRoutine,
+ NULL,
+ 0,
+ PalWorkerThread,
+ NULL,
+ &hTerminationRequestHandlingThread);
+
+ if (NO_ERROR != palErr)
+ {
+ ERROR("Unable to create worker thread\n");
+ }
+
+ if (hTerminationRequestHandlingThread != NULL)
+ {
+ CloseHandle(hTerminationRequestHandlingThread);
+ }
+
+ break;
+ case SynchWorkerCmdNop:
+ TRACE("Synch Worker: received SynchWorkerCmdNop\n");
+ if (fShuttingDown)
+ {
+ TRACE("Synch Worker: received a timeout when "
+ "fShuttingDown==true: worker is done, bailing "
+ "out from the loop\n");
+
+ // Whether WorkerThreadShuttingDownTimeout has elapsed
+ // or the last process with a descriptor opened for
+ // write on our process pipe, has just closed it,
+ // causing an EOF on the read fd (that can happen only
+ // at shutdown time since during normal run time we
+ // hold a fd opened for write within this process).
+ // In both the case it is time to go for the worker
+ // thread.
+ fWorkerIsDone = true;
+ }
+ else
+ {
+ lProcessCount = pSynchManager->DoMonitorProcesses(pthrWorker);
+ if (lProcessCount > 0)
+ {
+ iPollTimeout = WorkerThreadProcMonitoringTimeout;
+ }
+ else
+ {
+ iPollTimeout = INFTIM;
+ }
+ }
+ break;
+ case SynchWorkerCmdRemoteSignal:
+ {
+ // Note: this cannot be a wait all
+ WaitingThreadsListNode * pWLNode;
+ ThreadWaitInfo * ptwiWaitInfo;
+ DWORD dwObjIndex;
+ bool fSharedSynchLock = false;
+
+ // Lock
+ AcquireLocalSynchLock(pthrWorker);
+ AcquireSharedSynchLock(pthrWorker);
+ fSharedSynchLock = true;
+
+ pWLNode = SharedIDToTypePointer(WaitingThreadsListNode,
+ shridMarshaledData);
+
+ _ASSERT_MSG(NULL != pWLNode, "Received bad Shared ID %p\n",
+ shridMarshaledData);
+ _ASSERT_MSG(gPID == pWLNode->dwProcessId,
+ "Remote signal apparently sent to the wrong "
+ "process [target pid=%u current pid=%u]\n",
+ pWLNode->dwProcessId, gPID);
+ _ASSERT_MSG(0 == (WTLN_FLAG_WAIT_ALL & pWLNode->dwFlags),
+ "Wait all with remote awakening delegated "
+ "through SynchWorkerCmdRemoteSignal rather than "
+ "SynchWorkerCmdDelegatedObjectSignaling\n");
+
+
+ // Get the object index
+ dwObjIndex = pWLNode->dwObjIndex;
+
+ // Get the WaitInfo
+ ptwiWaitInfo = pWLNode->ptwiWaitInfo;
+
+ // Initialize the WakeUpReason to WaitSucceeded
+ twrWakeUpReason = WaitSucceeded;
+
+ CSynchData * psdSynchData =
+ SharedIDToTypePointer(CSynchData,
+ pWLNode->ptrOwnerObjSynchData.shrid);
+
+ TRACE("Synch Worker: received REMOTE SIGNAL cmd "
+ "[WInfo=%p {Type=%u Domain=%u ObjCount=%d TgtThread=%x} "
+ "SynchData={shriId=%p p=%p} {SigCount=%d IsAbandoned=%d}\n",
+ ptwiWaitInfo, ptwiWaitInfo->wtWaitType, ptwiWaitInfo->wdWaitDomain,
+ ptwiWaitInfo->lObjCount, ptwiWaitInfo->pthrOwner->GetThreadId(),
+ (VOID *)pWLNode->ptrOwnerObjSynchData.shrid, psdSynchData,
+ psdSynchData->GetSignalCount(), psdSynchData->IsAbandoned());
+
+ if (CObjectType::OwnershipTracked ==
+ psdSynchData->GetObjectType()->GetOwnershipSemantics())
+ {
+ // Abandoned status is not propagated through process
+ // pipe: need to get it from the object itself before
+ // resetting the data by acquiring the object ownership
+ if (psdSynchData->IsAbandoned())
+ {
+ twrWakeUpReason = MutexAbondoned;
+ }
+
+ // Acquire ownership
+ palErr = psdSynchData->AssignOwnershipToThread(
+ pthrWorker,
+ ptwiWaitInfo->pthrOwner);
+ if (NO_ERROR != palErr)
+ {
+ ERROR("Synch Worker: AssignOwnershipToThread "
+ "failed with error %u; ownership data on "
+ "object with SynchData %p may be "
+ "corrupted\n", palErr, psdSynchData);
+ }
+ }
+
+ // Unregister the wait
+ pSynchManager->UnRegisterWait(pthrWorker,
+ ptwiWaitInfo,
+ fSharedSynchLock);
+
+ // pWLNode is no longer valid after UnRegisterWait
+ pWLNode = NULL;
+
+ TRACE("Synch Worker: Waking up local thread %x "
+ "{WakeUpReason=%u ObjIndex=%u}\n",
+ ptwiWaitInfo->pthrOwner->GetThreadId(),
+ twrWakeUpReason, dwObjIndex);
+
+ // Wake up the target thread
+ palErr = WakeUpLocalThread(
+ pthrWorker,
+ ptwiWaitInfo->pthrOwner,
+ twrWakeUpReason,
+ dwObjIndex);
+ if (NO_ERROR != palErr)
+ {
+ ERROR("Synch Worker: Failed to wake up local thread "
+ "%#x while propagating remote signaling: "
+ "object signaling may be lost\n",
+ ptwiWaitInfo->pthrOwner->GetThreadId());
+ }
+
+ // Unlock
+ ReleaseSharedSynchLock(pthrWorker);
+ fSharedSynchLock = false;
+ ReleaseLocalSynchLock(pthrWorker);
+
+ break;
+ }
+ case SynchWorkerCmdDelegatedObjectSignaling:
+ {
+ CSynchData * psdSynchData;
+
+ TRACE("Synch Worker: received "
+ "SynchWorkerCmdDelegatedObjectSignaling\n");
+
+ psdSynchData = SharedIDToTypePointer(CSynchData,
+ shridMarshaledData);
+
+ _ASSERT_MSG(NULL != psdSynchData, "Received bad Shared ID %p\n",
+ shridMarshaledData);
+ _ASSERT_MSG(0 < dwData && (DWORD)INT_MAX > dwData,
+ "Received remote signaling with invalid signal "
+ "count\n");
+
+ // Lock
+ AcquireLocalSynchLock(pthrWorker);
+ AcquireSharedSynchLock(pthrWorker);
+
+ TRACE("Synch Worker: received DELEGATED OBJECT SIGNALING "
+ "cmd [SynchData={shriId=%p p=%p} SigCount=%u] [Current obj SigCount=%d "
+ "IsAbandoned=%d]\n", (VOID *)shridMarshaledData,
+ psdSynchData, dwData, psdSynchData->GetSignalCount(),
+ psdSynchData->IsAbandoned());
+
+ psdSynchData->Signal(pthrWorker,
+ psdSynchData->GetSignalCount() + dwData,
+ true);
+
+ // Current SynchData has been AddRef'd by remote process in
+ // order to be marshaled to the current one, therefore at
+ // this point we need to release it
+ psdSynchData->Release(pthrWorker);
+
+ // Unlock
+ ReleaseSharedSynchLock(pthrWorker);
+ ReleaseLocalSynchLock(pthrWorker);
+
+ break;
+ }
+ case SynchWorkerCmdShutdown:
+ TRACE("Synch Worker: received SynchWorkerCmdShutdown\n");
+
+ // Shutdown the process pipe: this will cause the process
+ // pipe to be unlinked and its write-only file descriptor
+ // to be closed, so that when the last fd opened for write
+ // on the fifo (from another process) will be closed, we
+ // will receive an EOF on the read end (i.e. poll in
+ // ReadBytesFromProcessPipe will return 1 with no data to
+ // be read). That will allow the worker thread to process
+ // possible commands already successfully written to the
+ // pipe by some other process, before shutting down.
+ pSynchManager->ShutdownProcessPipe();
+
+ // Shutting down: this will cause the worker thread to
+ // fetch residual cmds from the process pipe until an
+ // EOF is converted to a SynchWorkerCmdNop or the
+ // WorkerThreadShuttingDownTimeout has elapsed without
+ // receiving any cmd.
+ fShuttingDown = true;
+
+ // Set the timeout to WorkerThreadShuttingDownTimeout
+ iPollTimeout = WorkerThreadShuttingDownTimeout;
+ break;
+ default:
+ ASSERT("Synch Worker: Unknown worker cmd [swcWorkerCmd=%d]\n",
+ swcCmd);
+ break;
+ }
+ }
+
+ int iRet;
+ ThreadNativeWaitData * ptnwdWorkerThreadNativeData =
+ &pthrWorker->synchronizationInfo.m_tnwdNativeData;
+
+ // Using the worker thread's predicate/condition/mutex
+ // (that normally are never used) to signal the shutting
+ // down thread that the worker thread is done
+ iRet = pthread_mutex_lock(&ptnwdWorkerThreadNativeData->mutex);
+ _ASSERT_MSG(0 == iRet, "Cannot lock mutex [err=%d]\n", iRet);
+
+ ptnwdWorkerThreadNativeData->iPred = TRUE;
+
+ iRet = pthread_cond_signal(&ptnwdWorkerThreadNativeData->cond);
+ if (0 != iRet)
+ {
+ ERROR ("pthread_cond_signal returned %d [errno=%d (%s)]\n",
+ iRet, errno, strerror(errno));
+ }
+
+ iRet = pthread_mutex_unlock(&ptnwdWorkerThreadNativeData->mutex);
+ _ASSERT_MSG(0 == iRet, "Cannot lock mutex [err=%d]\n", iRet);
+
+ // Sleep forever
+ ThreadPrepareForShutdown();
+
+ return 0;
+ }
+
+ /*++
+ Method:
+ CPalSynchronizationManager::ReadCmdFromProcessPipe
+
+ Reads a worker thread cmd from the process pipe. If there is no data
+ to be read on the pipe, it blocks until there is data available or the
+ timeout expires.
+ --*/
+ PAL_ERROR CPalSynchronizationManager::ReadCmdFromProcessPipe(
+ int iPollTimeout,
+ SynchWorkerCmd * pswcWorkerCmd,
+ SharedID * pshridMarshaledData,
+ DWORD * pdwData)
+ {
+ int iRet;
+ BYTE byVal;
+ SynchWorkerCmd swcWorkerCmd = SynchWorkerCmdNop;
+
+ _ASSERTE(NULL != pswcWorkerCmd);
+ _ASSERTE(NULL != pshridMarshaledData);
+ _ASSERTE(NULL != pdwData);
+
+ iRet = ReadBytesFromProcessPipe(iPollTimeout, &byVal, sizeof(BYTE));
+
+ if (0 > iRet)
+ {
+ ERROR("Failed polling the process pipe [ret=%d errno=%d (%s)]\n",
+ iRet, errno, strerror(errno));
+
+ return ERROR_INTERNAL_ERROR;
+ }
+
+ if (iRet != 0)
+ {
+ _ASSERT_MSG(sizeof(BYTE) == iRet,
+ "Got %d bytes from process pipe while expecting for %d\n",
+ iRet, sizeof(BYTE));
+
+ swcWorkerCmd = (SynchWorkerCmd)byVal;
+
+ if (SynchWorkerCmdLast <= swcWorkerCmd)
+ {
+ ERROR("Got unknown worker command code %d from the process "
+ "pipe!\n", swcWorkerCmd);
+
+ return ERROR_INTERNAL_ERROR;
+ }
+
+ _ASSERT_MSG(SynchWorkerCmdNop == swcWorkerCmd ||
+ SynchWorkerCmdRemoteSignal == swcWorkerCmd ||
+ SynchWorkerCmdDelegatedObjectSignaling == swcWorkerCmd ||
+ SynchWorkerCmdShutdown == swcWorkerCmd ||
+ SynchWorkerCmdTerminationRequest == swcWorkerCmd,
+ "Unknown worker command code %u\n", swcWorkerCmd);
+
+ TRACE("Got cmd %u from process pipe\n", swcWorkerCmd);
+ }
+
+ if (SynchWorkerCmdRemoteSignal == swcWorkerCmd ||
+ SynchWorkerCmdDelegatedObjectSignaling == swcWorkerCmd)
+ {
+ SharedID shridMarshaledId = NULLSharedID;
+
+ TRACE("Received %s cmd\n",
+ (swcWorkerCmd == SynchWorkerCmdRemoteSignal) ?
+ "REMOTE SIGNAL" : "DELEGATED OBJECT SIGNALING" );
+
+ iRet = ReadBytesFromProcessPipe(WorkerCmdCompletionTimeout,
+ (BYTE *)&shridMarshaledId,
+ sizeof(shridMarshaledId));
+ if (sizeof(shridMarshaledId) != iRet)
+ {
+ ERROR("Unable to read marshaled Shared ID from the "
+ "process pipe [pipe=%d ret=%d errno=%d (%s)]\n",
+ m_iProcessPipeRead, iRet, errno, strerror(errno));
+
+ return ERROR_INTERNAL_ERROR;
+ }
+
+ TRACE("Received marshaled shrid=%p\n", (VOID *)shridMarshaledId);
+
+ *pshridMarshaledData = shridMarshaledId;
+ }
+
+ if (SynchWorkerCmdDelegatedObjectSignaling == swcWorkerCmd)
+ {
+ DWORD dwData;
+
+ iRet = ReadBytesFromProcessPipe(WorkerCmdCompletionTimeout,
+ (BYTE *)&dwData,
+ sizeof(dwData));
+ if (sizeof(dwData) != iRet)
+ {
+ ERROR("Unable to read signal count from the "
+ "process pipe [pipe=%d ret=%d errno=%d (%s)]\n",
+ m_iProcessPipeRead, iRet, errno, strerror(errno));
+
+ return ERROR_INTERNAL_ERROR;
+ }
+
+ TRACE("Received signal count %u\n", dwData);
+
+ *pdwData = dwData;
+ }
+
+ *pswcWorkerCmd = swcWorkerCmd;
+ return NO_ERROR;
+ }
+
+ /*++
+ Method:
+ CPalSynchronizationManager::ReadBytesFromProcessPipe
+
+ Reads the specified number of bytes from the process pipe. If there is
+ no data to be read on the pipe, it blocks until there is data available
+ or the timeout expires.
+ --*/
+ int CPalSynchronizationManager::ReadBytesFromProcessPipe(
+ int iTimeout,
+ BYTE * pRecvBuf,
+ LONG iBytes)
+ {
+#if !HAVE_KQUEUE
+ struct pollfd Poll;
+#endif // !HAVE_KQUEUE
+ int iRet = -1;
+ int iConsecutiveEintrs = 0;
+ LONG iBytesRead = 0;
+ BYTE * pPos = pRecvBuf;
+#if HAVE_KQUEUE && !HAVE_BROKEN_FIFO_KEVENT
+ struct kevent keChanges;
+ struct timespec ts, *pts;
+ int iNChanges;
+#endif // HAVE_KQUEUE
+
+ _ASSERTE(0 <= iBytes);
+
+ do
+ {
+ while (TRUE)
+ {
+ int iErrno = 0;
+#if HAVE_KQUEUE
+#if HAVE_BROKEN_FIFO_KEVENT
+#if HAVE_BROKEN_FIFO_SELECT
+#error Found no way to wait on a FIFO.
+#endif
+
+ timeval *ptv;
+ timeval tv;
+
+ if (INFTIM == iTimeout)
+ {
+ ptv = NULL;
+ }
+ else
+ {
+ tv.tv_usec = (iTimeout % tccSecondsToMillieSeconds) *
+ tccMillieSecondsToMicroSeconds;
+ tv.tv_sec = iTimeout / tccSecondsToMillieSeconds;
+ ptv = &tv;
+ }
+
+ fd_set readfds;
+ FD_ZERO(&readfds);
+ FD_SET(m_iProcessPipeRead, &readfds);
+ iRet = select(m_iProcessPipeRead + 1, &readfds, NULL, NULL, ptv);
+
+#else // HAVE_BROKEN_FIFO_KEVENT
+
+ // Note: FreeBSD needs to use kqueue/kevent support here, since on this
+ // platform the EOF notification on FIFOs is not surfaced through poll,
+ // and process pipe shutdown relies on this feature.
+ // If a thread is polling a FIFO or a pipe for POLLIN, when the last
+ // write descriptor for that pipe is closed, poll() is supposed to
+ // return with a POLLIN event but no data to be read on the FIFO/pipe,
+ // which means EOF.
+ // On FreeBSD such feature works for pipes but it doesn't for FIFOs.
+ // Using kevent the EOF is instead surfaced correctly.
+
+ if (iBytes > m_keProcessPipeEvent.data)
+ {
+ if (INFTIM == iTimeout)
+ {
+ pts = NULL;
+ }
+ else
+ {
+ ts.tv_nsec = (iTimeout % tccSecondsToMillieSeconds) *
+ tccMillieSecondsToNanoSeconds;
+ ts.tv_sec = iTimeout / tccSecondsToMillieSeconds;
+ pts = &ts;
+ }
+
+ if (0 != (EV_EOF & m_keProcessPipeEvent.flags))
+ {
+ TRACE("Refreshing kevent settings\n");
+ EV_SET(&keChanges, m_iProcessPipeRead, EVFILT_READ,
+ EV_ADD | EV_CLEAR, 0, 0, 0);
+ iNChanges = 1;
+ }
+ else
+ {
+ iNChanges = 0;
+ }
+
+ iRet = kevent(m_iKQueue, &keChanges, iNChanges,
+ &m_keProcessPipeEvent, 1, pts);
+
+ if (0 < iRet)
+ {
+ _ASSERTE(1 == iRet);
+ _ASSERTE(EVFILT_READ == m_keProcessPipeEvent.filter);
+
+ if (EV_ERROR & m_keProcessPipeEvent.flags)
+ {
+ ERROR("EV_ERROR from kevent [ident=%d filter=%d flags=%x]\n", m_keProcessPipeEvent.ident, m_keProcessPipeEvent.filter, m_keProcessPipeEvent.flags);
+ iRet = -1;
+ iErrno = m_keProcessPipeEvent.data;
+ m_keProcessPipeEvent.data = 0;
+ }
+ }
+ else if (0 > iRet)
+ {
+ iErrno = errno;
+ }
+
+ TRACE("Woken up from kevent() with ret=%d flags=%#x data=%d "
+ "[iTimeout=%d]\n", iRet, m_keProcessPipeEvent.flags,
+ m_keProcessPipeEvent.data, iTimeout);
+ }
+ else
+ {
+ // There is enough data already available in the buffer, just use that.
+ iRet = 1;
+ }
+
+#endif // HAVE_BROKEN_FIFO_KEVENT
+#else // HAVE_KQUEUE
+
+ Poll.fd = m_iProcessPipeRead;
+ Poll.events = POLLIN;
+ Poll.revents = 0;
+
+ iRet = poll(&Poll, 1, iTimeout);
+
+ TRACE("Woken up from poll() with ret=%d [iTimeout=%d]\n",
+ iRet, iTimeout);
+
+ if (1 == iRet &&
+ ((POLLERR | POLLHUP | POLLNVAL) & Poll.revents))
+ {
+ // During PAL shutdown the pipe gets closed and Poll.revents is set to POLLHUP
+ // (note: no other flags are set). We will also receive an EOF on from the read call.
+ // Please see the comment for SynchWorkerCmdShutdown in CPalSynchronizationManager::WorkerThread.
+ if (!PALIsShuttingDown() || (Poll.revents != POLLHUP))
+ {
+ ERROR("Unexpected revents=%x while polling pipe %d\n",
+ Poll.revents, Poll.fd);
+ iErrno = EINVAL;
+ iRet = -1;
+ }
+ }
+ else if (0 > iRet)
+ {
+ iErrno = errno;
+ }
+
+#endif // HAVE_KQUEUE
+
+ if (0 == iRet || 1 == iRet)
+ {
+ // 0 == wait timed out
+ // 1 == FIFO has data available
+ break;
+ }
+ else
+ {
+ if (1 < iRet)
+ {
+ // Unexpected iRet > 1
+ ASSERT("Unexpected return code %d from blocking poll/kevent call\n",
+ iRet);
+ goto RBFPP_exit;
+ }
+
+ if (EINTR != iErrno)
+ {
+ // Unexpected error
+ ASSERT("Unexpected error from blocking poll/kevent call: %d (%s)\n",
+ iErrno, strerror(iErrno));
+ goto RBFPP_exit;
+ }
+
+ iConsecutiveEintrs++;
+ TRACE("poll() failed with EINTR; re-polling\n");
+
+ if (iConsecutiveEintrs >= MaxWorkerConsecutiveEintrs)
+ {
+ if (iTimeout != INFTIM)
+ {
+ WARN("Receiving too many EINTRs; converting one of them "
+ "to a timeout");
+ iRet = 0;
+ break;
+ }
+ else if (0 == (iConsecutiveEintrs % MaxWorkerConsecutiveEintrs))
+ {
+ WARN("Receiving too many EINTRs [%d so far]",
+ iConsecutiveEintrs);
+ }
+ }
+ }
+ }
+
+ if (0 == iRet)
+ {
+ // Time out
+ break;
+ }
+ else
+ {
+#if HAVE_KQUEUE && !HAVE_BROKEN_FIFO_KEVENT
+ if (0 != (EV_EOF & m_keProcessPipeEvent.flags) && 0 == m_keProcessPipeEvent.data)
+ {
+ // EOF
+ TRACE("Received an EOF on process pipe via kevent\n");
+ goto RBFPP_exit;
+ }
+#endif // HAVE_KQUEUE
+
+ iRet = read(m_iProcessPipeRead, pPos, iBytes - iBytesRead);
+
+ if (0 == iRet)
+ {
+ // Poll returned 1 and read returned zero: this is an EOF,
+ // i.e. no other process has the pipe still open for write
+ TRACE("Received an EOF on process pipe via poll\n");
+ goto RBFPP_exit;
+ }
+ else if (0 > iRet)
+ {
+ ERROR("Unable to read %d bytes from the the process pipe "
+ "[pipe=%d ret=%d errno=%d (%s)]\n", iBytes - iBytesRead,
+ m_iProcessPipeRead, iRet, errno, strerror(errno));
+ goto RBFPP_exit;
+ }
+
+ TRACE("Read %d bytes from process pipe\n", iRet);
+
+ iBytesRead += iRet;
+ pPos += iRet;
+
+#if HAVE_KQUEUE && !HAVE_BROKEN_FIFO_KEVENT
+ // Update available data count
+ m_keProcessPipeEvent.data -= iRet;
+ _ASSERTE(0 <= m_keProcessPipeEvent.data);
+#endif // HAVE_KQUEUE
+ }
+ } while(iBytesRead < iBytes);
+
+ RBFPP_exit:
+ return (iRet < 0) ? iRet : iBytesRead;
+ }
+
+ /*++
+ Method:
+ CPalSynchronizationManager::WakeUpLocalThread
+
+ Wakes up a local thead currently sleeping for a wait or a sleep
+ --*/
+ PAL_ERROR CPalSynchronizationManager::WakeUpLocalThread(
+ CPalThread * pthrCurrent,
+ CPalThread * pthrTarget,
+ ThreadWakeupReason twrWakeupReason,
+ DWORD dwObjectIndex)
+ {
+ PAL_ERROR palErr = NO_ERROR;
+ ThreadNativeWaitData * ptnwdNativeWaitData =
+ pthrTarget->synchronizationInfo.GetNativeData();
+
+ TRACE("Waking up a local thread [WakeUpReason=%u ObjectIndex=%u "
+ "ptnwdNativeWaitData=%p]\n", twrWakeupReason, dwObjectIndex,
+ ptnwdNativeWaitData);
+
+ // Set wakeup reason and signaled object index
+ ptnwdNativeWaitData->twrWakeupReason = twrWakeupReason;
+ ptnwdNativeWaitData->dwObjectIndex = dwObjectIndex;
+
+#if SYNCHMGR_SUSPENSION_SAFE_CONDITION_SIGNALING
+ if (0 < GetLocalSynchLockCount(pthrCurrent))
+ {
+ // Defer the actual thread signaling to right after
+ // releasing the synch lock(s), so that signaling
+ // can happen from a thread-suspension safe area
+ palErr = DeferThreadConditionSignaling(pthrCurrent, pthrTarget);
+ }
+ else
+ {
+ // Signal the target thread's condition
+ palErr = SignalThreadCondition(ptnwdNativeWaitData);
+ }
+#else // SYNCHMGR_SUSPENSION_SAFE_CONDITION_SIGNALING
+ // Signal the target thread's condition
+ palErr = SignalThreadCondition(ptnwdNativeWaitData);
+#endif // SYNCHMGR_SUSPENSION_SAFE_CONDITION_SIGNALING
+
+ return palErr;
+ }
+
+#if SYNCHMGR_SUSPENSION_SAFE_CONDITION_SIGNALING
+ /*++
+ Method:
+ CPalSynchronizationManager::DeferThreadConditionSignaling
+
+ Defers thread signaling to the final release of synchronization
+ lock(s), so that condition signaling can happen when the signaling
+ thread is marked as safe for thread suspension.
+ --*/
+ PAL_ERROR CPalSynchronizationManager::DeferThreadConditionSignaling(
+ CPalThread * pthrCurrent,
+ CPalThread * pthrTarget)
+ {
+ PAL_ERROR palErr = NO_ERROR;
+ LONG lCount = pthrCurrent->synchronizationInfo.m_lPendingSignalingCount;
+
+ _ASSERTE(pthrTarget != pthrCurrent);
+
+ if (CThreadSynchronizationInfo::PendingSignalingsArraySize > lCount)
+ {
+ // If there is available room, add the target thread object to
+ // the array of pending thread signalings.
+ pthrCurrent->synchronizationInfo.m_rgpthrPendingSignalings[lCount] = pthrTarget;
+ }
+ else
+ {
+ // If the array is full, add the target thread object at the end
+ // of the overflow list
+ DeferredSignalingListNode * pdsln =
+ InternalNew<DeferredSignalingListNode>();
+
+ if (pdsln)
+ {
+ pdsln->pthrTarget = pthrTarget;
+
+ // Add the note to the end of the list.
+ // Note: no need to synchronize the access to this list since
+ // it is meant to be accessed only by the owner thread.
+ InsertTailList(&pthrCurrent->synchronizationInfo.m_lePendingSignalingsOverflowList,
+ &pdsln->Link);
+ }
+ else
+ {
+ palErr = ERROR_NOT_ENOUGH_MEMORY;
+ }
+ }
+
+ if (NO_ERROR == palErr)
+ {
+ // Increment the count of pending signalings
+ pthrCurrent->synchronizationInfo.m_lPendingSignalingCount += 1;
+
+ // Add a reference to the target CPalThread object; this is
+ // needed since deferring signaling after releasing the synch
+ // locks implies accessing the target thread object without
+ // holding the local synch lock. In rare circumstances, the
+ // target thread may have already exited while deferred signaling
+ // takes place, therefore invalidating the thread object. The
+ // reference added here ensures that the thread object is still
+ // good, even if the target thread has exited.
+ pthrTarget->AddThreadReference();
+ }
+
+ return palErr;
+ }
+#endif // SYNCHMGR_SUSPENSION_SAFE_CONDITION_SIGNALING
+
+ /*++
+ Method:
+ CPalSynchronizationManager::SignalThreadCondition
+
+ Performs the actual condition signaling in to wake up the target thread
+ --*/
+ PAL_ERROR CPalSynchronizationManager::SignalThreadCondition(
+ ThreadNativeWaitData * ptnwdNativeWaitData)
+ {
+ PAL_ERROR palErr = NO_ERROR;
+ int iRet;
+
+ // Lock the mutex
+ iRet = pthread_mutex_lock(&ptnwdNativeWaitData->mutex);
+ if (0 != iRet)
+ {
+ ERROR("Cannot lock mutex [err=%d]\n", iRet);
+ return ERROR_INTERNAL_ERROR;
+ }
+
+ // Set the predicate
+ ptnwdNativeWaitData->iPred = TRUE;
+
+ // Signal the condition
+ iRet = pthread_cond_signal(&ptnwdNativeWaitData->cond);
+ if (0 != iRet)
+ {
+ ERROR("Failed to signal condition: pthread_cond_signal "
+ "returned %d [errno=%d (%s)]\n", iRet, errno,
+ strerror(errno));
+ palErr = ERROR_INTERNAL_ERROR;
+ // Continue in order to unlock the mutex anyway
+ }
+
+ // Unlock the mutex
+ iRet = pthread_mutex_unlock(&ptnwdNativeWaitData->mutex);
+ if (0 != iRet)
+ {
+ ERROR("Cannot unlock mutex [err=%d]\n", iRet);
+ return ERROR_INTERNAL_ERROR;
+ }
+
+ return palErr;
+ }
+
+ /*++
+ Method:
+ CPalSynchronizationManager::ReadBytesFromProcessPipe
+
+ Wakes up a remote thead currently sleeping for a wait or a sleep
+ by sending the appropriate cmd to the remote process' worker
+ thread, which will take care to convert this command into a
+ WakeUpLocalThread in the remote process
+ --*/
+ PAL_ERROR CPalSynchronizationManager::WakeUpRemoteThread(
+ SharedID shridWLNode)
+ {
+ const int MsgSize = sizeof(BYTE) + sizeof(SharedID);
+ PAL_ERROR palErr = NO_ERROR;
+ BYTE rgSendBuf[MsgSize];
+ BYTE * pbySrc, * pbyDst = rgSendBuf;
+ WaitingThreadsListNode * pWLNode = SharedIDToTypePointer(WaitingThreadsListNode, shridWLNode);
+
+ _ASSERT_MSG(gPID != pWLNode->dwProcessId, "WakeUpRemoteThread called on local thread\n");
+ _ASSERT_MSG(NULLSharedID != shridWLNode, "NULL shared identifier\n");
+ _ASSERT_MSG(NULL != pWLNode, "Bad shared wait list node identifier (%p)\n", (VOID*)shridWLNode);
+ _ASSERT_MSG(MsgSize <= PIPE_BUF, "Message too long [MsgSize=%d PIPE_BUF=%d]\n", MsgSize, (int)PIPE_BUF);
+
+ TRACE("Waking up remote thread {pid=%x, tid=%x} by sending cmd=%u and shridWLNode=%p over process pipe\n",
+ pWLNode->dwProcessId, pWLNode->dwThreadId, SynchWorkerCmdRemoteSignal, (VOID *)shridWLNode);
+
+ // Prepare the message
+ // Cmd
+ *pbyDst++ = (BYTE)(SynchWorkerCmdRemoteSignal & 0xFF);
+
+ // WaitingThreadsListNode (not aligned, copy byte by byte)
+ pbySrc = (BYTE *)&shridWLNode;
+ for (int i = 0; i < (int)sizeof(SharedID); i++)
+ {
+ *pbyDst++ = *pbySrc++;
+ }
+
+ _ASSERT_MSG(pbyDst <= rgSendBuf + MsgSize + 1, "Buffer overrun");
+
+ // Send the message
+ palErr = SendMsgToRemoteWorker(pWLNode->dwProcessId, rgSendBuf, MsgSize);
+ if (NO_ERROR != palErr)
+ {
+ ERROR("Failed sending message to remote worker in process %u\n", pWLNode->dwProcessId);
+ }
+
+ return palErr;
+ }
+
+ /*++
+ Method:
+ CPalSynchronizationManager::DelegateSignalingToRemoteProcess
+
+ This method transfers an object signaling operation to a remote process,
+ where it will be performed by the worker thread. Such delegation takes
+ place when the currently processed thread (among those waiting on the
+ signald object) lives in a different process as the signaling thread,
+ and it is performing a wait all. In this case generally is not possible
+ to find out whether or not the wait all is satisfied, therefore the
+ signaling operation must be continued in the target process.
+ --*/
+ PAL_ERROR CPalSynchronizationManager::DelegateSignalingToRemoteProcess(
+ CPalThread * pthrCurrent,
+ DWORD dwTargetProcessId,
+ SharedID shridSynchData)
+ {
+ const int MsgSize = sizeof(BYTE) + sizeof(SharedID) + sizeof(DWORD);
+ int i;
+ PAL_ERROR palErr = NO_ERROR;
+ BYTE rgSendBuf[MsgSize];
+ BYTE * pbySrc, * pbyDst = rgSendBuf;
+ DWORD dwSigCount;
+ CSynchData * psdSynchData =
+ SharedIDToTypePointer(CSynchData, shridSynchData);
+
+ _ASSERT_MSG(gPID != dwTargetProcessId, " called on local thread\n");
+ _ASSERT_MSG(NULLSharedID != shridSynchData, "NULL shared identifier\n");
+ _ASSERT_MSG(NULL != psdSynchData, "Bad shared SynchData identifier (%p)\n", (VOID*)shridSynchData);
+ _ASSERT_MSG(MsgSize <= PIPE_BUF, "Message too long [MsgSize=%d PIPE_BUF=%d]\n", MsgSize, (int)PIPE_BUF);
+
+ TRACE("Transfering wait all signaling to remote process pid=%x by sending cmd=%u and shridSynchData=%p over process pipe\n",
+ dwTargetProcessId, SynchWorkerCmdDelegatedObjectSignaling, (VOID *)shridSynchData);
+
+ dwSigCount = psdSynchData->GetSignalCount();
+
+ // AddRef SynchData to be marshaled to remote process
+ psdSynchData->AddRef();
+
+ //
+ // Prepare the message
+ //
+
+ // Cmd
+ *pbyDst++ = (BYTE)(SynchWorkerCmdDelegatedObjectSignaling & 0xFF);
+
+ // CSynchData (not aligned, copy byte by byte)
+ pbySrc = (BYTE *)&shridSynchData;
+ for (i=0; i<(int)sizeof(SharedID); i++)
+ {
+ *pbyDst++ = *pbySrc++;
+ }
+
+ // Signal Count (not aligned, copy byte by byte)
+ pbySrc = (BYTE *)&dwSigCount;
+ for (i=0; i<(int)sizeof(DWORD); i++)
+ {
+ *pbyDst++ = *pbySrc++;
+ }
+
+ _ASSERT_MSG(pbyDst <= rgSendBuf + MsgSize + 1, "Buffer overrun");
+
+ // Send the message
+ palErr = SendMsgToRemoteWorker(dwTargetProcessId, rgSendBuf, MsgSize);
+ if (NO_ERROR != palErr)
+ {
+ TRACE("Failed sending message to remote worker in process %u\n", dwTargetProcessId);
+
+ // Undo refcounting
+ psdSynchData->Release(pthrCurrent);
+ }
+
+ return palErr;
+ }
+
+ /*++
+ Method:
+ CPalSynchronizationManager::SendMsgToRemoteWorker
+
+ Sends a message (command + data) to a remote process's worker thread.
+ --*/
+ PAL_ERROR CPalSynchronizationManager::SendMsgToRemoteWorker(
+ DWORD dwProcessId,
+ BYTE * pMsg,
+ int iMsgSize)
+ {
+#ifndef CORECLR
+ PAL_ERROR palErr = NO_ERROR;
+ int iProcessPipe, iBytesToWrite, iRetryCount;
+ ssize_t sszRet;
+ char strPipeFilename[MAX_PATH];
+ BYTE * pPos = pMsg;
+ bool fRet;
+ CPalThread *pthrCurrent = InternalGetCurrentThread();
+
+ _ASSERT_MSG(gPID != dwProcessId, "SendMsgToRemoteWorker called with local process as target process\n");
+
+ fRet = GetProcessPipeName(strPipeFilename, MAX_PATH, dwProcessId);
+
+ _ASSERT_MSG(fRet, "Failed to retrieve process pipe's name!\n");
+
+ iProcessPipe = InternalOpen(strPipeFilename, O_WRONLY);
+ if (-1 == iProcessPipe)
+ {
+ ERROR("Unable to open a process pipe to wake up a remote thread "
+ "[pid=%u errno=%d (%s) PipeFilename=%s]\n", dwProcessId,
+ errno, strerror(errno), strPipeFilename);
+ palErr = ERROR_INTERNAL_ERROR;
+ goto SMTRW_exit;
+ }
+
+ pPos = pMsg;
+ iBytesToWrite = iMsgSize;
+ while (0 < iBytesToWrite)
+ {
+ iRetryCount = 0;
+ do
+ {
+ sszRet = write(iProcessPipe, pPos, iBytesToWrite);
+ } while (-1 == sszRet &&
+ EAGAIN == errno &&
+ ++iRetryCount < MaxConsecutiveEagains &&
+ 0 == sched_yield());
+
+ if (0 >= sszRet)
+ {
+ ERROR("Error writing message to process pipe %d [target_pid=%u "
+ "bytes_to_write=%d bytes_written=%d ret=%d errno=%d (%s) "
+ "PipeFilename=%s]\n", iProcessPipe, dwProcessId, iMsgSize,
+ iMsgSize - iBytesToWrite, (int)sszRet, errno, strerror(errno),
+ strPipeFilename);
+ palErr = ERROR_INTERNAL_ERROR;
+ break;
+ }
+ iBytesToWrite -= (int)sszRet;
+ pPos += sszRet;
+
+ _ASSERT_MSG(0 == iBytesToWrite,
+ "Interleaved messages while writing to process pipe %d\n",
+ iProcessPipe);
+ }
+
+ // Close the opened pipe
+ close(iProcessPipe);
+
+ SMTRW_exit:
+ return palErr;
+#else // !CORECLR
+ ASSERT("There should never be a reason to send a message to a remote worker\n");
+ return ERROR_INTERNAL_ERROR;
+#endif // !CORECLR
+ }
+
+ /*++
+ Method:
+ CPalSynchronizationManager::WakeUpLocalWorkerThread
+
+ Wakes up the local worker thread by writing a 'nop' cmd to the
+ process pipe.
+ --*/
+ PAL_ERROR CPalSynchronizationManager::WakeUpLocalWorkerThread(
+ SynchWorkerCmd swcWorkerCmd)
+ {
+ PAL_ERROR palErr = NO_ERROR;
+
+ _ASSERT_MSG((swcWorkerCmd & 0xFF) == swcWorkerCmd,
+ "Value too big for swcWorkerCmd\n");
+
+ _ASSERT_MSG((SynchWorkerCmdNop == swcWorkerCmd) ||
+ (SynchWorkerCmdShutdown == swcWorkerCmd) ||
+ (SynchWorkerCmdTerminationRequest == swcWorkerCmd),
+ "WakeUpLocalWorkerThread supports only SynchWorkerCmdNop, SynchWorkerCmdShutdown, and SynchWorkerCmdTerminationRequest."
+ "[received cmd=%d]\n", swcWorkerCmd);
+
+ BYTE byCmd = (BYTE)(swcWorkerCmd & 0xFF);
+
+ TRACE("Waking up Synch Worker Thread for %u [byCmd=%u]\n",
+ swcWorkerCmd, (unsigned int)byCmd);
+
+ // As long as we use pipes and we keep the message size
+ // within PIPE_BUF, there's no need to lock here, since the
+ // write is guaranteed not to be interleaved with/into other
+ // writes of PIPE_BUF bytes or less.
+ _ASSERT_MSG(sizeof(BYTE) <= PIPE_BUF, "Message too long\n");
+
+ int iRetryCount = 0;
+ ssize_t sszWritten;
+ do
+ {
+ sszWritten = write(m_iProcessPipeWrite, &byCmd, sizeof(BYTE));
+ } while (-1 == sszWritten &&
+ EAGAIN == errno &&
+ ++iRetryCount < MaxConsecutiveEagains &&
+ 0 == sched_yield());
+
+ if (sszWritten != sizeof(BYTE))
+ {
+ ERROR("Unable to write to the process pipe to wake up the "
+ "worker thread [errno=%d (%s)]\n", errno, strerror(errno));
+ palErr = ERROR_INTERNAL_ERROR;
+ }
+
+ return palErr;
+ }
+
+ /*++
+ Method:
+ CPalSynchronizationManager::GetThreadWaitInfo
+
+ Returns a pointer to the WaitInfo structure for the passed CPalThread object
+ --*/
+ ThreadWaitInfo * CPalSynchronizationManager::GetThreadWaitInfo(
+ CPalThread * pthrCurrent)
+ {
+ return &pthrCurrent->synchronizationInfo.m_twiWaitInfo;
+ }
+
+ /*++
+ Method:
+ CPalSynchronizationManager::UnRegisterWait
+
+ Unregister the wait described by ptwiWaitInfo that in general involves
+ a thread other than the current one (most of the times the deregistration
+ is performed by the signaling thread)
+
+ Note: this method must be called while holding the local process
+ synchronization lock.
+ --*/
+ void CPalSynchronizationManager::UnRegisterWait(
+ CPalThread * pthrCurrent,
+ ThreadWaitInfo * ptwiWaitInfo,
+ bool fHaveSharedLock)
+ {
+ int i = 0;
+ CSynchData * psdSynchData = NULL;
+ bool fSharedSynchLock = false;
+
+ if (!fHaveSharedLock && LocalWait != ptwiWaitInfo->wdWaitDomain)
+ {
+ AcquireSharedSynchLock(pthrCurrent);
+ fSharedSynchLock = true;
+ }
+
+ TRACE("Unregistering wait for thread=%u [ObjCount=%d WaitType=%u WaitDomain=%u]\n",
+ ptwiWaitInfo->pthrOwner->GetThreadId(),
+ ptwiWaitInfo->lObjCount, ptwiWaitInfo->wtWaitType,
+ ptwiWaitInfo->wdWaitDomain);
+
+ for (i=0; i < ptwiWaitInfo->lObjCount; i++)
+ {
+ WaitingThreadsListNode * pwtlnItem = ptwiWaitInfo->rgpWTLNodes[i];
+
+ VALIDATEOBJECT(pwtlnItem);
+
+ if (pwtlnItem->dwFlags & WTLN_FLAG_OWNER_OBJECT_IS_SHARED)
+ {
+ // Shared object
+ WaitingThreadsListNode * pwtlnItemNext, * pwtlnItemPrev;
+
+ psdSynchData = SharedIDToTypePointer(CSynchData,
+ pwtlnItem->ptrOwnerObjSynchData.shrid);
+
+ VALIDATEOBJECT(psdSynchData);
+
+ pwtlnItemNext = SharedIDToTypePointer(WaitingThreadsListNode,
+ pwtlnItem->ptrNext.shrid);
+ pwtlnItemPrev = SharedIDToTypePointer(WaitingThreadsListNode,
+ pwtlnItem->ptrPrev.shrid);
+ if (pwtlnItemPrev)
+ {
+ VALIDATEOBJECT(pwtlnItemPrev);
+ pwtlnItemPrev->ptrNext.shrid = pwtlnItem->ptrNext.shrid;
+ }
+ else
+ {
+ psdSynchData->SetWTLHeadShrPtr(pwtlnItem->ptrNext.shrid);
+ }
+
+ if (pwtlnItemNext)
+ {
+ VALIDATEOBJECT(pwtlnItemNext);
+ pwtlnItemNext->ptrPrev.shrid = pwtlnItem->ptrPrev.shrid;
+ }
+ else
+ {
+ psdSynchData->SetWTLTailShrPtr(pwtlnItem->ptrPrev.shrid);
+ }
+
+ m_cacheSHRWTListNodes.Add(pthrCurrent, pwtlnItem->shridSHRThis);
+ }
+ else
+ {
+ // Local object
+ psdSynchData = pwtlnItem->ptrOwnerObjSynchData.ptr;
+
+ VALIDATEOBJECT(psdSynchData);
+
+ if (pwtlnItem->ptrPrev.ptr)
+ {
+ VALIDATEOBJECT(pwtlnItem);
+ pwtlnItem->ptrPrev.ptr->ptrNext.ptr = pwtlnItem->ptrNext.ptr;
+ }
+ else
+ {
+ psdSynchData->SetWTLHeadPtr(pwtlnItem->ptrNext.ptr);
+ }
+
+ if (pwtlnItem->ptrNext.ptr)
+ {
+ VALIDATEOBJECT(pwtlnItem);
+ pwtlnItem->ptrNext.ptr->ptrPrev.ptr = pwtlnItem->ptrPrev.ptr;
+ }
+ else
+ {
+ psdSynchData->SetWTLTailPtr(pwtlnItem->ptrPrev.ptr);
+ }
+
+ m_cacheWTListNodes.Add(pthrCurrent, pwtlnItem);
+ }
+
+ // Release the node's refcount on the synch data, and decerement
+ // waiting thread count
+ psdSynchData->DecrementWaitingThreadCount();
+ psdSynchData->Release(pthrCurrent);
+ }
+
+ // Reset wait data in ThreadWaitInfo structure: it is enough
+ // to reset lObjCount, lSharedObjCount and wdWaitDomain.
+ ptwiWaitInfo->lObjCount = 0;
+ ptwiWaitInfo->lSharedObjCount = 0;
+ ptwiWaitInfo->wdWaitDomain = LocalWait;
+
+ // Done
+ if (fSharedSynchLock)
+ {
+ ReleaseSharedSynchLock(pthrCurrent);
+ }
+
+ return;
+ }
+
+ /*++
+ Method:
+ CPalSynchronizationManager::UnsignalRestOfLocalAwakeningWaitAll
+
+ Unsignals all the objects involved in a wait all, except the target
+ one (i.e. psdTgtObjectSynchData)
+
+ Note: this method must be called while holding the synchronization locks
+ appropriate to all the objects involved in the wait-all. If any
+ of the objects is shared, the caller must own both local and
+ shared synch locks; if no shared object is involved in the wait,
+ only the local synch lock is needed.
+ --*/
+ void CPalSynchronizationManager::UnsignalRestOfLocalAwakeningWaitAll(
+ CPalThread * pthrCurrent,
+ CPalThread * pthrTarget,
+ WaitingThreadsListNode * pwtlnNode,
+ CSynchData * psdTgtObjectSynchData)
+ {
+ PAL_ERROR palErr = NO_ERROR;
+ CSynchData * psdSynchDataItem = NULL;
+
+#ifdef _DEBUG
+ bool bOriginatingNodeFound = false;
+#endif
+
+ VALIDATEOBJECT(psdTgtObjectSynchData);
+ VALIDATEOBJECT(pwtlnNode);
+
+ _ASSERT_MSG(0 != (WTLN_FLAG_WAIT_ALL & pwtlnNode->dwFlags),
+ "UnsignalRestOfLocalAwakeningWaitAll() called on a normal (non wait all) wait");
+
+ _ASSERT_MSG(gPID == pwtlnNode->dwProcessId,
+ "UnsignalRestOfLocalAwakeningWaitAll() called on a wait all with remote awakening");
+
+ ThreadWaitInfo *ptwiWaitInfo = pwtlnNode->ptwiWaitInfo;
+
+ int iObjCount = ptwiWaitInfo->lObjCount;
+ for (int i = 0; i < iObjCount; i++)
+ {
+ WaitingThreadsListNode * pwtlnItem = ptwiWaitInfo->rgpWTLNodes[i];
+
+ VALIDATEOBJECT(pwtlnItem);
+
+ if (0 != (WTLN_FLAG_OWNER_OBJECT_IS_SHARED & pwtlnItem->dwFlags))
+ {
+ psdSynchDataItem = SharedIDToTypePointer(CSynchData, pwtlnItem->ptrOwnerObjSynchData.shrid);
+ }
+ else
+ {
+ psdSynchDataItem = pwtlnItem->ptrOwnerObjSynchData.ptr;
+ }
+
+ VALIDATEOBJECT(psdSynchDataItem);
+
+ // Skip originating node
+ if (psdTgtObjectSynchData == psdSynchDataItem)
+ {
+#ifdef _DEBUG
+ bOriginatingNodeFound = true;
+#endif
+ continue;
+ }
+
+ palErr = psdSynchDataItem->ReleaseWaiterWithoutBlocking(pthrCurrent, pthrTarget);
+ if (NO_ERROR != palErr)
+ {
+ ERROR("ReleaseWaiterWithoutBlocking failed on SynchData @ %p [palErr = %u]\n", psdSynchDataItem, palErr);
+ }
+ }
+
+ _ASSERT_MSG(bOriginatingNodeFound, "Couldn't find originating node while unsignaling rest of the wait all\n");
+ }
+
+ /*++
+ Method:
+ CPalSynchronizationManager::MarkWaitForDelegatedObjectSignalingInProgress
+
+ Marks all the thread waiting list nodes involved in the the current wait-all
+ for "delegated object signaling in progress", so that this wait cannot be
+ involved in another delegated object signaling that may happen while the
+ current object singaling is being tranfered to the target process (while
+ transfering it, synchronization locks are released in this process and later
+ grabbed again in the target process; in this time window another thread
+ could signal another object part of the same wait-all. In this case no
+ signal delegation must take place.
+
+ Note: this method must be called while holding the synchronization locks
+ appropriate to the target object described by pwtlnNode (i.e. the
+ local process synch lock if the target object is local, both local
+ and shared one if the object is shared).
+ --*/
+ void CPalSynchronizationManager::MarkWaitForDelegatedObjectSignalingInProgress(
+ CPalThread * pthrCurrent,
+ WaitingThreadsListNode * pwtlnNode)
+ {
+ bool fSharedSynchLock = false;
+ bool fTargetObjectIsShared = (0 != (WTLN_FLAG_OWNER_OBJECT_IS_SHARED & pwtlnNode->dwFlags));
+
+ VALIDATEOBJECT(pwtlnNode);
+
+ _ASSERT_MSG(gPID == pwtlnNode->dwProcessId,
+ "MarkWaitForDelegatedObjectSignalingInProgress() called from the wrong process");
+
+ ThreadWaitInfo *ptwiWaitInfo = pwtlnNode->ptwiWaitInfo;
+
+ if (!fSharedSynchLock && !fTargetObjectIsShared &&
+ LocalWait != ptwiWaitInfo->wdWaitDomain)
+ {
+ AcquireSharedSynchLock(pthrCurrent);
+ fSharedSynchLock = true;
+ }
+
+ _ASSERT_MSG(MultipleObjectsWaitAll == ptwiWaitInfo->wtWaitType,
+ "MarkWaitForDelegatedObjectSignalingInProgress() called on a normal (non wait-all) wait");
+
+ // Unmark all nodes other than the target one
+ int iTgtCount = ptwiWaitInfo->lObjCount;
+ for (int i = 0; i < iTgtCount; i++)
+ {
+ VALIDATEOBJECT(ptwiWaitInfo->rgpWTLNodes[i]);
+ ptwiWaitInfo->rgpWTLNodes[i]->dwFlags &= ~WTLN_FLAG_DELEGATED_OBJECT_SIGNALING_IN_PROGRESS;
+ }
+
+ // Mark the target node
+ pwtlnNode->dwFlags |= WTLN_FLAG_DELEGATED_OBJECT_SIGNALING_IN_PROGRESS;
+
+ // Done
+ if (fSharedSynchLock)
+ {
+ ReleaseSharedSynchLock(pthrCurrent);
+ }
+
+ return;
+ }
+
+ /*++
+ Method:
+ CPalSynchronizationManager::UnmarkTWListForDelegatedObjectSignalingInProgress
+
+ Resets the "delegated object signaling in progress" flags in all the
+ nodes of the thread waitin list for the target waitable objects (represented
+ by its SynchData)
+
+ Note: this method must be called while holding the appropriate
+ synchronization locks (the local process synch lock if the target
+ object is local, both local and shared one if the object is shared).
+ --*/
+ void CPalSynchronizationManager::UnmarkTWListForDelegatedObjectSignalingInProgress(
+ CSynchData * pTgtObjectSynchData)
+ {
+ bool fSharedObject = (SharedObject == pTgtObjectSynchData->GetObjectDomain());
+ WaitingThreadsListNode * pwtlnNode;
+
+ VALIDATEOBJECT(pTgtObjectSynchData);
+
+ pwtlnNode = fSharedObject ? SharedIDToTypePointer(WaitingThreadsListNode, pTgtObjectSynchData->GetWTLHeadShmPtr())
+ : pTgtObjectSynchData->GetWTLHeadPtr();
+
+ while (pwtlnNode)
+ {
+ VALIDATEOBJECT(pwtlnNode);
+
+ pwtlnNode->dwFlags &= ~WTLN_FLAG_DELEGATED_OBJECT_SIGNALING_IN_PROGRESS;
+ pwtlnNode = fSharedObject ? SharedIDToTypePointer(WaitingThreadsListNode, pwtlnNode->ptrNext.shrid)
+ : pwtlnNode->ptrNext.ptr;
+ }
+ }
+
+ /*++
+ Method:
+ CPalSynchronizationManager::RegisterProcessForMonitoring
+
+ Registers the process object represented by the passed psdSynchData and
+ pProcLocalData. The worker thread will monitor the actual process and,
+ upon process termination, it will set the exit code in pProcLocalData,
+ and it will signal the process object, by signaling its psdSynchData.
+ --*/
+ PAL_ERROR CPalSynchronizationManager::RegisterProcessForMonitoring(
+ CPalThread * pthrCurrent,
+ CSynchData *psdSynchData,
+ IPalObject *pProcessObject,
+ CProcProcessLocalData * pProcLocalData)
+ {
+ PAL_ERROR palErr = NO_ERROR;
+ MonitoredProcessesListNode * pmpln;
+ bool fWakeUpWorker = false;
+ bool fMonitoredProcessesLock = false;
+
+ VALIDATEOBJECT(psdSynchData);
+
+ InternalEnterCriticalSection(pthrCurrent, &s_csMonitoredProcessesLock);
+
+ fMonitoredProcessesLock = true;
+
+ pmpln = m_pmplnMonitoredProcesses;
+ while (pmpln)
+ {
+ if (psdSynchData == pmpln->psdSynchData)
+ {
+ _ASSERT_MSG(pmpln->dwPid == pProcLocalData->dwProcessId, "Invalid node in Monitored Processes List\n");
+ break;
+ }
+
+ pmpln = pmpln->pNext;
+ }
+
+ if (pmpln)
+ {
+ pmpln->lRefCount++;
+ }
+ else
+ {
+ pmpln = InternalNew<MonitoredProcessesListNode>();
+ if (NULL == pmpln)
+ {
+ ERROR("No memory to allocate MonitoredProcessesListNode structure\n");
+ palErr = ERROR_NOT_ENOUGH_MEMORY;
+ goto RPFM_exit;
+ }
+
+ pmpln->lRefCount = 1;
+ pmpln->dwPid = pProcLocalData->dwProcessId;
+ pmpln->dwExitCode = 0;
+ pmpln->pProcessObject = pProcessObject;
+ pmpln->pProcessObject->AddReference();
+ pmpln->pProcLocalData = pProcLocalData;
+
+ // Acquire SynchData and AddRef it
+ pmpln->psdSynchData = psdSynchData;
+ psdSynchData->AddRef();
+
+ pmpln->pNext = m_pmplnMonitoredProcesses;
+ m_pmplnMonitoredProcesses = pmpln;
+ m_lMonitoredProcessesCount++;
+
+ fWakeUpWorker = true;
+ }
+
+ // Unlock
+ InternalLeaveCriticalSection(pthrCurrent, &s_csMonitoredProcessesLock);
+ fMonitoredProcessesLock = false;
+
+ if (fWakeUpWorker)
+ {
+ CPalSynchronizationManager * pSynchManager = GetInstance();
+
+ palErr = pSynchManager->WakeUpLocalWorkerThread(SynchWorkerCmdNop);
+ if (NO_ERROR != palErr)
+ {
+ ERROR("Failed waking up worker thread for process "
+ "monitoring registration [errno=%d {%s%}]\n",
+ errno, strerror(errno));
+ palErr = ERROR_INTERNAL_ERROR;
+ }
+ }
+
+ RPFM_exit:
+ if (fMonitoredProcessesLock)
+ {
+ InternalLeaveCriticalSection(pthrCurrent,
+ &s_csMonitoredProcessesLock);
+ }
+
+ return palErr;
+ }
+
+ /*++
+ Method:
+ CPalSynchronizationManager::UnRegisterProcessForMonitoring
+
+ Unregisters a process object currently monitored by the worker thread
+ (typically called if the wait timed out before the process exited, or
+ if the wait was a normal (i.e. non wait-all) wait that involved othter
+ objects, and another object has been signaled).
+ --*/
+ PAL_ERROR CPalSynchronizationManager::UnRegisterProcessForMonitoring(
+ CPalThread * pthrCurrent,
+ CSynchData *psdSynchData,
+ DWORD dwPid)
+ {
+ PAL_ERROR palErr = NO_ERROR;
+ MonitoredProcessesListNode * pmpln, * pmplnPrev = NULL;
+
+ VALIDATEOBJECT(psdSynchData);
+
+ InternalEnterCriticalSection(pthrCurrent, &s_csMonitoredProcessesLock);
+
+ pmpln = m_pmplnMonitoredProcesses;
+ while (pmpln)
+ {
+ if (psdSynchData == pmpln->psdSynchData)
+ {
+ _ASSERT_MSG(dwPid == pmpln->dwPid, "Invalid node in Monitored Processes List\n");
+ break;
+ }
+
+ pmplnPrev = pmpln;
+ pmpln = pmpln->pNext;
+ }
+
+ if (pmpln)
+ {
+ if (0 == --pmpln->lRefCount)
+ {
+ if (NULL != pmplnPrev)
+ {
+ pmplnPrev->pNext = pmpln->pNext;
+ }
+ else
+ {
+ m_pmplnMonitoredProcesses = pmpln->pNext;
+ }
+
+ m_lMonitoredProcessesCount--;
+ pmpln->pProcessObject->ReleaseReference(pthrCurrent);
+ pmpln->psdSynchData->Release(pthrCurrent);
+ InternalDelete(pmpln);
+ }
+ }
+ else
+ {
+ palErr = ERROR_NOT_FOUND;
+ }
+
+ InternalLeaveCriticalSection(pthrCurrent, &s_csMonitoredProcessesLock);
+ return palErr;
+ }
+
+ /*++
+ Method:
+ CPalSynchronizationManager::ThreadPrepareForShutdown
+
+ Used to hijack thread execution from known spots within the
+ Synchronization Manager in case a PAL shutdown is initiated
+ or the thread is being terminated by another thread.
+ --*/
+ void CPalSynchronizationManager::ThreadPrepareForShutdown()
+ {
+ TRACE("The Synchronization Manager hijacked the current thread "
+ "for process shutdown or thread termination\n");
+ while (true)
+ {
+ poll(NULL, 0, INFTIM);
+ sched_yield();
+ }
+
+ ASSERT("This code should never be executed\n");
+ }
+
+ /*++
+ Method:
+ CPalSynchronizationManager::DoMonitorProcesses
+
+ This method is called by the worker thread to execute one step of
+ monitoring for all the process currently registered for monitoring
+ --*/
+ LONG CPalSynchronizationManager::DoMonitorProcesses(
+ CPalThread * pthrCurrent)
+ {
+ MonitoredProcessesListNode * pNode, * pPrev = NULL, * pNext;
+ LONG lInitialNodeCount;
+ LONG lRemovingCount = 0;
+ bool fLocalSynchLock = false;
+ bool fSharedSynchLock = false;
+ bool fMonitoredProcessesLock = false;
+
+ // Note: we first need to grab the monitored processes lock to walk
+ // the list of monitored processes, and then, if there is any
+ // which exited, to grab the synchronization lock(s) to signal
+ // the process object. Anyway we cannot grab the synchronization
+ // lock(s) while holding the monitored processes lock; that
+ // would cause deadlock, since RegisterProcessForMonitoring and
+ // UnRegisterProcessForMonitoring call stacks grab the locks
+ // in the opposite order. Grabbing the synch lock(s) first (and
+ // therefore all the times) would cause unacceptable contention
+ // (process monitoring is done in polling mode).
+ // Therefore we need to remove list nodes for processes that
+ // exited copying them to the exited array, while holding only
+ // the monitored processes lock, and then to signal them from that
+ // array holding synch lock(s) and monitored processes lock,
+ // acquired in this order. Holding again the monitored processes
+ // lock is needed in order to support object promotion.
+
+ // Grab the monitored processes lock
+ InternalEnterCriticalSection(pthrCurrent, &s_csMonitoredProcessesLock);
+ fMonitoredProcessesLock = true;
+
+ lInitialNodeCount = m_lMonitoredProcessesCount;
+
+ pNode = m_pmplnMonitoredProcesses;
+ while (pNode)
+ {
+ pNext = pNode->pNext;
+
+ if (HasProcessExited(pNode->dwPid,
+ &pNode->dwExitCode,
+ &pNode->fIsActualExitCode))
+ {
+ TRACE("Process %u exited with return code %u\n",
+ pNode->dwPid,
+ pNode->fIsActualExitCode ? "actual" : "guessed",
+ pNode->dwExitCode);
+
+ if (NULL != pPrev)
+ {
+ pPrev->pNext = pNext;
+ }
+ else
+ {
+ m_pmplnMonitoredProcesses = pNext;
+ }
+
+ m_lMonitoredProcessesCount--;
+
+ // Insert in the list of nodes for exited processes
+ pNode->pNext = m_pmplnExitedNodes;
+ m_pmplnExitedNodes = pNode;
+ lRemovingCount++;
+ }
+ else
+ {
+ pPrev = pNode;
+ }
+
+ // Go to the next
+ pNode = pNext;
+ }
+
+ // Release the monitored processes lock
+ InternalLeaveCriticalSection(pthrCurrent, &s_csMonitoredProcessesLock);
+ fMonitoredProcessesLock = false;
+
+ if (lRemovingCount > 0)
+ {
+ // First grab the local synch lock
+ AcquireLocalSynchLock(pthrCurrent);
+ fLocalSynchLock = true;
+
+ // Acquire the monitored processes lock
+ InternalEnterCriticalSection(pthrCurrent, &s_csMonitoredProcessesLock);
+ fMonitoredProcessesLock = true;
+
+ if (!fSharedSynchLock)
+ {
+ bool fSharedSynchLockIsNeeded = false;
+
+ // See if the shared lock is needed
+ pNode = m_pmplnExitedNodes;
+ while (pNode)
+ {
+ if (SharedObject == pNode->psdSynchData->GetObjectDomain())
+ {
+ fSharedSynchLockIsNeeded = true;
+ break;
+ }
+
+ pNode = pNode->pNext;
+ }
+
+ if (fSharedSynchLockIsNeeded)
+ {
+ // Release the monitored processes lock
+ InternalLeaveCriticalSection(pthrCurrent,
+ &s_csMonitoredProcessesLock);
+ fMonitoredProcessesLock = false;
+
+ // Acquire the shared synch lock
+ AcquireSharedSynchLock(pthrCurrent);
+ fSharedSynchLock = true;
+
+ // Acquire again the monitored processes lock
+ InternalEnterCriticalSection(pthrCurrent,
+ &s_csMonitoredProcessesLock);
+ fMonitoredProcessesLock = true;
+ }
+ }
+
+ // Start from the beginning of the exited processes list
+ pNode = m_pmplnExitedNodes;
+
+ // Invalidate the list
+ m_pmplnExitedNodes = NULL;
+
+ while (pNode)
+ {
+ pNext = pNode->pNext;
+
+ TRACE("Process pid=%u exited with exitcode=%u\n",
+ pNode->dwPid, pNode->dwExitCode);
+
+ // Store the exit code in the process local data
+ if (pNode->fIsActualExitCode)
+ {
+ pNode->pProcLocalData->dwExitCode = pNode->dwExitCode;
+ }
+
+ // Set process status to PS_DONE
+ pNode->pProcLocalData->ps = PS_DONE;
+
+ // Set signal count
+ pNode->psdSynchData->SetSignalCount(1);
+
+ // Releasing all local waiters
+ //
+ // We just called directly in CSynchData::SetSignalCount(), so
+ // we need to take care of waking up waiting threads according
+ // to the Process object semantics (i.e. every thread must be
+ // awakend). Anyway if a process object is shared among two or
+ // more processes and threads from different processes are
+ // waiting on it, the object will be registered for monitoring
+ // in each of the processes. As result its signal count will
+ // be set to one more times (which is not a problem, given the
+ // process object semantics) and each worker thread will wake
+ // up waiting threads. Therefore we need to make sure that each
+ // worker wakes up only threads in its own process: we do that
+ // by calling ReleaseAllLocalWaiters
+ pNode->psdSynchData->ReleaseAllLocalWaiters(pthrCurrent);
+
+ // We are done with pProcLocalData, so we can release the process object
+ pNode->pProcessObject->ReleaseReference(pthrCurrent);
+
+ // Release the reference to the SynchData
+ pNode->psdSynchData->Release(pthrCurrent);
+
+ // Delete the node
+ InternalDelete(pNode);
+
+ // Go to the next
+ pNode = pNext;
+ }
+ }
+
+ if (fMonitoredProcessesLock)
+ {
+ InternalLeaveCriticalSection(pthrCurrent, &s_csMonitoredProcessesLock);
+ }
+
+ if (fSharedSynchLock)
+ {
+ ReleaseSharedSynchLock(pthrCurrent);
+ }
+
+ if (fLocalSynchLock)
+ {
+ ReleaseLocalSynchLock(pthrCurrent);
+ }
+
+ return (lInitialNodeCount - lRemovingCount);
+ }
+
+ /*++
+ Method:
+ CPalSynchronizationManager::DiscardMonitoredProcesses
+
+ This method is called at shutdown time to discard all the registration
+ for the processes currently monitored by the worker thread.
+ This method must be called at shutdown time, otherwise some shared memory
+ may be leaked at process shutdown.
+ --*/
+ void CPalSynchronizationManager::DiscardMonitoredProcesses(
+ CPalThread * pthrCurrent)
+ {
+ MonitoredProcessesListNode * pNode;
+
+ // Grab the monitored processes lock
+ InternalEnterCriticalSection(pthrCurrent, &s_csMonitoredProcessesLock);
+
+ while (m_pmplnMonitoredProcesses)
+ {
+ pNode = m_pmplnMonitoredProcesses;
+ m_pmplnMonitoredProcesses = pNode->pNext;
+ pNode->pProcessObject->ReleaseReference(pthrCurrent);
+ pNode->psdSynchData->Release(pthrCurrent);
+ InternalDelete(pNode);
+ }
+
+ // Release the monitored processes lock
+ InternalLeaveCriticalSection(pthrCurrent, &s_csMonitoredProcessesLock);
+ }
+
+ /*++
+ Method:
+ CPalSynchronizationManager::CreateProcessPipe
+
+ Creates the process pipe for the current process
+ --*/
+ bool CPalSynchronizationManager::CreateProcessPipe()
+ {
+ bool fRet = true;
+#if HAVE_KQUEUE && !HAVE_BROKEN_FIFO_KEVENT
+ int iKq = -1;
+#endif // HAVE_KQUEUE && !HAVE_BROKEN_FIFO_KEVENT
+
+#ifndef CORECLR
+ int iPipeRd = -1, iPipeWr = -1;
+ char szPipeFilename[MAX_PATH];
+
+ /* Create the blocking pipe */
+ if (!GetProcessPipeName(szPipeFilename, MAX_PATH, gPID))
+ {
+ ERROR("couldn't get process pipe's name\n");
+ szPipeFilename[0] = 0;
+ fRet = false;
+ goto CPP_exit;
+ }
+
+ /* create the pipe, with full access to the owner only */
+ if (mkfifo(szPipeFilename, S_IRWXU) == -1)
+ {
+ if (errno == EEXIST)
+ {
+ /* Some how no one deleted the pipe, perhaps it was left behind
+ from a crash?? Delete the pipe and try again. */
+ if (-1 == unlink(szPipeFilename))
+ {
+ ERROR( "Unable to delete the process pipe that was left behind.\n" );
+ fRet = false;
+ goto CPP_exit;
+ }
+ else
+ {
+ if (mkfifo(szPipeFilename, S_IRWXU) == -1)
+ {
+ ERROR( "Still unable to create the process pipe...giving up!\n" );
+ fRet = false;
+ goto CPP_exit;
+ }
+ }
+ }
+ else
+ {
+ ERROR( "Unable to create the process pipe.\n" );
+ fRet = false;
+ goto CPP_exit;
+ }
+ }
+
+ iPipeRd = InternalOpen(szPipeFilename, O_RDONLY | O_NONBLOCK);
+ if (iPipeRd == -1)
+ {
+ ERROR("Unable to open the process pipe for read\n");
+ fRet = false;
+ goto CPP_exit;
+ }
+
+ iPipeWr = InternalOpen(szPipeFilename, O_WRONLY | O_NONBLOCK);
+ if (iPipeWr == -1)
+ {
+ ERROR("Unable to open the process pipe for write\n");
+ fRet = false;
+ goto CPP_exit;
+ }
+#else // !CORECLR
+ int rgiPipe[] = { -1, -1 };
+ if (pipe(rgiPipe) == -1)
+ {
+ ERROR("Unable to create the process pipe\n");
+ fRet = false;
+ goto CPP_exit;
+ }
+#endif // !CORECLR
+
+#if HAVE_KQUEUE && !HAVE_BROKEN_FIFO_KEVENT
+ iKq = kqueue();
+ if (-1 == iKq)
+ {
+ ERROR("Failed to create kqueue associated to process pipe\n");
+ fRet = false;
+ goto CPP_exit;
+ }
+#endif // HAVE_KQUEUE
+
+ CPP_exit:
+ if (fRet)
+ {
+ // Succeeded
+#ifndef CORECLR
+ m_iProcessPipeRead = iPipeRd;
+ m_iProcessPipeWrite = iPipeWr;
+#else // !CORECLR
+ m_iProcessPipeRead = rgiPipe[0];
+ m_iProcessPipeWrite = rgiPipe[1];
+#endif // !CORECLR
+#if HAVE_KQUEUE && !HAVE_BROKEN_FIFO_KEVENT
+ m_iKQueue = iKq;
+#endif // HAVE_KQUEUE
+ }
+ else
+ {
+#ifndef CORECLR
+ // Failed
+ if (0 != szPipeFilename[0])
+ {
+ unlink(szPipeFilename);
+ }
+ if (-1 != iPipeRd)
+ {
+ close(iPipeRd);
+ }
+ if (-1 != iPipeWr)
+ {
+ close(iPipeWr);
+ }
+#else // !CORECLR
+ if (-1 != rgiPipe[0])
+ {
+ close(rgiPipe[0]);
+ close(rgiPipe[1]);
+ }
+#endif // !CORECLR
+#if HAVE_KQUEUE && !HAVE_BROKEN_FIFO_KEVENT
+ if (-1 != iKq)
+ {
+ close(iKq);
+ }
+#endif // HAVE_KQUEUE
+ }
+
+ return fRet;
+ }
+
+ /*++
+ Method:
+ CPalSynchronizationManager::ShutdownProcessPipe
+
+ Shuts down the process pipe and removes the fifo so that other processes
+ can no longer open it. It also closes the local write end of the pipe (see
+ comment below). From this moment on the worker thread will process any
+ possible data already received in the pipe (but not yet consumed) and any
+ data written by processes that still have a opened write end of this pipe;
+ it will wait (with timeout) until the last remote process which has a write
+ end opened closes it, and then it will yield to process shutdown.
+ --*/
+ PAL_ERROR CPalSynchronizationManager::ShutdownProcessPipe()
+ {
+ PAL_ERROR palErr = NO_ERROR;
+#ifndef CORECLR
+ char szPipeFilename[MAX_PATH];
+
+ if (GetProcessPipeName(szPipeFilename, MAX_PATH, gPID))
+ {
+ if (unlink(szPipeFilename) == -1)
+ {
+ ERROR("Unable to unlink the pipe file name errno=%d (%s)\n",
+ errno, strerror(errno));
+ palErr = ERROR_INTERNAL_ERROR;
+ // go on anyway
+ }
+ }
+ else
+ {
+ ERROR("Couldn't get the process pipe's name\n");
+ palErr = ERROR_INTERNAL_ERROR;
+ // go on anyway
+ }
+#endif // CORECLR
+
+ if (-1 != m_iProcessPipeWrite)
+ {
+ // Closing the write end of the process pipe. When the last process
+ // that still has a open write-fd on this pipe will close it, the
+ // worker thread will receive an EOF; the worker thread will wait
+ // for this EOF before shutting down, so to ensure to process any
+ // possible data already written to the pipe by other processes
+ // when the shutdown has been initiated in the current process.
+ // Note: no need here to worry about platforms where close(pipe)
+ // blocks on outstanding syscalls, since we are the only one using
+ // this fd.
+ TRACE("Closing the write end of process pipe\n");
+ if (close(m_iProcessPipeWrite) == -1)
+ {
+ ERROR("Unable to close the write end of process pipe\n");
+ palErr = ERROR_INTERNAL_ERROR;
+ }
+
+ m_iProcessPipeWrite = -1;
+ }
+
+ return palErr;
+ }
+
+#ifndef CORECLR
+ /*++
+ Method:
+ CPalSynchronizationManager::GetProcessPipeName
+
+ Returns the process pipe name for the target process (identified by its PID)
+ --*/
+ bool CPalSynchronizationManager::GetProcessPipeName(
+ LPSTR pDest,
+ int iDestSize,
+ DWORD dwPid)
+ {
+ CHAR config_dir[MAX_PATH];
+ int needed_size;
+
+ _ASSERT_MSG(NULL != pDest, "Destination pointer is NULL!\n");
+ _ASSERT_MSG(0 < iDestSize,"Invalid buffer size %d\n", iDestSize);
+
+ if (!PALGetPalConfigDir(config_dir, MAX_PATH))
+ {
+ ASSERT("Unable to determine the PAL config directory.\n");
+ pDest[0] = '\0';
+ return false;
+ }
+ needed_size = snprintf(pDest, iDestSize, "%s/%s-%u", config_dir,
+ PROCESS_PIPE_NAME_PREFIX, dwPid);
+ pDest[iDestSize-1] = 0;
+ if(needed_size >= iDestSize)
+ {
+ ERROR("threadpipe name needs %d characters, buffer only has room for "
+ "%d\n", needed_size, iDestSize+1);
+ return false;
+ }
+ return true;
+ }
+#endif // !CORECLR
+
+ /*++
+ Method:
+ CPalSynchronizationManager::AcquireProcessLock
+
+ Acquires the local Process Lock (which currently is the same as the
+ the local Process Synch Lock)
+ --*/
+ void CPalSynchronizationManager::AcquireProcessLock(CPalThread * pthrCurrent)
+ {
+ AcquireLocalSynchLock(pthrCurrent);
+ }
+
+ /*++
+ Method:
+ CPalSynchronizationManager::ReleaseProcessLock
+
+ Releases the local Process Lock (which currently is the same as the
+ the local Process Synch Lock)
+ --*/
+ void CPalSynchronizationManager::ReleaseProcessLock(CPalThread * pthrCurrent)
+ {
+ ReleaseLocalSynchLock(pthrCurrent);
+ }
+
+ /*++
+ Method:
+ CPalSynchronizationManager::PromoteObjectSynchData
+
+ Promotes an object's synchdata from local to shared
+ --*/
+ PAL_ERROR CPalSynchronizationManager::PromoteObjectSynchData(
+ CPalThread *pthrCurrent,
+ VOID *pvLocalSynchData,
+ VOID **ppvSharedSynchData)
+ {
+ PAL_ERROR palError = NO_ERROR;
+ CSynchData *psdLocal = reinterpret_cast<CSynchData *>(pvLocalSynchData);
+ CSynchData *psdShared = NULL;
+ SharedID shridSynchData = NULLSharedID;
+ SharedID *rgshridWTLNodes = NULL;
+ CObjectType *pot = NULL;
+ ULONG ulcWaitingThreads;
+
+ _ASSERTE(NULL != pthrCurrent);
+ _ASSERTE(NULL != pvLocalSynchData);
+ _ASSERTE(NULL != ppvSharedSynchData);
+ _ASSERTE(ProcessLocalObject == psdLocal->GetObjectDomain());
+
+#if _DEBUG
+
+ //
+ // TODO: Verify that the proper locks are held
+ //
+#endif
+
+ //
+ // Allocate shared memory CSynchData and map to local memory
+ //
+
+ shridSynchData = m_cacheSHRSynchData.Get(pthrCurrent);
+ if (NULLSharedID == shridSynchData)
+ {
+ ERROR("Unable to allocate shared memory\n");
+ palError = ERROR_NOT_ENOUGH_MEMORY;
+ goto POSD_exit;
+ }
+
+ psdShared = SharedIDToTypePointer(CSynchData, shridSynchData);
+ _ASSERTE(NULL != psdShared);
+
+ //
+ // Allocate shared memory WaitingThreadListNodes if there are
+ // any threads currently waiting on this object
+ //
+
+ ulcWaitingThreads = psdLocal->GetWaitingThreadCount();
+ if (0 < ulcWaitingThreads)
+ {
+ int i;
+
+ rgshridWTLNodes = InternalNewArray<SharedID>(ulcWaitingThreads);
+ if (NULL == rgshridWTLNodes)
+ {
+ palError = ERROR_OUTOFMEMORY;
+ goto POSD_exit;
+ }
+
+ i = m_cacheSHRWTListNodes.Get(
+ pthrCurrent,
+ ulcWaitingThreads,
+ rgshridWTLNodes
+ );
+
+ if (static_cast<ULONG>(i) != ulcWaitingThreads)
+ {
+ for (i -= 1; i >= 0; i -= 1)
+ {
+ m_cacheSHRWTListNodes.Add(pthrCurrent, rgshridWTLNodes[i]);
+ }
+
+ palError = ERROR_OUTOFMEMORY;
+ goto POSD_exit;
+ }
+ }
+
+ //
+ // If the synch data is for a process object we need to grab
+ // the monitored process list lock here
+ //
+
+ pot = psdLocal->GetObjectType();
+ _ASSERTE(NULL != pot);
+
+ if (otiProcess == pot->GetId())
+ {
+ InternalEnterCriticalSection(pthrCurrent, &s_csMonitoredProcessesLock);
+ }
+
+ //
+ // Copy pertinent CSynchData info to the shared memory version (and
+ // initialize other members)
+ //
+
+ psdShared->SetSharedThis(shridSynchData);
+ psdShared->SetObjectDomain(SharedObject);
+ psdShared->SetObjectType(psdLocal->GetObjectType());
+ psdShared->SetSignalCount(psdLocal->GetSignalCount());
+
+#ifdef SYNCH_STATISTICS
+ psdShared->SetStatContentionCount(psdLocal->GetStatContentionCount());
+ psdShared->SetStatWaitCount(psdLocal->GetStatWaitCount());
+#endif
+
+ //
+ // Rebuild the waiting thread list, and update the wait domain
+ // for the waiting threads
+ //
+
+ psdShared->SetWTLHeadShrPtr(NULLSharedID);
+ psdShared->SetWTLTailShrPtr(NULLSharedID);
+
+ if (0 < ulcWaitingThreads)
+ {
+ WaitingThreadsListNode *pwtlnOld;
+ WaitingThreadsListNode *pwtlnNew;
+ int i = 0;
+
+ for (pwtlnOld = psdLocal->GetWTLHeadPtr();
+ pwtlnOld != NULL;
+ pwtlnOld = pwtlnOld->ptrNext.ptr, i += 1)
+ {
+ pwtlnNew = SharedIDToTypePointer(
+ WaitingThreadsListNode,
+ rgshridWTLNodes[i]
+ );
+
+ _ASSERTE(NULL != pwtlnNew);
+
+ pwtlnNew->shridSHRThis = rgshridWTLNodes[i];
+ pwtlnNew->ptrOwnerObjSynchData.shrid = shridSynchData;
+
+ pwtlnNew->dwThreadId = pwtlnOld->dwThreadId;
+ pwtlnNew->dwProcessId = pwtlnOld->dwProcessId;
+ pwtlnNew->dwObjIndex = pwtlnOld->dwObjIndex;
+ pwtlnNew->dwFlags = pwtlnOld->dwFlags | WTLN_FLAG_OWNER_OBJECT_IS_SHARED;
+ pwtlnNew->shridWaitingState = pwtlnOld->shridWaitingState;
+ pwtlnNew->ptwiWaitInfo = pwtlnOld->ptwiWaitInfo;
+
+ psdShared->SharedWaiterEnqueue(rgshridWTLNodes[i]);
+ psdShared->AddRef();
+
+ _ASSERTE(pwtlnOld = pwtlnOld->ptwiWaitInfo->rgpWTLNodes[pwtlnOld->dwObjIndex]);
+ pwtlnNew->ptwiWaitInfo->rgpWTLNodes[pwtlnNew->dwObjIndex] = pwtlnNew;
+
+ pwtlnNew->ptwiWaitInfo->lSharedObjCount += 1;
+ if (pwtlnNew->ptwiWaitInfo->lSharedObjCount
+ == pwtlnNew->ptwiWaitInfo->lObjCount)
+ {
+ pwtlnNew->ptwiWaitInfo->wdWaitDomain = SharedWait;
+ }
+ else
+ {
+ _ASSERTE(pwtlnNew->ptwiWaitInfo->lSharedObjCount
+ < pwtlnNew->ptwiWaitInfo->lObjCount);
+
+ pwtlnNew->ptwiWaitInfo->wdWaitDomain = MixedWait;
+ }
+ }
+
+ _ASSERTE(psdShared->GetWaitingThreadCount() == ulcWaitingThreads);
+ }
+
+ //
+ // If the object tracks ownership and has a current owner update
+ // the OwnedObjectsListNode to point to the shared memory synch
+ // data
+ //
+
+ if (CObjectType::OwnershipTracked == pot->GetOwnershipSemantics())
+ {
+ OwnedObjectsListNode *pooln;
+
+ pooln = psdLocal->GetOwnershipListNode();
+ if (NULL != pooln)
+ {
+ pooln->pPalObjSynchData = psdShared;
+ psdShared->SetOwnershipListNode(pooln);
+ psdShared->AddRef();
+
+ //
+ // Copy over other ownership info.
+ //
+
+ psdShared->SetOwner(psdLocal->GetOwnerThread());
+ psdShared->SetOwnershipCount(psdLocal->GetOwnershipCount());
+ _ASSERTE(!psdShared->IsAbandoned());
+ }
+ else
+ {
+ _ASSERTE(0 == psdLocal->GetOwnershipCount());
+ _ASSERTE(0 == psdShared->GetOwnershipCount());
+ psdShared->SetAbandoned(psdLocal->IsAbandoned());
+ }
+ }
+
+ //
+ // If the synch data is for a process object update the monitored
+ // process list nodes to point to the shared memory object data,
+ // and release the monitored process list lock
+ //
+
+ if (otiProcess == pot->GetId())
+ {
+ MonitoredProcessesListNode *pmpn;
+
+ pmpn = m_pmplnMonitoredProcesses;
+ while (NULL != pmpn)
+ {
+ if (psdLocal == pmpn->psdSynchData)
+ {
+ pmpn->psdSynchData = psdShared;
+ psdShared->AddRef();
+ }
+
+ pmpn = pmpn->pNext;
+ }
+
+ pmpn = m_pmplnExitedNodes;
+ while (NULL != pmpn)
+ {
+ if (psdLocal == pmpn->psdSynchData)
+ {
+ pmpn->psdSynchData = psdShared;
+ psdShared->AddRef();
+ }
+
+ pmpn = pmpn->pNext;
+ }
+
+ InternalLeaveCriticalSection(pthrCurrent, &s_csMonitoredProcessesLock);
+ }
+
+ *ppvSharedSynchData = reinterpret_cast<VOID*>(shridSynchData);
+
+ //
+ // Free the local memory items to caches
+ //
+
+ if (0 < ulcWaitingThreads)
+ {
+ WaitingThreadsListNode *pwtln;
+
+ pwtln = psdLocal->GetWTLHeadPtr();
+ while (NULL != pwtln)
+ {
+ WaitingThreadsListNode *pwtlnTemp;
+
+ pwtlnTemp = pwtln;
+ pwtln = pwtln->ptrNext.ptr;
+ m_cacheWTListNodes.Add(pthrCurrent, pwtlnTemp);
+ }
+ }
+
+ m_cacheSynchData.Add(pthrCurrent, psdLocal);
+
+ POSD_exit:
+
+ if (NULL != rgshridWTLNodes)
+ {
+ InternalDeleteArray(rgshridWTLNodes);
+ }
+
+ return palError;
+ }
+
+
+ /////////////////////////////
+ // //
+ // _ThreadNativeWaitData //
+ // //
+ /////////////////////////////
+
+ _ThreadNativeWaitData::~_ThreadNativeWaitData()
+ {
+ if (fInitialized)
+ {
+ fInitialized = false;
+ pthread_cond_destroy(&cond);
+ pthread_mutex_destroy(&mutex);
+ }
+ }
+
+
+ //////////////////////////////////
+ // //
+ // CThreadSynchronizationInfo //
+ // //
+ //////////////////////////////////
+
+ CThreadSynchronizationInfo::CThreadSynchronizationInfo() :
+ m_tsThreadState(TS_IDLE),
+ m_shridWaitAwakened(NULLSharedID),
+ m_lLocalSynchLockCount(0),
+ m_lSharedSynchLockCount(0),
+ m_ownedNamedMutexListHead(nullptr)
+ {
+ InitializeListHead(&m_leOwnedObjsList);
+ InitializeCriticalSection(&m_ownedNamedMutexListLock);
+
+#ifdef SYNCHMGR_SUSPENSION_SAFE_CONDITION_SIGNALING
+ m_lPendingSignalingCount = 0;
+ InitializeListHead(&m_lePendingSignalingsOverflowList);
+#endif // SYNCHMGR_SUSPENSION_SAFE_CONDITION_SIGNALING
+ }
+
+ CThreadSynchronizationInfo::~CThreadSynchronizationInfo()
+ {
+ DeleteCriticalSection(&m_ownedNamedMutexListLock);
+ if (NULLSharedID != m_shridWaitAwakened)
+ {
+ RawSharedObjectFree(m_shridWaitAwakened);
+ }
+ }
+
+ void CThreadSynchronizationInfo::AcquireNativeWaitLock()
+ {
+#if !SYNCHMGR_SUSPENSION_SAFE_CONDITION_SIGNALING
+ int iRet;
+ iRet = pthread_mutex_lock(&m_tnwdNativeData.mutex);
+ _ASSERT_MSG(0 == iRet, "pthread_mutex_lock failed with error=%d\n", iRet);
+#endif // !SYNCHMGR_SUSPENSION_SAFE_CONDITION_SIGNALING
+ }
+
+ void CThreadSynchronizationInfo::ReleaseNativeWaitLock()
+ {
+#if !SYNCHMGR_SUSPENSION_SAFE_CONDITION_SIGNALING
+ int iRet;
+ iRet = pthread_mutex_unlock(&m_tnwdNativeData.mutex);
+ _ASSERT_MSG(0 == iRet, "pthread_mutex_unlock failed with error=%d\n", iRet);
+#endif // !SYNCHMGR_SUSPENSION_SAFE_CONDITION_SIGNALING
+ }
+
+ bool CThreadSynchronizationInfo::TryAcquireNativeWaitLock()
+ {
+ bool fRet = true;
+#if !SYNCHMGR_SUSPENSION_SAFE_CONDITION_SIGNALING
+ int iRet;
+ iRet = pthread_mutex_trylock(&m_tnwdNativeData.mutex);
+ _ASSERT_MSG(0 == iRet || EBUSY == iRet,
+ "pthread_mutex_trylock failed with error=%d\n", iRet);
+ fRet = (0 == iRet);
+#endif // !SYNCHMGR_SUSPENSION_SAFE_CONDITION_SIGNALING
+ return fRet;
+ }
+
+ /*++
+ Method:
+ CThreadSynchronizationInfo::InitializePreCreate
+
+ Part of CThreadSynchronizationInfo's initialization to be carried out
+ before actual thread creation
+ --*/
+ PAL_ERROR CThreadSynchronizationInfo::InitializePreCreate(void)
+ {
+ PAL_ERROR palErr = NO_ERROR;
+ DWORD * pdwWaitState = NULL;
+ int iRet;
+ const int MaxUnavailableResourceRetries = 10;
+ int iEagains;
+ m_shridWaitAwakened = RawSharedObjectAlloc(sizeof(DWORD),
+ DefaultSharedPool);
+ if (NULLSharedID == m_shridWaitAwakened)
+ {
+ ERROR("Fail allocating thread wait status shared object\n");
+ palErr = ERROR_NOT_ENOUGH_MEMORY;
+ goto IPrC_exit;
+ }
+
+ pdwWaitState = SharedIDToTypePointer(DWORD,
+ m_shridWaitAwakened);
+
+ _ASSERT_MSG(NULL != pdwWaitState,
+ "Unable to map shared wait state: bad shared ID [shrid=%p]\n", (VOID*)m_shridWaitAwakened);
+
+ VolatileStore<DWORD>(pdwWaitState, TWS_ACTIVE);
+ m_tsThreadState = TS_STARTING;
+
+ iEagains = 0;
+ Mutex_retry:
+ iRet = pthread_mutex_init(&m_tnwdNativeData.mutex, NULL);
+ if (0 != iRet)
+ {
+ ERROR("Failed creating thread synchronization mutex [error=%d (%s)]\n", iRet, strerror(iRet));
+ if (EAGAIN == iRet && MaxUnavailableResourceRetries >= ++iEagains)
+ {
+ poll(NULL, 0, min(100,10*iEagains));
+ goto Mutex_retry;
+ }
+ else if (ENOMEM == iRet)
+ {
+ palErr = ERROR_NOT_ENOUGH_MEMORY;
+ }
+ else
+ {
+ palErr = ERROR_INTERNAL_ERROR;
+ }
+
+ goto IPrC_exit;
+ }
+
+ iEagains = 0;
+ Cond_retry:
+ iRet = pthread_cond_init(&m_tnwdNativeData.cond, NULL);
+ if (0 != iRet)
+ {
+ ERROR("Failed creating thread synchronization condition "
+ "[error=%d (%s)]\n", iRet, strerror(iRet));
+ if (EAGAIN == iRet && MaxUnavailableResourceRetries >= ++iEagains)
+ {
+ poll(NULL, 0, min(100,10*iEagains));
+ goto Cond_retry;
+ }
+ else if (ENOMEM == iRet)
+ {
+ palErr = ERROR_NOT_ENOUGH_MEMORY;
+ }
+ else
+ {
+ palErr = ERROR_INTERNAL_ERROR;
+ }
+ pthread_mutex_destroy(&m_tnwdNativeData.mutex);
+ goto IPrC_exit;
+ }
+
+ m_tnwdNativeData.fInitialized = true;
+
+ IPrC_exit:
+ if (NO_ERROR != palErr)
+ {
+ m_tsThreadState = TS_FAILED;
+ }
+ return palErr;
+ }
+
+ /*++
+ Method:
+ CThreadSynchronizationInfo::InitializePostCreate
+
+ Part of CThreadSynchronizationInfo's initialization to be carried out
+ after actual thread creation
+ --*/
+ PAL_ERROR CThreadSynchronizationInfo::InitializePostCreate(
+ CPalThread *pthrCurrent,
+ SIZE_T threadId,
+ DWORD dwLwpId)
+ {
+ PAL_ERROR palErr = NO_ERROR;
+
+ if (TS_FAILED == m_tsThreadState)
+ {
+ palErr = ERROR_INTERNAL_ERROR;
+ }
+
+ m_twiWaitInfo.pthrOwner = pthrCurrent;
+
+ return palErr;
+ }
+
+
+ /*++
+ Method:
+ CThreadSynchronizationInfo::AddObjectToOwnedList
+
+ Adds an object to the list of currently owned objects.
+ --*/
+ void CThreadSynchronizationInfo::AddObjectToOwnedList(POwnedObjectsListNode pooln)
+ {
+ InsertTailList(&m_leOwnedObjsList, &pooln->Link);
+ }
+
+ /*++
+ Method:
+ CThreadSynchronizationInfo::RemoveObjectFromOwnedList
+
+ Removes an object from the list of currently owned objects.
+ --*/
+ void CThreadSynchronizationInfo::RemoveObjectFromOwnedList(POwnedObjectsListNode pooln)
+ {
+ RemoveEntryList(&pooln->Link);
+ }
+
+ /*++
+ Method:
+ CThreadSynchronizationInfo::RemoveFirstObjectFromOwnedList
+
+ Removes the first object from the list of currently owned objects.
+ --*/
+ POwnedObjectsListNode CThreadSynchronizationInfo::RemoveFirstObjectFromOwnedList()
+ {
+ OwnedObjectsListNode * poolnItem;
+
+ if (IsListEmpty(&m_leOwnedObjsList))
+ {
+ poolnItem = NULL;
+ }
+ else
+ {
+ PLIST_ENTRY pLink = RemoveHeadList(&m_leOwnedObjsList);
+ poolnItem = CONTAINING_RECORD(pLink, OwnedObjectsListNode, Link);
+ }
+
+ return poolnItem;
+ }
+
+ void CThreadSynchronizationInfo::AddOwnedNamedMutex(NamedMutexProcessData *processData)
+ {
+ _ASSERTE(processData != nullptr);
+ _ASSERTE(processData->GetNextInThreadOwnedNamedMutexList() == nullptr);
+
+ EnterCriticalSection(&m_ownedNamedMutexListLock);
+ processData->SetNextInThreadOwnedNamedMutexList(m_ownedNamedMutexListHead);
+ m_ownedNamedMutexListHead = processData;
+ LeaveCriticalSection(&m_ownedNamedMutexListLock);
+ }
+
+ void CThreadSynchronizationInfo::RemoveOwnedNamedMutex(NamedMutexProcessData *processData)
+ {
+ _ASSERTE(processData != nullptr);
+
+ EnterCriticalSection(&m_ownedNamedMutexListLock);
+ if (m_ownedNamedMutexListHead == processData)
+ {
+ m_ownedNamedMutexListHead = processData->GetNextInThreadOwnedNamedMutexList();
+ processData->SetNextInThreadOwnedNamedMutexList(nullptr);
+ }
+ else
+ {
+ bool found = false;
+ for (NamedMutexProcessData
+ *previous = m_ownedNamedMutexListHead,
+ *current = previous->GetNextInThreadOwnedNamedMutexList();
+ current != nullptr;
+ previous = current, current = current->GetNextInThreadOwnedNamedMutexList())
+ {
+ if (current == processData)
+ {
+ found = true;
+ previous->SetNextInThreadOwnedNamedMutexList(current->GetNextInThreadOwnedNamedMutexList());
+ current->SetNextInThreadOwnedNamedMutexList(nullptr);
+ break;
+ }
+ }
+ _ASSERTE(found);
+ }
+ LeaveCriticalSection(&m_ownedNamedMutexListLock);
+ }
+
+ NamedMutexProcessData *CThreadSynchronizationInfo::RemoveFirstOwnedNamedMutex()
+ {
+ EnterCriticalSection(&m_ownedNamedMutexListLock);
+ NamedMutexProcessData *processData = m_ownedNamedMutexListHead;
+ if (processData != nullptr)
+ {
+ m_ownedNamedMutexListHead = processData->GetNextInThreadOwnedNamedMutexList();
+ processData->SetNextInThreadOwnedNamedMutexList(nullptr);
+ }
+ LeaveCriticalSection(&m_ownedNamedMutexListLock);
+ return processData;
+ }
+
+ bool CThreadSynchronizationInfo::OwnsNamedMutex(NamedMutexProcessData *processData)
+ {
+ EnterCriticalSection(&m_ownedNamedMutexListLock);
+ bool found = false;
+ for (NamedMutexProcessData *current = m_ownedNamedMutexListHead;
+ current != nullptr;
+ current = current->GetNextInThreadOwnedNamedMutexList())
+ {
+ if (current == processData)
+ {
+ found = true;
+ break;
+ }
+ }
+ LeaveCriticalSection(&m_ownedNamedMutexListLock);
+ return found;
+ }
+
+#if SYNCHMGR_SUSPENSION_SAFE_CONDITION_SIGNALING
+
+ /*++
+ Method:
+ CThreadSynchronizationInfo::RunDeferredThreadConditionSignalings
+
+ Carries out all the pending condition signalings for the current thread.
+ --*/
+ PAL_ERROR CThreadSynchronizationInfo::RunDeferredThreadConditionSignalings()
+ {
+ PAL_ERROR palErr = NO_ERROR;
+
+ _ASSERTE(0 <= m_lPendingSignalingCount);
+
+ if (0 < m_lPendingSignalingCount)
+ {
+ LONG lArrayPendingSignalingCount = min(PendingSignalingsArraySize, m_lPendingSignalingCount);
+ LONG lIdx = 0;
+ PAL_ERROR palTempErr;
+
+ // Signal all the pending signalings from the array
+ for (lIdx = 0; lIdx < lArrayPendingSignalingCount; lIdx++)
+ {
+ // Do the actual signaling
+ palTempErr = CPalSynchronizationManager::SignalThreadCondition(
+ m_rgpthrPendingSignalings[lIdx]->synchronizationInfo.GetNativeData());
+ if (NO_ERROR != palTempErr)
+ {
+ palErr = palTempErr;
+ }
+
+ // Release the thread reference
+ m_rgpthrPendingSignalings[lIdx]->ReleaseThreadReference();
+ }
+
+ // Signal any pending signalings from the array overflow list
+ if (m_lPendingSignalingCount > PendingSignalingsArraySize)
+ {
+ PLIST_ENTRY pLink;
+ DeferredSignalingListNode * pdsln;
+
+ while (!IsListEmpty(&m_lePendingSignalingsOverflowList))
+ {
+ // Remove a node from the head of the queue
+ // Note: no need to synchronize the access to this list since
+ // it is meant to be accessed only by the owner thread.
+ pLink = RemoveHeadList(&m_lePendingSignalingsOverflowList);
+ pdsln = CONTAINING_RECORD(pLink,
+ DeferredSignalingListNode,
+ Link);
+
+ // Do the actual signaling
+ palTempErr = CPalSynchronizationManager::SignalThreadCondition(
+ pdsln->pthrTarget->synchronizationInfo.GetNativeData());
+ if (NO_ERROR != palTempErr)
+ {
+ palErr = palTempErr;
+ }
+
+ // Release the thread reference
+ pdsln->pthrTarget->ReleaseThreadReference();
+
+ // Delete the node
+ InternalDelete(pdsln);
+
+ lIdx += 1;
+ }
+
+ _ASSERTE(lIdx == m_lPendingSignalingCount);
+ }
+
+ // Reset the counter of pending signalings for this thread
+ m_lPendingSignalingCount = 0;
+ }
+
+ return palErr;
+ }
+
+#endif // SYNCHMGR_SUSPENSION_SAFE_CONDITION_SIGNALING
+
+ /*++
+ Method:
+ CPalSynchronizationManager::HasProcessExited
+
+ Tests whether or not a process has exited
+ --*/
+ bool CPalSynchronizationManager::HasProcessExited(
+ DWORD dwPid,
+ DWORD * pdwExitCode,
+ bool * pfIsActualExitCode)
+ {
+ pid_t pidWaitRetval;
+ int iStatus;
+ bool fRet = false;
+
+ TRACE("Looking for status of process; trying wait()\n");
+
+ while(1)
+ {
+ /* try to get state of process, using non-blocking call */
+ pidWaitRetval = waitpid(dwPid, &iStatus, WNOHANG);
+
+ if ((DWORD)pidWaitRetval == dwPid)
+ {
+ /* success; get the exit code */
+ if (WIFEXITED(iStatus))
+ {
+ *pdwExitCode = WEXITSTATUS(iStatus);
+ *pfIsActualExitCode = true;
+ TRACE("Exit code was %d\n", *pdwExitCode);
+ }
+ else
+ {
+ WARN("Process terminated without exiting; can't get exit "
+ "code. Assuming EXIT_FAILURE.\n");
+ *pfIsActualExitCode = true;
+ *pdwExitCode = EXIT_FAILURE;
+ }
+
+ fRet = true;
+ }
+ else if (0 == pidWaitRetval)
+ {
+ // The process is still running.
+ TRACE("Process %#x is still active.\n", dwPid);
+ }
+ else
+ {
+ // A legitimate cause of failure is EINTR; if this happens we
+ // have to try again. A second legitimate cause is ECHILD, which
+ // happens if we're trying to retrieve the status of a currently-
+ // running process that isn't a child of this process.
+ if(EINTR == errno)
+ {
+ TRACE("waitpid() failed with EINTR; re-waiting\n");
+ continue;
+ }
+ else if (ECHILD == errno)
+ {
+ TRACE("waitpid() failed with ECHILD; calling kill instead\n");
+ if (kill(dwPid, 0) != 0)
+ {
+ if (ESRCH == errno)
+ {
+ WARN("kill() failed with ESRCH, i.e. target "
+ "process exited and it wasn't a child, "
+ "so can't get the exit code, assuming "
+ "it was 0.\n");
+ *pfIsActualExitCode = false;
+ *pdwExitCode = 0;
+ }
+ else
+ {
+ ERROR("kill(pid, 0) failed; errno is %d (%s)\n",
+ errno, strerror(errno));
+ *pfIsActualExitCode = false;
+ *pdwExitCode = EXIT_FAILURE;
+ }
+
+ fRet = true;
+ }
+ }
+ else
+ {
+ // Ignoring unexpected waitpid errno and assuming that
+ // the process is still running
+ ERROR("waitpid(pid=%u) failed with errno=%d (%s)\n",
+ dwPid, errno, strerror(errno));
+ }
+ }
+
+ // Break out of the loop in all cases except EINTR.
+ break;
+ }
+
+ return fRet;
+ }
+
+ /*++
+ Method:
+ CPalSynchronizationManager::InterlockedAwaken
+
+ Tries to change the target wait status to 'active' in an interlocked fashion
+ --*/
+ bool CPalSynchronizationManager::InterlockedAwaken(
+ DWORD *pWaitState,
+ bool fAlertOnly)
+ {
+ DWORD dwPrevState;
+
+ dwPrevState = InterlockedCompareExchange((LONG *)pWaitState, TWS_ACTIVE, TWS_ALERTABLE);
+ if (TWS_ALERTABLE != dwPrevState)
+ {
+ if (fAlertOnly)
+ {
+ return false;
+ }
+
+ dwPrevState = InterlockedCompareExchange((LONG *)pWaitState, TWS_ACTIVE, TWS_WAITING);
+ if (TWS_WAITING == dwPrevState)
+ {
+ return true;
+ }
+ }
+ else
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ /*++
+ Method:
+ CPalSynchronizationManager::GetAbsoluteTimeout
+
+ Converts a relative timeout to an absolute one.
+ --*/
+ PAL_ERROR CPalSynchronizationManager::GetAbsoluteTimeout(DWORD dwTimeout, struct timespec * ptsAbsTmo)
+ {
+ PAL_ERROR palErr = NO_ERROR;
+ int iRet;
+
+#if HAVE_WORKING_CLOCK_GETTIME
+ // Not every platform implements a (working) clock_gettime
+ iRet = clock_gettime(CLOCK_REALTIME, ptsAbsTmo);
+#elif HAVE_WORKING_GETTIMEOFDAY
+ // Not every platform implements a (working) gettimeofday
+ struct timeval tv;
+ iRet = gettimeofday(&tv, NULL);
+ if (0 == iRet)
+ {
+ ptsAbsTmo->tv_sec = tv.tv_sec;
+ ptsAbsTmo->tv_nsec = tv.tv_usec * tccMicroSecondsToNanoSeconds;
+ }
+#else
+ #error "Don't know how to get hi-res current time on this platform"
+#endif // HAVE_WORKING_CLOCK_GETTIME, HAVE_WORKING_GETTIMEOFDAY
+
+ if (0 == iRet)
+ {
+ ptsAbsTmo->tv_sec += dwTimeout / tccSecondsToMillieSeconds;
+ ptsAbsTmo->tv_nsec += (dwTimeout % tccSecondsToMillieSeconds) * tccMillieSecondsToNanoSeconds;
+ while (ptsAbsTmo->tv_nsec >= tccSecondsToNanoSeconds)
+ {
+ ptsAbsTmo->tv_sec += 1;
+ ptsAbsTmo->tv_nsec -= tccSecondsToNanoSeconds;
+ }
+ }
+ else
+ {
+ palErr = ERROR_INTERNAL_ERROR;
+ }
+
+ return palErr;
+ }
+}
diff --git a/src/pal/src/synchmgr/synchmanager.hpp b/src/pal/src/synchmgr/synchmanager.hpp
new file mode 100644
index 0000000000..fdef82e936
--- /dev/null
+++ b/src/pal/src/synchmgr/synchmanager.hpp
@@ -0,0 +1,1022 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ synchmanager.hpp
+
+Abstract:
+ Private header file for synchronization manager and
+ controllers implementation
+
+
+
+--*/
+#ifndef _SYNCHMANAGER_HPP_
+#define _SYNCHMANAGER_HPP_
+
+#include "pal/synchobjects.hpp"
+#include "pal/synchcache.hpp"
+#include "pal/cs.hpp"
+#include "pal/corunix.hpp"
+#include "pal/thread.hpp"
+#include "pal/procobj.hpp"
+#include "pal/init.h"
+#include "pal/process.h"
+
+#include <sys/types.h>
+#include <unistd.h>
+#if HAVE_KQUEUE
+#include <sys/event.h>
+#endif // HAVE_KQUEUE
+#include "pal/dbgmsg.h"
+
+#ifdef _DEBUG
+// #define SYNCH_OBJECT_VALIDATION
+// #define SYNCH_STATISTICS
+#endif
+
+#ifdef SYNCH_OBJECT_VALIDATION
+#define VALIDATEOBJECT(obj) ((obj)->ValidateObject())
+#else
+#define VALIDATEOBJECT(obj)
+#endif
+
+namespace CorUnix
+{
+ const DWORD WTLN_FLAG_OWNER_OBJECT_IS_SHARED = 1<<0;
+ const DWORD WTLN_FLAG_WAIT_ALL = 1<<1;
+ const DWORD WTLN_FLAG_DELEGATED_OBJECT_SIGNALING_IN_PROGRESS = 1<<2;
+
+#ifdef SYNCH_OBJECT_VALIDATION
+ const DWORD HeadSignature = 0x48454144;
+ const DWORD TailSignature = 0x5441494C;
+ const DWORD EmptySignature = 0xBAADF00D;
+#endif
+
+ enum THREAD_WAIT_STATE
+ {
+ TWS_ACTIVE,
+ TWS_WAITING,
+ TWS_ALERTABLE,
+ TWS_EARLYDEATH,
+ };
+
+ enum WaitCompletionState
+ {
+ WaitIsNotSatisfied,
+ WaitIsSatisfied,
+ WaitMayBeSatisfied
+ };
+
+ typedef union _SynchDataGenrPtr
+ {
+ SharedID shrid;
+ CSynchData * ptr;
+ } SynchDataGenrPtr;
+
+ typedef union _WTLNodeGenrPtr
+ {
+ SharedID shrid;
+ struct _WaitingThreadsListNode * ptr;
+ } WTLNodeGenrPtr;
+
+ typedef struct _WaitingThreadsListNode
+ {
+#ifdef SYNCH_OBJECT_VALIDATION
+ DWORD dwDebugHeadSignature;
+#endif
+ WTLNodeGenrPtr ptrNext;
+ WTLNodeGenrPtr ptrPrev;
+ SharedID shridSHRThis;
+
+ // Data
+ DWORD dwThreadId;
+ DWORD dwProcessId;
+ DWORD dwObjIndex;
+ DWORD dwFlags;
+
+ // Pointers to related objects
+ SharedID shridWaitingState;
+ SynchDataGenrPtr ptrOwnerObjSynchData;
+ struct _ThreadWaitInfo * ptwiWaitInfo; // valid only in the
+ // target process
+#ifdef SYNCH_OBJECT_VALIDATION
+ _WaitingThreadsListNode();
+ ~_WaitingThreadsListNode();
+ void ValidateObject(void);
+ void ValidateEmptyObject(void);
+ void InvalidateObject(void);
+
+ DWORD dwDebugTailSignature;
+#endif
+ } WaitingThreadsListNode;
+
+ typedef struct _DeferredSignalingListNode
+ {
+ LIST_ENTRY Link;
+ CPalThread * pthrTarget;
+ } DeferredSignalingListNode;
+
+ typedef struct _OwnedObjectsListNode
+ {
+ LIST_ENTRY Link;
+ CSynchData * pPalObjSynchData;
+ } OwnedObjectsListNode;
+
+ typedef struct _ThreadApcInfoNode
+ {
+ struct _ThreadApcInfoNode * pNext;
+ PAPCFUNC pfnAPC;
+ ULONG_PTR pAPCData;
+ } ThreadApcInfoNode;
+
+ class CPalSynchronizationManager; // fwd declaration
+ class CProcProcessLocalData; // fwd declaration
+
+ class CSynchData
+ {
+#ifdef SYNCH_OBJECT_VALIDATION
+ DWORD m_dwDebugHeadSignature;
+#endif
+ // NB: For perforformance purposes this class is supposed
+ // to have no virtual methods, and no destructor.
+
+ WTLNodeGenrPtr m_ptrWTLHead;
+ WTLNodeGenrPtr m_ptrWTLTail;
+ ULONG m_ulcWaitingThreads;
+ SharedID m_shridThis;
+ ObjectDomain m_odObjectDomain;
+ PalObjectTypeId m_otiObjectTypeId;
+ LONG m_lRefCount;
+ LONG m_lSignalCount;
+
+ // Ownership data
+ LONG m_lOwnershipCount;
+ DWORD m_dwOwnerPid;
+ DWORD m_dwOwnerTid; // used only by remote processes
+ // (thread ids may be recycled)
+ CPalThread * m_pOwnerThread; // valid only on the target process
+ OwnedObjectsListNode * m_poolnOwnedObjectListNode;
+ bool m_fAbandoned;
+
+#ifdef SYNCH_STATISTICS
+ ULONG m_lStatWaitCount;
+ ULONG m_lStatContentionCount;
+#endif
+
+ public:
+ CSynchData()
+ : m_ulcWaitingThreads(0), m_shridThis(NULLSharedID), m_lRefCount(1),
+ m_lSignalCount(0), m_lOwnershipCount(0), m_dwOwnerPid(0),
+ m_dwOwnerTid(0), m_pOwnerThread(NULL),
+ m_poolnOwnedObjectListNode(NULL), m_fAbandoned(false)
+ {
+ // m_ptrWTLHead, m_ptrWTLTail, m_odObjectDomain
+ // and m_otiObjectTypeId are initialized by
+ // CPalSynchronizationManager::AllocateObjectSynchData
+#ifdef SYNCH_STATISTICS
+ m_lStatWaitCount = 0;
+ m_lStatContentionCount = 0;
+#endif
+#ifdef SYNCH_OBJECT_VALIDATION
+ ValidateEmptyObject();
+ m_dwDebugHeadSignature = HeadSignature;;
+ m_dwDebugTailSignature = TailSignature;
+#endif
+ }
+
+ LONG AddRef()
+ {
+ return InterlockedIncrement(&m_lRefCount);
+ }
+
+ LONG Release(CPalThread * pthrCurrent);
+
+ bool CanWaiterWaitWithoutBlocking(
+ CPalThread * pWaiterThread,
+ bool * pfAbandoned);
+
+ PAL_ERROR ReleaseWaiterWithoutBlocking(
+ CPalThread * pthrCurrent,
+ CPalThread * pthrTarget);
+
+ void WaiterEnqueue(WaitingThreadsListNode * pwtlnNewNode);
+ void SharedWaiterEnqueue(SharedID shridNewNode);
+
+ // Object Domain accessor methods
+ ObjectDomain GetObjectDomain(void)
+ {
+ return m_odObjectDomain;
+ }
+ void SetObjectDomain(ObjectDomain odObjectDomain)
+ {
+ m_odObjectDomain = odObjectDomain;
+ }
+
+ // Object Type accessor methods
+ CObjectType * GetObjectType(void)
+ {
+ return CObjectType::GetObjectTypeById(m_otiObjectTypeId);
+ }
+ PalObjectTypeId GetObjectTypeId(void)
+ {
+ return m_otiObjectTypeId;
+ }
+ void SetObjectType(CObjectType * pot)
+ {
+ m_otiObjectTypeId = pot->GetId();
+ }
+ void SetObjectType(PalObjectTypeId oti)
+ {
+ m_otiObjectTypeId = oti;
+ }
+
+ // Object shared 'this' pointer accessor methods
+ SharedID GetSharedThis (void)
+ {
+ return m_shridThis;
+ }
+ void SetSharedThis (SharedID shridThis)
+ {
+ m_shridThis = shridThis;
+ }
+
+ void Signal(
+ CPalThread * pthrCurrent,
+ LONG lSignalCount,
+ bool fWorkerThread);
+
+ bool ReleaseFirstWaiter(
+ CPalThread * pthrCurrent,
+ bool * pfDelegated,
+ bool fWorkerThread);
+
+ LONG ReleaseAllLocalWaiters(
+ CPalThread * pthrCurrent);
+
+ WaitCompletionState IsRestOfWaitAllSatisfied(
+ WaitingThreadsListNode * pwtlnNode);
+
+ // Object signal count accessor methods
+ LONG GetSignalCount(void)
+ {
+ _ASSERTE(m_lSignalCount >= 0);
+ return m_lSignalCount;
+ }
+ void SetSignalCount(LONG lSignalCount)
+ {
+ _ASSERTE(m_lSignalCount >= 0);
+ _ASSERTE(lSignalCount >= 0);
+ m_lSignalCount = lSignalCount;
+ }
+ LONG DecrementSignalCount(void)
+ {
+ _ASSERTE(m_lSignalCount > 0);
+ return --m_lSignalCount;
+ }
+
+ // Object ownership accessor methods
+ void SetOwner(CPalThread * pOwnerThread);
+ void ResetOwnership(void);
+ PAL_ERROR AssignOwnershipToThread(
+ CPalThread * pthrCurrent,
+ CPalThread * pthrTarget);
+ DWORD GetOwnerProcessID(void)
+ {
+ return m_dwOwnerPid;
+ }
+ DWORD GetOwnerThreadID(void)
+ {
+ return m_dwOwnerTid;
+ }
+ CPalThread * GetOwnerThread(void)
+ {
+ return m_pOwnerThread;
+ }
+ OwnedObjectsListNode * GetOwnershipListNode(void)
+ {
+ return m_poolnOwnedObjectListNode;
+ }
+ void SetOwnershipListNode(OwnedObjectsListNode * pooln)
+ {
+ m_poolnOwnedObjectListNode = pooln;
+ }
+
+ // Object ownership count accessor methods
+ LONG GetOwnershipCount(void)
+ {
+ return m_lOwnershipCount;
+ }
+ void SetOwnershipCount(LONG lOwnershipCount)
+ {
+ m_lOwnershipCount = lOwnershipCount;
+ }
+
+ // Object abandoned flag accessor methods
+ void SetAbandoned(bool fAbandoned)
+ { m_fAbandoned = fAbandoned; }
+ bool IsAbandoned(void) { return m_fAbandoned; }
+
+ void IncrementWaitingThreadCount(void)
+ {
+ m_ulcWaitingThreads += 1;
+ }
+ void DecrementWaitingThreadCount(void)
+ {
+ m_ulcWaitingThreads -= 1;
+ }
+ ULONG GetWaitingThreadCount(void)
+ {
+ return m_ulcWaitingThreads;
+ }
+
+
+#ifdef SYNCH_STATISTICS
+ void IncrementStatWaitCount(void)
+ {
+ m_lStatWaitCount++;
+ }
+ LONG GetStatWaitCount(void)
+ {
+ return m_lStatWaitCount;
+ }
+ void IncrementStatContentionCount(void)
+ {
+ m_lStatContentionCount++;
+ }
+ LONG GetStatContentionCount(void)
+ {
+ return m_lStatContentionCount;
+ }
+#endif
+ //
+ // Wating threads list access methods
+ //
+ WaitingThreadsListNode * GetWTLHeadPtr(void)
+ {
+ return m_ptrWTLHead.ptr;
+ }
+ WaitingThreadsListNode * GetWTLTailPtr(void)
+ {
+ return m_ptrWTLTail.ptr;
+ }
+ SharedID GetWTLHeadShmPtr(void)
+ {
+ return m_ptrWTLHead.shrid;
+ }
+ SharedID GetWTLTailShmPtr(void)
+ {
+ return m_ptrWTLTail.shrid;
+ }
+ void SetWTLHeadPtr(WaitingThreadsListNode * p)
+ {
+ m_ptrWTLHead.ptr = p;
+ }
+ void SetWTLTailPtr(WaitingThreadsListNode * p)
+ {
+ m_ptrWTLTail.ptr = p;
+ }
+ void SetWTLHeadShrPtr(SharedID shrid)
+ {
+ m_ptrWTLHead.shrid = shrid;
+ }
+ void SetWTLTailShrPtr(SharedID shrid)
+ {
+ m_ptrWTLTail.shrid = shrid;
+ }
+#ifdef SYNCH_OBJECT_VALIDATION
+ ~CSynchData();
+ void ValidateObject(bool fDestructor = false);
+ void ValidateEmptyObject(void);
+ void InvalidateObject(void);
+
+ DWORD m_dwDebugTailSignature;
+#endif
+ };
+
+
+ class CSynchControllerBase
+ {
+ friend class CPalSynchronizationManager;
+
+ // NB: For perforformance purposes this class is supposed
+ // to have no virtual methods, contructor and
+ // destructor
+ public:
+ enum ControllerType { WaitController, StateController };
+
+ protected:
+ CPalThread * m_pthrOwner;
+ ControllerType m_ctCtrlrType;
+ ObjectDomain m_odObjectDomain;
+ CObjectType * m_potObjectType;
+ CSynchData * m_psdSynchData;
+ WaitDomain m_wdWaitDomain;
+
+ PAL_ERROR Init(
+ CPalThread * pthrCurrent,
+ ControllerType ctCtrlrType,
+ ObjectDomain odObjectDomain,
+ CObjectType *potObjectType,
+ CSynchData * psdSynchData,
+ WaitDomain wdWaitDomain);
+
+ void Release(void);
+
+ void SetSynchData(CSynchData * psdSynchData)
+ {
+ m_psdSynchData = psdSynchData;
+ }
+ CSynchData * GetSynchData()
+ {
+ return m_psdSynchData;
+ }
+ };
+
+ class CSynchWaitController : public CSynchControllerBase,
+ public ISynchWaitController
+ {
+ // Per-object-type specific data
+ //
+ // Process (otiProcess)
+ IPalObject *m_pProcessObject; // process that owns m_pProcLocalData, this is stored without a reference
+ CProcProcessLocalData * m_pProcLocalData;
+
+ public:
+ CSynchWaitController() : m_pProcessObject(NULL), m_pProcLocalData(NULL) {}
+ virtual ~CSynchWaitController() = default;
+
+ //
+ // ISynchWaitController methods
+ //
+ virtual PAL_ERROR CanThreadWaitWithoutBlocking(
+ bool * pfCanWaitWithoutBlocking,
+ bool * pfAbandoned);
+
+ virtual PAL_ERROR ReleaseWaitingThreadWithoutBlocking(void);
+
+ virtual PAL_ERROR RegisterWaitingThread(
+ WaitType wtWaitType,
+ DWORD dwIndex,
+ bool fAlertable);
+
+ virtual void ReleaseController(void);
+
+ CProcProcessLocalData * GetProcessLocalData(void);
+
+ void SetProcessData(IPalObject* pProcessObject, CProcProcessLocalData * pProcLocalData);
+ };
+
+ class CSynchStateController : public CSynchControllerBase,
+ public ISynchStateController
+ {
+ public:
+ // NB: For perforformance purposes this class is supposed
+ // to have no constructor
+ virtual ~CSynchStateController() = default;
+
+ //
+ // ISynchStateController methods
+ //
+ virtual PAL_ERROR GetSignalCount(LONG *plSignalCount);
+ virtual PAL_ERROR SetSignalCount(LONG lNewCount);
+ virtual PAL_ERROR IncrementSignalCount(LONG lAmountToIncrement);
+ virtual PAL_ERROR DecrementSignalCount(LONG lAmountToDecrement);
+ virtual PAL_ERROR SetOwner(CPalThread *pNewOwningThread);
+ virtual PAL_ERROR DecrementOwnershipCount(void);
+ virtual void ReleaseController(void);
+ };
+
+ class CPalSynchronizationManager : public IPalSynchronizationManager
+ {
+ friend class CPalSynchMgrController;
+ template <class T> friend T *CorUnix::InternalNew();
+
+ public:
+ // types
+ typedef CSynchCache<CSynchWaitController> CSynchWaitControllerCache;
+ typedef CSynchCache<CSynchStateController> CSynchStateControllerCache;
+ typedef CSynchCache<CSynchData> CSynchDataCache;
+ typedef CSHRSynchCache<CSynchData> CSHRSynchDataCache;
+ typedef CSynchCache<WaitingThreadsListNode> CWaitingThreadsListNodeCache;
+ typedef CSHRSynchCache<WaitingThreadsListNode> CSHRWaitingThreadsListNodeCache;
+ typedef CSynchCache<ThreadApcInfoNode> CThreadApcInfoNodeCache;
+ typedef CSynchCache<OwnedObjectsListNode> COwnedObjectsListNodeCache;
+
+ private:
+ // types
+ enum InitStatus
+ {
+ SynchMgrStatusIdle,
+ SynchMgrStatusInitializing,
+ SynchMgrStatusRunning,
+ SynchMgrStatusShuttingDown,
+ SynchMgrStatusReadyForProcessShutDown,
+ SynchMgrStatusError
+ };
+ enum SynchWorkerCmd
+ {
+ SynchWorkerCmdNop,
+ SynchWorkerCmdRemoteSignal,
+ SynchWorkerCmdDelegatedObjectSignaling,
+ SynchWorkerCmdShutdown,
+ SynchWorkerCmdTerminationRequest,
+ SynchWorkerCmdLast
+ };
+
+ typedef struct _MonitoredProcessesListNode
+ {
+ struct _MonitoredProcessesListNode * pNext;
+ LONG lRefCount;
+ CSynchData * psdSynchData;
+ DWORD dwPid;
+ DWORD dwExitCode;
+ bool fIsActualExitCode;
+
+ // Object that owns pProcLocalData. This is stored, with a reference, to
+ // ensure that pProcLocalData is not deleted.
+ IPalObject *pProcessObject;
+ CProcProcessLocalData * pProcLocalData;
+ } MonitoredProcessesListNode;
+
+ // constants
+ static const int CtrlrsCacheMaxSize = 256;
+ static const int SynchDataCacheMaxSize = 256;
+ static const int WTListNodeCacheMaxSize = 256;
+ static const int ApcInfoNodeCacheMaxSize = 32;
+ static const int OwnedObjectsListCacheMaxSize = 16;
+ static const int MaxWorkerConsecutiveEintrs = 128;
+ static const int MaxConsecutiveEagains = 128;
+ static const int WorkerThreadProcMonitoringTimeout = 250; // ms
+ static const int WorkerThreadShuttingDownTimeout = 1000; // ms
+ static const int WorkerCmdCompletionTimeout = 250; // ms
+ static const DWORD SecondNativeWaitTimeout = INFINITE;
+ static const DWORD WorkerThreadTerminationTimeout = 2000; // ms
+
+ // static members
+ static CPalSynchronizationManager * s_pObjSynchMgr;
+ static Volatile<LONG> s_lInitStatus;
+ static CRITICAL_SECTION s_csSynchProcessLock;
+ static CRITICAL_SECTION s_csMonitoredProcessesLock;
+
+ // members
+ DWORD m_dwWorkerThreadTid;
+ IPalObject * m_pipoThread;
+ CPalThread * m_pthrWorker;
+ int m_iProcessPipeRead;
+ int m_iProcessPipeWrite;
+#if HAVE_KQUEUE
+ int m_iKQueue;
+ struct kevent m_keProcessPipeEvent;
+#endif // HAVE_KQUEUE
+
+ MonitoredProcessesListNode * m_pmplnMonitoredProcesses;
+ LONG m_lMonitoredProcessesCount;
+ MonitoredProcessesListNode * m_pmplnExitedNodes;
+
+ // caches
+ CSynchWaitControllerCache m_cacheWaitCtrlrs;
+ CSynchStateControllerCache m_cacheStateCtrlrs;
+ CSynchDataCache m_cacheSynchData;
+ CSHRSynchDataCache m_cacheSHRSynchData;
+ CWaitingThreadsListNodeCache m_cacheWTListNodes;
+ CSHRWaitingThreadsListNodeCache m_cacheSHRWTListNodes;
+ CThreadApcInfoNodeCache m_cacheThreadApcInfoNodes;
+ COwnedObjectsListNodeCache m_cacheOwnedObjectsListNodes;
+
+ // static methods
+ static PAL_ERROR Initialize();
+ static DWORD PALAPI WorkerThread(LPVOID pArg);
+
+ protected:
+ CPalSynchronizationManager();
+
+ PAL_ERROR GetSynchControllersForObjects(
+ CPalThread *pthrCurrent,
+ IPalObject *rgObjects[],
+ DWORD dwObjectCount,
+ void ** ppvControllers,
+ CSynchControllerBase::ControllerType ctCtrlrType);
+
+ private:
+ static IPalSynchronizationManager * CreatePalSynchronizationManager();
+ static PAL_ERROR StartWorker(CPalThread * pthrCurrent);
+ static PAL_ERROR PrepareForShutdown(void);
+
+ public:
+ virtual ~CPalSynchronizationManager();
+
+ static CPalSynchronizationManager * GetInstance(void)
+ {
+ // No need here to check for NULL and in case create the
+ // singleton, since its creation is enforced by the PAL
+ // initialization code.
+ return s_pObjSynchMgr;
+ }
+
+ //
+ // Inline utility methods
+ //
+ static void AcquireLocalSynchLock(CPalThread * pthrCurrent)
+ {
+ _ASSERTE(0 <= pthrCurrent->synchronizationInfo.m_lLocalSynchLockCount);
+
+ if (1 == ++pthrCurrent->synchronizationInfo.m_lLocalSynchLockCount)
+ {
+ InternalEnterCriticalSection(pthrCurrent, &s_csSynchProcessLock);
+ }
+ }
+ static void ReleaseLocalSynchLock(CPalThread * pthrCurrent)
+ {
+ _ASSERTE(0 < pthrCurrent->synchronizationInfo.m_lLocalSynchLockCount);
+ if (0 == --pthrCurrent->synchronizationInfo.m_lLocalSynchLockCount)
+ {
+ InternalLeaveCriticalSection(pthrCurrent, &s_csSynchProcessLock);
+
+#if SYNCHMGR_SUSPENSION_SAFE_CONDITION_SIGNALING
+ pthrCurrent->synchronizationInfo.RunDeferredThreadConditionSignalings();
+#endif // SYNCHMGR_SUSPENSION_SAFE_CONDITION_SIGNALING
+ }
+ }
+ static LONG ResetLocalSynchLock(CPalThread * pthrCurrent)
+ {
+ LONG lRet = pthrCurrent->synchronizationInfo.m_lLocalSynchLockCount;
+
+ _ASSERTE(0 <= lRet);
+ if (0 < lRet)
+ {
+ pthrCurrent->synchronizationInfo.m_lLocalSynchLockCount = 0;
+ InternalLeaveCriticalSection(pthrCurrent, &s_csSynchProcessLock);
+
+#if SYNCHMGR_SUSPENSION_SAFE_CONDITION_SIGNALING
+ pthrCurrent->synchronizationInfo.RunDeferredThreadConditionSignalings();
+#endif // SYNCHMGR_SUSPENSION_SAFE_CONDITION_SIGNALING
+ }
+ return lRet;
+ }
+ static LONG GetLocalSynchLockCount(CPalThread * pthrCurrent)
+ {
+ _ASSERTE(0 <= pthrCurrent->synchronizationInfo.m_lLocalSynchLockCount);
+ return pthrCurrent->synchronizationInfo.m_lLocalSynchLockCount;
+ }
+
+ static void AcquireSharedSynchLock(CPalThread * pthrCurrent)
+ {
+ _ASSERTE(0 <= pthrCurrent->synchronizationInfo.m_lSharedSynchLockCount);
+ _ASSERT_MSG(0 < pthrCurrent->synchronizationInfo.m_lLocalSynchLockCount,
+ "The local synch lock should be acquired before grabbing the "
+ "shared one.\n");
+ if (1 == ++pthrCurrent->synchronizationInfo.m_lSharedSynchLockCount)
+ {
+ SHMLock();
+ }
+ }
+ static void ReleaseSharedSynchLock(CPalThread * pthrCurrent)
+ {
+ _ASSERTE(0 < pthrCurrent->synchronizationInfo.m_lSharedSynchLockCount);
+ if (0 == --pthrCurrent->synchronizationInfo.m_lSharedSynchLockCount)
+ {
+ _ASSERT_MSG(0 < pthrCurrent->synchronizationInfo.m_lLocalSynchLockCount,
+ "Final release of the shared synch lock while not holding the "
+ "local one. Local synch lock should always be acquired first and "
+ "released last.\n");
+ SHMRelease();
+ }
+ }
+ static LONG ResetSharedSynchLock(CPalThread * pthrCurrent)
+ {
+ LONG lRet = pthrCurrent->synchronizationInfo.m_lSharedSynchLockCount;
+
+ _ASSERTE(0 <= lRet);
+ _ASSERTE(0 == lRet ||
+ 0 < pthrCurrent->synchronizationInfo.m_lLocalSynchLockCount);
+ if (0 < lRet)
+ {
+ pthrCurrent->synchronizationInfo.m_lSharedSynchLockCount = 0;
+ SHMRelease();
+ }
+ return lRet;
+ }
+ static LONG GetSharedSynchLockCount(CPalThread * pthrCurrent)
+ {
+ _ASSERTE(0 <= pthrCurrent->synchronizationInfo.m_lSharedSynchLockCount);
+ _ASSERTE(0 == pthrCurrent->synchronizationInfo.m_lSharedSynchLockCount ||
+ 0 < pthrCurrent->synchronizationInfo.m_lLocalSynchLockCount);
+ return pthrCurrent->synchronizationInfo.m_lSharedSynchLockCount;
+ }
+
+ CSynchWaitController * CacheGetWaitCtrlr(CPalThread * pthrCurrent)
+ {
+ return m_cacheWaitCtrlrs.Get(pthrCurrent);
+ }
+ int CacheGetWaitCtrlr(
+ CPalThread * pthrCurrent,
+ int n,
+ CSynchWaitController * prgCtrlrs[])
+ {
+ return m_cacheWaitCtrlrs.Get(pthrCurrent, n, prgCtrlrs);
+ }
+ void CacheAddWaitCtrlr(
+ CPalThread * pthrCurrent,
+ CSynchWaitController * pCtrlr)
+ {
+ m_cacheWaitCtrlrs.Add(pthrCurrent, pCtrlr);
+ }
+ CSynchStateController * CacheGetStateCtrlr(CPalThread * pthrCurrent)
+ {
+ return m_cacheStateCtrlrs.Get(pthrCurrent);
+ }
+ int CacheGetStateCtrlr(
+ CPalThread * pthrCurrent,
+ int n,
+ CSynchStateController * prgCtrlrs[])
+ {
+ return m_cacheStateCtrlrs.Get(pthrCurrent, n, prgCtrlrs);
+ }
+ void CacheAddStateCtrlr(
+ CPalThread * pthrCurrent,
+ CSynchStateController * pCtrlr)
+ {
+ m_cacheStateCtrlrs.Add(pthrCurrent, pCtrlr);
+ }
+
+ CSynchData * CacheGetLocalSynchData(CPalThread * pthrCurrent)
+ {
+ return m_cacheSynchData.Get(pthrCurrent);
+ }
+ void CacheAddLocalSynchData(
+ CPalThread * pthrCurrent,
+ CSynchData * psdSynchData)
+ {
+ m_cacheSynchData.Add(pthrCurrent, psdSynchData);
+ }
+ SharedID CacheGetSharedSynchData(CPalThread * pthrCurrent)
+ {
+ return m_cacheSHRSynchData.Get(pthrCurrent);
+ }
+ void CacheAddSharedSynchData(
+ CPalThread * pthrCurrent,
+ SharedID shridSData)
+ {
+ m_cacheSHRSynchData.Add(pthrCurrent, shridSData);
+ }
+
+ WaitingThreadsListNode * CacheGetLocalWTListNode(
+ CPalThread * pthrCurrent)
+ {
+ return m_cacheWTListNodes.Get(pthrCurrent);
+ }
+ void CacheAddLocalWTListNode(
+ CPalThread * pthrCurrent,
+ WaitingThreadsListNode * pWTLNode)
+ {
+ m_cacheWTListNodes.Add(pthrCurrent, pWTLNode);
+ }
+ SharedID CacheGetSharedWTListNode(CPalThread * pthrCurrent)
+ {
+ return m_cacheSHRWTListNodes.Get(pthrCurrent);
+ }
+ void CacheAddSharedWTListNode(
+ CPalThread * pthrCurrent,
+ SharedID shridWTLNode)
+ {
+ m_cacheSHRWTListNodes.Add(pthrCurrent, shridWTLNode);
+ }
+
+ ThreadApcInfoNode * CacheGetApcInfoNodes(CPalThread * pthrCurrent)
+ {
+ return m_cacheThreadApcInfoNodes.Get(pthrCurrent);
+ }
+ void CacheAddApcInfoNodes(
+ CPalThread * pthrCurrent,
+ ThreadApcInfoNode * pNode)
+ {
+ m_cacheThreadApcInfoNodes.Add(pthrCurrent, pNode);
+ }
+
+ OwnedObjectsListNode * CacheGetOwnedObjsListNode(
+ CPalThread * pthrCurrent)
+ {
+ return m_cacheOwnedObjectsListNodes.Get(pthrCurrent);
+ }
+ void CacheAddOwnedObjsListNode(
+ CPalThread * pthrCurrent,
+ OwnedObjectsListNode * pNode)
+ {
+ m_cacheOwnedObjectsListNodes.Add(pthrCurrent, pNode);
+ }
+
+
+ //
+ // IPalSynchronizationManager methods
+ //
+ virtual PAL_ERROR BlockThread(
+ CPalThread *pthrCurrent,
+ DWORD dwTimeout,
+ bool fAlertable,
+ bool fIsSleep,
+ ThreadWakeupReason *ptwrWakeupReason,
+ DWORD *pdwSignaledObject);
+
+ virtual PAL_ERROR AbandonObjectsOwnedByThread(
+ CPalThread *pthrCurrent,
+ CPalThread *pthrTarget);
+
+ virtual PAL_ERROR GetSynchWaitControllersForObjects(
+ CPalThread *pthrCurrent,
+ IPalObject *rgObjects[],
+ DWORD dwObjectCount,
+ ISynchWaitController *rgControllers[]);
+
+ virtual PAL_ERROR GetSynchStateControllersForObjects(
+ CPalThread *pthrCurrent,
+ IPalObject *rgObjects[],
+ DWORD dwObjectCount,
+ ISynchStateController *rgControllers[]);
+
+ virtual PAL_ERROR AllocateObjectSynchData(
+ CObjectType *potObjectType,
+ ObjectDomain odObjectDomain,
+ VOID **ppvSynchData);
+
+ virtual void FreeObjectSynchData(
+ CObjectType *potObjectType,
+ ObjectDomain odObjectDomain,
+ VOID *pvSynchData);
+
+ virtual PAL_ERROR PromoteObjectSynchData(
+ CPalThread *pthrCurrent,
+ VOID *pvLocalSynchData,
+ VOID **ppvSharedSynchData);
+
+ virtual PAL_ERROR CreateSynchStateController(
+ CPalThread *pthrCurrent,
+ CObjectType *potObjectType,
+ VOID *pvSynchData,
+ ObjectDomain odObjectDomain,
+ ISynchStateController **ppStateController);
+
+ virtual PAL_ERROR CreateSynchWaitController(
+ CPalThread *pthrCurrent,
+ CObjectType *potObjectType,
+ VOID *pvSynchData,
+ ObjectDomain odObjectDomain,
+ ISynchWaitController **ppWaitController);
+
+ virtual PAL_ERROR QueueUserAPC(
+ CPalThread * pthrCurrent,
+ CPalThread *pthrTarget,
+ PAPCFUNC pfnAPC,
+ ULONG_PTR uptrData);
+
+ virtual PAL_ERROR SendTerminationRequestToWorkerThread();
+
+ virtual bool AreAPCsPending(CPalThread * pthrTarget);
+
+ virtual PAL_ERROR DispatchPendingAPCs(CPalThread * pthrCurrent);
+
+ virtual void AcquireProcessLock(CPalThread *pthrCurrent);
+
+ virtual void ReleaseProcessLock(CPalThread *pthrCurrent);
+
+ //
+ // Static helper methods
+ //
+ public:
+ static PAL_ERROR WakeUpLocalThread(
+ CPalThread * pthrCurrent,
+ CPalThread * pthrTarget,
+ ThreadWakeupReason twrWakeupReason,
+ DWORD dwObjectIndex);
+
+ static PAL_ERROR SignalThreadCondition(
+ ThreadNativeWaitData * ptnwdNativeWaitData);
+
+ static PAL_ERROR DeferThreadConditionSignaling(
+ CPalThread * pthrCurrent,
+ CPalThread * pthrTarget);
+
+ static PAL_ERROR WakeUpRemoteThread(
+ SharedID shridWLNode);
+
+ static PAL_ERROR DelegateSignalingToRemoteProcess(
+ CPalThread * pthrCurrent,
+ DWORD dwTargetProcessId,
+ SharedID shridSynchData);
+
+ static PAL_ERROR SendMsgToRemoteWorker(
+ DWORD dwProcessId,
+ BYTE * pMsg,
+ int iMsgSize);
+
+ static ThreadWaitInfo * GetThreadWaitInfo(
+ CPalThread * pthrCurrent);
+
+ //
+ // The following methods must be called only by a Sync*Controller or
+ // while holding the required synchronization global locks
+ //
+ static void UnsignalRestOfLocalAwakeningWaitAll(
+ CPalThread * pthrCurrent,
+ CPalThread * pthrTarget,
+ WaitingThreadsListNode * pwtlnNode,
+ CSynchData * psdTgtObjectSynchData);
+
+ static void MarkWaitForDelegatedObjectSignalingInProgress(
+ CPalThread * pthrCurrent,
+ WaitingThreadsListNode * pwtlnNode);
+
+ static void UnmarkTWListForDelegatedObjectSignalingInProgress(
+ CSynchData * pTgtObjectSynchData);
+
+ static PAL_ERROR ThreadNativeWait(
+ ThreadNativeWaitData * ptnwdNativeWaitData,
+ DWORD dwTimeout,
+ ThreadWakeupReason * ptwrWakeupReason,
+ DWORD * pdwSignaledObject);
+
+ static void ThreadPrepareForShutdown(void);
+
+#ifndef CORECLR
+ static bool GetProcessPipeName(
+ LPSTR pDest,
+ int iDestSize,
+ DWORD dwPid);
+#endif // !CORECLR
+
+ //
+ // Non-static helper methods
+ //
+ private:
+ LONG DoMonitorProcesses(CPalThread * pthrCurrent);
+
+ void DiscardMonitoredProcesses(CPalThread * pthrCurrent);
+
+ PAL_ERROR ReadCmdFromProcessPipe(
+ int iPollTimeout,
+ SynchWorkerCmd * pswcWorkerCmd,
+ SharedID * pshridMarshaledData,
+ DWORD * pdwData);
+
+ PAL_ERROR WakeUpLocalWorkerThread(
+ SynchWorkerCmd swcWorkerCmd);
+
+ void DiscardAllPendingAPCs(
+ CPalThread * pthrCurrent,
+ CPalThread * pthrTarget);
+
+ int ReadBytesFromProcessPipe(
+ int iTimeout,
+ BYTE * pRecvBuf,
+ LONG lBytes);
+
+ bool CreateProcessPipe();
+
+ PAL_ERROR ShutdownProcessPipe();
+
+ public:
+ //
+ // The following methods must be called only by a Sync*Controller or
+ // while holding the required synchronization global locks
+ //
+ void UnRegisterWait(
+ CPalThread * pthrCurrent,
+ ThreadWaitInfo * ptwiWaitInfo,
+ bool fHaveSharedLock);
+
+ PAL_ERROR RegisterProcessForMonitoring(
+ CPalThread * pthrCurrent,
+ CSynchData *psdSynchData,
+ IPalObject *pProcessObject,
+ CProcProcessLocalData * pProcLocalData);
+
+ PAL_ERROR UnRegisterProcessForMonitoring(
+ CPalThread * pthrCurrent,
+ CSynchData *psdSynchData,
+ DWORD dwPid);
+
+ //
+ // Utility static methods, no lock required
+ //
+ static bool HasProcessExited(
+ DWORD dwPid,
+ DWORD * pdwExitCode,
+ bool * pfIsActualExitCode);
+
+ static bool InterlockedAwaken(
+ DWORD *pWaitState,
+ bool fAlertOnly);
+
+ static PAL_ERROR GetAbsoluteTimeout(
+ DWORD dwTimeout,
+ struct timespec * ptsAbsTmo);
+ };
+}
+
+#endif // _SYNCHMANAGER_HPP_
diff --git a/src/pal/src/synchmgr/wait.cpp b/src/pal/src/synchmgr/wait.cpp
new file mode 100644
index 0000000000..9c4fe3a9ca
--- /dev/null
+++ b/src/pal/src/synchmgr/wait.cpp
@@ -0,0 +1,711 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ wait.cpp
+
+Abstract:
+
+ Implementation of waiting functions as described in
+ the WIN32 API
+
+Revision History:
+
+
+
+--*/
+
+#include "pal/thread.hpp"
+#include "pal/synchobjects.hpp"
+#include "pal/malloc.hpp"
+#include "pal/dbgmsg.h"
+
+SET_DEFAULT_DEBUG_CHANNEL(SYNC);
+
+#define MAXIMUM_STACK_WAITOBJ_ARRAY_SIZE (MAXIMUM_WAIT_OBJECTS / 4)
+
+using namespace CorUnix;
+
+static PalObjectTypeId sg_rgWaitObjectsIds[] =
+ {
+ otiAutoResetEvent,
+ otiManualResetEvent,
+ otiMutex,
+ otiNamedMutex,
+ otiSemaphore,
+ otiProcess,
+ otiThread
+ };
+static CAllowedObjectTypes sg_aotWaitObject(sg_rgWaitObjectsIds,
+ sizeof(sg_rgWaitObjectsIds)/sizeof(sg_rgWaitObjectsIds[0]));
+
+/*++
+Function:
+ WaitForSingleObject
+
+See MSDN doc.
+--*/
+DWORD
+PALAPI
+WaitForSingleObject(IN HANDLE hHandle,
+ IN DWORD dwMilliseconds)
+{
+ DWORD dwRet;
+
+ PERF_ENTRY(WaitForSingleObject);
+ ENTRY("WaitForSingleObject(hHandle=%p, dwMilliseconds=%u)\n",
+ hHandle, dwMilliseconds);
+
+ CPalThread * pThread = InternalGetCurrentThread();
+
+ dwRet = InternalWaitForMultipleObjectsEx(pThread, 1, &hHandle, FALSE,
+ dwMilliseconds, FALSE);
+
+ LOGEXIT("WaitForSingleObject returns DWORD %u\n", dwRet);
+ PERF_EXIT(WaitForSingleObject);
+ return dwRet;
+}
+
+
+/*++
+Function:
+ WaitForSingleObjectEx
+
+See MSDN doc.
+--*/
+DWORD
+PALAPI
+WaitForSingleObjectEx(IN HANDLE hHandle,
+ IN DWORD dwMilliseconds,
+ IN BOOL bAlertable)
+{
+ DWORD dwRet;
+
+ PERF_ENTRY(WaitForSingleObjectEx);
+ ENTRY("WaitForSingleObjectEx(hHandle=%p, dwMilliseconds=%u, bAlertable=%s)\n",
+ hHandle, dwMilliseconds, bAlertable ? "TRUE" : "FALSE");
+
+ CPalThread * pThread = InternalGetCurrentThread();
+
+ dwRet = InternalWaitForMultipleObjectsEx(pThread, 1, &hHandle, FALSE,
+ dwMilliseconds, bAlertable);
+
+ LOGEXIT("WaitForSingleObjectEx returns DWORD %u\n", dwRet);
+ PERF_EXIT(WaitForSingleObjectEx);
+ return dwRet;
+}
+
+
+/*++
+Function:
+ WaitForMultipleObjects
+
+See MSDN doc.
+
+--*/
+DWORD
+PALAPI
+WaitForMultipleObjects(IN DWORD nCount,
+ IN CONST HANDLE *lpHandles,
+ IN BOOL bWaitAll,
+ IN DWORD dwMilliseconds)
+{
+ DWORD dwRet;
+
+ PERF_ENTRY(WaitForMultipleObjects);
+ ENTRY("WaitForMultipleObjects(nCount=%d, lpHandles=%p,"
+ " bWaitAll=%d, dwMilliseconds=%u)\n",
+ nCount, lpHandles, bWaitAll, dwMilliseconds);
+
+ CPalThread * pThread = InternalGetCurrentThread();
+
+ dwRet = InternalWaitForMultipleObjectsEx(pThread, nCount, lpHandles,
+ bWaitAll, dwMilliseconds, FALSE);
+
+ LOGEXIT("WaitForMultipleObjects returns DWORD %u\n", dwRet);
+ PERF_EXIT(WaitForMultipleObjects);
+ return dwRet;
+}
+
+/*++
+Function:
+ WaitForMultipleObjectsEx
+
+See MSDN doc for info about this function.
+--*/
+DWORD
+PALAPI
+WaitForMultipleObjectsEx(IN DWORD nCount,
+ IN CONST HANDLE *lpHandles,
+ IN BOOL bWaitAll,
+ IN DWORD dwMilliseconds,
+ IN BOOL bAlertable)
+{
+ DWORD dwRet;
+
+ PERF_ENTRY(WaitForMultipleObjectsEx);
+ ENTRY("WaitForMultipleObjectsEx(nCount=%d, lpHandles=%p,"
+ " bWaitAll=%d, dwMilliseconds=%u, bAlertable=d)\n",
+ nCount, lpHandles, bWaitAll, dwMilliseconds, bAlertable);
+
+ CPalThread * pThread = InternalGetCurrentThread();
+
+ dwRet = InternalWaitForMultipleObjectsEx(pThread, nCount, lpHandles, bWaitAll,
+ dwMilliseconds, bAlertable);
+
+ LOGEXIT("WaitForMultipleObjectsEx returns DWORD %u\n", dwRet);
+ PERF_EXIT(WaitForMultipleObjectsEx);
+ return dwRet;
+}
+
+/*++
+Function:
+ Sleep
+
+See MSDN doc.
+--*/
+VOID
+PALAPI
+Sleep(IN DWORD dwMilliseconds)
+{
+ PERF_ENTRY(Sleep);
+ ENTRY("Sleep(dwMilliseconds=%u)\n", dwMilliseconds);
+
+ CPalThread * pThread = InternalGetCurrentThread();
+
+ DWORD internalSleepRet = InternalSleepEx(pThread, dwMilliseconds, FALSE);
+
+ if (internalSleepRet != 0)
+ {
+ ERROR("Sleep(dwMilliseconds=%u) failed [error=%u]\n", dwMilliseconds, internalSleepRet);
+ pThread->SetLastError(internalSleepRet);
+ }
+
+ LOGEXIT("Sleep returns VOID\n");
+ PERF_EXIT(Sleep);
+}
+
+
+/*++
+Function:
+ SleepEx
+
+See MSDN doc.
+--*/
+DWORD
+PALAPI
+SleepEx(IN DWORD dwMilliseconds,
+ IN BOOL bAlertable)
+{
+ DWORD dwRet;
+
+ PERF_ENTRY(SleepEx);
+ ENTRY("SleepEx(dwMilliseconds=%u, bAlertable=%d)\n", dwMilliseconds, bAlertable);
+
+ CPalThread * pThread = InternalGetCurrentThread();
+
+ dwRet = InternalSleepEx(pThread, dwMilliseconds, bAlertable);
+
+ LOGEXIT("SleepEx returns DWORD %u\n", dwRet);
+ PERF_EXIT(SleepEx);
+
+ return dwRet;
+}
+
+/*++
+Function:
+ QueueUserAPC
+
+See MSDN doc.
+--*/
+DWORD
+PALAPI
+QueueUserAPC(
+ PAPCFUNC pfnAPC,
+ HANDLE hThread,
+ ULONG_PTR dwData)
+{
+ CPalThread * pCurrentThread = NULL;
+ CPalThread * pTargetThread = NULL;
+ IPalObject * pTargetThreadObject = NULL;
+ PAL_ERROR palErr;
+ DWORD dwRet;
+
+ PERF_ENTRY(QueueUserAPC);
+ ENTRY("QueueUserAPC(pfnAPC=%p, hThread=%p, dwData=%#x)\n",
+ pfnAPC, hThread, dwData);
+
+ /* NOTE: Windows does not check the validity of pfnAPC, even if it is
+ NULL. It just does an access violation later on when the APC call
+ is attempted */
+
+ pCurrentThread = InternalGetCurrentThread();
+
+ palErr = InternalGetThreadDataFromHandle(
+ pCurrentThread,
+ hThread,
+ 0, // THREAD_SET_CONTEXT
+ &pTargetThread,
+ &pTargetThreadObject
+ );
+
+ if (NO_ERROR != palErr)
+ {
+ ERROR("Unable to obtain thread data for handle %p (error %x)!\n",
+ hThread, palErr);
+ goto QueueUserAPC_exit;
+ }
+
+
+ palErr = g_pSynchronizationManager->QueueUserAPC(pCurrentThread, pTargetThread,
+ pfnAPC, dwData);
+
+QueueUserAPC_exit:
+ if (pTargetThreadObject)
+ {
+ pTargetThreadObject->ReleaseReference(pCurrentThread);
+ }
+
+ dwRet = (NO_ERROR == palErr) ? 1 : 0;
+
+ LOGEXIT("QueueUserAPC returns DWORD %d\n", dwRet);
+ PERF_EXIT(QueueUserAPC);
+ return dwRet;
+}
+
+DWORD CorUnix::InternalWaitForMultipleObjectsEx(
+ CPalThread * pThread,
+ DWORD nCount,
+ CONST HANDLE *lpHandles,
+ BOOL bWaitAll,
+ DWORD dwMilliseconds,
+ BOOL bAlertable)
+{
+ DWORD dwRet = WAIT_FAILED;
+ PAL_ERROR palErr = NO_ERROR;
+ int i, iSignaledObjCount, iSignaledObjIndex = -1;
+ bool fWAll = (bool)bWaitAll, fNeedToBlock = false;
+ bool fAbandoned = false;
+ WaitType wtWaitType;
+
+ IPalObject * pIPalObjStackArray[MAXIMUM_STACK_WAITOBJ_ARRAY_SIZE] = { NULL };
+ ISynchWaitController * pISyncStackArray[MAXIMUM_STACK_WAITOBJ_ARRAY_SIZE] = { NULL };
+ IPalObject ** ppIPalObjs = pIPalObjStackArray;
+ ISynchWaitController ** ppISyncWaitCtrlrs = pISyncStackArray;
+
+ if ((nCount == 0) || (nCount > MAXIMUM_WAIT_OBJECTS))
+ {
+ ppIPalObjs = NULL; // make delete at the end safe
+ ppISyncWaitCtrlrs = NULL; // make delete at the end safe
+ ERROR("Invalid object count=%d [range: 1 to %d]\n",
+ nCount, MAXIMUM_WAIT_OBJECTS)
+ pThread->SetLastError(ERROR_INVALID_PARAMETER);
+ goto WFMOExIntExit;
+ }
+ else if (nCount == 1)
+ {
+ fWAll = false; // makes no difference when nCount is 1
+ wtWaitType = SingleObject;
+ }
+ else
+ {
+ wtWaitType = fWAll ? MultipleObjectsWaitAll : MultipleObjectsWaitOne;
+ if (nCount > MAXIMUM_STACK_WAITOBJ_ARRAY_SIZE)
+ {
+ ppIPalObjs = InternalNewArray<IPalObject*>(nCount);
+ ppISyncWaitCtrlrs = InternalNewArray<ISynchWaitController*>(nCount);
+ if ((NULL == ppIPalObjs) || (NULL == ppISyncWaitCtrlrs))
+ {
+ ERROR("Out of memory allocating internal structures\n");
+ pThread->SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ goto WFMOExIntExit;
+ }
+ }
+ }
+
+ palErr = g_pObjectManager->ReferenceMultipleObjectsByHandleArray(pThread,
+ (VOID **)lpHandles,
+ nCount,
+ &sg_aotWaitObject,
+ SYNCHRONIZE,
+ ppIPalObjs);
+ if (NO_ERROR != palErr)
+ {
+ ERROR("Unable to obtain object for some or all of the handles [error=%u]\n",
+ palErr);
+ if (palErr == ERROR_INVALID_HANDLE)
+ pThread->SetLastError(ERROR_INVALID_HANDLE);
+ else
+ pThread->SetLastError(ERROR_INTERNAL_ERROR);
+ goto WFMOExIntExit;
+ }
+
+ if (nCount > 1)
+ {
+ // Check for any cross-process sync objects. "Wait for any" and "wait for all" operations are not supported on
+ // cross-process sync objects in the PAL.
+ for (DWORD i = 0; i < nCount; ++i)
+ {
+ if (ppIPalObjs[i]->GetObjectType()->GetId() == otiNamedMutex)
+ {
+ ERROR("Attempt to wait for any or all handles including a cross-process sync object", ERROR_NOT_SUPPORTED);
+ pThread->SetLastError(ERROR_NOT_SUPPORTED);
+ goto WFMOExIntCleanup;
+ }
+ }
+ }
+ else if (ppIPalObjs[0]->GetObjectType()->GetId() == otiNamedMutex)
+ {
+ SharedMemoryProcessDataHeader *processDataHeader =
+ SharedMemoryProcessDataHeader::PalObject_GetProcessDataHeader(ppIPalObjs[0]);
+ _ASSERTE(processDataHeader != nullptr);
+ try
+ {
+ MutexTryAcquireLockResult tryAcquireLockResult =
+ static_cast<NamedMutexProcessData *>(processDataHeader->GetData())->TryAcquireLock(dwMilliseconds);
+ switch (tryAcquireLockResult)
+ {
+ case MutexTryAcquireLockResult::AcquiredLock:
+ dwRet = WAIT_OBJECT_0;
+ break;
+
+ case MutexTryAcquireLockResult::AcquiredLockButMutexWasAbandoned:
+ dwRet = WAIT_ABANDONED_0;
+ break;
+
+ case MutexTryAcquireLockResult::TimedOut:
+ dwRet = WAIT_TIMEOUT;
+ break;
+
+ default:
+ _ASSERTE(false);
+ break;
+ }
+ }
+ catch (SharedMemoryException ex)
+ {
+ pThread->SetLastError(ex.GetErrorCode());
+ }
+ goto WFMOExIntCleanup;
+ }
+
+ if (fWAll)
+ {
+ // For a wait-all operation, check for duplicate wait objects in the array. This just uses a brute-force O(n^2)
+ // algorithm, but since MAXIMUM_WAIT_OBJECTS is small, the worst case is not so bad, and the average case would involve
+ // significantly fewer items.
+ for (DWORD i = 0; i < nCount - 1; ++i)
+ {
+ IPalObject *const objectToCheck = ppIPalObjs[i];
+ for (DWORD j = i + 1; j < nCount; ++j)
+ {
+ if (ppIPalObjs[j] == objectToCheck)
+ {
+ ERROR("Duplicate handle provided for a wait-all operation [error=%u]\n", ERROR_INVALID_PARAMETER);
+ pThread->SetLastError(ERROR_INVALID_PARAMETER);
+ goto WFMOExIntCleanup;
+ }
+ }
+ }
+ }
+
+ palErr = g_pSynchronizationManager->GetSynchWaitControllersForObjects(
+ pThread, ppIPalObjs, nCount, ppISyncWaitCtrlrs);
+ if (NO_ERROR != palErr)
+ {
+ ERROR("Unable to obtain ISynchWaitController interface for some or all "
+ "of the objects [error=%u]\n", palErr);
+ pThread->SetLastError(ERROR_INTERNAL_ERROR);
+ goto WFMOExIntCleanup;
+ }
+
+ if (bAlertable)
+ {
+ // First check for pending APC. We need to do that while holding the global
+ // synch lock implicitely grabbed by GetSynchWaitControllersForObjects
+ if (g_pSynchronizationManager->AreAPCsPending(pThread))
+ {
+ // If there is any pending APC we need to release the
+ // implicit global synch lock before calling into it
+ for (i = 0; (i < (int)nCount) && (NULL != ppISyncWaitCtrlrs[i]); i++)
+ {
+ ppISyncWaitCtrlrs[i]->ReleaseController();
+ ppISyncWaitCtrlrs[i] = NULL;
+ }
+ palErr = g_pSynchronizationManager->DispatchPendingAPCs(pThread);
+ if (NO_ERROR == palErr)
+ {
+ dwRet = WAIT_IO_COMPLETION;
+ }
+ else
+ {
+ ASSERT("Awakened for APC, but no APC is pending\n");
+ pThread->SetLastError(ERROR_INTERNAL_ERROR);
+ dwRet = WAIT_FAILED;
+ }
+ goto WFMOExIntCleanup;
+ }
+ }
+
+ iSignaledObjCount = 0;
+ iSignaledObjIndex = -1;
+ for (i=0;i<(int)nCount;i++)
+ {
+ bool fValue;
+ palErr = ppISyncWaitCtrlrs[i]->CanThreadWaitWithoutBlocking(&fValue, &fAbandoned);
+ if (NO_ERROR != palErr)
+ {
+ ERROR("ISynchWaitController::CanThreadWaitWithoutBlocking() failed for "
+ "%d-th object [handle=%p error=%u]\n", i, lpHandles[i], palErr);
+ pThread->SetLastError(ERROR_INTERNAL_ERROR);
+ goto WFMOExIntReleaseControllers;
+ }
+ if (fValue)
+ {
+ iSignaledObjCount++;
+ iSignaledObjIndex = i;
+ if (!fWAll)
+ break;
+ }
+ }
+
+ fNeedToBlock = (iSignaledObjCount == 0) || (fWAll && (iSignaledObjCount < (int)nCount));
+ if (!fNeedToBlock)
+ {
+ // At least one object signaled, or bWaitAll==TRUE and all object signaled.
+ // No need to wait, let's unsignal the object(s) and return without blocking
+ int iStartIdx, iEndIdx;
+
+ if (fWAll)
+ {
+ iStartIdx = 0;
+ iEndIdx = nCount;
+ }
+ else
+ {
+ iStartIdx = iSignaledObjIndex;
+ iEndIdx = iStartIdx + 1;
+ }
+
+ // Unsignal objects
+ if( iStartIdx < 0 )
+ {
+ ERROR("Buffer underflow due to iStartIdx < 0");
+ pThread->SetLastError(ERROR_INTERNAL_ERROR);
+ dwRet = WAIT_FAILED;
+ goto WFMOExIntCleanup;
+ }
+ for (i = iStartIdx; i < iEndIdx; i++)
+ {
+ palErr = ppISyncWaitCtrlrs[i]->ReleaseWaitingThreadWithoutBlocking();
+ if (NO_ERROR != palErr)
+ {
+ ERROR("ReleaseWaitingThreadWithoutBlocking() failed for %d-th "
+ "object [handle=%p error=%u]\n",
+ i, lpHandles[i], palErr);
+ pThread->SetLastError(palErr);
+ goto WFMOExIntReleaseControllers;
+ }
+ }
+
+ dwRet = (fAbandoned ? WAIT_ABANDONED_0 : WAIT_OBJECT_0);
+ }
+ else if (0 == dwMilliseconds)
+ {
+ // Not enough objects signaled, but timeout is zero: no actual wait
+ dwRet = WAIT_TIMEOUT;
+ fNeedToBlock = false;
+ }
+ else
+ {
+ // Register the thread for waiting on all objects
+ for (i=0;i<(int)nCount;i++)
+ {
+ palErr = ppISyncWaitCtrlrs[i]->RegisterWaitingThread(
+ wtWaitType,
+ i,
+ (TRUE == bAlertable));
+ if (NO_ERROR != palErr)
+ {
+ ERROR("RegisterWaitingThread() failed for %d-th object "
+ "[handle=%p error=%u]\n", i, lpHandles[i], palErr);
+ pThread->SetLastError(palErr);
+ goto WFMOExIntReleaseControllers;
+ }
+ }
+ }
+
+WFMOExIntReleaseControllers:
+ // Release all controllers before going to sleep
+ for (i = 0; i < (int)nCount; i++)
+ {
+ ppISyncWaitCtrlrs[i]->ReleaseController();
+ ppISyncWaitCtrlrs[i] = NULL;
+ }
+ if (NO_ERROR != palErr)
+ goto WFMOExIntCleanup;
+
+ if (fNeedToBlock)
+ {
+ ThreadWakeupReason twrWakeupReason;
+
+ //
+ // Going to sleep
+ //
+ palErr = g_pSynchronizationManager->BlockThread(pThread,
+ dwMilliseconds,
+ (TRUE == bAlertable),
+ false,
+ &twrWakeupReason,
+ (DWORD *)&iSignaledObjIndex);
+ //
+ // Awakened
+ //
+ if (NO_ERROR != palErr)
+ {
+ ERROR("IPalSynchronizationManager::BlockThread failed for thread "
+ "pThread=%p [error=%u]\n", pThread, palErr);
+ pThread->SetLastError(palErr);
+ goto WFMOExIntCleanup;
+ }
+ switch (twrWakeupReason)
+ {
+ case WaitSucceeded:
+ dwRet = WAIT_OBJECT_0; // offset added later
+ break;
+ case MutexAbondoned:
+ dwRet = WAIT_ABANDONED_0; // offset added later
+ break;
+ case WaitTimeout:
+ dwRet = WAIT_TIMEOUT;
+ break;
+ case Alerted:
+ _ASSERT_MSG(bAlertable,
+ "Awakened for APC from a non-alertable wait\n");
+
+ dwRet = WAIT_IO_COMPLETION;
+ palErr = g_pSynchronizationManager->DispatchPendingAPCs(pThread);
+
+ _ASSERT_MSG(NO_ERROR == palErr,
+ "Awakened for APC, but no APC is pending\n");
+ break;
+ case WaitFailed:
+ default:
+ ERROR("Thread %p awakened with some failure\n", pThread);
+ dwRet = WAIT_FAILED;
+ break;
+ }
+ }
+
+ if (!fWAll && ((WAIT_OBJECT_0 == dwRet) || (WAIT_ABANDONED_0 == dwRet)))
+ {
+ _ASSERT_MSG(0 <= iSignaledObjIndex,
+ "Failed to identify signaled/abandoned object\n");
+ _ASSERT_MSG(iSignaledObjIndex >= 0 && nCount > static_cast<DWORD>(iSignaledObjIndex),
+ "SignaledObjIndex object out of range "
+ "[index=%d obj_count=%u\n",
+ iSignaledObjCount, nCount);
+
+ if (iSignaledObjIndex < 0)
+ {
+ pThread->SetLastError(ERROR_INTERNAL_ERROR);
+ dwRet = WAIT_FAILED;
+ goto WFMOExIntCleanup;
+ }
+ dwRet += iSignaledObjIndex;
+ }
+
+WFMOExIntCleanup:
+ for (i = 0; i < (int)nCount; i++)
+ {
+ ppIPalObjs[i]->ReleaseReference(pThread);
+ ppIPalObjs[i] = NULL;
+ }
+
+WFMOExIntExit:
+ if (nCount > MAXIMUM_STACK_WAITOBJ_ARRAY_SIZE)
+ {
+ InternalDeleteArray(ppIPalObjs);
+ InternalDeleteArray(ppISyncWaitCtrlrs);
+ }
+
+ return dwRet;
+}
+
+DWORD CorUnix::InternalSleepEx (
+ CPalThread * pThread,
+ DWORD dwMilliseconds,
+ BOOL bAlertable)
+{
+ PAL_ERROR palErr = NO_ERROR;
+ DWORD dwRet = WAIT_FAILED;
+ int iSignaledObjIndex;
+
+ TRACE("Sleeping %u ms [bAlertable=%d]", dwMilliseconds, (int)bAlertable);
+
+ if (bAlertable)
+ {
+ // In this case do not use AreAPCsPending. In fact, since we are
+ // not holding the synch lock(s) an APC posting may race with
+ // AreAPCsPending.
+ palErr = g_pSynchronizationManager->DispatchPendingAPCs(pThread);
+ if (NO_ERROR == palErr)
+ {
+ return WAIT_IO_COMPLETION;
+ }
+ }
+
+ if (dwMilliseconds > 0)
+ {
+ ThreadWakeupReason twrWakeupReason;
+ palErr = g_pSynchronizationManager->BlockThread(pThread,
+ dwMilliseconds,
+ (TRUE == bAlertable),
+ true,
+ &twrWakeupReason,
+ (DWORD *)&iSignaledObjIndex);
+ if (NO_ERROR != palErr)
+ {
+ ERROR("IPalSynchronizationManager::BlockThread failed for thread "
+ "pThread=%p [error=%u]\n", pThread, palErr);
+ return dwRet;
+ }
+
+ switch (twrWakeupReason)
+ {
+ case WaitSucceeded:
+ case WaitTimeout:
+ dwRet = 0;
+ break;
+ case Alerted:
+ _ASSERT_MSG(bAlertable, "Awakened for APC from a non-alertable wait\n");
+
+ dwRet = WAIT_IO_COMPLETION;
+ palErr = g_pSynchronizationManager->DispatchPendingAPCs(pThread);
+ _ASSERT_MSG(NO_ERROR == palErr, "Awakened for APC, but no APC is pending\n");
+
+ break;
+ case MutexAbondoned:
+ ASSERT("Thread %p awakened with reason=MutexAbondoned from a SleepEx\n", pThread);
+ break;
+ case WaitFailed:
+ default:
+ ERROR("Thread %p awakened with some failure\n", pThread);
+ break;
+ }
+ }
+ else
+ {
+ dwRet = 0;
+ }
+
+ TRACE("Done sleeping %u ms [bAlertable=%d]", dwMilliseconds, (int)bAlertable);
+ return dwRet;
+}
+
diff --git a/src/pal/src/synchobj/event.cpp b/src/pal/src/synchobj/event.cpp
new file mode 100644
index 0000000000..54addad51c
--- /dev/null
+++ b/src/pal/src/synchobj/event.cpp
@@ -0,0 +1,589 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ event.cpp
+
+Abstract:
+
+ Implementation of event synchronization object as described in
+ the WIN32 API
+
+Revision History:
+
+
+
+--*/
+
+#include "pal/event.hpp"
+#include "pal/thread.hpp"
+#include "pal/dbgmsg.h"
+
+using namespace CorUnix;
+
+/* ------------------- Definitions ------------------------------*/
+SET_DEFAULT_DEBUG_CHANNEL(SYNC);
+
+CObjectType CorUnix::otManualResetEvent(
+ otiManualResetEvent,
+ NULL, // No cleanup routine
+ NULL, // No initialization routine
+ 0, // No immutable data
+ 0, // No process local data
+ 0, // No shared data
+ EVENT_ALL_ACCESS, // Currently ignored (no Win32 security)
+ CObjectType::SecuritySupported,
+ CObjectType::SecurityInfoNotPersisted,
+ CObjectType::UnnamedObject,
+ CObjectType::LocalDuplicationOnly,
+ CObjectType::WaitableObject,
+ CObjectType::ObjectCanBeUnsignaled,
+ CObjectType::ThreadReleaseHasNoSideEffects,
+ CObjectType::NoOwner
+ );
+
+CObjectType CorUnix::otAutoResetEvent(
+ otiAutoResetEvent,
+ NULL, // No cleanup routine
+ NULL, // No initialization routine
+ 0, // No immutable data
+ 0, // No process local data
+ 0, // No shared data
+ EVENT_ALL_ACCESS, // Currently ignored (no Win32 security)
+ CObjectType::SecuritySupported,
+ CObjectType::SecurityInfoNotPersisted,
+ CObjectType::UnnamedObject,
+ CObjectType::LocalDuplicationOnly,
+ CObjectType::WaitableObject,
+ CObjectType::ObjectCanBeUnsignaled,
+ CObjectType::ThreadReleaseAltersSignalCount,
+ CObjectType::NoOwner
+ );
+
+PalObjectTypeId rgEventIds[] = {otiManualResetEvent, otiAutoResetEvent};
+CAllowedObjectTypes aotEvent(rgEventIds, sizeof(rgEventIds)/sizeof(rgEventIds[0]));
+
+/*++
+Function:
+ CreateEventA
+
+Note:
+ lpEventAttributes currentely ignored:
+ -- Win32 object security not supported
+ -- handles to event objects are not inheritable
+
+Parameters:
+ See MSDN doc.
+--*/
+
+HANDLE
+PALAPI
+CreateEventA(
+ IN LPSECURITY_ATTRIBUTES lpEventAttributes,
+ IN BOOL bManualReset,
+ IN BOOL bInitialState,
+ IN LPCSTR lpName)
+{
+ HANDLE hEvent = NULL;
+ CPalThread *pthr = NULL;
+ PAL_ERROR palError;
+
+ PERF_ENTRY(CreateEventA);
+ ENTRY("CreateEventA(lpEventAttr=%p, bManualReset=%d, bInitialState=%d, lpName=%p (%s)\n",
+ lpEventAttributes, bManualReset, bInitialState, lpName, lpName?lpName:"NULL");
+
+ pthr = InternalGetCurrentThread();
+
+ if (lpName != nullptr)
+ {
+ ASSERT("lpName: Cross-process named objects are not supported in PAL");
+ palError = ERROR_NOT_SUPPORTED;
+ }
+ else
+ {
+ palError = InternalCreateEvent(
+ pthr,
+ lpEventAttributes,
+ bManualReset,
+ bInitialState,
+ NULL,
+ &hEvent
+ );
+ }
+
+ //
+ // We always need to set last error, even on success:
+ // we need to protect ourselves from the situation
+ // where last error is set to ERROR_ALREADY_EXISTS on
+ // entry to the function
+ //
+
+ pthr->SetLastError(palError);
+
+ LOGEXIT("CreateEventA returns HANDLE %p\n", hEvent);
+ PERF_EXIT(CreateEventA);
+ return hEvent;
+}
+
+
+/*++
+Function:
+ CreateEventW
+
+Note:
+ lpEventAttributes currentely ignored:
+ -- Win32 object security not supported
+ -- handles to event objects are not inheritable
+
+Parameters:
+ See MSDN doc.
+--*/
+
+HANDLE
+PALAPI
+CreateEventW(
+ IN LPSECURITY_ATTRIBUTES lpEventAttributes,
+ IN BOOL bManualReset,
+ IN BOOL bInitialState,
+ IN LPCWSTR lpName)
+{
+ HANDLE hEvent = NULL;
+ PAL_ERROR palError;
+ CPalThread *pthr = NULL;
+
+ PERF_ENTRY(CreateEventW);
+ ENTRY("CreateEventW(lpEventAttr=%p, bManualReset=%d, "
+ "bInitialState=%d, lpName=%p (%S)\n", lpEventAttributes, bManualReset,
+ bInitialState, lpName, lpName?lpName:W16_NULLSTRING);
+
+ pthr = InternalGetCurrentThread();
+
+ palError = InternalCreateEvent(
+ pthr,
+ lpEventAttributes,
+ bManualReset,
+ bInitialState,
+ lpName,
+ &hEvent
+ );
+
+ //
+ // We always need to set last error, even on success:
+ // we need to protect ourselves from the situation
+ // where last error is set to ERROR_ALREADY_EXISTS on
+ // entry to the function
+ //
+
+ pthr->SetLastError(palError);
+
+ LOGEXIT("CreateEventW returns HANDLE %p\n", hEvent);
+ PERF_EXIT(CreateEventW);
+ return hEvent;
+}
+
+/*++
+Function:
+ InternalCreateEvent
+
+Note:
+ lpEventAttributes currentely ignored:
+ -- Win32 object security not supported
+ -- handles to event objects are not inheritable
+
+Parameters:
+ pthr -- thread data for calling thread
+ phEvent -- on success, receives the allocated event handle
+
+ See MSDN docs on CreateEvent for all other parameters
+--*/
+
+PAL_ERROR
+CorUnix::InternalCreateEvent(
+ CPalThread *pthr,
+ LPSECURITY_ATTRIBUTES lpEventAttributes,
+ BOOL bManualReset,
+ BOOL bInitialState,
+ LPCWSTR lpName,
+ HANDLE *phEvent
+ )
+{
+ CObjectAttributes oa(lpName, lpEventAttributes);
+ PAL_ERROR palError = NO_ERROR;
+ IPalObject *pobjEvent = NULL;
+ IPalObject *pobjRegisteredEvent = NULL;
+
+ _ASSERTE(NULL != pthr);
+ _ASSERTE(NULL != phEvent);
+
+ ENTRY("InternalCreateEvent(pthr=%p, lpEventAttributes=%p, bManualReset=%i, "
+ "bInitialState=%i, lpName=%p, phEvent=%p)\n",
+ pthr,
+ lpEventAttributes,
+ bManualReset,
+ bInitialState,
+ lpName,
+ phEvent
+ );
+
+ if (lpName != nullptr)
+ {
+ ASSERT("lpName: Cross-process named objects are not supported in PAL");
+ palError = ERROR_NOT_SUPPORTED;
+ goto InternalCreateEventExit;
+ }
+
+ palError = g_pObjectManager->AllocateObject(
+ pthr,
+ bManualReset ? &otManualResetEvent : &otAutoResetEvent,
+ &oa,
+ &pobjEvent
+ );
+
+ if (NO_ERROR != palError)
+ {
+ goto InternalCreateEventExit;
+ }
+
+ if (bInitialState)
+ {
+ ISynchStateController *pssc;
+
+ palError = pobjEvent->GetSynchStateController(
+ pthr,
+ &pssc
+ );
+
+ if (NO_ERROR == palError)
+ {
+ palError = pssc->SetSignalCount(1);
+ pssc->ReleaseController();
+ }
+
+ if (NO_ERROR != palError)
+ {
+ ASSERT("Unable to set new event state (%d)\n", palError);
+ goto InternalCreateEventExit;
+ }
+ }
+
+ palError = g_pObjectManager->RegisterObject(
+ pthr,
+ pobjEvent,
+ &aotEvent,
+ EVENT_ALL_ACCESS, // Currently ignored (no Win32 security)
+ phEvent,
+ &pobjRegisteredEvent
+ );
+
+ //
+ // pobjEvent is invalidated by the call to RegisterObject, so NULL it
+ // out here to ensure that we don't try to release a reference on
+ // it down the line.
+ //
+
+ pobjEvent = NULL;
+
+InternalCreateEventExit:
+
+ if (NULL != pobjEvent)
+ {
+ pobjEvent->ReleaseReference(pthr);
+ }
+
+ if (NULL != pobjRegisteredEvent)
+ {
+ pobjRegisteredEvent->ReleaseReference(pthr);
+ }
+
+ LOGEXIT("InternalCreateEvent returns %i\n", palError);
+
+ return palError;
+}
+
+
+/*++
+Function:
+ SetEvent
+
+See MSDN doc.
+--*/
+
+BOOL
+PALAPI
+SetEvent(
+ IN HANDLE hEvent)
+{
+ PAL_ERROR palError = NO_ERROR;
+ CPalThread *pthr = NULL;
+
+ PERF_ENTRY(SetEvent);
+ ENTRY("SetEvent(hEvent=%p)\n", hEvent);
+
+ pthr = InternalGetCurrentThread();
+
+ palError = InternalSetEvent(pthr, hEvent, TRUE);
+
+ if (NO_ERROR != palError)
+ {
+ pthr->SetLastError(palError);
+ }
+
+ LOGEXIT("SetEvent returns BOOL %d\n", (NO_ERROR == palError));
+ PERF_EXIT(SetEvent);
+ return (NO_ERROR == palError);
+}
+
+
+/*++
+Function:
+ ResetEvent
+
+See MSDN doc.
+--*/
+
+BOOL
+PALAPI
+ResetEvent(
+ IN HANDLE hEvent)
+{
+ PAL_ERROR palError = NO_ERROR;
+ CPalThread *pthr = NULL;
+
+ PERF_ENTRY(ResetEvent);
+ ENTRY("ResetEvent(hEvent=%p)\n", hEvent);
+
+ pthr = InternalGetCurrentThread();
+
+ palError = InternalSetEvent(pthr, hEvent, FALSE);
+
+ if (NO_ERROR != palError)
+ {
+ pthr->SetLastError(palError);
+ }
+
+ LOGEXIT("ResetEvent returns BOOL %d\n", (NO_ERROR == palError));
+ PERF_EXIT(ResetEvent);
+ return (NO_ERROR == palError);
+}
+
+/*++
+Function:
+ InternalCreateEvent
+
+Parameters:
+ pthr -- thread data for calling thread
+ hEvent -- handle to the event to set
+ fSetEvent -- if TRUE, set the event; if FALSE, reset it
+--*/
+
+PAL_ERROR
+CorUnix::InternalSetEvent(
+ CPalThread *pthr,
+ HANDLE hEvent,
+ BOOL fSetEvent
+ )
+{
+ PAL_ERROR palError = NO_ERROR;
+ IPalObject *pobjEvent = NULL;
+ ISynchStateController *pssc = NULL;
+
+ _ASSERTE(NULL != pthr);
+
+ ENTRY("InternalSetEvent(pthr=%p, hEvent=%p, fSetEvent=%i\n",
+ pthr,
+ hEvent,
+ fSetEvent
+ );
+
+ palError = g_pObjectManager->ReferenceObjectByHandle(
+ pthr,
+ hEvent,
+ &aotEvent,
+ 0, // Should be EVENT_MODIFY_STATE; currently ignored (no Win32 security)
+ &pobjEvent
+ );
+
+ if (NO_ERROR != palError)
+ {
+ ERROR("Unable to obtain object for handle %p (error %d)!\n", hEvent, palError);
+ goto InternalSetEventExit;
+ }
+
+ palError = pobjEvent->GetSynchStateController(
+ pthr,
+ &pssc
+ );
+
+ if (NO_ERROR != palError)
+ {
+ ASSERT("Error %d obtaining synch state controller\n", palError);
+ goto InternalSetEventExit;
+ }
+
+ palError = pssc->SetSignalCount(fSetEvent ? 1 : 0);
+
+ if (NO_ERROR != palError)
+ {
+ ASSERT("Error %d setting event state\n", palError);
+ goto InternalSetEventExit;
+ }
+
+InternalSetEventExit:
+
+ if (NULL != pssc)
+ {
+ pssc->ReleaseController();
+ }
+
+ if (NULL != pobjEvent)
+ {
+ pobjEvent->ReleaseReference(pthr);
+ }
+
+ LOGEXIT("InternalSetEvent returns %d\n", palError);
+
+ return palError;
+}
+
+// TODO: Implementation of OpenEventA() doesn't exist, do we need it? More generally, do we need the A versions at all?
+
+/*++
+Function:
+ OpenEventW
+
+Note:
+ dwDesiredAccess is currently ignored (no Win32 object security support)
+ bInheritHandle is currently ignored (handles to events are not inheritable)
+
+Parameters:
+ See MSDN doc.
+--*/
+
+HANDLE
+PALAPI
+OpenEventW(
+ IN DWORD dwDesiredAccess,
+ IN BOOL bInheritHandle,
+ IN LPCWSTR lpName)
+{
+ HANDLE hEvent = NULL;
+ PAL_ERROR palError = NO_ERROR;
+ CPalThread *pthr = NULL;
+
+ PERF_ENTRY(OpenEventW);
+ ENTRY("OpenEventW(dwDesiredAccess=%#x, bInheritHandle=%d, lpName=%p (%S))\n",
+ dwDesiredAccess, bInheritHandle, lpName, lpName?lpName:W16_NULLSTRING);
+
+ pthr = InternalGetCurrentThread();
+
+ /* validate parameters */
+ if (lpName == nullptr)
+ {
+ ERROR("name is NULL\n");
+ palError = ERROR_INVALID_PARAMETER;
+ goto OpenEventWExit;
+ }
+ else
+ {
+ ASSERT("lpName: Cross-process named objects are not supported in PAL");
+ palError = ERROR_NOT_SUPPORTED;
+ }
+
+OpenEventWExit:
+
+ if (NO_ERROR != palError)
+ {
+ pthr->SetLastError(palError);
+ }
+
+ LOGEXIT("OpenEventW returns HANDLE %p\n", hEvent);
+ PERF_EXIT(OpenEventW);
+
+ return hEvent;
+}
+
+/*++
+Function:
+ InternalOpenEvent
+
+Note:
+ dwDesiredAccess is currently ignored (no Win32 object security support)
+ bInheritHandle is currently ignored (handles to events are not inheritable)
+
+Parameters:
+ pthr -- thread data for calling thread
+ phEvent -- on success, receives the allocated event handle
+
+ See MSDN docs on OpenEvent for all other parameters.
+--*/
+
+PAL_ERROR
+CorUnix::InternalOpenEvent(
+ CPalThread *pthr,
+ DWORD dwDesiredAccess,
+ BOOL bInheritHandle,
+ LPCWSTR lpName,
+ HANDLE *phEvent
+ )
+{
+ PAL_ERROR palError = NO_ERROR;
+ IPalObject *pobjEvent = NULL;
+ CPalString sObjectName(lpName);
+
+ _ASSERTE(NULL != pthr);
+ _ASSERTE(NULL != lpName);
+ _ASSERTE(NULL != phEvent);
+
+ ENTRY("InternalOpenEvent(pthr=%p, dwDesiredAccess=%#x, bInheritHandle=%d, "
+ "lpName=%p, phEvent=%p)\n",
+ pthr,
+ dwDesiredAccess,
+ bInheritHandle,
+ lpName,
+ phEvent
+ );
+
+ palError = g_pObjectManager->LocateObject(
+ pthr,
+ &sObjectName,
+ &aotEvent,
+ &pobjEvent
+ );
+
+ if (NO_ERROR != palError)
+ {
+ goto InternalOpenEventExit;
+ }
+
+ palError = g_pObjectManager->ObtainHandleForObject(
+ pthr,
+ pobjEvent,
+ dwDesiredAccess,
+ bInheritHandle,
+ NULL,
+ phEvent
+ );
+
+ if (NO_ERROR != palError)
+ {
+ goto InternalOpenEventExit;
+ }
+
+InternalOpenEventExit:
+
+ if (NULL != pobjEvent)
+ {
+ pobjEvent->ReleaseReference(pthr);
+ }
+
+ LOGEXIT("InternalOpenEvent returns %d\n", palError);
+
+ return palError;
+}
+
diff --git a/src/pal/src/synchobj/mutex.cpp b/src/pal/src/synchobj/mutex.cpp
new file mode 100644
index 0000000000..d929eaa472
--- /dev/null
+++ b/src/pal/src/synchobj/mutex.cpp
@@ -0,0 +1,1584 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ mutex.ccpp
+
+Abstract:
+
+ Implementation of mutex synchroniztion object as described in
+ the WIN32 API
+
+Revision History:
+
+
+
+--*/
+
+#include "pal/dbgmsg.h"
+
+SET_DEFAULT_DEBUG_CHANNEL(SYNC); // some headers have code with asserts, so do this first
+
+#include "pal/mutex.hpp"
+#include "pal/file.hpp"
+#include "pal/thread.hpp"
+
+#include "../synchmgr/synchmanager.hpp"
+
+#include <sys/file.h>
+#include <sys/types.h>
+
+#include <errno.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "pal/sharedmemory.inl"
+
+using namespace CorUnix;
+
+/* ------------------- Definitions ------------------------------*/
+
+CObjectType CorUnix::otMutex(
+ otiMutex,
+ NULL, // No cleanup routine
+ NULL, // No initialization routine
+ 0, // No immutable data
+ 0, // No process local data
+ 0, // No shared data
+ 0, // Should be MUTEX_ALL_ACCESS; currently ignored (no Win32 security)
+ CObjectType::SecuritySupported,
+ CObjectType::SecurityInfoNotPersisted,
+ CObjectType::UnnamedObject,
+ CObjectType::LocalDuplicationOnly,
+ CObjectType::WaitableObject,
+ CObjectType::ObjectCanBeUnsignaled,
+ CObjectType::ThreadReleaseAltersSignalCount,
+ CObjectType::OwnershipTracked
+ );
+
+static CAllowedObjectTypes aotMutex(otiMutex);
+
+CObjectType CorUnix::otNamedMutex(
+ otiNamedMutex,
+ &SharedMemoryProcessDataHeader::PalObject_Close, // Cleanup routine
+ NULL, // No initialization routine
+ sizeof(SharedMemoryProcessDataHeader *), // Immutable data
+ 0, // No process local data
+ 0, // No shared data
+ 0, // Should be MUTEX_ALL_ACCESS; currently ignored (no Win32 security)
+ CObjectType::SecuritySupported,
+ CObjectType::SecurityInfoNotPersisted,
+ CObjectType::UnnamedObject, // PAL's naming infrastructure is not used
+ CObjectType::LocalDuplicationOnly,
+ CObjectType::UnwaitableObject, // PAL's waiting infrastructure is not used
+ CObjectType::SignalingNotApplicable, // PAL's signaling infrastructure is not used
+ CObjectType::ThreadReleaseNotApplicable, // PAL's signaling infrastructure is not used
+ CObjectType::OwnershipNotApplicable // PAL's ownership infrastructure is not used
+ );
+
+static CAllowedObjectTypes aotNamedMutex(otiNamedMutex);
+
+static PalObjectTypeId anyMutexTypeIds[] = {otiMutex, otiNamedMutex};
+static CAllowedObjectTypes aotAnyMutex(anyMutexTypeIds, _countof(anyMutexTypeIds));
+
+/*++
+Function:
+ CreateMutexA
+
+Note:
+ lpMutexAttributes currentely ignored:
+ -- Win32 object security not supported
+ -- handles to mutex objects are not inheritable
+
+Parameters:
+ See MSDN doc.
+--*/
+
+HANDLE
+PALAPI
+CreateMutexA(
+ IN LPSECURITY_ATTRIBUTES lpMutexAttributes,
+ IN BOOL bInitialOwner,
+ IN LPCSTR lpName)
+{
+ HANDLE hMutex = NULL;
+ CPalThread *pthr = NULL;
+ PAL_ERROR palError;
+
+ PERF_ENTRY(CreateMutexA);
+ ENTRY("CreateMutexA(lpMutexAttr=%p, bInitialOwner=%d, lpName=%p (%s)\n",
+ lpMutexAttributes, bInitialOwner, lpName, lpName?lpName:"NULL");
+
+ pthr = InternalGetCurrentThread();
+
+ palError = InternalCreateMutex(
+ pthr,
+ lpMutexAttributes,
+ bInitialOwner,
+ lpName,
+ &hMutex
+ );
+
+ //
+ // We always need to set last error, even on success:
+ // we need to protect ourselves from the situation
+ // where last error is set to ERROR_ALREADY_EXISTS on
+ // entry to the function
+ //
+
+ pthr->SetLastError(palError);
+
+ LOGEXIT("CreateMutexA returns HANDLE %p\n", hMutex);
+ PERF_EXIT(CreateMutexA);
+ return hMutex;
+}
+
+
+/*++
+Function:
+ CreateMutexW
+
+Note:
+ lpMutexAttributes currentely ignored:
+ -- Win32 object security not supported
+ -- handles to mutex objects are not inheritable
+
+Parameters:
+ See MSDN doc.
+--*/
+
+HANDLE
+PALAPI
+CreateMutexW(
+ IN LPSECURITY_ATTRIBUTES lpMutexAttributes,
+ IN BOOL bInitialOwner,
+ IN LPCWSTR lpName)
+{
+ HANDLE hMutex = NULL;
+ PAL_ERROR palError;
+ CPalThread *pthr = NULL;
+ char utf8Name[SHARED_MEMORY_MAX_NAME_CHAR_COUNT + 1];
+
+ PERF_ENTRY(CreateMutexW);
+ ENTRY("CreateMutexW(lpMutexAttr=%p, bInitialOwner=%d, lpName=%p (%S)\n",
+ lpMutexAttributes, bInitialOwner, lpName, lpName?lpName:W16_NULLSTRING);
+
+ pthr = InternalGetCurrentThread();
+
+ if (lpName != nullptr)
+ {
+ int bytesWritten = WideCharToMultiByte(CP_ACP, 0, lpName, -1, utf8Name, _countof(utf8Name), nullptr, nullptr);
+ if (bytesWritten == 0)
+ {
+ DWORD errorCode = GetLastError();
+ if (errorCode == ERROR_INSUFFICIENT_BUFFER)
+ {
+ palError = static_cast<DWORD>(SharedMemoryError::NameTooLong);
+ }
+ else
+ {
+ ASSERT("WideCharToMultiByte failed (%u)\n", errorCode);
+ palError = errorCode;
+ }
+ goto CreateMutexWExit;
+ }
+ }
+
+ palError = InternalCreateMutex(
+ pthr,
+ lpMutexAttributes,
+ bInitialOwner,
+ lpName == nullptr ? nullptr : utf8Name,
+ &hMutex
+ );
+
+CreateMutexWExit:
+ //
+ // We always need to set last error, even on success:
+ // we need to protect ourselves from the situation
+ // where last error is set to ERROR_ALREADY_EXISTS on
+ // entry to the function
+ //
+
+ pthr->SetLastError(palError);
+
+ LOGEXIT("CreateMutexW returns HANDLE %p\n", hMutex);
+ PERF_EXIT(CreateMutexW);
+ return hMutex;
+}
+
+/*++
+Function:
+ InternalCreateMutex
+
+Note:
+ lpMutexAttributes currentely ignored:
+ -- Win32 object security not supported
+ -- handles to mutex objects are not inheritable
+
+Parameters:
+ pthr -- thread data for calling thread
+ phEvent -- on success, receives the allocated mutex handle
+
+ See MSDN docs on CreateMutex for all other parameters
+--*/
+
+PAL_ERROR
+CorUnix::InternalCreateMutex(
+ CPalThread *pthr,
+ LPSECURITY_ATTRIBUTES lpMutexAttributes,
+ BOOL bInitialOwner,
+ LPCSTR lpName,
+ HANDLE *phMutex
+ )
+{
+ CObjectAttributes oa(nullptr, lpMutexAttributes);
+ PAL_ERROR palError = NO_ERROR;
+ IPalObject *pobjMutex = NULL;
+ IPalObject *pobjRegisteredMutex = NULL;
+ ISynchStateController *pssc = NULL;
+ HANDLE hMutex = nullptr;
+
+ _ASSERTE(NULL != pthr);
+ _ASSERTE(NULL != phMutex);
+
+ ENTRY("InternalCreateMutex(pthr=%p, lpMutexAttributes=%p, bInitialOwner=%d"
+ ", lpName=%p, phMutex=%p)\n",
+ pthr,
+ lpMutexAttributes,
+ bInitialOwner,
+ lpName,
+ phMutex
+ );
+
+ if (lpName != nullptr && lpName[0] == '\0')
+ {
+ // Empty name is treated as a request for an unnamed process-local mutex
+ lpName = nullptr;
+ }
+
+ CObjectType *ot = lpName == nullptr ? &otMutex : &otNamedMutex;
+ CAllowedObjectTypes *aot = lpName == nullptr ? &aotMutex : &aotNamedMutex;
+
+ palError = g_pObjectManager->AllocateObject(
+ pthr,
+ ot,
+ &oa,
+ &pobjMutex
+ );
+
+ if (NO_ERROR != palError)
+ {
+ goto InternalCreateMutexExit;
+ }
+
+ if (lpName == nullptr)
+ {
+ palError = pobjMutex->GetSynchStateController(
+ pthr,
+ &pssc
+ );
+
+ if (NO_ERROR != palError)
+ {
+ ASSERT("Unable to create state controller (%d)\n", palError);
+ goto InternalCreateMutexExit;
+ }
+
+ if (bInitialOwner)
+ {
+ palError = pssc->SetOwner(pthr);
+ }
+ else
+ {
+ palError = pssc->SetSignalCount(1);
+ }
+
+ pssc->ReleaseController();
+
+ if (NO_ERROR != palError)
+ {
+ ASSERT("Unable to set initial mutex state (%d)\n", palError);
+ goto InternalCreateMutexExit;
+ }
+ }
+
+ palError = g_pObjectManager->RegisterObject(
+ pthr,
+ pobjMutex,
+ aot,
+ 0, // should be MUTEX_ALL_ACCESS -- currently ignored (no Win32 security)
+ &hMutex,
+ &pobjRegisteredMutex
+ );
+
+ if (palError != NO_ERROR)
+ {
+ _ASSERTE(palError != ERROR_ALREADY_EXISTS); // PAL's naming infrastructure is not used for named mutexes
+ _ASSERTE(pobjRegisteredMutex == nullptr);
+ _ASSERTE(hMutex == nullptr);
+ goto InternalCreateMutexExit;
+ }
+
+ // Now that the object has been registered successfully, it would have a reference associated with the handle, so release
+ // the initial reference. Any errors from now on need to revoke the handle.
+ _ASSERTE(pobjRegisteredMutex == pobjMutex);
+ _ASSERTE(hMutex != nullptr);
+ pobjMutex->ReleaseReference(pthr);
+ pobjRegisteredMutex = nullptr;
+
+ if (lpName != nullptr)
+ {
+ SharedMemoryProcessDataHeader *processDataHeader;
+ bool created = false;
+ try
+ {
+ processDataHeader = NamedMutexProcessData::CreateOrOpen(lpName, !!bInitialOwner, &created);
+ }
+ catch (SharedMemoryException ex)
+ {
+ palError = ex.GetErrorCode();
+ goto InternalCreateMutexExit;
+ }
+ SharedMemoryProcessDataHeader::PalObject_SetProcessDataHeader(pobjMutex, processDataHeader);
+
+ if (!created)
+ {
+ // Indicate to the caller that an existing mutex was opened, and hence the caller will not have initial ownership
+ // of the mutex if requested through bInitialOwner
+ palError = ERROR_ALREADY_EXISTS;
+ }
+ }
+
+ *phMutex = hMutex;
+ hMutex = nullptr;
+ pobjMutex = nullptr;
+
+InternalCreateMutexExit:
+
+ _ASSERTE(pobjRegisteredMutex == nullptr);
+ if (hMutex != nullptr)
+ {
+ g_pObjectManager->RevokeHandle(pthr, hMutex);
+ }
+ else if (NULL != pobjMutex)
+ {
+ pobjMutex->ReleaseReference(pthr);
+ }
+
+ LOGEXIT("InternalCreateMutex returns %i\n", palError);
+
+ return palError;
+}
+
+/*++
+Function:
+ ReleaseMutex
+
+Parameters:
+ See MSDN doc.
+--*/
+
+BOOL
+PALAPI
+ReleaseMutex( IN HANDLE hMutex )
+{
+ PAL_ERROR palError = NO_ERROR;
+ CPalThread *pthr = NULL;
+
+ PERF_ENTRY(ReleaseMutex);
+ ENTRY("ReleaseMutex(hMutex=%p)\n", hMutex);
+
+ pthr = InternalGetCurrentThread();
+
+ palError = InternalReleaseMutex(pthr, hMutex);
+
+ if (NO_ERROR != palError)
+ {
+ pthr->SetLastError(palError);
+ }
+
+ LOGEXIT("ReleaseMutex returns BOOL %d\n", (NO_ERROR == palError));
+ PERF_EXIT(ReleaseMutex);
+ return (NO_ERROR == palError);
+}
+
+/*++
+Function:
+ InternalReleaseMutex
+
+Parameters:
+ pthr -- thread data for calling thread
+
+ See MSDN docs on ReleaseMutex for all other parameters
+--*/
+
+PAL_ERROR
+CorUnix::InternalReleaseMutex(
+ CPalThread *pthr,
+ HANDLE hMutex
+ )
+{
+ PAL_ERROR palError = NO_ERROR;
+ IPalObject *pobjMutex = NULL;
+ ISynchStateController *pssc = NULL;
+ PalObjectTypeId objectTypeId;
+
+ _ASSERTE(NULL != pthr);
+
+ ENTRY("InternalReleaseMutex(pthr=%p, hMutex=%p)\n",
+ pthr,
+ hMutex
+ );
+
+ palError = g_pObjectManager->ReferenceObjectByHandle(
+ pthr,
+ hMutex,
+ &aotAnyMutex,
+ 0, // should be MUTEX_MODIFY_STATE -- current ignored (no Win32 security)
+ &pobjMutex
+ );
+
+ if (NO_ERROR != palError)
+ {
+ ERROR("Unable to obtain object for handle %p (error %d)!\n", hMutex, palError);
+ goto InternalReleaseMutexExit;
+ }
+
+ objectTypeId = pobjMutex->GetObjectType()->GetId();
+ if (objectTypeId == otiMutex)
+ {
+ palError = pobjMutex->GetSynchStateController(
+ pthr,
+ &pssc
+ );
+
+ if (NO_ERROR != palError)
+ {
+ ASSERT("Error %d obtaining synch state controller\n", palError);
+ goto InternalReleaseMutexExit;
+ }
+
+ palError = pssc->DecrementOwnershipCount();
+
+ if (NO_ERROR != palError)
+ {
+ ERROR("Error %d decrementing mutex ownership count\n", palError);
+ goto InternalReleaseMutexExit;
+ }
+ }
+ else
+ {
+ _ASSERTE(objectTypeId == otiNamedMutex);
+
+ SharedMemoryProcessDataHeader *processDataHeader =
+ SharedMemoryProcessDataHeader::PalObject_GetProcessDataHeader(pobjMutex);
+ _ASSERTE(processDataHeader != nullptr);
+ try
+ {
+ static_cast<NamedMutexProcessData *>(processDataHeader->GetData())->ReleaseLock();
+ }
+ catch (SharedMemoryException ex)
+ {
+ palError = ex.GetErrorCode();
+ goto InternalReleaseMutexExit;
+ }
+ }
+
+InternalReleaseMutexExit:
+
+ if (NULL != pssc)
+ {
+ pssc->ReleaseController();
+ }
+
+ if (NULL != pobjMutex)
+ {
+ pobjMutex->ReleaseReference(pthr);
+ }
+
+ LOGEXIT("InternalReleaseMutex returns %i\n", palError);
+
+ return palError;
+}
+
+/*++
+Function:
+ OpenMutexA
+
+Note:
+ dwDesiredAccess is currently ignored (no Win32 object security support)
+ bInheritHandle is currently ignored (handles to mutexes are not inheritable)
+
+See MSDN doc.
+--*/
+
+HANDLE
+PALAPI
+OpenMutexA (
+ IN DWORD dwDesiredAccess,
+ IN BOOL bInheritHandle,
+ IN LPCSTR lpName)
+{
+ HANDLE hMutex = NULL;
+ CPalThread *pthr = NULL;
+ PAL_ERROR palError;
+
+ PERF_ENTRY(OpenMutexA);
+ ENTRY("OpenMutexA(dwDesiredAccess=%#x, bInheritHandle=%d, lpName=%p (%s))\n",
+ dwDesiredAccess, bInheritHandle, lpName, lpName?lpName:"NULL");
+
+ pthr = InternalGetCurrentThread();
+
+ /* validate parameters */
+ if (lpName == nullptr)
+ {
+ ERROR("name is NULL\n");
+ palError = ERROR_INVALID_PARAMETER;
+ goto OpenMutexAExit;
+ }
+
+ palError = InternalOpenMutex(pthr, dwDesiredAccess, bInheritHandle, lpName, &hMutex);
+
+OpenMutexAExit:
+ if (NO_ERROR != palError)
+ {
+ pthr->SetLastError(palError);
+ }
+
+ LOGEXIT("OpenMutexA returns HANDLE %p\n", hMutex);
+ PERF_EXIT(OpenMutexA);
+ return hMutex;
+}
+
+/*++
+Function:
+ OpenMutexW
+
+Note:
+ dwDesiredAccess is currently ignored (no Win32 object security support)
+ bInheritHandle is currently ignored (handles to mutexes are not inheritable)
+
+See MSDN doc.
+--*/
+
+HANDLE
+PALAPI
+OpenMutexW(
+ IN DWORD dwDesiredAccess,
+ IN BOOL bInheritHandle,
+ IN LPCWSTR lpName)
+{
+ HANDLE hMutex = NULL;
+ PAL_ERROR palError = NO_ERROR;
+ CPalThread *pthr = NULL;
+ char utf8Name[SHARED_MEMORY_MAX_NAME_CHAR_COUNT + 1];
+
+ PERF_ENTRY(OpenMutexW);
+ ENTRY("OpenMutexW(dwDesiredAccess=%#x, bInheritHandle=%d, lpName=%p (%S))\n",
+ dwDesiredAccess, bInheritHandle, lpName, lpName?lpName:W16_NULLSTRING);
+
+ pthr = InternalGetCurrentThread();
+
+ /* validate parameters */
+ if (lpName == nullptr)
+ {
+ ERROR("name is NULL\n");
+ palError = ERROR_INVALID_PARAMETER;
+ goto OpenMutexWExit;
+ }
+
+ {
+ int bytesWritten = WideCharToMultiByte(CP_ACP, 0, lpName, -1, utf8Name, _countof(utf8Name), nullptr, nullptr);
+ if (bytesWritten == 0)
+ {
+ DWORD errorCode = GetLastError();
+ if (errorCode == ERROR_INSUFFICIENT_BUFFER)
+ {
+ palError = static_cast<DWORD>(SharedMemoryError::NameTooLong);
+ }
+ else
+ {
+ ASSERT("WideCharToMultiByte failed (%u)\n", errorCode);
+ palError = errorCode;
+ }
+ goto OpenMutexWExit;
+ }
+ }
+
+ palError = InternalOpenMutex(pthr, dwDesiredAccess, bInheritHandle, lpName == nullptr ? nullptr : utf8Name, &hMutex);
+
+OpenMutexWExit:
+ if (NO_ERROR != palError)
+ {
+ pthr->SetLastError(palError);
+ }
+
+ LOGEXIT("OpenMutexW returns HANDLE %p\n", hMutex);
+ PERF_EXIT(OpenMutexW);
+
+ return hMutex;
+}
+
+/*++
+Function:
+ InternalOpenMutex
+
+Note:
+ dwDesiredAccess is currently ignored (no Win32 object security support)
+ bInheritHandle is currently ignored (handles to mutexes are not inheritable)
+
+Parameters:
+ pthr -- thread data for calling thread
+ phEvent -- on success, receives the allocated mutex handle
+
+ See MSDN docs on OpenMutex for all other parameters.
+--*/
+
+PAL_ERROR
+CorUnix::InternalOpenMutex(
+ CPalThread *pthr,
+ DWORD dwDesiredAccess,
+ BOOL bInheritHandle,
+ LPCSTR lpName,
+ HANDLE *phMutex
+ )
+{
+ CObjectAttributes oa;
+ PAL_ERROR palError = NO_ERROR;
+ IPalObject *pobjMutex = NULL;
+ IPalObject *pobjRegisteredMutex = NULL;
+ HANDLE hMutex = nullptr;
+
+ _ASSERTE(NULL != pthr);
+ _ASSERTE(NULL != lpName);
+ _ASSERTE(NULL != phMutex);
+
+ ENTRY("InternalOpenMutex(pthr=%p, dwDesiredAcces=%d, bInheritHandle=%d, "
+ "lpName=%p, phMutex=%p)\n",
+ pthr,
+ dwDesiredAccess,
+ bInheritHandle,
+ lpName,
+ phMutex
+ );
+
+ palError = g_pObjectManager->AllocateObject(
+ pthr,
+ &otNamedMutex,
+ &oa,
+ &pobjMutex
+ );
+
+ if (NO_ERROR != palError)
+ {
+ goto InternalOpenMutexExit;
+ }
+
+ palError = g_pObjectManager->RegisterObject(
+ pthr,
+ pobjMutex,
+ &aotNamedMutex,
+ dwDesiredAccess,
+ &hMutex,
+ &pobjRegisteredMutex
+ );
+
+ if (palError != NO_ERROR)
+ {
+ _ASSERTE(palError != ERROR_ALREADY_EXISTS); // PAL's naming infrastructure is not used for named mutexes
+ _ASSERTE(pobjRegisteredMutex == nullptr);
+ _ASSERTE(hMutex == nullptr);
+ goto InternalOpenMutexExit;
+ }
+
+ // Now that the object has been registered successfully, it would have a reference associated with the handle, so release
+ // the initial reference. Any errors from now on need to revoke the handle.
+ _ASSERTE(pobjRegisteredMutex == pobjMutex);
+ _ASSERTE(hMutex != nullptr);
+ pobjMutex->ReleaseReference(pthr);
+ pobjRegisteredMutex = nullptr;
+
+ {
+ SharedMemoryProcessDataHeader *processDataHeader;
+ try
+ {
+ processDataHeader = NamedMutexProcessData::Open(lpName);
+ }
+ catch (SharedMemoryException ex)
+ {
+ palError = ex.GetErrorCode();
+ goto InternalOpenMutexExit;
+ }
+ if (processDataHeader == nullptr)
+ {
+ palError = ERROR_FILE_NOT_FOUND;
+ goto InternalOpenMutexExit;
+ }
+ SharedMemoryProcessDataHeader::PalObject_SetProcessDataHeader(pobjMutex, processDataHeader);
+ }
+
+ *phMutex = hMutex;
+ hMutex = nullptr;
+ pobjMutex = nullptr;
+
+InternalOpenMutexExit:
+
+ _ASSERTE(pobjRegisteredMutex == nullptr);
+ if (hMutex != nullptr)
+ {
+ g_pObjectManager->RevokeHandle(pthr, hMutex);
+ }
+ else if (NULL != pobjMutex)
+ {
+ pobjMutex->ReleaseReference(pthr);
+ }
+
+ LOGEXIT("InternalCreateMutex returns %i\n", palError);
+
+ return palError;
+}
+
+
+/* Basic spinlock implementation */
+void SPINLOCKAcquire (LONG * lock, unsigned int flags)
+{
+ size_t loop_seed = 1, loop_count = 0;
+
+ if (flags & SYNCSPINLOCK_F_ASYMMETRIC)
+ {
+ loop_seed = ((size_t)pthread_self() % 10) + 1;
+ }
+ while (InterlockedCompareExchange(lock, 1, 0))
+ {
+ if (!(flags & SYNCSPINLOCK_F_ASYMMETRIC) || (++loop_count % loop_seed))
+ {
+#if PAL_IGNORE_NORMAL_THREAD_PRIORITY
+ struct timespec tsSleepTime;
+ tsSleepTime.tv_sec = 0;
+ tsSleepTime.tv_nsec = 1;
+ nanosleep(&tsSleepTime, NULL);
+#else
+ sched_yield();
+#endif
+ }
+ }
+
+}
+
+void SPINLOCKRelease (LONG * lock)
+{
+ *lock = 0;
+}
+
+DWORD SPINLOCKTryAcquire (LONG * lock)
+{
+ return InterlockedCompareExchange(lock, 1, 0);
+ // only returns 0 or 1.
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// MutexHelpers
+
+#if NAMED_MUTEX_USE_PTHREAD_MUTEX
+void MutexHelpers::InitializeProcessSharedRobustRecursiveMutex(pthread_mutex_t *mutex)
+{
+ _ASSERTE(mutex != nullptr);
+
+ struct AutoCleanup
+ {
+ pthread_mutexattr_t *m_mutexAttributes;
+
+ AutoCleanup() : m_mutexAttributes(nullptr)
+ {
+ }
+
+ ~AutoCleanup()
+ {
+ if (m_mutexAttributes != nullptr)
+ {
+ int error = pthread_mutexattr_destroy(m_mutexAttributes);
+ _ASSERTE(error == 0);
+ }
+ }
+ } autoCleanup;
+
+ pthread_mutexattr_t mutexAttributes;
+ int error = pthread_mutexattr_init(&mutexAttributes);
+ if (error != 0)
+ {
+ throw SharedMemoryException(static_cast<DWORD>(SharedMemoryError::OutOfMemory));
+ }
+ autoCleanup.m_mutexAttributes = &mutexAttributes;
+
+ error = pthread_mutexattr_setpshared(&mutexAttributes, PTHREAD_PROCESS_SHARED);
+ _ASSERTE(error == 0);
+
+ error = pthread_mutexattr_setrobust(&mutexAttributes, PTHREAD_MUTEX_ROBUST);
+ _ASSERTE(error == 0);
+
+ error = pthread_mutexattr_settype(&mutexAttributes, PTHREAD_MUTEX_RECURSIVE);
+ _ASSERTE(error == 0);
+
+ error = pthread_mutex_init(mutex, &mutexAttributes);
+ if (error != 0)
+ {
+ throw SharedMemoryException(static_cast<DWORD>(error == EPERM ? SharedMemoryError::IO : SharedMemoryError::OutOfMemory));
+ }
+}
+
+void MutexHelpers::DestroyMutex(pthread_mutex_t *mutex)
+{
+ _ASSERTE(mutex != nullptr);
+
+ int error = pthread_mutex_destroy(mutex);
+ _ASSERTE(error == 0 || error == EBUSY); // the error will be EBUSY if the mutex is locked
+}
+
+MutexTryAcquireLockResult MutexHelpers::TryAcquireLock(pthread_mutex_t *mutex, DWORD timeoutMilliseconds)
+{
+ _ASSERTE(mutex != nullptr);
+
+ int lockResult;
+ switch (timeoutMilliseconds)
+ {
+ case static_cast<DWORD>(-1):
+ lockResult = pthread_mutex_lock(mutex);
+ break;
+
+ case 0:
+ lockResult = pthread_mutex_trylock(mutex);
+ break;
+
+ default:
+ {
+ struct timespec timeoutTime;
+ PAL_ERROR palError = CPalSynchronizationManager::GetAbsoluteTimeout(timeoutMilliseconds, &timeoutTime);
+ _ASSERTE(palError == NO_ERROR);
+ lockResult = pthread_mutex_timedlock(mutex, &timeoutTime);
+ break;
+ }
+ }
+
+ switch (lockResult)
+ {
+ case 0:
+ return MutexTryAcquireLockResult::AcquiredLock;
+
+ case EBUSY:
+ _ASSERTE(timeoutMilliseconds == 0);
+ return MutexTryAcquireLockResult::TimedOut;
+
+ case ETIMEDOUT:
+ _ASSERTE(timeoutMilliseconds != static_cast<DWORD>(-1));
+ _ASSERTE(timeoutMilliseconds != 0);
+ return MutexTryAcquireLockResult::TimedOut;
+
+ case EOWNERDEAD:
+ {
+ int setConsistentResult = pthread_mutex_consistent(mutex);
+ _ASSERTE(setConsistentResult == 0);
+ return MutexTryAcquireLockResult::AcquiredLockButMutexWasAbandoned;
+ }
+
+ case EAGAIN:
+ throw SharedMemoryException(static_cast<DWORD>(NamedMutexError::MaximumRecursiveLocksReached));
+
+ default:
+ throw SharedMemoryException(static_cast<DWORD>(NamedMutexError::Unknown));
+ }
+}
+
+void MutexHelpers::ReleaseLock(pthread_mutex_t *mutex)
+{
+ _ASSERTE(mutex != nullptr);
+
+ int unlockResult = pthread_mutex_unlock(mutex);
+ _ASSERTE(unlockResult == 0);
+}
+#endif // NAMED_MUTEX_USE_PTHREAD_MUTEX
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// NamedMutexSharedData
+
+NamedMutexSharedData::NamedMutexSharedData()
+ :
+#if !NAMED_MUTEX_USE_PTHREAD_MUTEX
+ m_timedWaiterCount(0),
+#endif // !NAMED_MUTEX_USE_PTHREAD_MUTEX
+ m_lockOwnerProcessId(SharedMemoryHelpers::InvalidProcessId),
+ m_lockOwnerThreadId(SharedMemoryHelpers::InvalidSharedThreadId),
+ m_isAbandoned(false)
+{
+#if !NAMED_MUTEX_USE_PTHREAD_MUTEX
+ static_assert_no_msg(sizeof(m_timedWaiterCount) == sizeof(LONG)); // for interlocked operations
+#endif // NAMED_MUTEX_USE_PTHREAD_MUTEX
+
+ _ASSERTE(SharedMemoryManager::IsCreationDeletionProcessLockAcquired());
+ _ASSERTE(SharedMemoryManager::IsCreationDeletionFileLockAcquired());
+
+#if NAMED_MUTEX_USE_PTHREAD_MUTEX
+ MutexHelpers::InitializeProcessSharedRobustRecursiveMutex(&m_lock);
+#endif // NAMED_MUTEX_USE_PTHREAD_MUTEX
+}
+
+NamedMutexSharedData::~NamedMutexSharedData()
+{
+ _ASSERTE(SharedMemoryManager::IsCreationDeletionProcessLockAcquired());
+ _ASSERTE(SharedMemoryManager::IsCreationDeletionFileLockAcquired());
+
+#if NAMED_MUTEX_USE_PTHREAD_MUTEX
+ MutexHelpers::DestroyMutex(&m_lock);
+#endif // NAMED_MUTEX_USE_PTHREAD_MUTEX
+}
+
+#if NAMED_MUTEX_USE_PTHREAD_MUTEX
+pthread_mutex_t *NamedMutexSharedData::GetLock()
+{
+ return &m_lock;
+}
+#else // !NAMED_MUTEX_USE_PTHREAD_MUTEX
+bool NamedMutexSharedData::HasAnyTimedWaiters() const
+{
+ return
+ InterlockedCompareExchange(
+ const_cast<LONG *>(reinterpret_cast<const LONG *>(&m_timedWaiterCount)),
+ -1 /* Exchange */,
+ -1 /* Comparand */) != 0;
+}
+
+void NamedMutexSharedData::IncTimedWaiterCount()
+{
+ ULONG newValue = InterlockedIncrement(reinterpret_cast<LONG *>(&m_timedWaiterCount));
+ if (newValue == 0)
+ {
+ throw SharedMemoryException(static_cast<DWORD>(SharedMemoryError::OutOfMemory));
+ }
+}
+
+void NamedMutexSharedData::DecTimedWaiterCount()
+{
+ ULONG newValue = InterlockedDecrement(reinterpret_cast<LONG *>(&m_timedWaiterCount));
+ _ASSERTE(newValue + 1 != 0);
+}
+#endif // NAMED_MUTEX_USE_PTHREAD_MUTEX
+
+bool NamedMutexSharedData::IsAbandoned() const
+{
+ _ASSERTE(IsLockOwnedByCurrentThread());
+ return m_isAbandoned;
+}
+
+void NamedMutexSharedData::SetIsAbandoned(bool isAbandoned)
+{
+ _ASSERTE(IsLockOwnedByCurrentThread());
+ _ASSERTE(m_isAbandoned != isAbandoned);
+
+ m_isAbandoned = isAbandoned;
+}
+
+bool NamedMutexSharedData::IsLockOwnedByAnyThread() const
+{
+ return
+ m_lockOwnerProcessId != SharedMemoryHelpers::InvalidProcessId ||
+ m_lockOwnerThreadId != SharedMemoryHelpers::InvalidSharedThreadId;
+}
+
+bool NamedMutexSharedData::IsLockOwnedByCurrentThread() const
+{
+ return m_lockOwnerProcessId == GetCurrentProcessId() && m_lockOwnerThreadId == THREADSilentGetCurrentThreadId();
+}
+
+void NamedMutexSharedData::SetLockOwnerToCurrentThread()
+{
+ m_lockOwnerProcessId = GetCurrentProcessId();
+ _ASSERTE(m_lockOwnerProcessId != SharedMemoryHelpers::InvalidProcessId);
+ m_lockOwnerThreadId = THREADSilentGetCurrentThreadId();
+ _ASSERTE(m_lockOwnerThreadId != SharedMemoryHelpers::InvalidSharedThreadId);
+}
+
+void NamedMutexSharedData::ClearLockOwner()
+{
+ _ASSERTE(IsLockOwnedByCurrentThread());
+
+ m_lockOwnerProcessId = SharedMemoryHelpers::InvalidProcessId;
+ m_lockOwnerThreadId = SharedMemoryHelpers::InvalidSharedThreadId;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// NamedMutexProcessData
+
+// This value should only be incremented if a non-backward-compatible change to the sync system is made. A process would fail to
+// open a mutex created with a different sync system version.
+const UINT8 NamedMutexProcessData::SyncSystemVersion = 1;
+
+const DWORD NamedMutexProcessData::PollLoopMaximumSleepMilliseconds = 100;
+
+SharedMemoryProcessDataHeader *NamedMutexProcessData::CreateOrOpen(LPCSTR name, bool acquireLockIfCreated, bool *createdRef)
+{
+ return CreateOrOpen(name, true /* createIfNotExist */, acquireLockIfCreated, createdRef);
+}
+
+SharedMemoryProcessDataHeader *NamedMutexProcessData::Open(LPCSTR name)
+{
+ return CreateOrOpen(name, false /* createIfNotExist */, false /* acquireLockIfCreated */, nullptr /* createdRef */);
+}
+
+SharedMemoryProcessDataHeader *NamedMutexProcessData::CreateOrOpen(
+ LPCSTR name,
+ bool createIfNotExist,
+ bool acquireLockIfCreated,
+ bool *createdRef)
+{
+ _ASSERTE(name != nullptr);
+ _ASSERTE(createIfNotExist || !acquireLockIfCreated);
+
+ struct AutoCleanup
+ {
+ bool m_acquiredCreationDeletionProcessLock;
+ bool m_acquiredCreationDeletionFileLock;
+ SharedMemoryProcessDataHeader *m_processDataHeader;
+ #if !NAMED_MUTEX_USE_PTHREAD_MUTEX
+ char *m_lockFilePath;
+ SIZE_T m_sessionDirectoryPathCharCount;
+ bool m_createdLockFile;
+ int m_lockFileDescriptor;
+ #endif // !NAMED_MUTEX_USE_PTHREAD_MUTEX
+ bool m_cancel;
+
+ AutoCleanup()
+ : m_acquiredCreationDeletionProcessLock(false),
+ m_acquiredCreationDeletionFileLock(false),
+ m_processDataHeader(nullptr),
+ #if !NAMED_MUTEX_USE_PTHREAD_MUTEX
+ m_lockFilePath(nullptr),
+ m_sessionDirectoryPathCharCount(0),
+ m_createdLockFile(false),
+ m_lockFileDescriptor(-1),
+ #endif // !NAMED_MUTEX_USE_PTHREAD_MUTEX
+ m_cancel(false)
+ {
+ }
+
+ ~AutoCleanup()
+ {
+ #if !NAMED_MUTEX_USE_PTHREAD_MUTEX
+ if (!m_cancel)
+ {
+ if (m_lockFileDescriptor != -1)
+ {
+ SharedMemoryHelpers::CloseFile(m_lockFileDescriptor);
+ }
+
+ if (m_createdLockFile)
+ {
+ _ASSERTE(m_lockFilePath != nullptr);
+ unlink(m_lockFilePath);
+ }
+
+ if (m_sessionDirectoryPathCharCount != 0)
+ {
+ _ASSERTE(m_lockFilePath != nullptr);
+ m_lockFilePath[m_sessionDirectoryPathCharCount] = '\0';
+ rmdir(m_lockFilePath);
+ }
+ }
+ #endif // !NAMED_MUTEX_USE_PTHREAD_MUTEX
+
+ if (m_acquiredCreationDeletionFileLock)
+ {
+ SharedMemoryManager::ReleaseCreationDeletionFileLock();
+ }
+
+ if (!m_cancel && m_processDataHeader != nullptr)
+ {
+ _ASSERTE(m_acquiredCreationDeletionProcessLock);
+ m_processDataHeader->DecRefCount();
+ }
+
+ if (m_acquiredCreationDeletionProcessLock)
+ {
+ SharedMemoryManager::ReleaseCreationDeletionProcessLock();
+ }
+ }
+ } autoCleanup;
+
+ SharedMemoryManager::AcquireCreationDeletionProcessLock();
+ autoCleanup.m_acquiredCreationDeletionProcessLock = true;
+
+ // Create or open the shared memory
+ bool created;
+ SharedMemoryProcessDataHeader *processDataHeader =
+ SharedMemoryProcessDataHeader::CreateOrOpen(
+ name,
+ SharedMemorySharedDataHeader(SharedMemoryType::Mutex, SyncSystemVersion),
+ sizeof(NamedMutexSharedData),
+ createIfNotExist,
+ &created);
+ if (createdRef != nullptr)
+ {
+ *createdRef = created;
+ }
+ if (created)
+ {
+ // If the shared memory file was created, the creation/deletion file lock would have been acquired so that we can
+ // initialize the shared data
+ autoCleanup.m_acquiredCreationDeletionFileLock = true;
+ }
+ if (processDataHeader == nullptr)
+ {
+ _ASSERTE(!createIfNotExist);
+ return nullptr;
+ }
+ autoCleanup.m_processDataHeader = processDataHeader;
+
+ if (created)
+ {
+ // Initialize the shared data
+ new(processDataHeader->GetSharedDataHeader()->GetData()) NamedMutexSharedData;
+ }
+
+ if (processDataHeader->GetData() == nullptr)
+ {
+ #if !NAMED_MUTEX_USE_PTHREAD_MUTEX
+ // Create the lock files directory
+ char lockFilePath[SHARED_MEMORY_MAX_FILE_PATH_CHAR_COUNT + 1];
+ SIZE_T lockFilePathCharCount =
+ SharedMemoryHelpers::CopyString(lockFilePath, 0, SHARED_MEMORY_LOCK_FILES_DIRECTORY_PATH);
+ if (created)
+ {
+ SharedMemoryHelpers::EnsureDirectoryExists(lockFilePath, true /* isGlobalLockAcquired */);
+ }
+
+ // Create the session directory
+ lockFilePath[lockFilePathCharCount++] = '/';
+ SharedMemoryId *id = processDataHeader->GetId();
+ lockFilePathCharCount = id->AppendSessionDirectoryName(lockFilePath, lockFilePathCharCount);
+ if (created)
+ {
+ SharedMemoryHelpers::EnsureDirectoryExists(lockFilePath, true /* isGlobalLockAcquired */);
+ autoCleanup.m_lockFilePath = lockFilePath;
+ autoCleanup.m_sessionDirectoryPathCharCount = lockFilePathCharCount;
+ }
+
+ // Create or open the lock file
+ lockFilePath[lockFilePathCharCount++] = '/';
+ lockFilePathCharCount =
+ SharedMemoryHelpers::CopyString(lockFilePath, lockFilePathCharCount, id->GetName(), id->GetNameCharCount());
+ int lockFileDescriptor = SharedMemoryHelpers::CreateOrOpenFile(lockFilePath, created);
+ if (lockFileDescriptor == -1)
+ {
+ _ASSERTE(!created);
+ if (createIfNotExist)
+ {
+ throw SharedMemoryException(static_cast<DWORD>(SharedMemoryError::IO));
+ }
+ return nullptr;
+ }
+ autoCleanup.m_createdLockFile = created;
+ autoCleanup.m_lockFileDescriptor = lockFileDescriptor;
+ #endif // !NAMED_MUTEX_USE_PTHREAD_MUTEX
+
+ // Create the process data
+ void *processDataBuffer = SharedMemoryHelpers::Alloc(sizeof(NamedMutexProcessData));
+ AutoFreeBuffer autoFreeProcessDataBuffer(processDataBuffer);
+ NamedMutexProcessData *processData =
+ new(processDataBuffer)
+ NamedMutexProcessData(
+ processDataHeader
+ #if !NAMED_MUTEX_USE_PTHREAD_MUTEX
+ ,
+ lockFileDescriptor
+ #endif // !NAMED_MUTEX_USE_PTHREAD_MUTEX
+ );
+ autoFreeProcessDataBuffer.Cancel();
+ processDataHeader->SetData(processData);
+
+ // If the mutex was created and if requested, acquire the lock initially while holding the creation/deletion locks
+ if (created && acquireLockIfCreated)
+ {
+ MutexTryAcquireLockResult tryAcquireLockResult = processData->TryAcquireLock(0);
+ _ASSERTE(tryAcquireLockResult == MutexTryAcquireLockResult::AcquiredLock);
+ }
+ }
+
+ autoCleanup.m_cancel = true;
+ return processDataHeader;
+}
+
+NamedMutexProcessData::NamedMutexProcessData(
+ SharedMemoryProcessDataHeader *processDataHeader
+#if !NAMED_MUTEX_USE_PTHREAD_MUTEX
+ ,
+ int sharedLockFileDescriptor
+#endif // !NAMED_MUTEX_USE_PTHREAD_MUTEX
+)
+ :
+ m_processDataHeader(processDataHeader),
+ m_lockCount(0),
+#if !NAMED_MUTEX_USE_PTHREAD_MUTEX
+ m_sharedLockFileDescriptor(sharedLockFileDescriptor),
+#endif // !NAMED_MUTEX_USE_PTHREAD_MUTEX
+ m_lockOwnerThread(nullptr),
+ m_nextInThreadOwnedNamedMutexList(nullptr)
+{
+ _ASSERTE(SharedMemoryManager::IsCreationDeletionProcessLockAcquired());
+ _ASSERTE(processDataHeader != nullptr);
+
+#if !NAMED_MUTEX_USE_PTHREAD_MUTEX
+ _ASSERTE(sharedLockFileDescriptor != -1);
+
+ m_processLockHandle = CreateMutex(nullptr /* lpMutexAttributes */, false /* bInitialOwner */, nullptr /* lpName */);
+ if (m_processLockHandle == nullptr)
+ {
+ throw SharedMemoryException(GetLastError());
+ }
+#endif // !NAMED_MUTEX_USE_PTHREAD_MUTEX
+}
+
+void NamedMutexProcessData::Close(bool isAbruptShutdown, bool releaseSharedData)
+{
+ _ASSERTE(SharedMemoryManager::IsCreationDeletionProcessLockAcquired());
+ _ASSERTE(!releaseSharedData || SharedMemoryManager::IsCreationDeletionFileLockAcquired());
+
+ // If the process is shutting down abruptly without having closed some mutexes, there could still be threads running with
+ // active references to the mutex. So when shutting down abruptly, don't clean up any object or global process-local state.
+ if (!isAbruptShutdown)
+ {
+ CPalThread *lockOwnerThread = m_lockOwnerThread;
+ if (lockOwnerThread != nullptr)
+ {
+ // The mutex was not released before it was closed. If the lock is owned by the current thread, abandon the mutex.
+ // In both cases, clean up the owner thread's list of owned mutexes.
+ lockOwnerThread->synchronizationInfo.RemoveOwnedNamedMutex(this);
+ if (lockOwnerThread == GetCurrentPalThread())
+ {
+ Abandon();
+ }
+ else
+ {
+ m_lockOwnerThread = nullptr;
+ }
+ }
+
+ if (releaseSharedData)
+ {
+ GetSharedData()->~NamedMutexSharedData();
+ }
+ }
+
+#if !NAMED_MUTEX_USE_PTHREAD_MUTEX
+ if (!isAbruptShutdown)
+ {
+ CloseHandle(m_processLockHandle);
+ SharedMemoryHelpers::CloseFile(m_sharedLockFileDescriptor);
+ }
+
+ if (!releaseSharedData)
+ {
+ return;
+ }
+
+ // Delete the lock file, and the session directory if it's not empty
+ char path[SHARED_MEMORY_MAX_FILE_PATH_CHAR_COUNT + 1];
+ SIZE_T sessionDirectoryPathCharCount = SharedMemoryHelpers::CopyString(path, 0, SHARED_MEMORY_LOCK_FILES_DIRECTORY_PATH);
+ path[sessionDirectoryPathCharCount++] = '/';
+ SharedMemoryId *id = m_processDataHeader->GetId();
+ sessionDirectoryPathCharCount = id->AppendSessionDirectoryName(path, sessionDirectoryPathCharCount);
+ path[sessionDirectoryPathCharCount++] = '/';
+ SharedMemoryHelpers::CopyString(path, sessionDirectoryPathCharCount, id->GetName(), id->GetNameCharCount());
+ unlink(path);
+ path[sessionDirectoryPathCharCount] = '\0';
+ rmdir(path);
+#endif // !NAMED_MUTEX_USE_PTHREAD_MUTEX
+}
+
+NamedMutexSharedData *NamedMutexProcessData::GetSharedData() const
+{
+ return reinterpret_cast<NamedMutexSharedData *>(m_processDataHeader->GetSharedDataHeader()->GetData());
+}
+
+void NamedMutexProcessData::SetLockOwnerThread(CorUnix::CPalThread *lockOwnerThread)
+{
+ _ASSERTE(lockOwnerThread == nullptr || lockOwnerThread == GetCurrentPalThread());
+ _ASSERTE(GetSharedData()->IsLockOwnedByCurrentThread());
+
+ m_lockOwnerThread = lockOwnerThread;
+}
+
+NamedMutexProcessData *NamedMutexProcessData::GetNextInThreadOwnedNamedMutexList() const
+{
+ return m_nextInThreadOwnedNamedMutexList;
+}
+
+void NamedMutexProcessData::SetNextInThreadOwnedNamedMutexList(NamedMutexProcessData *next)
+{
+ m_nextInThreadOwnedNamedMutexList = next;
+}
+
+MutexTryAcquireLockResult NamedMutexProcessData::TryAcquireLock(DWORD timeoutMilliseconds)
+{
+ NamedMutexSharedData *sharedData = GetSharedData();
+
+#if NAMED_MUTEX_USE_PTHREAD_MUTEX
+ MutexTryAcquireLockResult result = MutexHelpers::TryAcquireLock(sharedData->GetLock(), timeoutMilliseconds);
+ if (result == MutexTryAcquireLockResult::TimedOut)
+ {
+ return result;
+ }
+
+ // Check if a recursive lock was just taken. The recursion level is tracked manually so that the lock owner can be cleared
+ // at the appropriate time, see ReleaseLock().
+ if (m_lockCount != 0)
+ {
+ _ASSERTE(sharedData->IsLockOwnedByCurrentThread()); // otherwise, this thread would not have acquired the lock
+ _ASSERTE(GetCurrentPalThread()->synchronizationInfo.OwnsNamedMutex(this));
+
+ if (m_lockCount + 1 < m_lockCount)
+ {
+ MutexHelpers::ReleaseLock(sharedData->GetLock());
+ throw SharedMemoryException(static_cast<DWORD>(NamedMutexError::MaximumRecursiveLocksReached));
+ }
+ ++m_lockCount;
+
+ // The lock is released upon acquiring a recursive lock from the thread that already owns the lock
+ MutexHelpers::ReleaseLock(sharedData->GetLock());
+
+ _ASSERTE(result != MutexTryAcquireLockResult::AcquiredLockButMutexWasAbandoned);
+ _ASSERTE(!sharedData->IsAbandoned());
+ return result;
+ }
+
+ // The non-recursive case is handled below (skip the #else and see below that)
+#else // !NAMED_MUTEX_USE_PTHREAD_MUTEX
+ // If a timeout is specified, determine the start time
+ DWORD startTime = 0;
+ if (timeoutMilliseconds != static_cast<DWORD>(-1) && timeoutMilliseconds != 0)
+ {
+ startTime = GetTickCount();
+ }
+
+ // Acquire the process lock. A file lock can only be acquired once per file descriptor, so to synchronize the threads of
+ // this process, the process lock is used.
+ while (true)
+ {
+ DWORD waitResult = WaitForSingleObject(m_processLockHandle, timeoutMilliseconds);
+ switch (waitResult)
+ {
+ case WAIT_OBJECT_0:
+ case WAIT_ABANDONED: // abandoned state for the process lock is irrelevant, the shared lock will also have been abandoned
+ break;
+
+ case WAIT_TIMEOUT:
+ return MutexTryAcquireLockResult::TimedOut;
+
+ case WAIT_IO_COMPLETION:
+ continue;
+
+ case WAIT_FAILED:
+ throw SharedMemoryException(GetLastError());
+
+ default:
+ _ASSERTE(false);
+ break;
+ }
+ break;
+ }
+
+ struct AutoReleaseProcessLock
+ {
+ HANDLE m_processLockHandle;
+ bool m_cancel;
+
+ AutoReleaseProcessLock(HANDLE processLockHandle) : m_processLockHandle(processLockHandle), m_cancel(false)
+ {
+ }
+
+ ~AutoReleaseProcessLock()
+ {
+ if (!m_cancel)
+ {
+ ReleaseMutex(m_processLockHandle);
+ }
+ }
+ } autoReleaseProcessLock(m_processLockHandle);
+
+ // Check if it's a recursive lock attempt
+ if (m_lockCount != 0)
+ {
+ _ASSERTE(sharedData->IsLockOwnedByCurrentThread()); // otherwise, this thread would not have acquired the process lock
+ _ASSERTE(GetCurrentPalThread()->synchronizationInfo.OwnsNamedMutex(this));
+
+ if (m_lockCount + 1 < m_lockCount)
+ {
+ throw SharedMemoryException(static_cast<DWORD>(NamedMutexError::MaximumRecursiveLocksReached));
+ }
+ ++m_lockCount;
+
+ // The process lock is released upon acquiring a recursive lock from the thread that already owns the lock
+ return MutexTryAcquireLockResult::AcquiredLock;
+ }
+
+ switch (timeoutMilliseconds)
+ {
+ case static_cast<DWORD>(-1):
+ {
+ // The file lock API does not have a timeout on the wait, so timed waiters will poll the file lock in a loop,
+ // sleeping for a short duration in-between. Due to the polling nature of a timed wait, timed waiters will almost
+ // never acquire the file lock as long as there are also untimed waiters. So, in order to make the file lock
+ // acquisition reasonable, when there are timed waiters, have untimed waiters also use polling.
+ bool acquiredFileLock = false;
+ while (sharedData->HasAnyTimedWaiters())
+ {
+ if (SharedMemoryHelpers::TryAcquireFileLock(m_sharedLockFileDescriptor, LOCK_EX | LOCK_NB))
+ {
+ acquiredFileLock = true;
+ break;
+ }
+ Sleep(PollLoopMaximumSleepMilliseconds);
+ }
+ if (acquiredFileLock)
+ {
+ break;
+ }
+
+ acquiredFileLock = SharedMemoryHelpers::TryAcquireFileLock(m_sharedLockFileDescriptor, LOCK_EX);
+ _ASSERTE(acquiredFileLock);
+ break;
+ }
+
+ case 0:
+ if (!SharedMemoryHelpers::TryAcquireFileLock(m_sharedLockFileDescriptor, LOCK_EX | LOCK_NB))
+ {
+ return MutexTryAcquireLockResult::TimedOut;
+ }
+ break;
+
+ default:
+ {
+ // Try to acquire the file lock without waiting
+ if (SharedMemoryHelpers::TryAcquireFileLock(m_sharedLockFileDescriptor, LOCK_EX | LOCK_NB))
+ {
+ break;
+ }
+
+ // The file lock API does not have a timeout on the wait, so timed waiters need to poll the file lock in a loop,
+ // sleeping for a short duration in-between. Due to the polling nature of a timed wait, timed waiters will almost
+ // never acquire the file lock as long as there are also untimed waiters. So, in order to make the file lock
+ // acquisition reasonable, record that there is a timed waiter, to have untimed waiters also use polling.
+ sharedData->IncTimedWaiterCount();
+ struct AutoDecTimedWaiterCount
+ {
+ NamedMutexSharedData *m_sharedData;
+
+ AutoDecTimedWaiterCount(NamedMutexSharedData *sharedData) : m_sharedData(sharedData)
+ {
+ }
+
+ ~AutoDecTimedWaiterCount()
+ {
+ m_sharedData->DecTimedWaiterCount();
+ }
+ } autoDecTimedWaiterCount(sharedData);
+
+ // Poll for the file lock
+ do
+ {
+ DWORD elapsedMilliseconds = GetTickCount() - startTime;
+ if (elapsedMilliseconds >= timeoutMilliseconds)
+ {
+ return MutexTryAcquireLockResult::TimedOut;
+ }
+
+ DWORD remainingMilliseconds = timeoutMilliseconds - elapsedMilliseconds;
+ DWORD sleepMilliseconds =
+ remainingMilliseconds < PollLoopMaximumSleepMilliseconds
+ ? remainingMilliseconds
+ : PollLoopMaximumSleepMilliseconds;
+ Sleep(sleepMilliseconds);
+ } while (!SharedMemoryHelpers::TryAcquireFileLock(m_sharedLockFileDescriptor, LOCK_EX | LOCK_NB));
+ break;
+ }
+ }
+
+ // There cannot be any exceptions after this
+ autoReleaseProcessLock.m_cancel = true;
+
+ // After acquiring the file lock, if we find that a lock owner is already designated, the process that previously owned the
+ // lock must have terminated while holding the lock.
+ MutexTryAcquireLockResult result =
+ sharedData->IsLockOwnedByAnyThread()
+ ? MutexTryAcquireLockResult::AcquiredLockButMutexWasAbandoned
+ : MutexTryAcquireLockResult::AcquiredLock;
+#endif // NAMED_MUTEX_USE_PTHREAD_MUTEX
+
+ sharedData->SetLockOwnerToCurrentThread();
+ m_lockCount = 1;
+ CPalThread *currentThread = GetCurrentPalThread();
+ SetLockOwnerThread(currentThread);
+ currentThread->synchronizationInfo.AddOwnedNamedMutex(this);
+
+ if (sharedData->IsAbandoned())
+ {
+ // The thread that previously owned the lock did not release it before exiting
+ sharedData->SetIsAbandoned(false);
+ result = MutexTryAcquireLockResult::AcquiredLockButMutexWasAbandoned;
+ }
+ return result;
+}
+
+void NamedMutexProcessData::ReleaseLock()
+{
+ if (!GetSharedData()->IsLockOwnedByCurrentThread())
+ {
+ throw SharedMemoryException(static_cast<DWORD>(NamedMutexError::ThreadHasNotAcquiredMutex));
+ }
+
+ _ASSERTE(GetCurrentPalThread()->synchronizationInfo.OwnsNamedMutex(this));
+
+ _ASSERTE(m_lockCount != 0);
+ --m_lockCount;
+ if (m_lockCount != 0)
+ {
+ return;
+ }
+
+ GetCurrentPalThread()->synchronizationInfo.RemoveOwnedNamedMutex(this);
+ SetLockOwnerThread(nullptr);
+ ActuallyReleaseLock();
+}
+
+void NamedMutexProcessData::Abandon()
+{
+ NamedMutexSharedData *sharedData = GetSharedData();
+ _ASSERTE(sharedData->IsLockOwnedByCurrentThread());
+ _ASSERTE(m_lockCount != 0);
+
+ sharedData->SetIsAbandoned(true);
+ m_lockCount = 0;
+ SetLockOwnerThread(nullptr);
+ ActuallyReleaseLock();
+}
+
+void NamedMutexProcessData::ActuallyReleaseLock()
+{
+ NamedMutexSharedData *sharedData = GetSharedData();
+ _ASSERTE(sharedData->IsLockOwnedByCurrentThread());
+ _ASSERTE(!GetCurrentPalThread()->synchronizationInfo.OwnsNamedMutex(this));
+ _ASSERTE(m_lockCount == 0);
+
+ sharedData->ClearLockOwner();
+
+#if NAMED_MUTEX_USE_PTHREAD_MUTEX
+ MutexHelpers::ReleaseLock(sharedData->GetLock());
+#else // !NAMED_MUTEX_USE_PTHREAD_MUTEX
+ SharedMemoryHelpers::ReleaseFileLock(m_sharedLockFileDescriptor);
+ ReleaseMutex(m_processLockHandle);
+#endif // NAMED_MUTEX_USE_PTHREAD_MUTEX
+}
diff --git a/src/pal/src/synchobj/semaphore.cpp b/src/pal/src/synchobj/semaphore.cpp
new file mode 100644
index 0000000000..b2240184c5
--- /dev/null
+++ b/src/pal/src/synchobj/semaphore.cpp
@@ -0,0 +1,680 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ semaphore.cpp
+
+Abstract:
+
+ Implementation of the sempahore synchroniztion object as described in
+ the WIN32 API
+
+Revision History:
+
+
+
+--*/
+
+#include "pal/semaphore.hpp"
+#include "pal/thread.hpp"
+#include "pal/dbgmsg.h"
+
+using namespace CorUnix;
+
+/* ------------------- Definitions ------------------------------*/
+SET_DEFAULT_DEBUG_CHANNEL(SYNC);
+
+CObjectType CorUnix::otSemaphore(
+ otiSemaphore,
+ NULL, // No cleanup routine
+ NULL, // No initialization routine
+ sizeof(SemaphoreImmutableData),
+ 0, // No process local data
+ 0, // No shared data
+ 0, // Should be SEMAPHORE_ALL_ACCESS; currently ignored (no Win32 security)
+ CObjectType::SecuritySupported,
+ CObjectType::SecurityInfoNotPersisted,
+ CObjectType::UnnamedObject,
+ CObjectType::LocalDuplicationOnly,
+ CObjectType::WaitableObject,
+ CObjectType::ObjectCanBeUnsignaled,
+ CObjectType::ThreadReleaseAltersSignalCount,
+ CObjectType::NoOwner
+ );
+
+CAllowedObjectTypes aotSempahore(otiSemaphore);
+
+/*++
+Function:
+CreateSemaphoreExA
+
+Note:
+lpSemaphoreAttributes currently ignored:
+-- Win32 object security not supported
+-- handles to semaphore objects are not inheritable
+
+Parameters:
+See MSDN doc.
+--*/
+
+HANDLE
+PALAPI
+CreateSemaphoreExA(
+ IN LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,
+ IN LONG lInitialCount,
+ IN LONG lMaximumCount,
+ IN LPCSTR lpName,
+ IN /*_Reserved_*/ DWORD dwFlags,
+ IN DWORD dwDesiredAccess)
+{
+ // dwFlags is reserved and unused, and dwDesiredAccess is currently
+ // only ever used as SEMAPHORE_ALL_ACCESS. The other parameters
+ // all map to CreateSemaphoreA.
+ _ASSERTE(SEMAPHORE_ALL_ACCESS == dwDesiredAccess);
+
+ return CreateSemaphoreA(
+ lpSemaphoreAttributes,
+ lInitialCount,
+ lMaximumCount,
+ lpName);
+}
+
+/*++
+Function:
+ CreateSemaphoreA
+
+Note:
+ lpSemaphoreAttributes currently ignored:
+ -- Win32 object security not supported
+ -- handles to semaphore objects are not inheritable
+
+Parameters:
+ See MSDN doc.
+--*/
+
+HANDLE
+PALAPI
+CreateSemaphoreA(
+ IN LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,
+ IN LONG lInitialCount,
+ IN LONG lMaximumCount,
+ IN LPCSTR lpName)
+{
+ HANDLE hSemaphore = NULL;
+ CPalThread *pthr = NULL;
+ PAL_ERROR palError;
+
+ PERF_ENTRY(CreateSemaphoreA);
+ ENTRY("CreateSemaphoreA(lpSemaphoreAttributes=%p, lInitialCount=%d, "
+ "lMaximumCount=%d, lpName=%p (%s))\n",
+ lpSemaphoreAttributes, lInitialCount, lMaximumCount, lpName, lpName?lpName:"NULL");
+
+ pthr = InternalGetCurrentThread();
+
+ if (lpName != nullptr)
+ {
+ ASSERT("lpName: Cross-process named objects are not supported in PAL");
+ palError = ERROR_NOT_SUPPORTED;
+ }
+ else
+ {
+ palError = InternalCreateSemaphore(
+ pthr,
+ lpSemaphoreAttributes,
+ lInitialCount,
+ lMaximumCount,
+ NULL,
+ &hSemaphore
+ );
+ }
+
+ //
+ // We always need to set last error, even on success:
+ // we need to protect ourselves from the situation
+ // where last error is set to ERROR_ALREADY_EXISTS on
+ // entry to the function
+ //
+
+ pthr->SetLastError(palError);
+
+ LOGEXIT("CreateSemaphoreA returns HANDLE %p\n", hSemaphore);
+ PERF_EXIT(CreateSemaphoreA);
+ return hSemaphore;
+}
+
+/*++
+Function:
+CreateSemaphoreExW
+
+Note:
+lpSemaphoreAttributes currentely ignored:
+-- Win32 object security not supported
+-- handles to semaphore objects are not inheritable
+
+Parameters:
+See MSDN doc.
+--*/
+
+PALIMPORT
+HANDLE
+PALAPI
+CreateSemaphoreExW(
+ IN LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,
+ IN LONG lInitialCount,
+ IN LONG lMaximumCount,
+ IN LPCWSTR lpName,
+ IN /*_Reserved_*/ DWORD dwFlags,
+ IN DWORD dwDesiredAccess)
+{
+ // dwFlags is reserved and unused, and dwDesiredAccess is currently
+ // only ever used as SEMAPHORE_ALL_ACCESS. The other parameters
+ // all map to CreateSemaphoreW.
+ _ASSERTE(SEMAPHORE_ALL_ACCESS == dwDesiredAccess);
+
+ return CreateSemaphoreW(
+ lpSemaphoreAttributes,
+ lInitialCount,
+ lMaximumCount,
+ lpName);
+}
+
+/*++
+Function:
+ CreateSemaphoreW
+
+Note:
+ lpSemaphoreAttributes currentely ignored:
+ -- Win32 object security not supported
+ -- handles to semaphore objects are not inheritable
+
+Parameters:
+ See MSDN doc.
+--*/
+
+HANDLE
+PALAPI
+CreateSemaphoreW(
+ IN LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,
+ IN LONG lInitialCount,
+ IN LONG lMaximumCount,
+ IN LPCWSTR lpName)
+{
+ HANDLE hSemaphore = NULL;
+ PAL_ERROR palError;
+ CPalThread *pthr = NULL;
+
+ PERF_ENTRY(CreateSemaphoreW);
+ ENTRY("CreateSemaphoreW(lpSemaphoreAttributes=%p, lInitialCount=%d, "
+ "lMaximumCount=%d, lpName=%p (%S))\n",
+ lpSemaphoreAttributes, lInitialCount, lMaximumCount,
+ lpName, lpName?lpName:W16_NULLSTRING);
+
+ pthr = InternalGetCurrentThread();
+
+ palError = InternalCreateSemaphore(
+ pthr,
+ lpSemaphoreAttributes,
+ lInitialCount,
+ lMaximumCount,
+ lpName,
+ &hSemaphore
+ );
+
+ //
+ // We always need to set last error, even on success:
+ // we need to protect ourselves from the situation
+ // where last error is set to ERROR_ALREADY_EXISTS on
+ // entry to the function
+ //
+
+ pthr->SetLastError(palError);
+
+ LOGEXIT("CreateSemaphoreW returns HANDLE %p\n", hSemaphore);
+ PERF_EXIT(CreateSemaphoreW);
+ return hSemaphore;
+}
+
+/*++
+Function:
+ InternalCreateSemaphore
+
+Note:
+ lpSemaphoreAttributes currentely ignored:
+ -- Win32 object security not supported
+ -- handles to semaphore objects are not inheritable
+
+Parameters
+ pthr -- thread data for calling thread
+ phEvent -- on success, receives the allocated semaphore handle
+
+ See MSDN docs on CreateSemaphore for all other parameters.
+--*/
+
+PAL_ERROR
+CorUnix::InternalCreateSemaphore(
+ CPalThread *pthr,
+ LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,
+ LONG lInitialCount,
+ LONG lMaximumCount,
+ LPCWSTR lpName,
+ HANDLE *phSemaphore
+ )
+{
+ CObjectAttributes oa(lpName, lpSemaphoreAttributes);
+ PAL_ERROR palError = NO_ERROR;
+ IPalObject *pobjSemaphore = NULL;
+ IPalObject *pobjRegisteredSemaphore = NULL;
+ SemaphoreImmutableData *pSemaphoreData;
+
+ _ASSERTE(NULL != pthr);
+ _ASSERTE(NULL != phSemaphore);
+
+ ENTRY("InternalCreateSemaphore(pthr=%p, lpSemaphoreAttributes=%p, "
+ "lInitialCount=%d, lMaximumCount=%d, lpName=%p, phSemaphore=%p)\n",
+ pthr,
+ lpSemaphoreAttributes,
+ lInitialCount,
+ lMaximumCount,
+ lpName,
+ phSemaphore
+ );
+
+ if (lpName != nullptr)
+ {
+ ASSERT("lpName: Cross-process named objects are not supported in PAL");
+ palError = ERROR_NOT_SUPPORTED;
+ goto InternalCreateSemaphoreExit;
+ }
+
+ if (lMaximumCount <= 0)
+ {
+ ERROR("lMaximumCount is invalid (%d)\n", lMaximumCount);
+ palError = ERROR_INVALID_PARAMETER;
+ goto InternalCreateSemaphoreExit;
+ }
+
+ if ((lInitialCount < 0) || (lInitialCount > lMaximumCount))
+ {
+ ERROR("lInitialCount is invalid (%d)\n", lInitialCount);
+ palError = ERROR_INVALID_PARAMETER;
+ goto InternalCreateSemaphoreExit;
+ }
+
+ palError = g_pObjectManager->AllocateObject(
+ pthr,
+ &otSemaphore,
+ &oa,
+ &pobjSemaphore
+ );
+
+ if (NO_ERROR != palError)
+ {
+ goto InternalCreateSemaphoreExit;
+ }
+
+ palError = pobjSemaphore->GetImmutableData(reinterpret_cast<void**>(&pSemaphoreData));
+
+ if (NO_ERROR != palError)
+ {
+ ASSERT("Error %d obtaining object data\n", palError);
+ goto InternalCreateSemaphoreExit;
+ }
+
+ pSemaphoreData->lMaximumCount = lMaximumCount;
+
+ if (0 != lInitialCount)
+ {
+ ISynchStateController *pssc;
+
+ palError = pobjSemaphore->GetSynchStateController(
+ pthr,
+ &pssc
+ );
+
+ if (NO_ERROR == palError)
+ {
+ palError = pssc->SetSignalCount(lInitialCount);
+ pssc->ReleaseController();
+ }
+
+ if (NO_ERROR != palError)
+ {
+ ASSERT("Unable to set new semaphore state (%d)\n", palError);
+ goto InternalCreateSemaphoreExit;
+ }
+ }
+
+ palError = g_pObjectManager->RegisterObject(
+ pthr,
+ pobjSemaphore,
+ &aotSempahore,
+ 0, // Should be SEMAPHORE_ALL_ACCESS; currently ignored (no Win32 security)
+ phSemaphore,
+ &pobjRegisteredSemaphore
+ );
+
+ //
+ // pobjSemaphore is invalidated by the call to RegisterObject, so NULL it
+ // out here to ensure that we don't try to release a reference on
+ // it down the line.
+ //
+
+ pobjSemaphore = NULL;
+
+InternalCreateSemaphoreExit:
+
+ if (NULL != pobjSemaphore)
+ {
+ pobjSemaphore->ReleaseReference(pthr);
+ }
+
+ if (NULL != pobjRegisteredSemaphore)
+ {
+ pobjRegisteredSemaphore->ReleaseReference(pthr);
+ }
+
+ LOGEXIT("InternalCreateSemaphore returns %d\n", palError);
+
+ return palError;
+}
+
+
+/*++
+Function:
+ ReleaseSemaphore
+
+Parameters:
+ See MSDN doc.
+--*/
+
+BOOL
+PALAPI
+ReleaseSemaphore(
+ IN HANDLE hSemaphore,
+ IN LONG lReleaseCount,
+ OUT LPLONG lpPreviousCount)
+{
+ PAL_ERROR palError = NO_ERROR;
+ CPalThread *pthr = NULL;
+
+ PERF_ENTRY(ReleaseSemaphore);
+ ENTRY("ReleaseSemaphore(hSemaphore=%p, lReleaseCount=%d, "
+ "lpPreviousCount=%p)\n",
+ hSemaphore, lReleaseCount, lpPreviousCount);
+
+ pthr = InternalGetCurrentThread();
+
+ palError = InternalReleaseSemaphore(
+ pthr,
+ hSemaphore,
+ lReleaseCount,
+ lpPreviousCount
+ );
+
+ if (NO_ERROR != palError)
+ {
+ pthr->SetLastError(palError);
+ }
+
+ LOGEXIT ("ReleaseSemaphore returns BOOL %d\n", (NO_ERROR == palError));
+ PERF_EXIT(ReleaseSemaphore);
+ return (NO_ERROR == palError);
+}
+
+/*++
+Function:
+ InternalReleaseSemaphore
+
+Parameters:
+ pthr -- thread data for calling thread
+
+ See MSDN docs on ReleaseSemaphore for all other parameters
+--*/
+
+PAL_ERROR
+CorUnix::InternalReleaseSemaphore(
+ CPalThread *pthr,
+ HANDLE hSemaphore,
+ LONG lReleaseCount,
+ LPLONG lpPreviousCount
+ )
+{
+ PAL_ERROR palError = NO_ERROR;
+ IPalObject *pobjSemaphore = NULL;
+ ISynchStateController *pssc = NULL;
+ SemaphoreImmutableData *pSemaphoreData;
+ LONG lOldCount;
+
+ _ASSERTE(NULL != pthr);
+
+ ENTRY("InternalReleaseSempahore(pthr=%p, hSemaphore=%p, lReleaseCount=%d, "
+ "lpPreviousCount=%p)\n",
+ pthr,
+ hSemaphore,
+ lReleaseCount,
+ lpPreviousCount
+ );
+
+ if (0 >= lReleaseCount)
+ {
+ palError = ERROR_INVALID_PARAMETER;
+ goto InternalReleaseSemaphoreExit;
+ }
+
+ palError = g_pObjectManager->ReferenceObjectByHandle(
+ pthr,
+ hSemaphore,
+ &aotSempahore,
+ 0, // Should be SEMAPHORE_MODIFY_STATE; currently ignored (no Win32 security)
+ &pobjSemaphore
+ );
+
+ if (NO_ERROR != palError)
+ {
+ ERROR("Unable to obtain object for handle %p (error %d)!\n", hSemaphore, palError);
+ goto InternalReleaseSemaphoreExit;
+ }
+
+ palError = pobjSemaphore->GetImmutableData(reinterpret_cast<void**>(&pSemaphoreData));
+
+ if (NO_ERROR != palError)
+ {
+ ASSERT("Error %d obtaining object data\n", palError);
+ goto InternalReleaseSemaphoreExit;
+ }
+
+ palError = pobjSemaphore->GetSynchStateController(
+ pthr,
+ &pssc
+ );
+
+ if (NO_ERROR != palError)
+ {
+ ASSERT("Error %d obtaining synch state controller\n", palError);
+ goto InternalReleaseSemaphoreExit;
+ }
+
+ palError = pssc->GetSignalCount(&lOldCount);
+
+ if (NO_ERROR != palError)
+ {
+ ASSERT("Error %d obtaining current signal count\n", palError);
+ goto InternalReleaseSemaphoreExit;
+ }
+
+ _ASSERTE(lOldCount <= pSemaphoreData->lMaximumCount);
+ if (lReleaseCount > pSemaphoreData->lMaximumCount - lOldCount)
+ {
+ palError = ERROR_INVALID_PARAMETER;
+ goto InternalReleaseSemaphoreExit;
+ }
+
+ palError = pssc->IncrementSignalCount(lReleaseCount);
+
+ if (NO_ERROR != palError)
+ {
+ ASSERT("Error %d incrementing signal count\n", palError);
+ goto InternalReleaseSemaphoreExit;
+ }
+
+ if (NULL != lpPreviousCount)
+ {
+ *lpPreviousCount = lOldCount;
+ }
+
+InternalReleaseSemaphoreExit:
+
+ if (NULL != pssc)
+ {
+ pssc->ReleaseController();
+ }
+
+ if (NULL != pobjSemaphore)
+ {
+ pobjSemaphore->ReleaseReference(pthr);
+ }
+
+ LOGEXIT("InternalReleaseSemaphore returns %d\n", palError);
+
+ return palError;
+}
+
+// TODO: Implementation of OpenSemaphoreA() doesn't exist, do we need it? More generally, do we need the A versions at all?
+
+/*++
+Function:
+ OpenSemaphoreW
+
+Note:
+ dwDesiredAccess is currently ignored (no Win32 object security support)
+ bInheritHandle is currently ignored (handles to semaphore are not inheritable)
+
+Parameters:
+ See MSDN doc.
+--*/
+
+HANDLE
+PALAPI
+OpenSemaphoreW(
+ IN DWORD dwDesiredAccess,
+ IN BOOL bInheritHandle,
+ IN LPCWSTR lpName)
+{
+ HANDLE hSemaphore = NULL;
+ PAL_ERROR palError = NO_ERROR;
+ CPalThread *pthr = NULL;
+
+ PERF_ENTRY(OpenSemaphoreW);
+ ENTRY("OpenSemaphoreW(dwDesiredAccess=%#x, bInheritHandle=%d, lpName=%p (%S))\n",
+ dwDesiredAccess, bInheritHandle, lpName, lpName?lpName:W16_NULLSTRING);
+
+ pthr = InternalGetCurrentThread();
+
+ /* validate parameters */
+ if (lpName == nullptr)
+ {
+ ERROR("lpName is NULL\n");
+ palError = ERROR_INVALID_PARAMETER;
+ }
+ else
+ {
+ ASSERT("lpName: Cross-process named objects are not supported in PAL");
+ palError = ERROR_NOT_SUPPORTED;
+ }
+
+ if (NO_ERROR != palError)
+ {
+ pthr->SetLastError(palError);
+ }
+
+ LOGEXIT("OpenSemaphoreW returns HANDLE %p\n", hSemaphore);
+ PERF_EXIT(OpenSemaphoreW);
+
+ return hSemaphore;
+}
+
+/*++
+Function:
+ InternalOpenSemaphore
+
+Note:
+ dwDesiredAccess is currently ignored (no Win32 object security support)
+ bInheritHandle is currently ignored (handles to semaphores are not inheritable)
+
+Parameters:
+ pthr -- thread data for calling thread
+ phEvent -- on success, receives the allocated semaphore handle
+
+ See MSDN docs on OpenSemaphore for all other parameters.
+--*/
+
+PAL_ERROR
+CorUnix::InternalOpenSemaphore(
+ CPalThread *pthr,
+ DWORD dwDesiredAccess,
+ BOOL bInheritHandle,
+ LPCWSTR lpName,
+ HANDLE *phSemaphore
+ )
+{
+ PAL_ERROR palError = NO_ERROR;
+ IPalObject *pobjSemaphore = NULL;
+ CPalString sObjectName(lpName);
+
+ _ASSERTE(NULL != pthr);
+ _ASSERTE(NULL != lpName);
+ _ASSERTE(NULL != phSemaphore);
+
+ ENTRY("InternalOpenSemaphore(pthr=%p, dwDesiredAccess=%d, bInheritHandle=%d, "
+ "lpName=%p, phSemaphore=%p)\n",
+ pthr,
+ dwDesiredAccess,
+ bInheritHandle,
+ phSemaphore
+ );
+
+ palError = g_pObjectManager->LocateObject(
+ pthr,
+ &sObjectName,
+ &aotSempahore,
+ &pobjSemaphore
+ );
+
+ if (NO_ERROR != palError)
+ {
+ goto InternalOpenSemaphoreExit;
+ }
+
+ palError = g_pObjectManager->ObtainHandleForObject(
+ pthr,
+ pobjSemaphore,
+ dwDesiredAccess,
+ bInheritHandle,
+ NULL,
+ phSemaphore
+ );
+
+ if (NO_ERROR != palError)
+ {
+ goto InternalOpenSemaphoreExit;
+ }
+
+InternalOpenSemaphoreExit:
+
+ if (NULL != pobjSemaphore)
+ {
+ pobjSemaphore->ReleaseReference(pthr);
+ }
+
+ LOGEXIT("InternalOpenSemaphore returns %d\n", palError);
+
+ return palError;
+}
+
+
diff --git a/src/pal/src/thread/context.cpp b/src/pal/src/thread/context.cpp
new file mode 100644
index 0000000000..f832015710
--- /dev/null
+++ b/src/pal/src/thread/context.cpp
@@ -0,0 +1,1360 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ context.c
+
+Abstract:
+
+ Implementation of GetThreadContext/SetThreadContext/DebugBreak.
+ There are a lot of architecture specifics here.
+
+
+
+--*/
+
+#include "pal/dbgmsg.h"
+SET_DEFAULT_DEBUG_CHANNEL(THREAD); // some headers have code with asserts, so do this first
+
+#include "pal/palinternal.h"
+#include "pal/context.h"
+#include "pal/debug.h"
+#include "pal/thread.hpp"
+
+#include <sys/ptrace.h>
+#include <errno.h>
+#include <unistd.h>
+
+extern PGET_GCMARKER_EXCEPTION_CODE g_getGcMarkerExceptionCode;
+
+// in context2.S
+extern void CONTEXT_CaptureContext(LPCONTEXT lpContext);
+
+#ifdef _X86_
+#define CONTEXT_ALL_FLOATING (CONTEXT_FLOATING_POINT | CONTEXT_EXTENDED_REGISTERS)
+#elif defined(_AMD64_)
+#define CONTEXT_ALL_FLOATING CONTEXT_FLOATING_POINT
+#elif defined(_ARM_)
+#define CONTEXT_ALL_FLOATING CONTEXT_FLOATING_POINT
+#elif defined(_ARM64_)
+#define CONTEXT_ALL_FLOATING CONTEXT_FLOATING_POINT
+#else
+#error Unexpected architecture.
+#endif
+
+#if !HAVE_MACH_EXCEPTIONS
+
+#ifndef __GLIBC__
+typedef int __ptrace_request;
+#endif
+
+#if HAVE_MACHINE_REG_H
+#include <machine/reg.h>
+#endif // HAVE_MACHINE_REG_H
+#if HAVE_MACHINE_NPX_H
+#include <machine/npx.h>
+#endif // HAVE_MACHINE_NPX_H
+
+#if HAVE_PT_REGS
+#include <asm/ptrace.h>
+#endif // HAVE_PT_REGS
+
+#ifdef _AMD64_
+#define ASSIGN_CONTROL_REGS \
+ ASSIGN_REG(Rbp) \
+ ASSIGN_REG(Rip) \
+ ASSIGN_REG(SegCs) \
+ ASSIGN_REG(EFlags) \
+ ASSIGN_REG(Rsp) \
+
+#define ASSIGN_INTEGER_REGS \
+ ASSIGN_REG(Rdi) \
+ ASSIGN_REG(Rsi) \
+ ASSIGN_REG(Rbx) \
+ ASSIGN_REG(Rdx) \
+ ASSIGN_REG(Rcx) \
+ ASSIGN_REG(Rax) \
+ ASSIGN_REG(R8) \
+ ASSIGN_REG(R9) \
+ ASSIGN_REG(R10) \
+ ASSIGN_REG(R11) \
+ ASSIGN_REG(R12) \
+ ASSIGN_REG(R13) \
+ ASSIGN_REG(R14) \
+ ASSIGN_REG(R15) \
+
+#elif defined(_X86_)
+#define ASSIGN_CONTROL_REGS \
+ ASSIGN_REG(Ebp) \
+ ASSIGN_REG(Eip) \
+ ASSIGN_REG(SegCs) \
+ ASSIGN_REG(EFlags) \
+ ASSIGN_REG(Esp) \
+ ASSIGN_REG(SegSs) \
+
+#define ASSIGN_INTEGER_REGS \
+ ASSIGN_REG(Edi) \
+ ASSIGN_REG(Esi) \
+ ASSIGN_REG(Ebx) \
+ ASSIGN_REG(Edx) \
+ ASSIGN_REG(Ecx) \
+ ASSIGN_REG(Eax) \
+
+#elif defined(_ARM_)
+#define ASSIGN_CONTROL_REGS \
+ ASSIGN_REG(Sp) \
+ ASSIGN_REG(Lr) \
+ ASSIGN_REG(Pc) \
+ ASSIGN_REG(Cpsr) \
+
+#define ASSIGN_INTEGER_REGS \
+ ASSIGN_REG(R0) \
+ ASSIGN_REG(R1) \
+ ASSIGN_REG(R2) \
+ ASSIGN_REG(R3) \
+ ASSIGN_REG(R4) \
+ ASSIGN_REG(R5) \
+ ASSIGN_REG(R6) \
+ ASSIGN_REG(R7) \
+ ASSIGN_REG(R8) \
+ ASSIGN_REG(R9) \
+ ASSIGN_REG(R10) \
+ ASSIGN_REG(R11) \
+ ASSIGN_REG(R12)
+#elif defined(_ARM64_)
+#define ASSIGN_CONTROL_REGS \
+ ASSIGN_REG(Sp) \
+ ASSIGN_REG(Lr) \
+ ASSIGN_REG(Pc)
+
+#define ASSIGN_INTEGER_REGS \
+ ASSIGN_REG(X0) \
+ ASSIGN_REG(X1) \
+ ASSIGN_REG(X2) \
+ ASSIGN_REG(X3) \
+ ASSIGN_REG(X4) \
+ ASSIGN_REG(X5) \
+ ASSIGN_REG(X6) \
+ ASSIGN_REG(X7) \
+ ASSIGN_REG(X8) \
+ ASSIGN_REG(X9) \
+ ASSIGN_REG(X10) \
+ ASSIGN_REG(X11) \
+ ASSIGN_REG(X12) \
+ ASSIGN_REG(X13) \
+ ASSIGN_REG(X14) \
+ ASSIGN_REG(X15) \
+ ASSIGN_REG(X16) \
+ ASSIGN_REG(X17) \
+ ASSIGN_REG(X18) \
+ ASSIGN_REG(X19) \
+ ASSIGN_REG(X20) \
+ ASSIGN_REG(X21) \
+ ASSIGN_REG(X22) \
+ ASSIGN_REG(X23) \
+ ASSIGN_REG(X24) \
+ ASSIGN_REG(X25) \
+ ASSIGN_REG(X26) \
+ ASSIGN_REG(X27) \
+ ASSIGN_REG(X28)
+
+#else
+#error Don't know how to assign registers on this architecture
+#endif
+
+#define ASSIGN_ALL_REGS \
+ ASSIGN_CONTROL_REGS \
+ ASSIGN_INTEGER_REGS \
+
+/*++
+Function:
+ CONTEXT_GetRegisters
+
+Abstract
+ retrieve the machine registers value of the indicated process.
+
+Parameter
+ processId: process ID
+ lpContext: context structure in which the machine registers value will be returned.
+Return
+ returns TRUE if it succeeds, FALSE otherwise
+--*/
+BOOL CONTEXT_GetRegisters(DWORD processId, LPCONTEXT lpContext)
+{
+#if HAVE_BSD_REGS_T
+ int regFd = -1;
+#endif // HAVE_BSD_REGS_T
+ BOOL bRet = FALSE;
+
+ if (processId == GetCurrentProcessId())
+ {
+ CONTEXT_CaptureContext(lpContext);
+ }
+ else
+ {
+ ucontext_t registers;
+#if HAVE_PT_REGS
+ struct pt_regs ptrace_registers;
+ if (ptrace((__ptrace_request)PT_GETREGS, processId, (caddr_t) &ptrace_registers, 0) == -1)
+#elif HAVE_BSD_REGS_T
+ struct reg ptrace_registers;
+ if (PAL_PTRACE(PT_GETREGS, processId, &ptrace_registers, 0) == -1)
+#endif
+ {
+ ASSERT("Failed ptrace(PT_GETREGS, processId:%d) errno:%d (%s)\n",
+ processId, errno, strerror(errno));
+ }
+
+#if HAVE_PT_REGS
+#define ASSIGN_REG(reg) MCREG_##reg(registers.uc_mcontext) = PTREG_##reg(ptrace_registers);
+#elif HAVE_BSD_REGS_T
+#define ASSIGN_REG(reg) MCREG_##reg(registers.uc_mcontext) = BSDREG_##reg(ptrace_registers);
+#else
+#define ASSIGN_REG(reg)
+ ASSERT("Don't know how to get the context of another process on this platform!");
+ return bRet;
+#endif
+ ASSIGN_ALL_REGS
+#undef ASSIGN_REG
+
+ CONTEXTFromNativeContext(&registers, lpContext, lpContext->ContextFlags);
+ }
+
+ bRet = TRUE;
+#if HAVE_BSD_REGS_T
+ if (regFd != -1)
+ {
+ close(regFd);
+ }
+#endif // HAVE_BSD_REGS_T
+ return bRet;
+}
+
+/*++
+Function:
+ GetThreadContext
+
+See MSDN doc.
+--*/
+BOOL
+CONTEXT_GetThreadContext(
+ DWORD dwProcessId,
+ pthread_t self,
+ LPCONTEXT lpContext)
+{
+ BOOL ret = FALSE;
+
+ if (lpContext == NULL)
+ {
+ ERROR("Invalid lpContext parameter value\n");
+ SetLastError(ERROR_NOACCESS);
+ goto EXIT;
+ }
+
+ /* How to consider the case when self is different from the current
+ thread of its owner process. Machine registers values could be retreived
+ by a ptrace(pid, ...) call or from the "/proc/%pid/reg" file content.
+ Unfortunately, these two methods only depend on process ID, not on
+ thread ID. */
+
+ if (dwProcessId == GetCurrentProcessId())
+ {
+ if (self != pthread_self())
+ {
+ DWORD flags;
+ // There aren't any APIs for this. We can potentially get the
+ // context of another thread by using per-thread signals, but
+ // on FreeBSD signal handlers that are called as a result
+ // of signals raised via pthread_kill don't get a valid
+ // sigcontext or ucontext_t. But we need this to return TRUE
+ // to avoid an assertion in the CLR in code that manages to
+ // cope reasonably well without a valid thread context.
+ // Given that, we'll zero out our structure and return TRUE.
+ ERROR("GetThreadContext on a thread other than the current "
+ "thread is returning TRUE\n");
+ flags = lpContext->ContextFlags;
+ memset(lpContext, 0, sizeof(*lpContext));
+ lpContext->ContextFlags = flags;
+ ret = TRUE;
+ goto EXIT;
+ }
+
+ }
+
+ if (lpContext->ContextFlags &
+ (CONTEXT_CONTROL | CONTEXT_INTEGER))
+ {
+ if (CONTEXT_GetRegisters(dwProcessId, lpContext) == FALSE)
+ {
+ SetLastError(ERROR_INTERNAL_ERROR);
+ goto EXIT;
+ }
+ }
+
+ ret = TRUE;
+
+EXIT:
+ return ret;
+}
+
+/*++
+Function:
+ SetThreadContext
+
+See MSDN doc.
+--*/
+BOOL
+CONTEXT_SetThreadContext(
+ DWORD dwProcessId,
+ pthread_t self,
+ CONST CONTEXT *lpContext)
+{
+ BOOL ret = FALSE;
+
+#if HAVE_PT_REGS
+ struct pt_regs ptrace_registers;
+#elif HAVE_BSD_REGS_T
+ struct reg ptrace_registers;
+#endif
+
+ if (lpContext == NULL)
+ {
+ ERROR("Invalid lpContext parameter value\n");
+ SetLastError(ERROR_NOACCESS);
+ goto EXIT;
+ }
+
+ /* How to consider the case when self is different from the current
+ thread of its owner process. Machine registers values could be retreived
+ by a ptrace(pid, ...) call or from the "/proc/%pid/reg" file content.
+ Unfortunately, these two methods only depend on process ID, not on
+ thread ID. */
+
+ if (dwProcessId == GetCurrentProcessId())
+ {
+#ifdef FEATURE_PAL_SXS
+ // Need to implement SetThreadContext(current thread) for the IX architecture; look at common_signal_handler.
+ _ASSERT(FALSE);
+#endif // FEATURE_PAL_SXS
+ ASSERT("SetThreadContext should be called for cross-process only.\n");
+ SetLastError(ERROR_INVALID_PARAMETER);
+ goto EXIT;
+ }
+
+ if (lpContext->ContextFlags &
+ (CONTEXT_CONTROL | CONTEXT_INTEGER))
+ {
+#if HAVE_PT_REGS
+ if (ptrace((__ptrace_request)PT_GETREGS, dwProcessId, (caddr_t)&ptrace_registers, 0) == -1)
+#elif HAVE_BSD_REGS_T
+ if (PAL_PTRACE(PT_GETREGS, dwProcessId, &ptrace_registers, 0) == -1)
+#endif
+ {
+ ASSERT("Failed ptrace(PT_GETREGS, processId:%d) errno:%d (%s)\n",
+ dwProcessId, errno, strerror(errno));
+ SetLastError(ERROR_INTERNAL_ERROR);
+ goto EXIT;
+ }
+
+#if HAVE_PT_REGS
+#define ASSIGN_REG(reg) PTREG_##reg(ptrace_registers) = lpContext->reg;
+#elif HAVE_BSD_REGS_T
+#define ASSIGN_REG(reg) BSDREG_##reg(ptrace_registers) = lpContext->reg;
+#else
+#define ASSIGN_REG(reg)
+ ASSERT("Don't know how to set the context of another process on this platform!");
+ return FALSE;
+#endif
+ if (lpContext->ContextFlags & CONTEXT_CONTROL)
+ {
+ ASSIGN_CONTROL_REGS
+ }
+ if (lpContext->ContextFlags & CONTEXT_INTEGER)
+ {
+ ASSIGN_INTEGER_REGS
+ }
+#undef ASSIGN_REG
+
+#if HAVE_PT_REGS
+ if (ptrace((__ptrace_request)PT_SETREGS, dwProcessId, (caddr_t)&ptrace_registers, 0) == -1)
+#elif HAVE_BSD_REGS_T
+ if (PAL_PTRACE(PT_SETREGS, dwProcessId, &ptrace_registers, 0) == -1)
+#endif
+ {
+ ASSERT("Failed ptrace(PT_SETREGS, processId:%d) errno:%d (%s)\n",
+ dwProcessId, errno, strerror(errno));
+ SetLastError(ERROR_INTERNAL_ERROR);
+ goto EXIT;
+ }
+ }
+
+ ret = TRUE;
+ EXIT:
+ return ret;
+}
+
+/*++
+Function :
+ CONTEXTToNativeContext
+
+ Converts a CONTEXT record to a native context.
+
+Parameters :
+ CONST CONTEXT *lpContext : CONTEXT to convert
+ native_context_t *native : native context to fill in
+
+Return value :
+ None
+
+--*/
+void CONTEXTToNativeContext(CONST CONTEXT *lpContext, native_context_t *native)
+{
+#define ASSIGN_REG(reg) MCREG_##reg(native->uc_mcontext) = lpContext->reg;
+ if ((lpContext->ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL)
+ {
+ ASSIGN_CONTROL_REGS
+ }
+
+ if ((lpContext->ContextFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER)
+ {
+ ASSIGN_INTEGER_REGS
+ }
+#undef ASSIGN_REG
+
+#if HAVE_GREGSET_T || HAVE_GREGSET_T
+#if HAVE_GREGSET_T
+ if (native->uc_mcontext.fpregs == nullptr)
+#elif HAVE___GREGSET_T
+ if (native->uc_mcontext.__fpregs == nullptr)
+#endif
+ {
+ // If the pointer to the floating point state in the native context
+ // is not valid, we can't copy floating point registers regardless of
+ // whether CONTEXT_FLOATING_POINT is set in the CONTEXT's flags.
+ return;
+ }
+#endif
+
+ if ((lpContext->ContextFlags & CONTEXT_FLOATING_POINT) == CONTEXT_FLOATING_POINT)
+ {
+#ifdef _AMD64_
+ FPREG_ControlWord(native) = lpContext->FltSave.ControlWord;
+ FPREG_StatusWord(native) = lpContext->FltSave.StatusWord;
+ FPREG_TagWord(native) = lpContext->FltSave.TagWord;
+ FPREG_ErrorOffset(native) = lpContext->FltSave.ErrorOffset;
+ FPREG_ErrorSelector(native) = lpContext->FltSave.ErrorSelector;
+ FPREG_DataOffset(native) = lpContext->FltSave.DataOffset;
+ FPREG_DataSelector(native) = lpContext->FltSave.DataSelector;
+ FPREG_MxCsr(native) = lpContext->FltSave.MxCsr;
+ FPREG_MxCsr_Mask(native) = lpContext->FltSave.MxCsr_Mask;
+
+ for (int i = 0; i < 8; i++)
+ {
+ FPREG_St(native, i) = lpContext->FltSave.FloatRegisters[i];
+ }
+
+ for (int i = 0; i < 16; i++)
+ {
+ FPREG_Xmm(native, i) = lpContext->FltSave.XmmRegisters[i];
+ }
+#endif
+ }
+
+ // TODO: Enable for all Unix systems
+#if defined(_AMD64_) && defined(__linux__)
+ if ((lpContext->ContextFlags & CONTEXT_XSTATE) == CONTEXT_XSTATE)
+ {
+ _ASSERTE(FPREG_HasExtendedState(native));
+ memcpy_s(FPREG_Xstate_Ymmh(native), sizeof(M128A) * 16, lpContext->VectorRegister, sizeof(M128A) * 16);
+ }
+#endif // _AMD64_
+}
+
+/*++
+Function :
+ CONTEXTFromNativeContext
+
+ Converts a native context to a CONTEXT record.
+
+Parameters :
+ const native_context_t *native : native context to convert
+ LPCONTEXT lpContext : CONTEXT to fill in
+ ULONG contextFlags : flags that determine which registers are valid in
+ native and which ones to set in lpContext
+
+Return value :
+ None
+
+--*/
+void CONTEXTFromNativeContext(const native_context_t *native, LPCONTEXT lpContext,
+ ULONG contextFlags)
+{
+ lpContext->ContextFlags = contextFlags;
+
+#define ASSIGN_REG(reg) lpContext->reg = MCREG_##reg(native->uc_mcontext);
+ if ((contextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL)
+ {
+ ASSIGN_CONTROL_REGS
+#ifdef _ARM_
+ // WinContext assumes that the least bit of Pc is always 1 (denoting thumb)
+ // although the pc value retrived from native context might not have set the least bit.
+ // This becomes especially problematic if the context is on the JIT_WRITEBARRIER.
+ lpContext->Pc |= 0x1;
+#endif
+ }
+
+ if ((contextFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER)
+ {
+ ASSIGN_INTEGER_REGS
+ }
+#undef ASSIGN_REG
+
+#if HAVE_GREGSET_T || HAVE___GREGSET_T
+#if HAVE_GREGSET_T
+ if (native->uc_mcontext.fpregs == nullptr)
+#elif HAVE___GREGSET_T
+ if (native->uc_mcontext.__fpregs == nullptr)
+#endif
+ {
+ // Reset the CONTEXT_FLOATING_POINT bit(s) and the CONTEXT_XSTATE bit(s) so it's
+ // clear that the floating point and extended state data in the CONTEXT is not
+ // valid. Since these flags are defined as the architecture bit(s) OR'd with one
+ // or more other bits, we first get the bits that are unique to each by resetting
+ // the architecture bits. We determine what those are by inverting the union of
+ // CONTEXT_CONTROL and CONTEXT_INTEGER, both of which should also have the
+ // architecture bit(s) set.
+ const ULONG floatingPointFlags = CONTEXT_FLOATING_POINT & ~(CONTEXT_CONTROL & CONTEXT_INTEGER);
+ const ULONG xstateFlags = CONTEXT_XSTATE & ~(CONTEXT_CONTROL & CONTEXT_INTEGER);
+
+ lpContext->ContextFlags &= ~(floatingPointFlags | xstateFlags);
+
+ // Bail out regardless of whether the caller wanted CONTEXT_FLOATING_POINT or CONTEXT_XSTATE
+ return;
+ }
+#endif
+
+ if ((contextFlags & CONTEXT_FLOATING_POINT) == CONTEXT_FLOATING_POINT)
+ {
+#ifdef _AMD64_
+ lpContext->FltSave.ControlWord = FPREG_ControlWord(native);
+ lpContext->FltSave.StatusWord = FPREG_StatusWord(native);
+ lpContext->FltSave.TagWord = FPREG_TagWord(native);
+ lpContext->FltSave.ErrorOffset = FPREG_ErrorOffset(native);
+ lpContext->FltSave.ErrorSelector = FPREG_ErrorSelector(native);
+ lpContext->FltSave.DataOffset = FPREG_DataOffset(native);
+ lpContext->FltSave.DataSelector = FPREG_DataSelector(native);
+ lpContext->FltSave.MxCsr = FPREG_MxCsr(native);
+ lpContext->FltSave.MxCsr_Mask = FPREG_MxCsr_Mask(native);
+
+ for (int i = 0; i < 8; i++)
+ {
+ lpContext->FltSave.FloatRegisters[i] = FPREG_St(native, i);
+ }
+
+ for (int i = 0; i < 16; i++)
+ {
+ lpContext->FltSave.XmmRegisters[i] = FPREG_Xmm(native, i);
+ }
+#endif
+ }
+
+ // TODO: Enable for all Unix systems
+#if defined(_AMD64_) && defined(__linux__)
+ if ((contextFlags & CONTEXT_XSTATE) == CONTEXT_XSTATE)
+ {
+ if (FPREG_HasExtendedState(native))
+ {
+ memcpy_s(lpContext->VectorRegister, sizeof(M128A) * 16, FPREG_Xstate_Ymmh(native), sizeof(M128A) * 16);
+ }
+ else
+ {
+ // Reset the CONTEXT_XSTATE bit(s) so it's clear that the extended state data in
+ // the CONTEXT is not valid.
+ const ULONG xstateFlags = CONTEXT_XSTATE & ~(CONTEXT_CONTROL & CONTEXT_INTEGER);
+ lpContext->ContextFlags &= ~xstateFlags;
+ }
+ }
+#endif // _AMD64_
+}
+
+/*++
+Function :
+ GetNativeContextPC
+
+ Returns the program counter from the native context.
+
+Parameters :
+ const native_context_t *native : native context
+
+Return value :
+ The program counter from the native context.
+
+--*/
+LPVOID GetNativeContextPC(const native_context_t *context)
+{
+#ifdef _AMD64_
+ return (LPVOID)MCREG_Rip(context->uc_mcontext);
+#elif defined(_X86_)
+ return (LPVOID) MCREG_Eip(context->uc_mcontext);
+#elif defined(_ARM_)
+ return (LPVOID) MCREG_Pc(context->uc_mcontext);
+#elif defined(_ARM64_)
+ return (LPVOID) MCREG_Pc(context->uc_mcontext);
+#else
+# error implement me for this architecture
+#endif
+}
+
+/*++
+Function :
+ CONTEXTGetExceptionCodeForSignal
+
+ Translates signal and context information to a Win32 exception code.
+
+Parameters :
+ const siginfo_t *siginfo : signal information from a signal handler
+ const native_context_t *context : context information
+
+Return value :
+ The Win32 exception code that corresponds to the signal and context
+ information.
+
+--*/
+#ifdef ILL_ILLOPC
+// If si_code values are available for all signals, use those.
+DWORD CONTEXTGetExceptionCodeForSignal(const siginfo_t *siginfo,
+ const native_context_t *context)
+{
+ // IMPORTANT NOTE: This function must not call any signal unsafe functions
+ // since it is called from signal handlers.
+ // That includes ASSERT and TRACE macros.
+
+ switch (siginfo->si_signo)
+ {
+ case SIGILL:
+ switch (siginfo->si_code)
+ {
+ case ILL_ILLOPC: // Illegal opcode
+ case ILL_ILLOPN: // Illegal operand
+ case ILL_ILLADR: // Illegal addressing mode
+ case ILL_ILLTRP: // Illegal trap
+ case ILL_COPROC: // Co-processor error
+ return EXCEPTION_ILLEGAL_INSTRUCTION;
+ case ILL_PRVOPC: // Privileged opcode
+ case ILL_PRVREG: // Privileged register
+ return EXCEPTION_PRIV_INSTRUCTION;
+ case ILL_BADSTK: // Internal stack error
+ return EXCEPTION_STACK_OVERFLOW;
+ default:
+ break;
+ }
+ break;
+ case SIGFPE:
+ switch (siginfo->si_code)
+ {
+ case FPE_INTDIV:
+ return EXCEPTION_INT_DIVIDE_BY_ZERO;
+ case FPE_INTOVF:
+ return EXCEPTION_INT_OVERFLOW;
+ case FPE_FLTDIV:
+ return EXCEPTION_FLT_DIVIDE_BY_ZERO;
+ case FPE_FLTOVF:
+ return EXCEPTION_FLT_OVERFLOW;
+ case FPE_FLTUND:
+ return EXCEPTION_FLT_UNDERFLOW;
+ case FPE_FLTRES:
+ return EXCEPTION_FLT_INEXACT_RESULT;
+ case FPE_FLTINV:
+ return EXCEPTION_FLT_INVALID_OPERATION;
+ case FPE_FLTSUB:
+ return EXCEPTION_FLT_INVALID_OPERATION;
+ default:
+ break;
+ }
+ break;
+ case SIGSEGV:
+ switch (siginfo->si_code)
+ {
+ case SI_USER: // User-generated signal, sometimes sent
+ // for SIGSEGV under normal circumstances
+ case SEGV_MAPERR: // Address not mapped to object
+ case SEGV_ACCERR: // Invalid permissions for mapped object
+ return EXCEPTION_ACCESS_VIOLATION;
+
+#ifdef SI_KERNEL
+ case SI_KERNEL:
+ {
+ // Identify privileged instructions that are not identified as such by the system
+ if (g_getGcMarkerExceptionCode != nullptr)
+ {
+ DWORD exceptionCode = g_getGcMarkerExceptionCode(GetNativeContextPC(context));
+ if (exceptionCode != 0)
+ {
+ return exceptionCode;
+ }
+ }
+ return EXCEPTION_ACCESS_VIOLATION;
+ }
+#endif
+ default:
+ break;
+ }
+ break;
+ case SIGBUS:
+ switch (siginfo->si_code)
+ {
+ case BUS_ADRALN: // Invalid address alignment
+ return EXCEPTION_DATATYPE_MISALIGNMENT;
+ case BUS_ADRERR: // Non-existent physical address
+ return EXCEPTION_ACCESS_VIOLATION;
+ case BUS_OBJERR: // Object-specific hardware error
+ default:
+ break;
+ }
+ case SIGTRAP:
+ switch (siginfo->si_code)
+ {
+#ifdef SI_KERNEL
+ case SI_KERNEL:
+#endif
+ case SI_USER:
+ case TRAP_BRKPT: // Process breakpoint
+ return EXCEPTION_BREAKPOINT;
+ case TRAP_TRACE: // Process trace trap
+ return EXCEPTION_SINGLE_STEP;
+ default:
+ // Got unknown SIGTRAP signal with code siginfo->si_code;
+ return EXCEPTION_ILLEGAL_INSTRUCTION;
+ }
+ default:
+ break;
+ }
+
+ // Got unknown signal number siginfo->si_signo with code siginfo->si_code;
+ return EXCEPTION_ILLEGAL_INSTRUCTION;
+}
+#else // ILL_ILLOPC
+DWORD CONTEXTGetExceptionCodeForSignal(const siginfo_t *siginfo,
+ const native_context_t *context)
+{
+ // IMPORTANT NOTE: This function must not call any signal unsafe functions
+ // since it is called from signal handlers.
+ // That includes ASSERT and TRACE macros.
+
+ int trap;
+
+ if (siginfo->si_signo == SIGFPE)
+ {
+ // Floating point exceptions are mapped by their si_code.
+ switch (siginfo->si_code)
+ {
+ case FPE_INTDIV :
+ return EXCEPTION_INT_DIVIDE_BY_ZERO;
+ case FPE_INTOVF :
+ return EXCEPTION_INT_OVERFLOW;
+ case FPE_FLTDIV :
+ return EXCEPTION_FLT_DIVIDE_BY_ZERO;
+ case FPE_FLTOVF :
+ return EXCEPTION_FLT_OVERFLOW;
+ case FPE_FLTUND :
+ return EXCEPTION_FLT_UNDERFLOW;
+ case FPE_FLTRES :
+ return EXCEPTION_FLT_INEXACT_RESULT;
+ case FPE_FLTINV :
+ return EXCEPTION_FLT_INVALID_OPERATION;
+ case FPE_FLTSUB :/* subscript out of range */
+ return EXCEPTION_FLT_INVALID_OPERATION;
+ default:
+ // Got unknown signal code siginfo->si_code;
+ return 0;
+ }
+ }
+
+ trap = context->uc_mcontext.mc_trapno;
+ switch (trap)
+ {
+ case T_PRIVINFLT : /* privileged instruction */
+ return EXCEPTION_PRIV_INSTRUCTION;
+ case T_BPTFLT : /* breakpoint instruction */
+ return EXCEPTION_BREAKPOINT;
+ case T_ARITHTRAP : /* arithmetic trap */
+ return 0; /* let the caller pick an exception code */
+#ifdef T_ASTFLT
+ case T_ASTFLT : /* system forced exception : ^C, ^\. SIGINT signal
+ handler shouldn't be calling this function, since
+ it doesn't need an exception code */
+ // Trap code T_ASTFLT received, shouldn't get here;
+ return 0;
+#endif // T_ASTFLT
+ case T_PROTFLT : /* protection fault */
+ return EXCEPTION_ACCESS_VIOLATION;
+ case T_TRCTRAP : /* debug exception (sic) */
+ return EXCEPTION_SINGLE_STEP;
+ case T_PAGEFLT : /* page fault */
+ return EXCEPTION_ACCESS_VIOLATION;
+ case T_ALIGNFLT : /* alignment fault */
+ return EXCEPTION_DATATYPE_MISALIGNMENT;
+ case T_DIVIDE :
+ return EXCEPTION_INT_DIVIDE_BY_ZERO;
+ case T_NMI : /* non-maskable trap */
+ return EXCEPTION_ILLEGAL_INSTRUCTION;
+ case T_OFLOW :
+ return EXCEPTION_INT_OVERFLOW;
+ case T_BOUND : /* bound instruction fault */
+ return EXCEPTION_ARRAY_BOUNDS_EXCEEDED;
+ case T_DNA : /* device not available fault */
+ return EXCEPTION_ILLEGAL_INSTRUCTION;
+ case T_DOUBLEFLT : /* double fault */
+ return EXCEPTION_ILLEGAL_INSTRUCTION;
+ case T_FPOPFLT : /* fp coprocessor operand fetch fault */
+ return EXCEPTION_FLT_INVALID_OPERATION;
+ case T_TSSFLT : /* invalid tss fault */
+ return EXCEPTION_ILLEGAL_INSTRUCTION;
+ case T_SEGNPFLT : /* segment not present fault */
+ return EXCEPTION_ACCESS_VIOLATION;
+ case T_STKFLT : /* stack fault */
+ return EXCEPTION_STACK_OVERFLOW;
+ case T_MCHK : /* machine check trap */
+ return EXCEPTION_ILLEGAL_INSTRUCTION;
+ case T_RESERVED : /* reserved (unknown) */
+ return EXCEPTION_ILLEGAL_INSTRUCTION;
+ default:
+ // Got unknown trap code trap;
+ break;
+ }
+ return EXCEPTION_ILLEGAL_INSTRUCTION;
+}
+#endif // ILL_ILLOPC
+
+#else // !HAVE_MACH_EXCEPTIONS
+
+#include <mach/message.h>
+#include <mach/thread_act.h>
+#include "../exception/machexception.h"
+
+/*++
+Function:
+ CONTEXT_GetThreadContextFromPort
+
+ Helper for GetThreadContext that uses a mach_port
+--*/
+kern_return_t
+CONTEXT_GetThreadContextFromPort(
+ mach_port_t Port,
+ LPCONTEXT lpContext)
+{
+ // Extract the CONTEXT from the Mach thread.
+
+ kern_return_t MachRet = KERN_SUCCESS;
+ mach_msg_type_number_t StateCount;
+ thread_state_flavor_t StateFlavor;
+
+ if (lpContext->ContextFlags & (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS))
+ {
+#ifdef _X86_
+ x86_thread_state32_t State;
+ StateFlavor = x86_THREAD_STATE32;
+#elif defined(_AMD64_)
+ x86_thread_state64_t State;
+ StateFlavor = x86_THREAD_STATE64;
+#else
+#error Unexpected architecture.
+#endif
+ StateCount = sizeof(State) / sizeof(natural_t);
+ MachRet = thread_get_state(Port, StateFlavor, (thread_state_t)&State, &StateCount);
+ if (MachRet != KERN_SUCCESS)
+ {
+ ASSERT("thread_get_state(THREAD_STATE) failed: %d\n", MachRet);
+ goto exit;
+ }
+
+ CONTEXT_GetThreadContextFromThreadState(StateFlavor, (thread_state_t)&State, lpContext);
+ }
+
+ if (lpContext->ContextFlags & CONTEXT_ALL_FLOATING) {
+#ifdef _X86_
+ x86_float_state32_t State;
+ StateFlavor = x86_FLOAT_STATE32;
+#elif defined(_AMD64_)
+ x86_float_state64_t State;
+ StateFlavor = x86_FLOAT_STATE64;
+#else
+#error Unexpected architecture.
+#endif
+ StateCount = sizeof(State) / sizeof(natural_t);
+ MachRet = thread_get_state(Port, StateFlavor, (thread_state_t)&State, &StateCount);
+ if (MachRet != KERN_SUCCESS)
+ {
+ ASSERT("thread_get_state(FLOAT_STATE) failed: %d\n", MachRet);
+ goto exit;
+ }
+
+ CONTEXT_GetThreadContextFromThreadState(StateFlavor, (thread_state_t)&State, lpContext);
+ }
+
+exit:
+ return MachRet;
+}
+
+/*++
+Function:
+ CONTEXT_GetThreadContextFromThreadState
+
+--*/
+void
+CONTEXT_GetThreadContextFromThreadState(
+ thread_state_flavor_t threadStateFlavor,
+ thread_state_t threadState,
+ LPCONTEXT lpContext)
+{
+ switch (threadStateFlavor)
+ {
+#ifdef _X86_
+ case x86_THREAD_STATE32:
+ if (lpContext->ContextFlags & (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS))
+ {
+ x86_thread_state32_t *pState = (x86_thread_state32_t *)threadState;
+
+ lpContext->Eax = pState->eax;
+ lpContext->Ebx = pState->ebx;
+ lpContext->Ecx = pState->ecx;
+ lpContext->Edx = pState->edx;
+ lpContext->Edi = pState->edi;
+ lpContext->Esi = pState->esi;
+ lpContext->Ebp = pState->ebp;
+ lpContext->Esp = pState->esp;
+ lpContext->SegSs = pState->ss;
+ lpContext->EFlags = pState->eflags;
+ lpContext->Eip = pState->eip;
+ lpContext->SegCs = pState->cs;
+ lpContext->SegDs_PAL_Undefined = pState->ds;
+ lpContext->SegEs_PAL_Undefined = pState->es;
+ lpContext->SegFs_PAL_Undefined = pState->fs;
+ lpContext->SegGs_PAL_Undefined = pState->gs;
+ }
+ break;
+
+ case x86_FLOAT_STATE32:
+ {
+ x86_float_state32_t *pState = (x86_float_state32_t *)threadState;
+
+ if (lpContext->ContextFlags & CONTEXT_FLOATING_POINT)
+ {
+ lpContext->FloatSave.ControlWord = *(DWORD*)&pState->fpu_fcw;
+ lpContext->FloatSave.StatusWord = *(DWORD*)&pState->fpu_fsw;
+ lpContext->FloatSave.TagWord = pState->fpu_ftw;
+ lpContext->FloatSave.ErrorOffset = pState->fpu_ip;
+ lpContext->FloatSave.ErrorSelector = pState->fpu_cs;
+ lpContext->FloatSave.DataOffset = pState->fpu_dp;
+ lpContext->FloatSave.DataSelector = pState->fpu_ds;
+ lpContext->FloatSave.Cr0NpxState = pState->fpu_mxcsr;
+
+ // Windows stores the floating point registers in a packed layout (each 10-byte register end to end
+ // for a total of 80 bytes). But Mach returns each register in an 16-bit structure (presumably for
+ // alignment purposes). So we can't just memcpy the registers over in a single block, we need to copy
+ // them individually.
+ for (int i = 0; i < 8; i++)
+ memcpy(&lpContext->FloatSave.RegisterArea[i * 10], (&pState->fpu_stmm0)[i].mmst_reg, 10);
+ }
+
+ if (lpContext->ContextFlags & CONTEXT_EXTENDED_REGISTERS)
+ {
+ // The only extended register information that Mach will tell us about are the xmm register values.
+ // Both Windows and Mach store the registers in a packed layout (each of the 8 registers is 16 bytes)
+ // so we can simply memcpy them across.
+ memcpy(lpContext->ExtendedRegisters + CONTEXT_EXREG_XMM_OFFSET, &pState->fpu_xmm0, 8 * 16);
+ }
+ }
+ break;
+
+#elif defined(_AMD64_)
+ case x86_THREAD_STATE64:
+ if (lpContext->ContextFlags & (CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_SEGMENTS))
+ {
+ x86_thread_state64_t *pState = (x86_thread_state64_t *)threadState;
+
+ lpContext->Rax = pState->__rax;
+ lpContext->Rbx = pState->__rbx;
+ lpContext->Rcx = pState->__rcx;
+ lpContext->Rdx = pState->__rdx;
+ lpContext->Rdi = pState->__rdi;
+ lpContext->Rsi = pState->__rsi;
+ lpContext->Rbp = pState->__rbp;
+ lpContext->Rsp = pState->__rsp;
+ lpContext->R8 = pState->__r8;
+ lpContext->R9 = pState->__r9;
+ lpContext->R10 = pState->__r10;
+ lpContext->R11 = pState->__r11;
+ lpContext->R12 = pState->__r12;
+ lpContext->R13 = pState->__r13;
+ lpContext->R14 = pState->__r14;
+ lpContext->R15 = pState->__r15;
+ lpContext->EFlags = pState->__rflags;
+ lpContext->Rip = pState->__rip;
+ lpContext->SegCs = pState->__cs;
+ // RtlRestoreContext uses the actual ss instead of this one
+ // to build the iret frame so just set it zero.
+ lpContext->SegSs = 0;
+ lpContext->SegDs = 0;
+ lpContext->SegEs = 0;
+ lpContext->SegFs = pState->__fs;
+ lpContext->SegGs = pState->__gs;
+ }
+ break;
+
+ case x86_FLOAT_STATE64:
+ if (lpContext->ContextFlags & CONTEXT_FLOATING_POINT)
+ {
+ x86_float_state64_t *pState = (x86_float_state64_t *)threadState;
+
+ lpContext->FltSave.ControlWord = *(DWORD*)&pState->__fpu_fcw;
+ lpContext->FltSave.StatusWord = *(DWORD*)&pState->__fpu_fsw;
+ lpContext->FltSave.TagWord = pState->__fpu_ftw;
+ lpContext->FltSave.ErrorOffset = pState->__fpu_ip;
+ lpContext->FltSave.ErrorSelector = pState->__fpu_cs;
+ lpContext->FltSave.DataOffset = pState->__fpu_dp;
+ lpContext->FltSave.DataSelector = pState->__fpu_ds;
+ lpContext->FltSave.MxCsr = pState->__fpu_mxcsr;
+ lpContext->FltSave.MxCsr_Mask = pState->__fpu_mxcsrmask; // note: we don't save the mask for x86
+
+ // Windows stores the floating point registers in a packed layout (each 10-byte register end to end
+ // for a total of 80 bytes). But Mach returns each register in an 16-bit structure (presumably for
+ // alignment purposes). So we can't just memcpy the registers over in a single block, we need to copy
+ // them individually.
+ for (int i = 0; i < 8; i++)
+ memcpy(&lpContext->FltSave.FloatRegisters[i], (&pState->__fpu_stmm0)[i].__mmst_reg, 10);
+
+ // AMD64's FLOATING_POINT includes the xmm registers.
+ memcpy(&lpContext->Xmm0, &pState->__fpu_xmm0, 8 * 16);
+ }
+ break;
+#else
+#error Unexpected architecture.
+#endif
+ case x86_THREAD_STATE:
+ {
+ x86_thread_state_t *pState = (x86_thread_state_t *)threadState;
+ CONTEXT_GetThreadContextFromThreadState((thread_state_flavor_t)pState->tsh.flavor, (thread_state_t)&pState->uts, lpContext);
+ }
+ break;
+
+ case x86_FLOAT_STATE:
+ {
+ x86_float_state_t *pState = (x86_float_state_t *)threadState;
+ CONTEXT_GetThreadContextFromThreadState((thread_state_flavor_t)pState->fsh.flavor, (thread_state_t)&pState->ufs, lpContext);
+ }
+ break;
+
+ default:
+ ASSERT("Invalid thread state flavor %d\n", threadStateFlavor);
+ break;
+ }
+}
+
+/*++
+Function:
+ GetThreadContext
+
+See MSDN doc.
+--*/
+BOOL
+CONTEXT_GetThreadContext(
+ DWORD dwProcessId,
+ pthread_t self,
+ LPCONTEXT lpContext)
+{
+ BOOL ret = FALSE;
+
+ if (lpContext == NULL)
+ {
+ ERROR("Invalid lpContext parameter value\n");
+ SetLastError(ERROR_NOACCESS);
+ goto EXIT;
+ }
+
+ if (GetCurrentProcessId() == dwProcessId)
+ {
+ if (self != pthread_self())
+ {
+ // the target thread is in the current process, but isn't
+ // the current one: extract the CONTEXT from the Mach thread.
+ mach_port_t mptPort;
+ mptPort = pthread_mach_thread_np(self);
+
+ ret = (CONTEXT_GetThreadContextFromPort(mptPort, lpContext) == KERN_SUCCESS);
+ }
+ else
+ {
+ CONTEXT_CaptureContext(lpContext);
+ ret = TRUE;
+ }
+ }
+ else
+ {
+ ASSERT("Cross-process GetThreadContext() is not supported on this platform\n");
+ SetLastError(ERROR_NOACCESS);
+ }
+
+EXIT:
+ return ret;
+}
+
+/*++
+Function:
+ SetThreadContextOnPort
+
+ Helper for CONTEXT_SetThreadContext
+--*/
+kern_return_t
+CONTEXT_SetThreadContextOnPort(
+ mach_port_t Port,
+ IN CONST CONTEXT *lpContext)
+{
+ kern_return_t MachRet = KERN_SUCCESS;
+ mach_msg_type_number_t StateCount;
+ thread_state_flavor_t StateFlavor;
+
+ if (lpContext->ContextFlags & (CONTEXT_CONTROL|CONTEXT_INTEGER))
+ {
+#ifdef _X86_
+ x86_thread_state32_t State;
+ StateFlavor = x86_THREAD_STATE32;
+
+ State.eax = lpContext->Eax;
+ State.ebx = lpContext->Ebx;
+ State.ecx = lpContext->Ecx;
+ State.edx = lpContext->Edx;
+ State.edi = lpContext->Edi;
+ State.esi = lpContext->Esi;
+ State.ebp = lpContext->Ebp;
+ State.esp = lpContext->Esp;
+ State.ss = lpContext->SegSs;
+ State.eflags = lpContext->EFlags;
+ State.eip = lpContext->Eip;
+ State.cs = lpContext->SegCs;
+ State.ds = lpContext->SegDs_PAL_Undefined;
+ State.es = lpContext->SegEs_PAL_Undefined;
+ State.fs = lpContext->SegFs_PAL_Undefined;
+ State.gs = lpContext->SegGs_PAL_Undefined;
+#elif defined(_AMD64_)
+ x86_thread_state64_t State;
+ StateFlavor = x86_THREAD_STATE64;
+
+ State.__rax = lpContext->Rax;
+ State.__rbx = lpContext->Rbx;
+ State.__rcx = lpContext->Rcx;
+ State.__rdx = lpContext->Rdx;
+ State.__rdi = lpContext->Rdi;
+ State.__rsi = lpContext->Rsi;
+ State.__rbp = lpContext->Rbp;
+ State.__rsp = lpContext->Rsp;
+ State.__r8 = lpContext->R8;
+ State.__r9 = lpContext->R9;
+ State.__r10 = lpContext->R10;
+ State.__r11 = lpContext->R11;
+ State.__r12 = lpContext->R12;
+ State.__r13 = lpContext->R13;
+ State.__r14 = lpContext->R14;
+ State.__r15 = lpContext->R15;
+// State.ss = lpContext->SegSs;
+ State.__rflags = lpContext->EFlags;
+ State.__rip = lpContext->Rip;
+ State.__cs = lpContext->SegCs;
+// State.ds = lpContext->SegDs_PAL_Undefined;
+// State.es = lpContext->SegEs_PAL_Undefined;
+ State.__fs = lpContext->SegFs;
+ State.__gs = lpContext->SegGs;
+#else
+#error Unexpected architecture.
+#endif
+
+ StateCount = sizeof(State) / sizeof(natural_t);
+
+ MachRet = thread_set_state(Port,
+ StateFlavor,
+ (thread_state_t)&State,
+ StateCount);
+ if (MachRet != KERN_SUCCESS)
+ {
+ ASSERT("thread_set_state(THREAD_STATE) failed: %d\n", MachRet);
+ goto EXIT;
+ }
+ }
+
+ if (lpContext->ContextFlags & CONTEXT_ALL_FLOATING)
+ {
+
+#ifdef _X86_
+ x86_float_state32_t State;
+ StateFlavor = x86_FLOAT_STATE32;
+#elif defined(_AMD64_)
+ x86_float_state64_t State;
+ StateFlavor = x86_FLOAT_STATE64;
+#else
+#error Unexpected architecture.
+#endif
+
+ StateCount = sizeof(State) / sizeof(natural_t);
+
+ // If we're setting only one of the floating point or extended registers (of which Mach supports only
+ // the xmm values) then we don't have values for the other set. This is a problem since Mach only
+ // supports setting both groups as a single unit. So in this case we'll need to fetch the current
+ // values first.
+ if ((lpContext->ContextFlags & CONTEXT_ALL_FLOATING) !=
+ CONTEXT_ALL_FLOATING)
+ {
+ mach_msg_type_number_t StateCountGet = StateCount;
+ MachRet = thread_get_state(Port,
+ StateFlavor,
+ (thread_state_t)&State,
+ &StateCountGet);
+ if (MachRet != KERN_SUCCESS)
+ {
+ ASSERT("thread_get_state(FLOAT_STATE) failed: %d\n", MachRet);
+ goto EXIT;
+ }
+ _ASSERTE(StateCountGet == StateCount);
+ }
+
+ if (lpContext->ContextFlags & CONTEXT_FLOATING_POINT)
+ {
+#ifdef _X86_
+ *(DWORD*)&State.fpu_fcw = lpContext->FloatSave.ControlWord;
+ *(DWORD*)&State.fpu_fsw = lpContext->FloatSave.StatusWord;
+ State.fpu_ftw = lpContext->FloatSave.TagWord;
+ State.fpu_ip = lpContext->FloatSave.ErrorOffset;
+ State.fpu_cs = lpContext->FloatSave.ErrorSelector;
+ State.fpu_dp = lpContext->FloatSave.DataOffset;
+ State.fpu_ds = lpContext->FloatSave.DataSelector;
+ State.fpu_mxcsr = lpContext->FloatSave.Cr0NpxState;
+
+ // Windows stores the floating point registers in a packed layout (each 10-byte register end to
+ // end for a total of 80 bytes). But Mach returns each register in an 16-bit structure (presumably
+ // for alignment purposes). So we can't just memcpy the registers over in a single block, we need
+ // to copy them individually.
+ for (int i = 0; i < 8; i++)
+ memcpy((&State.fpu_stmm0)[i].mmst_reg, &lpContext->FloatSave.RegisterArea[i * 10], 10);
+#elif defined(_AMD64_)
+ *(DWORD*)&State.__fpu_fcw = lpContext->FltSave.ControlWord;
+ *(DWORD*)&State.__fpu_fsw = lpContext->FltSave.StatusWord;
+ State.__fpu_ftw = lpContext->FltSave.TagWord;
+ State.__fpu_ip = lpContext->FltSave.ErrorOffset;
+ State.__fpu_cs = lpContext->FltSave.ErrorSelector;
+ State.__fpu_dp = lpContext->FltSave.DataOffset;
+ State.__fpu_ds = lpContext->FltSave.DataSelector;
+ State.__fpu_mxcsr = lpContext->FltSave.MxCsr;
+ State.__fpu_mxcsrmask = lpContext->FltSave.MxCsr_Mask; // note: we don't save the mask for x86
+
+ // Windows stores the floating point registers in a packed layout (each 10-byte register end to
+ // end for a total of 80 bytes). But Mach returns each register in an 16-bit structure (presumably
+ // for alignment purposes). So we can't just memcpy the registers over in a single block, we need
+ // to copy them individually.
+ for (int i = 0; i < 8; i++)
+ memcpy((&State.__fpu_stmm0)[i].__mmst_reg, &lpContext->FltSave.FloatRegisters[i], 10);
+
+ memcpy(&State.__fpu_xmm0, &lpContext->Xmm0, 8 * 16);
+#else
+#error Unexpected architecture.
+#endif
+ }
+
+#ifdef _X86_
+ if (lpContext->ContextFlags & CONTEXT_EXTENDED_REGISTERS)
+ {
+ // The only extended register information that Mach will tell us about are the xmm register
+ // values. Both Windows and Mach store the registers in a packed layout (each of the 8 registers
+ // is 16 bytes) so we can simply memcpy them across.
+ memcpy(&State.fpu_xmm0, lpContext->ExtendedRegisters + CONTEXT_EXREG_XMM_OFFSET, 8 * 16);
+ }
+#endif // _X86_
+
+ MachRet = thread_set_state(Port,
+ StateFlavor,
+ (thread_state_t)&State,
+ StateCount);
+ if (MachRet != KERN_SUCCESS)
+ {
+ ASSERT("thread_set_state(FLOAT_STATE) failed: %d\n", MachRet);
+ goto EXIT;
+ }
+ }
+
+EXIT:
+ return MachRet;
+}
+
+/*++
+Function:
+ SetThreadContext
+
+See MSDN doc.
+--*/
+BOOL
+CONTEXT_SetThreadContext(
+ DWORD dwProcessId,
+ pthread_t self,
+ CONST CONTEXT *lpContext)
+{
+ BOOL ret = FALSE;
+
+ if (lpContext == NULL)
+ {
+ ERROR("Invalid lpContext parameter value\n");
+ SetLastError(ERROR_NOACCESS);
+ goto EXIT;
+ }
+
+ if (dwProcessId != GetCurrentProcessId())
+ {
+ // GetThreadContext() of a thread in another process
+ ASSERT("Cross-process GetThreadContext() is not supported\n");
+ SetLastError(ERROR_NOACCESS);
+ goto EXIT;
+ }
+
+ if (self != pthread_self())
+ {
+ // hThread is in the current process, but isn't the current
+ // thread. Extract the CONTEXT from the Mach thread.
+
+ mach_port_t mptPort;
+
+ mptPort = pthread_mach_thread_np(self);
+
+ ret = (CONTEXT_SetThreadContextOnPort(mptPort, lpContext) == KERN_SUCCESS);
+ }
+ else
+ {
+ MachSetThreadContext(const_cast<CONTEXT *>(lpContext));
+ ASSERT("MachSetThreadContext should never return\n");
+ }
+
+EXIT:
+ return ret;
+}
+
+#endif // !HAVE_MACH_EXCEPTIONS
+
+/*++
+Function:
+ DBG_FlushInstructionCache: processor-specific portion of
+ FlushInstructionCache
+
+See MSDN doc.
+--*/
+BOOL
+DBG_FlushInstructionCache(
+ IN LPCVOID lpBaseAddress,
+ IN SIZE_T dwSize)
+{
+ // Intrinsic should do the right thing across all platforms
+ __builtin___clear_cache((char *)lpBaseAddress, (char *)((INT_PTR)lpBaseAddress + dwSize));
+
+ return TRUE;
+}
diff --git a/src/pal/src/thread/process.cpp b/src/pal/src/thread/process.cpp
new file mode 100644
index 0000000000..315145dc03
--- /dev/null
+++ b/src/pal/src/thread/process.cpp
@@ -0,0 +1,4615 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ process.cpp
+
+Abstract:
+
+ Implementation of process object and functions related to processes.
+
+
+
+--*/
+
+#include "pal/procobj.hpp"
+#include "pal/thread.hpp"
+#include "pal/file.hpp"
+#include "pal/handlemgr.hpp"
+#include "pal/module.h"
+#include "procprivate.hpp"
+#include "pal/palinternal.h"
+#include "pal/process.h"
+#include "pal/init.h"
+#include "pal/critsect.h"
+#include "pal/debug.h"
+#include "pal/dbgmsg.h"
+#include "pal/utils.h"
+#include "pal/environ.h"
+#include "pal/virtual.h"
+#include "pal/stackstring.hpp"
+
+#include <errno.h>
+#if HAVE_POLL
+#include <poll.h>
+#else
+#include "pal/fakepoll.h"
+#endif // HAVE_POLL
+
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <signal.h>
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+#include <debugmacrosext.h>
+#include <semaphore.h>
+#include <stdint.h>
+
+#ifdef __APPLE__
+#include <sys/sysctl.h>
+#endif
+
+#ifdef __NetBSD__
+#include <sys/cdefs.h>
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#include <kvm.h>
+#endif
+
+using namespace CorUnix;
+
+SET_DEFAULT_DEBUG_CHANNEL(PROCESS);
+
+CObjectType CorUnix::otProcess(
+ otiProcess,
+ NULL,
+ NULL,
+ 0,
+ sizeof(CProcProcessLocalData),
+ 0,
+ PROCESS_ALL_ACCESS,
+ CObjectType::SecuritySupported,
+ CObjectType::SecurityInfoNotPersisted,
+ CObjectType::UnnamedObject,
+ CObjectType::CrossProcessDuplicationAllowed,
+ CObjectType::WaitableObject,
+ CObjectType::SingleTransitionObject,
+ CObjectType::ThreadReleaseHasNoSideEffects,
+ CObjectType::NoOwner
+ );
+
+static
+DWORD
+PALAPI
+StartupHelperThread(
+ LPVOID p);
+
+static
+BOOL
+GetProcessIdDisambiguationKey(
+ IN DWORD processId,
+ OUT UINT64 *disambiguationKey);
+
+//
+// Helper memory page used by the FlushProcessWriteBuffers
+//
+static int s_helperPage[VIRTUAL_PAGE_SIZE / sizeof(int)] __attribute__((aligned(VIRTUAL_PAGE_SIZE)));
+
+//
+// Mutex to make the FlushProcessWriteBuffersMutex thread safe
+//
+pthread_mutex_t flushProcessWriteBuffersMutex;
+
+CAllowedObjectTypes aotProcess(otiProcess);
+
+//
+// The representative IPalObject for this process
+//
+IPalObject* CorUnix::g_pobjProcess;
+
+//
+// Critical section that protects process data (e.g., the
+// list of active threads)/
+//
+CRITICAL_SECTION g_csProcess;
+
+//
+// List and count of active threads
+//
+CPalThread* CorUnix::pGThreadList;
+DWORD g_dwThreadCount;
+
+//
+// The command line and app name for the process
+//
+LPWSTR g_lpwstrCmdLine = NULL;
+LPWSTR g_lpwstrAppDir = NULL;
+
+// Thread ID of thread that has started the ExitProcess process
+Volatile<LONG> terminator = 0;
+
+// Process and session ID of this process.
+DWORD gPID = (DWORD) -1;
+DWORD gSID = (DWORD) -1;
+
+// The lowest common supported semaphore length, including null character
+// NetBSD-7.99.25: 15 characters
+// MacOSX 10.11: 31 -- Core 1.0 RC2 compatibility
+#if defined(__NetBSD__)
+#define CLR_SEM_MAX_NAMELEN 15
+#else
+#define CLR_SEM_MAX_NAMELEN (NAME_MAX - 4)
+#endif
+
+// Function to call during PAL/process shutdown/abort
+Volatile<PSHUTDOWN_CALLBACK> g_shutdownCallback = nullptr;
+
+//
+// Key used for associating CPalThread's with the underlying pthread
+// (through pthread_setspecific)
+//
+pthread_key_t CorUnix::thObjKey;
+
+#define PROCESS_PELOADER_FILENAME "clix"
+
+static WCHAR W16_WHITESPACE[]= {0x0020, 0x0009, 0x000D, 0};
+static WCHAR W16_WHITESPACE_DQUOTE[]= {0x0020, 0x0009, 0x000D, '"', 0};
+
+enum FILETYPE
+{
+ FILE_ERROR,/*ERROR*/
+ FILE_PE, /*PE/COFF file*/
+ FILE_UNIX, /*Unix Executable*/
+ FILE_DIR /*Directory*/
+};
+
+PAL_ERROR
+PROCGetProcessStatus(
+ CPalThread *pThread,
+ HANDLE hProcess,
+ PROCESS_STATE *pps,
+ DWORD *pdwExitCode
+ );
+
+static BOOL getFileName(LPCWSTR lpApplicationName, LPWSTR lpCommandLine,
+ PathCharString& lpFileName);
+static char ** buildArgv(LPCWSTR lpCommandLine, PathCharString& lpAppPath,
+ UINT *pnArg, BOOL prependLoader);
+static BOOL getPath(PathCharString& lpFileName, PathCharString& lpPathFileName);
+static int checkFileType(LPCSTR lpFileName);
+static BOOL PROCEndProcess(HANDLE hProcess, UINT uExitCode,
+ BOOL bTerminateUnconditionally);
+
+ProcessModules *GetProcessModulesFromHandle(IN HANDLE hProcess, OUT LPDWORD lpCount);
+ProcessModules *CreateProcessModules(IN DWORD dwProcessId, OUT LPDWORD lpCount);
+void DestroyProcessModules(IN ProcessModules *listHead);
+
+/*++
+Function:
+ GetCurrentProcessId
+
+See MSDN doc.
+--*/
+DWORD
+PALAPI
+GetCurrentProcessId(
+ VOID)
+{
+ PERF_ENTRY(GetCurrentProcessId);
+ ENTRY("GetCurrentProcessId()\n" );
+
+ LOGEXIT("GetCurrentProcessId returns DWORD %#x\n", gPID);
+ PERF_EXIT(GetCurrentProcessId);
+ return gPID;
+}
+
+
+/*++
+Function:
+ GetCurrentSessionId
+
+See MSDN doc.
+--*/
+DWORD
+PALAPI
+GetCurrentSessionId(
+ VOID)
+{
+ PERF_ENTRY(GetCurrentSessionId);
+ ENTRY("GetCurrentSessionId()\n" );
+
+ LOGEXIT("GetCurrentSessionId returns DWORD %#x\n", gSID);
+ PERF_EXIT(GetCurrentSessionId);
+ return gSID;
+}
+
+
+/*++
+Function:
+ GetCurrentProcess
+
+See MSDN doc.
+--*/
+HANDLE
+PALAPI
+GetCurrentProcess(
+ VOID)
+{
+ PERF_ENTRY(GetCurrentProcess);
+ ENTRY("GetCurrentProcess()\n" );
+
+ LOGEXIT("GetCurrentProcess returns HANDLE %p\n", hPseudoCurrentProcess);
+ PERF_EXIT(GetCurrentProcess);
+
+ /* return a pseudo handle */
+ return hPseudoCurrentProcess;
+}
+
+/*++
+Function:
+ CreateProcessA
+
+Note:
+ Only Standard handles need to be inherited.
+ Security attributes parameters are not used.
+
+See MSDN doc.
+--*/
+BOOL
+PALAPI
+CreateProcessA(
+ IN LPCSTR lpApplicationName,
+ IN LPSTR lpCommandLine,
+ IN LPSECURITY_ATTRIBUTES lpProcessAttributes,
+ IN LPSECURITY_ATTRIBUTES lpThreadAttributes,
+ IN BOOL bInheritHandles,
+ IN DWORD dwCreationFlags,
+ IN LPVOID lpEnvironment,
+ IN LPCSTR lpCurrentDirectory,
+ IN LPSTARTUPINFOA lpStartupInfo,
+ OUT LPPROCESS_INFORMATION lpProcessInformation)
+{
+ PAL_ERROR palError = NO_ERROR;
+ CPalThread *pThread;
+ STARTUPINFOW StartupInfoW;
+ LPWSTR CommandLineW = NULL;
+ LPWSTR ApplicationNameW = NULL;
+ LPWSTR CurrentDirectoryW = NULL;
+
+ int n;
+
+ PERF_ENTRY(CreateProcessA);
+ ENTRY("CreateProcessA(lpAppName=%p (%s), lpCmdLine=%p (%s), lpProcessAttr=%p, "
+ "lpThreadAttr=%p, bInherit=%d, dwFlags=%#x, lpEnv=%p, "
+ "lpCurrentDir=%p (%s), lpStartupInfo=%p, lpProcessInfo=%p)\n",
+ lpApplicationName?lpApplicationName:"NULL",
+ lpApplicationName?lpApplicationName:"NULL",
+ lpCommandLine?lpCommandLine:"NULL",
+ lpCommandLine?lpCommandLine:"NULL",
+ lpProcessAttributes, lpThreadAttributes, bInheritHandles,
+ dwCreationFlags, lpEnvironment,
+ lpCurrentDirectory?lpCurrentDirectory:"NULL",
+ lpCurrentDirectory?lpCurrentDirectory:"NULL",
+ lpStartupInfo, lpProcessInformation);
+
+ pThread = InternalGetCurrentThread();
+
+ if(lpStartupInfo == NULL)
+ {
+ ASSERT("lpStartupInfo is NULL!\n");
+ palError = ERROR_INVALID_PARAMETER;
+ goto done;
+ }
+
+ /* convert parameters to Unicode */
+
+ if(lpApplicationName)
+ {
+ n = MultiByteToWideChar(CP_ACP, 0, lpApplicationName, -1, NULL, 0);
+ if(0 == n)
+ {
+ ASSERT("MultiByteToWideChar failed!\n");
+ palError = ERROR_INTERNAL_ERROR;
+ goto done;
+ }
+ ApplicationNameW = (LPWSTR)InternalMalloc(sizeof(WCHAR)*n);
+ if(!ApplicationNameW)
+ {
+ ERROR("malloc() failed!\n");
+ palError = ERROR_NOT_ENOUGH_MEMORY;
+ goto done;
+ }
+ MultiByteToWideChar(CP_ACP, 0, lpApplicationName, -1, ApplicationNameW,
+ n);
+ }
+
+ if(lpCommandLine)
+ {
+ n = MultiByteToWideChar(CP_ACP, 0, lpCommandLine, -1, NULL, 0);
+ if(0 == n)
+ {
+ ASSERT("MultiByteToWideChar failed!\n");
+ palError = ERROR_INTERNAL_ERROR;
+ goto done;
+ }
+ CommandLineW = (LPWSTR)InternalMalloc(sizeof(WCHAR)*n);
+ if(!CommandLineW)
+ {
+ ERROR("malloc() failed!\n");
+ palError = ERROR_NOT_ENOUGH_MEMORY;
+ goto done;
+ }
+ MultiByteToWideChar(CP_ACP, 0, lpCommandLine, -1, CommandLineW, n);
+ }
+
+ if(lpCurrentDirectory)
+ {
+ n = MultiByteToWideChar(CP_ACP, 0, lpCurrentDirectory, -1, NULL, 0);
+ if(0 == n)
+ {
+ ASSERT("MultiByteToWideChar failed!\n");
+ palError = ERROR_INTERNAL_ERROR;
+ goto done;
+ }
+ CurrentDirectoryW = (LPWSTR)InternalMalloc(sizeof(WCHAR)*n);
+ if(!CurrentDirectoryW)
+ {
+ ERROR("malloc() failed!\n");
+ palError = ERROR_NOT_ENOUGH_MEMORY;
+ goto done;
+ }
+ MultiByteToWideChar(CP_ACP, 0, lpCurrentDirectory, -1,
+ CurrentDirectoryW, n);
+ }
+
+ // lpEnvironment should remain ansi on the call to CreateProcessW
+
+ StartupInfoW.cb = sizeof StartupInfoW;
+ StartupInfoW.dwFlags = lpStartupInfo->dwFlags;
+ StartupInfoW.hStdError = lpStartupInfo->hStdError;
+ StartupInfoW.hStdInput = lpStartupInfo->hStdInput;
+ StartupInfoW.hStdOutput = lpStartupInfo->hStdOutput;
+ /* all other members are PAL_Undefined, we can ignore them */
+
+ palError = InternalCreateProcess(
+ pThread,
+ ApplicationNameW,
+ CommandLineW,
+ lpProcessAttributes,
+ lpThreadAttributes,
+ bInheritHandles,
+ dwCreationFlags,
+ lpEnvironment,
+ CurrentDirectoryW,
+ &StartupInfoW,
+ lpProcessInformation
+ );
+done:
+ free(ApplicationNameW);
+ free(CommandLineW);
+ free(CurrentDirectoryW);
+
+ if (NO_ERROR != palError)
+ {
+ pThread->SetLastError(palError);
+ }
+
+ LOGEXIT("CreateProcessA returns BOOL %d\n", NO_ERROR == palError);
+ PERF_EXIT(CreateProcessA);
+ return NO_ERROR == palError;
+}
+
+
+/*++
+Function:
+ CreateProcessW
+
+Note:
+ Only Standard handles need to be inherited.
+ Security attributes parameters are not used.
+
+See MSDN doc.
+--*/
+BOOL
+PALAPI
+CreateProcessW(
+ IN LPCWSTR lpApplicationName,
+ IN LPWSTR lpCommandLine,
+ IN LPSECURITY_ATTRIBUTES lpProcessAttributes,
+ IN LPSECURITY_ATTRIBUTES lpThreadAttributes,
+ IN BOOL bInheritHandles,
+ IN DWORD dwCreationFlags,
+ IN LPVOID lpEnvironment,
+ IN LPCWSTR lpCurrentDirectory,
+ IN LPSTARTUPINFOW lpStartupInfo,
+ OUT LPPROCESS_INFORMATION lpProcessInformation)
+{
+ PAL_ERROR palError = NO_ERROR;
+ CPalThread *pThread;
+
+ PERF_ENTRY(CreateProcessW);
+ ENTRY("CreateProcessW(lpAppName=%p (%S), lpCmdLine=%p (%S), lpProcessAttr=%p,"
+ "lpThreadAttr=%p, bInherit=%d, dwFlags=%#x, lpEnv=%p,"
+ "lpCurrentDir=%p (%S), lpStartupInfo=%p, lpProcessInfo=%p)\n",
+ lpApplicationName?lpApplicationName:W16_NULLSTRING,
+ lpApplicationName?lpApplicationName:W16_NULLSTRING,
+ lpCommandLine?lpCommandLine:W16_NULLSTRING,
+ lpCommandLine?lpCommandLine:W16_NULLSTRING,lpProcessAttributes,
+ lpThreadAttributes, bInheritHandles, dwCreationFlags,lpEnvironment,
+ lpCurrentDirectory?lpCurrentDirectory:W16_NULLSTRING,
+ lpCurrentDirectory?lpCurrentDirectory:W16_NULLSTRING,
+ lpStartupInfo, lpProcessInformation);
+
+ pThread = InternalGetCurrentThread();
+
+ palError = InternalCreateProcess(
+ pThread,
+ lpApplicationName,
+ lpCommandLine,
+ lpProcessAttributes,
+ lpThreadAttributes,
+ bInheritHandles,
+ dwCreationFlags,
+ lpEnvironment,
+ lpCurrentDirectory,
+ lpStartupInfo,
+ lpProcessInformation
+ );
+
+ if (NO_ERROR != palError)
+ {
+ pThread->SetLastError(palError);
+ }
+
+ LOGEXIT("CreateProcessW returns BOOL %d\n", NO_ERROR == palError);
+ PERF_EXIT(CreateProcessW);
+
+ return NO_ERROR == palError;
+}
+
+PAL_ERROR
+PrepareStandardHandle(
+ CPalThread *pThread,
+ HANDLE hFile,
+ IPalObject **ppobjFile,
+ int *piFd
+ )
+{
+ PAL_ERROR palError = NO_ERROR;
+ IPalObject *pobjFile = NULL;
+ IDataLock *pDataLock = NULL;
+ CFileProcessLocalData *pLocalData = NULL;
+ int iError = 0;
+
+ palError = g_pObjectManager->ReferenceObjectByHandle(
+ pThread,
+ hFile,
+ &aotFile,
+ 0,
+ &pobjFile
+ );
+
+ if (NO_ERROR != palError)
+ {
+ ERROR("Bad handle passed through CreateProcess\n");
+ goto PrepareStandardHandleExit;
+ }
+
+ palError = pobjFile->GetProcessLocalData(
+ pThread,
+ ReadLock,
+ &pDataLock,
+ reinterpret_cast<void **>(&pLocalData)
+ );
+
+ if (NO_ERROR != palError)
+ {
+ ASSERT("Unable to access file data\n");
+ goto PrepareStandardHandleExit;
+ }
+
+ //
+ // The passed in file needs to be inheritable
+ //
+
+ if (!pLocalData->inheritable)
+ {
+ ERROR("Non-inheritable handle passed through CreateProcess\n");
+ palError = ERROR_INVALID_HANDLE;
+ goto PrepareStandardHandleExit;
+ }
+
+ iError = fcntl(pLocalData->unix_fd, F_SETFD, 0);
+ if (-1 == iError)
+ {
+ ERROR("Unable to remove close-on-exec for file (errno %i)\n", errno);
+ palError = ERROR_INVALID_HANDLE;
+ goto PrepareStandardHandleExit;
+ }
+
+ *piFd = pLocalData->unix_fd;
+ pDataLock->ReleaseLock(pThread, FALSE);
+ pDataLock = NULL;
+
+ //
+ // Transfer pobjFile reference to out parameter
+ //
+
+ *ppobjFile = pobjFile;
+ pobjFile = NULL;
+
+PrepareStandardHandleExit:
+
+ if (NULL != pDataLock)
+ {
+ pDataLock->ReleaseLock(pThread, FALSE);
+ }
+
+ if (NULL != pobjFile)
+ {
+ pobjFile->ReleaseReference(pThread);
+ }
+
+ return palError;
+}
+
+PAL_ERROR
+CorUnix::InternalCreateProcess(
+ CPalThread *pThread,
+ LPCWSTR lpApplicationName,
+ LPWSTR lpCommandLine,
+ LPSECURITY_ATTRIBUTES lpProcessAttributes,
+ LPSECURITY_ATTRIBUTES lpThreadAttributes,
+ BOOL bInheritHandles,
+ DWORD dwCreationFlags,
+ LPVOID lpEnvironment,
+ LPCWSTR lpCurrentDirectory,
+ LPSTARTUPINFOW lpStartupInfo,
+ LPPROCESS_INFORMATION lpProcessInformation
+ )
+{
+ PAL_ERROR palError = NO_ERROR;
+ IPalObject *pobjProcess = NULL;
+ IPalObject *pobjProcessRegistered = NULL;
+ IDataLock *pLocalDataLock = NULL;
+ CProcProcessLocalData *pLocalData;
+ IDataLock *pSharedDataLock = NULL;
+ CPalThread *pDummyThread = NULL;
+ HANDLE hDummyThread = NULL;
+ HANDLE hProcess = NULL;
+ CObjectAttributes oa(NULL, lpProcessAttributes);
+
+ IPalObject *pobjFileIn = NULL;
+ int iFdIn = -1;
+ IPalObject *pobjFileOut = NULL;
+ int iFdOut = -1;
+ IPalObject *pobjFileErr = NULL;
+ int iFdErr = -1;
+
+ pid_t processId;
+ PathCharString lpFileNamePS;
+ char **lppArgv = NULL;
+ UINT nArg;
+ int iRet;
+ char **EnvironmentArray=NULL;
+ int child_blocking_pipe = -1;
+ int parent_blocking_pipe = -1;
+
+ /* Validate parameters */
+
+ /* note : specs indicate lpApplicationName should always
+ be NULL; however support for it is already implemented. Leaving the code
+ in, specs can change; but rejecting non-NULL for now to conform to the
+ spec. */
+ if( NULL != lpApplicationName )
+ {
+ ASSERT("lpApplicationName should be NULL, but is %S instead\n",
+ lpApplicationName);
+ palError = ERROR_INVALID_PARAMETER;
+ goto InternalCreateProcessExit;
+ }
+
+ if (0 != (dwCreationFlags & ~(CREATE_SUSPENDED|CREATE_NEW_CONSOLE)))
+ {
+ ASSERT("Unexpected creation flags (%#x)\n", dwCreationFlags);
+ palError = ERROR_INVALID_PARAMETER;
+ goto InternalCreateProcessExit;
+ }
+
+ /* Security attributes parameters are ignored */
+ if (lpProcessAttributes != NULL &&
+ (lpProcessAttributes->lpSecurityDescriptor != NULL ||
+ lpProcessAttributes->bInheritHandle != TRUE))
+ {
+ ASSERT("lpProcessAttributes is invalid, parameter ignored (%p)\n",
+ lpProcessAttributes);
+ palError = ERROR_INVALID_PARAMETER;
+ goto InternalCreateProcessExit;
+ }
+
+ if (lpThreadAttributes != NULL)
+ {
+ ASSERT("lpThreadAttributes parameter must be NULL (%p)\n",
+ lpThreadAttributes);
+ palError = ERROR_INVALID_PARAMETER;
+ goto InternalCreateProcessExit;
+ }
+
+ /* note : Win32 crashes in this case */
+ if(NULL == lpStartupInfo)
+ {
+ ERROR("lpStartupInfo is NULL\n");
+ palError = ERROR_INVALID_PARAMETER;
+ goto InternalCreateProcessExit;
+ }
+
+ /* Validate lpStartupInfo.cb field */
+ if (lpStartupInfo->cb < sizeof(STARTUPINFOW))
+ {
+ ASSERT("lpStartupInfo parameter structure size is invalid (%u)\n",
+ lpStartupInfo->cb);
+ palError = ERROR_INVALID_PARAMETER;
+ goto InternalCreateProcessExit;
+ }
+
+ /* lpStartupInfo should be either zero or STARTF_USESTDHANDLES */
+ if (lpStartupInfo->dwFlags & ~STARTF_USESTDHANDLES)
+ {
+ ASSERT("lpStartupInfo parameter invalid flags (%#x)\n",
+ lpStartupInfo->dwFlags);
+ palError = ERROR_INVALID_PARAMETER;
+ goto InternalCreateProcessExit;
+ }
+
+ /* validate given standard handles if we have any */
+ if (lpStartupInfo->dwFlags & STARTF_USESTDHANDLES)
+ {
+ palError = PrepareStandardHandle(
+ pThread,
+ lpStartupInfo->hStdInput,
+ &pobjFileIn,
+ &iFdIn
+ );
+
+ if (NO_ERROR != palError)
+ {
+ goto InternalCreateProcessExit;
+ }
+
+ palError = PrepareStandardHandle(
+ pThread,
+ lpStartupInfo->hStdOutput,
+ &pobjFileOut,
+ &iFdOut
+ );
+
+ if (NO_ERROR != palError)
+ {
+ goto InternalCreateProcessExit;
+ }
+
+ palError = PrepareStandardHandle(
+ pThread,
+ lpStartupInfo->hStdError,
+ &pobjFileErr,
+ &iFdErr
+ );
+
+ if (NO_ERROR != palError)
+ {
+ goto InternalCreateProcessExit;
+ }
+ }
+
+ if (!getFileName(lpApplicationName, lpCommandLine, lpFileNamePS))
+ {
+ ERROR("Can't find executable!\n");
+ palError = ERROR_FILE_NOT_FOUND;
+ goto InternalCreateProcessExit;
+ }
+
+ /* check type of file */
+ iRet = checkFileType(lpFileNamePS);
+
+ switch (iRet)
+ {
+ case FILE_ERROR: /* file not found, or not an executable */
+ WARN ("File is not valid (%s)", lpFileNamePS.GetString());
+ palError = ERROR_FILE_NOT_FOUND;
+ goto InternalCreateProcessExit;
+
+ case FILE_PE: /* PE/COFF file */
+ //Get the path name where the PAL DLL was loaded from
+ if ( PAL_GetPALDirectoryA( lpFileNamePS ))
+ {
+ if (lpFileNamePS.Append("/", 1) == FALSE ||
+ lpFileNamePS.Append( PROCESS_PELOADER_FILENAME, strlen(PROCESS_PELOADER_FILENAME)) == FALSE)
+ {
+ ERROR("Append failed!\n");
+ palError = ERROR_INTERNAL_ERROR;
+ goto InternalCreateProcessExit;
+ }
+ }
+ else
+ {
+ ASSERT("PAL_GetPALDirectoryA failed to return the"
+ "pal installation directory \n");
+ palError = ERROR_INTERNAL_ERROR;
+ goto InternalCreateProcessExit;
+ }
+
+ break;
+
+ case FILE_UNIX: /* Unix binary file */
+ break; /* nothing to do */
+
+ case FILE_DIR:/*Directory*/
+ WARN ("File is a Directory (%s)", lpFileNamePS.GetString());
+ palError = ERROR_ACCESS_DENIED;
+ goto InternalCreateProcessExit;
+ break;
+
+ default: /* not supposed to get here */
+ ASSERT ("Invalid return type from checkFileType");
+ palError = ERROR_FILE_NOT_FOUND;
+ goto InternalCreateProcessExit;
+ }
+
+ /* build Argument list, lppArgv is allocated in buildArgv function and
+ requires to be freed */
+ lppArgv = buildArgv(lpCommandLine, lpFileNamePS, &nArg, iRet==1);
+
+ /* set the Environment variable */
+ if (lpEnvironment != NULL)
+ {
+ unsigned i;
+ // Since CREATE_UNICODE_ENVIRONMENT isn't supported we know the string is ansi
+ unsigned EnvironmentEntries = 0;
+ // Convert the environment block to array of strings
+ // Count the number of entries
+ // Is it a string that contains null terminated string, the end is delimited
+ // by two null in a row.
+ for (i = 0; ((char *)lpEnvironment)[i]!='\0'; i++)
+ {
+ EnvironmentEntries ++;
+ for (;((char *)lpEnvironment)[i]!='\0'; i++)
+ {
+ }
+ }
+ EnvironmentEntries++;
+ EnvironmentArray = (char **)InternalMalloc(EnvironmentEntries * sizeof(char *));
+
+ EnvironmentEntries = 0;
+ // Convert the environment block to array of strings
+ // Count the number of entries
+ // Is it a string that contains null terminated string, the end is delimited
+ // by two null in a row.
+ for (i = 0; ((char *)lpEnvironment)[i]!='\0'; i++)
+ {
+ EnvironmentArray[EnvironmentEntries] = &((char *)lpEnvironment)[i];
+ EnvironmentEntries ++;
+ for (;((char *)lpEnvironment)[i]!='\0'; i++)
+ {
+ }
+ }
+ EnvironmentArray[EnvironmentEntries] = NULL;
+ }
+
+ //
+ // Allocate and register the process object for the new process
+ //
+
+ palError = g_pObjectManager->AllocateObject(
+ pThread,
+ &otProcess,
+ &oa,
+ &pobjProcess
+ );
+
+ if (NO_ERROR != palError)
+ {
+ ERROR("Unable to allocate object for new proccess\n");
+ goto InternalCreateProcessExit;
+ }
+
+ palError = g_pObjectManager->RegisterObject(
+ pThread,
+ pobjProcess,
+ &aotProcess,
+ PROCESS_ALL_ACCESS,
+ &hProcess,
+ &pobjProcessRegistered
+ );
+
+ //
+ // pobjProcess is invalidated by the above call, so
+ // NULL it out here
+ //
+
+ pobjProcess = NULL;
+
+ if (NO_ERROR != palError)
+ {
+ ERROR("Unable to register new process object\n");
+ goto InternalCreateProcessExit;
+ }
+
+ //
+ // Create a new "dummy" thread object
+ //
+
+ palError = InternalCreateDummyThread(
+ pThread,
+ lpThreadAttributes,
+ &pDummyThread,
+ &hDummyThread
+ );
+
+ if (dwCreationFlags & CREATE_SUSPENDED)
+ {
+ int pipe_descs[2];
+
+ if (-1 == pipe(pipe_descs))
+ {
+ ERROR("pipe() failed! error is %d (%s)\n", errno, strerror(errno));
+ palError = ERROR_NOT_ENOUGH_MEMORY;
+ goto InternalCreateProcessExit;
+ }
+
+ /* [0] is read end, [1] is write end */
+ pDummyThread->suspensionInfo.SetBlockingPipe(pipe_descs[1]);
+ parent_blocking_pipe = pipe_descs[1];
+ child_blocking_pipe = pipe_descs[0];
+ }
+
+ palError = pobjProcessRegistered->GetProcessLocalData(
+ pThread,
+ WriteLock,
+ &pLocalDataLock,
+ reinterpret_cast<void **>(&pLocalData)
+ );
+
+ if (NO_ERROR != palError)
+ {
+ ASSERT("Unable to obtain local data for new process object\n");
+ goto InternalCreateProcessExit;
+ }
+
+
+ /* fork the new process */
+ processId = fork();
+
+ if (processId == -1)
+ {
+ ASSERT("Unable to create a new process with fork()\n");
+ if (-1 != child_blocking_pipe)
+ {
+ close(child_blocking_pipe);
+ close(parent_blocking_pipe);
+ }
+
+ palError = ERROR_INTERNAL_ERROR;
+ goto InternalCreateProcessExit;
+ }
+
+ /* From the time the child process begins running, to when it reaches execve,
+ the child process is not a real PAL process and does not own any PAL
+ resources, although it has access to the PAL resources of its parent process.
+ Thus, while the child process is in this window, it is dangerous for it to affect
+ its parent's PAL resources. As a consequence, no PAL code should be used
+ in this window; all code should make unix calls. Note the use of _exit
+ instead of exit to avoid calling PAL_Terminate and the lack of TRACE's and
+ ASSERT's. */
+
+ if (processId == 0) /* child process */
+ {
+ // At this point, the PAL should be considered uninitialized for this child process.
+
+ // Don't want to enter the init_critsec here since we're trying to avoid
+ // calling PAL functions. Furthermore, nothing should be changing
+ // the init_count in the child process at this point since this is the only
+ // thread executing.
+ init_count = 0;
+
+ sigset_t sm;
+
+ //
+ // Clear out the signal mask for the new process.
+ //
+
+ sigemptyset(&sm);
+ iRet = sigprocmask(SIG_SETMASK, &sm, NULL);
+ if (iRet != 0)
+ {
+ _exit(EXIT_FAILURE);
+ }
+
+ if (dwCreationFlags & CREATE_SUSPENDED)
+ {
+ BYTE resume_code = 0;
+ ssize_t read_ret;
+
+ /* close the write end of the pipe, the child doesn't need it */
+ close(parent_blocking_pipe);
+
+ read_again:
+ /* block until ResumeThread writes something to the pipe */
+ read_ret = read(child_blocking_pipe, &resume_code, sizeof(resume_code));
+ if (sizeof(resume_code) != read_ret)
+ {
+ if (read_ret == -1 && EINTR == errno)
+ {
+ goto read_again;
+ }
+ else
+ {
+ /* note : read might return 0 (and return EAGAIN) if the other
+ end of the pipe gets closed - for example because the parent
+ process dies (very) abruptly */
+ _exit(EXIT_FAILURE);
+ }
+ }
+ if (WAKEUPCODE != resume_code)
+ {
+ // resume_code should always equal WAKEUPCODE.
+ _exit(EXIT_FAILURE);
+ }
+
+ close(child_blocking_pipe);
+ }
+
+ /* Set the current directory */
+ if (lpCurrentDirectory)
+ {
+ SetCurrentDirectoryW(lpCurrentDirectory);
+ }
+
+ /* Set the standard handles to the incoming values */
+ if (lpStartupInfo->dwFlags & STARTF_USESTDHANDLES)
+ {
+ /* For each handle, we need to duplicate the incoming unix
+ fd to the corresponding standard one. The API that I use,
+ dup2, will copy the source to the destination, automatically
+ closing the existing destination, in an atomic way */
+ if (dup2(iFdIn, STDIN_FILENO) == -1)
+ {
+ // Didn't duplicate standard in.
+ _exit(EXIT_FAILURE);
+ }
+
+ if (dup2(iFdOut, STDOUT_FILENO) == -1)
+ {
+ // Didn't duplicate standard out.
+ _exit(EXIT_FAILURE);
+ }
+
+ if (dup2(iFdErr, STDERR_FILENO) == -1)
+ {
+ // Didn't duplicate standard error.
+ _exit(EXIT_FAILURE);
+ }
+
+ /* now close the original FDs, we don't need them anymore */
+ close(iFdIn);
+ close(iFdOut);
+ close(iFdErr);
+ }
+
+ /* execute the new process */
+
+ if (EnvironmentArray)
+ {
+ execve(lpFileNamePS, lppArgv, EnvironmentArray);
+ }
+ else
+ {
+ execve(lpFileNamePS, lppArgv, palEnvironment);
+ }
+
+ /* if we get here, it means the execve function call failed so just exit */
+ _exit(EXIT_FAILURE);
+ }
+
+ /* parent process */
+
+ /* close the read end of the pipe, the parent doesn't need it */
+ close(child_blocking_pipe);
+
+ /* Set the process ID */
+ pLocalData->dwProcessId = processId;
+ pLocalDataLock->ReleaseLock(pThread, TRUE);
+ pLocalDataLock = NULL;
+
+ //
+ // Release file handle info; we don't need them anymore. Note that
+ // this must happen after we've released the data locks, as
+ // otherwise a deadlock could result.
+ //
+
+ if (lpStartupInfo->dwFlags & STARTF_USESTDHANDLES)
+ {
+ pobjFileIn->ReleaseReference(pThread);
+ pobjFileIn = NULL;
+ pobjFileOut->ReleaseReference(pThread);
+ pobjFileOut = NULL;
+ pobjFileErr->ReleaseReference(pThread);
+ pobjFileErr = NULL;
+ }
+
+ /* fill PROCESS_INFORMATION strucutre */
+ lpProcessInformation->hProcess = hProcess;
+ lpProcessInformation->hThread = hDummyThread;
+ lpProcessInformation->dwProcessId = processId;
+ lpProcessInformation->dwThreadId_PAL_Undefined = 0;
+
+
+ TRACE("New process created: id=%#x\n", processId);
+
+InternalCreateProcessExit:
+
+ if (NULL != pLocalDataLock)
+ {
+ pLocalDataLock->ReleaseLock(pThread, FALSE);
+ }
+
+ if (NULL != pSharedDataLock)
+ {
+ pSharedDataLock->ReleaseLock(pThread, FALSE);
+ }
+
+ if (NULL != pobjProcess)
+ {
+ pobjProcess->ReleaseReference(pThread);
+ }
+
+ if (NULL != pobjProcessRegistered)
+ {
+ pobjProcessRegistered->ReleaseReference(pThread);
+ }
+
+ if (NO_ERROR != palError)
+ {
+ if (NULL != hProcess)
+ {
+ g_pObjectManager->RevokeHandle(pThread, hProcess);
+ }
+
+ if (NULL != hDummyThread)
+ {
+ g_pObjectManager->RevokeHandle(pThread, hDummyThread);
+ }
+ }
+
+ if (EnvironmentArray)
+ {
+ free(EnvironmentArray);
+ }
+
+ /* if we still have the file structures at this point, it means we
+ encountered an error sometime between when we acquired them and when we
+ fork()ed. We not only have to release them, we have to give them back
+ their close-on-exec flag */
+ if (NULL != pobjFileIn)
+ {
+ if(-1 == fcntl(iFdIn, F_SETFD, 1))
+ {
+ WARN("couldn't restore close-on-exec flag to stdin descriptor! "
+ "errno is %d (%s)\n", errno, strerror(errno));
+ }
+ pobjFileIn->ReleaseReference(pThread);
+ }
+
+ if (NULL != pobjFileOut)
+ {
+ if(-1 == fcntl(iFdOut, F_SETFD, 1))
+ {
+ WARN("couldn't restore close-on-exec flag to stdout descriptor! "
+ "errno is %d (%s)\n", errno, strerror(errno));
+ }
+ pobjFileOut->ReleaseReference(pThread);
+ }
+
+ if (NULL != pobjFileErr)
+ {
+ if(-1 == fcntl(iFdErr, F_SETFD, 1))
+ {
+ WARN("couldn't restore close-on-exec flag to stderr descriptor! "
+ "errno is %d (%s)\n", errno, strerror(errno));
+ }
+ pobjFileErr->ReleaseReference(pThread);
+ }
+
+ /* free allocated memory */
+ if (lppArgv)
+ {
+ free(*lppArgv);
+ free(lppArgv);
+ }
+
+ return palError;
+}
+
+
+/*++
+Function:
+ GetExitCodeProcess
+
+See MSDN doc.
+--*/
+BOOL
+PALAPI
+GetExitCodeProcess(
+ IN HANDLE hProcess,
+ IN LPDWORD lpExitCode)
+{
+ CPalThread *pThread;
+ PAL_ERROR palError = NO_ERROR;
+ DWORD dwExitCode;
+ PROCESS_STATE ps;
+
+ PERF_ENTRY(GetExitCodeProcess);
+ ENTRY("GetExitCodeProcess(hProcess = %p, lpExitCode = %p)\n",
+ hProcess, lpExitCode);
+
+ pThread = InternalGetCurrentThread();
+
+ if(NULL == lpExitCode)
+ {
+ WARN("Got NULL lpExitCode\n");
+ palError = ERROR_INVALID_PARAMETER;
+ goto done;
+ }
+
+ palError = PROCGetProcessStatus(
+ pThread,
+ hProcess,
+ &ps,
+ &dwExitCode
+ );
+
+ if (NO_ERROR != palError)
+ {
+ ASSERT("Couldn't get process status information!\n");
+ goto done;
+ }
+
+ if( PS_DONE == ps )
+ {
+ *lpExitCode = dwExitCode;
+ }
+ else
+ {
+ *lpExitCode = STILL_ACTIVE;
+ }
+
+done:
+
+ if (NO_ERROR != palError)
+ {
+ pThread->SetLastError(palError);
+ }
+
+ LOGEXIT("GetExitCodeProcess returns BOOL %d\n", NO_ERROR == palError);
+ PERF_EXIT(GetExitCodeProcess);
+
+ return NO_ERROR == palError;
+}
+
+/*++
+Function:
+ ExitProcess
+
+See MSDN doc.
+--*/
+PAL_NORETURN
+VOID
+PALAPI
+ExitProcess(
+ IN UINT uExitCode)
+{
+ DWORD old_terminator;
+
+ PERF_ENTRY_ONLY(ExitProcess);
+ ENTRY("ExitProcess(uExitCode=0x%x)\n", uExitCode );
+
+ old_terminator = InterlockedCompareExchange(&terminator, GetCurrentThreadId(), 0);
+
+ if (GetCurrentThreadId() == old_terminator)
+ {
+ // This thread has already initiated termination. This can happen
+ // in two ways:
+ // 1) DllMain(DLL_PROCESS_DETACH) triggers a call to ExitProcess.
+ // 2) PAL_exit() is called after the last PALTerminate().
+ // If the PAL is still initialized, we go straight through to
+ // PROCEndProcess. If it isn't, we simply exit.
+ if (!PALIsInitialized())
+ {
+ exit(uExitCode);
+ ASSERT("exit has returned\n");
+ }
+ else
+ {
+ WARN("thread re-called ExitProcess\n");
+ PROCEndProcess(GetCurrentProcess(), uExitCode, FALSE);
+ }
+ }
+ else if (0 != old_terminator)
+ {
+ /* another thread has already initiated the termination process. we
+ could just block on the PALInitLock critical section, but then
+ PROCSuspendOtherThreads would hang... so sleep forever here, we're
+ terminating anyway
+
+ Update: [TODO] PROCSuspendOtherThreads has been removed. Can this
+ code be changed? */
+ WARN("termination already started from another thread; blocking.\n");
+ poll(NULL, 0, INFTIM);
+ }
+
+ /* ExitProcess may be called even if PAL is not initialized.
+ Verify if process structure exist
+ */
+ if (PALInitLock() && PALIsInitialized())
+ {
+ PROCEndProcess(GetCurrentProcess(), uExitCode, FALSE);
+
+ /* Should not get here, because we terminate the current process */
+ ASSERT("PROCEndProcess has returned\n");
+ }
+ else
+ {
+ exit(uExitCode);
+
+ /* Should not get here, because we terminate the current process */
+ ASSERT("exit has returned\n");
+ }
+
+ /* this should never get executed */
+ ASSERT("ExitProcess should not return!\n");
+ for (;;);
+}
+
+/*++
+Function:
+ TerminateProcess
+
+Note:
+ hProcess is a handle on the current process.
+
+See MSDN doc.
+--*/
+BOOL
+PALAPI
+TerminateProcess(
+ IN HANDLE hProcess,
+ IN UINT uExitCode)
+{
+ BOOL ret;
+
+ PERF_ENTRY(TerminateProcess);
+ ENTRY("TerminateProcess(hProcess=%p, uExitCode=%u)\n",hProcess, uExitCode );
+
+ ret = PROCEndProcess(hProcess, uExitCode, TRUE);
+
+ LOGEXIT("TerminateProcess returns BOOL %d\n", ret);
+ PERF_EXIT(TerminateProcess);
+ return ret;
+}
+
+/*++
+Function:
+ PROCEndProcess
+
+ Called from TerminateProcess and ExitProcess. This does the work of
+ TerminateProcess, but also takes a flag that determines whether we
+ shut down unconditionally. If the flag is set, the PAL will do very
+ little extra work before exiting. Most importantly, it won't shut
+ down any DLLs that are loaded.
+
+--*/
+static BOOL PROCEndProcess(HANDLE hProcess, UINT uExitCode, BOOL bTerminateUnconditionally)
+{
+ DWORD dwProcessId;
+ BOOL ret = FALSE;
+
+ dwProcessId = PROCGetProcessIDFromHandle(hProcess);
+ if (dwProcessId == 0)
+ {
+ SetLastError(ERROR_INVALID_HANDLE);
+ }
+ else if(dwProcessId != GetCurrentProcessId())
+ {
+ if (uExitCode != 0)
+ WARN("exit code 0x%x ignored for external process.\n", uExitCode);
+
+ if (kill(dwProcessId, SIGKILL) == 0)
+ {
+ ret = TRUE;
+ }
+ else
+ {
+ switch (errno) {
+ case ESRCH:
+ SetLastError(ERROR_INVALID_HANDLE);
+ break;
+ case EPERM:
+ SetLastError(ERROR_ACCESS_DENIED);
+ break;
+ default:
+ // Unexpected failure.
+ ASSERT(FALSE);
+ SetLastError(ERROR_INTERNAL_ERROR);
+ break;
+ }
+ }
+ }
+ else
+ {
+ // WARN/ERROR before starting the termination process and/or leaving the PAL.
+ if (bTerminateUnconditionally)
+ {
+ WARN("exit code 0x%x ignored for terminate.\n", uExitCode);
+ }
+ else if ((uExitCode & 0xff) != uExitCode)
+ {
+ // TODO: Convert uExitCodes into sysexits(3)?
+ ERROR("exit() only supports the lower 8-bits of an exit code. "
+ "status will only see error 0x%x instead of 0x%x.\n", uExitCode & 0xff, uExitCode);
+ }
+
+ TerminateCurrentProcessNoExit(bTerminateUnconditionally);
+
+ LOGEXIT("PROCEndProcess will not return\n");
+
+ // exit() runs atexit handlers possibly registered by foreign code.
+ // The right thing to do here is to leave the PAL. If our client
+ // registered our own PAL_Terminate with atexit(), the latter will
+ // explicitly re-enter us.
+ PAL_Leave(PAL_BoundaryBottom);
+
+ if (bTerminateUnconditionally)
+ {
+ // abort() has the semantics that
+ // (1) it doesn't run atexit handlers
+ // (2) can invoke CrashReporter or produce a coredump,
+ // which is appropriate for TerminateProcess calls
+ abort();
+ }
+ else
+ {
+ exit(uExitCode);
+ }
+
+ ASSERT(FALSE); // we shouldn't get here
+ }
+
+ return ret;
+}
+
+/*++
+Function:
+ PAL_SetShutdownCallback
+
+Abstract:
+ Sets a callback that is executed when the PAL is shut down because of
+ ExitProcess, TerminateProcess or PAL_Shutdown but not PAL_Terminate/Ex.
+
+ NOTE: Currently only one callback can be set at a time.
+--*/
+PALIMPORT
+VOID
+PALAPI
+PAL_SetShutdownCallback(
+ IN PSHUTDOWN_CALLBACK callback)
+{
+ _ASSERTE(g_shutdownCallback == nullptr);
+ g_shutdownCallback = callback;
+}
+
+static bool IsCoreClrModule(const char* pModulePath)
+{
+ // Strip off everything up to and including the last slash in the path to get name
+ const char* pModuleName = pModulePath;
+ while (strchr(pModuleName, '/') != NULL)
+ {
+ pModuleName = strchr(pModuleName, '/');
+ pModuleName++; // pass the slash
+ }
+
+ return _stricmp(pModuleName, MAKEDLLNAME_A("coreclr")) == 0;
+}
+
+// Build the semaphore names using the PID and a value that can be used for distinguishing
+// between processes with the same PID (which ran at different times). This is to avoid
+// cases where a prior process with the same PID exited abnormally without having a chance
+// to clean up its semaphore.
+// Note to anyone modifying these names in the future: Semaphore names on OS X are limited
+// to SEM_NAME_LEN characters, including null. SEM_NAME_LEN is 31 (at least on OS X 10.11).
+// NetBSD limits semaphore names to 15 characters, including null (at least up to 7.99.25).
+// Keep 31 length for Core 1.0 RC2 compatibility
+#if defined(__NetBSD__)
+static const char* RuntimeStartupSemaphoreName = "/clrst%08llx";
+static const char* RuntimeContinueSemaphoreName = "/clrco%08llx";
+#else
+static const char* RuntimeStartupSemaphoreName = "/clrst%08x%016llx";
+static const char* RuntimeContinueSemaphoreName = "/clrco%08x%016llx";
+#endif
+
+#if defined(__NetBSD__)
+static uint64_t HashSemaphoreName(uint64_t a, uint64_t b)
+{
+ return (a ^ b) & 0xffffffff;
+}
+#else
+#define HashSemaphoreName(a,b) a,b
+#endif
+
+static const char* PipeNameFormat = "/tmp/clr-debug-pipe-%d-%llu-%s";
+
+class PAL_RuntimeStartupHelper
+{
+ LONG m_ref;
+ bool m_canceled;
+ PPAL_STARTUP_CALLBACK m_callback;
+ PVOID m_parameter;
+ DWORD m_threadId;
+ HANDLE m_threadHandle;
+ DWORD m_processId;
+
+ // A value that, used in conjunction with the process ID, uniquely identifies a process.
+ // See the format we use for debugger semaphore names for why this is necessary.
+ UINT64 m_processIdDisambiguationKey;
+
+ // Debugger waits on this semaphore and the runtime signals it on startup.
+ sem_t *m_startupSem;
+
+ // Debuggee waits on this semaphore and the debugger signals it after the startup callback
+ // registered (m_callback) returns.
+ sem_t *m_continueSem;
+
+public:
+ PAL_RuntimeStartupHelper(DWORD dwProcessId, PPAL_STARTUP_CALLBACK pfnCallback, PVOID parameter) :
+ m_ref(1),
+ m_canceled(false),
+ m_callback(pfnCallback),
+ m_parameter(parameter),
+ m_threadId(0),
+ m_threadHandle(NULL),
+ m_processId(dwProcessId),
+ m_startupSem(SEM_FAILED),
+ m_continueSem(SEM_FAILED)
+ {
+ }
+
+ ~PAL_RuntimeStartupHelper()
+ {
+ if (m_startupSem != SEM_FAILED)
+ {
+ char startupSemName[CLR_SEM_MAX_NAMELEN];
+ sprintf_s(startupSemName,
+ sizeof(startupSemName),
+ RuntimeStartupSemaphoreName,
+ HashSemaphoreName(m_processId,
+ m_processIdDisambiguationKey));
+
+ sem_close(m_startupSem);
+ sem_unlink(startupSemName);
+ }
+
+ if (m_continueSem != SEM_FAILED)
+ {
+ char continueSemName[CLR_SEM_MAX_NAMELEN];
+ sprintf_s(continueSemName,
+ sizeof(continueSemName),
+ RuntimeContinueSemaphoreName,
+ HashSemaphoreName(m_processId,
+ m_processIdDisambiguationKey));
+
+ sem_close(m_continueSem);
+ sem_unlink(continueSemName);
+ }
+
+ if (m_threadHandle != NULL)
+ {
+ CloseHandle(m_threadHandle);
+ }
+ }
+
+ LONG AddRef()
+ {
+ LONG ref = InterlockedIncrement(&m_ref);
+ return ref;
+ }
+
+ LONG Release()
+ {
+ LONG ref = InterlockedDecrement(&m_ref);
+ if (ref == 0)
+ {
+ delete this;
+ }
+ return ref;
+ }
+
+ PAL_ERROR GetSemError()
+ {
+ PAL_ERROR pe;
+ switch (errno)
+ {
+ case ENOENT:
+ pe = ERROR_NOT_FOUND;
+ break;
+ case EACCES:
+ pe = ERROR_INVALID_ACCESS;
+ break;
+ case EINVAL:
+ case ENAMETOOLONG:
+ pe = ERROR_INVALID_NAME;
+ break;
+ case ENOMEM:
+ pe = ERROR_OUTOFMEMORY;
+ break;
+ case EEXIST:
+ pe = ERROR_ALREADY_EXISTS;
+ break;
+ case ENOSPC:
+ pe = ERROR_TOO_MANY_SEMAPHORES;
+ break;
+ default:
+ pe = ERROR_INVALID_PARAMETER;
+ break;
+ }
+ return pe;
+ }
+
+ PAL_ERROR Register()
+ {
+ CPalThread *pThread = InternalGetCurrentThread();
+ char startupSemName[CLR_SEM_MAX_NAMELEN];
+ char continueSemName[CLR_SEM_MAX_NAMELEN];
+ PAL_ERROR pe = NO_ERROR;
+
+ // See semaphore name format for details about this value. We store it so that
+ // it can be used by the cleanup code that removes the semaphore with sem_unlink.
+ INDEBUG(BOOL disambiguationKeyRet = )
+ GetProcessIdDisambiguationKey(m_processId, &m_processIdDisambiguationKey);
+ _ASSERTE(disambiguationKeyRet == TRUE || m_processIdDisambiguationKey == 0);
+
+ sprintf_s(startupSemName,
+ sizeof(startupSemName),
+ RuntimeStartupSemaphoreName,
+ HashSemaphoreName(m_processId,
+ m_processIdDisambiguationKey));
+
+ sprintf_s(continueSemName,
+ sizeof(continueSemName),
+ RuntimeContinueSemaphoreName,
+ HashSemaphoreName(m_processId,
+ m_processIdDisambiguationKey));
+
+ TRACE("PAL_RuntimeStartupHelper.Register creating startup '%s' continue '%s'\n", startupSemName, continueSemName);
+
+ // Create the continue semaphore first so we don't race with PAL_NotifyRuntimeStarted. This open will fail if another
+ // debugger is trying to attach to this process because the name will already exist.
+ m_continueSem = sem_open(continueSemName, O_CREAT | O_EXCL, S_IRWXU, 0);
+ if (m_continueSem == SEM_FAILED)
+ {
+ TRACE("sem_open(continue) failed: errno is %d (%s)\n", errno, strerror(errno));
+ pe = GetSemError();
+ goto exit;
+ }
+
+ // Create the debuggee startup semaphore so the runtime (debuggee) knows to wait for a debugger connection.
+ m_startupSem = sem_open(startupSemName, O_CREAT | O_EXCL, S_IRWXU, 0);
+ if (m_startupSem == SEM_FAILED)
+ {
+ TRACE("sem_open(startup) failed: errno is %d (%s)\n", errno, strerror(errno));
+ pe = GetSemError();
+ goto exit;
+ }
+
+ // Add a reference for the thread handler
+ AddRef();
+
+ pe = InternalCreateThread(
+ pThread,
+ NULL,
+ 0,
+ ::StartupHelperThread,
+ this,
+ 0,
+ UserCreatedThread,
+ &m_threadId,
+ &m_threadHandle);
+
+ if (NO_ERROR != pe)
+ {
+ TRACE("InternalCreateThread failed %d\n", pe);
+ Release();
+ goto exit;
+ }
+
+ exit:
+ return pe;
+ }
+
+ void Unregister()
+ {
+ m_canceled = true;
+
+ // Tell the runtime to continue
+ if (sem_post(m_continueSem) != 0)
+ {
+ ASSERT("sem_post(continueSem) failed: errno is %d (%s)\n", errno, strerror(errno));
+ }
+
+ // Tell the worker thread to continue
+ if (sem_post(m_startupSem) != 0)
+ {
+ ASSERT("sem_post(startupSem) failed: errno is %d (%s)\n", errno, strerror(errno));
+ }
+
+ // Don't need to wait for the worker thread if unregister called on it
+ if (m_threadId != (DWORD)THREADSilentGetCurrentThreadId())
+ {
+ // Wait for work thread to exit
+ if (WaitForSingleObject(m_threadHandle, INFINITE) != WAIT_OBJECT_0)
+ {
+ ASSERT("WaitForSingleObject\n");
+ }
+ }
+ }
+
+ //
+ // There are a couple race conditions that need to be considered here:
+ //
+ // * On launch, between the fork and execv in the PAL's CreateProcess where the target process
+ // may contain a coreclr module image if the debugger process is running managed code. This
+ // makes just checking if the coreclr module exists not enough.
+ //
+ // * On launch (after the execv) or attach when the coreclr is loaded but before the DAC globals
+ // table is initialized where it is too soon to use/initialize the DAC on the debugger side.
+ //
+ // They are both fixed by check if the one of transport pipe files has been created.
+ //
+ bool IsCoreClrProcessReady()
+ {
+ char pipeName[MAX_DEBUGGER_TRANSPORT_PIPE_NAME_LENGTH];
+
+ PAL_GetTransportPipeName(pipeName, m_processId, "in");
+
+ struct stat buf;
+ if (stat(pipeName, &buf) == 0)
+ {
+ TRACE("IsCoreClrProcessReady: stat(%s) SUCCEEDED\n", pipeName);
+ return true;
+ }
+ TRACE("IsCoreClrProcessReady: stat(%s) FAILED: errno is %d (%s)\n", pipeName, errno, strerror(errno));
+ return false;
+ }
+
+ PAL_ERROR InvokeStartupCallback()
+ {
+ ProcessModules *listHead = NULL;
+ PAL_ERROR pe = NO_ERROR;
+ DWORD count;
+
+ if (m_canceled)
+ {
+ goto exit;
+ }
+
+ // Enumerate all the modules in the process and invoke the callback
+ // for the coreclr module if found.
+ listHead = CreateProcessModules(m_processId, &count);
+ if (listHead == NULL)
+ {
+ TRACE("CreateProcessModules failed for pid %d\n", m_processId);
+ pe = ERROR_INVALID_PARAMETER;
+ goto exit;
+ }
+
+ for (ProcessModules *entry = listHead; entry != NULL; entry = entry->Next)
+ {
+ if (IsCoreClrModule(entry->Name))
+ {
+ PAL_CPP_TRY
+ {
+ TRACE("InvokeStartupCallback executing callback %p %s\n", entry->BaseAddress, entry->Name);
+ m_callback(entry->Name, entry->BaseAddress, m_parameter);
+ }
+ PAL_CPP_CATCH_ALL
+ {
+ }
+ PAL_CPP_ENDTRY
+
+ // Currently only the first coreclr module in a process is supported
+ break;
+ }
+ }
+
+ exit:
+ // Wake up the runtime
+ if (sem_post(m_continueSem) != 0)
+ {
+ ASSERT("sem_post(continueSem) failed: errno is %d (%s)\n", errno, strerror(errno));
+ }
+ if (listHead != NULL)
+ {
+ DestroyProcessModules(listHead);
+ }
+ return pe;
+ }
+
+ void StartupHelperThread()
+ {
+ PAL_ERROR pe = NO_ERROR;
+
+ if (IsCoreClrProcessReady())
+ {
+ pe = InvokeStartupCallback();
+ }
+ else {
+ TRACE("sem_wait(startup)\n");
+
+ // Wait until the coreclr runtime (debuggee) starts up
+ if (sem_wait(m_startupSem) == 0)
+ {
+ pe = InvokeStartupCallback();
+ }
+ else
+ {
+ TRACE("sem_wait(startup) failed: errno is %d (%s)\n", errno, strerror(errno));
+ pe = GetSemError();
+ }
+ }
+
+ // Invoke the callback on errors
+ if (pe != NO_ERROR && !m_canceled)
+ {
+ SetLastError(pe);
+ m_callback(NULL, NULL, m_parameter);
+ }
+ }
+};
+
+static
+DWORD
+PALAPI
+StartupHelperThread(LPVOID p)
+{
+ TRACE("PAL's StartupHelperThread starting\n");
+
+ PAL_RuntimeStartupHelper *helper = (PAL_RuntimeStartupHelper *)p;
+ helper->StartupHelperThread();
+ helper->Release();
+ return 0;
+}
+
+/*++
+ PAL_RegisterForRuntimeStartup
+
+Parameters:
+ dwProcessId - process id of runtime process
+ pfnCallback - function to callback for coreclr module found
+ parameter - data to pass to callback
+ ppUnregisterToken - pointer to put PAL_UnregisterForRuntimeStartup token.
+
+Return value:
+ PAL_ERROR
+
+Note:
+ If the modulePath or hModule is NULL when the callback is invoked, an error occured
+ and GetLastError() will return the Win32 error code.
+
+ The callback is always invoked on a separate thread and this API returns immediately.
+
+ Only the first coreclr module is currently supported.
+
+--*/
+DWORD
+PALAPI
+PAL_RegisterForRuntimeStartup(
+ IN DWORD dwProcessId,
+ IN PPAL_STARTUP_CALLBACK pfnCallback,
+ IN PVOID parameter,
+ OUT PVOID *ppUnregisterToken)
+{
+ _ASSERTE(pfnCallback != NULL);
+ _ASSERTE(ppUnregisterToken != NULL);
+
+ PAL_RuntimeStartupHelper *helper = new PAL_RuntimeStartupHelper(dwProcessId, pfnCallback, parameter);
+
+ // Create the debuggee startup semaphore so the runtime (debuggee) knows to wait for
+ // a debugger connection.
+ PAL_ERROR pe = helper->Register();
+ if (NO_ERROR != pe)
+ {
+ helper->Release();
+ helper = NULL;
+ }
+
+ *ppUnregisterToken = helper;
+ return pe;
+}
+
+/*++
+ PAL_UnregisterForRuntimeStartup
+
+ Stops/cancels startup notification. This API can be called in the startup callback. Otherwise,
+ it will block until the callback thread finishes and no more callbacks will be initiated after
+ this API returns.
+
+Parameters:
+ dwUnregisterToken - token from PAL_RegisterForRuntimeStartup or NULL.
+
+Return value:
+ PAL_ERROR
+--*/
+DWORD
+PALAPI
+PAL_UnregisterForRuntimeStartup(
+ IN PVOID pUnregisterToken)
+{
+ if (pUnregisterToken != NULL)
+ {
+ PAL_RuntimeStartupHelper *helper = (PAL_RuntimeStartupHelper *)pUnregisterToken;
+ helper->Unregister();
+ helper->Release();
+ }
+ return NO_ERROR;
+}
+
+/*++
+ PAL_NotifyRuntimeStarted
+
+ Signals the debugger waiting for runtime startup notification to continue and
+ waits until the debugger signals us to continue.
+
+Parameters:
+ None
+
+Return value:
+ TRUE - succeeded, FALSE - failed
+--*/
+BOOL
+PALAPI
+PAL_NotifyRuntimeStarted()
+{
+ char startupSemName[CLR_SEM_MAX_NAMELEN];
+ char continueSemName[CLR_SEM_MAX_NAMELEN];
+ sem_t *startupSem = SEM_FAILED;
+ sem_t *continueSem = SEM_FAILED;
+ BOOL result = TRUE;
+
+ UINT64 processIdDisambiguationKey = 0;
+ GetProcessIdDisambiguationKey(gPID, &processIdDisambiguationKey);
+
+ sprintf_s(startupSemName, sizeof(startupSemName), RuntimeStartupSemaphoreName, HashSemaphoreName(gPID, processIdDisambiguationKey));
+ sprintf_s(continueSemName, sizeof(continueSemName), RuntimeContinueSemaphoreName, HashSemaphoreName(gPID, processIdDisambiguationKey));
+
+ TRACE("PAL_NotifyRuntimeStarted opening continue '%s' startup '%s'\n", continueSemName, startupSemName);
+
+
+ // Open the debugger startup semaphore. If it doesn't exists, then we do nothing and
+ // the function is successful.
+ startupSem = sem_open(startupSemName, 0);
+ if (startupSem == SEM_FAILED)
+ {
+ TRACE("sem_open(%s) failed: %d (%s)\n", startupSemName, errno, strerror(errno));
+ goto exit;
+ }
+
+ continueSem = sem_open(continueSemName, 0);
+ if (continueSem == SEM_FAILED)
+ {
+ ASSERT("sem_open(%s) failed: %d (%s)\n", continueSemName, errno, strerror(errno));
+ result = FALSE;
+ goto exit;
+ }
+
+ // Wake up the debugger waiting for startup
+ if (sem_post(startupSem) != 0)
+ {
+ ASSERT("sem_post(startupSem) failed: errno is %d (%s)\n", errno, strerror(errno));
+ result = FALSE;
+ goto exit;
+ }
+
+ // Now wait until the debugger's runtime startup notification is finished
+ if (sem_wait(continueSem) != 0)
+ {
+ ASSERT("sem_wait(continueSem) failed: errno is %d (%s)\n", errno, strerror(errno));
+ result = FALSE;
+ goto exit;
+ }
+
+exit:
+ if (startupSem != SEM_FAILED)
+ {
+ sem_close(startupSem);
+ }
+ if (continueSem != SEM_FAILED)
+ {
+ sem_close(continueSem);
+ }
+ return result;
+}
+
+/*++
+ Function:
+ GetProcessIdDisambiguationKey
+
+ Get a numeric value that can be used to disambiguate between processes with the same PID,
+ provided that one of them is still running. The numeric value can mean different things
+ on different platforms, so it should not be used for any other purpose. Under the hood,
+ it is implemented based on the creation time of the process.
+--*/
+BOOL
+GetProcessIdDisambiguationKey(DWORD processId, UINT64 *disambiguationKey)
+{
+ if (disambiguationKey == nullptr)
+ {
+ _ASSERTE(!"disambiguationKey argument cannot be null!");
+ return FALSE;
+ }
+
+ *disambiguationKey = 0;
+
+#if defined(__APPLE__)
+
+ // On OS X, we return the process start time expressed in Unix time (the number of seconds
+ // since the start of the Unix epoch).
+ struct kinfo_proc info = {};
+ size_t size = sizeof(info);
+ int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, processId };
+ int ret = ::sysctl(mib, sizeof(mib)/sizeof(*mib), &info, &size, nullptr, 0);
+
+ if (ret == 0)
+ {
+ timeval procStartTime = info.kp_proc.p_starttime;
+ long secondsSinceEpoch = procStartTime.tv_sec;
+
+ *disambiguationKey = secondsSinceEpoch;
+ return TRUE;
+ }
+ else
+ {
+ _ASSERTE(!"Failed to get start time of a process.");
+ return FALSE;
+ }
+
+#elif defined(__NetBSD__)
+
+ // On NetBSD, we return the process start time expressed in Unix time (the number of seconds
+ // since the start of the Unix epoch).
+ kvm_t *kd;
+ int cnt;
+ struct kinfo_proc2 *info;
+
+ kd = kvm_open(nullptr, nullptr, nullptr, KVM_NO_FILES, "kvm_open");
+ if (kd == nullptr)
+ {
+ _ASSERTE(!"Failed to get start time of a process.");
+ return FALSE;
+ }
+
+ info = kvm_getproc2(kd, KERN_PROC_PID, processId, sizeof(struct kinfo_proc2), &cnt);
+ if (info == nullptr || cnt < 1)
+ {
+ kvm_close(kd);
+ _ASSERTE(!"Failed to get start time of a process.");
+ return FALSE;
+ }
+
+ kvm_close(kd);
+
+ long secondsSinceEpoch = info->p_ustart_sec;
+ *disambiguationKey = secondsSinceEpoch;
+
+ return TRUE;
+
+#elif HAVE_PROCFS_STAT
+
+ // Here we read /proc/<pid>/stat file to get the start time for the process.
+ // We return this value (which is expressed in jiffies since boot time).
+
+ // Making something like: /proc/123/stat
+ char statFileName[64];
+
+ INDEBUG(int chars = )
+ snprintf(statFileName, sizeof(statFileName), "/proc/%d/stat", processId);
+ _ASSERTE(chars > 0 && chars <= sizeof(statFileName));
+
+ FILE *statFile = fopen(statFileName, "r");
+ if (statFile == nullptr)
+ {
+ SetLastError(ERROR_INVALID_HANDLE);
+ return FALSE;
+ }
+
+ char *line = nullptr;
+ size_t lineLen = 0;
+ if (getline(&line, &lineLen, statFile) == -1)
+ {
+ _ASSERTE(!"Failed to getline from the stat file for a process.");
+ return FALSE;
+ }
+
+ unsigned long long starttime;
+
+ // According to `man proc`, the second field in the stat file is the filename of the executable,
+ // in parentheses. Tokenizing the stat file using spaces as separators breaks when that name
+ // has spaces in it, so we start using sscanf after skipping everything up to and including the
+ // last closing paren and the space after it.
+ char *scanStartPosition = strrchr(line, ')') + 2;
+
+ // All the format specifiers for the fields in the stat file are provided by 'man proc'.
+ int sscanfRet = sscanf(scanStartPosition,
+ "%*c %*d %*d %*d %*d %*d %*u %*lu %*lu %*lu %*lu %*lu %*lu %*ld %*ld %*ld %*ld %*ld %*ld %llu \n",
+ &starttime);
+
+ if (sscanfRet != 1)
+ {
+ _ASSERTE(!"Failed to parse stat file contents with sscanf.");
+ return FALSE;
+ }
+
+ free(line);
+ fclose(statFile);
+
+ *disambiguationKey = starttime;
+ return TRUE;
+
+#else
+ // If this is not OS X and we don't have /proc, we just return FALSE.
+ WARN("GetProcessIdDisambiguationKey was called but is not implemented on this platform!");
+ return FALSE;
+#endif
+}
+
+/*++
+ Function:
+ PAL_GetTransportPipeName
+
+ Builds the transport pipe names from the process id.
+--*/
+void
+PALAPI
+PAL_GetTransportPipeName(char *name, DWORD id, const char *suffix)
+{
+ UINT64 disambiguationKey = 0;
+ BOOL ret = GetProcessIdDisambiguationKey(id, &disambiguationKey);
+
+ // If GetProcessIdDisambiguationKey failed for some reason, it should set the value
+ // to 0. We expect that anyone else making the pipe name will also fail and thus will
+ // also try to use 0 as the value.
+ _ASSERTE(ret == TRUE || disambiguationKey == 0);
+
+ int chars = _snprintf(name, MAX_DEBUGGER_TRANSPORT_PIPE_NAME_LENGTH, PipeNameFormat, id, disambiguationKey, suffix);
+ _ASSERTE(chars > 0 && chars < MAX_DEBUGGER_TRANSPORT_PIPE_NAME_LENGTH);
+}
+
+/*++
+Function:
+ GetProcessTimes
+
+See MSDN doc.
+--*/
+BOOL
+PALAPI
+GetProcessTimes(
+ IN HANDLE hProcess,
+ OUT LPFILETIME lpCreationTime,
+ OUT LPFILETIME lpExitTime,
+ OUT LPFILETIME lpKernelTime,
+ OUT LPFILETIME lpUserTime)
+{
+ BOOL retval = FALSE;
+ struct rusage resUsage;
+ __int64 calcTime;
+ const __int64 SECS_TO_NS = 1000000000; /* 10^9 */
+ const __int64 USECS_TO_NS = 1000; /* 10^3 */
+
+
+ PERF_ENTRY(GetProcessTimes);
+ ENTRY("GetProcessTimes(hProcess=%p, lpExitTime=%p, lpKernelTime=%p,"
+ "lpUserTime=%p)\n",
+ hProcess, lpCreationTime, lpExitTime, lpKernelTime, lpUserTime );
+
+ /* Make sure hProcess is the current process, this is the only supported
+ case */
+ if(PROCGetProcessIDFromHandle(hProcess)!=GetCurrentProcessId())
+ {
+ ASSERT("GetProcessTimes() does not work on a process other than the "
+ "current process.\n");
+ SetLastError(ERROR_INVALID_HANDLE);
+ goto GetProcessTimesExit;
+ }
+
+ /* First, we need to actually retrieve the relevant statistics from the
+ OS */
+ if (getrusage (RUSAGE_SELF, &resUsage) == -1)
+ {
+ ASSERT("Unable to get resource usage information for the current "
+ "process\n");
+ SetLastError(ERROR_INTERNAL_ERROR);
+ goto GetProcessTimesExit;
+ }
+
+ TRACE ("getrusage User: %ld sec,%ld microsec. Kernel: %ld sec,%ld"
+ " microsec\n",
+ resUsage.ru_utime.tv_sec, resUsage.ru_utime.tv_usec,
+ resUsage.ru_stime.tv_sec, resUsage.ru_stime.tv_usec);
+
+ if (lpUserTime)
+ {
+ /* Get the time of user mode execution, in 100s of nanoseconds */
+ calcTime = (__int64)resUsage.ru_utime.tv_sec * SECS_TO_NS;
+ calcTime += (__int64)resUsage.ru_utime.tv_usec * USECS_TO_NS;
+ calcTime /= 100; /* Produce the time in 100s of ns */
+ /* Assign the time into lpUserTime */
+ lpUserTime->dwLowDateTime = (DWORD)calcTime;
+ lpUserTime->dwHighDateTime = (DWORD)(calcTime >> 32);
+ }
+
+ if (lpKernelTime)
+ {
+ /* Get the time of kernel mode execution, in 100s of nanoseconds */
+ calcTime = (__int64)resUsage.ru_stime.tv_sec * SECS_TO_NS;
+ calcTime += (__int64)resUsage.ru_stime.tv_usec * USECS_TO_NS;
+ calcTime /= 100; /* Produce the time in 100s of ns */
+ /* Assign the time into lpUserTime */
+ lpKernelTime->dwLowDateTime = (DWORD)calcTime;
+ lpKernelTime->dwHighDateTime = (DWORD)(calcTime >> 32);
+ }
+
+ retval = TRUE;
+
+
+GetProcessTimesExit:
+ LOGEXIT("GetProcessTimes returns BOOL %d\n", retval);
+ PERF_EXIT(GetProcessTimes);
+ return (retval);
+}
+
+#define FILETIME_TO_ULONGLONG(f) \
+ (((ULONGLONG)(f).dwHighDateTime << 32) | ((ULONGLONG)(f).dwLowDateTime))
+
+/*++
+Function:
+ PAL_GetCPUBusyTime
+
+The main purpose of this function is to compute the overall CPU utilization
+for the CLR thread pool to regulate the number of I/O completion port
+worker threads.
+Since there is no consistent API on Unix to get the CPU utilization
+from a user process, getrusage and gettimeofday are used to
+compute the current process's CPU utilization instead.
+This function emulates the ThreadpoolMgr::GetCPUBusyTime_NT function in
+win32threadpool.cpp of the CLR.
+
+See MSDN doc for GetSystemTimes.
+--*/
+INT
+PALAPI
+PAL_GetCPUBusyTime(
+ IN OUT PAL_IOCP_CPU_INFORMATION *lpPrevCPUInfo)
+{
+ ULONGLONG nLastRecordedCurrentTime = 0;
+ ULONGLONG nLastRecordedUserTime = 0;
+ ULONGLONG nLastRecordedKernelTime = 0;
+ ULONGLONG nKernelTime = 0;
+ ULONGLONG nUserTime = 0;
+ ULONGLONG nCurrentTime = 0;
+ ULONGLONG nCpuBusyTime = 0;
+ ULONGLONG nCpuTotalTime = 0;
+ DWORD nReading = 0;
+ struct rusage resUsage;
+ struct timeval tv;
+ static DWORD dwNumberOfProcessors = 0;
+
+ if (dwNumberOfProcessors <= 0)
+ {
+ SYSTEM_INFO SystemInfo;
+ GetSystemInfo(&SystemInfo);
+ dwNumberOfProcessors = SystemInfo.dwNumberOfProcessors;
+ if (dwNumberOfProcessors <= 0)
+ {
+ return 0;
+ }
+ }
+
+ if (getrusage(RUSAGE_SELF, &resUsage) == -1)
+ {
+ ASSERT("getrusage() failed; errno is %d (%s)\n", errno, strerror(errno));
+ return 0;
+ }
+ else
+ {
+ nKernelTime = (ULONGLONG)resUsage.ru_stime.tv_sec*tccSecondsTo100NanoSeconds +
+ resUsage.ru_stime.tv_usec*tccMicroSecondsTo100NanoSeconds;
+ nUserTime = (ULONGLONG)resUsage.ru_utime.tv_sec*tccSecondsTo100NanoSeconds +
+ resUsage.ru_utime.tv_usec*tccMicroSecondsTo100NanoSeconds;
+ }
+
+ if (gettimeofday(&tv, NULL) == -1)
+ {
+ ASSERT("gettimeofday() failed; errno is %d (%s)\n", errno, strerror(errno));
+ return 0;
+ }
+ else
+ {
+ nCurrentTime = (ULONGLONG)tv.tv_sec*tccSecondsTo100NanoSeconds +
+ tv.tv_usec*tccMicroSecondsTo100NanoSeconds;
+ }
+
+ nLastRecordedCurrentTime = FILETIME_TO_ULONGLONG(lpPrevCPUInfo->LastRecordedTime.ftLastRecordedCurrentTime);
+ nLastRecordedUserTime = FILETIME_TO_ULONGLONG(lpPrevCPUInfo->ftLastRecordedUserTime);
+ nLastRecordedKernelTime = FILETIME_TO_ULONGLONG(lpPrevCPUInfo->ftLastRecordedKernelTime);
+
+ if (nCurrentTime > nLastRecordedCurrentTime)
+ {
+ nCpuTotalTime = (nCurrentTime - nLastRecordedCurrentTime);
+#if HAVE_THREAD_SELF || HAVE__LWP_SELF || HAVE_VM_READ
+ // For systems that run multiple threads of a process on multiple processors,
+ // the accumulated userTime and kernelTime of this process may exceed
+ // the elapsed time. In this case, the cpuTotalTime needs to be adjusted
+ // according to number of processors so that the cpu utilization
+ // will not be greater than 100.
+ nCpuTotalTime *= dwNumberOfProcessors;
+#endif // HAVE_THREAD_SELF || HAVE__LWP_SELF || HAVE_VM_READ
+ }
+
+ if (nUserTime >= nLastRecordedUserTime &&
+ nKernelTime >= nLastRecordedKernelTime)
+ {
+ nCpuBusyTime =
+ (nUserTime - nLastRecordedUserTime)+
+ (nKernelTime - nLastRecordedKernelTime);
+ }
+
+ if (nCpuTotalTime > 0 && nCpuBusyTime > 0)
+ {
+ nReading = (DWORD)((nCpuBusyTime*100)/nCpuTotalTime);
+ TRACE("PAL_GetCPUBusyTime: nCurrentTime=%lld, nKernelTime=%lld, nUserTime=%lld, nReading=%d\n",
+ nCurrentTime, nKernelTime, nUserTime, nReading);
+ }
+
+ if (nReading > 100)
+ {
+ ERROR("cpu utilization(%d) > 100\n", nReading);
+ }
+
+ lpPrevCPUInfo->LastRecordedTime.ftLastRecordedCurrentTime.dwLowDateTime = (DWORD)nCurrentTime;
+ lpPrevCPUInfo->LastRecordedTime.ftLastRecordedCurrentTime.dwHighDateTime = (DWORD)(nCurrentTime >> 32);
+
+ lpPrevCPUInfo->ftLastRecordedUserTime.dwLowDateTime = (DWORD)nUserTime;
+ lpPrevCPUInfo->ftLastRecordedUserTime.dwHighDateTime = (DWORD)(nUserTime >> 32);
+
+ lpPrevCPUInfo->ftLastRecordedKernelTime.dwLowDateTime = (DWORD)nKernelTime;
+ lpPrevCPUInfo->ftLastRecordedKernelTime.dwHighDateTime = (DWORD)(nKernelTime >> 32);
+
+ return (DWORD)nReading;
+}
+
+/*++
+Function:
+ GetCommandLineW
+
+See MSDN doc.
+--*/
+LPWSTR
+PALAPI
+GetCommandLineW(
+ VOID)
+{
+ PERF_ENTRY(GetCommandLineW);
+ ENTRY("GetCommandLineW()\n");
+
+ LPWSTR lpwstr = g_lpwstrCmdLine ? g_lpwstrCmdLine : (LPWSTR)W("");
+
+ LOGEXIT("GetCommandLineW returns LPWSTR %p (%S)\n",
+ g_lpwstrCmdLine,
+ lpwstr);
+ PERF_EXIT(GetCommandLineW);
+
+ return lpwstr;
+}
+
+/*++
+Function:
+ OpenProcess
+
+See MSDN doc.
+
+Notes :
+dwDesiredAccess is ignored (all supported operations will be allowed)
+bInheritHandle is ignored (no inheritance)
+--*/
+HANDLE
+PALAPI
+OpenProcess(
+ DWORD dwDesiredAccess,
+ BOOL bInheritHandle,
+ DWORD dwProcessId)
+{
+ PAL_ERROR palError;
+ CPalThread *pThread;
+ IPalObject *pobjProcess = NULL;
+ IPalObject *pobjProcessRegistered = NULL;
+ IDataLock *pDataLock;
+ CProcProcessLocalData *pLocalData;
+ CObjectAttributes oa;
+ HANDLE hProcess = NULL;
+
+ PERF_ENTRY(OpenProcess);
+ ENTRY("OpenProcess(dwDesiredAccess=0x%08x, bInheritHandle=%d, "
+ "dwProcessId = 0x%08x)\n",
+ dwDesiredAccess, bInheritHandle, dwProcessId );
+
+ pThread = InternalGetCurrentThread();
+
+ if (0 == dwProcessId)
+ {
+ palError = ERROR_INVALID_PARAMETER;
+ goto OpenProcessExit;
+ }
+
+ palError = g_pObjectManager->AllocateObject(
+ pThread,
+ &otProcess,
+ &oa,
+ &pobjProcess
+ );
+
+ if (NO_ERROR != palError)
+ {
+ goto OpenProcessExit;
+ }
+
+ palError = pobjProcess->GetProcessLocalData(
+ pThread,
+ WriteLock,
+ &pDataLock,
+ reinterpret_cast<void **>(&pLocalData)
+ );
+
+ if (NO_ERROR != palError)
+ {
+ goto OpenProcessExit;
+ }
+
+ pLocalData->dwProcessId = dwProcessId;
+ pDataLock->ReleaseLock(pThread, TRUE);
+
+ palError = g_pObjectManager->RegisterObject(
+ pThread,
+ pobjProcess,
+ &aotProcess,
+ dwDesiredAccess,
+ &hProcess,
+ &pobjProcessRegistered
+ );
+
+ //
+ // pobjProcess was invalidated by the above call, so NULL
+ // it out here
+ //
+
+ pobjProcess = NULL;
+
+ //
+ // TODO: check to see if the process actually exists?
+ //
+
+OpenProcessExit:
+
+ if (NULL != pobjProcess)
+ {
+ pobjProcess->ReleaseReference(pThread);
+ }
+
+ if (NULL != pobjProcessRegistered)
+ {
+ pobjProcessRegistered->ReleaseReference(pThread);
+ }
+
+ if (NO_ERROR != palError)
+ {
+ pThread->SetLastError(palError);
+ }
+
+ LOGEXIT("OpenProcess returns HANDLE %p\n", hProcess);
+ PERF_EXIT(OpenProcess);
+ return hProcess;
+}
+
+/*++
+Function:
+ EnumProcessModules
+
+Abstract
+ Returns a process's module list
+
+Return
+ TRUE if it succeeded, FALSE otherwise
+
+Notes
+ This API is tricky because the module handles are never closed/freed so there can't be any
+ allocations for the module handle or name strings, etc. The "handles" are actually the base
+ addresses of the modules. The module handles should only be used by GetModuleFileNameExW
+ below.
+--*/
+BOOL
+PALAPI
+EnumProcessModules(
+ IN HANDLE hProcess,
+ OUT HMODULE *lphModule,
+ IN DWORD cb,
+ OUT LPDWORD lpcbNeeded)
+{
+ PERF_ENTRY(EnumProcessModules);
+ ENTRY("EnumProcessModules(hProcess=0x%08x, cb=%d)\n", hProcess, cb);
+
+ BOOL result = TRUE;
+ DWORD count = 0;
+ ProcessModules *listHead = GetProcessModulesFromHandle(hProcess, &count);
+ if (listHead != NULL)
+ {
+ for (ProcessModules *entry = listHead; entry != NULL; entry = entry->Next)
+ {
+ if (cb <= 0)
+ {
+ break;
+ }
+ cb -= sizeof(HMODULE);
+ *lphModule = (HMODULE)entry->BaseAddress;
+ lphModule++;
+ }
+ }
+ else
+ {
+ result = FALSE;
+ }
+
+ if (lpcbNeeded)
+ {
+ // This return value isn't exactly up to spec because it should return the actual
+ // number of modules in the process even if "cb" isn't big enough but for our use
+ // it works just fine.
+ (*lpcbNeeded) = count * sizeof(HMODULE);
+ }
+
+ LOGEXIT("EnumProcessModules returns %d\n", result);
+ PERF_EXIT(EnumProcessModules);
+ return result;
+}
+
+/*++
+Function:
+ GetModuleFileNameExW
+
+ Used only with module handles returned from EnumProcessModule (for dbgshim).
+
+--*/
+DWORD
+PALAPI
+GetModuleFileNameExW(
+ IN HANDLE hProcess,
+ IN HMODULE hModule,
+ OUT LPWSTR lpFilename,
+ IN DWORD nSize
+)
+{
+ DWORD result = 0;
+ DWORD count = 0;
+
+ ProcessModules *listHead = GetProcessModulesFromHandle(hProcess, &count);
+ if (listHead != NULL)
+ {
+ for (ProcessModules *entry = listHead; entry != NULL; entry = entry->Next)
+ {
+ if ((HMODULE)entry->BaseAddress == hModule)
+ {
+ // Convert CHAR string into WCHAR string
+ result = MultiByteToWideChar(CP_ACP, 0, entry->Name, -1, lpFilename, nSize);
+ break;
+ }
+ }
+ }
+
+ return result;
+}
+
+/*++
+Function:
+ GetProcessModulesFromHandle
+
+Abstract
+ Returns a process's module list
+
+Return
+ ProcessModules * list
+
+--*/
+ProcessModules *
+GetProcessModulesFromHandle(
+ IN HANDLE hProcess,
+ OUT LPDWORD lpCount)
+{
+ CPalThread* pThread = InternalGetCurrentThread();
+ CProcProcessLocalData *pLocalData = NULL;
+ ProcessModules *listHead = NULL;
+ IPalObject *pobjProcess = NULL;
+ IDataLock *pDataLock = NULL;
+ PAL_ERROR palError = NO_ERROR;
+ DWORD dwProcessId = 0;
+ DWORD count = 0;
+
+ _ASSERTE(lpCount != NULL);
+
+ if (hPseudoCurrentProcess == hProcess)
+ {
+ pobjProcess = g_pobjProcess;
+ }
+ else
+ {
+ CAllowedObjectTypes aotProcess(otiProcess);
+
+ palError = g_pObjectManager->ReferenceObjectByHandle(
+ pThread,
+ hProcess,
+ &aotProcess,
+ 0,
+ &pobjProcess);
+
+ if (NO_ERROR != palError)
+ {
+ pThread->SetLastError(ERROR_INVALID_HANDLE);
+ goto exit;
+ }
+ }
+
+ palError = pobjProcess->GetProcessLocalData(
+ pThread,
+ WriteLock,
+ &pDataLock,
+ reinterpret_cast<void **>(&pLocalData));
+
+ _ASSERTE(NO_ERROR == palError);
+
+ dwProcessId = pLocalData->dwProcessId;
+ listHead = pLocalData->pProcessModules;
+ count = pLocalData->cProcessModules;
+
+ // If the module list hasn't been created yet, create it now
+ if (listHead == NULL)
+ {
+ listHead = CreateProcessModules(dwProcessId, &count);
+ if (listHead == NULL)
+ {
+ pThread->SetLastError(ERROR_INVALID_PARAMETER);
+ goto exit;
+ }
+
+ if (pLocalData != NULL)
+ {
+ pLocalData->pProcessModules = listHead;
+ pLocalData->cProcessModules = count;
+ }
+ }
+
+exit:
+ if (NULL != pDataLock)
+ {
+ pDataLock->ReleaseLock(pThread, TRUE);
+ }
+ if (NULL != pobjProcess)
+ {
+ pobjProcess->ReleaseReference(pThread);
+ }
+
+ *lpCount = count;
+ return listHead;
+}
+
+/*++
+Function:
+ CreateProcessModules
+
+Abstract
+ Returns a process's module list
+
+Return
+ ProcessModules * list
+
+--*/
+ProcessModules *
+CreateProcessModules(
+ IN DWORD dwProcessId,
+ OUT LPDWORD lpCount)
+{
+ ProcessModules *listHead = NULL;
+ _ASSERTE(lpCount != NULL);
+
+#if defined(__APPLE__)
+
+ // For OS X, the "vmmap" command outputs something similar to the /proc/*/maps file so popen the
+ // command and read the relevant lines:
+ //
+ // ...
+ // ==== regions for process 347 (non-writable and writable regions are interleaved)
+ // REGION TYPE START - END [ VSIZE] PRT/MAX SHRMOD REGION DETAIL
+ // __TEXT 000000010446d000-0000000104475000 [ 32K] r-x/rwx SM=COW /Users/mikem/coreclr/bin/Product/OSx.x64.Debug/corerun
+ // __DATA 0000000104475000-0000000104476000 [ 4K] rw-/rwx SM=PRV /Users/mikem/coreclr/bin/Product/OSx.x64.Debug/corerun
+ // __LINKEDIT 0000000104476000-000000010447a000 [ 16K] r--/rwx SM=COW /Users/mikem/coreclr/bin/Product/OSx.x64.Debug/corerun
+ // Kernel Alloc Once 000000010447a000-000000010447b000 [ 4K] rw-/rwx SM=PRV
+ // MALLOC (admin) 000000010447b000-000000010447c000 [ 4K] r--/rwx SM=ZER
+ // ...
+ // MALLOC (admin) 00000001044ab000-00000001044ac000 [ 4K] r--/rwx SM=PRV
+ // __TEXT 00000001044ac000-0000000104c84000 [ 8032K] r-x/rwx SM=COW /Users/mikem/coreclr/bin/Product/OSx.x64.Debug/libcoreclr.dylib
+ // __TEXT 0000000104c84000-0000000104c85000 [ 4K] rwx/rwx SM=PRV /Users/mikem/coreclr/bin/Product/OSx.x64.Debug/libcoreclr.dylib
+ // __TEXT 0000000104c85000-000000010513b000 [ 4824K] r-x/rwx SM=COW /Users/mikem/coreclr/bin/Product/OSx.x64.Debug/libcoreclr.dylib
+ // __TEXT 000000010513b000-000000010513c000 [ 4K] rwx/rwx SM=PRV /Users/mikem/coreclr/bin/Product/OSx.x64.Debug/libcoreclr.dylib
+ // __TEXT 000000010513c000-000000010516f000 [ 204K] r-x/rwx SM=COW /Users/mikem/coreclr/bin/Product/OSx.x64.Debug/libcoreclr.dylib
+ // __DATA 000000010516f000-00000001051ce000 [ 380K] rw-/rwx SM=COW /Users/mikem/coreclr/bin/Product/OSx.x64.Debug/libcoreclr.dylib
+ // __DATA 00000001051ce000-00000001051fa000 [ 176K] rw-/rwx SM=PRV /Users/mikem/coreclr/bin/Product/OSx.x64.Debug/libcoreclr.dylib
+ // __LINKEDIT 00000001051fa000-0000000105bac000 [ 9928K] r--/rwx SM=COW /Users/mikem/coreclr/bin/Product/OSx.x64.Debug/libcoreclr.dylib
+ // VM_ALLOCATE 0000000105bac000-0000000105bad000 [ 4K] r--/rw- SM=SHM
+ // MALLOC (admin) 0000000105bad000-0000000105bae000 [ 4K] r--/rwx SM=ZER
+ // MALLOC 0000000105bae000-0000000105baf000 [ 4K] rw-/rwx SM=ZER
+ char *line = NULL;
+ size_t lineLen = 0;
+ int count = 0;
+ ssize_t read;
+
+ char vmmapCommand[100];
+ int chars = snprintf(vmmapCommand, sizeof(vmmapCommand), "/usr/bin/vmmap -interleaved %d -wide", dwProcessId);
+ _ASSERTE(chars > 0 && chars <= sizeof(vmmapCommand));
+
+ FILE *vmmapFile = popen(vmmapCommand, "r");
+ if (vmmapFile == NULL)
+ {
+ goto exit;
+ }
+
+ // Reading maps file line by line
+ while ((read = getline(&line, &lineLen, vmmapFile)) != -1)
+ {
+ void *startAddress, *endAddress;
+ char moduleName[PATH_MAX];
+ int size;
+
+ if (sscanf(line, "__TEXT %p-%p [ %dK] %*[-/rwxsp] SM=%*[A-Z] %s\n", &startAddress, &endAddress, &size, moduleName) == 4)
+ {
+ bool dup = false;
+ for (ProcessModules *entry = listHead; entry != NULL; entry = entry->Next)
+ {
+ if (strcmp(moduleName, entry->Name) == 0)
+ {
+ dup = true;
+ break;
+ }
+ }
+
+ if (!dup)
+ {
+ int cbModuleName = strlen(moduleName) + 1;
+ ProcessModules *entry = (ProcessModules *)InternalMalloc(sizeof(ProcessModules) + cbModuleName);
+ if (entry == NULL)
+ {
+ DestroyProcessModules(listHead);
+ listHead = NULL;
+ count = 0;
+ break;
+ }
+ strcpy_s(entry->Name, cbModuleName, moduleName);
+ entry->BaseAddress = startAddress;
+ entry->Next = listHead;
+ listHead = entry;
+ count++;
+ }
+ }
+ }
+
+ *lpCount = count;
+
+ free(line); // We didn't allocate line, but as per contract of getline we should free it
+ pclose(vmmapFile);
+exit:
+
+#elif HAVE_PROCFS_MAPS
+
+ // Here we read /proc/<pid>/maps file in order to parse it and figure out what it says
+ // about a library we are looking for. This file looks something like this:
+ //
+ // [address] [perms] [offset] [dev] [inode] [pathname] - HEADER is not preset in an actual file
+ //
+ // 35b1800000-35b1820000 r-xp 00000000 08:02 135522 /usr/lib64/ld-2.15.so
+ // 35b1a1f000-35b1a20000 r--p 0001f000 08:02 135522 /usr/lib64/ld-2.15.so
+ // 35b1a20000-35b1a21000 rw-p 00020000 08:02 135522 /usr/lib64/ld-2.15.so
+ // 35b1a21000-35b1a22000 rw-p 00000000 00:00 0 [heap]
+ // 35b1c00000-35b1dac000 r-xp 00000000 08:02 135870 /usr/lib64/libc-2.15.so
+ // 35b1dac000-35b1fac000 ---p 001ac000 08:02 135870 /usr/lib64/libc-2.15.so
+ // 35b1fac000-35b1fb0000 r--p 001ac000 08:02 135870 /usr/lib64/libc-2.15.so
+ // 35b1fb0000-35b1fb2000 rw-p 001b0000 08:02 135870 /usr/lib64/libc-2.15.so
+
+ // Making something like: /proc/123/maps
+ char mapFileName[100];
+ char *line = NULL;
+ size_t lineLen = 0;
+ int count = 0;
+ ssize_t read;
+
+ INDEBUG(int chars = )
+ snprintf(mapFileName, sizeof(mapFileName), "/proc/%d/maps", dwProcessId);
+ _ASSERTE(chars > 0 && chars <= sizeof(mapFileName));
+
+ FILE *mapsFile = fopen(mapFileName, "r");
+ if (mapsFile == NULL)
+ {
+ goto exit;
+ }
+
+ // Reading maps file line by line
+ while ((read = getline(&line, &lineLen, mapsFile)) != -1)
+ {
+ void *startAddress, *endAddress, *offset;
+ int devHi, devLo, inode;
+ char moduleName[PATH_MAX];
+
+ if (sscanf(line, "%p-%p %*[-rwxsp] %p %x:%x %d %s\n", &startAddress, &endAddress, &offset, &devHi, &devLo, &inode, moduleName) == 7)
+ {
+ if (inode != 0)
+ {
+ bool dup = false;
+ for (ProcessModules *entry = listHead; entry != NULL; entry = entry->Next)
+ {
+ if (strcmp(moduleName, entry->Name) == 0)
+ {
+ dup = true;
+ break;
+ }
+ }
+
+ if (!dup)
+ {
+ int cbModuleName = strlen(moduleName) + 1;
+ ProcessModules *entry = (ProcessModules *)InternalMalloc(sizeof(ProcessModules) + cbModuleName);
+ if (entry == NULL)
+ {
+ DestroyProcessModules(listHead);
+ listHead = NULL;
+ count = 0;
+ break;
+ }
+ strcpy_s(entry->Name, cbModuleName, moduleName);
+ entry->BaseAddress = startAddress;
+ entry->Next = listHead;
+ listHead = entry;
+ count++;
+ }
+ }
+ }
+ }
+
+ *lpCount = count;
+
+ free(line); // We didn't allocate line, but as per contract of getline we should free it
+ fclose(mapsFile);
+exit:
+
+#else
+ _ASSERTE(!"Not implemented on this platform");
+#endif
+ return listHead;
+}
+
+/*++
+Function:
+ DestroyProcessModules
+
+Abstract
+ Cleans up the process module table.
+
+Return
+ None
+
+--*/
+void
+DestroyProcessModules(IN ProcessModules *listHead)
+{
+ for (ProcessModules *entry = listHead; entry != NULL; )
+ {
+ ProcessModules *next = entry->Next;
+ free(entry);
+ entry = next;
+ }
+}
+
+/*++
+Function:
+ PROCNotifyProcessShutdown
+
+ Calls the abort handler to do any shutdown cleanup. Call be called
+ from the unhandled native exception handler.
+
+(no return value)
+--*/
+__attribute__((destructor))
+void PROCNotifyProcessShutdown()
+{
+ // Call back into the coreclr to clean up the debugger transport pipes
+ PSHUTDOWN_CALLBACK callback = InterlockedExchangePointer(&g_shutdownCallback, NULL);
+ if (callback != NULL)
+ {
+ callback();
+ }
+}
+
+/*++
+Function:
+ PROCAbort()
+
+ Aborts the process after calling the shutdown cleanup handler. This function
+ should be called instead of calling abort() directly.
+
+ Does not return
+--*/
+PAL_NORETURN
+void
+PROCAbort()
+{
+ PROCNotifyProcessShutdown();
+ abort();
+}
+
+/*++
+Function:
+ InitializeFlushProcessWriteBuffers
+
+Abstract
+ This function initializes data structures needed for the FlushProcessWriteBuffers
+Return
+ TRUE if it succeeded, FALSE otherwise
+--*/
+BOOL InitializeFlushProcessWriteBuffers()
+{
+ // Verify that the s_helperPage is really aligned to the VIRTUAL_PAGE_SIZE
+ _ASSERTE((((SIZE_T)s_helperPage) & (VIRTUAL_PAGE_SIZE - 1)) == 0);
+
+ // Locking the page ensures that it stays in memory during the two mprotect
+ // calls in the FlushProcessWriteBuffers below. If the page was unmapped between
+ // those calls, they would not have the expected effect of generating IPI.
+ int status = mlock(s_helperPage, VIRTUAL_PAGE_SIZE);
+
+ if (status != 0)
+ {
+ return FALSE;
+ }
+
+ status = pthread_mutex_init(&flushProcessWriteBuffersMutex, NULL);
+ if (status != 0)
+ {
+ munlock(s_helperPage, VIRTUAL_PAGE_SIZE);
+ }
+
+ return status == 0;
+}
+
+#define FATAL_ASSERT(e, msg) \
+ do \
+ { \
+ if (!(e)) \
+ { \
+ fprintf(stderr, "FATAL ERROR: " msg); \
+ PROCAbort(); \
+ } \
+ } \
+ while(0)
+
+/*++
+Function:
+ FlushProcessWriteBuffers
+
+See MSDN doc.
+--*/
+VOID
+PALAPI
+FlushProcessWriteBuffers()
+{
+ int status = pthread_mutex_lock(&flushProcessWriteBuffersMutex);
+ FATAL_ASSERT(status == 0, "Failed to lock the flushProcessWriteBuffersMutex lock");
+
+ // Changing a helper memory page protection from read / write to no access
+ // causes the OS to issue IPI to flush TLBs on all processors. This also
+ // results in flushing the processor buffers.
+ status = mprotect(s_helperPage, VIRTUAL_PAGE_SIZE, PROT_READ | PROT_WRITE);
+ FATAL_ASSERT(status == 0, "Failed to change helper page protection to read / write");
+
+ // Ensure that the page is dirty before we change the protection so that
+ // we prevent the OS from skipping the global TLB flush.
+ InterlockedIncrement(s_helperPage);
+
+ status = mprotect(s_helperPage, VIRTUAL_PAGE_SIZE, PROT_NONE);
+ FATAL_ASSERT(status == 0, "Failed to change helper page protection to no access");
+
+ status = pthread_mutex_unlock(&flushProcessWriteBuffersMutex);
+ FATAL_ASSERT(status == 0, "Failed to unlock the flushProcessWriteBuffersMutex lock");
+}
+
+/*++
+Function:
+ PROCGetProcessIDFromHandle
+
+Abstract
+ Return the process ID from a process handle
+
+Parameter
+ hProcess: process handle
+
+Return
+ Return the process ID, or 0 if it's not a valid handle
+--*/
+DWORD
+PROCGetProcessIDFromHandle(
+ HANDLE hProcess)
+{
+ PAL_ERROR palError;
+ IPalObject *pobjProcess = NULL;
+ CPalThread *pThread = InternalGetCurrentThread();
+
+ DWORD dwProcessId = 0;
+
+ if (hPseudoCurrentProcess == hProcess)
+ {
+ dwProcessId = gPID;
+ goto PROCGetProcessIDFromHandleExit;
+ }
+
+
+ palError = g_pObjectManager->ReferenceObjectByHandle(
+ pThread,
+ hProcess,
+ &aotProcess,
+ 0,
+ &pobjProcess
+ );
+
+ if (NO_ERROR == palError)
+ {
+ IDataLock *pDataLock;
+ CProcProcessLocalData *pLocalData;
+
+ palError = pobjProcess->GetProcessLocalData(
+ pThread,
+ ReadLock,
+ &pDataLock,
+ reinterpret_cast<void **>(&pLocalData)
+ );
+
+ if (NO_ERROR == palError)
+ {
+ dwProcessId = pLocalData->dwProcessId;
+ pDataLock->ReleaseLock(pThread, FALSE);
+ }
+
+ pobjProcess->ReleaseReference(pThread);
+ }
+
+PROCGetProcessIDFromHandleExit:
+
+ return dwProcessId;
+}
+
+PAL_ERROR
+CorUnix::InitializeProcessData(
+ void
+ )
+{
+ PAL_ERROR palError = NO_ERROR;
+ bool fLockInitialized = FALSE;
+
+ pGThreadList = NULL;
+ g_dwThreadCount = 0;
+
+ InternalInitializeCriticalSection(&g_csProcess);
+ fLockInitialized = TRUE;
+
+ if (NO_ERROR != palError)
+ {
+ if (fLockInitialized)
+ {
+ InternalDeleteCriticalSection(&g_csProcess);
+ }
+ }
+
+ return palError;
+}
+
+/*++
+Function
+ InitializeProcessCommandLine
+
+Abstract
+ Initializes (or re-initializes) the saved command line and exe path.
+
+Parameter
+ lpwstrCmdLine
+ lpwstrFullPath
+
+Return
+ PAL_ERROR
+
+Notes
+ This function takes ownership of lpwstrCmdLine, but not of lpwstrFullPath
+--*/
+
+PAL_ERROR
+CorUnix::InitializeProcessCommandLine(
+ LPWSTR lpwstrCmdLine,
+ LPWSTR lpwstrFullPath
+)
+{
+ PAL_ERROR palError = NO_ERROR;
+ LPWSTR initial_dir = NULL;
+
+ //
+ // Save the command line and initial directory
+ //
+
+ if (lpwstrFullPath)
+ {
+ LPWSTR lpwstr = PAL_wcsrchr(lpwstrFullPath, '/');
+ lpwstr[0] = '\0';
+ INT n = lstrlenW(lpwstrFullPath) + 1;
+
+ int iLen = n;
+ initial_dir = reinterpret_cast<LPWSTR>(InternalMalloc(iLen*sizeof(WCHAR)));
+ if (NULL == initial_dir)
+ {
+ ERROR("malloc() failed! (initial_dir) \n");
+ palError = ERROR_NOT_ENOUGH_MEMORY;
+ goto exit;
+ }
+
+ if (wcscpy_s(initial_dir, iLen, lpwstrFullPath) != SAFECRT_SUCCESS)
+ {
+ ERROR("wcscpy_s failed!\n");
+ free(initial_dir);
+ palError = ERROR_INTERNAL_ERROR;
+ goto exit;
+ }
+
+ lpwstr[0] = '/';
+
+ free(g_lpwstrAppDir);
+ g_lpwstrAppDir = initial_dir;
+ }
+
+ free(g_lpwstrCmdLine);
+ g_lpwstrCmdLine = lpwstrCmdLine;
+
+exit:
+ return palError;
+}
+
+
+/*++
+Function:
+ CreateInitialProcessAndThreadObjects
+
+Abstract
+ Creates the IPalObjects that represent the current process
+ and the initial thread
+
+Parameter
+ pThread - the initial thread
+
+Return
+ PAL_ERROR
+--*/
+
+PAL_ERROR
+CorUnix::CreateInitialProcessAndThreadObjects(
+ CPalThread *pThread
+ )
+{
+ PAL_ERROR palError = NO_ERROR;
+ HANDLE hThread;
+ IPalObject *pobjProcess = NULL;
+ IDataLock *pDataLock;
+ CProcProcessLocalData *pLocalData;
+ CObjectAttributes oa;
+ HANDLE hProcess;
+
+ //
+ // Create initial thread object
+ //
+
+ palError = CreateThreadObject(pThread, pThread, &hThread);
+ if (NO_ERROR != palError)
+ {
+ goto CreateInitialProcessAndThreadObjectsExit;
+ }
+
+ //
+ // This handle isn't needed
+ //
+
+ (void) g_pObjectManager->RevokeHandle(pThread, hThread);
+
+ //
+ // Create and initialize process object
+ //
+
+ palError = g_pObjectManager->AllocateObject(
+ pThread,
+ &otProcess,
+ &oa,
+ &pobjProcess
+ );
+
+ if (NO_ERROR != palError)
+ {
+ ERROR("Unable to allocate process object");
+ goto CreateInitialProcessAndThreadObjectsExit;
+ }
+
+ palError = pobjProcess->GetProcessLocalData(
+ pThread,
+ WriteLock,
+ &pDataLock,
+ reinterpret_cast<void **>(&pLocalData)
+ );
+
+ if (NO_ERROR != palError)
+ {
+ ASSERT("Unable to access local data");
+ goto CreateInitialProcessAndThreadObjectsExit;
+ }
+
+ pLocalData->dwProcessId = gPID;
+ pLocalData->ps = PS_RUNNING;
+ pDataLock->ReleaseLock(pThread, TRUE);
+
+ palError = g_pObjectManager->RegisterObject(
+ pThread,
+ pobjProcess,
+ &aotProcess,
+ PROCESS_ALL_ACCESS,
+ &hProcess,
+ &g_pobjProcess
+ );
+
+ //
+ // pobjProcess is invalidated by the call to RegisterObject, so
+ // NULL it out here to prevent it from being released later
+ //
+
+ pobjProcess = NULL;
+
+ if (NO_ERROR != palError)
+ {
+ ASSERT("Failure registering process object");
+ goto CreateInitialProcessAndThreadObjectsExit;
+ }
+
+ //
+ // There's no need to keep this handle around, so revoke
+ // it now
+ //
+
+ g_pObjectManager->RevokeHandle(pThread, hProcess);
+
+CreateInitialProcessAndThreadObjectsExit:
+
+ if (NULL != pobjProcess)
+ {
+ pobjProcess->ReleaseReference(pThread);
+ }
+
+ return palError;
+}
+
+
+/*++
+Function:
+ PROCCleanupInitialProcess
+
+Abstract
+ Cleanup all the structures for the initial process.
+
+Parameter
+ VOID
+
+Return
+ VOID
+
+--*/
+VOID
+PROCCleanupInitialProcess(VOID)
+{
+ CPalThread *pThread = InternalGetCurrentThread();
+
+ InternalEnterCriticalSection(pThread, &g_csProcess);
+
+ /* Free the application directory */
+ free(g_lpwstrAppDir);
+
+ /* Free the stored command line */
+ free(g_lpwstrCmdLine);
+
+ InternalLeaveCriticalSection(pThread, &g_csProcess);
+
+ //
+ // Object manager shutdown will handle freeing the underlying
+ // thread and process data
+ //
+
+}
+
+/*++
+Function:
+ PROCAddThread
+
+Abstract
+ Add a thread to the thread list of the current process
+
+Parameter
+ pThread: Thread object
+
+--*/
+void
+CorUnix::PROCAddThread(
+ CPalThread *pCurrentThread,
+ CPalThread *pTargetThread
+ )
+{
+ /* protect the access of the thread list with critical section for
+ mutithreading access */
+ InternalEnterCriticalSection(pCurrentThread, &g_csProcess);
+
+ pTargetThread->SetNext(pGThreadList);
+ pGThreadList = pTargetThread;
+ g_dwThreadCount += 1;
+
+ TRACE("Thread 0x%p (id %#x) added to the process thread list\n",
+ pTargetThread, pTargetThread->GetThreadId());
+
+ InternalLeaveCriticalSection(pCurrentThread, &g_csProcess);
+}
+
+
+/*++
+Function:
+ PROCRemoveThread
+
+Abstract
+ Remove a thread form the thread list of the current process
+
+Parameter
+ CPalThread *pThread : thread object to remove
+
+(no return value)
+--*/
+void
+CorUnix::PROCRemoveThread(
+ CPalThread *pCurrentThread,
+ CPalThread *pTargetThread
+ )
+{
+ CPalThread *curThread, *prevThread;
+
+ /* protect the access of the thread list with critical section for
+ mutithreading access */
+ InternalEnterCriticalSection(pCurrentThread, &g_csProcess);
+
+ curThread = pGThreadList;
+
+ /* if thread list is empty */
+ if (curThread == NULL)
+ {
+ ASSERT("Thread list is empty.\n");
+ goto EXIT;
+ }
+
+ /* do we remove the first thread? */
+ if (curThread == pTargetThread)
+ {
+ pGThreadList = curThread->GetNext();
+ TRACE("Thread 0x%p (id %#x) removed from the process thread list\n",
+ pTargetThread, pTargetThread->GetThreadId());
+ goto EXIT;
+ }
+
+ prevThread = curThread;
+ curThread = curThread->GetNext();
+ /* find the thread to remove */
+ while (curThread != NULL)
+ {
+ if (curThread == pTargetThread)
+ {
+ /* found, fix the chain list */
+ prevThread->SetNext(curThread->GetNext());
+ g_dwThreadCount -= 1;
+ TRACE("Thread %p removed from the process thread list\n", pTargetThread);
+ goto EXIT;
+ }
+
+ prevThread = curThread;
+ curThread = curThread->GetNext();
+ }
+
+ WARN("Thread %p not removed (it wasn't found in the list)\n", pTargetThread);
+
+EXIT:
+ InternalLeaveCriticalSection(pCurrentThread, &g_csProcess);
+}
+
+
+/*++
+Function:
+ PROCGetNumberOfThreads
+
+Abstract
+ Return the number of threads in the thread list.
+
+Parameter
+ void
+
+Return
+ the number of threads.
+--*/
+INT
+CorUnix::PROCGetNumberOfThreads(
+ void)
+{
+ return g_dwThreadCount;
+}
+
+
+/*++
+Function:
+ PROCProcessLock
+
+Abstract
+ Enter the critical section associated to the current process
+
+Parameter
+ void
+
+Return
+ void
+--*/
+VOID
+PROCProcessLock(
+ VOID)
+{
+ CPalThread * pThread =
+ (PALIsThreadDataInitialized() ? InternalGetCurrentThread() : NULL);
+
+ InternalEnterCriticalSection(pThread, &g_csProcess);
+}
+
+
+/*++
+Function:
+ PROCProcessUnlock
+
+Abstract
+ Leave the critical section associated to the current process
+
+Parameter
+ void
+
+Return
+ void
+--*/
+VOID
+PROCProcessUnlock(
+ VOID)
+{
+ CPalThread * pThread =
+ (PALIsThreadDataInitialized() ? InternalGetCurrentThread() : NULL);
+
+ InternalLeaveCriticalSection(pThread, &g_csProcess);
+}
+
+#if USE_SYSV_SEMAPHORES
+/*++
+Function:
+ PROCCleanupThreadSemIds
+
+Abstract
+ Cleanup SysV semaphore ids for all threads
+
+(no parameters, no return value)
+--*/
+VOID
+PROCCleanupThreadSemIds(void)
+{
+ //
+ // When using SysV semaphores, the semaphore ids used by PAL threads must be removed
+ // so they can be used again.
+ //
+
+ PROCProcessLock();
+
+ CPalThread *pTargetThread = pGThreadList;
+ while (NULL != pTargetThread)
+ {
+ pTargetThread->suspensionInfo.DestroySemaphoreIds();
+ pTargetThread = pTargetThread->GetNext();
+ }
+
+ PROCProcessUnlock();
+
+}
+#endif // USE_SYSV_SEMAPHORES
+
+/*++
+Function:
+ TerminateCurrentProcessNoExit
+
+Abstract:
+ Terminate current Process, but leave the caller alive
+
+Parameters:
+ BOOL bTerminateUnconditionally - If this is set, the PAL will exit as
+ quickly as possible. In particular, it will not unload DLLs.
+
+Return value :
+ No return
+
+Note:
+ This function is used in ExitThread and TerminateProcess
+
+--*/
+void
+CorUnix::TerminateCurrentProcessNoExit(BOOL bTerminateUnconditionally)
+{
+ BOOL locked;
+ DWORD old_terminator;
+
+ old_terminator = InterlockedCompareExchange(&terminator, GetCurrentThreadId(), 0);
+
+ if (0 != old_terminator && GetCurrentThreadId() != old_terminator)
+ {
+ /* another thread has already initiated the termination process. we
+ could just block on the PALInitLock critical section, but then
+ PROCSuspendOtherThreads would hang... so sleep forever here, we're
+ terminating anyway
+
+ Update: [TODO] PROCSuspendOtherThreads has been removed. Can this
+ code be changed? */
+
+ /* note that if *this* thread has already started the termination
+ process, we want to proceed. the only way this can happen is if a
+ call to DllMain (from ExitProcess) brought us here (because DllMain
+ called ExitProcess, or TerminateProcess, or ExitThread);
+ TerminateProcess won't call DllMain, so there's no danger to get
+ caught in an infinite loop */
+ WARN("termination already started from another thread; blocking.\n");
+ poll(NULL, 0, INFTIM);
+ }
+
+ /* Try to lock the initialization count to prevent multiple threads from
+ terminating/initializing the PAL simultaneously */
+
+ /* note : it's also important to take this lock before the process lock,
+ because Init/Shutdown take the init lock, and the functions they call
+ may take the process lock. We must do it in the same order to avoid
+ deadlocks */
+
+ locked = PALInitLock();
+ if(locked && PALIsInitialized())
+ {
+ PROCNotifyProcessShutdown();
+ PALCommonCleanup();
+ }
+}
+
+/*++
+Function:
+ PROCGetProcessStatus
+
+Abstract:
+ Retrieve process state information (state & exit code).
+
+Parameters:
+ DWORD process_id : PID of process to retrieve state for
+ PROCESS_STATE *state : state of process (starting, running, done)
+ DWORD *exit_code : exit code of process (from ExitProcess, etc.)
+
+Return value :
+ TRUE on success
+--*/
+PAL_ERROR
+PROCGetProcessStatus(
+ CPalThread *pThread,
+ HANDLE hProcess,
+ PROCESS_STATE *pps,
+ DWORD *pdwExitCode
+ )
+{
+ PAL_ERROR palError = NO_ERROR;
+ IPalObject *pobjProcess = NULL;
+ IDataLock *pDataLock;
+ CProcProcessLocalData *pLocalData;
+ pid_t wait_retval;
+ int status;
+
+ //
+ // First, check if we already know the status of this process. This will be
+ // the case if this function has already been called for the same process.
+ //
+
+ palError = g_pObjectManager->ReferenceObjectByHandle(
+ pThread,
+ hProcess,
+ &aotProcess,
+ 0,
+ &pobjProcess
+ );
+
+ if (NO_ERROR != palError)
+ {
+ goto PROCGetProcessStatusExit;
+ }
+
+ palError = pobjProcess->GetProcessLocalData(
+ pThread,
+ WriteLock,
+ &pDataLock,
+ reinterpret_cast<void **>(&pLocalData)
+ );
+
+ if (PS_DONE == pLocalData->ps)
+ {
+ TRACE("We already called waitpid() on process ID %#x; process has "
+ "terminated, exit code is %d\n",
+ pLocalData->dwProcessId, pLocalData->dwExitCode);
+
+ *pps = pLocalData->ps;
+ *pdwExitCode = pLocalData->dwExitCode;
+
+ pDataLock->ReleaseLock(pThread, FALSE);
+
+ goto PROCGetProcessStatusExit;
+ }
+
+ /* By using waitpid(), we can even retrieve the exit code of a non-PAL
+ process. However, note that waitpid() can only provide the low 8 bits
+ of the exit code. This is all that is required for the PAL spec. */
+ TRACE("Looking for status of process; trying wait()");
+
+ while(1)
+ {
+ /* try to get state of process, using non-blocking call */
+ wait_retval = waitpid(pLocalData->dwProcessId, &status, WNOHANG);
+
+ if ( wait_retval == (pid_t) pLocalData->dwProcessId )
+ {
+ /* success; get the exit code */
+ if ( WIFEXITED( status ) )
+ {
+ *pdwExitCode = WEXITSTATUS(status);
+ TRACE("Exit code was %d\n", *pdwExitCode);
+ }
+ else
+ {
+ WARN("process terminated without exiting; can't get exit "
+ "code. faking it.\n");
+ *pdwExitCode = EXIT_FAILURE;
+ }
+ *pps = PS_DONE;
+ }
+ else if (0 == wait_retval)
+ {
+ // The process is still running.
+ TRACE("Process %#x is still active.\n", pLocalData->dwProcessId);
+ *pps = PS_RUNNING;
+ *pdwExitCode = 0;
+ }
+ else if (-1 == wait_retval)
+ {
+ // This might happen if waitpid() had already been called, but
+ // this shouldn't happen - we call waitpid once, store the
+ // result, and use that afterwards.
+ // One legitimate cause of failure is EINTR; if this happens we
+ // have to try again. A second legitimate cause is ECHILD, which
+ // happens if we're trying to retrieve the status of a currently-
+ // running process that isn't a child of this process.
+ if(EINTR == errno)
+ {
+ TRACE("waitpid() failed with EINTR; re-waiting");
+ continue;
+ }
+ else if (ECHILD == errno)
+ {
+ TRACE("waitpid() failed with ECHILD; calling kill instead");
+ if (kill(pLocalData->dwProcessId, 0) != 0)
+ {
+ if(ESRCH == errno)
+ {
+ WARN("kill() failed with ESRCH, i.e. target "
+ "process exited and it wasn't a child, "
+ "so can't get the exit code, assuming "
+ "it was 0.\n");
+ *pdwExitCode = 0;
+ }
+ else
+ {
+ ERROR("kill(pid, 0) failed; errno is %d (%s)\n",
+ errno, strerror(errno));
+ *pdwExitCode = EXIT_FAILURE;
+ }
+ *pps = PS_DONE;
+ }
+ else
+ {
+ *pps = PS_RUNNING;
+ *pdwExitCode = 0;
+ }
+ }
+ else
+ {
+ // Ignoring unexpected waitpid errno and assuming that
+ // the process is still running
+ ERROR("waitpid(pid=%u) failed with unexpected errno=%d (%s)\n",
+ pLocalData->dwProcessId, errno, strerror(errno));
+ *pps = PS_RUNNING;
+ *pdwExitCode = 0;
+ }
+ }
+ else
+ {
+ ASSERT("waitpid returned unexpected value %d\n",wait_retval);
+ *pdwExitCode = EXIT_FAILURE;
+ *pps = PS_DONE;
+ }
+ // Break out of the loop in all cases except EINTR.
+ break;
+ }
+
+ // Save the exit code for future reference (waitpid will only work once).
+ if(PS_DONE == *pps)
+ {
+ pLocalData->ps = PS_DONE;
+ pLocalData->dwExitCode = *pdwExitCode;
+ }
+
+ TRACE( "State of process 0x%08x : %d (exit code %d)\n",
+ pLocalData->dwProcessId, *pps, *pdwExitCode );
+
+ pDataLock->ReleaseLock(pThread, TRUE);
+
+PROCGetProcessStatusExit:
+
+ if (NULL != pobjProcess)
+ {
+ pobjProcess->ReleaseReference(pThread);
+ }
+
+ return palError;
+}
+
+#ifdef _DEBUG
+void PROCDumpThreadList()
+{
+ CPalThread *pThread;
+
+ PROCProcessLock();
+
+ TRACE ("Threads:{\n");
+
+ pThread = pGThreadList;
+ while (NULL != pThread)
+ {
+ TRACE (" {pThr=0x%p tid=%#x lwpid=%#x state=%d finsusp=%d}\n",
+ pThread, (int)pThread->GetThreadId(), (int)pThread->GetLwpId(),
+ (int)pThread->synchronizationInfo.GetThreadState(),
+ (int)pThread->suspensionInfo.GetSuspendedForShutdown());
+
+ pThread = pThread->GetNext();
+ }
+ TRACE ("Threads:}\n");
+
+ PROCProcessUnlock();
+}
+#endif
+
+/* Internal function definitions **********************************************/
+
+/*++
+Function:
+ getFileName
+
+Abstract:
+ Helper function for CreateProcessW, it retrieves the executable filename
+ from the application name, and the command line.
+
+Parameters:
+ IN lpApplicationName: first parameter from CreateProcessW (an unicode string)
+ IN lpCommandLine: second parameter from CreateProcessW (an unicode string)
+ OUT lpFileName: file to be executed (the new process)
+
+Return:
+ TRUE: if the file name is retrieved
+ FALSE: otherwise
+
+--*/
+static
+BOOL
+getFileName(
+ LPCWSTR lpApplicationName,
+ LPWSTR lpCommandLine,
+ PathCharString& lpPathFileName)
+{
+ LPWSTR lpEnd;
+ WCHAR wcEnd;
+ char * lpFileName;
+ PathCharString lpFileNamePS;
+ char *lpTemp;
+
+ if (lpApplicationName)
+ {
+ int length = WideCharToMultiByte(CP_ACP, 0, lpApplicationName, -1,
+ NULL, 0, NULL, NULL);
+
+ /* if only a file name is specified, prefix it with "./" */
+ if ((*lpApplicationName != '.') && (*lpApplicationName != '/') &&
+ (*lpApplicationName != '\\'))
+ {
+ length += 2;
+ lpTemp = lpPathFileName.OpenStringBuffer(length);
+
+ if (strcpy_s(lpTemp, length, "./") != SAFECRT_SUCCESS)
+ {
+ ERROR("strcpy_s failed!\n");
+ return FALSE;
+ }
+ lpTemp+=2;
+
+ }
+ else
+ {
+ lpTemp = lpPathFileName.OpenStringBuffer(length);
+ }
+
+ /* Convert to ASCII */
+ length = WideCharToMultiByte(CP_ACP, 0, lpApplicationName, -1,
+ lpTemp, length, NULL, NULL);
+ if (length == 0)
+ {
+ lpPathFileName.CloseBuffer(0);
+ ASSERT("WideCharToMultiByte failure\n");
+ return FALSE;
+ }
+
+ lpPathFileName.CloseBuffer(length -1);
+
+ /* Replace '\' by '/' */
+ FILEDosToUnixPathA(lpTemp);
+
+ return TRUE;
+ }
+ else
+ {
+ /* use the Command line */
+
+ /* filename should be the first token of the command line */
+
+ /* first skip all leading whitespace */
+ lpCommandLine = UTIL_inverse_wcspbrk(lpCommandLine,W16_WHITESPACE);
+ if(NULL == lpCommandLine)
+ {
+ ERROR("CommandLine contains only whitespace!\n");
+ return FALSE;
+ }
+
+ /* check if it is starting with a quote (") character */
+ if (*lpCommandLine == 0x0022)
+ {
+ lpCommandLine++; /* skip the quote */
+
+ /* file name ends with another quote */
+ lpEnd = PAL_wcschr(lpCommandLine+1, 0x0022);
+
+ /* if no quotes found, set lpEnd to the end of the Command line */
+ if (lpEnd == NULL)
+ lpEnd = lpCommandLine + PAL_wcslen(lpCommandLine);
+ }
+ else
+ {
+ /* filename is end out by a whitespace */
+ lpEnd = PAL_wcspbrk(lpCommandLine, W16_WHITESPACE);
+
+ /* if no whitespace found, set lpEnd to end of the Command line */
+ if (lpEnd == NULL)
+ {
+ lpEnd = lpCommandLine + PAL_wcslen(lpCommandLine);
+ }
+ }
+
+ if (lpEnd == lpCommandLine)
+ {
+ ERROR("application name and command line are both empty!\n");
+ return FALSE;
+ }
+
+ /* replace the last character by a null */
+ wcEnd = *lpEnd;
+ *lpEnd = 0x0000;
+
+ /* Convert to ASCII */
+ int size = 0;
+ int length = (PAL_wcslen(lpCommandLine)+1) * sizeof(WCHAR);
+ lpFileName = lpFileNamePS.OpenStringBuffer(length);
+ if (NULL == lpFileName)
+ {
+ ERROR("Not Enough Memory!\n");
+ return FALSE;
+ }
+ if (!(size = WideCharToMultiByte(CP_ACP, 0, lpCommandLine, -1,
+ lpFileName, length, NULL, NULL)))
+ {
+ ASSERT("WideCharToMultiByte failure\n");
+ return FALSE;
+ }
+
+ lpFileNamePS.CloseBuffer(size - 1);
+ /* restore last character */
+ *lpEnd = wcEnd;
+
+ /* Replace '\' by '/' */
+ FILEDosToUnixPathA(lpFileName);
+
+ if (!getPath(lpFileNamePS, lpPathFileName))
+ {
+ /* file is not in the path */
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+/*++
+Functions: VAL16 & VAL32
+ Byte swapping functions for reading in little endian format files
+--*/
+#ifdef BIGENDIAN
+
+static inline USHORT VAL16(USHORT x)
+{
+ return ( ((x & 0xFF00) >> 8) | ((x & 0x00FF) << 8) );
+}
+static inline ULONG VAL32(DWORD x)
+{
+ return( ((x & 0xFF000000L) >> 24) |
+ ((x & 0x00FF0000L) >> 8) |
+ ((x & 0x0000FF00L) << 8) |
+ ((x & 0x000000FFL) << 24) );
+}
+#else // BIGENDIAN
+// For little-endian machines, do nothing
+static __inline USHORT VAL16(unsigned short x) { return x; }
+static __inline DWORD VAL32(DWORD x){ return x; }
+#endif // BIGENDIAN
+
+static const DWORD IMAGE_DOS_SIGNATURE = 0x5A4D;
+static const DWORD IMAGE_NT_SIGNATURE = 0x00004550;
+static const DWORD IMAGE_SIZEOF_NT_OPTIONAL32_HEADER = 224;
+static const DWORD IMAGE_NT_OPTIONAL_HDR32_MAGIC = 0x10b;
+static const DWORD IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR = 14;
+
+typedef struct _IMAGE_DATA_DIRECTORY {
+ DWORD VirtualAddress;
+ DWORD Size;
+} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
+
+typedef struct _IMAGE_OPTIONAL_HEADER {
+ //
+ // Standard fields.
+ //
+
+ WORD Magic;
+ BYTE MajorLinkerVersion;
+ BYTE MinorLinkerVersion;
+ DWORD SizeOfCode;
+ DWORD SizeOfInitializedData;
+ DWORD SizeOfUninitializedData;
+ DWORD AddressOfEntryPoint;
+ DWORD BaseOfCode;
+ DWORD BaseOfData;
+
+ //
+ // NT additional fields.
+ //
+
+ DWORD ImageBase;
+ DWORD SectionAlignment;
+ DWORD FileAlignment;
+ WORD MajorOperatingSystemVersion;
+ WORD MinorOperatingSystemVersion;
+ WORD MajorImageVersion;
+ WORD MinorImageVersion;
+ WORD MajorSubsystemVersion;
+ WORD MinorSubsystemVersion;
+ DWORD Win32VersionValue;
+ DWORD SizeOfImage;
+ DWORD SizeOfHeaders;
+ DWORD CheckSum;
+ WORD Subsystem;
+ WORD DllCharacteristics;
+ DWORD SizeOfStackReserve;
+ DWORD SizeOfStackCommit;
+ DWORD SizeOfHeapReserve;
+ DWORD SizeOfHeapCommit;
+ DWORD LoaderFlags;
+ DWORD NumberOfRvaAndSizes;
+ IMAGE_DATA_DIRECTORY DataDirectory[16];
+} IMAGE_OPTIONAL_HEADER32, *PIMAGE_OPTIONAL_HEADER32;
+
+typedef struct _IMAGE_FILE_HEADER {
+ WORD Machine;
+ WORD NumberOfSections;
+ DWORD TimeDateStamp;
+ DWORD PointerToSymbolTable;
+ DWORD NumberOfSymbols;
+ WORD SizeOfOptionalHeader;
+ WORD Characteristics;
+} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
+
+typedef struct _IMAGE_NT_HEADERS {
+ DWORD Signature;
+ IMAGE_FILE_HEADER FileHeader;
+ IMAGE_OPTIONAL_HEADER32 OptionalHeader;
+} IMAGE_NT_HEADERS32, *PIMAGE_NT_HEADERS32;
+
+typedef struct _IMAGE_DOS_HEADER { /* DOS .EXE header*/
+ WORD e_magic; /* Magic number*/
+ WORD e_cblp; /* Bytes on last page of file*/
+ WORD e_cp; /* Pages in file*/
+ WORD e_crlc; /* Relocations*/
+ WORD e_cparhdr; /* Size of header in paragraphs*/
+ WORD e_minalloc; /* Minimum extra paragraphs needed*/
+ WORD e_maxalloc; /* Maximum extra paragraphs needed*/
+ WORD e_ss; /* Initial (relative) SS value*/
+ WORD e_sp; /* Initial SP value*/
+ WORD e_csum; /* Checksum*/
+ WORD e_ip; /* Initial IP value*/
+ WORD e_cs; /* Initial (relative) CS value*/
+ WORD e_lfarlc; /* File address of relocation table*/
+ WORD e_ovno; /* Overlay number*/
+ WORD e_res[4]; /* Reserved words*/
+ WORD e_oemid; /* OEM identifier (for e_oeminfo)*/
+ WORD e_oeminfo; /* OEM information; e_oemid specific*/
+ WORD e_res2[10]; /* Reserved words*/
+ LONG e_lfanew; /* File address of new exe header*/
+ } IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
+
+
+/*++
+Function:
+ isManagedExecutable
+
+Determines if the passed in file is a managed executable
+
+--*/
+static
+int
+isManagedExecutable(LPCSTR lpFileName)
+{
+ HANDLE hFile = INVALID_HANDLE_VALUE;
+ DWORD cbRead;
+ IMAGE_DOS_HEADER dosheader;
+ IMAGE_NT_HEADERS32 NtHeaders;
+ BOOL ret = 0;
+
+ /* then check if it is a PE/COFF file */
+ if((hFile = CreateFileA(lpFileName, GENERIC_READ, FILE_SHARE_READ, NULL,
+ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
+ NULL)) == INVALID_HANDLE_VALUE)
+ {
+ goto isManagedExecutableExit;
+ }
+
+ /* Open the file and read the IMAGE_DOS_HEADER structure */
+ if(!ReadFile(hFile, &dosheader, sizeof(IMAGE_DOS_HEADER), &cbRead, NULL) || cbRead != sizeof(IMAGE_DOS_HEADER) )
+ goto isManagedExecutableExit;
+
+ /* check the DOS headers */
+ if ( (dosheader.e_magic != VAL16(IMAGE_DOS_SIGNATURE)) || (VAL32(dosheader.e_lfanew) <= 0) )
+ goto isManagedExecutableExit;
+
+ /* Advance the file pointer to File address of new exe header */
+ if( SetFilePointer(hFile, VAL32(dosheader.e_lfanew), NULL, FILE_BEGIN) == 0xffffffff)
+ goto isManagedExecutableExit;
+
+ if( !ReadFile(hFile, &NtHeaders , sizeof(IMAGE_NT_HEADERS32), &cbRead, NULL) || cbRead != sizeof(IMAGE_NT_HEADERS32) )
+ goto isManagedExecutableExit;
+
+ /* check the NT headers */
+ if ((NtHeaders.Signature != VAL32(IMAGE_NT_SIGNATURE)) ||
+ (NtHeaders.FileHeader.SizeOfOptionalHeader != VAL16(IMAGE_SIZEOF_NT_OPTIONAL32_HEADER)) ||
+ (NtHeaders.OptionalHeader.Magic != VAL16(IMAGE_NT_OPTIONAL_HDR32_MAGIC)))
+ goto isManagedExecutableExit;
+
+ /* Check that the virtual address of IMAGE_DIRECTORY_ENTRY_COMHEADER is non-null */
+ if ( NtHeaders.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR].VirtualAddress == 0 )
+ goto isManagedExecutableExit;
+
+ /* The file is a managed executable */
+ ret = 1;
+
+ isManagedExecutableExit:
+ /* Close the file handle if we opened it */
+ if ( hFile != INVALID_HANDLE_VALUE )
+ CloseHandle(hFile);
+
+ return ret;
+}
+
+/*++
+Function:
+ checkFileType
+
+Abstract:
+ Return the type of the file.
+
+Parameters:
+ IN lpFileName: file name
+
+Return:
+ FILE_DIR: Directory
+ FILE_UNIX: Unix executable file
+ FILE_PE: managed PE/COFF file
+ FILE_ERROR: Error
+--*/
+static
+int
+checkFileType( LPCSTR lpFileName)
+{
+ struct stat stat_data;
+
+ /* check if the file exist */
+ if ( access(lpFileName, F_OK) != 0 )
+ {
+ return FILE_ERROR;
+ }
+
+ if( isManagedExecutable(lpFileName) )
+ {
+ return FILE_PE;
+ }
+
+ /* if it's not a PE/COFF file, check if it is executable */
+ if ( -1 != stat( lpFileName, &stat_data ) )
+ {
+
+ if((stat_data.st_mode & S_IFMT) == S_IFDIR )
+ {
+ /*The given file is a directory*/
+ return FILE_DIR;
+ }
+ if ( UTIL_IsExecuteBitsSet( &stat_data ) )
+ {
+ return FILE_UNIX;
+ }
+ else
+ {
+ return FILE_ERROR;
+ }
+ }
+ return FILE_ERROR;
+
+}
+
+
+/*++
+Function:
+ buildArgv
+
+Abstract:
+ Helper function for CreateProcessW, it builds the array of argument in
+ a format than can be passed to execve function.lppArgv is allocated
+ in this function and must be freed by the caller.
+
+Parameters:
+ IN lpCommandLine: second parameter from CreateProcessW (an unicode string)
+ IN lpAppPath: cannonical name of the application to launched
+ OUT lppArgv: array of arguments to be passed to the new process
+ IN prependLoader: If True first argument should be the PE loader
+
+Return:
+ the number of arguments
+
+note: this doesn't yet match precisely the behavior of Windows, but should be
+sufficient.
+what's here:
+1) stripping nonquoted whitespace
+2) handling of quoted parameters and quoted "parts" of parameters, removal of
+ doublequotes (<aaaa"b bbb b"ccc> becomes <aaaab bbb bccc>)
+3) \" as an escaped doublequote, both within doublequoted sequences and out
+what's known missing :
+1) \\ as an escaped backslash, but only if the string of '\'
+ is followed by a " (escaped or not)
+2) "alternate" escape sequence : double-doublequote within a double-quoted
+ argument (<"aaa a""aa aaa">) expands to a single-doublequote(<aaa a"aa aaa>)
+note that there may be other special cases
+--*/
+static
+char **
+buildArgv(
+ LPCWSTR lpCommandLine,
+ PathCharString& lpAppPath,
+ UINT *pnArg,
+ BOOL prependLoader)
+{
+ CPalThread *pThread = NULL;
+ UINT iWlen;
+ char *lpAsciiCmdLine;
+ char *pChar;
+ char **lppArgv;
+ char **lppTemp;
+ UINT i,j;
+
+ *pnArg = 0;
+
+ iWlen = WideCharToMultiByte(CP_ACP,0,lpCommandLine,-1,NULL,0,NULL,NULL);
+
+ if(0 == iWlen)
+ {
+ ASSERT("Can't determine length of command line\n");
+ return NULL;
+ }
+
+ pThread = InternalGetCurrentThread();
+ /* make sure to allocate enough space, up for the worst case scenario */
+ int iLength = (iWlen + strlen(PROCESS_PELOADER_FILENAME) + lpAppPath.GetCount() + 2);
+ lpAsciiCmdLine = (char *) InternalMalloc(iLength);
+
+ if (lpAsciiCmdLine == NULL)
+ {
+ ERROR("Unable to allocate memory\n");
+ return NULL;
+ }
+
+ pChar = lpAsciiCmdLine;
+
+ /* Prepend the PE loader, if it's required */
+ if (prependLoader)
+ {
+ if ((strcpy_s(lpAsciiCmdLine, iLength, PROCESS_PELOADER_FILENAME) != SAFECRT_SUCCESS) ||
+ (strcat_s(lpAsciiCmdLine, iLength, " ") != SAFECRT_SUCCESS))
+ {
+ ERROR("strcpy_s/strcat_s failed!\n");
+ return NULL;
+ }
+
+ pChar = lpAsciiCmdLine + strlen (lpAsciiCmdLine);
+
+ }
+ else
+ {
+ /* put the cannonical name of the application as the first parameter */
+ if ((strcpy_s(lpAsciiCmdLine, iLength, "\"") != SAFECRT_SUCCESS) ||
+ (strcat_s(lpAsciiCmdLine, iLength, lpAppPath) != SAFECRT_SUCCESS) ||
+ (strcat_s(lpAsciiCmdLine, iLength, "\"") != SAFECRT_SUCCESS) ||
+ (strcat_s(lpAsciiCmdLine, iLength, " ") != SAFECRT_SUCCESS))
+ {
+ ERROR("strcpy_s/strcat_s failed!\n");
+ return NULL;
+ }
+
+ pChar = lpAsciiCmdLine + strlen (lpAsciiCmdLine);
+
+ /* let's skip the first argument in the command line */
+
+ /* strip leading whitespace; function returns NULL if there's only
+ whitespace, so the if statement below will work correctly */
+ lpCommandLine = UTIL_inverse_wcspbrk((LPWSTR)lpCommandLine, W16_WHITESPACE);
+
+ if (lpCommandLine)
+ {
+ LPCWSTR stringstart = lpCommandLine;
+
+ do
+ {
+ /* find first whitespace or dquote character */
+ lpCommandLine = PAL_wcspbrk(lpCommandLine,W16_WHITESPACE_DQUOTE);
+ if(NULL == lpCommandLine)
+ {
+ /* no whitespace or dquote found : first arg is only arg */
+ break;
+ }
+ else if('"' == *lpCommandLine)
+ {
+ /* got a dquote; skip over it if it's escaped; make sure we
+ don't try to look before the first character in the
+ string */
+ if(lpCommandLine > stringstart && '\\' == lpCommandLine[-1])
+ {
+ lpCommandLine++;
+ continue;
+ }
+
+ /* found beginning of dquoted sequence, run to the end */
+ /* don't stop if we hit an escaped dquote */
+ lpCommandLine++;
+ while( *lpCommandLine )
+ {
+ lpCommandLine = PAL_wcschr(lpCommandLine, '"');
+ if(NULL == lpCommandLine)
+ {
+ /* no ending dquote, arg runs to end of string */
+ break;
+ }
+ if('\\' != lpCommandLine[-1])
+ {
+ /* dquote is not escaped, dquoted sequence is over*/
+ break;
+ }
+ lpCommandLine++;
+ }
+ if(NULL == lpCommandLine || '\0' == *lpCommandLine)
+ {
+ /* no terminating dquote */
+ break;
+ }
+
+ /* step over dquote, keep looking for end of arg */
+ lpCommandLine++;
+ }
+ else
+ {
+ /* found whitespace : end of arg. */
+ lpCommandLine++;
+ break;
+ }
+ }while(lpCommandLine);
+ }
+ }
+
+ /* Convert to ASCII */
+ if (lpCommandLine)
+ {
+ if (!WideCharToMultiByte(CP_ACP, 0, lpCommandLine, -1,
+ pChar, iWlen+1, NULL, NULL))
+ {
+ ASSERT("Unable to convert to a multibyte string\n");
+ free(lpAsciiCmdLine);
+ return NULL;
+ }
+ }
+
+ pChar = lpAsciiCmdLine;
+
+ /* loops through all the arguments, to find out how many arguments there
+ are; while looping replace whitespace by \0 */
+
+ /* skip leading whitespace (and replace by '\0') */
+ /* note : there shouldn't be any, command starts either with PE loader name
+ or computed application path, but this won't hurt */
+ while (*pChar)
+ {
+ if (!isspace((unsigned char) *pChar))
+ {
+ break;
+ }
+ WARN("unexpected whitespace in command line!\n");
+ *pChar++ = '\0';
+ }
+
+ while (*pChar)
+ {
+ (*pnArg)++;
+
+ /* find end of current arg */
+ while(*pChar && !isspace((unsigned char) *pChar))
+ {
+ if('"' == *pChar)
+ {
+ /* skip over dquote if it's escaped; make sure we don't try to
+ look before the start of the string for the \ */
+ if(pChar > lpAsciiCmdLine && '\\' == pChar[-1])
+ {
+ pChar++;
+ continue;
+ }
+
+ /* found leading dquote : look for ending dquote */
+ pChar++;
+ while (*pChar)
+ {
+ pChar = strchr(pChar,'"');
+ if(NULL == pChar)
+ {
+ /* no ending dquote found : argument extends to the end
+ of the string*/
+ break;
+ }
+ if('\\' != pChar[-1])
+ {
+ /* found a dquote, and it's not escaped : quoted
+ sequence is over*/
+ break;
+ }
+ /* found a dquote, but it was escaped : skip over it, keep
+ looking */
+ pChar++;
+ }
+ if(NULL == pChar || '\0' == *pChar)
+ {
+ /* reached the end of the string : we're done */
+ break;
+ }
+ }
+ pChar++;
+ }
+ if(NULL == pChar)
+ {
+ /* reached the end of the string : we're done */
+ break;
+ }
+ /* reached end of arg; replace trailing whitespace by '\0', to split
+ arguments into separate strings */
+ while (isspace((unsigned char) *pChar))
+ {
+ *pChar++ = '\0';
+ }
+ }
+
+ /* allocate lppargv according to the number of arguments
+ in the command line */
+ lppArgv = (char **) InternalMalloc((((*pnArg)+1) * sizeof(char *)));
+
+ if (lppArgv == NULL)
+ {
+ free(lpAsciiCmdLine);
+ return NULL;
+ }
+
+ lppTemp = lppArgv;
+
+ /* at this point all parameters are separated by NULL
+ we need to fill the array of arguments; we must also remove all dquotes
+ from arguments (new process shouldn't see them) */
+ for (i = *pnArg, pChar = lpAsciiCmdLine; i; i--)
+ {
+ /* skip NULLs */
+ while (!*pChar)
+ {
+ pChar++;
+ }
+
+ *lppTemp = pChar;
+
+ /* go to the next parameter, removing dquotes as we go along */
+ j = 0;
+ while (*pChar)
+ {
+ /* copy character if it's not a dquote */
+ if('"' != *pChar)
+ {
+ /* if it's the \ of an escaped dquote, skip over it, we'll
+ copy the " instead */
+ if( '\\' == pChar[0] && '"' == pChar[1] )
+ {
+ pChar++;
+ }
+ (*lppTemp)[j++] = *pChar;
+ }
+ pChar++;
+ }
+ /* re-NULL terminate the argument */
+ (*lppTemp)[j] = '\0';
+
+ lppTemp++;
+ }
+
+ *lppTemp = NULL;
+
+ return lppArgv;
+}
+
+
+/*++
+Function:
+ getPath
+
+Abstract:
+ Helper function for CreateProcessW, it looks in the path environment
+ variable to find where the process to executed is.
+
+Parameters:
+ IN lpFileName: file name to search in the path
+ OUT lpPathFileName: returned string containing the path and the filename
+
+Return:
+ TRUE if found
+ FALSE otherwise
+--*/
+static
+BOOL
+getPath(
+ PathCharString& lpFileNameString,
+ PathCharString& lpPathFileName)
+{
+ LPSTR lpPath;
+ LPSTR lpNext;
+ LPSTR lpCurrent;
+ LPWSTR lpwstr;
+ INT n;
+ INT nextLen;
+ INT slashLen;
+ CPalThread *pThread = NULL;
+ LPCSTR lpFileName = lpFileNameString.GetString();
+
+ /* if a path is specified, only look there */
+ if(strchr(lpFileName, '/'))
+ {
+ if (access (lpFileName, F_OK) == 0)
+ {
+ if (!lpPathFileName.Set(lpFileNameString))
+ {
+ TRACE("Set of StackString failed!\n");
+ return FALSE;
+ }
+
+ TRACE("file %s exists\n", lpFileName);
+ return TRUE;
+ }
+ else
+ {
+ TRACE("file %s doesn't exist.\n", lpFileName);
+ return FALSE;
+ }
+ }
+
+ /* first look in directory from which the application loaded */
+ lpwstr = g_lpwstrAppDir;
+
+ if (lpwstr)
+ {
+ /* convert path to multibyte, check buffer size */
+ n = WideCharToMultiByte(CP_ACP, 0, lpwstr, -1, NULL, 0,
+ NULL, NULL);
+
+ if (!lpPathFileName.Reserve(n + lpFileNameString.GetCount() + 1 ))
+ {
+ ERROR("StackString Reserve failed!\n");
+ return FALSE;
+ }
+
+ lpPath = lpPathFileName.OpenStringBuffer(n);
+
+ n = WideCharToMultiByte(CP_ACP, 0, lpwstr, -1, lpPath, n,
+ NULL, NULL);
+
+ if (n == 0)
+ {
+ lpPathFileName.CloseBuffer(0);
+ ASSERT("WideCharToMultiByte failure!\n");
+ return FALSE;
+ }
+
+ lpPathFileName.CloseBuffer(n - 1);
+
+ lpPathFileName.Append("/", 1);
+ lpPathFileName.Append(lpFileNameString);
+
+ if (access(lpPathFileName, F_OK) == 0)
+ {
+ TRACE("found %s in application directory (%s)\n", lpFileName, lpPathFileName.GetString());
+ return TRUE;
+ }
+ }
+
+ /* then try the current directory */
+ if (!lpPathFileName.Reserve(lpFileNameString.GetCount() + 2))
+ {
+ ERROR("StackString Reserve failed!\n");
+ return FALSE;
+ }
+
+ lpPathFileName.Set("./", 2);
+ lpPathFileName.Append(lpFileNameString);
+
+ if (access (lpPathFileName, R_OK) == 0)
+ {
+ TRACE("found %s in current directory.\n", lpFileName);
+ return TRUE;
+ }
+
+ pThread = InternalGetCurrentThread();
+
+ /* Then try to look in the path */
+ lpPath = EnvironGetenv("PATH");
+
+ if (!lpPath)
+ {
+ ERROR("EnvironGetenv returned NULL for $PATH\n");
+ return FALSE;
+ }
+
+ lpNext = lpPath;
+
+ /* search in every path directory */
+ TRACE("looking for file %s in $PATH (%s)\n", lpFileName, lpPath);
+ while (lpNext)
+ {
+ /* skip all leading ':' */
+ while(*lpNext==':')
+ {
+ lpNext++;
+ }
+
+ /* search for ':' */
+ lpCurrent = strchr(lpNext, ':');
+ if (lpCurrent)
+ {
+ *lpCurrent++ = '\0';
+ }
+
+ nextLen = strlen(lpNext);
+ slashLen = (lpNext[nextLen-1] == '/') ? 0:1;
+
+ if (!lpPathFileName.Reserve(nextLen + lpFileNameString.GetCount() + 1))
+ {
+ free(lpPath);
+ ERROR("StackString ran out of memory for full path\n");
+ return FALSE;
+ }
+
+ lpPathFileName.Set(lpNext, nextLen);
+
+ if( slashLen == 1)
+ {
+ /* append a '/' if there's no '/' at the end of the path */
+ lpPathFileName.Append("/", 1);
+ }
+
+ lpPathFileName.Append(lpFileNameString);
+
+ if ( access (lpPathFileName, F_OK) == 0)
+ {
+ TRACE("Found %s in $PATH element %s\n", lpFileName, lpNext);
+ free(lpPath);
+ return TRUE;
+ }
+
+ lpNext = lpCurrent; /* search in the next directory */
+ }
+
+ free(lpPath);
+ TRACE("File %s not found in $PATH\n", lpFileName);
+ return FALSE;
+}
+
+/*++
+Function:
+ ~CProcProcessLocalData
+
+Process data destructor
+--*/
+CorUnix::CProcProcessLocalData::~CProcProcessLocalData()
+{
+ if (pProcessModules != NULL)
+ {
+ DestroyProcessModules(pProcessModules);
+ }
+}
+
diff --git a/src/pal/src/thread/procprivate.hpp b/src/pal/src/thread/procprivate.hpp
new file mode 100644
index 0000000000..bd35b69fe2
--- /dev/null
+++ b/src/pal/src/thread/procprivate.hpp
@@ -0,0 +1,78 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ thread/procprivate.hpp
+
+Abstract:
+
+ Private process structures and routines
+
+Revision History:
+
+
+
+--*/
+
+#ifndef _PAL_PROCPRIVATE_HPP_
+#define _PAL_PROCPRIVATE_HPP_
+
+#include "pal/thread.hpp"
+
+namespace CorUnix
+{
+
+ /*++
+ Function:
+ PROCAddThread
+
+ Abstract
+ Add a thread to the thread list of the current process
+ --*/
+ void PROCAddThread(CPalThread *pCurrentThread, CPalThread *pTargetThread);
+
+ extern CPalThread *pGThreadList;
+
+ /*++
+ Function:
+ PROCRemoveThread
+
+ Abstract
+ Remove a thread form the thread list of the current process
+ --*/
+ void PROCRemoveThread(CPalThread *pCurrentThread, CPalThread *pTargetThread);
+
+ /*++
+ Function:
+ PROCGetNumberOfThreads
+
+ Abstract
+ Return the number of threads in the thread list.
+ --*/
+ INT PROCGetNumberOfThreads(void);
+
+
+ /*++
+ Function:
+ TerminateCurrentProcessNoExit
+
+ Parameters:
+ BOOL bTerminateUnconditionally - If this is set, the PAL will exit as
+ quickly as possible. In particular, it will not unload DLLs.
+
+ Abstract:
+ Terminate Current Process, but leave the caller alive
+ --*/
+ void TerminateCurrentProcessNoExit(BOOL bTerminateUnconditionally);
+
+}
+
+#endif //_PAL_PROCPRIVATE_HPP_
+
+
diff --git a/src/pal/src/thread/thread.cpp b/src/pal/src/thread/thread.cpp
new file mode 100644
index 0000000000..566ef855b4
--- /dev/null
+++ b/src/pal/src/thread/thread.cpp
@@ -0,0 +1,2871 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ thread.cpp
+
+Abstract:
+
+ Thread object and core APIs
+
+
+
+--*/
+
+#include "pal/dbgmsg.h"
+SET_DEFAULT_DEBUG_CHANNEL(THREAD); // some headers have code with asserts, so do this first
+
+#include "pal/corunix.hpp"
+#include "pal/context.h"
+#include "pal/thread.hpp"
+#include "pal/mutex.hpp"
+#include "pal/handlemgr.hpp"
+#include "pal/cs.hpp"
+#include "pal/seh.hpp"
+
+#include "procprivate.hpp"
+#include "pal/process.h"
+#include "pal/module.h"
+#include "pal/environ.h"
+#include "pal/init.h"
+
+#if defined(__NetBSD__) && !HAVE_PTHREAD_GETCPUCLOCKID
+#include <sys/cdefs.h>
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#include <kvm.h>
+#endif
+
+#include <signal.h>
+#include <pthread.h>
+#if HAVE_PTHREAD_NP_H
+#include <pthread_np.h>
+#endif
+#include <unistd.h>
+#include <errno.h>
+#include <stddef.h>
+#include <sys/stat.h>
+#if HAVE_MACH_THREADS
+#include <mach/mach.h>
+#endif // HAVE_MACH_THREADS
+#if HAVE_POLL
+#include <poll.h>
+#else
+#include "pal/fakepoll.h"
+#endif // HAVE_POLL
+#include <limits.h>
+
+#if HAVE_SYS_LWP_H
+#include <sys/lwp.h>
+#endif
+#if HAVE_LWP_H
+#include <lwp.h>
+#endif
+// If we don't have sys/lwp.h but do expect to use _lwp_self, declare it to silence compiler warnings
+#if HAVE__LWP_SELF && !HAVE_SYS_LWP_H && !HAVE_LWP_H
+extern "C" int _lwp_self ();
+#endif
+
+using namespace CorUnix;
+
+
+/* ------------------- Definitions ------------------------------*/
+
+// The default stack size of a newly created thread (currently 256KB)
+// when the dwStackSize parameter of PAL_CreateThread()
+// is zero. This value can be set by setting the
+// environment variable PAL_THREAD_DEFAULT_STACK_SIZE
+// (the value should be in bytes and in hex).
+DWORD CPalThread::s_dwDefaultThreadStackSize = 256*1024;
+
+/* list of free CPalThread objects */
+static Volatile<CPalThread*> free_threads_list = NULL;
+
+/* lock to access list of free THREAD structures */
+/* NOTE: can't use a CRITICAL_SECTION here (see comment in FreeTHREAD) */
+int free_threads_spinlock = 0;
+
+/* lock to access iEndingThreads counter, condition variable to signal shutdown
+thread when any remaining threads have died, and count of exiting threads that
+can't be suspended. */
+pthread_mutex_t ptmEndThread;
+pthread_cond_t ptcEndThread;
+static int iEndingThreads = 0;
+
+// Activation function that gets called when an activation is injected into a thread.
+PAL_ActivationFunction g_activationFunction = NULL;
+// Function to check if an activation can be safely injected at a specified context
+PAL_SafeActivationCheckFunction g_safeActivationCheckFunction = NULL;
+
+void
+ThreadCleanupRoutine(
+ CPalThread *pThread,
+ IPalObject *pObjectToCleanup,
+ bool fShutdown,
+ bool fCleanupSharedState
+ );
+
+PAL_ERROR
+ThreadInitializationRoutine(
+ CPalThread *pThread,
+ CObjectType *pObjectType,
+ void *pImmutableData,
+ void *pSharedData,
+ void *pProcessLocalData
+ );
+
+void
+IncrementEndingThreadCount(
+ void
+ );
+
+void
+DecrementEndingThreadCount(
+ void
+ );
+
+CObjectType CorUnix::otThread(
+ otiThread,
+ ThreadCleanupRoutine,
+ ThreadInitializationRoutine,
+ 0, //sizeof(CThreadImmutableData),
+ sizeof(CThreadProcessLocalData),
+ 0, //sizeof(CThreadSharedData),
+ 0, // THREAD_ALL_ACCESS,
+ CObjectType::SecuritySupported,
+ CObjectType::SecurityInfoNotPersisted,
+ CObjectType::UnnamedObject,
+ CObjectType::LocalDuplicationOnly,
+ CObjectType::WaitableObject,
+ CObjectType::SingleTransitionObject,
+ CObjectType::ThreadReleaseHasNoSideEffects,
+ CObjectType::NoOwner
+ );
+
+CAllowedObjectTypes aotThread(otiThread);
+
+/*++
+Function:
+ InternalEndCurrentThreadWrapper
+
+ Destructor for the thread-specific data representing the current PAL thread.
+ Called from pthread_exit. (pthread_exit is not called from the thread on which
+ main() was first invoked. This is not a problem, though, since when main()
+ returns, this results in an implicit call to exit().)
+
+ arg: the PAL thread
+*/
+static void InternalEndCurrentThreadWrapper(void *arg)
+{
+ CPalThread *pThread = (CPalThread *) arg;
+
+ // When pthread_exit calls us, it has already removed the PAL thread
+ // from TLS. Since InternalEndCurrentThread calls functions that assert
+ // that the current thread is known to this PAL, and that pThread
+ // actually is the current PAL thread, put it back in TLS temporarily.
+ pthread_setspecific(thObjKey, pThread);
+ (void)PAL_Enter(PAL_BoundaryTop);
+
+ /* Call entry point functions of every attached modules to
+ indicate the thread is exiting */
+ /* note : no need to enter a critical section for serialization, the loader
+ will lock its own critical section */
+ LOADCallDllMain(DLL_THREAD_DETACH, NULL);
+
+ // PAL_Leave will be called just before we release the thread reference
+ // in InternalEndCurrentThread.
+ InternalEndCurrentThread(pThread);
+ pthread_setspecific(thObjKey, NULL);
+}
+
+/*++
+Function:
+ TLSInitialize
+
+ Initialize the TLS subsystem
+--*/
+BOOL TLSInitialize()
+{
+ /* Create the pthread key for thread objects, which we use
+ for fast access to the current thread object. */
+ if (pthread_key_create(&thObjKey, InternalEndCurrentThreadWrapper))
+ {
+ ERROR("Couldn't create the thread object key\n");
+ return FALSE;
+ }
+
+ SPINLOCKInit(&free_threads_spinlock);
+
+ return TRUE;
+}
+
+/*++
+Function:
+ TLSCleanup
+
+ Shutdown the TLS subsystem
+--*/
+VOID TLSCleanup()
+{
+ SPINLOCKDestroy(&free_threads_spinlock);
+
+ pthread_key_delete(thObjKey);
+}
+
+/*++
+Function:
+ AllocTHREAD
+
+Abstract:
+ Allocate CPalThread instance
+
+Return:
+ The fresh thread structure, NULL otherwise
+--*/
+CPalThread* AllocTHREAD()
+{
+ CPalThread* pThread = NULL;
+
+ /* Get the lock */
+ SPINLOCKAcquire(&free_threads_spinlock, 0);
+
+ pThread = free_threads_list;
+ if (pThread != NULL)
+ {
+ free_threads_list = pThread->GetNext();
+ }
+
+ /* Release the lock */
+ SPINLOCKRelease(&free_threads_spinlock);
+
+ if (pThread == NULL)
+ {
+ pThread = InternalNew<CPalThread>();
+ }
+ else
+ {
+ pThread = new (pThread) CPalThread;
+ }
+
+ return pThread;
+}
+
+/*++
+Function:
+ FreeTHREAD
+
+Abstract:
+ Free THREAD structure
+
+--*/
+static void FreeTHREAD(CPalThread *pThread)
+{
+ //
+ // Run the destructors for this object
+ //
+
+ pThread->~CPalThread();
+
+#ifdef _DEBUG
+ // Fill value so we can find code re-using threads after they're dead. We
+ // check against pThread->dwGuard when getting the current thread's data.
+ memset((void*)pThread, 0xcc, sizeof(*pThread));
+#endif
+
+ // We SHOULD be doing the following, but it causes massive problems. See the
+ // comment below.
+ //pthread_setspecific(thObjKey, NULL); // Make sure any TLS entry is removed.
+
+ //
+ // Never actually free the THREAD structure to make the TLS lookaside cache work.
+ // THREAD* for terminated thread can be stuck in the lookaside cache code for an
+ // arbitrary amount of time. The unused THREAD* structures has to remain in a
+ // valid memory and thus can't be returned to the heap.
+ //
+ // TODO: is this really true? Why would the entry remain in the cache for
+ // an indefinite period of time after we've flushed it?
+ //
+
+ /* NOTE: can't use a CRITICAL_SECTION here: EnterCriticalSection(&cs,TRUE) and
+ LeaveCriticalSection(&cs,TRUE) need to access the thread private data
+ stored in the very THREAD structure that we just destroyed. Entering and
+ leaving the critical section with internal==FALSE leads to possible hangs
+ in the PROCSuspendOtherThreads logic, at shutdown time
+
+ Update: [TODO] PROCSuspendOtherThreads has been removed. Can this
+ code be changed?*/
+
+ /* Get the lock */
+ SPINLOCKAcquire(&free_threads_spinlock, 0);
+
+ pThread->SetNext(free_threads_list);
+ free_threads_list = pThread;
+
+ /* Release the lock */
+ SPINLOCKRelease(&free_threads_spinlock);
+}
+
+
+/*++
+Function:
+ THREADGetThreadProcessId
+
+returns the process owner ID of the indicated hThread
+--*/
+DWORD
+THREADGetThreadProcessId(
+ HANDLE hThread
+ // UNIXTODO Should take pThread parameter here (modify callers)
+ )
+{
+ CPalThread *pThread;
+ CPalThread *pTargetThread;
+ IPalObject *pobjThread = NULL;
+ PAL_ERROR palError = NO_ERROR;
+
+ DWORD dwProcessId = 0;
+
+ pThread = InternalGetCurrentThread();
+
+ palError = InternalGetThreadDataFromHandle(
+ pThread,
+ hThread,
+ 0,
+ &pTargetThread,
+ &pobjThread
+ );
+
+ if (NO_ERROR != palError)
+ {
+ if (!pThread->IsDummy())
+ {
+ dwProcessId = GetCurrentProcessId();
+ }
+ else
+ {
+ ASSERT("Dummy thread passed to THREADGetProcessId\n");
+ }
+
+ if (NULL != pobjThread)
+ {
+ pobjThread->ReleaseReference(pThread);
+ }
+ }
+ else
+ {
+ ERROR("Couldn't retreive the hThread:%p pid owner !\n", hThread);
+ }
+
+
+ return dwProcessId;
+}
+
+/*++
+Function:
+ GetCurrentThreadId
+
+See MSDN doc.
+--*/
+DWORD
+PALAPI
+GetCurrentThreadId(
+ VOID)
+{
+ DWORD dwThreadId;
+
+ PERF_ENTRY(GetCurrentThreadId);
+ ENTRY("GetCurrentThreadId()\n");
+
+ //
+ // TODO: should do perf test to see how this compares
+ // with calling InternalGetCurrentThread (i.e., is our lookaside
+ // cache faster on average than pthread_self?)
+ //
+
+ dwThreadId = (DWORD)THREADSilentGetCurrentThreadId();
+
+ LOGEXIT("GetCurrentThreadId returns DWORD %#x\n", dwThreadId);
+ PERF_EXIT(GetCurrentThreadId);
+
+ return dwThreadId;
+}
+
+
+
+/*++
+Function:
+ GetCurrentThread
+
+See MSDN doc.
+--*/
+HANDLE
+PALAPI
+PAL_GetCurrentThread(
+ VOID)
+{
+ PERF_ENTRY(GetCurrentThread);
+ ENTRY("GetCurrentThread()\n");
+
+ LOGEXIT("GetCurrentThread returns HANDLE %p\n", hPseudoCurrentThread);
+ PERF_EXIT(GetCurrentThread);
+
+ /* return a pseudo handle */
+ return (HANDLE) hPseudoCurrentThread;
+}
+
+/*++
+Function:
+ SwitchToThread
+
+See MSDN doc.
+--*/
+BOOL
+PALAPI
+SwitchToThread(
+ VOID)
+{
+ BOOL ret;
+
+ PERF_ENTRY(SwitchToThread);
+ ENTRY("SwitchToThread(VOID)\n");
+
+ /* sched_yield yields to another thread in the current process. This implementation
+ won't work well for cross-process synchronization. */
+ ret = (sched_yield() == 0);
+
+ LOGEXIT("SwitchToThread returns BOOL %d\n", ret);
+ PERF_EXIT(SwitchToThread);
+
+ return ret;
+}
+
+/*++
+Function:
+ CreateThread
+
+Note:
+ lpThreadAttributes could be ignored.
+
+See MSDN doc.
+
+--*/
+HANDLE
+PALAPI
+CreateThread(
+ IN LPSECURITY_ATTRIBUTES lpThreadAttributes,
+ IN DWORD dwStackSize,
+ IN LPTHREAD_START_ROUTINE lpStartAddress,
+ IN LPVOID lpParameter,
+ IN DWORD dwCreationFlags,
+ OUT LPDWORD lpThreadId)
+{
+ PAL_ERROR palError;
+ CPalThread *pThread;
+ HANDLE hNewThread = NULL;
+
+ PERF_ENTRY(CreateThread);
+ ENTRY("CreateThread(lpThreadAttr=%p, dwStackSize=%u, lpStartAddress=%p, "
+ "lpParameter=%p, dwFlags=%#x, lpThreadId=%#x)\n",
+ lpThreadAttributes, dwStackSize, lpStartAddress, lpParameter,
+ dwCreationFlags, lpThreadId);
+
+ pThread = InternalGetCurrentThread();
+
+ palError = InternalCreateThread(
+ pThread,
+ lpThreadAttributes,
+ dwStackSize,
+ lpStartAddress,
+ lpParameter,
+ dwCreationFlags,
+ UserCreatedThread,
+ lpThreadId,
+ &hNewThread
+ );
+
+ if (NO_ERROR != palError)
+ {
+ pThread->SetLastError(palError);
+ }
+
+ LOGEXIT("CreateThread returns HANDLE %p\n", hNewThread);
+ PERF_EXIT(CreateThread);
+
+ return hNewThread;
+}
+
+PAL_ERROR
+CorUnix::InternalCreateThread(
+ CPalThread *pThread,
+ LPSECURITY_ATTRIBUTES lpThreadAttributes,
+ DWORD dwStackSize,
+ LPTHREAD_START_ROUTINE lpStartAddress,
+ LPVOID lpParameter,
+ DWORD dwCreationFlags,
+ PalThreadType eThreadType,
+ LPDWORD lpThreadId,
+ HANDLE *phThread
+ )
+{
+ PAL_ERROR palError;
+ CPalThread *pNewThread = NULL;
+ CObjectAttributes oa;
+ bool fAttributesInitialized = FALSE;
+ bool fThreadDataAddedToProcessList = FALSE;
+ HANDLE hNewThread = NULL;
+
+ pthread_t pthread;
+ pthread_attr_t pthreadAttr;
+ size_t pthreadStackSize;
+#if PTHREAD_CREATE_MODIFIES_ERRNO
+ int storedErrno;
+#endif // PTHREAD_CREATE_MODIFIES_ERRNO
+ BOOL fHoldingProcessLock = FALSE;
+ int iError = 0;
+
+ if (0 != terminator)
+ {
+ //
+ // Since the PAL is in the middle of shutting down we don't want to
+ // create any new threads (since it's possible for that new thread
+ // to create another thread before the shutdown thread gets around
+ // to suspending it, and so on). We don't want to return an error
+ // here, though, as some programs (in particular, build) do not
+ // handle CreateThread errors properly -- instead, we just put
+ // the calling thread to sleep (unless it is the shutdown thread,
+ // which could occur if a DllMain PROCESS_DETACH handler tried to
+ // create a new thread for some odd reason).
+ //
+
+ ERROR("process is terminating, can't create new thread.\n");
+
+ if (pThread->GetThreadId() != static_cast<DWORD>(terminator))
+ {
+ while (true)
+ {
+ poll(NULL, 0, INFTIM);
+ sched_yield();
+ }
+ }
+ else
+ {
+ //
+ // This is the shutdown thread, so just return an error
+ //
+
+ palError = ERROR_PROCESS_ABORTED;
+ goto EXIT;
+ }
+ }
+
+ /* Validate parameters */
+
+ if (lpThreadAttributes != NULL)
+ {
+ ASSERT("lpThreadAttributes parameter must be NULL (%p)\n",
+ lpThreadAttributes);
+ palError = ERROR_INVALID_PARAMETER;
+ goto EXIT;
+ }
+
+ // Ignore the STACK_SIZE_PARAM_IS_A_RESERVATION flag
+ dwCreationFlags &= ~STACK_SIZE_PARAM_IS_A_RESERVATION;
+
+ if ((dwCreationFlags != 0) && (dwCreationFlags != CREATE_SUSPENDED))
+ {
+ ASSERT("dwCreationFlags parameter is invalid (%#x)\n", dwCreationFlags);
+ palError = ERROR_INVALID_PARAMETER;
+ goto EXIT;
+ }
+
+ //
+ // Create the CPalThread for the thread
+ //
+
+ pNewThread = AllocTHREAD();
+ if (NULL == pNewThread)
+ {
+ palError = ERROR_OUTOFMEMORY;
+ goto EXIT;
+ }
+
+ palError = pNewThread->RunPreCreateInitializers();
+ if (NO_ERROR != palError)
+ {
+ goto EXIT;
+ }
+
+ pNewThread->m_lpStartAddress = lpStartAddress;
+ pNewThread->m_lpStartParameter = lpParameter;
+ pNewThread->m_bCreateSuspended = (dwCreationFlags & CREATE_SUSPENDED) == CREATE_SUSPENDED;
+ pNewThread->m_eThreadType = eThreadType;
+
+ if (0 != pthread_attr_init(&pthreadAttr))
+ {
+ ERROR("couldn't initialize pthread attributes\n");
+ palError = ERROR_INTERNAL_ERROR;
+ goto EXIT;
+ }
+
+ fAttributesInitialized = TRUE;
+
+ /* adjust the stack size if necessary */
+ if (0 != pthread_attr_getstacksize(&pthreadAttr, &pthreadStackSize))
+ {
+ ERROR("couldn't set thread stack size\n");
+ palError = ERROR_INTERNAL_ERROR;
+ goto EXIT;
+ }
+
+ TRACE("default pthread stack size is %d, caller requested %d (default is %d)\n",
+ pthreadStackSize, dwStackSize, CPalThread::s_dwDefaultThreadStackSize);
+
+ if (0 == dwStackSize)
+ {
+ dwStackSize = CPalThread::s_dwDefaultThreadStackSize;
+ }
+
+#ifdef PTHREAD_STACK_MIN
+ if (PTHREAD_STACK_MIN > pthreadStackSize)
+ {
+ WARN("default stack size is reported as %d, but PTHREAD_STACK_MIN is "
+ "%d\n", pthreadStackSize, PTHREAD_STACK_MIN);
+ }
+#endif
+
+ if (pthreadStackSize < dwStackSize)
+ {
+ TRACE("setting thread stack size to %d\n", dwStackSize);
+ if (0 != pthread_attr_setstacksize(&pthreadAttr, dwStackSize))
+ {
+ ERROR("couldn't set pthread stack size to %d\n", dwStackSize);
+ palError = ERROR_INTERNAL_ERROR;
+ goto EXIT;
+ }
+ }
+ else
+ {
+ TRACE("using the system default thread stack size of %d\n", pthreadStackSize);
+ }
+
+#if HAVE_THREAD_SELF || HAVE__LWP_SELF
+ /* Create new threads as "bound", so each pthread is permanently bound
+ to an LWP. Get/SetThreadContext() depend on this 1:1 mapping. */
+ pthread_attr_setscope(&pthreadAttr, PTHREAD_SCOPE_SYSTEM);
+#endif // HAVE_THREAD_SELF || HAVE__LWP_SELF
+
+ //
+ // We never call pthread_join, so create the new thread as detached
+ //
+
+ iError = pthread_attr_setdetachstate(&pthreadAttr, PTHREAD_CREATE_DETACHED);
+ _ASSERTE(0 == iError);
+
+ //
+ // Create the IPalObject for the thread and store it in the object
+ //
+
+ palError = CreateThreadObject(
+ pThread,
+ pNewThread,
+ &hNewThread);
+
+ if (NO_ERROR != palError)
+ {
+ goto EXIT;
+ }
+
+ //
+ // Add the thread to the process list
+ //
+
+ //
+ // We use the process lock to ensure that we're not interrupted
+ // during the creation process. After adding the CPalThread reference
+ // to the process list, we want to make sure the actual thread has been
+ // started. Otherwise, there's a window where the thread can be found
+ // in the process list but doesn't yet exist in the system.
+ //
+
+ PROCProcessLock();
+ fHoldingProcessLock = TRUE;
+
+ PROCAddThread(pThread, pNewThread);
+ fThreadDataAddedToProcessList = TRUE;
+
+ //
+ // Spawn the new pthread
+ //
+
+#if PTHREAD_CREATE_MODIFIES_ERRNO
+ storedErrno = errno;
+#endif // PTHREAD_CREATE_MODIFIES_ERRNO
+
+#ifdef FEATURE_PAL_SXS
+ _ASSERT_MSG(pNewThread->IsInPal(), "New threads we're about to spawn should always be in the PAL.\n");
+#endif // FEATURE_PAL_SXS
+ iError = pthread_create(&pthread, &pthreadAttr, CPalThread::ThreadEntry, pNewThread);
+
+#if PTHREAD_CREATE_MODIFIES_ERRNO
+ if (iError == 0)
+ {
+ // Restore errno if pthread_create succeeded.
+ errno = storedErrno;
+ }
+#endif // PTHREAD_CREATE_MODIFIES_ERRNO
+
+ if (0 != iError)
+ {
+ ERROR("pthread_create failed, error is %d (%s)\n", iError, strerror(iError));
+ palError = ERROR_NOT_ENOUGH_MEMORY;
+ goto EXIT;
+ }
+
+ //
+ // Wait for the new thread to finish its initial startup tasks
+ // (i.e., the ones that might fail)
+ //
+ if (pNewThread->WaitForStartStatus())
+ {
+ //
+ // Everything succeeded. Store the handle for the new thread and
+ // the thread's ID in the out params
+ //
+ *phThread = hNewThread;
+
+ if (NULL != lpThreadId)
+ {
+ *lpThreadId = pNewThread->GetThreadId();
+ }
+ }
+ else
+ {
+ ERROR("error occurred in THREADEntry, thread creation failed.\n");
+ palError = ERROR_INTERNAL_ERROR;
+ goto EXIT;
+ }
+
+ //
+ // If we're here, then we've locked the process list and both pthread_create
+ // and WaitForStartStatus succeeded. Thus, we can now unlock the process list.
+ // Since palError == NO_ERROR, we won't call this again in the exit block.
+ //
+ PROCProcessUnlock();
+ fHoldingProcessLock = FALSE;
+
+EXIT:
+
+ if (fAttributesInitialized)
+ {
+ if (0 != pthread_attr_destroy(&pthreadAttr))
+ {
+ WARN("pthread_attr_destroy() failed\n");
+ }
+ }
+
+ if (NO_ERROR != palError)
+ {
+ //
+ // We either were not able to create the new thread, or a failure
+ // occurred in the new thread's entry routine. Free up the associated
+ // resources here
+ //
+
+ if (fThreadDataAddedToProcessList)
+ {
+ PROCRemoveThread(pThread, pNewThread);
+ }
+ //
+ // Once we remove the thread from the process list, we can call
+ // PROCProcessUnlock.
+ //
+ if (fHoldingProcessLock)
+ {
+ PROCProcessUnlock();
+ }
+ fHoldingProcessLock = FALSE;
+ }
+
+ _ASSERT_MSG(!fHoldingProcessLock, "Exiting InternalCreateThread while still holding the process critical section.\n");
+
+ return palError;
+}
+
+
+
+/*++
+Function:
+ ExitThread
+
+See MSDN doc.
+--*/
+PAL_NORETURN
+VOID
+PALAPI
+ExitThread(
+ IN DWORD dwExitCode)
+{
+ CPalThread *pThread;
+
+ ENTRY("ExitThread(dwExitCode=%u)\n", dwExitCode);
+ PERF_ENTRY_ONLY(ExitThread);
+
+ pThread = InternalGetCurrentThread();
+
+ /* store the exit code */
+ pThread->SetExitCode(dwExitCode);
+
+ /* pthread_exit runs TLS destructors and cleanup routines,
+ possibly registered by foreign code. The right thing
+ to do here is to leave the PAL. Our own TLS destructor
+ re-enters us explicitly. */
+ PAL_Leave(PAL_BoundaryTop);
+
+ /* kill the thread (itself), resulting in a call to InternalEndCurrentThread */
+ pthread_exit(NULL);
+
+ ASSERT("pthread_exit should not return!\n");
+ for (;;);
+}
+
+/*++
+Function:
+ GetExitCodeThread
+
+See MSDN doc.
+--*/
+BOOL
+PALAPI
+GetExitCodeThread(
+ IN HANDLE hThread,
+ IN LPDWORD lpExitCode)
+{
+ PAL_ERROR palError = NO_ERROR;
+ CPalThread *pthrCurrent = NULL;
+ CPalThread *pthrTarget = NULL;
+ IPalObject *pobjThread = NULL;
+ BOOL fExitCodeSet;
+
+ PERF_ENTRY(GetExitCodeThread);
+ ENTRY("GetExitCodeThread(hThread = %p, lpExitCode = %p)\n",
+ hThread, lpExitCode);
+
+ if (NULL == lpExitCode)
+ {
+ WARN("Got NULL lpExitCode\n");
+ palError = ERROR_INVALID_PARAMETER;
+ goto done;
+ }
+
+ pthrCurrent = InternalGetCurrentThread();
+ palError = InternalGetThreadDataFromHandle(
+ pthrCurrent,
+ hThread,
+ 0,
+ &pthrTarget,
+ &pobjThread
+ );
+
+ pthrTarget->Lock(pthrCurrent);
+
+ fExitCodeSet = pthrTarget->GetExitCode(lpExitCode);
+ if (!fExitCodeSet)
+ {
+ if (TS_DONE == pthrTarget->synchronizationInfo.GetThreadState())
+ {
+#ifdef FEATURE_PAL_SXS
+ // The thread exited without ever calling ExitThread.
+ // It must have wandered in.
+ *lpExitCode = 0;
+#else // FEATURE_PAL_SXS
+ ASSERT("exit code not set but thread is dead\n");
+#endif // FEATURE_PAL_SXS
+ }
+ else
+ {
+ *lpExitCode = STILL_ACTIVE;
+ }
+ }
+
+ pthrTarget->Unlock(pthrCurrent);
+
+done:
+ if (NULL != pobjThread)
+ {
+ pobjThread->ReleaseReference(pthrCurrent);
+ }
+
+ LOGEXIT("GetExitCodeThread returns BOOL %d\n", NO_ERROR == palError);
+ PERF_EXIT(GetExitCodeThread);
+
+ return NO_ERROR == palError;
+}
+
+
+/*++
+Function:
+ InternalEndCurrentThread
+
+Does any necessary memory clean up, signals waiting threads, and then forces
+the current thread to exit.
+--*/
+
+VOID
+CorUnix::InternalEndCurrentThread(
+ CPalThread *pThread
+ )
+{
+ PAL_ERROR palError = NO_ERROR;
+ ISynchStateController *pSynchStateController = NULL;
+
+#ifdef PAL_PERF
+ PERFDisableThreadProfile(UserCreatedThread != pThread->GetThreadType());
+#endif
+
+ //
+ // Abandon any objects owned by this thread
+ //
+
+ palError = g_pSynchronizationManager->AbandonObjectsOwnedByThread(
+ pThread,
+ pThread
+ );
+
+ if (NO_ERROR != palError)
+ {
+ ERROR("Failure abandoning owned objects");
+ }
+
+ //
+ // Need to synchronize setting the thread state to TS_DONE since
+ // this is checked for in InternalSuspendThreadFromData.
+ // TODO: Is this still needed after removing InternalSuspendThreadFromData?
+ //
+
+ pThread->suspensionInfo.AcquireSuspensionLock(pThread);
+ IncrementEndingThreadCount();
+ pThread->synchronizationInfo.SetThreadState(TS_DONE);
+ pThread->suspensionInfo.ReleaseSuspensionLock(pThread);
+
+ //
+ // Mark the thread object as signaled
+ //
+
+ palError = pThread->GetThreadObject()->GetSynchStateController(
+ pThread,
+ &pSynchStateController
+ );
+
+ if (NO_ERROR == palError)
+ {
+ palError = pSynchStateController->SetSignalCount(1);
+ if (NO_ERROR != palError)
+ {
+ ASSERT("Unable to mark thread object as signaled");
+ }
+
+ pSynchStateController->ReleaseController();
+ }
+ else
+ {
+ ASSERT("Unable to obtain state controller for thread");
+ }
+
+#ifndef FEATURE_PAL_SXS
+ // If this is the last thread then delete the process' data,
+ // but don't exit because the application hosting the PAL
+ // might have its own threads.
+ if (PROCGetNumberOfThreads() == 1)
+ {
+ TRACE("Last thread is exiting\n");
+ DecrementEndingThreadCount();
+ TerminateCurrentProcessNoExit(FALSE);
+ }
+ else
+#endif // !FEATURE_PAL_SXS
+ {
+ /* Do this ONLY if we aren't the last thread -> otherwise
+ it gets done by TerminateProcess->
+ PROCCleanupProcess->PALShutdown->PAL_Terminate */
+
+ //
+ // Add a reference to the thread data before releasing the
+ // thread object, so we can still use it
+ //
+
+ pThread->AddThreadReference();
+
+ //
+ // Release the reference to the IPalObject for this thread
+ //
+
+ pThread->GetThreadObject()->ReleaseReference(pThread);
+
+ /* Remove thread for the thread list of the process
+ (don't do if this is the last thread -> gets handled by
+ TerminateProcess->PROCCleanupProcess->PROCTerminateOtherThreads) */
+
+ PROCRemoveThread(pThread, pThread);
+
+#ifdef FEATURE_PAL_SXS
+ // Ensure that EH is disabled on the current thread
+ SEHDisable(pThread);
+ PAL_Leave(PAL_BoundaryTop);
+#endif // FEATURE_PAL_SXS
+
+
+ //
+ // Now release our reference to the thread data. We cannot touch
+ // it after this point
+ //
+
+ pThread->ReleaseThreadReference();
+ DecrementEndingThreadCount();
+
+ }
+}
+
+/*++
+Function:
+ GetThreadPriority
+
+See MSDN doc.
+--*/
+int
+PALAPI
+GetThreadPriority(
+ IN HANDLE hThread)
+{
+ CPalThread *pThread;
+ PAL_ERROR palError;
+ int iPriority = THREAD_PRIORITY_ERROR_RETURN;
+
+ PERF_ENTRY(GetThreadPriority);
+ ENTRY("GetThreadPriority(hThread=%p)\n", hThread);
+
+ pThread = InternalGetCurrentThread();
+
+ palError = InternalGetThreadPriority(
+ pThread,
+ hThread,
+ &iPriority
+ );
+
+ if (NO_ERROR != palError)
+ {
+ pThread->SetLastError(palError);
+ }
+
+ LOGEXIT("GetThreadPriorityExit returns int %d\n", iPriority);
+ PERF_EXIT(GetThreadPriority);
+
+ return iPriority;
+}
+
+PAL_ERROR
+CorUnix::InternalGetThreadPriority(
+ CPalThread *pThread,
+ HANDLE hThread,
+ int *piPriority
+ )
+{
+ PAL_ERROR palError = NO_ERROR;
+ CPalThread *pTargetThread;
+ IPalObject *pobjThread = NULL;
+
+ palError = InternalGetThreadDataFromHandle(
+ pThread,
+ hThread,
+ 0, // THREAD_QUERY_INFORMATION
+ &pTargetThread,
+ &pobjThread
+ );
+
+ if (NO_ERROR != palError)
+ {
+ goto InternalGetThreadPriorityExit;
+ }
+
+ pTargetThread->Lock(pThread);
+
+ *piPriority = pTargetThread->GetThreadPriority();
+
+ pTargetThread->Unlock(pThread);
+
+InternalGetThreadPriorityExit:
+
+ if (NULL != pobjThread)
+ {
+ pobjThread->ReleaseReference(pThread);
+ }
+
+ return palError;
+}
+
+
+/*++
+Function:
+ SetThreadPriority
+
+See MSDN doc.
+--*/
+BOOL
+PALAPI
+SetThreadPriority(
+ IN HANDLE hThread,
+ IN int nPriority)
+{
+ CPalThread *pThread;
+ PAL_ERROR palError = NO_ERROR;
+
+ PERF_ENTRY(SetThreadPriority);
+ ENTRY("SetThreadPriority(hThread=%p, nPriority=%#x)\n", hThread, nPriority);
+
+ pThread = InternalGetCurrentThread();
+
+ palError = InternalSetThreadPriority(
+ pThread,
+ hThread,
+ nPriority
+ );
+
+ if (NO_ERROR != palError)
+ {
+ pThread->SetLastError(palError);
+ }
+
+ LOGEXIT("SetThreadPriority returns BOOL %d\n", NO_ERROR == palError);
+ PERF_EXIT(SetThreadPriority);
+
+ return NO_ERROR == palError;
+}
+
+PAL_ERROR
+CorUnix::InternalSetThreadPriority(
+ CPalThread *pThread,
+ HANDLE hTargetThread,
+ int iNewPriority
+ )
+{
+ PAL_ERROR palError = NO_ERROR;
+ CPalThread *pTargetThread = NULL;
+ IPalObject *pobjThread = NULL;
+
+ int policy;
+ struct sched_param schedParam;
+ int max_priority;
+ int min_priority;
+ float posix_priority;
+
+
+ palError = InternalGetThreadDataFromHandle(
+ pThread,
+ hTargetThread,
+ 0, // THREAD_SET_INFORMATION
+ &pTargetThread,
+ &pobjThread
+ );
+
+ if (NO_ERROR != palError)
+ {
+ goto InternalSetThreadPriorityExit;
+ }
+
+ pTargetThread->Lock(pThread);
+
+ /* validate the requested priority */
+ switch (iNewPriority)
+ {
+ case THREAD_PRIORITY_TIME_CRITICAL: /* fall through */
+ case THREAD_PRIORITY_IDLE:
+ break;
+
+ case THREAD_PRIORITY_HIGHEST: /* fall through */
+ case THREAD_PRIORITY_ABOVE_NORMAL: /* fall through */
+ case THREAD_PRIORITY_NORMAL: /* fall through */
+ case THREAD_PRIORITY_BELOW_NORMAL: /* fall through */
+ case THREAD_PRIORITY_LOWEST:
+#if PAL_IGNORE_NORMAL_THREAD_PRIORITY
+ /* We aren't going to set the thread priority. Just record what it is,
+ and exit */
+ pTargetThread->m_iThreadPriority = iNewPriority;
+ goto InternalSetThreadPriorityExit;
+#endif
+ break;
+
+ default:
+ ASSERT("Priority %d not supported\n", iNewPriority);
+ palError = ERROR_INVALID_PARAMETER;
+ goto InternalSetThreadPriorityExit;
+ }
+
+ /* check if the thread is still running */
+ if (TS_DONE == pTargetThread->synchronizationInfo.GetThreadState())
+ {
+ /* the thread has exited, set the priority in the thread structure
+ and exit */
+ pTargetThread->m_iThreadPriority = iNewPriority;
+ goto InternalSetThreadPriorityExit;
+ }
+
+ /* get the previous thread schedule parameters. We need to know the
+ scheduling policy to determine the priority range */
+ if (pthread_getschedparam(
+ pTargetThread->GetPThreadSelf(),
+ &policy,
+ &schedParam
+ ) != 0)
+ {
+ ASSERT("Unable to get current thread scheduling information\n");
+ palError = ERROR_INTERNAL_ERROR;
+ goto InternalSetThreadPriorityExit;
+ }
+
+#if !HAVE_SCHED_OTHER_ASSIGNABLE
+ /* Defining thread priority for SCHED_OTHER is implementation defined.
+ Some platforms like NetBSD cannot reassign it as they are dynamic.
+ */
+ if (policy == SCHED_OTHER)
+ {
+ TRACE("Pthread priority levels for SCHED_OTHER cannot be reassigned on this platform\n");
+ goto InternalSetThreadPriorityExit;
+ }
+#endif
+
+#if HAVE_SCHED_GET_PRIORITY
+ max_priority = sched_get_priority_max(policy);
+ min_priority = sched_get_priority_min(policy);
+ if( -1 == max_priority || -1 == min_priority)
+ {
+ ASSERT("sched_get_priority_min/max failed; error is %d (%s)\n",
+ errno, strerror(errno));
+ palError = ERROR_INTERNAL_ERROR;
+ goto InternalSetThreadPriorityExit;
+ }
+#else
+ max_priority = PAL_THREAD_PRIORITY_MAX;
+ min_priority = PAL_THREAD_PRIORITY_MIN;
+#endif
+
+ TRACE("Pthread priorities for policy %d must be in the range %d to %d\n",
+ policy, min_priority, max_priority);
+
+ /* explanation for fancy maths below :
+ POSIX doesn't specify the range of thread priorities that can be used
+ with pthread_setschedparam. Instead, one must use sched_get_priority_min
+ and sched_get_priority_max to obtain the lower and upper bounds of this
+ range. Since the PAL also uses a range of values (from Idle [-15] to
+ Time Critical [+15]), we have to do a mapping from a known range to an
+ unknown (at compilation) range.
+ We do this by :
+ -substracting the minimal PAL priority from the desired priority. this
+ gives a value between 0 and the PAL priority range
+ -dividing this value by the PAL priority range. this allows us to
+ express the desired priority as a floating-point value between 0 and 1
+ -multiplying this value by the PTHREAD priority range. This gives a
+ value between 0 and the PTHREAD priority range
+ -adding the minimal PTHREAD priority range. This will give us a value
+ between the minimal and maximla pthread priority, which should be
+ equivalent to the original PAL value.
+
+ example : suppose a pthread range 100 to 200, and a desired priority
+ of 0 (halfway between PAL minimum and maximum)
+ 0 - (IDLE [-15]) = 15
+ 15 / (TIMECRITICAL[15] - IDLE[-15]) = 0.5
+ 0.5 * (pthreadmax[200]-pthreadmin[100]) = 50
+ 50 + pthreadmin[100] = 150 -> halfway between pthread min and max
+ */
+ posix_priority = (iNewPriority - THREAD_PRIORITY_IDLE);
+ posix_priority /= (THREAD_PRIORITY_TIME_CRITICAL - THREAD_PRIORITY_IDLE);
+ posix_priority *= (max_priority-min_priority);
+ posix_priority += min_priority;
+
+ schedParam.sched_priority = (int)posix_priority;
+
+ TRACE("PAL priority %d is mapped to pthread priority %d\n",
+ iNewPriority, schedParam.sched_priority);
+
+ /* Finally, set the new priority into place */
+ if (pthread_setschedparam(
+ pTargetThread->GetPThreadSelf(),
+ policy,
+ &schedParam
+ ) != 0)
+ {
+#if SET_SCHEDPARAM_NEEDS_PRIVS
+ if (EPERM == errno)
+ {
+ // UNIXTODO: Should log a warning to the event log
+ TRACE("Caller does not have OS privileges to call pthread_setschedparam\n");
+ pTargetThread->m_iThreadPriority = iNewPriority;
+ goto InternalSetThreadPriorityExit;
+ }
+#endif
+
+ ASSERT("Unable to set thread priority (errno %d)\n", errno);
+ palError = ERROR_INTERNAL_ERROR;
+ goto InternalSetThreadPriorityExit;
+ }
+
+ pTargetThread->m_iThreadPriority = iNewPriority;
+
+InternalSetThreadPriorityExit:
+
+ if (NULL != pTargetThread)
+ {
+ pTargetThread->Unlock(pThread);
+ }
+
+ if (NULL != pobjThread)
+ {
+ pobjThread->ReleaseReference(pThread);
+ }
+
+ return palError;
+}
+
+BOOL
+CorUnix::GetThreadTimesInternal(
+ IN HANDLE hThread,
+ OUT LPFILETIME lpKernelTime,
+ OUT LPFILETIME lpUserTime)
+{
+ __int64 calcTime;
+ BOOL retval = FALSE;
+ const __int64 SECS_TO_NS = 1000000000; /* 10^9 */
+ const __int64 USECS_TO_NS = 1000; /* 10^3 */
+
+#if HAVE_MACH_THREADS
+ thread_basic_info resUsage;
+ PAL_ERROR palError = NO_ERROR;
+ CPalThread *pthrCurrent = NULL;
+ CPalThread *pthrTarget = NULL;
+ IPalObject *pobjThread = NULL;
+ mach_msg_type_number_t resUsage_count = THREAD_BASIC_INFO_COUNT;
+
+ pthrCurrent = InternalGetCurrentThread();
+ palError = InternalGetThreadDataFromHandle(
+ pthrCurrent,
+ hThread,
+ 0,
+ &pthrTarget,
+ &pobjThread
+ );
+
+ if (palError != NO_ERROR)
+ {
+ ASSERT("Unable to get thread data from handle %p"
+ "thread\n", hThread);
+ SetLastError(ERROR_INTERNAL_ERROR);
+ goto SetTimesToZero;
+ }
+
+ pthrTarget->Lock(pthrCurrent);
+
+ mach_port_t mhThread;
+ mhThread = pthread_mach_thread_np(pthrTarget->GetPThreadSelf());
+
+ kern_return_t status;
+ status = thread_info(
+ mhThread,
+ THREAD_BASIC_INFO,
+ (thread_info_t)&resUsage,
+ &resUsage_count);
+
+ pthrTarget->Unlock(pthrCurrent);
+
+ if (status != KERN_SUCCESS)
+ {
+ ASSERT("Unable to get resource usage information for the current "
+ "thread\n");
+ SetLastError(ERROR_INTERNAL_ERROR);
+ goto SetTimesToZero;
+ }
+
+ /* Get the time of user mode execution, in nanoseconds */
+ calcTime = (__int64)resUsage.user_time.seconds * SECS_TO_NS;
+ calcTime += (__int64)resUsage.user_time.microseconds * USECS_TO_NS;
+ /* Assign the time into lpUserTime */
+ lpUserTime->dwLowDateTime = (DWORD)calcTime;
+ lpUserTime->dwHighDateTime = (DWORD)(calcTime >> 32);
+
+ /* Get the time of kernel mode execution, in nanoseconds */
+ calcTime = (__int64)resUsage.system_time.seconds * SECS_TO_NS;
+ calcTime += (__int64)resUsage.system_time.microseconds * USECS_TO_NS;
+ /* Assign the time into lpKernelTime */
+ lpKernelTime->dwLowDateTime = (DWORD)calcTime;
+ lpKernelTime->dwHighDateTime = (DWORD)(calcTime >> 32);
+
+ retval = TRUE;
+
+ goto GetThreadTimesInternalExit;
+
+#elif defined(__NetBSD__) && !HAVE_PTHREAD_GETCPUCLOCKID /* Currently unimplemented */
+
+ PAL_ERROR palError;
+ CPalThread *pThread;
+ CPalThread *pTargetThread;
+ IPalObject *pobjThread = NULL;
+ kvm_t *kd;
+ int cnt, nlwps;
+ struct kinfo_lwp *klwp;
+ int i;
+ bool found = false;
+
+ pThread = InternalGetCurrentThread();
+
+ palError = InternalGetThreadDataFromHandle(
+ pThread,
+ hThread,
+ 0, // THREAD_GET_CONTEXT
+ &pTargetThread,
+ &pobjThread
+ );
+ if (palError != NO_ERROR)
+ {
+ ASSERT("Unable to get thread data from handle %p"
+ "thread\n", hThread);
+ SetLastError(ERROR_INTERNAL_ERROR);
+ goto SetTimesToZero;
+ }
+
+ kd = kvm_open(NULL, NULL, NULL, KVM_NO_FILES, "kvm_open");
+ if (kd == NULL)
+ {
+ ASSERT("kvm_open(3) error");
+ SetLastError(ERROR_INTERNAL_ERROR);
+ goto SetTimesToZero;
+ }
+
+ pTargetThread->Lock(pThread);
+
+ klwp = kvm_getlwps(kd, getpid(), 0, sizeof(struct kinfo_lwp), &nlwps);
+ if (klwp == NULL || nlwps < 1)
+ {
+ kvm_close(kd);
+ ASSERT("Unable to get clock from %p thread\n", hThread);
+ SetLastError(ERROR_INTERNAL_ERROR);
+ pTargetThread->Unlock(pThread);
+ goto SetTimesToZero;
+ }
+
+ for (i = 0; i < nlwps; i++)
+ {
+ if (klwp[i].l_lid == THREADSilentGetCurrentThreadId())
+ {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found)
+ {
+ kvm_close(kd);
+ ASSERT("Unable to get clock from %p thread\n", hThread);
+ SetLastError(ERROR_INTERNAL_ERROR);
+ pTargetThread->Unlock(pThread);
+ goto SetTimesToZero;
+ }
+
+ pTargetThread->Unlock(pThread);
+
+ kvm_close(kd);
+
+ calcTime = (__int64) klwp[i].l_rtime_sec * SECS_TO_NS;
+ calcTime += (__int64) klwp[i].l_rtime_usec * USECS_TO_NS;
+ lpUserTime->dwLowDateTime = (DWORD)calcTime;
+ lpUserTime->dwHighDateTime = (DWORD)(calcTime >> 32);
+
+ /* NetBSD as of (7.0) doesn't differentiate used time in user/kernel for lwp */
+ lpKernelTime->dwLowDateTime = 0;
+ lpKernelTime->dwHighDateTime = 0;
+
+ retval = TRUE;
+ goto GetThreadTimesInternalExit;
+
+#else //HAVE_MACH_THREADS
+
+ PAL_ERROR palError;
+ CPalThread *pThread;
+ CPalThread *pTargetThread;
+ IPalObject *pobjThread = NULL;
+ clockid_t cid;
+
+ pThread = InternalGetCurrentThread();
+
+ palError = InternalGetThreadDataFromHandle(
+ pThread,
+ hThread,
+ 0, // THREAD_GET_CONTEXT
+ &pTargetThread,
+ &pobjThread
+ );
+ if (palError != NO_ERROR)
+ {
+ ASSERT("Unable to get thread data from handle %p"
+ "thread\n", hThread);
+ SetLastError(ERROR_INTERNAL_ERROR);
+ goto SetTimesToZero;
+ }
+
+ pTargetThread->Lock(pThread);
+
+#if HAVE_PTHREAD_GETCPUCLOCKID
+ if (pthread_getcpuclockid(pTargetThread->GetPThreadSelf(), &cid) != 0)
+#endif
+ {
+ ASSERT("Unable to get clock from thread\n", hThread);
+ SetLastError(ERROR_INTERNAL_ERROR);
+ pTargetThread->Unlock(pThread);
+ goto SetTimesToZero;
+ }
+
+ struct timespec ts;
+ if (clock_gettime(cid, &ts) != 0)
+ {
+ ASSERT("clock_gettime() failed; errno is %d (%s)\n", errno, strerror(errno));
+ SetLastError(ERROR_INTERNAL_ERROR);
+ pTargetThread->Unlock(pThread);
+ goto SetTimesToZero;
+ }
+
+ pTargetThread->Unlock(pThread);
+
+ /* Calculate time in nanoseconds and assign to user time */
+ calcTime = (__int64) ts.tv_sec * SECS_TO_NS;
+ calcTime += (__int64) ts.tv_nsec;
+ lpUserTime->dwLowDateTime = (DWORD)calcTime;
+ lpUserTime->dwHighDateTime = (DWORD)(calcTime >> 32);
+
+ /* Set kernel time to zero, for now */
+ lpKernelTime->dwLowDateTime = 0;
+ lpKernelTime->dwHighDateTime = 0;
+
+ retval = TRUE;
+ goto GetThreadTimesInternalExit;
+
+#endif //HAVE_MACH_THREADS
+
+SetTimesToZero:
+
+ lpUserTime->dwLowDateTime = 0;
+ lpUserTime->dwHighDateTime = 0;
+ lpKernelTime->dwLowDateTime = 0;
+ lpKernelTime->dwHighDateTime = 0;
+ goto GetThreadTimesInternalExit;
+
+GetThreadTimesInternalExit:
+ return retval;
+}
+
+/*++
+Function:
+ GetThreadTimes
+
+See MSDN doc.
+--*/
+BOOL
+PALAPI
+GetThreadTimes(
+ IN HANDLE hThread,
+ OUT LPFILETIME lpCreationTime,
+ OUT LPFILETIME lpExitTime,
+ OUT LPFILETIME lpKernelTime,
+ OUT LPFILETIME lpUserTime)
+{
+ PERF_ENTRY(GetThreadTimes);
+ ENTRY("GetThreadTimes(hThread=%p, lpExitTime=%p, lpKernelTime=%p,"
+ "lpUserTime=%p)\n",
+ hThread, lpCreationTime, lpExitTime, lpKernelTime, lpUserTime );
+
+ FILETIME KernelTime, UserTime;
+
+ BOOL retval = GetThreadTimesInternal(hThread, &KernelTime, &UserTime);
+
+ /* Not sure if this still needs to be here */
+ /*
+ TRACE ("thread_info User: %ld sec,%ld microsec. Kernel: %ld sec,%ld"
+ " microsec\n",
+ resUsage.user_time.seconds, resUsage.user_time.microseconds,
+ resUsage.system_time.seconds, resUsage.system_time.microseconds);
+ */
+
+ __int64 calcTime;
+ if (lpUserTime)
+ {
+ /* Produce the time in 100s of ns */
+ calcTime = ((ULONG64)UserTime.dwHighDateTime << 32);
+ calcTime += (ULONG64)UserTime.dwLowDateTime;
+ calcTime /= 100;
+ lpUserTime->dwLowDateTime = (DWORD)calcTime;
+ lpUserTime->dwHighDateTime = (DWORD)(calcTime >> 32);
+ }
+ if (lpKernelTime)
+ {
+ /* Produce the time in 100s of ns */
+ calcTime = ((ULONG64)KernelTime.dwHighDateTime << 32);
+ calcTime += (ULONG64)KernelTime.dwLowDateTime;
+ calcTime /= 100;
+ lpKernelTime->dwLowDateTime = (DWORD)calcTime;
+ lpKernelTime->dwHighDateTime = (DWORD)(calcTime >> 32);
+ }
+ //Set CreationTime and Exit time to zero for now - maybe change this later?
+ if (lpCreationTime)
+ {
+ lpCreationTime->dwLowDateTime = 0;
+ lpCreationTime->dwHighDateTime = 0;
+ }
+
+ if (lpExitTime)
+ {
+ lpExitTime->dwLowDateTime = 0;
+ lpExitTime->dwHighDateTime = 0;
+ }
+
+ LOGEXIT("GetThreadTimes returns BOOL %d\n", retval);
+ PERF_EXIT(GetThreadTimes);
+ return (retval);
+}
+
+
+
+void *
+CPalThread::ThreadEntry(
+ void *pvParam
+ )
+{
+ PAL_ERROR palError;
+ CPalThread *pThread;
+ PTHREAD_START_ROUTINE pfnStartRoutine;
+ LPVOID pvPar;
+ DWORD retValue;
+
+ pThread = reinterpret_cast<CPalThread*>(pvParam);
+
+ if (NULL == pThread)
+ {
+ ASSERT("THREAD pointer is NULL!\n");
+ goto fail;
+ }
+
+#if defined(FEATURE_PAL_SXS) && defined(_DEBUG)
+ // We cannot assert yet, as we haven't set in this thread into the TLS, and so __ASSERT_ENTER
+ // will fail if the assert fails and we'll crash.
+ //_ASSERT_MSG(pThread->m_fInPal == 1, "New threads should always be in the PAL upon ThreadEntry.\n");
+ if (g_Dbg_asserts_enabled && pThread->m_fInPal != 1)
+ DebugBreak();
+#endif // FEATURE_PAL_SXS && _DEBUG
+
+ pThread->m_threadId = THREADSilentGetCurrentThreadId();
+ pThread->m_pthreadSelf = pthread_self();
+#if HAVE_MACH_THREADS
+ pThread->m_machPortSelf = pthread_mach_thread_np(pThread->m_pthreadSelf);
+#endif
+#if HAVE_THREAD_SELF
+ pThread->m_dwLwpId = (DWORD) thread_self();
+#elif HAVE__LWP_SELF
+ pThread->m_dwLwpId = (DWORD) _lwp_self();
+#else
+ pThread->m_dwLwpId = 0;
+#endif
+
+ palError = pThread->RunPostCreateInitializers();
+ if (NO_ERROR != palError)
+ {
+ ASSERT("Error %i initializing thread data (post creation)\n", palError);
+ goto fail;
+ }
+
+ // Check if the thread should be started suspended.
+ if (pThread->GetCreateSuspended())
+ {
+ palError = pThread->suspensionInfo.InternalSuspendNewThreadFromData(pThread);
+ if (NO_ERROR != palError)
+ {
+ ASSERT("Error %i attempting to suspend new thread\n", palError);
+ goto fail;
+ }
+
+ //
+ // We need to run any APCs that have already been queued for
+ // this thread.
+ //
+
+ (void) g_pSynchronizationManager->DispatchPendingAPCs(pThread);
+ }
+ else
+ {
+ //
+ // All startup operations that might have failed have succeeded,
+ // so thread creation is successful. Let CreateThread return.
+ //
+
+ pThread->SetStartStatus(TRUE);
+ }
+
+ pThread->synchronizationInfo.SetThreadState(TS_RUNNING);
+
+ if (UserCreatedThread == pThread->GetThreadType())
+ {
+ /* Inform all loaded modules that a thread has been created */
+ /* note : no need to take a critical section to serialize here; the loader
+ will take the module critical section */
+ LOADCallDllMain(DLL_THREAD_ATTACH, NULL);
+ }
+
+#ifdef PAL_PERF
+ PERFAllocThreadInfo();
+ PERFEnableThreadProfile(UserCreatedThread != pThread->GetThreadType());
+#endif
+
+ /* call the startup routine */
+ pfnStartRoutine = pThread->GetStartAddress();
+ pvPar = pThread->GetStartParameter();
+
+ retValue = (*pfnStartRoutine)(pvPar);
+
+ TRACE("Thread exited (%u)\n", retValue);
+ ExitThread(retValue);
+
+ /* Note: never get here */
+ ASSERT("ExitThread failed!\n");
+ for (;;);
+
+fail:
+
+ //
+ // Notify InternalCreateThread that a failure occurred
+ //
+
+ if (NULL != pThread)
+ {
+ pThread->synchronizationInfo.SetThreadState(TS_FAILED);
+ pThread->SetStartStatus(FALSE);
+ }
+
+ /* do not call ExitThread : we don't want to call DllMain(), and the thread
+ isn't in a clean state (e.g. lpThread isn't in TLS). the cleanup work
+ above should release all resources */
+ return NULL;
+}
+
+
+#define PAL_THREAD_DEFAULT_STACK_SIZE "PAL_THREAD_DEFAULT_STACK_SIZE"
+
+PAL_ERROR
+CorUnix::InitializeGlobalThreadData(
+ void
+ )
+{
+ PAL_ERROR palError = NO_ERROR;
+ char *pszStackSize = NULL;
+
+ //
+ // Read in the environment to see whether we need to change the default
+ // thread stack size.
+ //
+ pszStackSize = EnvironGetenv(PAL_THREAD_DEFAULT_STACK_SIZE);
+ if (NULL != pszStackSize)
+ {
+ // Environment variable exists
+ char *pszEnd;
+ DWORD dw = PAL_strtoul(pszStackSize, &pszEnd, 16); // treat it as hex
+ if ( (pszStackSize != pszEnd) && (0 != dw) )
+ {
+ CPalThread::s_dwDefaultThreadStackSize = dw;
+ }
+
+ free(pszStackSize);
+ }
+
+ return palError;
+}
+
+
+/*++
+Function:
+ CreateThreadData
+
+Abstract:
+ Create the CPalThread for the startup thread
+ or another external thread entering the PAL
+ for the first time
+
+Parameters:
+ ppThread - on success, receives the CPalThread
+
+Return:
+ PAL_ERROR
+--*/
+
+PAL_ERROR
+CorUnix::CreateThreadData(
+ CPalThread **ppThread
+ )
+{
+ PAL_ERROR palError = NO_ERROR;
+ CPalThread *pThread = NULL;
+
+ /* Create the thread object */
+ pThread = AllocTHREAD();
+
+ if (NULL == pThread)
+ {
+ palError = ERROR_OUTOFMEMORY;
+ goto CreateThreadDataExit;
+ }
+
+ palError = pThread->RunPreCreateInitializers();
+
+ if (NO_ERROR != palError)
+ {
+ goto CreateThreadDataExit;
+ }
+
+ pThread->SetLastError(0);
+
+ pThread->m_threadId = THREADSilentGetCurrentThreadId();
+ pThread->m_pthreadSelf = pthread_self();
+#if HAVE_MACH_THREADS
+ pThread->m_machPortSelf = pthread_mach_thread_np(pThread->m_pthreadSelf);
+#endif
+#if HAVE_THREAD_SELF
+ pThread->m_dwLwpId = (DWORD) thread_self();
+#elif HAVE__LWP_SELF
+ pThread->m_dwLwpId = (DWORD) _lwp_self();
+#else
+ pThread->m_dwLwpId = 0;
+#endif
+
+ palError = pThread->RunPostCreateInitializers();
+ if (NO_ERROR != palError)
+ {
+ goto CreateThreadDataExit;
+ }
+
+ *ppThread = pThread;
+
+CreateThreadDataExit:
+
+ if (NO_ERROR != palError)
+ {
+ if (NULL != pThread)
+ {
+ pThread->ReleaseThreadReference();
+ }
+ }
+
+ return palError;
+}
+
+/*++
+Function:
+ CreateThreadData
+
+Abstract:
+ Creates the IPalObject for a thread, storing
+ the reference in the CPalThread
+
+Parameters:
+ pThread - the thread data for the creating thread
+ pNewThread - the thread data for the thread being initialized
+
+Return:
+ PAL_ERROR
+--*/
+
+PAL_ERROR
+CorUnix::CreateThreadObject(
+ CPalThread *pThread,
+ CPalThread *pNewThread,
+ HANDLE *phThread
+ )
+{
+ PAL_ERROR palError = NO_ERROR;
+ IPalObject *pobjThread = NULL;
+ IDataLock *pDataLock;
+ HANDLE hThread = NULL;
+ CThreadProcessLocalData *pLocalData = NULL;
+ CObjectAttributes oa;
+ BOOL fThreadDataStoredInObject = FALSE;
+ IPalObject *pobjRegisteredThread = NULL;
+
+ //
+ // Create the IPalObject for the thread
+ //
+
+ palError = g_pObjectManager->AllocateObject(
+ pThread,
+ &otThread,
+ &oa,
+ &pobjThread
+ );
+
+ if (NO_ERROR != palError)
+ {
+ goto CreateThreadObjectExit;
+ }
+
+ //
+ // Store the CPalThread inside of the IPalObject
+ //
+
+ palError = pobjThread->GetProcessLocalData(
+ pThread,
+ WriteLock,
+ &pDataLock,
+ reinterpret_cast<void **>(&pLocalData)
+ );
+
+ if (NO_ERROR != palError)
+ {
+ goto CreateThreadObjectExit;
+ }
+
+ pLocalData->pThread = pNewThread;
+ pDataLock->ReleaseLock(pThread, TRUE);
+ fThreadDataStoredInObject = TRUE;
+
+ //
+ // Register the IPalObject (obtaining a handle)
+ //
+
+ palError = g_pObjectManager->RegisterObject(
+ pThread,
+ pobjThread,
+ &aotThread,
+ 0, //THREAD_ALL_ACCESS,
+ &hThread,
+ &pobjRegisteredThread
+ );
+
+ //
+ // pobjThread is invalidated by the call to RegisterObject, so NULL
+ // it out here to prevent it from being released
+ //
+
+ pobjThread = NULL;
+
+ if (NO_ERROR != palError)
+ {
+ goto CreateThreadObjectExit;
+ }
+
+ //
+ // Store the registered object inside of the thread object,
+ // adding a reference for the thread itself
+ //
+
+ pNewThread->m_pThreadObject = pobjRegisteredThread;
+ pNewThread->m_pThreadObject->AddReference();
+
+ *phThread = hThread;
+
+CreateThreadObjectExit:
+
+ if (NO_ERROR != palError)
+ {
+ if (NULL != hThread)
+ {
+ g_pObjectManager->RevokeHandle(pThread, hThread);
+ }
+
+ if (NULL != pNewThread->m_pThreadObject)
+ {
+ //
+ // Release the new thread's reference on the underlying thread
+ // object
+ //
+
+ pNewThread->m_pThreadObject->ReleaseReference(pThread);
+ }
+
+ if (!fThreadDataStoredInObject)
+ {
+ //
+ // The CPalThread for the new thread was never stored in
+ // an IPalObject instance, so we need to release the initial
+ // reference here. (If it has been stored it will get freed in
+ // the owning object's cleanup routine)
+ //
+
+ pNewThread->ReleaseThreadReference();
+ }
+ }
+
+ if (NULL != pobjThread)
+ {
+ pobjThread->ReleaseReference(pThread);
+ }
+
+ if (NULL != pobjRegisteredThread)
+ {
+ pobjRegisteredThread->ReleaseReference(pThread);
+ }
+
+ return palError;
+}
+
+PAL_ERROR
+CorUnix::InternalCreateDummyThread(
+ CPalThread *pThread,
+ LPSECURITY_ATTRIBUTES lpThreadAttributes,
+ CPalThread **ppDummyThread,
+ HANDLE *phThread
+ )
+{
+ PAL_ERROR palError = NO_ERROR;
+ CPalThread *pDummyThread = NULL;
+ IPalObject *pobjThread = NULL;
+ IPalObject *pobjThreadRegistered = NULL;
+ IDataLock *pDataLock;
+ CThreadProcessLocalData *pLocalData;
+ CObjectAttributes oa(NULL, lpThreadAttributes);
+ bool fThreadDataStoredInObject = FALSE;
+
+ pDummyThread = AllocTHREAD();
+ if (NULL == pDummyThread)
+ {
+ palError = ERROR_OUTOFMEMORY;
+ goto InternalCreateDummyThreadExit;
+ }
+
+ pDummyThread->m_fIsDummy = TRUE;
+
+ palError = g_pObjectManager->AllocateObject(
+ pThread,
+ &otThread,
+ &oa,
+ &pobjThread
+ );
+
+ if (NO_ERROR != palError)
+ {
+ goto InternalCreateDummyThreadExit;
+ }
+
+ palError = pobjThread->GetProcessLocalData(
+ pThread,
+ WriteLock,
+ &pDataLock,
+ reinterpret_cast<void **>(&pLocalData)
+ );
+
+ if (NO_ERROR != palError)
+ {
+ goto InternalCreateDummyThreadExit;
+ }
+
+ pLocalData->pThread = pDummyThread;
+ pDataLock->ReleaseLock(pThread, TRUE);
+ fThreadDataStoredInObject = TRUE;
+
+ palError = g_pObjectManager->RegisterObject(
+ pThread,
+ pobjThread,
+ &aotThread,
+ 0, // THREAD_ALL_ACCESS
+ phThread,
+ &pobjThreadRegistered
+ );
+
+ //
+ // pobjThread is invalidated by the above call, so NULL
+ // it out here
+ //
+
+ pobjThread = NULL;
+
+ if (NO_ERROR != palError)
+ {
+ goto InternalCreateDummyThreadExit;
+ }
+
+ //
+ // Note the we do NOT store the registered object for the
+ // thread w/in pDummyThread. Since this thread is not actually
+ // executing that reference would never be released (and thus
+ // the thread object would never be cleaned up...)
+ //
+
+ *ppDummyThread = pDummyThread;
+
+InternalCreateDummyThreadExit:
+
+ if (NULL != pobjThreadRegistered)
+ {
+ pobjThreadRegistered->ReleaseReference(pThread);
+ }
+
+ if (NULL != pobjThread)
+ {
+ pobjThread->ReleaseReference(pThread);
+ }
+
+ if (NO_ERROR != palError
+ && NULL != pDummyThread
+ && !fThreadDataStoredInObject)
+ {
+ pDummyThread->ReleaseThreadReference();
+ }
+
+ return palError;
+}
+
+PAL_ERROR
+CorUnix::InternalGetThreadDataFromHandle(
+ CPalThread *pThread,
+ HANDLE hThread,
+ DWORD dwRightsRequired,
+ CPalThread **ppTargetThread,
+ IPalObject **ppobjThread
+ )
+{
+ PAL_ERROR palError = NO_ERROR;
+ IPalObject *pobj;
+ IDataLock *pLock;
+ CThreadProcessLocalData *pData;
+
+ *ppobjThread = NULL;
+
+ if (hPseudoCurrentThread == hThread)
+ {
+ *ppTargetThread = pThread;
+ }
+ else
+ {
+ palError = g_pObjectManager->ReferenceObjectByHandle(
+ pThread,
+ hThread,
+ &aotThread,
+ dwRightsRequired,
+ &pobj
+ );
+
+ if (NO_ERROR == palError)
+ {
+ palError = pobj->GetProcessLocalData(
+ pThread,
+ ReadLock,
+ &pLock,
+ reinterpret_cast<void**>(&pData)
+ );
+
+ if (NO_ERROR == palError)
+ {
+ *ppTargetThread = pData->pThread;
+ pLock->ReleaseLock(pThread, FALSE);
+
+ //
+ // Transfer object reference to out param
+ //
+
+ *ppobjThread = pobj;
+ }
+ else
+ {
+ pobj->ReleaseReference(pThread);
+ }
+ }
+ }
+
+ return palError;
+}
+
+PAL_ERROR
+CPalThread::RunPreCreateInitializers(
+ void
+ )
+{
+ PAL_ERROR palError = NO_ERROR;
+ int iError;
+
+ //
+ // First, perform initialization of CPalThread private members
+ //
+
+ InternalInitializeCriticalSection(&m_csLock);
+ m_fLockInitialized = TRUE;
+
+ iError = pthread_mutex_init(&m_startMutex, NULL);
+ if (0 != iError)
+ {
+ goto RunPreCreateInitializersExit;
+ }
+
+ iError = pthread_cond_init(&m_startCond, NULL);
+ if (0 != iError)
+ {
+ pthread_mutex_destroy(&m_startMutex);
+ goto RunPreCreateInitializersExit;
+ }
+
+ m_fStartItemsInitialized = TRUE;
+
+ //
+ // Call the pre-create initializers for embedded classes
+ //
+
+ palError = synchronizationInfo.InitializePreCreate();
+ if (NO_ERROR != palError)
+ {
+ goto RunPreCreateInitializersExit;
+ }
+
+ palError = suspensionInfo.InitializePreCreate();
+ if (NO_ERROR != palError)
+ {
+ goto RunPreCreateInitializersExit;
+ }
+
+ palError = sehInfo.InitializePreCreate();
+ if (NO_ERROR != palError)
+ {
+ goto RunPreCreateInitializersExit;
+ }
+
+ palError = tlsInfo.InitializePreCreate();
+ if (NO_ERROR != palError)
+ {
+ goto RunPreCreateInitializersExit;
+ }
+
+ palError = apcInfo.InitializePreCreate();
+ if (NO_ERROR != palError)
+ {
+ goto RunPreCreateInitializersExit;
+ }
+
+ palError = crtInfo.InitializePreCreate();
+ if (NO_ERROR != palError)
+ {
+ goto RunPreCreateInitializersExit;
+ }
+
+RunPreCreateInitializersExit:
+
+ return palError;
+}
+
+CPalThread::~CPalThread()
+{
+ // @UNIXTODO: This is our last chance to unlink our Mach exception handler from the pseudo-chain we're trying
+ // to maintain. Unfortunately we don't have enough data or control to do this at all well (and we can't
+ // guarantee that another component hasn't chained to us, about which we can do nothing). If the kernel or
+ // another component forwards an exception notification to us for this thread things will go badly (we'll
+ // terminate the process when trying to look up this CPalThread in order to find forwarding information).
+ // On the flip side I don't believe we'll get here currently unless the thread has been terminated (in
+ // which case it's not an issue). If we start supporting unload or early disposal of CPalThread objects
+ // (say when we return from an outer reverse p/invoke) then we'll need to revisit this. But hopefully by
+ // then we'll have an alternative design for handling hardware exceptions.
+
+ if (m_fLockInitialized)
+ {
+ InternalDeleteCriticalSection(&m_csLock);
+ }
+
+ if (m_fStartItemsInitialized)
+ {
+ int iError;
+
+ iError = pthread_cond_destroy(&m_startCond);
+ _ASSERTE(0 == iError);
+
+ iError = pthread_mutex_destroy(&m_startMutex);
+ _ASSERTE(0 == iError);
+ }
+}
+
+void
+CPalThread::AddThreadReference(
+ void
+ )
+{
+ InterlockedIncrement(&m_lRefCount);
+}
+
+void
+CPalThread::ReleaseThreadReference(
+ void
+ )
+{
+ LONG lRefCount = InterlockedDecrement(&m_lRefCount);
+ _ASSERT_MSG(lRefCount >= 0, "Released a thread and ended with a negative refcount (%ld)\n", lRefCount);
+ if (0 == lRefCount)
+ {
+ FreeTHREAD(this);
+ }
+
+}
+
+PAL_ERROR
+CPalThread::RunPostCreateInitializers(
+ void
+ )
+{
+ PAL_ERROR palError = NO_ERROR;
+
+ //
+ // Call the post-create initializers for embedded classes
+ //
+
+ palError = synchronizationInfo.InitializePostCreate(this, m_threadId, m_dwLwpId);
+ if (NO_ERROR != palError)
+ {
+ goto RunPostCreateInitializersExit;
+ }
+
+ palError = suspensionInfo.InitializePostCreate(this, m_threadId, m_dwLwpId);
+ if (NO_ERROR != palError)
+ {
+ goto RunPostCreateInitializersExit;
+ }
+
+ palError = sehInfo.InitializePostCreate(this, m_threadId, m_dwLwpId);
+ if (NO_ERROR != palError)
+ {
+ goto RunPostCreateInitializersExit;
+ }
+
+ palError = tlsInfo.InitializePostCreate(this, m_threadId, m_dwLwpId);
+ if (NO_ERROR != palError)
+ {
+ goto RunPostCreateInitializersExit;
+ }
+
+ palError = apcInfo.InitializePostCreate(this, m_threadId, m_dwLwpId);
+ if (NO_ERROR != palError)
+ {
+ goto RunPostCreateInitializersExit;
+ }
+
+ palError = crtInfo.InitializePostCreate(this, m_threadId, m_dwLwpId);
+ if (NO_ERROR != palError)
+ {
+ goto RunPostCreateInitializersExit;
+ }
+
+#ifdef FEATURE_PAL_SXS
+ _ASSERTE(m_fInPal);
+ palError = SEHEnable(this);
+ if (NO_ERROR != palError)
+ {
+ goto RunPostCreateInitializersExit;
+ }
+#endif // FEATURE_PAL_SXS
+
+RunPostCreateInitializersExit:
+
+ return palError;
+}
+
+void
+CPalThread::SetStartStatus(
+ bool fStartSucceeded
+ )
+{
+ int iError;
+
+#if _DEBUG
+ if (m_fStartStatusSet)
+ {
+ ASSERT("Multiple calls to CPalThread::SetStartStatus\n");
+ }
+#endif
+
+ //
+ // This routine may get called from CPalThread::ThreadEntry
+ //
+ // If we've reached this point there are no further thread
+ // suspensions that happen at creation time, so reset
+ // m_bCreateSuspended
+ //
+
+ m_bCreateSuspended = FALSE;
+
+ iError = pthread_mutex_lock(&m_startMutex);
+ if (0 != iError)
+ {
+ ASSERT("pthread primitive failure\n");
+ // bugcheck?
+ }
+
+ m_fStartStatus = fStartSucceeded;
+ m_fStartStatusSet = TRUE;
+
+ iError = pthread_cond_signal(&m_startCond);
+ if (0 != iError)
+ {
+ ASSERT("pthread primitive failure\n");
+ // bugcheck?
+ }
+
+ iError = pthread_mutex_unlock(&m_startMutex);
+ if (0 != iError)
+ {
+ ASSERT("pthread primitive failure\n");
+ // bugcheck?
+ }
+}
+
+bool
+CPalThread::WaitForStartStatus(
+ void
+ )
+{
+ int iError;
+
+ iError = pthread_mutex_lock(&m_startMutex);
+ if (0 != iError)
+ {
+ ASSERT("pthread primitive failure\n");
+ // bugcheck?
+ }
+
+ while (!m_fStartStatusSet)
+ {
+ iError = pthread_cond_wait(&m_startCond, &m_startMutex);
+ if (0 != iError)
+ {
+ ASSERT("pthread primitive failure\n");
+ // bugcheck?
+ }
+ }
+
+ iError = pthread_mutex_unlock(&m_startMutex);
+ if (0 != iError)
+ {
+ ASSERT("pthread primitive failure\n");
+ // bugcheck?
+ }
+
+ return m_fStartStatus;
+}
+
+/* IncrementEndingThreadCount and DecrementEndingThreadCount are used
+to control a global counter that indicates if any threads are about to die.
+Once a thread's state is set to TS_DONE, it cannot be suspended. However,
+the dying thread can still access PAL resources, which is dangerous if the
+thread dies during PAL cleanup. To avoid this, the shutdown thread calls
+WaitForEndingThreads after suspending all other threads. WaitForEndingThreads
+uses a condition variable along with the global counter to wait for remaining
+PAL threads to die before proceeding with cleanup. As threads die, they
+decrement the counter and signal the condition variable. */
+
+void
+IncrementEndingThreadCount(
+ void
+ )
+{
+ int iError;
+
+ iError = pthread_mutex_lock(&ptmEndThread);
+ _ASSERT_MSG(iError == 0, "pthread_mutex_lock returned %d\n", iError);
+
+ iEndingThreads++;
+
+ iError = pthread_mutex_unlock(&ptmEndThread);
+ _ASSERT_MSG(iError == 0, "pthread_mutex_unlock returned %d\n", iError);
+}
+
+void
+DecrementEndingThreadCount(
+ void
+ )
+{
+ int iError;
+
+ iError = pthread_mutex_lock(&ptmEndThread);
+ _ASSERT_MSG(iError == 0, "pthread_mutex_lock returned %d\n", iError);
+
+ iEndingThreads--;
+ _ASSERTE(iEndingThreads >= 0);
+
+ if (iEndingThreads == 0)
+ {
+ iError = pthread_cond_signal(&ptcEndThread);
+ _ASSERT_MSG(iError == 0, "pthread_cond_signal returned %d\n", iError);
+ }
+
+ iError = pthread_mutex_unlock(&ptmEndThread);
+ _ASSERT_MSG(iError == 0, "pthread_mutex_unlock returned %d\n", iError);
+}
+
+void
+WaitForEndingThreads(
+ void
+ )
+{
+ int iError;
+
+ iError = pthread_mutex_lock(&ptmEndThread);
+ _ASSERT_MSG(iError == 0, "pthread_mutex_lock returned %d\n", iError);
+
+ while (iEndingThreads > 0)
+ {
+ iError = pthread_cond_wait(&ptcEndThread, &ptmEndThread);
+ _ASSERT_MSG(iError == 0, "pthread_cond_wait returned %d\n", iError);
+ }
+
+ iError = pthread_mutex_unlock(&ptmEndThread);
+ _ASSERT_MSG(iError == 0, "pthread_mutex_unlock returned %d\n", iError);
+}
+
+PAL_ERROR
+CorUnix::InitializeEndingThreadsData(
+ void
+ )
+{
+ PAL_ERROR palError = ERROR_INTERNAL_ERROR;
+ int iError;
+
+ iError = pthread_mutex_init(&ptmEndThread, NULL);
+ if (0 != iError)
+ {
+ goto InitializeEndingThreadsDataExit;
+ }
+
+ iError = pthread_cond_init(&ptcEndThread, NULL);
+ if (0 != iError)
+ {
+ //
+ // Don't bother checking the return value of pthread_mutex_destroy
+ // since PAL initialization will now fail.
+ //
+
+ pthread_mutex_destroy(&ptmEndThread);
+ goto InitializeEndingThreadsDataExit;
+ }
+
+ palError = NO_ERROR;
+
+InitializeEndingThreadsDataExit:
+
+ return palError;
+}
+
+void
+ThreadCleanupRoutine(
+ CPalThread *pThread,
+ IPalObject *pObjectToCleanup,
+ bool fShutdown,
+ bool fCleanupSharedState
+ )
+{
+ CThreadProcessLocalData *pThreadData = NULL;
+ CPalThread *pThreadToCleanup = NULL;
+ IDataLock *pDataLock = NULL;
+ PAL_ERROR palError = NO_ERROR;
+
+ //
+ // Free the CPalThread data for the passed in thread
+ //
+
+ palError = pObjectToCleanup->GetProcessLocalData(
+ pThread,
+ WriteLock,
+ &pDataLock,
+ reinterpret_cast<void**>(&pThreadData)
+ );
+
+ if (NO_ERROR == palError)
+ {
+ //
+ // Note that we may be cleaning up the data for the calling
+ // thread (i.e., pThread == pThreadToCleanup), so the release
+ // of the thread reference needs to be the last thing that
+ // we do (though in that case it's very likely that the person
+ // calling us will be holding an extra reference to allow
+ // for the thread data to be available while the rest of the
+ // object cleanup takes place).
+ //
+
+ pThreadToCleanup = pThreadData->pThread;
+ pThreadData->pThread = NULL;
+ pDataLock->ReleaseLock(pThread, TRUE);
+ pThreadToCleanup->ReleaseThreadReference();
+ }
+ else
+ {
+ ASSERT("Unable to obtain thread data");
+ }
+
+}
+
+PAL_ERROR
+ThreadInitializationRoutine(
+ CPalThread *pThread,
+ CObjectType *pObjectType,
+ void *pImmutableData,
+ void *pSharedData,
+ void *pProcessLocalData
+ )
+{
+ return NO_ERROR;
+}
+
+// Get base address of the current thread's stack
+void *
+CPalThread::GetStackBase()
+{
+ void* stackBase;
+#ifdef _TARGET_MAC64
+ // This is a Mac specific method
+ stackBase = pthread_get_stackaddr_np(pthread_self());
+#else
+ pthread_attr_t attr;
+ void* stackAddr;
+ size_t stackSize;
+ int status;
+
+ pthread_t thread = pthread_self();
+
+ status = pthread_attr_init(&attr);
+ _ASSERT_MSG(status == 0, "pthread_attr_init call failed");
+
+#if HAVE_PTHREAD_ATTR_GET_NP
+ status = pthread_attr_get_np(thread, &attr);
+#elif HAVE_PTHREAD_GETATTR_NP
+ status = pthread_getattr_np(thread, &attr);
+#else
+#error Dont know how to get thread attributes on this platform!
+#endif
+ _ASSERT_MSG(status == 0, "pthread_getattr_np call failed");
+
+ status = pthread_attr_getstack(&attr, &stackAddr, &stackSize);
+ _ASSERT_MSG(status == 0, "pthread_attr_getstack call failed");
+
+ status = pthread_attr_destroy(&attr);
+ _ASSERT_MSG(status == 0, "pthread_attr_destroy call failed");
+
+ stackBase = (void*)((size_t)stackAddr + stackSize);
+#endif
+
+ return stackBase;
+}
+
+// Get limit address of the current thread's stack
+void *
+CPalThread::GetStackLimit()
+{
+ void* stackLimit;
+#ifdef _TARGET_MAC64
+ // This is a Mac specific method
+ stackLimit = ((BYTE *)pthread_get_stackaddr_np(pthread_self()) -
+ pthread_get_stacksize_np(pthread_self()));
+#else
+ pthread_attr_t attr;
+ size_t stackSize;
+ int status;
+
+ pthread_t thread = pthread_self();
+
+ status = pthread_attr_init(&attr);
+ _ASSERT_MSG(status == 0, "pthread_attr_init call failed");
+
+#if HAVE_PTHREAD_ATTR_GET_NP
+ status = pthread_attr_get_np(thread, &attr);
+#elif HAVE_PTHREAD_GETATTR_NP
+ status = pthread_getattr_np(thread, &attr);
+#else
+#error Dont know how to get thread attributes on this platform!
+#endif
+ _ASSERT_MSG(status == 0, "pthread_getattr_np call failed");
+
+ status = pthread_attr_getstack(&attr, &stackLimit, &stackSize);
+ _ASSERT_MSG(status == 0, "pthread_attr_getstack call failed");
+
+ status = pthread_attr_destroy(&attr);
+ _ASSERT_MSG(status == 0, "pthread_attr_destroy call failed");
+#endif
+
+ return stackLimit;
+}
+
+// Get cached base address of this thread's stack
+// Can be called only for the current thread.
+void *
+CPalThread::GetCachedStackBase()
+{
+ _ASSERT_MSG(this == InternalGetCurrentThread(), "CPalThread::GetStackBase called from foreign thread");
+
+ if (m_stackBase == NULL)
+ {
+ m_stackBase = GetStackBase();
+ }
+
+ return m_stackBase;
+}
+
+// Get cached limit address of this thread's stack.
+// Can be called only for the current thread.
+void *
+CPalThread::GetCachedStackLimit()
+{
+ _ASSERT_MSG(this == InternalGetCurrentThread(), "CPalThread::GetCachedStackLimit called from foreign thread");
+
+ if (m_stackLimit == NULL)
+ {
+ m_stackLimit = GetStackLimit();
+ }
+
+ return m_stackLimit;
+}
+
+void *
+PALAPI
+PAL_GetStackBase()
+{
+ CPalThread* thread = InternalGetCurrentThread();
+ return thread->GetCachedStackBase();
+}
+
+void *
+PALAPI
+PAL_GetStackLimit()
+{
+ CPalThread* thread = InternalGetCurrentThread();
+ return thread->GetCachedStackLimit();
+}
+
+PAL_ERROR InjectActivationInternal(CorUnix::CPalThread* pThread);
+
+/*++
+Function:
+ PAL_SetActivationFunction
+
+ Register an activation function that gets called when an activation is injected
+ into a thread.
+
+Parameters:
+ pActivationFunction - activation function
+ pSafeActivationCheckFunction - function to check if an activation can be safely
+ injected at a specified context
+Return value:
+ None
+--*/
+PALIMPORT
+VOID
+PALAPI
+PAL_SetActivationFunction(
+ IN PAL_ActivationFunction pActivationFunction,
+ IN PAL_SafeActivationCheckFunction pSafeActivationCheckFunction)
+{
+ g_activationFunction = pActivationFunction;
+ g_safeActivationCheckFunction = pSafeActivationCheckFunction;
+}
+
+/*++
+Function:
+PAL_InjectActivation
+
+Interrupt the specified thread and have it call an activation function registered
+using the PAL_SetActivationFunction
+
+Parameters:
+hThread - handle of the target thread
+
+Return:
+TRUE if it succeeded, FALSE otherwise.
+--*/
+BOOL
+PALAPI
+PAL_InjectActivation(
+ IN HANDLE hThread)
+{
+ PERF_ENTRY(PAL_InjectActivation);
+ ENTRY("PAL_InjectActivation(hThread=%p)\n", hThread);
+
+ CPalThread *pCurrentThread;
+ CPalThread *pTargetThread;
+ IPalObject *pobjThread = NULL;
+
+ pCurrentThread = InternalGetCurrentThread();
+
+ PAL_ERROR palError = InternalGetThreadDataFromHandle(
+ pCurrentThread,
+ hThread,
+ 0,
+ &pTargetThread,
+ &pobjThread
+ );
+
+ if (palError == NO_ERROR)
+ {
+ palError = InjectActivationInternal(pTargetThread);
+ }
+
+ if (palError == NO_ERROR)
+ {
+ pCurrentThread->SetLastError(palError);
+ }
+
+ if (pobjThread != NULL)
+ {
+ pobjThread->ReleaseReference(pCurrentThread);
+ }
+
+ BOOL success = (palError == NO_ERROR);
+ LOGEXIT("PAL_InjectActivation returns:d\n", success);
+ PERF_EXIT(PAL_InjectActivation);
+
+ return success;
+}
+
+#if HAVE_MACH_EXCEPTIONS
+
+extern mach_port_t s_ExceptionPort;
+
+// Get handler details for a given type of exception. If successful the structure pointed at by pHandler is
+// filled in and true is returned. Otherwise false is returned.
+bool CorUnix::CThreadMachExceptionHandlers::GetHandler(exception_type_t eException, CorUnix::MachExceptionHandler *pHandler)
+{
+ exception_mask_t bmExceptionMask = (1 << eException);
+ int idxHandler = GetIndexOfHandler(bmExceptionMask);
+
+ // Did we find a handler?
+ if (idxHandler == -1)
+ return false;
+
+ // Found one, so initialize the output structure with the details.
+ pHandler->m_mask = m_masks[idxHandler];
+ pHandler->m_handler = m_handlers[idxHandler];
+ pHandler->m_behavior = m_behaviors[idxHandler];
+ pHandler->m_flavor = m_flavors[idxHandler];
+
+ return true;
+}
+
+// Look for a handler for the given exception within the given handler node. Return its index if successful or
+// -1 otherwise.
+int CorUnix::CThreadMachExceptionHandlers::GetIndexOfHandler(exception_mask_t bmExceptionMask)
+{
+ // Check all handler entries for one handling the exception mask.
+ for (mach_msg_type_number_t i = 0; i < m_nPorts; i++)
+ {
+ // Entry covers this exception type and the handler isn't null
+ if (m_masks[i] & bmExceptionMask && m_handlers[i] != MACH_PORT_NULL)
+ {
+ _ASSERTE(m_handlers[i] != s_ExceptionPort);
+
+ // One more check; has the target handler port become dead?
+ mach_port_type_t ePortType;
+ if (mach_port_type(mach_task_self(), m_handlers[i], &ePortType) == KERN_SUCCESS && !(ePortType & MACH_PORT_TYPE_DEAD_NAME))
+ {
+ // Got a matching entry.
+ return i;
+ }
+ }
+ }
+
+ // Didn't find a handler.
+ return -1;
+}
+
+#endif // HAVE_MACH_EXCEPTIONS
diff --git a/src/pal/src/thread/threadsusp.cpp b/src/pal/src/thread/threadsusp.cpp
new file mode 100644
index 0000000000..b31b88da59
--- /dev/null
+++ b/src/pal/src/thread/threadsusp.cpp
@@ -0,0 +1,1046 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+
+/*++
+
+
+
+Module Name:
+
+ threadsusp.cpp
+
+Abstract:
+
+ Implementation of functions related to threads.
+
+Revision History:
+
+
+
+--*/
+
+#include "pal/corunix.hpp"
+#include "pal/thread.hpp"
+#include "pal/mutex.hpp"
+#include "pal/seh.hpp"
+#include "pal/init.h"
+#include "pal/dbgmsg.h"
+
+#include <pthread.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stddef.h>
+#include <sys/stat.h>
+#include <limits.h>
+#include <debugmacrosext.h>
+
+#if defined(_AIX)
+// AIX requires explicit definition of the union semun (see semctl man page)
+union semun
+{
+ int val;
+ struct semid_ds * buf;
+ unsigned short * array;
+};
+#endif
+
+using namespace CorUnix;
+
+/* ------------------- Definitions ------------------------------*/
+SET_DEFAULT_DEBUG_CHANNEL(THREAD);
+
+/* This code is written to the blocking pipe of a thread that was created
+ in suspended state in order to resume it. */
+CONST BYTE WAKEUPCODE=0x2A;
+
+// #define USE_GLOBAL_LOCK_FOR_SUSPENSION // Uncomment this define to use the global suspension lock.
+/* The global suspension lock can be used in place of each thread having its own
+suspension mutex or spinlock. The downside is that it restricts us to only
+performing one suspension or resumption in the PAL at a time. */
+#ifdef USE_GLOBAL_LOCK_FOR_SUSPENSION
+static LONG g_ssSuspensionLock = 0;
+#endif
+
+/*++
+Function:
+ InternalSuspendNewThreadFromData
+
+ On platforms where we use pipes for starting threads suspended, this
+ function sets the blocking pipe for the thread and blocks until the
+ wakeup code is written to the pipe by ResumeThread.
+
+--*/
+PAL_ERROR
+CThreadSuspensionInfo::InternalSuspendNewThreadFromData(
+ CPalThread *pThread
+ )
+{
+ PAL_ERROR palError = NO_ERROR;
+
+ AcquireSuspensionLock(pThread);
+ pThread->suspensionInfo.SetSelfSusp(TRUE);
+ ReleaseSuspensionLock(pThread);
+
+ int pipe_descs[2];
+ if (pipe(pipe_descs) == -1)
+ {
+ ERROR("pipe() failed! error is %d (%s)\n", errno, strerror(errno));
+ return ERROR_NOT_ENOUGH_MEMORY;
+ }
+
+ // [0] is the read end of the pipe, and [1] is the write end.
+ pThread->suspensionInfo.SetBlockingPipe(pipe_descs[1]);
+ pThread->SetStartStatus(TRUE);
+
+ BYTE resume_code = 0;
+ ssize_t read_ret;
+
+ // Block until ResumeThread writes something to the pipe
+ while ((read_ret = read(pipe_descs[0], &resume_code, sizeof(resume_code))) != sizeof(resume_code))
+ {
+ if (read_ret != -1 || EINTR != errno)
+ {
+ // read might return 0 (with EAGAIN) if the other end of the pipe gets closed
+ palError = ERROR_INTERNAL_ERROR;
+ break;
+ }
+ }
+
+ if (palError == NO_ERROR && resume_code != WAKEUPCODE)
+ {
+ // If we did read successfully but the byte didn't match WAKEUPCODE, we treat it as a failure.
+ palError = ERROR_INTERNAL_ERROR;
+ }
+
+ if (palError == NO_ERROR)
+ {
+ AcquireSuspensionLock(pThread);
+ pThread->suspensionInfo.SetSelfSusp(FALSE);
+ ReleaseSuspensionLock(pThread);
+ }
+
+ // Close the pipes regardless of whether we were successful.
+ close(pipe_descs[0]);
+ close(pipe_descs[1]);
+
+ return palError;
+}
+
+/*++
+Function:
+
+ ResumeThread
+
+See MSDN doc.
+--*/
+DWORD
+PALAPI
+ResumeThread(
+ IN HANDLE hThread
+ )
+{
+ PAL_ERROR palError;
+ CPalThread *pthrResumer;
+ DWORD dwSuspendCount = (DWORD)-1;
+
+ PERF_ENTRY(ResumeThread);
+ ENTRY("ResumeThread(hThread=%p)\n", hThread);
+
+ pthrResumer = InternalGetCurrentThread();
+ palError = InternalResumeThread(
+ pthrResumer,
+ hThread,
+ &dwSuspendCount
+ );
+
+ if (NO_ERROR != palError)
+ {
+ pthrResumer->SetLastError(palError);
+ dwSuspendCount = (DWORD) -1;
+ }
+ else
+ {
+ _ASSERT_MSG(dwSuspendCount != static_cast<DWORD>(-1), "InternalResumeThread returned success but dwSuspendCount did not change.\n");
+ }
+
+ LOGEXIT("ResumeThread returns DWORD %u\n", dwSuspendCount);
+ PERF_EXIT(ResumeThread);
+ return dwSuspendCount;
+}
+
+/*++
+Function:
+ InternalResumeThread
+
+InternalResumeThread converts the handle of the target thread to a
+CPalThread, and passes both the resumer and target thread references
+to InternalResumeThreadFromData. A reference to the suspend count from
+the resumption attempt is passed back to the caller of this function.
+--*/
+PAL_ERROR
+CorUnix::InternalResumeThread(
+ CPalThread *pthrResumer,
+ HANDLE hTargetThread,
+ DWORD *pdwSuspendCount
+ )
+{
+ PAL_ERROR palError = NO_ERROR;
+ CPalThread *pthrTarget = NULL;
+ IPalObject *pobjThread = NULL;
+
+ palError = InternalGetThreadDataFromHandle(
+ pthrResumer,
+ hTargetThread,
+ 0, // THREAD_SUSPEND_RESUME
+ &pthrTarget,
+ &pobjThread
+ );
+
+ if (NO_ERROR == palError)
+ {
+ palError = pthrResumer->suspensionInfo.InternalResumeThreadFromData(
+ pthrResumer,
+ pthrTarget,
+ pdwSuspendCount
+ );
+ }
+
+ if (NULL != pobjThread)
+ {
+ pobjThread->ReleaseReference(pthrResumer);
+ }
+
+ return palError;
+}
+
+/*++
+Function:
+ InternalResumeThreadFromData
+
+InternalResumeThreadFromData resumes the target thread. First, the suspension
+mutexes of the threads are acquired. Next, there's a check to ensure that the
+target thread was actually suspended. Finally, the resume attempt is made
+and the suspension mutexes are released. The suspend count of the
+target thread is passed back to the caller of this function.
+
+Note that ReleaseSuspensionLock(s) is called before hitting ASSERTs in error
+paths. Currently, this seems unnecessary since asserting within
+InternalResumeThreadFromData will not cause cleanup to occur. However,
+this may change since it would be preferable to perform cleanup. Thus, calls
+to release suspension locks remain in the error paths.
+--*/
+PAL_ERROR
+CThreadSuspensionInfo::InternalResumeThreadFromData(
+ CPalThread *pthrResumer,
+ CPalThread *pthrTarget,
+ DWORD *pdwSuspendCount
+ )
+{
+ PAL_ERROR palError = NO_ERROR;
+
+ int nWrittenBytes = -1;
+
+ if (SignalHandlerThread == pthrTarget->GetThreadType())
+ {
+ ASSERT("Attempting to resume the signal handling thread, which can never be suspended.\n");
+ palError = ERROR_INVALID_HANDLE;
+ goto InternalResumeThreadFromDataExit;
+ }
+
+ // Acquire suspension mutex
+ AcquireSuspensionLocks(pthrResumer, pthrTarget);
+
+ // Check target thread's state to ensure it hasn't died.
+ // Setting a thread's state to TS_DONE is protected by the
+ // target's suspension mutex.
+ if (pthrTarget->synchronizationInfo.GetThreadState() == TS_DONE)
+ {
+ palError = ERROR_INVALID_HANDLE;
+ ReleaseSuspensionLocks(pthrResumer, pthrTarget);
+ goto InternalResumeThreadFromDataExit;
+ }
+
+ // If this is a dummy thread, then it represents a process that was created with CREATE_SUSPENDED
+ // and it should have a blocking pipe set. If GetBlockingPipe returns -1 for a dummy thread, then
+ // something is wrong - either CREATE_SUSPENDED wasn't used or the process was already resumed.
+ if (pthrTarget->IsDummy() && -1 == pthrTarget->suspensionInfo.GetBlockingPipe())
+ {
+ palError = ERROR_INVALID_HANDLE;
+ ERROR("Tried to wake up dummy thread without a blocking pipe.\n");
+ ReleaseSuspensionLocks(pthrResumer, pthrTarget);
+ goto InternalResumeThreadFromDataExit;
+ }
+
+ // If there is a blocking pipe on this thread, resume it by writing the wake up code to that pipe.
+ if (-1 != pthrTarget->suspensionInfo.GetBlockingPipe())
+ {
+ // If write() is interrupted by a signal before writing data,
+ // it returns -1 and sets errno to EINTR. In this case, we
+ // attempt the write() again.
+ writeAgain:
+ nWrittenBytes = write(pthrTarget->suspensionInfo.GetBlockingPipe(), &WAKEUPCODE, sizeof(WAKEUPCODE));
+
+ // The size of WAKEUPCODE is 1 byte. If write returns 0, we'll treat it as an error.
+ if (sizeof(WAKEUPCODE) != nWrittenBytes)
+ {
+ // If we are here during process creation, this is most likely caused by the target
+ // process dying before reaching this point and thus breaking the pipe.
+ if (nWrittenBytes == -1 && EPIPE == errno)
+ {
+ palError = ERROR_INVALID_HANDLE;
+ ReleaseSuspensionLocks(pthrResumer, pthrTarget);
+ ERROR("Write failed with EPIPE\n");
+ goto InternalResumeThreadFromDataExit;
+ }
+ else if (nWrittenBytes == 0 || (nWrittenBytes == -1 && EINTR == errno))
+ {
+ TRACE("write() failed with EINTR; re-attempting write\n");
+ goto writeAgain;
+ }
+ else
+ {
+ // Some other error occurred; need to release suspension mutexes before leaving ResumeThread.
+ palError = ERROR_INTERNAL_ERROR;
+ ReleaseSuspensionLocks(pthrResumer, pthrTarget);
+ ASSERT("Write() failed; error is %d (%s)\n", errno, strerror(errno));
+ goto InternalResumeThreadFromDataExit;
+ }
+ }
+
+ // Reset blocking pipe to -1 since we're done using it.
+ pthrTarget->suspensionInfo.SetBlockingPipe(-1);
+
+ ReleaseSuspensionLocks(pthrResumer, pthrTarget);
+ goto InternalResumeThreadFromDataExit;
+ }
+ else
+ {
+ *pdwSuspendCount = 0;
+ palError = ERROR_BAD_COMMAND;
+ }
+
+InternalResumeThreadFromDataExit:
+
+ if (NO_ERROR == palError)
+ {
+ *pdwSuspendCount = 1;
+ }
+
+ return palError;
+}
+
+/*++
+Function:
+ TryAcquireSuspensionLock
+
+TryAcquireSuspensionLock is a utility function that tries to acquire a thread's
+suspension mutex or spinlock. If it succeeds, the function returns TRUE.
+Otherwise, it returns FALSE. This function is used in AcquireSuspensionLocks.
+Note that the global lock cannot be acquired in this function since it makes
+no sense to do so. A thread holding the global lock is the only thread that
+can perform suspend or resume operations so it doesn't need to acquire
+a second lock.
+--*/
+BOOL
+CThreadSuspensionInfo::TryAcquireSuspensionLock(
+ CPalThread* pthrTarget
+ )
+{
+ int iPthreadRet = 0;
+#if DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX
+{
+ iPthreadRet = SPINLOCKTryAcquire(pthrTarget->suspensionInfo.GetSuspensionSpinlock());
+}
+#else // DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX
+{
+ iPthreadRet = pthread_mutex_trylock(pthrTarget->suspensionInfo.GetSuspensionMutex());
+ _ASSERT_MSG(iPthreadRet == 0 || iPthreadRet == EBUSY, "pthread_mutex_trylock returned %d\n", iPthreadRet);
+}
+#endif // DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX
+
+ // If iPthreadRet is 0, lock acquisition was successful. Otherwise, it failed.
+ return (iPthreadRet == 0);
+}
+
+/*++
+Function:
+ AcquireSuspensionLock
+
+AcquireSuspensionLock acquires a thread's suspension mutex or spinlock.
+If USE_GLOBAL_LOCK_FOR_SUSPENSION is defined, it will acquire the global lock.
+A thread in this function blocks until it acquires
+its lock, unlike in TryAcquireSuspensionLock.
+--*/
+void
+CThreadSuspensionInfo::AcquireSuspensionLock(
+ CPalThread* pthrCurrent
+ )
+{
+#ifdef USE_GLOBAL_LOCK_FOR_SUSPENSION
+{
+ SPINLOCKAcquire(&g_ssSuspensionLock, 0);
+}
+#else // USE_GLOBAL_LOCK_FOR_SUSPENSION
+{
+ #if DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX
+ {
+ SPINLOCKAcquire(&pthrCurrent->suspensionInfo.m_nSpinlock, 0);
+ }
+ #else // DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX
+ {
+ INDEBUG(int iPthreadError = )
+ pthread_mutex_lock(&pthrCurrent->suspensionInfo.m_ptmSuspmutex);
+ _ASSERT_MSG(iPthreadError == 0, "pthread_mutex_lock returned %d\n", iPthreadError);
+ }
+ #endif // DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX
+}
+#endif // USE_GLOBAL_LOCK_FOR_SUSPENSION
+}
+
+/*++
+Function:
+ ReleaseSuspensionLock
+
+ReleaseSuspensionLock is a function that releases a thread's suspension mutex
+or spinlock. If USE_GLOBAL_LOCK_FOR_SUSPENSION is defined,
+it will release the global lock.
+--*/
+void
+CThreadSuspensionInfo::ReleaseSuspensionLock(
+ CPalThread* pthrCurrent
+ )
+{
+#ifdef USE_GLOBAL_LOCK_FOR_SUSPENSION
+{
+ SPINLOCKRelease(&g_ssSuspensionLock);
+}
+#else // USE_GLOBAL_LOCK_FOR_SUSPENSION
+{
+ #if DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX
+ {
+ SPINLOCKRelease(&pthrCurrent->suspensionInfo.m_nSpinlock);
+ }
+ #else // DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX
+ {
+ INDEBUG(int iPthreadError = )
+ pthread_mutex_unlock(&pthrCurrent->suspensionInfo.m_ptmSuspmutex);
+ _ASSERT_MSG(iPthreadError == 0, "pthread_mutex_unlock returned %d\n", iPthreadError);
+ }
+ #endif // DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX
+}
+#endif // USE_GLOBAL_LOCK_FOR_SUSPENSION
+}
+
+/*++
+Function:
+ AcquireSuspensionLocks
+
+AcquireSuspensionLocks is used to acquire the suspension locks
+of a suspender (or resumer) and target thread. The thread will
+perform a blocking call to acquire its own suspension lock
+and will then try to acquire the target thread's lock without blocking.
+If it fails to acquire the target's lock, it releases its own lock
+and the thread will try to acquire both locks again. The key
+is that both locks must be acquired together.
+
+Originally, only blocking calls were used to acquire the suspender
+and the target lock. However, this was problematic since a thread
+could acquire its own lock and then block on acquiring the target
+lock. In the meantime, the target could have already acquired its
+own lock and be attempting to suspend the suspender thread. This
+clearly causes deadlock. A second approach used locking hierarchies,
+where locks were acquired use thread id ordering. This was better but
+suffered from the scenario where thread A acquires thread B's
+suspension mutex first. In the meantime, thread C acquires thread A's
+suspension mutex and its own. Thus, thread A is suspended while
+holding thread B's mutex. This is problematic if thread C now wants
+to suspend thread B. The issue here is that a thread can be
+suspended while holding someone else's mutex but not holding its own.
+In the end, the correct approach is to always acquire your suspension
+mutex first. This prevents you from being suspended while holding the
+target's mutex. Then, attempt to acquire the target's mutex. If the mutex
+cannot be acquired, release your own and try again. This all or nothing
+approach is the safest and avoids nasty race conditions.
+
+If USE_GLOBAL_LOCK_FOR_SUSPENSION is defined, the calling thread
+will acquire the global lock when possible.
+--*/
+VOID
+CThreadSuspensionInfo::AcquireSuspensionLocks(
+ CPalThread *pthrSuspender,
+ CPalThread *pthrTarget
+ )
+{
+ BOOL fReacquire = FALSE;
+
+#ifdef USE_GLOBAL_LOCK_FOR_SUSPENSION
+ AcquireSuspensionLock(pthrSuspender);
+#else // USE_GLOBAL_LOCK_FOR_SUSPENSION
+ do
+ {
+ fReacquire = FALSE;
+ AcquireSuspensionLock(pthrSuspender);
+ if (!TryAcquireSuspensionLock(pthrTarget))
+ {
+ // pthread_mutex_trylock returned EBUSY so release the first lock and try again.
+ ReleaseSuspensionLock(pthrSuspender);
+ fReacquire = TRUE;
+ sched_yield();
+ }
+ } while (fReacquire);
+#endif // USE_GLOBAL_LOCK_FOR_SUSPENSION
+
+ // Whenever the native implementation for the wait subsystem's thread
+ // blocking requires a lock as protection (as pthread conditions do with
+ // the associated mutex), we need to grab that lock to prevent the target
+ // thread from being suspended while holding the lock.
+ // Failing to do so can lead to a multiple threads deadlocking such as the
+ // one described in VSW 363793.
+ // In general, in similar scenarios, we need to grab the protecting lock
+ // every time suspension safety/unsafety is unbalanced on the two sides
+ // using the same condition (or any other native blocking support which
+ // needs an associated native lock), i.e. when either the signaling
+ // thread(s) is(are) signaling from an unsafe area and the waiting
+ // thread(s) is(are) waiting from a safe one, or vice versa (the scenario
+ // described in VSW 363793 is a good example of the first type of
+ // unbalanced suspension safety/unsafety).
+ // Instead, whenever signaling and waiting sides are both marked safe or
+ // unsafe, the deadlock cannot take place since either the suspending
+ // thread will suspend them anyway (regardless of the native lock), or it
+ // won't suspend any of them, since they are both marked unsafe.
+ // Such a balanced scenario applies, for instance, to critical sections
+ // where depending on whether the target CS is internal or not, both the
+ // signaling and the waiting side will access the mutex/condition from
+ // respectively an unsafe or safe region.
+
+ pthrTarget->AcquireNativeWaitLock();
+}
+
+/*++
+Function:
+ ReleaseSuspensionLocks
+
+ReleaseSuspensionLocks releases both thread's suspension mutexes.
+Note that the locks are released in the opposite order they're acquired.
+This prevents a suspending or resuming thread from being suspended
+while holding the target's lock.
+If USE_GLOBAL_LOCK_FOR_SUSPENSION is defined, it simply releases the global lock.
+--*/
+VOID
+CThreadSuspensionInfo::ReleaseSuspensionLocks(
+ CPalThread *pthrSuspender,
+ CPalThread *pthrTarget
+ )
+{
+ // See comment in AcquireSuspensionLocks
+ pthrTarget->ReleaseNativeWaitLock();
+
+#ifdef USE_GLOBAL_LOCK_FOR_SUSPENSION
+ ReleaseSuspensionLock(pthrSuspender);
+#else // USE_GLOBAL_LOCK_FOR_SUSPENSION
+ ReleaseSuspensionLock(pthrTarget);
+ ReleaseSuspensionLock(pthrSuspender);
+#endif // USE_GLOBAL_LOCK_FOR_SUSPENSION
+}
+
+/*++
+Function:
+ PostOnSuspendSemaphore
+
+PostOnSuspendSemaphore is a utility function for a thread
+to post on its POSIX or SysV suspension semaphore.
+--*/
+void
+CThreadSuspensionInfo::PostOnSuspendSemaphore()
+{
+#if USE_POSIX_SEMAPHORES
+ if (sem_post(&m_semSusp) == -1)
+ {
+ ASSERT("sem_post returned -1 and set errno to %d (%s)\n", errno, strerror(errno));
+ }
+#elif USE_SYSV_SEMAPHORES
+ if (semop(m_nSemsuspid, &m_sbSempost, 1) == -1)
+ {
+ ASSERT("semop - post returned -1 and set errno to %d (%s)\n", errno, strerror(errno));
+ }
+#elif USE_PTHREAD_CONDVARS
+ int status;
+
+ // The suspending thread may not have entered the wait yet, in which case the cond var
+ // signal below will be a no-op. To prevent the race condition we set m_fSuspended to
+ // TRUE first (which the suspender will take as an indication that no wait is required).
+ // But the setting of the flag and the signal must appear atomic to the suspender (as
+ // reading the flag and potentially waiting must appear to us) to avoid the race
+ // condition where the suspender reads the flag as FALSE, we set it and signal and the
+ // suspender then waits.
+
+ // Acquire the suspend mutex. Once we enter the critical section the suspender has
+ // either gotten there before us (and is waiting for our signal) or is yet to even
+ // check the flag (so we can set it here to stop them attempting a wait).
+ status = pthread_mutex_lock(&m_mutexSusp);
+ if (status != 0)
+ {
+ ASSERT("pthread_mutex_lock returned %d (%s)\n", status, strerror(status));
+ }
+
+ m_fSuspended = TRUE;
+
+ status = pthread_cond_signal(&m_condSusp);
+ if (status != 0)
+ {
+ ASSERT("pthread_cond_signal returned %d (%s)\n", status, strerror(status));
+ }
+
+ status = pthread_mutex_unlock(&m_mutexSusp);
+ if (status != 0)
+ {
+ ASSERT("pthread_mutex_unlock returned %d (%s)\n", status, strerror(status));
+ }
+#endif // USE_POSIX_SEMAPHORES
+}
+
+/*++
+Function:
+ WaitOnSuspendSemaphore
+
+WaitOnSuspendSemaphore is a utility function for a thread
+to wait on its POSIX or SysV suspension semaphore.
+--*/
+void
+CThreadSuspensionInfo::WaitOnSuspendSemaphore()
+{
+#if USE_POSIX_SEMAPHORES
+ while (sem_wait(&m_semSusp) == -1)
+ {
+ ASSERT("sem_wait returned -1 and set errno to %d (%s)\n", errno, strerror(errno));
+ }
+#elif USE_SYSV_SEMAPHORES
+ while (semop(m_nSemsuspid, &m_sbSemwait, 1) == -1)
+ {
+ ASSERT("semop wait returned -1 and set errno to %d (%s)\n", errno, strerror(errno));
+ }
+#elif USE_PTHREAD_CONDVARS
+ int status;
+
+ // By the time we wait the target thread may have already signalled its suspension (in
+ // which case m_fSuspended will be TRUE and we shouldn't wait on the cond var). But we
+ // must check the flag and potentially wait atomically to avoid the race where we read
+ // the flag and the target thread sets it and signals before we have a chance to wait.
+
+ status = pthread_mutex_lock(&m_mutexSusp);
+ if (status != 0)
+ {
+ ASSERT("pthread_mutex_lock returned %d (%s)\n", status, strerror(status));
+ }
+
+ // If the target has already acknowledged the suspend we shouldn't wait.
+ while (!m_fSuspended)
+ {
+ // We got here before the target could signal. Wait on them (which atomically releases
+ // the mutex during the wait).
+ status = pthread_cond_wait(&m_condSusp, &m_mutexSusp);
+ if (status != 0)
+ {
+ ASSERT("pthread_cond_wait returned %d (%s)\n", status, strerror(status));
+ }
+ }
+
+ status = pthread_mutex_unlock(&m_mutexSusp);
+ if (status != 0)
+ {
+ ASSERT("pthread_mutex_unlock returned %d (%s)\n", status, strerror(status));
+ }
+#endif // USE_POSIX_SEMAPHORES
+}
+
+/*++
+Function:
+ PostOnResumeSemaphore
+
+PostOnResumeSemaphore is a utility function for a thread
+to post on its POSIX or SysV resume semaphore.
+--*/
+void
+CThreadSuspensionInfo::PostOnResumeSemaphore()
+{
+#if USE_POSIX_SEMAPHORES
+ if (sem_post(&m_semResume) == -1)
+ {
+ ASSERT("sem_post returned -1 and set errno to %d (%s)\n", errno, strerror(errno));
+ }
+#elif USE_SYSV_SEMAPHORES
+ if (semop(m_nSemrespid, &m_sbSempost, 1) == -1)
+ {
+ ASSERT("semop - post returned -1 and set errno to %d (%s)\n", errno, strerror(errno));
+ }
+#elif USE_PTHREAD_CONDVARS
+ int status;
+
+ // The resuming thread may not have entered the wait yet, in which case the cond var
+ // signal below will be a no-op. To prevent the race condition we set m_fResumed to
+ // TRUE first (which the resumer will take as an indication that no wait is required).
+ // But the setting of the flag and the signal must appear atomic to the resumer (as
+ // reading the flag and potentially waiting must appear to us) to avoid the race
+ // condition where the resumer reads the flag as FALSE, we set it and signal and the
+ // resumer then waits.
+
+ // Acquire the resume mutex. Once we enter the critical section the resumer has
+ // either gotten there before us (and is waiting for our signal) or is yet to even
+ // check the flag (so we can set it here to stop them attempting a wait).
+ status = pthread_mutex_lock(&m_mutexResume);
+ if (status != 0)
+ {
+ ASSERT("pthread_mutex_lock returned %d (%s)\n", status, strerror(status));
+ }
+
+ m_fResumed = TRUE;
+
+ status = pthread_cond_signal(&m_condResume);
+ if (status != 0)
+ {
+ ASSERT("pthread_cond_signal returned %d (%s)\n", status, strerror(status));
+ }
+
+ status = pthread_mutex_unlock(&m_mutexResume);
+ if (status != 0)
+ {
+ ASSERT("pthread_mutex_unlock returned %d (%s)\n", status, strerror(status));
+ }
+#endif // USE_POSIX_SEMAPHORES
+}
+
+/*++
+Function:
+ WaitOnResumeSemaphore
+
+WaitOnResumeSemaphore is a utility function for a thread
+to wait on its POSIX or SysV resume semaphore.
+--*/
+void
+CThreadSuspensionInfo::WaitOnResumeSemaphore()
+{
+#if USE_POSIX_SEMAPHORES
+ while (sem_wait(&m_semResume) == -1)
+ {
+ ASSERT("sem_wait returned -1 and set errno to %d (%s)\n", errno, strerror(errno));
+ }
+#elif USE_SYSV_SEMAPHORES
+ while (semop(m_nSemrespid, &m_sbSemwait, 1) == -1)
+ {
+ ASSERT("semop wait returned -1 and set errno to %d (%s)\n", errno, strerror(errno));
+ }
+#elif USE_PTHREAD_CONDVARS
+ int status;
+
+ // By the time we wait the target thread may have already signalled its resumption (in
+ // which case m_fResumed will be TRUE and we shouldn't wait on the cond var). But we
+ // must check the flag and potentially wait atomically to avoid the race where we read
+ // the flag and the target thread sets it and signals before we have a chance to wait.
+
+ status = pthread_mutex_lock(&m_mutexResume);
+ if (status != 0)
+ {
+ ASSERT("pthread_mutex_lock returned %d (%s)\n", status, strerror(status));
+ }
+
+ // If the target has already acknowledged the resume we shouldn't wait.
+ while (!m_fResumed)
+ {
+ // We got here before the target could signal. Wait on them (which atomically releases
+ // the mutex during the wait).
+ status = pthread_cond_wait(&m_condResume, &m_mutexResume);
+ if (status != 0)
+ {
+ ASSERT("pthread_cond_wait returned %d (%s)\n", status, strerror(status));
+ }
+ }
+
+ status = pthread_mutex_unlock(&m_mutexResume);
+ if (status != 0)
+ {
+ ASSERT("pthread_mutex_unlock returned %d (%s)\n", status, strerror(status));
+ }
+#endif // USE_POSIX_SEMAPHORES
+}
+
+/*++
+Function:
+ InitializeSuspensionLock
+
+InitializeSuspensionLock initializes a thread's suspension spinlock
+or suspension mutex. It is called from the CThreadSuspensionInfo
+constructor.
+--*/
+VOID
+CThreadSuspensionInfo::InitializeSuspensionLock()
+{
+#if DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX
+ SPINLOCKInit(&m_nSpinlock);
+#else
+ int iError = pthread_mutex_init(&m_ptmSuspmutex, NULL);
+ if (0 != iError )
+ {
+ ASSERT("pthread_mutex_init(&suspmutex) returned %d\n", iError);
+ return;
+ }
+ m_fSuspmutexInitialized = TRUE;
+#endif // DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX
+}
+
+/*++
+Function:
+ InitializePreCreate
+
+InitializePreCreate initializes the semaphores and signal masks used
+for thread suspension. At the end, it sets the calling thread's
+signal mask to the default signal mask.
+--*/
+PAL_ERROR
+CThreadSuspensionInfo::InitializePreCreate()
+{
+ PAL_ERROR palError = ERROR_INTERNAL_ERROR;
+ int iError = 0;
+#if SEM_INIT_MODIFIES_ERRNO
+ int nStoredErrno;
+#endif // SEM_INIT_MODIFIES_ERRNO
+
+#if USE_POSIX_SEMAPHORES
+
+#if SEM_INIT_MODIFIES_ERRNO
+ nStoredErrno = errno;
+#endif // SEM_INIT_MODIFIES_ERRNO
+
+ // initialize suspension semaphore
+ iError = sem_init(&m_semSusp, 0, 0);
+
+#if SEM_INIT_MODIFIES_ERRNO
+ if (iError == 0)
+ {
+ // Restore errno if sem_init succeeded.
+ errno = nStoredErrno;
+ }
+#endif // SEM_INIT_MODIFIES_ERRNO
+
+ if (0 != iError )
+ {
+ ASSERT("sem_init(&suspsem) returned %d\n", iError);
+ goto InitializePreCreateExit;
+ }
+
+#if SEM_INIT_MODIFIES_ERRNO
+ nStoredErrno = errno;
+#endif // SEM_INIT_MODIFIES_ERRNO
+
+ // initialize resume semaphore
+ iError = sem_init(&m_semResume, 0, 0);
+
+#if SEM_INIT_MODIFIES_ERRNO
+ if (iError == 0)
+ {
+ // Restore errno if sem_init succeeded.
+ errno = nStoredErrno;
+ }
+#endif // SEM_INIT_MODIFIES_ERRNO
+
+ if (0 != iError )
+ {
+ ASSERT("sem_init(&suspsem) returned %d\n", iError);
+ sem_destroy(&m_semSusp);
+ goto InitializePreCreateExit;
+ }
+
+ m_fSemaphoresInitialized = TRUE;
+
+#elif USE_SYSV_SEMAPHORES
+ // preparing to initialize the SysV semaphores.
+ union semun semunData;
+ m_nSemsuspid = semget(IPC_PRIVATE, 1, IPC_CREAT | 0666);
+ if (m_nSemsuspid == -1)
+ {
+ ASSERT("semget for suspension sem id returned -1 and set errno to %d (%s)\n", errno, strerror(errno));
+ goto InitializePreCreateExit;
+ }
+
+ m_nSemrespid = semget(IPC_PRIVATE, 1, IPC_CREAT | 0666);
+ if (m_nSemrespid == -1)
+ {
+ ASSERT("semget for resumption sem id returned -1 and set errno to %d (%s)\n", errno, strerror(errno));
+ goto InitializePreCreateExit;
+ }
+
+ if (m_nSemsuspid == m_nSemrespid)
+ {
+ ASSERT("Suspension and Resumption Semaphores have the same id\n");
+ goto InitializePreCreateExit;
+ }
+
+ semunData.val = 0;
+ iError = semctl(m_nSemsuspid, 0, SETVAL, semunData);
+ if (iError == -1)
+ {
+ ASSERT("semctl for suspension sem id returned -1 and set errno to %d (%s)\n", errno, strerror(errno));
+ goto InitializePreCreateExit;
+ }
+
+ semunData.val = 0;
+ iError = semctl(m_nSemrespid, 0, SETVAL, semunData);
+ if (iError == -1)
+ {
+ ASSERT("semctl for resumption sem id returned -1 and set errno to %d (%s)\n", errno, strerror(errno));
+ goto InitializePreCreateExit;
+ }
+
+ // initialize suspend semaphore
+ m_sbSemwait.sem_num = 0;
+ m_sbSemwait.sem_op = -1;
+ m_sbSemwait.sem_flg = 0;
+
+ // initialize resume semaphore
+ m_sbSempost.sem_num = 0;
+ m_sbSempost.sem_op = 1;
+ m_sbSempost.sem_flg = 0;
+#elif USE_PTHREAD_CONDVARS
+ iError = pthread_cond_init(&m_condSusp, NULL);
+ if (iError != 0)
+ {
+ ASSERT("pthread_cond_init for suspension returned %d (%s)\n", iError, strerror(iError));
+ goto InitializePreCreateExit;
+ }
+
+ iError = pthread_mutex_init(&m_mutexSusp, NULL);
+ if (iError != 0)
+ {
+ ASSERT("pthread_mutex_init for suspension returned %d (%s)\n", iError, strerror(iError));
+ goto InitializePreCreateExit;
+ }
+
+ iError = pthread_cond_init(&m_condResume, NULL);
+ if (iError != 0)
+ {
+ ASSERT("pthread_cond_init for resume returned %d (%s)\n", iError, strerror(iError));
+ goto InitializePreCreateExit;
+ }
+
+ iError = pthread_mutex_init(&m_mutexResume, NULL);
+ if (iError != 0)
+ {
+ ASSERT("pthread_mutex_init for resume returned %d (%s)\n", iError, strerror(iError));
+ goto InitializePreCreateExit;
+ }
+
+ m_fSemaphoresInitialized = TRUE;
+#endif // USE_POSIX_SEMAPHORES
+
+ // Initialization was successful.
+ palError = NO_ERROR;
+
+InitializePreCreateExit:
+
+ if (NO_ERROR == palError && 0 != iError)
+ {
+ switch (iError)
+ {
+ case ENOMEM:
+ case EAGAIN:
+ {
+ palError = ERROR_OUTOFMEMORY;
+ break;
+ }
+ default:
+ {
+ ASSERT("A pthrSuspender init call returned %d (%s)\n", iError, strerror(iError));
+ palError = ERROR_INTERNAL_ERROR;
+ }
+ }
+ }
+
+ return palError;
+}
+
+CThreadSuspensionInfo::~CThreadSuspensionInfo()
+{
+#if !DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX
+ if (m_fSuspmutexInitialized)
+ {
+ INDEBUG(int iError = )
+ pthread_mutex_destroy(&m_ptmSuspmutex);
+ _ASSERT_MSG(0 == iError, "pthread_mutex_destroy returned %d (%s)\n", iError, strerror(iError));
+ }
+#endif
+
+#if USE_POSIX_SEMAPHORES
+ if (m_fSemaphoresInitialized)
+ {
+ int iError;
+
+ iError = sem_destroy(&m_semSusp);
+ _ASSERT_MSG(0 == iError, "sem_destroy failed and set errno to %d (%s)\n", errno, strerror(errno));
+
+ iError = sem_destroy(&m_semResume);
+ _ASSERT_MSG(0 == iError, "sem_destroy failed and set errno to %d (%s)\n", errno, strerror(errno));
+ }
+#elif USE_SYSV_SEMAPHORES
+ DestroySemaphoreIds();
+#elif USE_PTHREAD_CONDVARS
+ if (m_fSemaphoresInitialized)
+ {
+ int iError;
+
+ iError = pthread_cond_destroy(&m_condSusp);
+ _ASSERT_MSG(0 == iError, "pthread_cond_destroy failed with %d (%s)\n", iError, strerror(iError));
+
+ iError = pthread_mutex_destroy(&m_mutexSusp);
+ _ASSERT_MSG(0 == iError, "pthread_mutex_destroy failed with %d (%s)\n", iError, strerror(iError));
+
+ iError = pthread_cond_destroy(&m_condResume);
+ _ASSERT_MSG(0 == iError, "pthread_cond_destroy failed with %d (%s)\n", iError, strerror(iError));
+
+ iError = pthread_mutex_destroy(&m_mutexResume);
+ _ASSERT_MSG(0 == iError, "pthread_mutex_destroy failed with %d (%s)\n", iError, strerror(iError));
+ }
+#endif // USE_POSIX_SEMAPHORES
+}
+
+#if USE_SYSV_SEMAPHORES
+/*++
+Function:
+ DestroySemaphoreIds
+
+DestroySemaphoreIds is called from the CThreadSuspensionInfo destructor and
+from PROCCleanupThreadSemIds. If a thread exits before shutdown or is suspended
+during shutdown, its destructor will be invoked and the semaphore ids destroyed.
+In assert or exceptions situations that are suspension unsafe,
+PROCCleanupThreadSemIds is called, which uses DestroySemaphoreIds.
+--*/
+void
+CThreadSuspensionInfo::DestroySemaphoreIds()
+{
+ union semun semunData;
+ if (m_nSemsuspid != 0)
+ {
+ semunData.val = 0;
+ if (0 != semctl(m_nSemsuspid, 0, IPC_RMID, semunData))
+ {
+ ERROR("semctl(Semsuspid) failed and set errno to %d (%s)\n", errno, strerror(errno));
+ }
+ else
+ {
+ m_nSemsuspid = 0;
+ }
+ }
+ if (this->m_nSemrespid)
+ {
+ semunData.val = 0;
+ if (0 != semctl(m_nSemrespid, 0, IPC_RMID, semunData))
+ {
+ ERROR("semctl(Semrespid) failed and set errno to %d (%s)\n", errno, strerror(errno));
+ }
+ else
+ {
+ m_nSemrespid = 0;
+ }
+ }
+}
+#endif // USE_SYSV_SEMAPHORES
diff --git a/src/pal/src/thread/tls.cpp b/src/pal/src/thread/tls.cpp
new file mode 100644
index 0000000000..ef6d02f00a
--- /dev/null
+++ b/src/pal/src/thread/tls.cpp
@@ -0,0 +1,226 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ tls.cpp
+
+Abstract:
+
+ Implementation of Thread local storage functions.
+
+
+
+--*/
+
+#include "pal/thread.hpp"
+#include "procprivate.hpp"
+
+#include <pthread.h>
+
+#include "pal/dbgmsg.h"
+#include "pal/misc.h"
+#include "pal/virtual.h"
+#include "pal/process.h"
+#include "pal/init.h"
+#include "pal/malloc.hpp"
+#include "pal_endian.h"
+
+#include <stddef.h>
+using namespace CorUnix;
+
+SET_DEFAULT_DEBUG_CHANNEL(THREAD);
+
+// In safemath.h, Template SafeInt uses macro _ASSERTE, which need to use variable
+// defdbgchan defined by SET_DEFAULT_DEBUG_CHANNEL. Therefore, the include statement
+// should be placed after the SET_DEFAULT_DEBUG_CHANNEL(THREAD)
+#include <safemath.h>
+
+/* This tracks the slots that are used for TlsAlloc. Its size in bits
+ must be the same as TLS_SLOT_SIZE in pal/thread.h. Since this is
+ static, it is initialized to 0, which is what we want. */
+static unsigned __int64 sTlsSlotFields;
+
+/*++
+Function:
+ TlsAlloc
+
+See MSDN doc.
+--*/
+DWORD
+PALAPI
+TlsAlloc(
+ VOID)
+{
+ DWORD dwIndex;
+ unsigned int i;
+
+ PERF_ENTRY(TlsAlloc);
+ ENTRY("TlsAlloc()\n");
+
+ /* Yes, this could be ever so slightly improved. It's not
+ likely to be called enough to matter, though, so we won't
+ optimize here until or unless we need to. */
+
+ PROCProcessLock();
+
+ for(i = 0; i < sizeof(sTlsSlotFields) * 8; i++)
+ {
+ if ((sTlsSlotFields & ((unsigned __int64) 1 << i)) == 0)
+ {
+ sTlsSlotFields |= ((unsigned __int64) 1 << i);
+ break;
+ }
+ }
+ if (i == sizeof(sTlsSlotFields) * 8)
+ {
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ dwIndex = TLS_OUT_OF_INDEXES;
+ }
+ else
+ {
+ dwIndex = i;
+ }
+
+ PROCProcessUnlock();
+
+ LOGEXIT("TlsAlloc returns DWORD %u\n", dwIndex);
+ PERF_EXIT(TlsAlloc);
+ return dwIndex;
+}
+
+
+/*++
+Function:
+ TlsGetValue
+
+See MSDN doc.
+--*/
+LPVOID
+PALAPI
+TlsGetValue(
+ IN DWORD dwTlsIndex)
+{
+ CPalThread *pThread;
+
+ PERF_ENTRY(TlsGetValue);
+ ENTRY("TlsGetValue()\n");
+
+ if (dwTlsIndex == (DWORD) -1 || dwTlsIndex >= TLS_SLOT_SIZE)
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return 0;
+ }
+
+ pThread = InternalGetCurrentThread();
+
+ /* From MSDN : "The TlsGetValue function calls SetLastError to clear a
+ thread's last error when it succeeds." */
+ pThread->SetLastError(NO_ERROR);
+
+ LOGEXIT("TlsGetValue \n" );
+ PERF_EXIT(TlsGetValue);
+
+ return pThread->tlsInfo.tlsSlots[dwTlsIndex];
+}
+
+
+/*++
+Function:
+ TlsSetValue
+
+See MSDN doc.
+--*/
+BOOL
+PALAPI
+TlsSetValue(
+ IN DWORD dwTlsIndex,
+ IN LPVOID lpTlsValue)
+{
+ CPalThread *pThread;
+ BOOL bRet = FALSE;
+ PERF_ENTRY(TlsSetValue);
+ ENTRY("TlsSetValue(dwTlsIndex=%u, lpTlsValue=%p)\n", dwTlsIndex, lpTlsValue);
+
+ if (dwTlsIndex == (DWORD) -1 || dwTlsIndex >= TLS_SLOT_SIZE)
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ goto EXIT;
+ }
+
+ pThread = InternalGetCurrentThread();
+ pThread->tlsInfo.tlsSlots[dwTlsIndex] = lpTlsValue;
+ bRet = TRUE;
+
+EXIT:
+ LOGEXIT("TlsSetValue returns BOOL %d\n", bRet);
+ PERF_EXIT(TlsSetValue);
+ return bRet;
+}
+
+
+/*++
+Function:
+ TlsFree
+
+See MSDN doc.
+--*/
+BOOL
+PALAPI
+TlsFree(
+ IN DWORD dwTlsIndex)
+{
+ CPalThread *pThread;
+
+ PERF_ENTRY(TlsFree);
+ ENTRY("TlsFree(dwTlsIndex=%u)\n", dwTlsIndex);
+
+
+ if (dwTlsIndex == (DWORD) -1 || dwTlsIndex >= TLS_SLOT_SIZE)
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ LOGEXIT("TlsFree returns BOOL FALSE\n");
+ PERF_EXIT(TlsFree);
+ return FALSE;
+ }
+
+ PROCProcessLock();
+
+ /* Reset all threads' values to zero for this index. */
+ for(pThread = pGThreadList;
+ pThread != NULL; pThread = pThread->GetNext())
+ {
+ pThread->tlsInfo.tlsSlots[dwTlsIndex] = 0;
+ }
+ sTlsSlotFields &= ~((unsigned __int64) 1 << dwTlsIndex);
+
+ PROCProcessUnlock();
+
+ LOGEXIT("TlsFree returns BOOL TRUE\n");
+ PERF_EXIT(TlsFree);
+ return TRUE;
+}
+
+PAL_ERROR
+CThreadTLSInfo::InitializePostCreate(
+ CPalThread *pThread,
+ SIZE_T threadId,
+ DWORD dwLwpId
+ )
+{
+ PAL_ERROR palError = NO_ERROR;
+
+ if (pthread_setspecific(thObjKey, reinterpret_cast<void*>(pThread)))
+ {
+ ASSERT("Unable to set the thread object key's value\n");
+ palError = ERROR_INTERNAL_ERROR;
+ }
+
+ return palError;
+}
+
diff --git a/src/pal/tests/CMakeLists.txt b/src/pal/tests/CMakeLists.txt
new file mode 100644
index 0000000000..a6d1ba4d5b
--- /dev/null
+++ b/src/pal/tests/CMakeLists.txt
@@ -0,0 +1,32 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+if(CLR_CMAKE_PLATFORM_ARCH_AMD64)
+ set(PAL_CMAKE_PLATFORM_ARCH_AMD64 1)
+elseif(CLR_CMAKE_PLATFORM_ARCH_ARM)
+ set(PAL_CMAKE_PLATFORM_ARCH_ARM 1)
+elseif(CLR_CMAKE_PLATFORM_ARCH_ARM64)
+ set(PAL_CMAKE_PLATFORM_ARCH_ARM64 1)
+endif()
+
+# Compile options
+add_definitions(-DPLATFORM_UNIX=1)
+add_definitions(-DLP64COMPATIBLE=1)
+add_definitions(-DFEATURE_PAL=1)
+add_definitions(-DCORECLR=1)
+add_definitions(-DPIC=1)
+if(PAL_CMAKE_PLATFORM_ARCH_AMD64)
+ add_definitions(-DBIT64=1)
+ add_definitions(-D_WIN64=1)
+elseif(PAL_CMAKE_PLATFORM_ARCH_ARM)
+ add_definitions(-DBIT32=1)
+elseif(PAL_CMAKE_PLATFORM_ARCH_ARM64)
+ add_definitions(-DBIT64=1)
+ add_definitions(-D_WIN64=1)
+else()
+ message(FATAL_ERROR "Only ARM, ARM64 and AMD64 is supported")
+endif()
+
+add_compile_options(-Wno-empty-body)
+
+add_subdirectory(palsuite)
+
diff --git a/src/pal/tests/palsuite/CMakeLists.txt b/src/pal/tests/palsuite/CMakeLists.txt
new file mode 100644
index 0000000000..235b695961
--- /dev/null
+++ b/src/pal/tests/palsuite/CMakeLists.txt
@@ -0,0 +1,24 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+project(PALTESTSUITE)
+
+include_directories(${PALTESTSUITE_SOURCE_DIR}/common)
+
+add_compile_options(-Wno-incompatible-pointer-types-discards-qualifiers)
+add_compile_options(-Wno-int-to-void-pointer-cast)
+
+# TODO: make these tests compile
+# add_subdirectory(composite)
+add_subdirectory(exception_handling)
+
+add_subdirectory(c_runtime)
+add_subdirectory(debug_api)
+add_subdirectory(filemapping_memmgt)
+add_subdirectory(file_io)
+add_subdirectory(loader)
+add_subdirectory(locale_info)
+add_subdirectory(miscellaneous)
+add_subdirectory(pal_specific)
+add_subdirectory(samples)
+add_subdirectory(threading)
+add_subdirectory($ENV{__IntermediatesDir}/Generated/eventprovider/tests ${CMAKE_CURRENT_BINARY_DIR}/eventprovider )
diff --git a/src/pal/tests/palsuite/DisabledTests.txt b/src/pal/tests/palsuite/DisabledTests.txt
new file mode 100644
index 0000000000..b3ca370586
--- /dev/null
+++ b/src/pal/tests/palsuite/DisabledTests.txt
@@ -0,0 +1,123 @@
+Disabled Test Cases
+~~~~~~~~~~~~~~~~~~~
+
+Below is a list of all disabled test cases currently listed in
+testconfig.dat and an explanation as to why they are disabled.
+
+debug_api/debugbreak/test1
+debug_api/outputdebugstringa/test1
+debug_api/outputdebugstringw/test1
+debug_api/writeprocessmemory/test1
+debug_api/writeprocessmemory/test2
+debug_api/writeprocessmemory/test3
+debug_api/writeprocessmemory/test4
+=======================================
+The above testcases were disabled in the palsuite, because they depend heavily on
+WaitForDebugEvent,DebugActiveProcess and ContinueDebugEvent, where these api's have been removed from the PAL and listed in the rotor_pal.doc (6.0)
+
+
+file_io/gettempfilenamea/test2 :
+=======================================
+This test takes longer than 60 seconds to run. The test creates
+about 65000 files and then deletes them. The test that takes longer
+than 60 seconds will be flagged as an error and so in such a case
+the test will have to be run manually.
+
+file_io/gettempfilenamew/test2 :
+=======================================
+This test takes longer than 60 seconds to run. The test creates
+about 65000 files and then deletes them. The test that takes longer
+than 60 seconds will be flagged as an error and so in such a case
+the test will have to be run manually.
+
+locale_info/getcpinfo/test2:
+=======================================
+This test will be useful in future versions for testing various
+languages (code pages). Currently only U.S. English (tested by -
+test1) is supported.
+
+locale_info/getcpinfo/test3:
+=======================================
+This test will be useful in future versions for testing various
+languages (code pages). Currently only U.S. English (tested by -
+test1) is supported.
+
+locale_info/isvalidcodepage/test2:
+=======================================
+This test will be useful in future versions for testing various
+languages (code pages). Currently only U.S. English (tested by -
+test1) is supported.
+
+miscellaneous/getcalendarinfow/test2:
+=======================================
+Currently the only calendars that are supported are CAL_GREGORIAN
+and CAL_GREGORIAN_US, which are tested by test1. This test will
+be useful when full calendar support is implemented.
+
+miscellaneous/getdateformatw/test1:
+===================================
+Currently the only calendars that are supported are CAL_GREGORIAN
+and CAL_GREGORIAN_US. The GetDateFormatW function will only be
+called when the calendar is CAL_TAIWAN. Since this calendar is not
+currently supported in this release of the PAL, the GetDateFormatW
+function is not implemented except to return an error. This test
+will be useful when full calendar support is implemented.
+
+miscellaneous/getdateformatw/getdateformatw_neg1:
+================================================
+Currently the only calendars that are supported are CAL_GREGORIAN
+and CAL_GREGORIAN_US. The GetDateFormatW function will only be
+called when the calendar is CAL_TAIWAN. Since this calendar is not
+currently supported in this release of the PAL, the GetDateFormatW
+function is not implemented except to return an error. This test
+will be useful when full calendar support is implemented.
+
+miscellaneous/getdateformatw/getdateformatw_neg2:
+================================================
+Currently the only calendars that are supported are CAL_GREGORIAN
+and CAL_GREGORIAN_US. The GetDateFormatW function will only be
+called when the calendar is CAL_TAIWAN. Since this calendar is not
+currently supported in this release of the PAL, the GetDateFormatW
+function is not implemented except to return an error. This test
+will be useful when full calendar support is implemented.
+
+
+pal_specific/pal_get_stdin/test1 :
+=======================================
+This test case should be run manually. Requires user input.
+
+
+threading/setconsolectrlhandler/test1
+threading/setconsolectrlhandler/test2
+threading/setconsolectrlhandler/test3
+threading/setconsolectrlhandler/test4
+=======================================
+These tests cases should be run manually. Requires user input.
+
+threading/getprocesstimes/test1
+=======================================
+According to rotor_pal.doc, GetProcessTimes() should be supported for the current
+process only. I've removed this test because it tests GetProcessTimes() with
+invalid process handle value.
+
+threading/getthreadcontext/test1,1
+=======================================
+According to rotor_pal.doc, when GetThreadContext is call for a thread within
+the same process, it could only be called for te current thread. I've removed
+this test, because it tests GetThreadContext() with a non current thread handle
+belong the current procees.
+
+loader/loadlibrarya/test4
+loader/loadlibraryw/test4
+=======================================
+PAL BSD should not append the .so extension in LoadLibrary if the extension is
+omitted.
+file_io/deletefilea/test3
+file_io/deletefilew/test3
+=======================================
+No code in Rotor depends on DeleteFile[A/W] failing on readonly files so we
+don't need to exactly emulate this feature of the Win32 filesystems on FreeBSD.
+
+filemapping_memmgt\MapViewOfFile\test1
+=======================================
+Refer this github issue https://github.com/dotnet/coreclr/issues/5176 \ No newline at end of file
diff --git a/src/pal/tests/palsuite/README.txt b/src/pal/tests/palsuite/README.txt
new file mode 100644
index 0000000000..577fc543f0
--- /dev/null
+++ b/src/pal/tests/palsuite/README.txt
@@ -0,0 +1,140 @@
+; Licensed to the .NET Foundation under one or more agreements.
+; The .NET Foundation licenses this file to you under the MIT license.
+; See the LICENSE file in the project root for more information.
+
+===========================================================================
+
+
+1. ENVIRONMENT SETUP
+
+2. RUNNING THE SUITES
+
+3. ENVIRONMENT VARIABLES AND AUTOMATED TESTING SPECIFICS
+3.1 PAL_DISABLE_MESSAGEBOX
+3.2 Other Notes
+
+4. ADDITIONAL NOTES ON TESTING/SPECIFIC TEST CASE ISSUES
+ C_runtime: _fdopen testing issues
+ File_IO: getfiletime/test5
+ File_IO: getfilesize/test1, setfilepointer/test(5,6,7)
+ File_IO: gettempfilename(a,w)/test2
+ File_IO: setfileattributesa/test(1,4), setfileattributesw/test(1,4)
+ Miscellaneous: messageboxw/test(1,2)
+ Pal_specific:: pal_get_stdin/test1, pal_get_stdout/test1, pal_get_stderr/test1
+ Threading: setconsolectrlhandler/test(3,4)
+
+
+===========================================================================
+
+1. ENVIRONMENT SETUP
+~~~~~~~~~~~~~~~~~~~~~
+
+Within a Rotor build window (env.sh/env.csh/env.bat), no additional
+configuration needs to be done.
+
+
+2. RUNNING THE SUITES
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Run %ROTOR_DIR%\tests\pvtrun.pl to launch the test suites. It will
+display information about each test as it runs, then report a
+summary of the results upon completion.
+
+The results are logged to %ROTOR_DIR%\tests\pvtResults.log.
+
+
+3. ENVIRONMENT VARIABLES AND AUTOMATED TESTING SPECIFICS
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+3.1 PAL_DISABLE_MESSAGEBOX
+
+For automated testing on the WIN32 PAL, the following environment
+variable is useful to prevent pop-up message boxes from interupting the
+execution of the MessageBoxW test cases:
+
+set PAL_DISABLE_MESSAGEBOX=1
+
+
+3.2 Other Notes
+
+See notes in section 4 on the following test cases if running automated tests:
+
+ Miscellaneous: messageboxw/test(1,2)
+ Threading: setconsolectrlhandler/test(3,4)
+
+
+4. ADDITIONAL NOTES ON TESTING/SPECIFIC TEST CASE ISSUES
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+C Runtime: _fdopen testing issues
+
+There is a very specific manner in which _fdopen has been documented to work,
+this will determine how the function will be tested.
+
+_fdopen takes a parameter of a c run-time file handle, to open a stream to the
+file. This file handle can only be returned from the _open_osfhandle function.
+The Rotor documentation states that _open_osfhandle will only return a
+READ-ONLY file handle, from an operating-system file handle returned from
+CreatePipe().
+
+With these restrictions _fdopen will only be tested with a mode of read(r).
+The other modes are not possible to test. _open_osfhandle returns an error
+when attempting to open a write pipe handle in a mode of read-only. As well,
+it is not possible to read and write to the same handle that is returned from
+CreatePipe().
+
+The modes that will not be tested are as follows:
+
+ "w" - Opens an empty file for writing.
+ "a" - Opens for writing at the end of the file (appending).
+ "r+" - Opens for both reading and writing.
+ "w+" - Opens an empty file for both reading and writing.
+ "a+" - Opens for reading and appending.
+
+
+
+File_IO: getfiletime/test5
+
+This test case is NTFS specific.
+
+
+File_IO: getfilesize/test1, getfilesizeex/test1 setfilepointer/test(5,6,7)
+
+These tests cases create a large number of temporary files which require
+ample disk space. On systems with less than 6Gb free disk space expect
+these test cases to fail.
+
+
+File_IO: gettempfilename(a,w)/test2
+
+These test cases take longer than 60 seconds to run. Currently, the Test
+Harness will timeout any test case that exceeds 60 seconds.
+
+
+File_IO: setfileattributesa/test(1,4), SetFileAttributesW/test(1,4)
+
+These test cases ensure restricted file permissions are respected. Administrators
+or super users (root) are not affected by file permissions and, as a result, these
+test cases will fail for such users.
+
+
+Miscellaneous: messageboxw/test(1,2)
+
+Setting PAL_MESSAGEBOX_DISABLE=1 for these test cases prevents message box pop
+ups that occur during the tests' execution on Windows. For automated testing
+where user interaction is not desired/possible, setting this environment
+variable will prevent a pause in the automated test run.
+
+
+ic: pal_get_stdin/test1, pal_get_stdout/test1, pal_get_stderr/test1
+
+These test cases should be manually inspected to ensure the information being returned
+is correct. The pal_get_stdin test case requires user input. The pal_get_stdout and
+pal_get_stderr test cases do not require user input, but their output should be inspected
+to verify that correct messages are being displayed.
+
+
+Threading: setconsolectrlhandler/test(3,4)
+
+These test cases require user response in order to produce a meaningful results.
+For automated testing, this test case is disabled.
diff --git a/src/pal/tests/palsuite/c_runtime/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/CMakeLists.txt
new file mode 100644
index 0000000000..533454c285
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/CMakeLists.txt
@@ -0,0 +1,162 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(abs)
+add_subdirectory(acos)
+add_subdirectory(asin)
+add_subdirectory(atan)
+add_subdirectory(atan2)
+add_subdirectory(atof)
+add_subdirectory(atoi)
+add_subdirectory(atol)
+add_subdirectory(bsearch)
+add_subdirectory(ceil)
+add_subdirectory(cos)
+add_subdirectory(cosh)
+
+# TODO: make this test compile
+# add_subdirectory(ctime)
+
+add_subdirectory(errno)
+add_subdirectory(exit)
+add_subdirectory(exp)
+add_subdirectory(fabs)
+add_subdirectory(fabsf)
+add_subdirectory(fclose)
+add_subdirectory(feof)
+add_subdirectory(ferror)
+add_subdirectory(fflush)
+add_subdirectory(fgets)
+add_subdirectory(floor)
+add_subdirectory(fmod)
+add_subdirectory(fmodf)
+add_subdirectory(fopen)
+add_subdirectory(fprintf)
+add_subdirectory(fputs)
+add_subdirectory(fread)
+add_subdirectory(free)
+add_subdirectory(fseek)
+add_subdirectory(ftell)
+add_subdirectory(fwprintf)
+add_subdirectory(fwrite)
+add_subdirectory(getc)
+add_subdirectory(getenv)
+add_subdirectory(isalnum)
+add_subdirectory(isalpha)
+add_subdirectory(isdigit)
+add_subdirectory(islower)
+add_subdirectory(isprint)
+add_subdirectory(isspace)
+add_subdirectory(isupper)
+add_subdirectory(iswdigit)
+add_subdirectory(iswspace)
+add_subdirectory(iswupper)
+add_subdirectory(iswxdigit)
+add_subdirectory(isxdigit)
+add_subdirectory(labs)
+add_subdirectory(llabs)
+add_subdirectory(localtime)
+add_subdirectory(log)
+add_subdirectory(log10)
+add_subdirectory(malloc)
+add_subdirectory(memchr)
+add_subdirectory(memcmp)
+add_subdirectory(memcpy)
+add_subdirectory(memmove)
+add_subdirectory(memset)
+add_subdirectory(modf)
+add_subdirectory(modff)
+add_subdirectory(pow)
+add_subdirectory(printf)
+add_subdirectory(qsort)
+add_subdirectory(rand_srand)
+add_subdirectory(realloc)
+add_subdirectory(sin)
+add_subdirectory(sinh)
+add_subdirectory(sprintf)
+add_subdirectory(sqrt)
+add_subdirectory(sscanf)
+add_subdirectory(strcat)
+add_subdirectory(strchr)
+add_subdirectory(strcmp)
+add_subdirectory(strcpy)
+add_subdirectory(strcspn)
+add_subdirectory(strlen)
+add_subdirectory(strncat)
+add_subdirectory(strncmp)
+add_subdirectory(strncpy)
+add_subdirectory(strpbrk)
+add_subdirectory(strrchr)
+add_subdirectory(strspn)
+add_subdirectory(strstr)
+add_subdirectory(strtod)
+add_subdirectory(strtok)
+add_subdirectory(strtoul)
+add_subdirectory(swprintf)
+add_subdirectory(swscanf)
+add_subdirectory(tan)
+add_subdirectory(tanh)
+add_subdirectory(time)
+add_subdirectory(tolower)
+add_subdirectory(toupper)
+add_subdirectory(towlower)
+add_subdirectory(towupper)
+add_subdirectory(ungetc)
+add_subdirectory(vfprintf)
+add_subdirectory(vprintf)
+add_subdirectory(vsprintf)
+add_subdirectory(vswprintf)
+add_subdirectory(wcscat)
+add_subdirectory(wcschr)
+add_subdirectory(wcscmp)
+add_subdirectory(wcscpy)
+add_subdirectory(wcslen)
+add_subdirectory(wcsncat)
+add_subdirectory(wcsncmp)
+add_subdirectory(wcsncpy)
+add_subdirectory(wcspbrk)
+add_subdirectory(wcsrchr)
+add_subdirectory(wcsstr)
+add_subdirectory(wcstod)
+add_subdirectory(wcstok)
+add_subdirectory(wcstol)
+add_subdirectory(wcstoul)
+add_subdirectory(wprintf)
+add_subdirectory(_alloca)
+add_subdirectory(_ecvt)
+add_subdirectory(_fdopen)
+add_subdirectory(_finite)
+add_subdirectory(_fullpath)
+
+# TODO: make this test compile
+# add_subdirectory(_gcvt)
+
+add_subdirectory(_getw)
+add_subdirectory(_isnan)
+add_subdirectory(_itow)
+add_subdirectory(_makepath)
+add_subdirectory(_mbsdec)
+add_subdirectory(_mbsinc)
+add_subdirectory(_mbslen)
+add_subdirectory(_mbsninc)
+add_subdirectory(_open_osfhandle)
+add_subdirectory(_putenv)
+add_subdirectory(_putw)
+add_subdirectory(_rotl)
+add_subdirectory(_rotr)
+add_subdirectory(_snprintf)
+add_subdirectory(_snwprintf)
+add_subdirectory(_splitpath)
+add_subdirectory(_stricmp)
+add_subdirectory(_strlwr)
+add_subdirectory(_strnicmp)
+add_subdirectory(_swab)
+add_subdirectory(_vsnprintf)
+add_subdirectory(_vsnwprintf)
+add_subdirectory(_wcsicmp)
+add_subdirectory(_wcslwr)
+add_subdirectory(_wcsnicmp)
+add_subdirectory(_wfopen)
+add_subdirectory(_wmakepath)
+add_subdirectory(_wsplitpath)
+add_subdirectory(_wtoi)
+add_subdirectory(__iscsym)
diff --git a/src/pal/tests/palsuite/c_runtime/__iscsym/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/__iscsym/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/__iscsym/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/__iscsym/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/__iscsym/test1/CMakeLists.txt
new file mode 100644
index 0000000000..a283161f7d
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/__iscsym/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ __iscsym.c
+)
+
+add_executable(paltest_iscsym_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_iscsym_test1 coreclrpal)
+
+target_link_libraries(paltest_iscsym_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/__iscsym/test1/__iscsym.c b/src/pal/tests/palsuite/c_runtime/__iscsym/test1/__iscsym.c
new file mode 100644
index 0000000000..9c8f1d0f25
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/__iscsym/test1/__iscsym.c
@@ -0,0 +1,93 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: __iscsym.c
+**
+** Purpose: Positive test the __iscsym API.
+** Call __iscsym to letter, digit and underscore
+**
+**
+**============================================================*/
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ int err;
+ int index;
+ char non_letter_set[]=
+ {'~','`','!','@','#','$','%','^','&','*','(',')',')',
+ '-','+','=','|','\\',';',':','"','\'','<','>',
+ ',','.','?','/','\0'};
+ char errBuffer[200];
+
+ /*Initialize the PAL environment*/
+ err = PAL_Initialize(argc, argv);
+ if(0 != err)
+ {
+ return FAIL;
+ }
+
+ /*To check if the parameter passed in is a character*/
+ for(index = 'a'; index <= 'z'; index++)
+ {
+ err = __iscsym(index);
+ if(0 == err)
+ {
+ Fail("\n__iscsym failed to recognize a "
+ "lower-case letter:%c!\n", index);
+ }
+ }
+
+ /*To check if the parameter passed in is a character*/
+ for(index = 'A'; index <= 'Z'; index++)
+ {
+ err = __iscsym(index);
+ if(0 == err)
+ {
+ Fail("\n__iscsym failed to recognize an "
+ "upper-case letter: %c!\n", index);
+ }
+ }
+
+ /*To check if the parameter passed in is a digit*/
+ for(index = '0'; index <= '9'; index++)
+ {
+ err = __iscsym(index);
+ if(0 == err)
+ {
+ Fail("\n__iscsym failed to recognize a digit %c!\n",
+ index);
+ }
+ }
+
+ /*To check if the parameter passed in is a underscore*/
+ err = __iscsym('_');
+ if(0 == err)
+ {
+ Fail("\n__iscsym failed to recognize an underscore!\n");
+ }
+
+ memset(errBuffer, 0, 200);
+
+ for(index = 0; non_letter_set[index]; index++)
+ {
+ err = __iscsym(non_letter_set[index]);
+ if(0 != err)
+ {
+ strncat(errBuffer, &non_letter_set[index], 1);
+ strcat(errBuffer, ", ");
+ }
+ }
+
+ if(strlen(errBuffer) > 0)
+ {
+ Fail("\n__iscsym failed to identify the characters '%s' "
+ "as not letters, digits "
+ "or underscores\n", errBuffer);
+ }
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/__iscsym/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/__iscsym/test1/testinfo.dat
new file mode 100644
index 0000000000..e6668edccf
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/__iscsym/test1/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = __iscsym
+Name = Positive test for __iscsym to test letter, digit and underscore
+TYPE = DEFAULT
+EXE1 = __iscsym
+Description
+=Test the __iscsym to test letter, digit and underscore
diff --git a/src/pal/tests/palsuite/c_runtime/_alloca/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_alloca/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_alloca/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/_alloca/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_alloca/test1/CMakeLists.txt
new file mode 100644
index 0000000000..236b356185
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_alloca/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_alloca_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_alloca_test1 coreclrpal)
+
+target_link_libraries(paltest_alloca_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_alloca/test1/test1.c b/src/pal/tests/palsuite/c_runtime/_alloca/test1/test1.c
new file mode 100644
index 0000000000..c533d84234
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_alloca/test1/test1.c
@@ -0,0 +1,62 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Checks that _alloca allocates memory, and that the memory is
+** readable and writeable.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char **argv)
+{
+
+ char *testA = NULL;
+ int i = 0;
+
+ /*
+ * Initialize the PAL and return FAIL if this fails
+ */
+ if (0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+
+ /* check that _alloca really gives us addressable memory */
+ testA = (char *)_alloca(20 * sizeof(char));
+ if (testA == NULL)
+ {
+ Fail ("The call to _alloca failed\n");
+ }
+
+ memset(testA, 'a', 20);
+
+ for (i = 0; i < 20; i++)
+ {
+ if (testA[i] != 'a')
+ {
+ Fail ("The memory returned by _alloca doesn't seem to be"
+ " properly allocated\n");
+ }
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
+
+
+
+
+
+
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/_alloca/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_alloca/test1/testinfo.dat
new file mode 100644
index 0000000000..e21562195e
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_alloca/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _alloca
+Name = Positive Test for _alloca
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Checks that _alloca allocates memory, and that the memory is
+= readable and writeable.
diff --git a/src/pal/tests/palsuite/c_runtime/_ecvt/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_ecvt/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_ecvt/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/_ecvt/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_ecvt/test1/CMakeLists.txt
new file mode 100644
index 0000000000..86f4547b2b
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_ecvt/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_ecvt_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_ecvt_test1 coreclrpal)
+
+target_link_libraries(paltest_ecvt_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_ecvt/test1/test1.c b/src/pal/tests/palsuite/c_runtime/_ecvt/test1/test1.c
new file mode 100644
index 0000000000..fbcf11ecfc
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_ecvt/test1/test1.c
@@ -0,0 +1,135 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: c_runtime/_ecvt/test1/test1.c
+**
+** Purpose: Call the _ecvt function on a number of cases. Check that it
+** handles negatives, positives and double bounds correctly. Also check that
+** the 'digit' specification works.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+#define INT64_TO_DOUBLE(a) (*(double*)&a)
+
+INT64 NaN = 0x7ff8000000000000;
+INT64 NegativeInfinity = 0xfff0000000000000;
+INT64 NegativeSmall = 0x8000000000000001;
+INT64 PositiveInfinity = 0x7ff0000000000000;
+INT64 PositiveSmall = 0x0000000000000001;
+
+struct testCase
+{
+ double value; /* number to be converted */
+ int precision; /* number of digits to be stored */
+ int decimal; /* (expected) decimal point position for stored
+ * number */
+ int sign; /* (expected) return value */
+ char expResult[256]; /* (expected) character array to be returned
+ * NOTE: this necessarily limits precision
+ * to a value between 0 and 255 */
+ char bsdExpResult[256]; /* (expected) character array to be returned
+ * NOTE: this necessarily limits precision
+ * to a value between 0 and 255 */
+};
+
+int __cdecl main(int argc, char **argv)
+{
+ char *result;
+ int testDecimal;
+ int testSign;
+ int i=0;
+
+ struct testCase testCases[] =
+ {
+ /* odd ball values */
+ {INT64_TO_DOUBLE(NaN), 7, 1, 0, "1#QNAN0" },
+ /* positive values */
+ {0, 0, 0, 0, ""},
+ {INT64_TO_DOUBLE(PositiveSmall), 17, -323, 0,
+ "49406564584124654"},
+ {.00123, 3, -2, 0, "123"},
+ {.123, 3, 0, 0, "123"},
+ {123, 3, 3, 0, "123"},
+ {3.1415926535, 9, 1, 0, "314159265"},
+ {3.1415926535, 10, 1, 0, "3141592654"},
+ {3.1415926535, 11, 1, 0, "31415926535"},
+ {3.1415926535, 12, 1, 0, "314159265350"},
+ {184467444073709570000.0, 21, 21, 0, "184467444073709570000",
+ "184467444073709568000" },
+ {184467444073709570000.0, 22, 21, 0, "1844674440737095700000",
+ "1844674440737095680000" },
+ {INT64_TO_DOUBLE(PositiveInfinity), 7, 1, 0, "1#INF00" },
+ /* negative values */
+ {-0, 0, 0, 0, ""},
+ {INT64_TO_DOUBLE(NegativeSmall), 17, -323, 1,
+ "49406564584124654"},
+ {-.00123, 3, -2, 1, "123"},
+ {-.123, 3, 0, 1, "123"},
+ {-123, 3, 3, 1, "123"},
+ {-3.1415926535, 9, 1, 1, "314159265"},
+ {-3.1415926535, 10, 1, 1, "3141592654"},
+ {-3.1415926535, 11, 1, 1, "31415926535"},
+ {-3.1415926535, 12, 1, 1, "314159265350"},
+ {-184467444073709570000.0, 21, 21, 1, "184467444073709570000",
+ "184467444073709568000" },
+ {-184467444073709570000.0, 22, 21, 1, "1844674440737095700000",
+ "1844674440737095680000" },
+ {INT64_TO_DOUBLE(NegativeInfinity), 7, 1, 1, "1#INF00"}
+
+ };
+
+ if (0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /* Loop through each case. Call _ecvt on each test case and check the
+ result.
+ */
+
+ for(i = 0; i < sizeof(testCases) / sizeof(struct testCase); i++)
+ {
+ result = _ecvt(testCases[i].value,
+ testCases[i].precision,
+ &testDecimal,
+ &testSign);
+
+ if (( strcmp(testCases[i].expResult, result) != 0 &&
+ strcmp(testCases[i].bsdExpResult, result) != 0 ) ||
+
+ ( testCases[i].sign != testSign ) ||
+ ( testCases[i].decimal != testDecimal ))
+
+ {
+ Fail("PALSUITE ERROR: Test %d\n"
+ "-----------------------\n"
+ "testCases[i].value = '%f'\n"
+ "testCases[i].precision = '%d'\n"
+ "testCases[i].decimal = '%d'\n"
+ "testCases[i].sign = '%d'\n"
+ "testCases[i].expResult = '%s'\n"
+ "result = '%s'\n"
+ "testDecimal = '%d'\n"
+ "testSign = '%d'\n\n",
+ i,
+ testCases[i].value,
+ testCases[i].precision,
+ testCases[i].decimal,
+ testCases[i].sign,
+ testCases[i].expResult,
+ result,
+ testDecimal,
+ testSign);
+ }
+
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/_ecvt/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_ecvt/test1/testinfo.dat
new file mode 100644
index 0000000000..12e7292ec7
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_ecvt/test1/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _ecvt
+Name = Call _ecvt on normal values, negatives, exponents and hex digits.
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Call the _ecvt function on a number of cases. Check that it
+= handles negatives, positives and double bounds correctly. Also check that
+= the 'digit' specification works.
diff --git a/src/pal/tests/palsuite/c_runtime/_fdopen/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_fdopen/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_fdopen/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/_fdopen/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_fdopen/test1/CMakeLists.txt
new file mode 100644
index 0000000000..441d32bd5c
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_fdopen/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_fdopen_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_fdopen_test1 coreclrpal)
+
+target_link_libraries(paltest_fdopen_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_fdopen/test1/test1.c b/src/pal/tests/palsuite/c_runtime/_fdopen/test1/test1.c
new file mode 100644
index 0000000000..b88267c6e4
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_fdopen/test1/test1.c
@@ -0,0 +1,112 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test1.c (fdopen)
+**
+** Purpose: Tests the PAL implementation of the fdopen function.
+** This will test fdopen in r (read) mode. This test
+** creates and opens a test pipe, to write and read
+** from. fdopen requires a file handle(int), therefore
+** _open_osfhandle is used to get that handle.
+** _open_osfhandle is only used with CreatePipe. The
+** test will write and read from the pipe comparing
+** the results.
+**
+** See /tests/palsuite/README.txt for more information.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+const char* cTestString = "one fish, two fish, read fish, blue fish.";
+
+int __cdecl main(int argc, char **argv)
+{
+ HANDLE hReadPipe = NULL;
+ HANDLE hWritePipe = NULL;
+ BOOL bRetVal = FALSE;
+ int iFiledes = 0;
+ DWORD dwBytesWritten;
+ char buffer[45];
+ FILE *fp;
+
+ SECURITY_ATTRIBUTES lpPipeAttributes;
+
+ /*Initialize the PAL*/
+ if ((PAL_Initialize(argc, argv)) != 0)
+ {
+ return (FAIL);
+ }
+
+ /*Setup SECURITY_ATTRIBUTES structure for CreatePipe*/
+ lpPipeAttributes.nLength = sizeof(lpPipeAttributes);
+ lpPipeAttributes.lpSecurityDescriptor = NULL;
+ lpPipeAttributes.bInheritHandle = TRUE;
+
+ /*Create a Pipe*/
+ bRetVal = CreatePipe(&hReadPipe, // read handle
+ &hWritePipe, // write handle
+ &lpPipeAttributes, // security attributes
+ 0); // pipe size
+
+ if (bRetVal == FALSE)
+ {
+ Fail("ERROR: unable to create pipe");
+ }
+
+ /*Write to the write pipe handle*/
+ bRetVal = WriteFile(hWritePipe, // handle to file
+ cTestString, // data buffer
+ (DWORD)strlen(cTestString), // number of bytes to write
+ &dwBytesWritten, // number of bytes written
+ NULL); // overlapped buffer
+
+ if (bRetVal == FALSE)
+ {
+ Fail("ERROR: unable to write to pipe write handle "
+ "hWritePipe=0x%lx", hWritePipe);
+ }
+
+ /*Get a file descriptor for the read pipe handle*/
+ iFiledes = _open_osfhandle((long)hReadPipe, _O_RDONLY);
+
+ if (iFiledes == -1)
+ {
+ Fail("ERROR: _open_osfhandle failed to open "
+ " hReadPipe=0x%lx", hReadPipe);
+ }
+
+ /*Open read pipe handle in read mode*/
+ fp = _fdopen(iFiledes, "r");
+
+ if (fp == NULL)
+ {
+ Fail("ERROR: unable to fdopen file descriptor"
+ " iFiledes=%d", iFiledes);
+ }
+
+ /*Read from the read pipe handle*/
+ if((fread(buffer, sizeof(char), strlen(cTestString), fp)) == 0)
+ {
+ Fail("ERROR: Unable to read from file stream fp=0x%lx\n", fp);
+ }
+
+ /*Compare what was read with what was written.*/
+ if ((memcmp(cTestString, buffer, strlen(cTestString))) != 0)
+ {
+ Fail("ERROR: read \"%s\" expected \"%s\" \n", buffer, cTestString);
+ }
+
+ /*Close the file handle*/
+ if (_close(iFiledes) != 0)
+ {
+ Fail("ERROR: Unable to close file handle iFiledes=%d\n", iFiledes);
+ }
+
+ PAL_Terminate();
+ return (PASS);
+}
diff --git a/src/pal/tests/palsuite/c_runtime/_fdopen/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_fdopen/test1/testinfo.dat
new file mode 100644
index 0000000000..89e48bb4c1
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_fdopen/test1/testinfo.dat
@@ -0,0 +1,23 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = fdopen
+Name = test for fdopen and _close
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Tests the PAL implementation of the fdopen function.
+= This will test fdopen in r (read) mode. This test
+= creates and opens a test pipe, to write and read
+= from. fdopen requires a file handle(int), therefore
+= _open_osfhandle is used to get that handle.
+= _open_osfhandle is only used with CreatePipe. The
+= test will write and read from the pipe comparing
+= the results.
+= As a secondary test, _close is tested since it needs
+= the handle returned by _open_osfhandle. The handle is
+= closed, then a read is attempted on the handle which
+= should fail.
diff --git a/src/pal/tests/palsuite/c_runtime/_finite/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_finite/CMakeLists.txt
new file mode 100644
index 0000000000..5e1ef7f28b
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_finite/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
diff --git a/src/pal/tests/palsuite/c_runtime/_finite/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_finite/test1/CMakeLists.txt
new file mode 100644
index 0000000000..8aca58a8dc
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_finite/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_finite_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_finite_test1 coreclrpal)
+
+target_link_libraries(paltest_finite_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_finite/test1/test1.c b/src/pal/tests/palsuite/c_runtime/_finite/test1/test1.c
new file mode 100644
index 0000000000..c815055b38
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_finite/test1/test1.c
@@ -0,0 +1,119 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Checks that _finite correctly classifies all types
+** of floating point numbers (NaN, -Infinity, Infinity,
+** finite nonzero, unnormalized, 0, and -0)
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+
+/*
+The IEEE double precision floating point standard looks like this:
+
+ S EEEEEEEEEEE FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+ 0 1 11 12 63
+
+S is the sign bit. The E bits are the exponent, and the 52 F bits are
+the fraction. These represent a value, V.
+
+If E=2047 and F is nonzero, then V=NaN ("Not a number")
+If E=2047 and F is zero and S is 1, then V=-Infinity
+If E=2047 and F is zero and S is 0, then V=Infinity
+If 0<E<2047 then V=(-1)^S * 2^(E-1023) * (1.F) where "1.F" is the binary
+ number created by prefixing F with a leading 1 and a binary point.
+If E=0 and F is nonzero, then V=(-1)^S * 2^(-1022) * (0.F) These are
+ "unnormalized" values.
+If E=0 and F is zero and S is 1, then V=-0
+If E=0 and F is zero and S is 0, then V=0
+
+*/
+
+#define TO_DOUBLE(x) (*((double*)((void*)&x)))
+
+int __cdecl main(int argc, char **argv)
+{
+ /*non-finite numbers*/
+ UINT64 lsnan = UI64(0xffffffffffffffff);
+ UINT64 lqnan = UI64(0x7fffffffffffffff);
+ UINT64 lneginf = UI64(0xfff0000000000000);
+ UINT64 lposinf = UI64(0x7ff0000000000000);
+
+ double snan = TO_DOUBLE(lsnan);
+ double qnan = TO_DOUBLE(lqnan);
+ double neginf = TO_DOUBLE(lneginf);
+ double posinf = TO_DOUBLE(lposinf);
+
+ /*finite numbers*/
+ UINT64 lnegunnormalized = UI64(0x800fffffffffffff);
+ UINT64 lposunnormalized = UI64(0x000fffffffffffff);
+ UINT64 lnegzero = UI64(0x8000000000000000);
+
+ double negunnormalized = TO_DOUBLE(lnegunnormalized);
+ double posunnormalized = TO_DOUBLE(lposunnormalized);
+ double negzero = TO_DOUBLE(lnegzero);
+
+ /*
+ * Initialize the PAL and return FAIL if this fails
+ */
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+ /*non-finite numbers*/
+ if (_finite(snan) || _finite(qnan))
+ {
+ Fail("_finite() found NAN to be finite.\n");
+ }
+
+ if (_finite(neginf))
+ {
+ Fail("_finite() found negative infinity to be finite.\n");
+ }
+
+ if (_finite(posinf))
+ {
+ Fail("_finite() found infinity to be finite.\n");
+ }
+
+ /*finite numbers*/
+ if (!_finite(negunnormalized))
+ {
+ Fail("_finite() found a negative unnormalized value to be infinite.\n");
+ }
+
+ if (!_finite(posunnormalized))
+ {
+ Fail("_finite() found an unnormalized value to be infinite.\n");
+ }
+
+ if (!_finite(negzero))
+ {
+ Fail("_finite() found negative zero to be infinite.\n");
+ }
+
+ if (!_finite(+0.0))
+ {
+ Fail("_finite() found zero to be infinite.\n");
+ }
+
+ if (!_finite(-123.456))
+ {
+ Fail("_finite() found %f to be infinite.\n", -123.456);
+ }
+
+ if (!_finite(+123.456))
+ {
+ Fail("_finite() found %f to be infinite.\n", +123.456);
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/_finite/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_finite/test1/testinfo.dat
new file mode 100644
index 0000000000..cec0f8ae4a
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_finite/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _finite
+Name = Positive Test for _finite
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Checks that _finite correctly classifies all types of floating point
+= numbers (NaN, -Infinity, Infinity, finite nonzero, unnormalized, 0, and -0).
diff --git a/src/pal/tests/palsuite/c_runtime/_fullpath/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_fullpath/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_fullpath/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/_fullpath/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_fullpath/test1/CMakeLists.txt
new file mode 100644
index 0000000000..9306efa700
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_fullpath/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_fullpath_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_fullpath_test1 coreclrpal)
+
+target_link_libraries(paltest_fullpath_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_fullpath/test1/test1.c b/src/pal/tests/palsuite/c_runtime/_fullpath/test1/test1.c
new file mode 100644
index 0000000000..f390f4309b
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_fullpath/test1/test1.c
@@ -0,0 +1,181 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: _fullpath/test1/test1.c
+**
+** Purpose: Test to see if the _fullpath function returns the
+** proper values. A check is done to ensure NULL is returned
+** by _fullpath only for the condition where the length of the
+** created absolute path name (absPath) is greater than
+** maxLength.
+**
+** Dependencies: strlen
+** strncmp
+** SetCurrentDirectory
+** GetCurrentDirectory
+**
+
+**
+**=========================================================*/
+
+#include <palsuite.h>
+
+struct testcase
+{
+ char relPath[50]; /* relative path array */
+ int maxLength; /* pathlength to pass */
+ BOOL bRet; /* TRUE if testcase expects function to return NULL */
+};
+
+int __cdecl main( int argc, char **argv )
+{
+
+ DWORD dwOrigDirLength;
+ DWORD dwNewDirLength;
+ DWORD dwRetStrLength;
+ BOOL bRet;
+ char *retPath;
+ char szAbsPath[_MAX_PATH + 1];
+ char szDirNameOWD[_MAX_DIR];
+ char szDirNameNWD[_MAX_DIR];
+ int i;
+
+ struct testcase testcases[]=
+ {
+ {"." , _MAX_PATH, FALSE},
+ {".." , _MAX_PATH, FALSE},
+ {"..\\..", _MAX_PATH, FALSE},
+ {"..\\..\\..", _MAX_PATH, FALSE},
+ {"..", 1, TRUE}
+ };
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return ( FAIL );
+ }
+
+ for (i = 0; i < sizeof(testcases)/sizeof(struct testcase) ; i++)
+ {
+
+ /* reset variables */
+ memset(szAbsPath, 0, _MAX_PATH + 1);
+ memset(szDirNameOWD, 0, _MAX_DIR);
+ memset(szDirNameNWD, 0, _MAX_DIR);
+
+ dwOrigDirLength = 0;
+ dwNewDirLength = 0;
+ dwRetStrLength = 0;
+
+ /* Get the current directory name */
+ dwOrigDirLength = GetCurrentDirectory(_MAX_PATH, szDirNameOWD);
+ if (0 == dwOrigDirLength)
+ {
+ Fail ("PALSUITE ERROR: _fullpath (char *, %s, %d) test failed."
+ "\nGetCurrentDirectory (%d, %s) call failed. GetLastError"
+ " returned '%d'\n", testcases[i].relPath,
+ testcases[i].maxLength, _MAX_PATH, szDirNameOWD,
+ GetLastError());
+ }
+
+ /*
+ * Set the current directory to relPath.
+ */
+ bRet = SetCurrentDirectory(testcases[i].relPath);
+ if (0 == bRet)
+ {
+ Fail ("PALSUITE ERROR: _fullpath (char *, %s, %d) test failed."
+ "\nSetCurrentDirectory (%s) call failed. GetLastError"
+ " returned '%d'\n", testcases[i].relPath,
+ testcases[i].maxLength, testcases[i].relPath,
+ GetLastError());
+ }
+
+ /* Get the new current directory name */
+ dwNewDirLength = GetCurrentDirectory(_MAX_PATH, szDirNameNWD);
+ if (0 == dwNewDirLength)
+ {
+ Fail ("PALSUITE ERROR: _fullpath (char *, %s, %d) test failed."
+ "\nGetCurrentDirectory(%d, %s) call failed. GetLastError"
+ " returned '%d'\n", testcases[i].relPath,
+ testcases[i].maxLength, _MAX_PATH, szDirNameNWD,
+ GetLastError());
+ }
+
+ /* Set the current directory back to the original one */
+ bRet = SetCurrentDirectory(szDirNameOWD);
+ if (0 == bRet)
+ {
+ Fail ("PALSUITE ERROR: _fullpath (char *, %s, %d) test failed."
+ "\nSetCurrentDirectory(%s) call failed. GetLastError"
+ " returned '%d'\n", testcases[i].relPath,
+ testcases[i].maxLength, szDirNameOWD, GetLastError());
+ }
+
+ retPath = _fullpath( szAbsPath,
+ testcases[i].relPath,
+ testcases[i].maxLength );
+
+ if ( NULL == retPath )
+ {
+ /* The function returned NULL when a value was expected */
+ if ( FALSE == testcases[i].bRet )
+ {
+ Fail("PALSUITE ERROR: test failed.\n"
+ "_fullpath (char *, %s, %d) returned NULL\n"
+ "when '%s' was expected\n", testcases[i].relPath,
+ testcases[i].maxLength, szDirNameNWD );
+ }
+ }
+ else
+ {
+ dwRetStrLength = strlen ( szAbsPath );
+
+ /* Check that the path lengths are identical. */
+ if ( dwRetStrLength != dwNewDirLength )
+ {
+ Fail ("PALSUITE ERROR: _fullpath (char *, %s, %d) test failed."
+ "\ndwRetStringLength '%d' is not equal to "
+ "dwNewDirLength '%d'.\nszAbsPath is '%s' retPath is '%s'\n"
+ "szDirNameNWD is '%s'\n" , testcases[i].relPath,
+ testcases[i].maxLength, dwRetStrLength ,dwNewDirLength
+ ,szAbsPath ,retPath ,szDirNameNWD);
+ }
+
+ /*
+ * Perform a string comparison on the path provided by
+ * GetCurrentDirectory and the path provided by _fullpath
+ * to ensure they are identical.
+ */
+ if ( 0 != strncmp( szDirNameNWD, szAbsPath, dwNewDirLength ))
+ {
+ Fail ("PALSUITE ERROR: _fullpath (char *, %s, %d) test failed."
+ "strncmp ( %s, %s, %d ) call failed.\n",
+ testcases[i].relPath, testcases[i].maxLength,
+ szDirNameNWD, szAbsPath, dwNewDirLength );
+ }
+
+ /*
+ * Perform a string comparison on both paths provided by
+ * _fullpath to ensure they are identical.
+ */
+ if ( 0 != strncmp( retPath, szAbsPath, dwNewDirLength ))
+ {
+ Fail ("PALSUITE ERROR: _fullpath (char *, %s, %d) test failed."
+ "strncmp ( %s, %s, %d ) call failed.\n",
+ testcases[i].relPath, testcases[i].maxLength,
+ szDirNameNWD, szAbsPath, dwNewDirLength );
+ }
+ }
+ }
+
+ PAL_Terminate();
+ return ( PASS );
+}
+
+
+
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/_fullpath/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_fullpath/test1/testinfo.dat
new file mode 100644
index 0000000000..cd4db831a4
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_fullpath/test1/testinfo.dat
@@ -0,0 +1,23 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = c_runtime
+Function = _fullpath
+Name = Positive Test for _fullpath
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Test to see if the _fullpath function returns the
+= proper values. A check is done to ensure NULL is returned
+= by _fullpath only for the condition where the length of the
+= created absolute path name (absPath) is greater than
+= maxLength.
+
+
+
+
+
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/_gcvt/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_gcvt/CMakeLists.txt
new file mode 100644
index 0000000000..ef14ea5352
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_gcvt/CMakeLists.txt
@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+
diff --git a/src/pal/tests/palsuite/c_runtime/_gcvt/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_gcvt/test1/CMakeLists.txt
new file mode 100644
index 0000000000..33eb5cf19c
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_gcvt/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ _gcvt.c
+)
+
+add_executable(paltest_gcvt_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_gcvt_test1 coreclrpal)
+
+target_link_libraries(paltest_gcvt_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_gcvt/test1/_gcvt.c b/src/pal/tests/palsuite/c_runtime/_gcvt/test1/_gcvt.c
new file mode 100644
index 0000000000..ccfc286898
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_gcvt/test1/_gcvt.c
@@ -0,0 +1,58 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: _gcvt.c
+**
+** Purpose: Positive test the _gcvt API.
+** Call _gcvt to convert a floatable value to a string
+** with specified sigficant digits stored
+**
+**
+**============================================================*/
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ int err;
+ double dValue = -3.1415926535;
+ char buffer[1024];
+ char *pChar7 = "-3.141593";
+
+ /*Initialize the PAL environment*/
+ err = PAL_Initialize(argc, argv);
+ if(0 != err)
+ {
+ return FAIL;
+ }
+
+
+ /* zero the buffer */
+ memset(buffer, 0, 1024);
+
+
+ /*
+
+ Testing
+ =======
+
+ To convert a floating-point value to
+ a string to save 7 significant digits
+ */
+ _gcvt(dValue, 7, buffer);
+ if(strcmp(pChar7, buffer))
+ {
+ Fail("\nFailed to call _gcvt to convert a floating-point value "
+ "to a string with 7 sigficants digits stored\n");
+ }
+
+
+ /*
+ Clean up and exit
+ */
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/_gcvt/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_gcvt/test1/testinfo.dat
new file mode 100644
index 0000000000..d527418108
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_gcvt/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _gcvt
+Name = Positive test for _gcvt API to convert a floatable value to a string
+TYPE = DEFAULT
+EXE1 = _gcvt
+Description
+=Test the _gcvt to convert a floatable value to a string
+=with specified sigficant digits stored
diff --git a/src/pal/tests/palsuite/c_runtime/_gcvt/test2/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_gcvt/test2/CMakeLists.txt
new file mode 100644
index 0000000000..05641b9b78
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_gcvt/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test2.c
+)
+
+add_executable(paltest_gcvt_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_gcvt_test2 coreclrpal)
+
+target_link_libraries(paltest_gcvt_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_gcvt/test2/test2.c b/src/pal/tests/palsuite/c_runtime/_gcvt/test2/test2.c
new file mode 100644
index 0000000000..7ac9a4fcf0
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_gcvt/test2/test2.c
@@ -0,0 +1,83 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test2.c
+**
+** Purpose: Call the _gcvt function on a number of cases. Check that it
+** handles negatives, exponents and hex digits properly. Also check that
+** the 'digit' specification works. (And that it doesn't truncate negative
+** signs or decimals)
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+struct testCase
+{
+ double Value;
+ int Digits;
+ char WinCorrectResult[128];
+ char BsdCorrectResult[128]; /* for the odd case where bsd sprintf
+ varies from windows sprintf */
+};
+
+int __cdecl main(int argc, char **argv)
+{
+ char result[128];
+ int i=0;
+
+ struct testCase testCases[] =
+ {
+ {1234567, 7, "1234567"},
+ {1234.123, 7, "1234.123"},
+ {1234.1234, 7, "1234.123"},
+ {12.325678e+2, 7, "1232.568"},
+ {-12.3233333, 8, "-12.323333"},
+ {-12.32, 8, "-12.32"},
+ {-12.32e+2, 8, "-1232.", "-1232" },
+ {0x21DDFABC, 8, "5.6819577e+008", "5.6819577e+08" },
+ {123456789012345.0, 15, "123456789012345" },
+ {12340000.0, 8, "12340000"},
+ {12340000000000000.0, 15, "1.234e+016", "1.234e+16" },
+ {12340000000000000.0, 17, "12340000000000000" },
+
+ };
+
+ if (0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /* Loop through each case. Call _gcvt on each test case and check the
+ result.
+ */
+
+ for(i = 0; i < sizeof(testCases) / sizeof(struct testCase); i++)
+ {
+ _gcvt(testCases[i].Value, testCases[i].Digits, result);
+
+ if (strcmp(testCases[i].WinCorrectResult, result) != 0 &&
+
+ ( testCases[i].BsdCorrectResult &&
+ strcmp(testCases[i].BsdCorrectResult, result) != 0 ) )
+ {
+ Fail("ERROR: _gcvt attempted to convert %f with %d digits "
+ "signifigant, which resulted in "
+ "the string '%s' instead of the correct(Win) string '%s' or the"
+ "correct(bsd) string '%s'.\n",
+ testCases[i].Value,
+ testCases[i].Digits,
+ result,
+ testCases[i].WinCorrectResult,
+ testCases[i].BsdCorrectResult);
+ }
+
+ memset(result, '\0', 128);
+ }
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/_gcvt/test2/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_gcvt/test2/testinfo.dat
new file mode 100644
index 0000000000..e9e192849a
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_gcvt/test2/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _gcvt
+Name = Call _gcvt on normal values, negatives, exponents and hex digits.
+TYPE = DEFAULT
+EXE1 = test2
+Description
+= Call the _gcvt function on a number of cases. Check that it
+= handles negatives, exponents and hex digits properly. Also check that
+= the 'digit' specification works. (And that it doesn't truncate negative
+= signs or decimals)
diff --git a/src/pal/tests/palsuite/c_runtime/_getw/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_getw/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_getw/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/_getw/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_getw/test1/CMakeLists.txt
new file mode 100644
index 0000000000..d44477b232
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_getw/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_getw_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getw_test1 coreclrpal)
+
+target_link_libraries(paltest_getw_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_getw/test1/test.dat b/src/pal/tests/palsuite/c_runtime/_getw/test1/test.dat
new file mode 100644
index 0000000000..b20eae054c
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_getw/test1/test.dat
Binary files differ
diff --git a/src/pal/tests/palsuite/c_runtime/_getw/test1/test1.c b/src/pal/tests/palsuite/c_runtime/_getw/test1/test1.c
new file mode 100644
index 0000000000..34ce4ee7de
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_getw/test1/test1.c
@@ -0,0 +1,96 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Several integers are read from a previously written file
+** using _getw. The test passes if the values read match those known to
+** be in the file.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+
+/*Tests _getw using a previously written data file */
+int __cdecl main(int argc, char **argv)
+{
+ const int testValues[] =
+ {
+ 0,
+ 1,
+ -1,
+ 0x7FFFFFFF, /* largest positive integer on 32 bit systems */
+ 0x80000000, /* largest negative integer on 32 bit systems */
+ 0xFFFFFFFF,
+ 0xFFFFAAAA
+ };
+
+ int i = 0;
+ int input = 0;
+
+ const char filename[] = "test.dat";
+
+
+ FILE *fp = NULL;
+
+ /*
+ * Initialize the PAL and return FAIL if this fails
+ */
+ if (0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /* write the file that we will use to test */
+
+
+ /*
+ Don't uncomment this code, it was used to create the data file
+ initially on windows, but if it is run on all test platforms, the
+ tests will always pass.
+
+ fp = fopen(filename, "w");
+ if (fp == NULL)
+ {
+ Fail("Unable to open file for write.\n");
+ }
+ for (i = 0; i < sizeof(testValues) / sizeof(testValues[0]); i++)
+ {
+ _putw(testValues[i], fp);
+ }
+
+ if (fclose(fp) != 0)
+ {
+ Fail("Error closing file after writing to it with _putw.\n");
+ }
+ */
+
+
+ /*Now read values back from the file and see if they match.*/
+ fp = fopen(filename, "r");
+ if (fp == NULL)
+ {
+ Fail ("Unable to open file for read.\n");
+ }
+ for (i = 0; i < sizeof(testValues) / sizeof(testValues[0]); i++)
+ {
+ input = _getw(fp);
+ if (VAL32(input) != testValues[i])
+ {
+ Fail ("_getw did not get the expected values when reading "
+ "from a file.\n");
+ }
+ }
+
+ if (fclose(fp) != 0)
+ {
+ Fail ("Error closing file after reading from it with _getw\n");
+ }
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/_getw/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_getw/test1/testinfo.dat
new file mode 100644
index 0000000000..4044dadbcc
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_getw/test1/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _getw
+Name = Positive Test for _getw
+TYPE = DEFAULT
+EXE1 = test1
+Description
+=Several integers are read from a previously written file
+=using _getw. The test passes if the values read match those known to
+=be in the file.
+
diff --git a/src/pal/tests/palsuite/c_runtime/_isnan/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_isnan/CMakeLists.txt
new file mode 100644
index 0000000000..5e1ef7f28b
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_isnan/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
diff --git a/src/pal/tests/palsuite/c_runtime/_isnan/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_isnan/test1/CMakeLists.txt
new file mode 100644
index 0000000000..e14d0cc64b
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_isnan/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_isnan_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_isnan_test1 coreclrpal)
+
+target_link_libraries(paltest_isnan_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_isnan/test1/test1.c b/src/pal/tests/palsuite/c_runtime/_isnan/test1/test1.c
new file mode 100644
index 0000000000..d793c9b371
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_isnan/test1/test1.c
@@ -0,0 +1,115 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose:
+** Test _isnan with a number of trivial values, to ensure they indicated that
+** they are numbers. Then try with Positive/Negative Infinite, which should
+** also be numbers. Finally set the least and most significant bits of
+** the fraction to positive and negative, at which point it should return
+** the true value.
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+
+#define TO_DOUBLE(x) (*((double*)((void*)&x)))
+#define TO_I64(x) (*((INT64*)((void*)&x)))
+
+/*
+ * NaN: any double with maximum exponent (0x7ff) and non-zero fraction
+ */
+int __cdecl main(int argc, char *argv[])
+{
+ /*
+ * Initialize the PAL and return FAIL if this fails
+ */
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+ /*
+ * Try some trivial values
+ */
+ if (_isnan(0.0))
+ {
+ Fail("_isnan() incorrectly identified %f as NaN!\n", 0.0);
+ }
+
+ if (_isnan(1.23456))
+ {
+ Fail("_isnan() incorrectly identified %f as NaN!\n", 1.234567);
+ }
+
+ if (_isnan(42.0))
+ {
+ Fail("_isnan() incorrectly identified %f as NaN!\n", 42.0);
+ }
+
+ UINT64 lneginf = UI64(0xfff0000000000000);
+ UINT64 lposinf = UI64(0x7ff0000000000000);
+
+ double neginf = TO_DOUBLE(lneginf);
+ double posinf = TO_DOUBLE(lposinf);
+
+ /*
+ * Try positive and negative infinity
+ */
+ if (_isnan(neginf))
+ {
+ Fail("_isnan() incorrectly identified negative infinity as NaN!\n");
+ }
+
+ if (_isnan(posinf))
+ {
+ Fail("_isnan() incorrectly identified infinity as NaN!\n");
+ }
+
+ /*
+ * Try setting the least significant bit of the fraction,
+ * positive and negative
+ */
+ UINT64 lsnan = UI64(0xfff0000000000001);
+ double snan = TO_DOUBLE(lsnan);
+
+ if (!_isnan(snan))
+ {
+ Fail("_isnan() failed to identify %I64x as NaN!\n", lsnan);
+ }
+
+ UINT64 lqnan = UI64(0x7ff0000000000001);
+ double qnan = TO_DOUBLE(lqnan);
+
+ if (!_isnan(qnan))
+ {
+ Fail("_isnan() failed to identify %I64x as NaN!\n", lqnan);
+ }
+
+ /*
+ * Try setting the most significant bit of the fraction,
+ * positive and negative
+ */
+ lsnan = UI64(0xfff8000000000000);
+ snan = TO_DOUBLE(lsnan);
+
+ if (!_isnan(snan))
+ {
+ Fail ("_isnan() failed to identify %I64x as NaN!\n", lsnan);
+ }
+
+ lqnan = UI64(0x7ff8000000000000);
+ qnan = TO_DOUBLE(lqnan);
+
+ if (!_isnan(qnan))
+ {
+ Fail ("_isnan() failed to identify %I64x as NaN!\n", lqnan);
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/_isnan/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_isnan/test1/testinfo.dat
new file mode 100644
index 0000000000..d5de17e219
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_isnan/test1/testinfo.dat
@@ -0,0 +1,16 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _isnan
+Name = Test #1 for _isnan
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Test _isnan with a number of trivial values, to ensure they indicated that
+= they are numbers. Then try with Positive/Negative Infinite, which should
+= also be numbers. Finally set the least and most significant bits of
+= the fraction to positive and negative, at which point it should return
+= the true value.
diff --git a/src/pal/tests/palsuite/c_runtime/_itow/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_itow/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_itow/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/_itow/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_itow/test1/CMakeLists.txt
new file mode 100644
index 0000000000..bd37f31216
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_itow/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_itow_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_itow_test1 coreclrpal)
+
+target_link_libraries(paltest_itow_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_itow/test1/test1.c b/src/pal/tests/palsuite/c_runtime/_itow/test1/test1.c
new file mode 100644
index 0000000000..745ce4acaa
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_itow/test1/test1.c
@@ -0,0 +1,102 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test1.c
+**
+** Purpose: Tests the PAL implementation of the _itow function.
+** Test a number of ints with different radix on each,
+** to ensure that the string returned is correct.
+**
+**
+**===================================================================*/
+
+#define UNICODE
+
+#include <palsuite.h>
+
+struct testCase
+{
+ wchar_t *CorrectResult;
+ int value;
+ int radix;
+};
+
+int __cdecl main(int argc, char **argv)
+{
+
+ wchar_t result[20];
+ wchar_t *pResult = NULL;
+ char *PrintResult = NULL; /* Use with convertC so we can */
+ char *PrintCorrectResult = NULL; /* print out the results */
+ int i = 0;
+
+ WCHAR case1[] = {'5','0','\0'};
+ WCHAR case2[] = {'5','5','5','\0'};
+ WCHAR case3[] = {'1','0','1','0','\0'};
+ WCHAR case4[] = {'2','2','\0'};
+ WCHAR case5[] = {'a','\0'};
+ WCHAR case6[] = {'c','g','\0'};
+
+ /* Correct Result, Value to Convert, Radix to use */
+ struct testCase testCases[] =
+ {
+ {case1, 50, 10},
+ {case2,555,10},
+ {case3,10,2},
+ {case4,10,4},
+ {case5,10,16},
+ {case6,400,32}
+ };
+
+ /*
+ * Initialize the PAL and return FAIL if this fails
+ */
+ if (0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /* Loop through each case. Convert the ints to strings. Check
+ to ensure they were converted properly.
+ */
+
+ for(i = 0; i < sizeof(testCases) / sizeof(struct testCase); i++)
+ {
+ pResult = _itow(testCases[i].value,result,testCases[i].radix);
+
+ if(pResult != &result[0])
+ {
+ Fail("ERROR: _itow didn't return a correct pointer to the "
+ "newly formed string.\n");
+ }
+
+ if (0 != wcscmp(testCases[i].CorrectResult,pResult))
+ {
+ PrintResult = convertC(pResult);
+ PrintCorrectResult = convertC(testCases[i].CorrectResult);
+ Fail("ERROR: _itow was called on %i, returning the string %s "
+ "when it should have returned the string %s.\n"
+ , testCases[i].value, PrintResult, PrintCorrectResult);
+ }
+
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/_itow/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_itow/test1/testinfo.dat
new file mode 100644
index 0000000000..394c34dff3
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_itow/test1/testinfo.dat
@@ -0,0 +1,18 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _itow
+Name = Positive Test for _itow
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Tests the PAL implementation of the _itow function.
+= Test a number of ints with different radix on each, to ensure that the
+= string returned is correct.
+
+
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/_makepath/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_makepath/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_makepath/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/_makepath/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_makepath/test1/CMakeLists.txt
new file mode 100644
index 0000000000..9fd81cce1a
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_makepath/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_makepath_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_makepath_test1 coreclrpal)
+
+target_link_libraries(paltest_makepath_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_makepath/test1/test1.c b/src/pal/tests/palsuite/c_runtime/_makepath/test1/test1.c
new file mode 100644
index 0000000000..94b366a7bb
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_makepath/test1/test1.c
@@ -0,0 +1,65 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test1.c
+**
+** Purpose: Tests the PAL implementation of the _makepath function.
+** Create a path, and ensure that it builds how it is
+** supposed to.
+**
+**
+**
+**===================================================================*/
+
+#if WIN32
+#define PATHNAME "C:\\test\\test.txt"
+#else
+#define PATHNAME "/test/test.txt"
+#endif
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char **argv)
+{
+ char FullPath[128];
+
+ /*
+ * Initialize the PAL and return FAIL if this fails
+ */
+ if (0 != (PAL_Initialize(argc,argv)))
+ {
+ return FAIL;
+ }
+
+#if WIN32
+ _makepath(FullPath,"C","\\test","test","txt");
+#else
+ _makepath(FullPath,NULL,"/test","test","txt");
+#endif
+
+ if(strcmp(FullPath,PATHNAME) != 0)
+ {
+ Fail("ERROR: The pathname which was created turned out to be %s "
+ "when it was supposed to be %s.\n",FullPath,PATHNAME);
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/_makepath/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_makepath/test1/testinfo.dat
new file mode 100644
index 0000000000..2aed8e549b
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_makepath/test1/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _makepath
+Name = Positive Test for _makepath
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Purpose: Tests the PAL implementation of the _makepath function.
+= Create a path, and ensure that it builds how it is supposed to.
+
diff --git a/src/pal/tests/palsuite/c_runtime/_mbsdec/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_mbsdec/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_mbsdec/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/_mbsdec/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_mbsdec/test1/CMakeLists.txt
new file mode 100644
index 0000000000..064f241f24
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_mbsdec/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_mbsdec_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_mbsdec_test1 coreclrpal)
+
+target_link_libraries(paltest_mbsdec_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_mbsdec/test1/test1.c b/src/pal/tests/palsuite/c_runtime/_mbsdec/test1/test1.c
new file mode 100644
index 0000000000..1cd7513293
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_mbsdec/test1/test1.c
@@ -0,0 +1,77 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose:
+** Ensure that this function moves the string pointer back one character.
+** First do a basic test to check that the pointer gets moved back the one
+** character, given str1 and str+1 as params. Then try with both
+** params being the same pointer, which should return NULL. Also test
+** when the first pointer is past the second pointer, which should
+** return null. Finally try this function on an array of single bytes,
+** which it assumes are characters and should work in the same fashion.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+
+/*
+ * Note: it seems like these functions would only be useful if they
+ * didn't assume a character was equivalent to a single byte. Be that
+ * as it may, I haven't seen a way to get it to behave otherwise.
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ unsigned char *str1 = (unsigned char*) "foo";
+ unsigned char str2[] = {0xC0, 0x80, 0xC0, 0x80, 0};
+ unsigned char str3[] = {0};
+ unsigned char *ret = NULL;
+
+ /*
+ * Initialize the PAL and return FAIL if this fails
+ */
+ if (0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ ret = _mbsdec(str1,str1+1);
+ if (ret != str1)
+ {
+ Fail ("ERROR: _mbsdec returned %p. Expected %p\n", ret, str1);
+ }
+
+ ret = _mbsdec(str1,str1);
+ if (ret != NULL)
+ {
+ Fail ("ERROR: _mbsdec returned %p. Expected %p\n", ret, NULL);
+ }
+
+ ret = _mbsdec(str1+100,str1);
+ if (ret != NULL)
+ {
+ Fail ("ERROR: _mbsdec returned %p. Expected %p\n", ret, NULL);
+ }
+
+ ret = _mbsdec(str2,str2+1);
+ if (ret != str2)
+ {
+ Fail ("ERROR: _mbsdec returned %p. Expected %p\n", ret, str2+1);
+ }
+
+ ret = _mbsdec(str3,str3+10);
+ if (ret != str3+9)
+ {
+ Fail ("ERROR: _mbsdec returned %p. Expected %p\n", ret, str3+9);
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/_mbsdec/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_mbsdec/test1/testinfo.dat
new file mode 100644
index 0000000000..ce2aa29aa5
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_mbsdec/test1/testinfo.dat
@@ -0,0 +1,18 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _mbsdec
+Name = Positive Test for _mbsdec
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Ensure that this function moves the string pointer back one character.
+= First do a basic test to check that the pointer gets moved back the one
+= character, given str1 and str+1 as params. Then try with both
+= params being the same pointer, which should return NULL. Also test
+= when the first pointer is past the second pointer, which should
+= return null. Finally try this function on an array of single bytes,
+= which it assumes are characters and should work in the same fashion.
diff --git a/src/pal/tests/palsuite/c_runtime/_mbsinc/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_mbsinc/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_mbsinc/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/_mbsinc/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_mbsinc/test1/CMakeLists.txt
new file mode 100644
index 0000000000..531ba8e793
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_mbsinc/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_mbsinc_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_mbsinc_test1 coreclrpal)
+
+target_link_libraries(paltest_mbsinc_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_mbsinc/test1/test1.c b/src/pal/tests/palsuite/c_runtime/_mbsinc/test1/test1.c
new file mode 100644
index 0000000000..95a5041af2
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_mbsinc/test1/test1.c
@@ -0,0 +1,62 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose:
+** Ensure that this function moves the string pointer ahead one character.
+** First do a basic test to check that the pointer gets moved ahead the one
+** character. Then try with an array of bytes and a NULL array. Each of
+** these should still work by returning a pointer to thePointer+1.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+
+/*
+ * Note: it seems like these functions would only be useful if they
+ * didn't assume a character was equivalent to a single byte. Be that
+ * as it may, I haven't seen a way to get it to behave otherwise.
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ unsigned char *str1 = (unsigned char*) "foo";
+ unsigned char str2[] = {0xC0, 0x80, 0xC0, 0x80, 0};
+ unsigned char str3[] = {0};
+ unsigned char *ret=NULL;
+
+ /*
+ * Initialize the PAL and return FAIL if this fails
+ */
+ if (0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ ret = _mbsinc(str1);
+ if (ret != str1 + 1)
+ {
+ Fail ("ERROR: _mbsinc returned %p. Expected %p\n", ret, str1);
+ }
+
+ ret = _mbsinc(str2);
+ if (ret != str2 + 1)
+ {
+ Fail ("ERROR: _mbsinc returned %p. Expected %p\n", ret, str1);
+ }
+
+ ret = _mbsinc(str3);
+ if (ret != str3 + 1)
+ {
+ Fail ("ERROR: _mbsinc returned %p. Expected %p\n", ret, str1);
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/_mbsinc/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_mbsinc/test1/testinfo.dat
new file mode 100644
index 0000000000..3f3883fa31
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_mbsinc/test1/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _mbsinc
+Name = Positive Test for _mbsinc
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Ensure that this function moves the string pointer ahead one character.
+= First do a basic test to check that the pointer gets moved ahead the one
+= character. Then try with an array of bytes and a NULL array. Each of
+= these should still work by returning a pointer to thePointer+1.
diff --git a/src/pal/tests/palsuite/c_runtime/_mbslen/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_mbslen/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_mbslen/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/_mbslen/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_mbslen/test1/CMakeLists.txt
new file mode 100644
index 0000000000..38aa6fb16e
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_mbslen/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_mbslen_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_mbslen_test1 coreclrpal)
+
+target_link_libraries(paltest_mbslen_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_mbslen/test1/test1.c b/src/pal/tests/palsuite/c_runtime/_mbslen/test1/test1.c
new file mode 100644
index 0000000000..fa24c77d8a
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_mbslen/test1/test1.c
@@ -0,0 +1,66 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*========================================================================
+**
+** Source: test1.c
+**
+** Purpose:
+** Check the length of a number of arrays. The first is a normal string
+** which should return its length. The second has two bytes and a null
+** character, which only returns a size of 2, and the last is just a NULL
+** array which should return 0.
+**
+**
+**========================================================================*/
+
+#include <palsuite.h>
+
+/*
+ * Note: it seems like these functions would only be useful if they
+ * didn't assume a character was equivalent to a single byte. Be that
+ * as it may, I haven't seen a way to get it to behave otherwise
+ * (eg locale)
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ unsigned char *str1 = (unsigned char*) "foo";
+ unsigned char str2[] = {0xC0, 0x80, 0}; /* the char U+0080 */
+ unsigned char str3[] = {0};
+ int ret=0;
+
+ /*
+ * Initialize the PAL and return FAIL if this fails
+ */
+ if (0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ ret = _mbslen(str1);
+ if (ret != 3)
+ {
+ Fail ("ERROR: _mbslen(\"%s\") returned %d. Expected %d\n",
+ str1, ret, 3);
+ }
+
+ ret = _mbslen(str2);
+ if (ret != 2)
+ {
+ Fail ("ERROR: _mbslen(\"%s\") returned %d. Expected %d\n",
+ str2, ret, 2);
+ }
+
+ ret = _mbslen(str3);
+ if (ret != 0)
+ {
+ Fail ("ERROR: _mbslen(\"%s\") returned %d. Expected %d\n",
+ str3, ret, 0);
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/_mbslen/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_mbslen/test1/testinfo.dat
new file mode 100644
index 0000000000..cf830a7539
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_mbslen/test1/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _mbsinc
+Name = Positive Test for _mbslen
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Check the length of a number of arrays. The first is a normal string
+= which should return its length. The second has two bytes and a null
+= character, which only returns a size of 2, and the last is just a NULL
+= array which should return 0.
diff --git a/src/pal/tests/palsuite/c_runtime/_mbsninc/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_mbsninc/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_mbsninc/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/_mbsninc/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_mbsninc/test1/CMakeLists.txt
new file mode 100644
index 0000000000..7285ce229e
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_mbsninc/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_mbsninc_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_mbsninc_test1 coreclrpal)
+
+target_link_libraries(paltest_mbsninc_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_mbsninc/test1/test1.c b/src/pal/tests/palsuite/c_runtime/_mbsninc/test1/test1.c
new file mode 100644
index 0000000000..59ef50dcc3
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_mbsninc/test1/test1.c
@@ -0,0 +1,65 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose:
+** Ensure that this functions increases a string pointer by n characters.
+** Use a for loop, and increase the pointer by a different number of characters
+** on each iteration, ensure that it is indeed pointing to the correct location
+** each time. The second test checks to see if you attempt to increase the
+** pointer past the end of the string, the pointer should just point at the
+** last character.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+
+/*
+ * Note: it seems like these functions would only be useful if they
+ * didn't assume a character was equivalent to a single byte. Be that
+ * as it may, I haven't seen a way to get it to behave otherwise.
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ unsigned char str[] = {0xC0, 0x80, 0xC0, 0x80, 0};
+ int i=0;
+ unsigned char *ret=NULL;
+
+ /*
+ * Initialize the PAL and return FAIL if this fails
+ */
+ if (0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ for (i=0; i<5; i++)
+ {
+ ret = _mbsninc(str, i);
+ if (ret != str + i)
+ {
+ Fail ("ERROR: _mbsninc returned %p. Expected %p\n", ret, str+i);
+ }
+ }
+
+ /*
+ * trying to advance past the end of the string should just
+ * return the end.
+ */
+ ret = _mbsninc(str, 5);
+ if (ret != str + 4)
+ {
+ Fail ("ERROR: _mbsninc returned %p. Expected %p\n", ret, str+4);
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/_mbsninc/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_mbsninc/test1/testinfo.dat
new file mode 100644
index 0000000000..b855222af9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_mbsninc/test1/testinfo.dat
@@ -0,0 +1,17 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _mbsninc
+Name = Positive Test for _mbsninc
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Ensure that this functions increases a string pointer by n characters.
+= Use a for loop, and increase the pointer by a different number of characters
+= on each iteration, ensure that it is indeed pointing to the correct location
+= each time. The second test checks to see if you attempt to increase the
+= pointer past the end of the string, the pointer should just point at the
+= last character.
diff --git a/src/pal/tests/palsuite/c_runtime/_open_osfhandle/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_open_osfhandle/CMakeLists.txt
new file mode 100644
index 0000000000..ef14ea5352
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_open_osfhandle/CMakeLists.txt
@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+
diff --git a/src/pal/tests/palsuite/c_runtime/_open_osfhandle/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_open_osfhandle/test1/CMakeLists.txt
new file mode 100644
index 0000000000..e9a3e29192
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_open_osfhandle/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_open_osfhandle_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_open_osfhandle_test1 coreclrpal)
+
+target_link_libraries(paltest_open_osfhandle_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_open_osfhandle/test1/test1.c b/src/pal/tests/palsuite/c_runtime/_open_osfhandle/test1/test1.c
new file mode 100644
index 0000000000..ee2c8ea418
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_open_osfhandle/test1/test1.c
@@ -0,0 +1,132 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test1.c (_open_osfhandle)
+**
+** Purpose: Tests the PAL implementation of the _open_osfhandle function.
+** This API accepts a OS Handle returned from CreatePipe() and
+** a flag of _O_RDONLY and returns a C Run-Time handle. The test
+** will write to the pipe and pass the C Run-Time handle to _fdopen
+** to open the Read Handle to compare what was written with what
+** was wrote. They should be the same.
+**
+** Depends: CreatePipe
+** WriteFile
+** _fdopen
+** fread
+** memcmp
+** fclose
+** strlen
+** CloseHandle
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+const char* cTestString = "one fish, two fish, red fish, blue fish.";
+
+int __cdecl main(int argc, char **argv)
+{
+ HANDLE hReadPipe = NULL;
+ HANDLE hWritePipe = NULL;
+ BOOL bRetVal = FALSE;
+ int iFiledes = 0;
+ DWORD dwBytesWritten;
+ char buffer[45];
+ FILE *fp;
+ size_t len;
+
+ SECURITY_ATTRIBUTES lpPipeAttributes;
+
+ /*Initialize the PAL*/
+ if ((PAL_Initialize(argc, argv)) != 0)
+ {
+ return (FAIL);
+ }
+
+ /*Setup SECURITY_ATTRIBUTES structure for CreatePipe*/
+ lpPipeAttributes.nLength = sizeof(lpPipeAttributes);
+ lpPipeAttributes.lpSecurityDescriptor = NULL;
+ lpPipeAttributes.bInheritHandle = TRUE;
+
+ /*Create a Pipe*/
+ bRetVal = CreatePipe(&hReadPipe, /* read handle*/
+ &hWritePipe, /* write handle */
+ &lpPipeAttributes, /* security attributes*/
+ 0); /* pipe size*/
+ if (bRetVal == FALSE)
+ {
+ Fail("ERROR: unable to create pipe");
+ }
+
+ /*Write to the write pipe handle*/
+ bRetVal = WriteFile(hWritePipe, /* handle to file*/
+ cTestString, /* data buffer*/
+ strlen(cTestString),/* number of bytes to write*/
+ &dwBytesWritten, /* number of bytes written*/
+ NULL); /* overlapped buffer*/
+ if (bRetVal == FALSE)
+ {
+ Fail("ERROR: unable to write to pipe write handle "
+ "hWritePipe=0x%lx", hWritePipe);
+ }
+
+ /*Test to see if the WriteFile wrote the correct amount*/
+ if(dwBytesWritten != strlen(cTestString))
+ {
+ Fail("Error: WriteFile wrote \"%d\", should have written \"%d\\n",
+ dwBytesWritten, strlen(cTestString));
+ }
+
+ /*Get a file descriptor for the read pipe handle.
+ *This is what we are testing.*/
+ iFiledes = _open_osfhandle((long)hReadPipe, _O_RDONLY);
+ if (iFiledes == -1)
+ {
+ Fail("ERROR: _open_osfhandle failed to open "
+ " hReadPipe=0x%lx", hReadPipe);
+ }
+
+ /*Open read pipe handle in read mode.
+ *Verify that we have returned a correct,
+ *C Run-time handle*/
+ fp = _fdopen(iFiledes, "r");
+ if (fp == NULL)
+ {
+ Fail("ERROR: unable to fdopen file descriptor"
+ " iFiledes=%d", iFiledes);
+ }
+
+ /*Read from the read pipe handle*/
+ len = fread(buffer, sizeof(char), strlen(cTestString), fp);
+ if((len == 0) || (len != strlen(cTestString)))
+ {
+ Fail("ERROR: Unable to read from file stream fp=0x%lx\n", fp);
+ }
+
+ /*Compare what was read with what was written.*/
+ if ((memcmp(cTestString, buffer, strlen(cTestString))) != 0)
+ {
+ Fail("ERROR: read \"%s\" expected \"%s\" \n", buffer, cTestString);
+ }
+
+ /*Close write pipe handle*/
+ if (CloseHandle(hWritePipe) == 0)
+ {
+ Fail("ERROR: Unable to close write pipe handle "
+ "hWritePipe=0x%lx", hWritePipe);
+ }
+
+ if ((fclose(fp)) != 0)
+ {
+ Fail("ERROR: Unable to close C-Runtime handle "
+ "iFilesdes=%d", iFiledes);
+ }
+
+ PAL_Terminate();
+ return (PASS);
+}
diff --git a/src/pal/tests/palsuite/c_runtime/_open_osfhandle/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_open_osfhandle/test1/testinfo.dat
new file mode 100644
index 0000000000..16317bb188
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_open_osfhandle/test1/testinfo.dat
@@ -0,0 +1,17 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _open_osfhandle
+Name = Test for _open_osfhandle
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Tests the PAL implementation of the _open_osfhandle function.
+= This API accepts a OS Handle returned from CreatePipe() and
+= a flag of _O_RDONLY and returns a C Run-Time handle. The test
+= will write to the pipe and pass the C Run-Time handle to _fdopen
+= to open the Read Handle to compare what was written with what
+= was wrote. They should be the same.
diff --git a/src/pal/tests/palsuite/c_runtime/_open_osfhandle/test2/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_open_osfhandle/test2/CMakeLists.txt
new file mode 100644
index 0000000000..1031ec1df9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_open_osfhandle/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test2.c
+)
+
+add_executable(paltest_open_osfhandle_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_open_osfhandle_test2 coreclrpal)
+
+target_link_libraries(paltest_open_osfhandle_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_open_osfhandle/test2/test2.c b/src/pal/tests/palsuite/c_runtime/_open_osfhandle/test2/test2.c
new file mode 100644
index 0000000000..6c756b177a
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_open_osfhandle/test2/test2.c
@@ -0,0 +1,86 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test2.c (_open_osfhandle)
+**
+** Purpose: Tests the PAL implementation of the _open_osfhandle function.
+** This API accepts a OS Handle returned from CreatePipe() and
+** a flag of _O_RDONLY and returns a C Run-Time handle. The test
+** will pass a NULL handle, and unsupported flags. All cases
+** should fail.
+**
+** Depends: CreatePipe
+** CloseHandle
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char **argv)
+{
+ HANDLE hReadPipe = NULL;
+ HANDLE hWritePipe = NULL;
+ BOOL bRetVal = FALSE;
+ int iFiledes = 0;
+
+ SECURITY_ATTRIBUTES lpPipeAttributes;
+
+ /*Initialize the PAL*/
+ if ((PAL_Initialize(argc, argv)) != 0)
+ {
+ return (FAIL);
+ }
+
+ /*Setup SECURITY_ATTRIBUTES structure for CreatePipe*/
+ lpPipeAttributes.nLength = sizeof(lpPipeAttributes);
+ lpPipeAttributes.lpSecurityDescriptor = NULL;
+ lpPipeAttributes.bInheritHandle = TRUE;
+
+ /*Create a Pipe*/
+ bRetVal = CreatePipe(&hReadPipe, /* read handle*/
+ &hWritePipe, /* write handle */
+ &lpPipeAttributes, /* security attributes*/
+ 0); /* pipe size*/
+ if (bRetVal == FALSE)
+ {
+ Fail("ERROR: unable to create pipe");
+ }
+
+ /*Close write pipe handle*/
+ if (CloseHandle(hWritePipe) == 0)
+ {
+ Fail("ERROR: Unable to close write pipe handle "
+ "hWritePipe=0x%lx", hWritePipe);
+ }
+
+ /*Close read pipe handle*/
+ if (CloseHandle(hReadPipe) == 0)
+ {
+ Fail("ERROR: Unable to close read pipe handle "
+ "hReadPipe=0x%lx", hReadPipe);
+ }
+
+ /*Test with a Closed handle and supported flag _O_RDONLY*/
+ iFiledes = _open_osfhandle((long)hReadPipe, _O_RDONLY);
+ if (iFiledes != -1)
+ {
+ Fail("ERROR: _open_osfhandle successfullly opened "
+ " hReadPipe which was closed, with _O_RDONLY");
+ }
+
+ /*Test with a NULL handle and supported flag _O_RDONLY*/
+ hReadPipe = NULL;
+ iFiledes = _open_osfhandle((long)hReadPipe, _O_RDONLY);
+ if (iFiledes != -1)
+ {
+ Fail("ERROR: _open_osfhandle successfullly opened "
+ " hReadPipe=NULL with _O_RDONLY");
+ }
+
+ PAL_Terminate();
+ return (PASS);
+}
diff --git a/src/pal/tests/palsuite/c_runtime/_open_osfhandle/test2/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_open_osfhandle/test2/testinfo.dat
new file mode 100644
index 0000000000..822e23fedd
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_open_osfhandle/test2/testinfo.dat
@@ -0,0 +1,16 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _open_osfhandle
+Name = Fail test for _open_osfhandle
+TYPE = DEFAULT
+EXE1 = test2
+Description
+= Tests the PAL implementation of the _open_osfhandle function.
+= This API accepts a OS Handle returned from CreatePipe() and
+= a flag of _O_RDONLY and returns a C Run-Time handle. The test
+= will pass a NULL handle, and unsupported flags. All cases
+= should fail.
diff --git a/src/pal/tests/palsuite/c_runtime/_putenv/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_putenv/CMakeLists.txt
new file mode 100644
index 0000000000..a3847f8ca9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_putenv/CMakeLists.txt
@@ -0,0 +1,7 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+add_subdirectory(test3)
+add_subdirectory(test4)
+
diff --git a/src/pal/tests/palsuite/c_runtime/_putenv/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_putenv/test1/CMakeLists.txt
new file mode 100644
index 0000000000..0a75b41113
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_putenv/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_putenv_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_putenv_test1 coreclrpal)
+
+target_link_libraries(paltest_putenv_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_putenv/test1/test1.c b/src/pal/tests/palsuite/c_runtime/_putenv/test1/test1.c
new file mode 100644
index 0000000000..2d096adc78
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_putenv/test1/test1.c
@@ -0,0 +1,99 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test1.c
+**
+** Purpose: Create an environment variable with _putenv and then use getenv
+** to check it. Check that we get the expected errors with invalid input.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+struct TestElement
+{
+ char _putenvString[1024]; /* argument string sent to putenv */
+ char varName[1024]; /* variable component of argument string */
+ char varValue[1024]; /* value component of argument string */
+ BOOL bValidString; /* valid argument string identifier */
+};
+
+struct TestElement TestCases[] =
+{
+ {"PalTestingEnvironmentVariable=A value", "PalTestingEnvironmentVariable",
+ "A value", TRUE},
+ {"AnotherVariable=", "AnotherVariable", "", TRUE},
+ {"YetAnotherVariable", "", "", FALSE},
+ {"=ADifferentVariable", "", "ADifferentVariable", FALSE},
+ {"", "", "", FALSE}
+
+};
+
+int __cdecl main(int argc, char **argv)
+{
+
+ int i;
+ char *variableValue;
+
+ if (0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ for (i = 0; i < (sizeof(TestCases)/sizeof(struct TestElement)) ; i++)
+ {
+ if((_putenv(TestCases[i]._putenvString) == -1) &&
+ ( TestCases[i].bValidString == TRUE))
+ {
+ Fail("ERROR: _putenv failed to set an environment "
+ "variable with a valid format.\n Call was"
+ "_putenv(%s)\n", TestCases[i]._putenvString);
+ }
+ /*
+ * For valid _putenvString values, check to see the variable was set
+ */
+ if (TestCases[i].bValidString == TRUE)
+ {
+ variableValue = getenv(TestCases[i].varName);
+
+ if (variableValue == NULL)
+ {
+ if (*TestCases[i].varValue != '\0')
+ {
+ Fail("ERROR: getenv(%s) call returned NULL.\nThe call "
+ "should have returned \"%s\"\n", TestCases[i].varName
+ , TestCases[i].varValue);
+ }
+ }
+ else if ( strcmp(variableValue, TestCases[i].varValue) != 0)
+ {
+ Fail("ERROR: _putenv(%s)\nshould have set the variable "
+ "%s\n to \"%s\".\nA subsequent call to getenv(%s)\n"
+ "returned \"%s\" instead.\n", TestCases[i]._putenvString
+ , TestCases[i].varName, TestCases[i].varValue
+ , TestCases[i].varName, variableValue);
+ }
+ }
+ else
+ /*
+ * Check to see that putenv fails for malformed _putenvString values
+ */
+ {
+ variableValue = getenv(TestCases[i].varName);
+
+ if (variableValue != NULL)
+ {
+ Fail("ERROR: getenv(%s) call should have returned NULL.\n"
+ "Instead it returned \"%s\".\n", TestCases[i].varName
+ , TestCases[i].varValue);
+ }
+ }
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/_putenv/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_putenv/test1/testinfo.dat
new file mode 100644
index 0000000000..d0978184fc
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_putenv/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _putenv
+Name = Positive test for _putenv
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Create an environment variable with _putenv and then use getenv to
+= check it. Check that we get the expected errors with invalid input.
diff --git a/src/pal/tests/palsuite/c_runtime/_putenv/test2/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_putenv/test2/CMakeLists.txt
new file mode 100644
index 0000000000..e0539681cd
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_putenv/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test2.c
+)
+
+add_executable(paltest_putenv_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_putenv_test2 coreclrpal)
+
+target_link_libraries(paltest_putenv_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_putenv/test2/test2.c b/src/pal/tests/palsuite/c_runtime/_putenv/test2/test2.c
new file mode 100644
index 0000000000..39be4f68b4
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_putenv/test2/test2.c
@@ -0,0 +1,76 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test2.c
+**
+** Purpose: Create an environment variable with _putenv and then use getenv
+** to check it. This test resets an environment variable.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+const char *_putenvString0 = "AnUnusualVariable=AnUnusualValue";
+const char *_putenvString1 = "AnUnusualVariable=";
+const char *variable = "AnUnusualVariable";
+const char *value = "AnUnusualValue";
+
+int __cdecl main(int argc, char **argv)
+{
+
+ char *variableValue;
+
+ if (0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ if(_putenv(_putenvString0) == -1)
+ {
+ Fail("ERROR: _putenv failed to set an environment "
+ "variable with a valid format.\n Call was"
+ "_putenv(%s)\n", _putenvString0);
+ }
+
+ variableValue = getenv(variable);
+
+ if (variableValue == NULL)
+ {
+ Fail("ERROR: getenv(%s) call returned NULL\nThe call "
+ "should have returned '%s'\n", variable, value);
+ }
+ else
+ {
+ if ( strcmp(variableValue, value) != 0 )
+ {
+ Fail("ERROR: _putenv(%s)\nshould have set the variable "
+ "'%s'\n to '%s'.\nA subsequent call to getenv(%s)\n"
+ "returned '%s' instead.\n", _putenvString0,
+ variable, value, variable, variableValue);
+ }
+ else
+ {
+ if(_putenv(_putenvString1) == -1)
+ {
+ Fail("ERROR: _putenv failed to set an environment "
+ "variable with a valid format.\n Call was"
+ "_putenv(%s)\n", _putenvString1);
+ }
+
+ variableValue = getenv(variable);
+
+ if (variableValue != NULL)
+ {
+ Fail("ERROR: getenv(%s) call did not return NULL.\nThe call "
+ "returned '%s'.\n", variable, value);
+ }
+ }
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/_putenv/test2/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_putenv/test2/testinfo.dat
new file mode 100644
index 0000000000..8d3a6ced1e
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_putenv/test2/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _putenv
+Name = Positive test for _putenv
+TYPE = DEFAULT
+EXE1 = test2
+Description
+= Create an environment variable with _putenv and then use getenv to
+= check it. This test resets an environment variable.
diff --git a/src/pal/tests/palsuite/c_runtime/_putenv/test3/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_putenv/test3/CMakeLists.txt
new file mode 100644
index 0000000000..a67241022b
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_putenv/test3/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test3.c
+)
+
+add_executable(paltest_putenv_test3
+ ${SOURCES}
+)
+
+add_dependencies(paltest_putenv_test3 coreclrpal)
+
+target_link_libraries(paltest_putenv_test3
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_putenv/test3/test3.c b/src/pal/tests/palsuite/c_runtime/_putenv/test3/test3.c
new file mode 100644
index 0000000000..8aa6777307
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_putenv/test3/test3.c
@@ -0,0 +1,102 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test3.c
+**
+** Purpose: Create environment variables that differ only in Case, and
+** verify that the BSD operating system treats the variables
+** differently.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char **argv)
+{
+#if WIN32
+
+ return PASS;
+
+#else
+
+ const char* FirstVariable = "PalTestingEnvironmentVariable=The value";
+ const char* SecondVariable = "PALTESTINGEnvironmentVariable=Different value";
+ const char* FirstVarName = "PalTestingEnvironmentVariable";
+ const char* FirstVarValue = "The value";
+ char* result;
+
+
+ if (0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /* Use _putenv to set an environment variable. This ensures that the
+ variable we're testing on is always present.
+ */
+
+ if(_putenv(FirstVariable) != 0)
+ {
+ Fail("ERROR: _putenv failed to set an environment variable that "
+ "getenv will be using for testing.\n");
+ }
+
+
+ /* Call getenv -- ensure it doesn't return NULL and the string it returns
+ is the value we set above. Also make sure that each environment variable,
+ differing only by case, returns it's own value.
+ */
+
+ result = getenv(FirstVarName);
+ if(result == NULL)
+ {
+ Fail("ERROR: The result of getenv on a valid Environment Variable "
+ "was NULL, which indicates the environment varaible was not "
+ "found.\n");
+ }
+
+ if(strcmp(result, FirstVarValue) != 0)
+ {
+ Fail("ERROR: The value obtained by getenv() was not equal to the "
+ "correct value of the environment variable. The correct "
+ "value is '%s' and the function returned '%s'.\n",
+ FirstVarValue,
+ result);
+ }
+
+ /* Set the second environment variable, which only differs in Case */
+ if(_putenv(SecondVariable) != 0)
+ {
+ Fail("ERROR: _putenv failed to set an environment variable that "
+ "getenv will be using for testing.\n");
+ }
+
+ /* Verify that the environment variables
+ */
+
+ result = getenv(FirstVarName);
+ if(result == NULL)
+ {
+ Fail("ERROR: The result of getenv on a valid Environment Variable "
+ "was NULL, which indicates the environment varaible was not "
+ "found.\n");
+ }
+
+ if(strcmp(result, FirstVarValue) != 0)
+ {
+ Fail("ERROR: The value obtained by getenv() was not equal to the "
+ "correct value of the environment variable. The correct "
+ "value is '%s' and the function returned '%s'.\n",
+ FirstVarValue,
+ result);
+ }
+
+ PAL_Terminate();
+ return PASS;
+
+#endif
+}
diff --git a/src/pal/tests/palsuite/c_runtime/_putenv/test3/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_putenv/test3/testinfo.dat
new file mode 100644
index 0000000000..2c6af1b5cf
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_putenv/test3/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _putenv
+Name = Positive test for _putenv
+TYPE = DEFAULT
+EXE1 = test3
+Description
+= Create environment variables that only differ by case
+= and check that the BSD operating system treats them
+= as two separate variables.
diff --git a/src/pal/tests/palsuite/c_runtime/_putenv/test4/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_putenv/test4/CMakeLists.txt
new file mode 100644
index 0000000000..518282ccc7
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_putenv/test4/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test4.c
+)
+
+add_executable(paltest_putenv_test4
+ ${SOURCES}
+)
+
+add_dependencies(paltest_putenv_test4 coreclrpal)
+
+target_link_libraries(paltest_putenv_test4
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_putenv/test4/test4.c b/src/pal/tests/palsuite/c_runtime/_putenv/test4/test4.c
new file mode 100644
index 0000000000..48d7ba963c
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_putenv/test4/test4.c
@@ -0,0 +1,75 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test4.c
+**
+** Purpose: Create an environment variable and try to retrieve
+** it using the same name but with different case. This
+** is to show that the Win32 representation of _putenv
+** is case insensitive.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char **argv)
+{
+#if WIN32
+
+ const char* FirstVariable = "PalTestingEnvironmentVariable=The value";
+ const char* ModifiedName = "PALTESTINGEnvironmentVariable";
+ const char* FirstVarValue = "The value";
+ char* result;
+
+
+ if (0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /* Use _putenv to set an environment variable. This ensures that the
+ variable we're testing on is always present.
+ */
+
+ if(_putenv(FirstVariable) != 0)
+ {
+ Fail("ERROR: _putenv failed to set an environment variable that "
+ "getenv will be using for testing.\n");
+ }
+
+
+ /* Call getenv -- ensure it doesn't return NULL and the string it returns
+ is the value we set above. Also make sure that each environment variable,
+ differing only by case, doesn't affect the return value.
+ */
+
+ result = getenv(ModifiedName);
+ if(result == NULL)
+ {
+ Fail("ERROR: The result of getenv on a valid Environment Variable "
+ "was NULL, which indicates the environment varaible was not "
+ "found.\n");
+ }
+
+ if(strcmp(result, FirstVarValue) != 0)
+ {
+ Fail("ERROR: The value obtained by getenv() was not equal to the "
+ "correct value of the environment variable. The correct "
+ "value is '%s' and the function returned '%s'.\n",
+ FirstVarValue,
+ result);
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+
+#else
+ return PASS;
+
+#endif
+}
diff --git a/src/pal/tests/palsuite/c_runtime/_putenv/test4/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_putenv/test4/testinfo.dat
new file mode 100644
index 0000000000..af1a01c2fc
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_putenv/test4/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _putenv
+Name = Positive test for _putenv
+TYPE = DEFAULT
+EXE1 = test4
+Description
+= Create an environment variable and check
+= that trying to retrieve it using a name with different
+= case, returns the correct value.
diff --git a/src/pal/tests/palsuite/c_runtime/_putw/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_putw/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_putw/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/_putw/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_putw/test1/CMakeLists.txt
new file mode 100644
index 0000000000..c3018ad322
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_putw/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_putw_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_putw_test1 coreclrpal)
+
+target_link_libraries(paltest_putw_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_putw/test1/test1.c b/src/pal/tests/palsuite/c_runtime/_putw/test1/test1.c
new file mode 100644
index 0000000000..ecfc9046ac
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_putw/test1/test1.c
@@ -0,0 +1,112 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Writes a series of integers to a file, test.dat,
+** then verifies the results.
+**
+** Dependency: fopen(...)
+** fclose(...)
+** CloseHandle(...)
+** DeleteFileA(...)
+** _getw(...)
+**
+**
+**
+**==========================================================================*/
+
+
+#include <palsuite.h>
+
+const char testFileName[] = "test.dat";
+
+static void Cleanup(HANDLE hFile)
+{
+ if (fclose(hFile))
+ {
+ Trace("_putw: ERROR -> Unable to close file \"%s\".\n",
+ testFileName);
+ }
+ if (!DeleteFileA(testFileName))
+ {
+ Trace("_putw: ERROR -> Unable to delete file \"%s\". ",
+ "GetLastError returned %u.\n",
+ testFileName,
+ GetLastError());
+ }
+}
+
+
+int __cdecl main(int argc, char **argv)
+{
+
+ FILE * pfTest = NULL;
+ int testArray[] = {0,1,-1,0x7FFFFFFF,0x80000000,0xFFFFFFFF,0xFFFFAAAA};
+ int i = 0;
+ int retValue = 0;
+
+ /*
+ * Initialize the PAL and return FAIL if this fails
+ */
+ if (0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /*write the file that we will use to test */
+ pfTest = fopen(testFileName, "w");
+ if (pfTest == NULL)
+ {
+ Fail ("Unable to write test file.\n");
+ }
+
+ for (i = 0; i < sizeof(testArray)/sizeof(int) ; i++)
+ {
+ _putw(testArray[i], pfTest);
+
+ if( ferror( pfTest ) )
+ {
+ Cleanup(pfTest);
+ Fail( "Error:in _putw -> error has occurred in the "
+ "stream while writing to the file: \"test.dat\"\n");
+ }
+
+ }
+
+ if (fclose(pfTest) != 0)
+ {
+ Cleanup(pfTest);
+ Fail ("Error closing file after writing with _putw(..).\n");
+ }
+
+ /*open the new test file and compare*/
+ pfTest = fopen(testFileName, "r");
+ if (pfTest == NULL)
+ {
+ Fail ("Error opening \"%s\", which is odd, since I just finished "
+ "creating that file.\n", testFileName);
+ }
+ retValue =_getw( pfTest );
+ i = 0;
+ while(retValue != EOF)
+ {
+ if(retValue != testArray[i])
+ {
+ Cleanup(pfTest);
+ Fail ("Integers written by _putw are not in the correct format\n",
+ testFileName);
+ }
+ retValue = _getw( pfTest );
+ i++ ;
+ }
+
+ Cleanup(pfTest);
+ PAL_Terminate();
+ return PASS;
+}
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/_putw/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_putw/test1/testinfo.dat
new file mode 100644
index 0000000000..3007b82407
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_putw/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _putw
+Name = Positive test for _putw
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Several integers are written to a new file using _putw. This file is
+= closed, reopened and read from to verify the writes were successful.
diff --git a/src/pal/tests/palsuite/c_runtime/_rotl/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_rotl/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_rotl/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/_rotl/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_rotl/test1/CMakeLists.txt
new file mode 100644
index 0000000000..bafaa23732
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_rotl/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.cpp
+)
+
+add_executable(paltest_rotl_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_rotl_test1 coreclrpal)
+
+target_link_libraries(paltest_rotl_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_rotl/test1/test1.cpp b/src/pal/tests/palsuite/c_runtime/_rotl/test1/test1.cpp
new file mode 100644
index 0000000000..3a31388893
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_rotl/test1/test1.cpp
@@ -0,0 +1,55 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test1.c (_rotl)
+**
+** Purpose: Tests the PAL implementation of the _rotl function.
+** The _rotl function rotates the unsigned value. _rotl
+** rotates the value left and "wraps" bits rotated off
+** one end of value to the other end.
+** This test compares the result to a previously determined
+** value.
+**
+**
+**
+**===================================================================*/
+#include <palsuite.h>
+
+int __cdecl main(int argc, char **argv)
+{
+ unsigned results = 0;
+ int i,j;
+
+ unsigned hTestNums[5][8] = {
+ {0x00ff, 0x01fe, 0x03fc, 0x07f8, 0x0ff0, 0x1fe0, 0x3fc0, 0x7f80},
+ {0x0055, 0x00aa, 0x0154, 0x02a8, 0x0550, 0x0aa0, 0x1540, 0x2a80},
+ {0x0099, 0x0132, 0x0264, 0x04c8, 0x0990, 0x1320, 0x2640, 0x4c80},
+ {0x0036, 0x006c, 0x00d8, 0x01b0, 0x0360, 0x06c0, 0x0d80, 0x1b00},
+ {0x008f, 0x011e, 0x023c, 0x0478, 0x08f0, 0x11e0, 0x23c0, 0x4780}};
+
+ if ((PAL_Initialize(argc, argv)) != 0)
+ {
+ return (FAIL);
+ }
+
+ /*Loop through expected test results*/
+ for (j = 0; j <= 4; j++)
+ {
+ for(i = 1; i <= 7; i++)
+ {
+ results = _rotl(hTestNums[j][0], i);
+ if (results != hTestNums[j][i])
+ {
+ Fail("ERROR: \"0x%4.4x\" rotated bits to the left %d times"
+ " gave \"0x%4.4x\", expected \"0x%4.4x\"\n",
+ hTestNums[j][0], i, results, hTestNums[j][i]) ;
+ }
+ }
+ }
+
+ PAL_Terminate();
+ return (PASS);
+}
diff --git a/src/pal/tests/palsuite/c_runtime/_rotl/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_rotl/test1/testinfo.dat
new file mode 100644
index 0000000000..9c87473f8e
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_rotl/test1/testinfo.dat
@@ -0,0 +1,17 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _rtol
+Name = Positive Test for _rotl
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Tests the PAL implementation of the _rotl function.
+= The _rotl function rotates the unsigned value. _rotl
+= rotates the value left and "wraps" bits rotated off
+= one end of value to the other end.
+= This test compares the result to a previously determined
+= value.
diff --git a/src/pal/tests/palsuite/c_runtime/_rotr/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_rotr/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_rotr/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/_rotr/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_rotr/test1/CMakeLists.txt
new file mode 100644
index 0000000000..c0c76feb36
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_rotr/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.cpp
+)
+
+add_executable(paltest_rotr_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_rotr_test1 coreclrpal)
+
+target_link_libraries(paltest_rotr_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_rotr/test1/test1.cpp b/src/pal/tests/palsuite/c_runtime/_rotr/test1/test1.cpp
new file mode 100644
index 0000000000..cf461c0a6e
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_rotr/test1/test1.cpp
@@ -0,0 +1,60 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test1.c (_rotr)
+**
+** Purpose: Tests the PAL implementation of the _rotr function.
+** The _rotr function rotates the unsigned value. _rotr
+** rotates the value right and "wraps" bits rotated off
+** one end of value to the other end.
+** This test compares the result to a previously
+** determined value.
+**
+**
+**===================================================================*/
+#include <palsuite.h>
+
+int __cdecl main(int argc, char **argv)
+{
+ unsigned results = 0;
+ int i,j;
+
+ unsigned hTestNums[5][8] = {
+ {0x00ff, 0x8000007f, 0xc000003f, 0xe000001f,
+ 0xf000000f, 0xf8000007, 0xfc000003, 0xfe000001},
+ {0x0055, 0x8000002a, 0x40000015, 0xa000000a,
+ 0x50000005, 0xa8000002, 0x54000001, 0xaa000000},
+ {0x0099, 0x8000004c, 0x40000026, 0x20000013,
+ 0x90000009, 0xc8000004, 0x64000002, 0x32000001},
+ {0x0036, 0x001b, 0x8000000d, 0xc0000006,
+ 0x60000003, 0xb0000001, 0xd8000000, 0x6c000000},
+ {0x008f, 0x80000047, 0xc0000023, 0xe0000011,
+ 0xf0000008, 0x78000004, 0x3c000002 ,0x1e000001}};
+
+
+ if ((PAL_Initialize(argc, argv)) != 0)
+ {
+ return (FAIL);
+ }
+
+ /*Loop through expected test results*/
+ for (j = 0; j <= 4; j++)
+ {
+ for(i = 1; i <= 7; i++)
+ {
+ results = _rotr(hTestNums[j][0], i);
+ if (results != hTestNums[j][i])
+ {
+ Fail("ERROR: \"0x%4.4x\" rotated bits to the left %d times"
+ " gave \"0x%4.4x\", expected \"0x%4.4x\"\n",
+ hTestNums[j][0], i, results, hTestNums[j][i]) ;
+ }
+ }
+ }
+
+ PAL_Terminate();
+ return (PASS);
+}
diff --git a/src/pal/tests/palsuite/c_runtime/_rotr/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_rotr/test1/testinfo.dat
new file mode 100644
index 0000000000..915f467662
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_rotr/test1/testinfo.dat
@@ -0,0 +1,17 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _rtor
+Name = Positive Test for _rotr
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Tests the PAL implementation of the _rotr function.
+= The _rotr function rotates the unsigned value. _rotr
+= rotates the value right and "wraps" bits rotated off
+= one end of value to the other end.
+= This test compares the result to a previously determined
+= value.
diff --git a/src/pal/tests/palsuite/c_runtime/_snprintf/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_snprintf/CMakeLists.txt
new file mode 100644
index 0000000000..cafb9536b0
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snprintf/CMakeLists.txt
@@ -0,0 +1,22 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test10)
+add_subdirectory(test11)
+add_subdirectory(test12)
+add_subdirectory(test13)
+add_subdirectory(test14)
+add_subdirectory(test15)
+add_subdirectory(test16)
+add_subdirectory(test17)
+add_subdirectory(test18)
+add_subdirectory(test19)
+add_subdirectory(test2)
+add_subdirectory(test3)
+add_subdirectory(test4)
+add_subdirectory(test5)
+add_subdirectory(test6)
+add_subdirectory(test7)
+add_subdirectory(test8)
+add_subdirectory(test9)
+
diff --git a/src/pal/tests/palsuite/c_runtime/_snprintf/_snprintf.h b/src/pal/tests/palsuite/c_runtime/_snprintf/_snprintf.h
new file mode 100644
index 0000000000..84abf62f0b
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snprintf/_snprintf.h
@@ -0,0 +1,194 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: _snprintf.h
+**
+** Purpose: Containts common testing functions for _snprintf
+**
+**
+**==========================================================================*/
+
+#ifndef __STRINGTEST_H__
+#define __STRINGTEST_H__
+
+void DoStrTest(char *formatstr, char* param, char *checkstr)
+{
+ char buf[256] = { 0 };
+
+ _snprintf(buf, 256, formatstr, param);
+ if (memcmp(buf, checkstr, strlen(checkstr) + 1) != 0)
+ {
+ Fail("ERROR: failed to insert string \"%s\" into \"%s\"\n"
+ "Expected \"%s\" got \"%s\".\n",
+ param, formatstr, checkstr, buf);
+ }
+}
+
+void DoWStrTest(char *formatstr, WCHAR* param, char *checkstr)
+{
+ char buf[256] = { 0 };
+
+ _snprintf(buf, 256, formatstr, param);
+ if (memcmp(buf, checkstr, strlen(checkstr) + 1) != 0)
+ {
+ Fail("ERROR: failed to insert wide string \"%s\" into \"%s\"\n"
+ "Expected \"%s\" got \"%s\".\n",
+ convertC(param), formatstr, checkstr, buf);
+ }
+}
+
+
+void DoPointerTest(char *formatstr, void* param, char* paramstr, char
+ *checkstr1)
+{
+ char buf[256] = { 0 };
+
+ _snprintf(buf, 256, formatstr, param);
+ if (memcmp(buf, checkstr1, strlen(checkstr1) + 1) != 0)
+ {
+ Fail("ERROR: failed to insert %s into \"%s\"\n"
+ "Expected \"%s\", got \"%s\".\n",
+ paramstr, formatstr, checkstr1, buf);
+ }
+}
+
+void DoCountTest(char *formatstr, int param, char *checkstr)
+{
+ char buf[512] = { 0 };
+ int n = -1;
+
+ _snprintf(buf, 512, formatstr, &n);
+
+ if (n != param)
+ {
+ Fail("ERROR: Expected count parameter to resolve to %d, got %X\n",
+ param, n);
+ }
+ if (memcmp(buf, checkstr, strlen(checkstr) + 1) != 0)
+ {
+ Fail("ERROR: Expected \"%s\" got \"%s\".\n", checkstr, buf);
+ }
+}
+
+void DoShortCountTest(char *formatstr, int param, char *checkstr)
+{
+ char buf[256] = { 0 };
+ short int n = -1;
+
+ _snprintf(buf, 256, formatstr, &n);
+
+ if (n != param)
+ {
+ Fail("ERROR: Expected count parameter to resolve to %d, got %X\n",
+ param, n);
+ }
+ if (memcmp(buf, checkstr, strlen(checkstr) + 1) != 0)
+ {
+ Fail("ERROR: Expected \"%s\" got \"%s\".\n", checkstr, buf);
+ }
+}
+
+void DoCharTest(char *formatstr, char param, char *checkstr)
+{
+ char buf[256] = { 0 };
+
+ _snprintf(buf, 256, formatstr, param);
+ if (memcmp(buf, checkstr, strlen(checkstr) + 1) != 0)
+ {
+ Fail("ERROR: failed to insert char \'%c\' (%d) into \"%s\"\n"
+ "Expected \"%s\" got \"%s\".\n",
+ param, param, formatstr, checkstr, buf);
+ }
+}
+
+void DoWCharTest(char *formatstr, WCHAR param, char *checkstr)
+{
+ char buf[256] = { 0 };
+
+ _snprintf(buf, 256, formatstr, param);
+ if (memcmp(buf, checkstr, strlen(checkstr) + 1) != 0)
+ {
+ Fail("ERROR: failed to insert wide char \'%c\' (%d) into \"%s\"\n"
+ "Expected \"%s\" got \"%s\".\n",
+ (char)param, param, formatstr, checkstr, buf);
+ }
+}
+
+void DoNumTest(char *formatstr, int value, char *checkstr)
+{
+ char buf[256] = { 0 };
+
+ _snprintf(buf, 256, formatstr, value);
+ if (memcmp(buf, checkstr, strlen(checkstr) + 1) != 0)
+ {
+ Fail("ERROR: failed to insert %#x into \"%s\"\n"
+ "Expected \"%s\" got \"%s\".\n",
+ value, formatstr, checkstr, buf);
+ }
+}
+
+void DoI64Test(char *formatstr, INT64 value, char *valuestr, char *checkstr1)
+{
+ char buf[256] = { 0 };
+
+ _snprintf(buf, 256, formatstr, value);
+ if (memcmp(buf, checkstr1, strlen(checkstr1) + 1) != 0)
+ {
+ Fail("ERROR: failed to insert %s into \"%s\"\n"
+ "Expected \"%s\", got \"%s\".\n",
+ valuestr, formatstr, checkstr1, buf);
+ }
+}
+
+void DoDoubleTest(char *formatstr, double value, char *checkstr1, char
+*checkstr2)
+{
+ char buf[256] = { 0 };
+
+ _snprintf(buf, 256, formatstr, value);
+ if (memcmp(buf, checkstr1, strlen(checkstr1) + 1) != 0
+ && memcmp(buf, checkstr2, strlen(checkstr2) + 1) != 0)
+ {
+ Fail("ERROR: failed to insert %f into \"%s\"\n"
+ "Expected \"%s\" or \"%s\", got \"%s\".\n",
+ value, formatstr, checkstr1, checkstr2, buf);
+ }
+}
+
+void DoArgumentPrecTest(char *formatstr, int precision, void *param, char
+*paramstr, char *checkstr1, char*checkstr2)
+{
+ char buf[256];
+
+ _snprintf(buf, 256, formatstr, precision, param);
+ if (memcmp(buf, checkstr1, strlen(checkstr1) + 1) != 0 &&
+ memcmp(buf, checkstr2, strlen(checkstr2) + 1) != 0)
+ {
+ Fail("ERROR: failed to insert %s into \"%s\" with precision %d\n"
+ "Expected \"%s\" or \"%s\", got \"%s\".\n",
+ paramstr, formatstr, precision, checkstr1, checkstr2, buf);
+ }
+
+}
+
+void DoArgumentPrecDoubleTest(char *formatstr, int precision, double param,
+char *checkstr1, char *checkstr2)
+{
+ char buf[256];
+
+ _snprintf(buf, 256, formatstr, precision, param);
+ if (memcmp(buf, checkstr1, strlen(checkstr1) + 1) != 0 &&
+ memcmp(buf, checkstr2, strlen(checkstr2) + 1) != 0)
+ {
+ Fail("ERROR: failed to insert %f into \"%s\" with precision %d\n"
+ "Expected \"%s\" or \"%s\", got \"%s\".\n",
+ param, formatstr, precision, checkstr1, checkstr2, buf);
+ }
+
+}
+
+#endif
+
diff --git a/src/pal/tests/palsuite/c_runtime/_snprintf/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_snprintf/test1/CMakeLists.txt
new file mode 100644
index 0000000000..ab126fc59d
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snprintf/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_snprintf_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_snprintf_test1 coreclrpal)
+
+target_link_libraries(paltest_snprintf_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_snprintf/test1/test1.c b/src/pal/tests/palsuite/c_runtime/_snprintf/test1/test1.c
new file mode 100644
index 0000000000..eef7406baa
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snprintf/test1/test1.c
@@ -0,0 +1,58 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose: General test to see if _snprintf works correctly
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../_snprintf.h"
+
+/*
+ * Notes: memcmp is used, as is strlen.
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ char checkstr[] = "hello world";
+ char buf[256] = { 0 };
+ int ret;
+
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+
+ _snprintf(buf, 256, "hello world");
+ if (memcmp(checkstr, buf, strlen(checkstr)+1) != 0)
+ {
+ Fail("ERROR: expected \"%s\" (up to %d chars), got \"%s\"\n",
+ checkstr, 256, buf);
+ }
+
+ _snprintf(buf, 256, "xxxxxxxxxxxxxxxxx");
+ ret = _snprintf(buf, 8, "hello world");
+
+ if (ret >= 0)
+ {
+ Fail("ERROR: expected negative return value, got %d", ret);
+ }
+ if (memcmp(checkstr, buf, 8) != 0 || buf[8] != 'x')
+ {
+ Fail("ERROR: expected %s (up to %d chars), got %s\n",
+ checkstr, 8, buf);
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/_snprintf/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_snprintf/test1/testinfo.dat
new file mode 100644
index 0000000000..c15ce1dcba
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snprintf/test1/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _snprintf
+Name = Positive Test for _snprintf
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= General test to see if _snprintf works correctly
diff --git a/src/pal/tests/palsuite/c_runtime/_snprintf/test10/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_snprintf/test10/CMakeLists.txt
new file mode 100644
index 0000000000..e8e9308849
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snprintf/test10/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test10.c
+)
+
+add_executable(paltest_snprintf_test10
+ ${SOURCES}
+)
+
+add_dependencies(paltest_snprintf_test10 coreclrpal)
+
+target_link_libraries(paltest_snprintf_test10
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_snprintf/test10/test10.c b/src/pal/tests/palsuite/c_runtime/_snprintf/test10/test10.c
new file mode 100644
index 0000000000..9191ccef27
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snprintf/test10/test10.c
@@ -0,0 +1,55 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test10.c
+**
+** Purpose: Tests _snprintf with octal numbers
+**
+**
+**==========================================================================*/
+
+
+
+
+#include <palsuite.h>
+#include "../_snprintf.h"
+
+/*
+ * Notes: memcmp is used, as is strlen.
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ int neg = -42;
+ int pos = 42;
+ INT64 l = 42;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+
+ DoNumTest("foo %o", pos, "foo 52");
+ DoNumTest("foo %lo", 0xFFFF, "foo 177777");
+ DoNumTest("foo %ho", 0xFFFF, "foo 177777");
+ DoNumTest("foo %Lo", pos, "foo 52");
+ DoI64Test("foo %I64o", l, "42", "foo 52");
+ DoNumTest("foo %3o", pos, "foo 52");
+ DoNumTest("foo %-3o", pos, "foo 52 ");
+ DoNumTest("foo %.1o", pos, "foo 52");
+ DoNumTest("foo %.3o", pos, "foo 052");
+ DoNumTest("foo %03o", pos, "foo 052");
+ DoNumTest("foo %#o", pos, "foo 052");
+ DoNumTest("foo %+o", pos, "foo 52");
+ DoNumTest("foo % o", pos, "foo 52");
+ DoNumTest("foo %+o", neg, "foo 37777777726");
+ DoNumTest("foo % o", neg, "foo 37777777726");
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/_snprintf/test10/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_snprintf/test10/testinfo.dat
new file mode 100644
index 0000000000..44ff48e030
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snprintf/test10/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _snprintf
+Name = Positive Test for _snprintf
+TYPE = DEFAULT
+EXE1 = test10
+Description
+= Tests _snprintf with octal numbers
diff --git a/src/pal/tests/palsuite/c_runtime/_snprintf/test11/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_snprintf/test11/CMakeLists.txt
new file mode 100644
index 0000000000..ccf3dc2572
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snprintf/test11/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test11.c
+)
+
+add_executable(paltest_snprintf_test11
+ ${SOURCES}
+)
+
+add_dependencies(paltest_snprintf_test11 coreclrpal)
+
+target_link_libraries(paltest_snprintf_test11
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_snprintf/test11/test11.c b/src/pal/tests/palsuite/c_runtime/_snprintf/test11/test11.c
new file mode 100644
index 0000000000..9d9302dee0
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snprintf/test11/test11.c
@@ -0,0 +1,54 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test11.c
+**
+** Purpose: Tests _snprintf with unsigned numbers
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../_snprintf.h"
+
+/*
+ * Notes: memcmp is used, as is strlen.
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ int neg = -42;
+ int pos = 42;
+ INT64 l = 42;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+
+ DoNumTest("foo %u", pos, "foo 42");
+ DoNumTest("foo %lu", 0xFFFF, "foo 65535");
+ DoNumTest("foo %hu", 0xFFFF, "foo 65535");
+ DoNumTest("foo %Lu", pos, "foo 42");
+ DoI64Test("foo %I64u", l, "42", "foo 42");
+ DoNumTest("foo %3u", pos, "foo 42");
+ DoNumTest("foo %-3u", pos, "foo 42 ");
+ DoNumTest("foo %.1u", pos, "foo 42");
+ DoNumTest("foo %.3u", pos, "foo 042");
+ DoNumTest("foo %03u", pos, "foo 042");
+ DoNumTest("foo %#u", pos, "foo 42");
+ DoNumTest("foo %+u", pos, "foo 42");
+ DoNumTest("foo % u", pos, "foo 42");
+ DoNumTest("foo %+u", neg, "foo 4294967254");
+ DoNumTest("foo % u", neg, "foo 4294967254");
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/_snprintf/test11/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_snprintf/test11/testinfo.dat
new file mode 100644
index 0000000000..1a77077950
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snprintf/test11/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _snprintf
+Name = Positive Test for _snprintf
+TYPE = DEFAULT
+EXE1 = test11
+Description
+= Tests _snprintf with unsigned numbers
diff --git a/src/pal/tests/palsuite/c_runtime/_snprintf/test12/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_snprintf/test12/CMakeLists.txt
new file mode 100644
index 0000000000..68b442f1d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snprintf/test12/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test12.c
+)
+
+add_executable(paltest_snprintf_test12
+ ${SOURCES}
+)
+
+add_dependencies(paltest_snprintf_test12 coreclrpal)
+
+target_link_libraries(paltest_snprintf_test12
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_snprintf/test12/test12.c b/src/pal/tests/palsuite/c_runtime/_snprintf/test12/test12.c
new file mode 100644
index 0000000000..d782fce788
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snprintf/test12/test12.c
@@ -0,0 +1,55 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test12.c
+**
+** Purpose: Tests _snprintf with hex numbers (lowercase)
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../_snprintf.h"
+
+/*
+ * Notes: memcmp is used, as is strlen.
+ */
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ int neg = -42;
+ int pos = 0x1234ab;
+ INT64 l = I64(0x1234567887654321);
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+
+ DoNumTest("foo %x", pos, "foo 1234ab");
+ DoNumTest("foo %lx", pos, "foo 1234ab");
+ DoNumTest("foo %hx", pos, "foo 34ab");
+ DoNumTest("foo %Lx", pos, "foo 1234ab");
+ DoI64Test("foo %I64x", l, "0x1234567887654321", "foo 1234567887654321");
+ DoNumTest("foo %7x", pos, "foo 1234ab");
+ DoNumTest("foo %-7x", pos, "foo 1234ab ");
+ DoNumTest("foo %.1x", pos, "foo 1234ab");
+ DoNumTest("foo %.7x", pos, "foo 01234ab");
+ DoNumTest("foo %07x", pos, "foo 01234ab");
+ DoNumTest("foo %#x", pos, "foo 0x1234ab");
+ DoNumTest("foo %+x", pos, "foo 1234ab");
+ DoNumTest("foo % x", pos, "foo 1234ab");
+ DoNumTest("foo %+x", neg, "foo ffffffd6");
+ DoNumTest("foo % x", neg, "foo ffffffd6");
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/_snprintf/test12/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_snprintf/test12/testinfo.dat
new file mode 100644
index 0000000000..6801c7417e
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snprintf/test12/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _snprintf
+Name = Positive Test for _snprintf
+TYPE = DEFAULT
+EXE1 = test12
+Description
+= Tests _snprintf with hex numbers (lowercase)
diff --git a/src/pal/tests/palsuite/c_runtime/_snprintf/test13/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_snprintf/test13/CMakeLists.txt
new file mode 100644
index 0000000000..832b3fefbf
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snprintf/test13/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test13.c
+)
+
+add_executable(paltest_snprintf_test13
+ ${SOURCES}
+)
+
+add_dependencies(paltest_snprintf_test13 coreclrpal)
+
+target_link_libraries(paltest_snprintf_test13
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_snprintf/test13/test13.c b/src/pal/tests/palsuite/c_runtime/_snprintf/test13/test13.c
new file mode 100644
index 0000000000..68ba554d93
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snprintf/test13/test13.c
@@ -0,0 +1,55 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test13.c
+**
+** Purpose: Tests _snprintf with hex numbers (uppercase)
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../_snprintf.h"
+
+/*
+ * Notes: memcmp is used, as is strlen.
+ */
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ int neg = -42;
+ int pos = 0x1234AB;
+ INT64 l = I64(0x1234567887654321);
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+
+ DoNumTest("foo %X", pos, "foo 1234AB");
+ DoNumTest("foo %lX", pos, "foo 1234AB");
+ DoNumTest("foo %hX", pos, "foo 34AB");
+ DoNumTest("foo %LX", pos, "foo 1234AB");
+ DoI64Test("foo %I64X", l, "0x1234567887654321", "foo 1234567887654321");
+ DoNumTest("foo %7X", pos, "foo 1234AB");
+ DoNumTest("foo %-7X", pos, "foo 1234AB ");
+ DoNumTest("foo %.1X", pos, "foo 1234AB");
+ DoNumTest("foo %.7X", pos, "foo 01234AB");
+ DoNumTest("foo %07X", pos, "foo 01234AB");
+ DoNumTest("foo %#X", pos, "foo 0X1234AB");
+ DoNumTest("foo %+X", pos, "foo 1234AB");
+ DoNumTest("foo % X", pos, "foo 1234AB");
+ DoNumTest("foo %+X", neg, "foo FFFFFFD6");
+ DoNumTest("foo % X", neg, "foo FFFFFFD6");
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/_snprintf/test13/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_snprintf/test13/testinfo.dat
new file mode 100644
index 0000000000..6901589a1b
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snprintf/test13/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _snprintf
+Name = Positive Test for _snprintf
+TYPE = DEFAULT
+EXE1 = test13
+Description
+= Tests _snprintf with hex numbers (uppercase)
diff --git a/src/pal/tests/palsuite/c_runtime/_snprintf/test14/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_snprintf/test14/CMakeLists.txt
new file mode 100644
index 0000000000..c2e3be148d
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snprintf/test14/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test14.c
+)
+
+add_executable(paltest_snprintf_test14
+ ${SOURCES}
+)
+
+add_dependencies(paltest_snprintf_test14 coreclrpal)
+
+target_link_libraries(paltest_snprintf_test14
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_snprintf/test14/test14.c b/src/pal/tests/palsuite/c_runtime/_snprintf/test14/test14.c
new file mode 100644
index 0000000000..d874690ba4
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snprintf/test14/test14.c
@@ -0,0 +1,57 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test14.c
+**
+** Purpose: Tests _snprintf with exponential format doubles (lowercase)
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../_snprintf.h"
+
+/*
+ * Notes: memcmp is used, as is strlen.
+ */
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ double val = 256.0;
+ double neg = -256.0;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+
+ DoDoubleTest("foo %e", val, "foo 2.560000e+002", "foo 2.560000e+02");
+ DoDoubleTest("foo %le", val, "foo 2.560000e+002", "foo 2.560000e+02");
+ DoDoubleTest("foo %he", val, "foo 2.560000e+002", "foo 2.560000e+02");
+ DoDoubleTest("foo %Le", val, "foo 2.560000e+002", "foo 2.560000e+02");
+ DoDoubleTest("foo %I64e", val, "foo 2.560000e+002", "foo 2.560000e+02");
+ DoDoubleTest("foo %14e", val, "foo 2.560000e+002",
+ "foo 2.560000e+02");
+ DoDoubleTest("foo %-14e", val, "foo 2.560000e+002 ",
+ "foo 2.560000e+02 ");
+ DoDoubleTest("foo %.1e", val, "foo 2.6e+002", "foo 2.6e+02");
+ DoDoubleTest("foo %.8e", val, "foo 2.56000000e+002",
+ "foo 2.56000000e+02");
+ DoDoubleTest("foo %014e", val, "foo 02.560000e+002",
+ "foo 002.560000e+02");
+ DoDoubleTest("foo %#e", val, "foo 2.560000e+002", "foo 2.560000e+02");
+ DoDoubleTest("foo %+e", val, "foo +2.560000e+002", "foo +2.560000e+02");
+ DoDoubleTest("foo % e", val, "foo 2.560000e+002", "foo 2.560000e+02");
+ DoDoubleTest("foo %+e", neg, "foo -2.560000e+002", "foo -2.560000e+02");
+ DoDoubleTest("foo % e", neg, "foo -2.560000e+002", "foo -2.560000e+02");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/_snprintf/test14/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_snprintf/test14/testinfo.dat
new file mode 100644
index 0000000000..0f32b9b59a
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snprintf/test14/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _snprintf
+Name = Positive Test for _snprintf
+TYPE = DEFAULT
+EXE1 = test14
+Description
+= Tests _snprintf with exponential format doubles (lowercase)
diff --git a/src/pal/tests/palsuite/c_runtime/_snprintf/test15/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_snprintf/test15/CMakeLists.txt
new file mode 100644
index 0000000000..1bd24d5ccd
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snprintf/test15/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test15.c
+)
+
+add_executable(paltest_snprintf_test15
+ ${SOURCES}
+)
+
+add_dependencies(paltest_snprintf_test15 coreclrpal)
+
+target_link_libraries(paltest_snprintf_test15
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_snprintf/test15/test15.c b/src/pal/tests/palsuite/c_runtime/_snprintf/test15/test15.c
new file mode 100644
index 0000000000..a637a706f5
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snprintf/test15/test15.c
@@ -0,0 +1,56 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test15.c
+**
+** Purpose: Tests _snprintf with exponential format doubles (uppercase)
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../_snprintf.h"
+
+/*
+ * Notes: memcmp is used, as is strlen.
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ double val = 256.0;
+ double neg = -256.0;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+
+ DoDoubleTest("foo %E", val, "foo 2.560000E+002", "foo 2.560000E+02");
+ DoDoubleTest("foo %lE", val, "foo 2.560000E+002", "foo 2.560000E+02");
+ DoDoubleTest("foo %hE", val, "foo 2.560000E+002", "foo 2.560000E+02");
+ DoDoubleTest("foo %LE", val, "foo 2.560000E+002", "foo 2.560000E+02");
+ DoDoubleTest("foo %I64E", val, "foo 2.560000E+002", "foo 2.560000E+02");
+ DoDoubleTest("foo %14E", val, "foo 2.560000E+002",
+ "foo 2.560000E+02");
+ DoDoubleTest("foo %-14E", val, "foo 2.560000E+002 ",
+ "foo 2.560000E+02 ");
+ DoDoubleTest("foo %.1E", val, "foo 2.6E+002", "foo 2.6E+02");
+ DoDoubleTest("foo %.8E", val, "foo 2.56000000E+002",
+ "foo 2.56000000E+02");
+ DoDoubleTest("foo %014E", val, "foo 02.560000E+002",
+ "foo 002.560000E+02");
+ DoDoubleTest("foo %#E", val, "foo 2.560000E+002", "foo 2.560000E+02");
+ DoDoubleTest("foo %+E", val, "foo +2.560000E+002", "foo +2.560000E+02");
+ DoDoubleTest("foo % E", val, "foo 2.560000E+002", "foo 2.560000E+02");
+ DoDoubleTest("foo %+E", neg, "foo -2.560000E+002", "foo -2.560000E+02");
+ DoDoubleTest("foo % E", neg, "foo -2.560000E+002", "foo -2.560000E+02");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/_snprintf/test15/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_snprintf/test15/testinfo.dat
new file mode 100644
index 0000000000..8008cff0b5
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snprintf/test15/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _snprintf
+Name = Positive Test for _snprintf
+TYPE = DEFAULT
+EXE1 = test15
+Description
+= Tests _snprintf with exponential format doubles (uppercase)
diff --git a/src/pal/tests/palsuite/c_runtime/_snprintf/test16/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_snprintf/test16/CMakeLists.txt
new file mode 100644
index 0000000000..952192e560
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snprintf/test16/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test16.c
+)
+
+add_executable(paltest_snprintf_test16
+ ${SOURCES}
+)
+
+add_dependencies(paltest_snprintf_test16 coreclrpal)
+
+target_link_libraries(paltest_snprintf_test16
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_snprintf/test16/test16.c b/src/pal/tests/palsuite/c_runtime/_snprintf/test16/test16.c
new file mode 100644
index 0000000000..6793019383
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snprintf/test16/test16.c
@@ -0,0 +1,52 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test16.c
+**
+** Purpose: Test #15 for the _snprintf function
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../_snprintf.h"
+
+/*
+ * Notes: memcmp is used, as is strlen.
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ double val = 2560.001;
+ double neg = -2560.001;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+
+ DoDoubleTest("foo %f", val, "foo 2560.001000", "foo 2560.001000");
+ DoDoubleTest("foo %lf", val, "foo 2560.001000", "foo 2560.001000");
+ DoDoubleTest("foo %hf", val, "foo 2560.001000", "foo 2560.001000");
+ DoDoubleTest("foo %Lf", val, "foo 2560.001000", "foo 2560.001000");
+ DoDoubleTest("foo %I64f", val, "foo 2560.001000", "foo 2560.001000");
+ DoDoubleTest("foo %12f", val, "foo 2560.001000", "foo 2560.001000");
+ DoDoubleTest("foo %-12f", val, "foo 2560.001000 ", "foo 2560.001000 ");
+ DoDoubleTest("foo %.1f", val, "foo 2560.0", "foo 2560.0");
+ DoDoubleTest("foo %.8f", val, "foo 2560.00100000", "foo 2560.00100000");
+ DoDoubleTest("foo %012f", val, "foo 02560.001000", "foo 02560.001000");
+ DoDoubleTest("foo %#f", val, "foo 2560.001000", "foo 2560.001000");
+ DoDoubleTest("foo %+f", val, "foo +2560.001000", "foo +2560.001000");
+ DoDoubleTest("foo % f", val, "foo 2560.001000", "foo 2560.001000");
+ DoDoubleTest("foo %+f", neg, "foo -2560.001000", "foo -2560.001000");
+ DoDoubleTest("foo % f", neg, "foo -2560.001000", "foo -2560.001000");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/_snprintf/test16/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_snprintf/test16/testinfo.dat
new file mode 100644
index 0000000000..e7a7df8f53
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snprintf/test16/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _snprintf
+Name = Positive Test for _snprintf
+TYPE = DEFAULT
+EXE1 = test16
+Description
+= Tests _snprintf with decimal point format doubles
diff --git a/src/pal/tests/palsuite/c_runtime/_snprintf/test17/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_snprintf/test17/CMakeLists.txt
new file mode 100644
index 0000000000..ce5cc1623e
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snprintf/test17/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test17.c
+)
+
+add_executable(paltest_snprintf_test17
+ ${SOURCES}
+)
+
+add_dependencies(paltest_snprintf_test17 coreclrpal)
+
+target_link_libraries(paltest_snprintf_test17
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_snprintf/test17/test17.c b/src/pal/tests/palsuite/c_runtime/_snprintf/test17/test17.c
new file mode 100644
index 0000000000..9981b44619
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snprintf/test17/test17.c
@@ -0,0 +1,53 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test17.c
+**
+** Purpose: Tests _snprintf with compact format doubles (lowercase)
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../_snprintf.h"
+
+/*
+ * Notes: memcmp is used, as is strlen.
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ double val = 2560.001;
+ double neg = -2560.001;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+
+ DoDoubleTest("foo %g", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %lg", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %hg", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %Lg", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %I64g", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %5g", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %-5g", val, "foo 2560 ", "foo 2560 ");
+ DoDoubleTest("foo %.1g", val, "foo 3e+003", "foo 3e+03");
+ DoDoubleTest("foo %.2g", val, "foo 2.6e+003", "foo 2.6e+03");
+ DoDoubleTest("foo %.12g", val, "foo 2560.001", "foo 2560.001");
+ DoDoubleTest("foo %06g", val, "foo 002560", "foo 002560");
+ DoDoubleTest("foo %#g", val, "foo 2560.00", "foo 2560.00");
+ DoDoubleTest("foo %+g", val, "foo +2560", "foo +2560");
+ DoDoubleTest("foo % g", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %+g", neg, "foo -2560", "foo -2560");
+ DoDoubleTest("foo % g", neg, "foo -2560", "foo -2560");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/_snprintf/test17/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_snprintf/test17/testinfo.dat
new file mode 100644
index 0000000000..4756bd0d78
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snprintf/test17/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _snprintf
+Name = Positive Test for _snprintf
+TYPE = DEFAULT
+EXE1 = test17
+Description
+= Tests _snprintf with compact format doubles (lowercase)
diff --git a/src/pal/tests/palsuite/c_runtime/_snprintf/test18/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_snprintf/test18/CMakeLists.txt
new file mode 100644
index 0000000000..bb9c9c37cc
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snprintf/test18/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test18.c
+)
+
+add_executable(paltest_snprintf_test18
+ ${SOURCES}
+)
+
+add_dependencies(paltest_snprintf_test18 coreclrpal)
+
+target_link_libraries(paltest_snprintf_test18
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_snprintf/test18/test18.c b/src/pal/tests/palsuite/c_runtime/_snprintf/test18/test18.c
new file mode 100644
index 0000000000..d28aec57d0
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snprintf/test18/test18.c
@@ -0,0 +1,53 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test18.c
+**
+** Purpose: Tests _snprintf with compact format doubles (uppercase)
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../_snprintf.h"
+
+/*
+ * Notes: memcmp is used, as is strlen.
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ double val = 2560.001;
+ double neg = -2560.001;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+
+ DoDoubleTest("foo %G", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %lG", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %hG", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %LG", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %I64G", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %5G", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %-5G", val, "foo 2560 ", "foo 2560 ");
+ DoDoubleTest("foo %.1G", val, "foo 3E+003", "foo 3E+03");
+ DoDoubleTest("foo %.2G", val, "foo 2.6E+003", "foo 2.6E+03");
+ DoDoubleTest("foo %.12G", val, "foo 2560.001", "foo 2560.001");
+ DoDoubleTest("foo %06G", val, "foo 002560", "foo 002560");
+ DoDoubleTest("foo %#G", val, "foo 2560.00", "foo 2560.00");
+ DoDoubleTest("foo %+G", val, "foo +2560", "foo +2560");
+ DoDoubleTest("foo % G", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %+G", neg, "foo -2560", "foo -2560");
+ DoDoubleTest("foo % G", neg, "foo -2560", "foo -2560");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/_snprintf/test18/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_snprintf/test18/testinfo.dat
new file mode 100644
index 0000000000..819d28cec9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snprintf/test18/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _snprintf
+Name = Positive Test for _snprintf
+TYPE = DEFAULT
+EXE1 = test18
+Description
+= Tests _snprintf with compact format doubles (uppercase)
diff --git a/src/pal/tests/palsuite/c_runtime/_snprintf/test19/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_snprintf/test19/CMakeLists.txt
new file mode 100644
index 0000000000..f3fbb95013
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snprintf/test19/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test19.c
+)
+
+add_executable(paltest_snprintf_test19
+ ${SOURCES}
+)
+
+add_dependencies(paltest_snprintf_test19 coreclrpal)
+
+target_link_libraries(paltest_snprintf_test19
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_snprintf/test19/test19.c b/src/pal/tests/palsuite/c_runtime/_snprintf/test19/test19.c
new file mode 100644
index 0000000000..26dffd9214
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snprintf/test19/test19.c
@@ -0,0 +1,76 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test19.c
+**
+** Purpose:Tests _snprintf with argument specified precision
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../_snprintf.h"
+
+/*
+ * Notes: memcmp is used, as is strlen.
+ */
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ int n = -1;
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+ DoArgumentPrecTest("%.*s", 2, "bar", "bar", "ba", "ba");
+ DoArgumentPrecTest("%.*S", 2, convert("bar"), "bar", "ba", "ba");
+ DoArgumentPrecTest("%.*n", 3, &n, "pointer to int", "", "");
+ if (n != 0)
+ {
+ Fail("ERROR: Expected count parameter to resolve to %d, got %X\n",
+ 0, n);
+ }
+
+ DoArgumentPrecTest("%.*c", 0, (void*)'a', "a", "a", "a");
+ DoArgumentPrecTest("%.*c", 4, (void*)'a', "a", "a", "a");
+ DoArgumentPrecTest("%.*C", 0, (void*)'a', "a", "a", "a");
+ DoArgumentPrecTest("%.*C", 4, (void*)'a', "a", "a", "a");
+ DoArgumentPrecTest("%.*d", 1, (void*)42, "42", "42", "42");
+ DoArgumentPrecTest("%.*d", 3, (void*)42, "42", "042", "042");
+ DoArgumentPrecTest("%.*i", 1, (void*)42, "42", "42", "42");
+ DoArgumentPrecTest("%.*i", 3, (void*)42, "42", "042", "042");
+ DoArgumentPrecTest("%.*o", 1, (void*)42, "42", "52", "52");
+ DoArgumentPrecTest("%.*o", 3, (void*)42, "42", "052", "052");
+ DoArgumentPrecTest("%.*u", 1, (void*)42, "42", "42", "42");
+ DoArgumentPrecTest("%.*u", 3, (void*)42, "42", "042", "042");
+ DoArgumentPrecTest("%.*x", 1, (void*)0x42, "0x42", "42", "42");
+ DoArgumentPrecTest("%.*x", 3, (void*)0x42, "0x42", "042", "042");
+ DoArgumentPrecTest("%.*X", 1, (void*)0x42, "0x42", "42", "42") ;
+ DoArgumentPrecTest("%.*X", 3, (void*)0x42, "0x42", "042", "042");
+
+
+ DoArgumentPrecDoubleTest("%.*e", 1, 2.01, "2.0e+000", "2.0e+00");
+ DoArgumentPrecDoubleTest("%.*e", 3, 2.01, "2.010e+000", "2.010e+00");
+ DoArgumentPrecDoubleTest("%.*E", 1, 2.01, "2.0E+000", "2.0E+00");
+ DoArgumentPrecDoubleTest("%.*E", 3, 2.01, "2.010E+000", "2.010E+00");
+ DoArgumentPrecDoubleTest("%.*f", 1, 2.01, "2.0", "2.0");
+ DoArgumentPrecDoubleTest("%.*f", 3, 2.01, "2.010", "2.010");
+ DoArgumentPrecDoubleTest("%.*g", 1, 256.01, "3e+002", "3e+02");
+ DoArgumentPrecDoubleTest("%.*g", 3, 256.01, "256", "256");
+ DoArgumentPrecDoubleTest("%.*g", 4, 256.01, "256", "256");
+ DoArgumentPrecDoubleTest("%.*g", 6, 256.01, "256.01", "256.01");
+ DoArgumentPrecDoubleTest("%.*G", 1, 256.01, "3E+002", "3E+02");
+ DoArgumentPrecDoubleTest("%.*G", 3, 256.01, "256", "256");
+ DoArgumentPrecDoubleTest("%.*G", 4, 256.01, "256", "256");
+ DoArgumentPrecDoubleTest("%.*G", 6, 256.01, "256.01", "256.01");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/_snprintf/test19/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_snprintf/test19/testinfo.dat
new file mode 100644
index 0000000000..875abf7071
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snprintf/test19/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _snprintf
+Name = Positive Test for _snprintf
+TYPE = DEFAULT
+EXE1 = test19
+Description
+= Tests _snprintf with argument specified precision
diff --git a/src/pal/tests/palsuite/c_runtime/_snprintf/test2/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_snprintf/test2/CMakeLists.txt
new file mode 100644
index 0000000000..8c617df108
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snprintf/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test2.c
+)
+
+add_executable(paltest_snprintf_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_snprintf_test2 coreclrpal)
+
+target_link_libraries(paltest_snprintf_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_snprintf/test2/test2.c b/src/pal/tests/palsuite/c_runtime/_snprintf/test2/test2.c
new file mode 100644
index 0000000000..3ccb66c23e
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snprintf/test2/test2.c
@@ -0,0 +1,44 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test2.c
+**
+** Purpose:Tests _snprintf with strings
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../_snprintf.h"
+/*
+ * Notes: memcmp is used, as is strlen.
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+ DoStrTest("foo %s", "bar", "foo bar");
+ DoStrTest("foo %hs", "bar", "foo bar");
+ DoWStrTest("foo %ls", convert("bar"), "foo bar");
+ DoWStrTest("foo %ws", convert("bar"), "foo bar");
+ DoStrTest("foo %Ls", "bar", "foo bar");
+ DoStrTest("foo %I64s", "bar", "foo bar");
+ DoStrTest("foo %5s", "bar", "foo bar");
+ DoStrTest("foo %.2s", "bar", "foo ba");
+ DoStrTest("foo %5.2s", "bar", "foo ba");
+ DoStrTest("foo %-5s", "bar", "foo bar ");
+ DoStrTest("foo %05s", "bar", "foo 00bar");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/_snprintf/test2/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_snprintf/test2/testinfo.dat
new file mode 100644
index 0000000000..40a1ede3d5
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snprintf/test2/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _snprintf
+Name = Positive Test for _snprintf
+TYPE = DEFAULT
+EXE1 = test2
+Description
+= Tests _snprintf with strings
diff --git a/src/pal/tests/palsuite/c_runtime/_snprintf/test3/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_snprintf/test3/CMakeLists.txt
new file mode 100644
index 0000000000..13330464a7
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snprintf/test3/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test3.c
+)
+
+add_executable(paltest_snprintf_test3
+ ${SOURCES}
+)
+
+add_dependencies(paltest_snprintf_test3 coreclrpal)
+
+target_link_libraries(paltest_snprintf_test3
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_snprintf/test3/test3.c b/src/pal/tests/palsuite/c_runtime/_snprintf/test3/test3.c
new file mode 100644
index 0000000000..496159c51e
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snprintf/test3/test3.c
@@ -0,0 +1,45 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test3.c
+**
+** Purpose: Tests _snprintf with wide strings
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../_snprintf.h"
+
+/*
+ * Notes: memcmp is used, as is strlen.
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+ DoWStrTest("foo %S", convert("bar"), "foo bar");
+ DoStrTest("foo %hS", "bar", "foo bar");
+ DoWStrTest("foo %lS", convert("bar"), "foo bar");
+ DoWStrTest("foo %wS", convert("bar"), "foo bar");
+ DoWStrTest("foo %LS", convert("bar"), "foo bar");
+ DoWStrTest("foo %I64S", convert("bar"), "foo bar");
+ DoWStrTest("foo %5S", convert("bar"), "foo bar");
+ DoWStrTest("foo %.2S", convert("bar"), "foo ba");
+ DoWStrTest("foo %5.2S", convert("bar"), "foo ba");
+ DoWStrTest("foo %-5S", convert("bar"), "foo bar ");
+ DoWStrTest("foo %05S", convert("bar"), "foo 00bar");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/_snprintf/test3/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_snprintf/test3/testinfo.dat
new file mode 100644
index 0000000000..fa53224510
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snprintf/test3/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _snprintf
+Name = Positive Test for _snprintf
+TYPE = DEFAULT
+EXE1 = test3
+Description
+= Tests _snprintf with wide strings
diff --git a/src/pal/tests/palsuite/c_runtime/_snprintf/test4/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_snprintf/test4/CMakeLists.txt
new file mode 100644
index 0000000000..5132aa02de
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snprintf/test4/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test4.c
+)
+
+add_executable(paltest_snprintf_test4
+ ${SOURCES}
+)
+
+add_dependencies(paltest_snprintf_test4 coreclrpal)
+
+target_link_libraries(paltest_snprintf_test4
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_snprintf/test4/test4.c b/src/pal/tests/palsuite/c_runtime/_snprintf/test4/test4.c
new file mode 100644
index 0000000000..8c39f222cc
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snprintf/test4/test4.c
@@ -0,0 +1,69 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test4.c
+**
+** Purpose: Tests _snprintf with pointers
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../_snprintf.h"
+
+/*
+ * Notes: memcmp is used, as is strlen.
+ */
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ void *ptr = (void*) 0x123456;
+ INT64 lptr = I64(0x1234567887654321);
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+ /*
+ ** Run only on 64 bit platforms
+ */
+ #if defined(BIT64) && defined(PLATFORM_UNIX)
+ Trace("Testing for 64 Bit Platforms \n");
+ DoPointerTest("%p", NULL, "NULL", "0000000000000000");
+ DoPointerTest("%p", ptr, "pointer to 0x123456", "0000000000123456");
+ DoPointerTest("%17p", ptr, "pointer to 0x123456", " 0000000000123456");
+ DoPointerTest("%17p", ptr, "pointer to 0x123456", " 0000000000123456");
+ DoPointerTest("%-17p", ptr, "pointer to 0x123456", "0000000000123456 ");
+ DoPointerTest("%+p", ptr, "pointer to 0x123456", "0000000000123456");
+ DoPointerTest("%#p", ptr, "pointer to 0x123456", "0X0000000000123456");
+ DoPointerTest("%lp", ptr, "pointer to 0x123456", "00123456");
+ DoPointerTest("%hp", ptr, "pointer to 0x123456", "00003456");
+ DoPointerTest("%Lp", ptr, "pointer to 0x123456", "00123456");
+ DoI64Test("%I64p", lptr, "pointer to 0x1234567887654321",
+ "1234567887654321");
+ #else
+ Trace("Testing for Non 64 Bit Platforms \n");
+ DoPointerTest("%p", NULL, "NULL", "00000000");
+ DoPointerTest("%p", ptr, "pointer to 0x123456", "00123456");
+ DoPointerTest("%9p", ptr, "pointer to 0x123456", " 00123456");
+ DoPointerTest("%09p", ptr, "pointer to 0x123456", " 00123456");
+ DoPointerTest("%-9p", ptr, "pointer to 0x123456", "00123456 ");
+ DoPointerTest("%+p", ptr, "pointer to 0x123456", "00123456");
+ DoPointerTest("%#p", ptr, "pointer to 0x123456", "0X00123456");
+ DoPointerTest("%lp", ptr, "pointer to 0x123456", "00123456");
+ DoPointerTest("%hp", ptr, "pointer to 0x123456", "00003456");
+ DoPointerTest("%Lp", ptr, "pointer to 0x123456", "00123456");
+ DoI64Test("%I64p", lptr, "pointer to 0x1234567887654321",
+ "1234567887654321");
+ #endif //defined(BIT64) && defined(PLATFORM_UNIX)
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/_snprintf/test4/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_snprintf/test4/testinfo.dat
new file mode 100644
index 0000000000..5d822d160b
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snprintf/test4/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _snprintf
+Name = Positive Test for _snprintf
+TYPE = DEFAULT
+EXE1 = test4
+Description
+= Tests _snprintf with pointers
diff --git a/src/pal/tests/palsuite/c_runtime/_snprintf/test5/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_snprintf/test5/CMakeLists.txt
new file mode 100644
index 0000000000..07e441cee0
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snprintf/test5/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test5.c
+)
+
+add_executable(paltest_snprintf_test5
+ ${SOURCES}
+)
+
+add_dependencies(paltest_snprintf_test5 coreclrpal)
+
+target_link_libraries(paltest_snprintf_test5
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_snprintf/test5/test5.c b/src/pal/tests/palsuite/c_runtime/_snprintf/test5/test5.c
new file mode 100644
index 0000000000..46ab1dd35e
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snprintf/test5/test5.c
@@ -0,0 +1,61 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test5.c
+**
+** Purpose: Tests _snprintf with the count specifier
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../_snprintf.h"
+
+/*
+ * Notes: memcmp is used, as is strlen.
+ */
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ char *longStr =
+ "really-long-string-that-just-keeps-going-on-and-on-and-on.."
+ "..................useless-filler.................................."
+ "..................useless-filler.................................."
+ "..................useless-filler.................................."
+ "%n bar";
+ char *longResult =
+ "really-long-string-that-just-keeps-going-on-and-on-and-on.."
+ "..................useless-filler.................................."
+ "..................useless-filler.................................."
+ "..................useless-filler.................................."
+ " bar";
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+ DoCountTest("foo %n bar", 4, "foo bar");
+ DoCountTest(longStr, 257, longResult);
+ DoCountTest("fo%n bar", 2, "fo bar");
+ DoCountTest("%n", 0, "");
+ DoCountTest("foo %#n bar", 4, "foo bar");
+ DoCountTest("foo % n bar", 4, "foo bar");
+ DoCountTest("foo %+n bar", 4, "foo bar");
+ DoCountTest("foo %-n bar", 4, "foo bar");
+ DoCountTest("foo %0n bar", 4, "foo bar");
+ DoShortCountTest("foo %hn bar", 4, "foo bar");
+ DoCountTest("foo %ln bar", 4, "foo bar");
+ DoCountTest("foo %Ln bar", 4, "foo bar");
+ DoCountTest("foo %I64n bar", 4, "foo bar");
+ DoCountTest("foo %20.3n bar", 4, "foo bar");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/_snprintf/test5/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_snprintf/test5/testinfo.dat
new file mode 100644
index 0000000000..33056defd8
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snprintf/test5/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _snprintf
+Name = Positive Test for _snprintf
+TYPE = DEFAULT
+EXE1 = test5
+Description
+= Tests _snprintf with the count specifier
diff --git a/src/pal/tests/palsuite/c_runtime/_snprintf/test6/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_snprintf/test6/CMakeLists.txt
new file mode 100644
index 0000000000..9ee5d90544
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snprintf/test6/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test6.c
+)
+
+add_executable(paltest_snprintf_test6
+ ${SOURCES}
+)
+
+add_dependencies(paltest_snprintf_test6 coreclrpal)
+
+target_link_libraries(paltest_snprintf_test6
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_snprintf/test6/test6.c b/src/pal/tests/palsuite/c_runtime/_snprintf/test6/test6.c
new file mode 100644
index 0000000000..32001c2d20
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snprintf/test6/test6.c
@@ -0,0 +1,47 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test6.c
+**
+** Purpose: Tests _snprintf with characters
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../_snprintf.h"
+
+/*
+ * Notes: memcmp is used, as is strlen.
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ WCHAR wc = (WCHAR) 'c';
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+
+ DoCharTest("foo %c", 'b', "foo b");
+ DoCharTest("foo %hc", 'b', "foo b");
+ DoWCharTest("foo %lc", wc, "foo c");
+ DoCharTest("foo %Lc", 'b', "foo b");
+ DoCharTest("foo %I64c", 'b', "foo b");
+ DoCharTest("foo %5c", 'b', "foo b");
+ DoCharTest("foo %.0c", 'b', "foo b");
+ DoCharTest("foo %-5c", 'b', "foo b ");
+ DoCharTest("foo %05c", 'b', "foo 0000b");
+ DoCharTest("foo % c", 'b', "foo b");
+ DoCharTest("foo %#c", 'b', "foo b");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/_snprintf/test6/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_snprintf/test6/testinfo.dat
new file mode 100644
index 0000000000..ba2ff818aa
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snprintf/test6/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _snprintf
+Name =Positive Test for _snprintf
+TYPE = DEFAULT
+EXE1 = test6
+Description
+= Tests _snprintf with characters
diff --git a/src/pal/tests/palsuite/c_runtime/_snprintf/test7/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_snprintf/test7/CMakeLists.txt
new file mode 100644
index 0000000000..f7651218e0
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snprintf/test7/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test7.c
+)
+
+add_executable(paltest_snprintf_test7
+ ${SOURCES}
+)
+
+add_dependencies(paltest_snprintf_test7 coreclrpal)
+
+target_link_libraries(paltest_snprintf_test7
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_snprintf/test7/test7.c b/src/pal/tests/palsuite/c_runtime/_snprintf/test7/test7.c
new file mode 100644
index 0000000000..bfd5c3f4f1
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snprintf/test7/test7.c
@@ -0,0 +1,47 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test7.c
+**
+** Purpose: Tests _snprintf with wide characters
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../_snprintf.h"
+/*
+ * Notes: memcmp is used, as is strlen.
+ */
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ WCHAR wb = (WCHAR) 'b';
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+
+ DoWCharTest("foo %C", wb, "foo b");
+ DoWCharTest("foo %hC", wb, "foo b");
+ DoCharTest("foo %lC", 'c', "foo c");
+ DoWCharTest("foo %LC", wb, "foo b");
+ DoWCharTest("foo %I64C", wb, "foo b");
+ DoWCharTest("foo %5C", wb, "foo b");
+ DoWCharTest("foo %.0C", wb, "foo b");
+ DoWCharTest("foo %-5C", wb, "foo b ");
+ DoWCharTest("foo %05C", wb, "foo 0000b");
+ DoWCharTest("foo % C", wb, "foo b");
+ DoWCharTest("foo %#C", wb, "foo b");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/_snprintf/test7/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_snprintf/test7/testinfo.dat
new file mode 100644
index 0000000000..5c2406c7b2
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snprintf/test7/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _snprintf
+Name = Positive Test for _snprintf
+TYPE = DEFAULT
+EXE1 = test7
+Description
+= Tests _snprintf with wide characters
diff --git a/src/pal/tests/palsuite/c_runtime/_snprintf/test8/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_snprintf/test8/CMakeLists.txt
new file mode 100644
index 0000000000..26af119852
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snprintf/test8/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test8.c
+)
+
+add_executable(paltest_snprintf_test8
+ ${SOURCES}
+)
+
+add_dependencies(paltest_snprintf_test8 coreclrpal)
+
+target_link_libraries(paltest_snprintf_test8
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_snprintf/test8/test8.c b/src/pal/tests/palsuite/c_runtime/_snprintf/test8/test8.c
new file mode 100644
index 0000000000..60ff1b05b8
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snprintf/test8/test8.c
@@ -0,0 +1,56 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test8.c
+**
+** Purpose: Tests _snprintf with decimal numbers
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../_snprintf.h"
+
+/*
+ * Notes: memcmp is used, as is strlen.
+ */
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ int neg = -42;
+ int pos = 42;
+ INT64 l = 42;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+
+ DoNumTest("foo %d", pos, "foo 42");
+ DoNumTest("foo %ld", 0xFFFF, "foo 65535");
+ DoNumTest("foo %hd", 0xFFFF, "foo -1");
+ DoNumTest("foo %Ld", pos, "foo 42");
+ DoI64Test("foo %I64d", l, "42", "foo 42");
+ DoNumTest("foo %3d", pos, "foo 42");
+ DoNumTest("foo %-3d", pos, "foo 42 ");
+ DoNumTest("foo %.1d", pos, "foo 42");
+ DoNumTest("foo %.3d", pos, "foo 042");
+ DoNumTest("foo %03d", pos, "foo 042");
+ DoNumTest("foo %#d", pos, "foo 42");
+ DoNumTest("foo %+d", pos, "foo +42");
+ DoNumTest("foo % d", pos, "foo 42");
+ DoNumTest("foo %+d", neg, "foo -42");
+ DoNumTest("foo % d", neg, "foo -42");
+
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/_snprintf/test8/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_snprintf/test8/testinfo.dat
new file mode 100644
index 0000000000..f6520d8dde
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snprintf/test8/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _snprintf
+Name = Positive Test for _snprintf
+TYPE = DEFAULT
+EXE1 = test8
+Description
+= Tests _snprintf with decimal numbers
diff --git a/src/pal/tests/palsuite/c_runtime/_snprintf/test9/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_snprintf/test9/CMakeLists.txt
new file mode 100644
index 0000000000..484075919e
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snprintf/test9/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test9.c
+)
+
+add_executable(paltest_snprintf_test9
+ ${SOURCES}
+)
+
+add_dependencies(paltest_snprintf_test9 coreclrpal)
+
+target_link_libraries(paltest_snprintf_test9
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_snprintf/test9/test9.c b/src/pal/tests/palsuite/c_runtime/_snprintf/test9/test9.c
new file mode 100644
index 0000000000..e836bcaee3
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snprintf/test9/test9.c
@@ -0,0 +1,55 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test9.c
+**
+** Purpose: Tests _snprintf with integer numbers
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../_snprintf.h"
+
+/*
+ * Notes: memcmp is used, as is strlen.
+ */
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ int neg = -42;
+ int pos = 42;
+ INT64 l = 42;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+
+ DoNumTest("foo %i", pos, "foo 42");
+ DoNumTest("foo %li", 0xFFFF, "foo 65535");
+ DoNumTest("foo %hi", 0xFFFF, "foo -1");
+ DoNumTest("foo %Li", pos, "foo 42");
+ DoI64Test("foo %I64i", l, "42", "foo 42");
+ DoNumTest("foo %3i", pos, "foo 42");
+ DoNumTest("foo %-3i", pos, "foo 42 ");
+ DoNumTest("foo %.1i", pos, "foo 42");
+ DoNumTest("foo %.3i", pos, "foo 042");
+ DoNumTest("foo %03i", pos, "foo 042");
+ DoNumTest("foo %#i", pos, "foo 42");
+ DoNumTest("foo %+i", pos, "foo +42");
+ DoNumTest("foo % i", pos, "foo 42");
+ DoNumTest("foo %+i", neg, "foo -42");
+ DoNumTest("foo % i", neg, "foo -42");
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/_snprintf/test9/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_snprintf/test9/testinfo.dat
new file mode 100644
index 0000000000..2a64b26030
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snprintf/test9/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _snprintf
+Name = Positive Test for _snprintf
+TYPE = DEFAULT
+EXE1 = test9
+Description
+= Tests _snprintf with integer numbers
diff --git a/src/pal/tests/palsuite/c_runtime/_snwprintf/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_snwprintf/CMakeLists.txt
new file mode 100644
index 0000000000..cafb9536b0
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snwprintf/CMakeLists.txt
@@ -0,0 +1,22 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test10)
+add_subdirectory(test11)
+add_subdirectory(test12)
+add_subdirectory(test13)
+add_subdirectory(test14)
+add_subdirectory(test15)
+add_subdirectory(test16)
+add_subdirectory(test17)
+add_subdirectory(test18)
+add_subdirectory(test19)
+add_subdirectory(test2)
+add_subdirectory(test3)
+add_subdirectory(test4)
+add_subdirectory(test5)
+add_subdirectory(test6)
+add_subdirectory(test7)
+add_subdirectory(test8)
+add_subdirectory(test9)
+
diff --git a/src/pal/tests/palsuite/c_runtime/_snwprintf/_snwprintf.h b/src/pal/tests/palsuite/c_runtime/_snwprintf/_snwprintf.h
new file mode 100644
index 0000000000..73bf4d6c12
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snwprintf/_snwprintf.h
@@ -0,0 +1,199 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: _snwprintf.h
+**
+** Purpose: Containts common testing functions for _snwprintf
+**
+**
+**==========================================================================*/
+
+#ifndef ___SNWPRINTF_H__
+#define ___SNWPRINTF_H__
+
+void DoWStrTest(WCHAR *formatstr, WCHAR *param, WCHAR *checkstr)
+{
+ WCHAR buf[256] = { 0 };
+
+ _snwprintf(buf, 256, formatstr, param);
+
+ if (memcmp(buf, checkstr, wcslen(checkstr) * 2 + 2) != 0)
+ {
+ Fail("ERROR: failed to insert wide string \"%s\" into \"%s\".\n"
+ "Expected \"%s\", got \"%s\".\n", convertC(param),
+ convertC(formatstr), convertC(checkstr), convertC(buf));
+ }
+}
+
+void DoStrTest(WCHAR *formatstr, char *param, WCHAR *checkstr)
+{
+ WCHAR buf[256] = { 0 };
+
+ _snwprintf(buf, 256, formatstr, param);
+
+ if (memcmp(buf, checkstr, wcslen(checkstr) * 2 + 2) != 0)
+ {
+ Fail("ERROR: failed to insert wide string \"%s\" into \"%s\".\n"
+ "Expected \"%s\", got \"%s\".\n",
+ param, convertC(formatstr), convertC(checkstr), convertC(buf));
+ }
+}
+
+void DoPointerTest(WCHAR *formatstr, void* param, WCHAR *checkstr1)
+{
+ WCHAR buf[256] = { 0 };
+
+ _snwprintf(buf, 256, formatstr, param);
+ if (memcmp(buf, checkstr1, wcslen(checkstr1)*2 + 2) != 0)
+ {
+ Fail("ERROR: failed to insert pointer to %#p into \"%s\"\n"
+ "Expected \"%s\", got \"%s\".\n", param, convertC(formatstr),
+ convertC(checkstr1), convertC(buf));
+ }
+}
+
+void DoCountTest(WCHAR *formatstr, int param, WCHAR *checkstr)
+{
+ WCHAR buf[512] = { 0 };
+ int n = -1;
+
+ _snwprintf(buf, 512, formatstr, &n);
+
+ if (n != param)
+ {
+ Fail("ERROR: Expected count parameter to resolve to %d, got %d\n",
+ param, n);
+ }
+
+ if (memcmp(buf, checkstr, wcslen(checkstr)*2 + 2) != 0)
+ {
+ Fail("ERROR: Expected \"%s\" got \"%s\".\n",
+ convertC(checkstr), convertC(buf));
+ }
+}
+
+void DoShortCountTest(WCHAR *formatstr, int param, WCHAR *checkstr)
+{
+ WCHAR buf[256] = { 0 };
+ short int n = -1;
+
+ _snwprintf(buf, 256, formatstr, &n);
+
+ if (n != param)
+ {
+ Fail("ERROR: Expected count parameter to resolve to %d, got %d\n",
+ param, n);
+ }
+
+ if (memcmp(buf, checkstr, wcslen(checkstr)*2 + 2) != 0)
+ {
+ Fail("ERROR: Expected \"%s\" got \"%s\".\n",
+ convertC(checkstr), convertC(buf));
+ }
+}
+
+void DoCharTest(WCHAR *formatstr, char param, WCHAR *checkstr)
+{
+ WCHAR buf[256] = { 0 };
+
+ _snwprintf(buf, 256, formatstr, param);
+ if (memcmp(buf, checkstr, wcslen(checkstr)*2 + 2) != 0)
+ {
+ Fail("ERROR: failed to insert char \'%c\' (%d) into \"%s\"\n"
+ "Expected \"%s\" got \"%s\".\n", param, param,
+ convertC(formatstr), convertC(checkstr), convertC(buf));
+ }
+}
+
+void DoWCharTest(WCHAR *formatstr, WCHAR param, WCHAR *checkstr)
+{
+ WCHAR buf[256] = { 0 };
+
+ _snwprintf(buf, 256, formatstr, param);
+ if (memcmp(buf, checkstr, wcslen(checkstr)*2 + 2) != 0)
+ {
+ Fail("ERROR: failed to insert wide char \'%c\' (%d) into \"%s\"\n"
+ "Expected \"%s\" got \"%s\".\n", (char) param, param,
+ convertC(formatstr), convertC(checkstr), convertC(buf));
+ }
+}
+
+void DoNumTest(WCHAR *formatstr, int value, WCHAR*checkstr)
+{
+ WCHAR buf[256] = { 0 };
+
+ _snwprintf(buf, 256, formatstr, value);
+ if (memcmp(buf, checkstr, wcslen(checkstr)* 2 + 2) != 0)
+ {
+ Fail("ERROR: failed to insert %#x into \"%s\"\n"
+ "Expected \"%s\" got \"%s\".\n", value, convertC(formatstr),
+ convertC(checkstr), convertC(buf));
+ }
+}
+
+
+void DoI64Test(WCHAR *formatstr, INT64 param, char *paramdesc,
+ WCHAR *checkstr1)
+{
+ WCHAR buf[256] = { 0 };
+
+ _snwprintf(buf, 256, formatstr, param);
+ if (memcmp(buf, checkstr1, wcslen(checkstr1)*2 + 2) != 0)
+ {
+ Fail("ERROR: failed to insert %s into \"%s\"\n"
+ "Expected \"%s\", got \"%s\".\n", paramdesc,
+ convertC(formatstr), convertC(checkstr1), convertC(buf));
+ }
+}
+
+void DoDoubleTest(WCHAR *formatstr, double value, WCHAR *checkstr1,
+ WCHAR *checkstr2)
+{
+ WCHAR buf[256] = { 0 };
+
+ _snwprintf(buf, 256, formatstr, value);
+ if (memcmp(buf, checkstr1, wcslen(checkstr1)*2 + 2) != 0 &&
+ memcmp(buf, checkstr2, wcslen(checkstr2)*2 + 2) != 0)
+ {
+ Fail("ERROR: failed to insert %f into \"%s\"\n"
+ "Expected \"%s\" or \"%s\", got \"%s\".\n",
+ value, convertC(formatstr), convertC(checkstr1),
+ convertC(checkstr2), convertC(buf));
+ }
+}
+
+void DoArgumentPrecTest(WCHAR *formatstr, int precision, void *param,
+ char *paramstr, WCHAR *checkstr1, WCHAR *checkstr2)
+{
+ WCHAR buf[256];
+
+ _snwprintf(buf, 256, formatstr, precision, param);
+ if (memcmp(buf, checkstr1, wcslen(checkstr1) + 2) != 0 &&
+ memcmp(buf, checkstr2, wcslen(checkstr2) + 2) != 0)
+ {
+ Fail("ERROR: failed to insert %s into \"%s\" with precision %d\n"
+ "Expected \"%s\" or \"%s\", got \"%s\".\n",
+ paramstr, convertC(formatstr), precision,
+ convertC(checkstr1), convertC(checkstr2) ,convertC(buf));
+ }
+}
+
+void DoArgumentPrecDoubleTest(WCHAR *formatstr, int precision, double param,
+ WCHAR *checkstr)
+{
+ WCHAR buf[256];
+
+ _snwprintf(buf, 256, formatstr, precision, param);
+ if (memcmp(buf, checkstr, wcslen(checkstr) + 2) != 0)
+ {
+ Fail("ERROR: failed to insert %f into \"%s\" with precision %d\n"
+ "Expected \"%s\", got \"%s\".\n", param, convertC(formatstr),
+ precision, convertC(checkstr), convertC(buf));
+ }
+}
+
+#endif
+
diff --git a/src/pal/tests/palsuite/c_runtime/_snwprintf/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_snwprintf/test1/CMakeLists.txt
new file mode 100644
index 0000000000..b4ab6d5161
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snwprintf/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_snwprintf_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_snwprintf_test1 coreclrpal)
+
+target_link_libraries(paltest_snwprintf_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_snwprintf/test1/test1.c b/src/pal/tests/palsuite/c_runtime/_snwprintf/test1/test1.c
new file mode 100644
index 0000000000..5d13aaf05d
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snwprintf/test1/test1.c
@@ -0,0 +1,62 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose: General test to see if _snwprintf works correctly
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../_snwprintf.h"
+
+/* memcmp is used to verify the results, so this test is dependent on it. */
+/* ditto with wcslen */
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ WCHAR *checkstr;
+ WCHAR buf[256] = { 0 };
+ int ret;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+ checkstr = convert("hello world");
+ _snwprintf(buf, 256, checkstr);
+ if (memcmp(checkstr, buf, wcslen(checkstr)*2+2) != 0)
+ {
+ Fail("ERROR: Expected \"%s\", got \"%s\"\n",
+ convertC(checkstr), convertC(buf));
+ }
+
+ _snwprintf(buf, 256, convert("xxxxxxxxxxxxxxxxx"));
+ ret = _snwprintf(buf, 8, checkstr);
+ if (memcmp(checkstr, buf, 16) != 0)
+ {
+ Fail("ERROR: Expected \"%8s\", got \"%8s\"\n",
+ convertC(checkstr), convertC(buf));
+ }
+ if (ret >= 0)
+ {
+ Fail("ERROR: Expected negative return value, got %d.\n", ret);
+ }
+ if (buf[8] != (WCHAR) 'x')
+ {
+ Fail("ERROR: buffer overflow using \"%s\" with length 8.\n",
+ convertC(checkstr));
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/_snwprintf/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_snwprintf/test1/testinfo.dat
new file mode 100644
index 0000000000..079a3b3989
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snwprintf/test1/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _snwprintf
+Name = Positive Test for _snwprintf
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= General test to see if _snwprintf works correctly
diff --git a/src/pal/tests/palsuite/c_runtime/_snwprintf/test10/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_snwprintf/test10/CMakeLists.txt
new file mode 100644
index 0000000000..27aaca3bb9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snwprintf/test10/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test10.c
+)
+
+add_executable(paltest_snwprintf_test10
+ ${SOURCES}
+)
+
+add_dependencies(paltest_snwprintf_test10 coreclrpal)
+
+target_link_libraries(paltest_snwprintf_test10
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_snwprintf/test10/test10.c b/src/pal/tests/palsuite/c_runtime/_snwprintf/test10/test10.c
new file mode 100644
index 0000000000..e8a6d93ea3
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snwprintf/test10/test10.c
@@ -0,0 +1,54 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test10.c
+**
+** Purpose: Tests _snwprintf with octal numbers
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../_snwprintf.h"
+
+/* memcmp is used to verify the results, so this test is dependent on it. */
+/* ditto with wcslen */
+
+int __cdecl main(int argc, char *argv[])
+{
+ int neg = -42;
+ int pos = 42;
+ INT64 l = 42;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+
+ DoNumTest(convert("foo %o"), pos, convert("foo 52"));
+ DoNumTest(convert("foo %lo"), 0xFFFF, convert("foo 177777"));
+ DoNumTest(convert("foo %ho"), 0xFFFF, convert("foo 177777"));
+ DoNumTest(convert("foo %Lo"), pos, convert("foo 52"));
+ DoI64Test(convert("foo %I64o"), l, "42", convert("foo 52"));
+ DoNumTest(convert("foo %3o"), pos, convert("foo 52"));
+ DoNumTest(convert("foo %-3o"), pos, convert("foo 52 "));
+ DoNumTest(convert("foo %.1o"), pos, convert("foo 52"));
+ DoNumTest(convert("foo %.3o"), pos, convert("foo 052"));
+ DoNumTest(convert("foo %03o"), pos, convert("foo 052"));
+ DoNumTest(convert("foo %#o"), pos, convert("foo 052"));
+ DoNumTest(convert("foo %+o"), pos, convert("foo 52"));
+ DoNumTest(convert("foo % o"), pos, convert("foo 52"));
+ DoNumTest(convert("foo %+o"), neg, convert("foo 37777777726"));
+ DoNumTest(convert("foo % o"), neg, convert("foo 37777777726"));
+
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/_snwprintf/test10/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_snwprintf/test10/testinfo.dat
new file mode 100644
index 0000000000..2c07cc6e45
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snwprintf/test10/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _snwprintf
+Name = Positive Test for _snwprintf
+TYPE = DEFAULT
+EXE1 = test10
+Description
+= Tests _snwprintf with octal numbers
diff --git a/src/pal/tests/palsuite/c_runtime/_snwprintf/test11/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_snwprintf/test11/CMakeLists.txt
new file mode 100644
index 0000000000..e18ad4a31b
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snwprintf/test11/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test11.c
+)
+
+add_executable(paltest_snwprintf_test11
+ ${SOURCES}
+)
+
+add_dependencies(paltest_snwprintf_test11 coreclrpal)
+
+target_link_libraries(paltest_snwprintf_test11
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_snwprintf/test11/test11.c b/src/pal/tests/palsuite/c_runtime/_snwprintf/test11/test11.c
new file mode 100644
index 0000000000..95f7f53210
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snwprintf/test11/test11.c
@@ -0,0 +1,54 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test11.c
+**
+** Purpose: Tests _snwprintf with unsigned numbers
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../_snwprintf.h"
+
+/* memcmp is used to verify the results, so this test is dependent on it. */
+/* ditto with wcslen */
+
+int __cdecl main(int argc, char *argv[])
+{
+ int neg = -42;
+ int pos = 42;
+ INT64 l = 42;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+
+ DoNumTest(convert("foo %u"), pos, convert("foo 42"));
+ DoNumTest(convert("foo %lu"), 0xFFFF, convert("foo 65535"));
+ DoNumTest(convert("foo %hu"), 0xFFFF, convert("foo 65535"));
+ DoNumTest(convert("foo %Lu"), pos, convert("foo 42"));
+ DoI64Test(convert("foo %I64u"), l, "42", convert("foo 42"));
+ DoNumTest(convert("foo %3u"), pos, convert("foo 42"));
+ DoNumTest(convert("foo %-3u"), pos, convert("foo 42 "));
+ DoNumTest(convert("foo %.1u"), pos, convert("foo 42"));
+ DoNumTest(convert("foo %.3u"), pos, convert("foo 042"));
+ DoNumTest(convert("foo %03u"), pos, convert("foo 042"));
+ DoNumTest(convert("foo %#u"), pos, convert("foo 42"));
+ DoNumTest(convert("foo %+u"), pos, convert("foo 42"));
+ DoNumTest(convert("foo % u"), pos, convert("foo 42"));
+ DoNumTest(convert("foo %+u"), neg, convert("foo 4294967254"));
+ DoNumTest(convert("foo % u"), neg, convert("foo 4294967254"));
+
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/_snwprintf/test11/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_snwprintf/test11/testinfo.dat
new file mode 100644
index 0000000000..f81a7861bf
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snwprintf/test11/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _snwprintf
+Name = Positive Test for _snwprintf
+TYPE = DEFAULT
+EXE1 = test11
+Description
+= Tests _snwprintf with unsigned numbers
diff --git a/src/pal/tests/palsuite/c_runtime/_snwprintf/test12/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_snwprintf/test12/CMakeLists.txt
new file mode 100644
index 0000000000..f2ae07c1b0
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snwprintf/test12/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test12.c
+)
+
+add_executable(paltest_snwprintf_test12
+ ${SOURCES}
+)
+
+add_dependencies(paltest_snwprintf_test12 coreclrpal)
+
+target_link_libraries(paltest_snwprintf_test12
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_snwprintf/test12/test12.c b/src/pal/tests/palsuite/c_runtime/_snwprintf/test12/test12.c
new file mode 100644
index 0000000000..ab58fa345f
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snwprintf/test12/test12.c
@@ -0,0 +1,54 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test12.c
+**
+** Purpose: Tests _snwprintf with hex numbers (lowercase)
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../_snwprintf.h"
+
+/* memcmp is used to verify the results, so this test is dependent on it. */
+/* ditto with wcslen */
+
+int __cdecl main(int argc, char *argv[])
+{
+ int neg = -42;
+ int pos = 0x1234ab;
+ INT64 l = I64(0x1234567887654321);
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+
+ DoNumTest(convert("foo %x"), pos, convert("foo 1234ab"));
+ DoNumTest(convert("foo %lx"), pos, convert("foo 1234ab"));
+ DoNumTest(convert("foo %hx"), pos, convert("foo 34ab"));
+ DoNumTest(convert("foo %Lx"), pos, convert("foo 1234ab"));
+ DoI64Test(convert("foo %I64x"), l, "0x1234567887654321",
+ convert("foo 1234567887654321"));
+ DoNumTest(convert("foo %7x"), pos, convert("foo 1234ab"));
+ DoNumTest(convert("foo %-7x"), pos, convert("foo 1234ab "));
+ DoNumTest(convert("foo %.1x"), pos, convert("foo 1234ab"));
+ DoNumTest(convert("foo %.7x"), pos, convert("foo 01234ab"));
+ DoNumTest(convert("foo %07x"), pos, convert("foo 01234ab"));
+ DoNumTest(convert("foo %#x"), pos, convert("foo 0x1234ab"));
+ DoNumTest(convert("foo %+x"), pos, convert("foo 1234ab"));
+ DoNumTest(convert("foo % x"), pos, convert("foo 1234ab"));
+ DoNumTest(convert("foo %+x"), neg, convert("foo ffffffd6"));
+ DoNumTest(convert("foo % x"), neg, convert("foo ffffffd6"));
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/_snwprintf/test12/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_snwprintf/test12/testinfo.dat
new file mode 100644
index 0000000000..653babae84
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snwprintf/test12/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _snwprintf
+Name = Positive Test for _snwprintf
+TYPE = DEFAULT
+EXE1 = test12
+Description
+= Tests _snwprintf with hex numbers (lowercase)
diff --git a/src/pal/tests/palsuite/c_runtime/_snwprintf/test13/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_snwprintf/test13/CMakeLists.txt
new file mode 100644
index 0000000000..42847b6bcd
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snwprintf/test13/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test13.c
+)
+
+add_executable(paltest_snwprintf_test13
+ ${SOURCES}
+)
+
+add_dependencies(paltest_snwprintf_test13 coreclrpal)
+
+target_link_libraries(paltest_snwprintf_test13
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_snwprintf/test13/test13.c b/src/pal/tests/palsuite/c_runtime/_snwprintf/test13/test13.c
new file mode 100644
index 0000000000..5a3e22802d
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snwprintf/test13/test13.c
@@ -0,0 +1,54 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test13.c
+**
+** Purpose: Tests _snwprintf with hex numbers (uppercase)
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../_snwprintf.h"
+
+/* memcmp is used to verify the results, so this test is dependent on it. */
+/* ditto with wcslen */
+
+int __cdecl main(int argc, char *argv[])
+{
+ int neg = -42;
+ int pos = 0x1234ab;
+ INT64 l = I64(0x1234567887654321);
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+
+ DoNumTest(convert("foo %X"), pos, convert("foo 1234AB"));
+ DoNumTest(convert("foo %lX"), pos, convert("foo 1234AB"));
+ DoNumTest(convert("foo %hX"), pos, convert("foo 34AB"));
+ DoNumTest(convert("foo %LX"), pos, convert("foo 1234AB"));
+ DoI64Test(convert("foo %I64X"), l, "0x1234567887654321",
+ convert("foo 1234567887654321"));
+ DoNumTest(convert("foo %7X"), pos, convert("foo 1234AB"));
+ DoNumTest(convert("foo %-7X"), pos, convert("foo 1234AB "));
+ DoNumTest(convert("foo %.1X"), pos, convert("foo 1234AB"));
+ DoNumTest(convert("foo %.7X"), pos, convert("foo 01234AB"));
+ DoNumTest(convert("foo %07X"), pos, convert("foo 01234AB"));
+ DoNumTest(convert("foo %#X"), pos, convert("foo 0X1234AB"));
+ DoNumTest(convert("foo %+X"), pos, convert("foo 1234AB"));
+ DoNumTest(convert("foo % X"), pos, convert("foo 1234AB"));
+ DoNumTest(convert("foo %+X"), neg, convert("foo FFFFFFD6"));
+ DoNumTest(convert("foo % X"), neg, convert("foo FFFFFFD6"));
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/_snwprintf/test13/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_snwprintf/test13/testinfo.dat
new file mode 100644
index 0000000000..cdeced6654
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snwprintf/test13/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _snwprintf
+Name = Positive Test for _snwprintf
+TYPE = DEFAULT
+EXE1 = test13
+Description
+= Tests _snwprintf with hex numbers (uppercase)
diff --git a/src/pal/tests/palsuite/c_runtime/_snwprintf/test14/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_snwprintf/test14/CMakeLists.txt
new file mode 100644
index 0000000000..e5cdbfad87
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snwprintf/test14/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test14.c
+)
+
+add_executable(paltest_snwprintf_test14
+ ${SOURCES}
+)
+
+add_dependencies(paltest_snwprintf_test14 coreclrpal)
+
+target_link_libraries(paltest_snwprintf_test14
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_snwprintf/test14/test14.c b/src/pal/tests/palsuite/c_runtime/_snwprintf/test14/test14.c
new file mode 100644
index 0000000000..c34875246d
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snwprintf/test14/test14.c
@@ -0,0 +1,66 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test14.c
+**
+** Purpose: Tests _snwprintf with exponential format doubles (lowercase)
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../_snwprintf.h"
+
+/* memcmp is used to verify the results, so this test is dependent on it. */
+/* ditto with wcslen */
+
+int __cdecl main(int argc, char *argv[])
+{
+ double val = 256.0;
+ double neg = -256.0;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+
+ DoDoubleTest(convert("foo %e"), val, convert("foo 2.560000e+002"),
+ convert("foo 2.560000e+02"));
+ DoDoubleTest(convert("foo %le"), val, convert("foo 2.560000e+002"),
+ convert("foo 2.560000e+02"));
+ DoDoubleTest(convert("foo %he"), val, convert("foo 2.560000e+002"),
+ convert("foo 2.560000e+02"));
+ DoDoubleTest(convert("foo %Le"), val, convert("foo 2.560000e+002"),
+ convert("foo 2.560000e+02"));
+ DoDoubleTest(convert("foo %I64e"), val, convert("foo 2.560000e+002"),
+ convert("foo 2.560000e+02"));
+ DoDoubleTest(convert("foo %14e"), val, convert("foo 2.560000e+002"),
+ convert("foo 2.560000e+02"));
+ DoDoubleTest(convert("foo %-14e"), val, convert("foo 2.560000e+002 "),
+ convert("foo 2.560000e+02 "));
+ DoDoubleTest(convert("foo %.1e"), val, convert("foo 2.6e+002"),
+ convert("foo 2.6e+02"));
+ DoDoubleTest(convert("foo %.8e"), val, convert("foo 2.56000000e+002"),
+ convert("foo 2.56000000e+02"));
+ DoDoubleTest(convert("foo %014e"), val, convert("foo 02.560000e+002"),
+ convert("foo 002.560000e+02"));
+ DoDoubleTest(convert("foo %#e"), val, convert("foo 2.560000e+002"),
+ convert("foo 2.560000e+02"));
+ DoDoubleTest(convert("foo %+e"), val, convert("foo +2.560000e+002"),
+ convert("foo +2.560000e+02"));
+ DoDoubleTest(convert("foo % e"), val, convert("foo 2.560000e+002"),
+ convert("foo 2.560000e+02"));
+ DoDoubleTest(convert("foo %+e"), neg, convert("foo -2.560000e+002"),
+ convert("foo -2.560000e+02"));
+ DoDoubleTest(convert("foo % e"), neg, convert("foo -2.560000e+002"),
+ convert("foo -2.560000e+02"));
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/_snwprintf/test14/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_snwprintf/test14/testinfo.dat
new file mode 100644
index 0000000000..b47611aa44
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snwprintf/test14/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _snwprintf
+Name = Positive Test for _snwprintf
+TYPE = DEFAULT
+EXE1 = test14
+Description
+= Tests _snwprintf with exponential format doubles (lowercase)
diff --git a/src/pal/tests/palsuite/c_runtime/_snwprintf/test15/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_snwprintf/test15/CMakeLists.txt
new file mode 100644
index 0000000000..dc7b4d66e9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snwprintf/test15/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test15.c
+)
+
+add_executable(paltest_snwprintf_test15
+ ${SOURCES}
+)
+
+add_dependencies(paltest_snwprintf_test15 coreclrpal)
+
+target_link_libraries(paltest_snwprintf_test15
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_snwprintf/test15/test15.c b/src/pal/tests/palsuite/c_runtime/_snwprintf/test15/test15.c
new file mode 100644
index 0000000000..f45005b758
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snwprintf/test15/test15.c
@@ -0,0 +1,67 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test15.c
+**
+** Purpose: Tests _snwprintf with exponential format doubles (uppercase)
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../_snwprintf.h"
+
+/* memcmp is used to verify the results, so this test is dependent on it. */
+/* ditto with wcslen */
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ double val = 256.0;
+ double neg = -256.0;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+
+ DoDoubleTest(convert("foo %E"), val, convert("foo 2.560000E+002"),
+ convert("foo 2.560000E+02"));
+ DoDoubleTest(convert("foo %lE"), val, convert("foo 2.560000E+002"),
+ convert("foo 2.560000E+02"));
+ DoDoubleTest(convert("foo %hE"), val, convert("foo 2.560000E+002"),
+ convert("foo 2.560000E+02"));
+ DoDoubleTest(convert("foo %LE"), val, convert("foo 2.560000E+002"),
+ convert("foo 2.560000E+02"));
+ DoDoubleTest(convert("foo %I64E"), val, convert("foo 2.560000E+002"),
+ convert("foo 2.560000E+02"));
+ DoDoubleTest(convert("foo %14E"), val, convert("foo 2.560000E+002"),
+ convert("foo 2.560000E+02"));
+ DoDoubleTest(convert("foo %-14E"), val, convert("foo 2.560000E+002 "),
+ convert("foo 2.560000E+02 "));
+ DoDoubleTest(convert("foo %.1E"), val, convert("foo 2.6E+002"),
+ convert("foo 2.6E+02"));
+ DoDoubleTest(convert("foo %.8E"), val, convert("foo 2.56000000E+002"),
+ convert("foo 2.56000000E+02"));
+ DoDoubleTest(convert("foo %014E"), val, convert("foo 02.560000E+002"),
+ convert("foo 002.560000E+02"));
+ DoDoubleTest(convert("foo %#E"), val, convert("foo 2.560000E+002"),
+ convert("foo 2.560000E+02"));
+ DoDoubleTest(convert("foo %+E"), val, convert("foo +2.560000E+002"),
+ convert("foo +2.560000E+02"));
+ DoDoubleTest(convert("foo % E"), val, convert("foo 2.560000E+002"),
+ convert("foo 2.560000E+02"));
+ DoDoubleTest(convert("foo %+E"), neg, convert("foo -2.560000E+002"),
+ convert("foo -2.560000E+02"));
+ DoDoubleTest(convert("foo % E"), neg, convert("foo -2.560000E+002"),
+ convert("foo -2.560000E+02"));
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/_snwprintf/test15/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_snwprintf/test15/testinfo.dat
new file mode 100644
index 0000000000..2c81391689
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snwprintf/test15/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _snwprintf
+Name = Positive Test for _snwprintf
+TYPE = DEFAULT
+EXE1 = test15
+Description
+= Tests _snwprintf with exponential format doubles (uppercase)
diff --git a/src/pal/tests/palsuite/c_runtime/_snwprintf/test16/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_snwprintf/test16/CMakeLists.txt
new file mode 100644
index 0000000000..f147ad7e67
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snwprintf/test16/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test16.c
+)
+
+add_executable(paltest_snwprintf_test16
+ ${SOURCES}
+)
+
+add_dependencies(paltest_snwprintf_test16 coreclrpal)
+
+target_link_libraries(paltest_snwprintf_test16
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_snwprintf/test16/test16.c b/src/pal/tests/palsuite/c_runtime/_snwprintf/test16/test16.c
new file mode 100644
index 0000000000..88f55bdc10
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snwprintf/test16/test16.c
@@ -0,0 +1,65 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test16.c
+**
+** Purpose: Tests _snwprintf with decimal point format doubles
+**
+**
+**==========================================================================*/
+
+
+#include <palsuite.h>
+#include "../_snwprintf.h"
+
+/* memcmp is used to verify the results, so this test is dependent on it. */
+/* ditto with wcslen */
+
+int __cdecl main(int argc, char *argv[])
+{
+ double val = 2560.001;
+ double neg = -2560.001;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+
+ DoDoubleTest(convert("foo %f"), val, convert("foo 2560.001000"),
+ convert("foo 2560.001000"));
+ DoDoubleTest(convert("foo %lf"), val, convert("foo 2560.001000"),
+ convert("foo 2560.001000"));
+ DoDoubleTest(convert("foo %hf"), val, convert("foo 2560.001000"),
+ convert("foo 2560.001000"));
+ DoDoubleTest(convert("foo %Lf"), val, convert("foo 2560.001000"),
+ convert("foo 2560.001000"));
+ DoDoubleTest(convert("foo %I64f"), val, convert("foo 2560.001000"),
+ convert("foo 2560.001000"));
+ DoDoubleTest(convert("foo %12f"), val, convert("foo 2560.001000"),
+ convert("foo 2560.001000"));
+ DoDoubleTest(convert("foo %-12f"), val, convert("foo 2560.001000 "),
+ convert("foo 2560.001000 "));
+ DoDoubleTest(convert("foo %.1f"), val, convert("foo 2560.0"),
+ convert("foo 2560.0"));
+ DoDoubleTest(convert("foo %.8f"), val, convert("foo 2560.00100000"),
+ convert("foo 2560.00100000"));
+ DoDoubleTest(convert("foo %012f"), val, convert("foo 02560.001000"),
+ convert("foo 02560.001000"));
+ DoDoubleTest(convert("foo %#f"), val, convert("foo 2560.001000"),
+ convert("foo 2560.001000"));
+ DoDoubleTest(convert("foo %+f"), val, convert("foo +2560.001000"),
+ convert("foo +2560.001000"));
+ DoDoubleTest(convert("foo % f"), val, convert("foo 2560.001000"),
+ convert("foo 2560.001000"));
+ DoDoubleTest(convert("foo %+f"), neg, convert("foo -2560.001000"),
+ convert("foo -2560.001000"));
+ DoDoubleTest(convert("foo % f"), neg, convert("foo -2560.001000"),
+ convert("foo -2560.001000"));
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/_snwprintf/test16/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_snwprintf/test16/testinfo.dat
new file mode 100644
index 0000000000..8d844e0b18
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snwprintf/test16/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _snwprintf
+Name = Positive Test for _snwprintf
+TYPE = DEFAULT
+EXE1 = test16
+Description
+= Tests _snwprintf with decimal point format doubles
diff --git a/src/pal/tests/palsuite/c_runtime/_snwprintf/test17/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_snwprintf/test17/CMakeLists.txt
new file mode 100644
index 0000000000..e40d3f4106
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snwprintf/test17/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test17.c
+)
+
+add_executable(paltest_snwprintf_test17
+ ${SOURCES}
+)
+
+add_dependencies(paltest_snwprintf_test17 coreclrpal)
+
+target_link_libraries(paltest_snwprintf_test17
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_snwprintf/test17/test17.c b/src/pal/tests/palsuite/c_runtime/_snwprintf/test17/test17.c
new file mode 100644
index 0000000000..82f2330b48
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snwprintf/test17/test17.c
@@ -0,0 +1,68 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test17.c
+**
+** Purpose: Tests _snwprintf with compact format doubles (lowercase)
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../_snwprintf.h"
+
+/* memcmp is used to verify the results, so this test is dependent on it. */
+/* ditto with wcslen */
+
+int __cdecl main(int argc, char *argv[])
+{
+ double val = 2560.001;
+ double neg = -2560.001;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+
+ DoDoubleTest(convert("foo %g"), val, convert("foo 2560"),
+ convert("foo 2560"));
+ DoDoubleTest(convert("foo %lg"), val, convert("foo 2560"),
+ convert("foo 2560"));
+ DoDoubleTest(convert("foo %hg"), val, convert("foo 2560"),
+ convert("foo 2560"));
+ DoDoubleTest(convert("foo %Lg"), val, convert("foo 2560"),
+ convert("foo 2560"));
+ DoDoubleTest(convert("foo %I64g"), val, convert("foo 2560"),
+ convert("foo 2560"));
+ DoDoubleTest(convert("foo %5g"), val, convert("foo 2560"),
+ convert("foo 2560"));
+ DoDoubleTest(convert("foo %-5g"), val, convert("foo 2560 "),
+ convert("foo 2560 "));
+ DoDoubleTest(convert("foo %.1g"), val, convert("foo 3e+003"),
+ convert("foo 3e+03"));
+ DoDoubleTest(convert("foo %.2g"), val, convert("foo 2.6e+003"),
+ convert("foo 2.6e+03"));
+ DoDoubleTest(convert("foo %.12g"), val, convert("foo 2560.001"),
+ convert("foo 2560.001"));
+ DoDoubleTest(convert("foo %06g"), val, convert("foo 002560"),
+ convert("foo 002560"));
+ DoDoubleTest(convert("foo %#g"), val, convert("foo 2560.00"),
+ convert("foo 2560.00"));
+ DoDoubleTest(convert("foo %+g"), val, convert("foo +2560"),
+ convert("foo +2560"));
+ DoDoubleTest(convert("foo % g"), val, convert("foo 2560"),
+ convert("foo 2560"));
+ DoDoubleTest(convert("foo %+g"), neg, convert("foo -2560"),
+ convert("foo -2560"));
+ DoDoubleTest(convert("foo % g"), neg, convert("foo -2560"),
+ convert("foo -2560"));
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/_snwprintf/test17/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_snwprintf/test17/testinfo.dat
new file mode 100644
index 0000000000..6b01fb3d7d
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snwprintf/test17/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _snwprintf
+Name = Positive Test for _snwprintf
+TYPE = DEFAULT
+EXE1 = test17
+Description
+= Tests _snwprintf with compact format doubles (lowercase)
diff --git a/src/pal/tests/palsuite/c_runtime/_snwprintf/test18/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_snwprintf/test18/CMakeLists.txt
new file mode 100644
index 0000000000..68a014cb66
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snwprintf/test18/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test18.c
+)
+
+add_executable(paltest_snwprintf_test18
+ ${SOURCES}
+)
+
+add_dependencies(paltest_snwprintf_test18 coreclrpal)
+
+target_link_libraries(paltest_snwprintf_test18
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_snwprintf/test18/test18.c b/src/pal/tests/palsuite/c_runtime/_snwprintf/test18/test18.c
new file mode 100644
index 0000000000..dbb6233061
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snwprintf/test18/test18.c
@@ -0,0 +1,69 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test18.c
+**
+** Purpose: Tests _snwprintf with compact format doubles (uppercase)
+**
+**
+**==========================================================================*/
+
+
+
+
+#include <palsuite.h>
+#include "../_snwprintf.h"
+
+/* memcmp is used to verify the results, so this test is dependent on it. */
+/* ditto with wcslen */
+
+int __cdecl main(int argc, char *argv[])
+{
+ double val = 2560.001;
+ double neg = -2560.001;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+
+ DoDoubleTest(convert("foo %G"), val, convert("foo 2560"),
+ convert("foo 2560"));
+ DoDoubleTest(convert("foo %lG"), val, convert("foo 2560"),
+ convert("foo 2560"));
+ DoDoubleTest(convert("foo %hG"), val, convert("foo 2560"),
+ convert("foo 2560"));
+ DoDoubleTest(convert("foo %LG"), val, convert("foo 2560"),
+ convert("foo 2560"));
+ DoDoubleTest(convert("foo %I64G"), val, convert("foo 2560"),
+ convert("foo 2560"));
+ DoDoubleTest(convert("foo %5G"), val, convert("foo 2560"),
+ convert("foo 2560"));
+ DoDoubleTest(convert("foo %-5G"), val, convert("foo 2560 "),
+ convert("foo 2560 "));
+ DoDoubleTest(convert("foo %.1G"), val, convert("foo 3E+003"),
+ convert("foo 3E+03"));
+ DoDoubleTest(convert("foo %.2G"), val, convert("foo 2.6E+003"),
+ convert("foo 2.6E+03"));
+ DoDoubleTest(convert("foo %.12G"), val, convert("foo 2560.001"),
+ convert("foo 2560.001"));
+ DoDoubleTest(convert("foo %06G"), val, convert("foo 002560"),
+ convert("foo 002560"));
+ DoDoubleTest(convert("foo %#G"), val, convert("foo 2560.00"),
+ convert("foo 2560.00"));
+ DoDoubleTest(convert("foo %+G"), val, convert("foo +2560"),
+ convert("foo +2560"));
+ DoDoubleTest(convert("foo % G"), val, convert("foo 2560"),
+ convert("foo 2560"));
+ DoDoubleTest(convert("foo %+G"), neg, convert("foo -2560"),
+ convert("foo -2560"));
+ DoDoubleTest(convert("foo % G"), neg, convert("foo -2560"),
+ convert("foo -2560"));
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/_snwprintf/test18/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_snwprintf/test18/testinfo.dat
new file mode 100644
index 0000000000..480087f560
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snwprintf/test18/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _snwprintf
+Name = Positive Test for _snwprintf
+TYPE = DEFAULT
+EXE1 = test18
+Description
+= Tests _snwprintf with compact format doubles (uppercase)
diff --git a/src/pal/tests/palsuite/c_runtime/_snwprintf/test19/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_snwprintf/test19/CMakeLists.txt
new file mode 100644
index 0000000000..6dc30b4d33
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snwprintf/test19/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test19.c
+)
+
+add_executable(paltest_snwprintf_test19
+ ${SOURCES}
+)
+
+add_dependencies(paltest_snwprintf_test19 coreclrpal)
+
+target_link_libraries(paltest_snwprintf_test19
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_snwprintf/test19/test19.c b/src/pal/tests/palsuite/c_runtime/_snwprintf/test19/test19.c
new file mode 100644
index 0000000000..efb222c6ba
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snwprintf/test19/test19.c
@@ -0,0 +1,90 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test19.c
+**
+** Purpose: Tests _snwprintf with argument specified precision
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../_snwprintf.h"
+
+int __cdecl main(int argc, char *argv[])
+{
+ int n = -1;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+ DoArgumentPrecTest(convert("%.*s"), 2, convert("bar"), "bar",
+ convert("ba"), convert("ba"));
+ DoArgumentPrecTest(convert("%.*S"), 2, "bar", "bar",
+ convert("ba"), convert("ba"));
+ DoArgumentPrecTest(convert("%.*n"), 3, &n, "pointer to int",
+ convert(""), convert(""));
+ if (n != 0)
+ {
+ Fail("ERROR: Expected count parameter to resolve to %d, got %X\n",
+ 0, n);
+ }
+
+ DoArgumentPrecTest(convert("%.*c"), 0, (void*)'a', "a",
+ convert("a"), convert("a"));
+ DoArgumentPrecTest(convert("%.*c"), 4, (void*)'a', "a",
+ convert("a"), convert("a"));
+ DoArgumentPrecTest(convert("%.*C"), 0, (void*)'a', "a",
+ convert("a"), convert("a"));
+ DoArgumentPrecTest(convert("%.*C"), 4, (void*)'a', "a",
+ convert("a"), convert("a"));
+ DoArgumentPrecTest(convert("%.*d"), 1, (void*)42, "42",
+ convert("42"), convert("42"));
+ DoArgumentPrecTest(convert("%.*d"), 3, (void*)42, "42",
+ convert("042"), convert("042"));
+ DoArgumentPrecTest(convert("%.*i"), 1, (void*)42, "42",
+ convert("42"), convert("42"));
+ DoArgumentPrecTest(convert("%.*i"), 3, (void*)42, "42",
+ convert("042"), convert("042"));
+ DoArgumentPrecTest(convert("%.*o"), 1, (void*)42, "42",
+ convert("52"), convert("52"));
+ DoArgumentPrecTest(convert("%.*o"), 3, (void*)42, "42",
+ convert("052"), convert("052"));
+ DoArgumentPrecTest(convert("%.*u"), 1, (void*)42, "42",
+ convert("42"), convert("42"));
+ DoArgumentPrecTest(convert("%.*u"), 3, (void*)42, "42",
+ convert("042"), convert("042"));
+ DoArgumentPrecTest(convert("%.*x"), 1, (void*)0x42, "0x42",
+ convert("42"), convert("42"));
+ DoArgumentPrecTest(convert("%.*x"), 3, (void*)0x42, "0x42",
+ convert("042"), convert("042"));
+ DoArgumentPrecTest(convert("%.*X"), 1, (void*)0x42, "0x42",
+ convert("42"), convert("42"));
+ DoArgumentPrecTest(convert("%.*X"), 3, (void*)0x42, "0x42",
+ convert("042"), convert("042"));
+ DoArgumentPrecDoubleTest(convert("%.*e"), 1, 2.01, convert("2.0e+000"));
+ DoArgumentPrecDoubleTest(convert("%.*e"), 3, 2.01, convert("2.010e+000"));
+ DoArgumentPrecDoubleTest(convert("%.*E"), 1, 2.01, convert("2.0E+000"));
+ DoArgumentPrecDoubleTest(convert("%.*E"), 3, 2.01, convert("2.010E+000"));
+ DoArgumentPrecDoubleTest(convert("%.*f"), 1, 2.01, convert("2.0"));
+ DoArgumentPrecDoubleTest(convert("%.*f"), 3, 2.01, convert("2.010"));
+ DoArgumentPrecDoubleTest(convert("%.*g"), 1, 256.01, convert("3e+002"));
+ DoArgumentPrecDoubleTest(convert("%.*g"), 3, 256.01, convert("256"));
+ DoArgumentPrecDoubleTest(convert("%.*g"), 4, 256.01, convert("256"));
+ DoArgumentPrecDoubleTest(convert("%.*g"), 6, 256.01, convert("256.01"));
+ DoArgumentPrecDoubleTest(convert("%.*G"), 1, 256.01, convert("3E+002"));
+ DoArgumentPrecDoubleTest(convert("%.*G"), 3, 256.01, convert("256"));
+ DoArgumentPrecDoubleTest(convert("%.*G"), 4, 256.01, convert("256"));
+ DoArgumentPrecDoubleTest(convert("%.*G"), 6, 256.01, convert("256.01"));
+
+ PAL_Terminate();
+ return PASS;
+
+}
diff --git a/src/pal/tests/palsuite/c_runtime/_snwprintf/test19/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_snwprintf/test19/testinfo.dat
new file mode 100644
index 0000000000..376cbc84d1
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snwprintf/test19/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _snwprintf
+Name = Positive Test for _snwprintf
+TYPE = DEFAULT
+EXE1 = test19
+Description
+= Tests _snwprintf with argument specified precision
diff --git a/src/pal/tests/palsuite/c_runtime/_snwprintf/test2/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_snwprintf/test2/CMakeLists.txt
new file mode 100644
index 0000000000..9e0d950885
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snwprintf/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test2.c
+)
+
+add_executable(paltest_snwprintf_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_snwprintf_test2 coreclrpal)
+
+target_link_libraries(paltest_snwprintf_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_snwprintf/test2/test2.c b/src/pal/tests/palsuite/c_runtime/_snwprintf/test2/test2.c
new file mode 100644
index 0000000000..974b7967f2
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snwprintf/test2/test2.c
@@ -0,0 +1,44 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test2.c
+**
+** Purpose:Tests _snwprintf with strings
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../_snwprintf.h"
+
+/* memcmp is used to verify the results, so this test is dependent on it. */
+/* ditto with wcslen */
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+ DoWStrTest(convert("foo %s"), convert("bar"), convert("foo bar"));
+ DoStrTest(convert("foo %hs"), "bar", convert("foo bar"));
+ DoWStrTest(convert("foo %ls"), convert("bar"), convert("foo bar"));
+ DoWStrTest(convert("foo %ws"), convert("bar"), convert("foo bar"));
+ DoWStrTest(convert("foo %Ls"), convert("bar"), convert("foo bar"));
+ DoWStrTest(convert("foo %I64s"), convert("bar"), convert("foo bar"));
+ DoWStrTest(convert("foo %5s"), convert("bar"), convert("foo bar"));
+ DoWStrTest(convert("foo %.2s"), convert("bar"), convert("foo ba"));
+ DoWStrTest(convert("foo %5.2s"), convert("bar"), convert("foo ba"));
+ DoWStrTest(convert("foo %-5s"), convert("bar"), convert("foo bar "));
+ DoWStrTest(convert("foo %05s"), convert("bar"), convert("foo 00bar"));
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/_snwprintf/test2/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_snwprintf/test2/testinfo.dat
new file mode 100644
index 0000000000..9c65c93e5a
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snwprintf/test2/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _snwprintf
+Name = Positive Test for _snwprintf
+TYPE = DEFAULT
+EXE1 = test2
+Description
+= Tests _snwprintf with strings
diff --git a/src/pal/tests/palsuite/c_runtime/_snwprintf/test3/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_snwprintf/test3/CMakeLists.txt
new file mode 100644
index 0000000000..4d5a28b0fe
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snwprintf/test3/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test3.c
+)
+
+add_executable(paltest_snwprintf_test3
+ ${SOURCES}
+)
+
+add_dependencies(paltest_snwprintf_test3 coreclrpal)
+
+target_link_libraries(paltest_snwprintf_test3
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_snwprintf/test3/test3.c b/src/pal/tests/palsuite/c_runtime/_snwprintf/test3/test3.c
new file mode 100644
index 0000000000..bfb75ce323
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snwprintf/test3/test3.c
@@ -0,0 +1,44 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test3.c
+**
+** Purpose: Tests _snwprintf with wide strings
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../_snwprintf.h"
+
+/* memcmp is used to verify the results, so this test is dependent on it. */
+/* ditto with wcslen */
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+ DoStrTest(convert("foo %S"), "bar", convert("foo bar"));
+ DoStrTest(convert("foo %hS"), "bar", convert("foo bar"));
+ DoWStrTest(convert("foo %lS"), convert("bar"), convert("foo bar"));
+ DoWStrTest(convert("foo %wS"), convert("bar"), convert("foo bar"));
+ DoStrTest(convert("foo %LS"), "bar", convert("foo bar"));
+ DoStrTest(convert("foo %I64S"), "bar", convert("foo bar"));
+ DoStrTest(convert("foo %5S"), "bar", convert("foo bar"));
+ DoStrTest(convert("foo %.2S"), "bar", convert("foo ba"));
+ DoStrTest(convert("foo %5.2S"), "bar", convert("foo ba"));
+ DoStrTest(convert("foo %-5S"), "bar", convert("foo bar "));
+ DoStrTest(convert("foo %05S"), "bar", convert("foo 00bar"));
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/_snwprintf/test3/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_snwprintf/test3/testinfo.dat
new file mode 100644
index 0000000000..b39f4f56b7
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snwprintf/test3/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _snwprintf
+Name = Positive Test for _snwprintf
+TYPE = DEFAULT
+EXE1 = test3
+Description
+= Tests _snwprintf with wide strings
diff --git a/src/pal/tests/palsuite/c_runtime/_snwprintf/test4/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_snwprintf/test4/CMakeLists.txt
new file mode 100644
index 0000000000..0102b0acea
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snwprintf/test4/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test4.c
+)
+
+add_executable(paltest_snwprintf_test4
+ ${SOURCES}
+)
+
+add_dependencies(paltest_snwprintf_test4 coreclrpal)
+
+target_link_libraries(paltest_snwprintf_test4
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_snwprintf/test4/test4.c b/src/pal/tests/palsuite/c_runtime/_snwprintf/test4/test4.c
new file mode 100644
index 0000000000..28f7998591
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snwprintf/test4/test4.c
@@ -0,0 +1,71 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test4.c
+**
+** Purpose: Tests _snwprintf with pointers
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../_snwprintf.h"
+
+/* memcmp is used to verify the results, so this test is dependent on it. */
+/* ditto with wcslen */
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ void *ptr = (void*) 0x123456;
+ INT64 lptr = I64(0x1234567887654321);
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+/*
+** Run only on 64 bit platforms
+*/
+#if defined(BIT64) && defined(PLATFORM_UNIX)
+ Trace("Testing for 64 Bit Platforms \n");
+ DoPointerTest(convert("%p"), NULL, convert("0000000000000000"));
+ DoPointerTest(convert("%p"), ptr, convert("0000000000123456"));
+ DoPointerTest(convert("%17p"), ptr, convert(" 0000000000123456"));
+ DoPointerTest(convert("%17p"), ptr, convert(" 0000000000123456"));
+ DoPointerTest(convert("%-17p"), ptr, convert("0000000000123456 "));
+ DoPointerTest(convert("%+p"), ptr, convert("0000000000123456"));
+ DoPointerTest(convert("% p"), ptr, convert("0000000000123456"));
+ DoPointerTest(convert("%#p"), ptr, convert("0X0000000000123456"));
+ DoPointerTest(convert("%lp"), ptr, convert("00123456"));
+ DoPointerTest(convert("%hp"), ptr, convert("00003456"));
+ DoPointerTest(convert("%Lp"), ptr, convert("00123456"));
+ DoI64Test(convert("%I64p"), lptr, "1234567887654321",
+ convert("1234567887654321"));
+#else
+ Trace("Testing for Non 64 Bit Platforms \n");
+ DoPointerTest(convert("%p"), NULL, convert("00000000"));
+ DoPointerTest(convert("%p"), ptr, convert("00123456"));
+ DoPointerTest(convert("%9p"), ptr, convert(" 00123456"));
+ DoPointerTest(convert("%09p"), ptr, convert(" 00123456"));
+ DoPointerTest(convert("%-9p"), ptr, convert("00123456 "));
+ DoPointerTest(convert("%+p"), ptr, convert("00123456"));
+ DoPointerTest(convert("% p"), ptr, convert("00123456"));
+ DoPointerTest(convert("%#p"), ptr, convert("0X00123456"));
+ DoPointerTest(convert("%lp"), ptr, convert("00123456"));
+ DoPointerTest(convert("%hp"), ptr, convert("00003456"));
+ DoPointerTest(convert("%Lp"), ptr, convert("00123456"));
+ DoI64Test(convert("%I64p"), lptr, "1234567887654321",
+ convert("1234567887654321"));
+#endif
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/_snwprintf/test4/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_snwprintf/test4/testinfo.dat
new file mode 100644
index 0000000000..3f3600160f
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snwprintf/test4/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _snwprintf
+Name = Positive Test for _snwprintf
+TYPE = DEFAULT
+EXE1 = test4
+Description
+= Tests _snwprintf with pointers
diff --git a/src/pal/tests/palsuite/c_runtime/_snwprintf/test5/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_snwprintf/test5/CMakeLists.txt
new file mode 100644
index 0000000000..c835c94845
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snwprintf/test5/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test5.c
+)
+
+add_executable(paltest_snwprintf_test5
+ ${SOURCES}
+)
+
+add_dependencies(paltest_snwprintf_test5 coreclrpal)
+
+target_link_libraries(paltest_snwprintf_test5
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_snwprintf/test5/test5.c b/src/pal/tests/palsuite/c_runtime/_snwprintf/test5/test5.c
new file mode 100644
index 0000000000..bbe459751b
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snwprintf/test5/test5.c
@@ -0,0 +1,63 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test5.c
+**
+** Purpose: Tests _snwprintf with the count specifier
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../_snwprintf.h"
+
+/* memcmp is used to verify the results, so this test is dependent on it. */
+/* ditto with wcslen */
+
+int __cdecl main(int argc, char *argv[])
+{
+ WCHAR *longStr;
+ WCHAR *longResult;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+ longStr = convert("really-long-string-that-just-keeps-going-on-and-on-and-on.."
+ "..................useless-filler.................................."
+ "..................useless-filler.................................."
+ "..................useless-filler.................................."
+ "%n bar");
+ longResult = convert("really-long-string-that-just-keeps-going-on-and-on-and-on.."
+ "..................useless-filler.................................."
+ "..................useless-filler.................................."
+ "..................useless-filler.................................."
+ " bar");
+ DoCountTest(convert("foo %n bar"), 4, convert("foo bar"));
+ DoCountTest(longStr, 257, longResult);
+ DoCountTest(convert("fo%n bar"), 2, convert("fo bar"));
+ DoCountTest(convert("%n"), 0, convert(""));
+ DoCountTest(convert("foo %#n bar"), 4, convert("foo bar"));
+ DoCountTest(convert("foo % n bar"), 4, convert("foo bar"));
+ DoCountTest(convert("foo %+n bar"), 4, convert("foo bar"));
+ DoCountTest(convert("foo %-n bar"), 4, convert("foo bar"));
+ DoCountTest(convert("foo %0n bar"), 4, convert("foo bar"));
+ DoShortCountTest(convert("foo %hn bar"), 4, convert("foo bar"));
+ DoCountTest(convert("foo %ln bar"), 4, convert("foo bar"));
+ DoCountTest(convert("foo %Ln bar"), 4, convert("foo bar"));
+ DoCountTest(convert("foo %I64n bar"), 4, convert("foo bar"));
+ DoCountTest(convert("foo %20.3n bar"), 4, convert("foo bar"));
+
+ free(longStr);
+ free(longResult);
+
+ PAL_Terminate();
+
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/_snwprintf/test5/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_snwprintf/test5/testinfo.dat
new file mode 100644
index 0000000000..2180b81cf5
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snwprintf/test5/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _snwprintf
+Name = Positive Test for _snwprintf
+TYPE = DEFAULT
+EXE1 = test5
+Description
+= Tests _snwprintf with the count specifier
diff --git a/src/pal/tests/palsuite/c_runtime/_snwprintf/test6/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_snwprintf/test6/CMakeLists.txt
new file mode 100644
index 0000000000..37a415ed86
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snwprintf/test6/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test6.c
+)
+
+add_executable(paltest_snwprintf_test6
+ ${SOURCES}
+)
+
+add_dependencies(paltest_snwprintf_test6 coreclrpal)
+
+target_link_libraries(paltest_snwprintf_test6
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_snwprintf/test6/test6.c b/src/pal/tests/palsuite/c_runtime/_snwprintf/test6/test6.c
new file mode 100644
index 0000000000..3d4ed3f882
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snwprintf/test6/test6.c
@@ -0,0 +1,46 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test6.c
+**
+** Purpose: Tests _snwprintf with characters
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../_snwprintf.h"
+
+/* memcmp is used to verify the results, so this test is dependent on it. */
+/* ditto with wcslen */
+
+int __cdecl main(int argc, char *argv[])
+{
+ WCHAR wc = (WCHAR) 'c';
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+
+ DoWCharTest(convert("foo %c"), wc, convert("foo c"));
+ DoCharTest(convert("foo %hc"), 'b', convert("foo b"));
+ DoWCharTest(convert("foo %lc"), wc, convert("foo c"));
+ DoWCharTest(convert("foo %Lc"), wc, convert("foo c"));
+ DoWCharTest(convert("foo %I64c"), wc, convert("foo c"));
+ DoWCharTest(convert("foo %5c"), wc, convert("foo c"));
+ DoWCharTest(convert("foo %.0c"), wc, convert("foo c"));
+ DoWCharTest(convert("foo %-5c"), wc, convert("foo c "));
+ DoWCharTest(convert("foo %05c"), wc, convert("foo 0000c"));
+ DoWCharTest(convert("foo % c"), wc, convert("foo c"));
+ DoWCharTest(convert("foo %#c"), wc, convert("foo c"));
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/_snwprintf/test6/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_snwprintf/test6/testinfo.dat
new file mode 100644
index 0000000000..6a170cd549
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snwprintf/test6/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _snwprintf
+Name = Positive Test for _snwprintf
+TYPE = DEFAULT
+EXE1 = test6
+Description
+= Tests _snwprintf with characters
diff --git a/src/pal/tests/palsuite/c_runtime/_snwprintf/test7/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_snwprintf/test7/CMakeLists.txt
new file mode 100644
index 0000000000..b1a07eeaa4
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snwprintf/test7/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test7.c
+)
+
+add_executable(paltest_snwprintf_test7
+ ${SOURCES}
+)
+
+add_dependencies(paltest_snwprintf_test7 coreclrpal)
+
+target_link_libraries(paltest_snwprintf_test7
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_snwprintf/test7/test7.c b/src/pal/tests/palsuite/c_runtime/_snwprintf/test7/test7.c
new file mode 100644
index 0000000000..7954ff71ca
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snwprintf/test7/test7.c
@@ -0,0 +1,46 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test7.c
+**
+** Purpose: Tests _snwprintf with wide characters
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../_snwprintf.h"
+
+/* memcmp is used to verify the results, so this test is dependent on it. */
+/* ditto with wcslen */
+
+int __cdecl main(int argc, char *argv[])
+{
+ WCHAR wc = (WCHAR) 'c';
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+
+ DoCharTest(convert("foo %C"), 'b', convert("foo b"));
+ DoWCharTest(convert("foo %hC"), wc, convert("foo c"));
+ DoCharTest(convert("foo %lC"), 'b', convert("foo b"));
+ DoCharTest(convert("foo %LC"), 'b', convert("foo b"));
+ DoCharTest(convert("foo %I64C"), 'b', convert("foo b"));
+ DoCharTest(convert("foo %5C"), 'b', convert("foo b"));
+ DoCharTest(convert("foo %.0C"), 'b', convert("foo b"));
+ DoCharTest(convert("foo %-5C"), 'b', convert("foo b "));
+ DoCharTest(convert("foo %05C"), 'b', convert("foo 0000b"));
+ DoCharTest(convert("foo % C"), 'b', convert("foo b"));
+ DoCharTest(convert("foo %#C"), 'b', convert("foo b"));
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/_snwprintf/test7/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_snwprintf/test7/testinfo.dat
new file mode 100644
index 0000000000..5749539e3f
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snwprintf/test7/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _snwprintf
+Name = Positive Test for _snwprintf
+TYPE = DEFAULT
+EXE1 = test7
+Description
+= Tests _snwprintf with wide characters
diff --git a/src/pal/tests/palsuite/c_runtime/_snwprintf/test8/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_snwprintf/test8/CMakeLists.txt
new file mode 100644
index 0000000000..063ee2b9b6
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snwprintf/test8/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test8.c
+)
+
+add_executable(paltest_snwprintf_test8
+ ${SOURCES}
+)
+
+add_dependencies(paltest_snwprintf_test8 coreclrpal)
+
+target_link_libraries(paltest_snwprintf_test8
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_snwprintf/test8/test8.c b/src/pal/tests/palsuite/c_runtime/_snwprintf/test8/test8.c
new file mode 100644
index 0000000000..91c2820076
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snwprintf/test8/test8.c
@@ -0,0 +1,53 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test8.c
+**
+** Purpose: Tests _snwprintf with decimal numbers
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../_snwprintf.h"
+
+/* memcmp is used to verify the results, so this test is dependent on it. */
+/* ditto with wcslen */
+
+int __cdecl main(int argc, char *argv[])
+{
+ int neg = -42;
+ int pos = 42;
+ INT64 l = 42;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+
+ DoNumTest(convert("foo %d"), pos, convert("foo 42"));
+ DoNumTest(convert("foo %ld"), 0xFFFF, convert("foo 65535"));
+ DoNumTest(convert("foo %hd"), 0xFFFF, convert("foo -1"));
+ DoNumTest(convert("foo %Ld"), pos, convert("foo 42"));
+ DoI64Test(convert("foo %I64d"), l, "42", convert("foo 42"));
+ DoNumTest(convert("foo %3d"), pos, convert("foo 42"));
+ DoNumTest(convert("foo %-3d"), pos, convert("foo 42 "));
+ DoNumTest(convert("foo %.1d"), pos, convert("foo 42"));
+ DoNumTest(convert("foo %.3d"), pos, convert("foo 042"));
+ DoNumTest(convert("foo %03d"), pos, convert("foo 042"));
+ DoNumTest(convert("foo %#d"), pos, convert("foo 42"));
+ DoNumTest(convert("foo %+d"), pos, convert("foo +42"));
+ DoNumTest(convert("foo % d"), pos, convert("foo 42"));
+ DoNumTest(convert("foo %+d"), neg, convert("foo -42"));
+ DoNumTest(convert("foo % d"), neg, convert("foo -42"));
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/_snwprintf/test8/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_snwprintf/test8/testinfo.dat
new file mode 100644
index 0000000000..6398f60183
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snwprintf/test8/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _snwprintf
+Name = Positive Test for _snwprintf
+TYPE = DEFAULT
+EXE1 = test8
+Description
+= Tests _snwprintf with decimal numbers
diff --git a/src/pal/tests/palsuite/c_runtime/_snwprintf/test9/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_snwprintf/test9/CMakeLists.txt
new file mode 100644
index 0000000000..8d5e41131d
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snwprintf/test9/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test9.c
+)
+
+add_executable(paltest_snwprintf_test9
+ ${SOURCES}
+)
+
+add_dependencies(paltest_snwprintf_test9 coreclrpal)
+
+target_link_libraries(paltest_snwprintf_test9
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_snwprintf/test9/test9.c b/src/pal/tests/palsuite/c_runtime/_snwprintf/test9/test9.c
new file mode 100644
index 0000000000..f8f994fdcc
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snwprintf/test9/test9.c
@@ -0,0 +1,53 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test9.c
+**
+** Purpose: Tests _snwprintf with integer numbers
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../_snwprintf.h"
+
+/* memcmp is used to verify the results, so this test is dependent on it. */
+/* ditto with wcslen */
+
+int __cdecl main(int argc, char *argv[])
+{
+ int neg = -42;
+ int pos = 42;
+ INT64 l = 42;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+
+ DoNumTest(convert("foo %i"), pos, convert("foo 42"));
+ DoNumTest(convert("foo %li"), 0xFFFF, convert("foo 65535"));
+ DoNumTest(convert("foo %hi"), 0xFFFF, convert("foo -1"));
+ DoNumTest(convert("foo %Li"), pos, convert("foo 42"));
+ DoI64Test(convert("foo %I64i"), l, "42", convert("foo 42"));
+ DoNumTest(convert("foo %3i"), pos, convert("foo 42"));
+ DoNumTest(convert("foo %-3i"), pos, convert("foo 42 "));
+ DoNumTest(convert("foo %.1i"), pos, convert("foo 42"));
+ DoNumTest(convert("foo %.3i"), pos, convert("foo 042"));
+ DoNumTest(convert("foo %03i"), pos, convert("foo 042"));
+ DoNumTest(convert("foo %#i"), pos, convert("foo 42"));
+ DoNumTest(convert("foo %+i"), pos, convert("foo +42"));
+ DoNumTest(convert("foo % i"), pos, convert("foo 42"));
+ DoNumTest(convert("foo %+i"), neg, convert("foo -42"));
+ DoNumTest(convert("foo % i"), neg, convert("foo -42"));
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/_snwprintf/test9/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_snwprintf/test9/testinfo.dat
new file mode 100644
index 0000000000..287de4a9e9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_snwprintf/test9/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _snwprintf
+Name = Positive Test for _snwprintf
+TYPE = DEFAULT
+EXE1 = test9
+Description
+= Tests _snwprintf with integer numbers
diff --git a/src/pal/tests/palsuite/c_runtime/_splitpath/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_splitpath/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_splitpath/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/_splitpath/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_splitpath/test1/CMakeLists.txt
new file mode 100644
index 0000000000..361b9084d7
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_splitpath/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_splitpath_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_splitpath_test1 coreclrpal)
+
+target_link_libraries(paltest_splitpath_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_splitpath/test1/test1.c b/src/pal/tests/palsuite/c_runtime/_splitpath/test1/test1.c
new file mode 100644
index 0000000000..e98354c2ee
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_splitpath/test1/test1.c
@@ -0,0 +1,108 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Passes _splitpath() a series of sample paths and checks that it
+** parses them as expected.
+**
+**
+**==========================================================================*/
+
+
+#include <palsuite.h>
+
+struct testCase
+{
+ const char path[_MAX_PATH]; /* The path to parse. */
+ const char drive[_MAX_DRIVE]; /* The expected values... */
+ const char dir[_MAX_DIR];
+ const char fname[_MAX_FNAME];
+ const char ext[_MAX_EXT];
+};
+
+
+int __cdecl main(int argc, char **argv)
+{
+ struct testCase testCases[] =
+ {
+#if WIN32
+ {"c:\\foo\\bar\\foo.bar", "c:", "\\foo\\bar\\", "foo", ".bar"},
+ {"c:/foo/bar/foo.bar", "c:", "/foo/bar/", "foo", ".bar"},
+ {"c:/foo/bar/foo", "c:", "/foo/bar/", "foo", ""},
+ {"c:/foo/bar/.bar", "c:", "/foo/bar/", "", ".bar"},
+ {"c:/foo/bar/", "c:", "/foo/bar/", "", ""},
+ {"/foo/bar/foo.bar", "", "/foo/bar/", "foo", ".bar"},
+ {"c:foo.bar", "c:", "", "foo", ".bar"}
+#else
+ {"c:\\foo\\bar\\foo.bar", "","c:/foo/bar/", "foo", ".bar"},
+ {"c:/foo/bar/foo.bar", "", "c:/foo/bar/", "foo", ".bar"},
+ {"c:/foo/bar/foo", "", "c:/foo/bar/", "foo", ""},
+ {"c:/foo/bar/.bar", "", "c:/foo/bar/", ".bar", ""},
+ {"c:/foo/bar/", "", "c:/foo/bar/", "", ""},
+ {"/foo/bar/foo.bar", "", "/foo/bar/", "foo", ".bar"},
+ {"c:foo.bar", "", "", "c:foo", ".bar"}
+#endif
+ };
+ char drive[_MAX_DRIVE];
+ char dir[_MAX_DIR];
+ char fname[_MAX_FNAME];
+ char ext[_MAX_EXT];
+
+ int i=0;
+
+ /*
+ * Initialize the PAL and return FAIL if this fails
+ */
+ if (0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ for (i = 0; i < sizeof(testCases)/sizeof(struct testCase); i++)
+ {
+ _splitpath(testCases[i].path, drive, dir, fname, ext);
+
+
+ /*on platforms that don't support drive letters, the drive
+ returned should always be "" */
+ if (strcmp(drive, testCases[i].drive) != 0)
+ {
+ Fail("_splitpath read the path \"%s\" and thought the drive was "
+ "\"%s\" instead of \"%s\"\n"
+ , testCases[i].path, drive, testCases[i].drive);
+ }
+
+ if (strcmp(dir, testCases[i].dir) != 0)
+ {
+ Fail("_splitpath read the path \"%s\" and thought the directory "
+ "was \"%s\" instead of \"%s\"\n"
+ , testCases[i].path, dir, testCases[i].dir);
+ }
+
+ if (strcmp(fname, testCases[i].fname) != 0)
+ {
+ Fail("_splitpath read the path \"%s\" and thought the filename "
+ "was \"%s\" instead of \"%s\"\n"
+ , testCases[i].path, fname, testCases[i].fname);
+ }
+
+ if (strcmp(ext, testCases[i].ext) != 0)
+ {
+ Fail("_splitpath read the path \"%s\" and thought the file "
+ "extension was \"%s\" instead of \"%s\"\n"
+ , testCases[i].path, ext, testCases[i].ext);
+ }
+ }
+ PAL_Terminate();
+ return PASS;
+}
+
+
+
+
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/_splitpath/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_splitpath/test1/testinfo.dat
new file mode 100644
index 0000000000..0a93e27456
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_splitpath/test1/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _splitpath
+Name = Positive Test for _splitpath
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Passes _splitpath() a series of sample paths and checks that it
+= parses them as expected.
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/_stricmp/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_stricmp/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_stricmp/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/_stricmp/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_stricmp/test1/CMakeLists.txt
new file mode 100644
index 0000000000..766660ccfc
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_stricmp/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_stricmp_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_stricmp_test1 coreclrpal)
+
+target_link_libraries(paltest_stricmp_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_stricmp/test1/test1.c b/src/pal/tests/palsuite/c_runtime/_stricmp/test1/test1.c
new file mode 100644
index 0000000000..60e2f9eb8b
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_stricmp/test1/test1.c
@@ -0,0 +1,70 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Do a lower case compare. Check two strings, only different
+** because they have different capitalization, and they should return 0. Try
+** two strings which will return less than 0 (one is smaller than the other).
+** Also try the opposite, to get a return value greater than 0.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+
+/*
+ * Note: The _stricmp is dependent on the LC_CTYPE category of the locale,
+ * and this is ignored by these tests.
+ */
+int __cdecl main(int argc, char *argv[])
+{
+ char *str1 = "foo";
+ char *str2 = "fOo";
+ char *str3 = "foo_bar";
+ char *str4 = "foobar";
+
+ /*
+ * Initialize the PAL and return FAIL if this fails
+ */
+ if (0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ if (_stricmp(str1, str2) != 0)
+ {
+ Fail ("ERROR: _stricmp returning incorrect value:\n"
+ "_stricmp(\"%s\", \"%s\") != 0\n", str1, str2);
+ }
+
+ if (_stricmp(str2, str3) >= 0)
+ {
+ Fail ("ERROR: _stricmp returning incorrect value:\n"
+ "_stricmp(\"%s\", \"%s\") >= 0\n", str2, str3);
+ }
+
+ if (_stricmp(str3, str4) >= 0)
+ {
+ Fail ("ERROR: _stricmp returning incorrect value:\n"
+ "_stricmp(\"%s\", \"%s\") >= 0\n", str3, str4);
+ }
+
+ if (_stricmp(str4, str1) <= 0)
+ {
+ Fail ("ERROR: _stricmp returning incorrect value:\n"
+ "_stricmp(\"%s\", \"%s\") <= 0\n", str4, str1);
+ }
+
+ if (_stricmp(str3, str2) <= 0)
+ {
+ Fail ("ERROR: _stricmp returning incorrect value:\n"
+ "_stricmp(\"%s\", \"%s\") <= 0\n", str2, str3);
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/_stricmp/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_stricmp/test1/testinfo.dat
new file mode 100644
index 0000000000..89d4e0f57b
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_stricmp/test1/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _stricmp
+Name = Positive Test for _stricmp
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Do a lower case compare. Check two strings, only different because they
+= have different capitalization, and they should return 0. Try two strings
+= which will return less than 0 (one is smaller than the other). Also try
+= the opposite, to get a return value greater than 0.
diff --git a/src/pal/tests/palsuite/c_runtime/_strlwr/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_strlwr/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_strlwr/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/_strlwr/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_strlwr/test1/CMakeLists.txt
new file mode 100644
index 0000000000..3a9394ca60
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_strlwr/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_strlwr_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_strlwr_test1 coreclrpal)
+
+target_link_libraries(paltest_strlwr_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_strlwr/test1/test1.c b/src/pal/tests/palsuite/c_runtime/_strlwr/test1/test1.c
new file mode 100644
index 0000000000..1c4015e3e2
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_strlwr/test1/test1.c
@@ -0,0 +1,42 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose:
+** Using memcmp, check to see that after changing a string into all lowercase
+** that it is the lowercase string that was expected.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ char string[] = "aASdff";
+ char checkstr[] = "aasdff";
+ char *ret=NULL;
+
+ /*
+ * Initialize the PAL and return FAIL if this fails
+ */
+ if (0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ ret = _strlwr(string);
+
+ if (memcmp(ret, checkstr, sizeof(checkstr)) != 0)
+ {
+ Fail ("ERROR: _strlwr returning incorrect value\n"
+ "Expected %s, got %s\n", checkstr, ret);
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/_strlwr/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_strlwr/test1/testinfo.dat
new file mode 100644
index 0000000000..4c2a1ad558
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_strlwr/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _strlwr
+Name = Positive Test for _strlwr
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Using memcmp, check to see that after changing a string into all lowercase
+= that it is the lowercase string that was expected.
diff --git a/src/pal/tests/palsuite/c_runtime/_strnicmp/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_strnicmp/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_strnicmp/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/_strnicmp/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_strnicmp/test1/CMakeLists.txt
new file mode 100644
index 0000000000..6a38747592
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_strnicmp/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_strnicmp_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_strnicmp_test1 coreclrpal)
+
+target_link_libraries(paltest_strnicmp_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_strnicmp/test1/test1.c b/src/pal/tests/palsuite/c_runtime/_strnicmp/test1/test1.c
new file mode 100644
index 0000000000..3c915dc621
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_strnicmp/test1/test1.c
@@ -0,0 +1,85 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Test #1 for the _strnicmp function
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ char str1[] = "foo";
+ char str2[] = "foox";
+ char str3[] = "fOo";
+ char str4[] = "ABCDE";
+ char str5[] = "ABCD[";
+ char str6[] = "abcde";
+ char str7[] = "abcd^";
+
+ /*
+ * Initialize the PAL and return FAIL if this fails
+ */
+ if (0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ if (_strnicmp(str1, str2, strlen(str2)) >= 0)
+ {
+ Fail ("ERROR: _strnicmp(\"%s\", \"%s\", %d) returned >= 0\n",
+ str1, str2, strlen(str2));
+ }
+
+ if (_strnicmp(str2, str1, strlen(str2)) <= 0)
+ {
+ Fail ("ERROR: _strnicmp(\"%s\", \"%s\", %d) returned <= 0\n",
+ str2, str1, strlen(str2));
+ }
+
+ if (_strnicmp(str1, str2, strlen(str1)) != 0)
+ {
+ Fail ("ERROR: _strnicmp(\"%s\", \"%s\", %d) returned != 0\n",
+ str1, str2, strlen(str1));
+ }
+
+ if (_strnicmp(str1, str3, strlen(str1)) != 0)
+ {
+ Fail ("ERROR: _strnicmp(\"%s\", \"%s\", %d) returned != 0\n",
+ str1, str3, strlen(str3));
+ }
+
+ if (_strnicmp(str3, str1, strlen(str1)) != 0)
+ {
+ Fail ("ERROR: _strnicmp(\"%s\", \"%s\", %d) returned != 0\n",
+ str3, str1, strlen(str1));
+ }
+
+ /* new testing */
+
+ /* str4 should be greater than str5 */
+ if (_strnicmp(str4, str5, strlen(str4)) <= 0)
+ {
+ Fail ("ERROR: _strnicmp(\"%s\", \"%s\", %d) returned >= 0\n",
+ str4, str5, strlen(str4));
+ }
+
+ /* str6 should be greater than str7 */
+ if (_strnicmp(str6, str7, strlen(str6)) <= 0)
+ {
+ Fail ("ERROR: _strnicmp(\"%s\", \"%s\", %d) returned <= 0\n",
+ str6, str7, strlen(str6));
+ }
+
+
+ PAL_Terminate();
+
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/_strnicmp/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_strnicmp/test1/testinfo.dat
new file mode 100644
index 0000000000..86744c04df
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_strnicmp/test1/testinfo.dat
@@ -0,0 +1,18 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _strnicmp
+Name = Test #1 for _strnicmp
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Take two strings and compare them, giving different lengths.
+= Comparing str1 and str2 with str2 length, should return <0
+= Comparing str2 and str1 with str2 length, should return >0
+= Comparing str1 and str2 with str1 lenght, should return 0
+= Bring in str3, which has a capital, but this function is doing a lower
+= case compare. Just ensure that two strings which differ only by capitals
+= return 0.
diff --git a/src/pal/tests/palsuite/c_runtime/_swab/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_swab/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_swab/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/_swab/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_swab/test1/CMakeLists.txt
new file mode 100644
index 0000000000..fc7fbef8b4
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_swab/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_swab_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_swab_test1 coreclrpal)
+
+target_link_libraries(paltest_swab_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_swab/test1/test1.c b/src/pal/tests/palsuite/c_runtime/_swab/test1/test1.c
new file mode 100644
index 0000000000..203e3b3a06
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_swab/test1/test1.c
@@ -0,0 +1,45 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Calls _swab on a buffer, and checks that it has correctly
+** swapped adjacent bytes
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char **argv)
+{
+ char before[] = "abcdefghijklmn";
+ char after[] = "--------------";
+ const char check[] = "badcfehgjilknm";
+
+ /*
+ * Initialize the PAL and return FAIL if this fails
+ */
+ if (0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ _swab(before, after, sizeof(before));
+ if (memcmp(after, check, sizeof(after)) != 0)
+ {
+ Fail ("_swab did not correctly swap adjacent bytes in a buffer.\n");
+ }
+
+ PAL_Terminate();
+ return PASS;
+
+}
+
+
+
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/_swab/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_swab/test1/testinfo.dat
new file mode 100644
index 0000000000..c59b017762
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_swab/test1/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _swab
+Name = Positive Test for _swab
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Calls _swab on a buffer, and checks that it has correctly swapped
+= adjacent bytes
+
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnprintf/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_vsnprintf/CMakeLists.txt
new file mode 100644
index 0000000000..cafb9536b0
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnprintf/CMakeLists.txt
@@ -0,0 +1,22 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test10)
+add_subdirectory(test11)
+add_subdirectory(test12)
+add_subdirectory(test13)
+add_subdirectory(test14)
+add_subdirectory(test15)
+add_subdirectory(test16)
+add_subdirectory(test17)
+add_subdirectory(test18)
+add_subdirectory(test19)
+add_subdirectory(test2)
+add_subdirectory(test3)
+add_subdirectory(test4)
+add_subdirectory(test5)
+add_subdirectory(test6)
+add_subdirectory(test7)
+add_subdirectory(test8)
+add_subdirectory(test9)
+
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnprintf/_vsnprintf.h b/src/pal/tests/palsuite/c_runtime/_vsnprintf/_vsnprintf.h
new file mode 100644
index 0000000000..240a72f017
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnprintf/_vsnprintf.h
@@ -0,0 +1,124 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: _vsnprintf.h
+**
+** Purpose: Contains common testing functions for _vsnprintf
+**
+**
+**==========================================================================*/
+
+#ifndef __STRINGTEST_H__
+#define __STRINGTEST_H__
+
+/* These functions leaks memory like crazy. C'est la vie. */
+int Testvsnprintf(char* buf, size_t count, const char* format, ...)
+{
+ int retVal;
+ va_list arglist;
+
+ va_start(arglist, format);
+ retVal = _vsnprintf(buf, count, format, arglist);
+ va_end(arglist);
+
+ return (retVal);
+}
+
+
+void DoStrTest(char *formatstr, char* param, char *checkstr)
+{
+ char buf[256] = { 0 };
+
+ Testvsnprintf(buf, 256, formatstr, param);
+ if (memcmp(buf, checkstr, strlen(buf) + 1) != 0)
+ {
+ Fail("ERROR: failed to insert string \"%s\" into \"%s\"\n"
+ "Expected \"%s\" got \"%s\".\n",
+ param, formatstr, checkstr, buf);
+ }
+}
+
+void DoWStrTest(char *formatstr, WCHAR* param, char *checkstr)
+{
+ char buf[256] = { 0 };
+
+ Testvsnprintf(buf, 256, formatstr, param);
+ if (memcmp(buf, checkstr, strlen(buf) + 1) != 0)
+ {
+ Fail("ERROR: failed to insert wide string \"%s\" into \"%s\"\n"
+ "Expected \"%s\" got \"%s\".\n",
+ convertC(param), formatstr, checkstr, buf);
+ }
+}
+
+
+void DoCharTest(char *formatstr, char param, char *checkstr)
+{
+ char buf[256] = { 0 };
+
+ Testvsnprintf(buf, 256, formatstr, param);
+ if (memcmp(buf, checkstr, strlen(buf) + 1) != 0)
+ {
+ Fail("ERROR: failed to insert char \'%c\' (%d) into \"%s\"\n"
+ "Expected \"%s\" got \"%s\".\n",
+ param, param, formatstr, checkstr, buf);
+ }
+}
+
+void DoWCharTest(char *formatstr, WCHAR param, char *checkstr)
+{
+ char buf[256] = { 0 };
+
+ Testvsnprintf(buf, 256, formatstr, param);
+ if (memcmp(buf, checkstr, strlen(buf) + 1) != 0)
+ {
+ Fail("ERROR: failed to insert wide char \'%c\' (%d) into \"%s\"\n"
+ "Expected \"%s\" got \"%s\".\n",
+ (char)param, param, formatstr, checkstr, buf);
+ }
+}
+
+void DoNumTest(char *formatstr, int value, char *checkstr)
+{
+ char buf[256] = { 0 };
+
+ Testvsnprintf(buf, 256, formatstr, value);
+ if (memcmp(buf, checkstr, strlen(buf) + 1) != 0)
+ {
+ Fail("ERROR: failed to insert %#x into \"%s\"\n"
+ "Expected \"%s\" got \"%s\".\n",
+ value, formatstr, checkstr, buf);
+ }
+}
+
+void DoI64Test(char *formatstr, INT64 value, char *valuestr, char *checkstr)
+{
+ char buf[256] = { 0 };
+
+ Testvsnprintf(buf, 256, formatstr, value);
+ if (memcmp(buf, checkstr, strlen(buf) + 1) != 0)
+ {
+ Fail("ERROR: failed to insert %s into \"%s\"\n"
+ "Expected \"%s\" got \"%s\".\n",
+ valuestr, formatstr, checkstr, buf);
+ }
+}
+void DoDoubleTest(char *formatstr, double value, char *checkstr1, char
+ *checkstr2)
+{
+ char buf[256] = { 0 };
+
+ Testvsnprintf(buf,256, formatstr, value);
+ if (memcmp(buf, checkstr1, strlen(checkstr1) + 1) != 0 &&
+ memcmp(buf, checkstr2, strlen(checkstr2) + 1) != 0)
+ {
+ Fail("ERROR: failed to insert %f into \"%s\"\n"
+ "Expected \"%s\" or \"%s\", got \"%s\".\n",
+ value, formatstr, checkstr1, checkstr2, buf);
+ }
+}
+
+#endif
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnprintf/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test1/CMakeLists.txt
new file mode 100644
index 0000000000..7c346a4638
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_vsnprintf_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vsnprintf_test1 coreclrpal)
+
+target_link_libraries(paltest_vsnprintf_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnprintf/test1/test1.c b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test1/test1.c
new file mode 100644
index 0000000000..88aeec27a5
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test1/test1.c
@@ -0,0 +1,55 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test1.c
+**
+** Purpose: Test #1 for the _vsnprintf function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+#include "../_vsnprintf.h"
+
+/*
+ * Notes: memcmp is used, as is strlen.
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ char checkstr[] = "hello world";
+ char buf[256] = { 0 };
+ int ret;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return(FAIL);
+ }
+
+ Testvsnprintf(buf, 256, "hello world");
+
+ if (memcmp(checkstr, buf, strlen(checkstr)+1) != 0)
+ {
+ Fail("ERROR: expected \"%s\" (up to %d chars), got \"%s\"\n",
+ checkstr, 256, buf);
+ }
+
+ Testvsnprintf(buf, 256, "xxxxxxxxxxxxxxxxx");
+
+ ret = Testvsnprintf(buf, 8, "hello world");
+
+ if (ret >= 0)
+ {
+ Fail("ERROR: expected negative return value, got %d", ret);
+ }
+ if (memcmp(checkstr, buf, 8) != 0 || buf[8] != 'x')
+ {
+ Fail("ERROR: expected %s (up to %d chars), got %s\n", checkstr, 8, buf);
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnprintf/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test1/testinfo.dat
new file mode 100644
index 0000000000..0e97856927
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _vsnprintf
+Name = Positive Test for _vsnprintf
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Tests the PAL implementation of the _vsnprintf function.
+= This test is modeled after _snprintf.
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnprintf/test10/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test10/CMakeLists.txt
new file mode 100644
index 0000000000..00dccc260d
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test10/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test10.c
+)
+
+add_executable(paltest_vsnprintf_test10
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vsnprintf_test10 coreclrpal)
+
+target_link_libraries(paltest_vsnprintf_test10
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnprintf/test10/test10.c b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test10/test10.c
new file mode 100644
index 0000000000..3099957ab7
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test10/test10.c
@@ -0,0 +1,50 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test10.c
+**
+** Purpose: Test #10 for the _vsnprintf function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+#include "../_vsnprintf.h"
+
+/*
+ * Notes: memcmp is used, as is strlen.
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ int neg = -42;
+ int pos = 42;
+ INT64 l = 42;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return(FAIL);
+ }
+
+ DoNumTest("foo %o", pos, "foo 52");
+ DoNumTest("foo %lo", 0xFFFF, "foo 177777");
+ DoNumTest("foo %ho", 0xFFFF, "foo 177777");
+ DoNumTest("foo %Lo", pos, "foo 52");
+ DoI64Test("foo %I64o", l, "42", "foo 52");
+ DoNumTest("foo %3o", pos, "foo 52");
+ DoNumTest("foo %-3o", pos, "foo 52 ");
+ DoNumTest("foo %.1o", pos, "foo 52");
+ DoNumTest("foo %.3o", pos, "foo 052");
+ DoNumTest("foo %03o", pos, "foo 052");
+ DoNumTest("foo %#o", pos, "foo 052");
+ DoNumTest("foo %+o", pos, "foo 52");
+ DoNumTest("foo % o", pos, "foo 52");
+ DoNumTest("foo %+o", neg, "foo 37777777726");
+ DoNumTest("foo % o", neg, "foo 37777777726");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnprintf/test10/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test10/testinfo.dat
new file mode 100644
index 0000000000..1399afae05
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test10/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _vsnprintf
+Name = Positive Test for _vsnprintf
+TYPE = DEFAULT
+EXE1 = test10
+Description
+= Tests the PAL implementation of the _vsnprintf function.
+= Tests _vsnprintf with octal numbers.
+= This test is modeled after _snprintf.
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnprintf/test11/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test11/CMakeLists.txt
new file mode 100644
index 0000000000..fd709f2a31
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test11/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test11.c
+)
+
+add_executable(paltest_vsnprintf_test11
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vsnprintf_test11 coreclrpal)
+
+target_link_libraries(paltest_vsnprintf_test11
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnprintf/test11/test11.c b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test11/test11.c
new file mode 100644
index 0000000000..74b0435c6d
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test11/test11.c
@@ -0,0 +1,50 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test11.c
+**
+** Purpose: Test #11 for the _vsnprintf function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+#include "../_vsnprintf.h"
+
+/*
+ * Notes: memcmp is used, as is strlen.
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ int neg = -42;
+ int pos = 42;
+ INT64 l = 42;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return(FAIL);
+ }
+
+ DoNumTest("foo %u", pos, "foo 42");
+ DoNumTest("foo %lu", 0xFFFF, "foo 65535");
+ DoNumTest("foo %hu", 0xFFFF, "foo 65535");
+ DoNumTest("foo %Lu", pos, "foo 42");
+ DoI64Test("foo %I64u", l, "42", "foo 42");
+ DoNumTest("foo %3u", pos, "foo 42");
+ DoNumTest("foo %-3u", pos, "foo 42 ");
+ DoNumTest("foo %.1u", pos, "foo 42");
+ DoNumTest("foo %.3u", pos, "foo 042");
+ DoNumTest("foo %03u", pos, "foo 042");
+ DoNumTest("foo %#u", pos, "foo 42");
+ DoNumTest("foo %+u", pos, "foo 42");
+ DoNumTest("foo % u", pos, "foo 42");
+ DoNumTest("foo %+u", neg, "foo 4294967254");
+ DoNumTest("foo % u", neg, "foo 4294967254");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnprintf/test11/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test11/testinfo.dat
new file mode 100644
index 0000000000..faa7428eff
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test11/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _vsnprintf
+Name = Positive Test for _vsnprintf
+TYPE = DEFAULT
+EXE1 = test11
+Description
+= Tests the PAL implementation of the _vsnprintf function.
+= Tests _vsnprintf with unsigned numbers.
+= This test is modeled after _snprintf.
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnprintf/test12/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test12/CMakeLists.txt
new file mode 100644
index 0000000000..02dac0cb91
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test12/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test12.c
+)
+
+add_executable(paltest_vsnprintf_test12
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vsnprintf_test12 coreclrpal)
+
+target_link_libraries(paltest_vsnprintf_test12
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnprintf/test12/test12.c b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test12/test12.c
new file mode 100644
index 0000000000..3718620971
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test12/test12.c
@@ -0,0 +1,52 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test12.c
+**
+** Purpose: Test #12 for the _vsnprintf function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+#include "../_vsnprintf.h"
+
+/*
+ * Notes: memcmp is used, as is strlen.
+ */
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ int neg = -42;
+ int pos = 0x1234ab;
+ INT64 l = I64(0x1234567887654321);
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return (FAIL);
+ }
+
+ DoNumTest("foo %x", pos, "foo 1234ab");
+ DoNumTest("foo %lx", pos, "foo 1234ab");
+ DoNumTest("foo %hx", pos, "foo 34ab");
+ DoNumTest("foo %Lx", pos, "foo 1234ab");
+ DoI64Test("foo %I64x", l, "0x1234567887654321",
+ "foo 1234567887654321");
+ DoNumTest("foo %7x", pos, "foo 1234ab");
+ DoNumTest("foo %-7x", pos, "foo 1234ab ");
+ DoNumTest("foo %.1x", pos, "foo 1234ab");
+ DoNumTest("foo %.7x", pos, "foo 01234ab");
+ DoNumTest("foo %07x", pos, "foo 01234ab");
+ DoNumTest("foo %#x", pos, "foo 0x1234ab");
+ DoNumTest("foo %+x", pos, "foo 1234ab");
+ DoNumTest("foo % x", pos, "foo 1234ab");
+ DoNumTest("foo %+x", neg, "foo ffffffd6");
+ DoNumTest("foo % x", neg, "foo ffffffd6");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnprintf/test12/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test12/testinfo.dat
new file mode 100644
index 0000000000..d48a5cc60d
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test12/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _vsnprintf
+Name = Positive Test for _vsnprintf
+TYPE = DEFAULT
+EXE1 = test12
+Description
+= Tests the PAL implementation of the _vsnprintf function.
+= Tests _vsnprintf with hex numbers (lowercase).
+= This test is modeled after _snprintf.
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnprintf/test13/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test13/CMakeLists.txt
new file mode 100644
index 0000000000..52562c99f8
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test13/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test13.c
+)
+
+add_executable(paltest_vsnprintf_test13
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vsnprintf_test13 coreclrpal)
+
+target_link_libraries(paltest_vsnprintf_test13
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnprintf/test13/test13.c b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test13/test13.c
new file mode 100644
index 0000000000..1abada4033
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test13/test13.c
@@ -0,0 +1,52 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test13.c
+**
+** Purpose: Test #13 for the _vsnprintf function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+#include "../_vsnprintf.h"
+
+/*
+ * Notes: memcmp is used, as is strlen.
+ */
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ int neg = -42;
+ int pos = 0x1234AB;
+ INT64 l = I64(0x1234567887654321);
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return(FAIL);
+ }
+
+ DoNumTest("foo %X", pos, "foo 1234AB");
+ DoNumTest("foo %lX", pos, "foo 1234AB");
+ DoNumTest("foo %hX", pos, "foo 34AB");
+ DoNumTest("foo %LX", pos, "foo 1234AB");
+ DoI64Test("foo %I64X", l, "0x1234567887654321",
+ "foo 1234567887654321");
+ DoNumTest("foo %7X", pos, "foo 1234AB");
+ DoNumTest("foo %-7X", pos, "foo 1234AB ");
+ DoNumTest("foo %.1X", pos, "foo 1234AB");
+ DoNumTest("foo %.7X", pos, "foo 01234AB");
+ DoNumTest("foo %07X", pos, "foo 01234AB");
+ DoNumTest("foo %#X", pos, "foo 0X1234AB");
+ DoNumTest("foo %+X", pos, "foo 1234AB");
+ DoNumTest("foo % X", pos, "foo 1234AB");
+ DoNumTest("foo %+X", neg, "foo FFFFFFD6");
+ DoNumTest("foo % X", neg, "foo FFFFFFD6");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnprintf/test13/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test13/testinfo.dat
new file mode 100644
index 0000000000..a3f14c21dc
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test13/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _vsnprintf
+Name = Positive Test for _vsnprintf
+TYPE = DEFAULT
+EXE1 = test13
+Description
+= Tests the PAL implementation of the _vsnprintf function.
+= Tests _vsnprintf with hex numbers (uppercase).
+= This test is modeled after _snprintf.
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnprintf/test14/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test14/CMakeLists.txt
new file mode 100644
index 0000000000..3fc8c814a6
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test14/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test14.c
+)
+
+add_executable(paltest_vsnprintf_test14
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vsnprintf_test14 coreclrpal)
+
+target_link_libraries(paltest_vsnprintf_test14
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnprintf/test14/test14.c b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test14/test14.c
new file mode 100644
index 0000000000..2e98f6ad4e
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test14/test14.c
@@ -0,0 +1,50 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test14.c
+**
+** Purpose: Test #14 for the _vsnprintf function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+#include "../_vsnprintf.h"
+
+/*
+ * Notes: memcmp is used, as is strlen.
+ */
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ double val = 256.0;
+ double neg = -256.0;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return(FAIL);
+ }
+
+ DoDoubleTest("foo %e", val, "foo 2.560000e+002", "foo 2.560000e+02");
+ DoDoubleTest("foo %le", val, "foo 2.560000e+002", "foo 2.560000e+02");
+ DoDoubleTest("foo %he", val, "foo 2.560000e+002", "foo 2.560000e+02");
+ DoDoubleTest("foo %Le", val, "foo 2.560000e+002", "foo 2.560000e+02");
+ DoDoubleTest("foo %I64e", val, "foo 2.560000e+002", "foo 2.560000e+02");
+ DoDoubleTest("foo %14e", val, "foo 2.560000e+002", "foo 2.560000e+02");
+ DoDoubleTest("foo %-14e", val, "foo 2.560000e+002 ", "foo 2.560000e+02 ");
+ DoDoubleTest("foo %.1e", val, "foo 2.6e+002", "foo 2.6e+02");
+ DoDoubleTest("foo %.8e", val, "foo 2.56000000e+002", "foo 2.56000000e+02");
+ DoDoubleTest("foo %014e", val, "foo 02.560000e+002", "foo 002.560000e+02");
+ DoDoubleTest("foo %#e", val, "foo 2.560000e+002", "foo 2.560000e+02");
+ DoDoubleTest("foo %+e", val, "foo +2.560000e+002", "foo +2.560000e+02");
+ DoDoubleTest("foo % e", val, "foo 2.560000e+002", "foo 2.560000e+02");
+ DoDoubleTest("foo %+e", neg, "foo -2.560000e+002", "foo -2.560000e+02");
+ DoDoubleTest("foo % e", neg, "foo -2.560000e+002", "foo -2.560000e+02");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnprintf/test14/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test14/testinfo.dat
new file mode 100644
index 0000000000..f4d921c139
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test14/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _vsnprintf
+Name = Positive Test for _vsnprintf
+TYPE = DEFAULT
+EXE1 = test14
+Description
+= Tests the PAL implementation of the _vsnprintf function.
+= Tests _vsnprintf with exponential format doubles (lowercase).
+= This test is modeled after _snprintf.
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnprintf/test15/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test15/CMakeLists.txt
new file mode 100644
index 0000000000..f6bdc83779
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test15/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test15.c
+)
+
+add_executable(paltest_vsnprintf_test15
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vsnprintf_test15 coreclrpal)
+
+target_link_libraries(paltest_vsnprintf_test15
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnprintf/test15/test15.c b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test15/test15.c
new file mode 100644
index 0000000000..4d32e9c638
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test15/test15.c
@@ -0,0 +1,49 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test15.c
+**
+** Purpose: Test #15 for the _vsnprintf function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+#include "../_vsnprintf.h"
+
+/*
+ * Notes: memcmp is used, as is strlen.
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ double val = 256.0;
+ double neg = -256.0;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return(FAIL);
+ }
+
+ DoDoubleTest("foo %E", val, "foo 2.560000E+002", "foo 2.560000E+02");
+ DoDoubleTest("foo %lE", val, "foo 2.560000E+002", "foo 2.560000E+02");
+ DoDoubleTest("foo %hE", val, "foo 2.560000E+002", "foo 2.560000E+02");
+ DoDoubleTest("foo %LE", val, "foo 2.560000E+002", "foo 2.560000E+02");
+ DoDoubleTest("foo %I64E", val, "foo 2.560000E+002", "foo 2.560000E+02");
+ DoDoubleTest("foo %14E", val, "foo 2.560000E+002", "foo 2.560000E+02");
+ DoDoubleTest("foo %-14E", val, "foo 2.560000E+002 ", "foo 2.560000E+02 ");
+ DoDoubleTest("foo %.1E", val, "foo 2.6E+002", "foo 2.6E+02");
+ DoDoubleTest("foo %.8E", val, "foo 2.56000000E+002", "foo 2.56000000E+02");
+ DoDoubleTest("foo %014E", val, "foo 02.560000E+002", "foo 002.560000E+02");
+ DoDoubleTest("foo %#E", val, "foo 2.560000E+002", "foo 2.560000E+02");
+ DoDoubleTest("foo %+E", val, "foo +2.560000E+002", "foo +2.560000E+02");
+ DoDoubleTest("foo % E", val, "foo 2.560000E+002", "foo 2.560000E+02");
+ DoDoubleTest("foo %+E", neg, "foo -2.560000E+002", "foo -2.560000E+02");
+ DoDoubleTest("foo % E", neg, "foo -2.560000E+002", "foo -2.560000E+02");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnprintf/test15/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test15/testinfo.dat
new file mode 100644
index 0000000000..3a6620ba46
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test15/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _vsnprintf
+Name = Positive Test for _vsnprintf
+TYPE = DEFAULT
+EXE1 = test15
+Description
+= Tests the PAL implementation of the _vsnprintf function.
+= Tests _vsnprintf with exponential format doubles (uppercase).
+= This test is modeled after _snprintf.
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnprintf/test16/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test16/CMakeLists.txt
new file mode 100644
index 0000000000..b7b06d19bb
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test16/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test16.c
+)
+
+add_executable(paltest_vsnprintf_test16
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vsnprintf_test16 coreclrpal)
+
+target_link_libraries(paltest_vsnprintf_test16
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnprintf/test16/test16.c b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test16/test16.c
new file mode 100644
index 0000000000..118ba1453c
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test16/test16.c
@@ -0,0 +1,49 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test16.c
+**
+** Purpose: Test #16 for the _vsnprintf function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+#include "../_vsnprintf.h"
+
+/*
+ * Notes: memcmp is used, as is strlen.
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ double val = 2560.001;
+ double neg = -2560.001;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return(FAIL);
+ }
+
+ DoDoubleTest("foo %f", val, "foo 2560.001000", "foo 2560.001000");
+ DoDoubleTest("foo %lf", val, "foo 2560.001000", "foo 2560.001000");
+ DoDoubleTest("foo %hf", val, "foo 2560.001000", "foo 2560.001000");
+ DoDoubleTest("foo %Lf", val, "foo 2560.001000", "foo 2560.001000");
+ DoDoubleTest("foo %I64f", val, "foo 2560.001000", "foo 2560.001000");
+ DoDoubleTest("foo %12f", val, "foo 2560.001000", "foo 2560.001000");
+ DoDoubleTest("foo %-12f", val, "foo 2560.001000 ", "foo 2560.001000 ");
+ DoDoubleTest("foo %.1f", val, "foo 2560.0", "foo 2560.0");
+ DoDoubleTest("foo %.8f", val, "foo 2560.00100000", "foo 2560.00100000");
+ DoDoubleTest("foo %012f", val, "foo 02560.001000", "foo 02560.001000");
+ DoDoubleTest("foo %#f", val, "foo 2560.001000", "foo 2560.001000");
+ DoDoubleTest("foo %+f", val, "foo +2560.001000", "foo +2560.001000");
+ DoDoubleTest("foo % f", val, "foo 2560.001000", "foo 2560.001000");
+ DoDoubleTest("foo %+f", neg, "foo -2560.001000", "foo -2560.001000");
+ DoDoubleTest("foo % f", neg, "foo -2560.001000", "foo -2560.001000");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnprintf/test16/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test16/testinfo.dat
new file mode 100644
index 0000000000..6363f294af
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test16/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _vsnprintf
+Name = Positive Test for _vsnprintf
+TYPE = DEFAULT
+EXE1 = test16
+Description
+= Tests the PAL implementation of the _vsnprintf function.
+= Tests _vsnprintf with decimal point format doubles.
+= This test is modeled after _snprintf.
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnprintf/test17/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test17/CMakeLists.txt
new file mode 100644
index 0000000000..2c91cccd4a
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test17/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test17.c
+)
+
+add_executable(paltest_vsnprintf_test17
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vsnprintf_test17 coreclrpal)
+
+target_link_libraries(paltest_vsnprintf_test17
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnprintf/test17/test17.c b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test17/test17.c
new file mode 100644
index 0000000000..9b5063ddf0
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test17/test17.c
@@ -0,0 +1,50 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test17.c
+**
+** Purpose: Test #17 for the _vsnprintf function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+#include "../_vsnprintf.h"
+
+/*
+ * Notes: memcmp is used, as is strlen.
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ double val = 2560.001;
+ double neg = -2560.001;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return(FAIL);
+ }
+
+ DoDoubleTest("foo %g", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %lg", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %hg", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %Lg", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %I64g", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %5g", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %-5g", val, "foo 2560 ", "foo 2560 ");
+ DoDoubleTest("foo %.1g", val, "foo 3e+003", "foo 3e+03");
+ DoDoubleTest("foo %.2g", val, "foo 2.6e+003", "foo 2.6e+03");
+ DoDoubleTest("foo %.12g", val, "foo 2560.001", "foo 2560.001");
+ DoDoubleTest("foo %06g", val, "foo 002560", "foo 002560");
+ DoDoubleTest("foo %#g", val, "foo 2560.00", "foo 2560.00");
+ DoDoubleTest("foo %+g", val, "foo +2560", "foo +2560");
+ DoDoubleTest("foo % g", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %+g", neg, "foo -2560", "foo -2560");
+ DoDoubleTest("foo % g", neg, "foo -2560", "foo -2560");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnprintf/test17/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test17/testinfo.dat
new file mode 100644
index 0000000000..ecec515de3
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test17/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _vsnprintf
+Name = Positive Test for _vsnprintf
+TYPE = DEFAULT
+EXE1 = test17
+Description
+= Tests the PAL implementation of the _vsnprintf function.
+= Tests _vsnprintf with compact format doubles (lowercase).
+= This test is modeled after _snprintf.
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnprintf/test18/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test18/CMakeLists.txt
new file mode 100644
index 0000000000..1a06ce01ee
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test18/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test18.c
+)
+
+add_executable(paltest_vsnprintf_test18
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vsnprintf_test18 coreclrpal)
+
+target_link_libraries(paltest_vsnprintf_test18
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnprintf/test18/test18.c b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test18/test18.c
new file mode 100644
index 0000000000..5232befc7f
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test18/test18.c
@@ -0,0 +1,50 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test18.c
+**
+** Purpose: Test #18 for the _vsnprintf function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+#include "../_vsnprintf.h"
+
+/*
+ * Notes: memcmp is used, as is strlen.
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ double val = 2560.001;
+ double neg = -2560.001;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return(FAIL);
+ }
+
+ DoDoubleTest("foo %G", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %lG", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %hG", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %LG", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %I64G", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %5G", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %-5G", val, "foo 2560 ", "foo 2560 ");
+ DoDoubleTest("foo %.1G", val, "foo 3E+003", "foo 3E+03");
+ DoDoubleTest("foo %.2G", val, "foo 2.6E+003", "foo 2.6E+03");
+ DoDoubleTest("foo %.12G", val, "foo 2560.001", "foo 2560.001");
+ DoDoubleTest("foo %06G", val, "foo 002560", "foo 002560");
+ DoDoubleTest("foo %#G", val, "foo 2560.00", "foo 2560.00");
+ DoDoubleTest("foo %+G", val, "foo +2560", "foo +2560");
+ DoDoubleTest("foo % G", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %+G", neg, "foo -2560", "foo -2560");
+ DoDoubleTest("foo % G", neg, "foo -2560", "foo -2560");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnprintf/test18/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test18/testinfo.dat
new file mode 100644
index 0000000000..34fd7ae2ff
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test18/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _vsnprintf
+Name = Positive Test for _vsnprintf
+TYPE = DEFAULT
+EXE1 = test18
+Description
+= Tests the PAL implementation of the _vsnprintf function.
+= Tests _vsnprintf with compact format doubles (uppercase).
+= This test is modeled after _snprintf.
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnprintf/test19/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test19/CMakeLists.txt
new file mode 100644
index 0000000000..6f2e42cc6b
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test19/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test19.c
+)
+
+add_executable(paltest_vsnprintf_test19
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vsnprintf_test19 coreclrpal)
+
+target_link_libraries(paltest_vsnprintf_test19
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnprintf/test19/test19.c b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test19/test19.c
new file mode 100644
index 0000000000..075a528aba
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test19/test19.c
@@ -0,0 +1,103 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test19.c
+**
+** Purpose: Test #19 for the _vsnprintf function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+#include "../_vsnprintf.h"
+
+/*
+ * Notes: memcmp is used, as is strlen.
+ */
+
+#define DOTEST(a,b,c,d,e) DoTest(a,b,(void*)c,d,e)
+
+void DoArgumentPrecTest(char *formatstr, int precision, void *param,
+ char *paramstr, char *checkstr1, char *checkstr2)
+{
+ char buf[256];
+
+ Testvsnprintf(buf,256,formatstr, precision, param);
+ if (memcmp(buf, checkstr1, strlen(checkstr1) + 1) != 0 &&
+ memcmp(buf, checkstr2, strlen(checkstr2) + 1) != 0)
+ {
+ Fail("ERROR: failed to insert %s into \"%s\" with precision %d\n"
+ "Expected \"%s\" or \"%s\", got \"%s\".\n",
+ paramstr, formatstr, precision, checkstr1, checkstr2, buf);
+ }
+
+}
+
+void DoArgumentPrecDoubleTest(char *formatstr, int precision, double param,
+ char *checkstr1, char *checkstr2)
+{
+ char buf[256];
+
+ Testvsnprintf(buf,256,formatstr, precision, param);
+ if (memcmp(buf, checkstr1, strlen(checkstr1) + 1) != 0 &&
+ memcmp(buf, checkstr2, strlen(checkstr2) + 1) != 0)
+ {
+ Fail("ERROR: failed to insert %f into \"%s\" with precision %d\n"
+ "Expected \"%s\" or \"%s\", got \"%s\".\n",
+ param, formatstr, precision, checkstr1, checkstr2, buf);
+ }
+
+}
+
+
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return(FAIL);
+ }
+
+
+ DoArgumentPrecTest("%.*s", 2, "bar", "bar", "ba", "ba");
+ DoArgumentPrecTest("%.*S", 2, convert("bar"), "bar", "ba", "ba");
+ DoArgumentPrecTest("%.*c", 0, (void*)'a', "a", "a", "a");
+ DoArgumentPrecTest("%.*c", 4, (void*)'a', "a", "a", "a");
+ DoArgumentPrecTest("%.*C", 0, (void*)'a', "a", "a", "a");
+ DoArgumentPrecTest("%.*C", 4, (void*)'a', "a", "a", "a");
+ DoArgumentPrecTest("%.*d", 1, (void*)42, "42", "42", "42");
+ DoArgumentPrecTest("%.*d", 3, (void*)42, "42", "042", "042");
+ DoArgumentPrecTest("%.*i", 1, (void*)42, "42", "42", "42");
+ DoArgumentPrecTest("%.*i", 3, (void*)42, "42", "042", "042");
+ DoArgumentPrecTest("%.*o", 1, (void*)42, "42", "52", "52");
+ DoArgumentPrecTest("%.*o", 3, (void*)42, "42", "052", "052");
+ DoArgumentPrecTest("%.*u", 1, (void*)42, "42", "42", "42");
+ DoArgumentPrecTest("%.*u", 3, (void*)42, "42", "042", "042");
+ DoArgumentPrecTest("%.*x", 1, (void*)0x42, "0x42", "42", "42");
+ DoArgumentPrecTest("%.*x", 3, (void*)0x42, "0x42", "042", "042");
+ DoArgumentPrecTest("%.*X", 1, (void*)0x42, "0x42", "42", "42");
+ DoArgumentPrecTest("%.*X", 3, (void*)0x42, "0x42", "042", "042");
+
+
+ DoArgumentPrecDoubleTest("%.*e", 1, 2.01, "2.0e+000", "2.0e+00");
+ DoArgumentPrecDoubleTest("%.*e", 3, 2.01, "2.010e+000", "2.010e+00");
+ DoArgumentPrecDoubleTest("%.*E", 1, 2.01, "2.0E+000", "2.0E+00");
+ DoArgumentPrecDoubleTest("%.*E", 3, 2.01, "2.010E+000", "2.010E+00");
+ DoArgumentPrecDoubleTest("%.*f", 1, 2.01, "2.0", "2.0");
+ DoArgumentPrecDoubleTest("%.*f", 3, 2.01, "2.010", "2.010");
+ DoArgumentPrecDoubleTest("%.*g", 1, 256.01, "3e+002", "3e+02");
+ DoArgumentPrecDoubleTest("%.*g", 3, 256.01, "256", "256");
+ DoArgumentPrecDoubleTest("%.*g", 4, 256.01, "256", "256");
+ DoArgumentPrecDoubleTest("%.*g", 6, 256.01, "256.01", "256.01");
+ DoArgumentPrecDoubleTest("%.*G", 1, 256.01, "3E+002", "3E+02");
+ DoArgumentPrecDoubleTest("%.*G", 3, 256.01, "256", "256");
+ DoArgumentPrecDoubleTest("%.*G", 4, 256.01, "256", "256");
+ DoArgumentPrecDoubleTest("%.*G", 6, 256.01, "256.01", "256.01");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnprintf/test19/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test19/testinfo.dat
new file mode 100644
index 0000000000..05f4b5bd87
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test19/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _vsnprintf
+Name = Positive Test for _vsnprintf
+TYPE = DEFAULT
+EXE1 = test19
+Description
+= Tests the PAL implementation of the _vsnprintf function.
+= Tests _vsnprintf with argument specified precision.
+= This test is modeled after _snprintf.
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnprintf/test2/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test2/CMakeLists.txt
new file mode 100644
index 0000000000..a3871d64cf
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test2.c
+)
+
+add_executable(paltest_vsnprintf_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vsnprintf_test2 coreclrpal)
+
+target_link_libraries(paltest_vsnprintf_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnprintf/test2/test2.c b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test2/test2.c
new file mode 100644
index 0000000000..4bac4d2c83
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test2/test2.c
@@ -0,0 +1,44 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test2.c
+**
+** Purpose: Test #2 for the _vsnprintf function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+#include "../_vsnprintf.h"
+/*
+ * Notes: memcmp is used, as is strlen.
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ WCHAR szwStr[] = {'b','a','r','\0'};
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return(FAIL);
+ }
+
+ DoStrTest("foo %s", "bar", "foo bar");
+ DoStrTest("foo %hs", "bar", "foo bar");
+ DoWStrTest("foo %ls", szwStr, "foo bar");
+ DoWStrTest("foo %ws", szwStr, "foo bar");
+ DoStrTest("foo %Ls", "bar", "foo bar");
+ DoStrTest("foo %I64s", "bar", "foo bar");
+ DoStrTest("foo %5s", "bar", "foo bar");
+ DoStrTest("foo %.2s", "bar", "foo ba");
+ DoStrTest("foo %5.2s", "bar", "foo ba");
+ DoStrTest("foo %-5s", "bar", "foo bar ");
+ DoStrTest("foo %05s", "bar", "foo 00bar");
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnprintf/test2/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test2/testinfo.dat
new file mode 100644
index 0000000000..5ee925e3f6
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test2/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _vsnprintf
+Name = Positive Test for _vsnprintf
+TYPE = DEFAULT
+EXE1 = test2
+Description
+= Tests the PAL implementation of the _vsnprintf function.
+= Tests _vsnprintf with strings.
+= This test is modeled after _snprintf.
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnprintf/test3/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test3/CMakeLists.txt
new file mode 100644
index 0000000000..1beae06277
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test3/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test3.c
+)
+
+add_executable(paltest_vsnprintf_test3
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vsnprintf_test3 coreclrpal)
+
+target_link_libraries(paltest_vsnprintf_test3
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnprintf/test3/test3.c b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test3/test3.c
new file mode 100644
index 0000000000..2b30c9ad99
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test3/test3.c
@@ -0,0 +1,43 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test3.c
+**
+** Purpose: Test #3 for the _vsnprintf function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+#include "../_vsnprintf.h"
+
+/*
+ * Notes: memcmp is used, as is strlen.
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return(FAIL);
+ }
+
+ DoWStrTest("foo %S", convert("bar"), "foo bar");
+ DoStrTest("foo %hS", "bar", "foo bar");
+ DoWStrTest("foo %lS", convert("bar"), "foo bar");
+ DoWStrTest("foo %wS", convert("bar"), "foo bar");
+ DoWStrTest("foo %LS", convert("bar"), "foo bar");
+ DoWStrTest("foo %I64S", convert("bar"), "foo bar");
+ DoWStrTest("foo %5S", convert("bar"), "foo bar");
+ DoWStrTest("foo %.2S", convert("bar"), "foo ba");
+ DoWStrTest("foo %5.2S", convert("bar"), "foo ba");
+ DoWStrTest("foo %-5S", convert("bar"), "foo bar ");
+ DoWStrTest("foo %05S", convert("bar"), "foo 00bar");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnprintf/test3/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test3/testinfo.dat
new file mode 100644
index 0000000000..626949c7c8
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test3/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _vsnprintf
+Name = Positive Test for _vsnprintf
+TYPE = DEFAULT
+EXE1 = test3
+Description
+= Tests the PAL implementation of the _vsnprintf function.
+= Tests _vsnprintf with wide strings.
+= This test is modeled after _snprintf.
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnprintf/test4/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test4/CMakeLists.txt
new file mode 100644
index 0000000000..daf7757ddb
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test4/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test4.c
+)
+
+add_executable(paltest_vsnprintf_test4
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vsnprintf_test4 coreclrpal)
+
+target_link_libraries(paltest_vsnprintf_test4
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnprintf/test4/test4.c b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test4/test4.c
new file mode 100644
index 0000000000..33fc49deba
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test4/test4.c
@@ -0,0 +1,98 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test4.c
+**
+** Purpose: Test #4 for the _vsnprintf function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+#include "../_vsnprintf.h"
+
+/*
+ * Notes: memcmp is used, as is strlen.
+ */
+
+static void DoPointerTest(char *formatstr, void* param, char* paramstr,
+ char *checkstr1)
+{
+ char buf[256] = { 0 };
+
+ Testvsnprintf(buf,256, formatstr, param);
+ if (memcmp(buf, checkstr1, strlen(checkstr1) + 1) != 0)
+ {
+ Fail("ERROR: failed to insert %s into \"%s\"\n"
+ "Expected \"%s\" got \"%s\".\n",
+ paramstr, formatstr, checkstr1, buf);
+ }
+}
+
+static void DoI64DoubleTest(char *formatstr, INT64 value, char *valuestr, char
+*checkstr1)
+{
+ char buf[256] = { 0 };
+
+ Testvsnprintf(buf,256,formatstr, value);
+ if (memcmp(buf, checkstr1, strlen(checkstr1) + 1) != 0)
+ {
+ Fail("ERROR: failed to insert %s into \"%s\"\n"
+ "Expected \"%s\", got \"%s\".\n",
+ valuestr, formatstr, checkstr1, buf);
+ }
+}
+
+int __cdecl main(int argc, char *argv[])
+{
+ void *ptr = (void*) 0x123456;
+ INT64 lptr = I64(0x1234567887654321);
+
+ if (PAL_Initialize(argc, argv) != 0)
+ return(FAIL);
+
+
+ /*
+** Run only on 64 bit platforms
+*/
+#if defined(BIT64) && defined(PLATFORM_UNIX)
+ Trace("Testing for 64 Bit Platforms \n");
+ DoPointerTest("%p", NULL, "NULL", "0000000000000000");
+ DoPointerTest("%p", ptr, "pointer to 0x123456", "0000000000123456");
+ DoPointerTest("%17p", ptr, "pointer to 0x123456", " 0000000000123456");
+ DoPointerTest("%17p", ptr, "pointer to 0x123456", " 0000000000123456");
+ DoPointerTest("%-17p", ptr, "pointer to 0x123456", "0000000000123456 ");
+ DoPointerTest("%+p", ptr, "pointer to 0x123456", "0000000000123456");
+ DoPointerTest("%#p", ptr, "pointer to 0x123456", "0X0000000000123456");
+ DoPointerTest("%lp", ptr, "pointer to 0x123456", "00123456");
+ DoPointerTest("%hp", ptr, "pointer to 0x123456", "00003456");
+ DoPointerTest("%Lp", ptr, "pointer to 0x123456", "00123456");
+ DoI64DoubleTest("%I64p", lptr, "pointer to 0x1234567887654321",
+ "1234567887654321");
+
+#else
+ Trace("Testing for Non 64 Bit Platforms \n");
+ DoPointerTest("%p", NULL, "NULL", "00000000");
+ DoPointerTest("%p", ptr, "pointer to 0x123456", "00123456");
+ DoPointerTest("%9p", ptr, "pointer to 0x123456", " 00123456");
+ DoPointerTest("%09p", ptr, "pointer to 0x123456", " 00123456");
+ DoPointerTest("%-9p", ptr, "pointer to 0x123456", "00123456 ");
+ DoPointerTest("%+p", ptr, "pointer to 0x123456", "00123456");
+ DoPointerTest("%#p", ptr, "pointer to 0x123456", "0X00123456");
+ DoPointerTest("%lp", ptr, "pointer to 0x123456", "00123456");
+ DoPointerTest("%hp", ptr, "pointer to 0x123456", "00003456");
+ DoPointerTest("%Lp", ptr, "pointer to 0x123456", "00123456");
+ DoI64DoubleTest("%I64p", lptr, "pointer to 0x1234567887654321",
+ "1234567887654321");
+#endif
+
+
+
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnprintf/test4/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test4/testinfo.dat
new file mode 100644
index 0000000000..bdfdef85ae
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test4/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _vsnprintf
+Name = Positive Test for _vsnprintf
+TYPE = DEFAULT
+EXE1 = test4
+Description
+= Tests the PAL implementation of the _vsnprintf function.
+= Tests _vsnprintf with pointers.
+= This test is modeled after _snprintf.
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnprintf/test5/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test5/CMakeLists.txt
new file mode 100644
index 0000000000..c255b07b42
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test5/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test5.c
+)
+
+add_executable(paltest_vsnprintf_test5
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vsnprintf_test5 coreclrpal)
+
+target_link_libraries(paltest_vsnprintf_test5
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnprintf/test5/test5.c b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test5/test5.c
new file mode 100644
index 0000000000..534e42e293
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test5/test5.c
@@ -0,0 +1,78 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test5.c
+**
+** Purpose: Test #5 for the _vsnprintf function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+#include "../_vsnprintf.h"
+
+/*
+ * Notes: memcmp is used, as is strlen.
+ */
+
+static void DoTest(char *formatstr, int param, char *checkstr)
+{
+ char buf[256] = { 0 };
+ int n = -1;
+
+ Testvsnprintf(buf, 256, formatstr, &n);
+
+ if (n != param)
+ {
+ Fail("ERROR: Expected count parameter to resolve to %d, got %X\n",
+ param, n);
+ }
+ if (memcmp(buf, checkstr, strlen(buf) + 1) != 0)
+ {
+ Fail("ERROR: Expected \"%s\" got \"%s\".\n", checkstr, buf);
+ }
+}
+
+static void DoShortTest(char *formatstr, int param, char *checkstr)
+{
+ char buf[256] = { 0 };
+ short int n = -1;
+
+ Testvsnprintf(buf, 256, formatstr, &n);
+
+ if (n != param)
+ {
+ Fail("ERROR: Expected count parameter to resolve to %d, got %X\n",
+ param, n);
+ }
+ if (memcmp(buf, checkstr, strlen(buf) + 1) != 0)
+ {
+ Fail("ERROR: Expected \"%s\" got \"%s\".\n", checkstr, buf);
+ }
+}
+
+int __cdecl main(int argc, char *argv[])
+{
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return(FAIL);
+ }
+
+ DoTest("foo %n bar", 4, "foo bar");
+ DoTest("foo %#n bar", 4, "foo bar");
+ DoTest("foo % n bar", 4, "foo bar");
+ DoTest("foo %+n bar", 4, "foo bar");
+ DoTest("foo %-n bar", 4, "foo bar");
+ DoTest("foo %0n bar", 4, "foo bar");
+ DoShortTest("foo %hn bar", 4, "foo bar");
+ DoTest("foo %ln bar", 4, "foo bar");
+ DoTest("foo %Ln bar", 4, "foo bar");
+ DoTest("foo %I64n bar", 4, "foo bar");
+ DoTest("foo %20.3n bar", 4, "foo bar");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnprintf/test5/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test5/testinfo.dat
new file mode 100644
index 0000000000..3cd3f7ee86
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test5/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _vsnprintf
+Name = Positive Test for _vsnprintf
+TYPE = DEFAULT
+EXE1 = test5
+Description
+= Tests the PAL implementation of the _vsnprintf function.
+= Tests _vsnprintf with the count specifier.
+= This test is modeled after _snprintf.
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnprintf/test6/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test6/CMakeLists.txt
new file mode 100644
index 0000000000..8e041f4af8
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test6/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test6.c
+)
+
+add_executable(paltest_vsnprintf_test6
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vsnprintf_test6 coreclrpal)
+
+target_link_libraries(paltest_vsnprintf_test6
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnprintf/test6/test6.c b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test6/test6.c
new file mode 100644
index 0000000000..103d1181c2
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test6/test6.c
@@ -0,0 +1,44 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test6.c
+**
+** Purpose: Test #6 for the _vsnprintf function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+#include "../_vsnprintf.h"
+
+/*
+ * Notes: memcmp is used, as is strlen.
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ WCHAR wc = (WCHAR) 'c';
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return(FAIL);
+ }
+
+ DoCharTest("foo %c", 'b', "foo b");
+ DoCharTest("foo %hc", 'b', "foo b");
+ DoWCharTest("foo %lc", wc, "foo c");
+ DoCharTest("foo %Lc", 'b', "foo b");
+ DoCharTest("foo %I64c", 'b', "foo b");
+ DoCharTest("foo %5c", 'b', "foo b");
+ DoCharTest("foo %.0c", 'b', "foo b");
+ DoCharTest("foo %-5c", 'b', "foo b ");
+ DoCharTest("foo %05c", 'b', "foo 0000b");
+ DoCharTest("foo % c", 'b', "foo b");
+ DoCharTest("foo %#c", 'b', "foo b");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnprintf/test6/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test6/testinfo.dat
new file mode 100644
index 0000000000..e379e0b3b8
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test6/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _vsnprintf
+Name = Positive Test for _vsnprintf
+TYPE = DEFAULT
+EXE1 = test6
+Description
+= Tests the PAL implementation of the _vsnprintf function.
+= Tests _vsnprintf with characters.
+= This test is modeled after _snprintf.
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnprintf/test7/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test7/CMakeLists.txt
new file mode 100644
index 0000000000..01f9620184
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test7/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test7.c
+)
+
+add_executable(paltest_vsnprintf_test7
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vsnprintf_test7 coreclrpal)
+
+target_link_libraries(paltest_vsnprintf_test7
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnprintf/test7/test7.c b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test7/test7.c
new file mode 100644
index 0000000000..c7e45d67fa
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test7/test7.c
@@ -0,0 +1,44 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test7.c
+**
+** Purpose: Test #7 for the _vsnprintf function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+#include "../_vsnprintf.h"
+/*
+ * Notes: memcmp is used, as is strlen.
+ */
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ WCHAR wb = (WCHAR) 'b';
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return(FAIL);
+ }
+
+ DoWCharTest("foo %c", wb, "foo b");
+ DoWCharTest("foo %hc", wb, "foo b");
+ DoCharTest("foo %lc", 'c', "foo c");
+ DoWCharTest("foo %Lc", wb, "foo b");
+ DoWCharTest("foo %I64c", wb, "foo b");
+ DoWCharTest("foo %5c", wb, "foo b");
+ DoWCharTest("foo %.0c", wb, "foo b");
+ DoWCharTest("foo %-5c", wb, "foo b ");
+ DoWCharTest("foo %05c", wb, "foo 0000b");
+ DoWCharTest("foo % c", wb, "foo b");
+ DoWCharTest("foo %#c", wb, "foo b");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnprintf/test7/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test7/testinfo.dat
new file mode 100644
index 0000000000..90749400a5
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test7/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _vsnprintf
+Name = Positive Test for _vsnprintf
+TYPE = DEFAULT
+EXE1 = test7
+Description
+= Tests the PAL implementation of the _vsnprintf function.
+= Tests _vsnprintf with wide characters.
+= This test is modeled after _snprintf.
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnprintf/test8/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test8/CMakeLists.txt
new file mode 100644
index 0000000000..9c525de15a
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test8/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test8.c
+)
+
+add_executable(paltest_vsnprintf_test8
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vsnprintf_test8 coreclrpal)
+
+target_link_libraries(paltest_vsnprintf_test8
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnprintf/test8/test8.c b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test8/test8.c
new file mode 100644
index 0000000000..2cefbeac25
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test8/test8.c
@@ -0,0 +1,52 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test8.c
+**
+** Purpose: Test #8 for the _vsnprintf function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+#include "../_vsnprintf.h"
+
+/*
+ * Notes: memcmp is used, as is strlen.
+ */
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ int neg = -42;
+ int pos = 42;
+ INT64 l = 42;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return(FAIL);
+ }
+
+ DoNumTest("foo %d", pos, "foo 42");
+ DoNumTest("foo %ld", 0xFFFF, "foo 65535");
+ DoNumTest("foo %hd", 0xFFFF, "foo -1");
+ DoNumTest("foo %Ld", pos, "foo 42");
+ DoI64Test("foo %I64d", l, "42", "foo 42");
+ DoNumTest("foo %3d", pos, "foo 42");
+ DoNumTest("foo %-3d", pos, "foo 42 ");
+ DoNumTest("foo %.1d", pos, "foo 42");
+ DoNumTest("foo %.3d", pos, "foo 042");
+ DoNumTest("foo %03d", pos, "foo 042");
+ DoNumTest("foo %#d", pos, "foo 42");
+ DoNumTest("foo %+d", pos, "foo +42");
+ DoNumTest("foo % d", pos, "foo 42");
+ DoNumTest("foo %+d", neg, "foo -42");
+ DoNumTest("foo % d", neg, "foo -42");
+
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnprintf/test8/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test8/testinfo.dat
new file mode 100644
index 0000000000..0afc334a67
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test8/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _vsnprintf
+Name = Positive Test for _vsnprintf
+TYPE = DEFAULT
+EXE1 = test8
+Description
+= Tests the PAL implementation of the _vsnprintf function.
+= Tests _vsnprintf with decimal numbers.
+= This test is modeled after _snprintf.
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnprintf/test9/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test9/CMakeLists.txt
new file mode 100644
index 0000000000..bfe2572a6d
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test9/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test9.c
+)
+
+add_executable(paltest_vsnprintf_test9
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vsnprintf_test9 coreclrpal)
+
+target_link_libraries(paltest_vsnprintf_test9
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnprintf/test9/test9.c b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test9/test9.c
new file mode 100644
index 0000000000..d2cd8165c0
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test9/test9.c
@@ -0,0 +1,51 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test9.c
+**
+** Purpose: Test #9 for the _vsnprintf function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+#include "../_vsnprintf.h"
+
+/*
+ * Notes: memcmp is used, as is strlen.
+ */
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ int neg = -42;
+ int pos = 42;
+ INT64 l = 42;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return(FAIL);
+ }
+
+ DoNumTest("foo %i", pos, "foo 42");
+ DoNumTest("foo %li", 0xFFFF, "foo 65535");
+ DoNumTest("foo %hi", 0xFFFF, "foo -1");
+ DoNumTest("foo %Li", pos, "foo 42");
+ DoI64Test("foo %I64i", l, "42", "foo 42");
+ DoNumTest("foo %3i", pos, "foo 42");
+ DoNumTest("foo %-3i", pos, "foo 42 ");
+ DoNumTest("foo %.1i", pos, "foo 42");
+ DoNumTest("foo %.3i", pos, "foo 042");
+ DoNumTest("foo %03i", pos, "foo 042");
+ DoNumTest("foo %#i", pos, "foo 42");
+ DoNumTest("foo %+i", pos, "foo +42");
+ DoNumTest("foo % i", pos, "foo 42");
+ DoNumTest("foo %+i", neg, "foo -42");
+ DoNumTest("foo % i", neg, "foo -42");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnprintf/test9/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test9/testinfo.dat
new file mode 100644
index 0000000000..125724a36b
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnprintf/test9/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _vsnprintf
+Name = Positive Test for _vsnprintf
+TYPE = DEFAULT
+EXE1 = test9
+Description
+= Tests the PAL implementation of the _vsnprintf function.
+= Tests _vsnprintf with integer numbers.
+= This test is modeled after _snprintf.
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnwprintf/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/CMakeLists.txt
new file mode 100644
index 0000000000..cafb9536b0
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/CMakeLists.txt
@@ -0,0 +1,22 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test10)
+add_subdirectory(test11)
+add_subdirectory(test12)
+add_subdirectory(test13)
+add_subdirectory(test14)
+add_subdirectory(test15)
+add_subdirectory(test16)
+add_subdirectory(test17)
+add_subdirectory(test18)
+add_subdirectory(test19)
+add_subdirectory(test2)
+add_subdirectory(test3)
+add_subdirectory(test4)
+add_subdirectory(test5)
+add_subdirectory(test6)
+add_subdirectory(test7)
+add_subdirectory(test8)
+add_subdirectory(test9)
+
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnwprintf/_vsnwprintf.h b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/_vsnwprintf.h
new file mode 100644
index 0000000000..a3a932f822
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/_vsnwprintf.h
@@ -0,0 +1,133 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: _vsnwprintf.h
+**
+** Purpose: Containts common testing functions for _vsnwprintf
+**
+**
+**==========================================================================*/
+
+#ifndef ___VSNWPRINTF_H__
+#define ___VSNWPRINTF_H__
+
+/* These functions leaks memory like crazy. C'est la vie. */
+int TestVsnwprintf(wchar_t* buf, size_t count, const wchar_t* format, ...)
+{
+ int retVal = 0;
+ va_list arglist;
+
+ va_start(arglist, format);
+ retVal = _vsnwprintf(buf, count, format, arglist);
+ va_end(arglist);
+
+ return( retVal);
+}
+
+
+void DoWStrTest(WCHAR *formatstr, WCHAR *param, WCHAR *checkstr)
+{
+ WCHAR buf[256] = { 0 };
+
+ TestVsnwprintf(buf, 256, formatstr, param);
+
+ if (memcmp(buf, checkstr, wcslen(buf) * 2 + 2) != 0)
+ {
+ Fail("ERROR: failed to insert wide string \"%s\" into \"%s\".\n"
+ "Expected \"%s\", got \"%s\".\n",
+ convertC(param), convertC(formatstr),
+ convertC(checkstr), convertC(buf));
+ }
+}
+
+void DoStrTest(WCHAR *formatstr, char *param, WCHAR *checkstr)
+{
+ WCHAR buf[256] = { 0 };
+
+ TestVsnwprintf(buf, 256, formatstr, param);
+
+ if (memcmp(buf, checkstr, wcslen(buf) * 2 + 2) != 0)
+ {
+ Fail("ERROR: failed to insert wide string \"%s\" into \"%s\".\n"
+ "Expected \"%s\", got \"%s\".\n",
+ param, convertC(formatstr), convertC(checkstr),
+ convertC(buf));
+ }
+}
+
+void DoCharTest(WCHAR *formatstr, char param, WCHAR *checkstr)
+{
+ WCHAR buf[256] = { 0 };
+
+ TestVsnwprintf(buf, 256, formatstr, param);
+ if (memcmp(buf, checkstr, wcslen(buf)*2 + 2) != 0)
+ {
+ Fail("ERROR: failed to insert char \'%c\' (%d) into \"%s\"\n"
+ "Expected \"%s\" got \"%s\".\n",
+ param, param, convertC(formatstr), convertC(checkstr),
+ convertC(buf));
+ }
+}
+
+void DoWCharTest(WCHAR *formatstr, WCHAR param, WCHAR *checkstr)
+{
+ WCHAR buf[256] = { 0 };
+
+ TestVsnwprintf(buf, 256, formatstr, param);
+ if (memcmp(buf, checkstr, wcslen(buf)*2 + 2) != 0)
+ {
+ Fail("ERROR: failed to insert wide char \'%c\' (%d) into \"%s\"\n"
+ "Expected \"%s\" got \"%s\".\n",
+ (char) param, param, convertC(formatstr),
+ convertC(checkstr), convertC(buf));
+ }
+}
+
+void DoNumTest(WCHAR *formatstr, int value, WCHAR*checkstr)
+{
+ WCHAR buf[256] = { 0 };
+
+ TestVsnwprintf(buf, 256, formatstr, value);
+ if (memcmp(buf, checkstr, wcslen(buf)* 2 + 2) != 0)
+ {
+ Fail("ERROR: failed to insert %#x into \"%s\"\n"
+ "Expected \"%s\" got \"%s\".\n", value, convertC(formatstr),
+ convertC(checkstr), convertC(buf));
+ }
+}
+
+void DoI64NumTest(WCHAR *formatstr, INT64 value, char *valuestr, WCHAR*checkstr)
+{
+ WCHAR buf[256] = { 0 };
+
+ TestVsnwprintf(buf, 256, formatstr, value);
+ if (memcmp(buf, checkstr, wcslen(buf)* 2 + 2) != 0)
+ {
+ Fail("ERROR: failed to insert %s into \"%s\"\n"
+ "Expected \"%s\" got \"%s\".\n", valuestr, convertC(formatstr),
+ convertC(checkstr), convertC(buf));
+ }
+}
+void DoDoubleTest(WCHAR *formatstr, double value,
+ WCHAR *checkstr1, WCHAR *checkstr2)
+{
+ WCHAR buf[256] = { 0 };
+
+ TestVsnwprintf(buf, 256, formatstr, value);
+ if (memcmp(buf, checkstr1, wcslen(checkstr1) + 2) != 0 &&
+ memcmp(buf, checkstr2, wcslen(checkstr2) + 2) != 0)
+ {
+ Fail("ERROR: failed to insert %f into \"%s\"\n"
+ "Expected \"%s\" or \"%s\", got \"%s\".\n",
+ value,
+ convertC(formatstr),
+ convertC(checkstr1),
+ convertC(checkstr2),
+ convertC(buf));
+ }
+}
+
+#endif
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test1/CMakeLists.txt
new file mode 100644
index 0000000000..52c442d572
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_vsnwprintf_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vsnwprintf_test1 coreclrpal)
+
+target_link_libraries(paltest_vsnwprintf_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test1/test1.c b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test1/test1.c
new file mode 100644
index 0000000000..0238e42611
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test1/test1.c
@@ -0,0 +1,60 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test1.c
+**
+** Purpose: Test #1 for the _vsnwprintf function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+#include "../_vsnwprintf.h"
+
+/* memcmp is used to verify the results, so this test is dependent on it. */
+/* ditto with wcslen */
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ WCHAR *checkstr;
+ WCHAR buf[256] = { 0 };
+ int ret;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return(FAIL);
+ }
+
+ checkstr = convert("hello world");
+ TestVsnwprintf(buf, 256, checkstr);
+ if (memcmp(checkstr, buf, wcslen(checkstr)*2+2) != 0)
+ {
+ Fail("ERROR: Expected \"%s\", got \"%s\"\n",
+ convertC(checkstr), convertC(buf));
+ }
+
+ TestVsnwprintf(buf, 256, convert("xxxxxxxxxxxxxxxxx"));
+ ret = TestVsnwprintf(buf, 8, checkstr);
+ if (memcmp(checkstr, buf, 16) != 0)
+ {
+ Fail("ERROR: Expected \"%8s\", got \"%8s\"\n",
+ convertC(checkstr), convertC(buf));
+ }
+ if (ret >= 0)
+ {
+ Fail("ERROR: Expected negative return value, got %d.\n", ret);
+ }
+ if (buf[8] != (WCHAR) 'x')
+ {
+ Fail("ERROR: buffer overflow using \"%s\" with length 8.\n",
+ convertC(checkstr));
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test1/testinfo.dat
new file mode 100644
index 0000000000..d806fb8ed8
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test1/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _vsnwprintf
+Name = Positive Test for _vsnwprintf
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Tests the PAL implementation of the _vsnwprintf function.
+= General test to see if _vsnwprintf works correctly.
+= This test is modeled after _snwprintf.
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test10/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test10/CMakeLists.txt
new file mode 100644
index 0000000000..86ea1a3160
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test10/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test10.c
+)
+
+add_executable(paltest_vsnwprintf_test10
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vsnwprintf_test10 coreclrpal)
+
+target_link_libraries(paltest_vsnwprintf_test10
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test10/test10.c b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test10/test10.c
new file mode 100644
index 0000000000..6e188e56ff
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test10/test10.c
@@ -0,0 +1,50 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test10.c
+**
+** Purpose: Test #10 for the _vsnwprintf function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+#include "../_vsnwprintf.h"
+
+/* memcmp is used to verify the results, so this test is dependent on it. */
+/* ditto with wcslen */
+
+int __cdecl main(int argc, char *argv[])
+{
+ int neg = -42;
+ int pos = 42;
+ INT64 l = 42;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return(FAIL);
+ }
+
+ DoNumTest(convert("foo %o"), pos, convert("foo 52"));
+ DoNumTest(convert("foo %lo"), 0xFFFF, convert("foo 177777"));
+ DoNumTest(convert("foo %ho"), 0xFFFF, convert("foo 177777"));
+ DoNumTest(convert("foo %Lo"), pos, convert("foo 52"));
+ DoI64NumTest(convert("foo %I64o"), l, "42", convert("foo 52"));
+ DoNumTest(convert("foo %3o"), pos, convert("foo 52"));
+ DoNumTest(convert("foo %-3o"), pos, convert("foo 52 "));
+ DoNumTest(convert("foo %.1o"), pos, convert("foo 52"));
+ DoNumTest(convert("foo %.3o"), pos, convert("foo 052"));
+ DoNumTest(convert("foo %03o"), pos, convert("foo 052"));
+ DoNumTest(convert("foo %#o"), pos, convert("foo 052"));
+ DoNumTest(convert("foo %+o"), pos, convert("foo 52"));
+ DoNumTest(convert("foo % o"), pos, convert("foo 52"));
+ DoNumTest(convert("foo %+o"), neg, convert("foo 37777777726"));
+ DoNumTest(convert("foo % o"), neg, convert("foo 37777777726"));
+
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test10/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test10/testinfo.dat
new file mode 100644
index 0000000000..beb5b41be9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test10/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _vsnwprintf
+Name = Positive Test for _vsnwprintf
+TYPE = DEFAULT
+EXE1 = test10
+Description
+= Tests the PAL implementation of the _vsnwprintf function.
+= Tests _vsnwprintf with octal numbers.
+= This test is modeled after _snwprintf.
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test11/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test11/CMakeLists.txt
new file mode 100644
index 0000000000..c6011dc1de
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test11/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test11.c
+)
+
+add_executable(paltest_vsnwprintf_test11
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vsnwprintf_test11 coreclrpal)
+
+target_link_libraries(paltest_vsnwprintf_test11
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test11/test11.c b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test11/test11.c
new file mode 100644
index 0000000000..af54985bdc
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test11/test11.c
@@ -0,0 +1,50 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test11.c
+**
+** Purpose: Test #11 for the _vsnwprintf function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+#include "../_vsnwprintf.h"
+
+/* memcmp is used to verify the results, so this test is dependent on it. */
+/* ditto with wcslen */
+
+int __cdecl main(int argc, char *argv[])
+{
+ int neg = -42;
+ int pos = 42;
+ INT64 l = 42;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return(FAIL);
+ }
+
+ DoNumTest(convert("foo %u"), pos, convert("foo 42"));
+ DoNumTest(convert("foo %lu"), 0xFFFF, convert("foo 65535"));
+ DoNumTest(convert("foo %hu"), 0xFFFF, convert("foo 65535"));
+ DoNumTest(convert("foo %Lu"), pos, convert("foo 42"));
+ DoI64NumTest(convert("foo %I64u"), l, "42", convert("foo 42"));
+ DoNumTest(convert("foo %3u"), pos, convert("foo 42"));
+ DoNumTest(convert("foo %-3u"), pos, convert("foo 42 "));
+ DoNumTest(convert("foo %.1u"), pos, convert("foo 42"));
+ DoNumTest(convert("foo %.3u"), pos, convert("foo 042"));
+ DoNumTest(convert("foo %03u"), pos, convert("foo 042"));
+ DoNumTest(convert("foo %#u"), pos, convert("foo 42"));
+ DoNumTest(convert("foo %+u"), pos, convert("foo 42"));
+ DoNumTest(convert("foo % u"), pos, convert("foo 42"));
+ DoNumTest(convert("foo %+u"), neg, convert("foo 4294967254"));
+ DoNumTest(convert("foo % u"), neg, convert("foo 4294967254"));
+
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test11/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test11/testinfo.dat
new file mode 100644
index 0000000000..083b0fa5af
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test11/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _vsnwprintf
+Name = Positive Test for _vsnwprintf
+TYPE = DEFAULT
+EXE1 = test11
+Description
+= Tests the PAL implementation of the _vsnwprintf function.
+= Tests _vsnwprintf with unsigned numbers.
+= This test is modeled after _snwprintf.
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test12/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test12/CMakeLists.txt
new file mode 100644
index 0000000000..bd9652c2fb
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test12/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test12.c
+)
+
+add_executable(paltest_vsnwprintf_test12
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vsnwprintf_test12 coreclrpal)
+
+target_link_libraries(paltest_vsnwprintf_test12
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test12/test12.c b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test12/test12.c
new file mode 100644
index 0000000000..b593a82b4b
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test12/test12.c
@@ -0,0 +1,50 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test12.c
+**
+** Purpose: Test #12 for the _vsnwprintf function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+#include "../_vsnwprintf.h"
+
+/* memcmp is used to verify the results, so this test is dependent on it. */
+/* ditto with wcslen */
+
+int __cdecl main(int argc, char *argv[])
+{
+ int neg = -42;
+ int pos = 0x1234ab;
+ INT64 l = I64(0x1234567887654321);
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return(FAIL);
+ }
+
+ DoNumTest(convert("foo %x"), pos, convert("foo 1234ab"));
+ DoNumTest(convert("foo %lx"), pos, convert("foo 1234ab"));
+ DoNumTest(convert("foo %hx"), pos, convert("foo 34ab"));
+ DoNumTest(convert("foo %Lx"), pos, convert("foo 1234ab"));
+ DoI64NumTest(convert("foo %I64x"), l, "0x1234567887654321",
+ convert("foo 1234567887654321"));
+ DoNumTest(convert("foo %7x"), pos, convert("foo 1234ab"));
+ DoNumTest(convert("foo %-7x"), pos, convert("foo 1234ab "));
+ DoNumTest(convert("foo %.1x"), pos, convert("foo 1234ab"));
+ DoNumTest(convert("foo %.7x"), pos, convert("foo 01234ab"));
+ DoNumTest(convert("foo %07x"), pos, convert("foo 01234ab"));
+ DoNumTest(convert("foo %#x"), pos, convert("foo 0x1234ab"));
+ DoNumTest(convert("foo %+x"), pos, convert("foo 1234ab"));
+ DoNumTest(convert("foo % x"), pos, convert("foo 1234ab"));
+ DoNumTest(convert("foo %+x"), neg, convert("foo ffffffd6"));
+ DoNumTest(convert("foo % x"), neg, convert("foo ffffffd6"));
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test12/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test12/testinfo.dat
new file mode 100644
index 0000000000..a4450ed8d0
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test12/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _vsnwprintf
+Name = Positive Test for _vsnwprintf
+TYPE = DEFAULT
+EXE1 = test12
+Description
+= Tests the PAL implementation of the _vsnwprintf function.
+= Tests _vsnwprintf with hex numbers (lowercase).
+= This test is modeled after _snwprintf.
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test13/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test13/CMakeLists.txt
new file mode 100644
index 0000000000..c608ab84e3
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test13/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test13.c
+)
+
+add_executable(paltest_vsnwprintf_test13
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vsnwprintf_test13 coreclrpal)
+
+target_link_libraries(paltest_vsnwprintf_test13
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test13/test13.c b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test13/test13.c
new file mode 100644
index 0000000000..59a9dc496f
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test13/test13.c
@@ -0,0 +1,50 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test13.c
+**
+** Purpose: Test #13 for the _vsnwprintf function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+#include "../_vsnwprintf.h"
+
+/* memcmp is used to verify the results, so this test is dependent on it. */
+/* ditto with wcslen */
+
+int __cdecl main(int argc, char *argv[])
+{
+ int neg = -42;
+ int pos = 0x1234ab;
+ INT64 l = I64(0x1234567887654321);
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return(FAIL);
+ }
+
+ DoNumTest(convert("foo %X"), pos, convert("foo 1234AB"));
+ DoNumTest(convert("foo %lX"), pos, convert("foo 1234AB"));
+ DoNumTest(convert("foo %hX"), pos, convert("foo 34AB"));
+ DoNumTest(convert("foo %LX"), pos, convert("foo 1234AB"));
+ DoI64NumTest(convert("foo %I64X"), l, "0x1234567887654321",
+ convert("foo 1234567887654321"));
+ DoNumTest(convert("foo %7X"), pos, convert("foo 1234AB"));
+ DoNumTest(convert("foo %-7X"), pos, convert("foo 1234AB "));
+ DoNumTest(convert("foo %.1X"), pos, convert("foo 1234AB"));
+ DoNumTest(convert("foo %.7X"), pos, convert("foo 01234AB"));
+ DoNumTest(convert("foo %07X"), pos, convert("foo 01234AB"));
+ DoNumTest(convert("foo %#X"), pos, convert("foo 0X1234AB"));
+ DoNumTest(convert("foo %+X"), pos, convert("foo 1234AB"));
+ DoNumTest(convert("foo % X"), pos, convert("foo 1234AB"));
+ DoNumTest(convert("foo %+X"), neg, convert("foo FFFFFFD6"));
+ DoNumTest(convert("foo % X"), neg, convert("foo FFFFFFD6"));
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test13/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test13/testinfo.dat
new file mode 100644
index 0000000000..fa54ae8a62
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test13/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _vsnwprintf
+Name = Positive Test for _vsnwprintf
+TYPE = DEFAULT
+EXE1 = test13
+Description
+= Tests the PAL implementation of the _vsnwprintf function.
+= Tests _vsnwprintf with hex numbers (uppercase).
+= This test is modeled after _snwprintf.
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test14/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test14/CMakeLists.txt
new file mode 100644
index 0000000000..3bf157a2b3
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test14/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test14.c
+)
+
+add_executable(paltest_vsnwprintf_test14
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vsnwprintf_test14 coreclrpal)
+
+target_link_libraries(paltest_vsnwprintf_test14
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test14/test14.c b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test14/test14.c
new file mode 100644
index 0000000000..633f9d68ae
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test14/test14.c
@@ -0,0 +1,63 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test14.c
+**
+** Purpose: Test #14 for the _vsnwprintf function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+#include "../_vsnwprintf.h"
+
+/* memcmp is used to verify the results, so this test is dependent on it. */
+/* ditto with wcslen */
+
+int __cdecl main(int argc, char *argv[])
+{
+ double val = 256.0;
+ double neg = -256.0;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return(FAIL);
+ }
+
+ DoDoubleTest(convert("foo %e"), val, convert("foo 2.560000e+002"),
+ convert("foo 2.560000e+02"));
+ DoDoubleTest(convert("foo %le"), val, convert("foo 2.560000e+002"),
+ convert("foo 2.560000e+02"));
+ DoDoubleTest(convert("foo %he"), val, convert("foo 2.560000e+002"),
+ convert("foo 2.560000e+02"));
+ DoDoubleTest(convert("foo %Le"), val, convert("foo 2.560000e+002"),
+ convert("foo 2.560000e+02"));
+ DoDoubleTest(convert("foo %I64e"), val, convert("foo 2.560000e+002"),
+ convert("foo 2.560000e+02"));
+ DoDoubleTest(convert("foo %14e"), val, convert("foo 2.560000e+002"),
+ convert("foo 2.560000e+02"));
+ DoDoubleTest(convert("foo %-14e"), val, convert("foo 2.560000e+002 "),
+ convert("foo 2.560000e+02 "));
+ DoDoubleTest(convert("foo %.1e"), val, convert("foo 2.6e+002"),
+ convert("foo 2.6e+02"));
+ DoDoubleTest(convert("foo %.8e"), val, convert("foo 2.56000000e+002"),
+ convert("foo 2.56000000e+02"));
+ DoDoubleTest(convert("foo %014e"), val, convert("foo 02.560000e+002"),
+ convert("foo 002.560000e+02"));
+ DoDoubleTest(convert("foo %#e"), val, convert("foo 2.560000e+002"),
+ convert("foo 2.560000e+02"));
+ DoDoubleTest(convert("foo %+e"), val, convert("foo +2.560000e+002"),
+ convert("foo +2.560000e+02"));
+ DoDoubleTest(convert("foo % e"), val, convert("foo 2.560000e+002"),
+ convert("foo 2.560000e+02"));
+ DoDoubleTest(convert("foo %+e"), neg, convert("foo -2.560000e+002"),
+ convert("foo -2.560000e+02"));
+ DoDoubleTest(convert("foo % e"), neg, convert("foo -2.560000e+002"),
+ convert("foo -2.560000e+02"));
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test14/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test14/testinfo.dat
new file mode 100644
index 0000000000..0796f5e81c
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test14/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _vsnwprintf
+Name = Positive Test for _vsnwprintf
+TYPE = DEFAULT
+EXE1 = test14
+Description
+= Tests the PAL implementation of the _vsnwprintf function.
+= Tests _vsnwprintf with exponential format doubles (lowercase).
+= This test is modeled after _snwprintf.
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test15/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test15/CMakeLists.txt
new file mode 100644
index 0000000000..eedc7bb9db
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test15/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test15.c
+)
+
+add_executable(paltest_vsnwprintf_test15
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vsnwprintf_test15 coreclrpal)
+
+target_link_libraries(paltest_vsnwprintf_test15
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test15/test15.c b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test15/test15.c
new file mode 100644
index 0000000000..0af41fe1dc
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test15/test15.c
@@ -0,0 +1,64 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test15.c
+**
+** Purpose: Test #15 for the _vsnwprintf function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+#include "../_vsnwprintf.h"
+
+/* memcmp is used to verify the results, so this test is dependent on it. */
+/* ditto with wcslen */
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ double val = 256.0;
+ double neg = -256.0;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return(FAIL);
+ }
+
+ DoDoubleTest(convert("foo %E"), val, convert("foo 2.560000E+002"),
+ convert("foo 2.560000E+02"));
+ DoDoubleTest(convert("foo %lE"), val, convert("foo 2.560000E+002"),
+ convert("foo 2.560000E+02"));
+ DoDoubleTest(convert("foo %hE"), val, convert("foo 2.560000E+002"),
+ convert("foo 2.560000E+02"));
+ DoDoubleTest(convert("foo %LE"), val, convert("foo 2.560000E+002"),
+ convert("foo 2.560000E+02"));
+ DoDoubleTest(convert("foo %I64E"), val, convert("foo 2.560000E+002"),
+ convert("foo 2.560000E+02"));
+ DoDoubleTest(convert("foo %14E"), val, convert("foo 2.560000E+002"),
+ convert("foo 2.560000E+02"));
+ DoDoubleTest(convert("foo %-14E"), val, convert("foo 2.560000E+002 "),
+ convert("foo 2.560000E+02 "));
+ DoDoubleTest(convert("foo %.1E"), val, convert("foo 2.6E+002"),
+ convert("foo 2.6E+02"));
+ DoDoubleTest(convert("foo %.8E"), val, convert("foo 2.56000000E+002"),
+ convert("foo 2.56000000E+02"));
+ DoDoubleTest(convert("foo %014E"), val, convert("foo 02.560000E+002"),
+ convert("foo 002.560000E+02"));
+ DoDoubleTest(convert("foo %#E"), val, convert("foo 2.560000E+002"),
+ convert("foo 2.560000E+02"));
+ DoDoubleTest(convert("foo %+E"), val, convert("foo +2.560000E+002"),
+ convert("foo +2.560000E+02"));
+ DoDoubleTest(convert("foo % E"), val, convert("foo 2.560000E+002"),
+ convert("foo 2.560000E+02"));
+ DoDoubleTest(convert("foo %+E"), neg, convert("foo -2.560000E+002"),
+ convert("foo -2.560000E+02"));
+ DoDoubleTest(convert("foo % E"), neg, convert("foo -2.560000E+002"),
+ convert("foo -2.560000E+002"));
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test15/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test15/testinfo.dat
new file mode 100644
index 0000000000..9de3c83b8a
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test15/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _vsnwprintf
+Name = Positive Test for _vsnwprintf
+TYPE = DEFAULT
+EXE1 = test15
+Description
+= Tests the PAL implementation of the _vsnwprintf function.
+= Tests _vsnwprintf with exponential format doubles (uppercase).
+= This test is modeled after _snwprintf.
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test16/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test16/CMakeLists.txt
new file mode 100644
index 0000000000..a469c497e9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test16/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test16.c
+)
+
+add_executable(paltest_vsnwprintf_test16
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vsnwprintf_test16 coreclrpal)
+
+target_link_libraries(paltest_vsnwprintf_test16
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test16/test16.c b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test16/test16.c
new file mode 100644
index 0000000000..77571b01b3
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test16/test16.c
@@ -0,0 +1,63 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test16.c
+**
+** Purpose: Test #16 for the _vsnwprintf function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+#include "../_vsnwprintf.h"
+
+/* memcmp is used to verify the results, so this test is dependent on it. */
+/* ditto with wcslen */
+
+int __cdecl main(int argc, char *argv[])
+{
+ double val = 2560.001;
+ double neg = -2560.001;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return(FAIL);
+ }
+
+ DoDoubleTest(convert("foo %f"), val, convert("foo 2560.001000"),
+ convert("foo 2560.001000"));
+ DoDoubleTest(convert("foo %lf"), val, convert("foo 2560.001000"),
+ convert("foo 2560.001000"));
+ DoDoubleTest(convert("foo %hf"), val, convert("foo 2560.001000"),
+ convert("foo 2560.001000"));
+ DoDoubleTest(convert("foo %Lf"), val, convert("foo 2560.001000"),
+ convert("foo 2560.001000"));
+ DoDoubleTest(convert("foo %I64f"), val, convert("foo 2560.001000"),
+ convert("foo 2560.001000"));
+ DoDoubleTest(convert("foo %12f"), val, convert("foo 2560.001000"),
+ convert("foo 2560.001000"));
+ DoDoubleTest(convert("foo %-12f"), val, convert("foo 2560.001000 "),
+ convert("foo 2560.001000 "));
+ DoDoubleTest(convert("foo %.1f"), val, convert("foo 2560.0"),
+ convert("foo 2560.0"));
+ DoDoubleTest(convert("foo %.8f"), val, convert("foo 2560.00100000"),
+ convert("foo 2560.00100000"));
+ DoDoubleTest(convert("foo %012f"), val, convert("foo 02560.001000"),
+ convert("foo 02560.001000"));
+ DoDoubleTest(convert("foo %#f"), val, convert("foo 2560.001000"),
+ convert("foo 2560.001000"));
+ DoDoubleTest(convert("foo %+f"), val, convert("foo +2560.001000"),
+ convert("foo +2560.001000"));
+ DoDoubleTest(convert("foo % f"), val, convert("foo 2560.001000"),
+ convert("foo 2560.001000"));
+ DoDoubleTest(convert("foo %+f"), neg, convert("foo -2560.001000"),
+ convert("foo -2560.001000"));
+ DoDoubleTest(convert("foo % f"), neg, convert("foo -2560.001000"),
+ convert("foo -2560.001000"));
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test16/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test16/testinfo.dat
new file mode 100644
index 0000000000..b7134c785b
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test16/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _vsnwprintf
+Name = Positive Test for _vsnwprintf
+TYPE = DEFAULT
+EXE1 = test16
+Description
+= Tests the PAL implementation of the _vsnwprintf function.
+= Tests _vsnwprintf with decimal point format doubles.
+= This test is modeled after _snwprintf.
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test17/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test17/CMakeLists.txt
new file mode 100644
index 0000000000..f429e94417
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test17/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test17.c
+)
+
+add_executable(paltest_vsnwprintf_test17
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vsnwprintf_test17 coreclrpal)
+
+target_link_libraries(paltest_vsnwprintf_test17
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test17/test17.c b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test17/test17.c
new file mode 100644
index 0000000000..3a9d70ad03
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test17/test17.c
@@ -0,0 +1,65 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test17.c
+**
+** Purpose: Test #17 for the _vsnwprintf function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+#include "../_vsnwprintf.h"
+
+/* memcmp is used to verify the results, so this test is dependent on it. */
+/* ditto with wcslen */
+
+int __cdecl main(int argc, char *argv[])
+{
+ double val = 2560.001;
+ double neg = -2560.001;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return(FAIL);
+ }
+
+ DoDoubleTest(convert("foo %g"), val, convert("foo 2560"),
+ convert("foo 2560"));
+ DoDoubleTest(convert("foo %lg"), val, convert("foo 2560"),
+ convert("foo 2560"));
+ DoDoubleTest(convert("foo %hg"), val, convert("foo 2560"),
+ convert("foo 2560"));
+ DoDoubleTest(convert("foo %Lg"), val, convert("foo 2560"),
+ convert("foo 2560"));
+ DoDoubleTest(convert("foo %I64g"), val, convert("foo 2560"),
+ convert("foo 2560"));
+ DoDoubleTest(convert("foo %5g"), val, convert("foo 2560"),
+ convert("foo 2560"));
+ DoDoubleTest(convert("foo %-5g"), val, convert("foo 2560 "),
+ convert("foo 2560 "));
+ DoDoubleTest(convert("foo %.1g"), val, convert("foo 3e+003"),
+ convert("foo 3e+03"));
+ DoDoubleTest(convert("foo %.2g"), val, convert("foo 2.6e+003"),
+ convert("foo 2.6e+03"));
+ DoDoubleTest(convert("foo %.12g"), val, convert("foo 2560.001"),
+ convert("foo 2560.001"));
+ DoDoubleTest(convert("foo %06g"), val, convert("foo 002560"),
+ convert("foo 002560"));
+ DoDoubleTest(convert("foo %#g"), val, convert("foo 2560.00"),
+ convert("foo 2560.00"));
+ DoDoubleTest(convert("foo %+g"), val, convert("foo +2560"),
+ convert("foo +2560"));
+ DoDoubleTest(convert("foo % g"), val, convert("foo 2560"),
+ convert("foo 2560"));
+ DoDoubleTest(convert("foo %+g"), neg, convert("foo -2560"),
+ convert("foo -2560"));
+ DoDoubleTest(convert("foo % g"), neg, convert("foo -2560"),
+ convert("foo -2560"));
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test17/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test17/testinfo.dat
new file mode 100644
index 0000000000..5d5553151e
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test17/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _vsnwprintf
+Name = Positive Test for _vsnwprintf
+TYPE = DEFAULT
+EXE1 = test17
+Description
+= Tests the PAL implementation of the _vsnwprintf function.
+= Tests _vsnwprintf with compact format doubles (lowercase).
+= This test is modeled after _snwprintf.
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test18/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test18/CMakeLists.txt
new file mode 100644
index 0000000000..25dd6a2c5b
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test18/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test18.c
+)
+
+add_executable(paltest_vsnwprintf_test18
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vsnwprintf_test18 coreclrpal)
+
+target_link_libraries(paltest_vsnwprintf_test18
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test18/test18.c b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test18/test18.c
new file mode 100644
index 0000000000..03f9870113
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test18/test18.c
@@ -0,0 +1,65 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test18.c
+**
+** Purpose: Test #18 for the _vsnwprintf function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+#include "../_vsnwprintf.h"
+
+/* memcmp is used to verify the results, so this test is dependent on it. */
+/* ditto with wcslen */
+
+int __cdecl main(int argc, char *argv[])
+{
+ double val = 2560.001;
+ double neg = -2560.001;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return(FAIL);
+ }
+
+ DoDoubleTest(convert("foo %G"), val, convert("foo 2560"),
+ convert("foo 2560"));
+ DoDoubleTest(convert("foo %lG"), val, convert("foo 2560"),
+ convert("foo 2560"));
+ DoDoubleTest(convert("foo %hG"), val, convert("foo 2560"),
+ convert("foo 2560"));
+ DoDoubleTest(convert("foo %LG"), val, convert("foo 2560"),
+ convert("foo 2560"));
+ DoDoubleTest(convert("foo %I64G"), val, convert("foo 2560"),
+ convert("foo 2560"));
+ DoDoubleTest(convert("foo %5G"), val, convert("foo 2560"),
+ convert("foo 2560"));
+ DoDoubleTest(convert("foo %-5G"), val, convert("foo 2560 "),
+ convert("foo 2560 "));
+ DoDoubleTest(convert("foo %.1G"), val, convert("foo 3E+003"),
+ convert("foo 3E+03"));
+ DoDoubleTest(convert("foo %.2G"), val, convert("foo 2.6E+003"),
+ convert("foo 2.6E+03"));
+ DoDoubleTest(convert("foo %.12G"), val, convert("foo 2560.001"),
+ convert("foo 2560.001"));
+ DoDoubleTest(convert("foo %06G"), val, convert("foo 002560"),
+ convert("foo 002560"));
+ DoDoubleTest(convert("foo %#G"), val, convert("foo 2560.00"),
+ convert("foo 2560.00"));
+ DoDoubleTest(convert("foo %+G"), val, convert("foo +2560"),
+ convert("foo +2560"));
+ DoDoubleTest(convert("foo % G"), val, convert("foo 2560"),
+ convert("foo 2560"));
+ DoDoubleTest(convert("foo %+G"), neg, convert("foo -2560"),
+ convert("foo -2560"));
+ DoDoubleTest(convert("foo % G"), neg, convert("foo -2560"),
+ convert("foo -2560"));
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test18/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test18/testinfo.dat
new file mode 100644
index 0000000000..f56c80980d
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test18/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _vsnwprintf
+Name = Positive Test for _vsnwprintf
+TYPE = DEFAULT
+EXE1 = test18
+Description
+= Tests the PAL implementation of the _vsnwprintf function.
+= Tests _vsnwprintf with compact format doubles (uppercase).
+= This test is modeled after _snwprintf.
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test19/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test19/CMakeLists.txt
new file mode 100644
index 0000000000..9c636b8b0a
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test19/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test19.c
+)
+
+add_executable(paltest_vsnwprintf_test19
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vsnwprintf_test19 coreclrpal)
+
+target_link_libraries(paltest_vsnwprintf_test19
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test19/test19.c b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test19/test19.c
new file mode 100644
index 0000000000..fea275a242
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test19/test19.c
@@ -0,0 +1,139 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test18.c
+**
+** Purpose: Test #18 for the _vsnwprintf function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+#include "../_vsnwprintf.h"
+
+/* memcmp is used to verify the results, so this test is dependent on it. */
+/* ditto with wcslen */
+
+#define DOTEST(a,b,c,d,e) DoTest(a,b,(void*)c,d,e)
+
+void DoArgumentPrecTest(WCHAR *formatstr, int precision, void *param,
+ WCHAR *paramstr, WCHAR *checkstr1, WCHAR *checkstr2)
+{
+ WCHAR buf[256];
+
+ TestVsnwprintf(buf, 256, formatstr, precision, param);
+ if (memcmp(buf, checkstr1, wcslen(checkstr1) + 2) != 0 &&
+ memcmp(buf, checkstr2, wcslen(checkstr2) + 2) != 0)
+ {
+ Fail("ERROR: failed to insert %s into \"%s\" with precision %d\n"
+ "Expected \"%s\" or \"%s\", got \"%s\".\n",
+ paramstr,
+ convertC(formatstr),
+ precision,
+ convertC(checkstr1),
+ convertC(checkstr2),
+ convertC(buf));
+ }
+}
+void DoArgumentPrecDoubleTest(WCHAR *formatstr, int precision, double param,
+ WCHAR *checkstr1, WCHAR *checkstr2)
+{
+ WCHAR buf[256];
+
+ TestVsnwprintf(buf, 256, formatstr, precision, param);
+ if (memcmp(buf, checkstr1, wcslen(checkstr1) + 2) != 0 &&
+ memcmp(buf, checkstr2, wcslen(checkstr2) + 2) != 0)
+ {
+ Fail("ERROR: failed to insert %f into \"%s\" with precision %d\n"
+ "Expected \"%s\" or \"%s\", got \"%s\".\n",
+ param, convertC(formatstr),
+ precision,
+ convertC(checkstr1),
+ convertC(checkstr2),
+ convertC(buf));
+ }
+}
+
+/*
+ * Uses memcmp & wcslen
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return(FAIL);
+ }
+
+ DoArgumentPrecTest(convert("%.*s"), 2, convert("bar"), convert("bar"),
+ convert("ba"), convert("ba"));
+ DoArgumentPrecTest(convert("%.*c"), 0, (void*)'a', convert("a"),
+ convert("a"), convert("a"));
+ DoArgumentPrecTest(convert("%.*c"), 4, (void*)'a', convert("a"),
+ convert("a"), convert("a"));
+ DoArgumentPrecTest(convert("%.*C"), 0, (void*)'a', convert("a"),
+ convert("a"), convert("a"));
+ DoArgumentPrecTest(convert("%.*C"), 4, (void*)'a', convert("a"),
+ convert("a"), convert("a"));
+ DoArgumentPrecTest(convert("%.*d"), 1, (void*)42, convert("42"),
+ convert("42"), convert("42"));
+ DoArgumentPrecTest(convert("%.*d"), 3, (void*)42, convert("42"),
+ convert("042"), convert("042"));
+ DoArgumentPrecTest(convert("%.*i"), 1, (void*)42, convert("42"),
+ convert("42"), convert("42"));
+ DoArgumentPrecTest(convert("%.*i"), 3, (void*)42, convert("42"),
+ convert("042"), convert("042"));
+ DoArgumentPrecTest(convert("%.*o"), 1, (void*)42, convert("42"),
+ convert("52"), convert("52"));
+ DoArgumentPrecTest(convert("%.*o"), 3, (void*)42, convert("42"),
+ convert("052"), convert("052"));
+ DoArgumentPrecTest(convert("%.*u"), 1, (void*)42, convert("42"),
+ convert("42"), convert("42"));
+ DoArgumentPrecTest(convert("%.*u"), 3, (void*)42, convert("42"),
+ convert("042"), convert("042"));
+ DoArgumentPrecTest(convert("%.*x"), 1, (void*)0x42, convert("0x42"),
+ convert("42"), convert("42"));
+ DoArgumentPrecTest(convert("%.*x"), 3, (void*)0x42, convert("0x42"),
+ convert("042"), convert("042"));
+ DoArgumentPrecTest(convert("%.*X"), 1, (void*)0x42, convert("0x42"),
+ convert("42"), convert("42"));
+ DoArgumentPrecTest(convert("%.*X"), 3, (void*)0x42, convert("0x42"),
+ convert("042"), convert("042"));
+
+
+ DoArgumentPrecDoubleTest(convert("%.*e"), 1, 2.01, convert("2.0e+000"),
+ convert("2.0e+00"));
+ DoArgumentPrecDoubleTest(convert("%.*e"), 3, 2.01, convert("2.010e+000"),
+ convert("2.010e+00"));
+ DoArgumentPrecDoubleTest(convert("%.*E"), 1, 2.01, convert("2.0E+000"),
+ convert("2.0E+00"));
+ DoArgumentPrecDoubleTest(convert("%.*E"), 3, 2.01, convert("2.010E+000"),
+ convert("2.010E+00"));
+ DoArgumentPrecDoubleTest(convert("%.*f"), 1, 2.01, convert("2.0"),
+ convert("2.0"));
+ DoArgumentPrecDoubleTest(convert("%.*f"), 3, 2.01, convert("2.010"),
+ convert("2.010"));
+ DoArgumentPrecDoubleTest(convert("%.*g"), 1, 256.01, convert("3e+002"),
+ convert("3e+02"));
+ DoArgumentPrecDoubleTest(convert("%.*g"), 3, 256.01, convert("256"),
+ convert("256"));
+ DoArgumentPrecDoubleTest(convert("%.*g"), 4, 256.01, convert("256"),
+ convert("256"));
+ DoArgumentPrecDoubleTest(convert("%.*g"), 6, 256.01, convert("256.01"),
+ convert("256.01"));
+ DoArgumentPrecDoubleTest(convert("%.*G"), 1, 256.01, convert("3E+002"),
+ convert("3E+02"));
+ DoArgumentPrecDoubleTest(convert("%.*G"), 3, 256.01, convert("256"),
+ convert("256"));
+ DoArgumentPrecDoubleTest(convert("%.*G"), 4, 256.01, convert("256"),
+ convert("256"));
+ DoArgumentPrecDoubleTest(convert("%.*G"), 6, 256.01, convert("256.01"),
+ convert("256.01"));
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test19/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test19/testinfo.dat
new file mode 100644
index 0000000000..77178f1471
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test19/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _vsnwprintf
+Name = Positive Test for _vsnwprintf
+TYPE = DEFAULT
+EXE1 = test19
+Description
+= Tests the PAL implementation of the _vsnwprintf function.
+= Tests _vsnwprintf with argument specified precision.
+= This test is modeled after _snwprintf.
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test2/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test2/CMakeLists.txt
new file mode 100644
index 0000000000..817657ea61
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test2.c
+)
+
+add_executable(paltest_vsnwprintf_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vsnwprintf_test2 coreclrpal)
+
+target_link_libraries(paltest_vsnwprintf_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test2/test2.c b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test2/test2.c
new file mode 100644
index 0000000000..20499954db
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test2/test2.c
@@ -0,0 +1,40 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test2.c
+**
+** Purpose: Test #2 for the _vsnwprintf function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+#include "../_vsnwprintf.h"
+
+/* memcmp is used to verify the results, so this test is dependent on it. */
+/* ditto with wcslen */
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ if (PAL_Initialize(argc, argv) != 0)
+ return(FAIL);
+
+ DoWStrTest(convert("foo %s"), convert("bar"), convert("foo bar"));
+ DoStrTest(convert("foo %hs"), "bar", convert("foo bar"));
+ DoWStrTest(convert("foo %ls"), convert("bar"), convert("foo bar"));
+ DoWStrTest(convert("foo %ws"), convert("bar"), convert("foo bar"));
+ DoWStrTest(convert("foo %Ls"), convert("bar"), convert("foo bar"));
+ DoWStrTest(convert("foo %I64s"), convert("bar"), convert("foo bar"));
+ DoWStrTest(convert("foo %5s"), convert("bar"), convert("foo bar"));
+ DoWStrTest(convert("foo %.2s"), convert("bar"), convert("foo ba"));
+ DoWStrTest(convert("foo %5.2s"), convert("bar"), convert("foo ba"));
+ DoWStrTest(convert("foo %-5s"), convert("bar"), convert("foo bar "));
+ DoWStrTest(convert("foo %05s"), convert("bar"), convert("foo 00bar"));
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test2/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test2/testinfo.dat
new file mode 100644
index 0000000000..429911bd83
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test2/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _vsnwprintf
+Name = Positive Test for _vsnwprintf
+TYPE = DEFAULT
+EXE1 = test2
+Description
+= Tests the PAL implementation of the _vsnwprintf function.
+= Tests _vsnwprintf with strings.
+= This test is modeled after _snwprintf.
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test3/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test3/CMakeLists.txt
new file mode 100644
index 0000000000..4af3e36f3b
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test3/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test3.c
+)
+
+add_executable(paltest_vsnwprintf_test3
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vsnwprintf_test3 coreclrpal)
+
+target_link_libraries(paltest_vsnwprintf_test3
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test3/test3.c b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test3/test3.c
new file mode 100644
index 0000000000..9a37d3fc4b
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test3/test3.c
@@ -0,0 +1,40 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test3.c
+**
+** Purpose: Test #3 for the _vsnwprintf function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+#include "../_vsnwprintf.h"
+
+/* memcmp is used to verify the results, so this test is dependent on it. */
+/* ditto with wcslen */
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ if (PAL_Initialize(argc, argv) != 0)
+ return(FAIL);
+
+ DoStrTest(convert("foo %S"), "bar", convert("foo bar"));
+ DoStrTest(convert("foo %hS"), "bar", convert("foo bar"));
+ DoWStrTest(convert("foo %lS"), convert("bar"), convert("foo bar"));
+ DoWStrTest(convert("foo %wS"), convert("bar"), convert("foo bar"));
+ DoStrTest(convert("foo %LS"), "bar", convert("foo bar"));
+ DoStrTest(convert("foo %I64S"), "bar", convert("foo bar"));
+ DoStrTest(convert("foo %5S"), "bar", convert("foo bar"));
+ DoStrTest(convert("foo %.2S"), "bar", convert("foo ba"));
+ DoStrTest(convert("foo %5.2S"), "bar", convert("foo ba"));
+ DoStrTest(convert("foo %-5S"), "bar", convert("foo bar "));
+ DoStrTest(convert("foo %05S"), "bar", convert("foo 00bar"));
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test3/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test3/testinfo.dat
new file mode 100644
index 0000000000..d4e2686763
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test3/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _vsnwprintf
+Name = Positive Test for _vsnwprintf
+TYPE = DEFAULT
+EXE1 = test3
+Description
+= Tests the PAL implementation of the _vsnwprintf function.
+= Tests _vsnwprintf with wide strings.
+= This test is modeled after _snwprintf.
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test4/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test4/CMakeLists.txt
new file mode 100644
index 0000000000..b7ff9e7bb3
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test4/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test4.c
+)
+
+add_executable(paltest_vsnwprintf_test4
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vsnwprintf_test4 coreclrpal)
+
+target_link_libraries(paltest_vsnwprintf_test4
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test4/test4.c b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test4/test4.c
new file mode 100644
index 0000000000..6f39be2a80
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test4/test4.c
@@ -0,0 +1,121 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test4.c
+**
+** Purpose: Test #4 for the _vsnwprintf function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+#include "../_vsnwprintf.h"
+
+/* memcmp is used to verify the results, so this test is dependent on it. */
+/* ditto with wcslen */
+static void DoPointerTest(WCHAR *formatstr, void* param, WCHAR* paramstr,
+ WCHAR *checkstr1)
+{
+ WCHAR buf[256] = { 0 };
+
+ TestVsnwprintf(buf, 256, formatstr, param);
+ if (memcmp(buf, checkstr1, wcslen(checkstr1) + 2) != 0)
+
+ {
+ Fail("ERROR: failed to insert pointer to %#p into \"%s\"\n"
+ "Expected \"%s\" got \"%s\".\n",
+ paramstr,
+ convertC(formatstr),
+ convertC(checkstr1),
+ convertC(buf));
+ }
+}
+
+static void DoI64DoubleTest(WCHAR *formatstr, INT64 value, WCHAR *valuestr,
+ WCHAR *checkstr1)
+{
+ WCHAR buf[256] = { 0 };
+
+ TestVsnwprintf(buf, 256, formatstr, value);
+ if (memcmp(buf, checkstr1, wcslen(checkstr1) + 2) != 0)
+ {
+ Fail("ERROR: failed to insert %s into \"%s\"\n"
+ "Expected \"%s\", got \"%s\".\n",
+ value,
+ convertC(formatstr),
+ convertC(checkstr1),
+ convertC(buf));
+ }
+}
+
+int __cdecl main(int argc, char *argv[])
+{
+ void *ptr = (void*) 0x123456;
+ INT64 lptr = I64(0x1234567887654321);
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return(FAIL);
+ }
+
+/*
+** Run only on 64 bit platforms
+*/
+#if defined(BIT64) && defined(PLATFORM_UNIX)
+ Trace("Testing for 64 Bit Platforms \n");
+ DoPointerTest(convert("%p"), NULL, convert("NULL"), convert("00000000"));
+ DoPointerTest(convert("%p"), ptr, convert("pointer to 0x123456"),
+ convert("0000000000123456"));
+ DoPointerTest(convert("%17p"), ptr, convert("pointer to 0x123456"),
+ convert(" 0000000000123456"));
+ DoPointerTest(convert("%17p"), ptr, convert("pointer to 0x123456"),
+ convert(" 0000000000123456"));
+ DoPointerTest(convert("%-17p"), ptr, convert("pointer to 0x123456"),
+ convert("0000000000123456 "));
+ DoPointerTest(convert("%+p"), ptr, convert("pointer to 0x123456"),
+ convert("0000000000123456"));
+ DoPointerTest(convert("%#p"), ptr, convert("pointer to 0x123456"),
+ convert("0X0000000000123456"));
+ DoPointerTest(convert("%lp"), ptr, convert("pointer to 0x123456"),
+ convert("00123456"));
+ DoPointerTest(convert("%hp"), ptr, convert("pointer to 0x123456"),
+ convert("00003456"));
+ DoPointerTest(convert("%Lp"), ptr, convert("pointer to 0x123456"),
+ convert("00123456"));
+ DoI64DoubleTest(convert("%I64p"), lptr,
+ convert("pointer to 0x1234567887654321"),
+ convert("1234567887654321"));
+
+#else
+ Trace("Testing for Non 64 Bit Platforms \n");
+ DoPointerTest(convert("%p"), NULL, convert("NULL"), convert("00000000"));
+ DoPointerTest(convert("%p"), ptr, convert("pointer to 0x123456"),
+ convert("00123456"));
+ DoPointerTest(convert("%9p"), ptr, convert("pointer to 0x123456"),
+ convert(" 00123456"));
+ DoPointerTest(convert("%09p"), ptr, convert("pointer to 0x123456"),
+ convert(" 00123456"));
+ DoPointerTest(convert("%-9p"), ptr, convert("pointer to 0x123456"),
+ convert("00123456 "));
+ DoPointerTest(convert("%+p"), ptr, convert("pointer to 0x123456"),
+ convert("00123456"));
+ DoPointerTest(convert("%#p"), ptr, convert("pointer to 0x123456"),
+ convert("0X00123456"));
+ DoPointerTest(convert("%lp"), ptr, convert("pointer to 0x123456"),
+ convert("00123456"));
+ DoPointerTest(convert("%hp"), ptr, convert("pointer to 0x123456"),
+ convert("00003456"));
+ DoPointerTest(convert("%Lp"), ptr, convert("pointer to 0x123456"),
+ convert("00123456"));
+ DoI64DoubleTest(convert("%I64p"), lptr,
+ convert("pointer to 0x1234567887654321"),
+ convert("1234567887654321"));
+#endif
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test4/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test4/testinfo.dat
new file mode 100644
index 0000000000..56f488a66a
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test4/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _vsnwprintf
+Name = Positive Test for _vsnwprintf
+TYPE = DEFAULT
+EXE1 = test4
+Description
+= Tests the PAL implementation of the _vsnwprintf function.
+= Tests _vsnwprintf with pointers.
+= This test is modeled after _snwprintf.
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test5/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test5/CMakeLists.txt
new file mode 100644
index 0000000000..9b316b9f90
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test5/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test5.c
+)
+
+add_executable(paltest_vsnwprintf_test5
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vsnwprintf_test5 coreclrpal)
+
+target_link_libraries(paltest_vsnwprintf_test5
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test5/test5.c b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test5/test5.c
new file mode 100644
index 0000000000..224db766ff
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test5/test5.c
@@ -0,0 +1,81 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test5.c
+**
+** Purpose: Test #5 for the _vsnwprintf function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+#include "../_vsnwprintf.h"
+
+/* memcmp is used to verify the results, so this test is dependent on it. */
+/* ditto with wcslen */
+
+static void DoTest(WCHAR *formatstr, int param, WCHAR *checkstr)
+{
+ WCHAR buf[256] = { 0 };
+ int n = -1;
+
+ TestVsnwprintf(buf, 256, formatstr, &n);
+
+ if (n != param)
+ {
+ Fail("ERROR: Expected count parameter to resolve to %d, got %d\n",
+ param, n);
+ }
+
+ if (memcmp(buf, checkstr, wcslen(buf)*2 + 2) != 0)
+ {
+ Fail("ERROR: Expected \"%s\" got \"%s\".\n",
+ convertC(checkstr), convertC(buf));
+ }
+}
+
+static void DoShortTest(WCHAR *formatstr, int param, WCHAR *checkstr)
+{
+ WCHAR buf[256] = { 0 };
+ short int n = -1;
+
+ TestVsnwprintf(buf, 256, formatstr, &n);
+
+ if (n != param)
+ {
+ Fail("ERROR: Expected count parameter to resolve to %d, got %d\n",
+ param, n);
+ }
+
+ if (memcmp(buf, checkstr, wcslen(buf)*2 + 2) != 0)
+ {
+ Fail("ERROR: Expected \"%s\" got \"%s\".\n",
+ convertC(checkstr), convertC(buf));
+ }
+}
+
+int __cdecl main(int argc, char *argv[])
+{
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return(FAIL);
+ }
+
+ DoTest(convert("foo %n bar"), 4, convert("foo bar"));
+ DoTest(convert("foo %#n bar"), 4, convert("foo bar"));
+ DoTest(convert("foo % n bar"), 4, convert("foo bar"));
+ DoTest(convert("foo %+n bar"), 4, convert("foo bar"));
+ DoTest(convert("foo %-n bar"), 4, convert("foo bar"));
+ DoTest(convert("foo %0n bar"), 4, convert("foo bar"));
+ DoShortTest(convert("foo %hn bar"), 4, convert("foo bar"));
+ DoTest(convert("foo %ln bar"), 4, convert("foo bar"));
+ DoTest(convert("foo %Ln bar"), 4, convert("foo bar"));
+ DoTest(convert("foo %I64n bar"), 4, convert("foo bar"));
+ DoTest(convert("foo %20.3n bar"), 4, convert("foo bar"));
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test5/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test5/testinfo.dat
new file mode 100644
index 0000000000..35d3816a76
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test5/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _vsnwprintf
+Name = Positive Test for _vsnwprintf
+TYPE = DEFAULT
+EXE1 = test5
+Description
+= Tests the PAL implementation of the _vsnwprintf function.
+= Tests _vsnwprintf with the count specifier.
+= This test is modeled after _snwprintf.
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test6/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test6/CMakeLists.txt
new file mode 100644
index 0000000000..d3fad03597
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test6/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test6.c
+)
+
+add_executable(paltest_vsnwprintf_test6
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vsnwprintf_test6 coreclrpal)
+
+target_link_libraries(paltest_vsnwprintf_test6
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test6/test6.c b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test6/test6.c
new file mode 100644
index 0000000000..1bd83ea85c
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test6/test6.c
@@ -0,0 +1,43 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test6.c
+**
+** Purpose: Test #6 for the _vsnwprintf function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+#include "../_vsnwprintf.h"
+
+/* memcmp is used to verify the results, so this test is dependent on it. */
+/* ditto with wcslen */
+
+int __cdecl main(int argc, char *argv[])
+{
+ WCHAR wc = (WCHAR) 'c';
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return(FAIL);
+ }
+
+ DoWCharTest(convert("foo %c"), wc, convert("foo c"));
+ DoCharTest(convert("foo %hc"), 'b', convert("foo b"));
+ DoWCharTest(convert("foo %lc"), wc, convert("foo c"));
+ DoWCharTest(convert("foo %Lc"), wc, convert("foo c"));
+ DoWCharTest(convert("foo %I64c"), wc, convert("foo c"));
+ DoWCharTest(convert("foo %5c"), wc, convert("foo c"));
+ DoWCharTest(convert("foo %.0c"), wc, convert("foo c"));
+ DoWCharTest(convert("foo %-5c"), wc, convert("foo c "));
+ DoWCharTest(convert("foo %05c"), wc, convert("foo 0000c"));
+ DoWCharTest(convert("foo % c"), wc, convert("foo c"));
+ DoWCharTest(convert("foo %#c"), wc, convert("foo c"));
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test6/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test6/testinfo.dat
new file mode 100644
index 0000000000..6afe96d1cd
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test6/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _vsnwprintf
+Name = Positive Test for _vsnwprintf
+TYPE = DEFAULT
+EXE1 = test6
+Description
+= Tests the PAL implementation of the _vsnwprintf function.
+= Tests _vsnwprintf with characters.
+= This test is modeled after _snwprintf.
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test7/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test7/CMakeLists.txt
new file mode 100644
index 0000000000..cede861358
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test7/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test7.c
+)
+
+add_executable(paltest_vsnwprintf_test7
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vsnwprintf_test7 coreclrpal)
+
+target_link_libraries(paltest_vsnwprintf_test7
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test7/test7.c b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test7/test7.c
new file mode 100644
index 0000000000..e13798b784
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test7/test7.c
@@ -0,0 +1,43 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test7.c
+**
+** Purpose: Test #7 for the _vsnwprintf function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+#include "../_vsnwprintf.h"
+
+/* memcmp is used to verify the results, so this test is dependent on it. */
+/* ditto with wcslen */
+
+int __cdecl main(int argc, char *argv[])
+{
+ WCHAR wc = (WCHAR) 'c';
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return(FAIL);
+ }
+
+ DoCharTest(convert("foo %C"), 'b', convert("foo b"));
+ DoWCharTest(convert("foo %hC"), wc, convert("foo c"));
+ DoCharTest(convert("foo %lC"), 'b', convert("foo b"));
+ DoCharTest(convert("foo %LC"), 'b', convert("foo b"));
+ DoCharTest(convert("foo %I64C"), 'b', convert("foo b"));
+ DoCharTest(convert("foo %5C"), 'b', convert("foo b"));
+ DoCharTest(convert("foo %.0C"), 'b', convert("foo b"));
+ DoCharTest(convert("foo %-5C"), 'b', convert("foo b "));
+ DoCharTest(convert("foo %05C"), 'b', convert("foo 0000b"));
+ DoCharTest(convert("foo % C"), 'b', convert("foo b"));
+ DoCharTest(convert("foo %#C"), 'b', convert("foo b"));
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test7/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test7/testinfo.dat
new file mode 100644
index 0000000000..ece40aa195
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test7/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _vsnwprintf
+Name = Positive Test for _vsnwprintf
+TYPE = DEFAULT
+EXE1 = test7
+Description
+= Tests the PAL implementation of the _vsnwprintf function.
+= Tests _vsnwprintf with wide characters.
+= This test is modeled after _snwprintf.
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test8/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test8/CMakeLists.txt
new file mode 100644
index 0000000000..846e7b9219
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test8/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test8.c
+)
+
+add_executable(paltest_vsnwprintf_test8
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vsnwprintf_test8 coreclrpal)
+
+target_link_libraries(paltest_vsnwprintf_test8
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test8/test8.c b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test8/test8.c
new file mode 100644
index 0000000000..8f02412eb0
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test8/test8.c
@@ -0,0 +1,49 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test8.c
+**
+** Purpose: Test #8 for the _vsnwprintf function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+#include "../_vsnwprintf.h"
+
+/* memcmp is used to verify the results, so this test is dependent on it. */
+/* ditto with wcslen */
+
+int __cdecl main(int argc, char *argv[])
+{
+ int neg = -42;
+ int pos = 42;
+ INT64 l = 42;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return(FAIL);
+ }
+
+ DoNumTest(convert("foo %d"), pos, convert("foo 42"));
+ DoNumTest(convert("foo %ld"), 0xFFFF, convert("foo 65535"));
+ DoNumTest(convert("foo %hd"), 0xFFFF, convert("foo -1"));
+ DoNumTest(convert("foo %Ld"), pos, convert("foo 42"));
+ DoI64NumTest(convert("foo %I64d"), l, "42", convert("foo 42"));
+ DoNumTest(convert("foo %3d"), pos, convert("foo 42"));
+ DoNumTest(convert("foo %-3d"), pos, convert("foo 42 "));
+ DoNumTest(convert("foo %.1d"), pos, convert("foo 42"));
+ DoNumTest(convert("foo %.3d"), pos, convert("foo 042"));
+ DoNumTest(convert("foo %03d"), pos, convert("foo 042"));
+ DoNumTest(convert("foo %#d"), pos, convert("foo 42"));
+ DoNumTest(convert("foo %+d"), pos, convert("foo +42"));
+ DoNumTest(convert("foo % d"), pos, convert("foo 42"));
+ DoNumTest(convert("foo %+d"), neg, convert("foo -42"));
+ DoNumTest(convert("foo % d"), neg, convert("foo -42"));
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test8/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test8/testinfo.dat
new file mode 100644
index 0000000000..d7a567a6d6
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test8/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _vsnwprintf
+Name = Positive Test for _vsnwprintf
+TYPE = DEFAULT
+EXE1 = test8
+Description
+= Tests the PAL implementation of the _vsnwprintf function.
+= Tests _vsnwprintf with decimal numbers.
+= This test is modeled after _snwprintf.
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test9/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test9/CMakeLists.txt
new file mode 100644
index 0000000000..e25eded172
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test9/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test9.c
+)
+
+add_executable(paltest_vsnwprintf_test9
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vsnwprintf_test9 coreclrpal)
+
+target_link_libraries(paltest_vsnwprintf_test9
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test9/test9.c b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test9/test9.c
new file mode 100644
index 0000000000..7b5b6cd8a6
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test9/test9.c
@@ -0,0 +1,49 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test9.c
+**
+** Purpose: Test #9 for the _vsnwprintf function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+#include "../_vsnwprintf.h"
+
+/* memcmp is used to verify the results, so this test is dependent on it. */
+/* ditto with wcslen */
+
+int __cdecl main(int argc, char *argv[])
+{
+ int neg = -42;
+ int pos = 42;
+ INT64 l = 42;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return(FAIL);
+ }
+
+ DoNumTest(convert("foo %i"), pos, convert("foo 42"));
+ DoNumTest(convert("foo %li"), 0xFFFF, convert("foo 65535"));
+ DoNumTest(convert("foo %hi"), 0xFFFF, convert("foo -1"));
+ DoNumTest(convert("foo %Li"), pos, convert("foo 42"));
+ DoI64NumTest(convert("foo %I64i"), l, "42", convert("foo 42"));
+ DoNumTest(convert("foo %3i"), pos, convert("foo 42"));
+ DoNumTest(convert("foo %-3i"), pos, convert("foo 42 "));
+ DoNumTest(convert("foo %.1i"), pos, convert("foo 42"));
+ DoNumTest(convert("foo %.3i"), pos, convert("foo 042"));
+ DoNumTest(convert("foo %03i"), pos, convert("foo 042"));
+ DoNumTest(convert("foo %#i"), pos, convert("foo 42"));
+ DoNumTest(convert("foo %+i"), pos, convert("foo +42"));
+ DoNumTest(convert("foo % i"), pos, convert("foo 42"));
+ DoNumTest(convert("foo %+i"), neg, convert("foo -42"));
+ DoNumTest(convert("foo % i"), neg, convert("foo -42"));
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test9/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test9/testinfo.dat
new file mode 100644
index 0000000000..726b060240
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_vsnwprintf/test9/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _vsnwprintf
+Name = Positive Test for _vsnwprintf
+TYPE = DEFAULT
+EXE1 = test9
+Description
+= Tests the PAL implementation of the _vsnwprintf function.
+= Tests _vsnwprintf with integer numbers
+= This test is modeled after _snwprintf.
diff --git a/src/pal/tests/palsuite/c_runtime/_wcsicmp/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_wcsicmp/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_wcsicmp/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/_wcsicmp/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_wcsicmp/test1/CMakeLists.txt
new file mode 100644
index 0000000000..5f085cc723
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_wcsicmp/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_wcsicmp_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_wcsicmp_test1 coreclrpal)
+
+target_link_libraries(paltest_wcsicmp_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_wcsicmp/test1/test1.c b/src/pal/tests/palsuite/c_runtime/_wcsicmp/test1/test1.c
new file mode 100644
index 0000000000..dd4bb54680
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_wcsicmp/test1/test1.c
@@ -0,0 +1,68 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Tests that _wcsicmp correctly compares two strings with
+** case insensitivity.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+
+/*
+ * Note: The _wcsicmp is dependent on the LC_CTYPE category of the locale,
+ * and this is ignored by these tests.
+ */
+int __cdecl main(int argc, char *argv[])
+{
+ WCHAR str1[] = {'f','o','o',0};
+ WCHAR str2[] = {'f','O','o',0};
+ WCHAR str3[] = {'f','o','o','_','b','a','r',0};
+ WCHAR str4[] = {'f','o','o','b','a','r',0};
+
+ /*
+ * Initialize the PAL and return FAIL if this fails
+ */
+ if (0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ if (_wcsicmp(str1, str2) != 0)
+ {
+ Fail ("ERROR: _wcsicmp returning incorrect value:\n"
+ "_wcsicmp(\"%S\", \"%S\") != 0\n", str1, str2);
+ }
+
+ if (_wcsicmp(str2, str3) >= 0)
+ {
+ Fail ("ERROR: _wcsicmp returning incorrect value:\n"
+ "_wcsicmp(\"%S\", \"%S\") >= 0\n", str2, str3);
+ }
+
+ if (_wcsicmp(str3, str4) >= 0)
+ {
+ Fail ("ERROR: _wcsicmp returning incorrect value:\n"
+ "_wcsicmp(\"%S\", \"%S\") >= 0\n", str3, str4);
+ }
+
+ if (_wcsicmp(str4, str1) <= 0)
+ {
+ Fail ("ERROR: _wcsicmp returning incorrect value:\n"
+ "_wcsicmp(\"%S\", \"%S\") <= 0\n", str4, str1);
+ }
+
+ if (_wcsicmp(str3, str2) <= 0)
+ {
+ Fail ("ERROR: _wcsicmp returning incorrect value:\n"
+ "_wcsicmp(\"%S\", \"%S\") <= 0\n", str2, str3);
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/_wcsicmp/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_wcsicmp/test1/testinfo.dat
new file mode 100644
index 0000000000..9351a156e0
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_wcsicmp/test1/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _wcsicmp
+Name = Test #1 for _wcsicmp
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Tests that _wcsicmp correctly compares two strings with case insensitivity.
diff --git a/src/pal/tests/palsuite/c_runtime/_wcslwr/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_wcslwr/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_wcslwr/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/_wcslwr/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_wcslwr/test1/CMakeLists.txt
new file mode 100644
index 0000000000..a78098f86a
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_wcslwr/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_wcslwr_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_wcslwr_test1 coreclrpal)
+
+target_link_libraries(paltest_wcslwr_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_wcslwr/test1/test1.c b/src/pal/tests/palsuite/c_runtime/_wcslwr/test1/test1.c
new file mode 100644
index 0000000000..3a758de39b
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_wcslwr/test1/test1.c
@@ -0,0 +1,50 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Using memcmp to check the result, convert a wide character string
+** with capitals, to all lowercase using this function. Test #1 for the
+** wcslwr function
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+
+/* uses memcmp,wcslen */
+
+int __cdecl main(int argc, char *argv[])
+{
+ WCHAR *test_str = NULL;
+ WCHAR *expect_str = NULL;
+ WCHAR *result_str = NULL;
+
+ /*
+ * Initialize the PAL and return FAIL if this fails
+ */
+ if (0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ test_str = convert("aSdF 1#");
+ expect_str = convert("asdf 1#");
+
+ result_str = _wcslwr(test_str);
+ if (memcmp(result_str, expect_str, wcslen(expect_str)*2 + 2) != 0)
+ {
+ Fail ("ERROR: Expected to get \"%s\", got \"%s\".\n",
+ convertC(expect_str), convertC(result_str));
+ }
+
+ free(result_str);
+ free(expect_str);
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/_wcslwr/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_wcslwr/test1/testinfo.dat
new file mode 100644
index 0000000000..5d691d84d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_wcslwr/test1/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _wcslwr
+Name = Positive Test for _wcslwr
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Using memcmp to check the result, convert a wide character string
+= with capitals, to all lowercase using this function.
+
diff --git a/src/pal/tests/palsuite/c_runtime/_wcsnicmp/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_wcsnicmp/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_wcsnicmp/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/_wcsnicmp/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_wcsnicmp/test1/CMakeLists.txt
new file mode 100644
index 0000000000..afd3560b10
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_wcsnicmp/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_wcsnicmp_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_wcsnicmp_test1 coreclrpal)
+
+target_link_libraries(paltest_wcsnicmp_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_wcsnicmp/test1/test1.c b/src/pal/tests/palsuite/c_runtime/_wcsnicmp/test1/test1.c
new file mode 100644
index 0000000000..0271bcc60d
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_wcsnicmp/test1/test1.c
@@ -0,0 +1,95 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Take two wide strings and compare them, giving different lengths.
+** Comparing str1 and str2 with str2 length, should return <0
+** Comparing str2 and str1 with str2 length, should return >0
+** Comparing str1 and str2 with str1 lenght, should return 0
+** Bring in str3, which has a capital, but this function is doing a lower
+** case compare. Just ensure that two strings which differ only by capitals
+** return 0.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+
+/*
+ * Notes: uses wcslen
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ WCHAR str1[] = {'f','o','o',0};
+ WCHAR str2[] = {'f','o','o','x',0};
+ WCHAR str3[] = {'f','O','o',0};
+ WCHAR str4[] = {'A','B','C','D','E',0};
+ WCHAR str5[] = {'A','B','C','D',']',0};
+ WCHAR str6[] = {'a','b','c','d','e',0};
+ WCHAR str7[] = {'a','b','c','d',']',0};
+ char cstr1[] = "foo";
+ char cstr2[] = "foox";
+ char cstr3[] = "fOo";
+ char cstr4[] = "ABCDE";
+ char cstr5[] = "ABCD]";
+ char cstr6[] = "abcde";
+ char cstr7[] = "abcd]";
+
+
+ /*
+ * Initialize the PAL and return FAIL if this fails
+ */
+ if (0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ if (_wcsnicmp(str1, str2, wcslen(str2)) >= 0)
+ {
+ Fail ("ERROR: wcsnicmp(\"%s\", \"%s\", %d) returned >= 0\n", cstr1,
+ cstr2, wcslen(str2));
+ }
+
+ if (_wcsnicmp(str2, str1, wcslen(str2)) <= 0)
+ {
+ Fail ("ERROR: wcsnicmp(\"%s\", \"%s\", %d) returned <= 0\n", cstr2,
+ cstr1, wcslen(str2));
+ }
+
+ if (_wcsnicmp(str1, str2, wcslen(str1)) != 0)
+ {
+ Fail ("ERROR: wcsnicmp(\"%s\", \"%s\", %d) returned != 0\n", cstr1,
+ cstr2, wcslen(str1));
+ }
+
+ if (_wcsnicmp(str1, str3, wcslen(str1)) != 0)
+ {
+ Fail ("ERROR: wcsnicmp(\"%s\", \"%s\", %d) returned != 0\n", cstr1,
+ cstr3, wcslen(str1));
+ }
+
+ /* new testing */
+
+ /* str4 should be greater than str5 */
+ if (_wcsnicmp(str4, str5, wcslen(str4)) <= 0)
+ {
+ Fail ("ERROR: _wcsnicmp(\"%s\", \"%s\", %d) returned >= 0\n",
+ cstr4, cstr5, wcslen(str4));
+ }
+
+ /* str6 should be greater than str7 */
+ if (_wcsnicmp(str6, str7, wcslen(str6)) <= 0)
+ {
+ Fail ("ERROR: _wcsnicmp(\"%s\", \"%s\", %d) returned <= 0\n",
+ cstr6, cstr7, wcslen(str6));
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/_wcsnicmp/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_wcsnicmp/test1/testinfo.dat
new file mode 100644
index 0000000000..df49cc1a9a
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_wcsnicmp/test1/testinfo.dat
@@ -0,0 +1,18 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _wcsnicmp
+Name = Positive Test for _wcsnicmp
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Take two wide strings and compare them, giving different lengths.
+= Comparing str1 and str2 with str2 length, should return <0
+= Comparing str2 and str1 with str2 length, should return >0
+= Comparing str1 and str2 with str1 lenght, should return 0
+= Bring in str3, which has a capital, but this function is doing a lower
+= case compare. Just ensure that two strings which differ only by capitals
+= return 0.
diff --git a/src/pal/tests/palsuite/c_runtime/_wfopen/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_wfopen/CMakeLists.txt
new file mode 100644
index 0000000000..19ee487a6a
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_wfopen/CMakeLists.txt
@@ -0,0 +1,10 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+add_subdirectory(test3)
+add_subdirectory(test4)
+add_subdirectory(test5)
+add_subdirectory(test6)
+add_subdirectory(test7)
+
diff --git a/src/pal/tests/palsuite/c_runtime/_wfopen/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_wfopen/test1/CMakeLists.txt
new file mode 100644
index 0000000000..96df58ee54
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_wfopen/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_wfopen_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_wfopen_test1 coreclrpal)
+
+target_link_libraries(paltest_wfopen_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_wfopen/test1/test1.c b/src/pal/tests/palsuite/c_runtime/_wfopen/test1/test1.c
new file mode 100644
index 0000000000..81d2502cd5
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_wfopen/test1/test1.c
@@ -0,0 +1,79 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test1.c
+**
+** Purpose: Tests the PAL implementation of the _wfopen function.
+** This test simply attempts to open a number of files with
+** different modes. It checks to ensure a valid file
+** pointer is returned. It doesn't do any checking to
+** ensure the mode is really what it claims.
+**
+
+**
+**===================================================================*/
+
+
+#define UNICODE
+#include <palsuite.h>
+
+struct testCase
+{
+ int CorrectResult;
+ WCHAR mode[20];
+};
+
+int __cdecl main(int argc, char **argv)
+{
+
+ FILE *fp;
+ WCHAR name[128];
+ WCHAR base[] = {'t','e','s','t','f','i','l','e','s','\0'};
+ char * PrintResult;
+ int i;
+
+ struct testCase testCases[] =
+ {
+ {0, {'r','\0' }}, {1, {'w','\0'}}, {1, {'a','\0'}},
+ {0, {'r','+','\0'}}, {1, {'w','+','\0'}}, {1, {'a','+','\0'}},
+ {1, {'w','t','\0'}}, {1, {'w','b','\0'}}, {1, {'w','S','\0'}},
+ {1, {'w','c','\0'}}, {1, {'w','n','\0'}}, {1, {'w', 'R','\0'}},
+ {1, {'w','T','\0'}}, {0, {'t','w','\0'}}, {0, {'.','\0'}}
+ };
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+
+ for(i = 0; i < sizeof(testCases) / sizeof(struct testCase); i++)
+ {
+ wcscpy(name,base);
+ wcscat(name,testCases[i].mode);
+
+ fp = _wfopen(name,testCases[i].mode);
+
+ if ((fp == 0 && testCases[i].CorrectResult != 0) ||
+ (testCases[i].CorrectResult == 0 && fp != 0) )
+ {
+ PrintResult = convertC(testCases[i].mode);
+ Fail("ERROR: fopen returned incorrectly "
+ "opening a file in %s mode. Perhaps it opened a "
+ "read only file which didn't exist and returned a correct "
+ "pointer?",PrintResult);
+ free(PrintResult);
+ }
+
+ memset(name, '\0', 128);
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/_wfopen/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_wfopen/test1/testinfo.dat
new file mode 100644
index 0000000000..6514137c2f
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_wfopen/test1/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _wfopen
+Name = Positive Test for _wfopen
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= This test simply attempts to open a number of files with different
+= modes. It checks to ensure a valid file pointer is returned. It
+= doesn't do any checking to ensure the mode is really what it claims.
+
diff --git a/src/pal/tests/palsuite/c_runtime/_wfopen/test2/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_wfopen/test2/CMakeLists.txt
new file mode 100644
index 0000000000..47203d86d5
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_wfopen/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test2.c
+)
+
+add_executable(paltest_wfopen_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_wfopen_test2 coreclrpal)
+
+target_link_libraries(paltest_wfopen_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_wfopen/test2/test2.c b/src/pal/tests/palsuite/c_runtime/_wfopen/test2/test2.c
new file mode 100644
index 0000000000..921ffef19d
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_wfopen/test2/test2.c
@@ -0,0 +1,68 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test2.c
+**
+** Purpose: Tests the PAL implementation of the _wfopen function.
+** Test to ensure that you can write to a 'w' mode file.
+** And that you can't read from a 'w' mode file.
+**
+** Depends:
+** fprintf
+** fseek
+** fgets
+**
+
+**
+**===================================================================*/
+
+#define UNICODE
+#include <palsuite.h>
+
+int __cdecl main(int argc, char **argv)
+{
+
+ FILE *fp;
+ char buffer[128];
+ WCHAR filename[] = {'t','e','s','t','f','i','l','e','\0'};
+ WCHAR write[] = {'w','\0'};
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ if( (fp = _wfopen( filename, write )) == NULL )
+ {
+ Fail( "ERROR: The file failed to open with 'w' mode.\n" );
+ }
+
+ /* Test that you can write */
+ if(fprintf(fp,"%s","some text") <= 0)
+ {
+ Fail("ERROR: Attempted to WRITE to a file opened with 'w' mode "
+ "but fprintf failed. Either fopen or fprintf have problems.");
+ }
+
+ if(fseek(fp, 0, SEEK_SET))
+ {
+ Fail("ERROR: fseek failed, and this test depends on it.");
+ }
+
+ /* Test that you can't read */
+ if(fgets(buffer,10,fp) != NULL)
+ {
+ Fail("ERROR: Tried to READ from a file with only 'w' mode set. "
+ "This should fail, but fgets didn't return NULL. "
+ "Either fgets or fopen is broken.");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/_wfopen/test2/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_wfopen/test2/testinfo.dat
new file mode 100644
index 0000000000..3ed2e3bbed
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_wfopen/test2/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _wfopen
+Name = Positive Test for _wfopen
+TYPE = DEFAULT
+EXE1 = test2
+Description
+= Test to ensure that you can write to a 'w' mode file. And that you can't
+= read from a 'w' mode file.
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/_wfopen/test3/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_wfopen/test3/CMakeLists.txt
new file mode 100644
index 0000000000..deec8bbfe6
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_wfopen/test3/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test3.c
+)
+
+add_executable(paltest_wfopen_test3
+ ${SOURCES}
+)
+
+add_dependencies(paltest_wfopen_test3 coreclrpal)
+
+target_link_libraries(paltest_wfopen_test3
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_wfopen/test3/test3.c b/src/pal/tests/palsuite/c_runtime/_wfopen/test3/test3.c
new file mode 100644
index 0000000000..3b67818bc5
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_wfopen/test3/test3.c
@@ -0,0 +1,70 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test3.c
+**
+** Purpose: Tests the PAL implementation of the _wfopen function.
+** Test to ensure that you can write to a 'w+' mode file.
+** And that you can read from a 'w+' mode file.
+**
+** Depends:
+** fprintf
+** fseek
+** fgets
+**
+
+**
+**===================================================================*/
+
+#define UNICODE
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char **argv)
+{
+
+ FILE *fp;
+ char buffer[128];
+ WCHAR filename[] = {'t','e','s','t','f','i','l','e','\0'};
+ WCHAR writeplus[] = {'w','+','\0'};
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ /* Open a file with 'w+' mode */
+ if( (fp = _wfopen( filename, writeplus )) == NULL )
+ {
+ Fail( "ERROR: The file failed to open with 'w+' mode.\n" );
+ }
+
+ /* Write some text to the file */
+ if(fprintf(fp,"%s","some text") <= 0)
+ {
+ Fail("ERROR: Attempted to WRITE to a file opened with 'w+' mode "
+ "but fprintf failed. Either fopen or fprintf have problems.");
+ }
+
+ if(fseek(fp, 0, SEEK_SET))
+ {
+ Fail("ERROR: fseek failed, and this test depends on it.");
+ }
+
+ /* Attempt to read from the 'w+' only file, should pass */
+ if(fgets(buffer,10,fp) == NULL)
+ {
+ Fail("ERROR: Tried to READ from a file with 'w+' mode set. "
+ "This should succeed, but fgets returned NULL. Either fgets "
+ "or fopen is broken.");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/_wfopen/test3/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_wfopen/test3/testinfo.dat
new file mode 100644
index 0000000000..3dd23e7946
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_wfopen/test3/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _wfopen
+Name = Positive Test for _wfopen
+TYPE = DEFAULT
+EXE1 = test3
+Description
+= Test to ensure that you can write to a 'w+' mode file. And that you can
+= read from a 'w+' mode file.
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/_wfopen/test4/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_wfopen/test4/CMakeLists.txt
new file mode 100644
index 0000000000..e93cdd58de
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_wfopen/test4/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test4.c
+)
+
+add_executable(paltest_wfopen_test4
+ ${SOURCES}
+)
+
+add_dependencies(paltest_wfopen_test4 coreclrpal)
+
+target_link_libraries(paltest_wfopen_test4
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_wfopen/test4/test4.c b/src/pal/tests/palsuite/c_runtime/_wfopen/test4/test4.c
new file mode 100644
index 0000000000..0948fa11cc
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_wfopen/test4/test4.c
@@ -0,0 +1,87 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test4.c
+**
+** Purpose: Tests the PAL implementation of the _wfopen function.
+** Test to ensure that you can't write to a 'r' mode file.
+** And that you can read from a 'r' mode file.
+**
+** Depends:
+** fprintf
+** fclose
+** fgets
+**
+
+**
+**===================================================================*/
+
+#define UNICODE
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char **argv)
+{
+
+ FILE *fp;
+ char buffer[128];
+ WCHAR filename[] = {'t','e','s','t','f','i','l','e','\0'};
+ WCHAR write[] = {'w','\0'};
+ WCHAR read[] = {'r','\0'};
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ /* Open a file with 'w' mode */
+ if( (fp = _wfopen( filename, write )) == NULL )
+ {
+ Fail( "ERROR: The file failed to open with 'w' mode.\n" );
+ }
+
+ /* Write some text to the file */
+ if(fprintf(fp,"%s","some text") <= 0)
+ {
+ Fail("ERROR: Attempted to WRITE to a file opened with 'w' mode "
+ "but fprintf failed. Either fopen or fprintf have problems.");
+ }
+
+ if(fclose(fp))
+ {
+ Fail("ERROR: Attempted to close a file, but fclose failed. "
+ "This test depends upon it.");
+ }
+
+ /* Open a file with 'r' mode */
+ if( (fp = _wfopen( filename, read )) == NULL )
+ {
+ Fail( "ERROR: The file failed to open with 'r' mode.\n" );
+ }
+
+ /* Attempt to read from the 'r' only file, should pass */
+ if(fgets(buffer,10,fp) == NULL)
+ {
+ Fail("ERROR: Tried to READ from a file with 'r' mode set. "
+ "This should succeed, but fgets returned NULL. Either fgets "
+ "or fopen is broken.");
+ }
+
+ /* Write some text to the file */
+ if(fprintf(fp,"%s","some text") > 0)
+ {
+ Fail("ERROR: Attempted to WRITE to a file opened with 'r' mode "
+ "but fprintf succeeded It should have failed. "
+ "Either fopen or fprintf have problems.");
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/_wfopen/test4/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_wfopen/test4/testinfo.dat
new file mode 100644
index 0000000000..de41d77317
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_wfopen/test4/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _wfopen
+Name = Positive Test for _wfopen
+TYPE = DEFAULT
+EXE1 = test4
+Description
+= Test to ensure that you can't write to a 'r' mode file. And that you can
+= read from a 'r' mode file.
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/_wfopen/test5/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_wfopen/test5/CMakeLists.txt
new file mode 100644
index 0000000000..1530416795
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_wfopen/test5/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test5.c
+)
+
+add_executable(paltest_wfopen_test5
+ ${SOURCES}
+)
+
+add_dependencies(paltest_wfopen_test5 coreclrpal)
+
+target_link_libraries(paltest_wfopen_test5
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_wfopen/test5/test5.c b/src/pal/tests/palsuite/c_runtime/_wfopen/test5/test5.c
new file mode 100644
index 0000000000..21e5ec84ed
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_wfopen/test5/test5.c
@@ -0,0 +1,82 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test5.c
+**
+** Purpose: Tests the PAL implementation of the _wfopen function.
+** Test to ensure that you can write to a 'r+' mode file.
+** And that you can read from a 'r+' mode file.
+**
+** Depends:
+** fprintf
+** fclose
+** fgets
+** fseek
+**
+
+**
+**===================================================================*/
+#define UNICODE
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char **argv)
+{
+
+ FILE *fp;
+ char buffer[128];
+ WCHAR filename[] = {'t','e','s','t','f','i','l','e','\0'};
+ WCHAR write[] = {'w','\0'};
+ WCHAR readplus[] = {'r','+','\0'};
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ /* Open a file with 'w' mode */
+ if( (fp = _wfopen( filename,write )) == NULL )
+ {
+ Fail( "ERROR: The file failed to open with 'w' mode.\n" );
+ }
+
+ if(fclose(fp))
+ {
+ Fail("ERROR: Attempted to close a file, but fclose failed. "
+ "This test depends upon it.");
+ }
+
+ if( (fp = _wfopen( filename, readplus )) == NULL )
+ {
+ Fail( "ERROR: The file failed to open with 'r+' mode.\n" );
+ }
+
+ /* Write some text to the file */
+ if(fprintf(fp,"%s","some text") <= 0)
+ {
+ Fail("ERROR: Attempted to WRITE to a file opened with 'r+' mode "
+ "but fprintf failed. Either fopen or fprintf have problems.");
+ }
+
+ if(fseek(fp, 0, SEEK_SET))
+ {
+ Fail("ERROR: fseek failed, and this test depends on it.");
+ }
+
+ /* Attempt to read from the 'r+' only file, should pass */
+ if(fgets(buffer,10,fp) == NULL)
+ {
+ Fail("ERROR: Tried to READ from a file with 'r+' mode set. "
+ "This should succeed, but fgets returned NULL. Either fgets "
+ "or fopen is broken.");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/_wfopen/test5/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_wfopen/test5/testinfo.dat
new file mode 100644
index 0000000000..6be33cb2be
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_wfopen/test5/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _wfopen
+Name = Positive Test for _wfopen
+TYPE = DEFAULT
+EXE1 = test5
+Description
+= Test to ensure that you can write to a 'r+' mode file. And that you can
+= read from a 'r+' mode file.
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/_wfopen/test6/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_wfopen/test6/CMakeLists.txt
new file mode 100644
index 0000000000..c401c6f40f
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_wfopen/test6/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test6.c
+)
+
+add_executable(paltest_wfopen_test6
+ ${SOURCES}
+)
+
+add_dependencies(paltest_wfopen_test6 coreclrpal)
+
+target_link_libraries(paltest_wfopen_test6
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_wfopen/test6/test6.c b/src/pal/tests/palsuite/c_runtime/_wfopen/test6/test6.c
new file mode 100644
index 0000000000..17d36a0c50
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_wfopen/test6/test6.c
@@ -0,0 +1,152 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test6.c
+**
+** Purpose: Tests the PAL implementation of the _wfopen function.
+** Test to ensure that you can write to an 'a' mode file.
+** And that you can't read from a 'a' mode file.
+**
+** Depends:
+** fprintf
+** fgets
+** fseek
+**
+
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char **argv)
+{
+ FILE *fp;
+ char buffer[128];
+ WCHAR filename[] = {'t','e','s','t','f','i','l','e','\0'};
+ WCHAR filename2[] = {'t','e','s','t','f','i','l','e','2','\0'};
+ WCHAR append[] = {'a','\0'};
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ /* Open a file with 'a' mode */
+ if( (fp = _wfopen( filename, append )) == NULL )
+ {
+ Fail( "ERROR: file failed to open with 'a' mode.\n" );
+ }
+
+ /* Write some text to the file */
+ if(fprintf(fp,"%s","some text") <= 0)
+ {
+ Fail("ERROR: Attempted to WRITE to a file opened with 'a' mode "
+ "but fprintf failed. Either fopen or fprintf have problems.");
+ }
+
+ if(fseek(fp, 0, SEEK_SET))
+ {
+ Fail("ERROR: fseek failed, and this test depends on it.");
+ }
+
+ /* Attempt to read from the 'a' only file, should fail */
+ if(fgets(buffer,10,fp) != NULL)
+ {
+ Fail("ERROR: Tried to READ from a file with 'a' mode set. "
+ "This should fail, but fgets returned success. Either fgets "
+ "or fopen is broken.");
+ }
+
+ // Delete the file now that we're done with it.
+ if (fclose(fp) != 0)
+ {
+ Fail("ERROR: fclose failed to close \"testfile\".\n");
+ }
+
+ if (!DeleteFileA("testfile"))
+ {
+ Fail("ERROR: Failed to delete \"testfile\".\n"
+ " Error is %d\n",
+ GetLastError());
+ }
+
+ /* Attempt to write to a file after using 'a' and fseek */
+ fp = _wfopen(filename2, append);
+ if(fp == NULL)
+ {
+ Fail("ERROR: _wfopen failed to be created with 'a' mode.\n");
+ }
+
+ /* write text to the file initially */
+ if(fprintf(fp,"%s","abcd") <= 0)
+ {
+ Fail("ERROR: Attempted to WRITE to a file opened with 'a' mode "
+ "but fprintf failed. Either fopen or fprintf have problems.\n");
+ }
+
+ /* set the pointer to the front of the file */
+ if(fseek(fp, 0, SEEK_SET))
+ {
+ Fail("ERROR: fseek failed, and this test depends on it.\n");
+ }
+
+ /* using 'a' should still write to the end of the file, not the front */
+ if(fputs("efgh", fp) < 0)
+ {
+ Fail("ERROR: Attempt to WRITE with fputs to the beginning of a file "
+ "opened with 'a' mode succeeded.\n");
+ }
+
+ /* set the pointer to the front of the file */
+ if(fseek(fp, 0, SEEK_SET))
+ {
+ Fail("ERROR: fseek failed, and this test depends on it.\n");
+ }
+
+ /* a file with 'a' mode can only write, so close the file before reading */
+ if(fclose(fp))
+ {
+ Fail("ERROR: fclose failed when it should have succeeded.\n");
+ }
+
+ /* open the file again to read */
+ fp = fopen("testfile2","r");
+ if(fp == NULL)
+ {
+ Fail("ERROR: fopen failed to open the file using 'r' mode");
+ }
+
+ /* Attempt to read from the 'a' only file, should succeed */
+ if(fgets(buffer,10,fp) == NULL)
+ {
+ Fail("ERROR: Tried to READ from a file with 'a' mode set. "
+ "This should pass, but fgets returned failure. Either fgets "
+ "or fopen is broken.\n");
+ }
+
+ /* Compare what was read and what should have been in the file */
+ if(memcmp(buffer,"abcdefgh",8))
+ {
+ Fail("ERROR: The string read should have equaled 'abcdefgh' "
+ "but instead it is %s\n", buffer);
+ }
+
+ // Delete the file now that we're done with it.
+ if (fclose(fp) != 0)
+ {
+ Fail("ERROR: fclose failed to close \"testfile\".\n");
+ }
+
+ if (!DeleteFileA("testfile2"))
+ {
+ Fail("ERROR: Failed to delete \"testfile2\".\n");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/_wfopen/test6/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_wfopen/test6/testinfo.dat
new file mode 100644
index 0000000000..832f102416
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_wfopen/test6/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _wfopen
+Name = Positive Test for _wfopen
+TYPE = DEFAULT
+EXE1 = test6
+Description
+= Test to ensure that you can write to a 'a' mode file. And that you can't
+= read from a 'a' mode file.
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/_wfopen/test7/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_wfopen/test7/CMakeLists.txt
new file mode 100644
index 0000000000..47f4804b43
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_wfopen/test7/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test7.c
+)
+
+add_executable(paltest_wfopen_test7
+ ${SOURCES}
+)
+
+add_dependencies(paltest_wfopen_test7 coreclrpal)
+
+target_link_libraries(paltest_wfopen_test7
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_wfopen/test7/test7.c b/src/pal/tests/palsuite/c_runtime/_wfopen/test7/test7.c
new file mode 100644
index 0000000000..0a889adc8a
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_wfopen/test7/test7.c
@@ -0,0 +1,119 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test7.c
+**
+** Purpose: Tests the PAL implementation of the _wfopen function.
+** Test to ensure that you can write to an 'a+' mode file.
+** And that you can read from a 'a+' mode file.
+**
+** Depends:
+** fprintf
+** fgets
+** fseek
+**
+
+**
+**===================================================================*/
+#define UNICODE
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char **argv)
+{
+
+ FILE *fp;
+ char buffer[128];
+ WCHAR filename[] = {'t','e','s','t','f','i','l','e','\0'};
+ WCHAR filename2[] = {'t','e','s','t','f','i','l','e','2','\0'};
+ WCHAR appendplus[] = {'a','+','\0'};
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ /* Open a file with 'a+' mode */
+ if( (fp = _wfopen( filename, appendplus )) == NULL )
+ {
+ Fail( "ERROR: The file failed to open with 'a+' mode.\n" );
+ }
+
+ /* Write some text to the file */
+ if(fprintf(fp,"%s","some text") <= 0)
+ {
+ Fail("ERROR: Attempted to WRITE to a file opened with 'a+' mode "
+ "but fprintf failed. Either fopen or fprintf have problems.");
+ }
+
+ if(fseek(fp, 0, SEEK_SET))
+ {
+ Fail("ERROR: fseek failed, and this test depends on it.");
+ }
+
+ /* Attempt to read from the 'a+' only file, should succeed */
+ if(fgets(buffer,10,fp) == NULL)
+ {
+ Fail("ERROR: Tried to READ from a file with 'a+' mode set. "
+ "This should pass, but fgets returned failure. Either fgets "
+ "or fopen is broken.");
+ }
+
+
+ /* Attempt to write to a file after using 'a+' and fseek */
+ fp = _wfopen(filename2, appendplus);
+ if(fp == NULL)
+ {
+ Fail("ERROR: _wfopen failed to be created with 'a+' mode.\n");
+ }
+
+ /* write text to the file initially */
+ if(fprintf(fp,"%s","abcd") <= 0)
+ {
+ Fail("ERROR: Attempted to WRITE to a file opened with 'a+' mode "
+ "but fprintf failed. Either fopen or fprintf have problems.\n");
+ }
+
+ /* set the pointer to the front of the file */
+ if(fseek(fp, 0, SEEK_SET))
+ {
+ Fail("ERROR: fseek failed, and this test depends on it.\n");
+ }
+
+ /* using 'a+' should still write to the end of the file, not the front */
+ if(fputs("efgh",fp) < 0)
+ {
+ Fail("ERROR: Attempted to WRITE to a file opened with 'a+' mode "
+ "but fputs failed.\n");
+ }
+
+ /* set the pointer to the front of the file */
+ if(fseek(fp, 0, SEEK_SET))
+ {
+ Fail("ERROR: fseek failed, and this test depends on it.\n");
+ }
+
+ /* Attempt to read from the 'a+' only file, should succeed */
+ if(fgets(buffer,10,fp) == NULL)
+ {
+ Fail("ERROR: Tried to READ from a file with 'a+' mode set. "
+ "This should pass, but fgets returned failure. Either fgets "
+ "or fopen is broken.\n");
+ }
+
+ /* Compare what was read and what should have been in the file */
+ if(memcmp(buffer,"abcdefgh",8))
+ {
+ Fail("ERROR: The string read should have equaled 'abcdefgh' "
+ "but instead it is %s\n", buffer);
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/_wfopen/test7/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_wfopen/test7/testinfo.dat
new file mode 100644
index 0000000000..0c50efb759
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_wfopen/test7/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _wfopen
+Name = Positive Test for _wfopen
+TYPE = DEFAULT
+EXE1 = test7
+Description
+= Test to ensure that you can write to a 'a+' mode file. And that you can
+= read from a 'a+' mode file.
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/_wmakepath/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_wmakepath/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_wmakepath/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/_wmakepath/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_wmakepath/test1/CMakeLists.txt
new file mode 100644
index 0000000000..343cb41f51
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_wmakepath/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_wmakepath_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_wmakepath_test1 coreclrpal)
+
+target_link_libraries(paltest_wmakepath_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_wmakepath/test1/test1.c b/src/pal/tests/palsuite/c_runtime/_wmakepath/test1/test1.c
new file mode 100644
index 0000000000..eb79dc6286
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_wmakepath/test1/test1.c
@@ -0,0 +1,76 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test1.c
+**
+** Purpose: Tests the PAL implementation of the _wmakepath function.
+** Create a path, and ensure that it builds how it is
+** supposed to.
+**
+**
+**===================================================================*/
+
+#define UNICODE
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char **argv)
+{
+ WCHAR FullPath[128];
+ WCHAR File[] = {'t','e','s','t','\0'};
+ WCHAR Ext[] = {'t','x','t','\0'};
+ char * PrintResult=NULL; /* Used for printing out errors */
+ char * PrintCorrect=NULL;
+
+#if WIN32
+ WCHAR Drive[] = {'C','\0'};
+ WCHAR Dir[] = {'\\','t','e','s','t','\0'};
+ WCHAR PathName[] =
+ {'C',':','\\','t','e','s','t','\\','t','e',
+ 's','t','.','t','x','t','\0'};
+#else
+ WCHAR *Drive = NULL;
+ WCHAR Dir[] = {'/','t','e','s','t','\0'};
+ WCHAR PathName[] =
+ {'/','t','e','s','t','/','t','e','s','t','.','t','x','t','\0'};
+#endif
+
+ /*
+ * Initialize the PAL and return FAIL if this fails
+ */
+ if (0 != (PAL_Initialize(argc,argv)))
+ {
+ return FAIL;
+ }
+
+ _wmakepath(FullPath, Drive, Dir, File, Ext);
+
+ if(wcscmp(FullPath,PathName) != 0)
+ {
+ PrintResult = convertC(FullPath);
+ PrintCorrect = convertC(PathName);
+
+ Fail("ERROR: The pathname which was created turned out to be %s "
+ "when it was supposed to be %s.\n",PrintResult,PrintCorrect);
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/_wmakepath/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_wmakepath/test1/testinfo.dat
new file mode 100644
index 0000000000..6720d342ce
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_wmakepath/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _wmakepath
+Name = Positive Test for _wmakepath
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Purpose: Tests the PAL implementation of the _wmakepath function.
+= Create a path, and ensure that it builds how it is supposed to.
diff --git a/src/pal/tests/palsuite/c_runtime/_wsplitpath/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_wsplitpath/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_wsplitpath/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/_wsplitpath/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_wsplitpath/test1/CMakeLists.txt
new file mode 100644
index 0000000000..ee9a7a8e96
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_wsplitpath/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_wsplitpath_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_wsplitpath_test1 coreclrpal)
+
+target_link_libraries(paltest_wsplitpath_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_wsplitpath/test1/test1.c b/src/pal/tests/palsuite/c_runtime/_wsplitpath/test1/test1.c
new file mode 100644
index 0000000000..305768e53a
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_wsplitpath/test1/test1.c
@@ -0,0 +1,151 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Passes _wsplitpath() a series of sample paths and checks
+** that it parses them as expected.
+**
+**
+**==========================================================================*/
+
+
+#include <palsuite.h>
+
+struct testCase
+{
+ char path[_MAX_PATH]; /* The path to parse. */
+ char drive[_MAX_DRIVE]; /* The expected values... */
+ char dir[_MAX_DIR];
+ char fname[_MAX_FNAME];
+ char ext[_MAX_EXT];
+};
+
+struct wTestCase
+{
+ WCHAR *path; /* The path to parse. */
+ WCHAR *drive; /* The expected values... */
+ WCHAR *dir;
+ WCHAR *fname;
+ WCHAR *ext;
+};
+
+
+
+int __cdecl main(int argc, char **argv)
+{
+ struct testCase testCases[] =
+ {
+#if WIN32
+ {"c:\\foo\\bar\\foo.bar", "c:", "\\foo\\bar\\", "foo", ".bar"},
+ {"c:/foo/bar/foo.bar", "c:", "/foo/bar/", "foo", ".bar"},
+ {"c:/foo/bar/foo", "c:", "/foo/bar/", "foo", ""},
+ {"c:/foo/bar/.bar", "c:", "/foo/bar/", "", ".bar"},
+ {"c:/foo/bar/", "c:", "/foo/bar/", "", ""},
+ {"/foo/bar/foo.bar", "", "/foo/bar/", "foo", ".bar"},
+ {"c:foo.bar", "c:", "", "foo", ".bar"}
+#else
+ {"c:\\foo\\bar\\foo.bar", "","c:/foo/bar/", "foo", ".bar"},
+ {"c:/foo/bar/foo.bar", "", "c:/foo/bar/", "foo", ".bar"},
+ {"c:/foo/bar/foo", "", "c:/foo/bar/", "foo", ""},
+ {"c:/foo/bar/.bar", "", "c:/foo/bar/", ".bar", ""},
+ {"c:/foo/bar/", "", "c:/foo/bar/", "", ""},
+ {"/foo/bar/foo.bar", "", "/foo/bar/", "foo", ".bar"},
+ {"c:foo.bar", "", "", "c:foo", ".bar"}
+#endif
+ };
+
+ struct wTestCase wTestCases[sizeof(testCases)/sizeof(struct testCase)];
+
+ wchar_t wDrive[_MAX_DRIVE];
+ wchar_t wDir[_MAX_DIR];
+ wchar_t wFname[_MAX_FNAME];
+ wchar_t wExt[_MAX_EXT];
+
+ char *drive;
+ char *dir;
+ char *fname;
+ char *ext;
+
+ int i;
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ /*create wide character versions of the test cases*/
+ for(i = 0; i < sizeof(testCases)/sizeof(struct testCase); i ++)
+ {
+ wTestCases[i].path = convert(testCases[i].path);
+ wTestCases[i].drive = convert(testCases[i].drive);
+ wTestCases[i].dir = convert(testCases[i].dir);
+ wTestCases[i].fname = convert(testCases[i].fname);
+ wTestCases[i].ext = convert(testCases[i].ext);
+ }
+
+
+ for (i = 0; i < sizeof(wTestCases)/sizeof(struct wTestCase); i++)
+ {
+ _wsplitpath(wTestCases[i].path, wDrive, wDir, wFname, wExt);
+
+ /*Convert the results to regular ANSI strings.*/
+ drive = convertC(wDrive);
+ dir = convertC(wDir);
+ fname = convertC(wFname);
+ ext = convertC(wExt);
+
+
+ /*on platforms that don't support drive letters, the drive
+ returned should always be "" */
+ if (wcscmp(wDrive, wTestCases[i].drive) != 0)
+ {
+ Fail("_wsplitpath read the path \"%s\" and thought the drive was "
+ "\"%s\" instead of \"%s\""
+ , testCases[i].path, drive, testCases[i].drive);
+ }
+
+ if (wcscmp(wDir, wTestCases[i].dir) != 0)
+ {
+ Fail("_wsplitpath read the path \"%s\" and thought the directory "
+ "was \"%s\" instead of \"%s\""
+ , testCases[i].path, dir, testCases[i].dir);
+ }
+
+ if (wcscmp(wFname, wTestCases[i].fname) != 0)
+ {
+ Fail("_wsplitpath read the path \"%s\" and thought the filename "
+ "was \"%s\" instead of \"%s\""
+ , testCases[i].path, fname, testCases[i].fname);
+ }
+
+ if (wcscmp(wExt, wTestCases[i].ext) != 0)
+ {
+ Fail("_wsplitpath read the path \"%s\" and thought the file "
+ "extension was \"%s\" instead of \"%s\""
+ , testCases[i].path, ext, testCases[i].ext);
+ }
+
+ free(drive);
+ free(dir);
+ free(fname);
+ free(ext);
+ }
+
+ for(i = 0; i < sizeof(testCases)/sizeof(struct testCase); i++)
+ {
+ free(wTestCases[i].path);
+ free(wTestCases[i].drive);
+ free(wTestCases[i].dir);
+ free(wTestCases[i].fname);
+ free(wTestCases[i].ext);
+ }
+
+ PAL_Terminate();
+
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/_wsplitpath/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_wsplitpath/test1/testinfo.dat
new file mode 100644
index 0000000000..30be680bb4
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_wsplitpath/test1/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _wsplitpath
+Name = Positive Test for _wsplitpath
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Passes _wsplitpath() a series of sample paths and checks that it
+= parses them as expected.
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/_wtoi/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_wtoi/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_wtoi/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/_wtoi/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/_wtoi/test1/CMakeLists.txt
new file mode 100644
index 0000000000..9e6610fc0f
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_wtoi/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_wtoi_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_wtoi_test1 coreclrpal)
+
+target_link_libraries(paltest_wtoi_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/_wtoi/test1/test1.c b/src/pal/tests/palsuite/c_runtime/_wtoi/test1/test1.c
new file mode 100644
index 0000000000..0b14dedd60
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_wtoi/test1/test1.c
@@ -0,0 +1,79 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test1.c
+**
+** Purpose: Tests the PAL implementation of the _wtoi function.
+** Check to ensure that the different ints are handled properly.
+** Exponents and decimals should be treated as invalid characters,
+** causing the conversion to quit. Whitespace before the int is valid.
+** Check would-be octal/hex digits to ensure they're treated no
+** differently than other strings.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+
+struct testCase
+{
+ int IntValue;
+ char avalue[20];
+};
+
+int __cdecl main(int argc, char **argv)
+{
+
+ int result=0;
+ int i=0;
+ WCHAR* temp;
+
+ struct testCase testCases[] =
+ {
+ {1234, "1234"},
+ {-1234, "-1234"},
+ {1234, "+1234"},
+ {1234, "1234.44"},
+ {1234, "1234e-5"},
+ {1234, "1234e+5"},
+ {1234, "1234E5"},
+ {1234, "\t1234"},
+ {0, "0x21"},
+ {17, "017"},
+ {1234, "1234.657e-8"},
+ {1234567, " 1234567e-8 foo"},
+ {0, "foo 32 bar"}
+ };
+
+ if (0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /* Loop through each case. Convert the wide string to an int
+ and then compare to ensure that it is the correct value.
+ */
+
+ for(i = 0; i < sizeof(testCases) / sizeof(struct testCase); i++)
+ {
+ /* Convert to a wide string, then call _wtoi to convert to an int */
+ temp = convert(testCases[i].avalue);
+ result = _wtoi(temp);
+ free(temp);
+ if (testCases[i].IntValue != result)
+ {
+ Fail("ERROR: _wtoi misinterpreted \"%s\" as %i instead of %i.\n",
+ testCases[i].avalue,
+ result,
+ testCases[i].IntValue);
+ }
+
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/_wtoi/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/_wtoi/test1/testinfo.dat
new file mode 100644
index 0000000000..4a1f21d4b9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/_wtoi/test1/testinfo.dat
@@ -0,0 +1,17 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = _wtoi
+Name = Test _wtoi on valid and invalid ints in a variety of formats
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Tests the PAL implementation of the _wtoi function.
+= Check to ensure that the different ints are handled properly.
+= Exponents and decimals should be treated as invalid characters,
+= causing the conversion to quit. Whitespace before the int is valid.
+= Check would-be octal/hex digits to ensure they're treated no
+= differently than other strings.
diff --git a/src/pal/tests/palsuite/c_runtime/abs/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/abs/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/abs/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/abs/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/abs/test1/CMakeLists.txt
new file mode 100644
index 0000000000..c8a8595d01
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/abs/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ abs.c
+)
+
+add_executable(paltest_abs_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_abs_test1 coreclrpal)
+
+target_link_libraries(paltest_abs_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/abs/test1/abs.c b/src/pal/tests/palsuite/c_runtime/abs/test1/abs.c
new file mode 100644
index 0000000000..233a5dcb30
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/abs/test1/abs.c
@@ -0,0 +1,54 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: abs.c (test 1)
+**
+** Purpose: Tests the PAL implementation of the abs function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+struct TESTS
+{
+ int nTest;
+ int nResult;
+};
+
+int __cdecl main(int argc, char *argv[])
+{
+ int i = 0;
+ int nRc = 0;
+ struct TESTS testCase[] =
+ {
+ {0, 0},
+ {1, 1},
+ {-1, 1}
+ };
+
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ for (i = 0; i < (sizeof(testCase)/sizeof(struct TESTS)); i++)
+ {
+ nRc = abs(testCase[i].nTest);
+ if (nRc != testCase[i].nResult)
+ {
+ Fail("abs: ERROR -> abs(%d) returned %d "
+ "when it was expected to return %d \n",
+ testCase[i].nTest,
+ nRc,
+ testCase[i].nResult);
+ }
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/abs/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/abs/test1/testinfo.dat
new file mode 100644
index 0000000000..98e2af21d4
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/abs/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C runtime
+Function = abs
+Name = test for abs (test 1)
+Type = DEFAULT
+EXE1 = abs
+Description
+= Test abs by passing a list of values and ensuring the
+= proper absolute value is returned.
diff --git a/src/pal/tests/palsuite/c_runtime/acos/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/acos/CMakeLists.txt
new file mode 100644
index 0000000000..5e1ef7f28b
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/acos/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
diff --git a/src/pal/tests/palsuite/c_runtime/acos/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/acos/test1/CMakeLists.txt
new file mode 100644
index 0000000000..978ab427e8
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/acos/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_acos_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_acos_test1 coreclrpal)
+
+target_link_libraries(paltest_acos_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/acos/test1/test1.c b/src/pal/tests/palsuite/c_runtime/acos/test1/test1.c
new file mode 100644
index 0000000000..c6ed0692c7
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/acos/test1/test1.c
@@ -0,0 +1,130 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Test to ensure that acos return the correct values
+**
+** Dependencies: PAL_Initialize
+** PAL_Terminate
+** Fail
+** fabs
+**
+**===========================================================================*/
+
+#include <palsuite.h>
+
+// binary64 (double) has a machine epsilon of 2^-52 (approx. 2.22e-16). However, this
+// is slightly too accurate when writing tests meant to run against libm implementations
+// for various platforms. 2^-50 (approx. 8.88e-16) seems to be as accurate as we can get.
+//
+// The tests themselves will take PAL_EPSILON and adjust it according to the expected result
+// so that the delta used for comparison will compare the most significant digits and ignore
+// any digits that are outside the double precision range (15-17 digits).
+
+// For example, a test with an expect result in the format of 0.xxxxxxxxxxxxxxxxx will use
+// PAL_EPSILON for the variance, while an expected result in the format of 0.0xxxxxxxxxxxxxxxxx
+// will use PAL_EPSILON / 10 and and expected result in the format of x.xxxxxxxxxxxxxxxx will
+// use PAL_EPSILON * 10.
+#define PAL_EPSILON 8.8817841970012523e-16
+
+#define PAL_NAN sqrt(-1.0)
+#define PAL_POSINF -log(0.0)
+#define PAL_NEGINF log(0.0)
+
+/**
+ * Helper test structure
+ */
+struct test
+{
+ double value; /* value to test the function with */
+ double expected; /* expected result */
+ double variance; /* maximum delta between the expected and actual result */
+};
+
+/**
+ * validate
+ *
+ * test validation function
+ */
+void __cdecl validate(double value, double expected, double variance)
+{
+ double result = acos(value);
+
+ /*
+ * The test is valid when the difference between result
+ * and expected is less than or equal to variance
+ */
+ double delta = fabs(result - expected);
+
+ if (delta > variance)
+ {
+ Fail("acos(%g) returned %20.17g when it should have returned %20.17g",
+ value, result, expected);
+ }
+}
+
+/**
+ * validate
+ *
+ * test validation function for values returning NaN
+ */
+void __cdecl validate_isnan(double value)
+{
+ double result = acos(value);
+
+ if (!_isnan(result))
+ {
+ Fail("acos(%g) returned %20.17g when it should have returned %20.17g",
+ value, result, PAL_NAN);
+ }
+}
+
+/**
+ * main
+ *
+ * executable entry point
+ */
+int __cdecl main(int argc, char **argv)
+{
+ struct test tests[] =
+ {
+ /* value expected variance */
+ { -1, 3.1415926535897932, PAL_EPSILON * 10 }, // expected: pi
+ { -0.91173391478696510, 2.7182818284590452, PAL_EPSILON * 10 }, // expected: e
+ { -0.66820151019031295, 2.3025850929940457, PAL_EPSILON * 10 }, // expected: ln(10)
+ { 0, 1.5707963267948966, PAL_EPSILON * 10 }, // expected: pi / 2
+ { 0.12775121753523991, 1.4426950408889634, PAL_EPSILON * 10 }, // expected: log2(e)
+ { 0.15594369476537447, 1.4142135623730950, PAL_EPSILON * 10 }, // expected: sqrt(2)
+ { 0.42812514788535792, 1.1283791670955126, PAL_EPSILON * 10 }, // expected: 2 / sqrt(pi)
+ { 0.54030230586813972, 1, PAL_EPSILON * 10 },
+ { 0.70710678118654752, 0.78539816339744831, PAL_EPSILON }, // expected: pi / 4, value: 1 / sqrt(2)
+ { 0.76024459707563015, 0.70710678118654752, PAL_EPSILON }, // expected: 1 / sqrt(2)
+ { 0.76923890136397213, 0.69314718055994531, PAL_EPSILON }, // expected: ln(2)
+ { 0.80410982822879171, 0.63661977236758134, PAL_EPSILON }, // expected: 2 / pi
+ { 0.90716712923909839, 0.43429448190325183, PAL_EPSILON }, // expected: log10(e)
+ { 0.94976571538163866, 0.31830988618379067, PAL_EPSILON }, // expected: 1 / pi
+ { 1, 0, PAL_EPSILON },
+ };
+
+ /* PAL initialization */
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+ for (int i = 0; i < (sizeof(tests) / sizeof(struct test)); i++)
+ {
+ validate(tests[i].value, tests[i].expected, tests[i].variance);
+ }
+
+ validate_isnan(PAL_NEGINF);
+ validate_isnan(PAL_NAN);
+ validate_isnan(PAL_POSINF);
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/acos/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/acos/test1/testinfo.dat
new file mode 100644
index 0000000000..4b43982fca
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/acos/test1/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = acos
+Name = Positive Test for acos
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Passes a series of values to the acos() function,
+= checking each for the expected result. Also checks
+= for proper handling of out-of-range values.
diff --git a/src/pal/tests/palsuite/c_runtime/asin/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/asin/CMakeLists.txt
new file mode 100644
index 0000000000..5e1ef7f28b
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/asin/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
diff --git a/src/pal/tests/palsuite/c_runtime/asin/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/asin/test1/CMakeLists.txt
new file mode 100644
index 0000000000..a3aec3f60f
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/asin/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_asin_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_asin_test1 coreclrpal)
+
+target_link_libraries(paltest_asin_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/asin/test1/test1.c b/src/pal/tests/palsuite/c_runtime/asin/test1/test1.c
new file mode 100644
index 0000000000..0a63356ed0
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/asin/test1/test1.c
@@ -0,0 +1,146 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Test to ensure that asin return the correct values
+**
+** Dependencies: PAL_Initialize
+** PAL_Terminate
+** Fail
+** fabs
+**
+**===========================================================================*/
+
+#include <palsuite.h>
+
+// binary64 (double) has a machine epsilon of 2^-52 (approx. 2.22e-16). However, this
+// is slightly too accurate when writing tests meant to run against libm implementations
+// for various platforms. 2^-50 (approx. 8.88e-16) seems to be as accurate as we can get.
+//
+// The tests themselves will take PAL_EPSILON and adjust it according to the expected result
+// so that the delta used for comparison will compare the most significant digits and ignore
+// any digits that are outside the double precision range (15-17 digits).
+
+// For example, a test with an expect result in the format of 0.xxxxxxxxxxxxxxxxx will use
+// PAL_EPSILON for the variance, while an expected result in the format of 0.0xxxxxxxxxxxxxxxxx
+// will use PAL_EPSILON / 10 and and expected result in the format of x.xxxxxxxxxxxxxxxx will
+// use PAL_EPSILON * 10.
+#define PAL_EPSILON 8.8817841970012523e-16
+
+#define PAL_NAN sqrt(-1.0)
+#define PAL_POSINF -log(0.0)
+#define PAL_NEGINF log(0.0)
+
+/**
+ * Helper test structure
+ */
+struct test
+{
+ double value; /* value to test the function with */
+ double expected; /* expected result */
+ double variance; /* maximum delta between the expected and actual result */
+};
+
+/**
+ * validate
+ *
+ * test validation function
+ */
+void __cdecl validate(double value, double expected, double variance)
+{
+ double result = asin(value);
+
+ /*
+ * The test is valid when the difference between result
+ * and expected is less than or equal to variance
+ */
+ double delta = fabs(result - expected);
+
+ if (delta > variance)
+ {
+ Fail("asin(%g) returned %20.17g when it should have returned %20.17g",
+ value, result, expected);
+ }
+}
+
+/**
+ * validate
+ *
+ * test validation function for values returning NaN
+ */
+void __cdecl validate_isnan(double value)
+{
+ double result = asin(value);
+
+ if (!_isnan(result))
+ {
+ Fail("asin(%g) returned %20.17g when it should have returned %20.17g",
+ value, result, PAL_NAN);
+ }
+}
+
+/**
+ * validate
+ *
+ * test validation function for values returning +INF
+ */
+void __cdecl validate_isinf_positive(double value)
+{
+ double result = asin(value);
+
+ if (result != PAL_POSINF)
+ {
+ Fail("asin(%g) returned %20.17g when it should have returned %20.17g",
+ value, result, PAL_POSINF);
+ }
+}
+
+/**
+ * main
+ *
+ * executable entry point
+ */
+int __cdecl main(int argc, char **argv)
+{
+ struct test tests[] =
+ {
+ /* value expected variance */
+ { 0, 0, PAL_EPSILON },
+ { 0.31296179620778659, 0.31830988618379067, PAL_EPSILON }, // expected: 1 / pi
+ { 0.41078129050290870, 0.42331082513074800, PAL_EPSILON }, // expected: pi - e
+ { 0.42077048331375735, 0.43429448190325183, PAL_EPSILON }, // expected: log10(e)
+ { 0.59448076852482208, 0.63661977236758134, PAL_EPSILON }, // expected: 2 / pi
+ { 0.63896127631363480, 0.69314718055994531, PAL_EPSILON }, // expected: ln(2)
+ { 0.64963693908006244, 0.70710678118654752, PAL_EPSILON }, // expected: 1 / sqrt(2)
+ { 0.70710678118654752, 0.78539816339744831, PAL_EPSILON }, // expected: pi / 4, value: 1 / sqrt(2)
+ { 0.74398033695749319, 0.83900756059574755, PAL_EPSILON }, // expected: pi - ln(10)
+ { 0.84147098480789651, 1, PAL_EPSILON * 10 },
+ { 0.90371945743584630, 1.1283791670955126, PAL_EPSILON * 10 }, // expected: 2 / sqrt(pi)
+ { 0.98776594599273553, 1.4142135623730950, PAL_EPSILON * 10 }, // expected: sqrt(2)
+ { 0.99180624439366372, 1.4426950408889634, PAL_EPSILON * 10 }, // expected: log2(e)
+ { 1, 1.5707963267948966, PAL_EPSILON * 10 }, // expected: pi / 2
+ };
+
+ /* PAL initialization */
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+ for (int i = 0; i < (sizeof(tests) / sizeof(struct test)); i++)
+ {
+ validate( tests[i].value, tests[i].expected, tests[i].variance);
+ validate(-tests[i].value, -tests[i].expected, tests[i].variance);
+ }
+
+ validate_isnan(PAL_NEGINF);
+ validate_isnan(PAL_NAN);
+ validate_isnan(PAL_POSINF);
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/asin/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/asin/test1/testinfo.dat
new file mode 100644
index 0000000000..fba9f95a21
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/asin/test1/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = asin
+Name = Positive Test for asin
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Passes a series of values to the asin() function,
+= checking each for the expected result. Also checks
+= for proper handling of out-of-range values.
diff --git a/src/pal/tests/palsuite/c_runtime/atan/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/atan/CMakeLists.txt
new file mode 100644
index 0000000000..5e1ef7f28b
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/atan/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
diff --git a/src/pal/tests/palsuite/c_runtime/atan/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/atan/test1/CMakeLists.txt
new file mode 100644
index 0000000000..b0b84e7c07
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/atan/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_atan_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_atan_test1 coreclrpal)
+
+target_link_libraries(paltest_atan_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/atan/test1/test1.c b/src/pal/tests/palsuite/c_runtime/atan/test1/test1.c
new file mode 100644
index 0000000000..6840d46172
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/atan/test1/test1.c
@@ -0,0 +1,128 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Test to ensure that atan return the correct values
+**
+** Dependencies: PAL_Initialize
+** PAL_Terminate
+** Fail
+** fabs
+**
+**===========================================================================*/
+
+#include <palsuite.h>
+
+// binary64 (double) has a machine epsilon of 2^-52 (approx. 2.22e-16). However, this
+// is slightly too accurate when writing tests meant to run against libm implementations
+// for various platforms. 2^-50 (approx. 8.88e-16) seems to be as accurate as we can get.
+//
+// The tests themselves will take PAL_EPSILON and adjust it according to the expected result
+// so that the delta used for comparison will compare the most significant digits and ignore
+// any digits that are outside the double precision range (15-17 digits).
+
+// For example, a test with an expect result in the format of 0.xxxxxxxxxxxxxxxxx will use
+// PAL_EPSILON for the variance, while an expected result in the format of 0.0xxxxxxxxxxxxxxxxx
+// will use PAL_EPSILON / 10 and and expected result in the format of x.xxxxxxxxxxxxxxxx will
+// use PAL_EPSILON * 10.
+#define PAL_EPSILON 8.8817841970012523e-16
+
+#define PAL_NAN sqrt(-1.0)
+#define PAL_POSINF -log(0.0)
+#define PAL_NEGINF log(0.0)
+
+/**
+ * Helper test structure
+ */
+struct test
+{
+ double value; /* value to test the function with */
+ double expected; /* expected result */
+ double variance; /* maximum delta between the expected and actual result */
+};
+
+/**
+ * validate
+ *
+ * test validation function
+ */
+void __cdecl validate(double value, double expected, double variance)
+{
+ double result = atan(value);
+
+ /*
+ * The test is valid when the difference between result
+ * and expected is less than or equal to variance
+ */
+ double delta = fabs(result - expected);
+
+ if (delta > variance)
+ {
+ Fail("atan(%g) returned %20.17g when it should have returned %20.17g",
+ value, result, expected);
+ }
+}
+
+/**
+ * validate
+ *
+ * test validation function for values returning NaN
+ */
+void __cdecl validate_isnan(double value)
+{
+ double result = atan(value);
+
+ if (!_isnan(result))
+ {
+ Fail("atan(%g) returned %20.17g when it should have returned %20.17g",
+ value, result, PAL_NAN);
+ }
+}
+
+/**
+ * main
+ *
+ * executable entry point
+ */
+int __cdecl main(int argc, char **argv)
+{
+ struct test tests[] =
+ {
+ /* value expected variance */
+ { 0, 0, PAL_EPSILON },
+ { 0.32951473309607836, 0.31830988618379067, PAL_EPSILON }, // expected: 1 / pi
+ { 0.45054953406980750, 0.42331082513074800, PAL_EPSILON }, // expected: pi - e
+ { 0.46382906716062964, 0.43429448190325183, PAL_EPSILON }, // expected: log10(e)
+ { 0.73930295048660405, 0.63661977236758134, PAL_EPSILON }, // expected: 2 / pi
+ { 0.83064087786078395, 0.69314718055994531, PAL_EPSILON }, // expected: ln(2)
+ { 0.85451043200960189, 0.70710678118654752, PAL_EPSILON }, // expected: 1 / sqrt(2)
+ { 1, 0.78539816339744831, PAL_EPSILON }, // expected: pi / 4
+ { 1.1134071468135374, 0.83900756059574755, PAL_EPSILON }, // expected: pi - ln(10)
+ { 1.5574077246549022, 1, PAL_EPSILON * 10 },
+ { 2.1108768356626451, 1.1283791670955126, PAL_EPSILON * 10 }, // expected: 2 / sqrt(pi)
+ { 6.3341191670421916, 1.4142135623730950, PAL_EPSILON * 10 }, // expected: sqrt(2)
+ { 7.7635756709721848, 1.4426950408889634, PAL_EPSILON * 10 }, // expected: log2(e)
+ { PAL_POSINF, 1.5707963267948966, PAL_EPSILON * 10 }, // expected: pi / 2
+ };
+
+ /* PAL initialization */
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+ for (int i = 0; i < (sizeof(tests) / sizeof(struct test)); i++)
+ {
+ validate( tests[i].value, tests[i].expected, tests[i].variance);
+ validate(-tests[i].value, -tests[i].expected, tests[i].variance);
+ }
+
+ validate_isnan(PAL_NAN);
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/atan/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/atan/test1/testinfo.dat
new file mode 100644
index 0000000000..8a181b8a94
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/atan/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = atan
+Name = Positive Test for atan
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Passes a series of values to the atan() function,
+= checking each for the expected result.
diff --git a/src/pal/tests/palsuite/c_runtime/atan2/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/atan2/CMakeLists.txt
new file mode 100644
index 0000000000..5e1ef7f28b
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/atan2/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
diff --git a/src/pal/tests/palsuite/c_runtime/atan2/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/atan2/test1/CMakeLists.txt
new file mode 100644
index 0000000000..8bd69da2fa
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/atan2/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_atan2_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_atan2_test1 coreclrpal)
+
+target_link_libraries(paltest_atan2_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/atan2/test1/test1.c b/src/pal/tests/palsuite/c_runtime/atan2/test1/test1.c
new file mode 100644
index 0000000000..15aa8f53b9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/atan2/test1/test1.c
@@ -0,0 +1,148 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test1.c
+**
+** Purpose: Tests that atan2 returns correct values for a subset of values.
+** Tests with positive and negative values of x and y to ensure
+** atan2 is returning results from the correct quadrant.
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+// binary64 (double) has a machine epsilon of 2^-52 (approx. 2.22e-16). However, this
+// is slightly too accurate when writing tests meant to run against libm implementations
+// for various platforms. 2^-50 (approx. 8.88e-16) seems to be as accurate as we can get.
+//
+// The tests themselves will take PAL_EPSILON and adjust it according to the expected result
+// so that the delta used for comparison will compare the most significant digits and ignore
+// any digits that are outside the double precision range (15-17 digits).
+
+// For example, a test with an expect result in the format of 0.xxxxxxxxxxxxxxxxx will use
+// PAL_EPSILON for the variance, while an expected result in the format of 0.0xxxxxxxxxxxxxxxxx
+// will use PAL_EPSILON / 10 and and expected result in the format of x.xxxxxxxxxxxxxxxx will
+// use PAL_EPSILON * 10.
+#define PAL_EPSILON 8.8817841970012523e-16
+
+#define PAL_NAN sqrt(-1.0)
+#define PAL_POSINF -log(0.0)
+#define PAL_NEGINF log(0.0)
+
+struct test
+{
+ double y; /* second component of the value to test the function with */
+ double x; /* first component of the value to test the function with */
+ double expected; /* expected result */
+ double variance; /* maximum delta between the expected and actual result */
+};
+
+/**
+ * validate
+ *
+ * test validation function
+ */
+void __cdecl validate(double y, double x, double expected, double variance)
+{
+ double result = atan2(y, x);
+
+ /*
+ * The test is valid when the difference between result
+ * and expected is less than or equal to variance
+ */
+ double delta = fabs(result - expected);
+
+ if (delta > variance)
+ {
+ Fail("atan2(%g, %g) returned %20.17g when it should have returned %20.17g",
+ y, x, result, expected);
+ }
+}
+
+/**
+ * validate
+ *
+ * test validation function for values returning NaN
+ */
+void __cdecl validate_isnan(double y, double x)
+{
+ double result = atan2(y, x);
+
+ if (!_isnan(result))
+ {
+ Fail("atan2(%g, %g) returned %20.17g when it should have returned %20.17g",
+ y, x, result, PAL_NAN);
+ }
+}
+
+/**
+ * main
+ *
+ * executable entry point
+ */
+int __cdecl main(int argc, char **argv)
+{
+ struct test tests[] =
+ {
+ /* y x expected variance */
+ { 0, PAL_POSINF, 0, PAL_EPSILON },
+ { 0, 0, 0, PAL_EPSILON },
+ { 0.31296179620778659, 0.94976571538163866, 0.31830988618379067, PAL_EPSILON }, // expected: 1 / pi
+ { 0.42077048331375735, 0.90716712923909839, 0.43429448190325183, PAL_EPSILON }, // expected: log10(e)
+ { 0.59448076852482208, 0.80410982822879171, 0.63661977236758134, PAL_EPSILON }, // expected: 2 / pi
+ { 0.63896127631363480, 0.76923890136397213, 0.69314718055994531, PAL_EPSILON }, // expected: ln(2)
+ { 0.64963693908006244, 0.76024459707563015, 0.70710678118654752, PAL_EPSILON }, // expected: 1 / sqrt(2)
+ { 0.70710678118654752, 0.70710678118654752, 0.78539816339744831, PAL_EPSILON }, // expected: pi / 4, value: 1 / sqrt(2)
+ { 1, 1, 0.78539816339744831, PAL_EPSILON }, // expected: pi / 4
+ { PAL_POSINF, PAL_POSINF, 0.78539816339744831, PAL_EPSILON }, // expected: pi / 4
+ { 0.84147098480789651, 0.54030230586813972, 1, PAL_EPSILON * 10 },
+ { 0.90371945743584630, 0.42812514788535792, 1.1283791670955126, PAL_EPSILON * 10 }, // expected: 2 / sqrt(pi)
+ { 0.98776594599273553, 0.15594369476537447, 1.4142135623730950, PAL_EPSILON * 10 }, // expected: sqrt(2)
+ { 0.99180624439366372, 0.12775121753523991, 1.4426950408889634, PAL_EPSILON * 10 }, // expected: log2(e)
+ { 1, 0, 1.5707963267948966, PAL_EPSILON * 10 }, // expected: pi / 2
+ { PAL_POSINF, 0, 1.5707963267948966, PAL_EPSILON * 10 }, // expected: pi / 2
+ { PAL_POSINF, 1, 1.5707963267948966, PAL_EPSILON * 10 }, // expected: pi / 2
+ { 0.74398033695749319, -0.66820151019031295, 2.3025850929940457, PAL_EPSILON * 10 }, // expected: ln(10)
+ { 0.41078129050290870, -0.91173391478696510, 2.7182818284590452, PAL_EPSILON * 10 }, // expected: e
+ { 0, -1, 3.1415926535897932, PAL_EPSILON * 10 }, // expected: pi
+ { 1, PAL_POSINF, 0, PAL_EPSILON },
+ };
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+ for (int i = 0; i < (sizeof(tests) / sizeof(struct test)); i++)
+ {
+ const double pi = 3.1415926535897932;
+
+ validate( tests[i].y, tests[i].x, tests[i].expected, tests[i].variance);
+ validate(-tests[i].y, tests[i].x, -tests[i].expected, tests[i].variance);
+ validate( tests[i].y, -tests[i].x, pi - tests[i].expected, tests[i].variance);
+ validate(-tests[i].y, -tests[i].x, tests[i].expected - pi, tests[i].variance);
+ }
+
+ validate_isnan(PAL_NEGINF, PAL_NAN);
+ validate_isnan(PAL_NAN, PAL_NEGINF);
+ validate_isnan(PAL_NAN, PAL_POSINF);
+ validate_isnan(PAL_POSINF, PAL_NAN);
+
+ validate_isnan(PAL_NAN, -1);
+ validate_isnan(PAL_NAN, -0.0);
+ validate_isnan(PAL_NAN, 0);
+ validate_isnan(PAL_NAN, 1);
+
+ validate_isnan(-1, PAL_NAN);
+ validate_isnan(-0.0, PAL_NAN);
+ validate_isnan( 0, PAL_NAN);
+ validate_isnan( 1, PAL_NAN);
+
+ validate_isnan(PAL_NAN, PAL_NAN);
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/atan2/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/atan2/test1/testinfo.dat
new file mode 100644
index 0000000000..78fb09118e
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/atan2/test1/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = atan2
+Name = Test #1 for atan2
+Type = DEFAULT
+EXE1 = test1
+Description
+=Tests that atan2 returns correct values for a subset of values.
+=Tests with positive and negative values of x and y to ensure
+=atan2 is returning results from the correct quadrant.
diff --git a/src/pal/tests/palsuite/c_runtime/atof/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/atof/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/atof/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/atof/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/atof/test1/CMakeLists.txt
new file mode 100644
index 0000000000..1f34b7ebf5
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/atof/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_atof_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_atof_test1 coreclrpal)
+
+target_link_libraries(paltest_atof_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/atof/test1/test1.c b/src/pal/tests/palsuite/c_runtime/atof/test1/test1.c
new file mode 100644
index 0000000000..a973133f9e
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/atof/test1/test1.c
@@ -0,0 +1,75 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Passes to atof() a series of strings containing floats,
+** checking that each one is correctly extracted.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+#include <float.h>
+
+struct testCase
+{
+ float fvalue;
+ char avalue[20];
+};
+
+int __cdecl main(int argc, char **argv)
+{
+ int i = 0;
+ double f = 0;
+ struct testCase testCases[] =
+ {
+ {1234, "1234"},
+ {-1234, "-1234"},
+ {1234e-5, "1234e-5"},
+ {1234e+5, "1234e+5"},
+ {1234e5, "1234E5"},
+ {1234.567e-8, "1234.567e-8"},
+ {1234.567e-8, " 1234.567e-8 foo"},
+ {0,"a12"}
+ };
+
+ /*
+ * Initialize the PAL and return FAIL if this fails
+ */
+ if (0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ for(i = 0; i < sizeof(testCases) / sizeof(struct testCase); i++)
+ {
+ /*Convert the string to a float.*/
+ f = atof(testCases[i].avalue);
+ double result = f - testCases[i].fvalue;
+
+ if (fabs(result) > FLT_EPSILON)
+ {
+ Fail ("atof misinterpreted \"%s\" as %g instead of %g. result %g fabs %g\n",
+ testCases[i].avalue, f, testCases[i].fvalue, result, fabs(result));
+ }
+ }
+ PAL_Terminate();
+ return PASS;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/atof/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/atof/test1/testinfo.dat
new file mode 100644
index 0000000000..7f37affb9c
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/atof/test1/testinfo.dat
@@ -0,0 +1,16 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = atof
+Name = Positive Test for atof
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Passes to atof() a series of strings containing floats, checking that
+= each one is correctly extracted.
+
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/atoi/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/atoi/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/atoi/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/atoi/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/atoi/test1/CMakeLists.txt
new file mode 100644
index 0000000000..3549aca737
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/atoi/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_atoi_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_atoi_test1 coreclrpal)
+
+target_link_libraries(paltest_atoi_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/atoi/test1/test1.c b/src/pal/tests/palsuite/c_runtime/atoi/test1/test1.c
new file mode 100644
index 0000000000..2554d4c353
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/atoi/test1/test1.c
@@ -0,0 +1,86 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test1.c
+**
+** Purpose: Tests the PAL implementation of the atoi function.
+** Check to ensure that the different ints (normal,
+** negative, decimal,exponent), all work as expected with
+** this function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+
+struct testCase
+{
+ int IntValue;
+ char avalue[20];
+};
+
+int __cdecl main(int argc, char **argv)
+{
+
+ int result=0;
+ int i=0;
+
+ struct testCase testCases[] =
+ {
+ {1234, "1234"},
+ {-1234, "-1234"},
+ {1234, "1234.44"},
+ {1234, "1234e-5"},
+ {1234, "1234e+5"},
+ {1234, "1234E5"},
+ {1234, "1234.657e-8"},
+ {1234567, " 1234567e-8 foo"},
+ {0, "aaa 32 test"}
+ };
+
+ /*
+ * Initialize the PAL and return FAIL if this fails
+ */
+ if (0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /* Loop through each case. Convert the string to an int
+ and then compare to ensure that it is the correct value.
+ */
+
+ for(i = 0; i < sizeof(testCases) / sizeof(struct testCase); i++)
+ {
+ /*Convert the string to an int.*/
+ result = atoi(testCases[i].avalue);
+
+ if (testCases[i].IntValue != result)
+ {
+ Fail("ERROR: atoi misinterpreted \"%s\" as %i instead of %i.\n"
+ , testCases[i].avalue, result, testCases[i].IntValue);
+ }
+
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/atoi/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/atoi/test1/testinfo.dat
new file mode 100644
index 0000000000..36a1a4499f
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/atoi/test1/testinfo.dat
@@ -0,0 +1,17 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = atoi
+Name = Positive Test for atoi
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Tests the PAL implementation of the atoi function.
+= Check to ensure that the different ints (normal, negative, decimal,
+= exponent), all work as expected with this function.
+
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/atol/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/atol/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/atol/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/atol/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/atol/test1/CMakeLists.txt
new file mode 100644
index 0000000000..4fea187ad8
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/atol/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_atol_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_atol_test1 coreclrpal)
+
+target_link_libraries(paltest_atol_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/atol/test1/test1.c b/src/pal/tests/palsuite/c_runtime/atol/test1/test1.c
new file mode 100644
index 0000000000..5ad85d873f
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/atol/test1/test1.c
@@ -0,0 +1,88 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test1.c
+**
+** Purpose: Tests the PAL implementation of the atol function.
+** Check to ensure that the different ints (normal,
+** negative, decimal,exponent), all work as expected with
+** this function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+struct testCase
+{
+ LONG LongValue;
+ char avalue[20];
+};
+
+int __cdecl main(int argc, char **argv)
+{
+
+ LONG result=0;
+ int i=0;
+
+ struct testCase testCases[] =
+ {
+ {1234, "1234"},
+ {-1234, "-1234"},
+ {1234, "1234.44"},
+ {1234, "1234e-5"},
+ {1234, "1234e+5"},
+ {1234, "1234E5"},
+ {1234, "1234.657e-8"},
+ {1234, "1234d-5"},
+ {1234, "1234d+5"},
+ {1234, "1234D5"},
+ {1234567, " 1234567e-8 foo"},
+ {0, "aaa 32 test"}
+ };
+
+ /*
+ * Initialize the PAL and return FAIL if this fails
+ */
+ if (0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /* Loop through each case. Convert the string to a LONG
+ and then compare to ensure that it is the correct value.
+ */
+
+ for(i = 0; i < sizeof(testCases) / sizeof(struct testCase); i++)
+ {
+ /*Convert the string to a LONG.*/
+ result = atol(testCases[i].avalue);
+
+ if (testCases[i].LongValue != result)
+ {
+ Fail("ERROR: atol misinterpreted \"%s\" as %d instead of %d.\n"
+ , testCases[i].avalue, result, testCases[i].LongValue);
+ }
+
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/atol/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/atol/test1/testinfo.dat
new file mode 100644
index 0000000000..962a1676a1
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/atol/test1/testinfo.dat
@@ -0,0 +1,17 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = atol
+Name = Positive Test for atol
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Tests the PAL implementation of the atol function.
+= Check to ensure that the different ints (normal, negative, decimal,
+= exponent), all work as expected with this function.
+
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/bsearch/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/bsearch/CMakeLists.txt
new file mode 100644
index 0000000000..ef14ea5352
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/bsearch/CMakeLists.txt
@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+
diff --git a/src/pal/tests/palsuite/c_runtime/bsearch/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/bsearch/test1/CMakeLists.txt
new file mode 100644
index 0000000000..d2018f3325
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/bsearch/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_bsearch_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_bsearch_test1 coreclrpal)
+
+target_link_libraries(paltest_bsearch_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/bsearch/test1/test1.c b/src/pal/tests/palsuite/c_runtime/bsearch/test1/test1.c
new file mode 100644
index 0000000000..c4b91738eb
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/bsearch/test1/test1.c
@@ -0,0 +1,48 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Calls bsearch to find a character in a sorted buffer, and
+** verifies that the correct position is returned.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+
+int __cdecl charcmp(const void *pa, const void *pb)
+{
+ return memcmp(pa, pb, 1);
+}
+
+int __cdecl main(int argc, char **argv)
+{
+
+ const char array[] = "abcdefghij";
+ char * found=NULL;
+
+ /*
+ * Initialize the PAL and return FAIL if this fails
+ */
+ if (0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ found = (char *)bsearch(&"d", array, sizeof(array) - 1, (sizeof(char))
+ , charcmp);
+ if (found != array + 3)
+ {
+ Fail ("bsearch was unable to find a specified character in a "
+ "sorted list.\n");
+ }
+ PAL_Terminate();
+ return PASS;
+}
+
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/bsearch/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/bsearch/test1/testinfo.dat
new file mode 100644
index 0000000000..3eb7369ac2
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/bsearch/test1/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = bsearch
+Name = Positive Test for bsearch
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Calls bsearch to find a character in a sorted buffer, and
+= verifies that the correct position is returned.
+
diff --git a/src/pal/tests/palsuite/c_runtime/bsearch/test2/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/bsearch/test2/CMakeLists.txt
new file mode 100644
index 0000000000..dc65560196
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/bsearch/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test2.c
+)
+
+add_executable(paltest_bsearch_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_bsearch_test2 coreclrpal)
+
+target_link_libraries(paltest_bsearch_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/bsearch/test2/test2.c b/src/pal/tests/palsuite/c_runtime/bsearch/test2/test2.c
new file mode 100644
index 0000000000..6de1b3fada
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/bsearch/test2/test2.c
@@ -0,0 +1,57 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Calls bsearch to find a character in a sorted buffer,
+** that does not exist.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+
+int __cdecl charcmp(const void *pa, const void *pb)
+{
+ return *(const char *)pa - *(const char *)pb;
+}
+
+int __cdecl main(int argc, char **argv)
+{
+
+ const char array[] = "abcefghij";
+ const char missing[] = "0dz";
+ char * found=NULL;
+ const char * candidate = missing;
+
+ /*
+ * Initialize the PAL and return FAIL if this fails
+ */
+ if (0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ while (*candidate) {
+ found = (char *)bsearch(candidate, array, sizeof(array) - 1,
+ (sizeof(char)), charcmp);
+ if (found != NULL)
+ {
+ Fail ("ERROR: bsearch was able to find a specified character '%c' "
+ "in a sorted list '%s' as '%c' "
+ "even though the character is not in the list.\n",
+ *candidate, array, *found);
+ }
+
+ candidate++;
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/bsearch/test2/testinfo.dat b/src/pal/tests/palsuite/c_runtime/bsearch/test2/testinfo.dat
new file mode 100644
index 0000000000..faa9dc1be6
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/bsearch/test2/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = bsearch
+Name = Negative Test for bsearch
+TYPE = DEFAULT
+EXE1 = test2
+Description
+= Calls bsearch to find a character in a sorted buffer,
+= that does not exist.
+
diff --git a/src/pal/tests/palsuite/c_runtime/ceil/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/ceil/CMakeLists.txt
new file mode 100644
index 0000000000..5e1ef7f28b
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/ceil/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
diff --git a/src/pal/tests/palsuite/c_runtime/ceil/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/ceil/test1/CMakeLists.txt
new file mode 100644
index 0000000000..c73ad1dbbe
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/ceil/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_ceil_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_ceil_test1 coreclrpal)
+
+target_link_libraries(paltest_ceil_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/ceil/test1/test1.c b/src/pal/tests/palsuite/c_runtime/ceil/test1/test1.c
new file mode 100644
index 0000000000..e6e36e6e33
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/ceil/test1/test1.c
@@ -0,0 +1,132 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Tests ceil with simple positive and negative values. Also tests
+** extreme cases like extremely small values and positive and
+** negative infinity. Makes sure that calling ceil on NaN returns
+** NaN
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+
+// binary64 (double) has a machine epsilon of 2^-52 (approx. 2.22e-16). However, this
+// is slightly too accurate when writing tests meant to run against libm implementations
+// for various platforms. 2^-50 (approx. 8.88e-16) seems to be as accurate as we can get.
+//
+// The tests themselves will take PAL_EPSILON and adjust it according to the expected result
+// so that the delta used for comparison will compare the most significant digits and ignore
+// any digits that are outside the double precision range (15-17 digits).
+
+// For example, a test with an expect result in the format of 0.xxxxxxxxxxxxxxxxx will use
+// PAL_EPSILON for the variance, while an expected result in the format of 0.0xxxxxxxxxxxxxxxxx
+// will use PAL_EPSILON / 10 and and expected result in the format of x.xxxxxxxxxxxxxxxx will
+// use PAL_EPSILON * 10.
+#define PAL_EPSILON 8.8817841970012523e-16
+
+#define PAL_NAN sqrt(-1.0)
+#define PAL_POSINF -log(0.0)
+#define PAL_NEGINF log(0.0)
+
+/**
+ * Helper test structure
+ */
+struct test
+{
+ double value; /* value to test the function with */
+ double expected; /* expected result */
+ double variance; /* maximum delta between the expected and actual result */
+};
+
+/**
+ * validate
+ *
+ * test validation function
+ */
+void __cdecl validate(double value, double expected, double variance)
+{
+ double result = ceil(value);
+
+ /*
+ * The test is valid when the difference between result
+ * and expected is less than or equal to variance
+ */
+ double delta = fabs(result - expected);
+
+ if (delta > variance)
+ {
+ Fail("ceil(%g) returned %20.17g when it should have returned %20.17g",
+ value, result, expected);
+ }
+}
+
+/**
+ * validate
+ *
+ * test validation function for values returning NaN
+ */
+void __cdecl validate_isnan(double value)
+{
+ double result = ceil(value);
+
+ if (!_isnan(result))
+ {
+ Fail("ceil(%g) returned %20.17g when it should have returned %20.17g",
+ value, result, PAL_NAN);
+ }
+}
+
+/**
+ * main
+ *
+ * executable entry point
+ */
+int __cdecl main(int argc, char *argv[])
+{
+ struct test tests[] =
+ {
+ /* value expected variance */
+ { 0.31830988618379067, 1, PAL_EPSILON * 10 }, // value: 1 / pi
+ { 0.43429448190325183, 1, PAL_EPSILON * 10 }, // value: log10(e)
+ { 0.63661977236758134, 1, PAL_EPSILON * 10 }, // value: 2 / pi
+ { 0.69314718055994531, 1, PAL_EPSILON * 10 }, // value: ln(2)
+ { 0.70710678118654752, 1, PAL_EPSILON * 10 }, // value: 1 / sqrt(2)
+ { 0.78539816339744831, 1, PAL_EPSILON * 10 }, // value: pi / 4
+ { 1.1283791670955126, 2, PAL_EPSILON * 10 }, // value: 2 / sqrt(pi)
+ { 1.4142135623730950, 2, PAL_EPSILON * 10 }, // value: sqrt(2)
+ { 1.4426950408889634, 2, PAL_EPSILON * 10 }, // value: log2(e)
+ { 1.5707963267948966, 2, PAL_EPSILON * 10 }, // value: pi / 2
+ { 2.3025850929940457, 3, PAL_EPSILON * 10 }, // value: ln(10)
+ { 2.7182818284590452, 3, PAL_EPSILON * 10 }, // value: e
+ { 3.1415926535897932, 4, PAL_EPSILON * 10 }, // value: pi
+ { PAL_POSINF, PAL_POSINF, 0 }
+ };
+
+ /* PAL initialization */
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+ validate( 0, 0, PAL_EPSILON);
+ validate(-0.0, 0, PAL_EPSILON);
+
+ validate( 1, 1, PAL_EPSILON * 10);
+ validate(-1.0, -1, PAL_EPSILON * 10);
+
+ for (int i = 0; i < (sizeof(tests) / sizeof(struct test)); i++)
+ {
+ validate( tests[i].value, tests[i].expected, tests[i].variance);
+ validate(-tests[i].value, 1 - tests[i].expected, tests[i].variance);
+ }
+
+ validate_isnan(PAL_NAN);
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/ceil/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/ceil/test1/testinfo.dat
new file mode 100644
index 0000000000..84e80a9cb7
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/ceil/test1/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = ceil
+Name = Test #1 for ceil
+TYPE = DEFAULT
+EXE1 = test1
+Description
+=Tests ceil with simple positive and negative values. Also tests
+=extreme cases like extremely small values and positive and negative
+=infinity. Makes sure that calling ceil on NaN returns NaN
diff --git a/src/pal/tests/palsuite/c_runtime/cos/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/cos/CMakeLists.txt
new file mode 100644
index 0000000000..5e1ef7f28b
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/cos/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
diff --git a/src/pal/tests/palsuite/c_runtime/cos/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/cos/test1/CMakeLists.txt
new file mode 100644
index 0000000000..1dda9a2563
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/cos/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_cos_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_cos_test1 coreclrpal)
+
+target_link_libraries(paltest_cos_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/cos/test1/test1.c b/src/pal/tests/palsuite/c_runtime/cos/test1/test1.c
new file mode 100644
index 0000000000..8c1c7300e6
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/cos/test1/test1.c
@@ -0,0 +1,131 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Test to ensure that cos return the correct values
+**
+** Dependencies: PAL_Initialize
+** PAL_Terminate
+** Fail
+** fabs
+**
+**===========================================================================*/
+
+#include <palsuite.h>
+
+// binary64 (double) has a machine epsilon of 2^-52 (approx. 2.22e-16). However, this
+// is slightly too accurate when writing tests meant to run against libm implementations
+// for various platforms. 2^-50 (approx. 8.88e-16) seems to be as accurate as we can get.
+//
+// The tests themselves will take PAL_EPSILON and adjust it according to the expected result
+// so that the delta used for comparison will compare the most significant digits and ignore
+// any digits that are outside the double precision range (15-17 digits).
+
+// For example, a test with an expect result in the format of 0.xxxxxxxxxxxxxxxxx will use
+// PAL_EPSILON for the variance, while an expected result in the format of 0.0xxxxxxxxxxxxxxxxx
+// will use PAL_EPSILON / 10 and and expected result in the format of x.xxxxxxxxxxxxxxxx will
+// use PAL_EPSILON * 10.
+#define PAL_EPSILON 8.8817841970012523e-16
+
+#define PAL_NAN sqrt(-1.0)
+#define PAL_POSINF -log(0.0)
+#define PAL_NEGINF log(0.0)
+
+/**
+ * Helper test structure
+ */
+struct test
+{
+ double value; /* value to test the function with */
+ double expected; /* expected result */
+ double variance; /* maximum delta between the expected and actual result */
+};
+
+/**
+ * validate
+ *
+ * test validation function
+ */
+void __cdecl validate(double value, double expected, double variance)
+{
+ double result = cos(value);
+
+ /*
+ * The test is valid when the difference between result
+ * and expected is less than or equal to variance
+ */
+ double delta = fabs(result - expected);
+
+ if (delta > variance)
+ {
+ Fail("cos(%g) returned %20.17g when it should have returned %20.17g",
+ value, result, expected);
+ }
+}
+
+/**
+ * validate
+ *
+ * test validation function for values returning NaN
+ */
+void __cdecl validate_isnan(double value)
+{
+ double result = cos(value);
+
+ if (!_isnan(result))
+ {
+ Fail("cos(%g) returned %20.17g when it should have returned %20.17g",
+ value, result, PAL_NAN);
+ }
+}
+
+/**
+ * main
+ *
+ * executable entry point
+ */
+int __cdecl main(int argc, char **argv)
+{
+ struct test tests[] =
+ {
+ /* value expected variance */
+ { 0, 1, PAL_EPSILON * 10 },
+ { 0.31830988618379067, 0.94976571538163866, PAL_EPSILON }, // value: 1 / pi
+ { 0.43429448190325183, 0.90716712923909839, PAL_EPSILON }, // value: log10(e)
+ { 0.63661977236758134, 0.80410982822879171, PAL_EPSILON }, // value: 2 / pi
+ { 0.69314718055994531, 0.76923890136397213, PAL_EPSILON }, // value: ln(2)
+ { 0.70710678118654752, 0.76024459707563015, PAL_EPSILON }, // value: 1 / sqrt(2)
+ { 0.78539816339744831, 0.70710678118654752, PAL_EPSILON }, // value: pi / 4, expected: 1 / sqrt(2)
+ { 1, 0.54030230586813972, PAL_EPSILON },
+ { 1.1283791670955126, 0.42812514788535792, PAL_EPSILON }, // value: 2 / sqrt(pi)
+ { 1.4142135623730950, 0.15594369476537447, PAL_EPSILON }, // value: sqrt(2)
+ { 1.4426950408889634, 0.12775121753523991, PAL_EPSILON }, // value: log2(e)
+ { 1.5707963267948966, 0, PAL_EPSILON }, // value: pi / 2
+ { 2.3025850929940457, -0.66820151019031295, PAL_EPSILON }, // value: ln(10)
+ { 2.7182818284590452, -0.91173391478696510, PAL_EPSILON }, // value: e
+ { 3.1415926535897932, -1, PAL_EPSILON * 10 }, // value: pi
+ };
+
+ /* PAL initialization */
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+ for (int i = 0; i < (sizeof(tests) / sizeof(struct test)); i++)
+ {
+ validate( tests[i].value, tests[i].expected, tests[i].variance);
+ validate(-tests[i].value, tests[i].expected, tests[i].variance);
+ }
+
+ validate_isnan(PAL_NEGINF);
+ validate_isnan(PAL_NAN);
+ validate_isnan(PAL_POSINF);
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/cos/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/cos/test1/testinfo.dat
new file mode 100644
index 0000000000..9e57b7f8ab
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/cos/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = cos
+Name = Positive Test for cos
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Passes to cos() a series of angle value, checking that
+= each one return the correct value.
diff --git a/src/pal/tests/palsuite/c_runtime/cosh/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/cosh/CMakeLists.txt
new file mode 100644
index 0000000000..5e1ef7f28b
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/cosh/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
diff --git a/src/pal/tests/palsuite/c_runtime/cosh/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/cosh/test1/CMakeLists.txt
new file mode 100644
index 0000000000..bea7b7a3b7
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/cosh/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_cosh_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_cosh_test1 coreclrpal)
+
+target_link_libraries(paltest_cosh_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/cosh/test1/test1.c b/src/pal/tests/palsuite/c_runtime/cosh/test1/test1.c
new file mode 100644
index 0000000000..40c2fca85d
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/cosh/test1/test1.c
@@ -0,0 +1,130 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Test to ensure that cosh return the correct values
+**
+** Dependencies: PAL_Initialize
+** PAL_Terminate
+** Fail
+** fabs
+**
+**===========================================================================*/
+
+#include <palsuite.h>
+
+// binary64 (double) has a machine epsilon of 2^-52 (approx. 2.22e-16). However, this
+// is slightly too accurate when writing tests meant to run against libm implementations
+// for various platforms. 2^-50 (approx. 8.88e-16) seems to be as accurate as we can get.
+//
+// The tests themselves will take PAL_EPSILON and adjust it according to the expected result
+// so that the delta used for comparison will compare the most significant digits and ignore
+// any digits that are outside the double precision range (15-17 digits).
+
+// For example, a test with an expect result in the format of 0.xxxxxxxxxxxxxxxxx will use
+// PAL_EPSILON for the variance, while an expected result in the format of 0.0xxxxxxxxxxxxxxxxx
+// will use PAL_EPSILON / 10 and and expected result in the format of x.xxxxxxxxxxxxxxxx will
+// use PAL_EPSILON * 10.
+#define PAL_EPSILON 8.8817841970012523e-16
+
+#define PAL_NAN sqrt(-1.0)
+#define PAL_POSINF -log(0.0)
+#define PAL_NEGINF log(0.0)
+
+/**
+ * Helper test structure
+ */
+struct test
+{
+ double value; /* value to test the function with */
+ double expected; /* expected result */
+ double variance; /* maximum delta between the expected and actual result */
+};
+
+/**
+ * validate
+ *
+ * test validation function
+ */
+void __cdecl validate(double value, double expected, double variance)
+{
+ double result = cosh(value);
+
+ /*
+ * The test is valid when the difference between result
+ * and expected is less than or equal to variance
+ */
+ double delta = fabs(result - expected);
+
+ if (delta > variance)
+ {
+ Fail("cosh(%g) returned %20.17g when it should have returned %20.17g",
+ value, result, expected);
+ }
+}
+
+/**
+ * validate
+ *
+ * test validation function for values returning PAL_NAN
+ */
+void __cdecl validate_isnan(double value)
+{
+ double result = cosh(value);
+
+ if (!_isnan(result))
+ {
+ Fail("cosh(%g) returned %20.17g when it should have returned %20.17g",
+ value, result, PAL_NAN);
+ }
+}
+
+/**
+ * main
+ *
+ * executable entry point
+ */
+int __cdecl main(int argc, char **argv)
+{
+ struct test tests[] =
+ {
+ /* value expected variance */
+ { 0, 1, PAL_EPSILON * 10 },
+ { 0.31830988618379067, 1.0510897883672876, PAL_EPSILON * 10 }, // value: 1 / pi
+ { 0.43429448190325183, 1.0957974645564909, PAL_EPSILON * 10 }, // value: log10(e)
+ { 0.63661977236758134, 1.2095794864199787, PAL_EPSILON * 10 }, // value: 2 / pi
+ { 0.69314718055994531, 1.25, PAL_EPSILON * 10 }, // value: ln(2)
+ { 0.70710678118654752, 1.2605918365213561, PAL_EPSILON * 10 }, // value: 1 / sqrt(2)
+ { 0.78539816339744831, 1.3246090892520058, PAL_EPSILON * 10 }, // value: pi / 4
+ { 1, 1.5430806348152438, PAL_EPSILON * 10 },
+ { 1.1283791670955126, 1.7071001431069344, PAL_EPSILON * 10 }, // value: 2 / sqrt(pi)
+ { 1.4142135623730950, 2.1781835566085709, PAL_EPSILON * 10 }, // value: sqrt(2)
+ { 1.4426950408889634, 2.2341880974508023, PAL_EPSILON * 10 }, // value: log2(e)
+ { 1.5707963267948966, 2.5091784786580568, PAL_EPSILON * 10 }, // value: pi / 2
+ { 2.3025850929940457, 5.05, PAL_EPSILON * 10 }, // value: ln(10)
+ { 2.7182818284590452, 7.6101251386622884, PAL_EPSILON * 10 }, // value: e
+ { 3.1415926535897932, 11.591953275521521, PAL_EPSILON * 100 }, // value: pi
+ { PAL_POSINF, PAL_POSINF, 0 },
+ };
+
+ /* PAL initialization */
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+ for (int i = 0; i < (sizeof(tests) / sizeof(struct test)); i++)
+ {
+ validate( tests[i].value, tests[i].expected, tests[i].variance);
+ validate(-tests[i].value, tests[i].expected, tests[i].variance);
+ }
+
+ validate_isnan(PAL_NAN);
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/cosh/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/cosh/test1/testinfo.dat
new file mode 100644
index 0000000000..131512289f
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/cosh/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = cosh
+Name = Positive Test for cosh
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Passes to cosh() a series of angle value, checking that
+= each one return to correct value.
diff --git a/src/pal/tests/palsuite/c_runtime/ctime/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/ctime/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/ctime/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/ctime/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/ctime/test1/CMakeLists.txt
new file mode 100644
index 0000000000..aa64a71d1e
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/ctime/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_ctime_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_ctime_test1 coreclrpal)
+
+target_link_libraries(paltest_ctime_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/ctime/test1/test1.c b/src/pal/tests/palsuite/c_runtime/ctime/test1/test1.c
new file mode 100644
index 0000000000..5d5e22ce89
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/ctime/test1/test1.c
@@ -0,0 +1,154 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Test to ensure that ctime return a valid
+** string when it received a valid number of second.
+** Test to ensure that ctime return null when it
+** receives a invalid number of second.
+**
+** Dependencies: PAL_Initialize
+** PAL_Terminate
+** Fail
+** IsBadReadPtr
+** strcmp
+**
+
+**
+**===========================================================================*/
+
+#include <palsuite.h>
+
+/*
+ * Date strings generated under win2000/WinXP, times & Strings are GMT
+ */
+const time_t VAL_SUN_JAN_17_2038 = 2147383647;
+const char *STR_SUN_JAN_17_2038 = "Sun Jan 17 23:27:27 2038\n";
+
+/* Note, there are two acceptable strings for this date. */
+/* The day can have a leading 0 under Windows. */
+const time_t VAL_FRI_JAN_02_1970 = 100000;
+const char *STR_FRI_JAN_02_1970 = "Fri Jan 02 03:46:40 1970\n";
+const char *STR_FRI_JAN__2_1970 = "Fri Jan 2 03:46:40 1970\n";
+
+const int STR_TIME_SIZE = 26; /* returned date size in byte*/
+
+
+
+int __cdecl main(int argc, char **argv)
+{
+ time_t LTime;
+ char *DateResult;
+ TIME_ZONE_INFORMATION tzInformation;
+
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ // Get the current timezone information
+ GetTimeZoneInformation(&tzInformation);
+
+ /*
+ * Test #1
+ */
+
+ /* set the valid date in time_t format, adjusted for current time zone*/
+ LTime = VAL_SUN_JAN_17_2038 + (tzInformation.Bias * 60);
+
+ /* convert it to string using ctime*/
+ DateResult = ctime( &LTime );
+
+ /* if it's null, ctime failed*/
+ if (DateResult == NULL)
+ {
+ Fail ("ERROR: (Test #1) ctime returned NULL. Expected string\n");
+ }
+
+ /* test if the entire string can ba access normaly */
+ if(IsBadReadPtr(DateResult, STR_TIME_SIZE)==0)
+ {
+ /* compare result with win2000 result */
+ if(strcmp( DateResult, STR_SUN_JAN_17_2038)!=0)
+ {
+ Fail("ERROR: (Test #1) ctime returned an unexpected string "
+ "%s, expexted string is %s\n"
+ ,DateResult, STR_SUN_JAN_17_2038);
+ }
+ }
+ else
+ {
+ Fail ("ERROR: (Test #1) ctime returned a bad pointer.\n");
+ }
+
+
+ /*
+ * Test #2
+ */
+
+ /* Set the valid date in time_t format, adjusted for current time zone */
+ LTime = VAL_FRI_JAN_02_1970 + (tzInformation.Bias * 60);
+
+ /* convert it to string using ctime */
+ DateResult = ctime( &LTime );
+
+ /* if it's null, ctime failed*/
+ if (DateResult == NULL)
+ {
+ Fail ("ERROR: (Test #2) ctime returned NULL. Expected string\n");
+ }
+
+ /* test if the entire string can ba access normaly */
+ if(IsBadReadPtr(DateResult, STR_TIME_SIZE)==0)
+ {
+ /* compare result with win2000 result */
+ if (strcmp(DateResult, STR_FRI_JAN_02_1970) != 0
+ && strcmp(DateResult, STR_FRI_JAN__2_1970) != 0)
+ {
+ Fail("ERROR: (Test #2) ctime returned an unexpected string "
+ "%s, expected string is %s\n"
+ ,DateResult, STR_FRI_JAN_02_1970);
+ }
+ }
+ else
+ {
+ Fail ("ERROR: (Test #2) ctime returned a bad pointer.\n");
+ }
+
+
+
+ /*
+ * Test #3
+ */
+
+ /* specify an invalid time */
+ LTime = -1;
+
+ /* try to convert it */
+ DateResult = ctime( &LTime );
+
+ /* Check the result for errors, should fail in this case */
+ if (DateResult != NULL)
+ {
+ Fail ("ERROR: (Test #3) ctime returned something different from NULL.:"
+ "Expected NULL\n");
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
+
+
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/ctime/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/ctime/test1/testinfo.dat
new file mode 100644
index 0000000000..c5aa3df65e
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/ctime/test1/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = ctime
+Name = Positive Test for ctime
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Call ctime with a valid number of second in it's t_time parameter
+= and expect a non-null char* as a return value.
+= Call ctime with a invalid number of second (-1) and expect
+= a null char* as a return value.
diff --git a/src/pal/tests/palsuite/c_runtime/errno/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/errno/CMakeLists.txt
new file mode 100644
index 0000000000..ef14ea5352
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/errno/CMakeLists.txt
@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+
diff --git a/src/pal/tests/palsuite/c_runtime/errno/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/errno/test1/CMakeLists.txt
new file mode 100644
index 0000000000..89b25a4fac
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/errno/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_errno_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_errno_test1 coreclrpal)
+
+target_link_libraries(paltest_errno_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/errno/test1/test1.c b/src/pal/tests/palsuite/c_runtime/errno/test1/test1.c
new file mode 100644
index 0000000000..3ae25fb02a
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/errno/test1/test1.c
@@ -0,0 +1,43 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Test that errno begins as 0, and sets to ERANGE when that
+** error is forced with wcstoul.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ WCHAR overstr[] = {'4','2','9','4','9','6','7','2','9','6',0};
+ WCHAR *end;
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ /*
+ From rotor.doc: The only value that must be supported is
+ ERANGE, in the event that wcstoul() fails due to overflow.
+ */
+
+ wcstoul(overstr, &end, 10);
+
+ if (errno != ERANGE)
+ {
+ Fail("ERROR: wcstoul did not set errno to ERANGE. Instead "
+ "the value of errno is %d\n", errno);
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/errno/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/errno/test1/testinfo.dat
new file mode 100644
index 0000000000..3291dbc60a
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/errno/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = errno
+Name = Positive Test for errno
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Test that errno begins as 0, and sets to ERANGE when that
+= error is forced with wcstoul.
diff --git a/src/pal/tests/palsuite/c_runtime/errno/test2/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/errno/test2/CMakeLists.txt
new file mode 100644
index 0000000000..edd4cf7975
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/errno/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test2.c
+)
+
+add_executable(paltest_errno_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_errno_test2 coreclrpal)
+
+target_link_libraries(paltest_errno_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/errno/test2/test2.c b/src/pal/tests/palsuite/c_runtime/errno/test2/test2.c
new file mode 100644
index 0000000000..f418d2f199
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/errno/test2/test2.c
@@ -0,0 +1,76 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test2.c
+**
+** Purpose: Test that errno is 'per-thread' as noted in the documentation.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+
+/*
+ This thread function just checks that errno is initially 0 and then sets
+ it to a new value before returning.
+*/
+DWORD PALAPI ThreadFunc( LPVOID lpParam )
+{
+
+ if(errno != 0)
+ {
+ *((DWORD*)lpParam) = 1;
+ }
+
+ errno = 20;
+
+ return 0;
+}
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ DWORD dwThreadId, dwThrdParam = 0;
+ HANDLE hThread;
+
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ /* Set errno to a value within this thread */
+
+ errno = 50;
+
+ hThread = CreateThread(NULL, 0, ThreadFunc, &dwThrdParam, 0, &dwThreadId);
+
+ if (hThread == NULL)
+ {
+ Fail("ERROR: CreateThread failed to create a thread. "
+ "GetLastError() returned %d.\n",GetLastError());
+ }
+
+ WaitForSingleObject(hThread, INFINITE);
+
+ /* This checks the result of calling the thread */
+ if(dwThrdParam)
+ {
+ Fail("ERROR: errno was not set to 0 in the new thread. Each "
+ "thread should have its own value for errno.\n");
+ }
+
+ /* Check to make sure errno is still set to 50 */
+ if(errno != 50)
+ {
+ Fail("ERROR: errno should be 50 in the main thread, even though "
+ "it was set to 20 in another thread. Currently it is %d.\n",
+ errno);
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/errno/test2/testinfo.dat b/src/pal/tests/palsuite/c_runtime/errno/test2/testinfo.dat
new file mode 100644
index 0000000000..90c232866f
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/errno/test2/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = errno
+Name = Positive Test for errno
+TYPE = DEFAULT
+EXE1 = test2
+Description
+= Test that errno is 'per-thread' as noted in the documentation.
diff --git a/src/pal/tests/palsuite/c_runtime/exit/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/exit/CMakeLists.txt
new file mode 100644
index 0000000000..ef14ea5352
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/exit/CMakeLists.txt
@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+
diff --git a/src/pal/tests/palsuite/c_runtime/exit/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/exit/test1/CMakeLists.txt
new file mode 100644
index 0000000000..eb9ca4e780
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/exit/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_exit_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_exit_test1 coreclrpal)
+
+target_link_libraries(paltest_exit_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/exit/test1/test1.c b/src/pal/tests/palsuite/c_runtime/exit/test1/test1.c
new file mode 100644
index 0000000000..87c9d22b8a
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/exit/test1/test1.c
@@ -0,0 +1,37 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Calls exit, and verifies that it actually stops program execution.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char **argv)
+{
+ /*
+ * Initialize the PAL and return FAIL if this fails
+ */
+ if (0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /*should return 0*/
+ exit(0);
+
+ Fail ("Exit didn't actually stop execution.\n");
+
+ return FAIL;
+}
+
+
+
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/exit/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/exit/test1/testinfo.dat
new file mode 100644
index 0000000000..3d9583bf96
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/exit/test1/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = exit
+Name = Positive Test for exit
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Calls exit, and verifies that it actually stops program execution.
diff --git a/src/pal/tests/palsuite/c_runtime/exit/test2/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/exit/test2/CMakeLists.txt
new file mode 100644
index 0000000000..47d3a44c85
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/exit/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test2.c
+)
+
+add_executable(paltest_exit_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_exit_test2 coreclrpal)
+
+target_link_libraries(paltest_exit_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/exit/test2/test2.c b/src/pal/tests/palsuite/c_runtime/exit/test2/test2.c
new file mode 100644
index 0000000000..16fbdfed2f
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/exit/test2/test2.c
@@ -0,0 +1,38 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test2.c
+**
+** Purpose: Calls exit on fail, and verifies that it actually
+** stops program execution and return 1.
+
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char **argv)
+{
+ /*
+ * Initialize the PAL and return FAIL if this fails
+ */
+ if (0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /*should return 1*/
+ exit(1);
+
+}
+
+
+
+
+
+
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/exit/test2/testinfo.dat b/src/pal/tests/palsuite/c_runtime/exit/test2/testinfo.dat
new file mode 100644
index 0000000000..6887f27c36
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/exit/test2/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = exit
+Name = Positive Test for exit
+TYPE = DEFAULT
+EXE1 = test2
+Description
+= Calls exit on fail, and verifies that it actually stops program execution,
+= and return 1.
diff --git a/src/pal/tests/palsuite/c_runtime/exp/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/exp/CMakeLists.txt
new file mode 100644
index 0000000000..5e1ef7f28b
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/exp/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
diff --git a/src/pal/tests/palsuite/c_runtime/exp/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/exp/test1/CMakeLists.txt
new file mode 100644
index 0000000000..9cdd4ec5ed
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/exp/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_exp_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_exp_test1 coreclrpal)
+
+target_link_libraries(paltest_exp_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/exp/test1/test1.c b/src/pal/tests/palsuite/c_runtime/exp/test1/test1.c
new file mode 100644
index 0000000000..20e071aa68
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/exp/test1/test1.c
@@ -0,0 +1,138 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test1.c
+**
+** Purpose: Tests exp with a normal set of values.
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+// binary64 (double) has a machine epsilon of 2^-52 (approx. 2.22e-16). However, this
+// is slightly too accurate when writing tests meant to run against libm implementations
+// for various platforms. 2^-50 (approx. 8.88e-16) seems to be as accurate as we can get.
+//
+// The tests themselves will take PAL_EPSILON and adjust it according to the expected result
+// so that the delta used for comparison will compare the most significant digits and ignore
+// any digits that are outside the double precision range (15-17 digits).
+
+// For example, a test with an expect result in the format of 0.xxxxxxxxxxxxxxxxx will use
+// PAL_EPSILON for the variance, while an expected result in the format of 0.0xxxxxxxxxxxxxxxxx
+// will use PAL_EPSILON / 10 and and expected result in the format of x.xxxxxxxxxxxxxxxx will
+// use PAL_EPSILON * 10.
+#define PAL_EPSILON 8.8817841970012523e-16
+
+#define PAL_NAN sqrt(-1.0)
+#define PAL_POSINF -log(0.0)
+#define PAL_NEGINF log(0.0)
+
+/**
+ * Helper test structure
+ */
+struct test
+{
+ double value; /* value to test the function with */
+ double expected; /* expected result */
+ double variance; /* maximum delta between the expected and actual result */
+};
+
+/**
+ * validate
+ *
+ * test validation function
+ */
+void __cdecl validate(double value, double expected, double variance)
+{
+ double result = exp(value);
+
+ /*
+ * The test is valid when the difference between result
+ * and expected is less than or equal to variance
+ */
+ double delta = fabs(result - expected);
+
+ if (delta > variance)
+ {
+ Fail("exp(%g) returned %20.17g when it should have returned %20.17g",
+ value, result, expected);
+ }
+}
+
+/**
+ * validate
+ *
+ * test validation function for values returning NaN
+ */
+void __cdecl validate_isnan(double value)
+{
+ double result = exp(value);
+
+ if (!_isnan(result))
+ {
+ Fail("exp(%g) returned %20.17g when it should have returned %20.17g",
+ value, result, PAL_NAN);
+ }
+}
+
+/**
+ * main
+ *
+ * executable entry point
+ */
+int __cdecl main(int argc, char **argv)
+{
+ struct test tests[] =
+ {
+ /* value expected variance */
+ { PAL_NEGINF, 0, PAL_EPSILON },
+ { -3.1415926535897932, 0.043213918263772250, PAL_EPSILON / 10 }, // value: -(pi)
+ { -2.7182818284590452, 0.065988035845312537, PAL_EPSILON / 10 }, // value: -(e)
+ { -2.3025850929940457, 0.1, PAL_EPSILON }, // value: -(ln(10))
+ { -1.5707963267948966, 0.20787957635076191, PAL_EPSILON }, // value: -(pi / 2)
+ { -1.4426950408889634, 0.23629008834452270, PAL_EPSILON }, // value: -(log2(e))
+ { -1.4142135623730950, 0.24311673443421421, PAL_EPSILON }, // value: -(sqrt(2))
+ { -1.1283791670955126, 0.32355726390307110, PAL_EPSILON }, // value: -(2 / sqrt(pi))
+ { -1, 0.36787944117144232, PAL_EPSILON }, // value: -(1)
+ { -0.78539816339744831, 0.45593812776599624, PAL_EPSILON }, // value: -(pi / 4)
+ { -0.70710678118654752, 0.49306869139523979, PAL_EPSILON }, // value: -(1 / sqrt(2))
+ { -0.69314718055994531, 0.5, PAL_EPSILON }, // value: -(ln(2))
+ { -0.63661977236758134, 0.52907780826773535, PAL_EPSILON }, // value: -(2 / pi)
+ { -0.43429448190325183, 0.64772148514180065, PAL_EPSILON }, // value: -(log10(e))
+ { -0.31830988618379067, 0.72737734929521647, PAL_EPSILON }, // value: -(1 / pi)
+ { 0, 1, PAL_EPSILON * 10 },
+ { 0.31830988618379067, 1.3748022274393586, PAL_EPSILON * 10 }, // value: 1 / pi
+ { 0.43429448190325183, 1.5438734439711811, PAL_EPSILON * 10 }, // value: log10(e)
+ { 0.63661977236758134, 1.8900811645722220, PAL_EPSILON * 10 }, // value: 2 / pi
+ { 0.69314718055994531, 2, PAL_EPSILON * 10 }, // value: ln(2)
+ { 0.70710678118654752, 2.0281149816474725, PAL_EPSILON * 10 }, // value: 1 / sqrt(2)
+ { 0.78539816339744831, 2.1932800507380155, PAL_EPSILON * 10 }, // value: pi / 4
+ { 1, 2.7182818284590452, PAL_EPSILON * 10 }, // expected: e
+ { 1.1283791670955126, 3.0906430223107976, PAL_EPSILON * 10 }, // value: 2 / sqrt(pi)
+ { 1.4142135623730950, 4.1132503787829275, PAL_EPSILON * 10 }, // value: sqrt(2)
+ { 1.4426950408889634, 4.2320861065570819, PAL_EPSILON * 10 }, // value: log2(e)
+ { 1.5707963267948966, 4.8104773809653517, PAL_EPSILON * 10 }, // value: pi / 2
+ { 2.3025850929940457, 10, PAL_EPSILON * 100 }, // value: ln(10)
+ { 2.7182818284590452, 15.154262241479264, PAL_EPSILON * 100 }, // value: e
+ { 3.1415926535897932, 23.140692632779269, PAL_EPSILON * 100 }, // value: pi
+ { PAL_POSINF, PAL_POSINF, 0 },
+ };
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+ for (int i = 0; i < (sizeof(tests) / sizeof(struct test)); i++)
+ {
+ validate(tests[i].value, tests[i].expected, tests[i].variance);
+ }
+
+ validate_isnan(PAL_NAN);
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/exp/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/exp/test1/testinfo.dat
new file mode 100644
index 0000000000..65fc192cd9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/exp/test1/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = exp
+Name = Test #1 for exp
+Type = DEFAULT
+EXE1 = test1
+Description
+=Tests exp with a normal set of values.
diff --git a/src/pal/tests/palsuite/c_runtime/fabs/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/fabs/CMakeLists.txt
new file mode 100644
index 0000000000..5e1ef7f28b
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fabs/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
diff --git a/src/pal/tests/palsuite/c_runtime/fabs/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/fabs/test1/CMakeLists.txt
new file mode 100644
index 0000000000..ab27230ac2
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fabs/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_fabs_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_fabs_test1 coreclrpal)
+
+target_link_libraries(paltest_fabs_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/fabs/test1/test1.c b/src/pal/tests/palsuite/c_runtime/fabs/test1/test1.c
new file mode 100644
index 0000000000..0a74d5c1c5
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fabs/test1/test1.c
@@ -0,0 +1,130 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Test to ensure that fabs return the correct values
+**
+** Dependencies: PAL_Initialize
+** PAL_Terminate
+** Fail
+**
+**===========================================================================*/
+
+#include <palsuite.h>
+
+// binary64 (double) has a machine epsilon of 2^-52 (approx. 2.22e-16). However, this
+// is slightly too accurate when writing tests meant to run against libm implementations
+// for various platforms. 2^-50 (approx. 8.88e-16) seems to be as accurate as we can get.
+//
+// The tests themselves will take PAL_EPSILON and adjust it according to the expected result
+// so that the delta used for comparison will compare the most significant digits and ignore
+// any digits that are outside the double precision range (15-17 digits).
+
+// For example, a test with an expect result in the format of 0.xxxxxxxxxxxxxxxxx will use
+// PAL_EPSILON for the variance, while an expected result in the format of 0.0xxxxxxxxxxxxxxxxx
+// will use PAL_EPSILON / 10 and and expected result in the format of x.xxxxxxxxxxxxxxxx will
+// use PAL_EPSILON * 10.
+#define PAL_EPSILON 8.8817841970012523e-16
+
+#define PAL_NAN sqrt(-1.0)
+#define PAL_POSINF -log(0.0)
+#define PAL_NEGINF log(0.0)
+
+/**
+ * Helper test structure
+ */
+struct test
+{
+ double value; /* value to test the function with */
+ double expected; /* expected result */
+ double variance; /* maximum delta between the expected and actual result */
+};
+
+/**
+ * validate
+ *
+ * test validation function
+ */
+void __cdecl validate(double value, double expected, double variance)
+{
+ double result = fabs(value);
+
+ /*
+ * The test is valid when the difference between result
+ * and expected is less than or equal to variance
+ */
+ double delta = fabs(result - expected);
+
+ if (delta > variance)
+ {
+ Fail("fabs(%g) returned %20.17g when it should have returned %20.17g",
+ value, result, expected);
+ }
+}
+
+/**
+ * validate
+ *
+ * test validation function for values returning NaN
+ */
+void __cdecl validate_isnan(double value)
+{
+ double result = fabs(value);
+
+ if (!_isnan(result))
+ {
+ Fail("fabs(%g) returned %20.17g when it should have returned %20.17g",
+ value, result, PAL_NAN);
+ }
+}
+
+/**
+ * main
+ *
+ * executable entry point
+ */
+INT __cdecl main(INT argc, CHAR **argv)
+{
+ struct test tests[] =
+ {
+ /* value expected variance */
+ { PAL_NEGINF, PAL_POSINF, 0 },
+ { -3.1415926535897932, 3.1415926535897932, PAL_EPSILON * 10 }, // value: -(pi) expected: pi
+ { -2.7182818284590452, 2.7182818284590452, PAL_EPSILON * 10 }, // value: -(e) expected: e
+ { -2.3025850929940457, 2.3025850929940457, PAL_EPSILON * 10 }, // value: -(ln(10)) expected: ln(10)
+ { -1.5707963267948966, 1.5707963267948966, PAL_EPSILON * 10 }, // value: -(pi / 2) expected: pi / 2
+ { -1.4426950408889634, 1.4426950408889634, PAL_EPSILON * 10 }, // value: -(log2(e)) expected: log2(e)
+ { -1.4142135623730950, 1.4142135623730950, PAL_EPSILON * 10 }, // value: -(sqrt(2)) expected: sqrt(2)
+ { -1.1283791670955126, 1.1283791670955126, PAL_EPSILON * 10 }, // value: -(2 / sqrt(pi)) expected: 2 / sqrt(pi)
+ { -1, 1, PAL_EPSILON * 10 },
+ { -0.78539816339744831, 0.78539816339744831, PAL_EPSILON }, // value: -(pi / 4) expected: pi / 4
+ { -0.70710678118654752, 0.70710678118654752, PAL_EPSILON }, // value: -(1 / sqrt(2)) expected: 1 / sqrt(2)
+ { -0.69314718055994531, 0.69314718055994531, PAL_EPSILON }, // value: -(ln(2)) expected: ln(2)
+ { -0.63661977236758134, 0.63661977236758134, PAL_EPSILON }, // value: -(2 / pi) expected: 2 / pi
+ { -0.43429448190325183, 0.43429448190325183, PAL_EPSILON }, // value: -(log10(e)) expected: log10(e)
+ { -0.31830988618379067, 0.31830988618379067, PAL_EPSILON }, // value: -(1 / pi) expected: 1 / pi
+ { -0.0, 0, PAL_EPSILON },
+ };
+
+
+ // PAL initialization
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+ for (int i = 0; i < (sizeof(tests) / sizeof(struct test)); i++)
+ {
+ validate( tests[i].value, tests[i].expected, tests[i].variance);
+ validate(-tests[i].value, tests[i].expected, tests[i].variance);
+ }
+
+ validate_isnan(PAL_NAN);
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/fabs/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/fabs/test1/testinfo.dat
new file mode 100644
index 0000000000..d5b2321edd
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fabs/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = fabs
+Name = Positive Test for fabs
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Passes to fabs() a series of values, checking that
+= each one return to correct value.
diff --git a/src/pal/tests/palsuite/c_runtime/fabsf/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/fabsf/CMakeLists.txt
new file mode 100644
index 0000000000..5e1ef7f28b
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fabsf/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
diff --git a/src/pal/tests/palsuite/c_runtime/fabsf/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/fabsf/test1/CMakeLists.txt
new file mode 100644
index 0000000000..06512ebd7c
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fabsf/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_fabsf_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_fabsf_test1 coreclrpal)
+
+target_link_libraries(paltest_fabsf_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/fabsf/test1/test1.c b/src/pal/tests/palsuite/c_runtime/fabsf/test1/test1.c
new file mode 100644
index 0000000000..0b020729b8
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fabsf/test1/test1.c
@@ -0,0 +1,130 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Test to ensure that fabsf return the correct values
+**
+** Dependencies: PAL_Initialize
+** PAL_Terminate
+** Fail
+**
+**===========================================================================*/
+
+#include <palsuite.h>
+
+// binary32 (float) has a machine epsilon of 2^-23 (approx. 1.19e-07). However, this
+// is slightly too accurate when writing tests meant to run against libm implementations
+// for various platforms. 2^-21 (approx. 4.76e-07) seems to be as accurate as we can get.
+//
+// The tests themselves will take PAL_EPSILON and adjust it according to the expected result
+// so that the delta used for comparison will compare the most significant digits and ignore
+// any digits that are outside the double precision range (6-9 digits).
+
+// For example, a test with an expect result in the format of 0.xxxxxxxxx will use PAL_EPSILON
+// for the variance, while an expected result in the format of 0.0xxxxxxxxx will use
+// PAL_EPSILON / 10 and and expected result in the format of x.xxxxxx will use PAL_EPSILON * 10.
+#define PAL_EPSILON 4.76837158e-07
+
+
+#define PAL_NAN sqrt(-1.0)
+#define PAL_POSINF -log(0.0)
+#define PAL_NEGINF log(0.0)
+
+/**
+ * Helper test structure
+ */
+struct test
+{
+ float value; /* value to test the function with */
+ float expected; /* expected result */
+ float variance; /* maximum delta between the expected and actual result */
+};
+
+/**
+ * validate
+ *
+ * test validation function
+ */
+void __cdecl validate(float value, float expected, float variance)
+{
+ float result = fabsf(value);
+
+ /*
+ * The test is valid when the difference between result
+ * and expected is less than or equal to variance
+ */
+ float delta = fabsf(result - expected);
+
+ if (delta > variance)
+ {
+ Fail("fabsf(%g) returned %10.9g when it should have returned %10.9g",
+ value, result, expected);
+ }
+}
+
+/**
+ * validate
+ *
+ * test validation function for values returning NaN
+ */
+void __cdecl validate_isnan(float value)
+{
+ float result = fabsf(value);
+
+ if (!_isnan(result))
+ {
+ Fail("fabsf(%g) returned %10.9g when it should have returned %10.9g",
+ value, result, PAL_NAN);
+ }
+}
+
+/**
+ * main
+ *
+ * executable entry point
+ */
+INT __cdecl main(INT argc, CHAR **argv)
+{
+ struct test tests[] =
+ {
+ /* value expected variance */
+ { PAL_NEGINF, PAL_POSINF, 0 },
+ { -3.14159265f, 3.14159265f, PAL_EPSILON * 10 }, // value: -(pi) expected: pi
+ { -2.71828183f, 2.71828183f, PAL_EPSILON * 10 }, // value: -(e) expected: e
+ { -2.30258509f, 2.30258509f, PAL_EPSILON * 10 }, // value: -(ln(10)) expected: ln(10)
+ { -1.57079633f, 1.57079633f, PAL_EPSILON * 10 }, // value: -(pi / 2) expected: pi / 2
+ { -1.44269504f, 1.44269504f, PAL_EPSILON * 10 }, // value: -(log2(e)) expected: log2(e)
+ { -1.41421356f, 1.41421356f, PAL_EPSILON * 10 }, // value: -(sqrt(2)) expected: sqrt(2)
+ { -1.12837917f, 1.12837917f, PAL_EPSILON * 10 }, // value: -(2 / sqrt(pi)) expected: 2 / sqrt(pi)
+ { -1, 1, PAL_EPSILON * 10 },
+ { -0.785398163f, 0.785398163f, PAL_EPSILON }, // value: -(pi / 4) expected: pi / 4
+ { -0.707106781f, 0.707106781f, PAL_EPSILON }, // value: -(1 / sqrt(2)) expected: 1 / sqrt(2)
+ { -0.693147181f, 0.693147181f, PAL_EPSILON }, // value: -(ln(2)) expected: ln(2)
+ { -0.636619772f, 0.636619772f, PAL_EPSILON }, // value: -(2 / pi) expected: 2 / pi
+ { -0.434294482f, 0.434294482f, PAL_EPSILON }, // value: -(log10(e)) expected: log10(e)
+ { -0.318309886f, 0.318309886f, PAL_EPSILON }, // value: -(1 / pi) expected: 1 / pi
+ { -0.0f, 0, PAL_EPSILON },
+ };
+
+
+ // PAL initialization
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+ for (int i = 0; i < (sizeof(tests) / sizeof(struct test)); i++)
+ {
+ validate( tests[i].value, tests[i].expected, tests[i].variance);
+ validate(-tests[i].value, tests[i].expected, tests[i].variance);
+ }
+
+ validate_isnan(PAL_NAN);
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/fabsf/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/fabsf/test1/testinfo.dat
new file mode 100644
index 0000000000..a927f1e3df
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fabsf/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = fabsf
+Name = Positive Test for fabsf
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Passes to fabsf() a series of values, checking that
+= each one return to correct value.
diff --git a/src/pal/tests/palsuite/c_runtime/fclose/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/fclose/CMakeLists.txt
new file mode 100644
index 0000000000..ef14ea5352
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fclose/CMakeLists.txt
@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+
diff --git a/src/pal/tests/palsuite/c_runtime/fclose/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/fclose/test1/CMakeLists.txt
new file mode 100644
index 0000000000..55ed7c674e
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fclose/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_fclose_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_fclose_test1 coreclrpal)
+
+target_link_libraries(paltest_fclose_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/fclose/test1/test1.c b/src/pal/tests/palsuite/c_runtime/fclose/test1/test1.c
new file mode 100644
index 0000000000..0a8463823d
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fclose/test1/test1.c
@@ -0,0 +1,79 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test1.c (fclose)
+**
+** Purpose: Tests the PAL implementation of the fclose function.
+** This test will use fdopen to create a file stream,
+** that will be used to test fclose. fclose will also
+** be passed a closed file handle to make sure it handle
+** it accordingly.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char **argv)
+{
+ HANDLE hReadPipe = NULL;
+ HANDLE hWritePipe = NULL;
+ BOOL bRetVal = FALSE;
+ int iFiledes = 0;
+ FILE *fp;
+
+ SECURITY_ATTRIBUTES lpPipeAttributes;
+
+ /*Initialize the PAL*/
+ if ((PAL_Initialize(argc, argv)) != 0)
+ {
+ return (FAIL);
+ }
+
+ /*Setup SECURITY_ATTRIBUTES structure for CreatePipe*/
+ lpPipeAttributes.nLength = sizeof(lpPipeAttributes);
+ lpPipeAttributes.lpSecurityDescriptor = NULL;
+ lpPipeAttributes.bInheritHandle = TRUE;
+
+ /*Create a Pipe*/
+ bRetVal = CreatePipe(&hReadPipe, // read handle
+ &hWritePipe, // write handle
+ &lpPipeAttributes,// security attributes
+ 0); // pipe size
+
+ if (bRetVal == FALSE)
+ {
+ Fail("ERROR: Unable to create pipe; returned error code %ld"
+ , GetLastError());
+ }
+
+ /*Get a file descriptor for the read pipe handle*/
+ iFiledes = _open_osfhandle((long)hReadPipe,_O_RDONLY);
+
+ if (iFiledes == -1)
+ {
+ Fail("ERROR: _open_osfhandle failed to open "
+ " hReadPipe=0x%lx", hReadPipe);
+ }
+
+ /*Open read pipe handle in read mode*/
+ fp = _fdopen(iFiledes, "r");
+
+ if (fp == NULL)
+ {
+ Fail("ERROR: unable to fdopen file descriptor"
+ " iFiledes=%d", iFiledes);
+ }
+
+ /*Attempt to close the file stream*/
+ if (fclose(fp) != 0)
+ {
+ Fail("ERROR: Unable to fclose file stream fp=0x%lx\n",fp);
+ }
+
+ PAL_Terminate();
+ return (PASS);
+}
diff --git a/src/pal/tests/palsuite/c_runtime/fclose/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/fclose/test1/testinfo.dat
new file mode 100644
index 0000000000..0904c4fa9d
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fclose/test1/testinfo.dat
@@ -0,0 +1,18 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = fclose
+Name = Test for fclose
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Tests the PAL implementation of the fclose function.
+= This test will use fdopen to create a file stream,
+= that will be used to test fclose. fclose will also
+= be passed a closed file handle to make sure it handle
+= it accordingly.
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/fclose/test2/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/fclose/test2/CMakeLists.txt
new file mode 100644
index 0000000000..178dc7d19a
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fclose/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test2.c
+)
+
+add_executable(paltest_fclose_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_fclose_test2 coreclrpal)
+
+target_link_libraries(paltest_fclose_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/fclose/test2/test2.c b/src/pal/tests/palsuite/c_runtime/fclose/test2/test2.c
new file mode 100644
index 0000000000..f4da535535
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fclose/test2/test2.c
@@ -0,0 +1,77 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test2.c (fclose)
+**
+** Purpose: Tests the PAL implementation of the fclose function.
+** fclose will be passed a closed file handle to make
+** sure it handles it accordingly.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char **argv)
+{
+ HANDLE hReadPipe = NULL;
+ HANDLE hWritePipe = NULL;
+ BOOL bRetVal = FALSE;
+ int iFiledes = 0;
+ FILE *fp;
+
+ SECURITY_ATTRIBUTES lpPipeAttributes;
+
+ /*Initialize the PAL*/
+ if ((PAL_Initialize(argc, argv)) != 0)
+ {
+ return (FAIL);
+ }
+
+ /*Setup SECURITY_ATTRIBUTES structure for CreatePipe*/
+ lpPipeAttributes.nLength = sizeof(lpPipeAttributes);
+ lpPipeAttributes.lpSecurityDescriptor = NULL;
+ lpPipeAttributes.bInheritHandle = TRUE;
+
+ /*Create a Pipe*/
+ bRetVal = CreatePipe(&hReadPipe, /* read handle */
+ &hWritePipe, /* write handle */
+ &lpPipeAttributes,/* security attributes */
+ 0); /* pipe size */
+
+ if (bRetVal == FALSE)
+ {
+ Fail("ERROR: Unable to create pipe; returned error code %ld"
+ , GetLastError());
+ }
+
+ /*Get a file descriptor for the read pipe handle*/
+ iFiledes = _open_osfhandle((long)hReadPipe,_O_RDONLY);
+
+ if (iFiledes == -1)
+ {
+ Fail("ERROR: _open_osfhandle failed to open "
+ " hReadPipe=0x%lx", hReadPipe);
+ }
+
+ /*Open read pipe handle in read mode*/
+ fp = _fdopen(iFiledes, "r");
+
+ if (fp == NULL)
+ {
+ Fail("ERROR: unable to fdopen file descriptor"
+ " iFiledes=%d", iFiledes);
+ }
+
+ /*Attempt to close the file stream*/
+ if (fclose(fp) != 0)
+ {
+ Fail("ERROR: Unable to fclose file stream fp=0x%lx\n", fp);
+ }
+
+ PAL_Terminate();
+ return (PASS);
+}
diff --git a/src/pal/tests/palsuite/c_runtime/fclose/test2/testinfo.dat b/src/pal/tests/palsuite/c_runtime/fclose/test2/testinfo.dat
new file mode 100644
index 0000000000..192b8d2f6b
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fclose/test2/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = fclose
+Name = Test for fclose
+TYPE = DEFAULT
+EXE1 = test2
+LANG = cpp
+Description
+= Tests the PAL implementation of the fclose function.
+= fclose will be passed a closed file handle to
+= make sure it handles it accordingly.
diff --git a/src/pal/tests/palsuite/c_runtime/feof/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/feof/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/feof/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/feof/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/feof/test1/CMakeLists.txt
new file mode 100644
index 0000000000..ee1389deb0
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/feof/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_feof_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_feof_test1 coreclrpal)
+
+target_link_libraries(paltest_feof_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/feof/test1/test1.c b/src/pal/tests/palsuite/c_runtime/feof/test1/test1.c
new file mode 100644
index 0000000000..ba018aa91d
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/feof/test1/test1.c
@@ -0,0 +1,88 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test1.c
+**
+** Purpose: Tests the PAL implementation of the feof function.
+** Open a file, and read some characters. Check that
+** feof states that it hasn't gone by the EOF. Then
+** read enough characters to go beyond the EOF, and check
+** that feof states this is so.
+**
+** Depends:
+** fopen
+** fread
+**
+**
+**
+**===================================================================*/
+
+/* The file 'testfile' should exist with 15 characters in it. If not,
+ something has been lost ...
+*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char **argv)
+{
+ const char filename[] = "testfile";
+ char buffer[128];
+ FILE * fp = NULL;
+ int result;
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ /* Open a file in READ mode */
+
+ if((fp = fopen(filename, "r")) == NULL)
+ {
+ Fail("Unable to open a file for reading. Is the file "
+ "in the directory? It should be.");
+ }
+
+ /* Read 10 characters from the file. The file has 15
+ characters in it.
+ */
+
+ if((result = fread(buffer,1,10,fp)) == 0)
+ {
+ Fail("ERROR: Zero characters read from the file. It should have "
+ "read 10 character in it.");
+ }
+
+ if(feof(fp))
+ {
+ Fail("ERROR: feof returned a value greater than 0. No read "
+ "operation has gone beyond the EOF yet, and feof should "
+ "return 0 still.");
+ }
+
+ /* Read 10 characters from the file. The file has 15
+ characters in it. The file pointer should have no passed
+ the end of file.
+ */
+
+ if((result = fread(buffer,1,10,fp)) == 0)
+ {
+ Fail("ERROR: Zero characters read from the file. It should have "
+ "read 5 character in it.");
+ }
+
+ if(feof(fp) == 0)
+ {
+ Fail("ERROR: feof returned 0. The file pointer has gone beyond "
+ "the EOF and this function should return positive now.");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/feof/test1/testfile b/src/pal/tests/palsuite/c_runtime/feof/test1/testfile
new file mode 100644
index 0000000000..273c1a9ffd
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/feof/test1/testfile
@@ -0,0 +1 @@
+This is a test. \ No newline at end of file
diff --git a/src/pal/tests/palsuite/c_runtime/feof/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/feof/test1/testinfo.dat
new file mode 100644
index 0000000000..e14044ee17
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/feof/test1/testinfo.dat
@@ -0,0 +1,16 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = feof
+Name = Positive Test for feof
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Tests the PAL implementation of the feof function.
+= Open a file, and read some characters. Check that feof states that
+= it hasn't gone by the EOF. Then read enough characters to go beyond
+= the EOF, and check that feof states this is so.
+
diff --git a/src/pal/tests/palsuite/c_runtime/ferror/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/ferror/CMakeLists.txt
new file mode 100644
index 0000000000..ef14ea5352
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/ferror/CMakeLists.txt
@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+
diff --git a/src/pal/tests/palsuite/c_runtime/ferror/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/ferror/test1/CMakeLists.txt
new file mode 100644
index 0000000000..2ab12b5db3
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/ferror/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_ferror_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_ferror_test1 coreclrpal)
+
+target_link_libraries(paltest_ferror_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/ferror/test1/test1.c b/src/pal/tests/palsuite/c_runtime/ferror/test1/test1.c
new file mode 100644
index 0000000000..516f2531ed
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/ferror/test1/test1.c
@@ -0,0 +1,74 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test1.c
+**
+** Purpose: Tests the PAL implementation of the ferror function.
+**
+** Depends:
+** fopen
+** fread
+** fclose
+**
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char **argv)
+{
+ const char filename[] = "testfile";
+ char buffer[128];
+ FILE * fp = NULL;
+ int result;
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ /* Open a file in READ mode */
+
+ if((fp = fopen(filename, "r")) == NULL)
+ {
+ Fail("Unable to open a file for reading. Is the file "
+ "in the directory? It should be.");
+ }
+
+ /* Read 10 characters from the file. The file has 15
+ characters in it.
+ */
+
+ if((result = fread(buffer,1,10,fp)) == 0)
+ {
+ Fail("ERROR: Zero characters read from the file. It should have "
+ "read 10 character in from a 15 character file.");
+ }
+
+ if(ferror(fp) != 0)
+ {
+ Fail("ERROR: ferror returned a value not equal to 0. The read "
+ "operation shouldn't have caused an error, and ferror should "
+ "return 0 still.");
+ }
+
+ /*
+ Close the open file and end the test.
+ */
+
+ if(fclose(fp) != 0)
+ {
+ Fail("ERROR: fclose failed when trying to close a file pointer. "
+ "This test depends on fclose working properly.");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/ferror/test1/testfile b/src/pal/tests/palsuite/c_runtime/ferror/test1/testfile
new file mode 100644
index 0000000000..273c1a9ffd
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/ferror/test1/testfile
@@ -0,0 +1 @@
+This is a test. \ No newline at end of file
diff --git a/src/pal/tests/palsuite/c_runtime/ferror/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/ferror/test1/testinfo.dat
new file mode 100644
index 0000000000..32e55a3b0d
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/ferror/test1/testinfo.dat
@@ -0,0 +1,16 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = ferror
+Name = Positive Test for ferror
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Tests the PAL implementation of the ferror function.
+= Open a file, and read some characters. Check that ferror states that
+= no error has occurred. Then close the file pointer. Attempt to read
+= some more. Check ferror now, and it should indicate that an error has
+= occurred.
diff --git a/src/pal/tests/palsuite/c_runtime/ferror/test2/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/ferror/test2/CMakeLists.txt
new file mode 100644
index 0000000000..077dde0bc6
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/ferror/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test2.c
+)
+
+add_executable(paltest_ferror_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_ferror_test2 coreclrpal)
+
+target_link_libraries(paltest_ferror_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/ferror/test2/test2.c b/src/pal/tests/palsuite/c_runtime/ferror/test2/test2.c
new file mode 100644
index 0000000000..fdf9e032c8
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/ferror/test2/test2.c
@@ -0,0 +1,69 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test2.c
+**
+** Purpose: Open a read-only file and attempt to write some data to it.
+** Check to ensure that an ferror occurs.
+**
+** Depends:
+** fopen
+** fwrite
+** fclose
+**
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char **argv)
+{
+ const char filename[] = "testfile";
+ FILE * fp = NULL;
+ int result;
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ /* Open a file in READONLY mode */
+
+ if((fp = fopen(filename, "r")) == NULL)
+ {
+ Fail("Unable to open a file for reading.");
+ }
+
+ /* Attempt to write 14 characters to the file. */
+
+ if((result = fwrite("This is a test",1,14,fp)) != 0)
+ {
+ Fail("ERROR: %d characters written. 0 characters should "
+ "have been written, since this file is read-only.", result);
+ }
+
+ if(ferror(fp) == 0)
+ {
+ Fail("ERROR: ferror should have generated an error when "
+ "write was called on a read-only file. But, it "
+ "retured 0, indicating no error.\n");
+ }
+
+ /* Close the file. */
+
+ if(fclose(fp) != 0)
+ {
+ Fail("ERROR: fclose failed when trying to close a file pointer. "
+ "This test depends on fclose working properly.");
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/ferror/test2/testfile b/src/pal/tests/palsuite/c_runtime/ferror/test2/testfile
new file mode 100644
index 0000000000..0135842a03
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/ferror/test2/testfile
@@ -0,0 +1 @@
+This is a test file. This needs to be kept in CVS. \ No newline at end of file
diff --git a/src/pal/tests/palsuite/c_runtime/ferror/test2/testinfo.dat b/src/pal/tests/palsuite/c_runtime/ferror/test2/testinfo.dat
new file mode 100644
index 0000000000..d724a4c4e7
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/ferror/test2/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = ferror
+Name = Positive Test for ferror, call write on a readonly file.
+TYPE = DEFAULT
+EXE1 = test2
+Description
+= Open a read-only file and attempt to write some data to it.
+= Check to ensure that an ferror occurs.
diff --git a/src/pal/tests/palsuite/c_runtime/fflush/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/fflush/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fflush/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/fflush/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/fflush/test1/CMakeLists.txt
new file mode 100644
index 0000000000..743f1d2111
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fflush/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_fflush_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_fflush_test1 coreclrpal)
+
+target_link_libraries(paltest_fflush_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/fflush/test1/test1.c b/src/pal/tests/palsuite/c_runtime/fflush/test1/test1.c
new file mode 100644
index 0000000000..7baf9ba5b9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fflush/test1/test1.c
@@ -0,0 +1,80 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Tests to see that fflush is working properly. Flushes a couple
+** buffers and checks the return value. Can't figure out a way to test
+** and ensure it is really dropping the buffers, since the system
+** does this automatically most of the time ...
+**
+**
+**==========================================================================*/
+
+/* This function is really tough to test. Right now it just tests
+ a bunch of return values. No solid way to ensure that it is really
+ flushing a buffer or not -- might have to be a manual test someday.
+*/
+
+#include <palsuite.h>
+
+
+int __cdecl main(int argc, char **argv)
+{
+
+ int TheReturn;
+ FILE* TheFile;
+ FILE* AnotherFile = NULL;
+
+ PAL_Initialize(argc,argv);
+
+ TheFile = fopen("theFile","w+");
+
+ if(TheFile == NULL)
+ {
+ Fail("ERROR: fopen failed. Test depends on this function.");
+ }
+
+ TheReturn = fwrite("foo",3,3,TheFile);
+
+ if(TheReturn != 3)
+ {
+ Fail("ERROR: fwrite failed. Test depends on this function.");
+ }
+
+ /* Test to see that FlushFileBuffers returns a success value */
+ TheReturn = fflush(TheFile);
+
+ if(TheReturn != 0)
+ {
+ Fail("ERROR: The fflush function returned non-zero, which "
+ "indicates failure, when trying to flush a buffer.");
+ }
+
+ /* Test to see that FlushFileBuffers returns a success value */
+ TheReturn = fflush(NULL);
+
+ if(TheReturn != 0)
+ {
+ Fail("ERROR: The fflush function returned non-zero, which "
+ "indicates failure, when trying to flush all buffers.");
+ }
+
+ /* Test to see that FlushFileBuffers returns a success value */
+ TheReturn = fflush(AnotherFile);
+
+ if(TheReturn != 0)
+ {
+ Fail("ERROR: The fflush function returned non-zero, which "
+ "indicates failure, when trying to flush a stream not "
+ "associated with a file.");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/fflush/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/fflush/test1/testinfo.dat
new file mode 100644
index 0000000000..1cff5a94a1
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fflush/test1/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = fflush
+Name = Positive Test for fflush
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Tests to see that fflush is working properly. Flushes a couple
+= buffers and checks the return value. Can't figure out a way to test
+= and ensure it is really dropping the buffers, since the system
+= does this automatically most of the time ...
diff --git a/src/pal/tests/palsuite/c_runtime/fgets/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/fgets/CMakeLists.txt
new file mode 100644
index 0000000000..1962ade358
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fgets/CMakeLists.txt
@@ -0,0 +1,6 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+add_subdirectory(test3)
+
diff --git a/src/pal/tests/palsuite/c_runtime/fgets/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/fgets/test1/CMakeLists.txt
new file mode 100644
index 0000000000..672d910c85
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fgets/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_fgets_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_fgets_test1 coreclrpal)
+
+target_link_libraries(paltest_fgets_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/fgets/test1/test1.c b/src/pal/tests/palsuite/c_runtime/fgets/test1/test1.c
new file mode 100644
index 0000000000..5e0e62dece
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fgets/test1/test1.c
@@ -0,0 +1,102 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Writes a simple file and calls fgets() to get a string shorter
+** than the first line of the file. Verifies that the correct
+** string is returned.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char **argv)
+{
+ const char outBuf1[] = "This is a test.\n";
+ const char outBuf2[] = "This is too.";
+ char inBuf[sizeof(outBuf1) + sizeof(outBuf2)];
+ const char filename[] = "testfile.tmp";
+ const int offset = 5; /* value chosen arbitrarily */
+ int actualLen;
+ int expectedLen;
+ FILE * fp;
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ /*write the file that we will use to test */
+ fp = fopen(filename, "w");
+ if (fp == NULL)
+ {
+ Fail("Unable to open file for write.\n");
+ }
+
+ fwrite(outBuf1, sizeof(outBuf1[0]), sizeof(outBuf1), fp);
+ fwrite(outBuf2, sizeof(outBuf2[0]), sizeof(outBuf2), fp);
+
+ if (fclose(fp) != 0)
+ {
+ Fail("Error closing a file opened for write.\n");
+ }
+
+
+ /*now read back the entire first string*/
+ fp = fopen(filename, "r");
+ if (fp == NULL)
+ {
+ Fail("Unable to open file for read.\n");
+ }
+
+ /*note: +1 because strlen() returns the length of a string _not_
+ including the NULL, while fgets() returns a string of specified
+ maximum length _including_ the NULL.*/
+ if (fgets(inBuf, strlen(outBuf1) - offset + 1, fp) != inBuf)
+ {
+ Fail("Error reading from file using fgets.\n");
+ }
+
+
+ expectedLen = strlen(outBuf1) - offset;
+ actualLen = strlen(inBuf);
+
+ if (actualLen < expectedLen)
+ {
+ Fail("fgets() was asked to read a one-line string and given the "
+ "length of the string as a parameter. The string it has "
+ "read is too short.\n");
+ }
+ if (actualLen > expectedLen)
+ {
+ Fail("fgets() was asked to read a one-line string and given the "
+ "length of the string as a parameter. The string it has "
+ "read is too long.\n");
+ }
+ if (memcmp(inBuf, outBuf1, actualLen) != 0)
+ {
+ /*We didn't read back exactly outBuf1*/
+ Fail("fgets() was asked to read a one-line string, and given the "
+ "length of the string as an parameter. It has returned a "
+ "string of the correct length, but the contents are not "
+ "correct.\n");
+ }
+
+ if (fclose(fp) != 0)
+ {
+ Fail("Error closing file after using fgets().\n");
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+
+}
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/fgets/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/fgets/test1/testinfo.dat
new file mode 100644
index 0000000000..70ea6690ca
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fgets/test1/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = fgets
+Name = Positive Test for fgets
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Writes a simple file and calls fgets() to get a string shorter than
+= the first line of the file. Verifies that the correct string is
+= returned.
+
diff --git a/src/pal/tests/palsuite/c_runtime/fgets/test2/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/fgets/test2/CMakeLists.txt
new file mode 100644
index 0000000000..d39401536b
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fgets/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test2.c
+)
+
+add_executable(paltest_fgets_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_fgets_test2 coreclrpal)
+
+target_link_libraries(paltest_fgets_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/fgets/test2/test2.c b/src/pal/tests/palsuite/c_runtime/fgets/test2/test2.c
new file mode 100644
index 0000000000..fa37cdbc13
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fgets/test2/test2.c
@@ -0,0 +1,97 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test2.c
+**
+** Purpose: Calls fgets to read a full line from a file. A maximum length
+** parameter greater than the length of the line is passed.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char **argv)
+{
+ const char outBuf1[] = "This is a test.\n";
+ const char outBuf2[] = "This is too.";
+
+ char inBuf[sizeof(outBuf1) + sizeof(outBuf2)];
+ const char filename[] = "testfile.tmp";
+ const int offset = 5; /*value chosen arbitrarily*/
+ int expectedLen;
+ int actualLen;
+
+ FILE * fp;
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ /*write the file that we will use to test */
+ fp = fopen(filename, "w");
+ if (fp == NULL)
+ {
+ Fail("Unable to open file for write.\n");
+ }
+
+ fwrite(outBuf1, sizeof(outBuf1[0]), sizeof(outBuf1), fp);
+ fwrite(outBuf2, sizeof(outBuf2[0]), sizeof(outBuf2), fp);
+
+ if (fclose(fp) != 0)
+ {
+ Fail("error closing stream opened for write.\n");
+ }
+
+ /*Read until the first linebreak*/
+ fp = fopen(filename, "r");
+ if (fp == NULL)
+ {
+ Fail("Unable to open file for read.\n");
+ }
+
+
+ if (fgets(inBuf, sizeof(outBuf1) + offset , fp) != inBuf)
+ {
+ Fail("Error reading from file using fgets.\n");
+ }
+
+ /*note: -1 because strlen returns the length of a string _not_
+ including the NULL, while fgets returns a string of specified
+ maximum length _including_ the NULL.*/
+ expectedLen = strlen(outBuf1);
+ actualLen = strlen(inBuf);
+ if (actualLen > expectedLen)
+ {
+ Fail("fgets() was asked to read the first line of a file, but did "
+ "not stop at the end of the line.\n");
+ }
+ else if (actualLen < expectedLen)
+ {
+ Fail("fgets() was asked to read the first line of a file, but did "
+ "not read the entire line.\n");
+ }
+ else if (memcmp(inBuf, outBuf1, actualLen) != 0)
+ {
+ /*We didn't read back exactly outBuf1*/
+ Fail("fgets() was asked to read the first line of a file. It "
+ "has read back a string of the correct length, but the"
+ " contents are not correct.\n");
+ }
+
+ if (fclose(fp) != 0)
+ {
+ Fail("Error closing file after using fgets().\n");
+ }
+
+ PAL_Terminate();
+ return PASS;
+
+}
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/fgets/test2/testinfo.dat b/src/pal/tests/palsuite/c_runtime/fgets/test2/testinfo.dat
new file mode 100644
index 0000000000..d282dbaa65
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fgets/test2/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = fgets
+Name = Positive Test for fgets
+TYPE = DEFAULT
+EXE1 = test2
+Description
+= Calls fgets to read a full line from a file. A maximum length
+= parameter greater than the length of the line is passed.
+
diff --git a/src/pal/tests/palsuite/c_runtime/fgets/test3/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/fgets/test3/CMakeLists.txt
new file mode 100644
index 0000000000..50f0901ee1
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fgets/test3/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test3.c
+)
+
+add_executable(paltest_fgets_test3
+ ${SOURCES}
+)
+
+add_dependencies(paltest_fgets_test3 coreclrpal)
+
+target_link_libraries(paltest_fgets_test3
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/fgets/test3/test3.c b/src/pal/tests/palsuite/c_runtime/fgets/test3/test3.c
new file mode 100644
index 0000000000..525ba9327f
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fgets/test3/test3.c
@@ -0,0 +1,73 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test3.c
+**
+** Purpose: Tries to read from an empty file using fgets(), to verify
+** handling of EOF condition.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char **argv)
+{
+ char inBuf[10];
+ const char filename[] = "testfile.tmp";
+
+ FILE * fp;
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ /*write the empty file that we will use to test */
+ fp = fopen(filename, "w");
+ if (fp == NULL)
+ {
+ Fail("Unable to open file for write.\n");
+ }
+
+ /*Don't write anything*/
+
+ if (fclose(fp) != 0)
+ {
+ Fail("Error closing stream opened for write.\n");
+ }
+
+
+ /*Open the file and try to read.*/
+ fp = fopen(filename, "r");
+ if (fp == NULL)
+ {
+ Fail("Unable to open file for read.\n");
+ }
+
+
+ if (fgets(inBuf, sizeof(inBuf) , fp) != NULL)
+ {
+ /*NULL could also mean an error condition, but since the PAL
+ doesn't supply feof or ferror, we can't distinguish between
+ the two.*/
+ Fail("fgets doesn't handle EOF properly. When asked to read from "
+ "an empty file, it didn't return NULL as it should have.\n");
+ }
+
+ if (fclose(fp) != 0)
+ {
+ Fail("Error closing an empty file after trying to use fgets().\n");
+ }
+ PAL_Terminate();
+ return PASS;
+
+}
+
+
+
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/fgets/test3/testinfo.dat b/src/pal/tests/palsuite/c_runtime/fgets/test3/testinfo.dat
new file mode 100644
index 0000000000..e10cf89968
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fgets/test3/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = fgets
+Name = Positive Test for fgets
+TYPE = DEFAULT
+EXE1 = test3
+Description
+= Tries to read from an empty file using fgets(), to verify handling of
+= EOF condition.
+
diff --git a/src/pal/tests/palsuite/c_runtime/floor/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/floor/CMakeLists.txt
new file mode 100644
index 0000000000..5e1ef7f28b
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/floor/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
diff --git a/src/pal/tests/palsuite/c_runtime/floor/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/floor/test1/CMakeLists.txt
new file mode 100644
index 0000000000..dbc5abde5b
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/floor/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_floor_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_floor_test1 coreclrpal)
+
+target_link_libraries(paltest_floor_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/floor/test1/test1.c b/src/pal/tests/palsuite/c_runtime/floor/test1/test1.c
new file mode 100644
index 0000000000..dba320919b
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/floor/test1/test1.c
@@ -0,0 +1,132 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Tests floor with simple positive and negative values. Also tests
+** extreme cases like extremely small values and positive and
+** negative infinity. Makes sure that calling floor on NaN returns
+** NaN
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+
+// binary64 (double) has a machine epsilon of 2^-52 (approx. 2.22e-16). However, this
+// is slightly too accurate when writing tests meant to run against libm implementations
+// for various platforms. 2^-50 (approx. 8.88e-16) seems to be as accurate as we can get.
+//
+// The tests themselves will take PAL_EPSILON and adjust it according to the expected result
+// so that the delta used for comparison will compare the most significant digits and ignore
+// any digits that are outside the double precision range (15-17 digits).
+
+// For example, a test with an expect result in the format of 0.xxxxxxxxxxxxxxxxx will use
+// PAL_EPSILON for the variance, while an expected result in the format of 0.0xxxxxxxxxxxxxxxxx
+// will use PAL_EPSILON / 10 and and expected result in the format of x.xxxxxxxxxxxxxxxx will
+// use PAL_EPSILON * 10.
+#define PAL_EPSILON 8.8817841970012523e-16
+
+#define PAL_NAN sqrt(-1.0)
+#define PAL_POSINF -log(0.0)
+#define PAL_NEGINF log(0.0)
+
+/**
+ * Helper test structure
+ */
+struct test
+{
+ double value; /* value to test the function with */
+ double expected; /* expected result */
+ double variance; /* maximum delta between the expected and actual result */
+};
+
+/**
+ * validate
+ *
+ * test validation function
+ */
+void __cdecl validate(double value, double expected, double variance)
+{
+ double result = floor(value);
+
+ /*
+ * The test is valid when the difference between result
+ * and expected is less than or equal to variance
+ */
+ double delta = fabs(result - expected);
+
+ if (delta > variance)
+ {
+ Fail("floor(%g) returned %20.17g when it should have returned %20.17g",
+ value, result, expected);
+ }
+}
+
+/**
+ * validate
+ *
+ * test validation function for values returning NaN
+ */
+void __cdecl validate_isnan(double value)
+{
+ double result = floor(value);
+
+ if (!_isnan(result))
+ {
+ Fail("floor(%g) returned %20.17g when it should have returned %20.17g",
+ value, result, PAL_NAN);
+ }
+}
+
+/**
+ * main
+ *
+ * executable entry point
+ */
+int __cdecl main(int argc, char *argv[])
+{
+ struct test tests[] =
+ {
+ /* value expected variance */
+ { 0.31830988618379067, 0, PAL_EPSILON }, // value: 1 / pi
+ { 0.43429448190325183, 0, PAL_EPSILON }, // value: log10(e)
+ { 0.63661977236758134, 0, PAL_EPSILON }, // value: 2 / pi
+ { 0.69314718055994531, 0, PAL_EPSILON }, // value: ln(2)
+ { 0.70710678118654752, 0, PAL_EPSILON }, // value: 1 / sqrt(2)
+ { 0.78539816339744831, 0, PAL_EPSILON }, // value: pi / 4
+ { 1.1283791670955126, 1, PAL_EPSILON * 10 }, // value: 2 / sqrt(pi)
+ { 1.4142135623730950, 1, PAL_EPSILON * 10 }, // value: sqrt(2)
+ { 1.4426950408889634, 1, PAL_EPSILON * 10 }, // value: log2(e)
+ { 1.5707963267948966, 1, PAL_EPSILON * 10 }, // value: pi / 2
+ { 2.3025850929940457, 2, PAL_EPSILON * 10 }, // value: ln(10)
+ { 2.7182818284590452, 2, PAL_EPSILON * 10 }, // value: e
+ { 3.1415926535897932, 3, PAL_EPSILON * 10 }, // value: pi
+ { PAL_POSINF, PAL_POSINF, 0 }
+ };
+
+ /* PAL initialization */
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+ validate( 0, 0, PAL_EPSILON);
+ validate(-0.0, 0, PAL_EPSILON);
+
+ validate( 1, 1, PAL_EPSILON * 10);
+ validate(-1.0, -1, PAL_EPSILON * 10);
+
+ for (int i = 0; i < (sizeof(tests) / sizeof(struct test)); i++)
+ {
+ validate( tests[i].value, tests[i].expected, tests[i].variance);
+ validate(-tests[i].value, -(tests[i].expected + 1), tests[i].variance);
+ }
+
+ validate_isnan(PAL_NAN);
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/floor/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/floor/test1/testinfo.dat
new file mode 100644
index 0000000000..90543ea7af
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/floor/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = floor
+Name = Positive Test for floor
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Passes to floor() a series of value, checking that
+= each one return to correct value.
diff --git a/src/pal/tests/palsuite/c_runtime/fmod/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/fmod/CMakeLists.txt
new file mode 100644
index 0000000000..5e1ef7f28b
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fmod/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
diff --git a/src/pal/tests/palsuite/c_runtime/fmod/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/fmod/test1/CMakeLists.txt
new file mode 100644
index 0000000000..c76df1f0bf
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fmod/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_fmod_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_fmod_test1 coreclrpal)
+
+target_link_libraries(paltest_fmod_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/fmod/test1/test1.c b/src/pal/tests/palsuite/c_runtime/fmod/test1/test1.c
new file mode 100644
index 0000000000..fd69ca52cb
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fmod/test1/test1.c
@@ -0,0 +1,157 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Test to ensure that fmod return the correct values
+**
+** Dependencies: PAL_Initialize
+** PAL_Terminate
+** Fail
+** fabs
+**
+**===========================================================================*/
+
+#include <palsuite.h>
+
+// binary64 (double) has a machine epsilon of 2^-52 (approx. 2.22e-16). However, this
+// is slightly too accurate when writing tests meant to run against libm implementations
+// for various platforms. 2^-50 (approx. 8.88e-16) seems to be as accurate as we can get.
+//
+// The tests themselves will take PAL_EPSILON and adjust it according to the expected result
+// so that the delta used for comparison will compare the most significant digits and ignore
+// any digits that are outside the double precision range (15-17 digits).
+
+// For example, a test with an expect result in the format of 0.xxxxxxxxxxxxxxxxx will use
+// PAL_EPSILON for the variance, while an expected result in the format of 0.0xxxxxxxxxxxxxxxxx
+// will use PAL_EPSILON / 10 and and expected result in the format of x.xxxxxxxxxxxxxxxx will
+// use PAL_EPSILON * 10.
+#define PAL_EPSILON 8.8817841970012523e-16
+
+#define PAL_NAN sqrt(-1.0)
+#define PAL_POSINF -log(0.0)
+#define PAL_NEGINF log(0.0)
+
+/**
+ * Helper test structure
+ */
+struct test
+{
+ double numerator; /* second component of the value to test the function with */
+ double denominator; /* first component of the value to test the function with */
+ double expected; /* expected result */
+ double variance; /* maximum delta between the expected and actual result */
+};
+
+/**
+ * validate
+ *
+ * test validation function
+ */
+void __cdecl validate(double numerator, double denominator, double expected, double variance)
+{
+ double result = fmod(numerator, denominator);
+
+ /*
+ * The test is valid when the difference between result
+ * and expected is less than or equal to variance
+ */
+ double delta = fabs(result - expected);
+
+ if (delta > variance)
+ {
+ Fail("fmod(%g, %g) returned %20.17g when it should have returned %20.17g",
+ numerator, denominator, result, expected);
+ }
+}
+
+/**
+ * validate
+ *
+ * test validation function for values returning NaN
+ */
+void __cdecl validate_isnan(double numerator, double denominator)
+{
+ double result = fmod(numerator, denominator);
+
+ if (!_isnan(result))
+ {
+ Fail("fmod(%g, %g) returned %20.17g when it should have returned %20.17g",
+ numerator, denominator, result, PAL_NAN);
+ }
+}
+
+/**
+ * main
+ *
+ * executable entry point
+ */
+INT __cdecl main(INT argc, CHAR **argv)
+{
+ struct test tests[] =
+ {
+ /* numerator denominator expected variance */
+ { 0, PAL_POSINF, 0, PAL_EPSILON },
+ { 0.31296179620778659, 0.94976571538163866, 0.31296179620778658, PAL_EPSILON },
+ { 0.42077048331375735, 0.90716712923909839, 0.42077048331375733, PAL_EPSILON },
+ { 0.59448076852482208, 0.80410982822879171, 0.59448076852482212, PAL_EPSILON },
+ { 0.63896127631363480, 0.76923890136397213, 0.63896127631363475, PAL_EPSILON },
+ { 0.64963693908006244, 0.76024459707563015, 0.64963693908006248, PAL_EPSILON },
+ { 0.70710678118654752, 0.70710678118654752, 0, PAL_EPSILON },
+ { 1, 1, 0, PAL_EPSILON },
+ { 0.84147098480789651, 0.54030230586813972, 0.30116867893975674, PAL_EPSILON },
+ { 0.90371945743584630, 0.42812514788535792, 0.047469161665130377, PAL_EPSILON / 10 },
+ { 0.98776594599273553, 0.15594369476537447, 0.052103777400488605, PAL_EPSILON / 10 },
+ { 0.99180624439366372, 0.12775121753523991, 0.097547721646984359, PAL_EPSILON / 10 },
+ { 0.74398033695749319, -0.66820151019031295, 0.075778826767180285, PAL_EPSILON / 10 },
+ { 0.41078129050290870, -0.91173391478696510, 0.41078129050290868, PAL_EPSILON },
+ { 0, -1, 0, PAL_EPSILON },
+ { 1, PAL_POSINF, 1, PAL_EPSILON * 10 },
+ };
+
+
+ // PAL initialization
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+ for (int i = 0; i < (sizeof(tests) / sizeof(struct test)); i++)
+ {
+ validate( tests[i].numerator, tests[i].denominator, tests[i].expected, tests[i].variance);
+ validate(-tests[i].numerator, tests[i].denominator, -tests[i].expected, tests[i].variance);
+ validate( tests[i].numerator, -tests[i].denominator, tests[i].expected, tests[i].variance);
+ validate(-tests[i].numerator, -tests[i].denominator, -tests[i].expected, tests[i].variance);
+ }
+
+ validate_isnan( 0, 0);
+ validate_isnan(-0.0, 0);
+ validate_isnan( 0, -0.0);
+ validate_isnan(-0.0, -0.0);
+
+ validate_isnan( 1, 0);
+ validate_isnan(-1.0, 0);
+ validate_isnan( 1, -0.0);
+ validate_isnan(-1.0, -0.0);
+
+ validate_isnan(PAL_POSINF, PAL_POSINF);
+ validate_isnan(PAL_NEGINF, PAL_POSINF);
+ validate_isnan(PAL_POSINF, PAL_NEGINF);
+ validate_isnan(PAL_NEGINF, PAL_NEGINF);
+
+ validate_isnan(PAL_POSINF, 0);
+ validate_isnan(PAL_NEGINF, 0);
+ validate_isnan(PAL_POSINF, -0.0);
+ validate_isnan(PAL_NEGINF, -0.0);
+
+ validate_isnan(PAL_POSINF, 1);
+ validate_isnan(PAL_NEGINF, 1);
+ validate_isnan(PAL_POSINF, -1.0);
+ validate_isnan(PAL_NEGINF, -1.0);
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/fmod/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/fmod/test1/testinfo.dat
new file mode 100644
index 0000000000..0a81fd80e0
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fmod/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = fmod
+Name = Positive Test for fmod
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Passes to fmod() a series of values, checking that
+= each one return to correct value.
diff --git a/src/pal/tests/palsuite/c_runtime/fmodf/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/fmodf/CMakeLists.txt
new file mode 100644
index 0000000000..5e1ef7f28b
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fmodf/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
diff --git a/src/pal/tests/palsuite/c_runtime/fmodf/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/fmodf/test1/CMakeLists.txt
new file mode 100644
index 0000000000..d1ea238a98
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fmodf/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_fmodf_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_fmodf_test1 coreclrpal)
+
+target_link_libraries(paltest_fmodf_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/fmodf/test1/test1.c b/src/pal/tests/palsuite/c_runtime/fmodf/test1/test1.c
new file mode 100644
index 0000000000..31b45d3606
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fmodf/test1/test1.c
@@ -0,0 +1,156 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Test to ensure that fmodf return the correct values
+**
+** Dependencies: PAL_Initialize
+** PAL_Terminate
+** Fail
+** fabsf
+**
+**===========================================================================*/
+
+#include <palsuite.h>
+
+// binary32 (float) has a machine epsilon of 2^-23 (approx. 1.19e-07). However, this
+// is slightly too accurate when writing tests meant to run against libm implementations
+// for various platforms. 2^-21 (approx. 4.76e-07) seems to be as accurate as we can get.
+//
+// The tests themselves will take PAL_EPSILON and adjust it according to the expected result
+// so that the delta used for comparison will compare the most significant digits and ignore
+// any digits that are outside the double precision range (6-9 digits).
+
+// For example, a test with an expect result in the format of 0.xxxxxxxxx will use PAL_EPSILON
+// for the variance, while an expected result in the format of 0.0xxxxxxxxx will use
+// PAL_EPSILON / 10 and and expected result in the format of x.xxxxxx will use PAL_EPSILON * 10.
+#define PAL_EPSILON 4.76837158e-07
+
+#define PAL_NAN sqrt(-1.0)
+#define PAL_POSINF -log(0.0)
+#define PAL_NEGINF log(0.0)
+
+/**
+ * Helper test structure
+ */
+struct test
+{
+ float numerator; /* second component of the value to test the function with */
+ float denominator; /* first component of the value to test the function with */
+ float expected; /* expected result */
+ float variance; /* maximum delta between the expected and actual result */
+};
+
+/**
+ * validate
+ *
+ * test validation function
+ */
+void __cdecl validate(float numerator, float denominator, float expected, float variance)
+{
+ float result = fmodf(numerator, denominator);
+
+ /*
+ * The test is valid when the difference between result
+ * and expected is less than or equal to variance
+ */
+ float delta = fabsf(result - expected);
+
+ if (delta > variance)
+ {
+ Fail("fmodf(%g, %g) returned %10.9g when it should have returned %10.9g",
+ numerator, denominator, result, expected);
+ }
+}
+
+/**
+ * validate
+ *
+ * test validation function for values returning NaN
+ */
+void __cdecl validate_isnan(float numerator, float denominator)
+{
+ float result = fmodf(numerator, denominator);
+
+ if (!_isnan(result))
+ {
+ Fail("fmodf(%g, %g) returned %10.9g when it should have returned %10.9g",
+ numerator, denominator, result, PAL_NAN);
+ }
+}
+
+/**
+ * main
+ *
+ * executable entry point
+ */
+INT __cdecl main(INT argc, CHAR **argv)
+{
+ struct test tests[] =
+ {
+ /* numerator denominator expected variance */
+ { 0, PAL_POSINF, 0, PAL_EPSILON },
+ { 0.312961796f, 0.949765715f, 0.312961796f, PAL_EPSILON },
+ { 0.420770483f, 0.907167129f, 0.420770483f, PAL_EPSILON },
+ { 0.594480769f, 0.804109828f, 0.594480769f, PAL_EPSILON },
+ { 0.638961276f, 0.769238901f, 0.638961276f, PAL_EPSILON },
+ { 0.649636939f, 0.760244597f, 0.649636939f, PAL_EPSILON },
+ { 0.707106781f, 0.707106781f, 0, PAL_EPSILON },
+ { 1, 1, 0, PAL_EPSILON },
+ { 0.841470985f, 0.540302306f, 0.301168679f, PAL_EPSILON },
+ { 0.903719457f, 0.428125148f, 0.0474691617f, PAL_EPSILON / 10 },
+ { 0.987765946f, 0.155943695f, 0.0521037774f, PAL_EPSILON / 10 },
+ { 0.991806244f, 0.127751218f, 0.0975477216f, PAL_EPSILON / 10 },
+ { 0.743980337f, -0.668201510f, 0.0757788268f, PAL_EPSILON / 10 },
+ { 0.410781291f, -0.911733915f, 0.410781291f, PAL_EPSILON },
+ { 0, -1, 0, PAL_EPSILON },
+ { 1, PAL_POSINF, 1, PAL_EPSILON * 10 },
+ };
+
+
+ // PAL initialization
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+ for (int i = 0; i < (sizeof(tests) / sizeof(struct test)); i++)
+ {
+ validate( tests[i].numerator, tests[i].denominator, tests[i].expected, tests[i].variance);
+ validate(-tests[i].numerator, tests[i].denominator, -tests[i].expected, tests[i].variance);
+ validate( tests[i].numerator, -tests[i].denominator, tests[i].expected, tests[i].variance);
+ validate(-tests[i].numerator, -tests[i].denominator, -tests[i].expected, tests[i].variance);
+ }
+
+ validate_isnan( 0, 0);
+ validate_isnan(-0.0f, 0);
+ validate_isnan( 0, -0.0f);
+ validate_isnan(-0.0f, -0.0f);
+
+ validate_isnan( 1, 0);
+ validate_isnan(-1, 0);
+ validate_isnan( 1, -0.0f);
+ validate_isnan(-1, -0.0f);
+
+ validate_isnan(PAL_POSINF, PAL_POSINF);
+ validate_isnan(PAL_NEGINF, PAL_POSINF);
+ validate_isnan(PAL_POSINF, PAL_NEGINF);
+ validate_isnan(PAL_NEGINF, PAL_NEGINF);
+
+ validate_isnan(PAL_POSINF, 0);
+ validate_isnan(PAL_NEGINF, 0);
+ validate_isnan(PAL_POSINF, -0.0f);
+ validate_isnan(PAL_NEGINF, -0.0f);
+
+ validate_isnan(PAL_POSINF, 1);
+ validate_isnan(PAL_NEGINF, 1);
+ validate_isnan(PAL_POSINF, -1);
+ validate_isnan(PAL_NEGINF, -1);
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/fmodf/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/fmodf/test1/testinfo.dat
new file mode 100644
index 0000000000..11c7978925
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fmodf/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = fmodf
+Name = Positive Test for fmodf
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Passes to fmodf() a series of values, checking that
+= each one return to correct value.
diff --git a/src/pal/tests/palsuite/c_runtime/fopen/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/fopen/CMakeLists.txt
new file mode 100644
index 0000000000..19ee487a6a
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fopen/CMakeLists.txt
@@ -0,0 +1,10 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+add_subdirectory(test3)
+add_subdirectory(test4)
+add_subdirectory(test5)
+add_subdirectory(test6)
+add_subdirectory(test7)
+
diff --git a/src/pal/tests/palsuite/c_runtime/fopen/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/fopen/test1/CMakeLists.txt
new file mode 100644
index 0000000000..6578c43659
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fopen/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_fopen_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_fopen_test1 coreclrpal)
+
+target_link_libraries(paltest_fopen_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/fopen/test1/test1.c b/src/pal/tests/palsuite/c_runtime/fopen/test1/test1.c
new file mode 100644
index 0000000000..565b4eb77d
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fopen/test1/test1.c
@@ -0,0 +1,82 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test1.c
+**
+** Purpose: Tests the PAL implementation of the fopen function.
+** This test simply attempts to open a number of files
+** with different modes. It checks to ensure a valid
+** file pointer is returned. It doesn't do any checking
+** to ensure the mode is really what it claims. And checks
+** for a NULL pointer when attempts to open a directory.
+**
+
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+struct testCase
+{
+ int CorrectResult;
+ char mode[20];
+};
+
+int __cdecl main(int argc, char **argv)
+{
+
+ FILE *fp;
+ char name[128];
+ int i;
+
+ struct testCase testCases[] =
+ {
+ {0, "r"}, {1, "w"}, {1, "a"},
+ {0, "r+"}, {1, "w+"}, {1, "a+"},
+ {1, "wt"}, {1, "wb"}, {1, "wS"},
+ {1, "w+c"}, {1, "w+n"}, {1, "wR"},
+ {1, "wT"}, {0, "tw"}
+ };
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+
+ for(i = 0; i < sizeof(testCases) / sizeof(struct testCase); i++)
+ {
+ strcpy(name,"testfiles");
+ strcat(name,testCases[i].mode);
+
+ fp = fopen(name,testCases[i].mode);
+
+ if ((fp == 0 && testCases[i].CorrectResult != 0) ||
+ (testCases[i].CorrectResult == 0 && fp != 0) )
+ {
+ Fail("ERROR: fopen returned incorrectly "
+ "opening a file in %s mode. Perhaps it opened a "
+ "read only file which didn't exist and returned a correct "
+ "pointer?",testCases[i].mode);
+ }
+
+ memset(name, '\0', 128);
+
+ }
+
+ /* When attempt to open a directory fopen should returned NULL */
+ if ( fopen(".", "r") != NULL)
+ {
+ Fail("ERROR: fopen returned non-NULL when trying to open a directory"
+ " the returned value was %d\n", fp);
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/fopen/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/fopen/test1/testinfo.dat
new file mode 100644
index 0000000000..d9908549ea
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fopen/test1/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = fopen
+Name = Positive Test for fopen
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= This test simply attempts to open a number of files with different
+= modes. It checks to ensure a valid file pointer is returned. It
+= doesn't do any checking to ensure the mode is really what it claims.
+= Checks for returned value when attempts to open a directory.
diff --git a/src/pal/tests/palsuite/c_runtime/fopen/test2/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/fopen/test2/CMakeLists.txt
new file mode 100644
index 0000000000..4458ed21d8
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fopen/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test2.c
+)
+
+add_executable(paltest_fopen_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_fopen_test2 coreclrpal)
+
+target_link_libraries(paltest_fopen_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/fopen/test2/test2.c b/src/pal/tests/palsuite/c_runtime/fopen/test2/test2.c
new file mode 100644
index 0000000000..4026efe89a
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fopen/test2/test2.c
@@ -0,0 +1,65 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test2.c
+**
+** Purpose: Tests the PAL implementation of the fopen function.
+** Test to ensure that you can write to a 'w' mode file.
+** And that you can't read from a 'w' mode file.
+**
+** Depends:
+** fprintf
+** fseek
+** fgets
+**
+
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char **argv)
+{
+
+ FILE *fp;
+ char buffer[128];
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ if( (fp = fopen( "testfile", "w" )) == NULL )
+ {
+ Fail( "ERROR: The file failed to open with 'w' mode.\n" );
+ }
+
+ /* Test that you can write */
+ if(fprintf(fp,"%s","some text") <= 0)
+ {
+ Fail("ERROR: Attempted to WRITE to a file opened with 'w' mode "
+ "but fprintf failed. Either fopen or fprintf have problems.");
+ }
+
+ if(fseek(fp, 0, SEEK_SET))
+ {
+ Fail("ERROR: fseek failed, and this test depends on it.");
+ }
+
+ /* Test that you can't read */
+ if(fgets(buffer,10,fp) != NULL)
+ {
+ Fail("ERROR: Tried to READ from a file with only 'w' mode set. "
+ "This should fail, but fgets didn't return NULL. Either "
+ "fgets or fopen is broken.");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/fopen/test2/testinfo.dat b/src/pal/tests/palsuite/c_runtime/fopen/test2/testinfo.dat
new file mode 100644
index 0000000000..4c1a0095f8
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fopen/test2/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = fopen
+Name = Positive Test for fopen
+TYPE = DEFAULT
+EXE1 = test2
+Description
+= Test to ensure that you can write to a 'w' mode file. And that you can't
+= read from a 'w' mode file.
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/fopen/test3/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/fopen/test3/CMakeLists.txt
new file mode 100644
index 0000000000..2c80f72ae7
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fopen/test3/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test3.c
+)
+
+add_executable(paltest_fopen_test3
+ ${SOURCES}
+)
+
+add_dependencies(paltest_fopen_test3 coreclrpal)
+
+target_link_libraries(paltest_fopen_test3
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/fopen/test3/test3.c b/src/pal/tests/palsuite/c_runtime/fopen/test3/test3.c
new file mode 100644
index 0000000000..f3af42dc8a
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fopen/test3/test3.c
@@ -0,0 +1,66 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test3.c
+**
+** Purpose: Tests the PAL implementation of the fopen function.
+** Test to ensure that you can write to a 'w+' mode file.
+** And that you can read from a 'w+' mode file.
+**
+** Depends:
+** fprintf
+** fseek
+** fgets
+**
+
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char **argv)
+{
+
+ FILE *fp;
+ char buffer[128];
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ /* Open a file with 'w+' mode */
+ if( (fp = fopen( "testfile", "w+" )) == NULL )
+ {
+ Fail( "ERROR: The file failed to open with 'w+' mode.\n" );
+ }
+
+ /* Write some text to the file */
+ if(fprintf(fp,"%s","some text") <= 0)
+ {
+ Fail("ERROR: Attempted to WRITE to a file opened with 'w+' mode "
+ "but fprintf failed. Either fopen or fprintf have problems.");
+ }
+
+ if(fseek(fp, 0, SEEK_SET))
+ {
+ Fail("ERROR: fseek failed, and this test depends on it.");
+ }
+
+ /* Attempt to read from the 'w+' only file, should pass */
+ if(fgets(buffer,10,fp) == NULL)
+ {
+ Fail("ERROR: Tried to READ from a file with 'w+' mode set. "
+ "This should succeed, but fgets returned NULL. Either fgets "
+ "or fopen is broken.");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/fopen/test3/testinfo.dat b/src/pal/tests/palsuite/c_runtime/fopen/test3/testinfo.dat
new file mode 100644
index 0000000000..c458c1196a
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fopen/test3/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = fopen
+Name = Positive Test for fopen
+TYPE = DEFAULT
+EXE1 = test3
+Description
+= Test to ensure that you can write to a 'w+' mode file. And that you can
+= read from a 'w+' mode file.
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/fopen/test4/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/fopen/test4/CMakeLists.txt
new file mode 100644
index 0000000000..92e0ef0bd8
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fopen/test4/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test4.c
+)
+
+add_executable(paltest_fopen_test4
+ ${SOURCES}
+)
+
+add_dependencies(paltest_fopen_test4 coreclrpal)
+
+target_link_libraries(paltest_fopen_test4
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/fopen/test4/test4.c b/src/pal/tests/palsuite/c_runtime/fopen/test4/test4.c
new file mode 100644
index 0000000000..04683d52c5
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fopen/test4/test4.c
@@ -0,0 +1,82 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test4.c
+**
+** Purpose: Tests the PAL implementation of the fopen function.
+** Test to ensure that you can't write to a 'r' mode file.
+** And that you can read from a 'r' mode file.
+**
+** Depends:
+** fprintf
+** fclose
+** fgets
+**
+
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char **argv)
+{
+
+ FILE *fp;
+ char buffer[128];
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ /* Open a file with 'w' mode */
+ if( (fp = fopen( "testfile", "w" )) == NULL )
+ {
+ Fail( "ERROR: The file failed to open with 'w' mode.\n" );
+ }
+
+ /* Write some text to the file */
+ if(fprintf(fp,"%s","some text") <= 0)
+ {
+ Fail("ERROR: Attempted to WRITE to a file opened with 'w' mode "
+ "but fprintf failed. Either fopen or fprintf have problems.");
+ }
+
+ if(fclose(fp))
+ {
+ Fail("ERROR: Attempted to close a file, but fclose failed. "
+ "This test depends upon it.");
+ }
+
+ /* Open a file with 'r' mode */
+ if( (fp = fopen( "testfile", "r" )) == NULL )
+ {
+ Fail( "ERROR: The file failed to open with 'r' mode.\n" );
+ }
+
+ /* Attempt to read from the 'r' only file, should pass */
+ if(fgets(buffer,10,fp) == NULL)
+ {
+ Fail("ERROR: Tried to READ from a file with 'r' mode set. "
+ "This should succeed, but fgets returned NULL. Either fgets "
+ "or fopen is broken.");
+ }
+
+ /* Write some text to the file */
+ if(fprintf(fp,"%s","some text") > 0)
+ {
+ Fail("ERROR: Attempted to WRITE to a file opened with 'r' mode "
+ "but fprintf succeeded It should have failed. "
+ "Either fopen or fprintf have problems.");
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/fopen/test4/testinfo.dat b/src/pal/tests/palsuite/c_runtime/fopen/test4/testinfo.dat
new file mode 100644
index 0000000000..a1ecaf959b
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fopen/test4/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = fopen
+Name = Positive Test for fopen
+TYPE = DEFAULT
+EXE1 = test4
+Description
+= Test to ensure that you can't write to a 'r' mode file. And that you can
+= read from a 'r' mode file.
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/fopen/test5/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/fopen/test5/CMakeLists.txt
new file mode 100644
index 0000000000..82529b9aab
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fopen/test5/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test5.c
+)
+
+add_executable(paltest_fopen_test5
+ ${SOURCES}
+)
+
+add_dependencies(paltest_fopen_test5 coreclrpal)
+
+target_link_libraries(paltest_fopen_test5
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/fopen/test5/test5.c b/src/pal/tests/palsuite/c_runtime/fopen/test5/test5.c
new file mode 100644
index 0000000000..0a760314e1
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fopen/test5/test5.c
@@ -0,0 +1,78 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test5.c
+**
+** Purpose: Tests the PAL implementation of the fopen function.
+** Test to ensure that you can write to a 'r+' mode file.
+** And that you can read from a 'r+' mode file.
+**
+** Depends:
+** fprintf
+** fclose
+** fgets
+** fseek
+**
+
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char **argv)
+{
+
+ FILE *fp;
+ char buffer[128];
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ /* Open a file with 'w' mode */
+ if( (fp = fopen( "testfile", "w" )) == NULL )
+ {
+ Fail( "ERROR: The file failed to open with 'w' mode.\n" );
+ }
+
+ if(fclose(fp))
+ {
+ Fail("ERROR: Attempted to close a file, but fclose failed. "
+ "This test depends upon it.");
+ }
+
+ if( (fp = fopen( "testfile", "r+" )) == NULL )
+ {
+ Fail( "ERROR: The file failed to open with 'r+' mode.\n" );
+ }
+
+ /* Write some text to the file */
+ if(fprintf(fp,"%s","some text") <= 0)
+ {
+ Fail("ERROR: Attempted to WRITE to a file opened with 'r+' mode "
+ "but fprintf failed. Either fopen or fprintf have problems.");
+ }
+
+ if(fseek(fp, 0, SEEK_SET))
+ {
+ Fail("ERROR: fseek failed, and this test depends on it.");
+ }
+
+ /* Attempt to read from the 'r+' only file, should pass */
+ if(fgets(buffer,10,fp) == NULL)
+ {
+ Fail("ERROR: Tried to READ from a file with 'r+' mode set. "
+ "This should succeed, but fgets returned NULL. Either fgets "
+ "or fopen is broken.");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/fopen/test5/testinfo.dat b/src/pal/tests/palsuite/c_runtime/fopen/test5/testinfo.dat
new file mode 100644
index 0000000000..8f8f5d950b
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fopen/test5/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = fopen
+Name = Positive Test for fopen
+TYPE = DEFAULT
+EXE1 = test5
+Description
+= Test to ensure that you can write to a 'r+' mode file. And that you can
+= read from a 'r+' mode file.
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/fopen/test6/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/fopen/test6/CMakeLists.txt
new file mode 100644
index 0000000000..9a01cfb9a8
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fopen/test6/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test6.c
+)
+
+add_executable(paltest_fopen_test6
+ ${SOURCES}
+)
+
+add_dependencies(paltest_fopen_test6 coreclrpal)
+
+target_link_libraries(paltest_fopen_test6
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/fopen/test6/test6.c b/src/pal/tests/palsuite/c_runtime/fopen/test6/test6.c
new file mode 100644
index 0000000000..03b6067fdd
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fopen/test6/test6.c
@@ -0,0 +1,131 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test6.c
+**
+** Purpose: Tests the PAL implementation of the fopen function.
+** Test to ensure that you can write to an 'a' mode file.
+** And that you can't read from a 'a' mode file. Also ensure
+** that you can use fseek and still write to the end of a file.
+**
+** Depends:
+** fprintf
+** fgets
+** fseek
+** fclose
+**
+
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char **argv)
+{
+
+ FILE *fp;
+ char buffer[128];
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ /* Open a file with 'a+' mode */
+ if( (fp = fopen( "testfile", "a" )) == NULL )
+ {
+ Fail( "ERROR: The file failed to open with 'a' mode.\n" );
+ }
+
+ /* Write some text to the file */
+ if(fprintf(fp,"%s","some text") <= 0)
+ {
+ Fail("ERROR: Attempted to WRITE to a file opened with 'a' mode "
+ "but fprintf failed. Either fopen or fprintf have problems.");
+ }
+
+ if(fseek(fp, 0, SEEK_SET))
+ {
+ Fail("ERROR: fseek failed, and this test depends on it.");
+ }
+
+ /* Attempt to read from the 'a' only file, should fail */
+ if(fgets(buffer,10,fp) != NULL)
+ {
+ Fail("ERROR: Tried to READ from a file with 'a' mode set. "
+ "This should fail, but fgets returned success. Either fgets "
+ "or fopen is broken.");
+ }
+
+
+ /* Attempt to write to a file after using 'a' and fseek */
+ fp = fopen("testfile2", "a");
+ if(fp == NULL)
+ {
+ Fail("ERROR: The file failed to be created with 'a' mode.\n");
+ }
+
+ /* write text to the file initially */
+ if(fprintf(fp,"%s","abcd") <= 0)
+ {
+ Fail("ERROR: Attempted to WRITE to a file opened with 'a' mode "
+ "but fprintf failed. Either fopen or fprintf have problems.\n");
+ }
+
+ /* set the pointer to the front of the file */
+ if(fseek(fp, 0, SEEK_SET))
+ {
+ Fail("ERROR: fseek failed, and this test depends on it.\n");
+ }
+
+ /* using 'a' should still write to the end of the file, not the front */
+ if(fputs("efgh",fp) < 0)
+ {
+ Fail("ERROR: Attempted to WRITE to a file opened with 'a' mode "
+ "but fputs failed.\n");
+ }
+
+ /* set the pointer to the front of the file */
+ if(fseek(fp, 0, SEEK_SET))
+ {
+ Fail("ERROR: fseek failed, and this test depends on it.\n");
+ }
+
+ /* a file with 'a' mode can only write, so close the file before reading */
+ if(fclose(fp))
+ {
+ Fail("ERROR: fclose failed when it should have succeeded.\n");
+ }
+
+ /* open the file again to read */
+ fp = fopen("testfile2","r");
+ if(fp == NULL)
+ {
+ Fail("ERROR: fopen failed to open the file using 'r' mode");
+ }
+
+ /* Attempt to read from the 'a' only file, should succeed */
+ if(fgets(buffer,10,fp) == NULL)
+ {
+ Fail("ERROR: Tried to READ from a file with 'a' mode set. "
+ "This should pass, but fgets returned failure. Either fgets "
+ "or fopen is broken.\n");
+ }
+
+ /* Compare what was read and what should have been in the file */
+ if(memcmp(buffer,"abcdefgh",8))
+ {
+ Fail("ERROR: The string read should have equaled 'abcdefgh' "
+ "but instead it is %s\n", buffer);
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/fopen/test6/testinfo.dat b/src/pal/tests/palsuite/c_runtime/fopen/test6/testinfo.dat
new file mode 100644
index 0000000000..5edd94416d
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fopen/test6/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = fopen
+Name = Positive Test for fopen
+TYPE = DEFAULT
+EXE1 = test6
+Description
+= Test to ensure that you can write to a 'a' mode file. And that you can't
+= read from a 'a' mode file.
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/fopen/test7/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/fopen/test7/CMakeLists.txt
new file mode 100644
index 0000000000..168a5aff53
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fopen/test7/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test7.c
+)
+
+add_executable(paltest_fopen_test7
+ ${SOURCES}
+)
+
+add_dependencies(paltest_fopen_test7 coreclrpal)
+
+target_link_libraries(paltest_fopen_test7
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/fopen/test7/test7.c b/src/pal/tests/palsuite/c_runtime/fopen/test7/test7.c
new file mode 100644
index 0000000000..3ef8602ddb
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fopen/test7/test7.c
@@ -0,0 +1,117 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test7.c
+**
+** Purpose: Tests the PAL implementation of the fopen function.
+** Test to ensure that you can write to an 'a+' mode file.
+** And that you can read from a 'a+' mode file. Also ensure
+** that you can use fseek and still write to the end of a file.
+**
+** Depends:
+** fprintf
+** fgets
+** fseek
+** fclose
+**
+
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char **argv)
+{
+
+ FILE *fp;
+ char buffer[128];
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ /* Open a file with 'a+' mode */
+ if( (fp = fopen( "testfile", "a+" )) == NULL )
+ {
+ Fail( "ERROR: The file failed to open with 'a+' mode.\n" );
+ }
+
+ /* Write some text to the file */
+ if(fprintf(fp,"%s","some text") <= 0)
+ {
+ Fail("ERROR: Attempted to WRITE to a file opened with 'a+' mode "
+ "but fprintf failed. Either fopen or fprintf have problems.\n");
+ }
+
+ if(fseek(fp, 0, SEEK_SET))
+ {
+ Fail("ERROR: fseek failed, and this test depends on it.\n");
+ }
+
+ /* Attempt to read from the 'a+' only file, should succeed */
+ if(fgets(buffer,10,fp) == NULL)
+ {
+ Fail("ERROR: Tried to READ from a file with 'a+' mode set. "
+ "This should pass, but fgets returned failure. Either fgets "
+ "or fopen is broken.\n");
+ }
+
+
+ /* Attempt to write to a file after using 'a+' and fseek */
+ fp = fopen("testfile2", "a+");
+ if(fp == NULL)
+ {
+ Fail("ERROR: The file failed to be created with 'a+' mode.\n");
+ }
+
+ /* write text to the file initially */
+ if(fprintf(fp,"%s","abcd") <= 0)
+ {
+ Fail("ERROR: Attempted to WRITE to a file opened with 'a+' mode "
+ "but fprintf failed. Either fopen or fprintf have problems.\n");
+ }
+
+ /* set the pointer to the front of the file */
+ if(fseek(fp, 0, SEEK_SET))
+ {
+ Fail("ERROR: fseek failed, and this test depends on it.\n");
+ }
+
+ /* using 'a+' should still write to the end of the file, not the front */
+ if(fputs("efgh",fp) < 0)
+ {
+ Fail("ERROR: Attempted to WRITE to a file opened with 'a+' mode "
+ "but fputs failed.\n");
+ }
+
+ /* set the pointer to the front of the file */
+ if(fseek(fp, 0, SEEK_SET))
+ {
+ Fail("ERROR: fseek failed, and this test depends on it.\n");
+ }
+
+ /* Attempt to read from the 'a+' only file, should succeed */
+ if(fgets(buffer,10,fp) == NULL)
+ {
+ Fail("ERROR: Tried to READ from a file with 'a+' mode set. "
+ "This should pass, but fgets returned failure. Either fgets "
+ "or fopen is broken.\n");
+ }
+
+ /* Compare what was read and what should have been in the file */
+ if(memcmp(buffer,"abcdefgh",8))
+ {
+ Fail("ERROR: The string read should have equaled 'abcdefgh' "
+ "but instead it is %s\n", buffer);
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/fopen/test7/testinfo.dat b/src/pal/tests/palsuite/c_runtime/fopen/test7/testinfo.dat
new file mode 100644
index 0000000000..e4bc99c910
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fopen/test7/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = fopen
+Name = Positive Test for fopen
+TYPE = DEFAULT
+EXE1 = test7
+Description
+= Test to ensure that you can write to a 'a+' mode file. And that you can
+= read from a 'a+' mode file.
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/fprintf/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/fprintf/CMakeLists.txt
new file mode 100644
index 0000000000..cafb9536b0
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fprintf/CMakeLists.txt
@@ -0,0 +1,22 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test10)
+add_subdirectory(test11)
+add_subdirectory(test12)
+add_subdirectory(test13)
+add_subdirectory(test14)
+add_subdirectory(test15)
+add_subdirectory(test16)
+add_subdirectory(test17)
+add_subdirectory(test18)
+add_subdirectory(test19)
+add_subdirectory(test2)
+add_subdirectory(test3)
+add_subdirectory(test4)
+add_subdirectory(test5)
+add_subdirectory(test6)
+add_subdirectory(test7)
+add_subdirectory(test8)
+add_subdirectory(test9)
+
diff --git a/src/pal/tests/palsuite/c_runtime/fprintf/fprintf.h b/src/pal/tests/palsuite/c_runtime/fprintf/fprintf.h
new file mode 100644
index 0000000000..380eb0a0b3
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fprintf/fprintf.h
@@ -0,0 +1,177 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*NOTE:
+The creation of the test file within each function is because the FILE
+structure is not defined within pal.h. Therefore, unable to have
+function with this as a return type.
+*/
+
+#ifndef __FPRINTF_H__
+#define __FPRINTF_H__
+
+void DoStrTest(char *formatstr, char* param, char *checkstr)
+{
+ FILE *fp;
+ char buf[256] = { 0 };
+
+ if ((fp = fopen("testfile.txt", "w+")) == NULL )
+ Fail("ERROR: fopen failed to create testfile\n");
+ if ((fprintf(fp, formatstr, param)) < 0)
+ Fail("ERROR: fprintf failed\n");
+ if ((fseek(fp, 0, SEEK_SET)) != 0)
+ Fail("ERROR: fseek failed\n");
+ if ((fgets(buf, 100, fp)) == NULL)
+ Fail("ERROR: fseek failed\n");
+
+ if (memcmp(buf, checkstr, strlen(buf) + 1) != 0)
+ {
+ Fail("ERROR: failed to insert string \"%s\" into \"%s\"\n"
+ "Expected \"%s\" got \"%s\".\n",
+ param, formatstr, checkstr, buf);
+ }
+ fclose(fp);
+}
+
+void DoWStrTest(char *formatstr, WCHAR* param, char *checkstr)
+{
+ FILE *fp;
+ char buf[256] = { 0 };
+
+ if ((fp = fopen("testfile.txt", "w+")) == NULL )
+ Fail("ERROR: fopen failed to create testfile\n");
+ if ((fprintf(fp, formatstr, param)) < 0)
+ Fail("ERROR: fprintf failed\n");
+ if ((fseek(fp, 0, SEEK_SET)) != 0)
+ Fail("ERROR: fseek failed\n");
+ if ((fgets(buf, 100, fp)) == NULL)
+ Fail("ERROR: fseek failed\n");
+
+ if (memcmp(buf, checkstr, strlen(buf) + 1) != 0)
+ {
+ Fail("ERROR: failed to insert wide string \"%s\" into \"%s\"\n"
+ "Expected \"%s\" got \"%s\".\n",
+ convertC(param), formatstr, checkstr, buf);
+ }
+ fclose(fp);
+}
+
+
+void DoCharTest(char *formatstr, char param, char *checkstr)
+{
+ FILE *fp;
+ char buf[256] = { 0 };
+
+ if ((fp = fopen("testfile.txt", "w+")) == NULL )
+ Fail("ERROR: fopen failed to create testfile\n");
+ if ((fprintf(fp, formatstr, param)) < 0)
+ Fail("ERROR: fprintf failed\n");
+ if ((fseek(fp, 0, SEEK_SET)) != 0)
+ Fail("ERROR: fseek failed\n");
+ if ((fgets(buf, 100, fp)) == NULL)
+ Fail("ERROR: fseek failed\n");
+
+ if (memcmp(buf, checkstr, strlen(buf) + 1) != 0)
+ {
+ Fail("ERROR: failed to insert char \'%c\' (%d) into \"%s\"\n"
+ "Expected \"%s\" got \"%s\".\n",
+ param, param, formatstr, checkstr, buf);
+ }
+ fclose(fp);
+}
+
+void DoWCharTest(char *formatstr, WCHAR param, char *checkstr)
+{
+ FILE *fp;
+ char buf[256] = { 0 };
+
+ if ((fp = fopen("testfile.txt", "w+")) == NULL )
+ Fail("ERROR: fopen failed to create testfile\n");
+ if ((fprintf(fp, formatstr, param)) < 0)
+ Fail("ERROR: fprintf failed\n");
+ if ((fseek(fp, 0, SEEK_SET)) != 0)
+ Fail("ERROR: fseek failed\n");
+ if ((fgets(buf, 100, fp)) == NULL)
+ Fail("ERROR: fseek failed\n");
+
+ if (memcmp(buf, checkstr, strlen(buf) + 1) != 0)
+ {
+ Fail("ERROR: failed to insert wide char \'%c\' (%d) into \"%s\"\n"
+ "Expected \"%s\" got \"%s\".\n",
+ (char)param, param, formatstr, checkstr, buf);
+ }
+ fclose(fp);
+}
+
+void DoNumTest(char *formatstr, int value, char *checkstr)
+{
+ FILE *fp;
+ char buf[256] = { 0 };
+
+ if ((fp = fopen("testfile.txt", "w+")) == NULL )
+ Fail("ERROR: fopen failed to create testfile\n");
+ if ((fprintf(fp, formatstr, value)) < 0)
+ Fail("ERROR: fprintf failed\n");
+ if ((fseek(fp, 0, SEEK_SET)) != 0)
+ Fail("ERROR: fseek failed\n");
+ if ((fgets(buf, 100, fp)) == NULL)
+ Fail("ERROR: fseek failed\n");
+
+ if (memcmp(buf, checkstr, strlen(buf) + 1) != 0)
+ {
+ Fail("ERROR: failed to insert %#x into \"%s\"\n"
+ "Expected \"%s\" got \"%s\".\n",
+ value, formatstr, checkstr, buf);
+ }
+ fclose(fp);
+}
+
+void DoI64Test(char *formatstr, INT64 value, char *valuestr, char *checkstr1, char *checkstr2)
+{
+ FILE *fp;
+ char buf[256] = { 0 };
+
+ if ((fp = fopen("testfile.txt", "w+")) == NULL )
+ Fail("ERROR: fopen failed to create testfile\n");
+ if ((fprintf(fp, formatstr, value)) < 0)
+ Fail("ERROR: fprintf failed\n");
+ if ((fseek(fp, 0, SEEK_SET)) != 0)
+ Fail("ERROR: fseek failed\n");
+ if ((fgets(buf, 100, fp)) == NULL)
+ Fail("ERROR: fseek failed\n");
+
+ if (memcmp(buf, checkstr1, strlen(buf) + 1) != 0 &&
+ memcmp(buf, checkstr2, strlen(buf) + 1) != 0)
+ {
+ Fail("ERROR: failed to insert %s into \"%s\"\n"
+ "Expected \"%s\" or \"%s\", got \"%s\".\n",
+ valuestr, formatstr, checkstr1, checkstr2, buf);
+ }
+ fclose(fp);
+}
+
+void DoDoubleTest(char *formatstr, double value, char *checkstr1, char *checkstr2)
+{
+ FILE *fp;
+ char buf[256] = { 0 };
+
+ if ((fp = fopen("testfile.txt", "w+")) == NULL )
+ Fail("ERROR: fopen failed to create testfile\n");
+ if ((fprintf(fp, formatstr, value)) < 0)
+ Fail("ERROR: fprintf failed\n");
+ if ((fseek(fp, 0, SEEK_SET)) != 0)
+ Fail("ERROR: fseek failed\n");
+ if ((fgets(buf, 100, fp)) == NULL)
+ Fail("ERROR: fseek failed\n");
+
+ if (memcmp(buf, checkstr1, strlen(buf) + 1) != 0 &&
+ memcmp(buf, checkstr2, strlen(buf) + 1) != 0)
+ {
+ Fail("ERROR: failed to insert %f into \"%s\"\n"
+ "Expected \"%s\" or \"%s\", got \"%s\".\n",
+ value, formatstr, checkstr1, checkstr2, buf);
+ }
+ fclose(fp);
+}
+#endif
diff --git a/src/pal/tests/palsuite/c_runtime/fprintf/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/fprintf/test1/CMakeLists.txt
new file mode 100644
index 0000000000..ab4176563d
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fprintf/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_fprintf_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_fprintf_test1 coreclrpal)
+
+target_link_libraries(paltest_fprintf_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/fprintf/test1/test1.c b/src/pal/tests/palsuite/c_runtime/fprintf/test1/test1.c
new file mode 100644
index 0000000000..d55fc2534c
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fprintf/test1/test1.c
@@ -0,0 +1,80 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c (fprintf)
+**
+** Purpose: A single, basic, test case with no formatting.
+** Test modeled after the sprintf series.
+**
+
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+
+/*
+ * Depends on memcmp, strlen, fopen, fgets, fseek and fclose.
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ FILE *fp;
+ char testfile[] = "testfile.txt";
+ char checkstr[] = "hello world";
+ char buf[256];
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return(FAIL);
+ }
+
+ if ((fp = fopen(testfile, "w+")) == NULL)
+ {
+ Fail("ERROR: fopen failed to create \"%s\"\n", testfile);
+ }
+
+ if ((fprintf(fp, "hello world")) < 0)
+ {
+ Fail("ERROR: fprintf failed to print to \"%s\"\n", testfile);
+ }
+
+ if ((fseek( fp, 0, SEEK_SET)) != 0)
+
+ {
+
+ Fail("ERROR: Fseek failed to set pointer to beginning of file\n" );
+
+ }
+
+
+
+ if ((fgets( buf, 100, fp )) == NULL)
+
+ {
+
+ Fail("ERROR: fgets failed\n");
+
+ }
+
+
+ if (memcmp(checkstr, buf, strlen(checkstr)+1) != 0)
+ {
+ Fail("ERROR: expected %s, got %s\n", checkstr, buf);
+ }
+
+
+
+ if ((fclose( fp )) != 0)
+
+ {
+
+ Fail("ERROR: fclose failed to close \"%s\"\n", testfile);
+
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/fprintf/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/fprintf/test1/testinfo.dat
new file mode 100644
index 0000000000..be3bf4b78a
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fprintf/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = fprintf
+Name = Positive Test for fprintf
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= A single, basic, test case with no formatting.
+= Test modeled after the sprintf series.
diff --git a/src/pal/tests/palsuite/c_runtime/fprintf/test10/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/fprintf/test10/CMakeLists.txt
new file mode 100644
index 0000000000..f718ad7934
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fprintf/test10/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test10.c
+)
+
+add_executable(paltest_fprintf_test10
+ ${SOURCES}
+)
+
+add_dependencies(paltest_fprintf_test10 coreclrpal)
+
+target_link_libraries(paltest_fprintf_test10
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/fprintf/test10/test10.c b/src/pal/tests/palsuite/c_runtime/fprintf/test10/test10.c
new file mode 100644
index 0000000000..5988e8da74
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fprintf/test10/test10.c
@@ -0,0 +1,49 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test10.c (fprintf)
+**
+** Purpose: Tests the octal specifier (%o).
+** This test is modeled after the fprintf series.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+#include "../fprintf.h"
+
+/*
+ * Depends on memcmp, strlen, fopen, fseek and fgets.
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ int neg = -42;
+ int pos = 42;
+ INT64 l = 42;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ return(FAIL);
+
+ DoNumTest("foo %o", pos, "foo 52");
+ DoNumTest("foo %lo", 0xFFFF, "foo 177777");
+ DoNumTest("foo %ho", 0xFFFF, "foo 177777");
+ DoNumTest("foo %Lo", pos, "foo 52");
+ DoI64Test("foo %I64o", l, "42", "foo 52", "foo 52");
+ DoNumTest("foo %3o", pos, "foo 52");
+ DoNumTest("foo %-3o", pos, "foo 52 ");
+ DoNumTest("foo %.1o", pos, "foo 52");
+ DoNumTest("foo %.3o", pos, "foo 052");
+ DoNumTest("foo %03o", pos, "foo 052");
+ DoNumTest("foo %#o", pos, "foo 052");
+ DoNumTest("foo %+o", pos, "foo 52");
+ DoNumTest("foo % o", pos, "foo 52");
+ DoNumTest("foo %+o", neg, "foo 37777777726");
+ DoNumTest("foo % o", neg, "foo 37777777726");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/fprintf/test10/testinfo.dat b/src/pal/tests/palsuite/c_runtime/fprintf/test10/testinfo.dat
new file mode 100644
index 0000000000..7afffeaf75
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fprintf/test10/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = fprintf
+Name = Positive Test for fprintf
+TYPE = DEFAULT
+EXE1 = test10
+Description
+= Tests the octal specifier (%o).
+= This test is modeled after the fprintf series.
diff --git a/src/pal/tests/palsuite/c_runtime/fprintf/test11/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/fprintf/test11/CMakeLists.txt
new file mode 100644
index 0000000000..6ccd58ddd2
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fprintf/test11/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test11.c
+)
+
+add_executable(paltest_fprintf_test11
+ ${SOURCES}
+)
+
+add_dependencies(paltest_fprintf_test11 coreclrpal)
+
+target_link_libraries(paltest_fprintf_test11
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/fprintf/test11/test11.c b/src/pal/tests/palsuite/c_runtime/fprintf/test11/test11.c
new file mode 100644
index 0000000000..01880552b7
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fprintf/test11/test11.c
@@ -0,0 +1,49 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test11.c (fprintf)
+**
+** Purpose: Test the unsigned int specifier (%u).
+** This test is modeled after the fprintf series.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+#include "../fprintf.h"
+
+/*
+ * Depends on memcmp, strlen, fopen, fseek and fgets.
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ int neg = -42;
+ int pos = 42;
+ INT64 l = 42;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ return(FAIL);
+
+ DoNumTest("foo %u", pos, "foo 42");
+ DoNumTest("foo %lu", 0xFFFF, "foo 65535");
+ DoNumTest("foo %hu", 0xFFFF, "foo 65535");
+ DoNumTest("foo %Lu", pos, "foo 42");
+ DoI64Test("foo %I64u", l, "42", "foo 42", "foo 42");
+ DoNumTest("foo %3u", pos, "foo 42");
+ DoNumTest("foo %-3u", pos, "foo 42 ");
+ DoNumTest("foo %.1u", pos, "foo 42");
+ DoNumTest("foo %.3u", pos, "foo 042");
+ DoNumTest("foo %03u", pos, "foo 042");
+ DoNumTest("foo %#u", pos, "foo 42");
+ DoNumTest("foo %+u", pos, "foo 42");
+ DoNumTest("foo % u", pos, "foo 42");
+ DoNumTest("foo %+u", neg, "foo 4294967254");
+ DoNumTest("foo % u", neg, "foo 4294967254");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/fprintf/test11/testinfo.dat b/src/pal/tests/palsuite/c_runtime/fprintf/test11/testinfo.dat
new file mode 100644
index 0000000000..8275f0f7ce
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fprintf/test11/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = fprintf
+Name = Positive Test for fprintf
+TYPE = DEFAULT
+EXE1 = test11
+Description
+= Test the unsigned int specifier (%u).
+= This test is modeled after the fprintf series.
diff --git a/src/pal/tests/palsuite/c_runtime/fprintf/test12/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/fprintf/test12/CMakeLists.txt
new file mode 100644
index 0000000000..17bc7f100b
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fprintf/test12/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test12.c
+)
+
+add_executable(paltest_fprintf_test12
+ ${SOURCES}
+)
+
+add_dependencies(paltest_fprintf_test12 coreclrpal)
+
+target_link_libraries(paltest_fprintf_test12
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/fprintf/test12/test12.c b/src/pal/tests/palsuite/c_runtime/fprintf/test12/test12.c
new file mode 100644
index 0000000000..0292e15014
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fprintf/test12/test12.c
@@ -0,0 +1,50 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test12.c
+**
+** Purpose: Tests the (lowercase) hexadecimal specifier (%x).
+** This test is modeled after the fprintf series.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+#include "../fprintf.h"
+
+/*
+ * Depends on memcmp, strlen, fopen, fseek and fgets.
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ int neg = -42;
+ int pos = 0x1234ab;
+ INT64 l = I64(0x1234567887654321);
+
+ if (PAL_Initialize(argc, argv) != 0)
+ return(FAIL);
+
+ DoNumTest("foo %x", pos, "foo 1234ab");
+ DoNumTest("foo %lx", pos, "foo 1234ab");
+ DoNumTest("foo %hx", pos, "foo 34ab");
+ DoNumTest("foo %Lx", pos, "foo 1234ab");
+ DoI64Test("foo %I64x", l, "0x1234567887654321",
+ "foo 1234567887654321", "foo 0x1234567887654321");
+ DoNumTest("foo %7x", pos, "foo 1234ab");
+ DoNumTest("foo %-7x", pos, "foo 1234ab ");
+ DoNumTest("foo %.1x", pos, "foo 1234ab");
+ DoNumTest("foo %.7x", pos, "foo 01234ab");
+ DoNumTest("foo %07x", pos, "foo 01234ab");
+ DoNumTest("foo %#x", pos, "foo 0x1234ab");
+ DoNumTest("foo %+x", pos, "foo 1234ab");
+ DoNumTest("foo % x", pos, "foo 1234ab");
+ DoNumTest("foo %+x", neg, "foo ffffffd6");
+ DoNumTest("foo % x", neg, "foo ffffffd6");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/fprintf/test12/testinfo.dat b/src/pal/tests/palsuite/c_runtime/fprintf/test12/testinfo.dat
new file mode 100644
index 0000000000..4b44cfc313
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fprintf/test12/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = fprintf
+Name = Positive Test for fprintf
+TYPE = DEFAULT
+EXE1 = test12
+Description
+= Tests the (lowercase) hexadecimal specifier (%x).
+= This test is modeled after the fprintf series.
diff --git a/src/pal/tests/palsuite/c_runtime/fprintf/test13/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/fprintf/test13/CMakeLists.txt
new file mode 100644
index 0000000000..c6eb0f9075
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fprintf/test13/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test13.c
+)
+
+add_executable(paltest_fprintf_test13
+ ${SOURCES}
+)
+
+add_dependencies(paltest_fprintf_test13 coreclrpal)
+
+target_link_libraries(paltest_fprintf_test13
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/fprintf/test13/test13.c b/src/pal/tests/palsuite/c_runtime/fprintf/test13/test13.c
new file mode 100644
index 0000000000..e171aeacce
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fprintf/test13/test13.c
@@ -0,0 +1,50 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test13.c (fprintf)
+**
+** Purpose: Tests the (uppercase) hexadecimal specifier (%X).
+** This test is modeled after the fprintf series.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+#include "../fprintf.h"
+
+/*
+ * Depends on memcmp, strlen, fopen, fseek and fgets.
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ int neg = -42;
+ int pos = 0x1234AB;
+ INT64 l = I64(0x1234567887654321);
+
+ if (PAL_Initialize(argc, argv) != 0)
+ return(FAIL);
+
+ DoNumTest("foo %X", pos, "foo 1234AB");
+ DoNumTest("foo %lX", pos, "foo 1234AB");
+ DoNumTest("foo %hX", pos, "foo 34AB");
+ DoNumTest("foo %LX", pos, "foo 1234AB");
+ DoI64Test("foo %I64X", l, "0x1234567887654321",
+ "foo 1234567887654321", "foo 0x1234567887654321");
+ DoNumTest("foo %7X", pos, "foo 1234AB");
+ DoNumTest("foo %-7X", pos, "foo 1234AB ");
+ DoNumTest("foo %.1X", pos, "foo 1234AB");
+ DoNumTest("foo %.7X", pos, "foo 01234AB");
+ DoNumTest("foo %07X", pos, "foo 01234AB");
+ DoNumTest("foo %#X", pos, "foo 0X1234AB");
+ DoNumTest("foo %+X", pos, "foo 1234AB");
+ DoNumTest("foo % X", pos, "foo 1234AB");
+ DoNumTest("foo %+X", neg, "foo FFFFFFD6");
+ DoNumTest("foo % X", neg, "foo FFFFFFD6");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/fprintf/test13/testinfo.dat b/src/pal/tests/palsuite/c_runtime/fprintf/test13/testinfo.dat
new file mode 100644
index 0000000000..ae983ec78a
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fprintf/test13/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = fprintf
+Name = Positive Test for fprintf
+TYPE = DEFAULT
+EXE1 = test13
+Description
+= Tests the (uppercase) hexadecimal specifier (%X).
+= This test is modeled after the fprintf series.
diff --git a/src/pal/tests/palsuite/c_runtime/fprintf/test14/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/fprintf/test14/CMakeLists.txt
new file mode 100644
index 0000000000..6bb281bc62
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fprintf/test14/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test14.c
+)
+
+add_executable(paltest_fprintf_test14
+ ${SOURCES}
+)
+
+add_dependencies(paltest_fprintf_test14 coreclrpal)
+
+target_link_libraries(paltest_fprintf_test14
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/fprintf/test14/test14.c b/src/pal/tests/palsuite/c_runtime/fprintf/test14/test14.c
new file mode 100644
index 0000000000..5d7d77387d
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fprintf/test14/test14.c
@@ -0,0 +1,49 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test14.c (fprintf)
+**
+** Purpose: Tests the lowercase exponential
+** notation double specifier (%e).
+** This test is modeled after the fprintf series.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+#include "../fprintf.h"
+
+/*
+ * Depends on memcmp, strlen, fopen, fseek and fgets.
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ double val = 256.0;
+ double neg = -256.0;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ return(FAIL);
+
+ DoDoubleTest("foo %e", val, "foo 2.560000e+002", "foo 2.560000e+02");
+ DoDoubleTest("foo %le", val, "foo 2.560000e+002", "foo 2.560000e+02");
+ DoDoubleTest("foo %he", val, "foo 2.560000e+002", "foo 2.560000e+02");
+ DoDoubleTest("foo %Le", val, "foo 2.560000e+002", "foo 2.560000e+02");
+ DoDoubleTest("foo %I64e", val, "foo 2.560000e+002", "foo 2.560000e+02");
+ DoDoubleTest("foo %14e", val, "foo 2.560000e+002", "foo 2.560000e+02");
+ DoDoubleTest("foo %-14e", val, "foo 2.560000e+002 ", "foo 2.560000e+02 ");
+ DoDoubleTest("foo %.1e", val, "foo 2.6e+002", "foo 2.6e+02");
+ DoDoubleTest("foo %.8e", val, "foo 2.56000000e+002", "foo 2.56000000e+02");
+ DoDoubleTest("foo %014e", val, "foo 02.560000e+002", "foo 002.560000e+02");
+ DoDoubleTest("foo %#e", val, "foo 2.560000e+002", "foo 2.560000e+02");
+ DoDoubleTest("foo %+e", val, "foo +2.560000e+002", "foo +2.560000e+02");
+ DoDoubleTest("foo % e", val, "foo 2.560000e+002", "foo 2.560000e+02");
+ DoDoubleTest("foo %+e", neg, "foo -2.560000e+002", "foo -2.560000e+02");
+ DoDoubleTest("foo % e", neg, "foo -2.560000e+002", "foo -2.560000e+02");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/fprintf/test14/testinfo.dat b/src/pal/tests/palsuite/c_runtime/fprintf/test14/testinfo.dat
new file mode 100644
index 0000000000..f0a843f480
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fprintf/test14/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = fprintf
+Name = Positive Test for fprintf
+TYPE = DEFAULT
+EXE1 = test14
+Description
+= Tests the lowercase exponential
+= notation double specifier (%e).
+= This test is modeled after the fprintf series.
diff --git a/src/pal/tests/palsuite/c_runtime/fprintf/test15/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/fprintf/test15/CMakeLists.txt
new file mode 100644
index 0000000000..ce1a8b6111
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fprintf/test15/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test15.c
+)
+
+add_executable(paltest_fprintf_test15
+ ${SOURCES}
+)
+
+add_dependencies(paltest_fprintf_test15 coreclrpal)
+
+target_link_libraries(paltest_fprintf_test15
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/fprintf/test15/test15.c b/src/pal/tests/palsuite/c_runtime/fprintf/test15/test15.c
new file mode 100644
index 0000000000..d024bdbd8a
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fprintf/test15/test15.c
@@ -0,0 +1,49 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test15.c (fprintf)
+**
+** Purpose: Tests the uppercase exponential
+** notation double specifier (%E).
+** This test is modeled after the fprintf series.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+#include "../fprintf.h"
+
+/*
+ * Depends on memcmp, strlen, fopen, fseek and fgets.
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ double val = 256.0;
+ double neg = -256.0;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ return(FAIL);
+
+ DoDoubleTest("foo %E", val, "foo 2.560000E+002", "foo 2.560000E+02");
+ DoDoubleTest("foo %lE", val, "foo 2.560000E+002", "foo 2.560000E+02");
+ DoDoubleTest("foo %hE", val, "foo 2.560000E+002", "foo 2.560000E+02");
+ DoDoubleTest("foo %LE", val, "foo 2.560000E+002", "foo 2.560000E+02");
+ DoDoubleTest("foo %I64E", val, "foo 2.560000E+002", "foo 2.560000E+02");
+ DoDoubleTest("foo %14E", val, "foo 2.560000E+002", "foo 2.560000E+02");
+ DoDoubleTest("foo %-14E", val, "foo 2.560000E+002 ", "foo 2.560000E+02 ");
+ DoDoubleTest("foo %.1E", val, "foo 2.6E+002", "foo 2.6E+02");
+ DoDoubleTest("foo %.8E", val, "foo 2.56000000E+002", "foo 2.56000000E+02");
+ DoDoubleTest("foo %014E", val, "foo 02.560000E+002", "foo 002.560000E+02");
+ DoDoubleTest("foo %#E", val, "foo 2.560000E+002", "foo 2.560000E+02");
+ DoDoubleTest("foo %+E", val, "foo +2.560000E+002", "foo +2.560000E+02");
+ DoDoubleTest("foo % E", val, "foo 2.560000E+002", "foo 2.560000E+02");
+ DoDoubleTest("foo %+E", neg, "foo -2.560000E+002", "foo -2.560000E+02");
+ DoDoubleTest("foo % E", neg, "foo -2.560000E+002", "foo -2.560000E+02");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/fprintf/test15/testinfo.dat b/src/pal/tests/palsuite/c_runtime/fprintf/test15/testinfo.dat
new file mode 100644
index 0000000000..fedabca3c6
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fprintf/test15/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = fprintf
+Name = Positive Test for fprintf
+TYPE = DEFAULT
+EXE1 = test15
+Description
+= Tests the uppercase exponential
+= notation double specifier (%E).
+= This test is modeled after the fprintf series.
diff --git a/src/pal/tests/palsuite/c_runtime/fprintf/test16/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/fprintf/test16/CMakeLists.txt
new file mode 100644
index 0000000000..011cd13fb1
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fprintf/test16/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test16.c
+)
+
+add_executable(paltest_fprintf_test16
+ ${SOURCES}
+)
+
+add_dependencies(paltest_fprintf_test16 coreclrpal)
+
+target_link_libraries(paltest_fprintf_test16
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/fprintf/test16/test16.c b/src/pal/tests/palsuite/c_runtime/fprintf/test16/test16.c
new file mode 100644
index 0000000000..079faeaf59
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fprintf/test16/test16.c
@@ -0,0 +1,48 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test16.c (fprintf)
+**
+** Purpose: Tests the decimal notation double specifier (%f).
+** This test is modeled after the fprintf series.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+#include "../fprintf.h"
+
+/*
+ * Depends on memcmp, strlen, fopen, fseek and fgets.
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ double val = 2560.001;
+ double neg = -2560.001;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ return(FAIL);
+
+ DoDoubleTest("foo %f", val, "foo 2560.001000", "foo 2560.001000");
+ DoDoubleTest("foo %lf", val, "foo 2560.001000", "foo 2560.001000");
+ DoDoubleTest("foo %hf", val, "foo 2560.001000", "foo 2560.001000");
+ DoDoubleTest("foo %Lf", val, "foo 2560.001000", "foo 2560.001000");
+ DoDoubleTest("foo %I64f", val, "foo 2560.001000", "foo 2560.001000");
+ DoDoubleTest("foo %12f", val, "foo 2560.001000", "foo 2560.001000");
+ DoDoubleTest("foo %-12f", val, "foo 2560.001000 ", "foo 2560.001000 ");
+ DoDoubleTest("foo %.1f", val, "foo 2560.0", "foo 2560.0");
+ DoDoubleTest("foo %.8f", val, "foo 2560.00100000", "foo 2560.00100000");
+ DoDoubleTest("foo %012f", val, "foo 02560.001000", "foo 02560.001000");
+ DoDoubleTest("foo %#f", val, "foo 2560.001000", "foo 2560.001000");
+ DoDoubleTest("foo %+f", val, "foo +2560.001000", "foo +2560.001000");
+ DoDoubleTest("foo % f", val, "foo 2560.001000", "foo 2560.001000");
+ DoDoubleTest("foo %+f", neg, "foo -2560.001000", "foo -2560.001000");
+ DoDoubleTest("foo % f", neg, "foo -2560.001000", "foo -2560.001000");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/fprintf/test16/testinfo.dat b/src/pal/tests/palsuite/c_runtime/fprintf/test16/testinfo.dat
new file mode 100644
index 0000000000..ef93c7c05d
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fprintf/test16/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = fprintf
+Name = Positive Test for fprintf
+TYPE = DEFAULT
+EXE1 = test16
+Description
+= Tests the decimal notation double specifier (%f).
+= This test is modeled after the fprintf series.
diff --git a/src/pal/tests/palsuite/c_runtime/fprintf/test17/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/fprintf/test17/CMakeLists.txt
new file mode 100644
index 0000000000..4516f4b769
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fprintf/test17/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test17.c
+)
+
+add_executable(paltest_fprintf_test17
+ ${SOURCES}
+)
+
+add_dependencies(paltest_fprintf_test17 coreclrpal)
+
+target_link_libraries(paltest_fprintf_test17
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/fprintf/test17/test17.c b/src/pal/tests/palsuite/c_runtime/fprintf/test17/test17.c
new file mode 100644
index 0000000000..7bd817d7db
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fprintf/test17/test17.c
@@ -0,0 +1,49 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test17.c (fprintf)
+**
+** Purpose: Tests the lowercase shorthand notation double specifier (%g).
+** This test is modeled after the fprintf series.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+#include "../fprintf.h"
+
+/*
+ * Depends on memcmp, strlen, fopen, fseek and fgets.
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ double val = 2560.001;
+ double neg = -2560.001;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ return(FAIL);
+
+ DoDoubleTest("foo %g", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %lg", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %hg", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %Lg", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %I64g", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %5g", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %-5g", val, "foo 2560 ", "foo 2560 ");
+ DoDoubleTest("foo %.1g", val, "foo 3e+003", "foo 3e+03");
+ DoDoubleTest("foo %.2g", val, "foo 2.6e+003", "foo 2.6e+03");
+ DoDoubleTest("foo %.12g", val, "foo 2560.001", "foo 2560.001");
+ DoDoubleTest("foo %06g", val, "foo 002560", "foo 002560");
+ DoDoubleTest("foo %#g", val, "foo 2560.00", "foo 2560.00");
+ DoDoubleTest("foo %+g", val, "foo +2560", "foo +2560");
+ DoDoubleTest("foo % g", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %+g", neg, "foo -2560", "foo -2560");
+ DoDoubleTest("foo % g", neg, "foo -2560", "foo -2560");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/fprintf/test17/testinfo.dat b/src/pal/tests/palsuite/c_runtime/fprintf/test17/testinfo.dat
new file mode 100644
index 0000000000..420703c668
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fprintf/test17/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = fprintf
+Name = Positive Test for fprintf
+TYPE = DEFAULT
+EXE1 = test17
+Description
+= Tests the lowercase shorthand notation double specifier (%g).
+= This test is modeled after the fprintf series.
diff --git a/src/pal/tests/palsuite/c_runtime/fprintf/test18/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/fprintf/test18/CMakeLists.txt
new file mode 100644
index 0000000000..fc035020ca
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fprintf/test18/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test18.c
+)
+
+add_executable(paltest_fprintf_test18
+ ${SOURCES}
+)
+
+add_dependencies(paltest_fprintf_test18 coreclrpal)
+
+target_link_libraries(paltest_fprintf_test18
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/fprintf/test18/test18.c b/src/pal/tests/palsuite/c_runtime/fprintf/test18/test18.c
new file mode 100644
index 0000000000..6582c41e0f
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fprintf/test18/test18.c
@@ -0,0 +1,49 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test18.c (fprintf)
+**
+** Purpose: Tests the uppercase shorthand notation double specifier (%G).
+** This test is modeled after the fprintf series.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+#include "../fprintf.h"
+
+/*
+ * Depends on memcmp, strlen, fopen, fseek and fgets.
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ double val = 2560.001;
+ double neg = -2560.001;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ return(FAIL);
+
+ DoDoubleTest("foo %G", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %lG", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %hG", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %LG", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %I64G", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %5G", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %-5G", val, "foo 2560 ", "foo 2560 ");
+ DoDoubleTest("foo %.1G", val, "foo 3E+003", "foo 3E+03");
+ DoDoubleTest("foo %.2G", val, "foo 2.6E+003", "foo 2.6E+03");
+ DoDoubleTest("foo %.12G", val, "foo 2560.001", "foo 2560.001");
+ DoDoubleTest("foo %06G", val, "foo 002560", "foo 002560");
+ DoDoubleTest("foo %#G", val, "foo 2560.00", "foo 2560.00");
+ DoDoubleTest("foo %+G", val, "foo +2560", "foo +2560");
+ DoDoubleTest("foo % G", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %+G", neg, "foo -2560", "foo -2560");
+ DoDoubleTest("foo % G", neg, "foo -2560", "foo -2560");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/fprintf/test18/testinfo.dat b/src/pal/tests/palsuite/c_runtime/fprintf/test18/testinfo.dat
new file mode 100644
index 0000000000..129febec27
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fprintf/test18/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = fprintf
+Name = Positive Test for fprintf
+TYPE = DEFAULT
+EXE1 = test18
+Description
+= Tests the uppercase shorthand notation double specifier (%G).
+= This test is modeled after the fprintf series.
diff --git a/src/pal/tests/palsuite/c_runtime/fprintf/test19/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/fprintf/test19/CMakeLists.txt
new file mode 100644
index 0000000000..3781b426f2
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fprintf/test19/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test19.c
+)
+
+add_executable(paltest_fprintf_test19
+ ${SOURCES}
+)
+
+add_dependencies(paltest_fprintf_test19 coreclrpal)
+
+target_link_libraries(paltest_fprintf_test19
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/fprintf/test19/test19.c b/src/pal/tests/palsuite/c_runtime/fprintf/test19/test19.c
new file mode 100644
index 0000000000..9d9a28c325
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fprintf/test19/test19.c
@@ -0,0 +1,153 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test19.c (fprintf)
+**
+** Purpose: Tests the variable length precision argument.
+** This test is modeled after the fprintf series.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+#include "../fprintf.h"
+
+/*
+ * Depends on memcmp, strlen, fopen, fseek and fgets.
+ */
+
+#define DOTEST(a,b,c,d,e,f) DoTest(a,b,(void*)c,d,e,f)
+
+void DoTest(char *formatstr, int precision, void *param,
+ char *paramstr, char *checkstr1, char *checkstr2)
+{
+ FILE *fp;
+ char buf[256];
+
+ if ((fp = fopen("testfile.txt", "w+")) == NULL )
+ {
+ Fail("ERROR: fopen failed to create testfile\n");
+ }
+
+ if ((fprintf(fp, formatstr, precision, param)) < 0)
+ {
+ Fail("ERROR: fprintf failed\n");
+ }
+
+ if ((fseek(fp, 0, SEEK_SET)) != 0)
+ {
+ Fail("ERROR: fseek failed\n");
+ }
+
+ if ((fgets(buf, 100, fp)) == NULL)
+ {
+ Fail("ERROR: fseek failed\n");
+ }
+
+ if (memcmp(buf, checkstr1, strlen(buf) + 1) != 0 &&
+ memcmp(buf, checkstr2, strlen(buf) + 1) != 0)
+ {
+ Fail("ERROR: failed to insert %s into \"%s\" with precision %d\n"
+ "Expected \"%s\" or \"%s\", got \"%s\".\n", paramstr, formatstr,
+ precision,
+ checkstr1, checkstr2, buf);
+ }
+
+ if ((fclose( fp )) != 0)
+
+ {
+ Fail("ERROR: fclose failed to close \"testfile.txt\"\n");
+ }
+
+}
+
+void DoublePrecTest(char *formatstr, int precision,
+ double param, char *checkstr1, char *checkstr2)
+{
+ FILE *fp;
+ char buf[256];
+
+ if ((fp = fopen("testfile.txt", "w+")) == NULL )
+ {
+ Fail("ERROR: fopen failed to create testfile\n");
+ }
+
+ if ((fprintf(fp, formatstr, precision, param)) < 0)
+ {
+ Fail("ERROR: fprintf failed\n");
+ }
+
+ if ((fseek(fp, 0, SEEK_SET)) != 0)
+ {
+ Fail("ERROR: fseek failed\n");
+ }
+
+ if ((fgets(buf, 100, fp)) == NULL)
+ {
+ Fail("ERROR: fseek failed\n");
+ }
+
+ if (memcmp(buf, checkstr1, strlen(buf) + 1) != 0 &&
+ memcmp(buf, checkstr2, strlen(buf) + 1) != 0)
+ {
+ Fail("ERROR: failed to insert %f into \"%s\" with precision %d\n"
+ "Expected \"%s\" or \"%s\", got \"%s\".\n",
+ param, formatstr, precision, checkstr1, checkstr2, buf);
+ }
+
+ if ((fclose( fp )) != 0)
+ {
+ Fail("ERROR: fclose failed to close \"testfile.txt\"\n");
+ }
+
+}
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ if (PAL_Initialize(argc, argv) != 0)
+ return(FAIL);
+
+ DOTEST("%.*s", 2, "bar", "bar", "ba", "ba");
+ DOTEST("%.*S", 2, convert("bar"), "bar", "ba", "ba");
+
+ //DOTEST("%.*n", 4, 2, "2", "0002");
+ DOTEST("%.*c", 0, 'a', "a", "a", "a");
+ DOTEST("%.*c", 4, 'a', "a", "a", "a");
+ DOTEST("%.*C", 0, (WCHAR)'a', "a", "a", "a");
+ DOTEST("%.*C", 4, (WCHAR)'a', "a", "a", "a");
+ DOTEST("%.*d", 1, 42, "42", "42", "42");
+ DOTEST("%.*d", 3, 42, "42", "042", "042");
+ DOTEST("%.*i", 1, 42, "42", "42", "42");
+ DOTEST("%.*i", 3, 42, "42", "042", "042");
+ DOTEST("%.*o", 1, 42, "42", "52", "52");
+ DOTEST("%.*o", 3, 42, "42", "052", "052");
+ DOTEST("%.*u", 1, 42, "42", "42", "42");
+ DOTEST("%.*u", 3, 42, "42", "042", "042");
+ DOTEST("%.*x", 1, 0x42, "0x42", "42", "42");
+ DOTEST("%.*x", 3, 0x42, "0x42", "042", "042");
+ DOTEST("%.*X", 1, 0x42, "0x42", "42", "42");
+ DOTEST("%.*X", 3, 0x42, "0x42", "042", "042");
+
+
+ DoublePrecTest("%.*e", 1, 2.01, "2.0e+000", "2.0e+00");
+ DoublePrecTest("%.*e", 3, 2.01, "2.010e+000", "2.010e+00");
+ DoublePrecTest("%.*E", 1, 2.01, "2.0E+000", "2.0E+00");
+ DoublePrecTest("%.*E", 3, 2.01, "2.010E+000", "2.010E+00");
+ DoublePrecTest("%.*f", 1, 2.01, "2.0", "2.0");
+ DoublePrecTest("%.*f", 3, 2.01, "2.010", "2.010");
+ DoublePrecTest("%.*g", 1, 256.01, "3e+002", "3e+02");
+ DoublePrecTest("%.*g", 3, 256.01, "256", "256");
+ DoublePrecTest("%.*g", 4, 256.01, "256", "256");
+ DoublePrecTest("%.*g", 6, 256.01, "256.01", "256.01");
+ DoublePrecTest("%.*G", 1, 256.01, "3E+002", "3E+02");
+ DoublePrecTest("%.*G", 3, 256.01, "256", "256");
+ DoublePrecTest("%.*G", 4, 256.01, "256", "256");
+ DoublePrecTest("%.*G", 6, 256.01, "256.01", "256.01");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/fprintf/test19/testinfo.dat b/src/pal/tests/palsuite/c_runtime/fprintf/test19/testinfo.dat
new file mode 100644
index 0000000000..25025b920a
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fprintf/test19/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = fprintf
+Name = Positive Test for fprintf
+TYPE = DEFAULT
+EXE1 = test19
+Description
+= Tests the variable length precision argument.
+= This test is modeled after the fprintf series.
diff --git a/src/pal/tests/palsuite/c_runtime/fprintf/test2/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/fprintf/test2/CMakeLists.txt
new file mode 100644
index 0000000000..0ef44b6b7d
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fprintf/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test2.c
+)
+
+add_executable(paltest_fprintf_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_fprintf_test2 coreclrpal)
+
+target_link_libraries(paltest_fprintf_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/fprintf/test2/test2.c b/src/pal/tests/palsuite/c_runtime/fprintf/test2/test2.c
new file mode 100644
index 0000000000..1ed7f3fd23
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fprintf/test2/test2.c
@@ -0,0 +1,43 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test2.c (fprintf)
+**
+** Purpose: Tests the string specifier (%s).
+** This test is modeled after the fprintf series.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+#include "../fprintf.h"
+
+/*
+ * Depends on memcmp, strlen, fopen, fseek and fgets.
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ if (PAL_Initialize(argc, argv) != 0)
+ return(FAIL);
+
+ DoStrTest("foo %s", "bar", "foo bar");
+ DoStrTest("foo %hs", "bar", "foo bar");
+ DoWStrTest("foo %ls", convert("bar"), "foo bar");
+ DoWStrTest("foo %ws", convert("bar"), "foo bar");
+ DoStrTest("foo %Ls", "bar", "foo bar");
+ DoStrTest("foo %I64s", "bar", "foo bar");
+ DoStrTest("foo %5s", "bar", "foo bar");
+ DoStrTest("foo %.2s", "bar", "foo ba");
+ DoStrTest("foo %5.2s", "bar", "foo ba");
+ DoStrTest("foo %-5s", "bar", "foo bar ");
+ DoStrTest("foo %05s", "bar", "foo 00bar");
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/fprintf/test2/testinfo.dat b/src/pal/tests/palsuite/c_runtime/fprintf/test2/testinfo.dat
new file mode 100644
index 0000000000..d4c7dbff43
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fprintf/test2/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = fprintf
+Name = Positive Test for fprintf
+TYPE = DEFAULT
+EXE1 = test2
+Description
+= Tests the string specifier (%s).
+= This test is modeled after the fprintf series.
diff --git a/src/pal/tests/palsuite/c_runtime/fprintf/test3/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/fprintf/test3/CMakeLists.txt
new file mode 100644
index 0000000000..adfd36fce7
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fprintf/test3/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test3.c
+)
+
+add_executable(paltest_fprintf_test3
+ ${SOURCES}
+)
+
+add_dependencies(paltest_fprintf_test3 coreclrpal)
+
+target_link_libraries(paltest_fprintf_test3
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/fprintf/test3/test3.c b/src/pal/tests/palsuite/c_runtime/fprintf/test3/test3.c
new file mode 100644
index 0000000000..6185135581
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fprintf/test3/test3.c
@@ -0,0 +1,43 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test3.c (fprintf)
+**
+** Purpose: Tests the wide string specifier (%S).
+** This test is modeled after the fprintf series.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+#include "../fprintf.h"
+
+/*
+ * Depends on memcmp, strlen, fopen, fseek and fgets.
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ if (PAL_Initialize(argc, argv) != 0)
+ return(FAIL);
+
+ DoWStrTest("foo %S", convert("bar"), "foo bar");
+ DoStrTest("foo %hS", "bar", "foo bar");
+ DoWStrTest("foo %lS", convert("bar"), "foo bar");
+ DoWStrTest("foo %wS", convert("bar"), "foo bar");
+ DoWStrTest("foo %LS", convert("bar"), "foo bar");
+ DoWStrTest("foo %I64S", convert("bar"), "foo bar");
+ DoWStrTest("foo %5S", convert("bar"), "foo bar");
+ DoWStrTest("foo %.2S", convert("bar"), "foo ba");
+ DoWStrTest("foo %5.2S", convert("bar"), "foo ba");
+ DoWStrTest("foo %-5S", convert("bar"), "foo bar ");
+ DoWStrTest("foo %05S", convert("bar"), "foo 00bar");
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/fprintf/test3/testinfo.dat b/src/pal/tests/palsuite/c_runtime/fprintf/test3/testinfo.dat
new file mode 100644
index 0000000000..88a1b03a7f
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fprintf/test3/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = fprintf
+Name = Positive Test for fprintf
+TYPE = DEFAULT
+EXE1 = test3
+Description
+= Tests the wide string specifier (%S).
+= This test is modeled after the fprintf series.
diff --git a/src/pal/tests/palsuite/c_runtime/fprintf/test4/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/fprintf/test4/CMakeLists.txt
new file mode 100644
index 0000000000..7d471b1b9c
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fprintf/test4/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test4.c
+)
+
+add_executable(paltest_fprintf_test4
+ ${SOURCES}
+)
+
+add_dependencies(paltest_fprintf_test4 coreclrpal)
+
+target_link_libraries(paltest_fprintf_test4
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/fprintf/test4/test4.c b/src/pal/tests/palsuite/c_runtime/fprintf/test4/test4.c
new file mode 100644
index 0000000000..51ec1f099c
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fprintf/test4/test4.c
@@ -0,0 +1,110 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test4.c (fprintf)
+**
+** Purpose: Tests the pointer specifier (%p).
+** This test is modeled after the fprintf series.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+#include "../fprintf.h"
+
+/*
+ * Depends on memcmp, strlen, fopen, fseek and fgets.
+ */
+
+static void DoTest(char *formatstr, void* param, char* paramstr,
+ char *checkstr1, char *checkstr2)
+{
+ FILE *fp;
+ char buf[256] = { 0 };
+
+ if ((fp = fopen("testfile.txt", "w+")) == NULL )
+ {
+ Fail("ERROR: fopen failed to create testfile\n");
+ }
+
+ if ((fprintf(fp, formatstr, param)) < 0)
+ {
+ Fail("ERROR: fprintf failed\n");
+ }
+
+ if ((fseek(fp, 0, SEEK_SET)) != 0)
+ {
+ Fail("ERROR: fseek failed\n");
+ }
+
+ if ((fgets(buf, 100, fp)) == NULL)
+ {
+ Fail("ERROR: fseek failed\n");
+ }
+
+ if (memcmp(buf, checkstr1, strlen(buf) + 1) != 0 &&
+ memcmp(buf, checkstr2, strlen(buf) + 1) != 0 )
+ {
+ Fail("ERROR: failed to insert %s into \"%s\"\n"
+ "Expected \"%s\" or \"%s\" got \"%s\".\n",
+ paramstr, formatstr, checkstr1, checkstr2, buf);
+ }
+
+ if ((fclose( fp )) != 0)
+
+ {
+
+ Fail("ERROR: fclose failed to close \"testfile.txt\"\n");
+
+ }
+}
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ void *ptr = (void*) 0x123456;
+ INT64 lptr = I64(0x1234567887654321);
+
+ if (PAL_Initialize(argc, argv) != 0)
+ return(FAIL);
+
+
+/*
+** Run only on 64 bit platforms
+*/
+#if defined(BIT64) && defined(PLATFORM_UNIX)
+ Trace("Testing for 64 Bit Platforms \n");
+ DoTest("%p", NULL, "NULL", "0000000000000000", "0x0");
+ DoTest("%p", ptr, "pointer to 0x123456", "0000000000123456", "0x123456");
+ DoTest("%17p", ptr, "pointer to 0x123456", " 0000000000123456", " 0x123456");
+ DoTest("%17p", ptr, "pointer to 0x123456", " 0000000000123456", "0x0123456");
+ DoTest("%-17p", ptr, "pointer to 0x123456", "0000000000123456 ", "0x123456 ");
+ DoTest("%+p", ptr, "pointer to 0x123456", "0000000000123456", "0x123456");
+ DoTest("%#p", ptr, "pointer to 0x123456", "0X0000000000123456", "0x123456");
+ DoTest("%lp", ptr, "pointer to 0x123456", "00123456", "0x123456");
+ DoTest("%hp", ptr, "pointer to 0x123456", "00003456", "0x3456");
+ DoTest("%Lp", ptr, "pointer to 0x123456", "00123456", "0x123456");
+ DoI64Test("%I64p", lptr, "pointer to 0x1234567887654321",
+ "1234567887654321", "0x1234567887654321");
+#else
+ Trace("Testing for Non 64 Bit Platforms \n");
+ DoTest("%p", NULL, "NULL", "00000000", "0x0");
+ DoTest("%p", ptr, "pointer to 0x123456", "00123456", "0x123456");
+ DoTest("%9p", ptr, "pointer to 0x123456", " 00123456", " 0x123456");
+ DoTest("%09p", ptr, "pointer to 0x123456", " 00123456", "0x0123456");
+ DoTest("%-9p", ptr, "pointer to 0x123456", "00123456 ", "0x123456 ");
+ DoTest("%+p", ptr, "pointer to 0x123456", "00123456", "0x123456");
+ DoTest("%#p", ptr, "pointer to 0x123456", "0X00123456", "0x123456");
+ DoTest("%lp", ptr, "pointer to 0x123456", "00123456", "0x123456");
+ DoTest("%hp", ptr, "pointer to 0x123456", "00003456", "0x3456");
+ DoTest("%Lp", ptr, "pointer to 0x123456", "00123456", "0x123456");
+ DoI64Test("%I64p", lptr, "pointer to 0x1234567887654321",
+ "1234567887654321", "0x1234567887654321");
+#endif
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/fprintf/test4/testinfo.dat b/src/pal/tests/palsuite/c_runtime/fprintf/test4/testinfo.dat
new file mode 100644
index 0000000000..5f373ac230
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fprintf/test4/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = fprintf
+Name = Positive Test for fprintf
+TYPE = DEFAULT
+EXE1 = test4
+Description
+= Tests the pointer specifier (%p).
+= This test is modeled after the fprintf series.
diff --git a/src/pal/tests/palsuite/c_runtime/fprintf/test5/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/fprintf/test5/CMakeLists.txt
new file mode 100644
index 0000000000..1e3a568513
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fprintf/test5/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test5.c
+)
+
+add_executable(paltest_fprintf_test5
+ ${SOURCES}
+)
+
+add_dependencies(paltest_fprintf_test5 coreclrpal)
+
+target_link_libraries(paltest_fprintf_test5
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/fprintf/test5/test5.c b/src/pal/tests/palsuite/c_runtime/fprintf/test5/test5.c
new file mode 100644
index 0000000000..c53e3f45b4
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fprintf/test5/test5.c
@@ -0,0 +1,131 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test5.c (fprintf)
+**
+** Purpose: Tests the count specifier (%n).
+** This test is modeled after the fprintf series.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+#include "../fprintf.h"
+
+/*
+ * Depends on memcmp, strlen, fopen, fseek and fgets.
+ */
+
+static void DoTest(char *formatstr, int param, char *checkstr)
+{
+ FILE *fp;
+ char buf[256] = { 0 };
+ int n = -1;
+
+ if ((fp = fopen("testfile.txt", "w+")) == NULL )
+ {
+ Fail("ERROR: fopen failed to create testfile\n");
+ }
+
+ if ((fprintf(fp, formatstr, &n)) < 0)
+ {
+ Fail("ERROR: fprintf failed\n");
+ }
+
+ if ((fseek(fp, 0, SEEK_SET)) != 0)
+ {
+ Fail("ERROR: fseek failed\n");
+ }
+
+ if ((fgets(buf, 100, fp)) == NULL)
+ {
+ Fail("ERROR: fseek failed\n");
+ }
+
+ if (n != param)
+ {
+ Fail("ERROR: Expected count parameter to resolve to %d, got %X\n",
+ param, n);
+ }
+
+ if (memcmp(buf, checkstr, strlen(buf) + 1) != 0)
+ {
+ Fail("ERROR: Expected \"%s\" got \"%s\".\n", checkstr, buf);
+ }
+
+
+ if ((fclose( fp )) != 0)
+
+ {
+
+ Fail("ERROR: fclose failed to close \"testfile.txt\"\n");
+
+ }
+}
+
+static void DoShortTest(char *formatstr, int param, char *checkstr)
+{
+ FILE *fp;
+ char buf[256] = { 0 };
+ short int n = -1;
+
+ if ((fp = fopen("testfile.txt", "w+")) == NULL )
+ {
+ Fail("ERROR: fopen failed to create testfile\n");
+ }
+
+ if ((fprintf(fp, formatstr, &n)) < 0)
+ {
+ Fail("ERROR: fprintf failed\n");
+ }
+
+ if ((fseek(fp, 0, SEEK_SET)) != 0)
+ {
+ Fail("ERROR: fseek failed\n");
+ }
+
+ if ((fgets(buf, 100, fp)) == NULL)
+ {
+ Fail("ERROR: fseek failed\n");
+ }
+
+ if (n != param)
+ {
+ Fail("ERROR: Expected count parameter to resolve to %d, got %X\n",
+ param, n);
+ }
+
+ if (memcmp(buf, checkstr, strlen(buf) + 1) != 0)
+ {
+ Fail("ERROR: Expected \"%s\" got \"%s\".\n", checkstr, buf);
+ }
+
+ if ((fclose( fp )) != 0)
+ {
+ Fail("ERROR: fclose failed to close \"testfile.txt\"\n");
+ }
+}
+
+int __cdecl main(int argc, char *argv[])
+{
+ if (PAL_Initialize(argc, argv) != 0)
+ return(FAIL);
+
+ DoTest("foo %n bar", 4, "foo bar");
+ DoTest("foo %#n bar", 4, "foo bar");
+ DoTest("foo % n bar", 4, "foo bar");
+ DoTest("foo %+n bar", 4, "foo bar");
+ DoTest("foo %-n bar", 4, "foo bar");
+ DoTest("foo %0n bar", 4, "foo bar");
+ DoShortTest("foo %hn bar", 4, "foo bar");
+ DoTest("foo %ln bar", 4, "foo bar");
+ DoTest("foo %Ln bar", 4, "foo bar");
+ DoTest("foo %I64n bar", 4, "foo bar");
+ DoTest("foo %20.3n bar", 4, "foo bar");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/fprintf/test5/testinfo.dat b/src/pal/tests/palsuite/c_runtime/fprintf/test5/testinfo.dat
new file mode 100644
index 0000000000..b4d0e81777
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fprintf/test5/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = fprintf
+Name = Positive Test for fprintf
+TYPE = DEFAULT
+EXE1 = test5
+Description
+= Tests the count specifier (%n).
+= This test is modeled after the fprintf series.
diff --git a/src/pal/tests/palsuite/c_runtime/fprintf/test6/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/fprintf/test6/CMakeLists.txt
new file mode 100644
index 0000000000..89620dd453
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fprintf/test6/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test6.c
+)
+
+add_executable(paltest_fprintf_test6
+ ${SOURCES}
+)
+
+add_dependencies(paltest_fprintf_test6 coreclrpal)
+
+target_link_libraries(paltest_fprintf_test6
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/fprintf/test6/test6.c b/src/pal/tests/palsuite/c_runtime/fprintf/test6/test6.c
new file mode 100644
index 0000000000..0a8bc6b103
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fprintf/test6/test6.c
@@ -0,0 +1,46 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test6.c (fprintf)
+**
+** Purpose: Tests the char specifier (%c).
+** This test is modeled after the fprintf series.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+#include "../fprintf.h"
+
+/*
+ * Depends on memcmp, strlen, fopen, fseek and fgets.
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ WCHAR wc = (WCHAR) 'c';
+
+ if (PAL_Initialize(argc, argv) != 0)
+ return(FAIL);
+
+ DoCharTest("foo %c", 'b', "foo b");
+ DoCharTest("foo %hc", 'b', "foo b");
+ DoWCharTest("foo %lc", wc, "foo c");
+ DoCharTest("foo %Lc", 'b', "foo b");
+ DoCharTest("foo %I64c", 'b', "foo b");
+ DoCharTest("foo %5c", 'b', "foo b");
+ DoCharTest("foo %.0c", 'b', "foo b");
+ DoCharTest("foo %-5c", 'b', "foo b ");
+ DoCharTest("foo %05c", 'b', "foo 0000b");
+ DoCharTest("foo % c", 'b', "foo b");
+ DoCharTest("foo %#c", 'b', "foo b");
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/fprintf/test6/testinfo.dat b/src/pal/tests/palsuite/c_runtime/fprintf/test6/testinfo.dat
new file mode 100644
index 0000000000..a8a071ca21
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fprintf/test6/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = fprintf
+Name = Positive Test for fprintf
+TYPE = DEFAULT
+EXE1 = test6
+Description
+= Tests the char specifier (%c).
+= This test is modeled after the fprintf series.
diff --git a/src/pal/tests/palsuite/c_runtime/fprintf/test7/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/fprintf/test7/CMakeLists.txt
new file mode 100644
index 0000000000..3dc10dd6dc
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fprintf/test7/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test7.c
+)
+
+add_executable(paltest_fprintf_test7
+ ${SOURCES}
+)
+
+add_dependencies(paltest_fprintf_test7 coreclrpal)
+
+target_link_libraries(paltest_fprintf_test7
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/fprintf/test7/test7.c b/src/pal/tests/palsuite/c_runtime/fprintf/test7/test7.c
new file mode 100644
index 0000000000..088e328de5
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fprintf/test7/test7.c
@@ -0,0 +1,44 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test7.c (fprintf)
+**
+** Purpose: Tests the wide char specifier (%C).
+** This test is modeled after the fprintf series.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+#include "../fprintf.h"
+
+/*
+ * Depends on memcmp, strlen, fopen, fseek and fgets.
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ WCHAR wb = (WCHAR) 'b';
+
+ if (PAL_Initialize(argc, argv) != 0)
+ return(FAIL);
+
+ DoWCharTest("foo %C", wb, "foo b");
+ DoWCharTest("foo %hC", wb, "foo b");
+ DoCharTest("foo %lC", 'c', "foo c");
+ DoWCharTest("foo %LC", wb, "foo b");
+ DoWCharTest("foo %I64C", wb, "foo b");
+ DoWCharTest("foo %5C", wb, "foo b");
+ DoWCharTest("foo %.0C", wb, "foo b");
+ DoWCharTest("foo %-5C", wb, "foo b ");
+ DoWCharTest("foo %05C", wb, "foo 0000b");
+ DoWCharTest("foo % C", wb, "foo b");
+ DoWCharTest("foo %#C", wb, "foo b");
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/fprintf/test7/testinfo.dat b/src/pal/tests/palsuite/c_runtime/fprintf/test7/testinfo.dat
new file mode 100644
index 0000000000..fc12718063
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fprintf/test7/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = fprintf
+Name = Positive Test for fprintf
+TYPE = DEFAULT
+EXE1 = test7
+Description
+= Tests the wide char specifier (%C).
+= This test is modeled after the fprintf series.
diff --git a/src/pal/tests/palsuite/c_runtime/fprintf/test8/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/fprintf/test8/CMakeLists.txt
new file mode 100644
index 0000000000..f6dd984af9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fprintf/test8/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test8.c
+)
+
+add_executable(paltest_fprintf_test8
+ ${SOURCES}
+)
+
+add_dependencies(paltest_fprintf_test8 coreclrpal)
+
+target_link_libraries(paltest_fprintf_test8
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/fprintf/test8/test8.c b/src/pal/tests/palsuite/c_runtime/fprintf/test8/test8.c
new file mode 100644
index 0000000000..c781abc968
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fprintf/test8/test8.c
@@ -0,0 +1,49 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test8.c (fprintf)
+**
+** Purpose: Tests the decimal specifier (%d).
+** This test is modeled after the fprintf series.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+#include "../fprintf.h"
+
+/*
+ * Depends on memcmp, strlen, fopen, fseek and fgets.
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ int neg = -42;
+ int pos = 42;
+ INT64 l = 42;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ return(FAIL);
+
+ DoNumTest("foo %d", pos, "foo 42");
+ DoNumTest("foo %ld", 0xFFFF, "foo 65535");
+ DoNumTest("foo %hd", 0xFFFF, "foo -1");
+ DoNumTest("foo %Ld", pos, "foo 42");
+ DoI64Test("foo %I64d", l, "42", "foo 42", "foo 42");
+ DoNumTest("foo %3d", pos, "foo 42");
+ DoNumTest("foo %-3d", pos, "foo 42 ");
+ DoNumTest("foo %.1d", pos, "foo 42");
+ DoNumTest("foo %.3d", pos, "foo 042");
+ DoNumTest("foo %03d", pos, "foo 042");
+ DoNumTest("foo %#d", pos, "foo 42");
+ DoNumTest("foo %+d", pos, "foo +42");
+ DoNumTest("foo % d", pos, "foo 42");
+ DoNumTest("foo %+d", neg, "foo -42");
+ DoNumTest("foo % d", neg, "foo -42");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/fprintf/test8/testinfo.dat b/src/pal/tests/palsuite/c_runtime/fprintf/test8/testinfo.dat
new file mode 100644
index 0000000000..2609260786
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fprintf/test8/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = fprintf
+Name = Positive Test for fprintf
+TYPE = DEFAULT
+EXE1 = test8
+Description
+= Tests the decimal specifier (%d).
+= This test is modeled after the fprintf series.
diff --git a/src/pal/tests/palsuite/c_runtime/fprintf/test9/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/fprintf/test9/CMakeLists.txt
new file mode 100644
index 0000000000..62aa85e6ff
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fprintf/test9/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test9.c
+)
+
+add_executable(paltest_fprintf_test9
+ ${SOURCES}
+)
+
+add_dependencies(paltest_fprintf_test9 coreclrpal)
+
+target_link_libraries(paltest_fprintf_test9
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/fprintf/test9/test9.c b/src/pal/tests/palsuite/c_runtime/fprintf/test9/test9.c
new file mode 100644
index 0000000000..3b06daec48
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fprintf/test9/test9.c
@@ -0,0 +1,49 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test9.c (fprintf)
+**
+** Purpose: Tests the integer specifier (%i).
+** This test is modeled after the fprintf series.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+#include "../fprintf.h"
+
+/*
+ * Depends on memcmp, strlen, fopen, fseek and fgets.
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ int neg = -42;
+ int pos = 42;
+ INT64 l = 42;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ return(FAIL);
+
+ DoNumTest("foo %i", pos, "foo 42");
+ DoNumTest("foo %li", 0xFFFF, "foo 65535");
+ DoNumTest("foo %hi", 0xFFFF, "foo -1");
+ DoNumTest("foo %Li", pos, "foo 42");
+ DoI64Test("foo %I64i", l, "42", "foo 42", "foo 42");
+ DoNumTest("foo %3i", pos, "foo 42");
+ DoNumTest("foo %-3i", pos, "foo 42 ");
+ DoNumTest("foo %.1i", pos, "foo 42");
+ DoNumTest("foo %.3i", pos, "foo 042");
+ DoNumTest("foo %03i", pos, "foo 042");
+ DoNumTest("foo %#i", pos, "foo 42");
+ DoNumTest("foo %+i", pos, "foo +42");
+ DoNumTest("foo % i", pos, "foo 42");
+ DoNumTest("foo %+i", neg, "foo -42");
+ DoNumTest("foo % i", neg, "foo -42");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/fprintf/test9/testinfo.dat b/src/pal/tests/palsuite/c_runtime/fprintf/test9/testinfo.dat
new file mode 100644
index 0000000000..e502af70b2
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fprintf/test9/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = fprintf
+Name = Positive Test for fprintf
+TYPE = DEFAULT
+EXE1 = test9
+Description
+= Tests the integer specifier (%i).
+= This test is modeled after the fprintf series.
diff --git a/src/pal/tests/palsuite/c_runtime/fputs/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/fputs/CMakeLists.txt
new file mode 100644
index 0000000000..ef14ea5352
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fputs/CMakeLists.txt
@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+
diff --git a/src/pal/tests/palsuite/c_runtime/fputs/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/fputs/test1/CMakeLists.txt
new file mode 100644
index 0000000000..e4a92d5966
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fputs/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_fputs_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_fputs_test1 coreclrpal)
+
+target_link_libraries(paltest_fputs_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/fputs/test1/test1.c b/src/pal/tests/palsuite/c_runtime/fputs/test1/test1.c
new file mode 100644
index 0000000000..b90ea082e9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fputs/test1/test1.c
@@ -0,0 +1,100 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test1.c
+**
+** Purpose: Call fputs twice and write two strings to a file. Then
+** call fread on the file and check that the data which was written is what
+** we expect it to be.
+**
+
+**
+**===================================================================*/
+
+
+#include <palsuite.h>
+
+
+int __cdecl main(int argc, char **argv)
+{
+
+ FILE* TheFile;
+ char* StringOne = "FooBar";
+ char* StringTwo = "BarFoo";
+ char* CompleteString = "FooBarBarFoo";
+ char ReadBuffer[64];
+ int ret;
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ /* Open the file that we'll be working with */
+
+ TheFile = fopen("TestFile", "w+");
+
+ if(TheFile == NULL)
+ {
+ Fail("ERROR: fopen failed to open the file 'TestFile' in read/write "
+ "mode.\n");
+ }
+
+ /* Call fputs twice to write two strings to the file stream */
+
+ if(fputs(StringOne, TheFile) < 0)
+ {
+ Fail("ERROR: fputs returned a negative value when attempting to "
+ "put the string '%s' to the file.\n",StringOne);
+ }
+
+ if(fputs(StringTwo, TheFile) < 0)
+ {
+ Fail("ERROR: fputs returned a negative value when attempting to "
+ "put the string '%s' to the file.\n",StringTwo);
+ }
+
+ /* Flush the buffers */
+ if(fflush(TheFile) != 0)
+ {
+ Fail("ERROR: fflush failed to properly flush the buffers.\n");
+ }
+
+ /* Now read from the file to ensure the data was written correctly.
+ Note: We read more than what was written to make sure nothing extra
+ was written.
+ */
+
+ if(fseek(TheFile, 0, SEEK_SET) != 0)
+ {
+ Fail("ERROR: fseek failed to set the file pointer back to the start "
+ "of the file.\n");
+ }
+
+
+ if((ret = fread(ReadBuffer, 1, 20, TheFile)) != 12)
+ {
+ Fail("ERROR: fread should have returned that it read in 12 characters "
+ "from the file, but instead it returned %d.\n", ret);
+ }
+
+ ReadBuffer[ret] = '\0';
+
+ if(strcmp(ReadBuffer, CompleteString) != 0)
+ {
+ Fail("ERROR: The data read back from the file is not exactly the same "
+ "as the data that was written by fputs. The file contains '%s' "
+ "instead of '%s'.\n",ReadBuffer, CompleteString);
+ }
+
+ if(fclose(TheFile) != 0)
+ {
+ Fail("ERROR: fclose failed to close the file stream.\n");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/fputs/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/fputs/test1/testinfo.dat
new file mode 100644
index 0000000000..bdef09c60f
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fputs/test1/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = fputs
+Name = Check that fputs writes correctly to a valid stream
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Call fputs twice and write two strings to a file. Then
+= call fread on the file and check that the data which was written is what
+= we expect it to be.
diff --git a/src/pal/tests/palsuite/c_runtime/fputs/test2/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/fputs/test2/CMakeLists.txt
new file mode 100644
index 0000000000..6e939f3346
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fputs/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test2.c
+)
+
+add_executable(paltest_fputs_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_fputs_test2 coreclrpal)
+
+target_link_libraries(paltest_fputs_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/fputs/test2/test2.c b/src/pal/tests/palsuite/c_runtime/fputs/test2/test2.c
new file mode 100644
index 0000000000..b8e2f410bb
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fputs/test2/test2.c
@@ -0,0 +1,88 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test2.c
+**
+** Purpose: Check to see that fputs fails and returns EOF when called on
+** a closed file stream and a read-only file stream.
+**
+
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char **argv)
+{
+
+ FILE* TheFile;
+ char* StringOne = "FooBar";
+ int ret;
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ /* Create a file with read/write access */
+
+ TheFile = fopen("TestFile", "w+");
+
+ if(TheFile == NULL)
+ {
+ Fail("ERROR: fopen failed to open the file 'TestFile' in read/write "
+ "mode.\n");
+ }
+
+ /* Then close that file we just opened */
+
+ if(fclose(TheFile) != 0)
+ {
+ Fail("ERROR: fclose failed to close the file.\n");
+ }
+
+ /* Check that calling fputs on this closed file stream fails. */
+
+ if((ret = fputs(StringOne, TheFile)) >= 0)
+ {
+ Fail("ERROR: fputs should have failed to write to a closed "
+ "file stream, but it didn't return a negative value.\n");
+ }
+
+ if(ret != EOF)
+ {
+ Fail("ERROR: fputs should have returned EOF on an error, but instead "
+ "returned %d.\n",ret);
+ }
+
+ /* Open a file as Readonly */
+
+ TheFile = fopen("TestFile", "r");
+
+ if(TheFile == NULL)
+ {
+ Fail("ERROR: fopen failed to open the file 'TestFile' in read/write "
+ "mode.\n");
+ }
+
+ /* Check that fputs fails when trying to write to a read-only stream */
+
+ if((ret = fputs(StringOne, TheFile)) >= 0)
+ {
+ Fail("ERROR: fputs should have failed to write to a read-only "
+ "file stream, but it didn't return a negative value.\n");
+ }
+
+ if(ret != EOF)
+ {
+ Fail("ERROR: fputs should have returned EOF when writing to a "
+ "read-only filestream, but instead "
+ "returned %d.\n",ret);
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/fputs/test2/testinfo.dat b/src/pal/tests/palsuite/c_runtime/fputs/test2/testinfo.dat
new file mode 100644
index 0000000000..0e2abbdc30
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fputs/test2/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = fputs
+Name = Check that fputs returns EOF when called on closed/readonly streams
+TYPE = DEFAULT
+EXE1 = test2
+Description
+= Check to see that fputs fails and returns EOF when called on
+= a closed file stream and a read-only file stream.
diff --git a/src/pal/tests/palsuite/c_runtime/fread/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/fread/CMakeLists.txt
new file mode 100644
index 0000000000..1962ade358
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fread/CMakeLists.txt
@@ -0,0 +1,6 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+add_subdirectory(test3)
+
diff --git a/src/pal/tests/palsuite/c_runtime/fread/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/fread/test1/CMakeLists.txt
new file mode 100644
index 0000000000..a2e09579b1
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fread/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_fread_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_fread_test1 coreclrpal)
+
+target_link_libraries(paltest_fread_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/fread/test1/test1.c b/src/pal/tests/palsuite/c_runtime/fread/test1/test1.c
new file mode 100644
index 0000000000..b706b2e91c
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fread/test1/test1.c
@@ -0,0 +1,135 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test1.c
+**
+** Purpose: Tests the PAL implementation of the fread function.
+** Open a file in READ mode, and then try to read all
+** the characters, more than all the characters,
+** 0 characters and 0 sized characters and check that
+** the return values are correct.
+**
+** Depends:
+** fopen
+** fseek
+** fclose
+**
+**
+**===================================================================*/
+
+/* Note: testfile should exist in the directory with 15 characters
+ in it ... something got lost if it isn't here.
+*/
+
+/* Note: Under win32, fread() crashes when passed NULL. The test to ensure that
+ it returns 0 has been removed to reflect this.
+*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char **argv)
+{
+ const char filename[] = "testfile";
+ char buffer[128];
+ FILE * fp = NULL;
+ int result;
+
+ if (0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ /* Open a file in READ mode */
+
+ if((fp = fopen(filename, "r")) == NULL)
+ {
+ Fail("Unable to open a file for reading. Is the file "
+ "in the directory? It should be.");
+ }
+
+ /* Read 15 characters from the file. The file has exactly this many
+ in it.
+ */
+ if((result = fread(buffer,1,15,fp)) == 0)
+ {
+ Fail("ERROR: Zero characters read from the file. It should have "
+ "15 characters in it.");
+ }
+
+ if(result != 15)
+ {
+ Fail("ERROR: The fread function should have returned that it read "
+ "in 15 characters from the file. But it indicates having "
+ "read %i characters.",result);
+ }
+
+ /* Go back to the start of the file */
+
+ if(fseek(fp, 0, SEEK_SET))
+ {
+ Fail("ERROR: fseek failed, and this test depends on it.");
+ }
+
+ /* Attempt to read 17 characters, the return should still be 15 */
+
+ if((result = fread(buffer,1,17,fp)) == 0)
+ {
+ Fail("ERROR: Zero characters read from the file. It should have "
+ "15 characters in it. Though, it attempted to read 17.");
+ }
+
+ if(result != 15)
+ {
+ Fail("ERROR: The fread function should have returned that it read "
+ "in 15 characters from the file. "
+ "But it indicates having read %i characters.",result);
+ }
+
+ /* Back to the start of the file */
+
+ if(fseek(fp, 0, SEEK_SET))
+ {
+ Fail("ERROR: fseek failed, and this test depends on it.");
+ }
+
+ /* Read 0 characters and ensure the function returns 0 */
+
+ if((result = fread(buffer,1,0,fp)) != 0)
+ {
+ Fail("ERROR: The return value should be 0, as we attempted to "
+ "read 0 characters.");
+ }
+
+ /* Read characters of 0 size and ensure the return value is 0 */
+
+ if((result = fread(buffer,0,5,fp)) != 0)
+ {
+ Fail("ERROR: The return value should be 0, as we attempted to "
+ "read 0 sized data.");
+ }
+
+ /* Close the file */
+
+ if(fclose(fp))
+ {
+ Fail("ERROR: fclose failed. Test depends on it.");
+ }
+
+ /* Read 5 characters of 1 size from a closed file pointer
+ and ensure the return value is 0
+ */
+
+ if((result = fread(buffer,1,5,fp)) != 0)
+ {
+ Fail("ERROR: The return value should be 0, as we attempted to "
+ "read data from a closed file pointer.");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/fread/test1/testfile b/src/pal/tests/palsuite/c_runtime/fread/test1/testfile
new file mode 100644
index 0000000000..273c1a9ffd
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fread/test1/testfile
@@ -0,0 +1 @@
+This is a test. \ No newline at end of file
diff --git a/src/pal/tests/palsuite/c_runtime/fread/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/fread/test1/testinfo.dat
new file mode 100644
index 0000000000..0f8b860616
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fread/test1/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = fread
+Name = Positive Test for fread
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Tests the PAL implementation of the fread function.
+= Open a file in READ mode, and then try to read all the characters,
+= more than all the characters, 0 characters and 0 sized characters and
+= check that the return values are correct.
diff --git a/src/pal/tests/palsuite/c_runtime/fread/test2/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/fread/test2/CMakeLists.txt
new file mode 100644
index 0000000000..0538e0c3af
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fread/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test2.c
+)
+
+add_executable(paltest_fread_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_fread_test2 coreclrpal)
+
+target_link_libraries(paltest_fread_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/fread/test2/test2.c b/src/pal/tests/palsuite/c_runtime/fread/test2/test2.c
new file mode 100644
index 0000000000..d7262a9321
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fread/test2/test2.c
@@ -0,0 +1,143 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test2.c
+**
+** Purpose: Tests the PAL implementation of the fread function.
+** Open a file in READ mode, and then try to read all
+** the characters, more than all the characters,
+** 0 characters and 0 sized characters and check that
+** the strings read in are correct.
+**
+** Depends:
+** fopen
+** fseek
+** fclose
+** strcmp
+** memset
+**
+**
+**===================================================================*/
+
+/* Note: testfile should exist in the directory with 15 characters
+ in it ... something got lost if it isn't here.
+*/
+
+/* Note: The behaviour in win32 is to crash if a NULL pointer is passed to
+ fread, so the test to check that it returns 0 has been removed.
+*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char **argv)
+{
+ const char filename[] = "testfile";
+ char buffer[128];
+ FILE * fp = NULL;
+
+ if (0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ /* Open a file in READ mode */
+
+ if((fp = fopen(filename, "r")) == NULL)
+ {
+ Fail("Unable to open a file for reading. Is the file "
+ "in the directory? It should be.");
+ }
+
+ /* Read 15 characters from the file. The file has exactly this many
+ in it. Then check to see that the data read in is correct.
+ Note: The 'testfile' should have "This is a test." written in it.
+ */
+ memset(buffer,'\0',128);
+ fread(buffer,1,15,fp);
+
+ if(strcmp(buffer,"This is a test.") != 0)
+ {
+ Fail("ERROR: The data read in should have been "
+ "'This is a test.' but, the buffer contains '%s'.",
+ buffer);
+ }
+
+ /* Go back to the start of the file */
+
+ if(fseek(fp, 0, SEEK_SET))
+ {
+ Fail("ERROR: fseek failed, and this test depends on it.");
+ }
+
+ /* Attempt to read 17 characters. The same 15 characters should
+ be in the buffer.
+ */
+
+ memset(buffer,'\0',128);
+ fread(buffer,1,17,fp);
+
+ if(strcmp(buffer,"This is a test.") != 0)
+ {
+ Fail("ERROR: The data read in should have been "
+ "'This is a test.' but, the buffer contains '%s'.",
+ buffer);
+ }
+
+ /* Back to the start of the file */
+
+ if(fseek(fp, 0, SEEK_SET))
+ {
+ Fail("ERROR: fseek failed, and this test depends on it.");
+ }
+
+ /* Read 0 characters and ensure the buffer is empty */
+
+ memset(buffer,'\0',128);
+ fread(buffer,1,0,fp);
+
+ if(strcmp(buffer,"\0") != 0)
+ {
+ Fail("ERROR: The data read in should have been "
+ "NULL but, the buffer contains '%s'.",
+ buffer);
+ }
+
+ /* Read characters of 0 size and ensure the buffer is empty */
+
+ memset(buffer,'\0',128);
+ fread(buffer,0,5,fp);
+
+ if(strcmp(buffer,"\0") != 0)
+ {
+ Fail("ERROR: The data read in should have been "
+ "NULL but, the buffer contains '%s'.",
+ buffer);
+ }
+
+ /* Close the file */
+
+ if(fclose(fp))
+ {
+ Fail("ERROR: fclose failed. Test depends on it.");
+ }
+
+ /* Read 5 characters of 1 size from a closed file pointer
+ and ensure the buffer is empty
+ */
+ memset(buffer,'\0',128);
+ fread(buffer,1,5,fp);
+ if(strcmp(buffer,"\0") != 0)
+ {
+ Fail("ERROR: The data read in should have been "
+ "NULL but, the buffer contains '%s'.",
+ buffer);
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/fread/test2/testfile b/src/pal/tests/palsuite/c_runtime/fread/test2/testfile
new file mode 100644
index 0000000000..273c1a9ffd
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fread/test2/testfile
@@ -0,0 +1 @@
+This is a test. \ No newline at end of file
diff --git a/src/pal/tests/palsuite/c_runtime/fread/test2/testinfo.dat b/src/pal/tests/palsuite/c_runtime/fread/test2/testinfo.dat
new file mode 100644
index 0000000000..a73c0ecf9e
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fread/test2/testinfo.dat
@@ -0,0 +1,16 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = fread
+Name = Positive Test for fread
+TYPE = DEFAULT
+EXE1 = test2
+Description
+= Tests the PAL implementation of the fread function.
+= Open a file in READ mode, and then try to read all
+= the characters, more than all the characters,
+= 0 characters and 0 sized characters and check that
+= the strings read in are correct.
diff --git a/src/pal/tests/palsuite/c_runtime/fread/test3/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/fread/test3/CMakeLists.txt
new file mode 100644
index 0000000000..f3c636f3df
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fread/test3/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test3.c
+)
+
+add_executable(paltest_fread_test3
+ ${SOURCES}
+)
+
+add_dependencies(paltest_fread_test3 coreclrpal)
+
+target_link_libraries(paltest_fread_test3
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/fread/test3/test3.c b/src/pal/tests/palsuite/c_runtime/fread/test3/test3.c
new file mode 100644
index 0000000000..8c79bee582
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fread/test3/test3.c
@@ -0,0 +1,131 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test3.c
+**
+** Purpose: Tests the PAL implementation of the fread function.
+** Open a file in READ mode, then try to read from the file with
+** different 'size' params. Check to ensure the return values and
+** the text in the buffer is correct.
+**
+** Depends:
+** fopen
+** fseek
+** strcmp
+** memset
+**
+**
+**===================================================================*/
+
+/* Note: testfile should exist in the directory with 15 characters
+ in it ... something got lost if it isn't here.
+*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char **argv)
+{
+ const char filename[] = "testfile";
+ char buffer[128];
+ FILE * fp = NULL;
+ int result;
+
+ if (0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ /* Open a file in READ mode */
+
+ if((fp = fopen(filename, "r")) == NULL)
+ {
+ Fail("Unable to open a file for reading. Is the file "
+ "in the directory? It should be.");
+ }
+
+ memset(buffer,'x',128);
+
+ /* Put the null one character past the end of the text that was read
+ in, to ensure that it wasn't reading in 0
+ */
+
+ buffer[16] = '\0';
+
+ /* Attempt to read in 5 bytes at a time. This should return 3 and
+ contain the full string in the buffer.
+ */
+
+ if((result = fread(buffer,5,3,fp)) != 3)
+ {
+ Fail("ERROR: Attempted to read in data of size 5. The file has "
+ "15 bytes in it so 3 items should have been read. But the value "
+ "returned was %d.",result);
+ }
+
+ if(strcmp(buffer, "This is a test.x") != 0)
+ {
+ Fail("ERROR: The buffer should have contained the text "
+ "'This is a test.x' but instead contained '%s'.",buffer);
+ }
+
+ memset(buffer,'x',128);
+
+ if(fseek(fp, 0, SEEK_SET))
+ {
+ Fail("ERROR: fseek failed, and this test depends on it.");
+ }
+
+ buffer[16] = '\0';
+
+ /* Attempt to read in 6 bytes at a time. The return should be 2. The
+ full string should still be in the buffer.
+ */
+
+ if((result = fread(buffer,6,3,fp)) != 2)
+ {
+ Fail("ERROR: Attempted to read in data of size 6. The file has "
+ "15 bytes in it, so 2 items should have been read. But the "
+ "value returned was %d.",result);
+ }
+
+ if(strcmp(buffer, "This is a test.x") != 0)
+ {
+ Fail("ERROR: The buffer should have contained the text "
+ "'This is a test.x' but instead contained '%s'.",buffer);
+ }
+
+ memset(buffer,'x',128);
+
+ buffer[7] = '\0';
+
+ if(fseek(fp, 0, SEEK_SET))
+ {
+ Fail("ERROR: fseek failed, and this test depends on it.");
+ }
+
+ /* Attempt to read in 6 bytes at a time but only one item max.
+ The return should be 1. The first 6 characters should be in the
+ buffer.
+ */
+
+ if((result = fread(buffer,6,1,fp)) != 1)
+ {
+ Fail("ERROR: Attempted to read in data of size 6 with a max count "
+ "of 1. Thus, one item should have been read, but the "
+ "value returned was %d.",result);
+ }
+
+ if(strcmp(buffer, "This ix") != 0)
+ {
+ Fail("ERROR: The buffer should have contained the text "
+ "'This ix.' but instead contained '%s'.",buffer);
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/fread/test3/testfile b/src/pal/tests/palsuite/c_runtime/fread/test3/testfile
new file mode 100644
index 0000000000..273c1a9ffd
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fread/test3/testfile
@@ -0,0 +1 @@
+This is a test. \ No newline at end of file
diff --git a/src/pal/tests/palsuite/c_runtime/fread/test3/testinfo.dat b/src/pal/tests/palsuite/c_runtime/fread/test3/testinfo.dat
new file mode 100644
index 0000000000..95bc30ebcf
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fread/test3/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = fread
+Name = Positive Test for fread
+TYPE = DEFAULT
+EXE1 = test3
+Description
+= Tests the PAL implementation of the fread function.
+= Open a file in READ mode, then try to read from the file with
+= different 'size' params. Check to ensure the return values and
+= the text in the buffer is correct
diff --git a/src/pal/tests/palsuite/c_runtime/free/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/free/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/free/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/free/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/free/test1/CMakeLists.txt
new file mode 100644
index 0000000000..bd94cb5733
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/free/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_free_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_free_test1 coreclrpal)
+
+target_link_libraries(paltest_free_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/free/test1/test1.c b/src/pal/tests/palsuite/c_runtime/free/test1/test1.c
new file mode 100644
index 0000000000..4ff8dfb094
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/free/test1/test1.c
@@ -0,0 +1,62 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Repeatedly allocates and frees a chunk of memory, to verify
+** that free is really returning memory to the heap
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char **argv)
+{
+
+ char *testA;
+
+ long i;
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ /* check that free really returns memory to the heap. */
+ for(i=1; i<1000000; i++)
+ {
+ testA = (char *)malloc(1000*sizeof(char));
+ if (testA==NULL)
+ {
+ Fail("Either free is failing to return memory to the heap, or"
+ " the system is running out of memory for some other "
+ "reason.\n");
+ }
+ free(testA);
+ }
+
+ free(NULL); /*should do nothing*/
+ PAL_Terminate();
+ return PASS;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/free/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/free/test1/testinfo.dat
new file mode 100644
index 0000000000..5bf400ce27
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/free/test1/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = free
+Name = Positive Test for free
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Repeatedly allocates and frees a chunk of memory, to verify that free
+= is really returning memory to the heap
+
diff --git a/src/pal/tests/palsuite/c_runtime/fseek/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/fseek/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fseek/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/fseek/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/fseek/test1/CMakeLists.txt
new file mode 100644
index 0000000000..fb55bd1051
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fseek/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_fseek_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_fseek_test1 coreclrpal)
+
+target_link_libraries(paltest_fseek_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/fseek/test1/test1.c b/src/pal/tests/palsuite/c_runtime/fseek/test1/test1.c
new file mode 100644
index 0000000000..8496289a01
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fseek/test1/test1.c
@@ -0,0 +1,193 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Call fseek to move a file pointer to the start of a file,
+** a position offset from the start, a position offset from the
+** current position, and a position offset from the end of the
+** file. Check that the file pointer is at the correct position
+** after each seek.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+
+const char filename[] = "testfile.txt";
+
+static BOOL Cleanup(HANDLE hFile)
+{
+ BOOL result= TRUE;
+
+ if (fclose(hFile))
+ {
+ Trace("fseek: ERROR -> Unable to close file \"%s\".\n",
+ filename);
+ result= FALSE;
+ }
+ if (!DeleteFileA(filename))
+ {
+ result= FALSE;
+ Trace("fseek: ERROR -> Unable to delete file \"%s\". ",
+ "GetLastError returned %u.\n",
+ filename,
+ GetLastError());
+ }
+ return result;
+}
+
+int __cdecl main(int argc, char **argv)
+{
+ char outBuf[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+ char inBuf[20];
+ FILE * fp;
+ int size = ( sizeof(outBuf)/sizeof(char) ) - 1;
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ /*create the file*/
+ fp = fopen(filename, "w");
+ if (fp == NULL)
+ {
+ Fail("Unable to open a file for write.\n");
+ }
+ if(fprintf(fp, outBuf) != size)
+ {
+ Trace("Unable to write to %s.\n", filename);
+ Cleanup(fp);
+ Fail("");
+ }
+
+ if (fclose(fp) != 0)
+ {
+ Trace("Unable to close newly written file.\n");
+ if (!DeleteFileA(filename))
+ {
+ Trace("fseek: ERROR -> Unable to delete file \"%s\". ",
+ "GetLastError returned %u.\n",
+ filename,
+ GetLastError());
+ }
+ Fail("");
+ }
+
+ fp = fopen(filename, "r");
+ if (fp == NULL)
+ {
+ if (!DeleteFileA(filename))
+ {
+ Trace("_putw: ERROR -> Unable to delete file \"%s\". ",
+ "GetLastError returned %u.\n",
+ filename,
+ GetLastError());
+ }
+ Fail("Unable to open a file for read.\n");
+ }
+
+ /*seek to the start*/
+ if (fseek(fp, 0, SEEK_SET) != 0)
+ {
+ Cleanup(fp);
+ Fail("fseek failed when seeking the start of a file.\n");
+ }
+ if (fgets(inBuf, 11, fp) != inBuf)
+ {
+ Cleanup(fp);
+ Fail("Unable to read from file after using fseek to move to the start.\n");
+ }
+ if (strncmp(inBuf, outBuf, 10) != 0)
+ {
+ Cleanup(fp);
+ Fail("fseek was asked to seek the start of a file,"
+ "but didn't get there.\n");
+ }
+
+ /*Seek with an offset from the start*/
+
+ if (fseek(fp, 10, SEEK_SET) != 0)
+ {
+ Cleanup(fp);
+ Fail("fseek failed when called with SEEK_SET and a positive offset.\n");
+ }
+
+ if (fgets(inBuf, 6, fp) != inBuf)
+ {
+ Cleanup(fp);
+ Fail("fgets failed after feek was called with SEEK_SET"
+ "and a positive offset.\n");
+ }
+
+
+ if (strncmp(inBuf, "ABCDE", 5) != 0)
+ {
+ Cleanup(fp);
+ Fail("fseek did not move to the correct position when passed SEEK_SET"
+ " and a positive offset.\n");
+ }
+
+ /*now move backwards and read the same string*/
+ if (fseek(fp, -5, SEEK_CUR) != 0)
+ {
+ Cleanup(fp);
+ Fail("fseek failed when passed SEEK_CUR and a negative offset.\n");
+ }
+
+ if (fgets(inBuf, 6, fp) != inBuf)
+ {
+ Cleanup(fp);
+ Fail("fgets failed after fseek was called with SEEK_CUR and a "
+ "negative offset.\n");
+ }
+
+ if (strncmp(inBuf, "ABCDE", 5) != 0)
+ {
+ Cleanup(fp);
+ Fail("fseek did not move to the correct position when called with"
+ " SEEK_CUR and a negative offset.\n");
+ }
+
+ /*Try seeking relative to the end of the file.*/
+ if (fseek(fp, -10, SEEK_END) != 0)
+ {
+ Cleanup(fp);
+ Fail("fseek failed when called with SEEK_END and a negative"
+ " offset.\n");
+ }
+ if (fgets(inBuf, 2, fp) != inBuf)
+ {
+ Cleanup(fp);
+ Fail("fgets failed after fseek was called with SEEK_END and a "
+ "negative offset\n");
+ }
+
+ if (strncmp(inBuf, "Q", 1) != 0)
+ {
+ Cleanup(fp);
+ Fail("fseek did not move to the correct position when called with "
+ "SEEK_END and a negative offset.\n");
+ }
+
+
+ /*close the file*/
+ if(!Cleanup(fp))
+ {
+ Fail("");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
+
+
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/fseek/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/fseek/test1/testinfo.dat
new file mode 100644
index 0000000000..788f8d4bea
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fseek/test1/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = fseek
+Name = Positive Test for fseek
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Call seek to move a file pointer to the start of a file, a position
+= offset from the start, a position offset from the current position, and
+= a position offset from the end of the file. Check that the file
+= pointer is at the correct position after each seek.
diff --git a/src/pal/tests/palsuite/c_runtime/ftell/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/ftell/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/ftell/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/ftell/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/ftell/test1/CMakeLists.txt
new file mode 100644
index 0000000000..7ea9a51111
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/ftell/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ ftell.c
+)
+
+add_executable(paltest_ftell_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_ftell_test1 coreclrpal)
+
+target_link_libraries(paltest_ftell_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/ftell/test1/ftell.c b/src/pal/tests/palsuite/c_runtime/ftell/test1/ftell.c
new file mode 100644
index 0000000000..66e0854847
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/ftell/test1/ftell.c
@@ -0,0 +1,145 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: ftell.c (test 1)
+**
+** Purpose: Tests the PAL implementation of the ftell function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+FILE* pFile;
+struct TESTS
+{
+ long lDist;
+ int nFrom;
+ long lPosition;
+};
+
+
+/*************************************************
+**
+** Validate
+**
+** Purpose:
+** Tests whether the move was successful. If
+** it passes, it returns TRUE. If it fails
+** it outputs some error messages and returns
+** FALSE.
+**
+*************************************************/
+BOOL Validate(long lExpected)
+{
+ long lPos = -2;
+
+ if (((lPos = ftell(pFile)) == -1) || (lPos != lExpected))
+ {
+ Trace("ftell: ERROR -> ftell returned %ld when expecting %ld.\n",
+ lPos,
+ lExpected);
+ if (fclose(pFile) != 0)
+ {
+ Trace("ftell: ERROR -> fclose failed to close the file.\n");
+ }
+ return FALSE;
+ }
+ return TRUE;
+}
+
+
+/*************************************************
+**
+** MovePointer
+**
+** Purpose:
+** Accepts the distance to move and the
+** distance and calls fseek to move the file
+** pointer. If the fseek fails, error messages
+** are displayed and FALSE is returned. TRUE
+** is returned on a successful fseek.
+**
+*************************************************/
+BOOL MovePointer(long lDist, int nFrom)
+{
+ /* move the file pointer*/
+ if (fseek(pFile, lDist, nFrom) != 0)
+ {
+ Trace("ftell: ERROR -> fseek failed to move the file pointer "
+ "%l characters.\n",
+ lDist);
+ if (fclose(pFile) != 0)
+ {
+ Trace("ftell: ERROR -> fclose failed to close the file.\n");
+ }
+ return FALSE;
+ }
+ return TRUE;
+}
+
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ const char szFileName[] = {"testfile.txt"};
+ long lPos = -1;
+ int i;
+ char szTempBuffer[256];
+ struct TESTS testCase[] =
+ {
+ {0, SEEK_SET, 0},
+ {10, SEEK_CUR, 10},
+ {-5, SEEK_CUR, 5},
+ {-2, SEEK_END, 50}
+ };
+
+
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ memset(szTempBuffer, 0, 256);
+
+
+ /* open the test file */
+ pFile = fopen(szFileName, "r");
+ if (pFile == NULL)
+ {
+ Fail("ftell: ERROR -> fopen failed to open the file \"%s\".\n");
+ }
+
+ /* loop through the test cases */
+ for (i = 0; i < (sizeof(testCase)/sizeof(struct TESTS)); i++)
+ {
+ if (MovePointer(testCase[i].lDist, testCase[i].nFrom) != TRUE)
+ {
+ Fail("");
+ }
+ else if (Validate(testCase[i].lPosition) != TRUE)
+ {
+ Fail("");
+ }
+ }
+
+ if (fclose(pFile) != 0)
+ {
+ Fail("ftell: ERROR -> fclose failed to close the file.\n");
+ }
+
+ /* lets just see if we can find out where we are in a closed stream... */
+ if ((lPos = ftell(pFile)) != -1)
+ {
+ Fail("ftell: ERROR -> ftell returned a valid position (%ld) on a "
+ "closed file handle\n",
+ lPos);
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/ftell/test1/testfile.txt b/src/pal/tests/palsuite/c_runtime/ftell/test1/testfile.txt
new file mode 100644
index 0000000000..dd0fe15fe1
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/ftell/test1/testfile.txt
@@ -0,0 +1 @@
+The quick brown fox jumped over the lazy dog's back. \ No newline at end of file
diff --git a/src/pal/tests/palsuite/c_runtime/ftell/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/ftell/test1/testinfo.dat
new file mode 100644
index 0000000000..c17ec9ad99
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/ftell/test1/testinfo.dat
@@ -0,0 +1,16 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = c_runtime
+Function = ftell
+Name = test for ftell (test 1)
+Type = DEFAULT
+EXE1 = ftell
+Description
+= Use fseek and a static list of distances to move, direction
+= to move and expected results to test the ftell function. A typical
+= test will move the file pointer with fseek then call ftell. The
+= results from ftell will then be compared to the expected result to
+= determine whether the test passed or failed.
diff --git a/src/pal/tests/palsuite/c_runtime/fwprintf/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/fwprintf/CMakeLists.txt
new file mode 100644
index 0000000000..cafb9536b0
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fwprintf/CMakeLists.txt
@@ -0,0 +1,22 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test10)
+add_subdirectory(test11)
+add_subdirectory(test12)
+add_subdirectory(test13)
+add_subdirectory(test14)
+add_subdirectory(test15)
+add_subdirectory(test16)
+add_subdirectory(test17)
+add_subdirectory(test18)
+add_subdirectory(test19)
+add_subdirectory(test2)
+add_subdirectory(test3)
+add_subdirectory(test4)
+add_subdirectory(test5)
+add_subdirectory(test6)
+add_subdirectory(test7)
+add_subdirectory(test8)
+add_subdirectory(test9)
+
diff --git a/src/pal/tests/palsuite/c_runtime/fwprintf/fwprintf.h b/src/pal/tests/palsuite/c_runtime/fwprintf/fwprintf.h
new file mode 100644
index 0000000000..36756636cf
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fwprintf/fwprintf.h
@@ -0,0 +1,453 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: fwprintf.h
+**
+** Purpose: Containts common testing functions for fwprintf
+**
+**
+**==========================================================================*/
+
+#ifndef __fwprintf_H__
+#define __fwprintf_H__
+
+void DoStrTest(WCHAR *formatstr, char* param, char *checkstr)
+{
+ FILE *fp;
+ char buf[256] = { 0 };
+
+ if ((fp = fopen("testfile.txt", "w+")) == NULL )
+ {
+ Fail("ERROR: fopen failed to create testfile\n");
+ }
+ if ((fwprintf(fp, formatstr, param)) < 0)
+ {
+ Fail("ERROR: fwprintf failed\n");
+ }
+ if ((fseek(fp, 0, SEEK_SET)) != 0)
+ {
+ Fail("ERROR: fseek failed\n");
+ }
+ if ((fgets(buf, 100, fp)) == NULL)
+ {
+ Fail("ERROR: fseek failed\n");
+ }
+
+ if (memcmp(buf, checkstr, strlen(checkstr) + 1) != 0)
+ {
+ Fail("ERROR: failed to insert string \"%\" into \"%S\"\n"
+ "Expected \"%s\" got \"%s\".\n",
+ param, formatstr, checkstr, buf);
+ }
+ fclose(fp);
+}
+
+void DoWStrTest(WCHAR *formatstr, WCHAR* param, char *checkstr)
+{
+ FILE *fp;
+ char buf[256] = { 0 };
+
+ if ((fp = fopen("testfile.txt", "w+")) == NULL )
+ {
+ Fail("ERROR: fopen failed to create testfile\n");
+ }
+ if ((fwprintf(fp, formatstr, param)) < 0)
+ {
+ Fail("ERROR: fwprintf failed\n");
+ }
+ if ((fseek(fp, 0, SEEK_SET)) != 0)
+ {
+ Fail("ERROR: fseek failed\n");
+ }
+ if ((fgets(buf, 100, fp)) == NULL)
+ {
+ Fail("ERROR: fseek failed\n");
+ }
+
+ if (memcmp(buf, checkstr, strlen(checkstr) + 1) != 0)
+ {
+ Fail("ERROR: failed to insert wide string \"%s\" into \"%S\"\n"
+ "Expected \"%s\" got \"%s\".\n",
+ convertC(param), formatstr, checkstr, buf);
+ }
+ fclose(fp);
+}
+
+
+void DoPointerTest(WCHAR *formatstr, void* param, char* paramstr,
+ char *checkstr1, char *checkstr2)
+{
+ FILE *fp;
+ char buf[256] = { 0 };
+
+ if ((fp = fopen("testfile.txt", "w+")) == NULL )
+ {
+ Fail("ERROR: fopen failed to create testfile\n");
+ }
+
+ if ((fwprintf(fp, formatstr, param)) < 0)
+ {
+ Fail("ERROR: fwprintf failed\n");
+ }
+
+ if ((fseek(fp, 0, SEEK_SET)) != 0)
+ {
+ Fail("ERROR: fseek failed\n");
+ }
+
+ if ((fgets(buf, 100, fp)) == NULL)
+ {
+ Fail("ERROR: fseek failed\n");
+ }
+
+ if (memcmp(buf, checkstr1, strlen(checkstr1) + 1) != 0 &&
+ memcmp(buf, checkstr2, strlen(checkstr2) + 1) != 0 )
+ {
+ Fail("ERROR: failed to insert %s into \"%s\"\n"
+ "Expected \"%s\" or \"%s\" got \"%s\".\n",
+ paramstr, formatstr, checkstr1, checkstr2, buf);
+ }
+
+ if ((fclose( fp )) != 0)
+ {
+ Fail("ERROR: fclose failed to close \"testfile.txt\"\n");
+ }
+}
+
+
+
+void DoCountTest(WCHAR *formatstr, int param, char *checkstr)
+{
+ FILE *fp;
+ char buf[512] = { 0 };
+ int n = -1;
+
+ if ((fp = fopen("testfile.txt", "w+")) == NULL )
+ {
+ Fail("ERROR: fopen failed to create testfile\n");
+ }
+
+ if ((fwprintf(fp, formatstr, &n)) < 0)
+ {
+ Fail("ERROR: fwprintf failed\n");
+ }
+
+ if ((fseek(fp, 0, SEEK_SET)) != 0)
+ {
+ Fail("ERROR: fseek failed\n");
+ }
+
+ if ((fgets(buf, sizeof(buf), fp)) == NULL)
+ {
+ Fail("ERROR: fseek failed\n");
+ }
+
+ if (n != param)
+ {
+ Fail("ERROR: Expected count parameter to resolve to %d, got %X\n",
+ param, n);
+ }
+
+ if (memcmp(buf, checkstr, strlen(checkstr) + 1) != 0)
+ {
+ Fail("ERROR: Expected \"%s\" got \"%s\".\n", checkstr, buf);
+ }
+
+ if ((fclose( fp )) != 0)
+ {
+ Fail("ERROR: fclose failed to close \"testfile.txt\"\n");
+ }
+}
+
+void DoShortCountTest(WCHAR *formatstr, int param, char *checkstr)
+{
+ FILE *fp;
+ char buf[512] = { 0 };
+ short int n = -1;
+
+ if ((fp = fopen("testfile.txt", "w+")) == NULL )
+ {
+ Fail("ERROR: fopen failed to create testfile\n");
+ }
+
+ if ((fwprintf(fp, formatstr, &n)) < 0)
+ {
+ Fail("ERROR: fwprintf failed\n");
+ }
+
+ if ((fseek(fp, 0, SEEK_SET)) != 0)
+ {
+ Fail("ERROR: fseek failed\n");
+ }
+
+ if ((fgets(buf, 100, fp)) == NULL)
+ {
+ Fail("ERROR: fseek failed\n");
+ }
+
+ if (n != param)
+ {
+ Fail("ERROR: Expected count parameter to resolve to %d, got %X\n",
+ param, n);
+ }
+
+ if (memcmp(buf, checkstr, strlen(checkstr) + 1) != 0)
+ {
+ Fail("ERROR: Expected \"%s\" got \"%s\".\n", checkstr, buf);
+ }
+
+ if ((fclose( fp )) != 0)
+ {
+ Fail("ERROR: fclose failed to close \"testfile.txt\"\n");
+ }
+}
+
+
+void DoCharTest(WCHAR *formatstr, char param, char *checkstr)
+{
+ FILE *fp;
+ char buf[256] = { 0 };
+
+ if ((fp = fopen("testfile.txt", "w+")) == NULL )
+ {
+ Fail("ERROR: fopen failed to create testfile\n");
+ }
+ if ((fwprintf(fp, formatstr, param)) < 0)
+ {
+ Fail("ERROR: fwprintf failed\n");
+ }
+ if ((fseek(fp, 0, SEEK_SET)) != 0)
+ {
+ Fail("ERROR: fseek failed\n");
+ }
+ if ((fgets(buf, 100, fp)) == NULL)
+ {
+ Fail("ERROR: fseek failed\n");
+ }
+
+ if (memcmp(buf, checkstr, strlen(checkstr) + 1) != 0)
+ {
+ Fail("ERROR: failed to insert char \'%c\' (%d) into \"%S\"\n"
+ "Expected \"%s\" got \"%s\".\n",
+ param, param, formatstr, checkstr, buf);
+ }
+ fclose(fp);
+}
+
+void DoWCharTest(WCHAR *formatstr, WCHAR param, char *checkstr)
+{
+ FILE *fp;
+ char buf[256] = { 0 };
+
+ if ((fp = fopen("testfile.txt", "w+")) == NULL )
+ {
+ Fail("ERROR: fopen failed to create testfile\n");
+ }
+ if ((fwprintf(fp, formatstr, param)) < 0)
+ {
+ Fail("ERROR: fwprintf failed\n");
+ }
+ if ((fseek(fp, 0, SEEK_SET)) != 0)
+ {
+ Fail("ERROR: fseek failed\n");
+ }
+ if ((fgets(buf, 100, fp)) == NULL)
+ {
+ Fail("ERROR: fseek failed\n");
+ }
+
+ if (memcmp(buf, checkstr, strlen(checkstr) + 1) != 0)
+ {
+ Fail("ERROR: failed to insert wide char \'%c\' (%d) into \"%S\"\n"
+ "Expected \"%s\" got \"%s\".\n",
+ (char)param, param, formatstr, checkstr, buf);
+ }
+ fclose(fp);
+}
+
+void DoNumTest(WCHAR *formatstr, int value, char *checkstr)
+{
+ FILE *fp;
+ char buf[256] = { 0 };
+
+ if ((fp = fopen("testfile.txt", "w+")) == NULL )
+ {
+ Fail("ERROR: fopen failed to create testfile\n");
+ }
+ if ((fwprintf(fp, formatstr, value)) < 0)
+ {
+ Fail("ERROR: fwprintf failed\n");
+ }
+ if ((fseek(fp, 0, SEEK_SET)) != 0)
+ {
+ Fail("ERROR: fseek failed\n");
+ }
+ if ((fgets(buf, 100, fp)) == NULL)
+ {
+ Fail("ERROR: fseek failed\n");
+ }
+
+ if (memcmp(buf, checkstr, strlen(checkstr) + 1) != 0)
+ {
+ Fail("ERROR: failed to insert %#x into \"%S\"\n"
+ "Expected \"%s\" got \"%s\".\n",
+ value, formatstr, checkstr, buf);
+ }
+ fclose(fp);
+}
+
+void DoI64Test(WCHAR *formatstr, INT64 value, char *valuestr, char *checkstr1,
+ char *checkstr2)
+{
+ FILE *fp;
+ char buf[256] = { 0 };
+
+ if ((fp = fopen("testfile.txt", "w+")) == NULL )
+ {
+ Fail("ERROR: fopen failed to create testfile\n");
+ }
+ if ((fwprintf(fp, formatstr, value)) < 0)
+ {
+ Fail("ERROR: fwprintf failed\n");
+ }
+ if ((fseek(fp, 0, SEEK_SET)) != 0)
+ {
+ Fail("ERROR: fseek failed\n");
+ }
+ if ((fgets(buf, 100, fp)) == NULL)
+ {
+ Fail("ERROR: fseek failed\n");
+ }
+
+ if (memcmp(buf, checkstr1, strlen(checkstr1) + 1) != 0 &&
+ memcmp(buf, checkstr2, strlen(checkstr2) + 1) != 0)
+ {
+ Fail("ERROR: failed to insert %s into \"%S\"\n"
+ "Expected \"%s\" or \"%s\", got \"%s\".\n",
+ valuestr, formatstr, checkstr1, checkstr2, buf);
+ }
+ fclose(fp);
+}
+
+void DoDoubleTest(WCHAR *formatstr, double value, char *checkstr1,
+ char *checkstr2)
+{
+ FILE *fp;
+ char buf[256] = { 0 };
+
+ if ((fp = fopen("testfile.txt", "w+")) == NULL )
+ {
+ Fail("ERROR: fopen failed to create testfile\n");
+ }
+
+ if ((fwprintf(fp, formatstr, value)) < 0)
+ {
+ Fail("ERROR: fwprintf failed\n");
+ }
+ if ((fseek(fp, 0, SEEK_SET)) != 0)
+ {
+ Fail("ERROR: fseek failed\n");
+ }
+ if ((fgets(buf, 100, fp)) == NULL)
+ {
+ Fail("ERROR: fseek failed\n");
+ }
+
+ if (memcmp(buf, checkstr1, strlen(checkstr1) + 1) != 0 &&
+ memcmp(buf, checkstr2, strlen(checkstr2) + 1) != 0)
+ {
+ Fail("ERROR: failed to insert %f into \"%S\"\n"
+ "Expected \"%s\" or \"%s\", got \"%s\".\n",
+ value, formatstr, checkstr1, checkstr2, buf);
+ }
+ fclose(fp);
+}
+
+
+void DoArgumentPrecTest(WCHAR *formatstr, int precision, void *param,
+ char *paramstr, char *checkstr1, char *checkstr2)
+{
+ FILE *fp;
+ char buf[256];
+
+ if ((fp = fopen("testfile.txt", "w+")) == NULL )
+ {
+ Fail("ERROR: fopen failed to create testfile\n");
+ }
+
+ if ((fwprintf(fp, formatstr, precision, param)) < 0)
+ {
+ Fail("ERROR: fwprintf failed\n");
+ }
+
+ if ((fseek(fp, 0, SEEK_SET)) != 0)
+ {
+ Fail("ERROR: fseek failed\n");
+ }
+
+ if ((fgets(buf, 100, fp)) == NULL)
+ {
+ Fail("ERROR: fseek failed\n");
+ }
+
+ if (memcmp(buf, checkstr1, strlen(checkstr1) + 1) != 0 &&
+ memcmp(buf, checkstr2, strlen(checkstr2) + 1) != 0)
+ {
+ Fail("ERROR: failed to insert %s into \"%s\" with precision %d\n"
+ "Expected \"%s\" or \"%s\", got \"%s\".\n", paramstr, formatstr,
+ precision, checkstr1, checkstr2, buf);
+ }
+
+
+ if ((fclose( fp )) != 0)
+ {
+ Fail("ERROR: fclose failed to close \"testfile.txt\"\n");
+ }
+
+}
+
+void DoArgumentPrecDoubleTest(WCHAR *formatstr, int precision, double param,
+ char *checkstr1, char *checkstr2)
+{
+ FILE *fp;
+ char buf[256];
+
+ if ((fp = fopen("testfile.txt", "w+")) == NULL )
+ {
+ Fail("ERROR: fopen failed to create testfile\n");
+ }
+
+ if ((fwprintf(fp, formatstr, precision, param)) < 0)
+ {
+ Fail("ERROR: fwprintf failed\n");
+ }
+
+ if ((fseek(fp, 0, SEEK_SET)) != 0)
+ {
+ Fail("ERROR: fseek failed\n");
+ }
+
+ if ((fgets(buf, 100, fp)) == NULL)
+ {
+ Fail("ERROR: fseek failed\n");
+ }
+
+ if (memcmp(buf, checkstr1, strlen(checkstr1) + 1) != 0 &&
+ memcmp(buf, checkstr2, strlen(checkstr2) + 1) != 0)
+ {
+ Fail("ERROR: failed to insert %f into \"%s\" with precision %d\n"
+ "Expected \"%s\" or \"%s\", got \"%s\".\n", param, formatstr,
+ precision, checkstr1, checkstr2, buf);
+ }
+
+ if ((fclose( fp )) != 0)
+ {
+ Fail("ERROR: fclose failed to close \"testfile.txt\"\n");
+ }
+
+}
+
+#endif
diff --git a/src/pal/tests/palsuite/c_runtime/fwprintf/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/fwprintf/test1/CMakeLists.txt
new file mode 100644
index 0000000000..ce4271edb2
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fwprintf/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_fwprintf_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_fwprintf_test1 coreclrpal)
+
+target_link_libraries(paltest_fwprintf_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/fwprintf/test1/test1.c b/src/pal/tests/palsuite/c_runtime/fwprintf/test1/test1.c
new file mode 100644
index 0000000000..8a171db52a
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fwprintf/test1/test1.c
@@ -0,0 +1,71 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose: A single, basic, test case with no formatting.
+** Test modeled after the sprintf series.
+**
+
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+
+/*
+ * Depends on memcmp, strlen, fopen, fgets, fseek and fclose.
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ FILE *fp;
+ char testfile[] = "testfile.txt";
+
+ WCHAR *outstr;
+ char checkstr[] = "hello world";
+ char buf[256];
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return(FAIL);
+ }
+
+ outstr = convert(checkstr);
+ if ((fp = fopen(testfile, "w+")) == NULL)
+ {
+ Fail("ERROR: fopen failed to create \"%s\"\n", testfile);
+ }
+
+ if ((fwprintf(fp, outstr)) < 0)
+ {
+ Fail("ERROR: fwprintf failed to print to \"%s\"\n", testfile);
+ }
+
+ if ((fseek( fp, 0, SEEK_SET)) != 0)
+ {
+ Fail("ERROR: Fseek failed to set pointer to beginning of file\n" );
+ }
+
+
+ if ((fgets( buf, 100, fp )) == NULL)
+ {
+ Fail("ERROR: fgets failed\n");
+ }
+
+ if (memcmp(checkstr, buf, strlen(checkstr)+1) != 0)
+ {
+ Fail("ERROR: expected %s, got %s\n", checkstr, buf);
+ }
+
+
+ if ((fclose( fp )) != 0)
+ {
+ Fail("ERROR: fclose failed to close \"%s\"\n", testfile);
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/fwprintf/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/fwprintf/test1/testinfo.dat
new file mode 100644
index 0000000000..3bef5c6384
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fwprintf/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = fwprintf
+Name = Positive Test for fwprintf
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= A single, basic, test case with no formatting.
+= Test modeled after the sprintf series.
diff --git a/src/pal/tests/palsuite/c_runtime/fwprintf/test10/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/fwprintf/test10/CMakeLists.txt
new file mode 100644
index 0000000000..a8323b4fc7
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fwprintf/test10/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test10.c
+)
+
+add_executable(paltest_fwprintf_test10
+ ${SOURCES}
+)
+
+add_dependencies(paltest_fwprintf_test10 coreclrpal)
+
+target_link_libraries(paltest_fwprintf_test10
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/fwprintf/test10/test10.c b/src/pal/tests/palsuite/c_runtime/fwprintf/test10/test10.c
new file mode 100644
index 0000000000..3aa2c45c7c
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fwprintf/test10/test10.c
@@ -0,0 +1,51 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test10.c
+**
+** Purpose: Tests the octal specifier (%o).
+** This test is modeled after the sprintf series.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+#include "../fwprintf.h"
+
+/*
+ * Depends on memcmp, strlen, fopen, fseek and fgets.
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ int neg = -42;
+ int pos = 42;
+ INT64 l = 42;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return(FAIL);
+ }
+
+ DoNumTest(convert("foo %o"), pos, "foo 52");
+ DoNumTest(convert("foo %lo"), 0xFFFF, "foo 177777");
+ DoNumTest(convert("foo %ho"), 0xFFFF, "foo 177777");
+ DoNumTest(convert("foo %Lo"), pos, "foo 52");
+ DoI64Test(convert("foo %I64o"), l, "42", "foo 52", "foo 52");
+ DoNumTest(convert("foo %3o"), pos, "foo 52");
+ DoNumTest(convert("foo %-3o"), pos, "foo 52 ");
+ DoNumTest(convert("foo %.1o"), pos, "foo 52");
+ DoNumTest(convert("foo %.3o"), pos, "foo 052");
+ DoNumTest(convert("foo %03o"), pos, "foo 052");
+ DoNumTest(convert("foo %#o"), pos, "foo 052");
+ DoNumTest(convert("foo %+o"), pos, "foo 52");
+ DoNumTest(convert("foo % o"), pos, "foo 52");
+ DoNumTest(convert("foo %+o"), neg, "foo 37777777726");
+ DoNumTest(convert("foo % o"), neg, "foo 37777777726");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/fwprintf/test10/testinfo.dat b/src/pal/tests/palsuite/c_runtime/fwprintf/test10/testinfo.dat
new file mode 100644
index 0000000000..17902cb7fc
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fwprintf/test10/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = fwprintf
+Name = Positive Test for fwprintf
+TYPE = DEFAULT
+EXE1 = test10
+Description
+= Tests the octal specifier (%o).
+= This test is modeled after the sprintf series.
diff --git a/src/pal/tests/palsuite/c_runtime/fwprintf/test11/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/fwprintf/test11/CMakeLists.txt
new file mode 100644
index 0000000000..1b7987400a
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fwprintf/test11/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test11.c
+)
+
+add_executable(paltest_fwprintf_test11
+ ${SOURCES}
+)
+
+add_dependencies(paltest_fwprintf_test11 coreclrpal)
+
+target_link_libraries(paltest_fwprintf_test11
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/fwprintf/test11/test11.c b/src/pal/tests/palsuite/c_runtime/fwprintf/test11/test11.c
new file mode 100644
index 0000000000..5867cd64fb
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fwprintf/test11/test11.c
@@ -0,0 +1,51 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test11.c
+**
+** Purpose: Test the unsigned int specifier (%u).
+** This test is modeled after the sprintf series.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+#include "../fwprintf.h"
+
+/*
+ * Depends on memcmp, strlen, fopen, fseek and fgets.
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ int neg = -42;
+ int pos = 42;
+ INT64 l = 42;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return(FAIL);
+ }
+
+ DoNumTest(convert("foo %u"), pos, "foo 42");
+ DoNumTest(convert("foo %lu"), 0xFFFF, "foo 65535");
+ DoNumTest(convert("foo %hu"), 0xFFFF, "foo 65535");
+ DoNumTest(convert("foo %Lu"), pos, "foo 42");
+ DoI64Test(convert("foo %I64u"), l, "42", "foo 42", "foo 42");
+ DoNumTest(convert("foo %3u"), pos, "foo 42");
+ DoNumTest(convert("foo %-3u"), pos, "foo 42 ");
+ DoNumTest(convert("foo %.1u"), pos, "foo 42");
+ DoNumTest(convert("foo %.3u"), pos, "foo 042");
+ DoNumTest(convert("foo %03u"), pos, "foo 042");
+ DoNumTest(convert("foo %#u"), pos, "foo 42");
+ DoNumTest(convert("foo %+u"), pos, "foo 42");
+ DoNumTest(convert("foo % u"), pos, "foo 42");
+ DoNumTest(convert("foo %+u"), neg, "foo 4294967254");
+ DoNumTest(convert("foo % u"), neg, "foo 4294967254");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/fwprintf/test11/testinfo.dat b/src/pal/tests/palsuite/c_runtime/fwprintf/test11/testinfo.dat
new file mode 100644
index 0000000000..beda0cc3ab
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fwprintf/test11/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = fwprintf
+Name = Positive Test for fwprintf
+TYPE = DEFAULT
+EXE1 = test11
+Description
+= Test the unsigned int specifier (%u).
+= This test is modeled after the sprintf series.
diff --git a/src/pal/tests/palsuite/c_runtime/fwprintf/test12/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/fwprintf/test12/CMakeLists.txt
new file mode 100644
index 0000000000..1e43a4c906
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fwprintf/test12/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test12.c
+)
+
+add_executable(paltest_fwprintf_test12
+ ${SOURCES}
+)
+
+add_dependencies(paltest_fwprintf_test12 coreclrpal)
+
+target_link_libraries(paltest_fwprintf_test12
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/fwprintf/test12/test12.c b/src/pal/tests/palsuite/c_runtime/fwprintf/test12/test12.c
new file mode 100644
index 0000000000..48a6123423
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fwprintf/test12/test12.c
@@ -0,0 +1,52 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test12.c
+**
+** Purpose: Tests the (lowercase) hexadecimal specifier (%x).
+** This test is modeled after the sprintf series.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+#include "../fwprintf.h"
+
+/*
+ * Depends on memcmp, strlen, fopen, fseek and fgets.
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ int neg = -42;
+ int pos = 0x1234ab;
+ INT64 l = I64(0x1234567887654321);
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return(FAIL);
+ }
+
+ DoNumTest(convert("foo %x"), pos, "foo 1234ab");
+ DoNumTest(convert("foo %lx"), pos, "foo 1234ab");
+ DoNumTest(convert("foo %hx"), pos, "foo 34ab");
+ DoNumTest(convert("foo %Lx"), pos, "foo 1234ab");
+ DoI64Test(convert("foo %I64x"), l, "0x1234567887654321",
+ "foo 1234567887654321", "foo 0x1234567887654321");
+ DoNumTest(convert("foo %7x"), pos, "foo 1234ab");
+ DoNumTest(convert("foo %-7x"), pos, "foo 1234ab ");
+ DoNumTest(convert("foo %.1x"), pos, "foo 1234ab");
+ DoNumTest(convert("foo %.7x"), pos, "foo 01234ab");
+ DoNumTest(convert("foo %07x"), pos, "foo 01234ab");
+ DoNumTest(convert("foo %#x"), pos, "foo 0x1234ab");
+ DoNumTest(convert("foo %+x"), pos, "foo 1234ab");
+ DoNumTest(convert("foo % x"), pos, "foo 1234ab");
+ DoNumTest(convert("foo %+x"), neg, "foo ffffffd6");
+ DoNumTest(convert("foo % x"), neg, "foo ffffffd6");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/fwprintf/test12/testinfo.dat b/src/pal/tests/palsuite/c_runtime/fwprintf/test12/testinfo.dat
new file mode 100644
index 0000000000..3d0bf4c8f8
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fwprintf/test12/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = fwprintf
+Name = Positive Test for fwprintf
+TYPE = DEFAULT
+EXE1 = test12
+Description
+= Tests the (lowercase) hexadecimal specifier (%x).
+= This test is modeled after the sprintf series.
diff --git a/src/pal/tests/palsuite/c_runtime/fwprintf/test13/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/fwprintf/test13/CMakeLists.txt
new file mode 100644
index 0000000000..c84dc3ea41
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fwprintf/test13/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test13.c
+)
+
+add_executable(paltest_fwprintf_test13
+ ${SOURCES}
+)
+
+add_dependencies(paltest_fwprintf_test13 coreclrpal)
+
+target_link_libraries(paltest_fwprintf_test13
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/fwprintf/test13/test13.c b/src/pal/tests/palsuite/c_runtime/fwprintf/test13/test13.c
new file mode 100644
index 0000000000..6eabec6c77
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fwprintf/test13/test13.c
@@ -0,0 +1,52 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test13.c
+**
+** Purpose: Tests the (uppercase) hexadecimal specifier (%X).
+** This test is modeled after the sprintf series.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+#include "../fwprintf.h"
+
+/*
+ * Depends on memcmp, strlen, fopen, fseek and fgets.
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ int neg = -42;
+ int pos = 0x1234AB;
+ INT64 l = I64(0x1234567887654321);
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return(FAIL);
+ }
+
+ DoNumTest(convert("foo %X"), pos, "foo 1234AB");
+ DoNumTest(convert("foo %lX"), pos, "foo 1234AB");
+ DoNumTest(convert("foo %hX"), pos, "foo 34AB");
+ DoNumTest(convert("foo %LX"), pos, "foo 1234AB");
+ DoI64Test(convert("foo %I64X"), l, "0x1234567887654321",
+ "foo 1234567887654321", "foo 0x1234567887654321");
+ DoNumTest(convert("foo %7X"), pos, "foo 1234AB");
+ DoNumTest(convert("foo %-7X"), pos, "foo 1234AB ");
+ DoNumTest(convert("foo %.1X"), pos, "foo 1234AB");
+ DoNumTest(convert("foo %.7X"), pos, "foo 01234AB");
+ DoNumTest(convert("foo %07X"), pos, "foo 01234AB");
+ DoNumTest(convert("foo %#X"), pos, "foo 0X1234AB");
+ DoNumTest(convert("foo %+X"), pos, "foo 1234AB");
+ DoNumTest(convert("foo % X"), pos, "foo 1234AB");
+ DoNumTest(convert("foo %+X"), neg, "foo FFFFFFD6");
+ DoNumTest(convert("foo % X"), neg, "foo FFFFFFD6");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/fwprintf/test13/testinfo.dat b/src/pal/tests/palsuite/c_runtime/fwprintf/test13/testinfo.dat
new file mode 100644
index 0000000000..c3222e7c9e
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fwprintf/test13/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = fwprintf
+Name = Positive Test for fwprintf
+TYPE = DEFAULT
+EXE1 = test13
+Description
+= Tests the (uppercase) hexadecimal specifier (%X).
+= This test is modeled after the sprintf series.
diff --git a/src/pal/tests/palsuite/c_runtime/fwprintf/test14/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/fwprintf/test14/CMakeLists.txt
new file mode 100644
index 0000000000..97824c76b7
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fwprintf/test14/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test14.c
+)
+
+add_executable(paltest_fwprintf_test14
+ ${SOURCES}
+)
+
+add_dependencies(paltest_fwprintf_test14 coreclrpal)
+
+target_link_libraries(paltest_fwprintf_test14
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/fwprintf/test14/test14.c b/src/pal/tests/palsuite/c_runtime/fwprintf/test14/test14.c
new file mode 100644
index 0000000000..001cf72689
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fwprintf/test14/test14.c
@@ -0,0 +1,66 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test14.c
+**
+** Purpose: Tests the lowercase exponential
+** notation double specifier (%e).
+** This test is modeled after the sprintf series.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+#include "../fwprintf.h"
+
+/*
+ * Depends on memcmp, strlen, fopen, fseek and fgets.
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ double val = 256.0;
+ double neg = -256.0;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return(FAIL);
+ }
+
+ DoDoubleTest(convert("foo %e"), val, "foo 2.560000e+002",
+ "foo 2.560000e+02");
+ DoDoubleTest(convert("foo %le"), val, "foo 2.560000e+002",
+ "foo 2.560000e+02");
+ DoDoubleTest(convert("foo %he"), val, "foo 2.560000e+002",
+ "foo 2.560000e+02");
+ DoDoubleTest(convert("foo %Le"), val, "foo 2.560000e+002",
+ "foo 2.560000e+02");
+ DoDoubleTest(convert("foo %I64e"), val, "foo 2.560000e+002",
+ "foo 2.560000e+02");
+ DoDoubleTest(convert("foo %14e"), val, "foo 2.560000e+002",
+ "foo 2.560000e+02");
+ DoDoubleTest(convert("foo %-14e"), val, "foo 2.560000e+002 ",
+ "foo 2.560000e+02 ");
+ DoDoubleTest(convert("foo %.1e"), val, "foo 2.6e+002",
+ "foo 2.6e+02");
+ DoDoubleTest(convert("foo %.8e"), val, "foo 2.56000000e+002",
+ "foo 2.56000000e+02");
+ DoDoubleTest(convert("foo %014e"), val, "foo 02.560000e+002",
+ "foo 002.560000e+02");
+ DoDoubleTest(convert("foo %#e"), val, "foo 2.560000e+002",
+ "foo 2.560000e+02");
+ DoDoubleTest(convert("foo %+e"), val, "foo +2.560000e+002",
+ "foo +2.560000e+02");
+ DoDoubleTest(convert("foo % e"), val, "foo 2.560000e+002",
+ "foo 2.560000e+02");
+ DoDoubleTest(convert("foo %+e"), neg, "foo -2.560000e+002",
+ "foo -2.560000e+02");
+ DoDoubleTest(convert("foo % e"), neg, "foo -2.560000e+002",
+ "foo -2.560000e+02");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/fwprintf/test14/testinfo.dat b/src/pal/tests/palsuite/c_runtime/fwprintf/test14/testinfo.dat
new file mode 100644
index 0000000000..a723f76083
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fwprintf/test14/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = fwprintf
+Name = Positive Test for fwprintf
+TYPE = DEFAULT
+EXE1 = test14
+Description
+= Tests the lowercase exponential
+= notation double specifier (%e).
+= This test is modeled after the sprintf series.
diff --git a/src/pal/tests/palsuite/c_runtime/fwprintf/test15/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/fwprintf/test15/CMakeLists.txt
new file mode 100644
index 0000000000..6786c5b774
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fwprintf/test15/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test15.c
+)
+
+add_executable(paltest_fwprintf_test15
+ ${SOURCES}
+)
+
+add_dependencies(paltest_fwprintf_test15 coreclrpal)
+
+target_link_libraries(paltest_fwprintf_test15
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/fwprintf/test15/test15.c b/src/pal/tests/palsuite/c_runtime/fwprintf/test15/test15.c
new file mode 100644
index 0000000000..9dfe82eccc
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fwprintf/test15/test15.c
@@ -0,0 +1,66 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test15.c
+**
+** Purpose: Tests the uppercase exponential
+** notation double specifier (%E).
+** This test is modeled after the sprintf series.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+#include "../fwprintf.h"
+
+/*
+ * Depends on memcmp, strlen, fopen, fseek and fgets.
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ double val = 256.0;
+ double neg = -256.0;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return(FAIL);
+ }
+
+ DoDoubleTest(convert("foo %E"), val, "foo 2.560000E+002",
+ "foo 2.560000E+02");
+ DoDoubleTest(convert("foo %lE"), val, "foo 2.560000E+002",
+ "foo 2.560000E+02");
+ DoDoubleTest(convert("foo %hE"), val, "foo 2.560000E+002",
+ "foo 2.560000E+02");
+ DoDoubleTest(convert("foo %LE"), val, "foo 2.560000E+002",
+ "foo 2.560000E+02");
+ DoDoubleTest(convert("foo %I64E"), val, "foo 2.560000E+002",
+ "foo 2.560000E+02");
+ DoDoubleTest(convert("foo %14E"), val, "foo 2.560000E+002",
+ "foo 2.560000E+02");
+ DoDoubleTest(convert("foo %-14E"), val, "foo 2.560000E+002 ",
+ "foo 2.560000E+02 ");
+ DoDoubleTest(convert("foo %.1E"), val, "foo 2.6E+002",
+ "foo 2.6E+02");
+ DoDoubleTest(convert("foo %.8E"), val, "foo 2.56000000E+002",
+ "foo 2.56000000E+02");
+ DoDoubleTest(convert("foo %014E"), val, "foo 02.560000E+002",
+ "foo 002.560000E+02");
+ DoDoubleTest(convert("foo %#E"), val, "foo 2.560000E+002",
+ "foo 2.560000E+02");
+ DoDoubleTest(convert("foo %+E"), val, "foo +2.560000E+002",
+ "foo +2.560000E+02");
+ DoDoubleTest(convert("foo % E"), val, "foo 2.560000E+002",
+ "foo 2.560000E+02");
+ DoDoubleTest(convert("foo %+E"), neg, "foo -2.560000E+002",
+ "foo -2.560000E+02");
+ DoDoubleTest(convert("foo % E"), neg, "foo -2.560000E+002",
+ "foo -2.560000E+02");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/fwprintf/test15/testinfo.dat b/src/pal/tests/palsuite/c_runtime/fwprintf/test15/testinfo.dat
new file mode 100644
index 0000000000..246072f797
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fwprintf/test15/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = fwprintf
+Name = Positive Test for fwprintf
+TYPE = DEFAULT
+EXE1 = test15
+Description
+= Tests the uppercase exponential
+= notation double specifier (%E).
+= This test is modeled after the sprintf series.
diff --git a/src/pal/tests/palsuite/c_runtime/fwprintf/test16/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/fwprintf/test16/CMakeLists.txt
new file mode 100644
index 0000000000..be14870863
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fwprintf/test16/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test16.c
+)
+
+add_executable(paltest_fwprintf_test16
+ ${SOURCES}
+)
+
+add_dependencies(paltest_fwprintf_test16 coreclrpal)
+
+target_link_libraries(paltest_fwprintf_test16
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/fwprintf/test16/test16.c b/src/pal/tests/palsuite/c_runtime/fwprintf/test16/test16.c
new file mode 100644
index 0000000000..1969be1824
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fwprintf/test16/test16.c
@@ -0,0 +1,65 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test16.c
+**
+** Purpose: Tests the decimal notation double specifier (%f).
+** This test is modeled after the sprintf series.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+#include "../fwprintf.h"
+
+/*
+ * Depends on memcmp, strlen, fopen, fseek and fgets.
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ double val = 2560.001;
+ double neg = -2560.001;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return(FAIL);
+ }
+
+ DoDoubleTest(convert("foo %f"), val, "foo 2560.001000",
+ "foo 2560.001000");
+ DoDoubleTest(convert("foo %lf"), val, "foo 2560.001000",
+ "foo 2560.001000");
+ DoDoubleTest(convert("foo %hf"), val, "foo 2560.001000",
+ "foo 2560.001000");
+ DoDoubleTest(convert("foo %Lf"), val, "foo 2560.001000",
+ "foo 2560.001000");
+ DoDoubleTest(convert("foo %I64f"), val, "foo 2560.001000",
+ "foo 2560.001000");
+ DoDoubleTest(convert("foo %12f"), val, "foo 2560.001000",
+ "foo 2560.001000");
+ DoDoubleTest(convert("foo %-12f"), val, "foo 2560.001000 ",
+ "foo 2560.001000 ");
+ DoDoubleTest(convert("foo %.1f"), val, "foo 2560.0",
+ "foo 2560.0");
+ DoDoubleTest(convert("foo %.8f"), val, "foo 2560.00100000",
+ "foo 2560.00100000");
+ DoDoubleTest(convert("foo %012f"), val, "foo 02560.001000",
+ "foo 02560.001000");
+ DoDoubleTest(convert("foo %#f"), val, "foo 2560.001000",
+ "foo 2560.001000");
+ DoDoubleTest(convert("foo %+f"), val, "foo +2560.001000",
+ "foo +2560.001000");
+ DoDoubleTest(convert("foo % f"), val, "foo 2560.001000",
+ "foo 2560.001000");
+ DoDoubleTest(convert("foo %+f"), neg, "foo -2560.001000",
+ "foo -2560.001000");
+ DoDoubleTest(convert("foo % f"), neg, "foo -2560.001000",
+ "foo -2560.001000");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/fwprintf/test16/testinfo.dat b/src/pal/tests/palsuite/c_runtime/fwprintf/test16/testinfo.dat
new file mode 100644
index 0000000000..9e5faf9baf
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fwprintf/test16/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = fwprintf
+Name = Positive Test for fwprintf
+TYPE = DEFAULT
+EXE1 = test16
+Description
+= Tests the decimal notation double specifier (%f).
+= This test is modeled after the sprintf series.
diff --git a/src/pal/tests/palsuite/c_runtime/fwprintf/test17/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/fwprintf/test17/CMakeLists.txt
new file mode 100644
index 0000000000..b390d15620
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fwprintf/test17/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test17.c
+)
+
+add_executable(paltest_fwprintf_test17
+ ${SOURCES}
+)
+
+add_dependencies(paltest_fwprintf_test17 coreclrpal)
+
+target_link_libraries(paltest_fwprintf_test17
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/fwprintf/test17/test17.c b/src/pal/tests/palsuite/c_runtime/fwprintf/test17/test17.c
new file mode 100644
index 0000000000..66b12716d0
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fwprintf/test17/test17.c
@@ -0,0 +1,51 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test17.c
+**
+** Purpose: Tests the lowercase shorthand notation double specifier (%g).
+** This test is modeled after the sprintf series.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+#include "../fwprintf.h"
+
+/*
+ * Depends on memcmp, strlen, fopen, fseek and fgets.
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ double val = 2560.001;
+ double neg = -2560.001;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return(FAIL);
+ }
+
+ DoDoubleTest(convert("foo %g"), val, "foo 2560", "foo 2560");
+ DoDoubleTest(convert("foo %lg"), val, "foo 2560", "foo 2560");
+ DoDoubleTest(convert("foo %hg"), val, "foo 2560", "foo 2560");
+ DoDoubleTest(convert("foo %Lg"), val, "foo 2560", "foo 2560");
+ DoDoubleTest(convert("foo %I64g"), val, "foo 2560", "foo 2560");
+ DoDoubleTest(convert("foo %5g"), val, "foo 2560", "foo 2560");
+ DoDoubleTest(convert("foo %-5g"), val, "foo 2560 ", "foo 2560 ");
+ DoDoubleTest(convert("foo %.1g"), val, "foo 3e+003", "foo 3e+03");
+ DoDoubleTest(convert("foo %.2g"), val, "foo 2.6e+003", "foo 2.6e+03");
+ DoDoubleTest(convert("foo %.12g"), val, "foo 2560.001", "foo 2560.001");
+ DoDoubleTest(convert("foo %06g"), val, "foo 002560", "foo 002560");
+ DoDoubleTest(convert("foo %#g"), val, "foo 2560.00", "foo 2560.00");
+ DoDoubleTest(convert("foo %+g"), val, "foo +2560", "foo +2560");
+ DoDoubleTest(convert("foo % g"), val, "foo 2560", "foo 2560");
+ DoDoubleTest(convert("foo %+g"), neg, "foo -2560", "foo -2560");
+ DoDoubleTest(convert("foo % g"), neg, "foo -2560", "foo -2560");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/fwprintf/test17/testinfo.dat b/src/pal/tests/palsuite/c_runtime/fwprintf/test17/testinfo.dat
new file mode 100644
index 0000000000..fe637d744c
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fwprintf/test17/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = fwprintf
+Name = Positive Test for fwprintf
+TYPE = DEFAULT
+EXE1 = test17
+Description
+= Tests the lowercase shorthand notation double specifier (%g).
+= This test is modeled after the sprintf series.
diff --git a/src/pal/tests/palsuite/c_runtime/fwprintf/test18/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/fwprintf/test18/CMakeLists.txt
new file mode 100644
index 0000000000..6f6d79bce5
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fwprintf/test18/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test18.c
+)
+
+add_executable(paltest_fwprintf_test18
+ ${SOURCES}
+)
+
+add_dependencies(paltest_fwprintf_test18 coreclrpal)
+
+target_link_libraries(paltest_fwprintf_test18
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/fwprintf/test18/test18.c b/src/pal/tests/palsuite/c_runtime/fwprintf/test18/test18.c
new file mode 100644
index 0000000000..a33dea39b3
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fwprintf/test18/test18.c
@@ -0,0 +1,51 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test18.c
+**
+** Purpose: Tests the uppercase shorthand notation double specifier (%G).
+** This test is modeled after the sprintf series.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+#include "../fwprintf.h"
+
+/*
+ * Depends on memcmp, strlen, fopen, fseek and fgets.
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ double val = 2560.001;
+ double neg = -2560.001;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return(FAIL);
+ }
+
+ DoDoubleTest(convert("foo %G"), val, "foo 2560", "foo 2560");
+ DoDoubleTest(convert("foo %lG"), val, "foo 2560", "foo 2560");
+ DoDoubleTest(convert("foo %hG"), val, "foo 2560", "foo 2560");
+ DoDoubleTest(convert("foo %LG"), val, "foo 2560", "foo 2560");
+ DoDoubleTest(convert("foo %I64G"), val, "foo 2560", "foo 2560");
+ DoDoubleTest(convert("foo %5G"), val, "foo 2560", "foo 2560");
+ DoDoubleTest(convert("foo %-5G"), val, "foo 2560 ", "foo 2560 ");
+ DoDoubleTest(convert("foo %.1G"), val, "foo 3E+003", "foo 3E+03");
+ DoDoubleTest(convert("foo %.2G"), val, "foo 2.6E+003", "foo 2.6E+03");
+ DoDoubleTest(convert("foo %.12G"), val, "foo 2560.001", "foo 2560.001");
+ DoDoubleTest(convert("foo %06G"), val, "foo 002560", "foo 002560");
+ DoDoubleTest(convert("foo %#G"), val, "foo 2560.00", "foo 2560.00");
+ DoDoubleTest(convert("foo %+G"), val, "foo +2560", "foo +2560");
+ DoDoubleTest(convert("foo % G"), val, "foo 2560", "foo 2560");
+ DoDoubleTest(convert("foo %+G"), neg, "foo -2560", "foo -2560");
+ DoDoubleTest(convert("foo % G"), neg, "foo -2560", "foo -2560");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/fwprintf/test18/testinfo.dat b/src/pal/tests/palsuite/c_runtime/fwprintf/test18/testinfo.dat
new file mode 100644
index 0000000000..23f621733b
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fwprintf/test18/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = fwprintf
+Name = Positive Test for fwprintf
+TYPE = DEFAULT
+EXE1 = test18
+Description
+= Tests the uppercase shorthand notation double specifier (%G).
+= This test is modeled after the sprintf series.
diff --git a/src/pal/tests/palsuite/c_runtime/fwprintf/test19/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/fwprintf/test19/CMakeLists.txt
new file mode 100644
index 0000000000..bc10825ce1
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fwprintf/test19/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test19.c
+)
+
+add_executable(paltest_fwprintf_test19
+ ${SOURCES}
+)
+
+add_dependencies(paltest_fwprintf_test19 coreclrpal)
+
+target_link_libraries(paltest_fwprintf_test19
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/fwprintf/test19/test19.c b/src/pal/tests/palsuite/c_runtime/fwprintf/test19/test19.c
new file mode 100644
index 0000000000..4600de7fa9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fwprintf/test19/test19.c
@@ -0,0 +1,81 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test19.c
+**
+** Purpose: Tests the variable length precision argument.
+** This test is modeled after the sprintf series.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+#include "../fwprintf.h"
+
+/*
+ * Depends on memcmp, strlen, fopen, fseek and fgets.
+ */
+
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ int n = -1;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return(FAIL);
+ }
+
+ DoArgumentPrecTest(convert("%.*s"), 2, convert("bar"), "bar", "ba", "ba");
+ DoArgumentPrecTest(convert("%.*S"), 2, "bar", "bar", "ba", "ba");
+ DoArgumentPrecTest(convert("foo %.*n"), 3, &n, "pointer to int", "foo ",
+ "foo ");
+ if (n != 4)
+ {
+ Fail("ERROR: Expected count parameter to resolve to %d, got %X\n",
+ 4, n);
+ }
+
+ DoArgumentPrecTest(convert("%.*c"), 0, (void*)'a', "a", "a", "a");
+ DoArgumentPrecTest(convert("%.*c"), 4, (void*)'a', "a", "a", "a");
+ DoArgumentPrecTest(convert("%.*C"), 0, (void*)'a', "a", "a", "a");
+ DoArgumentPrecTest(convert("%.*C"), 4, (void*)'a', "a", "a", "a");
+ DoArgumentPrecTest(convert("%.*d"), 1, (void*)42, "42", "42", "42");
+ DoArgumentPrecTest(convert("%.*d"), 3, (void*)42, "42", "042", "042");
+ DoArgumentPrecTest(convert("%.*i"), 1, (void*)42, "42", "42", "42");
+ DoArgumentPrecTest(convert("%.*i"), 3, (void*)42, "42", "042", "042");
+ DoArgumentPrecTest(convert("%.*o"), 1, (void*)42, "42", "52", "52");
+ DoArgumentPrecTest(convert("%.*o"), 3, (void*)42, "42", "052", "052");
+ DoArgumentPrecTest(convert("%.*u"), 1, (void*)42, "42", "42", "42");
+ DoArgumentPrecTest(convert("%.*u"), 3, (void*)42, "42", "042", "042");
+ DoArgumentPrecTest(convert("%.*x"), 1, (void*)0x42, "0x42", "42", "42");
+ DoArgumentPrecTest(convert("%.*x"), 3, (void*)0x42, "0x42", "042", "042");
+ DoArgumentPrecTest(convert("%.*X"), 1, (void*)0x42, "0x42", "42", "42");
+ DoArgumentPrecTest(convert("%.*X"), 3, (void*)0x42, "0x42", "042", "042");
+
+
+ DoArgumentPrecDoubleTest(convert("%.*e"), 1, 2.01, "2.0e+000", "2.0e+00");
+ DoArgumentPrecDoubleTest(convert("%.*e"), 3, 2.01, "2.010e+000",
+ "2.010e+00");
+ DoArgumentPrecDoubleTest(convert("%.*E"), 1, 2.01, "2.0E+000", "2.0E+00");
+ DoArgumentPrecDoubleTest(convert("%.*E"), 3, 2.01, "2.010E+000",
+ "2.010E+00");
+ DoArgumentPrecDoubleTest(convert("%.*f"), 1, 2.01, "2.0", "2.0");
+ DoArgumentPrecDoubleTest(convert("%.*f"), 3, 2.01, "2.010", "2.010");
+ DoArgumentPrecDoubleTest(convert("%.*g"), 1, 256.01, "3e+002", "3e+02");
+ DoArgumentPrecDoubleTest(convert("%.*g"), 3, 256.01, "256", "256");
+ DoArgumentPrecDoubleTest(convert("%.*g"), 4, 256.01, "256", "256");
+ DoArgumentPrecDoubleTest(convert("%.*g"), 6, 256.01, "256.01", "256.01");
+ DoArgumentPrecDoubleTest(convert("%.*G"), 1, 256.01, "3E+002", "3E+02");
+ DoArgumentPrecDoubleTest(convert("%.*G"), 3, 256.01, "256", "256");
+ DoArgumentPrecDoubleTest(convert("%.*G"), 4, 256.01, "256", "256");
+ DoArgumentPrecDoubleTest(convert("%.*G"), 6, 256.01, "256.01", "256.01");
+
+ PAL_Terminate();
+
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/fwprintf/test19/testinfo.dat b/src/pal/tests/palsuite/c_runtime/fwprintf/test19/testinfo.dat
new file mode 100644
index 0000000000..24aa8778c3
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fwprintf/test19/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = fwprintf
+Name = Positive Test for fwprintf
+TYPE = DEFAULT
+EXE1 = test19
+Description
+= Tests the variable length precision argument.
+= This test is modeled after the sprintf series.
diff --git a/src/pal/tests/palsuite/c_runtime/fwprintf/test2/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/fwprintf/test2/CMakeLists.txt
new file mode 100644
index 0000000000..64314651c0
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fwprintf/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test2.c
+)
+
+add_executable(paltest_fwprintf_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_fwprintf_test2 coreclrpal)
+
+target_link_libraries(paltest_fwprintf_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/fwprintf/test2/test2.c b/src/pal/tests/palsuite/c_runtime/fwprintf/test2/test2.c
new file mode 100644
index 0000000000..ecd3c513df
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fwprintf/test2/test2.c
@@ -0,0 +1,45 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test2.c
+**
+** Purpose: Tests the string specifier (%s).
+** This test is modeled after the sprintf series.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+#include "../fwprintf.h"
+
+/*
+ * Depends on memcmp, strlen, fopen, fseek and fgets.
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return(FAIL);
+ }
+
+ DoWStrTest(convert("foo %s"), convert("bar"), "foo bar");
+ DoStrTest(convert("foo %hs"), "bar", "foo bar");
+ DoWStrTest(convert("foo %ls"), convert("bar"), "foo bar");
+ DoWStrTest(convert("foo %ws"), convert("bar"), "foo bar");
+ DoWStrTest(convert("foo %Ls"), convert("bar"), "foo bar");
+ DoWStrTest(convert("foo %I64s"), convert("bar"), "foo bar");
+ DoWStrTest(convert("foo %5s"), convert("bar"), "foo bar");
+ DoWStrTest(convert("foo %.2s"), convert("bar"), "foo ba");
+ DoWStrTest(convert("foo %5.2s"), convert("bar"), "foo ba");
+ DoWStrTest(convert("foo %-5s"), convert("bar"), "foo bar ");
+ DoWStrTest(convert("foo %05s"), convert("bar"), "foo 00bar");
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/fwprintf/test2/testinfo.dat b/src/pal/tests/palsuite/c_runtime/fwprintf/test2/testinfo.dat
new file mode 100644
index 0000000000..1933682f24
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fwprintf/test2/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = fwprintf
+Name = Positive Test for fwprintf
+TYPE = DEFAULT
+EXE1 = test2
+Description
+= Tests the string specifier (%s).
+= This test is modeled after the sprintf series.
diff --git a/src/pal/tests/palsuite/c_runtime/fwprintf/test3/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/fwprintf/test3/CMakeLists.txt
new file mode 100644
index 0000000000..6906722cde
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fwprintf/test3/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test3.c
+)
+
+add_executable(paltest_fwprintf_test3
+ ${SOURCES}
+)
+
+add_dependencies(paltest_fwprintf_test3 coreclrpal)
+
+target_link_libraries(paltest_fwprintf_test3
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/fwprintf/test3/test3.c b/src/pal/tests/palsuite/c_runtime/fwprintf/test3/test3.c
new file mode 100644
index 0000000000..d718a19067
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fwprintf/test3/test3.c
@@ -0,0 +1,45 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test3.c
+**
+** Purpose: Tests the wide string specifier (%S).
+** This test is modeled after the sprintf series.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+#include "../fwprintf.h"
+
+/*
+ * Depends on memcmp, strlen, fopen, fseek and fgets.
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return(FAIL);
+ }
+
+ DoStrTest(convert("foo %S"), "bar", "foo bar");
+ DoStrTest(convert("foo %hS"), "bar", "foo bar");
+ DoWStrTest(convert("foo %lS"), convert("bar"), "foo bar");
+ DoWStrTest(convert("foo %wS"), convert("bar"), "foo bar");
+ DoStrTest(convert("foo %LS"), "bar", "foo bar");
+ DoStrTest(convert("foo %I64S"), "bar", "foo bar");
+ DoStrTest(convert("foo %5S"), "bar", "foo bar");
+ DoStrTest(convert("foo %.2S"), "bar", "foo ba");
+ DoStrTest(convert("foo %5.2S"),"bar", "foo ba");
+ DoStrTest(convert("foo %-5S"), "bar", "foo bar ");
+ DoStrTest(convert("foo %05S"), "bar", "foo 00bar");
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/fwprintf/test3/testinfo.dat b/src/pal/tests/palsuite/c_runtime/fwprintf/test3/testinfo.dat
new file mode 100644
index 0000000000..fa8a0bcf75
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fwprintf/test3/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = fwprintf
+Name = Positive Test for fwprintf
+TYPE = DEFAULT
+EXE1 = test3
+Description
+= Tests the wide string specifier (%S).
+= This test is modeled after the sprintf series.
diff --git a/src/pal/tests/palsuite/c_runtime/fwprintf/test4/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/fwprintf/test4/CMakeLists.txt
new file mode 100644
index 0000000000..b91bc87195
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fwprintf/test4/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test4.c
+)
+
+add_executable(paltest_fwprintf_test4
+ ${SOURCES}
+)
+
+add_dependencies(paltest_fwprintf_test4 coreclrpal)
+
+target_link_libraries(paltest_fwprintf_test4
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/fwprintf/test4/test4.c b/src/pal/tests/palsuite/c_runtime/fwprintf/test4/test4.c
new file mode 100644
index 0000000000..96fb472c3e
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fwprintf/test4/test4.c
@@ -0,0 +1,85 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test4.c
+**
+** Purpose: Tests the pointer specifier (%p).
+** This test is modeled after the sprintf series.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+#include "../fwprintf.h"
+
+/*
+ * Depends on memcmp, strlen, fopen, fseek and fgets.
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ void *ptr = (void*) 0x123456;
+ INT64 lptr = I64(0x1234567887654321);
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return(FAIL);
+ }
+
+/*
+** Run only on 64 bit platforms
+*/
+#if defined(BIT64) && defined(PLATFORM_UNIX)
+ Trace("Testing for 64 Bit Platforms \n");
+ DoPointerTest(convert("%p"), NULL, "NULL", "0000000000000000", "0x0");
+ DoPointerTest(convert("%p"), ptr, "pointer to 0x123456", "0000000000123456",
+ "0x123456");
+ DoPointerTest(convert("%17p"), ptr, "pointer to 0x123456", " 0000000000123456",
+ " 0x123456");
+ DoPointerTest(convert("%17p"), ptr, "pointer to 0x123456", " 0000000000123456",
+ "0x0123456");
+ DoPointerTest(convert("%-17p"), ptr, "pointer to 0x123456", "0000000000123456 ",
+ "0x123456 ");
+ DoPointerTest(convert("%+p"), ptr, "pointer to 0x123456", "0000000000123456",
+ "0x123456");
+ DoPointerTest(convert("%#p"), ptr, "pointer to 0x123456", "0X0000000000123456",
+ "0x123456");
+ DoPointerTest(convert("%lp"), ptr, "pointer to 0x123456", "00123456",
+ "0x123456");
+ DoPointerTest(convert("%hp"), ptr, "pointer to 0x123456", "00003456",
+ "0x3456");
+ DoPointerTest(convert("%Lp"), ptr, "pointer to 0x123456", "00123456",
+ "0x123456");
+ DoI64Test(convert("%I64p"), lptr, "pointer to 0x1234567887654321",
+ "1234567887654321", "0x1234567887654321");
+#else
+ Trace("Testing for Non 64 Bit Platforms \n");
+ DoPointerTest(convert("%p"), NULL, "NULL", "00000000", "0x0");
+ DoPointerTest(convert("%p"), ptr, "pointer to 0x123456", "00123456",
+ "0x123456");
+ DoPointerTest(convert("%9p"), ptr, "pointer to 0x123456", " 00123456",
+ " 0x123456");
+ DoPointerTest(convert("%09p"), ptr, "pointer to 0x123456", " 00123456",
+ "0x0123456");
+ DoPointerTest(convert("%-9p"), ptr, "pointer to 0x123456", "00123456 ",
+ "0x123456 ");
+ DoPointerTest(convert("%+p"), ptr, "pointer to 0x123456", "00123456",
+ "0x123456");
+ DoPointerTest(convert("%#p"), ptr, "pointer to 0x123456", "0X00123456",
+ "0x123456");
+ DoPointerTest(convert("%lp"), ptr, "pointer to 0x123456", "00123456",
+ "0x123456");
+ DoPointerTest(convert("%hp"), ptr, "pointer to 0x123456", "00003456",
+ "0x3456");
+ DoPointerTest(convert("%Lp"), ptr, "pointer to 0x123456", "00123456",
+ "0x123456");
+ DoI64Test(convert("%I64p"), lptr, "pointer to 0x1234567887654321",
+ "1234567887654321", "0x1234567887654321");
+#endif
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/fwprintf/test4/testinfo.dat b/src/pal/tests/palsuite/c_runtime/fwprintf/test4/testinfo.dat
new file mode 100644
index 0000000000..92140c29bb
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fwprintf/test4/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = fwprintf
+Name = Positive Test for fwprintf
+TYPE = DEFAULT
+EXE1 = test4
+Description
+= Tests the pointer specifier (%p).
+= This test is modeled after the sprintf series.
diff --git a/src/pal/tests/palsuite/c_runtime/fwprintf/test5/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/fwprintf/test5/CMakeLists.txt
new file mode 100644
index 0000000000..53bf482b6f
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fwprintf/test5/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test5.c
+)
+
+add_executable(paltest_fwprintf_test5
+ ${SOURCES}
+)
+
+add_dependencies(paltest_fwprintf_test5 coreclrpal)
+
+target_link_libraries(paltest_fwprintf_test5
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/fwprintf/test5/test5.c b/src/pal/tests/palsuite/c_runtime/fwprintf/test5/test5.c
new file mode 100644
index 0000000000..9d95989090
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fwprintf/test5/test5.c
@@ -0,0 +1,63 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test5.c
+**
+** Purpose: Tests the count specifier (%n).
+** This test is modeled after the sprintf series.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+#include "../fwprintf.h"
+
+/*
+ * Depends on memcmp, strlen, fopen, fseek and fgets.
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ WCHAR *longStr;
+ char *longResult =
+ "really-long-string-that-just-keeps-going-on-and-on-and-on.."
+ "..................useless-filler.................................."
+ "..................useless-filler.................................."
+ "..................useless-filler.................................."
+ " bar";
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ longStr =
+ convert("really-long-string-that-just-keeps-going-on-and-on-and-on.."
+ "..................useless-filler.................................."
+ "..................useless-filler.................................."
+ "..................useless-filler.................................."
+ "%n bar");
+ DoCountTest(convert("foo %n bar"), 4, "foo bar");
+ DoCountTest(longStr, 257, longResult);
+ DoCountTest(convert("fo%n bar"), 2, "fo bar");
+ DoCountTest(convert("%n foo"), 0, " foo");
+ DoCountTest(convert("foo %#n bar"), 4, "foo bar");
+ DoCountTest(convert("foo % n bar"), 4, "foo bar");
+ DoCountTest(convert("foo %+n bar"), 4, "foo bar");
+ DoCountTest(convert("foo %-n bar"), 4, "foo bar");
+ DoCountTest(convert("foo %0n bar"), 4, "foo bar");
+ DoShortCountTest(convert("foo %hn bar"), 4, "foo bar");
+ DoCountTest(convert("foo %ln bar"), 4, "foo bar");
+ DoCountTest(convert("foo %Ln bar"), 4, "foo bar");
+ DoCountTest(convert("foo %I64n bar"), 4, "foo bar");
+ DoCountTest(convert("foo %20.3n bar"), 4, "foo bar");
+
+ PAL_Terminate();
+
+ free(longStr);
+
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/fwprintf/test5/testinfo.dat b/src/pal/tests/palsuite/c_runtime/fwprintf/test5/testinfo.dat
new file mode 100644
index 0000000000..152f56334b
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fwprintf/test5/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = fwprintf
+Name = Positive Test for fwprintf
+TYPE = DEFAULT
+EXE1 = test5
+Description
+= Tests the count specifier (%n).
+= This test is modeled after the sprintf series.
diff --git a/src/pal/tests/palsuite/c_runtime/fwprintf/test6/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/fwprintf/test6/CMakeLists.txt
new file mode 100644
index 0000000000..bf7d7cccb8
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fwprintf/test6/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test6.c
+)
+
+add_executable(paltest_fwprintf_test6
+ ${SOURCES}
+)
+
+add_dependencies(paltest_fwprintf_test6 coreclrpal)
+
+target_link_libraries(paltest_fwprintf_test6
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/fwprintf/test6/test6.c b/src/pal/tests/palsuite/c_runtime/fwprintf/test6/test6.c
new file mode 100644
index 0000000000..160ff524e0
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fwprintf/test6/test6.c
@@ -0,0 +1,48 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test6.c
+**
+** Purpose: Tests the char specifier (%c).
+** This test is modeled after the sprintf series.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+#include "../fwprintf.h"
+
+/*
+ * Depends on memcmp, strlen, fopen, fseek and fgets.
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ WCHAR wb = (WCHAR) 'b';
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return(FAIL);
+ }
+
+ DoWCharTest(convert("foo %c"), wb, "foo b");
+ DoCharTest(convert("foo %hc"), 'c', "foo c");
+ DoWCharTest(convert("foo %lc"), wb, "foo b");
+ DoWCharTest(convert("foo %Lc"), wb, "foo b");
+ DoWCharTest(convert("foo %I64c"), wb, "foo b");
+ DoWCharTest(convert("foo %5c"), wb, "foo b");
+ DoWCharTest(convert("foo %.0c"), wb, "foo b");
+ DoWCharTest(convert("foo %-5c"), wb, "foo b ");
+ DoWCharTest(convert("foo %05c"), wb, "foo 0000b");
+ DoWCharTest(convert("foo % c"), wb, "foo b");
+ DoWCharTest(convert("foo %#c"), wb, "foo b");
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/fwprintf/test6/testinfo.dat b/src/pal/tests/palsuite/c_runtime/fwprintf/test6/testinfo.dat
new file mode 100644
index 0000000000..cc968bdf7f
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fwprintf/test6/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = fwprintf
+Name = Positive Test for fwprintf
+TYPE = DEFAULT
+EXE1 = test6
+Description
+= Tests the char specifier (%c).
+= This test is modeled after the sprintf series.
diff --git a/src/pal/tests/palsuite/c_runtime/fwprintf/test7/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/fwprintf/test7/CMakeLists.txt
new file mode 100644
index 0000000000..68bcc9ca65
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fwprintf/test7/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test7.c
+)
+
+add_executable(paltest_fwprintf_test7
+ ${SOURCES}
+)
+
+add_dependencies(paltest_fwprintf_test7 coreclrpal)
+
+target_link_libraries(paltest_fwprintf_test7
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/fwprintf/test7/test7.c b/src/pal/tests/palsuite/c_runtime/fwprintf/test7/test7.c
new file mode 100644
index 0000000000..c5515a8640
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fwprintf/test7/test7.c
@@ -0,0 +1,47 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test7.c
+**
+** Purpose: Tests the wide char specifier (%C).
+** This test is modeled after the sprintf series.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+#include "../fwprintf.h"
+
+/*
+ * Depends on memcmp, strlen, fopen, fseek and fgets.
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ WCHAR wb = (WCHAR) 'b';
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ DoCharTest(convert("foo %C"), 'c', "foo c");
+ DoWCharTest(convert("foo %hc"), wb, "foo b");
+ DoCharTest(convert("foo %lC"), 'c', "foo c");
+ DoCharTest(convert("foo %LC"), 'c', "foo c");
+ DoCharTest(convert("foo %I64C"), 'c', "foo c");
+ DoCharTest(convert("foo %5C"), 'c', "foo c");
+ DoCharTest(convert("foo %.0C"), 'c', "foo c");
+ DoCharTest(convert("foo %-5C"), 'c', "foo c ");
+ DoCharTest(convert("foo %05C"), 'c', "foo 0000c");
+ DoCharTest(convert("foo % C"), 'c', "foo c");
+ DoCharTest(convert("foo %#C"), 'c', "foo c");
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/fwprintf/test7/testinfo.dat b/src/pal/tests/palsuite/c_runtime/fwprintf/test7/testinfo.dat
new file mode 100644
index 0000000000..46cb35cf4b
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fwprintf/test7/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = fwprintf
+Name = Positive Test for fwprintf
+TYPE = DEFAULT
+EXE1 = test7
+Description
+= Tests the wide char specifier (%C).
+= This test is modeled after the sprintf series.
diff --git a/src/pal/tests/palsuite/c_runtime/fwprintf/test8/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/fwprintf/test8/CMakeLists.txt
new file mode 100644
index 0000000000..e07cbb9119
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fwprintf/test8/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test8.c
+)
+
+add_executable(paltest_fwprintf_test8
+ ${SOURCES}
+)
+
+add_dependencies(paltest_fwprintf_test8 coreclrpal)
+
+target_link_libraries(paltest_fwprintf_test8
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/fwprintf/test8/test8.c b/src/pal/tests/palsuite/c_runtime/fwprintf/test8/test8.c
new file mode 100644
index 0000000000..efc81a954a
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fwprintf/test8/test8.c
@@ -0,0 +1,51 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test8.c
+**
+** Purpose: Tests the decimal specifier (%d).
+** This test is modeled after the sprintf series.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+#include "../fwprintf.h"
+
+/*
+ * Depends on memcmp, strlen, fopen, fseek and fgets.
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ int neg = -42;
+ int pos = 42;
+ INT64 l = 42;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return(FAIL);
+ }
+
+ DoNumTest(convert("foo %d"), pos, "foo 42");
+ DoNumTest(convert("foo %ld"), 0xFFFF, "foo 65535");
+ DoNumTest(convert("foo %hd"), 0xFFFF, "foo -1");
+ DoNumTest(convert("foo %Ld"), pos, "foo 42");
+ DoI64Test(convert("foo %I64d"), l, "42", "foo 42", "foo 42");
+ DoNumTest(convert("foo %3d"), pos, "foo 42");
+ DoNumTest(convert("foo %-3d"), pos, "foo 42 ");
+ DoNumTest(convert("foo %.1d"), pos, "foo 42");
+ DoNumTest(convert("foo %.3d"), pos, "foo 042");
+ DoNumTest(convert("foo %03d"), pos, "foo 042");
+ DoNumTest(convert("foo %#d"), pos, "foo 42");
+ DoNumTest(convert("foo %+d"), pos, "foo +42");
+ DoNumTest(convert("foo % d"), pos, "foo 42");
+ DoNumTest(convert("foo %+d"), neg, "foo -42");
+ DoNumTest(convert("foo % d"), neg, "foo -42");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/fwprintf/test8/testinfo.dat b/src/pal/tests/palsuite/c_runtime/fwprintf/test8/testinfo.dat
new file mode 100644
index 0000000000..c8ce33acb9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fwprintf/test8/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = fwprintf
+Name = Positive Test for fwprintf
+TYPE = DEFAULT
+EXE1 = test8
+Description
+= Tests the decimal specifier (%d).
+= This test is modeled after the sprintf series.
diff --git a/src/pal/tests/palsuite/c_runtime/fwprintf/test9/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/fwprintf/test9/CMakeLists.txt
new file mode 100644
index 0000000000..898da1a64f
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fwprintf/test9/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test9.c
+)
+
+add_executable(paltest_fwprintf_test9
+ ${SOURCES}
+)
+
+add_dependencies(paltest_fwprintf_test9 coreclrpal)
+
+target_link_libraries(paltest_fwprintf_test9
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/fwprintf/test9/test9.c b/src/pal/tests/palsuite/c_runtime/fwprintf/test9/test9.c
new file mode 100644
index 0000000000..23db2d8971
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fwprintf/test9/test9.c
@@ -0,0 +1,51 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test9.c
+**
+** Purpose: Tests the integer specifier (%i).
+** This test is modeled after the sprintf series.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+#include "../fwprintf.h"
+
+/*
+ * Depends on memcmp, strlen, fopen, fseek and fgets.
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ int neg = -42;
+ int pos = 42;
+ INT64 l = 42;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return(FAIL);
+ }
+
+ DoNumTest(convert("foo %i"), pos, "foo 42");
+ DoNumTest(convert("foo %li"), 0xFFFF, "foo 65535");
+ DoNumTest(convert("foo %hi"), 0xFFFF, "foo -1");
+ DoNumTest(convert("foo %Li"), pos, "foo 42");
+ DoI64Test(convert("foo %I64i"), l, "42", "foo 42", "foo 42");
+ DoNumTest(convert("foo %3i"), pos, "foo 42");
+ DoNumTest(convert("foo %-3i"), pos, "foo 42 ");
+ DoNumTest(convert("foo %.1i"), pos, "foo 42");
+ DoNumTest(convert("foo %.3i"), pos, "foo 042");
+ DoNumTest(convert("foo %03i"), pos, "foo 042");
+ DoNumTest(convert("foo %#i"), pos, "foo 42");
+ DoNumTest(convert("foo %+i"), pos, "foo +42");
+ DoNumTest(convert("foo % i"), pos, "foo 42");
+ DoNumTest(convert("foo %+i"), neg, "foo -42");
+ DoNumTest(convert("foo % i"), neg, "foo -42");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/fwprintf/test9/testinfo.dat b/src/pal/tests/palsuite/c_runtime/fwprintf/test9/testinfo.dat
new file mode 100644
index 0000000000..5c2ec25ab5
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fwprintf/test9/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = fwprintf
+Name = Positive Test for fwprintf
+TYPE = DEFAULT
+EXE1 = test9
+Description
+= Tests the integer specifier (%i).
+= This test is modeled after the sprintf series.
diff --git a/src/pal/tests/palsuite/c_runtime/fwrite/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/fwrite/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fwrite/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/fwrite/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/fwrite/test1/CMakeLists.txt
new file mode 100644
index 0000000000..701e56acb5
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fwrite/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_fwrite_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_fwrite_test1 coreclrpal)
+
+target_link_libraries(paltest_fwrite_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/fwrite/test1/test1.c b/src/pal/tests/palsuite/c_runtime/fwrite/test1/test1.c
new file mode 100644
index 0000000000..392522879f
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fwrite/test1/test1.c
@@ -0,0 +1,104 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Write a short string to a file and check that it was written
+** properly.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char **argv)
+{
+ const char filename[] = "testfile.tmp";
+ const char outBuffer[] = "This is a test.";
+ char inBuffer[sizeof(outBuffer) + 10];
+ int itemsExpected;
+ int itemsWritten;
+ FILE * fp = NULL;
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ if((fp = fopen(filename, "w")) == NULL)
+ {
+ Fail("Unable to open a file for write.\n");
+ }
+
+ itemsExpected = sizeof(outBuffer);
+ itemsWritten = fwrite(outBuffer,
+ sizeof(outBuffer[0]),
+ sizeof(outBuffer),
+ fp);
+
+ if (itemsWritten == 0)
+ {
+ if(fclose(fp) != 0)
+ {
+ Fail("fwrite: Error occurred during the closing of a file.\n");
+ }
+
+ Fail("fwrite() couldn't write to a stream at all\n");
+ }
+ else if (itemsWritten != itemsExpected)
+ {
+ if(fclose(fp) != 0)
+ {
+ Fail("fwrite: Error occurred during the closing of a file.\n");
+ }
+
+ Fail("fwrite() produced errors writing to a stream.\n");
+ }
+
+ if(fclose(fp) != 0)
+ {
+ Fail("fwrite: Error occurred during the closing of a file.\n");
+ }
+
+ /* open the file to verify what was written to the file */
+ if ((fp = fopen(filename, "r")) == NULL)
+ {
+ Fail("Couldn't open newly written file for read.\n");
+ }
+
+ if (fgets(inBuffer, sizeof(inBuffer), fp) == NULL)
+ {
+ if(fclose(fp) != 0)
+ {
+ Fail("fwrite: Error occurred during the closing of a file.\n");
+ }
+
+ Fail("We wrote something to a file using fwrite() and got errors"
+ " when we tried to read it back using fgets(). Either "
+ "fwrite() or fgets() is broken.\n");
+ }
+
+ if (strcmp(inBuffer, outBuffer) != 0)
+ {
+ if(fclose(fp) != 0)
+ {
+ Fail("fwrite: Error occurred during the closing of a file.\n");
+ }
+
+ Fail("fwrite() (or fgets()) is broken. The string read back from"
+ " the file does not match the string written.\n");
+ }
+
+ if(fclose(fp) != 0)
+ {
+ Fail("fwrite: Error occurred during the closing of a file.\n");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/fwrite/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/fwrite/test1/testinfo.dat
new file mode 100644
index 0000000000..75ad9ed05d
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/fwrite/test1/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = fwrite
+Name = Positive Test for fwrite
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Write a short string to a file and check that it was written properly.
diff --git a/src/pal/tests/palsuite/c_runtime/getc/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/getc/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/getc/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/getc/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/getc/test1/CMakeLists.txt
new file mode 100644
index 0000000000..2a29e8af0a
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/getc/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ getc.c
+)
+
+add_executable(paltest_getc_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getc_test1 coreclrpal)
+
+target_link_libraries(paltest_getc_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/getc/test1/getc.c b/src/pal/tests/palsuite/c_runtime/getc/test1/getc.c
new file mode 100644
index 0000000000..dfe10d6160
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/getc/test1/getc.c
@@ -0,0 +1,152 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: getc.c (test 1)
+**
+** Purpose: Tests the PAL implementation of the getc function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ const char szFileName[] = {"testfile.tmp"};
+ const char szTestString[] =
+ {"The quick brown fox jumped over the lazy dog's back."};
+ FILE* pFile = NULL;
+ int nCount = 0;
+ int nChar = 0;
+ char szBuiltString[256];
+
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ memset(szBuiltString, 0, 256);
+
+
+ /* create/open a file for read and write */
+ pFile = fopen(szFileName, "w+");
+ if (pFile == NULL)
+ {
+ Fail("getc: ERROR -> fopen failed to create the file %s with the "
+ "error code %ld\n",
+ szFileName,
+ GetLastError());
+ }
+
+ /* try reading from an empty file */
+ if ((nChar = getc(pFile)) != EOF)
+ {
+ Trace("getc: ERROR -> getc returned \"%c\" when run on "
+ "an empty file.\n", nChar);
+ if (fclose(pFile) != 0)
+ {
+ Trace("getc: ERROR -> fclose failed to close the file. "
+ "GetLastError returned %ld\n",
+ GetLastError());
+ }
+ Fail("");
+ }
+
+ // Move the file pointer back to the beginning of the file. Some
+ // platforms require an fseek() between a getc() that returns EOF
+ // and any subsequent output to the file.
+ if (fseek(pFile, 0, SEEK_SET) != 0)
+ {
+ Trace("getc: ERROR -> fseek failed to move the file pointer to the "
+ "beginning of the file. GetLastError returned %ld\n",
+ GetLastError());
+ if (fclose(pFile) != 0)
+ {
+ Trace("getc: ERROR -> fclose failed to close the file. "
+ "GetLastError returned %ld\n",
+ GetLastError());
+ }
+ Fail("");
+ }
+
+ /* populate the file with a known string */
+ nCount = fprintf(pFile, szTestString);
+ if (nCount != strlen(szTestString))
+ {
+ Fail("getc: ERROR -> fprintf failed to write %s. The string is %d "
+ "characters long but fprintf apparently only wrote %d characters."
+ " GetLastError returned %ld\n",
+ szTestString,
+ strlen(szTestString),
+ nCount,
+ GetLastError());
+ }
+
+ /* move the file pointer back to the beginning of the file */
+ if (fseek(pFile, 0, SEEK_SET) != 0)
+ {
+ Trace("getc: ERROR -> fseek failed to move the file pointer to the "
+ "beginning of the file. GetLastError returned %ld\n",
+ GetLastError());
+ if (fclose(pFile) != 0)
+ {
+ Trace("getc: ERROR -> fclose failed to close the file. "
+ "GetLastError returned %ld\n",
+ GetLastError());
+ }
+ Fail("");
+ }
+
+ /* now get the characters one at a time */
+ nCount = 0;
+ while ((nChar = getc(pFile)) != EOF)
+ {
+ szBuiltString[nCount++] = nChar;
+ }
+
+ /* now, let's see if it worked */
+ if (strcmp(szBuiltString, szTestString) != 0)
+ {
+ Trace("getc: ERROR -> Reading one char at a time, getc built \"%s\" "
+ "however it should have built \"%s\".\n",
+ szBuiltString,
+ szTestString);
+ if (fclose(pFile) != 0)
+ {
+ Trace("getc: ERROR -> fclose failed to close the file. "
+ "GetLastError returned %ld\n",
+ GetLastError());
+ }
+ Fail("");
+ }
+
+ /* with the file pointer at EOF, try reading past EOF*/
+ if ((nChar = getc(pFile)) != EOF)
+ {
+ Trace("getc: ERROR -> getc returned \"%c\" when reading past "
+ "the end of the file.\n", nChar);
+ if (fclose(pFile) != 0)
+ {
+ Trace("getc: ERROR -> fclose failed to close the file. "
+ "GetLastError returned %ld\n",
+ GetLastError());
+ }
+ Fail("");
+ }
+
+ if (fclose(pFile) != 0)
+ {
+ Fail("getc: ERROR -> fclose failed to close the file. "
+ "GetLastError returned %ld\n",
+ GetLastError());
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/getc/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/getc/test1/testinfo.dat
new file mode 100644
index 0000000000..19a0c1ee1a
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/getc/test1/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = getc
+Name = test for getc (test 1)
+Type = DEFAULT
+EXE1 = getc
+Description
+= Write a string to a file, read it in one character
+= at a time with getc and compare with the original string.
+= It also verifies that getc can't read past EOF.
diff --git a/src/pal/tests/palsuite/c_runtime/getenv/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/getenv/CMakeLists.txt
new file mode 100644
index 0000000000..1962ade358
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/getenv/CMakeLists.txt
@@ -0,0 +1,6 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+add_subdirectory(test3)
+
diff --git a/src/pal/tests/palsuite/c_runtime/getenv/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/getenv/test1/CMakeLists.txt
new file mode 100644
index 0000000000..6243c032ab
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/getenv/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_getenv_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getenv_test1 coreclrpal)
+
+target_link_libraries(paltest_getenv_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/getenv/test1/test1.c b/src/pal/tests/palsuite/c_runtime/getenv/test1/test1.c
new file mode 100644
index 0000000000..0fb9025c8f
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/getenv/test1/test1.c
@@ -0,0 +1,78 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test1.c
+**
+** Purpose: Create an environment variable and then use getenv to get
+** a pointer to it. Check that the pointer is valid and that the string
+** is what we expected. Also check that searching for a non-existent
+** variable will cause getenv to return NULL. Also check that function
+** passes when the parameter has it's casing changed (e.g upper case)
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char **argv)
+{
+
+ const char* SetVariable = "PalTestingEnvironmentVariable=The value";
+ const char* VariableName = "PalTestingEnvironmentVariable";
+ const char* VariableValue = "The value";
+ char* result;
+
+
+ if (0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /* Use _putenv to set an environment variable. This ensures that the
+ variable we're testing on is always present.
+ */
+
+ if(_putenv(SetVariable) == -1)
+ {
+ Fail("ERROR: _putenv failed to set an environment variable that "
+ "getenv will be using for testing.\n");
+ }
+
+ /* Call getenv -- ensure it doesn't return NULL and the string it returns
+ is the value we set above.
+ */
+
+ result = getenv(VariableName);
+ if(result == NULL)
+ {
+ Fail("ERROR: The result of getenv on a valid Environment Variable "
+ "was NULL, which indicates the environment varaible was not "
+ "found.\n");
+ }
+
+ if(strcmp(result, VariableValue) != 0)
+ {
+ Fail("ERROR: The value obtained by getenv() was not equal to the "
+ "correct value of the environment variable. The correct "
+ "value is '%s' and the function returned '%s'.\n",
+ VariableValue,
+ result);
+ }
+
+ /* Try calling getenv on an environment variable which doesn't
+ exist.
+ */
+ result = getenv("SomeEnvironmentVariableThatReallyDoesNotExist");
+
+ if(result != NULL)
+ {
+ Fail("ERROR: Called getenv on an environment variable which "
+ "doesn't exist and it returned '%s' instead of NULL.\n",result);
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/getenv/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/getenv/test1/testinfo.dat
new file mode 100644
index 0000000000..b9cbf71986
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/getenv/test1/testinfo.dat
@@ -0,0 +1,16 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = getenv
+Name = Test retrieval of variables correctly, and failure if they don't exist
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Create an environment variable and then use getenv to get
+= a pointer to it. Check that the pointer is valid and that the string
+= is what we expected. Also check that searching for a non-existent
+= variable will cause getenv to return NULL. Also check that changing
+= the case (upper or lower) of a variable does not effect functionality.
diff --git a/src/pal/tests/palsuite/c_runtime/getenv/test2/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/getenv/test2/CMakeLists.txt
new file mode 100644
index 0000000000..7a301a5ca6
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/getenv/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test2.c
+)
+
+add_executable(paltest_getenv_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getenv_test2 coreclrpal)
+
+target_link_libraries(paltest_getenv_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/getenv/test2/test2.c b/src/pal/tests/palsuite/c_runtime/getenv/test2/test2.c
new file mode 100644
index 0000000000..26f245fcce
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/getenv/test2/test2.c
@@ -0,0 +1,101 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test2.c
+**
+** Purpose: Create environment variables that differ only in Case, and
+** verify that the BSD operating system treats the variables
+** differently.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char **argv)
+{
+#if WIN32
+
+ return PASS;
+
+#else
+
+ const char* FirstVariable = "PalTestingEnvironmentVariable=The value";
+ const char* SecondVariable = "PALTESTINGEnvironmentVariable=Different value";
+ const char* FirstVarName = "PalTestingEnvironmentVariable";
+ const char* SecondVarName = "PALTESTINGEnvironmentVariable";
+ const char* FirstVarValue = "The value";
+ const char* SecondVarValue = "Different value";
+ char* result;
+
+
+ if (0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /* Use _putenv to set the environment variables. This ensures that the
+ variables we're testing with are always present.
+ */
+ if(_putenv(FirstVariable) != 0)
+ {
+ Fail("ERROR: _putenv failed to set an environment variable that "
+ "getenv will be using for testing.\n");
+ }
+
+ if(_putenv(SecondVariable) != 0)
+ {
+ Fail("ERROR: _putenv failed to set an environment variable that "
+ "getenv will be using for testing.\n");
+ }
+
+
+ /* Call getenv -- ensure it doesn't return NULL and the string it returns
+ is the value we set above. Also make sure that each environment variable,
+ differing only by case, returns it's own value.
+ */
+
+ result = getenv(FirstVarName);
+ if(result == NULL)
+ {
+ Fail("ERROR: The result of getenv on a valid Environment Variable "
+ "was NULL, which indicates the environment varaible was not "
+ "found.\n");
+ }
+
+ if(strcmp(result, FirstVarValue) != 0)
+ {
+ Fail("ERROR: The value obtained by getenv() was not equal to the "
+ "correct value of the environment variable. The correct "
+ "value is '%s' and the function returned '%s'.\n",
+ FirstVarValue,
+ result);
+ }
+
+
+ result = getenv(SecondVarName);
+ if(result == NULL)
+ {
+ Fail("ERROR: The result of getenv on a valid Environment Variable "
+ "was NULL, which indicates the environment varaible was not "
+ "found.\n");
+ }
+
+ if(strcmp(result, SecondVarValue) != 0)
+ {
+ Fail("ERROR: The value obtained by getenv() was not equal to the "
+ "correct value of the environment variable. The correct "
+ "value is '%s' and the function returned '%s'.\n",
+ SecondVarValue,
+ result);
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+
+#endif
+}
diff --git a/src/pal/tests/palsuite/c_runtime/getenv/test2/testinfo.dat b/src/pal/tests/palsuite/c_runtime/getenv/test2/testinfo.dat
new file mode 100644
index 0000000000..90a4ac5aff
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/getenv/test2/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = getenv
+Name = Test retrieval of variables differing only by case.
+TYPE = DEFAULT
+EXE1 = test2
+Description
+= Check that environment variables differing only by their
+= case are interpreted as separate variables by the BSD Operationg
+= System.
diff --git a/src/pal/tests/palsuite/c_runtime/getenv/test3/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/getenv/test3/CMakeLists.txt
new file mode 100644
index 0000000000..2cbe472221
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/getenv/test3/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test3.c
+)
+
+add_executable(paltest_getenv_test3
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getenv_test3 coreclrpal)
+
+target_link_libraries(paltest_getenv_test3
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/getenv/test3/test3.c b/src/pal/tests/palsuite/c_runtime/getenv/test3/test3.c
new file mode 100644
index 0000000000..1eefd9d40c
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/getenv/test3/test3.c
@@ -0,0 +1,75 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test3.c
+**
+** Purpose: Create an environment variable and try to retrieve
+** it using the same name but with different case. This
+** is to show that the Win32 representation of getenv
+** is case insensitive.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char **argv)
+{
+#if WIN32
+
+ const char* FirstVariable = "PalTestingEnvironmentVariable=The value";
+ const char* ModifiedName = "PALTESTINGEnvironmentVariable";
+ const char* FirstVarValue = "The value";
+ char* result;
+
+
+ if (0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /* Use _putenv to set an environment variable. This ensures that the
+ variable we're testing on is always present.
+ */
+
+ if(_putenv(FirstVariable) != 0)
+ {
+ Fail("ERROR: _putenv failed to set an environment variable that "
+ "getenv will be using for testing.\n");
+ }
+
+
+ /* Call getenv -- ensure it doesn't return NULL and the string it returns
+ is the value we set above. Also make sure that each environment variable,
+ differing only by case, doesn't affect the return value.
+ */
+
+ result = getenv(ModifiedName);
+ if(result == NULL)
+ {
+ Fail("ERROR: The result of getenv on a valid Environment Variable "
+ "was NULL, which indicates the environment varaible was not "
+ "found.\n");
+ }
+
+ if(strcmp(result, FirstVarValue) != 0)
+ {
+ Fail("ERROR: The value obtained by getenv() was not equal to the "
+ "correct value of the environment variable. The correct "
+ "value is '%s' and the function returned '%s'.\n",
+ FirstVarValue,
+ result);
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+
+#else
+ return PASS;
+
+#endif
+}
diff --git a/src/pal/tests/palsuite/c_runtime/getenv/test3/testinfo.dat b/src/pal/tests/palsuite/c_runtime/getenv/test3/testinfo.dat
new file mode 100644
index 0000000000..6e12fc4385
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/getenv/test3/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = getenv
+Name = Test retrieval of variables differing only by case.
+TYPE = DEFAULT
+EXE1 = test3
+Description
+= Check that environment variables differing only by their
+= case are interpreted as the same variables in the WIN32
+= platform.
diff --git a/src/pal/tests/palsuite/c_runtime/isalnum/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/isalnum/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/isalnum/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/isalnum/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/isalnum/test1/CMakeLists.txt
new file mode 100644
index 0000000000..3879bb7902
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/isalnum/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_isalnum_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_isalnum_test1 coreclrpal)
+
+target_link_libraries(paltest_isalnum_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/isalnum/test1/test1.c b/src/pal/tests/palsuite/c_runtime/isalnum/test1/test1.c
new file mode 100644
index 0000000000..d9cdfcadf6
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/isalnum/test1/test1.c
@@ -0,0 +1,88 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test1.c
+**
+** Purpose: Tests the PAL implementation of the isalnum function
+** Check that a number of characters return the correct
+** values for whether they are alpha/numeric or not.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+
+struct testCase
+{
+ int CorrectResult;
+ int character;
+};
+
+int __cdecl main(int argc, char **argv)
+{
+
+ int result;
+ int i;
+
+ struct testCase testCases[] =
+ {
+ {1, 'a'},
+ {1, 'z'},
+ {1, 'B'},
+ {1, '5'},
+ {1, '0'},
+ {0, '?'},
+ {0, 230}
+ };
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ /* Loop through each case. Check to see if each is alpha/numeric or
+ not.
+ */
+
+ for(i = 0; i < sizeof(testCases) / sizeof(struct testCase); i++)
+ {
+
+ result = isalnum(testCases[i].character);
+
+ /* The return value is 'non-zero' for success. This if condition
+ * will still work if that non-zero isn't just 1
+ */
+ if ( ((testCases[i].CorrectResult == 1) && (result == 0)) ||
+ ( (testCases[i].CorrectResult == 0) && (result != 0) ))
+ {
+ Fail("ERROR: isalnum returned %i instead of %i for character "
+ " %c.\n",
+ result,
+ testCases[i].CorrectResult,
+ testCases[i].character);
+ }
+
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/isalnum/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/isalnum/test1/testinfo.dat
new file mode 100644
index 0000000000..ba8f07a722
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/isalnum/test1/testinfo.dat
@@ -0,0 +1,19 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = isalnum
+Name = Positive Test for isalnum
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Tests the PAL implementation of the isalnum function
+= Check that a number of characters return the correct values for whether
+= they are alpha/numeric or not.
+
+
+
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/isalpha/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/isalpha/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/isalpha/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/isalpha/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/isalpha/test1/CMakeLists.txt
new file mode 100644
index 0000000000..44fb72d7fe
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/isalpha/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_isalpha_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_isalpha_test1 coreclrpal)
+
+target_link_libraries(paltest_isalpha_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/isalpha/test1/test1.c b/src/pal/tests/palsuite/c_runtime/isalpha/test1/test1.c
new file mode 100644
index 0000000000..b494d14a92
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/isalpha/test1/test1.c
@@ -0,0 +1,86 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test1.c
+**
+** Purpose: Tests the PAL implementation of the isalpha function
+** Check that a number of characters return the correct
+** values for whether they are alpha or not.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+struct testCase
+{
+ int CorrectResult;
+ int character;
+};
+
+int __cdecl main(int argc, char **argv)
+{
+
+ int result;
+ int i;
+
+ struct testCase testCases[] =
+ {
+ {1, 'a'},
+ {1, 'z'},
+ {1, 'B'},
+ {0, '5'},
+ {0, '?'},
+ {0, 230}
+ };
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ /* Loop through each case. Check to see if each is alpha or
+ not.
+ */
+
+ for(i = 0; i < sizeof(testCases) / sizeof(struct testCase); i++)
+ {
+
+ result = isalpha(testCases[i].character);
+
+ /* The return value is 'non-zero' for success. This if condition
+ * will still work if that non-zero isn't just 1
+ */
+ if ( ((testCases[i].CorrectResult == 1) && (result == 0)) ||
+ ( (testCases[i].CorrectResult == 0) && (result != 0) ))
+ {
+ Fail("ERROR: isalpha returned %i instead of %i for character "
+ "%c.\n",
+ result,
+ testCases[i].CorrectResult,
+ testCases[i].character);
+ }
+
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/isalpha/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/isalpha/test1/testinfo.dat
new file mode 100644
index 0000000000..7d508366e8
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/isalpha/test1/testinfo.dat
@@ -0,0 +1,19 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = isalpha
+Name = Positive Test for isalpha
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Tests the PAL implementation of the isalpha function
+= Check that a number of characters return the correct values for whether
+= they are alpha or not.
+
+
+
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/isdigit/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/isdigit/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/isdigit/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/isdigit/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/isdigit/test1/CMakeLists.txt
new file mode 100644
index 0000000000..dd03b238e1
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/isdigit/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_isdigit_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_isdigit_test1 coreclrpal)
+
+target_link_libraries(paltest_isdigit_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/isdigit/test1/test1.c b/src/pal/tests/palsuite/c_runtime/isdigit/test1/test1.c
new file mode 100644
index 0000000000..ad2344827f
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/isdigit/test1/test1.c
@@ -0,0 +1,47 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Checks every character against the known range of digits.
+**
+**
+**==========================================================================*/
+
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ int i;
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ for (i=0; i<256; i++)
+ {
+ if (isdigit(i))
+ {
+ if (i < '0' || i > '9')
+ {
+ Fail("ERROR: isdigit returned true for '%c' (%d)!\n", i, i);
+ }
+ }
+ else
+ {
+ if (i >= '0' && i <= '9')
+ {
+ Fail("ERROR: isdigit returned false for '%c' (%d)!\n", i, i);
+ }
+ }
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/isdigit/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/isdigit/test1/testinfo.dat
new file mode 100644
index 0000000000..eb23739164
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/isdigit/test1/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = isdigit
+Name = Test #1 for isdigit
+TYPE = DEFAULT
+EXE1 = test1
+Description
+=Checks every character against the known range of digits.
diff --git a/src/pal/tests/palsuite/c_runtime/islower/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/islower/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/islower/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/islower/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/islower/test1/CMakeLists.txt
new file mode 100644
index 0000000000..b7f5ad069f
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/islower/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_islower_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_islower_test1 coreclrpal)
+
+target_link_libraries(paltest_islower_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/islower/test1/test1.c b/src/pal/tests/palsuite/c_runtime/islower/test1/test1.c
new file mode 100644
index 0000000000..c8e877b705
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/islower/test1/test1.c
@@ -0,0 +1,85 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test1.c
+**
+** Purpose: Tests the PAL implementation of the islower function
+** Check that a number of characters return the correct
+** values for whether they are lower case or not.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+struct testCase
+{
+ int CorrectResult;
+ int character;
+};
+
+int __cdecl main(int argc, char **argv)
+{
+
+ int result;
+ int i;
+
+ struct testCase testCases[] =
+ {
+ {1, 'a'}, /* Basic cases */
+ {1, 'z'},
+ {0, 'B'}, /* Lower case */
+ {0, '?'}, /* Characters without case */
+ {0, 230},
+ {0, '5'}
+ };
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ /* Loop through each case. Check to see if each is lower case or
+ not.
+ */
+
+ for(i = 0; i < sizeof(testCases) / sizeof(struct testCase); i++)
+ {
+
+ result = islower(testCases[i].character);
+
+ /* The return value is 'non-zero' for success. This if condition
+ * will still work if that non-zero isn't just 1
+ */
+ if ( ((testCases[i].CorrectResult == 1) && (result == 0)) ||
+ ( (testCases[i].CorrectResult == 0) && (result != 0) ))
+ {
+ Fail("ERROR: islower returned %i instead of %i for "
+ "character %c.\n",
+ result, testCases[i].CorrectResult,
+ testCases[i].character);
+ }
+
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/islower/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/islower/test1/testinfo.dat
new file mode 100644
index 0000000000..49a6fb761d
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/islower/test1/testinfo.dat
@@ -0,0 +1,19 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = islower
+Name = Positive Test for islower
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Tests the PAL implementation of the islower function
+= Check that a number of characters return the correct values for whether
+= they are lower case or not.
+
+
+
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/isprint/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/isprint/CMakeLists.txt
new file mode 100644
index 0000000000..ef14ea5352
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/isprint/CMakeLists.txt
@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+
diff --git a/src/pal/tests/palsuite/c_runtime/isprint/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/isprint/test1/CMakeLists.txt
new file mode 100644
index 0000000000..365777ab5a
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/isprint/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ isprint.c
+)
+
+add_executable(paltest_isprint_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_isprint_test1 coreclrpal)
+
+target_link_libraries(paltest_isprint_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/isprint/test1/isprint.c b/src/pal/tests/palsuite/c_runtime/isprint/test1/isprint.c
new file mode 100644
index 0000000000..54db666bf2
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/isprint/test1/isprint.c
@@ -0,0 +1,42 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: isprint.c
+**
+** Purpose: Positive test the isprint API.
+** Call isprint to test if a character is printable
+**
+**
+**============================================================*/
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ int err;
+ int index;
+
+ /*Initialize the PAL environment*/
+ err = PAL_Initialize(argc, argv);
+ if(0 != err)
+ {
+ return FAIL;
+ }
+
+ /*check if the character is printable*/
+ for(index = 0x20; index<=0x7E;index++)
+ {
+ err = isprint(index);
+ if(0 == err)
+ {
+ Fail("\nFailed to call isprint API to check "
+ "printable character from 0x20 to 0x7E!\n");
+ }
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/isprint/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/isprint/test1/testinfo.dat
new file mode 100644
index 0000000000..c9b9ec07ea
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/isprint/test1/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = miscellaneous
+Function = isprint
+Name = Positive test for isprint API to check if a character is printable
+TYPE = DEFAULT
+EXE1 = isprint
+Description
+=Test the isprint to check if a character is printable
diff --git a/src/pal/tests/palsuite/c_runtime/isprint/test2/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/isprint/test2/CMakeLists.txt
new file mode 100644
index 0000000000..a7ad75cc04
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/isprint/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test2.c
+)
+
+add_executable(paltest_isprint_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_isprint_test2 coreclrpal)
+
+target_link_libraries(paltest_isprint_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/isprint/test2/test2.c b/src/pal/tests/palsuite/c_runtime/isprint/test2/test2.c
new file mode 100644
index 0000000000..2170c47a14
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/isprint/test2/test2.c
@@ -0,0 +1,59 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: isprint.c
+**
+** Purpose: Negative test for the isprint API. Call isprint
+** to test if out of range characters are
+** not printable.
+**
+**
+**============================================================*/
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ int err;
+
+ /*Initialize the PAL environment*/
+ err = PAL_Initialize(argc, argv);
+ if(0 != err)
+ {
+ return FAIL;
+ }
+
+ /*check that function fails for values that are not printable*/
+ err = isprint(0x15);
+ if(err)
+ {
+ Fail("\nSucceeded when it should have failed because 0x15 "
+ "is not in the range of printable characters\n");
+ }
+
+ err = isprint(0xAA);
+ if(err)
+ {
+ Fail("\nSucceeded when it should have failed because 0xAA "
+ "is not in the range of printable characters\n");
+ }
+
+ /* check carriage return */
+ if(0 != isprint(0x0d))
+ {
+ Fail("\nSucceeded when it should have failed because 0x0d "
+ "is not in the range of printable characters\n");
+ }
+
+ /* check line feed */
+ if(0 != isprint(0x0a))
+ {
+ Fail("\nSucceeded when it should have failed because 0x0a "
+ "is not in the range of printable characters\n");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/isprint/test2/testinfo.dat b/src/pal/tests/palsuite/c_runtime/isprint/test2/testinfo.dat
new file mode 100644
index 0000000000..e115278edb
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/isprint/test2/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = miscellaneous
+Function = isprint
+Name = Test isprint API to check if out of range characters are not printable.
+TYPE = DEFAULT
+EXE1 = test2
+Description
+=Test the isprint function to verify that out of range characters
+=are not printable.
diff --git a/src/pal/tests/palsuite/c_runtime/isspace/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/isspace/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/isspace/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/isspace/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/isspace/test1/CMakeLists.txt
new file mode 100644
index 0000000000..34ad70d328
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/isspace/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_isspace_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_isspace_test1 coreclrpal)
+
+target_link_libraries(paltest_isspace_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/isspace/test1/test1.c b/src/pal/tests/palsuite/c_runtime/isspace/test1/test1.c
new file mode 100644
index 0000000000..6cd1ce878b
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/isspace/test1/test1.c
@@ -0,0 +1,82 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Test #1 for the isspace function
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+
+struct testCase
+{
+ long result;
+ char avalue;
+};
+
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ int i=0;
+ long result = 0;
+
+ /*
+ * A structures of the testcases to be tested with
+ * isspace function
+ */
+ struct testCase testCases[] =
+ {
+ {1,'\n'},
+ {1,'\t'},
+ {1,'\r'},
+ {1,'\v'},
+ {1,'\f'},
+ {1,' '},
+ {0,'a'},
+ {0,'A'},
+ {0,'z'},
+ {0,'Z'},
+ {0,'r'},
+ {0,'R'},
+ {0,'0'},
+ {0,'*'},
+ {0,3}
+ };
+
+ /*
+ * Initialize the PAL
+ */
+ if ( 0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ /* Loop through the testcases */
+ for (i=0; i<sizeof(testCases)/sizeof(struct testCase); i++)
+ {
+ result = isspace(testCases[i].avalue);
+ if ( ((testCases[i].result == 1) && (result==0)) ||
+ ((testCases[i].result ==0) && (result !=0)) )
+ {
+ Fail("ERROR: isspace() returned %d for %c instead of %d\n",
+ result,
+ testCases[i].avalue,
+ testCases[i].result );
+ }
+ }
+
+
+ PAL_Terminate();
+
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/isspace/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/isspace/test1/testinfo.dat
new file mode 100644
index 0000000000..fe9926e8c8
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/isspace/test1/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = isspace
+Name = Positive Test for isspace
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Run through every possible character. For each time that isspace returns
+= >0, check through a list of the known space characters to ensure that it
+= is really a space. Also, when it returns <=0, ensure that that character
+= isn't a space.
diff --git a/src/pal/tests/palsuite/c_runtime/isupper/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/isupper/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/isupper/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/isupper/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/isupper/test1/CMakeLists.txt
new file mode 100644
index 0000000000..c7fc71c43b
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/isupper/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_isupper_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_isupper_test1 coreclrpal)
+
+target_link_libraries(paltest_isupper_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/isupper/test1/test1.c b/src/pal/tests/palsuite/c_runtime/isupper/test1/test1.c
new file mode 100644
index 0000000000..b88bcc4a7e
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/isupper/test1/test1.c
@@ -0,0 +1,88 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test1.c
+**
+** Purpose: Tests the PAL implementation of the isupper function
+** Check that a number of characters return the correct
+** values for whether they are upper case or not.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+struct testCase
+{
+ int CorrectResult;
+ int character;
+};
+
+int __cdecl main(int argc, char **argv)
+{
+
+ int result;
+ int i;
+
+ /* Note: 1 iff char = A..Z
+ 0 iff char =~ A..Z
+ */
+
+ struct testCase testCases[] =
+ {
+ {1, 'A'}, /* Basic cases */
+ {1, 'Z'},
+ {0, 'b'}, /* Lower case */
+ {0, '?'}, /* Characters without case */
+ {0, 230},
+ {0, '5'}
+ };
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ /* Loop through each case. Check to see if each is upper case or
+ not.
+ */
+
+ for(i = 0; i < sizeof(testCases) / sizeof(struct testCase); i++)
+ {
+ result = isupper(testCases[i].character);
+
+ /* The return value is 'non-zero' for success. This if condition
+ * will still work if that non-zero isn't just 1
+ */
+ if ( ((testCases[i].CorrectResult == 1) && (result == 0)) ||
+ ( (testCases[i].CorrectResult == 0) && (result != 0) ))
+ {
+ Fail("ERROR: isupper returned %i instead of %i for "
+ "character %c.\n",
+ result,testCases[i].CorrectResult,
+ testCases[i].character);
+ }
+
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/isupper/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/isupper/test1/testinfo.dat
new file mode 100644
index 0000000000..fb2648a526
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/isupper/test1/testinfo.dat
@@ -0,0 +1,19 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = isupper
+Name = Positive Test for isupper
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Tests the PAL implementation of the isupper function
+= Check that a number of characters return the correct values for whether
+= they are upper case or not.
+
+
+
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/iswdigit/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/iswdigit/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/iswdigit/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/iswdigit/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/iswdigit/test1/CMakeLists.txt
new file mode 100644
index 0000000000..b35dd5ed6d
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/iswdigit/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_iswdigit_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_iswdigit_test1 coreclrpal)
+
+target_link_libraries(paltest_iswdigit_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/iswdigit/test1/test1.c b/src/pal/tests/palsuite/c_runtime/iswdigit/test1/test1.c
new file mode 100644
index 0000000000..1cf94c5d13
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/iswdigit/test1/test1.c
@@ -0,0 +1,69 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test1.c (iswdigit)
+**
+** Purpose: Tests the PAL implementation of the iswdigit function.
+** Tests the passed parameter to iswdigit for being a
+** digit ('0' - '9'). Also passes non-digits to make sure
+** iswdigit picks them up.
+** NOTE: There are three ASCII values that under Windows,
+** iswdigit will return non-zero, indicating a digit.
+** These values are quite apparently not digits:
+** 178, 179, 185.
+** These are not tested.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char **argv)
+{
+
+ int result;
+ int i;
+
+ wchar_t passTestCases[] = {'1','2','3','4','5','6','7','8','9'};
+ wchar_t failTestCases[] = {'a','b','p','$','?',234};
+
+ if ((PAL_Initialize(argc, argv)) != 0)
+ {
+ return (FAIL);
+ }
+
+ /* Loop through each case. Testing if each is a digit. */
+ for(i = 0; i < sizeof(passTestCases) / sizeof(wchar_t); i++)
+ {
+ result = iswdigit(passTestCases[i]);
+
+ /* The return value is 'non-zero' indicates digit*/
+ if (result == 0)
+ {
+ Fail("ERROR: iswdigit returned \"%d\" instead indicating"
+ " \"%c\" is not a digit\n",
+ result,
+ passTestCases[i]);
+ }
+ }
+
+ /* Loop through each case. Testing if each is a not a digit. */
+ for(i = 0; i < sizeof(failTestCases) / sizeof(wchar_t); i++)
+ {
+ result = iswdigit(failTestCases[i]);
+
+ /* The return value is 'zero' indicates non-digit*/
+ if (result != 0)
+ {
+ Fail("ERROR: iswdigit returned \"%d\", indicating"
+ " \"%c\" is a digit\n",
+ result,
+ failTestCases[i]);
+ }
+ }
+ PAL_Terminate();
+ return (PASS);
+}
diff --git a/src/pal/tests/palsuite/c_runtime/iswdigit/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/iswdigit/test1/testinfo.dat
new file mode 100644
index 0000000000..345c9d5661
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/iswdigit/test1/testinfo.dat
@@ -0,0 +1,19 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = iswdigit
+Name = Positive Test for iswdigit
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Tests the PAL implementation of the iswdigit function.
+= Tests the passed parameter to iswdigit for being a
+= digit ('0' - '9'). Also passes non-digits to make sure
+= iswdigit picks them up.
+= NOTE: There are three ASCII values that under Windows,
+= iswdigit will return non-zero, indicating a digit.
+= These values are quite apparently not digits:
+= 178, 179, 185. These are not tested.
diff --git a/src/pal/tests/palsuite/c_runtime/iswprint/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/iswprint/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/iswprint/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/iswprint/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/iswprint/test1/CMakeLists.txt
new file mode 100644
index 0000000000..5e436c3ca2
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/iswprint/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_iswprint_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_iswprint_test1 coreclrpal)
+
+target_link_libraries(paltest_iswprint_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/iswprint/test1/test1.c b/src/pal/tests/palsuite/c_runtime/iswprint/test1/test1.c
new file mode 100644
index 0000000000..08a985b2d6
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/iswprint/test1/test1.c
@@ -0,0 +1,59 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test1.c
+**
+** Purpose: Tests iswprint with all wide characters, ensuring they are
+** consistent with GetStringTypeExW.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char **argv)
+{
+ WORD Info;
+ int ret;
+ int i;
+ WCHAR ch;
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ for (i=0; i<=0xFFFF; i++)
+ {
+ ch = i;
+ ret = GetStringTypeExW(LOCALE_USER_DEFAULT, CT_CTYPE1, &ch, 1, &Info);
+ if (!ret)
+ {
+ Fail("GetStringTypeExW failed to get information for %#X!\n", ch);
+ }
+
+ ret = iswprint(ch);
+ if (Info & (C1_BLANK|C1_PUNCT|C1_ALPHA|C1_DIGIT))
+ {
+ if (!ret)
+ {
+ Fail("iswprint returned incorrect results for %#X: "
+ "expected printable\n", ch);
+ }
+ }
+ else
+ {
+ if (ret)
+ {
+ Fail("iswprint returned incorrect results for %#X: "
+ "expected non-printable\n", ch);
+ }
+ }
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/iswprint/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/iswprint/test1/testinfo.dat
new file mode 100644
index 0000000000..c425967b97
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/iswprint/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = iswprint
+Name = Positive Test for iswprint
+TYPE = DEFAULT
+EXE1 = test1
+Description
+=Tests iswprint with all wide characters, ensuring they are
+=consistent with GetStringTypeExW.
diff --git a/src/pal/tests/palsuite/c_runtime/iswspace/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/iswspace/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/iswspace/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/iswspace/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/iswspace/test1/CMakeLists.txt
new file mode 100644
index 0000000000..1368e55ccc
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/iswspace/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_iswspace_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_iswspace_test1 coreclrpal)
+
+target_link_libraries(paltest_iswspace_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/iswspace/test1/test1.c b/src/pal/tests/palsuite/c_runtime/iswspace/test1/test1.c
new file mode 100644
index 0000000000..c58997812e
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/iswspace/test1/test1.c
@@ -0,0 +1,78 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Tests iswspace with a range of wide characters.
+**
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ int ret;
+ int i;
+
+ struct testChars
+ {
+ WCHAR charValue;
+ int result;
+ };
+
+ /* create an array of chars that test the range of possible characters */
+ struct testChars testChars1[] =
+ {
+ {0x00,0}, /* null */
+ {0x09,1}, /* open circle */
+ {0x0D,1}, /* musical note */
+ {0x20,1}, /* space */
+ {0x3F,0}, /* ? */
+ {0x5E,0}, /* ^ */
+ {0x7B,0}, /* { */
+ {0x86,0}, /* a with circle on top */
+ {0x9F,0}, /* slanted f */
+ {0xC4,0}, /* long dash */
+ {0xE5,0} /* sigma */
+ };
+
+ if (0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ for (i = 0; i < (sizeof(testChars1) / sizeof(struct testChars)); i++)
+ {
+
+ ret = iswspace(testChars1[i].charValue);
+
+ if((ret==0) && (testChars1[i].result != 0))
+ {
+ Fail("ERROR: wide character %#X IS considered a space, "
+ "but iswspace did NOT indicate it was one with error %u.\n",
+ testChars1[i].charValue,
+ GetLastError());
+ }
+
+ if((ret!=0) && (testChars1[i].result == 0))
+ {
+ Fail("ERROR: wide character %#X is NOT considered a space, "
+ "but iswspace DID indicate it was a space with error %u.\n",
+ testChars1[i].charValue,
+ GetLastError());
+ }
+ }
+
+
+ PAL_Terminate();
+
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/iswspace/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/iswspace/test1/testinfo.dat
new file mode 100644
index 0000000000..0368052b91
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/iswspace/test1/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = iswspace
+Name = Positive Test for iswspace
+TYPE = DEFAULT
+EXE1 = test1
+Description
+=Tests iswspace with a range of wide characters.
diff --git a/src/pal/tests/palsuite/c_runtime/iswupper/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/iswupper/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/iswupper/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/iswupper/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/iswupper/test1/CMakeLists.txt
new file mode 100644
index 0000000000..8b8fae6d72
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/iswupper/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_iswupper_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_iswupper_test1 coreclrpal)
+
+target_link_libraries(paltest_iswupper_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/iswupper/test1/test1.c b/src/pal/tests/palsuite/c_runtime/iswupper/test1/test1.c
new file mode 100644
index 0000000000..a01686be44
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/iswupper/test1/test1.c
@@ -0,0 +1,91 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test1.c
+**
+** Purpose: Tests the PAL implementation of the iswupper function
+** Check that a number of characters return the correct
+** values for whether they are upper case or not.
+**
+**
+**===================================================================*/
+
+#define UNICODE
+#include <palsuite.h>
+
+
+struct testCase
+{
+ int CorrectResult;
+ WCHAR character;
+};
+
+int __cdecl main(int argc, char **argv)
+{
+
+ int result;
+ int i;
+
+ /* Note: 1 iff char = A..Z
+ 0 iff char =~ A..Z
+ */
+
+ struct testCase testCases[] =
+ {
+ {1, 'A'}, /* Basic cases */
+ {1, 'Z'},
+ {0, 'b'}, /* Lower case */
+ {0, '?'}, /* Characters without case */
+ {0, 230}
+ };
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ /* Loop through each case. Check to see if each is upper case or
+ not.
+ */
+
+ for(i = 0; i < sizeof(testCases) / sizeof(struct testCase); i++)
+ {
+
+ result = iswupper(testCases[i].character);
+
+ /* The return value is 'non-zero' for success. This if condition
+ * will still work if that non-zero isn't just 1
+ */
+ if ( ((testCases[i].CorrectResult == 1) && (result == 0)) ||
+ ( (testCases[i].CorrectResult == 0) && (result != 0) ))
+ {
+ Fail("ERROR: iswupper returned %i instead of %i for "
+ "character %c.\n",
+ result,
+ testCases[i].CorrectResult,
+ testCases[i].character);
+ }
+
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/iswupper/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/iswupper/test1/testinfo.dat
new file mode 100644
index 0000000000..22131e40ac
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/iswupper/test1/testinfo.dat
@@ -0,0 +1,19 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = isupper
+Name = Positive Test for iswupper
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Tests the PAL implementation of the iswupper function
+= Check that a number of characters return the correct values for whether
+= they are upper case or not.
+
+
+
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/iswxdigit/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/iswxdigit/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/iswxdigit/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/iswxdigit/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/iswxdigit/test1/CMakeLists.txt
new file mode 100644
index 0000000000..3a726eced9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/iswxdigit/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_iswxdigit_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_iswxdigit_test1 coreclrpal)
+
+target_link_libraries(paltest_iswxdigit_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/iswxdigit/test1/test1.c b/src/pal/tests/palsuite/c_runtime/iswxdigit/test1/test1.c
new file mode 100644
index 0000000000..73ad495856
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/iswxdigit/test1/test1.c
@@ -0,0 +1,61 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test1.c
+**
+** Purpose: Tests iswxdigit with every possible wide character, ensuring it
+** returns the correct results.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+/*
+ * These are the only wide characters Win2000 recogonizes as valid hex digits.
+ */
+WCHAR ValidHexDigits[] =
+{
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70, 97, 98, 99, 100,
+ 101, 102, 65296, 65297, 65298, 65299, 65300, 65301, 65302, 65303, 65304, 65305,
+ 65313, 65314, 65315, 65316, 65317, 65318, 65345, 65346, 65347, 65348, 65349, 65350,
+ 0
+};
+
+int __cdecl main(int argc, char **argv)
+{
+ int i;
+ WCHAR c;
+ int ret;
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ for (i=0; i<=0xFFFF; i++)
+ {
+ ret = iswxdigit(i);
+ c = (WCHAR) i;
+
+ if (ret)
+ {
+ if (wcschr(ValidHexDigits, c) == NULL)
+ {
+ /* iswxdigit says its a hex digit. We know better */
+ Fail("iswxdigit incorrectly found %#x to be a hex digit!\n", c);
+ }
+ }
+ else if (wcschr(ValidHexDigits, c) != NULL && c != 0)
+ {
+ /* iswxdigit says it isn't a hex digit. We know better */
+ Fail("iswxdigit failed to find %#x to be a hex digit!\n", c);
+ }
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/iswxdigit/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/iswxdigit/test1/testinfo.dat
new file mode 100644
index 0000000000..2b683c4eb7
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/iswxdigit/test1/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = iswxdigit
+Name = iswxdigit test #1
+TYPE = DEFAULT
+EXE1 = test1
+Description
+=Tests iswxdigit with every possible wide character, ensuring it
+=returns the correct results.
+
diff --git a/src/pal/tests/palsuite/c_runtime/isxdigit/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/isxdigit/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/isxdigit/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/isxdigit/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/isxdigit/test1/CMakeLists.txt
new file mode 100644
index 0000000000..8919b36e42
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/isxdigit/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_isxdigit_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_isxdigit_test1 coreclrpal)
+
+target_link_libraries(paltest_isxdigit_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/isxdigit/test1/test1.c b/src/pal/tests/palsuite/c_runtime/isxdigit/test1/test1.c
new file mode 100644
index 0000000000..be25af233c
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/isxdigit/test1/test1.c
@@ -0,0 +1,58 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Run through every possible character. For each time that
+** isxdigit returns:
+** 1, check through a list of the known hex characters to ensure that it
+** is really a hex char. Also, when it returns 0, ensure that that character
+** isn't a hex character.
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ int i;
+
+ /* Initialize the PAL */
+ if ( 0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ /* Loop through each character and call isxdigit for each character */
+ for (i=1; i<256; i++)
+ {
+
+ if (isxdigit(i) == 0)
+ {
+ if( ((i>=48) && (i<=57)) || ((i>=97) && (i<=102)) ||
+ ((i>=65) && (i<=70)) )
+ {
+ Fail("ERROR: isxdigit() returns true for '%c' (%d)\n", i, i);
+ }
+ }
+ else
+ {
+ if( ((i<48) && (i>58)) || ((i<97) && (i>102)) ||
+ ((i<65) && (i>70)) )
+ {
+ Fail("ERROR: isxdigit() returns false for '%c' (%d)\n", i, i);
+ }
+ }
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/isxdigit/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/isxdigit/test1/testinfo.dat
new file mode 100644
index 0000000000..fd031f0768
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/isxdigit/test1/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = isxdigit
+Name = Positive Test for isxdigit
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Run through every possible character. For each time that isxdigit returns
+= 1, check through a list of the known hex characters to ensure that it
+= is really a hex char. Also, when it returns 0, ensure that that character
+= isn't a hex character.
diff --git a/src/pal/tests/palsuite/c_runtime/labs/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/labs/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/labs/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/labs/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/labs/test1/CMakeLists.txt
new file mode 100644
index 0000000000..cf0f0999a9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/labs/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_labs_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_labs_test1 coreclrpal)
+
+target_link_libraries(paltest_labs_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/labs/test1/test1.c b/src/pal/tests/palsuite/c_runtime/labs/test1/test1.c
new file mode 100644
index 0000000000..41f85226e1
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/labs/test1/test1.c
@@ -0,0 +1,65 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test1.c
+**
+** Purpose: Call labs on a series of values -- negative, positive, zero,
+** and the largest negative value of a LONG. Ensure that they are all
+** changed properly to their absoulte value.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+struct testCase
+{
+ LONG LongValue;
+ LONG AbsoluteLongValue;
+};
+
+int __cdecl main(int argc, char **argv)
+{
+
+ LONG result=0;
+ int i=0;
+
+ struct testCase testCases[] =
+ {
+ {1234, 1234},
+ {-1234, 1234},
+ {0, 0},
+ {-2147483647, 2147483647}, /* Max value to abs */
+ {2147483647, 2147483647}
+ };
+
+ if (0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /* Loop through each case. Call labs on each LONG and ensure that
+ the resulting value is correct.
+ */
+
+ for(i = 0; i < sizeof(testCases) / sizeof(struct testCase); i++)
+ {
+ /* Absolute value on a LONG */
+ result = labs(testCases[i].LongValue);
+
+ if (testCases[i].AbsoluteLongValue != result)
+ {
+ Fail("ERROR: labs took the absoulte value of '%d' to be '%d' "
+ "instead of %d.\n",
+ testCases[i].LongValue,
+ result,
+ testCases[i].AbsoluteLongValue);
+ }
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/labs/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/labs/test1/testinfo.dat
new file mode 100644
index 0000000000..c385aa76b6
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/labs/test1/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = labs
+Name = Series of tests for labs: positive, negative, zero, maximum long value.
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Call labs on a series of values -- negative, positive, zero,
+= and the largest negative value of a long. Ensure that they are all
+= changed properly to their absoulte value.
diff --git a/src/pal/tests/palsuite/c_runtime/llabs/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/llabs/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/llabs/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/llabs/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/llabs/test1/CMakeLists.txt
new file mode 100644
index 0000000000..8f5bdbe097
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/llabs/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_llabs_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_llabs_test1 coreclrpal)
+
+target_link_libraries(paltest_llabs_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/llabs/test1/test1.c b/src/pal/tests/palsuite/c_runtime/llabs/test1/test1.c
new file mode 100644
index 0000000000..044e22f134
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/llabs/test1/test1.c
@@ -0,0 +1,65 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test1.c
+**
+** Purpose: Call llabs on a series of values -- negative, positive,
+** zero, and the largest negative value of an __int64. Ensure that
+** they are all changed properly to their absoulte value.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+struct testCase
+{
+ __int64 LongLongValue;
+ __int64 AbsoluteLongLongValue;
+};
+
+int __cdecl main(int argc, char **argv)
+{
+
+ __int64 result=0;
+ int i=0;
+
+ struct testCase testCases[] =
+ {
+ {1234, 1234},
+ {-1234, 1234},
+ {0, 0},
+ {-9223372036854775807LL, 9223372036854775807LL}, /* Max value to abs */
+ {9223372036854775807LL, 9223372036854775807LL}
+ };
+
+ if (0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /* Loop through each case. Call llabs on each __int64 and ensure that
+ the resulting value is correct.
+ */
+
+ for(i = 0; i < sizeof(testCases) / sizeof(struct testCase); i++)
+ {
+ /* Absolute value on an __int64 */
+ result = llabs(testCases[i].LongLongValue);
+
+ if (testCases[i].AbsoluteLongLongValue != result)
+ {
+ Fail("ERROR: llabs took the absoulte value of '%d' to be '%d' "
+ "instead of %d.\n",
+ testCases[i].LongLongValue,
+ result,
+ testCases[i].AbsoluteLongLongValue);
+ }
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/llabs/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/llabs/test1/testinfo.dat
new file mode 100644
index 0000000000..b1b76377bf
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/llabs/test1/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = labs
+Name = Series of tests for labs: positive, negative, zero, maximum __int64 value.
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Call llabs on a series of values -- negative, positive, zero,
+= and the largest negative value of an __int64. Ensure that they are all
+= changed properly to their absoulte value.
diff --git a/src/pal/tests/palsuite/c_runtime/localtime/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/localtime/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/localtime/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/localtime/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/localtime/test1/CMakeLists.txt
new file mode 100644
index 0000000000..25acf48749
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/localtime/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_localtime_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_localtime_test1 coreclrpal)
+
+target_link_libraries(paltest_localtime_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/localtime/test1/test1.c b/src/pal/tests/palsuite/c_runtime/localtime/test1/test1.c
new file mode 100644
index 0000000000..a993a17f69
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/localtime/test1/test1.c
@@ -0,0 +1,69 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test1.c (localtime)
+**
+** Purpose: Tests the PAL implementation of the localtime function.
+** localtime() is passed a date in seconds, since January 01
+** 1970 midnight, UTC. localtime() converts the time to the
+** tm struct, those values are tested for validity.
+**
+**
+**===================================================================*/
+#include <palsuite.h>
+
+int __cdecl main(int argc, char **argv)
+{
+ time_t dates[] ={1003327482, // Oct 17, 2001 10:04:42 am
+ 701307301, // March 22, 1992 6:35:01 pm
+ 973620900, // Nov 07, 2000 1:15:00 pm
+ 924632589, // April 20, 1999 2:23:09 pm
+ 951934989}; // March 01, 2000 1:23:09 pm
+ struct tm * converted_date;
+ int i;
+
+ if (PAL_Initialize(argc, argv) != 0)
+
+ return (FAIL);
+
+ /*Convert from time_t to struct tm*/
+ for ( i=0; i < (sizeof(dates)/sizeof(time_t)); i++)
+ {
+ converted_date = localtime(&dates[i]);
+
+ if ((converted_date->tm_hour < 0) || (converted_date->tm_hour > 23))
+ {
+ Fail("ERROR: localtime returned %d for tm_hour\n", converted_date->tm_hour);
+ }
+ if ((converted_date->tm_mday < 1) || (converted_date->tm_mday > 31))
+ {
+ Fail("ERROR: localtime returned %d for tm_mday\n",converted_date->tm_mday);
+ }
+ if ((converted_date->tm_min < 0) || (converted_date->tm_min > 59))
+ {
+ Fail("ERROR: localtime returned %d for tm_min\n",converted_date->tm_min);
+ }
+ if ((converted_date->tm_mon < 0) || (converted_date->tm_mon > 11))
+ {
+ Fail("ERROR: localtime returned %d for tm_mon\n",converted_date->tm_mon);
+ }
+ if ((converted_date->tm_sec < 0) || (converted_date->tm_sec > 59))
+ {
+ Fail("ERROR: localtime returned %d for tm_sec\n",converted_date->tm_sec);
+ }
+ if ((converted_date->tm_wday < 0) || (converted_date->tm_wday > 6 ))
+ {
+ Fail("ERROR: localtime returned %d for tm_wday\n",converted_date->tm_wday);
+ }
+ if ((converted_date->tm_yday < 0) || (converted_date->tm_yday > 365))
+ {
+ Fail("ERROR: localtime returned %d for tm_yday\n",converted_date->tm_yday);
+ }
+ }
+
+ PAL_Terminate();
+ return (PASS);
+}
diff --git a/src/pal/tests/palsuite/c_runtime/localtime/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/localtime/test1/testinfo.dat
new file mode 100644
index 0000000000..63f7fcda93
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/localtime/test1/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = localtime
+Name = Positive Test for localtime
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Tests the PAL implementation of the localtime function.
+= localtime() is passed a date in seconds, since January 01
+= 1970 midnight, UTC. localtime() converts the time to the
+= tm struct, those values are tested for validity.
diff --git a/src/pal/tests/palsuite/c_runtime/log/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/log/CMakeLists.txt
new file mode 100644
index 0000000000..5e1ef7f28b
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/log/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
diff --git a/src/pal/tests/palsuite/c_runtime/log/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/log/test1/CMakeLists.txt
new file mode 100644
index 0000000000..dd19002904
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/log/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_log_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_log_test1 coreclrpal)
+
+target_link_libraries(paltest_log_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/log/test1/test1.c b/src/pal/tests/palsuite/c_runtime/log/test1/test1.c
new file mode 100644
index 0000000000..eea592dd45
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/log/test1/test1.c
@@ -0,0 +1,140 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test1.c
+**
+** Purpose: Tests log with a normal set of values.
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+// binary64 (double) has a machine epsilon of 2^-52 (approx. 2.22e-16). However, this
+// is slightly too accurate when writing tests meant to run against libm implementations
+// for various platforms. 2^-50 (approx. 8.88e-16) seems to be as accurate as we can get.
+//
+// The tests themselves will take PAL_EPSILON and adjust it according to the expected result
+// so that the delta used for comparison will compare the most significant digits and ignore
+// any digits that are outside the double precision range (15-17 digits).
+
+// For example, a test with an expect result in the format of 0.xxxxxxxxxxxxxxxxx will use
+// PAL_EPSILON for the variance, while an expected result in the format of 0.0xxxxxxxxxxxxxxxxx
+// will use PAL_EPSILON / 10 and and expected result in the format of x.xxxxxxxxxxxxxxxx will
+// use PAL_EPSILON * 10.
+#define PAL_EPSILON 8.8817841970012523e-16
+
+#define PAL_NAN sqrt(-1.0)
+#define PAL_POSINF -log(0.0)
+#define PAL_NEGINF log(0.0)
+
+/**
+ * Helper test structure
+ */
+struct test
+{
+ double value; /* value to test the function with */
+ double expected; /* expected result */
+ double variance; /* maximum delta between the expected and actual result */
+};
+
+/**
+ * validate
+ *
+ * test validation function
+ */
+void __cdecl validate(double value, double expected, double variance)
+{
+ double result = log(value);
+
+ /*
+ * The test is valid when the difference between result
+ * and expected is less than or equal to variance
+ */
+ double delta = fabs(result - expected);
+
+ if (delta > variance)
+ {
+ Fail("log(%g) returned %20.17g when it should have returned %20.17g",
+ value, result, expected);
+ }
+}
+
+/**
+ * validate
+ *
+ * test validation function for values returning NaN
+ */
+void __cdecl validate_isnan(double value)
+{
+ double result = log(value);
+
+ if (!_isnan(result))
+ {
+ Fail("log(%g) returned %20.17g when it should have returned %20.17g",
+ value, result, PAL_NAN);
+ }
+}
+
+/**
+ * main
+ *
+ * executable entry point
+ */
+int __cdecl main(int argc, char **argv)
+{
+ struct test tests[] =
+ {
+ /* value expected variance */
+ { 0, PAL_NEGINF, 0 },
+ { 0.043213918263772250, -3.1415926535897932, PAL_EPSILON * 10 }, // expected: -(pi)
+ { 0.065988035845312537, -2.7182818284590452, PAL_EPSILON * 10 }, // expected: -(e)
+ { 0.1, -2.3025850929940457, PAL_EPSILON * 10 }, // expected: -(ln(10))
+ { 0.20787957635076191, -1.5707963267948966, PAL_EPSILON * 10 }, // expected: -(pi / 2)
+ { 0.23629008834452270, -1.4426950408889634, PAL_EPSILON * 10 }, // expected: -(log2(e))
+ { 0.24311673443421421, -1.4142135623730950, PAL_EPSILON * 10 }, // expected: -(sqrt(2))
+ { 0.32355726390307110, -1.1283791670955126, PAL_EPSILON * 10 }, // expected: -(2 / sqrt(pi))
+ { 0.36787944117144232, -1, PAL_EPSILON * 10 }, // expected: -(1)
+ { 0.45593812776599624, -0.78539816339744831, PAL_EPSILON }, // expected: -(pi / 4)
+ { 0.49306869139523979, -0.70710678118654752, PAL_EPSILON }, // expected: -(1 / sqrt(2))
+ { 0.5, -0.69314718055994531, PAL_EPSILON }, // expected: -(ln(2))
+ { 0.52907780826773535, -0.63661977236758134, PAL_EPSILON }, // expected: -(2 / pi)
+ { 0.64772148514180065, -0.43429448190325183, PAL_EPSILON }, // expected: -(log10(e))
+ { 0.72737734929521647, -0.31830988618379067, PAL_EPSILON }, // expected: -(1 / pi)
+ { 1, 0, PAL_EPSILON },
+ { 1.3748022274393586, 0.31830988618379067, PAL_EPSILON }, // expected: 1 / pi
+ { 1.5438734439711811, 0.43429448190325183, PAL_EPSILON }, // expected: log10(e)
+ { 1.8900811645722220, 0.63661977236758134, PAL_EPSILON }, // expected: 2 / pi
+ { 2, 0.69314718055994531, PAL_EPSILON }, // expected: ln(2)
+ { 2.0281149816474725, 0.70710678118654752, PAL_EPSILON }, // expected: 1 / sqrt(2)
+ { 2.1932800507380155, 0.78539816339744831, PAL_EPSILON }, // expected: pi / 4
+ { 2.7182818284590452, 1, PAL_EPSILON * 10 }, // value: e
+ { 3.0906430223107976, 1.1283791670955126, PAL_EPSILON * 10 }, // expected: 2 / sqrt(pi)
+ { 4.1132503787829275, 1.4142135623730950, PAL_EPSILON * 10 }, // expected: sqrt(2)
+ { 4.2320861065570819, 1.4426950408889634, PAL_EPSILON * 10 }, // expected: log2(e)
+ { 4.8104773809653517, 1.5707963267948966, PAL_EPSILON * 10 }, // expected: pi / 2
+ { 10, 2.3025850929940457, PAL_EPSILON * 10 }, // expected: ln(10)
+ { 15.154262241479264, 2.7182818284590452, PAL_EPSILON * 10 }, // expected: e
+ { 23.140692632779269, 3.1415926535897932, PAL_EPSILON * 10 }, // expected: pi
+ { PAL_POSINF, PAL_POSINF, 0 },
+ };
+
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+ for (int i = 0; i < (sizeof(tests) / sizeof(struct test)); i++)
+ {
+ validate(tests[i].value, tests[i].expected, tests[i].variance);
+ }
+
+ validate_isnan(PAL_NEGINF);
+ validate_isnan(PAL_NAN);
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/log/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/log/test1/testinfo.dat
new file mode 100644
index 0000000000..6b984f6eba
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/log/test1/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = log
+Name = Positive Test for log
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Passes a series of values to the log() function,
+= checking each for the expected result. Also checks
+= for proper handling of out-of-range values.
diff --git a/src/pal/tests/palsuite/c_runtime/log10/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/log10/CMakeLists.txt
new file mode 100644
index 0000000000..5e1ef7f28b
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/log10/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
diff --git a/src/pal/tests/palsuite/c_runtime/log10/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/log10/test1/CMakeLists.txt
new file mode 100644
index 0000000000..31e750df3e
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/log10/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_log10_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_log10_test1 coreclrpal)
+
+target_link_libraries(paltest_log10_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/log10/test1/test1.c b/src/pal/tests/palsuite/c_runtime/log10/test1/test1.c
new file mode 100644
index 0000000000..13711a752e
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/log10/test1/test1.c
@@ -0,0 +1,146 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Test to ensure that log10 returns correct values.
+**
+** Dependencies: PAL_Initialize
+** PAL_Terminate
+** Fail
+** fabs
+** _isnan
+**
+**===========================================================================*/
+
+#include <palsuite.h>
+
+// binary64 (double) has a machine epsilon of 2^-52 (approx. 2.22e-16). However, this
+// is slightly too accurate when writing tests meant to run against libm implementations
+// for various platforms. 2^-50 (approx. 8.88e-16) seems to be as accurate as we can get.
+//
+// The tests themselves will take PAL_EPSILON and adjust it according to the expected result
+// so that the delta used for comparison will compare the most significant digits and ignore
+// any digits that are outside the double precision range (15-17 digits).
+
+// For example, a test with an expect result in the format of 0.xxxxxxxxxxxxxxxxx will use
+// PAL_EPSILON for the variance, while an expected result in the format of 0.0xxxxxxxxxxxxxxxxx
+// will use PAL_EPSILON / 10 and and expected result in the format of x.xxxxxxxxxxxxxxxx will
+// use PAL_EPSILON * 10.
+#define PAL_EPSILON 8.8817841970012523e-16
+
+#define PAL_NAN sqrt(-1.0)
+#define PAL_POSINF -log(0.0)
+#define PAL_NEGINF log(0.0)
+
+/**
+ * Helper test structure
+ */
+struct test
+{
+ double value; /* value to test the function with */
+ double expected; /* expected result */
+ double variance; /* maximum delta between the expected and actual result */
+};
+
+/**
+ * validate
+ *
+ * test validation function
+ */
+void __cdecl validate(double value, double expected, double variance)
+{
+ double result = log10(value);
+
+ /*
+ * The test is valid when the difference between result
+ * and expected is less than or equal to variance
+ */
+ double delta = fabs(result - expected);
+
+ if (delta > variance)
+ {
+ Fail("log10(%g) returned %20.17g when it should have returned %20.17g",
+ value, result, expected);
+ }
+}
+
+/**
+ * validate
+ *
+ * test validation function for values returning NaN
+ */
+void __cdecl validate_isnan(double value)
+{
+ double result = log10(value);
+
+ if (!_isnan(result))
+ {
+ Fail("log10(%g) returned %20.17g when it should have returned %20.17g",
+ value, result, PAL_NAN);
+ }
+}
+
+/**
+ * main
+ *
+ * executable entry point
+ */
+int __cdecl main(int argc, char **argv)
+{
+ struct test tests[] =
+ {
+ /* value expected variance */
+ { 0, PAL_NEGINF, 0 },
+ { 0.00072178415907472774, -3.1415926535897932, PAL_EPSILON * 10 }, // expected: -(pi)
+ { 0.0019130141022243176, -2.7182818284590452, PAL_EPSILON * 10 }, // expected: -(e)
+ { 0.0049821282964407206, -2.3025850929940457, PAL_EPSILON * 10 }, // expected: -(ln(10))
+ { 0.026866041001136132, -1.5707963267948966, PAL_EPSILON * 10 }, // expected: -(pi / 2)
+ { 0.036083192820787210, -1.4426950408889634, PAL_EPSILON * 10 }, // expected: -(log2(e))
+ { 0.038528884700322026, -1.4142135623730950, PAL_EPSILON * 10 }, // expected: -(sqrt(2))
+ { 0.074408205860642723, -1.1283791670955126, PAL_EPSILON * 10 }, // expected: -(2 / sqrt(pi))
+ { 0.1, -1, PAL_EPSILON * 10 }, // expected: -(1)
+ { 0.16390863613957665, -0.78539816339744831, PAL_EPSILON }, // expected: -(pi / 4)
+ { 0.19628775993505562, -0.70710678118654752, PAL_EPSILON }, // expected: -(1 / sqrt(2))
+ { 0.20269956628651730, -0.69314718055994531, PAL_EPSILON }, // expected: -(ln(2))
+ { 0.23087676451600055, -0.63661977236758134, PAL_EPSILON }, // expected: -(2 / pi)
+ { 0.36787944117144232, -0.43429448190325183, PAL_EPSILON }, // expected: -(log10(e))
+ { 0.48049637305186868, -0.31830988618379067, PAL_EPSILON }, // expected: -(1 / pi)
+ { 1, 0, PAL_EPSILON },
+ { 2.0811811619898573, 0.31830988618379067, PAL_EPSILON }, // expected: 1 / pi
+ { 2.7182818284590452, 0.43429448190325183, PAL_EPSILON }, // expected: log10(e) value: e
+ { 4.3313150290214525, 0.63661977236758134, PAL_EPSILON }, // expected: 2 / pi
+ { 4.9334096679145963, 0.69314718055994531, PAL_EPSILON }, // expected: ln(2)
+ { 5.0945611704512962, 0.70710678118654752, PAL_EPSILON }, // expected: 1 / sqrt(2)
+ { 6.1009598002416937, 0.78539816339744831, PAL_EPSILON }, // expected: pi / 4
+ { 10, 1, PAL_EPSILON * 10 },
+ { 13.439377934644400, 1.1283791670955126, PAL_EPSILON * 10 }, // expected: 2 / sqrt(pi)
+ { 25.954553519470081, 1.4142135623730950, PAL_EPSILON * 10 }, // expected: sqrt(2)
+ { 27.713733786437790, 1.4426950408889634, PAL_EPSILON * 10 }, // expected: log2(e)
+ { 37.221710484165167, 1.5707963267948966, PAL_EPSILON * 10 }, // expected: pi / 2
+ { 200.71743249053009, 2.3025850929940457, PAL_EPSILON * 10 }, // expected: ln(10)
+ { 522.73529967043665, 2.7182818284590452, PAL_EPSILON * 10 }, // expected: e
+ { 1385.4557313670111, 3.1415926535897932, PAL_EPSILON * 10 }, // expected: pi
+ { PAL_POSINF, PAL_POSINF, 0 },
+ };
+
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+ for (int i = 0; i < (sizeof(tests) / sizeof(struct test)); i++)
+ {
+ validate(tests[i].value, tests[i].expected, tests[i].variance);
+ }
+
+ validate_isnan(PAL_NEGINF);
+ validate_isnan(PAL_NAN);
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/log10/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/log10/test1/testinfo.dat
new file mode 100644
index 0000000000..887bace692
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/log10/test1/testinfo.dat
@@ -0,0 +1,17 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = log10
+Name = Positive Test for log10
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Passes a series of values to the log10() function,
+= checking each for the expected result. Also checks
+= for proper handling of out-of-range values.
+
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/malloc/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/malloc/CMakeLists.txt
new file mode 100644
index 0000000000..ef14ea5352
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/malloc/CMakeLists.txt
@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+
diff --git a/src/pal/tests/palsuite/c_runtime/malloc/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/malloc/test1/CMakeLists.txt
new file mode 100644
index 0000000000..4a388ad3d7
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/malloc/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_malloc_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_malloc_test1 coreclrpal)
+
+target_link_libraries(paltest_malloc_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/malloc/test1/test1.c b/src/pal/tests/palsuite/c_runtime/malloc/test1/test1.c
new file mode 100644
index 0000000000..7ea4dd068f
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/malloc/test1/test1.c
@@ -0,0 +1,52 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Test that malloc returns useable memory
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+
+
+int __cdecl main(int argc, char **argv)
+{
+
+ char *testA;
+ int i;
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ /* check that malloc really gives us addressable memory */
+ testA = (char *)malloc(20 * sizeof(char));
+ if (testA == NULL)
+ {
+ Fail("Call to malloc failed.\n");
+ }
+ for (i = 0; i < 20; i++)
+ {
+ testA[i] = 'a';
+ }
+ for (i = 0; i < 20; i++)
+ {
+ if (testA[i] != 'a')
+ {
+ Fail("The memory doesn't seem to be properly allocated.\n");
+ }
+ }
+ free(testA);
+
+ PAL_Terminate();
+
+ return PASS;
+}
+
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/malloc/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/malloc/test1/testinfo.dat
new file mode 100644
index 0000000000..9060bc6284
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/malloc/test1/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = malloc
+Name = Positive Test for malloc
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Tests that malloc properly allocates memory.
diff --git a/src/pal/tests/palsuite/c_runtime/malloc/test2/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/malloc/test2/CMakeLists.txt
new file mode 100644
index 0000000000..abbed2aa62
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/malloc/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test2.c
+)
+
+add_executable(paltest_malloc_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_malloc_test2 coreclrpal)
+
+target_link_libraries(paltest_malloc_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/malloc/test2/test2.c b/src/pal/tests/palsuite/c_runtime/malloc/test2/test2.c
new file mode 100644
index 0000000000..5deee0eddb
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/malloc/test2/test2.c
@@ -0,0 +1,41 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test2.c
+**
+** Purpose: Test that malloc(0) returns non-zero value
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+
+
+int __cdecl main(int argc, char **argv)
+{
+
+ char *testA;
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ /* check that malloc(0) returns non-zero value */
+ testA = (char *)malloc(0);
+ if (testA == NULL)
+ {
+ Fail("Call to malloc(0) failed.\n");
+ }
+
+ free(testA);
+
+ PAL_Terminate();
+
+ return PASS;
+}
+
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/malloc/test2/testinfo.dat b/src/pal/tests/palsuite/c_runtime/malloc/test2/testinfo.dat
new file mode 100644
index 0000000000..1212a8f8f9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/malloc/test2/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = malloc
+Name = Positive Test for malloc
+TYPE = DEFAULT
+EXE1 = test2
+Description
+= Test that malloc(0) returns non-zero value
diff --git a/src/pal/tests/palsuite/c_runtime/memchr/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/memchr/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/memchr/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/memchr/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/memchr/test1/CMakeLists.txt
new file mode 100644
index 0000000000..4e33a8fc04
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/memchr/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_memchr_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_memchr_test1 coreclrpal)
+
+target_link_libraries(paltest_memchr_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/memchr/test1/test1.c b/src/pal/tests/palsuite/c_runtime/memchr/test1/test1.c
new file mode 100644
index 0000000000..043a6789d8
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/memchr/test1/test1.c
@@ -0,0 +1,122 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test1.c
+**
+** Purpose: Tests the PAL implementation of the memchr function.
+** Create a string buffer, and check for a number of
+** characters in it. Test to ensure it returns NULL if
+** it can't find the character, and that the size argument
+** works properly.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+struct testCase
+{
+ char *result;
+ char string[50];
+ int character;
+ int length;
+};
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ int i = 0;
+ char *result = NULL;
+
+ /*
+ * this structure includes several strings to be tested with
+ * memchr function and the expected results
+ */
+
+ struct testCase testCases[]=
+ {
+ {"st","corn cup cat cream coast",'s',23},
+ /* single instance of char */
+ {"st","corn cup cat cream coast",'s',24},
+ /* single inst, inst< exact length */
+ {"q","corn cup cat cream coastq",'q',25},
+ /* single inst at end, inst=exact length */
+ {"q","corn cup cat cream coastq",'q',26},
+ /* single inst at end, inst<length,
+ length>len(string) */
+ {"st","corn cup cat cream coast",115,24},
+ /* single int inst, inst<exact length */
+ {"corn cup cat cream coast","corn cup cat cream coast",'c',24},
+ /* multi-inst, inst=1, exact length */
+ {"corn cup cat cream coast","corn cup cat cream coast",'c',1},
+ /* multi-inst, inst = length, length=1 */
+ {"is is a test","This is a test",105,14},
+ /* single int inst, exact length */
+ {"is is a test","This is a test",'i',14},
+ /* double inst, exact length */
+ {"a test","This is a test",'a',9},
+ /* single instance instance = length */
+ {NULL,"This is a test",'b',14},
+ /* no instance exact length */
+ {NULL,"This is a test",'a',8},
+ /* single instance - < length */
+ {NULL,"This is a test",121,14},
+ /* single instance - exact length */
+ {" is a test of the function","This is a test of the function",
+ ' ',17} /* single inst<length, len(string)>length */
+ };
+
+
+ /* Initialize the PAL */
+ if ( 0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ /* Loop through the testcases in the structure */
+ for (i=0; i< sizeof(testCases)/sizeof(struct testCase); i++)
+ {
+ /* Need to type cast function in order to compare the result */
+ result = (char *)memchr(testCases[i].string,
+ testCases[i].character,testCases[i].length);
+
+ if (result==NULL)
+ {
+ if (testCases[i].result != NULL)
+ {
+ Fail("ERROR: Expected memcmp to return \"%s\" instead of"
+ " NULL\n", testCases[i].result);
+ }
+ }
+ else
+ {
+ if (strcmp(result,testCases[i].result)!=0 )
+
+ {
+ Fail("ERROR: Expected memcmp to return \"%s\" instead of"
+ " \"%s\"\n", testCases[i].result, result);
+ }
+
+ }
+ }
+
+ PAL_Terminate();
+
+ return PASS;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/memchr/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/memchr/test1/testinfo.dat
new file mode 100644
index 0000000000..fc2a8e95dc
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/memchr/test1/testinfo.dat
@@ -0,0 +1,19 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = memchr
+Name = Positive Test for memchr
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Create a string buffer, and check for a number of characters in it.
+= Test to ensure it returns NULL if it can't find the character, and that
+= the size argument works properly.
+
+
+
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/memcmp/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/memcmp/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/memcmp/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/memcmp/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/memcmp/test1/CMakeLists.txt
new file mode 100644
index 0000000000..b61f208f34
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/memcmp/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_memcmp_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_memcmp_test1 coreclrpal)
+
+target_link_libraries(paltest_memcmp_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/memcmp/test1/test1.c b/src/pal/tests/palsuite/c_runtime/memcmp/test1/test1.c
new file mode 100644
index 0000000000..7b63173e22
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/memcmp/test1/test1.c
@@ -0,0 +1,57 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Check that memcmp find identical buffers to be identical,
+** and that it correctly orders different buffers.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char **argv)
+{
+
+ char testA[] = "aaaaaaaaaaaaaaaaaaaa";
+ char testB[] = "aaaaaaaaaaaaaaaaaaaa";
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ if (!(memcmp(testA, testB, 20) == 0))
+ {
+ Fail("memcmp compared two identical buffers and found them to "
+ "differ.\n");
+ }
+ testB[3] = 'b';
+
+ if (!(memcmp(testA, testB, 20) < 0)
+ || !(memcmp(testB, testA, 20) >0 ))
+ {
+ Fail("memcmp compared two buffers with different contents, and"
+ " did not order them correctly.\n");
+ }
+
+ if (memcmp(testA, testB, 0) != 0)
+ {
+ Fail("memcmp didn't return 0 when comparing buffers of length 0.\n");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
+
+
+
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/memcmp/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/memcmp/test1/testinfo.dat
new file mode 100644
index 0000000000..2de36b2dd6
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/memcmp/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = memcmp
+Name = Positive Test for memcmp
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Check that memcmp find identical buffers to be identical,
+= and that it correctly orders different buffers.
diff --git a/src/pal/tests/palsuite/c_runtime/memcpy/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/memcpy/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/memcpy/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/memcpy/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/memcpy/test1/CMakeLists.txt
new file mode 100644
index 0000000000..d846bfc62d
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/memcpy/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_memcpy_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_memcpy_test1 coreclrpal)
+
+target_link_libraries(paltest_memcpy_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/memcpy/test1/test1.c b/src/pal/tests/palsuite/c_runtime/memcpy/test1/test1.c
new file mode 100644
index 0000000000..9da98d6573
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/memcpy/test1/test1.c
@@ -0,0 +1,87 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Calls memcpy and verifies that the buffer was copied correctly.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char **argv)
+{
+ char testA[20];
+ char testB[20];
+ void *retVal;
+ long i;
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ memset(testA, 'a', 20);
+ memset(testB, 'b', 20);
+
+ retVal = (char *)memcpy(testB, testA, 0);
+ if (retVal != testB)
+ {
+ Fail("memcpy should return a pointer to the destination buffer, "
+ "but doesn't.\n");
+ }
+ for(i = 0; i<20; i++)
+ {
+ if (testB[i]!= 'b')
+ {
+ Fail("The destination buffer overflowed by memcpy.\n");
+ }
+ }
+
+ retVal = (char *)memcpy(testB+1, testA, 18);
+ if (retVal != testB+1)
+ {
+ Fail("memcpy should return a pointer to the destination buffer, "
+ "but doesn't.\n");
+ }
+
+ if (testB[0] != 'b' || testB[19] != 'b')
+ {
+ Fail("The destination buffer was written out of bounds by memcpy!\n");
+ }
+
+ for(i = 1; i<19; i++)
+ {
+ if (testB[i]!= 'a')
+ {
+ Fail("The destination buffer copied to by memcpy doesn't match "
+ "the source buffer.\n");
+ }
+ }
+
+ PAL_Terminate();
+
+ return PASS;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/memcpy/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/memcpy/test1/testinfo.dat
new file mode 100644
index 0000000000..157da6cf87
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/memcpy/test1/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = memcpy
+Name = Positive Test for memcpy
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Calls memcpy and verifies that the buffer was copied correctly.
diff --git a/src/pal/tests/palsuite/c_runtime/memmove/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/memmove/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/memmove/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/memmove/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/memmove/test1/CMakeLists.txt
new file mode 100644
index 0000000000..cf50ec01b7
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/memmove/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_memmove_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_memmove_test1 coreclrpal)
+
+target_link_libraries(paltest_memmove_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/memmove/test1/test1.c b/src/pal/tests/palsuite/c_runtime/memmove/test1/test1.c
new file mode 100644
index 0000000000..c1af871f4a
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/memmove/test1/test1.c
@@ -0,0 +1,116 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Test that memmove correctly copies text from one buffer
+** to another even when the buffers overlap.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char **argv)
+{
+ char testA[11] = "abcdefghij";
+ char testB[15] = "aabbccddeeffgg";
+ char testC[15] = "aabbccddeeffgg";
+ char testD[15] = "aabbccddeeffgg";
+ char insString[3] = "zzz";
+ char *retVal;
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ /* move a string onto itself */
+ retVal = (char *)memmove(testA + 2, testA, 8);
+ if (retVal != testA + 2)
+ {
+ Fail("The return value should have been the value of the destination"
+ "pointer, but wasn't\n");
+ }
+
+ /*Check the most likely error*/
+ if (memcmp(testA, "ababababab", 11) == 0)
+ {
+ Fail("memmove should have saved the characters in the region of"
+ " overlap between source and destination, but didn't.\n");
+ }
+
+ if (memcmp(testA, "ababcdefgh", 11) != 0)
+ {
+ /* not sure what exactly went wrong. */
+ Fail("memmove was called on a region containing the characters"
+ " \"abcdefghij\". It was to move the first 8 positions to"
+ " the last 8 positions, giving the result \"ababcdefgh\". "
+ " Instead, it gave the result \"%s\".\n", testA);
+ }
+
+ /* move a string to the front of testB */
+ retVal = (char *)memmove(testB, insString, 3);
+ if(retVal != testB)
+ {
+ Fail("memmove: The function did not return the correct "
+ "string.\n");
+ }
+
+ if(memcmp(testB, "zzzbccddeeffgg",15) != 0)
+ {
+ Fail("memmove: The function failed to move the string "
+ "correctly.\n");
+ }
+
+
+ /* move a string to the middle of testC */
+ retVal = memmove(testC+5, insString, 3);
+ if(retVal != testC+5)
+ {
+ Fail("memmove: The function did not return the correct "
+ "string.\n");
+ }
+
+ if(memcmp(testC, "aabbczzzeeffgg",15) != 0)
+ {
+ Fail("memmove: The function failed to move the string "
+ "correctly.\n");
+ }
+
+
+ /* move a string to the end of testD */
+ retVal = memmove(testD+11, insString, 3);
+ if(retVal != testD+11)
+ {
+ Fail("memmove: The function did not return the correct "
+ "string.\n");
+ }
+
+ if(memcmp(testD, "aabbccddeefzzz",15) != 0)
+ {
+ Fail("memmove: The function failed to move the string "
+ "correctly.\n");
+ }
+
+ PAL_Terminate();
+ return PASS;
+
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/memmove/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/memmove/test1/testinfo.dat
new file mode 100644
index 0000000000..d8d4c0ead9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/memmove/test1/testinfo.dat
@@ -0,0 +1,19 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = memmove
+Name = Positive Test for memmove
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Test that memmove correctly copies text from one buffer to another
+= even when the buffers overlap.
+
+
+
+
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/memset/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/memset/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/memset/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/memset/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/memset/test1/CMakeLists.txt
new file mode 100644
index 0000000000..78b5a6bc00
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/memset/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_memset_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_memset_test1 coreclrpal)
+
+target_link_libraries(paltest_memset_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/memset/test1/test1.c b/src/pal/tests/palsuite/c_runtime/memset/test1/test1.c
new file mode 100644
index 0000000000..67cde8756b
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/memset/test1/test1.c
@@ -0,0 +1,60 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Check that memset correctly fills a destination buffer
+** without overflowing it.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char **argv)
+{
+
+ char testA[22] = "bbbbbbbbbbbbbbbbbbbbb";
+ char *retVal;
+
+ int i;
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ retVal = (char *)memset(testA, 'a', 20);
+ if (retVal != testA)
+ {
+ Fail("memset should have returned the value of the destination"
+ "pointer, but didn't");
+ }
+
+ for(i = 0; i<20; i++)
+ {
+ if (testA[i]!= 'a')
+ {
+ Fail("memset didn't set the destination bytes.\n");
+ }
+ }
+ if (testA[20] == 'a')
+ {
+ Fail("memset overfilled the destination buffer.\n");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
+
+
+
+
+
+
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/memset/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/memset/test1/testinfo.dat
new file mode 100644
index 0000000000..cab02fb4b7
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/memset/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = memset
+Name = Positive Test for memset
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Check that memset correctly fills a destination buffer without overflowing it.
+
diff --git a/src/pal/tests/palsuite/c_runtime/modf/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/modf/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/modf/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/modf/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/modf/test1/CMakeLists.txt
new file mode 100644
index 0000000000..4b65ba7a6f
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/modf/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_modf_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_modf_test1 coreclrpal)
+
+target_link_libraries(paltest_modf_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/modf/test1/test1.c b/src/pal/tests/palsuite/c_runtime/modf/test1/test1.c
new file mode 100644
index 0000000000..389d079253
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/modf/test1/test1.c
@@ -0,0 +1,136 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================================
+**
+** Source: test1.c (modf)
+**
+** Purpose: Test to ensure that modf return the correct values
+**
+** Dependencies: PAL_Initialize
+** PAL_Terminate
+** Fail
+** fabs
+**
+**===========================================================================*/
+
+#include <palsuite.h>
+
+// binary64 (double) has a machine epsilon of 2^-52 (approx. 2.22e-16). However, this
+// is slightly too accurate when writing tests meant to run against libm implementations
+// for various platforms. 2^-50 (approx. 8.88e-16) seems to be as accurate as we can get.
+//
+// The tests themselves will take PAL_EPSILON and adjust it according to the expected result
+// so that the delta used for comparison will compare the most significant digits and ignore
+// any digits that are outside the double precision range (15-17 digits).
+
+// For example, a test with an expect result in the format of 0.xxxxxxxxxxxxxxxxx will use
+// PAL_EPSILON for the variance, while an expected result in the format of 0.0xxxxxxxxxxxxxxxxx
+// will use PAL_EPSILON / 10 and and expected result in the format of x.xxxxxxxxxxxxxxxx will
+// use PAL_EPSILON * 10.
+#define PAL_EPSILON 8.8817841970012523e-16
+
+#define PAL_NAN sqrt(-1.0)
+#define PAL_POSINF -log(0.0)
+#define PAL_NEGINF log(0.0)
+
+/**
+ * Helper test structure
+ */
+struct test
+{
+ double value; /* value to test the function with */
+ double expected; /* expected result */
+ double variance; /* maximum delta between the expected and actual result */
+ double expected_intpart; /* expected result */
+ double variance_intpart; /* maximum delta between the expected and actual result */
+};
+
+/**
+ * validate
+ *
+ * test validation function
+ */
+void __cdecl validate(double value, double expected, double variance, double expected_intpart, double variance_intpart)
+{
+ double result_intpart;
+ double result = modf(value, &result_intpart);
+
+ /*
+ * The test is valid when the difference between result
+ * and expected is less than or equal to variance
+ */
+ double delta = fabs(result - expected);
+ double delta_intpart = fabs(result_intpart - expected_intpart);
+
+ if ((delta > variance) || (delta_intpart > variance_intpart))
+ {
+ Fail("modf(%g) returned %20.17g with an intpart of %20.17g when it should have returned %20.17g with an intpart of %20.17g",
+ value, result, result_intpart, expected, expected_intpart);
+ }
+}
+
+/**
+ * validate
+ *
+ * test validation function for values returning NaN
+ */
+void __cdecl validate_isnan(double value)
+{
+ double result_intpart;
+ double result = modf(value, &result_intpart);
+
+ if (!_isnan(result) || !_isnan(result_intpart))
+ {
+ Fail("modf(%g) returned %20.17g with an intpart of %20.17g when it should have returned %20.17g with an intpart of %20.17g",
+ value, result, result_intpart, PAL_NAN, PAL_NAN);
+ }
+}
+
+/**
+ * main
+ *
+ * executable entry point
+ */
+int __cdecl main(int argc, char **argv)
+{
+ struct test tests[] =
+ {
+ /* value expected variance expected_intpart variance_intpart */
+ { 0, 0, PAL_EPSILON, 0, PAL_EPSILON },
+ { 0.31830988618379067, 0.31830988618379067, PAL_EPSILON, 0, PAL_EPSILON }, // value: 1 / pi
+ { 0.43429448190325183, 0.43429448190325183, PAL_EPSILON, 0, PAL_EPSILON }, // value: log10(e)
+ { 0.63661977236758134, 0.63661977236758134, PAL_EPSILON, 0, PAL_EPSILON }, // value: 2 / pi
+ { 0.69314718055994531, 0.69314718055994531, PAL_EPSILON, 0, PAL_EPSILON }, // value: ln(2)
+ { 0.70710678118654752, 0.70710678118654752, PAL_EPSILON, 0, PAL_EPSILON }, // value: 1 / sqrt(2)
+ { 0.78539816339744831, 0.78539816339744831, PAL_EPSILON, 0, PAL_EPSILON }, // value: pi / 4
+ { 1, 0, PAL_EPSILON, 1, PAL_EPSILON * 10 },
+ { 1.1283791670955126, 0.1283791670955126, PAL_EPSILON, 1, PAL_EPSILON * 10 }, // value: 2 / sqrt(pi)
+ { 1.4142135623730950, 0.4142135623730950, PAL_EPSILON, 1, PAL_EPSILON * 10 }, // value: sqrt(2)
+ { 1.4426950408889634, 0.4426950408889634, PAL_EPSILON, 1, PAL_EPSILON * 10 }, // value: log2(e)
+ { 1.5707963267948966, 0.5707963267948966, PAL_EPSILON, 1, PAL_EPSILON * 10 }, // value: pi / 2
+ { 2.3025850929940457, 0.3025850929940457, PAL_EPSILON, 2, PAL_EPSILON * 10 }, // value: ln(10)
+ { 2.7182818284590452, 0.7182818284590452, PAL_EPSILON, 2, PAL_EPSILON * 10 }, // value: e
+ { 3.1415926535897932, 0.1415926535897932, PAL_EPSILON, 3, PAL_EPSILON * 10 }, // value: pi
+ { PAL_POSINF, 0, PAL_EPSILON, PAL_POSINF, 0 }
+
+ };
+
+ /* PAL initialization */
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+ for (int i = 0; i < (sizeof(tests) / sizeof(struct test)); i++)
+ {
+ validate( tests[i].value, tests[i].expected, tests[i].variance, tests[i].expected_intpart, tests[i].variance_intpart);
+ validate(-tests[i].value, -tests[i].expected, tests[i].variance, -tests[i].expected_intpart, tests[i].variance_intpart);
+ }
+
+ validate_isnan(PAL_NAN);
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/modf/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/modf/test1/testinfo.dat
new file mode 100644
index 0000000000..203b553e20
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/modf/test1/testinfo.dat
@@ -0,0 +1,16 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = modf
+Name = Positive Test for modf
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Passes to modf() a series of values, checking that
+= each one return to correct value.
+
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/modff/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/modff/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/modff/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/modff/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/modff/test1/CMakeLists.txt
new file mode 100644
index 0000000000..812cd1c47b
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/modff/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_modff_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_modff_test1 coreclrpal)
+
+target_link_libraries(paltest_modff_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/modff/test1/test1.c b/src/pal/tests/palsuite/c_runtime/modff/test1/test1.c
new file mode 100644
index 0000000000..6b7a50be39
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/modff/test1/test1.c
@@ -0,0 +1,135 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================================
+**
+** Source: test1.c (modf)
+**
+** Purpose: Test to ensure that modf return the correct values
+**
+** Dependencies: PAL_Initialize
+** PAL_Terminate
+** Fail
+** fabs
+**
+**===========================================================================*/
+
+#include <palsuite.h>
+
+// binary32 (float) has a machine epsilon of 2^-23 (approx. 1.19e-07). However, this
+// is slightly too accurate when writing tests meant to run against libm implementations
+// for various platforms. 2^-21 (approx. 4.76e-07) seems to be as accurate as we can get.
+//
+// The tests themselves will take PAL_EPSILON and adjust it according to the expected result
+// so that the delta used for comparison will compare the most significant digits and ignore
+// any digits that are outside the double precision range (6-9 digits).
+
+// For example, a test with an expect result in the format of 0.xxxxxxxxx will use PAL_EPSILON
+// for the variance, while an expected result in the format of 0.0xxxxxxxxx will use
+// PAL_EPSILON / 10 and and expected result in the format of x.xxxxxx will use PAL_EPSILON * 10.
+#define PAL_EPSILON 4.76837158e-07
+
+#define PAL_NAN sqrt(-1.0)
+#define PAL_POSINF -log(0.0)
+#define PAL_NEGINF log(0.0)
+
+/**
+ * Helper test structure
+ */
+struct test
+{
+ float value; /* value to test the function with */
+ float expected; /* expected result */
+ float variance; /* maximum delta between the expected and actual result */
+ float expected_intpart; /* expected result */
+ float variance_intpart; /* maximum delta between the expected and actual result */
+};
+
+/**
+ * validate
+ *
+ * test validation function
+ */
+void __cdecl validate(float value, float expected, float variance, float expected_intpart, float variance_intpart)
+{
+ float result_intpart;
+ float result = modff(value, &result_intpart);
+
+ /*
+ * The test is valid when the difference between result
+ * and expected is less than or equal to variance
+ */
+ float delta = fabsf(result - expected);
+ float delta_intpart = fabsf(result_intpart - expected_intpart);
+
+ if ((delta > variance) || (delta_intpart > variance_intpart))
+ {
+ Fail("modff(%g) returned %10.9g with an intpart of %10.9g when it should have returned %10.9g with an intpart of %10.9g",
+ value, result, result_intpart, expected, expected_intpart);
+ }
+}
+
+/**
+ * validate
+ *
+ * test validation function for values returning NaN
+ */
+void __cdecl validate_isnan(float value)
+{
+ float result_intpart;
+ float result = modff(value, &result_intpart);
+
+ if (!_isnan(result) || !_isnan(result_intpart))
+ {
+ Fail("modff(%g) returned %10.9g with an intpart of %10.9g when it should have returned %10.9g with an intpart of %10.9g",
+ value, result, result_intpart, PAL_NAN, PAL_NAN);
+ }
+}
+
+/**
+ * main
+ *
+ * executable entry point
+ */
+int __cdecl main(int argc, char **argv)
+{
+ struct test tests[] =
+ {
+ /* value expected variance expected_intpart variance_intpart */
+ { 0, 0, PAL_EPSILON, 0, PAL_EPSILON },
+ { 0.318309886f, 0.318309886f, PAL_EPSILON, 0, PAL_EPSILON }, // value: 1 / pi
+ { 0.434294482f, 0.434294482f, PAL_EPSILON, 0, PAL_EPSILON }, // value: log10(e)
+ { 0.636619772f, 0.636619772f, PAL_EPSILON, 0, PAL_EPSILON }, // value: 2 / pi
+ { 0.693147181f, 0.693147181f, PAL_EPSILON, 0, PAL_EPSILON }, // value: ln(2)
+ { 0.707106781f, 0.707106781f, PAL_EPSILON, 0, PAL_EPSILON }, // value: 1 / sqrt(2)
+ { 0.785398163f, 0.785398163f, PAL_EPSILON, 0, PAL_EPSILON }, // value: pi / 4
+ { 1, 0, PAL_EPSILON, 1, PAL_EPSILON * 10 },
+ { 1.12837917f, 0.128379167f, PAL_EPSILON, 1, PAL_EPSILON * 10 }, // value: 2 / sqrt(pi)
+ { 1.41421356f, 0.414213562f, PAL_EPSILON, 1, PAL_EPSILON * 10 }, // value: sqrt(2)
+ { 1.44269504f, 0.442695041f, PAL_EPSILON, 1, PAL_EPSILON * 10 }, // value: log2(e)
+ { 1.57079633f, 0.570796327f, PAL_EPSILON, 1, PAL_EPSILON * 10 }, // value: pi / 2
+ { 2.30258509f, 0.302585093f, PAL_EPSILON, 2, PAL_EPSILON * 10 }, // value: ln(10)
+ { 2.71828183f, 0.718281828f, PAL_EPSILON, 2, PAL_EPSILON * 10 }, // value: e
+ { 3.14159265f, 0.141592654f, PAL_EPSILON, 3, PAL_EPSILON * 10 }, // value: pi
+ { PAL_POSINF, 0, PAL_EPSILON, PAL_POSINF, 0 }
+
+ };
+
+ /* PAL initialization */
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+ for (int i = 0; i < (sizeof(tests) / sizeof(struct test)); i++)
+ {
+ validate( tests[i].value, tests[i].expected, tests[i].variance, tests[i].expected_intpart, tests[i].variance_intpart);
+ validate(-tests[i].value, -tests[i].expected, tests[i].variance, -tests[i].expected_intpart, tests[i].variance_intpart);
+ }
+
+ validate_isnan(PAL_NAN);
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/modff/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/modff/test1/testinfo.dat
new file mode 100644
index 0000000000..392491e3be
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/modff/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = modff
+Name = Positive Test for modff
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Passes to modff() a series of values, checking that
+= each one return to correct value.
diff --git a/src/pal/tests/palsuite/c_runtime/pow/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/pow/CMakeLists.txt
new file mode 100644
index 0000000000..5e1ef7f28b
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/pow/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
diff --git a/src/pal/tests/palsuite/c_runtime/pow/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/pow/test1/CMakeLists.txt
new file mode 100644
index 0000000000..69ba02af17
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/pow/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_pow_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_pow_test1 coreclrpal)
+
+target_link_libraries(paltest_pow_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/pow/test1/test1.c b/src/pal/tests/palsuite/c_runtime/pow/test1/test1.c
new file mode 100644
index 0000000000..0a05cd5a47
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/pow/test1/test1.c
@@ -0,0 +1,230 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test1.c
+**
+** Purpose: Tests that atan2 returns correct values for a subset of values.
+** Tests with positive and negative values of x and y to ensure
+** atan2 is returning results from the correct quadrant.
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+// binary64 (double) has a machine epsilon of 2^-52 (approx. 2.22e-16). However, this
+// is slightly too accurate when writing tests meant to run against libm implementations
+// for various platforms. 2^-50 (approx. 8.88e-16) seems to be as accurate as we can get.
+//
+// The tests themselves will take PAL_EPSILON and adjust it according to the expected result
+// so that the delta used for comparison will compare the most significant digits and ignore
+// any digits that are outside the double precision range (15-17 digits).
+
+// For example, a test with an expect result in the format of 0.xxxxxxxxxxxxxxxxx will use
+// PAL_EPSILON for the variance, while an expected result in the format of 0.0xxxxxxxxxxxxxxxxx
+// will use PAL_EPSILON / 10 and and expected result in the format of x.xxxxxxxxxxxxxxxx will
+// use PAL_EPSILON * 10.
+#define PAL_EPSILON 8.8817841970012523e-16
+
+#define PAL_NAN sqrt(-1.0)
+#define PAL_POSINF -log(0.0)
+#define PAL_NEGINF log(0.0)
+
+/**
+ * Helper test structure
+ */
+struct test
+{
+ double x; /* first component of the value to test the function with */
+ double y; /* second component of the value to test the function with */
+ double expected; /* expected result */
+ double variance; /* maximum delta between the expected and actual result */
+};
+
+/**
+ * validate
+ *
+ * test validation function
+ */
+void __cdecl validate(double x, double y, double expected, double variance)
+{
+ double result = pow(x, y);
+
+ /*
+ * The test is valid when the difference between result
+ * and expected is less than or equal to variance
+ */
+ double delta = fabs(result - expected);
+
+ if (delta > variance)
+ {
+ Fail("pow(%g, %g) returned %20.17g when it should have returned %20.17g",
+ x, y, result, expected);
+ }
+}
+
+/**
+ * validate
+ *
+ * test validation function for values returning NaN
+ */
+void __cdecl validate_isnan(double x, double y)
+{
+ double result = pow(x, y);
+
+ if (!_isnan(result))
+ {
+ Fail("pow(%g, %g) returned %20.17g when it should have returned %20.17g",
+ x, y, result, PAL_NAN);
+ }
+}
+
+/**
+ * main
+ *
+ * executable entry point
+ */
+int __cdecl main(int argc, char **argv)
+{
+ struct test tests[] =
+ {
+ /* x y expected variance */
+ { PAL_NEGINF, PAL_NEGINF, 0, PAL_EPSILON },
+ { PAL_NEGINF, PAL_POSINF, PAL_POSINF, 0 },
+
+ { -10, PAL_NEGINF, 0, PAL_EPSILON },
+ { -10, -1, -0.1, PAL_EPSILON },
+ { -10, 0, 1, PAL_EPSILON * 10 },
+ { -10, 1, -10, PAL_EPSILON * 100 },
+ { -10, PAL_POSINF, PAL_POSINF, 0 },
+
+ { -2.7182818284590452, PAL_NEGINF, 0, PAL_EPSILON }, // x: -(e)
+ { -2.7182818284590452, -1, -0.36787944117144232, PAL_EPSILON }, // x: -(e)
+ { -2.7182818284590452, 0, 1, PAL_EPSILON * 10 }, // x: -(e)
+ { -2.7182818284590452, 1, -2.7182818284590452, PAL_EPSILON * 10 }, // x: -(e) expected: e
+ { -2.7182818284590452, PAL_POSINF, PAL_POSINF, 0 }, // x: -(e)
+
+ { -0.0, PAL_NEGINF, PAL_POSINF, 0 },
+ { -0.0, -1, PAL_NEGINF, 0 },
+ { -0.0, -0.0, 1, PAL_EPSILON * 10 },
+ { -0.0, 0, 1, PAL_EPSILON * 10 },
+ { -0.0, 1, -0.0, PAL_EPSILON },
+ { -0.0, PAL_POSINF, 0, PAL_EPSILON },
+
+ { 0.0, PAL_NEGINF, PAL_POSINF, 0 },
+ { 0.0, -1, PAL_POSINF, 0 },
+ { 0, -0.0, 1, PAL_EPSILON * 10 },
+ { 0, 0, 1, PAL_EPSILON * 10 },
+ { 0.0, 1, 0, PAL_EPSILON },
+ { 0.0, PAL_POSINF, 0, PAL_EPSILON },
+
+ { 1, PAL_NEGINF, 1, PAL_EPSILON * 10 },
+ { 1, PAL_POSINF, 1, PAL_EPSILON * 10 },
+
+ { 2.7182818284590452, PAL_NEGINF, 0, PAL_EPSILON },
+ { 2.7182818284590452, -3.1415926535897932, 0.043213918263772250, PAL_EPSILON / 10 }, // x: e y: -(pi)
+ { 2.7182818284590452, -2.7182818284590452, 0.065988035845312537, PAL_EPSILON / 10 }, // x: e y: -(e)
+ { 2.7182818284590452, -2.3025850929940457, 0.1, PAL_EPSILON }, // x: e y: -(ln(10))
+ { 2.7182818284590452, -1.5707963267948966, 0.20787957635076191, PAL_EPSILON }, // x: e y: -(pi / 2)
+ { 2.7182818284590452, -1.4426950408889634, 0.23629008834452270, PAL_EPSILON }, // x: e y: -(log2(e))
+ { 2.7182818284590452, -1.4142135623730950, 0.24311673443421421, PAL_EPSILON }, // x: e y: -(sqrt(2))
+ { 2.7182818284590452, -1.1283791670955126, 0.32355726390307110, PAL_EPSILON }, // x: e y: -(2 / sqrt(pi))
+ { 2.7182818284590452, -1, 0.36787944117144232, PAL_EPSILON }, // x: e y: -(1)
+ { 2.7182818284590452, -0.78539816339744831, 0.45593812776599624, PAL_EPSILON }, // x: e y: -(pi / 4)
+ { 2.7182818284590452, -0.70710678118654752, 0.49306869139523979, PAL_EPSILON }, // x: e y: -(1 / sqrt(2))
+ { 2.7182818284590452, -0.69314718055994531, 0.5, PAL_EPSILON }, // x: e y: -(ln(2))
+ { 2.7182818284590452, -0.63661977236758134, 0.52907780826773535, PAL_EPSILON }, // x: e y: -(2 / pi)
+ { 2.7182818284590452, -0.43429448190325183, 0.64772148514180065, PAL_EPSILON }, // x: e y: -(log10(e))
+ { 2.7182818284590452, -0.31830988618379067, 0.72737734929521647, PAL_EPSILON }, // x: e y: -(1 / pi)
+ { 2.7182818284590452, 0, 1, PAL_EPSILON * 10 }, // x: e
+ { 2.7182818284590452, 0.31830988618379067, 1.3748022274393586, PAL_EPSILON * 10 }, // x: e y: 1 / pi
+ { 2.7182818284590452, 0.43429448190325183, 1.5438734439711811, PAL_EPSILON * 10 }, // x: e y: log10(e)
+ { 2.7182818284590452, 0.63661977236758134, 1.8900811645722220, PAL_EPSILON * 10 }, // x: e y: 2 / pi
+ { 2.7182818284590452, 0.69314718055994531, 2, PAL_EPSILON * 10 }, // x: e y: ln(2)
+ { 2.7182818284590452, 0.70710678118654752, 2.0281149816474725, PAL_EPSILON * 10 }, // x: e y: 1 / sqrt(2)
+ { 2.7182818284590452, 0.78539816339744831, 2.1932800507380155, PAL_EPSILON * 10 }, // x: e y: pi / 4
+ { 2.7182818284590452, 1, 2.7182818284590452, PAL_EPSILON * 10 }, // x: e expected: e
+ { 2.7182818284590452, 1.1283791670955126, 3.0906430223107976, PAL_EPSILON * 10 }, // x: e y: 2 / sqrt(pi)
+ { 2.7182818284590452, 1.4142135623730950, 4.1132503787829275, PAL_EPSILON * 10 }, // x: e y: sqrt(2)
+ { 2.7182818284590452, 1.4426950408889634, 4.2320861065570819, PAL_EPSILON * 10 }, // x: e y: log2(e)
+ { 2.7182818284590452, 1.5707963267948966, 4.8104773809653517, PAL_EPSILON * 10 }, // x: e y: pi / 2
+ { 2.7182818284590452, 2.3025850929940457, 10, PAL_EPSILON * 100 }, // x: e y: ln(10)
+ { 2.7182818284590452, 2.7182818284590452, 15.154262241479264, PAL_EPSILON * 100 }, // x: e y: e
+ { 2.7182818284590452, 3.1415926535897932, 23.140692632779269, PAL_EPSILON * 100 }, // x: e y: pi
+ { 2.7182818284590452, PAL_POSINF, PAL_POSINF, 0 }, // x: e
+
+ { 10, PAL_NEGINF, 0, 0 },
+ { 10, -3.1415926535897932, 0.00072178415907472774, PAL_EPSILON / 1000 }, // y: -(pi)
+ { 10, -2.7182818284590452, 0.0019130141022243176, PAL_EPSILON / 100 }, // y: -(e)
+ { 10, -2.3025850929940457, 0.0049821282964407206, PAL_EPSILON / 100 }, // y: -(ln(10))
+ { 10, -1.5707963267948966, 0.026866041001136132, PAL_EPSILON / 10 }, // y: -(pi / 2)
+ { 10, -1.4426950408889634, 0.036083192820787210, PAL_EPSILON / 10 }, // y: -(log2(e))
+ { 10, -1.4142135623730950, 0.038528884700322026, PAL_EPSILON / 10 }, // y: -(sqrt(2))
+ { 10, -1.1283791670955126, 0.074408205860642723, PAL_EPSILON / 10 }, // y: -(2 / sqrt(pi))
+ { 10, -1, 0.1, PAL_EPSILON }, // y: -(1)
+ { 10, -0.78539816339744831, 0.16390863613957665, PAL_EPSILON }, // y: -(pi / 4)
+ { 10, -0.70710678118654752, 0.19628775993505562, PAL_EPSILON }, // y: -(1 / sqrt(2))
+ { 10, -0.69314718055994531, 0.20269956628651730, PAL_EPSILON }, // y: -(ln(2))
+ { 10, -0.63661977236758134, 0.23087676451600055, PAL_EPSILON }, // y: -(2 / pi)
+ { 10, -0.43429448190325183, 0.36787944117144232, PAL_EPSILON }, // y: -(log10(e))
+ { 10, -0.31830988618379067, 0.48049637305186868, PAL_EPSILON }, // y: -(1 / pi)
+ { 10, 0, 1, PAL_EPSILON * 10 },
+ { 10, 0.31830988618379067, 2.0811811619898573, PAL_EPSILON * 10 }, // y: 1 / pi
+ { 10, 0.43429448190325183, 2.7182818284590452, PAL_EPSILON * 10 }, // y: log10(e) expected: e
+ { 10, 0.63661977236758134, 4.3313150290214525, PAL_EPSILON * 10 }, // y: 2 / pi
+ { 10, 0.69314718055994531, 4.9334096679145963, PAL_EPSILON * 10 }, // y: ln(2)
+ { 10, 0.70710678118654752, 5.0945611704512962, PAL_EPSILON * 10 }, // y: 1 / sqrt(2)
+ { 10, 0.78539816339744831, 6.1009598002416937, PAL_EPSILON * 10 }, // y: pi / 4
+ { 10, 1, 10, PAL_EPSILON * 100 },
+ { 10, 1.1283791670955126, 13.439377934644400, PAL_EPSILON * 100 }, // y: 2 / sqrt(pi)
+ { 10, 1.4142135623730950, 25.954553519470081, PAL_EPSILON * 100 }, // y: sqrt(2)
+ { 10, 1.4426950408889634, 27.713733786437790, PAL_EPSILON * 100 }, // y: log2(e)
+ { 10, 1.5707963267948966, 37.221710484165167, PAL_EPSILON * 100 }, // y: pi / 2
+ { 10, 2.3025850929940457, 200.71743249053009, PAL_EPSILON * 1000 }, // y: ln(10)
+ { 10, 2.7182818284590452, 522.73529967043665, PAL_EPSILON * 1000 }, // y: e
+ { 10, 3.1415926535897932, 1385.4557313670111, PAL_EPSILON * 10000 }, // y: pi
+ { 10, PAL_POSINF, PAL_POSINF, 0 },
+
+ { PAL_POSINF, PAL_NEGINF, 0, PAL_EPSILON },
+ { PAL_POSINF, PAL_POSINF, PAL_POSINF, 0 },
+ };
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+ for (int i = 0; i < (sizeof(tests) / sizeof(struct test)); i++)
+ {
+ validate(tests[i].x, tests[i].y, tests[i].expected, tests[i].variance);
+ }
+
+ validate_isnan(-10, -1.5707963267948966); // y: -(pi / 2)
+ validate_isnan(-10, -0.78539816339744828); // y: -(pi / 4)
+ validate_isnan(-10, 0.78539816339744828); // y: pi / 4
+ validate_isnan(-10, 1.5707963267948966); // y: pi / 2
+
+ validate_isnan(-2.7182818284590452, -1.5707963267948966); // x: -(e) y: -(pi / 2)
+ validate_isnan(-2.7182818284590452, -0.78539816339744828); // x: -(e) y: -(pi / 4)
+ validate_isnan(-2.7182818284590452, 0.78539816339744828); // x: -(e) y: pi / 4
+ validate_isnan(-2.7182818284590452, 1.5707963267948966); // x: -(e) y: pi / 2
+
+ validate_isnan(-1, PAL_NEGINF);
+ validate_isnan(-1, PAL_POSINF);
+
+ validate_isnan(PAL_NAN, -0.0);
+ validate_isnan(PAL_NAN, 0);
+
+ validate_isnan(PAL_NEGINF, PAL_NAN);
+ validate_isnan(PAL_NAN, PAL_NEGINF);
+
+ validate_isnan(PAL_POSINF, PAL_NAN);
+ validate_isnan(PAL_NAN, PAL_POSINF);
+
+ validate_isnan(PAL_NAN, PAL_NAN);
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/pow/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/pow/test1/testinfo.dat
new file mode 100644
index 0000000000..cf106d90ed
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/pow/test1/testinfo.dat
@@ -0,0 +1,17 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = pow
+Name = Call pow with some std input/output.
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Call the pow function with various num/exponent pairs
+= that should produce std answers.
+
+
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/printf/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/printf/CMakeLists.txt
new file mode 100644
index 0000000000..cafb9536b0
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/printf/CMakeLists.txt
@@ -0,0 +1,22 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test10)
+add_subdirectory(test11)
+add_subdirectory(test12)
+add_subdirectory(test13)
+add_subdirectory(test14)
+add_subdirectory(test15)
+add_subdirectory(test16)
+add_subdirectory(test17)
+add_subdirectory(test18)
+add_subdirectory(test19)
+add_subdirectory(test2)
+add_subdirectory(test3)
+add_subdirectory(test4)
+add_subdirectory(test5)
+add_subdirectory(test6)
+add_subdirectory(test7)
+add_subdirectory(test8)
+add_subdirectory(test9)
+
diff --git a/src/pal/tests/palsuite/c_runtime/printf/printf.h b/src/pal/tests/palsuite/c_runtime/printf/printf.h
new file mode 100644
index 0000000000..2eaa984bad
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/printf/printf.h
@@ -0,0 +1,182 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: printf.h
+**
+** Purpose: Containts common testing functions for printf
+**
+**
+**==========================================================================*/
+
+#ifndef __printf_H__
+#define __printf_H__
+
+void DoStrTest(char *formatstr, char* param, char *checkstr)
+{
+ int ret;
+
+ ret = printf(formatstr, param);
+ if (ret != strlen(checkstr))
+ {
+ Fail("Expected printf to return %d, got %d.\n",
+ strlen(checkstr), ret);
+ }
+}
+
+void DoWStrTest(char *formatstr, WCHAR* param, char *checkstr)
+{
+ int ret;
+
+ ret = printf(formatstr, param);
+ if (ret != strlen(checkstr))
+ {
+ Fail("Expected printf to return %d, got %d.\n",
+ strlen(checkstr), ret);
+ }
+}
+
+void DoPointerTest(char *formatstr, void* param, char* paramstr,
+ char *checkstr1)
+{
+ int ret;
+
+ ret = printf(formatstr, param);
+ if (ret != strlen(checkstr1))
+ {
+ Fail("Expected printf to return %d, got %d.\n",
+ strlen(checkstr1), ret);
+ }
+}
+
+void DoCountTest(char *formatstr, int param, char *checkstr)
+{
+ int ret;
+ int n = -1;
+
+ ret = printf(formatstr, &n);
+
+ if (n != param)
+ {
+ Fail("Expected count parameter to resolve to %d, got %d\n", param, n);
+ }
+
+ if (ret != strlen(checkstr))
+ {
+ Fail("Expected printf to return %d, got %d.\n",
+ strlen(checkstr), ret);
+ }
+}
+
+void DoShortCountTest(char *formatstr, int param, char *checkstr)
+{
+ int ret;
+ short int n = -1;
+
+ ret = printf(formatstr, &n);
+
+ if (n != param)
+ {
+ Fail("Expected count parameter to resolve to %d, got %d\n", param, n);
+ }
+
+ if (ret != strlen(checkstr))
+ {
+ Fail("Expected printf to return %d, got %d.\n",
+ strlen(checkstr), ret);
+ }
+}
+
+
+void DoCharTest(char *formatstr, char param, char *checkstr)
+{
+ int ret;
+
+ ret = printf(formatstr, param);
+ if (ret != strlen(checkstr))
+ {
+ Fail("Expected printf to return %d, got %d.\n",
+ strlen(checkstr), ret);
+ }
+}
+
+void DoWCharTest(char *formatstr, WCHAR param, char *checkstr)
+{
+ int ret;
+
+ ret = printf(formatstr, param);
+ if (ret != strlen(checkstr))
+ {
+ Fail("Expected printf to return %d, got %d.\n",
+ strlen(checkstr), ret);
+ }
+}
+
+void DoNumTest(char *formatstr, int param, char *checkstr)
+{
+ int ret;
+
+ ret = printf(formatstr, param);
+ if (ret != strlen(checkstr))
+ {
+ Fail("Expected printf to return %d, got %d.\n",
+ strlen(checkstr), ret);
+ }
+}
+
+void DoI64Test(char *formatstr, INT64 param, char *valuestr,
+ char *checkstr1)
+{
+ int ret;
+
+ ret = printf(formatstr, param);
+ if (ret != strlen(checkstr1))
+ {
+ Fail("Expected printf to return %d, got %d.\n",
+ strlen(checkstr1), ret);
+ }
+}
+
+void DoDoubleTest(char *formatstr, double param,
+ char *checkstr1, char *checkstr2)
+{
+ int ret;
+
+ ret = printf(formatstr, param);
+ if (ret != strlen(checkstr1) && ret != strlen(checkstr2))
+ {
+ Fail("Expected printf to return %d or %d, got %d.\n",
+ strlen(checkstr1), strlen(checkstr2), ret);
+ }
+}
+
+void DoArgumentPrecTest(char *formatstr, int precision, void *param,
+ char *paramstr, char *checkstr1, char *checkstr2)
+{
+ int ret;
+
+ ret = printf(formatstr, precision, param);
+ if (ret != strlen(checkstr1) && ret != strlen(checkstr2))
+ {
+ Fail("Expected printf to return %d or %d, got %d.\n",
+ strlen(checkstr1), strlen(checkstr2), ret);
+ }
+}
+
+void DoArgumentPrecDoubleTest(char *formatstr, int precision, double param,
+ char *checkstr1, char *checkstr2)
+{
+ int ret;
+
+ ret = printf(formatstr, precision, param);
+ if (ret != strlen(checkstr1) && ret != strlen(checkstr2))
+ {
+ Fail("Expected printf to return %d or %d, got %d.\n",
+ strlen(checkstr1), strlen(checkstr2), ret);
+ }
+}
+
+#endif
+
diff --git a/src/pal/tests/palsuite/c_runtime/printf/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/printf/test1/CMakeLists.txt
new file mode 100644
index 0000000000..bea9151ed7
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/printf/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_printf_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_printf_test1 coreclrpal)
+
+target_link_libraries(paltest_printf_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/printf/test1/test1.c b/src/pal/tests/palsuite/c_runtime/printf/test1/test1.c
new file mode 100644
index 0000000000..31b7014343
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/printf/test1/test1.c
@@ -0,0 +1,43 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Test #1 for the printf function. A single, basic, test
+** case with no formatting.
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../printf.h"
+
+int __cdecl main(int argc, char *argv[])
+{
+ char checkstr[] = "hello world";
+ int ret;
+
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ ret = printf("hello world");
+
+ if (ret != strlen(checkstr))
+ {
+ Fail("Expected printf to return %d, got %d.\n",
+ strlen(checkstr), ret);
+
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/printf/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/printf/test1/testinfo.dat
new file mode 100644
index 0000000000..fe8bee680e
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/printf/test1/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = printf
+Name = Positive Test for printf
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= General test to see if printf works correctly
diff --git a/src/pal/tests/palsuite/c_runtime/printf/test10/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/printf/test10/CMakeLists.txt
new file mode 100644
index 0000000000..89ff2e0190
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/printf/test10/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test10.c
+)
+
+add_executable(paltest_printf_test10
+ ${SOURCES}
+)
+
+add_dependencies(paltest_printf_test10 coreclrpal)
+
+target_link_libraries(paltest_printf_test10
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/printf/test10/test10.c b/src/pal/tests/palsuite/c_runtime/printf/test10/test10.c
new file mode 100644
index 0000000000..5e69175b07
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/printf/test10/test10.c
@@ -0,0 +1,52 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test10.c
+**
+** Purpose: Test #10 for the printf function. Tests the octal specifier
+** (%o).
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../printf.h"
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ int neg = -42;
+ int pos = 42;
+ INT64 l = 42;
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ DoNumTest("foo %o", pos, "foo 52");
+ DoNumTest("foo %lo", 0xFFFF, "foo 177777");
+ DoNumTest("foo %ho", 0xFFFF, "foo 177777");
+ DoNumTest("foo %Lo", pos, "foo 52");
+ DoI64Test("foo %I64o", l, "42", "foo 52");
+ DoNumTest("foo %3o", pos, "foo 52");
+ DoNumTest("foo %-3o", pos, "foo 52 ");
+ DoNumTest("foo %.1o", pos, "foo 52");
+ DoNumTest("foo %.3o", pos, "foo 052");
+ DoNumTest("foo %03o", pos, "foo 052");
+ DoNumTest("foo %#o", pos, "foo 052");
+ DoNumTest("foo %+o", pos, "foo 52");
+ DoNumTest("foo % o", pos, "foo 52");
+ DoNumTest("foo %+o", neg, "foo 37777777726");
+ DoNumTest("foo % o", neg, "foo 37777777726");
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/printf/test10/testinfo.dat b/src/pal/tests/palsuite/c_runtime/printf/test10/testinfo.dat
new file mode 100644
index 0000000000..7667a0f461
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/printf/test10/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = printf
+Name = Positive Test for printf
+TYPE = DEFAULT
+EXE1 = test10
+Description
+= Tests printf with octal numbers
diff --git a/src/pal/tests/palsuite/c_runtime/printf/test11/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/printf/test11/CMakeLists.txt
new file mode 100644
index 0000000000..349f154a8d
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/printf/test11/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test11.c
+)
+
+add_executable(paltest_printf_test11
+ ${SOURCES}
+)
+
+add_dependencies(paltest_printf_test11 coreclrpal)
+
+target_link_libraries(paltest_printf_test11
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/printf/test11/test11.c b/src/pal/tests/palsuite/c_runtime/printf/test11/test11.c
new file mode 100644
index 0000000000..788be8b2db
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/printf/test11/test11.c
@@ -0,0 +1,51 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test11.c
+**
+** Purpose: Test #11 for the printf function. Test the unsigned int
+** specifier (%u).
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../printf.h"
+
+int __cdecl main(int argc, char *argv[])
+{
+ int neg = -42;
+ int pos = 42;
+ INT64 l = 42;
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ DoNumTest("foo %u", pos, "foo 42");
+ DoNumTest("foo %lu", 0xFFFF, "foo 65535");
+ DoNumTest("foo %hu", 0xFFFF, "foo 65535");
+ DoNumTest("foo %Lu", pos, "foo 42");
+ DoI64Test("foo %I64u", l, "42", "foo 42");
+ DoNumTest("foo %3u", pos, "foo 42");
+ DoNumTest("foo %-3u", pos, "foo 42 ");
+ DoNumTest("foo %.1u", pos, "foo 42");
+ DoNumTest("foo %.3u", pos, "foo 042");
+ DoNumTest("foo %03u", pos, "foo 042");
+ DoNumTest("foo %#u", pos, "foo 42");
+ DoNumTest("foo %+u", pos, "foo 42");
+ DoNumTest("foo % u", pos, "foo 42");
+ DoNumTest("foo %+u", neg, "foo 4294967254");
+ DoNumTest("foo % u", neg, "foo 4294967254");
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/printf/test11/testinfo.dat b/src/pal/tests/palsuite/c_runtime/printf/test11/testinfo.dat
new file mode 100644
index 0000000000..a88e0d8fcb
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/printf/test11/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = printf
+Name = Positive Test for printf
+TYPE = DEFAULT
+EXE1 = test11
+Description
+= Tests printf with unsigned numbers
diff --git a/src/pal/tests/palsuite/c_runtime/printf/test12/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/printf/test12/CMakeLists.txt
new file mode 100644
index 0000000000..0d32ee1690
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/printf/test12/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test12.c
+)
+
+add_executable(paltest_printf_test12
+ ${SOURCES}
+)
+
+add_dependencies(paltest_printf_test12 coreclrpal)
+
+target_link_libraries(paltest_printf_test12
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/printf/test12/test12.c b/src/pal/tests/palsuite/c_runtime/printf/test12/test12.c
new file mode 100644
index 0000000000..b4006f2405
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/printf/test12/test12.c
@@ -0,0 +1,53 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test12.c
+**
+** Purpose: Test #12 for the printf function. Tests the (lowercase)
+** hexadecimal specifier (%x)
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../printf.h"
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ int neg = -42;
+ int pos = 0x1234ab;
+ INT64 l = I64(0x1234567887654321);
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ DoNumTest("foo %x", pos, "foo 1234ab");
+ DoNumTest("foo %lx", pos, "foo 1234ab");
+ DoNumTest("foo %hx", pos, "foo 34ab");
+ DoNumTest("foo %Lx", pos, "foo 1234ab");
+ DoI64Test("foo %I64x", l, "0x1234567887654321",
+ "foo 1234567887654321");
+ DoNumTest("foo %7x", pos, "foo 1234ab");
+ DoNumTest("foo %-7x", pos, "foo 1234ab ");
+ DoNumTest("foo %.1x", pos, "foo 1234ab");
+ DoNumTest("foo %.7x", pos, "foo 01234ab");
+ DoNumTest("foo %07x", pos, "foo 01234ab");
+ DoNumTest("foo %#x", pos, "foo 0x1234ab");
+ DoNumTest("foo %+x", pos, "foo 1234ab");
+ DoNumTest("foo % x", pos, "foo 1234ab");
+ DoNumTest("foo %+x", neg, "foo ffffffd6");
+ DoNumTest("foo % x", neg, "foo ffffffd6");
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/printf/test12/testinfo.dat b/src/pal/tests/palsuite/c_runtime/printf/test12/testinfo.dat
new file mode 100644
index 0000000000..a6e317f905
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/printf/test12/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = printf
+Name = Positive Test for printf
+TYPE = DEFAULT
+EXE1 = test12
+Description
+= Tests printf with hex numbers (lowercase)
diff --git a/src/pal/tests/palsuite/c_runtime/printf/test13/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/printf/test13/CMakeLists.txt
new file mode 100644
index 0000000000..348d25b22d
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/printf/test13/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test13.c
+)
+
+add_executable(paltest_printf_test13
+ ${SOURCES}
+)
+
+add_dependencies(paltest_printf_test13 coreclrpal)
+
+target_link_libraries(paltest_printf_test13
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/printf/test13/test13.c b/src/pal/tests/palsuite/c_runtime/printf/test13/test13.c
new file mode 100644
index 0000000000..ccd16b50d2
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/printf/test13/test13.c
@@ -0,0 +1,54 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test13.c
+**
+** Purpose: Test #13 for the printf function. Tests the (uppercase)
+** hexadecimal specifier (%X)
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../printf.h"
+
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ int neg = -42;
+ int pos = 0x1234AB;
+ INT64 l = I64(0x1234567887654321);
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ DoNumTest("foo %X", pos, "foo 1234AB");
+ DoNumTest("foo %lX", pos, "foo 1234AB");
+ DoNumTest("foo %hX", pos, "foo 34AB");
+ DoNumTest("foo %LX", pos, "foo 1234AB");
+ DoI64Test("foo %I64X", l, "0x1234567887654321",
+ "foo 1234567887654321");
+ DoNumTest("foo %7X", pos, "foo 1234AB");
+ DoNumTest("foo %-7X", pos, "foo 1234AB ");
+ DoNumTest("foo %.1X", pos, "foo 1234AB");
+ DoNumTest("foo %.7X", pos, "foo 01234AB");
+ DoNumTest("foo %07X", pos, "foo 01234AB");
+ DoNumTest("foo %#X", pos, "foo 0X1234AB");
+ DoNumTest("foo %+X", pos, "foo 1234AB");
+ DoNumTest("foo % X", pos, "foo 1234AB");
+ DoNumTest("foo %+X", neg, "foo FFFFFFD6");
+ DoNumTest("foo % X", neg, "foo FFFFFFD6");
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/printf/test13/testinfo.dat b/src/pal/tests/palsuite/c_runtime/printf/test13/testinfo.dat
new file mode 100644
index 0000000000..e814040b37
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/printf/test13/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = printf
+Name = Positive Test for printf
+TYPE = DEFAULT
+EXE1 = test13
+Description
+= Tests printf with hex numbers (uppercase)
diff --git a/src/pal/tests/palsuite/c_runtime/printf/test14/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/printf/test14/CMakeLists.txt
new file mode 100644
index 0000000000..659ea78cc6
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/printf/test14/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test14.c
+)
+
+add_executable(paltest_printf_test14
+ ${SOURCES}
+)
+
+add_dependencies(paltest_printf_test14 coreclrpal)
+
+target_link_libraries(paltest_printf_test14
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/printf/test14/test14.c b/src/pal/tests/palsuite/c_runtime/printf/test14/test14.c
new file mode 100644
index 0000000000..10577db67d
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/printf/test14/test14.c
@@ -0,0 +1,54 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test14.c
+**
+** Purpose: Test #14 for the printf function. Tests the lowercase
+** exponential notation double specifier (%e)
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../printf.h"
+
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ double val = 256.0;
+ double neg = -256.0;
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ DoDoubleTest("foo %e", val, "foo 2.560000e+002", "foo 2.560000e+02");
+ DoDoubleTest("foo %le", val, "foo 2.560000e+002", "foo 2.560000e+02");
+ DoDoubleTest("foo %he", val, "foo 2.560000e+002", "foo 2.560000e+02");
+ DoDoubleTest("foo %Le", val, "foo 2.560000e+002", "foo 2.560000e+02");
+ DoDoubleTest("foo %I64e", val, "foo 2.560000e+002", "foo 2.560000e+02");
+ DoDoubleTest("foo %14e", val, "foo 2.560000e+002", "foo 2.560000e+02");
+ DoDoubleTest("foo %-14e", val, "foo 2.560000e+002 ",
+ "foo 2.560000e+02 ");
+ DoDoubleTest("foo %.1e", val, "foo 2.6e+002", "foo 2.6e+02");
+ DoDoubleTest("foo %.8e", val, "foo 2.56000000e+002",
+ "foo 2.56000000e+02");
+ DoDoubleTest("foo %014e", val, "foo 02.560000e+002",
+ "foo 002.560000e+02");
+ DoDoubleTest("foo %#e", val, "foo 2.560000e+002", "foo 2.560000e+02");
+ DoDoubleTest("foo %+e", val, "foo +2.560000e+002", "foo +2.560000e+02");
+ DoDoubleTest("foo % e", val, "foo 2.560000e+002", "foo 2.560000e+02");
+ DoDoubleTest("foo %+e", neg, "foo -2.560000e+002", "foo -2.560000e+02");
+ DoDoubleTest("foo % e", neg, "foo -2.560000e+002", "foo -2.560000e+02");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/printf/test14/testinfo.dat b/src/pal/tests/palsuite/c_runtime/printf/test14/testinfo.dat
new file mode 100644
index 0000000000..5cb22c1fcc
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/printf/test14/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = printf
+Name = Positive Test for printf
+TYPE = DEFAULT
+EXE1 = test14
+Description
+= Tests printf with exponential format doubles (lowercase)
diff --git a/src/pal/tests/palsuite/c_runtime/printf/test15/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/printf/test15/CMakeLists.txt
new file mode 100644
index 0000000000..9e4e310304
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/printf/test15/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test15.c
+)
+
+add_executable(paltest_printf_test15
+ ${SOURCES}
+)
+
+add_dependencies(paltest_printf_test15 coreclrpal)
+
+target_link_libraries(paltest_printf_test15
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/printf/test15/test15.c b/src/pal/tests/palsuite/c_runtime/printf/test15/test15.c
new file mode 100644
index 0000000000..2acfc436a3
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/printf/test15/test15.c
@@ -0,0 +1,54 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test15.c
+**
+** Purpose: Test #15 for the printf function. Tests the uppercase
+** exponential notation double specifier (%E)
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../printf.h"
+
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ double val = 256.0;
+ double neg = -256.0;
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ DoDoubleTest("foo %E", val, "foo 2.560000E+002", "foo 2.560000E+02");
+ DoDoubleTest("foo %lE", val, "foo 2.560000E+002", "foo 2.560000E+02");
+ DoDoubleTest("foo %hE", val, "foo 2.560000E+002", "foo 2.560000E+02");
+ DoDoubleTest("foo %LE", val, "foo 2.560000E+002", "foo 2.560000E+02");
+ DoDoubleTest("foo %I64E", val, "foo 2.560000E+002", "foo 2.560000E+02");
+ DoDoubleTest("foo %14E", val, "foo 2.560000E+002", "foo 2.560000E+02");
+ DoDoubleTest("foo %-14E", val, "foo 2.560000E+002 ",
+ "foo 2.560000E+02 ");
+ DoDoubleTest("foo %.1E", val, "foo 2.6E+002", "foo 2.6E+02");
+ DoDoubleTest("foo %.8E", val, "foo 2.56000000E+002",
+ "foo 2.56000000E+02");
+ DoDoubleTest("foo %014E", val, "foo 02.560000E+002",
+ "foo 002.560000E+02");
+ DoDoubleTest("foo %#E", val, "foo 2.560000E+002", "foo 2.560000E+02");
+ DoDoubleTest("foo %+E", val, "foo +2.560000E+002", "foo +2.560000E+02");
+ DoDoubleTest("foo % E", val, "foo 2.560000E+002", "foo 2.560000E+02");
+ DoDoubleTest("foo %+E", neg, "foo -2.560000E+002", "foo -2.560000E+02");
+ DoDoubleTest("foo % E", neg, "foo -2.560000E+002", "foo -2.560000E+02");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/printf/test15/testinfo.dat b/src/pal/tests/palsuite/c_runtime/printf/test15/testinfo.dat
new file mode 100644
index 0000000000..bdfa2cc3b5
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/printf/test15/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = printf
+Name = Positive Test for printf
+TYPE = DEFAULT
+EXE1 = test15
+Description
+= Tests printf with exponential format doubles (uppercase)
diff --git a/src/pal/tests/palsuite/c_runtime/printf/test16/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/printf/test16/CMakeLists.txt
new file mode 100644
index 0000000000..7e477a3059
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/printf/test16/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test16.c
+)
+
+add_executable(paltest_printf_test16
+ ${SOURCES}
+)
+
+add_dependencies(paltest_printf_test16 coreclrpal)
+
+target_link_libraries(paltest_printf_test16
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/printf/test16/test16.c b/src/pal/tests/palsuite/c_runtime/printf/test16/test16.c
new file mode 100644
index 0000000000..50c952f959
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/printf/test16/test16.c
@@ -0,0 +1,50 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test16.c
+**
+** Purpose: Test #16 for the printf function. Tests the decimal notation
+** double specifier (%f)
+**
+**
+**==========================================================================*/
+
+
+#include <palsuite.h>
+#include "../printf.h"
+
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ double val = 2560.001;
+ double neg = -2560.001;
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ DoDoubleTest("foo %f", val, "foo 2560.001000", "foo 2560.001000");
+ DoDoubleTest("foo %lf", val, "foo 2560.001000", "foo 2560.001000");
+ DoDoubleTest("foo %hf", val, "foo 2560.001000", "foo 2560.001000");
+ DoDoubleTest("foo %Lf", val, "foo 2560.001000", "foo 2560.001000");
+ DoDoubleTest("foo %I64f", val, "foo 2560.001000", "foo 2560.001000");
+ DoDoubleTest("foo %12f", val, "foo 2560.001000", "foo 2560.001000");
+ DoDoubleTest("foo %-12f", val, "foo 2560.001000 ", "foo 2560.001000 ");
+ DoDoubleTest("foo %.1f", val, "foo 2560.0", "foo 2560.0");
+ DoDoubleTest("foo %.8f", val, "foo 2560.00100000", "foo 2560.00100000");
+ DoDoubleTest("foo %012f", val, "foo 02560.001000", "foo 02560.001000");
+ DoDoubleTest("foo %#f", val, "foo 2560.001000", "foo 2560.001000");
+ DoDoubleTest("foo %+f", val, "foo +2560.001000", "foo +2560.001000");
+ DoDoubleTest("foo % f", val, "foo 2560.001000", "foo 2560.001000");
+ DoDoubleTest("foo %+f", neg, "foo -2560.001000", "foo -2560.001000");
+ DoDoubleTest("foo % f", neg, "foo -2560.001000", "foo -2560.001000");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/printf/test16/testinfo.dat b/src/pal/tests/palsuite/c_runtime/printf/test16/testinfo.dat
new file mode 100644
index 0000000000..afb9a21b3b
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/printf/test16/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = printf
+Name = Positive Test for printf
+TYPE = DEFAULT
+EXE1 = test16
+Description
+= Tests printf with decimal point format doubles
diff --git a/src/pal/tests/palsuite/c_runtime/printf/test17/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/printf/test17/CMakeLists.txt
new file mode 100644
index 0000000000..c18450c2aa
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/printf/test17/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test17.c
+)
+
+add_executable(paltest_printf_test17
+ ${SOURCES}
+)
+
+add_dependencies(paltest_printf_test17 coreclrpal)
+
+target_link_libraries(paltest_printf_test17
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/printf/test17/test17.c b/src/pal/tests/palsuite/c_runtime/printf/test17/test17.c
new file mode 100644
index 0000000000..96ddd5c1e4
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/printf/test17/test17.c
@@ -0,0 +1,52 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test17.c
+**
+** Purpose: Test #17 for the printf function. Tests the lowercase
+** shorthand notation double specifier (%g)
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../printf.h"
+
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ double val = 2560.001;
+ double neg = -2560.001;
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ DoDoubleTest("foo %g", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %lg", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %hg", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %Lg", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %I64g", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %5g", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %-5g", val, "foo 2560 ", "foo 2560 ");
+ DoDoubleTest("foo %.1g", val, "foo 3e+003", "foo 3e+03");
+ DoDoubleTest("foo %.2g", val, "foo 2.6e+003", "foo 2.6e+03");
+ DoDoubleTest("foo %.12g", val, "foo 2560.001", "foo 2560.001");
+ DoDoubleTest("foo %06g", val, "foo 002560", "foo 002560");
+ DoDoubleTest("foo %#g", val, "foo 2560.00", "foo 2560.00");
+ DoDoubleTest("foo %+g", val, "foo +2560", "foo +2560");
+ DoDoubleTest("foo % g", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %+g", neg, "foo -2560", "foo -2560");
+ DoDoubleTest("foo % g", neg, "foo -2560", "foo -2560");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/printf/test17/testinfo.dat b/src/pal/tests/palsuite/c_runtime/printf/test17/testinfo.dat
new file mode 100644
index 0000000000..a8545d9542
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/printf/test17/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = printf
+Name = Positive Test for printf
+TYPE = DEFAULT
+EXE1 = test17
+Description
+= Tests printf with compact format doubles (lowercase)
diff --git a/src/pal/tests/palsuite/c_runtime/printf/test18/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/printf/test18/CMakeLists.txt
new file mode 100644
index 0000000000..b0468314a3
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/printf/test18/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test18.c
+)
+
+add_executable(paltest_printf_test18
+ ${SOURCES}
+)
+
+add_dependencies(paltest_printf_test18 coreclrpal)
+
+target_link_libraries(paltest_printf_test18
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/printf/test18/test18.c b/src/pal/tests/palsuite/c_runtime/printf/test18/test18.c
new file mode 100644
index 0000000000..6c05e40f42
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/printf/test18/test18.c
@@ -0,0 +1,51 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test18.c
+**
+** Purpose: Test #18 for the printf function. Tests the uppercase
+** shorthand notation double specifier (%G)
+**
+**
+**==========================================================================*/
+
+
+#include <palsuite.h>
+#include "../printf.h"
+
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ double val = 2560.001;
+ double neg = -2560.001;
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ DoDoubleTest("foo %G", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %lG", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %hG", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %LG", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %I64G", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %5G", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %-5G", val, "foo 2560 ", "foo 2560 ");
+ DoDoubleTest("foo %.1G", val, "foo 3E+003", "foo 3E+03");
+ DoDoubleTest("foo %.2G", val, "foo 2.6E+003", "foo 2.6E+03");
+ DoDoubleTest("foo %.12G", val, "foo 2560.001", "foo 2560.001");
+ DoDoubleTest("foo %06G", val, "foo 002560", "foo 002560");
+ DoDoubleTest("foo %#G", val, "foo 2560.00", "foo 2560.00");
+ DoDoubleTest("foo %+G", val, "foo +2560", "foo +2560");
+ DoDoubleTest("foo % G", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %+G", neg, "foo -2560", "foo -2560");
+ DoDoubleTest("foo % G", neg, "foo -2560", "foo -2560");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/printf/test18/testinfo.dat b/src/pal/tests/palsuite/c_runtime/printf/test18/testinfo.dat
new file mode 100644
index 0000000000..bd5c90b0c3
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/printf/test18/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = printf
+Name = Positive Test for printf
+TYPE = DEFAULT
+EXE1 = test18
+Description
+= Tests printf with compact format doubles (uppercase)
diff --git a/src/pal/tests/palsuite/c_runtime/printf/test19/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/printf/test19/CMakeLists.txt
new file mode 100644
index 0000000000..efd47563d4
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/printf/test19/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test19.c
+)
+
+add_executable(paltest_printf_test19
+ ${SOURCES}
+)
+
+add_dependencies(paltest_printf_test19 coreclrpal)
+
+target_link_libraries(paltest_printf_test19
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/printf/test19/test19.c b/src/pal/tests/palsuite/c_runtime/printf/test19/test19.c
new file mode 100644
index 0000000000..1e09398f7c
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/printf/test19/test19.c
@@ -0,0 +1,76 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test19.c
+**
+** Purpose: Test #19 for the printf function. Tests the variable length
+** precision argument.
+**
+**
+**==========================================================================*/
+
+
+#include <palsuite.h>
+#include "../printf.h"
+
+
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ int n = -1;
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ DoArgumentPrecTest("%.*s", 2, "bar", "bar", "ba", "ba");
+ DoArgumentPrecTest("%.*S", 2, convert("bar"), "bar", "ba", "ba");
+
+ DoArgumentPrecTest("%.*n", 3, &n, "pointer to int", "", "");
+ if (n != 0)
+ {
+ Fail("ERROR: Expected count parameter to resolve to %d, got %X\n",
+ 0, n);
+ }
+
+ DoArgumentPrecTest("%.*c", 0, (void*)'a', "a", "a", "a");
+ DoArgumentPrecTest("%.*c", 4, (void*)'a', "a", "a", "a");
+ DoArgumentPrecTest("%.*C", 0, (void*)'a', "a", "a", "a");
+ DoArgumentPrecTest("%.*C", 4, (void*)'a', "a", "a", "a");
+ DoArgumentPrecTest("%.*d", 1, (void*)42, "42", "42", "42");
+ DoArgumentPrecTest("%.*d", 3, (void*)42, "42", "042", "042");
+ DoArgumentPrecTest("%.*i", 1, (void*)42, "42", "42", "42");
+ DoArgumentPrecTest("%.*i", 3, (void*)42, "42", "042", "042");
+ DoArgumentPrecTest("%.*o", 1, (void*)42, "42", "52", "52");
+ DoArgumentPrecTest("%.*o", 3, (void*)42, "42", "052", "052");
+ DoArgumentPrecTest("%.*u", 1, (void*)42, "42", "42", "42");
+ DoArgumentPrecTest("%.*u", 3, (void*)42, "42", "042", "042");
+ DoArgumentPrecTest("%.*x", 1, (void*)0x42, "0x42", "42", "42");
+ DoArgumentPrecTest("%.*x", 3, (void*)0x42, "0x42", "042", "042");
+ DoArgumentPrecTest("%.*X", 1, (void*)0x42, "0x42", "42", "42");
+ DoArgumentPrecTest("%.*X", 3, (void*)0x42, "0x42", "042", "042");
+
+
+ DoArgumentPrecDoubleTest("%.*e", 1, 2.01, "2.0e+000", "2.0e+00");
+ DoArgumentPrecDoubleTest("%.*e", 3, 2.01, "2.010e+000", "2.010e+00");
+ DoArgumentPrecDoubleTest("%.*E", 1, 2.01, "2.0E+000", "2.0E+00");
+ DoArgumentPrecDoubleTest("%.*E", 3, 2.01, "2.010E+000", "2.010E+00");
+ DoArgumentPrecDoubleTest("%.*f", 1, 2.01, "2.0", "2.0");
+ DoArgumentPrecDoubleTest("%.*f", 3, 2.01, "2.010", "2.010");
+ DoArgumentPrecDoubleTest("%.*g", 1, 256.01, "3e+002", "3e+02");
+ DoArgumentPrecDoubleTest("%.*g", 3, 256.01, "256", "256");
+ DoArgumentPrecDoubleTest("%.*g", 4, 256.01, "256", "256");
+ DoArgumentPrecDoubleTest("%.*g", 6, 256.01, "256.01", "256.01");
+ DoArgumentPrecDoubleTest("%.*G", 1, 256.01, "3E+002", "3E+02");
+ DoArgumentPrecDoubleTest("%.*G", 3, 256.01, "256", "256");
+ DoArgumentPrecDoubleTest("%.*G", 4, 256.01, "256", "256");
+ DoArgumentPrecDoubleTest("%.*G", 6, 256.01, "256.01", "256.01");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/printf/test19/testinfo.dat b/src/pal/tests/palsuite/c_runtime/printf/test19/testinfo.dat
new file mode 100644
index 0000000000..6ad18f7591
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/printf/test19/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = printf
+Name = Positive Test for printf
+TYPE = DEFAULT
+EXE1 = test19
+Description
+= Tests printf with argument specified precision
diff --git a/src/pal/tests/palsuite/c_runtime/printf/test2/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/printf/test2/CMakeLists.txt
new file mode 100644
index 0000000000..c303a69134
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/printf/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test2.c
+)
+
+add_executable(paltest_printf_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_printf_test2 coreclrpal)
+
+target_link_libraries(paltest_printf_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/printf/test2/test2.c b/src/pal/tests/palsuite/c_runtime/printf/test2/test2.c
new file mode 100644
index 0000000000..e766ef4a90
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/printf/test2/test2.c
@@ -0,0 +1,45 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test2.c
+**
+** Purpose: Test #2 for the printf function. Tests the string specifier
+** (%s).
+**
+**
+**==========================================================================*/
+
+
+#include <palsuite.h>
+#include "../printf.h"
+
+
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ DoStrTest("foo %s", "bar", "foo bar");
+ DoStrTest("foo %hs", "bar", "foo bar");
+ DoWStrTest("foo %ls", convert("bar"), "foo bar");
+ DoWStrTest("foo %ws", convert("bar"), "foo bar");
+ DoStrTest("foo %Ls", "bar", "foo bar");
+ DoStrTest("foo %I64s", "bar", "foo bar");
+ DoStrTest("foo %5s", "bar", "foo bar");
+ DoStrTest("foo %.2s", "bar", "foo ba");
+ DoStrTest("foo %5.2s", "bar", "foo ba");
+ DoStrTest("foo %-5s", "bar", "foo bar ");
+ DoStrTest("foo %05s", "bar", "foo 00bar");
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/printf/test2/testinfo.dat b/src/pal/tests/palsuite/c_runtime/printf/test2/testinfo.dat
new file mode 100644
index 0000000000..3ff71c7496
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/printf/test2/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = printf
+Name = Positive Test for printf
+TYPE = DEFAULT
+EXE1 = test2
+Description
+= Tests printf with strings
diff --git a/src/pal/tests/palsuite/c_runtime/printf/test3/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/printf/test3/CMakeLists.txt
new file mode 100644
index 0000000000..8bc7479797
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/printf/test3/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test3.c
+)
+
+add_executable(paltest_printf_test3
+ ${SOURCES}
+)
+
+add_dependencies(paltest_printf_test3 coreclrpal)
+
+target_link_libraries(paltest_printf_test3
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/printf/test3/test3.c b/src/pal/tests/palsuite/c_runtime/printf/test3/test3.c
new file mode 100644
index 0000000000..5cc530948c
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/printf/test3/test3.c
@@ -0,0 +1,45 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test3.c
+**
+** Purpose: Test #3 for the printf function. Tests the wide string
+** specifier (%S).
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../printf.h"
+
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ DoWStrTest("foo %S", convert("bar"), "foo bar");
+ DoStrTest("foo %hS", "bar", "foo bar");
+ DoWStrTest("foo %lS", convert("bar"), "foo bar");
+ DoWStrTest("foo %wS", convert("bar"), "foo bar");
+ DoWStrTest("foo %LS", convert("bar"), "foo bar");
+ DoWStrTest("foo %I64S", convert("bar"), "foo bar");
+ DoWStrTest("foo %5S", convert("bar"), "foo bar");
+ DoWStrTest("foo %.2S", convert("bar"), "foo ba");
+ DoWStrTest("foo %5.2S", convert("bar"), "foo ba");
+ DoWStrTest("foo %-5S", convert("bar"), "foo bar ");
+ DoWStrTest("foo %05S", convert("bar"), "foo 00bar");
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/printf/test3/testinfo.dat b/src/pal/tests/palsuite/c_runtime/printf/test3/testinfo.dat
new file mode 100644
index 0000000000..295c172f09
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/printf/test3/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = printf
+Name = Positive Test for printf
+TYPE = DEFAULT
+EXE1 = test3
+Description
+= Tests printf with wide strings
diff --git a/src/pal/tests/palsuite/c_runtime/printf/test4/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/printf/test4/CMakeLists.txt
new file mode 100644
index 0000000000..55e5700fe3
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/printf/test4/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test4.c
+)
+
+add_executable(paltest_printf_test4
+ ${SOURCES}
+)
+
+add_dependencies(paltest_printf_test4 coreclrpal)
+
+target_link_libraries(paltest_printf_test4
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/printf/test4/test4.c b/src/pal/tests/palsuite/c_runtime/printf/test4/test4.c
new file mode 100644
index 0000000000..bcdc201d4f
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/printf/test4/test4.c
@@ -0,0 +1,66 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test4.c
+**
+** Purpose: Test #4 for the printf function. Tests the pointer
+** specifier (%p).
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../printf.h"
+
+int __cdecl main(int argc, char *argv[])
+{
+ void *ptr = (void*) 0x123456;
+ INT64 lptr = I64(0x1234567887654321);
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+/*
+** Run only on 64 bit platforms
+*/
+#if defined(BIT64) && defined(PLATFORM_UNIX)
+ Trace("Testing for 64 Bit Platforms \n");
+ DoPointerTest("%p", NULL, "NULL", "0000000000000000");
+ DoPointerTest("%p", ptr, "pointer to 0x123456", "0000000000123456");
+ DoPointerTest("%17p", ptr, "pointer to 0x123456", " 0000000000123456");
+ DoPointerTest("%17p", ptr, "pointer to 0x123456", " 0000000000123456");
+ DoPointerTest("%-17p", ptr, "pointer to 0x123456", "0000000000123456 ");
+ DoPointerTest("%+p", ptr, "pointer to 0x123456", "0000000000123456");
+ DoPointerTest("%#p", ptr, "pointer to 0x123456", "0X0000000000123456");
+ DoPointerTest("%lp", ptr, "pointer to 0x123456", "00123456");
+ DoPointerTest("%hp", ptr, "pointer to 0x123456", "00003456");
+ DoPointerTest("%Lp", ptr, "pointer to 0x123456", "00123456");
+ DoI64Test("%I64p", lptr, "pointer to 0x1234567887654321",
+ "1234567887654321");
+#else
+ Trace("Testing for Non 64 Bit Platforms \n");
+ DoPointerTest("%p", NULL, "NULL", "00000000");
+ DoPointerTest("%p", ptr, "pointer to 0x123456", "00123456");
+ DoPointerTest("%9p", ptr, "pointer to 0x123456", " 00123456");
+ DoPointerTest("%09p", ptr, "pointer to 0x123456", " 00123456");
+ DoPointerTest("%-9p", ptr, "pointer to 0x123456", "00123456 ");
+ DoPointerTest("%+p", ptr, "pointer to 0x123456", "00123456");
+ DoPointerTest("%#p", ptr, "pointer to 0x123456", "0X00123456");
+ DoPointerTest("%lp", ptr, "pointer to 0x123456", "00123456");
+ DoPointerTest("%hp", ptr, "pointer to 0x123456", "00003456");
+ DoPointerTest("%Lp", ptr, "pointer to 0x123456", "00123456");
+ DoI64Test("%I64p", lptr, "pointer to 0x1234567887654321",
+ "1234567887654321");
+
+#endif
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/printf/test4/testinfo.dat b/src/pal/tests/palsuite/c_runtime/printf/test4/testinfo.dat
new file mode 100644
index 0000000000..0c55e0ed39
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/printf/test4/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = printf
+Name = Positive Test for printf
+TYPE = DEFAULT
+EXE1 = test4
+Description
+= Tests printf with pointers
diff --git a/src/pal/tests/palsuite/c_runtime/printf/test5/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/printf/test5/CMakeLists.txt
new file mode 100644
index 0000000000..d091bca2dc
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/printf/test5/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test5.c
+)
+
+add_executable(paltest_printf_test5
+ ${SOURCES}
+)
+
+add_dependencies(paltest_printf_test5 coreclrpal)
+
+target_link_libraries(paltest_printf_test5
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/printf/test5/test5.c b/src/pal/tests/palsuite/c_runtime/printf/test5/test5.c
new file mode 100644
index 0000000000..9f8baa74da
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/printf/test5/test5.c
@@ -0,0 +1,60 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test5.c
+**
+** Purpose: Test #5 for the printf function. Tests the count specifier (%n).
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../printf.h"
+
+
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ char *longStr =
+ "really-long-string-that-just-keeps-going-on-and-on-and-on.."
+ "..................useless-filler.................................."
+ "..................useless-filler.................................."
+ "..................useless-filler.................................."
+ "%n bar";
+ char *longResult =
+ "really-long-string-that-just-keeps-going-on-and-on-and-on.."
+ "..................useless-filler.................................."
+ "..................useless-filler.................................."
+ "..................useless-filler.................................."
+ " bar";
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ DoCountTest("foo %n bar", 4, "foo bar");
+ DoCountTest(longStr, 257, longResult);
+ DoCountTest("fo%n bar", 2, "fo bar");
+ DoCountTest("%n", 0, "");
+ DoCountTest("foo %#n bar", 4, "foo bar");
+ DoCountTest("foo % n bar", 4, "foo bar");
+ DoCountTest("foo %+n bar", 4, "foo bar");
+ DoCountTest("foo %-n bar", 4, "foo bar");
+ DoCountTest("foo %0n bar", 4, "foo bar");
+ DoShortCountTest("foo %hn bar", 4, "foo bar");
+ DoCountTest("foo %ln bar", 4, "foo bar");
+ DoCountTest("foo %Ln bar", 4, "foo bar");
+ DoCountTest("foo %I64n bar", 4, "foo bar");
+ DoCountTest("foo %20.3n bar", 4, "foo bar");
+
+ PAL_Terminate();
+
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/printf/test5/testinfo.dat b/src/pal/tests/palsuite/c_runtime/printf/test5/testinfo.dat
new file mode 100644
index 0000000000..a7c7400f58
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/printf/test5/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = printf
+Name = Positive Test for printf
+TYPE = DEFAULT
+EXE1 = test5
+Description
+= Tests printf with the count specifier
diff --git a/src/pal/tests/palsuite/c_runtime/printf/test6/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/printf/test6/CMakeLists.txt
new file mode 100644
index 0000000000..c004e353e9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/printf/test6/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test6.c
+)
+
+add_executable(paltest_printf_test6
+ ${SOURCES}
+)
+
+add_dependencies(paltest_printf_test6 coreclrpal)
+
+target_link_libraries(paltest_printf_test6
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/printf/test6/test6.c b/src/pal/tests/palsuite/c_runtime/printf/test6/test6.c
new file mode 100644
index 0000000000..edc65b6b9b
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/printf/test6/test6.c
@@ -0,0 +1,48 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test6.c
+**
+** Purpose: Test #6 for the printf function. Tests the char specifier (%c).
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../printf.h"
+
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ WCHAR wc = (WCHAR) 'c';
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ DoCharTest("foo %c", 'b', "foo b");
+ DoCharTest("foo %hc", 'b', "foo b");
+ DoWCharTest("foo %lc", wc, "foo c");
+ DoCharTest("foo %Lc", 'b', "foo b");
+ DoCharTest("foo %I64c", 'b', "foo b");
+ DoCharTest("foo %5c", 'b', "foo b");
+ DoCharTest("foo %.0c", 'b', "foo b");
+ DoCharTest("foo %-5c", 'b', "foo b ");
+ DoCharTest("foo %05c", 'b', "foo 0000b");
+ DoCharTest("foo % c", 'b', "foo b");
+ DoCharTest("foo %#c", 'b', "foo b");
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/printf/test6/testinfo.dat b/src/pal/tests/palsuite/c_runtime/printf/test6/testinfo.dat
new file mode 100644
index 0000000000..fd8a985291
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/printf/test6/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = printf
+Name = Positive Test for printf
+TYPE = DEFAULT
+EXE1 = test6
+Description
+= Tests printf with characters
diff --git a/src/pal/tests/palsuite/c_runtime/printf/test7/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/printf/test7/CMakeLists.txt
new file mode 100644
index 0000000000..ff6b647ccd
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/printf/test7/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test7.c
+)
+
+add_executable(paltest_printf_test7
+ ${SOURCES}
+)
+
+add_dependencies(paltest_printf_test7 coreclrpal)
+
+target_link_libraries(paltest_printf_test7
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/printf/test7/test7.c b/src/pal/tests/palsuite/c_runtime/printf/test7/test7.c
new file mode 100644
index 0000000000..3aeb58f7dc
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/printf/test7/test7.c
@@ -0,0 +1,47 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test7.c
+**
+** Purpose: Test #7 for the printf function. Tests the wide char
+** specifier (%C).
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../printf.h"
+
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ WCHAR wb = (WCHAR) 'b';
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ DoWCharTest("foo %C", wb, "foo b");
+ DoWCharTest("foo %hC", wb, "foo b");
+ DoCharTest("foo %lC", 'c', "foo c");
+ DoWCharTest("foo %LC", wb, "foo b");
+ DoWCharTest("foo %I64C", wb, "foo b");
+ DoWCharTest("foo %5C", wb, "foo b");
+ DoWCharTest("foo %.0C", wb, "foo b");
+ DoWCharTest("foo %-5C", wb, "foo b ");
+ DoWCharTest("foo %05C", wb, "foo 0000b");
+ DoWCharTest("foo % C", wb, "foo b");
+ DoWCharTest("foo %#C", wb, "foo b");
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/printf/test7/testinfo.dat b/src/pal/tests/palsuite/c_runtime/printf/test7/testinfo.dat
new file mode 100644
index 0000000000..6d2b1cf84e
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/printf/test7/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = printf
+Name = Positive Test for printf
+TYPE = DEFAULT
+EXE1 = test7
+Description
+= Tests printf with wide characters
diff --git a/src/pal/tests/palsuite/c_runtime/printf/test8/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/printf/test8/CMakeLists.txt
new file mode 100644
index 0000000000..5ee387f5b8
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/printf/test8/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test8.c
+)
+
+add_executable(paltest_printf_test8
+ ${SOURCES}
+)
+
+add_dependencies(paltest_printf_test8 coreclrpal)
+
+target_link_libraries(paltest_printf_test8
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/printf/test8/test8.c b/src/pal/tests/palsuite/c_runtime/printf/test8/test8.c
new file mode 100644
index 0000000000..daa4674b92
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/printf/test8/test8.c
@@ -0,0 +1,53 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test8.c
+**
+** Purpose: Test #8 for the printf function. Tests the decimal
+** specifier (%d).
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../printf.h"
+
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ int neg = -42;
+ int pos = 42;
+ INT64 l = 42;
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ DoNumTest("foo %d", pos, "foo 42");
+ DoNumTest("foo %ld", 0xFFFF, "foo 65535");
+ DoNumTest("foo %hd", 0xFFFF, "foo -1");
+ DoNumTest("foo %Ld", pos, "foo 42");
+ DoI64Test("foo %I64d", l, "42", "foo 42");
+ DoNumTest("foo %3d", pos, "foo 42");
+ DoNumTest("foo %-3d", pos, "foo 42 ");
+ DoNumTest("foo %.1d", pos, "foo 42");
+ DoNumTest("foo %.3d", pos, "foo 042");
+ DoNumTest("foo %03d", pos, "foo 042");
+ DoNumTest("foo %#d", pos, "foo 42");
+ DoNumTest("foo %+d", pos, "foo +42");
+ DoNumTest("foo % d", pos, "foo 42");
+ DoNumTest("foo %+d", neg, "foo -42");
+ DoNumTest("foo % d", neg, "foo -42");
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/printf/test8/testinfo.dat b/src/pal/tests/palsuite/c_runtime/printf/test8/testinfo.dat
new file mode 100644
index 0000000000..6367235aa5
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/printf/test8/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = printf
+Name = Positive Test for printf
+TYPE = DEFAULT
+EXE1 = test8
+Description
+= Tests printf with decimal numbers
diff --git a/src/pal/tests/palsuite/c_runtime/printf/test9/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/printf/test9/CMakeLists.txt
new file mode 100644
index 0000000000..baf46c1065
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/printf/test9/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test9.c
+)
+
+add_executable(paltest_printf_test9
+ ${SOURCES}
+)
+
+add_dependencies(paltest_printf_test9 coreclrpal)
+
+target_link_libraries(paltest_printf_test9
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/printf/test9/test9.c b/src/pal/tests/palsuite/c_runtime/printf/test9/test9.c
new file mode 100644
index 0000000000..22c60d04f2
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/printf/test9/test9.c
@@ -0,0 +1,53 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test9.c
+**
+** Purpose: Test #9 for the printf function. Tests the integer
+** specifier (%i).
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../printf.h"
+
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ int neg = -42;
+ int pos = 42;
+ INT64 l = 42;
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ DoNumTest("foo %i", pos, "foo 42");
+ DoNumTest("foo %li", 0xFFFF, "foo 65535");
+ DoNumTest("foo %hi", 0xFFFF, "foo -1");
+ DoNumTest("foo %Li", pos, "foo 42");
+ DoI64Test("foo %I64i", l, "42", "foo 42");
+ DoNumTest("foo %3i", pos, "foo 42");
+ DoNumTest("foo %-3i", pos, "foo 42 ");
+ DoNumTest("foo %.1i", pos, "foo 42");
+ DoNumTest("foo %.3i", pos, "foo 042");
+ DoNumTest("foo %03i", pos, "foo 042");
+ DoNumTest("foo %#i", pos, "foo 42");
+ DoNumTest("foo %+i", pos, "foo +42");
+ DoNumTest("foo % i", pos, "foo 42");
+ DoNumTest("foo %+i", neg, "foo -42");
+ DoNumTest("foo % i", neg, "foo -42");
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/printf/test9/testinfo.dat b/src/pal/tests/palsuite/c_runtime/printf/test9/testinfo.dat
new file mode 100644
index 0000000000..3208cb44a5
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/printf/test9/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = printf
+Name = Positive Test for printf
+TYPE = DEFAULT
+EXE1 = test9
+Description
+= Tests printf with integer numbers
diff --git a/src/pal/tests/palsuite/c_runtime/qsort/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/qsort/CMakeLists.txt
new file mode 100644
index 0000000000..ef14ea5352
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/qsort/CMakeLists.txt
@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+
diff --git a/src/pal/tests/palsuite/c_runtime/qsort/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/qsort/test1/CMakeLists.txt
new file mode 100644
index 0000000000..105a727e91
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/qsort/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_qsort_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_qsort_test1 coreclrpal)
+
+target_link_libraries(paltest_qsort_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/qsort/test1/test1.c b/src/pal/tests/palsuite/c_runtime/qsort/test1/test1.c
new file mode 100644
index 0000000000..c65fb18e68
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/qsort/test1/test1.c
@@ -0,0 +1,48 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Calls qsort to sort a buffer, and verifies that it has done
+** the job correctly.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+
+int __cdecl charcmp(const void *pa, const void *pb)
+{
+ return memcmp(pa, pb, 1);
+}
+
+int __cdecl main(int argc, char **argv)
+{
+ char before[] = "cgaiehdbjf";
+ const char after[] = "abcdefghij";
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ qsort(before, sizeof(before) - 1, sizeof(char), charcmp);
+
+ if (memcmp(before, after, sizeof(before)) != 0)
+ {
+ Fail("qsort did not correctly sort an array of characters.\n");
+ }
+
+ PAL_Terminate();
+ return PASS;
+
+}
+
+
+
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/qsort/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/qsort/test1/testinfo.dat
new file mode 100644
index 0000000000..7e3b4b87c3
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/qsort/test1/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = qsort
+Name = Positive Test for qsort
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Calls qsort to sort a buffer, and verifies that it has done the job correctly.
diff --git a/src/pal/tests/palsuite/c_runtime/qsort/test2/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/qsort/test2/CMakeLists.txt
new file mode 100644
index 0000000000..09e3f6db1e
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/qsort/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test2.c
+)
+
+add_executable(paltest_qsort_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_qsort_test2 coreclrpal)
+
+target_link_libraries(paltest_qsort_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/qsort/test2/test2.c b/src/pal/tests/palsuite/c_runtime/qsort/test2/test2.c
new file mode 100644
index 0000000000..8110dcd2c2
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/qsort/test2/test2.c
@@ -0,0 +1,49 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test2.c
+**
+** Purpose: Calls qsort to sort a buffer, and verifies that it has done
+** the job correctly.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+
+int __cdecl twocharcmp(const void *pa, const void *pb)
+{
+ return memcmp(pa, pb, 2);
+}
+
+int __cdecl main(int argc, char **argv)
+{
+ char before[] = "ccggaaiieehhddbbjjff";
+ const char after[] = "aabbccddeeffgghhiijj";
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ qsort(before, (sizeof(before) - 1) / 2, 2 * sizeof(char), twocharcmp);
+
+ if (memcmp(before, after, sizeof(before)) != 0)
+ {
+ Fail("qsort did not correctly sort an array of 2-character "
+ "buffers.\n");
+ }
+
+ PAL_Terminate();
+ return PASS;
+
+}
+
+
+
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/qsort/test2/testinfo.dat b/src/pal/tests/palsuite/c_runtime/qsort/test2/testinfo.dat
new file mode 100644
index 0000000000..35f5f06076
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/qsort/test2/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = qsort
+Name = Positive Test for qsort
+TYPE = DEFAULT
+EXE1 = test2
+Description
+= Calls qsort to sort a buffer, and verifies that it has done the job correctly.
diff --git a/src/pal/tests/palsuite/c_runtime/rand_srand/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/rand_srand/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/rand_srand/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/rand_srand/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/rand_srand/test1/CMakeLists.txt
new file mode 100644
index 0000000000..939914662a
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/rand_srand/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_rand_srand_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_rand_srand_test1 coreclrpal)
+
+target_link_libraries(paltest_rand_srand_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/rand_srand/test1/test1.c b/src/pal/tests/palsuite/c_runtime/rand_srand/test1/test1.c
new file mode 100644
index 0000000000..34154cb6d2
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/rand_srand/test1/test1.c
@@ -0,0 +1,100 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Test to ensure that srand provide random
+** number to rand. Also make sure that rand result from a
+** srand with seed 1 and no call to srand are the same.
+**
+** Dependencies: PAL_Initialize
+** PAL_Terminate
+** Fail
+** srand()
+**
+
+**
+**===========================================================================*/
+
+#include <palsuite.h>
+
+
+int __cdecl main(int argc, char **argv)
+{
+ int RandNumber[10];
+ int TempRandNumber;
+ int i;
+ int SRAND_SEED;
+ int SRAND_REINIT = 1;
+
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ SRAND_SEED = time(NULL);
+
+ /* does not initialize srand and call rand. */
+ for (i=0; i<10; i++)
+ {
+ /* keep the value in a array */
+ RandNumber[i]=rand();
+ if (RandNumber[i] < 0 || RandNumber[i] > RAND_MAX)
+ {
+ Fail("1) ERROR: random generated an invalid value: %d", RandNumber[i]);
+ }
+ }
+
+
+ /* initialize random generator */
+ srand(SRAND_SEED);
+
+
+ /* choose 10 numbers with a different seed.
+ the numbers should be different than
+ those the previously generated one */
+ for(i = 0; i < 10; i++)
+ {
+ TempRandNumber=rand();
+ if (TempRandNumber < 0 || TempRandNumber > RAND_MAX)
+ {
+ Fail("2) ERROR: random generated an invalid value: %d", TempRandNumber);
+ }
+ }
+
+
+
+ /* renitialize the srand with 1 */
+ srand(SRAND_REINIT);
+
+
+
+ /* choose 10 numbers with seed 1,
+ the number should be the same as those we kept in the array. */
+ for( i = 0; i < 10;i++ )
+ {
+ /* pick the random number*/
+ TempRandNumber=rand();
+ /* test if it is the same number generated in the first sequences*/
+ if(RandNumber[i]!=TempRandNumber)
+ {
+ Fail ("ERROR: rand should return the same value when srand "
+ "is initialized with 1 or not initialized at all");
+ }
+ if (TempRandNumber < 0 || TempRandNumber > RAND_MAX)
+ {
+ Fail("3) ERROR: random generated an invalid value: %d", TempRandNumber);
+ }
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/rand_srand/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/rand_srand/test1/testinfo.dat
new file mode 100644
index 0000000000..cf1b42dbf0
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/rand_srand/test1/testinfo.dat
@@ -0,0 +1,16 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = rand and srand
+Name = Positive Test for rand and srand
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Call rand without srand and get 10 random number batch 1.
+= call srand with seed 2, get 10 other random number and verify
+= that numbers are different from the batch 1.
+= Set the seed to 1, get 10 other random number and verify
+= that the generated number are the same as batch 1.
diff --git a/src/pal/tests/palsuite/c_runtime/realloc/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/realloc/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/realloc/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/realloc/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/realloc/test1/CMakeLists.txt
new file mode 100644
index 0000000000..0a9f34fc3b
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/realloc/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_realloc_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_realloc_test1 coreclrpal)
+
+target_link_libraries(paltest_realloc_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/realloc/test1/test1.c b/src/pal/tests/palsuite/c_runtime/realloc/test1/test1.c
new file mode 100644
index 0000000000..d0dd128cc1
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/realloc/test1/test1.c
@@ -0,0 +1,66 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Uses realloc to allocate and realloate memory, checking
+** that memory contents are copied when the memory is reallocated.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char **argv)
+{
+ char *testA;
+ const int len1 = 10;
+ const char str1[] = "aaaaaaaaaa";
+
+ const int len2 = 20;
+ const char str2[] = "bbbbbbbbbbbbbbbbbbbb";
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ /* this should work like malloc */
+ testA = (char *)realloc(NULL, len1*sizeof(char));
+ memcpy(testA, str1, len1);
+ if (testA == NULL)
+ {
+ Fail("We ran out of memory (unlikely), or realloc is broken.\n");
+ }
+
+ if (memcmp(testA, str1, len1) != 0)
+ {
+ Fail("realloc doesn't properly allocate new memory.\n");
+ }
+
+ testA = (char *)realloc(testA, len2*sizeof(char));
+ if (memcmp(testA, str1, len1) != 0)
+ {
+ Fail("realloc doesn't move the contents of the original memory "
+ "block to the newly allocated block.\n");
+ }
+
+ memcpy(testA, str2, len2);
+ if (memcmp(testA, str2, len2) != 0)
+ {
+ Fail("Couldn't write to memory allocated by realloc.\n");
+ }
+
+ /* free the buffer */
+ testA = realloc(testA, 0);
+ if (testA != NULL)
+ {
+ Fail("Realloc didn't return NULL when called with a length "
+ "of zero.\n");
+ }
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/realloc/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/realloc/test1/testinfo.dat
new file mode 100644
index 0000000000..5d2a32224e
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/realloc/test1/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = realloc
+Name = Positive Test for realloc
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Uses realloc to allocate and realloate memory, checking that memory
+= contents are copied when the memory is reallocated.
+
diff --git a/src/pal/tests/palsuite/c_runtime/sin/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/sin/CMakeLists.txt
new file mode 100644
index 0000000000..5e1ef7f28b
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sin/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
diff --git a/src/pal/tests/palsuite/c_runtime/sin/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/sin/test1/CMakeLists.txt
new file mode 100644
index 0000000000..e074337452
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sin/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_sin_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_sin_test1 coreclrpal)
+
+target_link_libraries(paltest_sin_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/sin/test1/test1.c b/src/pal/tests/palsuite/c_runtime/sin/test1/test1.c
new file mode 100644
index 0000000000..bec58d4dd9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sin/test1/test1.c
@@ -0,0 +1,131 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Test to ensure that sin return the correct values
+**
+** Dependencies: PAL_Initialize
+** PAL_Terminate
+** Fail
+** fabs
+**
+**===========================================================================*/
+
+#include <palsuite.h>
+
+// binary64 (double) has a machine epsilon of 2^-52 (approx. 2.22e-16). However, this
+// is slightly too accurate when writing tests meant to run against libm implementations
+// for various platforms. 2^-50 (approx. 8.88e-16) seems to be as accurate as we can get.
+//
+// The tests themselves will take PAL_EPSILON and adjust it according to the expected result
+// so that the delta used for comparison will compare the most significant digits and ignore
+// any digits that are outside the double precision range (15-17 digits).
+
+// For example, a test with an expect result in the format of 0.xxxxxxxxxxxxxxxxx will use
+// PAL_EPSILON for the variance, while an expected result in the format of 0.0xxxxxxxxxxxxxxxxx
+// will use PAL_EPSILON / 10 and and expected result in the format of x.xxxxxxxxxxxxxxxx will
+// use PAL_EPSILON * 10.
+#define PAL_EPSILON 8.8817841970012523e-16
+
+#define PAL_NAN sqrt(-1.0)
+#define PAL_POSINF -log(0.0)
+#define PAL_NEGINF log(0.0)
+
+/**
+ * Helper test structure
+ */
+struct test
+{
+ double value; /* value to test the function with */
+ double expected; /* expected result */
+ double variance; /* maximum delta between the expected and actual result */
+};
+
+/**
+ * validate
+ *
+ * test validation function
+ */
+void __cdecl validate(double value, double expected, double variance)
+{
+ double result = sin(value);
+
+ /*
+ * The test is valid when the difference between result
+ * and expected is less than or equal to variance
+ */
+ double delta = fabs(result - expected);
+
+ if (delta > variance)
+ {
+ Fail("sin(%g) returned %20.17g when it should have returned %20.17g",
+ value, result, expected);
+ }
+}
+
+/**
+ * validate
+ *
+ * test validation function for values returning NaN
+ */
+void __cdecl validate_isnan(double value)
+{
+ double result = sin(value);
+
+ if (!_isnan(result))
+ {
+ Fail("sin(%g) returned %20.17g when it should have returned %20.17g",
+ value, result, PAL_NAN);
+ }
+}
+
+/**
+ * main
+ *
+ * executable entry point
+ */
+int __cdecl main(int argc, char **argv)
+{
+ struct test tests[] =
+ {
+ /* value expected variance */
+ { 0, 0, PAL_EPSILON },
+ { 0.31830988618379067, 0.31296179620778659, PAL_EPSILON }, // value: 1 / pi
+ { 0.43429448190325183, 0.42077048331375735, PAL_EPSILON }, // value: log10(e)
+ { 0.63661977236758134, 0.59448076852482208, PAL_EPSILON }, // value: 2 / pi
+ { 0.69314718055994531, 0.63896127631363480, PAL_EPSILON }, // value: ln(2)
+ { 0.70710678118654752, 0.64963693908006244, PAL_EPSILON }, // value: 1 / sqrt(2)
+ { 0.78539816339744831, 0.70710678118654752, PAL_EPSILON }, // value: pi / 4, expected: 1 / sqrt(2)
+ { 1, 0.84147098480789651, PAL_EPSILON },
+ { 1.1283791670955126, 0.90371945743584630, PAL_EPSILON }, // value: 2 / sqrt(pi)
+ { 1.4142135623730950, 0.98776594599273553, PAL_EPSILON }, // value: sqrt(2)
+ { 1.4426950408889634, 0.99180624439366372, PAL_EPSILON }, // value: log2(e)
+ { 1.5707963267948966, 1, PAL_EPSILON * 10 }, // value: pi / 2
+ { 2.3025850929940457, 0.74398033695749319, PAL_EPSILON }, // value: ln(10)
+ { 2.7182818284590452, 0.41078129050290870, PAL_EPSILON }, // value: e
+ { 3.1415926535897932, 0, PAL_EPSILON }, // value: pi
+ };
+
+ /* PAL initialization */
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+ for (int i = 0; i < (sizeof(tests) / sizeof(struct test)); i++)
+ {
+ validate( tests[i].value, tests[i].expected, tests[i].variance);
+ validate(-tests[i].value, -tests[i].expected, tests[i].variance);
+ }
+
+ validate_isnan(PAL_NEGINF);
+ validate_isnan(PAL_NAN);
+ validate_isnan(PAL_POSINF);
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/sin/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/sin/test1/testinfo.dat
new file mode 100644
index 0000000000..57eae6bfd1
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sin/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = sin
+Name = Positive Test for sin
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Passes to sin() a series of angle value, checking that
+= each one return to correct value.
diff --git a/src/pal/tests/palsuite/c_runtime/sinh/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/sinh/CMakeLists.txt
new file mode 100644
index 0000000000..5e1ef7f28b
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sinh/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
diff --git a/src/pal/tests/palsuite/c_runtime/sinh/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/sinh/test1/CMakeLists.txt
new file mode 100644
index 0000000000..66cc691d92
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sinh/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_sinh_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_sinh_test1 coreclrpal)
+
+target_link_libraries(paltest_sinh_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/sinh/test1/test1.c b/src/pal/tests/palsuite/c_runtime/sinh/test1/test1.c
new file mode 100644
index 0000000000..e790b16fb4
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sinh/test1/test1.c
@@ -0,0 +1,130 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Test to ensure that sinh return the correct values
+**
+** Dependencies: PAL_Initialize
+** PAL_Terminate
+** Fail
+** fabs
+**
+**===========================================================================*/
+
+#include <palsuite.h>
+
+// binary64 (double) has a machine epsilon of 2^-52 (approx. 2.22e-16). However, this
+// is slightly too accurate when writing tests meant to run against libm implementations
+// for various platforms. 2^-50 (approx. 8.88e-16) seems to be as accurate as we can get.
+//
+// The tests themselves will take PAL_EPSILON and adjust it according to the expected result
+// so that the delta used for comparison will compare the most significant digits and ignore
+// any digits that are outside the double precision range (15-17 digits).
+
+// For example, a test with an expect result in the format of 0.xxxxxxxxxxxxxxxxx will use
+// PAL_EPSILON for the variance, while an expected result in the format of 0.0xxxxxxxxxxxxxxxxx
+// will use PAL_EPSILON / 10 and and expected result in the format of x.xxxxxxxxxxxxxxxx will
+// use PAL_EPSILON * 10.
+#define PAL_EPSILON 8.8817841970012523e-16
+
+#define PAL_NAN sqrt(-1.0)
+#define PAL_POSINF -log(0.0)
+#define PAL_NEGINF log(0.0)
+
+/**
+ * Helper test structure
+ */
+struct test
+{
+ double value; /* value to test the function with */
+ double expected; /* expected result */
+ double variance; /* maximum delta between the expected and actual result */
+};
+
+/**
+ * validate
+ *
+ * test validation function
+ */
+void __cdecl validate(double value, double expected, double variance)
+{
+ double result = sinh(value);
+
+ /*
+ * The test is valid when the difference between result
+ * and expected is less than or equal to variance
+ */
+ double delta = fabs(result - expected);
+
+ if (delta > variance)
+ {
+ Fail("sinh(%g) returned %20.17g when it should have returned %20.17g",
+ value, result, expected);
+ }
+}
+
+/**
+ * validate
+ *
+ * test validation function for values returning NaN
+ */
+void __cdecl validate_isnan(double value)
+{
+ double result = sinh(value);
+
+ if (!_isnan(result))
+ {
+ Fail("sinh(%g) returned %20.17g when it should have returned %20.17g",
+ value, result, PAL_NAN);
+ }
+}
+
+/**
+ * main
+ *
+ * executable entry point
+ */
+int __cdecl main(int argc, char **argv)
+{
+ struct test tests[] =
+ {
+ /* value expected variance */
+ { 0, 0, PAL_EPSILON },
+ { 0.31830988618379067, 0.32371243907207108, PAL_EPSILON }, // value: 1 / pi
+ { 0.43429448190325183, 0.44807597941469025, PAL_EPSILON }, // value: log10(e)
+ { 0.63661977236758134, 0.68050167815224332, PAL_EPSILON }, // value: 2 / pi
+ { 0.69314718055994531, 0.75, PAL_EPSILON }, // value: ln(2)
+ { 0.70710678118654752, 0.76752314512611633, PAL_EPSILON }, // value: 1 / sqrt(2)
+ { 0.78539816339744831, 0.86867096148600961, PAL_EPSILON }, // value: pi / 4
+ { 1, 1.1752011936438015, PAL_EPSILON * 10 },
+ { 1.1283791670955126, 1.3835428792038633, PAL_EPSILON * 10 }, // value: 2 / sqrt(pi)
+ { 1.4142135623730950, 1.9350668221743567, PAL_EPSILON * 10 }, // value: sqrt(2)
+ { 1.4426950408889634, 1.9978980091062796, PAL_EPSILON * 10 }, // value: log2(e)
+ { 1.5707963267948966, 2.3012989023072949, PAL_EPSILON * 10 }, // value: pi / 2
+ { 2.3025850929940457, 4.95, PAL_EPSILON * 10 }, // value: ln(10)
+ { 2.7182818284590452, 7.5441371028169758, PAL_EPSILON * 10 }, // value: e
+ { 3.1415926535897932, 11.548739357257748, PAL_EPSILON * 100 }, // value: pi
+ { PAL_POSINF, PAL_POSINF, 0 },
+ };
+
+ /* PAL initialization */
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+ for (int i = 0; i < (sizeof(tests) / sizeof(struct test)); i++)
+ {
+ validate( tests[i].value, tests[i].expected, tests[i].variance);
+ validate(-tests[i].value, -tests[i].expected, tests[i].variance);
+ }
+
+ validate_isnan(PAL_NAN);
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/sinh/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/sinh/test1/testinfo.dat
new file mode 100644
index 0000000000..f7aee40201
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sinh/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = sinh
+Name = Positive Test for sinh
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Passes to sinh() a series of angle value, checking that
+= each one return to correct value.
diff --git a/src/pal/tests/palsuite/c_runtime/sprintf/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/sprintf/CMakeLists.txt
new file mode 100644
index 0000000000..cafb9536b0
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sprintf/CMakeLists.txt
@@ -0,0 +1,22 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test10)
+add_subdirectory(test11)
+add_subdirectory(test12)
+add_subdirectory(test13)
+add_subdirectory(test14)
+add_subdirectory(test15)
+add_subdirectory(test16)
+add_subdirectory(test17)
+add_subdirectory(test18)
+add_subdirectory(test19)
+add_subdirectory(test2)
+add_subdirectory(test3)
+add_subdirectory(test4)
+add_subdirectory(test5)
+add_subdirectory(test6)
+add_subdirectory(test7)
+add_subdirectory(test8)
+add_subdirectory(test9)
+
diff --git a/src/pal/tests/palsuite/c_runtime/sprintf/sprintf.h b/src/pal/tests/palsuite/c_runtime/sprintf/sprintf.h
new file mode 100644
index 0000000000..411ae66d54
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sprintf/sprintf.h
@@ -0,0 +1,195 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: sprintf.h
+**
+** Purpose: Containts common testing functions for sprintf
+**
+**
+**==========================================================================*/
+
+#ifndef __SPRINTF_H__
+#define __SPRINTF_H__
+
+void DoStrTest(char *formatstr, char* param, char *checkstr)
+{
+ char buf[256] = { 0 };
+
+ sprintf(buf, formatstr, param);
+ if (memcmp(buf, checkstr, strlen(checkstr) + 1) != 0)
+ {
+ Fail("ERROR: failed to insert string \"%s\" into \"%s\"\n"
+ "Expected \"%s\" got \"%s\".\n",
+ param, formatstr, checkstr, buf);
+ }
+}
+
+void DoWStrTest(char *formatstr, WCHAR* param, char *checkstr)
+{
+ char buf[256] = { 0 };
+
+ sprintf(buf, formatstr, param);
+ if (memcmp(buf, checkstr, strlen(checkstr) + 1) != 0)
+ {
+ Fail("ERROR: failed to insert wide string \"%s\" into \"%s\"\n"
+ "Expected \"%s\" got \"%s\".\n",
+ convertC(param), formatstr, checkstr, buf);
+ }
+}
+
+void DoPointerTest(char *formatstr, void* param, char* paramstr,
+ char *checkstr1)
+{
+ char buf[256] = { 0 };
+
+ sprintf(buf, formatstr, param);
+ if (memcmp(buf, checkstr1, strlen(checkstr1) + 1) != 0)
+ {
+ Fail("ERROR: failed to insert %s into \"%s\"\n"
+ "Expected \"%s\" got \"%s\".\n",
+ paramstr, formatstr, checkstr1, buf);
+ }
+}
+
+void DoCountTest(char *formatstr, int param, char *checkstr)
+{
+ char buf[512] = { 0 };
+ int n = -1;
+
+ sprintf(buf, formatstr, &n);
+
+ if (n != param)
+ {
+ Fail("ERROR: Expected count parameter to resolve to %d, got %X\n",
+ param, n);
+ }
+ if (memcmp(buf, checkstr, strlen(checkstr) + 1) != 0)
+ {
+ Fail("ERROR: Expected \"%s\" got \"%s\".\n", checkstr, buf);
+ }
+}
+
+void DoShortCountTest(char *formatstr, int param, char *checkstr)
+{
+ char buf[256] = { 0 };
+ short int n = -1;
+
+ sprintf(buf, formatstr, &n);
+
+ if (n != param)
+ {
+ Fail("ERROR: Expected count parameter to resolve to %d, got %X\n",
+ param, n);
+ }
+ if (memcmp(buf, checkstr, strlen(checkstr) + 1) != 0)
+ {
+ Fail("ERROR: Expected \"%s\" got \"%s\".\n", checkstr, buf);
+ }
+}
+
+
+void DoCharTest(char *formatstr, char param, char *checkstr)
+{
+ char buf[256] = { 0 };
+
+ sprintf(buf, formatstr, param);
+ if (memcmp(buf, checkstr, strlen(checkstr) + 1) != 0)
+ {
+ Fail("ERROR: failed to insert char \'%c\' (%d) into \"%s\"\n"
+ "Expected \"%s\" got \"%s\".\n",
+ param, param, formatstr, checkstr, buf);
+ }
+}
+
+void DoWCharTest(char *formatstr, WCHAR param, char *checkstr)
+{
+ char buf[256] = { 0 };
+
+ sprintf(buf, formatstr, param);
+ if (memcmp(buf, checkstr, strlen(checkstr) + 1) != 0)
+ {
+ Fail("ERROR: failed to insert wide char \'%c\' (%d) into \"%s\"\n"
+ "Expected \"%s\" got \"%s\".\n",
+ (char)param, param, formatstr, checkstr, buf);
+ }
+}
+
+void DoNumTest(char *formatstr, int value, char *checkstr)
+{
+ char buf[256] = { 0 };
+
+ sprintf(buf, formatstr, value);
+ if (memcmp(buf, checkstr, strlen(checkstr) + 1) != 0)
+ {
+ Fail("ERROR: failed to insert %#x into \"%s\"\n"
+ "Expected \"%s\" got \"%s\".\n",
+ value, formatstr, checkstr, buf);
+ }
+}
+
+void DoI64Test(char *formatstr, INT64 value, char *valuestr, char *checkstr1)
+{
+ char buf[256] = { 0 };
+
+ sprintf(buf, formatstr, value);
+ if (memcmp(buf, checkstr1, strlen(checkstr1) + 1) != 0)
+ {
+ Fail("ERROR: failed to insert %s into \"%s\"\n"
+ "Expected \"%s\", got \"%s\".\n",
+ valuestr, formatstr, checkstr1, buf);
+ }
+}
+
+void DoDoubleTest(char *formatstr, double value, char *checkstr1,
+ char *checkstr2)
+{
+ char buf[256] = { 0 };
+
+ sprintf(buf, formatstr, value);
+ if (memcmp(buf, checkstr1, strlen(checkstr1) + 1) != 0 &&
+ memcmp(buf, checkstr2, strlen(checkstr2) + 1) != 0)
+ {
+ Fail("ERROR: failed to insert %f into \"%s\"\n"
+ "Expected \"%s\" or \"%s\", got \"%s\".\n",
+ value, formatstr, checkstr1, checkstr2, buf);
+ }
+}
+
+void DoArgumentPrecTest(char *formatstr, int precision, void *param,
+ char *paramstr, char *checkstr1, char *checkstr2)
+{
+ char buf[256];
+
+ sprintf(buf, formatstr, precision, param);
+ if (memcmp(buf, checkstr1, strlen(checkstr1) + 1) != 0 &&
+ memcmp(buf, checkstr2, strlen(checkstr2) + 1) != 0)
+ {
+ Fail("ERROR: failed to insert %s into \"%s\" with precision %d\n"
+ "Expected \"%s\" or \"%s\", got \"%s\".\n", paramstr, formatstr,
+ precision, checkstr1, checkstr2, buf);
+ }
+
+}
+
+void DoArgumentPrecDoubleTest(char *formatstr, int precision, double param,
+ char *checkstr1, char *checkstr2)
+{
+ char buf[256];
+
+ sprintf(buf, formatstr, precision, param);
+ if (memcmp(buf, checkstr1, strlen(checkstr1) + 1) != 0 &&
+ memcmp(buf, checkstr2, strlen(checkstr2) + 1) != 0)
+ {
+ Fail("ERROR: failed to insert %f into \"%s\" with precision %d\n"
+ "Expected \"%s\" or \"%s\", got \"%s\".\n", param, formatstr,
+ precision, checkstr1, checkstr2, buf);
+ }
+
+}
+
+#endif
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/sprintf/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/sprintf/test1/CMakeLists.txt
new file mode 100644
index 0000000000..bdec045af9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sprintf/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_sprintf_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_sprintf_test1 coreclrpal)
+
+target_link_libraries(paltest_sprintf_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/sprintf/test1/test1.c b/src/pal/tests/palsuite/c_runtime/sprintf/test1/test1.c
new file mode 100644
index 0000000000..42e27f263b
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sprintf/test1/test1.c
@@ -0,0 +1,45 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Test #1 for the sprintf function. A single, basic, test
+** case with no formatting.
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../sprintf.h"
+
+/*
+ * Depends on memcmp and strlen
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ char checkstr[] = "hello world";
+ char buf[256];
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+
+ sprintf(buf, "hello world");
+
+ if (memcmp(checkstr, buf, strlen(checkstr)+1) != 0)
+ {
+ Fail("ERROR: expected %s, got %s\n", checkstr, buf);
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/sprintf/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/sprintf/test1/testinfo.dat
new file mode 100644
index 0000000000..abe07445cc
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sprintf/test1/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = sprintf
+Name = Positive Test for sprintf
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= General test to see if sprintf works correctly
diff --git a/src/pal/tests/palsuite/c_runtime/sprintf/test10/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/sprintf/test10/CMakeLists.txt
new file mode 100644
index 0000000000..91e9db8ccc
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sprintf/test10/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test10.c
+)
+
+add_executable(paltest_sprintf_test10
+ ${SOURCES}
+)
+
+add_dependencies(paltest_sprintf_test10 coreclrpal)
+
+target_link_libraries(paltest_sprintf_test10
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/sprintf/test10/test10.c b/src/pal/tests/palsuite/c_runtime/sprintf/test10/test10.c
new file mode 100644
index 0000000000..ae7dbfb177
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sprintf/test10/test10.c
@@ -0,0 +1,55 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test10.c
+**
+** Purpose: Test #10 for the sprintf function. Tests the octal specifier
+** (%o).
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../sprintf.h"
+
+/*
+ * Depends on memcmp and strlen
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ int neg = -42;
+ int pos = 42;
+ INT64 l = 42;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+
+ DoNumTest("foo %o", pos, "foo 52");
+ DoNumTest("foo %lo", 0xFFFF, "foo 177777");
+ DoNumTest("foo %ho", 0xFFFF, "foo 177777");
+ DoNumTest("foo %Lo", pos, "foo 52");
+ DoI64Test("foo %I64o", l, "42", "foo 52");
+ DoNumTest("foo %3o", pos, "foo 52");
+ DoNumTest("foo %-3o", pos, "foo 52 ");
+ DoNumTest("foo %.1o", pos, "foo 52");
+ DoNumTest("foo %.3o", pos, "foo 052");
+ DoNumTest("foo %03o", pos, "foo 052");
+ DoNumTest("foo %#o", pos, "foo 052");
+ DoNumTest("foo %+o", pos, "foo 52");
+ DoNumTest("foo % o", pos, "foo 52");
+ DoNumTest("foo %+o", neg, "foo 37777777726");
+ DoNumTest("foo % o", neg, "foo 37777777726");
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/sprintf/test10/testinfo.dat b/src/pal/tests/palsuite/c_runtime/sprintf/test10/testinfo.dat
new file mode 100644
index 0000000000..70b7f3ab75
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sprintf/test10/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = sprintf
+Name = Positive Test for sprintf
+TYPE = DEFAULT
+EXE1 = test10
+Description
+= Tests sprintf with octal numbers
diff --git a/src/pal/tests/palsuite/c_runtime/sprintf/test11/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/sprintf/test11/CMakeLists.txt
new file mode 100644
index 0000000000..b14c8be04d
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sprintf/test11/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test11.c
+)
+
+add_executable(paltest_sprintf_test11
+ ${SOURCES}
+)
+
+add_dependencies(paltest_sprintf_test11 coreclrpal)
+
+target_link_libraries(paltest_sprintf_test11
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/sprintf/test11/test11.c b/src/pal/tests/palsuite/c_runtime/sprintf/test11/test11.c
new file mode 100644
index 0000000000..0b5b5ab93d
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sprintf/test11/test11.c
@@ -0,0 +1,55 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test11.c
+**
+** Purpose: Test #11 for the sprintf function. Test the unsigned int
+** specifier (%u).
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../sprintf.h"
+
+/*
+ * Depends on memcmp and strlen
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ int neg = -42;
+ int pos = 42;
+ INT64 l = 42;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+
+ DoNumTest("foo %u", pos, "foo 42");
+ DoNumTest("foo %lu", 0xFFFF, "foo 65535");
+ DoNumTest("foo %hu", 0xFFFF, "foo 65535");
+ DoNumTest("foo %Lu", pos, "foo 42");
+ DoI64Test("foo %I64u", l, "42", "foo 42");
+ DoNumTest("foo %3u", pos, "foo 42");
+ DoNumTest("foo %-3u", pos, "foo 42 ");
+ DoNumTest("foo %.1u", pos, "foo 42");
+ DoNumTest("foo %.3u", pos, "foo 042");
+ DoNumTest("foo %03u", pos, "foo 042");
+ DoNumTest("foo %#u", pos, "foo 42");
+ DoNumTest("foo %+u", pos, "foo 42");
+ DoNumTest("foo % u", pos, "foo 42");
+ DoNumTest("foo %+u", neg, "foo 4294967254");
+ DoNumTest("foo % u", neg, "foo 4294967254");
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/sprintf/test11/testinfo.dat b/src/pal/tests/palsuite/c_runtime/sprintf/test11/testinfo.dat
new file mode 100644
index 0000000000..852bd3e7b6
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sprintf/test11/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = sprintf
+Name = Positive Test for sprintf
+TYPE = DEFAULT
+EXE1 = test11
+Description
+= Tests sprintf with unsigned numbers
diff --git a/src/pal/tests/palsuite/c_runtime/sprintf/test12/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/sprintf/test12/CMakeLists.txt
new file mode 100644
index 0000000000..1e517495bd
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sprintf/test12/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test12.c
+)
+
+add_executable(paltest_sprintf_test12
+ ${SOURCES}
+)
+
+add_dependencies(paltest_sprintf_test12 coreclrpal)
+
+target_link_libraries(paltest_sprintf_test12
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/sprintf/test12/test12.c b/src/pal/tests/palsuite/c_runtime/sprintf/test12/test12.c
new file mode 100644
index 0000000000..c2e778e494
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sprintf/test12/test12.c
@@ -0,0 +1,56 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test12.c
+**
+** Purpose: Test #12 for the sprintf function. Tests the (lowercase)
+** hexadecimal specifier (%x)
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../sprintf.h"
+
+/*
+ * Depends on memcmp and strlen
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ int neg = -42;
+ int pos = 0x1234ab;
+ INT64 l = I64(0x1234567887654321);
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+
+ DoNumTest("foo %x", pos, "foo 1234ab");
+ DoNumTest("foo %lx", pos, "foo 1234ab");
+ DoNumTest("foo %hx", pos, "foo 34ab");
+ DoNumTest("foo %Lx", pos, "foo 1234ab");
+ DoI64Test("foo %I64x", l, "0x1234567887654321",
+ "foo 1234567887654321");
+ DoNumTest("foo %7x", pos, "foo 1234ab");
+ DoNumTest("foo %-7x", pos, "foo 1234ab ");
+ DoNumTest("foo %.1x", pos, "foo 1234ab");
+ DoNumTest("foo %.7x", pos, "foo 01234ab");
+ DoNumTest("foo %07x", pos, "foo 01234ab");
+ DoNumTest("foo %#x", pos, "foo 0x1234ab");
+ DoNumTest("foo %+x", pos, "foo 1234ab");
+ DoNumTest("foo % x", pos, "foo 1234ab");
+ DoNumTest("foo %+x", neg, "foo ffffffd6");
+ DoNumTest("foo % x", neg, "foo ffffffd6");
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/sprintf/test12/testinfo.dat b/src/pal/tests/palsuite/c_runtime/sprintf/test12/testinfo.dat
new file mode 100644
index 0000000000..5df91d0e6a
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sprintf/test12/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = sprintf
+Name = Positive Test for sprintf
+TYPE = DEFAULT
+EXE1 = test12
+Description
+= Tests sprintf with hex numbers (lowercase)
diff --git a/src/pal/tests/palsuite/c_runtime/sprintf/test13/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/sprintf/test13/CMakeLists.txt
new file mode 100644
index 0000000000..25b033fe82
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sprintf/test13/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test13.c
+)
+
+add_executable(paltest_sprintf_test13
+ ${SOURCES}
+)
+
+add_dependencies(paltest_sprintf_test13 coreclrpal)
+
+target_link_libraries(paltest_sprintf_test13
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/sprintf/test13/test13.c b/src/pal/tests/palsuite/c_runtime/sprintf/test13/test13.c
new file mode 100644
index 0000000000..0b4b7ed9ae
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sprintf/test13/test13.c
@@ -0,0 +1,56 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test13.c
+**
+** Purpose: Test #13 for the sprintf function. Tests the (uppercase)
+** hexadecimal specifier (%X)
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../sprintf.h"
+
+/*
+ * Depends on memcmp and strlen
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ int neg = -42;
+ int pos = 0x1234AB;
+ INT64 l = I64(0x1234567887654321);
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+
+ DoNumTest("foo %X", pos, "foo 1234AB");
+ DoNumTest("foo %lX", pos, "foo 1234AB");
+ DoNumTest("foo %hX", pos, "foo 34AB");
+ DoNumTest("foo %LX", pos, "foo 1234AB");
+ DoI64Test("foo %I64X", l, "0x1234567887654321",
+ "foo 1234567887654321");
+ DoNumTest("foo %7X", pos, "foo 1234AB");
+ DoNumTest("foo %-7X", pos, "foo 1234AB ");
+ DoNumTest("foo %.1X", pos, "foo 1234AB");
+ DoNumTest("foo %.7X", pos, "foo 01234AB");
+ DoNumTest("foo %07X", pos, "foo 01234AB");
+ DoNumTest("foo %#X", pos, "foo 0X1234AB");
+ DoNumTest("foo %+X", pos, "foo 1234AB");
+ DoNumTest("foo % X", pos, "foo 1234AB");
+ DoNumTest("foo %+X", neg, "foo FFFFFFD6");
+ DoNumTest("foo % X", neg, "foo FFFFFFD6");
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/sprintf/test13/testinfo.dat b/src/pal/tests/palsuite/c_runtime/sprintf/test13/testinfo.dat
new file mode 100644
index 0000000000..634817a791
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sprintf/test13/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = sprintf
+Name = Positive Test for sprintf
+TYPE = DEFAULT
+EXE1 = test13
+Description
+= Tests sprintf with hex numbers (uppercase)
diff --git a/src/pal/tests/palsuite/c_runtime/sprintf/test14/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/sprintf/test14/CMakeLists.txt
new file mode 100644
index 0000000000..5eae306e16
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sprintf/test14/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test14.c
+)
+
+add_executable(paltest_sprintf_test14
+ ${SOURCES}
+)
+
+add_dependencies(paltest_sprintf_test14 coreclrpal)
+
+target_link_libraries(paltest_sprintf_test14
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/sprintf/test14/test14.c b/src/pal/tests/palsuite/c_runtime/sprintf/test14/test14.c
new file mode 100644
index 0000000000..20e986a9c3
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sprintf/test14/test14.c
@@ -0,0 +1,53 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test14.c
+**
+** Purpose: Test #14 for the sprintf function. Tests the lowercase
+** exponential notation double specifier (%e)
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../sprintf.h"
+
+/*
+ * Depends on memcmp and strlen
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ double val = 256.0;
+ double neg = -256.0;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+
+ DoDoubleTest("foo %e", val, "foo 2.560000e+002", "foo 2.560000e+02");
+ DoDoubleTest("foo %le", val, "foo 2.560000e+002", "foo 2.560000e+02");
+ DoDoubleTest("foo %he", val, "foo 2.560000e+002", "foo 2.560000e+02");
+ DoDoubleTest("foo %Le", val, "foo 2.560000e+002", "foo 2.560000e+02");
+ DoDoubleTest("foo %I64e", val, "foo 2.560000e+002", "foo 2.560000e+02");
+ DoDoubleTest("foo %14e", val, "foo 2.560000e+002", "foo 2.560000e+02");
+ DoDoubleTest("foo %-14e", val, "foo 2.560000e+002 ", "foo 2.560000e+02 ");
+ DoDoubleTest("foo %.1e", val, "foo 2.6e+002", "foo 2.6e+02");
+ DoDoubleTest("foo %.8e", val, "foo 2.56000000e+002", "foo 2.56000000e+02");
+ DoDoubleTest("foo %014e", val, "foo 02.560000e+002", "foo 002.560000e+02");
+ DoDoubleTest("foo %#e", val, "foo 2.560000e+002", "foo 2.560000e+02");
+ DoDoubleTest("foo %+e", val, "foo +2.560000e+002", "foo +2.560000e+02");
+ DoDoubleTest("foo % e", val, "foo 2.560000e+002", "foo 2.560000e+02");
+ DoDoubleTest("foo %+e", neg, "foo -2.560000e+002", "foo -2.560000e+02");
+ DoDoubleTest("foo % e", neg, "foo -2.560000e+002", "foo -2.560000e+02");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/sprintf/test14/testinfo.dat b/src/pal/tests/palsuite/c_runtime/sprintf/test14/testinfo.dat
new file mode 100644
index 0000000000..c7086efdbc
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sprintf/test14/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = sprintf
+Name = Positive Test for sprintf
+TYPE = DEFAULT
+EXE1 = test14
+Description
+= Tests sprintf with exponential format doubles (lowercase)
diff --git a/src/pal/tests/palsuite/c_runtime/sprintf/test15/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/sprintf/test15/CMakeLists.txt
new file mode 100644
index 0000000000..1fff23fc89
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sprintf/test15/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test15.c
+)
+
+add_executable(paltest_sprintf_test15
+ ${SOURCES}
+)
+
+add_dependencies(paltest_sprintf_test15 coreclrpal)
+
+target_link_libraries(paltest_sprintf_test15
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/sprintf/test15/test15.c b/src/pal/tests/palsuite/c_runtime/sprintf/test15/test15.c
new file mode 100644
index 0000000000..34199b2eb3
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sprintf/test15/test15.c
@@ -0,0 +1,53 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test15.c
+**
+** Purpose: Test #15 for the sprintf function. Tests the uppercase
+** exponential notation double specifier (%E)
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../sprintf.h"
+
+/*
+ * Depends on memcmp and strlen
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ double val = 256.0;
+ double neg = -256.0;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+
+ DoDoubleTest("foo %E", val, "foo 2.560000E+002", "foo 2.560000E+02");
+ DoDoubleTest("foo %lE", val, "foo 2.560000E+002", "foo 2.560000E+02");
+ DoDoubleTest("foo %hE", val, "foo 2.560000E+002", "foo 2.560000E+02");
+ DoDoubleTest("foo %LE", val, "foo 2.560000E+002", "foo 2.560000E+02");
+ DoDoubleTest("foo %I64E", val, "foo 2.560000E+002", "foo 2.560000E+02");
+ DoDoubleTest("foo %14E", val, "foo 2.560000E+002", "foo 2.560000E+02");
+ DoDoubleTest("foo %-14E", val, "foo 2.560000E+002 ", "foo 2.560000E+02 ");
+ DoDoubleTest("foo %.1E", val, "foo 2.6E+002", "foo 2.6E+02");
+ DoDoubleTest("foo %.8E", val, "foo 2.56000000E+002", "foo 2.56000000E+02");
+ DoDoubleTest("foo %014E", val, "foo 02.560000E+002", "foo 002.560000E+02");
+ DoDoubleTest("foo %#E", val, "foo 2.560000E+002", "foo 2.560000E+02");
+ DoDoubleTest("foo %+E", val, "foo +2.560000E+002", "foo +2.560000E+02");
+ DoDoubleTest("foo % E", val, "foo 2.560000E+002", "foo 2.560000E+02");
+ DoDoubleTest("foo %+E", neg, "foo -2.560000E+002", "foo -2.560000E+02");
+ DoDoubleTest("foo % E", neg, "foo -2.560000E+002", "foo -2.560000E+02");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/sprintf/test15/testinfo.dat b/src/pal/tests/palsuite/c_runtime/sprintf/test15/testinfo.dat
new file mode 100644
index 0000000000..0a47c5321a
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sprintf/test15/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = sprintf
+Name = Positive Test for sprintf
+TYPE = DEFAULT
+EXE1 = test15
+Description
+= Tests sprintf with exponential format doubles (uppercase)
diff --git a/src/pal/tests/palsuite/c_runtime/sprintf/test16/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/sprintf/test16/CMakeLists.txt
new file mode 100644
index 0000000000..2065c576d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sprintf/test16/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test16.c
+)
+
+add_executable(paltest_sprintf_test16
+ ${SOURCES}
+)
+
+add_dependencies(paltest_sprintf_test16 coreclrpal)
+
+target_link_libraries(paltest_sprintf_test16
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/sprintf/test16/test16.c b/src/pal/tests/palsuite/c_runtime/sprintf/test16/test16.c
new file mode 100644
index 0000000000..c93b68bc2d
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sprintf/test16/test16.c
@@ -0,0 +1,52 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test16.c
+**
+** Purpose: Test #16 for the sprintf function. Tests the decimal notation
+** double specifier (%f)
+**
+**
+**==========================================================================*/
+
+
+#include <palsuite.h>
+#include "../sprintf.h"
+
+/*
+ * Depends on memcmp and strlen
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ double val = 2560.001;
+ double neg = -2560.001;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+
+ DoDoubleTest("foo %f", val, "foo 2560.001000", "foo 2560.001000");
+ DoDoubleTest("foo %lf", val, "foo 2560.001000", "foo 2560.001000");
+ DoDoubleTest("foo %hf", val, "foo 2560.001000", "foo 2560.001000");
+ DoDoubleTest("foo %Lf", val, "foo 2560.001000", "foo 2560.001000");
+ DoDoubleTest("foo %I64f", val, "foo 2560.001000", "foo 2560.001000");
+ DoDoubleTest("foo %12f", val, "foo 2560.001000", "foo 2560.001000");
+ DoDoubleTest("foo %-12f", val, "foo 2560.001000 ", "foo 2560.001000 ");
+ DoDoubleTest("foo %.1f", val, "foo 2560.0", "foo 2560.0");
+ DoDoubleTest("foo %.8f", val, "foo 2560.00100000", "foo 2560.00100000");
+ DoDoubleTest("foo %012f", val, "foo 02560.001000", "foo 02560.001000");
+ DoDoubleTest("foo %#f", val, "foo 2560.001000", "foo 2560.001000");
+ DoDoubleTest("foo %+f", val, "foo +2560.001000", "foo +2560.001000");
+ DoDoubleTest("foo % f", val, "foo 2560.001000", "foo 2560.001000");
+ DoDoubleTest("foo %+f", neg, "foo -2560.001000", "foo -2560.001000");
+ DoDoubleTest("foo % f", neg, "foo -2560.001000", "foo -2560.001000");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/sprintf/test16/testinfo.dat b/src/pal/tests/palsuite/c_runtime/sprintf/test16/testinfo.dat
new file mode 100644
index 0000000000..e18fab1ad8
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sprintf/test16/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = sprintf
+Name = Positive Test for sprintf
+TYPE = DEFAULT
+EXE1 = test16
+Description
+= Tests sprintf with decimal point format doubles
diff --git a/src/pal/tests/palsuite/c_runtime/sprintf/test17/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/sprintf/test17/CMakeLists.txt
new file mode 100644
index 0000000000..ce3a8ad048
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sprintf/test17/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test17.c
+)
+
+add_executable(paltest_sprintf_test17
+ ${SOURCES}
+)
+
+add_dependencies(paltest_sprintf_test17 coreclrpal)
+
+target_link_libraries(paltest_sprintf_test17
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/sprintf/test17/test17.c b/src/pal/tests/palsuite/c_runtime/sprintf/test17/test17.c
new file mode 100644
index 0000000000..643215b8f5
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sprintf/test17/test17.c
@@ -0,0 +1,54 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test17.c
+**
+** Purpose: Test #17 for the sprintf function. Tests the lowercase
+** shorthand notation double specifier (%g)
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../sprintf.h"
+
+/*
+ * Depends on memcmp and strlen
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ double val = 2560.001;
+ double neg = -2560.001;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+
+ DoDoubleTest("foo %g", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %lg", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %hg", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %Lg", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %I64g", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %5g", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %-5g", val, "foo 2560 ", "foo 2560 ");
+ DoDoubleTest("foo %.1g", val, "foo 3e+003", "foo 3e+03");
+ DoDoubleTest("foo %.2g", val, "foo 2.6e+003", "foo 2.6e+03");
+ DoDoubleTest("foo %.12g", val, "foo 2560.001", "foo 2560.001");
+ DoDoubleTest("foo %06g", val, "foo 002560", "foo 002560");
+ DoDoubleTest("foo %#g", val, "foo 2560.00", "foo 2560.00");
+ DoDoubleTest("foo %+g", val, "foo +2560", "foo +2560");
+ DoDoubleTest("foo % g", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %+g", neg, "foo -2560", "foo -2560");
+ DoDoubleTest("foo % g", neg, "foo -2560", "foo -2560");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/sprintf/test17/testinfo.dat b/src/pal/tests/palsuite/c_runtime/sprintf/test17/testinfo.dat
new file mode 100644
index 0000000000..a723103e02
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sprintf/test17/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = sprintf
+Name = Positive Test for sprintf
+TYPE = DEFAULT
+EXE1 = test17
+Description
+= Tests sprintf with compact format doubles (lowercase)
diff --git a/src/pal/tests/palsuite/c_runtime/sprintf/test18/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/sprintf/test18/CMakeLists.txt
new file mode 100644
index 0000000000..6f69e1c7c2
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sprintf/test18/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test18.c
+)
+
+add_executable(paltest_sprintf_test18
+ ${SOURCES}
+)
+
+add_dependencies(paltest_sprintf_test18 coreclrpal)
+
+target_link_libraries(paltest_sprintf_test18
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/sprintf/test18/test18.c b/src/pal/tests/palsuite/c_runtime/sprintf/test18/test18.c
new file mode 100644
index 0000000000..fa88152479
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sprintf/test18/test18.c
@@ -0,0 +1,53 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test18.c
+**
+** Purpose: Test #18 for the sprintf function. Tests the uppercase
+** shorthand notation double specifier (%G)
+**
+**
+**==========================================================================*/
+
+
+#include <palsuite.h>
+#include "../sprintf.h"
+
+/*
+ * Depends on memcmp and strlen
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ double val = 2560.001;
+ double neg = -2560.001;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+
+ DoDoubleTest("foo %G", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %lG", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %hG", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %LG", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %I64G", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %5G", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %-5G", val, "foo 2560 ", "foo 2560 ");
+ DoDoubleTest("foo %.1G", val, "foo 3E+003", "foo 3E+03");
+ DoDoubleTest("foo %.2G", val, "foo 2.6E+003", "foo 2.6E+03");
+ DoDoubleTest("foo %.12G", val, "foo 2560.001", "foo 2560.001");
+ DoDoubleTest("foo %06G", val, "foo 002560", "foo 002560");
+ DoDoubleTest("foo %#G", val, "foo 2560.00", "foo 2560.00");
+ DoDoubleTest("foo %+G", val, "foo +2560", "foo +2560");
+ DoDoubleTest("foo % G", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %+G", neg, "foo -2560", "foo -2560");
+ DoDoubleTest("foo % G", neg, "foo -2560", "foo -2560");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/sprintf/test18/testinfo.dat b/src/pal/tests/palsuite/c_runtime/sprintf/test18/testinfo.dat
new file mode 100644
index 0000000000..dfafa4bcf4
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sprintf/test18/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = sprintf
+Name = Positive Test for sprintf
+TYPE = DEFAULT
+EXE1 = test18
+Description
+= Tests sprintf with compact format doubles (uppercase)
diff --git a/src/pal/tests/palsuite/c_runtime/sprintf/test19/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/sprintf/test19/CMakeLists.txt
new file mode 100644
index 0000000000..a2917b27dc
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sprintf/test19/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test19.c
+)
+
+add_executable(paltest_sprintf_test19
+ ${SOURCES}
+)
+
+add_dependencies(paltest_sprintf_test19 coreclrpal)
+
+target_link_libraries(paltest_sprintf_test19
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/sprintf/test19/test19.c b/src/pal/tests/palsuite/c_runtime/sprintf/test19/test19.c
new file mode 100644
index 0000000000..aee731cb74
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sprintf/test19/test19.c
@@ -0,0 +1,78 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test19.c
+**
+** Purpose: Test #19 for the sprintf function. Tests the variable length
+** precision argument.
+**
+**
+**==========================================================================*/
+
+
+#include <palsuite.h>
+#include "../sprintf.h"
+
+/*
+ * Depends on memcmp and strlen
+ */
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ int n = -1;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+ DoArgumentPrecTest("%.*s", 2, "bar", "bar", "ba", "ba");
+ DoArgumentPrecTest("%.*S", 2, convert("bar"), "bar", "ba", "ba");
+
+ DoArgumentPrecTest("%.*n", 3, &n, "pointer to int", "", "");
+ if (n != 0)
+ {
+ Fail("ERROR: Expected count parameter to resolve to %d, got %X\n",
+ 0, n);
+ }
+
+ DoArgumentPrecTest("%.*c", 0, (void*)'a', "a", "a", "a");
+ DoArgumentPrecTest("%.*c", 4, (void*)'a', "a", "a", "a");
+ DoArgumentPrecTest("%.*C", 0, (void*)'a', "a", "a", "a");
+ DoArgumentPrecTest("%.*C", 4, (void*)'a', "a", "a", "a");
+ DoArgumentPrecTest("%.*d", 1, (void*)42, "42", "42", "42");
+ DoArgumentPrecTest("%.*d", 3, (void*)42, "42", "042", "042");
+ DoArgumentPrecTest("%.*i", 1, (void*)42, "42", "42", "42");
+ DoArgumentPrecTest("%.*i", 3, (void*)42, "42", "042", "042");
+ DoArgumentPrecTest("%.*o", 1, (void*)42, "42", "52", "52");
+ DoArgumentPrecTest("%.*o", 3, (void*)42, "42", "052", "052");
+ DoArgumentPrecTest("%.*u", 1, (void*)42, "42", "42", "42");
+ DoArgumentPrecTest("%.*u", 3, (void*)42, "42", "042", "042");
+ DoArgumentPrecTest("%.*x", 1, (void*)0x42, "0x42", "42", "42");
+ DoArgumentPrecTest("%.*x", 3, (void*)0x42, "0x42", "042", "042");
+ DoArgumentPrecTest("%.*X", 1, (void*)0x42, "0x42", "42", "42");
+ DoArgumentPrecTest("%.*X", 3, (void*)0x42, "0x42", "042", "042");
+
+
+ DoArgumentPrecDoubleTest("%.*e", 1, 2.01, "2.0e+000", "2.0e+00");
+ DoArgumentPrecDoubleTest("%.*e", 3, 2.01, "2.010e+000", "2.010e+00");
+ DoArgumentPrecDoubleTest("%.*E", 1, 2.01, "2.0E+000", "2.0E+00");
+ DoArgumentPrecDoubleTest("%.*E", 3, 2.01, "2.010E+000", "2.010E+00");
+ DoArgumentPrecDoubleTest("%.*f", 1, 2.01, "2.0", "2.0");
+ DoArgumentPrecDoubleTest("%.*f", 3, 2.01, "2.010", "2.010");
+ DoArgumentPrecDoubleTest("%.*g", 1, 256.01, "3e+002", "3e+02");
+ DoArgumentPrecDoubleTest("%.*g", 3, 256.01, "256", "256");
+ DoArgumentPrecDoubleTest("%.*g", 4, 256.01, "256", "256");
+ DoArgumentPrecDoubleTest("%.*g", 6, 256.01, "256.01", "256.01");
+ DoArgumentPrecDoubleTest("%.*G", 1, 256.01, "3E+002", "3E+02");
+ DoArgumentPrecDoubleTest("%.*G", 3, 256.01, "256", "256");
+ DoArgumentPrecDoubleTest("%.*G", 4, 256.01, "256", "256");
+ DoArgumentPrecDoubleTest("%.*G", 6, 256.01, "256.01", "256.01");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/sprintf/test19/testinfo.dat b/src/pal/tests/palsuite/c_runtime/sprintf/test19/testinfo.dat
new file mode 100644
index 0000000000..ebd13025f6
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sprintf/test19/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = sprintf
+Name = Positive Test for sprintf
+TYPE = DEFAULT
+EXE1 = test19
+Description
+= Tests sprintf with argument specified precision
diff --git a/src/pal/tests/palsuite/c_runtime/sprintf/test2/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/sprintf/test2/CMakeLists.txt
new file mode 100644
index 0000000000..8af1c53a30
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sprintf/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test2.c
+)
+
+add_executable(paltest_sprintf_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_sprintf_test2 coreclrpal)
+
+target_link_libraries(paltest_sprintf_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/sprintf/test2/test2.c b/src/pal/tests/palsuite/c_runtime/sprintf/test2/test2.c
new file mode 100644
index 0000000000..d50679a5a3
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sprintf/test2/test2.c
@@ -0,0 +1,47 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test2.c
+**
+** Purpose: Test #2 for the sprintf function. Tests the string specifier
+** (%s).
+**
+**
+**==========================================================================*/
+
+
+#include <palsuite.h>
+#include "../sprintf.h"
+
+/*
+ * Depends on memcmp and strlen
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+
+ DoStrTest("foo %s", "bar", "foo bar");
+ DoStrTest("foo %hs", "bar", "foo bar");
+ DoWStrTest("foo %ls", convert("bar"), "foo bar");
+ DoWStrTest("foo %ws", convert("bar"), "foo bar");
+ DoStrTest("foo %Ls", "bar", "foo bar");
+ DoStrTest("foo %I64s", "bar", "foo bar");
+ DoStrTest("foo %5s", "bar", "foo bar");
+ DoStrTest("foo %.2s", "bar", "foo ba");
+ DoStrTest("foo %5.2s", "bar", "foo ba");
+ DoStrTest("foo %-5s", "bar", "foo bar ");
+ DoStrTest("foo %05s", "bar", "foo 00bar");
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/sprintf/test2/testinfo.dat b/src/pal/tests/palsuite/c_runtime/sprintf/test2/testinfo.dat
new file mode 100644
index 0000000000..e8d0f53ff3
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sprintf/test2/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = sprintf
+Name = Positive Test for sprintf
+TYPE = DEFAULT
+EXE1 = test2
+Description
+= Tests sprintf with strings
diff --git a/src/pal/tests/palsuite/c_runtime/sprintf/test3/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/sprintf/test3/CMakeLists.txt
new file mode 100644
index 0000000000..b7b7e0a579
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sprintf/test3/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test3.c
+)
+
+add_executable(paltest_sprintf_test3
+ ${SOURCES}
+)
+
+add_dependencies(paltest_sprintf_test3 coreclrpal)
+
+target_link_libraries(paltest_sprintf_test3
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/sprintf/test3/test3.c b/src/pal/tests/palsuite/c_runtime/sprintf/test3/test3.c
new file mode 100644
index 0000000000..ae52dbed08
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sprintf/test3/test3.c
@@ -0,0 +1,47 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test3.c
+**
+** Purpose: Test #3 for the sprintf function. Tests the wide string
+** specifier (%S).
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../sprintf.h"
+
+/*
+ * Depends on memcmp and strlen
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+ DoWStrTest("foo %S", convert("bar"), "foo bar");
+ DoStrTest("foo %hS", "bar", "foo bar");
+ DoWStrTest("foo %lS", convert("bar"), "foo bar");
+ DoWStrTest("foo %wS", convert("bar"), "foo bar");
+ DoWStrTest("foo %LS", convert("bar"), "foo bar");
+ DoWStrTest("foo %I64S", convert("bar"), "foo bar");
+ DoWStrTest("foo %5S", convert("bar"), "foo bar");
+ DoWStrTest("foo %.2S", convert("bar"), "foo ba");
+ DoWStrTest("foo %5.2S", convert("bar"), "foo ba");
+ DoWStrTest("foo %-5S", convert("bar"), "foo bar ");
+ DoWStrTest("foo %05S", convert("bar"), "foo 00bar");
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/sprintf/test3/testinfo.dat b/src/pal/tests/palsuite/c_runtime/sprintf/test3/testinfo.dat
new file mode 100644
index 0000000000..12e0a9cfb0
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sprintf/test3/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = sprintf
+Name = Positive Test for sprintf
+TYPE = DEFAULT
+EXE1 = test3
+Description
+= Tests sprintf with wide strings
diff --git a/src/pal/tests/palsuite/c_runtime/sprintf/test4/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/sprintf/test4/CMakeLists.txt
new file mode 100644
index 0000000000..3478867b7c
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sprintf/test4/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test4.c
+)
+
+add_executable(paltest_sprintf_test4
+ ${SOURCES}
+)
+
+add_dependencies(paltest_sprintf_test4 coreclrpal)
+
+target_link_libraries(paltest_sprintf_test4
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/sprintf/test4/test4.c b/src/pal/tests/palsuite/c_runtime/sprintf/test4/test4.c
new file mode 100644
index 0000000000..9660ffaa3a
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sprintf/test4/test4.c
@@ -0,0 +1,69 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test4.c
+**
+** Purpose: Test #4 for the sprintf function. Tests the pointer
+** specifier (%p).
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../sprintf.h"
+/*
+ * Depends on memcmp and strlen
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ void *ptr = (void*) 0x123456;
+ INT64 lptr = I64(0x1234567887654321);
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+/*
+** Run only on 64 bit platforms
+*/
+#if defined(BIT64) && defined(PLATFORM_UNIX)
+ Trace("Testing for 64 Bit Platforms \n");
+ DoPointerTest("%p", NULL, "NULL", "0000000000000000");
+ DoPointerTest("%p", ptr, "pointer to 0x123456", "0000000000123456");
+ DoPointerTest("%17p", ptr, "pointer to 0x123456", " 0000000000123456");
+ DoPointerTest("%17p", ptr, "pointer to 0x123456", " 0000000000123456");
+ DoPointerTest("%-17p", ptr, "pointer to 0x123456", "0000000000123456 ");
+ DoPointerTest("%+p", ptr, "pointer to 0x123456", "0000000000123456");
+ DoPointerTest("%#p", ptr, "pointer to 0x123456", "0X0000000000123456");
+ DoPointerTest("%lp", ptr, "pointer to 0x123456", "00123456");
+ DoPointerTest("%hp", ptr, "pointer to 0x123456", "00003456");
+ DoPointerTest("%Lp", ptr, "pointer to 0x123456", "00123456");
+ DoI64Test("%I64p", lptr, "pointer to 0x1234567887654321",
+ "1234567887654321");
+#else
+ Trace("Testing for Non 64 Bit Platforms \n");
+ DoPointerTest("%p", NULL, "NULL", "00000000");
+ DoPointerTest("%p", ptr, "pointer to 0x123456", "00123456");
+ DoPointerTest("%9p", ptr, "pointer to 0x123456", " 00123456");
+ DoPointerTest("%09p", ptr, "pointer to 0x123456", " 00123456");
+ DoPointerTest("%-9p", ptr, "pointer to 0x123456", "00123456 ");
+ DoPointerTest("%+p", ptr, "pointer to 0x123456", "00123456");
+ DoPointerTest("%#p", ptr, "pointer to 0x123456", "0X00123456");
+ DoPointerTest("%lp", ptr, "pointer to 0x123456", "00123456");
+ DoPointerTest("%hp", ptr, "pointer to 0x123456", "00003456");
+ DoPointerTest("%Lp", ptr, "pointer to 0x123456", "00123456");
+ DoI64Test("%I64p", lptr, "pointer to 0x1234567887654321",
+ "1234567887654321");
+#endif
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/sprintf/test4/testinfo.dat b/src/pal/tests/palsuite/c_runtime/sprintf/test4/testinfo.dat
new file mode 100644
index 0000000000..bf7236dc32
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sprintf/test4/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = sprintf
+Name = Positive Test for sprintf
+TYPE = DEFAULT
+EXE1 = test4
+Description
+= Tests sprintf with pointers
diff --git a/src/pal/tests/palsuite/c_runtime/sprintf/test5/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/sprintf/test5/CMakeLists.txt
new file mode 100644
index 0000000000..dfa7583766
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sprintf/test5/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test5.c
+)
+
+add_executable(paltest_sprintf_test5
+ ${SOURCES}
+)
+
+add_dependencies(paltest_sprintf_test5 coreclrpal)
+
+target_link_libraries(paltest_sprintf_test5
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/sprintf/test5/test5.c b/src/pal/tests/palsuite/c_runtime/sprintf/test5/test5.c
new file mode 100644
index 0000000000..1b52da77b6
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sprintf/test5/test5.c
@@ -0,0 +1,62 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test5.c
+**
+** Purpose: Test #5 for the sprintf function. Tests the count specifier (%n).
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../sprintf.h"
+
+/*
+ * Depends on memcmp and strlen
+ */
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ char *longStr =
+ "really-long-string-that-just-keeps-going-on-and-on-and-on.."
+ "..................useless-filler.................................."
+ "..................useless-filler.................................."
+ "..................useless-filler.................................."
+ "%n bar";
+ char *longResult =
+ "really-long-string-that-just-keeps-going-on-and-on-and-on.."
+ "..................useless-filler.................................."
+ "..................useless-filler.................................."
+ "..................useless-filler.................................."
+ " bar";
+
+ if (PAL_Initialize(argc, argv)!= 0)
+ {
+ return FAIL;
+ }
+
+ DoCountTest("foo %n bar", 4, "foo bar");
+ DoCountTest(longStr, 257, longResult);
+ DoCountTest("fo%n bar", 2, "fo bar");
+ DoCountTest("%n", 0, "");
+ DoCountTest("foo %#n bar", 4, "foo bar");
+ DoCountTest("foo % n bar", 4, "foo bar");
+ DoCountTest("foo %+n bar", 4, "foo bar");
+ DoCountTest("foo %-n bar", 4, "foo bar");
+ DoCountTest("foo %0n bar", 4, "foo bar");
+ DoShortCountTest("foo %hn bar", 4, "foo bar");
+ DoCountTest("foo %ln bar", 4, "foo bar");
+ DoCountTest("foo %Ln bar", 4, "foo bar");
+ DoCountTest("foo %I64n bar", 4, "foo bar");
+ DoCountTest("foo %20.3n bar", 4, "foo bar");
+
+ PAL_Terminate();
+
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/sprintf/test5/testinfo.dat b/src/pal/tests/palsuite/c_runtime/sprintf/test5/testinfo.dat
new file mode 100644
index 0000000000..31e0537bd0
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sprintf/test5/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = sprintf
+Name = Positive Test for sprintf
+TYPE = DEFAULT
+EXE1 = test5
+Description
+= Tests sprintf with the count specifier
diff --git a/src/pal/tests/palsuite/c_runtime/sprintf/test6/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/sprintf/test6/CMakeLists.txt
new file mode 100644
index 0000000000..7a9a5fc856
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sprintf/test6/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test6.c
+)
+
+add_executable(paltest_sprintf_test6
+ ${SOURCES}
+)
+
+add_dependencies(paltest_sprintf_test6 coreclrpal)
+
+target_link_libraries(paltest_sprintf_test6
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/sprintf/test6/test6.c b/src/pal/tests/palsuite/c_runtime/sprintf/test6/test6.c
new file mode 100644
index 0000000000..c14e075475
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sprintf/test6/test6.c
@@ -0,0 +1,50 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test6.c
+**
+** Purpose: Test #6 for the sprintf function. Tests the char specifier (%c).
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../sprintf.h"
+
+/*
+ * Depends on memcmp and strlen
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ WCHAR wc = (WCHAR) 'c';
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ DoCharTest("foo %c", 'b', "foo b");
+ DoCharTest("foo %hc", 'b', "foo b");
+ DoWCharTest("foo %lc", wc, "foo c");
+ DoCharTest("foo %Lc", 'b', "foo b");
+ DoCharTest("foo %I64c", 'b', "foo b");
+ DoCharTest("foo %5c", 'b', "foo b");
+ DoCharTest("foo %.0c", 'b', "foo b");
+ DoCharTest("foo %-5c", 'b', "foo b ");
+ DoCharTest("foo %05c", 'b', "foo 0000b");
+ DoCharTest("foo % c", 'b', "foo b");
+ DoCharTest("foo %#c", 'b', "foo b");
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/sprintf/test6/testinfo.dat b/src/pal/tests/palsuite/c_runtime/sprintf/test6/testinfo.dat
new file mode 100644
index 0000000000..037e4106ff
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sprintf/test6/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = sprintf
+Name = Positive Test for sprintf
+TYPE = DEFAULT
+EXE1 = test6
+Description
+= Tests sprintf with characters
diff --git a/src/pal/tests/palsuite/c_runtime/sprintf/test7/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/sprintf/test7/CMakeLists.txt
new file mode 100644
index 0000000000..a539a59ab9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sprintf/test7/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test7.c
+)
+
+add_executable(paltest_sprintf_test7
+ ${SOURCES}
+)
+
+add_dependencies(paltest_sprintf_test7 coreclrpal)
+
+target_link_libraries(paltest_sprintf_test7
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/sprintf/test7/test7.c b/src/pal/tests/palsuite/c_runtime/sprintf/test7/test7.c
new file mode 100644
index 0000000000..082bd20e6d
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sprintf/test7/test7.c
@@ -0,0 +1,49 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test7.c
+**
+** Purpose: Test #7 for the sprintf function. Tests the wide char
+** specifier (%C).
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../sprintf.h"
+
+/*
+ * Depends on memcmp and strlen
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ WCHAR wb = (WCHAR) 'b';
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+
+ DoWCharTest("foo %C", wb, "foo b");
+ DoWCharTest("foo %hC", wb, "foo b");
+ DoCharTest("foo %lC", 'c', "foo c");
+ DoWCharTest("foo %LC", wb, "foo b");
+ DoWCharTest("foo %I64C", wb, "foo b");
+ DoWCharTest("foo %5C", wb, "foo b");
+ DoWCharTest("foo %.0C", wb, "foo b");
+ DoWCharTest("foo %-5C", wb, "foo b ");
+ DoWCharTest("foo %05C", wb, "foo 0000b");
+ DoWCharTest("foo % C", wb, "foo b");
+ DoWCharTest("foo %#C", wb, "foo b");
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/sprintf/test7/testinfo.dat b/src/pal/tests/palsuite/c_runtime/sprintf/test7/testinfo.dat
new file mode 100644
index 0000000000..a2730bc97c
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sprintf/test7/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = sprintf
+Name = Positive Test for sprintf
+TYPE = DEFAULT
+EXE1 = test7
+Description
+= Tests sprintf with wide characters
diff --git a/src/pal/tests/palsuite/c_runtime/sprintf/test8/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/sprintf/test8/CMakeLists.txt
new file mode 100644
index 0000000000..7a92c5072a
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sprintf/test8/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test8.c
+)
+
+add_executable(paltest_sprintf_test8
+ ${SOURCES}
+)
+
+add_dependencies(paltest_sprintf_test8 coreclrpal)
+
+target_link_libraries(paltest_sprintf_test8
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/sprintf/test8/test8.c b/src/pal/tests/palsuite/c_runtime/sprintf/test8/test8.c
new file mode 100644
index 0000000000..9587c82c94
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sprintf/test8/test8.c
@@ -0,0 +1,55 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test8.c
+**
+** Purpose: Test #8 for the sprintf function. Tests the decimal
+** specifier (%d).
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../sprintf.h"
+
+/*
+ * Depends on memcmp and strlen
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ int neg = -42;
+ int pos = 42;
+ INT64 l = 42;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+
+ DoNumTest("foo %d", pos, "foo 42");
+ DoNumTest("foo %ld", 0xFFFF, "foo 65535");
+ DoNumTest("foo %hd", 0xFFFF, "foo -1");
+ DoNumTest("foo %Ld", pos, "foo 42");
+ DoI64Test("foo %I64d", l, "42", "foo 42");
+ DoNumTest("foo %3d", pos, "foo 42");
+ DoNumTest("foo %-3d", pos, "foo 42 ");
+ DoNumTest("foo %.1d", pos, "foo 42");
+ DoNumTest("foo %.3d", pos, "foo 042");
+ DoNumTest("foo %03d", pos, "foo 042");
+ DoNumTest("foo %#d", pos, "foo 42");
+ DoNumTest("foo %+d", pos, "foo +42");
+ DoNumTest("foo % d", pos, "foo 42");
+ DoNumTest("foo %+d", neg, "foo -42");
+ DoNumTest("foo % d", neg, "foo -42");
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/sprintf/test8/testinfo.dat b/src/pal/tests/palsuite/c_runtime/sprintf/test8/testinfo.dat
new file mode 100644
index 0000000000..adc0b66f06
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sprintf/test8/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = sprintf
+Name = Positive Test for sprintf
+TYPE = DEFAULT
+EXE1 = test8
+Description
+= Tests sprintf with decimal numbers
diff --git a/src/pal/tests/palsuite/c_runtime/sprintf/test9/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/sprintf/test9/CMakeLists.txt
new file mode 100644
index 0000000000..2a91658bd4
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sprintf/test9/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test9.c
+)
+
+add_executable(paltest_sprintf_test9
+ ${SOURCES}
+)
+
+add_dependencies(paltest_sprintf_test9 coreclrpal)
+
+target_link_libraries(paltest_sprintf_test9
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/sprintf/test9/test9.c b/src/pal/tests/palsuite/c_runtime/sprintf/test9/test9.c
new file mode 100644
index 0000000000..98f5db6ec1
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sprintf/test9/test9.c
@@ -0,0 +1,55 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test9.c
+**
+** Purpose: Test #9 for the sprintf function. Tests the integer
+** specifier (%i).
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../sprintf.h"
+
+/*
+ * Depends on memcmp and strlen
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ int neg = -42;
+ int pos = 42;
+ INT64 l = 42;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+
+ DoNumTest("foo %i", pos, "foo 42");
+ DoNumTest("foo %li", 0xFFFF, "foo 65535");
+ DoNumTest("foo %hi", 0xFFFF, "foo -1");
+ DoNumTest("foo %Li", pos, "foo 42");
+ DoI64Test("foo %I64i", l, "42", "foo 42");
+ DoNumTest("foo %3i", pos, "foo 42");
+ DoNumTest("foo %-3i", pos, "foo 42 ");
+ DoNumTest("foo %.1i", pos, "foo 42");
+ DoNumTest("foo %.3i", pos, "foo 042");
+ DoNumTest("foo %03i", pos, "foo 042");
+ DoNumTest("foo %#i", pos, "foo 42");
+ DoNumTest("foo %+i", pos, "foo +42");
+ DoNumTest("foo % i", pos, "foo 42");
+ DoNumTest("foo %+i", neg, "foo -42");
+ DoNumTest("foo % i", neg, "foo -42");
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/sprintf/test9/testinfo.dat b/src/pal/tests/palsuite/c_runtime/sprintf/test9/testinfo.dat
new file mode 100644
index 0000000000..e569e789cd
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sprintf/test9/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = sprintf
+Name = Positive Test for sprintf
+TYPE = DEFAULT
+EXE1 = test9
+Description
+= Tests sprintf with integer numbers
diff --git a/src/pal/tests/palsuite/c_runtime/sqrt/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/sqrt/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sqrt/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/sqrt/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/sqrt/test1/CMakeLists.txt
new file mode 100644
index 0000000000..4347c44e46
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sqrt/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_sqrt_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_sqrt_test1 coreclrpal)
+
+target_link_libraries(paltest_sqrt_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/sqrt/test1/test1.c b/src/pal/tests/palsuite/c_runtime/sqrt/test1/test1.c
new file mode 100644
index 0000000000..62d2251d61
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sqrt/test1/test1.c
@@ -0,0 +1,123 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test1.c
+**
+** Purpose: Call the sqrt function on a positive value, a positive value
+** with a decimal and on the maxium possible double value.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+// binary64 (double) has a machine epsilon of 2^-52 (approx. 2.22e-16). However, this
+// is slightly too accurate when writing tests meant to run against libm implementations
+// for various platforms. 2^-50 (approx. 8.88e-16) seems to be as accurate as we can get.
+//
+// The tests themselves will take PAL_EPSILON and adjust it according to the expected result
+// so that the delta used for comparison will compare the most significant digits and ignore
+// any digits that are outside the double precision range (15-17 digits).
+
+// For example, a test with an expect result in the format of 0.xxxxxxxxxxxxxxxxx will use
+// PAL_EPSILON for the variance, while an expected result in the format of 0.0xxxxxxxxxxxxxxxxx
+// will use PAL_EPSILON / 10 and and expected result in the format of x.xxxxxxxxxxxxxxxx will
+// use PAL_EPSILON * 10.
+#define PAL_EPSILON 8.8817841970012523e-16
+
+#define PAL_NAN sqrt(-1.0)
+#define PAL_POSINF -log(0.0)
+#define PAL_NEGINF log(0.0)
+
+/**
+ * Helper test structure
+ */
+struct test
+{
+ double value; /* value to test the function with */
+ double expected; /* expected result */
+ double variance; /* maximum delta between the expected and actual result */
+};
+
+/**
+ * validate
+ *
+ * test validation function
+ */
+void __cdecl validate(double value, double expected, double variance)
+{
+ double result = sqrt(value);
+
+ /*
+ * The test is valid when the difference between result
+ * and expected is less than or equal to variance
+ */
+ double delta = fabs(result - expected);
+
+ if (delta > variance)
+ {
+ Fail("sqrt(%g) returned %20.17g when it should have returned %20.17g",
+ value, result, expected);
+ }
+}
+
+/**
+ * validate
+ *
+ * test validation function for values returning NaN
+ */
+void __cdecl validate_isnan(double value)
+{
+ double result = sqrt(value);
+
+ if (!_isnan(result))
+ {
+ Fail("sqrt(%g) returned %20.17g when it should have returned %20.17g",
+ value, result, PAL_NAN);
+ }
+}
+
+int __cdecl main(int argc, char **argv)
+{
+ struct test tests[] =
+ {
+ /* value expected variance */
+ { 0.31830988618379067, 0.56418958354775629, PAL_EPSILON }, // value: 1 / pi
+ { 0.43429448190325183, 0.65901022898226081, PAL_EPSILON }, // value: log10(e)
+ { 0.63661977236758134, 0.79788456080286536, PAL_EPSILON }, // value: 2 / pi
+ { 0.69314718055994531, 0.83255461115769776, PAL_EPSILON }, // value: ln(2)
+ { 0.70710678118654752, 0.84089641525371454, PAL_EPSILON }, // value: 1 / sqrt(2)
+ { 0.78539816339744831, 0.88622692545275801, PAL_EPSILON }, // value: pi / 4
+ { 1, 1, PAL_EPSILON * 10 },
+ { 1.1283791670955126, 1.0622519320271969, PAL_EPSILON * 10 }, // value: 2 / sqrt(pi)
+ { 1.4142135623730950, 1.1892071150027211, PAL_EPSILON * 10 }, // value: sqrt(2)
+ { 1.4426950408889634, 1.2011224087864498, PAL_EPSILON * 10 }, // value: log2(e)
+ { 1.5707963267948966, 1.2533141373155003, PAL_EPSILON * 10 }, // value: pi / 2
+ { 2.3025850929940457, 1.5174271293851464, PAL_EPSILON * 10 }, // value: ln(10)
+ { 2.7182818284590452, 1.6487212707001281, PAL_EPSILON * 10 }, // value: e
+ { 3.1415926535897932, 1.7724538509055160, PAL_EPSILON * 10 }, // value: pi
+ };
+
+ /* PAL initialization */
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+ validate(-0.0, -0.0, PAL_EPSILON);
+ validate( 0.0, 0.0, PAL_EPSILON);
+
+ for (int i = 0; i < (sizeof(tests) / sizeof(struct test)); i++)
+ {
+ validate(tests[i].value, tests[i].expected, tests[i].variance);
+ validate_isnan(-tests[i].value);
+ }
+
+ validate_isnan(PAL_NAN);
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/sqrt/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/sqrt/test1/testinfo.dat
new file mode 100644
index 0000000000..804fef088c
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sqrt/test1/testinfo.dat
@@ -0,0 +1,17 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = sqrt
+Name = Call sqrt on positive values and zero.
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Call the sqrt function on a positive value, a positive value
+= with a decimal and on the maxium possible double value.
+
+
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/sscanf/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/sscanf/CMakeLists.txt
new file mode 100644
index 0000000000..59f39a5f58
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sscanf/CMakeLists.txt
@@ -0,0 +1,20 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test10)
+add_subdirectory(test11)
+add_subdirectory(test12)
+add_subdirectory(test13)
+add_subdirectory(test14)
+add_subdirectory(test15)
+add_subdirectory(test16)
+add_subdirectory(test17)
+add_subdirectory(test2)
+add_subdirectory(test3)
+add_subdirectory(test4)
+add_subdirectory(test5)
+add_subdirectory(test6)
+add_subdirectory(test7)
+add_subdirectory(test8)
+add_subdirectory(test9)
+
diff --git a/src/pal/tests/palsuite/c_runtime/sscanf/sscanf.h b/src/pal/tests/palsuite/c_runtime/sscanf/sscanf.h
new file mode 100644
index 0000000000..675a67aed2
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sscanf/sscanf.h
@@ -0,0 +1,246 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: sscanf.h
+**
+** Purpose: Contains common testing functions for sscanf.h
+**
+**
+**==========================================================================*/
+
+#ifndef __SSCANF_H__
+#define __SSCANF_H__
+
+void DoVoidTest(char *inputstr, char *formatstr)
+{
+ char buf[256] = { 0 };
+ int i;
+ int ret;
+
+ ret = sscanf(inputstr, formatstr, buf);
+ if (ret != 0)
+ {
+ Fail("ERROR: Expected sscanf to return 0, got %d.\n"
+ "Using \"%s\" in \"%s\".\n", ret, inputstr, formatstr);
+ }
+
+ for (i=0; i<256; i++)
+ {
+ if (buf[i] != 0)
+ {
+ Fail("ERROR: Parameter unexpectedly modified scanning \"%s\" "
+ "using \"%s\".\n", inputstr, formatstr);
+ }
+ }
+
+}
+
+void DoStrTest(char *inputstr, char *formatstr, char *checkstr)
+{
+ char buf[256] = { 0 };
+ int ret;
+
+ ret = sscanf(inputstr, formatstr, buf);
+ if (ret != 1)
+ {
+ Fail("ERROR: Expected sscanf to return 1, got %d.\n"
+ "Using \"%s\" in \"%s\".\n", ret, inputstr, formatstr);
+ }
+
+ if (memcmp(checkstr, buf, strlen(checkstr) + 1) != 0)
+ {
+ Fail("ERROR: scanned string incorrectly from \"%s\" using \"%s\".\n"
+ "Expected \"%s\", got \"%s\".\n", inputstr, formatstr, checkstr,
+ buf);
+ }
+
+}
+
+void DoWStrTest(char *inputstr, char *formatstr, WCHAR *checkstr)
+{
+ WCHAR buf[256] = { 0 };
+ int ret;
+
+ ret = sscanf(inputstr, formatstr, buf);
+ if (ret != 1)
+ {
+ Fail("ERROR: Expected sscanf to return 1, got %d.\n"
+ "Using \"%s\" in \"%s\".\n", ret, inputstr, formatstr);
+ }
+
+ if (memcmp(checkstr, buf, wcslen(checkstr)*2 + 2) != 0)
+ {
+ Fail("ERROR: scanned wide string incorrectly from \"%s\" using \"%s\".\n"
+ "Expected \"%s\", got \"%s\".\n", inputstr, formatstr,
+ convertC(checkstr), convertC(buf));
+ }
+
+}
+
+void DoNumTest(char *inputstr, char *formatstr, int checknum)
+{
+ int num;
+ int ret;
+
+ ret = sscanf(inputstr, formatstr, &num);
+ if (ret != 1)
+ {
+ Fail("ERROR: Expected sscanf to return 1, got %d.\n"
+ "Using \"%s\" in \"%s\".\n", ret, inputstr, formatstr);
+ }
+
+ if (checknum != num)
+ {
+ Fail("ERROR: scanned number incorrectly from \"%s\" using \"%s\".\n"
+ "Expected %d, got %d.\n", inputstr, formatstr, checknum, num);
+ }
+}
+
+void DoShortNumTest(char *inputstr, char *formatstr, short checknum)
+{
+ short num;
+ int ret;
+
+ ret = sscanf(inputstr, formatstr, &num);
+ if (ret != 1)
+ {
+ Fail("ERROR: Expected sscanf to return 1, got %d.\n"
+ "Using \"%s\" in \"%s\".\n", ret, inputstr, formatstr);
+ }
+
+ if (checknum != num)
+ {
+ Fail("ERROR: scanned number incorrectly from \"%s\" using \"%s\".\n"
+ "Expected %hd, got %hd.\n", inputstr, formatstr, checknum, num);
+ }
+}
+
+void DoI64NumTest(char *inputstr, char *formatstr, INT64 checknum)
+{
+ char buf[256];
+ char check[256];
+ INT64 num;
+ int ret;
+
+ ret = sscanf(inputstr, formatstr, &num);
+ if (ret != 1)
+ {
+ Fail("ERROR: Expected sscanf to return 1, got %d.\n"
+ "Using \"%s\" in \"%s\".\n", ret, inputstr, formatstr);
+ }
+
+ if (checknum != num)
+ {
+ sprintf(buf, "%I64d", num);
+ sprintf(check, "%I64d", checknum);
+ Fail("ERROR: scanned I64 number incorrectly from \"%s\" using \"%s\".\n"
+ "Expected %s, got %s.\n", inputstr, formatstr, check, buf);
+ }
+}
+
+void DoCharTest(char *inputstr, char *formatstr, char* checkchars, int numchars)
+{
+ char buf[256];
+ int ret;
+ int i;
+
+ for (i=0; i<256; i++)
+ buf[i] = (char)-1;
+
+ ret = sscanf(inputstr, formatstr, buf);
+ if (ret != 1)
+ {
+ Fail("ERROR: Expected sscanf to return 1, got %d.\n"
+ "Using \"%s\" in \"%s\".\n", ret, inputstr, formatstr);
+ }
+
+ if (memcmp(buf, checkchars, numchars) != 0)
+ {
+ buf[numchars] = 0;
+
+ Fail("ERROR: scanned character(s) incorrectly from \"%s\" using \"%s\".\n"
+ "Expected %s, got %s.\n", inputstr, formatstr, checkchars,
+ buf);
+ }
+
+ if (buf[numchars] != (char)-1)
+ {
+ Fail("ERROR: overflow occurred in scanning character(s) from \"%s\" "
+ "using \"%s\".\nExpected %d character(s)\n", inputstr, formatstr,
+ numchars);
+ }
+}
+
+void DoWCharTest(char *inputstr, char *formatstr, WCHAR* checkchars, int numchars)
+{
+ WCHAR buf[256];
+ int ret;
+ int i;
+
+ for (i=0; i<256; i++)
+ buf[i] = (WCHAR)-1;
+
+ ret = sscanf(inputstr, formatstr, buf);
+ if (ret != 1)
+ {
+ Fail("ERROR: Expected sscanf to return 1, got %d.\n"
+ "Using \"%s\" in \"%s\".\n", ret, inputstr, formatstr);
+ }
+
+ if (memcmp(buf, checkchars, numchars) != 0)
+ {
+ buf[numchars] = 0;
+
+ Fail("ERROR: scanned wide character(s) incorrectly from \"%s\" using \"%s\".\n"
+ "Expected %s, got %s.\n", inputstr, formatstr, convertC(checkchars),
+ convertC(buf));
+ }
+
+ if (buf[numchars] != (WCHAR)-1)
+ {
+ Fail("ERROR: overflow occurred in scanning wide character(s) from \"%s\" "
+ "using \"%s\".\nExpected %d character(s)\n", inputstr, formatstr,
+ numchars);
+ }
+}
+
+
+void DoFloatTest(char *inputstr, char *formatstr, float checkval)
+{
+ char buf[256] = { 0 };
+ float val;
+ int ret;
+ int i;
+
+ for (i=0; i<256; i++)
+ buf[i] = (char)-1;
+
+ ret = sscanf(inputstr, formatstr, buf);
+ val = *(float*)buf;
+
+ if (ret != 1)
+ {
+ Fail("ERROR: Expected sscanf to return 1, got %d.\n"
+ "Using \"%s\" in \"%s\".\n", ret, inputstr, formatstr);
+ }
+
+ if (val != checkval)
+ {
+ Fail("ERROR: scanned float incorrectly from \"%s\" using \"%s\".\n"
+ "Expected \"%f\", got \"%f\".\n", inputstr, formatstr, checkval,
+ val);
+ }
+
+ if (buf[4] != (char)-1)
+ {
+ Fail("ERROR: overflow occurred in scanning float from \"%s\" "
+ "using \"%s\".\n", inputstr, formatstr);
+
+ }
+}
+
+
+#endif
diff --git a/src/pal/tests/palsuite/c_runtime/sscanf/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/sscanf/test1/CMakeLists.txt
new file mode 100644
index 0000000000..dce6d1de87
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sscanf/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_sscanf_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_sscanf_test1 coreclrpal)
+
+target_link_libraries(paltest_sscanf_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/sscanf/test1/test1.c b/src/pal/tests/palsuite/c_runtime/sscanf/test1/test1.c
new file mode 100644
index 0000000000..c6f66a1d20
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sscanf/test1/test1.c
@@ -0,0 +1,53 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose: General test of sscanf
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../sscanf.h"
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ int num;
+ int ret;
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ DoVoidTest("foo bar", "foo ");
+ DoVoidTest("foo bar", "baz");
+ DoVoidTest("foo bar", "foo %*s");
+
+ DoStrTest("foo % bar", "foo %% %s", "bar");
+ DoStrTest("foo bar baz", "foo %bar %s", "baz");
+
+ DoVoidTest("foo bar baz", "foo % bar %s");
+ DoVoidTest("foo baz bar", "foo% baz %s");
+
+ ret = sscanf("foo bar baz", "foo bar %n", &num);
+ if (ret != 0 || num != 8)
+ {
+ Fail("ERROR: Got incorrect values in scanning \"%s\" using \"%s\".\n"
+ "Expected to get a value of %d with return value of %d, "
+ "got %d with return %d\n", "foo bar baz", "foo bar %n", 8, 0,
+ num, ret);
+
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/sscanf/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/sscanf/test1/testinfo.dat
new file mode 100644
index 0000000000..ef33ba9e13
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sscanf/test1/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = sscanf
+Name = Positive Test for sscanf
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= General test of sscanf
diff --git a/src/pal/tests/palsuite/c_runtime/sscanf/test10/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/sscanf/test10/CMakeLists.txt
new file mode 100644
index 0000000000..c27e4ce33a
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sscanf/test10/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test10.c
+)
+
+add_executable(paltest_sscanf_test10
+ ${SOURCES}
+)
+
+add_dependencies(paltest_sscanf_test10 coreclrpal)
+
+target_link_libraries(paltest_sscanf_test10
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/sscanf/test10/test10.c b/src/pal/tests/palsuite/c_runtime/sscanf/test10/test10.c
new file mode 100644
index 0000000000..aac5be43ae
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sscanf/test10/test10.c
@@ -0,0 +1,37 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test10.c
+**
+** Purpose: Tests sscanf with wide charactersn
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../sscanf.h"
+
+int __cdecl main(int argc, char *argv[])
+{
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ DoWCharTest("1234d", "%C", convert("1"), 1);
+ DoWCharTest("1234d", "%C", convert("1"), 1);
+ DoWCharTest("abc", "%2C", convert("ab"), 2);
+ DoWCharTest(" ab", "%C", convert(" "), 1);
+ DoCharTest("ab", "%hC", "a", 1);
+ DoWCharTest("ab", "%lC", convert("a"), 1);
+ DoWCharTest("ab", "%LC", convert("a"), 1);
+ DoWCharTest("ab", "%I64C", convert("a"), 1);
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/sscanf/test10/testinfo.dat b/src/pal/tests/palsuite/c_runtime/sscanf/test10/testinfo.dat
new file mode 100644
index 0000000000..7e854ed235
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sscanf/test10/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = sscanf
+Name = Positive Test for sscanf
+TYPE = DEFAULT
+EXE1 = test10
+Description
+= Tests sscanf with wide characters
diff --git a/src/pal/tests/palsuite/c_runtime/sscanf/test11/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/sscanf/test11/CMakeLists.txt
new file mode 100644
index 0000000000..7570e990bf
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sscanf/test11/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test11.c
+)
+
+add_executable(paltest_sscanf_test11
+ ${SOURCES}
+)
+
+add_dependencies(paltest_sscanf_test11 coreclrpal)
+
+target_link_libraries(paltest_sscanf_test11
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/sscanf/test11/test11.c b/src/pal/tests/palsuite/c_runtime/sscanf/test11/test11.c
new file mode 100644
index 0000000000..0e3db6cca0
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sscanf/test11/test11.c
@@ -0,0 +1,36 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test11.c
+**
+** Purpose: Tests sscanf with strings
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../sscanf.h"
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ DoStrTest("foo bar", "foo %s", "bar");
+ DoStrTest("foo bar", "foo %2s", "ba");
+ DoStrTest("foo bar", "foo %hs", "bar");
+ DoWStrTest("foo bar", "foo %ls", convert("bar"));
+ DoStrTest("foo bar", "foo %Ls", "bar");
+ DoStrTest("foo bar", "foo %I64s", "bar");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/sscanf/test11/testinfo.dat b/src/pal/tests/palsuite/c_runtime/sscanf/test11/testinfo.dat
new file mode 100644
index 0000000000..60f5cc46a4
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sscanf/test11/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = sscanf
+Name = Positive Test for sscanf
+TYPE = DEFAULT
+EXE1 = test11
+Description
+= Tests sscanf with strings
diff --git a/src/pal/tests/palsuite/c_runtime/sscanf/test12/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/sscanf/test12/CMakeLists.txt
new file mode 100644
index 0000000000..b6509e46d4
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sscanf/test12/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test12.c
+)
+
+add_executable(paltest_sscanf_test12
+ ${SOURCES}
+)
+
+add_dependencies(paltest_sscanf_test12 coreclrpal)
+
+target_link_libraries(paltest_sscanf_test12
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/sscanf/test12/test12.c b/src/pal/tests/palsuite/c_runtime/sscanf/test12/test12.c
new file mode 100644
index 0000000000..f800e452c0
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sscanf/test12/test12.c
@@ -0,0 +1,35 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test12.c
+**
+** Purpose: Tests sscanf with wide strings
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../sscanf.h"
+
+int __cdecl main(int argc, char *argv[])
+{
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ DoWStrTest("foo bar", "foo %S", convert("bar"));
+ DoWStrTest("foo bar", "foo %2S", convert("ba"));
+ DoStrTest("foo bar", "foo %hS", "bar");
+ DoWStrTest("foo bar", "foo %lS", convert("bar"));
+ DoWStrTest("foo bar", "foo %LS", convert("bar"));
+ DoWStrTest("foo bar", "foo %I64S", convert("bar"));
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/sscanf/test12/testinfo.dat b/src/pal/tests/palsuite/c_runtime/sscanf/test12/testinfo.dat
new file mode 100644
index 0000000000..3c453bf53a
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sscanf/test12/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = sscanf
+Name = Positive Test for sscanf
+TYPE = DEFAULT
+EXE1 = test12
+Description
+= Tests sscanf with wide strings
diff --git a/src/pal/tests/palsuite/c_runtime/sscanf/test13/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/sscanf/test13/CMakeLists.txt
new file mode 100644
index 0000000000..6fb4094f00
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sscanf/test13/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test13.c
+)
+
+add_executable(paltest_sscanf_test13
+ ${SOURCES}
+)
+
+add_dependencies(paltest_sscanf_test13 coreclrpal)
+
+target_link_libraries(paltest_sscanf_test13
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/sscanf/test13/test13.c b/src/pal/tests/palsuite/c_runtime/sscanf/test13/test13.c
new file mode 100644
index 0000000000..314604e3ac
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sscanf/test13/test13.c
@@ -0,0 +1,37 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test13.c
+**
+** Purpose: Tests sscanf with floats (decimal notation)
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../sscanf.h"
+
+int __cdecl main(int argc, char *argv[])
+{
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ DoFloatTest("123.0", "%f", 123.0f);
+ DoFloatTest("123.0", "%2f", 12.0f);
+ DoFloatTest("10E1", "%f", 100.0f);
+ DoFloatTest("-12.01e-2", "%f", -0.1201f);
+ DoFloatTest("+12.01e-2", "%f", 0.1201f);
+ DoFloatTest("-12.01e+2", "%f", -1201.0f);
+ DoFloatTest("+12.01e+2", "%f", 1201.0f);
+ DoFloatTest("1234567890.0123456789f", "%f", 1234567936);
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/sscanf/test13/testinfo.dat b/src/pal/tests/palsuite/c_runtime/sscanf/test13/testinfo.dat
new file mode 100644
index 0000000000..1c4c2fc26e
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sscanf/test13/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = sscanf
+Name = Positive Test for sscanf
+TYPE = DEFAULT
+EXE1 = test13
+Description
+= Tests sscanf with floats (decimal notation)
diff --git a/src/pal/tests/palsuite/c_runtime/sscanf/test14/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/sscanf/test14/CMakeLists.txt
new file mode 100644
index 0000000000..373a75fbda
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sscanf/test14/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test14.c
+)
+
+add_executable(paltest_sscanf_test14
+ ${SOURCES}
+)
+
+add_dependencies(paltest_sscanf_test14 coreclrpal)
+
+target_link_libraries(paltest_sscanf_test14
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/sscanf/test14/test14.c b/src/pal/tests/palsuite/c_runtime/sscanf/test14/test14.c
new file mode 100644
index 0000000000..d1291a3b65
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sscanf/test14/test14.c
@@ -0,0 +1,36 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test14.c
+**
+** Purpose: Tests sscanf with floats (exponential notation, lowercase)
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../sscanf.h"
+
+int __cdecl main(int argc, char *argv[])
+{
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ DoFloatTest("123.0", "%e", 123.0f);
+ DoFloatTest("123.0", "%2e", 12.0f);
+ DoFloatTest("10E1", "%e", 100.0f);
+ DoFloatTest("-12.01e-2", "%e", -0.1201f);
+ DoFloatTest("+12.01e-2", "%e", 0.1201f);
+ DoFloatTest("-12.01e+2", "%e", -1201.0f);
+ DoFloatTest("+12.01e+2", "%e", 1201.0f);
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/sscanf/test14/testinfo.dat b/src/pal/tests/palsuite/c_runtime/sscanf/test14/testinfo.dat
new file mode 100644
index 0000000000..97db6e4ffd
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sscanf/test14/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = sscanf
+Name = Positive Test for sscanf
+TYPE = DEFAULT
+EXE1 = test14
+Description
+= Tests sscanf with floats (exponential notation, lowercase)
diff --git a/src/pal/tests/palsuite/c_runtime/sscanf/test15/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/sscanf/test15/CMakeLists.txt
new file mode 100644
index 0000000000..d500901782
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sscanf/test15/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test15.c
+)
+
+add_executable(paltest_sscanf_test15
+ ${SOURCES}
+)
+
+add_dependencies(paltest_sscanf_test15 coreclrpal)
+
+target_link_libraries(paltest_sscanf_test15
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/sscanf/test15/test15.c b/src/pal/tests/palsuite/c_runtime/sscanf/test15/test15.c
new file mode 100644
index 0000000000..fa51467d85
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sscanf/test15/test15.c
@@ -0,0 +1,36 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test15.c
+**
+** Purpose: Tests sscanf with floats (exponential notation, uppercase
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../sscanf.h"
+
+int __cdecl main(int argc, char *argv[])
+{
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ DoFloatTest("123.0", "%E", 123.0f);
+ DoFloatTest("123.0", "%2E", 12.0f);
+ DoFloatTest("10E1", "%E", 100.0f);
+ DoFloatTest("-12.01e-2", "%E", -0.1201f);
+ DoFloatTest("+12.01e-2", "%E", 0.1201f);
+ DoFloatTest("-12.01e+2", "%E", -1201.0f);
+ DoFloatTest("+12.01e+2", "%E", 1201.0f);
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/sscanf/test15/testinfo.dat b/src/pal/tests/palsuite/c_runtime/sscanf/test15/testinfo.dat
new file mode 100644
index 0000000000..30c2cf4b30
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sscanf/test15/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = sscanf
+Name = Positive Test for sscanf
+TYPE = DEFAULT
+EXE1 = test15
+Description
+= Tests sscanf with floats (exponential notation, uppercase)
diff --git a/src/pal/tests/palsuite/c_runtime/sscanf/test16/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/sscanf/test16/CMakeLists.txt
new file mode 100644
index 0000000000..c5e18ec061
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sscanf/test16/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test16.c
+)
+
+add_executable(paltest_sscanf_test16
+ ${SOURCES}
+)
+
+add_dependencies(paltest_sscanf_test16 coreclrpal)
+
+target_link_libraries(paltest_sscanf_test16
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/sscanf/test16/test16.c b/src/pal/tests/palsuite/c_runtime/sscanf/test16/test16.c
new file mode 100644
index 0000000000..787b72ed0a
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sscanf/test16/test16.c
@@ -0,0 +1,37 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test16.c
+**
+** Purpose:Tests sscanf with floats (compact notation, lowercase)
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../sscanf.h"
+
+int __cdecl main(int argc, char *argv[])
+{
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ DoFloatTest("123.0", "%g", 123.0f);
+ DoFloatTest("123.0", "%2g", 12.0f);
+ DoFloatTest("10E1", "%g", 100.0f);
+ DoFloatTest("-12.01e-2", "%g", -0.1201f);
+ DoFloatTest("+12.01e-2", "%g", 0.1201f);
+ DoFloatTest("-12.01e+2", "%g", -1201.0f);
+ DoFloatTest("+12.01e+2", "%g", 1201.0f);
+ DoFloatTest("1234567890.0123456789g", "%g", 1234567936);
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/sscanf/test16/testinfo.dat b/src/pal/tests/palsuite/c_runtime/sscanf/test16/testinfo.dat
new file mode 100644
index 0000000000..2c1dd42b70
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sscanf/test16/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = sscanf
+Name = Positive Test for sscanf
+TYPE = DEFAULT
+EXE1 = test16
+Description
+= Tests sscanf with floats (compact notation, lowercase)
diff --git a/src/pal/tests/palsuite/c_runtime/sscanf/test17/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/sscanf/test17/CMakeLists.txt
new file mode 100644
index 0000000000..7d908ab832
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sscanf/test17/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test17.c
+)
+
+add_executable(paltest_sscanf_test17
+ ${SOURCES}
+)
+
+add_dependencies(paltest_sscanf_test17 coreclrpal)
+
+target_link_libraries(paltest_sscanf_test17
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/sscanf/test17/test17.c b/src/pal/tests/palsuite/c_runtime/sscanf/test17/test17.c
new file mode 100644
index 0000000000..c0dfd1699c
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sscanf/test17/test17.c
@@ -0,0 +1,37 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test17.c
+**
+** Purpose: Tests sscanf with floats (compact notation, uppercase)
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../sscanf.h"
+
+int __cdecl main(int argc, char *argv[])
+{
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ DoFloatTest("123.0", "%G", 123.0f);
+ DoFloatTest("123.0", "%2G", 12.0f);
+ DoFloatTest("10E1", "%G", 100.0f);
+ DoFloatTest("-12.01e-2", "%G", -0.1201f);
+ DoFloatTest("+12.01e-2", "%G", 0.1201f);
+ DoFloatTest("-12.01e+2", "%G", -1201.0f);
+ DoFloatTest("+12.01e+2", "%G", 1201.0f);
+ DoFloatTest("1234567890.0123456789G", "%G", 1234567936);
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/sscanf/test17/testinfo.dat b/src/pal/tests/palsuite/c_runtime/sscanf/test17/testinfo.dat
new file mode 100644
index 0000000000..e23be8541e
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sscanf/test17/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = sscanf
+Name = Positive Test for sscanf
+TYPE = DEFAULT
+EXE1 = test17
+Description
+= Tests sscanf with floats (compact notation, uppercase)
diff --git a/src/pal/tests/palsuite/c_runtime/sscanf/test2/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/sscanf/test2/CMakeLists.txt
new file mode 100644
index 0000000000..571d773a88
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sscanf/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test2.c
+)
+
+add_executable(paltest_sscanf_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_sscanf_test2 coreclrpal)
+
+target_link_libraries(paltest_sscanf_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/sscanf/test2/test2.c b/src/pal/tests/palsuite/c_runtime/sscanf/test2/test2.c
new file mode 100644
index 0000000000..1221124e3a
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sscanf/test2/test2.c
@@ -0,0 +1,44 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test2.c
+**
+** Purpose: Test to see if sscanf handles whitespace correctly
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../sscanf.h"
+
+
+/*
+ * Tests out how it handles whitespace. Seems to accept anything that qualifies
+ * as isspace (space, tab, vertical tab, line feed, carriage return and form
+ * feed), even if it says it only wants spaces tabs and newlines.
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ DoStrTest("foo bar", "foo %s", "bar");
+ DoStrTest("foo\tbar", "foo %s", "bar");
+ DoStrTest("foo\nbar", "foo %s", "bar");
+ DoStrTest("foo\rbar", "foo %s", "bar");
+ DoStrTest("foo\vbar", "foo %s", "bar");
+ DoStrTest("foo\fbar", "foo %s", "bar");
+ DoStrTest("foo \t\n\r\v\fbar", "foo %s", "bar");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/sscanf/test2/testinfo.dat b/src/pal/tests/palsuite/c_runtime/sscanf/test2/testinfo.dat
new file mode 100644
index 0000000000..f5ee4b52d4
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sscanf/test2/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = sscanf
+Name = Positive Test for sscanf
+TYPE = DEFAULT
+EXE1 = test2
+Description
+= Test to see if sscanf handles whitespace correctly
diff --git a/src/pal/tests/palsuite/c_runtime/sscanf/test3/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/sscanf/test3/CMakeLists.txt
new file mode 100644
index 0000000000..ced8d5f8da
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sscanf/test3/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test3.c
+)
+
+add_executable(paltest_sscanf_test3
+ ${SOURCES}
+)
+
+add_dependencies(paltest_sscanf_test3 coreclrpal)
+
+target_link_libraries(paltest_sscanf_test3
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/sscanf/test3/test3.c b/src/pal/tests/palsuite/c_runtime/sscanf/test3/test3.c
new file mode 100644
index 0000000000..9d18991070
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sscanf/test3/test3.c
@@ -0,0 +1,35 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test3.c
+**
+** Purpose: Tests sscanf with bracketed set strings
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../sscanf.h"
+
+int __cdecl main(int argc, char *argv[])
+{
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ DoStrTest("bar1", "%[a-z]", "bar");
+ DoStrTest("bar1", "%[z-a]", "bar");
+ DoStrTest("bar1", "%[ab]", "ba");
+ DoStrTest("bar1", "%[ar1b]", "bar1");
+ DoStrTest("bar1", "%[^4]", "bar1");
+ DoStrTest("bar1", "%[^4a]", "b");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/sscanf/test3/testinfo.dat b/src/pal/tests/palsuite/c_runtime/sscanf/test3/testinfo.dat
new file mode 100644
index 0000000000..c38a498225
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sscanf/test3/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = sscanf
+Name = Positive Test for sscanf
+TYPE = DEFAULT
+EXE1 = test3
+Description
+= Tests sscanf with bracketed set strings
diff --git a/src/pal/tests/palsuite/c_runtime/sscanf/test4/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/sscanf/test4/CMakeLists.txt
new file mode 100644
index 0000000000..3e70d6dae2
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sscanf/test4/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test4.c
+)
+
+add_executable(paltest_sscanf_test4
+ ${SOURCES}
+)
+
+add_dependencies(paltest_sscanf_test4 coreclrpal)
+
+target_link_libraries(paltest_sscanf_test4
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/sscanf/test4/test4.c b/src/pal/tests/palsuite/c_runtime/sscanf/test4/test4.c
new file mode 100644
index 0000000000..dd0538bcfe
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sscanf/test4/test4.c
@@ -0,0 +1,44 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test4.c
+**
+** Purpose: Tests sscanf with decimal numbers
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../sscanf.h"
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ int n65535 = 65535; /* Walkaround compiler strictness */
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ DoNumTest("1234d", "%d", 1234);
+ DoNumTest("1234d", "%2d", 12);
+ DoNumTest("-1", "%d", -1);
+ DoNumTest("0x1234", "%d", 0);
+ DoNumTest("012", "%d", 12);
+ DoShortNumTest("-1", "%hd", n65535);
+ DoShortNumTest("65536", "%hd", 0);
+ DoNumTest("-1", "%ld", -1);
+ DoNumTest("65536", "%ld", 65536);
+ DoNumTest("-1", "%Ld", -1);
+ DoNumTest("65536", "%Ld", 65536);
+ DoI64NumTest("4294967296", "%I64d", I64(4294967296));
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/sscanf/test4/testinfo.dat b/src/pal/tests/palsuite/c_runtime/sscanf/test4/testinfo.dat
new file mode 100644
index 0000000000..868056a6a5
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sscanf/test4/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = sscanf
+Name = Positive Test for sscanf
+TYPE = DEFAULT
+EXE1 = test4
+Description
+= Tests sscanf with decimal numbers
diff --git a/src/pal/tests/palsuite/c_runtime/sscanf/test5/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/sscanf/test5/CMakeLists.txt
new file mode 100644
index 0000000000..391e51baa2
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sscanf/test5/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test5.c
+)
+
+add_executable(paltest_sscanf_test5
+ ${SOURCES}
+)
+
+add_dependencies(paltest_sscanf_test5 coreclrpal)
+
+target_link_libraries(paltest_sscanf_test5
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/sscanf/test5/test5.c b/src/pal/tests/palsuite/c_runtime/sscanf/test5/test5.c
new file mode 100644
index 0000000000..0d45248af3
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sscanf/test5/test5.c
@@ -0,0 +1,43 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test5.c
+**
+** Purpose: Tests sscanf with integer numbers
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../sscanf.h"
+
+int __cdecl main(int argc, char *argv[])
+{
+ int n65535 = 65535; /* Walkaround compiler strictness */
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ DoNumTest("1234d", "%i", 1234);
+ DoNumTest("1234d", "%2i", 12);
+ DoNumTest("-1", "%i", -1);
+ DoNumTest("0x1234", "%i", 0x1234);
+ DoNumTest("012", "%i", 10);
+ DoShortNumTest("-1", "%hi", n65535);
+ DoShortNumTest("65536", "%hi", 0);
+ DoNumTest("-1", "%li", -1);
+ DoNumTest("65536", "%li", 65536);
+ DoNumTest("-1", "%Li", -1);
+ DoNumTest("65536", "%Li", 65536);
+ DoI64NumTest("4294967296", "%I64i", I64(4294967296));
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/sscanf/test5/testinfo.dat b/src/pal/tests/palsuite/c_runtime/sscanf/test5/testinfo.dat
new file mode 100644
index 0000000000..8678dc8f5a
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sscanf/test5/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = sscanf
+Name = Positive Test for sscanf
+TYPE = DEFAULT
+EXE1 = test5
+Description
+= Tests sscanf with integer numbers
diff --git a/src/pal/tests/palsuite/c_runtime/sscanf/test6/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/sscanf/test6/CMakeLists.txt
new file mode 100644
index 0000000000..c0b21bfd0d
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sscanf/test6/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test6.c
+)
+
+add_executable(paltest_sscanf_test6
+ ${SOURCES}
+)
+
+add_dependencies(paltest_sscanf_test6 coreclrpal)
+
+target_link_libraries(paltest_sscanf_test6
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/sscanf/test6/test6.c b/src/pal/tests/palsuite/c_runtime/sscanf/test6/test6.c
new file mode 100644
index 0000000000..c45ea31b04
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sscanf/test6/test6.c
@@ -0,0 +1,43 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test6.c
+**
+** Purpose: Tests sscanf with octal numbers
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../sscanf.h"
+
+int __cdecl main(int argc, char *argv[])
+{
+ int n65535 = 65535; /* Walkaround compiler strictness */
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ DoNumTest("1234d", "%o", 668);
+ DoNumTest("1234d", "%2o", 10);
+ DoNumTest("-1", "%o", -1);
+ DoNumTest("0x1234", "%o", 0);
+ DoNumTest("012", "%o", 10);
+ DoShortNumTest("-1", "%ho", n65535);
+ DoShortNumTest("200000", "%ho", 0);
+ DoNumTest("-1", "%lo", -1);
+ DoNumTest("200000", "%lo", 65536);
+ DoNumTest("-1", "%Lo", -1);
+ DoNumTest("200000", "%Lo", 65536);
+ DoI64NumTest("40000000000", "%I64o", I64(4294967296));
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/sscanf/test6/testinfo.dat b/src/pal/tests/palsuite/c_runtime/sscanf/test6/testinfo.dat
new file mode 100644
index 0000000000..b2547a776a
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sscanf/test6/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = sscanf
+Name = Positive Test for sscanf
+TYPE = DEFAULT
+EXE1 = test6
+Description
+= Tests sscanf with octal numbers
diff --git a/src/pal/tests/palsuite/c_runtime/sscanf/test7/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/sscanf/test7/CMakeLists.txt
new file mode 100644
index 0000000000..bcbd268011
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sscanf/test7/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test7.c
+)
+
+add_executable(paltest_sscanf_test7
+ ${SOURCES}
+)
+
+add_dependencies(paltest_sscanf_test7 coreclrpal)
+
+target_link_libraries(paltest_sscanf_test7
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/sscanf/test7/test7.c b/src/pal/tests/palsuite/c_runtime/sscanf/test7/test7.c
new file mode 100644
index 0000000000..0899671d64
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sscanf/test7/test7.c
@@ -0,0 +1,43 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test7.c
+**
+** Purpose: Tests sscanf with hex numbers (lowercase)
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../sscanf.h"
+
+int __cdecl main(int argc, char *argv[])
+{
+ int n65535 = 65535; /* Walkaround compiler strictness */
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ DoNumTest("1234i", "%x", 0x1234);
+ DoNumTest("1234i", "%2x", 0x12);
+ DoNumTest("-1", "%x", -1);
+ DoNumTest("0x1234", "%x", 0x1234);
+ DoNumTest("012", "%x", 0x12);
+ DoShortNumTest("-1", "%hx", n65535);
+ DoShortNumTest("10000", "%hx", 0);
+ DoNumTest("-1", "%lx", -1);
+ DoNumTest("10000", "%lx", 65536);
+ DoNumTest("-1", "%Lx", -1);
+ DoNumTest("10000", "%Lx", 65536);
+ DoI64NumTest("100000000", "%I64x", I64(4294967296));
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/sscanf/test7/testinfo.dat b/src/pal/tests/palsuite/c_runtime/sscanf/test7/testinfo.dat
new file mode 100644
index 0000000000..614333e650
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sscanf/test7/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = sscanf
+Name = Positive Test for sscanf
+TYPE = DEFAULT
+EXE1 = test7
+Description
+= Tests sscanf with hex numbers (lowercase)
diff --git a/src/pal/tests/palsuite/c_runtime/sscanf/test8/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/sscanf/test8/CMakeLists.txt
new file mode 100644
index 0000000000..211e9e4df6
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sscanf/test8/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test8.c
+)
+
+add_executable(paltest_sscanf_test8
+ ${SOURCES}
+)
+
+add_dependencies(paltest_sscanf_test8 coreclrpal)
+
+target_link_libraries(paltest_sscanf_test8
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/sscanf/test8/test8.c b/src/pal/tests/palsuite/c_runtime/sscanf/test8/test8.c
new file mode 100644
index 0000000000..53252f8929
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sscanf/test8/test8.c
@@ -0,0 +1,43 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test8.c
+**
+** Purpose:Tests sscanf with unsigned number
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../sscanf.h"
+
+int __cdecl main(int argc, char *argv[])
+{
+ int n65535 = 65535; /* Walkaround compiler strictness */
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ DoNumTest("1234d", "%u", 1234);
+ DoNumTest("1234d", "%2u", 12);
+ DoNumTest("-1", "%u", -1);
+ DoNumTest("0x1234", "%u", 0);
+ DoNumTest("012", "%u", 12);
+ DoShortNumTest("-1", "%hu", n65535);
+ DoShortNumTest("65536", "%hu", 0);
+ DoNumTest("-1", "%lu", -1);
+ DoNumTest("65536", "%lu", 65536);
+ DoNumTest("-1", "%Lu", -1);
+ DoNumTest("65536", "%Lu", 65536);
+ DoI64NumTest("4294967296", "%I64u", I64(4294967296));
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/sscanf/test8/testinfo.dat b/src/pal/tests/palsuite/c_runtime/sscanf/test8/testinfo.dat
new file mode 100644
index 0000000000..2cbc31ad2a
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sscanf/test8/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = sscanf
+Name = Positive Test for sscanf
+TYPE = DEFAULT
+EXE1 = test8
+Description
+= Tests sscanf with unsigned numbers
diff --git a/src/pal/tests/palsuite/c_runtime/sscanf/test9/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/sscanf/test9/CMakeLists.txt
new file mode 100644
index 0000000000..77c269aeaa
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sscanf/test9/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test9.c
+)
+
+add_executable(paltest_sscanf_test9
+ ${SOURCES}
+)
+
+add_dependencies(paltest_sscanf_test9 coreclrpal)
+
+target_link_libraries(paltest_sscanf_test9
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/sscanf/test9/test9.c b/src/pal/tests/palsuite/c_runtime/sscanf/test9/test9.c
new file mode 100644
index 0000000000..c5a2e0de5d
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sscanf/test9/test9.c
@@ -0,0 +1,38 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test9.c
+**
+** Purpose: Tests sscanf with characters
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../sscanf.h"
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ DoCharTest("1234d", "%c", "1", 1);
+ DoCharTest("1234d", "%c", "1", 1);
+ DoCharTest("abc", "%2c", "ab", 2);
+ DoCharTest(" ab", "%c", " ", 1);
+ DoCharTest("ab", "%hc", "a", 1);
+ DoWCharTest("ab", "%lc", convert("a"), 1);
+ DoCharTest("ab", "%Lc", "a", 1);
+ DoCharTest("ab", "%I64c", "a", 1);
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/sscanf/test9/testinfo.dat b/src/pal/tests/palsuite/c_runtime/sscanf/test9/testinfo.dat
new file mode 100644
index 0000000000..c0ccc8a4c9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/sscanf/test9/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section =C Runtime
+Function = sscanf
+Name = Positive Test for sscanf
+TYPE = DEFAULT
+EXE1 = test9
+Description
+= Tests sscanf with characters
diff --git a/src/pal/tests/palsuite/c_runtime/strcat/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/strcat/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/strcat/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/strcat/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/strcat/test1/CMakeLists.txt
new file mode 100644
index 0000000000..4a0f0be32d
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/strcat/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_strcat_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_strcat_test1 coreclrpal)
+
+target_link_libraries(paltest_strcat_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/strcat/test1/test1.c b/src/pal/tests/palsuite/c_runtime/strcat/test1/test1.c
new file mode 100644
index 0000000000..532d84621e
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/strcat/test1/test1.c
@@ -0,0 +1,66 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose:
+** Concatenate three strings into one string. Each time, check to ensure
+** the pointer returned was what we expected. When finished, compare the
+** newly formed string to what it should be to ensure no characters were
+** lost.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ char dest[80];
+ char *test = "foo bar baz";
+ char *str1 = "foo ";
+ char *str2 = "bar ";
+ char *str3 = "baz";
+ char *ptr;
+
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ dest[0] = 0;
+
+ ptr = strcat(dest, str1);
+ if (ptr != dest)
+ {
+ Fail("ERROR: Expected strcat to return ptr to %p, got %p", dest, ptr);
+ }
+
+ ptr = strcat(dest, str2);
+ if (ptr != dest)
+ {
+ Fail("ERROR: Expected strcat to return ptr to %p, got %p", dest, ptr);
+ }
+
+ ptr = strcat(dest, str3);
+ if (ptr != dest)
+ {
+ Fail("ERROR: Expected strcat to return ptr to %p, got %p", dest, ptr);
+ }
+
+ if (strcmp(dest, test) != 0)
+ {
+ Fail("ERROR: Expected strcat to give \"%s\", got \"%s\"\n",
+ test, dest);
+ }
+
+ PAL_Terminate();
+
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/strcat/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/strcat/test1/testinfo.dat
new file mode 100644
index 0000000000..6d67ffa180
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/strcat/test1/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = strcat
+Name = Test #1 for strcat
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Concatenate three strings into one string. Each time, check to ensure
+= the pointer returned was what we expected. When finished, compare the
+= newly formed string to what it should be to ensure no characters were
+= lost.
diff --git a/src/pal/tests/palsuite/c_runtime/strchr/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/strchr/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/strchr/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/strchr/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/strchr/test1/CMakeLists.txt
new file mode 100644
index 0000000000..1d248f3f56
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/strchr/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_strchr_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_strchr_test1 coreclrpal)
+
+target_link_libraries(paltest_strchr_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/strchr/test1/test1.c b/src/pal/tests/palsuite/c_runtime/strchr/test1/test1.c
new file mode 100644
index 0000000000..9190c4f7ce
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/strchr/test1/test1.c
@@ -0,0 +1,86 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose:
+** Test this on a character which is in a string, and ensure the pointer
+** points to that character. Then check the string for the null character,
+** which the return pointer should point to. Then search for a character not
+** in the string and check that the return value is NULL.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+
+struct testCase
+{
+ int result;
+ char string[50];
+ int character;
+};
+
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ int i = 0;
+ char *result;
+
+ /*
+ * this structure includes several strings to be tested with
+ * strchr function and the expected results
+ */
+
+ struct testCase testCases[]=
+ {
+ {22,"corn cup cat cream coast",'s'},
+ {10,"corn cup cat cream coast",'a'},
+ {2,"This is a test",'i'},
+ {10,"This is a test",'t'},
+ {'\0',"This is a test",'b'},/* zero used instead of NULL */
+ {'\0',"This is a test",121},/* zero used instead of NULL */
+ {4,"This is a test of the function",' '},
+ {25,"This is a test of the function",'c'},
+ {'\0',"This is a test of the function",'C'},
+ {24,"corn cup cat cream coast", '\0'}/* zero used instead of NULL */
+ };
+
+ if (0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ /* Loop through the structure and test each case */
+
+ for (i=0; i< sizeof(testCases)/sizeof(struct testCase); i++)
+ {
+ result = strchr(testCases[i].string,testCases[i].character);
+ if (result==NULL)
+ {
+ if (testCases[i].result != (int) NULL)
+ {
+ Fail("Expected strchr() to return \"%s\" instead of NULL!\n",
+ testCases[i].string + testCases[i].result);
+ }
+ }
+ else
+ {
+ if (result != testCases[i].string + testCases[i].result)
+ {
+ Fail("Expected strchr() to return \"%s\" instead of \"%s\"!\n",
+ testCases[i].string + testCases[i].result, result);
+ }
+ }
+
+ }
+
+ PAL_Terminate();
+
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/strchr/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/strchr/test1/testinfo.dat
new file mode 100644
index 0000000000..4985c47541
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/strchr/test1/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = strchr
+Name = Test #1 for strchr
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Test this on a character which is in a string, and ensure the pointer
+= points to that character. Then check the string for the null character,
+= which the return pointer should point to. Then search for a character not
+= in the string and check that the return value is NULL.
diff --git a/src/pal/tests/palsuite/c_runtime/strcmp/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/strcmp/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/strcmp/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/strcmp/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/strcmp/test1/CMakeLists.txt
new file mode 100644
index 0000000000..b953dfa034
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/strcmp/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_strcmp_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_strcmp_test1 coreclrpal)
+
+target_link_libraries(paltest_strcmp_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/strcmp/test1/test1.c b/src/pal/tests/palsuite/c_runtime/strcmp/test1/test1.c
new file mode 100644
index 0000000000..49428fd624
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/strcmp/test1/test1.c
@@ -0,0 +1,73 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose:
+** Compare a number of different strings against each other, ensure that the
+** three return values are given at the appropriate times.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+
+typedef struct
+{
+ int result;
+ char string1[50];
+ char string2[50];
+} testCase;
+
+testCase testCases[]=
+{
+ {0,"Hello","Hello"},
+ {1,"hello","Hello"},
+ {-1,"Hello","hello"},
+ {0,"0Test","0Test"},
+ {0,"***???","***???"},
+ {0,"Testing the string for string comparison","Testing the string for "
+ "string comparison"},
+ {-1,"Testing the string for string comparison","Testing the string for "
+ "string comparsioa"},
+ {1,"Testing the string for string comparison","Testing the string for "
+ "comparison"},
+ {-1,"aaaabbbbb","aabcdefeccg"}
+};
+
+int __cdecl main(int argc, char *argv[])
+{
+ int i = 0;
+ int result = 0;
+
+ /*
+ * Initialize the PAL
+ */
+ if (0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ /* Loop through structure and test each case */
+ for (i=0; i < sizeof(testCases)/sizeof(testCase); i++)
+ {
+ result = strcmp(testCases[i].string1,testCases[i].string2);
+
+ /* Compare returned value */
+ if( ((result == 0) && (testCases[i].result !=0)) ||
+ ((result <0) && (testCases[i].result !=-1)) ||
+ ((result >0) && (testCases[i].result !=1)) )
+ {
+ Fail("ERROR: strcmp returned %d instead of %d\n",
+ result, testCases[i].result);
+ }
+
+ }
+
+ PAL_Terminate();
+
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/strcmp/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/strcmp/test1/testinfo.dat
new file mode 100644
index 0000000000..174cb4be85
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/strcmp/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = strcmp
+Name = Test #1 for strcmp
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Compare a number of different strings against each other, ensure that the
+= three return values are given at the appropriate times.
diff --git a/src/pal/tests/palsuite/c_runtime/strcpy/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/strcpy/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/strcpy/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/strcpy/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/strcpy/test1/CMakeLists.txt
new file mode 100644
index 0000000000..043ec57d98
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/strcpy/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_strcpy_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_strcpy_test1 coreclrpal)
+
+target_link_libraries(paltest_strcpy_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/strcpy/test1/test1.c b/src/pal/tests/palsuite/c_runtime/strcpy/test1/test1.c
new file mode 100644
index 0000000000..43069e59a6
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/strcpy/test1/test1.c
@@ -0,0 +1,51 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose:
+** Call the function to copy into an empty buffer. Check that the return value
+** is pointing at the destination buffer. Also compare the string copied to
+** the origional string, to ensure they are the same.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ char dest[80];
+ char *result = "foo";
+ char str[] = {'f','o','o',0,'b','a','r',0};
+ char *ret;
+
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ ret = strcpy(dest, str);
+
+ if (ret != dest)
+ {
+ Fail("Expected strcpy to return %p, got %p!\n", dest, ret);
+
+ }
+
+ if (strcmp(dest, result) != 0)
+ {
+ Fail("Expected strcpy to give \"%s\", got \"%s\"!\n", result, dest);
+ }
+
+
+ PAL_Terminate();
+
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/strcpy/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/strcpy/test1/testinfo.dat
new file mode 100644
index 0000000000..700b124926
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/strcpy/test1/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = strcpy
+Name = Test #1 for strcpy
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Call the function to copy into an empty buffer. Check that the return value
+= is pointing at the destination buffer. Also compare the string copied to
+= the origional string, to ensure they are the same.
diff --git a/src/pal/tests/palsuite/c_runtime/strcspn/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/strcspn/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/strcspn/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/strcspn/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/strcspn/test1/CMakeLists.txt
new file mode 100644
index 0000000000..a38761c335
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/strcspn/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_strcspn_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_strcspn_test1 coreclrpal)
+
+target_link_libraries(paltest_strcspn_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/strcspn/test1/test1.c b/src/pal/tests/palsuite/c_runtime/strcspn/test1/test1.c
new file mode 100644
index 0000000000..ddc5667570
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/strcspn/test1/test1.c
@@ -0,0 +1,59 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Tests strcspn with a character set that should give an index into
+** the middle of the original string. Also tests with character sets
+** that are not in the string at all, and character sets that match
+** with the very first character.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+
+struct testCase
+{
+ long result;
+ char *string1;
+ char *string2;
+};
+
+int __cdecl main(int argc, char *argv[])
+{
+ int i=0;
+ long TheResult = 0;
+
+ struct testCase testCases[]=
+ {
+ {4,"abcdefg12345678hijklmnopqrst","t8m1sBe"},
+ {23,"This is a test, testing", "X\tylM"},
+ {0,"foobar","tzkfb"},
+ };
+
+ /*
+ * Initialize the PAL
+ */
+ if (0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ for (i=0; i<sizeof(testCases)/sizeof(struct testCase); i++)
+ {
+ TheResult = strcspn(testCases[i].string1,testCases[i].string2);
+ if (TheResult != testCases[i].result)
+ {
+ Fail("Expected strcspn to return %d, got %d!\n",
+ testCases[i].result,TheResult);
+ }
+
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/strcspn/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/strcspn/test1/testinfo.dat
new file mode 100644
index 0000000000..a302eb1fb7
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/strcspn/test1/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = strcspn
+Name = Test #1 for strcspn
+TYPE = DEFAULT
+EXE1 = test1
+Description
+=Tests strcspn with a character set that should give an index into
+=the middle of the original string. Also tests with character sets
+=that are not in the string at all, and character sets that match
+=with the very first character.
diff --git a/src/pal/tests/palsuite/c_runtime/strlen/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/strlen/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/strlen/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/strlen/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/strlen/test1/CMakeLists.txt
new file mode 100644
index 0000000000..c61828a97b
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/strlen/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_strlen_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_strlen_test1 coreclrpal)
+
+target_link_libraries(paltest_strlen_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/strlen/test1/test1.c b/src/pal/tests/palsuite/c_runtime/strlen/test1/test1.c
new file mode 100644
index 0000000000..40f8e151c7
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/strlen/test1/test1.c
@@ -0,0 +1,33 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose:
+** Check the length of a string and the length of a 0 character string to
+** see that this function returns the correct values for each.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ if (strlen("foo") != 3)
+ Fail("ERROR: strlen(\"foo\") != 3\n");
+
+ if (strlen("") != 0)
+ Fail("ERROR: strlen(\"\") != 0\n");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/strlen/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/strlen/test1/testinfo.dat
new file mode 100644
index 0000000000..ac5c3aec0f
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/strlen/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = strlen
+Name = Positive Test for strlen
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Check the length of a string and the length of a 0 character string to
+= see that this function returns the correct values for each.
diff --git a/src/pal/tests/palsuite/c_runtime/strncat/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/strncat/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/strncat/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/strncat/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/strncat/test1/CMakeLists.txt
new file mode 100644
index 0000000000..7595f66939
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/strncat/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_strncat_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_strncat_test1 coreclrpal)
+
+target_link_libraries(paltest_strncat_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/strncat/test1/test1.c b/src/pal/tests/palsuite/c_runtime/strncat/test1/test1.c
new file mode 100644
index 0000000000..000d1685b9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/strncat/test1/test1.c
@@ -0,0 +1,77 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose:
+** Concatenate a few strings together, setting different lengths to be
+** used for each one. Check to ensure the pointers which are returned are
+** correct, and that the final string is what was expected.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ char dest[80];
+ char *test = "foo barbaz";
+ char *str1 = "foo ";
+ char *str2 = "bar ";
+ char *str3 = "baz";
+ char *ptr;
+ int i;
+
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ dest[0] = 0;
+ for (i=1; i<80; i++)
+ {
+ dest[i] = 'x';
+ }
+
+ ptr = strncat(dest, str1, strlen(str1));
+ if (ptr != dest)
+ {
+ Fail("ERROR: Expected strncat to return ptr to %p, got %p", dest, ptr);
+ }
+
+ ptr = strncat(dest, str2, 3);
+ if (ptr != dest)
+ {
+ Fail("ERROR: Expected strncat to return ptr to %p, got %p", dest, ptr);
+ }
+ if (dest[7] != 0)
+ {
+ Fail("ERROR: strncat did not place a terminating NULL!");
+ }
+
+ ptr = strncat(dest, str3, 20);
+ if (ptr != dest)
+ {
+ Fail("ERROR: Expected strncat to return ptr to %p, got %p", dest, ptr);
+ }
+ if (strcmp(dest, test) != 0)
+ {
+ Fail("ERROR: Expected strncat to give \"%s\", got \"%s\"\n",
+ test, dest);
+ }
+ if (dest[strlen(test)+1] != 'x')
+ {
+ Fail("strncat went out of bounds!\n");
+ }
+
+ PAL_Terminate();
+
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/strncat/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/strncat/test1/testinfo.dat
new file mode 100644
index 0000000000..4aaedbf404
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/strncat/test1/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = strncat
+Name = Test #1 for strncat
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Concatenate a few strings together, setting different lengths to be
+= used for each one. Check to ensure the pointers which are returned are
+= correct, and that the final string is what was expected.
diff --git a/src/pal/tests/palsuite/c_runtime/strncmp/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/strncmp/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/strncmp/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/strncmp/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/strncmp/test1/CMakeLists.txt
new file mode 100644
index 0000000000..4a0337a3dc
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/strncmp/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_strncmp_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_strncmp_test1 coreclrpal)
+
+target_link_libraries(paltest_strncmp_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/strncmp/test1/test1.c b/src/pal/tests/palsuite/c_runtime/strncmp/test1/test1.c
new file mode 100644
index 0000000000..7326c3b61e
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/strncmp/test1/test1.c
@@ -0,0 +1,80 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose:
+** Test to ensure all three possible return values are given under the
+** appropriate circumstance. Also, uses different sizes, to only compare
+** portions of strings, checking to make sure these return the correct value.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+
+typedef struct
+{
+ int result;
+ char string1[50];
+ char string2[50];
+ int number;
+} testCase;
+
+testCase testCases[]=
+{
+ {0,"Hello","Hello",5},
+ {1,"hello","Hello",3},
+ {-1,"Hello","hello",5},
+ {0,"heLLo","heLLo",5},
+ {1,"hello","heLlo",5},
+ {-1,"heLlo","hello",5},
+ {0,"0Test","0Test",5},
+ {0,"***???","***???",6},
+ {0,"Testing the string for string comparison","Testing the string for "
+ "string comparison",40},
+ {-1,"Testing the string for string comparison","Testing the string for "
+ "string comparsioa",40},
+ {1,"Testing the string for string comparison","Testing the string for "
+ "comparison",34},
+ {0,"aaaabbbbb","aabcdefeccg",2},
+ {0,"abcd","abcd",10}
+};
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ int i=0;
+ int iresult=0;
+
+ /*
+ * Initialize the PAL
+ */
+ if (0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ for (i=0; i< sizeof(testCases)/sizeof(testCase); i++)
+ {
+ iresult = strncmp(testCases[i].string1,testCases[i].string2,
+ testCases[i].number);
+
+ if( ((iresult == 0) && (testCases[i].result !=0)) ||
+ ((iresult <0) && (testCases[i].result !=-1)) ||
+ ((iresult >0) && (testCases[i].result !=1)) )
+
+ {
+ Fail("ERROR: strncmp returned %d instead of %d\n",
+ iresult, testCases[i].result);
+ }
+
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/strncmp/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/strncmp/test1/testinfo.dat
new file mode 100644
index 0000000000..8e95311f36
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/strncmp/test1/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = strncmp
+Name = Test #1 for strncmp
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Test to ensure all three possible return values are given under the
+= appropriate circumstance. Also, uses different sizes, to only compare
+= portions of strings, checking to make sure these return the correct value.
diff --git a/src/pal/tests/palsuite/c_runtime/strncpy/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/strncpy/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/strncpy/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/strncpy/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/strncpy/test1/CMakeLists.txt
new file mode 100644
index 0000000000..6e0250bce3
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/strncpy/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_strncpy_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_strncpy_test1 coreclrpal)
+
+target_link_libraries(paltest_strncpy_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/strncpy/test1/test1.c b/src/pal/tests/palsuite/c_runtime/strncpy/test1/test1.c
new file mode 100644
index 0000000000..62baf61ba2
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/strncpy/test1/test1.c
@@ -0,0 +1,85 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose:
+** Test to see that you can copy a portion of a string into a new buffer.
+** Also check that the strncpy function doesn't overflow when it is used.
+** Finally check that if the number of characters given is greater than the
+** amount to copy, that the destination buffer is padded with NULLs.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ char dest[80];
+ char *result = "foobar";
+ char *str = "foobar\0baz";
+ char *ret;
+ int i;
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ for (i=0; i<80; i++)
+ {
+ dest[i] = 'x';
+ }
+
+ ret = strncpy(dest, str, 3);
+ if (ret != dest)
+ {
+ Fail("Expected strncpy to return %p, got %p!\n", dest, ret);
+ }
+
+ if (strncmp(dest, result, 3) != 0)
+ {
+ Fail("Expected strncpy to give \"%s\", got \"%s\"!\n", result, dest);
+ }
+
+ if (dest[3] != 'x')
+ {
+ Fail("strncpy overflowed!\n");
+ }
+
+ ret = strncpy(dest, str, 40);
+ if (ret != dest)
+ {
+ Fail("Expected strncpy to return %p, got %p!\n", dest, ret);
+ }
+
+ if (strcmp(dest, result) != 0)
+ {
+ Fail("Expected strncpy to give \"%s\", got \"%s\"!\n", result, dest);
+ }
+
+ for (i=strlen(str); i<40; i++)
+ {
+ if (dest[i] != 0)
+ {
+ Fail("strncpy failed to pad the destination with NULLs!\n");
+ }
+ }
+
+ if (dest[40] != 'x')
+ {
+ Fail("strncpy overflowed!\n");
+ }
+
+
+
+ PAL_Terminate();
+
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/strncpy/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/strncpy/test1/testinfo.dat
new file mode 100644
index 0000000000..c402adb1c1
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/strncpy/test1/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = strncpy
+Name = Test #1 for strncpy
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Test to see that you can copy a portion of a string into a new buffer.
+= Also check that the strncpy function doesn't overflow when it is used.
+= Finally check that if the number of characters given is greater than the
+= amount to copy, that the destination buffer is padded with NULLs.
diff --git a/src/pal/tests/palsuite/c_runtime/strpbrk/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/strpbrk/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/strpbrk/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/strpbrk/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/strpbrk/test1/CMakeLists.txt
new file mode 100644
index 0000000000..eac9ac9169
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/strpbrk/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_strpbrk_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_strpbrk_test1 coreclrpal)
+
+target_link_libraries(paltest_strpbrk_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/strpbrk/test1/test1.c b/src/pal/tests/palsuite/c_runtime/strpbrk/test1/test1.c
new file mode 100644
index 0000000000..a42b80f313
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/strpbrk/test1/test1.c
@@ -0,0 +1,85 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose:
+** Search a string for characters in a given character set and ensure the
+** pointer returned points to the first occurance. Check to see that the
+** function returns NULL if the character is not found.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+
+struct testCase
+{
+ char *result;
+ char *string1;
+ char *string2;
+};
+
+int __cdecl main(int argc, char *argv[])
+{
+ char *ptr = NULL;
+ int i = 0;
+
+ /*
+ * this structure includes several strings to be tested with
+ * strpbk function and the expected results
+ */
+
+ struct testCase testCases[] =
+ {
+ {"t cream coast","corn cup cat cream coast","sit"},
+ {"eam coast","corn cup cat cream coast","like"},
+ {"is is a test","This is a test","circle"},
+ {"a test","This is a test","way"},
+ {NULL,"This is a test","boo"},
+ {NULL,"This is a test","123"},
+ {" is a test of the function","This is a test of the function",
+ "zzz xx"}
+ };
+
+
+ if (0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ /* A loop to go through the testcases in the structure */
+
+ for (i=0; i< sizeof(testCases)/sizeof(struct testCase); i++)
+ {
+ ptr = strpbrk(testCases[i].string1,testCases[i].string2);
+ if (ptr==NULL)
+ {
+ if (testCases[i].result != NULL)
+ {
+ Fail("Expected strpbrk() to return %s, got NULL!\n",
+ testCases[i].result);
+ }
+ }
+ else
+ {
+ if (strcmp(ptr,testCases[i].result)!=0 )
+
+ {
+ Fail("Expected strpbrk() to return %s, got %s!\n",
+ testCases[i].result,ptr);
+ }
+
+ }
+
+ }
+
+
+ PAL_Terminate();
+
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/strpbrk/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/strpbrk/test1/testinfo.dat
new file mode 100644
index 0000000000..1bef6a7b9d
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/strpbrk/test1/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = strpbrk
+Name = Test #1 for strpbrk
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Search a string for characters in a given character set and ensure the
+= pointer returned points to the first occurance. Check to see that the
+= function returns NULL if the character is not found.
diff --git a/src/pal/tests/palsuite/c_runtime/strrchr/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/strrchr/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/strrchr/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/strrchr/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/strrchr/test1/CMakeLists.txt
new file mode 100644
index 0000000000..5c099b0cd2
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/strrchr/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_strrchr_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_strrchr_test1 coreclrpal)
+
+target_link_libraries(paltest_strrchr_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/strrchr/test1/test1.c b/src/pal/tests/palsuite/c_runtime/strrchr/test1/test1.c
new file mode 100644
index 0000000000..a5c147eece
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/strrchr/test1/test1.c
@@ -0,0 +1,55 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose: \
+** Search a string for a given character. Search for a character contained
+** in the string, and ensure the pointer returned points to it. Then search
+** for the null character, and ensure the pointer points to that. Finally
+** search for a character which is not in the string and ensure that it
+** returns NULL.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ char *str = "foo bar baz";
+ char *ptr;
+
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ ptr = strrchr(str, 'b');
+ if (ptr != str + 8)
+ {
+ Fail("Expected strrchr() to return %p, got %p!\n", str + 8, ptr);
+ }
+
+ ptr = strrchr(str, 0);
+ if (ptr != str + 11)
+ {
+ Fail("Expected strrchr() to return %p, got %p!\n", str + 11, ptr);
+ }
+
+ ptr = strrchr(str, 'x');
+ if (ptr != NULL)
+ {
+ Fail("Expected strrchr() to return NULL, got %p!\n", ptr);
+ }
+
+ PAL_Terminate();
+
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/strrchr/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/strrchr/test1/testinfo.dat
new file mode 100644
index 0000000000..45b27aecf9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/strrchr/test1/testinfo.dat
@@ -0,0 +1,16 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = strrchr
+Name = Test #1 for strrchr
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Search a string for a given character. Search for a character contained
+= in the string, and ensure the pointer returned points to it. Then search
+= for the null character, and ensure the pointer points to that. Finally
+= search for a character which is not in the string and ensure that it
+= returns NULL.
diff --git a/src/pal/tests/palsuite/c_runtime/strspn/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/strspn/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/strspn/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/strspn/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/strspn/test1/CMakeLists.txt
new file mode 100644
index 0000000000..45caaf1bf8
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/strspn/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_strspn_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_strspn_test1 coreclrpal)
+
+target_link_libraries(paltest_strspn_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/strspn/test1/test1.c b/src/pal/tests/palsuite/c_runtime/strspn/test1/test1.c
new file mode 100644
index 0000000000..78d2488438
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/strspn/test1/test1.c
@@ -0,0 +1,60 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose:
+** Check a character set against a string to see that the function returns
+** the length of the substring which consists of all characters in the string.
+** Also check that if the character set doesn't match the string at all, that
+** the value is 0.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+
+struct testCase
+{
+ long result;
+ char *string1;
+ char *string2;
+};
+
+int __cdecl main(int argc, char *argv[])
+{
+ int i=0;
+ long TheResult = 0;
+
+ struct testCase testCases[]=
+ {
+ {4,"abcdefg12345678hijklmnopqrst","a2bjk341cd"},
+ {14,"This is a test, testing", "aeioTts rh"},
+ {0,"foobar","kpzt"}
+ };
+
+ /*
+ * Initialize the PAL
+ */
+ if (0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ for (i=0; i<sizeof(testCases)/sizeof(struct testCase);i++)
+ {
+ TheResult = strspn(testCases[i].string1,testCases[i].string2);
+ if (TheResult != testCases[i].result)
+ {
+ Fail("Expected strspn to return %d, got %d!\n",
+ testCases[i].result,TheResult);
+ }
+
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/strspn/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/strspn/test1/testinfo.dat
new file mode 100644
index 0000000000..b56bd1574e
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/strspn/test1/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = strspn
+Name = Test #1 for strspn
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Check a character set against a string to see that the function returns
+= the length of the substring which consists of all characters in the string.
+= Also check that if the character set doesn't match the string at all, that
+= the value is 0.
diff --git a/src/pal/tests/palsuite/c_runtime/strstr/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/strstr/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/strstr/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/strstr/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/strstr/test1/CMakeLists.txt
new file mode 100644
index 0000000000..17e6ae8457
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/strstr/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_strstr_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_strstr_test1 coreclrpal)
+
+target_link_libraries(paltest_strstr_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/strstr/test1/test1.c b/src/pal/tests/palsuite/c_runtime/strstr/test1/test1.c
new file mode 100644
index 0000000000..db01e8b32a
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/strstr/test1/test1.c
@@ -0,0 +1,83 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose:
+** Check three cases of searching for a string within a string. First when
+** the string is contained, check that the pointer returned points to it.
+** Then when it isn't contained, ensure it returns null. And when the string
+** we're searching for is empty, it should return a pointer to the string
+** we're searching through.Test #1 for the strstr function
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+
+
+struct testCase
+{
+ char *result;
+ char *string1;
+ char *string2;
+
+};
+
+int __cdecl main(int argc, char *argv[])
+{
+ int i=0;
+ char *ptr=NULL;
+
+ struct testCase testCases[]=
+ {
+ {"is is a test", "This is a test","is"},
+ {"fghijkl","abcdefghijkl","fgh"},
+ {NULL,"aabbccddeeffgg","h"},
+ {NULL,"aabb", "eeeeeee"},
+ {"AAA", "BBddfdaaaaAAA","A"},
+ {"fdaaaaAAA", "BBddfdaaaaAAA","f"},
+ {"aadfsadfas","aadfsadfas",""},
+ {NULL,"","ccc"}
+ };
+
+ /*
+ * Initialize the PAL
+ */
+ if (0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ for (i=0; i<sizeof(testCases)/sizeof(struct testCase); i++)
+ {
+ ptr = strstr(testCases[i].string1,testCases[i].string2);
+ if (ptr==NULL)
+ {
+ if (testCases[i].result != NULL)
+ {
+ Fail("ERROR: strstr returned incorrect value\n"
+ "Expected a pointer to \"%s\" , got a pointer to NULL\n",
+ testCases[i].result);
+ }
+ }
+ else
+ {
+ if (strcmp(testCases[i].result,ptr) != 0)
+ {
+ Fail("ERROR: strstr returned incorrect value\n"
+ "Expected a pointer to \"%s\" , got a pointer to \"%s\"\n",
+ testCases[i].result, ptr);
+ }
+ }
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/strstr/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/strstr/test1/testinfo.dat
new file mode 100644
index 0000000000..cf13170af5
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/strstr/test1/testinfo.dat
@@ -0,0 +1,16 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = strstr
+Name = Positive Test for strstr
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Check three cases of searching for a string within a string. First when
+= the string is contained, check that the pointer returned points to it.
+= Then when it isn't contained, ensure it returns null. And when the string
+= we're searching for is empty, it should return a pointer to the string
+= we're searching through.
diff --git a/src/pal/tests/palsuite/c_runtime/strtod/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/strtod/CMakeLists.txt
new file mode 100644
index 0000000000..ef14ea5352
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/strtod/CMakeLists.txt
@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+
diff --git a/src/pal/tests/palsuite/c_runtime/strtod/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/strtod/test1/CMakeLists.txt
new file mode 100644
index 0000000000..d3a9d61a4d
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/strtod/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_strtod_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_strtod_test1 coreclrpal)
+
+target_link_libraries(paltest_strtod_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/strtod/test1/test1.c b/src/pal/tests/palsuite/c_runtime/strtod/test1/test1.c
new file mode 100644
index 0000000000..e312d98f58
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/strtod/test1/test1.c
@@ -0,0 +1,93 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test1.c
+**
+** Purpose: Tests the PAL implementation of the strtod function.
+** Convert a number of strings to doubles. Ensure they
+** convert correctly.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+
+struct testCase
+{
+ double CorrectResult; /* The returned double value */
+ char ResultString[20]; /* The remainder string */
+ char string[20]; /* The test string */
+};
+
+
+int __cdecl main(int argc, char **argv)
+{
+
+ char * endptr;
+ double result;
+ int i;
+
+ struct testCase testCases[] =
+ {
+ {1234,"","1234"},
+ {-1234,"","-1234"},
+ {1234.44,"","1234.44"},
+ {1234e-5,"","1234e-5"},
+ {1234e+5,"","1234e+5"},
+ {12345E5,"","12345e5"},
+ {1234.657e-8,"","1234.657e-8"},
+ {1234567e-8,"foo","1234567e-8foo"},
+ {999,"foo","999 foo"},
+ {7,"foo"," 7foo"},
+ {0,"a7","a7"},
+ {-777777,"z zz","-777777z zz"}
+ };
+
+ /*
+ * Initialize the PAL
+ */
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ /* Loop through the structure to test each case */
+ for(i = 0; i < sizeof(testCases) / sizeof(struct testCase); i++)
+ {
+ result = strtod(testCases[i].string,&endptr);
+
+ /* need to check the result and the endptr result */
+ if ((testCases[i].CorrectResult != result) &&
+ (strcmp(testCases[i].ResultString,endptr)!=0))
+ {
+ Fail("ERROR: strtod returned %f instead of %f and "
+ "\"%s\" instead of \"%s\" for the test of \"%s\"\n",
+ result,
+ testCases[i].CorrectResult,
+ endptr,
+ testCases[i].ResultString,
+ testCases[i].string);
+ }
+
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/strtod/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/strtod/test1/testinfo.dat
new file mode 100644
index 0000000000..2c98d2eaf6
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/strtod/test1/testinfo.dat
@@ -0,0 +1,17 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = strtod
+Name = Positive Test for strtod
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Purpose: Tests the PAL implementation of the strtod function.
+= Convert a number of strings to doubles. Ensure they convert correctly.
+
+
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/strtod/test2/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/strtod/test2/CMakeLists.txt
new file mode 100644
index 0000000000..6f407c5914
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/strtod/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test2.c
+)
+
+add_executable(paltest_strtod_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_strtod_test2 coreclrpal)
+
+target_link_libraries(paltest_strtod_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/strtod/test2/test2.c b/src/pal/tests/palsuite/c_runtime/strtod/test2/test2.c
new file mode 100644
index 0000000000..0eaf4f53b6
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/strtod/test2/test2.c
@@ -0,0 +1,65 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test2.c
+**
+** Purpose: Tests strtod with overflows
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char **argv)
+{
+ /* Representation of positive infinty for a IEEE 64-bit double */
+ INT64 PosInifity = (INT64)(0x7ff00000) << 32;
+ double HugeVal = *(double*) &PosInifity;
+ char *PosStr = "1E+10000";
+ char *NegStr = "-1E+10000";
+ double result;
+
+
+ if (PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ result = strtod(PosStr, NULL);
+
+ if (result != HugeVal)
+ {
+ Fail("ERROR: wcstod interpreted \"%s\" as %g instead of %g\n",
+ PosStr, result, HugeVal);
+ }
+
+ result = strtod(NegStr, NULL);
+
+ if (result != -HugeVal)
+ {
+ Fail("ERROR: wcstod interpreted \"%s\" as %g instead of %g\n",
+ NegStr, result, -HugeVal);
+ }
+
+ PAL_Terminate();
+
+ return PASS;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/strtod/test2/testinfo.dat b/src/pal/tests/palsuite/c_runtime/strtod/test2/testinfo.dat
new file mode 100644
index 0000000000..a50c07b8b5
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/strtod/test2/testinfo.dat
@@ -0,0 +1,16 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = strtod
+Name = Negative test for strtod with overflows
+TYPE = DEFAULT
+EXE1 = test2
+Description
+= Test strtod with overflows.
+
+
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/strtok/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/strtok/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/strtok/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/strtok/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/strtok/test1/CMakeLists.txt
new file mode 100644
index 0000000000..1d5fc04cca
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/strtok/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_strtok_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_strtok_test1 coreclrpal)
+
+target_link_libraries(paltest_strtok_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/strtok/test1/test1.c b/src/pal/tests/palsuite/c_runtime/strtok/test1/test1.c
new file mode 100644
index 0000000000..f1dec70380
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/strtok/test1/test1.c
@@ -0,0 +1,78 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose:
+** Search for a number of tokens within strings. Check that the return values
+** are what is expect, and also that the strings match up with our expected
+** results.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ char str[] = "foo bar baz";
+ char *result1= "foo \0ar baz";
+ char *result2= "foo \0a\0 baz";
+ int len = strlen(str) + 1;
+ char *ptr;
+
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ ptr = strtok(str, "bz");
+ if (ptr != str)
+ {
+ Fail("Expected strtok() to return %p, got %p!\n", str, ptr);
+ }
+ if (memcmp(str, result1, len) != 0)
+ {
+ Fail("strtok altered the string in an unexpeced way!\n");
+ }
+
+ ptr = strtok(NULL, "r ");
+ if (ptr != str + 5)
+ {
+ Fail("Expected strtok() to return %p, got %p!\n", str+5, ptr);
+ }
+ if (memcmp(str, result2, len) != 0)
+ {
+ Fail("strtok altered the string in an unexpeced way!\n");
+ }
+
+
+ ptr = strtok(NULL, "X");
+ if (ptr != str + 7)
+ {
+ Fail("Expected strtok() to return %p, got %p!\n", str + 7, ptr);
+ }
+ if (memcmp(str, result2, len) != 0)
+ {
+ Fail("strtok altered the string in an unexpeced way!\n");
+ }
+
+ ptr = strtok(NULL, "X");
+ if (ptr != NULL)
+ {
+ Fail("Expected strtok() to return %p, got %p!\n", NULL, ptr);
+ }
+ if (memcmp(str, result2, len) != 0)
+ {
+ Fail("strtok altered the string in an unexpeced way!\n");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/strtok/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/strtok/test1/testinfo.dat
new file mode 100644
index 0000000000..f3773514c2
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/strtok/test1/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = strtok
+Name = Test #1 for strtok
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Search for a number of tokens within strings. Check that the return values
+= are what is expect, and also that the strings match up with our expected
+= results.
diff --git a/src/pal/tests/palsuite/c_runtime/strtoul/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/strtoul/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/strtoul/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/strtoul/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/strtoul/test1/CMakeLists.txt
new file mode 100644
index 0000000000..61dbd4f9a3
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/strtoul/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_strtoul_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_strtoul_test1 coreclrpal)
+
+target_link_libraries(paltest_strtoul_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/strtoul/test1/test1.c b/src/pal/tests/palsuite/c_runtime/strtoul/test1/test1.c
new file mode 100644
index 0000000000..344671b5cc
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/strtoul/test1/test1.c
@@ -0,0 +1,73 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose:
+** Tests stroul with different bases and overflows, as well as valid input.
+** Makes sure that the end pointer is correct.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+
+char teststr1[] = "12345";
+char teststr2[] = "Z";
+char teststr3[] = "4294967295";
+char teststr4[] = "4294967296";
+
+typedef struct
+{
+ char *str;
+ char *end;
+ int base;
+ ULONG result;
+} TestCase;
+
+TestCase TestCases[] =
+{
+ { teststr1, teststr1 + 3, 4, 27},
+ { teststr1, teststr1 + 5, 10, 12345},
+ { teststr2, teststr2, 10, 0},
+ { teststr3, teststr3+10, 10, 4294967295ul},
+ { teststr4, teststr4+10, 10, 4294967295ul}
+};
+
+int NumCases = sizeof(TestCases) / sizeof(TestCases[0]);
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ char *end;
+ ULONG l;
+ int i;
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ for (i=0; i<NumCases; i++)
+ {
+ l = strtoul(TestCases[i].str, &end, TestCases[i].base);
+
+ if (l != TestCases[i].result)
+ {
+ Fail("ERROR: Expected strtoul to return %u, got %u\n",
+ TestCases[i].result, l);
+ }
+
+ if (end != TestCases[i].end)
+ {
+ Fail("ERROR: Expected strtoul to give an end value of %p, got %p\n",
+ TestCases[i].end, end);
+ }
+ }
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/strtoul/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/strtoul/test1/testinfo.dat
new file mode 100644
index 0000000000..c7fc2c0c4d
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/strtoul/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = strtoul
+Name = Test #1 for strtoul
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Tests stroul with different bases and overflows, as well as valid input.
+= Makes sure that the end pointer is correct.
diff --git a/src/pal/tests/palsuite/c_runtime/swprintf/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/swprintf/CMakeLists.txt
new file mode 100644
index 0000000000..cafb9536b0
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swprintf/CMakeLists.txt
@@ -0,0 +1,22 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test10)
+add_subdirectory(test11)
+add_subdirectory(test12)
+add_subdirectory(test13)
+add_subdirectory(test14)
+add_subdirectory(test15)
+add_subdirectory(test16)
+add_subdirectory(test17)
+add_subdirectory(test18)
+add_subdirectory(test19)
+add_subdirectory(test2)
+add_subdirectory(test3)
+add_subdirectory(test4)
+add_subdirectory(test5)
+add_subdirectory(test6)
+add_subdirectory(test7)
+add_subdirectory(test8)
+add_subdirectory(test9)
+
diff --git a/src/pal/tests/palsuite/c_runtime/swprintf/swprintf.h b/src/pal/tests/palsuite/c_runtime/swprintf/swprintf.h
new file mode 100644
index 0000000000..5229506064
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swprintf/swprintf.h
@@ -0,0 +1,202 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: swprintf.h
+**
+** Purpose: Containts common testing functions for swprintf.h
+**
+**
+**==========================================================================*/
+
+#ifndef __SWPRINTF_H__
+#define __SWPRINTF_H__
+
+void DoWStrTest(WCHAR *formatstr, WCHAR *param, WCHAR *checkstr)
+{
+ WCHAR buf[256] = { 0 };
+
+ swprintf(buf, formatstr, param);
+
+ if (memcmp(buf, checkstr, wcslen(checkstr) * 2 + 2) != 0)
+ {
+ Fail("ERROR: failed to insert wide string \"%s\" into \"%s\".\n"
+ "Expected \"%s\", got \"%s\".\n",
+ convertC(param), convertC(formatstr),
+ convertC(checkstr), convertC(buf));
+ }
+}
+
+void DoStrTest(WCHAR *formatstr, char *param, WCHAR *checkstr)
+{
+ WCHAR buf[256] = { 0 };
+
+ swprintf(buf, formatstr, param);
+
+ if (memcmp(buf, checkstr, wcslen(checkstr) * 2 + 2) != 0)
+ {
+ Fail("ERROR: failed to insert wide string \"%s\" into \"%s\".\n"
+ "Expected \"%s\", got \"%s\".\n",
+ param, convertC(formatstr), convertC(checkstr),
+ convertC(buf));
+ }
+}
+
+void DoPointerTest(WCHAR *formatstr, void* param, WCHAR *checkstr1)
+{
+ WCHAR buf[256] = { 0 };
+
+ swprintf(buf, formatstr, param);
+ if (memcmp(buf, checkstr1, wcslen(checkstr1)*2 + 2) != 0)
+ {
+ Fail("ERROR: failed to insert pointer to %#p into \"%s\"\n"
+ "Expected \"%s\", got \"%s\".\n", param,
+ convertC(formatstr), convertC(checkstr1), convertC(buf));
+ }
+}
+
+void DoCountTest(WCHAR *formatstr, int param, WCHAR *checkstr)
+{
+ WCHAR buf[512] = { 0 };
+ int n = -1;
+
+ swprintf(buf, formatstr, &n);
+
+ if (n != param)
+ {
+ Fail("ERROR: Expected count parameter to resolve to %d, got %d\n",
+ param, n);
+ }
+
+ if (memcmp(buf, checkstr, wcslen(checkstr)*2 + 2) != 0)
+ {
+ Fail("ERROR: Expected \"%s\" got \"%s\".\n",
+ convertC(checkstr), convertC(buf));
+ }
+}
+
+void DoShortCountTest(WCHAR *formatstr, int param, WCHAR *checkstr)
+{
+ WCHAR buf[256] = { 0 };
+ short int n = -1;
+
+ swprintf(buf, formatstr, &n);
+
+ if (n != param)
+ {
+ Fail("ERROR: Expected count parameter to resolve to %d, got %d\n",
+ param, n);
+ }
+
+ if (memcmp(buf, checkstr, wcslen(checkstr)*2 + 2) != 0)
+ {
+ Fail("ERROR: Expected \"%s\" got \"%s\".\n",
+ convertC(checkstr), convertC(buf));
+ }
+}
+
+void DoCharTest(WCHAR *formatstr, char param, WCHAR *checkstr)
+{
+ WCHAR buf[256] = { 0 };
+
+ swprintf(buf, formatstr, param);
+ if (memcmp(buf, checkstr, wcslen(checkstr)*2 + 2) != 0)
+ {
+ Fail("ERROR: failed to insert char \'%c\' (%d) into \"%s\"\n"
+ "Expected \"%s\" got \"%s\".\n", param, param,
+ convertC(formatstr), convertC(checkstr), convertC(buf));
+ }
+}
+
+void DoWCharTest(WCHAR *formatstr, WCHAR param, WCHAR *checkstr)
+{
+ WCHAR buf[256] = { 0 };
+
+ swprintf(buf, formatstr, param);
+ if (memcmp(buf, checkstr, wcslen(checkstr)*2 + 2) != 0)
+ {
+ Fail("ERROR: failed to insert wide char \'%c\' (%d) into \"%s\"\n"
+ "Expected \"%s\" got \"%s\".\n", (char) param, param,
+ convertC(formatstr), convertC(checkstr), convertC(buf));
+ }
+}
+
+void DoNumTest(WCHAR *formatstr, int value, WCHAR*checkstr)
+{
+ WCHAR buf[256] = { 0 };
+
+ swprintf(buf, formatstr, value);
+ if (memcmp(buf, checkstr, wcslen(checkstr)* 2 + 2) != 0)
+ {
+ Fail("ERROR: failed to insert %#x into \"%s\"\n"
+ "Expected \"%s\" got \"%s\".\n", value, convertC(formatstr),
+ convertC(checkstr), convertC(buf));
+ }
+}
+
+void DoI64Test(WCHAR *formatstr, INT64 param, char *paramdesc,
+ WCHAR *checkstr1)
+{
+ WCHAR buf[256] = { 0 };
+
+ swprintf(buf, formatstr, param);
+ if (memcmp(buf, checkstr1, wcslen(checkstr1)*2 + 2) != 0)
+ {
+ Fail("ERROR: failed to insert %s into \"%s\"\n"
+ "Expected \"%s\", got \"%s\".\n", paramdesc,
+ convertC(formatstr), convertC(checkstr1), convertC(buf));
+ }
+}
+
+void DoDoubleTest(WCHAR *formatstr, double value, WCHAR *checkstr1,
+ WCHAR *checkstr2)
+{
+ WCHAR buf[256] = { 0 };
+
+ swprintf(buf, formatstr, value);
+ if (memcmp(buf, checkstr1, wcslen(checkstr1)*2 + 2) != 0 &&
+ memcmp(buf, checkstr2, wcslen(checkstr2)*2 + 2) != 0)
+ {
+ Fail("ERROR: failed to insert %f into \"%s\"\n"
+ "Expected \"%s\" or \"%s\", got \"%s\".\n",
+ value, convertC(formatstr), convertC(checkstr1),
+ convertC(checkstr2), convertC(buf));
+ }
+}
+
+void DoArgumentPrecTest(WCHAR *formatstr, int precision, void *param,
+ char *paramstr, WCHAR *checkstr1, WCHAR *checkstr2)
+{
+ WCHAR buf[256];
+
+ swprintf(buf, formatstr, precision, param);
+ if (memcmp(buf, checkstr1, wcslen(checkstr1) + 2) != 0 &&
+ memcmp(buf, checkstr2, wcslen(checkstr2) + 2) != 0)
+ {
+ Fail("ERROR: failed to insert %s into \"%s\" with precision %d\n"
+ "Expected \"%s\" or \"%s\", got \"%s\".\n", paramstr,
+ convertC(formatstr), precision,
+ convertC(checkstr1), convertC(checkstr2), convertC(buf));
+ }
+}
+
+void DoArgumentPrecDoubleTest(WCHAR *formatstr, int precision, double param,
+ WCHAR *checkstr1, WCHAR *checkstr2)
+{
+ WCHAR buf[256];
+
+ swprintf(buf, formatstr, precision, param);
+ if (memcmp(buf, checkstr1, wcslen(checkstr1) + 2) != 0 &&
+ memcmp(buf, checkstr2, wcslen(checkstr2) + 2) != 0)
+ {
+ Fail("ERROR: failed to insert %f into \"%s\" with precision %d\n"
+ "Expected \"%s\" or \"%s\", got \"%s\".\n", param,
+ convertC(formatstr), precision,
+ convertC(checkstr1), convertC(checkstr2), convertC(buf));
+ }
+}
+
+#endif
+
diff --git a/src/pal/tests/palsuite/c_runtime/swprintf/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/swprintf/test1/CMakeLists.txt
new file mode 100644
index 0000000000..fcf816029e
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swprintf/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_swprintf_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_swprintf_test1 coreclrpal)
+
+target_link_libraries(paltest_swprintf_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/swprintf/test1/test1.c b/src/pal/tests/palsuite/c_runtime/swprintf/test1/test1.c
new file mode 100644
index 0000000000..626040d9f7
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swprintf/test1/test1.c
@@ -0,0 +1,44 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose: General test to see if swprintf works correctly
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../swprintf.h"
+
+/*
+ * Uses memcmp & wcslen
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ WCHAR *checkstr;
+ WCHAR buf[256];
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+ checkstr = convert("hello world");
+ swprintf(buf, convert("hello world"));
+
+ if (memcmp(checkstr, buf, wcslen(checkstr)*2+2) != 0)
+ {
+ Fail("ERROR: Expected \"%s\", got \"%s\".\n", "hello world",
+ convertC(buf));
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/swprintf/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/swprintf/test1/testinfo.dat
new file mode 100644
index 0000000000..f43d462daf
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swprintf/test1/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = swprintf
+Name = Positive Test for swprintf
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= General test to see if swprintf works correctly
diff --git a/src/pal/tests/palsuite/c_runtime/swprintf/test10/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/swprintf/test10/CMakeLists.txt
new file mode 100644
index 0000000000..302c5e5923
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swprintf/test10/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test10.c
+)
+
+add_executable(paltest_swprintf_test10
+ ${SOURCES}
+)
+
+add_dependencies(paltest_swprintf_test10 coreclrpal)
+
+target_link_libraries(paltest_swprintf_test10
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/swprintf/test10/test10.c b/src/pal/tests/palsuite/c_runtime/swprintf/test10/test10.c
new file mode 100644
index 0000000000..61aef593a0
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swprintf/test10/test10.c
@@ -0,0 +1,55 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test10.c
+**
+** Purpose:Tests swprintf with octal numbers
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../swprintf.h"
+
+/*
+ * Uses memcmp & wcslen
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ int neg = -42;
+ int pos = 42;
+ INT64 l = 42;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+
+ DoNumTest(convert("foo %o"), pos, convert("foo 52"));
+ DoNumTest(convert("foo %lo"), 0xFFFF, convert("foo 177777"));
+ DoNumTest(convert("foo %ho"), 0xFFFF, convert("foo 177777"));
+ DoNumTest(convert("foo %Lo"), pos, convert("foo 52"));
+ DoI64Test(convert("foo %I64o"), l, "0x0000000000000042",
+ convert("foo 52"));
+ DoNumTest(convert("foo %3o"), pos, convert("foo 52"));
+ DoNumTest(convert("foo %-3o"), pos, convert("foo 52 "));
+ DoNumTest(convert("foo %.1o"), pos, convert("foo 52"));
+ DoNumTest(convert("foo %.3o"), pos, convert("foo 052"));
+ DoNumTest(convert("foo %03o"), pos, convert("foo 052"));
+ DoNumTest(convert("foo %#o"), pos, convert("foo 052"));
+ DoNumTest(convert("foo %+o"), pos, convert("foo 52"));
+ DoNumTest(convert("foo % o"), pos, convert("foo 52"));
+ DoNumTest(convert("foo %+o"), neg, convert("foo 37777777726"));
+ DoNumTest(convert("foo % o"), neg, convert("foo 37777777726"));
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/swprintf/test10/testinfo.dat b/src/pal/tests/palsuite/c_runtime/swprintf/test10/testinfo.dat
new file mode 100644
index 0000000000..e860bb26e7
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swprintf/test10/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = swprintf
+Name = Positive Test for swprintf
+TYPE = DEFAULT
+EXE1 = test10
+Description
+= Tests swprintf with octal numbers
diff --git a/src/pal/tests/palsuite/c_runtime/swprintf/test11/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/swprintf/test11/CMakeLists.txt
new file mode 100644
index 0000000000..484d57ef58
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swprintf/test11/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test11.c
+)
+
+add_executable(paltest_swprintf_test11
+ ${SOURCES}
+)
+
+add_dependencies(paltest_swprintf_test11 coreclrpal)
+
+target_link_libraries(paltest_swprintf_test11
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/swprintf/test11/test11.c b/src/pal/tests/palsuite/c_runtime/swprintf/test11/test11.c
new file mode 100644
index 0000000000..216f9acdbb
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swprintf/test11/test11.c
@@ -0,0 +1,55 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test11.c
+**
+** Purpose: Tests swprintf with unsigned numbers
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../swprintf.h"
+
+/*
+ * Uses memcmp & wcslen
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ int neg = -42;
+ int pos = 42;
+ INT64 l = 42;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+
+ DoNumTest(convert("foo %u"), pos, convert("foo 42"));
+ DoNumTest(convert("foo %lu"), 0xFFFF, convert("foo 65535"));
+ DoNumTest(convert("foo %hu"), 0xFFFF, convert("foo 65535"));
+ DoNumTest(convert("foo %Lu"), pos, convert("foo 42"));
+ DoI64Test(convert("foo %I64u"), l, "0x0000000000000042",
+ convert("foo 42"));
+ DoNumTest(convert("foo %3u"), pos, convert("foo 42"));
+ DoNumTest(convert("foo %-3u"), pos, convert("foo 42 "));
+ DoNumTest(convert("foo %.1u"), pos, convert("foo 42"));
+ DoNumTest(convert("foo %.3u"), pos, convert("foo 042"));
+ DoNumTest(convert("foo %03u"), pos, convert("foo 042"));
+ DoNumTest(convert("foo %#u"), pos, convert("foo 42"));
+ DoNumTest(convert("foo %+u"), pos, convert("foo 42"));
+ DoNumTest(convert("foo % u"), pos, convert("foo 42"));
+ DoNumTest(convert("foo %+u"), neg, convert("foo 4294967254"));
+ DoNumTest(convert("foo % u"), neg, convert("foo 4294967254"));
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/swprintf/test11/testinfo.dat b/src/pal/tests/palsuite/c_runtime/swprintf/test11/testinfo.dat
new file mode 100644
index 0000000000..430a777e7a
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swprintf/test11/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = swprintf
+Name = Positive Test for swprintf
+TYPE = DEFAULT
+EXE1 = test11
+Description
+= Tests swprintf with unsigned numbers
diff --git a/src/pal/tests/palsuite/c_runtime/swprintf/test12/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/swprintf/test12/CMakeLists.txt
new file mode 100644
index 0000000000..6d45ee4646
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swprintf/test12/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test12.c
+)
+
+add_executable(paltest_swprintf_test12
+ ${SOURCES}
+)
+
+add_dependencies(paltest_swprintf_test12 coreclrpal)
+
+target_link_libraries(paltest_swprintf_test12
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/swprintf/test12/test12.c b/src/pal/tests/palsuite/c_runtime/swprintf/test12/test12.c
new file mode 100644
index 0000000000..a41b0ddbd3
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swprintf/test12/test12.c
@@ -0,0 +1,56 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test12.c
+**
+** Purpose: Tests swprintf with hex numbers (lowercase)
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../swprintf.h"
+
+/*
+ * Uses memcmp & wcslen
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ int neg = -42;
+ int pos = 0x1234ab;
+ INT64 l = I64(0x1234567887654321);
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+
+ DoNumTest(convert("foo %x"), pos, convert("foo 1234ab"));
+ DoNumTest(convert("foo %lx"), pos, convert("foo 1234ab"));
+ DoNumTest(convert("foo %hx"), pos, convert("foo 34ab"));
+ DoNumTest(convert("foo %Lx"), pos, convert("foo 1234ab"));
+ DoI64Test(convert("foo %I64x"), l, "0x1234567887654321",
+ convert("foo 1234567887654321"));
+ DoNumTest(convert("foo %7x"), pos, convert("foo 1234ab"));
+ DoNumTest(convert("foo %-7x"), pos, convert("foo 1234ab "));
+ DoNumTest(convert("foo %.1x"), pos, convert("foo 1234ab"));
+ DoNumTest(convert("foo %.7x"), pos, convert("foo 01234ab"));
+ DoNumTest(convert("foo %07x"), pos, convert("foo 01234ab"));
+ DoNumTest(convert("foo %#x"), pos, convert("foo 0x1234ab"));
+ DoNumTest(convert("foo %+x"), pos, convert("foo 1234ab"));
+ DoNumTest(convert("foo % x"), pos, convert("foo 1234ab"));
+ DoNumTest(convert("foo %+x"), neg, convert("foo ffffffd6"));
+ DoNumTest(convert("foo % x"), neg, convert("foo ffffffd6"));
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/swprintf/test12/testinfo.dat b/src/pal/tests/palsuite/c_runtime/swprintf/test12/testinfo.dat
new file mode 100644
index 0000000000..d53582644f
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swprintf/test12/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = swprintf
+Name = Positive Test for swprintf
+TYPE = DEFAULT
+EXE1 = test12
+Description
+= Tests swprintf with hex numbers (lowercase)
diff --git a/src/pal/tests/palsuite/c_runtime/swprintf/test13/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/swprintf/test13/CMakeLists.txt
new file mode 100644
index 0000000000..20f6f0df7b
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swprintf/test13/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test13.c
+)
+
+add_executable(paltest_swprintf_test13
+ ${SOURCES}
+)
+
+add_dependencies(paltest_swprintf_test13 coreclrpal)
+
+target_link_libraries(paltest_swprintf_test13
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/swprintf/test13/test13.c b/src/pal/tests/palsuite/c_runtime/swprintf/test13/test13.c
new file mode 100644
index 0000000000..b99232f7ea
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swprintf/test13/test13.c
@@ -0,0 +1,55 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test13.c
+**
+** Purpose: Tests swprintf with hex numbers (uppercase)
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../swprintf.h"
+
+/*
+ * Uses memcmp & wcslen
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ int neg = -42;
+ int pos = 0x1234ab;
+ INT64 l = I64(0x1234567887654321);
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+
+ DoNumTest(convert("foo %X"), pos, convert("foo 1234AB"));
+ DoNumTest(convert("foo %lX"), pos, convert("foo 1234AB"));
+ DoNumTest(convert("foo %hX"), pos, convert("foo 34AB"));
+ DoNumTest(convert("foo %LX"), pos, convert("foo 1234AB"));
+ DoI64Test(convert("foo %I64X"), l, "0X1234567887654321",
+ convert("foo 1234567887654321"));
+ DoNumTest(convert("foo %7X"), pos, convert("foo 1234AB"));
+ DoNumTest(convert("foo %-7X"), pos, convert("foo 1234AB "));
+ DoNumTest(convert("foo %.1X"), pos, convert("foo 1234AB"));
+ DoNumTest(convert("foo %.7X"), pos, convert("foo 01234AB"));
+ DoNumTest(convert("foo %07X"), pos, convert("foo 01234AB"));
+ DoNumTest(convert("foo %#X"), pos, convert("foo 0X1234AB"));
+ DoNumTest(convert("foo %+X"), pos, convert("foo 1234AB"));
+ DoNumTest(convert("foo % X"), pos, convert("foo 1234AB"));
+ DoNumTest(convert("foo %+X"), neg, convert("foo FFFFFFD6"));
+ DoNumTest(convert("foo % X"), neg, convert("foo FFFFFFD6"));
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/swprintf/test13/testinfo.dat b/src/pal/tests/palsuite/c_runtime/swprintf/test13/testinfo.dat
new file mode 100644
index 0000000000..1ce172414c
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swprintf/test13/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = swprintf
+Name = Positive Test for swprintf
+TYPE = DEFAULT
+EXE1 = test13
+Description
+= Tests swprintf with hex numbers (uppercase)
diff --git a/src/pal/tests/palsuite/c_runtime/swprintf/test14/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/swprintf/test14/CMakeLists.txt
new file mode 100644
index 0000000000..a052f60116
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swprintf/test14/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test14.c
+)
+
+add_executable(paltest_swprintf_test14
+ ${SOURCES}
+)
+
+add_dependencies(paltest_swprintf_test14 coreclrpal)
+
+target_link_libraries(paltest_swprintf_test14
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/swprintf/test14/test14.c b/src/pal/tests/palsuite/c_runtime/swprintf/test14/test14.c
new file mode 100644
index 0000000000..bcfd6a7c24
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swprintf/test14/test14.c
@@ -0,0 +1,67 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test14.c
+**
+** Purpose: Tests swprintf with exponential format doubles (lowercase)
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../swprintf.h"
+
+/*
+ * Uses memcmp & wcslen
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ double val = 256.0;
+ double neg = -256.0;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+
+ DoDoubleTest(convert("foo %e"), val, convert("foo 2.560000e+002"),
+ convert("foo 2.560000e+02"));
+ DoDoubleTest(convert("foo %le"), val, convert("foo 2.560000e+002"),
+ convert("foo 2.560000e+02"));
+ DoDoubleTest(convert("foo %he"), val, convert("foo 2.560000e+002"),
+ convert("foo 2.560000e+02"));
+ DoDoubleTest(convert("foo %Le"), val, convert("foo 2.560000e+002"),
+ convert("foo 2.560000e+02"));
+ DoDoubleTest(convert("foo %I64e"), val, convert("foo 2.560000e+002"),
+ convert("foo 2.560000e+02"));
+ DoDoubleTest(convert("foo %14e"), val, convert("foo 2.560000e+002"),
+ convert("foo 2.560000e+02"));
+ DoDoubleTest(convert("foo %-14e"), val, convert("foo 2.560000e+002 "),
+ convert("foo 2.560000e+02 "));
+ DoDoubleTest(convert("foo %.1e"), val, convert("foo 2.6e+002"),
+ convert("foo 2.6e+02"));
+ DoDoubleTest(convert("foo %.8e"), val, convert("foo 2.56000000e+002"),
+ convert("foo 2.56000000e+02"));
+ DoDoubleTest(convert("foo %014e"), val, convert("foo 02.560000e+002"),
+ convert("foo 002.560000e+02"));
+ DoDoubleTest(convert("foo %#e"), val, convert("foo 2.560000e+002"),
+ convert("foo 2.560000e+02"));
+ DoDoubleTest(convert("foo %+e"), val, convert("foo +2.560000e+002"),
+ convert("foo +2.560000e+02"));
+ DoDoubleTest(convert("foo % e"), val, convert("foo 2.560000e+002"),
+ convert("foo 2.560000e+02"));
+ DoDoubleTest(convert("foo %+e"), neg, convert("foo -2.560000e+002"),
+ convert("foo -2.560000e+02"));
+ DoDoubleTest(convert("foo % e"), neg, convert("foo -2.560000e+002"),
+ convert("foo -2.560000e+02"));
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/swprintf/test14/testinfo.dat b/src/pal/tests/palsuite/c_runtime/swprintf/test14/testinfo.dat
new file mode 100644
index 0000000000..7f3451820b
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swprintf/test14/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = swprintf
+Name = Positive Test for swprintf
+TYPE = DEFAULT
+EXE1 = test14
+Description
+= Tests swprintf with exponential format doubles (lowercase)
diff --git a/src/pal/tests/palsuite/c_runtime/swprintf/test15/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/swprintf/test15/CMakeLists.txt
new file mode 100644
index 0000000000..7bc2da122f
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swprintf/test15/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test15.c
+)
+
+add_executable(paltest_swprintf_test15
+ ${SOURCES}
+)
+
+add_dependencies(paltest_swprintf_test15 coreclrpal)
+
+target_link_libraries(paltest_swprintf_test15
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/swprintf/test15/test15.c b/src/pal/tests/palsuite/c_runtime/swprintf/test15/test15.c
new file mode 100644
index 0000000000..215afbe093
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swprintf/test15/test15.c
@@ -0,0 +1,67 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test15.c
+**
+** Purpose:Tests swprintf with exponential format doubles (uppercase)
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../swprintf.h"
+
+/*
+ * Uses memcmp & wcslen
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ double val = 256.0;
+ double neg = -256.0;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+
+ DoDoubleTest(convert("foo %E"), val, convert("foo 2.560000E+002"),
+ convert("foo 2.560000E+02"));
+ DoDoubleTest(convert("foo %lE"), val, convert("foo 2.560000E+002"),
+ convert("foo 2.560000E+02"));
+ DoDoubleTest(convert("foo %hE"), val, convert("foo 2.560000E+002"),
+ convert("foo 2.560000E+02"));
+ DoDoubleTest(convert("foo %LE"), val, convert("foo 2.560000E+002"),
+ convert("foo 2.560000E+02"));
+ DoDoubleTest(convert("foo %I64E"), val, convert("foo 2.560000E+002"),
+ convert("foo 2.560000E+02"));
+ DoDoubleTest(convert("foo %14E"), val, convert("foo 2.560000E+002"),
+ convert("foo 2.560000E+02"));
+ DoDoubleTest(convert("foo %-14E"), val, convert("foo 2.560000E+002 "),
+ convert("foo 2.560000E+02 "));
+ DoDoubleTest(convert("foo %.1E"), val, convert("foo 2.6E+002"),
+ convert("foo 2.6E+02"));
+ DoDoubleTest(convert("foo %.8E"), val, convert("foo 2.56000000E+002"),
+ convert("foo 2.56000000E+02"));
+ DoDoubleTest(convert("foo %014E"), val, convert("foo 02.560000E+002"),
+ convert("foo 002.560000E+02"));
+ DoDoubleTest(convert("foo %#E"), val, convert("foo 2.560000E+002"),
+ convert("foo 2.560000E+02"));
+ DoDoubleTest(convert("foo %+E"), val, convert("foo +2.560000E+002"),
+ convert("foo +2.560000E+02"));
+ DoDoubleTest(convert("foo % E"), val, convert("foo 2.560000E+002"),
+ convert("foo 2.560000E+02"));
+ DoDoubleTest(convert("foo %+E"), neg, convert("foo -2.560000E+002"),
+ convert("foo -2.560000E+02"));
+ DoDoubleTest(convert("foo % E"), neg, convert("foo -2.560000E+002"),
+ convert("foo -2.560000E+02"));
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/swprintf/test15/testinfo.dat b/src/pal/tests/palsuite/c_runtime/swprintf/test15/testinfo.dat
new file mode 100644
index 0000000000..a6044e7bcc
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swprintf/test15/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = swprintf
+Name = Positive Test for swprintf
+TYPE = DEFAULT
+EXE1 = test15
+Description
+= Tests swprintf with exponential format doubles (uppercase)
diff --git a/src/pal/tests/palsuite/c_runtime/swprintf/test16/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/swprintf/test16/CMakeLists.txt
new file mode 100644
index 0000000000..e6ad3abd3f
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swprintf/test16/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test16.c
+)
+
+add_executable(paltest_swprintf_test16
+ ${SOURCES}
+)
+
+add_dependencies(paltest_swprintf_test16 coreclrpal)
+
+target_link_libraries(paltest_swprintf_test16
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/swprintf/test16/test16.c b/src/pal/tests/palsuite/c_runtime/swprintf/test16/test16.c
new file mode 100644
index 0000000000..859afed8dd
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swprintf/test16/test16.c
@@ -0,0 +1,67 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test16.c
+**
+** Purpose:Tests swprintf with decimal point format doubles
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../swprintf.h"
+
+/*
+ * Uses memcmp & wcslen
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ double val = 2560.001;
+ double neg = -2560.001;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+
+ DoDoubleTest(convert("foo %f"), val, convert("foo 2560.001000"),
+ convert("foo 2560.001000"));
+ DoDoubleTest(convert("foo %lf"), val, convert("foo 2560.001000"),
+ convert("foo 2560.001000"));
+ DoDoubleTest(convert("foo %hf"), val, convert("foo 2560.001000"),
+ convert("foo 2560.001000"));
+ DoDoubleTest(convert("foo %Lf"), val, convert("foo 2560.001000"),
+ convert("foo 2560.001000"));
+ DoDoubleTest(convert("foo %I64f"), val, convert("foo 2560.001000"),
+ convert("foo 2560.001000"));
+ DoDoubleTest(convert("foo %12f"), val, convert("foo 2560.001000"),
+ convert("foo 2560.001000"));
+ DoDoubleTest(convert("foo %-12f"), val, convert("foo 2560.001000 "),
+ convert("foo 2560.001000 "));
+ DoDoubleTest(convert("foo %.1f"), val, convert("foo 2560.0"),
+ convert("foo 2560.0"));
+ DoDoubleTest(convert("foo %.8f"), val, convert("foo 2560.00100000"),
+ convert("foo 2560.00100000"));
+ DoDoubleTest(convert("foo %012f"), val, convert("foo 02560.001000"),
+ convert("foo 02560.001000"));
+ DoDoubleTest(convert("foo %#f"), val, convert("foo 2560.001000"),
+ convert("foo 2560.001000"));
+ DoDoubleTest(convert("foo %+f"), val, convert("foo +2560.001000"),
+ convert("foo +2560.001000"));
+ DoDoubleTest(convert("foo % f"), val, convert("foo 2560.001000"),
+ convert("foo 2560.001000"));
+ DoDoubleTest(convert("foo %+f"), neg, convert("foo -2560.001000"),
+ convert("foo -2560.001000"));
+ DoDoubleTest(convert("foo % f"), neg, convert("foo -2560.001000"),
+ convert("foo -2560.001000"));
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/swprintf/test16/testinfo.dat b/src/pal/tests/palsuite/c_runtime/swprintf/test16/testinfo.dat
new file mode 100644
index 0000000000..d2f9a125c4
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swprintf/test16/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = swprintf
+Name = Positive Test for swprintf
+TYPE = DEFAULT
+EXE1 = test16
+Description
+= Tests swprintf with decimal point format doubles
diff --git a/src/pal/tests/palsuite/c_runtime/swprintf/test17/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/swprintf/test17/CMakeLists.txt
new file mode 100644
index 0000000000..401285b740
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swprintf/test17/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test17.c
+)
+
+add_executable(paltest_swprintf_test17
+ ${SOURCES}
+)
+
+add_dependencies(paltest_swprintf_test17 coreclrpal)
+
+target_link_libraries(paltest_swprintf_test17
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/swprintf/test17/test17.c b/src/pal/tests/palsuite/c_runtime/swprintf/test17/test17.c
new file mode 100644
index 0000000000..480f2b2fe1
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swprintf/test17/test17.c
@@ -0,0 +1,69 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test17.c
+**
+** Purpose:Tests swprintf with compact format doubles (lowercase)
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../swprintf.h"
+
+/*
+ * Uses memcmp & wcslen
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ double val = 2560.001;
+ double neg = -2560.001;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+
+ DoDoubleTest(convert("foo %g"), val, convert("foo 2560"),
+ convert("foo 2560"));
+ DoDoubleTest(convert("foo %lg"), val, convert("foo 2560"),
+ convert("foo 2560"));
+ DoDoubleTest(convert("foo %hg"), val, convert("foo 2560"),
+ convert("foo 2560"));
+ DoDoubleTest(convert("foo %Lg"), val, convert("foo 2560"),
+ convert("foo 2560"));
+ DoDoubleTest(convert("foo %I64g"), val, convert("foo 2560"),
+ convert("foo 2560"));
+ DoDoubleTest(convert("foo %5g"), val, convert("foo 2560"),
+ convert("foo 2560"));
+ DoDoubleTest(convert("foo %-5g"), val, convert("foo 2560 "),
+ convert("foo 2560 "));
+ DoDoubleTest(convert("foo %.1g"), val, convert("foo 3e+003"),
+ convert("foo 3e+03"));
+ DoDoubleTest(convert("foo %.2g"), val, convert("foo 2.6e+003"),
+ convert("foo 2.6e+03"));
+ DoDoubleTest(convert("foo %.12g"), val, convert("foo 2560.001"),
+ convert("foo 2560.001"));
+ DoDoubleTest(convert("foo %06g"), val, convert("foo 002560"),
+ convert("foo 002560"));
+ DoDoubleTest(convert("foo %#g"), val, convert("foo 2560.00"),
+ convert("foo 2560.00"));
+ DoDoubleTest(convert("foo %+g"), val, convert("foo +2560"),
+ convert("foo +2560"));
+ DoDoubleTest(convert("foo % g"), val, convert("foo 2560"),
+ convert("foo 2560"));
+ DoDoubleTest(convert("foo %+g"), neg, convert("foo -2560"),
+ convert("foo -2560"));
+ DoDoubleTest(convert("foo % g"), neg, convert("foo -2560"),
+ convert("foo -2560"));
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/swprintf/test17/testinfo.dat b/src/pal/tests/palsuite/c_runtime/swprintf/test17/testinfo.dat
new file mode 100644
index 0000000000..f26029c659
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swprintf/test17/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = swprintf
+Name = Positive Test for swprintf
+TYPE = DEFAULT
+EXE1 = test17
+Description
+= Tests swprintf with compact format doubles (lowercase)
diff --git a/src/pal/tests/palsuite/c_runtime/swprintf/test18/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/swprintf/test18/CMakeLists.txt
new file mode 100644
index 0000000000..210ab2c7ec
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swprintf/test18/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test18.c
+)
+
+add_executable(paltest_swprintf_test18
+ ${SOURCES}
+)
+
+add_dependencies(paltest_swprintf_test18 coreclrpal)
+
+target_link_libraries(paltest_swprintf_test18
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/swprintf/test18/test18.c b/src/pal/tests/palsuite/c_runtime/swprintf/test18/test18.c
new file mode 100644
index 0000000000..1ed8cd00d8
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swprintf/test18/test18.c
@@ -0,0 +1,69 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test18.c
+**
+** Purpose: Tests swprintf with compact format doubles (uppercase)
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../swprintf.h"
+
+/*
+ * Uses memcmp & wcslen
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ double val = 2560.001;
+ double neg = -2560.001;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+
+ DoDoubleTest(convert("foo %G"), val, convert("foo 2560"),
+ convert("foo 2560"));
+ DoDoubleTest(convert("foo %lG"), val, convert("foo 2560"),
+ convert("foo 2560"));
+ DoDoubleTest(convert("foo %hG"), val, convert("foo 2560"),
+ convert("foo 2560"));
+ DoDoubleTest(convert("foo %LG"), val, convert("foo 2560"),
+ convert("foo 2560"));
+ DoDoubleTest(convert("foo %I64G"), val, convert("foo 2560"),
+ convert("foo 2560"));
+ DoDoubleTest(convert("foo %5G"), val, convert("foo 2560"),
+ convert("foo 2560"));
+ DoDoubleTest(convert("foo %-5G"), val, convert("foo 2560 "),
+ convert("foo 2560 "));
+ DoDoubleTest(convert("foo %.1G"), val, convert("foo 3E+003"),
+ convert("foo 3E+03"));
+ DoDoubleTest(convert("foo %.2G"), val, convert("foo 2.6E+003"),
+ convert("foo 2.6E+03"));
+ DoDoubleTest(convert("foo %.12G"), val, convert("foo 2560.001"),
+ convert("foo 2560.001"));
+ DoDoubleTest(convert("foo %06G"), val, convert("foo 002560"),
+ convert("foo 002560"));
+ DoDoubleTest(convert("foo %#G"), val, convert("foo 2560.00"),
+ convert("foo 2560.00"));
+ DoDoubleTest(convert("foo %+G"), val, convert("foo +2560"),
+ convert("foo +2560"));
+ DoDoubleTest(convert("foo % G"), val, convert("foo 2560"),
+ convert("foo 2560"));
+ DoDoubleTest(convert("foo %+G"), neg, convert("foo -2560"),
+ convert("foo -2560"));
+ DoDoubleTest(convert("foo % G"), neg, convert("foo -2560"),
+ convert("foo -2560"));
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/swprintf/test18/testinfo.dat b/src/pal/tests/palsuite/c_runtime/swprintf/test18/testinfo.dat
new file mode 100644
index 0000000000..6a8ca702ff
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swprintf/test18/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = swprintf
+Name = Positive Test for swprintf
+TYPE = DEFAULT
+EXE1 = test18
+Description
+= Tests swprintf with compact format doubles (uppercase)
diff --git a/src/pal/tests/palsuite/c_runtime/swprintf/test19/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/swprintf/test19/CMakeLists.txt
new file mode 100644
index 0000000000..b9d44a3031
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swprintf/test19/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test19.c
+)
+
+add_executable(paltest_swprintf_test19
+ ${SOURCES}
+)
+
+add_dependencies(paltest_swprintf_test19 coreclrpal)
+
+target_link_libraries(paltest_swprintf_test19
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/swprintf/test19/test19.c b/src/pal/tests/palsuite/c_runtime/swprintf/test19/test19.c
new file mode 100644
index 0000000000..5199cc3cd9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swprintf/test19/test19.c
@@ -0,0 +1,109 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test19.c
+**
+** Purpose: Tests swprintf with argument specified precision
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../swprintf.h"
+
+/*
+ * Uses memcmp & wcslen
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ int n = -1;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+ DoArgumentPrecTest(convert("%.*s"), 2, convert("bar"), "bar",
+ convert("ba"), convert("ba"));
+ DoArgumentPrecTest(convert("%.*S"), 2, "bar", "bar", convert("ba"),
+ convert("ba"));
+ DoArgumentPrecTest(convert("%.*n"), 3, &n, "pointer to int", convert(""),
+ convert(""));
+ if (n != 0)
+ {
+ Fail("ERROR: Expected count parameter to resolve to %d, got %X\n",
+ 0, n);
+ }
+
+ DoArgumentPrecTest(convert("%.*c"), 0, (void*)'a', "a", convert("a"),
+ convert("a"));
+ DoArgumentPrecTest(convert("%.*c"), 4, (void*)'a', "a", convert("a"),
+ convert("a"));
+ DoArgumentPrecTest(convert("%.*C"), 0, (void*)'a', "a", convert("a"),
+ convert("a"));
+ DoArgumentPrecTest(convert("%.*C"), 4, (void*)'a', "a", convert("a"),
+ convert("a"));
+ DoArgumentPrecTest(convert("%.*d"), 1, (void*)42, "42", convert("42"),
+ convert("42"));
+ DoArgumentPrecTest(convert("%.*d"), 3, (void*)42, "42", convert("042"),
+ convert("042"));
+ DoArgumentPrecTest(convert("%.*i"), 1, (void*)42, "42", convert("42"),
+ convert("42"));
+ DoArgumentPrecTest(convert("%.*i"), 3, (void*)42, "42", convert("042"),
+ convert("042"));
+ DoArgumentPrecTest(convert("%.*o"), 1, (void*)42, "42", convert("52"),
+ convert("52"));
+ DoArgumentPrecTest(convert("%.*o"), 3, (void*)42, "42", convert("052"),
+ convert("052"));
+ DoArgumentPrecTest(convert("%.*u"), 1, (void*)42, "42", convert("42"),
+ convert("42"));
+ DoArgumentPrecTest(convert("%.*u"), 3, (void*)42, "42", convert("042"),
+ convert("042"));
+ DoArgumentPrecTest(convert("%.*x"), 1, (void*)0x42, "0x42", convert("42"),
+ convert("42"));
+ DoArgumentPrecTest(convert("%.*x"), 3, (void*)0x42, "0x42", convert("042"),
+ convert("042"));
+ DoArgumentPrecTest(convert("%.*X"), 1, (void*)0x42, "0x42", convert("42"),
+ convert("42"));
+ DoArgumentPrecTest(convert("%.*X"), 3, (void*)0x42, "0x42", convert("042"),
+ convert("042"));
+
+
+ DoArgumentPrecDoubleTest(convert("%.*e"), 1, 2.01, convert("2.0e+000"),
+ convert("2.0e+000"));
+ DoArgumentPrecDoubleTest(convert("%.*e"), 3, 2.01, convert("2.010e+000"),
+ convert("2.010e+000"));
+ DoArgumentPrecDoubleTest(convert("%.*E"), 1, 2.01, convert("2.0E+000"),
+ convert("2.0E+000"));
+ DoArgumentPrecDoubleTest(convert("%.*E"), 3, 2.01, convert("2.010E+000"),
+ convert("2.010E+000"));
+ DoArgumentPrecDoubleTest(convert("%.*f"), 1, 2.01, convert("2.0"),
+ convert("2.0"));
+ DoArgumentPrecDoubleTest(convert("%.*f"), 3, 2.01, convert("2.010"),
+ convert("2.010"));
+ DoArgumentPrecDoubleTest(convert("%.*g"), 1, 256.01, convert("3e+002"),
+ convert("3e+002"));
+ DoArgumentPrecDoubleTest(convert("%.*g"), 3, 256.01, convert("256"),
+ convert("256"));
+ DoArgumentPrecDoubleTest(convert("%.*g"), 4, 256.01, convert("256"),
+ convert("256"));
+ DoArgumentPrecDoubleTest(convert("%.*g"), 6, 256.01, convert("256.01"),
+ convert("256.01"));
+ DoArgumentPrecDoubleTest(convert("%.*G"), 1, 256.01, convert("3E+002"),
+ convert("3E+002"));
+ DoArgumentPrecDoubleTest(convert("%.*G"), 3, 256.01, convert("256"),
+ convert("256"));
+ DoArgumentPrecDoubleTest(convert("%.*G"), 4, 256.01, convert("256"),
+ convert("256"));
+ DoArgumentPrecDoubleTest(convert("%.*G"), 6, 256.01, convert("256.01"),
+ convert("256.01"));
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/swprintf/test19/testinfo.dat b/src/pal/tests/palsuite/c_runtime/swprintf/test19/testinfo.dat
new file mode 100644
index 0000000000..cbd572a35c
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swprintf/test19/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = swprintf
+Name = Positive Test for swprintf
+TYPE = DEFAULT
+EXE1 = test19
+Description
+= Tests swprintf with argument specified precision
diff --git a/src/pal/tests/palsuite/c_runtime/swprintf/test2/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/swprintf/test2/CMakeLists.txt
new file mode 100644
index 0000000000..84446d5f6d
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swprintf/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test2.c
+)
+
+add_executable(paltest_swprintf_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_swprintf_test2 coreclrpal)
+
+target_link_libraries(paltest_swprintf_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/swprintf/test2/test2.c b/src/pal/tests/palsuite/c_runtime/swprintf/test2/test2.c
new file mode 100644
index 0000000000..deffd3edd7
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swprintf/test2/test2.c
@@ -0,0 +1,46 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test2.c
+**
+** Purpose: Tests swprintf with strings
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../swprintf.h"
+
+/*
+ * Uses memcmp & wcslen
+ */
+
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+ DoWStrTest(convert("foo %s"), convert("bar"), convert("foo bar"));
+ DoStrTest(convert("foo %hs"), "bar", convert("foo bar"));
+ DoWStrTest(convert("foo %ws"), convert("bar"), convert("foo bar"));
+ DoWStrTest(convert("foo %ls"), convert("bar"), convert("foo bar"));
+ DoWStrTest(convert("foo %Ls"), convert("bar"), convert("foo bar"));
+ DoWStrTest(convert("foo %I64s"), convert("bar"), convert("foo bar"));
+ DoWStrTest(convert("foo %5s"), convert("bar"), convert("foo bar"));
+ DoWStrTest(convert("foo %.2s"), convert("bar"), convert("foo ba"));
+ DoWStrTest(convert("foo %5.2s"), convert("bar"), convert("foo ba"));
+ DoWStrTest(convert("foo %-5s"), convert("bar"), convert("foo bar "));
+ DoWStrTest(convert("foo %05s"), convert("bar"), convert("foo 00bar"));
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/swprintf/test2/testinfo.dat b/src/pal/tests/palsuite/c_runtime/swprintf/test2/testinfo.dat
new file mode 100644
index 0000000000..d93fa7b400
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swprintf/test2/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = swprintf
+Name = Positive Test for swprintf
+TYPE = DEFAULT
+EXE1 = test2
+Description
+= Tests swprintf with strings
diff --git a/src/pal/tests/palsuite/c_runtime/swprintf/test3/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/swprintf/test3/CMakeLists.txt
new file mode 100644
index 0000000000..6dbd8a3c36
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swprintf/test3/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test3.c
+)
+
+add_executable(paltest_swprintf_test3
+ ${SOURCES}
+)
+
+add_dependencies(paltest_swprintf_test3 coreclrpal)
+
+target_link_libraries(paltest_swprintf_test3
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/swprintf/test3/test3.c b/src/pal/tests/palsuite/c_runtime/swprintf/test3/test3.c
new file mode 100644
index 0000000000..42875c0640
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swprintf/test3/test3.c
@@ -0,0 +1,43 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test3.c
+**
+** Purpose: Tests swprintf with wide strings
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../swprintf.h"
+
+/*
+ * Uses memcmp & wcslen
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+ DoStrTest(convert("foo %S"), "bar", convert("foo bar"));
+ DoStrTest(convert("foo %hS"), "bar", convert("foo bar"));
+ DoWStrTest(convert("foo %lS"), convert("bar"), convert("foo bar"));
+ DoWStrTest(convert("foo %wS"), convert("bar"), convert("foo bar"));
+ DoStrTest(convert("foo %LS"), "bar", convert("foo bar"));
+ DoStrTest(convert("foo %I64S"), "bar", convert("foo bar"));
+ DoStrTest(convert("foo %5S"), "bar", convert("foo bar"));
+ DoStrTest(convert("foo %.2S"), "bar", convert("foo ba"));
+ DoStrTest(convert("foo %5.2S"),"bar", convert("foo ba"));
+ DoStrTest(convert("foo %-5S"), "bar", convert("foo bar "));
+ DoStrTest(convert("foo %05S"), "bar", convert("foo 00bar"));
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/swprintf/test3/testinfo.dat b/src/pal/tests/palsuite/c_runtime/swprintf/test3/testinfo.dat
new file mode 100644
index 0000000000..923a8f0efd
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swprintf/test3/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = swprintf
+Name = Positive Test for swprintf
+TYPE = DEFAULT
+EXE1 = test3
+Description
+= Tests swprintf with wide strings
diff --git a/src/pal/tests/palsuite/c_runtime/swprintf/test4/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/swprintf/test4/CMakeLists.txt
new file mode 100644
index 0000000000..a665948c47
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swprintf/test4/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test4.c
+)
+
+add_executable(paltest_swprintf_test4
+ ${SOURCES}
+)
+
+add_dependencies(paltest_swprintf_test4 coreclrpal)
+
+target_link_libraries(paltest_swprintf_test4
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/swprintf/test4/test4.c b/src/pal/tests/palsuite/c_runtime/swprintf/test4/test4.c
new file mode 100644
index 0000000000..02cc3f9005
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swprintf/test4/test4.c
@@ -0,0 +1,71 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test4.c
+**
+** Purpose: Tests swprintf with pointers
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../swprintf.h"
+
+/*
+ * Uses memcmp & wcslen
+ */
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ void *ptr = (void*) 0x123456;
+ INT64 lptr = I64(0x1234567887654321);
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+/*
+** Run only on 64 bit platforms
+*/
+#if defined(BIT64) && defined(PLATFORM_UNIX)
+ Trace("Testing for 64 Bit Platforms \n");
+ DoPointerTest(convert("%p"), NULL, convert("0000000000000000"));
+ DoPointerTest(convert("%p"), ptr, convert("0000000000123456"));
+ DoPointerTest(convert("%17p"), ptr, convert(" 0000000000123456"));
+ DoPointerTest(convert("%17p"), ptr, convert(" 0000000000123456"));
+ DoPointerTest(convert("%-17p"), ptr, convert("0000000000123456 "));
+ DoPointerTest(convert("%+p"), ptr, convert("0000000000123456"));
+ DoPointerTest(convert("% p"), ptr, convert("0000000000123456"));
+ DoPointerTest(convert("%#p"), ptr, convert("0X0000000000123456"));
+ DoPointerTest(convert("%lp"), ptr, convert("00123456"));
+ DoPointerTest(convert("%hp"), ptr, convert("00003456"));
+ DoPointerTest(convert("%Lp"), ptr, convert("00123456"));
+ DoI64Test(convert("%I64p"), lptr, "pointer to 0X1234567887654321",
+ convert("1234567887654321"));
+#else
+ Trace("Testing for Non 64 Bit Platforms \n");
+ DoPointerTest(convert("%p"), NULL, convert("00000000"));
+ DoPointerTest(convert("%p"), ptr, convert("00123456"));
+ DoPointerTest(convert("%9p"), ptr, convert(" 00123456"));
+ DoPointerTest(convert("%09p"), ptr, convert(" 00123456"));
+ DoPointerTest(convert("%-9p"), ptr, convert("00123456 "));
+ DoPointerTest(convert("%+p"), ptr, convert("00123456"));
+ DoPointerTest(convert("% p"), ptr, convert("00123456"));
+ DoPointerTest(convert("%#p"), ptr, convert("0X00123456"));
+ DoPointerTest(convert("%lp"), ptr, convert("00123456"));
+ DoPointerTest(convert("%hp"), ptr, convert("00003456"));
+ DoPointerTest(convert("%Lp"), ptr, convert("00123456"));
+ DoI64Test(convert("%I64p"), lptr, "pointer to 0X1234567887654321",
+ convert("1234567887654321"));
+#endif
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/swprintf/test4/testinfo.dat b/src/pal/tests/palsuite/c_runtime/swprintf/test4/testinfo.dat
new file mode 100644
index 0000000000..dc481d32f1
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swprintf/test4/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = swprintf
+Name = Positive Test for swprintf
+TYPE = DEFAULT
+EXE1 = test4
+Description
+= Tests swprintf with pointers
diff --git a/src/pal/tests/palsuite/c_runtime/swprintf/test5/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/swprintf/test5/CMakeLists.txt
new file mode 100644
index 0000000000..8268ec2963
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swprintf/test5/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test5.c
+)
+
+add_executable(paltest_swprintf_test5
+ ${SOURCES}
+)
+
+add_dependencies(paltest_swprintf_test5 coreclrpal)
+
+target_link_libraries(paltest_swprintf_test5
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/swprintf/test5/test5.c b/src/pal/tests/palsuite/c_runtime/swprintf/test5/test5.c
new file mode 100644
index 0000000000..e85adc120e
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swprintf/test5/test5.c
@@ -0,0 +1,67 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test5.c
+**
+** Purpose:Tests swprintf with the count specifier
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../swprintf.h"
+
+/*
+ * Uses memcmp & wcslen
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ WCHAR *longStr;
+ WCHAR *longResult;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+ longStr =
+ convert("really-long-string-that-just-keeps-going-on-and-on-and-on.."
+ "..................useless-filler.................................."
+ "..................useless-filler.................................."
+ "..................useless-filler.................................."
+ "%n bar");
+ longResult =
+ convert("really-long-string-that-just-keeps-going-on-and-on-and-on.."
+ "..................useless-filler.................................."
+ "..................useless-filler.................................."
+ "..................useless-filler.................................."
+ " bar");
+
+ DoCountTest(convert("foo %n bar"), 4, convert("foo bar"));
+ DoCountTest(longStr, 257, longResult);
+ DoCountTest(convert("fo%n bar"), 2, convert("fo bar"));
+ DoCountTest(convert("%n"), 0, convert(""));
+ DoCountTest(convert("foo %#n bar"), 4, convert("foo bar"));
+ DoCountTest(convert("foo % n bar"), 4, convert("foo bar"));
+ DoCountTest(convert("foo %+n bar"), 4, convert("foo bar"));
+ DoCountTest(convert("foo %-n bar"), 4, convert("foo bar"));
+ DoCountTest(convert("foo %0n bar"), 4, convert("foo bar"));
+ DoShortCountTest(convert("foo %hn bar"), 4, convert("foo bar"));
+ DoCountTest(convert("foo %ln bar"), 4, convert("foo bar"));
+ DoCountTest(convert("foo %Ln bar"), 4, convert("foo bar"));
+ DoCountTest(convert("foo %I64n bar"), 4, convert("foo bar"));
+ DoCountTest(convert("foo %20.3n bar"), 4, convert("foo bar"));
+
+ PAL_Terminate();
+
+ free(longStr);
+ free(longResult);
+
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/swprintf/test5/testinfo.dat b/src/pal/tests/palsuite/c_runtime/swprintf/test5/testinfo.dat
new file mode 100644
index 0000000000..ef1f1ffc5a
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swprintf/test5/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = swprintf
+Name = Positive Test for swprintf
+TYPE = DEFAULT
+EXE1 = test5
+Description
+= Tests swprintf with the count specifier
diff --git a/src/pal/tests/palsuite/c_runtime/swprintf/test6/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/swprintf/test6/CMakeLists.txt
new file mode 100644
index 0000000000..6a90c0b88e
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swprintf/test6/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test6.c
+)
+
+add_executable(paltest_swprintf_test6
+ ${SOURCES}
+)
+
+add_dependencies(paltest_swprintf_test6 coreclrpal)
+
+target_link_libraries(paltest_swprintf_test6
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/swprintf/test6/test6.c b/src/pal/tests/palsuite/c_runtime/swprintf/test6/test6.c
new file mode 100644
index 0000000000..ecd6374264
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swprintf/test6/test6.c
@@ -0,0 +1,47 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test6.c
+**
+** Purpose: Tests swprintf with character
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../swprintf.h"
+
+/*
+ * Uses memcmp & wcslen
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ WCHAR wb = (WCHAR) 'b';
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+
+ DoWCharTest(convert("foo %c"), wb, convert("foo b"));
+ DoCharTest(convert("foo %hc"), 'c', convert("foo c"));
+ DoWCharTest(convert("foo %lc"), wb, convert("foo b"));
+ DoWCharTest(convert("foo %Lc"), wb, convert("foo b"));
+ DoWCharTest(convert("foo %I64c"), wb, convert("foo b"));
+ DoWCharTest(convert("foo %5c"), wb, convert("foo b"));
+ DoWCharTest(convert("foo %.0c"), wb, convert("foo b"));
+ DoWCharTest(convert("foo %-5c"), wb, convert("foo b "));
+ DoWCharTest(convert("foo %05c"), wb, convert("foo 0000b"));
+ DoWCharTest(convert("foo % c"), wb, convert("foo b"));
+ DoWCharTest(convert("foo %#c"), wb, convert("foo b"));
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/swprintf/test6/testinfo.dat b/src/pal/tests/palsuite/c_runtime/swprintf/test6/testinfo.dat
new file mode 100644
index 0000000000..4224d19519
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swprintf/test6/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = swprintf
+Name = Positive Test for swprintf
+TYPE = DEFAULT
+EXE1 = test6
+Description
+= Tests swprintf with characters
diff --git a/src/pal/tests/palsuite/c_runtime/swprintf/test7/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/swprintf/test7/CMakeLists.txt
new file mode 100644
index 0000000000..2b1c30cb56
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swprintf/test7/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test7.c
+)
+
+add_executable(paltest_swprintf_test7
+ ${SOURCES}
+)
+
+add_dependencies(paltest_swprintf_test7 coreclrpal)
+
+target_link_libraries(paltest_swprintf_test7
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/swprintf/test7/test7.c b/src/pal/tests/palsuite/c_runtime/swprintf/test7/test7.c
new file mode 100644
index 0000000000..e231ada3d2
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swprintf/test7/test7.c
@@ -0,0 +1,48 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test7.c
+**
+** Purpose: Tests swprintf with wide characters
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../swprintf.h"
+
+/*
+ * Uses memcmp & wcslen
+ */
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ WCHAR wb = (WCHAR) 'b';
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+
+ DoCharTest(convert("foo %C"), 'c', convert("foo c"));
+ DoWCharTest(convert("foo %hc"), wb, convert("foo b"));
+ DoCharTest(convert("foo %lC"), 'c', convert("foo c"));
+ DoCharTest(convert("foo %LC"), 'c', convert("foo c"));
+ DoCharTest(convert("foo %I64C"), 'c', convert("foo c"));
+ DoCharTest(convert("foo %5C"), 'c', convert("foo c"));
+ DoCharTest(convert("foo %.0C"), 'c', convert("foo c"));
+ DoCharTest(convert("foo %-5C"), 'c', convert("foo c "));
+ DoCharTest(convert("foo %05C"), 'c', convert("foo 0000c"));
+ DoCharTest(convert("foo % C"), 'c', convert("foo c"));
+ DoCharTest(convert("foo %#C"), 'c', convert("foo c"));
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/swprintf/test7/testinfo.dat b/src/pal/tests/palsuite/c_runtime/swprintf/test7/testinfo.dat
new file mode 100644
index 0000000000..7facc90b58
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swprintf/test7/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = swprintf
+Name = Positive Test for swprintf
+TYPE = DEFAULT
+EXE1 = test7
+Description
+= Tests swprintf with wide characters
diff --git a/src/pal/tests/palsuite/c_runtime/swprintf/test8/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/swprintf/test8/CMakeLists.txt
new file mode 100644
index 0000000000..281e6df097
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swprintf/test8/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test8.c
+)
+
+add_executable(paltest_swprintf_test8
+ ${SOURCES}
+)
+
+add_dependencies(paltest_swprintf_test8 coreclrpal)
+
+target_link_libraries(paltest_swprintf_test8
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/swprintf/test8/test8.c b/src/pal/tests/palsuite/c_runtime/swprintf/test8/test8.c
new file mode 100644
index 0000000000..b4be28e78d
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swprintf/test8/test8.c
@@ -0,0 +1,55 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test8.c
+**
+** Purpose: Tests swprintf with decimal numbers
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../swprintf.h"
+
+/*
+ * Uses memcmp & wcslen
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ int neg = -42;
+ int pos = 42;
+ INT64 l = 42;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+
+ DoNumTest(convert("foo %d"), pos, convert("foo 42"));
+ DoNumTest(convert("foo %ld"), 0xFFFF, convert("foo 65535"));
+ DoNumTest(convert("foo %hd"), 0xFFFF, convert("foo -1"));
+ DoNumTest(convert("foo %Ld"), pos, convert("foo 42"));
+ DoI64Test(convert("foo %I64d"), l, "0x0000000000000042",
+ convert("foo 42"));
+ DoNumTest(convert("foo %3d"), pos, convert("foo 42"));
+ DoNumTest(convert("foo %-3d"), pos, convert("foo 42 "));
+ DoNumTest(convert("foo %.1d"), pos, convert("foo 42"));
+ DoNumTest(convert("foo %.3d"), pos, convert("foo 042"));
+ DoNumTest(convert("foo %03d"), pos, convert("foo 042"));
+ DoNumTest(convert("foo %#d"), pos, convert("foo 42"));
+ DoNumTest(convert("foo %+d"), pos, convert("foo +42"));
+ DoNumTest(convert("foo % d"), pos, convert("foo 42"));
+ DoNumTest(convert("foo %+d"), neg, convert("foo -42"));
+ DoNumTest(convert("foo % d"), neg, convert("foo -42"));
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/swprintf/test8/testinfo.dat b/src/pal/tests/palsuite/c_runtime/swprintf/test8/testinfo.dat
new file mode 100644
index 0000000000..d5858b2cfe
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swprintf/test8/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = swprintf
+Name = Positive Test for swprintf
+TYPE = DEFAULT
+EXE1 = test8
+Description
+= Tests swprintf with decimal numbers
diff --git a/src/pal/tests/palsuite/c_runtime/swprintf/test9/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/swprintf/test9/CMakeLists.txt
new file mode 100644
index 0000000000..054b40a998
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swprintf/test9/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test9.c
+)
+
+add_executable(paltest_swprintf_test9
+ ${SOURCES}
+)
+
+add_dependencies(paltest_swprintf_test9 coreclrpal)
+
+target_link_libraries(paltest_swprintf_test9
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/swprintf/test9/test9.c b/src/pal/tests/palsuite/c_runtime/swprintf/test9/test9.c
new file mode 100644
index 0000000000..2f5429e5fd
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swprintf/test9/test9.c
@@ -0,0 +1,55 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test9.c
+**
+** Purpose: Tests swprintf with integer numbers
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../swprintf.h"
+
+/*
+ * Uses memcmp & wcslen
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ int neg = -42;
+ int pos = 42;
+ INT64 l = 42;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+
+ DoNumTest(convert("foo %i"), pos, convert("foo 42"));
+ DoNumTest(convert("foo %li"), 0xFFFF, convert("foo 65535"));
+ DoNumTest(convert("foo %hi"), 0xFFFF, convert("foo -1"));
+ DoNumTest(convert("foo %Li"), pos, convert("foo 42"));
+ DoI64Test(convert("foo %I64i"), l, "0x0000000000000042",
+ convert("foo 42"));
+ DoNumTest(convert("foo %3i"), pos, convert("foo 42"));
+ DoNumTest(convert("foo %-3i"), pos, convert("foo 42 "));
+ DoNumTest(convert("foo %.1i"), pos, convert("foo 42"));
+ DoNumTest(convert("foo %.3i"), pos, convert("foo 042"));
+ DoNumTest(convert("foo %03i"), pos, convert("foo 042"));
+ DoNumTest(convert("foo %#i"), pos, convert("foo 42"));
+ DoNumTest(convert("foo %+i"), pos, convert("foo +42"));
+ DoNumTest(convert("foo % i"), pos, convert("foo 42"));
+ DoNumTest(convert("foo %+i"), neg, convert("foo -42"));
+ DoNumTest(convert("foo % i"), neg, convert("foo -42"));
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/swprintf/test9/testinfo.dat b/src/pal/tests/palsuite/c_runtime/swprintf/test9/testinfo.dat
new file mode 100644
index 0000000000..7ef9eed134
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swprintf/test9/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = swprintf
+Name = Positive Test for swprintf
+TYPE = DEFAULT
+EXE1 = test9
+Description
+= Tests swprintf with integer numbers
diff --git a/src/pal/tests/palsuite/c_runtime/swscanf/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/swscanf/CMakeLists.txt
new file mode 100644
index 0000000000..59f39a5f58
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swscanf/CMakeLists.txt
@@ -0,0 +1,20 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test10)
+add_subdirectory(test11)
+add_subdirectory(test12)
+add_subdirectory(test13)
+add_subdirectory(test14)
+add_subdirectory(test15)
+add_subdirectory(test16)
+add_subdirectory(test17)
+add_subdirectory(test2)
+add_subdirectory(test3)
+add_subdirectory(test4)
+add_subdirectory(test5)
+add_subdirectory(test6)
+add_subdirectory(test7)
+add_subdirectory(test8)
+add_subdirectory(test9)
+
diff --git a/src/pal/tests/palsuite/c_runtime/swscanf/swscanf.h b/src/pal/tests/palsuite/c_runtime/swscanf/swscanf.h
new file mode 100644
index 0000000000..1cac450cf4
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swscanf/swscanf.h
@@ -0,0 +1,262 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: swscanf.h
+**
+** Purpose: Contains common testing functions for swscanf.h
+**
+**
+**==========================================================================*/
+
+#ifndef __SWSCANF_H__
+#define __SWSCANF_H__
+
+void DoVoidTest(WCHAR *inputstr, WCHAR *formatstr)
+{
+ char buf[256] = { 0 };
+ int i;
+ int ret;
+
+ ret = swscanf(inputstr, formatstr, buf);
+ if (ret != 0)
+ {
+ Fail("ERROR: Expected sscanf to return 0, got %d.\n"
+ "Using \"%s\" in \"%s\".\n", ret, convertC(inputstr),
+ convertC(formatstr));
+ }
+
+ for (i=0; i<256; i++)
+ {
+ if (buf[i] != 0)
+ {
+ Fail("ERROR: Parameter unexpectedly modified scanning \"%s\" "
+ "using \"%s\".\n", convertC(inputstr),
+ convertC(formatstr));
+ }
+ }
+
+}
+
+void DoStrTest(WCHAR *inputstr, WCHAR *formatstr, char *checkstr)
+{
+ char buf[256] = { 0 };
+ int ret;
+
+ ret = swscanf(inputstr, formatstr, buf);
+ if (ret != 1)
+ {
+ Fail("ERROR: Expected swscanf to return 1, got %d.\n"
+ "Using \"%s\" in \"%s\".\n", ret, convertC(inputstr),
+ convertC(formatstr));
+ }
+
+ if (memcmp(checkstr, buf, strlen(checkstr) + 1) != 0)
+ {
+ Fail("ERROR: scanned string incorrectly from \"%s\" using \"%s\".\n"
+ "Expected \"%s\", got \"%s\".\n", convertC(inputstr),
+ convertC(formatstr), checkstr,
+ buf);
+ }
+
+}
+
+void DoWStrTest(WCHAR *inputstr, WCHAR *formatstr, WCHAR *checkstr)
+{
+ WCHAR buf[256] = { 0 };
+ int ret;
+
+ ret = swscanf(inputstr, formatstr, buf);
+ if (ret != 1)
+ {
+ Fail("ERROR: Expected swscanf to return 1, got %d.\n"
+ "Using \"%s\" in \"%s\".\n", ret, convertC(inputstr),
+ convertC(formatstr));
+ }
+
+ if (memcmp(checkstr, buf, wcslen(checkstr)*2 + 2) != 0)
+ {
+ Fail("ERROR: scanned wide string incorrectly from \"%s\" using \"%s\".\n"
+ "Expected \"%s\", got \"%s\".\n", convertC(inputstr),
+ convertC(formatstr), convertC(checkstr),
+ convertC(buf));
+ }
+
+}
+
+void DoNumTest(WCHAR *inputstr, WCHAR *formatstr, int checknum)
+{
+ int num = 0;
+ int ret;
+
+ ret = swscanf(inputstr, formatstr, &num);
+ if (ret != 1)
+ {
+ Fail("ERROR: Expected swscanf to return 1, got %d.\n"
+ "Using \"%s\" in \"%s\".\n", ret, convertC(inputstr),
+ convertC(formatstr));
+ }
+
+ if (checknum != num)
+ {
+ Fail("ERROR: scanned number incorrectly from \"%s\" using \"%s\".\n"
+ "Expected %d, got %d.\n", convertC(inputstr),
+ convertC(formatstr), checknum, num);
+ }
+}
+
+void DoShortNumTest(WCHAR *inputstr, WCHAR *formatstr, short checknum)
+{
+ short num = 0;
+ int ret;
+
+ ret = swscanf(inputstr, formatstr, &num);
+ if (ret != 1)
+ {
+ Fail("ERROR: Expected swscanf to return 1, got %d.\n"
+ "Using \"%s\" in \"%s\".\n", ret, convertC(inputstr),
+ convertC(formatstr));
+ }
+
+ if (checknum != num)
+ {
+ Fail("ERROR: scanned number incorrectly from \"%s\" using \"%s\".\n"
+ "Expected %hd, got %hd.\n", convertC(inputstr),
+ convertC(formatstr), checknum, num);
+ }
+}
+
+void DoI64NumTest(WCHAR *inputstr, WCHAR *formatstr, INT64 checknum)
+{
+ char buf[256];
+ char check[256];
+ INT64 num;
+ int ret;
+
+ ret = swscanf(inputstr, formatstr, &num);
+ if (ret != 1)
+ {
+ Fail("ERROR: Expected swscanf to return 1, got %d.\n"
+ "Using \"%s\" in \"%s\".\n", ret, convertC(inputstr),
+ convertC(formatstr));
+ }
+
+ if (checknum != num)
+ {
+ sprintf(buf, "%I64d", num);
+ sprintf(check, "%I64d", checknum);
+ Fail("ERROR: scanned I64 number incorrectly from \"%s\" using \"%s\".\n"
+ "Expected %s, got %s.\n", convertC(inputstr),
+ convertC(formatstr), check, buf);
+ }
+}
+
+void DoCharTest(WCHAR *inputstr, WCHAR*formatstr, char* checkchars, int numchars)
+{
+ char buf[256];
+ int ret;
+ int i;
+
+ for (i=0; i<256; i++)
+ buf[i] = (char)-1;
+
+ ret = swscanf(inputstr, formatstr, buf);
+ if (ret != 1)
+ {
+ Fail("ERROR: Expected swscanf to return 1, got %d.\n"
+ "Using \"%s\" in \"%s\".\n", ret, convertC(inputstr),
+ convertC(formatstr));
+ }
+
+ if (memcmp(buf, checkchars, numchars) != 0)
+ {
+ buf[numchars] = 0;
+
+ Fail("ERROR: scanned character(s) incorrectly from \"%s\" using \"%s\".\n"
+ "Expected %s, got %s.\n", convertC(inputstr),
+ convertC(formatstr), checkchars, buf);
+ }
+
+ if (buf[numchars] != (char)-1)
+ {
+ Fail("ERROR: overflow occurred in scanning character(s) from \"%s\" "
+ "using \"%s\".\nExpected %d character(s)\n",
+ convertC(inputstr), convertC(formatstr), numchars);
+ }
+}
+
+void DoWCharTest(WCHAR *inputstr, WCHAR *formatstr, WCHAR *checkchars, int numchars)
+{
+ WCHAR buf[256];
+ int ret;
+ int i;
+
+ for (i=0; i<256; i++)
+ buf[i] = (WCHAR)-1;
+
+ ret = swscanf(inputstr, formatstr, buf);
+ if (ret != 1)
+ {
+ Fail("ERROR: Expected swscanf to return 1, got %d.\n"
+ "Using \"%s\" in \"%s\".\n", ret, convertC(inputstr),
+ convertC(formatstr));
+ }
+
+ if (memcmp(buf, checkchars, numchars*2) != 0)
+ {
+ buf[numchars] = 0;
+
+ Fail("ERROR: scanned wide character(s) incorrectly from \"%s\" using \"%s\".\n"
+ "Expected %s, got %s.\n", convertC(inputstr),
+ convertC(formatstr), convertC(checkchars),
+ convertC(buf));
+ }
+
+ if (buf[numchars] != (WCHAR)-1)
+ {
+ Fail("ERROR: overflow occurred in scanning wide character(s) from \"%s\" "
+ "using \"%s\".\nExpected %d character(s)\n",
+ convertC(inputstr), convertC(formatstr), numchars);
+ }
+}
+
+
+void DoFloatTest(WCHAR *inputstr, WCHAR *formatstr, float checkval)
+{
+ char buf[256] = { 0 };
+ float val;
+ int ret;
+ int i;
+
+ for (i=0; i<256; i++)
+ buf[i] = (char)-1;
+
+ ret = swscanf(inputstr, formatstr, buf);
+ val = *(float*)buf;
+
+ if (ret != 1)
+ {
+ Fail("ERROR: Expected swscanf to return 1, got %d.\n"
+ "Using \"%s\" in \"%s\".\n", ret, convertC(inputstr),
+ convertC(formatstr));
+ }
+
+ if (val != checkval)
+ {
+ Fail("ERROR: scanned float incorrectly from \"%s\" using \"%s\".\n"
+ "Expected \"%f\", got \"%f\".\n", convertC(inputstr),
+ convertC(formatstr), checkval, val);
+ }
+
+ if (buf[4] != (char)-1)
+ {
+ Fail("ERROR: overflow occurred in scanning float from \"%s\" "
+ "using \"%s\".\n", convertC(inputstr), convertC(formatstr));
+
+ }
+}
+
+
+#endif
diff --git a/src/pal/tests/palsuite/c_runtime/swscanf/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/swscanf/test1/CMakeLists.txt
new file mode 100644
index 0000000000..030aaaf709
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swscanf/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_swscanf_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_swscanf_test1 coreclrpal)
+
+target_link_libraries(paltest_swscanf_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/swscanf/test1/test1.c b/src/pal/tests/palsuite/c_runtime/swscanf/test1/test1.c
new file mode 100644
index 0000000000..66136e57c5
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swscanf/test1/test1.c
@@ -0,0 +1,53 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose: General test of swscanf
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../swscanf.h"
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ int num;
+ int ret;
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ DoVoidTest(convert("foo bar"), convert("foo"));
+ DoVoidTest(convert("foo bar"), convert("baz"));
+ DoVoidTest(convert("foo bar"), convert("foo %*s"));
+
+ DoStrTest(convert("foo % bar"), convert("foo %% %S"), "bar");
+ DoStrTest(convert("foo bar baz"), convert("foo %bar %S"), "baz");
+
+ DoVoidTest(convert("foo bar baz"), convert("foo % bar %S"));
+ DoVoidTest(convert("foo bar baz"), convert("foo% bar %S"));
+
+
+ ret = swscanf(convert("foo bar baz"), convert("foo bar %n"), &num);
+ if (ret != 0 || num != 8)
+ {
+ Fail("ERROR: Got incorrect values in scanning \"%s\" using \"%s\".\n"
+ "Expected to get a value of %d with return value of %d, "
+ "got %d with return %d\n", "foo bar baz", "foo bar %n", 8, 0,
+ num, ret);
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/swscanf/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/swscanf/test1/testinfo.dat
new file mode 100644
index 0000000000..b6366a73d0
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swscanf/test1/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = swscanf
+Name = Positive Test for swscanf
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= General test of swscanf
diff --git a/src/pal/tests/palsuite/c_runtime/swscanf/test10/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/swscanf/test10/CMakeLists.txt
new file mode 100644
index 0000000000..f7c8b284ff
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swscanf/test10/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test10.c
+)
+
+add_executable(paltest_swscanf_test10
+ ${SOURCES}
+)
+
+add_dependencies(paltest_swscanf_test10 coreclrpal)
+
+target_link_libraries(paltest_swscanf_test10
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/swscanf/test10/test10.c b/src/pal/tests/palsuite/c_runtime/swscanf/test10/test10.c
new file mode 100644
index 0000000000..a8628e0de1
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swscanf/test10/test10.c
@@ -0,0 +1,36 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test10.c
+**
+** Purpose:Tests swscanf with wide characters
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../swscanf.h"
+
+int __cdecl main(int argc, char *argv[])
+{
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ DoCharTest(convert("1234"), convert("%C"), "1", 1);
+ DoCharTest(convert("abc"), convert("%2C"), "ab", 2);
+ DoCharTest(convert(" ab"), convert("%C"), " ", 1);
+ DoCharTest(convert("ab"), convert("%hC"), "a", 1);
+ DoWCharTest(convert("ab"), convert("%lC"), convert("a"), 1);
+ DoCharTest(convert("ab"), convert("%LC"), "a", 1);
+ DoCharTest(convert("ab"), convert("%I64C"), "a", 1);
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/swscanf/test10/testinfo.dat b/src/pal/tests/palsuite/c_runtime/swscanf/test10/testinfo.dat
new file mode 100644
index 0000000000..2f8890db20
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swscanf/test10/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = swscanf
+Name = Positive Test for swscanf
+TYPE = DEFAULT
+EXE1 = test10
+Description
+= Tests swscanf with wide characters
diff --git a/src/pal/tests/palsuite/c_runtime/swscanf/test11/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/swscanf/test11/CMakeLists.txt
new file mode 100644
index 0000000000..17066f31b8
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swscanf/test11/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test11.c
+)
+
+add_executable(paltest_swscanf_test11
+ ${SOURCES}
+)
+
+add_dependencies(paltest_swscanf_test11 coreclrpal)
+
+target_link_libraries(paltest_swscanf_test11
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/swscanf/test11/test11.c b/src/pal/tests/palsuite/c_runtime/swscanf/test11/test11.c
new file mode 100644
index 0000000000..f7eb4af46f
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swscanf/test11/test11.c
@@ -0,0 +1,35 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test11.c
+**
+** Purpose: Tests swscanf with strings
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../swscanf.h"
+
+int __cdecl main(int argc, char *argv[])
+{
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ DoWStrTest(convert("foo bar"), convert("foo %s"), convert("bar"));
+ DoWStrTest(convert("foo bar"), convert("foo %2s"), convert("ba"));
+ DoStrTest(convert("foo bar"), convert("foo %hs"), "bar");
+ DoWStrTest(convert("foo bar"), convert("foo %ls"), convert("bar"));
+ DoWStrTest(convert("foo bar"), convert("foo %Ls"), convert("bar"));
+ DoWStrTest(convert("foo bar"), convert("foo %I64s"), convert("bar"));
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/swscanf/test11/testinfo.dat b/src/pal/tests/palsuite/c_runtime/swscanf/test11/testinfo.dat
new file mode 100644
index 0000000000..5bbc2e433b
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swscanf/test11/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = swscanf
+Name = Positive Test for swscanf
+TYPE = DEFAULT
+EXE1 = test11
+Description
+= Tests swscanf with strings
diff --git a/src/pal/tests/palsuite/c_runtime/swscanf/test12/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/swscanf/test12/CMakeLists.txt
new file mode 100644
index 0000000000..95f5174ecb
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swscanf/test12/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test12.c
+)
+
+add_executable(paltest_swscanf_test12
+ ${SOURCES}
+)
+
+add_dependencies(paltest_swscanf_test12 coreclrpal)
+
+target_link_libraries(paltest_swscanf_test12
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/swscanf/test12/test12.c b/src/pal/tests/palsuite/c_runtime/swscanf/test12/test12.c
new file mode 100644
index 0000000000..f5f8bbdf8a
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swscanf/test12/test12.c
@@ -0,0 +1,35 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test12.c
+**
+** Purpose: Tests swscanf with wide strings
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../swscanf.h"
+
+int __cdecl main(int argc, char *argv[])
+{
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ DoStrTest(convert("foo bar"), convert("foo %S"), "bar");
+ DoStrTest(convert("foo bar"), convert("foo %2S"), "ba");
+ DoStrTest(convert("foo bar"), convert("foo %hS"), "bar");
+ DoWStrTest(convert("foo bar"), convert("foo %lS"), convert("bar"));
+ DoStrTest(convert("foo bar"), convert("foo %LS"), "bar");
+ DoStrTest(convert("foo bar"), convert("foo %I64S"), "bar");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/swscanf/test12/testinfo.dat b/src/pal/tests/palsuite/c_runtime/swscanf/test12/testinfo.dat
new file mode 100644
index 0000000000..06bf26af9b
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swscanf/test12/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = swscanf
+Name = Positive Test for swscanf
+TYPE = DEFAULT
+EXE1 = test12
+Description
+= Tests swscanf with wide strings
diff --git a/src/pal/tests/palsuite/c_runtime/swscanf/test13/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/swscanf/test13/CMakeLists.txt
new file mode 100644
index 0000000000..47abc50313
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swscanf/test13/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test13.c
+)
+
+add_executable(paltest_swscanf_test13
+ ${SOURCES}
+)
+
+add_dependencies(paltest_swscanf_test13 coreclrpal)
+
+target_link_libraries(paltest_swscanf_test13
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/swscanf/test13/test13.c b/src/pal/tests/palsuite/c_runtime/swscanf/test13/test13.c
new file mode 100644
index 0000000000..1bb0b7b21c
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swscanf/test13/test13.c
@@ -0,0 +1,37 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test13.c
+**
+** Purpose: Tests swscanf with floats (decimal notation)
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../swscanf.h"
+
+int __cdecl main(int argc, char *argv[])
+{
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ DoFloatTest(convert("123.0"), convert("%f"), 123.0f);
+ DoFloatTest(convert("123.0"), convert("%2f"), 12.0f);
+ DoFloatTest(convert("10E1"), convert("%f"), 100.0f);
+ DoFloatTest(convert("-12.01e-2"), convert("%f"), -0.1201f);
+ DoFloatTest(convert("+12.01e-2"), convert("%f"), 0.1201f);
+ DoFloatTest(convert("-12.01e+2"), convert("%f"), -1201.0f);
+ DoFloatTest(convert("+12.01e+2"), convert("%f"), 1201.0f);
+ DoFloatTest(convert("1234567890.0123456789f"), convert("%f"), 1234567936);
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/swscanf/test13/testinfo.dat b/src/pal/tests/palsuite/c_runtime/swscanf/test13/testinfo.dat
new file mode 100644
index 0000000000..a3c01c5d76
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swscanf/test13/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = swscanf
+Name = Positive Test for swscanf
+TYPE = DEFAULT
+EXE1 = test13
+Description
+= Tests swscanf with floats (decimal notation)
diff --git a/src/pal/tests/palsuite/c_runtime/swscanf/test14/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/swscanf/test14/CMakeLists.txt
new file mode 100644
index 0000000000..a470436ce7
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swscanf/test14/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test14.c
+)
+
+add_executable(paltest_swscanf_test14
+ ${SOURCES}
+)
+
+add_dependencies(paltest_swscanf_test14 coreclrpal)
+
+target_link_libraries(paltest_swscanf_test14
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/swscanf/test14/test14.c b/src/pal/tests/palsuite/c_runtime/swscanf/test14/test14.c
new file mode 100644
index 0000000000..80581b726f
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swscanf/test14/test14.c
@@ -0,0 +1,38 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test14.c
+**
+** Purpose: Tests swscanf with floats (exponential notation, lowercase)
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../swscanf.h"
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ DoFloatTest(convert("123.0"), convert("%e"), 123.0f);
+ DoFloatTest(convert("123.0"), convert("%2e"), 12.0f);
+ DoFloatTest(convert("10E1"), convert("%e"), 100.0f);
+ DoFloatTest(convert("-12.01e-2"), convert("%e"), -0.1201f);
+ DoFloatTest(convert("+12.01e-2"), convert("%e"), 0.1201f);
+ DoFloatTest(convert("-12.01e+2"), convert("%e"), -1201.0f);
+ DoFloatTest(convert("+12.01e+2"), convert("%e"), 1201.0f);
+ DoFloatTest(convert("1234567890.0123456789f"), convert("%e"), 1234567936);
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/swscanf/test14/testinfo.dat b/src/pal/tests/palsuite/c_runtime/swscanf/test14/testinfo.dat
new file mode 100644
index 0000000000..184a3e7fb8
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swscanf/test14/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = swscanf
+Name = Positive Test for swscanf
+TYPE = DEFAULT
+EXE1 = test14
+Description
+= Tests swscanf with floats (exponential notation, lowercase)
diff --git a/src/pal/tests/palsuite/c_runtime/swscanf/test15/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/swscanf/test15/CMakeLists.txt
new file mode 100644
index 0000000000..d89650b12c
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swscanf/test15/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test15.c
+)
+
+add_executable(paltest_swscanf_test15
+ ${SOURCES}
+)
+
+add_dependencies(paltest_swscanf_test15 coreclrpal)
+
+target_link_libraries(paltest_swscanf_test15
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/swscanf/test15/test15.c b/src/pal/tests/palsuite/c_runtime/swscanf/test15/test15.c
new file mode 100644
index 0000000000..9b7d277e17
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swscanf/test15/test15.c
@@ -0,0 +1,37 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test15.c
+**
+** Purpose: Tests swscanf with floats (exponential notation, uppercase)
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../swscanf.h"
+
+int __cdecl main(int argc, char *argv[])
+{
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ DoFloatTest(convert("123.0"), convert("%E"), 123.0f);
+ DoFloatTest(convert("123.0"), convert("%2E"), 12.0f);
+ DoFloatTest(convert("10E1"), convert("%E"), 100.0f);
+ DoFloatTest(convert("-12.01e-2"), convert("%E"), -0.1201f);
+ DoFloatTest(convert("+12.01e-2"), convert("%E"), 0.1201f);
+ DoFloatTest(convert("-12.01e+2"), convert("%E"), -1201.0f);
+ DoFloatTest(convert("+12.01e+2"), convert("%E"), 1201.0f);
+ DoFloatTest(convert("1234567890.0123456789f"), convert("%E"), 1234567936);
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/swscanf/test15/testinfo.dat b/src/pal/tests/palsuite/c_runtime/swscanf/test15/testinfo.dat
new file mode 100644
index 0000000000..ab20463ecd
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swscanf/test15/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = swscanf
+Name = Positive Test for swscanf
+TYPE = DEFAULT
+EXE1 = test15
+Description
+= Tests swscanf with floats (exponential notation, uppercase)
diff --git a/src/pal/tests/palsuite/c_runtime/swscanf/test16/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/swscanf/test16/CMakeLists.txt
new file mode 100644
index 0000000000..a2a00f11b6
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swscanf/test16/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test16.c
+)
+
+add_executable(paltest_swscanf_test16
+ ${SOURCES}
+)
+
+add_dependencies(paltest_swscanf_test16 coreclrpal)
+
+target_link_libraries(paltest_swscanf_test16
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/swscanf/test16/test16.c b/src/pal/tests/palsuite/c_runtime/swscanf/test16/test16.c
new file mode 100644
index 0000000000..c83b64468b
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swscanf/test16/test16.c
@@ -0,0 +1,37 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test16.c
+**
+** Purpose: Tests swscanf with floats (compact notation, lowercase)
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../swscanf.h"
+
+int __cdecl main(int argc, char *argv[])
+{
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ DoFloatTest(convert("123.0"), convert("%g"), 123.0f);
+ DoFloatTest(convert("123.0"), convert("%2g"), 12.0f);
+ DoFloatTest(convert("10E1"), convert("%g"), 100.0f);
+ DoFloatTest(convert("-12.01e-2"), convert("%g"), -0.1201f);
+ DoFloatTest(convert("+12.01e-2"), convert("%g"), 0.1201f);
+ DoFloatTest(convert("-12.01e+2"), convert("%g"), -1201.0f);
+ DoFloatTest(convert("+12.01e+2"), convert("%g"), 1201.0f);
+ DoFloatTest(convert("1234567890.0123456789f"), convert("%g"), 1234567936);
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/swscanf/test16/testinfo.dat b/src/pal/tests/palsuite/c_runtime/swscanf/test16/testinfo.dat
new file mode 100644
index 0000000000..0cfa37d63b
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swscanf/test16/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = swscanf
+Name = Positive Test for swscanf
+TYPE = DEFAULT
+EXE1 = test16
+Description
+= Tests swscanf with floats (compact notation, lowercase)
diff --git a/src/pal/tests/palsuite/c_runtime/swscanf/test17/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/swscanf/test17/CMakeLists.txt
new file mode 100644
index 0000000000..c224f5d9a6
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swscanf/test17/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test17.c
+)
+
+add_executable(paltest_swscanf_test17
+ ${SOURCES}
+)
+
+add_dependencies(paltest_swscanf_test17 coreclrpal)
+
+target_link_libraries(paltest_swscanf_test17
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/swscanf/test17/test17.c b/src/pal/tests/palsuite/c_runtime/swscanf/test17/test17.c
new file mode 100644
index 0000000000..9023f7020a
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swscanf/test17/test17.c
@@ -0,0 +1,37 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test17.c
+**
+** Purpose: Tests swscanf with floats (compact notation, uppercase)
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../swscanf.h"
+
+int __cdecl main(int argc, char *argv[])
+{
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ DoFloatTest(convert("123.0"), convert("%G"), 123.0f);
+ DoFloatTest(convert("123.0"), convert("%2G"), 12.0f);
+ DoFloatTest(convert("10E1"), convert("%G"), 100.0f);
+ DoFloatTest(convert("-12.01e-2"), convert("%G"), -0.1201f);
+ DoFloatTest(convert("+12.01e-2"), convert("%G"), 0.1201f);
+ DoFloatTest(convert("-12.01e+2"), convert("%G"), -1201.0f);
+ DoFloatTest(convert("+12.01e+2"), convert("%G"), 1201.0f);
+ DoFloatTest(convert("1234567890.0123456789f"), convert("%G"), 1234567936);
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/swscanf/test17/testinfo.dat b/src/pal/tests/palsuite/c_runtime/swscanf/test17/testinfo.dat
new file mode 100644
index 0000000000..f0489dfa41
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swscanf/test17/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = swscanf
+Name = Positive Test for swscanf
+TYPE = DEFAULT
+EXE1 = test17
+Description
+= Tests swscanf with floats (compact notation, uppercase)
diff --git a/src/pal/tests/palsuite/c_runtime/swscanf/test2/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/swscanf/test2/CMakeLists.txt
new file mode 100644
index 0000000000..a5335ddb48
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swscanf/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test2.c
+)
+
+add_executable(paltest_swscanf_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_swscanf_test2 coreclrpal)
+
+target_link_libraries(paltest_swscanf_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/swscanf/test2/test2.c b/src/pal/tests/palsuite/c_runtime/swscanf/test2/test2.c
new file mode 100644
index 0000000000..8fbd3f86ba
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swscanf/test2/test2.c
@@ -0,0 +1,43 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test2.c
+**
+** Purpose: Test to see if swscanf handles whitespace correctly
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../swscanf.h"
+
+/*
+ * Tests out how it handles whitespace. Seems to accept anything that qualifies
+ * as isspace (space, tab, vertical tab, line feed, carriage return and form
+ * feed), even if it says it only wants spaces tabs and newlines.
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ DoStrTest(convert("foo bar"), convert("foo %S"), "bar");
+ DoStrTest(convert("foo\tbar"), convert("foo %S"), "bar");
+ DoStrTest(convert("foo\nbar"), convert("foo %S"), "bar");
+ DoStrTest(convert("foo\rbar"), convert("foo %S"), "bar");
+ DoStrTest(convert("foo\vbar"), convert("foo %S"), "bar");
+ DoStrTest(convert("foo\fbar"), convert("foo %S"), "bar");
+ DoStrTest(convert("foo \t\n\r\v\fbar"), convert("foo %S"), "bar");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/swscanf/test2/testinfo.dat b/src/pal/tests/palsuite/c_runtime/swscanf/test2/testinfo.dat
new file mode 100644
index 0000000000..88768ca465
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swscanf/test2/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = swscanf
+Name = Positive Test for swscanf
+TYPE = DEFAULT
+EXE1 = test2
+Description
+= Test to see if swscanf handles whitespace correctly
diff --git a/src/pal/tests/palsuite/c_runtime/swscanf/test3/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/swscanf/test3/CMakeLists.txt
new file mode 100644
index 0000000000..5c229c26d3
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swscanf/test3/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test3.c
+)
+
+add_executable(paltest_swscanf_test3
+ ${SOURCES}
+)
+
+add_dependencies(paltest_swscanf_test3 coreclrpal)
+
+target_link_libraries(paltest_swscanf_test3
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/swscanf/test3/test3.c b/src/pal/tests/palsuite/c_runtime/swscanf/test3/test3.c
new file mode 100644
index 0000000000..8b05df20f2
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swscanf/test3/test3.c
@@ -0,0 +1,36 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test3.c
+**
+** Purpose: Tests swscanf with bracketed set strings
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../swscanf.h"
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ DoWStrTest(convert("bar1"), convert("%[a-z]"), convert("bar"));
+ DoWStrTest(convert("bar1"), convert("%[z-a]"), convert("bar"));
+ DoWStrTest(convert("bar1"), convert("%[ab]"), convert("ba"));
+ DoWStrTest(convert("bar1"), convert("%[ar1b]"), convert("bar1"));
+ DoWStrTest(convert("bar1"), convert("%[^4]"), convert("bar1"));
+ DoWStrTest(convert("bar1"), convert("%[^4a]"), convert("b"));
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/swscanf/test3/testinfo.dat b/src/pal/tests/palsuite/c_runtime/swscanf/test3/testinfo.dat
new file mode 100644
index 0000000000..998cba8b6b
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swscanf/test3/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = swscanf
+Name = Positive Test for swscanf
+TYPE = DEFAULT
+EXE1 = test3
+Description
+= Tests swscanf with bracketed set strings
diff --git a/src/pal/tests/palsuite/c_runtime/swscanf/test4/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/swscanf/test4/CMakeLists.txt
new file mode 100644
index 0000000000..5e281aaf34
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swscanf/test4/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test4.c
+)
+
+add_executable(paltest_swscanf_test4
+ ${SOURCES}
+)
+
+add_dependencies(paltest_swscanf_test4 coreclrpal)
+
+target_link_libraries(paltest_swscanf_test4
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/swscanf/test4/test4.c b/src/pal/tests/palsuite/c_runtime/swscanf/test4/test4.c
new file mode 100644
index 0000000000..d63d25b7d0
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swscanf/test4/test4.c
@@ -0,0 +1,44 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test4.c
+**
+** Purpose:Tests swscanf with decimal numbers
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../swscanf.h"
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ int n65535 = 65535; /* Walkaround compiler strictness */
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ DoNumTest(convert("1234d"), convert("%d"), 1234);
+ DoNumTest(convert("1234d"), convert("%2d"), 12);
+ DoNumTest(convert("-1"), convert("%d"), -1);
+ DoNumTest(convert("0x1234"), convert("%d"), 0);
+ DoNumTest(convert("012"), convert("%d"), 12);
+ DoShortNumTest(convert("-1"), convert("%hd"), n65535);
+ DoShortNumTest(convert("65536"), convert("%hd"), 0);
+ DoNumTest(convert("-1"), convert("%ld"), -1);
+ DoNumTest(convert("65536"), convert("%ld"), 65536);
+ DoNumTest(convert("-1"), convert("%Ld"), -1);
+ DoNumTest(convert("65536"), convert("%Ld"), 65536);
+ DoI64NumTest(convert("4294967296"), convert("%I64d"), I64(4294967296));
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/swscanf/test4/testinfo.dat b/src/pal/tests/palsuite/c_runtime/swscanf/test4/testinfo.dat
new file mode 100644
index 0000000000..e6102872d7
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swscanf/test4/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = swscanf
+Name = Positive Test for swscanf
+TYPE = DEFAULT
+EXE1 = test4
+Description
+= Tests swscanf with decimal numbers
diff --git a/src/pal/tests/palsuite/c_runtime/swscanf/test5/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/swscanf/test5/CMakeLists.txt
new file mode 100644
index 0000000000..8b259aa78d
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swscanf/test5/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test5.c
+)
+
+add_executable(paltest_swscanf_test5
+ ${SOURCES}
+)
+
+add_dependencies(paltest_swscanf_test5 coreclrpal)
+
+target_link_libraries(paltest_swscanf_test5
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/swscanf/test5/test5.c b/src/pal/tests/palsuite/c_runtime/swscanf/test5/test5.c
new file mode 100644
index 0000000000..8ae2d81da6
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swscanf/test5/test5.c
@@ -0,0 +1,44 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test5.c
+**
+** Purpose: Tests swscanf with integer numbers
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../swscanf.h"
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ int n65535 = 65535; /* Walkaround compiler strictness */
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ DoNumTest(convert("1234d"), convert("%i"), 1234);
+ DoNumTest(convert("1234d"), convert("%2i"), 12);
+ DoNumTest(convert("-1"), convert("%i"), -1);
+ DoNumTest(convert("0x1234"), convert("%i"), 0x1234);
+ DoNumTest(convert("012"), convert("%i"), 10);
+ DoShortNumTest(convert("-1"), convert("%hi"), n65535);
+ DoShortNumTest(convert("65536"), convert("%hi"), 0);
+ DoNumTest(convert("-1"), convert("%li"), -1);
+ DoNumTest(convert("65536"), convert("%li"), 65536);
+ DoNumTest(convert("-1"), convert("%Li"), -1);
+ DoNumTest(convert("65536"), convert("%Li"), 65536);
+ DoI64NumTest(convert("4294967296"), convert("%I64i"), I64(4294967296));
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/swscanf/test5/testinfo.dat b/src/pal/tests/palsuite/c_runtime/swscanf/test5/testinfo.dat
new file mode 100644
index 0000000000..9991286402
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swscanf/test5/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = swscanf
+Name = Positive Test for swscanf
+TYPE = DEFAULT
+EXE1 = test5
+Description
+= Tests swscanf with integer numbers
diff --git a/src/pal/tests/palsuite/c_runtime/swscanf/test6/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/swscanf/test6/CMakeLists.txt
new file mode 100644
index 0000000000..c3fd8696ab
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swscanf/test6/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test6.c
+)
+
+add_executable(paltest_swscanf_test6
+ ${SOURCES}
+)
+
+add_dependencies(paltest_swscanf_test6 coreclrpal)
+
+target_link_libraries(paltest_swscanf_test6
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/swscanf/test6/test6.c b/src/pal/tests/palsuite/c_runtime/swscanf/test6/test6.c
new file mode 100644
index 0000000000..982f799cfc
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swscanf/test6/test6.c
@@ -0,0 +1,44 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test6.c
+**
+** Purpose:Tests swscanf with octal numbers
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../swscanf.h"
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ int n65535 = 65535; /* Walkaround compiler strictness */
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ DoNumTest(convert("1234d"), convert("%o"), 668);
+ DoNumTest(convert("1234d"), convert("%2o"), 10);
+ DoNumTest(convert("-1"), convert("%o"), -1);
+ DoNumTest(convert("0x1234"), convert("%o"), 0);
+ DoNumTest(convert("012"), convert("%o"), 10);
+ DoShortNumTest(convert("-1"), convert("%ho"), n65535);
+ DoShortNumTest(convert("200000"), convert("%ho"), 0);
+ DoNumTest(convert("-1"), convert("%lo"), -1);
+ DoNumTest(convert("200000"), convert("%lo"), 65536);
+ DoNumTest(convert("-1"), convert("%Lo"), -1);
+ DoNumTest(convert("200000"), convert("%Lo"), 65536);
+ DoI64NumTest(convert("40000000000"), convert("%I64o"), I64(4294967296));
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/swscanf/test6/testinfo.dat b/src/pal/tests/palsuite/c_runtime/swscanf/test6/testinfo.dat
new file mode 100644
index 0000000000..ca7870e962
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swscanf/test6/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = swscanf
+Name = Positive Test for swscanf
+TYPE = DEFAULT
+EXE1 = test6
+Description
+= Tests swscanf with octal numbers
diff --git a/src/pal/tests/palsuite/c_runtime/swscanf/test7/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/swscanf/test7/CMakeLists.txt
new file mode 100644
index 0000000000..00541306df
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swscanf/test7/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test7.c
+)
+
+add_executable(paltest_swscanf_test7
+ ${SOURCES}
+)
+
+add_dependencies(paltest_swscanf_test7 coreclrpal)
+
+target_link_libraries(paltest_swscanf_test7
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/swscanf/test7/test7.c b/src/pal/tests/palsuite/c_runtime/swscanf/test7/test7.c
new file mode 100644
index 0000000000..45e9400549
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swscanf/test7/test7.c
@@ -0,0 +1,44 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test7.c
+**
+** Purpose: Test #6 for the swscanf function
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../swscanf.h"
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ int n65535 = 65535; /* Walkaround compiler strictness */
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ DoNumTest(convert("1234d"), convert("%x"), 0x1234d);
+ DoNumTest(convert("1234d"), convert("%2x"), 0x12);
+ DoNumTest(convert("-1"), convert("%x"), -1);
+ DoNumTest(convert("0x1234"), convert("%x"), 0x1234);
+ DoNumTest(convert("012"), convert("%x"), 0x12);
+ DoShortNumTest(convert("-1"), convert("%hx"), n65535);
+ DoShortNumTest(convert("10000"), convert("%hx"), 0);
+ DoNumTest(convert("-1"), convert("%lx"), -1);
+ DoNumTest(convert("10000"), convert("%lx"), 65536);
+ DoNumTest(convert("-1"), convert("%Lx"), -1);
+ DoNumTest(convert("10000"), convert("%Lx"), 65536);
+ DoI64NumTest(convert("100000000"), convert("%I64x"), I64(4294967296));
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/swscanf/test7/testinfo.dat b/src/pal/tests/palsuite/c_runtime/swscanf/test7/testinfo.dat
new file mode 100644
index 0000000000..43ff8108df
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swscanf/test7/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = swscanf
+Name = Positive Test for swscanf
+TYPE = DEFAULT
+EXE1 = test7
+Description
+= Tests swscanf with hex numbers (lowercase)
diff --git a/src/pal/tests/palsuite/c_runtime/swscanf/test8/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/swscanf/test8/CMakeLists.txt
new file mode 100644
index 0000000000..d6aa631ab9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swscanf/test8/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test8.c
+)
+
+add_executable(paltest_swscanf_test8
+ ${SOURCES}
+)
+
+add_dependencies(paltest_swscanf_test8 coreclrpal)
+
+target_link_libraries(paltest_swscanf_test8
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/swscanf/test8/test8.c b/src/pal/tests/palsuite/c_runtime/swscanf/test8/test8.c
new file mode 100644
index 0000000000..a244de748f
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swscanf/test8/test8.c
@@ -0,0 +1,44 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test8.c
+**
+** Purpose: Tests swscanf with unsigned numbers
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../swscanf.h"
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ int n65535 = 65535; /* Walkaround compiler strictness */
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ DoNumTest(convert("1234d"), convert("%u"), 1234);
+ DoNumTest(convert("1234d"), convert("%2u"), 12);
+ DoNumTest(convert("-1"), convert("%u"), -1);
+ DoNumTest(convert("0x1234"), convert("%u"), 0);
+ DoNumTest(convert("012"), convert("%u"), 12);
+ DoShortNumTest(convert("-1"), convert("%hu"), n65535);
+ DoShortNumTest(convert("65536"), convert("%hu"), 0);
+ DoNumTest(convert("-1"), convert("%lu"), -1);
+ DoNumTest(convert("65536"), convert("%lu"), 65536);
+ DoNumTest(convert("-1"), convert("%Lu"), -1);
+ DoNumTest(convert("65536"), convert("%Lu"), 65536);
+ DoI64NumTest(convert("4294967296"), convert("%I64u"), I64(4294967296));
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/swscanf/test8/testinfo.dat b/src/pal/tests/palsuite/c_runtime/swscanf/test8/testinfo.dat
new file mode 100644
index 0000000000..0edefb0756
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swscanf/test8/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = swscanf
+Name = Positive Test for swscanf
+TYPE = DEFAULT
+EXE1 = test8
+Description
+= Tests swscanf with unsigned numbers
diff --git a/src/pal/tests/palsuite/c_runtime/swscanf/test9/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/swscanf/test9/CMakeLists.txt
new file mode 100644
index 0000000000..4f7595a205
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swscanf/test9/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test9.c
+)
+
+add_executable(paltest_swscanf_test9
+ ${SOURCES}
+)
+
+add_dependencies(paltest_swscanf_test9 coreclrpal)
+
+target_link_libraries(paltest_swscanf_test9
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/swscanf/test9/test9.c b/src/pal/tests/palsuite/c_runtime/swscanf/test9/test9.c
new file mode 100644
index 0000000000..e289d26f58
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swscanf/test9/test9.c
@@ -0,0 +1,37 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test9.c
+**
+** Purpose: Tests swscanf with characters
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../swscanf.h"
+
+int __cdecl main(int argc, char *argv[])
+{
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ DoWCharTest(convert("1234"), convert("%c"), convert("1"), 1);
+ DoWCharTest(convert("1234"), convert("%c"), convert("1"), 1);
+ DoWCharTest(convert("abc"), convert("%2c"), convert("ab"), 2);
+ DoWCharTest(convert(" ab"), convert("%c"), convert(" "), 1);
+ DoCharTest(convert("ab"), convert("%hc"), "a", 1);
+ DoWCharTest(convert("ab"), convert("%lc"), convert("a"), 1);
+ DoWCharTest(convert("ab"), convert("%Lc"), convert("a"), 1);
+ DoWCharTest(convert("ab"), convert("%I64c"), convert("a"), 1);
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/swscanf/test9/testinfo.dat b/src/pal/tests/palsuite/c_runtime/swscanf/test9/testinfo.dat
new file mode 100644
index 0000000000..955b62b12f
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/swscanf/test9/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = swscanf
+Name = Positive Test for swscanf
+TYPE = DEFAULT
+EXE1 = test9
+Description
+= Tests swscanf with characters
diff --git a/src/pal/tests/palsuite/c_runtime/tan/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/tan/CMakeLists.txt
new file mode 100644
index 0000000000..5e1ef7f28b
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/tan/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
diff --git a/src/pal/tests/palsuite/c_runtime/tan/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/tan/test1/CMakeLists.txt
new file mode 100644
index 0000000000..665fc22d5e
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/tan/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_tan_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_tan_test1 coreclrpal)
+
+target_link_libraries(paltest_tan_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/tan/test1/test1.c b/src/pal/tests/palsuite/c_runtime/tan/test1/test1.c
new file mode 100644
index 0000000000..443e5da6d6
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/tan/test1/test1.c
@@ -0,0 +1,137 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Test to ensure that tan return the correct values
+**
+** Dependencies: PAL_Initialize
+** PAL_Terminate
+** Fail
+** fabs
+**
+**===========================================================================*/
+
+#include <palsuite.h>
+
+// binary64 (double) has a machine epsilon of 2^-52 (approx. 2.22e-16). However, this
+// is slightly too accurate when writing tests meant to run against libm implementations
+// for various platforms. 2^-50 (approx. 8.88e-16) seems to be as accurate as we can get.
+//
+// The tests themselves will take PAL_EPSILON and adjust it according to the expected result
+// so that the delta used for comparison will compare the most significant digits and ignore
+// any digits that are outside the double precision range (15-17 digits).
+
+// For example, a test with an expect result in the format of 0.xxxxxxxxxxxxxxxxx will use
+// PAL_EPSILON for the variance, while an expected result in the format of 0.0xxxxxxxxxxxxxxxxx
+// will use PAL_EPSILON / 10 and and expected result in the format of x.xxxxxxxxxxxxxxxx will
+// use PAL_EPSILON * 10.
+#define PAL_EPSILON 8.8817841970012523e-16
+
+#define PAL_NAN sqrt(-1.0)
+#define PAL_POSINF -log(0.0)
+#define PAL_NEGINF log(0.0)
+
+/**
+ * Helper test structure
+ */
+struct test
+{
+ double value; /* value to test the function with */
+ double expected; /* expected result */
+ double variance; /* maximum delta between the expected and actual result */
+};
+
+/**
+ * validate
+ *
+ * test validation function
+ */
+void __cdecl validate(double value, double expected, double variance)
+{
+ double result = tan(value);
+
+ /*
+ * The test is valid when the difference between result
+ * and expected is less than or equal to variance
+ */
+ double delta = fabs(result - expected);
+
+ if (delta > variance)
+ {
+ Fail("tan(%g) returned %20.17g when it should have returned %20.17g",
+ value, result, expected);
+ }
+}
+
+/**
+ * validate
+ *
+ * test validation function for values returning NaN
+ */
+void __cdecl validate_isnan(double value)
+{
+ double result = tan(value);
+
+ if (!_isnan(result))
+ {
+ Fail("tan(%g) returned %20.17g when it should have returned %20.17g",
+ value, result, PAL_NAN);
+ }
+}
+
+/**
+ * main
+ *
+ * executable entry point
+ */
+int __cdecl main(int argc, char **argv)
+{
+ struct test tests[] =
+ {
+ /* value expected variance */
+ { 0, 0, PAL_EPSILON },
+ { 0.31830988618379067, 0.32951473309607836, PAL_EPSILON }, // value: 1 / pi
+ { 0.43429448190325183, 0.46382906716062964, PAL_EPSILON }, // value: log10(e)
+ { 0.63661977236758134, 0.73930295048660405, PAL_EPSILON }, // value: 2 / pi
+ { 0.69314718055994531, 0.83064087786078395, PAL_EPSILON }, // value: ln(2)
+ { 0.70710678118654752, 0.85451043200960189, PAL_EPSILON }, // value: 1 / sqrt(2)
+ { 0.78539816339744831, 1, PAL_EPSILON * 10 }, // value: pi / 4
+ { 1, 1.5574077246549022, PAL_EPSILON * 10 },
+ { 1.1283791670955126, 2.1108768356626451, PAL_EPSILON * 10 }, // value: 2 / sqrt(pi)
+ { 1.4142135623730950, 6.3341191670421916, PAL_EPSILON * 10 }, // value: sqrt(2)
+ { 1.4426950408889634, 7.7635756709721848, PAL_EPSILON * 10 }, // value: log2(e)
+ // SEE BELOW -- { 1.5707963267948966, PAL_POSINF, 0 }, // value: pi / 2
+ { 2.3025850929940457, -1.1134071468135374, PAL_EPSILON * 10 }, // value: ln(10)
+ { 2.7182818284590452, -0.45054953406980750, PAL_EPSILON }, // value: e
+ { 3.1415926535897932, 0, PAL_EPSILON }, // value: pi
+ };
+
+ /* PAL initialization */
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+ for (int i = 0; i < (sizeof(tests) / sizeof(struct test)); i++)
+ {
+ validate( tests[i].value, tests[i].expected, tests[i].variance);
+ validate(-tests[i].value, -tests[i].expected, tests[i].variance);
+ }
+
+ // -- SPECIAL CASE --
+ // Normally, tan(pi / 2) would return PAL_POSINF (atan2(PAL_POSINF) does return (pi / 2)).
+ // However, it seems instead (on all supported systems), we get a different number entirely.
+ validate( 1.5707963267948966, 16331239353195370.0, 0);
+ validate(-1.5707963267948966, -16331239353195370.0, 0);
+
+ validate_isnan(PAL_NEGINF);
+ validate_isnan(PAL_NAN);
+ validate_isnan(PAL_POSINF);
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/tan/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/tan/test1/testinfo.dat
new file mode 100644
index 0000000000..05d6cfeb74
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/tan/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = tan
+Name = Positive Test for tan
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Passes to tan() a series of angle value, checking that
+= each one return to correct value.
diff --git a/src/pal/tests/palsuite/c_runtime/tanh/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/tanh/CMakeLists.txt
new file mode 100644
index 0000000000..5e1ef7f28b
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/tanh/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
diff --git a/src/pal/tests/palsuite/c_runtime/tanh/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/tanh/test1/CMakeLists.txt
new file mode 100644
index 0000000000..f8e439dd95
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/tanh/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_tanh_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_tanh_test1 coreclrpal)
+
+target_link_libraries(paltest_tanh_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/tanh/test1/test1.c b/src/pal/tests/palsuite/c_runtime/tanh/test1/test1.c
new file mode 100644
index 0000000000..3b8f87964a
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/tanh/test1/test1.c
@@ -0,0 +1,130 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Test to ensure that tanh return the correct values
+**
+** Dependencies: PAL_Initialize
+** PAL_Terminate
+** Fail
+** fabs
+**
+**===========================================================================*/
+
+#include <palsuite.h>
+
+// binary64 (double) has a machine epsilon of 2^-52 (approx. 2.22e-16). However, this
+// is slightly too accurate when writing tests meant to run against libm implementations
+// for various platforms. 2^-50 (approx. 8.88e-16) seems to be as accurate as we can get.
+//
+// The tests themselves will take PAL_EPSILON and adjust it according to the expected result
+// so that the delta used for comparison will compare the most significant digits and ignore
+// any digits that are outside the double precision range (15-17 digits).
+
+// For example, a test with an expect result in the format of 0.xxxxxxxxxxxxxxxxx will use
+// PAL_EPSILON for the variance, while an expected result in the format of 0.0xxxxxxxxxxxxxxxxx
+// will use PAL_EPSILON / 10 and and expected result in the format of x.xxxxxxxxxxxxxxxx will
+// use PAL_EPSILON * 10.
+#define PAL_EPSILON 8.8817841970012523e-16
+
+#define PAL_NAN sqrt(-1.0)
+#define PAL_POSINF -log(0.0)
+#define PAL_NEGINF log(0.0)
+
+/**
+ * Helper test structure
+ */
+struct test
+{
+ double value; /* value to test the function with */
+ double expected; /* expected result */
+ double variance; /* maximum delta between the expected and actual result */
+};
+
+/**
+ * validate
+ *
+ * test validation function
+ */
+void __cdecl validate(double value, double expected, double variance)
+{
+ double result = tanh(value);
+
+ /*
+ * The test is valid when the difference between result
+ * and expected is less than or equal to variance
+ */
+ double delta = fabs(result - expected);
+
+ if (delta > variance)
+ {
+ Fail("tanh(%g) returned %20.17g when it should have returned %20.17g",
+ value, result, expected);
+ }
+}
+
+/**
+ * validate
+ *
+ * test validation function for values returning NaN
+ */
+void __cdecl validate_isnan(double value)
+{
+ double result = tanh(value);
+
+ if (!_isnan(result))
+ {
+ Fail("tanh(%g) returned %20.17g when it should have returned %20.17g",
+ value, result, PAL_NAN);
+ }
+}
+
+/**
+ * main
+ *
+ * executable entry point
+ */
+int __cdecl main(int argc, char **argv)
+{
+ struct test tests[] =
+ {
+ /* value expected variance */
+ { 0, 0, PAL_EPSILON },
+ { 0.31830988618379067, 0.30797791269089433, PAL_EPSILON }, // value: 1 / pi
+ { 0.43429448190325183, 0.40890401183401433, PAL_EPSILON }, // value: log10(e)
+ { 0.63661977236758134, 0.56259360033158334, PAL_EPSILON }, // value: 2 / pi
+ { 0.69314718055994531, 0.6, PAL_EPSILON }, // value: ln(2)
+ { 0.70710678118654752, 0.60885936501391381, PAL_EPSILON }, // value: 1 / sqrt(2)
+ { 0.78539816339744831, 0.65579420263267244, PAL_EPSILON }, // value: pi / 4
+ { 1, 0.76159415595576489, PAL_EPSILON },
+ { 1.1283791670955126, 0.81046380599898809, PAL_EPSILON }, // value: 2 / sqrt(pi)
+ { 1.4142135623730950, 0.88838556158566054, PAL_EPSILON }, // value: sqrt(2)
+ { 1.4426950408889634, 0.89423894585503855, PAL_EPSILON }, // value: log2(e)
+ { 1.5707963267948966, 0.91715233566727435, PAL_EPSILON }, // value: pi / 2
+ { 2.3025850929940457, 0.98019801980198020, PAL_EPSILON }, // value: ln(10)
+ { 2.7182818284590452, 0.99132891580059984, PAL_EPSILON }, // value: e
+ { 3.1415926535897932, 0.99627207622074994, PAL_EPSILON }, // value: pi
+ { PAL_POSINF, 1, PAL_EPSILON * 10 }
+ };
+
+ /* PAL initialization */
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+ for (int i = 0; i < (sizeof(tests) / sizeof(struct test)); i++)
+ {
+ validate( tests[i].value, tests[i].expected, tests[i].variance);
+ validate(-tests[i].value, -tests[i].expected, tests[i].variance);
+ }
+
+ validate_isnan(PAL_NAN);
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/tanh/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/tanh/test1/testinfo.dat
new file mode 100644
index 0000000000..1b2bc91b2b
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/tanh/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = tanh
+Name = Positive Test for tanh
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Passes to tanh() a series of angle value, checking that
+= each one return to correct value.
diff --git a/src/pal/tests/palsuite/c_runtime/time/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/time/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/time/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/time/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/time/test1/CMakeLists.txt
new file mode 100644
index 0000000000..d495266cef
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/time/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_time_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_time_test1 coreclrpal)
+
+target_link_libraries(paltest_time_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/time/test1/test1.c b/src/pal/tests/palsuite/c_runtime/time/test1/test1.c
new file mode 100644
index 0000000000..c668bf38e7
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/time/test1/test1.c
@@ -0,0 +1,51 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Calls the time function and verifies that the time returned
+** is at least a positive value.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char **argv)
+{
+ time_t t = 0;
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ time(&t);
+ /*I was going to test that the time returned didn't exceed some
+ reasonable value, but decided not to, for fear of creating my own
+ little Y2K-style disaster.*/
+
+ if (t <= 0)
+ {
+ Fail("time() function doesn't return a time.\n");
+ }
+ t = 0;
+ t = time(NULL);
+ if (t <= 0)
+ {
+ Fail("time() function doesn't return a time.\n");
+ }
+ PAL_Terminate();
+ return PASS;
+}
+
+
+
+
+
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/time/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/time/test1/testinfo.dat
new file mode 100644
index 0000000000..40134c7623
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/time/test1/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = time
+Name = Positive Test for time
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Calls the time function and verifies that the time returned is at
+= least a positive value.
+
diff --git a/src/pal/tests/palsuite/c_runtime/tolower/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/tolower/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/tolower/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/tolower/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/tolower/test1/CMakeLists.txt
new file mode 100644
index 0000000000..537f239cf8
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/tolower/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_tolower_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_tolower_test1 coreclrpal)
+
+target_link_libraries(paltest_tolower_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/tolower/test1/test1.c b/src/pal/tests/palsuite/c_runtime/tolower/test1/test1.c
new file mode 100644
index 0000000000..cab623d3f9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/tolower/test1/test1.c
@@ -0,0 +1,79 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test1.c
+**
+** Purpose: Tests the PAL implementation of the tolower function.
+** Check that the tolower function makes capital character
+** lower case. Also check that it has no effect on lower
+** case letters and special characters.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+struct testCase
+{
+ int lower;
+ int start;
+};
+
+int __cdecl main(int argc, char **argv)
+{
+
+ int result;
+ int i;
+
+ struct testCase testCases[] =
+ {
+ {'a', 'A'}, /* Basic cases */
+ {'z', 'Z'},
+ {'b', 'b'}, /* Lower case */
+ {'?', '?'}, /* Characters without case */
+ {230, 230}
+ };
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ /* Loop through each case. Convert each character to lower case
+ and then compare to ensure that it is the correct value.
+ */
+
+ for(i = 0; i < sizeof(testCases) / sizeof(struct testCase); i++)
+ {
+ /*Convert to lower case*/
+ result = tolower(testCases[i].start);
+
+ if (testCases[i].lower != result)
+ {
+ Fail("ERROR: tolower lowered \"%i\" to %i instead of %i.\n",
+ testCases[i].start, result, testCases[i].lower);
+ }
+
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/tolower/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/tolower/test1/testinfo.dat
new file mode 100644
index 0000000000..90f1c729cd
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/tolower/test1/testinfo.dat
@@ -0,0 +1,19 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = tolower
+Name = Positive Test for tolower
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Tests the PAL implementation of the tolower function.
+= Check that the tolower function makes capital character lower case.
+= Also check that it has no effect on lower case letters and special
+= characters.
+
+
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/toupper/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/toupper/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/toupper/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/toupper/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/toupper/test1/CMakeLists.txt
new file mode 100644
index 0000000000..e5aa375a9b
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/toupper/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_toupper_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_toupper_test1 coreclrpal)
+
+target_link_libraries(paltest_toupper_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/toupper/test1/test1.c b/src/pal/tests/palsuite/c_runtime/toupper/test1/test1.c
new file mode 100644
index 0000000000..c580699e3b
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/toupper/test1/test1.c
@@ -0,0 +1,64 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test1.c (toupper)
+**
+**
+** Purpose: Tests the PAL implementation of the toupper function.
+** Check that the toupper function makes lower case
+** character a capital. Also check that it has no effect
+** on upper case letters and special characters.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+struct testCase
+{
+ int upper;
+ int start;
+};
+
+int __cdecl main(int argc, char **argv)
+{
+
+ int result;
+ int i;
+
+ struct testCase testCases[] =
+ {
+ {'A', 'a'}, /* Basic cases */
+ {'Z', 'z'},
+ {'B', 'B'}, /* Upper case */
+ {'%', '%'}, /* Characters without case */
+ {157, 157}
+ };
+
+ if ((PAL_Initialize(argc, argv)) != 0)
+ {
+ return FAIL;
+ }
+
+
+ /* Loop through each case. Convert each character to upper case
+ and then compare to ensure that it is the correct value.
+ */
+ for(i = 0; i < sizeof(testCases) / sizeof(struct testCase); i++)
+ {
+ /*Convert to upper case*/
+ result = toupper(testCases[i].start);
+
+ if (testCases[i].upper != result)
+ {
+ Fail("ERROR: toupper capitalized \"%c\" to %c instead of %c.\n",
+ testCases[i].start, result, testCases[i].upper);
+ }
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/toupper/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/toupper/test1/testinfo.dat
new file mode 100644
index 0000000000..bde7affa4e
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/toupper/test1/testinfo.dat
@@ -0,0 +1,19 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = toupper
+Name = Positive Test for toupper
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Tests the PAL implementation of the toupper function.
+= Check that the toupper function makes lower case character a capital.
+= Also check that it has no effect on upper case letters and special
+= characters.
+
+
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/towlower/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/towlower/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/towlower/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/towlower/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/towlower/test1/CMakeLists.txt
new file mode 100644
index 0000000000..2a3e6a07ef
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/towlower/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_towlower_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_towlower_test1 coreclrpal)
+
+target_link_libraries(paltest_towlower_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/towlower/test1/test1.c b/src/pal/tests/palsuite/c_runtime/towlower/test1/test1.c
new file mode 100644
index 0000000000..5f2457a5fe
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/towlower/test1/test1.c
@@ -0,0 +1,79 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test1.c
+**
+** Purpose: Tests the PAL implementation of the towlower function.
+** Check that the tolower function makes capital character
+** lower case. Also check that it has no effect on lower
+** case letters and special characters.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+struct testCase
+{
+ WCHAR lower;
+ WCHAR start;
+};
+
+int __cdecl main(int argc, char **argv)
+{
+
+ int result;
+ int i;
+
+ struct testCase testCases[] =
+ {
+ {'a', 'A'}, /* Basic cases */
+ {'z', 'Z'},
+ {'b', 'b'}, /* Lower case */
+ {'?', '?'}, /* Characters without case */
+ {230, 230}
+ };
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ /* Loop through each case. Convert each character to lower case
+ and then compare to ensure that it is the correct value.
+ */
+
+ for(i = 0; i < sizeof(testCases) / sizeof(struct testCase); i++)
+ {
+ /*Convert to lower case*/
+ result = towlower(testCases[i].start);
+
+ if (testCases[i].lower != result)
+ {
+ Fail("ERROR: towlower lowered \"%c\" to %c instead of %c.\n",
+ testCases[i].start, result, testCases[i].lower);
+ }
+
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/towlower/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/towlower/test1/testinfo.dat
new file mode 100644
index 0000000000..2df179a8b6
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/towlower/test1/testinfo.dat
@@ -0,0 +1,19 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = towlower
+Name = Positive Test for towlower
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Tests the PAL implementation of the towlower function.
+= Check that the tolower function makes capital character lower case.
+= Also check that it has no effect on lower case letters and special
+= characters.
+
+
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/towupper/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/towupper/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/towupper/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/towupper/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/towupper/test1/CMakeLists.txt
new file mode 100644
index 0000000000..537efbe0fa
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/towupper/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_towupper_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_towupper_test1 coreclrpal)
+
+target_link_libraries(paltest_towupper_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/towupper/test1/test1.c b/src/pal/tests/palsuite/c_runtime/towupper/test1/test1.c
new file mode 100644
index 0000000000..63f051fa66
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/towupper/test1/test1.c
@@ -0,0 +1,65 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test1.c(towupper)
+**
+**
+** Purpose: Tests the PAL implementation of the towupper function.
+** Check that the towupper function makes lower case
+** character a capital. Also check that it has no effect
+** on upper case letters and special characters.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+struct testCase
+{
+ WCHAR upper;
+ WCHAR start;
+};
+
+int __cdecl main(int argc, char **argv)
+{
+
+ int result;
+ int i;
+
+ struct testCase testCases[] =
+ {
+ {'A', 'a'}, /* Basic cases */
+ {'Z', 'z'},
+ {'B', 'B'}, /* Upper case */
+ {'%', '%'}, /* Characters without case */
+ {157, 157}
+ };
+
+ if ((PAL_Initialize(argc, argv)) != 0)
+ {
+ return FAIL;
+ }
+
+
+ /* Loop through each case. Convert each character to upper case
+ and then compare to ensure that it is the correct value.
+ */
+
+ for(i = 0; i < sizeof(testCases) / sizeof(struct testCase); i++)
+ {
+ /*Convert to upper case*/
+ result = towupper(testCases[i].start);
+
+ if (testCases[i].upper != result)
+ {
+ Fail("ERROR: towupper capitalized \"%c\" to %c instead of %c.\n",
+ testCases[i].start, result, testCases[i].upper);
+ }
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/towupper/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/towupper/test1/testinfo.dat
new file mode 100644
index 0000000000..40b6fadd5a
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/towupper/test1/testinfo.dat
@@ -0,0 +1,19 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = towupper
+Name = Positive Test for towupper
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Tests the PAL implementation of the towupper function.
+= Check that the towupper function makes lower case character a capital.
+= Also check that it has no effect on upper case letters and special
+= characters.
+
+
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/ungetc/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/ungetc/CMakeLists.txt
new file mode 100644
index 0000000000..ef14ea5352
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/ungetc/CMakeLists.txt
@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+
diff --git a/src/pal/tests/palsuite/c_runtime/ungetc/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/ungetc/test1/CMakeLists.txt
new file mode 100644
index 0000000000..da19397e2c
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/ungetc/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ ungetc.c
+)
+
+add_executable(paltest_ungetc_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_ungetc_test1 coreclrpal)
+
+target_link_libraries(paltest_ungetc_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/ungetc/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/ungetc/test1/testinfo.dat
new file mode 100644
index 0000000000..08d5b0699a
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/ungetc/test1/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = c_runtime
+Function = ungetc
+Name = test for ungetc (test 1)
+Type = DEFAULT
+EXE1 = ungetc
+Description
+= Test how ungetc handles a write-only file (should fail)
diff --git a/src/pal/tests/palsuite/c_runtime/ungetc/test1/ungetc.c b/src/pal/tests/palsuite/c_runtime/ungetc/test1/ungetc.c
new file mode 100644
index 0000000000..397e42ac64
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/ungetc/test1/ungetc.c
@@ -0,0 +1,130 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: ungetc.c (test 1)
+**
+** Purpose: Tests the PAL implementation of the ungetc function by calling
+** the function on a write-only file.
+**
+** Dependencies:
+** fopen
+** fclose
+** fseek
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ char szFileName[] = {"test1.tmp"};
+ const char text[] =
+ {"The quick brown fox jumped over the lazy dog's back."};
+ FILE* pFile = NULL;
+ int nChar = 65; /* 'A' */
+ int nRc = 0;
+ int itemsExpected;
+ int itemsWritten;
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ /* create the file */
+ pFile = fopen(szFileName, "w");
+ if (pFile == NULL)
+ {
+ Fail("ungetc: ERROR -> fopen failed to create the file \"%s\""
+ " as write-only.\n",
+ szFileName);
+ }
+
+ /* write to the file */
+ itemsExpected = sizeof(text);
+ itemsWritten = fwrite(text, sizeof(text[0]), sizeof(text), pFile);
+ if (itemsWritten == 0)
+ {
+ Trace("ungetc: ERROR -> fwrite failed to write to the file \"%s\"\n",
+ szFileName);
+
+ if (fclose(pFile) != 0)
+ {
+ Fail("ungetc: ERROR -> fclose failed to close the file.\n");
+ }
+ Fail("");
+
+ }
+ else if (itemsWritten != itemsExpected)
+ {
+ Trace("ungetc: ERROR -> fwrite failed to write the correct number "
+ "of characters to the file \"%s\"\n",
+ szFileName);
+
+ if (fclose(pFile) != 0)
+ {
+ Fail("ungetc: ERROR -> fclose failed to close the file.\n");
+ }
+ Fail("");
+ }
+
+ /* Close the file */
+ if (fclose(pFile) != 0)
+ {
+ Fail("ungetc: ERROR -> fclose failed to close the file.\n");
+ }
+
+ /*
+ ** open the file in write only mode and
+ ** attempt to push an unread character back on the stream
+ */
+
+
+ /* open the file write-only */
+ pFile = fopen(szFileName, "a");
+ if (pFile == NULL)
+ {
+ Fail("ungetc: ERROR -> fopen failed to open the file \"%s\""
+ " as write-only.\n",
+ szFileName);
+ }
+
+ /* move the file pointer back to the beginning of the file */
+ if (fseek(pFile, 1, SEEK_SET) != 0)
+ {
+
+ Trace("ungetc: ERROR -> fseek failed to move the file pointer to the "
+ "beginning of the file.\n");
+ if (fclose(pFile) != 0)
+ {
+ Trace("ungetc: ERROR -> fclose failed to close the file.\n");
+ }
+ Fail("");
+ }
+
+ /* call ungetc on a write-only file which should fail */
+ if ((nRc = ungetc(nChar, pFile)) != EOF)
+ {
+ Trace("ungetc: ERROR -> ungetc returned \"%c\" when run on "
+ "an write-only file.\n", nChar);
+ if (fclose(pFile) != 0)
+ {
+ Trace("ungetc: ERROR -> fclose failed to close the file.\n");
+ }
+ Fail("");
+ }
+
+ if (fclose(pFile) != 0)
+ {
+ Fail("ungetc: ERROR -> fclose failed to close the file.\n");
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/ungetc/test2/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/ungetc/test2/CMakeLists.txt
new file mode 100644
index 0000000000..7b63423628
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/ungetc/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ ungetc.c
+)
+
+add_executable(paltest_ungetc_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_ungetc_test2 coreclrpal)
+
+target_link_libraries(paltest_ungetc_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/ungetc/test2/test2.txt b/src/pal/tests/palsuite/c_runtime/ungetc/test2/test2.txt
new file mode 100644
index 0000000000..96c906756d
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/ungetc/test2/test2.txt
@@ -0,0 +1 @@
+foo bar \ No newline at end of file
diff --git a/src/pal/tests/palsuite/c_runtime/ungetc/test2/testinfo.dat b/src/pal/tests/palsuite/c_runtime/ungetc/test2/testinfo.dat
new file mode 100644
index 0000000000..b942c931f5
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/ungetc/test2/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = c_runtime
+Function = ungetc
+Name = test for ungetc (test 2)
+Type = DEFAULT
+EXE1 = ungetc
+Description
+= Push characters back onto the stream and verify
diff --git a/src/pal/tests/palsuite/c_runtime/ungetc/test2/ungetc.c b/src/pal/tests/palsuite/c_runtime/ungetc/test2/ungetc.c
new file mode 100644
index 0000000000..cbc8102eec
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/ungetc/test2/ungetc.c
@@ -0,0 +1,188 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: ungetc.c (test 2)
+**
+** Purpose: Tests the PAL implementation of the ungetc function
+**
+** Dependencies:
+** fopen
+** fread
+** fclose
+** fseek
+** getc
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ const char szFileName[] = {"test2.txt"};
+ const char szNewString[] = {"bar bar"};
+ char szBuffer[MAX_PATH];
+ FILE* pFile = NULL;
+ int nChar = 32; /* space */
+ int i = 0;
+ int nRc = 0;
+ size_t nCount = 0;
+
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+
+ memset(szBuffer, 0, MAX_PATH);
+
+ /*
+ ** open the file in write only mode, populate it and
+ ** attempt to push an unread character back on the stream
+ */
+
+
+ /* open the file for read */
+ pFile = fopen(szFileName, "r");
+ if (pFile == NULL)
+ {
+ Fail("ungetc: ERROR -> fopen failed to open the file \"%s\""
+ " as read-only.n",
+ szFileName);
+ }
+
+
+ /*
+ ** Call getc to get the first char and ungetc to put
+ ** it back. getc should read it again.
+ */
+
+ /* read a character */
+ if ((nChar = getc(pFile)) == EOF)
+ {
+ Trace("ungetc: ERROR -> getc encountered an error reading.\n");
+ if (fclose(pFile) != 0)
+ {
+ Trace("ungetc: ERROR -> fclose failed to close the file.\n");
+ }
+ Fail("");
+ }
+
+ /* put it back */
+ if ((nRc = ungetc(nChar, pFile)) == EOF)
+ {
+ Trace("ungetc: ERROR -> ungetc failed to push '%c' back onto the"
+ " stream.\n");
+ if (fclose(pFile) != 0)
+ {
+ Trace("ungetc: ERROR -> fclose failed to close the file.\n");
+ }
+ Fail("");
+ }
+
+ /* read it again... hopefully */
+ if (((nChar = getc(pFile)) == EOF) || (nChar != nRc))
+ {
+ Trace("ungetc: ERROR -> getc encountered an error reading.\n");
+ if (fclose(pFile) != 0)
+ {
+ Trace("ungetc: ERROR -> fclose failed to close the file.\n");
+ }
+ Fail("");
+ }
+
+ /*
+ ** test multiple ungetcs by replacing "foo" in the stream with "bar"
+ */
+
+ /* move the file pointer back to the beginning of the file */
+ if (fseek(pFile, 0, SEEK_SET) != 0)
+ {
+ Trace("ungetc: ERROR -> fseek failed to move the file pointer to the "
+ "beginning of the file. GetLastError returned %ld\n",
+ GetLastError());
+ if (fclose(pFile) != 0)
+ {
+ Trace("ungetc: ERROR -> fclose failed to close the file.\n");
+ }
+ Fail("");
+ }
+
+ /* read a few characters */
+ for (i = 0; i < 3; i++)
+ {
+ if (getc(pFile) == EOF)
+ {
+ Trace("ungetc: ERROR -> getc encountered an error reading. "
+ "GetLastError returned %ld\n",
+ GetLastError());
+ if (fclose(pFile) != 0)
+ {
+ Trace("ungetc: ERROR -> fclose failed to close the file.\n");
+ }
+ Fail("");
+ }
+ }
+
+ /* we just read "foo" so push "bar" back on the stream */
+ for (i = 2; i >= 0; i--)
+ {
+ if ((nRc = ungetc(szNewString[i], pFile)) == EOF)
+ {
+ Trace("ungetc: ERROR -> ungetc failed to push '%c' back onto the"
+ " stream.\n");
+ if (fclose(pFile) != 0)
+ {
+ Trace("ungetc: ERROR -> fclose failed to close the file.\n");
+ }
+ Fail("");
+ }
+ }
+
+
+ /* read the new and improved stream - I use szNewString because it
+ is correct length */
+ nCount = fread(szBuffer, sizeof(char), strlen(szNewString), pFile);
+
+ /* did we get the right number of characters?*/
+ if (nCount != strlen(szNewString))
+ {
+ Trace("ungetc: ERROR -> fread read %d characters from the stream but"
+ " %d characters were expected\n",
+ nRc,
+ strlen(szNewString));
+ if (fclose(pFile) != 0)
+ {
+ Trace("ungetc: ERROR -> fclose failed to close the file.\n");
+ }
+ Fail("");
+ }
+
+ /* did we get the right string? */
+ if (strcmp(szBuffer, szNewString) != 0)
+ {
+ Trace("ungetc: ERROR -> fread returned \"%s\" but \"%s\" was "
+ "expected\n",
+ szBuffer,
+ szNewString);
+ if (fclose(pFile) != 0)
+ {
+ Trace("ungetc: ERROR -> fclose failed to close the file.\n");
+ }
+ Fail("");
+ }
+
+ if (fclose(pFile) != 0)
+ {
+ Fail("ungetc: ERROR -> fclose failed to close the file.\n");
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/vfprintf/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/vfprintf/CMakeLists.txt
new file mode 100644
index 0000000000..cafb9536b0
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vfprintf/CMakeLists.txt
@@ -0,0 +1,22 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test10)
+add_subdirectory(test11)
+add_subdirectory(test12)
+add_subdirectory(test13)
+add_subdirectory(test14)
+add_subdirectory(test15)
+add_subdirectory(test16)
+add_subdirectory(test17)
+add_subdirectory(test18)
+add_subdirectory(test19)
+add_subdirectory(test2)
+add_subdirectory(test3)
+add_subdirectory(test4)
+add_subdirectory(test5)
+add_subdirectory(test6)
+add_subdirectory(test7)
+add_subdirectory(test8)
+add_subdirectory(test9)
+
diff --git a/src/pal/tests/palsuite/c_runtime/vfprintf/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/vfprintf/test1/CMakeLists.txt
new file mode 100644
index 0000000000..4c967fbc5b
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vfprintf/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_vfprintf_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vfprintf_test1 coreclrpal)
+
+target_link_libraries(paltest_vfprintf_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/vfprintf/test1/test1.c b/src/pal/tests/palsuite/c_runtime/vfprintf/test1/test1.c
new file mode 100644
index 0000000000..302c914e3a
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vfprintf/test1/test1.c
@@ -0,0 +1,68 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Test #1 for the vfprintf function. A single, basic, test
+** case with no formatting.
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../vfprintf.h"
+
+int __cdecl main(int argc, char *argv[])
+{
+ FILE *fp;
+ char testfile[] = "testfile.txt";
+ char buf[256];
+ char checkstr[] = "hello world";
+ int ret;
+
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ if ((fp = fopen(testfile, "w+")) == NULL)
+ {
+ Fail("ERROR: fopen failed to create \"%s\"\n", testfile);
+ }
+
+ ret = DoVfprintf(fp, "hello world");
+
+ if (ret != strlen(checkstr))
+ {
+ Fail("Expected vfprintf to return %d, got %d.\n",
+ strlen(checkstr), ret);
+
+ }
+
+ if ((fseek(fp, 0, SEEK_SET)) != 0)
+ {
+ Fail("ERROR: Fseek failed to set pointer to beginning of file\n" );
+ }
+
+ if ((fgets(buf, 100, fp)) == NULL)
+ {
+ Fail("ERROR: fgets failed\n");
+ }
+ if (memcmp(checkstr, buf, strlen(checkstr)+1) != 0)
+ {
+ Fail("ERROR: expected %s, got %s\n", checkstr, buf);
+ }
+ if ((fclose(fp)) != 0)
+ {
+ Fail("ERROR: fclose failed to close \"%s\"\n", testfile);
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/vfprintf/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/vfprintf/test1/testinfo.dat
new file mode 100644
index 0000000000..8359de8e3d
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vfprintf/test1/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = vfprintf
+Name = Positive Test for vfprintf
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= General test to see if vfprintf works correctly
diff --git a/src/pal/tests/palsuite/c_runtime/vfprintf/test10/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/vfprintf/test10/CMakeLists.txt
new file mode 100644
index 0000000000..e154107e36
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vfprintf/test10/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test10.c
+)
+
+add_executable(paltest_vfprintf_test10
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vfprintf_test10 coreclrpal)
+
+target_link_libraries(paltest_vfprintf_test10
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/vfprintf/test10/test10.c b/src/pal/tests/palsuite/c_runtime/vfprintf/test10/test10.c
new file mode 100644
index 0000000000..ecb4b0314a
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vfprintf/test10/test10.c
@@ -0,0 +1,52 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test10.c
+**
+** Purpose: Test #10 for the vfprintf function. Tests the octal specifier
+** (%o).
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../vfprintf.h"
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ int neg = -42;
+ int pos = 42;
+ INT64 l = 42;
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ DoNumTest("foo %o", pos, "foo 52");
+ DoNumTest("foo %lo", 0xFFFF, "foo 177777");
+ DoNumTest("foo %ho", 0xFFFF, "foo 177777");
+ DoNumTest("foo %Lo", pos, "foo 52");
+ DoI64Test("foo %I64o", l, "42", "foo 52");
+ DoNumTest("foo %3o", pos, "foo 52");
+ DoNumTest("foo %-3o", pos, "foo 52 ");
+ DoNumTest("foo %.1o", pos, "foo 52");
+ DoNumTest("foo %.3o", pos, "foo 052");
+ DoNumTest("foo %03o", pos, "foo 052");
+ DoNumTest("foo %#o", pos, "foo 052");
+ DoNumTest("foo %+o", pos, "foo 52");
+ DoNumTest("foo % o", pos, "foo 52");
+ DoNumTest("foo %+o", neg, "foo 37777777726");
+ DoNumTest("foo % o", neg, "foo 37777777726");
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/vfprintf/test10/testinfo.dat b/src/pal/tests/palsuite/c_runtime/vfprintf/test10/testinfo.dat
new file mode 100644
index 0000000000..034610a7dc
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vfprintf/test10/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = vfprintf
+Name = Positive Test for vfprintf
+TYPE = DEFAULT
+EXE1 = test10
+Description
+= Tests vfprintf with octal numbers
diff --git a/src/pal/tests/palsuite/c_runtime/vfprintf/test11/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/vfprintf/test11/CMakeLists.txt
new file mode 100644
index 0000000000..f51f379bcd
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vfprintf/test11/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test11.c
+)
+
+add_executable(paltest_vfprintf_test11
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vfprintf_test11 coreclrpal)
+
+target_link_libraries(paltest_vfprintf_test11
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/vfprintf/test11/test11.c b/src/pal/tests/palsuite/c_runtime/vfprintf/test11/test11.c
new file mode 100644
index 0000000000..5f7bc118cc
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vfprintf/test11/test11.c
@@ -0,0 +1,51 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test11.c
+**
+** Purpose: Test #11 for the vfprintf function. Test the unsigned int
+** specifier (%u).
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../vfprintf.h"
+
+int __cdecl main(int argc, char *argv[])
+{
+ int neg = -42;
+ int pos = 42;
+ INT64 l = 42;
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ DoNumTest("foo %u", pos, "foo 42");
+ DoNumTest("foo %lu", 0xFFFF, "foo 65535");
+ DoNumTest("foo %hu", 0xFFFF, "foo 65535");
+ DoNumTest("foo %Lu", pos, "foo 42");
+ DoI64Test("foo %I64u", l, "42", "foo 42");
+ DoNumTest("foo %3u", pos, "foo 42");
+ DoNumTest("foo %-3u", pos, "foo 42 ");
+ DoNumTest("foo %.1u", pos, "foo 42");
+ DoNumTest("foo %.3u", pos, "foo 042");
+ DoNumTest("foo %03u", pos, "foo 042");
+ DoNumTest("foo %#u", pos, "foo 42");
+ DoNumTest("foo %+u", pos, "foo 42");
+ DoNumTest("foo % u", pos, "foo 42");
+ DoNumTest("foo %+u", neg, "foo 4294967254");
+ DoNumTest("foo % u", neg, "foo 4294967254");
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/vfprintf/test11/testinfo.dat b/src/pal/tests/palsuite/c_runtime/vfprintf/test11/testinfo.dat
new file mode 100644
index 0000000000..4050bd610e
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vfprintf/test11/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = vfprintf
+Name = Positive Test for vfprintf
+TYPE = DEFAULT
+EXE1 = test11
+Description
+= Tests vfprintf with unsigned numbers
diff --git a/src/pal/tests/palsuite/c_runtime/vfprintf/test12/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/vfprintf/test12/CMakeLists.txt
new file mode 100644
index 0000000000..3ef68cff70
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vfprintf/test12/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test12.c
+)
+
+add_executable(paltest_vfprintf_test12
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vfprintf_test12 coreclrpal)
+
+target_link_libraries(paltest_vfprintf_test12
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/vfprintf/test12/test12.c b/src/pal/tests/palsuite/c_runtime/vfprintf/test12/test12.c
new file mode 100644
index 0000000000..0bf61d3ecc
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vfprintf/test12/test12.c
@@ -0,0 +1,53 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test12.c
+**
+** Purpose: Test #12 for the vfprintf function. Tests the (lowercase)
+** hexadecimal specifier (%x)
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../vfprintf.h"
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ int neg = -42;
+ int pos = 0x1234ab;
+ INT64 l = I64(0x1234567887654321);
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ DoNumTest("foo %x", pos, "foo 1234ab");
+ DoNumTest("foo %lx", pos, "foo 1234ab");
+ DoNumTest("foo %hx", pos, "foo 34ab");
+ DoNumTest("foo %Lx", pos, "foo 1234ab");
+ DoI64Test("foo %I64x", l, "0x1234567887654321",
+ "foo 1234567887654321");
+ DoNumTest("foo %7x", pos, "foo 1234ab");
+ DoNumTest("foo %-7x", pos, "foo 1234ab ");
+ DoNumTest("foo %.1x", pos, "foo 1234ab");
+ DoNumTest("foo %.7x", pos, "foo 01234ab");
+ DoNumTest("foo %07x", pos, "foo 01234ab");
+ DoNumTest("foo %#x", pos, "foo 0x1234ab");
+ DoNumTest("foo %+x", pos, "foo 1234ab");
+ DoNumTest("foo % x", pos, "foo 1234ab");
+ DoNumTest("foo %+x", neg, "foo ffffffd6");
+ DoNumTest("foo % x", neg, "foo ffffffd6");
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/vfprintf/test12/testinfo.dat b/src/pal/tests/palsuite/c_runtime/vfprintf/test12/testinfo.dat
new file mode 100644
index 0000000000..640af62aff
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vfprintf/test12/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = vfprintf
+Name = Positive Test for vfprintf
+TYPE = DEFAULT
+EXE1 = test12
+Description
+= Tests vfprintf with hex numbers (lowercase)
diff --git a/src/pal/tests/palsuite/c_runtime/vfprintf/test13/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/vfprintf/test13/CMakeLists.txt
new file mode 100644
index 0000000000..cd34f6649c
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vfprintf/test13/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test13.c
+)
+
+add_executable(paltest_vfprintf_test13
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vfprintf_test13 coreclrpal)
+
+target_link_libraries(paltest_vfprintf_test13
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/vfprintf/test13/test13.c b/src/pal/tests/palsuite/c_runtime/vfprintf/test13/test13.c
new file mode 100644
index 0000000000..1e42ce9e8d
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vfprintf/test13/test13.c
@@ -0,0 +1,54 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test13.c
+**
+** Purpose: Test #13 for the vfprintf function. Tests the (uppercase)
+** hexadecimal specifier (%X)
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../vfprintf.h"
+
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ int neg = -42;
+ int pos = 0x1234AB;
+ INT64 l = I64(0x1234567887654321);
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ DoNumTest("foo %X", pos, "foo 1234AB");
+ DoNumTest("foo %lX", pos, "foo 1234AB");
+ DoNumTest("foo %hX", pos, "foo 34AB");
+ DoNumTest("foo %LX", pos, "foo 1234AB");
+ DoI64Test("foo %I64X", l, "0x1234567887654321",
+ "foo 1234567887654321");
+ DoNumTest("foo %7X", pos, "foo 1234AB");
+ DoNumTest("foo %-7X", pos, "foo 1234AB ");
+ DoNumTest("foo %.1X", pos, "foo 1234AB");
+ DoNumTest("foo %.7X", pos, "foo 01234AB");
+ DoNumTest("foo %07X", pos, "foo 01234AB");
+ DoNumTest("foo %#X", pos, "foo 0X1234AB");
+ DoNumTest("foo %+X", pos, "foo 1234AB");
+ DoNumTest("foo % X", pos, "foo 1234AB");
+ DoNumTest("foo %+X", neg, "foo FFFFFFD6");
+ DoNumTest("foo % X", neg, "foo FFFFFFD6");
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/vfprintf/test13/testinfo.dat b/src/pal/tests/palsuite/c_runtime/vfprintf/test13/testinfo.dat
new file mode 100644
index 0000000000..26c7db0523
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vfprintf/test13/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = vfprintf
+Name = Positive Test for vfprintf
+TYPE = DEFAULT
+EXE1 = test13
+Description
+= Tests vfprintf with hex numbers (uppercase)
diff --git a/src/pal/tests/palsuite/c_runtime/vfprintf/test14/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/vfprintf/test14/CMakeLists.txt
new file mode 100644
index 0000000000..396a4631c5
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vfprintf/test14/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test14.c
+)
+
+add_executable(paltest_vfprintf_test14
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vfprintf_test14 coreclrpal)
+
+target_link_libraries(paltest_vfprintf_test14
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/vfprintf/test14/test14.c b/src/pal/tests/palsuite/c_runtime/vfprintf/test14/test14.c
new file mode 100644
index 0000000000..82f247430f
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vfprintf/test14/test14.c
@@ -0,0 +1,54 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test14.c
+**
+** Purpose: Test #14 for the vfprintf function. Tests the lowercase
+** exponential notation double specifier (%e)
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../vfprintf.h"
+
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ double val = 256.0;
+ double neg = -256.0;
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ DoDoubleTest("foo %e", val, "foo 2.560000e+002", "foo 2.560000e+02");
+ DoDoubleTest("foo %le", val, "foo 2.560000e+002", "foo 2.560000e+02");
+ DoDoubleTest("foo %he", val, "foo 2.560000e+002", "foo 2.560000e+02");
+ DoDoubleTest("foo %Le", val, "foo 2.560000e+002", "foo 2.560000e+02");
+ DoDoubleTest("foo %I64e", val, "foo 2.560000e+002", "foo 2.560000e+02");
+ DoDoubleTest("foo %14e", val, "foo 2.560000e+002", "foo 2.560000e+02");
+ DoDoubleTest("foo %-14e", val, "foo 2.560000e+002 ",
+ "foo 2.560000e+02 ");
+ DoDoubleTest("foo %.1e", val, "foo 2.6e+002", "foo 2.6e+02");
+ DoDoubleTest("foo %.8e", val, "foo 2.56000000e+002",
+ "foo 2.56000000e+02");
+ DoDoubleTest("foo %014e", val, "foo 02.560000e+002",
+ "foo 002.560000e+02");
+ DoDoubleTest("foo %#e", val, "foo 2.560000e+002", "foo 2.560000e+02");
+ DoDoubleTest("foo %+e", val, "foo +2.560000e+002", "foo +2.560000e+02");
+ DoDoubleTest("foo % e", val, "foo 2.560000e+002", "foo 2.560000e+02");
+ DoDoubleTest("foo %+e", neg, "foo -2.560000e+002", "foo -2.560000e+02");
+ DoDoubleTest("foo % e", neg, "foo -2.560000e+002", "foo -2.560000e+02");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/vfprintf/test14/testinfo.dat b/src/pal/tests/palsuite/c_runtime/vfprintf/test14/testinfo.dat
new file mode 100644
index 0000000000..fa36319311
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vfprintf/test14/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = vfprintf
+Name = Positive Test for vfprintf
+TYPE = DEFAULT
+EXE1 = test14
+Description
+= Tests vfprintf with exponential format doubles (lowercase)
diff --git a/src/pal/tests/palsuite/c_runtime/vfprintf/test15/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/vfprintf/test15/CMakeLists.txt
new file mode 100644
index 0000000000..b9ddbe3b4a
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vfprintf/test15/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test15.c
+)
+
+add_executable(paltest_vfprintf_test15
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vfprintf_test15 coreclrpal)
+
+target_link_libraries(paltest_vfprintf_test15
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/vfprintf/test15/test15.c b/src/pal/tests/palsuite/c_runtime/vfprintf/test15/test15.c
new file mode 100644
index 0000000000..53cc2ceb87
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vfprintf/test15/test15.c
@@ -0,0 +1,54 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test15.c
+**
+** Purpose: Test #15 for the vfprintf function. Tests the uppercase
+** exponential notation double specifier (%E)
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../vfprintf.h"
+
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ double val = 256.0;
+ double neg = -256.0;
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ DoDoubleTest("foo %E", val, "foo 2.560000E+002", "foo 2.560000E+02");
+ DoDoubleTest("foo %lE", val, "foo 2.560000E+002", "foo 2.560000E+02");
+ DoDoubleTest("foo %hE", val, "foo 2.560000E+002", "foo 2.560000E+02");
+ DoDoubleTest("foo %LE", val, "foo 2.560000E+002", "foo 2.560000E+02");
+ DoDoubleTest("foo %I64E", val, "foo 2.560000E+002", "foo 2.560000E+02");
+ DoDoubleTest("foo %14E", val, "foo 2.560000E+002", "foo 2.560000E+02");
+ DoDoubleTest("foo %-14E", val, "foo 2.560000E+002 ",
+ "foo 2.560000E+02 ");
+ DoDoubleTest("foo %.1E", val, "foo 2.6E+002", "foo 2.6E+02");
+ DoDoubleTest("foo %.8E", val, "foo 2.56000000E+002",
+ "foo 2.56000000E+02");
+ DoDoubleTest("foo %014E", val, "foo 02.560000E+002",
+ "foo 002.560000E+02");
+ DoDoubleTest("foo %#E", val, "foo 2.560000E+002", "foo 2.560000E+02");
+ DoDoubleTest("foo %+E", val, "foo +2.560000E+002", "foo +2.560000E+02");
+ DoDoubleTest("foo % E", val, "foo 2.560000E+002", "foo 2.560000E+02");
+ DoDoubleTest("foo %+E", neg, "foo -2.560000E+002", "foo -2.560000E+02");
+ DoDoubleTest("foo % E", neg, "foo -2.560000E+002", "foo -2.560000E+02");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/vfprintf/test15/testinfo.dat b/src/pal/tests/palsuite/c_runtime/vfprintf/test15/testinfo.dat
new file mode 100644
index 0000000000..f51f72c122
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vfprintf/test15/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = vfprintf
+Name = Positive Test for vfprintf
+TYPE = DEFAULT
+EXE1 = test15
+Description
+= Tests vfprintf with exponential format doubles (uppercase)
diff --git a/src/pal/tests/palsuite/c_runtime/vfprintf/test16/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/vfprintf/test16/CMakeLists.txt
new file mode 100644
index 0000000000..0fd4177ed8
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vfprintf/test16/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test16.c
+)
+
+add_executable(paltest_vfprintf_test16
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vfprintf_test16 coreclrpal)
+
+target_link_libraries(paltest_vfprintf_test16
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/vfprintf/test16/test16.c b/src/pal/tests/palsuite/c_runtime/vfprintf/test16/test16.c
new file mode 100644
index 0000000000..2b7674bb94
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vfprintf/test16/test16.c
@@ -0,0 +1,50 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test16.c
+**
+** Purpose: Test #16 for the vfprintf function. Tests the decimal notation
+** double specifier (%f)
+**
+**
+**==========================================================================*/
+
+
+#include <palsuite.h>
+#include "../vfprintf.h"
+
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ double val = 2560.001;
+ double neg = -2560.001;
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ DoDoubleTest("foo %f", val, "foo 2560.001000", "foo 2560.001000");
+ DoDoubleTest("foo %lf", val, "foo 2560.001000", "foo 2560.001000");
+ DoDoubleTest("foo %hf", val, "foo 2560.001000", "foo 2560.001000");
+ DoDoubleTest("foo %Lf", val, "foo 2560.001000", "foo 2560.001000");
+ DoDoubleTest("foo %I64f", val, "foo 2560.001000", "foo 2560.001000");
+ DoDoubleTest("foo %12f", val, "foo 2560.001000", "foo 2560.001000");
+ DoDoubleTest("foo %-12f", val, "foo 2560.001000 ", "foo 2560.001000 ");
+ DoDoubleTest("foo %.1f", val, "foo 2560.0", "foo 2560.0");
+ DoDoubleTest("foo %.8f", val, "foo 2560.00100000", "foo 2560.00100000");
+ DoDoubleTest("foo %012f", val, "foo 02560.001000", "foo 02560.001000");
+ DoDoubleTest("foo %#f", val, "foo 2560.001000", "foo 2560.001000");
+ DoDoubleTest("foo %+f", val, "foo +2560.001000", "foo +2560.001000");
+ DoDoubleTest("foo % f", val, "foo 2560.001000", "foo 2560.001000");
+ DoDoubleTest("foo %+f", neg, "foo -2560.001000", "foo -2560.001000");
+ DoDoubleTest("foo % f", neg, "foo -2560.001000", "foo -2560.001000");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/vfprintf/test16/testinfo.dat b/src/pal/tests/palsuite/c_runtime/vfprintf/test16/testinfo.dat
new file mode 100644
index 0000000000..f91d9f429c
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vfprintf/test16/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = vfprintf
+Name = Positive Test for vfprintf
+TYPE = DEFAULT
+EXE1 = test16
+Description
+= Tests vfprintf with decimal point format doubles
diff --git a/src/pal/tests/palsuite/c_runtime/vfprintf/test17/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/vfprintf/test17/CMakeLists.txt
new file mode 100644
index 0000000000..afc0b3828d
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vfprintf/test17/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test17.c
+)
+
+add_executable(paltest_vfprintf_test17
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vfprintf_test17 coreclrpal)
+
+target_link_libraries(paltest_vfprintf_test17
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/vfprintf/test17/test17.c b/src/pal/tests/palsuite/c_runtime/vfprintf/test17/test17.c
new file mode 100644
index 0000000000..956be15f6f
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vfprintf/test17/test17.c
@@ -0,0 +1,52 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test17.c
+**
+** Purpose: Test #17 for the vfprintf function. Tests the lowercase
+** shorthand notation double specifier (%g)
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../vfprintf.h"
+
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ double val = 2560.001;
+ double neg = -2560.001;
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ DoDoubleTest("foo %g", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %lg", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %hg", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %Lg", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %I64g", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %5g", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %-5g", val, "foo 2560 ", "foo 2560 ");
+ DoDoubleTest("foo %.1g", val, "foo 3e+003", "foo 3e+03");
+ DoDoubleTest("foo %.2g", val, "foo 2.6e+003", "foo 2.6e+03");
+ DoDoubleTest("foo %.12g", val, "foo 2560.001", "foo 2560.001");
+ DoDoubleTest("foo %06g", val, "foo 002560", "foo 002560");
+ DoDoubleTest("foo %#g", val, "foo 2560.00", "foo 2560.00");
+ DoDoubleTest("foo %+g", val, "foo +2560", "foo +2560");
+ DoDoubleTest("foo % g", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %+g", neg, "foo -2560", "foo -2560");
+ DoDoubleTest("foo % g", neg, "foo -2560", "foo -2560");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/vfprintf/test17/testinfo.dat b/src/pal/tests/palsuite/c_runtime/vfprintf/test17/testinfo.dat
new file mode 100644
index 0000000000..623846465f
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vfprintf/test17/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = vfprintf
+Name = Positive Test for vfprintf
+TYPE = DEFAULT
+EXE1 = test17
+Description
+= Tests vfprintf with compact format doubles (lowercase)
diff --git a/src/pal/tests/palsuite/c_runtime/vfprintf/test18/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/vfprintf/test18/CMakeLists.txt
new file mode 100644
index 0000000000..9e373b999e
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vfprintf/test18/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test18.c
+)
+
+add_executable(paltest_vfprintf_test18
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vfprintf_test18 coreclrpal)
+
+target_link_libraries(paltest_vfprintf_test18
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/vfprintf/test18/test18.c b/src/pal/tests/palsuite/c_runtime/vfprintf/test18/test18.c
new file mode 100644
index 0000000000..c61c8cbdab
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vfprintf/test18/test18.c
@@ -0,0 +1,51 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test18.c
+**
+** Purpose: Test #18 for the vfprintf function. Tests the uppercase
+** shorthand notation double specifier (%G)
+**
+**
+**==========================================================================*/
+
+
+#include <palsuite.h>
+#include "../vfprintf.h"
+
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ double val = 2560.001;
+ double neg = -2560.001;
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ DoDoubleTest("foo %G", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %lG", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %hG", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %LG", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %I64G", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %5G", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %-5G", val, "foo 2560 ", "foo 2560 ");
+ DoDoubleTest("foo %.1G", val, "foo 3E+003", "foo 3E+03");
+ DoDoubleTest("foo %.2G", val, "foo 2.6E+003", "foo 2.6E+03");
+ DoDoubleTest("foo %.12G", val, "foo 2560.001", "foo 2560.001");
+ DoDoubleTest("foo %06G", val, "foo 002560", "foo 002560");
+ DoDoubleTest("foo %#G", val, "foo 2560.00", "foo 2560.00");
+ DoDoubleTest("foo %+G", val, "foo +2560", "foo +2560");
+ DoDoubleTest("foo % G", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %+G", neg, "foo -2560", "foo -2560");
+ DoDoubleTest("foo % G", neg, "foo -2560", "foo -2560");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/vfprintf/test18/testinfo.dat b/src/pal/tests/palsuite/c_runtime/vfprintf/test18/testinfo.dat
new file mode 100644
index 0000000000..44ddab30bc
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vfprintf/test18/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = vfprintf
+Name = Positive Test for vfprintf
+TYPE = DEFAULT
+EXE1 = test18
+Description
+= Tests vfprintf with compact format doubles (uppercase)
diff --git a/src/pal/tests/palsuite/c_runtime/vfprintf/test19/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/vfprintf/test19/CMakeLists.txt
new file mode 100644
index 0000000000..3120c9117f
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vfprintf/test19/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test19.c
+)
+
+add_executable(paltest_vfprintf_test19
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vfprintf_test19 coreclrpal)
+
+target_link_libraries(paltest_vfprintf_test19
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/vfprintf/test19/test19.c b/src/pal/tests/palsuite/c_runtime/vfprintf/test19/test19.c
new file mode 100644
index 0000000000..e88ce23663
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vfprintf/test19/test19.c
@@ -0,0 +1,76 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test19.c
+**
+** Purpose: Test #19 for the vfprintf function. Tests the variable length
+** precision argument.
+**
+**
+**==========================================================================*/
+
+
+#include <palsuite.h>
+#include "../vfprintf.h"
+
+
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ int n = -1;
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ DoArgumentPrecTest("%.*s", 2, "bar", "bar", "ba", "ba");
+ DoArgumentPrecTest("%.*S", 2, convert("bar"), "bar", "ba", "ba");
+
+ DoArgumentPrecTest("%.*n ", 3, &n, "pointer to int", " ", " ");
+ if (n != 0)
+ {
+ Fail("ERROR: Expected count parameter to resolve to %d, got %X\n",
+ 0, n);
+ }
+
+ DoArgumentPrecTest("%.*c", 0, (void*)'a', "a", "a", "a");
+ DoArgumentPrecTest("%.*c", 4, (void*)'a', "a", "a", "a");
+ DoArgumentPrecTest("%.*C", 0, (void*)'a', "a", "a", "a");
+ DoArgumentPrecTest("%.*C", 4, (void*)'a', "a", "a", "a");
+ DoArgumentPrecTest("%.*d", 1, (void*)42, "42", "42", "42");
+ DoArgumentPrecTest("%.*d", 3, (void*)42, "42", "042", "042");
+ DoArgumentPrecTest("%.*i", 1, (void*)42, "42", "42", "42");
+ DoArgumentPrecTest("%.*i", 3, (void*)42, "42", "042", "042");
+ DoArgumentPrecTest("%.*o", 1, (void*)42, "42", "52", "52");
+ DoArgumentPrecTest("%.*o", 3, (void*)42, "42", "052", "052");
+ DoArgumentPrecTest("%.*u", 1, (void*)42, "42", "42", "42");
+ DoArgumentPrecTest("%.*u", 3, (void*)42, "42", "042", "042");
+ DoArgumentPrecTest("%.*x", 1, (void*)0x42, "0x42", "42", "42");
+ DoArgumentPrecTest("%.*x", 3, (void*)0x42, "0x42", "042", "042");
+ DoArgumentPrecTest("%.*X", 1, (void*)0x42, "0x42", "42", "42");
+ DoArgumentPrecTest("%.*X", 3, (void*)0x42, "0x42", "042", "042");
+
+
+ DoArgumentPrecDoubleTest("%.*e", 1, 2.01, "2.0e+000", "2.0e+00");
+ DoArgumentPrecDoubleTest("%.*e", 3, 2.01, "2.010e+000", "2.010e+00");
+ DoArgumentPrecDoubleTest("%.*E", 1, 2.01, "2.0E+000", "2.0E+00");
+ DoArgumentPrecDoubleTest("%.*E", 3, 2.01, "2.010E+000", "2.010E+00");
+ DoArgumentPrecDoubleTest("%.*f", 1, 2.01, "2.0", "2.0");
+ DoArgumentPrecDoubleTest("%.*f", 3, 2.01, "2.010", "2.010");
+ DoArgumentPrecDoubleTest("%.*g", 1, 256.01, "3e+002", "3e+02");
+ DoArgumentPrecDoubleTest("%.*g", 3, 256.01, "256", "256");
+ DoArgumentPrecDoubleTest("%.*g", 4, 256.01, "256", "256");
+ DoArgumentPrecDoubleTest("%.*g", 6, 256.01, "256.01", "256.01");
+ DoArgumentPrecDoubleTest("%.*G", 1, 256.01, "3E+002", "3E+02");
+ DoArgumentPrecDoubleTest("%.*G", 3, 256.01, "256", "256");
+ DoArgumentPrecDoubleTest("%.*G", 4, 256.01, "256", "256");
+ DoArgumentPrecDoubleTest("%.*G", 6, 256.01, "256.01", "256.01");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/vfprintf/test19/testinfo.dat b/src/pal/tests/palsuite/c_runtime/vfprintf/test19/testinfo.dat
new file mode 100644
index 0000000000..729c279608
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vfprintf/test19/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = vfprintf
+Name = Positive Test for vfprintf
+TYPE = DEFAULT
+EXE1 = test19
+Description
+= Tests vfprintf with argument specified precision
diff --git a/src/pal/tests/palsuite/c_runtime/vfprintf/test2/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/vfprintf/test2/CMakeLists.txt
new file mode 100644
index 0000000000..6e700090d6
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vfprintf/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test2.c
+)
+
+add_executable(paltest_vfprintf_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vfprintf_test2 coreclrpal)
+
+target_link_libraries(paltest_vfprintf_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/vfprintf/test2/test2.c b/src/pal/tests/palsuite/c_runtime/vfprintf/test2/test2.c
new file mode 100644
index 0000000000..d01117f047
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vfprintf/test2/test2.c
@@ -0,0 +1,45 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test2.c
+**
+** Purpose: Test #2 for the vfprintf function. Tests the string specifier
+** (%s).
+**
+**
+**==========================================================================*/
+
+
+#include <palsuite.h>
+#include "../vfprintf.h"
+
+
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ DoStrTest("foo %s", "bar", "foo bar");
+ DoStrTest("foo %hs", "bar", "foo bar");
+ DoWStrTest("foo %ls", convert("bar"), "foo bar");
+ DoWStrTest("foo %ws", convert("bar"), "foo bar");
+ DoStrTest("foo %Ls", "bar", "foo bar");
+ DoStrTest("foo %I64s", "bar", "foo bar");
+ DoStrTest("foo %5s", "bar", "foo bar");
+ DoStrTest("foo %.2s", "bar", "foo ba");
+ DoStrTest("foo %5.2s", "bar", "foo ba");
+ DoStrTest("foo %-5s", "bar", "foo bar ");
+ DoStrTest("foo %05s", "bar", "foo 00bar");
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/vfprintf/test2/testinfo.dat b/src/pal/tests/palsuite/c_runtime/vfprintf/test2/testinfo.dat
new file mode 100644
index 0000000000..6d2f231566
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vfprintf/test2/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = vfprintf
+Name = Positive Test for vfprintf
+TYPE = DEFAULT
+EXE1 = test2
+Description
+= Tests vfprintf with strings
diff --git a/src/pal/tests/palsuite/c_runtime/vfprintf/test3/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/vfprintf/test3/CMakeLists.txt
new file mode 100644
index 0000000000..1a14d85603
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vfprintf/test3/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test3.c
+)
+
+add_executable(paltest_vfprintf_test3
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vfprintf_test3 coreclrpal)
+
+target_link_libraries(paltest_vfprintf_test3
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/vfprintf/test3/test3.c b/src/pal/tests/palsuite/c_runtime/vfprintf/test3/test3.c
new file mode 100644
index 0000000000..0081daa426
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vfprintf/test3/test3.c
@@ -0,0 +1,45 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test3.c
+**
+** Purpose: Test #3 for the vfprintf function. Tests the wide string
+** specifier (%S).
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../vfprintf.h"
+
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ DoWStrTest("foo %S", convert("bar"), "foo bar");
+ DoStrTest("foo %hS", "bar", "foo bar");
+ DoWStrTest("foo %lS", convert("bar"), "foo bar");
+ DoWStrTest("foo %wS", convert("bar"), "foo bar");
+ DoWStrTest("foo %LS", convert("bar"), "foo bar");
+ DoWStrTest("foo %I64S", convert("bar"), "foo bar");
+ DoWStrTest("foo %5S", convert("bar"), "foo bar");
+ DoWStrTest("foo %.2S", convert("bar"), "foo ba");
+ DoWStrTest("foo %5.2S", convert("bar"), "foo ba");
+ DoWStrTest("foo %-5S", convert("bar"), "foo bar ");
+ DoWStrTest("foo %05S", convert("bar"), "foo 00bar");
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/vfprintf/test3/testinfo.dat b/src/pal/tests/palsuite/c_runtime/vfprintf/test3/testinfo.dat
new file mode 100644
index 0000000000..b5aa1e2f07
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vfprintf/test3/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = vfprintf
+Name = Positive Test for vfprintf
+TYPE = DEFAULT
+EXE1 = test3
+Description
+= Tests vfprintf with wide strings
diff --git a/src/pal/tests/palsuite/c_runtime/vfprintf/test4/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/vfprintf/test4/CMakeLists.txt
new file mode 100644
index 0000000000..c1285942bc
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vfprintf/test4/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test4.c
+)
+
+add_executable(paltest_vfprintf_test4
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vfprintf_test4 coreclrpal)
+
+target_link_libraries(paltest_vfprintf_test4
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/vfprintf/test4/test4.c b/src/pal/tests/palsuite/c_runtime/vfprintf/test4/test4.c
new file mode 100644
index 0000000000..d24f08d6e0
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vfprintf/test4/test4.c
@@ -0,0 +1,70 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test4.c
+**
+** Purpose: Test #4 for the vfprintf function. Tests the pointer
+** specifier (%p).
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../vfprintf.h"
+
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ void *ptr = (void*) 0x123456;
+ INT64 lptr = I64(0x1234567887654321);
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+/*
+** Run only on 64 bit platforms
+*/
+#if defined(BIT64) && defined(PLATFORM_UNIX)
+ Trace("Testing for 64 Bit Platforms \n");
+ DoPointerTest("%p", NULL, "NULL", "0000000000000000");
+ DoPointerTest("%p", ptr, "pointer to 0x123456", "0000000000123456");
+ DoPointerTest("%17p", ptr, "pointer to 0x123456", " 0000000000123456");
+ DoPointerTest("%17p", ptr, "pointer to 0x123456", " 0000000000123456");
+ DoPointerTest("%-17p", ptr, "pointer to 0x123456", "0000000000123456 ");
+ DoPointerTest("%+p", ptr, "pointer to 0x123456", "0000000000123456");
+ DoPointerTest("%#p", ptr, "pointer to 0x123456", "0X0000000000123456");
+ DoPointerTest("%lp", ptr, "pointer to 0x123456", "00123456");
+ DoPointerTest("%hp", ptr, "pointer to 0x123456", "00003456");
+ DoPointerTest("%Lp", ptr, "pointer to 0x123456", "00123456");
+ DoI64Test("%I64p", lptr, "pointer to 0x1234567887654321",
+ "1234567887654321");
+
+#else
+ Trace("Testing for Non 64 Bit Platforms \n");
+ DoPointerTest("%p", NULL, "NULL", "00000000");
+ DoPointerTest("%p", ptr, "pointer to 0x123456", "00123456");
+ DoPointerTest("%9p", ptr, "pointer to 0x123456", " 00123456");
+ DoPointerTest("%09p", ptr, "pointer to 0x123456", " 00123456");
+ DoPointerTest("%-9p", ptr, "pointer to 0x123456", "00123456 ");
+ DoPointerTest("%+p", ptr, "pointer to 0x123456", "00123456");
+ DoPointerTest("%#p", ptr, "pointer to 0x123456", "0X00123456");
+ DoPointerTest("%lp", ptr, "pointer to 0x123456", "00123456");
+ DoPointerTest("%hp", ptr, "pointer to 0x123456", "00003456");
+ DoPointerTest("%Lp", ptr, "pointer to 0x123456", "00123456");
+ DoI64Test("%I64p", lptr, "pointer to 0x1234567887654321",
+ "1234567887654321");
+
+#endif
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/vfprintf/test4/testinfo.dat b/src/pal/tests/palsuite/c_runtime/vfprintf/test4/testinfo.dat
new file mode 100644
index 0000000000..d08928a8b6
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vfprintf/test4/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = vfprintf
+Name = Positive Test for vfprintf
+TYPE = DEFAULT
+EXE1 = test4
+Description
+= Tests vfprintf with pointers
diff --git a/src/pal/tests/palsuite/c_runtime/vfprintf/test5/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/vfprintf/test5/CMakeLists.txt
new file mode 100644
index 0000000000..0cccdfd630
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vfprintf/test5/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test5.c
+)
+
+add_executable(paltest_vfprintf_test5
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vfprintf_test5 coreclrpal)
+
+target_link_libraries(paltest_vfprintf_test5
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/vfprintf/test5/test5.c b/src/pal/tests/palsuite/c_runtime/vfprintf/test5/test5.c
new file mode 100644
index 0000000000..44f21b61db
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vfprintf/test5/test5.c
@@ -0,0 +1,60 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test5.c
+**
+** Purpose: Test #5 for the vfprintf function. Tests the count specifier (%n).
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../vfprintf.h"
+
+
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ char *longStr =
+ "really-long-string-that-just-keeps-going-on-and-on-and-on.."
+ "..................useless-filler.................................."
+ "..................useless-filler.................................."
+ "..................useless-filler.................................."
+ "%n bar";
+ char *longResult =
+ "really-long-string-that-just-keeps-going-on-and-on-and-on.."
+ "..................useless-filler.................................."
+ "..................useless-filler.................................."
+ "..................useless-filler.................................."
+ " bar";
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ DoCountTest("foo %n bar", 4, "foo bar");
+ DoCountTest(longStr, 257, longResult);
+ DoCountTest("fo%n bar", 2, "fo bar");
+ DoCountTest("%n ", 0, " ");
+ DoCountTest("foo %#n bar", 4, "foo bar");
+ DoCountTest("foo % n bar", 4, "foo bar");
+ DoCountTest("foo %+n bar", 4, "foo bar");
+ DoCountTest("foo %-n bar", 4, "foo bar");
+ DoCountTest("foo %0n bar", 4, "foo bar");
+ DoShortCountTest("foo %hn bar", 4, "foo bar");
+ DoCountTest("foo %ln bar", 4, "foo bar");
+ DoCountTest("foo %Ln bar", 4, "foo bar");
+ DoCountTest("foo %I64n bar", 4, "foo bar");
+ DoCountTest("foo %20.3n bar", 4, "foo bar");
+
+ PAL_Terminate();
+
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/vfprintf/test5/testinfo.dat b/src/pal/tests/palsuite/c_runtime/vfprintf/test5/testinfo.dat
new file mode 100644
index 0000000000..73feaa0202
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vfprintf/test5/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = vfprintf
+Name = Positive Test for vfprintf
+TYPE = DEFAULT
+EXE1 = test5
+Description
+= Tests vfprintf with the count specifier
diff --git a/src/pal/tests/palsuite/c_runtime/vfprintf/test6/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/vfprintf/test6/CMakeLists.txt
new file mode 100644
index 0000000000..2c036a45ae
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vfprintf/test6/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test6.c
+)
+
+add_executable(paltest_vfprintf_test6
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vfprintf_test6 coreclrpal)
+
+target_link_libraries(paltest_vfprintf_test6
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/vfprintf/test6/test6.c b/src/pal/tests/palsuite/c_runtime/vfprintf/test6/test6.c
new file mode 100644
index 0000000000..36c6fe51ca
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vfprintf/test6/test6.c
@@ -0,0 +1,48 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test6.c
+**
+** Purpose: Test #6 for the vfprintf function. Tests the char specifier (%c).
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../vfprintf.h"
+
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ WCHAR wc = (WCHAR) 'c';
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ DoCharTest("foo %c", 'b', "foo b");
+ DoCharTest("foo %hc", 'b', "foo b");
+ DoWCharTest("foo %lc", wc, "foo c");
+ DoCharTest("foo %Lc", 'b', "foo b");
+ DoCharTest("foo %I64c", 'b', "foo b");
+ DoCharTest("foo %5c", 'b', "foo b");
+ DoCharTest("foo %.0c", 'b', "foo b");
+ DoCharTest("foo %-5c", 'b', "foo b ");
+ DoCharTest("foo %05c", 'b', "foo 0000b");
+ DoCharTest("foo % c", 'b', "foo b");
+ DoCharTest("foo %#c", 'b', "foo b");
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/vfprintf/test6/testinfo.dat b/src/pal/tests/palsuite/c_runtime/vfprintf/test6/testinfo.dat
new file mode 100644
index 0000000000..cb1337dfd7
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vfprintf/test6/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = vfprintf
+Name = Positive Test for vfprintf
+TYPE = DEFAULT
+EXE1 = test6
+Description
+= Tests vfprintf with characters
diff --git a/src/pal/tests/palsuite/c_runtime/vfprintf/test7/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/vfprintf/test7/CMakeLists.txt
new file mode 100644
index 0000000000..ca483af773
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vfprintf/test7/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test7.c
+)
+
+add_executable(paltest_vfprintf_test7
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vfprintf_test7 coreclrpal)
+
+target_link_libraries(paltest_vfprintf_test7
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/vfprintf/test7/test7.c b/src/pal/tests/palsuite/c_runtime/vfprintf/test7/test7.c
new file mode 100644
index 0000000000..a9cfe319bd
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vfprintf/test7/test7.c
@@ -0,0 +1,47 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test7.c
+**
+** Purpose: Test #7 for the vfprintf function. Tests the wide char
+** specifier (%C).
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../vfprintf.h"
+
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ WCHAR wb = (WCHAR) 'b';
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ DoWCharTest("foo %C", wb, "foo b");
+ DoWCharTest("foo %hC", wb, "foo b");
+ DoCharTest("foo %lC", 'c', "foo c");
+ DoWCharTest("foo %LC", wb, "foo b");
+ DoWCharTest("foo %I64C", wb, "foo b");
+ DoWCharTest("foo %5C", wb, "foo b");
+ DoWCharTest("foo %.0C", wb, "foo b");
+ DoWCharTest("foo %-5C", wb, "foo b ");
+ DoWCharTest("foo %05C", wb, "foo 0000b");
+ DoWCharTest("foo % C", wb, "foo b");
+ DoWCharTest("foo %#C", wb, "foo b");
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/vfprintf/test7/testinfo.dat b/src/pal/tests/palsuite/c_runtime/vfprintf/test7/testinfo.dat
new file mode 100644
index 0000000000..c861344845
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vfprintf/test7/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = vfprintf
+Name = Positive Test for vfprintf
+TYPE = DEFAULT
+EXE1 = test7
+Description
+= Tests vfprintf with wide characters
diff --git a/src/pal/tests/palsuite/c_runtime/vfprintf/test8/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/vfprintf/test8/CMakeLists.txt
new file mode 100644
index 0000000000..89459b4e93
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vfprintf/test8/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test8.c
+)
+
+add_executable(paltest_vfprintf_test8
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vfprintf_test8 coreclrpal)
+
+target_link_libraries(paltest_vfprintf_test8
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/vfprintf/test8/test8.c b/src/pal/tests/palsuite/c_runtime/vfprintf/test8/test8.c
new file mode 100644
index 0000000000..5cef99741a
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vfprintf/test8/test8.c
@@ -0,0 +1,53 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test8.c
+**
+** Purpose: Test #8 for the vfprintf function. Tests the decimal
+** specifier (%d).
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../vfprintf.h"
+
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ int neg = -42;
+ int pos = 42;
+ INT64 l = 42;
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ DoNumTest("foo %d", pos, "foo 42");
+ DoNumTest("foo %ld", 0xFFFF, "foo 65535");
+ DoNumTest("foo %hd", 0xFFFF, "foo -1");
+ DoNumTest("foo %Ld", pos, "foo 42");
+ DoI64Test("foo %I64d", l, "42", "foo 42");
+ DoNumTest("foo %3d", pos, "foo 42");
+ DoNumTest("foo %-3d", pos, "foo 42 ");
+ DoNumTest("foo %.1d", pos, "foo 42");
+ DoNumTest("foo %.3d", pos, "foo 042");
+ DoNumTest("foo %03d", pos, "foo 042");
+ DoNumTest("foo %#d", pos, "foo 42");
+ DoNumTest("foo %+d", pos, "foo +42");
+ DoNumTest("foo % d", pos, "foo 42");
+ DoNumTest("foo %+d", neg, "foo -42");
+ DoNumTest("foo % d", neg, "foo -42");
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/vfprintf/test8/testinfo.dat b/src/pal/tests/palsuite/c_runtime/vfprintf/test8/testinfo.dat
new file mode 100644
index 0000000000..e96723378d
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vfprintf/test8/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = vfprintf
+Name = Positive Test for vfprintf
+TYPE = DEFAULT
+EXE1 = test8
+Description
+= Tests vfprintf with decimal numbers
diff --git a/src/pal/tests/palsuite/c_runtime/vfprintf/test9/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/vfprintf/test9/CMakeLists.txt
new file mode 100644
index 0000000000..3e3b5b99ed
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vfprintf/test9/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test9.c
+)
+
+add_executable(paltest_vfprintf_test9
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vfprintf_test9 coreclrpal)
+
+target_link_libraries(paltest_vfprintf_test9
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/vfprintf/test9/test9.c b/src/pal/tests/palsuite/c_runtime/vfprintf/test9/test9.c
new file mode 100644
index 0000000000..45d0dc7a9e
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vfprintf/test9/test9.c
@@ -0,0 +1,53 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test9.c
+**
+** Purpose: Test #9 for the vfprintf function. Tests the integer
+** specifier (%i).
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../vfprintf.h"
+
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ int neg = -42;
+ int pos = 42;
+ INT64 l = 42;
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ DoNumTest("foo %i", pos, "foo 42");
+ DoNumTest("foo %li", 0xFFFF, "foo 65535");
+ DoNumTest("foo %hi", 0xFFFF, "foo -1");
+ DoNumTest("foo %Li", pos, "foo 42");
+ DoI64Test("foo %I64i", l, "42", "foo 42");
+ DoNumTest("foo %3i", pos, "foo 42");
+ DoNumTest("foo %-3i", pos, "foo 42 ");
+ DoNumTest("foo %.1i", pos, "foo 42");
+ DoNumTest("foo %.3i", pos, "foo 042");
+ DoNumTest("foo %03i", pos, "foo 042");
+ DoNumTest("foo %#i", pos, "foo 42");
+ DoNumTest("foo %+i", pos, "foo +42");
+ DoNumTest("foo % i", pos, "foo 42");
+ DoNumTest("foo %+i", neg, "foo -42");
+ DoNumTest("foo % i", neg, "foo -42");
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/vfprintf/test9/testinfo.dat b/src/pal/tests/palsuite/c_runtime/vfprintf/test9/testinfo.dat
new file mode 100644
index 0000000000..48621773cc
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vfprintf/test9/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = vfprintf
+Name = Positive Test for vfprintf
+TYPE = DEFAULT
+EXE1 = test9
+Description
+= Tests vfprintf with integer numbers
diff --git a/src/pal/tests/palsuite/c_runtime/vfprintf/vfprintf.h b/src/pal/tests/palsuite/c_runtime/vfprintf/vfprintf.h
new file mode 100644
index 0000000000..f4ae7a53fa
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vfprintf/vfprintf.h
@@ -0,0 +1,463 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: vfprintf.h
+**
+** Purpose: Contains common testing functions for vfprintf
+**
+**
+**==========================================================================*/
+
+#ifndef __vfprintf_H__
+#define __vfprintf_H__
+
+int DoVfprintf(FILE *fp, char *format, ...)
+{
+ int retVal;
+ va_list arglist;
+
+ va_start(arglist, format);
+ retVal = vfprintf(fp, format, arglist);
+ va_end(arglist);
+
+ return (retVal);
+}
+
+void DoStrTest(char *formatstr, char* param, char *checkstr)
+{
+ FILE *fp;
+ char buf[256] = { 0 };
+
+ if ((fp = fopen("testfile.txt", "w+")) == NULL )
+ {
+ Fail("ERROR: fopen failed to create testfile\n");
+ }
+ if ((DoVfprintf(fp, formatstr, param)) < 0)
+ {
+ Fail("ERROR: vfprintf failed\n");
+ }
+ if ((fseek(fp, 0, SEEK_SET)) != 0)
+ {
+ Fail("ERROR: fseek failed\n");
+ }
+ if ((fgets(buf, 100, fp)) == NULL)
+ {
+ Fail("ERROR: fgets failed\n");
+ }
+
+ if (memcmp(buf, checkstr, strlen(checkstr) + 1) != 0)
+ {
+ Fail("ERROR: failed to insert string \"%s\" into \"%s\"\n"
+ "Expected \"%s\" got \"%s\".\n",
+ param, formatstr, checkstr, buf);
+ }
+ fclose(fp);
+}
+
+void DoWStrTest(char *formatstr, WCHAR* param, char *checkstr)
+{
+ FILE *fp;
+ char buf[256] = { 0 };
+
+ if ((fp = fopen("testfile.txt", "w+")) == NULL )
+ {
+ Fail("ERROR: fopen failed to create testfile\n");
+ }
+ if ((DoVfprintf(fp, formatstr, param)) < 0)
+ {
+ Fail("ERROR: vfprintf failed\n");
+ }
+ if ((fseek(fp, 0, SEEK_SET)) != 0)
+ {
+ Fail("ERROR: fseek failed\n");
+ }
+ if ((fgets(buf, 100, fp)) == NULL)
+ {
+ Fail("ERROR: fgets failed\n");
+ }
+
+ if (memcmp(buf, checkstr, strlen(checkstr) + 1) != 0)
+ {
+ Fail("ERROR: failed to insert wide string \"%S\" into \"%s\"\n"
+ "Expected \"%s\" got \"%s\".\n",
+ param, formatstr, checkstr, buf);
+ }
+ fclose(fp);
+}
+
+
+void DoPointerTest(char *formatstr, void* param, char* paramstr,
+ char *checkstr1)
+{
+ FILE *fp;
+ char buf[256] = { 0 };
+
+ if ((fp = fopen("testfile.txt", "w+")) == NULL )
+ {
+ Fail("ERROR: fopen failed to create testfile\n");
+ }
+
+ if ((DoVfprintf(fp, formatstr, param)) < 0)
+ {
+ Fail("ERROR: vfprintf failed\n");
+ }
+
+ if ((fseek(fp, 0, SEEK_SET)) != 0)
+ {
+ Fail("ERROR: fseek failed\n");
+ }
+
+ if ((fgets(buf, 100, fp)) == NULL)
+ {
+ Fail("ERROR: fgets failed\n");
+ }
+
+ if (memcmp(buf, checkstr1, strlen(checkstr1) + 1) != 0)
+ {
+ Fail("ERROR: failed to insert %s into \"%s\"\n"
+ "Expected \"%s\" got \"%s\".\n",
+ paramstr, formatstr, checkstr1, buf);
+ }
+
+ if ((fclose( fp )) != 0)
+ {
+ Fail("ERROR: fclose failed to close \"testfile.txt\"\n");
+ }
+}
+
+
+
+void DoCountTest(char *formatstr, int param, char *checkstr)
+{
+ FILE *fp;
+ char buf[512] = { 0 };
+ int n = -1;
+
+ if ((fp = fopen("testfile.txt", "w+")) == NULL )
+ {
+ Fail("ERROR: fopen failed to create testfile\n");
+ }
+
+ if ((DoVfprintf(fp, formatstr, &n)) < 0)
+ {
+ Fail("ERROR: vfprintf failed\n");
+ }
+
+ if ((fseek(fp, 0, SEEK_SET)) != 0)
+ {
+ Fail("ERROR: fseek failed\n");
+ }
+
+ if ((fgets(buf, sizeof(buf), fp)) == NULL)
+ {
+ Fail("ERROR: fgets failed\n");
+ }
+
+ if (n != param)
+ {
+ Fail("ERROR: Expected count parameter to resolve to %d, got %X\n",
+ param, n);
+ }
+
+ if (memcmp(buf, checkstr, strlen(checkstr) + 1) != 0)
+ {
+ Fail("ERROR: Expected \"%s\" got \"%s\".\n", checkstr, buf);
+ }
+
+ if ((fclose( fp )) != 0)
+ {
+ Fail("ERROR: fclose failed to close \"testfile.txt\"\n");
+ }
+}
+
+void DoShortCountTest(char *formatstr, int param, char *checkstr)
+{
+ FILE *fp;
+ char buf[512] = { 0 };
+ short int n = -1;
+
+ if ((fp = fopen("testfile.txt", "w+")) == NULL )
+ {
+ Fail("ERROR: fopen failed to create testfile\n");
+ }
+
+ if ((DoVfprintf(fp, formatstr, &n)) < 0)
+ {
+ Fail("ERROR: vfprintf failed\n");
+ }
+
+ if ((fseek(fp, 0, SEEK_SET)) != 0)
+ {
+ Fail("ERROR: fseek failed\n");
+ }
+
+ if ((fgets(buf, 100, fp)) == NULL)
+ {
+ Fail("ERROR: fgets failed\n");
+ }
+
+ if (n != param)
+ {
+ Fail("ERROR: Expected count parameter to resolve to %d, got %X\n",
+ param, n);
+ }
+
+ if (memcmp(buf, checkstr, strlen(checkstr) + 1) != 0)
+ {
+ Fail("ERROR: Expected \"%s\" got \"%s\".\n", checkstr, buf);
+ }
+
+ if ((fclose( fp )) != 0)
+ {
+ Fail("ERROR: fclose failed to close \"testfile.txt\"\n");
+ }
+}
+
+
+void DoCharTest(char *formatstr, char param, char *checkstr)
+{
+ FILE *fp;
+ char buf[256] = { 0 };
+
+ if ((fp = fopen("testfile.txt", "w+")) == NULL )
+ {
+ Fail("ERROR: fopen failed to create testfile\n");
+ }
+ if ((DoVfprintf(fp, formatstr, param)) < 0)
+ {
+ Fail("ERROR: vfprintf failed\n");
+ }
+ if ((fseek(fp, 0, SEEK_SET)) != 0)
+ {
+ Fail("ERROR: fseek failed\n");
+ }
+ if ((fgets(buf, 100, fp)) == NULL)
+ {
+ Fail("ERROR: fgets failed\n");
+ }
+
+ if (memcmp(buf, checkstr, strlen(checkstr) + 1) != 0)
+ {
+ Fail("ERROR: failed to insert char \'%c\' (%d) into \"%s\"\n"
+ "Expected \"%s\" got \"%s\".\n",
+ param, param, formatstr, checkstr, buf);
+ }
+ fclose(fp);
+}
+
+void DoWCharTest(char *formatstr, WCHAR param, char *checkstr)
+{
+ FILE *fp;
+ char buf[256] = { 0 };
+
+ if ((fp = fopen("testfile.txt", "w+")) == NULL )
+ {
+ Fail("ERROR: fopen failed to create testfile\n");
+ }
+ if ((DoVfprintf(fp, formatstr, param)) < 0)
+ {
+ Fail("ERROR: vfprintf failed\n");
+ }
+ if ((fseek(fp, 0, SEEK_SET)) != 0)
+ {
+ Fail("ERROR: fseek failed\n");
+ }
+ if ((fgets(buf, 100, fp)) == NULL)
+ {
+ Fail("ERROR: fgets failed\n");
+ }
+
+ if (memcmp(buf, checkstr, strlen(checkstr) + 1) != 0)
+ {
+ Fail("ERROR: failed to insert wide char \'%c\' (%d) into \"%s\"\n"
+ "Expected \"%s\" got \"%s\".\n",
+ (char)param, param, formatstr, checkstr, buf);
+ }
+ fclose(fp);
+}
+
+void DoNumTest(char *formatstr, int value, char *checkstr)
+{
+ FILE *fp;
+ char buf[256] = { 0 };
+
+ if ((fp = fopen("testfile.txt", "w+")) == NULL )
+ {
+ Fail("ERROR: fopen failed to create testfile\n");
+ }
+ if ((DoVfprintf(fp, formatstr, value)) < 0)
+ {
+ Fail("ERROR: vfprintf failed\n");
+ }
+ if ((fseek(fp, 0, SEEK_SET)) != 0)
+ {
+ Fail("ERROR: fseek failed\n");
+ }
+ if ((fgets(buf, 100, fp)) == NULL)
+ {
+ Fail("ERROR: fgets failed\n");
+ }
+
+ if (memcmp(buf, checkstr, strlen(checkstr) + 1) != 0)
+ {
+ Fail("ERROR: failed to insert %#x into \"%s\"\n"
+ "Expected \"%s\" got \"%s\".\n",
+ value, formatstr, checkstr, buf);
+ }
+ fclose(fp);
+}
+
+void DoI64Test(char *formatstr, INT64 value, char *valuestr, char *checkstr1)
+{
+ FILE *fp;
+ char buf[256] = { 0 };
+
+ if ((fp = fopen("testfile.txt", "w+")) == NULL )
+ {
+ Fail("ERROR: fopen failed to create testfile\n");
+ }
+ if ((DoVfprintf(fp, formatstr, value)) < 0)
+ {
+ Fail("ERROR: vfprintf failed\n");
+ }
+ if ((fseek(fp, 0, SEEK_SET)) != 0)
+ {
+ Fail("ERROR: fseek failed\n");
+ }
+ if ((fgets(buf, 100, fp)) == NULL)
+ {
+ Fail("ERROR: fgets failed\n");
+ }
+
+ if (memcmp(buf, checkstr1, strlen(checkstr1) + 1) != 0)
+ {
+ Fail("ERROR: failed to insert %s into \"%s\"\n"
+ "Expected \"%s\", got \"%s\".\n",
+ valuestr, formatstr, checkstr1, buf);
+ }
+ fclose(fp);
+}
+
+void DoDoubleTest(char *formatstr, double value, char *checkstr1,
+ char *checkstr2)
+{
+ FILE *fp;
+ char buf[256] = { 0 };
+
+ if ((fp = fopen("testfile.txt", "w+")) == NULL )
+ {
+ Fail("ERROR: fopen failed to create testfile\n");
+ }
+
+ if ((DoVfprintf(fp, formatstr, value)) < 0)
+ {
+ Fail("ERROR: vfprintf failed\n");
+ }
+ if ((fseek(fp, 0, SEEK_SET)) != 0)
+ {
+ Fail("ERROR: fseek failed\n");
+ }
+ if ((fgets(buf, 100, fp)) == NULL)
+ {
+ Fail("ERROR: fgets failed\n");
+ }
+
+ if (memcmp(buf, checkstr1, strlen(checkstr1) + 1) != 0 &&
+ memcmp(buf, checkstr2, strlen(checkstr2) + 1) != 0)
+ {
+ Fail("ERROR: failed to insert %f into \"%s\"\n"
+ "Expected \"%s\" or \"%s\", got \"%s\".\n",
+ value, formatstr, checkstr1, checkstr2, buf);
+ }
+ fclose(fp);
+}
+
+
+void DoArgumentPrecTest(char *formatstr, int precision, void *param,
+ char *paramstr, char *checkstr1, char *checkstr2)
+{
+ FILE *fp;
+ char buf[256];
+
+ if ((fp = fopen("testfile.txt", "w+")) == NULL )
+ {
+ Fail("ERROR: fopen failed to create testfile\n");
+ }
+
+ if ((DoVfprintf(fp, formatstr, precision, param)) < 0)
+ {
+ Fail("ERROR: vfprintf failed\n");
+ }
+
+ if ((fseek(fp, 0, SEEK_SET)) != 0)
+ {
+ Fail("ERROR: fseek failed\n");
+ }
+
+ if ((fgets(buf, 100, fp)) == NULL)
+ {
+ Fail("ERROR: fgets failed\n");
+ }
+
+ if (memcmp(buf, checkstr1, strlen(checkstr1) + 1) != 0 &&
+ memcmp(buf, checkstr2, strlen(checkstr2) + 1) != 0)
+ {
+ Fail("ERROR: failed to insert %s into \"%s\" with precision %d\n"
+ "Expected \"%s\" or \"%s\", got \"%s\".\n", paramstr, formatstr,
+ precision, checkstr1, checkstr2, buf);
+ }
+
+
+ if ((fclose( fp )) != 0)
+ {
+ Fail("ERROR: fclose failed to close \"testfile.txt\"\n");
+ }
+
+}
+
+void DoArgumentPrecDoubleTest(char *formatstr, int precision, double param,
+ char *checkstr1, char *checkstr2)
+{
+ FILE *fp;
+ char buf[256];
+
+ if ((fp = fopen("testfile.txt", "w+")) == NULL )
+ {
+ Fail("ERROR: fopen failed to create testfile\n");
+ }
+
+ if ((DoVfprintf(fp, formatstr, precision, param)) < 0)
+ {
+ Fail("ERROR: vfprintf failed\n");
+ }
+
+ if ((fseek(fp, 0, SEEK_SET)) != 0)
+ {
+ Fail("ERROR: fseek failed\n");
+ }
+
+ if ((fgets(buf, 100, fp)) == NULL)
+ {
+ Fail("ERROR: fgets failed\n");
+ }
+
+ if (memcmp(buf, checkstr1, strlen(checkstr1) + 1) != 0 &&
+ memcmp(buf, checkstr2, strlen(checkstr2) + 1) != 0)
+ {
+ Fail("ERROR: failed to insert %f into \"%s\" with precision %d\n"
+ "Expected \"%s\" or \"%s\", got \"%s\".\n", param, formatstr,
+ precision, checkstr1, checkstr2, buf);
+ }
+
+ if ((fclose( fp )) != 0)
+ {
+ Fail("ERROR: fclose failed to close \"testfile.txt\"\n");
+ }
+
+}
+
+#endif
+
diff --git a/src/pal/tests/palsuite/c_runtime/vprintf/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/vprintf/CMakeLists.txt
new file mode 100644
index 0000000000..c7e7647ea9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vprintf/CMakeLists.txt
@@ -0,0 +1,23 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+# This test fails to build on ARM
+#add_subdirectory(test1)
+add_subdirectory(test10)
+add_subdirectory(test11)
+add_subdirectory(test12)
+add_subdirectory(test13)
+add_subdirectory(test14)
+add_subdirectory(test15)
+add_subdirectory(test16)
+add_subdirectory(test17)
+add_subdirectory(test18)
+add_subdirectory(test19)
+add_subdirectory(test2)
+add_subdirectory(test3)
+add_subdirectory(test4)
+add_subdirectory(test5)
+add_subdirectory(test6)
+add_subdirectory(test7)
+add_subdirectory(test8)
+add_subdirectory(test9)
+
diff --git a/src/pal/tests/palsuite/c_runtime/vprintf/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/vprintf/test1/CMakeLists.txt
new file mode 100644
index 0000000000..eabdf87393
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vprintf/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_vprintf_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vprintf_test1 coreclrpal)
+
+target_link_libraries(paltest_vprintf_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/vprintf/test1/test1.c b/src/pal/tests/palsuite/c_runtime/vprintf/test1/test1.c
new file mode 100644
index 0000000000..404d7a0dc9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vprintf/test1/test1.c
@@ -0,0 +1,43 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Test #1 for the vprintf function. A single, basic, test
+** case with no formatting.
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../vprintf.h"
+
+int __cdecl main(int argc, char *argv[])
+{
+ char checkstr[] = "hello world";
+ int ret;
+
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ ret = vprintf("hello world", NULL);
+
+ if (ret != strlen(checkstr))
+ {
+ Fail("Expected vprintf to return %d, got %d.\n",
+ strlen(checkstr), ret);
+
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/vprintf/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/vprintf/test1/testinfo.dat
new file mode 100644
index 0000000000..ac5de86341
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vprintf/test1/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = vprintf
+Name = Positive Test for vprintf
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= General test to see if vprintf works correctly
diff --git a/src/pal/tests/palsuite/c_runtime/vprintf/test10/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/vprintf/test10/CMakeLists.txt
new file mode 100644
index 0000000000..47a21d909a
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vprintf/test10/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test10.c
+)
+
+add_executable(paltest_vprintf_test10
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vprintf_test10 coreclrpal)
+
+target_link_libraries(paltest_vprintf_test10
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/vprintf/test10/test10.c b/src/pal/tests/palsuite/c_runtime/vprintf/test10/test10.c
new file mode 100644
index 0000000000..b363d7c02c
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vprintf/test10/test10.c
@@ -0,0 +1,52 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test10.c
+**
+** Purpose: Test #10 for the vprintf function. Tests the octal specifier
+** (%o).
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../vprintf.h"
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ int neg = -42;
+ int pos = 42;
+ INT64 l = 42;
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ DoNumTest("foo %o", pos, "foo 52");
+ DoNumTest("foo %lo", 0xFFFF, "foo 177777");
+ DoNumTest("foo %ho", 0xFFFF, "foo 177777");
+ DoNumTest("foo %Lo", pos, "foo 52");
+ DoI64Test("foo %I64o", l, "42", "foo 52");
+ DoNumTest("foo %3o", pos, "foo 52");
+ DoNumTest("foo %-3o", pos, "foo 52 ");
+ DoNumTest("foo %.1o", pos, "foo 52");
+ DoNumTest("foo %.3o", pos, "foo 052");
+ DoNumTest("foo %03o", pos, "foo 052");
+ DoNumTest("foo %#o", pos, "foo 052");
+ DoNumTest("foo %+o", pos, "foo 52");
+ DoNumTest("foo % o", pos, "foo 52");
+ DoNumTest("foo %+o", neg, "foo 37777777726");
+ DoNumTest("foo % o", neg, "foo 37777777726");
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/vprintf/test10/testinfo.dat b/src/pal/tests/palsuite/c_runtime/vprintf/test10/testinfo.dat
new file mode 100644
index 0000000000..4494024300
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vprintf/test10/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = vprintf
+Name = Positive Test for vprintf
+TYPE = DEFAULT
+EXE1 = test10
+Description
+= Tests vprintf with octal numbers
diff --git a/src/pal/tests/palsuite/c_runtime/vprintf/test11/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/vprintf/test11/CMakeLists.txt
new file mode 100644
index 0000000000..4c750b72ac
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vprintf/test11/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test11.c
+)
+
+add_executable(paltest_vprintf_test11
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vprintf_test11 coreclrpal)
+
+target_link_libraries(paltest_vprintf_test11
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/vprintf/test11/test11.c b/src/pal/tests/palsuite/c_runtime/vprintf/test11/test11.c
new file mode 100644
index 0000000000..f5157ac99f
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vprintf/test11/test11.c
@@ -0,0 +1,51 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test11.c
+**
+** Purpose: Test #11 for the vprintf function. Test the unsigned int
+** specifier (%u).
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../vprintf.h"
+
+int __cdecl main(int argc, char *argv[])
+{
+ int neg = -42;
+ int pos = 42;
+ INT64 l = 42;
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ DoNumTest("foo %u", pos, "foo 42");
+ DoNumTest("foo %lu", 0xFFFF, "foo 65535");
+ DoNumTest("foo %hu", 0xFFFF, "foo 65535");
+ DoNumTest("foo %Lu", pos, "foo 42");
+ DoI64Test("foo %I64u", l, "42", "foo 42");
+ DoNumTest("foo %3u", pos, "foo 42");
+ DoNumTest("foo %-3u", pos, "foo 42 ");
+ DoNumTest("foo %.1u", pos, "foo 42");
+ DoNumTest("foo %.3u", pos, "foo 042");
+ DoNumTest("foo %03u", pos, "foo 042");
+ DoNumTest("foo %#u", pos, "foo 42");
+ DoNumTest("foo %+u", pos, "foo 42");
+ DoNumTest("foo % u", pos, "foo 42");
+ DoNumTest("foo %+u", neg, "foo 4294967254");
+ DoNumTest("foo % u", neg, "foo 4294967254");
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/vprintf/test11/testinfo.dat b/src/pal/tests/palsuite/c_runtime/vprintf/test11/testinfo.dat
new file mode 100644
index 0000000000..c504c70e88
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vprintf/test11/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = vprintf
+Name = Positive Test for vprintf
+TYPE = DEFAULT
+EXE1 = test11
+Description
+= Tests vprintf with unsigned numbers
diff --git a/src/pal/tests/palsuite/c_runtime/vprintf/test12/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/vprintf/test12/CMakeLists.txt
new file mode 100644
index 0000000000..1feb886fc1
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vprintf/test12/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test12.c
+)
+
+add_executable(paltest_vprintf_test12
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vprintf_test12 coreclrpal)
+
+target_link_libraries(paltest_vprintf_test12
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/vprintf/test12/test12.c b/src/pal/tests/palsuite/c_runtime/vprintf/test12/test12.c
new file mode 100644
index 0000000000..703a8c4fdc
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vprintf/test12/test12.c
@@ -0,0 +1,53 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test12.c
+**
+** Purpose: Test #12 for the vprintf function. Tests the (lowercase)
+** hexadecimal specifier (%x)
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../vprintf.h"
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ int neg = -42;
+ int pos = 0x1234ab;
+ INT64 l = I64(0x1234567887654321);
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ DoNumTest("foo %x", pos, "foo 1234ab");
+ DoNumTest("foo %lx", pos, "foo 1234ab");
+ DoNumTest("foo %hx", pos, "foo 34ab");
+ DoNumTest("foo %Lx", pos, "foo 1234ab");
+ DoI64Test("foo %I64x", l, "0x1234567887654321",
+ "foo 1234567887654321");
+ DoNumTest("foo %7x", pos, "foo 1234ab");
+ DoNumTest("foo %-7x", pos, "foo 1234ab ");
+ DoNumTest("foo %.1x", pos, "foo 1234ab");
+ DoNumTest("foo %.7x", pos, "foo 01234ab");
+ DoNumTest("foo %07x", pos, "foo 01234ab");
+ DoNumTest("foo %#x", pos, "foo 0x1234ab");
+ DoNumTest("foo %+x", pos, "foo 1234ab");
+ DoNumTest("foo % x", pos, "foo 1234ab");
+ DoNumTest("foo %+x", neg, "foo ffffffd6");
+ DoNumTest("foo % x", neg, "foo ffffffd6");
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/vprintf/test12/testinfo.dat b/src/pal/tests/palsuite/c_runtime/vprintf/test12/testinfo.dat
new file mode 100644
index 0000000000..558ce37c8b
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vprintf/test12/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = vprintf
+Name = Positive Test for vprintf
+TYPE = DEFAULT
+EXE1 = test12
+Description
+= Tests vprintf with hex numbers (lowercase)
diff --git a/src/pal/tests/palsuite/c_runtime/vprintf/test13/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/vprintf/test13/CMakeLists.txt
new file mode 100644
index 0000000000..cd7535a1ad
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vprintf/test13/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test13.c
+)
+
+add_executable(paltest_vprintf_test13
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vprintf_test13 coreclrpal)
+
+target_link_libraries(paltest_vprintf_test13
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/vprintf/test13/test13.c b/src/pal/tests/palsuite/c_runtime/vprintf/test13/test13.c
new file mode 100644
index 0000000000..ecb83ba38d
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vprintf/test13/test13.c
@@ -0,0 +1,54 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test13.c
+**
+** Purpose: Test #13 for the vprintf function. Tests the (uppercase)
+** hexadecimal specifier (%X)
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../vprintf.h"
+
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ int neg = -42;
+ int pos = 0x1234AB;
+ INT64 l = I64(0x1234567887654321);
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ DoNumTest("foo %X", pos, "foo 1234AB");
+ DoNumTest("foo %lX", pos, "foo 1234AB");
+ DoNumTest("foo %hX", pos, "foo 34AB");
+ DoNumTest("foo %LX", pos, "foo 1234AB");
+ DoI64Test("foo %I64X", l, "0x1234567887654321",
+ "foo 1234567887654321");
+ DoNumTest("foo %7X", pos, "foo 1234AB");
+ DoNumTest("foo %-7X", pos, "foo 1234AB ");
+ DoNumTest("foo %.1X", pos, "foo 1234AB");
+ DoNumTest("foo %.7X", pos, "foo 01234AB");
+ DoNumTest("foo %07X", pos, "foo 01234AB");
+ DoNumTest("foo %#X", pos, "foo 0X1234AB");
+ DoNumTest("foo %+X", pos, "foo 1234AB");
+ DoNumTest("foo % X", pos, "foo 1234AB");
+ DoNumTest("foo %+X", neg, "foo FFFFFFD6");
+ DoNumTest("foo % X", neg, "foo FFFFFFD6");
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/vprintf/test13/testinfo.dat b/src/pal/tests/palsuite/c_runtime/vprintf/test13/testinfo.dat
new file mode 100644
index 0000000000..33822958dd
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vprintf/test13/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = vprintf
+Name = Positive Test for vprintf
+TYPE = DEFAULT
+EXE1 = test13
+Description
+= Tests vprintf with hex numbers (uppercase)
diff --git a/src/pal/tests/palsuite/c_runtime/vprintf/test14/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/vprintf/test14/CMakeLists.txt
new file mode 100644
index 0000000000..82cfd68ecf
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vprintf/test14/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test14.c
+)
+
+add_executable(paltest_vprintf_test14
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vprintf_test14 coreclrpal)
+
+target_link_libraries(paltest_vprintf_test14
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/vprintf/test14/test14.c b/src/pal/tests/palsuite/c_runtime/vprintf/test14/test14.c
new file mode 100644
index 0000000000..536c1950e3
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vprintf/test14/test14.c
@@ -0,0 +1,54 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test14.c
+**
+** Purpose: Test #14 for the vprintf function. Tests the lowercase
+** exponential notation double specifier (%e)
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../vprintf.h"
+
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ double val = 256.0;
+ double neg = -256.0;
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ DoDoubleTest("foo %e", val, "foo 2.560000e+002", "foo 2.560000e+02");
+ DoDoubleTest("foo %le", val, "foo 2.560000e+002", "foo 2.560000e+02");
+ DoDoubleTest("foo %he", val, "foo 2.560000e+002", "foo 2.560000e+02");
+ DoDoubleTest("foo %Le", val, "foo 2.560000e+002", "foo 2.560000e+02");
+ DoDoubleTest("foo %I64e", val, "foo 2.560000e+002", "foo 2.560000e+02");
+ DoDoubleTest("foo %14e", val, "foo 2.560000e+002", "foo 2.560000e+02");
+ DoDoubleTest("foo %-14e", val, "foo 2.560000e+002 ",
+ "foo 2.560000e+02 ");
+ DoDoubleTest("foo %.1e", val, "foo 2.6e+002", "foo 2.6e+02");
+ DoDoubleTest("foo %.8e", val, "foo 2.56000000e+002",
+ "foo 2.56000000e+02");
+ DoDoubleTest("foo %014e", val, "foo 02.560000e+002",
+ "foo 002.560000e+02");
+ DoDoubleTest("foo %#e", val, "foo 2.560000e+002", "foo 2.560000e+02");
+ DoDoubleTest("foo %+e", val, "foo +2.560000e+002", "foo +2.560000e+02");
+ DoDoubleTest("foo % e", val, "foo 2.560000e+002", "foo 2.560000e+02");
+ DoDoubleTest("foo %+e", neg, "foo -2.560000e+002", "foo -2.560000e+02");
+ DoDoubleTest("foo % e", neg, "foo -2.560000e+002", "foo -2.560000e+02");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/vprintf/test14/testinfo.dat b/src/pal/tests/palsuite/c_runtime/vprintf/test14/testinfo.dat
new file mode 100644
index 0000000000..d2633fca43
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vprintf/test14/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = vprintf
+Name = Positive Test for vprintf
+TYPE = DEFAULT
+EXE1 = test14
+Description
+= Tests vprintf with exponential format doubles (lowercase)
diff --git a/src/pal/tests/palsuite/c_runtime/vprintf/test15/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/vprintf/test15/CMakeLists.txt
new file mode 100644
index 0000000000..29a134d48c
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vprintf/test15/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test15.c
+)
+
+add_executable(paltest_vprintf_test15
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vprintf_test15 coreclrpal)
+
+target_link_libraries(paltest_vprintf_test15
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/vprintf/test15/test15.c b/src/pal/tests/palsuite/c_runtime/vprintf/test15/test15.c
new file mode 100644
index 0000000000..9aff6e457d
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vprintf/test15/test15.c
@@ -0,0 +1,54 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test15.c
+**
+** Purpose: Test #15 for the vprintf function. Tests the uppercase
+** exponential notation double specifier (%E)
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../vprintf.h"
+
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ double val = 256.0;
+ double neg = -256.0;
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ DoDoubleTest("foo %E", val, "foo 2.560000E+002", "foo 2.560000E+02");
+ DoDoubleTest("foo %lE", val, "foo 2.560000E+002", "foo 2.560000E+02");
+ DoDoubleTest("foo %hE", val, "foo 2.560000E+002", "foo 2.560000E+02");
+ DoDoubleTest("foo %LE", val, "foo 2.560000E+002", "foo 2.560000E+02");
+ DoDoubleTest("foo %I64E", val, "foo 2.560000E+002", "foo 2.560000E+02");
+ DoDoubleTest("foo %14E", val, "foo 2.560000E+002", "foo 2.560000E+02");
+ DoDoubleTest("foo %-14E", val, "foo 2.560000E+002 ",
+ "foo 2.560000E+02 ");
+ DoDoubleTest("foo %.1E", val, "foo 2.6E+002", "foo 2.6E+02");
+ DoDoubleTest("foo %.8E", val, "foo 2.56000000E+002",
+ "foo 2.56000000E+02");
+ DoDoubleTest("foo %014E", val, "foo 02.560000E+002",
+ "foo 002.560000E+02");
+ DoDoubleTest("foo %#E", val, "foo 2.560000E+002", "foo 2.560000E+02");
+ DoDoubleTest("foo %+E", val, "foo +2.560000E+002", "foo +2.560000E+02");
+ DoDoubleTest("foo % E", val, "foo 2.560000E+002", "foo 2.560000E+02");
+ DoDoubleTest("foo %+E", neg, "foo -2.560000E+002", "foo -2.560000E+02");
+ DoDoubleTest("foo % E", neg, "foo -2.560000E+002", "foo -2.560000E+02");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/vprintf/test15/testinfo.dat b/src/pal/tests/palsuite/c_runtime/vprintf/test15/testinfo.dat
new file mode 100644
index 0000000000..c1e00520a7
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vprintf/test15/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = vprintf
+Name = Positive Test for vprintf
+TYPE = DEFAULT
+EXE1 = test15
+Description
+= Tests vprintf with exponential format doubles (uppercase)
diff --git a/src/pal/tests/palsuite/c_runtime/vprintf/test16/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/vprintf/test16/CMakeLists.txt
new file mode 100644
index 0000000000..7fbf43ac84
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vprintf/test16/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test16.c
+)
+
+add_executable(paltest_vprintf_test16
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vprintf_test16 coreclrpal)
+
+target_link_libraries(paltest_vprintf_test16
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/vprintf/test16/test16.c b/src/pal/tests/palsuite/c_runtime/vprintf/test16/test16.c
new file mode 100644
index 0000000000..66e9afe2d7
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vprintf/test16/test16.c
@@ -0,0 +1,50 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test16.c
+**
+** Purpose: Test #16 for the vprintf function. Tests the decimal notation
+** double specifier (%f)
+**
+**
+**==========================================================================*/
+
+
+#include <palsuite.h>
+#include "../vprintf.h"
+
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ double val = 2560.001;
+ double neg = -2560.001;
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ DoDoubleTest("foo %f", val, "foo 2560.001000", "foo 2560.001000");
+ DoDoubleTest("foo %lf", val, "foo 2560.001000", "foo 2560.001000");
+ DoDoubleTest("foo %hf", val, "foo 2560.001000", "foo 2560.001000");
+ DoDoubleTest("foo %Lf", val, "foo 2560.001000", "foo 2560.001000");
+ DoDoubleTest("foo %I64f", val, "foo 2560.001000", "foo 2560.001000");
+ DoDoubleTest("foo %12f", val, "foo 2560.001000", "foo 2560.001000");
+ DoDoubleTest("foo %-12f", val, "foo 2560.001000 ", "foo 2560.001000 ");
+ DoDoubleTest("foo %.1f", val, "foo 2560.0", "foo 2560.0");
+ DoDoubleTest("foo %.8f", val, "foo 2560.00100000", "foo 2560.00100000");
+ DoDoubleTest("foo %012f", val, "foo 02560.001000", "foo 02560.001000");
+ DoDoubleTest("foo %#f", val, "foo 2560.001000", "foo 2560.001000");
+ DoDoubleTest("foo %+f", val, "foo +2560.001000", "foo +2560.001000");
+ DoDoubleTest("foo % f", val, "foo 2560.001000", "foo 2560.001000");
+ DoDoubleTest("foo %+f", neg, "foo -2560.001000", "foo -2560.001000");
+ DoDoubleTest("foo % f", neg, "foo -2560.001000", "foo -2560.001000");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/vprintf/test16/testinfo.dat b/src/pal/tests/palsuite/c_runtime/vprintf/test16/testinfo.dat
new file mode 100644
index 0000000000..8b17d2f71a
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vprintf/test16/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = vprintf
+Name = Positive Test for vprintf
+TYPE = DEFAULT
+EXE1 = test16
+Description
+= Tests vprintf with decimal point format doubles
diff --git a/src/pal/tests/palsuite/c_runtime/vprintf/test17/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/vprintf/test17/CMakeLists.txt
new file mode 100644
index 0000000000..25970cba15
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vprintf/test17/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test17.c
+)
+
+add_executable(paltest_vprintf_test17
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vprintf_test17 coreclrpal)
+
+target_link_libraries(paltest_vprintf_test17
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/vprintf/test17/test17.c b/src/pal/tests/palsuite/c_runtime/vprintf/test17/test17.c
new file mode 100644
index 0000000000..d36a084903
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vprintf/test17/test17.c
@@ -0,0 +1,52 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test17.c
+**
+** Purpose: Test #17 for the vprintf function. Tests the lowercase
+** shorthand notation double specifier (%g)
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../vprintf.h"
+
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ double val = 2560.001;
+ double neg = -2560.001;
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ DoDoubleTest("foo %g", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %lg", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %hg", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %Lg", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %I64g", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %5g", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %-5g", val, "foo 2560 ", "foo 2560 ");
+ DoDoubleTest("foo %.1g", val, "foo 3e+003", "foo 3e+03");
+ DoDoubleTest("foo %.2g", val, "foo 2.6e+003", "foo 2.6e+03");
+ DoDoubleTest("foo %.12g", val, "foo 2560.001", "foo 2560.001");
+ DoDoubleTest("foo %06g", val, "foo 002560", "foo 002560");
+ DoDoubleTest("foo %#g", val, "foo 2560.00", "foo 2560.00");
+ DoDoubleTest("foo %+g", val, "foo +2560", "foo +2560");
+ DoDoubleTest("foo % g", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %+g", neg, "foo -2560", "foo -2560");
+ DoDoubleTest("foo % g", neg, "foo -2560", "foo -2560");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/vprintf/test17/testinfo.dat b/src/pal/tests/palsuite/c_runtime/vprintf/test17/testinfo.dat
new file mode 100644
index 0000000000..9f40fb03a0
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vprintf/test17/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = vprintf
+Name = Positive Test for vprintf
+TYPE = DEFAULT
+EXE1 = test17
+Description
+= Tests vprintf with compact format doubles (lowercase)
diff --git a/src/pal/tests/palsuite/c_runtime/vprintf/test18/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/vprintf/test18/CMakeLists.txt
new file mode 100644
index 0000000000..45676b93dd
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vprintf/test18/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test18.c
+)
+
+add_executable(paltest_vprintf_test18
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vprintf_test18 coreclrpal)
+
+target_link_libraries(paltest_vprintf_test18
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/vprintf/test18/test18.c b/src/pal/tests/palsuite/c_runtime/vprintf/test18/test18.c
new file mode 100644
index 0000000000..6fde79b5fb
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vprintf/test18/test18.c
@@ -0,0 +1,51 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test18.c
+**
+** Purpose: Test #18 for the vprintf function. Tests the uppercase
+** shorthand notation double specifier (%G)
+**
+**
+**==========================================================================*/
+
+
+#include <palsuite.h>
+#include "../vprintf.h"
+
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ double val = 2560.001;
+ double neg = -2560.001;
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ DoDoubleTest("foo %G", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %lG", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %hG", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %LG", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %I64G", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %5G", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %-5G", val, "foo 2560 ", "foo 2560 ");
+ DoDoubleTest("foo %.1G", val, "foo 3E+003", "foo 3E+03");
+ DoDoubleTest("foo %.2G", val, "foo 2.6E+003", "foo 2.6E+03");
+ DoDoubleTest("foo %.12G", val, "foo 2560.001", "foo 2560.001");
+ DoDoubleTest("foo %06G", val, "foo 002560", "foo 002560");
+ DoDoubleTest("foo %#G", val, "foo 2560.00", "foo 2560.00");
+ DoDoubleTest("foo %+G", val, "foo +2560", "foo +2560");
+ DoDoubleTest("foo % G", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %+G", neg, "foo -2560", "foo -2560");
+ DoDoubleTest("foo % G", neg, "foo -2560", "foo -2560");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/vprintf/test18/testinfo.dat b/src/pal/tests/palsuite/c_runtime/vprintf/test18/testinfo.dat
new file mode 100644
index 0000000000..b41f8c63e0
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vprintf/test18/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = vprintf
+Name = Positive Test for vprintf
+TYPE = DEFAULT
+EXE1 = test18
+Description
+= Tests vprintf with compact format doubles (uppercase)
diff --git a/src/pal/tests/palsuite/c_runtime/vprintf/test19/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/vprintf/test19/CMakeLists.txt
new file mode 100644
index 0000000000..25bc2fccd1
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vprintf/test19/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test19.c
+)
+
+add_executable(paltest_vprintf_test19
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vprintf_test19 coreclrpal)
+
+target_link_libraries(paltest_vprintf_test19
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/vprintf/test19/test19.c b/src/pal/tests/palsuite/c_runtime/vprintf/test19/test19.c
new file mode 100644
index 0000000000..d79f2e2591
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vprintf/test19/test19.c
@@ -0,0 +1,76 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test19.c
+**
+** Purpose: Test #19 for the vprintf function. Tests the variable length
+** precision argument.
+**
+**
+**==========================================================================*/
+
+
+#include <palsuite.h>
+#include "../vprintf.h"
+
+
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ int n = -1;
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ DoArgumentPrecTest("%.*s", 2, "bar", "bar", "ba", "ba");
+ DoArgumentPrecTest("%.*S", 2, convert("bar"), "bar", "ba", "ba");
+
+ DoArgumentPrecTest("%.*n", 3, &n, "pointer to int", "", "");
+ if (n != 0)
+ {
+ Fail("ERROR: Expected count parameter to resolve to %d, got %X\n",
+ 0, n);
+ }
+
+ DoArgumentPrecTest("%.*c", 0, (void*)'a', "a", "a", "a");
+ DoArgumentPrecTest("%.*c", 4, (void*)'a', "a", "a", "a");
+ DoArgumentPrecTest("%.*C", 0, (void*)'a', "a", "a", "a");
+ DoArgumentPrecTest("%.*C", 4, (void*)'a', "a", "a", "a");
+ DoArgumentPrecTest("%.*d", 1, (void*)42, "42", "42", "42");
+ DoArgumentPrecTest("%.*d", 3, (void*)42, "42", "042", "042");
+ DoArgumentPrecTest("%.*i", 1, (void*)42, "42", "42", "42");
+ DoArgumentPrecTest("%.*i", 3, (void*)42, "42", "042", "042");
+ DoArgumentPrecTest("%.*o", 1, (void*)42, "42", "52", "52");
+ DoArgumentPrecTest("%.*o", 3, (void*)42, "42", "052", "052");
+ DoArgumentPrecTest("%.*u", 1, (void*)42, "42", "42", "42");
+ DoArgumentPrecTest("%.*u", 3, (void*)42, "42", "042", "042");
+ DoArgumentPrecTest("%.*x", 1, (void*)0x42, "0x42", "42", "42");
+ DoArgumentPrecTest("%.*x", 3, (void*)0x42, "0x42", "042", "042");
+ DoArgumentPrecTest("%.*X", 1, (void*)0x42, "0x42", "42", "42");
+ DoArgumentPrecTest("%.*X", 3, (void*)0x42, "0x42", "042", "042");
+
+
+ DoArgumentPrecDoubleTest("%.*e", 1, 2.01, "2.0e+000", "2.0e+00");
+ DoArgumentPrecDoubleTest("%.*e", 3, 2.01, "2.010e+000", "2.010e+00");
+ DoArgumentPrecDoubleTest("%.*E", 1, 2.01, "2.0E+000", "2.0E+00");
+ DoArgumentPrecDoubleTest("%.*E", 3, 2.01, "2.010E+000", "2.010E+00");
+ DoArgumentPrecDoubleTest("%.*f", 1, 2.01, "2.0", "2.0");
+ DoArgumentPrecDoubleTest("%.*f", 3, 2.01, "2.010", "2.010");
+ DoArgumentPrecDoubleTest("%.*g", 1, 256.01, "3e+002", "3e+02");
+ DoArgumentPrecDoubleTest("%.*g", 3, 256.01, "256", "256");
+ DoArgumentPrecDoubleTest("%.*g", 4, 256.01, "256", "256");
+ DoArgumentPrecDoubleTest("%.*g", 6, 256.01, "256.01", "256.01");
+ DoArgumentPrecDoubleTest("%.*G", 1, 256.01, "3E+002", "3E+02");
+ DoArgumentPrecDoubleTest("%.*G", 3, 256.01, "256", "256");
+ DoArgumentPrecDoubleTest("%.*G", 4, 256.01, "256", "256");
+ DoArgumentPrecDoubleTest("%.*G", 6, 256.01, "256.01", "256.01");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/vprintf/test19/testinfo.dat b/src/pal/tests/palsuite/c_runtime/vprintf/test19/testinfo.dat
new file mode 100644
index 0000000000..03c3afa693
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vprintf/test19/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = vprintf
+Name = Positive Test for vprintf
+TYPE = DEFAULT
+EXE1 = test19
+Description
+= Tests vprintf with argument specified precision
diff --git a/src/pal/tests/palsuite/c_runtime/vprintf/test2/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/vprintf/test2/CMakeLists.txt
new file mode 100644
index 0000000000..6820069cb9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vprintf/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test2.c
+)
+
+add_executable(paltest_vprintf_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vprintf_test2 coreclrpal)
+
+target_link_libraries(paltest_vprintf_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/vprintf/test2/test2.c b/src/pal/tests/palsuite/c_runtime/vprintf/test2/test2.c
new file mode 100644
index 0000000000..4d9c9bc6f5
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vprintf/test2/test2.c
@@ -0,0 +1,45 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test2.c
+**
+** Purpose: Test #2 for the vprintf function. Tests the string specifier
+** (%s).
+**
+**
+**==========================================================================*/
+
+
+#include <palsuite.h>
+#include "../vprintf.h"
+
+
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ DoStrTest("foo %s", "bar", "foo bar");
+ DoStrTest("foo %hs", "bar", "foo bar");
+ DoWStrTest("foo %ls", convert("bar"), "foo bar");
+ DoWStrTest("foo %ws", convert("bar"), "foo bar");
+ DoStrTest("foo %Ls", "bar", "foo bar");
+ DoStrTest("foo %I64s", "bar", "foo bar");
+ DoStrTest("foo %5s", "bar", "foo bar");
+ DoStrTest("foo %.2s", "bar", "foo ba");
+ DoStrTest("foo %5.2s", "bar", "foo ba");
+ DoStrTest("foo %-5s", "bar", "foo bar ");
+ DoStrTest("foo %05s", "bar", "foo 00bar");
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/vprintf/test2/testinfo.dat b/src/pal/tests/palsuite/c_runtime/vprintf/test2/testinfo.dat
new file mode 100644
index 0000000000..32c1d70d9e
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vprintf/test2/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = vprintf
+Name = Positive Test for vprintf
+TYPE = DEFAULT
+EXE1 = test2
+Description
+= Tests vprintf with strings
diff --git a/src/pal/tests/palsuite/c_runtime/vprintf/test3/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/vprintf/test3/CMakeLists.txt
new file mode 100644
index 0000000000..676d19bf7a
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vprintf/test3/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test3.c
+)
+
+add_executable(paltest_vprintf_test3
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vprintf_test3 coreclrpal)
+
+target_link_libraries(paltest_vprintf_test3
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/vprintf/test3/test3.c b/src/pal/tests/palsuite/c_runtime/vprintf/test3/test3.c
new file mode 100644
index 0000000000..5376c56b76
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vprintf/test3/test3.c
@@ -0,0 +1,45 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test3.c
+**
+** Purpose: Test #3 for the vprintf function. Tests the wide string
+** specifier (%S).
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../vprintf.h"
+
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ DoWStrTest("foo %S", convert("bar"), "foo bar");
+ DoStrTest("foo %hS", "bar", "foo bar");
+ DoWStrTest("foo %lS", convert("bar"), "foo bar");
+ DoWStrTest("foo %wS", convert("bar"), "foo bar");
+ DoWStrTest("foo %LS", convert("bar"), "foo bar");
+ DoWStrTest("foo %I64S", convert("bar"), "foo bar");
+ DoWStrTest("foo %5S", convert("bar"), "foo bar");
+ DoWStrTest("foo %.2S", convert("bar"), "foo ba");
+ DoWStrTest("foo %5.2S", convert("bar"), "foo ba");
+ DoWStrTest("foo %-5S", convert("bar"), "foo bar ");
+ DoWStrTest("foo %05S", convert("bar"), "foo 00bar");
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/vprintf/test3/testinfo.dat b/src/pal/tests/palsuite/c_runtime/vprintf/test3/testinfo.dat
new file mode 100644
index 0000000000..c3b385e8f1
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vprintf/test3/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = vprintf
+Name = Positive Test for vprintf
+TYPE = DEFAULT
+EXE1 = test3
+Description
+= Tests vprintf with wide strings
diff --git a/src/pal/tests/palsuite/c_runtime/vprintf/test4/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/vprintf/test4/CMakeLists.txt
new file mode 100644
index 0000000000..9ddb087e83
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vprintf/test4/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test4.c
+)
+
+add_executable(paltest_vprintf_test4
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vprintf_test4 coreclrpal)
+
+target_link_libraries(paltest_vprintf_test4
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/vprintf/test4/test4.c b/src/pal/tests/palsuite/c_runtime/vprintf/test4/test4.c
new file mode 100644
index 0000000000..3b66cde22e
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vprintf/test4/test4.c
@@ -0,0 +1,70 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test4.c
+**
+** Purpose: Test #4 for the vprintf function. Tests the pointer
+** specifier (%p).
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../vprintf.h"
+
+
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ void *ptr = (void*) 0x123456;
+ INT64 lptr = I64(0x1234567887654321);
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+/*
+** Run only on 64 bit platforms
+*/
+#if defined(BIT64) && defined(PLATFORM_UNIX)
+ Trace("Testing for 64 Bit Platforms \n");
+ DoPointerTest("%p", NULL, "NULL", "0000000000000000");
+ DoPointerTest("%p", ptr, "pointer to 0x123456", "0000000000123456");
+ DoPointerTest("%17p", ptr, "pointer to 0x123456", " 0000000000123456");
+ DoPointerTest("%17p", ptr, "pointer to 0x123456", " 0000000000123456");
+ DoPointerTest("%-17p", ptr, "pointer to 0x123456", "0000000000123456 ");
+ DoPointerTest("%+p", ptr, "pointer to 0x123456", "0000000000123456");
+ DoPointerTest("%#p", ptr, "pointer to 0x123456", "0X0000000000123456");
+ DoPointerTest("%lp", ptr, "pointer to 0x123456", "00123456");
+ DoPointerTest("%hp", ptr, "pointer to 0x123456", "00003456");
+ DoPointerTest("%Lp", ptr, "pointer to 0x123456", "00123456");
+ DoI64Test("%I64p", lptr, "pointer to 0x1234567887654321",
+ "1234567887654321");
+
+#else
+ Trace("Testing for Non 64 Bit Platforms \n");
+ DoPointerTest("%p", NULL, "NULL", "00000000");
+ DoPointerTest("%p", ptr, "pointer to 0x123456", "00123456");
+ DoPointerTest("%9p", ptr, "pointer to 0x123456", " 00123456");
+ DoPointerTest("%09p", ptr, "pointer to 0x123456", " 00123456");
+ DoPointerTest("%-9p", ptr, "pointer to 0x123456", "00123456 ");
+ DoPointerTest("%+p", ptr, "pointer to 0x123456", "00123456");
+ DoPointerTest("%#p", ptr, "pointer to 0x123456", "0X00123456");
+ DoPointerTest("%lp", ptr, "pointer to 0x123456", "00123456");
+ DoPointerTest("%hp", ptr, "pointer to 0x123456", "00003456");
+ DoPointerTest("%Lp", ptr, "pointer to 0x123456", "00123456");
+ DoI64Test("%I64p", lptr, "pointer to 0x1234567887654321",
+ "1234567887654321");
+
+#endif
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/vprintf/test4/testinfo.dat b/src/pal/tests/palsuite/c_runtime/vprintf/test4/testinfo.dat
new file mode 100644
index 0000000000..74c4ce932e
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vprintf/test4/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = vprintf
+Name = Positive Test for vprintf
+TYPE = DEFAULT
+EXE1 = test4
+Description
+= Tests vprintf with pointers
diff --git a/src/pal/tests/palsuite/c_runtime/vprintf/test5/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/vprintf/test5/CMakeLists.txt
new file mode 100644
index 0000000000..f453bb66ee
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vprintf/test5/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test5.c
+)
+
+add_executable(paltest_vprintf_test5
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vprintf_test5 coreclrpal)
+
+target_link_libraries(paltest_vprintf_test5
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/vprintf/test5/test5.c b/src/pal/tests/palsuite/c_runtime/vprintf/test5/test5.c
new file mode 100644
index 0000000000..c9e2901230
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vprintf/test5/test5.c
@@ -0,0 +1,60 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test5.c
+**
+** Purpose: Test #5 for the vprintf function. Tests the count specifier (%n).
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../vprintf.h"
+
+
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ char *longStr =
+ "really-long-string-that-just-keeps-going-on-and-on-and-on.."
+ "..................useless-filler.................................."
+ "..................useless-filler.................................."
+ "..................useless-filler.................................."
+ "%n bar";
+ char *longResult =
+ "really-long-string-that-just-keeps-going-on-and-on-and-on.."
+ "..................useless-filler.................................."
+ "..................useless-filler.................................."
+ "..................useless-filler.................................."
+ " bar";
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ DoCountTest("foo %n bar", 4, "foo bar");
+ DoCountTest(longStr, 257, longResult);
+ DoCountTest("fo%n bar", 2, "fo bar");
+ DoCountTest("%n", 0, "");
+ DoCountTest("foo %#n bar", 4, "foo bar");
+ DoCountTest("foo % n bar", 4, "foo bar");
+ DoCountTest("foo %+n bar", 4, "foo bar");
+ DoCountTest("foo %-n bar", 4, "foo bar");
+ DoCountTest("foo %0n bar", 4, "foo bar");
+ DoShortCountTest("foo %hn bar", 4, "foo bar");
+ DoCountTest("foo %ln bar", 4, "foo bar");
+ DoCountTest("foo %Ln bar", 4, "foo bar");
+ DoCountTest("foo %I64n bar", 4, "foo bar");
+ DoCountTest("foo %20.3n bar", 4, "foo bar");
+
+ PAL_Terminate();
+
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/vprintf/test5/testinfo.dat b/src/pal/tests/palsuite/c_runtime/vprintf/test5/testinfo.dat
new file mode 100644
index 0000000000..01ff864208
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vprintf/test5/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = vprintf
+Name = Positive Test for vprintf
+TYPE = DEFAULT
+EXE1 = test5
+Description
+= Tests vprintf with the count specifier
diff --git a/src/pal/tests/palsuite/c_runtime/vprintf/test6/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/vprintf/test6/CMakeLists.txt
new file mode 100644
index 0000000000..1ce8d5aa4c
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vprintf/test6/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test6.c
+)
+
+add_executable(paltest_vprintf_test6
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vprintf_test6 coreclrpal)
+
+target_link_libraries(paltest_vprintf_test6
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/vprintf/test6/test6.c b/src/pal/tests/palsuite/c_runtime/vprintf/test6/test6.c
new file mode 100644
index 0000000000..6a83cccea6
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vprintf/test6/test6.c
@@ -0,0 +1,48 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test6.c
+**
+** Purpose: Test #6 for the vprintf function. Tests the char specifier (%c).
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../vprintf.h"
+
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ WCHAR wc = (WCHAR) 'c';
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ DoCharTest("foo %c", 'b', "foo b");
+ DoCharTest("foo %hc", 'b', "foo b");
+ DoWCharTest("foo %lc", wc, "foo c");
+ DoCharTest("foo %Lc", 'b', "foo b");
+ DoCharTest("foo %I64c", 'b', "foo b");
+ DoCharTest("foo %5c", 'b', "foo b");
+ DoCharTest("foo %.0c", 'b', "foo b");
+ DoCharTest("foo %-5c", 'b', "foo b ");
+ DoCharTest("foo %05c", 'b', "foo 0000b");
+ DoCharTest("foo % c", 'b', "foo b");
+ DoCharTest("foo %#c", 'b', "foo b");
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
+
diff --git a/src/pal/tests/palsuite/c_runtime/vprintf/test6/testinfo.dat b/src/pal/tests/palsuite/c_runtime/vprintf/test6/testinfo.dat
new file mode 100644
index 0000000000..ce450183f6
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vprintf/test6/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = vprintf
+Name = Positive Test for vprintf
+TYPE = DEFAULT
+EXE1 = test6
+Description
+= Tests vprintf with characters
diff --git a/src/pal/tests/palsuite/c_runtime/vprintf/test7/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/vprintf/test7/CMakeLists.txt
new file mode 100644
index 0000000000..5627fe4c1e
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vprintf/test7/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test7.c
+)
+
+add_executable(paltest_vprintf_test7
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vprintf_test7 coreclrpal)
+
+target_link_libraries(paltest_vprintf_test7
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/vprintf/test7/test7.c b/src/pal/tests/palsuite/c_runtime/vprintf/test7/test7.c
new file mode 100644
index 0000000000..5096ace42c
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vprintf/test7/test7.c
@@ -0,0 +1,47 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test7.c
+**
+** Purpose: Test #7 for the vprintf function. Tests the wide char
+** specifier (%C).
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../vprintf.h"
+
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ WCHAR wb = (WCHAR) 'b';
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ DoWCharTest("foo %C", wb, "foo b");
+ DoWCharTest("foo %hC", wb, "foo b");
+ DoCharTest("foo %lC", 'c', "foo c");
+ DoWCharTest("foo %LC", wb, "foo b");
+ DoWCharTest("foo %I64C", wb, "foo b");
+ DoWCharTest("foo %5C", wb, "foo b");
+ DoWCharTest("foo %.0C", wb, "foo b");
+ DoWCharTest("foo %-5C", wb, "foo b ");
+ DoWCharTest("foo %05C", wb, "foo 0000b");
+ DoWCharTest("foo % C", wb, "foo b");
+ DoWCharTest("foo %#C", wb, "foo b");
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/vprintf/test7/testinfo.dat b/src/pal/tests/palsuite/c_runtime/vprintf/test7/testinfo.dat
new file mode 100644
index 0000000000..254e31e5f8
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vprintf/test7/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = vprintf
+Name = Positive Test for vprintf
+TYPE = DEFAULT
+EXE1 = test7
+Description
+= Tests vprintf with wide characters
diff --git a/src/pal/tests/palsuite/c_runtime/vprintf/test8/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/vprintf/test8/CMakeLists.txt
new file mode 100644
index 0000000000..0131e4943e
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vprintf/test8/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test8.c
+)
+
+add_executable(paltest_vprintf_test8
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vprintf_test8 coreclrpal)
+
+target_link_libraries(paltest_vprintf_test8
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/vprintf/test8/test8.c b/src/pal/tests/palsuite/c_runtime/vprintf/test8/test8.c
new file mode 100644
index 0000000000..2683339ece
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vprintf/test8/test8.c
@@ -0,0 +1,53 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test8.c
+**
+** Purpose: Test #8 for the vprintf function. Tests the decimal
+** specifier (%d).
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../vprintf.h"
+
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ int neg = -42;
+ int pos = 42;
+ INT64 l = 42;
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ DoNumTest("foo %d", pos, "foo 42");
+ DoNumTest("foo %ld", 0xFFFF, "foo 65535");
+ DoNumTest("foo %hd", 0xFFFF, "foo -1");
+ DoNumTest("foo %Ld", pos, "foo 42");
+ DoI64Test("foo %I64d", l, "42", "foo 42");
+ DoNumTest("foo %3d", pos, "foo 42");
+ DoNumTest("foo %-3d", pos, "foo 42 ");
+ DoNumTest("foo %.1d", pos, "foo 42");
+ DoNumTest("foo %.3d", pos, "foo 042");
+ DoNumTest("foo %03d", pos, "foo 042");
+ DoNumTest("foo %#d", pos, "foo 42");
+ DoNumTest("foo %+d", pos, "foo +42");
+ DoNumTest("foo % d", pos, "foo 42");
+ DoNumTest("foo %+d", neg, "foo -42");
+ DoNumTest("foo % d", neg, "foo -42");
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/vprintf/test8/testinfo.dat b/src/pal/tests/palsuite/c_runtime/vprintf/test8/testinfo.dat
new file mode 100644
index 0000000000..73f287b9fe
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vprintf/test8/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = vprintf
+Name = Positive Test for vprintf
+TYPE = DEFAULT
+EXE1 = test8
+Description
+= Tests vprintf with decimal numbers
diff --git a/src/pal/tests/palsuite/c_runtime/vprintf/test9/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/vprintf/test9/CMakeLists.txt
new file mode 100644
index 0000000000..c70631f9dc
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vprintf/test9/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test9.c
+)
+
+add_executable(paltest_vprintf_test9
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vprintf_test9 coreclrpal)
+
+target_link_libraries(paltest_vprintf_test9
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/vprintf/test9/test9.c b/src/pal/tests/palsuite/c_runtime/vprintf/test9/test9.c
new file mode 100644
index 0000000000..8545bc760e
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vprintf/test9/test9.c
@@ -0,0 +1,53 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test9.c
+**
+** Purpose: Test #9 for the vprintf function. Tests the integer
+** specifier (%i).
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../vprintf.h"
+
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ int neg = -42;
+ int pos = 42;
+ INT64 l = 42;
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ DoNumTest("foo %i", pos, "foo 42");
+ DoNumTest("foo %li", 0xFFFF, "foo 65535");
+ DoNumTest("foo %hi", 0xFFFF, "foo -1");
+ DoNumTest("foo %Li", pos, "foo 42");
+ DoI64Test("foo %I64i", l, "42", "foo 42");
+ DoNumTest("foo %3i", pos, "foo 42");
+ DoNumTest("foo %-3i", pos, "foo 42 ");
+ DoNumTest("foo %.1i", pos, "foo 42");
+ DoNumTest("foo %.3i", pos, "foo 042");
+ DoNumTest("foo %03i", pos, "foo 042");
+ DoNumTest("foo %#i", pos, "foo 42");
+ DoNumTest("foo %+i", pos, "foo +42");
+ DoNumTest("foo % i", pos, "foo 42");
+ DoNumTest("foo %+i", neg, "foo -42");
+ DoNumTest("foo % i", neg, "foo -42");
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/vprintf/test9/testinfo.dat b/src/pal/tests/palsuite/c_runtime/vprintf/test9/testinfo.dat
new file mode 100644
index 0000000000..c4c77b9d11
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vprintf/test9/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = vprintf
+Name = Positive Test for vprintf
+TYPE = DEFAULT
+EXE1 = test9
+Description
+= Tests vprintf with integer numbers
diff --git a/src/pal/tests/palsuite/c_runtime/vprintf/vprintf.h b/src/pal/tests/palsuite/c_runtime/vprintf/vprintf.h
new file mode 100644
index 0000000000..477db32f4d
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vprintf/vprintf.h
@@ -0,0 +1,193 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: vprintf.h
+**
+** Purpose: Containts common testing functions for vprintf
+**
+**
+**==========================================================================*/
+
+#ifndef __vprintf_H__
+#define __vprintf_H__
+
+int DoVprintf(char *format, ...)
+{
+ int retVal;
+ va_list arglist;
+
+ va_start(arglist, format);
+ retVal = vprintf(format, arglist);
+ va_end(arglist);
+
+ return (retVal);
+}
+
+void DoStrTest(char *formatstr, char* param, char *checkstr)
+{
+ int ret;
+
+ ret = DoVprintf(formatstr, param);
+ if (ret != strlen(checkstr))
+ {
+ Fail("Expected vprintf to return %d, got %d.\n",
+ strlen(checkstr), ret);
+ }
+}
+
+void DoWStrTest(char *formatstr, WCHAR* param, char *checkstr)
+{
+ int ret;
+
+ ret = DoVprintf(formatstr, param);
+ if (ret != strlen(checkstr))
+ {
+ Fail("Expected vprintf to return %d, got %d.\n",
+ strlen(checkstr), ret);
+ }
+}
+
+void DoPointerTest(char *formatstr, void* param, char* paramstr,
+ char *checkstr1)
+{
+ int ret;
+
+ ret = DoVprintf(formatstr, param);
+ if (ret != strlen(checkstr1))
+ {
+ Fail("Expected vprintf to return %d, got %d.\n",
+ strlen(checkstr1), ret);
+ }
+}
+
+void DoCountTest(char *formatstr, int param, char *checkstr)
+{
+ int ret;
+ int n = -1;
+
+ ret = DoVprintf(formatstr, &n);
+
+ if (n != param)
+ {
+ Fail("Expected count parameter to resolve to %d, got %d\n", param, n);
+ }
+
+ if (ret != strlen(checkstr))
+ {
+ Fail("Expected vprintf to return %d, got %d.\n",
+ strlen(checkstr), ret);
+ }
+}
+
+void DoShortCountTest(char *formatstr, int param, char *checkstr)
+{
+ int ret;
+ short int n = -1;
+
+ ret = DoVprintf(formatstr, &n);
+
+ if (n != param)
+ {
+ Fail("Expected count parameter to resolve to %d, got %d\n", param, n);
+ }
+
+ if (ret != strlen(checkstr))
+ {
+ Fail("Expected vprintf to return %d, got %d.\n",
+ strlen(checkstr), ret);
+ }
+}
+
+
+void DoCharTest(char *formatstr, char param, char *checkstr)
+{
+ int ret;
+
+ ret = DoVprintf(formatstr, param);
+ if (ret != strlen(checkstr))
+ {
+ Fail("Expected vprintf to return %d, got %d.\n",
+ strlen(checkstr), ret);
+ }
+}
+
+void DoWCharTest(char *formatstr, WCHAR param, char *checkstr)
+{
+ int ret;
+
+ ret = DoVprintf(formatstr, param);
+ if (ret != strlen(checkstr))
+ {
+ Fail("Expected vprintf to return %d, got %d.\n",
+ strlen(checkstr), ret);
+ }
+}
+
+void DoNumTest(char *formatstr, int param, char *checkstr)
+{
+ int ret;
+
+ ret = DoVprintf(formatstr, param);
+ if (ret != strlen(checkstr))
+ {
+ Fail("Expected vprintf to return %d, got %d.\n",
+ strlen(checkstr), ret);
+ }
+}
+
+void DoI64Test(char *formatstr, INT64 param, char *valuestr, char *checkstr1)
+{
+ int ret;
+
+ ret = DoVprintf(formatstr, param);
+ if (ret != strlen(checkstr1))
+ {
+ Fail("Expected vprintf to return %d, got %d.\n",
+ strlen(checkstr1), ret);
+ }
+}
+
+void DoDoubleTest(char *formatstr, double param, char *checkstr1,
+ char *checkstr2)
+{
+ int ret;
+
+ ret = DoVprintf(formatstr, param);
+ if (ret != strlen(checkstr1) && ret != strlen(checkstr2))
+ {
+ Fail("Expected vprintf to return %d or %d, got %d.\n",
+ strlen(checkstr1), strlen(checkstr2), ret);
+ }
+}
+
+void DoArgumentPrecTest(char *formatstr, int precision, void *param,
+ char *paramstr, char *checkstr1, char *checkstr2)
+{
+ int ret;
+
+ ret = DoVprintf(formatstr, precision, param);
+ if (ret != strlen(checkstr1) && ret != strlen(checkstr2))
+ {
+ Fail("Expected vprintf to return %d or %d, got %d.\n",
+ strlen(checkstr1), strlen(checkstr2), ret);
+ }
+}
+
+void DoArgumentPrecDoubleTest(char *formatstr, int precision, double param,
+ char *checkstr1, char *checkstr2)
+{
+ int ret;
+
+ ret = DoVprintf(formatstr, precision, param);
+ if (ret != strlen(checkstr1) && ret != strlen(checkstr2))
+ {
+ Fail("Expected vprintf to return %d or %d, got %d.\n",
+ strlen(checkstr1), strlen(checkstr2), ret);
+ }
+}
+
+#endif
+
diff --git a/src/pal/tests/palsuite/c_runtime/vsprintf/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/vsprintf/CMakeLists.txt
new file mode 100644
index 0000000000..cafb9536b0
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vsprintf/CMakeLists.txt
@@ -0,0 +1,22 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test10)
+add_subdirectory(test11)
+add_subdirectory(test12)
+add_subdirectory(test13)
+add_subdirectory(test14)
+add_subdirectory(test15)
+add_subdirectory(test16)
+add_subdirectory(test17)
+add_subdirectory(test18)
+add_subdirectory(test19)
+add_subdirectory(test2)
+add_subdirectory(test3)
+add_subdirectory(test4)
+add_subdirectory(test5)
+add_subdirectory(test6)
+add_subdirectory(test7)
+add_subdirectory(test8)
+add_subdirectory(test9)
+
diff --git a/src/pal/tests/palsuite/c_runtime/vsprintf/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/vsprintf/test1/CMakeLists.txt
new file mode 100644
index 0000000000..4f0872eccc
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vsprintf/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_vsprintf_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vsprintf_test1 coreclrpal)
+
+target_link_libraries(paltest_vsprintf_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/vsprintf/test1/test1.c b/src/pal/tests/palsuite/c_runtime/vsprintf/test1/test1.c
new file mode 100644
index 0000000000..2007fefc5b
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vsprintf/test1/test1.c
@@ -0,0 +1,55 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test1.c
+**
+** Purpose: Test #1 for the vsprintf function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+#include "../vsprintf.h"
+
+/*
+ * Notes: memcmp is used, as is strlen.
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ char checkstr[] = "hello world";
+ char buf[256] = { 0 };
+ int ret;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return(FAIL);
+ }
+
+ testvsp(buf, "hello world");
+
+ if (memcmp(checkstr, buf, strlen(checkstr)+1) != 0)
+ {
+ Fail("ERROR: expected \"%s\" (up to %d chars), got \"%s\"\n",
+ checkstr, 256, buf);
+ }
+
+ testvsp(buf, "xxxxxxxxxxxxxxxxx");
+ ret = testvsp(buf, "hello world");
+
+ if (ret != strlen(checkstr))
+ {
+ Fail("ERROR: expected negative return value, got %d", ret);
+ }
+
+ if (memcmp(checkstr, buf, ret) != 0)
+ {
+ Fail("ERROR: expected %s, got %s\n", checkstr, buf);
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/vsprintf/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/vsprintf/test1/testinfo.dat
new file mode 100644
index 0000000000..996364f366
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vsprintf/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = vsprintf
+Name = Positive Test for vsprintf
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Tests the PAL implementation of the vsprintf function.
+= This test is modeled after _snprintf.
diff --git a/src/pal/tests/palsuite/c_runtime/vsprintf/test10/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/vsprintf/test10/CMakeLists.txt
new file mode 100644
index 0000000000..d32de01ba1
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vsprintf/test10/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test10.c
+)
+
+add_executable(paltest_vsprintf_test10
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vsprintf_test10 coreclrpal)
+
+target_link_libraries(paltest_vsprintf_test10
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/vsprintf/test10/test10.c b/src/pal/tests/palsuite/c_runtime/vsprintf/test10/test10.c
new file mode 100644
index 0000000000..791213fccc
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vsprintf/test10/test10.c
@@ -0,0 +1,50 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test10.c
+**
+** Purpose: Test #10 for the vsprintf function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+#include "../vsprintf.h"
+
+/*
+ * Notes: memcmp is used, as is strlen.
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ int neg = -42;
+ int pos = 42;
+ INT64 l = 42;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return(FAIL);
+ }
+
+ DoNumTest("foo %o", pos, "foo 52");
+ DoNumTest("foo %lo", 0xFFFF, "foo 177777");
+ DoNumTest("foo %ho", 0xFFFF, "foo 177777");
+ DoNumTest("foo %Lo", pos, "foo 52");
+ DoI64Test("foo %I64o", l, "42", "foo 52");
+ DoNumTest("foo %3o", pos, "foo 52");
+ DoNumTest("foo %-3o", pos, "foo 52 ");
+ DoNumTest("foo %.1o", pos, "foo 52");
+ DoNumTest("foo %.3o", pos, "foo 052");
+ DoNumTest("foo %03o", pos, "foo 052");
+ DoNumTest("foo %#o", pos, "foo 052");
+ DoNumTest("foo %+o", pos, "foo 52");
+ DoNumTest("foo % o", pos, "foo 52");
+ DoNumTest("foo %+o", neg, "foo 37777777726");
+ DoNumTest("foo % o", neg, "foo 37777777726");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/vsprintf/test10/testinfo.dat b/src/pal/tests/palsuite/c_runtime/vsprintf/test10/testinfo.dat
new file mode 100644
index 0000000000..1a1f4ef217
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vsprintf/test10/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = vsprintf
+Name = Positive Test for vsprintf
+TYPE = DEFAULT
+EXE1 = test10
+Description
+= Tests the PAL implementation of the vsprintf function.
+= Tests vsprintf with octal numbers.
+= This test is modeled after _snprintf.
diff --git a/src/pal/tests/palsuite/c_runtime/vsprintf/test11/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/vsprintf/test11/CMakeLists.txt
new file mode 100644
index 0000000000..ce67444c39
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vsprintf/test11/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test11.c
+)
+
+add_executable(paltest_vsprintf_test11
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vsprintf_test11 coreclrpal)
+
+target_link_libraries(paltest_vsprintf_test11
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/vsprintf/test11/test11.c b/src/pal/tests/palsuite/c_runtime/vsprintf/test11/test11.c
new file mode 100644
index 0000000000..e0af94981b
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vsprintf/test11/test11.c
@@ -0,0 +1,50 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test11.c
+**
+** Purpose: Test #11 for the vsprintf function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+#include "../vsprintf.h"
+
+/*
+ * Notes: memcmp is used, as is strlen.
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ int neg = -42;
+ int pos = 42;
+ INT64 l = 42;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return(FAIL);
+ }
+
+ DoNumTest("foo %u", pos, "foo 42");
+ DoNumTest("foo %lu", 0xFFFF, "foo 65535");
+ DoNumTest("foo %hu", 0xFFFF, "foo 65535");
+ DoNumTest("foo %Lu", pos, "foo 42");
+ DoI64Test("foo %I64u", l, "42", "foo 42");
+ DoNumTest("foo %3u", pos, "foo 42");
+ DoNumTest("foo %-3u", pos, "foo 42 ");
+ DoNumTest("foo %.1u", pos, "foo 42");
+ DoNumTest("foo %.3u", pos, "foo 042");
+ DoNumTest("foo %03u", pos, "foo 042");
+ DoNumTest("foo %#u", pos, "foo 42");
+ DoNumTest("foo %+u", pos, "foo 42");
+ DoNumTest("foo % u", pos, "foo 42");
+ DoNumTest("foo %+u", neg, "foo 4294967254");
+ DoNumTest("foo % u", neg, "foo 4294967254");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/vsprintf/test11/testinfo.dat b/src/pal/tests/palsuite/c_runtime/vsprintf/test11/testinfo.dat
new file mode 100644
index 0000000000..d44167e255
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vsprintf/test11/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = vsprintf
+Name = Positive Test for vsprintf
+TYPE = DEFAULT
+EXE1 = test11
+Description
+= Tests the PAL implementation of the vsprintf function.
+= Tests vsprintf with unsigned numbers.
+= This test is modeled after _snprintf.
diff --git a/src/pal/tests/palsuite/c_runtime/vsprintf/test12/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/vsprintf/test12/CMakeLists.txt
new file mode 100644
index 0000000000..fe6ccb8399
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vsprintf/test12/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test12.c
+)
+
+add_executable(paltest_vsprintf_test12
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vsprintf_test12 coreclrpal)
+
+target_link_libraries(paltest_vsprintf_test12
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/vsprintf/test12/test12.c b/src/pal/tests/palsuite/c_runtime/vsprintf/test12/test12.c
new file mode 100644
index 0000000000..f86ddcade8
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vsprintf/test12/test12.c
@@ -0,0 +1,52 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test12.c
+**
+** Purpose: Test #12 for the vsprintf function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+#include "../vsprintf.h"
+
+/*
+ * Notes: memcmp is used, as is strlen.
+ */
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ int neg = -42;
+ int pos = 0x1234ab;
+ INT64 l = I64(0x1234567887654321);
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return (FAIL);
+ }
+
+ DoNumTest("foo %x", pos, "foo 1234ab");
+ DoNumTest("foo %lx", pos, "foo 1234ab");
+ DoNumTest("foo %hx", pos, "foo 34ab");
+ DoNumTest("foo %Lx", pos, "foo 1234ab");
+ DoI64Test("foo %I64x", l, "0x1234567887654321",
+ "foo 1234567887654321");
+ DoNumTest("foo %7x", pos, "foo 1234ab");
+ DoNumTest("foo %-7x", pos, "foo 1234ab ");
+ DoNumTest("foo %.1x", pos, "foo 1234ab");
+ DoNumTest("foo %.7x", pos, "foo 01234ab");
+ DoNumTest("foo %07x", pos, "foo 01234ab");
+ DoNumTest("foo %#x", pos, "foo 0x1234ab");
+ DoNumTest("foo %+x", pos, "foo 1234ab");
+ DoNumTest("foo % x", pos, "foo 1234ab");
+ DoNumTest("foo %+x", neg, "foo ffffffd6");
+ DoNumTest("foo % x", neg, "foo ffffffd6");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/vsprintf/test12/testinfo.dat b/src/pal/tests/palsuite/c_runtime/vsprintf/test12/testinfo.dat
new file mode 100644
index 0000000000..781fb9cae8
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vsprintf/test12/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = vsprintf
+Name = Positive Test for vsprintf
+TYPE = DEFAULT
+EXE1 = test12
+Description
+= Tests the PAL implementation of the vsprintf function.
+= Tests vsprintf with hex numbers (lowercase).
+= This test is modeled after _snprintf.
diff --git a/src/pal/tests/palsuite/c_runtime/vsprintf/test13/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/vsprintf/test13/CMakeLists.txt
new file mode 100644
index 0000000000..97fdf8cdd0
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vsprintf/test13/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test13.c
+)
+
+add_executable(paltest_vsprintf_test13
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vsprintf_test13 coreclrpal)
+
+target_link_libraries(paltest_vsprintf_test13
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/vsprintf/test13/test13.c b/src/pal/tests/palsuite/c_runtime/vsprintf/test13/test13.c
new file mode 100644
index 0000000000..36e7825531
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vsprintf/test13/test13.c
@@ -0,0 +1,52 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test13.c
+**
+** Purpose: Test #13 for the vsprintf function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+#include "../vsprintf.h"
+
+/*
+ * Notes: memcmp is used, as is strlen.
+ */
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ int neg = -42;
+ int pos = 0x1234AB;
+ INT64 l = I64(0x1234567887654321);
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return(FAIL);
+ }
+
+ DoNumTest("foo %X", pos, "foo 1234AB");
+ DoNumTest("foo %lX", pos, "foo 1234AB");
+ DoNumTest("foo %hX", pos, "foo 34AB");
+ DoNumTest("foo %LX", pos, "foo 1234AB");
+ DoI64Test("foo %I64X", l, "0x1234567887654321",
+ "foo 1234567887654321");
+ DoNumTest("foo %7X", pos, "foo 1234AB");
+ DoNumTest("foo %-7X", pos, "foo 1234AB ");
+ DoNumTest("foo %.1X", pos, "foo 1234AB");
+ DoNumTest("foo %.7X", pos, "foo 01234AB");
+ DoNumTest("foo %07X", pos, "foo 01234AB");
+ DoNumTest("foo %#X", pos, "foo 0X1234AB");
+ DoNumTest("foo %+X", pos, "foo 1234AB");
+ DoNumTest("foo % X", pos, "foo 1234AB");
+ DoNumTest("foo %+X", neg, "foo FFFFFFD6");
+ DoNumTest("foo % X", neg, "foo FFFFFFD6");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/vsprintf/test13/testinfo.dat b/src/pal/tests/palsuite/c_runtime/vsprintf/test13/testinfo.dat
new file mode 100644
index 0000000000..7b28a91e65
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vsprintf/test13/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = vsprintf
+Name = Positive Test for vsprintf
+TYPE = DEFAULT
+EXE1 = test13
+Description
+= Tests the PAL implementation of the vsprintf function.
+= Tests vsprintf with hex numbers (uppercase).
+= This test is modeled after _snprintf.
diff --git a/src/pal/tests/palsuite/c_runtime/vsprintf/test14/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/vsprintf/test14/CMakeLists.txt
new file mode 100644
index 0000000000..2851a8893e
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vsprintf/test14/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test14.c
+)
+
+add_executable(paltest_vsprintf_test14
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vsprintf_test14 coreclrpal)
+
+target_link_libraries(paltest_vsprintf_test14
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/vsprintf/test14/test14.c b/src/pal/tests/palsuite/c_runtime/vsprintf/test14/test14.c
new file mode 100644
index 0000000000..360fafc37f
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vsprintf/test14/test14.c
@@ -0,0 +1,50 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test14.c
+**
+** Purpose: Test #14 for the vsprintf function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+#include "../vsprintf.h"
+
+/*
+ * Notes: memcmp is used, as is strlen.
+ */
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ double val = 256.0;
+ double neg = -256.0;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return(FAIL);
+ }
+
+ DoDoubleTest("foo %e", val, "foo 2.560000e+002", "foo 2.560000e+02");
+ DoDoubleTest("foo %le", val, "foo 2.560000e+002", "foo 2.560000e+02");
+ DoDoubleTest("foo %he", val, "foo 2.560000e+002", "foo 2.560000e+02");
+ DoDoubleTest("foo %Le", val, "foo 2.560000e+002", "foo 2.560000e+02");
+ DoDoubleTest("foo %I64e", val, "foo 2.560000e+002", "foo 2.560000e+02");
+ DoDoubleTest("foo %14e", val, "foo 2.560000e+002", "foo 2.560000e+02");
+ DoDoubleTest("foo %-14e", val, "foo 2.560000e+002 ", "foo 2.560000e+02 ");
+ DoDoubleTest("foo %.1e", val, "foo 2.6e+002", "foo 2.6e+02");
+ DoDoubleTest("foo %.8e", val, "foo 2.56000000e+002", "foo 2.56000000e+02");
+ DoDoubleTest("foo %014e", val, "foo 02.560000e+002", "foo 002.560000e+02");
+ DoDoubleTest("foo %#e", val, "foo 2.560000e+002", "foo 2.560000e+02");
+ DoDoubleTest("foo %+e", val, "foo +2.560000e+002", "foo +2.560000e+02");
+ DoDoubleTest("foo % e", val, "foo 2.560000e+002", "foo 2.560000e+02");
+ DoDoubleTest("foo %+e", neg, "foo -2.560000e+002", "foo -2.560000e+02");
+ DoDoubleTest("foo % e", neg, "foo -2.560000e+002", "foo -2.560000e+02");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/vsprintf/test14/testinfo.dat b/src/pal/tests/palsuite/c_runtime/vsprintf/test14/testinfo.dat
new file mode 100644
index 0000000000..a0934096cc
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vsprintf/test14/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = vsprintf
+Name = Positive Test for vsprintf
+TYPE = DEFAULT
+EXE1 = test14
+Description
+= Tests the PAL implementation of the vsprintf function.
+= Tests vsprintf with exponential format doubles (lowercase).
+= This test is modeled after _snprintf.
diff --git a/src/pal/tests/palsuite/c_runtime/vsprintf/test15/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/vsprintf/test15/CMakeLists.txt
new file mode 100644
index 0000000000..6fb1d321b8
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vsprintf/test15/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test15.c
+)
+
+add_executable(paltest_vsprintf_test15
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vsprintf_test15 coreclrpal)
+
+target_link_libraries(paltest_vsprintf_test15
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/vsprintf/test15/test15.c b/src/pal/tests/palsuite/c_runtime/vsprintf/test15/test15.c
new file mode 100644
index 0000000000..a5b4c94226
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vsprintf/test15/test15.c
@@ -0,0 +1,64 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test15.c
+**
+** Purpose: Test #15 for the vsprintf function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+#include "../vsprintf.h"
+
+/*
+ * Notes: memcmp is used, as is strlen.
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ double val = 256.0;
+ double neg = -256.0;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return(FAIL);
+ }
+
+ DoDoubleTest("foo %E", val, "foo 2.560000E+002",
+ "foo 2.560000E+02");
+ DoDoubleTest("foo %lE", val, "foo 2.560000E+002",
+ "foo 2.560000E+02");
+ DoDoubleTest("foo %hE", val, "foo 2.560000E+002",
+ "foo 2.560000E+02");
+ DoDoubleTest("foo %LE", val, "foo 2.560000E+002",
+ "foo 2.560000E+02");
+ DoDoubleTest("foo %I64E", val, "foo 2.560000E+002",
+ "foo 2.560000E+02");
+ DoDoubleTest("foo %14E", val, "foo 2.560000E+002",
+ "foo 2.560000E+02");
+ DoDoubleTest("foo %-14E", val, "foo 2.560000E+002 ",
+ "foo 2.560000E+02 ");
+ DoDoubleTest("foo %.1E", val, "foo 2.6E+002",
+ "foo 2.6E+02");
+ DoDoubleTest("foo %.8E", val, "foo 2.56000000E+002",
+ "foo 2.56000000E+02");
+ DoDoubleTest("foo %014E", val, "foo 02.560000E+002",
+ "foo 002.560000E+02");
+ DoDoubleTest("foo %#E", val, "foo 2.560000E+002",
+ "foo 2.560000E+02");
+ DoDoubleTest("foo %+E", val, "foo +2.560000E+002",
+ "foo +2.560000E+02");
+ DoDoubleTest("foo % E", val, "foo 2.560000E+002",
+ "foo 2.560000E+02");
+ DoDoubleTest("foo %+E", neg, "foo -2.560000E+002",
+ "foo -2.560000E+02");
+ DoDoubleTest("foo % E", neg, "foo -2.560000E+002",
+ "foo -2.560000E+02");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/vsprintf/test15/testinfo.dat b/src/pal/tests/palsuite/c_runtime/vsprintf/test15/testinfo.dat
new file mode 100644
index 0000000000..c3b8ebd292
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vsprintf/test15/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = vsprintf
+Name = Positive Test for vsprintf
+TYPE = DEFAULT
+EXE1 = test15
+Description
+= Tests the PAL implementation of the vsprintf function.
+= Tests vsprintf with exponential format doubles (uppercase).
+= This test is modeled after _snprintf.
diff --git a/src/pal/tests/palsuite/c_runtime/vsprintf/test16/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/vsprintf/test16/CMakeLists.txt
new file mode 100644
index 0000000000..ccc21378fc
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vsprintf/test16/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test16.c
+)
+
+add_executable(paltest_vsprintf_test16
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vsprintf_test16 coreclrpal)
+
+target_link_libraries(paltest_vsprintf_test16
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/vsprintf/test16/test16.c b/src/pal/tests/palsuite/c_runtime/vsprintf/test16/test16.c
new file mode 100644
index 0000000000..a7258db9d6
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vsprintf/test16/test16.c
@@ -0,0 +1,49 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test16.c
+**
+** Purpose: Test #16 for the vsprintf function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+#include "../vsprintf.h"
+
+/*
+ * Notes: memcmp is used, as is strlen.
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ double val = 2560.001;
+ double neg = -2560.001;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return(FAIL);
+ }
+
+ DoDoubleTest("foo %f", val, "foo 2560.001000", "foo 2560.001000");
+ DoDoubleTest("foo %lf", val, "foo 2560.001000", "foo 2560.001000");
+ DoDoubleTest("foo %hf", val, "foo 2560.001000", "foo 2560.001000");
+ DoDoubleTest("foo %Lf", val, "foo 2560.001000", "foo 2560.001000");
+ DoDoubleTest("foo %I64f", val, "foo 2560.001000", "foo 2560.001000");
+ DoDoubleTest("foo %12f", val, "foo 2560.001000", "foo 2560.001000");
+ DoDoubleTest("foo %-12f", val, "foo 2560.001000 ", "foo 2560.001000 ");
+ DoDoubleTest("foo %.1f", val, "foo 2560.0", "foo 2560.0");
+ DoDoubleTest("foo %.8f", val, "foo 2560.00100000", "foo 2560.00100000");
+ DoDoubleTest("foo %012f", val, "foo 02560.001000", "foo 02560.001000");
+ DoDoubleTest("foo %#f", val, "foo 2560.001000", "foo 2560.001000");
+ DoDoubleTest("foo %+f", val, "foo +2560.001000", "foo +2560.001000");
+ DoDoubleTest("foo % f", val, "foo 2560.001000", "foo 2560.001000");
+ DoDoubleTest("foo %+f", neg, "foo -2560.001000", "foo -2560.001000");
+ DoDoubleTest("foo % f", neg, "foo -2560.001000", "foo -2560.001000");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/vsprintf/test16/testinfo.dat b/src/pal/tests/palsuite/c_runtime/vsprintf/test16/testinfo.dat
new file mode 100644
index 0000000000..d29634e3ed
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vsprintf/test16/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = vsprintf
+Name = Positive Test for vsprintf
+TYPE = DEFAULT
+EXE1 = test16
+Description
+= Tests the PAL implementation of the vsprintf function.
+= Tests vsprintf with decimal point format doubles.
+= This test is modeled after _snprintf.
diff --git a/src/pal/tests/palsuite/c_runtime/vsprintf/test17/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/vsprintf/test17/CMakeLists.txt
new file mode 100644
index 0000000000..4c9dcd986f
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vsprintf/test17/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test17.c
+)
+
+add_executable(paltest_vsprintf_test17
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vsprintf_test17 coreclrpal)
+
+target_link_libraries(paltest_vsprintf_test17
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/vsprintf/test17/test17.c b/src/pal/tests/palsuite/c_runtime/vsprintf/test17/test17.c
new file mode 100644
index 0000000000..0ad246a1ae
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vsprintf/test17/test17.c
@@ -0,0 +1,50 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test17.c
+**
+** Purpose: Test #17 for the vsprintf function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+#include "../vsprintf.h"
+
+/*
+ * Notes: memcmp is used, as is strlen.
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ double val = 2560.001;
+ double neg = -2560.001;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return(FAIL);
+ }
+
+ DoDoubleTest("foo %g", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %lg", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %hg", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %Lg", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %I64g", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %5g", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %-5g", val, "foo 2560 ", "foo 2560 ");
+ DoDoubleTest("foo %.1g", val, "foo 3e+003", "foo 3e+03");
+ DoDoubleTest("foo %.2g", val, "foo 2.6e+003", "foo 2.6e+03");
+ DoDoubleTest("foo %.12g", val, "foo 2560.001", "foo 2560.001");
+ DoDoubleTest("foo %06g", val, "foo 002560", "foo 002560");
+ DoDoubleTest("foo %#g", val, "foo 2560.00", "foo 2560.00");
+ DoDoubleTest("foo %+g", val, "foo +2560", "foo +2560");
+ DoDoubleTest("foo % g", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %+g", neg, "foo -2560", "foo -2560");
+ DoDoubleTest("foo % g", neg, "foo -2560", "foo -2560");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/vsprintf/test17/testinfo.dat b/src/pal/tests/palsuite/c_runtime/vsprintf/test17/testinfo.dat
new file mode 100644
index 0000000000..0dcd3c869e
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vsprintf/test17/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = vsprintf
+Name = Positive Test for vsprintf
+TYPE = DEFAULT
+EXE1 = test17
+Description
+= Tests the PAL implementation of the vsprintf function.
+= Tests vsprintf with compact format doubles (lowercase).
+= This test is modeled after _snprintf.
diff --git a/src/pal/tests/palsuite/c_runtime/vsprintf/test18/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/vsprintf/test18/CMakeLists.txt
new file mode 100644
index 0000000000..2e8610d4a5
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vsprintf/test18/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test18.c
+)
+
+add_executable(paltest_vsprintf_test18
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vsprintf_test18 coreclrpal)
+
+target_link_libraries(paltest_vsprintf_test18
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/vsprintf/test18/test18.c b/src/pal/tests/palsuite/c_runtime/vsprintf/test18/test18.c
new file mode 100644
index 0000000000..9a45305562
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vsprintf/test18/test18.c
@@ -0,0 +1,50 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test18.c
+**
+** Purpose: Test #18 for the vsprintf function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+#include "../vsprintf.h"
+
+/*
+ * Notes: memcmp is used, as is strlen.
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ double val = 2560.001;
+ double neg = -2560.001;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return(FAIL);
+ }
+
+ DoDoubleTest("foo %G", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %lG", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %hG", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %LG", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %I64G", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %5G", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %-5G", val, "foo 2560 ", "foo 2560 ");
+ DoDoubleTest("foo %.1G", val, "foo 3E+003", "foo 3E+03");
+ DoDoubleTest("foo %.2G", val, "foo 2.6E+003", "foo 2.6E+03");
+ DoDoubleTest("foo %.12G", val, "foo 2560.001", "foo 2560.001");
+ DoDoubleTest("foo %06G", val, "foo 002560", "foo 002560");
+ DoDoubleTest("foo %#G", val, "foo 2560.00", "foo 2560.00");
+ DoDoubleTest("foo %+G", val, "foo +2560", "foo +2560");
+ DoDoubleTest("foo % G", val, "foo 2560", "foo 2560");
+ DoDoubleTest("foo %+G", neg, "foo -2560", "foo -2560");
+ DoDoubleTest("foo % G", neg, "foo -2560", "foo -2560");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/vsprintf/test18/testinfo.dat b/src/pal/tests/palsuite/c_runtime/vsprintf/test18/testinfo.dat
new file mode 100644
index 0000000000..43299968c3
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vsprintf/test18/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = vsprintf
+Name = Positive Test for vsprintf
+TYPE = DEFAULT
+EXE1 = test18
+Description
+= Tests the PAL implementation of the vsprintf function.
+= Tests vsprintf with compact format doubles (uppercase).
+= This test is modeled after _snprintf.
diff --git a/src/pal/tests/palsuite/c_runtime/vsprintf/test19/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/vsprintf/test19/CMakeLists.txt
new file mode 100644
index 0000000000..92e39ab597
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vsprintf/test19/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test19.c
+)
+
+add_executable(paltest_vsprintf_test19
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vsprintf_test19 coreclrpal)
+
+target_link_libraries(paltest_vsprintf_test19
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/vsprintf/test19/test19.c b/src/pal/tests/palsuite/c_runtime/vsprintf/test19/test19.c
new file mode 100644
index 0000000000..18590ed51b
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vsprintf/test19/test19.c
@@ -0,0 +1,67 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test19.c
+**
+** Purpose: Test #19 for the vsprintf function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+#include "../vsprintf.h"
+
+/*
+ * Notes: memcmp is used, as is strlen.
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return(FAIL);
+ }
+
+
+ DoArgumentPrecTest("%.*s", 2, "bar", "bar", "ba", "ba");
+ DoArgumentPrecTest("%.*S", 2, convert("bar"), "bar", "ba", "ba");
+ DoArgumentPrecTest("%.*c", 0, (void*)'a', "a", "a", "a");
+ DoArgumentPrecTest("%.*c", 4, (void*)'a', "a", "a", "a");
+ DoArgumentPrecTest("%.*C", 0, (void*)'a', "a", "a", "a");
+ DoArgumentPrecTest("%.*C", 4, (void*)'a', "a", "a", "a");
+ DoArgumentPrecTest("%.*d", 1, (void*)42, "42", "42", "42");
+ DoArgumentPrecTest("%.*d", 3, (void*)42, "42", "042", "042");
+ DoArgumentPrecTest("%.*i", 1, (void*)42, "42", "42", "42");
+ DoArgumentPrecTest("%.*i", 3, (void*)42, "42", "042", "042");
+ DoArgumentPrecTest("%.*o", 1, (void*)42, "42", "52", "52");
+ DoArgumentPrecTest("%.*o", 3, (void*)42, "42", "052", "052");
+ DoArgumentPrecTest("%.*u", 1, (void*)42, "42", "42", "42");
+ DoArgumentPrecTest("%.*u", 3, (void*)42, "42", "042", "042");
+ DoArgumentPrecTest("%.*x", 1, (void*)0x42, "0x42", "42", "42");
+ DoArgumentPrecTest("%.*x", 3, (void*)0x42, "0x42", "042", "042");
+ DoArgumentPrecTest("%.*X", 1, (void*)0x42, "0x42", "42", "42");
+ DoArgumentPrecTest("%.*X", 3, (void*)0x42, "0x42", "042", "042");
+
+
+ DoArgumentPrecDoubleTest("%.*e", 1, 2.01, "2.0e+000", "2.0e+00");
+ DoArgumentPrecDoubleTest("%.*e", 3, 2.01, "2.010e+000", "2.010e+00");
+ DoArgumentPrecDoubleTest("%.*E", 1, 2.01, "2.0E+000", "2.0E+00");
+ DoArgumentPrecDoubleTest("%.*E", 3, 2.01, "2.010E+000", "2.010E+00");
+ DoArgumentPrecDoubleTest("%.*f", 1, 2.01, "2.0", "2.0");
+ DoArgumentPrecDoubleTest("%.*f", 3, 2.01, "2.010", "2.010");
+ DoArgumentPrecDoubleTest("%.*g", 1, 256.01, "3e+002", "3e+02");
+ DoArgumentPrecDoubleTest("%.*g", 3, 256.01, "256", "256");
+ DoArgumentPrecDoubleTest("%.*g", 4, 256.01, "256", "256");
+ DoArgumentPrecDoubleTest("%.*g", 6, 256.01, "256.01", "256.01");
+ DoArgumentPrecDoubleTest("%.*G", 1, 256.01, "3E+002", "3E+02");
+ DoArgumentPrecDoubleTest("%.*G", 3, 256.01, "256", "256");
+ DoArgumentPrecDoubleTest("%.*G", 4, 256.01, "256", "256");
+ DoArgumentPrecDoubleTest("%.*G", 6, 256.01, "256.01", "256.01");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/vsprintf/test19/testinfo.dat b/src/pal/tests/palsuite/c_runtime/vsprintf/test19/testinfo.dat
new file mode 100644
index 0000000000..1e7bc7615e
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vsprintf/test19/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = vsprintf
+Name = Positive Test for vsprintf
+TYPE = DEFAULT
+EXE1 = test19
+Description
+= Tests the PAL implementation of the vsprintf function.
+= Tests vsprintf with argument specified precision.
+= This test is modeled after _snprintf.
diff --git a/src/pal/tests/palsuite/c_runtime/vsprintf/test2/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/vsprintf/test2/CMakeLists.txt
new file mode 100644
index 0000000000..2308bc2573
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vsprintf/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test2.c
+)
+
+add_executable(paltest_vsprintf_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vsprintf_test2 coreclrpal)
+
+target_link_libraries(paltest_vsprintf_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/vsprintf/test2/test2.c b/src/pal/tests/palsuite/c_runtime/vsprintf/test2/test2.c
new file mode 100644
index 0000000000..fbd4b41068
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vsprintf/test2/test2.c
@@ -0,0 +1,42 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test2.c
+**
+** Purpose: Test #2 for the vsprintf function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+#include "../vsprintf.h"
+/*
+ * Notes: memcmp is used, as is strlen.
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return(FAIL);
+ }
+
+ DoStrTest("foo %s", "bar", "foo bar");
+ DoStrTest("foo %hs", "bar", "foo bar");
+ DoWStrTest("foo %ls", convert("bar"), "foo bar");
+ DoWStrTest("foo %ws", convert("bar"), "foo bar");
+ DoStrTest("foo %Ls", "bar", "foo bar");
+ DoStrTest("foo %I64s", "bar", "foo bar");
+ DoStrTest("foo %5s", "bar", "foo bar");
+ DoStrTest("foo %.2s", "bar", "foo ba");
+ DoStrTest("foo %5.2s", "bar", "foo ba");
+ DoStrTest("foo %-5s", "bar", "foo bar ");
+ DoStrTest("foo %05s", "bar", "foo 00bar");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/vsprintf/test2/testinfo.dat b/src/pal/tests/palsuite/c_runtime/vsprintf/test2/testinfo.dat
new file mode 100644
index 0000000000..7958c1ad97
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vsprintf/test2/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = vsprintf
+Name = Positive Test for vsprintf
+TYPE = DEFAULT
+EXE1 = test2
+Description
+= Tests the PAL implementation of the vsprintf function.
+= Tests vsprintf with strings.
+= This test is modeled after _snprintf.
diff --git a/src/pal/tests/palsuite/c_runtime/vsprintf/test3/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/vsprintf/test3/CMakeLists.txt
new file mode 100644
index 0000000000..aef24171fc
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vsprintf/test3/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test3.c
+)
+
+add_executable(paltest_vsprintf_test3
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vsprintf_test3 coreclrpal)
+
+target_link_libraries(paltest_vsprintf_test3
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/vsprintf/test3/test3.c b/src/pal/tests/palsuite/c_runtime/vsprintf/test3/test3.c
new file mode 100644
index 0000000000..742370ebe9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vsprintf/test3/test3.c
@@ -0,0 +1,43 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test3.c
+**
+** Purpose: Test #3 for the vsprintf function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+#include "../vsprintf.h"
+
+/*
+ * Notes: memcmp is used, as is strlen.
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return(FAIL);
+ }
+
+ DoWStrTest("foo %S", convert("bar"), "foo bar");
+ DoStrTest("foo %hS", "bar", "foo bar");
+ DoWStrTest("foo %lS", convert("bar"), "foo bar");
+ DoWStrTest("foo %wS", convert("bar"), "foo bar");
+ DoWStrTest("foo %LS", convert("bar"), "foo bar");
+ DoWStrTest("foo %I64S", convert("bar"), "foo bar");
+ DoWStrTest("foo %5S", convert("bar"), "foo bar");
+ DoWStrTest("foo %.2S", convert("bar"), "foo ba");
+ DoWStrTest("foo %5.2S", convert("bar"), "foo ba");
+ DoWStrTest("foo %-5S", convert("bar"), "foo bar ");
+ DoWStrTest("foo %05S", convert("bar"), "foo 00bar");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/vsprintf/test3/testinfo.dat b/src/pal/tests/palsuite/c_runtime/vsprintf/test3/testinfo.dat
new file mode 100644
index 0000000000..afeb7da953
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vsprintf/test3/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = vsprintf
+Name = Positive Test for vsprintf
+TYPE = DEFAULT
+EXE1 = test3
+Description
+= Tests the PAL implementation of the vsprintf function.
+= Tests vsprintf with wide strings.
+= This test is modeled after _snprintf.
diff --git a/src/pal/tests/palsuite/c_runtime/vsprintf/test4/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/vsprintf/test4/CMakeLists.txt
new file mode 100644
index 0000000000..9570255475
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vsprintf/test4/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test4.c
+)
+
+add_executable(paltest_vsprintf_test4
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vsprintf_test4 coreclrpal)
+
+target_link_libraries(paltest_vsprintf_test4
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/vsprintf/test4/test4.c b/src/pal/tests/palsuite/c_runtime/vsprintf/test4/test4.c
new file mode 100644
index 0000000000..dc43a9e2c7
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vsprintf/test4/test4.c
@@ -0,0 +1,72 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test4.c
+**
+** Purpose: Test #4 for the vsprintf function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+#include "../vsprintf.h"
+
+/*
+ * Notes: memcmp is used, as is strlen.
+ */
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ void *ptr = (void*) 0x123456;
+ INT64 lptr = I64(0x1234567887654321);
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return(FAIL);
+ }
+/*
+** Run only on 64 bit platforms
+*/
+#if defined(BIT64) && defined(PLATFORM_UNIX)
+ Trace("Testing for 64 Bit Platforms \n");
+ DoPointerTest("%p", NULL, "NULL", "0000000000000000");
+ DoPointerTest("%p", ptr, "pointer to 0x123456", "0000000000123456");
+ DoPointerTest("%17p", ptr, "pointer to 0x123456", " 0000000000123456");
+ DoPointerTest("%17p", ptr, "pointer to 0x123456", " 0000000000123456");
+ DoPointerTest("%-17p", ptr, "pointer to 0x123456", "0000000000123456 ");
+ DoPointerTest("%+p", ptr, "pointer to 0x123456", "0000000000123456");
+ DoPointerTest("%#p", ptr, "pointer to 0x123456", "0X0000000000123456");
+ DoPointerTest("%lp", ptr, "pointer to 0x123456", "00123456");
+ DoPointerTest("%hp", ptr, "pointer to 0x123456", "00003456");
+ DoPointerTest("%Lp", ptr, "pointer to 0x123456", "00123456");
+ DoI64DoubleTest("%I64p", lptr, "pointer to 0x1234567887654321",
+ "1234567887654321");
+#else
+ Trace("Testing for Non 64 Bit Platforms \n");
+ DoPointerTest("%p", NULL, "NULL", "00000000");
+ DoPointerTest("%p", ptr, "pointer to 0x123456", "00123456");
+ DoPointerTest("%9p", ptr, "pointer to 0x123456", " 00123456");
+ DoPointerTest("%09p", ptr, "pointer to 0x123456", " 00123456");
+ DoPointerTest("%-9p", ptr, "pointer to 0x123456", "00123456 ");
+ DoPointerTest("%+p", ptr, "pointer to 0x123456", "00123456");
+ DoPointerTest("%#p", ptr, "pointer to 0x123456", "0X00123456");
+ DoPointerTest("%lp", ptr, "pointer to 0x123456", "00123456");
+ DoPointerTest("%hp", ptr, "pointer to 0x123456", "00003456");
+ DoPointerTest("%Lp", ptr, "pointer to 0x123456", "00123456");
+ DoI64DoubleTest("%I64p", lptr, "pointer to 0x1234567887654321",
+ "1234567887654321");
+#endif
+
+
+
+
+
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/vsprintf/test4/testinfo.dat b/src/pal/tests/palsuite/c_runtime/vsprintf/test4/testinfo.dat
new file mode 100644
index 0000000000..7331c20375
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vsprintf/test4/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = vsprintf
+Name = Positive Test for vsprintf
+TYPE = DEFAULT
+EXE1 = test4
+Description
+= Tests the PAL implementation of the vsprintf function.
+= Tests vsprintf with pointers.
+= This test is modeled after _snprintf.
diff --git a/src/pal/tests/palsuite/c_runtime/vsprintf/test5/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/vsprintf/test5/CMakeLists.txt
new file mode 100644
index 0000000000..34a3e6243f
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vsprintf/test5/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test5.c
+)
+
+add_executable(paltest_vsprintf_test5
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vsprintf_test5 coreclrpal)
+
+target_link_libraries(paltest_vsprintf_test5
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/vsprintf/test5/test5.c b/src/pal/tests/palsuite/c_runtime/vsprintf/test5/test5.c
new file mode 100644
index 0000000000..e630d8863b
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vsprintf/test5/test5.c
@@ -0,0 +1,43 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test5.c
+**
+** Purpose: Test #5 for the vsprintf function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+#include "../vsprintf.h"
+
+/*
+ * Notes: memcmp is used, as is strlen.
+ */
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return(FAIL);
+ }
+
+ DoTest("foo %n bar", 4, "foo bar");
+ DoTest("foo %#n bar", 4, "foo bar");
+ DoTest("foo % n bar", 4, "foo bar");
+ DoTest("foo %+n bar", 4, "foo bar");
+ DoTest("foo %-n bar", 4, "foo bar");
+ DoTest("foo %0n bar", 4, "foo bar");
+ DoShortTest("foo %hn bar", 4, "foo bar");
+ DoTest("foo %ln bar", 4, "foo bar");
+ DoTest("foo %Ln bar", 4, "foo bar");
+ DoTest("foo %I64n bar", 4, "foo bar");
+ DoTest("foo %20.3n bar", 4, "foo bar");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/vsprintf/test5/testinfo.dat b/src/pal/tests/palsuite/c_runtime/vsprintf/test5/testinfo.dat
new file mode 100644
index 0000000000..81748f88b9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vsprintf/test5/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = vsprintf
+Name = Positive Test for vsprintf
+TYPE = DEFAULT
+EXE1 = test5
+Description
+= Tests the PAL implementation of the vsprintf function.
+= Tests vsprintf with the count specifier.
+= This test is modeled after _snprintf.
diff --git a/src/pal/tests/palsuite/c_runtime/vsprintf/test6/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/vsprintf/test6/CMakeLists.txt
new file mode 100644
index 0000000000..dccca0b2b7
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vsprintf/test6/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test6.c
+)
+
+add_executable(paltest_vsprintf_test6
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vsprintf_test6 coreclrpal)
+
+target_link_libraries(paltest_vsprintf_test6
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/vsprintf/test6/test6.c b/src/pal/tests/palsuite/c_runtime/vsprintf/test6/test6.c
new file mode 100644
index 0000000000..0d38a3a114
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vsprintf/test6/test6.c
@@ -0,0 +1,44 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test6.c
+**
+** Purpose: Test #6 for the vsprintf function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+#include "../vsprintf.h"
+
+/*
+ * Notes: memcmp is used, as is strlen.
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ WCHAR wc = (WCHAR) 'c';
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return(FAIL);
+ }
+
+ DoCharTest("foo %c", 'b', "foo b");
+ DoCharTest("foo %hc", 'b', "foo b");
+ DoWCharTest("foo %lc", wc, "foo c");
+ DoCharTest("foo %Lc", 'b', "foo b");
+ DoCharTest("foo %I64c", 'b', "foo b");
+ DoCharTest("foo %5c", 'b', "foo b");
+ DoCharTest("foo %.0c", 'b', "foo b");
+ DoCharTest("foo %-5c", 'b', "foo b ");
+ DoCharTest("foo %05c", 'b', "foo 0000b");
+ DoCharTest("foo % c", 'b', "foo b");
+ DoCharTest("foo %#c", 'b', "foo b");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/vsprintf/test6/testinfo.dat b/src/pal/tests/palsuite/c_runtime/vsprintf/test6/testinfo.dat
new file mode 100644
index 0000000000..d76c5bf1a8
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vsprintf/test6/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = vsprintf
+Name = Positive Test for vsprintf
+TYPE = DEFAULT
+EXE1 = test6
+Description
+= Tests the PAL implementation of the vsprintf function.
+= Tests vsprintf with characters.
+= This test is modeled after _snprintf.
diff --git a/src/pal/tests/palsuite/c_runtime/vsprintf/test7/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/vsprintf/test7/CMakeLists.txt
new file mode 100644
index 0000000000..7f18de056e
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vsprintf/test7/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test7.c
+)
+
+add_executable(paltest_vsprintf_test7
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vsprintf_test7 coreclrpal)
+
+target_link_libraries(paltest_vsprintf_test7
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/vsprintf/test7/test7.c b/src/pal/tests/palsuite/c_runtime/vsprintf/test7/test7.c
new file mode 100644
index 0000000000..c9f87d4343
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vsprintf/test7/test7.c
@@ -0,0 +1,44 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test7.c
+**
+** Purpose: Test #7 for the vsprintf function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+#include "../vsprintf.h"
+/*
+ * Notes: memcmp is used, as is strlen.
+ */
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ WCHAR wb = (WCHAR) 'b';
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return(FAIL);
+ }
+
+ DoWCharTest("foo %c", wb, "foo b");
+ DoWCharTest("foo %hc", wb, "foo b");
+ DoCharTest("foo %lc", 'c', "foo c");
+ DoWCharTest("foo %Lc", wb, "foo b");
+ DoWCharTest("foo %I64c", wb, "foo b");
+ DoWCharTest("foo %5c", wb, "foo b");
+ DoWCharTest("foo %.0c", wb, "foo b");
+ DoWCharTest("foo %-5c", wb, "foo b ");
+ DoWCharTest("foo %05c", wb, "foo 0000b");
+ DoWCharTest("foo % c", wb, "foo b");
+ DoWCharTest("foo %#c", wb, "foo b");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/vsprintf/test7/testinfo.dat b/src/pal/tests/palsuite/c_runtime/vsprintf/test7/testinfo.dat
new file mode 100644
index 0000000000..facf60d6aa
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vsprintf/test7/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = vsprintf
+Name = Positive Test for vsprintf
+TYPE = DEFAULT
+EXE1 = test7
+Description
+= Tests the PAL implementation of the vsprintf function.
+= Tests vsprintf with wide characters.
+= This test is modeled after _snprintf.
diff --git a/src/pal/tests/palsuite/c_runtime/vsprintf/test8/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/vsprintf/test8/CMakeLists.txt
new file mode 100644
index 0000000000..34c92e1045
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vsprintf/test8/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test8.c
+)
+
+add_executable(paltest_vsprintf_test8
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vsprintf_test8 coreclrpal)
+
+target_link_libraries(paltest_vsprintf_test8
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/vsprintf/test8/test8.c b/src/pal/tests/palsuite/c_runtime/vsprintf/test8/test8.c
new file mode 100644
index 0000000000..e741d1da8b
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vsprintf/test8/test8.c
@@ -0,0 +1,52 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test8.c
+**
+** Purpose: Test #8 for the vsprintf function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+#include "../vsprintf.h"
+
+/*
+ * Notes: memcmp is used, as is strlen.
+ */
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ int neg = -42;
+ int pos = 42;
+ INT64 l = 42;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return(FAIL);
+ }
+
+ DoNumTest("foo %d", pos, "foo 42");
+ DoNumTest("foo %ld", 0xFFFF, "foo 65535");
+ DoNumTest("foo %hd", 0xFFFF, "foo -1");
+ DoNumTest("foo %Ld", pos, "foo 42");
+ DoI64Test("foo %I64d", l, "42", "foo 42");
+ DoNumTest("foo %3d", pos, "foo 42");
+ DoNumTest("foo %-3d", pos, "foo 42 ");
+ DoNumTest("foo %.1d", pos, "foo 42");
+ DoNumTest("foo %.3d", pos, "foo 042");
+ DoNumTest("foo %03d", pos, "foo 042");
+ DoNumTest("foo %#d", pos, "foo 42");
+ DoNumTest("foo %+d", pos, "foo +42");
+ DoNumTest("foo % d", pos, "foo 42");
+ DoNumTest("foo %+d", neg, "foo -42");
+ DoNumTest("foo % d", neg, "foo -42");
+
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/vsprintf/test8/testinfo.dat b/src/pal/tests/palsuite/c_runtime/vsprintf/test8/testinfo.dat
new file mode 100644
index 0000000000..05f84f4999
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vsprintf/test8/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = vsprintf
+Name = Positive Test for vsprintf
+TYPE = DEFAULT
+EXE1 = test8
+Description
+= Tests the PAL implementation of the vsprintf function.
+= Tests vsprintf with decimal numbers.
+= This test is modeled after _snprintf.
diff --git a/src/pal/tests/palsuite/c_runtime/vsprintf/test9/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/vsprintf/test9/CMakeLists.txt
new file mode 100644
index 0000000000..1fe177de95
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vsprintf/test9/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test9.c
+)
+
+add_executable(paltest_vsprintf_test9
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vsprintf_test9 coreclrpal)
+
+target_link_libraries(paltest_vsprintf_test9
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/vsprintf/test9/test9.c b/src/pal/tests/palsuite/c_runtime/vsprintf/test9/test9.c
new file mode 100644
index 0000000000..e1f7c84195
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vsprintf/test9/test9.c
@@ -0,0 +1,51 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test9.c
+**
+** Purpose: Test #9 for the vsprintf function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+#include "../vsprintf.h"
+
+/*
+ * Notes: memcmp is used, as is strlen.
+ */
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ int neg = -42;
+ int pos = 42;
+ INT64 l = 42;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return(FAIL);
+ }
+
+ DoNumTest("foo %i", pos, "foo 42");
+ DoNumTest("foo %li", 0xFFFF, "foo 65535");
+ DoNumTest("foo %hi", 0xFFFF, "foo -1");
+ DoNumTest("foo %Li", pos, "foo 42");
+ DoI64Test("foo %I64i", l, "42", "foo 42");
+ DoNumTest("foo %3i", pos, "foo 42");
+ DoNumTest("foo %-3i", pos, "foo 42 ");
+ DoNumTest("foo %.1i", pos, "foo 42");
+ DoNumTest("foo %.3i", pos, "foo 042");
+ DoNumTest("foo %03i", pos, "foo 042");
+ DoNumTest("foo %#i", pos, "foo 42");
+ DoNumTest("foo %+i", pos, "foo +42");
+ DoNumTest("foo % i", pos, "foo 42");
+ DoNumTest("foo %+i", neg, "foo -42");
+ DoNumTest("foo % i", neg, "foo -42");
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/vsprintf/test9/testinfo.dat b/src/pal/tests/palsuite/c_runtime/vsprintf/test9/testinfo.dat
new file mode 100644
index 0000000000..3bc0057c96
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vsprintf/test9/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = vsprintf
+Name = Positive Test for vsprintf
+TYPE = DEFAULT
+EXE1 = test9
+Description
+= Tests the PAL implementation of the vsprintf function.
+= Tests vsprintf with integer numbers.
+= This test is modeled after _snprintf.
diff --git a/src/pal/tests/palsuite/c_runtime/vsprintf/vsprintf.h b/src/pal/tests/palsuite/c_runtime/vsprintf/vsprintf.h
new file mode 100644
index 0000000000..10648d896f
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vsprintf/vsprintf.h
@@ -0,0 +1,218 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: vsprintf.h
+**
+** Purpose: Helper functions for the vsprintf tests.
+**
+**
+**===================================================================*/
+#ifndef __VSPRINTF_H__
+#define __VSPRINTF_H__
+
+/* These functions leaks memory like crazy. C'est la vie. */
+int testvsp(char* buf, const char* format, ...)
+{
+ int retVal;
+ va_list arglist;
+
+ va_start(arglist, format);
+ retVal = vsprintf(buf, format, arglist);
+ va_end(arglist);
+
+ return (retVal);
+}
+
+void DoStrTest(char *formatstr, char* param, char *checkstr)
+{
+ char buf[256] = { 0 };
+
+ testvsp(buf, formatstr, param);
+ if (memcmp(buf, checkstr, strlen(buf) + 1) != 0)
+ {
+ Fail("ERROR: failed to insert string \"%s\" into \"%s\"\n"
+ "Expected \"%s\" got \"%s\".\n",
+ param, formatstr, checkstr, buf);
+ }
+}
+
+void DoWStrTest(char *formatstr, WCHAR* param, char *checkstr)
+{
+ char buf[256] = { 0 };
+
+ testvsp(buf, formatstr, param);
+ if (memcmp(buf, checkstr, strlen(buf) + 1) != 0)
+ {
+ Fail("ERROR: failed to insert wide string \"%s\" into \"%s\"\n"
+ "Expected \"%s\" got \"%s\".\n",
+ convertC(param), formatstr, checkstr, buf);
+ }
+}
+
+
+void DoCharTest(char *formatstr, char param, char *checkstr)
+{
+ char buf[256] = { 0 };
+
+ testvsp(buf, formatstr, param);
+ if (memcmp(buf, checkstr, strlen(buf) + 1) != 0)
+ {
+ Fail("ERROR: failed to insert char \'%c\' (%d) into \"%s\"\n"
+ "Expected \"%s\" got \"%s\".\n",
+ param, param, formatstr, checkstr, buf);
+ }
+}
+
+void DoWCharTest(char *formatstr, WCHAR param, char *checkstr)
+{
+ char buf[256] = { 0 };
+
+ testvsp(buf, formatstr, param);
+ if (memcmp(buf, checkstr, strlen(buf) + 1) != 0)
+ {
+ Fail("ERROR: failed to insert wide char \'%c\' (%d) into \"%s\"\n"
+ "Expected \"%s\" got \"%s\".\n",
+ (char)param, param, formatstr, checkstr, buf);
+ }
+}
+
+void DoNumTest(char *formatstr, int value, char *checkstr)
+{
+ char buf[256] = { 0 };
+
+ testvsp(buf, formatstr, value);
+ if (memcmp(buf, checkstr, strlen(buf) + 1) != 0)
+ {
+ Fail("ERROR: failed to insert %#x into \"%s\"\n"
+ "Expected \"%s\" got \"%s\".\n",
+ value, formatstr, checkstr, buf);
+ }
+}
+
+void DoI64Test(char *formatstr, INT64 value, char *valuestr, char *checkstr)
+{
+ char buf[256] = { 0 };
+
+ testvsp(buf, formatstr, value);
+ if (memcmp(buf, checkstr, strlen(buf) + 1) != 0)
+ {
+ Fail("ERROR: failed to insert %s into \"%s\"\n"
+ "Expected \"%s\" got \"%s\".\n",
+ valuestr, formatstr, checkstr, buf);
+ }
+}
+void DoDoubleTest(char *formatstr, double value, char *checkstr1, char
+*checkstr2)
+{
+ char buf[256] = { 0 };
+
+ testvsp(buf, formatstr, value);
+ if (memcmp(buf, checkstr1, strlen(checkstr1) + 1) != 0 &&
+ memcmp(buf, checkstr2, strlen(checkstr2) + 1) != 0)
+ {
+ Fail("ERROR: failed to insert %f into \"%s\"\n"
+ "Expected \"%s\" or \"%s\", got \"%s\".\n",
+ value, formatstr, checkstr1, checkstr2, buf);
+ }
+}
+/*FROM TEST 9*/
+void DoArgumentPrecTest(char *formatstr, int precision, void *param,
+ char *paramstr, char *checkstr1, char *checkstr2)
+{
+ char buf[256];
+
+ testvsp(buf, formatstr, precision, param);
+ if (memcmp(buf, checkstr1, strlen(checkstr1) + 1) != 0 &&
+ memcmp(buf, checkstr2, strlen(checkstr2) + 1) != 0)
+ {
+ Fail("ERROR: failed to insert %s into \"%s\" with precision %d\n"
+ "Expected \"%s\" or \"%s\", got \"%s\".\n", paramstr, formatstr,
+ precision, checkstr1, checkstr2, buf);
+ }
+
+}
+
+void DoArgumentPrecDoubleTest(char *formatstr, int precision, double param,
+ char *checkstr1, char *checkstr2)
+{
+ char buf[256];
+
+ testvsp(buf, formatstr, precision, param);
+ if (memcmp(buf, checkstr1, strlen(checkstr1) + 1) != 0 &&
+ memcmp(buf, checkstr2, strlen(checkstr2) + 1) != 0)
+ {
+ Fail("ERROR: failed to insert %f into \"%s\" with precision %d\n"
+ "Expected \"%s\" or \"%s\", got \"%s\".\n", param, formatstr,
+ precision, checkstr1, checkstr2, buf);
+ }
+}
+/*FROM TEST4*/
+void DoPointerTest(char *formatstr, void* param, char* paramstr,
+ char *checkstr1)
+{
+ char buf[256] = { 0 };
+
+ testvsp(buf, formatstr, param);
+ if (memcmp(buf, checkstr1, strlen(checkstr1) + 1))
+ {
+ Fail("ERROR: failed to insert %s into \"%s\"\n"
+ "Expected \"%s\" got \"%s\".\n",
+ paramstr, formatstr, checkstr1, buf);
+ }
+}
+
+void DoI64DoubleTest(char *formatstr, INT64 value, char *valuestr,
+ char *checkstr1)
+{
+ char buf[256] = { 0 };
+
+ testvsp(buf, formatstr, value);
+ if (memcmp(buf, checkstr1, strlen(checkstr1) + 1) != 0)
+ {
+ Fail("ERROR: failed to insert %s into \"%s\"\n"
+ "Expected \"%s\", got \"%s\".\n",
+ valuestr, formatstr, checkstr1, buf);
+ }
+}
+
+void DoTest(char *formatstr, int param, char *checkstr)
+{
+ char buf[256] = { 0 };
+ int n = -1;
+
+ testvsp(buf, formatstr, &n);
+
+ if (n != param)
+ {
+ Fail("ERROR: Expected count parameter to resolve to %d, got %X\n",
+ param, n);
+ }
+ if (memcmp(buf, checkstr, strlen(buf) + 1) != 0)
+ {
+ Fail("ERROR: Expected \"%s\" got \"%s\".\n", checkstr, buf);
+ }
+}
+
+void DoShortTest(char *formatstr, int param, char *checkstr)
+{
+ char buf[256] = { 0 };
+ short int n = -1;
+
+ testvsp(buf, formatstr, &n);
+
+ if (n != param)
+ {
+ Fail("ERROR: Expected count parameter to resolve to %d, got %X\n",
+ param, n);
+ }
+ if (memcmp(buf, checkstr, strlen(buf) + 1) != 0)
+ {
+ Fail("ERROR: Expected \"%s\" got \"%s\".\n", checkstr, buf);
+ }
+}
+
+#endif
+
diff --git a/src/pal/tests/palsuite/c_runtime/vswprintf/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/vswprintf/CMakeLists.txt
new file mode 100644
index 0000000000..cafb9536b0
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vswprintf/CMakeLists.txt
@@ -0,0 +1,22 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test10)
+add_subdirectory(test11)
+add_subdirectory(test12)
+add_subdirectory(test13)
+add_subdirectory(test14)
+add_subdirectory(test15)
+add_subdirectory(test16)
+add_subdirectory(test17)
+add_subdirectory(test18)
+add_subdirectory(test19)
+add_subdirectory(test2)
+add_subdirectory(test3)
+add_subdirectory(test4)
+add_subdirectory(test5)
+add_subdirectory(test6)
+add_subdirectory(test7)
+add_subdirectory(test8)
+add_subdirectory(test9)
+
diff --git a/src/pal/tests/palsuite/c_runtime/vswprintf/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/vswprintf/test1/CMakeLists.txt
new file mode 100644
index 0000000000..97fbeb4e28
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vswprintf/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_vswprintf_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vswprintf_test1 coreclrpal)
+
+target_link_libraries(paltest_vswprintf_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/vswprintf/test1/test1.c b/src/pal/tests/palsuite/c_runtime/vswprintf/test1/test1.c
new file mode 100644
index 0000000000..d386ce104f
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vswprintf/test1/test1.c
@@ -0,0 +1,41 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test1.c
+**
+** Purpose: Test #1 for the vswprintf function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+#include "../vswprintf.h"
+
+/* memcmp is used to verify the results, so this test is dependent on it. */
+/* ditto with wcslen */
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ WCHAR *checkstr = NULL;
+ WCHAR buf[256] = { 0 };
+
+ if (PAL_Initialize(argc, argv) != 0)
+ return(FAIL);
+
+ checkstr = convert("hello world");
+ testvswp(buf, checkstr);
+
+ if (memcmp(checkstr, buf, wcslen(checkstr)*2+2) != 0)
+ {
+ Fail("ERROR: Expected \"%s\", got \"%s\"\n",
+ convertC(checkstr), convertC(buf));
+ }
+
+ free(checkstr);
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/vswprintf/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/vswprintf/test1/testinfo.dat
new file mode 100644
index 0000000000..6161190d4c
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vswprintf/test1/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = vswprintf
+Name = Positive Test for vswprintf
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Tests the PAL implementation of the vswprintf function.
+= General test to see if vswprintf works correctly.
+= This test is modeled after _snwprintf.
diff --git a/src/pal/tests/palsuite/c_runtime/vswprintf/test10/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/vswprintf/test10/CMakeLists.txt
new file mode 100644
index 0000000000..06c11f68ca
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vswprintf/test10/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test10.c
+)
+
+add_executable(paltest_vswprintf_test10
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vswprintf_test10 coreclrpal)
+
+target_link_libraries(paltest_vswprintf_test10
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/vswprintf/test10/test10.c b/src/pal/tests/palsuite/c_runtime/vswprintf/test10/test10.c
new file mode 100644
index 0000000000..7f316e28f6
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vswprintf/test10/test10.c
@@ -0,0 +1,48 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test10.c
+**
+** Purpose: Test #10 for the vswprintf function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+#include "../vswprintf.h"
+
+/* memcmp is used to verify the results, so this test is dependent on it. */
+/* ditto with wcslen */
+
+int __cdecl main(int argc, char *argv[])
+{
+ int neg = -42;
+ int pos = 42;
+ INT64 l = 42;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ return(FAIL);
+
+ DoNumTest(convert("foo %o"), pos, convert("foo 52"));
+ DoNumTest(convert("foo %lo"), 0xFFFF, convert("foo 177777"));
+ DoNumTest(convert("foo %ho"), 0xFFFF, convert("foo 177777"));
+ DoNumTest(convert("foo %Lo"), pos, convert("foo 52"));
+ DoI64NumTest(convert("foo %I64o"), l, "42", convert("foo 52"));
+ DoNumTest(convert("foo %3o"), pos, convert("foo 52"));
+ DoNumTest(convert("foo %-3o"), pos, convert("foo 52 "));
+ DoNumTest(convert("foo %.1o"), pos, convert("foo 52"));
+ DoNumTest(convert("foo %.3o"), pos, convert("foo 052"));
+ DoNumTest(convert("foo %03o"), pos, convert("foo 052"));
+ DoNumTest(convert("foo %#o"), pos, convert("foo 052"));
+ DoNumTest(convert("foo %+o"), pos, convert("foo 52"));
+ DoNumTest(convert("foo % o"), pos, convert("foo 52"));
+ DoNumTest(convert("foo %+o"), neg, convert("foo 37777777726"));
+ DoNumTest(convert("foo % o"), neg, convert("foo 37777777726"));
+
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/vswprintf/test10/testinfo.dat b/src/pal/tests/palsuite/c_runtime/vswprintf/test10/testinfo.dat
new file mode 100644
index 0000000000..81fbce5e4d
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vswprintf/test10/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = vswprintf
+Name = Positive Test for vswprintf
+TYPE = DEFAULT
+EXE1 = test10
+Description
+= Tests the PAL implementation of the vswprintf function.
+= Tests vswprintf with octal numbers.
+= This test is modeled after _snwprintf.
diff --git a/src/pal/tests/palsuite/c_runtime/vswprintf/test11/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/vswprintf/test11/CMakeLists.txt
new file mode 100644
index 0000000000..5237ba4e1d
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vswprintf/test11/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test11.c
+)
+
+add_executable(paltest_vswprintf_test11
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vswprintf_test11 coreclrpal)
+
+target_link_libraries(paltest_vswprintf_test11
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/vswprintf/test11/test11.c b/src/pal/tests/palsuite/c_runtime/vswprintf/test11/test11.c
new file mode 100644
index 0000000000..608069f829
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vswprintf/test11/test11.c
@@ -0,0 +1,48 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test11.c
+**
+** Purpose: Test #11 for the vswprintf function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+#include "../vswprintf.h"
+
+/* memcmp is used to verify the results, so this test is dependent on it. */
+/* ditto with wcslen */
+
+int __cdecl main(int argc, char *argv[])
+{
+ int neg = -42;
+ int pos = 42;
+ INT64 l = 42;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ return(FAIL);
+
+ DoNumTest(convert("foo %u"), pos, convert("foo 42"));
+ DoNumTest(convert("foo %lu"), 0xFFFF, convert("foo 65535"));
+ DoNumTest(convert("foo %hu"), 0xFFFF, convert("foo 65535"));
+ DoNumTest(convert("foo %Lu"), pos, convert("foo 42"));
+ DoI64NumTest(convert("foo %I64u"), l, "42", convert("foo 42"));
+ DoNumTest(convert("foo %3u"), pos, convert("foo 42"));
+ DoNumTest(convert("foo %-3u"), pos, convert("foo 42 "));
+ DoNumTest(convert("foo %.1u"), pos, convert("foo 42"));
+ DoNumTest(convert("foo %.3u"), pos, convert("foo 042"));
+ DoNumTest(convert("foo %03u"), pos, convert("foo 042"));
+ DoNumTest(convert("foo %#u"), pos, convert("foo 42"));
+ DoNumTest(convert("foo %+u"), pos, convert("foo 42"));
+ DoNumTest(convert("foo % u"), pos, convert("foo 42"));
+ DoNumTest(convert("foo %+u"), neg, convert("foo 4294967254"));
+ DoNumTest(convert("foo % u"), neg, convert("foo 4294967254"));
+
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/vswprintf/test11/testinfo.dat b/src/pal/tests/palsuite/c_runtime/vswprintf/test11/testinfo.dat
new file mode 100644
index 0000000000..13585cc94e
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vswprintf/test11/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = vswprintf
+Name = Positive Test for vswprintf
+TYPE = DEFAULT
+EXE1 = test11
+Description
+= Tests the PAL implementation of the vswprintf function.
+= Tests vswprintf with unsigned numbers.
+= This test is modeled after _snwprintf.
diff --git a/src/pal/tests/palsuite/c_runtime/vswprintf/test12/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/vswprintf/test12/CMakeLists.txt
new file mode 100644
index 0000000000..26199c3dcc
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vswprintf/test12/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test12.c
+)
+
+add_executable(paltest_vswprintf_test12
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vswprintf_test12 coreclrpal)
+
+target_link_libraries(paltest_vswprintf_test12
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/vswprintf/test12/test12.c b/src/pal/tests/palsuite/c_runtime/vswprintf/test12/test12.c
new file mode 100644
index 0000000000..36b203853a
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vswprintf/test12/test12.c
@@ -0,0 +1,48 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test12.c
+**
+** Purpose: Test #12 for the vswprintf function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+#include "../vswprintf.h"
+
+/* memcmp is used to verify the results, so this test is dependent on it. */
+/* ditto with wcslen */
+
+int __cdecl main(int argc, char *argv[])
+{
+ int neg = -42;
+ int pos = 0x1234ab;
+ INT64 l = I64(0x1234567887654321);
+
+ if (PAL_Initialize(argc, argv) != 0)
+ return(FAIL);
+
+ DoNumTest(convert("foo %x"), pos, convert("foo 1234ab"));
+ DoNumTest(convert("foo %lx"), pos, convert("foo 1234ab"));
+ DoNumTest(convert("foo %hx"), pos, convert("foo 34ab"));
+ DoNumTest(convert("foo %Lx"), pos, convert("foo 1234ab"));
+ DoI64NumTest(convert("foo %I64x"), l, "0x1234567887654321",
+ convert("foo 1234567887654321"));
+ DoNumTest(convert("foo %7x"), pos, convert("foo 1234ab"));
+ DoNumTest(convert("foo %-7x"), pos, convert("foo 1234ab "));
+ DoNumTest(convert("foo %.1x"), pos, convert("foo 1234ab"));
+ DoNumTest(convert("foo %.7x"), pos, convert("foo 01234ab"));
+ DoNumTest(convert("foo %07x"), pos, convert("foo 01234ab"));
+ DoNumTest(convert("foo %#x"), pos, convert("foo 0x1234ab"));
+ DoNumTest(convert("foo %+x"), pos, convert("foo 1234ab"));
+ DoNumTest(convert("foo % x"), pos, convert("foo 1234ab"));
+ DoNumTest(convert("foo %+x"), neg, convert("foo ffffffd6"));
+ DoNumTest(convert("foo % x"), neg, convert("foo ffffffd6"));
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/vswprintf/test12/testinfo.dat b/src/pal/tests/palsuite/c_runtime/vswprintf/test12/testinfo.dat
new file mode 100644
index 0000000000..d42e9a1801
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vswprintf/test12/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = vswprintf
+Name = Positive Test for vswprintf
+TYPE = DEFAULT
+EXE1 = test12
+Description
+= Tests the PAL implementation of the vswprintf function.
+= Tests vswprintf with hex numbers (lowercase).
+= This test is modeled after _snwprintf.
diff --git a/src/pal/tests/palsuite/c_runtime/vswprintf/test13/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/vswprintf/test13/CMakeLists.txt
new file mode 100644
index 0000000000..d0acd98d64
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vswprintf/test13/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test13.c
+)
+
+add_executable(paltest_vswprintf_test13
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vswprintf_test13 coreclrpal)
+
+target_link_libraries(paltest_vswprintf_test13
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/vswprintf/test13/test13.c b/src/pal/tests/palsuite/c_runtime/vswprintf/test13/test13.c
new file mode 100644
index 0000000000..63dc36a960
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vswprintf/test13/test13.c
@@ -0,0 +1,48 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test13.c
+**
+** Purpose: Test #13 for the vswprintf function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+#include "../vswprintf.h"
+
+/* memcmp is used to verify the results, so this test is dependent on it. */
+/* ditto with wcslen */
+
+int __cdecl main(int argc, char *argv[])
+{
+ int neg = -42;
+ int pos = 0x1234ab;
+ INT64 l = I64(0x1234567887654321);
+
+ if (PAL_Initialize(argc, argv) != 0)
+ return(FAIL);
+
+ DoNumTest(convert("foo %X"), pos, convert("foo 1234AB"));
+ DoNumTest(convert("foo %lX"), pos, convert("foo 1234AB"));
+ DoNumTest(convert("foo %hX"), pos, convert("foo 34AB"));
+ DoNumTest(convert("foo %LX"), pos, convert("foo 1234AB"));
+ DoI64NumTest(convert("foo %I64X"), l, "0x1234567887654321",
+ convert("foo 1234567887654321"));
+ DoNumTest(convert("foo %7X"), pos, convert("foo 1234AB"));
+ DoNumTest(convert("foo %-7X"), pos, convert("foo 1234AB "));
+ DoNumTest(convert("foo %.1X"), pos, convert("foo 1234AB"));
+ DoNumTest(convert("foo %.7X"), pos, convert("foo 01234AB"));
+ DoNumTest(convert("foo %07X"), pos, convert("foo 01234AB"));
+ DoNumTest(convert("foo %#X"), pos, convert("foo 0X1234AB"));
+ DoNumTest(convert("foo %+X"), pos, convert("foo 1234AB"));
+ DoNumTest(convert("foo % X"), pos, convert("foo 1234AB"));
+ DoNumTest(convert("foo %+X"), neg, convert("foo FFFFFFD6"));
+ DoNumTest(convert("foo % X"), neg, convert("foo FFFFFFD6"));
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/vswprintf/test13/testinfo.dat b/src/pal/tests/palsuite/c_runtime/vswprintf/test13/testinfo.dat
new file mode 100644
index 0000000000..f7c6756e30
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vswprintf/test13/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = vswprintf
+Name = Positive Test for vswprintf
+TYPE = DEFAULT
+EXE1 = test13
+Description
+= Tests the PAL implementation of the vswprintf function.
+= Tests vswprintf with hex numbers (uppercase).
+= This test is modeled after _snwprintf.
diff --git a/src/pal/tests/palsuite/c_runtime/vswprintf/test14/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/vswprintf/test14/CMakeLists.txt
new file mode 100644
index 0000000000..06c12674a4
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vswprintf/test14/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test14.c
+)
+
+add_executable(paltest_vswprintf_test14
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vswprintf_test14 coreclrpal)
+
+target_link_libraries(paltest_vswprintf_test14
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/vswprintf/test14/test14.c b/src/pal/tests/palsuite/c_runtime/vswprintf/test14/test14.c
new file mode 100644
index 0000000000..bb4ab16a54
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vswprintf/test14/test14.c
@@ -0,0 +1,61 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test14.c
+**
+** Purpose: Test #14 for the vswprintf function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+#include "../vswprintf.h"
+
+/* memcmp is used to verify the results, so this test is dependent on it. */
+/* ditto with wcslen */
+
+int __cdecl main(int argc, char *argv[])
+{
+ double val = 256.0;
+ double neg = -256.0;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ return(FAIL);
+
+ DoDoubleTest(convert("foo %e"), val, convert("foo 2.560000e+002"),
+ convert("foo 2.560000e+02"));
+ DoDoubleTest(convert("foo %le"), val, convert("foo 2.560000e+002"),
+ convert("foo 2.560000e+02"));
+ DoDoubleTest(convert("foo %he"), val, convert("foo 2.560000e+002"),
+ convert("foo 2.560000e+02"));
+ DoDoubleTest(convert("foo %Le"), val, convert("foo 2.560000e+002"),
+ convert("foo 2.560000e+02"));
+ DoDoubleTest(convert("foo %I64e"), val, convert("foo 2.560000e+002"),
+ convert("foo 2.560000e+02"));
+ DoDoubleTest(convert("foo %14e"), val, convert("foo 2.560000e+002"),
+ convert("foo 2.560000e+02"));
+ DoDoubleTest(convert("foo %-14e"), val, convert("foo 2.560000e+002 "),
+ convert("foo 2.560000e+02 "));
+ DoDoubleTest(convert("foo %.1e"), val, convert("foo 2.6e+002"),
+ convert("foo 2.6e+02"));
+ DoDoubleTest(convert("foo %.8e"), val, convert("foo 2.56000000e+002"),
+ convert("foo 2.56000000e+02"));
+ DoDoubleTest(convert("foo %014e"), val, convert("foo 02.560000e+002"),
+ convert("foo 002.560000e+02"));
+ DoDoubleTest(convert("foo %#e"), val, convert("foo 2.560000e+002"),
+ convert("foo 2.560000e+02"));
+ DoDoubleTest(convert("foo %+e"), val, convert("foo +2.560000e+002"),
+ convert("foo +2.560000e+02"));
+ DoDoubleTest(convert("foo % e"), val, convert("foo 2.560000e+002"),
+ convert("foo 2.560000e+02"));
+ DoDoubleTest(convert("foo %+e"), neg, convert("foo -2.560000e+002"),
+ convert("foo -2.560000e+02"));
+ DoDoubleTest(convert("foo % e"), neg, convert("foo -2.560000e+002"),
+ convert("foo -2.560000e+02"));
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/vswprintf/test14/testinfo.dat b/src/pal/tests/palsuite/c_runtime/vswprintf/test14/testinfo.dat
new file mode 100644
index 0000000000..e9615f906a
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vswprintf/test14/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = vswprintf
+Name = Positive Test for vswprintf
+TYPE = DEFAULT
+EXE1 = test14
+Description
+= Tests the PAL implementation of the vswprintf function.
+= Tests vswprintf with exponential format doubles (lowercase).
+= This test is modeled after _snwprintf.
diff --git a/src/pal/tests/palsuite/c_runtime/vswprintf/test15/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/vswprintf/test15/CMakeLists.txt
new file mode 100644
index 0000000000..05dc41b0d8
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vswprintf/test15/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test15.c
+)
+
+add_executable(paltest_vswprintf_test15
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vswprintf_test15 coreclrpal)
+
+target_link_libraries(paltest_vswprintf_test15
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/vswprintf/test15/test15.c b/src/pal/tests/palsuite/c_runtime/vswprintf/test15/test15.c
new file mode 100644
index 0000000000..6296220c4e
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vswprintf/test15/test15.c
@@ -0,0 +1,62 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test15.c
+**
+** Purpose: Test #15 for the vswprintf function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+#include "../vswprintf.h"
+
+/* memcmp is used to verify the results, so this test is dependent on it. */
+/* ditto with wcslen */
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ double val = 256.0;
+ double neg = -256.0;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ return(FAIL);
+
+ DoDoubleTest(convert("foo %E"), val, convert("foo 2.560000E+002"),
+ convert("foo 2.560000E+02"));
+ DoDoubleTest(convert("foo %lE"), val, convert("foo 2.560000E+002"),
+ convert("foo 2.560000E+02"));
+ DoDoubleTest(convert("foo %hE"), val, convert("foo 2.560000E+002"),
+ convert("foo 2.560000E+02"));
+ DoDoubleTest(convert("foo %LE"), val, convert("foo 2.560000E+002"),
+ convert("foo 2.560000E+02"));
+ DoDoubleTest(convert("foo %I64E"), val, convert("foo 2.560000E+002"),
+ convert("foo 2.560000E+02"));
+ DoDoubleTest(convert("foo %14E"), val, convert("foo 2.560000E+002"),
+ convert("foo 2.560000E+02"));
+ DoDoubleTest(convert("foo %-14E"), val, convert("foo 2.560000E+002 "),
+ convert("foo 2.560000E+02 "));
+ DoDoubleTest(convert("foo %.1E"), val, convert("foo 2.6E+002"),
+ convert("foo 2.6E+02"));
+ DoDoubleTest(convert("foo %.8E"), val, convert("foo 2.56000000E+002"),
+ convert("foo 2.56000000E+02"));
+ DoDoubleTest(convert("foo %014E"), val, convert("foo 02.560000E+002"),
+ convert("foo 002.560000E+02"));
+ DoDoubleTest(convert("foo %#E"), val, convert("foo 2.560000E+002"),
+ convert("foo 2.560000E+02"));
+ DoDoubleTest(convert("foo %+E"), val, convert("foo +2.560000E+002"),
+ convert("foo +2.560000E+02"));
+ DoDoubleTest(convert("foo % E"), val, convert("foo 2.560000E+002"),
+ convert("foo 2.560000E+02"));
+ DoDoubleTest(convert("foo %+E"), neg, convert("foo -2.560000E+002"),
+ convert("foo -2.560000E+02"));
+ DoDoubleTest(convert("foo % E"), neg, convert("foo -2.560000E+002"),
+ convert("foo -2.560000E+002"));
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/vswprintf/test15/testinfo.dat b/src/pal/tests/palsuite/c_runtime/vswprintf/test15/testinfo.dat
new file mode 100644
index 0000000000..24ff03b11a
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vswprintf/test15/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = vswprintf
+Name = Positive Test for vswprintf
+TYPE = DEFAULT
+EXE1 = test15
+Description
+= Tests the PAL implementation of the vswprintf function.
+= Tests vswprintf with exponential format doubles (uppercase).
+= This test is modeled after _snwprintf.
diff --git a/src/pal/tests/palsuite/c_runtime/vswprintf/test16/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/vswprintf/test16/CMakeLists.txt
new file mode 100644
index 0000000000..3c42755043
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vswprintf/test16/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test16.c
+)
+
+add_executable(paltest_vswprintf_test16
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vswprintf_test16 coreclrpal)
+
+target_link_libraries(paltest_vswprintf_test16
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/vswprintf/test16/test16.c b/src/pal/tests/palsuite/c_runtime/vswprintf/test16/test16.c
new file mode 100644
index 0000000000..3a2059a491
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vswprintf/test16/test16.c
@@ -0,0 +1,61 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test16.c
+**
+** Purpose: Test #16 for the vswprintf function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+#include "../vswprintf.h"
+
+/* memcmp is used to verify the results, so this test is dependent on it. */
+/* ditto with wcslen */
+
+int __cdecl main(int argc, char *argv[])
+{
+ double val = 2560.001;
+ double neg = -2560.001;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ return(FAIL);
+
+ DoDoubleTest(convert("foo %f"), val, convert("foo 2560.001000"),
+ convert("foo 2560.001000"));
+ DoDoubleTest(convert("foo %lf"), val, convert("foo 2560.001000"),
+ convert("foo 2560.001000"));
+ DoDoubleTest(convert("foo %hf"), val, convert("foo 2560.001000"),
+ convert("foo 2560.001000"));
+ DoDoubleTest(convert("foo %Lf"), val, convert("foo 2560.001000"),
+ convert("foo 2560.001000"));
+ DoDoubleTest(convert("foo %I64f"), val, convert("foo 2560.001000"),
+ convert("foo 2560.001000"));
+ DoDoubleTest(convert("foo %12f"), val, convert("foo 2560.001000"),
+ convert("foo 2560.001000"));
+ DoDoubleTest(convert("foo %-12f"), val, convert("foo 2560.001000 "),
+ convert("foo 2560.001000 "));
+ DoDoubleTest(convert("foo %.1f"), val, convert("foo 2560.0"),
+ convert("foo 2560.0"));
+ DoDoubleTest(convert("foo %.8f"), val, convert("foo 2560.00100000"),
+ convert("foo 2560.00100000"));
+ DoDoubleTest(convert("foo %012f"), val, convert("foo 02560.001000"),
+ convert("foo 02560.001000"));
+ DoDoubleTest(convert("foo %#f"), val, convert("foo 2560.001000"),
+ convert("foo 2560.001000"));
+ DoDoubleTest(convert("foo %+f"), val, convert("foo +2560.001000"),
+ convert("foo +2560.001000"));
+ DoDoubleTest(convert("foo % f"), val, convert("foo 2560.001000"),
+ convert("foo 2560.001000"));
+ DoDoubleTest(convert("foo %+f"), neg, convert("foo -2560.001000"),
+ convert("foo -2560.001000"));
+ DoDoubleTest(convert("foo % f"), neg, convert("foo -2560.001000"),
+ convert("foo -2560.001000"));
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/vswprintf/test16/testinfo.dat b/src/pal/tests/palsuite/c_runtime/vswprintf/test16/testinfo.dat
new file mode 100644
index 0000000000..6dc45f4c78
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vswprintf/test16/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = vswprintf
+Name = Positive Test for vswprintf
+TYPE = DEFAULT
+EXE1 = test16
+Description
+= Tests the PAL implementation of the vswprintf function.
+= Tests vswprintf with decimal point format doubles.
+= This test is modeled after _snwprintf.
diff --git a/src/pal/tests/palsuite/c_runtime/vswprintf/test17/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/vswprintf/test17/CMakeLists.txt
new file mode 100644
index 0000000000..b94c466d5f
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vswprintf/test17/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test17.c
+)
+
+add_executable(paltest_vswprintf_test17
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vswprintf_test17 coreclrpal)
+
+target_link_libraries(paltest_vswprintf_test17
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/vswprintf/test17/test17.c b/src/pal/tests/palsuite/c_runtime/vswprintf/test17/test17.c
new file mode 100644
index 0000000000..95e3bd9995
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vswprintf/test17/test17.c
@@ -0,0 +1,63 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test17.c
+**
+** Purpose: Test #17 for the vswprintf function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+#include "../vswprintf.h"
+
+/* memcmp is used to verify the results, so this test is dependent on it. */
+/* ditto with wcslen */
+
+int __cdecl main(int argc, char *argv[])
+{
+ double val = 2560.001;
+ double neg = -2560.001;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ return(FAIL);
+
+ DoDoubleTest(convert("foo %g"), val, convert("foo 2560"),
+ convert("foo 2560"));
+ DoDoubleTest(convert("foo %lg"), val, convert("foo 2560"),
+ convert("foo 2560"));
+ DoDoubleTest(convert("foo %hg"), val, convert("foo 2560"),
+ convert("foo 2560"));
+ DoDoubleTest(convert("foo %Lg"), val, convert("foo 2560"),
+ convert("foo 2560"));
+ DoDoubleTest(convert("foo %I64g"), val, convert("foo 2560"),
+ convert("foo 2560"));
+ DoDoubleTest(convert("foo %5g"), val, convert("foo 2560"),
+ convert("foo 2560"));
+ DoDoubleTest(convert("foo %-5g"), val, convert("foo 2560 "),
+ convert("foo 2560 "));
+ DoDoubleTest(convert("foo %.1g"), val, convert("foo 3e+003"),
+ convert("foo 3e+03"));
+ DoDoubleTest(convert("foo %.2g"), val, convert("foo 2.6e+003"),
+ convert("foo 2.6e+03"));
+ DoDoubleTest(convert("foo %.12g"), val, convert("foo 2560.001"),
+ convert("foo 2560.001"));
+ DoDoubleTest(convert("foo %06g"), val, convert("foo 002560"),
+ convert("foo 002560"));
+ DoDoubleTest(convert("foo %#g"), val, convert("foo 2560.00"),
+ convert("foo 2560.00"));
+ DoDoubleTest(convert("foo %+g"), val, convert("foo +2560"),
+ convert("foo +2560"));
+ DoDoubleTest(convert("foo % g"), val, convert("foo 2560"),
+ convert("foo 2560"));
+ DoDoubleTest(convert("foo %+g"), neg, convert("foo -2560"),
+ convert("foo -2560"));
+ DoDoubleTest(convert("foo % g"), neg, convert("foo -2560"),
+ convert("foo -2560"));
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/vswprintf/test17/testinfo.dat b/src/pal/tests/palsuite/c_runtime/vswprintf/test17/testinfo.dat
new file mode 100644
index 0000000000..815e57ddf5
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vswprintf/test17/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = vswprintf
+Name = Positive Test for vswprintf
+TYPE = DEFAULT
+EXE1 = test17
+Description
+= Tests the PAL implementation of the vswprintf function.
+= Tests vswprintf with compact format doubles (lowercase).
+= This test is modeled after _snwprintf.
diff --git a/src/pal/tests/palsuite/c_runtime/vswprintf/test18/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/vswprintf/test18/CMakeLists.txt
new file mode 100644
index 0000000000..57cc8ccb03
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vswprintf/test18/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test18.c
+)
+
+add_executable(paltest_vswprintf_test18
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vswprintf_test18 coreclrpal)
+
+target_link_libraries(paltest_vswprintf_test18
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/vswprintf/test18/test18.c b/src/pal/tests/palsuite/c_runtime/vswprintf/test18/test18.c
new file mode 100644
index 0000000000..ae7ae4c44b
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vswprintf/test18/test18.c
@@ -0,0 +1,63 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test18.c
+**
+** Purpose: Test #18 for the vswprintf function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+#include "../vswprintf.h"
+
+/* memcmp is used to verify the results, so this test is dependent on it. */
+/* ditto with wcslen */
+
+int __cdecl main(int argc, char *argv[])
+{
+ double val = 2560.001;
+ double neg = -2560.001;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ return(FAIL);
+
+ DoDoubleTest(convert("foo %G"), val, convert("foo 2560"),
+ convert("foo 2560"));
+ DoDoubleTest(convert("foo %lG"), val, convert("foo 2560"),
+ convert("foo 2560"));
+ DoDoubleTest(convert("foo %hG"), val, convert("foo 2560"),
+ convert("foo 2560"));
+ DoDoubleTest(convert("foo %LG"), val, convert("foo 2560"),
+ convert("foo 2560"));
+ DoDoubleTest(convert("foo %I64G"), val, convert("foo 2560"),
+ convert("foo 2560"));
+ DoDoubleTest(convert("foo %5G"), val, convert("foo 2560"),
+ convert("foo 2560"));
+ DoDoubleTest(convert("foo %-5G"), val, convert("foo 2560 "),
+ convert("foo 2560 "));
+ DoDoubleTest(convert("foo %.1G"), val, convert("foo 3E+003"),
+ convert("foo 3E+03"));
+ DoDoubleTest(convert("foo %.2G"), val, convert("foo 2.6E+003"),
+ convert("foo 2.6E+03"));
+ DoDoubleTest(convert("foo %.12G"), val, convert("foo 2560.001"),
+ convert("foo 2560.001"));
+ DoDoubleTest(convert("foo %06G"), val, convert("foo 002560"),
+ convert("foo 002560"));
+ DoDoubleTest(convert("foo %#G"), val, convert("foo 2560.00"),
+ convert("foo 2560.00"));
+ DoDoubleTest(convert("foo %+G"), val, convert("foo +2560"),
+ convert("foo +2560"));
+ DoDoubleTest(convert("foo % G"), val, convert("foo 2560"),
+ convert("foo 2560"));
+ DoDoubleTest(convert("foo %+G"), neg, convert("foo -2560"),
+ convert("foo -2560"));
+ DoDoubleTest(convert("foo % G"), neg, convert("foo -2560"),
+ convert("foo -2560"));
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/vswprintf/test18/testinfo.dat b/src/pal/tests/palsuite/c_runtime/vswprintf/test18/testinfo.dat
new file mode 100644
index 0000000000..b5165999a6
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vswprintf/test18/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = vswprintf
+Name = Positive Test for vswprintf
+TYPE = DEFAULT
+EXE1 = test18
+Description
+= Tests the PAL implementation of the vswprintf function.
+= Tests vswprintf with compact format doubles (uppercase).
+= This test is modeled after _snwprintf.
diff --git a/src/pal/tests/palsuite/c_runtime/vswprintf/test19/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/vswprintf/test19/CMakeLists.txt
new file mode 100644
index 0000000000..2187b58727
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vswprintf/test19/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test19.c
+)
+
+add_executable(paltest_vswprintf_test19
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vswprintf_test19 coreclrpal)
+
+target_link_libraries(paltest_vswprintf_test19
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/vswprintf/test19/test19.c b/src/pal/tests/palsuite/c_runtime/vswprintf/test19/test19.c
new file mode 100644
index 0000000000..c00185be6d
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vswprintf/test19/test19.c
@@ -0,0 +1,137 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test18.c
+**
+** Purpose: Test #18 for the vswprintf function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+#include "../vswprintf.h"
+
+/* memcmp is used to verify the results, so this test is dependent on it. */
+/* ditto with wcslen */
+
+#define DOTEST(a,b,c,d,e) DoTest(a,b,(void*)c,d,e)
+
+void DoArgumentPrecTest(WCHAR *formatstr, int precision, void *param,
+ WCHAR *paramstr, WCHAR *checkstr1, WCHAR *checkstr2)
+{
+ WCHAR buf[256];
+
+ testvswp(buf, formatstr, precision, param);
+ if (memcmp(buf, checkstr1, wcslen(checkstr1) + 2) != 0 &&
+ memcmp(buf, checkstr2, wcslen(checkstr2) + 2) != 0)
+ {
+ Fail("ERROR: failed to insert %s into \"%s\" with precision %d\n"
+ "Expected \"%s\" or \"%s\", got \"%s\".\n",
+ paramstr,
+ convertC(formatstr),
+ precision,
+ convertC(checkstr1),
+ convertC(checkstr2),
+ convertC(buf));
+ }
+}
+void DoArgumentPrecDoubleTest(WCHAR *formatstr, int precision, double param,
+ WCHAR *checkstr1, WCHAR *checkstr2)
+{
+ WCHAR buf[256];
+
+ testvswp(buf, formatstr, precision, param);
+ if (memcmp(buf, checkstr1, wcslen(checkstr1) + 2) != 0 &&
+ memcmp(buf, checkstr2, wcslen(checkstr2) + 2) != 0)
+ {
+ Fail("ERROR: failed to insert %f into \"%s\" with precision %d\n"
+ "Expected \"%s\" or \"%s\", got \"%s\".\n",
+ param, convertC(formatstr),
+ precision,
+ convertC(checkstr1),
+ convertC(checkstr2),
+ convertC(buf));
+ }
+}
+
+/*
+ * Uses memcmp & wcslen
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ if (PAL_Initialize(argc, argv) != 0)
+ return(FAIL);
+
+ DoArgumentPrecTest(convert("%.*s"), 2, convert("bar"), convert("bar"),
+ convert("ba"), convert("ba"));
+ DoArgumentPrecTest(convert("%.*c"), 0, (void*)'a', convert("a"),
+ convert("a"), convert("a"));
+ DoArgumentPrecTest(convert("%.*c"), 4, (void*)'a', convert("a"),
+ convert("a"), convert("a"));
+ DoArgumentPrecTest(convert("%.*C"), 0, (void*)'a', convert("a"),
+ convert("a"), convert("a"));
+ DoArgumentPrecTest(convert("%.*C"), 4, (void*)'a', convert("a"),
+ convert("a"), convert("a"));
+ DoArgumentPrecTest(convert("%.*d"), 1, (void*)42, convert("42"),
+ convert("42"), convert("42"));
+ DoArgumentPrecTest(convert("%.*d"), 3, (void*)42, convert("42"),
+ convert("042"), convert("042"));
+ DoArgumentPrecTest(convert("%.*i"), 1, (void*)42, convert("42"),
+ convert("42"), convert("42"));
+ DoArgumentPrecTest(convert("%.*i"), 3, (void*)42, convert("42"),
+ convert("042"), convert("042"));
+ DoArgumentPrecTest(convert("%.*o"), 1, (void*)42, convert("42"),
+ convert("52"), convert("52"));
+ DoArgumentPrecTest(convert("%.*o"), 3, (void*)42, convert("42"),
+ convert("052"), convert("052"));
+ DoArgumentPrecTest(convert("%.*u"), 1, (void*)42, convert("42"),
+ convert("42"), convert("42"));
+ DoArgumentPrecTest(convert("%.*u"), 3, (void*)42, convert("42"),
+ convert("042"), convert("042"));
+ DoArgumentPrecTest(convert("%.*x"), 1, (void*)0x42, convert("0x42"),
+ convert("42"), convert("42"));
+ DoArgumentPrecTest(convert("%.*x"), 3, (void*)0x42, convert("0x42"),
+ convert("042"), convert("042"));
+ DoArgumentPrecTest(convert("%.*X"), 1, (void*)0x42, convert("0x42"),
+ convert("42"), convert("42"));
+ DoArgumentPrecTest(convert("%.*X"), 3, (void*)0x42, convert("0x42"),
+ convert("042"), convert("042"));
+
+
+ DoArgumentPrecDoubleTest(convert("%.*e"), 1, 2.01, convert("2.0e+000"),
+ convert("2.0e+00"));
+ DoArgumentPrecDoubleTest(convert("%.*e"), 3, 2.01, convert("2.010e+000"),
+ convert("2.010e+00"));
+ DoArgumentPrecDoubleTest(convert("%.*E"), 1, 2.01, convert("2.0E+000"),
+ convert("2.0E+00"));
+ DoArgumentPrecDoubleTest(convert("%.*E"), 3, 2.01, convert("2.010E+000"),
+ convert("2.010E+00"));
+ DoArgumentPrecDoubleTest(convert("%.*f"), 1, 2.01, convert("2.0"),
+ convert("2.0"));
+ DoArgumentPrecDoubleTest(convert("%.*f"), 3, 2.01, convert("2.010"),
+ convert("2.010"));
+ DoArgumentPrecDoubleTest(convert("%.*g"), 1, 256.01, convert("3e+002"),
+ convert("3e+02"));
+ DoArgumentPrecDoubleTest(convert("%.*g"), 3, 256.01, convert("256"),
+ convert("256"));
+ DoArgumentPrecDoubleTest(convert("%.*g"), 4, 256.01, convert("256"),
+ convert("256"));
+ DoArgumentPrecDoubleTest(convert("%.*g"), 6, 256.01, convert("256.01"),
+ convert("256.01"));
+ DoArgumentPrecDoubleTest(convert("%.*G"), 1, 256.01, convert("3E+002"),
+ convert("3E+02"));
+ DoArgumentPrecDoubleTest(convert("%.*G"), 3, 256.01, convert("256"),
+ convert("256"));
+ DoArgumentPrecDoubleTest(convert("%.*G"), 4, 256.01, convert("256"),
+ convert("256"));
+ DoArgumentPrecDoubleTest(convert("%.*G"), 6, 256.01, convert("256.01"),
+ convert("256.01"));
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/vswprintf/test19/testinfo.dat b/src/pal/tests/palsuite/c_runtime/vswprintf/test19/testinfo.dat
new file mode 100644
index 0000000000..ccc08cd7ba
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vswprintf/test19/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = vswprintf
+Name = Positive Test for vswprintf
+TYPE = DEFAULT
+EXE1 = test19
+Description
+= Tests the PAL implementation of the vswprintf function.
+= Tests vswprintf with argument specified precision.
+= This test is modeled after _snwprintf.
diff --git a/src/pal/tests/palsuite/c_runtime/vswprintf/test2/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/vswprintf/test2/CMakeLists.txt
new file mode 100644
index 0000000000..295448cb0c
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vswprintf/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test2.c
+)
+
+add_executable(paltest_vswprintf_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vswprintf_test2 coreclrpal)
+
+target_link_libraries(paltest_vswprintf_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/vswprintf/test2/test2.c b/src/pal/tests/palsuite/c_runtime/vswprintf/test2/test2.c
new file mode 100644
index 0000000000..491d99f0cf
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vswprintf/test2/test2.c
@@ -0,0 +1,40 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test2.c
+**
+** Purpose: Test #2 for the vswprintf function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+#include "../vswprintf.h"
+
+/* memcmp is used to verify the results, so this test is dependent on it. */
+/* ditto with wcslen */
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ if (PAL_Initialize(argc, argv) != 0)
+ return(FAIL);
+
+ DoWStrTest(convert("foo %s"), convert("bar"), convert("foo bar"));
+ DoStrTest(convert("foo %hs"), "bar", convert("foo bar"));
+ DoWStrTest(convert("foo %ls"), convert("bar"), convert("foo bar"));
+ DoWStrTest(convert("foo %ws"), convert("bar"), convert("foo bar"));
+ DoWStrTest(convert("foo %Ls"), convert("bar"), convert("foo bar"));
+ DoWStrTest(convert("foo %I64s"), convert("bar"), convert("foo bar"));
+ DoWStrTest(convert("foo %5s"), convert("bar"), convert("foo bar"));
+ DoWStrTest(convert("foo %.2s"), convert("bar"), convert("foo ba"));
+ DoWStrTest(convert("foo %5.2s"), convert("bar"), convert("foo ba"));
+ DoWStrTest(convert("foo %-5s"), convert("bar"), convert("foo bar "));
+ DoWStrTest(convert("foo %05s"), convert("bar"), convert("foo 00bar"));
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/vswprintf/test2/testinfo.dat b/src/pal/tests/palsuite/c_runtime/vswprintf/test2/testinfo.dat
new file mode 100644
index 0000000000..d6d7c3e8bd
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vswprintf/test2/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = vswprintf
+Name = Positive Test for vswprintf
+TYPE = DEFAULT
+EXE1 = test2
+Description
+= Tests the PAL implementation of the vswprintf function.
+= Tests vswprintf with strings.
+= This test is modeled after _snwprintf.
diff --git a/src/pal/tests/palsuite/c_runtime/vswprintf/test3/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/vswprintf/test3/CMakeLists.txt
new file mode 100644
index 0000000000..1fb6272ae7
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vswprintf/test3/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test3.c
+)
+
+add_executable(paltest_vswprintf_test3
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vswprintf_test3 coreclrpal)
+
+target_link_libraries(paltest_vswprintf_test3
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/vswprintf/test3/test3.c b/src/pal/tests/palsuite/c_runtime/vswprintf/test3/test3.c
new file mode 100644
index 0000000000..1eb0b65ebe
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vswprintf/test3/test3.c
@@ -0,0 +1,40 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test3.c
+**
+** Purpose: Test #3 for the vswprintf function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+#include "../vswprintf.h"
+
+/* memcmp is used to verify the results, so this test is dependent on it. */
+/* ditto with wcslen */
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ if (PAL_Initialize(argc, argv) != 0)
+ return(FAIL);
+
+ DoStrTest(convert("foo %S"), "bar", convert("foo bar"));
+ DoStrTest(convert("foo %hS"), "bar", convert("foo bar"));
+ DoWStrTest(convert("foo %lS"), convert("bar"), convert("foo bar"));
+ DoWStrTest(convert("foo %wS"), convert("bar"), convert("foo bar"));
+ DoStrTest(convert("foo %LS"), "bar", convert("foo bar"));
+ DoStrTest(convert("foo %I64S"), "bar", convert("foo bar"));
+ DoStrTest(convert("foo %5S"), "bar", convert("foo bar"));
+ DoStrTest(convert("foo %.2S"), "bar", convert("foo ba"));
+ DoStrTest(convert("foo %5.2S"), "bar", convert("foo ba"));
+ DoStrTest(convert("foo %-5S"), "bar", convert("foo bar "));
+ DoStrTest(convert("foo %05S"), "bar", convert("foo 00bar"));
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/vswprintf/test3/testinfo.dat b/src/pal/tests/palsuite/c_runtime/vswprintf/test3/testinfo.dat
new file mode 100644
index 0000000000..8fb9dc8060
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vswprintf/test3/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = vswprintf
+Name = Positive Test for vswprintf
+TYPE = DEFAULT
+EXE1 = test3
+Description
+= Tests the PAL implementation of the vswprintf function.
+= Tests vswprintf with wide strings.
+= This test is modeled after _snwprintf.
diff --git a/src/pal/tests/palsuite/c_runtime/vswprintf/test4/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/vswprintf/test4/CMakeLists.txt
new file mode 100644
index 0000000000..cae0806e03
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vswprintf/test4/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test4.c
+)
+
+add_executable(paltest_vswprintf_test4
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vswprintf_test4 coreclrpal)
+
+target_link_libraries(paltest_vswprintf_test4
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/vswprintf/test4/test4.c b/src/pal/tests/palsuite/c_runtime/vswprintf/test4/test4.c
new file mode 100644
index 0000000000..5c9047b5a7
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vswprintf/test4/test4.c
@@ -0,0 +1,118 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test4.c
+**
+** Purpose: Test #4 for the vswprintf function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+#include "../vswprintf.h"
+
+/* memcmp is used to verify the results, so this test is dependent on it. */
+/* ditto with wcslen */
+static void DoPointerTest(WCHAR *formatstr, void* param, WCHAR* paramstr,
+ WCHAR *checkstr1)
+{
+ WCHAR buf[256] = { 0 };
+
+ testvswp(buf, formatstr, param);
+ if (memcmp(buf, checkstr1, wcslen(checkstr1) + 2) != 0)
+
+ {
+ Fail("ERROR: failed to insert pointer to %#p into \"%s\"\n"
+ "Expected \"%s\" got \"%s\".\n",
+ paramstr,
+ convertC(formatstr),
+ convertC(checkstr1),
+ convertC(buf));
+ }
+}
+
+static void DoI64DoubleTest(WCHAR *formatstr, INT64 value, WCHAR *valuestr,
+ WCHAR *checkstr1)
+{
+ WCHAR buf[256] = { 0 };
+
+ testvswp(buf, formatstr, value);
+ if (memcmp(buf, checkstr1, wcslen(checkstr1) + 2) != 0)
+ {
+ Fail("ERROR: failed to insert %s into \"%s\"\n"
+ "Expected \"%s\", got \"%s\".\n",
+ value,
+ convertC(formatstr),
+ convertC(checkstr1),
+ convertC(buf));
+ }
+}
+
+int __cdecl main(int argc, char *argv[])
+{
+ void *ptr = (void*) 0x123456;
+ INT64 lptr = I64(0x1234567887654321);
+
+ if (PAL_Initialize(argc, argv) != 0)
+ return(FAIL);
+
+/*
+** Run only on 64 bit platforms
+*/
+#if defined(BIT64) && defined(PLATFORM_UNIX)
+ Trace("Testing for 64 Bit Platforms \n");
+ DoPointerTest(convert("%p"), NULL, convert("NULL"), convert("0000000000000000"));
+ DoPointerTest(convert("%p"), ptr, convert("pointer to 0x123456"),
+ convert("0000000000123456"));
+ DoPointerTest(convert("%17p"), ptr, convert("pointer to 0x123456"),
+ convert(" 0000000000123456"));
+ DoPointerTest(convert("%17p"), ptr, convert("pointer to 0x123456"),
+ convert(" 0000000000123456"));
+ DoPointerTest(convert("%-17p"), ptr, convert("pointer to 0x123456"),
+ convert("0000000000123456 "));
+ DoPointerTest(convert("%+p"), ptr, convert("pointer to 0x123456"),
+ convert("0000000000123456"));
+ DoPointerTest(convert("%#p"), ptr, convert("pointer to 0x123456"),
+ convert("0X0000000000123456"));
+ DoPointerTest(convert("%lp"), ptr, convert("pointer to 0x123456"),
+ convert("00123456"));
+ DoPointerTest(convert("%hp"), ptr, convert("pointer to 0x123456"),
+ convert("00003456"));
+ DoPointerTest(convert("%Lp"), ptr, convert("pointer to 0x123456"),
+ convert("00123456"));
+ DoI64DoubleTest(convert("%I64p"), lptr,
+ convert("pointer to 0x1234567887654321"), convert("1234567887654321"));
+
+#else
+ Trace("Testing for Non 64 Bit Platforms \n");
+ DoPointerTest(convert("%p"), NULL, convert("NULL"), convert("00000000"));
+ DoPointerTest(convert("%p"), ptr, convert("pointer to 0x123456"),
+ convert("00123456"));
+ DoPointerTest(convert("%9p"), ptr, convert("pointer to 0x123456"),
+ convert(" 00123456"));
+ DoPointerTest(convert("%09p"), ptr, convert("pointer to 0x123456"),
+ convert(" 00123456"));
+ DoPointerTest(convert("%-9p"), ptr, convert("pointer to 0x123456"),
+ convert("00123456 "));
+ DoPointerTest(convert("%+p"), ptr, convert("pointer to 0x123456"),
+ convert("00123456"));
+ DoPointerTest(convert("%#p"), ptr, convert("pointer to 0x123456"),
+ convert("0X00123456"));
+ DoPointerTest(convert("%lp"), ptr, convert("pointer to 0x123456"),
+ convert("00123456"));
+ DoPointerTest(convert("%hp"), ptr, convert("pointer to 0x123456"),
+ convert("00003456"));
+ DoPointerTest(convert("%Lp"), ptr, convert("pointer to 0x123456"),
+ convert("00123456"));
+ DoI64DoubleTest(convert("%I64p"), lptr,
+ convert("pointer to 0x1234567887654321"), convert("1234567887654321"));
+
+#endif
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/vswprintf/test4/testinfo.dat b/src/pal/tests/palsuite/c_runtime/vswprintf/test4/testinfo.dat
new file mode 100644
index 0000000000..435f9703cd
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vswprintf/test4/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = vswprintf
+Name = Positive Test for vswprintf
+TYPE = DEFAULT
+EXE1 = test4
+Description
+= Tests the PAL implementation of the vswprintf function.
+= Tests vswprintf with pointers.
+= This test is modeled after _snwprintf.
diff --git a/src/pal/tests/palsuite/c_runtime/vswprintf/test5/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/vswprintf/test5/CMakeLists.txt
new file mode 100644
index 0000000000..7c480455ed
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vswprintf/test5/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test5.c
+)
+
+add_executable(paltest_vswprintf_test5
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vswprintf_test5 coreclrpal)
+
+target_link_libraries(paltest_vswprintf_test5
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/vswprintf/test5/test5.c b/src/pal/tests/palsuite/c_runtime/vswprintf/test5/test5.c
new file mode 100644
index 0000000000..42146c8be7
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vswprintf/test5/test5.c
@@ -0,0 +1,79 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test5.c
+**
+** Purpose: Test #5 for the vswprintf function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+#include "../vswprintf.h"
+
+/* memcmp is used to verify the results, so this test is dependent on it. */
+/* ditto with wcslen */
+
+static void DoTest(WCHAR *formatstr, int param, WCHAR *checkstr)
+{
+ WCHAR buf[256] = { 0 };
+ int n = -1;
+
+ testvswp(buf, formatstr, &n);
+
+ if (n != param)
+ {
+ Fail("ERROR: Expected count parameter to resolve to %d, got %d\n",
+ param, n);
+ }
+
+ if (memcmp(buf, checkstr, wcslen(buf)*2 + 2) != 0)
+ {
+ Fail("ERROR: Expected \"%s\" got \"%s\".\n",
+ convertC(checkstr), convertC(buf));
+ }
+}
+
+static void DoShortTest(WCHAR *formatstr, int param, WCHAR *checkstr)
+{
+ WCHAR buf[256] = { 0 };
+ short int n = -1;
+
+ testvswp(buf, formatstr, &n);
+
+ if (n != param)
+ {
+ Fail("ERROR: Expected count parameter to resolve to %d, got %d\n",
+ param, n);
+ }
+
+ if (memcmp(buf, checkstr, wcslen(buf)*2 + 2) != 0)
+ {
+ Fail("ERROR: Expected \"%s\" got \"%s\".\n",
+ convertC(checkstr), convertC(buf));
+ }
+}
+
+int __cdecl main(int argc, char *argv[])
+{
+ if (PAL_Initialize(argc, argv) != 0)
+ return(FAIL);
+
+ DoTest(convert("foo %n bar"), 4, convert("foo bar"));
+ DoTest(convert("foo %#n bar"), 4, convert("foo bar"));
+ DoTest(convert("foo % n bar"), 4, convert("foo bar"));
+ DoTest(convert("foo %+n bar"), 4, convert("foo bar"));
+ DoTest(convert("foo %-n bar"), 4, convert("foo bar"));
+ DoTest(convert("foo %0n bar"), 4, convert("foo bar"));
+ DoShortTest(convert("foo %hn bar"), 4, convert("foo bar"));
+ DoTest(convert("foo %ln bar"), 4, convert("foo bar"));
+ DoTest(convert("foo %Ln bar"), 4, convert("foo bar"));
+ DoTest(convert("foo %I64n bar"), 4, convert("foo bar"));
+ DoTest(convert("foo %20.3n bar"), 4, convert("foo bar"));
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/vswprintf/test5/testinfo.dat b/src/pal/tests/palsuite/c_runtime/vswprintf/test5/testinfo.dat
new file mode 100644
index 0000000000..17ca0fd33b
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vswprintf/test5/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = vswprintf
+Name = Positive Test for vswprintf
+TYPE = DEFAULT
+EXE1 = test5
+Description
+= Tests the PAL implementation of the vswprintf function.
+= Tests vswprintf with the count specifier.
+= This test is modeled after _snwprintf.
diff --git a/src/pal/tests/palsuite/c_runtime/vswprintf/test6/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/vswprintf/test6/CMakeLists.txt
new file mode 100644
index 0000000000..d7de580853
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vswprintf/test6/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test6.c
+)
+
+add_executable(paltest_vswprintf_test6
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vswprintf_test6 coreclrpal)
+
+target_link_libraries(paltest_vswprintf_test6
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/vswprintf/test6/test6.c b/src/pal/tests/palsuite/c_runtime/vswprintf/test6/test6.c
new file mode 100644
index 0000000000..51e99267a1
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vswprintf/test6/test6.c
@@ -0,0 +1,41 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test6.c
+**
+** Purpose: Test #6 for the vswprintf function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+#include "../vswprintf.h"
+
+/* memcmp is used to verify the results, so this test is dependent on it. */
+/* ditto with wcslen */
+
+int __cdecl main(int argc, char *argv[])
+{
+ WCHAR wc = (WCHAR) 'c';
+
+ if (PAL_Initialize(argc, argv) != 0)
+ return(FAIL);
+
+ DoWCharTest(convert("foo %c"), wc, convert("foo c"));
+ DoCharTest(convert("foo %hc"), 'b', convert("foo b"));
+ DoWCharTest(convert("foo %lc"), wc, convert("foo c"));
+ DoWCharTest(convert("foo %Lc"), wc, convert("foo c"));
+ DoWCharTest(convert("foo %I64c"), wc, convert("foo c"));
+ DoWCharTest(convert("foo %5c"), wc, convert("foo c"));
+ DoWCharTest(convert("foo %.0c"), wc, convert("foo c"));
+ DoWCharTest(convert("foo %-5c"), wc, convert("foo c "));
+ DoWCharTest(convert("foo %05c"), wc, convert("foo 0000c"));
+ DoWCharTest(convert("foo % c"), wc, convert("foo c"));
+ DoWCharTest(convert("foo %#c"), wc, convert("foo c"));
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/vswprintf/test6/testinfo.dat b/src/pal/tests/palsuite/c_runtime/vswprintf/test6/testinfo.dat
new file mode 100644
index 0000000000..f4ad2e954e
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vswprintf/test6/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = vswprintf
+Name = Positive Test for vswprintf
+TYPE = DEFAULT
+EXE1 = test6
+Description
+= Tests the PAL implementation of the vswprintf function.
+= Tests vswprintf with characters.
+= This test is modeled after _snwprintf.
diff --git a/src/pal/tests/palsuite/c_runtime/vswprintf/test7/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/vswprintf/test7/CMakeLists.txt
new file mode 100644
index 0000000000..eb07ee2cae
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vswprintf/test7/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test7.c
+)
+
+add_executable(paltest_vswprintf_test7
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vswprintf_test7 coreclrpal)
+
+target_link_libraries(paltest_vswprintf_test7
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/vswprintf/test7/test7.c b/src/pal/tests/palsuite/c_runtime/vswprintf/test7/test7.c
new file mode 100644
index 0000000000..6037cb0fe7
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vswprintf/test7/test7.c
@@ -0,0 +1,41 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test7.c
+**
+** Purpose: Test #7 for the vswprintf function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+#include "../vswprintf.h"
+
+/* memcmp is used to verify the results, so this test is dependent on it. */
+/* ditto with wcslen */
+
+int __cdecl main(int argc, char *argv[])
+{
+ WCHAR wc = (WCHAR) 'c';
+
+ if (PAL_Initialize(argc, argv) != 0)
+ return(FAIL);
+
+ DoCharTest(convert("foo %C"), 'b', convert("foo b"));
+ DoWCharTest(convert("foo %hC"), wc, convert("foo c"));
+ DoCharTest(convert("foo %lC"), 'b', convert("foo b"));
+ DoCharTest(convert("foo %LC"), 'b', convert("foo b"));
+ DoCharTest(convert("foo %I64C"), 'b', convert("foo b"));
+ DoCharTest(convert("foo %5C"), 'b', convert("foo b"));
+ DoCharTest(convert("foo %.0C"), 'b', convert("foo b"));
+ DoCharTest(convert("foo %-5C"), 'b', convert("foo b "));
+ DoCharTest(convert("foo %05C"), 'b', convert("foo 0000b"));
+ DoCharTest(convert("foo % C"), 'b', convert("foo b"));
+ DoCharTest(convert("foo %#C"), 'b', convert("foo b"));
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/vswprintf/test7/testinfo.dat b/src/pal/tests/palsuite/c_runtime/vswprintf/test7/testinfo.dat
new file mode 100644
index 0000000000..ed0a474f7e
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vswprintf/test7/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = vswprintf
+Name = Positive Test for vswprintf
+TYPE = DEFAULT
+EXE1 = test7
+Description
+= Tests the PAL implementation of the vswprintf function.
+= Tests vswprintf with wide characters.
+= This test is modeled after _snwprintf.
diff --git a/src/pal/tests/palsuite/c_runtime/vswprintf/test8/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/vswprintf/test8/CMakeLists.txt
new file mode 100644
index 0000000000..ed35ea8dd0
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vswprintf/test8/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test8.c
+)
+
+add_executable(paltest_vswprintf_test8
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vswprintf_test8 coreclrpal)
+
+target_link_libraries(paltest_vswprintf_test8
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/vswprintf/test8/test8.c b/src/pal/tests/palsuite/c_runtime/vswprintf/test8/test8.c
new file mode 100644
index 0000000000..baba524650
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vswprintf/test8/test8.c
@@ -0,0 +1,47 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test8.c
+**
+** Purpose: Test #8 for the vswprintf function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+#include "../vswprintf.h"
+
+/* memcmp is used to verify the results, so this test is dependent on it. */
+/* ditto with wcslen */
+
+int __cdecl main(int argc, char *argv[])
+{
+ int neg = -42;
+ int pos = 42;
+ INT64 l = 42;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ return(FAIL);
+
+ DoNumTest(convert("foo %d"), pos, convert("foo 42"));
+ DoNumTest(convert("foo %ld"), 0xFFFF, convert("foo 65535"));
+ DoNumTest(convert("foo %hd"), 0xFFFF, convert("foo -1"));
+ DoNumTest(convert("foo %Ld"), pos, convert("foo 42"));
+ DoI64NumTest(convert("foo %I64d"), l, "42", convert("foo 42"));
+ DoNumTest(convert("foo %3d"), pos, convert("foo 42"));
+ DoNumTest(convert("foo %-3d"), pos, convert("foo 42 "));
+ DoNumTest(convert("foo %.1d"), pos, convert("foo 42"));
+ DoNumTest(convert("foo %.3d"), pos, convert("foo 042"));
+ DoNumTest(convert("foo %03d"), pos, convert("foo 042"));
+ DoNumTest(convert("foo %#d"), pos, convert("foo 42"));
+ DoNumTest(convert("foo %+d"), pos, convert("foo +42"));
+ DoNumTest(convert("foo % d"), pos, convert("foo 42"));
+ DoNumTest(convert("foo %+d"), neg, convert("foo -42"));
+ DoNumTest(convert("foo % d"), neg, convert("foo -42"));
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/vswprintf/test8/testinfo.dat b/src/pal/tests/palsuite/c_runtime/vswprintf/test8/testinfo.dat
new file mode 100644
index 0000000000..4c5114bd27
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vswprintf/test8/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = vswprintf
+Name = Positive Test for vswprintf
+TYPE = DEFAULT
+EXE1 = test8
+Description
+= Tests the PAL implementation of the vswprintf function.
+= Tests vswprintf with decimal numbers.
+= This test is modeled after _snwprintf.
diff --git a/src/pal/tests/palsuite/c_runtime/vswprintf/test9/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/vswprintf/test9/CMakeLists.txt
new file mode 100644
index 0000000000..7098da31d0
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vswprintf/test9/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test9.c
+)
+
+add_executable(paltest_vswprintf_test9
+ ${SOURCES}
+)
+
+add_dependencies(paltest_vswprintf_test9 coreclrpal)
+
+target_link_libraries(paltest_vswprintf_test9
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/vswprintf/test9/test9.c b/src/pal/tests/palsuite/c_runtime/vswprintf/test9/test9.c
new file mode 100644
index 0000000000..5de004f5ed
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vswprintf/test9/test9.c
@@ -0,0 +1,47 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test9.c
+**
+** Purpose: Test #9 for the vswprintf function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+#include "../vswprintf.h"
+
+/* memcmp is used to verify the results, so this test is dependent on it. */
+/* ditto with wcslen */
+
+int __cdecl main(int argc, char *argv[])
+{
+ int neg = -42;
+ int pos = 42;
+ INT64 l = 42;
+
+ if (PAL_Initialize(argc, argv) != 0)
+ return(FAIL);
+
+ DoNumTest(convert("foo %i"), pos, convert("foo 42"));
+ DoNumTest(convert("foo %li"), 0xFFFF, convert("foo 65535"));
+ DoNumTest(convert("foo %hi"), 0xFFFF, convert("foo -1"));
+ DoNumTest(convert("foo %Li"), pos, convert("foo 42"));
+ DoI64NumTest(convert("foo %I64i"), l, "42", convert("foo 42"));
+ DoNumTest(convert("foo %3i"), pos, convert("foo 42"));
+ DoNumTest(convert("foo %-3i"), pos, convert("foo 42 "));
+ DoNumTest(convert("foo %.1i"), pos, convert("foo 42"));
+ DoNumTest(convert("foo %.3i"), pos, convert("foo 042"));
+ DoNumTest(convert("foo %03i"), pos, convert("foo 042"));
+ DoNumTest(convert("foo %#i"), pos, convert("foo 42"));
+ DoNumTest(convert("foo %+i"), pos, convert("foo +42"));
+ DoNumTest(convert("foo % i"), pos, convert("foo 42"));
+ DoNumTest(convert("foo %+i"), neg, convert("foo -42"));
+ DoNumTest(convert("foo % i"), neg, convert("foo -42"));
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/vswprintf/test9/testinfo.dat b/src/pal/tests/palsuite/c_runtime/vswprintf/test9/testinfo.dat
new file mode 100644
index 0000000000..3c2bcdf3e5
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vswprintf/test9/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = vswprintf
+Name = Positive Test for vswprintf
+TYPE = DEFAULT
+EXE1 = test9
+Description
+= Tests the PAL implementation of the vswprintf function.
+= Tests vswprintf with integer numbers
+= This test is modeled after _snwprintf.
diff --git a/src/pal/tests/palsuite/c_runtime/vswprintf/vswprintf.h b/src/pal/tests/palsuite/c_runtime/vswprintf/vswprintf.h
new file mode 100644
index 0000000000..a79c9bb7a9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/vswprintf/vswprintf.h
@@ -0,0 +1,132 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: vswprintf.h
+**
+** Purpose: Containts common testing functions for vswprintf
+**
+**
+**==========================================================================*/
+
+#ifndef __vswprintf_H__
+#define __vswprintf_H__
+
+/* These functions leaks memory like crazy. C'est la vie. */
+int testvswp(wchar_t* buf, const wchar_t* format, ...)
+{
+ int retVal = 0;
+ va_list arglist;
+
+ va_start(arglist, format);
+ retVal = vswprintf(buf, format, arglist);
+ va_end(arglist);
+
+ return( retVal);
+}
+
+void DoWStrTest(WCHAR *formatstr, WCHAR *param, WCHAR *checkstr)
+{
+ WCHAR buf[256] = { 0 };
+
+ testvswp(buf, formatstr, param);
+
+ if (memcmp(buf, checkstr, wcslen(buf) * 2 + 2) != 0)
+ {
+ Fail("ERROR: failed to insert wide string \"%s\" into \"%s\".\n"
+ "Expected \"%s\", got \"%s\".\n",
+ convertC(param), convertC(formatstr),
+ convertC(checkstr), convertC(buf));
+ }
+}
+
+void DoStrTest(WCHAR *formatstr, char *param, WCHAR *checkstr)
+{
+ WCHAR buf[256] = { 0 };
+
+ testvswp(buf, formatstr, param);
+
+ if (memcmp(buf, checkstr, wcslen(buf) * 2 + 2) != 0)
+ {
+ Fail("ERROR: failed to insert wide string \"%s\" into \"%s\".\n"
+ "Expected \"%s\", got \"%s\".\n",
+ param, convertC(formatstr), convertC(checkstr),
+ convertC(buf));
+ }
+}
+
+void DoCharTest(WCHAR *formatstr, char param, WCHAR *checkstr)
+{
+ WCHAR buf[256] = { 0 };
+
+ testvswp(buf, formatstr, param);
+ if (memcmp(buf, checkstr, wcslen(buf)*2 + 2) != 0)
+ {
+ Fail("ERROR: failed to insert char \'%c\' (%d) into \"%s\"\n"
+ "Expected \"%s\" got \"%s\".\n",
+ param, param, convertC(formatstr), convertC(checkstr),
+ convertC(buf));
+ }
+}
+
+void DoWCharTest(WCHAR *formatstr, WCHAR param, WCHAR *checkstr)
+{
+ WCHAR buf[256] = { 0 };
+
+ testvswp(buf, formatstr, param);
+ if (memcmp(buf, checkstr, wcslen(buf)*2 + 2) != 0)
+ {
+ Fail("ERROR: failed to insert wide char \'%c\' (%d) into \"%s\"\n"
+ "Expected \"%s\" got \"%s\".\n",
+ (char) param, param, convertC(formatstr), convertC(checkstr),
+ convertC(buf));
+ }
+}
+
+void DoNumTest(WCHAR *formatstr, int value, WCHAR*checkstr)
+{
+ WCHAR buf[256] = { 0 };
+
+ testvswp(buf, formatstr, value);
+ if (memcmp(buf, checkstr, wcslen(buf)* 2 + 2) != 0)
+ {
+ Fail("ERROR: failed to insert %#x into \"%s\"\n"
+ "Expected \"%s\" got \"%s\".\n", value, convertC(formatstr),
+ convertC(checkstr), convertC(buf));
+ }
+}
+
+void DoI64NumTest(WCHAR *formatstr, INT64 value, char *valuestr, WCHAR*checkstr)
+{
+ WCHAR buf[256] = { 0 };
+
+ testvswp(buf, formatstr, value);
+ if (memcmp(buf, checkstr, wcslen(buf)* 2 + 2) != 0)
+ {
+ Fail("ERROR: failed to insert %s into \"%s\"\n"
+ "Expected \"%s\" got \"%s\".\n", valuestr, convertC(formatstr),
+ convertC(checkstr), convertC(buf));
+ }
+}
+void DoDoubleTest(WCHAR *formatstr, double value, WCHAR *checkstr1, WCHAR
+ *checkstr2)
+{
+ WCHAR buf[256] = { 0 };
+
+ testvswp(buf, formatstr, value);
+ if (memcmp(buf, checkstr1, wcslen(checkstr1) + 2) != 0 &&
+ memcmp(buf, checkstr2, wcslen(checkstr2) + 2) != 0)
+ {
+ Fail("ERROR: failed to insert %f into \"%s\"\n"
+ "Expected \"%s\" or \"%s\", got \"%s\".\n",
+ value,
+ convertC(formatstr),
+ convertC(checkstr1),
+ convertC(checkstr2),
+ convertC(buf));
+ }
+}
+
+#endif
diff --git a/src/pal/tests/palsuite/c_runtime/wcscat/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/wcscat/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcscat/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/wcscat/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/wcscat/test1/CMakeLists.txt
new file mode 100644
index 0000000000..34dfee01bd
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcscat/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_wcscat_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_wcscat_test1 coreclrpal)
+
+target_link_libraries(paltest_wcscat_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/wcscat/test1/test1.c b/src/pal/tests/palsuite/c_runtime/wcscat/test1/test1.c
new file mode 100644
index 0000000000..789eebf5a3
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcscat/test1/test1.c
@@ -0,0 +1,71 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose:
+** Test to that wcscat correctly concatanates wide strings, including placing
+** null pointers.
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+
+/*
+ * Notes: uses memcmp and the (pal) sprintf
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ WCHAR dest[80];
+ WCHAR test[] = {'f','o','o',' ','b','a','r',' ','b','a','z',0};
+ WCHAR str1[] = {'f','o','o',' ',0};
+ WCHAR str2[] = {'b','a','r',' ',0};
+ WCHAR str3[] = {'b','a','z',0};
+ WCHAR *ptr;
+ char buffer[256];
+
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ dest[0] = 0;
+
+ ptr = wcscat(dest, str1);
+ if (ptr != dest)
+ {
+ Fail("ERROR: Expected wcscat to return ptr to %p, got %p", dest, ptr);
+ }
+
+ ptr = wcscat(dest, str2);
+ if (ptr != dest)
+ {
+ Fail("ERROR: Expected wcscat to return ptr to %p, got %p", dest, ptr);
+ }
+
+ ptr = wcscat(dest, str3);
+ if (ptr != dest)
+ {
+ Fail("ERROR: Expected wcscat to return ptr to %p, got %p", dest, ptr);
+ }
+
+ if (memcmp(dest, test, sizeof(test)) != 0)
+ {
+ sprintf(buffer, "%S", dest);
+ Fail("ERROR: Expected wcscat to give \"%s\", got \"%s\"\n",
+ "foo bar baz", buffer);
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/wcscat/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/wcscat/test1/testinfo.dat
new file mode 100644
index 0000000000..878c446251
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcscat/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = wcscat
+Name = Positive Test for wcscat
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Test to that wcscat correctly concatanates wide strings, including placing
+= null pointers
diff --git a/src/pal/tests/palsuite/c_runtime/wcschr/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/wcschr/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcschr/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/wcschr/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/wcschr/test1/CMakeLists.txt
new file mode 100644
index 0000000000..542d70b7e6
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcschr/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_wcschr_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_wcschr_test1 coreclrpal)
+
+target_link_libraries(paltest_wcschr_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/wcschr/test1/test1.c b/src/pal/tests/palsuite/c_runtime/wcschr/test1/test1.c
new file mode 100644
index 0000000000..a4963672f8
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcschr/test1/test1.c
@@ -0,0 +1,51 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose:
+** Tests that wcschr correctly finds the first occurrence of a character in a
+** string
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ WCHAR str[] = {'f','o','o',' ','b','a','r',' ',0};
+ WCHAR c = (WCHAR)' ';
+ WCHAR c2 = (WCHAR)'$';
+ WCHAR *ptr;
+
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ ptr = wcschr(str, c);
+ if (ptr != str + 3)
+ {
+ Fail("ERROR: expected wcschr to return pointer to %p, got %p\n",
+ str + 3, ptr);
+ }
+
+ ptr = wcschr(str, c2);
+ if (ptr != NULL)
+ {
+ Fail("ERROR: expected wcschr to return pointer to %p, got %p\n",
+ NULL, ptr);
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/wcschr/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/wcschr/test1/testinfo.dat
new file mode 100644
index 0000000000..40a166d615
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcschr/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = wcschr
+Name = Positive Test for wcschr
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Tests that wcschr correctly finds the first occurrence of a character in a
+= string.
diff --git a/src/pal/tests/palsuite/c_runtime/wcscmp/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/wcscmp/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcscmp/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/wcscmp/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/wcscmp/test1/CMakeLists.txt
new file mode 100644
index 0000000000..009e48e1ba
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcscmp/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_wcscmp_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_wcscmp_test1 coreclrpal)
+
+target_link_libraries(paltest_wcscmp_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/wcscmp/test1/test1.c b/src/pal/tests/palsuite/c_runtime/wcscmp/test1/test1.c
new file mode 100644
index 0000000000..1c38dd6d58
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcscmp/test1/test1.c
@@ -0,0 +1,57 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Tests that wcscmp correctly compares two strings with
+** case sensitivity.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ WCHAR str1[] = {'f','o','o',0};
+ WCHAR str2[] = {'f','o','o','x',0};
+ WCHAR str3[] = {'f','O','o',0};
+ char cstr1[] = "foo";
+ char cstr2[] = "foox";
+ char cstr3[] = "fOo";
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+
+ if (wcscmp(str1, str2) >= 0)
+ {
+ Fail("ERROR: wcscmp(\"%s\", \"%s\") returned >= 0\n", cstr1, cstr2);
+ }
+
+ if (wcscmp(str2, str1) <= 0)
+ {
+ Fail("ERROR: wcscmp(\"%s\", \"%s\") returned <= 0\n", cstr2, cstr1);
+ }
+
+ if (wcscmp(str1, str3) <= 0)
+ {
+ Fail("ERROR: wcscmp(\"%s\", \"%s\") returned >= 0\n", cstr1, cstr3);
+ }
+
+ if (wcscmp(str3, str1) >= 0)
+ {
+ Fail("ERROR: wcscmp(\"%s\", \"%s\") returned >= 0\n", cstr3, cstr1);
+ }
+
+ PAL_Terminate();
+
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/wcscmp/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/wcscmp/test1/testinfo.dat
new file mode 100644
index 0000000000..0fe696fbe7
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcscmp/test1/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = wcscmp
+Name = Test #1 for wcscmp
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Tests that wcscmp correctly compares two strings with case sensitivity.
diff --git a/src/pal/tests/palsuite/c_runtime/wcscpy/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/wcscpy/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcscpy/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/wcscpy/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/wcscpy/test1/CMakeLists.txt
new file mode 100644
index 0000000000..5f21b829ee
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcscpy/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_wcscpy_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_wcscpy_test1 coreclrpal)
+
+target_link_libraries(paltest_wcscpy_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/wcscpy/test1/test1.c b/src/pal/tests/palsuite/c_runtime/wcscpy/test1/test1.c
new file mode 100644
index 0000000000..4e45c86516
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcscpy/test1/test1.c
@@ -0,0 +1,47 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Tests that wcscpy correctly copies a null-terminated wide string.
+**
+**
+**==========================================================================*/
+
+
+#include <palsuite.h>
+
+/*
+ * Notes: uses memcmp and sprintf.
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ WCHAR str[] = {'f','o','o',0,'b','a','r',0};
+ WCHAR dest[80];
+ WCHAR result[] = {'f','o','o',0};
+ WCHAR *ret;
+ char buffer[256];
+
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ ret = wcscpy(dest, str);
+
+ if (ret != dest || memcmp(dest, result, sizeof(result)) != 0)
+ {
+ sprintf(buffer, "%S", dest);
+ Fail("Expected wcscpy to give \"%s\" with a return value of %p, got \"%s\" "
+ "with a return value of %p.\n", "foo", dest, buffer, ret);
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/wcscpy/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/wcscpy/test1/testinfo.dat
new file mode 100644
index 0000000000..ef9c58ecc9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcscpy/test1/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = wcscpy
+Name = Positive Test for wcscpy
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Tests that wcscpy correctly copies a null-terminated wide string.
diff --git a/src/pal/tests/palsuite/c_runtime/wcslen/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/wcslen/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcslen/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/wcslen/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/wcslen/test1/CMakeLists.txt
new file mode 100644
index 0000000000..de0f1c22d3
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcslen/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_wcslen_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_wcslen_test1 coreclrpal)
+
+target_link_libraries(paltest_wcslen_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/wcslen/test1/test1.c b/src/pal/tests/palsuite/c_runtime/wcslen/test1/test1.c
new file mode 100644
index 0000000000..17d0327628
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcslen/test1/test1.c
@@ -0,0 +1,49 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose:
+** Tests that wcslen correctly returns the length (in wide characters,
+** not byte) of a wide string
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ WCHAR str1[] = {'f','o','o',' ',0};
+ WCHAR str2[] = {0};
+ int ret;
+
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ ret = wcslen(str1);
+ if (ret != 4)
+ {
+ Fail("ERROR: Expected wcslen of \"foo \" to be 4, got %d\n", ret);
+ }
+
+ ret = wcslen(str2);
+ if (ret != 0)
+ {
+ Fail("ERROR: Expected wcslen of \"\" to be 0, got %d\n", ret);
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/wcslen/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/wcslen/test1/testinfo.dat
new file mode 100644
index 0000000000..cfdef4819d
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcslen/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = wcslen
+Name = Positive Test for wcslen
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Tests that wcslen correctly returns the length (in wide characters, not byte)
+= of a wide string
diff --git a/src/pal/tests/palsuite/c_runtime/wcsncat/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/wcsncat/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcsncat/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/wcsncat/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/wcsncat/test1/CMakeLists.txt
new file mode 100644
index 0000000000..12c286a43a
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcsncat/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_wcsncat_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_wcsncat_test1 coreclrpal)
+
+target_link_libraries(paltest_wcsncat_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/wcsncat/test1/test1.c b/src/pal/tests/palsuite/c_runtime/wcsncat/test1/test1.c
new file mode 100644
index 0000000000..0cd5c3e15a
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcsncat/test1/test1.c
@@ -0,0 +1,77 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose:
+** Tests that wcsncat correctly appends wide strings, making sure it handles
+** count argument correctly (appending no more than count characters, always
+** placing a null, and padding the string if necessary).
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ WCHAR dest[80];
+ WCHAR test[] = {'f','o','o',' ','b','a','r','b','a','z',0};
+ WCHAR str1[] = {'f','o','o',' ',0};
+ WCHAR str2[] = {'b','a','r',' ',0};
+ WCHAR str3[] = {'b','a','z',0};
+ WCHAR *ptr;
+ int i;
+
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ dest[0] = 0;
+ for (i=1; i<80; i++)
+ {
+ dest[i] = (WCHAR)'x';
+ }
+
+ ptr = wcsncat(dest, str1, wcslen(str1));
+ if (ptr != dest)
+ {
+ Fail("ERROR: Expected wcsncat to return ptr to %p, got %p", dest, ptr);
+ }
+
+ ptr = wcsncat(dest, str2, 3);
+ if (ptr != dest)
+ {
+ Fail("ERROR: Expected wcsncat to return ptr to %p, got %p", dest, ptr);
+ }
+ if (dest[7] != 0)
+ {
+ Fail("ERROR: wcsncat did not place a terminating NULL!");
+ }
+
+ ptr = wcsncat(dest, str3, 20);
+ if (ptr != dest)
+ {
+ Fail("ERROR: Expected wcsncat to return ptr to %p, got %p", dest, ptr);
+ }
+ if (wcscmp(dest, test) != 0)
+ {
+ Fail("ERROR: Expected wcsncat to give \"%S\", got \"%S\"\n",
+ test, dest);
+ }
+ if (dest[wcslen(test)+1] != (WCHAR)'x')
+ {
+ Fail("wcsncat went out of bounds!\n");
+ }
+
+ PAL_Terminate();
+
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/wcsncat/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/wcsncat/test1/testinfo.dat
new file mode 100644
index 0000000000..39077a237d
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcsncat/test1/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = wcsncat
+Name = Test #1 for wcsncat
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Tests that wcsncat correctly appends wide strings, making sure it handles
+= count argument correctly (appending no more than count characters, always
+= placing a null, and padding the string if necessary).
diff --git a/src/pal/tests/palsuite/c_runtime/wcsncmp/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/wcsncmp/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcsncmp/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/wcsncmp/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/wcsncmp/test1/CMakeLists.txt
new file mode 100644
index 0000000000..56c9b25806
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcsncmp/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_wcsncmp_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_wcsncmp_test1 coreclrpal)
+
+target_link_libraries(paltest_wcsncmp_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/wcsncmp/test1/test1.c b/src/pal/tests/palsuite/c_runtime/wcsncmp/test1/test1.c
new file mode 100644
index 0000000000..4e4488f5a1
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcsncmp/test1/test1.c
@@ -0,0 +1,73 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose:
+** Tests that wcsncmp case-sensitively compares wide strings, making sure that
+** the count argument is handled correctly.
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+
+/*
+ * Notes: uses wcslen.
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ WCHAR str1[] = {'f','o','o',0};
+ WCHAR str2[] = {'f','o','o','x',0};
+ WCHAR str3[] = {'f','O','o',0};
+ char cstr1[] = "foo";
+ char cstr2[] = "foox";
+ char cstr3[] = "fOo";
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+
+ if (wcsncmp(str1, str2, wcslen(str2)) >= 0)
+ {
+ Fail("ERROR: wcsncmp(\"%s\", \"%s\", %d) returned >= 0\n", cstr1,
+ cstr2, wcslen(str2));
+ }
+
+ if (wcsncmp(str2, str1, wcslen(str2)) <= 0)
+ {
+ Fail("ERROR: wcsncmp(\"%s\", \"%s\", %d) returned <= 0\n", cstr2,
+ cstr1, wcslen(str2));
+ }
+
+ if (wcsncmp(str1, str2, wcslen(str1)) != 0)
+ {
+ Fail("ERROR: wcsncmp(\"%s\", \"%s\", %d) returned != 0\n", cstr1,
+ cstr2, wcslen(str1));
+ }
+
+ if (wcsncmp(str1, str3, wcslen(str1)) <= 0)
+ {
+ Fail("ERROR: wcsncmp(\"%s\", \"%s\", %d) returned >= 0\n", cstr1,
+ cstr3, wcslen(str1));
+ }
+
+ if (wcsncmp(str3, str1, wcslen(str1)) >= 0)
+ {
+ Fail("ERROR: wcsncmp(\"%s\", \"%s\", %d) returned >= 0\n", cstr3,
+ cstr1, wcslen(str1));
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/wcsncmp/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/wcsncmp/test1/testinfo.dat
new file mode 100644
index 0000000000..1f8b508748
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcsncmp/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = wcsncmp
+Name = Positive Test for wcsncmp
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Tests that wcsncmp case-sensitively compares wide strings, making sure that
+= the count argument is handled correctly.
diff --git a/src/pal/tests/palsuite/c_runtime/wcsncpy/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/wcsncpy/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcsncpy/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/wcsncpy/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/wcsncpy/test1/CMakeLists.txt
new file mode 100644
index 0000000000..1c1d70ba04
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcsncpy/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_wcsncpy_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_wcsncpy_test1 coreclrpal)
+
+target_link_libraries(paltest_wcsncpy_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/wcsncpy/test1/test1.c b/src/pal/tests/palsuite/c_runtime/wcsncpy/test1/test1.c
new file mode 100644
index 0000000000..50d97b0e9c
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcsncpy/test1/test1.c
@@ -0,0 +1,84 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose:
+** Tests to see that wcsncpy correctly copies wide strings, including handling
+** the count argument correctly (copying no more that count characters, not
+** automatically adding a null, and padding if necessary).
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ WCHAR dest[80];
+ WCHAR result[] = {'f','o','o','b','a','r',0};
+ WCHAR str[] = {'f','o','o','b','a','r',0,'b','a','z',0};
+ WCHAR *ret;
+ int i;
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ for (i=0; i<80; i++)
+ {
+ dest[i] = 'x';
+ }
+
+ ret = wcsncpy(dest, str, 3);
+ if (ret != dest)
+ {
+ Fail("Expected wcsncpy to return %p, got %p!\n", dest, ret);
+ }
+
+ if (wcsncmp(dest, result, 3) != 0)
+ {
+ Fail("Expected wcsncpy to give \"%S\", got \"%S\"!\n", result, dest);
+ }
+
+ if (dest[3] != (WCHAR)'x')
+ {
+ Fail("wcsncpy overflowed!\n");
+ }
+
+ ret = wcsncpy(dest, str, 40);
+ if (ret != dest)
+ {
+ Fail("Expected wcsncpy to return %p, got %p!\n", dest, ret);
+ }
+
+ if (wcscmp(dest, result) != 0)
+ {
+ Fail("Expected wcsncpy to give \"%S\", got \"%S\"!\n", result, dest);
+ }
+
+ for (i=wcslen(str); i<40; i++)
+ {
+ if (dest[i] != 0)
+ {
+ Fail("wcsncpy failed to pad the destination with NULLs!\n");
+ }
+ }
+
+ if (dest[40] != (WCHAR)'x')
+ {
+ Fail("wcsncpy overflowed!\n");
+ }
+
+
+
+ PAL_Terminate();
+
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/wcsncpy/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/wcsncpy/test1/testinfo.dat
new file mode 100644
index 0000000000..b8b0ddb3f7
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcsncpy/test1/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = wcsncpy
+Name = Test #1 for wcsncpy
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Tests to see that wcsncpy correctly copies wide strings, including handling
+= the count argument correctly (copying no more that count characters, not
+= automatically adding a null, and padding if necessary).
+
diff --git a/src/pal/tests/palsuite/c_runtime/wcspbrk/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/wcspbrk/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcspbrk/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/wcspbrk/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/wcspbrk/test1/CMakeLists.txt
new file mode 100644
index 0000000000..c6a3f87d75
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcspbrk/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_wcspbrk_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_wcspbrk_test1 coreclrpal)
+
+target_link_libraries(paltest_wcspbrk_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/wcspbrk/test1/test1.c b/src/pal/tests/palsuite/c_runtime/wcspbrk/test1/test1.c
new file mode 100644
index 0000000000..b0432f7819
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcspbrk/test1/test1.c
@@ -0,0 +1,61 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose:
+** Tests that wcspbrk returns a pointer to the first element in the first
+** string that matches a character in the second (or NULL).
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ WCHAR *string;
+ WCHAR *key1;
+ WCHAR *key2;
+ WCHAR key3[] = {0};
+ WCHAR *result;
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ string = convert("foo bar baz bar");
+ key1 = convert("z ");
+ key2 = convert("Q");
+
+ result = wcspbrk(string, key1);
+ if (result != string + 3)
+ {
+ Fail("ERROR: Got incorrect result in scanning \"%s\" with the set \"%s\".\n"
+ "Expected to get pointer to %#p, got %#p\n", convertC(string),
+ convertC(key1), string + 3, result);
+ }
+
+ result = wcspbrk(string, key2);
+ if (result != NULL)
+ {
+ Fail("ERROR: Got incorrect result in scanning \"%s\" with the set \"%s\".\n"
+ "Expected to get pointer to %#p, got %#p\n", convertC(string),
+ convertC(key2), NULL, result);
+ }
+
+ result = wcspbrk(string, key3);
+ if (result != NULL)
+ {
+ Fail("ERROR: Got incorrect result in scanning \"%s\" with the set \"%s\".\n"
+ "Expected to get pointer to %#p, got %#p\n", convertC(string),
+ convertC(key3), NULL, result);
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/wcspbrk/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/wcspbrk/test1/testinfo.dat
new file mode 100644
index 0000000000..7044197b77
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcspbrk/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = wcspbrk
+Name = Positive Test for wcspbrk
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Tests that wcspbrk returns a pointer to the first element in the first
+= string that matches a character in the second (or NULL).
diff --git a/src/pal/tests/palsuite/c_runtime/wcsrchr/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/wcsrchr/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcsrchr/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/wcsrchr/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/wcsrchr/test1/CMakeLists.txt
new file mode 100644
index 0000000000..80513af1af
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcsrchr/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_wcsrchr_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_wcsrchr_test1 coreclrpal)
+
+target_link_libraries(paltest_wcsrchr_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/wcsrchr/test1/test1.c b/src/pal/tests/palsuite/c_runtime/wcsrchr/test1/test1.c
new file mode 100644
index 0000000000..ae8765776e
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcsrchr/test1/test1.c
@@ -0,0 +1,50 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose:
+** Tests to see that wcsrchr correctly returns a pointer to the last occurence
+** of a character in a a string.
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ WCHAR str[] = {'f','o','o',' ','b','a','r',' ','b','a','z',0};
+ WCHAR c = (WCHAR)' ';
+ WCHAR c2 = (WCHAR)'$';
+ WCHAR *ptr;
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ ptr = wcsrchr(str, c);
+ if (ptr != str + 7)
+ {
+ Fail("ERROR: expected wcsrchr to return pointer to %p, got %p\n",
+ str + 7, ptr);
+ }
+
+ ptr = wcsrchr(str, c2);
+ if (ptr != NULL)
+ {
+ Fail("ERROR: expected wcsrchr to return pointer to %p, got %p\n",
+ NULL, ptr);
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/wcsrchr/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/wcsrchr/test1/testinfo.dat
new file mode 100644
index 0000000000..984df9a3f3
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcsrchr/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = wcsrchr
+Name = Positive Test for wcsrchr
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Tests to see that wcsrchr correctly returns a pointer to the last occurence
+= of a character in a a string.
diff --git a/src/pal/tests/palsuite/c_runtime/wcsstr/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/wcsstr/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcsstr/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/wcsstr/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/wcsstr/test1/CMakeLists.txt
new file mode 100644
index 0000000000..e42619344d
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcsstr/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_wcsstr_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_wcsstr_test1 coreclrpal)
+
+target_link_libraries(paltest_wcsstr_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/wcsstr/test1/test1.c b/src/pal/tests/palsuite/c_runtime/wcsstr/test1/test1.c
new file mode 100644
index 0000000000..8296a74983
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcsstr/test1/test1.c
@@ -0,0 +1,62 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose:
+** Tests that wcsstr correctly find substrings in wide stings, including
+** returning NULL when the substring can't be found.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ WCHAR *string;
+ WCHAR *key1;
+ WCHAR *key2;
+ WCHAR key3[] = { 0 };
+ WCHAR *result;
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ string = convert("foo bar baz bar");
+ key1 = convert("bar");
+ key2 = convert("Bar");
+
+ result = wcsstr(string, key1);
+ if (result != string + 4)
+ {
+ Fail("ERROR: Got incorrect result in scanning \"%s\" for \"%s\".\n"
+ "Expected to get pointer to %#p, got %#p\n", convertC(string),
+ convertC(key1), string + 4, result);
+ }
+
+
+ result = wcsstr(string, key2);
+ if (result != NULL)
+ {
+ Fail("ERROR: Got incorrect result in scanning \"%s\" for \"%s\".\n"
+ "Expected to get pointer to %#p, got %#p\n", convertC(string),
+ convertC(key2), NULL, result);
+ }
+
+ result = wcsstr(string, key3);
+ if (result != string)
+ {
+ Fail("ERROR: Got incorrect result in scanning \"%s\" for \"%s\".\n"
+ "Expected to get pointer to %#p, got %#p\n", convertC(string),
+ convertC(key3), string, result);
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/wcsstr/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/wcsstr/test1/testinfo.dat
new file mode 100644
index 0000000000..e42fd8c9eb
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcsstr/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = wcsstr
+Name = Positive Test for wcsstr
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Tests that wcsstr correctly find substrings in wide stings, including
+= returning NULL when the substring can't be found.
diff --git a/src/pal/tests/palsuite/c_runtime/wcstod/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/wcstod/CMakeLists.txt
new file mode 100644
index 0000000000..ef14ea5352
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcstod/CMakeLists.txt
@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+
diff --git a/src/pal/tests/palsuite/c_runtime/wcstod/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/wcstod/test1/CMakeLists.txt
new file mode 100644
index 0000000000..cf585d051a
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcstod/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_wcstod_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_wcstod_test1 coreclrpal)
+
+target_link_libraries(paltest_wcstod_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/wcstod/test1/test1.c b/src/pal/tests/palsuite/c_runtime/wcstod/test1/test1.c
new file mode 100644
index 0000000000..e41e92e961
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcstod/test1/test1.c
@@ -0,0 +1,79 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test1.c
+**
+** Purpose: Tests wcstod with a number of sample strings.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+struct testCase
+{
+ double CorrectResult;
+ char string[20];
+ int stopChar;
+};
+
+struct testCase testCases[] =
+{
+ {1234,"1234", 4},
+ {-1234,"-1234", 5},
+ {1234.44,"1234.44", 7},
+ {1234e-5,"1234e-5", 7},
+ {1234e+5,"1234e+5", 7},
+ {1234E5,"1234E5", 6},
+ {1234.657e-8, "1234.657e-8", 11},
+ {0, "1e-800", 6},
+ {0, "-1e-800", 7},
+ {1234567e-8, " 1234567e-8 foo", 13},
+ {0, " foo 32 bar", 0},
+};
+
+int __cdecl main(int argc, char **argv)
+{
+ WCHAR *wideStr;
+ WCHAR *endptr;
+ double result;
+ int i;
+
+ if (PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ for(i = 0; i < sizeof(testCases) / sizeof(struct testCase); i++)
+ {
+ wideStr = convert(testCases[i].string);
+ result = wcstod(wideStr, &endptr);
+
+ if (testCases[i].CorrectResult != result)
+ {
+ free(wideStr);
+ Fail("ERROR: wcstod misinterpreted \"%s\" as %g instead of "
+ "%g.\n",
+ testCases[i].string,
+ result,
+ testCases[i].CorrectResult);
+ }
+
+ if (endptr != wideStr + testCases[i].stopChar)
+ {
+ free(wideStr);
+ Fail("ERROR: wcstod stopped scanning \"%s\" at %p, "
+ "instead of %p!\n", testCases[i].string, endptr,
+ wideStr + testCases[i].stopChar);
+ }
+
+ free(wideStr);
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/wcstod/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/wcstod/test1/testinfo.dat
new file mode 100644
index 0000000000..19da0b5a42
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcstod/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = wcstod
+Name = Positive Test for wcstod
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Tests wcstod with a number of sample strings.
+
diff --git a/src/pal/tests/palsuite/c_runtime/wcstod/test2/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/wcstod/test2/CMakeLists.txt
new file mode 100644
index 0000000000..43d5bf8a40
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcstod/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test2.c
+)
+
+add_executable(paltest_wcstod_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_wcstod_test2 coreclrpal)
+
+target_link_libraries(paltest_wcstod_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/wcstod/test2/test2.c b/src/pal/tests/palsuite/c_runtime/wcstod/test2/test2.c
new file mode 100644
index 0000000000..8f9b5cbf58
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcstod/test2/test2.c
@@ -0,0 +1,59 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test2.c
+**
+** Purpose: Tests wcstod with overflows
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char **argv)
+{
+ /* Representation of positive infinty for a IEEE 64-bit double */
+ INT64 PosInifity = (INT64)(0x7ff00000) << 32;
+ double HugeVal = *(double*) &PosInifity;
+ char *PosStr = "1E+10000";
+ char *NegStr = "-1E+10000";
+ WCHAR *wideStr;
+ double result;
+
+
+ if (PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ wideStr = convert(PosStr);
+ result = wcstod(wideStr, NULL);
+ free(wideStr);
+
+ if (result != HugeVal)
+ {
+ Fail("ERROR: wcstod interpreted \"%s\" as %g instead of %g\n",
+ PosStr, result, HugeVal);
+ }
+
+
+
+ wideStr = convert(NegStr);
+ result = wcstod(wideStr, NULL);
+ free(wideStr);
+
+ if (result != -HugeVal)
+ {
+ Fail("ERROR: wcstod interpreted \"%s\" as %g instead of %g\n",
+ NegStr, result, -HugeVal);
+ }
+
+
+ PAL_Terminate();
+
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/wcstod/test2/testinfo.dat b/src/pal/tests/palsuite/c_runtime/wcstod/test2/testinfo.dat
new file mode 100644
index 0000000000..bf41e97075
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcstod/test2/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = wcstod
+Name = Positive Test for wcstod
+TYPE = DEFAULT
+EXE1 = test2
+Description
+= Tests wcstod with overflows
+
diff --git a/src/pal/tests/palsuite/c_runtime/wcstok/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/wcstok/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcstok/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/c_runtime/wcstok/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/wcstok/test1/CMakeLists.txt
new file mode 100644
index 0000000000..863f5d8c29
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcstok/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_wcstok_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_wcstok_test1 coreclrpal)
+
+target_link_libraries(paltest_wcstok_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/wcstok/test1/test1.c b/src/pal/tests/palsuite/c_runtime/wcstok/test1/test1.c
new file mode 100644
index 0000000000..76d7dc02b3
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcstok/test1/test1.c
@@ -0,0 +1,114 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose:
+** Search for a number of tokens within strings. Check that the return values
+** are what is expected, and also that the strings match up with our expected
+** results.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ /* foo bar baz */
+ WCHAR str[] = {'f','o','o',' ','b','a','r',' ','b','a','z','\0'};
+
+ /* foo \0ar baz */
+ WCHAR result1[] = {'f','o','o',' ','\0','a','r',' ','b','a','z','\0'};
+
+ /* foo \0a\0 baz */
+ WCHAR result2[] = {'f','o','o',' ','\0','a','\0',' ','b','a','z','\0'};
+
+ WCHAR* tempString;
+ int len = 0;
+ WCHAR *ptr;
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ len = (wcslen(str)*sizeof(WCHAR)) + 2;
+
+ /* Tokenize 'str'. It will hit the 'b' delimiter first. Check to see
+ that the ptr is pointing to the start of the string and do a compare
+ to ensure the tokenized string is what we expected.
+ */
+
+ tempString = convert("bz");
+ ptr = wcstok(str, tempString);
+ free(tempString);
+
+ if (ptr != str)
+ {
+ Fail("ERROR: Expected wcstok() to return %p, got %p!\n", str, ptr);
+ }
+
+ if (memcmp(str, result1, len) != 0)
+ {
+ Fail("ERROR: wcstok altered the string in an unexpected fashion.");
+ }
+
+ /* If NULL is passed as the first parameter, wcstok will continue
+ tokenizing the same string. Test that this works properly.
+ */
+ tempString = convert("r ");
+ ptr = wcstok(NULL, tempString);
+ free(tempString);
+
+ if (ptr != str + 5)
+ {
+ Fail("ERROR: Expected wcstok() to return %p, got %p!\n", str+5, ptr);
+ }
+
+ if (memcmp(str, result2, len) != 0)
+ {
+ Fail("ERROR: wcstok altered the string in an unexpected fashion.");
+ }
+
+ /* Continue onward, and search for 'X' now, which won't be found. The
+ pointer should point just after the last NULL in the string. And
+ the string itself shouldn't have changed.
+ */
+ tempString = convert("X");
+ ptr = wcstok(NULL, tempString);
+ free(tempString);
+
+ if (ptr != str + 7)
+ {
+ Fail("ERROR: Expected wcstok() to return %p, got %p!\n", str + 7, ptr);
+ }
+
+ if (memcmp(str, result2, len) != 0)
+ {
+ Fail("ERROR: wcstok altered the string in an unexpeced fashion.\n");
+ }
+
+ /* Call wcstok again. Now the ptr should point to the end of the
+ string at NULL. And the string itself shouldn't have changed.
+ */
+ tempString = convert("X");
+ ptr = wcstok(NULL, tempString);
+ free(tempString);
+
+ if (ptr != NULL)
+ {
+ Fail("ERROR: Expected wcstok() to return %p, got %p!\n", NULL, ptr);
+ }
+
+ if (memcmp(str, result2, len) != 0)
+ {
+ Fail("ERROR: wcstok altered the string in an unexpeced fashion.\n");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/wcstok/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/wcstok/test1/testinfo.dat
new file mode 100644
index 0000000000..cc00844c6a
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcstok/test1/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = wcstok
+Name = wcstok test- tokenize a string and ensure the string takes correct form.
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Search for a number of tokens within strings. Check that the return values
+= are what is expect, and also that the strings match up with our expected
+= results.
diff --git a/src/pal/tests/palsuite/c_runtime/wcstol/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/wcstol/CMakeLists.txt
new file mode 100644
index 0000000000..7c20179353
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcstol/CMakeLists.txt
@@ -0,0 +1,9 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+add_subdirectory(test3)
+add_subdirectory(test4)
+add_subdirectory(test5)
+add_subdirectory(test6)
+
diff --git a/src/pal/tests/palsuite/c_runtime/wcstol/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/wcstol/test1/CMakeLists.txt
new file mode 100644
index 0000000000..25e96e7de0
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcstol/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_wcstol_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_wcstol_test1 coreclrpal)
+
+target_link_libraries(paltest_wcstol_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/wcstol/test1/test1.c b/src/pal/tests/palsuite/c_runtime/wcstol/test1/test1.c
new file mode 100644
index 0000000000..d84ba66adc
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcstol/test1/test1.c
@@ -0,0 +1,53 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Test #1 for the wcstol function. Does a simple test with radix 4.
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+
+
+/*
+ * Notes: wcstol should depend on the current locale's LC_NUMERIC category,
+ * this is not currently tested.
+ */
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ WCHAR *end;
+ WCHAR teststr[] = {'1','2','3','4','5',0};
+ LONG result = 27;
+ LONG l;
+
+ if ( 0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ l = wcstol(teststr, &end, 4);
+
+ if (l != result)
+ {
+ Fail("ERROR: Expected wcstol to return %d, got %d\n", result, l);
+ }
+
+ if (end != teststr + 3)
+ {
+ Fail("ERROR: Expected wcstol to give an end value of %p, got %p\n",
+ teststr + 3, end);
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/wcstol/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/wcstol/test1/testinfo.dat
new file mode 100644
index 0000000000..48108f22bf
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcstol/test1/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = wcstol
+Name = Positive Test for wcstol
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Tests wcstol with base 4 and a string that includes some invalid characters.
diff --git a/src/pal/tests/palsuite/c_runtime/wcstol/test2/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/wcstol/test2/CMakeLists.txt
new file mode 100644
index 0000000000..ea33ec8c7e
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcstol/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test2.c
+)
+
+add_executable(paltest_wcstol_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_wcstol_test2 coreclrpal)
+
+target_link_libraries(paltest_wcstol_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/wcstol/test2/test2.c b/src/pal/tests/palsuite/c_runtime/wcstol/test2/test2.c
new file mode 100644
index 0000000000..58309be6b4
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcstol/test2/test2.c
@@ -0,0 +1,53 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test2.c
+**
+** Purpose: Test #2 for the wcstol function. Does a simple test with radix
+** 10.
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+
+
+/*
+ * Notes: wcstol should depend on the current locale's LC_NUMERIC category,
+ * this is not currently tested.
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ WCHAR *end;
+ WCHAR teststr[] = {'1','2','3','4','5',0};
+ LONG result = 12345;
+ LONG l;
+
+ if (0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ l = wcstol(teststr, &end, 10);
+
+ if (l != result)
+ {
+ Fail("ERROR: Expected wcstol to return %d, got %d\n", result, l);
+ }
+
+ if (end != teststr + 5)
+ {
+ Fail("ERROR: Expected wcstol to give an end value of %p, got %p\n",
+ teststr + 5, end);
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/wcstol/test2/testinfo.dat b/src/pal/tests/palsuite/c_runtime/wcstol/test2/testinfo.dat
new file mode 100644
index 0000000000..8dd1460010
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcstol/test2/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = wcstol
+Name = Positive Test for wcstol
+TYPE = DEFAULT
+EXE1 = test2
+Description
+= Tests wcstol with base 10 and a completely valid string.
diff --git a/src/pal/tests/palsuite/c_runtime/wcstol/test3/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/wcstol/test3/CMakeLists.txt
new file mode 100644
index 0000000000..509feca08c
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcstol/test3/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test3.c
+)
+
+add_executable(paltest_wcstol_test3
+ ${SOURCES}
+)
+
+add_dependencies(paltest_wcstol_test3 coreclrpal)
+
+target_link_libraries(paltest_wcstol_test3
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/wcstol/test3/test3.c b/src/pal/tests/palsuite/c_runtime/wcstol/test3/test3.c
new file mode 100644
index 0000000000..8b5ce6943d
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcstol/test3/test3.c
@@ -0,0 +1,52 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test3.c
+**
+** Purpose: Test #3 for the wcstol function. Tests an invalid string
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+
+
+/*
+ * Notes: wcstol should depend on the current locale's LC_NUMERIC category,
+ * this is not currently tested.
+ */
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ WCHAR str[] = {'Z',0};
+ WCHAR *end;
+ LONG l;
+
+ if (0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ l = wcstol(str, &end, 10);
+
+ if (l != 0)
+ {
+ Fail("ERROR: Expected wcstol to return %d, got %d\n", 0, l);
+ }
+
+ if (end != str)
+ {
+ Fail("ERROR: Expected wcstol to give an end value of %p, got %p\n",
+ str + 3, end);
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/wcstol/test3/testinfo.dat b/src/pal/tests/palsuite/c_runtime/wcstol/test3/testinfo.dat
new file mode 100644
index 0000000000..0e851d8657
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcstol/test3/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = wcstol
+Name = Positive Test for wcstol
+TYPE = DEFAULT
+EXE1 = test3
+Description
+= Tests wcstol with a completely invalid string (base 10).
diff --git a/src/pal/tests/palsuite/c_runtime/wcstol/test4/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/wcstol/test4/CMakeLists.txt
new file mode 100644
index 0000000000..043c562102
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcstol/test4/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test4.c
+)
+
+add_executable(paltest_wcstol_test4
+ ${SOURCES}
+)
+
+add_dependencies(paltest_wcstol_test4 coreclrpal)
+
+target_link_libraries(paltest_wcstol_test4
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/wcstol/test4/test4.c b/src/pal/tests/palsuite/c_runtime/wcstol/test4/test4.c
new file mode 100644
index 0000000000..a5e65946e9
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcstol/test4/test4.c
@@ -0,0 +1,77 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test4.c
+**
+** Purpose: Test #4 for the wcstol function. Tests the limits of the
+** conversions.
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+
+
+/*
+ * Notes: wcstol should depend on the current locale's LC_NUMERIC category,
+ * this is not currently tested.
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ WCHAR maxstr[] = {'2','1','4','7','4','8','3','6','4','7',0};
+ LONG max = 2147483647;
+ WCHAR minstr[] = {'-','2','1','4','7','4','8','3','6','4','8',0};
+ LONG min = 0x80000000; /* putting -2147483648 gives a warning */
+ WCHAR *end;
+ LONG l;
+
+ if ( 0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ errno = 0;
+
+ l = wcstol(maxstr, &end, 10);
+
+ if (l != max)
+ {
+ Fail("ERROR: Expected wcstol to return %d, got %d\n", max, l);
+ }
+ if (end != maxstr + 10)
+ {
+ Fail("ERROR: Expected wcstol to give an end value of %p, got %p\n",
+ maxstr + 10, end);
+ }
+ if (errno != 0)
+ {
+ Fail("ERROR: wcstol set errno to non-zero (%d)\n", errno);
+ }
+
+
+ l = wcstol(minstr, &end, 10);
+
+ if (l != min)
+ {
+ Fail("ERROR: Expected wcstol to return %d, got %d\n", min, l);
+ }
+ if (end != minstr + 11)
+ {
+ Fail("ERROR: Expected wcstol to give an end value of %p, got %p\n",
+ minstr + 11, end);
+ }
+ if (errno != 0)
+ {
+ Fail("ERROR: wcstol set errno to non-zero (%d)\n", errno);
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/wcstol/test4/testinfo.dat b/src/pal/tests/palsuite/c_runtime/wcstol/test4/testinfo.dat
new file mode 100644
index 0000000000..d2c5652e6e
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcstol/test4/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = wcstol
+Name = Positive Test for wcstol
+TYPE = DEFAULT
+EXE1 = test4
+Description
+= Tests wcstol with base 10 and the highest and lowest possible values.
diff --git a/src/pal/tests/palsuite/c_runtime/wcstol/test5/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/wcstol/test5/CMakeLists.txt
new file mode 100644
index 0000000000..c887369880
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcstol/test5/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test5.c
+)
+
+add_executable(paltest_wcstol_test5
+ ${SOURCES}
+)
+
+add_dependencies(paltest_wcstol_test5 coreclrpal)
+
+target_link_libraries(paltest_wcstol_test5
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/wcstol/test5/test5.c b/src/pal/tests/palsuite/c_runtime/wcstol/test5/test5.c
new file mode 100644
index 0000000000..62f0a895a6
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcstol/test5/test5.c
@@ -0,0 +1,76 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test5.c
+**
+** Purpose: Test #5 for the wcstol function. Tests over and under flowing.
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+
+
+/*
+ * Notes: wcstol should depend on the current locale's LC_NUMERIC category,
+ * this is not currently tested.
+ */
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ WCHAR overstr[] = {'2','1','4','7','4','8','3','6','4','8',0};
+ WCHAR understr[] = {'-','2','1','4','7','4','8','3','6','4','9',0};
+ WCHAR *end;
+ LONG l;
+
+ if (0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ errno = 0;
+
+ l = wcstol(overstr, &end, 10);
+
+ if (l != LONG_MAX)
+ {
+ Fail("ERROR: Expected wcstol to return %u, got %u\n", LONG_MAX, l);
+ }
+ if (end != overstr + 10)
+ {
+ Fail("ERROR: Expected wcstol to give an end value of %p, got %p\n",
+ overstr + 10, end);
+ }
+ if (errno != ERANGE)
+ {
+ Fail("ERROR: wcstol did not set errno to ERANGE (%d)\n", errno);
+ }
+
+
+ errno = 0;
+ l = wcstol(understr, &end, 10);
+
+ if (l != LONG_MIN)
+ {
+ Fail("ERROR: Expected wcstol to return %u, got %u\n", LONG_MIN, l);
+ }
+ if (end != understr + 11)
+ {
+ Fail("ERROR: Expected wcstol to give an end value of %p, got %p\n",
+ understr + 11, end);
+ }
+ if (errno != ERANGE)
+ {
+ Fail("ERROR: wcstol did not set errno to ERANGE (%d)\n", errno);
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/wcstol/test5/testinfo.dat b/src/pal/tests/palsuite/c_runtime/wcstol/test5/testinfo.dat
new file mode 100644
index 0000000000..18b4478e3a
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcstol/test5/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = wcstol
+Name = Positive Test for wcstol
+TYPE = DEFAULT
+EXE1 = test5
+Description
+= Tests wcstol (base 10) with underflowing and overflowing.
+= Chesks that errno gets set to ERANGE.
diff --git a/src/pal/tests/palsuite/c_runtime/wcstol/test6/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/wcstol/test6/CMakeLists.txt
new file mode 100644
index 0000000000..d328161f39
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcstol/test6/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test6.c
+)
+
+add_executable(paltest_wcstol_test6
+ ${SOURCES}
+)
+
+add_dependencies(paltest_wcstol_test6 coreclrpal)
+
+target_link_libraries(paltest_wcstol_test6
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/wcstol/test6/test6.c b/src/pal/tests/palsuite/c_runtime/wcstol/test6/test6.c
new file mode 100644
index 0000000000..14f6208231
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcstol/test6/test6.c
@@ -0,0 +1,86 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test6.c
+**
+** Purpose: Test #6 for the wcstol function. Tests strings with octal/hex
+** number specifers
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+
+
+/*
+ * Notes: wcstol should depend on the current locale's LC_NUMERIC category,
+ * this is not currently tested.
+ */
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ WCHAR test1[] = {'0','x','1','2', 0};
+ WCHAR test2[] = {'0','1','2',0};
+ WCHAR *end;
+ LONG l;
+
+ if (0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ l = wcstol(test1, &end, 16);
+ if (l != 0x12)
+ {
+ Fail("ERROR: Expected wcstol to return %d, got %d\n", 0x12, l);
+ }
+ if (end != test1 + 4)
+ {
+ Fail("ERROR: Expected wcstol to give an end value of %p, got %p\n",
+ test1 + 4, end);
+ }
+
+ l = wcstol(test1, &end, 10);
+ if (l != 0)
+ {
+ Fail("ERROR: Expected wcstol to return %d, got %d\n", 0, l);
+ }
+ if (end != test1+1)
+ {
+ Fail("ERROR: Expected wcstol to give an end value of %p, got %p\n",
+ test1+1, end);
+ }
+
+ l = wcstol(test2, &end, 8);
+ if (l != 10)
+ {
+ Fail("ERROR: Expected wcstol to return %d, got %d\n", 10, l);
+ }
+ if (end != test2 + 3)
+ {
+ Fail("ERROR: Expected wcstol to give an end value of %p, got %p\n",
+ test2 + 3, end);
+ }
+
+ l = wcstol(test2, &end, 10);
+ if (l != 12)
+ {
+ Fail("ERROR: Expected wcstol to return %d, got %d\n", 12, l);
+ }
+
+ if (end != test2 + 3)
+ {
+ Fail("ERROR: Expected wcstol to give an end value of %p, got %p\n",
+ test2 + 3, end);
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/wcstol/test6/testinfo.dat b/src/pal/tests/palsuite/c_runtime/wcstol/test6/testinfo.dat
new file mode 100644
index 0000000000..0e10761e4d
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcstol/test6/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = wcstol
+Name = Positive Test for wcstol
+TYPE = DEFAULT
+EXE1 = test6
+Description
+= Tests wcstol with hex and octal strings, with different bases.
diff --git a/src/pal/tests/palsuite/c_runtime/wcstoul/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/wcstoul/CMakeLists.txt
new file mode 100644
index 0000000000..7c20179353
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcstoul/CMakeLists.txt
@@ -0,0 +1,9 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+add_subdirectory(test3)
+add_subdirectory(test4)
+add_subdirectory(test5)
+add_subdirectory(test6)
+
diff --git a/src/pal/tests/palsuite/c_runtime/wcstoul/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/wcstoul/test1/CMakeLists.txt
new file mode 100644
index 0000000000..b24523e93b
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcstoul/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_wcstoul_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_wcstoul_test1 coreclrpal)
+
+target_link_libraries(paltest_wcstoul_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/wcstoul/test1/test1.c b/src/pal/tests/palsuite/c_runtime/wcstoul/test1/test1.c
new file mode 100644
index 0000000000..5274905e30
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcstoul/test1/test1.c
@@ -0,0 +1,49 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Test #1 for the wcstoul function
+**
+**
+**==========================================================================*/
+#include <palsuite.h>
+
+/*
+ * Notes: wcstoul should depend on the current locale's LC_NUMERIC category,
+ * this is not currently tested.
+ */
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ WCHAR teststr[] = {'1','2','3','4','5',0};
+ WCHAR *end;
+ ULONG result = 27;
+ ULONG l;
+
+ if (0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ l = wcstoul(teststr, &end, 4);
+
+ if (l != result)
+ {
+ Fail("ERROR: Expected wcstoul to return %u, got %u\n", result, l);
+ }
+
+ if (end != teststr + 3)
+ {
+ Fail("ERROR: Expected wcstoul to give an end value of %p, got %p\n",
+ teststr + 3, end);
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/wcstoul/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/wcstoul/test1/testinfo.dat
new file mode 100644
index 0000000000..af4fb7e55d
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcstoul/test1/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = wcstoul
+Name = Positive Test for wcstoul
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Tests wcstoul with base 4 and a string that includes some invalid characters.
diff --git a/src/pal/tests/palsuite/c_runtime/wcstoul/test2/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/wcstoul/test2/CMakeLists.txt
new file mode 100644
index 0000000000..e262078e34
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcstoul/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test2.c
+)
+
+add_executable(paltest_wcstoul_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_wcstoul_test2 coreclrpal)
+
+target_link_libraries(paltest_wcstoul_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/wcstoul/test2/test2.c b/src/pal/tests/palsuite/c_runtime/wcstoul/test2/test2.c
new file mode 100644
index 0000000000..2ab2dbf5d1
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcstoul/test2/test2.c
@@ -0,0 +1,49 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test2.c
+**
+** Purpose: Test #2 for the wcstoul function
+**
+**
+**==========================================================================*/
+#include <palsuite.h>
+
+/*
+ * Notes: wcstoul should depend on the current locale's LC_NUMERIC category,
+ * this is not currently tested.
+ */
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ WCHAR teststr[] = {'1','2','3','4','5',0};
+ WCHAR *end;
+ ULONG result = 12345;
+ ULONG l;
+
+ if (0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ l = wcstoul((wchar_t*)teststr, &end, 10);
+
+ if (l != result)
+ {
+ Fail("ERROR: Expected wcstoul to return %u, got %u\n", result, l);
+ }
+
+ if (end != teststr + 5)
+ {
+ Fail("ERROR: Expected wcstoul to give an end value of %p, got %p\n",
+ teststr + 5, end);
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/wcstoul/test2/testinfo.dat b/src/pal/tests/palsuite/c_runtime/wcstoul/test2/testinfo.dat
new file mode 100644
index 0000000000..b7e301f423
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcstoul/test2/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = wcstoul
+Name = Positive Test for wcstoul
+TYPE = DEFAULT
+EXE1 = test2
+Description
+= Tests wcstoul with base 10 and a completely valid string.
diff --git a/src/pal/tests/palsuite/c_runtime/wcstoul/test3/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/wcstoul/test3/CMakeLists.txt
new file mode 100644
index 0000000000..aae268ac59
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcstoul/test3/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test3.c
+)
+
+add_executable(paltest_wcstoul_test3
+ ${SOURCES}
+)
+
+add_dependencies(paltest_wcstoul_test3 coreclrpal)
+
+target_link_libraries(paltest_wcstoul_test3
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/wcstoul/test3/test3.c b/src/pal/tests/palsuite/c_runtime/wcstoul/test3/test3.c
new file mode 100644
index 0000000000..eac46615e2
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcstoul/test3/test3.c
@@ -0,0 +1,49 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test3.c
+**
+** Purpose: Test #3 for the wcstoul function
+**
+**
+**==========================================================================*/
+#include <palsuite.h>
+
+/*
+ * Notes: wcstoul should depend on the current locale's LC_NUMERIC category,
+ * this is not currently tested.
+ */
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ WCHAR str[] = {'Z',0};
+ WCHAR *end;
+ ULONG l;
+
+ if (0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ l = wcstoul(str, &end, 10);
+
+ if (l != 0)
+ {
+ Fail("ERROR: Expected wcstoul to return %u, got %u\n", 0, l);
+ }
+
+ if (end != str)
+ {
+ Fail("ERROR: Expected wcstoul to give an end value of %p, got %p\n",
+ str, end);
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/wcstoul/test3/testinfo.dat b/src/pal/tests/palsuite/c_runtime/wcstoul/test3/testinfo.dat
new file mode 100644
index 0000000000..f7f6302d79
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcstoul/test3/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = wcstoul
+Name = Positive Test for wcstoul
+TYPE = DEFAULT
+EXE1 = test3
+Description
+= Tests wcstoul with a completely invalid string (base 10).
diff --git a/src/pal/tests/palsuite/c_runtime/wcstoul/test4/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/wcstoul/test4/CMakeLists.txt
new file mode 100644
index 0000000000..bd8073023f
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcstoul/test4/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test4.c
+)
+
+add_executable(paltest_wcstoul_test4
+ ${SOURCES}
+)
+
+add_dependencies(paltest_wcstoul_test4 coreclrpal)
+
+target_link_libraries(paltest_wcstoul_test4
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/wcstoul/test4/test4.c b/src/pal/tests/palsuite/c_runtime/wcstoul/test4/test4.c
new file mode 100644
index 0000000000..0261da4275
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcstoul/test4/test4.c
@@ -0,0 +1,52 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test4.c
+**
+** Purpose: Test #4 for the wcstoul function
+**
+**
+**==========================================================================*/
+#include <palsuite.h>
+
+/*
+ * Notes: wcstoul should depend on the current locale's LC_NUMERIC category,
+ * this is not currently tested.
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ WCHAR maxstr[] = {'4','2','9','4','9','6','7','2','9','5',0};
+ ULONG max = 4294967295ul;
+ WCHAR *end;
+ ULONG l;
+
+ if (0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ errno = 0;
+
+ l = wcstoul(maxstr, &end, 10);
+ if (l != max)
+ {
+ Fail("ERROR: Expected wcstoul to return %u, got %u\n", max, l);
+ }
+ if (end != maxstr + 10)
+ {
+ Fail("ERROR: Expected wcstoul to give an end value of %p, got %p\n",
+ maxstr + 10, end);
+ }
+ if (errno != 0)
+ {
+ Fail("ERROR: wcstoul set errno to non-zero (%d)\n", errno);
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/wcstoul/test4/testinfo.dat b/src/pal/tests/palsuite/c_runtime/wcstoul/test4/testinfo.dat
new file mode 100644
index 0000000000..301178be3a
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcstoul/test4/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = wcstoul
+Name = Positive Test for wcstoul
+TYPE = DEFAULT
+EXE1 = test4
+Description
+= Tests wcstoul with base 10 and the highest possible value.
diff --git a/src/pal/tests/palsuite/c_runtime/wcstoul/test5/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/wcstoul/test5/CMakeLists.txt
new file mode 100644
index 0000000000..1451e6ad57
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcstoul/test5/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test5.c
+)
+
+add_executable(paltest_wcstoul_test5
+ ${SOURCES}
+)
+
+add_dependencies(paltest_wcstoul_test5 coreclrpal)
+
+target_link_libraries(paltest_wcstoul_test5
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/wcstoul/test5/test5.c b/src/pal/tests/palsuite/c_runtime/wcstoul/test5/test5.c
new file mode 100644
index 0000000000..00287cf7f4
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcstoul/test5/test5.c
@@ -0,0 +1,69 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test5.c
+**
+** Purpose: Test #5 for the wcstoul function
+**
+**
+**==========================================================================*/
+#include <palsuite.h>
+
+/*
+ * Notes: wcstoul should depend on the current locale's LC_NUMERIC category,
+ * this is not currently tested.
+ */
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ WCHAR overstr[] = {'4','2','9','4','9','6','7','2','9','6',0};
+ WCHAR understr[] = {'-','1',0};
+ WCHAR *end;
+ ULONG l;
+
+ if (0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ errno = 0;
+ l = wcstoul(overstr, &end, 10);
+
+ if (l != ULONG_MAX)
+ {
+ Fail("ERROR: Expected wcstoul to return %u, got %u\n", ULONG_MAX, l);
+ }
+ if (end != overstr + 10)
+ {
+ Fail("ERROR: Expected wcstoul to give an end value of %p, got %p\n",
+ overstr + 10, end);
+ }
+ if (errno != ERANGE)
+ {
+ Fail("ERROR: wcstoul did not set errno to ERANGE (%d)\n", errno);
+ }
+
+ errno = 0;
+ l = wcstoul(understr, &end, 10);
+
+ if (l != ULONG_MAX)
+ {
+ Fail("ERROR: Expected wcstoul to return %u, got %u\n", ULONG_MAX, l);
+ }
+ if (end != understr + 2)
+ {
+ Fail("ERROR: Expected wcstoul to give an end value of %p, got %p\n",
+ understr + 2, end);
+ }
+ if (errno != 0)
+ {
+ Fail("ERROR: wcstoul set errno to non-zero (%d)\n", errno);
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/wcstoul/test5/testinfo.dat b/src/pal/tests/palsuite/c_runtime/wcstoul/test5/testinfo.dat
new file mode 100644
index 0000000000..bf7b2b6fe0
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcstoul/test5/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = wcstoul
+Name = Positive Test for wcstoul
+TYPE = DEFAULT
+EXE1 = test5
+Description
+= Tests wcstoul (base 10) with underflowing and overflowing.
+= Chesks that errno gets set to ERANGE.
diff --git a/src/pal/tests/palsuite/c_runtime/wcstoul/test6/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/wcstoul/test6/CMakeLists.txt
new file mode 100644
index 0000000000..15518bdcf8
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcstoul/test6/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test6.c
+)
+
+add_executable(paltest_wcstoul_test6
+ ${SOURCES}
+)
+
+add_dependencies(paltest_wcstoul_test6 coreclrpal)
+
+target_link_libraries(paltest_wcstoul_test6
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/wcstoul/test6/test6.c b/src/pal/tests/palsuite/c_runtime/wcstoul/test6/test6.c
new file mode 100644
index 0000000000..28397ec73f
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcstoul/test6/test6.c
@@ -0,0 +1,83 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test6.c
+**
+** Purpose: Test #6 for the wcstoul function. Tests strings with octal/hex
+** number specifers
+**
+**
+**==========================================================================*/
+#include <palsuite.h>
+
+
+/*
+ * Notes: wcstoul should depend on the current locale's LC_NUMERIC category,
+ * this is not currently tested.
+ */
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ WCHAR test1[] = {'0','x','1','2', 0};
+ WCHAR test2[] = {'0','1','2',0};
+ WCHAR *end;
+ ULONG l;
+
+ if (0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ l = wcstoul(test1, &end, 16);
+ if (l != 0x12)
+ {
+ Fail("ERROR: Expected wcstoul to return %u, got %u\n", 0x12, l);
+ }
+ if (end != test1 + 4)
+ {
+ Fail("ERROR: Expected wcstoul to give an end value of %p, got %p\n",
+ test1 + 4, end);
+ }
+
+ l = wcstoul(test1, &end, 10);
+ if (l != 0)
+ {
+ Fail("ERROR: Expected wcstoul to return %u, got %u\n", 0, l);
+ }
+ if (end != test1+1)
+ {
+ Fail("ERROR: Expected wcstoul to give an end value of %p, got %p\n",
+ test1+1, end);
+ }
+
+ l = wcstoul(test2, &end, 8);
+ if (l != 10)
+ {
+ Fail("ERROR: Expected wcstoul to return %u, got %u\n", 10, l);
+ }
+ if (end != test2 + 3)
+ {
+ Fail("ERROR: Expected wcstoul to give an end value of %p, got %p\n",
+ test2 + 3, end);
+ }
+
+ l = wcstoul(test2, &end, 10);
+ if (l != 12)
+ {
+ Fail("ERROR: Expected wcstoul to return %u, got %u\n", 12, l);
+ }
+
+ if (end != test2 + 3)
+ {
+ Fail("ERROR: Expected wcstoul to give an end value of %p, got %p\n",
+ test2 + 3, end);
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/c_runtime/wcstoul/test6/testinfo.dat b/src/pal/tests/palsuite/c_runtime/wcstoul/test6/testinfo.dat
new file mode 100644
index 0000000000..40e18d540d
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wcstoul/test6/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = wcstoul
+Name = Positive Test for wcstoul
+TYPE = DEFAULT
+EXE1 = test6
+Description
+= Tests wcstoul with hex and octal strings, with different bases.
diff --git a/src/pal/tests/palsuite/c_runtime/wprintf/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/wprintf/CMakeLists.txt
new file mode 100644
index 0000000000..ef14ea5352
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wprintf/CMakeLists.txt
@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+
diff --git a/src/pal/tests/palsuite/c_runtime/wprintf/test1/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/wprintf/test1/CMakeLists.txt
new file mode 100644
index 0000000000..701bbe4160
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wprintf/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_wprintf_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_wprintf_test1 coreclrpal)
+
+target_link_libraries(paltest_wprintf_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/wprintf/test1/test1.c b/src/pal/tests/palsuite/c_runtime/wprintf/test1/test1.c
new file mode 100644
index 0000000000..d99dc8cf93
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wprintf/test1/test1.c
@@ -0,0 +1,47 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Test #1 for the wprintf function. A single, basic, test
+** case with no formatting.
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+#include "../wprintf.h"
+
+int __cdecl main(int argc, char *argv[])
+{
+ char checkstr[] = "hello world";
+ WCHAR *wcheckstr;
+ int ret;
+
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ wcheckstr = convert(checkstr);
+
+ ret = wprintf(wcheckstr);
+
+ if (ret != wcslen(wcheckstr))
+ {
+ Fail("Expected wprintf to return %d, got %d.\n",
+ wcslen(wcheckstr), ret);
+
+ }
+
+ free(wcheckstr);
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/wprintf/test1/testinfo.dat b/src/pal/tests/palsuite/c_runtime/wprintf/test1/testinfo.dat
new file mode 100644
index 0000000000..02946361b0
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wprintf/test1/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = wprintf
+Name = Positive Test for wprintf
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= General test to see if wprintf works correctly
diff --git a/src/pal/tests/palsuite/c_runtime/wprintf/test2/CMakeLists.txt b/src/pal/tests/palsuite/c_runtime/wprintf/test2/CMakeLists.txt
new file mode 100644
index 0000000000..55c3d11913
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wprintf/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test2.c
+)
+
+add_executable(paltest_wprintf_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_wprintf_test2 coreclrpal)
+
+target_link_libraries(paltest_wprintf_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/c_runtime/wprintf/test2/test2.c b/src/pal/tests/palsuite/c_runtime/wprintf/test2/test2.c
new file mode 100644
index 0000000000..254e98a394
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wprintf/test2/test2.c
@@ -0,0 +1,45 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test2.c
+**
+** Purpose: Test #2 for the wprintf function. Tests the string specifier
+** (%s).
+**
+**
+**==========================================================================*/
+
+
+#include <palsuite.h>
+#include "../wprintf.h"
+
+
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ DoStrTest(u"foo %s", u"bar", u"foo bar");
+ DoStrTest(u"foo %ws", u"bar", u"foo bar");
+ DoStrTest(u"foo %ls", u"bar", u"foo bar");
+ DoStrTest(u"foo %ws", u"bar", u"foo bar");
+ DoStrTest(u"foo %Ls", u"bar", u"foo bar");
+ DoStrTest(u"foo %I64s", u"bar", u"foo bar");
+ DoStrTest(u"foo %5s", u"bar", u"foo bar");
+ DoStrTest(u"foo %.2s", u"bar", u"foo ba");
+ DoStrTest(u"foo %5.2s", u"bar", u"foo ba");
+ DoStrTest(u"foo %-5s", u"bar", u"foo bar ");
+ DoStrTest(u"foo %05s", u"bar", u"foo 00bar");
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/c_runtime/wprintf/test2/testinfo.dat b/src/pal/tests/palsuite/c_runtime/wprintf/test2/testinfo.dat
new file mode 100644
index 0000000000..7808c069dd
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wprintf/test2/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = wprintf
+Name = Positive Test for wprintf
+TYPE = DEFAULT
+EXE1 = test2
+Description
+= Tests wprintf with strings
diff --git a/src/pal/tests/palsuite/c_runtime/wprintf/wprintf.h b/src/pal/tests/palsuite/c_runtime/wprintf/wprintf.h
new file mode 100644
index 0000000000..7d3caf1b02
--- /dev/null
+++ b/src/pal/tests/palsuite/c_runtime/wprintf/wprintf.h
@@ -0,0 +1,171 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: wprintf.h
+**
+** Purpose: Containts common testing functions for wprintf
+**
+**
+**==========================================================================*/
+
+#ifndef __wprintf_H__
+#define __wprintf_H__
+
+void DoStrTest(WCHAR *formatstr, WCHAR* param, WCHAR *checkstr)
+{
+ int ret;
+
+ ret = wprintf(formatstr, param);
+ if (ret != wcslen(checkstr))
+ {
+ Fail("DoStrTest:Expected wprintf to return %d, got %d.\n",
+ wcslen(checkstr), ret);
+ }
+}
+
+
+void DoPointerTest(WCHAR *formatstr, void* param, WCHAR* paramstr,
+ WCHAR *checkstr1)
+{
+ int ret;
+
+ ret = wprintf(formatstr, param);
+ if (ret != wcslen(checkstr1))
+ {
+ Fail("DoPointerTest:Expected wprintf to return %d, got %d.\n",
+ wcslen(checkstr1), ret);
+ }
+}
+
+void DoCountTest(WCHAR *formatstr, int param, WCHAR *checkstr)
+{
+ int ret;
+ int n = -1;
+
+ ret = wprintf(formatstr, &n);
+
+ if (n != param)
+ {
+ Fail("DoCountTest:Expected count parameter to resolve to %d, got %d\n", param, n);
+ }
+
+ if (ret != wcslen(checkstr))
+ {
+ Fail("DoCountTest:Expected wprintf to return %d, got %d.\n",
+ wcslen(checkstr), ret);
+ }
+}
+
+void DoShortCountTest(WCHAR *formatstr, int param, WCHAR *checkstr)
+{
+ int ret;
+ short int n = -1;
+
+ ret = wprintf(formatstr, &n);
+
+ if (n != param)
+ {
+ Fail("DoShortCountTest:Expected count parameter to resolve to %d, got %d\n", param, n);
+ }
+
+ if (ret != wcslen(checkstr))
+ {
+ Fail("DoShortCountTest:Expected wprintf to return %d, got %d.\n",
+ wcslen(checkstr), ret);
+ }
+}
+
+
+void DoCharTest(WCHAR *formatstr, WCHAR param, WCHAR *checkstr)
+{
+ int ret;
+
+ ret = wprintf(formatstr, param);
+ if (ret != wcslen(checkstr))
+ {
+ Fail("DoCharTest:Expected wprintf to return %d, got %d.\n",
+ wcslen(checkstr), ret);
+ }
+}
+
+void DoWCharTest(WCHAR *formatstr, WCHAR param, WCHAR *checkstr)
+{
+ int ret;
+
+ ret = wprintf(formatstr, param);
+ if (ret != wcslen(checkstr))
+ {
+ Fail("DoWCharTest:Expected wprintf to return %d, got %d.\n",
+ wcslen(checkstr), ret);
+ }
+}
+
+void DoNumTest(WCHAR *formatstr, int param, WCHAR *checkstr)
+{
+ int ret;
+
+ ret = wprintf(formatstr, param);
+ if (ret != wcslen(checkstr))
+ {
+ Fail("DoNumTest:Expected wprintf to return %d, got %d.\n",
+ wcslen(checkstr), ret);
+ }
+}
+
+void DoI64Test(WCHAR *formatstr, INT64 param, WCHAR *valuestr,
+ WCHAR *checkstr1)
+{
+ int ret;
+
+ ret = wprintf(formatstr, param);
+ if (ret != wcslen(checkstr1))
+ {
+ Fail("DoI64Test:Expected wprintf to return %d, got %d.\n",
+ wcslen(checkstr1), ret);
+ }
+}
+
+void DoDoubleTest(WCHAR *formatstr, double param,
+ WCHAR *checkstr1, WCHAR *checkstr2)
+{
+ int ret;
+
+ ret = wprintf(formatstr, param);
+ if (ret != wcslen(checkstr1) && ret != wcslen(checkstr2))
+ {
+ Fail("DoDoubleTest:Expected wprintf to return %d or %d, got %d.\n",
+ wcslen(checkstr1), wcslen(checkstr2), ret);
+ }
+}
+
+void DoArgumentPrecTest(WCHAR *formatstr, int precision, void *param,
+ WCHAR *paramstr, WCHAR *checkstr1, WCHAR *checkstr2)
+{
+ int ret;
+
+ ret = wprintf(formatstr, precision, param);
+ if (ret != wcslen(checkstr1) && ret != wcslen(checkstr2))
+ {
+ Fail("DoArgumentPrecTest:Expected wprintf to return %d or %d, got %d.\n",
+ wcslen(checkstr1), wcslen(checkstr2), ret);
+ }
+}
+
+void DoArgumentPrecDoubleTest(WCHAR *formatstr, int precision, double param,
+ WCHAR *checkstr1, WCHAR *checkstr2)
+{
+ int ret;
+
+ ret = wprintf(formatstr, precision, param);
+ if (ret != wcslen(checkstr1) && ret != wcslen(checkstr2))
+ {
+ Fail("DoArgumentPrecDoubleTest:Expected wprintf to return %d or %d, got %d.\n",
+ wcslen(checkstr1), wcslen(checkstr2), ret);
+ }
+}
+
+#endif
+
diff --git a/src/pal/tests/palsuite/common/ResultBuffer.cpp b/src/pal/tests/palsuite/common/ResultBuffer.cpp
new file mode 100644
index 0000000000..e38c324187
--- /dev/null
+++ b/src/pal/tests/palsuite/common/ResultBuffer.cpp
@@ -0,0 +1,69 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+//#include "stdafx.h"
+#include "resultbuffer.h"
+//
+//#using <mscorlib.dll>
+//
+//using namespace System;
+
+
+ResultBuffer:: ResultBuffer(int ThreadCount, int ThreadLogSize)
+ {
+ // Declare an internal status variable
+ int Status=0;
+
+ // Update the maximum thread count
+ MaxThreadCount = ThreadCount;
+
+ // Allocate the memory buffer based on the passed in thread and process counts
+ // and the specified size of the thread specific buffer
+ buffer = NULL;
+ buffer = (char*)malloc(ThreadCount*ThreadLogSize);
+ // Check to see if the buffer memory was allocated
+ if (buffer == NULL)
+ Status = -1;
+ // Initialize the buffer to 0 to prevent bogus data
+ memset(buffer,0,ThreadCount*ThreadLogSize);
+
+ // The ThreadOffset is equal to the total number of bytes that will be stored per thread
+ ThreadOffset = ThreadLogSize;
+
+ }
+
+
+ int ResultBuffer::LogResult(int Thread, char* Data)
+ {
+ // Declare an internal status flad
+ int status = 0;
+
+ // Declare an object to store the offset address into the buffer
+ int Offset;
+
+ // Check to make sure the Thread index is not out of range
+ if(Thread > MaxThreadCount)
+ {
+ Trace("Thread index is out of range, Value of Thread[%d], Value of MaxThreadCount[%d]\n", Thread, MaxThreadCount);
+ status = -1;
+ return(status);
+ }
+
+ // Caculate the offset into the shared buffer based on the process and thread indices
+ Offset = (Thread)*ThreadOffset;
+
+ // Write the passed in data to the reserved buffer
+ memcpy(buffer+Offset,Data,ThreadOffset);
+
+ return(status);
+ }
+
+
+ char* ResultBuffer::getResultBuffer(int threadId)
+ {
+
+ return (buffer + threadId*ThreadOffset);
+
+ }
+
diff --git a/src/pal/tests/palsuite/common/ResultBuffer.h b/src/pal/tests/palsuite/common/ResultBuffer.h
new file mode 100644
index 0000000000..c59d421e2d
--- /dev/null
+++ b/src/pal/tests/palsuite/common/ResultBuffer.h
@@ -0,0 +1,43 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+//#include <stdio.h>
+//#include <iostream>
+//#include <assert.h>
+#ifndef _RESULT_BUFFER_H_
+#define _RESULT_BUFFER_H_
+
+#include <palsuite.h>
+
+struct ResultData
+{
+ int value;
+ int size;
+// ResultData* NextResult;
+};
+
+ class ResultBuffer
+{
+ // Declare a pointer to a memory buffer to store the logged results
+ char* buffer;
+ // Declare an object to store the maximum Thread count
+ int MaxThreadCount;
+ // Declare and internal data object to store the calculated offset between adjacent threads data sets
+ int ThreadOffset;
+
+ // Declare a linked list object to store the parameter values
+public:
+
+ // Declare a constructor for the single process case
+ ResultBuffer(int ThreadCount, int ThreadLogSize);
+ // Declare a method to log data for the single process instance
+ int LogResult(int Thread, char* Data);
+
+ char* getResultBuffer(int threadId);
+};
+
+#include "resultbuffer.cpp"
+#endif // _RESULT_BUFFER_H_
+
+
diff --git a/src/pal/tests/palsuite/common/ResultTime.h b/src/pal/tests/palsuite/common/ResultTime.h
new file mode 100644
index 0000000000..df706e7a64
--- /dev/null
+++ b/src/pal/tests/palsuite/common/ResultTime.h
@@ -0,0 +1,103 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#ifndef _RESULT_TIME_H_
+#define _RESULT_TIME_H_
+
+#include <palsuite.h>
+
+#define DWORD_MAX ((DWORD) 0xFFFFFFFF)
+const char *szDotNetInstallEnvVar = "DOTNET_INSTALL";
+const char *szQASupportDirEnvVar = "QA_SUPPORT_DIR";
+
+#ifdef PLATFORM_UNIX
+#define SEPERATOR "/"
+#else
+#define SEPERATOR "\\"
+#endif
+char *getBuildNumber()
+{
+ char *szBuildFileName = "buildinfo.txt";
+ char *pDirectoryName = NULL;
+ char szBuildFileLoc[256];
+
+ char szTemp[100];
+ // buildinfo.txt contains information in key/value pair
+ char szTempKey[100];
+ char *szTempValue;
+ FILE *fp;
+
+ szTempValue = (char *) malloc (sizeof(char) *100);
+ if (szTempValue == NULL)
+ {
+ Fail("ERROR: Couldn't allocate enough memory to potentially store build number\n");
+ }
+
+#ifndef PLATFORM_UNIX
+ pDirectoryName = getenv(szDotNetInstallEnvVar);
+ if (pDirectoryName == NULL)
+ {
+ /* This condition may exist if the test is being run in say the Dev environment.*/
+ Trace("WARNING: Coriolis Test Environment may not be setup correctly. Variable DOTNET_INSTALL not set\n");
+ _snprintf(szTempValue, 99, "0000.00");
+ return szTempValue;
+ }
+#else
+ pDirectoryName = getenv(szQASupportDirEnvVar);
+ if (pDirectoryName == NULL)
+ {
+ Trace("WARNING: Coriolis Test Environment may not be setup correctly. Variable QA_SUPPORT_DIR not set\n");
+ _snprintf(szTempValue, 99, "0000.00");
+ return szTempValue;
+ }
+
+#endif //PLATFORM_UNIX
+
+#ifndef PLATFORM_UNIX
+ _snprintf(szBuildFileLoc, MAX_PATH, "%s%s%s", pDirectoryName, SEPERATOR, szBuildFileName);
+#else
+ // To avoid buffer overruns for pDirectoryName
+ _snprintf(szBuildFileLoc, MAX_PATH, "%s/../1.0%s%s", pDirectoryName, SEPERATOR, szBuildFileName);
+#endif //PLATFORM_UNIX
+ fp = fopen( szBuildFileLoc, "r");
+ if( fp == NULL)
+ {
+ Trace("WARNING: Couldn't open szBuildFileLoc [%s]\n", szBuildFileLoc);
+ _snprintf(szTempValue, 99, "0000.00");
+ return szTempValue;
+ }
+
+ while( fgets( szTemp, 100, fp ) != NULL)
+ {
+ sscanf(szTemp, "%s %s\n", szTempKey, szTempValue);
+ if(strcmp(szTempKey, "Build-Number:") == 0)
+ {
+ fclose(fp);
+ return szTempValue;
+ }
+ }
+
+ fclose(fp);
+ return szTempValue;
+
+}
+
+DWORD GetTimeDiff( DWORD dwStartTime)
+{
+ DWORD dwDiffTime = 0;
+ DWORD dwEndTime = GetTickCount();
+
+ if( dwEndTime < dwStartTime)
+ {
+ // To account for overflow, we add one
+ dwDiffTime = dwEndTime + (DWORD_MAX - dwStartTime) + 1;
+ }
+ else
+ {
+ dwDiffTime = dwEndTime - dwStartTime;
+ }
+
+ return dwDiffTime;
+}
+#endif // _RESULT_TIME_H_
diff --git a/src/pal/tests/palsuite/common/pal_stdclib.h b/src/pal/tests/palsuite/common/pal_stdclib.h
new file mode 100644
index 0000000000..61963db67c
--- /dev/null
+++ b/src/pal/tests/palsuite/common/pal_stdclib.h
@@ -0,0 +1,24 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: pal_stdlib.h
+**
+** Purpose:
+**
+**
+**==========================================================================*/
+
+
+#ifndef __PAL_STDCLIB_H__
+#define __PAL_STDCLIB_H__
+
+/*
+ * <stdio.h> definitions & functions
+ */
+
+#define EOF (-1)
+
+#endif // __PAL_STDCLIB_H__
diff --git a/src/pal/tests/palsuite/common/palsuite.h b/src/pal/tests/palsuite/common/palsuite.h
new file mode 100644
index 0000000000..ef644ad8e5
--- /dev/null
+++ b/src/pal/tests/palsuite/common/palsuite.h
@@ -0,0 +1,182 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: palsuite.h
+**
+** Purpose: Define constants and implement functions that are useful to
+** multiple function categories. If common functions are useful
+** only amongst the test cases for a particular function, a separate
+** header file is placed in the root of those test cases.
+**
+**
+**==========================================================================*/
+
+#ifndef __PALSUITE_H__
+#define __PALSUITE_H__
+
+#include <pal_assert.h>
+#include <pal.h>
+#include <palprivate.h>
+
+enum
+{
+ PASS = 0,
+ FAIL = 1
+};
+
+
+void Trace(const char *format, ...)
+{
+ va_list arglist;
+
+ va_start(arglist, format);
+
+ vprintf(format, arglist);
+
+ va_end(arglist);
+}
+
+void Fail(const char *format, ...)
+{
+ va_list arglist;
+
+ va_start(arglist, format);
+
+ vprintf(format, arglist);
+
+ va_end(arglist);
+ printf("\n");
+
+ // This will exit the test process
+ PAL_TerminateEx(FAIL);
+}
+
+#ifdef PAL_PERF
+
+int __cdecl Test_Main(int argc, char **argv);
+int PAL_InitializeResult = 0;
+static const char PALTEST_LOOP_ENV[]="PALTEST_LOOP_COUNT";
+
+int __cdecl main(int argc, char **argv)
+{
+ int lastMainResult=0;
+
+ int loopCount=1; // default: run the test's main once
+ int loopIndex=0;
+ char *szPerfLoopEnv = NULL;
+
+ // Run PAL_Initialize once, save off the result. Any failures here
+ // will be detected later by calls to PAL_Initialize in the test's main.
+ PAL_InitializeResult = PAL_Initialize(argc, argv);
+
+ // Check the environment to see if we need to run the test's main
+ // multiple times. Ideally, we want to do this before PAL_Initialize so
+ // that the overhead of checking the environment is not included in the
+ // time between PAL_Initialize and PAL_Terminate. However, getenv in PAL
+ // can be run only after PAL_Initialize.
+ szPerfLoopEnv = getenv(PALTEST_LOOP_ENV);
+ if (szPerfLoopEnv != NULL)
+ {
+ loopCount = atoi(szPerfLoopEnv);
+ if (loopCount <= 0) loopCount = 1;
+ }
+
+ // call the test's actual main in a loop
+ for(loopIndex=0; loopIndex<loopCount; loopIndex++) {
+ lastMainResult = Test_Main(argc, argv);
+ }
+
+ // call PAL_Terminate for real
+ PAL_TerminateEx(lastMainResult);
+
+ return lastMainResult;
+}
+
+// Test's calls to PAL_Initialize and PAL_Terminate are redirected
+// to these bogus functions. These rely on PAL_Initialize and PAL_Terminate
+// being called by the 'main' above.
+#define PAL_Initialize(a, b) Bogus_PAL_Initialize(a, b)
+#define PAL_Terminate() Bogus_PAL_Terminate()
+int Bogus_PAL_Initialize(int argc, char* argv[])
+{
+ // PAL_Initialize has already been called by the real main.
+ // Just return the result.
+ return PAL_InitializeResult;
+}
+
+void Bogus_PAL_Terminate()
+{
+ // Don't call PAL_Terminate. It will be called later by the
+ // real main.
+ return;
+}
+
+// Rename the main provided by the test case
+#define main Test_Main
+
+#endif // PAL_PERF
+
+#ifdef BIGENDIAN
+inline ULONG VAL32(ULONG x)
+{
+ return( ((x & 0xFF000000L) >> 24) |
+ ((x & 0x00FF0000L) >> 8) |
+ ((x & 0x0000FF00L) << 8) |
+ ((x & 0x000000FFL) << 24) );
+}
+#define th_htons(w) (w)
+#else // BIGENDIAN
+#define VAL32(x) (x)
+#define th_htons(w) (((w) >> 8) | ((w) << 8))
+#endif // BIGENDIAN
+
+
+
+WCHAR* convert(char * aString)
+{
+ int size;
+ WCHAR* wideBuffer;
+
+ size = MultiByteToWideChar(CP_ACP,0,aString,-1,NULL,0);
+ wideBuffer = (WCHAR*) malloc(size*sizeof(WCHAR));
+ if (wideBuffer == NULL)
+ {
+ Fail("ERROR: Unable to allocate memory!\n");
+ }
+ MultiByteToWideChar(CP_ACP,0,aString,-1,wideBuffer,size);
+ return wideBuffer;
+}
+
+char* convertC(WCHAR * wString)
+{
+ int size;
+ char * MultiBuffer = NULL;
+
+ size = WideCharToMultiByte(CP_ACP,0,wString,-1,MultiBuffer,0,NULL,NULL);
+ MultiBuffer = (char*) malloc(size);
+ if (MultiBuffer == NULL)
+ {
+ Fail("ERROR: Unable to allocate memory!\n");
+ }
+ WideCharToMultiByte(CP_ACP,0,wString,-1,MultiBuffer,size,NULL,NULL);
+ return MultiBuffer;
+}
+
+UINT64 GetHighPrecisionTimeStamp(LARGE_INTEGER performanceFrequency)
+{
+ LARGE_INTEGER ts;
+ if (!QueryPerformanceCounter(&ts))
+ {
+ Fail("ERROR: Unable to query performance counter!\n");
+ }
+
+ return ts.QuadPart / (performanceFrequency.QuadPart / 1000);
+}
+
+#endif
+
+
+
diff --git a/src/pal/tests/palsuite/composite/CMakeLists.txt b/src/pal/tests/palsuite/composite/CMakeLists.txt
new file mode 100644
index 0000000000..220b8cc18f
--- /dev/null
+++ b/src/pal/tests/palsuite/composite/CMakeLists.txt
@@ -0,0 +1,7 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(object_management)
+add_subdirectory(synchronization)
+add_subdirectory(threading)
+add_subdirectory(wfmo)
+
diff --git a/src/pal/tests/palsuite/composite/object_management/CMakeLists.txt b/src/pal/tests/palsuite/composite/object_management/CMakeLists.txt
new file mode 100644
index 0000000000..5fd88b0046
--- /dev/null
+++ b/src/pal/tests/palsuite/composite/object_management/CMakeLists.txt
@@ -0,0 +1,6 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(event)
+add_subdirectory(mutex)
+add_subdirectory(semaphore)
+
diff --git a/src/pal/tests/palsuite/composite/object_management/event/CMakeLists.txt b/src/pal/tests/palsuite/composite/object_management/event/CMakeLists.txt
new file mode 100644
index 0000000000..2534564f95
--- /dev/null
+++ b/src/pal/tests/palsuite/composite/object_management/event/CMakeLists.txt
@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(nonshared)
+add_subdirectory(shared)
+
diff --git a/src/pal/tests/palsuite/composite/object_management/event/nonshared/CMakeLists.txt b/src/pal/tests/palsuite/composite/object_management/event/nonshared/CMakeLists.txt
new file mode 100644
index 0000000000..c6c00377e1
--- /dev/null
+++ b/src/pal/tests/palsuite/composite/object_management/event/nonshared/CMakeLists.txt
@@ -0,0 +1,21 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ event.c
+ main.c
+)
+
+add_executable(paltest_event_nonshared
+ ${SOURCES}
+)
+
+add_dependencies(paltest_event_nonshared coreclrpal)
+
+target_link_libraries(paltest_event_nonshared
+ pthread
+ rt
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/composite/object_management/event/nonshared/event.c b/src/pal/tests/palsuite/composite/object_management/event/nonshared/event.c
new file mode 100644
index 0000000000..69ad9a30e3
--- /dev/null
+++ b/src/pal/tests/palsuite/composite/object_management/event/nonshared/event.c
@@ -0,0 +1,358 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source Code: main.c and event.c
+** main.c creates process and waits for all processes to get over
+** event.c creates a event and then calls threads which will contend for the event
+**
+** This test is for Object Management Test case for event where Object type is shareable.
+** Algorithm
+** o Main Process Creates OBJECT_TYPE Object
+** o Create PROCESS_COUNT processes aware of the Shared Object
+**
+** Author: ShamitP
+**
+**
+**============================================================
+*/
+
+#include <palsuite.h>
+#include "resultbuffer.h"
+#include "resulttime.h"
+
+#define TIMEOUT 5000
+/* Test Input Variables */
+unsigned int USE_PROCESS_COUNT = 0;
+unsigned int THREAD_COUNT = 0;
+unsigned int REPEAT_COUNT = 0;
+unsigned int RELATION_ID= 0;
+
+/* Event variables */
+//unsigned long lInitialCount = 1; /* Signaled */
+//unsigned long lMaximumCount = 1; /* Maximum value of 1 */
+
+/* Capture statistics at per thread basis */
+struct statistics{
+ unsigned int processId;
+ unsigned int operationsFailed;
+ unsigned int operationsPassed;
+ unsigned int operationsTotal;
+ DWORD operationTime;
+ unsigned int relationId;
+};
+
+struct ProcessStats{
+ unsigned int processId;
+ DWORD operationTime;
+ unsigned int relationId;
+};
+
+HANDLE StartTestsEvHandle = NULL;
+HANDLE hEventHandle = NULL;
+
+/* Results Buffer */
+ResultBuffer *resultBuffer = NULL;
+
+int testStatus;
+
+const char sTmpEventName[MAX_PATH_FNAME] = "StartTestEvent";
+
+void PALAPI Run_Thread(LPVOID lpParam);
+
+int GetParameters( int argc, char **argv)
+{
+ if( (argc != 5) || ((argc == 1) && !strcmp(argv[1],"/?"))
+ || !strcmp(argv[1],"/h") || !strcmp(argv[1],"/H"))
+ {
+ printf("PAL -Composite Object Management Event Test\n");
+ printf("Usage:\n");
+ printf("Event\n\t[USE_PROCESS_COUNT [greater than 1] \n");
+ printf("\t[THREAD_COUNT [greater than 1] \n");
+ printf("\t[REPEAT_COUNT [greater than 1]\n");
+ printf("\t[RELATION_ID [greater than or Equal to 1]\n");
+
+ return -1;
+ }
+
+ // Trace("Args 1 is [%s], Arg 2 is [%s], Arg 3 is [%s]\n", argv[1], argv[2], argv[3]);
+
+ USE_PROCESS_COUNT = atoi(argv[1]);
+ if( USE_PROCESS_COUNT < 0)
+ {
+ printf("\nInvalid USE_PROCESS_COUNT number, Pass greater than 1\n");
+ return -1;
+ }
+
+ THREAD_COUNT = atoi(argv[2]);
+ if( (THREAD_COUNT < 1) || (THREAD_COUNT > MAXIMUM_WAIT_OBJECTS) )
+ {
+ printf("\nInvalid THREAD_COUNT number, Pass greater than 1 and less than %d\n", MAXIMUM_WAIT_OBJECTS);
+ return -1;
+ }
+
+ REPEAT_COUNT = atoi(argv[3]);
+ if( REPEAT_COUNT < 1)
+ {
+ printf("\nInvalid REPEAT_COUNT number, Pass greater than 1\n");
+ return -1;
+ }
+
+ RELATION_ID = atoi(argv[4]);
+ if( RELATION_ID < 1)
+ {
+ printf("\nMain Process:Invalid RELATION_ID number, Pass greater than 1\n");
+ return -1;
+ }
+
+
+ return 0;
+}
+
+ int __cdecl main(INT argc, CHAR **argv)
+{
+ unsigned int i = 0;
+ HANDLE hThread[MAXIMUM_WAIT_OBJECTS];
+ DWORD threadId[MAXIMUM_WAIT_OBJECTS];
+ int returnCode = 0;
+
+ DWORD dwParam = 0;
+
+ /* Variables to capture the file name and the file pointer at thread level*/
+ char fileName[MAX_LONGPATH];
+ FILE *pFile = NULL;
+ struct statistics* buffer = NULL;
+ int statisticsSize = 0;
+
+ /* Variables to capture the file name and the file pointer at process level*/
+ char processFileName[MAX_LONGPATH];
+ FILE *pProcessFile = NULL;
+ struct ProcessStats processStats;
+ DWORD dwStartTime;
+
+ testStatus = PASS;
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return ( FAIL );
+ }
+
+ if(GetParameters(argc, argv))
+ {
+ Fail("Error in obtaining the parameters\n");
+ }
+// Trace("Process created, value of process count is [%d]\n", USE_PROCESS_COUNT);
+
+ /* Register the start time */
+ dwStartTime = GetTickCount();
+ processStats.relationId = RELATION_ID;
+ processStats.processId = USE_PROCESS_COUNT;
+
+ _snprintf(processFileName, MAX_LONGPATH, "%d_process_event_%d_.txt", USE_PROCESS_COUNT, RELATION_ID);
+ pProcessFile = fopen(processFileName, "w+");
+ if(pProcessFile == NULL)
+ {
+ Fail("Error in opening process File file for write for process [%d]\n", USE_PROCESS_COUNT);
+ }
+
+ statisticsSize = sizeof(struct statistics);
+
+ _snprintf(fileName, MAX_LONGPATH, "%d_thread_event_%d_.txt", USE_PROCESS_COUNT, RELATION_ID);
+ pFile = fopen(fileName, "w+");
+
+ if(pFile == NULL)
+ {
+ Fail("Error in opening thread File for write for process [%d]\n", USE_PROCESS_COUNT);
+ }
+ // For each thread we will log operations failed (int), passed (int), total (int)
+ // and number of ticks (DWORD) for the operations
+ resultBuffer = new ResultBuffer( THREAD_COUNT, statisticsSize);
+
+ StartTestsEvHandle = CreateEvent(
+ NULL, /* lpEventAttributes*/
+ TRUE, /* bManualReset */
+ FALSE, /* bInitialState */
+ NULL /* name of Event */
+ );
+
+ if( StartTestsEvHandle == NULL )
+ {
+ Fail("Error:%d: Unexpected failure "
+ "to create %s Event for process count %d\n", GetLastError(), sTmpEventName, USE_PROCESS_COUNT );
+
+ }
+
+ /* Create StartTest Event */
+
+ hEventHandle = CreateEvent(
+ NULL, /* lpEventAttributes, inheritable to child processes*/
+ TRUE, /* bAutomaticReset */
+ TRUE, /* bInitialState */
+ NULL
+ );
+
+ if( hEventHandle == NULL)
+ {
+ Fail("Unable to create Event handle for process id [%d], returned error [%d]\n", i, GetLastError());
+ }
+ /* We already assume that the Event was created previously*/
+
+ for( i = 0; i < THREAD_COUNT; i++ )
+ {
+ dwParam = (int) i;
+ //Create thread
+ hThread[i] = CreateThread(
+ NULL, /* no security attributes */
+ 0, /* use default stack size */
+ (LPTHREAD_START_ROUTINE)Run_Thread,/* thread function */
+ (LPVOID)dwParam, /* argument to thread function */
+ 0, /* use default creation flags */
+ &threadId[i] /* returns the thread identifier*/
+ );
+
+
+ if(hThread[i] == NULL)
+ {
+ Fail("Create Thread failed for %d process, and GetLastError value is %d\n", USE_PROCESS_COUNT, GetLastError());
+ }
+
+ }
+
+ if (!SetEvent(StartTestsEvHandle))
+ {
+ Fail("Set Event for Start Tests failed for %d process, and GetLastError value is %d\n", USE_PROCESS_COUNT, GetLastError());
+ }
+ /* Test running */
+ returnCode = WaitForMultipleObjects( THREAD_COUNT, hThread, TRUE, INFINITE);
+
+ if( WAIT_OBJECT_0 != returnCode )
+ {
+ Trace("Wait for Object(s) for %d process returned %d, and GetLastError value is %d\n", USE_PROCESS_COUNT, returnCode, GetLastError());
+ testStatus = FAIL;
+ }
+
+ processStats.operationTime = GetTimeDiff(dwStartTime);
+
+ /* Write to a file*/
+ if(pFile!= NULL)
+ {
+ for( i = 0; i < THREAD_COUNT; i++ )
+ {
+ buffer = (struct statistics *)resultBuffer->getResultBuffer(i);
+ returnCode = fprintf(pFile, "%d,%d,%d,%d,%lu,%d\n", buffer->processId, buffer->operationsFailed, buffer->operationsPassed, buffer->operationsTotal, buffer->operationTime, buffer->relationId );
+ //Trace("Iteration %d over\n", i);
+
+ }
+ }
+ if(fclose(pFile))
+ {
+ Trace("Error: fclose failed for pFile\n");
+ testStatus = FAIL;
+ }
+
+ fprintf(pProcessFile, "%d,%d,%d\n", USE_PROCESS_COUNT, processStats.operationTime, processStats.relationId );
+ if(fclose(pProcessFile))
+ {
+ Trace("Error: fclose failed for pProcessFile at Process %d\n", USE_PROCESS_COUNT);
+ testStatus = FAIL;
+ }
+
+ /* Logging for the test case over, clean up the handles */
+
+// Trace("Test Thread %d done\n", USE_PROCESS_COUNT);
+ /* Clean Up */
+ for( i = 0; i < THREAD_COUNT; i++ )
+ {
+ if(!CloseHandle(hThread[i]) )
+ {
+ Trace("Error:%d: CloseHandle failed for Process [%d] hThread[%d]\n", GetLastError(), USE_PROCESS_COUNT, i);
+ testStatus = FAIL;
+ }
+ }
+
+ if(!CloseHandle(StartTestsEvHandle))
+ {
+ Trace("Error:%d: CloseHandle failed for Process [%d] StartTestsEvHandle\n", GetLastError(), USE_PROCESS_COUNT);
+ testStatus = FAIL;
+ }
+
+ if(!CloseHandle(hEventHandle))
+ {
+ Trace("Error:%d: CloseHandle failed for Process [%d] hEventHandle\n", GetLastError(), USE_PROCESS_COUNT);
+ testStatus = FAIL;
+ }
+
+ PAL_Terminate();
+ return testStatus;
+
+}
+
+void PALAPI Run_Thread (LPVOID lpParam)
+{
+ unsigned int i = 0;
+ DWORD dwWaitResult;
+
+ struct statistics stats;
+ DWORD dwStartTime;
+
+ stats.relationId = RELATION_ID;
+ stats.processId = USE_PROCESS_COUNT;
+ stats.operationsFailed = 0;
+ stats.operationsPassed = 0;
+ stats.operationsTotal = 0;
+ stats.operationTime = 0;
+
+ int Id=(int)lpParam;
+
+ dwWaitResult = WaitForSingleObject(
+ StartTestsEvHandle, // handle to start test handle
+ TIMEOUT);
+
+ if(dwWaitResult != WAIT_OBJECT_0)
+ {
+ Fail("Error while waiting for StartTest Event@ thread %d, RC is %d, Error is %d\n", Id, dwWaitResult, GetLastError());
+ }
+
+ dwStartTime = GetTickCount();
+
+ for( i = 0; i < REPEAT_COUNT; i++ )
+ {
+ dwWaitResult = WaitForSingleObject(
+ hEventHandle, // handle to Event
+ TIMEOUT);
+
+ if(dwWaitResult != WAIT_OBJECT_0)
+ {
+// Trace("Error while waiting for onject @ thread %d, # iter %d, RC is %d, Error is %d\n", Id, i, dwWaitResult, GetLastError());
+ stats.operationsFailed += 1;
+ stats.operationsTotal += 1;
+ testStatus = FAIL;
+ continue;
+ }
+
+ if (! SetEvent(hEventHandle))
+ {
+ // Deal with error.
+// Trace("Error while setting Event @ thread %d # iter %d\n", Id, i);
+ stats.operationsFailed += 1;
+ stats.operationsTotal += 1;
+ // Do we need to have while true loop to attempt to set event?
+ testStatus = FAIL;
+ continue;
+ }
+
+ stats.operationsTotal += 1;
+ stats.operationsPassed += 1;
+// Trace("Successs while setting Event @ iteration %d -> thread %d -> Process %d\n", i, Id, USE_PROCESS_COUNT);
+
+ }
+
+ stats.operationTime = GetTimeDiff(dwStartTime);
+ if(resultBuffer->LogResult(Id, (char *)&stats))
+ {
+ Fail("Error:%d: while writing to shared memory, Thread Id is[%d] and Process id is [%d]\n", GetLastError(), Id, USE_PROCESS_COUNT);
+ }
+ //Trace("Thread %d over for process %d\n", Id, USE_PROCESS_COUNT);
+}
diff --git a/src/pal/tests/palsuite/composite/object_management/event/nonshared/main.c b/src/pal/tests/palsuite/composite/object_management/event/nonshared/main.c
new file mode 100644
index 0000000000..7b61e91737
--- /dev/null
+++ b/src/pal/tests/palsuite/composite/object_management/event/nonshared/main.c
@@ -0,0 +1,228 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source Code: main.c and event.c
+** main.c creates process and waits for all processes to get over
+** event.c creates a event and then calls threads which will contend for the event
+**
+** This test is for Object Management Test case for event where Object type is not shareable.
+** Algorithm
+** o Create PROCESS_COUNT processes.
+** o Main Thread of each process creates OBJECT_TYPE Object
+**
+** Author: ShamitP
+**============================================================
+*/
+
+#include <palsuite.h>
+#include "resulttime.h"
+
+/* Test Input Variables */
+unsigned int PROCESS_COUNT = 10;
+unsigned int THREAD_COUNT = 20;
+unsigned int REPEAT_COUNT = 20000;
+unsigned int RELATION_ID = 1001;
+
+
+struct TestStats{
+ DWORD operationTime;
+ unsigned int relationId;
+ unsigned int processCount;
+ unsigned int threadCount;
+ unsigned int repeatCount;
+ char* buildNumber;
+
+};
+
+
+int GetParameters( int argc, char **argv)
+{
+ if( (argc != 5) || ((argc == 1) && !strcmp(argv[1],"/?"))
+ || !strcmp(argv[1],"/h") || !strcmp(argv[1],"/H"))
+ {
+ printf("PAL -Composite Object Management event Test\n");
+ printf("Usage:\n");
+ printf("main\n\t[PROCESS_COUNT [greater than 1] \n");
+ printf("\t[THREAD_COUNT [greater than 1] \n");
+ printf("\t[REPEAT_COUNT [greater than 1]\n");
+ printf("\t[RELATION_ID [greater than or Equal to 1]\n");
+ return -1;
+ }
+
+ PROCESS_COUNT = atoi(argv[1]);
+ if( (PROCESS_COUNT < 1) || (PROCESS_COUNT > MAXIMUM_WAIT_OBJECTS) )
+ {
+ printf("\nMain Process:Invalid PROCESS_COUNT number, Pass greater than 1 and less than PROCESS_COUNT %d\n", MAXIMUM_WAIT_OBJECTS);
+ return -1;
+ }
+
+ THREAD_COUNT = atoi(argv[2]);
+ if( (THREAD_COUNT < 1) || (THREAD_COUNT > MAXIMUM_WAIT_OBJECTS) )
+ {
+ printf("\nInvalid THREAD_COUNT number, Pass greater than 1 and less than %d\n", MAXIMUM_WAIT_OBJECTS);
+ return -1;
+ }
+
+ REPEAT_COUNT = atoi(argv[3]);
+ if( REPEAT_COUNT < 1)
+ {
+ printf("\nMain Process:Invalid REPEAT_COUNT number, Pass greater than 1\n");
+ return -1;
+ }
+
+ RELATION_ID = atoi(argv[4]);
+ if( RELATION_ID < 1)
+ {
+ printf("\nMain Process:Invalid RELATION_ID number, Pass greater than 1\n");
+ return -1;
+ }
+
+
+ return 0;
+}
+
+ int __cdecl main(INT argc, CHAR **argv)
+{
+ unsigned int i = 0;
+ HANDLE hProcess[MAXIMUM_WAIT_OBJECTS];
+
+ STARTUPINFO si[MAXIMUM_WAIT_OBJECTS];
+ PROCESS_INFORMATION pi[MAXIMUM_WAIT_OBJECTS];
+
+ char lpCommandLine[MAX_LONGPATH] = "";
+ const char *ObjName = "Event";
+
+ int returnCode = 0;
+ DWORD processReturnCode = 0;
+ int testReturnCode = PASS;
+
+ char fileName[MAX_LONGPATH];
+ FILE *pFile = NULL;
+ DWORD dwStartTime = 0;
+ struct TestStats testStats;
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return ( FAIL );
+ }
+
+ if(GetParameters(argc, argv))
+ {
+ Fail("Error in obtaining the parameters\n");
+ }
+
+ /* Register the start time */
+ dwStartTime = GetTickCount();
+ testStats.relationId = RELATION_ID;
+ testStats.processCount = PROCESS_COUNT;
+ testStats.threadCount = THREAD_COUNT;
+ testStats.repeatCount = REPEAT_COUNT;
+ testStats.buildNumber = getBuildNumber();
+
+
+ _snprintf(fileName, MAX_LONGPATH, "main_event_%d_.txt", RELATION_ID);
+ pFile = fopen(fileName, "w+");
+ if(pFile == NULL)
+ {
+ Fail("Error in opening main file for write\n");
+ }
+
+ for( i = 0; i < PROCESS_COUNT; i++ )
+ {
+
+ ZeroMemory( lpCommandLine, MAX_PATH );
+ if ( _snprintf( lpCommandLine, MAX_LONGPATH-1, "event %d %d %d %d", i, THREAD_COUNT, REPEAT_COUNT, RELATION_ID) < 0 )
+ {
+ Fail ("Error: Insufficient Event name string length for %s for iteration [%d]\n", ObjName, i);
+ }
+
+ /* Zero the data structure space */
+ ZeroMemory ( &pi[i], sizeof(pi[i]) );
+ ZeroMemory ( &si[i], sizeof(si[i]) );
+
+ /* Set the process flags and standard io handles */
+ si[i].cb = sizeof(si[i]);
+
+ //Create Process
+ if(!CreateProcess( NULL, /* lpApplicationName*/
+ lpCommandLine, /* lpCommandLine */
+ NULL, /* lpProcessAttributes */
+ NULL, /* lpThreadAttributes */
+ TRUE, /* bInheritHandles */
+ 0, /* dwCreationFlags, */
+ NULL, /* lpEnvironment */
+ NULL, /* pCurrentDirectory */
+ &si[i], /* lpStartupInfo */
+ &pi[i] /* lpProcessInformation */
+ ))
+ {
+ Fail("Process Not created for [%d], the error code is [%d]\n", i, GetLastError());
+ }
+ else
+ {
+ hProcess[i] = pi[i].hProcess;
+ //Trace("Process created for [%d]\n", i);
+
+ }
+
+ }
+
+ returnCode = WaitForMultipleObjects( PROCESS_COUNT, hProcess, TRUE, INFINITE);
+ if( WAIT_OBJECT_0 != returnCode )
+ {
+ Trace("Wait for Object(s) @ Main thread for %d processes returned %d, and GetLastError value is %d\n", PROCESS_COUNT, returnCode, GetLastError());
+ testReturnCode = FAIL;
+ }
+
+ for( i = 0; i < PROCESS_COUNT; i++ )
+ {
+ /* check the exit code from the process */
+ if( ! GetExitCodeProcess( pi[i].hProcess, &processReturnCode ) )
+ {
+ Trace( "GetExitCodeProcess call failed for iteration %d with error code %u\n",
+ i, GetLastError() );
+
+ testReturnCode = FAIL;
+ }
+
+ if(processReturnCode == FAIL)
+ {
+ Trace( "Process [%d] failed and returned FAIL\n", i);
+ testReturnCode = FAIL;
+ }
+
+ if(!CloseHandle(pi[i].hThread))
+ {
+ Trace("Error:%d: CloseHandle failed for Process [%d] hThread\n", GetLastError(), i);
+ testReturnCode = FAIL;
+ }
+
+ if(!CloseHandle(pi[i].hProcess) )
+ {
+ Trace("Error:%d: CloseHandle failed for Process [%d] hProcess\n", GetLastError(), i);
+ testReturnCode = FAIL;
+ }
+ }
+
+ testStats.operationTime = GetTimeDiff(dwStartTime);
+ fprintf(pFile, "%d,%d,%d,%d,%d,%s\n", testStats.operationTime, testStats.relationId, testStats.processCount, testStats.threadCount, testStats.repeatCount, testStats.buildNumber);
+ if(fclose(pFile))
+ {
+ Trace("Error: fclose failed for pFile\n");
+ testReturnCode = FAIL;
+ }
+
+ if( testReturnCode == PASS)
+ {
+ Trace("Test Passed\n");
+ }
+ else
+ {
+ Trace("Test Failed\n");
+ }
+ PAL_Terminate();
+ return testReturnCode;
+}
diff --git a/src/pal/tests/palsuite/composite/object_management/event/shared/CMakeLists.txt b/src/pal/tests/palsuite/composite/object_management/event/shared/CMakeLists.txt
new file mode 100644
index 0000000000..d326e3a42b
--- /dev/null
+++ b/src/pal/tests/palsuite/composite/object_management/event/shared/CMakeLists.txt
@@ -0,0 +1,21 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ event.c
+ main.c
+)
+
+add_executable(paltest_event_shared
+ ${SOURCES}
+)
+
+add_dependencies(paltest_event_shared coreclrpal)
+
+target_link_libraries(paltest_event_shared
+ pthread
+ rt
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/composite/object_management/event/shared/event.c b/src/pal/tests/palsuite/composite/object_management/event/shared/event.c
new file mode 100644
index 0000000000..83d5fce27e
--- /dev/null
+++ b/src/pal/tests/palsuite/composite/object_management/event/shared/event.c
@@ -0,0 +1,373 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source Code: main.c and event.c
+** main.c creates process and waits for all processes to get over
+** event.c creates a event and then calls threads which will contend for the event
+**
+** This test is for Object Management Test case for event where Object type is shareable.
+** Algorithm
+** o Main Process Creates OBJECT_TYPE Object
+** o Create PROCESS_COUNT processes aware of the Shared Object
+**
+** Author: ShamitP
+** Author: ShamitP
+**
+**
+**============================================================
+*/
+
+#include <palsuite.h>
+#include "resultbuffer.h"
+#include "resulttime.h"
+
+#define TIMEOUT 5000
+/* Test Input Variables */
+unsigned int USE_PROCESS_COUNT = 0;
+unsigned int THREAD_COUNT = 0;
+unsigned int REPEAT_COUNT = 0;
+unsigned int RELATION_ID = 0;
+
+/* Capture statistics at per thread basis */
+struct statistics{
+ unsigned int processId;
+ unsigned int operationsFailed;
+ unsigned int operationsPassed;
+ unsigned int operationsTotal;
+ DWORD operationTime;
+ unsigned int relationId;
+};
+
+struct ProcessStats{
+ unsigned int processId;
+ DWORD operationTime;
+ unsigned int relationId;
+};
+
+HANDLE StartTestsEvHandle = NULL;
+HANDLE hEventHandle = NULL;
+
+/* Results Buffer */
+ResultBuffer *resultBuffer= NULL;
+
+int testStatus;
+
+const char sTmpEventName[MAX_PATH] = "StartTestEvent";
+char objectSuffix[MAX_PATH];
+
+void PALAPI Run_Thread(LPVOID lpParam);
+
+int GetParameters( int argc, char **argv)
+{
+ if( (!((argc == 5) || (argc == 6) ) )|| ((argc == 1) && !strcmp(argv[1],"/?"))
+ || !strcmp(argv[1],"/h") || !strcmp(argv[1],"/H"))
+ {
+ printf("PAL -Composite Object Management event Test\n");
+ printf("Usage:\n");
+ printf("main\n\t[USE_PROCESS_COUNT (greater than 1)] \n");
+ printf("\t[THREAD_COUNT (greater than 1)] \n");
+ printf("\t[REPEAT_COUNT (greater than 1)]\n");
+ printf("\t[RELATION_ID [greater than or equal to 1]\n");
+ printf("\t[Object Name Suffix]\n");
+
+ return -1;
+ }
+
+ // Trace("Args 1 is [%s], Arg 2 is [%s], Arg 3 is [%s]\n", argv[1], argv[2], argv[3]);
+
+ USE_PROCESS_COUNT = atoi(argv[1]);
+ if( USE_PROCESS_COUNT < 0)
+ {
+ printf("\nInvalid USE_PROCESS_COUNT number, Pass greater than 1\n");
+ return -1;
+ }
+
+ THREAD_COUNT = atoi(argv[2]);
+ if( (THREAD_COUNT < 1) || (THREAD_COUNT > MAXIMUM_WAIT_OBJECTS) )
+ {
+ printf("\nInvalid THREAD_COUNT number, Pass greater than 1 and less than %d\n", MAXIMUM_WAIT_OBJECTS);
+ return -1;
+ }
+
+ REPEAT_COUNT = atoi(argv[3]);
+ if( REPEAT_COUNT < 1)
+ {
+ printf("\nInvalid REPEAT_COUNT number, Pass greater than 1\n");
+ return -1;
+ }
+
+ RELATION_ID = atoi(argv[4]);
+ if( RELATION_ID < 1)
+ {
+ printf("\nMain Process:Invalid RELATION_ID number, Pass greater than 1\n");
+ return -1;
+ }
+
+ if(argc == 6)
+ {
+ strncpy(objectSuffix, argv[5], MAX_PATH-1);
+ }
+
+ return 0;
+}
+
+ int __cdecl main(INT argc, CHAR **argv)
+{
+ unsigned int i = 0;
+ HANDLE hThread[MAXIMUM_WAIT_OBJECTS];
+ DWORD threadId[MAXIMUM_WAIT_OBJECTS];
+
+ WCHAR *wcObjName = NULL;
+
+ char ObjName[MAX_PATH] = "SHARED_EVENT";
+ DWORD dwParam = 0;
+
+ int returnCode = 0;
+
+ /* Variables to capture the file name and the file pointer at thread level*/
+ char fileName[MAX_PATH];
+ FILE *pFile = NULL;
+ struct statistics* buffer = NULL;
+ int statisticsSize = 0;
+
+ /* Variables to capture the file name and the file pointer at process level*/
+ char processFileName[MAX_PATH];
+ FILE *pProcessFile = NULL;
+ struct ProcessStats processStats;
+ DWORD dwStartTime;
+
+ testStatus = PASS;
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return ( FAIL );
+ }
+
+ ZeroMemory( objectSuffix, MAX_PATH );
+
+ if(GetParameters(argc, argv))
+ {
+ Fail("Error in obtaining the parameters\n");
+ }
+// Trace("Process created, value of process count is [%d]\n", USE_PROCESS_COUNT);
+
+ if(argc == 5)
+ {
+ strncat(ObjName, objectSuffix, MAX_PATH - (sizeof(ObjName) + 1) );
+ }
+
+ /* Register the start time */
+ dwStartTime = GetTickCount();
+ processStats.relationId = RELATION_ID;
+ processStats.processId = USE_PROCESS_COUNT;
+
+ _snprintf(processFileName, MAX_PATH, "%d_process_event_%d_.txt", USE_PROCESS_COUNT, RELATION_ID);
+ pProcessFile = fopen(processFileName, "w+");
+ if(pProcessFile == NULL)
+ {
+ Fail("Error:%d: in opening Process File for write for process [%d]\n", GetLastError(), USE_PROCESS_COUNT);
+ }
+
+ statisticsSize = sizeof(struct statistics);
+
+ _snprintf(fileName, MAX_PATH, "%d_thread_event_%d_.txt", USE_PROCESS_COUNT, RELATION_ID);
+ pFile = fopen(fileName, "w+");
+
+ if(pFile == NULL)
+ {
+ Fail("Error:%d: in opening thread file for write for process [%d]\n", GetLastError(), USE_PROCESS_COUNT);
+ }
+ // For each thread we will log operations failed (int), passed (int), total (int)
+ // and number of ticks (DWORD) for the operations
+ resultBuffer = new ResultBuffer( THREAD_COUNT, statisticsSize);
+
+ wcObjName = convert(ObjName);
+
+ StartTestsEvHandle = CreateEvent( NULL, /* lpEventAttributes*/
+ TRUE, /* bManualReset */
+ FALSE, /* bInitialState */
+ NULL); /* name of Event */
+
+ if( StartTestsEvHandle == NULL )
+ {
+ Fail("Error:%d: Unexpected failure "
+ "to create %s Event for process count %d\n", GetLastError(), sTmpEventName, USE_PROCESS_COUNT );
+
+ }
+
+ /* Create StartTest Event */
+
+ hEventHandle = OpenEventW(
+ EVENT_ALL_ACCESS, /* lpEventAttributes, inheritable to child processes*/
+ FALSE, /* bAutomaticReset */
+ wcObjName
+ );
+
+ if( hEventHandle == NULL)
+ {
+ Fail("Unable to create Event handle for process id [%d], returned error [%d]\n", i, GetLastError());
+ }
+ /* We already assume that the Event was created previously*/
+
+ for( i = 0; i < THREAD_COUNT; i++ )
+ {
+ dwParam = (int) i;
+ //Create thread
+ hThread[i] = CreateThread(
+ NULL, /* no security attributes */
+ 0, /* use default stack size */
+ (LPTHREAD_START_ROUTINE)Run_Thread,/* thread function */
+ (LPVOID)dwParam, /* argument to thread function */
+ 0, /* use default creation flags */
+ &threadId[i] /* returns the thread identifier*/
+ );
+
+ if(hThread[i] == NULL)
+ {
+ Fail("Create Thread failed for %d process, and GetLastError value is %d\n", USE_PROCESS_COUNT, GetLastError());
+ }
+
+ }
+
+ if (!SetEvent(StartTestsEvHandle))
+ {
+ Fail("Set Event for Start Tests failed for %d process, and GetLastError value is %d\n", USE_PROCESS_COUNT, GetLastError());
+ }
+
+ /* Test running */
+ returnCode = WaitForMultipleObjects( THREAD_COUNT, hThread, TRUE, INFINITE);
+
+ if( WAIT_OBJECT_0 != returnCode )
+ {
+ Trace("Wait for Object(s) for %d process returned %d, and GetLastError value is %d\n", USE_PROCESS_COUNT, returnCode, GetLastError());
+ testStatus = FAIL;
+ }
+
+ processStats.operationTime = GetTimeDiff(dwStartTime);
+
+ /* Write to a file*/
+ if(pFile!= NULL)
+ {
+ for( i = 0; i < THREAD_COUNT; i++ )
+ {
+ buffer = (struct statistics *)resultBuffer->getResultBuffer(i);
+ returnCode = fprintf(pFile, "%d,%d,%d,%d,%lu,%d\n", buffer->processId, buffer->operationsFailed, buffer->operationsPassed, buffer->operationsTotal, buffer->operationTime, buffer->relationId );
+// Trace("Iteration %d over\n", i);
+
+ }
+ }
+
+ if(fclose(pFile))
+ {
+ Trace("Error: fclose failed for pFile at Process %d\n", USE_PROCESS_COUNT);
+ testStatus = FAIL;
+ }
+
+ fprintf(pProcessFile, "%d,%d,%d\n", USE_PROCESS_COUNT, processStats.operationTime, processStats.relationId );
+ if(fclose(pProcessFile))
+ {
+ Trace("Error: fclose failed for pProcessFile at Process %d\n", USE_PROCESS_COUNT);
+ testStatus = FAIL;
+ }
+ /* Logging for the test case over, clean up the handles */
+
+// Trace("Test Thread %d done\n", USE_PROCESS_COUNT);
+
+ for( i = 0; i < THREAD_COUNT; i++ )
+ {
+ if(!CloseHandle(hThread[i]) )
+ {
+ Trace("Error:%d: CloseHandle failed for Process [%d] hThread[%d]\n", GetLastError(), USE_PROCESS_COUNT, i);
+ testStatus = FAIL;
+ }
+ }
+
+ if(!CloseHandle(StartTestsEvHandle))
+ {
+ Trace("Error:%d: CloseHandle failed for Process [%d] StartTestsEvHandle\n", GetLastError(), USE_PROCESS_COUNT);
+ testStatus = FAIL;
+ }
+
+ if(!CloseHandle(hEventHandle))
+ {
+ Trace("Error:%d: CloseHandle failed for Process [%d] hEventHandle\n", GetLastError(), USE_PROCESS_COUNT);
+ testStatus = FAIL;
+ }
+
+ free(wcObjName);
+ PAL_Terminate();
+ return testStatus;
+}
+
+void PALAPI Run_Thread (LPVOID lpParam)
+{
+ unsigned int i = 0;
+ DWORD dwWaitResult;
+
+ struct statistics stats;
+ DWORD dwStartTime;
+
+ stats.relationId = RELATION_ID;
+ stats.processId = USE_PROCESS_COUNT;
+ stats.operationsFailed = 0;
+ stats.operationsPassed = 0;
+ stats.operationsTotal = 0;
+ stats.operationTime = 0;
+
+ int Id=(int)lpParam;
+
+ dwWaitResult = WaitForSingleObject(
+ StartTestsEvHandle, // handle to start test handle
+ TIMEOUT);
+
+ if(dwWaitResult != WAIT_OBJECT_0)
+ {
+ Trace("Error:%d: while waiting for StartTest Event@ thread %d\n", GetLastError(), Id);
+ testStatus = FAIL;
+ }
+
+ dwStartTime = GetTickCount();
+
+ for( i = 0; i < REPEAT_COUNT; i++ )
+ {
+ dwWaitResult = WaitForSingleObject(
+ hEventHandle, // handle to Event
+ TIMEOUT);
+
+ if(dwWaitResult != WAIT_OBJECT_0)
+ {
+ //Trace("Error:%d: while waiting for onject @ thread %d, # iter %d\n", GetLastError(), Id, i);
+ stats.operationsFailed += 1;
+ stats.operationsTotal += 1;
+ testStatus = FAIL;
+ continue;
+ }
+
+ if (! SetEvent(hEventHandle))
+ {
+ // Deal with error.
+// Trace("Error while setting Event @ thread %d # iter %d\n", Id, i);
+ stats.operationsFailed += 1;
+ stats.operationsTotal += 1;
+ // do we need to have while true loop to attempt to set event...?
+ testStatus = FAIL;
+ continue;
+ }
+
+ stats.operationsTotal += 1;
+ stats.operationsPassed += 1;
+ // Trace("Successs while setting Event @ iteration %d -> thread %d -> Process %d for handle %d\n", i, Id, USE_PROCESS_COUNT, hEventHandle);
+
+ }
+
+ stats.operationTime = GetTimeDiff(dwStartTime);
+ //Trace("OPeration time is %d", stats.operationTime );
+ if(resultBuffer->LogResult(Id, (char *)&stats))
+ {
+ Fail("Error:%d: while writing to shared memory, Thread Id is[%d] and Process id is [%d]\n", GetLastError(), Id, USE_PROCESS_COUNT);
+ }
+ //Trace("Thread %d over for process %d\n", Id, USE_PROCESS_COUNT);
+}
diff --git a/src/pal/tests/palsuite/composite/object_management/event/shared/main.c b/src/pal/tests/palsuite/composite/object_management/event/shared/main.c
new file mode 100644
index 0000000000..c4a4067b5d
--- /dev/null
+++ b/src/pal/tests/palsuite/composite/object_management/event/shared/main.c
@@ -0,0 +1,265 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source Code: main.c and event.c
+** main.c creates process and waits for all processes to get over
+** event.c creates a event and then calls threads which will contend for the event
+**
+** This test is for Object Management Test case for event where Object type is shareable.
+** Algorithm
+** o Main Process Creates OBJECT_TYPE Object
+** o Create PROCESS_COUNT processes aware of the Shared Object
+**
+** Author: ShamitP
+**
+**
+**============================================================
+*/
+#include <palsuite.h>
+#include "resulttime.h"
+
+/* Test Input Variables */
+unsigned int PROCESS_COUNT = 2;
+unsigned int THREAD_COUNT = 20;
+unsigned int REPEAT_COUNT = 200;
+unsigned int RELATION_ID = 1001;
+
+
+char objectSuffix[MAX_PATH_FNAME];
+
+struct TestStats{
+ DWORD operationTime;
+ unsigned int relationId;
+ unsigned int processCount;
+ unsigned int threadCount;
+ unsigned int repeatCount;
+ char* buildNumber;
+
+};
+
+int GetParameters( int argc, char **argv)
+{
+ if( (!((argc == 5) || (argc == 6) ) )|| ((argc == 1) && !strcmp(argv[1],"/?"))
+ || !strcmp(argv[1],"/h") || !strcmp(argv[1],"/H"))
+ {
+ printf("PAL -Composite Object Management event Test\n");
+ printf("Usage:\n");
+ printf("main\n\t[PROCESS_COUNT (greater than 1)] \n");
+ printf("\t[THREAD_COUNT (greater than 1)] \n");
+ printf("\t[REPEAT_COUNT (greater than 1)]\n");
+ printf("\t[RELATION_ID [greater than or equal to 1]\n");
+ printf("\t[Object Name Suffix]\n");
+ return -1;
+ }
+
+ PROCESS_COUNT = atoi(argv[1]);
+ if( (PROCESS_COUNT < 1) || (PROCESS_COUNT > MAXIMUM_WAIT_OBJECTS) )
+ {
+ printf("\nMain Process:Invalid PROCESS_COUNT number, Pass greater than 1 and less than PROCESS_COUNT %d\n", MAXIMUM_WAIT_OBJECTS);
+ return -1;
+ }
+
+ THREAD_COUNT = atoi(argv[2]);
+ if( (THREAD_COUNT < 1) || (THREAD_COUNT > MAXIMUM_WAIT_OBJECTS) )
+ {
+ printf("\nInvalid THREAD_COUNT number, Pass greater than 1 and less than %d\n", MAXIMUM_WAIT_OBJECTS);
+ return -1;
+ }
+
+ REPEAT_COUNT = atoi(argv[3]);
+ if( REPEAT_COUNT < 1)
+ {
+ printf("\nMain Process:Invalid REPEAT_COUNT number, Pass greater than 1\n");
+ return -1;
+ }
+
+ RELATION_ID = atoi(argv[4]);
+ if( RELATION_ID < 1)
+ {
+ printf("\nMain Process:Invalid RELATION_ID number, Pass greater than 1\n");
+ return -1;
+ }
+
+
+ if(argc == 6)
+ {
+ strncpy(objectSuffix, argv[5], MAX_PATH_FNAME-1);
+ }
+
+ return 0;
+}
+
+ int __cdecl main(INT argc, CHAR **argv)
+{
+ unsigned int i = 0;
+ HANDLE hProcess[MAXIMUM_WAIT_OBJECTS];
+ HANDLE hEventHandle;
+
+ STARTUPINFO si[MAXIMUM_WAIT_OBJECTS];
+ PROCESS_INFORMATION pi[MAXIMUM_WAIT_OBJECTS];
+
+ char lpCommandLine[MAX_LONGPATH] = "";
+ char ObjName[MAX_PATH_FNAME] = "SHARED_EVENT";
+
+ int returnCode = 0;
+ DWORD processReturnCode = 0;
+ int testReturnCode = PASS;
+
+ char fileName[MAX_PATH_FNAME];
+ FILE *pFile = NULL;
+ DWORD dwStartTime;
+ struct TestStats testStats;
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return ( FAIL );
+ }
+
+ ZeroMemory( objectSuffix, MAX_PATH_FNAME );
+
+ if(GetParameters(argc, argv))
+ {
+ Fail("Error in obtaining the parameters\n");
+ }
+
+ if(argc == 5)
+ {
+ strncat(ObjName, objectSuffix, MAX_PATH_FNAME - (sizeof(ObjName) + 1) );
+ }
+
+ /* Register the start time */
+ dwStartTime = GetTickCount();
+ testStats.relationId = RELATION_ID;
+ testStats.processCount = PROCESS_COUNT;
+ testStats.threadCount = THREAD_COUNT;
+ testStats.repeatCount = REPEAT_COUNT;
+ testStats.buildNumber = getBuildNumber();
+
+
+ _snprintf(fileName, MAX_PATH_FNAME, "main_event_%d_.txt", RELATION_ID);
+ pFile = fopen(fileName, "w+");
+ if(pFile == NULL)
+ {
+ Fail("Error in opening main file for write\n");
+ }
+
+ hEventHandle = CreateEvent(
+ NULL, /* lpEventAttributes, inheritable to child processes*/
+ TRUE, /* bAutomaticReset */
+ TRUE, /* bInitialState */
+ ObjName
+ );
+
+ if( hEventHandle == NULL)
+ {
+ Fail("Unable to create Event handle, returned error [%d]\n", GetLastError());
+ }
+
+ for( i = 0; i < PROCESS_COUNT; i++ )
+ {
+
+ ZeroMemory( lpCommandLine, MAX_PATH_FNAME );
+ if ( _snprintf( lpCommandLine, MAX_PATH_FNAME-1, "event %d %d %d %d %s", i, THREAD_COUNT, REPEAT_COUNT, RELATION_ID, objectSuffix) < 0 )
+ {
+ Fail ("Error: Insufficient Event name string length for %s for iteration [%d]\n", ObjName, i);
+ }
+
+ /* Zero the data structure space */
+ ZeroMemory ( &pi[i], sizeof(pi[i]) );
+ ZeroMemory ( &si[i], sizeof(si[i]) );
+
+ /* Set the process flags and standard io handles */
+ si[i].cb = sizeof(si[i]);
+
+ if(!CreateProcess( NULL, /* lpApplicationName*/
+ lpCommandLine, /* lpCommandLine */
+ NULL, /* lpProcessAttributes */
+ NULL, /* lpThreadAttributes */
+ TRUE, /* bInheritHandles */
+ 0, /* dwCreationFlags, */
+ NULL, /* lpEnvironment */
+ NULL, /* pCurrentDirectory */
+ &si[i], /* lpStartupInfo */
+ &pi[i] /* lpProcessInformation */
+ ))
+ {
+ Fail("Process Not created for [%d], the error code is [%d]\n", i, GetLastError());
+ }
+ else
+ {
+ hProcess[i] = pi[i].hProcess;
+// Trace("Process created for [%d]\n", i);
+
+ }
+
+ //Create Process
+
+ }
+
+ returnCode = WaitForMultipleObjects( PROCESS_COUNT, hProcess, TRUE, INFINITE);
+ if( WAIT_OBJECT_0 != returnCode )
+ {
+ Trace("Wait for Object(s) @ Main thread for %d processes returned %d, and GetLastError value is %d\n", PROCESS_COUNT, returnCode, GetLastError());
+ testReturnCode = FAIL;
+ }
+
+// Trace("Test over\n");
+ for( i = 0; i < PROCESS_COUNT; i++ )
+ {
+ /* check the exit code from the process */
+ if( ! GetExitCodeProcess( pi[i].hProcess, &processReturnCode ) )
+ {
+ Trace( "GetExitCodeProcess call failed for iteration %d with error code %u\n",
+ i, GetLastError() );
+
+ testReturnCode = FAIL;
+ }
+
+ if(processReturnCode == FAIL)
+ {
+ Trace( "Process [%d] failed and returned FAIL\n", i);
+ testReturnCode = FAIL;
+ }
+
+ if(!CloseHandle(pi[i].hThread))
+ {
+ Trace("Error:%d: CloseHandle failed for Process [%d] hThread\n", GetLastError(), i);
+ testReturnCode = FAIL;
+ }
+
+ if(!CloseHandle(pi[i].hProcess) )
+ {
+ Trace("Error:%d: CloseHandle failed for Process [%d] hProcess\n", GetLastError(), i);
+ testReturnCode = FAIL;
+ }
+ }
+
+ testStats.operationTime = GetTimeDiff(dwStartTime);
+ fprintf(pFile, "%d,%d,%d,%d,%d,%s\n", testStats.operationTime, testStats.relationId, testStats.processCount, testStats.threadCount, testStats.repeatCount, testStats.buildNumber);
+ if(fclose(pFile))
+ {
+ Trace("Error: fclose failed for pFile\n");
+ testReturnCode = FAIL;
+ }
+
+ if(!CloseHandle(hEventHandle))
+ {
+ Trace("Error:%d: CloseHandle failed for hEventHandle\n", GetLastError());
+ testReturnCode = FAIL;
+ }
+
+ if( testReturnCode == PASS)
+ {
+ Trace("Test Passed\n");
+ }
+ else
+ {
+ Trace("Test Failed\n");
+ }
+
+ PAL_Terminate();
+ return testReturnCode;
+}
diff --git a/src/pal/tests/palsuite/composite/object_management/mutex/CMakeLists.txt b/src/pal/tests/palsuite/composite/object_management/mutex/CMakeLists.txt
new file mode 100644
index 0000000000..2534564f95
--- /dev/null
+++ b/src/pal/tests/palsuite/composite/object_management/mutex/CMakeLists.txt
@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(nonshared)
+add_subdirectory(shared)
+
diff --git a/src/pal/tests/palsuite/composite/object_management/mutex/nonshared/CMakeLists.txt b/src/pal/tests/palsuite/composite/object_management/mutex/nonshared/CMakeLists.txt
new file mode 100644
index 0000000000..7859cd4653
--- /dev/null
+++ b/src/pal/tests/palsuite/composite/object_management/mutex/nonshared/CMakeLists.txt
@@ -0,0 +1,21 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ main.c
+ mutex.c
+)
+
+add_executable(paltest_mutex_nonshared
+ ${SOURCES}
+)
+
+add_dependencies(paltest_mutex_nonshared coreclrpal)
+
+target_link_libraries(paltest_mutex_nonshared
+ pthread
+ rt
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/composite/object_management/mutex/nonshared/main.c b/src/pal/tests/palsuite/composite/object_management/mutex/nonshared/main.c
new file mode 100644
index 0000000000..80f31aad6e
--- /dev/null
+++ b/src/pal/tests/palsuite/composite/object_management/mutex/nonshared/main.c
@@ -0,0 +1,230 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source Code: main.c and mutex.c
+** main.c creates process and waits for all processes to get over
+** mutex.c creates a mutex and then calls threads which will contend for the mutex
+**
+** This test is for Object Management Test case for Mutex where Object type is not shareable.
+** Algorithm
+** o Create PROCESS_COUNT processes.
+** o Main Thread of each process creates OBJECT_TYPE Object
+**
+** Author: ShamitP
+**============================================================
+*/
+
+#include <palsuite.h>
+#include "resulttime.h"
+
+/* Test Input Variables */
+unsigned int PROCESS_COUNT = 2;
+unsigned int THREAD_COUNT = 20;
+unsigned int REPEAT_COUNT = 4000;
+unsigned int RELATION_ID = 1001;
+
+
+struct TestStats{
+ DWORD operationTime;
+ unsigned int relationId;
+ unsigned int processCount;
+ unsigned int threadCount;
+ unsigned int repeatCount;
+ char* buildNumber;
+
+};
+
+int GetParameters( int argc, char **argv)
+{
+ if( (argc != 5) || ((argc == 1) && !strcmp(argv[1],"/?"))
+ || !strcmp(argv[1],"/h") || !strcmp(argv[1],"/H"))
+ {
+ printf("PAL -Composite Object Management Mutex Test\n");
+ printf("Usage:\n");
+ printf("main\n\t[PROCESS_COUNT [greater than 1] \n");
+ printf("\t[THREAD_COUNT [greater than 1] \n");
+ printf("\t[REPEAT_COUNT [greater than 1]\n");
+ printf("\t[RELATION_ID [greater than 1]\n");
+
+
+ return -1;
+ }
+
+ PROCESS_COUNT = atoi(argv[1]);
+ if( (PROCESS_COUNT < 1) || (PROCESS_COUNT > MAXIMUM_WAIT_OBJECTS) )
+ {
+ printf("\nMain Process:Invalid PROCESS_COUNT number, Pass greater than 1 and less than PROCESS_COUNT %d\n", MAXIMUM_WAIT_OBJECTS);
+ return -1;
+ }
+
+ THREAD_COUNT = atoi(argv[2]);
+ if( (THREAD_COUNT < 1) || (THREAD_COUNT > MAXIMUM_WAIT_OBJECTS) )
+ {
+ printf("\nInvalid THREAD_COUNT number, Pass greater than 1 and less than %d\n", MAXIMUM_WAIT_OBJECTS);
+ return -1;
+ }
+
+ REPEAT_COUNT = atoi(argv[3]);
+ if( REPEAT_COUNT < 1)
+ {
+ printf("\nMain Process:Invalid REPEAT_COUNT number, Pass greater than 1\n");
+ return -1;
+ }
+
+ RELATION_ID = atoi(argv[4]);
+ if( RELATION_ID < 1)
+ {
+ printf("\nMain Process:Invalid RELATION_ID number, Pass greater than 1\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+ int __cdecl main(INT argc, CHAR **argv)
+{
+ unsigned int i = 0;
+ HANDLE hProcess[MAXIMUM_WAIT_OBJECTS];
+ HANDLE hMutexHandle[MAXIMUM_WAIT_OBJECTS];
+
+ STARTUPINFO si[MAXIMUM_WAIT_OBJECTS];
+ PROCESS_INFORMATION pi[MAXIMUM_WAIT_OBJECTS];
+
+ const char *ObjName = "Mutex";
+ char lpCommandLine[MAX_PATH] = "";
+
+ int returnCode = 0;
+ DWORD processReturnCode = 0;
+ int testReturnCode = PASS;
+
+ char fileName[MAX_PATH];
+ FILE *pFile = NULL;
+ DWORD dwStartTime;
+ struct TestStats testStats;
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return ( FAIL );
+ }
+
+ if(GetParameters(argc, argv))
+ {
+ Fail("Error in obtaining the parameters\n");
+ }
+
+ /* Register the start time */
+ dwStartTime = GetTickCount();
+ testStats.relationId = RELATION_ID;
+ testStats.processCount = PROCESS_COUNT;
+ testStats.threadCount = THREAD_COUNT;
+ testStats.repeatCount = REPEAT_COUNT;
+ testStats.buildNumber = getBuildNumber();
+
+
+ _snprintf(fileName, MAX_PATH, "main_mutex_%d_.txt", RELATION_ID);
+ pFile = fopen(fileName, "w+");
+ if(pFile == NULL)
+ {
+ Fail("Error in opening main file for write\n");
+ }
+
+ for( i = 0; i < PROCESS_COUNT; i++ )
+ {
+ ZeroMemory( lpCommandLine, MAX_PATH );
+ if ( _snprintf( lpCommandLine, MAX_PATH-1, "mutex %d %d %d %d", i, THREAD_COUNT, REPEAT_COUNT, RELATION_ID) < 0 )
+ {
+ Fail("Error Insufficient mutex name string length for %s for iteration [%d]\n", ObjName, i);
+ }
+
+ /* Zero the data structure space */
+ ZeroMemory ( &pi[i], sizeof(pi[i]) );
+ ZeroMemory ( &si[i], sizeof(si[i]) );
+
+ /* Set the process flags and standard io handles */
+ si[i].cb = sizeof(si[i]);
+
+ if(!CreateProcess( NULL, /* lpApplicationName*/
+ lpCommandLine, /* lpCommandLine */
+ NULL, /* lpProcessAttributes */
+ NULL, /* lpThreadAttributes */
+ TRUE, /* bInheritHandles */
+ 0, /* dwCreationFlags, */
+ NULL, /* lpEnvironment */
+ NULL, /* pCurrentDirectory */
+ &si[i], /* lpStartupInfo */
+ &pi[i] /* lpProcessInformation */
+ ))
+ {
+ Fail("Process Not created for [%d], the error code is [%d]\n", i, GetLastError());
+ }
+ else
+ {
+ hProcess[i] = pi[i].hProcess;
+// Trace("Process created for [%d]\n", i);
+
+ }
+
+ //Create Process
+
+ }
+
+ returnCode = WaitForMultipleObjects( PROCESS_COUNT, hProcess, TRUE, INFINITE);
+ if( WAIT_OBJECT_0 != returnCode )
+ {
+ Trace("Wait for Object(s) @ Main thread for %d processes returned %d, and GetLastError value is %d\n", PROCESS_COUNT, returnCode, GetLastError());
+ testReturnCode = FAIL;
+ }
+
+ for( i = 0; i < PROCESS_COUNT; i++ )
+ {
+ /* check the exit code from the process */
+ if( ! GetExitCodeProcess( pi[i].hProcess, &processReturnCode ) )
+ {
+ Trace( "GetExitCodeProcess call failed for iteration %d with error code %u\n",
+ i, GetLastError() );
+
+ testReturnCode = FAIL;
+ }
+
+ if(processReturnCode == FAIL)
+ {
+ Trace( "Process [%d] failed and returned FAIL\n", i);
+ testReturnCode = FAIL;
+ }
+
+ if(!CloseHandle(pi[i].hThread))
+ {
+ Trace("Error:%d: CloseHandle failed for Process [%d] hThread\n", GetLastError(), i);
+ testReturnCode = FAIL;
+ }
+
+ if(!CloseHandle(pi[i].hProcess) )
+ {
+ Trace("Error:%d: CloseHandle failed for Process [%d] hProcess\n", GetLastError(), i);
+ testReturnCode = FAIL;
+ }
+ }
+
+ testStats.operationTime = GetTimeDiff(dwStartTime);
+ fprintf(pFile, "%d,%d,%d,%d,%d,%s\n", testStats.operationTime, testStats.relationId, testStats.processCount, testStats.threadCount, testStats.repeatCount, testStats.buildNumber);
+ if(fclose(pFile))
+ {
+ Trace("Error: fclose failed for pFile\n");
+ testReturnCode = FAIL;
+ }
+
+ if( testReturnCode == PASS)
+ {
+ Trace("Test Passed\n");
+ }
+ else
+ {
+ Trace("Test Failed\n");
+ }
+
+ PAL_Terminate();
+ return testReturnCode;
+}
diff --git a/src/pal/tests/palsuite/composite/object_management/mutex/nonshared/mutex.c b/src/pal/tests/palsuite/composite/object_management/mutex/nonshared/mutex.c
new file mode 100644
index 0000000000..7f1f659f92
--- /dev/null
+++ b/src/pal/tests/palsuite/composite/object_management/mutex/nonshared/mutex.c
@@ -0,0 +1,340 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source Code: main.c and mutex.c
+** main.c creates process and waits for all processes to get over
+** mutex.c creates a mutex and then calls threads which will contend for the mutex
+**
+** This test is for Object Management Test case for Mutex where Object type is not shareable.
+** Algorithm
+** o Create PROCESS_COUNT processes.
+** o Main Thread of each process creates OBJECT_TYPE Object
+**
+** Author: ShamitP
+**============================================================
+*/
+
+#include <palsuite.h>
+#include "resultbuffer.h"
+#include "resulttime.h"
+
+#define TIMEOUT 5000
+/* Test Input Variables */
+unsigned int USE_PROCESS_COUNT = 0;
+unsigned int THREAD_COUNT = 0;
+unsigned int REPEAT_COUNT = 0;
+unsigned int RELATION_ID = 1001;
+
+/* Capture statistics at per thread basis */
+struct statistics{
+ unsigned int processId;
+ unsigned int operationsFailed;
+ unsigned int operationsPassed;
+ unsigned int operationsTotal;
+ DWORD operationTime;
+ unsigned int relationId;
+};
+
+struct ProcessStats{
+ unsigned int processId;
+ DWORD operationTime;
+ unsigned int relationId;
+};
+
+HANDLE StartTestsEvHandle = NULL;
+HANDLE hMutexHandle = NULL;
+
+/* Results Buffer */
+ResultBuffer *resultBuffer = NULL;
+
+int testStatus;
+
+void PALAPI Run_Thread(LPVOID lpParam);
+
+int GetParameters( int argc, char **argv)
+{
+ if( (argc != 5) || ((argc == 1) && !strcmp(argv[1],"/?"))
+ || !strcmp(argv[1],"/h") || !strcmp(argv[1],"/H"))
+ {
+ printf("PAL -Composite Object Management Mutex Test\n");
+ printf("Usage:\n");
+ printf("mutex\n\t[USE_PROCESS_COUNT ( greater than 1] \n");
+ printf("\t[THREAD_COUNT ( greater than 1] \n");
+ printf("\t[REPEAT_COUNT ( greater than 1]\n");
+ printf("\t[RELATION_ID [greater than 1]\n");
+ return -1;
+ }
+
+ // Trace("Args 1 is [%s], Arg 2 is [%s], Arg 3 is [%s]\n", argv[1], argv[2], argv[3]);
+
+ USE_PROCESS_COUNT = atoi(argv[1]);
+ if( USE_PROCESS_COUNT < 0)
+ {
+ printf("\nInvalid USE_PROCESS_COUNT number, Pass greater than 1\n");
+ return -1;
+ }
+
+ THREAD_COUNT = atoi(argv[2]);
+ if( (THREAD_COUNT < 1) || (THREAD_COUNT > MAXIMUM_WAIT_OBJECTS) )
+ {
+ printf("\nInvalid THREAD_COUNT number, Pass greater than 1 and less than %d\n", MAXIMUM_WAIT_OBJECTS);
+ return -1;
+ }
+
+ REPEAT_COUNT = atoi(argv[3]);
+ if( REPEAT_COUNT < 1)
+ {
+ printf("\nInvalid REPEAT_COUNT number, Pass greater than 1\n");
+ return -1;
+ }
+
+ RELATION_ID = atoi(argv[4]);
+ if( RELATION_ID < 1)
+ {
+ printf("\nMain Process:Invalid RELATION_ID number, Pass greater than 1\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+ int __cdecl main(INT argc, CHAR **argv)
+{
+ unsigned int i = 0;
+ HANDLE hThread[MAXIMUM_WAIT_OBJECTS];
+ DWORD threadId[MAXIMUM_WAIT_OBJECTS];
+
+ const char sTmpEventName[MAX_PATH] = "StartTestEvent";
+
+ DWORD dwParam = 0;
+
+ int returnCode = 0;
+
+ /* Variables to capture the file name and the file pointer at thread level*/
+ char fileName[MAX_PATH];
+ FILE *pFile = NULL;
+ struct statistics* buffer = NULL;
+ int statisticsSize = 0;
+
+ /* Variables to capture the file name and the file pointer at process level*/
+ char processFileName[MAX_PATH];
+ FILE *pProcessFile = NULL;
+ struct ProcessStats processStats;
+ DWORD dwStartTime;
+
+ testStatus = PASS;
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return ( FAIL );
+ }
+
+ if(GetParameters(argc, argv))
+ {
+ Fail("Error in obtaining the parameters\n");
+ }
+// Trace("Process created, value of process count is [%d]\n", USE_PROCESS_COUNT);
+
+ /* Register the start time */
+ dwStartTime = GetTickCount();
+ processStats.relationId = RELATION_ID;
+ processStats.processId = USE_PROCESS_COUNT;
+
+ _snprintf(processFileName, MAX_PATH, "%d_process_mutex_%d_.txt", USE_PROCESS_COUNT,RELATION_ID);
+ pProcessFile = fopen(processFileName, "w+");
+ if(pProcessFile == NULL)
+ {
+ Fail("Error in opening process File file for write for process [%d]\n", USE_PROCESS_COUNT);
+ }
+
+ statisticsSize = sizeof(struct statistics);
+
+ _snprintf(fileName, MAX_PATH, "%d_thread_mutex_%d_.txt", USE_PROCESS_COUNT, RELATION_ID);
+ pFile = fopen(fileName, "w+");
+ if(pFile == NULL)
+ {
+ Fail("Error in opening file for write for process [%d]\n", USE_PROCESS_COUNT);
+ }
+ // For each thread we will log operations failed (int), passed (int), total (int)
+ // and number of ticks (DWORD) for the operations
+ resultBuffer = new ResultBuffer( THREAD_COUNT, statisticsSize);
+
+ StartTestsEvHandle = CreateEvent( NULL, /* lpEventAttributes*/
+ TRUE, /* bManualReset */
+ FALSE, /* bInitialState */
+ NULL
+ ); /* name of Event */
+
+ if( StartTestsEvHandle == NULL )
+ {
+ Fail("Error:%d: Unexpected failure "
+ "to create %s Event for process count %d\n", GetLastError(), sTmpEventName, USE_PROCESS_COUNT );
+
+ }
+
+ /* Create StartTest Event */
+
+ hMutexHandle = CreateMutex(
+ NULL,
+ FALSE, /* bInitialOwner, owns initially */
+ NULL
+ );
+
+ if( hMutexHandle == NULL)
+ {
+ Fail("Unable to create Mutex handle for process id [%d], returned error [%d]\n", i, GetLastError());
+ }
+ /* We already assume that the mutex was created previously*/
+
+ for( i = 0; i < THREAD_COUNT; i++ )
+ {
+ dwParam = (int) i;
+ //Create thread
+ hThread[i] = CreateThread(
+ NULL, /* no security attributes */
+ 0, /* use default stack size */
+ (LPTHREAD_START_ROUTINE)Run_Thread,/* thread function */
+ (LPVOID)dwParam, /* argument to thread function */
+ 0, /* use default creation flags */
+ &threadId[i] /* returns the thread identifier*/
+ );
+
+ if(hThread[i] == NULL)
+ {
+ Fail("Create Thread failed for %d process, and GetLastError value is %d\n", USE_PROCESS_COUNT, GetLastError());
+ }
+
+ }
+
+ if (!SetEvent(StartTestsEvHandle))
+ {
+ Fail("Set Event for Start Tests failed for %d process, and GetLastError value is %d\n", USE_PROCESS_COUNT, GetLastError());
+ }
+
+ /* Test running */
+ returnCode = WaitForMultipleObjects( THREAD_COUNT, hThread, TRUE, INFINITE);
+
+ if( WAIT_OBJECT_0 != returnCode )
+ {
+ Trace("Wait for Object(s) for %d process returned %d, and GetLastError value is %d\n", USE_PROCESS_COUNT, returnCode, GetLastError());
+ testStatus = FAIL;
+ }
+
+ processStats.operationTime = GetTimeDiff(dwStartTime);
+
+ /* Write to a file*/
+ if(pFile!= NULL)
+ {
+ for( i = 0; i < THREAD_COUNT; i++ )
+ {
+ buffer = (struct statistics *)resultBuffer->getResultBuffer(i);
+ returnCode = fprintf(pFile, "%d,%d,%d,%d,%lu,%d\n", buffer->processId, buffer->operationsFailed, buffer->operationsPassed, buffer->operationsTotal, buffer->operationTime, buffer->relationId );
+// Trace("Iteration %d over\n", i);
+
+ }
+ }
+ fclose(pFile);
+
+ fprintf(pProcessFile, "%d,%d,%d\n", USE_PROCESS_COUNT, processStats.operationTime, processStats.relationId );
+ fclose(pProcessFile);
+
+ /* Logging for the test case over, clean up the handles */
+
+// Trace("Test Thread %d done\n", USE_PROCESS_COUNT);
+
+
+ for( i = 0; i < THREAD_COUNT; i++ )
+ {
+ if(!CloseHandle(hThread[i]) )
+ {
+ Trace("Error:%d: CloseHandle failed for Process [%d] hThread[%d]\n", GetLastError(), USE_PROCESS_COUNT, i);
+ testStatus = FAIL;
+ }
+ }
+
+ if(!CloseHandle(StartTestsEvHandle))
+ {
+ Trace("Error:%d: CloseHandle failed for Process [%d] StartTestsEvHandle\n", GetLastError(), USE_PROCESS_COUNT);
+ testStatus = FAIL;
+ }
+
+ if(!CloseHandle(hMutexHandle))
+ {
+ Trace("Error:%d: CloseHandle failed for Process [%d] hMutexHandle\n", GetLastError(), USE_PROCESS_COUNT);
+ testStatus = FAIL;
+ }
+
+ PAL_Terminate();
+ return testStatus;
+}
+
+void PALAPI Run_Thread (LPVOID lpParam)
+{
+ unsigned int i = 0;
+ DWORD dwWaitResult;
+
+ struct statistics stats;
+ DWORD dwStartTime;
+
+ stats.relationId = RELATION_ID;
+ stats.processId = USE_PROCESS_COUNT;
+ stats.operationsFailed = 0;
+ stats.operationsPassed = 0;
+ stats.operationsTotal = 0;
+ stats.operationTime = 0;
+
+ int Id=(int)lpParam;
+
+ dwWaitResult = WaitForSingleObject(
+ StartTestsEvHandle, // handle to mutex
+ TIMEOUT);
+
+ if(dwWaitResult != WAIT_OBJECT_0)
+ {
+ Trace("Error while waiting for StartTest Event@ thread %d\n", Id);
+ testStatus = FAIL;
+ }
+
+ dwStartTime = GetTickCount();
+
+ for( i = 0; i < REPEAT_COUNT; i++ )
+ {
+ dwWaitResult = WaitForSingleObject(
+ hMutexHandle, // handle to mutex
+ TIMEOUT);
+
+ if(dwWaitResult != WAIT_OBJECT_0)
+ {
+// Trace("Error while waiting for onject @ thread %d, # iter %d\n", Id, i);
+ stats.operationsFailed += 1;
+ stats.operationsTotal += 1;
+ testStatus = FAIL;
+ continue;
+ }
+ if (! ReleaseMutex(hMutexHandle))
+ {
+ // Deal with error.
+// Trace("Error while releasing mutex @ thread %d # iter %d\n", Id, i);
+ stats.operationsFailed += 1;
+ stats.operationsTotal += 1;
+ // Probably need to have while true loop to attempt to release mutex...
+ testStatus = FAIL;
+ continue;
+ }
+
+ stats.operationsTotal += 1;
+ stats.operationsPassed += 1;
+ // Trace("Successs while releasing mutex @ iteration %d -> thread %d -> Process %d\n", i, Id, USE_PROCESS_COUNT);
+
+ }
+
+ stats.operationTime = GetTimeDiff(dwStartTime);
+ //Trace("OPeration time is %d", stats.operationTime );
+ if(resultBuffer->LogResult(Id, (char *)&stats))
+ {
+ Fail("Error:%d: while writing to shared memory, Thread Id is[%d] and Process id is [%d]\n", GetLastError(), Id, USE_PROCESS_COUNT);
+ }
+}
diff --git a/src/pal/tests/palsuite/composite/object_management/mutex/shared/CMakeLists.txt b/src/pal/tests/palsuite/composite/object_management/mutex/shared/CMakeLists.txt
new file mode 100644
index 0000000000..cf33d0b464
--- /dev/null
+++ b/src/pal/tests/palsuite/composite/object_management/mutex/shared/CMakeLists.txt
@@ -0,0 +1,21 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ main.c
+ mutex.c
+)
+
+add_executable(paltest_mutex_shared
+ ${SOURCES}
+)
+
+add_dependencies(paltest_mutex_shared coreclrpal)
+
+target_link_libraries(paltest_mutex_shared
+ pthread
+ rt
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/composite/object_management/mutex/shared/main.c b/src/pal/tests/palsuite/composite/object_management/mutex/shared/main.c
new file mode 100644
index 0000000000..aa98855565
--- /dev/null
+++ b/src/pal/tests/palsuite/composite/object_management/mutex/shared/main.c
@@ -0,0 +1,265 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** This test is for Object Management Test case for Mutex where Object type is shareable.
+**
+** Source Code: main.c and mutex.c
+** main.c creates a mutex, creates processes and waits for all processes to get over
+** mutex.c create threads which will contend for the mutex
+**
+** This test is for Object Management Test case for Mutex where Object type is not shareable.
+** Algorithm
+** o Main Process Creates OBJECT_TYPE Object
+** o Create PROCESS_COUNT processes aware of the Shared Object
+**
+** Author: ShamitP
+**
+**
+**============================================================
+*/
+
+#include <palsuite.h>
+#include "resulttime.h"
+
+/* Test Input Variables */
+unsigned int PROCESS_COUNT = 2;
+unsigned int THREAD_COUNT = 2;
+unsigned int REPEAT_COUNT = 40000;
+unsigned int RELATION_ID = 1001;
+
+
+char objectSuffix[MAX_PATH];
+
+struct TestStats{
+ DWORD operationTime;
+ unsigned int relationId;
+ unsigned int processCount;
+ unsigned int threadCount;
+ unsigned int repeatCount;
+ char* buildNumber;
+
+};
+
+int GetParameters( int argc, char **argv)
+{
+ if( (!((argc == 5) || (argc == 6) ) )|| ((argc == 1) && !strcmp(argv[1],"/?"))
+ || !strcmp(argv[1],"/h") || !strcmp(argv[1],"/H"))
+ {
+ printf("PAL -Composite Object Management event Test\n");
+ printf("Usage:\n");
+ printf("main\n\t[PROCESS_COUNT (greater than 1)] \n");
+ printf("\t[THREAD_COUNT (greater than 1)] \n");
+ printf("\t[REPEAT_COUNT (greater than 1)]\n");
+ printf("\t[RELATION_ID [greater than 1]\n");
+ printf("\t[Object Name Suffix]\n");
+ return -1;
+ }
+
+ PROCESS_COUNT = atoi(argv[1]);
+ if( (PROCESS_COUNT < 1) || (PROCESS_COUNT > MAXIMUM_WAIT_OBJECTS) )
+ {
+ printf("\nMain Process:Invalid PROCESS_COUNT number, Pass greater than 1 and less than PROCESS_COUNT %d\n", MAXIMUM_WAIT_OBJECTS);
+ return -1;
+ }
+
+ THREAD_COUNT = atoi(argv[2]);
+ if( (THREAD_COUNT < 1) || (THREAD_COUNT > MAXIMUM_WAIT_OBJECTS) )
+ {
+ printf("\nInvalid THREAD_COUNT number, Pass greater than 1 and less than %d\n", MAXIMUM_WAIT_OBJECTS);
+ return -1;
+ }
+
+ REPEAT_COUNT = atoi(argv[3]);
+ if( REPEAT_COUNT < 1)
+ {
+ printf("\nMain Process:Invalid REPEAT_COUNT number, Pass greater than 1\n");
+ return -1;
+ }
+
+ RELATION_ID = atoi(argv[4]);
+ if( RELATION_ID < 1)
+ {
+ printf("\nMain Process:Invalid RELATION_ID number, Pass greater than 1\n");
+ return -1;
+ }
+
+ if(argc == 6)
+ {
+ strncpy(objectSuffix, argv[5], MAX_PATH-1);
+ }
+
+ return 0;
+}
+
+ int __cdecl main(INT argc, CHAR **argv)
+{
+ unsigned int i = 0;
+ HANDLE hProcess[MAXIMUM_WAIT_OBJECTS];
+ HANDLE hMutexHandle;
+
+ STARTUPINFO si[MAXIMUM_WAIT_OBJECTS];
+ PROCESS_INFORMATION pi[MAXIMUM_WAIT_OBJECTS];
+
+ char ObjName[MAX_PATH] = "SHARED_MUTEX";
+ char lpCommandLine[MAX_PATH] = "";
+
+ int returnCode = 0;
+ DWORD processReturnCode = 0;
+ int testReturnCode = PASS;
+
+ char fileName[MAX_PATH];
+ FILE *pFile = NULL;
+ DWORD dwStartTime;
+ struct TestStats testStats;
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return ( FAIL );
+ }
+
+ ZeroMemory( objectSuffix, MAX_PATH );
+
+ if(GetParameters(argc, argv))
+ {
+ Fail("Error in obtaining the parameters\n");
+ }
+
+ if(argc == 5)
+ {
+ strncat(ObjName, objectSuffix, MAX_PATH - (sizeof(ObjName) + 1) );
+ }
+
+ /* Register the start time */
+ dwStartTime = GetTickCount();
+ testStats.relationId = RELATION_ID;
+ testStats.processCount = PROCESS_COUNT;
+ testStats.threadCount = THREAD_COUNT;
+ testStats.repeatCount = REPEAT_COUNT;
+ testStats.buildNumber = getBuildNumber();
+
+
+ _snprintf(fileName, MAX_PATH, "main_mutex_%d_.txt", RELATION_ID);
+ pFile = fopen(fileName, "w+");
+ if(pFile == NULL)
+ {
+ Fail("Error in opening main file for write\n");
+ }
+
+ hMutexHandle = CreateMutex(
+ NULL,
+ FALSE, /* bInitialOwner, owns initially */
+ ObjName
+ );
+
+ if( hMutexHandle == NULL)
+ {
+ Fail("Unable to create Mutex handle for Main thread returned error [%d]\n", GetLastError());
+ }
+
+ for( i = 0; i < PROCESS_COUNT; i++ )
+ {
+ ZeroMemory( lpCommandLine, MAX_PATH );
+ if ( _snprintf( lpCommandLine, MAX_PATH-1, "mutex %d %d %d %d %s", i, THREAD_COUNT, REPEAT_COUNT, RELATION_ID, objectSuffix) < 0 )
+ {
+ Fail ("Error Insufficient mutex name string length for %s for iteration [%d]\n", ObjName, i);
+ }
+
+
+ /* Zero the data structure space */
+ ZeroMemory ( &pi[i], sizeof(pi[i]) );
+ ZeroMemory ( &si[i], sizeof(si[i]) );
+
+ /* Set the process flags and standard io handles */
+ si[i].cb = sizeof(si[i]);
+
+ //Create Process
+ if(!CreateProcess( NULL, /* lpApplicationName*/
+ lpCommandLine, /* lpCommandLine */
+ NULL, /* lpProcessAttributes */
+ NULL, /* lpThreadAttributes */
+ TRUE, /* bInheritHandles */
+ 0, /* dwCreationFlags, */
+ NULL, /* lpEnvironment */
+ NULL, /* pCurrentDirectory */
+ &si[i], /* lpStartupInfo */
+ &pi[i] /* lpProcessInformation */
+ ))
+ {
+ Fail("Process Not created for [%d], the error code is [%d]\n", i, GetLastError());
+ }
+ else
+ {
+ hProcess[i] = pi[i].hProcess;
+// Trace("Process created for [%d]\n", i);
+
+ }
+ }
+
+ returnCode = WaitForMultipleObjects( PROCESS_COUNT, hProcess, TRUE, INFINITE);
+ if( WAIT_OBJECT_0 != returnCode )
+ {
+ Trace("Wait for Object(s) @ Main thread for %d processes returned %d, and GetLastError value is %d\n", PROCESS_COUNT, returnCode, GetLastError());
+ testReturnCode = FAIL;
+ }
+
+ for( i = 0; i < PROCESS_COUNT; i++ )
+ {
+ /* check the exit code from the process */
+ if( ! GetExitCodeProcess( pi[i].hProcess, &processReturnCode ) )
+ {
+ Trace( "GetExitCodeProcess call failed for iteration %d with error code %u\n",
+ i, GetLastError() );
+
+ testReturnCode = FAIL;
+ }
+
+ if(processReturnCode == FAIL)
+ {
+ Trace( "Process [%d] failed and returned FAIL\n", i);
+ testReturnCode = FAIL;
+ }
+
+ if(!CloseHandle(pi[i].hThread))
+ {
+ Trace("Error:%d: CloseHandle failed for Process [%d] hThread\n", GetLastError(), i);
+ testReturnCode = FAIL;
+ }
+
+ if(!CloseHandle(pi[i].hProcess) )
+ {
+ Trace("Error:%d: CloseHandle failed for Process [%d] hProcess\n", GetLastError(), i);
+ testReturnCode = FAIL;
+ }
+ }
+
+ testStats.operationTime = GetTimeDiff(dwStartTime);
+ fprintf(pFile, "%d,%d,%d,%d,%d,%s\n", testStats.operationTime, testStats.relationId, testStats.processCount, testStats.threadCount, testStats.repeatCount, testStats.buildNumber );
+ if(fclose(pFile))
+ {
+ Trace("Error: fclose failed for pFile\n");
+ testReturnCode = FAIL;
+ }
+
+ if(!CloseHandle(hMutexHandle))
+ {
+ Trace("Error:%d: CloseHandle failed for hMutexHandle\n", GetLastError());
+ testReturnCode = FAIL;
+
+ }
+
+ if( testReturnCode == PASS)
+ {
+ Trace("Test Passed\n");
+ }
+ else
+ {
+ Trace("Test Failed\n");
+ }
+
+ PAL_Terminate();
+ return testReturnCode;
+}
+
diff --git a/src/pal/tests/palsuite/composite/object_management/mutex/shared/mutex.c b/src/pal/tests/palsuite/composite/object_management/mutex/shared/mutex.c
new file mode 100644
index 0000000000..ec5d9b37ac
--- /dev/null
+++ b/src/pal/tests/palsuite/composite/object_management/mutex/shared/mutex.c
@@ -0,0 +1,354 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** This test is for Object Management Test case for Mutex where Object type is shareable.
+**
+** Source Code: main.c and mutex.c
+** main.c creates a mutex, creates processes and waits for all processes to get over
+** mutex.c create threads which will contend for the mutex
+**
+** This test is for Object Management Test case for Mutex where Object type is not shareable.
+** Algorithm
+** o Main Process Creates OBJECT_TYPE Object
+** o Create PROCESS_COUNT processes aware of the Shared Object
+**
+** Author: ShamitP
+**
+**
+**============================================================
+*/
+
+#include <palsuite.h>
+#include "resultbuffer.h"
+#include "resulttime.h"
+
+#define TIMEOUT 5000
+/* Test Input Variables */
+unsigned int USE_PROCESS_COUNT = 0;
+unsigned int THREAD_COUNT = 0;
+unsigned int REPEAT_COUNT = 0;
+unsigned int RELATION_ID = 0;
+
+
+/* Capture statistics at per thread basis */
+struct statistics{
+ unsigned int processId;
+ unsigned int operationsFailed;
+ unsigned int operationsPassed;
+ unsigned int operationsTotal;
+ DWORD operationTime;
+ unsigned int relationId;
+};
+
+struct ProcessStats{
+ unsigned int processId;
+ DWORD operationTime;
+ unsigned int relationId;
+};
+
+HANDLE StartTestsEvHandle = NULL;
+HANDLE hMutexHandle = NULL;
+
+/* Results Buffer */
+ResultBuffer *resultBuffer = NULL;
+
+int testStatus;
+
+const char sTmpEventName[MAX_PATH] = "StartTestEvent";
+char objectSuffix[MAX_PATH];
+
+void PALAPI Run_Thread(LPVOID lpParam);
+
+int GetParameters( int argc, char **argv)
+{
+ if( (!((argc == 5) || (argc == 6) ) )|| ((argc == 1) && !strcmp(argv[1],"/?"))
+ || !strcmp(argv[1],"/h") || !strcmp(argv[1],"/H"))
+ {
+ printf("PAL -Composite Object Management event Test\n");
+ printf("Usage:\n");
+ printf("main\n\t[USE_PROCESS_COUNT (greater than 1)] \n");
+ printf("\t[THREAD_COUNT (greater than 1)] \n");
+ printf("\t[REPEAT_COUNT (greater than 1)]\n");
+ printf("\t[RELATION_ID [greater than 1]\n");
+ printf("\t[Object Name Suffix]\n");
+
+ return -1;
+ }
+
+ // Trace("Args 1 is [%s], Arg 2 is [%s], Arg 3 is [%s]\n", argv[1], argv[2], argv[3]);
+
+ USE_PROCESS_COUNT = atoi(argv[1]);
+ if( USE_PROCESS_COUNT < 0)
+ {
+ printf("\nInvalid USE_PROCESS_COUNT number, Pass greater than 1\n");
+ return -1;
+ }
+
+ THREAD_COUNT = atoi(argv[2]);
+ if( (THREAD_COUNT < 1) || (THREAD_COUNT > MAXIMUM_WAIT_OBJECTS) )
+ {
+ printf("\nInvalid THREAD_COUNT number, Pass greater than 1 and less than %d\n", MAXIMUM_WAIT_OBJECTS);
+ return -1;
+ }
+
+ REPEAT_COUNT = atoi(argv[3]);
+ if( REPEAT_COUNT < 1)
+ {
+ printf("\nInvalid REPEAT_COUNT number, Pass greater than 1\n");
+ return -1;
+ }
+
+ RELATION_ID = atoi(argv[4]);
+ if( RELATION_ID < 1)
+ {
+ printf("\nMain Process:Invalid RELATION_ID number, Pass greater than 1\n");
+ return -1;
+ }
+
+ if(argc == 6)
+ {
+ strncpy(objectSuffix, argv[5], MAX_PATH-1);
+ }
+
+ return 0;
+}
+
+ int __cdecl main(INT argc, CHAR **argv)
+{
+ unsigned int i = 0;
+ HANDLE hThread[MAXIMUM_WAIT_OBJECTS];
+ DWORD threadId[MAXIMUM_WAIT_OBJECTS];
+
+ char ObjName[MAX_PATH] = "SHARED_MUTEX";
+ DWORD dwParam = 0;
+
+ int returnCode = 0;
+
+ /* Variables to capture the file name and the file pointer*/
+ char fileName[MAX_PATH];
+ FILE *pFile = NULL;
+ struct statistics* buffer = NULL;
+ int statisticsSize = 0;
+
+ /* Variables to capture the file name and the file pointer at process level*/
+ char processFileName[MAX_PATH];
+ FILE *pProcessFile = NULL;
+ struct ProcessStats processStats;
+ DWORD dwStartTime;
+
+ testStatus = PASS;
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return ( FAIL );
+ }
+
+ ZeroMemory( objectSuffix, MAX_PATH );
+
+ if(GetParameters(argc, argv))
+ {
+ Fail("Error in obtaining the parameters\n");
+ }
+// Trace("Process created, value of process count is [%d]\n", USE_PROCESS_COUNT);
+
+ if(argc == 5)
+ {
+ strncat(ObjName, objectSuffix, MAX_PATH - (sizeof(ObjName) + 1) );
+ }
+
+ /* Register the start time */
+ dwStartTime = GetTickCount();
+ processStats.relationId = RELATION_ID;
+ processStats.processId = USE_PROCESS_COUNT;
+
+ _snprintf(processFileName, MAX_PATH, "%d_process_mutex_%d_.txt", USE_PROCESS_COUNT, RELATION_ID);
+ pProcessFile = fopen(processFileName, "w+");
+ if(pProcessFile == NULL)
+ {
+ Fail("Error in opening process File file for write for process [%d]\n", USE_PROCESS_COUNT);
+ } statisticsSize = sizeof(struct statistics);
+
+ _snprintf(fileName, MAX_PATH, "%d_thread_mutex_%d_.txt", USE_PROCESS_COUNT, RELATION_ID);
+ pFile = fopen(fileName, "w+");
+ if(pFile == NULL)
+ {
+ Fail("Error in opening file for write for process [%d]\n", USE_PROCESS_COUNT);
+ }
+ // For each thread we will log operations failed (int), passed (int), total (int)
+ // and number of ticks (DWORD) for the operations
+ resultBuffer = new ResultBuffer( THREAD_COUNT, statisticsSize);
+
+ /* Create StartTest Event */
+ StartTestsEvHandle = CreateEvent( NULL, /* lpEventAttributes*/
+ TRUE, /* bManualReset */
+ FALSE, /* bInitialState */
+ NULL); /* name of Event */
+
+ if( StartTestsEvHandle == NULL )
+ {
+ Fail("Error:%d: Unexpected failure "
+ "to create %s Event for process count %d\n", GetLastError(), sTmpEventName, USE_PROCESS_COUNT );
+
+ }
+
+ hMutexHandle = CreateMutex(
+ NULL,
+ FALSE, /* bInitialOwner, owns initially */
+ ObjName
+ );
+
+ if( (hMutexHandle == NULL)|| (GetLastError() != ERROR_ALREADY_EXISTS))
+ {
+ Fail("Unable to create Mutex handle for process id [%d], returned error [%d], expected ERROR_ALREADY_EXISTS\n", i, GetLastError());
+ }
+ /* We already assume that the mutex was created previously*/
+
+ for( i = 0; i < THREAD_COUNT; i++ )
+ {
+ dwParam = (int) i;
+ //Create thread
+ hThread[i] = CreateThread(
+ NULL, /* no security attributes */
+ 0, /* use default stack size */
+ (LPTHREAD_START_ROUTINE)Run_Thread,/* thread function */
+ (LPVOID)dwParam, /* argument to thread function */
+ 0, /* use default creation flags */
+ &threadId[i] /* returns the thread identifier*/
+ );
+
+ if(hThread[i] == NULL)
+ {
+ Fail("Create Thread failed for %d process, and GetLastError value is %d\n", USE_PROCESS_COUNT, GetLastError());
+ }
+
+ }
+
+ if (!SetEvent(StartTestsEvHandle))
+ {
+ Fail("Set Event for Start Tests failed for %d process, and GetLastError value is %d\n", USE_PROCESS_COUNT, GetLastError());
+ }
+
+ /* Test running */
+ returnCode = WaitForMultipleObjects( THREAD_COUNT, hThread, TRUE, INFINITE);
+
+ if( WAIT_OBJECT_0 != returnCode )
+ {
+ Trace("Wait for Object(s) for %d process returned %d, and GetLastError value is %d\n", USE_PROCESS_COUNT, returnCode, GetLastError());
+ testStatus = FAIL;
+ }
+
+ processStats.operationTime = GetTimeDiff(dwStartTime);
+
+ /* Write to a file*/
+ if(pFile!= NULL)
+ {
+ for( i = 0; i < THREAD_COUNT; i++ )
+ {
+ buffer = (struct statistics *)resultBuffer->getResultBuffer(i);
+ returnCode = fprintf(pFile, "%d,%d,%d,%d,%lu,%d\n", buffer->processId, buffer->operationsFailed, buffer->operationsPassed, buffer->operationsTotal, buffer->operationTime, buffer->relationId );
+// Trace("Iteration %d over\n", i);
+
+ }
+ }
+ fclose(pFile);
+
+ fprintf(pProcessFile, "%d,%d,%d\n", USE_PROCESS_COUNT, processStats.operationTime, processStats.relationId );
+ fclose(pProcessFile);
+
+ /* Logging for the test case over, clean up the handles */
+
+// Trace("Process Count %d over\n",USE_PROCESS_COUNT);
+
+ for( i = 0; i < THREAD_COUNT; i++ )
+ {
+ if(!CloseHandle(hThread[i]) )
+ {
+ Trace("Error:%d: CloseHandle failed for Process [%d] hThread[%d]\n", GetLastError(), USE_PROCESS_COUNT, i);
+ testStatus = FAIL;
+ }
+ }
+
+ if(!CloseHandle(StartTestsEvHandle))
+ {
+ Trace("Error:%d: CloseHandle failed for Process [%d] StartTestsEvHandle\n", GetLastError(), USE_PROCESS_COUNT);
+ testStatus = FAIL;
+ }
+
+ if(!CloseHandle(hMutexHandle))
+ {
+ Trace("Error:%d: CloseHandle failed for Process [%d] hMutexHandle\n", GetLastError(), USE_PROCESS_COUNT);
+ testStatus = FAIL;
+ }
+
+ PAL_Terminate();
+ return testStatus;
+}
+
+void PALAPI Run_Thread (LPVOID lpParam)
+{
+ unsigned int i = 0;
+ DWORD dwWaitResult;
+
+ struct statistics stats;
+ DWORD dwStartTime;
+
+ stats.relationId = RELATION_ID;
+ stats.processId = USE_PROCESS_COUNT;
+ stats.operationsFailed = 0;
+ stats.operationsPassed = 0;
+ stats.operationsTotal = 0;
+ stats.operationTime = 0;
+
+ int Id=(int)lpParam;
+
+ dwWaitResult = WaitForSingleObject(
+ StartTestsEvHandle, // handle to mutex
+ TIMEOUT);
+
+ if(dwWaitResult != WAIT_OBJECT_0)
+ {
+ Trace("Error while waiting for StartTest Event@ thread %d\n", Id);
+ testStatus = FAIL;
+ }
+
+ dwStartTime = GetTickCount();
+
+ for( i = 0; i < REPEAT_COUNT; i++ )
+ {
+ dwWaitResult = WaitForSingleObject(
+ hMutexHandle, // handle to mutex
+ TIMEOUT);
+
+ if(dwWaitResult != WAIT_OBJECT_0)
+ {
+// Trace("Error while waiting for onject @ thread %d, # iter %d, Error Returned [%d]\n", Id, i, GetLastError());
+ stats.operationsFailed += 1;
+ stats.operationsTotal += 1;
+ testStatus = FAIL;
+ continue;
+ }
+ if (! ReleaseMutex(hMutexHandle))
+ {
+ // Deal with error.
+// Trace("Error while releasing mutex @ thread %d # iter %d\n", Id, i);
+ stats.operationsFailed += 1;
+ stats.operationsTotal += 1;
+ // Probably need to have while true loop to attempt to release mutex...
+ testStatus = FAIL;
+ continue;
+ }
+
+ stats.operationsTotal += 1;
+ stats.operationsPassed += 1;
+// Trace("Successs while releasing mutex @ iteration %d -> thread %d -> Process count %d\n", i, Id, USE_PROCESS_COUNT);
+
+ }
+ stats.operationTime = GetTimeDiff(dwStartTime);
+ if(resultBuffer->LogResult(Id, (char *)&stats))
+ {
+ Fail("Error:%d: while writing to shared memory, Thread Id is[%d] and Process id is [%d]\n", GetLastError(), Id, USE_PROCESS_COUNT);
+ }
+}
diff --git a/src/pal/tests/palsuite/composite/object_management/readme.txt b/src/pal/tests/palsuite/composite/object_management/readme.txt
new file mode 100644
index 0000000000..6bae5f105d
--- /dev/null
+++ b/src/pal/tests/palsuite/composite/object_management/readme.txt
@@ -0,0 +1,29 @@
+To compile:
+
+1) create a dat file (say object_management.dat) with contents:
+
+PAL,Composite,palsuite\composite\object_management\mutex\nonshared,mutex=main.c mutex.c,<SUPPORTEXE>,<TESTLANGCPP>,<COMPILEONLY>
+PAL,Composite,palsuite\composite\object_management\mutex\shared,mutex=main.c mutex.c,<SUPPORTEXE>,<TESTLANGCPP>,<COMPILEONLY>
+PAL,Composite,palsuite\composite\object_management\semaphore\nonshared,semaphore=main.c semaphore.c,<SUPPORTEXE>,<TESTLANGCPP>,<COMPILEONLY>
+PAL,Composite,palsuite\composite\object_management\semaphore\shared,semaphore=main.c semaphore.c,<SUPPORTEXE>,<TESTLANGCPP>,<COMPILEONLY>
+PAL,Composite,palsuite\composite\object_management\event\nonshared,event=main.c event.c,<SUPPORTEXE>,<TESTLANGCPP>,<COMPILEONLY>
+PAL,Composite,palsuite\composite\object_management\event\shared,event=main.c event.c,<SUPPORTEXE>,<TESTLANGCPP>,<COMPILEONLY>
+
+
+2) perl rrunmod.pl -r object_management.dat
+
+
+To execute:
+For each of the test cases,
+main [PROCESS_COUNT] [THREAD_COUNT] [REPEAT_COUNT]
+
+
+Output:
+The performance numbers will be in <process_logical_id>_[event|semaphore|mutex].txt
+(will be at palsuite\composite\object_management\[mutex|event|semaphore]\[shared|nonshared]\obj[r|c|d] directory if u use rrunmod.pl)
+
+So if process_count is 3, you will have files 0_mutex.txt, 1_mutex.txt and so on…
+
+For each process txt file created,
+each row represents a thread data (process id, number of failures, number of pass, total number of repeated operations and an integer that will be used to identify a run
+(currently zero)).
diff --git a/src/pal/tests/palsuite/composite/object_management/semaphore/CMakeLists.txt b/src/pal/tests/palsuite/composite/object_management/semaphore/CMakeLists.txt
new file mode 100644
index 0000000000..2534564f95
--- /dev/null
+++ b/src/pal/tests/palsuite/composite/object_management/semaphore/CMakeLists.txt
@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(nonshared)
+add_subdirectory(shared)
+
diff --git a/src/pal/tests/palsuite/composite/object_management/semaphore/nonshared/CMakeLists.txt b/src/pal/tests/palsuite/composite/object_management/semaphore/nonshared/CMakeLists.txt
new file mode 100644
index 0000000000..6efa228fbb
--- /dev/null
+++ b/src/pal/tests/palsuite/composite/object_management/semaphore/nonshared/CMakeLists.txt
@@ -0,0 +1,21 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ main.c
+ semaphore.c
+)
+
+add_executable(paltest_semaphore_nonshared
+ ${SOURCES}
+)
+
+add_dependencies(paltest_semaphore_nonshared coreclrpal)
+
+target_link_libraries(paltest_semaphore_nonshared
+ pthread
+ rt
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/composite/object_management/semaphore/nonshared/main.c b/src/pal/tests/palsuite/composite/object_management/semaphore/nonshared/main.c
new file mode 100644
index 0000000000..854809c8f8
--- /dev/null
+++ b/src/pal/tests/palsuite/composite/object_management/semaphore/nonshared/main.c
@@ -0,0 +1,228 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source Code: main.c and semaphore.c
+** main.c creates process and waits for all processes to get over
+** semaphore.c creates a semaphore and then calls threads which will contend for the semaphore
+**
+** This test is for Object Management Test case for semaphore where Object type is not shareable.
+** Algorithm
+** o Create PROCESS_COUNT processes.
+** o Main Thread of each process creates OBJECT_TYPE Object
+**
+** Author: ShamitP
+**
+**
+**============================================================
+*/
+
+#include <palsuite.h>
+#include "resulttime.h"
+
+/* Test Input Variables */
+unsigned int PROCESS_COUNT = 2;
+unsigned int THREAD_COUNT = 15;
+unsigned int REPEAT_COUNT = 40000;
+unsigned int RELATION_ID = 1001;
+
+
+
+struct TestStats{
+ DWORD operationTime;
+ unsigned int relationId;
+ unsigned int processCount;
+ unsigned int threadCount;
+ unsigned int repeatCount;
+ char* buildNumber;
+};
+
+int GetParameters( int argc, char **argv)
+{
+ if( (argc != 5) || ((argc == 1) && !strcmp(argv[1],"/?"))
+ || !strcmp(argv[1],"/h") || !strcmp(argv[1],"/H"))
+ {
+ printf("PAL -Composite Object Management Semaphore Test\n");
+ printf("Usage:\n");
+ printf("main\n\t[PROCESS_COUNT [greater than 1] \n");
+ printf("\t[THREAD_COUNT [greater than 1] \n");
+ printf("\t[REPEAT_COUNT [greater than 1]\n");
+ printf("\t[RELATION_ID [greater than 1]\n");
+ return -1;
+ }
+
+ PROCESS_COUNT = atoi(argv[1]);
+ if( (PROCESS_COUNT < 1) || (PROCESS_COUNT > MAXIMUM_WAIT_OBJECTS) )
+ {
+ printf("\nMain Process:Invalid PROCESS_COUNT number, Pass greater than 1 and less than PROCESS_COUNT %d\n", MAXIMUM_WAIT_OBJECTS);
+ return -1;
+ }
+
+ THREAD_COUNT = atoi(argv[2]);
+ if( (THREAD_COUNT < 1) || (THREAD_COUNT > MAXIMUM_WAIT_OBJECTS) )
+ {
+ printf("\nInvalid THREAD_COUNT number, Pass greater than 1 and less than %d\n", MAXIMUM_WAIT_OBJECTS);
+ return -1;
+ }
+
+ REPEAT_COUNT = atoi(argv[3]);
+ if( REPEAT_COUNT < 1)
+ {
+ printf("\nMain Process:Invalid REPEAT_COUNT number, Pass greater than 1\n");
+ return -1;
+ }
+
+ RELATION_ID = atoi(argv[4]);
+ if( RELATION_ID < 1)
+ {
+ printf("\nMain Process:Invalid RELATION_ID number, Pass greater than or Equal to 1\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+ int __cdecl main(INT argc, CHAR **argv)
+{
+ unsigned int i = 0;
+ HANDLE hProcess[MAXIMUM_WAIT_OBJECTS];
+ HANDLE hSemaphoreHandle[MAXIMUM_WAIT_OBJECTS];
+
+ STARTUPINFO si[MAXIMUM_WAIT_OBJECTS];
+ PROCESS_INFORMATION pi[MAXIMUM_WAIT_OBJECTS];
+
+ const char *ObjName = "Semaphore";
+ char lpCommandLine[MAX_PATH] = "";
+
+ int returnCode = 0;
+ DWORD processReturnCode = 0;
+ int testReturnCode = PASS;
+
+ char fileName[MAX_PATH];
+ FILE *pFile = NULL;
+ DWORD dwStartTime;
+ struct TestStats testStats;
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return ( FAIL );
+ }
+
+ if(GetParameters(argc, argv))
+ {
+ Fail("Error in obtaining the parameters\n");
+ }
+
+ /* Register the start time */
+ dwStartTime = GetTickCount();
+ testStats.relationId = RELATION_ID;
+ testStats.processCount = PROCESS_COUNT;
+ testStats.threadCount = THREAD_COUNT;
+ testStats.repeatCount = REPEAT_COUNT;
+ testStats.buildNumber = getBuildNumber();
+
+
+ _snprintf(fileName, MAX_PATH, "main_semaphore_%d_.txt", RELATION_ID);
+ pFile = fopen(fileName, "w+");
+ if(pFile == NULL)
+ {
+ Fail("Error in opening main file for write\n");
+ }
+
+ for( i = 0; i < PROCESS_COUNT; i++ )
+ {
+ ZeroMemory( lpCommandLine, MAX_PATH );
+ if ( _snprintf( lpCommandLine, MAX_PATH-1, "semaphore %d %d %d %d", i, THREAD_COUNT, REPEAT_COUNT, RELATION_ID) < 0 )
+ {
+ Fail("Error Insufficient semaphore name string length for %s for iteration [%d]\n", ObjName, i);
+ }
+
+ /* Zero the data structure space */
+ ZeroMemory ( &pi[i], sizeof(pi[i]) );
+ ZeroMemory ( &si[i], sizeof(si[i]) );
+
+ /* Set the process flags and standard io handles */
+ si[i].cb = sizeof(si[i]);
+
+ //Create Process
+ if(!CreateProcess( NULL, /* lpApplicationName*/
+ lpCommandLine, /* lpCommandLine */
+ NULL, /* lpProcessAttributes */
+ NULL, /* lpThreadAttributes */
+ TRUE, /* bInheritHandles */
+ 0, /* dwCreationFlags, */
+ NULL, /* lpEnvironment */
+ NULL, /* pCurrentDirectory */
+ &si[i], /* lpStartupInfo */
+ &pi[i] /* lpProcessInformation */
+ ))
+ {
+ Fail("Process Not created for [%d], the error code is [%d]\n", i, GetLastError());
+ }
+ else
+ {
+ hProcess[i] = pi[i].hProcess;
+// Trace("Process created for [%d]\n", i);
+
+ }
+ }
+
+ returnCode = WaitForMultipleObjects( PROCESS_COUNT, hProcess, TRUE, INFINITE);
+ if( WAIT_OBJECT_0 != returnCode )
+ {
+ Trace("Wait for Object(s) @ Main thread for %d processes returned %d, and GetLastError value is %d\n", PROCESS_COUNT, returnCode, GetLastError());
+ testReturnCode = FAIL;
+ }
+
+ for( i = 0; i < PROCESS_COUNT; i++ )
+ {
+ /* check the exit code from the process */
+ if( ! GetExitCodeProcess( pi[i].hProcess, &processReturnCode ) )
+ {
+ Trace( "GetExitCodeProcess call failed for iteration %d with error code %u\n",
+ i, GetLastError() );
+
+ testReturnCode = FAIL;
+ }
+
+ if(processReturnCode == FAIL)
+ {
+ Trace( "Process [%d] failed and returned FAIL\n", i);
+ testReturnCode = FAIL;
+ }
+
+ if(!CloseHandle(pi[i].hThread))
+ {
+ Trace("Error:%d: CloseHandle failed for Process [%d] hThread\n", GetLastError(), i);
+ testReturnCode = FAIL;
+ }
+
+ if(!CloseHandle(pi[i].hProcess) )
+ {
+ Trace("Error:%d: CloseHandle failed for Process [%d] hProcess\n", GetLastError(), i);
+ testReturnCode = FAIL;
+ }
+ }
+
+ testStats.operationTime = GetTimeDiff(dwStartTime);
+ fprintf(pFile, "%d,%d,%d,%d,%d,%s\n", testStats.operationTime, testStats.relationId,testStats.processCount, testStats.threadCount, testStats.repeatCount, testStats.buildNumber );
+ if(fclose(pFile))
+ {
+ Trace("Error: fclose failed for pFile\n");
+ testReturnCode = FAIL;
+ }
+
+ if( testReturnCode == PASS)
+ {
+ Trace("Test Passed\n");
+ }
+ else
+ {
+ Trace("Test Failed\n");
+ }
+
+ PAL_Terminate();
+ return testReturnCode;
+}
diff --git a/src/pal/tests/palsuite/composite/object_management/semaphore/nonshared/semaphore.c b/src/pal/tests/palsuite/composite/object_management/semaphore/nonshared/semaphore.c
new file mode 100644
index 0000000000..0e487f2c17
--- /dev/null
+++ b/src/pal/tests/palsuite/composite/object_management/semaphore/nonshared/semaphore.c
@@ -0,0 +1,342 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source Code: main.c and semaphore.c
+** main.c creates process and waits for all processes to get over
+** semaphore.c creates a semaphore and then calls threads which will contend for the semaphore
+**
+** This test is for Object Management Test case for semaphore where Object type is not shareable.
+** Algorithm
+** o Create PROCESS_COUNT processes.
+** o Main Thread of each process creates OBJECT_TYPE Object
+**
+** Author: ShamitP
+**
+**
+**============================================================
+*/
+
+#include <palsuite.h>
+#include "resultbuffer.h"
+#include "resulttime.h"
+
+#define TIMEOUT 5000
+/* Test Input Variables */
+unsigned int USE_PROCESS_COUNT = 0;
+unsigned int THREAD_COUNT = 0;
+unsigned int REPEAT_COUNT = 0;
+unsigned int RELATION_ID = 0;
+
+/* Capture statistics at per thread basis */
+struct statistics{
+ unsigned int processId;
+ unsigned int operationsFailed;
+ unsigned int operationsPassed;
+ unsigned int operationsTotal;
+ DWORD operationTime;
+ unsigned int relationId;
+};
+
+struct ProcessStats{
+ unsigned int processId;
+ DWORD operationTime;
+ unsigned int relationId;
+};
+
+/* Semaphore variables */
+unsigned long lInitialCount = 1; /* Signaled */
+unsigned long lMaximumCount = 1; /* Maximum value of 1 */
+
+HANDLE StartTestsEvHandle = NULL;
+HANDLE hSemaphoreHandle = NULL;
+
+/* Results Buffer */
+ResultBuffer *resultBuffer = NULL;
+
+int testStatus;
+
+const char sTmpEventName[MAX_PATH] = "StartTestEvent";
+
+void PALAPI Run_Thread(LPVOID lpParam);
+
+int GetParameters( int argc, char **argv)
+{
+ if( (argc != 5) || ((argc == 1) && !strcmp(argv[1],"/?"))
+ || !strcmp(argv[1],"/h") || !strcmp(argv[1],"/H"))
+ {
+ printf("PAL -Composite Object Management Semaphore Test\n");
+ printf("Usage:\n");
+ printf("semaphore\n\t[USE_PROCESS_COUNT ( greater than 1] \n");
+ printf("\t[THREAD_COUNT ( greater than 1] \n");
+ printf("\t[REPEAT_COUNT ( greater than 1]\n");
+ printf("\t[RELATION_ID [greater than 1]\n");
+ return -1;
+ }
+
+ // Trace("Args 1 is [%s], Arg 2 is [%s], Arg 3 is [%s]\n", argv[1], argv[2], argv[3]);
+
+ USE_PROCESS_COUNT = atoi(argv[1]);
+ if( USE_PROCESS_COUNT < 0)
+ {
+ printf("\nInvalid USE_PROCESS_COUNT number, Pass greater than 1\n");
+ return -1;
+ }
+
+ THREAD_COUNT = atoi(argv[2]);
+ if( (THREAD_COUNT < 1) || (THREAD_COUNT > MAXIMUM_WAIT_OBJECTS) )
+ {
+ printf("\nInvalid THREAD_COUNT number, Pass greater than 1 and less than %d\n", MAXIMUM_WAIT_OBJECTS);
+ return -1;
+ }
+
+ REPEAT_COUNT = atoi(argv[3]);
+ if( REPEAT_COUNT < 1)
+ {
+ printf("\nInvalid REPEAT_COUNT number, Pass greater than 1\n");
+ return -1;
+ }
+
+ RELATION_ID = atoi(argv[4]);
+ if( RELATION_ID < 1)
+ {
+ printf("\nMain Process:Invalid RELATION_ID number, Pass greater than or Equal to 1\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+ int __cdecl main(INT argc, CHAR **argv)
+{
+ unsigned int i = 0;
+ HANDLE hThread[MAXIMUM_WAIT_OBJECTS];
+ DWORD threadId[MAXIMUM_WAIT_OBJECTS];
+
+ const char *ObjName = "Semaphore";
+
+ DWORD dwParam = 0;
+
+ int returnCode = 0;
+
+ /* Variables to capture the file name and the file pointer at thread level*/
+ char fileName[MAX_PATH];
+ FILE *pFile = NULL;
+ struct statistics* buffer = NULL;
+ int statisticsSize = 0;
+
+ /* Variables to capture the file name and the file pointer at process level*/
+ char processFileName[MAX_PATH];
+ FILE *pProcessFile = NULL;
+ struct ProcessStats processStats;
+ DWORD dwStartTime;
+
+ testStatus = PASS;
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return ( FAIL );
+ }
+
+ if(GetParameters(argc, argv))
+ {
+ Fail("Error in obtaining the parameters\n");
+ }
+ // Trace("Process created, value of process count is [%d]\n", USE_PROCESS_COUNT);
+
+ /* Register the start time */
+ dwStartTime = GetTickCount();
+ processStats.relationId = RELATION_ID;
+ processStats.processId = USE_PROCESS_COUNT;
+
+ _snprintf(processFileName, MAX_PATH, "%d_process_semaphore_%d_.txt", USE_PROCESS_COUNT, RELATION_ID);
+ pProcessFile = fopen(processFileName, "w+");
+ if(pProcessFile == NULL)
+ {
+ Fail("Error in opening process File file for write for process [%d]\n", USE_PROCESS_COUNT);
+ }
+
+ statisticsSize = sizeof(struct statistics);
+
+ _snprintf(fileName, MAX_PATH, "%d_thread_semaphore_%d_.txt", USE_PROCESS_COUNT, RELATION_ID);
+ pFile = fopen(fileName, "w+");
+ if(pFile == NULL)
+ {
+ Fail("Error in opening file for write for process [%d]\n", USE_PROCESS_COUNT);
+ }
+ // For each thread we will log operations failed (int), passed (int), total (int)
+ // and number of ticks (DWORD) for the operations
+ resultBuffer = new ResultBuffer( THREAD_COUNT, statisticsSize);
+
+ StartTestsEvHandle = CreateEvent( NULL, /* lpEventAttributes*/
+ TRUE, /* bManualReset */
+ FALSE, /* bInitialState */
+ NULL); /* name of Event */
+
+ if( StartTestsEvHandle == NULL )
+ {
+ Fail("Error:%d: Unexpected failure "
+ "to create %s Event for process count %d\n", GetLastError(), sTmpEventName, USE_PROCESS_COUNT );
+
+ }
+
+ /* Create StartTest Event */
+ hSemaphoreHandle = CreateSemaphore(
+ NULL, /* lpSemaphoreAttributes */
+ lInitialCount, /*lInitialCount*/
+ lMaximumCount, /*lMaximumCount */
+ NULL
+ );
+
+ if( hSemaphoreHandle == NULL)
+ {
+ Fail("Unable to create Semaphore handle for process id [%d], returned error [%d]\n", i, GetLastError());
+ }
+ /* We already assume that the Semaphore was created previously*/
+
+ for( i = 0; i < THREAD_COUNT; i++ )
+ {
+ dwParam = (int) i;
+ //Create thread
+ hThread[i] = CreateThread(
+ NULL, /* no security attributes */
+ 0, /* use default stack size */
+ (LPTHREAD_START_ROUTINE)Run_Thread,/* thread function */
+ (LPVOID)dwParam, /* argument to thread function */
+ 0, /* use default creation flags */
+ &threadId[i] /* returns the thread identifier*/
+ );
+
+
+ if(hThread[i] == NULL)
+ {
+ Fail("Create Thread failed for %d process, and GetLastError value is %d\n", USE_PROCESS_COUNT, GetLastError());
+ }
+
+ }
+
+ if (!SetEvent(StartTestsEvHandle))
+ {
+ Fail("Set Event for Start Tests failed for %d process, and GetLastError value is %d\n", USE_PROCESS_COUNT, GetLastError());
+ }
+
+ /* Test running */
+ returnCode = WaitForMultipleObjects( THREAD_COUNT, hThread, TRUE, INFINITE);
+
+ if( WAIT_OBJECT_0 != returnCode )
+ {
+ Trace("Wait for Object(s) for %d process returned %d, and GetLastError value is %d\n", USE_PROCESS_COUNT, returnCode, GetLastError());
+ testStatus = FAIL;
+ }
+
+ processStats.operationTime = GetTimeDiff(dwStartTime);
+
+ /* Write to a file*/
+ if(pFile!= NULL)
+ {
+ for( i = 0; i < THREAD_COUNT; i++ )
+ {
+ buffer = (struct statistics *)resultBuffer->getResultBuffer(i);
+ returnCode = fprintf(pFile, "%d,%d,%d,%d,%lu,%d\n", buffer->processId, buffer->operationsFailed, buffer->operationsPassed, buffer->operationsTotal, buffer->operationTime, buffer->relationId );
+ //Trace("Iteration %d over\n", i);
+
+ }
+ }
+ fclose(pFile);
+ /* Logging for the test case over, clean up the handles */
+
+// Trace("Test Thread %d done\n", USE_PROCESS_COUNT);
+
+ for( i = 0; i < THREAD_COUNT; i++ )
+ {
+ if(!CloseHandle(hThread[i]) )
+ {
+ Trace("Error:%d: CloseHandle failed for Process [%d] hThread[%d]\n", GetLastError(), USE_PROCESS_COUNT, i);
+ testStatus = FAIL;
+ }
+ }
+
+ if(!CloseHandle(StartTestsEvHandle))
+ {
+ Trace("Error:%d: CloseHandle failed for Process [%d] StartTestsEvHandle\n", GetLastError(), USE_PROCESS_COUNT);
+ testStatus = FAIL;
+ }
+
+ if(!CloseHandle(hSemaphoreHandle))
+ {
+ Trace("Error:%d: CloseHandle failed for Process [%d] hSemaphoreHandle\n", GetLastError(), USE_PROCESS_COUNT);
+ testStatus = FAIL;
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
+void PALAPI Run_Thread (LPVOID lpParam)
+{
+ unsigned int i = 0;
+ DWORD dwWaitResult;
+
+ int Id=(int)lpParam;
+
+ struct statistics stats;
+ DWORD dwStartTime;
+
+ stats.relationId = RELATION_ID;
+ stats.processId = USE_PROCESS_COUNT;
+ stats.operationsFailed = 0;
+ stats.operationsPassed = 0;
+ stats.operationsTotal = 0;
+ stats.operationTime = 0;
+
+ dwWaitResult = WaitForSingleObject(
+ StartTestsEvHandle, // handle to start test handle
+ TIMEOUT);
+
+ if(dwWaitResult != WAIT_OBJECT_0)
+ {
+ Fail("Error while waiting for StartTest Event@ thread %d, RC is %d, Error is %d\n", Id, dwWaitResult, GetLastError());
+ }
+
+ dwStartTime = GetTickCount();
+
+ for( i = 0; i < REPEAT_COUNT; i++ )
+ {
+ dwWaitResult = WaitForSingleObject(
+ hSemaphoreHandle, // handle to Semaphore
+ TIMEOUT);
+
+ if(dwWaitResult != WAIT_OBJECT_0)
+ {
+// Trace("Error while waiting for onject @ thread %d, # iter %d, RC is %d, Error is %d\n", Id, i, dwWaitResult, GetLastError());
+ stats.operationsFailed += 1;
+ stats.operationsTotal += 1;
+ testStatus = FAIL;
+ continue;
+ }
+ if (! ReleaseSemaphore(hSemaphoreHandle, 1, NULL))
+ {
+ // Deal with error.
+ // Trace("Error while releasing Semaphore @ thread %d # iter %d\n", Id, i);
+ stats.operationsFailed += 1;
+ stats.operationsTotal += 1;
+ // Probably need to have while true loop to attempt to release semaphore...
+ testStatus = FAIL;
+ continue;
+ }
+
+ stats.operationsTotal += 1;
+ stats.operationsPassed += 1;
+// Trace("Successs while releasing Semaphore @ iteration %d -> thread %d -> Process %d\n", i, Id, USE_PROCESS_COUNT);
+
+ }
+
+ stats.operationTime = GetTimeDiff(dwStartTime);
+ if(resultBuffer->LogResult(Id, (char *)&stats))
+ {
+ Fail("Error:%d: while writing to shared memory, Thread Id is[%d] and Process id is [%d]\n", GetLastError(), Id, USE_PROCESS_COUNT);
+ }
+ // Trace("Thread %d over for process %d\n", Id, USE_PROCESS_COUNT);
+}
diff --git a/src/pal/tests/palsuite/composite/object_management/semaphore/shared/CMakeLists.txt b/src/pal/tests/palsuite/composite/object_management/semaphore/shared/CMakeLists.txt
new file mode 100644
index 0000000000..12d3ca867e
--- /dev/null
+++ b/src/pal/tests/palsuite/composite/object_management/semaphore/shared/CMakeLists.txt
@@ -0,0 +1,21 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ main.c
+ semaphore.c
+)
+
+add_executable(paltest_semaphore_shared
+ ${SOURCES}
+)
+
+add_dependencies(paltest_semaphore_shared coreclrpal)
+
+target_link_libraries(paltest_semaphore_shared
+ pthread
+ rt
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/composite/object_management/semaphore/shared/main.c b/src/pal/tests/palsuite/composite/object_management/semaphore/shared/main.c
new file mode 100644
index 0000000000..deb8252b70
--- /dev/null
+++ b/src/pal/tests/palsuite/composite/object_management/semaphore/shared/main.c
@@ -0,0 +1,278 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source Code: main.c and semaphore.c
+** main.c creates process and waits for all processes to get over
+** semaphore.c creates a semaphore and then calls threads which will contend for the semaphore
+**
+** This test is for Object Management Test case for semaphore where Object type is shareable.
+** Algorithm
+** o Main Process Creates OBJECT_TYPE Object
+** o Create PROCESS_COUNT processes aware of the Shared Object
+**
+**
+**
+**============================================================
+*/
+
+#include <palsuite.h>
+#include "resulttime.h"
+
+/* Test Input Variables */
+unsigned int PROCESS_COUNT = 1;
+unsigned int THREAD_COUNT = 1;
+unsigned int REPEAT_COUNT = 4;
+unsigned int RELATION_ID = 1001;
+
+
+unsigned long lInitialCount = 1; /* Signaled */
+unsigned long lMaximumCount = 1; /* Maximum value of 1 */
+
+char objectSuffix[MAX_PATH];
+
+struct TestStats{
+ DWORD operationTime;
+ unsigned int relationId;
+ unsigned int processCount;
+ unsigned int threadCount;
+ unsigned int repeatCount;
+ char* buildNumber;
+
+};
+
+int GetParameters( int argc, char **argv)
+{
+ if( (!((argc == 5) || (argc == 6) ) )|| ((argc == 1) && !strcmp(argv[1],"/?"))
+ || !strcmp(argv[1],"/h") || !strcmp(argv[1],"/H"))
+ {
+ printf("PAL -Composite Object Management event Test\n");
+ printf("Usage:\n");
+ printf("main\n\t[PROCESS_COUNT (greater than 1)] \n");
+ printf("\t[THREAD_COUNT (greater than 1)] \n");
+ printf("\t[REPEAT_COUNT (greater than 1)]\n");
+ printf("\t[RELATION_ID [greater than or equal to 1]\n");
+ printf("\t[Object Name Suffix]\n");
+ return -1;
+ }
+
+ PROCESS_COUNT = atoi(argv[1]);
+ if( (PROCESS_COUNT < 1) || (PROCESS_COUNT > MAXIMUM_WAIT_OBJECTS) )
+ {
+ printf("\nMain Process:Invalid PROCESS_COUNT number, Pass greater than 1 and less than PROCESS_COUNT %d\n", MAXIMUM_WAIT_OBJECTS);
+ return -1;
+ }
+
+ THREAD_COUNT = atoi(argv[2]);
+ if( (THREAD_COUNT < 1) || (THREAD_COUNT > MAXIMUM_WAIT_OBJECTS) )
+ {
+ printf("\nInvalid THREAD_COUNT number, Pass greater than 1 and less than %d\n", MAXIMUM_WAIT_OBJECTS);
+ return -1;
+ }
+
+ REPEAT_COUNT = atoi(argv[3]);
+ if( REPEAT_COUNT < 1)
+ {
+ printf("\nMain Process:Invalid REPEAT_COUNT number, Pass greater than 1\n");
+ return -1;
+ }
+
+ RELATION_ID = atoi(argv[4]);
+ if( RELATION_ID < 1)
+ {
+ printf("\nMain Process:Invalid RELATION_ID number, Pass greater than 1\n");
+ return -1;
+ }
+
+
+ if(argc == 6)
+ {
+ strncpy(objectSuffix, argv[5], MAX_PATH-1);
+ }
+
+ return 0;
+}
+
+ int __cdecl main(INT argc, CHAR **argv)
+{
+ unsigned int i = 0;
+ HANDLE hProcess[MAXIMUM_WAIT_OBJECTS];
+ HANDLE hSemaphoreHandle;
+
+ STARTUPINFO si[MAXIMUM_WAIT_OBJECTS];
+ PROCESS_INFORMATION pi[MAXIMUM_WAIT_OBJECTS];
+
+ char lpCommandLine[MAX_PATH] = "";
+ char ObjName[MAX_PATH] = "SHARED_SEMAPHORE";
+
+ int returnCode = 0;
+ DWORD processReturnCode = 0;
+ int testReturnCode = PASS;
+
+ char fileName[MAX_PATH];
+ FILE *pFile = NULL;
+ DWORD dwStartTime;
+ struct TestStats testStats;
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return ( FAIL );
+ }
+
+/*
+"While the new PAL does support named semaphore it's unclear
+if we should change the Windows PAL, since we share that w/ Rotor
+and they are still using the old PAL. For the time being it may
+make the most sense to just skip the named semaphore test on Windows
+- from an object management perspective it doesn't really gain
+us anything over what we already have."
+*/
+#ifdef PLATFORM_UNIX
+
+ ZeroMemory( objectSuffix, MAX_PATH );
+
+ if(GetParameters(argc, argv))
+ {
+ Fail("Error in obtaining the parameters\n");
+ }
+
+ if(argc == 6)
+ {
+ strncat(ObjName, objectSuffix, MAX_PATH - (sizeof(ObjName) + 1) );
+ }
+
+ /* Register the start time */
+ dwStartTime = GetTickCount();
+ testStats.relationId = RELATION_ID;
+ testStats.processCount = PROCESS_COUNT;
+ testStats.threadCount = THREAD_COUNT;
+ testStats.repeatCount = REPEAT_COUNT;
+ testStats.buildNumber = getBuildNumber();
+
+ _snprintf(fileName, MAX_PATH, "main_semaphore_%d_.txt", RELATION_ID);
+ pFile = fopen(fileName, "w+");
+ if(pFile == NULL)
+ {
+ Fail("Error in opening main file for write\n");
+ }
+
+ hSemaphoreHandle = CreateSemaphore(
+ NULL, /* lpSemaphoreAttributes */
+ lInitialCount, /*lInitialCount*/
+ lMaximumCount, /*lMaximumCount */
+ ObjName
+ );
+
+ if( hSemaphoreHandle == NULL)
+ {
+ Fail("Unable to create shared Semaphore handle @ Main returned error [%d]\n", GetLastError());
+ }
+
+ for( i = 0; i < PROCESS_COUNT; i++ )
+ {
+
+
+ ZeroMemory( lpCommandLine, MAX_PATH );
+ if ( _snprintf( lpCommandLine, MAX_PATH-1, "semaphore %d %d %d %d %s", i, THREAD_COUNT, REPEAT_COUNT, RELATION_ID, objectSuffix) < 0 )
+ {
+ Fail("Error: Insufficient semaphore name string length for %s for iteration [%d]\n", ObjName, i);
+ }
+
+
+ /* Zero the data structure space */
+ ZeroMemory ( &pi[i], sizeof(pi[i]) );
+ ZeroMemory ( &si[i], sizeof(si[i]) );
+
+ /* Set the process flags and standard io handles */
+ si[i].cb = sizeof(si[i]);
+
+ if(!CreateProcess( NULL, /* lpApplicationName*/
+ lpCommandLine, /* lpCommandLine */
+ NULL, /* lpProcessAttributes */
+ NULL, /* lpThreadAttributes */
+ TRUE, /* bInheritHandles */
+ 0, /* dwCreationFlags, */
+ NULL, /* lpEnvironment */
+ NULL, /* pCurrentDirectory */
+ &si[i], /* lpStartupInfo */
+ &pi[i] /* lpProcessInformation */
+ ))
+ {
+ Fail("Process Not created for [%d], the error code is [%d]\n", i, GetLastError());
+ }
+ else
+ {
+ hProcess[i] = pi[i].hProcess;
+// Trace("Process created for [%d]\n", i);
+
+ }
+
+ }
+
+ returnCode = WaitForMultipleObjects( PROCESS_COUNT, hProcess, TRUE, INFINITE);
+ if( WAIT_OBJECT_0 != returnCode )
+ {
+ Trace("Wait for Object(s) @ Main thread for %d processes returned %d, and GetLastError value is %d\n", PROCESS_COUNT, returnCode, GetLastError());
+ testReturnCode = FAIL;
+ }
+
+ for( i = 0; i < PROCESS_COUNT; i++ )
+ {
+ /* check the exit code from the process */
+ if( ! GetExitCodeProcess( pi[i].hProcess, &processReturnCode ) )
+ {
+ Trace( "GetExitCodeProcess call failed for iteration %d with error code %u\n",
+ i, GetLastError() );
+
+ testReturnCode = FAIL;
+ }
+
+ if(processReturnCode == FAIL)
+ {
+ Trace( "Process [%d] failed and returned FAIL\n", i);
+ testReturnCode = FAIL;
+ }
+
+ if(!CloseHandle(pi[i].hThread))
+ {
+ Trace("Error:%d: CloseHandle failed for Process [%d] hThread\n", GetLastError(), i);
+ testReturnCode = FAIL;
+ }
+
+ if(!CloseHandle(pi[i].hProcess) )
+ {
+ Trace("Error:%d: CloseHandle failed for Process [%d] hProcess\n", GetLastError(), i);
+ testReturnCode = FAIL;
+ }
+ }
+
+ testStats.operationTime = GetTimeDiff(dwStartTime);
+ fprintf(pFile, "%d,%d,%d,%d,%d,%s\n", testStats.operationTime, testStats.relationId, testStats.processCount, testStats.threadCount, testStats.repeatCount, testStats.buildNumber);
+ if(fclose(pFile))
+ {
+ Trace("Error: fclose failed for pFile\n");
+ testReturnCode = FAIL;
+ };
+
+ if(!CloseHandle(hSemaphoreHandle))
+ {
+ Trace("Error:%d: CloseHandle failed for hSemaphoreHandle\n", GetLastError());
+ testReturnCode = FAIL;
+
+ }
+
+ if( testReturnCode == PASS)
+ {
+ Trace("Test Passed\n");
+ }
+ else
+ {
+ Trace("Test Failed\n");
+ }
+
+#endif //PLATFORM_UNIX
+ PAL_Terminate();
+ return testReturnCode;
+}
diff --git a/src/pal/tests/palsuite/composite/object_management/semaphore/shared/semaphore.c b/src/pal/tests/palsuite/composite/object_management/semaphore/shared/semaphore.c
new file mode 100644
index 0000000000..5143c55143
--- /dev/null
+++ b/src/pal/tests/palsuite/composite/object_management/semaphore/shared/semaphore.c
@@ -0,0 +1,351 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source Code: main.c and semaphore.c
+** main.c creates process and waits for all processes to get over
+** semaphore.c creates a semaphore and then calls threads which will contend for the semaphore
+**
+** This test is for Object Management Test case for semaphore where Object type is shareable.
+** Algorithm
+** o Main Process Creates OBJECT_TYPE Object
+** o Create PROCESS_COUNT processes aware of the Shared Object
+**
+**
+**
+**============================================================
+*/
+
+#include <palsuite.h>
+#include "resultbuffer.h"
+#include "resulttime.h"
+
+#define TIMEOUT 5000
+/* Test Input Variables */
+unsigned int USE_PROCESS_COUNT = 0;
+unsigned int THREAD_COUNT = 0;
+unsigned int REPEAT_COUNT = 0;
+unsigned int RELATION_ID= 0;
+
+/* Capture statistics at per thread basis */
+struct statistics{
+ unsigned int processId;
+ unsigned int operationsFailed;
+ unsigned int operationsPassed;
+ unsigned int operationsTotal;
+ DWORD operationTime;
+ unsigned int relationId;
+};
+
+struct ProcessStats{
+ unsigned int processId;
+ DWORD operationTime;
+ unsigned int relationId;
+};
+
+/* Semaphore variables */
+unsigned long lInitialCount = 1; /* Signaled */
+unsigned long lMaximumCount = 1; /* Maximum value of 1 */
+
+HANDLE StartTestsEvHandle = NULL;
+HANDLE hSemaphoreHandle = NULL;
+
+/* Results Buffer */
+ResultBuffer *resultBuffer = NULL;
+
+int testStatus;
+
+const char sTmpEventName[MAX_PATH] = "StartTestEvent";
+char objectSuffix[MAX_PATH];
+
+void PALAPI Run_Thread(LPVOID lpParam);
+
+int GetParameters( int argc, char **argv)
+{
+ if( (!((argc == 5) || (argc == 6) ) )|| ((argc == 1) && !strcmp(argv[1],"/?"))
+ || !strcmp(argv[1],"/h") || !strcmp(argv[1],"/H"))
+ {
+ printf("PAL -Composite Object Management event Test\n");
+ printf("Usage:\n");
+ printf("main\n\t[PROCESS_COUNT (greater than 1)] \n");
+ printf("\t[THREAD_COUNT (greater than 1)] \n");
+ printf("\t[REPEAT_COUNT (greater than 1)]\n");
+ printf("\t[RELATION_ID [greater than or equal to 1]\n");
+ printf("\t[Object Name Suffix]\n");
+ return -1;
+ }
+
+ USE_PROCESS_COUNT = atoi(argv[1]);
+ if(USE_PROCESS_COUNT < 0)
+ {
+ printf("\nMain Process:Invalid PROCESS_COUNT number, Pass greater than 0 \n");
+ return -1;
+ }
+
+ THREAD_COUNT = atoi(argv[2]);
+ if( (THREAD_COUNT < 1) || (THREAD_COUNT > MAXIMUM_WAIT_OBJECTS) )
+ {
+ printf("\nInvalid THREAD_COUNT number, Pass greater than 1 and less than %d\n", MAXIMUM_WAIT_OBJECTS);
+ return -1;
+ }
+
+ REPEAT_COUNT = atoi(argv[3]);
+ if( REPEAT_COUNT < 1)
+ {
+ printf("\nMain Process:Invalid REPEAT_COUNT number, Pass greater than 1\n");
+ return -1;
+ }
+
+ RELATION_ID = atoi(argv[4]);
+ if( RELATION_ID < 1)
+ {
+ printf("\nMain Process:Invalid RELATION_ID number, Pass greater than 1\n");
+ return -1;
+ }
+
+ if(argc == 6)
+ {
+ strncpy(objectSuffix, argv[5], MAX_PATH-1);
+ }
+
+ return 0;
+}
+
+ int __cdecl main(INT argc, CHAR **argv)
+{
+ unsigned int i = 0;
+ HANDLE hThread[MAXIMUM_WAIT_OBJECTS];
+ DWORD threadId[MAXIMUM_WAIT_OBJECTS];
+
+ char ObjName[MAX_PATH] = "SHARED_SEMAPHORE";
+ DWORD dwParam = 0;
+
+ int returnCode = 0;
+
+ /* Variables to capture the file name and the file pointer at thread level*/
+ char fileName[MAX_PATH];
+ FILE *pFile = NULL;
+ struct statistics* buffer = NULL;
+ int statisticsSize = 0;
+
+ /* Variables to capture the file name and the file pointer at process level*/
+ char processFileName[MAX_PATH];
+ FILE *pProcessFile = NULL;
+ struct ProcessStats processStats;
+ DWORD dwStartTime;
+
+ testStatus = PASS;
+
+ ZeroMemory( objectSuffix, MAX_PATH );
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return ( FAIL );
+ }
+
+ if(GetParameters(argc, argv))
+ {
+ Fail("Error in obtaining the parameters\n");
+ }
+// Trace("Process created, value of process count is [%d]\n", USE_PROCESS_COUNT);
+
+ if(argc == 6)
+ {
+ strncat(ObjName , objectSuffix, MAX_PATH - (sizeof(ObjName) + 1) );
+ }
+
+ /* Register the start time */
+ dwStartTime = GetTickCount();
+ processStats.relationId = RELATION_ID;
+ processStats.processId = USE_PROCESS_COUNT;
+
+ _snprintf(processFileName, MAX_PATH, "%d_process_semaphore_%d_.txt", USE_PROCESS_COUNT, RELATION_ID);
+ pProcessFile = fopen(processFileName, "w+");
+ if(pProcessFile == NULL)
+ {
+ Fail("Error in opening process File file for write for process [%d]\n", USE_PROCESS_COUNT);
+ }
+
+ statisticsSize = sizeof(struct statistics);
+
+ _snprintf(fileName, MAX_PATH, "%d_thread_semaphore_%d_.txt", USE_PROCESS_COUNT, RELATION_ID);
+ pFile = fopen(fileName, "w+");
+ if(pFile == NULL)
+ {
+ Fail("Error in opening file for write for process [%d]\n", USE_PROCESS_COUNT);
+ }
+ // For each thread we will log operations failed (int), passed (int), total (int)
+ // and number of ticks (DWORD) for the operations
+ resultBuffer = new ResultBuffer( THREAD_COUNT, statisticsSize);
+
+ /* Create Start Tests event */
+ StartTestsEvHandle = CreateEvent( NULL, /* lpEventAttributes*/
+ TRUE, /* bManualReset */
+ FALSE, /* bInitialState */
+ NULL); /* name of Event */
+
+ if( StartTestsEvHandle == NULL )
+ {
+ Fail("Error:%d: Unexpected failure "
+ "to create %s Event for process count %d\n", GetLastError(), sTmpEventName, USE_PROCESS_COUNT );
+
+ }
+
+ hSemaphoreHandle = CreateSemaphore(
+ NULL, /* lpSemaphoreAttributes */
+ lInitialCount, /*lInitialCount*/
+ lMaximumCount, /*lMaximumCount */
+ ObjName
+ );
+
+
+ if( (hSemaphoreHandle == NULL) || (GetLastError() != ERROR_ALREADY_EXISTS) )
+ {
+ Fail("Unable to create Semaphore handle for process id [%d], returned error [%d], expected ERROR_ALREADY_EXISTS\n", i, GetLastError());
+ }
+
+ /* We already assume that the Semaphore was created previously*/
+
+ for( i = 0; i < THREAD_COUNT; i++ )
+ {
+ dwParam = (int) i;
+ //Create thread
+ hThread[i] = CreateThread(
+ NULL, /* no security attributes */
+ 0, /* use default stack size */
+ (LPTHREAD_START_ROUTINE)Run_Thread,/* thread function */
+ (LPVOID)dwParam, /* argument to thread function */
+ 0, /* use default creation flags */
+ &threadId[i] /* returns the thread identifier*/
+ );
+
+ if(hThread[i] == NULL)
+ {
+ Fail("Create Thread failed for %d process, and GetLastError value is %d\n", USE_PROCESS_COUNT, GetLastError());
+ }
+ }
+
+ if (!SetEvent(StartTestsEvHandle))
+ {
+ Fail("Set Event for Start Tests failed for %d process, and GetLastError value is %d\n", USE_PROCESS_COUNT, GetLastError());
+ }
+
+ /* Test running */
+ returnCode = WaitForMultipleObjects( THREAD_COUNT, hThread, TRUE, INFINITE);
+
+ if( WAIT_OBJECT_0 != returnCode )
+ {
+ Trace("Wait for Object(s) for %d process returned %d, and GetLastError value is %d\n", USE_PROCESS_COUNT, returnCode, GetLastError());
+ testStatus = FAIL;
+ }
+
+ processStats.operationTime = GetTimeDiff(dwStartTime);
+
+ /* Write to a file*/
+ if(pFile!= NULL)
+ {
+ for( i = 0; i < THREAD_COUNT; i++ )
+ {
+ buffer = (struct statistics *)resultBuffer->getResultBuffer(i);
+ returnCode = fprintf(pFile, "%d,%d,%d,%d,%lu,%d\n", buffer->processId, buffer->operationsFailed, buffer->operationsPassed, buffer->operationsTotal, buffer->operationTime, buffer->relationId );
+// Trace("Iteration %d over\n", i);
+
+ }
+ }
+ fclose(pFile);
+ /* Logging for the test case over, clean up the handles */
+
+// Trace("Test Thread %d done\n", USE_PROCESS_COUNT);
+ for( i = 0; i < THREAD_COUNT; i++ )
+ {
+ if(!CloseHandle(hThread[i]) )
+ {
+ Trace("Error:%d: CloseHandle failed for Process [%d] hThread[%d]\n", GetLastError(), USE_PROCESS_COUNT, i);
+ testStatus = FAIL;
+ }
+ }
+
+ if(!CloseHandle(StartTestsEvHandle))
+ {
+ Trace("Error:%d: CloseHandle failed for Process [%d] StartTestsEvHandle\n", GetLastError(), USE_PROCESS_COUNT);
+ testStatus = FAIL;
+ }
+
+ if(!CloseHandle(hSemaphoreHandle))
+ {
+ Trace("Error:%d: CloseHandle failed for Process [%d] hSemaphoreHandle\n", GetLastError(), USE_PROCESS_COUNT);
+ testStatus = FAIL;
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
+void PALAPI Run_Thread (LPVOID lpParam)
+{
+ unsigned int i = 0;
+ DWORD dwWaitResult;
+
+ int Id=(int)lpParam;
+
+ struct statistics stats;
+ DWORD dwStartTime;
+
+ stats.relationId = RELATION_ID;
+ stats.processId = USE_PROCESS_COUNT;
+ stats.operationsFailed = 0;
+ stats.operationsPassed = 0;
+ stats.operationsTotal = 0;
+ stats.operationTime = 0;
+
+ dwWaitResult = WaitForSingleObject(
+ StartTestsEvHandle, // handle to start test handle
+ TIMEOUT);
+
+ if(dwWaitResult != WAIT_OBJECT_0)
+ {
+ Fail("Error while waiting for StartTest Event@ thread %d, RC is %d, Error is %d\n", Id, dwWaitResult, GetLastError());
+ }
+
+ dwStartTime = GetTickCount();
+
+ for( i = 0; i < REPEAT_COUNT; i++ )
+ {
+ dwWaitResult = WaitForSingleObject(
+ hSemaphoreHandle, // handle to Semaphore
+ TIMEOUT);
+
+ if(dwWaitResult != WAIT_OBJECT_0)
+ {
+// Trace("Error while waiting for onject @ thread %d, # iter %d, RC is %d, Error is %d\n", Id, i, dwWaitResult, GetLastError());
+ stats.operationsFailed += 1;
+ stats.operationsTotal += 1;
+ testStatus = FAIL;
+ continue;
+ }
+ if (! ReleaseSemaphore(hSemaphoreHandle, 1, NULL))
+ {
+ // Deal with error.
+ // Trace("Error while releasing Semaphore @ thread %d # iter %d\n", Id, i);
+ stats.operationsFailed += 1;
+ stats.operationsTotal += 1;
+ // Probably need to have while true loop to attempt to release semaphore..
+ testStatus = FAIL;
+ continue;
+ }
+
+ stats.operationsTotal += 1;
+ stats.operationsPassed += 1;
+// Trace("Successs while releasing Semaphore @ iteration %d -> thread %d -> Process %d\n", i, Id, USE_PROCESS_COUNT);
+
+ }
+
+ stats.operationTime = GetTimeDiff(dwStartTime);
+ if(resultBuffer->LogResult(Id, (char *)&stats))
+ {
+ Fail("Error:%d: while writing to shared memory, Thread Id is[%d] and Process id is [%d]\n", GetLastError(), Id, USE_PROCESS_COUNT);
+ }
+ // Trace("Thread %d over for process %d\n", Id, USE_PROCESS_COUNT);
+}
diff --git a/src/pal/tests/palsuite/composite/synchronization/CMakeLists.txt b/src/pal/tests/palsuite/composite/synchronization/CMakeLists.txt
new file mode 100644
index 0000000000..cffb4f78ab
--- /dev/null
+++ b/src/pal/tests/palsuite/composite/synchronization/CMakeLists.txt
@@ -0,0 +1,6 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(criticalsection)
+add_subdirectory(nativecriticalsection)
+add_subdirectory(nativecs_interlocked)
+
diff --git a/src/pal/tests/palsuite/composite/synchronization/criticalsection/CMakeLists.txt b/src/pal/tests/palsuite/composite/synchronization/criticalsection/CMakeLists.txt
new file mode 100644
index 0000000000..936c0fe82d
--- /dev/null
+++ b/src/pal/tests/palsuite/composite/synchronization/criticalsection/CMakeLists.txt
@@ -0,0 +1,20 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ criticalsection.c
+ mainWrapper.c
+)
+
+add_executable(paltest_synchronization_criticalsection
+ ${SOURCES}
+)
+
+add_dependencies(paltest_synchronization_criticalsection coreclrpal)
+
+target_link_libraries(paltest_synchronization_criticalsection
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/composite/synchronization/criticalsection/criticalsection.c b/src/pal/tests/palsuite/composite/synchronization/criticalsection/criticalsection.c
new file mode 100644
index 0000000000..2fcd363e8a
--- /dev/null
+++ b/src/pal/tests/palsuite/composite/synchronization/criticalsection/criticalsection.c
@@ -0,0 +1,418 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: criticalsection.c
+**
+** Purpose: Test Critical Section Reengineering PAL Effort
+**
+** PseudoCode:
+ Preparation:
+ Create PROCESS_COUNT processes.
+ In each process create a Critical Section
+
+ Test:
+ Create THREAD_COUNT threads.
+ In a loop repeated REPEAT_COUNT times:
+ Enter Critical Section
+ Do Work
+ Leave Critical Section
+ The main thread waits for all of the created threads to exit (WFMO wait all on the created thread handles) and call DeleteCriticalSection
+
+ Parameters:
+ PROCESS_COUNT: Number of processes
+ THREAD_COUNT: Number of threads in each process
+ REPEAT_COUNT: The number of times to execute the loop..
+
+ Statistics Captured:
+ Total elapsed time
+ MTBF
+
+ Scenario:
+ Single Process with Multiple threads. Main thread creates critical section.
+ All other threads call EnterCriticalSection. When thread enters critical section
+ it does some work and leaves critical section.
+
+** Dependencies:
+ CreateThread
+** InitializeCriticalSection
+** EnterCriticalSection
+** LeaveCriticalSection
+** DeleteCriticalSection
+** WaitForSingleObject
+**
+** Author: rameshg
+**
+**
+**=========================================================*/
+
+#include <palsuite.h>
+#include "resultbuffer.h"
+
+//Global Variables
+DWORD dwThreadId;
+long long GLOBAL_COUNTER ;
+HANDLE g_hEvent;
+
+/* Test Input Variables */
+unsigned int USE_PROCESS_COUNT = 0;
+unsigned int THREAD_COUNT = 0;
+unsigned int REPEAT_COUNT = 0;
+unsigned int SLEEP_LENGTH = 0;
+unsigned int RELATION_ID = 0;
+
+
+CRITICAL_SECTION CriticalSectionM; /* Critical Section Object (used as mutex) */
+
+
+/* Capture statistics for each worker thread */
+struct statistics{
+ unsigned int processId;
+ unsigned int operationsFailed;
+ unsigned int operationsPassed;
+ unsigned int operationsTotal;
+ DWORD operationTime; //Milliseconds
+ unsigned int relationId;
+};
+
+
+/*Capture Statistics at a Process level*/
+struct processStatistics{
+ unsigned int processId;
+ DWORD operationTime; //Milliseconds
+ unsigned int relationId;
+};
+
+
+ResultBuffer *resultBuffer;
+
+//function declarations
+int GetParameters( int , char **);
+void setup (void);
+void cleanup(void);
+void incrementCounter(void);
+DWORD PALAPI enterandleavecs( LPVOID );
+
+
+/*
+*Setup for the test case
+*/
+
+VOID
+setup(VOID)
+{
+
+g_hEvent = CreateEvent(NULL,TRUE,FALSE, NULL);
+if(g_hEvent == NULL)
+{
+ Fail("Create Event Failed\n"
+ "GetLastError returned %d\n", GetLastError());
+}
+
+GLOBAL_COUNTER=0;
+/*
+* Create mutual exclusion mechanisms
+*/
+InitializeCriticalSection ( &CriticalSectionM );
+
+}
+
+
+/*
+* Cleanup for the test case
+*/
+VOID
+cleanup(VOID)
+{
+ /*
+ * Clean up Critical Section object
+ */
+ DeleteCriticalSection(&CriticalSectionM);
+ PAL_Terminate();
+}
+
+
+/*function that increments a counter*/
+VOID
+incrementCounter(VOID)
+{
+
+ if (INT_MAX==GLOBAL_COUNTER)
+ GLOBAL_COUNTER=0;
+
+ GLOBAL_COUNTER++;
+
+}
+
+/*
+ * Enter and Leave Critical Section
+ */
+DWORD
+PALAPI
+enterandleavecs( LPVOID lpParam )
+{
+
+ struct statistics stats;
+ int loopcount = REPEAT_COUNT;
+ int i;
+ DWORD dwStart =0;
+
+ int Id=(int)lpParam;
+
+ //initialize strucutre to hold thread level statistics
+ stats.relationId = RELATION_ID;
+ stats.processId = USE_PROCESS_COUNT;
+ stats.operationsFailed = 0;
+ stats.operationsPassed = 0;
+ stats.operationsTotal = 0;
+ stats.operationTime = 0;
+
+ //Wait for main thread to signal event
+ if (WAIT_OBJECT_0 != WaitForSingleObject(g_hEvent,INFINITE))
+ {
+ Fail ("readfile: Wait for Single Object (g_hEvent) failed. Failing test.\n"
+ "GetLastError returned %d\n", GetLastError());
+ }
+
+ //Collect operation start time
+ dwStart = GetTickCount();
+
+ //Operation starts loopcount times
+ for(i = 0; i < loopcount; i++)
+ {
+
+ EnterCriticalSection(&CriticalSectionM);
+ /*
+ *Do Some Thing once you enter critical section
+ */
+ incrementCounter();
+ LeaveCriticalSection(&CriticalSectionM);
+
+ stats.operationsPassed++;
+ stats.operationsTotal++;
+ }
+ //collect operation end time
+ stats.operationTime = GetTickCount() - dwStart;
+
+ /*Trace("\n\n\n\nOperation Time %d\n", stats.operationTime);
+ Trace("Operation Passed %d\n", stats.operationsPassed);
+ Trace("Operation Total %d\n", stats.operationsTotal);
+ Trace("Operation Failed %d\n", stats.operationsFailed); */
+
+ if(resultBuffer->LogResult(Id, (char *)&stats))
+ {
+ Fail("Error while writing to shared memory, Thread Id is[%d] and Process id is [%d]\n", Id, USE_PROCESS_COUNT);
+ }
+
+
+ return 0;
+}
+
+
+int __cdecl main (int argc, char **argv)
+{
+
+/*
+* Parameter to the threads that will be created
+*/
+DWORD dwThrdParam = 0;
+HANDLE hThread[64];
+unsigned int i = 0;
+DWORD dwStart;
+
+/* Variables to capture the file name and the file pointer*/
+char fileName[MAX_PATH_FNAME];
+char processFileName[MAX_PATH_FNAME];
+FILE *hFile,*hProcessFile;
+struct processStatistics processStats;
+
+struct statistics* buffer;
+int statisticsSize = 0;
+
+/*
+* PAL Initialize
+*/
+if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+if(GetParameters(argc, argv))
+ {
+ Fail("Error in obtaining the parameters\n");
+ }
+
+
+/*setup file for process result collection */
+_snprintf(processFileName, MAX_PATH_FNAME, "%d_process_criticalsection_%d_.txt", USE_PROCESS_COUNT, RELATION_ID);
+hProcessFile = fopen(processFileName, "w+");
+if(hProcessFile == NULL)
+ {
+ Fail("Error in opening file to write process results for process [%d]\n", USE_PROCESS_COUNT);
+ }
+
+//Initialize Process Stats Variables
+processStats.operationTime = 0;
+processStats.processId = USE_PROCESS_COUNT;
+processStats.relationId = RELATION_ID; //Will change later
+
+//Start Process Time Capture
+dwStart = GetTickCount();
+
+//setup file for thread result collection
+statisticsSize = sizeof(struct statistics);
+_snprintf(fileName, MAX_PATH_FNAME, "%d_thread_criticalsection_%d_.txt", USE_PROCESS_COUNT, RELATION_ID);
+hFile = fopen(fileName, "w+");
+if(hFile == NULL)
+{
+ Fail("Error in opening file for write for process [%d]\n", USE_PROCESS_COUNT);
+}
+
+// For each thread we will log operations failed (int), passed (int), total (int)
+// and number of ticks (DWORD) for the operations
+resultBuffer = new ResultBuffer( THREAD_COUNT, statisticsSize);
+
+/*
+* Call the Setup Routine
+*/
+setup();
+
+//Create Thread Count Worker Threads
+
+while (i< THREAD_COUNT)
+{
+ dwThrdParam = i;
+
+ hThread[i] = CreateThread(
+ NULL,
+ 0,
+ enterandleavecs,
+ (LPVOID)dwThrdParam,
+ 0,
+ &dwThreadId);
+
+ if ( NULL == hThread[i] )
+ {
+ Fail ( "CreateThread() returned NULL. Failing test.\n"
+ "GetLastError returned %d\n", GetLastError());
+ }
+ i++;
+}
+
+/*
+* Set Event to signal all threads to start using the CS
+*/
+
+if (0==SetEvent(g_hEvent))
+{
+ Fail ( "SetEvent returned Zero. Failing test.\n"
+ "GetLastError returned %d\n", GetLastError());
+}
+
+/*
+ * Wait for worker threads to complete
+ *
+ */
+if ( WAIT_OBJECT_0 != WaitForMultipleObjects (THREAD_COUNT,hThread,TRUE, INFINITE))
+{
+ Fail ( "WaitForMultipleObject Failed. Failing test.\n"
+ "GetLastError returned %d\n", GetLastError());
+}
+
+
+//Get the end time of the process
+processStats.operationTime = GetTickCount() - dwStart;
+
+//Write Process Result Contents to File
+if(hProcessFile!= NULL)
+ {
+ fprintf(hProcessFile, "%d,%lu,%d\n", processStats.processId, processStats.operationTime, processStats.relationId );
+ }
+
+if (0!=fclose(hProcessFile))
+{
+ Fail("Unable to write process results to file"
+ "GetLastError returned %d\n", GetLastError());
+}
+
+
+/*Write Threads Results to a file*/
+if(hFile!= NULL)
+{
+ for( i = 0; i < THREAD_COUNT; i++ )
+ {
+ buffer = (struct statistics *)resultBuffer->getResultBuffer(i);
+ fprintf(hFile, "%d,%d,%d,%d,%lu,%d\n", buffer->processId, buffer->operationsFailed, buffer->operationsPassed, buffer->operationsTotal, buffer->operationTime, buffer->relationId );
+ //Trace("Iteration %d over\n", i);
+ }
+}
+
+if (0!=fclose(hFile))
+{
+ Fail("Unable to write thread results to file"
+ "GetLastError returned %d\n", GetLastError());
+}
+
+ /* Logging for the test case over, clean up the handles */
+ //Trace("Contents of the buffer are [%s]\n", resultBuffer->getResultBuffer());
+
+
+//Call Cleanup for Test Case
+cleanup();
+
+//Trace("Value of GLOBAL COUNTER %d \n", GLOBAL_COUNTER);
+return (PASS);
+
+}
+
+
+int GetParameters( int argc, char **argv)
+{
+
+ if( (argc != 5) || ((argc == 1) && !strcmp(argv[1],"/?"))
+ || !strcmp(argv[1],"/h") || !strcmp(argv[1],"/H"))
+ {
+ printf("PAL -Composite Critical Section Test\n");
+ printf("Usage:\n");
+ printf("\t[PROCESS_COUNT] Greater than or Equal to 1 \n");
+ printf("\t[WORKER_THREAD_MULTIPLIER_COUNT] Greater than or Equal to 1 and Less than or Equal to 64 \n");
+ printf("\t[REPEAT_COUNT] Greater than or Equal to 1\n");
+ printf("\t[RELATION_ID [Greater than or Equal to 1]\n");
+ return -1;
+ }
+
+// Trace("Args 1 is [%s], Arg 2 is [%s], Arg 3 is [%s]\n", argv[1], argv[2], argv[3]);
+
+ USE_PROCESS_COUNT = atoi(argv[1]);
+ if( USE_PROCESS_COUNT < 0)
+ {
+ printf("\nPROCESS_COUNT to greater than or equal to 1\n");
+ return -1;
+ }
+
+ THREAD_COUNT = atoi(argv[2]);
+ if( THREAD_COUNT < 1 || THREAD_COUNT > 64)
+ {
+ printf("\nTHREAD_COUNT to be greater than or equal to 1 or less than or equal to 64\n");
+ return -1;
+ }
+
+ REPEAT_COUNT = atoi(argv[3]);
+ if( REPEAT_COUNT < 1)
+ {
+ printf("\nREPEAT_COUNT to greater than or equal to 1\n");
+ return -1;
+ }
+
+ RELATION_ID = atoi(argv[4]);
+ if( RELATION_ID < 1)
+ {
+ printf("\nMain Process:Invalid RELATION_ID number, Pass greater than 1\n");
+ return -1;
+ }
+
+ return 0;
+}
+
diff --git a/src/pal/tests/palsuite/composite/synchronization/criticalsection/mainWrapper.c b/src/pal/tests/palsuite/composite/synchronization/criticalsection/mainWrapper.c
new file mode 100644
index 0000000000..4bc2f3d834
--- /dev/null
+++ b/src/pal/tests/palsuite/composite/synchronization/criticalsection/mainWrapper.c
@@ -0,0 +1,255 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*
+Source Code: mainWrapper.c
+
+mainWrapper.c creates Composite Test Case Processes and waits for all processes to get over
+
+Algorithm
+o Create PROCESS_COUNT processes.
+
+Author: RameshG
+*/
+
+#include <palsuite.h>
+#include "resulttime.h"
+
+/* Test Input Variables */
+unsigned int USE_PROCESS_COUNT = 0; //default
+unsigned int THREAD_COUNT = 0; //default
+unsigned int REPEAT_COUNT = 0; //default
+unsigned int SLEEP_LENGTH = 0; //default
+unsigned int RELATION_ID = 1001;
+
+
+//Strucuture to capture application wide statistics
+struct applicationStatistics{
+ DWORD operationTime;
+ unsigned int relationId;
+ unsigned int processCount;
+ unsigned int threadCount;
+ unsigned int repeatCount;
+ char* buildNumber;
+
+};
+
+
+//Get parameters from the commandline
+int GetParameters( int argc, char **argv)
+{
+
+ if( (argc != 5) || ((argc == 1) && !strcmp(argv[1],"/?"))
+ || !strcmp(argv[1],"/h") || !strcmp(argv[1],"/H"))
+ {
+ printf("Main Wrapper PAL -Composite Critical Section Test\n");
+ printf("Usage:\n");
+ printf("\t[PROCESS_COUNT] Greater than or Equal to 1 \n");
+ printf("\t[THREAD_COUNT] Greater than or Equal to 1 and Less than or Equal to 64 \n");
+ printf("\t[REPEAT_COUNT] Greater than or Equal to 1\n");
+ printf("\t[RELATION_ID [Greater than or Equal to 1]\n");
+
+ return -1;
+ }
+
+ USE_PROCESS_COUNT = atoi(argv[1]);
+ if( USE_PROCESS_COUNT < 0)
+ {
+ printf("\nPROCESS_COUNT to greater than or equal to 1\n");
+ return -1;
+ }
+
+ THREAD_COUNT = atoi(argv[2]);
+ if( THREAD_COUNT < 1 || THREAD_COUNT > 64)
+ {
+ printf("\nTHREAD_COUNT to be greater than or equal to 1 or less than or equal to 64\n");
+ return -1;
+ }
+
+ REPEAT_COUNT = atoi(argv[3]);
+ if( REPEAT_COUNT < 1)
+ {
+ printf("\nREPEAT_COUNT to greater than or equal to 1\n");
+ return -1;
+ }
+
+ RELATION_ID = atoi(argv[4]);
+ if( RELATION_ID < 1)
+ {
+ printf("\nMain Process:Invalid RELATION_ID number, Pass greater than 1\n");
+ return -1;
+ }
+
+
+
+
+ return 0;
+}
+
+//Main entry point for the application
+ int __cdecl main(INT argc, CHAR **argv)
+{
+ unsigned int i = 0;
+ HANDLE hProcess[MAXIMUM_WAIT_OBJECTS]; //Array to hold Process handles
+ DWORD processReturnCode = 0;
+ int testReturnCode = PASS;
+ STARTUPINFO si[MAXIMUM_WAIT_OBJECTS];
+ PROCESS_INFORMATION pi[MAXIMUM_WAIT_OBJECTS];
+ FILE *hFile; //handle to application results file
+ char fileName[MAX_PATH]; //file name of the application results file
+ struct applicationStatistics appStats;
+ DWORD dwStart=0; //to store the tick count
+ char lpCommandLine[MAX_PATH] = "";
+ int returnCode = 0;
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return ( FAIL );
+ }
+
+
+
+
+ if(GetParameters(argc, argv))
+ {
+ Fail("Error in obtaining the parameters\n");
+ }
+
+ //Initialize Application Statistics Strucuture
+ appStats.operationTime=0;
+ appStats.relationId = RELATION_ID;
+ appStats.processCount = USE_PROCESS_COUNT;
+ appStats.threadCount = THREAD_COUNT;
+ appStats.repeatCount = REPEAT_COUNT;
+ appStats.buildNumber = getBuildNumber();
+
+
+_snprintf(fileName, MAX_PATH, "main_criticalsection_%d_.txt", RELATION_ID);
+
+hFile = fopen(fileName, "w+");
+
+if(hFile == NULL)
+ {
+ Fail("Error in opening file to write application results for Critical Section Test, and error code is %d\n", GetLastError());
+ }
+
+//Start Process Time Capture
+dwStart = GetTickCount();
+
+for( i = 0; i < USE_PROCESS_COUNT; i++ )
+ {
+
+ ZeroMemory( lpCommandLine, MAX_PATH );
+ if ( _snprintf( lpCommandLine, MAX_PATH-1, "criticalsection %d %d %d %d", i, THREAD_COUNT, REPEAT_COUNT, RELATION_ID) < 0 )
+ {
+ Trace ("Error: Insufficient commandline string length for for iteration [%d]\n", i);
+ }
+
+ /* Zero the data structure space */
+ ZeroMemory ( &pi[i], sizeof(pi[i]) );
+ ZeroMemory ( &si[i], sizeof(si[i]) );
+
+ /* Set the process flags and standard io handles */
+ si[i].cb = sizeof(si[i]);
+
+ //Printing the Command Line
+ //Trace("Command Line \t %s \n", lpCommandLine);
+
+ //Create Process
+ if(!CreateProcess( NULL, /* lpApplicationName*/
+ lpCommandLine, /* lpCommandLine */
+ NULL, /* lpProcessAttributes */
+ NULL, /* lpThreadAttributes */
+ TRUE, /* bInheritHandles */
+ 0, /* dwCreationFlags, */
+ NULL, /* lpEnvironment */
+ NULL, /* pCurrentDirectory */
+ &si[i], /* lpStartupInfo */
+ &pi[i] /* lpProcessInformation */
+ ))
+ {
+ Fail("Process Not created for [%d] and failed with error code %d\n", i, GetLastError());
+ }
+ else
+ {
+ hProcess[i] = pi[i].hProcess;
+ //Trace("Process created for [%d]\n", i);
+ }
+
+ }
+
+ returnCode = WaitForMultipleObjects( USE_PROCESS_COUNT, hProcess, TRUE, INFINITE);
+ if( WAIT_OBJECT_0 != returnCode )
+ {
+ Trace("Wait for Object(s) @ Main thread for %d processes returned %d, and GetLastError value is %d\n", USE_PROCESS_COUNT, returnCode, GetLastError());
+ testReturnCode = FAIL;
+ }
+
+ for( i = 0; i < USE_PROCESS_COUNT; i++ )
+ {
+ /* check the exit code from the process */
+ if( ! GetExitCodeProcess( pi[i].hProcess, &processReturnCode ) )
+ {
+ Trace( "GetExitCodeProcess call failed for iteration %d with error code %u\n",
+ i, GetLastError() );
+
+ testReturnCode = FAIL;
+ }
+
+ if(processReturnCode == FAIL)
+ {
+ Trace( "Process [%d] failed and returned FAIL\n", i);
+ testReturnCode = FAIL;
+ }
+
+ if(!CloseHandle(pi[i].hThread))
+ {
+ Trace("Error:%d: CloseHandle failed for Process [%d] hThread\n", GetLastError(), i);
+ testReturnCode = FAIL;
+ }
+
+ if(!CloseHandle(pi[i].hProcess) )
+ {
+ Trace("Error:%d: CloseHandle failed for Process [%d] hProcess\n", GetLastError(), i);
+ testReturnCode = FAIL;
+ }
+ }
+
+//Get the end time of the process
+appStats.operationTime = GetTickCount() - dwStart;
+
+if( testReturnCode == PASS)
+ {
+ Trace("Test Passed\n");
+
+ }
+ else
+ {
+ Fail("Test Failed\n");
+
+ }
+
+//Write Process Result Contents to File
+if(hFile!= NULL)
+ {
+ fprintf(hFile, "%lu,%d,%d,%d,%d,%s\n", appStats.operationTime, appStats.relationId,appStats.processCount, appStats.threadCount, appStats.repeatCount, appStats.buildNumber);
+ }
+
+if (0!=fclose(hFile))
+{
+ Trace("Error:%d: fclose failed for file %s\n", GetLastError(), fileName);
+}
+
+ PAL_Terminate();
+
+if( testReturnCode == PASS)
+{
+ return PASS;
+}
+else
+{
+ return FAIL;
+}
+
+}
diff --git a/src/pal/tests/palsuite/composite/synchronization/criticalsection/readme.txt b/src/pal/tests/palsuite/composite/synchronization/criticalsection/readme.txt
new file mode 100644
index 0000000000..af6ef5d230
--- /dev/null
+++ b/src/pal/tests/palsuite/composite/synchronization/criticalsection/readme.txt
@@ -0,0 +1,11 @@
+To compile:
+
+1) create a dat file (say criticalsection.dat) with contents:
+PAL,Composite,palsuite\composite\syncronization\criticalsection,criticalsection=mainWrapper.c,criticalsection.c,<SUPPORTEXE>,<TESTLANGCPP>,<COMPILEONLY>
+
+2) perl rrunmod.pl -r criticalsection.dat
+
+
+To execute:
+mainwrapper [PROCESS_COUNT] [WORKER_THREAD_MULTIPLIER_COUNT] [REPEAT_COUNT]
+
diff --git a/src/pal/tests/palsuite/composite/synchronization/nativecriticalsection/CMakeLists.txt b/src/pal/tests/palsuite/composite/synchronization/nativecriticalsection/CMakeLists.txt
new file mode 100644
index 0000000000..d01b1064f6
--- /dev/null
+++ b/src/pal/tests/palsuite/composite/synchronization/nativecriticalsection/CMakeLists.txt
@@ -0,0 +1,21 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ mtx_critsect.cpp
+ pal_composite_native_cs.c
+ resultbuffer.cpp
+)
+
+add_executable(paltest_synchronization_nativecriticalsection
+ ${SOURCES}
+)
+
+add_dependencies(paltest_synchronization_nativecriticalsection coreclrpal)
+
+target_link_libraries(paltest_synchronization_nativecriticalsection
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/composite/synchronization/nativecriticalsection/mtx_critsect.cpp b/src/pal/tests/palsuite/composite/synchronization/nativecriticalsection/mtx_critsect.cpp
new file mode 100644
index 0000000000..790c89f966
--- /dev/null
+++ b/src/pal/tests/palsuite/composite/synchronization/nativecriticalsection/mtx_critsect.cpp
@@ -0,0 +1,111 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+//#include <stdio.h>
+#include <assert.h>
+#include "mtx_critsect.h"
+
+CsWaiterReturnState MTXWaitOnCS(LPCRITICAL_SECTION lpCriticalSection);
+void MTXDoActualWait(LPCRITICAL_SECTION lpCriticalSection);
+void MTXWakeUpWaiter(LPCRITICAL_SECTION lpCriticalSection);
+
+/*extern "C" {
+ LONG InterlockedCompareExchange(
+ LONG volatile *Destination,
+ LONG Exchange,
+ LONG Comperand);
+}
+*/
+int MTXInitializeCriticalSection(LPCRITICAL_SECTION lpCriticalSection)
+{
+ int retcode = 0;
+
+ lpCriticalSection->DebugInfo = NULL;
+ lpCriticalSection->LockCount = 0;
+ lpCriticalSection->RecursionCount = 0;
+ lpCriticalSection->SpinCount = 0;
+ lpCriticalSection->OwningThread = NULL;
+
+ lpCriticalSection->LockSemaphore = (HANDLE)&lpCriticalSection->NativeData;
+
+ if (0!= pthread_mutex_init(&lpCriticalSection->NativeData.Mutex, NULL))
+ {
+ printf("Error Initializing Critical Section\n");
+ retcode = -1;
+ }
+
+
+ lpCriticalSection->InitCount = CS_INITIALIZED;
+ return retcode;
+}
+
+int MTXDeleteCriticalSection(LPCRITICAL_SECTION lpCriticalSection)
+{
+ int retcode = 0;
+
+ if (lpCriticalSection->InitCount == CS_INITIALIZED)
+ {
+
+ if (0!=pthread_mutex_destroy(&lpCriticalSection->NativeData.Mutex))
+ {
+ printf("Error Deleting Critical Section\n");
+ retcode = -1;
+ }
+ }
+
+ lpCriticalSection->InitCount = CS_NOT_INIZIALIZED;
+ return retcode;
+}
+
+int MTXEnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection)
+{
+
+ DWORD thread_id;
+ int retcode = 0;
+
+ thread_id = (DWORD)THREADSilentGetCurrentThreadId();
+
+ /* check if the current thread already owns the criticalSection */
+ if (lpCriticalSection->OwningThread == (HANDLE)thread_id)
+ {
+ lpCriticalSection->RecursionCount++;
+ //Check if this is a failure condition
+ return 0;
+ }
+
+ if (0!= pthread_mutex_lock(&lpCriticalSection->NativeData.Mutex))
+ {
+ //Error Condition
+ printf("Error Entering Critical Section\n");
+ retcode = -1;
+ }
+ else
+ {
+ lpCriticalSection->OwningThread = (HANDLE)thread_id;
+ lpCriticalSection->RecursionCount = 1;
+ }
+
+ return retcode;
+}
+
+int MTXLeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection)
+{
+ int retcode = 0;
+
+ if (--lpCriticalSection->RecursionCount > 0)
+ //*****check this *****
+ return 0;
+
+ lpCriticalSection->OwningThread = 0;
+
+ if (0!= pthread_mutex_unlock(&lpCriticalSection->NativeData.Mutex))
+ {
+ //Error Condition
+ printf("Error Leaving Critical Section\n");
+ retcode = -1;
+ }
+
+ return retcode;
+}
+
diff --git a/src/pal/tests/palsuite/composite/synchronization/nativecriticalsection/mtx_critsect.h b/src/pal/tests/palsuite/composite/synchronization/nativecriticalsection/mtx_critsect.h
new file mode 100644
index 0000000000..bc44ad8ecd
--- /dev/null
+++ b/src/pal/tests/palsuite/composite/synchronization/nativecriticalsection/mtx_critsect.h
@@ -0,0 +1,51 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#include <pthread.h>
+
+typedef void VOID;
+typedef unsigned long DWORD;
+typedef long LONG;
+typedef unsigned long ULONG;
+typedef void* HANDLE;
+typedef unsigned long ULONG_PTR;
+
+#define FALSE 0
+#define TRUE 1
+
+#define CSBIT_CS_IS_LOCKED 1
+#define CSBIT_NEW_WAITER 2
+
+typedef enum CsInitState { CS_NOT_INIZIALIZED, CS_INITIALIZED, CS_FULLY_INITIALIZED } CsInitState;
+typedef enum _CsWaiterReturnState { CS_WAITER_WOKEN_UP, CS_WAITER_DIDNT_WAIT } CsWaiterReturnState;
+
+typedef struct _CRITICAL_SECTION_DEBUG_INFO {
+ LONG volatile ContentionCount;
+ LONG volatile InternalContentionCount;
+ ULONG volatile AcquireCount;
+ ULONG volatile EnterCount;
+} CRITICAL_SECTION_DEBUG_INFO, *PCRITICAL_SECTION_DEBUG_INFO;
+
+typedef struct _CRITICAL_SECTION_NATIVE_DATA {
+ pthread_mutex_t Mutex;
+} CRITICAL_SECTION_NATIVE_DATA, *PCRITICAL_SECTION_NATIVE_DATA;
+
+typedef struct _CRITICAL_SECTION {
+
+ CsInitState InitCount;
+ PCRITICAL_SECTION_DEBUG_INFO DebugInfo;
+ LONG LockCount;
+ LONG RecursionCount;
+ HANDLE OwningThread;
+ HANDLE LockSemaphore;
+ ULONG_PTR SpinCount;
+ CRITICAL_SECTION_NATIVE_DATA NativeData;
+
+} CRITICAL_SECTION, *PCRITICAL_SECTION, *LPCRITICAL_SECTION;
+
+int MTXInitializeCriticalSection(LPCRITICAL_SECTION lpCriticalSection);
+int MTXDeleteCriticalSection(LPCRITICAL_SECTION lpCriticalSection);
+int MTXEnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection);
+int MTXLeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection);
+
diff --git a/src/pal/tests/palsuite/composite/synchronization/nativecriticalsection/pal_composite_native_cs.c b/src/pal/tests/palsuite/composite/synchronization/nativecriticalsection/pal_composite_native_cs.c
new file mode 100644
index 0000000000..40efacd7c9
--- /dev/null
+++ b/src/pal/tests/palsuite/composite/synchronization/nativecriticalsection/pal_composite_native_cs.c
@@ -0,0 +1,471 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <time.h>
+//#include <pthread.h>
+#include "mtx_critsect.cpp"
+//#include "mtx_critsect.h"
+#include "resultbuffer.h"
+
+
+
+#define LONGLONG long long
+#define ULONGLONG unsigned LONGLONG
+/*Defining Global Variables*/
+
+int THREAD_COUNT=0;
+int REPEAT_COUNT=0;
+int GLOBAL_COUNTER=0;
+int USE_PROCESS_COUNT = 0;
+int RELATION_ID =0;
+int g_counter = 0;
+int MAX_PATH = 256;
+LONGLONG callibrationValue = 0;
+
+pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER;
+pthread_cond_t g_cv = PTHREAD_COND_INITIALIZER;
+pthread_cond_t g_cv2 = PTHREAD_COND_INITIALIZER;
+CRITICAL_SECTION g_cs;
+
+/* Capture statistics for each worker thread */
+struct statistics{
+ unsigned int processId;
+ unsigned int operationsFailed;
+ unsigned int operationsPassed;
+ unsigned int operationsTotal;
+ DWORD operationTime;
+ unsigned int relationId;
+};
+
+
+struct applicationStatistics{
+ DWORD operationTime;
+ unsigned int relationId;
+ unsigned int processCount;
+ unsigned int threadCount;
+ unsigned int repeatCount;
+ char* buildNumber;
+
+};
+
+ResultBuffer *resultBuffer;
+
+
+void* waitforworkerthreads(void*);
+void starttests(int);
+int setuptest(void);
+int cleanuptest(void);
+int GetParameters( int , char **);
+void incrementCounter(void);
+ULONGLONG GetTicks(void);
+ULONGLONG getPerfCallibrationValue(void);
+
+
+
+extern int main(int argc, char **argv)
+ {
+ //Variable Declaration
+ pthread_t pthreads[640];
+ int threadID[640];
+ int i=0;
+ int j=0;
+ int rtn=0;
+ ULONGLONG startTicks = 0;
+
+ /* Variables to capture the file name and the file pointer*/
+ char fileName[MAX_PATH];
+ FILE *hFile;
+ struct statistics* buffer;
+ int statisticsSize = 0;
+
+ /*Variable to Captutre Information at the Application Level*/
+ struct applicationStatistics appStats;
+ char mainFileName[MAX_PATH];
+ FILE *hMainFile;
+
+ //Get perfCallibrationValue
+
+ callibrationValue = getPerfCallibrationValue();
+ printf("Callibration Value for this Platform %llu \n", callibrationValue);
+
+
+ //Get Parameters
+ if(GetParameters(argc, argv))
+ {
+ printf("Error in obtaining the parameters\n");
+ exit(-1);
+ }
+
+ //Assign Values to Application Statistics Members
+ appStats.relationId=RELATION_ID;
+ appStats.operationTime=0;
+ appStats.buildNumber = "999.99";
+ appStats.processCount = USE_PROCESS_COUNT;
+ appStats.threadCount = THREAD_COUNT;
+ appStats.repeatCount = REPEAT_COUNT;
+
+ printf("RELATION ID : %d\n", appStats.relationId);
+ printf("Process Count : %d\n", appStats.processCount);
+ printf("Thread Count : %d\n", appStats.threadCount);
+ printf("Repeat Count : %d\n", appStats.repeatCount);
+
+
+ //Open file for Application Statistics Collection
+ snprintf(mainFileName, MAX_PATH, "main_nativecriticalsection_%d_.txt",appStats.relationId);
+ hMainFile = fopen(mainFileName, "w+");
+
+ if(hMainFile == NULL)
+ {
+ printf("Error in opening main file for write\n");
+ }
+
+
+ for (i=0;i<THREAD_COUNT;i++)
+ {
+ threadID[i] = i;
+ }
+
+ statisticsSize = sizeof(struct statistics);
+
+ snprintf(fileName, MAX_PATH, "%d_thread_nativecriticalsection_%d_.txt", USE_PROCESS_COUNT, RELATION_ID);
+ hFile = fopen(fileName, "w+");
+
+ if(hFile == NULL)
+ {
+ printf("Error in opening file for write for process [%d]\n", USE_PROCESS_COUNT);
+ }
+
+
+ // For each thread we will log operations failed (int), passed (int), total (int)
+ // and number of ticks (DWORD) for the operations
+ resultBuffer = new ResultBuffer( THREAD_COUNT, statisticsSize);
+
+ //Call Test Case Setup Routine
+ if (0!=setuptest())
+ {
+ //Error Condition
+ printf("Error Initializing Test Case\n");
+ exit(-1);
+ }
+
+ //Accquire Lock
+ if (0!=pthread_mutex_lock(&g_mutex))
+ {
+ //Error Condition
+ printf("Error Accquiring Lock\n");
+ exit(-1);
+ }
+
+ //USE NATIVE METHOD TO GET TICK COUNT
+ startTicks = GetTicks();
+
+ /*Loop to create number THREAD_COUNT number of threads*/
+ for (i=0;i< THREAD_COUNT;i++)
+ {
+
+ //printf("Creating Thread Count %d\n", i);
+ //printf("Thread arrary value = %d\n", threadID[i]);
+ rtn=pthread_create(&pthreads[i], NULL, waitforworkerthreads, &threadID[i]);
+ if (0 != rtn)
+ { /* ERROR Condition */
+ printf("Error: pthread Creat, %s \n", strerror(rtn));
+ exit(-1);
+ }
+
+ }
+
+
+ //printf("Main Thread waits to recevie signal when all threads are done\n");
+ pthread_cond_wait(&g_cv2,&g_mutex);
+
+ //printf("Main thread has received signal\n");
+
+ /*Signal Threads to Start Working*/
+ //printf("Raise signal for all threads to start working\n");
+
+
+
+ if (0!=pthread_cond_broadcast(&g_cv))
+ {
+ //Error Condition
+ printf("Error Broadcasting Conditional Event\n");
+ exit(-1);
+ }
+
+ //Release the lock
+ if (0!=pthread_mutex_unlock(&g_mutex))
+ {
+ //Error Condition
+ printf("Error Releasing Lock\n");
+ exit(-1);
+ }
+
+ /*Join Threads */
+ while (j < THREAD_COUNT)
+ {
+ if (0 != pthread_join(pthreads[j],NULL))
+ {
+ //Error Condition
+ printf("Error Joining Threads\n");
+ exit(-1);
+ }
+ j++;
+ }
+
+
+ /*Write Application Results to File*/
+ //CAPTURE NATIVE TICK COUNT HERE
+ appStats.operationTime = (DWORD)(GetTicks() - startTicks)/callibrationValue;
+
+
+ /* Write Results to a file*/
+ if(hFile!= NULL)
+ {
+ for( i = 0; i < THREAD_COUNT; i++ )
+ {
+ buffer = (struct statistics *)resultBuffer->getResultBuffer(i);
+ fprintf(hFile, "%d,%d,%d,%d,%lu,%d\n", buffer->processId, buffer->operationsFailed, buffer->operationsPassed, buffer->operationsTotal, buffer->operationTime, buffer->relationId );
+ //printf("Iteration %d over\n", i);
+ }
+ }
+ fclose(hFile);
+
+
+
+ //Call Test Case Cleanup Routine
+ if (0!=cleanuptest())
+ {
+ //Error Condition
+ printf("Error Cleaning up Test Case");
+ exit(-1);
+ }
+
+
+ if(hMainFile!= NULL)
+ {
+ printf("Writing to Main File \n");
+ fprintf(hMainFile, "%lu,%d,%d,%d,%d,%s\n", appStats.operationTime, appStats.relationId, appStats.processCount, appStats.threadCount, appStats.repeatCount, appStats.buildNumber);
+
+ }
+ fclose(hMainFile);
+ return 0;
+ }
+
+void * waitforworkerthreads(void * threadId)
+{
+
+ int *threadParam = (int*) threadId;
+
+// printf("Thread ID : %d \n", *threadParam);
+
+ //Accquire Lock
+ if (0!=pthread_mutex_lock(&g_mutex))
+ {
+ //Error Condition
+ printf("Error Accquiring Mutex Lock in Wait for Worker Thread\n");
+ exit(-1);
+ }
+
+ //Increment Global Counter
+ GLOBAL_COUNTER++;
+
+
+ //If global counter is equal to thread count then signal main thread
+ if (GLOBAL_COUNTER == THREAD_COUNT)
+ {
+ if (0!=pthread_cond_signal(&g_cv2))
+ {
+ //Error Condition
+ printf("Error in setting conditional variable\n");
+ exit(-1);
+ }
+ }
+
+ //Wait for main thread to signal
+ if (0!=pthread_cond_wait(&g_cv,&g_mutex))
+ {
+ //Error Condition
+ printf("Error waiting on conditional variable in Worker Thread\n");
+ exit(-1);
+ }
+
+ //Release the mutex lock
+ if (0!=pthread_mutex_unlock(&g_mutex))
+ {
+ //Error Condition
+ printf("Error Releasing Mutex Lock in Worker Thread\n");
+ exit(-1);
+ }
+
+ //Start the test
+ starttests(*threadParam);
+
+}
+
+void starttests(int threadID)
+{
+ /*All threads beign executing tests cases*/
+ int i = 0;
+ int Id = threadID;
+ struct statistics stats;
+ ULONGLONG startTime = 0;
+ ULONGLONG endTime = 0;
+
+
+ stats.relationId = RELATION_ID;
+ stats.processId = USE_PROCESS_COUNT;
+ stats.operationsFailed = 0;
+ stats.operationsPassed = 0;
+ stats.operationsTotal = 0;
+ stats.operationTime = 0;
+
+ //Enter and Leave Critical Section in a loop REPEAT_COUNT Times
+
+ startTime = GetTicks();
+
+ for (i=0;i<REPEAT_COUNT;i++)
+ {
+ if (0!=MTXEnterCriticalSection(&g_cs))
+ {
+ stats.operationsFailed++;
+ stats.operationsTotal++;
+ continue;
+ }
+
+ incrementCounter();
+
+ if (0!=MTXLeaveCriticalSection(&g_cs))
+ {
+ stats.operationsFailed++;
+ stats.operationsTotal++;
+ continue;
+ }
+ stats.operationsPassed++;
+ stats.operationsTotal++;
+
+ }
+
+ stats.operationTime = (DWORD)(GetTicks() - startTime)/callibrationValue;
+
+// printf("Operation Time %d \n", stats.operationTime);
+
+ if(resultBuffer->LogResult(Id, (char *)&stats))
+ {
+ printf("Error while writing to shared memory, Thread Id is[??] and Process id is [%d]\n", USE_PROCESS_COUNT);
+ }
+
+}
+
+int setuptest(void)
+{
+
+ //Initalize Critical Section
+ if (0!=MTXInitializeCriticalSection( &g_cs))
+ {
+ return -1;
+ }
+ return 0;
+}
+
+int cleanuptest(void)
+{
+
+ //Delete Critical Section
+ if (0!=MTXDeleteCriticalSection(&g_cs))
+ {
+ return -1;
+ }
+ return 0;
+}
+
+int GetParameters( int argc, char **argv)
+{
+
+ if( (argc != 5) || ((argc == 1) && !strcmp(argv[1],"/?"))
+ || !strcmp(argv[1],"/h") || !strcmp(argv[1],"/H"))
+ {
+ printf("PAL -Composite Native Critical Section Test\n");
+ printf("Usage:\n");
+ printf("\t[PROCESS_ID ( greater than 1] \n");
+ printf("\t[THREAD_COUNT ( greater than 1] \n");
+ printf("\t[REPEAT_COUNT ( greater than 1]\n");
+ printf("\t[RELATION_ID [greater than or Equal to 1]\n");
+ return -1;
+ }
+
+
+ USE_PROCESS_COUNT = atoi(argv[1]);
+ if( USE_PROCESS_COUNT < 0)
+ {
+ printf("\nInvalid THREAD_COUNT number, Pass greater than 1\n");
+ return -1;
+ }
+
+ THREAD_COUNT = atoi(argv[2]);
+ if( THREAD_COUNT < 1)
+ {
+ printf("\nInvalid THREAD_COUNT number, Pass greater than 1\n");
+ return -1;
+ }
+
+ REPEAT_COUNT = atoi(argv[3]);
+ if( REPEAT_COUNT < 1)
+ {
+ printf("\nInvalid REPEAT_COUNT number, Pass greater than 1\n");
+ return -1;
+ }
+
+ RELATION_ID = atoi(argv[4]);
+ if( RELATION_ID < 1)
+ {
+ printf("\nInvalid RELATION_ID number, Pass greater than 1\n");
+ return -1;
+ }
+
+
+ return 0;
+}
+
+void incrementCounter(void)
+{
+ g_counter ++;
+}
+
+
+//Implementation borrowed from pertrace.c
+ULONGLONG GetTicks(void)
+{
+#ifdef i386
+ unsigned long a, d;
+ asm volatile("rdtsc":"=a" (a), "=d" (d));
+ return ((ULONGLONG)((unsigned int)(d)) << 32) | (unsigned int)(a);
+#else
+#if defined(__sparc__) || (defined (_HPUX_) && defined(__ia64__))
+ return (ULONGLONG)gethrtime();
+#else
+ // #error Don''t know how to get ticks on this platform
+ return (ULONGLONG)gethrtime();
+#endif // __sparc__
+#endif // _X86_
+}
+
+
+/**/
+ULONGLONG getPerfCallibrationValue(void)
+{
+ ULONGLONG startTicks;
+ ULONGLONG endTicks;
+
+ startTicks = GetTicks();
+ sleep(1);
+ endTicks = GetTicks();
+
+ return ((endTicks-startTicks)/1000); //Return number of Ticks in One Milliseconds
+
+}
+
diff --git a/src/pal/tests/palsuite/composite/synchronization/nativecriticalsection/readme.txt b/src/pal/tests/palsuite/composite/synchronization/nativecriticalsection/readme.txt
new file mode 100644
index 0000000000..8d83bf794c
--- /dev/null
+++ b/src/pal/tests/palsuite/composite/synchronization/nativecriticalsection/readme.txt
@@ -0,0 +1,19 @@
+To compile:
+
+For FReeBSD Platform use the following to compile:
+gcc -pthread -lm -lgcc -lstdc++ -xc++ -Di386 pal_composite_native_cs.c
+
+For Solaris Platform use the following to compile:
+gcc -lpthread -lm -lgcc -lstdc++ -xc++ -D__sparc__ pal_composite_native_cs.c
+
+For HPUX Platform use the following to compile:
+gcc -lpthread -mlp64 -lm -lgcc -lstdc++ -xc++ -D_HPUX_ -D__ia64__ pal_composite_native_cs.c
+
+To execute:
+./a.out [PROCESS_COUNT] [THREAD_COUNT] [REPEAT_COUNT]
+
+
+ ./a.out 1 32 1000000 4102406
+
+
+
diff --git a/src/pal/tests/palsuite/composite/synchronization/nativecriticalsection/resultbuffer.cpp b/src/pal/tests/palsuite/composite/synchronization/nativecriticalsection/resultbuffer.cpp
new file mode 100644
index 0000000000..c9ed9435f1
--- /dev/null
+++ b/src/pal/tests/palsuite/composite/synchronization/nativecriticalsection/resultbuffer.cpp
@@ -0,0 +1,69 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+//#include "stdafx.h"
+#include "resultbuffer.h"
+//
+//#using <mscorlib.dll>
+//
+//using namespace System;
+
+
+ResultBuffer:: ResultBuffer(int ThreadCount, int ThreadLogSize)
+ {
+ // Declare an internal status variable
+ int Status=0;
+
+ // Update the maximum thread count
+ MaxThreadCount = ThreadCount;
+
+ // Allocate the memory buffer based on the passed in thread and process counts
+ // and the specified size of the thread specific buffer
+ buffer = NULL;
+ buffer = (char*)malloc(ThreadCount*ThreadLogSize);
+ // Check to see if the buffer memory was allocated
+ if (buffer == NULL)
+ Status = -1;
+ // Initialize the buffer to 0 to prevent bogus data
+ memset(buffer,0,ThreadCount*ThreadLogSize);
+
+ // The ThreadOffset is equal to the total number of bytes that will be stored per thread
+ ThreadOffset = ThreadLogSize;
+
+ }
+
+
+ int ResultBuffer::LogResult(int Thread, char* Data)
+ {
+ // Declare an internal status flad
+ int status = 0;
+
+ // Declare an object to store the offset address into the buffer
+ int Offset;
+
+ // Check to make sure the Thread index is not out of range
+ if(Thread > MaxThreadCount)
+ {
+ printf("Thread index is out of range, Value of Thread[%d], Value of MaxThreadCount[%d]\n", Thread, MaxThreadCount);
+ status = -1;
+ return(status);
+ }
+
+ // Caculate the offset into the shared buffer based on the process and thread indices
+ Offset = (Thread)*ThreadOffset;
+
+ // Write the passed in data to the reserved buffer
+ memcpy(buffer+Offset,Data,ThreadOffset);
+
+ return(status);
+ }
+
+
+ char* ResultBuffer::getResultBuffer(int threadId)
+ {
+
+ return (buffer + threadId*ThreadOffset);
+
+ }
+
diff --git a/src/pal/tests/palsuite/composite/synchronization/nativecriticalsection/resultbuffer.h b/src/pal/tests/palsuite/composite/synchronization/nativecriticalsection/resultbuffer.h
new file mode 100644
index 0000000000..8920958100
--- /dev/null
+++ b/src/pal/tests/palsuite/composite/synchronization/nativecriticalsection/resultbuffer.h
@@ -0,0 +1,43 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#include <stdio.h>
+#include <iostream>
+//#include <assert.h>
+#ifndef _RESULT_BUFFER_H_
+#define _RESULT_BUFFER_H_
+
+//#include <palsuite.h>
+
+struct ResultData
+{
+ int value;
+ int size;
+// ResultData* NextResult;
+};
+
+ class ResultBuffer
+{
+ // Declare a pointer to a memory buffer to store the logged results
+ char* buffer;
+ // Declare an object to store the maximum Thread count
+ int MaxThreadCount;
+ // Declare and internal data object to store the calculated offset between adjacent threads data sets
+ int ThreadOffset;
+
+ // Declare a linked list object to store the parameter values
+public:
+
+ // Declare a constructor for the single process case
+ ResultBuffer(int ThreadCount, int ThreadLogSize);
+ // Declare a method to log data for the single process instance
+ int LogResult(int Thread, char* Data);
+
+ char* getResultBuffer(int threadId);
+};
+
+#include "resultbuffer.cpp"
+#endif // _RESULT_BUFFER_H_
+
+
diff --git a/src/pal/tests/palsuite/composite/synchronization/nativecs_interlocked/CMakeLists.txt b/src/pal/tests/palsuite/composite/synchronization/nativecs_interlocked/CMakeLists.txt
new file mode 100644
index 0000000000..c4567f638c
--- /dev/null
+++ b/src/pal/tests/palsuite/composite/synchronization/nativecs_interlocked/CMakeLists.txt
@@ -0,0 +1,22 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ interlocked.cpp
+ mtx_critsect.cpp
+ pal_composite_native_cs.c
+ resultbuffer.cpp
+)
+
+add_executable(paltest_synchronization_nativecs_interlocked
+ ${SOURCES}
+)
+
+add_dependencies(paltest_synchronization_nativecs_interlocked coreclrpal)
+
+target_link_libraries(paltest_synchronization_nativecs_interlocked
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/composite/synchronization/nativecs_interlocked/hpitinterlock.s b/src/pal/tests/palsuite/composite/synchronization/nativecs_interlocked/hpitinterlock.s
new file mode 100644
index 0000000000..062f4ebe6a
--- /dev/null
+++ b/src/pal/tests/palsuite/composite/synchronization/nativecs_interlocked/hpitinterlock.s
@@ -0,0 +1,168 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+Module Name:
+
+ interlock.s
+
+Abstract:
+
+ Implementation of Interlocked functions (32 and 64 bits) for the HPUX/Itanium
+ platform. These functions are processor dependent.
+ See the i386 implementations for more information.
+
+--*/
+ .file "interlock.s"
+ .section .text, "ax", "progbits"
+ .align 16
+ .global InterlockedExchangeAdd#
+ .proc InterlockedExchangeAdd#
+InterlockedExchangeAdd:
+ .body
+ ld4.nt1 r8 = [r32]
+ ;;
+Iea10:
+ mov ar.ccv = r8
+ add r15 = r33, r8
+ mov r14 = r8
+ ;;
+ cmpxchg4.acq r8 = [r32], r15, ar.ccv
+ ;;
+ cmp.ne p6,p7 = r8, r14 // check if the target changes?
+(p6)br.cond.spnt.few Iea10 // if yes, go back to do it again
+(p7)br.ret.sptk.clr b0
+ ;;
+ .endp InterlockedExchangeAdd#
+
+ .align 16
+ .global InterlockedIncrement#
+ .proc InterlockedIncrement#
+InterlockedIncrement:
+ .body
+ fetchadd4.acq r8 = [r32], 1
+ ;;
+ adds r8 = 1, r8
+ br.ret.sptk b0
+ ;;
+ .endp InterlockedIncrement#
+
+ .align 16
+ .global InterlockedIncrement64#
+ .proc InterlockedIncrement64#
+InterlockedIncrement64:
+ .body
+ fetchadd8.acq r8 = [r32], 1
+ ;;
+ adds r8 = 1, r8
+ br.ret.sptk b0
+ ;;
+ .endp InterlockedIncrement64#
+
+ .align 16
+ .global InterlockedDecrement#
+ .proc InterlockedDecrement#
+InterlockedDecrement:
+ .body
+ fetchadd4.acq r8 = [r32], -1
+ ;;
+ adds r8 = -1, r8
+ br.ret.sptk b0
+ ;;
+ .endp InterlockedDecrement#
+
+ .align 16
+ .global InterlockedDecrement64#
+ .proc InterlockedDecrement64#
+InterlockedDecrement64:
+ .body
+ fetchadd8.acq r8 = [r32], -1
+ ;;
+ adds r8 = -1, r8
+ br.ret.sptk b0
+ ;;
+ .endp InterlockedDecrement64#
+
+ .align 16
+ .global InterlockedExchange#
+ .proc InterlockedExchange#
+InterlockedExchange:
+ .body
+ mf
+ zxt4 r33 = r33 // sanitize the upper 32 bits
+ ;;
+ xchg4 r8 = [r32], r33
+ br.ret.sptk b0
+ ;;
+ .endp InterlockedExchange#
+
+ .align 16
+ .global InterlockedExchange64#
+ .proc InterlockedExchange64#
+InterlockedExchange64:
+ .body
+ mf
+ xchg8 r8 = [r32], r33
+ br.ret.sptk b0
+ ;;
+ .endp InterlockedExchange64#
+
+ .align 16
+ .global InterlockedCompareExchange#
+ .proc InterlockedCompareExchange#
+InterlockedCompareExchange:
+ .body
+ mf
+ zxt4 r33 = r33 // sanitize the upper 32 bits
+ zxt4 r34 = r34 // sanitize the upper 32 bits
+ ;;
+ mov ar.ccv = r34
+ ;;
+ cmpxchg4.acq r8 = [r32], r33, ar.ccv
+ br.ret.sptk.clr b0
+ ;;
+ .endp InterlockedCompareExchange#
+
+ .align 16
+ .global InterlockedCompareExchange64#
+ .proc InterlockedCompareExchange64#
+InterlockedCompareExchange64:
+ .body
+ mf
+ mov ar.ccv = r34
+ ;;
+ cmpxchg8.acq r8 = [r32], r33, ar.ccv
+ br.ret.sptk.clr b0
+ ;;
+ .endp InterlockedCompareExchange64#
+
+/*++
+ DBG_DebugBreak is extracted from DbgBreakPoint function
+ in debugstb.s from win64.
+--*/
+ BREAKPOINT_STOP = 0x80016
+ .align 16
+ .global DBG_DebugBreak#
+ .proc DBG_DebugBreak#
+DBG_DebugBreak:
+ .body
+ flushrs
+ ;;
+ break.i BREAKPOINT_STOP
+ br.ret.sptk.clr b0
+ ;;
+ .endp DBG_DebugBreak#
+
+ .align 16
+ .global MemoryBarrier#
+ .proc MemoryBarrier#
+MemoryBarrier:
+ .body
+ mf
+ br.ret.sptk.clr b0
+ ;;
+ .endp MemoryBarrier#
diff --git a/src/pal/tests/palsuite/composite/synchronization/nativecs_interlocked/interlocked.cpp b/src/pal/tests/palsuite/composite/synchronization/nativecs_interlocked/interlocked.cpp
new file mode 100644
index 0000000000..b6c1dd7a8f
--- /dev/null
+++ b/src/pal/tests/palsuite/composite/synchronization/nativecs_interlocked/interlocked.cpp
@@ -0,0 +1,27 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+
+typedef long LONG;
+
+extern "C" {
+LONG InterlockedCompareExchange(
+ LONG volatile *Destination,
+ LONG Exchange,
+ LONG Comperand)
+{
+#ifdef i386
+ LONG result;
+
+ __asm__ __volatile__(
+ "lock; cmpxchgl %2,(%1)"
+ : "=a" (result)
+ : "r" (Destination), "r" (Exchange), "0" (Comperand)
+ : "memory"
+ );
+
+ return result;
+#endif
+}
+}
diff --git a/src/pal/tests/palsuite/composite/synchronization/nativecs_interlocked/makefile b/src/pal/tests/palsuite/composite/synchronization/nativecs_interlocked/makefile
new file mode 100644
index 0000000000..376745aafc
--- /dev/null
+++ b/src/pal/tests/palsuite/composite/synchronization/nativecs_interlocked/makefile
@@ -0,0 +1,70 @@
+#
+# Use gmake to build this project
+#
+
+
+OSNAME=$(shell uname -s)
+OSVER=$(shell uname -r | cut -c1-3)
+BASEOBJDIR=./obj
+TGTDIR=$(BASEOBJDIR)/$(shell uname -m)
+COMP=gcc
+DEBUGOPT=-D_DEBUG -g
+# DEBUGOPT=-DNDEBUG
+
+
+ifeq ($(OSNAME),SunOS)
+COPT=-DSUNOS -O2 -finline-functions $(DEBUGOPT) -xc++
+LOPT=-lpthread -lrt -O2 -finline-functions $(DEBUGOPT)
+INTERLOCK_OBJ=sparcinterloc.o
+else
+ ifeq ($(OSNAME),FreeBSD)
+ ifeq ($(OSVER),5.2)
+ COMP=g++
+ COPT=-DFREEBSD -Di386 -O2 -finline-functions $(DEBUGOPT) -xc++
+ LOPT=-lkse -O2 -finline-functions $(DEBUGOPT)
+ else
+ COPT=-DFREEBSD -Di386 -O2 -finline-functions $(DEBUGOPT)
+ LOPT=-pthread -O2 -finline-functions $(DEBUGOPT)
+ endif
+ INTERLOCK_OBJ=interlocked.o
+ else
+ ifeq ($(OSNAME),HP-UX)
+ COMP=g++
+ INTERLOCK_OBJ=hpitinterlock.o
+ COPT=-DHPUX -O2 -mlp64 -finline -fPIC -DPIC -DBIT64 -D_WIN64 -DLP64COMPATIBLE \
+ -D_POSIX_C_SOURCE=199506L -D_HPUX_ -D_XOPEN_SOURCE_EXTENDED -DBIT64 \
+ -DBIGENDIAN -D_WIN64 $(DEBUGOPT) -xc++
+ LOPT=-O2 -mlp64 -DBIT64 -D_WIN64 -lgcc -lpthread /usr/lib/hpux64/libunwind.so
+ endif
+ endif
+endif
+
+
+TARGET0=$(TGTDIR)/native_cs_interlocked
+
+all: dirs $(TARGET0) $(TARGET1) $(TARGET2) $(TARGET3) $(TARGET4)
+
+dirs:
+ @echo Target dir: $(TGTDIR)
+ @if [ \! -d $(BASEOBJDIR) ]; then mkdir $(BASEOBJDIR); fi
+ @if [ \! -d $(TGTDIR) ]; then mkdir $(TGTDIR); fi
+
+$(TGTDIR)/native_cs_interlocked: $(TGTDIR)/$(INTERLOCK_OBJ) $(TGTDIR)/native_cs_interlocked.o
+ $(COMP) $(LOPT) -o $(TARGET0) $(TGTDIR)/native_cs_interlocked.o $(TGTDIR)/$(INTERLOCK_OBJ)
+
+$(TGTDIR)/native_cs_interlocked.o: pal_composite_native_cs.c
+ $(COMP) $(COPT) -DFULL_CSIMPL -o $(TGTDIR)/native_cs_interlocked.o -c pal_composite_native_cs.c
+
+$(TGTDIR)/interlocked.o: interlocked.cpp
+ $(COMP) $(COPT) -c -o $(TGTDIR)/interlocked.o interlocked.cpp
+
+$(TGTDIR)/sparcinterloc.o: sparcinterloc.s
+ $(COMP) -x assembler-with-cpp -c -Wa,-Av9 -o $(TGTDIR)/sparcinterloc.o sparcinterloc.s
+
+$(TGTDIR)/hpitinterlock.o: hpitinterlock.s
+ $(COMP) $(COPT) -x assembler-with-cpp -c -fno-strict-aliasing -o $(TGTDIR)/hpitinterlock.o hpitinterlock.s
+
+clean:
+ @echo Cleaning
+ @rm -f $(TGTDIR)/*.o $(TARGET0) $(TARGET1) $(TARGET2) $(TARGET3) $(TARGET4)
+ @if [ -d $(TGTDIR) ]; then rmdir $(TGTDIR); fi
diff --git a/src/pal/tests/palsuite/composite/synchronization/nativecs_interlocked/mtx_critsect.cpp b/src/pal/tests/palsuite/composite/synchronization/nativecs_interlocked/mtx_critsect.cpp
new file mode 100644
index 0000000000..69c10e9078
--- /dev/null
+++ b/src/pal/tests/palsuite/composite/synchronization/nativecs_interlocked/mtx_critsect.cpp
@@ -0,0 +1,112 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#include <stdio.h>
+
+#include <assert.h>
+#include "mtx_critsect.h"
+
+CsWaiterReturnState MTXWaitOnCS(LPCRITICAL_SECTION lpCriticalSection);
+void MTXDoActualWait(LPCRITICAL_SECTION lpCriticalSection);
+void MTXWakeUpWaiter(LPCRITICAL_SECTION lpCriticalSection);
+
+/*extern "C" {
+ LONG InterlockedCompareExchange(
+ LONG volatile *Destination,
+ LONG Exchange,
+ LONG Comperand);
+}
+*/
+int MTXInitializeCriticalSection(LPCRITICAL_SECTION lpCriticalSection)
+{
+ int retcode = 0;
+
+ lpCriticalSection->DebugInfo = NULL;
+ lpCriticalSection->LockCount = 0;
+ lpCriticalSection->RecursionCount = 0;
+ lpCriticalSection->SpinCount = 0;
+ lpCriticalSection->OwningThread = NULL;
+
+ lpCriticalSection->LockSemaphore = (HANDLE)&lpCriticalSection->NativeData;
+
+ if (0!= pthread_mutex_init(&lpCriticalSection->NativeData.Mutex, NULL))
+ {
+ printf("Error Initializing Critical Section\n");
+ retcode = -1;
+ }
+
+
+ lpCriticalSection->InitCount = CS_INITIALIZED;
+ return retcode;
+}
+
+int MTXDeleteCriticalSection(LPCRITICAL_SECTION lpCriticalSection)
+{
+ int retcode = 0;
+
+ if (lpCriticalSection->InitCount == CS_INITIALIZED)
+ {
+
+ if (0!=pthread_mutex_destroy(&lpCriticalSection->NativeData.Mutex))
+ {
+ printf("Error Deleting Critical Section\n");
+ retcode = -1;
+ }
+ }
+
+ lpCriticalSection->InitCount = CS_NOT_INIZIALIZED;
+ return retcode;
+}
+
+int MTXEnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection)
+{
+
+ DWORD thread_id;
+ int retcode = 0;
+
+ thread_id = (DWORD)THREADSilentGetCurrentThreadId();
+
+ /* check if the current thread already owns the criticalSection */
+ if (lpCriticalSection->OwningThread == (HANDLE)thread_id)
+ {
+ lpCriticalSection->RecursionCount++;
+ //Check if this is a failure condition
+ return 0;
+ }
+
+ if (0!= pthread_mutex_lock(&lpCriticalSection->NativeData.Mutex))
+ {
+ //Error Condition
+ printf("Error Entering Critical Section\n");
+ retcode = -1;
+ }
+ else
+ {
+ lpCriticalSection->OwningThread = (HANDLE)thread_id;
+ lpCriticalSection->RecursionCount = 1;
+ }
+
+ return retcode;
+}
+
+int MTXLeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection)
+{
+ int retcode = 0;
+
+ if (--lpCriticalSection->RecursionCount > 0)
+ //*****check this *****
+ return 0;
+
+ lpCriticalSection->OwningThread = 0;
+
+ if (0!= pthread_mutex_unlock(&lpCriticalSection->NativeData.Mutex))
+ {
+ //Error Condition
+ printf("Error Leaving Critical Section\n");
+ retcode = -1;
+ }
+
+ return retcode;
+}
+
diff --git a/src/pal/tests/palsuite/composite/synchronization/nativecs_interlocked/mtx_critsect.h b/src/pal/tests/palsuite/composite/synchronization/nativecs_interlocked/mtx_critsect.h
new file mode 100644
index 0000000000..becbf6f0ca
--- /dev/null
+++ b/src/pal/tests/palsuite/composite/synchronization/nativecs_interlocked/mtx_critsect.h
@@ -0,0 +1,67 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#include <pthread.h>
+
+typedef void VOID;
+typedef void* HANDLE;
+typedef unsigned long ULONG_PTR;
+
+#ifdef HPUX
+ typedef unsigned int DWORD;
+ typedef int LONG;
+ typedef unsigned int ULONG;
+#else
+ typedef unsigned long DWORD;
+ typedef long LONG;
+ typedef unsigned long ULONG;
+#endif
+
+
+
+
+#define FALSE 0
+#define TRUE 1
+
+#define CSBIT_CS_IS_LOCKED 1
+#define CSBIT_NEW_WAITER 2
+
+typedef enum CsInitState { CS_NOT_INIZIALIZED, CS_INITIALIZED, CS_FULLY_INITIALIZED } CsInitState;
+typedef enum _CsWaiterReturnState { CS_WAITER_WOKEN_UP, CS_WAITER_DIDNT_WAIT } CsWaiterReturnState;
+
+typedef struct _CRITICAL_SECTION_DEBUG_INFO {
+ LONG volatile ContentionCount;
+ LONG volatile InternalContentionCount;
+ ULONG volatile AcquireCount;
+ ULONG volatile EnterCount;
+} CRITICAL_SECTION_DEBUG_INFO, *PCRITICAL_SECTION_DEBUG_INFO;
+
+typedef struct _CRITICAL_SECTION_NATIVE_DATA {
+ pthread_mutex_t Mutex;
+} CRITICAL_SECTION_NATIVE_DATA, *PCRITICAL_SECTION_NATIVE_DATA;
+
+typedef struct _CRITICAL_SECTION {
+
+ CsInitState InitCount;
+ PCRITICAL_SECTION_DEBUG_INFO DebugInfo;
+ LONG LockCount;
+ LONG RecursionCount;
+ HANDLE OwningThread;
+ HANDLE LockSemaphore;
+ ULONG_PTR SpinCount;
+ CRITICAL_SECTION_NATIVE_DATA NativeData;
+
+} CRITICAL_SECTION, *PCRITICAL_SECTION, *LPCRITICAL_SECTION;
+
+int MTXInitializeCriticalSection(LPCRITICAL_SECTION lpCriticalSection);
+int MTXDeleteCriticalSection(LPCRITICAL_SECTION lpCriticalSection);
+int MTXEnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection);
+int MTXLeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection);
+
+extern "C" {
+ LONG InterlockedCompareExchange(
+ LONG volatile *Destination,
+ LONG Exchange,
+ LONG Comperand);
+}
diff --git a/src/pal/tests/palsuite/composite/synchronization/nativecs_interlocked/notes.txt b/src/pal/tests/palsuite/composite/synchronization/nativecs_interlocked/notes.txt
new file mode 100644
index 0000000000..4882c3bd03
--- /dev/null
+++ b/src/pal/tests/palsuite/composite/synchronization/nativecs_interlocked/notes.txt
@@ -0,0 +1,15 @@
+gcc -O2 -finline-functions -D_DEBUG -g -DFULL_CSIMPL -o ./obj/sun4u/critsecttest.o -c critsecttest.cpp
+gcc -O2 -finline-functions -D_DEBUG -g -c -o ./obj/sun4u/cs.o cs.cpp
+gcc -x assembler-with-cpp -c -Wa,-Av9 -o ./obj/sun4u/sparcinterloc.o sparcinterloc.s
+gcc -lpthread -lrt -O2 -finline-functions -D_DEBUG -g -o ./obj/sun4u/critsecttest ./obj/sun4u/critsecttest.o ./obj/sun4u/cs.o ./obj/sun4u/sparcinterloc.o
+gcc -O2 -finline-functions -D_DEBUG -g -DCXNG_CSIMPL -o ./obj/sun4u/cxngtest.o -c critsecttest.cpp
+gcc -O2 -finline-functions -D_DEBUG -g -c -o ./obj/sun4u/cxng_critsect.o cxng_critsect.cpp
+gcc -lpthread -lrt -O2 -finline-functions -D_DEBUG -g -o ./obj/sun4u/cxngtest ./obj/sun4u/cxngtest.o ./obj/sun4u/cxng_critsect.o ./obj/sun4u/sparcinterloc.o
+gcc -O2 -finline-functions -D_DEBUG -g -DMTX_CSIMPL -o ./obj/sun4u/mtxtest.o -c critsecttest.cpp
+gcc -O2 -finline-functions -D_DEBUG -g -c -o ./obj/sun4u/mtx_critsect.o mtx_critsect.cpp
+gcc -lpthread -lrt -O2 -finline-functions -D_DEBUG -g -o ./obj/sun4u/mtxtest ./obj/sun4u/mtxtest.o ./obj/sun4u/mtx_critsect.o ./obj/sun4u/sparcinterloc.o
+gcc -O2 -finline-functions -D_DEBUG -g -DRECMTX_CSIMPL -o ./obj/sun4u/recmtxtest.o -c critsecttest.cpp
+gcc -O2 -finline-functions -D_DEBUG -g -c -o ./obj/sun4u/recmtx_critsect.o recmtx_critsect.cpp
+gcc -lpthread -lrt -O2 -finline-functions -D_DEBUG -g -o ./obj/sun4u/recmtxtest ./obj/sun4u/recmtxtest.o ./obj/sun4u/recmtx_critsect.o ./obj/sun4u/sparcinterloc.o
+gcc -O2 -finline-functions -D_DEBUG -g -DINLRECMTX_CSIMPL -o ./obj/sun4u/inlrecmtxtest.o -c critsecttest.cpp
+gcc -lpthread -lrt -O2 -finline-functions -D_DEBUG -g -o ./obj/sun4u/inlrecmtxtest ./obj/sun4u/inlrecmtxtest.o ./obj/sun4u/sparcinterloc.o
diff --git a/src/pal/tests/palsuite/composite/synchronization/nativecs_interlocked/pal_composite_native_cs.c b/src/pal/tests/palsuite/composite/synchronization/nativecs_interlocked/pal_composite_native_cs.c
new file mode 100644
index 0000000000..4c19d3b0de
--- /dev/null
+++ b/src/pal/tests/palsuite/composite/synchronization/nativecs_interlocked/pal_composite_native_cs.c
@@ -0,0 +1,475 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <time.h>
+//#include <pthread.h>
+//#include "mtx_critsect.cpp"
+#include "mtx_critsect.h"
+#include "resultbuffer.h"
+
+
+
+#define LONGLONG long long
+#define ULONGLONG unsigned LONGLONG
+/*Defining Global Variables*/
+
+int THREAD_COUNT=0;
+int REPEAT_COUNT=0;
+int GLOBAL_COUNTER=0;
+int USE_PROCESS_COUNT = 0;
+int RELATION_ID =0;
+int g_counter = 0;
+int MAX_PATH = 256;
+LONGLONG callibrationValue = 0;
+
+pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER;
+pthread_cond_t g_cv = PTHREAD_COND_INITIALIZER;
+pthread_cond_t g_cv2 = PTHREAD_COND_INITIALIZER;
+CRITICAL_SECTION g_cs;
+
+/* Capture statistics for each worker thread */
+struct statistics{
+ unsigned int processId;
+ unsigned int operationsFailed;
+ unsigned int operationsPassed;
+ unsigned int operationsTotal;
+ DWORD operationTime;
+ unsigned int relationId;
+};
+
+
+struct applicationStatistics{
+ DWORD operationTime;
+ unsigned int relationId;
+ unsigned int processCount;
+ unsigned int threadCount;
+ unsigned int repeatCount;
+ char* buildNumber;
+
+};
+
+ResultBuffer *resultBuffer;
+
+
+void* waitforworkerthreads(void*);
+void starttests(int);
+int setuptest(void);
+int cleanuptest(void);
+int GetParameters( int , char **);
+void incrementCounter(void);
+ULONGLONG GetTicks(void);
+ULONGLONG getPerfCallibrationValue(void);
+
+
+
+extern int main(int argc, char **argv)
+ {
+ //Variable Declaration
+ pthread_t pthreads[640];
+ int threadID[640];
+ int i=0;
+ int j=0;
+ int rtn=0;
+ ULONGLONG startTicks = 0;
+
+ /* Variables to capture the file name and the file pointer*/
+ char fileName[MAX_PATH];
+ FILE *hFile;
+ struct statistics* buffer;
+ int statisticsSize = 0;
+
+ /*Variable to Captutre Information at the Application Level*/
+ struct applicationStatistics appStats;
+ char mainFileName[MAX_PATH];
+ FILE *hMainFile;
+
+ //Get perfCallibrationValue
+
+ callibrationValue = getPerfCallibrationValue();
+ printf("Callibration Value for this Platform %llu \n", callibrationValue);
+
+
+ //Get Parameters
+ if(GetParameters(argc, argv))
+ {
+ printf("Error in obtaining the parameters\n");
+ exit(-1);
+ }
+
+ //Assign Values to Application Statistics Members
+ appStats.relationId=RELATION_ID;
+ appStats.operationTime=0;
+ appStats.buildNumber = "999.99";
+ appStats.processCount = USE_PROCESS_COUNT;
+ appStats.threadCount = THREAD_COUNT;
+ appStats.repeatCount = REPEAT_COUNT;
+
+ printf("RELATION ID : %d\n", appStats.relationId);
+ printf("Process Count : %d\n", appStats.processCount);
+ printf("Thread Count : %d\n", appStats.threadCount);
+ printf("Repeat Count : %d\n", appStats.repeatCount);
+
+
+ //Open file for Application Statistics Collection
+ snprintf(mainFileName, MAX_PATH, "main_nativecriticalsection_%d_.txt",appStats.relationId);
+ hMainFile = fopen(mainFileName, "w+");
+
+ if(hMainFile == NULL)
+ {
+ printf("Error in opening main file for write\n");
+ }
+
+
+ for (i=0;i<THREAD_COUNT;i++)
+ {
+ threadID[i] = i;
+ }
+
+ statisticsSize = sizeof(struct statistics);
+
+ snprintf(fileName, MAX_PATH, "%d_thread_nativecriticalsection_%d_.txt", USE_PROCESS_COUNT, RELATION_ID);
+ hFile = fopen(fileName, "w+");
+
+ if(hFile == NULL)
+ {
+ printf("Error in opening file for write for process [%d]\n", USE_PROCESS_COUNT);
+ }
+
+
+ // For each thread we will log operations failed (int), passed (int), total (int)
+ // and number of ticks (DWORD) for the operations
+ resultBuffer = new ResultBuffer( THREAD_COUNT, statisticsSize);
+
+ //Call Test Case Setup Routine
+ if (0!=setuptest())
+ {
+ //Error Condition
+ printf("Error Initializing Test Case\n");
+ exit(-1);
+ }
+
+ //Accquire Lock
+ if (0!=pthread_mutex_lock(&g_mutex))
+ {
+ //Error Condition
+ printf("Error Accquiring Lock\n");
+ exit(-1);
+ }
+
+ //USE NATIVE METHOD TO GET TICK COUNT
+ startTicks = GetTicks();
+
+ /*Loop to create number THREAD_COUNT number of threads*/
+ for (i=0;i< THREAD_COUNT;i++)
+ {
+
+ //printf("Creating Thread Count %d\n", i);
+ //printf("Thread arrary value = %d\n", threadID[i]);
+ rtn=pthread_create(&pthreads[i], NULL, waitforworkerthreads, &threadID[i]);
+ if (0 != rtn)
+ { /* ERROR Condition */
+ printf("Error: pthread Creat, %s \n", strerror(rtn));
+ exit(-1);
+ }
+
+ }
+
+
+ //printf("Main Thread waits to recevie signal when all threads are done\n");
+ pthread_cond_wait(&g_cv2,&g_mutex);
+
+ //printf("Main thread has received signal\n");
+
+ /*Signal Threads to Start Working*/
+ //printf("Raise signal for all threads to start working\n");
+
+
+
+ if (0!=pthread_cond_broadcast(&g_cv))
+ {
+ //Error Condition
+ printf("Error Broadcasting Conditional Event\n");
+ exit(-1);
+ }
+
+ //Release the lock
+ if (0!=pthread_mutex_unlock(&g_mutex))
+ {
+ //Error Condition
+ printf("Error Releasing Lock\n");
+ exit(-1);
+ }
+
+ /*Join Threads */
+ while (j < THREAD_COUNT)
+ {
+ if (0 != pthread_join(pthreads[j],NULL))
+ {
+ //Error Condition
+ printf("Error Joining Threads\n");
+ exit(-1);
+ }
+ j++;
+ }
+
+
+ /*Write Application Results to File*/
+ //CAPTURE NATIVE TICK COUNT HERE
+ appStats.operationTime = (DWORD)(GetTicks() - startTicks)/callibrationValue;
+
+
+ /* Write Results to a file*/
+ if(hFile!= NULL)
+ {
+ for( i = 0; i < THREAD_COUNT; i++ )
+ {
+ buffer = (struct statistics *)resultBuffer->getResultBuffer(i);
+ fprintf(hFile, "%d,%d,%d,%d,%lu,%d\n", buffer->processId, buffer->operationsFailed, buffer->operationsPassed, buffer->operationsTotal, buffer->operationTime, buffer->relationId );
+ //printf("Iteration %d over\n", i);
+ }
+ }
+ fclose(hFile);
+
+
+
+ //Call Test Case Cleanup Routine
+ if (0!=cleanuptest())
+ {
+ //Error Condition
+ printf("Error Cleaning up Test Case");
+ exit(-1);
+ }
+
+
+ if(hMainFile!= NULL)
+ {
+ printf("Writing to Main File \n");
+ fprintf(hMainFile, "%lu,%d,%d,%d,%d,%s\n", appStats.operationTime, appStats.relationId, appStats.processCount, appStats.threadCount, appStats.repeatCount, appStats.buildNumber);
+
+ }
+ fclose(hMainFile);
+ return 0;
+ }
+
+void * waitforworkerthreads(void * threadId)
+{
+
+ int *threadParam = (int*) threadId;
+
+// printf("Thread ID : %d \n", *threadParam);
+
+ //Accquire Lock
+ if (0!=pthread_mutex_lock(&g_mutex))
+ {
+ //Error Condition
+ printf("Error Accquiring Mutex Lock in Wait for Worker Thread\n");
+ exit(-1);
+ }
+
+ //Increment Global Counter
+ GLOBAL_COUNTER++;
+
+
+ //If global counter is equal to thread count then signal main thread
+ if (GLOBAL_COUNTER == THREAD_COUNT)
+ {
+ if (0!=pthread_cond_signal(&g_cv2))
+ {
+ //Error Condition
+ printf("Error in setting conditional variable\n");
+ exit(-1);
+ }
+ }
+
+ //Wait for main thread to signal
+ if (0!=pthread_cond_wait(&g_cv,&g_mutex))
+ {
+ //Error Condition
+ printf("Error waiting on conditional variable in Worker Thread\n");
+ exit(-1);
+ }
+
+ //Release the mutex lock
+ if (0!=pthread_mutex_unlock(&g_mutex))
+ {
+ //Error Condition
+ printf("Error Releasing Mutex Lock in Worker Thread\n");
+ exit(-1);
+ }
+
+ //Start the test
+ starttests(*threadParam);
+
+}
+
+void starttests(int threadID)
+{
+ /*All threads beign executing tests cases*/
+ int i = 0;
+ int Id = threadID;
+ struct statistics stats;
+ ULONGLONG startTime = 0;
+ ULONGLONG endTime = 0;
+
+ LONG volatile Destination;
+ LONG Exchange;
+ LONG Comperand;
+ LONG result;
+
+ stats.relationId = RELATION_ID;
+ stats.processId = USE_PROCESS_COUNT;
+ stats.operationsFailed = 0;
+ stats.operationsPassed = 0;
+ stats.operationsTotal = 0;
+ stats.operationTime = 0;
+
+ //Enter and Leave Critical Section in a loop REPEAT_COUNT Times
+
+
+ startTime = GetTicks();
+
+ for (i=0;i<REPEAT_COUNT;i++)
+ {
+ Destination = (LONG volatile) threadID;
+ Exchange = (LONG) i;
+ Comperand = (LONG) threadID;
+ result = InterlockedCompareExchange(&Destination, Exchange, Comperand);
+
+ if( i != result )
+ {
+ stats.operationsFailed++;
+ stats.operationsTotal++;
+ continue;
+ }
+
+ }
+
+
+ stats.operationTime = (DWORD)(GetTicks() - startTime)/callibrationValue;
+
+// printf("Operation Time %d \n", stats.operationTime);
+
+ if(resultBuffer->LogResult(Id, (char *)&stats))
+ {
+ printf("Error while writing to shared memory, Thread Id is[??] and Process id is [%d]\n", USE_PROCESS_COUNT);
+ }
+
+}
+
+int setuptest(void)
+{
+
+ //Initalize Critical Section
+ /*
+ if (0!=MTXInitializeCriticalSection( &g_cs))
+ {
+ return -1;
+ }
+ */
+ return 0;
+}
+
+int cleanuptest(void)
+{
+
+ //Delete Critical Section
+ /*
+ if (0!=MTXDeleteCriticalSection(&g_cs))
+ {
+ return -1;
+ }
+ */
+ return 0;
+}
+
+int GetParameters( int argc, char **argv)
+{
+
+ if( (argc != 5) || ((argc == 1) && !strcmp(argv[1],"/?"))
+ || !strcmp(argv[1],"/h") || !strcmp(argv[1],"/H"))
+ {
+ printf("PAL -Composite Native Critical Section Test\n");
+ printf("Usage:\n");
+ printf("\t[PROCESS_ID ( greater than 1] \n");
+ printf("\t[THREAD_COUNT ( greater than 1] \n");
+ printf("\t[REPEAT_COUNT ( greater than 1]\n");
+ printf("\t[RELATION_ID [greater than or Equal to 1]\n");
+ return -1;
+ }
+
+
+ USE_PROCESS_COUNT = atoi(argv[1]);
+ if( USE_PROCESS_COUNT < 0)
+ {
+ printf("\nInvalid THREAD_COUNT number, Pass greater than 1\n");
+ return -1;
+ }
+
+ THREAD_COUNT = atoi(argv[2]);
+ if( THREAD_COUNT < 1)
+ {
+ printf("\nInvalid THREAD_COUNT number, Pass greater than 1\n");
+ return -1;
+ }
+
+ REPEAT_COUNT = atoi(argv[3]);
+ if( REPEAT_COUNT < 1)
+ {
+ printf("\nInvalid REPEAT_COUNT number, Pass greater than 1\n");
+ return -1;
+ }
+
+ RELATION_ID = atoi(argv[4]);
+ if( RELATION_ID < 1)
+ {
+ printf("\nInvalid RELATION_ID number, Pass greater than 1\n");
+ return -1;
+ }
+
+
+ return 0;
+}
+
+void incrementCounter(void)
+{
+ g_counter ++;
+}
+
+
+//Implementation borrowed from pertrace.c
+ULONGLONG GetTicks(void)
+{
+#ifdef i386
+ unsigned long a, d;
+ asm volatile("rdtsc":"=a" (a), "=d" (d));
+ return ((ULONGLONG)((unsigned int)(d)) << 32) | (unsigned int)(a);
+#else
+#if defined(__sparc__) || (defined (_HPUX_) && defined(__ia64__))
+ return (ULONGLONG)gethrtime();
+#else
+ // #error Don''t know how to get ticks on this platform
+ return (ULONGLONG)gethrtime();
+#endif // __sparc__
+#endif // _X86_
+}
+
+
+/**/
+ULONGLONG getPerfCallibrationValue(void)
+{
+ ULONGLONG startTicks;
+ ULONGLONG endTicks;
+
+ startTicks = GetTicks();
+ sleep(1);
+ endTicks = GetTicks();
+
+ return ((endTicks-startTicks)/1000); //Return number of Ticks in One Milliseconds
+
+}
+
diff --git a/src/pal/tests/palsuite/composite/synchronization/nativecs_interlocked/readme.txt b/src/pal/tests/palsuite/composite/synchronization/nativecs_interlocked/readme.txt
new file mode 100644
index 0000000000..a407e9f8b5
--- /dev/null
+++ b/src/pal/tests/palsuite/composite/synchronization/nativecs_interlocked/readme.txt
@@ -0,0 +1,39 @@
+To compile:
+
+For FReeBSD Platform use the following to compile:
+gcc -pthread -lm -lgcc -lstdc++ -xc++ -Di386 pal_composite_native_cs.c
+
+
+--------------------------------------------------------
+For Solaris Platform use the following to compile:
+ gcc -lpthread -lm -lgcc -lstdc++ -xc++ -D__sparc__ -mimpure-text -shared -o critsect.so mtx_critsect.cpp interlock.s
+gcc -lpthread -lm -lgcc -lstdc++ -xc++ -D__sparc__ pal_composite_native_cs.c
+
+
+setenv LD_LIBRARY_PATH /usr/lib/lwp:/usr/local/lib:/usr/lib:/opt/sfw/lib:.
+ gcc -lpthread -lm -lgcc -lstdc++ -lcritsect -xc++ -D__sparc__ pal_composite_native_cs.c
+ gcc -lpthread -lm -lgcc -lstdc++ -xc++ -D__sparc__ -mimpure-text -shared -o critsect.so mtx_critsect.cpp
+
+(pts/2):{4}% ldd critsect.so
+ libpthread.so.1 => /usr/lib/libpthread.so.1
+ libm.so.1 => /usr/lib/libm.so.1
+ libstdc++.so.2.10.0 => /usr/local/lib/libstdc++.so.2.10.0
+ libc.so.1 => /usr/lib/libc.so.1
+ libdl.so.1 => /usr/lib/libdl.so.1
+ libthread.so.1 => /usr/lib/libthread.so.1
+ /usr/platform/SUNW,Serverblade1/lib/libc_psr.so.1
+
+
+--------------------------------------------------------
+For HPUX Platform use the following to compile:
+gcc -lpthread -mlp64 -lm -lgcc -lstdc++ -xc++ -D_HPUX_ -D__ia64__ pal_composite_native_cs.c
+
+--------------------------------------------------------
+To execute:
+./a.out [PROCESS_COUNT] [THREAD_COUNT] [REPEAT_COUNT]
+
+
+ ./a.out 1 32 1000000 4102406
+
+
+
diff --git a/src/pal/tests/palsuite/composite/synchronization/nativecs_interlocked/resultbuffer.cpp b/src/pal/tests/palsuite/composite/synchronization/nativecs_interlocked/resultbuffer.cpp
new file mode 100644
index 0000000000..c9ed9435f1
--- /dev/null
+++ b/src/pal/tests/palsuite/composite/synchronization/nativecs_interlocked/resultbuffer.cpp
@@ -0,0 +1,69 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+//#include "stdafx.h"
+#include "resultbuffer.h"
+//
+//#using <mscorlib.dll>
+//
+//using namespace System;
+
+
+ResultBuffer:: ResultBuffer(int ThreadCount, int ThreadLogSize)
+ {
+ // Declare an internal status variable
+ int Status=0;
+
+ // Update the maximum thread count
+ MaxThreadCount = ThreadCount;
+
+ // Allocate the memory buffer based on the passed in thread and process counts
+ // and the specified size of the thread specific buffer
+ buffer = NULL;
+ buffer = (char*)malloc(ThreadCount*ThreadLogSize);
+ // Check to see if the buffer memory was allocated
+ if (buffer == NULL)
+ Status = -1;
+ // Initialize the buffer to 0 to prevent bogus data
+ memset(buffer,0,ThreadCount*ThreadLogSize);
+
+ // The ThreadOffset is equal to the total number of bytes that will be stored per thread
+ ThreadOffset = ThreadLogSize;
+
+ }
+
+
+ int ResultBuffer::LogResult(int Thread, char* Data)
+ {
+ // Declare an internal status flad
+ int status = 0;
+
+ // Declare an object to store the offset address into the buffer
+ int Offset;
+
+ // Check to make sure the Thread index is not out of range
+ if(Thread > MaxThreadCount)
+ {
+ printf("Thread index is out of range, Value of Thread[%d], Value of MaxThreadCount[%d]\n", Thread, MaxThreadCount);
+ status = -1;
+ return(status);
+ }
+
+ // Caculate the offset into the shared buffer based on the process and thread indices
+ Offset = (Thread)*ThreadOffset;
+
+ // Write the passed in data to the reserved buffer
+ memcpy(buffer+Offset,Data,ThreadOffset);
+
+ return(status);
+ }
+
+
+ char* ResultBuffer::getResultBuffer(int threadId)
+ {
+
+ return (buffer + threadId*ThreadOffset);
+
+ }
+
diff --git a/src/pal/tests/palsuite/composite/synchronization/nativecs_interlocked/resultbuffer.h b/src/pal/tests/palsuite/composite/synchronization/nativecs_interlocked/resultbuffer.h
new file mode 100644
index 0000000000..8920958100
--- /dev/null
+++ b/src/pal/tests/palsuite/composite/synchronization/nativecs_interlocked/resultbuffer.h
@@ -0,0 +1,43 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#include <stdio.h>
+#include <iostream>
+//#include <assert.h>
+#ifndef _RESULT_BUFFER_H_
+#define _RESULT_BUFFER_H_
+
+//#include <palsuite.h>
+
+struct ResultData
+{
+ int value;
+ int size;
+// ResultData* NextResult;
+};
+
+ class ResultBuffer
+{
+ // Declare a pointer to a memory buffer to store the logged results
+ char* buffer;
+ // Declare an object to store the maximum Thread count
+ int MaxThreadCount;
+ // Declare and internal data object to store the calculated offset between adjacent threads data sets
+ int ThreadOffset;
+
+ // Declare a linked list object to store the parameter values
+public:
+
+ // Declare a constructor for the single process case
+ ResultBuffer(int ThreadCount, int ThreadLogSize);
+ // Declare a method to log data for the single process instance
+ int LogResult(int Thread, char* Data);
+
+ char* getResultBuffer(int threadId);
+};
+
+#include "resultbuffer.cpp"
+#endif // _RESULT_BUFFER_H_
+
+
diff --git a/src/pal/tests/palsuite/composite/synchronization/nativecs_interlocked/sparcinterloc.s b/src/pal/tests/palsuite/composite/synchronization/nativecs_interlocked/sparcinterloc.s
new file mode 100644
index 0000000000..b9708bc770
--- /dev/null
+++ b/src/pal/tests/palsuite/composite/synchronization/nativecs_interlocked/sparcinterloc.s
@@ -0,0 +1,73 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*++
+
+
+
+ Module Name:
+
+ interlock.s
+
+Abstract:
+
+ Implementation of Interlocked functions for the SPARC
+ platform. These functions are processor dependent.
+ See the i386 implementations for more information.
+
+ --*/
+
+ // A handy macro for declaring a public function
+ // The first argument is the function name.
+ #define ASMFUNC(n,typename); \
+ .align 4 ; \
+ .global n ; \
+ .type n,typename ; \
+n: ;
+
+ .text
+ ASMFUNC(InterlockedIncrement,#function)
+ ld [%o0], %o1
+loopI:
+ mov %o1, %o2
+ add %o1, 1, %o1
+ cas [%o0], %o2, %o1
+ cmp %o2, %o1
+ bne loopI
+ nop
+ retl
+ add %o1, 1, %o0
+
+
+ ASMFUNC(InterlockedDecrement,#function)
+ ld [%o0], %o1
+loopD:
+ mov %o1, %o2
+ sub %o1, 1, %o1
+ cas [%o0], %o2, %o1
+ cmp %o2, %o1
+ bne loopD
+ nop
+ retl
+ sub %o1, 1, %o0
+
+
+ ASMFUNC(InterlockedExchange,#function)
+ swap [%o0], %o1
+ retl
+ mov %o1, %o0
+
+ ASMFUNC(InterlockedCompareExchange,#function)
+ cas [%o0], %o2, %o1
+ retl
+ mov %o1, %o0
+
+ ASMFUNC(MemoryBarrier,#function)
+ // ROTORTODO: SPARC
+ retl
+ nop
+
+ ASMFUNC(YieldProcessor,#function)
+ retl
+ nop
diff --git a/src/pal/tests/palsuite/composite/threading/CMakeLists.txt b/src/pal/tests/palsuite/composite/threading/CMakeLists.txt
new file mode 100644
index 0000000000..793f86c059
--- /dev/null
+++ b/src/pal/tests/palsuite/composite/threading/CMakeLists.txt
@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(threadsuspension)
+add_subdirectory(threadsuspension_switchthread)
+
diff --git a/src/pal/tests/palsuite/composite/threading/threadsuspension/CMakeLists.txt b/src/pal/tests/palsuite/composite/threading/threadsuspension/CMakeLists.txt
new file mode 100644
index 0000000000..134cce0809
--- /dev/null
+++ b/src/pal/tests/palsuite/composite/threading/threadsuspension/CMakeLists.txt
@@ -0,0 +1,20 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ mainWrapper.c
+ threadsuspension.c
+)
+
+add_executable(paltest_threading_threadsuspension
+ ${SOURCES}
+)
+
+add_dependencies(paltest_threading_threadsuspension coreclrpal)
+
+target_link_libraries(paltest_threading_threadsuspension
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/composite/threading/threadsuspension/mainWrapper.c b/src/pal/tests/palsuite/composite/threading/threadsuspension/mainWrapper.c
new file mode 100644
index 0000000000..05a71191cf
--- /dev/null
+++ b/src/pal/tests/palsuite/composite/threading/threadsuspension/mainWrapper.c
@@ -0,0 +1,274 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*
+Source Code: mainWrapper.c
+
+mainWrapper.c creates Composite Test Case Processes and waits for all processes to get over
+
+Algorithm
+o Create PROCESS_COUNT processes.
+
+Author: RameshG
+*/
+
+#include <palsuite.h>
+#include "resulttime.h"
+
+/* Test Input Variables */
+unsigned int USE_PROCESS_COUNT = 0; //default
+unsigned int WORKER_THREAD_MULTIPLIER_COUNT = 0; //default
+unsigned int REPEAT_COUNT = 0; //default
+unsigned int SLEEP_LENGTH = 0; //default
+unsigned int RELATION_ID = 0;//default
+unsigned int THREAD_COUNT = 1; //There is only one suspender and resume thread for this test case
+
+char *testCaseName;
+
+
+struct applicationStatistics{
+ DWORD operationTime;
+ unsigned int relationId;
+ unsigned int processCount;
+ unsigned int threadCount;
+ unsigned int repeatCount;
+ char* buildNumber;
+
+};
+
+
+int GetParameters( int argc, char **argv)
+{
+
+ if( (argc != 5) || ((argc == 1) && !strcmp(argv[1],"/?"))
+ || !strcmp(argv[1],"/h") || !strcmp(argv[1],"/H"))
+ {
+ printf("PAL -Composite Thread Suspension Test\n");
+ printf("Usage:\n");
+ printf("\t[PROCESS_COUNT] Greater than or Equal to 1 \n");
+ printf("\t[WORKER_THREAD_MULTIPLIER_COUNT] Greater than or Equal to 1 and Less than or Equal to %d \n", MAXIMUM_WAIT_OBJECTS);
+ printf("\t[REPEAT_COUNT] Greater than or Equal to 1\n");
+ printf("\t[RELATION_ID [greater than or Equal to 1]\n");
+ return -1;
+ }
+
+ // Trace("Args 1 is [%s], Arg 2 is [%s], Arg 3 is [%s]\n", argv[1], argv[2], argv[3]);
+
+ USE_PROCESS_COUNT = atoi(argv[1]);
+ if( USE_PROCESS_COUNT < 0)
+ {
+ printf("\nPROCESS_COUNT to greater than or equal to 1\n");
+ return -1;
+ }
+
+ WORKER_THREAD_MULTIPLIER_COUNT = atoi(argv[2]);
+ if( WORKER_THREAD_MULTIPLIER_COUNT < 1 || WORKER_THREAD_MULTIPLIER_COUNT > 64)
+ {
+ printf("\nWORKER_THREAD_MULTIPLIER_COUNT to be greater than or equal to 1 or less than or equal to 64\n");
+ return -1;
+ }
+
+ REPEAT_COUNT = atoi(argv[3]);
+ if( REPEAT_COUNT < 1)
+ {
+ printf("\nREPEAT_COUNT to greater than or equal to 1\n");
+ return -1;
+ }
+
+ RELATION_ID = atoi(argv[4]);
+ if( RELATION_ID < 1)
+ {
+ printf("\nRELATION_ID to be greater than or equal to 1\n");
+ return -1;
+ }
+
+
+
+ return 0;
+}
+
+ int __cdecl main(INT argc, CHAR **argv)
+{
+ unsigned int i = 0;
+ HANDLE hProcess[MAXIMUM_WAIT_OBJECTS];
+ DWORD processReturnCode = 0;
+ int testReturnCode = PASS;
+ STARTUPINFO si[MAXIMUM_WAIT_OBJECTS];
+ PROCESS_INFORMATION pi[MAXIMUM_WAIT_OBJECTS];
+
+ FILE *hFile;
+ char fileName[MAX_PATH];
+ struct applicationStatistics appStats;
+
+ DWORD dwStart=0;
+
+ char lpCommandLine[MAX_PATH] = "";
+
+ char build[] ="0000.00";
+ int returnCode = 0;
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return ( FAIL );
+ }
+
+ //Initialize Application Statistics Strucuture
+ appStats.relationId=RELATION_ID;
+ appStats.operationTime=0;
+ appStats.buildNumber = getBuildNumber();
+ //appStats.buildNumber = build;
+ appStats.processCount = 0;
+ appStats.threadCount = 0;
+ appStats.repeatCount = 0;
+
+
+
+
+
+//Start Process Time Capture
+dwStart = GetTickCount();
+
+ if(GetParameters(argc, argv))
+ {
+ Fail("Error in obtaining the parameters\n");
+ }
+
+//Assign Correct Values to the Application Stats Structure
+ appStats.relationId=RELATION_ID;
+ appStats.processCount = USE_PROCESS_COUNT;
+ appStats.threadCount = THREAD_COUNT ;
+ appStats.repeatCount = REPEAT_COUNT;
+
+ Trace("Relation ID: %d \n", RELATION_ID);
+ Trace("USE_PROCESS_COUNT: %d \n", USE_PROCESS_COUNT);
+ Trace("WORKER_THREAD_MULTIPLIER_COUNT: %d \n", WORKER_THREAD_MULTIPLIER_COUNT);
+ Trace("REPEAT_COUNT: %d \n", REPEAT_COUNT);
+
+
+_snprintf(fileName, MAX_PATH, "main_threadsuspension_%d_.txt",appStats.relationId);
+
+ hFile = fopen(fileName, "w+");
+if(hFile == NULL)
+ {
+ Fail("Error in opening file to write application results for Thread Suspension Test with error code %d \n", GetLastError() );
+ }
+
+
+
+ for( i = 0; i < USE_PROCESS_COUNT; i++ )
+ {
+
+ ZeroMemory( lpCommandLine, MAX_PATH );
+ if ( _snprintf( lpCommandLine, MAX_PATH-1, "threadsuspension %d %d %d %d", i, WORKER_THREAD_MULTIPLIER_COUNT, REPEAT_COUNT, RELATION_ID) < 0 )
+ {
+ Trace ("Error: Insufficient commandline string length for for iteration [%d]\n", i);
+ }
+
+ /* Zero the data structure space */
+ ZeroMemory ( &pi[i], sizeof(pi[i]) );
+ ZeroMemory ( &si[i], sizeof(si[i]) );
+
+ /* Set the process flags and standard io handles */
+ si[i].cb = sizeof(si[i]);
+
+ //Printing the Command Line
+ //Trace("Command Line \t %s \n", lpCommandLine);
+
+ //Create Process
+ if(!CreateProcess( NULL, /* lpApplicationName*/
+ lpCommandLine, /* lpCommandLine */
+ NULL, /* lpProcessAttributes */
+ NULL, /* lpThreadAttributes */
+ TRUE, /* bInheritHandles */
+ 0, /* dwCreationFlags, */
+ NULL, /* lpEnvironment */
+ NULL, /* pCurrentDirectory */
+ &si[i], /* lpStartupInfo */
+ &pi[i] /* lpProcessInformation */
+ ))
+ {
+ Fail("Process Not created for [%d] and GetLastError value is %d\n", i, GetLastError());
+
+ }
+ else
+ {
+ hProcess[i] = pi[i].hProcess;
+ //Trace("Process created for [%d]\n", i);
+ }
+
+ }
+
+ returnCode = WaitForMultipleObjects( USE_PROCESS_COUNT, hProcess, TRUE, INFINITE);
+ if( WAIT_OBJECT_0 != returnCode )
+ {
+ Trace("Wait for Object(s) @ Main thread for %d processes returned %d, and GetLastError value is %d\n", USE_PROCESS_COUNT, returnCode, GetLastError());
+ testReturnCode = FAIL;
+ }
+
+ for( i = 0; i < USE_PROCESS_COUNT; i++ )
+ {
+ /* check the exit code from the process */
+ if( ! GetExitCodeProcess( pi[i].hProcess, &processReturnCode ) )
+ {
+ Trace( "GetExitCodeProcess call failed for iteration %d with error code %u\n",
+ i, GetLastError() );
+
+ testReturnCode = FAIL;
+ }
+
+ if(processReturnCode == FAIL)
+ {
+ Trace( "Process [%d] failed and returned FAIL\n", i);
+ testReturnCode = FAIL;
+ }
+
+ if(!CloseHandle(pi[i].hThread))
+ {
+ Trace("Error:%d: CloseHandle failed for Process [%d] hThread\n", GetLastError(), i);
+ testReturnCode = FAIL;
+ }
+
+ if(!CloseHandle(pi[i].hProcess) )
+ {
+ Trace("Error:%d: CloseHandle failed for Process [%d] hProcess\n", GetLastError(), i);
+ testReturnCode = FAIL;
+ }
+ }
+
+//Get the end time of the process
+appStats.operationTime = GetTickCount() - dwStart;
+
+if( testReturnCode == PASS)
+ {
+ Trace("Test Passed\n");
+ }
+ else
+ {
+ Trace("Test Failed\n");
+ }
+
+//Write Process Result Contents to File
+if(hFile!= NULL)
+ {
+ fprintf(hFile, "%lu,%d,%d,%d,%d,%s\n", appStats.operationTime, appStats.relationId, appStats.processCount, appStats.threadCount, appStats.repeatCount, appStats.buildNumber);
+ }
+
+if (0!=fclose(hFile))
+{
+ Trace("Error:%d: fclose failed for file %s\n", GetLastError(), fileName);
+}
+ PAL_Terminate();
+
+
+if( testReturnCode == PASS)
+ {
+ return PASS;
+ }
+ else
+ {
+ return FAIL;
+
+ }
+
+}
diff --git a/src/pal/tests/palsuite/composite/threading/threadsuspension/readme.txt b/src/pal/tests/palsuite/composite/threading/threadsuspension/readme.txt
new file mode 100644
index 0000000000..d722f1d127
--- /dev/null
+++ b/src/pal/tests/palsuite/composite/threading/threadsuspension/readme.txt
@@ -0,0 +1,11 @@
+To compile:
+
+1) create a dat file (say threadsuspension.dat) with contents:
+PAL,Composite,palsuite\composite\threading\threadsuspension,wfmo=mainWrapper.c threadsuspension.c,<SUPPORTEXE>,<TESTLANGCPP>,<COMPILEONLY>
+
+2) perl rrunmod.pl -r threadsuspension.dat
+
+
+To execute:
+mainWrapper [PROCESS_COUNT] [THREAD_COUNT] [REPEAT_COUNT]
+
diff --git a/src/pal/tests/palsuite/composite/threading/threadsuspension/samplefile.dat b/src/pal/tests/palsuite/composite/threading/threadsuspension/samplefile.dat
new file mode 100644
index 0000000000..d6505f2549
--- /dev/null
+++ b/src/pal/tests/palsuite/composite/threading/threadsuspension/samplefile.dat
@@ -0,0 +1,5124 @@
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense blackasdf dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
diff --git a/src/pal/tests/palsuite/composite/threading/threadsuspension/threadsuspension.c b/src/pal/tests/palsuite/composite/threading/threadsuspension/threadsuspension.c
new file mode 100644
index 0000000000..86ee4e2fc0
--- /dev/null
+++ b/src/pal/tests/palsuite/composite/threading/threadsuspension/threadsuspension.c
@@ -0,0 +1,907 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: \composite\threading\threadsuspension\threadsuspension.c
+**
+** Purpose: To verify Thread Suspension Reegneering effort for this milestone
+
+ PsedoCode:
+
+ Preparation:
+ Create PROCESS_COUNT processes.
+ Test:
+ Create Worker Thread
+ Start Reading and writing to a File
+
+ Create Worker Thread
+ In an infinite loop do the following
+ Enter Critical Section
+ Increment Counter
+ Leave Critical Section
+
+ Create Worker Thread
+ Allocate Memory and Free Memory
+
+ Create Worker Thread
+ In a tight loop add numbers
+
+ In a loop repeated REPEAT_COUNT times
+
+ Create Thread
+
+ Suspend all worker threads
+ Resume all worker threads
+
+ At the end of the loop call PAL_Shutdown
+
+ Parameters:
+ PROCESS_COUNT: Number of processes
+ WORKER_THREAD_MULTIPLIER_COUNT: Number of instances of worker threads in each process
+ REPEAT_COUNT: The number of times to execute the loop.
+
+ Statistics Captured:
+ Total elapsed time
+ MTBF
+
+
+ Scenario:
+**
+ One thread suspends all remaining threads which are in the middle of doing some work and resume all threads
+ Thread 1: Reading and Writing File
+ Thread 2: Enter and Leave Critical Section
+ Thread 3: Allocating chunks of memory
+ Thread 4: Perform Unsafe Operation (printf, malloc)
+ Thread 5: Suspends Thread 1 to Thread 4 and resumes them
+
+**
+**
+**
+** Dependencies:
+**
+**
+
+**
+**=========================================================*/
+
+#include <palsuite.h>
+#include "resultbuffer.h"
+
+#define BUFSIZE 4096
+#define NUMBER_OF_WORKER_THREAD_TYPES 4
+#define THREAD_MAX 64
+
+#define TEST_FAIL 1
+#define TEST_PASS 0
+
+
+DWORD GLOBAL_COUNTER ;
+DWORD UNIQUE_FILE_NUMBER=0;
+HANDLE g_hEvent;
+
+bool failFlag = false; //To Track failure at the Operation Level
+
+// 2 dimensional array to hold thread handles for each worker thread
+HANDLE hThread[NUMBER_OF_WORKER_THREAD_TYPES][THREAD_MAX];
+
+/*unsigned int g_readfileoperation;
+unsigned int g_enterleavecsoperation;
+unsigned int g_allocatefreeoperation;
+unsigned int g_doworintightloop;
+*/
+
+int TYPES_OF_WORKER_THREAD = NUMBER_OF_WORKER_THREAD_TYPES;
+
+int testStatus=TEST_PASS; //Indicates test failure
+
+
+struct statistics{
+ unsigned int processId;
+ unsigned int operationsFailed;
+ unsigned int operationsPassed;
+ unsigned int operationsTotal;
+ DWORD operationTime;
+ unsigned int relationId;
+};
+
+struct processStatistics{
+ unsigned int processId;
+ DWORD operationTime;
+ unsigned int relationId;
+};
+
+/* Results Buffer */
+ResultBuffer *resultBuffer;
+
+
+/* Test Input Variables */
+unsigned int USE_PROCESS_COUNT = 0; //Identifies the Process number. There could potentially
+unsigned int WORKER_THREAD_MULTIPLIER_COUNT = 0; //In this test case this represents the number of worker thread instances
+unsigned int REPEAT_COUNT = 0; //Number of Suspend Resume operation of worker threads
+unsigned int RELATION_ID = 0;
+
+
+
+CRITICAL_SECTION CriticalSectionM; /* Critical Section Object (used as mutex) */
+CRITICAL_SECTION g_csUniqueFileName;
+
+void PALAPI setup(void);
+void PALAPI cleanup(void);
+void PALAPI incrementCounter(void);
+DWORD PALAPI readfile( LPVOID);
+DWORD PALAPI enterandleave_cs( LPVOID);
+DWORD PALAPI allocateandfree_memory( LPVOID);
+DWORD PALAPI doworkintightloop_cs( LPVOID);
+DWORD PALAPI suspendandresumethreads( LPVOID);
+int GetParameters(int, char * *);
+
+
+//Main Entry for the Thread Suspension Test Case
+int __cdecl main (int argc, char **argv)
+{
+
+/*
+* Parameter to the threads that will be created
+*/
+
+
+DWORD dwThrdParam = 0;
+DWORD dwStart;
+
+/* Variables to capture the file name and the file pointer*/
+char fileName[MAX_PATH];
+char processFileName[MAX_PATH];
+
+FILE *hFile, *hProcessFile;
+struct statistics* buffer;
+struct processStatistics *processBuffer;
+
+struct processStatistics processStats;
+
+struct statistics* tmpBuf = NULL;
+int statisticsSize = 0;
+
+DWORD dwThreadId=0;
+HANDLE hMainThread;
+unsigned int i = 0;
+int j = 0;
+
+
+/*
+* PAL Initialize
+*/
+
+if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+
+//Get Parameters
+if(GetParameters(argc, argv))
+ {
+ Fail("Error in obtaining the parameters\n");
+ }
+
+
+//Setup for Process Result Collection
+statisticsSize = sizeof(struct statistics);
+_snprintf(processFileName, MAX_PATH, "%d_process_threadsuspension_%d_.txt", USE_PROCESS_COUNT, RELATION_ID);
+hProcessFile = fopen(processFileName, "w+");
+
+if(hProcessFile == NULL)
+ {
+ Fail("Error in opening file to write process results for process [%d]\n", USE_PROCESS_COUNT);
+ }
+
+//Initialize Process Stats Variables
+processStats.operationTime = 0;
+processStats.processId = USE_PROCESS_COUNT;
+processStats.relationId = RELATION_ID;
+
+//Start Process Time Capture
+dwStart = GetTickCount();
+
+//Setup for Thread Result Collection
+statisticsSize = sizeof(struct statistics);
+_snprintf(fileName, MAX_PATH, "%d_thread_threadsuspension_%d_.txt", USE_PROCESS_COUNT,RELATION_ID);
+hFile = fopen(fileName, "w+");
+
+if(hFile == NULL)
+ {
+ Fail("Error in opening file to write thread results for process [%d]\n", USE_PROCESS_COUNT);
+ }
+
+// For each thread we will log relationid (int), processid (int), operations failed (int), passed (int), total (int)
+// and number of ticks (DWORD) for the operations
+resultBuffer = new ResultBuffer( 1, statisticsSize);
+
+/*
+* Call the Setup Routine
+*/
+setup();
+
+Trace("WORKER_THREAD_MULTIPLIER_COUNT: %d \n", WORKER_THREAD_MULTIPLIER_COUNT);
+
+//Create WORKER_THREAD_MULTIPLIER_COUNT Instances of each type of worker thread
+for (i=0;i<WORKER_THREAD_MULTIPLIER_COUNT;i++)
+{
+
+ /*
+ * Create readfile thread
+ */
+ hThread[0][i] = CreateThread(
+ NULL,
+ 0,
+ readfile,
+ NULL,
+ 0,
+ &dwThreadId);
+
+ if ( NULL == hThread[0][i] )
+ {
+ Fail ( "CreateThread() returned NULL. Failing test.\n"
+ "GetLastError returned %d\n", GetLastError());
+ }
+
+
+
+ /*
+ * Create Enter and Leave Critical Section Thread
+ */
+ hThread[1][i] = CreateThread(
+ NULL,
+ 0,
+ enterandleave_cs,
+ NULL,
+ 0,
+ &dwThreadId);
+
+ if ( NULL == hThread[1][i] )
+ {
+ Fail ( "CreateThread() returned NULL. Failing test.\n"
+ "GetLastError returned %d\n", GetLastError());
+ }
+
+
+
+ /*
+ * Create Allocate and Free Memory Thread
+ */
+ hThread[2][i] = CreateThread(
+ NULL,
+ 0,
+ allocateandfree_memory,
+ NULL,
+ 0,
+ &dwThreadId);
+
+ if ( NULL == hThread[2][i])
+ {
+ Fail ( "CreateThread() returned NULL. Failing test.\n"
+ "GetLastError returned %d\n", GetLastError());
+ }
+
+
+
+ /*
+ * Create Work in tight Loop thread
+ */
+ hThread[3][i] = CreateThread(
+ NULL,
+ 0,
+ doworkintightloop_cs,
+ NULL,
+ 0,
+ &dwThreadId);
+
+ if ( NULL == hThread[3][i])
+ {
+ Fail ( "CreateThread() returned NULL. Failing test.\n"
+ "GetLastError returned %d\n", GetLastError());
+ }
+
+
+
+}
+
+
+
+
+
+/*
+ * Create Main test case thread that Suspends and Resumes Threads
+ */
+ hMainThread = CreateThread(
+ NULL,
+ 0,
+ suspendandresumethreads,
+ (LPVOID)dwThrdParam,
+ 0,
+ &dwThreadId);
+
+ if ( NULL == hMainThread )
+ {
+ Fail ( "CreateThread() returned NULL. Failing test.\n"
+ "GetLastError returned %d\n", GetLastError());
+ }
+
+
+
+
+/*
+* Set Event to allow all threads to start
+*/
+
+if (0==SetEvent(g_hEvent))
+{
+ Fail ( "SetEvent returned Zero. Failing test.\n"
+ "GetLastError returned %d\n", GetLastError());
+}
+
+/*
+ * Wait for main thread to complete
+ *
+ */
+ if (WAIT_OBJECT_0 != WaitForSingleObject (hMainThread, INFINITE))
+ {
+ Fail ("Main: Wait for Single Object (mainThread) failed. Failing test.\n"
+ "GetLastError returned %d\n", GetLastError());
+ }
+
+//Get the end time of the process
+processStats.operationTime = GetTickCount() - dwStart;
+
+//Write Process Result Contents to File
+if(hProcessFile!= NULL)
+ {
+ fprintf(hProcessFile, "%d,%lu,%d\n", processStats.processId, processStats.operationTime, processStats.relationId );
+ }
+
+if (0!=fclose(hProcessFile))
+{
+ Fail("Unable to write process results to file"
+ "GetLastError returned %d\n", GetLastError());
+}
+
+
+//Write to log file
+//Trace("# of Read File Operations %d\n", g_readfileoperation);
+//Trace("# of Enter and Leace CS Operations %d\n", g_enterleavecsoperation);
+//Trace("# of Do Work In Tight Loop Operations %d\n", g_doworintightloop);
+//Trace("# of Allocate and Free Operations %d\n", g_allocatefreeoperation);
+
+
+//Write Thread Result Contents to File
+if(hFile!= NULL)
+ {
+ for( i = 0; i < 1; i++ )
+ {
+ buffer = (struct statistics *)resultBuffer->getResultBuffer(i);
+ fprintf(hFile, "%d,%d,%d,%d,%lu,%d\n", buffer->processId, buffer->operationsFailed, buffer->operationsPassed, buffer->operationsTotal, buffer->operationTime, buffer->relationId );
+ }
+ }
+
+if (0!=fclose(hFile))
+{
+ Fail("Unable to write thread results to file"
+ "GetLastError returned %d\n", GetLastError());
+}
+
+cleanup();
+
+if (failFlag == TRUE)
+{
+ return FAIL;
+}
+else
+{
+ return PASS;
+}
+}
+
+
+/*
+* Setup for the test case
+*/
+
+VOID
+setup(VOID)
+{
+ /*Delete All Temporary Files Created by the previous execution of the test case*/
+ HANDLE hSearch;
+ BOOL fFinished = FALSE;
+ WIN32_FIND_DATA FileData;
+
+ //Start searching for .tmp files in the current directory.
+ hSearch = FindFirstFile("*.tmp*", &FileData);
+ if (hSearch == INVALID_HANDLE_VALUE)
+ {
+ //No Files That Matched Criteria
+ fFinished = TRUE;
+ }
+
+ //Delete all files that match the pattern
+ while (!fFinished)
+ {
+ if (!DeleteFile(FileData.cFileName))
+ {
+ Trace("Setup: Could not delete temporary file %s\n",FileData.cFileName );
+ Fail ("GetLastError returned %d\n", GetLastError());
+ }
+ if (!FindNextFile(hSearch, &FileData))
+ {
+ if (GetLastError() == ERROR_NO_MORE_FILES)
+ {
+ fFinished = TRUE;
+ }
+ else
+ {
+ Fail("Unable to Delete Temporary Files, GetLastError is %d \n", GetLastError());
+ }
+ }
+ }
+
+ // Close the search handle, only if HANDLE is Valid
+ if (hSearch != INVALID_HANDLE_VALUE)
+ {
+ if (!FindClose(hSearch))
+ {
+ Trace("Setup: Could not close search handle \n");
+ Fail ("GetLastError returned %d\n", GetLastError());
+ }
+ }
+
+ g_hEvent = CreateEvent(NULL,TRUE,FALSE, NULL);
+ if(g_hEvent == NULL)
+ {
+ Fail("Create Event Failed\n"
+ "GetLastError returned %d\n", GetLastError());
+ }
+
+ InitializeCriticalSection ( &g_csUniqueFileName);
+}
+
+/*
+* Cleanup for the test case
+*/
+
+VOID
+cleanup(VOID)
+{
+ //DeleteCriticalSection(&g_csUniqueFileName);
+ PAL_Terminate();
+}
+
+
+VOID
+incrementCounter(VOID)
+{
+
+ if (INT_MAX == GLOBAL_COUNTER)
+ {
+ GLOBAL_COUNTER = 0;
+ }
+
+ GLOBAL_COUNTER++;
+}
+
+/*
+ * Worker Thread
+ * Read File: Read from a file and write to a temporary file and then delete the temp file
+ */
+DWORD
+PALAPI
+readfile( LPVOID lpParam )
+{
+
+ // Declaring Local Variables
+ HANDLE hFile,hTempfile;
+ char buffer[BUFSIZE];
+ DWORD dwBytesRead, dwBytesWritten, dwBufSize=BUFSIZE;
+ DWORD dwWaitResult=0;
+ char filename[MAX_PATH];
+
+ //Wait for event to signal to start test
+ dwWaitResult = WaitForSingleObject(g_hEvent,INFINITE);
+ if (WAIT_OBJECT_0 != dwWaitResult)
+ {
+ Fail ("readfile: Wait for Single Object (g_hEvent) failed. Failing test.\n"
+ "GetLastError returned %d\n", GetLastError());
+ }
+
+
+ /*Start Operation*/
+
+ // Open the existing file.
+ while(TRUE)
+ {
+
+ hFile = CreateFile("samplefile.dat", // file name
+ GENERIC_READ, // open for reading
+ FILE_SHARE_READ, // Share the file for read
+ NULL, // default security
+ OPEN_EXISTING, // existing file only
+ FILE_ATTRIBUTE_NORMAL, // normal file
+ NULL); // no template
+
+ if (hFile == INVALID_HANDLE_VALUE)
+ {
+ Trace("Could not open file \n");
+ Fail ( "GetLastError returned %d\n", GetLastError());
+ }
+
+ //Generate Unique File Name to Write
+ //Enter CS
+ EnterCriticalSection(&g_csUniqueFileName);
+
+ //Increment Number and assign to local variable
+ UNIQUE_FILE_NUMBER++;
+ _snprintf(filename, MAX_PATH, "%d_%d_tempfile.tmp", USE_PROCESS_COUNT,UNIQUE_FILE_NUMBER);
+ //filename = itoa(UNIQUE_FILE_NUMBER);
+ //Leave CS
+ LeaveCriticalSection(&g_csUniqueFileName);
+
+
+ // Create a temporary file with name generate above
+ hTempfile = CreateFile(filename, // file name
+ GENERIC_WRITE, // open for read/write
+ 0, // do not share
+ NULL, // default security
+ CREATE_ALWAYS, // overwrite existing file
+ FILE_ATTRIBUTE_NORMAL, // normal file
+ NULL); // no template
+
+
+ if (hTempfile == INVALID_HANDLE_VALUE)
+ {
+ Trace("Could not create temporary file\n");
+ Fail ( "GetLastError returned %d\n", GetLastError());
+ }
+
+ // Read 4K blocks to the buffer.
+ // Change all characters in the buffer to upper case.
+ // Write the buffer to the temporary file.
+
+ do
+ {
+ if (ReadFile(hFile, buffer, 4096,
+ &dwBytesRead, NULL))
+ {
+
+ WriteFile(hTempfile, buffer, dwBytesRead,
+ &dwBytesWritten, NULL);
+ }
+ } while (dwBytesRead == BUFSIZE);
+
+
+
+ // Close both files.
+ if (0==CloseHandle(hFile))
+ {
+ Trace("Could not handle hFile\n");
+ Fail ( "GetLastError returned %d\n", GetLastError());
+ }
+
+ if (0==CloseHandle(hTempfile))
+ {
+ Trace("Could not handle hTempFile\n");
+ Fail ( "GetLastError returned %d\n", GetLastError());
+ }
+
+ //Delete the file that was created
+ if (!DeleteFile(filename))
+ {
+ Trace("Could not delete temporary file %s\n", filename);
+ Fail ( "GetLastError returned %d\n", GetLastError());
+
+ }
+
+ //g_readfileoperation++;
+ }
+
+/*End Operation*/
+
+ return 0;
+}
+
+
+/* Worker Thread
+ * Enter and Leave Nested Critical Sections
+ */
+DWORD
+PALAPI
+enterandleave_cs( LPVOID lpParam )
+{
+
+ //Declare Local Variables
+
+ CRITICAL_SECTION lcs;
+ CRITICAL_SECTION lcsNested;
+
+ DWORD dwWaitResult;
+
+ //Intialize Critical Section Structures
+ InitializeCriticalSection ( &lcs);
+ InitializeCriticalSection ( &lcsNested);
+
+
+ //Wait for event to signal to start test
+ dwWaitResult = WaitForSingleObject(g_hEvent,INFINITE);
+ if (WAIT_OBJECT_0 != dwWaitResult)
+ {
+ Fail ("enterandleave_cs: Wait for Single Object (g_hEvent) failed. Failing test.\n"
+ "GetLastError returned %d\n", GetLastError());
+ }
+
+ //Trace("Critical Section Started\n");
+
+ while(TRUE)
+ {
+ EnterCriticalSection(&lcs);
+
+ EnterCriticalSection(&lcsNested);
+
+ incrementCounter();
+
+ LeaveCriticalSection(&lcsNested);
+
+ LeaveCriticalSection(&lcs);
+ //g_enterleavecsoperation++;
+ }
+
+ //Delete Critical Section Structures
+
+ DeleteCriticalSection(&lcs);
+ DeleteCriticalSection(&lcsNested);
+
+
+ return 0;
+}
+
+
+/*
+ * Allocate and Free Memory
+ */
+DWORD
+PALAPI
+allocateandfree_memory( LPVOID lpParam )
+{
+
+
+ int i;
+ char *textArrPtr[64];
+ DWORD dwWaitResult;
+
+ //Wait for event to signal to start test
+ dwWaitResult = WaitForSingleObject(g_hEvent,INFINITE);
+ if (WAIT_OBJECT_0 != dwWaitResult)
+ {
+ Fail ("allocateandfree_memory: Wait for Single Object (g_hEvent) failed. Failing test.\n"
+ "GetLastError returned %d\n", GetLastError());
+ }
+
+
+ while(TRUE)
+ {
+
+ //do allocate and free operation
+
+ for (i=0;i<64;i++)
+ {
+ textArrPtr[i] = (char*) malloc(BUFSIZE);
+ if (textArrPtr[i] == NULL)
+ {
+ Fail("Insufficient Memory Available, GetLastError is %d \n", GetLastError());
+ testStatus = TEST_FAIL;
+ }
+ }
+
+ for (i=0;i<64;i++)
+ {
+ free(textArrPtr[i]);
+ }
+ //g_allocatefreeoperation++;
+ }
+
+
+
+
+ return 0;
+}
+
+/*
+ * Do work in a tight loop
+ */
+DWORD
+PALAPI
+doworkintightloop_cs( LPVOID lpParam )
+{
+
+ unsigned int i;
+ DWORD dwWaitResult;
+
+ //Wait for event to signal to start test
+ dwWaitResult = WaitForSingleObject(g_hEvent,INFINITE);
+ if (WAIT_OBJECT_0 != dwWaitResult)
+ {
+ Fail ("doworkintightloop_cs: Wait for Single Object (g_hEvent) failed. Failing test.\n"
+ "GetLastError returned %d\n", GetLastError());
+ }
+
+ i= 0;
+ while (TRUE)
+ {
+
+ if (INT_MAX == i)
+ i =0;
+ i++;
+ //g_doworintightloop++;
+ }
+
+ return 0;
+}
+
+
+/*
+ * Main Test Case worker thread which will suspend and resume all other worker threads
+ */
+DWORD
+PALAPI
+suspendandresumethreads( LPVOID lpParam )
+{
+
+ unsigned int loopcount = REPEAT_COUNT;
+ int Id=(int)lpParam;
+ unsigned int i,j,k;
+ DWORD dwStart;
+ DWORD dwWaitResult=0;
+ DWORD dwLastError = 0;
+ struct statistics stats;
+ struct statistics* buffer;
+
+
+
+ //Initialize the Statistics Structure
+ stats.relationId = RELATION_ID;
+ stats.processId = USE_PROCESS_COUNT;
+ stats.operationsFailed = 0;
+ stats.operationsPassed = 0;
+ stats.operationsTotal = 0;
+ stats.operationTime = 0;
+
+
+
+ //Wait for event to signal to start test
+ WaitForSingleObject(g_hEvent,INFINITE);
+ if (WAIT_OBJECT_0 != dwWaitResult)
+ {
+ Fail ("suspendandresumethreads: Wait for Single Object (g_hEvent) failed. Failing test.\n"
+ "GetLastError returned %d\n", GetLastError());
+ }
+
+
+ //Capture Start Import
+ dwStart = GetTickCount();
+
+ for(i = 0; i < loopcount; i++)
+ {
+
+ failFlag = false;
+
+ //Suspend Worker Threads
+ for (k=0;k<WORKER_THREAD_MULTIPLIER_COUNT;k++)
+ {
+ for (j=0;j<4;j++)
+ {
+ if (-1 == SuspendThread(hThread[j][k]))
+ {
+ //If the operation indicate failure
+ failFlag = true;
+ }
+ }
+ }
+
+
+ //Resume Worker Threads
+ for (k=0;k<WORKER_THREAD_MULTIPLIER_COUNT;k++)
+ {
+ for (j=0;j<4;j++)
+ {
+
+ //Only suspend if not already in suspended state
+
+ if (-1 == ResumeThread(hThread[j][k]))
+ {
+ //If the operation indicate failure
+ failFlag = true;
+ }
+
+ }
+ }
+
+
+ //Check for Fail Flag. If set increment number of failures
+ // If Fail flag not set then increment number of operations and number of passe
+ if (failFlag == true)
+ {
+ stats.operationsFailed++;
+ }
+ else
+ {
+ stats.operationsPassed +=1;
+
+ }
+ stats.operationsTotal +=1;
+
+ }
+
+ stats.operationTime = GetTickCount() - dwStart;
+
+ /*Trace("\n\n\n\nOperation Time: %d milliseconds\n", stats.operationTime);
+ Trace("Operation Passed: %d\n", stats.operationsPassed);
+ Trace("Operation Total: %d\n", stats.operationsTotal);
+ Trace("Operation Failed: %d\n", stats.operationsFailed);
+ */
+ if(resultBuffer->LogResult(Id, (char *)&stats))
+ {
+ Fail("Error while writing to shared memory, Thread Id is[%d] and Process id is [%d]\n", Id, USE_PROCESS_COUNT);
+ }
+
+ buffer = (struct statistics *)resultBuffer->getResultBuffer(Id);
+ //Trace("\n%d,%d,%d,%lu\n", buffer->operationsFailed, buffer->operationsPassed, buffer->operationsTotal, buffer->operationTime );
+
+
+ return 0;
+}
+
+
+
+int GetParameters( int argc, char **argv)
+{
+
+ if( (argc != 5) || ((argc == 1) && !strcmp(argv[1],"/?"))
+ || !strcmp(argv[1],"/h") || !strcmp(argv[1],"/H"))
+ {
+ Trace("PAL -Composite Thread Suspension Test\n");
+ Trace("Usage:\n");
+ Trace("\t[PROCESS_COUNT] Greater than or Equal to 1 \n");
+ Trace("\t[WORKER_THREAD_MULTIPLIER_COUNT] Greater than or Equal to 1 and Less than or Equal to 64 \n");
+ Trace("\t[REPEAT_COUNT] Greater than or Equal to 1\n");
+ Trace("\t[RELATION_ID [greater than or Equal to 1]\n");
+ return -1;
+ }
+
+// Trace("Args 1 is [%s], Arg 2 is [%s], Arg 3 is [%s]\n", argv[1], argv[2], argv[3]);
+
+ USE_PROCESS_COUNT = atoi(argv[1]);
+ if( USE_PROCESS_COUNT < 0)
+ {
+ Trace("\nPROCESS_COUNT to greater than or equal to 1\n");
+ return -1;
+ }
+
+ WORKER_THREAD_MULTIPLIER_COUNT = atoi(argv[2]);
+ if( WORKER_THREAD_MULTIPLIER_COUNT < 1 || WORKER_THREAD_MULTIPLIER_COUNT > 64)
+ {
+ Trace("\nWORKER_THREAD_MULTIPLIER_COUNT to be greater than or equal to 1 or less than or equal to 64\n");
+ return -1;
+ }
+
+ REPEAT_COUNT = atoi(argv[3]);
+ if( REPEAT_COUNT < 1)
+ {
+ Trace("\nREPEAT_COUNT to greater than or equal to 1\n");
+ return -1;
+ }
+
+ RELATION_ID = atoi(argv[4]);
+ if( RELATION_ID < 1)
+ {
+ Trace("\nRELATION_ID to be greater than or equal to 1\n");
+ return -1;
+ }
+ return 0;
+}
diff --git a/src/pal/tests/palsuite/composite/threading/threadsuspension_switchthread/CMakeLists.txt b/src/pal/tests/palsuite/composite/threading/threadsuspension_switchthread/CMakeLists.txt
new file mode 100644
index 0000000000..5361a1cf0d
--- /dev/null
+++ b/src/pal/tests/palsuite/composite/threading/threadsuspension_switchthread/CMakeLists.txt
@@ -0,0 +1,20 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ mainWrapper.c
+ threadsuspension.c
+)
+
+add_executable(paltest_threading_threadsuspension_switchthread
+ ${SOURCES}
+)
+
+add_dependencies(paltest_threading_threadsuspension_switchthread coreclrpal)
+
+target_link_libraries(paltest_threading_threadsuspension_switchthread
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/composite/threading/threadsuspension_switchthread/mainWrapper.c b/src/pal/tests/palsuite/composite/threading/threadsuspension_switchthread/mainWrapper.c
new file mode 100644
index 0000000000..05a71191cf
--- /dev/null
+++ b/src/pal/tests/palsuite/composite/threading/threadsuspension_switchthread/mainWrapper.c
@@ -0,0 +1,274 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*
+Source Code: mainWrapper.c
+
+mainWrapper.c creates Composite Test Case Processes and waits for all processes to get over
+
+Algorithm
+o Create PROCESS_COUNT processes.
+
+Author: RameshG
+*/
+
+#include <palsuite.h>
+#include "resulttime.h"
+
+/* Test Input Variables */
+unsigned int USE_PROCESS_COUNT = 0; //default
+unsigned int WORKER_THREAD_MULTIPLIER_COUNT = 0; //default
+unsigned int REPEAT_COUNT = 0; //default
+unsigned int SLEEP_LENGTH = 0; //default
+unsigned int RELATION_ID = 0;//default
+unsigned int THREAD_COUNT = 1; //There is only one suspender and resume thread for this test case
+
+char *testCaseName;
+
+
+struct applicationStatistics{
+ DWORD operationTime;
+ unsigned int relationId;
+ unsigned int processCount;
+ unsigned int threadCount;
+ unsigned int repeatCount;
+ char* buildNumber;
+
+};
+
+
+int GetParameters( int argc, char **argv)
+{
+
+ if( (argc != 5) || ((argc == 1) && !strcmp(argv[1],"/?"))
+ || !strcmp(argv[1],"/h") || !strcmp(argv[1],"/H"))
+ {
+ printf("PAL -Composite Thread Suspension Test\n");
+ printf("Usage:\n");
+ printf("\t[PROCESS_COUNT] Greater than or Equal to 1 \n");
+ printf("\t[WORKER_THREAD_MULTIPLIER_COUNT] Greater than or Equal to 1 and Less than or Equal to %d \n", MAXIMUM_WAIT_OBJECTS);
+ printf("\t[REPEAT_COUNT] Greater than or Equal to 1\n");
+ printf("\t[RELATION_ID [greater than or Equal to 1]\n");
+ return -1;
+ }
+
+ // Trace("Args 1 is [%s], Arg 2 is [%s], Arg 3 is [%s]\n", argv[1], argv[2], argv[3]);
+
+ USE_PROCESS_COUNT = atoi(argv[1]);
+ if( USE_PROCESS_COUNT < 0)
+ {
+ printf("\nPROCESS_COUNT to greater than or equal to 1\n");
+ return -1;
+ }
+
+ WORKER_THREAD_MULTIPLIER_COUNT = atoi(argv[2]);
+ if( WORKER_THREAD_MULTIPLIER_COUNT < 1 || WORKER_THREAD_MULTIPLIER_COUNT > 64)
+ {
+ printf("\nWORKER_THREAD_MULTIPLIER_COUNT to be greater than or equal to 1 or less than or equal to 64\n");
+ return -1;
+ }
+
+ REPEAT_COUNT = atoi(argv[3]);
+ if( REPEAT_COUNT < 1)
+ {
+ printf("\nREPEAT_COUNT to greater than or equal to 1\n");
+ return -1;
+ }
+
+ RELATION_ID = atoi(argv[4]);
+ if( RELATION_ID < 1)
+ {
+ printf("\nRELATION_ID to be greater than or equal to 1\n");
+ return -1;
+ }
+
+
+
+ return 0;
+}
+
+ int __cdecl main(INT argc, CHAR **argv)
+{
+ unsigned int i = 0;
+ HANDLE hProcess[MAXIMUM_WAIT_OBJECTS];
+ DWORD processReturnCode = 0;
+ int testReturnCode = PASS;
+ STARTUPINFO si[MAXIMUM_WAIT_OBJECTS];
+ PROCESS_INFORMATION pi[MAXIMUM_WAIT_OBJECTS];
+
+ FILE *hFile;
+ char fileName[MAX_PATH];
+ struct applicationStatistics appStats;
+
+ DWORD dwStart=0;
+
+ char lpCommandLine[MAX_PATH] = "";
+
+ char build[] ="0000.00";
+ int returnCode = 0;
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return ( FAIL );
+ }
+
+ //Initialize Application Statistics Strucuture
+ appStats.relationId=RELATION_ID;
+ appStats.operationTime=0;
+ appStats.buildNumber = getBuildNumber();
+ //appStats.buildNumber = build;
+ appStats.processCount = 0;
+ appStats.threadCount = 0;
+ appStats.repeatCount = 0;
+
+
+
+
+
+//Start Process Time Capture
+dwStart = GetTickCount();
+
+ if(GetParameters(argc, argv))
+ {
+ Fail("Error in obtaining the parameters\n");
+ }
+
+//Assign Correct Values to the Application Stats Structure
+ appStats.relationId=RELATION_ID;
+ appStats.processCount = USE_PROCESS_COUNT;
+ appStats.threadCount = THREAD_COUNT ;
+ appStats.repeatCount = REPEAT_COUNT;
+
+ Trace("Relation ID: %d \n", RELATION_ID);
+ Trace("USE_PROCESS_COUNT: %d \n", USE_PROCESS_COUNT);
+ Trace("WORKER_THREAD_MULTIPLIER_COUNT: %d \n", WORKER_THREAD_MULTIPLIER_COUNT);
+ Trace("REPEAT_COUNT: %d \n", REPEAT_COUNT);
+
+
+_snprintf(fileName, MAX_PATH, "main_threadsuspension_%d_.txt",appStats.relationId);
+
+ hFile = fopen(fileName, "w+");
+if(hFile == NULL)
+ {
+ Fail("Error in opening file to write application results for Thread Suspension Test with error code %d \n", GetLastError() );
+ }
+
+
+
+ for( i = 0; i < USE_PROCESS_COUNT; i++ )
+ {
+
+ ZeroMemory( lpCommandLine, MAX_PATH );
+ if ( _snprintf( lpCommandLine, MAX_PATH-1, "threadsuspension %d %d %d %d", i, WORKER_THREAD_MULTIPLIER_COUNT, REPEAT_COUNT, RELATION_ID) < 0 )
+ {
+ Trace ("Error: Insufficient commandline string length for for iteration [%d]\n", i);
+ }
+
+ /* Zero the data structure space */
+ ZeroMemory ( &pi[i], sizeof(pi[i]) );
+ ZeroMemory ( &si[i], sizeof(si[i]) );
+
+ /* Set the process flags and standard io handles */
+ si[i].cb = sizeof(si[i]);
+
+ //Printing the Command Line
+ //Trace("Command Line \t %s \n", lpCommandLine);
+
+ //Create Process
+ if(!CreateProcess( NULL, /* lpApplicationName*/
+ lpCommandLine, /* lpCommandLine */
+ NULL, /* lpProcessAttributes */
+ NULL, /* lpThreadAttributes */
+ TRUE, /* bInheritHandles */
+ 0, /* dwCreationFlags, */
+ NULL, /* lpEnvironment */
+ NULL, /* pCurrentDirectory */
+ &si[i], /* lpStartupInfo */
+ &pi[i] /* lpProcessInformation */
+ ))
+ {
+ Fail("Process Not created for [%d] and GetLastError value is %d\n", i, GetLastError());
+
+ }
+ else
+ {
+ hProcess[i] = pi[i].hProcess;
+ //Trace("Process created for [%d]\n", i);
+ }
+
+ }
+
+ returnCode = WaitForMultipleObjects( USE_PROCESS_COUNT, hProcess, TRUE, INFINITE);
+ if( WAIT_OBJECT_0 != returnCode )
+ {
+ Trace("Wait for Object(s) @ Main thread for %d processes returned %d, and GetLastError value is %d\n", USE_PROCESS_COUNT, returnCode, GetLastError());
+ testReturnCode = FAIL;
+ }
+
+ for( i = 0; i < USE_PROCESS_COUNT; i++ )
+ {
+ /* check the exit code from the process */
+ if( ! GetExitCodeProcess( pi[i].hProcess, &processReturnCode ) )
+ {
+ Trace( "GetExitCodeProcess call failed for iteration %d with error code %u\n",
+ i, GetLastError() );
+
+ testReturnCode = FAIL;
+ }
+
+ if(processReturnCode == FAIL)
+ {
+ Trace( "Process [%d] failed and returned FAIL\n", i);
+ testReturnCode = FAIL;
+ }
+
+ if(!CloseHandle(pi[i].hThread))
+ {
+ Trace("Error:%d: CloseHandle failed for Process [%d] hThread\n", GetLastError(), i);
+ testReturnCode = FAIL;
+ }
+
+ if(!CloseHandle(pi[i].hProcess) )
+ {
+ Trace("Error:%d: CloseHandle failed for Process [%d] hProcess\n", GetLastError(), i);
+ testReturnCode = FAIL;
+ }
+ }
+
+//Get the end time of the process
+appStats.operationTime = GetTickCount() - dwStart;
+
+if( testReturnCode == PASS)
+ {
+ Trace("Test Passed\n");
+ }
+ else
+ {
+ Trace("Test Failed\n");
+ }
+
+//Write Process Result Contents to File
+if(hFile!= NULL)
+ {
+ fprintf(hFile, "%lu,%d,%d,%d,%d,%s\n", appStats.operationTime, appStats.relationId, appStats.processCount, appStats.threadCount, appStats.repeatCount, appStats.buildNumber);
+ }
+
+if (0!=fclose(hFile))
+{
+ Trace("Error:%d: fclose failed for file %s\n", GetLastError(), fileName);
+}
+ PAL_Terminate();
+
+
+if( testReturnCode == PASS)
+ {
+ return PASS;
+ }
+ else
+ {
+ return FAIL;
+
+ }
+
+}
diff --git a/src/pal/tests/palsuite/composite/threading/threadsuspension_switchthread/readme.txt b/src/pal/tests/palsuite/composite/threading/threadsuspension_switchthread/readme.txt
new file mode 100644
index 0000000000..d722f1d127
--- /dev/null
+++ b/src/pal/tests/palsuite/composite/threading/threadsuspension_switchthread/readme.txt
@@ -0,0 +1,11 @@
+To compile:
+
+1) create a dat file (say threadsuspension.dat) with contents:
+PAL,Composite,palsuite\composite\threading\threadsuspension,wfmo=mainWrapper.c threadsuspension.c,<SUPPORTEXE>,<TESTLANGCPP>,<COMPILEONLY>
+
+2) perl rrunmod.pl -r threadsuspension.dat
+
+
+To execute:
+mainWrapper [PROCESS_COUNT] [THREAD_COUNT] [REPEAT_COUNT]
+
diff --git a/src/pal/tests/palsuite/composite/threading/threadsuspension_switchthread/samplefile.dat b/src/pal/tests/palsuite/composite/threading/threadsuspension_switchthread/samplefile.dat
new file mode 100644
index 0000000000..d6505f2549
--- /dev/null
+++ b/src/pal/tests/palsuite/composite/threading/threadsuspension_switchthread/samplefile.dat
@@ -0,0 +1,5124 @@
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense blackasdf dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
+By Patricia Reaney
+LONDON (Reuters) - Europe, Africa and the Middle East are the best vantage points to see the first transit of Venus across the sun in more than a century on Tuesday, scientists said.
+
+Mostly clear skies are forecast in many parts of the three regions, but people were urged to be careful if they watch the rare event when it begins at 1:19 a.m. EDT because it could cause blindness. Views will be restricted from Asia and the Americas.
+
+Unlike a solar eclipse by the moon that is over in two or three minutes, Venus's transit -- which last occurred in 1882 -- will go on for six hours.
+
+The planet will appear as an intense black dot on the solar disc.
+
+Most of the sun will be visible as Venus crosses to the right from the bottom left side of the solar disc. Venus will be 26.7 million miles from earth.
+
+"Venus will be about 1/30 the size of the diameter of the sun, but it will be much darker and more intense than sunspots," said Dr Robert Walsh, of the University of Central Lancashire's Center for Astrophysics in northern England.
+
+Scientists recommend some form of indirect projection as the safest way to observe the phenomenon.
+
+"Never ever look directly at the sun with the naked eye or any sort of optical equipment -- telescope, binoculars or even digital camera," said Walsh.
+
+"Even if you glance at the sun for a short period of time you can damage your eye and lose some of your sight," he said.
+
+Internet sites will be covering the transit and observatories around the world have organized viewings.
+
+"Mainly Western Europe could see some high cloud that might prevent people from seeing it," said a spokesman for Britain's Meteorological Office. "The rest of Europe shouldn't be too bad. It should be fine."
+
+German astronomer Johannes Kepler first predicted a transit of Venus in 1627 but he died before he could witness one. English astronomer Jeremiah Horrocks first observed it in 1639.
+
+The transit occurs four times in every 243 years. There are two December transits, eight years apart, and then 121.5 years later there are two June transits, also eight years apart. After another 105.5 years the cycle begins again.
+
+The next transit will occur in 2012 when it will be visible from parts of Asia and the Pacific but not Europe.
diff --git a/src/pal/tests/palsuite/composite/threading/threadsuspension_switchthread/threadsuspension.c b/src/pal/tests/palsuite/composite/threading/threadsuspension_switchthread/threadsuspension.c
new file mode 100644
index 0000000000..a117b86174
--- /dev/null
+++ b/src/pal/tests/palsuite/composite/threading/threadsuspension_switchthread/threadsuspension.c
@@ -0,0 +1,914 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: \composite\threading\threadsuspension\threadsuspension.c
+**
+** Purpose: To verify Thread Suspension Reegneering effort for this milestone
+
+ PsedoCode:
+
+ Preparation:
+ Create PROCESS_COUNT processes.
+ Test:
+ Create Worker Thread
+ Start Reading and writing to a File
+
+ Create Worker Thread
+ In an infinite loop do the following
+ Enter Critical Section
+ Increment Counter
+ Leave Critical Section
+
+ Create Worker Thread
+ Allocate Memory and Free Memory
+
+ Create Worker Thread
+ In a tight loop add numbers
+
+ In a loop repeated REPEAT_COUNT times
+
+ Create Thread
+
+ Suspend all worker threads
+ Resume all worker threads
+
+ At the end of the loop call PAL_Shutdown
+
+ Parameters:
+ PROCESS_COUNT: Number of processes
+ WORKER_THREAD_MULTIPLIER_COUNT: Number of instances of worker threads in each process
+ REPEAT_COUNT: The number of times to execute the loop.
+
+ Statistics Captured:
+ Total elapsed time
+ MTBF
+
+
+ Scenario:
+**
+ One thread suspends all remaining threads which are in the middle of doing some work and resume all threads
+ Thread 1: Reading and Writing File
+ Thread 2: Enter and Leave Critical Section
+ Thread 3: Allocating chunks of memory
+ Thread 4: Perform Unsafe Operation (printf, malloc)
+ Thread 5: Suspends Thread 1 to Thread 4 and resumes them
+
+**
+**
+**
+** Dependencies:
+**
+**
+
+**
+**=========================================================*/
+
+#include <palsuite.h>
+#include "resultbuffer.h"
+
+#define BUFSIZE 4096
+#define NUMBER_OF_WORKER_THREAD_TYPES 4
+#define THREAD_MAX 64
+
+#define TEST_FAIL 1
+#define TEST_PASS 0
+
+
+DWORD GLOBAL_COUNTER ;
+DWORD UNIQUE_FILE_NUMBER=0;
+HANDLE g_hEvent;
+
+bool failFlag = false; //To Track failure at the Operation Level
+
+// 2 dimensional array to hold thread handles for each worker thread
+HANDLE hThread[NUMBER_OF_WORKER_THREAD_TYPES][THREAD_MAX];
+
+/*unsigned int g_readfileoperation;
+unsigned int g_enterleavecsoperation;
+unsigned int g_allocatefreeoperation;
+unsigned int g_doworintightloop;
+*/
+
+int TYPES_OF_WORKER_THREAD = NUMBER_OF_WORKER_THREAD_TYPES;
+
+int testStatus=TEST_PASS; //Indicates test failure
+
+
+struct statistics{
+ unsigned int processId;
+ unsigned int operationsFailed;
+ unsigned int operationsPassed;
+ unsigned int operationsTotal;
+ DWORD operationTime;
+ unsigned int relationId;
+};
+
+struct processStatistics{
+ unsigned int processId;
+ DWORD operationTime;
+ unsigned int relationId;
+};
+
+/* Results Buffer */
+ResultBuffer *resultBuffer;
+
+
+/* Test Input Variables */
+unsigned int USE_PROCESS_COUNT = 0; //Identifies the Process number. There could potentially
+unsigned int WORKER_THREAD_MULTIPLIER_COUNT = 0; //In this test case this represents the number of worker thread instances
+unsigned int REPEAT_COUNT = 0; //Number of Suspend Resume operation of worker threads
+unsigned int RELATION_ID = 0;
+
+
+
+CRITICAL_SECTION CriticalSectionM; /* Critical Section Object (used as mutex) */
+CRITICAL_SECTION g_csUniqueFileName;
+
+void PALAPI setup(void);
+void PALAPI cleanup(void);
+void PALAPI incrementCounter(void);
+DWORD PALAPI readfile( LPVOID);
+DWORD PALAPI enterandleave_cs( LPVOID);
+DWORD PALAPI allocateandfree_memory( LPVOID);
+DWORD PALAPI doworkintightloop_cs( LPVOID);
+DWORD PALAPI suspendandresumethreads( LPVOID);
+int GetParameters(int, char * *);
+
+
+//Main Entry for the Thread Suspension Test Case
+int __cdecl main (int argc, char **argv)
+{
+
+/*
+* Parameter to the threads that will be created
+*/
+
+
+DWORD dwThrdParam = 0;
+DWORD dwStart;
+
+/* Variables to capture the file name and the file pointer*/
+char fileName[MAX_PATH];
+char processFileName[MAX_PATH];
+
+FILE *hFile, *hProcessFile;
+struct statistics* buffer;
+struct processStatistics *processBuffer;
+
+struct processStatistics processStats;
+
+struct statistics* tmpBuf = NULL;
+int statisticsSize = 0;
+
+DWORD dwThreadId=0;
+HANDLE hMainThread;
+unsigned int i = 0;
+int j = 0;
+
+
+/*
+* PAL Initialize
+*/
+
+if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+
+//Get Parameters
+if(GetParameters(argc, argv))
+ {
+ Fail("Error in obtaining the parameters\n");
+ }
+
+
+//Setup for Process Result Collection
+statisticsSize = sizeof(struct statistics);
+_snprintf(processFileName, MAX_PATH, "%d_process_threadsuspension_%d_.txt", USE_PROCESS_COUNT, RELATION_ID);
+hProcessFile = fopen(processFileName, "w+");
+
+if(hProcessFile == NULL)
+ {
+ Fail("Error in opening file to write process results for process [%d]\n", USE_PROCESS_COUNT);
+ }
+
+//Initialize Process Stats Variables
+processStats.operationTime = 0;
+processStats.processId = USE_PROCESS_COUNT;
+processStats.relationId = RELATION_ID;
+
+//Start Process Time Capture
+dwStart = GetTickCount();
+
+//Setup for Thread Result Collection
+statisticsSize = sizeof(struct statistics);
+_snprintf(fileName, MAX_PATH, "%d_thread_threadsuspension_%d_.txt", USE_PROCESS_COUNT,RELATION_ID);
+hFile = fopen(fileName, "w+");
+
+if(hFile == NULL)
+ {
+ Fail("Error in opening file to write thread results for process [%d]\n", USE_PROCESS_COUNT);
+ }
+
+// For each thread we will log relationid (int), processid (int), operations failed (int), passed (int), total (int)
+// and number of ticks (DWORD) for the operations
+resultBuffer = new ResultBuffer( 1, statisticsSize);
+
+/*
+* Call the Setup Routine
+*/
+setup();
+
+Trace("WORKER_THREAD_MULTIPLIER_COUNT: %d \n", WORKER_THREAD_MULTIPLIER_COUNT);
+
+//Create WORKER_THREAD_MULTIPLIER_COUNT Instances of each type of worker thread
+for (i=0;i<WORKER_THREAD_MULTIPLIER_COUNT;i++)
+{
+
+ /*
+ * Create readfile thread
+ */
+ hThread[0][i] = CreateThread(
+ NULL,
+ 0,
+ readfile,
+ NULL,
+ 0,
+ &dwThreadId);
+
+ if ( NULL == hThread[0][i] )
+ {
+ Fail ( "CreateThread() returned NULL. Failing test.\n"
+ "GetLastError returned %d\n", GetLastError());
+ }
+
+
+
+ /*
+ * Create Enter and Leave Critical Section Thread
+ */
+ hThread[1][i] = CreateThread(
+ NULL,
+ 0,
+ enterandleave_cs,
+ NULL,
+ 0,
+ &dwThreadId);
+
+ if ( NULL == hThread[1][i] )
+ {
+ Fail ( "CreateThread() returned NULL. Failing test.\n"
+ "GetLastError returned %d\n", GetLastError());
+ }
+
+
+
+ /*
+ * Create Allocate and Free Memory Thread
+ */
+ hThread[2][i] = CreateThread(
+ NULL,
+ 0,
+ allocateandfree_memory,
+ NULL,
+ 0,
+ &dwThreadId);
+
+ if ( NULL == hThread[2][i])
+ {
+ Fail ( "CreateThread() returned NULL. Failing test.\n"
+ "GetLastError returned %d\n", GetLastError());
+ }
+
+
+
+ /*
+ * Create Work in tight Loop thread
+ */
+ hThread[3][i] = CreateThread(
+ NULL,
+ 0,
+ doworkintightloop_cs,
+ NULL,
+ 0,
+ &dwThreadId);
+
+ if ( NULL == hThread[3][i])
+ {
+ Fail ( "CreateThread() returned NULL. Failing test.\n"
+ "GetLastError returned %d\n", GetLastError());
+ }
+
+
+
+}
+
+
+
+
+
+/*
+ * Create Main test case thread that Suspends and Resumes Threads
+ */
+ hMainThread = CreateThread(
+ NULL,
+ 0,
+ suspendandresumethreads,
+ (LPVOID)dwThrdParam,
+ 0,
+ &dwThreadId);
+
+ if ( NULL == hMainThread )
+ {
+ Fail ( "CreateThread() returned NULL. Failing test.\n"
+ "GetLastError returned %d\n", GetLastError());
+ }
+
+
+
+
+/*
+* Set Event to allow all threads to start
+*/
+
+if (0==SetEvent(g_hEvent))
+{
+ Fail ( "SetEvent returned Zero. Failing test.\n"
+ "GetLastError returned %d\n", GetLastError());
+}
+
+/*
+ * Wait for main thread to complete
+ *
+ */
+ if (WAIT_OBJECT_0 != WaitForSingleObject (hMainThread, INFINITE))
+ {
+ Fail ("Main: Wait for Single Object (mainThread) failed. Failing test.\n"
+ "GetLastError returned %d\n", GetLastError());
+ }
+
+//Get the end time of the process
+processStats.operationTime = GetTickCount() - dwStart;
+
+//Write Process Result Contents to File
+if(hProcessFile!= NULL)
+ {
+ fprintf(hProcessFile, "%d,%lu,%d\n", processStats.processId, processStats.operationTime, processStats.relationId );
+ }
+
+if (0!=fclose(hProcessFile))
+{
+ Fail("Unable to write process results to file"
+ "GetLastError returned %d\n", GetLastError());
+}
+
+
+//Write to log file
+//Trace("# of Read File Operations %d\n", g_readfileoperation);
+//Trace("# of Enter and Leace CS Operations %d\n", g_enterleavecsoperation);
+//Trace("# of Do Work In Tight Loop Operations %d\n", g_doworintightloop);
+//Trace("# of Allocate and Free Operations %d\n", g_allocatefreeoperation);
+
+
+//Write Thread Result Contents to File
+if(hFile!= NULL)
+ {
+ for( i = 0; i < 1; i++ )
+ {
+ buffer = (struct statistics *)resultBuffer->getResultBuffer(i);
+ fprintf(hFile, "%d,%d,%d,%d,%lu,%d\n", buffer->processId, buffer->operationsFailed, buffer->operationsPassed, buffer->operationsTotal, buffer->operationTime, buffer->relationId );
+ }
+ }
+
+if (0!=fclose(hFile))
+{
+ Fail("Unable to write thread results to file"
+ "GetLastError returned %d\n", GetLastError());
+}
+
+cleanup();
+
+if (failFlag == TRUE)
+{
+ return FAIL;
+}
+else
+{
+ return PASS;
+}
+}
+
+
+/*
+* Setup for the test case
+*/
+
+VOID
+setup(VOID)
+{
+ /*Delete All Temporary Files Created by the previous execution of the test case*/
+ HANDLE hSearch;
+ BOOL fFinished = FALSE;
+ WIN32_FIND_DATA FileData;
+
+ //Start searching for .tmp files in the current directory.
+ hSearch = FindFirstFile("*.tmp*", &FileData);
+ if (hSearch == INVALID_HANDLE_VALUE)
+ {
+ //No Files That Matched Criteria
+ fFinished = TRUE;
+ }
+
+ //Delete all files that match the pattern
+ while (!fFinished)
+ {
+ if (!DeleteFile(FileData.cFileName))
+ {
+ Trace("Setup: Could not delete temporary file %s\n",FileData.cFileName );
+ Fail ("GetLastError returned %d\n", GetLastError());
+ }
+ if (!FindNextFile(hSearch, &FileData))
+ {
+ if (GetLastError() == ERROR_NO_MORE_FILES)
+ {
+ fFinished = TRUE;
+ }
+ else
+ {
+ Fail("Unable to Delete Temporary Files, GetLastError is %d \n", GetLastError());
+ }
+ }
+ }
+
+ // Close the search handle, only if HANDLE is Valid
+ if (hSearch != INVALID_HANDLE_VALUE)
+ {
+ if (!FindClose(hSearch))
+ {
+ Trace("Setup: Could not close search handle \n");
+ Fail ("GetLastError returned %d\n", GetLastError());
+ }
+ }
+
+ g_hEvent = CreateEvent(NULL,TRUE,FALSE, NULL);
+ if(g_hEvent == NULL)
+ {
+ Fail("Create Event Failed\n"
+ "GetLastError returned %d\n", GetLastError());
+ }
+
+ InitializeCriticalSection ( &g_csUniqueFileName);
+}
+
+/*
+* Cleanup for the test case
+*/
+
+VOID
+cleanup(VOID)
+{
+ //DeleteCriticalSection(&g_csUniqueFileName);
+ PAL_Terminate();
+}
+
+
+VOID
+incrementCounter(VOID)
+{
+
+ if (INT_MAX == GLOBAL_COUNTER)
+ {
+ GLOBAL_COUNTER = 0;
+ }
+
+ GLOBAL_COUNTER++;
+}
+
+/*
+ * Worker Thread
+ * Read File: Read from a file and write to a temporary file and then delete the temp file
+ */
+DWORD
+PALAPI
+readfile( LPVOID lpParam )
+{
+
+ // Declaring Local Variables
+ HANDLE hFile,hTempfile;
+ char buffer[BUFSIZE];
+ DWORD dwBytesRead, dwBytesWritten, dwBufSize=BUFSIZE;
+ DWORD dwWaitResult=0;
+ char filename[MAX_PATH];
+
+ //Wait for event to signal to start test
+ dwWaitResult = WaitForSingleObject(g_hEvent,INFINITE);
+ if (WAIT_OBJECT_0 != dwWaitResult)
+ {
+ Fail ("readfile: Wait for Single Object (g_hEvent) failed. Failing test.\n"
+ "GetLastError returned %d\n", GetLastError());
+ }
+
+
+ /*Start Operation*/
+
+ // Open the existing file.
+ while(TRUE)
+ {
+
+ hFile = CreateFile("samplefile.dat", // file name
+ GENERIC_READ, // open for reading
+ FILE_SHARE_READ, // Share the file for read
+ NULL, // default security
+ OPEN_EXISTING, // existing file only
+ FILE_ATTRIBUTE_NORMAL, // normal file
+ NULL); // no template
+
+ if (hFile == INVALID_HANDLE_VALUE)
+ {
+ Trace("Could not open file \n");
+ Fail ( "GetLastError returned %d\n", GetLastError());
+ }
+
+ //Generate Unique File Name to Write
+ //Enter CS
+ EnterCriticalSection(&g_csUniqueFileName);
+
+ //Increment Number and assign to local variable
+ UNIQUE_FILE_NUMBER++;
+ _snprintf(filename, MAX_PATH, "%d_%d_tempfile.tmp", USE_PROCESS_COUNT,UNIQUE_FILE_NUMBER);
+ //filename = itoa(UNIQUE_FILE_NUMBER);
+ //Leave CS
+ LeaveCriticalSection(&g_csUniqueFileName);
+
+
+ // Create a temporary file with name generate above
+ hTempfile = CreateFile(filename, // file name
+ GENERIC_WRITE, // open for read/write
+ 0, // do not share
+ NULL, // default security
+ CREATE_ALWAYS, // overwrite existing file
+ FILE_ATTRIBUTE_NORMAL, // normal file
+ NULL); // no template
+
+
+ if (hTempfile == INVALID_HANDLE_VALUE)
+ {
+ Trace("Could not create temporary file\n");
+ Fail ( "GetLastError returned %d\n", GetLastError());
+ }
+
+ // Read 4K blocks to the buffer.
+ // Change all characters in the buffer to upper case.
+ // Write the buffer to the temporary file.
+
+ do
+ {
+ if (ReadFile(hFile, buffer, 4096,
+ &dwBytesRead, NULL))
+ {
+
+ WriteFile(hTempfile, buffer, dwBytesRead,
+ &dwBytesWritten, NULL);
+ }
+ } while (dwBytesRead == BUFSIZE);
+
+
+
+ // Close both files.
+ if (0==CloseHandle(hFile))
+ {
+ Trace("Could not handle hFile\n");
+ Fail ( "GetLastError returned %d\n", GetLastError());
+ }
+
+ if (0==CloseHandle(hTempfile))
+ {
+ Trace("Could not handle hTempFile\n");
+ Fail ( "GetLastError returned %d\n", GetLastError());
+ }
+
+ //Delete the file that was created
+ if (!DeleteFile(filename))
+ {
+ Trace("Could not delete temporary file %s\n", filename);
+ Fail ( "GetLastError returned %d\n", GetLastError());
+
+ }
+
+ SwitchToThread();
+ //g_readfileoperation++;
+ }
+
+/*End Operation*/
+
+ return 0;
+}
+
+
+/* Worker Thread
+ * Enter and Leave Nested Critical Sections
+ */
+DWORD
+PALAPI
+enterandleave_cs( LPVOID lpParam )
+{
+
+ //Declare Local Variables
+
+ CRITICAL_SECTION lcs;
+ CRITICAL_SECTION lcsNested;
+
+ DWORD dwWaitResult;
+
+ //Intialize Critical Section Structures
+ InitializeCriticalSection ( &lcs);
+ InitializeCriticalSection ( &lcsNested);
+
+
+ //Wait for event to signal to start test
+ dwWaitResult = WaitForSingleObject(g_hEvent,INFINITE);
+ if (WAIT_OBJECT_0 != dwWaitResult)
+ {
+ Fail ("enterandleave_cs: Wait for Single Object (g_hEvent) failed. Failing test.\n"
+ "GetLastError returned %d\n", GetLastError());
+ }
+
+ //Trace("Critical Section Started\n");
+
+ while(TRUE)
+ {
+ EnterCriticalSection(&lcs);
+
+ EnterCriticalSection(&lcsNested);
+
+ incrementCounter();
+
+ LeaveCriticalSection(&lcsNested);
+
+ LeaveCriticalSection(&lcs);
+
+ SwitchToThread();
+ //g_enterleavecsoperation++;
+ }
+
+ //Delete Critical Section Structures
+
+ DeleteCriticalSection(&lcs);
+ DeleteCriticalSection(&lcsNested);
+
+
+ return 0;
+}
+
+
+/*
+ * Allocate and Free Memory
+ */
+DWORD
+PALAPI
+allocateandfree_memory( LPVOID lpParam )
+{
+
+
+ int i;
+ char *textArrPtr[64];
+ DWORD dwWaitResult;
+
+ //Wait for event to signal to start test
+ dwWaitResult = WaitForSingleObject(g_hEvent,INFINITE);
+ if (WAIT_OBJECT_0 != dwWaitResult)
+ {
+ Fail ("allocateandfree_memory: Wait for Single Object (g_hEvent) failed. Failing test.\n"
+ "GetLastError returned %d\n", GetLastError());
+ }
+
+
+ while(TRUE)
+ {
+
+ //do allocate and free operation
+
+ for (i=0;i<64;i++)
+ {
+ textArrPtr[i] = (char*) malloc(BUFSIZE);
+ if (textArrPtr[i] == NULL)
+ {
+ Fail("Insufficient Memory Available, GetLastError is %d \n", GetLastError());
+ testStatus = TEST_FAIL;
+ }
+ }
+
+ for (i=0;i<64;i++)
+ {
+ free(textArrPtr[i]);
+ }
+
+ SwitchToThread();
+ //g_allocatefreeoperation++;
+ }
+
+
+
+
+ return 0;
+}
+
+/*
+ * Do work in a tight loop
+ */
+DWORD
+PALAPI
+doworkintightloop_cs( LPVOID lpParam )
+{
+
+ unsigned int i;
+ DWORD dwWaitResult;
+
+ //Wait for event to signal to start test
+ dwWaitResult = WaitForSingleObject(g_hEvent,INFINITE);
+ if (WAIT_OBJECT_0 != dwWaitResult)
+ {
+ Fail ("doworkintightloop_cs: Wait for Single Object (g_hEvent) failed. Failing test.\n"
+ "GetLastError returned %d\n", GetLastError());
+ }
+
+ i= 0;
+ while (TRUE)
+ {
+
+ if (INT_MAX == i)
+ i =0;
+ i++;
+ //g_doworintightloop++;
+
+ SwitchToThread();
+ }
+
+ return 0;
+}
+
+
+/*
+ * Main Test Case worker thread which will suspend and resume all other worker threads
+ */
+DWORD
+PALAPI
+suspendandresumethreads( LPVOID lpParam )
+{
+
+ unsigned int loopcount = REPEAT_COUNT;
+ int Id=(int)lpParam;
+ unsigned int i,j,k;
+ DWORD dwStart;
+ DWORD dwWaitResult=0;
+ DWORD dwLastError = 0;
+ struct statistics stats;
+ struct statistics* buffer;
+
+
+
+ //Initialize the Statistics Structure
+ stats.relationId = RELATION_ID;
+ stats.processId = USE_PROCESS_COUNT;
+ stats.operationsFailed = 0;
+ stats.operationsPassed = 0;
+ stats.operationsTotal = 0;
+ stats.operationTime = 0;
+
+
+
+ //Wait for event to signal to start test
+ WaitForSingleObject(g_hEvent,INFINITE);
+ if (WAIT_OBJECT_0 != dwWaitResult)
+ {
+ Fail ("suspendandresumethreads: Wait for Single Object (g_hEvent) failed. Failing test.\n"
+ "GetLastError returned %d\n", GetLastError());
+ }
+
+
+ //Capture Start Import
+ dwStart = GetTickCount();
+
+ for(i = 0; i < loopcount; i++)
+ {
+
+ failFlag = false;
+
+ //Suspend Worker Threads
+ for (k=0;k<WORKER_THREAD_MULTIPLIER_COUNT;k++)
+ {
+ for (j=0;j<4;j++)
+ {
+ if (-1 == SuspendThread(hThread[j][k]))
+ {
+ //If the operation indicate failure
+ failFlag = true;
+ }
+ }
+ }
+
+
+ //Resume Worker Threads
+ for (k=0;k<WORKER_THREAD_MULTIPLIER_COUNT;k++)
+ {
+ for (j=0;j<4;j++)
+ {
+
+ //Only suspend if not already in suspended state
+
+ if (-1 == ResumeThread(hThread[j][k]))
+ {
+ //If the operation indicate failure
+ failFlag = true;
+ }
+
+ }
+ }
+
+
+ //Check for Fail Flag. If set increment number of failures
+ // If Fail flag not set then increment number of operations and number of passe
+ if (failFlag == true)
+ {
+ stats.operationsFailed++;
+ }
+ else
+ {
+ stats.operationsPassed +=1;
+
+ }
+ stats.operationsTotal +=1;
+
+ }
+
+ stats.operationTime = GetTickCount() - dwStart;
+
+ /*Trace("\n\n\n\nOperation Time: %d milliseconds\n", stats.operationTime);
+ Trace("Operation Passed: %d\n", stats.operationsPassed);
+ Trace("Operation Total: %d\n", stats.operationsTotal);
+ Trace("Operation Failed: %d\n", stats.operationsFailed);
+ */
+ if(resultBuffer->LogResult(Id, (char *)&stats))
+ {
+ Fail("Error while writing to shared memory, Thread Id is[%d] and Process id is [%d]\n", Id, USE_PROCESS_COUNT);
+ }
+
+ buffer = (struct statistics *)resultBuffer->getResultBuffer(Id);
+ //Trace("\n%d,%d,%d,%lu\n", buffer->operationsFailed, buffer->operationsPassed, buffer->operationsTotal, buffer->operationTime );
+
+
+ return 0;
+}
+
+
+
+int GetParameters( int argc, char **argv)
+{
+
+ if( (argc != 5) || ((argc == 1) && !strcmp(argv[1],"/?"))
+ || !strcmp(argv[1],"/h") || !strcmp(argv[1],"/H"))
+ {
+ Trace("PAL -Composite Thread Suspension Test\n");
+ Trace("Usage:\n");
+ Trace("\t[PROCESS_COUNT] Greater than or Equal to 1 \n");
+ Trace("\t[WORKER_THREAD_MULTIPLIER_COUNT] Greater than or Equal to 1 and Less than or Equal to 64 \n");
+ Trace("\t[REPEAT_COUNT] Greater than or Equal to 1\n");
+ Trace("\t[RELATION_ID [greater than or Equal to 1]\n");
+ return -1;
+ }
+
+// Trace("Args 1 is [%s], Arg 2 is [%s], Arg 3 is [%s]\n", argv[1], argv[2], argv[3]);
+
+ USE_PROCESS_COUNT = atoi(argv[1]);
+ if( USE_PROCESS_COUNT < 0)
+ {
+ Trace("\nPROCESS_COUNT to greater than or equal to 1\n");
+ return -1;
+ }
+
+ WORKER_THREAD_MULTIPLIER_COUNT = atoi(argv[2]);
+ if( WORKER_THREAD_MULTIPLIER_COUNT < 1 || WORKER_THREAD_MULTIPLIER_COUNT > 64)
+ {
+ Trace("\nWORKER_THREAD_MULTIPLIER_COUNT to be greater than or equal to 1 or less than or equal to 64\n");
+ return -1;
+ }
+
+ REPEAT_COUNT = atoi(argv[3]);
+ if( REPEAT_COUNT < 1)
+ {
+ Trace("\nREPEAT_COUNT to greater than or equal to 1\n");
+ return -1;
+ }
+
+ RELATION_ID = atoi(argv[4]);
+ if( RELATION_ID < 1)
+ {
+ Trace("\nRELATION_ID to be greater than or equal to 1\n");
+ return -1;
+ }
+ return 0;
+}
diff --git a/src/pal/tests/palsuite/composite/wfmo/CMakeLists.txt b/src/pal/tests/palsuite/composite/wfmo/CMakeLists.txt
new file mode 100644
index 0000000000..7dbddbc989
--- /dev/null
+++ b/src/pal/tests/palsuite/composite/wfmo/CMakeLists.txt
@@ -0,0 +1,21 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ main.c
+ mutex.c
+)
+
+add_executable(paltest_composite_wfmo
+ ${SOURCES}
+)
+
+add_dependencies(paltest_composite_wfmo coreclrpal)
+
+target_link_libraries(paltest_composite_wfmo
+ pthread
+ rt
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/composite/wfmo/main.c b/src/pal/tests/palsuite/composite/wfmo/main.c
new file mode 100644
index 0000000000..d186aa7b8b
--- /dev/null
+++ b/src/pal/tests/palsuite/composite/wfmo/main.c
@@ -0,0 +1,239 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+** Source Code: main.c and mutex.c
+** main.c creates process and waits for all processes to get over
+** mutex.c creates a mutex and then calls threads which will contend for the mutex
+**
+** This test is for WFMO Test case for Mutex
+** Algorithm
+** o Create PROCESS_COUNT processes.
+** o Main Thread of each process creates OBJECT_TYPE Object
+**
+** Author: ShamitP
+**
+**
+**============================================================
+*/
+
+#include <palsuite.h>
+#include "resulttime.h"
+
+/* Test Input Variables */
+unsigned int PROCESS_COUNT = 3;
+unsigned int THREAD_COUNT = 30;
+unsigned int REPEAT_COUNT = 40;
+unsigned int SLEEP_LENGTH = 4;
+unsigned int RELATION_ID = 1001;
+
+
+
+struct TestStats{
+ DWORD operationTime;
+ unsigned int relationId;
+ unsigned int processCount;
+ unsigned int threadCount;
+ unsigned int repeatCount;
+ char* buildNumber;
+
+};
+
+int GetParameters( int argc, char **argv)
+{
+ if( (argc != 6) || ((argc == 1) && !strcmp(argv[1],"/?"))
+ || !strcmp(argv[1],"/h") || !strcmp(argv[1],"/H"))
+ {
+ printf("PAL -Composite WFMO Test\n");
+ printf("Usage:\n");
+ printf("main\n\t[PROCESS_COUNT [greater than 0] \n");
+ printf("\t[THREAD_COUNT [greater than 0] \n");
+ printf("\t[REPEAT_COUNT [greater than 0]\n");
+ printf("\t[SLEEP_LENGTH [greater than 0]\n");
+ printf("\t[RELATION_ID [greater than 0]\n");
+
+
+
+ return -1;
+ }
+
+ PROCESS_COUNT = atoi(argv[1]);
+ if( (PROCESS_COUNT < 1) || (PROCESS_COUNT > MAXIMUM_WAIT_OBJECTS) )
+ {
+ printf("\nMain Process:Invalid PROCESS_COUNT number, Pass greater than 1 and less than PROCESS_COUNT %d\n", MAXIMUM_WAIT_OBJECTS);
+ return -1;
+ }
+
+ THREAD_COUNT = atoi(argv[2]);
+ if( (THREAD_COUNT < 1) || (THREAD_COUNT > MAXIMUM_WAIT_OBJECTS) )
+ {
+ printf("\nInvalid THREAD_COUNT number, Pass greater than 1 and less than %d\n", MAXIMUM_WAIT_OBJECTS);
+ return -1;
+ }
+
+ REPEAT_COUNT = atoi(argv[3]);
+ if( REPEAT_COUNT < 1)
+ {
+ printf("\nMain Process:Invalid REPEAT_COUNT number, Pass greater than 1\n");
+ return -1;
+ }
+
+ SLEEP_LENGTH = atoi(argv[4]);
+ if( SLEEP_LENGTH < 1)
+ {
+ printf("\nMain Process:Invalid SLEEP_LENGTH number, Pass greater than 1\n");
+ return -1;
+ }
+
+ RELATION_ID = atoi(argv[5]);
+ if( RELATION_ID < 1)
+ {
+ printf("\nMain Process:Invalid RELATION_ID number, Pass greater than 1\n");
+ return -1;
+ }
+
+
+
+ return 0;
+}
+
+ int __cdecl main(INT argc, CHAR **argv)
+{
+ unsigned int i = 0;
+ HANDLE hProcess[MAXIMUM_WAIT_OBJECTS];
+
+ STARTUPINFO si[MAXIMUM_WAIT_OBJECTS];
+ PROCESS_INFORMATION pi[MAXIMUM_WAIT_OBJECTS];
+
+ char lpCommandLine[MAX_PATH] = "";
+
+ int returnCode = 0;
+ DWORD processReturnCode = 0;
+ int testReturnCode = PASS;
+
+ char fileName[MAX_PATH];
+ FILE *pFile = NULL;
+ DWORD dwStartTime;
+ struct TestStats testStats;
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return ( FAIL );
+ }
+
+ if(GetParameters(argc, argv))
+ {
+ Fail("Error in obtaining the parameters\n");
+ }
+
+ /* Register the start time */
+ dwStartTime = GetTickCount();
+ testStats.relationId = 0;
+ testStats.relationId = RELATION_ID;
+ testStats.processCount = PROCESS_COUNT;
+ testStats.threadCount = THREAD_COUNT;
+ testStats.repeatCount = REPEAT_COUNT;
+ testStats.buildNumber = getBuildNumber();
+
+
+
+ _snprintf(fileName, MAX_PATH, "main_wfmo_%d_.txt",testStats.relationId);
+ pFile = fopen(fileName, "w+");
+ if(pFile == NULL)
+ {
+ Fail("Error in opening main file for write\n");
+ }
+
+ for( i = 0; i < PROCESS_COUNT; i++ )
+ {
+
+ ZeroMemory( lpCommandLine, MAX_PATH );
+ if ( _snprintf( lpCommandLine, MAX_PATH-1, "mutex %d %d %d %d %d", i, THREAD_COUNT, REPEAT_COUNT, SLEEP_LENGTH, RELATION_ID) < 0 )
+ {
+ Trace ("Error: Insufficient commandline string length for for iteration [%d]\n", i);
+ }
+
+ /* Zero the data structure space */
+ ZeroMemory ( &pi[i], sizeof(pi[i]) );
+ ZeroMemory ( &si[i], sizeof(si[i]) );
+
+ /* Set the process flags and standard io handles */
+ si[i].cb = sizeof(si[i]);
+
+ //Create Process
+ if(!CreateProcess( NULL, /* lpApplicationName*/
+ lpCommandLine, /* lpCommandLine */
+ NULL, /* lpProcessAttributes */
+ NULL, /* lpThreadAttributes */
+ TRUE, /* bInheritHandles */
+ 0, /* dwCreationFlags, */
+ NULL, /* lpEnvironment */
+ NULL, /* pCurrentDirectory */
+ &si[i], /* lpStartupInfo */
+ &pi[i] /* lpProcessInformation */
+ ))
+ {
+ Fail("Process Not created for [%d], the error code is [%d]\n", i, GetLastError());
+ }
+ else
+ {
+ hProcess[i] = pi[i].hProcess;
+ // Trace("Process created for [%d]\n", i);
+ }
+
+ }
+
+ returnCode = WaitForMultipleObjects( PROCESS_COUNT, hProcess, TRUE, INFINITE);
+ if( WAIT_OBJECT_0 != returnCode )
+ {
+ Trace("Wait for Object(s) @ Main thread for %d processes returned %d, and GetLastError value is %d\n", PROCESS_COUNT, returnCode, GetLastError());
+ }
+
+ for( i = 0; i < PROCESS_COUNT; i++ )
+ {
+ /* check the exit code from the process */
+ if( ! GetExitCodeProcess( pi[i].hProcess, &processReturnCode ) )
+ {
+ Trace( "GetExitCodeProcess call failed for iteration %d with error code %u\n",
+ i, GetLastError() );
+
+ testReturnCode = FAIL;
+ }
+
+ if(processReturnCode == FAIL)
+ {
+ Trace( "Process [%d] failed and returned FAIL\n", i);
+ testReturnCode = FAIL;
+ }
+
+ if(!CloseHandle(pi[i].hThread))
+ {
+ Trace("Error:%d: CloseHandle failed for Process [%d] hThread\n", GetLastError(), i);
+ }
+
+ if(!CloseHandle(pi[i].hProcess) )
+ {
+ Trace("Error:%d: CloseHandle failed for Process [%d] hProcess\n", GetLastError(), i);
+ }
+ }
+
+ testStats.operationTime = GetTimeDiff(dwStartTime);
+ fprintf(pFile, "%d,%d,%d,%d,%d,%s\n", testStats.operationTime, testStats.relationId, testStats.processCount, testStats.threadCount, testStats.repeatCount, testStats.buildNumber);
+ if(fclose(pFile))
+ {
+ Trace("Error: fclose failed for pFile\n");
+ testReturnCode = FAIL;
+ }
+
+ if( testReturnCode == PASS)
+ {
+ Trace("Test Passed\n");
+ }
+ else
+ {
+ Trace("Test Failed\n");
+ }
+ PAL_Terminate();
+ return testReturnCode;
+}
diff --git a/src/pal/tests/palsuite/composite/wfmo/mutex.c b/src/pal/tests/palsuite/composite/wfmo/mutex.c
new file mode 100644
index 0000000000..c8ed01426c
--- /dev/null
+++ b/src/pal/tests/palsuite/composite/wfmo/mutex.c
@@ -0,0 +1,365 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**Source Code: main.c and mutex.c
+** main.c creates process and waits for all processes to get over
+** mutex.c creates a mutex and then calls threads which will
+** contend for the mutex
+**
+** This test is for WFMO Test case for Mutex
+** Algorithm
+** o Create PROCESS_COUNT processes.
+** o Main Thread of each process creates OBJECT_TYPE Object
+**
+** Author: ShamitP
+**
+**
+**============================================================
+*/
+
+#include <palsuite.h>
+#include "resultbuffer.h"
+#include "resulttime.h"
+
+/* Test Input Variables */
+unsigned int USE_PROCESS_COUNT = 0;
+unsigned int THREAD_COUNT = 0;
+unsigned int REPEAT_COUNT = 0;
+unsigned int SLEEP_LENGTH = 0;
+unsigned int RELATION_ID = 1001;
+
+
+/* Capture statistics at per thread basis */
+struct statistics{
+ unsigned int processId;
+ unsigned int operationsFailed;
+ unsigned int operationsPassed;
+ unsigned int operationsTotal;
+ DWORD operationTime;
+ unsigned int relationId;
+
+};
+
+struct ProcessStats{
+ unsigned int processId;
+ DWORD operationTime;
+ unsigned int relationId;
+};
+
+/* Handle to signal threads to start the tests */
+HANDLE StartTestsEvHandle = NULL;
+/* Handle to mutex which will be contended by threads */
+HANDLE hMutexHandle = NULL;
+/* Results Buffer */
+ResultBuffer *resultBuffer = NULL;
+
+int testStatus;
+
+void PALAPI Run_Thread(LPVOID lpParam);
+
+int GetParameters( int argc, char **argv)
+{
+ if( (argc != 6) || ((argc == 1) && !strcmp(argv[1],"/?"))
+ || !strcmp(argv[1],"/h") || !strcmp(argv[1],"/H"))
+ {
+ printf("PAL -Composite WFMO Test\n");
+ printf("Usage:\n");
+ printf("mutex\n\t[USE_PROCESS_COUNT [greater than 0] \n");
+ printf("\t[THREAD_COUNT [greater than 0] \n");
+ printf("\t[REPEAT_COUNT [greater than 0]\n");
+ printf("\t[SLEEP_LENGTH [greater than 0]\n");
+ printf("\t[RELATION_ID [greater than 0]\n");
+
+
+ return -1;
+ }
+
+ // Trace("Args 1 is [%s], Arg 2 is [%s], Arg 3 is [%s]\n", argv[1], argv[2], argv[3]);
+
+ USE_PROCESS_COUNT = atoi(argv[1]);
+ if( USE_PROCESS_COUNT < 0)
+ {
+ printf("\nInvalid USE_PROCESS_COUNT number, Pass greater than 1\n");
+ return -1;
+ }
+
+ THREAD_COUNT = atoi(argv[2]);
+ if( (THREAD_COUNT < 1) || (THREAD_COUNT > MAXIMUM_WAIT_OBJECTS) )
+ {
+ printf("\nInvalid THREAD_COUNT number, Pass greater than 1 and less than %d\n", MAXIMUM_WAIT_OBJECTS);
+ return -1;
+ }
+
+ REPEAT_COUNT = atoi(argv[3]);
+ if( REPEAT_COUNT < 1)
+ {
+ printf("\nInvalid REPEAT_COUNT number, Pass greater than 1\n");
+ return -1;
+ }
+
+ SLEEP_LENGTH = atoi(argv[4]);
+ if( SLEEP_LENGTH < 1)
+ {
+ printf("\nMain Process:Invalid SLEEP_LENGTH number, Pass greater than 1\n");
+ return -1;
+ }
+
+ RELATION_ID = atoi(argv[5]);
+ if( RELATION_ID < 1)
+ {
+ printf("\nMain Process:Invalid RELATION_ID number, Pass greater than 1\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+ int __cdecl main(INT argc, CHAR **argv)
+{
+ unsigned int i = 0;
+ HANDLE hThread[MAXIMUM_WAIT_OBJECTS];
+ DWORD threadId[MAXIMUM_WAIT_OBJECTS];
+ int returnCode = 0;
+
+ DWORD dwParam = 0;
+
+ /* Variables to capture the file name and the file pointer at thread level*/
+ char fileName[MAX_PATH];
+ FILE *pFile = NULL;
+ struct statistics* buffer = NULL;
+ int statisticsSize = 0;
+
+ /* Variables to capture the file name and the file pointer at process level*/
+ char processFileName[MAX_PATH];
+ FILE *pProcessFile = NULL;
+ struct ProcessStats processStats;
+ DWORD dwStartTime;
+
+ testStatus = PASS;
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return ( FAIL );
+ }
+
+ if(GetParameters(argc, argv))
+ {
+ Fail("Error in obtaining the parameters\n");
+ }
+// Trace("Process created, value of process count is [%d] and no. of threads is [%d]\n", USE_PROCESS_COUNT, THREAD_COUNT);
+
+ /* Register the start time */
+ dwStartTime = GetTickCount();
+ processStats.relationId = RELATION_ID;
+ processStats.processId = USE_PROCESS_COUNT;
+
+ _snprintf(processFileName, MAX_PATH, "%d_process_wfmo_%d_.txt", USE_PROCESS_COUNT, RELATION_ID);
+ pProcessFile = fopen(processFileName, "w+");
+ if(pProcessFile == NULL)
+ {
+ Fail("Error:%d: in opening Process File for write for process [%d]\n", GetLastError(), USE_PROCESS_COUNT);
+ }
+
+ statisticsSize = sizeof(struct statistics);
+
+ _snprintf(fileName, MAX_PATH, "%d_thread_wfmo_%d_.txt", USE_PROCESS_COUNT, RELATION_ID);
+ pFile = fopen(fileName, "w+");
+ if(pFile == NULL)
+ {
+ Fail("Error in opening file for write for process [%d], error [%d]\n", USE_PROCESS_COUNT, GetLastError());
+ }
+ // For each thread we will log operations failed (int), passed (int), total (int)
+ // and number of ticks (DWORD) for the operations
+ resultBuffer = new ResultBuffer( THREAD_COUNT, statisticsSize);
+
+ StartTestsEvHandle = CreateEvent( NULL, /* lpEventAttributes*/
+ TRUE, /* bManualReset */
+ FALSE, /* bInitialState */
+ NULL); /* name of Event */
+
+ if( StartTestsEvHandle == NULL )
+ {
+ Fail("Error:%d: Unexpected failure "
+ "to create start tests Event for process count %d\n", GetLastError(), USE_PROCESS_COUNT );
+
+ }
+
+ /* Create StartTest Event */
+ hMutexHandle = CreateMutex(
+ NULL,
+ FALSE, /* bInitialOwner, owns initially */
+ NULL
+ );
+
+ if( hMutexHandle == NULL)
+ {
+ Fail("Unable to create Mutex handle for process id [%d], returned error [%d]\n", i, GetLastError());
+ }
+
+ /* We already assume that the mutex was created previously*/
+ for( i = 0; i < THREAD_COUNT; i++ )
+ {
+ dwParam = (int) i;
+ //Create thread
+ hThread[i] = CreateThread(
+ NULL, /* no security attributes */
+ 0, /* use default stack size */
+ (LPTHREAD_START_ROUTINE)Run_Thread,/* thread function */
+ (LPVOID)dwParam, /* argument to thread function */
+ 0, /* use default creation flags */
+ &threadId[i] /* returns the thread identifier*/
+ );
+
+ if(hThread[i] == NULL)
+ {
+ Fail("Create Thread failed for %d process, and GetLastError value is %d\n", USE_PROCESS_COUNT, GetLastError());
+ }
+
+ }
+
+ if (!SetEvent(StartTestsEvHandle))
+ {
+ Fail("Set Event for Start Tests failed for %d process, and GetLastError value is %d\n", USE_PROCESS_COUNT, GetLastError());
+ }
+ /* Test running */
+
+ if( THREAD_COUNT != 1 )
+ {
+ returnCode = WaitForMultipleObjects(THREAD_COUNT, hThread, TRUE, INFINITE);
+ }
+ else
+ {
+ returnCode = WaitForSingleObject(hThread[0], INFINITE);
+ }
+
+ if( WAIT_OBJECT_0 != returnCode )
+ {
+ Trace("Wait for Object(s) for %d process returned %d, and GetLastError value is %d\n", USE_PROCESS_COUNT, returnCode, GetLastError());
+ testStatus = FAIL;
+ }
+
+ processStats.operationTime = GetTimeDiff(dwStartTime);
+
+ /* Write to a file*/
+ if(pFile!= NULL)
+ {
+ for( i = 0; i < THREAD_COUNT; i++ )
+ {
+ buffer = (struct statistics *)resultBuffer->getResultBuffer(i);
+ returnCode = fprintf(pFile, "%d,%d,%d,%d,%lu,%d\n", buffer->processId, buffer->operationsFailed, buffer->operationsPassed, buffer->operationsTotal, buffer->operationTime, buffer->relationId );
+ //Trace("Iteration %d over\n", i);
+
+ }
+ }
+ if(fclose(pFile))
+ {
+ Trace("Error: fclose failed for pFile at Process %d\n", USE_PROCESS_COUNT);
+ testStatus = FAIL;
+ }
+
+ fprintf(pProcessFile, "%d,%d,%d\n", USE_PROCESS_COUNT, processStats.operationTime, processStats.relationId );
+ if(fclose(pProcessFile))
+ {
+ Trace("Error: fclose failed for pProcessFile at Process %d\n", USE_PROCESS_COUNT);
+ testStatus = FAIL;
+ }
+
+ /* Logging for the test case over, clean up the handles */
+ // Trace("Test Process %d done\n", USE_PROCESS_COUNT);
+ //Trace("Contents of the buffer are [%s]\n", resultBuffer->getResultBuffer());
+ for( i = 0; i < THREAD_COUNT; i++ )
+ {
+ if(!CloseHandle(hThread[i]) )
+ {
+ Trace("Error:%d: CloseHandle failed for Process [%d] hThread[%d]\n", GetLastError(), USE_PROCESS_COUNT, i);
+ testStatus = FAIL;
+ }
+ }
+
+ if(!CloseHandle(StartTestsEvHandle))
+ {
+ Trace("Error:%d: CloseHandle failed for Process [%d] StartTestsEvHandle\n", GetLastError(), USE_PROCESS_COUNT);
+ testStatus = FAIL;
+ }
+
+ PAL_Terminate();
+ return testStatus;
+}
+
+void PALAPI Run_Thread (LPVOID lpParam)
+{
+ unsigned int i = 0;
+ struct statistics stats;
+
+ DWORD dwWaitResult;
+ DWORD dwStartTime;
+
+ stats.relationId = RELATION_ID;
+ stats.processId = USE_PROCESS_COUNT;
+ stats.operationsFailed = 0;
+ stats.operationsPassed = 0;
+ stats.operationsTotal = 0;
+ stats.operationTime = 0;
+
+ int Id=(int)lpParam;
+
+ dwWaitResult = WaitForSingleObject(
+ StartTestsEvHandle, // handle to mutex
+ INFINITE);
+
+ if(dwWaitResult != WAIT_OBJECT_0)
+ {
+ Trace("Error:%d: while waiting for StartTest Event@ thread %d\n", GetLastError(), Id);
+ testStatus = FAIL;
+ }
+
+ /* Register the start time */
+ dwStartTime = GetTickCount();
+
+ /* Run the tests repeat count times */
+ for( i = 0; i < REPEAT_COUNT; i++ )
+ {
+ dwWaitResult = WaitForSingleObject(
+ hMutexHandle, // handle to mutex
+ INFINITE);
+
+ if(dwWaitResult != WAIT_OBJECT_0)
+ {
+ Trace("Error:%d: while waiting for onject @ thread %d, # iter %d\n", GetLastError(), Id, i);
+ stats.operationsFailed += 1;
+ stats.operationsTotal += 1;
+ testStatus = FAIL;
+ continue;
+ }
+
+ Sleep(SLEEP_LENGTH);
+
+ if (!ReleaseMutex(hMutexHandle))
+ {
+ // Deal with error.
+ Trace("Error:%d: while releasing mutex @ thread %d # iter %d\n", GetLastError(), Id, i);
+ stats.operationsFailed += 1;
+ stats.operationsTotal += 1;
+ // do we need to have while true loop to attempt to release mutex...?
+ testStatus = FAIL;
+ continue;
+ }
+
+ stats.operationsTotal += 1;
+ stats.operationsPassed += 1;
+
+// Trace("Successs while releasing mutex @ iteration %d -> thread %d -> Process %d\n", i, Id, USE_PROCESS_COUNT);
+
+ }
+
+ stats.operationTime = GetTimeDiff(dwStartTime);
+ // Trace("Operation Time %lu, Process Count [%d], ThreadCount[%d]\n", stats.operationTime, USE_PROCESS_COUNT, Id);
+
+ if(resultBuffer->LogResult(Id, (char *)&stats))
+ {
+ Fail("Error:%d: while writing to shared memory, Thread Id is[%d] and Process id is [%d]\n", GetLastError(), Id, USE_PROCESS_COUNT);
+ }
+ // Trace("Contents of the buffer are after thread [%d]\n", Id);
+}
diff --git a/src/pal/tests/palsuite/composite/wfmo/readme.txt b/src/pal/tests/palsuite/composite/wfmo/readme.txt
new file mode 100644
index 0000000000..6be55d8ff4
--- /dev/null
+++ b/src/pal/tests/palsuite/composite/wfmo/readme.txt
@@ -0,0 +1,22 @@
+To compile:
+
+1) create a dat file (say wfmo.dat) with contents:
+PAL,Composite,palsuite\composite\wfmo,wfmo=main.c mutex.c,<SUPPORTEXE>,<TESTLANGCPP>,<COMPILEONLY>
+
+2) perl rrunmod.pl -r wfmo.dat
+
+
+To execute:
+main [PROCESS_COUNT] [THREAD_COUNT] [REPEAT_COUNT] [SLEEP_LENGTH]
+
+Output:
+The performance numbers will be in <process_logical_id>_wfmo.txt
+(will be at palsuite\composite\wfmo\obj[r|c|d] directory if u use rrunmod.pl)
+
+So if process_count is 3, you will have files 0_wfmo.txt, 1_wfmo.txt and so on…
+
+For each process txt file created,
+each row represents a thread data (process id, number of failures, number of pass, total number of repeated operations and an integer that will be used to identify a run
+(currently zero)).
+
+
diff --git a/src/pal/tests/palsuite/debug_api/CMakeLists.txt b/src/pal/tests/palsuite/debug_api/CMakeLists.txt
new file mode 100644
index 0000000000..a568131d3f
--- /dev/null
+++ b/src/pal/tests/palsuite/debug_api/CMakeLists.txt
@@ -0,0 +1,9 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+# TODO: make these tests compile
+# add_subdirectory(DebugBreak)
+# add_subdirectory(WriteProcessMemory)
+
+add_subdirectory(OutputDebugStringA)
+add_subdirectory(OutputDebugStringW)
+
diff --git a/src/pal/tests/palsuite/debug_api/DebugBreak/CMakeLists.txt b/src/pal/tests/palsuite/debug_api/DebugBreak/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/debug_api/DebugBreak/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/debug_api/DebugBreak/test1/CMakeLists.txt b/src/pal/tests/palsuite/debug_api/DebugBreak/test1/CMakeLists.txt
new file mode 100644
index 0000000000..db66cbe1d0
--- /dev/null
+++ b/src/pal/tests/palsuite/debug_api/DebugBreak/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_debugbreak_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_debugbreak_test1 coreclrpal)
+
+target_link_libraries(paltest_debugbreak_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/debug_api/DebugBreak/test1/test1.c b/src/pal/tests/palsuite/debug_api/DebugBreak/test1/test1.c
new file mode 100644
index 0000000000..2b10b9ad9d
--- /dev/null
+++ b/src/pal/tests/palsuite/debug_api/DebugBreak/test1/test1.c
@@ -0,0 +1,47 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: test1.c
+**
+** Purpose: Tests that DebugBreak works in the grossest fashion.
+**
+**
+**============================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ BOOL bTry = FALSE;
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ PAL_TRY
+ {
+ DebugBreak();
+ if (!bTry)
+ {
+ Fail("DebugBreak: Continued in Try block.\n");
+ }
+ }
+ PAL_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ bTry = TRUE;
+ }
+ PAL_ENDTRY;
+
+ if (!bTry)
+ {
+ Fail("DebugBreak: Did not reach the exception block.\n");
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/debug_api/DebugBreak/test1/testinfo.dat b/src/pal/tests/palsuite/debug_api/DebugBreak/test1/testinfo.dat
new file mode 100644
index 0000000000..25c480eccb
--- /dev/null
+++ b/src/pal/tests/palsuite/debug_api/DebugBreak/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Debug
+Function = DebugBreak
+Name = DebugBreak test #1
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Tests that DebugBreak "works". This will require case by case
+= manual interpretation.
diff --git a/src/pal/tests/palsuite/debug_api/OutputDebugStringA/CMakeLists.txt b/src/pal/tests/palsuite/debug_api/OutputDebugStringA/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/debug_api/OutputDebugStringA/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/debug_api/OutputDebugStringA/test1/CMakeLists.txt b/src/pal/tests/palsuite/debug_api/OutputDebugStringA/test1/CMakeLists.txt
new file mode 100644
index 0000000000..5bc7fdb6e9
--- /dev/null
+++ b/src/pal/tests/palsuite/debug_api/OutputDebugStringA/test1/CMakeLists.txt
@@ -0,0 +1,38 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(TESTSOURCES
+ test1.c
+)
+
+add_executable(paltest_outputdebugstringa_test1
+ ${TESTSOURCES}
+)
+
+add_dependencies(paltest_outputdebugstringa_test1 coreclrpal)
+
+target_link_libraries(paltest_outputdebugstringa_test1
+ pthread
+ m
+ coreclrpal
+)
+
+
+set(HELPERSOURCES
+ helper.c
+)
+
+add_executable(paltest_outputdebugstringa_test1_helper
+ ${HELPERSOURCES}
+)
+
+add_dependencies(paltest_outputdebugstringa_test1_helper coreclrpal)
+
+target_link_libraries(paltest_outputdebugstringa_test1_helper
+ pthread
+ m
+ coreclrpal
+)
+
+
diff --git a/src/pal/tests/palsuite/debug_api/OutputDebugStringA/test1/helper.c b/src/pal/tests/palsuite/debug_api/OutputDebugStringA/test1/helper.c
new file mode 100644
index 0000000000..90073dfedd
--- /dev/null
+++ b/src/pal/tests/palsuite/debug_api/OutputDebugStringA/test1/helper.c
@@ -0,0 +1,35 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: helper.c
+**
+** Purpose: Intended to be the child process of a debugger. Calls
+** OutputDebugStringA once with a normal string, once with an empty
+** string
+**
+**
+**============================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ OutputDebugStringA("Foo!\n");
+
+ OutputDebugStringA("");
+
+ /* give a chance to the debugger process to read the debug string before
+ exiting */
+ Sleep(1000);
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/debug_api/OutputDebugStringA/test1/test1.c b/src/pal/tests/palsuite/debug_api/OutputDebugStringA/test1/test1.c
new file mode 100644
index 0000000000..080c6ac53e
--- /dev/null
+++ b/src/pal/tests/palsuite/debug_api/OutputDebugStringA/test1/test1.c
@@ -0,0 +1,94 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: test1.c
+**
+** Purpose: Debugs the helper application. Checks that certain events, in
+** particular the OUTPUT_DEBUG_STRING_EVENT, is generated correctly
+** and gives the correct values.
+**
+**
+**============================================================*/
+
+#include <palsuite.h>
+
+const int DELAY_MS = 2000;
+
+struct OutputCheck
+{
+ DWORD ExpectedEventCode;
+ DWORD ExpectedUnicode;
+ char *ExpectedStr;
+};
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ PROCESS_INFORMATION pi;
+ STARTUPINFO si;
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ ZeroMemory( &si, sizeof(si) );
+ si.cb = sizeof(si);
+ ZeroMemory( &pi, sizeof(pi) );
+
+ /* Create a new process. This is the process to be Debugged */
+ if(!CreateProcess( NULL, "helper", NULL, NULL,
+ FALSE, 0, NULL, NULL, &si, &pi))
+ {
+ Fail("ERROR: CreateProcess failed to load executable 'helper'. "
+ "GetLastError() returned %d.\n",GetLastError());
+ }
+
+ /* This is the main loop. It exits when the process which is being
+ debugged is finished executing.
+ */
+
+ while(1)
+ {
+ DWORD dwRet = 0;
+ dwRet = WaitForSingleObject(pi.hProcess,
+ DELAY_MS /* Wait for 2 seconds max*/
+ );
+
+ if (dwRet != WAIT_OBJECT_0)
+ {
+ Trace("WaitForSingleObjectTest:WaitForSingleObject "
+ "failed (%x) after waiting %d seconds for the helper\n",
+ GetLastError(), DELAY_MS / 1000);
+ }
+ else
+ {
+ DWORD dwExitCode;
+
+ /* check the exit code from the process */
+ if( ! GetExitCodeProcess( pi.hProcess, &dwExitCode ) )
+ {
+ DWORD dwError;
+
+ dwError = GetLastError();
+ CloseHandle ( pi.hProcess );
+ CloseHandle ( pi.hThread );
+ Fail( "GetExitCodeProcess call failed with error code %d\n",
+ dwError );
+ }
+
+ if(dwExitCode != STILL_ACTIVE) {
+ CloseHandle(pi.hThread);
+ CloseHandle(pi.hProcess);
+ break;
+ }
+ Trace("still executing %d..\n", dwExitCode);
+ }
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/debug_api/OutputDebugStringA/test1/testinfo.dat b/src/pal/tests/palsuite/debug_api/OutputDebugStringA/test1/testinfo.dat
new file mode 100644
index 0000000000..d49e9048d1
--- /dev/null
+++ b/src/pal/tests/palsuite/debug_api/OutputDebugStringA/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Debug
+Function = OutputDebugStringA
+Name = OutputDebugStringA test #1
+TYPE = DEFAULT
+EXE1 = test1
+EXE2 = helper
+Description
+=Tests that OutputDebugString generates the correct debugging event behaviour.
diff --git a/src/pal/tests/palsuite/debug_api/OutputDebugStringW/CMakeLists.txt b/src/pal/tests/palsuite/debug_api/OutputDebugStringW/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/debug_api/OutputDebugStringW/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/debug_api/OutputDebugStringW/test1/CMakeLists.txt b/src/pal/tests/palsuite/debug_api/OutputDebugStringW/test1/CMakeLists.txt
new file mode 100644
index 0000000000..9202baeaef
--- /dev/null
+++ b/src/pal/tests/palsuite/debug_api/OutputDebugStringW/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_outputdebugstringw_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_outputdebugstringw_test1 coreclrpal)
+
+target_link_libraries(paltest_outputdebugstringw_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/debug_api/OutputDebugStringW/test1/test1.c b/src/pal/tests/palsuite/debug_api/OutputDebugStringW/test1/test1.c
new file mode 100644
index 0000000000..88b55427bc
--- /dev/null
+++ b/src/pal/tests/palsuite/debug_api/OutputDebugStringW/test1/test1.c
@@ -0,0 +1,41 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: test1.c
+**
+** Purpose: Intended to be the child process of a debugger. Calls
+** OutputDebugStringW once with a normal string, once with an empty
+** string
+**
+**
+**============================================================*/
+
+#define UNICODE
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ WCHAR *str1;
+ WCHAR *str2;
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ str1 = convert("Foo!");
+ str2 = convert("");
+
+ OutputDebugStringW(str1);
+
+ OutputDebugStringW(str2);
+
+ free(str1);
+ free(str2);
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/debug_api/OutputDebugStringW/test1/testinfo.dat b/src/pal/tests/palsuite/debug_api/OutputDebugStringW/test1/testinfo.dat
new file mode 100644
index 0000000000..d6bc4ac5a1
--- /dev/null
+++ b/src/pal/tests/palsuite/debug_api/OutputDebugStringW/test1/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Debug
+Function = OutputDebugStringW
+Name = OutputDebugStringW test #1
+TYPE = DEFAULT
+EXE1 = test1
+Description
+=Tests that OutputDebugString generates the correct debugging event behaviour.
diff --git a/src/pal/tests/palsuite/debug_api/WriteProcessMemory/CMakeLists.txt b/src/pal/tests/palsuite/debug_api/WriteProcessMemory/CMakeLists.txt
new file mode 100644
index 0000000000..078b55691f
--- /dev/null
+++ b/src/pal/tests/palsuite/debug_api/WriteProcessMemory/CMakeLists.txt
@@ -0,0 +1,6 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test3)
+add_subdirectory(test4)
+
diff --git a/src/pal/tests/palsuite/debug_api/WriteProcessMemory/test1/CMakeLists.txt b/src/pal/tests/palsuite/debug_api/WriteProcessMemory/test1/CMakeLists.txt
new file mode 100644
index 0000000000..39130aac1c
--- /dev/null
+++ b/src/pal/tests/palsuite/debug_api/WriteProcessMemory/test1/CMakeLists.txt
@@ -0,0 +1,36 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(TESTSOURCES
+ test1.c
+)
+
+add_executable(paltest_writeprocessmemory_test1
+ ${TESTSOURCES}
+)
+
+add_dependencies(paltest_writeprocessmemory_test1 coreclrpal)
+
+target_link_libraries(paltest_writeprocessmemory_test1
+ pthread
+ m
+ coreclrpal
+)
+
+
+set(HELPERSOURCES
+ helper.c
+)
+
+add_executable(paltest_writeprocessmemory_test1_helper
+ ${HELPERSOURCES}
+)
+
+add_dependencies(paltest_writeprocessmemory_test1_helper coreclrpal)
+
+target_link_libraries(paltest_writeprocessmemory_test1_helper
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/debug_api/WriteProcessMemory/test1/commonconsts.h b/src/pal/tests/palsuite/debug_api/WriteProcessMemory/test1/commonconsts.h
new file mode 100644
index 0000000000..eb7d511534
--- /dev/null
+++ b/src/pal/tests/palsuite/debug_api/WriteProcessMemory/test1/commonconsts.h
@@ -0,0 +1,46 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: commonconsts.h
+**
+**
+**============================================================*/
+
+#ifndef _COMMONCONSTS_H_
+#define _COMMONCONSTS_H_
+
+#include <pal.h>
+
+const int TIMEOUT = 40000;
+
+const WCHAR szcToHelperEvName[] = { 'T', 'o', '\0' };
+const WCHAR szcFromHelperEvName[] = { 'F', 'r', 'o', 'm', '\0' };
+
+const char initialValue = '-';
+const char nextValue = '|';
+const char guardValue = '*';
+const char *commsFileName = "AddrNLen.dat";
+
+/* PEDANTIC and PEDANTIC0 is a helper macro that just grumps about any
+ * zero return codes in a generic way. with little typing */
+#define PEDANTIC(function, parameters) \
+{ \
+ if (! (function parameters) ) \
+ { \
+ Trace("%s: NonFatal failure of %s%s for reasons %u and %u\n", \
+ __FILE__, #function, #parameters, GetLastError(), errno); \
+ } \
+}
+#define PEDANTIC1(function, parameters) \
+{ \
+ if ( (function parameters) ) \
+ { \
+ Trace("%s: NonFatal failure of %s%s for reasons %u and %u\n", \
+ __FILE__, #function, #parameters, GetLastError(), errno); \
+ } \
+}
+
+#endif
diff --git a/src/pal/tests/palsuite/debug_api/WriteProcessMemory/test1/helper.c b/src/pal/tests/palsuite/debug_api/WriteProcessMemory/test1/helper.c
new file mode 100644
index 0000000000..1a7318969c
--- /dev/null
+++ b/src/pal/tests/palsuite/debug_api/WriteProcessMemory/test1/helper.c
@@ -0,0 +1,243 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: helper.c
+**
+** Purpose: This helper process sets up a several blocks of memory,
+** then uses a file to tell its parent process where that memory is
+** So it can do a WriteProcessMemory on it. When the parent process is done
+** we check here that it was written properly.
+**
+**
+**============================================================*/
+
+#include "commonconsts.h"
+
+#include <palsuite.h>
+
+struct allhandles_t
+{
+ HANDLE hEvToHelper;
+ HANDLE hEvFromHelper;
+ char *valuesFileName;
+};
+
+
+/* function: wpmDoIt
+ *
+ * This is a general WriteProcessMemory testing function that sets up
+ * the RAM pointed to and tells the companion process on the other end
+ * of the handles in 'Comms' to attempt to alter 'lenDest' bytes at
+ * '*pDest'.
+ *
+ * '*pBuffer'[0..'lenBuffer'] is expected to be a guard region
+ * surrounding the '*pDest'[0..'lenDest'] region so that this function
+ * can verify that only the proper bytes were altered.
+ */
+
+int wpmDoIt(struct allhandles_t Comms,
+ char * pBuffer, unsigned int lenBuffer,
+ char * pDest, unsigned int lenDest,
+ const char* storageDescription)
+{
+ char *pCurr;
+ FILE *commsFile;
+ DWORD dwRet;
+
+ if (pBuffer > pDest || lenDest > lenBuffer)
+ {
+ Trace("WriteProcessMemory::DoIt() test implementation: "
+ "(pBuffer > pDest || lenDest > lenBuffer)\n");
+ return FALSE;
+ }
+
+ /* set up the storage */
+ memset(pBuffer, guardValue, lenBuffer);
+ memset(pDest, initialValue, lenDest);
+
+ /* tell the parent what RAM to adjust */
+ if(!(commsFile = fopen(Comms.valuesFileName, "w")))
+ {
+ Trace("WriteProcessMemory: fopen of '%S' failed (%u). \n",
+ Comms.valuesFileName, GetLastError());
+ return FALSE;
+ }
+ if (!fprintf(commsFile, "%u %u '%s'\n",
+ pDest, lenDest, storageDescription))
+ {
+ Trace("WriteProcessMemory: fprintf to '%S' failed (%u). \n",
+ Comms.valuesFileName, GetLastError());
+ return FALSE;
+ }
+ PEDANTIC1(fclose, (commsFile));
+
+ /* Tell the parent the data is ready for it to adjust */
+ PEDANTIC(ResetEvent, (Comms.hEvToHelper));
+ PEDANTIC(SetEvent, (Comms.hEvFromHelper));
+
+ dwRet = WaitForSingleObject(Comms.hEvToHelper, TIMEOUT); /* parent is done */
+ if (dwRet != WAIT_OBJECT_0)
+ {
+ Trace("helper WaitForSingleObjectTest: WaitForSingleObject "
+ "failed (%u)\n", GetLastError());
+ return FALSE;
+ }
+
+ /* check the stuff that SHOULD have changed */
+ for (pCurr = pDest; pCurr < (pDest + lenDest); pCurr++)
+ {
+ if ( *pCurr != nextValue)
+ {
+ Trace("When testing '%s': alteration test failed "
+ "at %u offset %u. Found '%c' instead of '%c'\n.",
+ storageDescription, pDest, pCurr - pDest, *pCurr, nextValue);
+ Trace(" 'Altered' string: '%.*s'\n",lenBuffer, pBuffer);
+ return FALSE;
+ }
+ }
+ /* check the stuff that should NOT have changed */
+ for (pCurr = pBuffer; pCurr < pDest; pCurr++ )
+ {
+ if ( *pCurr != guardValue)
+ {
+ Trace("When testing '%s': leading guard zone test failed "
+ "at %u offset %u. Found '%c' instead of '%c'\n.",
+ storageDescription, pDest, pCurr - pBuffer, *pCurr, guardValue);
+ Trace(" 'Altered' string: '%.*s'\n",lenBuffer, pBuffer);
+ return FALSE;
+ }
+ }
+ for (pCurr = pDest + lenDest; pCurr < (pBuffer + lenBuffer); pCurr++ )
+ {
+ if ( *pCurr != guardValue)
+ {
+ Trace("When testing '%s': trailing guard zone test failed "
+ "at %u offset %u. Found '%c' instead of '%c'\n.",
+ storageDescription, pDest + lenDest, pCurr - pBuffer, *pCurr, guardValue);
+ Trace(" 'Altered' string: '%.*s'\n",lenBuffer, pBuffer);
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ BOOL success = TRUE; /* assume success */
+ struct allhandles_t Comms = {0,0,0} ;
+
+ /* variables to track storage to alter */
+ char *pTarget = NULL;
+ unsigned int sizeTarget;
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /* hook up with the events created by the parent */
+ Comms.hEvToHelper = OpenEventW(EVENT_ALL_ACCESS, 0, szcToHelperEvName);
+ if (!Comms.hEvToHelper)
+ {
+ Fail("WriteProcessMemory: OpenEvent of '%S' failed (%u). "
+ "(the event should already exist!)\n",
+ szcToHelperEvName, GetLastError());
+ }
+ Comms.hEvFromHelper = OpenEventW(EVENT_ALL_ACCESS, 0, szcFromHelperEvName);
+ if (!Comms.hEvToHelper)
+ {
+ Trace("WriteProcessMemory: OpenEvent of '%S' failed (%u). "
+ "(the event should already exist!)\n",
+ szcFromHelperEvName, GetLastError());
+ success = FALSE;
+ goto EXIT;
+ }
+ Comms.valuesFileName = argv[1];
+
+ {
+ char autoAllocatedOnStack[51];
+
+ /* Get the parent process to write to the local stack */
+ success &= wpmDoIt(Comms, autoAllocatedOnStack,
+ sizeof(autoAllocatedOnStack),
+ autoAllocatedOnStack + sizeof(int),
+ sizeof(autoAllocatedOnStack) - 2 * sizeof(int),
+ "const size array on stack with int sized guards");
+ }
+
+ /* Get the parent process to write to stuff on the heap */
+ sizeTarget = 2 * sizeof(int) + 23 ; /* 23 is just a random prime > 16 */
+ if (!(pTarget = malloc(sizeTarget)))
+ {
+ Trace("WriteProcessMemory helper: unable to allocate '%s'->%d bytes of memory"
+ "(%u).\n",
+ argv[3], sizeTarget, GetLastError());
+ success = FALSE;
+ goto EXIT;
+
+ }
+ success &= wpmDoIt(Comms, pTarget, sizeTarget,
+ pTarget + sizeof(int),
+ sizeTarget - 2 * sizeof(int),
+ "array on heap with int sized guards");
+
+ /* just to be nice try something 16 - 2 * sizeof(int) bytes long */
+ {
+ char autoAllocatedOnStack[16];
+
+ /* Get the parent process to write to the local stack */
+ success &= wpmDoIt(Comms, autoAllocatedOnStack,
+ sizeof(autoAllocatedOnStack),
+ autoAllocatedOnStack + sizeof(int),
+ sizeof(autoAllocatedOnStack) - 2 * sizeof(int),
+ "another 16 byte array on stack with int sized guards inside");
+ }
+
+ /* NOTE: Don't try 0 bytes long. Win32 WriteProcessMemory claims
+ * it writes 8 bytes in that case! */
+
+ /* and 1 byte long... */
+ {
+ char autoAllocatedOnStack[1+ 2 * sizeof(int)];
+
+ /* Get the parent process to write to the local stack */
+ success &= wpmDoIt(Comms, autoAllocatedOnStack,
+ sizeof(autoAllocatedOnStack),
+ autoAllocatedOnStack + sizeof(int),
+ 1,
+ "no bytes with int sized guards outside on stack");
+ }
+
+
+EXIT:
+ /* Tell the parent that we are done */
+ if (!DeleteFile(Comms.valuesFileName))
+ {
+ Trace("helper: DeleteFile failed so parent (test1) is unlikely "
+ "to exit cleanly\n");
+ }
+ PEDANTIC(ResetEvent, (Comms.hEvToHelper));
+ if (!SetEvent(Comms.hEvFromHelper))
+ {
+ Trace("helper: SetEvent failed so parent (test1) is unlikely "
+ "to exit cleanly\n");
+ }
+
+ free(pTarget);
+ PEDANTIC(CloseHandle, (Comms.hEvToHelper));
+ PEDANTIC(CloseHandle, (Comms.hEvFromHelper));
+
+ if (!success)
+ {
+ Fail("");
+ }
+
+ PAL_Terminate();
+
+ return success ? PASS : FAIL;
+}
diff --git a/src/pal/tests/palsuite/debug_api/WriteProcessMemory/test1/test1.c b/src/pal/tests/palsuite/debug_api/WriteProcessMemory/test1/test1.c
new file mode 100644
index 0000000000..8de029d973
--- /dev/null
+++ b/src/pal/tests/palsuite/debug_api/WriteProcessMemory/test1/test1.c
@@ -0,0 +1,189 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: test1.c
+**
+** Purpose: Create a child process and some events for communications with it.
+** When the child gets back to us with a memory location and a length,
+** Call WriteProcessMemory on this location and check to see that it
+** writes successfully.
+**
+**
+**============================================================*/
+
+#define UNICODE
+
+#include "commonconsts.h"
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ PROCESS_INFORMATION pi;
+ STARTUPINFO si;
+ HANDLE hEvToHelper;
+ HANDLE hEvFromHelper;
+ DWORD dwExitCode;
+
+
+ DWORD dwRet;
+ char cmdComposeBuf[MAX_PATH];
+ PWCHAR uniString;
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /* Create the signals we need for cross process communication */
+ hEvToHelper = CreateEvent(NULL, TRUE, FALSE, szcToHelperEvName);
+ if (!hEvToHelper)
+ {
+ Fail("WriteProcessMemory: CreateEvent of '%S' failed. "
+ "GetLastError() returned %d.\n", szcToHelperEvName,
+ GetLastError());
+ }
+ if (GetLastError() == ERROR_ALREADY_EXISTS)
+ {
+ Fail("WriteProcessMemory: CreateEvent of '%S' failed. "
+ "(already exists!)\n", szcToHelperEvName);
+ }
+ hEvFromHelper = CreateEvent(NULL, TRUE, FALSE, szcFromHelperEvName);
+ if (!hEvToHelper)
+ {
+ Fail("WriteProcessMemory: CreateEvent of '%S' failed. "
+ "GetLastError() returned %d.\n", szcFromHelperEvName,
+ GetLastError());
+ }
+ if (GetLastError() == ERROR_ALREADY_EXISTS)
+ {
+ Fail("WriteProcessMemory: CreateEvent of '%S' failed. "
+ "(already exists!)\n", szcFromHelperEvName);
+ }
+ ResetEvent(hEvFromHelper);
+ ResetEvent(hEvToHelper);
+
+ if (!sprintf(cmdComposeBuf, "helper %s", commsFileName))
+ {
+ Fail("Could not convert command line\n");
+ }
+ uniString = convert(cmdComposeBuf);
+
+ ZeroMemory( &si, sizeof(si) );
+ si.cb = sizeof(si);
+ ZeroMemory( &pi, sizeof(pi) );
+
+ /* Create a new process. This is the process that will ask for
+ * memory munging */
+ if(!CreateProcess( NULL, uniString, NULL, NULL,
+ FALSE, 0, NULL, NULL, &si, &pi))
+ {
+ Trace("ERROR: CreateProcess failed to load executable '%S'. "
+ "GetLastError() returned %u.\n",
+ uniString, GetLastError());
+ free(uniString);
+ Fail("");
+ }
+ free(uniString);
+
+ while(1)
+ {
+ FILE *commsFile;
+ char* pSrcMemory;
+ char* pDestMemory;
+ int Count;
+ SIZE_T wpmCount;
+ char incomingCMDBuffer[MAX_PATH + 1];
+
+ /* wait until the helper tells us that it has given us
+ * something to do */
+ dwRet = WaitForSingleObject(hEvFromHelper, TIMEOUT);
+ if (dwRet != WAIT_OBJECT_0)
+ {
+ Trace("test1 WaitForSingleObjectTest: WaitForSingleObject "
+ "failed (%u)\n", GetLastError());
+ break; /* no more work incoming */
+ }
+
+ /* get the parameters to test WriteProcessMemory with */
+ if (!(commsFile = fopen(commsFileName, "r")))
+ {
+ /* no file means there is no more work */
+ break;
+ }
+ if ( NULL == fgets(incomingCMDBuffer, MAX_PATH, commsFile))
+ {
+ Fail ("unable to read from communication file %s "
+ "for reasons %u & %u\n",
+ errno, GetLastError());
+ }
+ PEDANTIC1(fclose,(commsFile));
+ sscanf(incomingCMDBuffer, "%u %u", &pDestMemory, &Count);
+ if (argc > 1)
+ {
+ Trace("Preparing to write to %u bytes @ %u ('%s')\n",
+ Count, pDestMemory, incomingCMDBuffer);
+ }
+
+ /* compose some data to write to the client process */
+ if (!(pSrcMemory = malloc(Count)))
+ {
+ Trace("could not dynamically allocate memory to copy from "
+ "for reasons %u & %u\n",
+ errno, GetLastError());
+ goto doneIteration;
+ }
+ memset(pSrcMemory, nextValue, Count);
+
+ /* do the work */
+ dwRet = WriteProcessMemory(pi.hProcess,
+ pDestMemory,
+ pSrcMemory,
+ Count,
+ &wpmCount);
+ if (!dwRet)
+ {
+ Trace("%s: Problem: on a write to %u bytes @ %u ('%s')\n",
+ argv[0], Count, pDestMemory, incomingCMDBuffer);
+ Trace("test1 WriteProcessMemory returned a%u(!=0) (GLE=%u)\n",
+ GetLastError());
+ }
+ if(Count != wpmCount)
+ {
+ Trace("%s: Problem: on a write to %u bytes @ %u ('%s')\n",
+ argv[0], Count, pDestMemory, incomingCMDBuffer);
+ Trace("The number of bytes written should have been "
+ "%u, but was reported as %u.\n", Count, wpmCount);
+ }
+ free(pSrcMemory);
+
+ doneIteration:
+ PEDANTIC(ResetEvent, (hEvFromHelper));
+ PEDANTIC(SetEvent, (hEvToHelper));
+ }
+
+ /* wait for the child process to complete */
+ WaitForSingleObject ( pi.hProcess, TIMEOUT );
+ /* this may return a failure code on a success path */
+
+ /* check the exit code from the process */
+ if( ! GetExitCodeProcess( pi.hProcess, &dwExitCode ) )
+ {
+ Trace( "GetExitCodeProcess call failed with error code %u\n",
+ GetLastError() );
+ dwExitCode = FAIL;
+ }
+
+
+ PEDANTIC(CloseHandle, (hEvToHelper));
+ PEDANTIC(CloseHandle, (hEvFromHelper));
+ PEDANTIC(CloseHandle, (pi.hThread));
+ PEDANTIC(CloseHandle, (pi.hProcess));
+
+ PAL_TerminateEx(dwExitCode);
+ return dwExitCode;
+}
diff --git a/src/pal/tests/palsuite/debug_api/WriteProcessMemory/test1/testinfo.dat b/src/pal/tests/palsuite/debug_api/WriteProcessMemory/test1/testinfo.dat
new file mode 100644
index 0000000000..0946f8f138
--- /dev/null
+++ b/src/pal/tests/palsuite/debug_api/WriteProcessMemory/test1/testinfo.dat
@@ -0,0 +1,16 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Debug
+Function = WriteProcessMemory
+Name = Check that writing text to process memory succeeds.
+TYPE = DEFAULT
+EXE1 = test1
+EXE2 = helper
+Description
+= Create a child process and attempt to write to its memory
+= at the places and lengths it specifies via a data file.
+= the child verifies that all the specified memory was altered
+= with no overruns.
diff --git a/src/pal/tests/palsuite/debug_api/WriteProcessMemory/test3/CMakeLists.txt b/src/pal/tests/palsuite/debug_api/WriteProcessMemory/test3/CMakeLists.txt
new file mode 100644
index 0000000000..ecc0e06dac
--- /dev/null
+++ b/src/pal/tests/palsuite/debug_api/WriteProcessMemory/test3/CMakeLists.txt
@@ -0,0 +1,36 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(TESTSOURCES
+ test3.c
+)
+
+add_executable(paltest_writeprocessmemory_test3
+ ${TESTSOURCES}
+)
+
+add_dependencies(paltest_writeprocessmemory_test3 coreclrpal)
+
+target_link_libraries(paltest_writeprocessmemory_test3
+ pthread
+ m
+ coreclrpal
+)
+
+
+set(HELPERSOURCES
+ helper.c
+)
+
+add_executable(paltest_writeprocessmemory_test3_helper
+ ${HELPERSOURCES}
+)
+
+add_dependencies(paltest_writeprocessmemory_test3_helper coreclrpal)
+
+target_link_libraries(paltest_writeprocessmemory_test3_helper
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/debug_api/WriteProcessMemory/test3/commonconsts.h b/src/pal/tests/palsuite/debug_api/WriteProcessMemory/test3/commonconsts.h
new file mode 100644
index 0000000000..c1cec18e2d
--- /dev/null
+++ b/src/pal/tests/palsuite/debug_api/WriteProcessMemory/test3/commonconsts.h
@@ -0,0 +1,50 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Header: commonconsts.h
+**
+**
+==============================================================*/
+
+#ifndef _COMMONCONSTS_H_
+#define _COMMONCONSTS_H_
+
+#include <pal.h>
+
+const int TIMEOUT = 40000;
+
+const WCHAR szcToHelperEvName[] = { 'T', 'o', '\0' };
+const WCHAR szcFromHelperEvName[] = { 'F', 'r', 'o', 'm', '\0' };
+
+const char initialValue = '-';
+const char nextValue = '|';
+const char guardValue = '*';
+const char *commsFileName = "AddrNLen.dat";
+
+/* PEDANTIC and PEDANTIC0 is a helper macro that just grumps about any
+ * zero return codes in a generic way. with little typing */
+#define PEDANTIC(function, parameters) \
+{ \
+ unsigned int retval = (function parameters); \
+ if ( !retval ) \
+ { \
+ Trace("%s: NonFatal failure of %s%s (returned %u) " \
+ "for reasons %u and %u.\n", \
+ __FILE__, #function, #parameters, retval, GetLastError(), errno); \
+ } \
+}
+#define PEDANTIC1(function, parameters) \
+{ \
+ unsigned int retval = (function parameters); \
+ if ( retval ) \
+ { \
+ Trace("%s: NonFatal failure of %s%s (returned %u) " \
+ "for reasons %u and %u\n", \
+ __FILE__, #function, #parameters, retval, GetLastError(), errno); \
+ } \
+}
+
+#endif
diff --git a/src/pal/tests/palsuite/debug_api/WriteProcessMemory/test3/helper.c b/src/pal/tests/palsuite/debug_api/WriteProcessMemory/test3/helper.c
new file mode 100644
index 0000000000..170e2064cb
--- /dev/null
+++ b/src/pal/tests/palsuite/debug_api/WriteProcessMemory/test3/helper.c
@@ -0,0 +1,256 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: helper.c
+
+**
+==============================================================*/
+
+
+/*
+**
+** Purpose: This helper process sets up a several blocks of memory
+** that should be unwritable from the parent process, then uses a file
+** to tell its parent process where that memory is so it can attempt a
+** WriteProcessMemory on it. When the parent process is done we check
+** here that it was (properly) unable to change the contents of the
+** memory.
+*/
+
+#include "commonconsts.h"
+
+#include <palsuite.h>
+
+struct allhandles_t
+{
+ HANDLE hEvToHelper;
+ HANDLE hEvFromHelper;
+ char *valuesFileName;
+};
+
+
+/* function: wpmVerifyCant
+ *
+ * This is a general WriteProcessMemory testing function that sets up
+ * the RAM pointed to and tells the companion process on the other end
+ * of the handles in 'Comms' to attempt to alter 'lenDest' bytes at
+ * '*pDest'.
+ *
+ * However, the memory at pDest[0..lenDest] is expected to be unwritable by
+ * the companion process. The companion is expects this. This function
+ * verifies that no bytes were affected
+ */
+
+int wpmVerifyCant(struct allhandles_t Comms,
+ char * pDest, unsigned int lenDest,
+ unsigned int lenLegitDest,
+ DWORD dwExpectedErrorCode,
+ const char* storageDescription)
+{
+ char *pCurr;
+ FILE *commsFile;
+ DWORD dwRet;
+
+ unsigned int lenSafe = min(lenDest, lenLegitDest);
+
+ PAL_TRY
+ {
+ memset(pDest, initialValue, lenSafe);
+ }
+ PAL_EXCEPT_EX (setup, EXCEPTION_EXECUTE_HANDLER)
+ {
+ Trace("WriteProcessMemory: bug in test values for '%s' (%p, %u, %u), "
+ "the initial memset threw an exception.\n",
+ storageDescription, pDest, lenDest, lenSafe);
+ }
+ PAL_ENDTRY;
+
+ /* tell the parent what RAM to attempt to adjust */
+ if(!(commsFile = fopen(Comms.valuesFileName, "w")))
+ {
+ Trace("WriteProcessMemory: fopen of '%S' failed (%u). \n",
+ Comms.valuesFileName, GetLastError());
+ return FALSE;
+ }
+ if (!fprintf(commsFile, "%u %u %u '%s'\n",
+ pDest, lenDest, dwExpectedErrorCode, storageDescription))
+ {
+ Trace("WriteProcessMemory: fprintf to '%S' failed (%u). \n",
+ Comms.valuesFileName, GetLastError());
+ return FALSE;
+ }
+ PEDANTIC1(fclose, (commsFile));
+
+ /* Tell the parent the data is ready for it to adjust */
+ PEDANTIC(ResetEvent, (Comms.hEvToHelper));
+ PEDANTIC(SetEvent, (Comms.hEvFromHelper));
+
+ dwRet = WaitForSingleObject(Comms.hEvToHelper, TIMEOUT);
+ if (dwRet != WAIT_OBJECT_0)
+ {
+ Trace("helper WaitForSingleObjectTest: WaitForSingleObject "
+ "failed (%u)\n", GetLastError());
+ return FALSE;
+ }
+
+ PAL_TRY
+ {
+ /* check the stuff (as much as we can) that should NOT have changed */
+ for (pCurr = pDest; pCurr < (pDest + lenSafe); pCurr++ )
+ {
+ if ( *pCurr != initialValue)
+ {
+ Trace("When testing '%s': real memory values preservation failed "
+ "at %u offset %u. Found '%c' instead of '%c'\n.",
+ storageDescription, pDest, pCurr - pDest,
+ *pCurr, initialValue);
+ return FALSE;
+ }
+ }
+ }
+ PAL_EXCEPT_EX (testing, EXCEPTION_EXECUTE_HANDLER)
+ {
+ Trace("WriteProcessMemory: bug in test values for '%s' (%p, %u, %u), "
+ "the verification pass threw an exception.\n",
+ storageDescription, pDest, lenDest, lenSafe);
+ }
+ PAL_ENDTRY;
+
+ return TRUE;
+}
+
+int __cdecl main(int argc, char *argv[])
+{
+ BOOL success = TRUE; /* assume success */
+ struct allhandles_t Comms = {0,0,0} ;
+
+ SYSTEM_INFO sysinfo;
+
+ char* Memory;
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /* hook up with the events created by the parent */
+ Comms.hEvToHelper = OpenEventW(EVENT_ALL_ACCESS, 0, szcToHelperEvName);
+ if (!Comms.hEvToHelper)
+ {
+ Fail("WriteProcessMemory: OpenEvent of '%S' failed (%u). "
+ "(the event should already exist!)\n",
+ szcToHelperEvName, GetLastError());
+ success = FALSE;
+ goto EXIT;
+ }
+ Comms.hEvFromHelper = OpenEventW(EVENT_ALL_ACCESS, 0, szcFromHelperEvName);
+ if (!Comms.hEvToHelper)
+ {
+ Trace("WriteProcessMemory: OpenEvent of '%S' failed (%u). "
+ "(the event should already exist!)\n",
+ szcFromHelperEvName, GetLastError());
+ success = FALSE;
+ goto EXIT;
+ }
+ Comms.valuesFileName = argv[1];
+
+ /* test setup */
+ GetSystemInfo(&sysinfo);
+
+ {
+ unsigned int allocSize = sysinfo.dwPageSize * 2;
+ unsigned int writeLen = allocSize * 2;
+
+ /* First test: overrun the allocated memory */
+ Memory = (char*)VirtualAlloc(NULL, allocSize,
+ MEM_COMMIT, PAGE_READWRITE);
+
+ if(Memory == NULL)
+ {
+ Fail("ERROR: Attempted to commit two pages, but the "
+ " VirtualAlloc call failed. "
+ "GetLastError() returned %u.\n",GetLastError());
+ }
+ success &= wpmVerifyCant(Comms, Memory, writeLen, allocSize,
+ ERROR_INVALID_ADDRESS,
+ "should not write beyond committed allocation");
+
+ PEDANTIC1(VirtualFree, (Memory, allocSize,
+ MEM_DECOMMIT | MEM_RELEASE));
+ }
+
+ {
+ /* Allocate the memory as readonly */
+ unsigned int allocSize = sysinfo.dwPageSize * 2;
+ unsigned int writeLen = allocSize;
+
+ Memory = (char*)VirtualAlloc(NULL, allocSize,
+ MEM_COMMIT, PAGE_READONLY);
+
+ if(Memory == NULL)
+ {
+ Fail("ERROR: Attempted to commit two pages readonly, but the "
+ " VirtualAlloc call failed. "
+ "GetLastError() returned %u.\n",GetLastError());
+ }
+ success &= wpmVerifyCant(Comms, Memory, writeLen, 0,
+ ERROR_NOACCESS,
+ "should not write in READONLY allocation");
+
+ PEDANTIC1(VirtualFree, (Memory, allocSize,
+ MEM_DECOMMIT | MEM_RELEASE));
+ }
+
+
+ {
+ /* attempt to write to memory that is not committed yet */
+ unsigned int allocSize = sysinfo.dwPageSize * 2;
+ unsigned int writeLen = allocSize;
+
+ Memory = (char*)VirtualAlloc(NULL, allocSize,
+ MEM_RESERVE, PAGE_NOACCESS);
+
+ if(Memory == NULL)
+ {
+ Fail("ERROR: Attempted to reserve two pages, but the "
+ " VirtualAlloc call failed. "
+ "GetLastError() returned %u.\n",GetLastError());
+ }
+ success &= wpmVerifyCant(Comms, Memory, writeLen, 0,
+ ERROR_INVALID_ADDRESS,
+ "should not write in memory that is"
+ " RESERVED but not COMMITTED");
+
+ PEDANTIC1(VirtualFree, (Memory, allocSize, MEM_RELEASE));
+ }
+
+
+EXIT:
+ /* Tell the parent that we are done */
+ if (!DeleteFile(Comms.valuesFileName))
+ {
+ Trace("helper: DeleteFile failed so parent (test1) is unlikely "
+ "to exit cleanly\n");
+ }
+ PEDANTIC(ResetEvent, (Comms.hEvToHelper));
+ if (!SetEvent(Comms.hEvFromHelper))
+ {
+ Trace("helper: SetEvent failed so parent (test1) is unlikely "
+ "to exit cleanly\n");
+ }
+
+ PEDANTIC(CloseHandle, (Comms.hEvToHelper));
+ PEDANTIC(CloseHandle, (Comms.hEvFromHelper));
+
+ if (!success)
+ {
+ Fail("");
+ }
+
+ PAL_Terminate();
+
+ return success ? PASS : FAIL;
+}
diff --git a/src/pal/tests/palsuite/debug_api/WriteProcessMemory/test3/test3.c b/src/pal/tests/palsuite/debug_api/WriteProcessMemory/test3/test3.c
new file mode 100644
index 0000000000..063cb4cbec
--- /dev/null
+++ b/src/pal/tests/palsuite/debug_api/WriteProcessMemory/test3/test3.c
@@ -0,0 +1,205 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: test3.c
+**
+** Purpose: Create a child process and debug it. When the child
+** raises an exception, it sends back a memory location. Call
+** WriteProcessMemory on the memory location, but attempt to write
+** more than the memory allows. This should cause an error and the
+** data should be unchanged.
+**
+**
+==============================================================*/
+
+#define UNICODE
+
+#include "commonconsts.h"
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ PROCESS_INFORMATION pi;
+ STARTUPINFO si;
+ HANDLE hEvToHelper;
+ HANDLE hEvFromHelper;
+ DWORD dwExitCode;
+
+
+ DWORD dwRet;
+ BOOL success = TRUE; /* assume success */
+ char cmdComposeBuf[MAX_PATH];
+ PWCHAR uniString;
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /* Create the signals we need for cross process communication */
+ hEvToHelper = CreateEvent(NULL, TRUE, FALSE, szcToHelperEvName);
+ if (!hEvToHelper)
+ {
+ Fail("WriteProcessMemory: CreateEvent of '%S' failed. "
+ "GetLastError() returned %u.\n", szcToHelperEvName,
+ GetLastError());
+ }
+ if (GetLastError() == ERROR_ALREADY_EXISTS)
+ {
+ Fail("WriteProcessMemory: CreateEvent of '%S' failed. "
+ "(already exists!)\n", szcToHelperEvName);
+ }
+ hEvFromHelper = CreateEvent(NULL, TRUE, FALSE, szcFromHelperEvName);
+ if (!hEvToHelper)
+ {
+ Fail("WriteProcessMemory: CreateEvent of '%S' failed. "
+ "GetLastError() returned %u.\n", szcFromHelperEvName,
+ GetLastError());
+ }
+ if (GetLastError() == ERROR_ALREADY_EXISTS)
+ {
+ Fail("WriteProcessMemory: CreateEvent of '%S' failed. "
+ "(already exists!)\n", szcFromHelperEvName);
+ }
+
+ if (!sprintf(cmdComposeBuf, "helper %s", commsFileName))
+ {
+ Fail("Could not convert command line\n");
+ }
+ uniString = convert(cmdComposeBuf);
+
+ ZeroMemory( &si, sizeof(si) );
+ si.cb = sizeof(si);
+ ZeroMemory( &pi, sizeof(pi) );
+
+ /* Create a new process. This is the process that will ask for
+ * memory munging */
+ if(!CreateProcess( NULL, uniString, NULL, NULL,
+ FALSE, 0, NULL, NULL, &si, &pi))
+ {
+ Trace("ERROR: CreateProcess failed to load executable '%S'. "
+ "GetLastError() returned %u.\n",
+ uniString, GetLastError());
+ free(uniString);
+ Fail("");
+ }
+ free(uniString);
+
+ while(1)
+ {
+ FILE *commsFile;
+ char* pSrcMemory;
+ char* pDestMemory;
+ int Count;
+ SIZE_T wpmCount;
+ DWORD dwExpectedErrorCode;
+
+ char incomingCMDBuffer[MAX_PATH + 1];
+
+ /* wait until the helper tells us that it has given us
+ * something to do */
+ dwRet = WaitForSingleObject(hEvFromHelper, TIMEOUT);
+ if (dwRet != WAIT_OBJECT_0)
+ {
+ Trace("test1 WaitForSingleObjectTest: WaitForSingleObject "
+ "failed (%u)\n", GetLastError());
+ break; /* no more work incoming */
+ }
+
+ /* get the parameters to test WriteProcessMemory with */
+ if (!(commsFile = fopen(commsFileName, "r")))
+ {
+ /* no file means there is no more work */
+ break;
+ }
+ if ( NULL == fgets(incomingCMDBuffer, MAX_PATH, commsFile))
+ {
+ Trace ("unable to read from communication file %s "
+ "for reasons %u & %u\n",
+ errno, GetLastError());
+ success = FALSE;
+ PEDANTIC1(fclose,(commsFile));
+ /* it's not worth continuing this trial */
+ goto doneIteration;
+ }
+ PEDANTIC1(fclose,(commsFile));
+ sscanf(incomingCMDBuffer, "%u %u %u",
+ &pDestMemory, &Count, &dwExpectedErrorCode);
+ if (argc > 1)
+ {
+ Trace("Preparing to write to %u bytes @ %u ('%s')\n",
+ Count, pDestMemory, incomingCMDBuffer);
+ }
+
+ /* compose some data to write to the client process */
+ if (!(pSrcMemory = malloc(Count)))
+ {
+ Trace("could not dynamically allocate memory to copy from "
+ "for reasons %u & %u\n",
+ errno, GetLastError());
+ success = FALSE;
+ goto doneIteration;
+ }
+ memset(pSrcMemory, nextValue, Count);
+
+ /* do the work */
+ dwRet = WriteProcessMemory(pi.hProcess,
+ pDestMemory,
+ pSrcMemory,
+ Count,
+ &wpmCount);
+
+ if(dwRet != 0)
+ {
+ Trace("ERROR: Situation: '%s', return code: %u, bytes 'written': %u\n",
+ incomingCMDBuffer, dwRet, wpmCount);
+ Trace("ERROR: WriteProcessMemory did not fail as it should, as "
+ "it attempted to write to a range of memory which was "
+ "not completely accessible.\n");
+ success = FALSE;
+ }
+
+ if(GetLastError() != dwExpectedErrorCode)
+ {
+ Trace("ERROR: GetLastError() should have returned "
+ "%u , but instead it returned %u.\n",
+ dwExpectedErrorCode, GetLastError());
+ success = FALSE;
+ }
+ free(pSrcMemory);
+
+ doneIteration:
+ PEDANTIC(ResetEvent, (hEvFromHelper));
+ PEDANTIC(SetEvent, (hEvToHelper));
+ }
+
+
+ /* wait for the child process to complete */
+ WaitForSingleObject ( pi.hProcess, TIMEOUT );
+ /* this may return a failure code on a success path */
+
+ /* check the exit code from the process */
+ if( ! GetExitCodeProcess( pi.hProcess, &dwExitCode ) )
+ {
+ Trace( "GetExitCodeProcess call failed with error code %u\n",
+ GetLastError() );
+ dwExitCode = FAIL;
+ }
+ if(!success)
+ {
+ dwExitCode = FAIL;
+ }
+
+ PEDANTIC(CloseHandle, (hEvToHelper));
+ PEDANTIC(CloseHandle, (hEvFromHelper));
+ PEDANTIC(CloseHandle, (pi.hThread));
+ PEDANTIC(CloseHandle, (pi.hProcess));
+
+ PAL_Terminate(dwExitCode);
+ return dwExitCode;
+}
diff --git a/src/pal/tests/palsuite/debug_api/WriteProcessMemory/test3/testinfo.dat b/src/pal/tests/palsuite/debug_api/WriteProcessMemory/test3/testinfo.dat
new file mode 100644
index 0000000000..23ad3ae567
--- /dev/null
+++ b/src/pal/tests/palsuite/debug_api/WriteProcessMemory/test3/testinfo.dat
@@ -0,0 +1,17 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Debug
+Function = WriteProcessMemory
+Name = Check that you can't write from writable to protected memory.
+TYPE = DEFAULT
+EXE1 = test3
+EXE2 = helper
+Description
+= Create a child process and debug it. When the child
+= raises an exception, it sends back a memory location. Call
+= WriteProcessMemory on the memory location, but attempt to write
+= more than the memory allows. This should cause an error and the
+= data should be unchanged.
diff --git a/src/pal/tests/palsuite/debug_api/WriteProcessMemory/test4/CMakeLists.txt b/src/pal/tests/palsuite/debug_api/WriteProcessMemory/test4/CMakeLists.txt
new file mode 100644
index 0000000000..cf1ce13862
--- /dev/null
+++ b/src/pal/tests/palsuite/debug_api/WriteProcessMemory/test4/CMakeLists.txt
@@ -0,0 +1,36 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(TESTSOURCES
+ test4.c
+)
+
+add_executable(paltest_writeprocessmemory_test4
+ ${TESTSOURCES}
+)
+
+add_dependencies(paltest_writeprocessmemory_test4 coreclrpal)
+
+target_link_libraries(paltest_writeprocessmemory_test4
+ pthread
+ m
+ coreclrpal
+)
+
+
+set(HELPERSOURCES
+ helper.c
+)
+
+add_executable(paltest_writeprocessmemory_test4_helper
+ ${HELPERSOURCES}
+)
+
+add_dependencies(paltest_writeprocessmemory_test4_helper coreclrpal)
+
+target_link_libraries(paltest_writeprocessmemory_test4_helper
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/debug_api/WriteProcessMemory/test4/helper.c b/src/pal/tests/palsuite/debug_api/WriteProcessMemory/test4/helper.c
new file mode 100644
index 0000000000..b653ea5057
--- /dev/null
+++ b/src/pal/tests/palsuite/debug_api/WriteProcessMemory/test4/helper.c
@@ -0,0 +1,67 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: helper.c
+**
+** Purpose: This helper process sets up a block of memory, then
+** raises an exception to pass that memory location back to the
+** parent process. When the parent process is done calling WriteProcessMemory
+** we check here that it was written properly.
+**
+**
+**============================================================*/
+
+#include <palsuite.h>
+const int MY_EXCEPTION=999;
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ char* Memory;
+ char* TheArray[1];
+ int i;
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ Memory = (char*)VirtualAlloc(NULL, 4096, MEM_COMMIT, PAGE_READONLY);
+
+ if(Memory == NULL)
+ {
+ Fail("ERROR: Attempted to allocate two pages, but the VirtualAlloc "
+ "call failed. GetLastError() returned %d.\n",GetLastError());
+ }
+
+
+ TheArray[0] = Memory;
+
+
+ /* Need to sleep for a couple seconds. Otherwise this process
+ won't be being debugged when the first exception is raised.
+ */
+ Sleep(4000);
+
+ RaiseException(MY_EXCEPTION, 0, 1, (ULONG_PTR*)TheArray);
+
+ for(i=0; i<4096; ++i)
+ {
+ if(Memory[i] != '\0')
+ {
+ Fail("ERROR: The memory should be unchanged after the "
+ "invalid call to WriteProcessMemory, but the char "
+ "at index %d has changed.\n",i);
+ }
+ }
+
+
+
+
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/debug_api/WriteProcessMemory/test4/test4.c b/src/pal/tests/palsuite/debug_api/WriteProcessMemory/test4/test4.c
new file mode 100644
index 0000000000..51db23499b
--- /dev/null
+++ b/src/pal/tests/palsuite/debug_api/WriteProcessMemory/test4/test4.c
@@ -0,0 +1,124 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: test4.c
+**
+** Purpose: Create a child process and debug it. When the child
+** raises an exception, it sends back a memory location. Call
+** WriteProcessMemory on a restricted memory location and ensure that
+** it fails.
+**
+**
+**============================================================*/
+
+#include <palsuite.h>
+const int MY_EXCEPTION=999;
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ PROCESS_INFORMATION pi;
+ STARTUPINFO si;
+ DEBUG_EVENT DebugEv;
+ DWORD dwContinueStatus = DBG_CONTINUE;
+ int Count, ret;
+ char* DataBuffer[4096];
+ char* Memory;
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ ZeroMemory( &si, sizeof(si) );
+ si.cb = sizeof(si);
+ ZeroMemory( &pi, sizeof(pi) );
+
+ memset(DataBuffer, 'z', 4096);
+
+ /* Create a new process. This is the process to be Debugged */
+ if(!CreateProcess( NULL, "helper", NULL, NULL,
+ FALSE, 0, NULL, NULL, &si, &pi))
+ {
+ Fail("ERROR: CreateProcess failed to load executable 'helper'. "
+ "GetLastError() returned %d.\n",GetLastError());
+ }
+
+ /* Call DebugActiveProcess, because the process wasn't created as a
+ debug process.
+ */
+ if(DebugActiveProcess(pi.dwProcessId) == 0)
+ {
+ Fail("ERROR: Failed calling DebugActiveProcess on the process "
+ "which was created to debug. GetLastError() returned %d.\n",
+ GetLastError());
+ }
+
+
+ /* Call WaitForDebugEvent, which will wait until the helper process
+ raises an exception.
+ */
+
+ while(1)
+ {
+ if(WaitForDebugEvent(&DebugEv, INFINITE) == 0)
+ {
+ Fail("ERROR: WaitForDebugEvent returned 0, indicating failure. "
+ "GetLastError() returned %d.\n",GetLastError());
+ }
+
+ /* We're waiting for the helper process to send this exception.
+ When it does, we call WriteProcess. If it gets called more than
+ once, it is ignored.
+ */
+
+ if(DebugEv.u.Exception.ExceptionRecord.ExceptionCode == MY_EXCEPTION)
+ {
+
+ Memory = (LPVOID)
+ DebugEv.u.Exception.ExceptionRecord.ExceptionInformation[0];
+
+ /* Write to this memory which we have no access to. */
+
+ ret = WriteProcessMemory(pi.hProcess,
+ Memory,
+ DataBuffer,
+ 4096,
+ &Count);
+
+ if(ret != 0)
+ {
+ Fail("ERROR: WriteProcessMemory should have failed, as "
+ "it attempted to write to a range of memory which was "
+ "not accessible.\n");
+ }
+
+ if(GetLastError() != ERROR_NOACCESS)
+ {
+ Fail("ERROR: GetLastError() should have returned "
+ "ERROR_NOACCESS , but intead it returned "
+ "%d.\n",GetLastError());
+ }
+ }
+
+ if(DebugEv.dwDebugEventCode == EXIT_PROCESS_DEBUG_EVENT)
+ {
+ break;
+ }
+
+ if(ContinueDebugEvent(DebugEv.dwProcessId,
+ DebugEv.dwThreadId, dwContinueStatus) == 0)
+ {
+ Fail("ERROR: ContinueDebugEvent failed to continue the thread "
+ "which had a debug event. GetLastError() returned %d.\n",
+ GetLastError());
+ }
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/debug_api/WriteProcessMemory/test4/testinfo.dat b/src/pal/tests/palsuite/debug_api/WriteProcessMemory/test4/testinfo.dat
new file mode 100644
index 0000000000..c6f4edb5d6
--- /dev/null
+++ b/src/pal/tests/palsuite/debug_api/WriteProcessMemory/test4/testinfo.dat
@@ -0,0 +1,17 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Debug
+Function = WriteProcessMemory
+Name = Check that you can't write to protected memory.
+TYPE = DEFAULT
+EXE1 = test4
+EXE2 = helper
+Description
+= Create a child process and debug it. When the child
+= raises an exception, it sends back a memory location. Call
+= WriteProcessMemory on a restricted memory location and ensure that
+= it fails.
+
diff --git a/src/pal/tests/palsuite/exception_handling/CMakeLists.txt b/src/pal/tests/palsuite/exception_handling/CMakeLists.txt
new file mode 100644
index 0000000000..d0de335427
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/CMakeLists.txt
@@ -0,0 +1,13 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(pal_sxs)
+#add_subdirectory(pal_except)
+#add_subdirectory(PAL_EXCEPT_FILTER)
+#add_subdirectory(PAL_EXCEPT_FILTER_EX)
+#add_subdirectory(pal_finally)
+#add_subdirectory(PAL_TRY_EXCEPT)
+#add_subdirectory(PAL_TRY_EXCEPT_EX)
+#add_subdirectory(PAL_TRY_LEAVE_FINALLY)
+add_subdirectory(RaiseException)
+#add_subdirectory(SetUnhandledExceptionFilter)
+
diff --git a/src/pal/tests/palsuite/exception_handling/PAL_EXCEPT_FILTER/CMakeLists.txt b/src/pal/tests/palsuite/exception_handling/PAL_EXCEPT_FILTER/CMakeLists.txt
new file mode 100644
index 0000000000..1962ade358
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/PAL_EXCEPT_FILTER/CMakeLists.txt
@@ -0,0 +1,6 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+add_subdirectory(test3)
+
diff --git a/src/pal/tests/palsuite/exception_handling/PAL_EXCEPT_FILTER/test1/CMakeLists.txt b/src/pal/tests/palsuite/exception_handling/PAL_EXCEPT_FILTER/test1/CMakeLists.txt
new file mode 100644
index 0000000000..adbc8ae86a
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/PAL_EXCEPT_FILTER/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ PAL_EXCEPT_FILTER.c
+)
+
+add_executable(paltest_pal_except_filter_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_pal_except_filter_test1 coreclrpal)
+
+target_link_libraries(paltest_pal_except_filter_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/exception_handling/PAL_EXCEPT_FILTER/test1/PAL_EXCEPT_FILTER.c b/src/pal/tests/palsuite/exception_handling/PAL_EXCEPT_FILTER/test1/PAL_EXCEPT_FILTER.c
new file mode 100644
index 0000000000..ee65f43d2c
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/PAL_EXCEPT_FILTER/test1/PAL_EXCEPT_FILTER.c
@@ -0,0 +1,118 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: pal_except_filter.c (test 1)
+**
+** Purpose: Tests the PAL implementation of the PAL_EXCEPT_FILTER. An
+** exception is forced and a known value is passed to the filter
+** fuction. The known value as well as booleans are tested to
+** ensure proper functioning.
+**
+**
+**===================================================================*/
+
+
+
+#include <palsuite.h>
+
+BOOL bFilter = FALSE;
+BOOL bTry = FALSE;
+const int nValidator = 12321;
+
+LONG ExitFilter(EXCEPTION_POINTERS* ep, LPVOID pnTestInt)
+{
+ int nTestInt = *(int *)pnTestInt;
+
+ /* let the main know we've hit the filter function */
+ bFilter = TRUE;
+
+ if (!bTry)
+ {
+ Fail("PAL_EXCEPT_FILTER: ERROR -> Something weird is going on."
+ " The filter was hit without PAL_TRY being hit.\n");
+ }
+
+ /* was the correct value passed? */
+ if (nValidator != nTestInt)
+ {
+ Fail("PAL_EXCEPT_FILTER: ERROR -> Parameter passed to filter function"
+ " should have been \"%d\" but was \"%d\".\n",
+ nValidator,
+ nTestInt);
+ }
+ return EXCEPTION_EXECUTE_HANDLER;
+}
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ int* p = 0x00000000; /* pointer to NULL */
+ BOOL bExcept = FALSE;
+
+ if (0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ /*
+ ** test to make sure we get into the exception block
+ */
+
+ PAL_TRY
+ {
+ if (bExcept)
+ {
+ Fail("PAL_EXCEPT_FILTER: ERROR -> Something weird is going on."
+ " PAL_EXCEPT_FILTER was hit before PAL_TRY.\n");
+ }
+ bTry = TRUE; /* indicate we hit the PAL_TRY block */
+ *p = 13; /* causes an access violation exception */
+
+ Fail("PAL_EXCEPT_FILTER: ERROR -> code was executed after the "
+ "access violation.\n");
+ }
+ PAL_EXCEPT_FILTER(ExitFilter, (LPVOID)&nValidator)
+ {
+ if (!bTry)
+ {
+ Fail("PAL_EXCEPT_FILTER: ERROR -> Something weird is going on."
+ " PAL_EXCEPT_FILTER was hit without PAL_TRY being hit.\n");
+ }
+ bExcept = TRUE; /* indicate we hit the PAL_EXCEPT_FILTER block */
+ }
+ PAL_ENDTRY;
+
+ if (!bTry)
+ {
+ Trace("PAL_EXCEPT_FILTER: ERROR -> It appears the code in the PAL_TRY"
+ " block was not executed.\n");
+ }
+
+ if (!bExcept)
+ {
+ Trace("PAL_EXCEPT_FILTER: ERROR -> It appears the code in the "
+ "PAL_EXCEPT_FILTER block was not executed.\n");
+ }
+
+ if (!bFilter)
+ {
+ Trace("PAL_EXCEPT_FILTER: ERROR -> It appears the code in the filter"
+ " function was not executed.\n");
+ }
+
+
+ /* did we hit all the code blocks? */
+ if(!bTry || !bExcept || !bFilter)
+ {
+ Fail("");
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+
+}
diff --git a/src/pal/tests/palsuite/exception_handling/PAL_EXCEPT_FILTER/test1/testinfo.dat b/src/pal/tests/palsuite/exception_handling/PAL_EXCEPT_FILTER/test1/testinfo.dat
new file mode 100644
index 0000000000..b0b90d3ab4
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/PAL_EXCEPT_FILTER/test1/testinfo.dat
@@ -0,0 +1,16 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = exception_handling
+Function = PAL_EXCEPT_FILTER
+Name = Test for PAL_EXCEPT_FILTER
+Type = DEFAULT
+EXE1 = pal_except_filter
+LANG = cpp
+Description
+= Tests the PAL implementation of the PAL_EXCEPT_FILTER. An
+= exception is forced and a known value is passed to the filter
+= fuction. The known value as well as booleans are tested to
+= ensure proper functioning.
diff --git a/src/pal/tests/palsuite/exception_handling/PAL_EXCEPT_FILTER/test2/CMakeLists.txt b/src/pal/tests/palsuite/exception_handling/PAL_EXCEPT_FILTER/test2/CMakeLists.txt
new file mode 100644
index 0000000000..62cda706d5
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/PAL_EXCEPT_FILTER/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ pal_except_filter.c
+)
+
+add_executable(paltest_pal_except_filter_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_pal_except_filter_test2 coreclrpal)
+
+target_link_libraries(paltest_pal_except_filter_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/exception_handling/PAL_EXCEPT_FILTER/test2/pal_except_filter.c b/src/pal/tests/palsuite/exception_handling/PAL_EXCEPT_FILTER/test2/pal_except_filter.c
new file mode 100644
index 0000000000..ccf53fb0ba
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/PAL_EXCEPT_FILTER/test2/pal_except_filter.c
@@ -0,0 +1,154 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: pal_except_filter.c (test 2)
+**
+** Purpose: Tests the PAL implementation of the PAL_EXCEPT_FILTER. An
+** exception is forced and the filter returns
+** EXCEPTION_CONTINUE_EXECUTION to allow execution to continue.
+**
+**
+**===================================================================*/
+
+
+#include <palsuite.h>
+
+char* p; /* pointer to be abused */
+
+BOOL bFilter = FALSE;
+BOOL bTry = FALSE;
+BOOL bTry2 = FALSE;
+BOOL bContinued = FALSE;
+const int nValidator = 12321;
+
+LONG ExitFilter(EXCEPTION_POINTERS* ep, LPVOID pnTestInt)
+{
+ int nTestInt = *(int *)pnTestInt;
+ void *Temp;
+
+ /* let the main know we've hit the filter function */
+ bFilter = TRUE;
+
+ if (!bTry)
+ {
+ Fail("PAL_EXCEPT_FILTER: ERROR -> Something weird is going on."
+ " The filter was hit without PAL_TRY being hit.\n");
+ }
+
+ /* was the correct value passed? */
+ if (nValidator != nTestInt)
+ {
+ Fail("PAL_EXCEPT_FILTER: ERROR -> Parameter passed to filter function"
+ " should have been \"%d\" but was \"%d\".\n",
+ nValidator,
+ nTestInt);
+ }
+
+ /* Are we dealing with the exception we expected? */
+ if (EXCEPTION_ACCESS_VIOLATION != ep->ExceptionRecord->ExceptionCode)
+ {
+ Fail("PAL_EXCEPT_FILTER: ERROR -> Unexpected Exception"
+ " should have been \"%x\" but was \"%x\".\n",
+ EXCEPTION_ACCESS_VIOLATION,
+ ep->ExceptionRecord->ExceptionCode);
+ }
+
+ /* attempt to correct the problem by commiting the page at address 'p' */
+ Temp= VirtualAlloc(p, 1, MEM_COMMIT, PAGE_READWRITE);
+ if (!Temp)
+ {
+ Fail("EXCEPTION_CONTINUE_EXECUTION: last error = %u - probably "
+ "out of memory. Unable to continue, not proof of exception "
+ "failure\n",
+ GetLastError());
+ }
+ /* The memory that 'p' points to is now valid */
+
+ return EXCEPTION_CONTINUE_EXECUTION;
+}
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ BOOL bExcept = FALSE;
+
+ if (0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ /*
+ ** test to make sure we get into the exception block
+ */
+
+ PAL_TRY
+ {
+ if (bExcept)
+ {
+ Fail("PAL_EXCEPT_FILTER: ERROR -> Something weird is going on."
+ " PAL_EXCEPT_FILTER was hit before PAL_TRY.\n");
+ }
+ bTry = TRUE; /* indicate we hit the PAL_TRY block */
+
+ /* reserve an address chunk for p to point to */
+ p = (char*) VirtualAlloc(0, 1, MEM_RESERVE, PAGE_READONLY);
+ if (!p)
+ {
+ Fail("EXCEPTION_CONTINUE_EXECUTION: test setup via "
+ "VirtualAlloc failed.\n");
+ }
+
+ *p = 13; /* causes an access violation exception */
+
+ bTry2 = TRUE;
+
+
+ }
+ PAL_EXCEPT_FILTER(ExitFilter, (LPVOID)&nValidator)
+ {
+ bExcept = TRUE; /* indicate we hit the PAL_EXCEPT_FILTER block */
+ Fail("PAL_EXCEPT_FILTER: ERROR -> in handler despite filter's "
+ "continue choice\n");
+ }
+ PAL_ENDTRY;
+
+ if (!bTry)
+ {
+ Trace("PAL_EXCEPT_FILTER: ERROR -> It appears the code in the PAL_TRY"
+ " block was not executed.\n");
+ }
+
+ if (bExcept)
+ {
+ Trace("PAL_EXCEPT_FILTER: ERROR -> It appears the code in the "
+ "PAL_EXCEPT_FILTER block was executed.\n");
+ }
+
+ if (!bFilter)
+ {
+ Trace("PAL_EXCEPT_FILTER: ERROR -> It appears the code in the filter"
+ " function was not executed.\n");
+ }
+
+
+ if (!bTry2)
+ {
+ Trace("PAL_EXCEPT_FILTER: ERROR -> It appears the code in the PAL_TRY"
+ " block after the exception causing statements was not executed.\n");
+ }
+
+ /* did we hit all the code blocks? */
+ if(!bTry || bExcept || !bFilter)
+ {
+ Fail("");
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+
+}
diff --git a/src/pal/tests/palsuite/exception_handling/PAL_EXCEPT_FILTER/test2/testinfo.dat b/src/pal/tests/palsuite/exception_handling/PAL_EXCEPT_FILTER/test2/testinfo.dat
new file mode 100644
index 0000000000..729d2a4c49
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/PAL_EXCEPT_FILTER/test2/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = exception_handling
+Function = PAL_EXCEPT_FILTER
+Name = Test for PAL_EXCEPT_FILTER
+Type = DEFAULT
+EXE1 = pal_except_filter
+LANG = cpp
+Description
+= Tests the PAL implementation of the PAL_EXCEPT_FILTER. An
+= exception is forced and the filter returns
+= EXCEPTION_CONTINUE_EXECUTION to allow execution to continue.
diff --git a/src/pal/tests/palsuite/exception_handling/PAL_EXCEPT_FILTER/test3/CMakeLists.txt b/src/pal/tests/palsuite/exception_handling/PAL_EXCEPT_FILTER/test3/CMakeLists.txt
new file mode 100644
index 0000000000..cc68fb031c
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/PAL_EXCEPT_FILTER/test3/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ pal_except_filter.c
+)
+
+add_executable(paltest_pal_except_filter_test3
+ ${SOURCES}
+)
+
+add_dependencies(paltest_pal_except_filter_test3 coreclrpal)
+
+target_link_libraries(paltest_pal_except_filter_test3
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/exception_handling/PAL_EXCEPT_FILTER/test3/pal_except_filter.c b/src/pal/tests/palsuite/exception_handling/PAL_EXCEPT_FILTER/test3/pal_except_filter.c
new file mode 100644
index 0000000000..20c36840b1
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/PAL_EXCEPT_FILTER/test3/pal_except_filter.c
@@ -0,0 +1,206 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: pal_except_filter.c (test 3)
+**
+** Purpose: Tests the PAL implementation of the PAL_EXCEPT_FILTER in the
+** presence of a call stack. An
+** exception is forced and passed to two nested exception filters for
+** consideration. The first filter returns EXCEPTION_CONTINUE_SEARCH
+** so the second can run and return EXCEPTION_EXECUTE_HANDLER. The
+** initial exception handler should be skipped, and the second
+** executed
+**
+**
+**===================================================================*/
+
+
+
+#include <palsuite.h>
+
+BOOL bFilterCS = FALSE;
+BOOL bFilterEE = FALSE;
+BOOL bTry1 = FALSE;
+BOOL bTry2 = FALSE;
+BOOL bExcept1 = FALSE;
+BOOL bExcept2 = FALSE;
+BOOL bContinued = FALSE;
+const int nValidator = 12321;
+
+LONG ContSearchFilter(EXCEPTION_POINTERS* ep, LPVOID pnTestInt)
+{
+
+ /* let the main know we've hit the filter function */
+ bFilterCS = TRUE;
+
+ if (!bTry1 || !bTry2)
+ {
+ Fail("PAL_EXCEPT_FILTER: ERROR -> Something weird is going on."
+ " The ContSearch filter was hit without PAL_TRY being hit.\n");
+ }
+
+ if (bFilterEE)
+ {
+ Fail("PAL_EXCEPT_FILTER: ERROR -> Something weird is going on."
+ " The ContSearch filter was hit after the ExecuteException "
+ "filter.\n");
+ }
+
+ return EXCEPTION_CONTINUE_SEARCH;
+}
+
+LONG ExecExeptionFilter(EXCEPTION_POINTERS* ep, LPVOID pnTestInt)
+{
+ /* let the main know we've hit the filter function */
+ bFilterEE = TRUE;
+
+ if (!bTry1 || !bTry2)
+ {
+ Fail("PAL_EXCEPT_FILTER: ERROR -> Something weird is going on."
+ " The ContSearch filter was hit without PAL_TRY being hit.\n");
+ }
+
+ if (!bFilterCS)
+ {
+ Fail("PAL_EXCEPT_FILTER: ERROR -> Something weird is going on."
+ " The ExecExeption filter was hit before the ContSearch "
+ "filter.\n");
+ }
+ return EXCEPTION_EXECUTE_HANDLER;
+}
+
+void NestedFunc1 (void)
+{
+ int* p = 0x00000000; /* pointer to NULL */
+
+ PAL_TRY
+ {
+ if (bExcept1 || bExcept2)
+ {
+ Fail("PAL_EXCEPT_FILTER: ERROR -> Something weird is going on."
+ " PAL_EXCEPT_FILTER was hit before PAL_TRY.\n");
+ }
+ bTry2 = TRUE; /* indicate we hit the inner PAL_TRY block */
+ *p = 13; /* causes an access violation exception */
+
+ Fail("PAL_EXCEPT_FILTER: ERROR -> Something weird is going on."
+ " We executed beyond the trapping code.\n");
+ }
+ PAL_EXCEPT_FILTER(ContSearchFilter, (LPVOID)&nValidator)
+ {
+ Fail("PAL_EXCEPT_FILTER: ERROR -> Something weird is going on."
+ " The dummy handler was "
+ "being hit.\n");
+ bExcept2 = TRUE; /* indicate we hit the inner block */
+ }
+ PAL_ENDTRY;
+
+}
+
+void NestedFunc2 (void)
+{
+ NestedFunc1();
+}
+
+int __cdecl main(int argc, char *argv[])
+{
+ if (0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ /*
+ ** test to make sure we get into the second exception block only based
+ ** on the return codes of the filters
+ */
+
+ PAL_TRY
+ {
+ if (bExcept1 || bExcept2)
+ {
+ Fail("PAL_EXCEPT_FILTER: ERROR -> Something weird is going on."
+ " PAL_EXCEPT_FILTER was hit before PAL_TRY.\n");
+ }
+ bTry1 = TRUE; /* indicate we hit the outer PAL_TRY block */
+
+ NestedFunc2();
+
+ Fail("PAL_EXCEPT_FILTER: ERROR -> Something weird is going on."
+ " We executed beyond the trapping code.\n");
+ }
+ PAL_EXCEPT_FILTER(ExecExeptionFilter, (LPVOID)&nValidator)
+ {
+ if (!bTry1)
+ {
+ Fail("PAL_EXCEPT_FILTER: ERROR -> Something weird is going on."
+ " PAL_EXCEPT_FILTER's handler was hit without PAL_TRY's code "
+ "being hit.\n");
+ }
+ if (!bTry2)
+ {
+ Fail("PAL_EXCEPT_FILTER: ERROR -> Something weird is going on."
+ " PAL_EXCEPT_FILTER's handler was hit without PAL_TRY's code "
+ "being hit.\n");
+ }
+ if (!bFilterCS)
+ {
+ Fail("PAL_EXCEPT_FILTER: ERROR -> Something weird is going on."
+ " PAL_EXCEPT_FILTER's handler was hit without the inner filter "
+ "being hit.\n");
+ }
+ if (!bFilterEE)
+ {
+ Fail("PAL_EXCEPT_FILTER: ERROR -> Something weird is going on."
+ " PAL_EXCEPT_FILTER's handler was hit without the outer filter "
+ "being hit.\n");
+ }
+ bExcept1 = TRUE; /* indicate we hit the outer block */
+ }
+ PAL_ENDTRY;
+
+ if (!bTry1)
+ {
+ Trace("PAL_EXCEPT_FILTER: ERROR -> It appears the code in the outer"
+ " PAL_TRY block was not executed.\n");
+ }
+
+ if (bExcept2)
+ {
+ Trace("PAL_EXCEPT_FILTER: ERROR -> It appears the code in the "
+ "inner PAL_EXCEPT_FILTER block was executed.\n");
+ }
+ if (!bExcept1)
+ {
+ Trace("PAL_EXCEPT_FILTER: ERROR -> It appears the code in the "
+ "outer PAL_EXCEPT_FILTER block was not executed.\n");
+ }
+
+ if (!bFilterCS)
+ {
+ Trace("PAL_EXCEPT_FILTER: ERROR -> It appears the code in the "
+ "search continuing filter"
+ " function was not executed.\n");
+ }
+ if (!bFilterEE)
+ {
+ Trace("PAL_EXCEPT_FILTER: ERROR -> It appears the code in the "
+ "execute handler filter"
+ " function was not executed.\n");
+ }
+
+
+ /* did we hit all the code blocks? */
+ if(!bTry1 || !bTry2 || !bExcept1 || bExcept2 || !bFilterEE || !bFilterCS )
+ {
+ Fail("");
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+
+}
diff --git a/src/pal/tests/palsuite/exception_handling/PAL_EXCEPT_FILTER/test3/testinfo.dat b/src/pal/tests/palsuite/exception_handling/PAL_EXCEPT_FILTER/test3/testinfo.dat
new file mode 100644
index 0000000000..d2df399392
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/PAL_EXCEPT_FILTER/test3/testinfo.dat
@@ -0,0 +1,19 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = exception_handling
+Function = PAL_EXCEPT_FILTER_EX
+Name = Test for nested PAL_EXCEPT_FILTER functions & EXCEPTION_CONTINUE_SEARCH
+Type = DEFAULT
+EXE1 = pal_except_filter
+LANG = cpp
+Description
+= Tests the PAL implementation of the PAL_EXCEPT_FILTER with nested
+= functions to build a call stack. An
+= exception is forced and passed to two nested exception filters for
+= consideration. The first filter returns EXCEPTION_CONTINUE_SEARCH
+= so the second can run and return EXCEPTION_EXECUTE_HANDLER. The
+= initial exception handler should be skipped, and the second
+= executed
diff --git a/src/pal/tests/palsuite/exception_handling/PAL_EXCEPT_FILTER_EX/CMakeLists.txt b/src/pal/tests/palsuite/exception_handling/PAL_EXCEPT_FILTER_EX/CMakeLists.txt
new file mode 100644
index 0000000000..1962ade358
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/PAL_EXCEPT_FILTER_EX/CMakeLists.txt
@@ -0,0 +1,6 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+add_subdirectory(test3)
+
diff --git a/src/pal/tests/palsuite/exception_handling/PAL_EXCEPT_FILTER_EX/test1/CMakeLists.txt b/src/pal/tests/palsuite/exception_handling/PAL_EXCEPT_FILTER_EX/test1/CMakeLists.txt
new file mode 100644
index 0000000000..21c3b5d33c
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/PAL_EXCEPT_FILTER_EX/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ PAL_EXCEPT_FILTER_EX.c
+)
+
+add_executable(paltest_pal_except_filter_ex_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_pal_except_filter_ex_test1 coreclrpal)
+
+target_link_libraries(paltest_pal_except_filter_ex_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/exception_handling/PAL_EXCEPT_FILTER_EX/test1/PAL_EXCEPT_FILTER_EX.c b/src/pal/tests/palsuite/exception_handling/PAL_EXCEPT_FILTER_EX/test1/PAL_EXCEPT_FILTER_EX.c
new file mode 100644
index 0000000000..91f392d8d7
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/PAL_EXCEPT_FILTER_EX/test1/PAL_EXCEPT_FILTER_EX.c
@@ -0,0 +1,197 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: PAL_EXCEPT_FILTER_EX.c (test 1)
+**
+** Purpose: Tests the PAL implementation of the PAL_EXCEPT_FILTER_EX.
+** There are two try blocks in this test. The first forces an
+** exception error to force hitting the first filter. The second
+** doesn't to make sure we don't hit the filter. A value is also
+** passed into the filter program and it is validated to make sure
+** it was passed correctly.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+BOOL bFilter = FALSE;
+BOOL bTry = FALSE;
+const int nValidator = 12321;
+
+
+/**
+**
+** Filter function for the first try block
+**
+**/
+
+LONG Filter_01(EXCEPTION_POINTERS* ep, VOID *pnTestInt)
+{
+ int nTestInt = *(int *)pnTestInt;
+
+ /* let the main know we've hit the filter function */
+ bFilter = TRUE;
+
+ if (!bTry)
+ {
+ Fail("PAL_EXCEPT_FILTER_EX: ERROR -> Something weird is going on."
+ " The filter was hit without PAL_TRY being hit.\n");
+ }
+
+ /* was the correct value passed? */
+ if (nValidator != nTestInt)
+ {
+ Fail("PAL_EXCEPT_FILTER_EX: ERROR -> Parameter passed to filter"
+ " function should have been \"%d\" but was \"%d\".\n",
+ nValidator,
+ nTestInt);
+ }
+
+ return EXCEPTION_EXECUTE_HANDLER;
+}
+
+
+/**
+**
+** Filter function for the second try block. We shouldn't
+** hit this function.
+**
+**/
+
+LONG Filter_02(EXCEPTION_POINTERS* ep, VOID *pnTestInt)
+{
+ /* let the main know we've hit the filter function */
+ bFilter = TRUE;
+
+ return EXCEPTION_EXECUTE_HANDLER;
+}
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ int* p = 0x00000000;
+ BOOL bExcept = FALSE;
+
+ if (0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ /*
+ ** test to make sure we get into the exception block
+ */
+
+ PAL_TRY
+ {
+ if (bExcept)
+ {
+ Fail("PAL_EXCEPT_FILTER_EX: ERROR -> Something weird is going on."
+ " The first PAL_EXCEPT_FILTER_EX was hit before PAL_TRY.\n");
+ }
+
+ bTry = TRUE; /* indicate we hit the PAL_TRY block */
+ *p = 13; /* causes an access violation exception */
+
+ Fail("PAL_EXCEPT_FILTER_EX: ERROR -> code was executed after the "
+ "access violation.\n");
+ }
+ PAL_EXCEPT_FILTER(Filter_01, (LPVOID)&nValidator)
+ {
+ if (!bTry)
+ {
+ Fail("PAL_EXCEPT_FILTER_EX: ERROR -> Something weird is going on."
+ " PAL_EXCEPT_FILTER_EX was hit without PAL_TRY being hit.\n");
+ }
+ bExcept = TRUE; /* indicate we hit the PAL_EXCEPT_FILTER_EX block */
+ }
+ PAL_ENDTRY;
+
+ if (!bTry)
+ {
+ Trace("PAL_EXCEPT_FILTER_EX: ERROR -> It appears the code in the "
+ "first PAL_TRY block was not executed.\n");
+ }
+
+ if (!bExcept)
+ {
+ Trace("PAL_EXCEPT_FILTER_EX: ERROR -> It appears the code in the "
+ "first PAL_EXCEPT_FILTER_EX block was not executed.\n");
+ }
+
+ if (!bFilter)
+ {
+ Trace("PAL_EXCEPT_FILTER_EX: ERROR -> It appears the code in the first"
+ " filter function was not executed.\n");
+ }
+
+
+ /* did we hit all the code blocks? */
+ if(!bTry || !bExcept || !bFilter)
+ {
+ Fail("");
+ }
+
+ bTry = bExcept = bFilter = FALSE;
+
+
+ /*
+ ** test to make sure we skip the exception block
+ */
+
+ PAL_TRY
+ {
+ if (bExcept)
+ {
+ Fail("PAL_EXCEPT_FILTER_EX: ERROR -> Something weird is going on."
+ " Second PAL_EXCEPT_FILTER_EX was hit before PAL_TRY.\n");
+ }
+ bTry = TRUE; /* indicate we hit the PAL_TRY block */
+ }
+ PAL_EXCEPT_FILTER(Filter_02, (LPVOID)&nValidator)
+ {
+ if (!bTry)
+ {
+ Fail("PAL_EXCEPT_FILTER_EX: ERROR -> Something weird is going on."
+ " PAL_EXCEPT_FILTER_EX was hit without PAL_TRY being hit.\n");
+ }
+ bExcept = TRUE; /* indicate we hit the PAL_EXCEPT_FILTER_EX block */
+ }
+ PAL_ENDTRY;
+
+ if (!bTry)
+ {
+ Trace("PAL_EXCEPT_FILTER_EX: ERROR -> It appears the code in the "
+ "second PAL_TRY block was not executed.\n");
+ }
+
+ if (bExcept)
+ {
+ Trace("PAL_EXCEPT_FILTER_EX: ERROR -> It appears the code in the "
+ "second PAL_EXCEPT_FILTER_EX block was executed even though an"
+ " exception was not triggered.\n");
+ }
+
+ if (bFilter)
+ {
+ Trace("PAL_EXCEPT_FILTER_EX: ERROR -> It appears the code in the second"
+ " filter function was executed even though an exception was"
+ " not triggered.\n");
+ }
+
+
+ /* did we hit all the correct code blocks? */
+ if(!bTry || bExcept || bFilter)
+ {
+ Fail("");
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+
+}
diff --git a/src/pal/tests/palsuite/exception_handling/PAL_EXCEPT_FILTER_EX/test1/testinfo.dat b/src/pal/tests/palsuite/exception_handling/PAL_EXCEPT_FILTER_EX/test1/testinfo.dat
new file mode 100644
index 0000000000..1d8f8f600e
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/PAL_EXCEPT_FILTER_EX/test1/testinfo.dat
@@ -0,0 +1,18 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = exception_handling
+Function = PAL_EXCEPT_FILTER_EX
+Name = Test for PAL_EXCEPT_FILTER_EX
+Type = DEFAULT
+EXE1 = pal_except_filter_ex
+LANG = cpp
+Description
+= Tests the PAL implementation of the PAL_EXCEPT_FILTER_EX.
+= There are two try blocks in this test. The first forces an
+= exception error to force hitting the first filter. The second
+= doesn't to make sure we don't hit the filter. A value is also
+= passed into the filter program and it is validated to make sure
+= it was passed correctly.
diff --git a/src/pal/tests/palsuite/exception_handling/PAL_EXCEPT_FILTER_EX/test2/CMakeLists.txt b/src/pal/tests/palsuite/exception_handling/PAL_EXCEPT_FILTER_EX/test2/CMakeLists.txt
new file mode 100644
index 0000000000..350acff036
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/PAL_EXCEPT_FILTER_EX/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ pal_except_filter_ex.c
+)
+
+add_executable(paltest_pal_except_filter_ex_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_pal_except_filter_ex_test2 coreclrpal)
+
+target_link_libraries(paltest_pal_except_filter_ex_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/exception_handling/PAL_EXCEPT_FILTER_EX/test2/pal_except_filter_ex.c b/src/pal/tests/palsuite/exception_handling/PAL_EXCEPT_FILTER_EX/test2/pal_except_filter_ex.c
new file mode 100644
index 0000000000..ab25c49733
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/PAL_EXCEPT_FILTER_EX/test2/pal_except_filter_ex.c
@@ -0,0 +1,142 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: PAL_EXCEPT_FILTER_EX.c (test 2)
+**
+** Purpose: Tests the PAL implementation of the PAL_EXCEPT_FILTER_EX.
+** There is a nested try blocks in this test. The nested
+** PAL_TRY creates an exception and the FILTER creates another.
+** This test makes sure that this case does not end in a
+** infinite loop.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+BOOL bFilter = FALSE;
+BOOL bTry = FALSE;
+BOOL bTry2 = FALSE;
+const int nValidator = 12321;
+
+/* Filter function for the first try block.
+ */
+LONG Filter_01(EXCEPTION_POINTERS* ep, VOID *pnTestInt)
+{
+ int nTestInt = *(int *)pnTestInt;
+
+ /* Signal main() that filter has been executed. */
+ bFilter = TRUE;
+
+ if (!bTry)
+ {
+ Fail("ERROR: The filter was executed without "
+ "entering the first PAL_TRY.\n");
+ }
+
+ if (!bTry2)
+ {
+ Fail("ERROR: The filter was executed without "
+ "entering the second PAL_TRY.\n");
+ }
+
+ /* Was the correct value passed? */
+ if (nValidator != nTestInt)
+ {
+ Fail("ERROR: Parameter passed to filter function "
+ "should have been \"%d\" but was \"%d\".\n",
+ nValidator,
+ nTestInt);
+ }
+
+ return EXCEPTION_EXECUTE_HANDLER;
+}
+
+int __cdecl main(int argc, char *argv[])
+{
+ int* p = 0x00000000;
+ BOOL bExcept = FALSE;
+ BOOL bExcept2 = FALSE;
+
+ /* Initalize the PAL.
+ */
+ if (0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ /* Test a nested PAL_Try block.
+ */
+ PAL_TRY
+ {
+ /* Signal entry into first PAL_TRY block.*/
+ bTry = TRUE;
+
+ PAL_TRY
+ {
+ /* Signal entry into second PAL_TRY block.*/
+ bTry2 = TRUE;
+ /* Cause an exception.*/
+ *p = 13;
+ }
+ PAL_EXCEPT_FILTER(Filter_01, (LPVOID)&nValidator)
+ {
+ /* Signal entry into second PAL_EXCEPT filter.*/
+ bExcept = TRUE;
+ /* Cause another exception.*/
+ *p = 13;
+ }
+ PAL_ENDTRY
+
+ }
+ PAL_EXCEPT_FILTER(Filter_01, (LPVOID)&nValidator)
+ {
+ /* Signal entry into second PAL_EXCEPT filter.*/
+ bExcept2 = TRUE;
+ }
+ PAL_ENDTRY;
+
+ if (!bTry)
+ {
+ Trace("ERROR: The code in the first "
+ "PAL_TRY block was not executed.\n");
+ }
+
+ if (!bTry2)
+ {
+ Trace("ERROR: The code in the nested "
+ "PAL_TRY block was not executed.\n");
+ }
+
+ if (!bExcept)
+ {
+ Trace("ERROR: The code in the first "
+ "PAL_EXCEPT_FILTER_EX block was not executed.\n");
+ }
+
+ if (!bExcept2)
+ {
+ Trace("ERROR: The code in the second "
+ "PAL_EXCEPT_FILTER_EX block was not executed.\n");
+ }
+
+ if (!bFilter)
+ {
+ Trace("ERROR: The code in the first "
+ "filter function was not executed.\n");
+ }
+
+ if(!bTry || !bTry2 || !bExcept || !bExcept2 || !bFilter )
+ {
+ Fail("");
+ }
+
+ /* Terminate the PAL.
+ */
+ PAL_Terminate();
+ return PASS;
+
+}
diff --git a/src/pal/tests/palsuite/exception_handling/PAL_EXCEPT_FILTER_EX/test2/testinfo.dat b/src/pal/tests/palsuite/exception_handling/PAL_EXCEPT_FILTER_EX/test2/testinfo.dat
new file mode 100644
index 0000000000..0343d133e8
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/PAL_EXCEPT_FILTER_EX/test2/testinfo.dat
@@ -0,0 +1,17 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = exception_handling
+Function = PAL_EXCEPT_FILTER_EX
+Name = Test for PAL_EXCEPT_FILTER_EX
+Type = DEFAULT
+EXE1 = pal_except_filter_ex
+LANG = cpp
+Description
+= Tests the PAL implementation of the PAL_EXCEPT_FILTER_EX.
+= There is a nested try blocks in this test. The nested
+= PAL_TRY creates an exception and the FILTER creates another.
+= This test makes sure that this case does not end in a
+= infinite loop.
diff --git a/src/pal/tests/palsuite/exception_handling/PAL_EXCEPT_FILTER_EX/test3/CMakeLists.txt b/src/pal/tests/palsuite/exception_handling/PAL_EXCEPT_FILTER_EX/test3/CMakeLists.txt
new file mode 100644
index 0000000000..7f485c8ca4
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/PAL_EXCEPT_FILTER_EX/test3/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ pal_except_filter.c
+)
+
+add_executable(paltest_pal_except_filter_ex_test3
+ ${SOURCES}
+)
+
+add_dependencies(paltest_pal_except_filter_ex_test3 coreclrpal)
+
+target_link_libraries(paltest_pal_except_filter_ex_test3
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/exception_handling/PAL_EXCEPT_FILTER_EX/test3/pal_except_filter.c b/src/pal/tests/palsuite/exception_handling/PAL_EXCEPT_FILTER_EX/test3/pal_except_filter.c
new file mode 100644
index 0000000000..a17cb4f6b3
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/PAL_EXCEPT_FILTER_EX/test3/pal_except_filter.c
@@ -0,0 +1,208 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: pal_except_filter_ex.c (test 3)
+**
+** Purpose: Tests the PAL implementation of the PAL_EXCEPT_FILTER_EX. An
+** exception is forced and passed to two nested exception filters for
+** consideration. The first filter returns EXCEPTION_CONTINUE_SEARCH
+** so the second can run and return EXCEPTION_EXECUTE_HANDLER. The
+** initial exception handler should be skipped, and the second
+** executed
+**
+**
+**===================================================================*/
+
+
+
+#include <palsuite.h>
+
+BOOL bFilterCS = FALSE;
+BOOL bFilterEE = FALSE;
+BOOL bTry1 = FALSE;
+BOOL bTry2 = FALSE;
+BOOL bContinued = FALSE;
+const int nValidator = 12321;
+
+LONG ContSearchFilter(EXCEPTION_POINTERS* ep, LPVOID pnTestInt)
+{
+
+ /* let the main know we've hit the filter function */
+ bFilterCS = TRUE;
+
+ if (!bTry1 || !bTry2)
+ {
+ Fail("PAL_EXCEPT_FILTER: ERROR -> Something weird is going on."
+ " The ContSearch filter was hit without PAL_TRY being hit.\n");
+ }
+
+ if (bFilterEE)
+ {
+ Fail("PAL_EXCEPT_FILTER: ERROR -> Something weird is going on."
+ " The ContSearch filter was hit after the ExecuteException "
+ "filter.\n");
+ }
+
+ return EXCEPTION_CONTINUE_SEARCH;
+}
+
+LONG ExecExeptionFilter(EXCEPTION_POINTERS* ep, LPVOID pnTestInt)
+{
+ /* let the main know we've hit the filter function */
+ bFilterEE = TRUE;
+
+ if (!bTry1 || !bTry2)
+ {
+ Fail("PAL_EXCEPT_FILTER: ERROR -> Something weird is going on."
+ " The ContSearch filter was hit without PAL_TRY being hit.\n");
+ }
+
+ if (!bFilterCS)
+ {
+ Fail("PAL_EXCEPT_FILTER: ERROR -> Something weird is going on."
+ " The ExecExeption filter was hit before the ContSearch "
+ "filter.\n");
+ }
+ return EXCEPTION_EXECUTE_HANDLER;
+}
+
+int __cdecl main(int argc, char *argv[])
+{
+ int* p = 0x00000000; /* pointer to NULL */
+ BOOL bExcept1 = FALSE;
+ BOOL bExcept2 = FALSE;
+
+ if (0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ /*
+ ** test to make sure we get into the second exception block only based
+ ** on the return codes of the filters
+ */
+
+ PAL_TRY
+ {
+ if (bExcept1 || bExcept2)
+ {
+ Fail("PAL_EXCEPT_FILTER: ERROR -> Something weird is going on."
+ " PAL_EXCEPT_FILTER was hit before PAL_TRY.\n");
+ }
+ bTry1 = TRUE; /* indicate we hit the outer PAL_TRY block */
+
+ PAL_TRY
+ {
+ if (bExcept1 || bExcept2)
+ {
+ Fail("PAL_EXCEPT_FILTER: ERROR -> Something weird is going on."
+ " PAL_EXCEPT_FILTER was hit before PAL_TRY.\n");
+ }
+ bTry2 = TRUE; /* indicate we hit the inner PAL_TRY block */
+ *p = 13; /* causes an access violation exception */
+
+ Fail("PAL_EXCEPT_FILTER: ERROR -> Something weird is going on."
+ " We executed beyond the trapping code.\n");
+ }
+
+ PAL_EXCEPT_FILTER(ContSearchFilter, (LPVOID)&nValidator)
+ {
+ Fail("PAL_EXCEPT_FILTER: ERROR -> Something weird is going on."
+ " The dummy handler was "
+ "being hit.\n");
+ }
+ PAL_ENDTRY;
+
+ bExcept2 = TRUE; /* indicate we hit the inner block */
+ }
+ PAL_EXCEPT_FILTER(ExecExeptionFilter, (LPVOID)&nValidator)
+ {
+ if (!bTry1)
+ {
+ Fail("PAL_EXCEPT_FILTER: ERROR -> Something weird is going on."
+ " PAL_EXCEPT_FILTER's handler was hit without PAL_TRY's code "
+ "being hit.\n");
+ }
+ if (!bTry2)
+ {
+ Fail("PAL_EXCEPT_FILTER: ERROR -> Something weird is going on."
+ " PAL_EXCEPT_FILTER's handler was hit without PAL_TRY's code "
+ "being hit.\n");
+ }
+ if (!bFilterCS)
+ {
+ Fail("PAL_EXCEPT_FILTER: ERROR -> Something weird is going on. "
+ "PAL_EXCEPT_FILTER's handler was hit without "
+ "the inner filter being hit.\n");
+ }
+ if (!bFilterEE)
+ {
+ Fail("PAL_EXCEPT_FILTER: ERROR -> Something weird is going on. "
+ "PAL_EXCEPT_FILTER's handler was hit without "
+ "the outer filter being hit.\n");
+ }
+ bExcept1 = TRUE; /* indicate we hit the outer block */
+ }
+ PAL_ENDTRY;
+
+ if (!bTry1)
+ {
+ Trace("PAL_EXCEPT_FILTER: ERROR -> It appears the code in the outer"
+ " PAL_TRY block was not executed.\n");
+ }
+
+ if (!bTry2)
+ {
+ Trace("PAL_EXCEPT_FILTER: ERROR -> It appears the code in the inner"
+ " PAL_TRY block was not executed.\n");
+ }
+
+ if (bExcept2)
+ {
+ Trace("PAL_EXCEPT_FILTER: ERROR -> It appears the code in the "
+ "inner PAL_EXCEPT_FILTER block was executed.\n");
+ }
+ if (!bExcept1)
+ {
+ Trace("PAL_EXCEPT_FILTER: ERROR -> It appears the code in the "
+ "outer PAL_EXCEPT_FILTER block was not executed.\n");
+ }
+
+ if (!bFilterCS)
+ {
+ Trace("PAL_EXCEPT_FILTER: ERROR -> It appears the code in the "
+ "search continuing filter"
+ " function was not executed.\n");
+ }
+ if (!bFilterEE)
+ {
+ Trace("PAL_EXCEPT_FILTER: ERROR -> It appears the code in the "
+ "execute handler filter"
+ " function was not executed.\n");
+ }
+
+
+ if (!bTry2)
+ {
+ Trace("PAL_EXCEPT_FILTER: ERROR -> It appears the code in the PAL_TRY "
+ "block after the exception causing statements "
+ "was not executed.\n");
+ }
+
+ /* did we hit all the code blocks? */
+ if(!bTry1 || !bTry2 || !bExcept1 || bExcept2 || !bFilterEE || !bFilterCS )
+ {
+ Fail("");
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+
+}
+
+
diff --git a/src/pal/tests/palsuite/exception_handling/PAL_EXCEPT_FILTER_EX/test3/testinfo.dat b/src/pal/tests/palsuite/exception_handling/PAL_EXCEPT_FILTER_EX/test3/testinfo.dat
new file mode 100644
index 0000000000..568296c399
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/PAL_EXCEPT_FILTER_EX/test3/testinfo.dat
@@ -0,0 +1,18 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = exception_handling
+Function = PAL_EXCEPT_FILTER_EX
+Name = Test for nested PAL_EXCEPT_FILTER_EX & EXCEPTION_CONTINUE_SEARCH
+Type = DEFAULT
+EXE1 = pal_except_filter
+LANG = cpp
+Description
+= Tests the PAL implementation of the PAL_EXCEPT_FILTER_EX. An
+= exception is forced and passed to two nested exception filters for
+= consideration. The first filter returns EXCEPTION_CONTINUE_SEARCH
+= so the second can run and return EXCEPTION_EXECUTE_HANDLER. The
+= initial exception handler should be skipped, and the second
+= executed
diff --git a/src/pal/tests/palsuite/exception_handling/PAL_TRY_EXCEPT/CMakeLists.txt b/src/pal/tests/palsuite/exception_handling/PAL_TRY_EXCEPT/CMakeLists.txt
new file mode 100644
index 0000000000..ef14ea5352
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/PAL_TRY_EXCEPT/CMakeLists.txt
@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+
diff --git a/src/pal/tests/palsuite/exception_handling/PAL_TRY_EXCEPT/test1/CMakeLists.txt b/src/pal/tests/palsuite/exception_handling/PAL_TRY_EXCEPT/test1/CMakeLists.txt
new file mode 100644
index 0000000000..8a1a832361
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/PAL_TRY_EXCEPT/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ PAL_TRY_EXCEPT.c
+)
+
+add_executable(paltest_pal_try_except_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_pal_try_except_test1 coreclrpal)
+
+target_link_libraries(paltest_pal_try_except_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/exception_handling/PAL_TRY_EXCEPT/test1/PAL_TRY_EXCEPT.c b/src/pal/tests/palsuite/exception_handling/PAL_TRY_EXCEPT/test1/PAL_TRY_EXCEPT.c
new file mode 100644
index 0000000000..4fb09bd276
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/PAL_TRY_EXCEPT/test1/PAL_TRY_EXCEPT.c
@@ -0,0 +1,82 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: PAL_TRY_EXCEPT.c (test 1)
+**
+** Purpose: Tests the PAL implementation of the PAL_TRY and
+** PAL_EXCEPT functions. An exception is forced to ensure
+** the exception block is hit.
+**
+**
+**===================================================================*/
+
+
+
+#include <palsuite.h>
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ int* p = 0x00000000; /* NULL pointer */
+ BOOL bTry = FALSE;
+ BOOL bExcept = FALSE;
+
+ if (0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ /*
+ ** test to make sure we get into the exception block
+ */
+
+ PAL_TRY
+ {
+ if (bExcept)
+ {
+ Fail("PAL_TRY_EXCEPT: ERROR -> Something weird is going on."
+ " PAL_EXCEPT was hit before PAL_TRY.\n");
+ }
+ bTry = TRUE; /* indicate we hit the PAL_TRY block */
+ *p = 13; /* causes an access violation exception */
+ Fail("PAL_TRY_EXCEPT: ERROR -> code was executed after the "
+ "access violation.\n");
+ }
+ PAL_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ if (!bTry)
+ {
+ Fail("PAL_TRY_EXCEPT: ERROR -> Something weird is going on."
+ " PAL_EXCEPT was hit without PAL_TRY being hit.\n");
+ }
+ bExcept = TRUE; /* indicate we hit the PAL_EXCEPT block */
+ }
+ PAL_ENDTRY;
+
+ if (!bTry)
+ {
+ Trace("PAL_TRY_EXCEPT: ERROR -> It appears the code in the PAL_TRY"
+ " block was not executed.\n");
+ }
+
+ if (!bExcept)
+ {
+ Trace("PAL_TRY_EXCEPT: ERROR -> It appears the code in the PAL_EXCEPT"
+ " block was not executed.\n");
+ }
+
+ /* did we hit all the code blocks? */
+ if(!bTry || !bExcept)
+ {
+ Fail("");
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+
+}
diff --git a/src/pal/tests/palsuite/exception_handling/PAL_TRY_EXCEPT/test1/testinfo.dat b/src/pal/tests/palsuite/exception_handling/PAL_TRY_EXCEPT/test1/testinfo.dat
new file mode 100644
index 0000000000..1f663a8bc5
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/PAL_TRY_EXCEPT/test1/testinfo.dat
@@ -0,0 +1,16 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = exception_handling
+Function = PAL_TRY and PAL_EXCEPT
+Name = Test for PAL_TRY and PAL_EXCEPT
+Type = DEFAULT
+EXE1 = pal_try_except
+LANG = cpp
+Description
+= Since these two are so closely connected, they are tested together.
+= In the PAL_TRY block, an access violation is forced to gain
+= access to the PAL_EXCEPT block. Booleans are used to ensure
+= each of the code blocks are hit.
diff --git a/src/pal/tests/palsuite/exception_handling/PAL_TRY_EXCEPT/test2/CMakeLists.txt b/src/pal/tests/palsuite/exception_handling/PAL_TRY_EXCEPT/test2/CMakeLists.txt
new file mode 100644
index 0000000000..cdf371926c
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/PAL_TRY_EXCEPT/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ PAL_TRY_EXCEPT.c
+)
+
+add_executable(paltest_pal_try_except_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_pal_try_except_test2 coreclrpal)
+
+target_link_libraries(paltest_pal_try_except_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/exception_handling/PAL_TRY_EXCEPT/test2/PAL_TRY_EXCEPT.c b/src/pal/tests/palsuite/exception_handling/PAL_TRY_EXCEPT/test2/PAL_TRY_EXCEPT.c
new file mode 100644
index 0000000000..eb7b9d1257
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/PAL_TRY_EXCEPT/test2/PAL_TRY_EXCEPT.c
@@ -0,0 +1,68 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: PAL_TRY_EXCEPT.c (test 2)
+**
+** Purpose: Tests the PAL implementation of the PAL_TRY and
+** PAL_EXCEPT functions. Tests that the EXCEPTION block
+** is missed if no exceptions happen
+**
+**
+**===================================================================*/
+
+
+
+#include <palsuite.h>
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ BOOL bTry = FALSE;
+ BOOL bExcept = FALSE;
+
+ if (0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ /*
+ ** Test to make sure we skip the exception block.
+ */
+
+ PAL_TRY
+ {
+ bTry = TRUE; /* indicate we hit the PAL_TRY block */
+ }
+ PAL_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ bExcept = TRUE; /* indicate we hit the PAL_EXCEPT block */
+ }
+ PAL_ENDTRY;
+
+ if (!bTry)
+ {
+ Trace("PAL_TRY_EXCEPT: ERROR -> It appears the code in the PAL_TRY"
+ " block was not executed.\n");
+ }
+
+ if (bExcept)
+ {
+ Trace("PAL_TRY_EXCEPT: ERROR -> It appears the code in the PAL_EXCEPT"
+ " block was executed even though no exception was supposed to"
+ " happen.\n");
+ }
+
+ /* did we hit the correct code blocks? */
+ if(!bTry || bExcept)
+ {
+ Fail("");
+ }
+
+ PAL_Terminate();
+ return PASS;
+
+}
diff --git a/src/pal/tests/palsuite/exception_handling/PAL_TRY_EXCEPT/test2/testinfo.dat b/src/pal/tests/palsuite/exception_handling/PAL_TRY_EXCEPT/test2/testinfo.dat
new file mode 100644
index 0000000000..a5815f5722
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/PAL_TRY_EXCEPT/test2/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = exception_handling
+Function = PAL_TRY and PAL_EXCEPT (test 2)
+Name = Test for PAL_TRY and PAL_EXCEPT
+Type = DEFAULT
+EXE1 = pal_try_except
+LANG = cpp
+Description
+= Since these two are so closely connected, they are tested together.
+= In this test, no exceptions are forced to ensure the EXCEPTION block
+= isn't hit. Booleans are used to ensure the proper code blocks are hit.
diff --git a/src/pal/tests/palsuite/exception_handling/PAL_TRY_EXCEPT_EX/CMakeLists.txt b/src/pal/tests/palsuite/exception_handling/PAL_TRY_EXCEPT_EX/CMakeLists.txt
new file mode 100644
index 0000000000..1962ade358
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/PAL_TRY_EXCEPT_EX/CMakeLists.txt
@@ -0,0 +1,6 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+add_subdirectory(test3)
+
diff --git a/src/pal/tests/palsuite/exception_handling/PAL_TRY_EXCEPT_EX/test1/CMakeLists.txt b/src/pal/tests/palsuite/exception_handling/PAL_TRY_EXCEPT_EX/test1/CMakeLists.txt
new file mode 100644
index 0000000000..c30877f65e
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/PAL_TRY_EXCEPT_EX/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ PAL_TRY_EXCEPT_EX.c
+)
+
+add_executable(paltest_pal_try_except_ex_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_pal_try_except_ex_test1 coreclrpal)
+
+target_link_libraries(paltest_pal_try_except_ex_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/exception_handling/PAL_TRY_EXCEPT_EX/test1/PAL_TRY_EXCEPT_EX.c b/src/pal/tests/palsuite/exception_handling/PAL_TRY_EXCEPT_EX/test1/PAL_TRY_EXCEPT_EX.c
new file mode 100644
index 0000000000..8b4dd7b430
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/PAL_TRY_EXCEPT_EX/test1/PAL_TRY_EXCEPT_EX.c
@@ -0,0 +1,133 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: PAL_TRY_EXCEPT.c (test 1)
+**
+** Purpose: Tests the PAL implementation of the PAL_TRY and
+** PAL_EXCEPT functions. Exceptions are forced to ensure
+** the exception blocks are hit.
+**
+**
+**===================================================================*/
+
+
+
+#include <palsuite.h>
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ int* p = 0x00000000; /* NULL pointer */
+ BOOL bTry = FALSE;
+ BOOL bExcept = FALSE;
+ BOOL bTestA = TRUE;
+
+ if (0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ /*
+ ** test to make sure we get into the exception block
+ */
+
+ PAL_TRY
+ {
+ if (!bTestA)
+ {
+ Fail("PAL_TRY_EXCEPT: ERROR ->"
+ " It appears the first try block was hit a second time.\n");
+ }
+ bTry = TRUE; /* indicate we hit the PAL_TRY block */
+ *p = 13; /* causes an access violation exception */
+ Fail("PAL_TRY_EXCEPT: ERROR -> code was executed after the "
+ "access violation.\n");
+ }
+ PAL_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ if (!bTestA)
+ {
+ Fail("PAL_TRY_EXCEPT: ERROR ->"
+ " It appears the first except block was hit a second time.\n");
+ }
+ bExcept = TRUE; /* indicate we hit the PAL_EXCEPT block */
+ }
+ PAL_ENDTRY;
+
+ if (!bTry)
+ {
+ Trace("PAL_TRY_EXCEPT: ERROR -> It appears the code in the PAL_TRY"
+ " block was not executed.\n");
+ }
+
+ if (!bExcept)
+ {
+ Trace("PAL_TRY_EXCEPT: ERROR -> It appears the code in the first"
+ " PAL_EXCEPT block was not executed.\n");
+ }
+
+ /* did we hit all the code blocks? */
+ if(!bTry || !bExcept)
+ {
+ Fail("");
+ }
+
+
+ /*
+ ** test to make sure we get into the second exception block
+ */
+
+ bTry = FALSE;
+ bExcept = FALSE;
+ bTestA = FALSE; /* we are now going into the second block test */
+
+
+ PAL_TRY
+ {
+ if (bTestA)
+ {
+ Fail("PAL_TRY_EXCEPT: ERROR -> It appears"
+ " the second try block was hit too early.\n");
+ }
+ bTry = TRUE; /* indicate we hit the PAL_TRY block */
+ *p = 13; /* causes an access violation exception */
+ Fail("PAL_TRY_EXCEPT: ERROR -> code was executed after the "
+ "access violation.\n");
+ }
+ PAL_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ if (bTestA)
+ {
+ Fail("PAL_TRY_EXCEPT: ERROR -> It appears"
+ " the second except block was hit too early.\n");
+ }
+ bExcept = TRUE; /* indicate we hit the PAL_EXCEPT block */
+ }
+ PAL_ENDTRY;
+
+ if (!bTry)
+ {
+ Trace("PAL_TRY_EXCEPT: ERROR -> It appears the code in the second"
+ " PAL_TRY block was not executed.");
+ }
+
+ if (!bExcept)
+ {
+ Trace("PAL_TRY_EXCEPT: ERROR -> It appears the code in the PAL_EXCEPT"
+ " block was not executed.");
+ }
+
+ /* did we hit all the code blocks? */
+ if(!bTry || !bExcept)
+ {
+ Fail("\n");
+ }
+
+ PAL_Terminate();
+ return PASS;
+
+}
diff --git a/src/pal/tests/palsuite/exception_handling/PAL_TRY_EXCEPT_EX/test1/testinfo.dat b/src/pal/tests/palsuite/exception_handling/PAL_TRY_EXCEPT_EX/test1/testinfo.dat
new file mode 100644
index 0000000000..b571427935
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/PAL_TRY_EXCEPT_EX/test1/testinfo.dat
@@ -0,0 +1,16 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = exception_handling
+Function = PAL_TRY and PAL_EXCEPT_EX
+Name = Test for PAL_TRY and PAL_EXCEPT_EX
+Type = DEFAULT
+EXE1 = pal_try_except_ex
+LANG = cpp
+Description
+= Since these two are so closely connected, they are tested together.
+= In the PAL_TRY block, an access violation is forced to gain
+= access to the PAL_EXCEPT block. Booleans are used to ensure
+= each of the code blocks are hit.
diff --git a/src/pal/tests/palsuite/exception_handling/PAL_TRY_EXCEPT_EX/test2/CMakeLists.txt b/src/pal/tests/palsuite/exception_handling/PAL_TRY_EXCEPT_EX/test2/CMakeLists.txt
new file mode 100644
index 0000000000..0d4c4db240
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/PAL_TRY_EXCEPT_EX/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ PAL_TRY_EXCEPT_EX.c
+)
+
+add_executable(paltest_pal_try_except_ex_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_pal_try_except_ex_test2 coreclrpal)
+
+target_link_libraries(paltest_pal_try_except_ex_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/exception_handling/PAL_TRY_EXCEPT_EX/test2/PAL_TRY_EXCEPT_EX.c b/src/pal/tests/palsuite/exception_handling/PAL_TRY_EXCEPT_EX/test2/PAL_TRY_EXCEPT_EX.c
new file mode 100644
index 0000000000..5ab4a95ce9
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/PAL_TRY_EXCEPT_EX/test2/PAL_TRY_EXCEPT_EX.c
@@ -0,0 +1,123 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: PAL_TRY_EXCEPT.c (test 2)
+**
+** Purpose: Tests the PAL implementation of the PAL_TRY and
+** PAL_EXCEPT functions. Exceptions are not forced to ensure
+** the proper blocks are hit.
+**
+**
+**===================================================================*/
+
+
+
+#include <palsuite.h>
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ BOOL bTry = FALSE;
+ BOOL bExcept = FALSE;
+ BOOL bTestA = TRUE;
+
+ if (0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ /*
+ ** test to make sure we get into the exception block
+ */
+
+ PAL_TRY
+ {
+ if (!bTestA)
+ {
+ Fail("PAL_TRY_EXCEPT: ERROR ->"
+ " It appears the first try block was hit a second time.\n");
+ }
+ bTry = TRUE; /* indicate we hit the PAL_TRY block */
+ }
+ PAL_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ bExcept = TRUE; /* indicate we hit the PAL_EXCEPT block */
+ }
+ PAL_ENDTRY;
+
+ if (!bTry)
+ {
+ Trace("PAL_TRY_EXCEPT: ERROR -> It appears the code in the PAL_TRY"
+ " block was not executed.\n");
+ }
+
+ if (bExcept)
+ {
+ Trace("PAL_TRY_EXCEPT: ERROR -> It appears the code in the first"
+ " PAL_EXCEPT block was executed even though no exceptions were "
+ "encountered.\n");
+ }
+
+ /* did we hit all the proper code blocks? */
+ if(!bTry || bExcept)
+ {
+ Fail("");
+ }
+
+
+ /*
+ ** test to make sure we skip the second exception block
+ */
+
+ bTry = FALSE;
+ bExcept = FALSE;
+ bTestA = FALSE; /* we are now going into the second block test */
+
+
+ PAL_TRY
+ {
+ if (bTestA)
+ {
+ Fail("PAL_TRY_EXCEPT: ERROR -> It appears"
+ " the second try block was hit too early.\n");
+ }
+ bTry = TRUE; /* indicate we hit the PAL_TRY block */
+ }
+ PAL_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ if (bTestA)
+ {
+ Fail("PAL_TRY_EXCEPT: ERROR -> It appears"
+ " the second except block was hit too early.\n");
+ }
+ bExcept = TRUE; /* indicate we hit the PAL_TRY block */
+ }
+ PAL_ENDTRY;
+
+ if (!bTry)
+ {
+ Trace("PAL_TRY_EXCEPT: ERROR -> It appears the code in the second"
+ " PAL_TRY block was not executed.\n");
+ }
+
+ if (bExcept)
+ {
+ Trace("PAL_TRY_EXCEPT: ERROR -> It appears the code in the second"
+ " PAL_EXCEPT block was executed even though no exceptions were "
+ "encountered.\n");
+ }
+
+ /* did we hit all the proper code blocks? */
+ if(!bTry || bExcept)
+ {
+ Fail("\n");
+ }
+
+ PAL_Terminate();
+ return PASS;
+
+}
diff --git a/src/pal/tests/palsuite/exception_handling/PAL_TRY_EXCEPT_EX/test2/testinfo.dat b/src/pal/tests/palsuite/exception_handling/PAL_TRY_EXCEPT_EX/test2/testinfo.dat
new file mode 100644
index 0000000000..f71964da1c
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/PAL_TRY_EXCEPT_EX/test2/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = exception_handling
+Function = PAL_TRY and PAL_EXCEPT_EX (test 2)
+Name = Test for PAL_TRY and PAL_EXCEPT_EX
+Type = DEFAULT
+EXE1 = pal_try_except_ex
+LANG = cpp
+Description
+= Since these two are so closely connected, they are tested together.
+= In this test, no exceptions are forced to ensure the EXCEPTION block
+= isn't hit. Booleans are used to ensure the proper code blocks are hit.
diff --git a/src/pal/tests/palsuite/exception_handling/PAL_TRY_EXCEPT_EX/test3/CMakeLists.txt b/src/pal/tests/palsuite/exception_handling/PAL_TRY_EXCEPT_EX/test3/CMakeLists.txt
new file mode 100644
index 0000000000..dc797f2f09
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/PAL_TRY_EXCEPT_EX/test3/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ PAL_TRY_EXCEPT_EX.c
+)
+
+add_executable(paltest_pal_try_except_ex_test3
+ ${SOURCES}
+)
+
+add_dependencies(paltest_pal_try_except_ex_test3 coreclrpal)
+
+target_link_libraries(paltest_pal_try_except_ex_test3
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/exception_handling/PAL_TRY_EXCEPT_EX/test3/PAL_TRY_EXCEPT_EX.c b/src/pal/tests/palsuite/exception_handling/PAL_TRY_EXCEPT_EX/test3/PAL_TRY_EXCEPT_EX.c
new file mode 100644
index 0000000000..d6a948926b
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/PAL_TRY_EXCEPT_EX/test3/PAL_TRY_EXCEPT_EX.c
@@ -0,0 +1,130 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: PAL_TRY_EXCEPT.c (test 3)
+**
+** Purpose: Tests the PAL implementation of the PAL_TRY and
+** PAL_EXCEPT functions. Force an exception in only one block
+** to ensure the proper exception block is hit.
+**
+**
+**===================================================================*/
+
+
+
+#include <palsuite.h>
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ int* p = 0x00000000; /* NULL pointer */
+ BOOL bTry = FALSE;
+ BOOL bExcept = FALSE;
+ BOOL bTestA = TRUE;
+
+ if (0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ /*
+ ** test to make sure we get into the exception block
+ */
+
+ PAL_TRY
+ {
+ if (!bTestA)
+ {
+ Fail("PAL_TRY_EXCEPT: ERROR ->"
+ " It appears the first try block was hit a second time.\n");
+ }
+ bTry = TRUE; /* indicate we hit the PAL_TRY block */
+ *p = 13; /* causes an access violation exception */
+ Fail("PAL_TRY_EXCEPT: ERROR -> code was executed after the "
+ "access violation.\n");
+ }
+ PAL_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ if (!bTestA)
+ {
+ Fail("PAL_TRY_EXCEPT: ERROR ->"
+ " It appears the first except block was hit a second time.\n");
+ }
+ bExcept = TRUE; /* indicate we hit the PAL_EXCEPT block */
+ }
+ PAL_ENDTRY;
+
+ if (!bTry)
+ {
+ Trace("PAL_TRY_EXCEPT: ERROR -> It appears the code in the PAL_TRY"
+ " block was not executed.\n");
+ }
+
+ if (!bExcept)
+ {
+ Trace("PAL_TRY_EXCEPT: ERROR -> It appears the code in the first"
+ " PAL_EXCEPT block was not executed.\n");
+ }
+
+ /* did we hit all the code blocks? */
+ if(!bTry || !bExcept)
+ {
+ Fail("\n");
+ }
+
+
+ /*
+ ** test to make sure we get into the second exception block
+ */
+
+ bTry = FALSE;
+ bExcept = FALSE;
+ bTestA = FALSE; /* we are now going into the second block test */
+
+
+ PAL_TRY
+ {
+ if (bTestA)
+ {
+ Fail("PAL_TRY_EXCEPT: ERROR -> It appears"
+ " the second try block was hit too early.\n");
+ }
+ bTry = TRUE; /* indicate we hit the PAL_TRY block */
+ }
+ PAL_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ if (bTestA)
+ {
+ Fail("PAL_TRY_EXCEPT: ERROR -> It appears"
+ " the second except block was hit too early.\n");
+ }
+ bExcept = TRUE; /* indicate we hit the PAL_EXCEPT block */
+ }
+ PAL_ENDTRY;
+
+ if (!bTry)
+ {
+ Trace("PAL_TRY_EXCEPT: ERROR -> It appears the code in the second"
+ " PAL_TRY block was not executed.\n");
+ }
+
+ if (bExcept)
+ {
+ Trace("PAL_TRY_EXCEPT: ERROR -> It appears the code in the second "
+ " PAL_EXCEPT block was executed for some reason.\n");
+ }
+
+ /* did we hit all the correct code blocks? */
+ if(!bTry || bExcept)
+ {
+ Fail("\n");
+ }
+
+ PAL_Terminate();
+ return PASS;
+
+}
diff --git a/src/pal/tests/palsuite/exception_handling/PAL_TRY_EXCEPT_EX/test3/testinfo.dat b/src/pal/tests/palsuite/exception_handling/PAL_TRY_EXCEPT_EX/test3/testinfo.dat
new file mode 100644
index 0000000000..a245447088
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/PAL_TRY_EXCEPT_EX/test3/testinfo.dat
@@ -0,0 +1,16 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = exception_handling
+Function = PAL_TRY and PAL_EXCEPT_EX (test3)
+Name = Test for PAL_TRY and PAL_EXCEPT_EX
+Type = DEFAULT
+EXE1 = pal_try_except_ex
+LANG = cpp
+Description
+= Since these two are so closely connected, they are tested together.
+= Only one of the PAL_TRY blocks will force and exception to ensure the
+= correct PAL_EXCEPT_EX block is hit. Booleans are used to ensure
+= the correct code blocks are hit.
diff --git a/src/pal/tests/palsuite/exception_handling/PAL_TRY_LEAVE_FINALLY/CMakeLists.txt b/src/pal/tests/palsuite/exception_handling/PAL_TRY_LEAVE_FINALLY/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/PAL_TRY_LEAVE_FINALLY/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/exception_handling/PAL_TRY_LEAVE_FINALLY/test1/CMakeLists.txt b/src/pal/tests/palsuite/exception_handling/PAL_TRY_LEAVE_FINALLY/test1/CMakeLists.txt
new file mode 100644
index 0000000000..a5fdd26924
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/PAL_TRY_LEAVE_FINALLY/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ PAL_TRY_LEAVE_FINALLY.c
+)
+
+add_executable(paltest_pal_try_leave_finally_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_pal_try_leave_finally_test1 coreclrpal)
+
+target_link_libraries(paltest_pal_try_leave_finally_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/exception_handling/PAL_TRY_LEAVE_FINALLY/test1/PAL_TRY_LEAVE_FINALLY.c b/src/pal/tests/palsuite/exception_handling/PAL_TRY_LEAVE_FINALLY/test1/PAL_TRY_LEAVE_FINALLY.c
new file mode 100644
index 0000000000..675c2a5947
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/PAL_TRY_LEAVE_FINALLY/test1/PAL_TRY_LEAVE_FINALLY.c
@@ -0,0 +1,77 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: pal_try_leave_finally.c
+**
+** Purpose: Tests the PAL implementation of the PAL_TRY, PAL_LEAVE
+** and PAL_FINALLY functions.
+**
+**
+**===================================================================*/
+
+
+
+#include <palsuite.h>
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ BOOL bTry = FALSE;
+ BOOL bFinally = FALSE;
+ BOOL bLeave = TRUE;
+
+ if (0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ PAL_TRY
+ {
+ bTry = TRUE; /* indicate we hit the PAL_TRY block */
+
+ goto Done;
+
+ bLeave = FALSE; /* indicate we stuck around */
+ Done: ;
+ }
+ PAL_FINALLY
+ {
+ bFinally = TRUE; /* indicate we hit the PAL_FINALLY block */
+ }
+ PAL_ENDTRY;
+
+ /* did we go where we were meant to go */
+ if (!bTry)
+ {
+ Trace("PAL_TRY_FINALLY: ERROR -> It appears the code in the PAL_TRY"
+ " block was not executed.\n");
+ }
+
+ if (!bLeave)
+ {
+ Trace("PAL_TRY_FINALLY: ERROR -> It appears code was executed after "
+ "PAL_LEAVE was called. It should have jumped directly to the "
+ "PAL_FINALLY block.\n");
+ }
+
+ if (!bFinally)
+ {
+ Trace("PAL_TRY_FINALLY: ERROR -> It appears the code in the PAL_FINALLY"
+ " block was not executed.\n");
+ }
+
+ /* did we hit all the code blocks? */
+ if(!bTry || !bLeave || !bFinally)
+ {
+ Fail("");
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+
+}
diff --git a/src/pal/tests/palsuite/exception_handling/PAL_TRY_LEAVE_FINALLY/test1/testinfo.dat b/src/pal/tests/palsuite/exception_handling/PAL_TRY_LEAVE_FINALLY/test1/testinfo.dat
new file mode 100644
index 0000000000..8a90ef392c
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/PAL_TRY_LEAVE_FINALLY/test1/testinfo.dat
@@ -0,0 +1,17 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = PAL_TRY, PAL_LEAVE and PAL_FINALLY
+Name = Test for PAL_TRY, PAL_LEAVE and PAL_EXCEPT
+Type = DEFAULT
+EXE1 = pal_try_leave_finally
+LANG = cpp
+Description
+= Since these three are so closely connected, they are tested together.
+= The PAL_TRY block contains a PAL_LEAVE which kicks execution to
+= the PAL_FINALLY block. Booleans are used to ensure each of the
+= code blocks are properly hit.
+
diff --git a/src/pal/tests/palsuite/exception_handling/RaiseException/CMakeLists.txt b/src/pal/tests/palsuite/exception_handling/RaiseException/CMakeLists.txt
new file mode 100644
index 0000000000..1962ade358
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/RaiseException/CMakeLists.txt
@@ -0,0 +1,6 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+add_subdirectory(test3)
+
diff --git a/src/pal/tests/palsuite/exception_handling/RaiseException/test1/CMakeLists.txt b/src/pal/tests/palsuite/exception_handling/RaiseException/test1/CMakeLists.txt
new file mode 100644
index 0000000000..2fba7dd9b3
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/RaiseException/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.cpp
+)
+
+add_executable(paltest_raiseexception_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_raiseexception_test1 coreclrpal)
+
+target_link_libraries(paltest_raiseexception_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/exception_handling/RaiseException/test1/test1.cpp b/src/pal/tests/palsuite/exception_handling/RaiseException/test1/test1.cpp
new file mode 100644
index 0000000000..9130bc362d
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/RaiseException/test1/test1.cpp
@@ -0,0 +1,130 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: test1.c
+**
+** Purpose: Tests that RaiseException throws a catchable exception
+** and Tests the behaviour of RaiseException with
+** PAL_FINALLY
+**
+**
+**============================================================*/
+
+
+#include <palsuite.h>
+
+BOOL bExcept = FALSE;
+BOOL bTry = FALSE;
+BOOL bFinally = FALSE;
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /*********************************************************
+ * Tests that RaiseException throws a catchable exception
+ */
+ PAL_TRY(VOID*, unused, NULL)
+ {
+ bTry = TRUE;
+ RaiseException(0,0,0,0);
+
+ Fail("RaiseException: ERROR -> code was executed after the "
+ "exception was raised.\n");
+ }
+ PAL_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ bExcept = TRUE;
+ }
+ PAL_ENDTRY;
+
+ if (!bTry)
+ {
+ Trace("RaiseException: ERROR -> It appears the code in the "
+ "PAL_TRY block was not executed.\n");
+ }
+
+ if (!bExcept)
+ {
+ Trace("RaiseException: ERROR -> It appears the code in the "
+ "PAL_EXCEPT_FILTER_EX block was not executed.\n");
+ }
+
+ /* did we hit all the code blocks? */
+ if(!bTry || !bExcept)
+ {
+ Fail("");
+ }
+
+ /* Reinit flags */
+ bTry = bExcept = FALSE;
+
+
+ /*********************************************************
+ * Tests the behaviour of RaiseException with
+ * PAL_FINALLY
+ * (bFinally should be set before bExcept)
+ */
+ PAL_TRY(VOID*, unused, NULL)
+ {
+ PAL_TRY(VOID*, unused, NULL)
+ {
+ bTry = TRUE;
+ RaiseException(0,0,0,0);
+
+ Fail("RaiseException: ERROR -> code was executed after the "
+ "exception was raised.\n");
+ }
+ PAL_FINALLY
+ {
+ bFinally = TRUE;
+ }
+ PAL_ENDTRY;
+ }
+ PAL_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ if( bFinally == FALSE )
+ {
+ Fail("RaiseException: ERROR -> It appears the code in the "
+ "PAL_EXCEPT executed before the code in PAL_FINALLY.\n");
+ }
+
+ bExcept = TRUE;
+ }
+
+ PAL_ENDTRY;
+
+ if (!bTry)
+ {
+ Trace("RaiseException: ERROR -> It appears the code in the "
+ "PAL_TRY block was not executed.\n");
+ }
+
+ if (!bExcept)
+ {
+ Trace("RaiseException: ERROR -> It appears the code in the "
+ "PAL_EXCEPT block was not executed.\n");
+ }
+
+ if (!bFinally)
+ {
+ Trace("RaiseException: ERROR -> It appears the code in the "
+ "PAL_FINALLY block was not executed.\n");
+ }
+
+ /* did we hit all the code blocks? */
+ if(!bTry || !bExcept || !bFinally)
+ {
+ Fail("");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/exception_handling/RaiseException/test1/testinfo.dat b/src/pal/tests/palsuite/exception_handling/RaiseException/test1/testinfo.dat
new file mode 100644
index 0000000000..890b5efec7
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/RaiseException/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = exception_handling
+Function = RaiseException
+Name = RaiseException test #1
+TYPE = DEFAULT
+EXE1 = test1
+LANG = cpp
+Description
+=Tests that RaiseException throws a catchable exception
diff --git a/src/pal/tests/palsuite/exception_handling/RaiseException/test2/CMakeLists.txt b/src/pal/tests/palsuite/exception_handling/RaiseException/test2/CMakeLists.txt
new file mode 100644
index 0000000000..7fc9f5f12c
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/RaiseException/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test2.cpp
+)
+
+add_executable(paltest_raiseexception_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_raiseexception_test2 coreclrpal)
+
+target_link_libraries(paltest_raiseexception_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/exception_handling/RaiseException/test2/test2.cpp b/src/pal/tests/palsuite/exception_handling/RaiseException/test2/test2.cpp
new file mode 100644
index 0000000000..f8db573ac0
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/RaiseException/test2/test2.cpp
@@ -0,0 +1,224 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: test2.c (exception_handling\raiseexception\test2)
+**
+** Purpose: Tests that the correct arguments are passed
+** to the filter by RaiseException and tests that
+** the number of arguments never exceeds
+** EXCEPTION_MAXIMUM_PARAMETERS, even though we
+** pass a greater number of arguments
+**
+**
+**============================================================*/
+
+
+#include <palsuite.h>
+
+BOOL bFilter;
+BOOL bTry;
+BOOL bExcept;
+
+ULONG_PTR lpArguments_test1[EXCEPTION_MAXIMUM_PARAMETERS];
+DWORD nArguments_test1 = EXCEPTION_MAXIMUM_PARAMETERS;
+
+ULONG_PTR lpArguments_test2[EXCEPTION_MAXIMUM_PARAMETERS+1];
+DWORD nArguments_test2 = EXCEPTION_MAXIMUM_PARAMETERS+1;
+
+
+/**
+**
+** Filter function that checks for the parameters
+**
+**/
+LONG Filter_test1(EXCEPTION_POINTERS* ep, VOID *unused)
+{
+ int i;
+
+ /* let the main know we've hit the filter function */
+ bFilter = TRUE;
+
+ if (!bTry)
+ {
+ Fail("PAL_EXCEPT_FILTER_EX: ERROR -> Something weird is going on."
+ " The filter was hit without PAL_TRY being hit.\n");
+ }
+
+
+ /* was the correct number of arguments passed */
+ if (ep->ExceptionRecord->NumberParameters != (DWORD) nArguments_test1)
+ {
+ Fail("RaiseException: ERROR -> Number of arguments passed to filter"
+ " was %d when it should have been %d",
+ ep->ExceptionRecord->NumberParameters,
+ nArguments_test1);
+
+ }
+
+ /* were the correct arguments passed */
+ for( i=0; ((DWORD)i)<nArguments_test1; i++ )
+ {
+ if( ep->ExceptionRecord->ExceptionInformation[i]
+ != lpArguments_test1[i])
+ {
+ Fail("RaiseException: ERROR -> Argument %d passed to filter"
+ " was %d when it should have been %d",
+ i,
+ ep->ExceptionRecord->ExceptionInformation[i],
+ lpArguments_test1[i]);
+ }
+ }
+
+ return EXCEPTION_EXECUTE_HANDLER;
+}
+
+/**
+**
+** Filter function that checks for the maximum parameters
+**
+**/
+LONG Filter_test2(EXCEPTION_POINTERS* ep, VOID* unused)
+{
+ /* let the main know we've hit the filter function */
+ bFilter = TRUE;
+
+ if (ep->ExceptionRecord->NumberParameters > EXCEPTION_MAXIMUM_PARAMETERS)
+ {
+ Fail("RaiseException: ERROR -> Number of arguments passed to filter"
+ " was %d which is greater than the maximum allowed of %d\n",
+ ep->ExceptionRecord->NumberParameters,
+ EXCEPTION_MAXIMUM_PARAMETERS);
+ }
+
+ return EXCEPTION_EXECUTE_HANDLER;
+}
+
+int __cdecl main(int argc, char *argv[])
+{
+ bExcept = FALSE;
+
+ if (0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ /********************************************************
+ * Test that the correct arguments are passed
+ * to the filter by RaiseException
+ */
+ PAL_TRY(VOID*, unused, NULL)
+ {
+ bTry = TRUE; /* indicate we hit the PAL_TRY block */
+
+ /* Initialize arguments to pass to filter */
+ for(int i = 0; ((DWORD)i) < nArguments_test1; i++ )
+ {
+ lpArguments_test1[i] = i;
+ }
+
+ RaiseException(0,0,nArguments_test1,lpArguments_test1);
+
+ Fail("RaiseException: ERROR -> code was executed after the "
+ "exception was raised.\n");
+ }
+ PAL_EXCEPT_FILTER(Filter_test1)
+ {
+ if (!bTry)
+ {
+ Fail("RaiseException: ERROR -> Something weird is going on."
+ " PAL_EXCEPT_FILTER was hit without PAL_TRY being hit.\n");
+ }
+ bExcept = TRUE; /* indicate we hit the PAL_EXCEPT_FILTER_EX block */
+ }
+ PAL_ENDTRY;
+
+ if (!bTry)
+ {
+ Trace("RaiseException: ERROR -> It appears the code in the "
+ "PAL_TRY block was not executed.\n");
+ }
+
+ if (!bExcept)
+ {
+ Trace("RaiseException: ERROR -> It appears the code in the "
+ "PAL_EXCEPT_FILTER_EX block was not executed.\n");
+ }
+
+ if (!bFilter)
+ {
+ Trace("RaiseException: ERROR -> It appears the code in the"
+ " filter function was not executed.\n");
+ }
+
+ /* did we hit all the code blocks? */
+ if(!bTry || !bExcept || !bFilter)
+ {
+ Fail("");
+ }
+
+
+ /* Reinit flags */
+ bTry = bExcept = bFilter = FALSE;
+
+ /********************************************************
+ * Test that the number of arguments never
+ * exceeds EXCEPTION_MAXIMUM_PARAMETERS, even though we
+ * pass a greater number of arguments
+ */
+ PAL_TRY(VOID*, unused, NULL)
+ {
+ bTry = TRUE; /* indicate we hit the PAL_TRY block */
+
+ /* Initialize arguments to pass to filter */
+ for(int i = 0; ((DWORD)i) < nArguments_test2; i++ )
+ {
+ lpArguments_test2[i] = i;
+ }
+
+ RaiseException(0,0,nArguments_test2,lpArguments_test2);
+
+ Fail("RaiseException: ERROR -> code was executed after the "
+ "exception was raised.\n");
+ }
+ PAL_EXCEPT_FILTER(Filter_test2)
+ {
+ if (!bTry)
+ {
+ Fail("RaiseException: ERROR -> Something weird is going on."
+ " PAL_EXCEPT_FILTER was hit without PAL_TRY being hit.\n");
+ }
+ bExcept = TRUE; /* indicate we hit the PAL_EXCEPT_FILTER_EX block */
+ }
+ PAL_ENDTRY;
+
+ if (!bTry)
+ {
+ Trace("RaiseException: ERROR -> It appears the code in the "
+ "PAL_TRY block was not executed.\n");
+ }
+
+ if (!bExcept)
+ {
+ Trace("RaiseException: ERROR -> It appears the code in the "
+ "PAL_EXCEPT_FILTER_EX block was not executed.\n");
+ }
+
+ if (!bFilter)
+ {
+ Trace("RaiseException: ERROR -> It appears the code in the"
+ " filter function was not executed.\n");
+ }
+
+ /* did we hit all the code blocks? */
+ if(!bTry || !bExcept || !bFilter)
+ {
+ Fail("");
+ }
+
+ PAL_Terminate();
+ return PASS;
+
+}
diff --git a/src/pal/tests/palsuite/exception_handling/RaiseException/test2/testinfo.dat b/src/pal/tests/palsuite/exception_handling/RaiseException/test2/testinfo.dat
new file mode 100644
index 0000000000..ce85e67ace
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/RaiseException/test2/testinfo.dat
@@ -0,0 +1,28 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+
+Section = exception_handling
+
+Function = RaiseException
+
+Name = RaiseException test #2
+
+TYPE = DEFAULT
+
+EXE1 = test2
+LANG = cpp
+
+Description
+
+=Tests that the correct arguments are passed
+
+=to the filter by RaiseException and tests that
+
+=the number of arguments never exceeds
+
+=EXCEPTION_MAXIMUM_PARAMETERS, even though we
+
+=pass a greater number of arguments
diff --git a/src/pal/tests/palsuite/exception_handling/RaiseException/test3/CMakeLists.txt b/src/pal/tests/palsuite/exception_handling/RaiseException/test3/CMakeLists.txt
new file mode 100644
index 0000000000..72e5427b69
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/RaiseException/test3/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.cpp
+)
+
+add_executable(paltest_raiseexception_test3
+ ${SOURCES}
+)
+
+add_dependencies(paltest_raiseexception_test3 coreclrpal)
+
+target_link_libraries(paltest_raiseexception_test3
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/exception_handling/RaiseException/test3/test.cpp b/src/pal/tests/palsuite/exception_handling/RaiseException/test3/test.cpp
new file mode 100644
index 0000000000..5278ad1772
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/RaiseException/test3/test.cpp
@@ -0,0 +1,115 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: test.c (exception_handling\raiseexception\test3)
+**
+** Purpose: Tests that the correct ExceptionCode is passed
+** to the filter by RaiseException
+**
+**
+**============================================================*/
+
+
+#include <palsuite.h>
+
+BOOL bFilter = FALSE;
+BOOL bTry = FALSE;
+BOOL bExcept = FALSE;
+
+/**
+**
+** Filter function that checks for the parameters
+**
+**/
+LONG Filter_test1(EXCEPTION_POINTERS* ep, VOID* unused)
+{
+ /* let the main know we've hit the filter function */
+ bFilter = TRUE;
+
+ if (!bTry)
+ {
+ Fail("PAL_EXCEPT_FILTER_EX: ERROR -> Something weird is going on."
+ " The filter was hit without PAL_TRY being hit.\n");
+ }
+
+
+ /* was the correct exception code passed? */
+ if (ep->ExceptionRecord->ExceptionCode != EXCEPTION_ARRAY_BOUNDS_EXCEEDED)
+ {
+ Fail("RaiseException: ERROR -> ep->ExceptionRecord->ExceptionCode"
+ " was %x when it was expected to be %x\n",
+ ep->ExceptionRecord->ExceptionCode,
+ EXCEPTION_ARRAY_BOUNDS_EXCEEDED);
+
+ }
+
+ return EXCEPTION_EXECUTE_HANDLER;
+}
+
+int __cdecl main(int argc, char *argv[])
+{
+ bExcept = FALSE;
+
+ if (0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ /********************************************************
+ * Test that the correct arguments are passed
+ * to the filter by RaiseException
+ */
+ PAL_TRY(VOID*, unused, NULL)
+ {
+ bTry = TRUE; /* indicate we hit the PAL_TRY block */
+
+ RaiseException(EXCEPTION_ARRAY_BOUNDS_EXCEEDED,
+ 0,
+ 0,NULL);
+
+ Fail("RaiseException: ERROR -> code was executed after the "
+ "exception was raised.\n");
+ }
+ PAL_EXCEPT_FILTER(Filter_test1)
+ {
+ if (!bTry)
+ {
+ Fail("RaiseException: ERROR -> Something weird is going on."
+ " PAL_EXCEPT_FILTER was hit without PAL_TRY being hit.\n");
+ }
+ bExcept = TRUE; /* indicate we hit the PAL_EXCEPT_FILTER_EX block */
+ }
+ PAL_ENDTRY;
+
+ if (!bTry)
+ {
+ Trace("RaiseException: ERROR -> It appears the code in the "
+ "PAL_TRY block was not executed.\n");
+ }
+
+ if (!bExcept)
+ {
+ Trace("RaiseException: ERROR -> It appears the code in the "
+ "PAL_EXCEPT_FILTER_EX block was not executed.\n");
+ }
+
+ if (!bFilter)
+ {
+ Trace("RaiseException: ERROR -> It appears the code in the"
+ " filter function was not executed.\n");
+ }
+
+ /* did we hit all the code blocks? */
+ if(!bTry || !bExcept || !bFilter)
+ {
+ Fail("");
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+
+}
diff --git a/src/pal/tests/palsuite/exception_handling/RaiseException/test3/testinfo.dat b/src/pal/tests/palsuite/exception_handling/RaiseException/test3/testinfo.dat
new file mode 100644
index 0000000000..12a56f0efe
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/RaiseException/test3/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = exception_handling
+Function = RaiseException
+Name = RaiseException test #3
+TYPE = DEFAULT
+EXE1 = test
+LANG = cpp
+Description
+= Tests that the exception code passed to
+= RaiseException makes it to the filter.
diff --git a/src/pal/tests/palsuite/exception_handling/SetUnhandledExceptionFilter/CMakeLists.txt b/src/pal/tests/palsuite/exception_handling/SetUnhandledExceptionFilter/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/SetUnhandledExceptionFilter/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/exception_handling/SetUnhandledExceptionFilter/test1/CMakeLists.txt b/src/pal/tests/palsuite/exception_handling/SetUnhandledExceptionFilter/test1/CMakeLists.txt
new file mode 100644
index 0000000000..e526029bee
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/SetUnhandledExceptionFilter/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_setunhandledexceptionfilter_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_setunhandledexceptionfilter_test1 coreclrpal)
+
+target_link_libraries(paltest_setunhandledexceptionfilter_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/exception_handling/SetUnhandledExceptionFilter/test1/test1.c b/src/pal/tests/palsuite/exception_handling/SetUnhandledExceptionFilter/test1/test1.c
new file mode 100644
index 0000000000..5a067f9354
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/SetUnhandledExceptionFilter/test1/test1.c
@@ -0,0 +1,82 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: test1.c
+**
+** Purpose: Sets up a new unhandled exception filter, and makes sure it
+** returns the previous filter. Raises an unhandled exception and
+** makes sure this reaches the filter.
+**
+**
+**============================================================*/
+
+
+#include <palsuite.h>
+
+/* This isn't defined in the pal, so copied from win32 */
+#define EXCEPTION_EXECUTE_HANDLER 1
+#define EXCEPTION_CONTINUE_EXECUTION -1
+
+
+int InFilter = FALSE;
+
+LONG PALAPI FirstFilter(LPEXCEPTION_POINTERS p)
+{
+ return EXCEPTION_EXECUTE_HANDLER;
+}
+
+LONG PALAPI ContinueFilter(LPEXCEPTION_POINTERS p)
+{
+ InFilter = TRUE;
+
+ Trace("This test has succeeded as far at the automated checks can "
+ "tell. Manual verification is now required to be completely sure.\n");
+ Trace("Now the PAL's handling of application errors will be tested "
+ "with an exception code of %u.\n",
+ p->ExceptionRecord->ExceptionCode);
+ Trace("Please verify that the actions that the PAL now takes are "
+ "as specified for it.\n");
+
+ return EXCEPTION_CONTINUE_SEARCH;
+}
+
+int __cdecl main(int argc, char *argv[])
+{
+ LPTOP_LEVEL_EXCEPTION_FILTER OldFilter;
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+
+ SetUnhandledExceptionFilter(FirstFilter);
+
+ OldFilter = SetUnhandledExceptionFilter(ContinueFilter);
+ if (OldFilter != FirstFilter)
+ {
+ Fail("SetUnhandledExceptionFilter did not return a pointer to the "
+ "previous filter!\n");
+ }
+
+ /*
+ * Raise an unhandled exception. This should cause our filter to be
+ * excecuted and the program to exit with a code the same as the
+ * exception code.
+ */
+ RaiseException(3,0,0,0);
+
+
+ /*
+ * This code should not be executed because the toplevelhandler is
+ * expected to "just" set the exit code and abend the program
+ */
+ Fail("An unhandled exception did not cause the program to abend with"
+ "the exit code == the ExceptionCode!\n");
+
+ PAL_Terminate();
+ return FAIL;
+}
diff --git a/src/pal/tests/palsuite/exception_handling/SetUnhandledExceptionFilter/test1/testinfo.dat b/src/pal/tests/palsuite/exception_handling/SetUnhandledExceptionFilter/test1/testinfo.dat
new file mode 100644
index 0000000000..2af29a299a
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/SetUnhandledExceptionFilter/test1/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = exception_handling
+Function = SetUnhandledExceptionFilter
+Name = SetUnhandledExceptionFilter test #1
+TYPE = DEFAULT
+EXE1 = test1
+LANG = cpp
+Description
+=Sets up a new unhandled exception filter, and makes sure it
+=returns the previous filter. Raises an unhandled exception and
+=makes sure this reaches the filter.
diff --git a/src/pal/tests/palsuite/exception_handling/pal_except/CMakeLists.txt b/src/pal/tests/palsuite/exception_handling/pal_except/CMakeLists.txt
new file mode 100644
index 0000000000..19ee487a6a
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/pal_except/CMakeLists.txt
@@ -0,0 +1,10 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+add_subdirectory(test3)
+add_subdirectory(test4)
+add_subdirectory(test5)
+add_subdirectory(test6)
+add_subdirectory(test7)
+
diff --git a/src/pal/tests/palsuite/exception_handling/pal_except/test1/CMakeLists.txt b/src/pal/tests/palsuite/exception_handling/pal_except/test1/CMakeLists.txt
new file mode 100644
index 0000000000..635e35d635
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/pal_except/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_pal_except_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_pal_except_test1 coreclrpal)
+
+target_link_libraries(paltest_pal_except_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/exception_handling/pal_except/test1/test1.c b/src/pal/tests/palsuite/exception_handling/pal_except/test1/test1.c
new file mode 100644
index 0000000000..0fe48e7fc3
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/pal_except/test1/test1.c
@@ -0,0 +1,67 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test1.c (exception_handling\pal_except\test1)
+**
+** Purpose: Test to make sure the PAL_EXCEPT block is executed
+** after an exception occurs in the PAL_TRY block
+**
+**
+**===================================================================*/
+#include <palsuite.h>
+
+/* Execution flags */
+BOOL bTry = FALSE;
+BOOL bExcept = FALSE;
+
+int __cdecl main(int argc, char *argv[])
+{
+ if (0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ PAL_TRY
+ {
+ int* p = 0x00000000; /* NULL pointer */
+
+ bTry = TRUE; /* indicate we hit the PAL_TRY block */
+ *p = 13; /* causes an access violation exception */
+
+ Fail("ERROR: code was executed after the access violation.\n");
+ }
+ PAL_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ if (!bTry)
+ {
+ Fail("ERROR: PAL_EXCEPT was hit without PAL_TRY being hit.\n");
+ }
+
+ bExcept = TRUE; /* indicate we hit the PAL_EXCEPT block */
+ }
+ PAL_ENDTRY;
+
+ if (!bTry)
+ {
+ Trace("ERROR: the code in the PAL_TRY block was not executed.\n");
+ }
+
+ if (!bExcept)
+ {
+ Trace("ERROR: the code in the PAL_EXCEPT block was not executed.\n");
+ }
+
+ /* did we hit all the code blocks? */
+ if(!bTry || !bExcept)
+ {
+ Fail("");
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+
+}
diff --git a/src/pal/tests/palsuite/exception_handling/pal_except/test1/testinfo.dat b/src/pal/tests/palsuite/exception_handling/pal_except/test1/testinfo.dat
new file mode 100644
index 0000000000..246553a9cb
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/pal_except/test1/testinfo.dat
@@ -0,0 +1,23 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+
+Section = exception_handling
+
+Function = PAL_TRY and PAL_EXCEPT
+
+Name = Test for PAL_TRY and PAL_EXCEPT
+
+Type = DEFAULT
+
+EXE1 = test1
+
+LANG = cpp
+
+Description
+
+= Test to make sure the PAL_EXCEPT block is executed
+
+= after an exception occurs in the PAL_TRY block
diff --git a/src/pal/tests/palsuite/exception_handling/pal_except/test2/CMakeLists.txt b/src/pal/tests/palsuite/exception_handling/pal_except/test2/CMakeLists.txt
new file mode 100644
index 0000000000..813b0e66a1
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/pal_except/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test2.c
+)
+
+add_executable(paltest_pal_except_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_pal_except_test2 coreclrpal)
+
+target_link_libraries(paltest_pal_except_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/exception_handling/pal_except/test2/test2.c b/src/pal/tests/palsuite/exception_handling/pal_except/test2/test2.c
new file mode 100644
index 0000000000..bc0d4e300a
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/pal_except/test2/test2.c
@@ -0,0 +1,111 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test2.c (exception_handling\pal_except\test2)
+**
+** Purpose: Test to make sure the PAL_EXCEPT block is executed
+** after an exception occurs in the PAL_TRY block
+** that contains another PAL_TRY-PAL_EXCEPT block
+**
+**
+**===================================================================*/
+#include <palsuite.h>
+
+/* Execution flags */
+BOOL bTry = FALSE;
+BOOL bExcept = FALSE;
+BOOL bTry_nested = FALSE;
+BOOL bExcept_nested = FALSE;
+
+int __cdecl main(int argc, char *argv[])
+{
+ if (0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ PAL_TRY
+ {
+ int* p = 0x00000000; /* NULL pointer */
+
+ bTry = TRUE; /* indicate we hit the PAL_TRY block */
+
+
+ /* Nested PAL_TRY */
+ PAL_TRY
+ {
+ bTry_nested = TRUE;
+
+ *p = 13; /* causes an access violation exception */
+
+ Fail("ERROR: code was executed after the nested access violation.\n");
+
+ }
+ PAL_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ if (!bTry)
+ {
+ Fail("ERROR: Nested PAL_EXCEPT was hit without "
+ "nested PAL_TRY being hit.\n");
+ }
+ bExcept_nested = TRUE;
+ }
+ PAL_ENDTRY;
+
+ *p = 13; /* causes an access violation exception */
+
+ Fail("ERROR: code was executed after the access violation.\n");
+ }
+ PAL_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ if (!bTry)
+ {
+ Fail("ERROR: PAL_EXCEPT was hit without PAL_TRY being hit.\n");
+ }
+ if (!bExcept_nested)
+ {
+ Fail("ERROR: PAL_EXCEPT was hit without "
+ "nested PAL_EXCEPT being hit.\n");
+ }
+
+ bExcept = TRUE; /* indicate we hit the PAL_EXCEPT block */
+ }
+ PAL_ENDTRY;
+
+ if (!bTry)
+ {
+ Trace("ERROR: the code in the PAL_TRY block was not executed.\n");
+ }
+
+ if (!bExcept)
+ {
+ Trace("ERROR: the code in the PAL_EXCEPT block was not executed.\n");
+ }
+
+ if (!bTry_nested)
+ {
+ Trace("ERROR: the code in the "
+ "nested PAL_TRY block was not executed.\n");
+ }
+
+ if (!bExcept_nested)
+ {
+ Trace("ERROR: the code in the "
+ "nested PAL_EXCEPT block was not executed.\n");
+ }
+
+ /* did we hit all the code blocks? */
+ if(!bTry || !bExcept ||
+ !bTry_nested || !bExcept_nested)
+ {
+ Fail("");
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+
+}
diff --git a/src/pal/tests/palsuite/exception_handling/pal_except/test2/testinfo.dat b/src/pal/tests/palsuite/exception_handling/pal_except/test2/testinfo.dat
new file mode 100644
index 0000000000..39a628b16c
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/pal_except/test2/testinfo.dat
@@ -0,0 +1,25 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+
+Section = exception_handling
+
+Function = PAL_TRY and PAL_EXCEPT_EX
+
+Name = Test for PAL_TRY and PAL_EXCEPT_EX
+
+Type = DEFAULT
+
+EXE1 = test2
+
+LANG = cpp
+
+Description
+
+= Test to make sure the PAL_EXCEPT_EX block is executed
+
+= after an exception occurs in the PAL_TRY block
+
+= that contains another PAL_TRY-PAL_EXCEPT_EX block
diff --git a/src/pal/tests/palsuite/exception_handling/pal_except/test3/CMakeLists.txt b/src/pal/tests/palsuite/exception_handling/pal_except/test3/CMakeLists.txt
new file mode 100644
index 0000000000..5fc3b096af
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/pal_except/test3/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test3.c
+)
+
+add_executable(paltest_pal_except_test3
+ ${SOURCES}
+)
+
+add_dependencies(paltest_pal_except_test3 coreclrpal)
+
+target_link_libraries(paltest_pal_except_test3
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/exception_handling/pal_except/test3/test3.c b/src/pal/tests/palsuite/exception_handling/pal_except/test3/test3.c
new file mode 100644
index 0000000000..0137697774
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/pal_except/test3/test3.c
@@ -0,0 +1,120 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test3.c (exception_handling\pal_except\test3)
+**
+** Purpose: Test to make sure the PAL_EXCEPT block is executed
+** after an exception occurs in the PAL_TRY block
+** that calls a function that contains
+** another PAL_TRY-PAL_EXCEPT block
+**
+**
+**===================================================================*/
+#include <palsuite.h>
+
+/* Execution flags */
+BOOL bTry = FALSE;
+BOOL bExcept = FALSE;
+BOOL bTry_function = FALSE;
+BOOL bExcept_function = FALSE;
+
+/*
+ * Helper function that contains a PAL_TRY-PAL_EXCEPT block
+ */
+void Helper()
+{
+ /* Nested PAL_TRY */
+ PAL_TRY
+ {
+ int *lp = 0x00000000;
+
+ bTry_function = TRUE;
+
+ *lp = 13; /* causes an access violation exception */
+
+ Fail("ERROR: code was executed after the function's access violation.\n");
+
+ }
+ PAL_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ if (!bTry)
+ {
+ Fail("ERROR: Nested PAL_EXCEPT was hit without "
+ "the function's PAL_TRY being hit.\n");
+ }
+ bExcept_function = TRUE;
+ }
+ PAL_ENDTRY;
+}
+
+int __cdecl main(int argc, char *argv[])
+{
+ if (0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ PAL_TRY
+ {
+ int* p = 0x00000000; /* NULL pointer */
+
+ bTry = TRUE; /* indicate we hit the PAL_TRY block */
+
+ Helper();
+
+ *p = 13; /* causes an access violation exception */
+
+ Fail("ERROR: code was executed after the access violation.\n");
+ }
+ PAL_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ if (!bTry)
+ {
+ Fail("ERROR: PAL_EXCEPT was hit without PAL_TRY being hit.\n");
+ }
+ if (!bExcept_function)
+ {
+ Fail("ERROR: PAL_EXCEPT was hit without "
+ "function's PAL_EXCEPT being hit.\n");
+ }
+
+ bExcept = TRUE; /* indicate we hit the PAL_EXCEPT block */
+ }
+ PAL_ENDTRY;
+
+ if (!bTry)
+ {
+ Trace("ERROR: the code in the PAL_TRY block was not executed.\n");
+ }
+
+ if (!bExcept)
+ {
+ Trace("ERROR: the code in the PAL_EXCEPT block was not executed.\n");
+ }
+
+ if (!bTry_function)
+ {
+ Trace("ERROR: the code in the "
+ "function's PAL_TRY block was not executed.\n");
+ }
+
+ if (!bExcept_function)
+ {
+ Trace("ERROR: the code in the "
+ "function's PAL_EXCEPT block was not executed.\n");
+ }
+
+ /* did we hit all the code blocks? */
+ if(!bTry || !bExcept ||
+ !bTry_function || !bExcept_function)
+ {
+ Fail("");
+ }
+
+ PAL_Terminate();
+ return PASS;
+
+}
diff --git a/src/pal/tests/palsuite/exception_handling/pal_except/test3/testinfo.dat b/src/pal/tests/palsuite/exception_handling/pal_except/test3/testinfo.dat
new file mode 100644
index 0000000000..07da444a5a
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/pal_except/test3/testinfo.dat
@@ -0,0 +1,27 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+
+Section = exception_handling
+
+Function = PAL_TRY and PAL_EXCEPT
+
+Name = Test for PAL_TRY and PAL_EXCEPT
+
+Type = DEFAULT
+
+EXE1 = test3
+
+LANG = cpp
+
+Description
+
+= Test to make sure the PAL_EXCEPT block is executed
+
+= after an exception occurs in the PAL_TRY block
+
+= that calls a function that contains
+
+= another PAL_TRY-PAL_EXCEPT block
diff --git a/src/pal/tests/palsuite/exception_handling/pal_except/test4/CMakeLists.txt b/src/pal/tests/palsuite/exception_handling/pal_except/test4/CMakeLists.txt
new file mode 100644
index 0000000000..cc054d15dd
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/pal_except/test4/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test4.c
+)
+
+add_executable(paltest_pal_except_test4
+ ${SOURCES}
+)
+
+add_dependencies(paltest_pal_except_test4 coreclrpal)
+
+target_link_libraries(paltest_pal_except_test4
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/exception_handling/pal_except/test4/test4.c b/src/pal/tests/palsuite/exception_handling/pal_except/test4/test4.c
new file mode 100644
index 0000000000..87844973b0
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/pal_except/test4/test4.c
@@ -0,0 +1,105 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test4.c (exception_handling\pal_except\test4)
+**
+** Purpose: Test to make sure the PAL_EXCEPT block is executed
+** after an exception occurs in the PAL_TRY block
+** if the PAL_EXCEPT block contains a nested
+** PAL_TRY-PAL_EXCEPT block
+**
+**
+**===================================================================*/
+#include <palsuite.h>
+
+/* Execution flags */
+BOOL bTry = FALSE;
+BOOL bExcept = FALSE;
+BOOL bTry_nested = FALSE;
+BOOL bExcept_nested = FALSE;
+
+int __cdecl main(int argc, char *argv[])
+{
+ if (0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ PAL_TRY
+ {
+ int* p = 0x00000000; /* NULL pointer */
+
+ bTry = TRUE; /* indicate we hit the PAL_TRY block */
+ *p = 13; /* causes an access violation exception */
+
+ Fail("ERROR: code was executed after the access violation.\n");
+ }
+ PAL_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ if (!bTry)
+ {
+ Fail("ERROR: PAL_EXCEPT was hit without PAL_TRY being hit.\n");
+ }
+
+ PAL_TRY
+ {
+ int *lp = 0x00000000;
+
+ bTry_nested = TRUE;
+ *lp = 13; /* causes an access violation exception */
+
+ Fail("ERROR: code was executed after the "
+ "nested access violation.\n");
+ }
+ PAL_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ if (!bTry_nested)
+ {
+ Fail("ERROR: PAL_EXCEPT was hit without PAL_TRY being hit "
+ "in the nested block.\n");
+ }
+ bExcept_nested = TRUE;
+ }
+ PAL_ENDTRY;
+
+ bExcept = TRUE; /* indicate we hit the PAL_EXCEPT block */
+ }
+ PAL_ENDTRY;
+
+ if (!bTry)
+ {
+ Trace("ERROR: the code in the PAL_TRY block was not executed.\n");
+ }
+
+ if (!bExcept)
+ {
+ Trace("ERROR: the code in the PAL_EXCEPT block was not executed.\n");
+ }
+
+ if (!bTry_nested)
+ {
+ Trace("ERROR: the code in the nested "
+ "PAL_TRY block was not executed.\n");
+ }
+
+ if (!bExcept_nested)
+ {
+ Trace("ERROR: the code in the nested "
+ "PAL_EXCEPT block was not executed.\n");
+ }
+
+ /* did we hit all the code blocks? */
+ if(!bTry || !bExcept ||
+ !bTry_nested || !bExcept_nested)
+ {
+ Fail("");
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+
+}
diff --git a/src/pal/tests/palsuite/exception_handling/pal_except/test4/testinfo.dat b/src/pal/tests/palsuite/exception_handling/pal_except/test4/testinfo.dat
new file mode 100644
index 0000000000..d658cc85fa
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/pal_except/test4/testinfo.dat
@@ -0,0 +1,27 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+
+Section = exception_handling
+
+Function = PAL_TRY and PAL_EXCEPT
+
+Name = Test for PAL_TRY and PAL_EXCEPT
+
+Type = DEFAULT
+
+EXE1 = test4
+
+LANG = cpp
+
+Description
+
+= Test to make sure the PAL_EXCEPT block is executed
+
+= after an exception occurs in the PAL_TRY block
+
+= if the PAL_EXCEPT block contains a nested
+
+= PAL_TRY-PAL_EXCEPT block
diff --git a/src/pal/tests/palsuite/exception_handling/pal_except/test5/CMakeLists.txt b/src/pal/tests/palsuite/exception_handling/pal_except/test5/CMakeLists.txt
new file mode 100644
index 0000000000..7b8f1d0361
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/pal_except/test5/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test5.c
+)
+
+add_executable(paltest_pal_except_test5
+ ${SOURCES}
+)
+
+add_dependencies(paltest_pal_except_test5 coreclrpal)
+
+target_link_libraries(paltest_pal_except_test5
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/exception_handling/pal_except/test5/test5.c b/src/pal/tests/palsuite/exception_handling/pal_except/test5/test5.c
new file mode 100644
index 0000000000..f9faf4440e
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/pal_except/test5/test5.c
@@ -0,0 +1,112 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test5.c (exception_handling\pal_except\test5)
+**
+** Purpose: Test to make sure the PAL_EXCEPT block is executed
+** after an exception occurs in the PAL_TRY block
+** if the PAL_EXCEPT block calls a function that contains
+** another PAL_TRY-PAL_EXCEPT block
+**
+**
+**===================================================================*/
+#include <palsuite.h>
+
+/* Execution flags */
+BOOL bTry = FALSE;
+BOOL bExcept = FALSE;
+BOOL bTry_nested = FALSE;
+BOOL bExcept_nested = FALSE;
+
+int __cdecl main(int argc, char *argv[])
+{
+ if (0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ PAL_TRY
+ {
+ int* p = 0x00000000; /* NULL pointer */
+
+ bTry = TRUE; /* indicate we hit the PAL_TRY block */
+
+
+ /* Nested PAL_TRY */
+ PAL_TRY
+ {
+ bTry_nested = TRUE;
+
+ *p = 13; /* causes an access violation exception */
+
+ Fail("ERROR: code was executed after the nested access violation.\n");
+
+ }
+ PAL_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ if (!bTry)
+ {
+ Fail("ERROR: Nested PAL_EXCEPT was hit without "
+ "nested PAL_TRY being hit.\n");
+ }
+ bExcept_nested = TRUE;
+ }
+ PAL_ENDTRY;
+
+ *p = 13; /* causes an access violation exception */
+
+ Fail("ERROR: code was executed after the access violation.\n");
+ }
+ PAL_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ if (!bTry)
+ {
+ Fail("ERROR: PAL_EXCEPT was hit without PAL_TRY being hit.\n");
+ }
+ if (!bExcept_nested)
+ {
+ Fail("ERROR: PAL_EXCEPT was hit without "
+ "nested PAL_EXCEPT being hit.\n");
+ }
+
+ bExcept = TRUE; /* indicate we hit the PAL_EXCEPT block */
+ }
+ PAL_ENDTRY;
+
+ if (!bTry)
+ {
+ Trace("ERROR: the code in the PAL_TRY block was not executed.\n");
+ }
+
+ if (!bExcept)
+ {
+ Trace("ERROR: the code in the PAL_EXCEPT block was not executed.\n");
+ }
+
+ if (!bTry_nested)
+ {
+ Trace("ERROR: the code in the "
+ "nested PAL_TRY block was not executed.\n");
+ }
+
+ if (!bExcept_nested)
+ {
+ Trace("ERROR: the code in the "
+ "nested PAL_EXCEPT block was not executed.\n");
+ }
+
+ /* did we hit all the code blocks? */
+ if(!bTry || !bExcept ||
+ !bTry_nested || !bExcept_nested)
+ {
+ Fail("");
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+
+}
diff --git a/src/pal/tests/palsuite/exception_handling/pal_except/test5/testinfo.dat b/src/pal/tests/palsuite/exception_handling/pal_except/test5/testinfo.dat
new file mode 100644
index 0000000000..2e12d0c64b
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/pal_except/test5/testinfo.dat
@@ -0,0 +1,27 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+
+Section = exception_handling
+
+Function = PAL_TRY and PAL_EXCEPT
+
+Name = Test for PAL_TRY and PAL_EXCEPT
+
+Type = DEFAULT
+
+EXE1 = test5
+
+LANG = cpp
+
+Description
+
+= Test to make sure the PAL_EXCEPT block is executed
+
+= after an exception occurs in the PAL_TRY block
+
+= if the PAL_EXCEPT block calls a function that contains
+
+= another PAL_TRY-PAL_EXCEPT block
diff --git a/src/pal/tests/palsuite/exception_handling/pal_except/test6/CMakeLists.txt b/src/pal/tests/palsuite/exception_handling/pal_except/test6/CMakeLists.txt
new file mode 100644
index 0000000000..7f943bf126
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/pal_except/test6/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test6.c
+)
+
+add_executable(paltest_pal_except_test6
+ ${SOURCES}
+)
+
+add_dependencies(paltest_pal_except_test6 coreclrpal)
+
+target_link_libraries(paltest_pal_except_test6
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/exception_handling/pal_except/test6/test6.c b/src/pal/tests/palsuite/exception_handling/pal_except/test6/test6.c
new file mode 100644
index 0000000000..44b0ba1bc9
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/pal_except/test6/test6.c
@@ -0,0 +1,160 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test6.c (exception_handling\pal_except\test6)
+**
+** Purpose: Test to make sure the PAL_EXCEPT block is executed
+** after an exception occurs in the PAL_TRY block
+** that contains multiple PAL_TRY-PAL_EXCEPT blocks
+**
+**
+**===================================================================*/
+#include <palsuite.h>
+
+/* Execution flags */
+BOOL bTry = FALSE;
+BOOL bExcept = FALSE;
+BOOL bTry_nested = FALSE;
+BOOL bExcept_nested = FALSE;
+BOOL bTry_nested2 = FALSE;
+BOOL bExcept_nested2 = FALSE;
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ if (0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ /* First block */
+ PAL_TRY
+ {
+ int* p = 0x00000000; /* NULL pointer */
+
+ bTry = TRUE; /* indicate we hit the PAL_TRY block */
+
+ /* Second PAL_TRY block */
+ PAL_TRY
+ {
+ bTry_nested = TRUE;
+
+ /* Third PAL_TRY block*/
+ PAL_TRY
+ {
+ bTry_nested2 = TRUE;
+
+ *p = 13; /* causes an access violation exception */
+
+ Fail("ERROR: code was executed after the nested access violation.\n");
+
+ }
+ PAL_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ if (!bTry_nested2)
+ {
+ Fail("ERROR: Third PAL_EXCEPT was hit without "
+ "third PAL_TRY being hit.\n");
+ }
+ bExcept_nested2 = TRUE;
+ }
+ PAL_ENDTRY;
+
+ *p = 13; /* causes an access violation exception */
+
+ Fail("ERROR: code was executed after the nested access violation.\n");
+
+ }
+ PAL_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ if (!bTry_nested)
+ {
+ Fail("ERROR: Second PAL_EXCEPT was hit without "
+ "second PAL_TRY being hit.\n");
+ }
+ if (!bExcept_nested2)
+ {
+ Fail("ERROR: second PAL_EXCEPT was hit without "
+ "third PAL_EXCEPT being hit.\n");
+ }
+ bExcept_nested = TRUE;
+ }
+ PAL_ENDTRY;
+
+ *p = 13; /* causes an access violation exception */
+
+ Fail("ERROR: code was executed after the access violation.\n");
+ }
+ PAL_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ if (!bTry)
+ {
+ Fail("ERROR: PAL_EXCEPT was hit without PAL_TRY being hit.\n");
+ }
+ if (!bExcept_nested)
+ {
+ Fail("ERROR: first PAL_EXCEPT was hit without "
+ "second PAL_EXCEPT being hit.\n");
+ }
+ if (!bExcept_nested2)
+ {
+ Fail("ERROR: first PAL_EXCEPT was hit without "
+ "third PAL_EXCEPT being hit.\n");
+ }
+
+ bExcept = TRUE; /* indicate we hit the PAL_EXCEPT block */
+ }
+ PAL_ENDTRY;
+
+ if (!bTry)
+ {
+ Trace("ERROR: the code in the "
+ "first PAL_TRY block was not executed.\n");
+ }
+
+ if (!bExcept)
+ {
+ Trace("ERROR: the code in the "
+ "first PAL_EXCEPT block was not executed.\n");
+ }
+
+ if (!bTry_nested)
+ {
+ Trace("ERROR: the code in the "
+ "second PAL_TRY block was not executed.\n");
+ }
+
+ if (!bExcept_nested)
+ {
+ Trace("ERROR: the code in the "
+ "second PAL_EXCEPT block was not executed.\n");
+ }
+
+ if (!bTry_nested2)
+ {
+ Trace("ERROR: the code in the "
+ "third PAL_TRY block was not executed.\n");
+ }
+
+ if (!bExcept_nested2)
+ {
+ Trace("ERROR: the code in the "
+ "third PAL_EXCEPT block was not executed.\n");
+ }
+
+ /* did we hit all the code blocks? */
+ if(!bTry || !bExcept ||
+ !bTry_nested || !bExcept_nested ||
+ !bTry_nested2 || !bExcept_nested2)
+ {
+ Fail("");
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+
+}
diff --git a/src/pal/tests/palsuite/exception_handling/pal_except/test6/testinfo.dat b/src/pal/tests/palsuite/exception_handling/pal_except/test6/testinfo.dat
new file mode 100644
index 0000000000..f8901a7f50
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/pal_except/test6/testinfo.dat
@@ -0,0 +1,25 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+
+Section = exception_handling
+
+Function = PAL_TRY and PAL_EXCEPT_EX
+
+Name = Test for PAL_TRY and PAL_EXCEPT_EX
+
+Type = DEFAULT
+
+EXE1 = test6
+
+LANG = cpp
+
+Description
+
+= Test to make sure the PAL_EXCEPT_EX block is executed
+
+= after an exception occurs in the PAL_TRY block
+
+= that contains multiple PAL_TRY-PAL_EXCEPT_EX blocks
diff --git a/src/pal/tests/palsuite/exception_handling/pal_except/test7/CMakeLists.txt b/src/pal/tests/palsuite/exception_handling/pal_except/test7/CMakeLists.txt
new file mode 100644
index 0000000000..09399c8f6b
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/pal_except/test7/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test7.c
+)
+
+add_executable(paltest_pal_except_test7
+ ${SOURCES}
+)
+
+add_dependencies(paltest_pal_except_test7 coreclrpal)
+
+target_link_libraries(paltest_pal_except_test7
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/exception_handling/pal_except/test7/test7.c b/src/pal/tests/palsuite/exception_handling/pal_except/test7/test7.c
new file mode 100644
index 0000000000..a8dc8331c2
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/pal_except/test7/test7.c
@@ -0,0 +1,67 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test7.c (exception_handling\pal_except\test7)
+**
+** Purpose: Tests the PAL implementation of the PAL_TRY and
+** PAL_EXCEPT functions. Tests that the EXCEPTION block
+** is missed if no exceptions happen
+**
+**
+**===================================================================*/
+
+
+
+#include <palsuite.h>
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ BOOL bTry = FALSE;
+ BOOL bExcept = FALSE;
+
+ if (0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ /*
+ ** Test to make sure we skip the exception block.
+ */
+
+ PAL_TRY
+ {
+ bTry = TRUE; /* indicate we hit the PAL_TRY block */
+ }
+ PAL_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ bExcept = TRUE; /* indicate we hit the PAL_EXCEPT block */
+ }
+ PAL_ENDTRY;
+
+ if (!bTry)
+ {
+ Trace("PAL_TRY_EXCEPT: ERROR -> It appears the code in the PAL_TRY"
+ " block was not executed.\n");
+ }
+
+ if (bExcept)
+ {
+ Trace("PAL_TRY_EXCEPT: ERROR -> It appears the code in the PAL_EXCEPT"
+ " block was executed even though no exception was supposed to"
+ " happen.\n");
+ }
+
+ /* did we hit the correct code blocks? */
+ if(!bTry || bExcept)
+ {
+ Fail("");
+ }
+
+ PAL_Terminate();
+ return PASS;
+
+}
diff --git a/src/pal/tests/palsuite/exception_handling/pal_except/test7/testinfo.dat b/src/pal/tests/palsuite/exception_handling/pal_except/test7/testinfo.dat
new file mode 100644
index 0000000000..546d64cdec
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/pal_except/test7/testinfo.dat
@@ -0,0 +1,24 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+
+Section = exception_handling
+
+Function = PAL_TRY and PAL_EXCEPT
+
+Name = Test for PAL_TRY and PAL_EXCEPT
+
+Type = DEFAULT
+
+EXE1 = test7
+
+LANG = cpp
+
+Description
+
+= In this test, no exceptions are forced to ensure the EXCEPTION block
+
+= isn't hit.
+
diff --git a/src/pal/tests/palsuite/exception_handling/pal_finally/CMakeLists.txt b/src/pal/tests/palsuite/exception_handling/pal_finally/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/pal_finally/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/exception_handling/pal_finally/test1/CMakeLists.txt b/src/pal/tests/palsuite/exception_handling/pal_finally/test1/CMakeLists.txt
new file mode 100644
index 0000000000..5d947ad7db
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/pal_finally/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ pal_finally.c
+)
+
+add_executable(paltest_pal_finally_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_pal_finally_test1 coreclrpal)
+
+target_link_libraries(paltest_pal_finally_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/exception_handling/pal_finally/test1/pal_finally.c b/src/pal/tests/palsuite/exception_handling/pal_finally/test1/pal_finally.c
new file mode 100644
index 0000000000..f278f98956
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/pal_finally/test1/pal_finally.c
@@ -0,0 +1,302 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: pal_finally.c (test 3)
+**
+** Purpose: Tests the PAL implementation of the PAL_FINALLY in the
+** presence of a call stack. An exception is forced and
+** passed to two nested exception filters for consideration.
+** The first filter returns EXCEPTION_CONTINUE_SEARCH so the
+** second can run and return EXCEPTION_EXECUTE_HANDLER. The
+** initial exception handler should be skipped, and the
+** second executed, and all the PAL_FINALLY blocks handled
+**
+**
+**===================================================================*/
+#include <palsuite.h>
+
+BOOL bFilterCS = FALSE;
+BOOL bFilterEE = FALSE;
+BOOL bFinally1 = FALSE;
+BOOL bFinally2 = FALSE;
+BOOL bFinally3 = FALSE;
+BOOL bFinally4 = FALSE;
+BOOL bTry1 = FALSE;
+BOOL bTry2 = FALSE;
+BOOL bExcept1 = FALSE;
+BOOL bExcept2 = FALSE;
+BOOL bContinued = FALSE;
+const int nValidator = 12321;
+
+LONG ContSearchFilter(EXCEPTION_POINTERS* ep, LPVOID pnTestInt)
+{
+
+ /* let the main know we've hit the filter function */
+ bFilterCS = TRUE;
+
+ if (!bTry1 || !bTry2)
+ {
+ Fail("PAL_EXCEPT_FILTER: ERROR -> Something weird is going on."
+ " The ContSearch filter was hit without PAL_TRY being hit.\n");
+ }
+
+ if (bFilterEE)
+ {
+ Fail("PAL_EXCEPT_FILTER: ERROR -> Something weird is going on."
+ " The ContSearch filter was hit after the ExecuteException "
+ "filter.\n");
+ }
+
+ return EXCEPTION_CONTINUE_SEARCH;
+}
+
+LONG ExecExeptionFilter(EXCEPTION_POINTERS* ep, LPVOID pnTestInt)
+{
+ /* let the main know we've hit the filter function */
+ bFilterEE = TRUE;
+
+ if (!bTry1 || !bTry2)
+ {
+ Fail("PAL_EXCEPT_FILTER: ERROR -> Something weird is going on."
+ " The ContSearch filter was hit without PAL_TRY being hit.\n");
+ }
+
+ if (!bFilterCS)
+ {
+ Fail("PAL_EXCEPT_FILTER: ERROR -> Something weird is going on."
+ " The ExecExeption filter was hit before the ContSearch "
+ "filter.\n");
+ }
+ return EXCEPTION_EXECUTE_HANDLER;
+}
+
+void NestedFunc1 (void)
+{
+ int* p = 0x00000000; /* pointer to NULL */
+
+ PAL_TRY
+ {
+ PAL_TRY
+ {
+
+ if (bExcept1 || bExcept2)
+ {
+ Fail("PAL_EXCEPT_FILTER: ERROR -> Something weird is going on."
+ " PAL_EXCEPT_FILTER was hit before PAL_TRY.\n");
+ }
+ bTry2 = TRUE; /* indicate we hit the inner PAL_TRY block */
+ *p = 13; /* causes an access violation exception */
+
+ Fail("PAL_EXCEPT_FILTER: ERROR -> Something weird is going on."
+ " We executed beyond the trapping code.\n");
+ }
+ PAL_FINALLY
+ {
+ if (!bTry1)
+ {
+ Fail("PAL_EXCEPT_FILTER: ERROR -> Something weird is going on."
+ " The first finally handler was hit without the outer "
+ "PAL_TRY's code being hit.\n");
+ }
+ if (!bTry2)
+ {
+ Fail("PAL_EXCEPT_FILTER: ERROR -> Something weird is going on."
+ " The first finally handler was hit without the inner "
+ "PAL_TRY's code being hit.\n");
+ }
+ if (!bFilterCS)
+ {
+ Fail("PAL_EXCEPT_FILTER: ERROR -> Something weird is going on."
+ " The first finally handler was hit without the inner "
+ "filter being hit.\n");
+ }
+ if (!bFilterEE)
+ {
+ Fail("PAL_EXCEPT_FILTER: ERROR -> Something weird is going on."
+ " The first finally handler handler was hit without the "
+ "outer filter being hit.\n");
+ }
+ bFinally1 = TRUE; /* indicate we hit the first finally block */
+ }
+ PAL_ENDTRY;
+ }
+ PAL_EXCEPT_FILTER(ContSearchFilter, (LPVOID)&nValidator)
+ {
+ Fail("PAL_EXCEPT_FILTER: ERROR -> Something weird is going on."
+ " The dummy handler was "
+ "being hit.\n");
+ bExcept2 = TRUE; /* indicate we hit the inner block */
+ }
+ PAL_ENDTRY;
+
+}
+
+void NestedFunc2 (void)
+{
+ PAL_TRY
+ {
+ NestedFunc1();
+ }
+ PAL_FINALLY
+ {
+ if (!bFinally1)
+ {
+ Fail("PAL_EXCEPT_FILTER: ERROR -> Something weird is going on."
+ " The second finally handler handler was hit without the "
+ " top level one being hit.\n");
+ }
+ bFinally2 = TRUE;
+ }
+ PAL_ENDTRY ;
+}
+
+int __cdecl main(int argc, char *argv[])
+{
+ if (0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ /*
+ ** test to make sure we get into the second exception block only based
+ ** on the return codes of the filters
+ */
+
+ PAL_TRY
+ {
+ PAL_TRY
+ {
+ PAL_TRY
+ {
+ if (bExcept1 || bExcept2)
+ {
+ Fail("PAL_EXCEPT_FILTER: ERROR -> Something weird is going"
+ " on. PAL_EXCEPT_FILTER was hit before PAL_TRY.\n");
+ }
+ bTry1 = TRUE; /* indicate we hit the outer PAL_TRY block */
+
+ NestedFunc2();
+
+ Fail("PAL_EXCEPT_FILTER: ERROR -> Something weird is going on."
+ " We executed beyond the trapping code.\n");
+ }
+ PAL_FINALLY
+ {
+ if (!bFinally2)
+ {
+ Fail("PAL_EXCEPT_FILTER: ERROR -> Something weird is going"
+ " on. Finally handlers hit out of order (2->3)\n");
+ }
+ bFinally3 = TRUE;
+ }
+ PAL_ENDTRY;
+ }
+ PAL_EXCEPT_FILTER(ExecExeptionFilter, (LPVOID)&nValidator)
+ {
+ if (!bTry1)
+ {
+ Fail("PAL_EXCEPT_FILTER: ERROR -> Something weird is going on."
+ " PAL_EXCEPT_FILTER's handler was hit without the outer "
+ "PAL_TRY's code being hit.\n");
+ }
+ if (!bTry2)
+ {
+ Fail("PAL_EXCEPT_FILTER: ERROR -> Something weird is going on."
+ " PAL_EXCEPT_FILTER's handler was hit without the inner "
+ "PAL_TRY's code being hit.\n");
+ }
+ if (!bFilterCS)
+ {
+ Fail("PAL_EXCEPT_FILTER: ERROR -> Something weird is going on."
+ " PAL_EXCEPT_FILTER's handler was hit without the inner "
+ "filter being hit.\n");
+ }
+ if (!bFilterEE)
+ {
+ Fail("PAL_EXCEPT_FILTER: ERROR -> Something weird is going on."
+ " PAL_EXCEPT_FILTER's handler was hit without the outer "
+ "filter being hit.\n");
+ }
+ bExcept1 = TRUE; /* indicate we hit the outer block */
+ }
+ PAL_ENDTRY;
+
+ if (bFinally4)
+ {
+ Fail("PAL_EXCEPT_FILTER: ERROR -> Something weird is going on."
+ " Finally handler # 4 executed before it should be \n");
+ }
+ }
+ PAL_FINALLY
+ {
+ if (!bExcept1 || bExcept2)
+ {
+ Fail("PAL_EXCEPT_FILTER: ERROR -> Something weird is going on."
+ " Exceptions handlers hit in wierd ways\n");
+ }
+ if (!bFinally3)
+ {
+ Fail("PAL_EXCEPT_FILTER: ERROR -> Something weird is going on."
+ " Finally handlers hit out of order 3->4)\n");
+ }
+
+ bFinally4 = TRUE;
+ }
+ PAL_ENDTRY;
+
+ if (!bTry1)
+ {
+ Trace("PAL_EXCEPT_FILTER: ERROR -> It appears the code in the outer"
+ " PAL_TRY block was not executed.\n");
+ }
+
+ if (!bTry2)
+ {
+ Trace("PAL_EXCEPT_FILTER: ERROR -> It appears the code in the inner"
+ " PAL_TRY block was not executed.\n");
+ }
+
+ if (bExcept2)
+ {
+ Trace("PAL_EXCEPT_FILTER: ERROR -> It appears the code in the "
+ "inner PAL_EXCEPT_FILTER block was executed.\n");
+ }
+ if (!bExcept1)
+ {
+ Trace("PAL_EXCEPT_FILTER: ERROR -> It appears the code in the "
+ "outer PAL_EXCEPT_FILTER block was not executed.\n");
+ }
+
+ if (!bFilterCS)
+ {
+ Trace("PAL_EXCEPT_FILTER: ERROR -> It appears the code in the "
+ "search continuing filter"
+ " function was not executed.\n");
+ }
+ if (!bFilterEE)
+ {
+ Trace("PAL_EXCEPT_FILTER: ERROR -> It appears the code in the "
+ "execute handler filter"
+ " function was not executed.\n");
+ }
+
+ /* did we hit all the code blocks? */
+ if (!bFinally1 || !bFinally2 || !bFinally3 || !bFinally4)
+ {
+ Fail("");
+ }
+ if(!bTry1 || !bTry2 || !bExcept1 || bExcept2 || !bFilterEE || !bFilterCS )
+ {
+ Fail("");
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+
+}
+
diff --git a/src/pal/tests/palsuite/exception_handling/pal_finally/test1/testinfo.dat b/src/pal/tests/palsuite/exception_handling/pal_finally/test1/testinfo.dat
new file mode 100644
index 0000000000..5c26243438
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/pal_finally/test1/testinfo.dat
@@ -0,0 +1,19 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = exception_handling
+Function = PAL_FINALLY
+Name = Test for nested PAL_FINALLY
+Type = DEFAULT
+EXE1 = pal_finally
+LANG = cpp
+Description
+= Tests the PAL implementation of the PAL_FINALLY in the presence
+= of a call stack. An exception is forced and passed to two nested
+= exception filters for consideration. The first filter returns
+= EXCEPTION_CONTINUE_SEARCH so the second can run and return
+= EXCEPTION_EXECUTE_HANDLER. The initial exception handler should
+= be skipped, and the second executed, and all the PAL_FINALLY
+= blocks handled.
diff --git a/src/pal/tests/palsuite/exception_handling/pal_sxs/CMakeLists.txt b/src/pal/tests/palsuite/exception_handling/pal_sxs/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/pal_sxs/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/exception_handling/pal_sxs/test1/CMakeLists.txt b/src/pal/tests/palsuite/exception_handling/pal_sxs/test1/CMakeLists.txt
new file mode 100644
index 0000000000..b0458db998
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/pal_sxs/test1/CMakeLists.txt
@@ -0,0 +1,97 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+if(CLR_CMAKE_PLATFORM_UNIX)
+ add_compile_options(-fPIC)
+ add_definitions(-DFEATURE_ENABLE_HARDWARE_EXCEPTIONS)
+endif(CLR_CMAKE_PLATFORM_UNIX)
+
+# Set the RPATH of paltest_pal_sxs_test1 so that it can find dependencies without needing to set LD_LIBRARY
+# For more information: http://www.cmake.org/Wiki/CMake_RPATH_handling.
+if(CORECLR_SET_RPATH)
+ if(CLR_CMAKE_PLATFORM_LINUX)
+ set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
+ set(CMAKE_INSTALL_RPATH "\$ORIGIN")
+ endif(CLR_CMAKE_PLATFORM_LINUX)
+endif(CORECLR_SET_RPATH)
+
+# Test DLL1
+
+set(DEF_SOURCES1 dlltest1.src)
+convert_to_absolute_path(DEF_SOURCES1 ${DEF_SOURCES1})
+set(EXPORTS_FILE1 ${CMAKE_CURRENT_BINARY_DIR}/dlltest1.exports)
+generate_exports_file(${DEF_SOURCES1} ${EXPORTS_FILE1})
+
+if(CMAKE_SYSTEM_NAME STREQUAL Linux OR CMAKE_SYSTEM_NAME STREQUAL FreeBSD OR CMAKE_SYSTEM_NAME STREQUAL NetBSD)
+ set(EXPORTS_LINKER_OPTION1 -Wl,--version-script=${EXPORTS_FILE1})
+endif(CMAKE_SYSTEM_NAME STREQUAL Linux OR CMAKE_SYSTEM_NAME STREQUAL FreeBSD OR CMAKE_SYSTEM_NAME STREQUAL NetBSD)
+
+if(CMAKE_SYSTEM_NAME STREQUAL Darwin)
+ set(EXPORTS_LINKER_OPTION1 -Wl,-exported_symbols_list,${EXPORTS_FILE1})
+endif(CMAKE_SYSTEM_NAME STREQUAL Darwin)
+
+set(DLL1SOURCES dlltest1.cpp)
+add_library(paltest_pal_sxs_test1_dll1 SHARED ${DLL1SOURCES})
+add_custom_target(dlltest1_exports DEPENDS ${EXPORTS_FILE1})
+set_property(TARGET paltest_pal_sxs_test1_dll1 APPEND_STRING PROPERTY LINK_FLAGS ${EXPORTS_LINKER_OPTION1})
+set_property(TARGET paltest_pal_sxs_test1_dll1 APPEND_STRING PROPERTY LINK_DEPENDS ${EXPORTS_FILE1})
+
+add_dependencies(paltest_pal_sxs_test1_dll1
+ dlltest1_exports
+ coreclrpal
+)
+
+target_link_libraries(paltest_pal_sxs_test1_dll1
+ pthread
+ m
+ coreclrpal
+)
+
+# Test DLL2
+
+set(DEF_SOURCES2 dlltest2.src)
+convert_to_absolute_path(DEF_SOURCES2 ${DEF_SOURCES2})
+set(EXPORTS_FILE2 ${CMAKE_CURRENT_BINARY_DIR}/dlltest2.exports)
+generate_exports_file(${DEF_SOURCES2} ${EXPORTS_FILE2})
+
+if(CMAKE_SYSTEM_NAME STREQUAL Linux OR CMAKE_SYSTEM_NAME STREQUAL FreeBSD OR CMAKE_SYSTEM_NAME STREQUAL NetBSD)
+ set(EXPORTS_LINKER_OPTION2 -Wl,--version-script=${EXPORTS_FILE2})
+endif(CMAKE_SYSTEM_NAME STREQUAL Linux OR CMAKE_SYSTEM_NAME STREQUAL FreeBSD OR CMAKE_SYSTEM_NAME STREQUAL NetBSD)
+
+if(CMAKE_SYSTEM_NAME STREQUAL Darwin)
+ set(EXPORTS_LINKER_OPTION2 -Wl,-exported_symbols_list,${EXPORTS_FILE2})
+endif(CMAKE_SYSTEM_NAME STREQUAL Darwin)
+
+set(DLL2SOURCES dlltest2.cpp)
+add_library(paltest_pal_sxs_test1_dll2 SHARED ${DLL2SOURCES})
+add_custom_target(dlltest2_exports DEPENDS ${EXPORTS_FILE2})
+set_property(TARGET paltest_pal_sxs_test1_dll2 APPEND_STRING PROPERTY LINK_FLAGS ${EXPORTS_LINKER_OPTION2})
+set_property(TARGET paltest_pal_sxs_test1_dll2 APPEND_STRING PROPERTY LINK_DEPENDS ${EXPORTS_FILE2})
+
+add_dependencies(paltest_pal_sxs_test1_dll2
+ dlltest2_exports
+ coreclrpal
+)
+
+target_link_libraries(paltest_pal_sxs_test1_dll2
+ pthread
+ m
+ coreclrpal
+)
+
+# Main program
+
+set(TESTSOURCES exceptionsxs.cpp)
+
+add_executable(paltest_pal_sxs_test1 ${TESTSOURCES})
+
+add_dependencies(paltest_pal_sxs_test1
+ paltest_pal_sxs_test1_dll1
+ paltest_pal_sxs_test1_dll2
+)
+
+target_link_libraries(paltest_pal_sxs_test1
+ paltest_pal_sxs_test1_dll1
+ paltest_pal_sxs_test1_dll2
+)
diff --git a/src/pal/tests/palsuite/exception_handling/pal_sxs/test1/dlltest1.cpp b/src/pal/tests/palsuite/exception_handling/pal_sxs/test1/dlltest1.cpp
new file mode 100644
index 0000000000..614690897a
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/pal_sxs/test1/dlltest1.cpp
@@ -0,0 +1,75 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: dlltest1.c (exception_handling\pal_sxs\test1)
+**
+** Purpose: Test to make sure the PAL_EXCEPT block is executed
+** after an exception occurs in the PAL_TRY block with
+** multiple PALs in the process.
+**
+**
+**===================================================================*/
+#include <palsuite.h>
+
+extern "C"
+int InitializeDllTest1()
+{
+ return PAL_InitializeDLL();
+}
+
+BOOL bTry = FALSE;
+BOOL bExcept = FALSE;
+
+extern "C"
+int DllTest1()
+{
+ Trace("Starting pal_sxs test1 DllTest1\n");
+
+ PAL_TRY(VOID*, unused, NULL)
+ {
+ volatile int* p = (volatile int *)0x11; // Invalid pointer
+
+ bTry = TRUE; // Indicate we hit the PAL_TRY block
+ *p = 1; // Causes an access violation exception
+
+ Fail("ERROR: code was executed after the access violation.\n");
+ }
+ PAL_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ if (!bTry)
+ {
+ Fail("ERROR: PAL_EXCEPT was hit without PAL_TRY being hit.\n");
+ }
+
+ // Validate that the faulting address is correct; the contents of "p" (0x11).
+ if (ex.GetExceptionRecord()->ExceptionInformation[1] != 0x11)
+ {
+ Fail("ERROR: PAL_EXCEPT ExceptionInformation[1] != 0x11\n");
+ }
+
+ bExcept = TRUE; // Indicate we hit the PAL_EXCEPT block
+ }
+ PAL_ENDTRY;
+
+ if (!bTry)
+ {
+ Trace("ERROR: the code in the PAL_TRY block was not executed.\n");
+ }
+
+ if (!bExcept)
+ {
+ Trace("ERROR: the code in the PAL_EXCEPT block was not executed.\n");
+ }
+
+ // Did we hit all the code blocks?
+ if(!bTry || !bExcept)
+ {
+ Fail("DllTest1 FAILED\n");
+ }
+
+ Trace("DLLTest1 PASSED\n");
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/exception_handling/pal_sxs/test1/dlltest1.src b/src/pal/tests/palsuite/exception_handling/pal_sxs/test1/dlltest1.src
new file mode 100644
index 0000000000..0a0a6ee44a
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/pal_sxs/test1/dlltest1.src
@@ -0,0 +1,3 @@
+InitializeDllTest1
+DllTest1
+
diff --git a/src/pal/tests/palsuite/exception_handling/pal_sxs/test1/dlltest2.cpp b/src/pal/tests/palsuite/exception_handling/pal_sxs/test1/dlltest2.cpp
new file mode 100644
index 0000000000..1e85821422
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/pal_sxs/test1/dlltest2.cpp
@@ -0,0 +1,75 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: dlltest2.c (exception_handling\pal_sxs\test1)
+**
+** Purpose: Test to make sure the PAL_EXCEPT block is executed
+** after an exception occurs in the PAL_TRY block with
+** multiple PALs in the process.
+**
+**
+**===================================================================*/
+#include <palsuite.h>
+
+extern "C"
+int InitializeDllTest2()
+{
+ return PAL_InitializeDLL();
+}
+
+BOOL bTry = FALSE;
+BOOL bExcept = FALSE;
+
+extern "C"
+int DllTest2()
+{
+ Trace("Starting pal_sxs test1 DllTest2\n");
+
+ PAL_TRY(VOID*, unused, NULL)
+ {
+ volatile int* p = (volatile int *)0x22; // Invalid pointer
+
+ bTry = TRUE; // Indicate we hit the PAL_TRY block
+ *p = 2; // Causes an access violation exception
+
+ Fail("ERROR: code was executed after the access violation.\n");
+ }
+ PAL_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ if (!bTry)
+ {
+ Fail("ERROR: PAL_EXCEPT was hit without PAL_TRY being hit.\n");
+ }
+
+ // Validate that the faulting address is correct; the contents of "p" (0x22).
+ if (ex.GetExceptionRecord()->ExceptionInformation[1] != 0x22)
+ {
+ Fail("ERROR: PAL_EXCEPT ExceptionInformation[1] != 0x22\n");
+ }
+
+ bExcept = TRUE; // Indicate we hit the PAL_EXCEPT block
+ }
+ PAL_ENDTRY;
+
+ if (!bTry)
+ {
+ Trace("ERROR: the code in the PAL_TRY block was not executed.\n");
+ }
+
+ if (!bExcept)
+ {
+ Trace("ERROR: the code in the PAL_EXCEPT block was not executed.\n");
+ }
+
+ // Did we hit all the code blocks?
+ if(!bTry || !bExcept)
+ {
+ Fail("DllTest2 FAILED\n");
+ }
+
+ Trace("DLLTest2 PASSED\n");
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/exception_handling/pal_sxs/test1/dlltest2.src b/src/pal/tests/palsuite/exception_handling/pal_sxs/test1/dlltest2.src
new file mode 100644
index 0000000000..433419bc5b
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/pal_sxs/test1/dlltest2.src
@@ -0,0 +1,3 @@
+InitializeDllTest2
+DllTest2
+
diff --git a/src/pal/tests/palsuite/exception_handling/pal_sxs/test1/exceptionsxs.cpp b/src/pal/tests/palsuite/exception_handling/pal_sxs/test1/exceptionsxs.cpp
new file mode 100644
index 0000000000..97a963c120
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/pal_sxs/test1/exceptionsxs.cpp
@@ -0,0 +1,117 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: exceptionsxs.c (exception_handling\pal_sxs\test1)
+**
+** Purpose: Test to make sure the PAL_EXCEPT block is executed
+** after an exception occurs in the PAL_TRY block with
+** multiple PALs in the process.
+**
+**
+**===================================================================*/
+
+#include <stdio.h>
+#include <signal.h>
+#include <errno.h>
+#include <sys/ucontext.h>
+#include <sys/utsname.h>
+#include <unistd.h>
+
+enum
+{
+ PASS = 0,
+ FAIL = 1
+};
+
+extern "C" int InitializeDllTest1();
+extern "C" int InitializeDllTest2();
+extern "C" int DllTest1();
+extern "C" int DllTest2();
+
+bool bSignal = false;
+bool bCatch = false;
+bool bHandler = false;
+
+void sigsegv_handler(int code, siginfo_t *siginfo, void *context)
+{
+ printf("pal_sxs test1: signal handler called\n");
+ bHandler = true; // Mark that the signal handler was executed
+
+ if (!bSignal)
+ {
+ printf("ERROR: executed signal handler NOT from try/catch\n");
+ _exit(FAIL);
+ }
+
+ // Validate that the faulting address is correct; the contents of "p" (0x22).
+ if (siginfo->si_addr != (void *)0x33)
+ {
+ printf("ERROR: signal handler faulting address != 0x33\n");
+ _exit(FAIL);
+ }
+
+ // Unmask signal so we can receive it again
+ sigset_t signal_set;
+ sigemptyset(&signal_set);
+ sigaddset(&signal_set, SIGSEGV);
+ if (-1 == sigprocmask(SIG_UNBLOCK, &signal_set, NULL))
+ {
+ printf("ERROR: sigprocmask failed; error is %d\n", errno);
+ _exit(FAIL);
+ }
+
+ printf("Signal chaining PASSED\n");
+ _exit(PASS);
+}
+
+int main(int argc, char *argv[])
+{
+ struct sigaction newAction;
+ struct sigaction oldAction;
+ newAction.sa_flags = SA_SIGINFO | SA_RESTART;
+ newAction.sa_handler = NULL;
+ newAction.sa_sigaction = sigsegv_handler;
+ sigemptyset(&newAction.sa_mask);
+
+ if (-1 == sigaction(SIGSEGV, &newAction, &oldAction))
+ {
+ printf("ERROR: sigaction failed; error is %d\n", errno);
+ return FAIL;
+ }
+
+ printf("PAL_SXS test1 SIGSEGV handler %p\n", oldAction.sa_sigaction);
+
+ if (0 != InitializeDllTest1())
+ {
+ return FAIL;
+ }
+
+ if (0 != InitializeDllTest2())
+ {
+ return FAIL;
+ }
+
+ // Test catching exceptions in other PAL instances
+ DllTest2();
+ DllTest1();
+ DllTest2();
+
+ if (bHandler)
+ {
+ printf("ERROR: signal handler called by PAL sxs tests\n");
+ return FAIL;
+ }
+
+ printf("Starting PAL_SXS test1 signal chaining\n");
+
+ bSignal = true;
+
+ volatile int* p = (volatile int *)0x33; // Invalid pointer
+ *p = 3; // Causes an access violation exception
+
+ printf("ERROR: code was executed after the access violation.\n");
+ return FAIL;
+}
diff --git a/src/pal/tests/palsuite/exception_handling/pal_sxs/test1/testinfo.dat b/src/pal/tests/palsuite/exception_handling/pal_sxs/test1/testinfo.dat
new file mode 100644
index 0000000000..c0cf1ddfcb
--- /dev/null
+++ b/src/pal/tests/palsuite/exception_handling/pal_sxs/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = exception_handling
+Function = test1
+Name = pal_sxs test #1
+TYPE = DEFAULT
+EXE1 = test1
+LANG = cpp
+Description
+=Tests that exceptions across multiples pals work correctly
diff --git a/src/pal/tests/palsuite/file_io/AreFileApisANSI/CMakeLists.txt b/src/pal/tests/palsuite/file_io/AreFileApisANSI/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/AreFileApisANSI/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/file_io/AreFileApisANSI/test1/AreFileApisANSI.c b/src/pal/tests/palsuite/file_io/AreFileApisANSI/test1/AreFileApisANSI.c
new file mode 100644
index 0000000000..ec61f0cb7d
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/AreFileApisANSI/test1/AreFileApisANSI.c
@@ -0,0 +1,40 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: AreFileApisANSI.c
+**
+** Purpose: Tests the PAL implementation of the AreFileApisANSI function.
+** The only possible return is TRUE.
+**
+**
+**===================================================================*/
+
+
+
+#include <palsuite.h>
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ BOOL bRc = FALSE;
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ bRc = AreFileApisANSI();
+
+
+ if (bRc == FALSE)
+ {
+ Fail("AreFileApisANSI: ERROR: Function returned FALSE whereas only TRUE "
+ "is acceptable.\n");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/file_io/AreFileApisANSI/test1/CMakeLists.txt b/src/pal/tests/palsuite/file_io/AreFileApisANSI/test1/CMakeLists.txt
new file mode 100644
index 0000000000..4f50127cb9
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/AreFileApisANSI/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ AreFileApisANSI.c
+)
+
+add_executable(paltest_arefileapisansi_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_arefileapisansi_test1 coreclrpal)
+
+target_link_libraries(paltest_arefileapisansi_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/AreFileApisANSI/test1/testinfo.dat b/src/pal/tests/palsuite/file_io/AreFileApisANSI/test1/testinfo.dat
new file mode 100644
index 0000000000..5e6b422ae4
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/AreFileApisANSI/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = AreFileApisANSI
+Name = Positive Test for AreFileApisANSI
+Type = DEFAULT
+EXE1 = arefileapisansi
+Description
+=Ensure the return is TRUE because FALSE is not an option in FreeBSD
+
diff --git a/src/pal/tests/palsuite/file_io/CMakeLists.txt b/src/pal/tests/palsuite/file_io/CMakeLists.txt
new file mode 100644
index 0000000000..3d6eff1379
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/CMakeLists.txt
@@ -0,0 +1,61 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(AreFileApisANSI)
+add_subdirectory(CompareFileTime)
+add_subdirectory(CopyFileA)
+add_subdirectory(CopyFileW)
+add_subdirectory(CreateDirectoryA)
+add_subdirectory(CreateDirectoryW)
+add_subdirectory(CreateFileA)
+add_subdirectory(CreateFileW)
+add_subdirectory(DeleteFileA)
+add_subdirectory(DeleteFileW)
+add_subdirectory(errorpathnotfound)
+add_subdirectory(FILECanonicalizePath)
+add_subdirectory(FileTimeToDosDateTime)
+add_subdirectory(FindClose)
+add_subdirectory(FindFirstFileA)
+add_subdirectory(FindFirstFileW)
+add_subdirectory(FindNextFileA)
+add_subdirectory(FindNextFileW)
+add_subdirectory(FlushFileBuffers)
+add_subdirectory(GetConsoleCP)
+add_subdirectory(GetConsoleOutputCP)
+add_subdirectory(GetCurrentDirectoryA)
+add_subdirectory(GetCurrentDirectoryW)
+add_subdirectory(GetDiskFreeSpaceW)
+add_subdirectory(GetFileAttributesA)
+add_subdirectory(GetFileAttributesExW)
+add_subdirectory(GetFileAttributesW)
+add_subdirectory(GetFileSize)
+add_subdirectory(GetFileSizeEx)
+add_subdirectory(GetFileTime)
+add_subdirectory(GetFileType)
+add_subdirectory(GetFullPathNameA)
+add_subdirectory(GetFullPathNameW)
+add_subdirectory(GetLongPathNameW)
+add_subdirectory(GetStdHandle)
+add_subdirectory(GetSystemTime)
+add_subdirectory(GetSystemTimeAsFileTime)
+add_subdirectory(GetTempFileNameA)
+add_subdirectory(GetTempFileNameW)
+add_subdirectory(gettemppatha)
+add_subdirectory(GetTempPathW)
+add_subdirectory(MoveFileA)
+add_subdirectory(MoveFileExA)
+add_subdirectory(MoveFileExW)
+add_subdirectory(MoveFileW)
+add_subdirectory(ReadFile)
+add_subdirectory(RemoveDirectoryA)
+add_subdirectory(RemoveDirectoryW)
+add_subdirectory(SearchPathA)
+add_subdirectory(SearchPathW)
+add_subdirectory(SetCurrentDirectoryA)
+add_subdirectory(SetCurrentDirectoryW)
+add_subdirectory(SetEndOfFile)
+add_subdirectory(SetFileAttributesA)
+add_subdirectory(SetFileAttributesW)
+add_subdirectory(SetFilePointer)
+add_subdirectory(SetFileTime)
+add_subdirectory(WriteFile)
+
diff --git a/src/pal/tests/palsuite/file_io/CompareFileTime/CMakeLists.txt b/src/pal/tests/palsuite/file_io/CompareFileTime/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/CompareFileTime/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/file_io/CompareFileTime/test1/CMakeLists.txt b/src/pal/tests/palsuite/file_io/CompareFileTime/test1/CMakeLists.txt
new file mode 100644
index 0000000000..fdcb6559b3
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/CompareFileTime/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ CompareFileTime.c
+)
+
+add_executable(paltest_comparefiletime_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_comparefiletime_test1 coreclrpal)
+
+target_link_libraries(paltest_comparefiletime_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/CompareFileTime/test1/CompareFileTime.c b/src/pal/tests/palsuite/file_io/CompareFileTime/test1/CompareFileTime.c
new file mode 100644
index 0000000000..3758f7e4eb
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/CompareFileTime/test1/CompareFileTime.c
@@ -0,0 +1,68 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: CompareFileTime.c
+**
+** Purpose: Tests the PAL implementation of the CompareFileTime function.
+** Defines a large and small file time, and compares them in all fashions
+** to ensure proper return values.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+
+
+int __cdecl main(int argc, char **argv)
+{
+
+ FILETIME SmallTime, BigTime;
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ /* Set a Big and Small time. These were generated using
+ GetFileTime on a file, with a recent creation time and an old
+ modify time, to get a bigger and smaller value.
+ */
+
+ BigTime.dwLowDateTime = -755748832;
+ BigTime.dwHighDateTime = 29436941;
+
+ SmallTime.dwLowDateTime = -459754240;
+ SmallTime.dwHighDateTime = 29436314;
+
+ /* Check to see that SmallTime is less than Big Time */
+
+ if(CompareFileTime(&SmallTime,&BigTime) != -1)
+ {
+ Fail("ERROR: The first time is less than the second time, so "
+ "-1 should have been returned to indicate this.");
+ }
+
+ /* Check that BigTime is greater than SmallTime */
+
+ if(CompareFileTime(&BigTime,&SmallTime) != 1)
+ {
+ Fail("ERROR: The first time is greater than the second time, so "
+ "1 should have been returned to indicate this.");
+ }
+
+ /* Check that BigTime is equal to BigTime */
+
+ if(CompareFileTime(&BigTime,&BigTime) != 0)
+ {
+ Fail("ERROR: The first time is equal to the second time, so "
+ "0 should have been returned to indicate this.");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/file_io/CompareFileTime/test1/testinfo.dat b/src/pal/tests/palsuite/file_io/CompareFileTime/test1/testinfo.dat
new file mode 100644
index 0000000000..4ff1b4c980
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/CompareFileTime/test1/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = CompareFileTime
+Name = Positive Test for CompareFileTime
+TYPE = DEFAULT
+EXE1 = comparefiletime
+Description
+= Test the CompareFileTime function.
+= Defines a large and small file time, and compares them in all fashions
+= to ensure proper return values.
diff --git a/src/pal/tests/palsuite/file_io/CopyFileA/CMakeLists.txt b/src/pal/tests/palsuite/file_io/CopyFileA/CMakeLists.txt
new file mode 100644
index 0000000000..a3847f8ca9
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/CopyFileA/CMakeLists.txt
@@ -0,0 +1,7 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+add_subdirectory(test3)
+add_subdirectory(test4)
+
diff --git a/src/pal/tests/palsuite/file_io/CopyFileA/test1/CMakeLists.txt b/src/pal/tests/palsuite/file_io/CopyFileA/test1/CMakeLists.txt
new file mode 100644
index 0000000000..b52e5076fa
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/CopyFileA/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ CopyFileA.c
+)
+
+add_executable(paltest_copyfilea_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_copyfilea_test1 coreclrpal)
+
+target_link_libraries(paltest_copyfilea_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/CopyFileA/test1/CopyFileA.c b/src/pal/tests/palsuite/file_io/CopyFileA/test1/CopyFileA.c
new file mode 100644
index 0000000000..bfea85b7cb
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/CopyFileA/test1/CopyFileA.c
@@ -0,0 +1,159 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: CopyFileA.c
+**
+** Purpose: Tests the PAL implementation of the CopyFileA function
+**
+**
+**===================================================================*/
+
+/*
+ 1. copy an existing file to existing with overwrite true
+ 2. copy an existing file to existing with overwrite false
+ 3. copy an existing file to non-existant with overwrite true
+ 4. copy an existing file to non-existant with overwrite false
+ 5. copy non-existant file to existing with overwrite true
+ 6. copy non-existant file to existing with overwrite false
+ 7. copy non-existant file to non-existant with overwrite true
+ 8. copy non-existant file to non-existant with overwrite false
+*/
+
+#include <palsuite.h>
+
+struct TESTS{
+ char* lpSource;
+ char* lpDestination;
+ BOOL bFailIfExists;
+ int nResult;
+ };
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ char szSrcExisting[] = {"src_existing.tmp"};
+ char szSrcNonExistant[] = {"src_non-existant.tmp"};
+ char szDstExisting[] = {"dst_existing.tmp"};
+ char szDstNonExistant[] = {"dst_non-existant.tmp"};
+ BOOL bRc = TRUE;
+ BOOL bSuccess = TRUE;
+ FILE* tempFile = NULL;
+ int i;
+ struct TESTS testCase[] =
+ {
+ {szSrcExisting, szDstExisting, FALSE, 1},
+ {szSrcExisting, szDstExisting, TRUE, 0},
+ {szSrcExisting, szDstNonExistant, FALSE, 1},
+ {szSrcExisting, szDstNonExistant, TRUE, 1},
+ {szSrcNonExistant, szDstExisting, FALSE, 0},
+ {szSrcNonExistant, szDstExisting, TRUE, 0},
+ {szSrcNonExistant, szDstNonExistant, FALSE, 0},
+ {szSrcNonExistant, szDstNonExistant, TRUE, 0}
+ };
+
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ /* create the src_existing file */
+ tempFile = fopen(szSrcExisting, "w");
+ if (tempFile != NULL)
+ {
+ fprintf(tempFile, "CopyFileA test file: src_existing.tmp\n");
+ fclose(tempFile);
+ }
+ else
+ {
+ Fail("CopyFileA: ERROR-> Couldn't create \"src_existing.tmp\" with "
+ "error %ld\n",
+ GetLastError());
+ }
+
+ /* create the dst_existing file */
+ tempFile = fopen(szDstExisting, "w");
+ if (tempFile != NULL)
+ {
+ fprintf(tempFile, "CopyFileA test file: dst_existing.tmp\n");
+ fclose(tempFile);
+ }
+ else
+ {
+ Fail("CopyFileA: ERROR-> Couldn't create \"dst_existing.tmp\" with "
+ "error %ld\n",
+ GetLastError());
+ }
+
+
+
+ for (i = 0; i < (sizeof(testCase) / sizeof(struct TESTS)); i++)
+ {
+ bRc = CopyFileA(testCase[i].lpSource,
+ testCase[i].lpDestination,
+ testCase[i].bFailIfExists);
+ if (!bRc)
+ {
+ if (testCase[i].nResult == 1)
+ {
+ Trace("CopyFileA: FAILED: %s -> %s with bFailIfExists = %d "
+ "with error %ld\n",
+ testCase[i].lpSource,
+ testCase[i].lpDestination,
+ testCase[i].bFailIfExists,
+ GetLastError());
+ bSuccess = FALSE;
+ }
+ }
+ else
+ {
+ if (testCase[i].nResult == 0)
+ {
+ Trace("CopyFileA: FAILED: %s -> %s with bFailIfExists = %d\n",
+ testCase[i].lpSource,
+ testCase[i].lpDestination,
+ testCase[i].bFailIfExists);
+ bSuccess = FALSE;
+ }
+ else
+ {
+ /* verify the file was moved */
+ if (GetFileAttributesA(testCase[i].lpDestination) == -1)
+ {
+ Trace("CopyFileA: GetFileAttributes of destination file "
+ "failed with error code %ld. \n",
+ GetLastError());
+ bSuccess = FALSE;
+ }
+ else if (GetFileAttributesA(testCase[i].lpSource) == -1)
+ {
+ Trace("CopyFileA: GetFileAttributes of source file "
+ "failed with error code %ld. \n",
+ GetLastError());
+ bSuccess = FALSE;
+ }
+ else
+ {
+ /* verify attributes of destination file to source file*/
+ if(GetFileAttributes(testCase[i].lpSource) !=
+ GetFileAttributes(testCase[i].lpDestination))
+ {
+ Trace("CopyFileA : The file attributes of the "
+ "destination file do not match the file "
+ "attributes of the source file.\n");
+ bSuccess = FALSE;
+ }
+ }
+ }
+ }
+ /* delete file file but don't worry if it fails */
+ DeleteFileA(szDstNonExistant);
+ }
+
+ int exitCode = bSuccess ? PASS : FAIL;
+ PAL_TerminateEx(exitCode);
+ return exitCode;
+}
diff --git a/src/pal/tests/palsuite/file_io/CopyFileA/test1/testinfo.dat b/src/pal/tests/palsuite/file_io/CopyFileA/test1/testinfo.dat
new file mode 100644
index 0000000000..88b9c73cb4
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/CopyFileA/test1/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = CopyFileA
+Name = Test for CopyFileA (test 1)
+Type = DEFAULT
+EXE1 = copyfilea
+Description
+= Test the CopyFileA function
diff --git a/src/pal/tests/palsuite/file_io/CopyFileA/test2/CMakeLists.txt b/src/pal/tests/palsuite/file_io/CopyFileA/test2/CMakeLists.txt
new file mode 100644
index 0000000000..7454f32f51
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/CopyFileA/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test2.c
+)
+
+add_executable(paltest_copyfilea_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_copyfilea_test2 coreclrpal)
+
+target_link_libraries(paltest_copyfilea_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/CopyFileA/test2/test2.c b/src/pal/tests/palsuite/file_io/CopyFileA/test2/test2.c
new file mode 100644
index 0000000000..56618d0a58
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/CopyFileA/test2/test2.c
@@ -0,0 +1,120 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test2.c
+**
+** Purpose: Tests the PAL implementation of the CopyFileA function
+** to see if a file can be copied to itself
+**
+**
+**===================================================================*/
+
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ BOOL bRc = TRUE;
+ char* szSrcExisting = "src_existing.tmp";
+ FILE* tempFile = NULL;
+ DWORD temp;
+ int retCode;
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ /* create the src_existing file */
+ tempFile = fopen(szSrcExisting, "w");
+ if (tempFile != NULL)
+ {
+ retCode = fputs("CopyFileA test file: src_existing.tmp ", tempFile);
+ if(retCode < 0)
+ {
+ Fail("CopyFileA: ERROR-> Couldn't write to %s with error "
+ "%u.\n", szSrcExisting, GetLastError());
+ }
+ retCode = fclose(tempFile);
+ if(retCode != 0)
+ {
+ Fail("CopyFileA: ERROR-> Couldn't close file: %s with error "
+ "%u.\n", szSrcExisting, GetLastError());
+ }
+
+ }
+ else
+ {
+ Fail("CopyFileA: ERROR-> Couldn't create %s with "
+ "error %ld\n",szSrcExisting,GetLastError());
+ }
+
+ /* Get file attributes of source */
+ temp = GetFileAttributes(szSrcExisting);
+ if (temp == -1)
+ {
+ Fail("CopyFileA: GetFileAttributes of source file "
+ "failed with error code %ld. \n",
+ GetLastError());
+ }
+
+ /* make sure a file can't copy to itself
+ first testing with IfFileExists flag set to true */
+ bRc = CopyFileA(szSrcExisting,szSrcExisting,TRUE);
+ if(bRc)
+ {
+ Fail("ERROR: Cannot copy a file to itself, %u",GetLastError());
+ }
+
+ /* try to get file attributes of desitnation */
+ if (GetFileAttributesA(szSrcExisting) == -1)
+ {
+ Fail("CopyFileA: GetFileAttributes of destination file "
+ "failed with error code %ld. \n",
+ GetLastError());
+ }
+ else
+ {
+ /* verify attributes of destination file to source file*/
+
+ if(temp != GetFileAttributes(szSrcExisting))
+ {
+ Fail("CopyFileA : The file attributes of the "
+ "destination file do not match the file "
+ "attributes of the source file.\n");
+ }
+ }
+
+ /* testing with IfFileExists flags set to false
+ should fail in Windows and pass in UNIX */
+ bRc = CopyFileA(szSrcExisting,szSrcExisting,FALSE);
+ if(bRc && (GetLastError() != ERROR_ALREADY_EXISTS))
+ {
+ Fail("ERROR: Cannot copy a file to itself, %u",GetLastError());
+ }
+
+ if (GetFileAttributesA(szSrcExisting) == -1)
+ {
+ Fail("CopyFileA: GetFileAttributes of destination file "
+ "failed with error code %ld. \n",
+ GetLastError());
+ }
+ else
+ {
+ /* verify attributes of destination file to source file*/
+
+ if(temp != GetFileAttributes(szSrcExisting))
+ {
+ Fail("CopyFileA : The file attributes of the "
+ "destination file do not match the file "
+ "attributes of the source file.\n");
+ }
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/file_io/CopyFileA/test2/testinfo.dat b/src/pal/tests/palsuite/file_io/CopyFileA/test2/testinfo.dat
new file mode 100644
index 0000000000..31143842e6
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/CopyFileA/test2/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = CopyFileA
+Name = CopyFileA - checking copying to itself (test2)
+Type = DEFAULT
+EXE1 = test2
+Description
+= Test the CopyFileA function's behaviour
+= for copying a file to itself.
+
diff --git a/src/pal/tests/palsuite/file_io/CopyFileA/test3/CMakeLists.txt b/src/pal/tests/palsuite/file_io/CopyFileA/test3/CMakeLists.txt
new file mode 100644
index 0000000000..986be9fd22
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/CopyFileA/test3/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test3.c
+)
+
+add_executable(paltest_copyfilea_test3
+ ${SOURCES}
+)
+
+add_dependencies(paltest_copyfilea_test3 coreclrpal)
+
+target_link_libraries(paltest_copyfilea_test3
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/CopyFileA/test3/test3.c b/src/pal/tests/palsuite/file_io/CopyFileA/test3/test3.c
new file mode 100644
index 0000000000..18c8ce80dc
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/CopyFileA/test3/test3.c
@@ -0,0 +1,141 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test3.c
+**
+** Purpose: Tests the PAL implementation of the CopyFileA function
+** to see if a file can be copied to itself
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ BOOL bRc = TRUE;
+ char* szSrcExisting = "src_existing.tmp";
+ char* szDest = "src_dest.tmp";
+ FILE* tempFile = NULL;
+ int retCode;
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ /* create the src_existing file */
+ tempFile = fopen(szSrcExisting, "w");
+ if (tempFile != NULL)
+ {
+ retCode = fputs("CopyFileA test file: src_existing.tmp ", tempFile);
+ if(retCode < 0)
+ {
+ retCode = fclose(tempFile);
+ if(retCode != 0)
+ {
+ Trace("CopyFileA: ERROR-> Couldn't close file: %s with error "
+ "%u.\n", szSrcExisting, GetLastError());
+ }
+
+ Fail("CopyFileA: ERROR-> Couldn't write to %s with error "
+ "%u.\n", szSrcExisting, GetLastError());
+ }
+ retCode = fclose(tempFile);
+ if(retCode != 0)
+ {
+ Fail("CopyFileA: ERROR-> Couldn't close file: %s with error "
+ "%u.\n", szSrcExisting, GetLastError());
+ }
+
+ }
+ else
+ {
+ Fail("CopyFileA: ERROR-> Couldn't create %s with "
+ "error %ld\n",szSrcExisting,GetLastError());
+ }
+
+ /* set the file attributes of the source file to readonly */
+ bRc = SetFileAttributes(szSrcExisting, FILE_ATTRIBUTE_READONLY);
+ if(!bRc)
+ {
+ Fail("CopyFileA: ERROR-> Couldn't set file attributes for "
+ "file %s with error %u\n", szSrcExisting, GetLastError());
+ }
+
+ // Check the file attributes to make sure SetFileAttributes() above actually succeeded
+ DWORD fileAttributes = GetFileAttributesA(szSrcExisting);
+ if (fileAttributes == INVALID_FILE_ATTRIBUTES)
+ {
+ Fail("CopyFileA: Failed to get file attributes for source file, %u\n", GetLastError());
+ }
+ if ((fileAttributes & FILE_ATTRIBUTE_READONLY) == 0)
+ {
+ Fail("CopyFileA: SetFileAttributes(read-only) on source file returned success but did not make it read-only.\n");
+ }
+
+ /* copy the file */
+ bRc = CopyFileA(szSrcExisting,szDest,TRUE);
+ if(!bRc)
+ {
+ Fail("CopyFileA: Cannot copy a file with error, %u",GetLastError());
+ }
+
+
+ /* try to get file attributes of destination file */
+ fileAttributes = GetFileAttributesA(szDest);
+ if (fileAttributes == INVALID_FILE_ATTRIBUTES)
+ {
+ Fail("CopyFileA: GetFileAttributes of destination file "
+ "failed with error code %ld. \n",
+ GetLastError());
+ }
+
+ /* verify attributes of destination file to source file*/
+ if((fileAttributes & FILE_ATTRIBUTE_READONLY) != FILE_ATTRIBUTE_READONLY)
+ {
+ Fail("CopyFileA : The file attributes of the "
+ "destination file do not match the file "
+ "attributes of the source file.\n");
+ }
+
+ /* set the attributes of the destination file to normal again */
+ bRc = SetFileAttributesA(szDest, FILE_ATTRIBUTE_NORMAL);
+ if(!bRc)
+ {
+ Fail("CopyFileA: ERROR-> Couldn't set file attributes for "
+ "file %s with error %u\n", szDest, GetLastError());
+ }
+
+ /* delete the newly copied file */
+ bRc = DeleteFile(szDest);
+ if(!bRc)
+ {
+ Fail("CopyFileA: DeleteFile failed to delete the"
+ "file correctly with error,%u.\n",GetLastError());
+ }
+
+ /* set the attributes of the source file to normal again */
+ bRc = SetFileAttributesA(szSrcExisting, FILE_ATTRIBUTE_NORMAL);
+ if(!bRc)
+ {
+ Fail("CopyFileA: ERROR-> Couldn't set file attributes for "
+ "file %s with error %u\n", szSrcExisting, GetLastError());
+ }
+
+ /* delete the original file */
+ bRc = DeleteFile(szSrcExisting);
+ if(!bRc)
+ {
+ Fail("CopyFileA: DeleteFile failed to delete the"
+ "file correctly with error,%u.\n",GetLastError());
+ }
+
+ PAL_Terminate();
+ return PASS;
+
+}
diff --git a/src/pal/tests/palsuite/file_io/CopyFileA/test3/testinfo.dat b/src/pal/tests/palsuite/file_io/CopyFileA/test3/testinfo.dat
new file mode 100644
index 0000000000..5a9775d14f
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/CopyFileA/test3/testinfo.dat
@@ -0,0 +1,16 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = CopyFileA
+Name = CopyFileA - checking file attributes maintained (test2)
+Type = DEFAULT
+EXE1 = test3
+Description
+= Test the CopyFileA function's behaviour
+= for copying a file and verifying that
+= the copied file has the same file attributes
+= as the original.
+
diff --git a/src/pal/tests/palsuite/file_io/CopyFileA/test4/CMakeLists.txt b/src/pal/tests/palsuite/file_io/CopyFileA/test4/CMakeLists.txt
new file mode 100644
index 0000000000..fb48c83741
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/CopyFileA/test4/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test4.c
+)
+
+add_executable(paltest_copyfilea_test4
+ ${SOURCES}
+)
+
+add_dependencies(paltest_copyfilea_test4 coreclrpal)
+
+target_link_libraries(paltest_copyfilea_test4
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/CopyFileA/test4/test4.c b/src/pal/tests/palsuite/file_io/CopyFileA/test4/test4.c
new file mode 100644
index 0000000000..1ae69f5e1f
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/CopyFileA/test4/test4.c
@@ -0,0 +1,180 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test4.c
+**
+** Purpose: Tests the PAL implementation of the CopyFileA function
+** to see if a file can through different users belonging to
+** different groups.
+**
+
+=====================================================================*/
+
+/* USECASE
+ Copy a file from a different user, belonging to a different group to
+ the the current user, who is a member of the current group. Then check
+ to see that the current user has the basic access rights to the copied
+ file.
+
+ Thie original file used is the passwd file in the etc directory of a
+ BSD machine. This file should exist on all machines.
+*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+
+#if WIN32
+ return PASS;
+
+#else
+
+ BOOL bRc = TRUE;
+ char* szSrcExisting = "/etc/passwd";
+ char* szDest = "temp.tmp";
+ char* szStringTest = "Marry had a little lamb";
+ char szStringRead[30]; /* large enough for string szStringTest */
+
+ HANDLE hFile = NULL;
+ DWORD dwBytesWritten=0;
+ DWORD dwBytesRead=0;
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ /* copy the file */
+ bRc = CopyFileA(szSrcExisting,szDest,TRUE);
+ if(!bRc)
+ {
+ Fail("CopyFileA: Cannot copy a file with error, %u",GetLastError());
+ }
+
+ /* try to get file attributes of destination file */
+ if (GetFileAttributesA(szDest) == -1)
+ {
+ Fail("CopyFileA: GetFileAttributes of destination file "
+ "failed with error code %u. \n",
+ GetLastError());
+ }
+
+ /* set the attributes of the destination file to normal again */
+ bRc = SetFileAttributes(szDest, FILE_ATTRIBUTE_NORMAL);
+ if(!bRc)
+ {
+ Fail("CopyFileA: ERROR-> Couldn't set file attributes for "
+ "file %s with error %u\n", szDest, GetLastError());
+ }
+
+ /* open the file for write purposes */
+ hFile = CreateFile(szDest,
+ GENERIC_WRITE,
+ 0,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if(hFile == INVALID_HANDLE_VALUE)
+ {
+ Fail("CopyFileA: ERROR -> Unable to create file \"%s\".\n",
+ szDest);
+ }
+
+ /* Attempt to write to the file */
+ bRc = WriteFile(hFile, szStringTest, strlen(szStringTest), &dwBytesWritten, NULL);
+ if (!bRc)
+ {
+ Trace("CopyFileA: ERROR -> Unable to write to copied file with error "
+ "%u.\n", GetLastError());
+ bRc = CloseHandle(hFile);
+ if (!bRc)
+ {
+ Fail("CopyFileA: ERROR -> Unable to close file \"%s\" with "
+ "error %u.\n",szDest, GetLastError());
+ }
+ Fail("");
+
+ }
+
+ /* Close the file handle */
+ bRc = CloseHandle(hFile);
+ if (!bRc)
+ {
+ Fail("CopyFileA: ERROR -> Unable to close file \"%s\" with error %u "
+ ".\n",szDest,GetLastError());
+ }
+
+
+ /* open the file for read purposes */
+ hFile = CreateFile(szDest,
+ GENERIC_READ,
+ 0,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if(hFile == INVALID_HANDLE_VALUE)
+ {
+ Fail("CopyFileA: ERROR -> Unable to create file \"%s\".\n",
+ szDest);
+ }
+
+ /* Attempt to read from the file */
+ bRc = ReadFile(hFile, szStringRead, strlen(szStringTest), &dwBytesRead, NULL);
+ if (!bRc)
+ {
+ Trace("CopyFileA: ERROR -> Unable to read from copied file with "
+ "error %u.\n",GetLastError());
+ bRc = CloseHandle(hFile);
+ if (!bRc)
+ {
+ Fail("CopyFileA: ERROR -> Unable to close file \"%s\" with "
+ "error %u.\n",szDest, GetLastError());
+ }
+ Fail("");
+
+ }
+
+ if(strncmp(szStringTest,szStringRead, strlen(szStringTest)) != 0)
+ {
+ Trace("CopyFileA: ERROR -> The string which was written '%s' does not "
+ "match the string '%s' which was read from the copied file.\n",
+ szStringTest,szStringRead);
+ bRc = CloseHandle(hFile);
+ if (!bRc)
+ {
+ Fail("CopyFileA: ERROR -> Unable to close file \"%s\" with "
+ "error %u.\n",szDest, GetLastError());
+ }
+ Fail("");
+ }
+
+ /* Close the file handle */
+ bRc = CloseHandle(hFile);
+ if (!bRc)
+ {
+ Fail("CopyFileA: ERROR -> Unable to close file \"%s\" with error %u "
+ ".\n",szDest,GetLastError());
+ }
+
+ /* Remove the temporary file */
+ bRc = DeleteFile(szDest);
+ if(!bRc)
+ {
+ Fail("CopyFileA: Could not remove copied file with error %u\n",
+ GetLastError());
+ }
+
+ PAL_Terminate();
+ return PASS;
+
+#endif
+
+}
diff --git a/src/pal/tests/palsuite/file_io/CopyFileA/test4/testinfo.dat b/src/pal/tests/palsuite/file_io/CopyFileA/test4/testinfo.dat
new file mode 100644
index 0000000000..42187b760f
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/CopyFileA/test4/testinfo.dat
@@ -0,0 +1,16 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = CopyFileA
+Name = CopyFileA - checking file attributes maintained (test4)
+Type = DEFAULT
+EXE1 = test4
+Description
+= Copy a file from a different user, belonging to a different group to
+= the the current user, who is a member of the current group. Then check
+= to see that the current user has the basic access rights to the copied
+= file.
+
diff --git a/src/pal/tests/palsuite/file_io/CopyFileW/CMakeLists.txt b/src/pal/tests/palsuite/file_io/CopyFileW/CMakeLists.txt
new file mode 100644
index 0000000000..1962ade358
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/CopyFileW/CMakeLists.txt
@@ -0,0 +1,6 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+add_subdirectory(test3)
+
diff --git a/src/pal/tests/palsuite/file_io/CopyFileW/test1/CMakeLists.txt b/src/pal/tests/palsuite/file_io/CopyFileW/test1/CMakeLists.txt
new file mode 100644
index 0000000000..766b120035
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/CopyFileW/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ CopyFileW.c
+)
+
+add_executable(paltest_copyfilew_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_copyfilew_test1 coreclrpal)
+
+target_link_libraries(paltest_copyfilew_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/CopyFileW/test1/CopyFileW.c b/src/pal/tests/palsuite/file_io/CopyFileW/test1/CopyFileW.c
new file mode 100644
index 0000000000..6127cc21bd
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/CopyFileW/test1/CopyFileW.c
@@ -0,0 +1,155 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: CopyFileW.c
+**
+** Purpose: Tests the PAL implementation of the CopyFileW function
+**
+**
+**===================================================================*/
+
+/*
+1. copy an existing file to non-existant with overwrite true
+2. copy an existing file to non-existant with overwrite false
+3. copy an existing file to existing with overwrite true
+4. copy an existing file to existing with overwrite false
+5. copy non-existant file to non-existant with overwrite true
+6. copy non-existant file to non-existant with overwrite false
+7. copy non-existant file to existing with overwrite true
+8. copy non-existant file to existing with overwrite false
+*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ LPSTR lpSource[2] = {"src_existing.tmp", "src_non-existant.tmp"};
+ LPSTR lpDestination[2] = {"dst_existing.tmp", "dst_non-existant.tmp"};
+ WCHAR* wcSource;
+ WCHAR* wcDest;
+ BOOL bFailIfExists[3] = {FALSE, TRUE};
+ BOOL bRc = TRUE;
+ BOOL bSuccess = TRUE;
+ char results[20];
+ FILE* resultsFile = NULL;
+ FILE* tempFile = NULL;
+ int nCounter = 0;
+ int i, j, k;
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ /* load the expected results */
+ resultsFile = fopen("expectedresults.txt", "r");
+ memset (results, 0, 20);
+ fgets(results, 20, resultsFile);
+ fclose(resultsFile);
+
+ nCounter = 0;
+
+ /* create the src_existing file */
+ tempFile = fopen(lpSource[0], "w");
+ if (tempFile != NULL)
+ {
+ fprintf(tempFile, "CopyFileW test file: src_existing.tmp\n");
+ fclose(tempFile);
+ }
+ else
+ {
+ Fail("CopyFileW: ERROR-> Couldn't create \"src_existing.tmp\"\n");
+ }
+
+ /* create the dst_existing file */
+ tempFile = fopen(lpDestination[0], "w");
+ if (tempFile != NULL)
+ {
+ fprintf(tempFile, "CopyFileW test file: dst_existing.tmp\n");
+ fclose(tempFile);
+ }
+ else
+ {
+ Fail("CopyFileW: ERROR-> Couldn't create \"dst_existing.tmp\"\n");
+ }
+
+
+ /* lpSource loop */
+ for (i = 0; i < 2; i++)
+ {
+ /* lpDestination loop */
+ for (j = 0; j < 2; j++)
+ {
+ /* bFailIfExists loop */
+ for (k = 0; k < 2; k++)
+ {
+ wcSource = convert(lpSource[i]);
+ wcDest = convert(lpDestination[j]);
+ bRc = CopyFileW(wcSource,
+ wcDest,
+ bFailIfExists[k]);
+ free(wcSource);
+ free(wcDest);
+ if (!bRc)
+ {
+ if (results[nCounter] == '1')
+ {
+ Trace("CopyFileW: FAILED: test[%d][%d][%d]\n", i, j, k);
+ bSuccess = FALSE;
+ }
+ }
+ else
+ {
+ if (results[nCounter] == '0')
+ {
+ Trace("CopyFileW: FAILED: test[%d][%d][%d]\n", i, j, k);
+ bSuccess = FALSE;
+ }
+ else
+ {
+ /* verify the file was moved */
+ if (GetFileAttributesA(lpDestination[j]) == -1)
+ {
+ Trace("CopyFileW: GetFileAttributes of destination"
+ "file failed on test[%d][%d][%d] with error "
+ "code %ld. \n",i,j,k,GetLastError());
+ bSuccess = FALSE;
+ }
+ else if (GetFileAttributesA(lpSource[i]) == -1)
+ {
+ Trace("CopyFileW: GetFileAttributes of source file "
+ "file failed on test[%d][%d][%d] with error "
+ "code %ld. \n",i,j,k,GetLastError());
+ bSuccess = FALSE;
+ }
+ else
+ {
+ /* verify attributes of destination file to
+ source file*/
+ if(GetFileAttributes(lpSource[i]) !=
+ GetFileAttributes(lpDestination[j]))
+ {
+ Trace("CopyFileW : The file attributes of the "
+ "destination file do not match the file "
+ "attributes of the source file on test "
+ "[%d][%d][%d].\n",i,j,k);
+ bSuccess = FALSE;
+ }
+ }
+ }
+
+ }
+ nCounter++;
+ /* delete file file but don't worry if it fails */
+ DeleteFileA(lpDestination[1]);
+ }
+ }
+ }
+
+ int exitCode = bSuccess ? PASS : FAIL;
+ PAL_TerminateEx(exitCode);
+ return exitCode;
+}
diff --git a/src/pal/tests/palsuite/file_io/CopyFileW/test1/ExpectedResults.txt b/src/pal/tests/palsuite/file_io/CopyFileW/test1/ExpectedResults.txt
new file mode 100644
index 0000000000..535a89fe50
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/CopyFileW/test1/ExpectedResults.txt
@@ -0,0 +1 @@
+10110000 \ No newline at end of file
diff --git a/src/pal/tests/palsuite/file_io/CopyFileW/test1/testinfo.dat b/src/pal/tests/palsuite/file_io/CopyFileW/test1/testinfo.dat
new file mode 100644
index 0000000000..b7ff6de2fd
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/CopyFileW/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = CopyFileW
+Name = Tests CopyFileW functionality.
+Type = DEFAULT
+EXE1 = copyfilew
+Description
+= Test the CopyFileW function
+
diff --git a/src/pal/tests/palsuite/file_io/CopyFileW/test2/CMakeLists.txt b/src/pal/tests/palsuite/file_io/CopyFileW/test2/CMakeLists.txt
new file mode 100644
index 0000000000..5c0030bc8d
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/CopyFileW/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test2.c
+)
+
+add_executable(paltest_copyfilew_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_copyfilew_test2 coreclrpal)
+
+target_link_libraries(paltest_copyfilew_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/CopyFileW/test2/test2.c b/src/pal/tests/palsuite/file_io/CopyFileW/test2/test2.c
new file mode 100644
index 0000000000..5380a181ca
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/CopyFileW/test2/test2.c
@@ -0,0 +1,124 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test2.c
+**
+** Purpose: Tests the PAL implementation of the CopyFileW function
+** Attempt to copy a file to itself
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ LPSTR szSrcExisting = "src_existing.tmp";
+ WCHAR* wcSource;
+ BOOL bRc = TRUE;
+ FILE* tempFile = NULL;
+ DWORD temp;
+ int retCode;
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ /* create the src_existing file */
+ tempFile = fopen(szSrcExisting, "w");
+ if (tempFile != NULL)
+ {
+ retCode = fputs("CopyFileA test file: src_existing.tmp ", tempFile);
+ if(retCode < 0)
+ {
+ Fail("CopyFileW: ERROR-> Couldn't write to %s with error "
+ "%u.\n", szSrcExisting, GetLastError());
+ }
+ retCode = fclose(tempFile);
+ if(retCode != 0)
+ {
+ Fail("CopyFileW: ERROR-> Couldn't close file: %s with error "
+ "%u.\n", szSrcExisting, GetLastError());
+ }
+ }
+ else
+ {
+ Fail("CopyFileW: ERROR-> Couldn't create %s.\n", szSrcExisting);
+ }
+
+ /* convert source string to wide character */
+ wcSource = convert(szSrcExisting);
+
+ /* Get file attributes of source */
+ temp = GetFileAttributes(szSrcExisting);
+ if (temp == -1)
+ {
+ free(wcSource);
+ Fail("CopyFileW: GetFileAttributes of source file "
+ "failed with error code %ld. \n",
+ GetLastError());
+ }
+
+ /* make sure a file can't copy to itself
+ first testing with IfFileExists flag set to true */
+ bRc = CopyFileW(wcSource,wcSource,TRUE);
+ if(bRc)
+ {
+ free(wcSource);
+ Fail("ERROR: Cannot copy a file to itself, %u",GetLastError());
+ }
+
+ /* try to get file attributes of desitnation */
+ if (GetFileAttributesA(szSrcExisting) == -1)
+ {
+ free(wcSource);
+ Fail("CopyFileW: GetFileAttributes of destination file "
+ "failed with error code %ld. \n",
+ GetLastError());
+ }
+ else
+ {
+ /* verify attributes of destination file to source file*/
+ if(temp != GetFileAttributes(szSrcExisting))
+ {
+ free(wcSource);
+ Fail("CopyFileW : The file attributes of the "
+ "destination file do not match the file "
+ "attributes of the source file.\n");
+ }
+ }
+
+ /* testing with IfFileExists flags set to false
+ should fail in Windows and pass in UNIX */
+ bRc = CopyFileW(wcSource,wcSource,FALSE);
+ free(wcSource);
+ if(bRc && (GetLastError() != ERROR_ALREADY_EXISTS))
+ {
+ Fail("ERROR: Cannot copy a file to itself, %u",GetLastError());
+ }
+
+ if (GetFileAttributesA(szSrcExisting) == -1)
+ {
+ Fail("CopyFileW: GetFileAttributes of destination file "
+ "failed with error code %ld. \n",
+ GetLastError());
+ }
+ else
+ {
+ /* verify attributes of destination file to source file*/
+
+ if(temp != GetFileAttributes(szSrcExisting))
+ {
+ Fail("CopyFileW : The file attributes of the "
+ "destination file do not match the file "
+ "attributes of the source file.\n");
+ }
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/file_io/CopyFileW/test2/testinfo.dat b/src/pal/tests/palsuite/file_io/CopyFileW/test2/testinfo.dat
new file mode 100644
index 0000000000..7e1591dd72
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/CopyFileW/test2/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = CopyFileW
+Name = Tests CopyFileW to check if file can be copied to itself. (test2)
+Type = DEFAULT
+EXE1 = test2
+Description
+= Test the CopyFileW function
+= to see the effect of copying a
+= file to itself.
+
diff --git a/src/pal/tests/palsuite/file_io/CopyFileW/test3/CMakeLists.txt b/src/pal/tests/palsuite/file_io/CopyFileW/test3/CMakeLists.txt
new file mode 100644
index 0000000000..52d9aad1c0
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/CopyFileW/test3/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test3.c
+)
+
+add_executable(paltest_copyfilew_test3
+ ${SOURCES}
+)
+
+add_dependencies(paltest_copyfilew_test3 coreclrpal)
+
+target_link_libraries(paltest_copyfilew_test3
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/CopyFileW/test3/test3.c b/src/pal/tests/palsuite/file_io/CopyFileW/test3/test3.c
new file mode 100644
index 0000000000..a2eb04c443
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/CopyFileW/test3/test3.c
@@ -0,0 +1,196 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test4.c
+**
+** Purpose: Tests the PAL implementation of the CopyFileW function
+** to see if a file can through different users belonging to
+** different groups.
+**
+
+=====================================================================*/
+
+/* USECASE
+ Copy a file from a different user, belonging to a different group to
+ the the current user, who is a member of the current group. Then check
+ to see that the current user has the basic access rights to the copied
+ file.
+
+ Thie original file used is the passwd file in the etc directory of a
+ BSD machine. This file should exist on all machines.
+*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+
+#if WIN32
+ return PASS;
+
+#else
+
+ BOOL bRc = TRUE;
+ WCHAR szSrcExisting[] = {'/','e','t','c','/','p','a','s','s','w','d','\0'};
+ WCHAR szDest[] = {'t','e','m','p','.','t','m','p','\0'};
+ WCHAR szStringTest[] = {'M','a','r','r','y',' ','h','a','d',' ','a',' ',
+ 'l','i','t','t','l','e',' ','l','a','m','b','\0'};
+ WCHAR szStringRead[30]; /* large enough for string szStringTest */
+
+ HANDLE hFile = NULL;
+ DWORD dwBytesWritten=0;
+ DWORD dwBytesRead=0;
+ int size=0;
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ /* copy the file */
+ bRc = CopyFileW(szSrcExisting,szDest,TRUE);
+ if(!bRc)
+ {
+ Fail("CopyFileW: Cannot copy a file with error, %u",GetLastError());
+ }
+
+ /* try to get file attributes of destination file */
+ if (GetFileAttributesW(szDest) == -1)
+ {
+ Fail("CopyFileW: GetFileAttributes of destination file "
+ "failed with error code %u. \n",
+ GetLastError());
+ }
+
+ /* set the attributes of the destination file to normal again */
+ bRc = SetFileAttributesW(szDest, FILE_ATTRIBUTE_NORMAL);
+ if(!bRc)
+ {
+ Fail("CopyFileW: ERROR-> Couldn't set file attributes for "
+ "file %S with error %u\n", szDest, GetLastError());
+ }
+
+ /* open the file for write purposes */
+ hFile = CreateFileW((WCHAR *)szDest,
+ GENERIC_WRITE,
+ 0,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if(hFile == INVALID_HANDLE_VALUE)
+ {
+ Fail("CopyFileW: ERROR -> Unable to create file \"%S\".\n",
+ szDest);
+ }
+
+ /* To account for the size of a WCHAR is twice that of a char */
+ size = wcslen(szStringTest);
+ size = size*sizeof(WCHAR);
+
+ /* Attempt to write to the file */
+ bRc = WriteFile(hFile,
+ szStringTest,
+ size,
+ &dwBytesWritten,
+ NULL);
+
+ if (!bRc)
+ {
+ Trace("CopyFileW: ERROR -> Unable to write to copied file with error "
+ "%u.\n", GetLastError());
+ bRc = CloseHandle(hFile);
+ if (!bRc)
+ {
+ Fail("CopyFileW: ERROR -> Unable to close file \"%S\" with "
+ "error %u.\n",szDest, GetLastError());
+ }
+ Fail("");
+
+ }
+
+ /* Close the file handle */
+ bRc = CloseHandle(hFile);
+ if (!bRc)
+ {
+ Fail("CopyFileW: ERROR -> Unable to close file \"%S\" with error %u "
+ ".\n",szDest,GetLastError());
+ }
+
+
+ /* open the file for read purposes */
+ hFile = CreateFileW((WCHAR *)szDest,
+ GENERIC_READ,
+ 0,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if(hFile == INVALID_HANDLE_VALUE)
+ {
+ Fail("CopyFileW: ERROR -> Unable to create file \"%S\".\n",
+ szDest);
+ }
+
+ /* Attempt to read from the file */
+ bRc = ReadFile(hFile,
+ szStringRead,
+ size,
+ &dwBytesRead,
+ NULL);
+
+ if (!bRc)
+ {
+ Trace("CopyFileW: ERROR -> Unable to read from copied file with "
+ "error %u.\n",GetLastError());
+ bRc = CloseHandle(hFile);
+ if (!bRc)
+ {
+ Fail("CopyFileW: ERROR -> Unable to close file \"%S\" with "
+ "error %u.\n",szDest, GetLastError());
+ }
+ Fail("");
+
+ }
+
+ if(wcsncmp(szStringTest,szStringRead, wcslen(szStringTest)) != 0)
+ {
+ Trace("CopyFileW: ERROR -> The string which was written '%S' does not "
+ "match the string '%S' which was read from the copied file.\n",
+ szStringTest,szStringRead);
+ bRc = CloseHandle(hFile);
+ if (!bRc)
+ {
+ Fail("CopyFileW: ERROR -> Unable to close file \"%S\" with "
+ "error %u.\n",szDest, GetLastError());
+ }
+ Fail("");
+ }
+
+ /* Close the file handle */
+ bRc = CloseHandle(hFile);
+ if (!bRc)
+ {
+ Fail("CopyFileW: ERROR -> Unable to close file \"%S\" with error %u "
+ ".\n",szDest,GetLastError());
+ }
+
+ /* Remove the temporary file */
+ bRc = DeleteFileW(szDest);
+ if(!bRc)
+ {
+ Fail("CopyFileW: Could not remove copied file with error %u.\n",
+ GetLastError());
+ }
+
+ PAL_Terminate();
+ return PASS;
+
+#endif
+
+}
diff --git a/src/pal/tests/palsuite/file_io/CopyFileW/test3/testinfo.dat b/src/pal/tests/palsuite/file_io/CopyFileW/test3/testinfo.dat
new file mode 100644
index 0000000000..9fd185dad0
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/CopyFileW/test3/testinfo.dat
@@ -0,0 +1,16 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = CopyFileW
+Name = CopyFileW - checking file attributes maintained (test3)
+Type = DEFAULT
+EXE1 = test3
+Description
+= Copy a file from a different user, belonging to a different group to
+= the the current user, who is a member of the current group. Then check
+= to see that the current user has the basic access rights to the copied
+= file.
+
diff --git a/src/pal/tests/palsuite/file_io/CreateDirectoryA/CMakeLists.txt b/src/pal/tests/palsuite/file_io/CreateDirectoryA/CMakeLists.txt
new file mode 100644
index 0000000000..ef14ea5352
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/CreateDirectoryA/CMakeLists.txt
@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+
diff --git a/src/pal/tests/palsuite/file_io/CreateDirectoryA/test1/CMakeLists.txt b/src/pal/tests/palsuite/file_io/CreateDirectoryA/test1/CMakeLists.txt
new file mode 100644
index 0000000000..f8cdf19933
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/CreateDirectoryA/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ CreateDirectoryA.c
+)
+
+add_executable(paltest_createdirectorya_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_createdirectorya_test1 coreclrpal)
+
+target_link_libraries(paltest_createdirectorya_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/CreateDirectoryA/test1/CreateDirectoryA.c b/src/pal/tests/palsuite/file_io/CreateDirectoryA/test1/CreateDirectoryA.c
new file mode 100644
index 0000000000..2bb441e732
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/CreateDirectoryA/test1/CreateDirectoryA.c
@@ -0,0 +1,296 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: CreateDirectoryA.c
+**
+** Purpose: Tests the PAL implementation of the CreateDirectoryA function.
+**
+** Depends on:
+** RemoveDirectoryW (since RemoveDirectoryA is unavailable)
+** GetCurrentDirectoryA
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+
+/* apparently, under WIN32 the max path size is 248 but under
+ BSD it is _MAX_PATH */
+#if WIN32
+#define CREATE_MAX_PATH_SIZE 248
+#else
+#define CREATE_MAX_PATH_SIZE _MAX_PATH
+#endif
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ const char* szTestDir = {"test_directory"};
+ const char* szDotDir = {".dotDirectory"};
+ BOOL bRc = FALSE;
+ BOOL bSuccess = FALSE;
+ const int buf_size = CREATE_MAX_PATH_SIZE + 10;
+ char szDirName[CREATE_MAX_PATH_SIZE + 10];
+ char buffer[CREATE_MAX_PATH_SIZE + 10];
+ WCHAR* pTemp = NULL;
+ DWORD curDirLen;
+ DWORD curDirectory = 1024;
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+
+ /* directory does not exist */
+ bRc = CreateDirectoryA(szTestDir, NULL);
+ if (bRc == FALSE)
+ {
+ Fail("CreateDirectoryA: Failed to create \"%s\" with error code %ld\n",
+ szTestDir,
+ GetLastError());
+ }
+
+
+ /* directory exists should fail */
+ bRc = CreateDirectoryA(szTestDir, NULL);
+ if (bRc == TRUE)
+ {
+ pTemp = convert((LPSTR)szTestDir);
+ bRc = RemoveDirectoryW(pTemp);
+ free(pTemp);
+ if (!bRc)
+ {
+ Trace("CreateDirectoryA: RemoveDirectoryW failed to remove "
+ "\"%s\" with the error code %ld.\n",
+ szTestDir,
+ GetLastError());
+ }
+ Fail("CreateDirectoryA: Succeeded creating the directory"
+ "\"%s\" when it exists already.\n",
+ szTestDir);
+ }
+ else
+ {
+ pTemp = convert((LPSTR)szTestDir);
+ bRc = RemoveDirectoryW(pTemp);
+ free(pTemp);
+ if (!bRc)
+ {
+ Fail("CreateDirectoryA: RemoveDirectoryW failed to remove "
+ "\"%s\" with the error code %ld.\n",
+ szTestDir,
+ GetLastError());
+ }
+ }
+
+
+ /* long directory names (CREATE_MAX_PATH_SIZE - 1, CREATE_MAX_PATH_SIZE
+ and CREATE_MAX_PATH_SIZE + 1 characters
+ including terminating null char) */
+
+ curDirLen = GetCurrentDirectoryA(0, NULL);
+
+ memset(szDirName, 0, buf_size);
+ memset(szDirName, 'a', CREATE_MAX_PATH_SIZE - 2 - curDirLen);
+ bRc = CreateDirectoryA(szDirName, NULL);
+ if (bRc == FALSE)
+ {
+ Fail("CreateDirectoryA: Failed to create a directory"
+ " name %d chars long with the error code %ld\n",
+ strlen(szDirName),
+ GetLastError());
+ }
+ else
+ {
+ /* Check to see if it's possible to navigate to directory */
+ GetCurrentDirectoryA(curDirectory, buffer);
+ bSuccess = SetCurrentDirectoryA(szDirName);
+ if(!bSuccess)
+ {
+ Fail("CreateDirectoryA: SetCurrentDirectoryA failed to "
+ "navigate to the newly created directory with error "
+ "code %u.\n", GetLastError());
+ }
+
+ /* Set directory back to initial directory */
+ SetCurrentDirectoryA(buffer);
+
+ pTemp = convert((LPSTR)szDirName);
+ bRc = RemoveDirectoryW(pTemp);
+ free(pTemp);
+ if (!bRc)
+ {
+ Fail("CreateDirectoryA: RemoveDirectoryW failed to remove "
+ "\"%s\" with the error code %ld.\n",
+ szDirName,
+ GetLastError());
+ }
+ }
+
+
+ memset(szDirName, 0, buf_size);
+ memset(szDirName, 'a', CREATE_MAX_PATH_SIZE - 1 - curDirLen);
+ bRc = CreateDirectoryA(szDirName, NULL);
+ if (bRc == FALSE)
+ {
+ Fail("CreateDirectoryA: Failed to create a directory"
+ " name %d chars long with error code %ld\n",
+ strlen(szDirName),
+ GetLastError());
+ }
+ else
+ {
+ /* Check to see if it's possible to navigate to directory */
+ GetCurrentDirectoryA(curDirectory, buffer);
+ bSuccess = SetCurrentDirectoryA(szDirName);
+ if(!bSuccess)
+ {
+ Fail("CreateDirectoryA: SetCurrentDirectoryA failed to "
+ "navigate to the newly created directory with error "
+ "code %u.\n", GetLastError());
+ }
+
+ /* Set Directroy back to initial directory */
+ SetCurrentDirectoryA(buffer);
+
+ pTemp = convert(szDirName);
+ bRc = RemoveDirectoryW(pTemp);
+ free(pTemp);
+ if (!bRc)
+ {
+ Fail("CreateDirectoryA: RemoveDirectoryW failed to remove "
+ "\"%s\" with the error code %ld.\n",
+ szDirName,
+ GetLastError());
+ }
+ }
+
+ memset(szDirName, 0, buf_size);
+ memset(szDirName, 'a', CREATE_MAX_PATH_SIZE - curDirLen);
+ bRc = CreateDirectoryA(szDirName, NULL);
+ if (bRc != FALSE)
+ {
+ /* Check to see if it's possible to navigate to directory */
+ GetCurrentDirectoryA(curDirectory, buffer);
+ bSuccess = SetCurrentDirectoryA(szDirName);
+ if(!bSuccess)
+ {
+ Fail("CreateDirectoryA: SetCurrentDirectoryA failed to "
+ "navigate to the newly created directory with error "
+ "code %u.\n", GetLastError());
+ }
+
+ /* set directory back to initial directory */
+ SetCurrentDirectoryA(buffer);
+
+ pTemp = convert(szDirName);
+ bRc = RemoveDirectoryW(pTemp);
+ free(pTemp);
+ if (!bRc)
+ {
+ Trace("CreateDirectoryA: RemoveDirectoryW failed to remove "
+ "\"%s\" with the error code %ld.\n",
+ szDirName,
+ GetLastError());
+ }
+ if (strlen(szDirName) > CREATE_MAX_PATH_SIZE)
+ {
+ Fail("CreateDirectoryA: Failed because it created a directory"
+ " name 1 character longer (%d chars) than the max dir size "
+ "allowed\n",
+ strlen(szDirName));
+ }
+ }
+
+
+ /* long directory name CREATE_MAX_PATH_SIZE + 3 chars including "..\"
+ (real path length <= CREATE_MAX_PATH_SIZE) */
+ memset(szDirName, 0, buf_size);
+ memset(szDirName, 'a', CREATE_MAX_PATH_SIZE + 3 - 1 - curDirLen);
+ szDirName[0] = '.';
+ szDirName[1] = '.';
+ szDirName[2] = '\\';
+ bRc = CreateDirectoryA(szDirName, NULL);
+ if (bRc == FALSE)
+ {
+ Fail("CreateDirectoryA: Failed to create a directory name more "
+ "than %d chars long and its real path name is less "
+ "than %d chars, error %u\n",
+ CREATE_MAX_PATH_SIZE,
+ CREATE_MAX_PATH_SIZE, GetLastError());
+ }
+ else
+ {
+ /* Check to see if it's possible to navigate to directory */
+ GetCurrentDirectoryA(curDirectory, buffer);
+ bSuccess = SetCurrentDirectoryA(szDirName);
+ if(!bSuccess)
+ {
+ Fail("CreateDirectoryA: SetCurrentDirectoryA failed to "
+ "navigate to the newly created directory with error "
+ "code %u.\n", GetLastError());
+ }
+
+ /* set directory back to initial directory */
+ SetCurrentDirectoryA(buffer);
+
+ pTemp = convert(szDirName);
+ bRc = RemoveDirectoryW(pTemp);
+ free(pTemp);
+ if (!bRc)
+ {
+ Fail("CreateDirectoryA: RemoveDirectoryW failed to remove "
+ " \"%s\" with the error code %ld.\n",
+ szDirName,
+ GetLastError());
+ }
+ }
+
+
+ /* directories with dots */
+ memset(szDirName, 0, buf_size);
+ sprintf(szDirName, szDotDir);
+ bRc = CreateDirectoryA(szDirName, NULL);
+ if (bRc == FALSE)
+ {
+ Fail("CreateDirectoryA: Failed to create \"%s\" with error code %ld\n",
+ szDotDir,
+ GetLastError());
+ }
+ else
+ {
+
+ /* Check to see if it's possible to navigate to directory */
+ GetCurrentDirectoryA(curDirectory, buffer);
+ bSuccess = SetCurrentDirectoryA(szDirName);
+ if(!bSuccess)
+ {
+ Fail("CreateDirectoryA: SetCurrentDirectoryA failed to "
+ "navigate to the newly created directory with error "
+ "code %u.\n", GetLastError());
+ }
+
+ /* set directory back to initial directory */
+ SetCurrentDirectoryA(buffer);
+
+ pTemp = convert((LPSTR)szDotDir);
+ bRc = RemoveDirectoryW(pTemp);
+ free(pTemp);
+ if (!bRc)
+ {
+ Fail("CreateDirectoryA: RemoveDirectoryW failed to remove "
+ " \"%s\" with the error code %ld.\n",
+ szDotDir,
+ GetLastError());
+ }
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/file_io/CreateDirectoryA/test1/testinfo.dat b/src/pal/tests/palsuite/file_io/CreateDirectoryA/test1/testinfo.dat
new file mode 100644
index 0000000000..562d76d7be
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/CreateDirectoryA/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = CreateDirectoryA
+Name = Test for CreateDirectoryA
+Type = DEFAULT
+EXE1 = createdirectorya
+Description
+= Create a directory that exists (should fail) and create
+= a directory that doesn't exist and verify results.
diff --git a/src/pal/tests/palsuite/file_io/CreateDirectoryA/test2/CMakeLists.txt b/src/pal/tests/palsuite/file_io/CreateDirectoryA/test2/CMakeLists.txt
new file mode 100644
index 0000000000..a50a986d1a
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/CreateDirectoryA/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ createdirectorya.c
+)
+
+add_executable(paltest_createdirectorya_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_createdirectorya_test2 coreclrpal)
+
+target_link_libraries(paltest_createdirectorya_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/CreateDirectoryA/test2/createdirectorya.c b/src/pal/tests/palsuite/file_io/CreateDirectoryA/test2/createdirectorya.c
new file mode 100644
index 0000000000..fc1bc967b7
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/CreateDirectoryA/test2/createdirectorya.c
@@ -0,0 +1,335 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: createdirectorya.c
+**
+** Purpose: Tests the PAL implementation of the CreateDirectoryA function.
+** Test creating a directory in a directory path that does not exist.
+** Test creating directory with trailing slashes.
+**
+** Depends on:
+** RemoveDirectoryW (since RemoveDirectoryA is unavailable)
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+
+int main(int argc, char *argv[])
+{
+
+#if WIN32
+ const char* szTestRootDir = {"/at_root_directory_PALTEST"};
+#endif
+
+ const char* szTestDir = {"test_ directory"};
+ const char* szTestSubDir =
+ {".\\./././../test2/./../../////////createdirectorya"
+ "\\\\/test2/test_ directory\\sub"};
+ const char* szTest2SubDir = {"test_ directory/sub\\sub_sub"};
+ const char* szTest2SubDirWinSlash =
+ {"test_ directory/sub\\sub_sub\\"};
+ const char* szTest2SubDirUnixSlash =
+ {"test_ directory/sub\\sub_sub/////"};
+ BOOL bRc = FALSE;
+ BOOL clean = TRUE;
+ WCHAR* pTemp = NULL;
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ /* platform dependent cases */
+ /* test for WIN32, create directory at the root."
+ * using '/directory_name ' format */
+#if WIN32
+
+ bRc = CreateDirectoryA(szTestRootDir, NULL);
+
+ if (bRc != TRUE)
+ {
+ Fail("CreateDirectoryA: Failed creating the directory "
+ "\"%s\" with the error code %ld.\n",
+ szTestRootDir,GetLastError());
+ }
+
+ /* clean szTestRootDir */
+ pTemp = convert((LPSTR) szTestRootDir);
+ bRc = RemoveDirectoryW(pTemp);
+ free(pTemp);
+
+ if (! bRc)
+ {
+ clean=bRc;
+ Trace("CreateDirectoryA: RemoveDirectoryW failed to remove "
+ "\"%s\" with the error code %ld.\n",
+ szTestRootDir,
+ GetLastError());
+ }
+
+#endif
+
+
+ /*
+ * create subdirectory "test_directory//sub//sub_sub"
+ * while parent directory does not exist.
+ */
+ bRc = CreateDirectoryA(szTest2SubDir, NULL);
+ if (bRc == TRUE)
+ {
+ pTemp = convert((LPSTR)szTest2SubDir);
+ bRc = RemoveDirectoryW(pTemp);
+ free(pTemp);
+ if (!bRc)
+ {
+ Trace("CreateDirectoryA: RemoveDirectoryW failed to remove "
+ "\"%s\" with the error code %ld.\n",
+ szTest2SubDir,
+ GetLastError());
+ }
+ Fail("CreateDirectoryA: Succeeded creating the directory\"%s\" while"
+ " its parent directory does not exists. It should fail.\n",
+ szTest2SubDir);
+
+ }
+
+
+ /* create directory tree one by one
+ * first create "test_dir"
+ */
+ bRc = CreateDirectoryA(szTestDir, NULL);
+
+ if (bRc != TRUE)/*failed creating the path*/
+ {
+ Fail("CreateDirectoryA: Failed creating the directory "
+ "\"%s\" with the error code %ld.\n", szTestDir,GetLastError());
+ }
+
+ /* create the sub directory test_directory//sub */
+ bRc = CreateDirectoryA(szTestSubDir, NULL);
+
+ if (bRc != TRUE)/*failed creating the path*/
+ {
+ Trace("CreateDirectoryA: Failed creating the directory "
+ "\"%s\" with the error code %ld.\n",
+ szTestSubDir , GetLastError());
+
+ /* cleaning... remove parent directory */
+ pTemp = convert((LPSTR)szTestDir);
+ bRc = RemoveDirectoryW(pTemp);
+ free(pTemp);
+ if (!bRc)
+ {
+ Trace("CreateDirectoryA: RemoveDirectoryW failed to remove "
+ "\"%s\" with an error code %ld.\n",
+ szTestDir,
+ GetLastError());
+ }
+ Fail("");
+ }
+
+ /*
+ * the director structure is test_directory//sub
+ * test creating directory " test_directory//sub//sub_sub"
+ */
+ bRc = CreateDirectoryA(szTest2SubDir, NULL);
+ if (bRc != TRUE)
+ {
+ Trace("CreateDirectoryA: Failed creating the directory "
+ "\"%s\" with the error code %ld.\n",
+ szTest2SubDir , GetLastError());
+
+ /* remove parent directory test_directory//sub */
+ pTemp = convert((LPSTR)szTestSubDir);
+ bRc = RemoveDirectoryW(pTemp);
+ free(pTemp);
+ if (!bRc)
+ {
+ Trace("CreateDirectoryA: RemoveDirectoryW failed to remove "
+ "\"%s\" with the error code %ld.\n",
+ szTestSubDir,
+ GetLastError());
+ }
+
+ /* remove parent directory test_directory */
+ pTemp = convert((LPSTR)szTestDir);
+ bRc = RemoveDirectoryW(pTemp);
+ free(pTemp);
+ if (! bRc)
+ {
+ Trace("CreateDirectoryA: RemoveDirectoryW failed to remove "
+ "\"%s\" with the error code %ld.\n",
+ szTestDir,
+ GetLastError());
+ }
+ Fail("");
+
+ }
+
+ /* RemoveDirectiryW szTest2SubDir */
+ pTemp = convert((LPSTR)szTest2SubDir);
+ bRc = RemoveDirectoryW(pTemp);
+ free(pTemp);
+
+ if (! bRc)
+ {
+ clean=bRc;
+ Trace("CreateDirectoryA: RemoveDirectoryW failed to remove "
+ "\"%s\" with the error code %ld.\n",
+ szTest2SubDir,
+ GetLastError());
+ }
+
+
+ /*
+ * the director structure is test_directory//sub
+ * test creating directory " test_directory//sub//sub_sub\\"
+ */
+ bRc = CreateDirectoryA(szTest2SubDirWinSlash, NULL);
+ if (bRc != TRUE)
+ {
+ Trace("CreateDirectoryA: Failed creating the directory "
+ "\"%s\" with the error code %ld.\n",
+ szTest2SubDirWinSlash , GetLastError());
+
+ /* remove parent directory test_directory//sub */
+ pTemp = convert((LPSTR)szTestSubDir);
+ bRc = RemoveDirectoryW(pTemp);
+ free(pTemp);
+ if (! bRc)
+ {
+ Trace("CreateDirectoryA: RemoveDirectoryW failed to remove "
+ "\"%s\" with the error code %ld.\n",
+ szTestSubDir,
+ GetLastError());
+ }
+
+ /* remove parent directory test_directory */
+ pTemp = convert((LPSTR)szTestDir);
+ bRc = RemoveDirectoryW(pTemp);
+ free(pTemp);
+ if (! bRc)
+ {
+ Trace("CreateDirectoryA: RemoveDirectoryW failed to remove "
+ "\"%s\" with the error code %ld.\n",
+ szTestDir,
+ GetLastError());
+ }
+ Fail("");
+
+ }
+
+ /* RemoveDirectiryW szTest2SubDirWinSlash */
+ pTemp = convert((LPSTR)szTest2SubDirWinSlash);
+ bRc = RemoveDirectoryW(pTemp);
+ free(pTemp);
+
+ if (! bRc)
+ {
+ clean=bRc;
+ Trace("CreateDirectoryA: RemoveDirectoryW failed to remove "
+ "\"%s\" with the error code %ld.\n",
+ szTest2SubDirWinSlash,
+ GetLastError());
+ }
+
+ /*
+ * the director structure is test_directory//sub
+ * test creating directory " test_directory//sub//sub_sub/////"
+ */
+ bRc = CreateDirectoryA(szTest2SubDirUnixSlash, NULL);
+ if (bRc != TRUE)
+ {
+ Trace("CreateDirectoryA: Failed creating the directory "
+ "\"%s\" with the error code %ld.\n",
+ szTest2SubDirUnixSlash , GetLastError());
+
+ /* remove parent directory test_directory//sub */
+ pTemp = convert((LPSTR)szTestSubDir);
+ bRc = RemoveDirectoryW(pTemp);
+ free(pTemp);
+ if (! bRc)
+ {
+ Trace("CreateDirectoryA: RemoveDirectoryW failed to remove "
+ "\"%s\" with the error code %ld.\n",
+ szTestSubDir,
+ GetLastError());
+ }
+
+ /* remove parent directory test_directory */
+ pTemp = convert((LPSTR)szTestDir);
+ bRc = RemoveDirectoryW(pTemp);
+ free(pTemp);
+ if (! bRc)
+ {
+ Trace("CreateDirectoryA: RemoveDirectoryW failed to remove "
+ "\"%s\" with the error code %ld.\n",
+ szTestDir,
+ GetLastError());
+ }
+ Fail("");
+
+ }
+
+ /* RemoveDirectiryW will return false if directory does not exist.
+ * if it returns true then test is completed and the directory path
+ * is clean for running the test again.
+ */
+ pTemp = convert((LPSTR)szTest2SubDirUnixSlash);
+ bRc = RemoveDirectoryW(pTemp);
+ free(pTemp);
+
+ if (! bRc)
+ {
+ clean=bRc;
+ Trace("CreateDirectoryA: RemoveDirectoryW failed to remove "
+ "\"%s\" with the error code %ld.\n",
+ szTest2SubDirUnixSlash,
+ GetLastError());
+ }
+
+
+
+
+ /*clean parent szTestSubDir */
+ pTemp = convert((LPSTR)szTestSubDir);
+ bRc = RemoveDirectoryW(pTemp);
+ free(pTemp);
+
+ if (! bRc)
+ {
+ clean = bRc;
+ Trace("CreateDirectoryA: RemoveDirectoryW failed to remove "
+ "\"%s\" with the error code %ld.\n",
+ szTestSubDir,
+ GetLastError());
+ }
+
+ /*clean parent szTestDir */
+ pTemp = convert((LPSTR)szTestDir);
+ bRc = RemoveDirectoryW(pTemp);
+ free(pTemp);
+
+ if (! bRc)
+ {
+ clean = bRc;
+ Trace("CreateDirectoryA: RemoveDirectoryW failed to remove "
+ "\"%s\" with the error code %ld.\n",
+ szTestDir,
+ GetLastError());
+ }
+
+ if(! clean)
+ {
+ Fail("");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/file_io/CreateDirectoryA/test2/testinfo.dat b/src/pal/tests/palsuite/file_io/CreateDirectoryA/test2/testinfo.dat
new file mode 100644
index 0000000000..1e2ae774da
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/CreateDirectoryA/test2/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = CreateDirectoryA
+Name = Test for CreateDirectoryA
+Type = DEFAULT
+EXE1 = createdirectorya
+Description
+= Call CreateDirectoryA with a path in which more than just
+= the last component doesn't exist.
diff --git a/src/pal/tests/palsuite/file_io/CreateDirectoryW/CMakeLists.txt b/src/pal/tests/palsuite/file_io/CreateDirectoryW/CMakeLists.txt
new file mode 100644
index 0000000000..ef14ea5352
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/CreateDirectoryW/CMakeLists.txt
@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+
diff --git a/src/pal/tests/palsuite/file_io/CreateDirectoryW/test1/CMakeLists.txt b/src/pal/tests/palsuite/file_io/CreateDirectoryW/test1/CMakeLists.txt
new file mode 100644
index 0000000000..1981e37082
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/CreateDirectoryW/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ CreateDirectoryW.c
+)
+
+add_executable(paltest_createdirectoryw_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_createdirectoryw_test1 coreclrpal)
+
+target_link_libraries(paltest_createdirectoryw_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/CreateDirectoryW/test1/CreateDirectoryW.c b/src/pal/tests/palsuite/file_io/CreateDirectoryW/test1/CreateDirectoryW.c
new file mode 100644
index 0000000000..9b020cc19c
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/CreateDirectoryW/test1/CreateDirectoryW.c
@@ -0,0 +1,347 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: CreateDirectoryW.c
+**
+** Purpose: Tests the PAL implementation of the CreateDirectoryW function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+
+/* apparently, under WIN32 the max path size is 248 but under
+ BSD it is _MAX_PATH */
+#if WIN32
+#define CREATE_MAX_PATH_SIZE 248
+#else
+#define CREATE_MAX_PATH_SIZE _MAX_PATH
+#endif
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ BOOL bRc = FALSE;
+ BOOL bSuccess = FALSE;
+ const int buf_size = CREATE_MAX_PATH_SIZE + 10;
+ char szDirName[CREATE_MAX_PATH_SIZE + 10];
+ char buffer[CREATE_MAX_PATH_SIZE + 10];
+ WCHAR* pTemp = NULL;
+ DWORD curDirLen;
+ DWORD curDirectory = 1024;
+
+
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ /* directory does not exist */
+ pTemp = convert("test_directory");
+ bRc = CreateDirectoryW(pTemp, NULL);
+ free(pTemp);
+ if (bRc == FALSE)
+ {
+ Fail("CreateDirectoryW: Failed to create \"test_directory\"\n");
+ }
+
+ /* directory exists */
+ pTemp = convert("test_directory");
+ bRc = CreateDirectoryW(pTemp, NULL);
+ if (bRc == TRUE)
+ {
+ bRc = RemoveDirectoryW(pTemp);
+ if(!bRc)
+ {
+ free(pTemp);
+ Fail("CreateDirectoryW: RemoveDirectoryW failed to "
+ "delete the directory with error %u.\n",
+ GetLastError());
+ }
+ free(pTemp);
+ Fail("CreateDirectoryW: Succeeded creating the directory"
+ " \"test_directory\" when it exists already.\n");
+ }
+
+ bRc = RemoveDirectoryW(pTemp);
+ if(!bRc)
+ {
+ free(pTemp);
+ Fail("CreateDirectoryW: RemoveDirectoryW failed to "
+ "delete the directory with error %u.\n",
+ GetLastError());
+ }
+ free(pTemp);
+
+ /* long directory names (CREATE_MAX_PATH_SIZE - 1, CREATE_MAX_PATH_SIZE
+ and CREATE_MAX_PATH_SIZE + 1 characters
+ including terminating null char) */
+
+ curDirLen = GetCurrentDirectoryA(0, NULL);
+
+ memset(szDirName, 0, buf_size);
+ memset(szDirName, 'a', CREATE_MAX_PATH_SIZE - 2 - curDirLen);
+ pTemp = convert((LPSTR)szDirName);
+ bRc = CreateDirectoryW(pTemp, NULL);
+ if (bRc == FALSE)
+ {
+ free(pTemp);
+ Fail("CreateDirectoryW: Failed to create a directory"
+ " name (%d) chars long with the error code %ld\n",
+ CREATE_MAX_PATH_SIZE - 1,
+ GetLastError());
+ }
+ else
+ {
+
+ /* Check to see if it's possible to navigate to directory */
+ GetCurrentDirectoryA(curDirectory, buffer);
+ bSuccess = SetCurrentDirectoryA(szDirName);
+ if(!bSuccess)
+ {
+ Trace("CreateDirectoryW: SetCurrentDirectoryA failed to "
+ "navigate to the newly created directory with error "
+ "code %u.\n", GetLastError());
+ bRc = RemoveDirectoryW(pTemp);
+ if(!bRc)
+ {
+ free(pTemp);
+ Fail("CreateDirectoryW: RemoveDirectoryW failed to "
+ "delete the directory with error %u.\n",
+ GetLastError());
+ }
+ free(pTemp);
+ Fail("");
+
+ }
+
+ /* Set directory back to initial directory */
+ bRc = SetCurrentDirectoryA(buffer);
+ if(!bRc)
+ {
+ free(pTemp);
+ Fail("CreateDirectoryW: SetCurrentDirectoryA failed to "
+ "change the directory with error %u.\n",
+ GetLastError());
+ }
+
+ bRc = RemoveDirectoryW(pTemp);
+ if(!bRc)
+ {
+ free(pTemp);
+ Fail("CreateDirectoryW: RemoveDirectoryW failed to "
+ "delete the directory with error %u.\n",
+ GetLastError());
+ }
+ free(pTemp);
+ }
+
+
+ memset(szDirName, 0, buf_size);
+ memset(szDirName, 'a', CREATE_MAX_PATH_SIZE - 1 - curDirLen);
+ pTemp = convert(szDirName);
+ bRc = CreateDirectoryW(pTemp, NULL);
+ if (bRc == FALSE)
+ {
+ free(pTemp);
+ Fail("CreateDirectoryW: Failed to create a directory"
+ " name %d chars long with error code %ld\n",
+ strlen(szDirName),
+ GetLastError());
+ }
+ else
+ {
+ /* Check to see if it's possible to navigate to directory */
+ GetCurrentDirectoryA(curDirectory, buffer);
+ bSuccess = SetCurrentDirectoryA(szDirName);
+ if(!bSuccess)
+ {
+ Trace("CreateDirectoryW: SetCurrentDirectoryA failed to "
+ "navigate to the newly created directory with error "
+ "code %u.\n", GetLastError());
+
+ bRc = RemoveDirectoryW(pTemp);
+ if(!bRc)
+ {
+ free(pTemp);
+ Fail("CreateDirectoryW: RemoveDirectoryW failed to "
+ "delete the directory with error %u.\n",
+ GetLastError());
+ }
+ free(pTemp);
+ Fail("");
+ }
+
+ /* Set directory back to initial directory */
+ bRc = SetCurrentDirectoryA(buffer);
+ if(!bRc)
+ {
+ free(pTemp);
+ Fail("CreateDirectoryW: SetCurrentDirectoryA failed to "
+ "change the directory with error %u.\n",
+ GetLastError());
+ }
+
+
+ bRc = RemoveDirectoryW(pTemp);
+ if(!bRc)
+ {
+ free(pTemp);
+ Fail("CreateDirectoryW: RemoveDirectoryW failed to "
+ "delete the directory with error %u.\n",
+ GetLastError());
+ }
+ free(pTemp);
+ }
+
+ memset(szDirName, 0, buf_size);
+ memset(szDirName, 'a', CREATE_MAX_PATH_SIZE - curDirLen);
+ pTemp = convert(szDirName);
+ bRc = CreateDirectoryW(pTemp, NULL);
+
+ if (bRc != FALSE)
+ {
+ RemoveDirectoryW(pTemp);
+ if(!bRc)
+ {
+ free(pTemp);
+ Fail("CreateDirectoryW: RemoveDirectoryW failed to "
+ "delete the directory with error %u.\n",
+ GetLastError());
+ }
+ if (strlen(szDirName) > CREATE_MAX_PATH_SIZE)
+ {
+ free(pTemp);
+ Fail("CreateDirectoryW: Failed because it created a directory"
+ " name 1 character longer (%d chars) than the max dir size"
+ " allowed\n",
+ strlen(szDirName));
+ }
+ }
+
+ free(pTemp);
+
+ /* long directory name CREATE_MAX_PATH_SIZE + 3 chars including "..\"
+ (real path length <= CREATE_MAX_PATH_SIZE) */
+ memset(szDirName, 0, buf_size);
+ memset(szDirName, 'a', CREATE_MAX_PATH_SIZE + 3 - 1 - curDirLen);
+ szDirName[0] = '.';
+ szDirName[1] = '.';
+ szDirName[2] = '\\';
+ pTemp = convert(szDirName);
+ bRc = CreateDirectoryW(pTemp, NULL);
+ if (bRc == FALSE)
+ {
+ free(pTemp);
+ Fail("CreateDirectoryW: Failed to create a directory name more "
+ "than %d chars long and its real path name is less "
+ "than %d chars\n",
+ CREATE_MAX_PATH_SIZE,
+ CREATE_MAX_PATH_SIZE);
+ }
+ else
+ {
+ /* Check to see if it's possible to navigate to directory */
+ GetCurrentDirectoryA(curDirectory, buffer);
+ bSuccess = SetCurrentDirectoryA(szDirName);
+ if(!bSuccess)
+ {
+ Trace("CreateDirectoryW: SetCurrentDirectoryA failed to "
+ "navigate to the newly created directory with error "
+ "code %u.\n", GetLastError());
+ bRc = RemoveDirectoryW(pTemp);
+ if(!bRc)
+ {
+ free(pTemp);
+ Fail("CreateDirectoryW: RemoveDirectoryW failed to "
+ "delete the directory with error %u.\n",
+ GetLastError());
+ }
+ free(pTemp);
+ Fail("");
+ }
+
+ /* Set directory back to initial directory */
+ bRc = SetCurrentDirectoryA(buffer);
+ if(!bRc)
+ {
+ free(pTemp);
+ Fail("CreateDirectoryW: SetCurrentDirectoryA failed to "
+ "change the directory with error %u.\n",
+ GetLastError());
+ }
+
+ bRc = RemoveDirectoryW(pTemp);
+ if(!bRc)
+ {
+ free(pTemp);
+ Fail("CreateDirectoryW: RemoveDirectoryW failed to "
+ "delete the directory with error %u.\n",
+ GetLastError());
+ }
+ free(pTemp);
+ }
+
+ /* directories with dots */
+ memset(szDirName, 0, 252);
+ sprintf(szDirName, ".dotDirectory");
+ pTemp = convert(szDirName);
+ bRc = CreateDirectoryW(pTemp, NULL);
+ if (bRc == FALSE)
+ {
+ free(pTemp);
+ Fail("CreateDirectoryW: Failed to create a dot directory\n");
+ }
+ else
+ {
+ /* Check to see if it's possible to navigate to directory */
+ GetCurrentDirectoryA(curDirectory, buffer);
+ bSuccess = SetCurrentDirectoryA(szDirName);
+ if(!bSuccess)
+ {
+ Trace("CreateDirectoryW: SetCurrentDirectoryA failed to "
+ "navigate to the newly created directory with error "
+ "code %u.\n", GetLastError());
+
+ bRc = RemoveDirectoryW(pTemp);
+ if(!bRc)
+ {
+ free(pTemp);
+ Fail("CreateDirectoryW: RemoveDirectoryW failed to "
+ "delete the directory with error %u.\n",
+ GetLastError());
+ }
+ free(pTemp);
+ Fail("");
+ }
+
+ /* Set directory back to initial directory */
+ bRc = SetCurrentDirectoryA(buffer);
+ if(!bRc)
+ {
+ free(pTemp);
+ Fail("CreateDirectoryW: SetCurrentDirectoryA failed to "
+ "change the directory with error %u.\n",
+ GetLastError());
+ }
+
+ bRc = RemoveDirectoryW(pTemp);
+ if(!bRc)
+ {
+ free(pTemp);
+ Fail("CreateDirectoryW: RemoveDirectoryW failed to "
+ "delete the directory with error %u.\n",
+ GetLastError());
+ }
+ free(pTemp);
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/file_io/CreateDirectoryW/test1/testinfo.dat b/src/pal/tests/palsuite/file_io/CreateDirectoryW/test1/testinfo.dat
new file mode 100644
index 0000000000..bc664892b4
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/CreateDirectoryW/test1/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = CreateDirectoryW
+Name = Positive Test for CreateDirectoryW
+Type = DEFAULT
+EXE1 = createdirectoryw
+Description
+= Test the CreateDirctoryW function
diff --git a/src/pal/tests/palsuite/file_io/CreateDirectoryW/test2/CMakeLists.txt b/src/pal/tests/palsuite/file_io/CreateDirectoryW/test2/CMakeLists.txt
new file mode 100644
index 0000000000..aae4e7dc54
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/CreateDirectoryW/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ createdirectoryw.c
+)
+
+add_executable(paltest_createdirectoryw_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_createdirectoryw_test2 coreclrpal)
+
+target_link_libraries(paltest_createdirectoryw_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/CreateDirectoryW/test2/createdirectoryw.c b/src/pal/tests/palsuite/file_io/CreateDirectoryW/test2/createdirectoryw.c
new file mode 100644
index 0000000000..20fac5a879
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/CreateDirectoryW/test2/createdirectoryw.c
@@ -0,0 +1,345 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: createdirectoryw.c
+**
+** Purpose: Tests the PAL implementation of the CreateDirectoryW function.
+** Test creating a directory in a directory path that does not exist.
+** Test creating directory with trailing slashes.
+**
+** Depends on:
+** RemoveDirectoryW.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+
+#if WIN32
+WCHAR* szTestRootDir = NULL;
+#endif
+
+WCHAR* szTestDir = NULL;
+WCHAR* szTestSubDir = NULL;
+WCHAR* szTest2SubDir = NULL;
+WCHAR* szTest2SubDirWinSlash = NULL;
+WCHAR* szTest2SubDirUnixSlash = NULL;
+
+
+/* Free the memory allocated by convert(...) function*/
+static void CleanMemory(){
+
+#if WIN32
+ free(szTestRootDir);
+#endif
+
+ free( szTestDir);
+ free( szTestSubDir);
+ free( szTest2SubDir);
+ free( szTest2SubDirWinSlash);
+ free( szTest2SubDirUnixSlash);
+
+}
+
+
+int main(int argc, char *argv[])
+{
+ BOOL bRc = FALSE;
+ BOOL clean = TRUE;
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ /* initialize strings */
+
+#if WIN32
+ szTestRootDir = convert("/at_root_directory_PALTEST");
+#endif
+
+ szTestDir = convert("test_ directory");
+ szTestSubDir = convert(
+ ".\\./././../test2/./../../////////createdirectoryw"
+ "\\\\/test2/test_ directory\\sub");
+ szTest2SubDir = convert("test_ directory/sub\\sub_sub");
+ szTest2SubDirWinSlash = convert("test_ directory/sub\\sub_sub\\\\");
+ szTest2SubDirUnixSlash = convert("test_ directory/sub\\sub_sub///");
+
+
+ /* Platform dependent cases:-
+ * test for WIN32, create directory at the root.
+ * using /directory_name format
+ */
+#if WIN32
+
+ bRc = CreateDirectoryW(szTestRootDir, NULL);
+
+ if (bRc != TRUE)
+ {
+
+ Trace("CreateDirectoryW: Failed creating the directory "
+ "\"%S\" with the error code %ld.\n",
+ szTestRootDir,GetLastError());
+ CleanMemory();
+ Fail("");
+ }
+
+ /*clean szTestRootDir */
+ bRc = RemoveDirectoryW(szTestRootDir);
+
+ if (! bRc)
+ {
+ clean = bRc;
+ Trace("CreateDirectoryW: RemoveDirectoryW failed to remove "
+ "\"%S\" with the error code %ld.\n",
+ szTestRootDir,
+ GetLastError());
+ }
+
+#endif
+
+
+ /*
+ * create subdirectory "test_directory//sub//sub_sub"
+ * while parent directory does not exist.
+ */
+ bRc = CreateDirectoryW(szTest2SubDir, NULL);
+ if (bRc == TRUE)
+ {
+ bRc = RemoveDirectoryW(szTest2SubDir);
+
+ if (! bRc )
+ {
+ Trace("CreateDirectoryW: RemoveDirectoryW failed to remove "
+ "\"%S\" with the error code %ld.\n",
+ szTest2SubDir,
+ GetLastError());
+ }
+
+ Trace("CreateDirectoryW: Succeeded creating the directory\"%S\" while"
+ " its parent directory does not exists. It should fail.\n",
+ szTest2SubDir);
+ CleanMemory();
+ Fail("");
+
+ }
+
+
+ /* create directory tree one by one
+ * first create "test_dir"
+ */
+ bRc = CreateDirectoryW(szTestDir, NULL);
+
+
+ if (bRc != TRUE)/*failed creating the path*/
+ {
+
+ Trace("CreateDirectoryW: Failed creating the directory "
+ "\"%S\" with the error code %ld.\n", szTestDir,GetLastError());
+ CleanMemory();
+ Fail("");
+ }
+
+ /* create the sub directory test_directory//sub */
+ bRc = CreateDirectoryW(szTestSubDir, NULL);
+
+ if (bRc != TRUE)/*failed creating the path*/
+ {
+ Trace("CreateDirectoryW: Failed creating the directory "
+ "\"%S\" with the error code %ld.\n",
+ szTestSubDir , GetLastError());
+
+ /* cleaning... remove parent directory */
+ bRc = RemoveDirectoryW(szTestDir);
+ if (! bRc)
+ {
+ Trace("CreateDirectoryW: RemoveDirectoryW failed to remove "
+ "\"%S\" with an error code %ld.\n",
+ szTestDir,
+ GetLastError());
+ }
+ CleanMemory();
+ Fail("");
+ }
+
+ /*
+ * the director structure is test_directory//sub
+ * test creating directory " test_directory//sub//sub_sub"
+ */
+ bRc = CreateDirectoryW(szTest2SubDir, NULL);
+ if (bRc != TRUE)
+ {
+ Trace("CreateDirectoryW: Failed creating the directory "
+ "\"%S\" with the error code %ld.\n",
+ szTest2SubDir , GetLastError());
+
+ /* remove parent directory test_directory//sub */
+ bRc = RemoveDirectoryW(szTestSubDir);
+ if (! bRc)
+ {
+ Trace("CreateDirectoryW: RemoveDirectoryW failed to remove "
+ "\"%S\" with the error code %ld.\n",
+ szTestSubDir,
+ GetLastError());
+ }
+
+ /* remove parent directory test_directory */
+ bRc = RemoveDirectoryW(szTestDir);
+ if (! bRc)
+ {
+ Trace("CreateDirectoryW: RemoveDirectoryW failed to remove "
+ "\"%S\" with the error code %ld.\n",
+ szTestDir,
+ GetLastError());
+ }
+ CleanMemory();
+ Fail("");
+
+ }
+
+ /* Remove Directiry szTest2SubDir*/
+ bRc = RemoveDirectoryW(szTest2SubDir);
+
+ if (! bRc)
+ {
+ clean = bRc;
+ Trace("CreateDirectoryW: RemoveDirectoryW failed to remove "
+ "\"%S\" with the error code %ld.\n",
+ szTest2SubDir,
+ GetLastError());
+ }
+
+ /*
+ * the director structure is test_directory//sub
+ * test creating directory " test_directory//sub//sub_sub\\\\"
+ */
+ bRc = CreateDirectoryW(szTest2SubDirWinSlash, NULL);
+ if (bRc != TRUE)
+ {
+ Trace("CreateDirectoryW: Failed creating the directory "
+ "\"%S\" with the error code %ld.\n",
+ szTest2SubDirWinSlash , GetLastError());
+
+ /* remove parent directory test_directory//sub */
+ bRc = RemoveDirectoryW(szTestSubDir);
+ if (! bRc)
+ {
+ Trace("CreateDirectoryW: RemoveDirectoryW failed to remove "
+ "\"%S\" with the error code %ld.\n",
+ szTestSubDir,
+ GetLastError());
+ }
+
+ /* remove parent directory test_directory */
+ bRc = RemoveDirectoryW(szTestDir);
+ if (! bRc)
+ {
+ Trace("CreateDirectoryW: RemoveDirectoryW failed to remove "
+ "\"%S\" with the error code %ld.\n",
+ szTestDir,
+ GetLastError());
+ }
+ CleanMemory();
+ Fail("");
+
+ }
+
+ /* Remove Directiry szTest2SubDirWinSlash */
+ bRc = RemoveDirectoryW(szTest2SubDirWinSlash);
+
+ if (! bRc)
+ {
+ clean = bRc;
+ Trace("CreateDirectoryW: RemoveDirectoryW failed to remove "
+ "\"%S\" with the error code %ld.\n",
+ szTest2SubDirWinSlash,
+ GetLastError());
+ }
+
+ /*
+ * the director structure is test_directory//sub
+ * test creating directory " test_directory//sub//sub_sub///"
+ */
+ bRc = CreateDirectoryW(szTest2SubDirUnixSlash, NULL);
+ if (bRc != TRUE)
+ {
+ Trace("CreateDirectoryW: Failed creating the directory "
+ "\"%S\" with the error code %ld.\n",
+ szTest2SubDirUnixSlash , GetLastError());
+
+ /* remove parent directory test_directory//sub */
+ bRc = RemoveDirectoryW(szTestSubDir);
+ if (! bRc)
+ {
+ Trace("CreateDirectoryW: RemoveDirectoryW failed to remove "
+ "\"%S\" with the error code %ld.\n",
+ szTestSubDir,
+ GetLastError());
+ }
+
+ /* remove parent directory test_directory */
+ bRc = RemoveDirectoryW(szTestDir);
+ if (! bRc)
+ {
+ Trace("CreateDirectoryW: RemoveDirectoryW failed to remove "
+ "\"%S\" with the error code %ld.\n",
+ szTestDir,
+ GetLastError());
+ }
+ CleanMemory();
+ Fail("");
+
+ }
+
+ /* Remove Directiry szTest2SubDirUnixSlash.*/
+ bRc = RemoveDirectoryW(szTest2SubDirUnixSlash);
+
+ if (! bRc)
+ {
+ clean = bRc;
+ Trace("CreateDirectoryW: RemoveDirectoryW failed to remove "
+ "\"%S\" with the error code %ld.\n",
+ szTest2SubDirUnixSlash,
+ GetLastError());
+ }
+
+ /*clean parent szTestSubDir */
+ bRc = RemoveDirectoryW(szTestSubDir);
+
+ if (! bRc)
+ {
+ clean = bRc;
+ Trace("CreateDirectoryW: RemoveDirectoryW failed to remove "
+ "\"%S\" with the error code %ld.\n",
+ szTestSubDir,
+ GetLastError());
+ }
+
+ /*clean parent szTestDir */
+ bRc = RemoveDirectoryW(szTestDir);
+
+
+ if (! bRc)
+ {
+ clean = bRc;
+ Trace("CreateDirectoryW: RemoveDirectoryW failed to remove "
+ "\"%S\" with the error code %ld.\n",
+ szTestDir,
+ GetLastError());
+ }
+
+ if(! clean)
+ {
+ CleanMemory();
+ Fail("");
+ }
+
+ CleanMemory();
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/file_io/CreateDirectoryW/test2/testinfo.dat b/src/pal/tests/palsuite/file_io/CreateDirectoryW/test2/testinfo.dat
new file mode 100644
index 0000000000..0d98a5f3b6
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/CreateDirectoryW/test2/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = CreateDirectoryW
+Name = Test for CreateDirectoryW
+Type = DEFAULT
+EXE1 = createdirectoryW
+Description
+= Call CreateDirectoryW with a path in which more than just
+= the last component doesn't exist.
diff --git a/src/pal/tests/palsuite/file_io/CreateFileA/CMakeLists.txt b/src/pal/tests/palsuite/file_io/CreateFileA/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/CreateFileA/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/file_io/CreateFileA/test1/CMakeLists.txt b/src/pal/tests/palsuite/file_io/CreateFileA/test1/CMakeLists.txt
new file mode 100644
index 0000000000..8814b2281b
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/CreateFileA/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ CreateFileA.c
+)
+
+add_executable(paltest_createfilea_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_createfilea_test1 coreclrpal)
+
+target_link_libraries(paltest_createfilea_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/CreateFileA/test1/CreateFileA.c b/src/pal/tests/palsuite/file_io/CreateFileA/test1/CreateFileA.c
new file mode 100644
index 0000000000..a70867a5c8
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/CreateFileA/test1/CreateFileA.c
@@ -0,0 +1,145 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: CreateFileA.c
+**
+** Purpose: Test the PAL implementation of the CreateFileA function
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+BOOL Cleanup(void)
+{
+ char FileName[20];
+ int i;
+ BOOL bRet = TRUE; // assume success
+
+ // loop through all accesses, modes, dispositions and flags
+ for (i=0; i<4*8*4*5; ++i) {
+ sprintf(FileName, "test%03d.txt", i);
+ if (DeleteFileA(FileName) == FALSE) {
+ if (GetLastError() != ERROR_FILE_NOT_FOUND) {
+ bRet = FALSE;
+ }
+ }
+ }
+ return bRet;
+}
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ BOOL bSuccess = TRUE;
+ int nCounter = 0;
+ HANDLE hFile;
+ char lpFileName[20];
+ FILE *outFile = NULL;
+ char results[1024];
+ int i, j, k, l;
+ DWORD dwDesiredAccess[4] = {0, // 0
+ GENERIC_READ, // 1
+ GENERIC_WRITE, // 2
+ GENERIC_READ | GENERIC_WRITE}; // 3
+ DWORD dwShareMode[8] = {0, // 0
+ FILE_SHARE_READ, // 1
+ FILE_SHARE_WRITE, // 2
+ FILE_SHARE_DELETE, // 3
+ FILE_SHARE_READ | FILE_SHARE_WRITE, // 4
+ FILE_SHARE_READ | FILE_SHARE_DELETE, // 5
+ FILE_SHARE_WRITE | FILE_SHARE_DELETE, // 6
+ FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE}; // 7
+ LPSECURITY_ATTRIBUTES lpAttr = NULL;
+ DWORD dwCreationDisp[4] = {CREATE_NEW, // 0
+ CREATE_ALWAYS, // 1
+ OPEN_EXISTING, // 2
+ OPEN_ALWAYS}; // 3
+ DWORD dwFlagsAttrib[5] = {FILE_ATTRIBUTE_NORMAL, // 0
+ FILE_FLAG_SEQUENTIAL_SCAN, // 1
+ FILE_FLAG_WRITE_THROUGH, // 2
+ FILE_FLAG_NO_BUFFERING, // 3
+ FILE_FLAG_RANDOM_ACCESS}; // 4
+ HANDLE hTemplate = NULL;
+
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ if (!Cleanup()) {
+ Trace("Pre-test Cleanup() failed. LastError=%d\n", GetLastError());
+ return FAIL;
+ }
+
+ /* open the file to read the expected results */
+ outFile = fopen("winoutput", "r");
+ memset (results, 0, 1024);
+
+ fgets(results, 1024, outFile);
+ nCounter = (int)strlen(results);
+ fclose(outFile);
+
+ nCounter = 0;
+
+ // desired access loop
+ for (i = 0; i < 4; i++)
+ {
+ // share mode loop
+ for (j = 0; j < 8; j++)
+ {
+ // security attributes loop
+ for (k = 0; k < 4; k++)
+ {
+ // creation disp loop
+ for (l = 0; l < 5; l++)
+ {
+ sprintf(lpFileName, "test%03d.txt", nCounter);
+ hFile = CreateFile(lpFileName,
+ dwDesiredAccess[i],
+ dwShareMode[j],
+ lpAttr,
+ dwCreationDisp[k],
+ dwFlagsAttrib[l],
+ hTemplate);
+ if (hFile == INVALID_HANDLE_VALUE)
+ {
+ if (results[nCounter] == '1')
+ {
+ Trace("CreateFile: ERROR: Failed when expected "
+ "to pass %s [%d][%d][%d][%d]\n",
+ lpFileName, i, j, k, l);
+ bSuccess = FALSE;
+ }
+ }
+ else
+ {
+ CloseHandle(hFile);
+ if (results[nCounter] == '0')
+ {
+ Trace("CreateFile: ERROR: Passed when expected "
+ "to fail %s [%d][%d][%d][%d]\n",
+ lpFileName, i, j, k, l);
+ bSuccess = FALSE;
+ }
+ }
+ nCounter ++;
+ }
+ }
+ }
+ }
+
+ if (!Cleanup())
+ {
+ Trace("Post-test Cleanup() failed. LastError=%d\n", GetLastError());
+ return FAIL;
+ }
+
+ int exitCode = bSuccess ? PASS : FAIL;
+ PAL_TerminateEx(exitCode);
+ return exitCode;
+}
diff --git a/src/pal/tests/palsuite/file_io/CreateFileA/test1/testinfo.dat b/src/pal/tests/palsuite/file_io/CreateFileA/test1/testinfo.dat
new file mode 100644
index 0000000000..bb872806eb
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/CreateFileA/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = CreateFileA
+Name = test for CreateFileA
+Type = DEFAULT
+EXE1 = createfilea
+Description
+= Attempts to create files based on all combinations of
+= options of CreateFileA
diff --git a/src/pal/tests/palsuite/file_io/CreateFileA/test1/winoutput b/src/pal/tests/palsuite/file_io/CreateFileA/test1/winoutput
new file mode 100644
index 0000000000..3913b99427
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/CreateFileA/test1/winoutput
@@ -0,0 +1 @@
+1111111111000001111111111111110000011111111111111100000111111111111111000001111111111111110000011111111111111100000111111111111111000001111111111111110000011111111111111100000111111111111111000001111111111111110000011111111111111100000111111111111111000001111111111111110000011111111111111100000111111111111111000001111111111111110000011111111111111100000111111111111111000001111111111111110000011111111111111100000111111111111111000001111111111111110000011111111111111100000111111111111111000001111111111111110000011111111111111100000111111111111111000001111111111111110000011111111111111100000111111111111111000001111111111111110000011111 \ No newline at end of file
diff --git a/src/pal/tests/palsuite/file_io/CreateFileW/CMakeLists.txt b/src/pal/tests/palsuite/file_io/CreateFileW/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/CreateFileW/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/file_io/CreateFileW/test1/CMakeLists.txt b/src/pal/tests/palsuite/file_io/CreateFileW/test1/CMakeLists.txt
new file mode 100644
index 0000000000..1ff0b8062f
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/CreateFileW/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ CreateFileW.c
+)
+
+add_executable(paltest_createfilew_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_createfilew_test1 coreclrpal)
+
+target_link_libraries(paltest_createfilew_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/CreateFileW/test1/CreateFileW.c b/src/pal/tests/palsuite/file_io/CreateFileW/test1/CreateFileW.c
new file mode 100644
index 0000000000..4d7d20af29
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/CreateFileW/test1/CreateFileW.c
@@ -0,0 +1,152 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: CreateFileW.c
+**
+** Purpose: Test the PAL implementation of the CreateFileW function
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+BOOL Cleanup(void)
+{
+ char FileName[20];
+ int i;
+ BOOL bRet = TRUE; // assume success
+
+ // loop through all accesses, modes, dispositions and flags
+ for (i=0; i<4*8*4*5; ++i) {
+ sprintf(FileName, "test%03d.txt", i);
+ if (DeleteFileA(FileName) == FALSE) {
+ if (GetLastError() != ERROR_FILE_NOT_FOUND) {
+ bRet = FALSE;
+ }
+ }
+ }
+ return bRet;
+}
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ BOOL bSuccess = TRUE;
+ int nCounter = 0;
+ HANDLE hFile = NULL;
+ WCHAR *lpFileName = NULL;
+ char* pTemp = NULL;
+ char string[40];
+ FILE *outFile = NULL;
+ char results[1024];
+ int i, j, k, l;
+ DWORD dwDesiredAccess[4] = {0, // 0
+ GENERIC_READ, // 1
+ GENERIC_WRITE, // 2
+ GENERIC_READ | GENERIC_WRITE}; // 3
+ DWORD dwShareMode[8] = {0, // 0
+ FILE_SHARE_READ, // 1
+ FILE_SHARE_WRITE, // 2
+ FILE_SHARE_DELETE, // 3
+ FILE_SHARE_READ | FILE_SHARE_WRITE, // 4
+ FILE_SHARE_READ | FILE_SHARE_DELETE, // 5
+ FILE_SHARE_WRITE | FILE_SHARE_DELETE, // 6
+ FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE}; // 7
+ LPSECURITY_ATTRIBUTES lpAttr = NULL;
+ DWORD dwCreationDisp[4] = {CREATE_NEW, // 0
+ CREATE_ALWAYS, // 1
+ OPEN_EXISTING, // 2
+ OPEN_ALWAYS}; // 3
+ DWORD dwFlagsAttrib[5] = {FILE_ATTRIBUTE_NORMAL, // 0
+ FILE_FLAG_SEQUENTIAL_SCAN, // 1
+ FILE_FLAG_WRITE_THROUGH, // 2
+ FILE_FLAG_NO_BUFFERING, // 3
+ FILE_FLAG_RANDOM_ACCESS}; // 4
+ HANDLE hTemplate = NULL;
+
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ if (!Cleanup()) {
+ Trace("Pre-test Cleanup() failed. LastError=%d\n", GetLastError());
+ return FAIL;
+ }
+
+ /* open the file to read the expected results */
+ outFile = fopen("winoutput", "r");
+ memset (results, 0, 1024);
+
+ fgets(results, 1024, outFile);
+ fclose(outFile);
+
+ nCounter = 0;
+
+ // desired access loop
+ for (i = 0; i < 4; i++)
+ {
+ // share mode loop
+ for (j = 0; j < 8; j++)
+ {
+ // security attributes loop
+ for (k = 0; k < 4; k++)
+ {
+ // creation disp loop
+ for (l = 0; l < 5; l++)
+ {
+ sprintf(string, "test%03d.txt", nCounter);
+ lpFileName = convert(string);
+ hFile = CreateFileW(lpFileName,
+ dwDesiredAccess[i],
+ dwShareMode[j],
+ lpAttr,
+ dwCreationDisp[k],
+ dwFlagsAttrib[l],
+ hTemplate);
+ free(lpFileName);
+ if (hFile == INVALID_HANDLE_VALUE)
+ {
+ if (results[nCounter] == '1')
+ {
+ pTemp = convertC(lpFileName);
+ Trace("CreateFile: ERROR: Failed when expected "
+ "to pass %s [%d][%d][%d][%d]\n",
+ pTemp, i, j, k, l);
+ free(pTemp);
+ bSuccess = FALSE;
+ }
+ }
+ else
+ {
+ CloseHandle(hFile);
+ if (results[nCounter] == '0')
+ {
+ pTemp = convertC(lpFileName);
+ Trace("CreateFile: ERROR: Passed when expected "
+ "to fail %s [%d][%d][%d][%d]\n",
+ pTemp, i, j, k, l);
+ free(pTemp);
+ bSuccess = FALSE;
+ }
+ }
+ nCounter ++;
+ }
+ }
+ }
+ }
+
+ if (!Cleanup())
+ {
+ Trace("Post-test Cleanup() failed. LastError=%d\n", GetLastError());
+ return FAIL;
+ }
+
+ int exitCode = bSuccess ? PASS : FAIL;
+ PAL_TerminateEx(exitCode);
+ return exitCode;
+}
diff --git a/src/pal/tests/palsuite/file_io/CreateFileW/test1/testinfo.dat b/src/pal/tests/palsuite/file_io/CreateFileW/test1/testinfo.dat
new file mode 100644
index 0000000000..2dbf159996
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/CreateFileW/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = CreateFileW
+Name = test for CreateFileW
+Type = DEFAULT
+EXE1 = createfilew
+Description
+= Attempts to create files based on all combinations of
+= options of CreateFileW
diff --git a/src/pal/tests/palsuite/file_io/CreateFileW/test1/winoutput b/src/pal/tests/palsuite/file_io/CreateFileW/test1/winoutput
new file mode 100644
index 0000000000..3913b99427
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/CreateFileW/test1/winoutput
@@ -0,0 +1 @@
+1111111111000001111111111111110000011111111111111100000111111111111111000001111111111111110000011111111111111100000111111111111111000001111111111111110000011111111111111100000111111111111111000001111111111111110000011111111111111100000111111111111111000001111111111111110000011111111111111100000111111111111111000001111111111111110000011111111111111100000111111111111111000001111111111111110000011111111111111100000111111111111111000001111111111111110000011111111111111100000111111111111111000001111111111111110000011111111111111100000111111111111111000001111111111111110000011111111111111100000111111111111111000001111111111111110000011111 \ No newline at end of file
diff --git a/src/pal/tests/palsuite/file_io/DeleteFileA/CMakeLists.txt b/src/pal/tests/palsuite/file_io/DeleteFileA/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/DeleteFileA/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/file_io/DeleteFileA/test1/CMakeLists.txt b/src/pal/tests/palsuite/file_io/DeleteFileA/test1/CMakeLists.txt
new file mode 100644
index 0000000000..b979c206b2
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/DeleteFileA/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ DeleteFileA.cpp
+)
+
+add_executable(paltest_deletefilea_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_deletefilea_test1 coreclrpal)
+
+target_link_libraries(paltest_deletefilea_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/DeleteFileA/test1/DeleteFileA.cpp b/src/pal/tests/palsuite/file_io/DeleteFileA/test1/DeleteFileA.cpp
new file mode 100644
index 0000000000..a8eb71decb
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/DeleteFileA/test1/DeleteFileA.cpp
@@ -0,0 +1,182 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: DeleteFileA.c
+**
+** Purpose: Tests the PAL implementation of the DeleteFileA function.
+**
+**
+**===================================================================*/
+
+// delete an existing file
+// delete a non-existant file
+// delete an open file
+// delete files using wild cards
+// delete a hidden file
+// delete a file without proper permissions
+//
+
+#define PAL_STDCPP_COMPAT
+#include <palsuite.h>
+#undef PAL_STDCPP_COMPAT
+
+#include <unistd.h>
+#include <sys/stat.h>
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ FILE *tempFile = NULL;
+ BOOL bRc = FALSE;
+
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ //
+ // create a test file
+ //
+ tempFile = fopen("testFile01.txt", "w");
+ if (tempFile == NULL)
+ {
+ Fail ("DeleteFileA: ERROR: Couldn't create \"DeleteFileA's"
+ " testFile01.txt\"\n");
+ }
+
+ fprintf(tempFile, "DeleteFileA test file.\n");
+ if (fclose(tempFile) != 0)
+ {
+ Fail ("DeleteFileA: ERROR: Couldn't close \"DeleteFileA's"
+ " testFile01.txt\"\n");
+ }
+
+ //
+ // delete a symlink to an existing file
+ //
+ if (symlink("testFile01.txt", "testFile01_symlink") != 0)
+ {
+ Fail("DeleteFileA: ERROR: Failed to create a symlink to testFile01.txt.\n");
+ }
+
+ bRc = DeleteFileA("testFile01_symlink");
+ if (bRc != TRUE)
+ {
+ Fail ("DeleteFileA: ERROR: Couldn't delete symlink!\n Error is %d\n", GetLastError());
+ }
+
+ struct stat statBuffer;
+ if (lstat("testFile01.txt", &statBuffer) != 0)
+ {
+ Fail("DeleteFileA: ERROR: Deleting a symlink deleted the file it was pointing to.\n");
+ }
+
+ if (lstat("testFile01_symlink", &statBuffer) == 0)
+ {
+ Fail("DeleteFileA: ERROR: Failed to delete a symlink.\n");
+ }
+
+ //
+ // deleting an existing file
+ //
+ bRc = DeleteFileA("testFile01.txt");
+ if (bRc != TRUE)
+ {
+ Fail ("DeleteFileA: ERROR: Couldn't delete DeleteFileA's"
+ " \"testFile01.txt\"\n"
+ " Error is %d\n", GetLastError());
+ }
+
+
+ //
+ // deleting a non-existant file : should fail
+ //
+
+ bRc = DeleteFileA("testFile02.txt");
+ if (bRc != FALSE)
+ {
+ Fail ("DeleteFileA: ERROR: Was able to delete the non-existant"
+ " file \"testFile02.txt\"\n");
+ }
+
+
+
+
+ //
+ // deleting an open file
+ //
+ tempFile = fopen("testFile03.txt", "w");
+ if (tempFile == NULL)
+ {
+ Fail("DeleteFileA: ERROR: Couldn't create \"DeleteFileA's"
+ " testFile03.txt\"\n");
+ }
+
+ fprintf(tempFile, "DeleteFileA test file.\n");
+ if (fclose(tempFile) != 0)
+ {
+ Fail ("DeleteFileA: ERROR: Couldn't close \"DeleteFileA's"
+ " testFile03.txt\"\n");
+ }
+
+ bRc = DeleteFileA("testFile03.txt");
+ if (bRc != TRUE)
+ {
+ Fail("DeleteFileA: ERROR: Couldn't delete DeleteFileA's"
+ " \"testFile03.txt\"\n"
+ " Error is %d\n", GetLastError());
+ }
+ bRc = DeleteFileA("testFile03.txt");
+
+
+
+
+ //
+ // delete using wild cards
+ //
+
+ // create the test file
+ tempFile = fopen("testFile04.txt", "w");
+ if (tempFile == NULL)
+ {
+ Fail("DeleteFileA: ERROR: Couldn't create DeleteFileA's"
+ " \"testFile04.txt\"\n");
+ }
+ fprintf(tempFile, "DeleteFileA test file.\n");
+ if (fclose(tempFile) != 0)
+ {
+ Fail ("DeleteFileA: ERROR: Couldn't close \"DeleteFileA's"
+ " testFile04.txt\"\n");
+ }
+
+ // delete using '?'
+ bRc = DeleteFileA("testFile0?.txt");
+ if (bRc == TRUE)
+ {
+ Fail("DeleteFileA: ERROR: Was able to delete using the"
+ " \'?\' wildcard\n");
+ }
+
+ // delete using '*'
+ bRc = DeleteFileA("testFile*.txt");
+ if (bRc == TRUE)
+ {
+ Fail("DeleteFileA: ERROR: Was able to delete using the"
+ " \'*\' wildcard\n");
+ }
+
+ bRc = DeleteFileA("testFile04.txt");
+ if (bRc != TRUE)
+ {
+ Fail ("DeleteFileA: ERROR: Couldn't delete DeleteFileA's"
+ " \"testFile04.txt\"\n"
+ " Error is %d\n", GetLastError());
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/file_io/DeleteFileA/test1/testinfo.dat b/src/pal/tests/palsuite/file_io/DeleteFileA/test1/testinfo.dat
new file mode 100644
index 0000000000..24283ed932
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/DeleteFileA/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = DeleteFileA
+Name = Test for DeleteFileA (test 1)
+Type = DEFAULT
+EXE1 = deletefilea
+Description
+= Attempt to delete various files.
+
diff --git a/src/pal/tests/palsuite/file_io/DeleteFileW/CMakeLists.txt b/src/pal/tests/palsuite/file_io/DeleteFileW/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/DeleteFileW/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/file_io/DeleteFileW/test1/CMakeLists.txt b/src/pal/tests/palsuite/file_io/DeleteFileW/test1/CMakeLists.txt
new file mode 100644
index 0000000000..046fd35148
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/DeleteFileW/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ DeleteFileW.c
+)
+
+add_executable(paltest_deletefilew_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_deletefilew_test1 coreclrpal)
+
+target_link_libraries(paltest_deletefilew_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/DeleteFileW/test1/DeleteFileW.c b/src/pal/tests/palsuite/file_io/DeleteFileW/test1/DeleteFileW.c
new file mode 100644
index 0000000000..fca96d1e00
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/DeleteFileW/test1/DeleteFileW.c
@@ -0,0 +1,164 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: DeleteFileW.c
+**
+** Purpose: Tests the PAL implementation of the DeleteFileW function.
+**
+**
+**===================================================================*/
+
+// delete an existing file
+// delete a non-existant file
+// delete an open file
+// delete files using wild cards
+// delete a hidden file
+// delete a file without proper permissions
+//
+
+
+#include <palsuite.h>
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ FILE *tempFile = NULL;
+ BOOL bRc = FALSE;
+ WCHAR* pTemp = NULL;
+
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ //
+ // deleting an existing file
+ //
+ tempFile = fopen("testFile01.tmp", "w");
+ if (tempFile == NULL)
+ {
+ Fail ("DeleteFileW: ERROR: Couldn't create \"DeleteFileW's"
+ " testFile01.tmp\"\n");
+ }
+
+ fprintf(tempFile, "DeleteFileW test file.\n");
+ if (fclose(tempFile) != 0)
+ {
+ Fail ("DeleteFileA: ERROR: Couldn't close \"DeleteFileW's"
+ " testFile01.tmp\"\n");
+ }
+
+ pTemp = convert("testFile01.tmp");
+ bRc = DeleteFileW(pTemp);
+ free(pTemp);
+ if (bRc != TRUE)
+ {
+ Fail ("DeleteFileW: ERROR: Couldn't delete DeleteFileW's"
+ " \"testFile01.tmp\"\n"
+ " Error is %d\n", GetLastError());
+ }
+
+
+ //
+ // deleting a non-existant file : should fail
+ //
+
+ pTemp = convert("testFile02.tmp");
+ bRc = DeleteFileW(pTemp);
+ free(pTemp);
+ if (bRc != FALSE)
+ {
+ Fail ("DeleteFileW: ERROR: Was able to delete the non-existant"
+ " file \"testFile02.tmp\"\n");
+ }
+
+
+
+
+ //
+ // deleting an open file
+ //
+ tempFile = fopen("testFile03.tmp", "w");
+ if (tempFile == NULL)
+ {
+ Fail("DeleteFileW: ERROR: Couldn't create \"DeleteFileW's"
+ " testFile03.tmp\"\n");
+ }
+
+ fprintf(tempFile, "DeleteFileW test file.\n");
+ if (fclose(tempFile) != 0)
+ {
+ Fail ("DeleteFileA: ERROR: Couldn't close \"DeleteFileW's"
+ " testFile03.tmp\"\n");
+ }
+
+ pTemp = convert("testFile03.tmp");
+ bRc = DeleteFileW(pTemp);
+ if (bRc != TRUE)
+ {
+ Fail("DeleteFileW: ERROR: Couldn't delete DeleteFileW's"
+ " \"testFile03.tmp\"\n"
+ " Error is %d\n", GetLastError());
+ free(pTemp);
+ }
+ bRc = DeleteFileW(pTemp);
+ free(pTemp);
+
+
+
+
+ //
+ // delete using wild cards
+ //
+
+ // create the test file
+ tempFile = fopen("testFile04.tmp", "w");
+ if (tempFile == NULL)
+ {
+ Fail("DeleteFileW: ERROR: Couldn't create DeleteFileW's"
+ " \"testFile04.tmp\"\n");
+ }
+ fprintf(tempFile, "DeleteFileW test file.\n");
+ if (fclose(tempFile) != 0)
+ {
+ Fail ("DeleteFileA: ERROR: Couldn't close \"DeleteFileW's"
+ " testFile04.tmp\"\n");
+ }
+
+ // delete using '?'
+ pTemp = convert("testFile0?.tmp");
+ bRc = DeleteFileW(pTemp);
+ free(pTemp);
+ if (bRc == TRUE)
+ {
+ Fail("DeleteFileW: ERROR: Was able to delete using the"
+ " \'?\' wildcard\n");
+ }
+
+ // delete using '*'
+ pTemp = convert("testFile*.tmp");
+ bRc = DeleteFileW(pTemp);
+ free(pTemp);
+ if (bRc == TRUE)
+ {
+ Fail("DeleteFileW: ERROR: Was able to delete using the"
+ " \'*\' wildcard\n");
+ }
+
+ pTemp = convert("testFile04.tmp");
+ bRc = DeleteFileW(pTemp);
+ free(pTemp);
+ if (bRc != TRUE)
+ {
+ Fail ("DeleteFileW: ERROR: Couldn't delete DeleteFileW's"
+ " \"testFile04.tmp\"\n"
+ " Error is %d\n", GetLastError());
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/file_io/DeleteFileW/test1/testinfo.dat b/src/pal/tests/palsuite/file_io/DeleteFileW/test1/testinfo.dat
new file mode 100644
index 0000000000..db44f998fc
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/DeleteFileW/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = DeleteFileW
+Name = Test for DeleteFileW (test 1)
+Type = DEFAULT
+EXE1 = deletefilew
+Description
+= Tests DeleteFileW on various file names
+
diff --git a/src/pal/tests/palsuite/file_io/FILECanonicalizePath/CMakeLists.txt b/src/pal/tests/palsuite/file_io/FILECanonicalizePath/CMakeLists.txt
new file mode 100644
index 0000000000..0c02c98f15
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/FILECanonicalizePath/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ FILECanonicalizePath.c
+)
+
+add_executable(paltest_filecanonicalizepath_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_filecanonicalizepath_test1 coreclrpal)
+
+target_link_libraries(paltest_filecanonicalizepath_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/FILECanonicalizePath/FILECanonicalizePath.c b/src/pal/tests/palsuite/file_io/FILECanonicalizePath/FILECanonicalizePath.c
new file mode 100644
index 0000000000..91bac1f3cb
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/FILECanonicalizePath/FILECanonicalizePath.c
@@ -0,0 +1,83 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: FILECanonicalizePath.c (test 1)
+**
+** Purpose: Tests the PAL implementation of the FILECanonicalizePath function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+extern void FILECanonicalizePath(LPSTR lpUnixPath);
+
+void TestCase(LPSTR input, LPSTR expectedOutput);
+
+int __cdecl main(int argc, char *argv[])
+{
+ if (PAL_Initialize(argc,argv) != 0)
+ {
+ return FAIL;
+ }
+
+ // Case 01: /<name> should not change
+ TestCase("/Test", "/Test");
+
+ // Case 02: /<name>/<name2> should not change
+ TestCase("/Test/Foo", "/Test/Foo");
+
+ // Case 03: // transforms to /
+ TestCase("//", "/");
+
+ // Case 04: /./ transforms to /
+ TestCase("/./", "/");
+
+ // Case 05: /<name>/../ transforms to /
+ TestCase("/Test/../", "/");
+
+ // Case 06: /Test/Foo/.. transforms to /Test
+ TestCase("/Test/Foo/..", "/Test");
+
+ // Case 07: /Test/.. transforms to /
+ TestCase("/Test/..", "/");
+
+ // Case 08: /. transforms to /
+ TestCase("/.", "/");
+
+ // Case 09: /<name/. transforms to /<name>
+ TestCase("/Test/.", "/Test");
+
+ // Case 10: /<name>/../. transforms to /
+ TestCase("/Test/../.", "/");
+
+ // Case 11: /.. transforms to /
+ TestCase("/..", "/");
+
+ PAL_Terminate();
+ return PASS;
+}
+
+void TestCase(LPSTR input, LPSTR expectedOutput)
+{
+ // Save the input for debug logging since the input is edited in-place
+ char* pOriginalInput = (char*)malloc(strlen(input) * sizeof(char) + 1);
+ strcpy(pOriginalInput, input);
+
+ char* pInput = (char*)malloc(strlen(input) * sizeof(char) + 1);
+ strcpy(pInput, pOriginalInput);
+
+ FILECanonicalizePath(pInput);
+ if (strcmp(pInput, expectedOutput) != 0)
+ {
+ free(pOriginalInput);
+ free(pInput);
+ Fail("FILECanonicalizePath error: input %s did not match expected output %s; got %s instead", pOriginalInput, expectedOutput, pInput);
+ }
+
+ free(pOriginalInput);
+ free(pInput);
+}
diff --git a/src/pal/tests/palsuite/file_io/FILECanonicalizePath/testinfo.dat b/src/pal/tests/palsuite/file_io/FILECanonicalizePath/testinfo.dat
new file mode 100644
index 0000000000..033ad78b47
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/FILECanonicalizePath/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = FILECanonicalizePath
+Name = Test for FILECanonicalizePath (test 1)
+Type = DEFAULT
+EXE1 = filecanonicalizepath
+Description
+= Canonicalizes paths and verifies the results
diff --git a/src/pal/tests/palsuite/file_io/FileTimeToDosDateTime/CMakeLists.txt b/src/pal/tests/palsuite/file_io/FileTimeToDosDateTime/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/FileTimeToDosDateTime/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/file_io/FileTimeToDosDateTime/test1/CMakeLists.txt b/src/pal/tests/palsuite/file_io/FileTimeToDosDateTime/test1/CMakeLists.txt
new file mode 100644
index 0000000000..131054266b
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/FileTimeToDosDateTime/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_filetimetodosdatetime_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_filetimetodosdatetime_test1 coreclrpal)
+
+target_link_libraries(paltest_filetimetodosdatetime_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/FileTimeToDosDateTime/test1/test1.c b/src/pal/tests/palsuite/file_io/FileTimeToDosDateTime/test1/test1.c
new file mode 100644
index 0000000000..5f2c81ff98
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/FileTimeToDosDateTime/test1/test1.c
@@ -0,0 +1,116 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test1.c
+**
+** Purpose: Tests that FileTimeToDosDateTime successfully converts values.
+** Makes sure values are rounded up, and the limits of the function
+** pass. Also tests that values outside the valid range fail.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+typedef struct
+{
+ DWORD FileTimeLow;
+ DWORD FileTimeHigh;
+ WORD FatDate;
+ WORD FatTime;
+} testCase;
+
+int __cdecl main(int argc, char **argv)
+{
+ FILETIME FileTime;
+ WORD ResultDate;
+ WORD ResultTime;
+ BOOL ret;
+ int i;
+
+ testCase testCases[] =
+ {
+ /* Test a normal time */
+ {0x9BE00100, 0x1B4A02C, 0x14CF, 0x55AF}, /* 12/15/2000, 10:45:30 AM*/
+ /* Test that 12/15/2000, 10:45:29 Gets rounded up */
+ {0x9B476A80, 0x1B4A02C, 0x14CF, 0x55AF}, /* 12/15/2000, 10:45:30 AM*/
+ /* Test that 12/15/2000, 10:45:31 Gets rounded up */
+ {0x9C789780, 0x1B4A02C, 0x14CF, 0x55B0}, /* 12/15/2000, 10:45:32 AM*/
+
+ /* Test the upper and lower limits of the function */
+ {0xE1D58000, 0x1A8E79F, 0x0021, 0x0000}, /* 1/1/1980, 12:00:00 AM*/
+ {0xb9de1300, 0x1e9eede, 0x739f, 0xbf7d}, /* 12/31/2037, 11:59:58 PM*/
+
+ /* Tests that should fail */
+ {0, 0, 0, 0},
+ {0xE0A45300, 0x1A8E79F, 0, 0},
+ {0x66D29301, 0x23868B8, 0, 0}
+
+ /* All this accomplishes is for the date to overflow.
+ Likely the only reason it fails in Windows is bacause the
+ resulting date falls outside of the legal range. Under BSD,
+ it falls into a legal range. This being that BSD calculates time
+ from 1900 to 2037, not 1980 to 2107.
+ {0xFFFFFFFF, 0xFFFFFFF, 0, 0}
+ */
+ };
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ for (i=0; i<sizeof(testCases) / sizeof(testCase); i++)
+ {
+ ResultDate = 0xFFFF;
+ ResultTime = 0xFFFF;
+
+ FileTime.dwLowDateTime = testCases[i].FileTimeLow;
+ FileTime.dwHighDateTime = testCases[i].FileTimeHigh;
+
+
+ ret = FileTimeToDosDateTime(&FileTime, &ResultDate, &ResultTime);
+ if (testCases[i].FatDate != 0 || testCases[i].FatTime != 0)
+ {
+ /* Expected it to pass */
+ if (!ret)
+ {
+ Fail("FileTimeToDosDateTime failed for %X,%X!\n",
+ testCases[i].FileTimeLow, testCases[i].FileTimeHigh);
+ }
+
+ if (ResultDate != testCases[i].FatDate ||
+ ResultTime != testCases[i].FatTime)
+ {
+ Fail("FileTimeToDosDateTime did not convert %X,%X "
+ "successfully:\nExpected date to be %hX, time %hx.\n"
+ "Got %hX, %hX\n", testCases[i].FileTimeLow,
+ testCases[i].FileTimeHigh, testCases[i].FatDate,
+ testCases[i].FatTime, ResultDate, ResultTime);
+ }
+ }
+ else
+ {
+ /* Expected it to fail. */
+ if (ret)
+ {
+ Fail("FileTimeToDosDateTime passed for %X,%X!\n",
+ testCases[i].FileTimeLow, testCases[i].FileTimeHigh);
+ }
+
+ if (ResultDate != 0xFFFF || ResultTime != 0xFFFF)
+ {
+ Fail("FileTimeToDosDateTime failed, but modified output "
+ "parameters: %X %X\n", ResultDate, ResultTime);
+ }
+ }
+
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/file_io/FileTimeToDosDateTime/test1/testinfo.dat b/src/pal/tests/palsuite/file_io/FileTimeToDosDateTime/test1/testinfo.dat
new file mode 100644
index 0000000000..b5c7e1ae52
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/FileTimeToDosDateTime/test1/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = FileTimeToDosDateTime
+Name = Positive Test #1 for FileTimeToDosDateTime
+TYPE = DEFAULT
+EXE1 = test1
+Description
+=Tests that FileTimeToDosDateTime successfully converts values.
+=Makes sure values are rounded up, and the limits of the function
+=pass. Also tests that values outside the valid range fail.
+
diff --git a/src/pal/tests/palsuite/file_io/FindClose/CMakeLists.txt b/src/pal/tests/palsuite/file_io/FindClose/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/FindClose/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/file_io/FindClose/test1/CMakeLists.txt b/src/pal/tests/palsuite/file_io/FindClose/test1/CMakeLists.txt
new file mode 100644
index 0000000000..732c9f58d3
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/FindClose/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ FindClose.c
+)
+
+add_executable(paltest_findclose_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_findclose_test1 coreclrpal)
+
+target_link_libraries(paltest_findclose_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/FindClose/test1/FindClose.c b/src/pal/tests/palsuite/file_io/FindClose/test1/FindClose.c
new file mode 100644
index 0000000000..3d53806e48
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/FindClose/test1/FindClose.c
@@ -0,0 +1,275 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: FindClose.c
+**
+** Purpose: Tests the PAL implementation of the FindClose function.
+**
+**
+**===================================================================*/
+
+
+#include <palsuite.h>
+
+
+
+const WCHAR szFindName[] = {'t','e', 's', 't', '0', '1', '.', 't', 'x', 't', '\0'};
+const WCHAR szFindName_02[] = {'t','e', 's', 't', '0', '2', '.', 't', 'x', 't', '\0'};
+const WCHAR szFindName_03[] = {'t','e', 's', 't', '0', '3', '.', 't', 'x', 't', '\0'};
+const WCHAR szFindNameWldCard_01[] = {'t','e', 's', 't', '0', '?', '.', 't', 'x', 't', '\0'};
+const WCHAR szFindNameWldCard_02[] = {'*', '.', 't', 'x', 't', '\0'};
+const WCHAR szDirName[] = {'t','e', 's', 't', '_', 'd', 'i', 'r', '\0'};
+const WCHAR szDirName_02[] = {'t','e', 's', 't', '_', 'd', 'i', 'r', '0', '2', '\0'};
+const WCHAR szDirNameWldCard[] = {'t','e', 's', 't', '_', '*', '\0'};
+
+
+
+BOOL createTestFile(const WCHAR* szName)
+{
+ FILE *pFile = NULL;
+ char* pTemp = NULL;
+
+ pTemp = convertC((WCHAR*)szName);
+ pFile = fopen(pTemp, "w");
+ if (pFile == NULL)
+ {
+ Trace("FindClose: ERROR -> Unable to create file \"%s\".\n", pTemp);
+ free(pTemp);
+ return FALSE;
+ }
+ else
+ {
+ fprintf(pFile, "FindClose test file, \"%s\".\n", pTemp);
+ free(pTemp);
+ fclose(pFile);
+ }
+ return TRUE;
+}
+
+
+void removeAll()
+{
+ RemoveDirectoryW(szDirName);
+ RemoveDirectoryW(szDirName_02);
+
+ DeleteFileW(szFindName);
+ DeleteFileW(szFindName_02);
+ DeleteFileW(szFindName_03);
+}
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ WIN32_FIND_DATAW findFileData;
+ WIN32_FIND_DATAW findFileData_02;
+ HANDLE hFind = NULL;
+ BOOL bRc = FALSE;
+ char* pTemp = NULL;
+
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ /* do some clean up just to be sure */
+ removeAll();
+
+ /* FindClose a null handle */
+ if(FindClose(NULL)!=0)
+ {
+ Fail("FindClose: ERROR -> Closing a NULL handle succeeded.\n");
+ }
+
+ /* find a file that exists */
+ if(createTestFile(szFindName) == FALSE)
+ {
+ removeAll();
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+ if(createTestFile(szFindName_02) == FALSE)
+ {
+ removeAll();
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+ if(createTestFile(szFindName_03) == FALSE)
+ {
+ removeAll();
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+
+ // close a FindFirstFileW handle
+ hFind = FindFirstFileW(szFindName, &findFileData);
+ if (hFind == INVALID_HANDLE_VALUE)
+ {
+ pTemp = convertC((WCHAR*)szFindName);
+ Trace("FindClose: ERROR -> Unable to find \"%s\"\n", pTemp);
+ free(pTemp);
+ removeAll();
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+ else
+ {
+ bRc = FindClose(hFind);
+ if (bRc == FALSE)
+ {
+ removeAll();
+ Fail("FindClose: ERROR -> Unable to close a valid"
+ " FindFirstFileW handle.\n");
+ }
+ }
+ hFind = FindFirstFileW(szFindName, &findFileData);
+ if (hFind == INVALID_HANDLE_VALUE)
+ {
+ pTemp = convertC((WCHAR*)szFindName);
+ Trace("FindClose: ERROR -> Unable to find \"%s\"\n", pTemp);
+ free(pTemp);
+ removeAll();
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+ else
+ {
+ bRc = FindNextFileW(hFind, &findFileData);
+ if (bRc != FALSE)
+ {
+ removeAll();
+ Fail("FindClose: ERROR -> Found a file that doesn't exist.\n");
+ }
+ else
+ {
+ bRc = FindClose(hFind);
+ if (bRc == FALSE)
+ {
+ removeAll();
+ Fail("FindClose: ERROR -> Unable to close a valid "
+ "FindNextFileW handle.\n");
+ }
+ }
+ }
+
+ /* find a directory that exists */
+ bRc = CreateDirectoryW(szDirName, NULL);
+ if (bRc == FALSE)
+ {
+ pTemp = convertC((WCHAR*)szDirName);
+ Trace("FindClose: ERROR -> Failed to create the directory \"%s\"\n",
+ pTemp);
+ free(pTemp);
+ removeAll();
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+
+ bRc = CreateDirectoryW(szDirName_02, NULL);
+ if (bRc == FALSE)
+ {
+ pTemp = convertC((WCHAR*)szDirName_02);
+ Trace("FindClose: ERROR -> Failed to create the directory \"%s\"\n",
+ pTemp);
+ free(pTemp);
+ removeAll();
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+
+ hFind = FindFirstFileW(szDirName, &findFileData);
+ if (hFind == INVALID_HANDLE_VALUE)
+ {
+ pTemp = convertC((WCHAR*)szDirName);
+ Trace("FindClose: ERROR. FindFirstFileW was unable to find \"%s\"\n",
+ pTemp);
+ free(pTemp);
+ removeAll();
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+ else
+ {
+ bRc = FindClose(hFind);
+ if (bRc == FALSE)
+ {
+ removeAll();
+ Fail("FindClose: ERROR -> Unable to close a valid"
+ " FindFirstFileW handle of a directory.\n");
+ }
+ }
+
+ /* find a file using wild cards */
+ hFind = FindFirstFileW(szFindNameWldCard_01, &findFileData);
+ if (hFind == INVALID_HANDLE_VALUE)
+ {
+ pTemp = convertC((WCHAR*)szFindNameWldCard_01);
+ Trace("FindClose: ERROR -> FindFirstFileW was unable to find \"%s\"\n",
+ pTemp);
+ free(pTemp);
+ removeAll();
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+ else
+ {
+ bRc = FindNextFileW(hFind, &findFileData_02);
+ if (bRc == FALSE)
+ {
+ removeAll();
+ Fail("FindClose: ERROR -> Unable to find another file.\n");
+ }
+ else
+ {
+ bRc = FindClose(hFind);
+ if (bRc == FALSE)
+ {
+ removeAll();
+ Fail("FindClose: ERROR -> Unable to close a valid"
+ " FindNextFileW handle.\n");
+ }
+ }
+ }
+
+ /* find a directory using wild cards */
+ hFind = FindFirstFileW(szDirNameWldCard, &findFileData);
+ if (hFind == INVALID_HANDLE_VALUE)
+ {
+ pTemp = convertC((WCHAR*)szDirNameWldCard);
+ Trace("FindClose: ERROR -> Unable to find \"%s\"\n",
+ pTemp);
+ free(pTemp);
+ removeAll();
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+ else
+ {
+ bRc = FindNextFileW(hFind, &findFileData_02);
+ if (bRc == FALSE)
+ {
+ removeAll();
+ Fail("FindClose: ERROR -> Unable to find another directory.\n");
+ }
+ else
+ {
+ bRc = FindClose(hFind);
+ if (bRc == FALSE)
+ {
+ removeAll();
+ Fail("FindClose: ERROR -> Unable to close a valid"
+ " FindNextFileW handle of a directory.\n");
+ }
+ }
+ }
+
+
+ removeAll();
+ PAL_Terminate();
+
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/file_io/FindClose/test1/testinfo.dat b/src/pal/tests/palsuite/file_io/FindClose/test1/testinfo.dat
new file mode 100644
index 0000000000..b59bcbf578
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/FindClose/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = FindClose
+Name = Test for FindClose (test 1)
+Type = DEFAULT
+EXE1 = findclose
+Description
+= Test the FindClose on handles opened using the Find functions
+
diff --git a/src/pal/tests/palsuite/file_io/FindFirstFileA/CMakeLists.txt b/src/pal/tests/palsuite/file_io/FindFirstFileA/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/FindFirstFileA/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/file_io/FindFirstFileA/test1/CMakeLists.txt b/src/pal/tests/palsuite/file_io/FindFirstFileA/test1/CMakeLists.txt
new file mode 100644
index 0000000000..6613c4d444
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/FindFirstFileA/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ FindFirstFileA.c
+)
+
+add_executable(paltest_findfirstfilea_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_findfirstfilea_test1 coreclrpal)
+
+target_link_libraries(paltest_findfirstfilea_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/FindFirstFileA/test1/FindFirstFileA.c b/src/pal/tests/palsuite/file_io/FindFirstFileA/test1/FindFirstFileA.c
new file mode 100644
index 0000000000..6ceb6a9747
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/FindFirstFileA/test1/FindFirstFileA.c
@@ -0,0 +1,206 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: FindFirstFileA.c
+**
+** Purpose: Tests the PAL implementation of the FindFirstFileA function.
+**
+**
+**===================================================================*/
+
+
+#include <palsuite.h>
+
+
+const char* szNoFileName = "333asdf.x77t";
+const char* szFindName = "test01.txt";
+const char* szFindNameWldCard_01 = "test0?.txt";
+const char* szFindNameWldCard_02 = "*.txt";
+const char* szDirName = "test_dir";
+const char* szDirNameSlash = "test_dir\\";
+const char* szDirNameWldCard_01 = "?est_dir";
+const char* szDirNameWldCard_02 = "test_*";
+/* Longer than MAX_LONGPATH characters */
+char szLongFindName[MAX_LONGPATH+1];
+
+BOOL CleanUp()
+{
+ DWORD dwAtt;
+ BOOL result = TRUE;
+
+ dwAtt = GetFileAttributesA(szFindName);
+ if( dwAtt != INVALID_FILE_ATTRIBUTES )
+ {
+ if(!SetFileAttributesA (szFindName, FILE_ATTRIBUTE_NORMAL))
+ {
+ result = FALSE;
+ Trace("ERROR:%d: Error setting attributes [%s][%d]\n", szFindName, FILE_ATTRIBUTE_NORMAL);
+ }
+ if(!DeleteFileA (szFindName))
+ {
+ result = FALSE;
+ Trace("ERROR:%d: Error deleting file [%s][%d]\n", GetLastError(), szFindName, dwAtt);
+ }
+ }
+
+ dwAtt = GetFileAttributesA(szDirName);
+ if( dwAtt != INVALID_FILE_ATTRIBUTES )
+ {
+ if(!RemoveDirectoryA (szDirName))
+ {
+ result = FALSE;
+ Trace("ERROR:%d: Error deleting file [%s][%d]\n", GetLastError(), szDirName, dwAtt);
+ }
+ }
+
+ return result;
+}
+
+int __cdecl main(int argc, char *argv[])
+{
+ WIN32_FIND_DATA findFileData;
+ HANDLE hFind = NULL;
+ FILE *pFile = NULL;
+ BOOL bRc = FALSE;
+ WCHAR* szwTemp = NULL;
+
+ memset(szLongFindName, 'a', MAX_LONGPATH+1);
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+
+ if(!CleanUp())
+ {
+ Fail("FindFirstFileW: ERROR : Initial Clean Up failed\n");
+ }
+
+ //
+ // find a file with a NULL pointer
+ //
+ hFind = FindFirstFileA(NULL, &findFileData);
+ if (hFind != INVALID_HANDLE_VALUE)
+ {
+ Fail ("FindFirstFileA: ERROR -> Found invalid NULL file");
+ }
+
+
+ //
+ // find a file that doesn't exist
+ //
+ hFind = FindFirstFileA(szNoFileName, &findFileData);
+ if (hFind != INVALID_HANDLE_VALUE)
+ {
+ Fail ("FindFirstFileA: ERROR -> Found invalid NULL file");
+ }
+
+
+ //
+ // find a file that exists
+ //
+ pFile = fopen(szFindName, "w");
+ if (pFile == NULL)
+ {
+ Fail("FindFirstFileA: ERROR -> Unable to create a test file\n");
+ }
+ else
+ {
+ fclose(pFile);
+ }
+ hFind = FindFirstFileA(szFindName, &findFileData);
+ if (hFind == INVALID_HANDLE_VALUE)
+ {
+ Fail ("FindFirstFileA: ERROR -> Unable to find \"%s\"\n", szFindName);
+ }
+ else
+ {
+ // validate we found the correct file
+ if (strcmp(szFindName, findFileData.cFileName) != 0)
+ {
+ Fail ("FindFirstFileA: ERROR -> Found the wrong file\n");
+ }
+ }
+
+
+ //
+ // find a directory that exists
+ //
+ szwTemp = convert((LPSTR)szDirName);
+ bRc = CreateDirectoryW(szwTemp, NULL);
+ free(szwTemp);
+ if (bRc == FALSE)
+ {
+ Fail("FindFirstFileA: ERROR -> Failed to create the directory "
+ "\"%s\"\n",
+ szDirName);
+ }
+
+ hFind = FindFirstFileA(szDirName, &findFileData);
+ if (hFind == INVALID_HANDLE_VALUE)
+ {
+ Fail ("FindFirstFileA: ERROR. Unable to find \"%s\"\n", szDirName);
+ }
+ else
+ {
+ // validate we found the correct directory
+ if (strcmp(szDirName, findFileData.cFileName) != 0)
+ {
+ Fail ("FindFirstFileA: ERROR -> Found the wrong directory\n");
+ }
+ }
+
+
+ //
+ // find a directory using a trailing '\' on the directory name: should fail
+ //
+ hFind = FindFirstFileA(szDirNameSlash, &findFileData);
+ if (hFind != INVALID_HANDLE_VALUE)
+ {
+ Fail ("FindFirstFileA: ERROR -> Able to find \"%s\": trailing "
+ "slash should have failed.\n",
+ szDirNameSlash);
+ }
+
+ // find a file using wild cards
+ hFind = FindFirstFileA(szFindNameWldCard_01, &findFileData);
+ if (hFind == INVALID_HANDLE_VALUE)
+ {
+ Fail ("FindFirstFileA: ERROR -> Unable to find \"%s\"\n",
+ szFindNameWldCard_01);
+ }
+
+ hFind = FindFirstFileA(szFindNameWldCard_02, &findFileData);
+ if (hFind == INVALID_HANDLE_VALUE)
+ {
+ Fail ("FindFirstFileA: ERROR -> Unable to find \"%s\"\n", szFindNameWldCard_02);
+ }
+
+
+ //
+ // find a directory using wild cards
+ //
+ hFind = FindFirstFileA(szDirNameWldCard_01, &findFileData);
+ if (hFind == INVALID_HANDLE_VALUE)
+ {
+ Fail ("FindFirstFileA: ERROR -> Unable to find \"%s\"\n", szDirNameWldCard_01);
+ }
+
+ hFind = FindFirstFileA(szDirNameWldCard_02, &findFileData);
+ if (hFind == INVALID_HANDLE_VALUE)
+ {
+ Fail ("FindFirstFileA: ERROR -> Unable to find \"%s\"\n", szDirNameWldCard_02);
+ }
+
+ if(!CleanUp())
+ {
+ Fail("FindFirstFileW: ERROR : Final Clean Up failed\n");
+ }
+
+ PAL_Terminate();
+
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/file_io/FindFirstFileA/test1/testinfo.dat b/src/pal/tests/palsuite/file_io/FindFirstFileA/test1/testinfo.dat
new file mode 100644
index 0000000000..5b92f8c642
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/FindFirstFileA/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = FindFirstFileA
+Name = Test for FindFirstFileA (test 1)
+Type = DEFAULT
+EXE1 = findfirstfilea
+Description
+= Create a number of files and try to find them
+
diff --git a/src/pal/tests/palsuite/file_io/FindFirstFileW/CMakeLists.txt b/src/pal/tests/palsuite/file_io/FindFirstFileW/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/FindFirstFileW/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/file_io/FindFirstFileW/test1/CMakeLists.txt b/src/pal/tests/palsuite/file_io/FindFirstFileW/test1/CMakeLists.txt
new file mode 100644
index 0000000000..23e95c7dad
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/FindFirstFileW/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ FindFirstFileW.c
+)
+
+add_executable(paltest_findfirstfilew_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_findfirstfilew_test1 coreclrpal)
+
+target_link_libraries(paltest_findfirstfilew_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/FindFirstFileW/test1/FindFirstFileW.c b/src/pal/tests/palsuite/file_io/FindFirstFileW/test1/FindFirstFileW.c
new file mode 100644
index 0000000000..f69a625976
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/FindFirstFileW/test1/FindFirstFileW.c
@@ -0,0 +1,212 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: FindFirstFileW.c
+**
+** Purpose: Tests the PAL implementation of the FindFirstFileW function.
+**
+**
+**===================================================================*/
+
+
+#include <palsuite.h>
+
+
+const char* szNoFileName = "333asdf.x77t";
+const char* szFindName = "test01.txt";
+const char* szFindNameWldCard_01 = "test0?.txt";
+const char* szFindNameWldCard_02 = "*.txt";
+const char* szDirName = "test_dir";
+const char* szDirNameSlash = "test_dir\\";
+const char* szDirNameWldCard_01 = "?est_dir";
+const char* szDirNameWldCard_02 = "test_*";
+
+
+BOOL CleanUp()
+{
+ DWORD dwAtt;
+ BOOL result = TRUE;
+
+ dwAtt = GetFileAttributesA(szFindName);
+ if( dwAtt != INVALID_FILE_ATTRIBUTES )
+ {
+ if(!SetFileAttributesA (szFindName, FILE_ATTRIBUTE_NORMAL))
+ {
+ result = FALSE;
+ Trace("ERROR:%d: Error setting attributes [%s][%d]\n", szFindName, FILE_ATTRIBUTE_NORMAL);
+ }
+ if(!DeleteFileA (szFindName))
+ {
+ result = FALSE;
+ Trace("ERROR:%d: Error deleting file [%s][%d]\n", GetLastError(), szFindName, dwAtt);
+ }
+ }
+
+ dwAtt = GetFileAttributesA(szDirName);
+ if( dwAtt != INVALID_FILE_ATTRIBUTES )
+ {
+ if(!RemoveDirectoryA (szDirName))
+ {
+ result = FALSE;
+ Trace("ERROR:%d: Error deleting file [%s][%d]\n", GetLastError(), szDirName, dwAtt);
+ }
+ }
+
+ return result;
+}
+
+int __cdecl main(int argc, char *argv[])
+{
+ WIN32_FIND_DATAW findFileData;
+ HANDLE hFind = NULL;
+ FILE *pFile = NULL;
+ BOOL bRc = FALSE;
+ WCHAR* pTemp = NULL;
+
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ if(!CleanUp())
+ {
+ Fail("FindFirstFileW: ERROR : Initial Clean Up failed\n");
+ }
+
+ //
+ // find a file that doesn't exist
+ //
+ pTemp = convert((LPSTR)szNoFileName);
+ hFind = FindFirstFileW(pTemp, &findFileData);
+ free(pTemp);
+ if (hFind != INVALID_HANDLE_VALUE)
+ {
+ Fail ("FindFirstFileW: ERROR -> Found invalid NULL file\n");
+ }
+
+
+ //
+ // find a file that exists
+ //
+ pFile = fopen(szFindName, "w");
+ if (pFile == NULL)
+ {
+ Fail("FindFirstFileW: ERROR -> Unable to create a test file\n");
+ }
+ else
+ {
+ fclose(pFile);
+ }
+ pTemp = convert((LPSTR)szFindName);
+ hFind = FindFirstFileW(pTemp, &findFileData);
+ if (hFind == INVALID_HANDLE_VALUE)
+ {
+ free(pTemp);
+ Fail ("FindFirstFileW: ERROR -> Unable to find \"%s\"\n", szFindName);
+ }
+ else
+ {
+ // validate we found the correct file
+ if (wcscmp(pTemp, findFileData.cFileName) != 0)
+ {
+ free(pTemp);
+ Fail ("FindFirstFileW: ERROR -> Found the wrong file\n");
+ }
+ }
+ free(pTemp);
+
+ //
+ // find a directory that exists
+ //
+ pTemp = convert((LPSTR)szDirName);
+ bRc = CreateDirectoryW(pTemp, NULL);
+ if (bRc == FALSE)
+ {
+ Fail("FindFirstFileW: ERROR[%u] -> Failed to create the directory \"%s\"\n",
+ GetLastError(), szDirName);
+ }
+
+ hFind = FindFirstFileW(pTemp, &findFileData);
+ if (hFind == INVALID_HANDLE_VALUE)
+ {
+ free(pTemp);
+ Fail("FindFirstFileW: ERROR. Unable to find \"%s\"\n", szDirName);
+ }
+ else
+ {
+ // validate we found the correct directory
+ if (wcscmp(pTemp, findFileData.cFileName) != 0)
+ {
+ free(pTemp);
+ Fail("FindFirstFileW: ERROR -> Found the wrong directory\n");
+ }
+ }
+ free(pTemp);
+
+ //
+ // find a directory using a trailing '\' on the directory name: should fail
+ //
+ pTemp = convert((LPSTR)szDirNameSlash);
+ hFind = FindFirstFileW(pTemp, &findFileData);
+ free(pTemp);
+ if (hFind != INVALID_HANDLE_VALUE)
+ {
+ Fail("FindFirstFileW: ERROR -> Able to find \"%s\": trailing "
+ "slash should have failed.\n",
+ szDirNameSlash);
+ }
+
+ // find a file using wild cards
+ pTemp = convert((LPSTR)szFindNameWldCard_01);
+ hFind = FindFirstFileW(pTemp, &findFileData);
+ free(pTemp);
+ if (hFind == INVALID_HANDLE_VALUE)
+ {
+ Fail("FindFirstFileW: ERROR -> Unable to find \"%s\"\n",
+ szFindNameWldCard_01);
+ }
+
+ pTemp = convert((LPSTR)szFindNameWldCard_02);
+ hFind = FindFirstFileW(pTemp, &findFileData);
+ free(pTemp);
+ if (hFind == INVALID_HANDLE_VALUE)
+ {
+ Fail("FindFirstFileW: ERROR -> Unable to find \"%s\"\n",
+ szFindNameWldCard_02);
+ }
+
+
+ //
+ // find a directory using wild cards
+ //
+
+ pTemp = convert((LPSTR)szDirNameWldCard_01);
+ hFind = FindFirstFileW(pTemp, &findFileData);
+ free(pTemp);
+ if (hFind == INVALID_HANDLE_VALUE)
+ {
+ Fail("FindFirstFileW: ERROR -> Unable to find \"%s\"\n",
+ szDirNameWldCard_01);
+ }
+
+ pTemp = convert((LPSTR)szDirNameWldCard_02);
+ hFind = FindFirstFileW(pTemp, &findFileData);
+ free(pTemp);
+ if (hFind == INVALID_HANDLE_VALUE)
+ {
+ Fail("FindFirstFileW: ERROR -> Unable to find \"%s\"\n",
+ szDirNameWldCard_02);
+ }
+
+ if(!CleanUp())
+ {
+ Fail("FindFirstFileW: ERROR : Final Clean Up failed\n");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/file_io/FindFirstFileW/test1/testinfo.dat b/src/pal/tests/palsuite/file_io/FindFirstFileW/test1/testinfo.dat
new file mode 100644
index 0000000000..c088c04cbd
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/FindFirstFileW/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = FindFirstFileW
+Name = Test for FindFirstFileW (test 1)
+Type = DEFAULT
+EXE1 = findfirstfilew
+Description
+= Create a number of files and try to find them
+
diff --git a/src/pal/tests/palsuite/file_io/FindNextFileA/CMakeLists.txt b/src/pal/tests/palsuite/file_io/FindNextFileA/CMakeLists.txt
new file mode 100644
index 0000000000..ef14ea5352
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/FindNextFileA/CMakeLists.txt
@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+
diff --git a/src/pal/tests/palsuite/file_io/FindNextFileA/test1/CMakeLists.txt b/src/pal/tests/palsuite/file_io/FindNextFileA/test1/CMakeLists.txt
new file mode 100644
index 0000000000..efb1655d95
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/FindNextFileA/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ FindNextFileA.c
+)
+
+add_executable(paltest_findnextfilea_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_findnextfilea_test1 coreclrpal)
+
+target_link_libraries(paltest_findnextfilea_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/FindNextFileA/test1/FindNextFileA.c b/src/pal/tests/palsuite/file_io/FindNextFileA/test1/FindNextFileA.c
new file mode 100644
index 0000000000..578fa00542
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/FindNextFileA/test1/FindNextFileA.c
@@ -0,0 +1,243 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: FindNextFileA.c
+**
+** Purpose: Tests the PAL implementation of the FindNextFileA function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+
+const char* szFindName = "test01.txt";
+const char* szFindName_02 = "test02.txt";
+const char* szFindNameWldCard_01 = "test0?.txt";
+const char* szFindNameWldCard_02 = "*.txt";
+const char* szDirName = "test_dir";
+const char* szDirName_02 = "test_dir_02";
+const char* szDirNameWldCard = "test_*";
+
+
+
+void removeAll()
+{
+ WCHAR* wTempPtr = NULL;
+
+ wTempPtr = convert((LPSTR)szDirName);
+ RemoveDirectoryW(wTempPtr);
+ free (wTempPtr);
+ wTempPtr = convert((LPSTR)szDirName_02);
+ RemoveDirectoryW(wTempPtr);
+ free (wTempPtr);
+ DeleteFile(szFindName);
+ DeleteFile(szFindName_02);
+}
+
+
+
+BOOL createTestFile(const char* szName)
+{
+ FILE *pFile = NULL;
+
+ pFile = fopen(szName, "w");
+ if (pFile == NULL)
+ {
+ Trace("FindNextFile: ERROR -> Unable to create file \"%s\".\n",
+ szName);
+ removeAll();
+ return FALSE;
+ }
+ else
+ {
+ fprintf(pFile, "FindNextFile test file, \"%s\".\n", szFindName);
+ fclose(pFile);
+ }
+ return TRUE;
+}
+
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ WIN32_FIND_DATA findFileData;
+ WIN32_FIND_DATA findFileData_02;
+ HANDLE hFind = NULL;
+ BOOL bRc = FALSE;
+ DWORD dwBytesWritten;
+ WCHAR* wTempPtr = NULL;
+
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+ removeAll();
+
+
+ //
+ // find a file with a NULL pointer
+ //
+ hFind = FindFirstFileA(NULL, &findFileData);
+ if (hFind != INVALID_HANDLE_VALUE)
+ {
+ Fail("FindNextFile: ERROR -> Found invalid NULL file");
+ }
+
+ bRc = FindNextFile(hFind, &findFileData);
+ if (bRc == TRUE)
+ {
+ Fail("FindNextFile: ERROR -> Found a file based on an invalid handle");
+ }
+
+
+ //
+ // find a file that exists
+ //
+ if(createTestFile(szFindName) == FALSE)
+ {
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+ if(createTestFile(szFindName_02) == FALSE)
+ {
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+
+ hFind = FindFirstFileA(szFindName, &findFileData);
+ if (hFind == INVALID_HANDLE_VALUE)
+ {
+ removeAll();
+ Fail("FindNextFile: ERROR -> Unable to find \"%s\"\n", szFindName);
+ }
+ else
+ {
+ bRc = FindNextFile(hFind, &findFileData);
+ if (bRc != FALSE)
+ {
+ removeAll();
+ Fail("FindNextFile: ERROR -> Found a file that doesn't exist.\n");
+ }
+ }
+
+
+ //
+ // find a directory that exists
+ //
+ wTempPtr = convert((LPSTR)szDirName);
+ bRc = CreateDirectoryW(wTempPtr, NULL);
+ free (wTempPtr);
+ if (bRc == FALSE)
+ {
+ removeAll();
+ Fail("FindNextFile: ERROR -> Failed to create the directory \"%s\"\n",
+ szDirName);
+ }
+ wTempPtr = convert((LPSTR)szDirName_02);
+ bRc = CreateDirectoryW(wTempPtr, NULL);
+ free (wTempPtr);
+ if (bRc == FALSE)
+ {
+ removeAll();
+ Fail("FindNextFile: ERROR -> Failed to create the directory \"%s\"\n",
+ szDirName_02);
+ }
+
+ hFind = FindFirstFileA(szDirName, &findFileData);
+ if (hFind == INVALID_HANDLE_VALUE)
+ {
+ removeAll();
+ Fail("FindNextFile: ERROR. FindFirstFileA was unable to find \"%s\"\n",
+ szDirName);
+ }
+ else
+ {
+ bRc = FindNextFile(hFind, &findFileData);
+ if (bRc != FALSE)
+ {
+ removeAll();
+ Fail("FindNextFile: ERROR -> Found a directory that doesn't exist.\n");
+ }
+ }
+
+
+ //
+ // find a file using wild cards
+ //
+ hFind = FindFirstFileA(szFindNameWldCard_01, &findFileData);
+ if (hFind == INVALID_HANDLE_VALUE)
+ {
+ removeAll();
+ Fail("FindNextFile: ERROR -> FindFirstFileA was unable to find \"%s\"\n",
+ szFindNameWldCard_01);
+ }
+ else
+ {
+ bRc = FindNextFile(hFind, &findFileData_02);
+ if (bRc == FALSE)
+ {
+ removeAll();
+ Fail("FindNextFile: ERROR -> Unable to find another file.\n");
+ }
+ else
+ {
+ // validate we found the correct file
+ if (strcmp(findFileData_02.cFileName, findFileData.cFileName) == 0)
+ {
+ removeAll();
+ Fail("FindNextFile: ERROR -> Found the same file \"%s\".\n",
+ findFileData.cFileName);
+ }
+ }
+ }
+
+
+ //
+ // find a directory using wild cards
+ //
+ hFind = FindFirstFileA(szDirNameWldCard, &findFileData);
+ if (hFind == INVALID_HANDLE_VALUE)
+ {
+ removeAll();
+ Fail("FindNextFile: ERROR -> Unable to find \"%s\"\n",
+ szDirNameWldCard);
+ }
+ else
+ {
+ bRc = FindNextFile(hFind, &findFileData_02);
+ if (bRc == FALSE)
+ {
+ removeAll();
+ Fail("FindNextFile: ERROR -> Unable to find another directory.\n");
+ }
+ else
+ {
+ // validate we found the correct directory
+ if (strcmp(findFileData_02.cFileName, findFileData.cFileName) == 0)
+ {
+ removeAll();
+ Fail("FindNextFile: ERROR -> Found the same directory \"%s\".\n",
+ findFileData.cFileName);
+ }
+ }
+ }
+
+ //
+ // attempt to write to the hFind handle (which should fail)
+ //
+ bRc = WriteFile(hFind, "this is a test", 10, &dwBytesWritten, NULL);
+ removeAll();
+ if (bRc == TRUE)
+ {
+ Fail("FindNextFile: ERROR -> Able to write to a FindNextFile handle.\n");
+ }
+
+ PAL_Terminate();
+
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/file_io/FindNextFileA/test1/testinfo.dat b/src/pal/tests/palsuite/file_io/FindNextFileA/test1/testinfo.dat
new file mode 100644
index 0000000000..e1027eff32
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/FindNextFileA/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = FindNextFileA
+Name = Test for FindNextFileA (test 1)
+Type = DEFAULT
+EXE1 = findnextfilea
+Description
+= Create test files and directories to verify FindNextFileA
+
diff --git a/src/pal/tests/palsuite/file_io/FindNextFileA/test2/CMakeLists.txt b/src/pal/tests/palsuite/file_io/FindNextFileA/test2/CMakeLists.txt
new file mode 100644
index 0000000000..96821bdaaa
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/FindNextFileA/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ findnextfilea.c
+)
+
+add_executable(paltest_findnextfilea_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_findnextfilea_test2 coreclrpal)
+
+target_link_libraries(paltest_findnextfilea_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/FindNextFileA/test2/findnextfilea.c b/src/pal/tests/palsuite/file_io/FindNextFileA/test2/findnextfilea.c
new file mode 100644
index 0000000000..c841a4d498
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/FindNextFileA/test2/findnextfilea.c
@@ -0,0 +1,107 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: findnextfilea.c
+**
+** Purpose: Tests the PAL implementation of the FindNextFileA function.
+** Tests '*' and '*.*' to ensure that '.' and '..' are
+** returned in the expected order
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+
+const char* szDot = ".";
+const char* szDotDot = "..";
+const char* szStar = "*";
+const char* szStarDotStar = "*.*";
+
+
+static void DoTest(const char* szDir,
+ const char* szResult1,
+ const char* szResult2)
+{
+ HANDLE hFind;
+ WIN32_FIND_DATA findFileData;
+
+ /*
+ ** find the first
+ */
+ if ((hFind = FindFirstFileA(szDir, &findFileData)) == INVALID_HANDLE_VALUE)
+ {
+ Fail("FindNextFileA: ERROR -> FindFirstFileA(\"%s\") failed. "
+ "GetLastError returned %u.\n",
+ szStar,
+ GetLastError());
+ }
+
+ /* did we find the expected */
+ if (strcmp(szResult1, findFileData.cFileName) != 0)
+ {
+ if (!FindClose(hFind))
+ {
+ Trace("FindNextFileA: ERROR -> Failed to close the find handle. "
+ "GetLastError returned %u.\n",
+ GetLastError());
+ }
+ Fail("FindNextFileA: ERROR -> FindFirstFile(\"%s\") didn't find"
+ " the expected \"%s\" but found \"%s\" instead.\n",
+ szDir,
+ szResult1,
+ findFileData.cFileName);
+ }
+
+ /* we found the first expected, let's see if we find the next expected*/
+ if (!FindNextFileA(hFind, &findFileData))
+ {
+ Trace("FindNextFileA: ERROR -> FindNextFileA should have found \"%s\""
+ " but failed. GetLastError returned %u.\n",
+ szResult2,
+ GetLastError());
+ if (!FindClose(hFind))
+ {
+ Trace("FindNextFileA: ERROR -> Failed to close the find handle. "
+ "GetLastError returned %u.\n",
+ GetLastError());
+ }
+ Fail("");
+ }
+
+ /* we found something, but was it '.' */
+ if (strcmp(szResult2, findFileData.cFileName) != 0)
+ {
+ if (!FindClose(hFind))
+ {
+ Trace("FindNextFileA: ERROR -> Failed to close the find handle. "
+ "GetLastError returned %u.\n",
+ GetLastError());
+ }
+ Fail("FindNextFileA: ERROR -> FindNextFileA based on \"%s\" didn't find"
+ " the expected \"%s\" but found \"%s\" instead.\n",
+ szDir,
+ szResult2,
+ findFileData.cFileName);
+ }
+}
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ DoTest(szStar, szDot, szDotDot);
+ DoTest(szStarDotStar, szDot, szDotDot);
+
+
+ PAL_Terminate();
+
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/file_io/FindNextFileA/test2/testinfo.dat b/src/pal/tests/palsuite/file_io/FindNextFileA/test2/testinfo.dat
new file mode 100644
index 0000000000..dd6c1e48b3
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/FindNextFileA/test2/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = FindNextFileA
+Name = Test for FindNextFileA (test 2)
+Type = DEFAULT
+EXE1 = findnextfilea
+Description
+= Tests the PAL implementation of the FindNextFileA function.
+= Tests '*' and '*.*' to ensure that '.' and '..' are
+= returned in the expected order
diff --git a/src/pal/tests/palsuite/file_io/FindNextFileW/CMakeLists.txt b/src/pal/tests/palsuite/file_io/FindNextFileW/CMakeLists.txt
new file mode 100644
index 0000000000..ef14ea5352
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/FindNextFileW/CMakeLists.txt
@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+
diff --git a/src/pal/tests/palsuite/file_io/FindNextFileW/test1/CMakeLists.txt b/src/pal/tests/palsuite/file_io/FindNextFileW/test1/CMakeLists.txt
new file mode 100644
index 0000000000..4a283dd3a5
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/FindNextFileW/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ FindNextFileW.c
+)
+
+add_executable(paltest_findnextfilew_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_findnextfilew_test1 coreclrpal)
+
+target_link_libraries(paltest_findnextfilew_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/FindNextFileW/test1/FindNextFileW.c b/src/pal/tests/palsuite/file_io/FindNextFileW/test1/FindNextFileW.c
new file mode 100644
index 0000000000..42e2e55805
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/FindNextFileW/test1/FindNextFileW.c
@@ -0,0 +1,249 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: FindNextFileW.c
+**
+** Purpose: Tests the PAL implementation of the FindNextFileW function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+
+const char* szFindName = "test01.txt";
+const char* szFindName_02 = "test02.txt";
+const char* szFindNameWldCard_01 = "test0?.txt";
+const char* szFindNameWldCard_02 = "*.txt";
+const char* szDirName = "test_dir";
+const char* szDirName_02 = "test_dir_02";
+const char* szDirNameWldCard = "test_*";
+
+
+
+void removeAll()
+{
+ WCHAR* wTempPtr = NULL;
+
+ wTempPtr = convert((LPSTR)szDirName);
+ RemoveDirectoryW(wTempPtr);
+ free(wTempPtr);
+
+ wTempPtr = convert((LPSTR)szDirName_02);
+ RemoveDirectoryW(wTempPtr);
+ free(wTempPtr);
+
+ wTempPtr = convert((LPSTR)szFindName);
+ DeleteFileW(wTempPtr);
+ free(wTempPtr);
+
+ wTempPtr = convert((LPSTR)szFindName_02);
+ DeleteFileW(wTempPtr);
+ free(wTempPtr);
+}
+
+
+
+BOOL createTestFile(const char* szName)
+{
+ FILE *pFile = NULL;
+
+ pFile = fopen(szName, "w");
+ if (pFile == NULL)
+ {
+ Trace("FindNextFileW: ERROR -> Unable to create file \"%s\".\n", szName);
+ removeAll();
+ return FALSE;
+ }
+ else
+ {
+ fprintf(pFile, "FindNextFileW test file, \"%s\".\n", szFindName);
+ fclose(pFile);
+ }
+
+ return TRUE;
+}
+
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ WIN32_FIND_DATAW findFileData;
+ WIN32_FIND_DATAW findFileData_02;
+ HANDLE hFind = NULL;
+ BOOL bRc = FALSE;
+ DWORD dwBytesWritten;
+ WCHAR* wTempPtr = NULL;
+
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+ removeAll();
+
+
+ //
+ // find a file that exists
+ //
+ if(createTestFile(szFindName) == FALSE)
+ {
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+ if(createTestFile(szFindName_02) == FALSE)
+ {
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+
+ wTempPtr = convert((LPSTR)szFindName);
+ hFind = FindFirstFileW(wTempPtr, &findFileData);
+ free(wTempPtr);
+ if (hFind == INVALID_HANDLE_VALUE)
+ {
+ removeAll();
+ Fail("FindNextFileW: ERROR -> Unable to find \"%s\"\n", szFindName);
+ }
+ else
+ {
+ bRc = FindNextFileW(hFind, &findFileData);
+ if (bRc != FALSE)
+ {
+ removeAll();
+ Fail("FindNextFileW: ERROR -> Found a file that doesn't exist.\n");
+ }
+ }
+
+
+ //
+ // find a directory that exists
+ //
+ wTempPtr = convert((LPSTR)szDirName);
+ bRc = CreateDirectoryW(wTempPtr, NULL);
+ free (wTempPtr);
+ if (bRc == FALSE)
+ {
+ removeAll();
+ Fail("FindNextFileW: ERROR -> Failed to create the directory \"%s\"\n",
+ szDirName);
+ }
+ wTempPtr = convert((LPSTR)szDirName_02);
+ bRc = CreateDirectoryW(wTempPtr, NULL);
+ free (wTempPtr);
+ if (bRc == FALSE)
+ {
+ removeAll();
+ Fail("FindNextFileW: ERROR -> Failed to create the directory "
+ "\"%s\"\n",
+ szDirName_02);
+ }
+
+ wTempPtr = convert((LPSTR)szDirName);
+ hFind = FindFirstFileW(wTempPtr, &findFileData);
+ free (wTempPtr);
+ if (hFind == INVALID_HANDLE_VALUE)
+ {
+ removeAll();
+ Fail("FindNextFileW: ERROR. FindFirstFileW was unable "
+ "to find \"%s\"\n",
+ szDirName);
+ }
+ else
+ {
+ bRc = FindNextFileW(hFind, &findFileData);
+ if (bRc != FALSE)
+ {
+ removeAll();
+ Fail("FindNextFileW: ERROR -> Found a directory that "
+ "doesn't exist.\n");
+ }
+ }
+
+
+ //
+ // find a file using wild cards
+ //
+ wTempPtr = convert((LPSTR)szFindNameWldCard_01);
+ hFind = FindFirstFileW(wTempPtr, &findFileData);
+ free(wTempPtr);
+ if (hFind == INVALID_HANDLE_VALUE)
+ {
+ removeAll();
+ Fail("FindNextFileW: ERROR -> FindFirstFileW was unable to "
+ "find \"%s\"\n",
+ szFindNameWldCard_01);
+ }
+ else
+ {
+ bRc = FindNextFileW(hFind, &findFileData_02);
+ if (bRc == FALSE)
+ {
+ removeAll();
+ Fail("FindNextFileW: ERROR -> Unable to find another file.\n");
+ }
+ else
+ {
+ // validate we found the correct file
+ if (wcscmp(findFileData_02.cFileName, findFileData.cFileName) == 0)
+ {
+ removeAll();
+ Fail("FindNextFileW: ERROR -> Found the same file \"%S\".\n",
+ findFileData.cFileName);
+ }
+ }
+ }
+
+
+ //
+ // find a directory using wild cards
+ //
+ wTempPtr = convert((LPSTR)szDirNameWldCard);
+ hFind = FindFirstFileW(wTempPtr, &findFileData);
+ free(wTempPtr);
+ if (hFind == INVALID_HANDLE_VALUE)
+ {
+ removeAll();
+ Fail("FindNextFileW: ERROR -> Unable to find \"%s\"\n",
+ szDirNameWldCard);
+ }
+ else
+ {
+ bRc = FindNextFileW(hFind, &findFileData_02);
+ if (bRc == FALSE)
+ {
+ removeAll();
+ Fail("FindNextFileW: ERROR -> Unable to find another directory.\n");
+ }
+ else
+ {
+ // validate we found the correct directory
+ if (wcscmp(findFileData_02.cFileName, findFileData.cFileName) == 0)
+ {
+ removeAll();
+ Fail("FindNextFileW: ERROR -> Found the same directory "
+ "\"%S\".\n",
+ findFileData.cFileName);
+ }
+ }
+ }
+
+ //
+ // attempt to write to the hFind handle (which should fail)
+ //
+ bRc = WriteFile(hFind, "this is a test", 10, &dwBytesWritten, NULL);
+ if (bRc == TRUE)
+ {
+ removeAll();
+ Fail("FindNextFileW: ERROR -> Able to write to a FindNextFileW "
+ "handle.\n");
+ }
+
+ removeAll();
+ PAL_Terminate();
+
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/file_io/FindNextFileW/test1/testinfo.dat b/src/pal/tests/palsuite/file_io/FindNextFileW/test1/testinfo.dat
new file mode 100644
index 0000000000..3eaebef43e
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/FindNextFileW/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = FindNextFileW
+Name = Test for FindNextFileW (test 1)
+Type = DEFAULT
+EXE1 = findnextfilew
+Description
+= Create test files and directories to verify FindNextFileW
+
diff --git a/src/pal/tests/palsuite/file_io/FindNextFileW/test2/CMakeLists.txt b/src/pal/tests/palsuite/file_io/FindNextFileW/test2/CMakeLists.txt
new file mode 100644
index 0000000000..2938afb888
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/FindNextFileW/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ findnextfilew.c
+)
+
+add_executable(paltest_findnextfilew_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_findnextfilew_test2 coreclrpal)
+
+target_link_libraries(paltest_findnextfilew_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/FindNextFileW/test2/findnextfilew.c b/src/pal/tests/palsuite/file_io/FindNextFileW/test2/findnextfilew.c
new file mode 100644
index 0000000000..3e806c2576
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/FindNextFileW/test2/findnextfilew.c
@@ -0,0 +1,107 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: FindNextFileW.c
+**
+** Purpose: Tests the PAL implementation of the FindNextFileW function.
+** Tests '*' and '*.*' to ensure that '.' and '..' are
+** returned in the expected order
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+
+const WCHAR szwDot[] = {'.','\0'};
+const WCHAR szwDotDot[] = {'.','.','\0'};
+const WCHAR szwStar[] = {'*','\0'};
+const WCHAR szwStarDotStar[] = {'*','.','*','\0'};
+
+
+static void DoTest(const WCHAR* szwDir,
+ const WCHAR* szwResult1,
+ const WCHAR* szwResult2)
+{
+ HANDLE hFind;
+ WIN32_FIND_DATAW findFileData;
+
+ /*
+ ** find the first
+ */
+ if ((hFind = FindFirstFileW(szwDir, &findFileData)) == INVALID_HANDLE_VALUE)
+ {
+ Fail("FindNextFileW: ERROR -> FindFirstFileW(\"%S\") failed. "
+ "GetLastError returned %u.\n",
+ szwStar,
+ GetLastError());
+ }
+
+ /* did we find the expected */
+ if (wcscmp(szwResult1, findFileData.cFileName) != 0)
+ {
+ if (!FindClose(hFind))
+ {
+ Trace("FindNextFileW: ERROR -> Failed to close the find handle. "
+ "GetLastError returned %u.\n",
+ GetLastError());
+ }
+ Fail("FindNextFileW: ERROR -> FindFirstFile(\"%S\") didn't find"
+ " the expected \"%S\" but found \"%S\" instead.\n",
+ szwDir,
+ szwResult1,
+ findFileData.cFileName);
+ }
+
+ /* we found the first expected, let's see if we find the next expected*/
+ if (!FindNextFileW(hFind, &findFileData))
+ {
+ Trace("FindNextFileW: ERROR -> FindNextFileW should have found \"%S\""
+ " but failed. GetLastError returned %u.\n",
+ szwResult2,
+ GetLastError());
+ if (!FindClose(hFind))
+ {
+ Trace("FindNextFileW: ERROR -> Failed to close the find handle. "
+ "GetLastError returned %u.\n",
+ GetLastError());
+ }
+ Fail("");
+ }
+
+ /* we found something, but was it '.' */
+ if (wcscmp(szwResult2, findFileData.cFileName) != 0)
+ {
+ if (!FindClose(hFind))
+ {
+ Trace("FindNextFileW: ERROR -> Failed to close the find handle. "
+ "GetLastError returned %u.\n",
+ GetLastError());
+ }
+ Fail("FindNextFileW: ERROR -> FindNextFileW based on \"%S\" didn't find"
+ " the expected \"%S\" but found \"%S\" instead.\n",
+ szwDir,
+ szwResult2,
+ findFileData.cFileName);
+ }
+}
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ DoTest(szwStar, szwDot, szwDotDot);
+ DoTest(szwStarDotStar, szwDot, szwDotDot);
+
+
+ PAL_Terminate();
+
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/file_io/FindNextFileW/test2/testinfo.dat b/src/pal/tests/palsuite/file_io/FindNextFileW/test2/testinfo.dat
new file mode 100644
index 0000000000..98bd5e7793
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/FindNextFileW/test2/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = FindNextFileW
+Name = Test for FindNextFileW (test 2)
+Type = DEFAULT
+EXE1 = findnextfilew
+Description
+= Tests the PAL implementation of the FindNextFileW function.
+= Tests '*' and '*.*' to ensure that '.' and '..' are
+= returned in the expected order
diff --git a/src/pal/tests/palsuite/file_io/FlushFileBuffers/CMakeLists.txt b/src/pal/tests/palsuite/file_io/FlushFileBuffers/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/FlushFileBuffers/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/file_io/FlushFileBuffers/test1/CMakeLists.txt b/src/pal/tests/palsuite/file_io/FlushFileBuffers/test1/CMakeLists.txt
new file mode 100644
index 0000000000..e3fbccd2ae
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/FlushFileBuffers/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ FlushFileBuffers.c
+)
+
+add_executable(paltest_flushfilebuffers_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_flushfilebuffers_test1 coreclrpal)
+
+target_link_libraries(paltest_flushfilebuffers_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/FlushFileBuffers/test1/FlushFileBuffers.c b/src/pal/tests/palsuite/file_io/FlushFileBuffers/test1/FlushFileBuffers.c
new file mode 100644
index 0000000000..246be64847
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/FlushFileBuffers/test1/FlushFileBuffers.c
@@ -0,0 +1,130 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: FlushFileBuffers.c
+**
+** Purpose: Tests the PAL implementation of the FlushFileBuffers function
+** This tests checks the return values of FlushFileBuffers -- once on an
+** open handle and once on a closed handle.
+**
+** Depends:
+** CreateFile
+** WriteFile
+** CloseHandle
+** DeleteFileA
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+
+int __cdecl main(int argc, char **argv)
+{
+
+ int TheReturn;
+ HANDLE TheFileHandle;
+ DWORD temp;
+ DWORD originalSize=10000;
+ DWORD finalSize=10000;
+ const char* fileName="the_file";
+
+ /* 1 2 3 4*/
+ char * SomeText = "1234567890123456789012345678901234567890";
+
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+
+ /* Open the file to get a HANDLE */
+ TheFileHandle =
+ CreateFile(
+ fileName,
+ GENERIC_READ|GENERIC_WRITE,
+ FILE_SHARE_READ,
+ NULL,
+ OPEN_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if(TheFileHandle == INVALID_HANDLE_VALUE)
+ {
+ Fail("ERROR: CreateFile failed. Test depends on this function.");
+ }
+
+ /* get the file size */
+ originalSize = GetFileSize (TheFileHandle, NULL) ;
+ if(originalSize == INVALID_FILE_SIZE)
+ {
+ Fail("ERROR: call to GetFileSize faild with error "
+ "The GetLastError is %d.",GetLastError());
+ }
+
+ /* Write something too the HANDLE. Should be buffered */
+ TheReturn = WriteFile(TheFileHandle,
+ SomeText,
+ strlen(SomeText),
+ &temp,
+ NULL);
+
+ if(TheReturn == 0)
+ {
+ Fail("ERROR: WriteFile failed. Test depends on this function.");
+ }
+
+ /* Test to see that FlushFileBuffers returns a success value */
+ TheReturn = FlushFileBuffers(TheFileHandle);
+ if(TheReturn == 0)
+ {
+ Fail("ERROR: The FlushFileBuffers function returned 0, which "
+ "indicates failure, when trying to flush a valid HANDLE. "
+ "The GetLastError is %d.",GetLastError());
+ }
+
+ /* test if flush modified the file */
+ finalSize = GetFileSize (TheFileHandle, NULL) ;
+ if(finalSize==INVALID_FILE_SIZE)
+ {
+ Fail("ERROR: call to GetFileSize faild with error "
+ "The GetLastError is %d.",GetLastError());
+ }
+ if(finalSize!=(originalSize+strlen(SomeText)))
+ {
+ Fail("ERROR: FlushFileBuffers failed. data was not written to the file");
+ }
+
+
+ /* Close the Handle */
+ TheReturn = CloseHandle(TheFileHandle);
+ if(TheReturn == 0)
+ {
+ Fail("ERROR: CloseHandle failed. This function depends "
+ "upon it.");
+ }
+
+
+ /* Test to see that FlushFileBuffers returns a failure value */
+ TheReturn = FlushFileBuffers(TheFileHandle);
+ if(TheReturn != 0)
+ {
+ Fail("ERROR: The FlushFileBuffers function returned non-zero, "
+ "which indicates success, when trying to flush an invalid "
+ "HANDLE.");
+ }
+
+ /* make sure file does not exist */
+ if(DeleteFileA(fileName)== 0 )
+ {
+ Fail("ERROR: call to DeleteFileA faild with error "
+ "The GetLastError is %d.",GetLastError());
+ }
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/file_io/FlushFileBuffers/test1/testinfo.dat b/src/pal/tests/palsuite/file_io/FlushFileBuffers/test1/testinfo.dat
new file mode 100644
index 0000000000..3a0da6918d
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/FlushFileBuffers/test1/testinfo.dat
@@ -0,0 +1,17 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = FlushFileBuffers
+Name = Positive Test for FlushFileBuffers
+TYPE = DEFAULT
+EXE1 = flushfilebuffers
+Description
+= Test the FlushFileBuffers
+= Test the return values -- ensure that the correct values are
+= returned for success and failure.
+= This test does not prove that flush worked,
+= there is no way of stopping the OS from flushing
+= the file by itself.
diff --git a/src/pal/tests/palsuite/file_io/GetConsoleCP/CMakeLists.txt b/src/pal/tests/palsuite/file_io/GetConsoleCP/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetConsoleCP/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/file_io/GetConsoleCP/test1/CMakeLists.txt b/src/pal/tests/palsuite/file_io/GetConsoleCP/test1/CMakeLists.txt
new file mode 100644
index 0000000000..131f4a5fb7
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetConsoleCP/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ GetConsoleCP.c
+)
+
+add_executable(paltest_getconsolecp_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getconsolecp_test1 coreclrpal)
+
+target_link_libraries(paltest_getconsolecp_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/GetConsoleCP/test1/GetConsoleCP.c b/src/pal/tests/palsuite/file_io/GetConsoleCP/test1/GetConsoleCP.c
new file mode 100644
index 0000000000..ba17d6c64d
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetConsoleCP/test1/GetConsoleCP.c
@@ -0,0 +1,35 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: GetConsoleCP.c (test 1)
+**
+** Purpose: Tests the PAL implementation of the GetConsoleCP function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ UINT uiCP = 0;
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ uiCP = GetConsoleCP();
+ if ((uiCP != CP_ACP) && (uiCP != GetACP()) && (uiCP != 437)) /*437 for MSDOS*/
+ {
+ Fail("GetConsoleCP: ERROR -> The invalid code page %d was returned.\n",
+ uiCP);
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/file_io/GetConsoleCP/test1/testinfo.dat b/src/pal/tests/palsuite/file_io/GetConsoleCP/test1/testinfo.dat
new file mode 100644
index 0000000000..608a01b2ef
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetConsoleCP/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = GetConsoleCP
+Name = Positive Test for GetConsoleCP (test 1)
+Type = DEFAULT
+EXE1 = getconsolecp
+Description
+= Test GetConsoleCP. Apparently there are only two possible
+= return values: CP_ACP or 1252
diff --git a/src/pal/tests/palsuite/file_io/GetConsoleOutputCP/CMakeLists.txt b/src/pal/tests/palsuite/file_io/GetConsoleOutputCP/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetConsoleOutputCP/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/file_io/GetConsoleOutputCP/test1/CMakeLists.txt b/src/pal/tests/palsuite/file_io/GetConsoleOutputCP/test1/CMakeLists.txt
new file mode 100644
index 0000000000..d19ab95a37
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetConsoleOutputCP/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ GetConsoleOutputCP.c
+)
+
+add_executable(paltest_getconsoleoutputcp_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getconsoleoutputcp_test1 coreclrpal)
+
+target_link_libraries(paltest_getconsoleoutputcp_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/GetConsoleOutputCP/test1/GetConsoleOutputCP.c b/src/pal/tests/palsuite/file_io/GetConsoleOutputCP/test1/GetConsoleOutputCP.c
new file mode 100644
index 0000000000..3deaebf68f
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetConsoleOutputCP/test1/GetConsoleOutputCP.c
@@ -0,0 +1,35 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: GetConsoleOutputCP.c (test 1)
+**
+** Purpose: Tests the PAL implementation of the GetConsoleOutputCP function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ UINT uiCP = 0;
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ uiCP = GetConsoleOutputCP();
+ if ((uiCP != CP_ACP) && (uiCP != GetACP()) && (uiCP != 437)) /*437 for MSDOS*/
+ {
+ Fail("GetConsoleOutputCP: ERROR -> The invalid code page %d was returned.\n",
+ uiCP);
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/file_io/GetConsoleOutputCP/test1/testinfo.dat b/src/pal/tests/palsuite/file_io/GetConsoleOutputCP/test1/testinfo.dat
new file mode 100644
index 0000000000..9ad624eaf2
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetConsoleOutputCP/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = GetConsoleOutputCP
+Name = Positive Test for GetConsoleOutputCP (test 1)
+Type = DEFAULT
+EXE1 = getconsoleoutputcp
+Description
+= Test GetConsoleOutputCP. Apparently there are only two possible
+= return values: CP_ACP or 1252
diff --git a/src/pal/tests/palsuite/file_io/GetCurrentDirectoryA/CMakeLists.txt b/src/pal/tests/palsuite/file_io/GetCurrentDirectoryA/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetCurrentDirectoryA/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/file_io/GetCurrentDirectoryA/test1/CMakeLists.txt b/src/pal/tests/palsuite/file_io/GetCurrentDirectoryA/test1/CMakeLists.txt
new file mode 100644
index 0000000000..f7382b047d
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetCurrentDirectoryA/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ GetCurrentDirectoryA.c
+)
+
+add_executable(paltest_getcurrentdirectorya_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getcurrentdirectorya_test1 coreclrpal)
+
+target_link_libraries(paltest_getcurrentdirectorya_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/GetCurrentDirectoryA/test1/GetCurrentDirectoryA.c b/src/pal/tests/palsuite/file_io/GetCurrentDirectoryA/test1/GetCurrentDirectoryA.c
new file mode 100644
index 0000000000..b09e8a104d
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetCurrentDirectoryA/test1/GetCurrentDirectoryA.c
@@ -0,0 +1,97 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: GetCurrentDirectoryA.c (test 1)
+**
+** Purpose: Tests the PAL implementation of the GetCurrentDirectoryA function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+const char* szFileName = "blah";
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ DWORD dwRc = 0;
+ DWORD dwRc2 = 0;
+ char szReturnedPath[_MAX_PATH+1];
+ char szCurrentDir[_MAX_PATH+1];
+ LPSTR pPathPtr;
+ size_t nCount = 0;
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ // use GetFullPathName to to get the current path by stripping
+ // the file name off the end
+ memset(szReturnedPath, 0, sizeof(char)*(_MAX_PATH+1));
+ dwRc = GetFullPathNameA(szFileName, _MAX_PATH, szReturnedPath, &pPathPtr);
+ if (dwRc == 0)
+ {
+ // GetFullPathName failed
+ Fail("GetCurrentDirectoryA: ERROR -> GetFullPathNameA failed "
+ "with error code: %ld.\n", GetLastError());
+ }
+ else if(dwRc > _MAX_PATH)
+ {
+ Fail("GetCurrentDirectoryA: ERROR -> The path name GetFullPathNameA "
+ "returned is longer than _MAX_PATH characters.\n");
+ }
+
+
+ // strip the file name from the full path to get the current path
+ nCount = strlen(szReturnedPath) - strlen(szFileName) - 1;
+ memset(szCurrentDir, 0, sizeof(char)*(_MAX_PATH+1));
+ strncpy(szCurrentDir, szReturnedPath, nCount);
+
+ // compare the results of GetCurrentDirectoryA with the above
+ memset(szReturnedPath, 0, sizeof(char)*(_MAX_PATH+1));
+ dwRc = GetCurrentDirectoryA((sizeof(char)*(_MAX_PATH+1)), szReturnedPath);
+ if (dwRc == 0)
+ {
+ Fail("GetCurrentDirectoryA: ERROR -> GetCurrentDirectoryA failed "
+ "with error code: %ld.\n", GetLastError());
+ }
+ else if(dwRc > _MAX_PATH)
+ {
+ Fail("GetCurrentDirectoryA: ERROR -> The path name "
+ "returned is longer than _MAX_PATH characters.\n");
+ }
+
+
+ /* test case the passed buffer size is not big enough
+ * function should return the size required + 1 a terminating null character
+ */
+
+ /* good buffer size */
+ dwRc = GetCurrentDirectoryA((sizeof(CHAR)*(_MAX_PATH+1)), szReturnedPath);
+
+ /* small buffer (0 size)*/
+ dwRc2 = GetCurrentDirectoryA(0, szReturnedPath);
+ if (dwRc2 != (dwRc+1) )
+ {
+ Fail("GetCurrentDirectoryA: ERROR -> failed to give the correct "
+ "return value when passed a buffer not big enough. "
+ "Expected %u while result is %u \n",(dwRc+1),dwRc2);
+
+ }
+
+ if (strcmp(szReturnedPath, szCurrentDir) != 0)
+ {
+ Fail("GetCurrentDirectoryA: ERROR -> The computed and returned "
+ "directories do not compare.\n");
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/file_io/GetCurrentDirectoryA/test1/testinfo.dat b/src/pal/tests/palsuite/file_io/GetCurrentDirectoryA/test1/testinfo.dat
new file mode 100644
index 0000000000..c14eb42b22
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetCurrentDirectoryA/test1/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = GetCurrentDirectoryA
+Name = Test for GetCurrentDirectoryA (test 1)
+Type = DEFAULT
+EXE1 = getcurrentdirectorya
+Description
+= Calculate the current directory name and compare to that
+= returned by GetCurrentDirectoryA
+
diff --git a/src/pal/tests/palsuite/file_io/GetCurrentDirectoryW/CMakeLists.txt b/src/pal/tests/palsuite/file_io/GetCurrentDirectoryW/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetCurrentDirectoryW/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/file_io/GetCurrentDirectoryW/test1/CMakeLists.txt b/src/pal/tests/palsuite/file_io/GetCurrentDirectoryW/test1/CMakeLists.txt
new file mode 100644
index 0000000000..ed8419926c
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetCurrentDirectoryW/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ GetCurrentDirectoryW.c
+)
+
+add_executable(paltest_getcurrentdirectoryw_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getcurrentdirectoryw_test1 coreclrpal)
+
+target_link_libraries(paltest_getcurrentdirectoryw_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/GetCurrentDirectoryW/test1/GetCurrentDirectoryW.c b/src/pal/tests/palsuite/file_io/GetCurrentDirectoryW/test1/GetCurrentDirectoryW.c
new file mode 100644
index 0000000000..4f4697b0a2
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetCurrentDirectoryW/test1/GetCurrentDirectoryW.c
@@ -0,0 +1,106 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: GetCurrentDirectoryW.c (test 1)
+**
+** Purpose: Tests the PAL implementation of the GetCurrentDirectoryW function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ DWORD dwRc = 0;
+ DWORD dwRc2 = 0;
+ WCHAR szwReturnedPath[_MAX_PATH+1];
+ WCHAR szwCurrentDir[_MAX_PATH+1];
+ WCHAR szwFileName[_MAX_PATH] = {'b','l','a','h','\0'};
+ LPWSTR pPathPtr;
+ size_t nCount = 0;
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ /* use GetFullPathName to to get the current path by stripping
+ * the file name off the end */
+ memset(szwReturnedPath, 0, sizeof(WCHAR)*(_MAX_PATH+1));
+ dwRc = GetFullPathNameW(szwFileName, _MAX_PATH, szwReturnedPath, &pPathPtr);
+ if (dwRc == 0)
+ {
+ /* GetFullPathName failed */
+ Fail("GetCurrentDirectoryW: ERROR -> GetFullPathNameW failed "
+ "with error code: %ld.\n", GetLastError());
+ }
+ else if(dwRc >_MAX_PATH)
+ {
+ Fail("GetCurrentDirectoryW: ERROR -> The path name GetFullPathNameW "
+ "returned is longer than _MAX_PATH characters.\n");
+ }
+
+ /* strip the file name from the full path to get the current path */
+ nCount = wcslen(szwReturnedPath) - wcslen(szwFileName) - 1;
+ memset(szwCurrentDir, 0, sizeof(WCHAR)*(_MAX_PATH+1));
+ memcpy(szwCurrentDir, szwReturnedPath, nCount*sizeof(WCHAR));
+
+ /* compare the results of GetCurrentDirectoryW with the above */
+ memset(szwReturnedPath, 0, sizeof(WCHAR)*(_MAX_PATH+1));
+ dwRc = GetCurrentDirectoryW((sizeof(WCHAR)*(_MAX_PATH+1)), szwReturnedPath);
+ if (dwRc == 0)
+ {
+ Fail("GetCurrentDirectoryW: ERROR -> GetCurrentDirectoryW failed "
+ "with error code: %ld.\n", GetLastError());
+ }
+ else if(dwRc >_MAX_PATH)
+ {
+ Fail("GetCurrentDirectoryW: ERROR -> The path name "
+ "returned is longer than _MAX_PATH characters.\n");
+ }
+
+ /* check to see whether the length of the returned string is equal to
+ * the DWORD returned by GetCurrentDirectoryW.
+ */
+ if(wcslen(szwReturnedPath) != dwRc)
+ {
+ Fail("GetCurrentDirectoryW: ERROR -> The Length of the path name "
+ "returned \"%u\" is not equal to the return value of the "
+ "function \"%u\".\n" , wcslen(szwReturnedPath), dwRc);
+ }
+
+
+
+ /* test case the passed buffer size is not big enough
+ * function should return the size required + 1 for a terminating null character
+ */
+
+ /* good buffer size */
+ dwRc = GetCurrentDirectoryW((sizeof(WCHAR)*(_MAX_PATH+1)), szwReturnedPath);
+
+ /* small buffer (0 size)*/
+ dwRc2 = GetCurrentDirectoryW(0, szwReturnedPath);
+ if (dwRc2 != (dwRc+1) )
+ {
+ Fail("GetCurrentDirectoryW: ERROR -> failed to give the correct "
+ "return value when passed a buffer not big enough. "
+ "Expected %u while result is %u ",(dwRc+1),dwRc2);
+
+ }
+
+ if (wcsncmp(szwReturnedPath, szwCurrentDir, wcslen(szwReturnedPath)) != 0)
+ {
+ Fail("GetCurrentDirectoryW: ERROR -> The computed and returned "
+ "directories do not compare.\n");
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/file_io/GetCurrentDirectoryW/test1/testinfo.dat b/src/pal/tests/palsuite/file_io/GetCurrentDirectoryW/test1/testinfo.dat
new file mode 100644
index 0000000000..4443a79833
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetCurrentDirectoryW/test1/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = GetCurrentDirectoryW
+Name = Test for GetCurrentDirectoryW (test 1)
+Type = DEFAULT
+EXE1 = getcurrentdirectoryw
+Description
+= Compute the current directory and compare with the results
+= from GetCurrentDirectoryW
+
diff --git a/src/pal/tests/palsuite/file_io/GetDiskFreeSpaceW/CMakeLists.txt b/src/pal/tests/palsuite/file_io/GetDiskFreeSpaceW/CMakeLists.txt
new file mode 100644
index 0000000000..ef14ea5352
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetDiskFreeSpaceW/CMakeLists.txt
@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+
diff --git a/src/pal/tests/palsuite/file_io/GetDiskFreeSpaceW/test1/CMakeLists.txt b/src/pal/tests/palsuite/file_io/GetDiskFreeSpaceW/test1/CMakeLists.txt
new file mode 100644
index 0000000000..6b06376233
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetDiskFreeSpaceW/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ GetDiskFreeSpaceW.c
+)
+
+add_executable(paltest_getdiskfreespacew_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getdiskfreespacew_test1 coreclrpal)
+
+target_link_libraries(paltest_getdiskfreespacew_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/GetDiskFreeSpaceW/test1/GetDiskFreeSpaceW.c b/src/pal/tests/palsuite/file_io/GetDiskFreeSpaceW/test1/GetDiskFreeSpaceW.c
new file mode 100644
index 0000000000..c1445f654f
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetDiskFreeSpaceW/test1/GetDiskFreeSpaceW.c
@@ -0,0 +1,94 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: GetDiskFreeSpaceW.c (test 1)
+**
+** Purpose: Tests the PAL implementation of the GetDiskFreeSpaceW function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ DWORD dwSectorsPerCluster; /* sectors per cluster */
+ DWORD dwBytesPerSector; /* bytes per sector */
+ DWORD dwSectorsPerCluster_02; /* sectors per cluster */
+ DWORD dwBytesPerSector_02; /* bytes per sector */
+ DWORD dwNumberOfFreeClusters; /* free clusters */
+ DWORD dwTotalNumberOfClusters; /* total clusters */
+ BOOL bRc = FALSE;
+ WCHAR szwRootPath[10] = {'/','\0'};
+
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ /* test the NULL option which translates to the current drive */
+ bRc = GetDiskFreeSpaceW(NULL,
+ &dwSectorsPerCluster,
+ &dwBytesPerSector,
+ &dwNumberOfFreeClusters,
+ &dwTotalNumberOfClusters);
+ if (bRc != TRUE)
+ {
+ Fail("GetDiskFreeSpaceW: ERROR -> Failed with error code: %ld\n",
+ GetLastError());
+ }
+ else if (dwSectorsPerCluster == 0)
+ {
+ Fail("GetDiskFreeSpaceW: ERROR -> dwSectorsPerCluster returned 0\n");
+ }
+ else if (dwBytesPerSector == 0)
+ {
+ Fail("GetDiskFreeSpaceW: ERROR -> dwBytesPerSector returned 0\n");
+ }
+
+ /* test the root directory to the current drive */
+ bRc = GetDiskFreeSpaceW(szwRootPath,
+ &dwSectorsPerCluster_02,
+ &dwBytesPerSector_02,
+ &dwNumberOfFreeClusters,
+ &dwTotalNumberOfClusters);
+ if (bRc != TRUE)
+ {
+ Fail("GetDiskFreeSpaceW: ERROR -> Failed with error code: %ld\n",
+ GetLastError());
+ }
+ else if (dwSectorsPerCluster == 0)
+ {
+ Fail("GetDiskFreeSpaceW: ERROR -> dwSectorsPerCluster returned 0\n");
+ }
+ else if (dwBytesPerSector == 0)
+ {
+ Fail("GetDiskFreeSpaceW: ERROR -> dwBytesPerSector returned 0\n");
+ }
+ /*
+ ** make sure the values returned for NULL path and root path
+ ** are the same
+ */
+ else if (dwSectorsPerCluster_02 != dwSectorsPerCluster)
+ {
+ Fail("GetDiskFreeSpaceW: ERROR -> dwSectorsPerCluster for NULL path "
+ "(%u) should have been the same as the root path (%u).\n",
+ dwSectorsPerCluster,
+ dwSectorsPerCluster_02);
+ }
+ else if (dwBytesPerSector_02 != dwBytesPerSector)
+ {
+ Fail("GetDiskFreeSpaceW: ERROR -> dwBytesPerSector for NULL path "
+ "(%u) should have been the same as the root path (%u).\n",
+ dwBytesPerSector,
+ dwBytesPerSector_02);
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/file_io/GetDiskFreeSpaceW/test1/testinfo.dat b/src/pal/tests/palsuite/file_io/GetDiskFreeSpaceW/test1/testinfo.dat
new file mode 100644
index 0000000000..61b0e55fae
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetDiskFreeSpaceW/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = GetDiskFreeSpaceW
+Name = Positive Test for GetDiskFreeSpaceW (test 1)
+Type = DEFAULT
+EXE1 = getdiskfreespacew
+Description
+= Test GetDiskFreeSpaceW. lpNumberOfFreeClusters and
+= lpTotalNumberOfClusters are to be ignored
diff --git a/src/pal/tests/palsuite/file_io/GetDiskFreeSpaceW/test2/CMakeLists.txt b/src/pal/tests/palsuite/file_io/GetDiskFreeSpaceW/test2/CMakeLists.txt
new file mode 100644
index 0000000000..5660b39e1a
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetDiskFreeSpaceW/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ getdiskfreespacew.c
+)
+
+add_executable(paltest_getdiskfreespacew_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getdiskfreespacew_test2 coreclrpal)
+
+target_link_libraries(paltest_getdiskfreespacew_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/GetDiskFreeSpaceW/test2/getdiskfreespacew.c b/src/pal/tests/palsuite/file_io/GetDiskFreeSpaceW/test2/getdiskfreespacew.c
new file mode 100644
index 0000000000..83dcb54b51
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetDiskFreeSpaceW/test2/getdiskfreespacew.c
@@ -0,0 +1,65 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: GetDiskFreeSpaceW.c (test 2)
+**
+** Purpose: Tests the PAL implementation of the GetDiskFreeSpaceW
+** function on valid non-root paths.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ DWORD dwSectorsPerCluster; /* sectors per cluster */
+ DWORD dwBytesPerSector; /* bytes per sector */
+ DWORD dwNumberOfFreeClusters; /* free clusters */
+ DWORD dwTotalNumberOfClusters; /* total clusters */
+ BOOL bRc = FALSE;
+ WCHAR szwCurrentPath[MAX_LONGPATH];
+
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ /* get the current directory so we are sure to have a valid path */
+ if (!GetCurrentDirectoryW(MAX_LONGPATH, szwCurrentPath))
+ {
+ Fail("GetDiskFreeSpaceW: ERROR -> GetCurrentDirectoryW failed with "
+ "error code: %u.\n",
+ GetLastError());
+ }
+
+ /* test the current path*/
+ bRc = GetDiskFreeSpaceW(szwCurrentPath,
+ &dwSectorsPerCluster,
+ &dwBytesPerSector,
+ &dwNumberOfFreeClusters,
+ &dwTotalNumberOfClusters);
+ if (bRc != TRUE)
+ {
+ Fail("GetDiskFreeSpaceW: ERROR -> Failed with error code: %u for "
+ "the path \"%S\".\n",
+ GetLastError(),
+ szwCurrentPath);
+ }
+ else if (dwSectorsPerCluster == 0)
+ {
+ Fail("GetDiskFreeSpaceW: ERROR -> dwSectorsPerCluster returned 0\n");
+ }
+ else if (dwBytesPerSector == 0)
+ {
+ Fail("GetDiskFreeSpaceW: ERROR -> dwBytesPerSector returned 0\n");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/file_io/GetDiskFreeSpaceW/test2/testinfo.dat b/src/pal/tests/palsuite/file_io/GetDiskFreeSpaceW/test2/testinfo.dat
new file mode 100644
index 0000000000..0a687240ea
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetDiskFreeSpaceW/test2/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = GetDiskFreeSpaceW
+Name = Positive Test for GetDiskFreeSpaceW (test 2)
+Type = DEFAULT
+EXE1 = getdiskfreespacew
+Description
+= Test GetDiskFreeSpaceW with valid non-root paths
diff --git a/src/pal/tests/palsuite/file_io/GetFileAttributesA/CMakeLists.txt b/src/pal/tests/palsuite/file_io/GetFileAttributesA/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileAttributesA/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/file_io/GetFileAttributesA/test1/.hidden_directory/CMakeLists.txt b/src/pal/tests/palsuite/file_io/GetFileAttributesA/test1/.hidden_directory/CMakeLists.txt
new file mode 100644
index 0000000000..a8fd227402
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileAttributesA/test1/.hidden_directory/CMakeLists.txt
@@ -0,0 +1,2 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
diff --git a/src/pal/tests/palsuite/file_io/GetFileAttributesA/test1/.hidden_directory/keepme b/src/pal/tests/palsuite/file_io/GetFileAttributesA/test1/.hidden_directory/keepme
new file mode 100644
index 0000000000..31eade7217
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileAttributesA/test1/.hidden_directory/keepme
@@ -0,0 +1 @@
+Make CVS checkout this directory even with -p option. \ No newline at end of file
diff --git a/src/pal/tests/palsuite/file_io/GetFileAttributesA/test1/.hidden_file b/src/pal/tests/palsuite/file_io/GetFileAttributesA/test1/.hidden_file
new file mode 100644
index 0000000000..0d1ac31cfa
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileAttributesA/test1/.hidden_file
@@ -0,0 +1 @@
+Hidden file \ No newline at end of file
diff --git a/src/pal/tests/palsuite/file_io/GetFileAttributesA/test1/.hidden_ro_directory/CMakeLists.txt b/src/pal/tests/palsuite/file_io/GetFileAttributesA/test1/.hidden_ro_directory/CMakeLists.txt
new file mode 100644
index 0000000000..a8fd227402
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileAttributesA/test1/.hidden_ro_directory/CMakeLists.txt
@@ -0,0 +1,2 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
diff --git a/src/pal/tests/palsuite/file_io/GetFileAttributesA/test1/.hidden_ro_directory/keepme b/src/pal/tests/palsuite/file_io/GetFileAttributesA/test1/.hidden_ro_directory/keepme
new file mode 100644
index 0000000000..31eade7217
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileAttributesA/test1/.hidden_ro_directory/keepme
@@ -0,0 +1 @@
+Make CVS checkout this directory even with -p option. \ No newline at end of file
diff --git a/src/pal/tests/palsuite/file_io/GetFileAttributesA/test1/.hidden_ro_file b/src/pal/tests/palsuite/file_io/GetFileAttributesA/test1/.hidden_ro_file
new file mode 100644
index 0000000000..8f78fcb436
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileAttributesA/test1/.hidden_ro_file
@@ -0,0 +1 @@
+.hidden_ro_file
diff --git a/src/pal/tests/palsuite/file_io/GetFileAttributesA/test1/CMakeLists.txt b/src/pal/tests/palsuite/file_io/GetFileAttributesA/test1/CMakeLists.txt
new file mode 100644
index 0000000000..6bf9818e86
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileAttributesA/test1/CMakeLists.txt
@@ -0,0 +1,26 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ GetFileAttributesA.c
+)
+
+add_executable(paltest_getfileattributesa_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getfileattributesa_test1 coreclrpal)
+
+target_link_libraries(paltest_getfileattributesa_test1
+ pthread
+ m
+ coreclrpal
+)
+add_subdirectory(.hidden_directory)
+add_subdirectory(.hidden_ro_directory)
+add_subdirectory(normal_test_directory)
+add_subdirectory(no_directory)
+add_subdirectory(ro_test_directory)
+add_subdirectory(rw_directory)
+
diff --git a/src/pal/tests/palsuite/file_io/GetFileAttributesA/test1/GetFileAttributesA.c b/src/pal/tests/palsuite/file_io/GetFileAttributesA/test1/GetFileAttributesA.c
new file mode 100644
index 0000000000..ff6bd0b8e0
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileAttributesA/test1/GetFileAttributesA.c
@@ -0,0 +1,340 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================================
+**
+** Source: GetFileAttributesA.c
+**
+** Purpose: Tests the PAL implementation of the GetFileAttributesA function by
+** checking the attributes of:
+** - a normal directory and file
+** - a read only directory and file
+** - a read write directory and file
+** - a hidden directory and file
+** - a read only hidden directory and file
+** - a directory and a file with no attributes
+** - an invalid file name
+**
+**
+**===========================================================================*/
+#include <palsuite.h>
+
+const int TYPE_DIR = 0;
+const int TYPE_FILE = 1;
+/* Structure defining a test case */
+typedef struct
+{
+ char *name; /* name of the file/directory */
+ DWORD expectedAttribs; /* expected attributes */
+ HANDLE hFile; /* Handle to the file */
+ int isFile; /* is file (1) or dir (0) */
+}TestCaseFile;
+
+typedef struct
+{
+ char *name; /* name of the file/directory */
+ DWORD expectedAttribs; /* expected attributes */
+ HANDLE hFile; /* Handle to the file */
+ int isFile; /* is file (1) or dir (0) */
+}TestCaseDir;
+
+DWORD desiredAccessFile = GENERIC_READ | GENERIC_WRITE;
+DWORD shareModeFile = FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE;
+LPSECURITY_ATTRIBUTES lpAttrFile = NULL;
+DWORD dwCreationDispFile = CREATE_NEW;
+DWORD dwFlagsAttribFile = FILE_ATTRIBUTE_NORMAL;
+HANDLE hTemplateFile = NULL;
+
+int numFileTests = 6;
+TestCaseFile gfaTestsFile[6]; /* GetFileAttributes tests list */
+
+int numDirTests = 6;
+TestCaseDir gfaTestsDir[6]; /* GetFileAttributes tests list */
+
+BOOL CleanUpFiles()
+{
+ DWORD dwAtt;
+ int i;
+ BOOL result = TRUE;
+ for (i = 0; i < numFileTests -1 ; i++ )
+ {
+ dwAtt = GetFileAttributesA(gfaTestsFile[i].name);
+
+ if( dwAtt != INVALID_FILE_ATTRIBUTES )
+ {
+ //Trace("Files iteration %d\n", i);
+ if(!SetFileAttributesA (gfaTestsFile[i].name, FILE_ATTRIBUTE_NORMAL))
+ {
+ result = FALSE;
+ Trace("ERROR:%d: Error setting attributes [%s][%d]\n", GetLastError(), gfaTestsFile[i].name, FILE_ATTRIBUTE_NORMAL);
+ }
+
+ if(!DeleteFileA (gfaTestsFile[i].name))
+ {
+ result = FALSE;
+ Trace("ERROR:%d: Error deleting file [%s][%d]\n", GetLastError(), gfaTestsFile[i].name, dwAtt);
+ }
+
+ }
+ }
+// Trace("Value of result is %d\n", result);
+ return result;
+}
+BOOL SetUpFiles()
+{
+ int i = 0;
+ BOOL result = TRUE;
+ for (i = 0; i < numFileTests -1; i++ )
+ {
+ gfaTestsFile[i].hFile = CreateFile(gfaTestsFile[i].name,
+ desiredAccessFile,
+ shareModeFile,
+ lpAttrFile,
+ dwCreationDispFile,
+ dwFlagsAttribFile,
+ hTemplateFile);
+
+ if( gfaTestsFile[i].hFile == NULL )
+ {
+ Fail("Error while creating files for iteration %d\n", i);
+ }
+
+ if(!SetFileAttributesA (gfaTestsFile[i].name, gfaTestsFile[i].expectedAttribs))
+ {
+ result = FALSE;
+ Trace("ERROR:%d: Error setting attributes [%s][%d]\n", GetLastError(), gfaTestsFile[i].name, gfaTestsFile[i].expectedAttribs);
+ }
+ }
+
+ return result;
+}
+
+BOOL CleanUpDirs()
+{
+ DWORD dwAtt;
+ int i;
+ BOOL result = TRUE;
+ for (i = 0; i < numDirTests -1 ; i++ )
+ {
+ dwAtt = GetFileAttributesA(gfaTestsDir[i].name);
+
+ if( dwAtt != INVALID_FILE_ATTRIBUTES )
+ {
+
+ if(!SetFileAttributesA (gfaTestsDir[i].name, FILE_ATTRIBUTE_DIRECTORY))
+ {
+ result = FALSE;
+ Trace("ERROR:%d: Error setting attributes [%s][%d]\n", GetLastError(), gfaTestsDir[i].name, (FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_DIRECTORY));
+ }
+
+ if(!RemoveDirectoryA (gfaTestsDir[i].name))
+ {
+ result = FALSE;
+ Trace("ERROR:%d: Error deleting file [%s][%d]\n", GetLastError(), gfaTestsDir[i].name, dwAtt);
+ }
+
+ }
+ }
+
+ return result;
+}
+
+BOOL SetUpDirs()
+{
+ int i = 0;
+ BOOL result = TRUE;
+ DWORD ret = 0;
+ for (i = 0; i < numDirTests - 1 ; i++ )
+ {
+ result = CreateDirectory(gfaTestsDir[i].name,
+ NULL);
+
+ if(!result )
+ {
+ result = FALSE;
+ Fail("Error while creating directory for iteration %d\n", i);
+ }
+
+ if(!SetFileAttributesA (gfaTestsDir[i].name, gfaTestsDir[i].expectedAttribs))
+ {
+ result = FALSE;
+ Trace("ERROR:%d: Error setting attributes [%s][%d]\n", GetLastError(), gfaTestsDir[i].name, gfaTestsDir[i].expectedAttribs);
+ }
+
+ ret = GetFileAttributesA (gfaTestsDir[i].name);
+ if(ret != gfaTestsDir[i].expectedAttribs)
+ {
+ result = FALSE;
+ Trace("ERROR: Error setting attributes [%s][%d]\n", gfaTestsDir[i].name, gfaTestsDir[i].expectedAttribs);
+ }
+ //Trace("Setup Dir setting attr [%d], returned [%d]\n", gfaTestsDir[i].expectedAttribs, ret);
+
+ }
+ //Trace("Setup dirs returning %d\n", result);
+ return result;
+}
+int __cdecl main(int argc, char **argv)
+{
+ int i;
+ BOOL bFailed = FALSE;
+ DWORD result;
+
+ char * NormalDirectoryName = "normal_test_directory";
+ char * ReadOnlyDirectoryName = "ro_test_directory";
+ char * ReadWriteDirectoryName = "rw_directory";
+ char * HiddenDirectoryName = ".hidden_directory";
+ char * HiddenReadOnlyDirectoryName = ".hidden_ro_directory";
+ char * NoDirectoryName = "no_directory";
+
+ char * NormalFileName = "normal_test_file";
+ char * ReadOnlyFileName = "ro_test_file";
+ char * ReadWriteFileName = "rw_file";
+ char * HiddenFileName = ".hidden_file";
+ char * HiddenReadOnlyFileName = ".hidden_ro_file";
+ char * NotReallyAFileName = "not_really_a_file";
+
+ /* Tests on directory */
+ gfaTestsDir[0].name = NormalDirectoryName;
+ gfaTestsDir[0].expectedAttribs = FILE_ATTRIBUTE_DIRECTORY;
+ gfaTestsDir[0].isFile = TYPE_DIR;
+
+ gfaTestsDir[1].name = ReadOnlyDirectoryName;
+ gfaTestsDir[1].expectedAttribs = FILE_ATTRIBUTE_DIRECTORY |
+ FILE_ATTRIBUTE_READONLY;
+ gfaTestsDir[1].isFile = TYPE_DIR;
+
+ gfaTestsDir[2].name = ReadWriteDirectoryName;
+ gfaTestsDir[2].expectedAttribs = FILE_ATTRIBUTE_DIRECTORY;
+ gfaTestsDir[2].isFile = TYPE_DIR;
+
+ gfaTestsDir[3].name = HiddenDirectoryName;
+ gfaTestsDir[3].expectedAttribs = FILE_ATTRIBUTE_DIRECTORY; //|
+ //FILE_ATTRIBUTE_HIDDEN;
+ gfaTestsDir[3].isFile = TYPE_DIR;
+
+ gfaTestsDir[4].name = HiddenReadOnlyDirectoryName;
+ gfaTestsDir[4].expectedAttribs = FILE_ATTRIBUTE_DIRECTORY |
+ FILE_ATTRIBUTE_READONLY; //|
+ //FILE_ATTRIBUTE_HIDDEN;
+ gfaTestsDir[4].isFile = TYPE_DIR;
+
+ gfaTestsDir[5].name = NoDirectoryName;
+ gfaTestsDir[5].expectedAttribs = INVALID_FILE_ATTRIBUTES;
+ gfaTestsDir[5].isFile = TYPE_DIR;
+
+ /* Tests on file */
+ gfaTestsFile[0].name = NormalFileName;
+ gfaTestsFile[0].expectedAttribs = FILE_ATTRIBUTE_NORMAL;
+ gfaTestsFile[0].isFile = TYPE_FILE;
+
+
+ gfaTestsFile[1].name = ReadOnlyFileName;
+ gfaTestsFile[1].expectedAttribs = FILE_ATTRIBUTE_READONLY;
+ gfaTestsFile[1].isFile = TYPE_FILE;
+
+ gfaTestsFile[2].name = ReadWriteFileName;
+ gfaTestsFile[2].expectedAttribs = FILE_ATTRIBUTE_NORMAL;
+ gfaTestsFile[2].isFile = TYPE_FILE;
+
+ gfaTestsFile[3].name = HiddenFileName;
+ gfaTestsFile[3].expectedAttribs = FILE_ATTRIBUTE_NORMAL; //FILE_ATTRIBUTE_HIDDEN;
+ gfaTestsFile[3].isFile = TYPE_FILE;
+
+ gfaTestsFile[4].name = HiddenReadOnlyFileName;
+ gfaTestsFile[4].expectedAttribs = FILE_ATTRIBUTE_READONLY; //|
+ //FILE_ATTRIBUTE_HIDDEN;
+ gfaTestsFile[4].isFile = TYPE_FILE;
+
+
+ gfaTestsFile[5].name = NotReallyAFileName;
+ gfaTestsFile[5].expectedAttribs = INVALID_FILE_ATTRIBUTES;
+ gfaTestsFile[5].isFile = TYPE_FILE;
+
+ /* Initialize PAL environment */
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ if(!CleanUpFiles())
+ {
+ Fail("GetFileAttributesA: Pre-Clean Up Files Failed\n");
+ }
+
+ if(0 == SetUpFiles())
+ {
+ Fail("GetFileAttributesA: SetUp Files Failed\n");
+ }
+
+ if(!CleanUpDirs())
+ {
+ Fail("GetFileAttributesA: Pre-Clean Up Directories Failed\n");
+ }
+
+ if(!SetUpDirs())
+ {
+ Fail("GetFileAttributesA: SetUp Directories Failed\n");
+ }
+
+ /*
+ * Go through all the test cases above,
+ * call GetFileAttributesA on the name and
+ * make sure the return value is the one expected
+ */
+ for( i = 0; i < numFileTests; i++ )
+ {
+ result = GetFileAttributesA(gfaTestsFile[i].name);
+
+ if( result != gfaTestsFile[i].expectedAttribs )
+ {
+ bFailed = TRUE;
+
+ Trace("ERROR: GetFileAttributesA Test#%u on %s "
+ "returned %u instead of %u. \n",
+ i,
+ gfaTestsFile[i].name,
+ result,
+ gfaTestsFile[i].expectedAttribs);
+
+ }
+ }
+
+
+ for( i = 0; i < numDirTests; i++ )
+ {
+ result = GetFileAttributesA(gfaTestsDir[i].name);
+
+ if( result != gfaTestsDir[i].expectedAttribs )
+ {
+ bFailed = TRUE;
+
+ Trace("ERROR: GetFileAttributesA on Directories Test#%u on %s "
+ "returned %u instead of %u. \n",
+ i,
+ gfaTestsDir[i].name,
+ result,
+ gfaTestsDir[i].expectedAttribs);
+
+ }
+ }
+
+ if(!CleanUpFiles())
+ {
+ Fail("GetFileAttributesA: Post-Clean Up Files Failed\n");
+ }
+
+ if(!CleanUpDirs())
+ {
+ Fail("GetFileAttributesA: Post-Clean Up Directories Failed\n");
+ }
+
+ /* If any errors, just call Fail() */
+ if( bFailed )
+ {
+ Fail("");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/file_io/GetFileAttributesA/test1/no_directory/CMakeLists.txt b/src/pal/tests/palsuite/file_io/GetFileAttributesA/test1/no_directory/CMakeLists.txt
new file mode 100644
index 0000000000..a8fd227402
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileAttributesA/test1/no_directory/CMakeLists.txt
@@ -0,0 +1,2 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
diff --git a/src/pal/tests/palsuite/file_io/GetFileAttributesA/test1/no_directory/keepme b/src/pal/tests/palsuite/file_io/GetFileAttributesA/test1/no_directory/keepme
new file mode 100644
index 0000000000..31eade7217
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileAttributesA/test1/no_directory/keepme
@@ -0,0 +1 @@
+Make CVS checkout this directory even with -p option. \ No newline at end of file
diff --git a/src/pal/tests/palsuite/file_io/GetFileAttributesA/test1/no_file b/src/pal/tests/palsuite/file_io/GetFileAttributesA/test1/no_file
new file mode 100644
index 0000000000..3d631e8103
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileAttributesA/test1/no_file
@@ -0,0 +1 @@
+No attribs file \ No newline at end of file
diff --git a/src/pal/tests/palsuite/file_io/GetFileAttributesA/test1/normal_test_directory/CMakeLists.txt b/src/pal/tests/palsuite/file_io/GetFileAttributesA/test1/normal_test_directory/CMakeLists.txt
new file mode 100644
index 0000000000..a8fd227402
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileAttributesA/test1/normal_test_directory/CMakeLists.txt
@@ -0,0 +1,2 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
diff --git a/src/pal/tests/palsuite/file_io/GetFileAttributesA/test1/normal_test_directory/keepme b/src/pal/tests/palsuite/file_io/GetFileAttributesA/test1/normal_test_directory/keepme
new file mode 100644
index 0000000000..31eade7217
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileAttributesA/test1/normal_test_directory/keepme
@@ -0,0 +1 @@
+Make CVS checkout this directory even with -p option. \ No newline at end of file
diff --git a/src/pal/tests/palsuite/file_io/GetFileAttributesA/test1/normal_test_file b/src/pal/tests/palsuite/file_io/GetFileAttributesA/test1/normal_test_file
new file mode 100644
index 0000000000..a6e1e627a8
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileAttributesA/test1/normal_test_file
@@ -0,0 +1,6 @@
+file_io
+CopyFileW
+Positive Test for CopyFileW
+test the CopyFileW function
+DEFAULT
+CopyFileW \ No newline at end of file
diff --git a/src/pal/tests/palsuite/file_io/GetFileAttributesA/test1/ro_test_directory/CMakeLists.txt b/src/pal/tests/palsuite/file_io/GetFileAttributesA/test1/ro_test_directory/CMakeLists.txt
new file mode 100644
index 0000000000..a8fd227402
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileAttributesA/test1/ro_test_directory/CMakeLists.txt
@@ -0,0 +1,2 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
diff --git a/src/pal/tests/palsuite/file_io/GetFileAttributesA/test1/ro_test_directory/keepme b/src/pal/tests/palsuite/file_io/GetFileAttributesA/test1/ro_test_directory/keepme
new file mode 100644
index 0000000000..31eade7217
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileAttributesA/test1/ro_test_directory/keepme
@@ -0,0 +1 @@
+Make CVS checkout this directory even with -p option. \ No newline at end of file
diff --git a/src/pal/tests/palsuite/file_io/GetFileAttributesA/test1/ro_test_file b/src/pal/tests/palsuite/file_io/GetFileAttributesA/test1/ro_test_file
new file mode 100644
index 0000000000..a6e1e627a8
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileAttributesA/test1/ro_test_file
@@ -0,0 +1,6 @@
+file_io
+CopyFileW
+Positive Test for CopyFileW
+test the CopyFileW function
+DEFAULT
+CopyFileW \ No newline at end of file
diff --git a/src/pal/tests/palsuite/file_io/GetFileAttributesA/test1/rw_directory/CMakeLists.txt b/src/pal/tests/palsuite/file_io/GetFileAttributesA/test1/rw_directory/CMakeLists.txt
new file mode 100644
index 0000000000..a8fd227402
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileAttributesA/test1/rw_directory/CMakeLists.txt
@@ -0,0 +1,2 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
diff --git a/src/pal/tests/palsuite/file_io/GetFileAttributesA/test1/rw_directory/keepme b/src/pal/tests/palsuite/file_io/GetFileAttributesA/test1/rw_directory/keepme
new file mode 100644
index 0000000000..31eade7217
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileAttributesA/test1/rw_directory/keepme
@@ -0,0 +1 @@
+Make CVS checkout this directory even with -p option. \ No newline at end of file
diff --git a/src/pal/tests/palsuite/file_io/GetFileAttributesA/test1/rw_file b/src/pal/tests/palsuite/file_io/GetFileAttributesA/test1/rw_file
new file mode 100644
index 0000000000..39d66f0365
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileAttributesA/test1/rw_file
@@ -0,0 +1 @@
+Read Write file \ No newline at end of file
diff --git a/src/pal/tests/palsuite/file_io/GetFileAttributesA/test1/testinfo.dat b/src/pal/tests/palsuite/file_io/GetFileAttributesA/test1/testinfo.dat
new file mode 100644
index 0000000000..2053220bf3
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileAttributesA/test1/testinfo.dat
@@ -0,0 +1,20 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+
+Section = file_io
+
+Function = GetFileAttributesA
+
+Name = Positive Test for GetFileAttributesA
+
+TYPE = DEFAULT
+
+EXE1 = getfileattributesa
+
+Description
+
+= Test the GetFileAttributesA function
+
diff --git a/src/pal/tests/palsuite/file_io/GetFileAttributesExW/CMakeLists.txt b/src/pal/tests/palsuite/file_io/GetFileAttributesExW/CMakeLists.txt
new file mode 100644
index 0000000000..ef14ea5352
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileAttributesExW/CMakeLists.txt
@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+
diff --git a/src/pal/tests/palsuite/file_io/GetFileAttributesExW/test1/.hidden_directory/CMakeLists.txt b/src/pal/tests/palsuite/file_io/GetFileAttributesExW/test1/.hidden_directory/CMakeLists.txt
new file mode 100644
index 0000000000..a8fd227402
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileAttributesExW/test1/.hidden_directory/CMakeLists.txt
@@ -0,0 +1,2 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
diff --git a/src/pal/tests/palsuite/file_io/GetFileAttributesExW/test1/.hidden_directory/anchor.txt b/src/pal/tests/palsuite/file_io/GetFileAttributesExW/test1/.hidden_directory/anchor.txt
new file mode 100644
index 0000000000..9a277fa04e
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileAttributesExW/test1/.hidden_directory/anchor.txt
@@ -0,0 +1,2 @@
+This file is here so this directory gets checked out even with the -P
+option. \ No newline at end of file
diff --git a/src/pal/tests/palsuite/file_io/GetFileAttributesExW/test1/.hidden_file b/src/pal/tests/palsuite/file_io/GetFileAttributesExW/test1/.hidden_file
new file mode 100644
index 0000000000..0d1ac31cfa
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileAttributesExW/test1/.hidden_file
@@ -0,0 +1 @@
+Hidden file \ No newline at end of file
diff --git a/src/pal/tests/palsuite/file_io/GetFileAttributesExW/test1/CMakeLists.txt b/src/pal/tests/palsuite/file_io/GetFileAttributesExW/test1/CMakeLists.txt
new file mode 100644
index 0000000000..2d299d82e5
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileAttributesExW/test1/CMakeLists.txt
@@ -0,0 +1,23 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_getfileattributesexw_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getfileattributesexw_test1 coreclrpal)
+
+target_link_libraries(paltest_getfileattributesexw_test1
+ pthread
+ m
+ coreclrpal
+)
+add_subdirectory(.hidden_directory)
+add_subdirectory(normal_test_directory)
+add_subdirectory(ro_test_directory)
+
diff --git a/src/pal/tests/palsuite/file_io/GetFileAttributesExW/test1/normal_test_directory/CMakeLists.txt b/src/pal/tests/palsuite/file_io/GetFileAttributesExW/test1/normal_test_directory/CMakeLists.txt
new file mode 100644
index 0000000000..a8fd227402
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileAttributesExW/test1/normal_test_directory/CMakeLists.txt
@@ -0,0 +1,2 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
diff --git a/src/pal/tests/palsuite/file_io/GetFileAttributesExW/test1/normal_test_directory/keepme b/src/pal/tests/palsuite/file_io/GetFileAttributesExW/test1/normal_test_directory/keepme
new file mode 100644
index 0000000000..31eade7217
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileAttributesExW/test1/normal_test_directory/keepme
@@ -0,0 +1 @@
+Make CVS checkout this directory even with -p option. \ No newline at end of file
diff --git a/src/pal/tests/palsuite/file_io/GetFileAttributesExW/test1/normal_test_file b/src/pal/tests/palsuite/file_io/GetFileAttributesExW/test1/normal_test_file
new file mode 100644
index 0000000000..ab7622ffb1
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileAttributesExW/test1/normal_test_file
@@ -0,0 +1,6 @@
+file_io
+CopyFileW
+Positive Test for CopyFileW
+test the CopyFileW function
+DEFAULT
+CopyFileW \ No newline at end of file
diff --git a/src/pal/tests/palsuite/file_io/GetFileAttributesExW/test1/ro_test_directory/CMakeLists.txt b/src/pal/tests/palsuite/file_io/GetFileAttributesExW/test1/ro_test_directory/CMakeLists.txt
new file mode 100644
index 0000000000..a8fd227402
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileAttributesExW/test1/ro_test_directory/CMakeLists.txt
@@ -0,0 +1,2 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
diff --git a/src/pal/tests/palsuite/file_io/GetFileAttributesExW/test1/ro_test_directory/keepme b/src/pal/tests/palsuite/file_io/GetFileAttributesExW/test1/ro_test_directory/keepme
new file mode 100644
index 0000000000..31eade7217
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileAttributesExW/test1/ro_test_directory/keepme
@@ -0,0 +1 @@
+Make CVS checkout this directory even with -p option. \ No newline at end of file
diff --git a/src/pal/tests/palsuite/file_io/GetFileAttributesExW/test1/ro_test_file b/src/pal/tests/palsuite/file_io/GetFileAttributesExW/test1/ro_test_file
new file mode 100644
index 0000000000..ab7622ffb1
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileAttributesExW/test1/ro_test_file
@@ -0,0 +1,6 @@
+file_io
+CopyFileW
+Positive Test for CopyFileW
+test the CopyFileW function
+DEFAULT
+CopyFileW \ No newline at end of file
diff --git a/src/pal/tests/palsuite/file_io/GetFileAttributesExW/test1/test1.c b/src/pal/tests/palsuite/file_io/GetFileAttributesExW/test1/test1.c
new file mode 100644
index 0000000000..7a622b628c
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileAttributesExW/test1/test1.c
@@ -0,0 +1,227 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test1.c
+**
+** Purpose: Tests the PAL implementation of the GetFileAttributesExW function.
+** Call the function on a normal directory and file and a read-only directory
+** and file and a hidden file and directory.
+** Ensure that the attributes returned are correct, and the
+** file times and file sizes.
+**
+**
+**===================================================================*/
+
+#define UNICODE
+#include <palsuite.h>
+
+typedef enum Item
+{
+ IS_DIR,
+ IS_FILE
+}ItemType;
+
+/*
+ This is a helper function which takes two FILETIME structures and
+ checks to see if they contain the exact same time.
+*/
+int IsEqualFileTime(FILETIME FirstTime, FILETIME SecondTime)
+{
+
+ ULONG64 TimeOne, TimeTwo;
+
+ TimeOne = ((((ULONG64)FirstTime.dwHighDateTime)<<32) |
+ ((ULONG64)FirstTime.dwLowDateTime));
+
+ TimeTwo = ((((ULONG64)SecondTime.dwHighDateTime)<<32) |
+ ((ULONG64)SecondTime.dwLowDateTime));
+
+ return(TimeOne == TimeTwo);
+}
+
+/* This function takes a structure and checks that the information
+ within the structure is correct. The 'Attribs' are the expected
+ file attributes, 'TheType' is IS_DIR or IS_FILE and the 'Name' is the
+ name of the file/directory in question.
+*/
+void VerifyInfo(WIN32_FILE_ATTRIBUTE_DATA InfoStruct,
+ DWORD Attribs, ItemType TheType, WCHAR* Name)
+{
+ HANDLE hFile;
+ FILETIME CorrectCreation, CorrectAccess, CorrectModify;
+ WCHAR CopyName[64];
+
+ wcscpy(CopyName,Name);
+ free(Name);
+
+ /* Check to see that the file attributes were recorded */
+ if(InfoStruct.dwFileAttributes != Attribs)
+ {
+ Fail("ERROR: The file attributes on the file/directory were "
+ "recorded as being %d instead of %d.\n",
+ InfoStruct.dwFileAttributes,
+ Attribs);
+ }
+
+ /* Note: We can't open a handle to a directory in windows. This
+ block of tests will only be run on files.
+ */
+ if(TheType == IS_FILE)
+ {
+
+ /* Get a handle to the file */
+ hFile = CreateFile(CopyName,
+ 0,
+ 0,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if (hFile == INVALID_HANDLE_VALUE)
+ {
+ Fail("ERROR: Could not open a handle to the file "
+ "'%S'. GetLastError() returned %d.",CopyName,
+ GetLastError());
+ }
+
+
+
+ /* Get the FileTime of the file in question */
+ if(GetFileTime(hFile, &CorrectCreation,
+ &CorrectAccess, &CorrectModify) == 0)
+ {
+ Fail("ERROR: GetFileTime failed to get the filetime of the "
+ "file. GetLastError() returned %d.",
+ GetLastError());
+ }
+
+ /* Check that the Creation, Access and Last Modified times are all
+ the same in the structure as what GetFileTime just returned.
+ */
+ if(!IsEqualFileTime(CorrectCreation, InfoStruct.ftCreationTime))
+ {
+ Fail("ERROR: The creation time of the file "
+ "does not match the creation time given from "
+ "GetFileTime.\n");
+ }
+ if(!IsEqualFileTime(CorrectAccess, InfoStruct.ftLastAccessTime))
+ {
+ Fail("ERROR: The access time of the file "
+ "does not match the access time given from "
+ "GetFileTime.\n");
+ }
+ if(!IsEqualFileTime(CorrectModify, InfoStruct.ftLastWriteTime))
+ {
+ Fail("ERROR: The write time of the file "
+ "does not match the last write time given from "
+ "GetFileTime.\n");
+ }
+
+ if(InfoStruct.nFileSizeLow != GetFileSize(hFile,NULL))
+ {
+ Fail("ERROR: The file size reported by GetFileAttributesEx "
+ "did not match the file size given by GetFileSize.\n");
+ }
+
+ if(CloseHandle(hFile) == 0)
+ {
+ Fail("ERROR: Failed to properly close the handle to the "
+ "file we're testing. GetLastError() returned %d.\n",
+ GetLastError());
+
+ }
+
+ }
+
+
+}
+
+/* Given a file/directory name, the expected attribs and whether or not it
+ is a file or directory, call GetFileAttributesEx and verify the
+ results are correct.
+*/
+
+void RunTest(char* Name, DWORD Attribs, ItemType TheType )
+{
+ WCHAR* TheName;
+ WIN32_FILE_ATTRIBUTE_DATA InfoStruct;
+ DWORD TheResult;
+
+ TheName = convert(Name);
+
+ TheResult = GetFileAttributesEx(TheName,
+ GetFileExInfoStandard,
+ &InfoStruct);
+ if(TheResult == 0)
+ {
+ free(TheName);
+ Fail("ERROR: GetFileAttributesEx returned 0, indicating failure. "
+ "GetLastError returned %d.\n",GetLastError());
+ }
+
+ VerifyInfo(InfoStruct, Attribs, TheType, TheName);
+
+}
+
+int __cdecl main(int argc, char **argv)
+{
+ DWORD TheResult;
+ WCHAR* FileName;
+ WIN32_FILE_ATTRIBUTE_DATA InfoStruct;
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ /* Test a Directroy */
+ RunTest("normal_test_directory", FILE_ATTRIBUTE_DIRECTORY, IS_DIR);
+
+
+ /* Test a Normal File */
+
+ RunTest("normal_test_file", FILE_ATTRIBUTE_NORMAL, IS_FILE);
+
+ /* Test a Read-Only Directroy */
+
+ RunTest("ro_test_directory",
+ FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_DIRECTORY, IS_DIR);
+
+ /* Test a Read-Only File */
+
+ RunTest("ro_test_file", FILE_ATTRIBUTE_READONLY, IS_FILE);
+
+ /* Test a Hidden File */
+
+ RunTest(".hidden_file", FILE_ATTRIBUTE_HIDDEN, IS_FILE);
+
+ /* Test a Hidden Directroy */
+
+ RunTest(".hidden_directory",
+ FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_DIRECTORY, IS_DIR);
+
+ /* Test a Non-Existant File */
+
+ FileName = convert("nonexistent_test_file");
+
+ TheResult = GetFileAttributesEx(FileName,
+ GetFileExInfoStandard,
+ &InfoStruct);
+
+ if(TheResult != 0)
+ {
+ free(FileName);
+ Fail("ERROR: GetFileAttributesEx returned non-zero, indicating "
+ "success when it should have failed. It was called on a "
+ "non-existent file.");
+ }
+
+ free(FileName);
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/file_io/GetFileAttributesExW/test1/testinfo.dat b/src/pal/tests/palsuite/file_io/GetFileAttributesExW/test1/testinfo.dat
new file mode 100644
index 0000000000..fbc397eac0
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileAttributesExW/test1/testinfo.dat
@@ -0,0 +1,16 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = GetFileAttributesExW
+Name = Test with normal file/dir and readonly file/dir and hidden file/dir
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Tests the PAL implementation of the GetFileAttributesExW function.
+= Call the function on a normal directory and file and a read-only directory
+= and file and a hidden file and directory.
+= Ensure that the attributes returned are correct, and the
+= file times and file sizes.
diff --git a/src/pal/tests/palsuite/file_io/GetFileAttributesExW/test2/CMakeLists.txt b/src/pal/tests/palsuite/file_io/GetFileAttributesExW/test2/CMakeLists.txt
new file mode 100644
index 0000000000..70caac2c69
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileAttributesExW/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test2.c
+)
+
+add_executable(paltest_getfileattributesexw_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getfileattributesexw_test2 coreclrpal)
+
+target_link_libraries(paltest_getfileattributesexw_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/GetFileAttributesExW/test2/test2.c b/src/pal/tests/palsuite/file_io/GetFileAttributesExW/test2/test2.c
new file mode 100644
index 0000000000..f244a3bf6a
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileAttributesExW/test2/test2.c
@@ -0,0 +1,170 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: getfileattributesexw.c (getfileattributesexw\test2)
+**
+** Purpose: Tests the PAL implementation of GetFileAttributesExW.
+** First get a file's attributes, modify the file,
+** re-get its attributes
+** and compare the two sets of attributes.
+**
+**
+**===================================================================*/
+#include <palsuite.h>
+
+/**
+ * This is a helper function which takes two FILETIME structures and
+ * checks that the second time isn't before the first.
+ */
+static int IsFileTimeOk(FILETIME FirstTime, FILETIME SecondTime)
+{
+
+ ULONG64 TimeOne, TimeTwo;
+
+ TimeOne = ((((ULONG64)FirstTime.dwHighDateTime)<<32) |
+ ((ULONG64)FirstTime.dwLowDateTime));
+
+ TimeTwo = ((((ULONG64)SecondTime.dwHighDateTime)<<32) |
+ ((ULONG64)SecondTime.dwLowDateTime));
+
+ return(TimeOne <= TimeTwo);
+}
+
+int __cdecl main(int argc, char **argv)
+{
+ DWORD res;
+ char fileName[MAX_PATH] = "test_file";
+ WCHAR *wFileName;
+ WIN32_FILE_ATTRIBUTE_DATA beforeAttribs;
+ WIN32_FILE_ATTRIBUTE_DATA afterAttribs;
+ FILE *testFile;
+ ULONG64 beforeFileSize;
+ ULONG64 afterFileSize;
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ /* Create the file */
+ testFile = fopen(fileName, "w+");
+ if( NULL == testFile )
+ {
+ Fail("Unexpected error: Unable to open file %S "
+ "with fopen. \n",
+ fileName);
+ }
+
+ if( EOF == fputs( "testing", testFile ) )
+ {
+ Fail("Unexpected error: Unable to write to file %S "
+ "with fputs. \n",
+ fileName);
+ }
+
+ if( 0 != fclose(testFile) )
+ {
+ Fail("Unexpected error: Unable to close file %S "
+ "with fclose. \n",
+ fileName);
+ }
+
+ /* Test the Values returned by GetFileAttributesExW
+ * before and after manipulating a file shouldn't be the same.
+ */
+
+ wFileName = convert(fileName);
+
+ res = GetFileAttributesExW(wFileName,
+ GetFileExInfoStandard,
+ &beforeAttribs);
+
+ if(res == 0)
+ {
+ Fail("ERROR: unable to get initial file attributes with "
+ "GetFileAttributesEx that returned 0 with error %d.\n",
+ GetLastError());
+ }
+
+ /* Make sure the time are different */
+ Sleep(500);
+
+ testFile = fopen(fileName, "w+");
+ if( NULL == testFile )
+ {
+ Fail("Unexpected error: Unable to open file %S "
+ "with fopen. \n",
+ fileName);
+ }
+
+ if( EOF == fputs( "testing GetFileAttributesExW", testFile ) )
+ {
+ Fail("Unexpected error: Unable to write to file %S "
+ "with fputs. \n",
+ fileName);
+ }
+
+ if( 0 != fclose(testFile) )
+ {
+ Fail("Unexpected error: Unable to close file %S "
+ "with fclose. \n",
+ fileName);
+ }
+
+ res = GetFileAttributesExW(wFileName,
+ GetFileExInfoStandard,
+ &afterAttribs);
+
+ if(res == 0)
+ {
+ Fail("ERROR: unable to get file attributes after operations with "
+ "GetFileAttributesEx that returned 0 with error %d.\n",
+ GetLastError());
+ }
+
+ /* Check the creation time */
+ if(!IsFileTimeOk(beforeAttribs.ftCreationTime,
+ afterAttribs.ftCreationTime))
+ {
+ Fail("ERROR: Creation time after the fputs operation "
+ "is earlier than the creation time before the fputs.\n");
+ }
+
+ /* Check the last access time */
+ if(!IsFileTimeOk(beforeAttribs.ftLastAccessTime,
+ afterAttribs.ftLastAccessTime))
+ {
+ Fail("ERROR: Last access time after the fputs operation "
+ "is earlier than the last access time before the fputs.\n");
+ }
+
+ /* Check the last write time */
+ if(!IsFileTimeOk(beforeAttribs.ftLastWriteTime,
+ afterAttribs.ftLastWriteTime))
+ {
+ Fail("ERROR: Last write time after the fputs operation "
+ "is earlier than the last write time before the fputs.\n");
+ }
+
+ beforeFileSize = ((ULONG64)beforeAttribs.nFileSizeHigh)<< 32 |
+ ((ULONG64)beforeAttribs.nFileSizeLow);
+
+ afterFileSize = ((ULONG64)afterAttribs.nFileSizeHigh)<< 32 |
+ ((ULONG64)afterAttribs.nFileSizeLow);
+
+ /* Check the file size */
+ if( afterFileSize <= beforeFileSize )
+ {
+ Fail("ERROR: the file should have had a bigger size "
+ "after(%d) the operations than before(%d)\n",
+ afterAttribs.nFileSizeLow,
+ beforeAttribs.nFileSizeLow);
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/file_io/GetFileAttributesExW/test2/testinfo.dat b/src/pal/tests/palsuite/file_io/GetFileAttributesExW/test2/testinfo.dat
new file mode 100644
index 0000000000..560e3f6266
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileAttributesExW/test2/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = GetFileAttributesExW
+Name = Test for GetFileAttributesExW
+TYPE = DEFAULT
+EXE1 = test2
+Description
+= Tests the PAL implementation of the GetFileAttributesExW function.
+= First get a file's attributes, modify the file, re-get its attributes
+= and compare the two sets of attributes
diff --git a/src/pal/tests/palsuite/file_io/GetFileAttributesW/CMakeLists.txt b/src/pal/tests/palsuite/file_io/GetFileAttributesW/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileAttributesW/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/file_io/GetFileAttributesW/test1/.hidden_directory/CMakeLists.txt b/src/pal/tests/palsuite/file_io/GetFileAttributesW/test1/.hidden_directory/CMakeLists.txt
new file mode 100644
index 0000000000..a8fd227402
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileAttributesW/test1/.hidden_directory/CMakeLists.txt
@@ -0,0 +1,2 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
diff --git a/src/pal/tests/palsuite/file_io/GetFileAttributesW/test1/.hidden_directory/keepme b/src/pal/tests/palsuite/file_io/GetFileAttributesW/test1/.hidden_directory/keepme
new file mode 100644
index 0000000000..31eade7217
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileAttributesW/test1/.hidden_directory/keepme
@@ -0,0 +1 @@
+Make CVS checkout this directory even with -p option. \ No newline at end of file
diff --git a/src/pal/tests/palsuite/file_io/GetFileAttributesW/test1/.hidden_file b/src/pal/tests/palsuite/file_io/GetFileAttributesW/test1/.hidden_file
new file mode 100644
index 0000000000..0d1ac31cfa
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileAttributesW/test1/.hidden_file
@@ -0,0 +1 @@
+Hidden file \ No newline at end of file
diff --git a/src/pal/tests/palsuite/file_io/GetFileAttributesW/test1/.hidden_ro_directory/CMakeLists.txt b/src/pal/tests/palsuite/file_io/GetFileAttributesW/test1/.hidden_ro_directory/CMakeLists.txt
new file mode 100644
index 0000000000..a8fd227402
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileAttributesW/test1/.hidden_ro_directory/CMakeLists.txt
@@ -0,0 +1,2 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
diff --git a/src/pal/tests/palsuite/file_io/GetFileAttributesW/test1/.hidden_ro_directory/keepme b/src/pal/tests/palsuite/file_io/GetFileAttributesW/test1/.hidden_ro_directory/keepme
new file mode 100644
index 0000000000..31eade7217
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileAttributesW/test1/.hidden_ro_directory/keepme
@@ -0,0 +1 @@
+Make CVS checkout this directory even with -p option. \ No newline at end of file
diff --git a/src/pal/tests/palsuite/file_io/GetFileAttributesW/test1/.hidden_ro_file b/src/pal/tests/palsuite/file_io/GetFileAttributesW/test1/.hidden_ro_file
new file mode 100644
index 0000000000..8f78fcb436
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileAttributesW/test1/.hidden_ro_file
@@ -0,0 +1 @@
+.hidden_ro_file
diff --git a/src/pal/tests/palsuite/file_io/GetFileAttributesW/test1/CMakeLists.txt b/src/pal/tests/palsuite/file_io/GetFileAttributesW/test1/CMakeLists.txt
new file mode 100644
index 0000000000..7050484607
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileAttributesW/test1/CMakeLists.txt
@@ -0,0 +1,26 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ GetFileAttributesW.c
+)
+
+add_executable(paltest_getfileattributesw_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getfileattributesw_test1 coreclrpal)
+
+target_link_libraries(paltest_getfileattributesw_test1
+ pthread
+ m
+ coreclrpal
+)
+add_subdirectory(.hidden_directory)
+add_subdirectory(.hidden_ro_directory)
+add_subdirectory(normal_test_directory)
+add_subdirectory(no_directory)
+add_subdirectory(ro_test_directory)
+add_subdirectory(rw_test_directory)
+
diff --git a/src/pal/tests/palsuite/file_io/GetFileAttributesW/test1/GetFileAttributesW.c b/src/pal/tests/palsuite/file_io/GetFileAttributesW/test1/GetFileAttributesW.c
new file mode 100644
index 0000000000..9d00da4bd4
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileAttributesW/test1/GetFileAttributesW.c
@@ -0,0 +1,345 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================================
+**
+** Source: GetFileAttributesW.c
+**
+** Purpose: Tests the PAL implementation of the GetFileAttributesW function by
+** checking the attributes of:
+** - a normal directory and file
+** - a read only directory and file
+** - a read write directory and file
+** - a hidden directory and file
+** - a read only hidden directory and file
+** - a directory and a file with no attributes
+** - an invalid file name
+**
+**
+**===========================================================================*/
+#include <palsuite.h>
+
+const int TYPE_DIR = 0;
+const int TYPE_FILE = 1;
+/* Structure defining a test case */
+typedef struct
+{
+ char *name; /* name of the file/directory */
+ DWORD expectedAttribs; /* expected attributes */
+ HANDLE hFile; /* Handle to the file */
+ int isFile; /* is file (1) or dir (0) */
+}TestCaseFile;
+
+typedef struct
+{
+ char *name; /* name of the file/directory */
+ DWORD expectedAttribs; /* expected attributes */
+ HANDLE hFile; /* Handle to the file */
+ int isFile; /* is file (1) or dir (0) */
+}TestCaseDir;
+
+DWORD desiredAccessFile = GENERIC_READ | GENERIC_WRITE;
+DWORD shareModeFile = FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE;
+LPSECURITY_ATTRIBUTES lpAttrFile = NULL;
+DWORD dwCreationDispFile = CREATE_NEW;
+DWORD dwFlagsAttribFile = FILE_ATTRIBUTE_NORMAL;
+HANDLE hTemplateFile = NULL;
+
+int numFileTests = 6;
+TestCaseFile gfaTestsFile[6]; /* GetFileAttributes tests list */
+
+int numDirTests = 6;
+TestCaseDir gfaTestsDir[6]; /* GetFileAttributes tests list */
+
+BOOL CleanUpFiles()
+{
+ DWORD dwAtt;
+ int i;
+ BOOL result = TRUE;
+ for (i = 0; i < numFileTests - 1 ; i++ )
+ {
+ dwAtt = GetFileAttributesA(gfaTestsFile[i].name);
+
+ if( dwAtt != INVALID_FILE_ATTRIBUTES )
+ {
+ //Trace("Files iteration %d\n", i);
+ if(!SetFileAttributesA (gfaTestsFile[i].name, FILE_ATTRIBUTE_NORMAL))
+ {
+ result = FALSE;
+ Trace("ERROR:%d: Error setting attributes [%s][%d]\n", GetLastError(), gfaTestsFile[i].name, FILE_ATTRIBUTE_NORMAL);
+ }
+
+ if(!DeleteFileA (gfaTestsFile[i].name))
+ {
+ result = FALSE;
+ Trace("ERROR:%d: Error deleting file [%s][%d]\n", GetLastError(), gfaTestsFile[i].name, dwAtt);
+ }
+
+ }
+ }
+// Trace("Value of result is %d\n", result);
+ return result;
+}
+BOOL SetUpFiles()
+{
+ int i = 0;
+ BOOL result = TRUE;
+ for (i = 0; i < numFileTests - 1 ; i++ )
+ {
+ gfaTestsFile[i].hFile = CreateFile(gfaTestsFile[i].name,
+ desiredAccessFile,
+ shareModeFile,
+ lpAttrFile,
+ dwCreationDispFile,
+ dwFlagsAttribFile,
+ hTemplateFile);
+
+ if( gfaTestsFile[i].hFile == NULL )
+ {
+ Fail("Error while creating files for iteration %d\n", i);
+ }
+
+ if(!SetFileAttributesA (gfaTestsFile[i].name, gfaTestsFile[i].expectedAttribs))
+ {
+ result = FALSE;
+ Trace("ERROR:%d: Error setting attributes [%s][%d]\n", GetLastError(), gfaTestsFile[i].name, gfaTestsFile[i].expectedAttribs);
+ }
+ }
+
+ return result;
+}
+
+BOOL CleanUpDirs()
+{
+ DWORD dwAtt;
+ int i;
+ BOOL result = TRUE;
+ for (i = 0; i < numDirTests - 1; i++ )
+ {
+ dwAtt = GetFileAttributesA(gfaTestsDir[i].name);
+
+ if( dwAtt != INVALID_FILE_ATTRIBUTES )
+ {
+
+ if(!SetFileAttributesA (gfaTestsDir[i].name, FILE_ATTRIBUTE_DIRECTORY))
+ {
+ result = FALSE;
+ Trace("ERROR:%d: Error setting attributes [%s][%d]\n", GetLastError(), gfaTestsDir[i].name, (FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_DIRECTORY));
+ }
+
+ if(!RemoveDirectoryA (gfaTestsDir[i].name))
+ {
+ result = FALSE;
+ Trace("ERROR:%d: Error deleting file [%s][%d]\n", GetLastError(), gfaTestsDir[i].name, dwAtt);
+ }
+
+ }
+ }
+
+ return result;
+}
+
+BOOL SetUpDirs()
+{
+ int i = 0;
+ BOOL result = TRUE;
+ DWORD ret = 0;
+ for (i = 0; i < numDirTests - 1; i++ )
+ {
+ result = CreateDirectory(gfaTestsDir[i].name,
+ NULL);
+
+ if(!result )
+ {
+ result = FALSE;
+ Fail("Error while creating directory for iteration %d\n", i);
+ }
+
+ if(!SetFileAttributesA (gfaTestsDir[i].name, gfaTestsDir[i].expectedAttribs))
+ {
+ result = FALSE;
+ Trace("ERROR:%d: Error setting attributes [%s][%d]\n", GetLastError(), gfaTestsDir[i].name, gfaTestsDir[i].expectedAttribs);
+ }
+
+ ret = GetFileAttributesA (gfaTestsDir[i].name);
+ if(ret != gfaTestsDir[i].expectedAttribs)
+ {
+ result = FALSE;
+ Trace("ERROR: Error setting attributes [%s][%d]\n", gfaTestsDir[i].name, gfaTestsDir[i].expectedAttribs);
+ }
+ // Trace("Setup Dir setting attr [%d], returned [%d]\n", gfaTestsDir[i].expectedAttribs, ret);
+
+ }
+// Trace("Setup dirs returning %d\n", result);
+ return result;
+}
+int __cdecl main(int argc, char **argv)
+{
+ int i;
+ BOOL bFailed = FALSE;
+ DWORD result;
+
+ char * NormalDirectoryName = "normal_test_directory";
+ char * ReadOnlyDirectoryName = "ro_test_directory";
+ char * ReadWriteDirectoryName = "rw_directory";
+ char * HiddenDirectoryName = ".hidden_directory";
+ char * HiddenReadOnlyDirectoryName = ".hidden_ro_directory";
+ char * NoDirectoryName = "no_directory";
+
+ char * NormalFileName = "normal_test_file";
+ char * ReadOnlyFileName = "ro_test_file";
+ char * ReadWriteFileName = "rw_file";
+ char * HiddenFileName = ".hidden_file";
+ char * HiddenReadOnlyFileName = ".hidden_ro_file";
+ char * NotReallyAFileName = "not_really_a_file";
+
+ WCHAR *WStr;
+ /* Tests on directory */
+ gfaTestsDir[0].name = NormalDirectoryName;
+ gfaTestsDir[0].expectedAttribs = FILE_ATTRIBUTE_DIRECTORY;
+ gfaTestsDir[0].isFile = TYPE_DIR;
+
+ gfaTestsDir[1].name = ReadOnlyDirectoryName;
+ gfaTestsDir[1].expectedAttribs = FILE_ATTRIBUTE_DIRECTORY |
+ FILE_ATTRIBUTE_READONLY;
+ gfaTestsDir[1].isFile = TYPE_DIR;
+
+ gfaTestsDir[2].name = ReadWriteDirectoryName;
+ gfaTestsDir[2].expectedAttribs = FILE_ATTRIBUTE_DIRECTORY;
+ gfaTestsDir[2].isFile = TYPE_DIR;
+
+ gfaTestsDir[3].name = HiddenDirectoryName;
+ gfaTestsDir[3].expectedAttribs = FILE_ATTRIBUTE_DIRECTORY; //|
+ //FILE_ATTRIBUTE_HIDDEN;
+ gfaTestsDir[3].isFile = TYPE_DIR;
+
+ gfaTestsDir[4].name = HiddenReadOnlyDirectoryName;
+ gfaTestsDir[4].expectedAttribs = FILE_ATTRIBUTE_DIRECTORY |
+ FILE_ATTRIBUTE_READONLY; //|
+ //FILE_ATTRIBUTE_HIDDEN;
+ gfaTestsDir[4].isFile = TYPE_DIR;
+
+ gfaTestsDir[5].name = NoDirectoryName;
+ gfaTestsDir[5].expectedAttribs = INVALID_FILE_ATTRIBUTES;
+ gfaTestsDir[5].isFile = TYPE_DIR;
+
+ /* Tests on file */
+ gfaTestsFile[0].name = NormalFileName;
+ gfaTestsFile[0].expectedAttribs = FILE_ATTRIBUTE_NORMAL;
+ gfaTestsFile[0].isFile = TYPE_FILE;
+
+
+ gfaTestsFile[1].name = ReadOnlyFileName;
+ gfaTestsFile[1].expectedAttribs = FILE_ATTRIBUTE_READONLY;
+ gfaTestsFile[1].isFile = TYPE_FILE;
+
+ gfaTestsFile[2].name = ReadWriteFileName;
+ gfaTestsFile[2].expectedAttribs = FILE_ATTRIBUTE_NORMAL;
+ gfaTestsFile[2].isFile = TYPE_FILE;
+
+ gfaTestsFile[3].name = HiddenFileName;
+ gfaTestsFile[3].expectedAttribs = FILE_ATTRIBUTE_NORMAL; //FILE_ATTRIBUTE_HIDDEN;
+ gfaTestsFile[3].isFile = TYPE_FILE;
+
+ gfaTestsFile[4].name = HiddenReadOnlyFileName;
+ gfaTestsFile[4].expectedAttribs = FILE_ATTRIBUTE_READONLY; //|
+ //FILE_ATTRIBUTE_HIDDEN;
+ gfaTestsFile[4].isFile = TYPE_FILE;
+
+
+ gfaTestsFile[5].name = NotReallyAFileName;
+ gfaTestsFile[5].expectedAttribs = INVALID_FILE_ATTRIBUTES;
+ gfaTestsFile[5].isFile = TYPE_FILE;
+
+ /* Initialize PAL environment */
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ if(!CleanUpFiles())
+ {
+ Fail("GetFileAttributesW: Pre-Clean Up Files Failed\n");
+ }
+
+ if(0 == SetUpFiles())
+ {
+ Fail("GetFileAttributesW: SetUp Files Failed\n");
+ }
+
+ if(!CleanUpDirs())
+ {
+ Fail("GetFileAttributesW: Pre-Clean Up Directories Failed\n");
+ }
+
+ if(!SetUpDirs())
+ {
+ Fail("GetFileAttributesW: SetUp Directories Failed\n");
+ }
+
+ /*
+ * Go through all the test cases above,
+ * call GetFileAttributesW on the name and
+ * make sure the return value is the one expected
+ */
+ for( i = 0; i < numFileTests; i++ )
+ {
+ WStr = convert(gfaTestsFile[i].name);
+ result = GetFileAttributesW(WStr);
+
+ if( result != gfaTestsFile[i].expectedAttribs )
+ {
+ bFailed = TRUE;
+
+ Trace("ERROR: GetFileAttributesW Test#%u on %s "
+ "returned %u instead of %u. \n",
+ i,
+ gfaTestsFile[i].name,
+ result,
+ gfaTestsFile[i].expectedAttribs);
+
+ }
+ free(WStr);
+ }
+
+
+ for( i = 0; i < numDirTests; i++ )
+ {
+ WStr = convert(gfaTestsDir[i].name);
+ result = GetFileAttributesW(WStr);
+
+ if( result != gfaTestsDir[i].expectedAttribs )
+ {
+ bFailed = TRUE;
+
+ Trace("ERROR: GetFileAttributesW on Directories Test#%u on %s "
+ "returned %u instead of %u. \n",
+ i,
+ gfaTestsDir[i].name,
+ result,
+ gfaTestsDir[i].expectedAttribs);
+
+ }
+ free(WStr);
+ }
+
+ if(!CleanUpFiles())
+ {
+ Fail("GetFileAttributesW: Post-Clean Up Files Failed\n");
+ }
+
+ if(!CleanUpDirs())
+ {
+ Fail("GetFileAttributesW: Post-Clean Up Directories Failed\n");
+ }
+
+ /* If any errors, just call Fail() */
+ if( bFailed )
+ {
+ Fail("");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/file_io/GetFileAttributesW/test1/no_directory/CMakeLists.txt b/src/pal/tests/palsuite/file_io/GetFileAttributesW/test1/no_directory/CMakeLists.txt
new file mode 100644
index 0000000000..a8fd227402
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileAttributesW/test1/no_directory/CMakeLists.txt
@@ -0,0 +1,2 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
diff --git a/src/pal/tests/palsuite/file_io/GetFileAttributesW/test1/no_directory/keepme b/src/pal/tests/palsuite/file_io/GetFileAttributesW/test1/no_directory/keepme
new file mode 100644
index 0000000000..31eade7217
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileAttributesW/test1/no_directory/keepme
@@ -0,0 +1 @@
+Make CVS checkout this directory even with -p option. \ No newline at end of file
diff --git a/src/pal/tests/palsuite/file_io/GetFileAttributesW/test1/no_file b/src/pal/tests/palsuite/file_io/GetFileAttributesW/test1/no_file
new file mode 100644
index 0000000000..3d631e8103
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileAttributesW/test1/no_file
@@ -0,0 +1 @@
+No attribs file \ No newline at end of file
diff --git a/src/pal/tests/palsuite/file_io/GetFileAttributesW/test1/normal_test_directory/CMakeLists.txt b/src/pal/tests/palsuite/file_io/GetFileAttributesW/test1/normal_test_directory/CMakeLists.txt
new file mode 100644
index 0000000000..a8fd227402
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileAttributesW/test1/normal_test_directory/CMakeLists.txt
@@ -0,0 +1,2 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
diff --git a/src/pal/tests/palsuite/file_io/GetFileAttributesW/test1/normal_test_directory/keepme b/src/pal/tests/palsuite/file_io/GetFileAttributesW/test1/normal_test_directory/keepme
new file mode 100644
index 0000000000..31eade7217
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileAttributesW/test1/normal_test_directory/keepme
@@ -0,0 +1 @@
+Make CVS checkout this directory even with -p option. \ No newline at end of file
diff --git a/src/pal/tests/palsuite/file_io/GetFileAttributesW/test1/normal_test_file b/src/pal/tests/palsuite/file_io/GetFileAttributesW/test1/normal_test_file
new file mode 100644
index 0000000000..a6e1e627a8
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileAttributesW/test1/normal_test_file
@@ -0,0 +1,6 @@
+file_io
+CopyFileW
+Positive Test for CopyFileW
+test the CopyFileW function
+DEFAULT
+CopyFileW \ No newline at end of file
diff --git a/src/pal/tests/palsuite/file_io/GetFileAttributesW/test1/ro_test_directory/CMakeLists.txt b/src/pal/tests/palsuite/file_io/GetFileAttributesW/test1/ro_test_directory/CMakeLists.txt
new file mode 100644
index 0000000000..a8fd227402
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileAttributesW/test1/ro_test_directory/CMakeLists.txt
@@ -0,0 +1,2 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
diff --git a/src/pal/tests/palsuite/file_io/GetFileAttributesW/test1/ro_test_directory/keepme b/src/pal/tests/palsuite/file_io/GetFileAttributesW/test1/ro_test_directory/keepme
new file mode 100644
index 0000000000..31eade7217
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileAttributesW/test1/ro_test_directory/keepme
@@ -0,0 +1 @@
+Make CVS checkout this directory even with -p option. \ No newline at end of file
diff --git a/src/pal/tests/palsuite/file_io/GetFileAttributesW/test1/ro_test_file b/src/pal/tests/palsuite/file_io/GetFileAttributesW/test1/ro_test_file
new file mode 100644
index 0000000000..a6e1e627a8
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileAttributesW/test1/ro_test_file
@@ -0,0 +1,6 @@
+file_io
+CopyFileW
+Positive Test for CopyFileW
+test the CopyFileW function
+DEFAULT
+CopyFileW \ No newline at end of file
diff --git a/src/pal/tests/palsuite/file_io/GetFileAttributesW/test1/rw_file b/src/pal/tests/palsuite/file_io/GetFileAttributesW/test1/rw_file
new file mode 100644
index 0000000000..39d66f0365
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileAttributesW/test1/rw_file
@@ -0,0 +1 @@
+Read Write file \ No newline at end of file
diff --git a/src/pal/tests/palsuite/file_io/GetFileAttributesW/test1/rw_test_directory/CMakeLists.txt b/src/pal/tests/palsuite/file_io/GetFileAttributesW/test1/rw_test_directory/CMakeLists.txt
new file mode 100644
index 0000000000..a8fd227402
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileAttributesW/test1/rw_test_directory/CMakeLists.txt
@@ -0,0 +1,2 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
diff --git a/src/pal/tests/palsuite/file_io/GetFileAttributesW/test1/rw_test_directory/keepme b/src/pal/tests/palsuite/file_io/GetFileAttributesW/test1/rw_test_directory/keepme
new file mode 100644
index 0000000000..31eade7217
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileAttributesW/test1/rw_test_directory/keepme
@@ -0,0 +1 @@
+Make CVS checkout this directory even with -p option. \ No newline at end of file
diff --git a/src/pal/tests/palsuite/file_io/GetFileAttributesW/test1/testinfo.dat b/src/pal/tests/palsuite/file_io/GetFileAttributesW/test1/testinfo.dat
new file mode 100644
index 0000000000..1a8089a0f1
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileAttributesW/test1/testinfo.dat
@@ -0,0 +1,20 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+
+Section = file_io
+
+Function = GetFileAttributesW
+
+Name = Positive Test for GetFileAttributesW
+
+TYPE = DEFAULT
+
+EXE1 = getfileattributesw
+
+Description
+
+= Test the GetFileAttributesW function
+
diff --git a/src/pal/tests/palsuite/file_io/GetFileSize/CMakeLists.txt b/src/pal/tests/palsuite/file_io/GetFileSize/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileSize/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/file_io/GetFileSize/test1/CMakeLists.txt b/src/pal/tests/palsuite/file_io/GetFileSize/test1/CMakeLists.txt
new file mode 100644
index 0000000000..ff20de5905
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileSize/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ GetFileSize.c
+)
+
+add_executable(paltest_getfilesize_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getfilesize_test1 coreclrpal)
+
+target_link_libraries(paltest_getfilesize_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/GetFileSize/test1/GetFileSize.c b/src/pal/tests/palsuite/file_io/GetFileSize/test1/GetFileSize.c
new file mode 100644
index 0000000000..fac01c98c9
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileSize/test1/GetFileSize.c
@@ -0,0 +1,173 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: GetFileSize.c (test 1)
+**
+** Purpose: Tests the PAL implementation of the GetFileSize function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+const char* szTextFile = "text.txt";
+
+void CleanUp(HANDLE hFile)
+{
+ if (CloseHandle(hFile) != TRUE)
+ {
+ Fail("GetFileSize: ERROR -> Unable to close file \"%s\".\n",
+ szTextFile);
+ }
+ if (!DeleteFileA(szTextFile))
+ {
+ Fail("GetFileSize: ERROR -> Unable to delete file \"%s\".\n",
+ szTextFile);
+ }
+}
+
+void CheckFileSize(HANDLE hFile, DWORD dwOffset, DWORD dwHighOrder)
+{
+ DWORD dwRc = 0;
+ DWORD dwReturnedHighOrder = 0;
+ DWORD dwReturnedOffset = 0;
+
+ dwRc = SetFilePointer(hFile, dwOffset, (PLONG)&dwHighOrder, FILE_BEGIN);
+ if (dwRc == INVALID_SET_FILE_POINTER)
+ {
+ Trace("GetFileSize: ERROR -> Call to SetFilePointer failed with %ld.\n",
+ GetLastError());
+ CleanUp(hFile);
+ Fail("");
+ }
+ else
+ {
+ if (!SetEndOfFile(hFile))
+ {
+ Trace("GetFileSize: ERROR -> Call to SetEndOfFile failed with %ld.\n",
+ GetLastError());
+ CleanUp(hFile);
+ Fail("");
+ }
+ dwReturnedOffset = GetFileSize(hFile, &dwReturnedHighOrder);
+ if ((dwReturnedOffset != dwOffset) ||
+ (dwReturnedHighOrder != dwHighOrder))
+ {
+ CleanUp(hFile);
+ Fail("GetFileSize: ERROR -> File sizes do not match up.\n");
+ }
+ }
+}
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ HANDLE hFile = NULL;
+ DWORD dwRc = 0;
+ DWORD dwRc2 = 0;
+ DWORD dwHighOrder = 0;
+ DWORD lpNumberOfBytesWritten;
+ char * data = "1234567890";
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+
+ /* test on a null file handle */
+ dwRc = GetFileSize(hFile, NULL);
+ if (dwRc != INVALID_FILE_SIZE)
+ {
+ Fail("GetFileSize: ERROR -> A file size was returned for "
+ "a null handle.\n");
+ }
+
+ /* test on a null file handle using the high order option */
+ dwRc = GetFileSize(hFile, &dwHighOrder);
+ if (dwRc != INVALID_FILE_SIZE)
+ {
+ Fail("GetFileSize: ERROR -> A file size was returned for "
+ "a null handle.\n");
+ }
+
+ /* test on an invalid file handle */
+ dwRc = GetFileSize(INVALID_HANDLE_VALUE, NULL);
+ if (dwRc != INVALID_FILE_SIZE)
+ {
+ Fail("GetFileSize: ERROR -> A file size was returned for "
+ "an invalid handle.\n");
+ }
+
+ /* test on an invalid file handle using the high order option */
+ dwRc = GetFileSize(INVALID_HANDLE_VALUE, &dwHighOrder);
+ if (dwRc != INVALID_FILE_SIZE)
+ {
+ Fail("GetFileSize: ERROR -> A file size was returned for "
+ "an invalid handle.\n");
+ }
+
+
+ /* create a test file */
+ hFile = CreateFile(szTextFile,
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if(hFile == INVALID_HANDLE_VALUE)
+ {
+ Fail("GetFileSize: ERROR -> Unable to create file \"%s\".\n",
+ szTextFile);
+ }
+
+ /* give the file a size */
+ CheckFileSize(hFile, 256, 0);
+
+ /* make the file large using the high order option */
+ CheckFileSize(hFile, 256, 1);
+
+
+ /* set the file size to zero */
+ CheckFileSize(hFile, 0, 0);
+
+ /* test if file size changes by writing to it. */
+ /* get file size */
+ dwRc = GetFileSize(hFile, NULL);
+
+ /* test writing to the file */
+ if(WriteFile(hFile, data, strlen(data), &lpNumberOfBytesWritten, NULL)==0)
+ {
+ Trace("GetFileSize: ERROR -> Call to WriteFile failed with %ld.\n",
+ GetLastError());
+ CleanUp(hFile);
+ Fail("");
+ }
+
+ /* make sure the buffer flushed.*/
+ if(FlushFileBuffers(hFile)==0)
+ {
+ Trace("GetFileSize: ERROR -> Call to FlushFileBuffers failed with %ld.\n",
+ GetLastError());
+ CleanUp(hFile);
+ Fail("");
+ }
+
+ /* get file size after writing some chars */
+ dwRc2 = GetFileSize(hFile, NULL);
+ if((dwRc2-dwRc) !=strlen(data))
+ {
+ CleanUp(hFile);
+ Fail("GetFileSize: ERROR -> File size did not increase properly after.\n"
+ "writing %d chars\n", strlen(data));
+ }
+
+ CleanUp(hFile);
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/file_io/GetFileSize/test1/testinfo.dat b/src/pal/tests/palsuite/file_io/GetFileSize/test1/testinfo.dat
new file mode 100644
index 0000000000..38258572db
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileSize/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = GetFileSize
+Name = Positive Test for GetFileSize (test 1)
+Type = DEFAULT
+EXE1 = getfilesize
+Description
+= Test GetFileSize on a NULL handle and valid file handles
+
diff --git a/src/pal/tests/palsuite/file_io/GetFileSizeEx/CMakeLists.txt b/src/pal/tests/palsuite/file_io/GetFileSizeEx/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileSizeEx/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/file_io/GetFileSizeEx/test1/CMakeLists.txt b/src/pal/tests/palsuite/file_io/GetFileSizeEx/test1/CMakeLists.txt
new file mode 100644
index 0000000000..1369a5dc5a
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileSizeEx/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ GetFileSizeEx.c
+)
+
+add_executable(paltest_getfilesizeex_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getfilesizeex_test1 coreclrpal)
+
+target_link_libraries(paltest_getfilesizeex_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/GetFileSizeEx/test1/GetFileSizeEx.c b/src/pal/tests/palsuite/file_io/GetFileSizeEx/test1/GetFileSizeEx.c
new file mode 100644
index 0000000000..ef5afd0e6b
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileSizeEx/test1/GetFileSizeEx.c
@@ -0,0 +1,173 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: GetFileSizeEx.c (test 1)
+**
+** Purpose: Tests the PAL implementation of the GetFileSizeEx function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+const char* szTextFile = "text.txt";
+
+void CleanUp(HANDLE hFile)
+{
+ if (CloseHandle(hFile) != TRUE)
+ {
+ Fail("GetFileSizeEx: ERROR -> Unable to close file \"%s\".\n"
+ " Error is %d\n",
+ szTextFile, GetLastError());
+ }
+ if (!DeleteFileA(szTextFile))
+ {
+ Fail("GetFileSizeEx: ERROR -> Unable to delete file \"%s\".\n"
+ " Error is %d\n",
+ szTextFile, GetLastError());
+ }
+}
+
+void CheckFileSize(HANDLE hFile, DWORD dwOffset, DWORD dwHighOrder)
+{
+ DWORD dwRc = 0;
+ DWORD dwError = 0;
+ LARGE_INTEGER qwFileSize;
+
+ dwRc = SetFilePointer(hFile, dwOffset, (PLONG)&dwHighOrder, FILE_BEGIN);
+ if (dwRc == INVALID_SET_FILE_POINTER)
+ {
+ Trace("GetFileSizeEx: ERROR -> Call to SetFilePointer failed with %ld.\n",
+ GetLastError());
+ CleanUp(hFile);
+ Fail("");
+ }
+ else
+ {
+ if (!SetEndOfFile(hFile))
+ {
+ dwError = GetLastError();
+ CleanUp(hFile);
+ if (dwError == 112)
+ {
+ Fail("GetFileSizeEx: ERROR -> SetEndOfFile failed due to lack of "
+ "disk space\n");
+ }
+ else
+ {
+ Fail("GetFileSizeEx: ERROR -> SetEndOfFile call failed "
+ "with error %ld\n", dwError);
+ }
+ }
+ else
+ {
+ GetFileSizeEx(hFile, &qwFileSize);
+ if ((qwFileSize.u.LowPart != dwOffset) ||
+ (qwFileSize.u.HighPart != dwHighOrder))
+ {
+ CleanUp(hFile);
+ Fail("GetFileSizeEx: ERROR -> File sizes do not match up.\n");
+ }
+ }
+ }
+}
+
+int __cdecl main(int argc, char *argv[])
+{
+ HANDLE hFile = NULL;
+ BOOL bRc = FALSE;
+ DWORD lpNumberOfBytesWritten;
+ LARGE_INTEGER qwFileSize;
+ LARGE_INTEGER qwFileSize2;
+ char * data = "1234567890";
+
+ qwFileSize.QuadPart = 0;
+ qwFileSize2.QuadPart = 0;
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+
+ /* test on a null file */
+ bRc = GetFileSizeEx(NULL, &qwFileSize);
+ if (bRc != FALSE)
+ {
+ Fail("GetFileSizeEx: ERROR -> Returned status as TRUE for "
+ "a null handle.\n");
+ }
+
+
+ /* test on an invalid file */
+ bRc = GetFileSizeEx(INVALID_HANDLE_VALUE, &qwFileSize);
+ if (bRc != FALSE)
+ {
+ Fail("GetFileSizeEx: ERROR -> Returned status as TRUE for "
+ "an invalid handle.\n");
+ }
+
+
+ /* create a test file */
+ hFile = CreateFile(szTextFile,
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if(hFile == INVALID_HANDLE_VALUE)
+ {
+ Fail("GetFileSizeEx: ERROR -> Unable to create file \"%s\".\n",
+ szTextFile);
+ }
+
+ /* give the file a size */
+ CheckFileSize(hFile, 256, 0);
+
+ /* make the file large using the high order option */
+ CheckFileSize(hFile, 256, 1);
+
+
+ /* set the file size to zero */
+ CheckFileSize(hFile, 0, 0);
+
+ /* test if file size changes by writing to it. */
+ /* get file size */
+ GetFileSizeEx(hFile, &qwFileSize);
+
+ /* test writing to the file */
+ if(WriteFile(hFile, data, strlen(data), &lpNumberOfBytesWritten, NULL)==0)
+ {
+ Trace("GetFileSizeEx: ERROR -> Call to WriteFile failed with %ld.\n",
+ GetLastError());
+ CleanUp(hFile);
+ Fail("");
+ }
+
+ /* make sure the buffer flushed.*/
+ if(FlushFileBuffers(hFile)==0)
+ {
+ Trace("GetFileSizeEx: ERROR -> Call to FlushFileBuffers failed with %ld.\n",
+ GetLastError());
+ CleanUp(hFile);
+ Fail("");
+ }
+
+ /* get file size after writing some chars */
+ GetFileSizeEx(hFile, &qwFileSize2);
+ if((qwFileSize2.QuadPart-qwFileSize.QuadPart) !=strlen(data))
+ {
+ CleanUp(hFile);
+ Fail("GetFileSizeEx: ERROR -> File size did not increase properly after.\n"
+ "writing %d chars\n", strlen(data));
+ }
+
+ CleanUp(hFile);
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/file_io/GetFileSizeEx/test1/testinfo.dat b/src/pal/tests/palsuite/file_io/GetFileSizeEx/test1/testinfo.dat
new file mode 100644
index 0000000000..5968fe7271
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileSizeEx/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = GetFileSizeEx
+Name = Positive Test for GetFileSizeEx (test 1)
+Type = DEFAULT
+EXE1 = getfilesizeex
+Description
+= Test GetFileSizeEx on a NULL handle and valid file handles
+
diff --git a/src/pal/tests/palsuite/file_io/GetFileTime/CMakeLists.txt b/src/pal/tests/palsuite/file_io/GetFileTime/CMakeLists.txt
new file mode 100644
index 0000000000..19ee487a6a
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileTime/CMakeLists.txt
@@ -0,0 +1,10 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+add_subdirectory(test3)
+add_subdirectory(test4)
+add_subdirectory(test5)
+add_subdirectory(test6)
+add_subdirectory(test7)
+
diff --git a/src/pal/tests/palsuite/file_io/GetFileTime/test1/CMakeLists.txt b/src/pal/tests/palsuite/file_io/GetFileTime/test1/CMakeLists.txt
new file mode 100644
index 0000000000..6a89846d21
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileTime/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ GetFileTime.c
+)
+
+add_executable(paltest_getfiletime_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getfiletime_test1 coreclrpal)
+
+target_link_libraries(paltest_getfiletime_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/GetFileTime/test1/GetFileTime.c b/src/pal/tests/palsuite/file_io/GetFileTime/test1/GetFileTime.c
new file mode 100644
index 0000000000..fb7bcb8513
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileTime/test1/GetFileTime.c
@@ -0,0 +1,180 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: GetFileTime.c
+**
+** Purpose: Tests the PAL implementation of the GetFileTime function.
+** This test checks the time of a file, writes to it, then checks the
+** time again to ensure that write time has increased. It
+** also checks that creation time is the same under WIN32 and has
+** increased under FreeBSD.
+**
+** Depends:
+** CreateFile
+** WriteFile
+** CloseHandle
+**
+**
+**===================================================================*/
+
+
+#include <palsuite.h>
+
+
+int __cdecl main(int argc, char **argv)
+{
+
+ FILETIME Creation,LastAccess,LastWrite;
+ HANDLE TheFileHandle;
+ ULONG64 FirstWrite, SecondWrite, FirstCreationTime, SecondCreationTime;
+ DWORD temp;
+ BOOL result;
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ /* Open the file to get a HANDLE */
+ TheFileHandle =
+ CreateFile(
+ "the_file", // File Name
+ GENERIC_READ|GENERIC_WRITE, // Access Mode
+ 0, // Share Mode
+ NULL, // SD
+ OPEN_ALWAYS, // Howto Create
+ FILE_ATTRIBUTE_NORMAL, // File Attributes
+ NULL // Template file
+ );
+
+ if(TheFileHandle == INVALID_HANDLE_VALUE)
+ {
+ Fail("ERROR: Failed to open the file. The error number "
+ "returned was %d.",GetLastError());
+ }
+
+
+ /* Get the Last Write, Creation and Access File time of that File */
+ if(!GetFileTime(TheFileHandle,&Creation,&LastAccess,&LastWrite))
+ {
+ Fail("ERROR: GetFileTime returned 0, indicating failure.");
+ }
+
+ /* Convert the structure to an ULONG64 */
+
+ FirstCreationTime = ((((ULONG64)Creation.dwHighDateTime)<<32) |
+ ((ULONG64)Creation.dwLowDateTime));
+
+ FirstWrite = ((((ULONG64)LastWrite.dwHighDateTime)<<32) |
+ ((ULONG64)LastWrite.dwLowDateTime));
+
+ /* Sleep for 3 seconds, this will ensure the time changes */
+ Sleep(3000);
+
+ /* Write to the file -- this should change write access and
+ last access
+ */
+
+ result = WriteFile(TheFileHandle, // File handle
+ "something", // String to write
+ 9, // Bytes to write
+ &temp, // Bytes written
+ NULL);
+
+ if(result == 0)
+ {
+ Fail("ERROR: Failed to write to file. The file must be "
+ "written to in order to test that the write time is "
+ "updated.");
+ }
+
+ /* Close the File, so the changes are recorded */
+ result = CloseHandle(TheFileHandle);
+
+ if(result == 0)
+ {
+ Fail("ERROR: Failed to close the file handle.");
+ }
+
+
+ /* Reopen the file */
+ TheFileHandle =
+ CreateFile(
+ "the_file", /* file name */
+ GENERIC_READ|GENERIC_WRITE, /* access mode */
+ 0, /* share mode */
+ NULL, /* SD */
+ OPEN_ALWAYS, /* how to create */
+ FILE_ATTRIBUTE_NORMAL, /* file attributes */
+ NULL /* handle to template file */
+ );
+
+
+ if(TheFileHandle == INVALID_HANDLE_VALUE)
+ {
+ Fail("ERROR: Failed to re-open the file. The error number "
+ "returned was %d.",GetLastError());
+ }
+
+
+
+ /* Call GetFileTime again */
+ if(!GetFileTime(TheFileHandle,&Creation,&LastAccess,&LastWrite))
+ {
+ Fail("ERROR: GetFileTime returned 0, indicating failure.");
+ }
+
+ /* Store the results in a ULONG64 */
+
+ SecondCreationTime = ( (((ULONG64)Creation.dwHighDateTime)<<32) |
+ ((ULONG64)Creation.dwLowDateTime));
+
+ SecondWrite = ( (((ULONG64)LastWrite.dwHighDateTime)<<32) |
+ ((ULONG64)LastWrite.dwLowDateTime));
+
+
+ /* Now -- to test. We'll ensure that the Second
+ LastWrite time is larger than the first. It tells us that
+ time is passing, which is good!
+ */
+
+ if(FirstWrite >= SecondWrite)
+ {
+ Fail("ERROR: The last-write-file-time after writing did not "
+ "increase from the original. The second value should be "
+ "larger.");
+ }
+
+#if WIN32
+ /* Then we can check to make sure that the creation time
+ hasn't changed. This should always stay the same.
+ */
+
+ if(FirstCreationTime != SecondCreationTime)
+ {
+ Fail("ERROR: The creation time after writing should not "
+ "not change from the original. The second value should be "
+ "equal.");
+ }
+#else
+ /* Then we can check to make sure that the creation time
+ has changed. Under FreeBSD it changes whenever the file is
+ access or written.
+ */
+
+ if(FirstCreationTime >= SecondCreationTime)
+ {
+ Fail("ERROR: The creation time after writing should be "
+ "greater than the original. The second value should be "
+ "larger.");
+ }
+
+#endif
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/file_io/GetFileTime/test1/testinfo.dat b/src/pal/tests/palsuite/file_io/GetFileTime/test1/testinfo.dat
new file mode 100644
index 0000000000..50cd35214d
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileTime/test1/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = GetFileTime
+Name = Positive Test for GetFileTime
+TYPE = DEFAULT
+EXE1 = getfiletime
+Description
+= Test the GetFileTime function. Open a file and get the time. Then write
+= to that file. This will change the write and under FreeBSD
+= the creation time. Ensure that all of these are increasing.
diff --git a/src/pal/tests/palsuite/file_io/GetFileTime/test2/CMakeLists.txt b/src/pal/tests/palsuite/file_io/GetFileTime/test2/CMakeLists.txt
new file mode 100644
index 0000000000..3d315e44de
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileTime/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ GetFileTime.c
+)
+
+add_executable(paltest_getfiletime_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getfiletime_test2 coreclrpal)
+
+target_link_libraries(paltest_getfiletime_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/GetFileTime/test2/GetFileTime.c b/src/pal/tests/palsuite/file_io/GetFileTime/test2/GetFileTime.c
new file mode 100644
index 0000000000..5b14a1e357
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileTime/test2/GetFileTime.c
@@ -0,0 +1,195 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: GetFileTime.c
+**
+** Purpose: Tests the PAL implementation of the GetFileTime function
+** Test to see that access date either stays the same or increases
+** when a read is performed. Write
+** and creation time should stay unchanged. Note: Under FreeBSD
+** the Creation time should not change with just a read.
+**
+** Depends:
+** FileTimeToDosDateTime
+** CreateFile
+** ReadFile
+** CloseHandle
+**
+**
+**===================================================================*/
+
+
+#include <palsuite.h>
+
+
+int __cdecl main(int argc, char **argv)
+{
+
+ FILETIME Creation,LastAccess,LastWrite;
+ HANDLE TheFileHandle;
+ ULONG64 FirstWrite, SecondWrite,
+ FirstCreationTime, SecondCreationTime;
+ DWORD temp;
+ char ReadBuffer[10];
+ BOOL result;
+ WORD DosDateOne, DosDateTwo, DosTime;
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ /* Open the file to get a HANDLE */
+ TheFileHandle =
+ CreateFile(
+ "the_file",
+ GENERIC_READ,
+ 0,
+ NULL,
+ OPEN_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+
+ if(TheFileHandle == INVALID_HANDLE_VALUE)
+ {
+ Fail("ERROR: Failed to open the file. The error number "
+ "returned was %d.",GetLastError());
+ }
+
+
+ /* Get the Last Write, Creation and Access File time of that File */
+ if(GetFileTime(TheFileHandle,&Creation,&LastAccess,&LastWrite)==0)
+ {
+ Fail("ERROR: GetFileTime returned 0, indicating failure.");
+ }
+
+ /* Call FileTimeToDosDateTime so we can aquire just the date
+ portion of the Last Access FILETIME.
+ */
+ if(FileTimeToDosDateTime(&LastAccess, &DosDateOne, &DosTime) == 0)
+ {
+ Fail("ERROR: FiletimeToDosDateTime failed, returning 0. "
+ "GetLastError returned %d.\n",GetLastError());
+ }
+
+ /* Convert the structure to an ULONG64 */
+
+ FirstCreationTime = ( (((ULONG64)Creation.dwHighDateTime)<<32) |
+ ((ULONG64)Creation.dwLowDateTime));
+
+ FirstWrite = ( (((ULONG64)LastWrite.dwHighDateTime)<<32) |
+ ((ULONG64)LastWrite.dwLowDateTime));
+
+ /* Sleep for 3 seconds, this will ensure the time changes */
+ Sleep(3000);
+
+ /* Read from the file -- this should change
+ last access, but we'll only check the date portion, because some file
+ systems have a resolution of a day.
+ */
+
+ result = ReadFile(TheFileHandle, // handle to file
+ &ReadBuffer, // data buffer
+ 2, // number of bytes to read
+ &temp, // number of bytes read
+ NULL);
+
+ if(result == 0)
+ {
+ Fail("ERROR: Failed to read from the file.");
+ }
+
+
+ /* Close the File, so the changes are recorded */
+ result = CloseHandle(TheFileHandle);
+
+ if(result == 0)
+ {
+ Fail("ERROR: Failed to close the file handle.");
+ }
+
+
+ /* Reopen the file */
+ TheFileHandle =
+ CreateFile("the_file", /* file name */
+ GENERIC_READ, /* access mode */
+ 0, /* share mode */
+ NULL, /* SD */
+ OPEN_ALWAYS, /* how to create */
+ FILE_ATTRIBUTE_NORMAL, /* file attributes */
+ NULL /* handle to template file */
+ );
+
+ if(TheFileHandle == INVALID_HANDLE_VALUE)
+ {
+ Fail("ERROR: Failed to re-open the file. The error number "
+ "returned was %d.",GetLastError());
+ }
+
+ /* Call GetFileTime again */
+ if(GetFileTime(TheFileHandle,&Creation,&LastAccess,&LastWrite) == 0)
+ {
+ Fail("ERROR: GetFileTime returned 0, indicating failure.");
+ }
+
+ /* Get the Date of the LastAccessTime here again. */
+ if(FileTimeToDosDateTime(&LastAccess, &DosDateTwo, &DosTime) == 0)
+ {
+ Fail("ERROR: FileTimeToDosDateTime failed, returning 0. "
+ "GetLastError returned %d.\n",GetLastError());
+ }
+
+
+ /* Store the results in a ULONG64 */
+
+ SecondCreationTime = ( (((ULONG64)Creation.dwHighDateTime)<<32) |
+ ((ULONG64)Creation.dwLowDateTime));
+
+ SecondWrite = ( (((ULONG64)LastWrite.dwHighDateTime)<<32) |
+ ((ULONG64)LastWrite.dwLowDateTime));
+
+ /* Now -- to test. We'll ensure that the Second
+ LastWrite time is the same as the first. This shouldn't
+ have changed.
+ */
+
+ if(FirstWrite != SecondWrite)
+ {
+ Fail("ERROR: The last-write-file-time after reading "
+ "increased from the original. The second value should be "
+ "equal.");
+ }
+
+
+ /*
+ For LastAccessTime, just check that the date is greater or equal
+ for the second over the first. The time is not conisered on some
+ file systems. (such as fat32)
+ */
+
+ if(DosDateOne > DosDateTwo)
+ {
+ Fail("ERROR: The last-access-time after reading should have "
+ "stayed the same or increased, but it did not.\n");
+ }
+
+
+ /* Check to ensure CreationTime hasn't changed. This should not
+ have changed in either environment.
+ */
+
+ if(FirstCreationTime != SecondCreationTime)
+ {
+ Fail("ERROR: The creation time after reading should not "
+ "not change from the original. The second value should be "
+ "equal.");
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/file_io/GetFileTime/test2/testinfo.dat b/src/pal/tests/palsuite/file_io/GetFileTime/test2/testinfo.dat
new file mode 100644
index 0000000000..a60dcf45a4
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileTime/test2/testinfo.dat
@@ -0,0 +1,16 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = GetFileTime
+Name = Positive Test for GetFileTime
+TYPE = DEFAULT
+EXE1 = getfiletime
+Description
+= Tests the PAL implementation of the GetFileTime function
+= Test to see that access date either stays the same or increases
+= when a read is performed. Write
+= and creation time should stay unchanged. Note: Under FreeBSD
+= the Creation time should not change with just a read.
diff --git a/src/pal/tests/palsuite/file_io/GetFileTime/test3/CMakeLists.txt b/src/pal/tests/palsuite/file_io/GetFileTime/test3/CMakeLists.txt
new file mode 100644
index 0000000000..34f7310464
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileTime/test3/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ GetFileTime.c
+)
+
+add_executable(paltest_getfiletime_test3
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getfiletime_test3 coreclrpal)
+
+target_link_libraries(paltest_getfiletime_test3
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/GetFileTime/test3/GetFileTime.c b/src/pal/tests/palsuite/file_io/GetFileTime/test3/GetFileTime.c
new file mode 100644
index 0000000000..a3f46c2bf8
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileTime/test3/GetFileTime.c
@@ -0,0 +1,142 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: GetFileTime.c
+**
+** Purpose: Tests the PAL implementation of the GetFileTime function
+** Test to see that creation time is changed when two different files
+** are created.
+**
+** Depends:
+** CreateFile
+** ReadFile
+** CloseHandle
+**
+**
+**===================================================================*/
+
+
+#include <palsuite.h>
+
+
+int __cdecl main(int argc, char **argv)
+{
+
+ FILETIME Creation;
+ HANDLE TheFileHandle, SecondFileHandle;
+ ULONG64 FirstCreationTime, SecondCreationTime;
+ BOOL result;
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ /* Open the file to get a HANDLE */
+ TheFileHandle =
+ CreateFile(
+ "the_file",
+ GENERIC_READ,
+ 0,
+ NULL,
+ OPEN_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+
+ if(TheFileHandle == INVALID_HANDLE_VALUE)
+ {
+ Fail("ERROR: Failed to open the file. The error number "
+ "returned was %d.",GetLastError());
+ }
+
+
+ /* Get the Creation time of the File */
+ if(GetFileTime(TheFileHandle,&Creation,NULL,NULL)==0)
+ {
+ Fail("ERROR: GetFileTime returned 0, indicating failure. "
+ "Two of the params were NULL in this case, did they "
+ "cause the probleM?");
+ }
+
+ /* Convert the structure to an ULONG64 */
+
+ FirstCreationTime = ( (((ULONG64)Creation.dwHighDateTime)<<32) |
+ ((ULONG64)Creation.dwLowDateTime));
+
+
+ /* Close the File, so the changes are recorded */
+ result = CloseHandle(TheFileHandle);
+
+ if(result == 0)
+ {
+ Fail("ERROR: Failed to close the file handle.");
+ }
+
+
+ /* Sleep for 3 seconds, this will ensure the time changes */
+ Sleep(3000);
+
+
+
+ /* Open another file */
+ SecondFileHandle =
+ CreateFile("the_other_file", /* file name */
+ GENERIC_READ, /* access mode */
+ 0, /* share mode */
+ NULL, /* SD */
+ CREATE_ALWAYS, /* how to create */
+ FILE_ATTRIBUTE_NORMAL, /* file attributes */
+ NULL /* handle to template file */
+ );
+
+ if(SecondFileHandle == INVALID_HANDLE_VALUE)
+ {
+ Fail("ERROR: Failed to open the second file. The error number "
+ "returned was %d.",GetLastError());
+ }
+
+
+ /* Call GetFileTime again */
+ if(GetFileTime(SecondFileHandle,&Creation,NULL,NULL) == 0)
+ {
+ Fail("ERROR: GetFileTime returned 0, indicating failure. "
+ "Perhaps the NULLs in the function broke it?");
+ }
+
+ /* Close the File*/
+ result = CloseHandle(SecondFileHandle);
+
+ if(result == 0)
+ {
+ Fail("ERROR: Failed to close the file handle.");
+ }
+
+
+ /* Store the results in a ULONG64 */
+
+ SecondCreationTime = ( (((ULONG64)Creation.dwHighDateTime)<<32) |
+ ((ULONG64)Creation.dwLowDateTime));
+
+
+
+ /* Now -- to test. We ensure that the FirstCreationTime is
+ less than the SecondCreationTime
+ */
+
+
+ if(FirstCreationTime >= SecondCreationTime)
+ {
+ Fail("ERROR: The creation time of the two files should be "
+ "different. The first file should have a creation "
+ "time less than the second.");
+ }
+
+
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/file_io/GetFileTime/test3/testinfo.dat b/src/pal/tests/palsuite/file_io/GetFileTime/test3/testinfo.dat
new file mode 100644
index 0000000000..6d1eba739d
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileTime/test3/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = GetFileTime
+Name = Positive Test for GetFileTime
+TYPE = DEFAULT
+EXE1 = getfiletime
+Description
+= Test the GetFileTime function. This test creates two files and compares
+= their creation times. They should be different. It also tries to get the
+= file time of an invalid handle, which should cause the function to tail.
diff --git a/src/pal/tests/palsuite/file_io/GetFileTime/test4/CMakeLists.txt b/src/pal/tests/palsuite/file_io/GetFileTime/test4/CMakeLists.txt
new file mode 100644
index 0000000000..0c9dcf7802
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileTime/test4/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ GetFileTime.c
+)
+
+add_executable(paltest_getfiletime_test4
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getfiletime_test4 coreclrpal)
+
+target_link_libraries(paltest_getfiletime_test4
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/GetFileTime/test4/GetFileTime.c b/src/pal/tests/palsuite/file_io/GetFileTime/test4/GetFileTime.c
new file mode 100644
index 0000000000..ffba516e35
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileTime/test4/GetFileTime.c
@@ -0,0 +1,98 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: GetFileTime.c
+**
+** Purpose: Tests the PAL implementation of the GetFileTime function
+** Test to see that passing NULL values to GetFileTime works and that
+** calling the function on a bad HANDLE causes the correct failure.
+**
+** Depends:
+** CreateFile
+** CloseHandle
+**
+**
+**===================================================================*/
+
+
+#include <palsuite.h>
+
+
+int __cdecl main(int argc, char **argv)
+{
+
+ FILETIME Creation,LastWrite,LastAccess;
+ HANDLE TheFileHandle;
+ BOOL result;
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ /* Open the file to get a HANDLE */
+ TheFileHandle =
+ CreateFile(
+ "the_file",
+ GENERIC_READ,
+ 0,
+ NULL,
+ OPEN_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+
+ if(TheFileHandle == INVALID_HANDLE_VALUE)
+ {
+ Fail("ERROR: Failed to open the file. The error number "
+ "returned was %d.",GetLastError());
+ }
+
+ /* Pass all NULLs, this is useless but should still work. */
+ if(GetFileTime(TheFileHandle,NULL,NULL,NULL)==0)
+ {
+ Fail("ERROR: GetFileTime returned 0, indicating failure. "
+ "Three of the params were NULL in this case, did they "
+ "cause the problem?");
+ }
+
+
+ /* Get the Creation time of the File */
+ if(GetFileTime(TheFileHandle,&Creation,NULL,NULL)==0)
+ {
+ Fail("ERROR: GetFileTime returned 0, indicating failure. "
+ "Two of the params were NULL in this case, did they "
+ "cause the probleM?");
+ }
+
+ /* Get the Creation, LastWrite time of the File */
+ if(GetFileTime(TheFileHandle,&Creation,&LastWrite,NULL)==0)
+ {
+ Fail("ERROR: GetFileTime returned 0, indicating failure. "
+ "One of the params were NULL in this case, did it "
+ "cause the problem?");
+ }
+
+
+ /* Close the File, so the changes are recorded */
+ result = CloseHandle(TheFileHandle);
+
+ if(result == 0)
+ {
+ Fail("ERROR: Failed to close the file handle.");
+ }
+
+ /* Call GetFileTime again */
+ if(GetFileTime(TheFileHandle,&Creation,&LastWrite,&LastAccess) != 0)
+ {
+ Fail("ERROR: GetFileTime returned non zero, indicating success. "
+ "It was passed an invalid file HANDLE and should have "
+ "failed.");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/file_io/GetFileTime/test4/testinfo.dat b/src/pal/tests/palsuite/file_io/GetFileTime/test4/testinfo.dat
new file mode 100644
index 0000000000..af90558cae
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileTime/test4/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = GetFileTime
+Name = Positive Test for GetFileTime
+TYPE = DEFAULT
+EXE1 = getfiletime
+Description
+= Test the GetFileTime function. This test gets the file time of a given
+= file while passing all the combonations of NULL as parameters. The
+= function should handle these as unneeded times, and still succeed.
diff --git a/src/pal/tests/palsuite/file_io/GetFileTime/test5/CMakeLists.txt b/src/pal/tests/palsuite/file_io/GetFileTime/test5/CMakeLists.txt
new file mode 100644
index 0000000000..a82717e657
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileTime/test5/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ getfiletime.c
+)
+
+add_executable(paltest_getfiletime_test5
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getfiletime_test5 coreclrpal)
+
+target_link_libraries(paltest_getfiletime_test5
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/GetFileTime/test5/getfiletime.c b/src/pal/tests/palsuite/file_io/GetFileTime/test5/getfiletime.c
new file mode 100644
index 0000000000..d8196d84bc
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileTime/test5/getfiletime.c
@@ -0,0 +1,224 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: GetFileTime.c
+**
+** Purpose: Test the PAL implementation of GetFileTime. This test
+** creates a file and compares create and write times between
+** writes, but before the close, and verifies the results are
+** as expected
+**
+** Depends:
+** CreateFile
+** WriteFile
+** CloseHandle
+**
+**
+**===================================================================*/
+
+
+#include <palsuite.h>
+
+
+int __cdecl main(int argc, char **argv)
+{
+ FILETIME Creation;
+ FILETIME LastAccess;
+ FILETIME LastWrite;
+ HANDLE hFile;
+ ULONG64 FirstWrite;
+ ULONG64 SecondWrite;
+ ULONG64 FirstCreationTime;
+ ULONG64 SecondCreationTime;
+ DWORD temp;
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ /* Open the file to get a HANDLE */
+ hFile = CreateFile("test.tmp",
+ GENERIC_READ|GENERIC_WRITE,
+ 0,
+ NULL,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if(hFile == INVALID_HANDLE_VALUE)
+ {
+ Fail("ERROR: Failed to create the file. The error number "
+ "returned was %u.\n",
+ GetLastError());
+ }
+
+ /* Write to the file -- this should change write access and
+ last access
+ */
+ if(!WriteFile(hFile, "something", 9, &temp, NULL))
+ {
+ Trace("ERROR: Failed to write to file. The file must be "
+ "written to in order to test that the write time is "
+ "updated. GetLastError returned %u.\n",
+ GetLastError());
+ /* Close the File */
+ if(!CloseHandle(hFile))
+ {
+ Trace("ERROR: Failed to close the file handle. "
+ "GetLastError returned %u.\n",
+ GetLastError());
+ }
+ Fail("");
+ }
+
+ FlushFileBuffers(hFile);
+
+ /* Get the Last Write, Creation and Access File time of that File */
+ if(!GetFileTime(hFile, &Creation, &LastAccess, &LastWrite))
+ {
+ Trace("ERROR: GetFileTime returned 0, indicating failure."
+ " GetLastError returned %u\n",
+ GetLastError());
+ /* Close the File */
+ if(!CloseHandle(hFile))
+ {
+ Trace("ERROR: Failed to close the file handle. "
+ "GetLastError returned %u.\n",
+ GetLastError());
+ }
+ Fail("");
+ }
+
+ /* Convert the structure to an ULONG64 */
+
+ FirstCreationTime = ((((ULONG64)Creation.dwHighDateTime)<<32) |
+ ((ULONG64)Creation.dwLowDateTime));
+
+ FirstWrite = ((((ULONG64)LastWrite.dwHighDateTime)<<32) |
+ ((ULONG64)LastWrite.dwLowDateTime));
+
+ /* Sleep for 3 seconds, this will ensure the time changes */
+ Sleep(3000);
+
+ /* Write to the file again -- this should change write access and
+ last access
+ */
+ if(!WriteFile(hFile, "something", 9, &temp, NULL))
+ {
+ Trace("ERROR: Failed to write to file. The file must be "
+ "written to in order to test that the write time is "
+ "updated. GetLastError returned %u.\n",
+ GetLastError());
+ /* Close the File */
+ if(!CloseHandle(hFile))
+ {
+ Trace("ERROR: Failed to close the file handle. "
+ "GetLastError returned %u.\n",
+ GetLastError());
+ }
+ Fail("");
+ }
+
+
+ FlushFileBuffers(hFile);
+
+ /* Call GetFileTime again */
+ if(!GetFileTime(hFile,&Creation,&LastAccess,&LastWrite))
+ {
+ Trace("ERROR: GetFileTime returned 0, indicating failure."
+ "GetLastError returned %u.\n",
+ GetLastError());
+ /* Close the File */
+ if(!CloseHandle(hFile))
+ {
+ Trace("ERROR: Failed to close the file handle. "
+ "GetLastError returned %u.\n",
+ GetLastError());
+ }
+ Fail("");
+ }
+
+ /* Store the results in a ULONG64 */
+
+ SecondCreationTime = ( (((ULONG64)Creation.dwHighDateTime)<<32) |
+ ((ULONG64)Creation.dwLowDateTime));
+
+ SecondWrite = ( (((ULONG64)LastWrite.dwHighDateTime)<<32) |
+ ((ULONG64)LastWrite.dwLowDateTime));
+
+
+ /* Now -- to test. We'll ensure that the Second
+ LastWrite time is larger than the first. It tells us that
+ time is passing, which is good!
+ */
+
+ if(FirstWrite >= SecondWrite)
+ {
+ /* Close the File */
+ if(!CloseHandle(hFile))
+ {
+ Trace("ERROR: Failed to close the file handle. "
+ "GetLastError returned %u.\n",
+ GetLastError());
+ }
+ Fail("ERROR: The last-write-file-time after writing did not "
+ "increase from the original. The second value should be "
+ "larger.\n");
+ }
+
+#if WIN32
+ /* Then we can check to make sure that the creation time
+ hasn't changed. This should always stay the same.
+ */
+
+ if(FirstCreationTime != SecondCreationTime)
+ {
+ /* Close the File */
+ if(!CloseHandle(hFile))
+ {
+ Trace("ERROR: Failed to close the file handle. "
+ "GetLastError returned %u.\n",
+ GetLastError());
+ }
+ Fail("ERROR: The creation time after writing should not "
+ "not change from the original. The second value should be "
+ "equal.\n");
+ }
+#else
+ /* Then we can check to make sure that the creation time
+ has changed. Under FreeBSD it changes whenever the file is
+ access or written.
+ */
+
+ if(FirstCreationTime >= SecondCreationTime)
+ {
+ /* Close the File */
+ if(!CloseHandle(hFile))
+ {
+ Trace("ERROR: Failed to close the file handle. "
+ "GetLastError returned %u.\n",
+ GetLastError());
+ }
+ Fail("ERROR: The creation time after writing should be "
+ "greater than the original. The second value should be "
+ "larger.\n");
+ }
+
+#endif
+
+ /* Close the File */
+ if(!CloseHandle(hFile))
+ {
+ Fail("ERROR: Failed to close the file handle. "
+ "GetLastError returned %u.\n",
+ GetLastError());
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/file_io/GetFileTime/test5/testinfo.dat b/src/pal/tests/palsuite/file_io/GetFileTime/test5/testinfo.dat
new file mode 100644
index 0000000000..fd4112b1fa
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileTime/test5/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = GetFileTime
+Name = Positive Test for GetFileTime
+TYPE = DEFAULT
+EXE1 = getfiletime
+Description
+= Test the PAL implementation of GetFileTime. This test
+= creates a file and compares create and write times between
+= writes, but before the close, and verifies the results are
+= as expected
diff --git a/src/pal/tests/palsuite/file_io/GetFileTime/test6/CMakeLists.txt b/src/pal/tests/palsuite/file_io/GetFileTime/test6/CMakeLists.txt
new file mode 100644
index 0000000000..24992dfa66
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileTime/test6/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ getfiletime.c
+)
+
+add_executable(paltest_getfiletime_test6
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getfiletime_test6 coreclrpal)
+
+target_link_libraries(paltest_getfiletime_test6
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/GetFileTime/test6/getfiletime.c b/src/pal/tests/palsuite/file_io/GetFileTime/test6/getfiletime.c
new file mode 100644
index 0000000000..3eedddf82d
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileTime/test6/getfiletime.c
@@ -0,0 +1,281 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: GetFileTime.c
+**
+** Purpose: Tests the PAL implementation of the GetFileTime function.
+** Perform two reads from a file without closing until the end
+** of the test and verify that only the access times change.
+** Note: Under Win32, modify time changes as well so we will
+** check that it doesn't go backwards
+**
+** Depends:
+** FileTimeToDosDateTime
+** CreateFile
+** ReadFile
+** WriteFile
+** CloseHandle
+**
+**
+**===================================================================*/
+
+
+#include <palsuite.h>
+
+
+int __cdecl main(int argc, char **argv)
+{
+
+ FILETIME Creation;
+ FILETIME LastAccess;
+ FILETIME LastWrite;
+ HANDLE hFile;
+ ULONG64 FirstWrite = (ULONG64)0;
+ ULONG64 SecondWrite = (ULONG64)0;
+ ULONG64 FirstCreationTime = (ULONG64)0;
+ ULONG64 SecondCreationTime = (ULONG64)0;
+ DWORD temp;
+ char ReadBuffer[10];
+ WORD DosDateOne;
+ WORD DosDateTwo;
+ WORD DosTime;
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+ memset(&Creation, 0, sizeof(FILETIME));
+ memset(&LastAccess, 0, sizeof(FILETIME));
+ memset(&LastWrite, 0, sizeof(FILETIME));
+
+ /* Create the file to get a HANDLE */
+ hFile = CreateFile("test.tmp",
+ GENERIC_READ|GENERIC_WRITE,
+ 0,
+ NULL,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if(hFile == INVALID_HANDLE_VALUE)
+ {
+ Fail("ERROR: Failed to create the file. The error number "
+ "returned was %u.\n",
+ GetLastError());
+ }
+
+ /* give us something to read from the file */
+ if(!WriteFile(hFile, "something", 9, &temp, NULL))
+ {
+ Trace("ERROR: Failed to write to file. "
+ "GetLastError returned %u.\n",
+ GetLastError());
+ /* Close the File */
+ if(!CloseHandle(hFile))
+ {
+ Trace("ERROR: Failed to close the file handle. "
+ "GetLastError returned %u.\n",
+ GetLastError());
+ }
+ Fail("");
+ }
+
+ /* let's do a read to set the file times for our test */
+ if(!ReadFile(hFile, &ReadBuffer, 2, &temp, NULL))
+ {
+ Trace("ERROR: Failed to read from the file. "
+ "GetLastError returned %u.\n",
+ GetLastError());
+ /* Close the File */
+ if(!CloseHandle(hFile))
+ {
+ Trace("ERROR: Failed to close the file handle. "
+ "GetLastError returned %u.\n",
+ GetLastError());
+ }
+ Fail("");
+ }
+
+ /* Get the Last Write, Creation and Access File time of the file */
+ if(GetFileTime(hFile, &Creation, &LastAccess, &LastWrite)==0)
+ {
+ Trace("ERROR: GetFileTime returned 0, indicating failure."
+ " GetLastError returned %u\n",
+ GetLastError());
+ /* Close the File */
+ if(!CloseHandle(hFile))
+ {
+ Trace("ERROR: Failed to close the file handle. "
+ "GetLastError returned %u.\n",
+ GetLastError());
+ }
+ Fail("");
+ }
+
+ /* Call FileTimeToDosDateTime so we can aquire just the date
+ portion of the Last Access FILETIME.
+ */
+ if(FileTimeToDosDateTime(&LastAccess, &DosDateOne, &DosTime) == 0)
+ {
+ Trace("ERROR: FiletimeToDosDateTime failed, returning 0. "
+ "GetLastError returned %u.\n",
+ GetLastError());
+ /* Close the File */
+ if(!CloseHandle(hFile))
+ {
+ Trace("ERROR: Failed to close the file handle. "
+ "GetLastError returned %u.\n",
+ GetLastError());
+ }
+ Fail("");
+ }
+
+ /* Convert the structure to an ULONG64 */
+ FirstCreationTime = ( (((ULONG64)Creation.dwHighDateTime)<<32) |
+ ((ULONG64)Creation.dwLowDateTime));
+
+ FirstWrite = ( (((ULONG64)LastWrite.dwHighDateTime)<<32) |
+ ((ULONG64)LastWrite.dwLowDateTime));
+
+ /* Sleep for 3 seconds, this will ensure the time changes */
+ Sleep(3000);
+
+ /* Read from the file -- this should change
+ last access, but we'll only check the date portion, because some file
+ systems have a resolution of a day.
+ */
+ memset(&Creation, 0, sizeof(FILETIME));
+ memset(&LastAccess, 0, sizeof(FILETIME));
+ memset(&LastWrite, 0, sizeof(FILETIME));
+
+ if(!ReadFile(hFile, &ReadBuffer, 2, &temp, NULL))
+ {
+ Trace("ERROR: Failed to read from the file. "
+ "GetLastError returned %u.\n",
+ GetLastError());
+ /* Close the File */
+ if(!CloseHandle(hFile))
+ {
+ Trace("ERROR: Failed to close the file handle. "
+ "GetLastError returned %u.\n",
+ GetLastError());
+ }
+ Fail("");
+ }
+
+
+ /* Call GetFileTime to get the updated time values*/
+ if(GetFileTime(hFile, &Creation, &LastAccess, &LastWrite) == 0)
+ {
+ Trace("ERROR: GetFileTime returned 0, indicating failure. "
+ "GetLastError returned %d.\n",
+ GetLastError());
+ /* Close the File */
+ if(!CloseHandle(hFile))
+ {
+ Trace("ERROR: Failed to close the file handle. "
+ "GetLastError returned %u.\n",
+ GetLastError());
+ }
+ Fail("");
+ }
+
+ /* Get the Date of the LastAccessTime here again. */
+ if(FileTimeToDosDateTime(&LastAccess, &DosDateTwo, &DosTime) == 0)
+ {
+ Trace("ERROR: FileTimeToDosDateTime failed, returning 0. "
+ "GetLastError returned %d.\n",
+ GetLastError());
+ /* Close the File */
+ if(!CloseHandle(hFile))
+ {
+ Trace("ERROR: Failed to close the file handle. "
+ "GetLastError returned %u.\n",
+ GetLastError());
+ }
+ Fail("");
+ }
+
+
+ /* Store the results in a ULONG64 */
+ SecondCreationTime = ( (((ULONG64)Creation.dwHighDateTime)<<32) |
+ ((ULONG64)Creation.dwLowDateTime));
+
+ SecondWrite = ( (((ULONG64)LastWrite.dwHighDateTime)<<32) |
+ ((ULONG64)LastWrite.dwLowDateTime));
+
+ /* Now -- to test. We'll ensure that the SecondWrite
+ time is not less than the FirstWrite time
+ */
+
+ if(SecondWrite < FirstWrite)
+ {
+ Trace("ERROR: The write-file-time (%I64d) after the first read "
+ "is less than the write-file-time (%I64d) after the second "
+ "read.\n",
+ FirstWrite,
+ LastWrite);
+ /* Close the File */
+ if(!CloseHandle(hFile))
+ {
+ Trace("ERROR: Failed to close the file handle. "
+ "GetLastError returned %u.\n",
+ GetLastError());
+ }
+ Fail("");
+ }
+
+ /*
+ For LastAccessTime, just check that the date is greater or equal
+ for the second over the first. The time is not conisered on some
+ file systems. (such as fat32)
+ */
+
+ if(DosDateOne > DosDateTwo)
+ {
+ Trace("ERROR: The last-access-time after reading should have "
+ "stayed the same or increased, but it did not.\n");
+ /* Close the File */
+ if(!CloseHandle(hFile))
+ {
+ Trace("ERROR: Failed to close the file handle. "
+ "GetLastError returned %u.\n",
+ GetLastError());
+ }
+ Fail("");
+ }
+
+
+ /* Check to ensure CreationTime hasn't changed. This should not
+ have changed in either environment.
+ */
+
+ if(FirstCreationTime != SecondCreationTime)
+ {
+ Trace("ERROR: The creation time after reading should not "
+ "not change from the original. The second value should be "
+ "equal.\n");
+ /* Close the File */
+ if(!CloseHandle(hFile))
+ {
+ Trace("ERROR: Failed to close the file handle. "
+ "GetLastError returned %u.\n",
+ GetLastError());
+ }
+ Fail("");
+ }
+
+ /* Close the File, so the changes are recorded */
+ if(!CloseHandle(hFile))
+ {
+ Fail("ERROR: Failed to close the file handle. "
+ "GetLastError returned %u.\n",
+ GetLastError());
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/file_io/GetFileTime/test6/testinfo.dat b/src/pal/tests/palsuite/file_io/GetFileTime/test6/testinfo.dat
new file mode 100644
index 0000000000..844043689c
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileTime/test6/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = GetFileTime
+Name = Positive Test for GetFileTime
+TYPE = DEFAULT
+EXE1 = getfiletime
+Description
+= Tests the PAL implementation of the GetFileTime function.
+= Perform two reads from a file without closing until the end
+= of the test and verify that only the access times change.
diff --git a/src/pal/tests/palsuite/file_io/GetFileTime/test7/CMakeLists.txt b/src/pal/tests/palsuite/file_io/GetFileTime/test7/CMakeLists.txt
new file mode 100644
index 0000000000..6646fd9272
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileTime/test7/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ getfiletime.c
+)
+
+add_executable(paltest_getfiletime_test7
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getfiletime_test7 coreclrpal)
+
+target_link_libraries(paltest_getfiletime_test7
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/GetFileTime/test7/getfiletime.c b/src/pal/tests/palsuite/file_io/GetFileTime/test7/getfiletime.c
new file mode 100644
index 0000000000..d33175b8ec
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileTime/test7/getfiletime.c
@@ -0,0 +1,279 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: GetFileTime.c
+**
+** Purpose: Test the PAL implementation of GetFileTime. This test
+** creates a file and compares create and write times after
+** the buffers are flushed, but before the close, and verifies
+** the results are as expected
+**
+** Depends:
+** CreateFile
+** WriteFile
+** FlushFileBuffers
+** CloseHandle
+**
+**
+**===================================================================*/
+
+
+#include <palsuite.h>
+
+
+int __cdecl main(int argc, char **argv)
+{
+ FILETIME Creation;
+ FILETIME LastAccess;
+ FILETIME LastWrite;
+ HANDLE hFile;
+ ULONG64 FirstWrite;
+ ULONG64 SecondWrite;
+ ULONG64 FirstAccess;
+ ULONG64 SecondAccess;
+ ULONG64 FirstCreationTime;
+ ULONG64 SecondCreationTime;
+ DWORD temp;
+ const char* someText = "1234567890123456789012345678901234567890";
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ /* Open the file to get a HANDLE */
+ hFile = CreateFile("test.tmp",
+ GENERIC_READ|GENERIC_WRITE,
+ 0,
+ NULL,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if(hFile == INVALID_HANDLE_VALUE)
+ {
+ Fail("ERROR: Failed to create the file. The error number "
+ "returned was %u.\n",
+ GetLastError());
+ }
+
+ /* Write to the file -- this should change write access and
+ last access
+ */
+ if(!WriteFile(hFile, someText, strlen(someText), &temp, NULL))
+ {
+ Trace("ERROR: Failed to write to file. The file must be "
+ "written to in order to test that the write time is "
+ "updated. GetLastError returned %u.\n",
+ GetLastError());
+ /* Close the File */
+ if(!CloseHandle(hFile))
+ {
+ Trace("ERROR: Failed to close the file handle. "
+ "GetLastError returned %u.\n",
+ GetLastError());
+ }
+ Fail("");
+ }
+
+ /* Flush the buffers */
+ if(!FlushFileBuffers(hFile))
+ {
+ Trace("ERROR: The FlushFileBuffers function failed. "
+ "GetLastError returned %u.\n",
+ GetLastError());
+ /* Close the File */
+ if(!CloseHandle(hFile))
+ {
+ Trace("ERROR: Failed to close the file handle. "
+ "GetLastError returned %u.\n",
+ GetLastError());
+ }
+ Fail("");
+ }
+
+ /* Get the Last Write, Creation and Access File time of that File */
+ if(!GetFileTime(hFile, &Creation, &LastAccess, &LastWrite))
+ {
+ Trace("ERROR: GetFileTime returned 0, indicating failure."
+ " GetLastError returned %u\n",
+ GetLastError());
+ /* Close the File */
+ if(!CloseHandle(hFile))
+ {
+ Trace("ERROR: Failed to close the file handle. "
+ "GetLastError returned %u.\n",
+ GetLastError());
+ }
+ Fail("");
+ }
+
+ /* Convert the structures to an ULONG64 */
+ FirstCreationTime = ((((ULONG64)Creation.dwHighDateTime)<<32) |
+ ((ULONG64)Creation.dwLowDateTime));
+
+ FirstWrite = ((((ULONG64)LastWrite.dwHighDateTime)<<32) |
+ ((ULONG64)LastWrite.dwLowDateTime));
+
+ FirstAccess = ((((ULONG64)LastAccess.dwHighDateTime)<<32) |
+ ((ULONG64)LastAccess.dwLowDateTime));
+
+ /* Sleep for 3 seconds, this will ensure the time changes */
+ Sleep(3000);
+
+ /* Write to the file again so we have something to flush */
+ if(!WriteFile(hFile, someText, strlen(someText), &temp, NULL))
+ {
+ Trace("ERROR: Failed to write to file. The file must be "
+ "written to in order to test that the write time is "
+ "updated. GetLastError returned %u.\n",
+ GetLastError());
+ /* Close the File */
+ if(!CloseHandle(hFile))
+ {
+ Trace("ERROR: Failed to close the file handle. "
+ "GetLastError returned %u.\n",
+ GetLastError());
+ }
+ Fail("");
+ }
+
+ /* Flush the buffers forcing the access/mod time to change */
+ if(!FlushFileBuffers(hFile))
+ {
+ Trace("ERROR: The FlushFileBuffers function failed. "
+ "GetLastError returned %u.\n",
+ GetLastError());
+ /* Close the File */
+ if(!CloseHandle(hFile))
+ {
+ Trace("ERROR: Failed to close the file handle. "
+ "GetLastError returned %u.\n",
+ GetLastError());
+ }
+ Fail("");
+ }
+
+
+ /* Call GetFileTime again */
+ if(!GetFileTime(hFile,&Creation,&LastAccess,&LastWrite))
+ {
+ Trace("ERROR: GetFileTime returned 0, indicating failure."
+ "GetLastError returned %u.\n",
+ GetLastError());
+ /* Close the File */
+ if(!CloseHandle(hFile))
+ {
+ Trace("ERROR: Failed to close the file handle. "
+ "GetLastError returned %u.\n",
+ GetLastError());
+ }
+ Fail("");
+ }
+
+ /* Store the results in a ULONG64 */
+
+ SecondCreationTime = ( (((ULONG64)Creation.dwHighDateTime)<<32) |
+ ((ULONG64)Creation.dwLowDateTime));
+
+ SecondWrite = ( (((ULONG64)LastWrite.dwHighDateTime)<<32) |
+ ((ULONG64)LastWrite.dwLowDateTime));
+
+ SecondAccess = ((((ULONG64)LastAccess.dwHighDateTime)<<32) |
+ ((ULONG64)LastAccess.dwLowDateTime));
+
+
+ /* Now -- to test. We'll ensure that the Second
+ LastWrite and access times are larger than the first.
+ It tells us that time is passing, which is good!
+ */
+
+ if(FirstWrite >= SecondWrite)
+ {
+ /* Close the File */
+ if(!CloseHandle(hFile))
+ {
+ Trace("ERROR: Failed to close the file handle. "
+ "GetLastError returned %u.\n",
+ GetLastError());
+ }
+ Fail("ERROR: The write-file-time (%I64d) after the first flush "
+ "should be less than the write-file-time (%I64d) after the second "
+ "flush.\n",
+ FirstWrite,
+ LastWrite);
+
+ }
+
+
+ if(SecondAccess < FirstAccess)
+ {
+ /* Close the File */
+ if(!CloseHandle(hFile))
+ {
+ Trace("ERROR: Failed to close the file handle. "
+ "GetLastError returned %u.\n",
+ GetLastError());
+ }
+ Fail("ERROR: The access-file-time (%I64d) after the first flush "
+ "should be less than or equal to the access-file-time (%I64d) "
+ "after the second flush.\n",
+ FirstAccess,
+ LastAccess);
+ }
+
+#if WIN32
+ /* Then we can check to make sure that the creation time
+ hasn't changed. This should always stay the same.
+ */
+
+ if(FirstCreationTime != SecondCreationTime)
+ {
+ /* Close the File */
+ if(!CloseHandle(hFile))
+ {
+ Trace("ERROR: Failed to close the file handle. "
+ "GetLastError returned %u.\n",
+ GetLastError());
+ }
+ Fail("ERROR: The creation time after writing should not "
+ "not change from the original. The second value should be "
+ "equal.\n");
+ }
+#else
+ /* Then we can check to make sure that the creation time
+ has changed. Under FreeBSD it changes whenever the file is
+ access or written.
+ */
+
+ if(FirstCreationTime >= SecondCreationTime)
+ {
+ /* Close the File */
+ if(!CloseHandle(hFile))
+ {
+ Trace("ERROR: Failed to close the file handle. "
+ "GetLastError returned %u.\n",
+ GetLastError());
+ }
+ Fail("ERROR: The creation time after writing should be "
+ "greater than the original. The second value should be "
+ "larger.\n");
+ }
+
+#endif
+
+ /* Close the File */
+ if(!CloseHandle(hFile))
+ {
+ Fail("ERROR: Failed to close the file handle. "
+ "GetLastError returned %u.\n",
+ GetLastError());
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/file_io/GetFileTime/test7/testinfo.dat b/src/pal/tests/palsuite/file_io/GetFileTime/test7/testinfo.dat
new file mode 100644
index 0000000000..774f759adc
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileTime/test7/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = GetFileTime
+Name = Positive Test for GetFileTime
+TYPE = DEFAULT
+EXE1 = getfiletime
+Description
+= Test the PAL implementation of GetFileTime. This test
+= creates a file and compares create and write times after
+= the buffers are flushed, but before the close, and verifies
+= the results are as expected
diff --git a/src/pal/tests/palsuite/file_io/GetFileType/CMakeLists.txt b/src/pal/tests/palsuite/file_io/GetFileType/CMakeLists.txt
new file mode 100644
index 0000000000..1962ade358
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileType/CMakeLists.txt
@@ -0,0 +1,6 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+add_subdirectory(test3)
+
diff --git a/src/pal/tests/palsuite/file_io/GetFileType/test1/CMakeLists.txt b/src/pal/tests/palsuite/file_io/GetFileType/test1/CMakeLists.txt
new file mode 100644
index 0000000000..66467e99c5
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileType/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ GetFileType.c
+)
+
+add_executable(paltest_getfiletype_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getfiletype_test1 coreclrpal)
+
+target_link_libraries(paltest_getfiletype_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/GetFileType/test1/GetFileType.c b/src/pal/tests/palsuite/file_io/GetFileType/test1/GetFileType.c
new file mode 100644
index 0000000000..6558c00bdd
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileType/test1/GetFileType.c
@@ -0,0 +1,76 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: GetFileType.c (test 1)
+**
+** Purpose: Tests the PAL implementation of the GetFileType function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+const char* szTextFile = "text.txt";
+
+int __cdecl main(int argc, char *argv[])
+{
+ HANDLE hFile = NULL;
+ DWORD dwRc = 0;
+
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+
+ /* test FILE_TYPE_UNKNOWN */
+ dwRc = GetFileType(hFile);
+ if (dwRc != FILE_TYPE_UNKNOWN)
+ {
+ Fail("GetFileType: ERROR -> Was expecting a return type of "
+ "FILE_TYPE_UNKNOWN but the function returned %ld.\n",
+ dwRc);
+ }
+
+
+ /* create a test file */
+ hFile = CreateFile(szTextFile,
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if(hFile == INVALID_HANDLE_VALUE)
+ {
+ Fail("GetFileType: ERROR -> Unable to create file \"%s\".\n",
+ szTextFile);
+ }
+
+ dwRc = GetFileType(hFile);
+ if (CloseHandle(hFile) != TRUE)
+ {
+ Fail("GetFileType: ERROR -> Unable to close file \"%s\".\n",
+ szTextFile);
+ }
+ if (!DeleteFileA(szTextFile))
+ {
+ Fail("GetFileType: ERROR -> Unable to delete file \"%s\".\n",
+ szTextFile);
+ }
+
+ if (dwRc != FILE_TYPE_DISK)
+ {
+ Fail("GetFileType: ERROR -> Was expecting a return type of "
+ "FILE_TYPE_DISK but the function returned %ld.\n",
+ dwRc);
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/file_io/GetFileType/test1/testinfo.dat b/src/pal/tests/palsuite/file_io/GetFileType/test1/testinfo.dat
new file mode 100644
index 0000000000..f12a81a20b
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileType/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = GetFileType
+Name = Positive Test for GetFileType (test 1)
+Type = DEFAULT
+EXE1 = getfiletype
+Description
+= Test GetFileType on a NULL handle and a valid handle to a file
+
diff --git a/src/pal/tests/palsuite/file_io/GetFileType/test2/CMakeLists.txt b/src/pal/tests/palsuite/file_io/GetFileType/test2/CMakeLists.txt
new file mode 100644
index 0000000000..382b27e788
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileType/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ getfiletype.c
+)
+
+add_executable(paltest_getfiletype_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getfiletype_test2 coreclrpal)
+
+target_link_libraries(paltest_getfiletype_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/GetFileType/test2/getfiletype.c b/src/pal/tests/palsuite/file_io/GetFileType/test2/getfiletype.c
new file mode 100644
index 0000000000..c9d4eb6572
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileType/test2/getfiletype.c
@@ -0,0 +1,95 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: getfiletype.c
+**
+** Purpose: Test the PAL implementation of GetFileType to ensure it
+** recognizes opened pipes.
+**
+** Depends: CreatePipe
+** CloseHandle
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+
+int __cdecl main(int argc, char **argv)
+{
+ HANDLE hReadPipe = NULL;
+ HANDLE hWritePipe = NULL;
+ BOOL bRetVal = FALSE;
+ DWORD dwFileType;
+ SECURITY_ATTRIBUTES lpPipeAttributes;
+
+ /*Initialize the PAL*/
+ if ((PAL_Initialize(argc, argv)) != 0)
+ {
+ return (FAIL);
+ }
+
+ /*
+ ** create a pipe and make sure GetFileType returns the correct value
+ */
+
+ /*Setup SECURITY_ATTRIBUTES structure for CreatePipe*/
+ lpPipeAttributes.nLength = sizeof(lpPipeAttributes);
+ lpPipeAttributes.lpSecurityDescriptor = NULL;
+ lpPipeAttributes.bInheritHandle = TRUE;
+
+ /*Create a Pipe*/
+ bRetVal = CreatePipe(&hReadPipe, /* read handle*/
+ &hWritePipe, /* write handle */
+ &lpPipeAttributes, /* security attributes*/
+ 0); /* pipe size*/
+ if (bRetVal == FALSE)
+ {
+ Fail("ERROR: %u :Unable to create pipe.\n", GetLastError());
+ }
+
+ // Get the file type
+ dwFileType = GetFileType(hReadPipe);
+ if (dwFileType != FILE_TYPE_PIPE)
+ {
+ if (!CloseHandle(hWritePipe))
+ {
+ Trace("ERROR: %u : Unable to close write pipe handle "
+ "hWritePipe=0x%lx\n", GetLastError(), hWritePipe);
+ }
+ if (!CloseHandle(hReadPipe))
+ {
+ Trace("ERROR: %u : Unable to close read pipe handle "
+ "hReadPipe=0x%lx\n", GetLastError(), hReadPipe);
+ }
+ Fail("ERROR: GetFileType returned %u for a pipe instead of the "
+ "expected FILE_TYPE_PIPE (%u).\n",
+ dwFileType,
+ FILE_TYPE_PIPE);
+ }
+
+ /*Close write pipe handle*/
+ if (!CloseHandle(hWritePipe))
+ {
+ if (!CloseHandle(hReadPipe))
+ {
+ Trace("ERROR: %u : Unable to close read pipe handle "
+ "hReadPipe=0x%lx\n", GetLastError(), hReadPipe);
+ }
+ Fail("ERROR: %u : Unable to close write pipe handle "
+ "hWritePipe=0x%lx\n", GetLastError(), hWritePipe);
+ }
+
+ /*Close Read pipe handle*/
+ if (!CloseHandle(hReadPipe))
+ {
+ Fail("ERROR: %u : Unable to close read pipe handle "
+ "hReadPipe=0x%lx\n", GetLastError(), hReadPipe);
+ }
+
+ PAL_Terminate();
+ return (PASS);
+}
diff --git a/src/pal/tests/palsuite/file_io/GetFileType/test2/testinfo.dat b/src/pal/tests/palsuite/file_io/GetFileType/test2/testinfo.dat
new file mode 100644
index 0000000000..eb1361d3f6
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileType/test2/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = GetFileType
+Name = Test for GetFileType
+TYPE = DEFAULT
+EXE1 = getfiletype
+Description
+= Test the PAL implementation of GetFileType to ensure it
+= recognizes opened pipes.
diff --git a/src/pal/tests/palsuite/file_io/GetFileType/test3/CMakeLists.txt b/src/pal/tests/palsuite/file_io/GetFileType/test3/CMakeLists.txt
new file mode 100644
index 0000000000..52b6077570
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileType/test3/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ getfiletype.c
+)
+
+add_executable(paltest_getfiletype_test3
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getfiletype_test3 coreclrpal)
+
+target_link_libraries(paltest_getfiletype_test3
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/GetFileType/test3/getfiletype.c b/src/pal/tests/palsuite/file_io/GetFileType/test3/getfiletype.c
new file mode 100644
index 0000000000..6a95585bab
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileType/test3/getfiletype.c
@@ -0,0 +1,72 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: getfiletype.c
+**
+** Purpose: Test the PAL implementation of the GetFileType on a handle
+** to a console.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ HANDLE hFile;
+#if WIN32
+ char *lpFileName = "CONIN$";
+#else
+ char *lpFileName = "/dev/null";
+#endif
+ DWORD dwFileType;
+
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ /* get a handle to the console */
+ hFile = CreateFile(lpFileName,
+ GENERIC_READ,
+ FILE_SHARE_READ,
+ NULL,
+ OPEN_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+ if (hFile == INVALID_HANDLE_VALUE)
+ {
+ Fail("GetFileType: ERROR: CreateFile failed to open %s with "
+ "error %u.\n",
+ lpFileName,
+ GetLastError());
+ }
+
+ /* Get the file type */
+ if ((dwFileType = GetFileType(hFile)) != FILE_TYPE_CHAR)
+ {
+ if (!CloseHandle(hFile))
+ {
+ Trace("GetFileType: ERROR: %u : Unable to close the handle "
+ "hFile=0x%lx\n", GetLastError(), hFile);
+ }
+ Fail("GetFileType: ERROR: GetFileType returned %u for a device "
+ "instead of the expected FILE_TYPE_CHAR (%u).\n",
+ dwFileType,
+ FILE_TYPE_CHAR);
+ }
+
+ if (!CloseHandle(hFile))
+ {
+ Fail("GetFileType: ERROR: %u : Unable to close the handle "
+ "hFile=0x%lx\n", GetLastError(), hFile);
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/file_io/GetFileType/test3/testinfo.dat b/src/pal/tests/palsuite/file_io/GetFileType/test3/testinfo.dat
new file mode 100644
index 0000000000..9ffd4c2b15
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFileType/test3/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = GetFileType
+Name = Test for GetFileTYpe
+TYPE = DEFAULT
+EXE1 = getfiletype
+Description
+= Test the PAL implementation of the GetFileType on a handle
+= to a console.
diff --git a/src/pal/tests/palsuite/file_io/GetFullPathNameA/CMakeLists.txt b/src/pal/tests/palsuite/file_io/GetFullPathNameA/CMakeLists.txt
new file mode 100644
index 0000000000..a3847f8ca9
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFullPathNameA/CMakeLists.txt
@@ -0,0 +1,7 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+add_subdirectory(test3)
+add_subdirectory(test4)
+
diff --git a/src/pal/tests/palsuite/file_io/GetFullPathNameA/test1/CMakeLists.txt b/src/pal/tests/palsuite/file_io/GetFullPathNameA/test1/CMakeLists.txt
new file mode 100644
index 0000000000..8c10e479fa
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFullPathNameA/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ GetFullPathNameA.c
+)
+
+add_executable(paltest_getfullpathnamea_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getfullpathnamea_test1 coreclrpal)
+
+target_link_libraries(paltest_getfullpathnamea_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/GetFullPathNameA/test1/GetFullPathNameA.c b/src/pal/tests/palsuite/file_io/GetFullPathNameA/test1/GetFullPathNameA.c
new file mode 100644
index 0000000000..de9a266f5a
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFullPathNameA/test1/GetFullPathNameA.c
@@ -0,0 +1,122 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: GetFullPathNameA.c (test 1)
+**
+** Purpose: Tests the PAL implementation of the GetFullPathNameA function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+const char* szFileName = "testing.tmp";
+
+int __cdecl main(int argc, char *argv[])
+{
+ DWORD dwRc = 0;
+ char szReturnedPath[_MAX_DIR+1];
+ char szShortBuff[2];
+ LPSTR pPathPtr;
+ HANDLE hFile = NULL;
+
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ /* perform a short buffer test */
+ if (GetFullPathNameA(szFileName, 2, szShortBuff, &pPathPtr) <= 2)
+ {
+ /* this test should have failed but didn't */
+ Fail("GetFullPathNameA: ERROR -> The API was passed a buffer that was"
+ " too small for the path name and yet it apparently passed.\n");
+ }
+
+ memset(szReturnedPath, 0, _MAX_DIR+1);
+ dwRc = GetFullPathNameA(szFileName,
+ _MAX_DIR,
+ szReturnedPath,
+ &pPathPtr);
+
+ if (dwRc == 0)
+ {
+ // this test should have passed but didn't
+ Fail("GetFullPathNameA: ERROR -> Function failed for the "
+ "file \"%s\" with error code: %ld.\n", szFileName, GetLastError());
+ }
+
+ // the returned value should be the current directory with the
+ // file name appended
+ hFile = CreateFileA(szFileName,
+ GENERIC_READ,
+ FILE_SHARE_READ,
+ NULL,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+ if (hFile == INVALID_HANDLE_VALUE)
+ {
+ Fail("GetFullPathNameA: ERROR -> CreateFileA failed to create "
+ "file \"%s\" with error code: %ld.\n",
+ szFileName,
+ GetLastError());
+ }
+ if (CloseHandle(hFile) != TRUE)
+ {
+ Fail("GetFullPathNameA: ERROR -> CloseHandle failed with error "
+ "code: %ld.\n", GetLastError());
+ }
+
+ // now try to create the file based on the returned value with the
+ // CREATE_NEW option which should fail since the file should
+ // already exist
+ hFile = CreateFileA(szReturnedPath,
+ GENERIC_READ,
+ FILE_SHARE_READ,
+ NULL,
+ CREATE_NEW,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+ if (hFile != INVALID_HANDLE_VALUE)
+ {
+ Fail("GetFullPathNameA: ERROR -> CreateFileA was able to "
+ "CREATE_NEW the returned file \"%s\". The returned file "
+ "name is therefore apparently wrong.\n",
+ szReturnedPath);
+ if (CloseHandle(hFile) != TRUE)
+ {
+ Fail("GetFullPathNameA: ERROR -> CloseHandle failed with "
+ "error code: %ld.\n", GetLastError());
+ }
+ if ((DeleteFileA(szReturnedPath) != TRUE) ||
+ (DeleteFileA(szFileName) != TRUE))
+ {
+ Fail("GetFullPathNameA: ERROR -> DeleteFileA failed to "
+ "delete the test files with error code: %ld.\n",
+ GetLastError());
+ }
+ }
+
+ // now make sure the pPathPtr is the same as the file name
+ if (strcmp(pPathPtr, szFileName) != 0)
+ {
+ Fail("GetFullPathNameA: ERROR -> %s != %s\n",
+ pPathPtr, szFileName);
+ }
+ if (DeleteFileA(szFileName) != TRUE)
+ {
+ Fail("GetFullPathNameA: ERROR -> DeleteFileA failed to "
+ "delete \"%s\" with error code: %ld.\n",
+ szFileName,
+ GetLastError());
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/file_io/GetFullPathNameA/test1/testinfo.dat b/src/pal/tests/palsuite/file_io/GetFullPathNameA/test1/testinfo.dat
new file mode 100644
index 0000000000..a4ccc95348
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFullPathNameA/test1/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = GetFullPathNameA
+Name = Test for GetFullPathNameA (test 1)
+Type = DEFAULT
+EXE1 = getfullpathnamea
+Description
+= Get the full path for a file name and verify the results.
+= Also, attempt to call GetFullPathNameA with a buffer that is
+= too small for the returned path and verify the results.
+
diff --git a/src/pal/tests/palsuite/file_io/GetFullPathNameA/test2/CMakeLists.txt b/src/pal/tests/palsuite/file_io/GetFullPathNameA/test2/CMakeLists.txt
new file mode 100644
index 0000000000..382b8fa4bd
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFullPathNameA/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test2.c
+)
+
+add_executable(paltest_getfullpathnamea_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getfullpathnamea_test2 coreclrpal)
+
+target_link_libraries(paltest_getfullpathnamea_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/GetFullPathNameA/test2/test2.c b/src/pal/tests/palsuite/file_io/GetFullPathNameA/test2/test2.c
new file mode 100644
index 0000000000..95a1497331
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFullPathNameA/test2/test2.c
@@ -0,0 +1,143 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test2.c
+**
+** Purpose: Tests the PAL implementation of the GetFullPathNameA API.
+** GetFullPathA will be passed a directory that contains '..'.
+** To add to this test, we will also call SetCurrentDirectory to
+** ensure this is handled properly.
+** The test will create a file with in the parent directory
+** to verify that the returned directory is valid.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+const char* szDotDot = "..\\";
+const char* szFileName = "testing.tmp";
+
+int __cdecl main(int argc, char *argv[])
+{
+ DWORD dwRc = 0;
+ char szReturnedPath[_MAX_DIR+1];
+ char szFullFileName[_MAX_DIR+1];
+ LPSTR pPathPtr;
+ HANDLE hFile = NULL;
+
+ /* Initialize the PAL.
+ */
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return (FAIL);
+ }
+
+ /* change the directory */
+ if (!SetCurrentDirectoryA(szDotDot))
+ {
+ Fail("ERROR: SetCurrentDirectoryA failed with error code %u"
+ " when passed \"%s\".\n",
+ GetLastError(),
+ szDotDot);
+ }
+
+ /* Initialize the receiving char buffers.
+ */
+ memset(szReturnedPath, 0, _MAX_DIR+1);
+ memset(szFullFileName, 0, _MAX_DIR+1);
+
+ /* Create Full filename to pass, will include '..\'
+ * as a pre-fix. */
+ strcat(szFullFileName, szDotDot);
+ strcat(szFullFileName, szFileName);
+
+ /* Get the full path to the filename.
+ */
+ dwRc = GetFullPathNameA(szFullFileName,
+ _MAX_DIR,
+ szReturnedPath,
+ &pPathPtr);
+ if (dwRc == 0)
+ {
+ Fail("ERROR :%ld: GetFullPathName failed to "
+ "retrieve the path of \"%s\".\n",
+ GetLastError(),
+ szFileName);
+ }
+
+ /* The returned value should be the parent directory with the
+ * file name appended. */
+ hFile = CreateFileA(szReturnedPath,
+ GENERIC_READ,
+ FILE_SHARE_READ,
+ NULL,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if (hFile == INVALID_HANDLE_VALUE)
+ {
+ Fail("ERROR :%ld: CreateFileA failed to create \"%s\".\n",
+ GetLastError(),
+ szReturnedPath);
+ }
+
+ /* Close the handle to the created file.
+ */
+ if (CloseHandle(hFile) != TRUE)
+ {
+ Trace("ERROR :%ld: CloseHandle failed close hFile=0x%lx.\n",
+ GetLastError());
+ goto terminate;
+ }
+
+ /* Verify that the file was created, attempt to create
+ * the file again. */
+ hFile = CreateFileA(szReturnedPath,
+ GENERIC_READ,
+ FILE_SHARE_READ,
+ NULL,
+ CREATE_NEW,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+ if ((hFile != INVALID_HANDLE_VALUE) &&
+ (GetLastError() != ERROR_ALREADY_EXISTS))
+ {
+ Fail("ERROR :%ld: CreateFileA succeeded to create file "
+ "\"%s\", that already existed.\n",
+ GetLastError(),
+ szFullFileName);
+ }
+
+
+ /* Verify that the returned filename is the same as the supplied.
+ */
+ if (strcmp(pPathPtr, szFileName) != 0)
+ {
+ Trace("ERROR : Returned filename \"%s\" is not equal to "
+ "supplied filename \"%s\".\n",
+ pPathPtr,
+ szFileName);
+ goto terminate;
+ }
+
+terminate:
+ /* Delete the create file.
+ */
+ if (DeleteFileA(szReturnedPath) != TRUE)
+ {
+ Fail("ERROR :%ld: DeleteFileA failed to delete \"%s\".\n",
+ GetLastError(),
+ szFileName);
+ }
+
+ /* Terminate the PAL.*/
+ PAL_Terminate();
+ return PASS;
+}
+
+
diff --git a/src/pal/tests/palsuite/file_io/GetFullPathNameA/test2/testinfo.dat b/src/pal/tests/palsuite/file_io/GetFullPathNameA/test2/testinfo.dat
new file mode 100644
index 0000000000..b75f48114b
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFullPathNameA/test2/testinfo.dat
@@ -0,0 +1,18 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = GetFullPathNameA
+Name = Test for GetFullPathNameA
+Type = DEFAULT
+EXE1 = test2
+Description
+= Tests the PAL implementation of the GetFullPathNameA API.
+= GetFullPathA will be passed a directory that contains '..'.
+= To add to this test, we will also call SetCurrentDirectory to
+= ensure this is handled properly.
+= The test will create a file with in the parent directory
+= to verify that the returned directory is valid.
+
diff --git a/src/pal/tests/palsuite/file_io/GetFullPathNameA/test3/CMakeLists.txt b/src/pal/tests/palsuite/file_io/GetFullPathNameA/test3/CMakeLists.txt
new file mode 100644
index 0000000000..f0f8929b4a
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFullPathNameA/test3/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test3.c
+)
+
+add_executable(paltest_getfullpathnamea_test3
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getfullpathnamea_test3 coreclrpal)
+
+target_link_libraries(paltest_getfullpathnamea_test3
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/GetFullPathNameA/test3/test3.c b/src/pal/tests/palsuite/file_io/GetFullPathNameA/test3/test3.c
new file mode 100644
index 0000000000..0cc39e7300
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFullPathNameA/test3/test3.c
@@ -0,0 +1,241 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test3.c
+**
+** Purpose: Tests the PAL implementation of the GetFullPathNameA API.
+** GetFullPathA will be passed a directory that contains '..'.
+** Example: test_directory\level1\..\testing.tmp.
+** To add to this test, we will also call SetCurrentDirectory to
+** ensure this is handled properly.
+** The test will create a file with in the parent directory
+** to verify that the returned directory is valid.
+**
+** Depends: SetCurrentDirectory,
+** CreateDirectory,
+** strcat,
+** memset,
+** CreateFile,
+** CloseHandle,
+** strcmp,
+** DeleteFileA,
+** RemoveDirectory.
+**
+
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+#ifdef WIN32
+ const char* szSeperator = "\\";
+#else
+ const char* szSeperator = "//";
+#endif
+
+const char* szDotDot = "..\\";
+const char* szFileName = "testing.tmp";
+
+int __cdecl main(int argc, char *argv[])
+{
+ DWORD dwRc = 0;
+ char szReturnedPath[_MAX_DIR+1];
+ char szFullFileName[_MAX_DIR+1];
+ char szDirectory[256];
+ char* szCreatedDir = {"test_directory"};
+ char* szCreatedNextDir = {"level1"};
+ WCHAR *szCreatedDirW;
+ LPSTR pPathPtr;
+ HANDLE hFile = NULL;
+ BOOL bRetVal = FAIL;
+
+ /* Initialize the PAL.
+ */
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return (FAIL);
+ }
+
+ /* Initialize the buffer.
+ */
+ memset(szDirectory, '\0', 256);
+
+ /* Change the current working directory.
+ */
+ if (!SetCurrentDirectoryA(szDotDot))
+ {
+ Fail("ERROR: SetCurrentDirectoryA failed with error code %u"
+ " when passed \"%s\".\n",
+ GetLastError(),
+ szDotDot);
+ }
+
+ /* Create the path to the next level of directory to create.
+ */
+ strcat( szDirectory, szCreatedDir );
+
+
+ /* Create a test directory.
+ */
+ if ( !CreateDirectoryA( szDirectory, NULL ) )
+ {
+ Fail("ERROR:%u: Unable to create directories \"%s\".\n",
+ GetLastError(),
+ szDirectory);
+ }
+
+ /* Create the path to the next level of directory to create.
+ */
+ strcat( szDirectory, szSeperator );
+ strcat( szDirectory, szCreatedNextDir );
+
+ /* Create a test directory.
+ */
+ if ( !CreateDirectoryA( szDirectory, NULL ) )
+ {
+ Trace("ERROR:%u: Unable to create directories \"%s\".\n",
+ GetLastError(),
+ szDirectory);
+ bRetVal = FAIL;
+ goto cleanUpOne;
+ }
+
+ /* Initialize the receiving char buffers.
+ */
+ memset(szReturnedPath, 0, _MAX_DIR+1);
+ memset(szFullFileName, 0, _MAX_DIR+1);
+
+ /* Create Full filename to pass, will include '..\'
+ * in the middle of the path.
+ */
+ strcat(szFullFileName, szCreatedDir);
+ strcat(szFullFileName, szDotDot);
+ strcat(szFullFileName, szFileName);
+
+ /* Get the full path to the filename.
+ */
+ dwRc = GetFullPathNameA(szFullFileName,
+ _MAX_DIR,
+ szReturnedPath,
+ &pPathPtr);
+ if (dwRc == 0)
+ {
+ Trace("ERROR :%ld: GetFullPathName failed to "
+ "retrieve the path of \"%s\".\n",
+ GetLastError(),
+ szFileName);
+ bRetVal = FAIL;
+ goto cleanUpTwo;
+ }
+
+ /* The returned value should be the parent directory with the
+ * file name appended. */
+ hFile = CreateFileA(szReturnedPath,
+ GENERIC_READ,
+ FILE_SHARE_READ,
+ NULL,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if (hFile == INVALID_HANDLE_VALUE)
+ {
+ Trace("ERROR :%ld: CreateFileA failed to create \"%s\".\n",
+ GetLastError(),
+ szReturnedPath);
+ bRetVal = FAIL;
+ goto cleanUpTwo;
+ }
+
+ /* Close the handle to the created file.
+ */
+ if (CloseHandle(hFile) != TRUE)
+ {
+ Trace("ERROR :%ld: CloseHandle failed close hFile=0x%lx.\n",
+ GetLastError());
+ bRetVal = FAIL;
+ goto cleanUpThree;
+ }
+
+ /* Verify that the file was created, attempt to create
+ * the file again. */
+ hFile = CreateFileA(szReturnedPath,
+ GENERIC_READ,
+ FILE_SHARE_READ,
+ NULL,
+ CREATE_NEW,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+ if ((hFile != INVALID_HANDLE_VALUE) &&
+ (GetLastError() != ERROR_ALREADY_EXISTS))
+ {
+ Trace("ERROR :%ld: CreateFileA succeeded to create file "
+ "\"%s\", that already existed.\n",
+ GetLastError(),
+ szFullFileName);
+ bRetVal = FAIL;
+ goto cleanUpThree;
+ }
+
+ /* Verify that the returned filename is the same as the supplied.
+ */
+ if (strcmp(pPathPtr, szFileName) != 0)
+ {
+ Trace("ERROR : Returned filename \"%s\" is not equal to "
+ "supplied filename \"%s\".\n",
+ pPathPtr,
+ szFileName);
+ bRetVal = FAIL;
+ goto cleanUpThree;
+ }
+
+ /* Successful test.
+ */
+ bRetVal = PASS;
+
+cleanUpThree:
+
+ /* Delete the create file.
+ */
+ if (DeleteFileA(szReturnedPath) != TRUE)
+ {
+ Fail("ERROR :%ld: DeleteFileA failed to delete \"%s\".\n",
+ GetLastError(),
+ szFileName);
+ }
+
+cleanUpTwo:
+
+ /* Remove the empty directory.
+ */
+ szCreatedDirW = convert((LPSTR)szDirectory);
+ if (!RemoveDirectoryW(szCreatedDirW))
+ {
+ free (szCreatedDirW);
+ Fail("ERROR:%u: Unable to remove directory \"%s\".\n",
+ GetLastError(),
+ szCreatedDir);
+ }
+ free (szCreatedDirW);
+
+cleanUpOne:
+
+ /* Remove the empty directory.
+ */
+ szCreatedDirW = convert((LPSTR)szCreatedDir);
+ if (!RemoveDirectoryW(szCreatedDirW))
+ {
+ free (szCreatedDirW);
+ Fail("ERROR:%u: Unable to remove directory \"%s\".\n",
+ GetLastError(),
+ szCreatedDir);
+ }
+ free (szCreatedDirW);
+
+ /* Terminate the PAL.*/
+ PAL_Terminate();
+ return bRetVal;
+}
diff --git a/src/pal/tests/palsuite/file_io/GetFullPathNameA/test3/testinfo.dat b/src/pal/tests/palsuite/file_io/GetFullPathNameA/test3/testinfo.dat
new file mode 100644
index 0000000000..3991744d42
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFullPathNameA/test3/testinfo.dat
@@ -0,0 +1,19 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = GetFullPathNameA
+Name = Test for GetFullPathNameA
+Type = DEFAULT
+EXE1 = test3
+Description
+= Tests the PAL implementation of the GetFullPathNameA API.
+= GetFullPathA will be passed a directory that contains '..'.
+= Example: test_directory\level1\..\testing.tmp.
+= To add to this test, we will also call SetCurrentDirectory to
+= ensure this is handled properly.
+= The test will create a file with in the parent directory
+= to verify that the returned directory is valid.
+
diff --git a/src/pal/tests/palsuite/file_io/GetFullPathNameA/test4/CMakeLists.txt b/src/pal/tests/palsuite/file_io/GetFullPathNameA/test4/CMakeLists.txt
new file mode 100644
index 0000000000..cf0d7ff18c
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFullPathNameA/test4/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test4.c
+)
+
+add_executable(paltest_getfullpathnamea_test4
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getfullpathnamea_test4 coreclrpal)
+
+target_link_libraries(paltest_getfullpathnamea_test4
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/GetFullPathNameA/test4/test4.c b/src/pal/tests/palsuite/file_io/GetFullPathNameA/test4/test4.c
new file mode 100644
index 0000000000..fb22c1f07b
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFullPathNameA/test4/test4.c
@@ -0,0 +1,203 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test4.c
+**
+** Purpose: Tests the PAL implementation of the GetFullPathNameA API.
+** GetFullPathA will be passed a directory that begins with '..'.
+** Example: ..\test_directory\testing.tmp.
+** To add to this test, we will also call SetCurrentDirectory to
+** ensure this is handled properly.
+** The test will create a file with in the parent directory
+** to verify that the returned directory is valid.
+**
+** Depends: SetCurrentDirectory,
+** CreateDirectory,
+** strcat,
+** memset,
+** CreateFile,
+** CloseHandle,
+** strcmp,
+** DeleteFileA,
+** RemoveDirectory.
+**
+
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+#ifdef WIN32
+ const char* szSeperator = "\\";
+#else
+ const char* szSeperator = "//";
+#endif
+
+const char* szDotDot = "..";
+const char* szFileName = "testing.tmp";
+
+int __cdecl main(int argc, char *argv[])
+{
+ DWORD dwRc = 0;
+ char szReturnedPath[_MAX_DIR+1];
+ char szFullFileName[_MAX_DIR+1];
+ char szDirectory[256];
+ char* szCreatedDir = {"test_directory"};
+ WCHAR *szCreatedDirW;
+ LPSTR pPathPtr;
+ HANDLE hFile = NULL;
+ BOOL bRetVal = FAIL;
+
+ /* Initialize the PAL.
+ */
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return (FAIL);
+ }
+
+ /* Initialize the buffer.
+ */
+ memset(szDirectory, '\0', 256);
+
+ /* Create the path to the next level of directory to create.
+ */
+ strcat( szDirectory, szDotDot ); /* .. */
+ strcat( szDirectory, szSeperator ); /* ../ */
+ strcat( szDirectory, szCreatedDir ); /* ../test_directory */
+
+ /* Create a test directory.
+ */
+ if ( !CreateDirectoryA( szDirectory, NULL ) )
+ {
+ Fail("ERROR:%u: Unable to create directories \"%s\".\n",
+ GetLastError(),
+ szDirectory);
+ }
+
+ /* Initialize the receiving char buffers.
+ */
+ memset(szReturnedPath, 0, _MAX_DIR+1);
+ memset(szFullFileName, 0, _MAX_DIR+1);
+
+ /* Create Full filename to pass, will include '..\'
+ * in the middle of the path.
+ */
+ strcat( szFullFileName, szDotDot ); /* .. */
+ strcat( szFullFileName, szSeperator ); /* ../ */
+ strcat( szFullFileName, szCreatedDir ); /* ../test_directory */
+ strcat( szFullFileName, szSeperator ); /* ../test_directory/ */
+ strcat( szFullFileName, szFileName ); /* ../test_directory/testing.tmp */
+
+ /* Get the full path to the filename.
+ */
+ dwRc = GetFullPathNameA(szFullFileName,
+ _MAX_DIR,
+ szReturnedPath,
+ &pPathPtr);
+ if (dwRc == 0)
+ {
+ Trace("ERROR :%ld: GetFullPathName failed to "
+ "retrieve the path of \"%s\".\n",
+ GetLastError(),
+ szFileName);
+ bRetVal = FAIL;
+ goto cleanUpOne;
+ }
+
+ /* The returned value should be the parent directory with the
+ * file name appended. */
+ hFile = CreateFileA(szReturnedPath,
+ GENERIC_READ,
+ FILE_SHARE_READ,
+ NULL,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if (hFile == INVALID_HANDLE_VALUE)
+ {
+ Trace("ERROR :%ld: CreateFileA failed to create \"%s\".\n",
+ GetLastError(),
+ szReturnedPath);
+ bRetVal = FAIL;
+ goto cleanUpOne;
+ }
+
+ /* Close the handle to the created file.
+ */
+ if (CloseHandle(hFile) != TRUE)
+ {
+ Trace("ERROR :%ld: CloseHandle failed close hFile=0x%lx.\n",
+ GetLastError());
+ bRetVal = FAIL;
+ goto cleanUpTwo;
+ }
+
+ /* Verify that the file was created, attempt to create
+ * the file again. */
+ hFile = CreateFileA(szReturnedPath,
+ GENERIC_READ,
+ FILE_SHARE_READ,
+ NULL,
+ CREATE_NEW,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+ if ((hFile != INVALID_HANDLE_VALUE) &&
+ (GetLastError() != ERROR_ALREADY_EXISTS))
+ {
+ Trace("ERROR :%ld: CreateFileA succeeded to create file "
+ "\"%s\", that already existed.\n",
+ GetLastError(),
+ szFullFileName);
+ bRetVal = FAIL;
+ goto cleanUpTwo;
+ }
+
+ /* Verify that the returned filename is the same as the supplied.
+ */
+ if (strcmp(pPathPtr, szFileName) != 0)
+ {
+ Trace("ERROR : Returned filename \"%s\" is not equal to "
+ "supplied filename \"%s\".\n",
+ pPathPtr,
+ szFileName);
+ bRetVal = FAIL;
+ goto cleanUpTwo;
+ }
+
+ /* Successful test.
+ */
+ bRetVal = PASS;
+
+cleanUpTwo:
+
+ /* Delete the create file.
+ */
+ if (DeleteFileA(szReturnedPath) != TRUE)
+ {
+ Fail("ERROR :%ld: DeleteFileA failed to delete \"%s\".\n",
+ GetLastError(),
+ szFileName);
+ }
+
+cleanUpOne:
+
+ /* Remove the empty directory.
+ */
+ szCreatedDirW = convert((LPSTR)szDirectory);
+ if (!RemoveDirectoryW(szCreatedDirW))
+ {
+ free (szCreatedDirW);
+ Fail("ERROR:%u: Unable to remove directory \"%s\".\n",
+ GetLastError(),
+ szCreatedDir);
+ }
+ free (szCreatedDirW);
+
+ /* Terminate the PAL.*/
+ PAL_Terminate();
+ return bRetVal;
+}
diff --git a/src/pal/tests/palsuite/file_io/GetFullPathNameA/test4/testinfo.dat b/src/pal/tests/palsuite/file_io/GetFullPathNameA/test4/testinfo.dat
new file mode 100644
index 0000000000..8a7b3b35da
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFullPathNameA/test4/testinfo.dat
@@ -0,0 +1,19 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = GetFullPathNameA
+Name = Test for GetFullPathNameA
+Type = DEFAULT
+EXE1 = test4
+Description
+= Tests the PAL implementation of the GetFullPathNameA API.
+= GetFullPathA will be passed a directory that begins with '..'.
+= Example: ..\test_directory\level1\testing.tmp.
+= To add to this test, we will also call SetCurrentDirectory to
+= ensure this is handled properly.
+= The test will create a file with in the parent directory
+= to verify that the returned directory is valid.
+
diff --git a/src/pal/tests/palsuite/file_io/GetFullPathNameW/CMakeLists.txt b/src/pal/tests/palsuite/file_io/GetFullPathNameW/CMakeLists.txt
new file mode 100644
index 0000000000..a3847f8ca9
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFullPathNameW/CMakeLists.txt
@@ -0,0 +1,7 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+add_subdirectory(test3)
+add_subdirectory(test4)
+
diff --git a/src/pal/tests/palsuite/file_io/GetFullPathNameW/test1/CMakeLists.txt b/src/pal/tests/palsuite/file_io/GetFullPathNameW/test1/CMakeLists.txt
new file mode 100644
index 0000000000..a6f354f5a5
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFullPathNameW/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ GetFullPathNameW.c
+)
+
+add_executable(paltest_getfullpathnamew_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getfullpathnamew_test1 coreclrpal)
+
+target_link_libraries(paltest_getfullpathnamew_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/GetFullPathNameW/test1/GetFullPathNameW.c b/src/pal/tests/palsuite/file_io/GetFullPathNameW/test1/GetFullPathNameW.c
new file mode 100644
index 0000000000..592d3ad4c5
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFullPathNameW/test1/GetFullPathNameW.c
@@ -0,0 +1,157 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: GetFullPathNameW.c (test 1)
+**
+** Purpose: Tests the PAL implementation of the GetFullPathNameW function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+const char* szFileName = "testing.tmp";
+
+int __cdecl main(int argc, char *argv[])
+{
+ DWORD dwRc = 0;
+ WCHAR szwReturnedPath[_MAX_DIR+1];
+ WCHAR szwShortBuff[2];
+ LPWSTR pPathPtr;
+ HANDLE hFile = NULL;
+ WCHAR* szwFileName = NULL;
+
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ szwFileName = convert((char*)szFileName);
+
+ /* perform a short buffer test */
+ if (GetFullPathNameW(szwFileName, 2, szwShortBuff, &pPathPtr) <= 2)
+ {
+ free(szwFileName);
+ /* this test should have failed but didn't */
+ Fail("GetFullPathNameW: ERROR -> The API was passed a buffer that was"
+ " too small for the path name and yet it apparently passed.\n");
+ }
+
+
+ memset(szwReturnedPath, 0, _MAX_DIR+1);
+ dwRc = GetFullPathNameW(szwFileName,
+ _MAX_DIR,
+ szwReturnedPath,
+ &pPathPtr);
+
+ if (dwRc == 0)
+ {
+ /* this test should have passed but didn't */
+ free(szwFileName);
+ Fail("GetFullPathNameW: ERROR -> Function failed for the "
+ "file \"%s\" with error code: %ld.\n", szFileName, GetLastError());
+ }
+ /*
+ * the returned value should be the current directory with the
+ * file name appended
+ */
+ hFile = CreateFileW(szwFileName,
+ GENERIC_READ,
+ FILE_SHARE_READ,
+ NULL,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+ if (hFile == INVALID_HANDLE_VALUE)
+ {
+ free(szwFileName);
+ Fail("GetFullPathNameW: ERROR -> CreateFileW failed to create "
+ "file \"%s\" with error code: %ld.\n",
+ szFileName,
+ GetLastError());
+ }
+ if (CloseHandle(hFile) != TRUE)
+ {
+ free(szwFileName);
+ Trace("GetFullPathNameW: ERROR -> CloseHandle failed with error "
+ "code: %ld.\n", GetLastError());
+ if (DeleteFileA(szFileName) != TRUE)
+ {
+ Trace("GetFullPathNameW: ERROR -> DeleteFileW failed to "
+ "delete the test file with error code: %ld.\n",
+ GetLastError());
+ }
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+
+ /*
+ * now try to create the file based on the returned value with the
+ * CREATE_NEW option which should fail since the file should
+ * already exist
+ */
+ hFile = CreateFileW(szwReturnedPath,
+ GENERIC_READ,
+ FILE_SHARE_READ,
+ NULL,
+ CREATE_NEW,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+ if (hFile != INVALID_HANDLE_VALUE)
+ {
+ Trace("GetFullPathNameW: ERROR -> CreateFileW was able to "
+ "CREATE_NEW the returned file \"%s\". The returned file "
+ "name is therefore apparently wrong.\n",
+ szwReturnedPath);
+ if (CloseHandle(hFile) != TRUE)
+ {
+ Trace("GetFullPathNameW: ERROR -> CloseHandle failed with "
+ "error code: %ld.\n", GetLastError());
+ }
+ if ((DeleteFileW(szwReturnedPath) != TRUE) ||
+ (DeleteFileW(szwFileName) != TRUE))
+ {
+ Trace("GetFullPathNameW: ERROR -> DeleteFileW failed to "
+ "delete the test files with error code: %ld.\n",
+ GetLastError());
+ }
+ free(szwFileName);
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+
+ /* now make sure the pPathPtr is the same as the file name */
+ if (wcsncmp(pPathPtr, szwFileName, wcslen(szwFileName)) != 0)
+ {
+ Trace("GetFullPathNameW: ERROR -> %s != %s\n",
+ pPathPtr, szFileName);
+ if ((DeleteFileW(szwReturnedPath) != TRUE) ||
+ (DeleteFileW(szwFileName) != TRUE))
+ {
+ Trace("GetFullPathNameW: ERROR -> DeleteFileW failed to "
+ "delete the test files with error code: %ld.\n",
+ GetLastError());
+ }
+ free(szwFileName);
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+
+ /* clean up */
+ free(szwFileName);
+ if (DeleteFileA(szFileName) != TRUE)
+ {
+ Fail("GetFullPathNameW: ERROR -> DeleteFileW failed to "
+ "delete \"%s\" with error code: %ld.\n",
+ szFileName,
+ GetLastError());
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/file_io/GetFullPathNameW/test1/testinfo.dat b/src/pal/tests/palsuite/file_io/GetFullPathNameW/test1/testinfo.dat
new file mode 100644
index 0000000000..4f70617d48
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFullPathNameW/test1/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = GetFullPathNameW
+Name = Test for GetFullPathNameW (test 1)
+Type = DEFAULT
+EXE1 = getfullpathnamew
+Description
+= Get the full path for a file name and verify the results.
+= Also, attempt to call GetFullPathNameW with a buffer that is
+= too small for the returned path and verify the results.
diff --git a/src/pal/tests/palsuite/file_io/GetFullPathNameW/test2/CMakeLists.txt b/src/pal/tests/palsuite/file_io/GetFullPathNameW/test2/CMakeLists.txt
new file mode 100644
index 0000000000..199aa1efce
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFullPathNameW/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test2.c
+)
+
+add_executable(paltest_getfullpathnamew_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getfullpathnamew_test2 coreclrpal)
+
+target_link_libraries(paltest_getfullpathnamew_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/GetFullPathNameW/test2/test2.c b/src/pal/tests/palsuite/file_io/GetFullPathNameW/test2/test2.c
new file mode 100644
index 0000000000..fae042d229
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFullPathNameW/test2/test2.c
@@ -0,0 +1,159 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test2.c
+**
+** Purpose: Tests the PAL implementation of the GetFullPathNameW function.
+** Get the full path for a file name and verify the results.
+** This test will use a relative path, containing '..\'. To
+** add to this test, we will also call SetCurrentDirectory to
+** ensure this is handled properly.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+WCHAR szwDotDot[] = {'.','.','\\','\0'};
+WCHAR szwFileName[] = {'t','e','s','t','i','n','g','.','t','m','p','\0'};
+
+int __cdecl main(int argc, char *argv[])
+{
+ DWORD dwRc = 0;
+ WCHAR szwReturnedPath[_MAX_DIR+1];
+ WCHAR szwFullFileName[_MAX_DIR+1];
+ char *szReturnedPath;
+ char *szFileName;
+ LPWSTR pPathPtr;
+ HANDLE hFile = NULL;
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ /* change the directory */
+ if (!SetCurrentDirectoryW(szwDotDot))
+ {
+ Fail("ERROR: SetCurrentDirectoryW failed with error code %u"
+ " when passed \"%S\".\n",
+ GetLastError(),
+ szwDotDot);
+ }
+
+ /* Initialize the receiving char buffers.
+ */
+ memset(szwReturnedPath, 0, _MAX_DIR+1);
+ memset(szwFullFileName, 0, _MAX_DIR+1);
+
+ /* Create Full filename to pass, will include '..\'
+ * as a pre-fix. */
+ wcscat(szwFullFileName, szwDotDot);
+ wcscat(szwFullFileName, szwFileName);
+
+ /* Convert wide char strings to multibyte, to us
+ * incase of error messages.*/
+ szFileName = convertC(szwFileName);
+
+ /* Get the full path to the filename.
+ */
+ dwRc = GetFullPathNameW(szwFullFileName,
+ _MAX_DIR,
+ szwReturnedPath,
+ &pPathPtr);
+
+ szReturnedPath = convertC(szwReturnedPath);
+
+ if (dwRc == 0)
+ {
+ Trace("ERROR :%ld: Failed to get path to \"%s\".\n",
+ GetLastError(),
+ szReturnedPath);
+ free(szReturnedPath);
+ free(szFileName);
+ Fail("");
+ }
+
+ /*
+ * The returned value should be the parent directory with the
+ * file name appended.
+ */
+ hFile = CreateFileW(szwReturnedPath,
+ GENERIC_READ,
+ FILE_SHARE_READ,
+ NULL,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+ if (hFile == INVALID_HANDLE_VALUE)
+ {
+ Trace("ERROR :%ld: CreateFileW failed to create file \"%s\".\n",
+ GetLastError(),
+ szReturnedPath);
+ free(szFileName);
+ free(szReturnedPath);
+ Fail("");
+ }
+
+ /* Close the handle to the create file.*/
+ if (CloseHandle(hFile) != TRUE)
+ {
+ Trace("ERROR :%ld: Failed to close handle hFile=0x%lx.\n",
+ GetLastError(),
+ hFile);
+ goto terminate;
+ }
+
+ /* Verify that the file was created, attempt to create
+ * the file again. */
+ hFile = CreateFileW(szwReturnedPath,
+ GENERIC_READ,
+ FILE_SHARE_READ,
+ NULL,
+ CREATE_NEW,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+ if ((hFile != INVALID_HANDLE_VALUE) &&
+ (GetLastError() != ERROR_ALREADY_EXISTS))
+ {
+ Trace("ERROR :%ld: CreateFileW succeeded to create file "
+ "\"%s\", that already existed.\n",
+ GetLastError(),
+ szReturnedPath);
+ goto terminate;
+ }
+
+ /* Verify that the returned filename is the same as the supplied.
+ */
+ if (wcsncmp(pPathPtr, szwFileName, wcslen(szwFileName)) != 0)
+ {
+ Trace("ERROR : Returned filename is not equal to \"%s\".\n",
+ szFileName);
+ goto terminate;
+ }
+
+terminate:
+ /* Delete the create file.
+ */
+ if (DeleteFileW(szwFullFileName) != TRUE)
+ {
+ Trace("ERROR :%ld: DeleteFileW failed to delete \"%s\".\n",
+ szFileName,
+ GetLastError());
+ free(szFileName);
+ free(szReturnedPath);
+ Fail("");
+ }
+
+ free(szFileName);
+ free(szReturnedPath);
+
+ /* Terminate the PAL.
+ */
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/file_io/GetFullPathNameW/test2/testinfo.dat b/src/pal/tests/palsuite/file_io/GetFullPathNameW/test2/testinfo.dat
new file mode 100644
index 0000000000..b8460e0b78
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFullPathNameW/test2/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = GetFullPathNameW
+Name = Test for GetFullPathNameW (test 2)
+Type = DEFAULT
+EXE1 = test2
+Description
+= Get the full path for a file name and verify the results.
+= This test will use a relative path, containing '..\'. To
+= add to this test, we will also call SetCurrentDirectory to
+= ensure this is handled properly.
diff --git a/src/pal/tests/palsuite/file_io/GetFullPathNameW/test3/CMakeLists.txt b/src/pal/tests/palsuite/file_io/GetFullPathNameW/test3/CMakeLists.txt
new file mode 100644
index 0000000000..6284958b07
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFullPathNameW/test3/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test3.c
+)
+
+add_executable(paltest_getfullpathnamew_test3
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getfullpathnamew_test3 coreclrpal)
+
+target_link_libraries(paltest_getfullpathnamew_test3
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/GetFullPathNameW/test3/test3.c b/src/pal/tests/palsuite/file_io/GetFullPathNameW/test3/test3.c
new file mode 100644
index 0000000000..ba80cf222d
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFullPathNameW/test3/test3.c
@@ -0,0 +1,240 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test3.c
+**
+** Purpose: Tests the PAL implementation of the GetFullPathNameW API.
+** GetFullPathW will be passed a directory that contains '..'.
+** Example: test_directory\level1\..\testing.tmp.
+** To add to this test, we will also call SetCurrentDirectory to
+** ensure this is handled properly.
+** The test will create a file with in the parent directory
+** to verify that the returned directory is valid.
+**
+** Depends: SetCurrentDirectory,
+** CreateDirectory,
+** strcat,
+** memset,
+** CreateFile,
+** CloseHandle,
+** strcmp,
+** DeleteFileW,
+** RemoveDirectory.
+**
+
+**
+**===================================================================*/
+#define UNICODE
+#include <palsuite.h>
+
+#ifdef WIN32
+const WCHAR szSeperator[] = {'\\','\\','\0'};
+#else
+const WCHAR szSeperator[] = {'/','/','\0'};
+#endif
+
+const WCHAR szDotDot[] = {'.','.','\0'};
+const WCHAR szFileName[] = {'t','e','s','t','i','n','g','.','t','m','p','\0'};
+
+int __cdecl main(int argc, char *argv[])
+{
+ DWORD dwRc = 0;
+
+ WCHAR szReturnedPath[_MAX_DIR+1];
+ WCHAR szFullFileName[_MAX_DIR+1];
+ WCHAR szDirectory[256];
+ WCHAR szCreatedDir[] = {'t','e','s','t','_','d','i','r','\0'};
+ WCHAR szCreatedNextDir[] = {'l','e','v','e','l','1','\0'};
+
+ LPWSTR pPathPtr;
+ HANDLE hFile = NULL;
+ BOOL bRetVal = FAIL;
+
+ /* Initialize the PAL.
+ */
+ if ( 0 != PAL_Initialize(argc,argv) )
+ {
+ return (FAIL);
+ }
+
+ /* Initialize the buffer.
+ */
+ memset( szDirectory, '\0', 256 );
+
+ /* Change the current working directory.
+ */
+ if ( !SetCurrentDirectoryW(szDotDot) )
+ {
+ Fail("ERROR: SetCurrentDirectoryA failed with error code %u "
+ "when passed \"%S\".\n",
+ GetLastError(),
+ szDotDot);
+ }
+
+ /* Create the path to the next level of directory to create.
+ */
+ wcscat(szDirectory, szCreatedDir); /* test_dir */
+
+
+ /* Create a test directory.
+ */
+ if (!CreateDirectoryW(szDirectory, NULL))
+ {
+ Fail("ERROR:%u: Unable to create directories \"%S\".\n",
+ GetLastError(),
+ szDirectory);
+ }
+
+ /* Create the path to the next level of directory to create.
+ */
+ wcscat(szDirectory, szSeperator); /* / */
+ wcscat(szDirectory, szCreatedNextDir); /* /level1 */
+
+ /* Create a test directory.
+ */
+ if (!CreateDirectoryW(szDirectory, NULL))
+ {
+ Trace("ERROR:%u: Unable to create directories \"%S\".\n",
+ GetLastError(),
+ szDirectory);
+ bRetVal = FAIL;
+ goto cleanUpOne;
+ }
+
+ /* Initialize the receiving char buffers.
+ */
+ memset(szReturnedPath, 0, _MAX_DIR+1);
+ memset(szFullFileName, 0, _MAX_DIR+1);
+
+ /* Create Full filename to pass, will include '..\'
+ * in the middle of the path.
+ */
+ wcscat(szFullFileName, szCreatedDir); /*test_dir */
+ wcscat(szFullFileName, szSeperator); /*test_dir/ */
+ wcscat(szFullFileName, szCreatedNextDir);/*test_dir/level1 */
+ wcscat(szFullFileName, szSeperator); /*test_dir/level1/ */
+ wcscat(szFullFileName, szDotDot); /*test_dir/level1/.. */
+ wcscat(szFullFileName, szSeperator); /*test_dir/level1/../ */
+ wcscat(szFullFileName, szFileName); /*test_dir/level1/../testing.tmp */
+
+ /* Get the full path to the filename.
+ */
+ dwRc = GetFullPathNameW(szFullFileName,
+ _MAX_DIR,
+ szReturnedPath,
+ &pPathPtr);
+ if (dwRc == 0)
+ {
+ Trace("ERROR :%ld: GetFullPathNameW failed to "
+ "retrieve the path of \"%S\".\n",
+ GetLastError(),
+ szFileName);
+ bRetVal = FAIL;
+ goto cleanUpTwo;
+ }
+
+ /* The returned value should be the parent directory with the
+ * file name appended. */
+ hFile = CreateFileW(szReturnedPath,
+ GENERIC_READ,
+ FILE_SHARE_READ,
+ NULL,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if (hFile == INVALID_HANDLE_VALUE)
+ {
+ Trace("ERROR :%ld: CreateFileA failed to create \"%S\".\n",
+ GetLastError(),
+ szReturnedPath);
+ bRetVal = FAIL;
+ goto cleanUpTwo;
+ }
+
+ /* Close the handle to the created file.
+ */
+ if (CloseHandle(hFile) != TRUE)
+ {
+ Trace("ERROR :%ld: CloseHandle failed close hFile=0x%lx.\n",
+ GetLastError());
+ bRetVal = FAIL;
+ goto cleanUpThree;
+ }
+
+ /* Verify that the file was created, attempt to create
+ * the file again. */
+ hFile = CreateFileW(szReturnedPath,
+ GENERIC_READ,
+ FILE_SHARE_READ,
+ NULL,
+ CREATE_NEW,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+ if ((hFile != INVALID_HANDLE_VALUE) &&
+ (GetLastError() != ERROR_ALREADY_EXISTS))
+ {
+ Trace("ERROR :%ld: CreateFileA succeeded to create file "
+ "\"%S\", that already existed.\n",
+ GetLastError(),
+ szFullFileName);
+ bRetVal = FAIL;
+ goto cleanUpThree;
+ }
+
+ /* Verify that the returned filename is the same as the supplied.
+ */
+ if (wcscmp(pPathPtr, szFileName) != 0)
+ {
+ Trace("ERROR : Returned filename \"%s\" is not equal to "
+ "supplied filename \"%s\".\n",
+ pPathPtr,
+ szFileName);
+ bRetVal = FAIL;
+ goto cleanUpThree;
+ }
+
+ /* Successful test.
+ */
+ bRetVal = PASS;
+
+cleanUpThree:
+
+ /* Delete the create file.
+ */
+ if (DeleteFileW(szReturnedPath) != TRUE)
+ {
+ Fail("ERROR :%ld: DeleteFileA failed to delete \"%S\".\n",
+ GetLastError(),
+ szFileName);
+ }
+
+cleanUpTwo:
+
+ /* Remove the empty directory.
+ */
+ if (!RemoveDirectoryW(szDirectory))
+ {
+ Fail("ERROR:%u: Unable to remove directory \"%S\".\n",
+ GetLastError(),
+ szCreatedDir);
+ }
+
+cleanUpOne:
+
+ /* Remove the empty directory.
+ */
+ if (!RemoveDirectoryW(szCreatedDir))
+ {
+ Fail("ERROR:%u: Unable to remove directory \"%s\".\n",
+ GetLastError(),
+ szCreatedDir);
+ }
+
+ /* Terminate the PAL.*/
+ PAL_TerminateEx(bRetVal);
+ return bRetVal;
+}
diff --git a/src/pal/tests/palsuite/file_io/GetFullPathNameW/test3/testinfo.dat b/src/pal/tests/palsuite/file_io/GetFullPathNameW/test3/testinfo.dat
new file mode 100644
index 0000000000..1eb6a27ada
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFullPathNameW/test3/testinfo.dat
@@ -0,0 +1,19 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = GetFullPathNameW
+Name = Test for GetFullPathNameW
+Type = DEFAULT
+EXE1 = test3
+Description
+= Tests the PAL implementation of the GetFullPathNameW API.
+= GetFullPathW will be passed a directory that contains '..'.
+= Example: test_directory\level1\..\testing.tmp.
+= To add to this test, we will also call SetCurrentDirectory to
+= ensure this is handled properly.
+= The test will create a file with in the parent directory
+= to verify that the returned directory is valid.
+
diff --git a/src/pal/tests/palsuite/file_io/GetFullPathNameW/test4/CMakeLists.txt b/src/pal/tests/palsuite/file_io/GetFullPathNameW/test4/CMakeLists.txt
new file mode 100644
index 0000000000..d479b998cc
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFullPathNameW/test4/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test4.c
+)
+
+add_executable(paltest_getfullpathnamew_test4
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getfullpathnamew_test4 coreclrpal)
+
+target_link_libraries(paltest_getfullpathnamew_test4
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/GetFullPathNameW/test4/test4.c b/src/pal/tests/palsuite/file_io/GetFullPathNameW/test4/test4.c
new file mode 100644
index 0000000000..25eb10d654
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFullPathNameW/test4/test4.c
@@ -0,0 +1,201 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test4.c
+**
+** Purpose: Tests the PAL implementation of the GetFullPathNameW API.
+** GetFullPathNameW will be passed a directory that begins with '..'.
+** Example: ..\test_directory\testing.tmp.
+** To add to this test, we will also call SetCurrentDirectory to
+** ensure this is handled properly.
+** The test will create a file with in the parent directory
+** to verify that the returned directory is valid.
+**
+** Depends: SetCurrentDirectory,
+** CreateDirectory,
+** strcat,
+** memset,
+** CreateFile,
+** CloseHandle,
+** strcmp,
+** DeleteFileW,
+** RemoveDirectory.
+**
+
+**
+**===================================================================*/
+#define UNICODE
+#include <palsuite.h>
+
+#ifdef WIN32
+ const WCHAR szSeperator[] = {'\\','\\','\0'};
+#else
+ const WCHAR szSeperator[] = {'/','/','\0'};
+#endif
+
+const WCHAR szDotDot[] = {'.','.','\0'};
+const WCHAR szFileName[] = {'t','e','s','t','i','n','g','.','t','m','p','\0'};
+
+int __cdecl main(int argc, char *argv[])
+{
+ DWORD dwRc = 0;
+
+ WCHAR szReturnedPath[_MAX_DIR+1];
+ WCHAR szFullFileName[_MAX_DIR+1];
+ WCHAR szDirectory[256];
+ WCHAR szCreatedDir[] = {'t','e','s','t','_','d','i','r','\0'};
+
+ LPWSTR pPathPtr;
+ HANDLE hFile = NULL;
+ BOOL bRetVal = FAIL;
+
+ /* Initialize the PAL.
+ */
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return (FAIL);
+ }
+
+ /* Initialize the buffer.
+ */
+ memset(szDirectory, '\0', 256);
+
+ /* Create the path to the next level of directory to create.
+ */
+ wcscat(szDirectory, szDotDot); /* .. */
+ wcscat(szDirectory, szSeperator); /* ../ */
+ wcscat(szDirectory, szCreatedDir); /* ../test_directory */
+
+ /* Create a test directory.
+ */
+ if (!CreateDirectoryW(szDirectory, NULL))
+ {
+ Fail("ERROR:%u: Unable to create directories \"%S\".\n",
+ GetLastError(),
+ szDirectory);
+ }
+
+ /* Initialize the receiving char buffers.
+ */
+ memset(szReturnedPath, 0, _MAX_DIR+1);
+ memset(szFullFileName, 0, _MAX_DIR+1);
+
+ /* Create Full filename to pass, will include '..\'
+ * in the middle of the path.
+ */
+ wcscat( szFullFileName, szDotDot ); /* .. */
+ wcscat( szFullFileName, szSeperator ); /* ../ */
+ wcscat( szFullFileName, szCreatedDir ); /* ../test_directory */
+ wcscat( szFullFileName, szSeperator ); /* ../test_directory/ */
+ wcscat( szFullFileName, szFileName ); /* ../test_directory/testing.tmp */
+
+ /* Get the full path to the filename.
+ */
+ dwRc = GetFullPathNameW(szFullFileName,
+ _MAX_DIR,
+ szReturnedPath,
+ &pPathPtr);
+ if (dwRc == 0)
+ {
+ Trace("ERROR :%ld: GetFullPathName failed to "
+ "retrieve the path of \"%S\".\n",
+ GetLastError(),
+ szFileName);
+ bRetVal = FAIL;
+ goto cleanUpOne;
+ }
+
+ /* The returned value should be the parent directory with the
+ * file name appended. */
+ hFile = CreateFileW(szReturnedPath,
+ GENERIC_READ,
+ FILE_SHARE_READ,
+ NULL,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if (hFile == INVALID_HANDLE_VALUE)
+ {
+ Trace("ERROR :%ld: CreateFileA failed to create \"%S\".\n",
+ GetLastError(),
+ szReturnedPath);
+ bRetVal = FAIL;
+ goto cleanUpOne;
+ }
+
+ /* Close the handle to the created file.
+ */
+ if (CloseHandle(hFile) != TRUE)
+ {
+ Trace("ERROR :%ld: CloseHandle failed close hFile=0x%lx.\n",
+ GetLastError());
+ bRetVal = FAIL;
+ goto cleanUpTwo;
+ }
+
+ /* Verify that the file was created, attempt to create
+ * the file again. */
+ hFile = CreateFileW(szReturnedPath,
+ GENERIC_READ,
+ FILE_SHARE_READ,
+ NULL,
+ CREATE_NEW,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+ if ((hFile != INVALID_HANDLE_VALUE) &&
+ (GetLastError() != ERROR_ALREADY_EXISTS))
+ {
+ Trace("ERROR :%ld: CreateFileA succeeded to create file "
+ "\"%S\", that already existed.\n",
+ GetLastError(),
+ szFullFileName);
+ bRetVal = FAIL;
+ goto cleanUpTwo;
+ }
+
+ /* Verify that the returned filename is the same as the supplied.
+ */
+ if (wcscmp(pPathPtr, szFileName) != 0)
+ {
+ Trace("ERROR : Returned filename \"%S\" is not equal to "
+ "supplied filename \"%S\".\n",
+ pPathPtr,
+ szFileName);
+ bRetVal = FAIL;
+ goto cleanUpTwo;
+ }
+
+ /* Successful test.
+ */
+ bRetVal = PASS;
+
+cleanUpTwo:
+
+ /* Delete the create file.
+ */
+ if (DeleteFileW(szReturnedPath) != TRUE)
+ {
+ Fail("ERROR :%ld: DeleteFileA failed to delete \"%S\".\n",
+ GetLastError(),
+ szFileName);
+ }
+
+cleanUpOne:
+
+ /* Remove the empty directory.
+ */
+ if (!RemoveDirectoryW(szDirectory))
+ {
+ Fail("ERROR:%u: Unable to remove directory \"%s\".\n",
+ GetLastError(),
+ szCreatedDir);
+ }
+
+ /* Terminate the PAL.*/
+ PAL_TerminateEx(bRetVal);
+ return bRetVal;
+}
diff --git a/src/pal/tests/palsuite/file_io/GetFullPathNameW/test4/testinfo.dat b/src/pal/tests/palsuite/file_io/GetFullPathNameW/test4/testinfo.dat
new file mode 100644
index 0000000000..8a7b3b35da
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetFullPathNameW/test4/testinfo.dat
@@ -0,0 +1,19 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = GetFullPathNameA
+Name = Test for GetFullPathNameA
+Type = DEFAULT
+EXE1 = test4
+Description
+= Tests the PAL implementation of the GetFullPathNameA API.
+= GetFullPathA will be passed a directory that begins with '..'.
+= Example: ..\test_directory\level1\testing.tmp.
+= To add to this test, we will also call SetCurrentDirectory to
+= ensure this is handled properly.
+= The test will create a file with in the parent directory
+= to verify that the returned directory is valid.
+
diff --git a/src/pal/tests/palsuite/file_io/GetLongPathNameW/CMakeLists.txt b/src/pal/tests/palsuite/file_io/GetLongPathNameW/CMakeLists.txt
new file mode 100644
index 0000000000..ef14ea5352
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetLongPathNameW/CMakeLists.txt
@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+
diff --git a/src/pal/tests/palsuite/file_io/GetLongPathNameW/test1/CMakeLists.txt b/src/pal/tests/palsuite/file_io/GetLongPathNameW/test1/CMakeLists.txt
new file mode 100644
index 0000000000..cf5dcd0bfc
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetLongPathNameW/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ GetLongPathNameW.c
+)
+
+add_executable(paltest_getlongpathnamew_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getlongpathnamew_test1 coreclrpal)
+
+target_link_libraries(paltest_getlongpathnamew_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/GetLongPathNameW/test1/GetLongPathNameW.c b/src/pal/tests/palsuite/file_io/GetLongPathNameW/test1/GetLongPathNameW.c
new file mode 100644
index 0000000000..22831dda15
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetLongPathNameW/test1/GetLongPathNameW.c
@@ -0,0 +1,280 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: GetLongPathNameW.c Win32 version(test 1)
+**
+** Purpose: Tests the PAL implementation of the GetLongPathNameW function.
+** as expected under Win32
+**
+** Depends on:
+** CreateDirectoryA
+** RemoveDirectoryW
+**
+**
+**===================================================================*/
+/*
+tests:
+ - test invalid path names
+ - test an already short path name
+ - test a long path name
+ - test with buffer size too small
+*/
+
+#include <palsuite.h>
+
+
+int __cdecl main(int argc, char *argv[])
+{
+/* Since GetLongPathNameW operates differently under FreeBSD and Win32 this test
+ is for Win32 only. It runs the same tests as the FreeBSD version but checks for
+ different results
+*/
+
+#if WIN32
+ DWORD dwRc = 0;
+ WCHAR szwReturnedPath[MAX_LONGPATH];
+ WCHAR szwSmallBuff[3];
+ const char szShortPathName[] = {"testing"};
+ const char szLongPathName[] = {"This_is_a_long_directory_name"};
+ const char szShortenedPathName[] = {"THIS_I~1"};
+ WCHAR* wLongPathPtr = NULL;
+ WCHAR* wShortPathPtr = NULL;
+
+
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ memset(szwReturnedPath, 0, MAX_LONGPATH*sizeof(WCHAR));
+ memset(szwSmallBuff, 0, 3*sizeof(WCHAR));
+ wLongPathPtr = convert((char*)szLongPathName);
+ wShortPathPtr = convert((char*)szShortenedPathName);
+
+ /* do some clean up just to be safe */
+ RemoveDirectoryW(wLongPathPtr);
+ RemoveDirectoryW(wShortPathPtr);
+
+
+ /* attempt call on an invalid short path name */
+ dwRc = GetLongPathNameW(wShortPathPtr, szwReturnedPath, MAX_LONGPATH);
+ if (dwRc != 0)
+ {
+ Trace("GetLongPathNameW: ERROR -> Call made with an invalid short "
+ "path \"%S\" returned \"%S\"\n",
+ wShortPathPtr,
+ szwReturnedPath);
+ free (wLongPathPtr);
+ free (wShortPathPtr);
+ Fail("");
+ }
+
+
+ /* attempt call on an invalid long path name */
+ dwRc = GetLongPathNameW(wLongPathPtr, szwReturnedPath, MAX_LONGPATH);
+ if (dwRc != 0)
+ {
+ Trace("GetLongPathNameW: ERROR -> Call made with an invalid long "
+ "path \"%S\" returned \"%S\"\n",
+ wLongPathPtr,
+ szwReturnedPath);
+ free (wLongPathPtr);
+ free (wShortPathPtr);
+ Fail("");
+ }
+
+
+ /* create a long directory name */
+ if (TRUE != CreateDirectoryW(wLongPathPtr, NULL))
+ {
+ free(wLongPathPtr);
+ free(wShortPathPtr);
+ Fail("GetLongPathNameW: ERROR -> CreateDirectoryW failed with an error"
+ " code of %ld when asked to create a directory called \"%s\".\n",
+ GetLastError(),
+ szLongPathName);
+ }
+
+
+ /* get the long path name */
+ memset(szwReturnedPath, 0, MAX_LONGPATH*sizeof(WCHAR));
+ dwRc = GetLongPathNameW(wShortPathPtr, szwReturnedPath, MAX_LONGPATH);
+ if (dwRc == 0)
+ {
+ Trace("GetLongPathNameW: ERROR -> failed with an error"
+ " code of %ld when asked for the long version of \"%s\".\n",
+ GetLastError(),
+ szShortenedPathName);
+ if (RemoveDirectoryW(wLongPathPtr) != TRUE)
+ {
+ Trace("GetLongPathNameW: ERROR -> RemoveDirectoryW failed to "
+ " remove the directory \"%S\" with an error code of %ld.\n",
+ wLongPathPtr,
+ GetLastError());
+ }
+ free(wLongPathPtr);
+ free(wShortPathPtr);
+ Fail("");
+ }
+
+ /* does the returned match the expected */
+ if (wcsncmp(wLongPathPtr, szwReturnedPath, wcslen(wLongPathPtr)) ||
+ (wcslen(wLongPathPtr) != wcslen(szwReturnedPath)))
+ {
+ if (RemoveDirectoryW(wLongPathPtr) != TRUE)
+ {
+ Trace("GetLongPathNameW: ERROR -> RemoveDirectoryW failed to "
+ " remove the directory \"%S\" with an error code of %ld.\n",
+ wLongPathPtr,
+ GetLastError());
+ }
+ free(wLongPathPtr);
+ free(wShortPathPtr);
+ Fail("GetLongPathNameW: ERROR -> The returned path, \"%S\" doesn't "
+ "match the expected return, \"%s\".\n",
+ szwReturnedPath,
+ szLongPathName);
+ }
+
+ /* does the length returned match the actual length */
+ if (dwRc != wcslen(szwReturnedPath))
+ {
+ if (RemoveDirectoryW(wLongPathPtr) != TRUE)
+ {
+ Trace("GetLongPathNameW: ERROR -> RemoveDirectoryW failed to "
+ " remove the directory \"%S\" with an error code of %ld.\n",
+ wLongPathPtr,
+ GetLastError());
+ }
+ free(wLongPathPtr);
+ free(wShortPathPtr);
+ Fail("GetLongPathNameW: ERROR -> The returned length, %ld, doesn't "
+ "match the string length, %ld.\n",
+ dwRc,
+ wcslen(szwReturnedPath));
+ }
+
+ if (RemoveDirectoryW(wLongPathPtr) != TRUE)
+ {
+ Trace("GetLongPathNameW: ERROR -> RemoveDirectoryW failed to "
+ " remove the directory \"%S\" with an error code of %ld.\n",
+ wLongPathPtr,
+ GetLastError());
+ free(wShortPathPtr);
+ free(wLongPathPtr);
+ Fail("");
+ }
+ free(wShortPathPtr);
+ free(wLongPathPtr);
+
+
+ /* test an actual short name */
+ /* create a long directory name */
+ wShortPathPtr = convert((char*)szShortPathName);
+ RemoveDirectoryW(wShortPathPtr);
+
+ if (TRUE != CreateDirectoryW(wShortPathPtr, NULL))
+ {
+ Trace("GetLongPathNameW: ERROR -> CreateDirectoryW failed with an error"
+ " code of %ld when asked to create a directory called \"%s\".\n",
+ GetLastError(),
+ szShortPathName);
+ free(wShortPathPtr);
+ Fail("");
+ }
+
+
+ /* get the long path name */
+ memset(szwReturnedPath, 0, MAX_LONGPATH*sizeof(WCHAR));
+ dwRc = GetLongPathNameW(wShortPathPtr, szwReturnedPath, MAX_LONGPATH);
+ if (dwRc == 0)
+ {
+ Trace("GetLongPathNameW: ERROR -> failed with an error"
+ " code of %ld when asked for the long version of \"%s\".\n",
+ GetLastError(),
+ szShortenedPathName);
+ if (RemoveDirectoryW(wShortPathPtr) != TRUE)
+ {
+ Trace("GetLongPathNameW: ERROR -> RemoveDirectoryW failed to "
+ " remove the directory \"%S\" with an error code of %ld.\n",
+ wShortPathPtr,
+ GetLastError());
+ }
+ free(wShortPathPtr);
+ Fail("");
+ }
+
+ /* does the returned match the expected */
+ if (wcsncmp(wShortPathPtr, szwReturnedPath, wcslen(wShortPathPtr)) ||
+ (wcslen(wShortPathPtr) != wcslen(szwReturnedPath)))
+ {
+ if (RemoveDirectoryW(wShortPathPtr) != TRUE)
+ {
+ Trace("GetLongPathNameW: ERROR -> RemoveDirectoryW failed to "
+ " remove the directory \"%S\" with an error code of %ld.\n",
+ wShortPathPtr,
+ GetLastError());
+ }
+ free(wShortPathPtr);
+ Fail("GetLongPathNameW: ERROR -> The returned path, \"%S\" doesn't "
+ "match the expected return, \"%s\".\n",
+ szwReturnedPath,
+ szShortPathName);
+ }
+
+ /* does the length returned match the actual length */
+ if (dwRc != wcslen(szwReturnedPath))
+ {
+ if (RemoveDirectoryW(wShortPathPtr) != TRUE)
+ {
+ Trace("GetLongPathNameW: ERROR -> RemoveDirectoryW failed to "
+ " remove the directory \"%S\" with an error code of %ld.\n",
+ wShortPathPtr,
+ GetLastError());
+ }
+ free(wShortPathPtr);
+ Fail("GetLongPathNameW: ERROR -> The returned length, %ld, doesn't "
+ "match the string length, %ld.\n",
+ dwRc,
+ wcslen(szwReturnedPath));
+ }
+
+ /* test using a too small return buffer */
+ dwRc = GetLongPathNameW(wShortPathPtr, szwSmallBuff, 3);
+ if ((dwRc != (strlen(szShortPathName)+1)) || /* +1 for the required NULL */
+ szwSmallBuff[0] != '\0')
+ {
+ if (RemoveDirectoryW(wShortPathPtr) != TRUE)
+ {
+ Trace("GetLongPathNameW: ERROR -> RemoveDirectoryW failed to "
+ " remove the directory \"%S\" with an error code of %ld.\n",
+ wShortPathPtr,
+ GetLastError());
+ }
+ free(wShortPathPtr);
+ Fail("GetLongPathNameW: ERROR -> using a return buffer that was too"
+ " small was not handled properly.\n");
+ }
+
+ if (RemoveDirectoryW(wShortPathPtr) != TRUE)
+ {
+ Trace("GetLongPathNameW: ERROR -> RemoveDirectoryW failed to "
+ " remove the directory \"%S\" with an error code of %ld.\n",
+ wShortPathPtr,
+ GetLastError());
+ free(wShortPathPtr);
+ Fail("");
+ }
+ free(wShortPathPtr);
+
+ PAL_Terminate();
+
+#endif /* WIN32 */
+
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/file_io/GetLongPathNameW/test1/testinfo.dat b/src/pal/tests/palsuite/file_io/GetLongPathNameW/test1/testinfo.dat
new file mode 100644
index 0000000000..f730300c43
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetLongPathNameW/test1/testinfo.dat
@@ -0,0 +1,16 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = GetLongPathNameW
+Name = Test for GetLongPathNameW Win32 (test 1)
+Type = DEFAULT
+EXE1 = getlongpathnamew
+Description
+= Tests invalid path names. Tests conversion of short to long
+= path names as well as passing it a path name that is already short.
+= Under BSD, there isn't a shortened version of directory names so
+= I just use a long path name as the short path name to ensure it returns
+= the same thing.
diff --git a/src/pal/tests/palsuite/file_io/GetLongPathNameW/test2/CMakeLists.txt b/src/pal/tests/palsuite/file_io/GetLongPathNameW/test2/CMakeLists.txt
new file mode 100644
index 0000000000..5746ef3e04
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetLongPathNameW/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ getlongpathnamew.c
+)
+
+add_executable(paltest_getlongpathnamew_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getlongpathnamew_test2 coreclrpal)
+
+target_link_libraries(paltest_getlongpathnamew_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/GetLongPathNameW/test2/getlongpathnamew.c b/src/pal/tests/palsuite/file_io/GetLongPathNameW/test2/getlongpathnamew.c
new file mode 100644
index 0000000000..3b033e9a64
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetLongPathNameW/test2/getlongpathnamew.c
@@ -0,0 +1,266 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: GetLongPathNameW.c FreeBSD version(test 2)
+**
+** Purpose: Tests the PAL implementation of the GetLongPathNameW function
+** as expected under FreeBSD
+**
+** Depends on:
+** CreateDirectoryA
+** RemoveDirectoryW
+**
+**
+**===================================================================*/
+/*
+tests:
+ - test invalid path names
+ - test an already short path name
+ - test a long path name
+ - test with buffer size too small
+*/
+
+#include <palsuite.h>
+
+
+int __cdecl main(int argc, char *argv[])
+{
+/* Since GetLongPathNameW operates differently under FreeBSD and Win32 this test
+ is for freeBSD only. It runs the same tests as the Win32 version but checks for
+ different results
+*/
+#if !(WIN32) /* Only execute if the is Free BSD */
+
+ DWORD dwRc = 0;
+ WCHAR szwReturnedPath[MAX_LONGPATH];
+ WCHAR szwSmallBuff[3];
+ const char szShortPathName[] = {"testing"};
+ const char szLongPathName[] = {"This_is_a_long_directory_name"};
+ /* since BSD doesn't shorten long dir names, it will only use the long name */
+ const char szShortenedPathName[] = {"This_is_a_long_directory_name"};
+ WCHAR* wLongPathPtr = NULL;
+ WCHAR* wShortPathPtr = NULL;
+ int StringLen = 0;
+
+
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+ memset(szwReturnedPath, 0, MAX_LONGPATH*sizeof(WCHAR));
+ memset(szwSmallBuff, 0, 3*sizeof(WCHAR));
+ wLongPathPtr = convert((char*)szLongPathName);
+ wShortPathPtr = convert((char*)szShortenedPathName);
+
+
+ /* do some clean up just to be safe */
+ RemoveDirectoryW(wLongPathPtr);
+ RemoveDirectoryW(wShortPathPtr);
+
+
+ /* attempt call on an invalid short path name */
+ dwRc = GetLongPathNameW(wShortPathPtr, szwReturnedPath, MAX_LONGPATH);
+ if (dwRc != 0)
+ {
+ Trace("GetLongPathNameW: ERROR -> Call made with an invalid short "
+ "path \"%S\" returned \"%S\"\n",
+ wShortPathPtr,
+ szwReturnedPath);
+ free (wLongPathPtr);
+ free (wShortPathPtr);
+ Fail("");
+ }
+
+
+ /* attempt call on an invalid long path name */
+ dwRc = GetLongPathNameW(wLongPathPtr, szwReturnedPath, MAX_LONGPATH);
+ if (dwRc != 0)
+ {
+ Trace("GetLongPathNameW: ERROR -> Call made with an invalid long "
+ "path \"%S\" returned \"%S\"\n",
+ wLongPathPtr,
+ szwReturnedPath);
+ free (wLongPathPtr);
+ free (wShortPathPtr);
+ Fail("");
+ }
+
+
+ /* create a long directory name */
+ if (TRUE != CreateDirectoryW(wLongPathPtr, NULL))
+ {
+ free(wLongPathPtr);
+ free(wShortPathPtr);
+ Fail("GetLongPathNameW: ERROR -> CreateDirectoryW failed with an error"
+ " code of %ld when asked to create a directory called \"%s\".\n",
+ GetLastError(),
+ szLongPathName);
+ }
+
+
+ /* get the long path name */
+ memset(szwReturnedPath, 0, MAX_LONGPATH*sizeof(WCHAR));
+ dwRc = GetLongPathNameW(wShortPathPtr, szwReturnedPath, MAX_LONGPATH);
+ StringLen = wcslen(wShortPathPtr);
+
+ if (dwRc != StringLen)
+ {
+ Trace("GetLongPathNameW: ERROR -> Under FreeBSD, this test should"
+ " have returned %d but instead returned %d.\n",
+ StringLen, dwRc);
+ if (RemoveDirectoryW(wLongPathPtr) != TRUE)
+ {
+ Trace("GetLongPathNameW: ERROR -> RemoveDirectoryW failed to "
+ " remove the directory \"%S\" with an error code of %ld.\n",
+ wLongPathPtr,
+ GetLastError());
+ }
+ free(wLongPathPtr);
+ free(wShortPathPtr);
+ Fail("");
+ }
+ if (wcsncmp(wShortPathPtr,szwReturnedPath, StringLen) != 0)
+ {
+ Trace("GetLongPathNameW: ERROR -> Under Unix,"
+ "the lpszLongPath \"%s\" should have been,"
+ "but was \"%s\".\n",
+ wShortPathPtr, szwReturnedPath);
+
+ if (RemoveDirectoryW(wLongPathPtr) != TRUE)
+ {
+ Trace("GetLongPathNameW: ERROR -> RemoveDirectoryW failed to "
+ " remove the directory \"%S\" with an error code of %ld.\n",
+ wLongPathPtr,
+ GetLastError());
+ }
+ free(wLongPathPtr);
+ free(wShortPathPtr);
+ Fail("");
+ }
+
+ if (RemoveDirectoryW(wLongPathPtr) != TRUE)
+ {
+ Trace("GetLongPathNameW: ERROR -> RemoveDirectoryW failed to "
+ " remove the directory \"%S\" with an error code of %ld.\n",
+ wLongPathPtr,
+ GetLastError());
+ free(wLongPathPtr);
+ free(wShortPathPtr);
+ Fail("");
+ }
+ free(wShortPathPtr);
+ free(wLongPathPtr);
+
+
+ /* test an actual short name */
+ /* create a long directory name */
+ wShortPathPtr = convert((char*)szShortPathName);
+ RemoveDirectoryW(wShortPathPtr);
+
+ if (TRUE != CreateDirectoryW(wShortPathPtr, NULL))
+ {
+ free(wShortPathPtr);
+ Fail("GetLongPathNameW: ERROR -> CreateDirectoryW failed with an error"
+ " code of %ld when asked to create a directory called \"%s\".\n",
+ GetLastError(),
+ szShortPathName);
+ }
+
+
+ /* get the long path name */
+ memset(szwReturnedPath, 0, MAX_LONGPATH*sizeof(WCHAR));
+ dwRc = GetLongPathNameW(wShortPathPtr, szwReturnedPath, MAX_LONGPATH);
+ StringLen = wcslen (wShortPathPtr);
+
+ if (dwRc != StringLen)
+ {
+ Trace("GetLongPathNameW: ERROR -> Under FreeBSD, this test should"
+ " have returned %d but instead returned %d.\n",
+ StringLen, dwRc);
+ if (RemoveDirectoryW(wShortPathPtr) != TRUE)
+ {
+ Trace("GetLongPathNameW: ERROR -> RemoveDirectoryW failed to "
+ " remove the directory \"%S\" with an error code of %ld.\n",
+ wShortPathPtr,
+ GetLastError());
+ }
+ free(wShortPathPtr);
+ Fail("");
+ }
+ if (wcsncmp(wShortPathPtr, szwReturnedPath, StringLen) != 0)
+ {
+ Trace("GetLongPathNameW: ERROR -> Under Unix, the lpszLongPath"
+ "\"%s\" should have been,"
+ "but was \"%s\".\n",
+ wShortPathPtr, szwReturnedPath);
+
+ if (RemoveDirectoryW(wShortPathPtr) != TRUE)
+ {
+ Trace("GetLongPathNameW: ERROR -> RemoveDirectoryW failed to "
+ " remove the directory \"%S\" with an error code of %ld.\n",
+ wShortPathPtr,
+ GetLastError());
+ }
+ free(wShortPathPtr);
+ Fail("");
+ }
+
+
+ /* test using a too small return buffer */
+ dwRc = GetLongPathNameW(wShortPathPtr, szwSmallBuff, 3);
+ StringLen = wcslen (wShortPathPtr);
+
+
+ if (dwRc != (StringLen + 1)) //Return size includes NULL char
+ {
+ Trace("GetLongPathNameW: ERROR -> Under FreeBSD, this test should"
+ " have returned %d but instead returned %d.\n",
+ StringLen, dwRc);
+ if (RemoveDirectoryW(wShortPathPtr) != TRUE)
+ {
+ Trace("GetLongPathNameW: ERROR -> RemoveDirectoryW failed to "
+ " remove the directory \"%S\" with an error code of %ld.\n",
+ wShortPathPtr,
+ GetLastError());
+ }
+ free(wShortPathPtr);
+ Fail("");
+ }
+ if (szwSmallBuff[0] != 0)
+ {
+ Trace("GetLongPathNameW: ERROR -> Under FreeBSD, this test should"
+ " not have touched lpszLongPath but instead it returned\"%s\".\n",
+ szwReturnedPath);
+ if (RemoveDirectoryW(wShortPathPtr) != TRUE)
+ {
+ Trace("GetLongPathNameW: ERROR -> RemoveDirectoryW failed to "
+ " remove the directory \"%S\" with an error code of %ld.\n",
+ wShortPathPtr,
+ GetLastError());
+ }
+ free(wShortPathPtr);
+ Fail("");
+ }
+
+ /* clean up */
+ if (RemoveDirectoryW(wShortPathPtr) != TRUE)
+ {
+ Trace("GetLongPathNameW: ERROR -> RemoveDirectoryW failed to "
+ " remove the directory \"%S\" with an error code of %ld.\n",
+ wShortPathPtr,
+ GetLastError());
+ free(wShortPathPtr);
+ Fail("");
+ }
+ free(wShortPathPtr);
+
+ PAL_Terminate();
+
+#endif /* Free BSD */
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/file_io/GetLongPathNameW/test2/testinfo.dat b/src/pal/tests/palsuite/file_io/GetLongPathNameW/test2/testinfo.dat
new file mode 100644
index 0000000000..5144a35b13
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetLongPathNameW/test2/testinfo.dat
@@ -0,0 +1,16 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = GetLongPathNameW
+Name = Test for GetLongPathNameW FreeBSD version (test 2)
+Type = DEFAULT
+EXE1 = getlongpathnamew
+Description
+= Tests invalid path names. Tests conversion of short to long
+= path names as well as passing it a path name that is already short.
+= Under BSD, there isn't a shortened version of directory names so
+= I just use a long path name as the short path name to ensure it returns
+= the same thing.
diff --git a/src/pal/tests/palsuite/file_io/GetStdHandle/CMakeLists.txt b/src/pal/tests/palsuite/file_io/GetStdHandle/CMakeLists.txt
new file mode 100644
index 0000000000..ef14ea5352
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetStdHandle/CMakeLists.txt
@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+
diff --git a/src/pal/tests/palsuite/file_io/GetStdHandle/test1/CMakeLists.txt b/src/pal/tests/palsuite/file_io/GetStdHandle/test1/CMakeLists.txt
new file mode 100644
index 0000000000..04bcc5fd67
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetStdHandle/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ GetStdHandle.c
+)
+
+add_executable(paltest_getstdhandle_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getstdhandle_test1 coreclrpal)
+
+target_link_libraries(paltest_getstdhandle_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/GetStdHandle/test1/GetStdHandle.c b/src/pal/tests/palsuite/file_io/GetStdHandle/test1/GetStdHandle.c
new file mode 100644
index 0000000000..f4fe03195d
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetStdHandle/test1/GetStdHandle.c
@@ -0,0 +1,132 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: GetStdHandle.c (test 1)
+**
+** Purpose: Tests the PAL implementation of the GetStdHandle function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ HANDLE hFile = NULL;
+ DWORD dwBytesWritten = 0;
+ DWORD dwFileType;
+ BOOL bRc = FALSE;
+ const char* szText = "this is a test of GetStdHandle\n";
+
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ /*
+ * attempt to get an invalid handle
+ */
+ hFile = GetStdHandle(-2);
+ if (hFile != INVALID_HANDLE_VALUE)
+ {
+ Fail("GetStdHandle: ERROR -> A request for the STD_INPUT_HANDLE "
+ "returned an invalid handle.\n");
+ }
+
+
+ /*
+ * test the STD_INPUT_HANDLE handle
+ */
+ hFile = GetStdHandle(STD_INPUT_HANDLE);
+ if (hFile == INVALID_HANDLE_VALUE)
+ {
+ Fail("GetStdHandle: ERROR -> A request for the STD_INPUT_HANDLE "
+ "returned an invalid handle.\n");
+ }
+
+ /* an attempt to write to the input handle should fail */
+ /* I don't know how to automate a read from the input handle */
+ bRc = WriteFile(hFile, szText, (DWORD)strlen(szText), &dwBytesWritten, NULL);
+ if (bRc != FALSE)
+ {
+ Fail("GetStdHandle: ERROR -> WriteFile was able to write to "
+ "STD_INPUT_HANDLE when it should have failed.\n");
+ }
+
+
+ /*
+ * test the STD_OUTPUT_HANDLE handle
+ */
+ hFile = GetStdHandle(STD_OUTPUT_HANDLE);
+ if (hFile == INVALID_HANDLE_VALUE)
+ {
+ Fail("GetStdHandle: ERROR -> A request for the STD_OUTPUT_HANDLE "
+ "returned an invalid handle.\n");
+ }
+
+ /* try to write to the output handle */
+ bRc = WriteFile(hFile, szText, (DWORD)strlen(szText), &dwBytesWritten, NULL);
+ if (bRc != TRUE)
+ {
+ Fail("GetStdHandle: ERROR -> WriteFile failed to write to "
+ "STD_OUTPUT_HANDLE with the error %ld\n",
+ GetLastError());
+ }
+
+
+ /* test the STD_ERROR_HANDLE handle */
+ hFile = GetStdHandle(STD_ERROR_HANDLE);
+ if (hFile == INVALID_HANDLE_VALUE)
+ {
+ Fail("GetStdHandle: ERROR -> A request for the STD_ERROR_HANDLE "
+ "returned an invalid handle.\n");
+ }
+
+ /* try to write to the error handle */
+ bRc = WriteFile(hFile, szText, (DWORD)strlen(szText), &dwBytesWritten, NULL);
+ if (bRc != TRUE)
+ {
+ Fail("GetStdHandle: ERROR -> WriteFile failed to write to "
+ "STD_ERROR_HANDLE with the error %ld\n",
+ GetLastError());
+ }
+
+ /* check if the file type is correct for the handle */
+ if((dwFileType = GetFileType(hFile)) != FILE_TYPE_CHAR)
+ {
+ Fail("GetStdHandle: ERROR -> GetFileType returned %u for "
+ "STD_ERROR_HANDLE instead of the expected FILE_TYPE_CHAR (%u).\n",
+ dwFileType,
+ FILE_TYPE_CHAR);
+ }
+
+ /* check to see if we can CloseHandle works on the STD_ERROR_HANDLE */
+ if (!CloseHandle(hFile))
+ {
+ Fail("GetStdHandle: ERROR -> CloseHandle failed. GetLastError "
+ "returned %u.\n",
+ GetLastError());
+ }
+
+ /* try to write to the closed error handle */
+ bRc = WriteFile(hFile,
+ szText,
+ (DWORD)strlen(szText),
+ &dwBytesWritten,
+ NULL);
+ if (bRc)
+ {
+ Fail("GetStdHandle: ERROR -> WriteFile was able to write to the closed"
+ " STD_ERROR_HANDLE handle.\n");
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/file_io/GetStdHandle/test1/testinfo.dat b/src/pal/tests/palsuite/file_io/GetStdHandle/test1/testinfo.dat
new file mode 100644
index 0000000000..3f7dbf5f42
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetStdHandle/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = GetStdHandle
+Name = Positive Test for GetStdHandle (test 1)
+Type = DEFAULT
+EXE1 = getstdhandle
+Description
+= Test GetStdHandle on a valid/invalid std handles
+
diff --git a/src/pal/tests/palsuite/file_io/GetStdHandle/test2/CMakeLists.txt b/src/pal/tests/palsuite/file_io/GetStdHandle/test2/CMakeLists.txt
new file mode 100644
index 0000000000..97816b4319
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetStdHandle/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ GetStdHandle.c
+)
+
+add_executable(paltest_getstdhandle_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getstdhandle_test2 coreclrpal)
+
+target_link_libraries(paltest_getstdhandle_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/GetStdHandle/test2/GetStdHandle.c b/src/pal/tests/palsuite/file_io/GetStdHandle/test2/GetStdHandle.c
new file mode 100644
index 0000000000..45f5ddd243
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetStdHandle/test2/GetStdHandle.c
@@ -0,0 +1,79 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: GetStdHandle.c (test 2)
+**
+** Purpose: Smoke Tests the PAL implementation of the GetStdHandle function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ HANDLE hFile = NULL;
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ /*
+ * attempt to get an invalid handle
+ */
+ hFile = GetStdHandle(-2);
+ if (hFile != INVALID_HANDLE_VALUE)
+ {
+ Fail("GetStdHandle: ERROR -> A request for the STD_INPUT_HANDLE "
+ "returned an invalid handle.\n");
+ }
+
+
+ /*
+ * test the STD_INPUT_HANDLE handle
+ */
+ hFile = GetStdHandle(STD_INPUT_HANDLE);
+ if (hFile == INVALID_HANDLE_VALUE)
+ {
+ Fail("GetStdHandle: ERROR -> A request for the STD_INPUT_HANDLE "
+ "returned an invalid handle.\n");
+ }
+
+
+ /*
+ * test the STD_OUTPUT_HANDLE handle
+ */
+ hFile = GetStdHandle(STD_OUTPUT_HANDLE);
+ if (hFile == INVALID_HANDLE_VALUE)
+ {
+ Fail("GetStdHandle: ERROR -> A request for the STD_OUTPUT_HANDLE "
+ "returned an invalid handle.\n");
+ }
+
+ /* test the STD_ERROR_HANDLE handle */
+ hFile = GetStdHandle(STD_ERROR_HANDLE);
+ if (hFile == INVALID_HANDLE_VALUE)
+ {
+ Fail("GetStdHandle: ERROR -> A request for the STD_ERROR_HANDLE "
+ "returned an invalid handle.\n");
+ }
+
+
+ /* check to see if we can CloseHandle works on the STD_ERROR_HANDLE */
+ if (!CloseHandle(hFile))
+ {
+ Fail("GetStdHandle: ERROR -> CloseHandle failed. GetLastError "
+ "returned %u.\n",
+ GetLastError());
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/file_io/GetStdHandle/test2/testinfo.dat b/src/pal/tests/palsuite/file_io/GetStdHandle/test2/testinfo.dat
new file mode 100644
index 0000000000..dcd498c6ef
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetStdHandle/test2/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = GetStdHandle
+Name = Positive Test for GetStdHandle (test 2)
+Type = DEFAULT
+EXE1 = getstdhandle
+Description
+= Smoke Test GetStdHandle on a valid/invalid std handles
+
diff --git a/src/pal/tests/palsuite/file_io/GetSystemTime/CMakeLists.txt b/src/pal/tests/palsuite/file_io/GetSystemTime/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetSystemTime/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/file_io/GetSystemTime/test1/CMakeLists.txt b/src/pal/tests/palsuite/file_io/GetSystemTime/test1/CMakeLists.txt
new file mode 100644
index 0000000000..94d5bcded9
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetSystemTime/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.c
+)
+
+add_executable(paltest_getsystemtime_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getsystemtime_test1 coreclrpal)
+
+target_link_libraries(paltest_getsystemtime_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/GetSystemTime/test1/test.c b/src/pal/tests/palsuite/file_io/GetSystemTime/test1/test.c
new file mode 100644
index 0000000000..361dbef33d
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetSystemTime/test1/test.c
@@ -0,0 +1,124 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: test.c
+**
+** Purpose: Test for GetSystemTime() function
+**
+**
+**=========================================================*/
+
+/* Note: Some of the range comparisons only check
+ * the high end of the range. Since the structure
+ * contains WORDs, negative values can never be included,
+ * so there is no reason to check and see if the lower
+ * end of the spectrum is <0
+*/
+
+#include <palsuite.h>
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ SYSTEMTIME TheTime;
+ SYSTEMTIME firstTime;
+ SYSTEMTIME secondTime;
+
+ WORD avgDeltaFileTime = 0;
+
+ int i=0;
+
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ GetSystemTime(&TheTime);
+
+ /* Go through each item in the structure and ensure it is a valid value.
+ We can't ensure they have the exact values of the current time, but
+ at least that they have been set to a valid range of values for that
+ item.
+ */
+
+ /* Year */
+ if(TheTime.wYear < (WORD)2001)
+ {
+ Fail("ERROR: The year is %d, when it should be at least 2001.",
+ TheTime.wYear);
+ }
+
+ /* Month */
+ if(TheTime.wMonth > (WORD)12 || TheTime.wMonth < (WORD)1)
+ {
+ Fail("ERROR: The month should be between 1 and 12, and it is "
+ "showing up as %d.",TheTime.wMonth);
+ }
+
+ /* Weekday */
+ if(TheTime.wDayOfWeek > 6)
+ {
+ Fail("ERROR: The day of the week should be between 0 and 6, "
+ "and it is showing up as %d.",TheTime.wDayOfWeek);
+ }
+
+ /* Day of the Month */
+ if(TheTime.wDay > 31 || TheTime.wDay < 1)
+ {
+ Fail("ERROR: The day of the month should be between 1 and "
+ "31, and it is showing up as %d.",TheTime.wDay);
+ }
+
+ /* Hour */
+ if(TheTime.wHour > 23)
+ {
+ Fail("ERROR: The hour should be between 0 and 23, and it is "
+ "showing up as %d.",TheTime.wHour);
+ }
+
+ /* Minute */
+ if(TheTime.wMinute > 59)
+ {
+ Fail("ERROR: The minute should be between 0 and 59 and it is "
+ "showing up as %d.",TheTime.wMinute);
+ }
+
+ /* Second */
+ if(TheTime.wSecond > 59)
+ {
+ Fail("ERROR: The second should be between 0 and 59 and it is"
+ " showing up as %d.",TheTime.wSecond);
+ }
+
+ /* Millisecond */
+ if(TheTime.wMilliseconds > 999)
+ {
+ Fail("ERROR: The milliseconds should be between 0 and 999 "
+ "and it is currently showing %d.",TheTime.wMilliseconds);
+ }
+
+ /* check if two consecutive calls to system time return */
+ /* correct time in ms after sleep() call. */
+ for (i = 0; i<5 ;i++)
+ {
+ GetSystemTime(&firstTime);
+ Sleep(1000);
+ GetSystemTime(&secondTime);
+ avgDeltaFileTime += abs(firstTime.wSecond - secondTime.wSecond );
+
+ }
+
+ if( (avgDeltaFileTime/5) < 1.0)
+ {
+ Fail("ERROR: 2 calls for GetSystemTime interrupted"
+ " by a 1000 ms sleep failed Value[%f]", avgDeltaFileTime/5 );
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/file_io/GetSystemTime/test1/testinfo.dat b/src/pal/tests/palsuite/file_io/GetSystemTime/test1/testinfo.dat
new file mode 100644
index 0000000000..05169f65c6
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetSystemTime/test1/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = GetSystemTime
+Name = Positive test of GetSystemTime
+Type = DEFAULT
+EXE1 = test
+Description
+= Tests the PAL implementation of the GetSystemTime API
diff --git a/src/pal/tests/palsuite/file_io/GetSystemTimeAsFileTime/CMakeLists.txt b/src/pal/tests/palsuite/file_io/GetSystemTimeAsFileTime/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetSystemTimeAsFileTime/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/file_io/GetSystemTimeAsFileTime/test1/CMakeLists.txt b/src/pal/tests/palsuite/file_io/GetSystemTimeAsFileTime/test1/CMakeLists.txt
new file mode 100644
index 0000000000..977a826e7a
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetSystemTimeAsFileTime/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ GetSystemTimeAsFileTime.c
+)
+
+add_executable(paltest_getsystemtimeasfiletime_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getsystemtimeasfiletime_test1 coreclrpal)
+
+target_link_libraries(paltest_getsystemtimeasfiletime_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/GetSystemTimeAsFileTime/test1/GetSystemTimeAsFileTime.c b/src/pal/tests/palsuite/file_io/GetSystemTimeAsFileTime/test1/GetSystemTimeAsFileTime.c
new file mode 100644
index 0000000000..bd7e856abd
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetSystemTimeAsFileTime/test1/GetSystemTimeAsFileTime.c
@@ -0,0 +1,86 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: GetSystemTimeAsFileTime.c
+**
+** Purpose: Tests the PAL implementation of GetSystemTimeAsFileTime
+** Take two times, three seconds apart, and ensure that the time is
+** increasing, and that it has increased at least 3 seconds.
+**
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+
+int __cdecl main(int argc, char **argv)
+{
+
+ FILETIME TheFirstTime, TheSecondTime;
+ ULONG64 FullFirstTime, FullSecondTime;
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ /* Get two times, 3 seconds apart */
+
+ GetSystemTimeAsFileTime( &TheFirstTime );
+
+ Sleep( 3000 );
+
+ GetSystemTimeAsFileTime( &TheSecondTime );
+
+ /* Convert them to ULONG64 to work with */
+
+ FullFirstTime = ((( (ULONG64)TheFirstTime.dwHighDateTime )<<32) |
+ ( (ULONG64)TheFirstTime.dwLowDateTime ));
+
+ FullSecondTime = ((( (ULONG64)TheSecondTime.dwHighDateTime )<<32) |
+ ( (ULONG64)TheSecondTime.dwLowDateTime ));
+
+ /* Test to ensure the second value is larger than the first */
+
+ if( FullSecondTime <= FullFirstTime )
+ {
+ Fail("ERROR: The system time didn't increase in the last "
+ "three seconds. The second time tested was less than "
+ "or equal to the first.");
+ }
+
+ /* Note: The 30000000 magic number is 3 seconds in hundreds of nano
+ seconds. This test checks to ensure at least 3 seconds passed
+ between the readings.
+ */
+
+ if( ( (LONG64)( FullSecondTime - FullFirstTime ) - 30000000 ) < 0 )
+ {
+ ULONG64 TimeError;
+
+ /* Note: This test used to compare the difference between full times
+ in terms of hundreds of nanoseconds. But the x86 clock seems to be
+ precise only to the level of about 10000 nanoseconds, so we would
+ fail the comparison depending on when we took time slices.
+
+ To fix this, we just check that we're within a millisecond of
+ sleeping 3000 milliseconds. We're not currently ensuring that we
+ haven't slept much more than 3000 ms. We may want to do that.
+ */
+ TimeError = 30000000 - ( FullSecondTime - FullFirstTime );
+ if ( TimeError > 10000)
+ {
+ Fail("ERROR: Two system times were tested, with a sleep of 3 "
+ "seconds between. The time passed should have been at least "
+ "3 seconds. But, it was less according to the function.");
+ }
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/file_io/GetSystemTimeAsFileTime/test1/testinfo.dat b/src/pal/tests/palsuite/file_io/GetSystemTimeAsFileTime/test1/testinfo.dat
new file mode 100644
index 0000000000..3318d1386a
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetSystemTimeAsFileTime/test1/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = GetSystemTimeAsFileTime
+Name = Positive Test for GetSystemTimeAsFileTime
+TYPE = DEFAULT
+EXE1 = getsystemtimeasfiletime
+Description
+= Test the GetSystemTimeAsFileTime function.
+= Take two times, three seconds apart, and ensure that the time is
+= increasing, and that it has increased at least 3 seconds.
diff --git a/src/pal/tests/palsuite/file_io/GetTempFileNameA/CMakeLists.txt b/src/pal/tests/palsuite/file_io/GetTempFileNameA/CMakeLists.txt
new file mode 100644
index 0000000000..1962ade358
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetTempFileNameA/CMakeLists.txt
@@ -0,0 +1,6 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+add_subdirectory(test3)
+
diff --git a/src/pal/tests/palsuite/file_io/GetTempFileNameA/test1/CMakeLists.txt b/src/pal/tests/palsuite/file_io/GetTempFileNameA/test1/CMakeLists.txt
new file mode 100644
index 0000000000..1b759af2eb
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetTempFileNameA/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ GetTempFileNameA.c
+)
+
+add_executable(paltest_gettempfilenamea_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_gettempfilenamea_test1 coreclrpal)
+
+target_link_libraries(paltest_gettempfilenamea_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/GetTempFileNameA/test1/GetTempFileNameA.c b/src/pal/tests/palsuite/file_io/GetTempFileNameA/test1/GetTempFileNameA.c
new file mode 100644
index 0000000000..8ede8bab04
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetTempFileNameA/test1/GetTempFileNameA.c
@@ -0,0 +1,125 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: GetTempFileNameA.c (test 1)
+**
+** Purpose: Tests the PAL implementation of the GetTempFileNameA function.
+**
+** Depends on:
+** GetFileAttributesA
+** DeleteFileA
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ UINT uiError = 0;
+ const UINT uUnique = 0;
+ const char* szDot = {"."};
+ const char* szValidPrefix = {"cfr"};
+ const char* szLongValidPrefix = {"cfrwxyz"};
+ char szReturnedName[256];
+ char szTempString[256];
+
+ if (0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ /* valid path with null prefix */
+ uiError = GetTempFileNameA(szDot, NULL, uUnique, szReturnedName);
+ if (uiError == 0)
+ {
+ Fail("GetTempFileNameA: ERROR -> Call failed with a valid path "
+ "with the error code: %ld\n", GetLastError());
+ }
+ else
+ {
+ /* verify temp file was created */
+ if (GetFileAttributesA(szReturnedName) == -1)
+ {
+ Fail("GetTempFileNameA: ERROR -> GetFileAttributes failed on the "
+ "returned temp file \"%s\" with error code: %ld.\n",
+ szReturnedName,
+ GetLastError());
+ }
+ if (DeleteFileA(szReturnedName) != TRUE)
+ {
+ Fail("GetTempFileNameA: ERROR -> DeleteFileW failed to delete"
+ "the created temp file with error code: %ld.\n", GetLastError());
+ }
+ }
+
+
+ /* valid path with valid prefix */
+ uiError = GetTempFileNameA(szDot, szValidPrefix, uUnique, szReturnedName);
+ if (uiError == 0)
+ {
+ Fail("GetTempFileNameA: ERROR -> Call failed with a valid path and "
+ "prefix with the error code: %ld\n", GetLastError());
+ }
+ else
+ {
+ /* verify temp file was created */
+ if (GetFileAttributesA(szReturnedName) == -1)
+ {
+ Fail("GetTempFileNameA: ERROR -> GetFileAttributes failed on the "
+ "returned temp file \"%s\" with error code: %ld.\n",
+ szReturnedName,
+ GetLastError());
+ }
+ if (DeleteFileA(szReturnedName) != TRUE)
+ {
+ Fail("GetTempFileNameA: ERROR -> DeleteFileW failed to delete"
+ "the created temp \"%s\" file with error code: %ld.\n",
+ szReturnedName,
+ GetLastError());
+ }
+ }
+
+ /* valid path with long prefix */
+ uiError = GetTempFileNameA(szDot, szLongValidPrefix, uUnique, szReturnedName);
+ if (uiError == 0)
+ {
+ Fail("GetTempFileNameA: ERROR -> Call failed with a valid path and "
+ "prefix with the error code: %ld\n", GetLastError());
+ }
+ else
+ {
+ /* verify temp file was created */
+ if (GetFileAttributesA(szReturnedName) == -1)
+ {
+ Fail("GetTempFileNameA: ERROR -> GetFileAttributes failed on the "
+ "returned temp file \"%s\" with error code: %ld.\n",
+ szReturnedName,
+ GetLastError());
+ }
+
+ /* now verify that it only used the first 3 characters of the prefix */
+ sprintf(szTempString, "%s\\%s", szDot, szLongValidPrefix);
+ if (strncmp(szTempString, szReturnedName, 6) == 0)
+ {
+ Fail("GetTempFileNameA: ERROR -> It appears that an improper prefix "
+ "was used.\n");
+ }
+
+ if (DeleteFileA(szReturnedName) != TRUE)
+ {
+ Fail("GetTempFileNameA: ERROR -> DeleteFileW failed to delete"
+ "the created temp file \"%s\" with error code: %ld.\n",
+ szReturnedName,
+ GetLastError());
+ }
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/file_io/GetTempFileNameA/test1/testinfo.dat b/src/pal/tests/palsuite/file_io/GetTempFileNameA/test1/testinfo.dat
new file mode 100644
index 0000000000..4bf0000b9f
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetTempFileNameA/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = GetTempFileNameA
+Name = Test for GetTempFileNameA (test 1)
+Type = DEFAULT
+EXE1 = gettempfilenamea
+Description
+= Tests the PAL implimentation of GetTempFileNameA by testing
+= various combinations of path and prefix names.
diff --git a/src/pal/tests/palsuite/file_io/GetTempFileNameA/test2/CMakeLists.txt b/src/pal/tests/palsuite/file_io/GetTempFileNameA/test2/CMakeLists.txt
new file mode 100644
index 0000000000..f4bd9b8797
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetTempFileNameA/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ GetTempFileNameA.c
+)
+
+add_executable(paltest_gettempfilenamea_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_gettempfilenamea_test2 coreclrpal)
+
+target_link_libraries(paltest_gettempfilenamea_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/GetTempFileNameA/test2/GetTempFileNameA.c b/src/pal/tests/palsuite/file_io/GetTempFileNameA/test2/GetTempFileNameA.c
new file mode 100644
index 0000000000..861a8b87e8
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetTempFileNameA/test2/GetTempFileNameA.c
@@ -0,0 +1,80 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: GetTempFileNameA.c (test 2)
+**
+** Purpose: Tests the number of files GetTempFileNameA can create.
+**
+** Depends on:
+** GetFileAttributesA
+** oodles of free disk space (>4.07GB)
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ UINT uiError = 0;
+ DWORD dwError = 0;
+ const UINT uUnique = 0;
+ const char* szDot = {"."};
+ const char* szValidPrefix = {"cfr"};
+ char szReturnedName[256];
+ DWORD i;
+
+ if (0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ /* test the number of temp files that can be created */
+ for (i = 0; i < 0x10005; i++)
+ {
+ uiError = GetTempFileNameA(szDot, szValidPrefix, uUnique, szReturnedName);
+ if (uiError == 0)
+ {
+ dwError = GetLastError();
+ if (dwError == ERROR_FILE_EXISTS)
+ {
+ /* file already existes so break out of the loop */
+ i--; /* decrement the count because it wasn't successful */
+ break;
+ }
+ else
+ {
+ /* it was something other than the file already existing? */
+ Fail("GetTempFileNameA: ERROR -> Call failed with a valid "
+ "path and prefix with the error code: %ld\n", GetLastError());
+ }
+ }
+ else
+ {
+ /* verify temp file was created */
+ if (GetFileAttributesA(szReturnedName) == -1)
+ {
+ Fail("GetTempFileNameA: ERROR -> GetFileAttributes failed "
+ "on the returned temp file \"%s\" with error code: %ld.\n",
+ szReturnedName,
+ GetLastError());
+ }
+ }
+ }
+
+ /* did it create more than 0xffff files */
+ if (i > 0xffff)
+ {
+ Fail("GetTempFileNameA: ERROR -> Was able to create more than 0xffff"
+ " temp files.\n");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/file_io/GetTempFileNameA/test2/testinfo.dat b/src/pal/tests/palsuite/file_io/GetTempFileNameA/test2/testinfo.dat
new file mode 100644
index 0000000000..ca46f6d842
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetTempFileNameA/test2/testinfo.dat
@@ -0,0 +1,17 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = GetTempFileNameA
+Name = Test for GetTempFileNameA (test 2)
+Type = DEFAULT
+EXE1 = gettempfilenamea
+Description
+= Test the number of files that can be created. Since
+= GetTempFileNameA only handles 8.3 file names, the test
+= attempts to create more than the maximum temp files possible
+= with a 3 character prefix. Since this test takes so long, it
+= is not to be included in the standard test harness.
+= This test will also need more than 4.07 GB free disk space.
diff --git a/src/pal/tests/palsuite/file_io/GetTempFileNameA/test3/CMakeLists.txt b/src/pal/tests/palsuite/file_io/GetTempFileNameA/test3/CMakeLists.txt
new file mode 100644
index 0000000000..9c02865575
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetTempFileNameA/test3/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ gettempfilenamea.c
+)
+
+add_executable(paltest_gettempfilenamea_test3
+ ${SOURCES}
+)
+
+add_dependencies(paltest_gettempfilenamea_test3 coreclrpal)
+
+target_link_libraries(paltest_gettempfilenamea_test3
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/GetTempFileNameA/test3/gettempfilenamea.c b/src/pal/tests/palsuite/file_io/GetTempFileNameA/test3/gettempfilenamea.c
new file mode 100644
index 0000000000..8eccc3d2e8
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetTempFileNameA/test3/gettempfilenamea.c
@@ -0,0 +1,159 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: GetTempFileNameA.c (test 3)
+**
+** Purpose: Tests the PAL implementation of the GetTempFileNameA function.
+** Checks the file attributes and ensures that getting a file name,
+** deleting the file and getting another doesn't produce the same
+** as the just deleted file. Also checks the file size is 0.
+**
+** Depends on:
+** GetFileAttributesA
+** CloseHandle
+** DeleteFileA
+** CreateFileA
+** GetFileSize
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ const UINT uUnique = 0;
+ UINT uiError;
+ const char* szDot = {"."};
+ char szReturnedName[MAX_LONGPATH];
+ char szReturnedName_02[MAX_LONGPATH];
+ DWORD dwFileSize = 0;
+ HANDLE hFile;
+
+ if (0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ /* valid path with null prefix */
+ uiError = GetTempFileNameA(szDot, NULL, uUnique, szReturnedName);
+ if (uiError == 0)
+ {
+ Fail("GetTempFileNameA: ERROR -> Call failed with a valid path "
+ "with the error code: %u.\n",
+ GetLastError());
+ }
+
+ /* verify temp file was created */
+ if (GetFileAttributesA(szReturnedName) == -1)
+ {
+ Fail("GetTempFileNameA: ERROR -> GetFileAttributes failed on the "
+ "returned temp file \"%s\" with error code: %u.\n",
+ szReturnedName,
+ GetLastError());
+ }
+
+ /*
+ ** verify that the file size is 0 bytes
+ */
+
+ hFile = CreateFileA(szReturnedName,
+ GENERIC_READ,
+ FILE_SHARE_READ,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+ if (hFile == INVALID_HANDLE_VALUE)
+ {
+ Trace("GetTempFileNameA: ERROR -> CreateFileA failed to open"
+ " the created temp file with error code: %u.\n",
+ GetLastError());
+ if (!DeleteFileA(szReturnedName))
+ {
+ Trace("GetTempFileNameA: ERROR -> DeleteFileA failed to delete"
+ " the created temp file with error code: %u.\n",
+ GetLastError());
+ }
+ Fail("");
+ }
+
+ if ((dwFileSize = GetFileSize(hFile, NULL)) != (DWORD)0)
+ {
+ Trace("GetTempFileNameA: ERROR -> GetFileSize returned %u whereas"
+ "it should have returned 0.\n",
+ dwFileSize);
+ if (!CloseHandle(hFile))
+ {
+ Trace("GetTempFileNameA: ERROR -> CloseHandle failed. "
+ "GetLastError returned: %u.\n",
+ GetLastError());
+ }
+ if (!DeleteFileA(szReturnedName))
+ {
+ Trace("GetTempFileNameA: ERROR -> DeleteFileA failed to delete"
+ " the created temp file with error code: %u.\n",
+ GetLastError());
+ }
+ Fail("");
+ }
+
+
+ if (!CloseHandle(hFile))
+ {
+ Fail("GetTempFileNameA: ERROR -> CloseHandle failed. "
+ "GetLastError returned: %u.\n",
+ GetLastError());
+ }
+
+ if (DeleteFileA(szReturnedName) != TRUE)
+ {
+ Fail("GetTempFileNameA: ERROR -> DeleteFileA failed to delete"
+ " the created temp file with error code: %u.\n",
+ GetLastError());
+ }
+
+ /* get another and make sure it's not the same as the last */
+ uiError = GetTempFileNameA(szDot, NULL, uUnique, szReturnedName_02);
+ if (uiError == 0)
+ {
+ Fail("GetTempFileNameA: ERROR -> Call failed with a valid path "
+ "with the error code: %u.\n",
+ GetLastError());
+ }
+
+ /* did we get different names? */
+ if (strcmp(szReturnedName, szReturnedName_02) == 0)
+ {
+ Trace("GetTempFileNameA: ERROR -> The first call returned \"%s\". "
+ "The second call returned \"%s\" and the two should not be"
+ " the same.\n",
+ szReturnedName,
+ szReturnedName_02);
+ if (!DeleteFileA(szReturnedName_02))
+ {
+ Trace("GetTempFileNameA: ERROR -> DeleteFileA failed to delete"
+ " the created temp file with error code: %u.\n",
+ GetLastError());
+ }
+ Fail("");
+ }
+
+ /* clean up */
+ if (!DeleteFileA(szReturnedName_02))
+ {
+ Fail("GetTempFileNameA: ERROR -> DeleteFileA failed to delete"
+ " the created temp file with error code: %u.\n",
+ GetLastError());
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/file_io/GetTempFileNameA/test3/testinfo.dat b/src/pal/tests/palsuite/file_io/GetTempFileNameA/test3/testinfo.dat
new file mode 100644
index 0000000000..f1f5bf5764
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetTempFileNameA/test3/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = GetTempFileNameA
+Name = Test for GetTempFileNameA (test 3)
+Type = DEFAULT
+EXE1 = gettempfilenamea
+Description
+= Tests the PAL implementation of the GetTempFileNameA function.
+= Checks the file attributes and ensures that getting a file name,
+= deleting the file and getting another doesn't produce the same
+= as the just deleted file. Also checks the file size is 0.
diff --git a/src/pal/tests/palsuite/file_io/GetTempFileNameW/CMakeLists.txt b/src/pal/tests/palsuite/file_io/GetTempFileNameW/CMakeLists.txt
new file mode 100644
index 0000000000..1962ade358
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetTempFileNameW/CMakeLists.txt
@@ -0,0 +1,6 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+add_subdirectory(test3)
+
diff --git a/src/pal/tests/palsuite/file_io/GetTempFileNameW/test1/CMakeLists.txt b/src/pal/tests/palsuite/file_io/GetTempFileNameW/test1/CMakeLists.txt
new file mode 100644
index 0000000000..1b6c599da4
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetTempFileNameW/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ GetTempFileNameW.c
+)
+
+add_executable(paltest_gettempfilenamew_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_gettempfilenamew_test1 coreclrpal)
+
+target_link_libraries(paltest_gettempfilenamew_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/GetTempFileNameW/test1/GetTempFileNameW.c b/src/pal/tests/palsuite/file_io/GetTempFileNameW/test1/GetTempFileNameW.c
new file mode 100644
index 0000000000..43cda8f447
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetTempFileNameW/test1/GetTempFileNameW.c
@@ -0,0 +1,129 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: GetTempFileNameW.c (test 1)
+**
+** Purpose: Tests the PAL implementation of the GetTempFileNameW function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ UINT uiError = 0;
+ const UINT uUnique = 0;
+ WCHAR* wPrefix = NULL;
+ WCHAR* wPath = NULL;
+ WCHAR wReturnedName[256];
+ WCHAR wTempString[256];
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+
+ // valid path with null ext
+ wPath = convert(".");
+ uiError = GetTempFileNameW(wPath, wPrefix, uUnique, wReturnedName);
+ free (wPath);
+ if (uiError == 0)
+ {
+ Fail("GetTempFileNameW: ERROR -> Call failed with a valid path "
+ "with the error code: %ld\n", GetLastError());
+ }
+ else
+ {
+ // verify temp file was created
+ if (GetFileAttributesW(wReturnedName) == -1)
+ {
+ Fail("GetTempFileNameW: ERROR -> GetFileAttributes failed on the "
+ "returned temp file with error code: %ld.\n", GetLastError());
+ }
+ if (DeleteFileW(wReturnedName) != TRUE)
+ {
+ Fail("GetTempFileNameW: ERROR -> DeleteFileW failed to delete"
+ "the created temp file with error code: %lld.\n", GetLastError());
+ }
+ }
+
+
+ // valid path with valid prefix
+ wPath = convert(".");
+ wPrefix = convert("cfr");
+ uiError = GetTempFileNameW(wPath, wPrefix, uUnique, wReturnedName);
+ free (wPath);
+ free (wPrefix);
+ if (uiError == 0)
+ {
+ Fail("GetTempFileNameW: ERROR -> Call failed with a valid path and "
+ "prefix with the error code: %ld\n", GetLastError());
+ }
+ else
+ {
+ // verify temp file was created
+ if (GetFileAttributesW(wReturnedName) == -1)
+ {
+ Fail("GetTempFileNameW: ERROR -> GetFileAttributes failed on the "
+ "returned temp file with error code: %ld.\n", GetLastError());
+ }
+ if (DeleteFileW(wReturnedName) != TRUE)
+ {
+ Fail("GetTempFileNameW: ERROR -> DeleteFileW failed to delete"
+ "the created temp file with error code: %lld.\n", GetLastError());
+ }
+ }
+
+ // valid path with long prefix
+ wPath = convert(".");
+ wPrefix = convert("cfrwxyz");
+ uiError = GetTempFileNameW(wPath, wPrefix, uUnique, wReturnedName);
+ if (uiError == 0)
+ {
+ free (wPath);
+ free (wPrefix);
+ Fail("GetTempFileNameW: ERROR -> Call failed with a valid path and "
+ "prefix with the error code: %ld\n", GetLastError());
+ }
+ else
+ {
+ // verify temp file was created
+ if (GetFileAttributesW(wReturnedName) == -1)
+ {
+ free (wPath);
+ free (wPrefix);
+ Fail("GetTempFileNameW: ERROR -> GetFileAttributes failed on the "
+ "returned temp file with error code: %ld.\n", GetLastError());
+ }
+
+ // now verify that it only used the first 3 characters of the prefix
+ swprintf(wTempString, convert("%s\\%s"), wPath, wPrefix);
+ if (memcmp(wTempString, wReturnedName, wcslen(wTempString)*sizeof(WCHAR)) == 0)
+ {
+ free (wPath);
+ free (wPrefix);
+ Fail("GetTempFileNameW: ERROR -> It appears that an improper prefix "
+ "was used.\n");
+ }
+
+ if (DeleteFileW(wReturnedName) != TRUE)
+ {
+ free (wPath);
+ free (wPrefix);
+ Fail("GetTempFileNameW: ERROR -> DeleteFileW failed to delete"
+ "the created temp file with error code: %lld.\n", GetLastError());
+ }
+ }
+
+ free (wPath);
+ free (wPrefix);
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/file_io/GetTempFileNameW/test1/testinfo.dat b/src/pal/tests/palsuite/file_io/GetTempFileNameW/test1/testinfo.dat
new file mode 100644
index 0000000000..72af6930d9
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetTempFileNameW/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = GetTempFileNameW
+Name = Test for GetTempFileNameW (test 1)
+Type = DEFAULT
+EXE1 = gettempfilenamew
+Description
+= Test all the different options of GetTempFileNameW
+
diff --git a/src/pal/tests/palsuite/file_io/GetTempFileNameW/test2/CMakeLists.txt b/src/pal/tests/palsuite/file_io/GetTempFileNameW/test2/CMakeLists.txt
new file mode 100644
index 0000000000..851030d9ae
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetTempFileNameW/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ GetTempFileNameW.c
+)
+
+add_executable(paltest_gettempfilenamew_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_gettempfilenamew_test2 coreclrpal)
+
+target_link_libraries(paltest_gettempfilenamew_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/GetTempFileNameW/test2/GetTempFileNameW.c b/src/pal/tests/palsuite/file_io/GetTempFileNameW/test2/GetTempFileNameW.c
new file mode 100644
index 0000000000..2c8b19e081
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetTempFileNameW/test2/GetTempFileNameW.c
@@ -0,0 +1,84 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: GetTempFileNameW.c (test 2)
+**
+** Purpose: Tests the PAL implementation of the GetTempFileNameW function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ UINT uiError = 0;
+ DWORD dwError = 0;
+ const UINT uUnique = 0;
+ WCHAR* wPrefix = NULL;
+ WCHAR* wPath = NULL;
+ WCHAR wReturnedName[256];
+ DWORD i;
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+
+ // test the number of temp files that can be created
+ wPrefix = convert("cfr");
+ wPath = convert(".");
+ for (i = 0; i < 0x10005; i++)
+ {
+ uiError = GetTempFileNameW(wPath, wPrefix, uUnique, wReturnedName);
+ if (uiError == 0)
+ {
+ dwError = GetLastError();
+ if (dwError == ERROR_FILE_EXISTS)
+ {
+ // file already existes so break out of the loop
+ i--; // decrement the count because it wasn't successful
+ break;
+ }
+ else
+ {
+ // it was something other than the file already existing?
+ free (wPath);
+ free (wPrefix);
+ Fail("GetTempFileNameW: ERROR -> Call failed with a valid "
+ "path and prefix with the error code: %ld\n", GetLastError());
+ }
+ }
+ else
+ {
+ // verify temp file was created
+ if (GetFileAttributesW(wReturnedName) == -1)
+ {
+ free (wPath);
+ free (wPrefix);
+ Fail("GetTempFileNameW: ERROR -> GetFileAttributes failed "
+ "on the returned temp file with error code: %ld.\n",
+ GetLastError());
+ }
+ }
+ }
+
+ free (wPath);
+ free (wPrefix);
+
+ // did it create more than 0xffff files
+ if (i > 0xffff)
+ {
+ Fail("GetTempFileNameW: ERROR -> Was able to create more than 0xffff"
+ " temp files.\n");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/file_io/GetTempFileNameW/test2/testinfo.dat b/src/pal/tests/palsuite/file_io/GetTempFileNameW/test2/testinfo.dat
new file mode 100644
index 0000000000..72500111ad
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetTempFileNameW/test2/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = GetTempFileNameW
+Name = Test for GetTempFileNameW (test 2)
+Type = DEFAULT
+EXE1 = gettempfilenamew
+Description
+= This test attempts to create over 65000 files and will
+= have to be run manually because it will take longer than
+= the maximum 60 seconds allowed per test
+
diff --git a/src/pal/tests/palsuite/file_io/GetTempFileNameW/test3/CMakeLists.txt b/src/pal/tests/palsuite/file_io/GetTempFileNameW/test3/CMakeLists.txt
new file mode 100644
index 0000000000..82dd0a9f3f
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetTempFileNameW/test3/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ gettempfilenamew.c
+)
+
+add_executable(paltest_gettempfilenamew_test3
+ ${SOURCES}
+)
+
+add_dependencies(paltest_gettempfilenamew_test3 coreclrpal)
+
+target_link_libraries(paltest_gettempfilenamew_test3
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/GetTempFileNameW/test3/gettempfilenamew.c b/src/pal/tests/palsuite/file_io/GetTempFileNameW/test3/gettempfilenamew.c
new file mode 100644
index 0000000000..96d8e66410
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetTempFileNameW/test3/gettempfilenamew.c
@@ -0,0 +1,161 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: GetTempFileNameW.c (test 3)
+**
+** Purpose: Tests the PAL implementation of the GetTempFileNameW function.
+** Checks the file attributes and ensures that getting a file name,
+** deleting the file and getting another doesn't produce the same
+** as the just deleted file. Also checks the file size is 0.
+**
+** Depends on:
+** GetFileAttributesW
+** DeleteFileW
+** CreateFileW
+** GetFileSize
+** CloseHandle
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ const UINT uUnique = 0;
+ UINT uiError;
+ WCHAR szwReturnedName[MAX_LONGPATH];
+ WCHAR szwReturnedName_02[MAX_LONGPATH];
+ DWORD dwFileSize = 0;
+ HANDLE hFile;
+ const WCHAR szwDot[] = {'.','\0'};
+ const WCHAR szwPre[] = {'c','\0'};
+
+ if (0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ /* valid path with null prefix */
+ uiError = GetTempFileNameW(szwDot, szwPre, uUnique, szwReturnedName);
+ if (uiError == 0)
+ {
+ Fail("GetTempFileNameW: ERROR -> Call failed with a valid path "
+ "with the error code: %u.\n",
+ GetLastError());
+ }
+
+ /* verify temp file was created */
+ if (GetFileAttributesW(szwReturnedName) == -1)
+ {
+ Fail("GetTempFileNameW: ERROR -> GetFileAttributes failed on the "
+ "returned temp file \"%S\" with error code: %u.\n",
+ szwReturnedName,
+ GetLastError());
+ }
+
+ /*
+ ** verify that the file size is 0 bytes
+ */
+
+ hFile = CreateFileW(szwReturnedName,
+ GENERIC_READ,
+ FILE_SHARE_READ,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+ if (hFile == INVALID_HANDLE_VALUE)
+ {
+ Trace("GetTempFileNameW: ERROR -> CreateFileW failed to open"
+ " the created temp file with error code: %u.\n",
+ GetLastError());
+ if (!DeleteFileW(szwReturnedName))
+ {
+ Trace("GetTempFileNameW: ERROR -> DeleteFileW failed to delete"
+ " the created temp file with error code: %u.\n",
+ GetLastError());
+ }
+ Fail("");
+ }
+
+ if ((dwFileSize = GetFileSize(hFile, NULL)) != (DWORD)0)
+ {
+ Trace("GetTempFileNameW: ERROR -> GetFileSize returned %u whereas"
+ "it should have returned 0.\n",
+ dwFileSize);
+ if (!CloseHandle(hFile))
+ {
+ Trace("GetTempFileNameW: ERROR -> CloseHandle was unable to close the "
+ "opened file. GetLastError returned %u.\n",
+ GetLastError());
+ }
+ if (!DeleteFileW(szwReturnedName))
+ {
+ Trace("GetTempFileNameW: ERROR -> DeleteFileW failed to delete"
+ " the created temp file with error code: %u.\n",
+ GetLastError());
+ }
+ Fail("");
+ }
+
+ if (!CloseHandle(hFile))
+ {
+ Fail("GetTempFileNameW: ERROR -> CloseHandle was unable to close the "
+ "opened file. GetLastError returned %u.\n",
+ GetLastError());
+ }
+
+
+ /* delete the file to see if we get the same name next time around */
+ if (DeleteFileW(szwReturnedName) != TRUE)
+ {
+ Fail("GetTempFileNameW: ERROR -> DeleteFileW failed to delete"
+ " the created temp file with error code: %u.\n",
+ GetLastError());
+ }
+
+ /* get another and make sure it's not the same as the last */
+ uiError = GetTempFileNameW(szwDot, szwPre, uUnique, szwReturnedName_02);
+ if (uiError == 0)
+ {
+ Fail("GetTempFileNameW: ERROR -> Call failed with a valid path "
+ "with the error code: %u.\n",
+ GetLastError());
+ }
+
+ /* did we get different names? */
+ if (wcsncmp(szwReturnedName, szwReturnedName_02, wcslen(szwReturnedName)) == 0)
+ {
+ Fail("GetTempFileNameW: ERROR -> The first call returned \"%S\". "
+ "The second call returned \"%S\" and the two should not be"
+ " the same.\n",
+ szwReturnedName,
+ szwReturnedName_02);
+ if (!DeleteFileW(szwReturnedName_02))
+ {
+ Trace("GetTempFileNameW: ERROR -> DeleteFileW failed to delete"
+ " the created temp file with error code: %u.\n",
+ GetLastError());
+ }
+ Fail("");
+ }
+
+ /* clean up */
+ if (!DeleteFileW(szwReturnedName_02))
+ {
+ Fail("GetTempFileNameW: ERROR -> DeleteFileW failed to delete"
+ " the created temp file with error code: %u.\n",
+ GetLastError());
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/file_io/GetTempFileNameW/test3/testinfo.dat b/src/pal/tests/palsuite/file_io/GetTempFileNameW/test3/testinfo.dat
new file mode 100644
index 0000000000..dd482dbde5
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetTempFileNameW/test3/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = GetTempFileNameW
+Name = Test for GetTempFileNameW (test 3)
+Type = DEFAULT
+EXE1 = gettempfilenamew
+Description
+= Tests the PAL implementation of the GetTempFileNameW function.
+= Checks the file attributes and ensures that getting a file name,
+= deleting the file and getting another doesn't produce the same
+= as the just deleted file. Also checks the file size is 0.
diff --git a/src/pal/tests/palsuite/file_io/GetTempPathW/CMakeLists.txt b/src/pal/tests/palsuite/file_io/GetTempPathW/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetTempPathW/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/file_io/GetTempPathW/test1/CMakeLists.txt b/src/pal/tests/palsuite/file_io/GetTempPathW/test1/CMakeLists.txt
new file mode 100644
index 0000000000..f2979e9536
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetTempPathW/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ GetTempPathW.c
+)
+
+add_executable(paltest_gettemppathw_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_gettemppathw_test1 coreclrpal)
+
+target_link_libraries(paltest_gettemppathw_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/GetTempPathW/test1/GetTempPathW.c b/src/pal/tests/palsuite/file_io/GetTempPathW/test1/GetTempPathW.c
new file mode 100644
index 0000000000..08c88075ca
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetTempPathW/test1/GetTempPathW.c
@@ -0,0 +1,103 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: GetTempPathW.c (test 1)
+**
+** Purpose: Tests the PAL implementation of the GetTempPathW function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+static void SetTmpDir(WCHAR path[])
+{
+ DWORD result = SetEnvironmentVariableW(W("TMPDIR"), path);
+ if (!result)
+ {
+ Fail("ERROR -> SetEnvironmentVariableW failed with result %d and error code %d.\n",
+ result, GetLastError());
+ }
+}
+
+static void SetAndCompare(WCHAR tmpDirPath[], WCHAR expected[])
+{
+ DWORD dwBufferLength = _MAX_DIR;
+ WCHAR path[dwBufferLength];
+
+ SetTmpDir(tmpDirPath);
+
+ DWORD dwResultLen = GetTempPathW(dwBufferLength, path);
+ if (dwResultLen <= 0)
+ {
+ Fail("ERROR: GetTempPathW returned %d with error code %d.\n", dwResultLen, GetLastError());
+ }
+ if (dwResultLen >= dwBufferLength)
+ {
+ Fail("ERROR: Buffer of length %d passed to GetTempPathA was too small to hold %d chars..\n", dwBufferLength, dwResultLen);
+ }
+ if (wcscmp(expected, path) != 0)
+ {
+ Fail("ERROR: GetTempPathW expected to get '%S' but instead got '%S'.\n", expected, path);
+ }
+ if (expected[dwResultLen - 1] != '/')
+ {
+ Fail("ERROR: GetTempPathW returned '%S', which should have ended in '/'.\n", path);
+ }
+}
+
+static void SetAndCheckLength(WCHAR tmpDirPath [], int bufferLength, int expectedResultLength)
+{
+ WCHAR path[bufferLength];
+
+ SetTmpDir(tmpDirPath);
+ DWORD dwResultLen = GetTempPathW(bufferLength, path);
+
+ if (dwResultLen != expectedResultLength)
+ {
+ Fail("GetTempPathW(%d, %S) expected to return %d but returned %d.\n",
+ bufferLength, tmpDirPath?tmpDirPath:W("NULL"), expectedResultLength, dwResultLen);
+ }
+}
+
+int __cdecl main(int argc, char *argv[])
+{
+ if (0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ SetAndCompare(W("/tmp"), W("/tmp/"));
+ SetAndCompare(W("/tmp/"), W("/tmp/"));
+ SetAndCompare(W(""), W("/tmp/"));
+ SetAndCompare(NULL, W("/tmp/"));
+ SetAndCompare(W("/"), W("/"));
+ SetAndCompare(W("/var/tmp"), W("/var/tmp/"));
+ SetAndCompare(W("/var/tmp/"), W("/var/tmp/"));
+ SetAndCompare(W("~"), W("~/"));
+ SetAndCompare(W("~/"), W("~/"));
+ SetAndCompare(W(".tmp"), W(".tmp/"));
+ SetAndCompare(W("./tmp"), W("./tmp/"));
+ SetAndCompare(W("/home/someuser/sometempdir"), W("/home/someuser/sometempdir/"));
+ SetAndCompare(NULL, W("/tmp/"));
+
+ DWORD dwResultLen = GetTempPathA(0, NULL);
+ if (dwResultLen != 0 || GetLastError() != ERROR_INVALID_PARAMETER)
+ {
+ Fail("GetTempPathW(NULL, ...) returned %d with error code %d but "
+ "should have failed with ERROR_INVALID_PARAMETER (%d).\n",
+ dwResultLen, GetLastError(), ERROR_INVALID_PARAMETER);
+ }
+
+ SetAndCheckLength(W("abc/"), 5, 4);
+ SetAndCheckLength(W("abcd"), 5, 6);
+ SetAndCheckLength(W("abcde"), 5, 7);
+ SetAndCheckLength(W("abcdef/"), 5, 9);
+ SetAndCheckLength(NULL, 5, 6);
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/file_io/GetTempPathW/test1/testinfo.dat b/src/pal/tests/palsuite/file_io/GetTempPathW/test1/testinfo.dat
new file mode 100644
index 0000000000..84dc33832c
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/GetTempPathW/test1/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = GetTempPathW
+Name = Test for GetTempPathW (test 1)
+Type = DEFAULT
+EXE1 = gettemppathw
+Description
+= Calls GetTempPathW and verifies by passing the returned
+= value to CreateDirectoryW. If the returned path exists,
+= CreateDirectoryW will fail.
+
diff --git a/src/pal/tests/palsuite/file_io/MoveFileA/CMakeLists.txt b/src/pal/tests/palsuite/file_io/MoveFileA/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/MoveFileA/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/file_io/MoveFileA/test1/CMakeLists.txt b/src/pal/tests/palsuite/file_io/MoveFileA/test1/CMakeLists.txt
new file mode 100644
index 0000000000..9a3d0069db
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/MoveFileA/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ MoveFileA.c
+)
+
+add_executable(paltest_movefilea_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_movefilea_test1 coreclrpal)
+
+target_link_libraries(paltest_movefilea_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/MoveFileA/test1/ExpectedResults.txt b/src/pal/tests/palsuite/file_io/MoveFileA/test1/ExpectedResults.txt
new file mode 100644
index 0000000000..43b67af6b2
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/MoveFileA/test1/ExpectedResults.txt
@@ -0,0 +1 @@
+0101000001010000 \ No newline at end of file
diff --git a/src/pal/tests/palsuite/file_io/MoveFileA/test1/MoveFileA.c b/src/pal/tests/palsuite/file_io/MoveFileA/test1/MoveFileA.c
new file mode 100644
index 0000000000..8d1bc0eded
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/MoveFileA/test1/MoveFileA.c
@@ -0,0 +1,469 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: MoveFileA.c
+**
+** Purpose: Tests the PAL implementation of the MoveFileA function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+LPSTR lpSource[4] = {"src_existing.txt",
+ "src_non-existant.txt",
+ "src_dir_existing",
+ "src_dir_non-existant"};
+LPSTR lpDestination[4] = {"dst_existing.txt",
+ "dst_non-existant.txt",
+ "dst_dir_existing",
+ "dst_dir_non-existant"};
+
+
+/* Create all the required test files */
+int createExisting(void)
+{
+ FILE* tempFile = NULL;
+ DWORD dwError;
+ BOOL bRc = FALSE;
+ char szBuffer[100];
+
+ /* create the src_existing file */
+ tempFile = fopen(lpSource[0], "w");
+ if (tempFile != NULL)
+ {
+ fprintf(tempFile, "MoveFileA test file: src_existing.txt\n");
+ fclose(tempFile);
+ }
+ else
+ {
+ Trace("ERROR: couldn't create %s\n", lpSource[0]);
+ return FAIL;
+ }
+
+ /* create the src_dir_existing directory and files */
+ bRc = CreateDirectoryA(lpSource[2], NULL);
+ if (bRc != TRUE)
+ {
+ Trace("MoveFileA: ERROR: couldn't create \"%s\" because of "
+ "error code %ld\n",
+ lpSource[2],
+ GetLastError());
+ return FAIL;
+ }
+
+ memset(szBuffer, 0, 100);
+ sprintf(szBuffer, "%s/test01.txt", lpSource[2]);
+ tempFile = fopen(szBuffer, "w");
+ if (tempFile != NULL)
+ {
+ fprintf(tempFile, "MoveFileA test file: %s\n", szBuffer);
+ fclose(tempFile);
+ }
+ else
+ {
+ Trace("ERROR[%ld]:MoveFileA couldn't create %s\n", GetLastError(), szBuffer);
+ return FAIL;
+ }
+
+ memset(szBuffer, 0, 100);
+ sprintf(szBuffer, "%s/test02.txt", lpSource[2]);
+ tempFile = fopen(szBuffer, "w");
+ if (tempFile != NULL)
+ {
+ fprintf(tempFile, "MoveFileA test file: %s\n", szBuffer);
+ fclose(tempFile);
+ }
+ else
+ {
+ Trace("ERROR[%ld]: couldn't create %s\n", GetLastError(), szBuffer);
+ return FAIL;
+ }
+
+
+ /* create the dst_existing file */
+ tempFile = fopen(lpDestination[0], "w");
+ if (tempFile != NULL)
+ {
+ fprintf(tempFile, "MoveFileA test file: dst_existing.txt\n");
+ fclose(tempFile);
+ }
+ else
+ {
+ Trace("ERROR[%ld]:MoveFileA couldn't create \"%s\"\n", GetLastError(), lpDestination[0]);
+ return FAIL;
+ }
+
+ /* create the dst_dir_existing directory and files */
+ bRc = CreateDirectoryA(lpDestination[2], NULL);
+ if (bRc != TRUE)
+ {
+ dwError = GetLastError();
+ Trace("Error[%ld]:MoveFileA: couldn't create \"%s\"\n", GetLastError(), lpDestination[2]);
+ return FAIL;
+ }
+
+ tempFile = fopen("dst_dir_existing/test01.txt", "w");
+ if (tempFile != NULL)
+ {
+ fprintf(tempFile, "MoveFileA test file: dst_dir_existing/test01.txt\n");
+ fclose(tempFile);
+ }
+ else
+ {
+ Trace("ERROR: couldn't create dst_dir_existing/test01.txt\n");
+ return FAIL;
+ }
+ tempFile = fopen("dst_dir_existing/test02.txt", "w");
+ if (tempFile != NULL)
+ {
+ fprintf(tempFile, "MoveFileA test file: dst_dir_existing/test02.txt\n");
+ fclose(tempFile);
+ }
+ else
+ {
+ Trace("ERROR[%ul]: couldn't create dst_dir_existing/test02.txt\n", GetLastError());
+ return FAIL;
+ }
+
+ return PASS;
+}
+
+
+
+void removeDirectoryHelper(LPSTR dir, int location)
+{
+ DWORD dwAtt = GetFileAttributesA(dir);
+ if (( dwAtt != INVALID_FILE_ATTRIBUTES ) && ( dwAtt & FILE_ATTRIBUTE_DIRECTORY) )
+ {
+ if(!RemoveDirectoryA(dir))
+ {
+ Fail("ERROR: Failed to remove Directory [%s], Error Code [%d], location [%d]\n", dir, GetLastError(), location);
+ }
+ }
+}
+
+void removeFileHelper(LPSTR pfile, int location)
+{
+ FILE *fp;
+ fp = fopen( pfile, "r");
+
+ if (fp != NULL)
+ {
+ if(fclose(fp))
+ {
+ Fail("ERROR: Failed to close the file [%s], Error Code [%d], location [%d]\n", pfile, GetLastError(), location);
+ }
+
+ if(!DeleteFileA(pfile))
+ {
+ Fail("ERROR: Failed to delete file [%s], Error Code [%d], location [%d]\n", pfile, GetLastError(), location);
+ }
+ else
+ {
+ // Trace("Success: deleted file [%S], Error Code [%d], location [%d]\n", wfile, GetLastError(), location);
+ }
+ }
+
+}
+
+
+/* remove all created files in preparation for the next test */
+void removeAll(void)
+{
+ char szTemp[40];
+ DWORD dwAtt;
+
+ /* get rid of source dirs and files */
+ removeFileHelper(lpSource[0], 1);
+ removeFileHelper(lpSource[1], 2);
+
+ dwAtt = GetFileAttributesA(lpSource[2]);
+ if (( dwAtt != INVALID_FILE_ATTRIBUTES ) && ( dwAtt & FILE_ATTRIBUTE_DIRECTORY) )
+ {
+ sprintf(szTemp, "%s/test01.txt", lpSource[2]);
+ removeFileHelper(szTemp, 18);
+
+ sprintf(szTemp, "%s/test02.txt", lpSource[2]);
+ removeFileHelper(szTemp, 19);
+ removeDirectoryHelper(lpSource[2], 103);
+ }
+ else
+ {
+ removeFileHelper(lpSource[2], 17);
+ }
+
+
+ dwAtt = GetFileAttributesA(lpSource[3]);
+ if (( dwAtt != INVALID_FILE_ATTRIBUTES ) && ( dwAtt & FILE_ATTRIBUTE_DIRECTORY) )
+ {
+ sprintf(szTemp, "%s/test01.txt", lpSource[3]);
+ removeFileHelper(szTemp, 18);
+
+ sprintf(szTemp, "%s/test02.txt", lpSource[3]);
+ removeFileHelper(szTemp, 19);
+ removeDirectoryHelper(lpSource[3], 103);
+ }
+ else
+ {
+ removeFileHelper(lpSource[3], 17);
+ }
+
+ /* get rid of destination dirs and files */
+ dwAtt = GetFileAttributesA(lpDestination[0]);
+ if (( dwAtt != INVALID_FILE_ATTRIBUTES ) && ( dwAtt & FILE_ATTRIBUTE_DIRECTORY) )
+ {
+ sprintf(szTemp, "%s/test01.txt", lpDestination[0]);
+ removeFileHelper(szTemp, 18);
+
+ sprintf(szTemp, "%s/test02.txt", lpDestination[0]);
+ removeFileHelper(szTemp, 19);
+ removeDirectoryHelper(lpDestination[0], 103);
+ }
+ else
+ {
+ removeFileHelper(lpDestination[0], 17);
+ }
+
+ dwAtt = GetFileAttributesA(lpDestination[1]);
+ if (( dwAtt != INVALID_FILE_ATTRIBUTES ) && ( dwAtt & FILE_ATTRIBUTE_DIRECTORY) )
+ {
+ sprintf(szTemp, "%s/test01.txt", lpDestination[1]);
+ removeFileHelper(szTemp, 18);
+
+ sprintf(szTemp, "%s/test02.txt", lpDestination[1]);
+ removeFileHelper(szTemp, 19);
+ removeDirectoryHelper(lpDestination[1], 103);
+ }
+ else
+ {
+ removeFileHelper(lpDestination[1], 17);
+ }
+
+ dwAtt = GetFileAttributesA(lpDestination[2]);
+ if (( dwAtt != INVALID_FILE_ATTRIBUTES ) && ( dwAtt & FILE_ATTRIBUTE_DIRECTORY) )
+ {
+ sprintf(szTemp, "%s/test01.txt", lpDestination[2]);
+ removeFileHelper(szTemp, 18);
+
+ sprintf(szTemp, "%s/test02.txt", lpDestination[2]);
+ removeFileHelper(szTemp, 19);
+ removeDirectoryHelper(lpDestination[2], 103);
+ }
+ else
+ {
+ removeFileHelper(lpDestination[2], 17);
+ }
+
+ dwAtt = GetFileAttributesA(lpDestination[3]);
+ if (( dwAtt != INVALID_FILE_ATTRIBUTES ) && ( dwAtt & FILE_ATTRIBUTE_DIRECTORY) )
+ {
+ sprintf(szTemp, "%s/test01.txt", lpDestination[3]);
+ removeFileHelper(szTemp, 18);
+
+ sprintf(szTemp, "%s/test02.txt", lpDestination[3]);
+ removeFileHelper(szTemp, 19);
+ removeDirectoryHelper(lpDestination[3], 103);
+ }
+ else
+ {
+ removeFileHelper(lpDestination[3], 17);
+ }
+
+}
+
+
+
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ BOOL bRc = TRUE;
+ BOOL bSuccess = TRUE;
+ char results[40];
+ FILE* resultsFile = NULL;
+ int nCounter = 0;
+ int i, j;
+ char tempSource[] = {'t','e','m','p','k','.','t','m','p','\0'};
+ char tempDest[] = {'t','e','m','p','2','.','t','m','p','\0'};
+ HANDLE hFile;
+ DWORD result;
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ /* read in the expected results to compare with actual results */
+ memset (results, 0, 20);
+ resultsFile = fopen("expectedresults.txt", "r");
+ if (resultsFile == NULL)
+ {
+ Fail("MoveFileA ERROR[%ul]: Unable to open \"expectedresults.txt\"\n", GetLastError());
+ }
+
+ fgets(results, 20, resultsFile);
+ fclose(resultsFile);
+
+ /* clean the slate */
+ removeAll();
+
+ if (createExisting() != 0)
+ {
+ removeAll();
+ }
+
+
+ /* lpSource loop */
+ for (i = 0; i < 4; i++)
+ {
+ /* lpDestination loop */
+ for (j = 0; j < 4; j++)
+ {
+ bRc = MoveFileA(lpSource[i], lpDestination[j]);
+ if (!(
+ ((bRc == TRUE) && (results[nCounter] == '1'))
+ ||
+ ((bRc == FALSE ) && (results[nCounter] == '0')) )
+ )
+ {
+ Trace("MoveFileA: FAILED: test[%d][%d]: \"%s\" -> \"%s\"\n",
+ i, j, lpSource[i], lpDestination[j]);
+ bSuccess = FALSE;
+ }
+
+ /* undo the last move */
+ removeAll();
+ createExisting();
+
+ nCounter++;
+ }
+ }
+
+ removeAll();
+ if (bSuccess == FALSE)
+ {
+ Fail("MoveFileA: Test Failed");
+ }
+
+ /* create the temp source file */
+ hFile = CreateFileA(tempSource, GENERIC_WRITE, 0, 0, CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL, 0);
+
+ if( hFile == INVALID_HANDLE_VALUE )
+ {
+ Fail("Error[%ul]:MoveFileA: CreateFile failed to "
+ "create the file correctly.\n", GetLastError());
+ }
+
+ bRc = CloseHandle(hFile);
+ if(!bRc)
+ {
+ Trace("MoveFileA: CloseHandle failed to close the "
+ "handle correctly. ERROR:%u\n",GetLastError());
+
+ /* delete the created file */
+ bRc = DeleteFileA(tempSource);
+ if(!bRc)
+ {
+ Fail("Error[%ul]:MoveFileA: DeleteFileA failed to delete the"
+ "file correctly.\n", GetLastError());
+ }
+ Fail("");
+ }
+
+ /* set the file attributes to be readonly */
+ bRc = SetFileAttributesA(tempSource, FILE_ATTRIBUTE_READONLY);
+ if(!bRc)
+ {
+ Trace("MoveFileA: SetFileAttributes failed to set file "
+ "attributes correctly. GetLastError returned %u\n",GetLastError());
+ /* delete the created file */
+ bRc = DeleteFileA(tempSource);
+ if(!bRc)
+ {
+ Fail("Error[%ul]:MoveFileA: DeleteFileA failed to delete the"
+ "file correctly.\n", GetLastError());
+ }
+ Fail("");
+ }
+
+ /* move the file to the new location */
+ bRc = MoveFileA(tempSource, tempDest);
+ if(!bRc)
+ {
+ /* delete the created file */
+ bRc = DeleteFileA(tempSource);
+ if(!bRc)
+ {
+ Fail("Error[%ul]:MoveFileA: DeleteFileA failed to delete the"
+ "file correctly.\n", GetLastError());
+ }
+
+ Fail("Error[%ul]:MoveFileA(%S, %S): GetFileAttributes "
+ "failed to get the file's attributes.\n",
+ GetLastError(), tempSource, tempDest);
+ }
+
+ /* check that the newly moved file has the same file attributes
+ as the original */
+ result = GetFileAttributesA(tempDest);
+ if(result == 0)
+ {
+ /* delete the created file */
+ bRc = DeleteFileA(tempDest);
+ if(!bRc)
+ {
+ Fail("Error[%ul]:MoveFileA: DeleteFileA failed to delete the"
+ "file correctly.\n", GetLastError());
+ }
+
+ Fail("Error[%ul]:MoveFileA: GetFileAttributes failed to get "
+ "the file's attributes.\n", GetLastError());
+ }
+
+ if((result & FILE_ATTRIBUTE_READONLY) != FILE_ATTRIBUTE_READONLY)
+ {
+ /* delete the newly moved file */
+ bRc = DeleteFileA(tempDest);
+ if(!bRc)
+ {
+ Fail("Error[%ul]:MoveFileA: DeleteFileA failed to delete the"
+ "file correctly.\n", GetLastError());
+ }
+
+ Fail("Error[%ul]MoveFileA: GetFileAttributes failed to get "
+ "the correct file attributes.\n", GetLastError());
+ }
+
+ /* set the file attributes back to normal, to be deleted */
+ bRc = SetFileAttributesA(tempDest, FILE_ATTRIBUTE_NORMAL);
+ if(!bRc)
+ {
+ /* delete the newly moved file */
+ bRc = DeleteFileA(tempDest);
+ if(!bRc)
+ {
+ Fail("Error[%ul]:MoveFileA: DeleteFileA failed to delete the"
+ "file correctly.\n", GetLastError());
+ }
+
+ Fail("Error[%ul]:MoveFileA: SetFileAttributes failed to set "
+ "file attributes correctly.\n", GetLastError());
+ }
+
+ /* delete the newly moved file */
+ bRc = DeleteFileA(tempDest);
+ if(!bRc)
+ {
+ Fail("Error[%ul]:MoveFileA: DeleteFileA failed to delete the"
+ "file correctly.\n", GetLastError());
+ }
+
+ PAL_Terminate();
+
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/file_io/MoveFileA/test1/testinfo.dat b/src/pal/tests/palsuite/file_io/MoveFileA/test1/testinfo.dat
new file mode 100644
index 0000000000..685072fcd9
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/MoveFileA/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = MoveFileA
+Name = Positive Test for MoveFileA
+TYPE = DEFAULT
+EXE1 = movefilea
+Description
+=Performs a number of MoveFileA tests and uses the
+=file ExpectedResults.txt to determine if the test passed/failed
diff --git a/src/pal/tests/palsuite/file_io/MoveFileExA/CMakeLists.txt b/src/pal/tests/palsuite/file_io/MoveFileExA/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/MoveFileExA/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/file_io/MoveFileExA/test1/CMakeLists.txt b/src/pal/tests/palsuite/file_io/MoveFileExA/test1/CMakeLists.txt
new file mode 100644
index 0000000000..f41dd7fd08
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/MoveFileExA/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ MoveFileExA.c
+)
+
+add_executable(paltest_movefileexa_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_movefileexa_test1 coreclrpal)
+
+target_link_libraries(paltest_movefileexa_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/MoveFileExA/test1/ExpectedResults.txt b/src/pal/tests/palsuite/file_io/MoveFileExA/test1/ExpectedResults.txt
new file mode 100644
index 0000000000..684b8a536f
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/MoveFileExA/test1/ExpectedResults.txt
@@ -0,0 +1 @@
+01110011000000000111001100000000
diff --git a/src/pal/tests/palsuite/file_io/MoveFileExA/test1/MoveFileExA.c b/src/pal/tests/palsuite/file_io/MoveFileExA/test1/MoveFileExA.c
new file mode 100644
index 0000000000..0bce2b08d1
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/MoveFileExA/test1/MoveFileExA.c
@@ -0,0 +1,360 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: MoveFileExA.c
+**
+** Purpose: Tests the PAL implementation of the MoveFileExA function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+
+LPSTR lpSource[4] = {
+ "src_existing.tmp",
+ "src_non-existant.tmp",
+ "src_dir_existing",
+ "src_dir_non-existant"
+ };
+LPSTR lpDestination[4]={
+ "dst_existing.tmp",
+ "dst_non-existant.tmp",
+ "dst_dir_existing",
+ "dst_dir_non-existant"
+ };
+
+LPSTR lpFiles[14] ={
+ "src_dir_existing\\test01.tmp",
+ "src_dir_existing\\test02.tmp",
+ "dst_dir_existing\\test01.tmp",
+ "dst_dir_existing\\test02.tmp",
+ "src_dir_non-existant\\test01.tmp",
+ "src_dir_non-existant\\test02.tmp",
+ "dst_existing.tmp\\test01.tmp",
+ "dst_existing.tmp\\test02.tmp",
+ "dst_non-existant.tmp\\test01.tmp",
+ "dst_non-existant.tmp\\test02.tmp",
+ "dst_dir_existing\\test01.tmp",
+ "dst_dir_existing\\test02.tmp",
+ "dst_dir_non-existant\\test01.tmp",
+ "dst_dir_non-existant\\test02.tmp"
+ };
+
+DWORD dwFlag[2] = {MOVEFILE_COPY_ALLOWED, MOVEFILE_REPLACE_EXISTING};
+
+
+
+
+int createExisting(void)
+{
+ HANDLE tempFile = NULL;
+ HANDLE tempFile2 = NULL;
+
+ /* create the src_existing file and dst_existing file */
+ tempFile = CreateFileA(lpSource[0], GENERIC_WRITE, 0, 0, CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL, 0);
+ tempFile2 = CreateFileA(lpDestination[0], GENERIC_WRITE, 0, 0, CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL, 0);
+ CloseHandle(tempFile2);
+ CloseHandle(tempFile);
+
+ if ((tempFile == NULL) || (tempFile2 == NULL))
+ {
+ Trace("ERROR[%ul]: couldn't create %S or %S\n", GetLastError(), lpSource[0],
+ lpDestination[0]);
+ return FAIL;
+ }
+
+ /* create the src_dir_existing and dst_dir_existing directory and files */
+ CreateDirectoryA(lpSource[2], NULL);
+
+ tempFile = CreateFileA(lpFiles[0], GENERIC_WRITE, 0, 0, CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL, 0);
+ tempFile2 = CreateFileA(lpFiles[1], GENERIC_WRITE, 0, 0, CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL, 0);
+ CloseHandle(tempFile2);
+ CloseHandle(tempFile);
+
+ if ((tempFile == NULL) || (tempFile2 == NULL))
+ {
+ Trace("ERROR[%ul]: couldn't create src_dir_existing\\test01.tmp\n", GetLastError());
+ return FAIL;
+ }
+
+ CreateDirectoryA(lpDestination[2], NULL);
+ tempFile = CreateFileA(lpFiles[2], GENERIC_WRITE, 0, 0, CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL, 0);
+ tempFile2 = CreateFileA(lpFiles[3], GENERIC_WRITE, 0, 0, CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL, 0);
+ CloseHandle(tempFile2);
+ CloseHandle(tempFile);
+
+ if ((tempFile == NULL) || (tempFile2 == NULL))
+ {
+ Trace("ERROR[%ul]: couldn't create dst_dir_existing\\test01.tmp\n" , GetLastError());
+ return FAIL;
+ }
+ return PASS;
+
+}
+
+void removeDirectoryHelper(LPSTR dir, int location)
+{
+ DWORD dwAtt = GetFileAttributesA(dir);
+
+ if (( dwAtt != INVALID_FILE_ATTRIBUTES ) && ( dwAtt & FILE_ATTRIBUTE_DIRECTORY) )
+ {
+ if(!RemoveDirectoryA(dir))
+ {
+ Fail("ERROR: Failed to remove Directory [%s], Error Code [%d], location [%d]\n", dir, GetLastError(), location);
+ }
+ }
+}
+
+void removeFileHelper(LPSTR pfile, int location)
+{
+ FILE *fp;
+ fp = fopen( pfile, "r");
+
+ if (fp != NULL)
+ {
+ if(fclose(fp))
+ {
+ Fail("ERROR: Failed to close the file [%s], Error Code [%d], location [%d]\n", pfile, GetLastError(), location);
+ }
+
+ if(!DeleteFileA(pfile))
+ {
+ Fail("ERROR: Failed to delete file [%s], Error Code [%d], location [%d]\n", pfile, GetLastError(), location);
+ }
+ }
+
+}
+
+void removeAll(void)
+{
+ DWORD dwAtt;
+ /* get rid of destination dirs and files */
+ removeFileHelper(lpSource[0], 11);
+ removeFileHelper(lpSource[1], 12);
+ removeFileHelper(lpFiles[0], 13);
+ removeFileHelper(lpFiles[1], 14);
+
+ removeDirectoryHelper(lpSource[2], 101);
+ removeFileHelper(lpFiles[4], 15);
+ removeFileHelper(lpFiles[5], 16);
+ removeDirectoryHelper(lpSource[3], 102);
+
+ /* get rid of destination dirs and files */
+ dwAtt = GetFileAttributesA(lpDestination[0]);
+ if (( dwAtt != INVALID_FILE_ATTRIBUTES ) && ( dwAtt & FILE_ATTRIBUTE_DIRECTORY) )
+ {
+ removeFileHelper(lpFiles[6], 18);
+ removeFileHelper(lpFiles[7], 19);
+ removeDirectoryHelper(lpDestination[0], 103);
+ }
+ else
+ {
+ removeFileHelper(lpDestination[0], 17);
+ }
+
+ dwAtt = GetFileAttributesA(lpDestination[1]);
+ if (( dwAtt != INVALID_FILE_ATTRIBUTES ) && ( dwAtt & FILE_ATTRIBUTE_DIRECTORY) )
+ {
+ removeFileHelper(lpFiles[8], 21);
+ removeFileHelper(lpFiles[9], 22);
+ removeDirectoryHelper(lpDestination[1], 104);
+ }
+ else
+ {
+ removeFileHelper(lpDestination[1], 19);
+ }
+
+ dwAtt = GetFileAttributesA(lpDestination[2]);
+ if (( dwAtt != INVALID_FILE_ATTRIBUTES ) && ( dwAtt & FILE_ATTRIBUTE_DIRECTORY) )
+ {
+ removeFileHelper(lpFiles[10], 24);
+ removeFileHelper(lpFiles[11], 25);
+ removeDirectoryHelper(lpDestination[2], 105);
+ }
+ else
+ {
+ removeFileHelper(lpDestination[2], 23);
+ }
+
+ dwAtt = GetFileAttributesA(lpDestination[3]);
+ if (( dwAtt != INVALID_FILE_ATTRIBUTES ) && ( dwAtt & FILE_ATTRIBUTE_DIRECTORY) )
+ {
+ removeFileHelper(lpFiles[12], 26);
+ removeFileHelper(lpFiles[13], 27);
+ removeDirectoryHelper(lpDestination[3], 106);
+ }
+ else
+ {
+ removeFileHelper(lpDestination[3], 107);
+ }
+
+}
+
+int __cdecl main(int argc, char *argv[])
+{
+ BOOL bRc = TRUE;
+ char results[40];
+ FILE* resultsFile = NULL;
+ int i, j, k, nCounter = 0;
+ int res = FAIL;
+ char tempSource[] = {'t','e','m','p','k','.','t','m','p','\0'};
+ char tempDest[] = {'t','e','m','p','2','.','t','m','p','\0'};
+ HANDLE hFile;
+ DWORD result;
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ /* read in the expected results to compare with actual results */
+ memset (results, 0, 34);
+ resultsFile = fopen("expectedresults.txt", "r");
+ if (resultsFile == NULL)
+ {
+ Trace("MoveFileExA ERROR: Unable to open \"expectedresults.txt\"\n");
+ goto EXIT;
+ }
+
+ fgets(results, 34, resultsFile);
+ fclose(resultsFile);
+
+ nCounter = 0;
+
+
+ /* clean the slate */
+ removeAll();
+ if (createExisting() != PASS)
+ {
+ goto EXIT;
+ }
+
+ /* lpSource loop */
+ for (i = 0; i < 4; i++)
+ {
+ /* lpDestination loop */
+ for (j = 0; j < 4; j++)
+ {
+ /* dwFlag loop */
+ for (k = 0; k < 2; k++)
+ {
+
+ /* move the file to the new location */
+ bRc = MoveFileExA(lpSource[i], lpDestination[j], dwFlag[k]);
+
+ if (!(
+ ((bRc == TRUE) && (results[nCounter] == '1'))
+ ||
+ ((bRc == FALSE ) && (results[nCounter] == '0')) )
+ )
+ {
+ Trace("MoveFileExA(%s, %s, %s): Values of i[%d], j[%d], k [%d] and results[%d]=%c LastError[%d]Flag[%d]FAILED\n",
+ lpSource[i], lpDestination[j],
+ k == 1 ?
+ "MOVEFILE_REPLACE_EXISTING":"MOVEFILE_COPY_ALLOWED", i, j, k, nCounter, results[nCounter], GetLastError(), bRc);
+ goto EXIT;
+ }
+
+ /* undo the last move */
+ removeAll();
+ if (createExisting() != PASS)
+ {
+ goto EXIT;
+ }
+ nCounter++;
+ }
+ }
+ }
+
+ /* create the temp source file */
+ hFile = CreateFileA(tempSource, GENERIC_WRITE, 0, 0, CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL, 0);
+
+ if( hFile == INVALID_HANDLE_VALUE )
+ {
+ Trace("MoveFileExA: CreateFile failed to "
+ "create the file correctly.\n");
+ goto EXIT;
+ }
+
+ bRc = CloseHandle(hFile);
+ if(!bRc)
+ {
+ Trace("MoveFileExA: CloseHandle failed to close the "
+ "handle correctly. yo %u\n",GetLastError());
+ goto EXIT;
+ }
+
+ /* set the file attributes to be readonly */
+ bRc = SetFileAttributesA(tempSource, FILE_ATTRIBUTE_READONLY);
+ if(!bRc)
+ {
+ Trace("MoveFileExA: SetFileAttributes failed to set file "
+ "attributes correctly. ERROR:%u\n",GetLastError());
+ goto EXIT;
+ }
+
+ /* move the file to the new location */
+ bRc = MoveFileExA(tempSource, tempDest, MOVEFILE_COPY_ALLOWED );
+ if(!bRc)
+ {
+ Trace("MoveFileExA(%S, %S, %s): GetFileAttributes "
+ "failed to get the file's attributes.\n",
+ tempSource, tempDest, "MOVEFILE_COPY_ALLOWED");
+ goto EXIT;
+ }
+
+ /* check that the newly moved file has the same file attributes
+ as the original */
+ result = GetFileAttributesA(tempDest);
+ if(result == 0)
+ {
+ Trace("MoveFileExA: GetFileAttributes failed to get "
+ "the file's attributes.\n");
+ goto EXIT;
+ }
+
+ if((result & FILE_ATTRIBUTE_READONLY) != FILE_ATTRIBUTE_READONLY)
+ {
+ Trace("MoveFileExA: GetFileAttributes failed to get "
+ "the correct file attributes.\n");
+ goto EXIT;
+ }
+
+ /* set the file attributes back to normal, to be deleted */
+ bRc = SetFileAttributesA(tempDest, FILE_ATTRIBUTE_NORMAL);
+ if(!bRc)
+ {
+ Trace("MoveFileExA: SetFileAttributes "
+ "failed to set file attributes correctly.\n");
+ goto EXIT;
+ }
+
+ /* delete the newly moved file */
+ bRc = DeleteFileA(tempDest);
+ if(!bRc)
+ {
+ Trace("MoveFileExA: DeleteFileA failed to delete the"
+ "file correctly.\n");
+ goto EXIT;
+ }
+
+ res = PASS;
+
+EXIT:
+ removeAll();
+
+ PAL_TerminateEx(res);
+ return res;
+}
+
diff --git a/src/pal/tests/palsuite/file_io/MoveFileExA/test1/testinfo.dat b/src/pal/tests/palsuite/file_io/MoveFileExA/test1/testinfo.dat
new file mode 100644
index 0000000000..d8d19af880
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/MoveFileExA/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = MoveFileExA
+Name = Test for MoveFileExA (test 1)
+Type = DEFAULT
+EXE1 = movefileexa
+Description
+= Creates a number of files/directories and attempts to move them.
+
diff --git a/src/pal/tests/palsuite/file_io/MoveFileExW/CMakeLists.txt b/src/pal/tests/palsuite/file_io/MoveFileExW/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/MoveFileExW/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/file_io/MoveFileExW/test1/CMakeLists.txt b/src/pal/tests/palsuite/file_io/MoveFileExW/test1/CMakeLists.txt
new file mode 100644
index 0000000000..4c6a70f050
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/MoveFileExW/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ MoveFileExW.c
+)
+
+add_executable(paltest_movefileexw_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_movefileexw_test1 coreclrpal)
+
+target_link_libraries(paltest_movefileexw_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/MoveFileExW/test1/ExpectedResults.txt b/src/pal/tests/palsuite/file_io/MoveFileExW/test1/ExpectedResults.txt
new file mode 100644
index 0000000000..684b8a536f
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/MoveFileExW/test1/ExpectedResults.txt
@@ -0,0 +1 @@
+01110011000000000111001100000000
diff --git a/src/pal/tests/palsuite/file_io/MoveFileExW/test1/MoveFileExW.c b/src/pal/tests/palsuite/file_io/MoveFileExW/test1/MoveFileExW.c
new file mode 100644
index 0000000000..4f5b72dcf7
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/MoveFileExW/test1/MoveFileExW.c
@@ -0,0 +1,431 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: MoveFileExW.c
+**
+** Purpose: Tests the PAL implementation of the MoveFileExW function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+
+LPWSTR lpSource[4];
+LPWSTR lpDestination[4];
+LPWSTR lpFiles[14];
+
+DWORD dwFlag[2] = {MOVEFILE_COPY_ALLOWED, MOVEFILE_REPLACE_EXISTING};
+
+
+
+int createExisting(void)
+{
+ HANDLE tempFile = NULL;
+ HANDLE tempFile2 = NULL;
+
+ /* create the src_existing file and dst_existing file */
+ tempFile = CreateFileW(lpSource[0], GENERIC_WRITE, 0, 0, CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL, 0);
+ tempFile2 = CreateFileW(lpDestination[0], GENERIC_WRITE, 0, 0, CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL, 0);
+ CloseHandle(tempFile2);
+ CloseHandle(tempFile);
+
+ if ((tempFile == NULL) || (tempFile2 == NULL))
+ {
+ Trace("ERROR: couldn't create %S or %S\n", lpSource[0],
+ lpDestination[0]);
+ return FAIL;
+ }
+
+ /* create the src_dir_existing and dst_dir_existing directory and files */
+ CreateDirectoryW(lpSource[2], NULL);
+
+ tempFile = CreateFileW(lpFiles[0], GENERIC_WRITE, 0, 0, CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL, 0);
+ tempFile2 = CreateFileW(lpFiles[1], GENERIC_WRITE, 0, 0, CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL, 0);
+ CloseHandle(tempFile2);
+ CloseHandle(tempFile);
+
+ if ((tempFile == NULL) || (tempFile2 == NULL))
+ {
+ Trace("ERROR: couldn't create src_dir_existing\\test01.tmp\n");
+ return FAIL;
+ }
+
+ CreateDirectoryW(lpDestination[2], NULL);
+ tempFile = CreateFileW(lpFiles[2], GENERIC_WRITE, 0, 0, CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL, 0);
+ tempFile2 = CreateFileW(lpFiles[3], GENERIC_WRITE, 0, 0, CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL, 0);
+ CloseHandle(tempFile2);
+ CloseHandle(tempFile);
+
+ if ((tempFile == NULL) || (tempFile2 == NULL))
+ {
+ Trace("ERROR: couldn't create dst_dir_existing\\test01.tmp\n");
+ return FAIL;
+ }
+ return PASS;
+}
+
+void removeDirectoryHelper(LPWSTR dir, int location)
+{
+ DWORD dwAtt = GetFileAttributesW(dir);
+// Trace(" Value of location[%d], and directorye [%S]\n", location, dir);
+
+ if (( dwAtt != INVALID_FILE_ATTRIBUTES ) && ( dwAtt & FILE_ATTRIBUTE_DIRECTORY) )
+ {
+ if(!RemoveDirectoryW(dir))
+ {
+ Fail("ERROR: Failed to remove Directory [%S], Error Code [%d], location [%d]\n", dir, GetLastError(), location);
+ }
+ }
+}
+
+void removeFileHelper(LPWSTR wfile, int location)
+{
+ FILE *fp;
+ char * pfile = convertC(wfile);
+
+// Trace(" Value of location[%d], and file [%s]\n", location, pfile);
+ fp = fopen( pfile, "r");
+
+ if (fp != NULL)
+ {
+ if(fclose(fp))
+ {
+ Fail("ERROR: Failed to close the file [%S], Error Code [%d], location [%d]\n", wfile, GetLastError(), location);
+ }
+
+ if(!DeleteFileW(wfile))
+ {
+ Fail("ERROR: Failed to delete file [%S], Error Code [%d], location [%d]\n", wfile, GetLastError(), location);
+ }
+ else
+ {
+ // Trace("Success: deleted file [%S], Error Code [%d], location [%d]\n", wfile, GetLastError(), location);
+ }
+ }
+
+ free(pfile);
+}
+
+void removeAll(void)
+{
+ DWORD dwAtt;
+ /* get rid of destination dirs and files */
+ removeFileHelper(lpSource[0], 11);
+// lpSource[0] = convert("src_existing.tmp");
+
+ removeFileHelper(lpSource[1], 12);
+ //lpSource[1] = convert("src_non-existant.tmp");
+
+ removeFileHelper(lpFiles[0], 13);
+// lpFiles[0] = convert("src_dir_existing\\test01.tmp");
+
+ removeFileHelper(lpFiles[1], 14);
+// lpFiles[1] = convert("src_dir_existing\\test02.tmp");
+
+ removeDirectoryHelper(lpSource[2], 101);
+// lpSource[2] = convert("src_dir_existing");
+
+ removeFileHelper(lpFiles[4], 15);
+// lpFiles[4] = convert("src_dir_non-existant\\test01.tmp");
+
+ removeFileHelper(lpFiles[5], 16);
+// lpFiles[5] = convert("src_dir_non-existant\\test02.tmp");
+
+ removeDirectoryHelper(lpSource[3], 102);
+// lpSource[3] = convert("src_dir_non-existant");
+
+ /* get rid of destination dirs and files */
+ dwAtt = GetFileAttributesW(lpDestination[0]);
+ if (( dwAtt != INVALID_FILE_ATTRIBUTES ) && ( dwAtt & FILE_ATTRIBUTE_DIRECTORY) )
+ {
+ removeFileHelper(lpFiles[6], 18);
+ // lpFiles[6] = convert("dst_existing.tmp\\test01.tmp");
+ removeFileHelper(lpFiles[7], 19);
+ // lpFiles[7] = convert("dst_existing.tmp\\test02.tmp");
+ removeDirectoryHelper(lpDestination[0], 103);
+ // lpDestination[0] = convert("dst_existing.tmp");
+
+ }
+ else
+ {
+ removeFileHelper(lpDestination[0], 17);
+ // lpDestination[0] = convert("dst_existing.tmp");
+ }
+
+ dwAtt = GetFileAttributesW(lpDestination[1]);
+ if (( dwAtt != INVALID_FILE_ATTRIBUTES ) && ( dwAtt & FILE_ATTRIBUTE_DIRECTORY) )
+ {
+ removeFileHelper(lpFiles[8], 21);
+ // lpFiles[8] = convert("dst_non-existant.tmp\\test01.tmp");
+ removeFileHelper(lpFiles[9], 22);
+ // lpFiles[9] = convert("dst_non-existant.tmp\\test02.tmp");
+ removeDirectoryHelper(lpDestination[1], 104);
+ // lpDestination[1] = convert("dst_non-existant.tmp");
+
+ }
+ else
+ {
+ removeFileHelper(lpDestination[1], 19);
+ //lpDestination[1] = convert("dst_non-existant.tmp");
+ }
+
+ dwAtt = GetFileAttributesW(lpDestination[2]);
+ if (( dwAtt != INVALID_FILE_ATTRIBUTES ) && ( dwAtt & FILE_ATTRIBUTE_DIRECTORY) )
+ {
+ removeFileHelper(lpFiles[10], 24);
+ // lpFiles[10] = convert("dst_dir_existing\\test01.tmp");
+ removeFileHelper(lpFiles[11], 25);
+ // lpFiles[11] = convert("dst_dir_existing\\test02.tmp");
+ removeDirectoryHelper(lpDestination[2], 105);
+ // lpDestination[2] = convert("dst_dir_existing");
+
+ }
+ else
+ {
+ removeFileHelper(lpDestination[2], 23);
+ // lpDestination[2] = convert("dst_dir_existing");
+
+ }
+
+ dwAtt = GetFileAttributesW(lpDestination[3]);
+ if (( dwAtt != INVALID_FILE_ATTRIBUTES ) && ( dwAtt & FILE_ATTRIBUTE_DIRECTORY) )
+ {
+ removeFileHelper(lpFiles[12], 26);
+ // lpFiles[12] = convert("dst_dir_non-existant\\test01.tmp");
+ removeFileHelper(lpFiles[13], 27);
+ // lpFiles[13] = convert("dst_dir_non-existant\\test02.tmp");
+ removeDirectoryHelper(lpDestination[3], 106);
+ // lpDestination[3] = convert("dst_dir_non-existant");
+
+ }
+ else
+ {
+ removeFileHelper(lpDestination[3], 107);
+ // lpDestination[3] = convert("dst_dir_non-existant");
+
+ }
+
+}
+
+int __cdecl main(int argc, char *argv[])
+{
+ BOOL bRc = TRUE;
+ char results[40];
+ FILE* resultsFile = NULL;
+ int i, j, k, nCounter = 0;
+ int res = FAIL;
+ WCHAR tempSource[] = {'t','e','m','p','k','.','t','m','p','\0'};
+ WCHAR tempDest[] = {'t','e','m','p','2','.','t','m','p','\0'};
+ HANDLE hFile;
+ DWORD result;
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ lpSource[0] = convert("src_existing.tmp");
+ lpSource[1] = convert("src_non-existant.tmp");
+ lpSource[2] = convert("src_dir_existing");
+ lpSource[3] = convert("src_dir_non-existant");
+
+ lpDestination[0] = convert("dst_existing.tmp");
+ lpDestination[1] = convert("dst_non-existant.tmp");
+ lpDestination[2] = convert("dst_dir_existing");
+ lpDestination[3] = convert("dst_dir_non-existant");
+
+ lpFiles[0] = convert("src_dir_existing\\test01.tmp");
+ lpFiles[1] = convert("src_dir_existing\\test02.tmp");
+ lpFiles[2] = convert("dst_dir_existing\\test01.tmp");
+ lpFiles[3] = convert("dst_dir_existing\\test02.tmp");
+ lpFiles[4] = convert("src_dir_non-existant\\test01.tmp");
+ lpFiles[5] = convert("src_dir_non-existant\\test02.tmp");
+
+ lpFiles[6] = convert("dst_existing.tmp\\test01.tmp");
+ lpFiles[7] = convert("dst_existing.tmp\\test02.tmp");
+
+ lpFiles[8] = convert("dst_non-existant.tmp\\test01.tmp");
+ lpFiles[9] = convert("dst_non-existant.tmp\\test02.tmp");
+
+ lpFiles[10] = convert("dst_dir_existing\\test01.tmp");
+ lpFiles[11] = convert("dst_dir_existing\\test02.tmp");
+
+ lpFiles[12] = convert("dst_dir_non-existant\\test01.tmp");
+ lpFiles[13] = convert("dst_dir_non-existant\\test02.tmp");
+
+ /* read in the expected results to compare with actual results */
+ memset (results, 0, 34);
+ resultsFile = fopen("expectedresults.txt", "r");
+ if (resultsFile == NULL)
+ {
+ Trace("MoveFileExW ERROR: Unable to open \"expectedresults.txt\"\n");
+ goto EXIT;
+ }
+
+ fgets(results, 34, resultsFile);
+ fclose(resultsFile);
+
+// Trace("Value of results[%]=%s\n", i, results);
+ for( i = 0; i < 32; i++)
+ {
+ Trace("Value of results[%d]=%c\n", i, results[i]);
+ }
+ nCounter = 0;
+
+
+ /* clean the slate */
+ removeAll();
+ if (createExisting() != PASS)
+ {
+ goto EXIT;
+ }
+
+ /* lpSource loop */
+ for (i = 0; i < 4; i++)
+ {
+ /* lpDestination loop */
+ for (j = 0; j < 4; j++)
+ {
+ /* dwFlag loop */
+ for (k = 0; k < 2; k++)
+ {
+
+ //if(nCounter == 22)
+ //{
+ //exit(1);
+ //}
+ /* move the file to the new location */
+ bRc = MoveFileExW(lpSource[i], lpDestination[j], dwFlag[k]);
+
+ if (!(
+ ((bRc == TRUE) && (results[nCounter] == '1'))
+ ||
+ ((bRc == FALSE ) && (results[nCounter] == '0')) )
+ )
+ {
+ Trace("MoveFileExW(%S, %S, %s): Values of i[%d], j[%d], k [%d] and results[%d]=%c LastError[%d]Flag[%d]FAILED\n",
+ lpSource[i], lpDestination[j],
+ k == 1 ?
+ "MOVEFILE_REPLACE_EXISTING":"MOVEFILE_COPY_ALLOWED", i, j, k, nCounter, results[nCounter], GetLastError(), bRc);
+ goto EXIT;
+ }
+
+ //Trace("MoveFileExW(%S, %S, %s): Values of i[%d], j[%d], k [%d] and results[%d]=%c \n",
+ // lpSource[i], lpDestination[j],
+ // k == 1 ?
+ // "MOVEFILE_REPLACE_EXISTING":"MOVEFILE_COPY_ALLOWED", i, j, k, nCounter, results[nCounter]);
+
+
+ /* undo the last move */
+ removeAll();
+ if (createExisting() != PASS)
+ {
+ goto EXIT;
+ }
+ //Trace("Counter [%d] over \n", nCounter);
+ nCounter++;
+ }
+ }
+ }
+
+ /* create the temp source file */
+ hFile = CreateFileW(tempSource, GENERIC_WRITE, 0, 0, CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL, 0);
+
+ if( hFile == INVALID_HANDLE_VALUE )
+ {
+ Trace("MoveFileExW: CreateFile failed to "
+ "create the file correctly.\n");
+ goto EXIT;
+ }
+
+ bRc = CloseHandle(hFile);
+ if(!bRc)
+ {
+ Trace("MoveFileExW: CloseHandle failed to close the "
+ "handle correctly. yo %u\n",GetLastError());
+ goto EXIT;
+ }
+
+ /* set the file attributes to be readonly */
+ bRc = SetFileAttributesW(tempSource, FILE_ATTRIBUTE_READONLY);
+ if(!bRc)
+ {
+ Trace("MoveFileExW: SetFileAttributes failed to set file "
+ "attributes correctly. ERROR:%u\n",GetLastError());
+ goto EXIT;
+ }
+
+ /* move the file to the new location */
+ bRc = MoveFileExW(tempSource, tempDest, MOVEFILE_COPY_ALLOWED );
+ if(!bRc)
+ {
+ Trace("MoveFileExW(%S, %S, %s): GetFileAttributes "
+ "failed to get the file's attributes.\n",
+ tempSource, tempDest, "MOVEFILE_COPY_ALLOWED");
+ goto EXIT;
+ }
+
+ /* check that the newly moved file has the same file attributes
+ as the original */
+ result = GetFileAttributesW(tempDest);
+ if(result == 0)
+ {
+ Trace("MoveFileExW: GetFileAttributes failed to get "
+ "the file's attributes.\n");
+ goto EXIT;
+ }
+
+ if((result & FILE_ATTRIBUTE_READONLY) != FILE_ATTRIBUTE_READONLY)
+ {
+ Trace("MoveFileExW: GetFileAttributes failed to get "
+ "the correct file attributes.\n");
+ goto EXIT;
+ }
+
+ /* set the file attributes back to normal, to be deleted */
+ bRc = SetFileAttributesW(tempDest, FILE_ATTRIBUTE_NORMAL);
+ if(!bRc)
+ {
+ Trace("MoveFileExW: SetFileAttributes "
+ "failed to set file attributes correctly.\n");
+ goto EXIT;
+ }
+
+ /* delete the newly moved file */
+ bRc = DeleteFileW(tempDest);
+ if(!bRc)
+ {
+ Trace("MoveFileExW: DeleteFileW failed to delete the"
+ "file correctly.\n");
+ goto EXIT;
+ }
+
+ res = PASS;
+
+EXIT:
+ removeAll();
+ for (i=0; i<4; i++)
+ {
+ free(lpSource[i]);
+ free(lpDestination[i]);
+ }
+ for (i=0; i<14; i++)
+ {
+ free(lpFiles[i]);
+ }
+
+ PAL_TerminateEx(res);
+ return res;
+}
+
diff --git a/src/pal/tests/palsuite/file_io/MoveFileExW/test1/testinfo.dat b/src/pal/tests/palsuite/file_io/MoveFileExW/test1/testinfo.dat
new file mode 100644
index 0000000000..9b001b5c38
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/MoveFileExW/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = MoveFileExW
+Name = Test for MoveFileExW (test 1)
+Type = DEFAULT
+EXE1 = movefileexw
+Description
+= Creates a number of files/directories and attempts to move them.
+
diff --git a/src/pal/tests/palsuite/file_io/MoveFileW/CMakeLists.txt b/src/pal/tests/palsuite/file_io/MoveFileW/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/MoveFileW/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/file_io/MoveFileW/test1/CMakeLists.txt b/src/pal/tests/palsuite/file_io/MoveFileW/test1/CMakeLists.txt
new file mode 100644
index 0000000000..497f654122
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/MoveFileW/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ MoveFileW.c
+)
+
+add_executable(paltest_movefilew_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_movefilew_test1 coreclrpal)
+
+target_link_libraries(paltest_movefilew_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/MoveFileW/test1/ExpectedResults.txt b/src/pal/tests/palsuite/file_io/MoveFileW/test1/ExpectedResults.txt
new file mode 100644
index 0000000000..43b67af6b2
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/MoveFileW/test1/ExpectedResults.txt
@@ -0,0 +1 @@
+0101000001010000 \ No newline at end of file
diff --git a/src/pal/tests/palsuite/file_io/MoveFileW/test1/MoveFileW.c b/src/pal/tests/palsuite/file_io/MoveFileW/test1/MoveFileW.c
new file mode 100644
index 0000000000..58999302d0
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/MoveFileW/test1/MoveFileW.c
@@ -0,0 +1,478 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: MoveFileW.c
+**
+** Purpose: Tests the PAL implementation of the MoveFileW function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+LPSTR lpSource[4] = {"src_existing.txt",
+ "src_non-existant.txt",
+ "src_dir_existing",
+ "src_dir_non-existant"};
+LPSTR lpDestination[4] = {"dst_existing.txt",
+ "dst_non-existant.txt",
+ "dst_dir_existing",
+ "dst_dir_non-existant"};
+
+
+/* Create all the required test files */
+int createExisting(void)
+{
+ FILE* tempFile = NULL;
+ DWORD dwError;
+ BOOL bRc = FALSE;
+ WCHAR* wPtr = NULL;
+ char szBuffer[100];
+
+ /* create the src_existing file */
+ tempFile = fopen(lpSource[0], "w");
+ if (tempFile != NULL)
+ {
+ fprintf(tempFile, "MoveFile test file: src_existing.txt\n");
+ fclose(tempFile);
+ }
+ else
+ {
+ Trace("ERROR: couldn't create %s\n", lpSource[0]);
+ return FAIL;
+ }
+
+ /* create the src_dir_existing directory and files */
+ wPtr = convert(lpSource[2]);
+ bRc = CreateDirectoryW(wPtr, NULL);
+ free(wPtr);
+ if (bRc != TRUE)
+ {
+ Trace("MoveFileW: ERROR: couldn't create \"%s\" because of "
+ "error code %ld\n",
+ lpSource[2],
+ GetLastError());
+ return FAIL;
+ }
+
+ memset(szBuffer, 0, 100);
+ sprintf(szBuffer, "%s/test01.txt", lpSource[2]);
+ tempFile = fopen(szBuffer, "w");
+ if (tempFile != NULL)
+ {
+ fprintf(tempFile, "MoveFileW test file: %s\n", szBuffer);
+ fclose(tempFile);
+ }
+ else
+ {
+ Trace("ERROR: couldn't create %s\n", szBuffer);
+ return FAIL;
+ }
+
+ memset(szBuffer, 0, 100);
+ sprintf(szBuffer, "%s/test02.txt", lpSource[2]);
+ tempFile = fopen(szBuffer, "w");
+ if (tempFile != NULL)
+ {
+ fprintf(tempFile, "MoveFileW test file: %s\n", szBuffer);
+ fclose(tempFile);
+ }
+ else
+ {
+ Trace("ERROR: couldn't create %s\n", szBuffer);
+ return FAIL;
+ }
+
+
+ /* create the dst_existing file */
+ tempFile = fopen(lpDestination[0], "w");
+ if (tempFile != NULL)
+ {
+ fprintf(tempFile, "MoveFileW test file: dst_existing.txt\n");
+ fclose(tempFile);
+ }
+ else
+ {
+ Trace("ERROR: couldn't create \"%s\"\n", lpDestination[0]);
+ return FAIL;
+ }
+
+ /* create the dst_dir_existing directory and files */
+ wPtr = convert(lpDestination[2]);
+ bRc = CreateDirectoryW(wPtr, NULL);
+ free(wPtr);
+ if (bRc != TRUE)
+ {
+ dwError = GetLastError();
+ Trace("MoveFileW: ERROR: couldn't create \"%s\"\n", lpDestination[2]);
+ return FAIL;
+ }
+
+ tempFile = fopen("dst_dir_existing/test01.txt", "w");
+ if (tempFile != NULL)
+ {
+ fprintf(tempFile, "MoveFileW test file: dst_dir_existing/test01.txt\n");
+ fclose(tempFile);
+ }
+ else
+ {
+ Trace("ERROR: couldn't create dst_dir_existing/test01.txt\n");
+ return FAIL;
+ }
+ tempFile = fopen("dst_dir_existing/test02.txt", "w");
+ if (tempFile != NULL)
+ {
+ fprintf(tempFile, "MoveFileW test file: dst_dir_existing/test02.txt\n");
+ fclose(tempFile);
+ }
+ else
+ {
+ Trace("ERROR: couldn't create dst_dir_existing/test02.txt\n");
+ return FAIL;
+ }
+
+ return PASS;
+}
+
+void removeDirectoryHelper(LPSTR dir, int location)
+{
+ DWORD dwAtt = GetFileAttributesA(dir);
+ if (( dwAtt != INVALID_FILE_ATTRIBUTES ) && ( dwAtt & FILE_ATTRIBUTE_DIRECTORY) )
+ {
+ if(!RemoveDirectoryA(dir))
+ {
+ Fail("ERROR: Failed to remove Directory [%s], Error Code [%d], location [%d]\n", dir, GetLastError(), location);
+ }
+ }
+}
+
+void removeFileHelper(LPSTR pfile, int location)
+{
+ FILE *fp;
+ fp = fopen( pfile, "r");
+
+ if (fp != NULL)
+ {
+ if(fclose(fp))
+ {
+ Fail("ERROR: Failed to close the file [%s], Error Code [%d], location [%d]\n", pfile, GetLastError(), location);
+ }
+
+ if(!DeleteFileA(pfile))
+ {
+ Fail("ERROR: Failed to delete file [%s], Error Code [%d], location [%d]\n", pfile, GetLastError(), location);
+ }
+ else
+ {
+ // Trace("Success: deleted file [%S], Error Code [%d], location [%d]\n", wfile, GetLastError(), location);
+ }
+ }
+
+}
+
+/* remove all created files in preparation for the next test */
+void removeAll(void)
+{
+ char szTemp[40];
+ DWORD dwAtt;
+
+ /* get rid of source dirs and files */
+ removeFileHelper(lpSource[0], 1);
+ removeFileHelper(lpSource[1], 2);
+
+ dwAtt = GetFileAttributesA(lpSource[2]);
+ if (( dwAtt != INVALID_FILE_ATTRIBUTES ) && ( dwAtt & FILE_ATTRIBUTE_DIRECTORY) )
+ {
+ sprintf(szTemp, "%s/test01.txt", lpSource[2]);
+ removeFileHelper(szTemp, 18);
+
+ sprintf(szTemp, "%s/test02.txt", lpSource[2]);
+ removeFileHelper(szTemp, 19);
+ removeDirectoryHelper(lpSource[2], 103);
+ }
+ else
+ {
+ removeFileHelper(lpSource[2], 17);
+ }
+
+
+ dwAtt = GetFileAttributesA(lpSource[3]);
+ if (( dwAtt != INVALID_FILE_ATTRIBUTES ) && ( dwAtt & FILE_ATTRIBUTE_DIRECTORY) )
+ {
+ sprintf(szTemp, "%s/test01.txt", lpSource[3]);
+ removeFileHelper(szTemp, 18);
+
+ sprintf(szTemp, "%s/test02.txt", lpSource[3]);
+ removeFileHelper(szTemp, 19);
+ removeDirectoryHelper(lpSource[3], 103);
+ }
+ else
+ {
+ removeFileHelper(lpSource[3], 17);
+ }
+
+ /* get rid of destination dirs and files */
+ dwAtt = GetFileAttributesA(lpDestination[0]);
+ if (( dwAtt != INVALID_FILE_ATTRIBUTES ) && ( dwAtt & FILE_ATTRIBUTE_DIRECTORY) )
+ {
+ sprintf(szTemp, "%s/test01.txt", lpDestination[0]);
+ removeFileHelper(szTemp, 18);
+
+ sprintf(szTemp, "%s/test02.txt", lpDestination[0]);
+ removeFileHelper(szTemp, 19);
+ removeDirectoryHelper(lpDestination[0], 103);
+ }
+ else
+ {
+ removeFileHelper(lpDestination[0], 17);
+ }
+
+ dwAtt = GetFileAttributesA(lpDestination[1]);
+ if (( dwAtt != INVALID_FILE_ATTRIBUTES ) && ( dwAtt & FILE_ATTRIBUTE_DIRECTORY) )
+ {
+ sprintf(szTemp, "%s/test01.txt", lpDestination[1]);
+ removeFileHelper(szTemp, 18);
+
+ sprintf(szTemp, "%s/test02.txt", lpDestination[1]);
+ removeFileHelper(szTemp, 19);
+ removeDirectoryHelper(lpDestination[1], 103);
+ }
+ else
+ {
+ removeFileHelper(lpDestination[1], 17);
+ }
+
+ dwAtt = GetFileAttributesA(lpDestination[2]);
+ if (( dwAtt != INVALID_FILE_ATTRIBUTES ) && ( dwAtt & FILE_ATTRIBUTE_DIRECTORY) )
+ {
+ sprintf(szTemp, "%s/test01.txt", lpDestination[2]);
+ removeFileHelper(szTemp, 18);
+
+ sprintf(szTemp, "%s/test02.txt", lpDestination[2]);
+ removeFileHelper(szTemp, 19);
+ removeDirectoryHelper(lpDestination[2], 103);
+ }
+ else
+ {
+ removeFileHelper(lpDestination[2], 17);
+ }
+
+ dwAtt = GetFileAttributesA(lpDestination[3]);
+ if (( dwAtt != INVALID_FILE_ATTRIBUTES ) && ( dwAtt & FILE_ATTRIBUTE_DIRECTORY) )
+ {
+ sprintf(szTemp, "%s/test01.txt", lpDestination[3]);
+ removeFileHelper(szTemp, 18);
+
+ sprintf(szTemp, "%s/test02.txt", lpDestination[3]);
+ removeFileHelper(szTemp, 19);
+ removeDirectoryHelper(lpDestination[3], 103);
+ }
+ else
+ {
+ removeFileHelper(lpDestination[3], 17);
+ }
+
+}
+
+
+
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ BOOL bRc = TRUE;
+ BOOL bSuccess = TRUE;
+ char results[40];
+ FILE* resultsFile = NULL;
+ int nCounter = 0;
+ int i, j;
+ WCHAR* wSource = NULL;
+ WCHAR* wDest = NULL;
+ WCHAR tempSource[] = {'t','e','m','p','k','.','t','m','p','\0'};
+ WCHAR tempDest[] = {'t','e','m','p','2','.','t','m','p','\0'};
+ HANDLE hFile;
+ DWORD result;
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ /* read in the expected results to compare with actual results */
+ memset (results, 0, 20);
+ resultsFile = fopen("expectedresults.txt", "r");
+ if (resultsFile == NULL)
+ {
+ Fail("MoveFileW ERROR: Unable to open \"expectedresults.txt\"\n");
+ }
+
+ fgets(results, 20, resultsFile);
+ fclose(resultsFile);
+
+ /* clean the slate */
+ removeAll();
+
+ if (createExisting() != 0)
+ {
+ removeAll();
+ }
+
+
+ /* lpSource loop */
+ for (i = 0; i < 4; i++)
+ {
+ /* lpDestination loop */
+ for (j = 0; j < 4; j++)
+ {
+
+ wSource = convert(lpSource[i]);
+ wDest = convert(lpDestination[j]);
+ bRc = MoveFileW(wSource, wDest);
+ free(wSource);
+ free(wDest);
+ if (!(
+ ((bRc == TRUE) && (results[nCounter] == '1'))
+ ||
+ ((bRc == FALSE ) && (results[nCounter] == '0')) )
+ )
+ {
+ Trace("MoveFileW: FAILED: test[%d][%d]: \"%s\" -> \"%s\"\n",
+ i, j, lpSource[i], lpDestination[j]);
+ bSuccess = FALSE;
+ }
+
+ /* undo the last move */
+ removeAll();
+ createExisting();
+
+ nCounter++;
+ }
+ }
+
+ removeAll();
+ if (bSuccess == FALSE)
+ {
+ Fail("MoveFileW: Test Failed");
+ }
+
+ /* create the temp source file */
+ hFile = CreateFileW(tempSource, GENERIC_WRITE, 0, 0, CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL, 0);
+
+ if( hFile == INVALID_HANDLE_VALUE )
+ {
+ Fail("MoveFileW: CreateFile failed to "
+ "create the file correctly.\n");
+ }
+
+ bRc = CloseHandle(hFile);
+ if(!bRc)
+ {
+ Trace("MoveFileW: CloseHandle failed to close the "
+ "handle correctly. ERROR:%u\n",GetLastError());
+
+ /* delete the created file */
+ bRc = DeleteFileW(tempSource);
+ if(!bRc)
+ {
+ Fail("MoveFileW: DeleteFileW failed to delete the"
+ "file correctly.\n");
+ }
+ Fail("");
+ }
+
+ /* set the file attributes to be readonly */
+ bRc = SetFileAttributesW(tempSource, FILE_ATTRIBUTE_READONLY);
+ if(!bRc)
+ {
+ Trace("MoveFileW: SetFileAttributes failed to set file "
+ "attributes correctly. GetLastError returned %u\n",GetLastError());
+ /* delete the created file */
+ bRc = DeleteFileW(tempSource);
+ if(!bRc)
+ {
+ Fail("MoveFileW: DeleteFileW failed to delete the"
+ "file correctly.\n");
+ }
+ Fail("");
+ }
+
+ /* move the file to the new location */
+ bRc = MoveFileW(tempSource, tempDest);
+ if(!bRc)
+ {
+ /* delete the created file */
+ bRc = DeleteFileW(tempSource);
+ if(!bRc)
+ {
+ Fail("MoveFileW: DeleteFileW failed to delete the"
+ "file correctly.\n");
+ }
+
+ Fail("MoveFileW(%S, %S): GetFileAttributes "
+ "failed to get the file's attributes.\n",
+ tempSource, tempDest);
+ }
+
+ /* check that the newly moved file has the same file attributes
+ as the original */
+ result = GetFileAttributesW(tempDest);
+ if(result == 0)
+ {
+ /* delete the created file */
+ bRc = DeleteFileW(tempDest);
+ if(!bRc)
+ {
+ Fail("MoveFileW: DeleteFileW failed to delete the"
+ "file correctly.\n");
+ }
+
+ Fail("MoveFileW: GetFileAttributes failed to get "
+ "the file's attributes.\n");
+ }
+
+ if((result & FILE_ATTRIBUTE_READONLY) != FILE_ATTRIBUTE_READONLY)
+ {
+ /* delete the newly moved file */
+ bRc = DeleteFileW(tempDest);
+ if(!bRc)
+ {
+ Fail("MoveFileW: DeleteFileW failed to delete the"
+ "file correctly.\n");
+ }
+
+ Fail("MoveFileW: GetFileAttributes failed to get "
+ "the correct file attributes.\n");
+ }
+
+ /* set the file attributes back to normal, to be deleted */
+ bRc = SetFileAttributesW(tempDest, FILE_ATTRIBUTE_NORMAL);
+ if(!bRc)
+ {
+ /* delete the newly moved file */
+ bRc = DeleteFileW(tempDest);
+ if(!bRc)
+ {
+ Fail("MoveFileW: DeleteFileW failed to delete the"
+ "file correctly.\n");
+ }
+
+ Fail("MoveFileW: SetFileAttributes failed to set "
+ "file attributes correctly.\n");
+ }
+
+ /* delete the newly moved file */
+ bRc = DeleteFileW(tempDest);
+ if(!bRc)
+ {
+ Fail("MoveFileW: DeleteFileW failed to delete the"
+ "file correctly.\n");
+ }
+
+ PAL_Terminate();
+
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/file_io/MoveFileW/test1/testinfo.dat b/src/pal/tests/palsuite/file_io/MoveFileW/test1/testinfo.dat
new file mode 100644
index 0000000000..8852a03ca2
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/MoveFileW/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = MoveFileW
+Name = Positive Test for MoveFileW
+TYPE = DEFAULT
+EXE1 = movefilew
+Description
+=Performs a number of MoveFileW tests and uses the
+=file ExpectedResults.txt to determine if the test passed/failed
diff --git a/src/pal/tests/palsuite/file_io/ReadFile/CMakeLists.txt b/src/pal/tests/palsuite/file_io/ReadFile/CMakeLists.txt
new file mode 100644
index 0000000000..a3847f8ca9
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/ReadFile/CMakeLists.txt
@@ -0,0 +1,7 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+add_subdirectory(test3)
+add_subdirectory(test4)
+
diff --git a/src/pal/tests/palsuite/file_io/ReadFile/test1/CMakeLists.txt b/src/pal/tests/palsuite/file_io/ReadFile/test1/CMakeLists.txt
new file mode 100644
index 0000000000..7b166e17b0
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/ReadFile/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ ReadFile.c
+)
+
+add_executable(paltest_readfile_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_readfile_test1 coreclrpal)
+
+target_link_libraries(paltest_readfile_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/ReadFile/test1/NonReadableFile.txt b/src/pal/tests/palsuite/file_io/ReadFile/test1/NonReadableFile.txt
new file mode 100644
index 0000000000..a8a940627d
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/ReadFile/test1/NonReadableFile.txt
@@ -0,0 +1 @@
+this is a test \ No newline at end of file
diff --git a/src/pal/tests/palsuite/file_io/ReadFile/test1/ReadFile.c b/src/pal/tests/palsuite/file_io/ReadFile/test1/ReadFile.c
new file mode 100644
index 0000000000..a59e29212e
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/ReadFile/test1/ReadFile.c
@@ -0,0 +1,82 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: ReadFile.c (test 1)
+**
+** Purpose: Tests the PAL implementation of the ReadFile function.
+** This test will attempt to read from a NULL handle and from
+** a file without read permissions set.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ HANDLE hFile = NULL;
+ DWORD dwByteCount = 0;
+ DWORD dwBytesRead = 0;
+ BOOL bRc = FALSE;
+ char szBuffer[256];
+ char* szNonReadableFile = {"nonreadablefile.txt"};
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ memset(szBuffer, 0, 256);
+
+ /* Read from a NULL handle
+ */
+
+ bRc = ReadFile(hFile, szBuffer, 20, &dwBytesRead, NULL);
+
+ if (bRc == TRUE)
+ {
+ Fail("ReadFile: ERROR -> Able to read from a NULL handle\n");
+ }
+
+
+ /* Read from a file without read permissions
+ */
+
+#if WIN32
+
+#else
+ /* attempt to read from the unreadable file
+ * open a file without read permissions
+ */
+ hFile = CreateFile(szNonReadableFile,
+ GENERIC_WRITE,
+ FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if(hFile == INVALID_HANDLE_VALUE)
+ {
+ dwByteCount = GetLastError();
+ Fail("ReadFile: ERROR -> Unable to create file \"%s\".\n",
+ szNonReadableFile);
+ }
+
+ bRc = ReadFile(hFile, szBuffer, 20, &dwBytesRead, NULL);
+
+ if (bRc == TRUE)
+ {
+ Fail("ReadFile: ERROR -> Able to read from a file without read "
+ "permissions\n");
+ }
+#endif
+
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/file_io/ReadFile/test1/testinfo.dat b/src/pal/tests/palsuite/file_io/ReadFile/test1/testinfo.dat
new file mode 100644
index 0000000000..b0df11a3ab
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/ReadFile/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = ReadFile
+Name = Positive Test for ReadFile
+Type = DEFAULT
+EXE1 = readfile
+Description
+=Attempt to read from a NULL handle and a file without read permissions
+
diff --git a/src/pal/tests/palsuite/file_io/ReadFile/test2/CMakeLists.txt b/src/pal/tests/palsuite/file_io/ReadFile/test2/CMakeLists.txt
new file mode 100644
index 0000000000..fc4870e73d
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/ReadFile/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ ReadFile.c
+)
+
+add_executable(paltest_readfile_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_readfile_test2 coreclrpal)
+
+target_link_libraries(paltest_readfile_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/ReadFile/test2/ReadFile.c b/src/pal/tests/palsuite/file_io/ReadFile/test2/ReadFile.c
new file mode 100644
index 0000000000..f16858e573
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/ReadFile/test2/ReadFile.c
@@ -0,0 +1,198 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: ReadFile.c (test 2)
+**
+** Purpose: Tests the PAL implementation of the ReadFile function.
+** Creates a test file and performs an array of read tests.
+**
+** Assumes successful:
+** CreateFile
+** CloseHandle
+** WriteFile
+** GetLastError
+**
+**
+**===================================================================*/
+
+
+#include <palsuite.h>
+
+
+const char* szStringTest = "The quick fox jumped over the lazy dog's back.\0";
+const char* szEmptyString = "";
+const char* szReadableFile = "Readable.txt";
+const char* szResultsFile = "Results.txt";
+
+//Previously number of tests was 6, now 4 refer VSW 312690
+#define NOOFTESTS 4
+
+#ifdef __sparc__
+const int PAGESIZE = 8192;
+#else // __sparc__
+const int PAGESIZE = 4096;
+#endif // __sparc__
+
+char *readBuffer;
+
+BOOL validateResults(const char* szString, // string read
+ DWORD dwByteCount, // amount requested
+ DWORD dwBytesRead) // amount read
+{
+ // were the correct number of bytes read?
+ if (dwBytesRead > dwByteCount)
+ {
+ Trace("bytes read > bytes asked for\n");
+ return FALSE;
+ }
+ if (dwBytesRead != strlen(szString))
+ {
+ Trace("bytes read != length of read string\n");
+ return FALSE;
+ }
+
+ //
+ // compare results
+ //
+
+ if (memcmp(szString, szStringTest, dwBytesRead) != 0)
+ {
+ Trace("read = %s string = %s", szString, szStringTest);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+BOOL readTest(DWORD dwByteCount, char cResult)
+{
+ HANDLE hFile = NULL;
+ DWORD dwBytesRead;
+ BOOL bRc = FALSE;
+
+ // open the test file
+ hFile = CreateFile(szReadableFile,
+ GENERIC_READ,
+ FILE_SHARE_READ,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+ if(hFile == INVALID_HANDLE_VALUE)
+ {
+ Trace("ReadFile: ERROR -> Unable to open file \"%s\".\n",
+ szReadableFile);
+ return FALSE;
+ }
+
+ memset(readBuffer, 0, PAGESIZE);
+
+ bRc = ReadFile(hFile, readBuffer, dwByteCount, &dwBytesRead, NULL);
+
+ if (bRc == FALSE)
+ {
+ // if it failed, was it supposed to fail?
+ if (cResult == '1')
+ {
+ Trace("\nbRc = %d\n", bRc);
+ Trace("readBuffer = [%s] dwByteCount = %d dwBytesRead = %d\n", readBuffer, dwByteCount, dwBytesRead);
+ Trace("cresult = 1\n");
+ Trace("getlasterror = %d\n", GetLastError());
+ CloseHandle(hFile);
+ return FALSE;
+ }
+ }
+ else
+ {
+ CloseHandle(hFile);
+ // if it passed, was it supposed to pass?
+ if (cResult == '0')
+ {
+ Trace("cresult = 0\n");
+ return FALSE;
+ }
+ else
+ {
+ return (validateResults(readBuffer, dwByteCount, dwBytesRead));
+ }
+ }
+
+ CloseHandle(hFile);
+ return TRUE;
+}
+
+int __cdecl main(int argc, char *argv[])
+{
+ HANDLE hFile = NULL;
+ const int BUFFER_SIZE = 2 * PAGESIZE;
+
+ DWORD dwByteCount[] = { 0,
+ 10,
+ strlen(szStringTest),
+ PAGESIZE
+ // Commented out two negative test cases : Refer VSW 312690
+ // 2 * PAGESIZE,
+ // -1
+ };
+
+ DWORD oldProt;
+ char szResults[] = "1111"; // Was "111100": Refer VSW 312690
+ int i;
+ BOOL bRc = FALSE;
+ DWORD dwBytesWritten = 0;
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ /* aloocate read-write memery for readBuffer */
+ if (!(readBuffer = (char*) VirtualAlloc(NULL, BUFFER_SIZE, MEM_COMMIT, PAGE_READWRITE)))
+ {
+ Fail("VirtualAlloc failed: GetLastError returns %d\n", GetLastError());
+ return FAIL;
+ }
+
+ /* write protect the second page of readBuffer */
+ if (!VirtualProtect(&readBuffer[PAGESIZE], PAGESIZE, PAGE_NOACCESS, &oldProt))
+ {
+ Fail("VirtualProtect failed: GetLastError returns %d\n", GetLastError());
+ return FAIL;
+ }
+
+ // create the test file
+ hFile = CreateFile(szReadableFile,
+ GENERIC_WRITE,
+ FILE_SHARE_WRITE,
+ NULL,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if(hFile == INVALID_HANDLE_VALUE)
+ {
+ Fail("ReadFile: ERROR -> Unable to create file \"%s\" (%d).\n",
+ szReadableFile, GetLastError());
+ }
+
+ bRc = WriteFile(hFile, szStringTest, strlen(szStringTest), &dwBytesWritten, NULL);
+ CloseHandle(hFile);
+
+
+ for (i = 0; i< NOOFTESTS; i++)
+ {
+ bRc = readTest(dwByteCount[i], szResults[i]);
+ if (bRc != TRUE)
+ {
+ Fail("ReadFile: ERROR -> Failed on test[%d]\n", i);
+ }
+ }
+
+ VirtualFree(readBuffer, BUFFER_SIZE, MEM_RELEASE);
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/file_io/ReadFile/test2/testinfo.dat b/src/pal/tests/palsuite/file_io/ReadFile/test2/testinfo.dat
new file mode 100644
index 0000000000..82b6326170
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/ReadFile/test2/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = ReadFile
+Name = Positive Test for ReadFile
+Type = DEFAULT
+EXE1 = readfile
+Description
+=Multiple tests of reads of varying sizes with verification
+
diff --git a/src/pal/tests/palsuite/file_io/ReadFile/test3/CMakeLists.txt b/src/pal/tests/palsuite/file_io/ReadFile/test3/CMakeLists.txt
new file mode 100644
index 0000000000..77397743d4
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/ReadFile/test3/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ ReadFile.c
+)
+
+add_executable(paltest_readfile_test3
+ ${SOURCES}
+)
+
+add_dependencies(paltest_readfile_test3 coreclrpal)
+
+target_link_libraries(paltest_readfile_test3
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/ReadFile/test3/ReadFile.c b/src/pal/tests/palsuite/file_io/ReadFile/test3/ReadFile.c
new file mode 100644
index 0000000000..c5d6b1d155
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/ReadFile/test3/ReadFile.c
@@ -0,0 +1,184 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: ReadFile.c (test 3)
+**
+** Purpose: Tests the PAL implementation of the ReadFile function.
+** Creates a test file and performs an array of sequential read
+** tests.
+**
+** Assumes successful:
+** CreateFile
+** CloseHandle
+** memset
+** WriteFile
+** CreateFile
+** CloseHandle
+** GetLastError
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+const char* szStringTest = "The quick fox jumped over the lazy dog's back.\0";
+const char* szEmptyString = "";
+const char* szReadableFile = "Readable.txt";
+const char* szResultsFile = "Results.txt";
+
+
+BOOL validateResults(const char* szString, // string read
+ DWORD dwByteCount, // amount requested
+ DWORD dwBytesRead) // amount read
+{
+ // were the correct number of bytes read?
+ if (dwBytesRead > dwByteCount)
+ {
+ Trace("bytes read > bytes asked for\n");
+ return FALSE;
+ }
+ if (dwBytesRead != strlen(szString))
+ {
+ Trace("bytes read != length of read string\n");
+ return FALSE;
+ }
+
+
+ //
+ // compare results
+ //
+
+ if (memcmp(szString, szStringTest, dwByteCount) != 0)
+ {
+ Trace("read = %s string = %s", szString, szStringTest);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+
+
+BOOL readTest(DWORD dwByteCount, char cResult)
+{
+ HANDLE hFile = NULL;
+ DWORD dwBytesRead = 0;
+ DWORD dwTotal = 0;
+ DWORD dwRequested = 0;
+ BOOL bRc = FALSE;
+ char szString[100];
+ char* szPtr = szString;
+ int i = 0;
+
+ // open the test file
+ hFile = CreateFile(szReadableFile,
+ GENERIC_READ,
+ FILE_SHARE_READ,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+ if(hFile == INVALID_HANDLE_VALUE)
+ {
+ Trace("ReadFile: ERROR -> Unable to open file \"%s\".\n",
+ szReadableFile);
+ return FALSE;
+ }
+
+ memset(szString, 0, 100);
+
+ for (i = 0; i < 5; i++)
+ {
+ bRc = ReadFile(hFile, szPtr, dwByteCount, &dwBytesRead, NULL);
+ szPtr += dwByteCount;
+ dwTotal += dwBytesRead;
+ dwRequested += dwByteCount;
+ }
+
+ if (bRc == FALSE)
+ {
+ // if it failed, was it supposed to fail?
+ if (cResult == '1')
+ {
+ Trace("\nbRc = %d\n", bRc);
+ Trace("szString = [%s] dwByteCount = %d dwBytesRead = %d\n",
+ szString,
+ dwByteCount,
+ dwBytesRead);
+ Trace ("cresult = 1\n");
+ Trace ("getlasterror = %d\n", GetLastError());
+ CloseHandle(hFile);
+ return FALSE;
+ }
+ }
+ else
+ {
+ CloseHandle(hFile);
+ // if it passed, was it supposed to pass?
+ if (cResult == '0')
+ {
+ Trace ("cresult = 0\n");
+ return FALSE;
+ }
+ else
+ {
+ return (validateResults(szString, dwRequested, dwTotal));
+ }
+ }
+
+ CloseHandle(hFile);
+ return TRUE;
+}
+
+
+
+int __cdecl main(int argc, char **argv)
+{
+ HANDLE hFile = NULL;
+ DWORD dwByteCount[4] = {0, 1, 2, 3};
+ char szResults[4] = {'1', '1', '1', '1'};
+ int i;
+ BOOL bRc = FALSE;
+ DWORD dwBytesWritten = 0;
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+
+ // create the test file
+ hFile = CreateFile(szReadableFile,
+ GENERIC_WRITE,
+ FILE_SHARE_WRITE,
+ NULL,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+ if(hFile == INVALID_HANDLE_VALUE)
+ {
+ Fail("ReadFile: ERROR -> Unable to create file \"%s\".\n",
+ szReadableFile);
+ }
+
+ bRc = WriteFile(hFile, szStringTest, strlen(szStringTest),
+ &dwBytesWritten,
+ NULL);
+ CloseHandle(hFile);
+
+ for (i = 0; i < 4; i++)
+ {
+ bRc = readTest(dwByteCount[i], szResults[i]);
+ if (bRc != TRUE)
+ {
+ Fail("ReadFile: ERROR -> Failed on test[%d]\n", i);
+ }
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/file_io/ReadFile/test3/testinfo.dat b/src/pal/tests/palsuite/file_io/ReadFile/test3/testinfo.dat
new file mode 100644
index 0000000000..82b6326170
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/ReadFile/test3/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = ReadFile
+Name = Positive Test for ReadFile
+Type = DEFAULT
+EXE1 = readfile
+Description
+=Multiple tests of reads of varying sizes with verification
+
diff --git a/src/pal/tests/palsuite/file_io/ReadFile/test4/CMakeLists.txt b/src/pal/tests/palsuite/file_io/ReadFile/test4/CMakeLists.txt
new file mode 100644
index 0000000000..37f227aced
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/ReadFile/test4/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ readfile.c
+)
+
+add_executable(paltest_readfile_test4
+ ${SOURCES}
+)
+
+add_dependencies(paltest_readfile_test4 coreclrpal)
+
+target_link_libraries(paltest_readfile_test4
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/ReadFile/test4/readfile.c b/src/pal/tests/palsuite/file_io/ReadFile/test4/readfile.c
new file mode 100644
index 0000000000..3ec939f63a
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/ReadFile/test4/readfile.c
@@ -0,0 +1,147 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: ReadFile.c (test 4)
+**
+** Purpose: Tests the PAL implementation of the ReadFile function.
+** Creates a file and writes a small string to it, attempt
+** to read many more characters that exist. The returned
+** number of chars should be the amount written originally
+** not the number requested.
+**
+**
+**===================================================================*/
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ HANDLE hFile = NULL;
+ DWORD dwBytesWritten;
+ BOOL bRc = FALSE;
+ char szBuffer[256];
+ DWORD dwBytesRead = 0;
+ int szRequestSize = 256;
+ char testFile[] = "testfile.tmp";
+ char testString[] = "people stop and stare";
+ DWORD res = 0;
+
+ /* Initialize the PAL.
+ */
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ /* Initialize the buffer.
+ */
+ memset(szBuffer, 0, 256);
+
+ /* Create a file to test with.
+ */
+ hFile = CreateFile(testFile,
+ GENERIC_WRITE|GENERIC_READ,
+ FILE_SHARE_WRITE|FILE_SHARE_READ,
+ NULL,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if(hFile == INVALID_HANDLE_VALUE)
+ {
+ Fail("ERROR:%u: Unable to create file \"%s\".\n",
+ GetLastError(),
+ testFile);
+ }
+
+ /* Write to the File handle.
+ */
+ bRc = WriteFile(hFile,
+ testString,
+ strlen(testString),
+ &dwBytesWritten,
+ NULL);
+
+ if (bRc == FALSE)
+ {
+ Trace("ERROR:%u: Unable to write to file handle "
+ "hFile=0x%lx\n",
+ GetLastError(),
+ hFile);
+ if (!CloseHandle(hFile))
+ {
+ Trace("ERROR:%u%: Unable to close handle 0x%lx.\n",
+ GetLastError(),
+ hFile);
+ }
+ Fail("");
+ }
+
+ /* Set the file pointer to beginning of file.
+ */
+ res = SetFilePointer(hFile, (LONG)NULL, NULL, FILE_BEGIN);
+
+ if( (res == INVALID_SET_FILE_POINTER) &&
+ (GetLastError() != NO_ERROR))
+ {
+ Trace("ERROR:%u: Unable to set file pointer to the beginning of file.",
+ GetLastError());
+
+ if (!CloseHandle(hFile))
+ {
+ Trace("ERROR:%u%: Unable to close handle 0x%lx.\n",
+ GetLastError(),
+ hFile);
+ }
+ Fail("");
+ }
+
+
+ /* Attempt to read 256 characters from a file
+ * that does not contain that many.
+ */
+ bRc = ReadFile(hFile,
+ szBuffer,
+ szRequestSize,
+ &dwBytesRead,
+ NULL);
+
+ if (bRc == FALSE)
+ {
+ Trace("ERROR:%u: Unable to read from file handle 0x%lx.\n",
+ GetLastError(),
+ hFile);
+ if (!CloseHandle(hFile))
+ {
+ Trace("ERROR:%u%: Unable to close handle 0x%lx.\n",
+ GetLastError(),
+ hFile);
+ }
+ Fail("");
+ }
+
+ /* Confirm the number of bytes read with that requested.
+ */
+ if (dwBytesRead != strlen(testString))
+ {
+ Trace("ERROR: The number of bytes read \"%d\" is not equal to the "
+ "number originally written \"%d\" to the file.\n",
+ dwBytesRead,
+ strlen(testString));
+ if (!CloseHandle(hFile))
+ {
+ Trace("ERROR:%u%: Unable to close handle 0x%lx.\n",
+ GetLastError(),
+ hFile);
+ }
+ Fail("");
+ }
+
+ /* Terminate the PAL.
+ */
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/file_io/ReadFile/test4/testinfo.dat b/src/pal/tests/palsuite/file_io/ReadFile/test4/testinfo.dat
new file mode 100644
index 0000000000..6f3267d591
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/ReadFile/test4/testinfo.dat
@@ -0,0 +1,17 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = ReadFile
+Name = Positive Test for ReadFile
+Type = DEFAULT
+EXE1 = readfile
+Description
+= Tests the PAL implementation of the ReadFile function.
+= Creates a file and writes a small string to it, attempt
+= to read many more characters that exist. The returned
+= number of chars should be the amount written originally
+= not the number requested.
+
diff --git a/src/pal/tests/palsuite/file_io/RemoveDirectoryA/CMakeLists.txt b/src/pal/tests/palsuite/file_io/RemoveDirectoryA/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/RemoveDirectoryA/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/file_io/RemoveDirectoryA/test1/CMakeLists.txt b/src/pal/tests/palsuite/file_io/RemoveDirectoryA/test1/CMakeLists.txt
new file mode 100644
index 0000000000..7a8d1c9d57
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/RemoveDirectoryA/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ RemoveDirectoryA.cpp
+)
+
+add_executable(paltest_removedirectorya_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_removedirectorya_test1 coreclrpal)
+
+target_link_libraries(paltest_removedirectorya_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/RemoveDirectoryA/test1/RemoveDirectoryA.cpp b/src/pal/tests/palsuite/file_io/RemoveDirectoryA/test1/RemoveDirectoryA.cpp
new file mode 100644
index 0000000000..167af58163
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/RemoveDirectoryA/test1/RemoveDirectoryA.cpp
@@ -0,0 +1,315 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: RemoveDirectoryA.c
+**
+** Purpose: Tests the PAL implementation of the RemoveDirectoryA function.
+**
+**
+**===================================================================*/
+
+
+#define PAL_STDCPP_COMPAT
+#include <palsuite.h>
+#undef PAL_STDCPP_COMPAT
+
+#include <unistd.h>
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ BOOL bRc = FALSE;
+ char szDirName[252];
+ DWORD curDirLen;
+ char *szTemp = NULL;
+ char *szTemp2 = NULL;
+ char szwCurrentDir[MAX_PATH];
+ char szwSubDir[MAX_PATH];
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ /*
+ * remove a NULL directory
+ */
+ bRc = RemoveDirectoryA(NULL);
+ if (bRc != FALSE)
+ {
+ Fail("Error[%ul]:RemoveDirectoryA: Failed since it was able to remove a"
+ " NULL directory name\n", GetLastError());
+ }
+
+ /*
+ * remove a directory that does not exist
+ */
+ szTemp = (char *) malloc (sizeof("test_directory"));
+ sprintf(szTemp, "test_directory");
+ bRc = RemoveDirectoryA(szTemp);
+ if (bRc != FALSE)
+ {
+ free(szTemp);
+ Fail("Error[%ul]:RemoveDirectoryA: Failed since it was able to remove"
+ " the non-existant directory \"test_directory\"\n", GetLastError());
+ }
+
+ /*
+ * remove a symlink to a directory
+ */
+ bRc = CreateDirectoryA(szTemp, NULL);
+ if (bRc != TRUE)
+ {
+ free(szTemp);
+ Fail("Error[%ul]:RemoveDirectoryA: Failed to create the directory "
+ "\"test_directory\".\n", GetLastError());
+ }
+
+ char *szSymlinkName = (char *) malloc (sizeof("test_directory_symlink"));
+ sprintf(szSymlinkName, "test_directory_symlink");
+ if (symlink(szTemp, szSymlinkName) != 0)
+ {
+ Fail("Error:RemoveDirectoryA: Failed to create a symlink to the directory \"test_directory\".\n");
+ }
+
+ bRc = RemoveDirectoryA(szSymlinkName);
+ if (bRc != FALSE)
+ {
+ Fail("Error:RemoveDirectoryA: RemoveDirectoryA should return FALSE when passed a symlink.\n");
+ }
+
+ unlink(szSymlinkName);
+
+ /*
+ * remove a directory that exists
+ */
+ bRc = RemoveDirectoryA(szTemp);
+ if (bRc == FALSE)
+ {
+ free(szTemp);
+ Fail("Error[%ul]:RemoveDirectoryW: Failed to remove the directory "
+ "\"test_directory\"\n",
+ GetLastError());
+ }
+ /* Make sure the directory was removed */
+ if( -1 != GetFileAttributesA(szTemp) )
+ {
+ free(szTemp);
+ Fail("Error[%ul]:RemoveDirectoryA: Able to get the attributes of "
+ "the removed directory\n" , GetLastError());
+ }
+ free(szTemp);
+
+ /*
+ * remove long directory names (245 characters)
+ */
+ curDirLen = GetCurrentDirectoryA(0, NULL) + 1;
+ memset(szDirName, 0, 252);
+ memset(szDirName, 'a', 245 - curDirLen);
+ szTemp = (char *) malloc (sizeof(szDirName));
+ szTemp = strncpy(szTemp, szDirName, strlen(szDirName) + 1);
+
+ bRc = CreateDirectoryA(szTemp, NULL);
+ if (bRc == FALSE)
+ {
+ free(szTemp);
+ Fail("Error[%ul]:RemoveDirectoryA: Failed to create a directory name "
+ "245 chars long\n" , GetLastError());
+ }
+ bRc = RemoveDirectoryA(szTemp);
+ if (bRc == FALSE)
+ {
+ free(szTemp);
+ Fail("Error[%ul]:RemoveDirectoryA: Failed to remove a 245 char "
+ "long directory\n", GetLastError());
+ }
+
+ /* Make sure the directory was removed */
+ if( -1 != GetFileAttributesA(szTemp) )
+ {
+ free(szTemp);
+ Fail("Error[%ul]:RemoveDirectoryA: Able to get the attributes of "
+ "the removed directory\n", GetLastError());
+ }
+ free(szTemp);
+
+ /*
+ * directories with dots
+ */
+ memset(szDirName, 0, 252);
+ sprintf(szDirName, ".dotDirectory");
+ szTemp = (char *) malloc (sizeof(szDirName));
+ szTemp = strncpy(szTemp, szDirName, strlen(szDirName) + 1);
+
+ bRc = CreateDirectoryA(szTemp, NULL);
+ if (bRc == FALSE)
+ {
+ free(szTemp);
+ Fail("Error[%ul]:RemoveDirectoryA: Failed to create \"%s\"\n", GetLastError(), szDirName);
+ }
+ bRc = RemoveDirectoryA(szTemp);
+ if (bRc == FALSE)
+ {
+ free(szTemp);
+ Fail("Error[%ul]:RemoveDirectoryA: Failed to remove \"%s\"\n", GetLastError(), szDirName);
+ }
+
+ /* Make sure the directory was removed */
+ if( -1 != GetFileAttributesA(szTemp) )
+ {
+ free(szTemp);
+ Fail("Error[%ul]:RemoveDirectoryA: Able to get the attributes of "
+ "the removed directory\n", GetLastError());
+ }
+ free(szTemp);
+
+ /*
+ * Try calling RemoveDirectory with a file name
+ */
+ memset(szDirName, 0, 252);
+ sprintf(szDirName, "removedirectoryw.c");
+ szTemp = (char *) malloc (sizeof(szDirName));
+ szTemp = strncpy(szTemp, szDirName, strlen(szDirName) + 1);
+
+ bRc = RemoveDirectoryA(szTemp);
+ free(szTemp);
+ if (bRc != FALSE)
+ {
+ Fail("Error[%ul]:RemoveDirectoryA: should have failed when "
+ "called with a valid file name", GetLastError() );
+ }
+
+ /*
+ * remove a non empty directory
+ *
+ * To test that, we'll first create non_empty_dir, we'll
+ * set the current dir to non_empty_dir in which we'll
+ * create sub_dir. We'll go back to the root of non_empty_dir
+ * and we'll try to delete it (it shouldn't work).
+ * After that we'll cleanup sub_dir and non_empty_dir
+ */
+
+ /* Get the current directory so it is easy to get back
+ to it later */
+ if( 0 == GetCurrentDirectoryA(MAX_PATH, szwCurrentDir) )
+ {
+ Fail("RemoveDirectoryA: Failed to get current directory "
+ "with GetCurrentDirectoryA.\n");
+ }
+
+ /* Create non_empty_dir */
+ sprintf( szDirName, "non_empty_dir");
+ szTemp = (char *) malloc (sizeof(szDirName));
+ szTemp = strncpy(szTemp, szDirName, strlen(szDirName) + 1);
+ bRc = CreateDirectoryA(szTemp, NULL);
+ if (bRc != TRUE)
+ {
+ free(szTemp);
+ Fail("Error[%ul]:RemoveDirectoryA: Failed to create the directory "
+ "\"non_empty_dir\" when it exists already.\n", GetLastError());
+ }
+
+ if( 0 == SetCurrentDirectoryA(szTemp) )
+ {
+ free(szTemp);
+ Fail("Error[%ul]:RemoveDirectoryA: Failed to set current directory to "
+ "\"non_empty_dir\" with SetCurrentDirectoryA.\n", GetLastError());
+ }
+
+ /* Get the directory full path so it is easy to get back
+ to it later */
+ if( 0 == GetCurrentDirectoryA(MAX_PATH, szwSubDir) )
+ {
+ free(szTemp);
+ Fail("Error[%ul]:RemoveDirectoryA: Failed to get current directory "
+ "with GetCurrentDirectoryA.\n", GetLastError());
+ }
+
+ /* Create sub_dir */
+ sprintf (szDirName, "sub_dir");
+ szTemp2 = (char *) malloc (sizeof(szDirName));
+ szTemp2 = strncpy(szTemp2, szDirName, strlen(szDirName) + 1);
+ bRc = CreateDirectoryA(szTemp2, NULL);
+ if (bRc != TRUE)
+ {
+ free(szTemp);
+ free(szTemp2);
+ Fail("Error[%ul]:RemoveDirectoryA: Failed to create the directory "
+ "\"sub_dir\" when it exists already.\n", GetLastError());
+ }
+
+ /* Set the current dir to the parent of non_empty_dir/sub_dir */
+ if( 0 == SetCurrentDirectoryA(szwCurrentDir) )
+ {
+ free(szTemp);
+ free(szTemp2);
+ Fail("Error[%ul]:RemoveDirectoryA: Failed to set current directory to "
+ "\"non_empty_dir\" with SetCurrentDirectoryA.\n", GetLastError());
+ }
+
+ /* Try to remove non_empty_dir (shouldn't work) */
+ bRc = RemoveDirectoryA(szTemp);
+ if (bRc == TRUE)
+ {
+ free(szTemp);
+ free(szTemp2);
+ Fail("Error[%ul]:RemoveDirectoryA: shouldn't have been able to remove "
+ "the non empty directory \"non_empty_dir\"\n", GetLastError());
+ }
+
+ /* Go back to non_empty_dir and remove sub_dir */
+ if( 0 == SetCurrentDirectoryA(szwSubDir) )
+ {
+ free(szTemp);
+ free(szTemp2);
+ Fail("Error[%ul]:RemoveDirectoryA: Failed to set current directory to "
+ "\"non_empty_dir\" with SetCurrentDirectoryA.\n", GetLastError());
+ }
+
+ bRc = RemoveDirectoryA(szTemp2);
+ if (bRc == FALSE)
+ {
+ free(szTemp);
+ free(szTemp2);
+ Fail("Error[%ul]:RemoveDirectoryA: unable to remove "
+ "directory \"sub_dir\" \n",
+ GetLastError());
+ }
+ /* Make sure the directory was removed */
+ if( -1 != GetFileAttributesA(szTemp2) )
+ {
+ Fail("Error[%ul]RemoveDirectoryA: Able to get the attributes of "
+ "the removed directory\n", GetLastError());
+ }
+ free(szTemp2);
+
+ /* Go back to parent of non_empty_dir and remove non_empty_dir */
+ if( 0 == SetCurrentDirectoryA(szwCurrentDir) )
+ {
+ free(szTemp);
+ Fail("Error[%ul]:RemoveDirectoryA: Failed to set current directory to "
+ "\"..\non_empty_dir\" with SetCurrentDirectoryA.\n", GetLastError());
+ }
+ bRc = RemoveDirectoryA(szTemp);
+ if (bRc == FALSE)
+ {
+ free(szTemp);
+ Fail("Error[%ul]RemoveDirectoryA: unable to remove "
+ "the directory \"non_empty_dir\"\n",
+ GetLastError());
+ }
+ /* Make sure the directory was removed */
+ if( -1 != GetFileAttributesA(szTemp) )
+ {
+ Fail("Error[%ul]:RemoveDirectoryA: Able to get the attributes of "
+ "the removed directory\n", GetLastError());
+ }
+ free(szTemp);
+
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/file_io/RemoveDirectoryA/test1/testinfo.dat b/src/pal/tests/palsuite/file_io/RemoveDirectoryA/test1/testinfo.dat
new file mode 100644
index 0000000000..6d8f72d27e
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/RemoveDirectoryA/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = RemoveDirectoryA
+Name = Test for RemoveDirectoryA (test 1)
+Type = DEFAULT
+EXE1 = removedirectorya
+Description
+= Create directories and attempt to remove them.
+
diff --git a/src/pal/tests/palsuite/file_io/RemoveDirectoryW/CMakeLists.txt b/src/pal/tests/palsuite/file_io/RemoveDirectoryW/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/RemoveDirectoryW/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/file_io/RemoveDirectoryW/test1/CMakeLists.txt b/src/pal/tests/palsuite/file_io/RemoveDirectoryW/test1/CMakeLists.txt
new file mode 100644
index 0000000000..45b51cec30
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/RemoveDirectoryW/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ RemoveDirectoryW.c
+)
+
+add_executable(paltest_removedirectoryw_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_removedirectoryw_test1 coreclrpal)
+
+target_link_libraries(paltest_removedirectoryw_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/RemoveDirectoryW/test1/RemoveDirectoryW.c b/src/pal/tests/palsuite/file_io/RemoveDirectoryW/test1/RemoveDirectoryW.c
new file mode 100644
index 0000000000..ae1dd0fb97
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/RemoveDirectoryW/test1/RemoveDirectoryW.c
@@ -0,0 +1,282 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: RemoveDirectoryW.c
+**
+** Purpose: Tests the PAL implementation of the RemoveDirectoryW function.
+**
+**
+**===================================================================*/
+
+
+#include <palsuite.h>
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ BOOL bRc = FALSE;
+ char szDirName[252];
+ DWORD curDirLen;
+ WCHAR *szwTemp = NULL;
+ WCHAR *szwTemp2 = NULL;
+ WCHAR szwCurrentDir[MAX_PATH];
+ WCHAR szwSubDir[MAX_PATH];
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ /*
+ * remove a NULL directory
+ */
+ bRc = RemoveDirectoryW(NULL);
+ if (bRc != FALSE)
+ {
+ Fail("RemoveDirectoryW: Failed since it was able to remove a"
+ " NULL directory name\n");
+ }
+
+ /*
+ * remove a directory that does not exist
+ */
+ szwTemp = convert("test_directory");
+ bRc = RemoveDirectoryW(szwTemp);
+ if (bRc != FALSE)
+ {
+ free(szwTemp);
+ Fail("RemoveDirectoryW: Failed since it was able to remove"
+ " the non-existant directory \"test_directory\"\n");
+ }
+
+ /*
+ * remove a directory that exists
+ */
+ bRc = CreateDirectoryW(szwTemp, NULL);
+ if (bRc != TRUE)
+ {
+ free(szwTemp);
+ Fail("RemoveDirectoryW: Failed to create the directory "
+ "\"test_directory\" when it exists already.\n");
+ }
+ bRc = RemoveDirectoryW(szwTemp);
+ if (bRc == FALSE)
+ {
+ free(szwTemp);
+ Fail("RemoveDirectoryW: Failed to remove the directory "
+ "\"test_directory\" (error code %d)\n",
+ GetLastError());
+ }
+ /* Make sure the directory was removed */
+ if( -1 != GetFileAttributesW(szwTemp) )
+ {
+ free(szwTemp);
+ Fail("RemoveDirectoryW: Able to get the attributes of "
+ "the removed directory\n");
+ }
+ free(szwTemp);
+
+ /*
+ * remove long directory names (245 characters)
+ */
+ curDirLen = GetCurrentDirectoryA(0, NULL) + 1;
+ memset(szDirName, 0, 252);
+ memset(szDirName, 'a', 245 - curDirLen);
+ szwTemp = convert(szDirName);
+ bRc = CreateDirectoryW(szwTemp, NULL);
+ if (bRc == FALSE)
+ {
+ free(szwTemp);
+ Fail("RemoveDirectoryW: Failed to create a directory name "
+ "245 chars long\n");
+ }
+ bRc = RemoveDirectoryW(szwTemp);
+ if (bRc == FALSE)
+ {
+ free(szwTemp);
+ Fail("RemoveDirectoryW: Failed to remove a 245 char "
+ "long directory\n");
+ }
+
+ /* Make sure the directory was removed */
+ if( -1 != GetFileAttributesW(szwTemp) )
+ {
+ free(szwTemp);
+ Fail("RemoveDirectoryW: Able to get the attributes of "
+ "the removed directory\n");
+ }
+ free(szwTemp);
+
+ /*
+ * directories with dots
+ */
+ memset(szDirName, 0, 252);
+ sprintf(szDirName, ".dotDirectory");
+ szwTemp = convert(szDirName);
+ bRc = CreateDirectoryW(szwTemp, NULL);
+ if (bRc == FALSE)
+ {
+ free(szwTemp);
+ Fail("RemoveDirectoryW: Failed to create \"%s\"\n", szDirName);
+ }
+ bRc = RemoveDirectoryW(szwTemp);
+ if (bRc == FALSE)
+ {
+ free(szwTemp);
+ Fail("RemoveDirectoryW: Failed to remove \"%s\"\n", szDirName);
+ }
+
+ /* Make sure the directory was removed */
+ if( -1 != GetFileAttributesW(szwTemp) )
+ {
+ free(szwTemp);
+ Fail("RemoveDirectoryW: Able to get the attributes of "
+ "the removed directory\n");
+ }
+ free(szwTemp);
+
+ /*
+ * Try calling RemoveDirectory with a file name
+ */
+ memset(szDirName, 0, 252);
+ sprintf(szDirName, "removedirectoryw.c");
+ szwTemp = convert(szDirName);
+
+ bRc = RemoveDirectoryW(szwTemp);
+ free(szwTemp);
+ if (bRc != FALSE)
+ {
+ Fail("RemoveDirectoryW: should have failed when "
+ "called with a valid file name" );
+ }
+
+ /*
+ * remove a non empty directory
+ *
+ * To test that, we'll first create non_empty_dir, we'll
+ * set the current dir to non_empty_dir in which we'll
+ * create sub_dir. We'll go back to the root of non_empty_dir
+ * and we'll try to delete it (it shouldn't work).
+ * After that we'll cleanup sub_dir and non_empty_dir
+ */
+
+ /* Get the current directory so it is easy to get back
+ to it later */
+ if( 0 == GetCurrentDirectoryW(MAX_PATH, szwCurrentDir) )
+ {
+ Fail("RemoveDirectoryW: Failed to get current directory "
+ "with GetCurrentDirectoryW.\n");
+ }
+
+ /* Create non_empty_dir */
+ szwTemp = convert("non_empty_dir");
+ bRc = CreateDirectoryW(szwTemp, NULL);
+ if (bRc != TRUE)
+ {
+ free(szwTemp);
+ Fail("RemoveDirectoryW: Failed to create the directory "
+ "\"non_empty_dir\" when it exists already.\n");
+ }
+
+ if( 0 == SetCurrentDirectoryW(szwTemp) )
+ {
+ free(szwTemp);
+ Fail("RemoveDirectoryW: Failed to set current directory to "
+ "\"non_empty_dir\" with SetCurrentDirectoryW.\n");
+ }
+
+ /* Get the directory full path so it is easy to get back
+ to it later */
+ if( 0 == GetCurrentDirectoryW(MAX_PATH, szwSubDir) )
+ {
+ free(szwTemp);
+ Fail("RemoveDirectoryW: Failed to get current directory "
+ "with GetCurrentDirectoryW.\n");
+ }
+
+ /* Create sub_dir */
+ szwTemp2 = convert("sub_dir");
+ bRc = CreateDirectoryW(szwTemp2, NULL);
+ if (bRc != TRUE)
+ {
+ free(szwTemp);
+ free(szwTemp2);
+ Fail("RemoveDirectoryW: Failed to create the directory "
+ "\"sub_dir\" when it exists already.\n");
+ }
+
+ /* Set the current dir to the parent of non_empty_dir/sub_dir */
+ if( 0 == SetCurrentDirectoryW(szwCurrentDir) )
+ {
+ free(szwTemp);
+ free(szwTemp2);
+ Fail("RemoveDirectoryW: Failed to set current directory to "
+ "\"non_empty_dir\" with SetCurrentDirectoryW.\n");
+ }
+
+ /* Try to remove non_empty_dir (shouldn't work) */
+ bRc = RemoveDirectoryW(szwTemp);
+ if (bRc == TRUE)
+ {
+ free(szwTemp);
+ free(szwTemp2);
+ Fail("RemoveDirectoryW: shouldn't have been able to remove "
+ "the non empty directory \"non_empty_dir\"\n");
+ }
+
+ /* Go back to non_empty_dir and remove sub_dir */
+ if( 0 == SetCurrentDirectoryW(szwSubDir) )
+ {
+ free(szwTemp);
+ free(szwTemp2);
+ Fail("RemoveDirectoryW: Failed to set current directory to "
+ "\"non_empty_dir\" with SetCurrentDirectoryW.\n");
+ }
+
+ bRc = RemoveDirectoryW(szwTemp2);
+ if (bRc == FALSE)
+ {
+ free(szwTemp);
+ free(szwTemp2);
+ Fail("RemoveDirectoryW: unable to remove "
+ "directory \"sub_dir\"(error code %d)\n",
+ GetLastError());
+ }
+ /* Make sure the directory was removed */
+ if( -1 != GetFileAttributesW(szwTemp2) )
+ {
+ Fail("RemoveDirectoryW: Able to get the attributes of "
+ "the removed directory\n");
+ }
+ free(szwTemp2);
+
+ /* Go back to parent of non_empty_dir and remove non_empty_dir */
+ if( 0 == SetCurrentDirectoryW(szwCurrentDir) )
+ {
+ free(szwTemp);
+ Fail("RemoveDirectoryW: Failed to set current directory to "
+ "\"..\non_empty_dir\" with SetCurrentDirectoryW.\n");
+ }
+ bRc = RemoveDirectoryW(szwTemp);
+ if (bRc == FALSE)
+ {
+ free(szwTemp);
+ Fail("RemoveDirectoryW: unable to remove "
+ "the directory \"non_empty_dir\"(error code %d)\n",
+ GetLastError());
+ }
+ /* Make sure the directory was removed */
+ if( -1 != GetFileAttributesW(szwTemp) )
+ {
+ Fail("RemoveDirectoryW: Able to get the attributes of "
+ "the removed directory\n");
+ }
+ free(szwTemp);
+
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/file_io/RemoveDirectoryW/test1/testinfo.dat b/src/pal/tests/palsuite/file_io/RemoveDirectoryW/test1/testinfo.dat
new file mode 100644
index 0000000000..f94b9b2445
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/RemoveDirectoryW/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = RemoveDirectoryW
+Name = Test for RemoveDirectoryW (test 1)
+Type = DEFAULT
+EXE1 = removedirectoryw
+Description
+= Create directories and attempt to remove them.
+
diff --git a/src/pal/tests/palsuite/file_io/SearchPathA/CMakeLists.txt b/src/pal/tests/palsuite/file_io/SearchPathA/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SearchPathA/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/file_io/SearchPathA/test1/CMakeLists.txt b/src/pal/tests/palsuite/file_io/SearchPathA/test1/CMakeLists.txt
new file mode 100644
index 0000000000..d1ac975d18
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SearchPathA/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ SearchPathA.c
+)
+
+add_executable(paltest_searchpatha_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_searchpatha_test1 coreclrpal)
+
+target_link_libraries(paltest_searchpatha_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/SearchPathA/test1/SearchPathA.c b/src/pal/tests/palsuite/file_io/SearchPathA/test1/SearchPathA.c
new file mode 100644
index 0000000000..ab9eecdebc
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SearchPathA/test1/SearchPathA.c
@@ -0,0 +1,144 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: SearchPathA.c
+**
+** Purpose: Tests the PAL implementation of the SearchFileA function.
+**
+**
+** TODO: Write a test where complete path is passed (say c:\?)
+**===================================================================*/
+//SearchPath
+//
+//The SearchPath function searches for the specified file in the specified path.
+//
+
+
+#include <palsuite.h>
+char* szDir = ".";
+
+char* szNoFileName = "333asdf";
+char* szNoFileNameExt = ".x77t";
+
+char* szFileNameExists = "searchfile";
+char* szFileNameExtExists = ".txt";
+
+char* szFileNameExistsWithExt = "searchfile.txt";
+char fileloc[_MAX_PATH];
+
+void removeFileHelper(LPSTR pfile, int location)
+{
+ FILE *fp;
+ fp = fopen( pfile, "r");
+
+ if (fp != NULL)
+ {
+ if(fclose(fp))
+ {
+ Fail("ERROR: Failed to close the file [%s], Error Code [%d], location [%d]\n", pfile, GetLastError(), location);
+ }
+
+ if(!DeleteFileA(pfile))
+ {
+ Fail("ERROR: Failed to delete file [%s], Error Code [%d], location [%d]\n", pfile, GetLastError(), location);
+ }
+ }
+
+}
+
+
+void RemoveAll()
+{
+ removeFileHelper(fileloc, 1);
+}
+
+int __cdecl main(int argc, char *argv[]) {
+
+ char* lpPath = NULL;
+ char* lpFileName = NULL;
+ char* lpExtension = NULL;
+ DWORD nBufferLength = 0;
+ char lpBuffer[_MAX_PATH];
+ char** lpFilePart = NULL;
+ DWORD error = 0;
+ DWORD result = 0;
+
+ HANDLE hsearchfile;
+ char fname[_MAX_FNAME];
+ char ext[_MAX_EXT];
+ char fullPath[_MAX_DIR];
+ char drive[_MAX_DRIVE];
+ char dir[_MAX_DIR];
+
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+
+ /* Initalize the buffer.
+ */
+ memset(fullPath, 0, _MAX_DIR);
+
+ /* Get the full path to the library (DLL).
+ */
+
+ if ( NULL != _fullpath( fullPath, argv[0], _MAX_DIR )) {
+ _splitpath(fullPath,drive,dir,fname,ext);
+ _makepath(fullPath,drive,dir,"","");
+ } else {
+ Fail("ERROR: conversion from relative path \" %s \" to absolute path failed. _fullpath returned NULL\n",argv[0]);
+ }
+
+ memset(fileloc, 0, _MAX_PATH);
+ sprintf(fileloc, "%s%s", fullPath, szFileNameExistsWithExt);
+
+ RemoveAll();
+
+ hsearchfile = CreateFileA(fileloc, GENERIC_WRITE, 0, 0, CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL, 0);
+
+ if (hsearchfile == INVALID_HANDLE_VALUE)
+ {
+ Trace("ERROR[%ul]: couldn't create %s\n", GetLastError(), fileloc);
+ return FAIL;
+ }
+
+ CloseHandle(hsearchfile);
+
+ //
+ // find a file that doesn't exist
+ //
+ ZeroMemory( lpBuffer, sizeof(lpBuffer));
+ lpPath = fullPath;
+ lpFileName = szNoFileName;
+ lpExtension = NULL;
+
+ if( SearchPathA( lpPath, lpFileName, lpExtension, nBufferLength, lpBuffer, lpFilePart) != 0 ){
+ error = GetLastError();
+ Fail ("SearchPathA: ERROR1 -> Found invalid file[%s][%s][%s][%d]\n", lpPath, szNoFileName, szNoFileNameExt, error);
+ }
+
+ //
+ // find a file that exists, when path is mentioned explicitly
+ //
+ ZeroMemory( lpBuffer, sizeof(lpBuffer));
+ lpPath = fullPath;
+ lpFileName = szFileNameExistsWithExt;
+ lpExtension = NULL;
+
+ result = SearchPathA( lpPath, lpFileName, lpExtension, nBufferLength, lpBuffer, lpFilePart);
+
+ if( result == 0 ){
+ error = GetLastError();
+ Fail ("SearchPathA: ERROR2 -> Did not Find valid file[%s][%s][%d]\n", lpPath, szFileNameExistsWithExt, error);
+ }
+
+ RemoveAll();
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/file_io/SearchPathA/test1/testinfo.dat b/src/pal/tests/palsuite/file_io/SearchPathA/test1/testinfo.dat
new file mode 100644
index 0000000000..82401eeeb2
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SearchPathA/test1/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = SearchPathA
+Name = Test #1 for SearchPathA
+TYPE = DEFAULT
+EXE1 = test1
+Description
+=Tests the PAL implementation of the SearchFileA function
diff --git a/src/pal/tests/palsuite/file_io/SearchPathW/CMakeLists.txt b/src/pal/tests/palsuite/file_io/SearchPathW/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SearchPathW/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/file_io/SearchPathW/test1/CMakeLists.txt b/src/pal/tests/palsuite/file_io/SearchPathW/test1/CMakeLists.txt
new file mode 100644
index 0000000000..d0c6252472
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SearchPathW/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ SearchPathW.c
+)
+
+add_executable(paltest_searchpathw_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_searchpathw_test1 coreclrpal)
+
+target_link_libraries(paltest_searchpathw_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/SearchPathW/test1/SearchPathW.c b/src/pal/tests/palsuite/file_io/SearchPathW/test1/SearchPathW.c
new file mode 100644
index 0000000000..2bc7694dc0
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SearchPathW/test1/SearchPathW.c
@@ -0,0 +1,198 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: SearchPathW.c
+**
+** Purpose: Tests the PAL implementation of the SearchFileW function.
+**
+**
+** TODO: Write a test where complete path is passed (say c:\?)
+**===================================================================*/
+//SearchPath
+//
+//The SearchPath function searches for the specified file in the specified path.
+//
+//
+//DWORD SearchPath(
+// LPCTSTR lpPath,
+// LPCTSTR lpFileName,
+// LPCTSTR lpExtension,
+// DWORD nBufferLength,
+// LPTSTR lpBuffer,
+// LPTSTR* lpFilePart
+//);
+//
+//Parameters
+//lpPath
+//[in] Pointer to a null-terminated string that specifies the path to be searched for the file. If this parameter is NULL, the function searches for a matching file in the following directories in the following sequence:
+//The directory from which the application loaded.
+//The current directory.
+//The system directory. Use the GetSystemDirectory function to get the path of this directory.
+//The 16-bit system directory. There is no function that retrieves the path of this directory, but it is searched.
+//The Windows directory. Use the GetWindowsDirectory function to get the path of this directory.
+//The directories that are listed in the PATH environment variable.
+
+//lpFileName
+//[in] Pointer to a null-terminated string that specifies the name of the file to search for.
+
+//lpExtension
+//[in] Pointer to a null-terminated string that specifies an extension to be added to the file name when searching for the file. The first character of the file name extension must be a period (.). The extension is added only if the specified file name does not end with an extension.
+//If a file name extension is not required or if the file name contains an extension, this parameter can be NULL.
+//
+//nBufferLength
+//[in] Size of the buffer that receives the valid path and file name, in TCHARs.
+
+//lpBuffer
+//[out] Pointer to the buffer that receives the path and file name of the file found.
+
+//lpFilePart
+//[out] Pointer to the variable that receives the address (within lpBuffer) of the last component of the valid path and file name, which is the address of the character immediately following the final backslash (\) in the path.
+
+//Return Values
+//If the function succeeds, the value returned is the length, in TCHARs, of the string copied to the buffer, not including the terminating null character. If the return value is greater than nBufferLength, the value returned is the size of the buffer required to hold the path.
+//
+//If the function fails, the return value is zero. To get extended error information, call GetLastError.
+
+
+#include <palsuite.h>
+const char* szDir = ".";
+
+const char* szNoFileName = "333asdf";
+const char* szNoFileNameExt = ".x77t";
+
+const char* szFileNameExists = "searchpathw";
+const char* szFileNameExtExists = ".c";
+
+const char* szFileNameExistsWithExt = "searchpathw.c";
+
+char fileloc[_MAX_PATH];
+
+void removeFileHelper(LPSTR pfile, int location)
+{
+ FILE *fp;
+ fp = fopen( pfile, "r");
+
+ if (fp != NULL)
+ {
+ if(fclose(fp))
+ {
+ Fail("ERROR: Failed to close the file [%s], Error Code [%d], location [%d]\n", pfile, GetLastError(), location);
+ }
+
+ if(!DeleteFileA(pfile))
+ {
+ Fail("ERROR: Failed to delete file [%s], Error Code [%d], location [%d]\n", pfile, GetLastError(), location);
+ }
+ else
+ {
+ // Trace("Success: deleted file [%S], Error Code [%d], location [%d]\n", wfile, GetLastError(), location);
+ }
+ }
+
+}
+
+void RemoveAll()
+{
+ removeFileHelper(fileloc, 1);
+}
+
+int __cdecl main(int argc, char *argv[]) {
+
+ WCHAR* lpPath = NULL;
+ WCHAR* lpFileName = NULL;
+ WCHAR* lpExtension = NULL;
+ DWORD nBufferLength = 0;
+ WCHAR lpBuffer[_MAX_PATH];
+ WCHAR** lpFilePart = NULL;
+ DWORD error = 0;
+ DWORD result = 0;
+
+ HANDLE hsearchfile;
+ char fname[_MAX_FNAME];
+ char ext[_MAX_EXT];
+ char fullPath[_MAX_DIR];
+ char drive[_MAX_DRIVE];
+ char dir[_MAX_DIR];
+
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /* Initalize the buffer.
+ */
+ memset(fullPath, 0, _MAX_DIR);
+
+ /* Get the full path to the library (DLL).
+ */
+
+ if ( NULL != _fullpath( fullPath, argv[0], _MAX_DIR )) {
+ _splitpath(fullPath,drive,dir,fname,ext);
+ _makepath(fullPath,drive,dir,"","");
+ } else {
+ Fail("ERROR: conversion from relative path \" %s \" to absolute path failed. _fullpath returned NULL\n",argv[0]);
+ }
+
+ memset(fileloc, 0, _MAX_PATH);
+ sprintf(fileloc, "%s%s", fullPath, szFileNameExistsWithExt);
+
+ RemoveAll();
+
+ hsearchfile = CreateFileA(fileloc, GENERIC_WRITE, 0, 0, CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL, 0);
+
+ if (hsearchfile == NULL)
+ {
+ Trace("ERROR[%ul]: couldn't create %s\n", GetLastError(), fileloc);
+ return FAIL;
+ }
+
+ CloseHandle(hsearchfile);
+
+ //
+ // find a file that doesn't exist
+ //
+ ZeroMemory( lpBuffer, sizeof(lpBuffer));
+ lpPath = convert((LPSTR)fullPath);
+ lpFileName = convert((LPSTR)szNoFileName);
+ lpExtension = NULL;
+
+ if( SearchPathW( lpPath, lpFileName, lpExtension, nBufferLength, lpBuffer, lpFilePart) != 0 ){
+ error = GetLastError();
+ free(lpPath);
+ free(lpFileName);
+ Fail ("SearchPathW: ERROR1 -> Found invalid file[%s][%s][%s][%d]\n", lpPath, szNoFileName, szNoFileNameExt, error);
+ }
+
+ free(lpPath);
+ free(lpFileName);
+
+ //
+ // find a file that exists, when path is mentioned explicitly
+ //
+ ZeroMemory( lpBuffer, sizeof(lpBuffer));
+ lpPath = convert((LPSTR)fullPath);
+ lpFileName = convert((LPSTR)szFileNameExistsWithExt);
+ lpExtension = NULL;
+
+ result = SearchPathW( lpPath, lpFileName, lpExtension, nBufferLength, lpBuffer, lpFilePart);
+
+ if( result == 0 ){
+ error = GetLastError();
+ free(lpPath);
+ free(lpFileName);
+ Fail ("SearchPathA: ERROR2 -> Did not Find valid file[%s][%s][%d]\n", lpPath, szFileNameExistsWithExt, error);
+ }
+
+ free(lpPath);
+ free(lpFileName);
+
+ RemoveAll();
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/file_io/SearchPathW/test1/testinfo.dat b/src/pal/tests/palsuite/file_io/SearchPathW/test1/testinfo.dat
new file mode 100644
index 0000000000..f7a36eb53b
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SearchPathW/test1/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = SearchPathW
+Name = Test #1 for SearchPathW
+TYPE = DEFAULT
+EXE1 = test1
+Description
+=Tests the PAL implementation of the SearchFileW function
diff --git a/src/pal/tests/palsuite/file_io/SetCurrentDirectoryA/CMakeLists.txt b/src/pal/tests/palsuite/file_io/SetCurrentDirectoryA/CMakeLists.txt
new file mode 100644
index 0000000000..1962ade358
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetCurrentDirectoryA/CMakeLists.txt
@@ -0,0 +1,6 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+add_subdirectory(test3)
+
diff --git a/src/pal/tests/palsuite/file_io/SetCurrentDirectoryA/test1/CMakeLists.txt b/src/pal/tests/palsuite/file_io/SetCurrentDirectoryA/test1/CMakeLists.txt
new file mode 100644
index 0000000000..7376b22226
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetCurrentDirectoryA/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ SetCurrentDirectoryA.c
+)
+
+add_executable(paltest_setcurrentdirectorya_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_setcurrentdirectorya_test1 coreclrpal)
+
+target_link_libraries(paltest_setcurrentdirectorya_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/SetCurrentDirectoryA/test1/SetCurrentDirectoryA.c b/src/pal/tests/palsuite/file_io/SetCurrentDirectoryA/test1/SetCurrentDirectoryA.c
new file mode 100644
index 0000000000..c07a62412b
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetCurrentDirectoryA/test1/SetCurrentDirectoryA.c
@@ -0,0 +1,215 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: SetCurrentDirectoryA.c (test 1)
+**
+** Purpose: Tests the PAL implementation of the SetCurrentDirectoryA function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+
+
+/* In order to avoid the "chicken and egg" scenario, this is another
+ method of getting the current directory. GetFullPathNameA is called with
+ a dummy file name and then the file name is stripped off leaving the
+ current working directory
+*/
+
+BOOL GetCurrentDir(char* szCurrentDir)
+{
+ const char* szFileName = "blah";
+ DWORD dwRc = 0;
+ char szReturnedPath[_MAX_DIR+1];
+ LPSTR pPathPtr;
+ size_t nCount = 0;
+
+ /* use GetFullPathNameA to to get the current path by stripping
+ the file name off the end */
+ memset(szReturnedPath, 0, (_MAX_DIR+1));
+ dwRc = GetFullPathNameA(szFileName,
+ _MAX_DIR,
+ szReturnedPath,
+ &pPathPtr);
+
+ if (dwRc == 0)
+ {
+ /* GetFullPathNameA failed */
+ Trace("SetCurrentDirectoryA: ERROR -> GetFullPathNameA failed "
+ "with error code: %ld.\n", GetLastError());
+ return(FALSE);
+ }
+
+ /* now strip the file name from the full path to get the current path */
+ nCount = strlen(szReturnedPath) - strlen(szFileName);
+ memset(szCurrentDir, 0, (_MAX_DIR+1));
+ strncpy(szCurrentDir, szReturnedPath, nCount);
+
+ return(TRUE);
+}
+
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ const char* szDirName = "testing";
+ /* directory name longer than MAX_PATH characters */
+ char szLongDirName[MAX_LONGPATH+1];
+ char szNewDir[_MAX_DIR+1];
+ char szBuiltDir[_MAX_DIR+1];
+ char szHomeDir[_MAX_DIR+1];
+ WCHAR* szwPtr = NULL;
+
+ memset(szLongDirName, 'a', MAX_LONGPATH+1);
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ /* remove the directory just in case a previous run of the test didn't */
+ szwPtr = convert((LPSTR)szDirName);
+
+ /* clean up. Remove the directory
+ * if it exists */
+ RemoveDirectoryW(szwPtr);
+
+ /* create a temp directory off the current directory */
+ if (CreateDirectoryA(szDirName, NULL) != TRUE)
+ {
+ free(szwPtr);
+ Fail("SetCurrentDirectoryA: ERROR -> CreateDirectoryW failed "
+ "with error code: %ld.\n", GetLastError());
+ }
+
+ /* find out what the current "home" directory is */
+ memset(szHomeDir, 0, (_MAX_DIR+1));
+ if(GetCurrentDir(szHomeDir) != TRUE)
+ {
+ if (!RemoveDirectoryW(szwPtr))
+ {
+ Trace("SetCurrentDirectoryA: ERROR -> RemoveDirectoryW failed "
+ "with error code: %ld.\n", GetLastError());
+ }
+ free(szwPtr);
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+
+ /* set the current directory to the temp directory */
+
+ if (SetCurrentDirectoryA(szDirName) != TRUE)
+ {
+ Trace("SetCurrentDirectoryA: ERROR -> Unable to set current "
+ "directory. Failed with error code: %ld.\n", GetLastError());
+ if (!RemoveDirectoryW(szwPtr))
+ {
+ Trace("SetCurrentDirectoryA: ERROR -> RemoveDirectoryW failed "
+ "with error code: %ld.\n", GetLastError());
+ }
+ free(szwPtr);
+ Fail("");
+ }
+
+ /* append the temp name to the "home" directory */
+ memset(szBuiltDir, 0, (_MAX_DIR+1));
+#if WIN32
+ sprintf(szBuiltDir,"%s%s\\", szHomeDir, szDirName);
+#else
+ sprintf(szBuiltDir,"%s%s/", szHomeDir, szDirName);
+#endif
+
+ /* get the new current directory */
+ memset(szNewDir, 0, (_MAX_DIR+1));
+ if(GetCurrentDir(szNewDir) != TRUE)
+ {
+ if (!RemoveDirectoryW(szwPtr))
+ {
+ Trace("SetCurrentDirectoryA: ERROR -> RemoveDirectoryW failed "
+ "with error code: %ld.\n", GetLastError());
+ }
+ free(szwPtr);
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+
+ /*compare the new current dir to the compiled current dir */
+ if (strncmp(szNewDir, szBuiltDir, strlen(szNewDir)) != 0)
+ {
+ if (!RemoveDirectoryW(szwPtr))
+ {
+ Trace("SetCurrentDirectoryA: ERROR -> RemoveDirectoryW failed "
+ "with error code: %ld.\n", GetLastError());
+ }
+ free(szwPtr);
+ Fail("SetCurrentDirectoryA: ERROR -> The set directory \"%s\" does not"
+ " compare to the built directory \"%s\".\n",
+ szNewDir,
+ szBuiltDir);
+ }
+
+
+
+ /* set the current dir back to the original */
+ if (SetCurrentDirectoryA(szHomeDir) != TRUE)
+ {
+ Trace("SetCurrentDirectoryA: ERROR -> Unable to set current "
+ "directory. Failed with error code: %ld.\n", GetLastError());
+ if (!RemoveDirectoryW(szwPtr))
+ {
+ Trace("SetCurrentDirectoryA: ERROR -> RemoveDirectoryW failed "
+ "with error code: %ld.\n", GetLastError());
+ }
+ free(szwPtr);
+ Fail("");
+ }
+
+
+ /* get the new current directory */
+ memset(szNewDir, 0, sizeof(char)*(_MAX_DIR+1));
+ if(GetCurrentDir(szNewDir) != TRUE)
+ {
+ if (!RemoveDirectoryW(szwPtr))
+ {
+ Trace("SetCurrentDirectoryA: ERROR -> RemoveDirectoryW failed "
+ "with error code: %ld.\n", GetLastError());
+ }
+ free(szwPtr);
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+
+ /* ensure it compares to the "home" directory which is where
+ we should be now */
+ if (strncmp(szNewDir, szHomeDir, strlen(szNewDir)) != 0)
+ {
+ if (!RemoveDirectoryW(szwPtr))
+ {
+ Trace("SetCurrentDirectoryA: ERROR -> RemoveDirectoryW failed "
+ "with error code: %ld.\n", GetLastError());
+ }
+ free(szwPtr);
+ Fail("SetCurrentDirectoryA: ERROR -> The set directory does not "
+ "compare to the built directory.\n");
+ }
+
+
+ /* clean up */
+ if (!RemoveDirectoryW(szwPtr))
+ {
+ free(szwPtr);
+ Fail("SetCurrentDirectoryA: ERROR -> RemoveDirectoryW failed "
+ "with error code: %ld.\n", GetLastError());
+ }
+
+ free(szwPtr);
+ PAL_Terminate();
+
+ return PASS;
+}
+
+
diff --git a/src/pal/tests/palsuite/file_io/SetCurrentDirectoryA/test1/testinfo.dat b/src/pal/tests/palsuite/file_io/SetCurrentDirectoryA/test1/testinfo.dat
new file mode 100644
index 0000000000..743b2ea3db
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetCurrentDirectoryA/test1/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = SetCurrentDirectoryA
+Name = Test for SetCurrentDirectoryA (test 1)
+Type = DEFAULT
+EXE1 = setcurrentdirectorya
+Description
+= Change the current directory and verify the results.
diff --git a/src/pal/tests/palsuite/file_io/SetCurrentDirectoryA/test2/CMakeLists.txt b/src/pal/tests/palsuite/file_io/SetCurrentDirectoryA/test2/CMakeLists.txt
new file mode 100644
index 0000000000..7c9caf8081
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetCurrentDirectoryA/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ setcurrentdirectorya.c
+)
+
+add_executable(paltest_setcurrentdirectorya_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_setcurrentdirectorya_test2 coreclrpal)
+
+target_link_libraries(paltest_setcurrentdirectorya_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/SetCurrentDirectoryA/test2/setcurrentdirectorya.c b/src/pal/tests/palsuite/file_io/SetCurrentDirectoryA/test2/setcurrentdirectorya.c
new file mode 100644
index 0000000000..415dbbf045
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetCurrentDirectoryA/test2/setcurrentdirectorya.c
@@ -0,0 +1,142 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: SetCurrentDirectoryA.c (test 2)
+**
+** Purpose: Tests the PAL implementation of the SetCurrentDirectoryA function
+** by setting the current directory with ../
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ const char szDirName[MAX_PATH] = "testing";
+ char szBuiltDir[_MAX_DIR+1];
+ char szHomeDirBefore[_MAX_DIR+1];
+ char szHomeDirAfter[_MAX_DIR+1];
+ WCHAR* szwPtr = NULL;
+
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ /* create a temp directory off the current directory */
+ szwPtr = convert((LPSTR)szDirName);
+
+ if (CreateDirectoryA(szDirName, NULL) != TRUE)
+ {
+ free(szwPtr);
+ Fail("Unexpected error: CreateDirectoryW failed "
+ "with error code: %ld.\n",
+ GetLastError());
+ }
+
+ /* find out what the current "home" directory is */
+ memset(szHomeDirBefore, 0, (_MAX_DIR+1));
+
+ if( 0 == GetCurrentDirectoryA((_MAX_DIR+1), szHomeDirBefore) )
+ {
+ Trace("Unexpected error: Unable to get current directory "
+ "with GetCurrentDirectoryA that returned %ld\n",
+ GetLastError());
+
+ if (!RemoveDirectoryW(szwPtr))
+ {
+ Trace("Unexpected error: RemoveDirectoryW failed "
+ "with error code: %ld.\n",
+ GetLastError());
+ }
+ free(szwPtr);
+
+ Fail("");
+ }
+
+ /* append the temp name to the "home" directory */
+ memset(szBuiltDir, 0, (_MAX_DIR+1));
+#if WIN32
+ sprintf(szBuiltDir,"%s\\..\\", szDirName);
+#else
+ sprintf(szBuiltDir,"%s/../", szDirName);
+#endif
+
+
+ /* set the current directory to the temp directory */
+ if (SetCurrentDirectoryA(szBuiltDir) != TRUE)
+ {
+ Trace("ERROR: Unable to set current "
+ "directory to %s. Failed with error code: %ld.\n",
+ szBuiltDir,
+ GetLastError());
+
+ if (!RemoveDirectoryW(szwPtr))
+ {
+ Trace("SetCurrentDirectoryA: ERROR -> RemoveDirectoryW failed "
+ "with error code: %ld.\n",
+ GetLastError());
+ }
+ free(szwPtr);
+ Fail("");
+ }
+
+ /* find out what the current "home" directory is */
+ memset(szHomeDirAfter, 0, (_MAX_DIR+1));
+
+ if( 0 == GetCurrentDirectoryA((_MAX_DIR+1), szHomeDirAfter) )
+ {
+ Trace("Unexpected error: Unable to get current directory "
+ "with GetCurrentDirectoryA that returned %ld\n",
+ GetLastError());
+
+ if (!RemoveDirectoryW(szwPtr))
+ {
+ Trace("Unexpected error: RemoveDirectoryW failed "
+ "with error code: %ld.\n",
+ GetLastError());
+ }
+ free(szwPtr);
+
+ Fail("");
+ }
+
+ /*compare the new current dir to the compiled current dir */
+ if (strncmp(szHomeDirBefore, szHomeDirAfter, strlen(szHomeDirBefore)) != 0)
+ {
+ Trace("ERROR: The set directory \"%s\" does not "
+ "compare to the built directory \"%s\".\n",
+ szHomeDirAfter,
+ szHomeDirBefore);
+
+ if (!RemoveDirectoryW(szwPtr))
+ {
+ Trace("Unexpected error: RemoveDirectoryW failed "
+ "with error code: %ld.\n",
+ GetLastError());
+ }
+ free(szwPtr);
+ Fail("");
+ }
+
+ /* clean up */
+ if (!RemoveDirectoryW(szwPtr))
+ {
+ free(szwPtr);
+ Fail("Unexpected error: RemoveDirectoryW failed "
+ "with error code: %ld.\n",
+ GetLastError());
+ }
+
+ free(szwPtr);
+ PAL_Terminate();
+
+ return PASS;
+}
+
+
diff --git a/src/pal/tests/palsuite/file_io/SetCurrentDirectoryA/test2/testinfo.dat b/src/pal/tests/palsuite/file_io/SetCurrentDirectoryA/test2/testinfo.dat
new file mode 100644
index 0000000000..677c484062
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetCurrentDirectoryA/test2/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = SetCurrentDirectoryA
+Name = Positive test for SetCurrentDirectoryA (test 2)
+Type = DEFAULT
+EXE1 = setcurrentdirectorya
+Description
+= Set the current directory with ../ and verify the results.
diff --git a/src/pal/tests/palsuite/file_io/SetCurrentDirectoryA/test3/CMakeLists.txt b/src/pal/tests/palsuite/file_io/SetCurrentDirectoryA/test3/CMakeLists.txt
new file mode 100644
index 0000000000..57d3577d8f
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetCurrentDirectoryA/test3/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ setcurrentdirectorya.c
+)
+
+add_executable(paltest_setcurrentdirectorya_test3
+ ${SOURCES}
+)
+
+add_dependencies(paltest_setcurrentdirectorya_test3 coreclrpal)
+
+target_link_libraries(paltest_setcurrentdirectorya_test3
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/SetCurrentDirectoryA/test3/setcurrentdirectorya.c b/src/pal/tests/palsuite/file_io/SetCurrentDirectoryA/test3/setcurrentdirectorya.c
new file mode 100644
index 0000000000..a23a7a6314
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetCurrentDirectoryA/test3/setcurrentdirectorya.c
@@ -0,0 +1,56 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: SetCurrentDirectoryA.c (test 3)
+**
+** Purpose: Try calling SetCurrentDirectoryA with an invalid path,
+** with a valid filename and with NULL
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ const char szDirName[MAX_PATH] = "testing";
+ const char szFileName[MAX_PATH] = "setcurrentdirectorya.c";
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ /* set the current directory to an unexistant folder */
+ if (0 != SetCurrentDirectoryA(szDirName))
+ {
+ Fail("ERROR: SetCurrentDirectoryA should have failed "
+ "when trying to set the current directory to "
+ "an invalid folder\n");
+ }
+
+ /* set the current directory to an unexistant folder */
+ if (0 != SetCurrentDirectoryA(szFileName))
+ {
+ Fail("ERROR: SetCurrentDirectoryA should have failed "
+ "when trying to set the current directory to "
+ "a valid file name\n");
+ }
+
+ /* set the current directory to NULL */
+ if (0 != SetCurrentDirectoryA(NULL))
+ {
+ Fail("ERROR: SetCurrentDirectoryA should have failed "
+ "when trying to set the current directory to "
+ "NULL\n");
+ }
+
+ PAL_Terminate();
+
+ return PASS;
+}
+
+
diff --git a/src/pal/tests/palsuite/file_io/SetCurrentDirectoryA/test3/testinfo.dat b/src/pal/tests/palsuite/file_io/SetCurrentDirectoryA/test3/testinfo.dat
new file mode 100644
index 0000000000..d5520f7993
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetCurrentDirectoryA/test3/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = SetCurrentDirectoryA
+Name = Negative test for SetCurrentDirectoryA (test 3)
+Type = DEFAULT
+EXE1 = setcurrentdirectorya
+Description
+= Try calling SetCurrentDirectoryA with an invalid path,
+= with a valid filename and with NULL
diff --git a/src/pal/tests/palsuite/file_io/SetCurrentDirectoryW/CMakeLists.txt b/src/pal/tests/palsuite/file_io/SetCurrentDirectoryW/CMakeLists.txt
new file mode 100644
index 0000000000..1962ade358
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetCurrentDirectoryW/CMakeLists.txt
@@ -0,0 +1,6 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+add_subdirectory(test3)
+
diff --git a/src/pal/tests/palsuite/file_io/SetCurrentDirectoryW/test1/CMakeLists.txt b/src/pal/tests/palsuite/file_io/SetCurrentDirectoryW/test1/CMakeLists.txt
new file mode 100644
index 0000000000..a0c1dff62a
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetCurrentDirectoryW/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ SetCurrentDirectoryW.c
+)
+
+add_executable(paltest_setcurrentdirectoryw_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_setcurrentdirectoryw_test1 coreclrpal)
+
+target_link_libraries(paltest_setcurrentdirectoryw_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/SetCurrentDirectoryW/test1/SetCurrentDirectoryW.c b/src/pal/tests/palsuite/file_io/SetCurrentDirectoryW/test1/SetCurrentDirectoryW.c
new file mode 100644
index 0000000000..257d016ffb
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetCurrentDirectoryW/test1/SetCurrentDirectoryW.c
@@ -0,0 +1,178 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: SetCurrentDirectoryW.c (test 1)
+**
+** Purpose: Tests the PAL implementation of the SetCurrentDirectoryW function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+const char* szFileName = "blah";
+const char* szDirName = "testing";
+
+
+// In order to avoid the "chicken and egg" scenario, this is another
+// method of getting the current directory. GetFullPathNameW is called with
+// a dummy file name and then the file name is stripped off leaving the
+// current working directory
+BOOL GetCurrentDir(WCHAR* szwCurrentDir)
+{
+ DWORD dwRc = 0;
+ WCHAR szwReturnedPath[_MAX_DIR+1];
+ LPWSTR pPathPtr;
+ WCHAR* szwFileName = NULL;
+ WCHAR* szwDirName = NULL;
+ int nCount = 0;
+
+ // use GetFullPathName to to get the current path by stripping
+ // the file name off the end
+ memset(szwReturnedPath, 0, sizeof(WCHAR)*(_MAX_DIR+1));
+ szwFileName = convert((char*)szFileName);
+ dwRc = GetFullPathNameW(szwFileName,
+ _MAX_DIR,
+ szwReturnedPath,
+ &pPathPtr);
+
+ if (dwRc == 0)
+ {
+ // GetFullPathName failed
+ Trace("SetCurrentDirectoryW: ERROR -> GetFullPathNameW failed "
+ "with error code: %ld.\n", GetLastError());
+ RemoveDirectoryW(szwDirName);
+ free(szwFileName);
+ return(FALSE);
+ }
+
+ // now strip the file name from the full path to get the current path
+ nCount = lstrlenW(szwReturnedPath) - lstrlenW(szwFileName);
+ memset(szwCurrentDir, 0, sizeof(WCHAR)*(_MAX_DIR+1));
+ lstrcpynW(szwCurrentDir, szwReturnedPath, nCount);
+
+ free(szwFileName);
+ return(TRUE);
+}
+
+int __cdecl main(int argc, char *argv[])
+{
+ WCHAR* szwDirName = NULL;
+ WCHAR szwNewDir[_MAX_DIR+1];
+ WCHAR szwBuiltDir[_MAX_DIR+1];
+ WCHAR szwHomeDir[_MAX_DIR+1];
+#if WIN32
+ WCHAR szwSlash[] = {'\\','\0'};
+#else
+ WCHAR szwSlash[] = {'/','\0'};
+#endif
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ // remove the directory just in case a previous run of the test didn't
+ szwDirName = convert((char*)szDirName);
+ RemoveDirectoryW(szwDirName);
+
+ // create a temp directory off the current directory
+ if (CreateDirectoryW(szwDirName, NULL) != TRUE)
+ {
+ Trace("SetCurrentDirectoryW: ERROR -> CreateDirectoryW failed "
+ "with error code: %ld.\n", GetLastError());
+ RemoveDirectoryW(szwDirName);
+ free(szwDirName);
+ Fail("");
+ }
+
+ // find out what the current "home" directory is
+ memset(szwHomeDir, 0, sizeof(WCHAR)*(_MAX_DIR+1));
+ if(GetCurrentDir(szwHomeDir) != TRUE)
+ {
+ RemoveDirectoryW(szwDirName);
+ free(szwDirName);
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+
+ // set the current directory to the temp directory
+ if (SetCurrentDirectoryW(szwDirName) != TRUE)
+ {
+ Trace("SetCurrentDirectoryW: ERROR -> Unable to set current "
+ "directory. Failed with error code: %ld.\n", GetLastError());
+ RemoveDirectoryW(szwDirName);
+ free(szwDirName);
+ Fail("");
+ }
+
+ // append the temp name to the "home" directory
+ memset(szwBuiltDir, 0, sizeof(WCHAR)*(_MAX_DIR+1));
+ wcscpy(szwBuiltDir, szwHomeDir);
+ wcscat(szwBuiltDir, szwSlash);
+ wcscat(szwBuiltDir, szwDirName);
+
+ // get the new current directory
+ memset(szwNewDir, 0, sizeof(WCHAR)*(_MAX_DIR+1));
+ if(GetCurrentDir(szwNewDir) != TRUE)
+ {
+ RemoveDirectoryW(szwDirName);
+ free(szwDirName);
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+
+ // compare the new current dir to the compiled current dir
+ if (wcsncmp(szwNewDir, szwBuiltDir, wcslen(szwNewDir)) != 0)
+ {
+ RemoveDirectoryW(szwDirName);
+ free(szwDirName);
+ Fail("SetCurrentDirectoryW: ERROR -> The set directory does not "
+ "compare to the built directory.\n");
+ }
+
+
+
+ // set the current dir back to the original
+ if (SetCurrentDirectoryW(szwHomeDir) != TRUE)
+ {
+ Trace("SetCurrentDirectoryW: ERROR -> Unable to set current "
+ "directory. Failed with error code: %ld.\n", GetLastError());
+ RemoveDirectoryW(szwDirName);
+ free(szwDirName);
+ Fail("");
+ }
+
+
+ // get the new current directory
+ memset(szwNewDir, 0, sizeof(WCHAR)*(_MAX_DIR+1));
+ if(GetCurrentDir(szwNewDir) != TRUE)
+ {
+ RemoveDirectoryW(szwDirName);
+ free(szwDirName);
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+
+ // ensure it compares to the "home" directory which is where
+ // we should be now
+ if (wcsncmp(szwNewDir, szwHomeDir, wcslen(szwNewDir)) != 0)
+ {
+ RemoveDirectoryW(szwDirName);
+ free(szwDirName);
+ Fail("SetCurrentDirectoryW: ERROR -> The set directory does not "
+ "compare to the built directory.\n");
+ }
+
+
+ RemoveDirectoryW(szwDirName);
+ free(szwDirName);
+ PAL_Terminate();
+
+ return PASS;
+}
+
+
diff --git a/src/pal/tests/palsuite/file_io/SetCurrentDirectoryW/test1/testinfo.dat b/src/pal/tests/palsuite/file_io/SetCurrentDirectoryW/test1/testinfo.dat
new file mode 100644
index 0000000000..3a63887e07
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetCurrentDirectoryW/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = SetCurrentDirectoryW
+Name = Test for SetCurrentDirectoryW (test 1)
+Type = DEFAULT
+EXE1 = setcurrentdirectoryw
+Description
+= Change the current directory and verify the results.
+
diff --git a/src/pal/tests/palsuite/file_io/SetCurrentDirectoryW/test2/CMakeLists.txt b/src/pal/tests/palsuite/file_io/SetCurrentDirectoryW/test2/CMakeLists.txt
new file mode 100644
index 0000000000..a032462d19
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetCurrentDirectoryW/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ setcurrentdirectoryw.c
+)
+
+add_executable(paltest_setcurrentdirectoryw_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_setcurrentdirectoryw_test2 coreclrpal)
+
+target_link_libraries(paltest_setcurrentdirectoryw_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/SetCurrentDirectoryW/test2/setcurrentdirectoryw.c b/src/pal/tests/palsuite/file_io/SetCurrentDirectoryW/test2/setcurrentdirectoryw.c
new file mode 100644
index 0000000000..7e3d7b785f
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetCurrentDirectoryW/test2/setcurrentdirectoryw.c
@@ -0,0 +1,147 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: SetCurrentDirectoryW.c (test 2)
+**
+** Purpose: Tests the PAL implementation of the SetCurrentDirectoryW function
+** by setting the current directory with ../
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ const char szDirName[MAX_PATH] = "testing";
+ char szBuiltDir[MAX_PATH];
+ WCHAR* szwBuiltDir = NULL;
+ WCHAR szwHomeDirBefore[MAX_PATH];
+ WCHAR szwHomeDirAfter[MAX_PATH];
+ WCHAR* szwPtr = NULL;
+
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ /* create a temp directory off the current directory */
+ szwPtr = convert((LPSTR)szDirName);
+
+ if (CreateDirectoryW(szwPtr, NULL) != TRUE)
+ {
+ free(szwPtr);
+ Fail("Unexpected error: CreateDirectoryW failed "
+ "with error code: %ld.\n",
+ GetLastError());
+ }
+
+ /* find out what the current "home" directory is */
+ memset(szwHomeDirBefore, 0, MAX_PATH * sizeof(WCHAR));
+
+ if( 0 == GetCurrentDirectoryW(MAX_PATH, szwHomeDirBefore) )
+ {
+ Trace("Unexpected error: Unable to get current directory "
+ "with GetCurrentDirectoryW that returned %ld\n",
+ GetLastError());
+
+ if (!RemoveDirectoryW(szwPtr))
+ {
+ Trace("Unexpected error: RemoveDirectoryW failed "
+ "with error code: %ld.\n",
+ GetLastError());
+ }
+ free(szwPtr);
+
+ Fail("");
+ }
+
+ /* append the temp name to the "home" directory */
+ memset(szBuiltDir, 0, MAX_PATH);
+#if WIN32
+ sprintf(szBuiltDir,"%s\\..\\", szDirName);
+#else
+ sprintf(szBuiltDir,"%s/../", szDirName);
+#endif
+
+ szwBuiltDir = convert(szBuiltDir);
+
+ /* set the current directory to the temp directory */
+ if (SetCurrentDirectoryW(szwBuiltDir) != TRUE)
+ {
+ Trace("ERROR: Unable to set current "
+ "directory to %S. Failed with error code: %ld.\n",
+ szwBuiltDir,
+ GetLastError());
+
+ if (!RemoveDirectoryW(szwPtr))
+ {
+ Trace("Unexpected error: RemoveDirectoryW failed "
+ "with error code: %ld.\n",
+ GetLastError());
+ }
+ free(szwPtr);
+ free(szwBuiltDir);
+ Fail("");
+ }
+
+ free(szwBuiltDir);
+
+ /* find out what the current "home" directory is */
+ memset(szwHomeDirAfter, 0, MAX_PATH * sizeof(WCHAR));
+
+ if( 0 == GetCurrentDirectoryW(MAX_PATH, szwHomeDirAfter) )
+ {
+ Trace("Unexpected error: Unable to get current directory "
+ "with GetCurrentDirectoryW that returned %ld\n",
+ GetLastError());
+
+ if (!RemoveDirectoryW(szwPtr))
+ {
+ Trace("ERROR: RemoveDirectoryW failed "
+ "with error code: %ld.\n",
+ GetLastError());
+ }
+ free(szwPtr);
+
+ Fail("");
+ }
+
+ /*compare the new current dir to the compiled current dir */
+ if (wcsncmp(szwHomeDirBefore, szwHomeDirAfter, wcslen(szwHomeDirBefore)) != 0)
+ {
+ Trace("ERROR:The set directory \"%S\" does not "
+ "compare to the built directory \"%S\".\n",
+ szwHomeDirAfter,
+ szwHomeDirBefore);
+
+ if (!RemoveDirectoryW(szwPtr))
+ {
+ Trace("Unexpected error: RemoveDirectoryW failed "
+ "with error code: %ld.\n",
+ GetLastError());
+ }
+ free(szwPtr);
+ Fail("");
+ }
+
+ /* clean up */
+ if (!RemoveDirectoryW(szwPtr))
+ {
+ free(szwPtr);
+ Fail("Unexpected error: RemoveDirectoryW failed "
+ "with error code: %ld.\n",
+ GetLastError());
+ }
+
+ free(szwPtr);
+ PAL_Terminate();
+
+ return PASS;
+}
+
+
diff --git a/src/pal/tests/palsuite/file_io/SetCurrentDirectoryW/test2/testinfo.dat b/src/pal/tests/palsuite/file_io/SetCurrentDirectoryW/test2/testinfo.dat
new file mode 100644
index 0000000000..a739688d4d
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetCurrentDirectoryW/test2/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = SetCurrentDirectoryW
+Name = Positive test for SetCurrentDirectoryW (test 2)
+Type = DEFAULT
+EXE1 = setcurrentdirectoryw
+Description
+= Set the current directory with ../ and verify the results.
diff --git a/src/pal/tests/palsuite/file_io/SetCurrentDirectoryW/test3/CMakeLists.txt b/src/pal/tests/palsuite/file_io/SetCurrentDirectoryW/test3/CMakeLists.txt
new file mode 100644
index 0000000000..3b981f9564
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetCurrentDirectoryW/test3/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ setcurrentdirectoryw.c
+)
+
+add_executable(paltest_setcurrentdirectoryw_test3
+ ${SOURCES}
+)
+
+add_dependencies(paltest_setcurrentdirectoryw_test3 coreclrpal)
+
+target_link_libraries(paltest_setcurrentdirectoryw_test3
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/SetCurrentDirectoryW/test3/setcurrentdirectoryw.c b/src/pal/tests/palsuite/file_io/SetCurrentDirectoryW/test3/setcurrentdirectoryw.c
new file mode 100644
index 0000000000..e8c4be2ad4
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetCurrentDirectoryW/test3/setcurrentdirectoryw.c
@@ -0,0 +1,64 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: SetCurrentDirectoryW.c (test 3)
+**
+** Purpose: Try calling SetCurrentDirectoryW with an invalid path,
+** with a valid filename and with NULL
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ char szDirName[MAX_PATH] = "testing";
+ WCHAR* szwDirName = NULL;
+ char szFileName[MAX_PATH] = "setcurrentdirectorya.c";
+ WCHAR* szwFileName = NULL;
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ /* set the current directory to an unexistant folder */
+ szwDirName = convert(szDirName);
+ if (0 != SetCurrentDirectoryW(szwDirName))
+ {
+ free(szwDirName);
+ Fail("ERROR: SetCurrentDirectoryW should have failed "
+ "when trying to set the current directory to "
+ "an invalid folder\n");
+ }
+ free(szwDirName);
+
+ /* set the current directory to an unexistant folder */
+ szwFileName = convert(szFileName);
+ if (0 != SetCurrentDirectoryW(szwFileName))
+ {
+ free(szwFileName);
+ Fail("ERROR: SetCurrentDirectoryW should have failed "
+ "when trying to set the current directory to "
+ "a valid file name\n");
+ }
+ free(szwFileName);
+
+ /* set the current directory to NULL */
+ if (0 != SetCurrentDirectoryW(NULL))
+ {
+ Fail("ERROR: SetCurrentDirectoryW should have failed "
+ "when trying to set the current directory to "
+ "NULL\n");
+ }
+
+ PAL_Terminate();
+
+ return PASS;
+}
+
+
diff --git a/src/pal/tests/palsuite/file_io/SetCurrentDirectoryW/test3/testinfo.dat b/src/pal/tests/palsuite/file_io/SetCurrentDirectoryW/test3/testinfo.dat
new file mode 100644
index 0000000000..fc931291ec
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetCurrentDirectoryW/test3/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = SetCurrentDirectoryW
+Name = Negative test for SetCurrentDirectoryW (test 3)
+Type = DEFAULT
+EXE1 = setcurrentdirectoryw
+Description
+= Try calling SetCurrentDirectoryW with an invalid path,
+= with a valid filename and with NULL
diff --git a/src/pal/tests/palsuite/file_io/SetEndOfFile/CMakeLists.txt b/src/pal/tests/palsuite/file_io/SetEndOfFile/CMakeLists.txt
new file mode 100644
index 0000000000..8083faf655
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetEndOfFile/CMakeLists.txt
@@ -0,0 +1,8 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+add_subdirectory(test3)
+add_subdirectory(test4)
+add_subdirectory(test5)
+
diff --git a/src/pal/tests/palsuite/file_io/SetEndOfFile/test1/CMakeLists.txt b/src/pal/tests/palsuite/file_io/SetEndOfFile/test1/CMakeLists.txt
new file mode 100644
index 0000000000..e77ab30b86
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetEndOfFile/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ SetEndOfFile.c
+)
+
+add_executable(paltest_setendoffile_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_setendoffile_test1 coreclrpal)
+
+target_link_libraries(paltest_setendoffile_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/SetEndOfFile/test1/SetEndOfFile.c b/src/pal/tests/palsuite/file_io/SetEndOfFile/test1/SetEndOfFile.c
new file mode 100644
index 0000000000..9078ddc65b
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetEndOfFile/test1/SetEndOfFile.c
@@ -0,0 +1,85 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: SetEndOfFile.c (test 1)
+**
+** Purpose: Tests the PAL implementation of the SetEndOfFile function.
+** This test will attempt to operate on a NULL file handle and
+** also test truncating a file not opened with GENERIC_WRITE
+**
+** Assumes successful:
+** SetEndOfFile
+** CreateFile
+** CloseHandle
+**
+
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+const char* szTextFile = "text.txt";
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ HANDLE hFile = NULL;
+ BOOL bRc = FALSE;
+
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ bRc = SetEndOfFile(NULL);
+ if (bRc == TRUE)
+ {
+ Fail("SetEndOfFile: ERROR -> Operation succeeded on a NULL file "
+ "handle\n");
+ }
+
+ /* create a test file */
+ hFile = CreateFile(szTextFile,
+ GENERIC_READ,
+ FILE_SHARE_READ,
+ NULL,
+ OPEN_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if(hFile == INVALID_HANDLE_VALUE)
+ {
+ Fail("SetEndOfFile: ERROR -> Unable to create file \"%s\".\n",
+ szTextFile);
+ }
+
+ bRc = SetEndOfFile(hFile);
+ if (bRc == TRUE)
+ {
+ Trace("SetEndOfFile: ERROR -> Operation succeeded on read-only"
+ " file.\n");
+ bRc = CloseHandle(hFile);
+ if (bRc != TRUE)
+ {
+ Trace("SetEndOfFile: ERROR -> Unable to close file \"%s\".\n",
+ szTextFile);
+ }
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+
+ bRc = CloseHandle(hFile);
+ if (bRc != TRUE)
+ {
+ Fail("SetEndOfFile: ERROR -> Unable to close file \"%s\".\n",
+ szTextFile);
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/file_io/SetEndOfFile/test1/testinfo.dat b/src/pal/tests/palsuite/file_io/SetEndOfFile/test1/testinfo.dat
new file mode 100644
index 0000000000..72fc5e59e6
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetEndOfFile/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = SetEndOfFile
+Name = Positive Test for SetEndOfFile
+Type = DEFAULT
+EXE1 = setendoffile
+Description
+=Truncate a file
+
diff --git a/src/pal/tests/palsuite/file_io/SetEndOfFile/test2/CMakeLists.txt b/src/pal/tests/palsuite/file_io/SetEndOfFile/test2/CMakeLists.txt
new file mode 100644
index 0000000000..b04dea04a6
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetEndOfFile/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ SetEndOfFile.c
+)
+
+add_executable(paltest_setendoffile_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_setendoffile_test2 coreclrpal)
+
+target_link_libraries(paltest_setendoffile_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/SetEndOfFile/test2/SetEndOfFile.c b/src/pal/tests/palsuite/file_io/SetEndOfFile/test2/SetEndOfFile.c
new file mode 100644
index 0000000000..6b3c05088e
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetEndOfFile/test2/SetEndOfFile.c
@@ -0,0 +1,154 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: SetEndOfFile.c (test 2)
+**
+** Purpose: Tests the PAL implementation of the SetEndOfFile function.
+** This test will attempt to truncate a file
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+
+const char* szStringTest = "The quick fox jumped over the lazy dog's back.";
+const char* szTextFile = "text.txt";
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ HANDLE hFile = NULL;
+ DWORD dwByteCount = 0;
+ DWORD dwBytesWritten;
+ BOOL bRc = FALSE;
+ char szBuffer[100];
+ DWORD dwBytesRead = 0;
+ FILE *pFile = NULL;
+
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ // create a test file
+ hFile = CreateFile(szTextFile,
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if(hFile == INVALID_HANDLE_VALUE)
+ {
+ Fail("SetEndOfFile: ERROR -> Unable to create file \"%s\".\n",
+ szTextFile);
+ }
+
+ bRc = WriteFile(hFile, szStringTest, 20, &dwBytesWritten, NULL);
+ if (bRc != TRUE)
+ {
+ Trace("SetEndOfFile: ERROR -> Uable to write to \"%s\".\n",
+ szTextFile);
+ bRc = CloseHandle(hFile);
+ if (bRc != TRUE)
+ {
+ Trace("SetEndOfFile: ERROR -> Unable to close file \"%s\".\n",
+ szTextFile);
+ }
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+
+ bRc = CloseHandle(hFile);
+ if (bRc != TRUE)
+ {
+ Fail("SetEndOfFile: ERROR -> Unable to close file \"%s\".\n",
+ szTextFile);
+ }
+
+ // open the test file
+ hFile = CreateFile(szTextFile,
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if(hFile == INVALID_HANDLE_VALUE)
+ {
+ Fail("SetEndOfFile: ERROR -> Unable to open file \"%s\".\n",
+ szTextFile);
+ }
+
+ // read a bit of the file to move the file pointer
+ dwByteCount = 10;
+ bRc = ReadFile(hFile, szBuffer, dwByteCount, &dwBytesRead, NULL);
+ if (bRc != TRUE)
+ {
+ Trace("SetEndOfFile: ERROR -> Uable to read from \"%s\".\n",
+ szTextFile);
+ bRc = CloseHandle(hFile);
+ if (bRc != TRUE)
+ {
+ Trace("SetEndOfFile: ERROR -> Unable to close file \"%s\".\n",
+ szTextFile);
+ }
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+
+ bRc = SetEndOfFile(hFile);
+ if (bRc != TRUE)
+ {
+ Trace("SetEndOfFile: ERROR -> Uable to set end of file.\n");
+ bRc = CloseHandle(hFile);
+ if (bRc != TRUE)
+ {
+ Trace("SetEndOfFile: ERROR -> Unable to close file \"%s\".\n",
+ szTextFile);
+ }
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+
+ bRc = CloseHandle(hFile);
+ if (bRc != TRUE)
+ {
+ Fail("SetEndOfFile: ERROR -> Unable to close file \"%s\".\n",
+ szTextFile);
+ }
+
+ // open and read the test file
+ pFile = fopen(szTextFile, "r");
+ if (pFile == NULL)
+ {
+ Fail("SetEndOfFile: ERROR -> fopen was unable to open file \"%s\".\n",
+ szTextFile);
+ }
+
+ // since we truncated the file at 10 characters,
+ // try reading 20 just to be safe
+ memset(szBuffer, 0, 100);
+ fgets(szBuffer, 20, pFile);
+ fclose(pFile);
+ if (strlen(szBuffer) != dwByteCount)
+ {
+ Fail("SetEndOfFile: ERROR -> file apparently not truncated at "
+ "correct position.\n");
+ }
+ if (strncmp(szBuffer, szStringTest, dwByteCount) != 0)
+ {
+ Fail("SetEndOfFile: ERROR -> truncated file contents doesn't "
+ "compare with what should be there\n");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/file_io/SetEndOfFile/test2/testinfo.dat b/src/pal/tests/palsuite/file_io/SetEndOfFile/test2/testinfo.dat
new file mode 100644
index 0000000000..555f0d823f
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetEndOfFile/test2/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = SetEndOfFile
+Name = Positive Test for SetEndOfFile
+Type = DEFAULT
+EXE1 = setendoffile
+Description
+=Truncate the test file using SetEndOfFile
diff --git a/src/pal/tests/palsuite/file_io/SetEndOfFile/test3/CMakeLists.txt b/src/pal/tests/palsuite/file_io/SetEndOfFile/test3/CMakeLists.txt
new file mode 100644
index 0000000000..1ab177d00a
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetEndOfFile/test3/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ SetEndOfFile.c
+)
+
+add_executable(paltest_setendoffile_test3
+ ${SOURCES}
+)
+
+add_dependencies(paltest_setendoffile_test3 coreclrpal)
+
+target_link_libraries(paltest_setendoffile_test3
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/SetEndOfFile/test3/SetEndOfFile.c b/src/pal/tests/palsuite/file_io/SetEndOfFile/test3/SetEndOfFile.c
new file mode 100644
index 0000000000..dfd9194465
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetEndOfFile/test3/SetEndOfFile.c
@@ -0,0 +1,109 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: SetEndOfFile.c (test 3)
+**
+** Purpose: Tests the PAL implementation of the SetEndOfFile function.
+** This test will attempt to expand a file. Assumes successful
+** SetFilePointer and GetFileSize tests.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+
+const char* szTextFile = "text.txt";
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ HANDLE hFile = NULL;
+ DWORD dwByteCount = 0;
+ DWORD dwOffset = 25;
+ DWORD dwRc = 0;
+ BOOL bRc = FALSE;
+
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ /* create a test file */
+ hFile = CreateFile(szTextFile,
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if(hFile == INVALID_HANDLE_VALUE)
+ {
+ Fail("SetEndOfFile: ERROR -> Unable to create file \"%s\".\n",
+ szTextFile);
+ }
+
+ /* move the file pointer */
+ /* assumes a successful SetFilePointer test */
+ dwRc = SetFilePointer(hFile, dwOffset, NULL, FILE_BEGIN);
+ if (dwRc == INVALID_SET_FILE_POINTER)
+ {
+ Trace("SetEndOfFile: ERROR -> Call to SetFilePointer failed\n");
+ bRc = CloseHandle(hFile);
+ if (bRc != TRUE)
+ {
+ Trace("SetEndOfFile: ERROR -> Unable to close file \"%s\".\n",
+ szTextFile);
+ }
+ PAL_Terminate();
+ return FAIL;
+ }
+
+ bRc = SetEndOfFile(hFile);
+ if (bRc != TRUE)
+ {
+ Trace("SetEndOfFile: ERROR -> Uable to set end of file.\n");
+ bRc = CloseHandle(hFile);
+ if (bRc != TRUE)
+ {
+ Trace("SetEndOfFile: ERROR -> Unable to close file \"%s\".\n",
+ szTextFile);
+ }
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+
+
+ /* call GetFileSize to verify pointer position */
+ /* assumes a successful GetFileSize test */
+
+ dwByteCount = GetFileSize(hFile, NULL);
+ if (dwByteCount != dwOffset)
+ {
+ Trace("SetEndOfFile: ERROR -> file apparently not expanded to the"
+ " correct size.\n");
+ bRc = CloseHandle(hFile);
+ if (bRc != TRUE)
+ {
+ Trace("SetEndOfFile: ERROR -> Unable to close file \"%s\".\n",
+ szTextFile);
+ }
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+
+ bRc = CloseHandle(hFile);
+ if (bRc != TRUE)
+ {
+ Fail("SetEndOfFile: ERROR -> Unable to close file \"%s\".\n",
+ szTextFile);
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/file_io/SetEndOfFile/test3/testinfo.dat b/src/pal/tests/palsuite/file_io/SetEndOfFile/test3/testinfo.dat
new file mode 100644
index 0000000000..7f3868d6ca
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetEndOfFile/test3/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = SetEndOfFile
+Name = Positive Test for SetEndOfFile
+Type = DEFAULT
+EXE1 = setendoffile
+Description
+=Set the end of file past the actual end
+=of file thereby, extending it.
+
diff --git a/src/pal/tests/palsuite/file_io/SetEndOfFile/test4/CMakeLists.txt b/src/pal/tests/palsuite/file_io/SetEndOfFile/test4/CMakeLists.txt
new file mode 100644
index 0000000000..ff0b6f999c
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetEndOfFile/test4/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ setendoffile.c
+)
+
+add_executable(paltest_setendoffile_test4
+ ${SOURCES}
+)
+
+add_dependencies(paltest_setendoffile_test4 coreclrpal)
+
+target_link_libraries(paltest_setendoffile_test4
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/SetEndOfFile/test4/setendoffile.c b/src/pal/tests/palsuite/file_io/SetEndOfFile/test4/setendoffile.c
new file mode 100644
index 0000000000..98a6ec63da
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetEndOfFile/test4/setendoffile.c
@@ -0,0 +1,138 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: setendoffile.c (test 4)
+**
+** Purpose: Tests the PAL implementation of the SetEndOfFile function.
+** Verify that the file pointer is the same before
+** and after a SetEndOfFile using SetFilePointer with
+** FILE_BEGIN, FILE_CURRENT and FILE_END
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+
+const char* szStringTest = "The quick fox jumped over the lazy dog's back.";
+const char* szTextFile = "test.tmp";
+
+static void Cleanup(HANDLE hFile)
+{
+ if (!CloseHandle(hFile))
+ {
+ Trace("SetEndOfFile: ERROR -> Unable to close file \"%s\". ",
+ "GetLastError returned %u.\n",
+ szTextFile,
+ GetLastError());
+ }
+ if (!DeleteFileA(szTextFile))
+ {
+ Trace("SetEndOfFile: ERROR -> Unable to delete file \"%s\". ",
+ "GetLastError returned %u.\n",
+ szTextFile,
+ GetLastError());
+ }
+}
+
+static void DoTest(HANDLE hFile, DWORD dwOffset, DWORD dwMethod)
+{
+ DWORD dwFP1 = 0;
+ DWORD dwFP2 = 0;
+ DWORD dwError;
+
+ /* set the pointer*/
+ dwFP1 = SetFilePointer(hFile, dwOffset, NULL, dwMethod);
+ if ((dwFP1 == INVALID_SET_FILE_POINTER) &&
+ ((dwError = GetLastError()) != ERROR_SUCCESS))
+ {
+ Trace("SetEndOfFile: ERROR -> Unable to set the pointer to the "
+ "end of the file. GetLastError returned %u.\n",
+ dwError);
+ Cleanup(hFile);
+ Fail("");
+ }
+
+ /* set EOF */
+ if (!SetEndOfFile(hFile))
+ {
+ Trace("SetEndOfFile: ERROR -> Unable to set end of file. "
+ "GetLastError returned %u.\n",
+ GetLastError());
+ Cleanup(hFile);
+ Fail("");
+ }
+
+ /* get current file pointer pointer */
+ dwFP2 = SetFilePointer(hFile, 0, NULL, FILE_CURRENT);
+ if ((dwFP1 == INVALID_SET_FILE_POINTER) &&
+ ((dwError = GetLastError()) != ERROR_SUCCESS))
+ {
+ Trace("SetEndOfFile: ERROR -> Unable to set the pointer to the "
+ "end of the file. GetLastError returned %u.\n",
+ dwError);
+ Cleanup(hFile);
+ Fail("");
+ }
+
+ /* are they the same? */
+ if (dwFP1 != dwFP2)
+ {
+ Trace("SetEndOfFile: ERROR -> File pointer before (%u) the "
+ "SetEndOfFile call was different than after (%u).\n",
+ dwFP1,
+ dwFP2);
+ Cleanup(hFile);
+ Fail("");
+ }
+}
+
+int __cdecl main(int argc, char *argv[])
+{
+ HANDLE hFile = NULL;
+ DWORD dwBytesWritten;
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ /* create a test file */
+ hFile = CreateFile(szTextFile,
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if(hFile == INVALID_HANDLE_VALUE)
+ {
+ Fail("SetEndOfFile: ERROR -> Unable to create file \"%s\". "
+ "GetLastError returned %u.\n",
+ szTextFile,
+ GetLastError());
+ }
+
+ if (!WriteFile(hFile, szStringTest, strlen(szStringTest), &dwBytesWritten, NULL))
+ {
+ Trace("SetEndOfFile: ERROR -> Unable to write to \"%s\". ",
+ "GetLastError returned %u.\n",
+ szTextFile,
+ GetLastError());
+ Cleanup(hFile);
+ Fail("");
+ }
+
+ DoTest(hFile, -2, FILE_END); /* test the end */
+ DoTest(hFile, -10, FILE_CURRENT); /* test the middle-ish */
+ DoTest(hFile, 0, FILE_BEGIN); /* test the start */
+
+ Cleanup(hFile);
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/file_io/SetEndOfFile/test4/testinfo.dat b/src/pal/tests/palsuite/file_io/SetEndOfFile/test4/testinfo.dat
new file mode 100644
index 0000000000..51d9185343
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetEndOfFile/test4/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = SetEndOfFile
+Name = Positive Test for SetEndOfFile (test 4)
+Type = DEFAULT
+EXE1 = setendoffile
+Description
+= Tests the PAL implementation of the SetEndOfFile function.
+= Verify that the file pointer is the same before
+= and after a SetEndOfFile using SetFilePointer with
+= FILE_BEGIN, FILE_CURRENT and FILE_END
diff --git a/src/pal/tests/palsuite/file_io/SetEndOfFile/test5/CMakeLists.txt b/src/pal/tests/palsuite/file_io/SetEndOfFile/test5/CMakeLists.txt
new file mode 100644
index 0000000000..cca7167762
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetEndOfFile/test5/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test5.c
+)
+
+add_executable(paltest_setendoffile_test5
+ ${SOURCES}
+)
+
+add_dependencies(paltest_setendoffile_test5 coreclrpal)
+
+target_link_libraries(paltest_setendoffile_test5
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/SetEndOfFile/test5/test5.c b/src/pal/tests/palsuite/file_io/SetEndOfFile/test5/test5.c
new file mode 100644
index 0000000000..7000d1af15
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetEndOfFile/test5/test5.c
@@ -0,0 +1,183 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test5.c
+**
+** Purpose: Tests the PAL implementation of the SetEndOfFile function.
+** Test attempts to read the number of characters up to
+** the EOF pointer, which was specified.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ HANDLE hFile = NULL;
+ DWORD dwBytesWritten;
+ DWORD retCode;
+ BOOL bRc = FALSE;
+ char szBuffer[256];
+ DWORD dwBytesRead = 0;
+ char testFile[] = "testfile.tmp";
+ char testString[] = "watch what happens";
+ LONG shiftAmount = 10;
+
+ /* Initialize the PAL.
+ */
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ /* Initialize the buffer.
+ */
+ memset(szBuffer, 0, 256);
+
+ /* Create a file to test with.
+ */
+ hFile = CreateFile(testFile,
+ GENERIC_WRITE|GENERIC_READ,
+ FILE_SHARE_WRITE|FILE_SHARE_READ,
+ NULL,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if(hFile == INVALID_HANDLE_VALUE)
+ {
+ Fail("ERROR:%u: Unable to create file \"%s\".\n",
+ GetLastError(),
+ testFile);
+ }
+
+ /* Write to the File handle.
+ */
+ bRc = WriteFile(hFile,
+ testString,
+ strlen(testString),
+ &dwBytesWritten,
+ NULL);
+
+ if (bRc == FALSE)
+ {
+ Trace("ERROR:%u: Unable to write to file handle "
+ "hFile=0x%lx\n",
+ GetLastError(),
+ hFile);
+ if (!CloseHandle(hFile))
+ {
+ Fail("ERROR:%u%: Unable to close handle 0x%lx.\n",
+ GetLastError(),
+ hFile);
+ }
+ Fail("");
+ }
+
+ /* Set the file pointer to shiftAmount bytes from the front of the file
+ */
+ retCode = SetFilePointer(hFile, shiftAmount, NULL, FILE_BEGIN);
+ if(retCode == INVALID_SET_FILE_POINTER)
+ {
+ Trace("ERROR:%u: Unable to set the file pointer to %d\n",
+ GetLastError(),
+ shiftAmount);
+ if (!CloseHandle(hFile))
+ {
+ Fail("ERROR:%u%: Unable to close handle 0x%lx.\n",
+ GetLastError(),
+ hFile);
+ }
+ Fail("");
+ }
+
+ /* set the end of file pointer to 'shiftAmount' */
+ bRc = SetEndOfFile(hFile);
+ if (bRc == FALSE)
+ {
+ Trace("ERROR:%u: Unable to set file pointer of file handle 0x%lx.\n",
+ GetLastError(),
+ hFile);
+ if (!CloseHandle(hFile))
+ {
+ Fail("ERROR:%u%: Unable to close handle 0x%lx.\n",
+ GetLastError(),
+ hFile);
+ }
+ Fail("");
+ }
+
+ /* Set the file pointer to 10 bytes from the front of the file
+ */
+ retCode = SetFilePointer(hFile, (LONG)NULL, NULL, FILE_BEGIN);
+ if(retCode == INVALID_SET_FILE_POINTER)
+ {
+ Trace("ERROR:%u: Unable to set the file pointer to %d\n",
+ GetLastError(),
+ FILE_BEGIN);
+ if (!CloseHandle(hFile))
+ {
+ Fail("ERROR:%u%: Unable to close handle 0x%lx.\n",
+ GetLastError(),
+ hFile);
+ }
+ Fail("");
+ }
+
+ /* Attempt to read the entire string, 'testString' from a file
+ * that has it's end of pointer set at shiftAmount;
+ */
+ bRc = ReadFile(hFile,
+ szBuffer,
+ strlen(testString),
+ &dwBytesRead,
+ NULL);
+
+ if (bRc == FALSE)
+ {
+ Trace("ERROR:%u: Unable to read from file handle 0x%lx.\n",
+ GetLastError(),
+ hFile);
+ if (!CloseHandle(hFile))
+ {
+ Fail("ERROR:%u%: Unable to close handle 0x%lx.\n",
+ GetLastError(),
+ hFile);
+ }
+ Fail("");
+ }
+
+ /* Confirm the number of bytes read with that requested.
+ */
+ if (dwBytesRead != shiftAmount)
+ {
+ Trace("ERROR: The number of bytes read \"%d\" is not equal to the "
+ "number that should have been written \"%d\".\n",
+ dwBytesRead,
+ shiftAmount);
+ if (!CloseHandle(hFile))
+ {
+ Fail("ERROR:%u%: Unable to close handle 0x%lx.\n",
+ GetLastError(),
+ hFile);
+ }
+ Fail("");
+ }
+
+ bRc = CloseHandle(hFile);
+ if(!bRc)
+ {
+ Fail("ERROR:%u CloseHandle failed to close the handle\n",
+ GetLastError());
+ }
+
+ /* Terminate the PAL.
+ */
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/file_io/SetEndOfFile/test5/testinfo.dat b/src/pal/tests/palsuite/file_io/SetEndOfFile/test5/testinfo.dat
new file mode 100644
index 0000000000..3a226ff8ad
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetEndOfFile/test5/testinfo.dat
@@ -0,0 +1,16 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = SetEndOfFile
+Name = Positive Test for SetEndOfFile
+Type = DEFAULT
+EXE1 = test5
+Description
+= Tests the PAL implementation of the SetEndOfFile function.
+= Test attempts to set the end of file pointer to a position
+= which has data before and after it. Then it attempts to
+= read text beyond the end of file pointer.
+
diff --git a/src/pal/tests/palsuite/file_io/SetFileAttributesA/CMakeLists.txt b/src/pal/tests/palsuite/file_io/SetFileAttributesA/CMakeLists.txt
new file mode 100644
index 0000000000..a3847f8ca9
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetFileAttributesA/CMakeLists.txt
@@ -0,0 +1,7 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+add_subdirectory(test3)
+add_subdirectory(test4)
+
diff --git a/src/pal/tests/palsuite/file_io/SetFileAttributesA/test1/CMakeLists.txt b/src/pal/tests/palsuite/file_io/SetFileAttributesA/test1/CMakeLists.txt
new file mode 100644
index 0000000000..81e2dfdea2
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetFileAttributesA/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ SetFileAttributesA.c
+)
+
+add_executable(paltest_setfileattributesa_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_setfileattributesa_test1 coreclrpal)
+
+target_link_libraries(paltest_setfileattributesa_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/SetFileAttributesA/test1/SetFileAttributesA.c b/src/pal/tests/palsuite/file_io/SetFileAttributesA/test1/SetFileAttributesA.c
new file mode 100644
index 0000000000..bacab2a0ad
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetFileAttributesA/test1/SetFileAttributesA.c
@@ -0,0 +1,168 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: SetFileAttributesA.c
+**
+**
+** Purpose: Tests the PAL implementation of the SetFileAttributesA function
+** Test that we can set a file READONLY, and then that we're unable to
+** open that file with WRITE access. Then change it to NORMAL attributes, and
+** try to open it again -- it should work now.
+**
+** Depends:
+** CreateFile
+** CloseHandle
+**
+**
+**===================================================================*/
+
+/* According to the spec, only READONLY attribute can be set
+ in FreeBSD.
+*/
+
+#include <palsuite.h>
+
+
+
+int __cdecl main(int argc, char **argv)
+{
+ DWORD TheResult;
+ HANDLE TheFile;
+ char* FileName = {"test_file"};
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ // Create the test file
+ FILE *testFile = fopen(FileName, "w");
+ if (testFile == NULL)
+ {
+ Fail("Unexpected error: Unable to open file %S with fopen. \n", FileName);
+ }
+ if (fputs("testing", testFile) == EOF)
+ {
+ Fail("Unexpected error: Unable to write to file %S with fputs. \n", FileName);
+ }
+ if (fclose(testFile) != 0)
+ {
+ Fail("Unexpected error: Unable to close file %S with fclose. \n", FileName);
+ }
+ testFile = NULL;
+
+ /* Try to set the file to Read-only */
+
+ TheResult = SetFileAttributesA(FileName, FILE_ATTRIBUTE_READONLY);
+
+ if(TheResult == 0)
+ {
+ Fail("ERROR: SetFileAttributesA returned 0, failure, when trying "
+ "to set the FILE_ATTRIBUTE_READONLY attribute.");
+ }
+
+ /* Attempt to open this READONLY file with WRITE access,
+ The open should fail and the HANDLE should be invalid.
+ */
+
+ TheFile = CreateFileA(
+ FileName, // file name
+ GENERIC_READ|GENERIC_WRITE, // access mode
+ 0, // share mode
+ NULL, // SD
+ OPEN_ALWAYS, // how to create
+ FILE_ATTRIBUTE_NORMAL, // file attributes
+ NULL // handle to template file
+ );
+
+ if(TheFile != INVALID_HANDLE_VALUE)
+ {
+ TheResult = CloseHandle(TheFile);
+ if(TheResult == 0)
+ {
+ Fail("ERROR: CloseHandle failed. This tests relies upon it "
+ "working properly.");
+ }
+ Fail("ERROR: Tried to open a file that was created as "
+ "READONLY with the GENERIC_WRITE access mode. This should"
+ " cause CreateFile to return an INVALID_HANDLE_VALUE.");
+ }
+
+ /* Try to open the file with READ access, this should be ok.
+ The HANDLE will be valid.
+ */
+
+ TheFile = CreateFileA(
+ FileName, // file name
+ GENERIC_READ, // access mode
+ 0, // share mode
+ NULL, // SD
+ OPEN_ALWAYS, // how to create
+ FILE_ATTRIBUTE_NORMAL, // file attributes
+ NULL // handle to template file
+ );
+
+ if(TheFile == INVALID_HANDLE_VALUE)
+ {
+ Fail("ERROR: Tried to open a file that was created as "
+ "READONLY with the GENERIC_READ access mode. This should"
+ " cause CreateFile to return an valid handle, but "
+ "INVALID_HANDLE_VALUE was returned!.");
+ }
+
+ /* Close that HANDLE */
+
+ TheResult = CloseHandle(TheFile);
+
+ if(TheResult == 0)
+ {
+ Fail("ERROR: CloseHandle failed. This tests relies upon it "
+ "working properly.");
+ }
+
+ /* Set the file to NORMAL */
+
+ TheResult = SetFileAttributesA(FileName, FILE_ATTRIBUTE_NORMAL);
+
+ if(TheResult == 0)
+ {
+ Fail("ERROR: SetFileAttributesA returned 0, failure, when trying "
+ "to set the FILE_ATTRIBUTE_NORMAL attribute.");
+ }
+
+ /* To ensure that the set worked correctly, try to open the file
+ with WRITE access again -- this time it should succeed.
+ */
+
+ TheFile = CreateFileA(
+ FileName, // file name
+ GENERIC_READ|GENERIC_WRITE, // access mode
+ 0, // share mode
+ NULL, // SD
+ OPEN_ALWAYS, // how to create
+ FILE_ATTRIBUTE_NORMAL, // file attributes
+ NULL // handle to template file
+ );
+
+ if(TheFile == INVALID_HANDLE_VALUE)
+ {
+ Fail("ERROR: Tried to open a file that was created as "
+ "NORMAL with the GENERIC_WRITE access mode. This should"
+ " cause CreateFile to return an valid handle, but "
+ "INVALID_HANDLE_VALUE was returned!.");
+ }
+
+ TheResult = CloseHandle(TheFile);
+
+ if(TheResult == 0)
+ {
+ Fail("ERROR: CloseHandle failed. This tests relies upon it "
+ "working properly.");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/file_io/SetFileAttributesA/test1/test_file b/src/pal/tests/palsuite/file_io/SetFileAttributesA/test1/test_file
new file mode 100644
index 0000000000..1b4bcfe1b5
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetFileAttributesA/test1/test_file
@@ -0,0 +1 @@
+Don't delete me. I'm needed. The File. \ No newline at end of file
diff --git a/src/pal/tests/palsuite/file_io/SetFileAttributesA/test1/testinfo.dat b/src/pal/tests/palsuite/file_io/SetFileAttributesA/test1/testinfo.dat
new file mode 100644
index 0000000000..e39eac71b4
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetFileAttributesA/test1/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = SetFileAttributesA
+Name = Test for SetFileAttributesA which tests READONLY and NORMAL attributes
+TYPE = DEFAULT
+EXE1 = setfileattributesa
+Description
+= Test the SetFileAttributesA function. Set a file as READONLY and
+= attempt to open it with WRITE access, to ensure that this doesn't work.
+= Then switch to NORMAL attributes, and try again -- it should work.
diff --git a/src/pal/tests/palsuite/file_io/SetFileAttributesA/test2/CMakeLists.txt b/src/pal/tests/palsuite/file_io/SetFileAttributesA/test2/CMakeLists.txt
new file mode 100644
index 0000000000..03445c1df0
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetFileAttributesA/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ SetFileAttributesA.c
+)
+
+add_executable(paltest_setfileattributesa_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_setfileattributesa_test2 coreclrpal)
+
+target_link_libraries(paltest_setfileattributesa_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/SetFileAttributesA/test2/SetFileAttributesA.c b/src/pal/tests/palsuite/file_io/SetFileAttributesA/test2/SetFileAttributesA.c
new file mode 100644
index 0000000000..5c04a6b181
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetFileAttributesA/test2/SetFileAttributesA.c
@@ -0,0 +1,114 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: SetFileAttributesA.c
+**
+**
+** Purpose: Tests the PAL implementation of the SetFileAttributesA function
+** Test that we can set the defined attributes aside from READONLY on a
+** file, and that it doesn't return failure. Note, these attributes won't
+** do anything to the file, however.
+**
+**
+**===================================================================*/
+
+
+#include <palsuite.h>
+
+/* this cleanup method tries to revert the file back to its initial attributes */
+void do_cleanup(char* filename, DWORD attributes)
+{
+ DWORD result;
+ result = SetFileAttributesA(filename, attributes);
+ if (result == 0)
+ {
+ Fail("ERROR:SetFileAttributesA returned 0,failure in the do_cleanup "
+ "method when trying to revert the file back to its initial attributes (%u)", GetLastError());
+ }
+}
+
+int __cdecl main(int argc, char **argv)
+{
+ DWORD TheResult;
+ DWORD initialAttr;
+
+ char* FileName = {"test_file"};
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ // Create the test file
+ FILE *testFile = fopen(FileName, "w");
+ if (testFile == NULL)
+ {
+ Fail("Unexpected error: Unable to open file %S with fopen. \n", FileName);
+ }
+ if (fputs("testing", testFile) == EOF)
+ {
+ Fail("Unexpected error: Unable to write to file %S with fputs. \n", FileName);
+ }
+ if (fclose(testFile) != 0)
+ {
+ Fail("Unexpected error: Unable to close file %S with fclose. \n", FileName);
+ }
+ testFile = NULL;
+
+ /* Get the initial attributes of the file */
+
+ initialAttr = GetFileAttributesA(FileName);
+
+ /* Try to set the file to HIDDEN */
+
+ TheResult = SetFileAttributesA(FileName, FILE_ATTRIBUTE_HIDDEN);
+
+ if(TheResult == 0)
+ {
+ do_cleanup(FileName,initialAttr);
+ Fail("ERROR: SetFileAttributesA returned 0, failure, when trying "
+ "to set the FILE_ATTRIBUTE_HIDDEN attribute. This should "
+ "not do anything in FreeBSD, but it shouldn't fail.");
+ }
+
+ /* Try to set the file to ARCHIVE */
+
+ TheResult = SetFileAttributesA(FileName, FILE_ATTRIBUTE_ARCHIVE);
+
+ if(TheResult == 0)
+ {
+ do_cleanup(FileName,initialAttr);
+ Fail("ERROR: SetFileAttributesA returned 0, failure, when trying "
+ "to set the FILE_ATTRIBUTE_ARCHIVE attribute.");
+ }
+
+ /* Try to set the file to SYSTEM */
+
+ TheResult = SetFileAttributesA(FileName, FILE_ATTRIBUTE_SYSTEM);
+
+ if(TheResult == 0)
+ {
+ do_cleanup(FileName,initialAttr);
+ Fail("ERROR: SetFileAttributesA returned 0, failure, when trying "
+ "to set the FILE_ATTRIBUTE_SYSTEM attribute.");
+ }
+
+ /* Try to set the file to DIRECTORY */
+
+ TheResult = SetFileAttributesA(FileName, FILE_ATTRIBUTE_DIRECTORY);
+
+ if(TheResult == 0)
+ {
+ do_cleanup(FileName,initialAttr);
+ Fail("ERROR: SetFileAttributesA returned 0, failure, when trying "
+ "to set the FILE_ATTRIBUTE_DIRECTORY attribute.");
+ }
+
+
+ do_cleanup(FileName,initialAttr);
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/file_io/SetFileAttributesA/test2/test_file b/src/pal/tests/palsuite/file_io/SetFileAttributesA/test2/test_file
new file mode 100644
index 0000000000..18d630a34d
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetFileAttributesA/test2/test_file
@@ -0,0 +1 @@
+The File. \ No newline at end of file
diff --git a/src/pal/tests/palsuite/file_io/SetFileAttributesA/test2/testinfo.dat b/src/pal/tests/palsuite/file_io/SetFileAttributesA/test2/testinfo.dat
new file mode 100644
index 0000000000..778335258d
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetFileAttributesA/test2/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = SetFileAttributesA
+Name = smoke test for SetFileAttributesA
+TYPE = DEFAULT
+EXE1 = setfileattributesa
+Description
+= Test the SetFileAttributesA function
+= Try to set the attributes that are not valid in FreeBSD. These should
+= return success in either WIN32 or FreeBSD, just have no effect in FreeBSD.
diff --git a/src/pal/tests/palsuite/file_io/SetFileAttributesA/test3/CMakeLists.txt b/src/pal/tests/palsuite/file_io/SetFileAttributesA/test3/CMakeLists.txt
new file mode 100644
index 0000000000..3c35172d7c
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetFileAttributesA/test3/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ SetFileAttributesA.c
+)
+
+add_executable(paltest_setfileattributesa_test3
+ ${SOURCES}
+)
+
+add_dependencies(paltest_setfileattributesa_test3 coreclrpal)
+
+target_link_libraries(paltest_setfileattributesa_test3
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/SetFileAttributesA/test3/SetFileAttributesA.c b/src/pal/tests/palsuite/file_io/SetFileAttributesA/test3/SetFileAttributesA.c
new file mode 100644
index 0000000000..445b515c7f
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetFileAttributesA/test3/SetFileAttributesA.c
@@ -0,0 +1,48 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: SetFileAttributesA.c
+**
+**
+** Purpose: Tests the PAL implementation of the SetFileAttributesA function
+** Test that the function fails if the file doesn't exist..
+**
+**
+**===================================================================*/
+
+
+#include <palsuite.h>
+
+
+int __cdecl main(int argc, char **argv)
+{
+ DWORD TheResult;
+ char* FileName = {"no_file"};
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+
+ /* Try to set the file to NORMAL on a file that doesn't
+ exist.
+ */
+
+ TheResult = SetFileAttributesA(FileName, FILE_ATTRIBUTE_NORMAL);
+
+ if(TheResult != 0)
+ {
+ Fail("ERROR: SetFileAttributesA returned non-zero0, success, when"
+ " trying to set the FILE_ATTRIBUTE_NORMAL attribute on a non "
+ "existant file. This should fail.");
+ }
+
+
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/file_io/SetFileAttributesA/test3/testinfo.dat b/src/pal/tests/palsuite/file_io/SetFileAttributesA/test3/testinfo.dat
new file mode 100644
index 0000000000..33a4b03d64
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetFileAttributesA/test3/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = SetFileAttributesA
+Name = Test SetFileAttributesA on an invalid file
+TYPE = DEFAULT
+EXE1 = setfileattributesa
+Description
+= Test the SetFileAttributesA function
+= Try the function on a file that doesn't exist. It should fail.
diff --git a/src/pal/tests/palsuite/file_io/SetFileAttributesA/test4/CMakeLists.txt b/src/pal/tests/palsuite/file_io/SetFileAttributesA/test4/CMakeLists.txt
new file mode 100644
index 0000000000..f30969ad04
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetFileAttributesA/test4/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ SetFileAttributesA.c
+)
+
+add_executable(paltest_setfileattributesa_test4
+ ${SOURCES}
+)
+
+add_dependencies(paltest_setfileattributesa_test4 coreclrpal)
+
+target_link_libraries(paltest_setfileattributesa_test4
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/SetFileAttributesA/test4/SetFileAttributesA.c b/src/pal/tests/palsuite/file_io/SetFileAttributesA/test4/SetFileAttributesA.c
new file mode 100644
index 0000000000..240e89ff6f
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetFileAttributesA/test4/SetFileAttributesA.c
@@ -0,0 +1,128 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: SetFileAttributesA.c
+**
+**
+** Purpose: Tests the PAL implementation of the SetFileAttributesA function
+** Check that using two flags (READONLY and NORMAL) only sets the file
+** as READONLY, as MSDN notes that everything else overrides NORMAL.
+**
+** Depends:
+** CreateFileA
+** CloseHandle
+**
+**
+**===================================================================*/
+
+
+#include <palsuite.h>
+
+
+
+int __cdecl main(int argc, char **argv)
+{
+ DWORD TheResult;
+ HANDLE TheFile;
+ char* FileName = {"test_file"};
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ // Create the test file
+ FILE *testFile = fopen(FileName, "w");
+ if (testFile == NULL)
+ {
+ Fail("Unexpected error: Unable to open file %S with fopen. \n", FileName);
+ }
+ if (fputs("testing", testFile) == EOF)
+ {
+ Fail("Unexpected error: Unable to write to file %S with fputs. \n", FileName);
+ }
+ if (fclose(testFile) != 0)
+ {
+ Fail("Unexpected error: Unable to close file %S with fclose. \n", FileName);
+ }
+ testFile = NULL;
+
+ /* Try to set the file to Read-only|Normal ... It should
+ end up as Readonly, since this overrides Normal*/
+
+ TheResult = SetFileAttributesA(FileName,
+ FILE_ATTRIBUTE_NORMAL|
+ FILE_ATTRIBUTE_READONLY);
+
+ if(TheResult == 0)
+ {
+ Fail("ERROR: SetFileAttributesA returned 0, failure, when trying "
+ "to set the FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_NORMAL "
+ "attribute.");
+ }
+
+ /* Attempt to open this READONLY file with WRITE access,
+ The open should fail and the HANDLE should be invalid.
+ */
+
+ TheFile = CreateFileA(
+ FileName, // file name
+ GENERIC_READ|GENERIC_WRITE, // access mode
+ 0, // share mode
+ NULL, // SD
+ OPEN_ALWAYS, // how to create
+ FILE_ATTRIBUTE_NORMAL, // file attributes
+ NULL // handle to template file
+ );
+
+ if(TheFile != INVALID_HANDLE_VALUE)
+ {
+ TheResult = CloseHandle(TheFile);
+ if(TheResult == 0)
+ {
+ Trace("ERROR: CloseHandle failed. This tests relies upon it "
+ "working properly.");
+ }
+ Fail("ERROR: Tried to open a file that was created as "
+ "READONLY with the GENERIC_WRITE access mode. This should"
+ " cause CreateFileA to return an INVALID_HANDLE_VALUE.");
+ }
+
+ /* Try to open the file with READ access, this should be ok.
+ The HANDLE will be valid.
+ */
+
+ TheFile = CreateFileA(
+ FileName, // file name
+ GENERIC_READ, // access mode
+ 0, // share mode
+ NULL, // SD
+ OPEN_ALWAYS, // how to create
+ FILE_ATTRIBUTE_NORMAL, // file attributes
+ NULL // handle to template file
+ );
+
+ if(TheFile == INVALID_HANDLE_VALUE)
+ {
+ Fail("ERROR: Tried to open a file that was created as "
+ "READONLY with the GENERIC_READ access mode. This should"
+ " cause CreateFileA to return an valid handle, but "
+ "INVALID_HANDLE_VALUE was returned!.");
+ }
+
+ /* Close that HANDLE */
+
+ TheResult = CloseHandle(TheFile);
+
+ if(TheResult == 0)
+ {
+ Fail("ERROR: CloseHandle failed. This tests relies upon it "
+ "working properly.");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/file_io/SetFileAttributesA/test4/test_file b/src/pal/tests/palsuite/file_io/SetFileAttributesA/test4/test_file
new file mode 100644
index 0000000000..1b4bcfe1b5
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetFileAttributesA/test4/test_file
@@ -0,0 +1 @@
+Don't delete me. I'm needed. The File. \ No newline at end of file
diff --git a/src/pal/tests/palsuite/file_io/SetFileAttributesA/test4/testinfo.dat b/src/pal/tests/palsuite/file_io/SetFileAttributesA/test4/testinfo.dat
new file mode 100644
index 0000000000..d8df0625bc
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetFileAttributesA/test4/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = SetFileAttributesA
+Name = Tests SetFileAttributesA properly overrides NORMAL
+TYPE = DEFAULT
+EXE1 = setfileattributesa
+Description
+= Test the SetFileAttributesA function. Check that using two flags
+= (READONLY and NORMAL) only sets the file as READONLY, as MSDN
+= notes that everything else overrides NORMAL.
diff --git a/src/pal/tests/palsuite/file_io/SetFileAttributesW/CMakeLists.txt b/src/pal/tests/palsuite/file_io/SetFileAttributesW/CMakeLists.txt
new file mode 100644
index 0000000000..a3847f8ca9
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetFileAttributesW/CMakeLists.txt
@@ -0,0 +1,7 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+add_subdirectory(test3)
+add_subdirectory(test4)
+
diff --git a/src/pal/tests/palsuite/file_io/SetFileAttributesW/test1/CMakeLists.txt b/src/pal/tests/palsuite/file_io/SetFileAttributesW/test1/CMakeLists.txt
new file mode 100644
index 0000000000..35927b4b1d
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetFileAttributesW/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ SetFileAttributesW.c
+)
+
+add_executable(paltest_setfileattributesw_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_setfileattributesw_test1 coreclrpal)
+
+target_link_libraries(paltest_setfileattributesw_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/SetFileAttributesW/test1/SetFileAttributesW.c b/src/pal/tests/palsuite/file_io/SetFileAttributesW/test1/SetFileAttributesW.c
new file mode 100644
index 0000000000..753c396d1f
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetFileAttributesW/test1/SetFileAttributesW.c
@@ -0,0 +1,167 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: SetFileAttributesW.c
+**
+** Purpose: Tests the PAL implementation of the SetFileAttributesW function
+** Test that we can set a file READONLY, and then that we're unable to
+** open that file with WRITE access. Then change it to NORMAL attributes, and
+** try to open it again -- it should work now.
+**
+** Depends:
+** CreateFile
+** CloseHandle
+**
+**
+**===================================================================*/
+
+/* According to the spec, only READONLY attribute can be set
+ in FreeBSD.
+*/
+
+#define UNICODE
+
+#include <palsuite.h>
+
+
+
+int __cdecl main(int argc, char **argv)
+{
+ DWORD TheResult;
+ HANDLE TheFile;
+ CHAR *FileName_Multibyte = "test_file";
+ WCHAR FileName[MAX_PATH];
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ // Create the test file
+ FILE *testFile = fopen(FileName_Multibyte, "w");
+ if (testFile == NULL)
+ {
+ Fail("Unexpected error: Unable to open file %S with fopen. \n", FileName);
+ }
+ if (fputs("testing", testFile) == EOF)
+ {
+ Fail("Unexpected error: Unable to write to file %S with fputs. \n", FileName);
+ }
+ if (fclose(testFile) != 0)
+ {
+ Fail("Unexpected error: Unable to close file %S with fclose. \n", FileName);
+ }
+ testFile = NULL;
+
+ /* Make a wide character string for the file name */
+
+ MultiByteToWideChar(CP_ACP,
+ 0,
+ FileName_Multibyte,
+ -1,
+ FileName,
+ MAX_PATH);
+
+
+ /* Try to set the file to Read-only */
+
+ TheResult = SetFileAttributes(FileName,FILE_ATTRIBUTE_READONLY);
+
+ if(TheResult == 0)
+ {
+ Fail("ERROR: SetFileAttributes returned 0, failure, when trying "
+ "to set the FILE_ATTRIBUTE_READONLY attribute.");
+ }
+
+ /* Attempt to open this READONLY file with WRITE access,
+ The open should fail and the HANDLE should be invalid.
+ */
+
+ TheFile = CreateFile(
+ FileName, // file name
+ GENERIC_READ|GENERIC_WRITE, // access mode
+ 0, // share mode
+ NULL, // SD
+ OPEN_ALWAYS, // how to create
+ FILE_ATTRIBUTE_NORMAL, // file attributes
+ NULL // handle to template file
+ );
+
+ if(TheFile != INVALID_HANDLE_VALUE)
+ {
+ Fail("ERROR: Tried to open a file that was created as "
+ "READONLY with the GENERIC_WRITE access mode. This should"
+ " cause CreateFile to return an INVALID_HANDLE_VALUE.");
+ }
+
+ /* Try to open the file with READ access, this should be ok.
+ The HANDLE will be valid.
+ */
+
+ TheFile = CreateFile(
+ FileName, // file name
+ GENERIC_READ, // access mode
+ 0, // share mode
+ NULL, // SD
+ OPEN_ALWAYS, // how to create
+ FILE_ATTRIBUTE_NORMAL, // file attributes
+ NULL // handle to template file
+ );
+
+ if(TheFile == INVALID_HANDLE_VALUE)
+ {
+ Fail("ERROR: Tried to open a file that was created as "
+ "READONLY with the GENERIC_READ access mode. This should"
+ " cause CreateFile to return an valid handle, but "
+ "INVALID_HANDLE_VALUE was returned!.");
+ }
+
+ /* Close that HANDLE */
+
+ TheResult = CloseHandle(TheFile);
+
+ if(TheResult == 0)
+ {
+ Fail("ERROR: CloseHandle failed. This tests relies upon it "
+ "working properly.");
+ }
+
+ /* Set the file to NORMAL */
+
+ TheResult = SetFileAttributes(FileName,FILE_ATTRIBUTE_NORMAL);
+
+ if(TheResult == 0)
+ {
+ Fail("ERROR: SetFileAttributes returned 0, failure, when trying "
+ "to set the FILE_ATTRIBUTE_NORMAL attribute.");
+ }
+
+ /* To ensure that the set worked correctly, try to open the file
+ with WRITE access again -- this time it should succeed.
+ */
+
+ TheFile = CreateFile(
+ FileName, // file name
+ GENERIC_READ|GENERIC_WRITE, // access mode
+ 0, // share mode
+ NULL, // SD
+ OPEN_ALWAYS, // how to create
+ FILE_ATTRIBUTE_NORMAL, // file attributes
+ NULL // handle to template file
+ );
+
+ if(TheFile == INVALID_HANDLE_VALUE)
+ {
+ Fail("ERROR: Tried to open a file that was created as "
+ "NORMAL with the GENERIC_WRITE access mode. This should"
+ " cause CreateFile to return an valid handle, but "
+ "INVALID_HANDLE_VALUE was returned!.");
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/file_io/SetFileAttributesW/test1/test_file b/src/pal/tests/palsuite/file_io/SetFileAttributesW/test1/test_file
new file mode 100644
index 0000000000..1b4bcfe1b5
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetFileAttributesW/test1/test_file
@@ -0,0 +1 @@
+Don't delete me. I'm needed. The File. \ No newline at end of file
diff --git a/src/pal/tests/palsuite/file_io/SetFileAttributesW/test1/testinfo.dat b/src/pal/tests/palsuite/file_io/SetFileAttributesW/test1/testinfo.dat
new file mode 100644
index 0000000000..75cdc3b719
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetFileAttributesW/test1/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = SetFileAttributesW
+Name = Positive Test for SetFileAttributesW
+TYPE = DEFAULT
+EXE1 = setfileattributesw
+Description
+= Test the SetFileAttributesW function. Set a file as READONLY and
+= attempt to open it with WRITE access, to ensure that this doesn't work.
+= Then switch to NORMAL attributes, and try again -- it should work.
diff --git a/src/pal/tests/palsuite/file_io/SetFileAttributesW/test2/CMakeLists.txt b/src/pal/tests/palsuite/file_io/SetFileAttributesW/test2/CMakeLists.txt
new file mode 100644
index 0000000000..81fa02c1dd
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetFileAttributesW/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ SetFileAttributesW.c
+)
+
+add_executable(paltest_setfileattributesw_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_setfileattributesw_test2 coreclrpal)
+
+target_link_libraries(paltest_setfileattributesw_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/SetFileAttributesW/test2/SetFileAttributesW.c b/src/pal/tests/palsuite/file_io/SetFileAttributesW/test2/SetFileAttributesW.c
new file mode 100644
index 0000000000..f657436845
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetFileAttributesW/test2/SetFileAttributesW.c
@@ -0,0 +1,121 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: SetFileAttributesW.c
+**
+** Purpose: Tests the PAL implementation of the SetFileAttributesW function
+** Test that we can set the defined attributes aside from READONLY on a
+** file, and that it doesn't return failure. Note, these attributes won't
+** do anything to the file, however.
+**
+**
+**===================================================================*/
+
+#define UNICODE
+
+#include <palsuite.h>
+
+/* this cleanup method tries to revert the file back to its initial attributes */
+void do_cleanup(WCHAR* filename, DWORD attributes)
+{
+ DWORD result;
+ result = SetFileAttributes(filename, attributes);
+ if (result == 0)
+ {
+ Fail("ERROR:SetFileAttributesW returned 0,failure in the do_cleanup "
+ "method when trying to revert the file back to its initial attributes (%u)", GetLastError());
+ }
+}
+
+int __cdecl main(int argc, char **argv)
+{
+ DWORD TheResult;
+ DWORD initialAttr;
+ CHAR *FileName_Multibyte = "test_file";
+ WCHAR FileName[MAX_PATH];
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ // Create the test file
+ FILE *testFile = fopen(FileName_Multibyte, "w");
+ if (testFile == NULL)
+ {
+ Fail("Unexpected error: Unable to open file %S with fopen. \n", FileName);
+ }
+ if (fputs("testing", testFile) == EOF)
+ {
+ Fail("Unexpected error: Unable to write to file %S with fputs. \n", FileName);
+ }
+ if (fclose(testFile) != 0)
+ {
+ Fail("Unexpected error: Unable to close file %S with fclose. \n", FileName);
+ }
+ testFile = NULL;
+
+ /* Make a wide character string for the file name */
+
+ MultiByteToWideChar(CP_ACP,
+ 0,
+ FileName_Multibyte,
+ -1,
+ FileName,
+ MAX_PATH);
+
+ /* Get the initial attributes of the file */
+ initialAttr = GetFileAttributesW(FileName);
+
+ /* Try to set the file to HIDDEN */
+
+ TheResult = SetFileAttributes(FileName,FILE_ATTRIBUTE_HIDDEN);
+
+ if(TheResult == 0)
+ {
+ do_cleanup(FileName,initialAttr);
+ Fail("ERROR: SetFileAttributes returned 0, failure, when trying "
+ "to set the FILE_ATTRIBUTE_HIDDEN attribute. This should "
+ "not do anything in FreeBSD, but it shouldn't fail.");
+ }
+
+ /* Try to set the file to ARCHIVE */
+
+ TheResult = SetFileAttributes(FileName,FILE_ATTRIBUTE_ARCHIVE);
+
+ if(TheResult == 0)
+ {
+ do_cleanup(FileName,initialAttr);
+ Fail("ERROR: SetFileAttributes returned 0, failure, when trying "
+ "to set the FILE_ATTRIBUTE_ARCHIVE attribute.");
+ }
+
+ /* Try to set the file to SYSTEM */
+
+ TheResult = SetFileAttributes(FileName,FILE_ATTRIBUTE_SYSTEM);
+
+ if(TheResult == 0)
+ {
+ do_cleanup(FileName,initialAttr);
+ Fail("ERROR: SetFileAttributes returned 0, failure, when trying "
+ "to set the FILE_ATTRIBUTE_SYSTEM attribute.");
+ }
+
+ /* Try to set the file to DIRECTORY */
+
+ TheResult = SetFileAttributes(FileName,FILE_ATTRIBUTE_DIRECTORY);
+
+ if(TheResult == 0)
+ {
+ do_cleanup(FileName,initialAttr);
+ Fail("ERROR: SetFileAttributes returned 0, failure, when trying "
+ "to set the FILE_ATTRIBUTE_DIRECTORY attribute.");
+ }
+
+ do_cleanup(FileName,initialAttr);
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/file_io/SetFileAttributesW/test2/test_file b/src/pal/tests/palsuite/file_io/SetFileAttributesW/test2/test_file
new file mode 100644
index 0000000000..18d630a34d
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetFileAttributesW/test2/test_file
@@ -0,0 +1 @@
+The File. \ No newline at end of file
diff --git a/src/pal/tests/palsuite/file_io/SetFileAttributesW/test2/testinfo.dat b/src/pal/tests/palsuite/file_io/SetFileAttributesW/test2/testinfo.dat
new file mode 100644
index 0000000000..e3161a9bd6
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetFileAttributesW/test2/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = SetFileAttributesW
+Name = Positive Test for SetFileAttributesW
+TYPE = DEFAULT
+EXE1 = setfileattributesw
+Description
+= Test the SetFileAttributesW function
+= Try to set the attributes that are not valid in FreeBSD. These should
+= return success in either WIN32 or FreeBSD, just have no effect in FreeBSD.
diff --git a/src/pal/tests/palsuite/file_io/SetFileAttributesW/test3/CMakeLists.txt b/src/pal/tests/palsuite/file_io/SetFileAttributesW/test3/CMakeLists.txt
new file mode 100644
index 0000000000..c2cdacb0d0
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetFileAttributesW/test3/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ SetFileAttributesW.c
+)
+
+add_executable(paltest_setfileattributesw_test3
+ ${SOURCES}
+)
+
+add_dependencies(paltest_setfileattributesw_test3 coreclrpal)
+
+target_link_libraries(paltest_setfileattributesw_test3
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/SetFileAttributesW/test3/SetFileAttributesW.c b/src/pal/tests/palsuite/file_io/SetFileAttributesW/test3/SetFileAttributesW.c
new file mode 100644
index 0000000000..8a8bafac68
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetFileAttributesW/test3/SetFileAttributesW.c
@@ -0,0 +1,57 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: SetFileAttributesW.c
+**
+** Purpose: Tests the PAL implementation of the SetFileAttributesW function
+** Test that the function fails if the file doesn't exist..
+**
+**
+**===================================================================*/
+
+#define UNICODE
+
+#include <palsuite.h>
+
+
+int __cdecl main(int argc, char **argv)
+{
+ DWORD TheResult;
+ WCHAR FileName[MAX_PATH];
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ /* Make a wide character string for the file name */
+
+ MultiByteToWideChar(CP_ACP,
+ 0,
+ "no_file",
+ -1,
+ FileName,
+ MAX_PATH);
+
+
+ /* Try to set the file to NORMAL on a file that doesn't
+ exist.
+ */
+
+ TheResult = SetFileAttributes(FileName,FILE_ATTRIBUTE_NORMAL);
+
+ if(TheResult != 0)
+ {
+ Fail("ERROR: SetFileAttributes returned non-zero0, success, when"
+ " trying to set the FILE_ATTRIBUTE_NORMAL attribute on a non "
+ "existant file. This should fail.");
+ }
+
+
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/file_io/SetFileAttributesW/test3/testinfo.dat b/src/pal/tests/palsuite/file_io/SetFileAttributesW/test3/testinfo.dat
new file mode 100644
index 0000000000..4b264898df
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetFileAttributesW/test3/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = SetFileAttributesW
+Name = Positive Test for SetFileAttributesW
+TYPE = DEFAULT
+EXE1 = setfileattributesw
+Description
+= Test the SetFileAttributesW function
+= Try the function on a file that doesn't exist. It should fail.
diff --git a/src/pal/tests/palsuite/file_io/SetFileAttributesW/test4/CMakeLists.txt b/src/pal/tests/palsuite/file_io/SetFileAttributesW/test4/CMakeLists.txt
new file mode 100644
index 0000000000..6a4aa8adc3
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetFileAttributesW/test4/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ SetFileAttributesW.c
+)
+
+add_executable(paltest_setfileattributesw_test4
+ ${SOURCES}
+)
+
+add_dependencies(paltest_setfileattributesw_test4 coreclrpal)
+
+target_link_libraries(paltest_setfileattributesw_test4
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/SetFileAttributesW/test4/SetFileAttributesW.c b/src/pal/tests/palsuite/file_io/SetFileAttributesW/test4/SetFileAttributesW.c
new file mode 100644
index 0000000000..bebadfa264
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetFileAttributesW/test4/SetFileAttributesW.c
@@ -0,0 +1,133 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: SetFileAttributesW.c
+**
+** Purpose: Tests the PAL implementation of the SetFileAttributesW function
+** Check that using two flags (READONLY and NORMAL) only sets the file
+** as READONLY, as MSDN notes that everything else overrides NORMAL.
+**
+** Depends:
+** CreateFile
+** CloseHandle
+**
+**
+**===================================================================*/
+
+#define UNICODE
+
+#include <palsuite.h>
+
+
+
+int __cdecl main(int argc, char **argv)
+{
+ DWORD TheResult;
+ HANDLE TheFile;
+ CHAR *FileName_Multibyte = "test_file";
+ WCHAR FileName[MAX_PATH];
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ // Create the test file
+ FILE *testFile = fopen(FileName_Multibyte, "w");
+ if (testFile == NULL)
+ {
+ Fail("Unexpected error: Unable to open file %S with fopen. \n", FileName);
+ }
+ if (fputs("testing", testFile) == EOF)
+ {
+ Fail("Unexpected error: Unable to write to file %S with fputs. \n", FileName);
+ }
+ if (fclose(testFile) != 0)
+ {
+ Fail("Unexpected error: Unable to close file %S with fclose. \n", FileName);
+ }
+ testFile = NULL;
+
+ /* Make a wide character string for the file name */
+
+ MultiByteToWideChar(CP_ACP,
+ 0,
+ FileName_Multibyte,
+ -1,
+ FileName,
+ MAX_PATH);
+
+
+ /* Try to set the file to Read-only|Normal ... It should
+ end up as Readonly, since this overrides Normal*/
+
+ TheResult = SetFileAttributes(FileName,
+ FILE_ATTRIBUTE_NORMAL|
+ FILE_ATTRIBUTE_READONLY);
+
+ if(TheResult == 0)
+ {
+ Fail("ERROR: SetFileAttributes returned 0, failure, when trying "
+ "to set the FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_NORMAL "
+ "attribute.");
+ }
+
+ /* Attempt to open this READONLY file with WRITE access,
+ The open should fail and the HANDLE should be invalid.
+ */
+
+ TheFile = CreateFile(
+ FileName, // file name
+ GENERIC_READ|GENERIC_WRITE, // access mode
+ 0, // share mode
+ NULL, // SD
+ OPEN_ALWAYS, // how to create
+ FILE_ATTRIBUTE_NORMAL, // file attributes
+ NULL // handle to template file
+ );
+
+ if(TheFile != INVALID_HANDLE_VALUE)
+ {
+ Fail("ERROR: Tried to open a file that was created as "
+ "READONLY with the GENERIC_WRITE access mode. This should"
+ " cause CreateFile to return an INVALID_HANDLE_VALUE.");
+ }
+
+ /* Try to open the file with READ access, this should be ok.
+ The HANDLE will be valid.
+ */
+
+ TheFile = CreateFile(
+ FileName, // file name
+ GENERIC_READ, // access mode
+ 0, // share mode
+ NULL, // SD
+ OPEN_ALWAYS, // how to create
+ FILE_ATTRIBUTE_NORMAL, // file attributes
+ NULL // handle to template file
+ );
+
+ if(TheFile == INVALID_HANDLE_VALUE)
+ {
+ Fail("ERROR: Tried to open a file that was created as "
+ "READONLY with the GENERIC_READ access mode. This should"
+ " cause CreateFile to return an valid handle, but "
+ "INVALID_HANDLE_VALUE was returned!.");
+ }
+
+ /* Close that HANDLE */
+
+ TheResult = CloseHandle(TheFile);
+
+ if(TheResult == 0)
+ {
+ Fail("ERROR: CloseHandle failed. This tests relies upon it "
+ "working properly.");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/file_io/SetFileAttributesW/test4/test_file b/src/pal/tests/palsuite/file_io/SetFileAttributesW/test4/test_file
new file mode 100644
index 0000000000..1b4bcfe1b5
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetFileAttributesW/test4/test_file
@@ -0,0 +1 @@
+Don't delete me. I'm needed. The File. \ No newline at end of file
diff --git a/src/pal/tests/palsuite/file_io/SetFileAttributesW/test4/testinfo.dat b/src/pal/tests/palsuite/file_io/SetFileAttributesW/test4/testinfo.dat
new file mode 100644
index 0000000000..75cdc3b719
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetFileAttributesW/test4/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = SetFileAttributesW
+Name = Positive Test for SetFileAttributesW
+TYPE = DEFAULT
+EXE1 = setfileattributesw
+Description
+= Test the SetFileAttributesW function. Set a file as READONLY and
+= attempt to open it with WRITE access, to ensure that this doesn't work.
+= Then switch to NORMAL attributes, and try again -- it should work.
diff --git a/src/pal/tests/palsuite/file_io/SetFilePointer/CMakeLists.txt b/src/pal/tests/palsuite/file_io/SetFilePointer/CMakeLists.txt
new file mode 100644
index 0000000000..19ee487a6a
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetFilePointer/CMakeLists.txt
@@ -0,0 +1,10 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+add_subdirectory(test3)
+add_subdirectory(test4)
+add_subdirectory(test5)
+add_subdirectory(test6)
+add_subdirectory(test7)
+
diff --git a/src/pal/tests/palsuite/file_io/SetFilePointer/test1/CMakeLists.txt b/src/pal/tests/palsuite/file_io/SetFilePointer/test1/CMakeLists.txt
new file mode 100644
index 0000000000..e352449981
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetFilePointer/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ SetFilePointer.c
+)
+
+add_executable(paltest_setfilepointer_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_setfilepointer_test1 coreclrpal)
+
+target_link_libraries(paltest_setfilepointer_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/SetFilePointer/test1/SetFilePointer.c b/src/pal/tests/palsuite/file_io/SetFilePointer/test1/SetFilePointer.c
new file mode 100644
index 0000000000..14b5f85e69
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetFilePointer/test1/SetFilePointer.c
@@ -0,0 +1,123 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: SetFilePointer.c (test 1)
+**
+** Purpose: Tests the PAL implementation of the SetFilePointer function.
+** Set the file pointer using a NULL handle and other invalid
+** options.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+
+const char* szTextFile = "text.txt";
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ HANDLE hFile = NULL;
+ DWORD dwByteCount = 0;
+ DWORD dwOffset = 25;
+ DWORD dwRc = 0;
+ BOOL bRc = FALSE;
+ char buffer[100];
+
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ /* set the file pointer on a NULL file handle */
+ dwRc = SetFilePointer(NULL, dwOffset, NULL, FILE_BEGIN);
+ if (dwRc != INVALID_SET_FILE_POINTER)
+ {
+ Fail("SetFilePointer: ERROR -> Call to SetFilePointer succeeded "
+ "with a NULL pointer\n");
+ }
+
+
+ /* create a test file without proper permission */
+ hFile = CreateFile(szTextFile,
+ 0,
+ 0,
+ NULL,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if(hFile == INVALID_HANDLE_VALUE)
+ {
+ Fail("SetFilePointer: ERROR -> Unable to create file \"%s\".\n",
+ szTextFile);
+ }
+
+ /* ReadFile fails as expected */
+ bRc = ReadFile(hFile, buffer, 1, &dwByteCount, NULL);
+ if (bRc != FALSE)
+ {
+ Trace("SetFilePointer: ERROR -> ReadFile was successful when it was "
+ "expected to fail\n");
+ if (!CloseHandle(hFile))
+ {
+ Trace("SetFilePointer: ERROR -> Unable to close file \"%s\".\n",
+ szTextFile);
+ }
+ if (!DeleteFileA(szTextFile))
+ {
+ Trace("SetFilePointer: ERROR -> Unable to delete file \"%s\".\n",
+ szTextFile);
+ }
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+
+ /* move the file pointer before the beginning of the file */
+ dwRc = SetFilePointer(hFile, -1, NULL, FILE_BEGIN);
+ if (dwRc != INVALID_SET_FILE_POINTER)
+ {
+ Trace("SetFilePointer: ERROR -> Was able to move the pointer before "
+ "the beginning of the file.\n");
+ bRc = CloseHandle(hFile);
+ if (bRc != TRUE)
+ {
+ Trace("SetFilePointer: ERROR -> Unable to close file \"%s\".\n",
+ szTextFile);
+ }
+ if (!DeleteFileA(szTextFile))
+ {
+ Trace("SetFilePointer: ERROR -> Unable to delete file \"%s\".\n",
+ szTextFile);
+ }
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+
+ bRc = CloseHandle(hFile);
+ if (bRc != TRUE)
+ {
+ Trace("SetFilePointer: ERROR -> Unable to close file \"%s\".\n",
+ szTextFile);
+ if (!DeleteFileA(szTextFile))
+ {
+ Trace("SetFilePointer: ERROR -> Unable to delete file \"%s\".\n",
+ szTextFile);
+ }
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+
+ if (!DeleteFileA(szTextFile))
+ {
+ Fail("SetFilePointer: ERROR -> Unable to delete file \"%s\".\n",
+ szTextFile);
+ }
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/file_io/SetFilePointer/test1/testinfo.dat b/src/pal/tests/palsuite/file_io/SetFilePointer/test1/testinfo.dat
new file mode 100644
index 0000000000..dfd4b6bd42
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetFilePointer/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = SetFilePointer
+Name = Test for SetFilePointer (test 1)
+Type = DEFAULT
+EXE1 = setfilepointer
+Description
+=Set the file pointer on a NULL file handle and other invalid options
+
diff --git a/src/pal/tests/palsuite/file_io/SetFilePointer/test2/CMakeLists.txt b/src/pal/tests/palsuite/file_io/SetFilePointer/test2/CMakeLists.txt
new file mode 100644
index 0000000000..290a01107f
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetFilePointer/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ SetFilePointer.c
+)
+
+add_executable(paltest_setfilepointer_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_setfilepointer_test2 coreclrpal)
+
+target_link_libraries(paltest_setfilepointer_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/SetFilePointer/test2/SetFilePointer.c b/src/pal/tests/palsuite/file_io/SetFilePointer/test2/SetFilePointer.c
new file mode 100644
index 0000000000..19e99a74b3
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetFilePointer/test2/SetFilePointer.c
@@ -0,0 +1,356 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: SetFilePointer.c (test 2)
+**
+** Purpose: Tests the PAL implementation of the SetFilePointer function.
+** Test the FILE_BEGIN option
+**
+** Assumes Successful:
+** CreateFile
+** ReadFile
+** WriteFile
+** strlen
+** CloseHandle
+** strcmp
+** GetFileSize
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+const char * const szText =
+ "The quick brown fox jumped over the lazy dog's back.";
+const char* szTextFile = "text.txt";
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ HANDLE hFile = NULL;
+ DWORD dwByteCount = 0;
+ DWORD dwRc = 0;
+ BOOL bRc = FALSE;
+ char szBuffer[100];
+ const char *szPtr;
+
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ /* create a test file */
+ hFile = CreateFile(szTextFile,
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if(hFile == INVALID_HANDLE_VALUE)
+ {
+ Fail("SetFilePointer: ERROR -> Unable to create file \"%s\".\n",
+ szTextFile);
+ }
+
+ bRc = WriteFile(hFile, szText, (DWORD)strlen(szText), &dwByteCount, NULL);
+ if (bRc == FALSE)
+ {
+ Trace("SetFilePointer: ERROR -> Unable to write to file \"%s\".\n",
+ szTextFile);
+ bRc = CloseHandle(hFile);
+ if (bRc != TRUE)
+ {
+ Trace("SetFilePointer: ERROR -> Unable to close file \"%s\".\n",
+ szTextFile);
+ }
+ if (!DeleteFileA(szTextFile))
+ {
+ Trace("SetFilePointer: ERROR -> Unable to delete file \"%s\".\n",
+ szTextFile);
+ }
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+
+
+ /* move -1 from beginning which should fail */
+ dwRc = SetFilePointer(hFile, -1, NULL, FILE_BEGIN);
+ if ((dwRc != INVALID_SET_FILE_POINTER) ||
+ (GetLastError() == ERROR_SUCCESS))
+ {
+ Trace("SetFilePointer: ERROR -> Succeeded to move the pointer "
+ "before the beginning of the file.\n");
+ bRc = CloseHandle(hFile);
+ if (bRc != TRUE)
+ {
+ Trace("SetFilePointer: ERROR -> Unable to close file \"%s\".\n",
+ szTextFile);
+ }
+ if (!DeleteFileA(szTextFile))
+ {
+ Trace("SetFilePointer: ERROR -> Unable to delete file \"%s\".\n",
+ szTextFile);
+ }
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+
+ /* move the file pointer 0 bytes from the beginning and verify */
+ dwRc = SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
+ if (dwRc != 0)
+ {
+ Trace("SetFilePointer: ERROR -> Asked to move 0 bytes from the "
+ "beginning of the file but moved %ld bytes.\n", dwRc);
+ bRc = CloseHandle(hFile);
+ if (bRc != TRUE)
+ {
+ Trace("SetFilePointer: ERROR -> Unable to close file \"%s\".\n",
+ szTextFile);
+ }
+ if (!DeleteFileA(szTextFile))
+ {
+ Trace("SetFilePointer: ERROR -> Unable to delete file \"%s\".\n",
+ szTextFile);
+ }
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+
+ /* move the pointer ahead in the file and verify */
+ dwRc = SetFilePointer(hFile, 20, NULL, FILE_BEGIN);
+ if (dwRc != 20)
+ {
+ Trace("SetFilePointer: ERROR -> Asked to move 0 bytes from the "
+ "beginning of the file but moved %ld bytes.\n", dwRc);
+ bRc = CloseHandle(hFile);
+ if (bRc != TRUE)
+ {
+ Trace("SetFilePointer: ERROR -> Unable to close file \"%s\".\n",
+ szTextFile);
+ }
+ if (!DeleteFileA(szTextFile))
+ {
+ Trace("SetFilePointer: ERROR -> Unable to delete file \"%s\".\n",
+ szTextFile);
+ }
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+ else
+ {
+ /* verify results */
+ memset(szBuffer, 0, 100);
+ bRc = ReadFile(hFile, szBuffer, (DWORD)strlen(szText)-20, &dwByteCount,
+ NULL);
+ if ((bRc != TRUE) || (dwByteCount != strlen(szText)-20))
+ {
+ Trace("SetFilePointer: ERROR -> ReadFile failed to read correctly");
+ bRc = CloseHandle(hFile);
+ if (bRc != TRUE)
+ {
+ Trace("SetFilePointer: ERROR -> Unable to close file"
+ "\"%s\".\n", szTextFile);
+ }
+ if (!DeleteFileA(szTextFile))
+ {
+ Trace("SetFilePointer: ERROR -> Unable to delete file"
+ "\"%s\".\n", szTextFile);
+ }
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+ szPtr = szText + 20;
+ if (strcmp(szPtr, szBuffer) != 0)
+ {
+ Trace("SetFilePointer: ERROR -> Apparently failed to move the "
+ "pointer properly\n");
+ bRc = CloseHandle(hFile);
+ if (bRc != TRUE)
+ {
+ Trace("SetFilePointer: ERROR -> Unable to close file"
+ " \"%s\".\n", szTextFile);
+ }
+ if (!DeleteFileA(szTextFile))
+ {
+ Trace("SetFilePointer: ERROR -> Unable to delete file"
+ " \"%s\".\n", szTextFile);
+ }
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+ }
+
+ /* move the file pointer back to the beginning and verify */
+ dwRc = SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
+ if (dwRc != 0)
+ {
+ Trace("SetFilePointer: ERROR -> Asked to move 0 bytes from the "
+ "beginning of the file but moved %ld bytes.\n", dwRc);
+ bRc = CloseHandle(hFile);
+ if (bRc != TRUE)
+ {
+ Trace("SetFilePointer: ERROR -> Unable to close file \"%s\".\n",
+ szTextFile);
+ }
+ if (!DeleteFileA(szTextFile))
+ {
+ Trace("SetFilePointer: ERROR -> Unable to delete file \"%s\".\n",
+ szTextFile);
+ }
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+ else
+ {
+ /* verify results */
+ memset(szBuffer, 0, 100);
+ bRc = ReadFile(hFile, szBuffer, (DWORD)strlen(szText), &dwByteCount,
+ NULL);
+ if ((bRc != TRUE) || (dwByteCount != strlen(szText)))
+ {
+ Trace("SetFilePointer: ERROR -> ReadFile failed to read correctly");
+ bRc = CloseHandle(hFile);
+ if (bRc != TRUE)
+ {
+ Trace("SetFilePointer: ERROR -> Unable to close file"
+ " \"%s\".\n", szTextFile);
+ }
+ if (!DeleteFileA(szTextFile))
+ {
+ Trace("SetFilePointer: ERROR -> Unable to delete file"
+ " \"%s\".\n", szTextFile);
+ }
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+ if (strcmp(szText, szBuffer) != 0)
+ {
+ Trace("SetFilePointer: ERROR -> Failed to return the pointer "
+ "properly to the beginning of the file\n");
+ bRc = CloseHandle(hFile);
+ if (bRc != TRUE)
+ {
+ Trace("SetFilePointer: ERROR -> Unable to close file"
+ " \"%s\".\n", szTextFile);
+ }
+ if (!DeleteFileA(szTextFile))
+ {
+ Trace("SetFilePointer: ERROR -> Unable to delete file"
+ " \"%s\".\n", szTextFile);
+ }
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+ }
+
+ /* return the pointer to the beginning of the file */
+ dwRc = SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
+ if (dwRc != 0)
+ {
+ Trace("SetFilePointer: ERROR -> Asked to move 0 bytes from the "
+ "beginning of the file but moved %ld bytes.\n", dwRc);
+ bRc = CloseHandle(hFile);
+ if (bRc != TRUE)
+ {
+ Trace("SetFilePointer: ERROR -> Unable to close file \"%s\".\n",
+ szTextFile);
+ }
+ if (!DeleteFileA(szTextFile))
+ {
+ Trace("SetFilePointer: ERROR -> Unable to delete file \"%s\".\n",
+ szTextFile);
+ }
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+
+ /* set the pointer past the end of the file and verify */
+ dwRc = SetFilePointer(hFile, (DWORD)strlen(szText)+20, NULL, FILE_BEGIN);
+ if ((dwRc == INVALID_SET_FILE_POINTER) && (GetLastError() != ERROR_SUCCESS))
+ {
+ Trace("SetFilePointer: ERROR -> Failed to move pointer past EOF.\n");
+ bRc = CloseHandle(hFile);
+ if (bRc != TRUE)
+ {
+ Trace("SetFilePointer: ERROR -> Unable to close file \"%s\".\n",
+ szTextFile);
+ }
+ if (!DeleteFileA(szTextFile))
+ {
+ Trace("SetFilePointer: ERROR -> Unable to delete file \"%s\".\n",
+ szTextFile);
+ }
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+ else
+ {
+ /* verify */
+ bRc = SetEndOfFile(hFile);
+ if (bRc != TRUE)
+ {
+ bRc = CloseHandle(hFile);
+ if (bRc != TRUE)
+ {
+ Trace("SetFilePointer: ERROR -> Unable to close file"
+ " \"%s\".\n", szTextFile);
+ }
+ if (!DeleteFileA(szTextFile))
+ {
+ Trace("SetFilePointer: ERROR -> Unable to delete file"
+ " \"%s\".\n", szTextFile);
+ }
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+
+ if (GetFileSize(hFile, NULL) != strlen(szText)+20)
+ {
+ Trace("SetFilePointer: ERROR -> Failed to move pointer past"
+ " EOF.\n");
+ bRc = CloseHandle(hFile);
+ if (bRc != TRUE)
+ {
+ Trace("SetFilePointer: ERROR -> Unable to close file"
+ " \"%s\".\n", szTextFile);
+ }
+ if (!DeleteFileA(szTextFile))
+ {
+ Trace("SetFilePointer: ERROR -> Unable to delete file"
+ " \"%s\".\n", szTextFile);
+ }
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+ }
+
+
+
+ bRc = CloseHandle(hFile);
+ if (bRc != TRUE)
+ {
+ Trace("SetFilePointer: ERROR -> Unable to close file \"%s\".\n",
+ szTextFile);
+ if (!DeleteFileA(szTextFile))
+ {
+ Trace("SetFilePointer: ERROR -> Unable to delete file \"%s\".\n",
+ szTextFile);
+ }
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+
+ if (!DeleteFileA(szTextFile))
+ {
+ Fail("SetFilePointer: ERROR -> Unable to delete file \"%s\".\n",
+ szTextFile);
+ }
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/file_io/SetFilePointer/test2/testinfo.dat b/src/pal/tests/palsuite/file_io/SetFilePointer/test2/testinfo.dat
new file mode 100644
index 0000000000..e3a0a861f4
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetFilePointer/test2/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = SetFilePointer
+Name = Positive Test for SetFilePointer (test 2)
+Type = DEFAULT
+EXE1 = setfilepointer
+Description
+=Tests the FILE_BEGIN option
+
diff --git a/src/pal/tests/palsuite/file_io/SetFilePointer/test3/CMakeLists.txt b/src/pal/tests/palsuite/file_io/SetFilePointer/test3/CMakeLists.txt
new file mode 100644
index 0000000000..daa7553a1a
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetFilePointer/test3/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ SetFilePointer.c
+)
+
+add_executable(paltest_setfilepointer_test3
+ ${SOURCES}
+)
+
+add_dependencies(paltest_setfilepointer_test3 coreclrpal)
+
+target_link_libraries(paltest_setfilepointer_test3
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/SetFilePointer/test3/SetFilePointer.c b/src/pal/tests/palsuite/file_io/SetFilePointer/test3/SetFilePointer.c
new file mode 100644
index 0000000000..dd53829629
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetFilePointer/test3/SetFilePointer.c
@@ -0,0 +1,350 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: SetFilePointer.c (test 3)
+**
+** Purpose: Tests the PAL implementation of the SetFilePointer function.
+** Test the FILE_CURRENT option
+**
+** Assumes Successful:
+** CreateFile
+** ReadFile
+** WriteFile
+** strlen
+** CloseHandle
+** strcmp
+** GetFileSize
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+const char* const szText =
+ "The quick brown fox jumped over the lazy dog's back.";
+const char* szTextFile = "text.txt";
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ HANDLE hFile = NULL;
+ DWORD dwByteCount = 0;
+ DWORD dwRc = 0;
+ BOOL bRc = FALSE;
+ char szBuffer[100];
+ const char* szPtr;
+
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ /* create a test file */
+ hFile = CreateFile(szTextFile,
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if(hFile == INVALID_HANDLE_VALUE)
+ {
+ Fail("SetFilePointer: ERROR -> Unable to create file \"%s\".\n",
+ szTextFile);
+ }
+
+ bRc = WriteFile(hFile, szText, (DWORD)strlen(szText), &dwByteCount, NULL);
+ if (bRc == FALSE)
+ {
+ Trace("SetFilePointer: ERROR -> Unable to write to file \"%s\".\n",
+ szTextFile);
+ if (CloseHandle(hFile) != TRUE)
+ {
+ Trace("SetFilePointer: ERROR -> Unable to close file \"%s\".\n",
+ szTextFile);
+ }
+ if (!DeleteFileA(szTextFile))
+ {
+ Trace("SetFilePointer: ERROR -> Unable to delete file \"%s\".\n",
+ szTextFile);
+ }
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+
+ /* reset the pointer to the beginning */
+ if (SetFilePointer(hFile, 0, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER)
+ {
+ if (GetLastError() != ERROR_SUCCESS)
+ {
+ Trace("SetFilePointer: ERROR -> Unable to reset the pointer to the "
+ "beginning of the file");
+ if (CloseHandle(hFile) != TRUE)
+ {
+ Trace("SetFilePointer: ERROR -> Unable to close file \"%s\".\n",
+ szTextFile);
+ }
+ if (!DeleteFileA(szTextFile))
+ {
+ Trace("SetFilePointer: ERROR -> Unable to delete file"
+ " \"%s\".\n", szTextFile);
+ }
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+ }
+
+ /* move -1 from beginning which should fail */
+ dwRc = SetFilePointer(hFile, -1, NULL, FILE_CURRENT);
+ if ((dwRc != INVALID_SET_FILE_POINTER) ||
+ (GetLastError() == ERROR_SUCCESS))
+ {
+ Trace("SetFilePointer: ERROR -> Succeeded to move the pointer "
+ "before the beginning of the file.\n");
+ if (CloseHandle(hFile) != TRUE)
+ {
+ Trace("SetFilePointer: ERROR -> Unable to close file \"%s\".\n",
+ szTextFile);
+ }
+ if (!DeleteFileA(szTextFile))
+ {
+ Trace("SetFilePointer: ERROR -> Unable to delete file \"%s\".\n",
+ szTextFile);
+ }
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+
+
+ /* move the file pointer 0 bytes from the beginning and verify */
+ dwRc = SetFilePointer(hFile, 0, NULL, FILE_CURRENT);
+ if (dwRc != 0)
+ {
+ Trace("SetFilePointer: ERROR -> Asked to move 0 bytes from the "
+ "beginning of the file but moved %ld bytes.\n", dwRc);
+ if (CloseHandle(hFile) != TRUE)
+ {
+ Trace("SetFilePointer: ERROR -> Unable to close file \"%s\".\n",
+ szTextFile);
+ }
+ if (!DeleteFileA(szTextFile))
+ {
+ Trace("SetFilePointer: ERROR -> Unable to delete file \"%s\".\n",
+ szTextFile);
+ }
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+
+ /* move the pointer ahead in the file and verify */
+ dwRc = SetFilePointer(hFile, 20, NULL, FILE_CURRENT);
+ if (dwRc != 20)
+ {
+ Trace("SetFilePointer: ERROR -> Asked to move 20 bytes from the "
+ "beginning of the file but moved %ld bytes.\n", dwRc);
+ if (CloseHandle(hFile) != TRUE)
+ {
+ Trace("SetFilePointer: ERROR -> Unable to close file \"%s\".\n",
+ szTextFile);
+ }
+ if (!DeleteFileA(szTextFile))
+ {
+ Trace("SetFilePointer: ERROR -> Unable to delete file \"%s\".\n",
+ szTextFile);
+ }
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+ else
+ {
+ /* verify results */
+ memset(szBuffer, 0, 100);
+ bRc = ReadFile(hFile, szBuffer, (DWORD)strlen(szText)-20, &dwByteCount,
+ NULL);
+ if ((bRc != TRUE) || (dwByteCount != strlen(szText)-20))
+ {
+ Trace("SetFilePointer: ERROR -> ReadFile failed to read correctly");
+ if (CloseHandle(hFile) != TRUE)
+ {
+ Trace("SetFilePointer: ERROR -> Unable to close file \"%s\".\n",
+ szTextFile);
+ }
+ if (!DeleteFileA(szTextFile))
+ {
+ Trace("SetFilePointer: ERROR -> Unable to delete file"
+ " \"%s\".\n", szTextFile);
+ }
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+ szPtr = szText + 20;;
+ if (strcmp(szPtr, szBuffer) != 0)
+ {
+ Trace("SetFilePointer: ERROR -> Apparently failed to move the"
+ " pointer properly\n");
+ if (CloseHandle(hFile) != TRUE)
+ {
+ Trace("SetFilePointer: ERROR -> Unable to close file \"%s\".\n",
+ szTextFile);
+ }
+ if (!DeleteFileA(szTextFile))
+ {
+ Trace("SetFilePointer: ERROR -> Unable to delete file"
+ " \"%s\".\n", szTextFile);
+ }
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+ }
+
+
+ /* get the current file pointer position (should be 52) */
+ dwRc = SetFilePointer(hFile, 0, NULL, FILE_CURRENT);
+ if (dwRc != 52)
+ {
+ Trace("SetFilePointer: ERROR -> Asked for current position."
+ " Should be 52 but was %ld.\n", dwRc);
+ if (CloseHandle(hFile) != TRUE)
+ {
+ Trace("SetFilePointer: ERROR -> Unable to close file \"%s\".\n",
+ szTextFile);
+ }
+ if (!DeleteFileA(szTextFile))
+ {
+ Trace("SetFilePointer: ERROR -> Unable to delete file \"%s\".\n",
+ szTextFile);
+ }
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+
+
+ /* move the pointer backwards in the file and verify */
+ dwRc = SetFilePointer(hFile, -10, NULL, FILE_CURRENT);
+ if (dwRc != 42)
+ {
+ Trace("SetFilePointer: ERROR -> Asked to move back 10 bytes from the"
+ "end of the file but moved it to position %ld.\n", dwRc);
+ if (CloseHandle(hFile) != TRUE)
+ {
+ Trace("SetFilePointer: ERROR -> Unable to close file \"%s\".\n",
+ szTextFile);
+ }
+ if (!DeleteFileA(szTextFile))
+ {
+ Trace("SetFilePointer: ERROR -> Unable to delete file \"%s\".\n",
+ szTextFile);
+ }
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+ else
+ {
+ /* verify results */
+ memset(szBuffer, 0, 100);
+ bRc = ReadFile(hFile, szBuffer, 10, &dwByteCount, NULL);
+ if ((bRc != TRUE) || (dwByteCount != 10))
+ {
+ Trace("SetFilePointer: ERROR -> ReadFile failed to read correctly");
+ if (CloseHandle(hFile) != TRUE)
+ {
+ Trace("SetFilePointer: ERROR -> Unable to close file \"%s\".\n",
+ szTextFile);
+ }
+ if (!DeleteFileA(szTextFile))
+ {
+ Trace("SetFilePointer: ERROR -> Unable to delete file"
+ " \"%s\".\n", szTextFile);
+ }
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+ szPtr = szText + 42;
+ if (strcmp(szPtr, szBuffer) != 0)
+ {
+ Trace("SetFilePointer: ERROR -> Apparently failed to move the"
+ " pointer properly\n");
+ if (CloseHandle(hFile) != TRUE)
+ {
+ Trace("SetFilePointer: ERROR -> Unable to close file \"%s\".\n",
+ szTextFile);
+ }
+ if (!DeleteFileA(szTextFile))
+ {
+ Trace("SetFilePointer: ERROR -> Unable to delete file"
+ " \"%s\".\n", szTextFile);
+ }
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+ }
+
+ /*
+ * the file pointer is currently at the end of the file so...
+ * set the pointer past the end of the file and verify
+ */
+ dwRc = SetFilePointer(hFile, 20, NULL, FILE_CURRENT);
+ if ((dwRc == INVALID_SET_FILE_POINTER) && (GetLastError() != ERROR_SUCCESS))
+ {
+ Trace("SetFilePointer: ERROR -> Failed to move pointer past EOF.\n");
+ if (CloseHandle(hFile) != TRUE)
+ {
+ Trace("SetFilePointer: ERROR -> Unable to close file \"%s\".\n",
+ szTextFile);
+ }
+ if (!DeleteFileA(szTextFile))
+ {
+ Trace("SetFilePointer: ERROR -> Unable to delete file \"%s\".\n",
+ szTextFile);
+ }
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+ else
+ {
+ if (SetFilePointer(hFile, 0, NULL, FILE_CURRENT) != strlen(szText)+20)
+ {
+ Trace("SetFilePointer: ERROR -> Failed to move pointer past"
+ " EOF.\n");
+ if (CloseHandle(hFile) != TRUE)
+ {
+ Trace("SetFilePointer: ERROR -> Unable to close file \"%s\".\n",
+ szTextFile);
+ }
+ if (!DeleteFileA(szTextFile))
+ {
+ Trace("SetFilePointer: ERROR -> Unable to delete file"
+ " \"%s\".\n", szTextFile);
+ }
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+ }
+
+ if (CloseHandle(hFile) != TRUE)
+ {
+ Trace("SetFilePointer: ERROR -> Unable to close file \"%s\".\n",
+ szTextFile);
+ if (!DeleteFileA(szTextFile))
+ {
+ Trace("SetFilePointer: ERROR -> Unable to delete file \"%s\".\n",
+ szTextFile);
+ }
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+
+ if (!DeleteFileA(szTextFile))
+ {
+ Fail("SetFilePointer: ERROR -> Unable to delete file \"%s\".\n",
+ szTextFile);
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/file_io/SetFilePointer/test3/testinfo.dat b/src/pal/tests/palsuite/file_io/SetFilePointer/test3/testinfo.dat
new file mode 100644
index 0000000000..7c51fbc384
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetFilePointer/test3/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = SetFilePointer
+Name = Positive Test for SetFilePointer (test 3)
+Type = DEFAULT
+EXE1 = setfilepointer
+Description
+=Tests the FILE_CURRENT option
+
diff --git a/src/pal/tests/palsuite/file_io/SetFilePointer/test4/CMakeLists.txt b/src/pal/tests/palsuite/file_io/SetFilePointer/test4/CMakeLists.txt
new file mode 100644
index 0000000000..1117893350
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetFilePointer/test4/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ SetFilePointer.c
+)
+
+add_executable(paltest_setfilepointer_test4
+ ${SOURCES}
+)
+
+add_dependencies(paltest_setfilepointer_test4 coreclrpal)
+
+target_link_libraries(paltest_setfilepointer_test4
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/SetFilePointer/test4/SetFilePointer.c b/src/pal/tests/palsuite/file_io/SetFilePointer/test4/SetFilePointer.c
new file mode 100644
index 0000000000..2993cfd354
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetFilePointer/test4/SetFilePointer.c
@@ -0,0 +1,242 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: SetFilePointer.c (test 4)
+**
+** Purpose: Tests the PAL implementation of the SetFilePointer function.
+** Test the FILE_END option
+**
+** Assumes Successful:
+** CreateFile
+** ReadFile
+** WriteFile
+** strlen
+** CloseHandle
+** strcmp
+** GetFileSize
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+const char* szText = "The quick brown fox jumped over the lazy dog's back.";
+const char* szTextFile = "text.txt";
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ HANDLE hFile = NULL;
+ DWORD dwByteCount = 0;
+ DWORD dwOffset = 0;
+ DWORD dwRc = 0;
+ BOOL bRc = FALSE;
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ /* create a test file */
+ hFile = CreateFile(szTextFile,
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if(hFile == INVALID_HANDLE_VALUE)
+ {
+ Fail("SetFilePointer: ERROR -> Unable to create file \"%s\".\n",
+ szTextFile);
+ }
+
+ bRc = WriteFile(hFile, szText, (DWORD)strlen(szText), &dwByteCount, NULL);
+ if (bRc == FALSE)
+ {
+ Trace("SetFilePointer: ERROR -> Unable to write to file \"%s\".\n",
+ szTextFile);
+ if (CloseHandle(hFile) != TRUE)
+ {
+ Trace("SetFilePointer: ERROR -> Unable to close file \"%s\".\n",
+ szTextFile);
+ }
+ if (!DeleteFileA(szTextFile))
+ {
+ Trace("SetFilePointer: ERROR -> Unable to delete file \"%s\".\n",
+ szTextFile);
+ }
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+
+
+ /*
+ * move -1 from the end
+ */
+ dwRc = SetFilePointer(hFile, -1, NULL, FILE_END);
+ if (dwRc == INVALID_SET_FILE_POINTER)
+ {
+ if (GetLastError() != ERROR_SUCCESS)
+ {
+ Trace("SetFilePointer: ERROR -> Failed to move the pointer "
+ "back one character from EOF.\n");
+ if (CloseHandle(hFile) != TRUE)
+ {
+ Trace("SetFilePointer: ERROR -> Unable to close file"
+ " \"%s\".\n", szTextFile);
+ }
+ if (!DeleteFileA(szTextFile))
+ {
+ Trace("SetFilePointer: ERROR -> Unable to delete file"
+ " \"%s\".\n", szTextFile);
+ }
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+ }
+ else
+ {
+ /* verify */
+ if ((dwRc != strlen(szText)-1))
+ {
+ Trace("SetFilePointer: ERROR -> Failed to move the pointer"
+ " -1 bytes from EOF\n");
+ if (CloseHandle(hFile) != TRUE)
+ {
+ Trace("SetFilePointer: ERROR -> Unable to close file"
+ " \"%s\".\n", szTextFile);
+ }
+ if (!DeleteFileA(szTextFile))
+ {
+ Trace("SetFilePointer: ERROR -> Unable to delete file"
+ " \"%s\".\n", szTextFile);
+ }
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+ }
+
+ /*
+ * move the file pointer 0 bytes from the end and verify
+ */
+ dwRc = SetFilePointer(hFile, 0, NULL, FILE_END);
+ if (dwRc != strlen(szText))
+ {
+ Trace("SetFilePointer: ERROR -> Asked to move 0 bytes from the "
+ "end of the file. Function returned %ld instead of 52.\n", dwRc);
+ if (CloseHandle(hFile) != TRUE)
+ {
+ Trace("SetFilePointer: ERROR -> Unable to close file \"%s\".\n",
+ szTextFile);
+ }
+ if (!DeleteFileA(szTextFile))
+ {
+ Trace("SetFilePointer: ERROR -> Unable to delete file \"%s\".\n",
+ szTextFile);
+ }
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+
+ /*
+ * move the pointer past the end of the file and verify
+ */
+ dwRc = SetFilePointer(hFile, 20, NULL, FILE_END);
+ if (dwRc != strlen(szText)+20)
+ {
+ Trace("SetFilePointer: ERROR -> Asked to move 20 bytes past the "
+ "end of the file. Function returned %ld instead of %d.\n",
+ dwRc,
+ strlen(szText)+20);
+ if (CloseHandle(hFile) != TRUE)
+ {
+ Trace("SetFilePointer: ERROR -> Unable to close file \"%s\".\n",
+ szTextFile);
+ }
+ if (!DeleteFileA(szTextFile))
+ {
+ Trace("SetFilePointer: ERROR -> Unable to delete file \"%s\".\n",
+ szTextFile);
+ }
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+ else
+ {
+ /* verify results */
+ bRc = SetEndOfFile(hFile);
+ if ((dwRc = GetFileSize(hFile, NULL)) != strlen(szText)+20)
+ {
+ Trace("SetFilePointer: ERROR -> Asked to move back 20 bytes past"
+ " theend of the file. GetFileSize returned %ld whereas it "
+ "should have been %d.\n",
+ dwRc,
+ strlen(szText)+20);
+ if (CloseHandle(hFile) != TRUE)
+ {
+ Trace("SetFilePointer: ERROR -> Unable to close file"
+ " \"%s\".\n", szTextFile);
+ }
+ if (!DeleteFileA(szTextFile))
+ {
+ Trace("SetFilePointer: ERROR -> Unable to delete file"
+ " \"%s\".\n", szTextFile);
+ }
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+ }
+
+
+ /*
+ * move the pointer backwards to before the start of the file and verify
+ */
+
+ dwOffset = (dwRc + 20) * -1;
+ dwRc = SetFilePointer(hFile, dwOffset, NULL, FILE_END);
+ if ((dwRc != INVALID_SET_FILE_POINTER) ||
+ (GetLastError() == ERROR_SUCCESS))
+ {
+ Trace("SetFilePointer: ERROR -> Was able to move the pointer "
+ "to before the beginning of the file.\n");
+ if (CloseHandle(hFile) != TRUE)
+ {
+ Trace("SetFilePointer: ERROR -> Unable to close file \"%s\".\n",
+ szTextFile);
+ }
+ if (!DeleteFileA(szTextFile))
+ {
+ Trace("SetFilePointer: ERROR -> Unable to delete file \"%s\".\n",
+ szTextFile);
+ }
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+
+
+ if (CloseHandle(hFile) != TRUE)
+ {
+ Trace("SetFilePointer: ERROR -> Unable to close file \"%s\".\n",
+ szTextFile);
+ if (!DeleteFileA(szTextFile))
+ {
+ Trace("SetFilePointer: ERROR -> Unable to delete file \"%s\".\n",
+ szTextFile);
+ }
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+
+ if (!DeleteFileA(szTextFile))
+ {
+ Fail("SetFilePointer: ERROR -> Unable to delete file \"%s\".\n",
+ szTextFile);
+ }
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/file_io/SetFilePointer/test4/testinfo.dat b/src/pal/tests/palsuite/file_io/SetFilePointer/test4/testinfo.dat
new file mode 100644
index 0000000000..dce6f9eb21
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetFilePointer/test4/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = SetFilePointer
+Name = Positive Test for SetFilePointer (test 4)
+Type = DEFAULT
+EXE1 = setfilepointer
+Description
+=Tests the FILE_END option
+
diff --git a/src/pal/tests/palsuite/file_io/SetFilePointer/test5/CMakeLists.txt b/src/pal/tests/palsuite/file_io/SetFilePointer/test5/CMakeLists.txt
new file mode 100644
index 0000000000..b37bf42ffc
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetFilePointer/test5/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ SetFilePointer.c
+)
+
+add_executable(paltest_setfilepointer_test5
+ ${SOURCES}
+)
+
+add_dependencies(paltest_setfilepointer_test5 coreclrpal)
+
+target_link_libraries(paltest_setfilepointer_test5
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/SetFilePointer/test5/SetFilePointer.c b/src/pal/tests/palsuite/file_io/SetFilePointer/test5/SetFilePointer.c
new file mode 100644
index 0000000000..f1d392da38
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetFilePointer/test5/SetFilePointer.c
@@ -0,0 +1,182 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: SetFilePointer.c (test 5)
+**
+** Purpose: Tests the PAL implementation of the SetFilePointer function.
+** Test the FILE_BEGIN option using the high word parameter
+**
+** Assumes Successful:
+** CreateFile
+** ReadFile
+** WriteFile
+** strlen
+** CloseHandle
+** strcmp
+** GetFileSize
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+const char* szTextFile = "text.txt";
+
+int __cdecl main(int argc, char *argv[])
+{
+ HANDLE hFile = NULL;
+ DWORD dwOffset = 1;
+ LONG dwHighWord = 1;
+ DWORD dwReturnedOffset = 0;
+ DWORD dwReturnedHighWord = 0;
+ DWORD dwRc = 0;
+ DWORD dwError = 0;
+ BOOL bRc = FALSE;
+
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ /* create a test file */
+ hFile = CreateFile(szTextFile,
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if(hFile == INVALID_HANDLE_VALUE)
+ {
+ dwError = GetLastError();
+ Fail("SetFilePointer: ERROR -> Unable to create file \"%s\".\n with "
+ "error %ld",
+ szTextFile,
+ GetLastError());
+ }
+
+
+
+ /* move -1 from beginning which should fail */
+ dwRc = SetFilePointer(hFile, -1, &dwHighWord, FILE_BEGIN);
+ if (dwRc != INVALID_SET_FILE_POINTER)
+ {
+ Trace("SetFilePointer: ERROR -> Succeeded to move the pointer "
+ "before the beginning of the file using the high word.\n");
+ bRc = CloseHandle(hFile);
+ if (bRc != TRUE)
+ {
+ Trace("SetFilePointer: ERROR -> Unable to close file \"%s\".\n",
+ szTextFile);
+ }
+ if (!DeleteFileA(szTextFile))
+ {
+ Trace("SetFilePointer: ERROR -> Unable to delete file \"%s\".\n",
+ szTextFile);
+ }
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+
+ /* set the pointer past the end of the file and verify */
+ dwRc = SetFilePointer(hFile, dwOffset, &dwHighWord, FILE_BEGIN);
+ if ((dwRc == INVALID_SET_FILE_POINTER) &&
+ ((dwError = GetLastError()) != ERROR_SUCCESS))
+ {
+ Trace("SetFilePointer: ERROR -> Failed to move pointer past EOF.\n");
+ bRc = CloseHandle(hFile);
+ if (bRc != TRUE)
+ {
+ Trace("SetFilePointer: ERROR -> Unable to close file \"%s\".\n",
+ szTextFile);
+ }
+ if (!DeleteFileA(szTextFile))
+ {
+ Trace("SetFilePointer: ERROR -> Unable to delete file \"%s\".\n",
+ szTextFile);
+ }
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+ else
+ {
+ /* verify */
+ bRc = SetEndOfFile(hFile);
+ if (bRc != TRUE)
+ {
+ dwError = GetLastError();
+ if (dwError == 112)
+ {
+ Trace("SetFilePointer: ERROR -> SetEndOfFile failed due to "
+ "lack of disk space\n");
+ }
+ else
+ {
+ Trace("SetFilePointer: ERROR -> SetEndOfFile call failed with "
+ "error %ld\n", dwError);
+ }
+ bRc = CloseHandle(hFile);
+ if (bRc != TRUE)
+ {
+ Trace("SetFilePointer: ERROR -> Unable to close file"
+ " \"%s\".\n", szTextFile);
+ }
+ if (!DeleteFileA(szTextFile))
+ {
+ Trace("SetFilePointer: ERROR -> Unable to delete file"
+ " \"%s\".\n", szTextFile);
+ }
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+
+ dwReturnedOffset = GetFileSize(hFile, &dwReturnedHighWord);
+ if ((dwOffset != dwReturnedOffset) ||
+ (dwHighWord != dwReturnedHighWord))
+ {
+ Trace("SetFilePointer: ERROR -> Failed to move pointer past"
+ " EOF.\n");
+ bRc = CloseHandle(hFile);
+ if (bRc != TRUE)
+ {
+ Trace("SetFilePointer: ERROR -> Unable to close file"
+ " \"%s\".\n", szTextFile);
+ }
+ if (!DeleteFileA(szTextFile))
+ {
+ Trace("SetFilePointer: ERROR -> Unable to delete file"
+ " \"%s\".\n", szTextFile);
+ }
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+ }
+
+ bRc = CloseHandle(hFile);
+ if (bRc != TRUE)
+ {
+ Trace("SetFilePointer: ERROR -> Unable to close file \"%s\".\n",
+ szTextFile);
+ if (!DeleteFileA(szTextFile))
+ {
+ Trace("SetFilePointer: ERROR -> Unable to delete file \"%s\".\n",
+ szTextFile);
+ }
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+
+ if (!DeleteFileA(szTextFile))
+ {
+ Fail("SetFilePointer: ERROR -> Unable to delete file \"%s\".\n",
+ szTextFile);
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/file_io/SetFilePointer/test5/testinfo.dat b/src/pal/tests/palsuite/file_io/SetFilePointer/test5/testinfo.dat
new file mode 100644
index 0000000000..64745c0e98
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetFilePointer/test5/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = SetFilePointer
+Name = Positive Test for SetFilePointer (test 5)
+Type = DEFAULT
+EXE1 = setfilepointer
+Description
+=Tests the FILE_BEGIN option with the high word parameter.
+=This test requires about 4 gig free disk space
+
diff --git a/src/pal/tests/palsuite/file_io/SetFilePointer/test6/CMakeLists.txt b/src/pal/tests/palsuite/file_io/SetFilePointer/test6/CMakeLists.txt
new file mode 100644
index 0000000000..8f99ed2d76
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetFilePointer/test6/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ SetFilePointer.c
+)
+
+add_executable(paltest_setfilepointer_test6
+ ${SOURCES}
+)
+
+add_dependencies(paltest_setfilepointer_test6 coreclrpal)
+
+target_link_libraries(paltest_setfilepointer_test6
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/SetFilePointer/test6/SetFilePointer.c b/src/pal/tests/palsuite/file_io/SetFilePointer/test6/SetFilePointer.c
new file mode 100644
index 0000000000..b35247ec24
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetFilePointer/test6/SetFilePointer.c
@@ -0,0 +1,213 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: SetFilePointer.c (test 6)
+**
+** Purpose: Tests the PAL implementation of the SetFilePointer function.
+** Test the FILE_CURRENT option with high order support
+**
+** Assumes Successful:
+** CreateFile
+** ReadFile
+** WriteFile
+** strlen
+** CloseHandle
+** strcmp
+** GetFileSize
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+const char* szTextFile = "text.txt";
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ HANDLE hFile = NULL;
+ DWORD dwOffset = 0;
+ LONG dwHighOrder = 0;
+ DWORD dwReturnedOffset = 0;
+ LONG dwReturnedHighOrder = 0;
+ DWORD dwRc = 0;
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ /* create a test file */
+ hFile = CreateFile(szTextFile,
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if(hFile == INVALID_HANDLE_VALUE)
+ {
+ Fail("SetFilePointer: ERROR -> Unable to create file \"%s\".\n",
+ szTextFile);
+ }
+
+
+ /* move waaaay before the beginning which should fail */
+ dwHighOrder = -1;
+ dwOffset = 0;
+ dwRc = SetFilePointer(hFile, dwOffset, &dwHighOrder, FILE_CURRENT);
+ if (dwRc != INVALID_SET_FILE_POINTER)
+ {
+ Trace("SetFilePointer: ERROR -> Succeeded to move the pointer "
+ "before the beginning of the file.\n");
+ if (CloseHandle(hFile) != TRUE)
+ {
+ Trace("SetFilePointer: ERROR -> Unable to close file \"%s\".\n",
+ szTextFile);
+ }
+ if (!DeleteFileA(szTextFile))
+ {
+ Trace("SetFilePointer: ERROR -> Unable to delete file \"%s\".\n",
+ szTextFile);
+ }
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+
+ /* move the pointer ahead in the file and verify */
+ dwHighOrder = 1;
+ dwOffset = 10;
+ dwRc = SetFilePointer(hFile, dwOffset, &dwHighOrder, FILE_CURRENT);
+ if ((dwRc != 10) || (dwHighOrder != 1))
+ {
+ Trace("SetFilePointer: ERROR -> Asked to move 2GB plus 10 bytes from "
+ "the beginning of the file but didn't.\n");
+ if (CloseHandle(hFile) != TRUE)
+ {
+ Trace("SetFilePointer: ERROR -> Unable to close file \"%s\".\n",
+ szTextFile);
+ }
+ if (!DeleteFileA(szTextFile))
+ {
+ Trace("SetFilePointer: ERROR -> Unable to delete file \"%s\".\n",
+ szTextFile);
+ }
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+ else
+ {
+ /* verify results */
+ if (SetEndOfFile(hFile) != TRUE)
+ {
+ Trace("SetFilePointer: ERROR -> Call to SetEndOfFile failed with "
+ "error code: %d\n", GetLastError());
+ if (CloseHandle(hFile) != TRUE)
+ {
+ Trace("SetFilePointer: ERROR -> Unable to close file"
+ " \"%s\".\n", szTextFile);
+ }
+ if (!DeleteFileA(szTextFile))
+ {
+ Trace("SetFilePointer: ERROR -> Unable to delete file"
+ " \"%s\".\n", szTextFile);
+ }
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+ dwReturnedOffset = GetFileSize(hFile, (DWORD*)&dwReturnedHighOrder);
+ if ((dwReturnedOffset != dwOffset) ||
+ (dwReturnedHighOrder != dwHighOrder))
+ {
+ Trace("SetFilePointer: ERROR -> Asked to move far past the "
+ "current file pointer. "
+ "low order sent: %ld low order returned: %ld "
+ "high order sent: %ld high order returned: %ld",
+ dwOffset, dwReturnedOffset,
+ dwHighOrder, dwReturnedHighOrder);
+ if (!DeleteFileA(szTextFile))
+ {
+ Trace("SetFilePointer: ERROR -> Unable to delete file"
+ " \"%s\".\n", szTextFile);
+ }
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+ }
+
+
+ /*
+ * move the pointer backwards in the file and verify
+ */
+ dwOffset = 0;
+ dwHighOrder = -1;
+ dwRc = SetFilePointer(hFile, dwOffset, &dwHighOrder, FILE_CURRENT);
+ if (dwRc != 10)
+ {
+ Trace("SetFilePointer: ERROR -> Asked to move back to 10 bytes from the"
+ "beginning of the file but moved it to position %ld.\n", dwRc);
+ if (CloseHandle(hFile) != TRUE)
+ {
+ Trace("SetFilePointer: ERROR -> Unable to close file \"%s\".\n",
+ szTextFile);
+ }
+ if (!DeleteFileA(szTextFile))
+ {
+ Trace("SetFilePointer: ERROR -> Unable to delete file \"%s\".\n",
+ szTextFile);
+ }
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+ else
+ {
+ /* verify results */
+ dwReturnedHighOrder = 0;
+ dwRc = SetFilePointer(hFile, 0, &dwReturnedHighOrder, FILE_CURRENT);
+ if (dwRc != 10)
+ {
+ Trace("SetFilePointer: ERROR -> Asked for current position. "
+ "Should be 10 but was %ld.\n", dwRc);
+ if (CloseHandle(hFile) != TRUE)
+ {
+ Trace("SetFilePointer: ERROR -> Unable to close file"
+ " \"%s\".\n", szTextFile);
+ }
+ if (!DeleteFileA(szTextFile))
+ {
+ Trace("SetFilePointer: ERROR -> Unable to delete file"
+ " \"%s\".\n", szTextFile);
+ }
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+ }
+
+
+ /* clean up, clean up, everybody do their share... */
+ if (CloseHandle(hFile) != TRUE)
+ {
+ Trace("SetFilePointer: ERROR -> Unable to close file \"%s\".\n",
+ szTextFile);
+ if (!DeleteFileA(szTextFile))
+ {
+ Trace("SetFilePointer: ERROR -> Unable to delete file \"%s\".\n",
+ szTextFile);
+ }
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+
+ if (!DeleteFileA(szTextFile))
+ {
+ Fail("SetFilePointer: ERROR -> Unable to delete file \"%s\".\n",
+ szTextFile);
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/file_io/SetFilePointer/test6/testinfo.dat b/src/pal/tests/palsuite/file_io/SetFilePointer/test6/testinfo.dat
new file mode 100644
index 0000000000..3138e9bb40
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetFilePointer/test6/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = SetFilePointer
+Name = Positive Test for SetFilePointer (test 6)
+Type = DEFAULT
+EXE1 = setfilepointer
+Description
+=Tests the FILE_CURRENT option with the high word parameter.
+=This test requires about 4 GB free disk space.
+
diff --git a/src/pal/tests/palsuite/file_io/SetFilePointer/test7/CMakeLists.txt b/src/pal/tests/palsuite/file_io/SetFilePointer/test7/CMakeLists.txt
new file mode 100644
index 0000000000..c5a46a531a
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetFilePointer/test7/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ SetFilePointer.c
+)
+
+add_executable(paltest_setfilepointer_test7
+ ${SOURCES}
+)
+
+add_dependencies(paltest_setfilepointer_test7 coreclrpal)
+
+target_link_libraries(paltest_setfilepointer_test7
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/SetFilePointer/test7/SetFilePointer.c b/src/pal/tests/palsuite/file_io/SetFilePointer/test7/SetFilePointer.c
new file mode 100644
index 0000000000..33dfd5e711
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetFilePointer/test7/SetFilePointer.c
@@ -0,0 +1,213 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: SetFilePointer.c (test 7)
+**
+** Purpose: Tests the PAL implementation of the SetFilePointer function.
+** Test the FILE_END option with high order support
+**
+** Assumes Successful:
+** CreateFile
+** ReadFile
+** WriteFile
+** strlen
+** CloseHandle
+** strcmp
+** GetFileSize
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+const char* szTextFile = "text.txt";
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ HANDLE hFile = NULL;
+ DWORD dwOffset = 0;
+ LONG dwHighOrder = 0;
+ DWORD dwReturnedOffset = 0;
+ LONG dwReturnedHighOrder = 0;
+ DWORD dwRc = 0;
+
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ /* create a test file */
+ hFile = CreateFile(szTextFile,
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if(hFile == INVALID_HANDLE_VALUE)
+ {
+ Fail("SetFilePointer: ERROR -> Unable to create file \"%s\".\n",
+ szTextFile);
+ }
+
+
+ /* move -1 from beginning which should fail */
+ dwHighOrder = -1;
+ dwOffset = 0;
+ dwRc = SetFilePointer(hFile, dwOffset, &dwHighOrder, FILE_END);
+ if (dwRc != INVALID_SET_FILE_POINTER)
+ {
+ Trace("SetFilePointer: ERROR -> Succeeded to move the pointer "
+ "before the beginning of the file.\n");
+ if (CloseHandle(hFile) != TRUE)
+ {
+ Trace("SetFilePointer: ERROR -> Unable to close file \"%s\".\n",
+ szTextFile);
+ }
+ if (!DeleteFileA(szTextFile))
+ {
+ Trace("SetFilePointer: ERROR -> Unable to delete file \"%s\".\n",
+ szTextFile);
+ }
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+
+ /* move the pointer ahead in the file and verify */
+ dwHighOrder = 1;
+ dwOffset = 10;
+ dwRc = SetFilePointer(hFile, dwOffset, &dwHighOrder, FILE_END);
+ if ((dwRc != 10) || (dwHighOrder != 1))
+ {
+ Trace("SetFilePointer: ERROR -> Asked to move 4GB plus 10 bytes from "
+ "the beginning of the file but didn't.\n");
+ if (CloseHandle(hFile) != TRUE)
+ {
+ Trace("SetFilePointer: ERROR -> Unable to close file \"%s\".\n",
+ szTextFile);
+ }
+ if (!DeleteFileA(szTextFile))
+ {
+ Trace("SetFilePointer: ERROR -> Unable to delete file \"%s\".\n",
+ szTextFile);
+ }
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+ else
+ {
+ /* verify results */
+ if (SetEndOfFile(hFile) != TRUE)
+ {
+ Trace("SetFilePointer: ERROR -> Call to SetEndOfFile failed with "
+ "error code: %d\n",
+ GetLastError());
+ if (CloseHandle(hFile) != TRUE)
+ {
+ Trace("SetFilePointer: ERROR -> Unable to close file \"%s\".\n",
+ szTextFile);
+ }
+ if (!DeleteFileA(szTextFile))
+ {
+ Trace("SetFilePointer: ERROR -> Unable to delete file \"%s\".\n",
+ szTextFile);
+ }
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+ dwReturnedOffset = GetFileSize(hFile, (DWORD*)&dwReturnedHighOrder);
+ if ((dwReturnedOffset != dwOffset) || (dwReturnedHighOrder != dwHighOrder))
+ {
+ Trace("SetFilePointer: ERROR -> Asked to move far past the "
+ "end of the file. low order sent: %ld low order returned: %ld "
+ "high order sent: %ld high order returned: %ld",
+ dwOffset, dwReturnedOffset,
+ dwHighOrder, dwReturnedHighOrder);
+ if (!DeleteFileA(szTextFile))
+ {
+ Trace("SetFilePointer: ERROR -> Unable to delete file \"%s\".\n",
+ szTextFile);
+ }
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+ }
+
+
+ /*
+ * move the pointer backwards in the file and verify
+ */
+ dwOffset = 0;
+ dwHighOrder = -1;
+ dwRc = SetFilePointer(hFile, dwOffset, &dwHighOrder, FILE_END);
+ if (dwRc != 10)
+ {
+ Trace("SetFilePointer: ERROR -> Asked to move back to 10 bytes from the"
+ "beginning of the file but moved it to position %ld.\n", dwRc);
+ if (CloseHandle(hFile) != TRUE)
+ {
+ Trace("SetFilePointer: ERROR -> Unable to close file \"%s\".\n",
+ szTextFile);
+ }
+ if (!DeleteFileA(szTextFile))
+ {
+ Trace("SetFilePointer: ERROR -> Unable to delete file \"%s\".\n",
+ szTextFile);
+ }
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+ else
+ {
+ /* verify results */
+ dwReturnedHighOrder = 0;
+ dwRc = SetFilePointer(hFile, 0, &dwReturnedHighOrder, FILE_CURRENT);
+ if (dwRc != 10)
+ {
+ Trace("SetFilePointer: ERROR -> Asked for current position. "
+ "Should be 10 but was %ld.\n", dwRc);
+ if (CloseHandle(hFile) != TRUE)
+ {
+ Trace("SetFilePointer: ERROR -> Unable to close file"
+ " \"%s\".\n", szTextFile);
+ }
+ if (!DeleteFileA(szTextFile))
+ {
+ Trace("SetFilePointer: ERROR -> Unable to delete file"
+ " \"%s\".\n", szTextFile);
+ }
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+ }
+
+
+ /* clean up, clean up, everybody do their share... */
+ if (CloseHandle(hFile) != TRUE)
+ {
+ Trace("SetFilePointer: ERROR -> Unable to close file \"%s\".\n",
+ szTextFile);
+ if (!DeleteFileA(szTextFile))
+ {
+ Trace("SetFilePointer: ERROR -> Unable to delete file \"%s\".\n",
+ szTextFile);
+ }
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+
+ if (!DeleteFileA(szTextFile))
+ {
+ Fail("SetFilePointer: ERROR -> Unable to delete file \"%s\".\n",
+ szTextFile);
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/file_io/SetFilePointer/test7/testinfo.dat b/src/pal/tests/palsuite/file_io/SetFilePointer/test7/testinfo.dat
new file mode 100644
index 0000000000..6e8826291f
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetFilePointer/test7/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = SetFilePointer
+Name = Positive Test for SetFilePointer (test 7)
+Type = DEFAULT
+EXE1 = setfilepointer
+Description
+=Tests the FILE_END option with the high word parameter
+=This test requires about 4 GB of free disk space.
+
diff --git a/src/pal/tests/palsuite/file_io/SetFileTime/CMakeLists.txt b/src/pal/tests/palsuite/file_io/SetFileTime/CMakeLists.txt
new file mode 100644
index 0000000000..a3847f8ca9
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetFileTime/CMakeLists.txt
@@ -0,0 +1,7 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+add_subdirectory(test3)
+add_subdirectory(test4)
+
diff --git a/src/pal/tests/palsuite/file_io/SetFileTime/test1/CMakeLists.txt b/src/pal/tests/palsuite/file_io/SetFileTime/test1/CMakeLists.txt
new file mode 100644
index 0000000000..4c4b5d7611
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetFileTime/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ SetFileTime.c
+)
+
+add_executable(paltest_setfiletime_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_setfiletime_test1 coreclrpal)
+
+target_link_libraries(paltest_setfiletime_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/SetFileTime/test1/SetFileTime.c b/src/pal/tests/palsuite/file_io/SetFileTime/test1/SetFileTime.c
new file mode 100644
index 0000000000..4711aeba89
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetFileTime/test1/SetFileTime.c
@@ -0,0 +1,129 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: SetFileTime.c
+**
+** Purpose: Tests the PAL implementation of the SetFileTime function.
+** This test first sets a valid file time on the file which is opened.
+** Then it calls GetFileTime, and compares the values. They should
+** be the same. Note: Access time isn't checked in this test. It will
+** be dealt with seperatly due to odd behaviour.
+**
+** Depends:
+** CreateFile
+** GetFileTime
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char **argv)
+{
+
+#if WIN32
+ FILETIME Creation;
+ FILETIME SetCreation;
+#endif
+ FILETIME LastWrite;
+ FILETIME SetLastWrite;
+ HANDLE TheFileHandle;
+ BOOL result;
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ /* Populate some FILETIME structures with values
+ These values are valid Creation, Access and Write times
+ which I generated, and should work properly.
+ */
+#if WIN32
+ SetCreation.dwLowDateTime = 458108416;
+ SetCreation.dwHighDateTime = 29436904;
+#endif
+
+ SetLastWrite.dwLowDateTime = -1995099136;
+ SetLastWrite.dwHighDateTime = 29436915;
+
+
+ /* Open the file to get a HANDLE */
+ TheFileHandle = CreateFile("the_file",
+ GENERIC_READ|GENERIC_WRITE,
+ 0,
+ NULL,
+ OPEN_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if(TheFileHandle == INVALID_HANDLE_VALUE)
+ {
+ Fail("ERROR: Failed to open the file. The error number "
+ "returned was %d.\n",GetLastError());
+ }
+
+ /* Set the new file time */
+#if WIN32
+ result = SetFileTime(TheFileHandle,
+ &SetCreation, NULL, &SetLastWrite);
+#else
+ result = SetFileTime(TheFileHandle,
+ NULL, NULL, &SetLastWrite);
+#endif
+ if(result == 0)
+ {
+ Fail("ERROR: SetFileTime failed when trying to set the "
+ "new file time. The GetLastError was %d.\n",GetLastError());
+ }
+
+
+ /* Then get the file time of the file */
+#if WIN32
+ result = GetFileTime(TheFileHandle, &Creation, NULL, &LastWrite);
+#else
+ result = GetFileTime(TheFileHandle, NULL, NULL, &LastWrite);
+#endif
+
+ if(result == 0)
+ {
+ Fail("ERROR: GetFileTime failed, and this tests depends "
+ "upon it working properly, in order to ensure that the "
+ "file time was set with SetFileTime. GetLastError() "
+ "returned %d.\n",GetLastError());
+ }
+
+ /* Compare the write time we Set to the write time aquired with
+ Get. They should be the same.
+ */
+
+ if(LastWrite.dwLowDateTime != SetLastWrite.dwLowDateTime ||
+ LastWrite.dwHighDateTime != SetLastWrite.dwHighDateTime)
+ {
+ Fail("ERROR: After setting the write time, it is not "
+ "equal to what it was set to. Either Set of GetFileTime are "
+ "broken.\n");
+ }
+
+ /* Within FreeBSD, the Creation time is ignored when SetFileTime
+ is called. Since FreeBSD has no equivalent. For that reason,
+ it is not checked with the following test.
+ */
+
+#if WIN32
+ if(Creation.dwHighDateTime != SetCreation.dwHighDateTime ||
+ Creation.dwLowDateTime != SetCreation.dwLowDateTime)
+ {
+ Fail("ERROR: After setting the file time, the Creation "
+ "time is not what it should be. Either Set or GetFileTime "
+ "are broken.");
+ }
+#endif
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/file_io/SetFileTime/test1/testinfo.dat b/src/pal/tests/palsuite/file_io/SetFileTime/test1/testinfo.dat
new file mode 100644
index 0000000000..09dfa0b623
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetFileTime/test1/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = SetFileTime
+Name = Positive Test for SetFileTime
+TYPE = DEFAULT
+EXE1 = setfiletime
+Description
+= Test the SetFileTime function.
+= This test calls SetFileTime and sets a file to a given time. It then
+= calls GetFileTime, and compares the values of the two, which should be
+= equal
diff --git a/src/pal/tests/palsuite/file_io/SetFileTime/test2/CMakeLists.txt b/src/pal/tests/palsuite/file_io/SetFileTime/test2/CMakeLists.txt
new file mode 100644
index 0000000000..35c18c8d8d
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetFileTime/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ SetFileTime.c
+)
+
+add_executable(paltest_setfiletime_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_setfiletime_test2 coreclrpal)
+
+target_link_libraries(paltest_setfiletime_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/SetFileTime/test2/SetFileTime.c b/src/pal/tests/palsuite/file_io/SetFileTime/test2/SetFileTime.c
new file mode 100644
index 0000000000..e950153bb0
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetFileTime/test2/SetFileTime.c
@@ -0,0 +1,101 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: SetFileTime.c
+**
+** Purpose: Tests the PAL implementation of the SetFileTime
+** This test first tries to SetFileTime on a HANDLE which doesn't have
+** GENERIC_WRITE set, which should fail.
+**
+**
+** Depends:
+** CreateFile
+** CloseHandle
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+
+
+
+int __cdecl main(int argc, char **argv)
+{
+
+ FILETIME SetCreation,SetLastAccess,SetLastWrite;
+ HANDLE TheFileHandle;
+ BOOL result;
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ /* Populate some FILETIME structures with values
+ These values are valid Creation, Access and Write times
+ which I generated, and should work properly.
+
+ The access times are not seperated into WIN32 and FreeBSD here,
+ but it should be fine, as no comparisons are being done in this
+ test.
+ */
+
+ SetCreation.dwLowDateTime = 458108416;
+ SetCreation.dwHighDateTime = 29436904;
+
+ SetLastAccess.dwLowDateTime = 341368832;
+ SetLastAccess.dwHighDateTime = 29436808;
+
+ SetLastWrite.dwLowDateTime = -1995099136;
+ SetLastWrite.dwHighDateTime = 29436915;
+
+
+/* Open the file to get a HANDLE, without GENERIC WRITE */
+
+ TheFileHandle =
+ CreateFile(
+ "the_file",
+ GENERIC_READ,
+ 0,
+ NULL,
+ OPEN_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+
+ if(TheFileHandle == INVALID_HANDLE_VALUE)
+ {
+ Fail("ERROR: Failed to open the file. The error number "
+ "returned was %d.",GetLastError());
+ }
+
+ /* This SetFileTime should fail, because the HANDLE isn't set with
+ GENERIC_WRITE
+ */
+ result = SetFileTime(TheFileHandle,
+ &SetCreation,&SetLastAccess,&SetLastWrite);
+
+ if(result != 0)
+ {
+ Fail("ERROR: SetFileTime should have failed, but returned a "
+ "non-zero result. The File HANDLE passed was no set Writable "
+ "which should cause failure.");
+ }
+
+ result = CloseHandle(TheFileHandle);
+
+ if(result == 0)
+ {
+ Fail("ERROR: CloseHandle failed. This test depends upon "
+ "it working.");
+ }
+
+
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/file_io/SetFileTime/test2/testinfo.dat b/src/pal/tests/palsuite/file_io/SetFileTime/test2/testinfo.dat
new file mode 100644
index 0000000000..f1699facaf
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetFileTime/test2/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = SetFileTime
+Name = Negative Test for SetFileTime
+TYPE = DEFAULT
+EXE1 = setfiletime
+Description
+= Test the SetFileTime function.
+= This test first tries to SetFileTime on a HANDLE which doesn't have
+= GENERIC_WRITE set, which should fail. Then it attempts to set the file
+= time with bad FILETIME structures, which should also fail
diff --git a/src/pal/tests/palsuite/file_io/SetFileTime/test3/CMakeLists.txt b/src/pal/tests/palsuite/file_io/SetFileTime/test3/CMakeLists.txt
new file mode 100644
index 0000000000..0a85d30c51
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetFileTime/test3/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ SetFileTime.c
+)
+
+add_executable(paltest_setfiletime_test3
+ ${SOURCES}
+)
+
+add_dependencies(paltest_setfiletime_test3 coreclrpal)
+
+target_link_libraries(paltest_setfiletime_test3
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/SetFileTime/test3/SetFileTime.c b/src/pal/tests/palsuite/file_io/SetFileTime/test3/SetFileTime.c
new file mode 100644
index 0000000000..97f49495d7
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetFileTime/test3/SetFileTime.c
@@ -0,0 +1,66 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: SetFileTime.c
+**
+** Purpose: Tests the PAL implementation of the SetFileTime function.
+** This test checks to ensure that the function fails when passed an
+** invalid file HANDLE
+**
+**
+**===================================================================*/
+
+
+
+#include <palsuite.h>
+
+
+
+
+int __cdecl main(int argc, char **argv)
+{
+
+ FILETIME SetCreation, SetLastWrite, SetLastAccess;
+ HANDLE TheFileHandle = NULL;
+ BOOL result;
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ /* Populate some FILETIME structures with values
+ These values are valid Creation, Access and Write times
+ which I generated, and should work properly.
+ */
+
+ SetCreation.dwLowDateTime = 458108416;
+ SetCreation.dwHighDateTime = 29436904;
+
+ SetLastAccess.dwLowDateTime = 341368832;
+ SetLastAccess.dwHighDateTime = 29436808;
+
+ SetLastWrite.dwLowDateTime = -1995099136;
+ SetLastWrite.dwHighDateTime = 29436915;
+
+
+ /* Pass this function an invalid file HANDLE and it should
+ fail.
+ */
+
+ result = SetFileTime(TheFileHandle,
+ &SetCreation,&SetLastAccess,&SetLastWrite);
+
+ if(result != 0)
+ {
+ Fail("ERROR: Passed an invalid file HANDLE to SetFileTime, but it "
+ "returned non-zero. This should return zero for failure.");
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/file_io/SetFileTime/test3/testinfo.dat b/src/pal/tests/palsuite/file_io/SetFileTime/test3/testinfo.dat
new file mode 100644
index 0000000000..e27280469e
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetFileTime/test3/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = SetFileTime
+Name = Negative Test for SetFileTime
+TYPE = DEFAULT
+EXE1 = setfiletime
+Description
+= Test the SetFileTime function.
+= This test checks to ensure that the function fails when passed an
+= invalid file HANDLE
diff --git a/src/pal/tests/palsuite/file_io/SetFileTime/test4/CMakeLists.txt b/src/pal/tests/palsuite/file_io/SetFileTime/test4/CMakeLists.txt
new file mode 100644
index 0000000000..086e35e535
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetFileTime/test4/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ SetFileTime.c
+)
+
+add_executable(paltest_setfiletime_test4
+ ${SOURCES}
+)
+
+add_dependencies(paltest_setfiletime_test4 coreclrpal)
+
+target_link_libraries(paltest_setfiletime_test4
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/SetFileTime/test4/SetFileTime.c b/src/pal/tests/palsuite/file_io/SetFileTime/test4/SetFileTime.c
new file mode 100644
index 0000000000..3edd2403c4
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetFileTime/test4/SetFileTime.c
@@ -0,0 +1,108 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: SetFileTime.c
+**
+** Purpose: Tests the PAL implementation of the SetFileTime function
+** This passes a variety of NULL values as parameters to the function.
+** It should still succeed.
+**
+** Depends:
+** CreateFile
+**
+
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+
+
+int __cdecl main(int argc, char **argv)
+{
+#if WIN32
+ FILETIME Creation;
+#endif
+ FILETIME LastWrite,LastAccess;
+ HANDLE TheFileHandle;
+
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ /* Populate some FILETIME structures with values
+ These values are valid Creation, Access and Write times
+ which I generated, and should work properly.
+
+ These values aren't being used for comparison, so they should
+ work ok, even though they weren't generated specifically for
+ FreeBSD or WIN32 ...
+ */
+#if WIN32
+ Creation.dwLowDateTime = 458108416;
+ Creation.dwHighDateTime = 29436904;
+#endif
+ LastAccess.dwLowDateTime = 341368832;
+ LastAccess.dwHighDateTime = 29436808;
+
+ LastWrite.dwLowDateTime = -1995099136;
+ LastWrite.dwHighDateTime = 29436915;
+
+ /* Open the file to get a HANDLE */
+ TheFileHandle =
+ CreateFile(
+ "the_file",
+ GENERIC_READ|GENERIC_WRITE,
+ 0,
+ NULL,
+ OPEN_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+
+ if(TheFileHandle == INVALID_HANDLE_VALUE)
+ {
+ Fail("ERROR: Failed to open the file. The error number "
+ "returned was %d.",GetLastError());
+ }
+
+ /* Pass all NULLs, this is useless but should still work. */
+ if(SetFileTime(TheFileHandle,NULL,NULL,NULL)==0)
+ {
+ Fail("ERROR: SetFileTime returned 0, indicating failure. "
+ "Three of the params were NULL in this case, did they "
+ "cause the problem?");
+ }
+
+#if WIN32
+ /* Set the Creation time of the File */
+ if(SetFileTime(TheFileHandle,&Creation,NULL,NULL)==0)
+ {
+ Fail("ERROR: SetFileTime returned 0, indicating failure. "
+ "Two of the params were NULL in this case, did they "
+ "cause the problem?");
+ }
+#endif
+
+#if WIN32
+ /* Set the Creation, LastWrite time of the File */
+ if(SetFileTime(TheFileHandle,&Creation,&LastWrite,NULL)==0)
+#else
+ /* Set the LastWrite time of the File */
+ if(SetFileTime(TheFileHandle,NULL,&LastWrite,NULL)==0)
+#endif
+ {
+ Fail("ERROR: SetFileTime returned 0, indicating failure. "
+ "One of the params were NULL in this case, did it "
+ "cause the problem?");
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/file_io/SetFileTime/test4/testinfo.dat b/src/pal/tests/palsuite/file_io/SetFileTime/test4/testinfo.dat
new file mode 100644
index 0000000000..a3dfdd02f0
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/SetFileTime/test4/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = SetFileTime
+Name = Positive Test for SetFileTime
+TYPE = DEFAULT
+EXE1 = setfiletime
+Description
+= Test the SetFileTime function.
+= This passes a variety of NULL values as parameters to the function.
+= It should still succeed
diff --git a/src/pal/tests/palsuite/file_io/WriteFile/CMakeLists.txt b/src/pal/tests/palsuite/file_io/WriteFile/CMakeLists.txt
new file mode 100644
index 0000000000..8083faf655
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/WriteFile/CMakeLists.txt
@@ -0,0 +1,8 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+add_subdirectory(test3)
+add_subdirectory(test4)
+add_subdirectory(test5)
+
diff --git a/src/pal/tests/palsuite/file_io/WriteFile/test1/CMakeLists.txt b/src/pal/tests/palsuite/file_io/WriteFile/test1/CMakeLists.txt
new file mode 100644
index 0000000000..0c6760a2ce
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/WriteFile/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ WriteFile.c
+)
+
+add_executable(paltest_writefile_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_writefile_test1 coreclrpal)
+
+target_link_libraries(paltest_writefile_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/WriteFile/test1/WriteFile.c b/src/pal/tests/palsuite/file_io/WriteFile/test1/WriteFile.c
new file mode 100644
index 0000000000..1ac38ddaf0
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/WriteFile/test1/WriteFile.c
@@ -0,0 +1,114 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: WriteFile.c (test 1)
+**
+** Purpose: Tests the PAL implementation of the WriteFile function.
+** This test will attempt to write to a NULL handle and a
+** read-only file
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+
+const char* szStringTest = "The quick fox jumped over the lazy dog's back.";
+const char* szReadOnlyFile = "ReadOnly.txt";
+void do_cleanup()
+{
+ BOOL bRc = FALSE;
+ bRc = DeleteFileA(szReadOnlyFile);
+ if (bRc != TRUE)
+ {
+ Fail ("DeleteFileA: ERROR[%ld]: During Cleanup: Couldn't delete WriteFile's"
+ " \"ReadOnly.txt\"\n", GetLastError());
+ }
+
+}
+
+int __cdecl main(int argc, char *argv[])
+{
+ HANDLE hFile = NULL;
+ DWORD dwBytesWritten;
+ BOOL bRc = FALSE;
+ DWORD last_error;
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ //
+ // Write to a NULL handle
+ //
+
+ bRc = WriteFile(hFile, szStringTest, 20, &dwBytesWritten, NULL);
+
+ if (bRc == TRUE)
+ {
+ last_error = GetLastError();
+ Fail("WriteFile: ERROR[%ld] -> Able to write to a NULL handle\n", last_error);
+ }
+
+
+ //
+ // Write to a file with read-only permissions
+ //
+
+ // create a file without write permissions
+ hFile = CreateFile(szReadOnlyFile,
+ GENERIC_READ,
+ FILE_SHARE_READ,
+ NULL,
+ OPEN_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if(hFile == INVALID_HANDLE_VALUE)
+ {
+ last_error = GetLastError();
+ Fail("WriteFile: ERROR[%ld] -> Unable to create file \"%s\".\n",
+ last_error, szReadOnlyFile);
+ }
+
+ if (!SetFileAttributes(szReadOnlyFile, FILE_ATTRIBUTE_READONLY))
+ {
+ last_error = GetLastError();
+ Trace("WriteFile: ERROR[%ld] -> Unable to make the file read-only.\n", last_error);
+ do_cleanup();
+ Fail("WriteFile: ERROR[%ld] -> Unable to make the file read-only.\n", last_error);
+ }
+
+ bRc = WriteFile(hFile, szStringTest, 20, &dwBytesWritten, NULL);
+ if (bRc == TRUE)
+ { last_error = GetLastError();
+ Trace("WriteFile: ERROR[%ld] -> Able to write to a read-only file.\n", last_error);
+ do_cleanup();
+ Fail("WriteFile: ERROR[%ld] -> Able to write to a read-only file.\n", last_error);
+ }
+
+
+ bRc = CloseHandle(hFile);
+ if (bRc != TRUE)
+ { last_error = GetLastError();
+ Trace("WriteFile: ERROR[%ld] -> Unable to close file \"%s\".\n", last_error, szReadOnlyFile);
+ do_cleanup();
+ Fail("WriteFile: ERROR -> Unable to close file \"%s\".\n",
+ szReadOnlyFile);
+ }
+
+ //To delete file need to make it normal
+ if(!SetFileAttributesA(szReadOnlyFile,FILE_ATTRIBUTE_NORMAL))
+ {
+ last_error = GetLastError();
+ Fail("WriteFile: ERROR[%ld] -> Unable to make the file attribute NORMAL.\n", last_error);
+
+ }
+ do_cleanup();
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/file_io/WriteFile/test1/testinfo.dat b/src/pal/tests/palsuite/file_io/WriteFile/test1/testinfo.dat
new file mode 100644
index 0000000000..148a2678e5
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/WriteFile/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = WriteFile
+Name = test for WriteFile
+Type = DEFAULT
+EXE1 = writefile
+Description
+=Attempt to write to a NULL handle and to a read-only file
+
diff --git a/src/pal/tests/palsuite/file_io/WriteFile/test2/CMakeLists.txt b/src/pal/tests/palsuite/file_io/WriteFile/test2/CMakeLists.txt
new file mode 100644
index 0000000000..a9b51efa3d
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/WriteFile/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ WriteFile.c
+)
+
+add_executable(paltest_writefile_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_writefile_test2 coreclrpal)
+
+target_link_libraries(paltest_writefile_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/WriteFile/test2/Results.txt b/src/pal/tests/palsuite/file_io/WriteFile/test2/Results.txt
new file mode 100644
index 0000000000..1c4c37885a
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/WriteFile/test2/Results.txt
@@ -0,0 +1 @@
+0011100111 \ No newline at end of file
diff --git a/src/pal/tests/palsuite/file_io/WriteFile/test2/WriteFile.c b/src/pal/tests/palsuite/file_io/WriteFile/test2/WriteFile.c
new file mode 100644
index 0000000000..24c148afb8
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/WriteFile/test2/WriteFile.c
@@ -0,0 +1,109 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: WriteFile.c (test 2)
+**
+** Purpose: Tests the PAL implementation of the WriteFile function.
+** Creates a number of files and writes different amounts of
+** data and verifies the writes.
+**
+**
+**===================================================================*/
+
+
+#include <palsuite.h>
+
+
+char* writeBuffer;
+const char* szWritableFile = "Writeable.txt";
+const char* szResultsFile = "Results.txt";
+#ifdef __sparc__
+const int PAGESIZE = 8192;
+#else // __sparc__
+const int PAGESIZE = 4096;
+#endif // __sparc__
+
+BOOL writeTest(DWORD dwByteCount, DWORD dwBytesWrittenResult, BOOL bResult)
+{
+ HANDLE hFile = NULL;
+ DWORD dwBytesWritten;
+ BOOL bRc = FALSE;
+
+ /* create the test file */
+ DeleteFile(szWritableFile);
+ hFile = CreateFile(szWritableFile, GENERIC_WRITE, FILE_SHARE_WRITE,
+ NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+
+ if(hFile == INVALID_HANDLE_VALUE)
+ {
+ Trace("WriteFile: ERROR -> Unable to create file \"%s\".\n",
+ szWritableFile);
+ return FALSE;
+ }
+
+ bRc = WriteFile(hFile, writeBuffer, dwByteCount, &dwBytesWritten, NULL);
+ CloseHandle(hFile);
+
+ if ((bRc != bResult) || (dwBytesWrittenResult != dwBytesWritten))
+ {
+ Trace("WriteFile returned BOOL:%d and dwWritten:%d what we do expect is"
+ " BOOL:%d and dwWritten:%d\n", bRc, dwBytesWritten, bResult,
+ dwBytesWrittenResult);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+int __cdecl main(int argc, char *argv[])
+{
+ const char * testString = "The quick fox jumped over the lazy dog's back.";
+ const int testStringLen = strlen(testString);
+
+ DWORD dwByteCount[4] = {-1, 10, testStringLen, 0};
+ DWORD dwByteWritten[4] = {0, 10, testStringLen, 0};
+ BOOL bResults[] = {FALSE, TRUE, TRUE, TRUE};
+
+ const int BUFFER_SIZE = 2 * PAGESIZE;
+ int j;
+ BOOL bRc = FALSE;
+ DWORD oldProt;
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ /* allocate read-write memery for writeBuffer */
+ if (!(writeBuffer = (char*) VirtualAlloc(NULL, BUFFER_SIZE, MEM_COMMIT,
+ PAGE_READWRITE)))
+ {
+ Fail("VirtualAlloc failed: GetLastError returns %d\n", GetLastError());
+ return FAIL;
+ }
+
+ memset((void*) writeBuffer, '.', BUFFER_SIZE);
+ strcpy(writeBuffer, testString);
+
+ /* write protect the second page of writeBuffer */
+ if (!VirtualProtect(&writeBuffer[PAGESIZE], PAGESIZE, PAGE_NOACCESS, &oldProt))
+ {
+ Fail("VirtualProtect failed: GetLastError returns %d\n", GetLastError());
+ return FAIL;
+ }
+
+ for (j = 0; j< 4; j++)
+ {
+ bRc = writeTest(dwByteCount[j], dwByteWritten[j], bResults[j]);
+ if (bRc != TRUE)
+ {
+ Fail("WriteFile: ERROR -> Failed on test[%d]\n", j);
+ }
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/file_io/WriteFile/test2/testinfo.dat b/src/pal/tests/palsuite/file_io/WriteFile/test2/testinfo.dat
new file mode 100644
index 0000000000..a09df962f3
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/WriteFile/test2/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = WriteFile
+Name = Positive Test for WriteFile
+Type = DEFAULT
+EXE1 = writefile
+Description
+=Multiple tests of writes of varying sizes with verification
+
diff --git a/src/pal/tests/palsuite/file_io/WriteFile/test3/CMakeLists.txt b/src/pal/tests/palsuite/file_io/WriteFile/test3/CMakeLists.txt
new file mode 100644
index 0000000000..e16e8a48f6
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/WriteFile/test3/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ WriteFile.c
+)
+
+add_executable(paltest_writefile_test3
+ ${SOURCES}
+)
+
+add_dependencies(paltest_writefile_test3 coreclrpal)
+
+target_link_libraries(paltest_writefile_test3
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/WriteFile/test3/WriteFile.c b/src/pal/tests/palsuite/file_io/WriteFile/test3/WriteFile.c
new file mode 100644
index 0000000000..751f89ff2c
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/WriteFile/test3/WriteFile.c
@@ -0,0 +1,136 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: WriteFile.c (test 3)
+**
+** Purpose: Tests the PAL implementation of the WriteFile function.
+** Performs multiple writes to a file and verifies the results.
+**
+**
+**===================================================================*/
+
+
+#include <palsuite.h>
+
+
+const char* szStringTest = "The quick fox jumped over the lazy dog's back.\0";
+const char* szWritableFile = "writeable.txt";
+
+
+BOOL validateResults(const char* szString)
+{
+ FILE *pFile = NULL;
+ char szReadString[100];
+ DWORD dwBytesRead;
+ DWORD dwStringLength = strlen(szString);
+
+
+
+ memset(szReadString, 0, 100);
+
+ /* open the file */
+ pFile = fopen(szWritableFile, "r");
+ if (pFile == NULL)
+ {
+ Trace("couldn't open test file\n");
+ return FALSE;
+ }
+
+ dwBytesRead = fread(szReadString, sizeof(char), dwStringLength, pFile);
+ fclose(pFile);
+
+ if(dwBytesRead != dwStringLength)
+ {
+ Trace("dwbyteread != string length\n");
+ return FALSE;
+ }
+
+ if (strcmp(szReadString, szString))
+ {
+ Trace("read = %s string = %s", szReadString, szString);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+
+
+
+BOOL writeTest(const char* szString)
+{
+ HANDLE hFile = NULL;
+ DWORD dwBytesWritten;
+ BOOL bRc = FALSE;
+ BOOL bAllPassed = TRUE;
+ int nStringLength = 0;
+ char* szPtr = NULL;
+ int i = 0;
+
+ // create the test file
+ hFile = CreateFile(szWritableFile,
+ GENERIC_WRITE,
+ FILE_SHARE_WRITE,
+ NULL,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if(hFile == INVALID_HANDLE_VALUE)
+ {
+ Trace("WriteFile: ERROR -> Unable to create file \"%s\".\n",
+ szWritableFile);
+ return FALSE;
+ }
+
+ nStringLength = strlen(szString);
+ szPtr = (char*) szString;
+
+ for (i = 0; i < nStringLength; i++)
+ {
+ bRc = WriteFile(hFile, szPtr++, 1, &dwBytesWritten, NULL);
+ if ((bRc == FALSE) || (dwBytesWritten != 1))
+ {
+ bAllPassed = FALSE;
+ }
+ }
+ CloseHandle(hFile);
+
+ if (bAllPassed == FALSE)
+ {
+ Trace ("WriteFile: ERROR: Failed to write data.\n");
+ return FALSE;
+ }
+ else
+ {
+ return (validateResults(szString));
+ }
+
+ return TRUE;
+}
+
+
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ const char *pString = szStringTest;
+ BOOL bRc = FALSE;
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+
+ bRc = writeTest(pString);
+ if (bRc != TRUE)
+ {
+ Fail("WriteFile: ERROR -> Failed\n");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/file_io/WriteFile/test3/testinfo.dat b/src/pal/tests/palsuite/file_io/WriteFile/test3/testinfo.dat
new file mode 100644
index 0000000000..e88e985b44
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/WriteFile/test3/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = WriteFile
+Name = Positive Test for WriteFile
+Type = DEFAULT
+EXE1 = writefile
+Description
+=Multiple consecutive writes to a file with verification
+
diff --git a/src/pal/tests/palsuite/file_io/WriteFile/test4/CMakeLists.txt b/src/pal/tests/palsuite/file_io/WriteFile/test4/CMakeLists.txt
new file mode 100644
index 0000000000..fff886b430
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/WriteFile/test4/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ writefile.c
+)
+
+add_executable(paltest_writefile_test4
+ ${SOURCES}
+)
+
+add_dependencies(paltest_writefile_test4 coreclrpal)
+
+target_link_libraries(paltest_writefile_test4
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/WriteFile/test4/testinfo.dat b/src/pal/tests/palsuite/file_io/WriteFile/test4/testinfo.dat
new file mode 100644
index 0000000000..87ddf9d857
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/WriteFile/test4/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = WriteFile
+Name = Positive Test for WriteFile
+Type = DEFAULT
+EXE1 = writefile
+Description
+= writes to a file at different locations with verification
+
diff --git a/src/pal/tests/palsuite/file_io/WriteFile/test4/writefile.c b/src/pal/tests/palsuite/file_io/WriteFile/test4/writefile.c
new file mode 100644
index 0000000000..47a0066ec9
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/WriteFile/test4/writefile.c
@@ -0,0 +1,155 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: WriteFile.c (test 4)
+**
+** Purpose: Tests the PAL implementation of the WriteFile function.
+** Performs multiple writes to a file at different locations
+** then verifies the results with GetFileSize.
+**
+** dependency:
+** CreateFile.
+** GetFileSize.
+** FlushFileBuffers
+** SetFilePointer.
+** CloseHandle.
+** DeleteFile.
+**
+**
+**
+**===================================================================*/
+
+
+#include <palsuite.h>
+
+BOOL CleanUp(HANDLE hFile, const char * fileName)
+{
+ BOOL bRc = TRUE;
+ if (CloseHandle(hFile) != TRUE)
+ {
+ bRc = FALSE;
+ Trace("WriteFile: ERROR -> Unable to close file \"%s\","
+ " error: %ld.\n", fileName, GetLastError());
+ }
+ if (!DeleteFileA(fileName))
+ {
+ bRc = FALSE;
+ Trace("WriteFile: ERROR -> Unable to delete file \"%s\","
+ " error: %ld.\n", fileName, GetLastError());
+ }
+ return bRc;
+}
+
+int __cdecl main(int argc, char *argv[])
+{
+ const char* szStringTest = "1234567890";
+ const char* szWritableFile = "writeable.txt";
+ HANDLE hFile = NULL;
+ DWORD dwBytesWritten;
+
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ /* create the test file */
+ hFile = CreateFile(szWritableFile,
+ GENERIC_WRITE,
+ FILE_SHARE_WRITE,
+ NULL,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if(hFile == INVALID_HANDLE_VALUE)
+ {
+ Fail("WriteFile: ERROR -> Unable to create file \"%s\".\n",
+ szWritableFile);
+ }
+
+
+ /* test wtriting to the file */
+ if( WriteFile(hFile, /* HANDLE handle to file */
+ szStringTest, /* data buffer */
+ strlen(szStringTest), /* number of bytes to write */
+ &dwBytesWritten, /* number of bytes written */
+ NULL) /* overlapped buffer */
+ ==0)
+ {
+ Trace("WriteFile: ERROR -> Unable to write to file error: %ld \n",
+ GetLastError());
+ CleanUp(hFile,szWritableFile);
+ Fail("");
+ }
+
+ if(!FlushFileBuffers(hFile))
+ { Trace("WriteFile: ERROR -> Call to FlushFile Buffers failed "
+ "error %ld \n",GetLastError());
+ CleanUp(hFile,szWritableFile);
+ Fail("");
+ }
+
+ /* check the file size */
+ if(GetFileSize(hFile, NULL)!=strlen(szStringTest))
+ {
+ Trace("WriteFile: ERROR -> writing %u chars to empty file "
+ "caused its size to become %u\n",strlen(szStringTest),
+ GetFileSize(hFile, NULL));
+ CleanUp(hFile,szWritableFile);
+ Fail("");
+ }
+
+ /* test writing to the file at position 5. */
+ SetFilePointer(
+ hFile, /* handle to file */
+ 0x5, /* bytes to move pointer */
+ NULL, /* bytes to move pointer */
+ FILE_BEGIN /* starting point */
+ );
+
+
+ if( WriteFile(hFile, /* HANDLE handle to file */
+ szStringTest, /* data buffer */
+ strlen(szStringTest), /* number of bytes to write */
+ &dwBytesWritten, /* number of bytes written */
+ NULL) /* overlapped buffer */
+ ==0)
+ {
+ Trace("WriteFile: ERROR -> Unable to write to file after "
+ " moiving the file poiner to 5 error: %ld \n",
+ GetLastError());
+ CleanUp(hFile,szWritableFile);
+ Fail("");
+ }
+
+
+ if(!FlushFileBuffers(hFile))
+ {
+ Trace("WriteFile: ERROR -> Call to FlushFile Buffers failed "
+ "error %ld \n",GetLastError());
+ CleanUp(hFile,szWritableFile);
+ Fail("");
+ }
+
+ /* Check the file size */
+ if(GetFileSize(hFile, NULL)!=(strlen(szStringTest)+5))
+ {
+ Trace("WriteFile: ERROR -> writing %u chars to the file after "
+ "sitting the file pointer to 5 resulted in wrong file size; "
+ "Expected %u resulted %u.",strlen(szStringTest),
+ (strlen(szStringTest)+5),GetFileSize(hFile, NULL));
+ CleanUp(hFile,szWritableFile);
+ Fail("");
+ }
+
+ if (!CleanUp(hFile,szWritableFile))
+ {
+ Fail("");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/file_io/WriteFile/test5/CMakeLists.txt b/src/pal/tests/palsuite/file_io/WriteFile/test5/CMakeLists.txt
new file mode 100644
index 0000000000..978eb7f1e7
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/WriteFile/test5/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ writefile.c
+)
+
+add_executable(paltest_writefile_test5
+ ${SOURCES}
+)
+
+add_dependencies(paltest_writefile_test5 coreclrpal)
+
+target_link_libraries(paltest_writefile_test5
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/WriteFile/test5/testinfo.dat b/src/pal/tests/palsuite/file_io/WriteFile/test5/testinfo.dat
new file mode 100644
index 0000000000..ffde30ea23
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/WriteFile/test5/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = WriteFile
+Name = Positive Test for WriteFile
+Type = DEFAULT
+EXE1 = writefile
+Description
+= write lots of data to a file. then check with
+= GetFileSize
+= This test is disabled due to its time overhead.
+
diff --git a/src/pal/tests/palsuite/file_io/WriteFile/test5/writefile.c b/src/pal/tests/palsuite/file_io/WriteFile/test5/writefile.c
new file mode 100644
index 0000000000..46920b3335
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/WriteFile/test5/writefile.c
@@ -0,0 +1,117 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: WriteFile.c (test 5)
+**
+** Purpose: Tests the PAL implementation of the WriteFile function.
+** Performs writing a huge file.
+**
+** dependency:
+** CreateFile.
+** GetFileSize.
+** FlushFileBuffers
+** CloseHandle
+** DeleteFile
+**
+**
+**===================================================================*/
+
+
+#include <palsuite.h>
+
+BOOL CleanUp(HANDLE hFile, const char * fileName)
+{
+ BOOL bRc = TRUE;
+ if (CloseHandle(hFile) != TRUE)
+ {
+ bRc = FALSE;
+ Trace("WriteFile: ERROR -> Unable to close file \"%s\","
+ " error: %ld.\n", fileName, GetLastError());
+ }
+ if (!DeleteFileA(fileName))
+ {
+ bRc = FALSE;
+ Trace("WriteFile: ERROR -> Unable to delete file \"%s\","
+ " error: %ld.\n", fileName, GetLastError());
+ }
+ return bRc;
+}
+
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ HANDLE hFile = NULL;
+ DWORD dwBytesWritten;
+ const char* hugeStringTest =
+ "1234567890123456789012345678901234567890";
+ const char* szWritableFile = "writeable.txt";
+ int i =0;
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ /* create the test file */
+ hFile = CreateFile(szWritableFile,
+ GENERIC_WRITE,
+ FILE_SHARE_WRITE,
+ NULL,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if(hFile == INVALID_HANDLE_VALUE)
+ {
+ Fail("WriteFile: ERROR -> Unable to create file \"%s\".\n",
+ szWritableFile);
+ }
+
+ /* write 4000 000 chars to the file.*/
+ for (i=0; i<100000;i++)
+ {
+ if( WriteFile(hFile, /* HANDLE handle to file */
+ hugeStringTest, /* data buffer */
+ strlen(hugeStringTest), /* number of bytes to write */
+ &dwBytesWritten, /* number of bytes written */
+ NULL) /* overlapped buffer */
+ ==0)
+ {
+ Trace("WriteFile: ERROR -> Unable to write to file error: %ld \n",
+ GetLastError());
+ CleanUp(hFile,szWritableFile);
+ Fail("");
+
+ }
+ }
+
+ if(!FlushFileBuffers(hFile))
+ {
+ Trace("WriteFile: ERROR -> Call to FlushFileBuffers failed"
+ "error %ld \n",GetLastError());
+ CleanUp(hFile,szWritableFile);
+ Fail("");
+ }
+
+ /* test if the size changed properly. */
+ if(GetFileSize(hFile,NULL) != 4000000)
+ {
+ Trace("WriteFile: ERROR -> file size did not change properly"
+ " after writing 4000 000 chars to it ( size= %u )\n",
+ GetFileSize(hFile,NULL));
+ CleanUp(hFile,szWritableFile);
+ Fail("");
+
+ }
+
+ if (!CleanUp(hFile,szWritableFile))
+ {
+ Fail("");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/file_io/errorpathnotfound/CMakeLists.txt b/src/pal/tests/palsuite/file_io/errorpathnotfound/CMakeLists.txt
new file mode 100644
index 0000000000..a3847f8ca9
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/errorpathnotfound/CMakeLists.txt
@@ -0,0 +1,7 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+add_subdirectory(test3)
+add_subdirectory(test4)
+
diff --git a/src/pal/tests/palsuite/file_io/errorpathnotfound/test1/CMakeLists.txt b/src/pal/tests/palsuite/file_io/errorpathnotfound/test1/CMakeLists.txt
new file mode 100644
index 0000000000..91b7db1f03
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/errorpathnotfound/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_errorpathnotfound_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_errorpathnotfound_test1 coreclrpal)
+
+target_link_libraries(paltest_errorpathnotfound_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/errorpathnotfound/test1/test1.c b/src/pal/tests/palsuite/file_io/errorpathnotfound/test1/test1.c
new file mode 100644
index 0000000000..eaf3db3a30
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/errorpathnotfound/test1/test1.c
@@ -0,0 +1,783 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+
+**
+
+** Source: test1.c
+
+**
+
+** Purpose: Test the return value of GetLastError() after calling
+
+** some file_io functions with an invalid path.
+
+**
+
+** Functions covered by this test are:
+
+** CopyFileA, CopyFileW, CreateFileA,CreateFileW,
+
+** DeleteFileA and DeleteFileW.
+
+**
+**
+
+
+
+**
+
+**===================================================================*/
+
+
+
+#include <palsuite.h>
+
+
+
+int __cdecl main(int argc, char *argv[])
+
+{
+
+
+
+ BOOL testPass = TRUE;
+
+ BOOL bRc = TRUE;
+
+ HANDLE hFile;
+
+
+
+ const char* sBadFilePath = "bad/badPath.tmp";
+
+ const char* sBadFileName = "badName.tmp";
+
+ const char* sDest = "dest.tmp";
+
+ const WCHAR wBadFilePath[] =
+
+ {'w','b','a','d','/','b','a',
+
+ 'd','.','t','m','p','\0'};
+
+ const WCHAR wBadFileName[] =
+
+ {'w','B','a','d','.','t','m','p','\0'};
+
+ const WCHAR wDest[] =
+
+ {'w','d','e','s','t','.','t','m','p','\0'};
+
+
+
+
+
+ if (0 != PAL_Initialize(argc,argv))
+
+ {
+
+ return FAIL;
+
+ }
+
+
+
+ /*...................Test CopyFileW.............................*/
+
+
+
+ /* test with an invalid path */
+
+ bRc = CopyFileW(wBadFilePath,wDest,TRUE);
+
+ if(!bRc)
+
+ {
+
+ if(GetLastError()!= ERROR_PATH_NOT_FOUND)
+
+ {
+
+ Trace("CopyFileW: calling GetLastError() after copying a file"
+
+ " with wrong path returned [%u] while it should return [%u]\n"
+
+ ,GetLastError(), ERROR_PATH_NOT_FOUND);
+
+ testPass = FALSE;
+
+ }
+
+ }
+
+ else
+
+ {
+
+ testPass = FALSE;
+
+ }
+
+
+
+ /* test with invalid file name */
+
+ bRc = CopyFileW(wBadFileName,wDest,TRUE);
+
+ if(!bRc)
+
+ {
+
+ if(GetLastError()!= ERROR_FILE_NOT_FOUND)
+
+ {
+
+ Trace("CopyFileW: calling GetLastError() after copying a file"
+
+ " with wrong name returned [%u] while it should return [%u]\n"
+
+ ,GetLastError(), ERROR_FILE_NOT_FOUND);
+
+ testPass = FALSE;
+
+ }
+
+
+
+ }
+
+ else
+
+ {
+
+ Trace("CopyFileW: managed to copy a file with wrong name\n");
+
+ testPass = FALSE;
+
+ }
+
+
+
+
+
+
+
+ /*..................CopyFileA...................................*/
+
+
+
+ /* test with an invalid path */
+
+ bRc = CopyFileA(sBadFilePath,sDest,TRUE);
+
+ if(! bRc)
+
+ {
+
+ if(GetLastError()!= ERROR_PATH_NOT_FOUND)
+
+ {
+
+ Trace("CopyFileA: calling GetLastError() after copying a file"
+
+ " with wrong path returned [%u] while it should return [%u]\n"
+
+ ,GetLastError(), ERROR_PATH_NOT_FOUND);
+
+ testPass = FALSE;
+
+ }
+
+ }
+
+ else
+
+ {
+
+ Trace("CopyFileA: managed to copy a file with wrong path\n");
+
+ testPass = FALSE;
+
+ }
+
+
+
+ /* test with an invalid file name */
+
+ bRc = CopyFileA(sBadFileName,sDest,TRUE);
+
+ if(! bRc)
+
+ {
+
+ if(GetLastError()!= ERROR_FILE_NOT_FOUND)
+
+ {
+
+ Trace("CopyFileA: calling GetLastError() after copying a file"
+
+ " with wrong name returned [%u] while it should return [%u]\n"
+
+ ,GetLastError(), ERROR_FILE_NOT_FOUND);
+
+ testPass = FALSE;
+
+ }
+
+ }
+
+ else
+
+ {
+
+ Trace("CopyFileA: managed to copy a file with wrong name\n");
+
+ testPass = FALSE;
+
+ }
+
+
+
+
+
+
+
+ /*............. Test CreateFileA..................................*/
+
+
+
+ /* test with an invalid file name */
+
+ hFile = CreateFileA(sBadFileName,
+
+ GENERIC_READ, /* open for reading */
+
+ FILE_SHARE_READ, /* share for reading */
+
+ NULL, /* no security */
+
+ OPEN_EXISTING, /* existing file only */
+
+ FILE_ATTRIBUTE_NORMAL, /* normal file */
+
+ NULL); /* no attr. template */
+
+
+
+ if (hFile == INVALID_HANDLE_VALUE)
+
+ {
+
+ if(GetLastError() != ERROR_FILE_NOT_FOUND)
+
+ {
+
+ Trace("CreateFileA: calling GetLastError() returned [%u] "
+
+ "while it should return [%u] for a bad File Name\n",
+
+ GetLastError(),ERROR_FILE_NOT_FOUND);
+
+ testPass = FALSE;
+
+ }
+
+
+
+ }
+
+ else
+
+ {
+
+ Trace("CreateFileA: managed to create a file with an incorrect "
+
+ "filename\n");
+
+ testPass = FALSE;
+
+
+
+ if(!CloseHandle(hFile))
+
+ {
+
+ Trace("CreateFileA: Call to CloseHandle failed with ErrorCode "
+
+ "[%u]\n", GetLastError());
+
+
+
+ }
+
+ if(!DeleteFile(sBadFileName))
+
+ {
+
+ Trace("CreateFileA: Call to DeleteFile failed with ErrorCode "
+
+ "[%u]\n", GetLastError());
+
+ }
+
+ }
+
+
+
+ /* test with an invalid path */
+
+ hFile = CreateFileA(sBadFilePath,
+
+ GENERIC_READ, /* open for reading */
+
+ FILE_SHARE_READ, /* share for reading */
+
+ NULL, /* no security */
+
+ OPEN_EXISTING, /* existing file only */
+
+ FILE_ATTRIBUTE_NORMAL, /* normal file */
+
+ NULL); /* no attr. template */
+
+
+
+ if (hFile == INVALID_HANDLE_VALUE)
+
+ {
+
+ if(GetLastError() != ERROR_PATH_NOT_FOUND)
+
+ {
+
+ Trace("CreateFileA: calling GetLastError() returned [%u] "
+
+ "while it should return [%u] for a bad file path name\n",
+
+ GetLastError(), ERROR_PATH_NOT_FOUND);
+
+ testPass = FALSE;
+
+ }
+
+
+
+ }
+
+ else
+
+ {
+
+ Trace("CreateFileA: managed to create a file with an incorrect "
+
+ "filename\n");
+
+ testPass = FALSE;
+
+ /*this should not happen*/
+
+ if(!CloseHandle(hFile))
+
+ {
+
+ Trace("CreateFileA: Call to CloseHandle Failed with ErrorCode "
+
+ "[%u]\n", GetLastError());
+
+
+
+ }
+
+ if(!DeleteFile(sBadFilePath))
+
+ {
+
+ Trace("CreateFileA: Call to DeleteFile Failed with ErrorCode "
+
+ "[%u]\n", GetLastError());
+
+ }
+
+ }
+
+
+
+
+
+
+
+
+
+ /*............. Test CreateFileW..................................*/
+
+
+
+ /* test with an invalid file name */
+
+ hFile = CreateFileW(wBadFileName,
+
+ GENERIC_READ, /* open for reading */
+
+ FILE_SHARE_READ, /* share for reading */
+
+ NULL, /* no security */
+
+ OPEN_EXISTING, /* existing file only */
+
+ FILE_ATTRIBUTE_NORMAL, /* normal file */
+
+ NULL); /* no attr. template */
+
+
+
+ if (hFile == INVALID_HANDLE_VALUE)
+
+ {
+
+ if(GetLastError() != ERROR_FILE_NOT_FOUND)
+
+ {
+
+ Trace("CreateFileW: calling GetLastError() returned [%u] "
+
+ "while it should return [%u] for a bad filename\n",
+
+ GetLastError(), ERROR_FILE_NOT_FOUND);
+
+ testPass = FALSE;
+
+ }
+
+
+
+ }
+
+ else
+
+ {
+
+ Trace("CreateFileW: managed to create a file with an incorrect "
+
+ "filename\n");
+
+ testPass = FALSE;
+
+
+
+ if(!CloseHandle(hFile))
+
+ {
+
+ Trace("CreateFileW: Call to CloseHandle Failed with ErrorCode "
+
+ "[%u]\n", GetLastError());
+
+
+
+ }
+
+
+
+ if(!DeleteFileW(wBadFileName))
+
+ {
+
+ Trace("CreateFileW: Call to DeleteFile Failed with ErrorCode "
+
+ "[%u]\n", GetLastError());
+
+ }
+
+ }
+
+
+
+
+
+
+
+ /* test with an invalid path */
+
+ hFile = CreateFileW(wBadFilePath,
+
+ GENERIC_READ, /* open for reading */
+
+ FILE_SHARE_READ, /* share for reading */
+
+ NULL, /* no security */
+
+ OPEN_EXISTING, /* existing file only */
+
+ FILE_ATTRIBUTE_NORMAL, /* normal file */
+
+ NULL); /* no attr. template */
+
+
+
+ if (hFile == INVALID_HANDLE_VALUE)
+
+ {
+
+
+
+ if(GetLastError() != ERROR_PATH_NOT_FOUND)
+
+ {
+
+ Trace("CreateFileW: calling GetLastError() returned [%u] "
+
+ "while it should return [%u] for a bad file path \n",
+
+ GetLastError(), ERROR_FILE_NOT_FOUND);
+
+ testPass = FALSE;
+
+ }
+
+
+
+ }
+
+ else
+
+ {
+
+ Trace("CreateFileW: managed to create a file with an incorrect "
+
+ "filename\n");
+
+ testPass = FALSE;
+
+
+
+ if(!CloseHandle(hFile))
+
+ {
+
+ Trace("CreateFileW: Call to CloseHandle Failed with ErrorCode "
+
+ "[%u]\n", GetLastError());
+
+
+
+ }
+
+ if(!DeleteFileW(wBadFilePath))
+
+ {
+
+ Trace("CreateFileW: Call to DeleteFile Failed with ErrorCode "
+
+ "[%u]\n", GetLastError());
+
+ }
+
+ }
+
+
+
+
+
+
+
+ /* ............. DeleteFileW..................................*/
+
+
+
+ /* test with an invalid path */
+
+ if(DeleteFileW(wBadFilePath))
+
+ {
+
+ Trace("DeleteFileW: Call to DeleteFileW to delete a file"
+
+ " that does not exist succeeded\n");
+
+ testPass = FALSE;
+
+
+
+ }
+
+ else
+
+ {
+
+ if(GetLastError() != ERROR_PATH_NOT_FOUND)
+
+ {
+
+ Trace("DeleteFileW: Call GetLastError()returned "
+
+ "[%u] while it should return ERROR_PATH_NOT_FOUND [%u]\n",
+
+ GetLastError(),ERROR_FILE_NOT_FOUND);
+
+ testPass = FALSE;
+
+
+
+ }
+
+
+
+ }
+
+
+
+ /* test with an invalid file name */
+
+ if(DeleteFileW(wBadFileName))
+
+ {
+
+ Trace("DeleteFileW: Call to DeleteFileW to delete a file"
+
+ " that does not exist succeeded\n");
+
+ testPass = FALSE;
+
+
+
+ }
+
+ else
+
+ {
+
+ if(GetLastError() != ERROR_FILE_NOT_FOUND)
+
+ {
+
+ Trace("DeleteFileW: Call GetLastError()returned [%u]"
+
+ " while it should return ERROR_FILE_NOT_FOUND [%u]\n",
+
+ GetLastError(),ERROR_FILE_NOT_FOUND);
+
+ testPass = FALSE;
+
+
+
+ }
+
+
+
+ }
+
+
+
+
+
+ /* ............. DeleteFileA..................................*/
+
+
+
+ /* test with an invalid path */
+
+ if(DeleteFileA(sBadFilePath))
+
+ {
+
+ Trace("DeleteFileA: Call to DeleteFileA to delete a file"
+
+ " that does not exist succeeded\n");
+
+ testPass = FALSE;
+
+
+
+ }
+
+ else
+
+ {
+
+ if(GetLastError() != ERROR_PATH_NOT_FOUND)
+
+ {
+
+ Trace("DeleteFileA: Call GetLastError() returned [%u]"
+
+ " while it should return ERROR_PATH_NOT_FOUND [%u]\n",
+
+ GetLastError(),ERROR_FILE_NOT_FOUND);
+
+ testPass = FALSE;
+
+
+
+ }
+
+
+
+ }
+
+
+
+ /* test with an invalid file name */
+
+ if(DeleteFileA(sBadFileName))
+
+ {
+
+ Trace("DeleteFileA: Call to DeleteFileA to delete a file"
+
+ " that does not exist succeeded\n");
+
+ testPass = FALSE;
+
+
+
+ }
+
+ else
+
+ {
+
+ if(GetLastError() != ERROR_FILE_NOT_FOUND)
+
+ {
+
+ Trace("DeleteFileA: Call GetLastError() returned [%u]"
+
+ " while it should return ERROR_FILE_NOT_FOUND [%u]\n",
+
+ GetLastError(),ERROR_FILE_NOT_FOUND);
+
+ testPass = FALSE;
+
+
+
+ }
+
+
+
+ }
+
+
+
+
+
+
+
+ if(! testPass)
+
+ {
+
+ Fail("");
+
+ }
+
+ PAL_Terminate();
+
+ return PASS;
+
+}
+
+
+
diff --git a/src/pal/tests/palsuite/file_io/errorpathnotfound/test1/testinfo.dat b/src/pal/tests/palsuite/file_io/errorpathnotfound/test1/testinfo.dat
new file mode 100644
index 0000000000..dc1ddc96f1
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/errorpathnotfound/test1/testinfo.dat
@@ -0,0 +1,31 @@
+# Licensed to the .NET Foundation under one or more agreements.
+
+# The .NET Foundation licenses this file to you under the MIT license.
+
+# See the LICENSE file in the project root for more information.
+
+
+
+
+Version = 1.0
+
+Section = file_io
+
+Function = some File_io functions
+
+Name = errorpathnotfound - checking GetLastError.
+
+Type = DEFAULT
+
+EXE1 = test1
+
+Description
+
+= Test the return value of GetLastError() after calling
+
+= some file_io functions with an invalid path.
+
+= Functions covered by this test are:
+
+= CopyFile, CreateFile and DeleteFile.
+
diff --git a/src/pal/tests/palsuite/file_io/errorpathnotfound/test2/CMakeLists.txt b/src/pal/tests/palsuite/file_io/errorpathnotfound/test2/CMakeLists.txt
new file mode 100644
index 0000000000..7d525c21d5
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/errorpathnotfound/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test2.c
+)
+
+add_executable(paltest_errorpathnotfound_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_errorpathnotfound_test2 coreclrpal)
+
+target_link_libraries(paltest_errorpathnotfound_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/errorpathnotfound/test2/test2.c b/src/pal/tests/palsuite/file_io/errorpathnotfound/test2/test2.c
new file mode 100644
index 0000000000..5c2ab86b99
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/errorpathnotfound/test2/test2.c
@@ -0,0 +1,785 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+
+**
+
+** Source: test2.c
+
+**
+
+** Purpose: Test the return value of GetLastError() after calling
+
+** some file_io functions with an invalid path.
+
+**
+
+** Functions covered by this test are:
+
+** MoveFileW, FindFirstFileA, FindFirstFileW,
+
+** GetFileAttributesA, GetFileAttributesW,
+
+** SetFileAttributesA, SetFileAttributesW.
+
+**
+**
+
+**
+
+
+
+**
+
+**===================================================================*/
+
+
+
+#include <palsuite.h>
+
+
+
+int __cdecl main(int argc, char *argv[])
+
+{
+
+
+
+ BOOL testPass = TRUE;
+
+ BOOL bRc = TRUE;
+
+ HANDLE hFile;
+
+ WIN32_FIND_DATA findFileData;
+
+ WIN32_FIND_DATAW wFindFileData;
+
+ DWORD fileAttrib;
+
+
+
+ const char* sBadFilePath = "bad/badPath.tmp";
+
+ const char* sBadFileName = "badName.tmp";
+
+
+
+ const WCHAR wBadFilePath[] =
+
+ {'w','b','a','d','/','b','a',
+
+ 'd','.','t','m','p','\0'};
+
+ const WCHAR wBadFileName[] =
+
+ {'w','B','a','d','.','t','m','p','\0'};
+
+ const WCHAR wDest[] =
+
+ {'w','d','e','s','t','.','t','m','p','\0'};
+
+
+
+
+
+ if (0 != PAL_Initialize(argc,argv))
+
+ {
+
+ return FAIL;
+
+ }
+
+
+
+ /*...................Test MoveFileW.............................*/
+
+
+
+ /* test with an invalid path */
+
+ bRc = MoveFileW(wBadFilePath,wDest);
+
+ if(!bRc)
+
+ {
+
+ if(GetLastError()!= ERROR_PATH_NOT_FOUND)
+
+ {
+
+ Trace("MoveFileW: calling GetLastError() after moving a file"
+
+ " with wrong path returned [%u] while it should return [%u]\n"
+
+ ,GetLastError(), ERROR_PATH_NOT_FOUND);
+
+ testPass = FALSE;
+
+ }
+
+ }
+
+ else
+
+ {
+
+ testPass = FALSE;
+
+ }
+
+
+
+ /* test with invalid file name */
+
+ bRc = MoveFileW(wBadFileName,wDest);
+
+ if(!bRc)
+
+ {
+
+ if(GetLastError()!= ERROR_FILE_NOT_FOUND)
+
+ {
+
+ Trace("MoveFileW: calling GetLastError() after moving a file"
+
+ " with wrong name returned [%u] while it should return [%u]\n"
+
+ ,GetLastError(), ERROR_FILE_NOT_FOUND);
+
+ testPass = FALSE;
+
+ }
+
+ }
+
+ else
+
+ {
+
+ Trace("MoveFileW: managed to move a file with wrong name\n");
+
+ testPass = FALSE;
+
+ }
+
+
+
+ /*............. Test FindFirstFileA..................................*/
+
+
+
+ /* test with an invalid file name */
+
+ hFile = FindFirstFileA(sBadFileName,&findFileData );
+
+
+
+ if (hFile == INVALID_HANDLE_VALUE)
+
+ {
+
+ if(GetLastError() != ERROR_FILE_NOT_FOUND)
+
+ {
+
+ Trace("FindFirstFileA: calling GetLastError() returned [%u] "
+
+ "while it should return [%u] for a bad File Name\n",
+
+ GetLastError(),ERROR_FILE_NOT_FOUND);
+
+ testPass = FALSE;
+
+ }
+
+
+
+ }
+
+ else
+
+ {
+
+ Trace("FindFirstFileA: managed to find a file with an incorrect "
+
+ "filename\n");
+
+ testPass = FALSE;
+
+
+
+ if(!FindClose(hFile))
+
+ {
+
+ Trace("FindFirstFileA: Call to FindClose failed with ErrorCode"
+
+ " [%u]\n", GetLastError());
+
+
+
+ }
+
+
+
+ }
+
+
+
+ /* test with an invalid path */
+
+ hFile = FindFirstFileA(sBadFilePath,&findFileData);
+
+
+
+ if (hFile == INVALID_HANDLE_VALUE)
+
+ {
+
+ if(GetLastError() != ERROR_PATH_NOT_FOUND)
+
+ {
+
+ Trace("FindFirstFileA: calling GetLastError() returned [%u] "
+
+ "while it should return [%u] for a bad file path name\n",
+
+ GetLastError(), ERROR_PATH_NOT_FOUND);
+
+ testPass = FALSE;
+
+ }
+
+
+
+ }
+
+ else
+
+ {
+
+ Trace("FindFirstFileA: managed to find a file with an incorrect"
+
+ " filename\n");
+
+ testPass = FALSE;
+
+ /*this should not happen*/
+
+ if(!FindClose(hFile))
+
+ {
+
+ Trace("FindFirstFileA: Call to FindClose Failed with ErrorCode"
+
+ " [%u]\n", GetLastError());
+
+
+
+ }
+
+
+
+ }
+
+
+
+
+
+
+
+ /*............. Test FindFirstFileW..................................*/
+
+
+
+ /* test with an invalid file name */
+
+ hFile = FindFirstFileW(wBadFileName,&wFindFileData );
+
+
+
+ if (hFile == INVALID_HANDLE_VALUE)
+
+ {
+
+ if(GetLastError() != ERROR_FILE_NOT_FOUND)
+
+ {
+
+ Trace("FindFirstFileW: calling GetLastError() returned [%u] "
+
+ "while it should return [%u] for a bad File Name\n",
+
+ GetLastError(),ERROR_FILE_NOT_FOUND);
+
+ testPass = FALSE;
+
+ }
+
+
+
+ }
+
+ else
+
+ {
+
+ Trace("FindFirstFileW: managed to find a file with an incorrect "
+
+ "filename\n");
+
+ testPass = FALSE;
+
+
+
+ if(!FindClose(hFile))
+
+ {
+
+ Trace("FindFirstFileW: Call to FindClose failed with ErrorCode"
+
+ " [%u]\n", GetLastError());
+
+
+
+ }
+
+
+
+ }
+
+
+
+ /* test with an invalid path */
+
+ hFile = FindFirstFileW(wBadFilePath,&wFindFileData);
+
+
+
+ if (hFile == INVALID_HANDLE_VALUE)
+
+ {
+
+ if(GetLastError() != ERROR_PATH_NOT_FOUND)
+
+ {
+
+ Trace("FindFirstFileW: calling GetLastError() returned [%u] "
+
+ "while it should return [%u] for a bad file path name\n",
+
+ GetLastError(), ERROR_PATH_NOT_FOUND);
+
+ testPass = FALSE;
+
+ }
+
+
+
+ }
+
+ else
+
+ {
+
+ Trace("FindFirstFileW: managed to find a file with an incorrect "
+
+ "filename\n");
+
+ testPass = FALSE;
+
+ /*this should not happen*/
+
+ if(!FindClose(hFile))
+
+ {
+
+ Trace("FindFirstFileW: Call to FindClose Failed with ErrorCode "
+
+ "[%u]\n", GetLastError());
+
+
+
+ }
+
+
+
+ }
+
+
+
+
+
+ /*...................Test GetFileAttributesW.............................*/
+
+
+
+ /* test with an invalid path */
+
+ fileAttrib = GetFileAttributesW(wBadFilePath);
+
+ if(fileAttrib == -1)
+
+ {
+
+ if(GetLastError()!= ERROR_PATH_NOT_FOUND)
+
+ {
+
+ Trace("GetFileAttributesW: calling GetLastError() after getting"
+
+ " the attributes of a file with wrong path returned [%u]"
+
+ " while it should return [%u]\n",
+
+ GetLastError(), ERROR_PATH_NOT_FOUND);
+
+ testPass = FALSE;
+
+ }
+
+ }
+
+ else
+
+ {
+
+ Trace("GetFileAttributesW: managed to get the attrib of a file"
+
+ " with wrong path\n");
+
+ testPass = FALSE;
+
+ }
+
+
+
+ /* test with invalid file name */
+
+ fileAttrib = GetFileAttributesW(wBadFileName);
+
+ if(fileAttrib == -1)
+
+ {
+
+ if(GetLastError()!= ERROR_FILE_NOT_FOUND)
+
+ {
+
+ Trace("GetFileAttributesW: calling GetLastError() after getting"
+
+ " the attributes of a file with wrong name returned [%u] "
+
+ "while it should return [%u]\n"
+
+ ,GetLastError(), ERROR_FILE_NOT_FOUND);
+
+ testPass = FALSE;
+
+ }
+
+ }
+
+ else
+
+ {
+
+ Trace("GetFileAttributesW: managed to get the attrib of a file"
+
+ " with wrong name\n");
+
+ testPass = FALSE;
+
+ }
+
+
+
+ /*...................Test GetFileAttributesA.............................*/
+
+
+
+ /* test with an invalid path */
+
+ fileAttrib = GetFileAttributesA(sBadFilePath);
+
+ if(fileAttrib == -1)
+
+ {
+
+ if(GetLastError()!= ERROR_PATH_NOT_FOUND)
+
+ {
+
+ Trace("GetFileAttributesA: calling GetLastError() after getting"
+
+ " the attributes of a file with wrong path returned [%u] while"
+
+ " it should return [%u]\n",
+
+ GetLastError(), ERROR_PATH_NOT_FOUND);
+
+ testPass = FALSE;
+
+ }
+
+ }
+
+ else
+
+ {
+
+ Trace("GetFileAttributesA: managed to get the attrib of a file"
+
+ " with wrong path\n");
+
+ testPass = FALSE;
+
+ }
+
+
+
+ /* test with invalid file name */
+
+ fileAttrib = GetFileAttributesA(sBadFileName);
+
+ if(fileAttrib == -1)
+
+ {
+
+ if(GetLastError()!= ERROR_FILE_NOT_FOUND)
+
+ {
+
+ Trace("GetFileAttributesA: calling GetLastError() after getting "
+
+ "the attributes of a file with wrong name returned [%u] "
+
+ "while it should return [%u]\n"
+
+ ,GetLastError(), ERROR_FILE_NOT_FOUND);
+
+ testPass = FALSE;
+
+ }
+
+
+
+ }
+
+ else
+
+ {
+
+ Trace("GetFileAttributesA: managed to get the attrib of a file with"
+
+ " wrong name\n");
+
+ testPass = FALSE;
+
+ }
+
+
+
+
+
+
+
+
+
+ /*...................Test SetFileAttributesW.............................*/
+
+
+
+ /* test with an invalid path */
+
+ bRc = SetFileAttributesW(wBadFilePath,FILE_ATTRIBUTE_NORMAL);
+
+ if(!bRc)
+
+ {
+
+ if(GetLastError()!= ERROR_PATH_NOT_FOUND)
+
+ {
+
+ Trace("SetFileAttributesW: calling GetLastError() after setting"
+
+ " the attributes of a file with wrong path returned [%u] "
+
+ "while it should return [%u]\n",
+
+ GetLastError(), ERROR_PATH_NOT_FOUND);
+
+ testPass = FALSE;
+
+ }
+
+ }
+
+ else
+
+ {
+
+ Trace("SetFileAttributesW: managed to get the attrib of a file"
+
+ " with wrong path\n");
+
+ testPass = FALSE;
+
+ }
+
+
+
+ /* test with invalid file name */
+
+ bRc = SetFileAttributesW(wBadFileName,FILE_ATTRIBUTE_NORMAL);
+
+ if(!bRc)
+
+ {
+
+ if(GetLastError()!= ERROR_FILE_NOT_FOUND)
+
+ {
+
+ Trace("SetFileAttributesW: calling GetLastError() after setting"
+
+ " the attributes of a file with wrong name returned [%u]"
+
+ " while it should return [%u]\n",
+
+ GetLastError(), ERROR_FILE_NOT_FOUND);
+
+ testPass = FALSE;
+
+ }
+
+
+
+ }
+
+ else
+
+ {
+
+ Trace("SetFileAttributesW: managed to get the attrib of a file with"
+
+ " wrong name\n");
+
+ testPass = FALSE;
+
+ }
+
+
+
+
+
+ /*...................Test SetFileAttributesA.............................*/
+
+
+
+ /* test with an invalid path */
+
+ bRc = SetFileAttributesA(sBadFilePath,FILE_ATTRIBUTE_NORMAL);
+
+ if(!bRc)
+
+ {
+
+ if(GetLastError()!= ERROR_PATH_NOT_FOUND)
+
+ {
+
+ Trace("SetFileAttributesA: calling GetLastError() after setting "
+
+ "the attributes of a file with wrong path returned [%u] "
+
+ "while it should return [%u]\n"
+
+ ,GetLastError(), ERROR_PATH_NOT_FOUND);
+
+ testPass = FALSE;
+
+ }
+
+ }
+
+ else
+
+ {
+
+ Trace("SetFileAttributesA: managed to get the attrib of a file "
+
+ "with wrong path\n");
+
+ testPass = FALSE;
+
+ }
+
+
+
+ /* test with invalid file name */
+
+ bRc = SetFileAttributesA(sBadFileName,FILE_ATTRIBUTE_NORMAL);
+
+ if(!bRc)
+
+ {
+
+ if(GetLastError()!= ERROR_FILE_NOT_FOUND)
+
+ {
+
+ Trace("SetFileAttributesA: calling GetLastError() after setting"
+
+ " the attributes of a file with wrong name returned [%u]"
+
+ " while it should return [%u]\n",
+
+ GetLastError(), ERROR_FILE_NOT_FOUND);
+
+ testPass = FALSE;
+
+ }
+
+
+
+ }
+
+ else
+
+ {
+
+ Trace("SetFileAttributesA: managed to get the attrib of a file with "
+
+ "wrong name\n");
+
+ testPass = FALSE;
+
+ }
+
+
+
+
+
+ if(! testPass)
+
+ {
+
+ Fail("");
+
+ }
+
+ PAL_Terminate();
+
+ return PASS;
+
+}
+
+
+
diff --git a/src/pal/tests/palsuite/file_io/errorpathnotfound/test2/testinfo.dat b/src/pal/tests/palsuite/file_io/errorpathnotfound/test2/testinfo.dat
new file mode 100644
index 0000000000..c5a61b949a
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/errorpathnotfound/test2/testinfo.dat
@@ -0,0 +1,34 @@
+# Licensed to the .NET Foundation under one or more agreements.
+
+# The .NET Foundation licenses this file to you under the MIT license.
+
+# See the LICENSE file in the project root for more information.
+
+
+
+Version = 1.0
+
+Section = file_io
+
+Function = some File_io functions
+
+Name = errorpathnotfound - checking GetLastError.
+
+Type = DEFAULT
+
+EXE1 = test2
+
+Description
+
+= Test the return value of GetLastError() after calling
+
+= some file_io functions with an invalid path.
+
+= Functions covered by this test are:
+
+= MoveFileW, FindFirstFileA, FindFirstFileW,
+
+= GetFileAttributesA, GetFileAttributesW,
+
+= SetFileAttributesA, SetFileAttributesW.
+
diff --git a/src/pal/tests/palsuite/file_io/errorpathnotfound/test3/CMakeLists.txt b/src/pal/tests/palsuite/file_io/errorpathnotfound/test3/CMakeLists.txt
new file mode 100644
index 0000000000..c7434f3dba
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/errorpathnotfound/test3/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test3.c
+)
+
+add_executable(paltest_errorpathnotfound_test3
+ ${SOURCES}
+)
+
+add_dependencies(paltest_errorpathnotfound_test3 coreclrpal)
+
+target_link_libraries(paltest_errorpathnotfound_test3
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/errorpathnotfound/test3/test3.c b/src/pal/tests/palsuite/file_io/errorpathnotfound/test3/test3.c
new file mode 100644
index 0000000000..414cbab176
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/errorpathnotfound/test3/test3.c
@@ -0,0 +1,244 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+
+**
+
+** Source: test3.c
+
+**
+
+** Purpose: Test the return value of GetLastError() after calling
+
+** some file_io functions with an invalid path.
+
+**
+
+** Functions covered by this test are:
+
+** CreateDirectoryA, CreateDirectoryW, RemoveDirectoryW,
+
+**
+**
+
+
+
+**
+
+**===================================================================*/
+
+
+
+#include <palsuite.h>
+
+
+
+int __cdecl main(int argc, char *argv[])
+
+{
+
+
+
+ BOOL testPass = TRUE;
+
+ BOOL bRc = TRUE;
+
+ DWORD errCode;
+
+
+
+ const char* sBadSubDirectory = "bad/badDir";
+
+
+
+ /* Needed for RemoveDirectoryW */
+
+ const WCHAR tempName[] = {'b','a','d','/',
+
+ 'b','a','d','D','i','r'};
+
+
+
+ const WCHAR wBadSubDirectory[] =
+
+ {'w','b','a','d','/','b','a',
+
+ 'd','D','i','r','\0'};
+
+
+
+ if (0 != PAL_Initialize(argc,argv))
+
+ {
+
+ return FAIL;
+
+ }
+
+
+
+ /* ---------------------CreateDirectoryA------------------------- */
+
+
+
+
+
+ /* Testing of CreateDirectoryA */
+
+ bRc = CreateDirectoryA(sBadSubDirectory,NULL);
+
+ if(!bRc)
+
+ {
+
+ errCode = GetLastError();
+
+ if(errCode != ERROR_PATH_NOT_FOUND)
+
+ {
+
+ Trace("CreateDirectoryA: calling GetLastError() after creating a "
+
+ "directory with invalid path returned [%u] while it should "
+
+ "return [%u]\n",errCode, ERROR_PATH_NOT_FOUND);
+
+ testPass = FALSE;
+
+ }
+
+ }
+
+ else
+
+ {
+
+ Trace("CreateDirectoryA: Created a directory with an invalid path.\n");
+
+ bRc = RemoveDirectoryW(tempName);
+
+ if(!bRc)
+
+ {
+
+ Trace("Failed to remove %s with error %u.\n",
+
+ sBadSubDirectory,GetLastError());
+
+ }
+
+ testPass = FALSE;
+
+ }
+
+
+
+ /* ---------------------CreateDirectoryW------------------------- */
+
+
+
+ /* Testing of CreateDirectoryW */
+
+ bRc = CreateDirectoryW(wBadSubDirectory,NULL);
+
+ if(!bRc)
+
+ {
+
+ errCode = GetLastError();
+
+ if(errCode != ERROR_PATH_NOT_FOUND)
+
+ {
+
+ Trace("CreateDirectoryW: calling GetLastError() after creating a "
+
+ "directory with invalid path returned [%u] while it should "
+
+ "return [%u]\n",errCode, ERROR_PATH_NOT_FOUND);
+
+ testPass = FALSE;
+
+ }
+
+ }
+
+ else
+
+ {
+
+ Trace("CreateDirectoryW: Created a directory with an invalid path.\n");
+
+ bRc = RemoveDirectoryW(wBadSubDirectory);
+
+ if(!bRc)
+
+ {
+
+ Trace("Failed to remove %S with error %u.\n",
+
+ wBadSubDirectory,GetLastError());
+
+ }
+
+ testPass = FALSE;
+
+ }
+
+
+
+ /* ---------------------RemoveDirectoryW------------------------ */
+
+
+
+ /* Testing of RemoveDirectoryW */
+
+ bRc = RemoveDirectoryW(wBadSubDirectory);
+
+ if(!bRc)
+
+ {
+
+ errCode = GetLastError();
+
+ if(errCode != ERROR_PATH_NOT_FOUND)
+
+ {
+
+ Trace("RemoveDirectoryW: calling GetLastError() after removing a "
+
+ "sub directory with invalid path returned [%u] while it should "
+
+ "return [%u]\n",errCode, ERROR_PATH_NOT_FOUND);
+
+ testPass = FALSE;
+
+ }
+
+ }
+
+ else
+
+ {
+
+ Trace("RemoveDirectoryW: Removed a directory that did not exist.\n");
+
+ }
+
+ int exitCode = testPass ? PASS : FAIL;
+ PAL_TerminateEx(exitCode);
+ return exitCode;
+
+
+
+
+
+
+
+
+
+
+}
+
diff --git a/src/pal/tests/palsuite/file_io/errorpathnotfound/test3/testinfo.dat b/src/pal/tests/palsuite/file_io/errorpathnotfound/test3/testinfo.dat
new file mode 100644
index 0000000000..7a9019f17b
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/errorpathnotfound/test3/testinfo.dat
@@ -0,0 +1,30 @@
+# Licensed to the .NET Foundation under one or more agreements.
+
+# The .NET Foundation licenses this file to you under the MIT license.
+
+# See the LICENSE file in the project root for more information.
+
+
+
+Version = 1.0
+
+Section = file_io
+
+Function = some File_io functions
+
+Name = errorpathnotfound - checking GetLastError.
+
+Type = DEFAULT
+
+EXE1 = test3
+
+Description
+
+= Test the return value of GetLastError() after calling
+
+= some file_io functions with an invalid path.
+
+= Functions covered by this test are:
+
+= CreateDirectory, RemoveDirectory
+
diff --git a/src/pal/tests/palsuite/file_io/errorpathnotfound/test4/CMakeLists.txt b/src/pal/tests/palsuite/file_io/errorpathnotfound/test4/CMakeLists.txt
new file mode 100644
index 0000000000..f8062fd127
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/errorpathnotfound/test4/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test4.c
+)
+
+add_executable(paltest_errorpathnotfound_test4
+ ${SOURCES}
+)
+
+add_dependencies(paltest_errorpathnotfound_test4 coreclrpal)
+
+target_link_libraries(paltest_errorpathnotfound_test4
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/errorpathnotfound/test4/test4.c b/src/pal/tests/palsuite/file_io/errorpathnotfound/test4/test4.c
new file mode 100644
index 0000000000..e1b68995b0
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/errorpathnotfound/test4/test4.c
@@ -0,0 +1,351 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+
+**
+
+** Source: test4.c
+
+**
+
+** Purpose: Test the return value of GetLastError() after calling
+
+** some file_io functions with an invalid path.
+
+**
+
+** Functions covered by this test are:
+
+** GetDiskFreeSpaceW, GetTempFileNameA
+
+** and GetTempFileNameW
+
+**
+**
+
+**
+
+
+
+**
+
+**===================================================================*/
+
+
+
+#include <palsuite.h>
+
+
+
+int __cdecl main(int argc, char *argv[])
+
+{
+
+
+
+ BOOL testPass = TRUE;
+
+ BOOL bRc = TRUE;
+
+ DWORD lastErr=-50;
+
+ DWORD dwSectorsPerCluster_02; /* sectors per cluster */
+
+ DWORD dwBytesPerSector_02; /* bytes per sector */
+
+ DWORD dwNumberOfFreeClusters; /* free clusters */
+
+ DWORD dwTotalNumberOfClusters; /* total clusters */
+
+
+
+ UINT uiError = 0;
+
+ char szReturnedName[256];
+
+ const UINT uUnique = 0;
+
+ const char* sDot = {"tmpr"};
+
+ const char* sPrefix = {"cfr"};
+
+
+
+ WCHAR wzReturnedName[256];
+
+ const WCHAR wDot[] = {'t','m','p','r','\0'};
+
+ const WCHAR wPrefix[] = {'c','f','r','\0'};
+
+
+
+
+
+ const WCHAR wBadFilePath[] =
+
+ {'w','b','a','d','/','b','a',
+
+ 'd','.','t','m','p','\0'};
+
+ const WCHAR wBadFileName[] =
+
+ {'w','B','a','d','.','t','m','p','\0'};
+
+
+
+
+
+
+
+ if (0 != PAL_Initialize(argc,argv))
+
+ {
+
+ return FAIL;
+
+ }
+
+
+
+ /* test .................. GetDiskFreeSpaceW .................. */
+
+
+
+ /* test with invalid file name */
+
+ bRc = GetDiskFreeSpaceW(wBadFileName,
+
+ &dwSectorsPerCluster_02,
+
+ &dwBytesPerSector_02,
+
+ &dwNumberOfFreeClusters,
+
+ &dwTotalNumberOfClusters);
+
+ if (bRc != TRUE)
+
+
+
+ {
+
+ lastErr=GetLastError();
+
+
+
+ if(lastErr != ERROR_FILE_NOT_FOUND)
+
+ {
+
+ Trace("GetDiskFreeSpaceW: calling GetLastError() returned [%u] "
+
+ "while it should return [%u] for a bad File Name\n",
+
+ lastErr,ERROR_FILE_NOT_FOUND);
+
+ testPass = FALSE;
+
+ }
+
+ }
+
+ else
+
+ {
+
+ Trace("GetDiskFreeSpaceW: GetDiskFreeSpaceW succeeded when given "
+
+ "a bad fileName\n");
+
+ testPass = FALSE;
+
+
+
+ }
+
+
+
+
+
+ /* test with invalid path name */
+
+ bRc = GetDiskFreeSpaceW(wBadFilePath,
+
+ &dwSectorsPerCluster_02,
+
+ &dwBytesPerSector_02,
+
+ &dwNumberOfFreeClusters,
+
+ &dwTotalNumberOfClusters);
+
+ if (bRc != TRUE)
+
+
+
+ {
+
+ lastErr=GetLastError();
+
+ if(lastErr != ERROR_PATH_NOT_FOUND)
+
+ {
+
+ Trace("GetDiskFreeSpaceW: calling GetLastError() returned [%u] "
+
+ "while it should return [%u] for a bad File Name\n",
+
+ lastErr,ERROR_PATH_NOT_FOUND);
+
+ testPass = FALSE;
+
+ }
+
+ }
+
+ else
+
+ {
+
+ Trace("GetDiskFreeSpaceW: GetDiskFreeSpaceW succeeded when given "
+
+ "a bad fileName\n");
+
+ testPass = FALSE;
+
+
+
+
+
+ }
+
+
+
+
+
+ /* test .................. GetTempFileNameA .................. */
+
+
+
+ /* test with invalid path name */
+
+ uiError = GetTempFileNameA(sDot, sPrefix, uUnique, szReturnedName);
+
+ if (uiError == 0)
+
+ {
+
+ lastErr=GetLastError();
+
+ if(lastErr != ERROR_DIRECTORY)
+
+ {
+
+
+
+ Trace("GetTempFileNameA: calling GetLastError() returned [%u] "
+
+ "while it should return [%u] for invalid path name\n",
+
+ lastErr,ERROR_DIRECTORY);
+
+ testPass = FALSE;
+
+ }
+
+ }
+
+ else
+
+ {
+
+ Trace("GetTempFileNameA: GetTempFileNameA succeeded when given "
+
+ "invalid path name\n");
+
+ testPass = FALSE;
+
+ }
+
+
+
+
+
+
+
+ /* test .................. GetTempFileNameW .................. */
+
+
+
+ /* test with invalid path name */
+
+ uiError = GetTempFileNameW(wDot, wPrefix, uUnique, wzReturnedName);
+
+ if (uiError == 0)
+
+ {
+
+ lastErr=GetLastError();
+
+ if(lastErr != ERROR_DIRECTORY)
+
+ {
+
+
+
+ Trace("GetTempFileNameW: calling GetLastError() returned [%u] "
+
+ "while it should return [%u] for an invalid path name\n",
+
+ lastErr,ERROR_DIRECTORY);
+
+ testPass = FALSE;
+
+ }
+
+ }
+
+ else
+
+ {
+
+ Trace("GetTempFileNameW: GetTempFileNameW succeeded when given"
+
+ " an invalid path name\n");
+
+ testPass = FALSE;
+
+ }
+
+
+
+ if(! testPass)
+
+ {
+
+ Fail("");
+
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PAL_Terminate();
+
+ return PASS;
+
+}
+
+
+
diff --git a/src/pal/tests/palsuite/file_io/errorpathnotfound/test4/testinfo.dat b/src/pal/tests/palsuite/file_io/errorpathnotfound/test4/testinfo.dat
new file mode 100644
index 0000000000..d7b707fca9
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/errorpathnotfound/test4/testinfo.dat
@@ -0,0 +1,34 @@
+# Licensed to the .NET Foundation under one or more agreements.
+
+# The .NET Foundation licenses this file to you under the MIT license.
+
+# See the LICENSE file in the project root for more information.
+
+
+
+Version = 1.0
+
+Section = file_io
+
+Function = some File_io functions
+
+Name = errorpathnotfound - checking GetLastError.
+
+Type = DEFAULT
+
+EXE1 = test4
+
+Description
+
+= Test the return value of GetLastError() after calling
+
+= some file_io functions with an invalid path.
+
+= Functions covered by this test are:
+
+= MoveFIlew, FindFirstFileA, FindFirstFileW,
+
+= GetFileAttributesA, GetFileAttributesW,
+
+= SetFileAttributesA, SetFileAttributesW.
+
diff --git a/src/pal/tests/palsuite/file_io/gettemppatha/CMakeLists.txt b/src/pal/tests/palsuite/file_io/gettemppatha/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/gettemppatha/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/file_io/gettemppatha/test1/CMakeLists.txt b/src/pal/tests/palsuite/file_io/gettemppatha/test1/CMakeLists.txt
new file mode 100644
index 0000000000..2aff599e74
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/gettemppatha/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ gettemppatha.c
+)
+
+add_executable(paltest_gettemppatha_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_gettemppatha_test1 coreclrpal)
+
+target_link_libraries(paltest_gettemppatha_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/file_io/gettemppatha/test1/gettemppatha.c b/src/pal/tests/palsuite/file_io/gettemppatha/test1/gettemppatha.c
new file mode 100644
index 0000000000..b0da528af8
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/gettemppatha/test1/gettemppatha.c
@@ -0,0 +1,103 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: gettemppatha.c (test 1)
+**
+** Purpose: Tests the PAL implementation of the GetTempPathA function.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+static void SetTmpDir(CHAR path[])
+{
+ DWORD result = SetEnvironmentVariableA("TMPDIR", path);
+ if (!result)
+ {
+ Fail("ERROR -> SetEnvironmentVariableA failed with result %d and error code %d.\n",
+ result, GetLastError());
+ }
+}
+
+static void SetAndCompare(CHAR tmpDirPath[], CHAR expected[])
+{
+ DWORD dwBufferLength = _MAX_DIR;
+ CHAR path[dwBufferLength];
+
+ SetTmpDir(tmpDirPath);
+
+ DWORD dwResultLen = GetTempPathA(dwBufferLength, path);
+ if (dwResultLen <= 0)
+ {
+ Fail("ERROR: GetTempPathA returned %d with error code %d.\n", dwResultLen, GetLastError());
+ }
+ if (dwResultLen >= dwBufferLength)
+ {
+ Fail("ERROR: Buffer of length %d passed to GetTempPathA was too small to hold %d chars..\n", dwBufferLength, dwResultLen);
+ }
+ if (strcmp(expected, path) != 0)
+ {
+ Fail("ERROR: GetTempPathA expected to get '%s' but instead got '%s'.\n", expected, path);
+ }
+ if (expected[dwResultLen - 1] != '/')
+ {
+ Fail("ERROR: GetTempPathA returned '%s', which should have ended in '/'.\n", path);
+ }
+}
+
+static void SetAndCheckLength(CHAR tmpDirPath[], int bufferLength, int expectedResultLength)
+{
+ CHAR path[bufferLength];
+
+ SetTmpDir(tmpDirPath);
+ DWORD dwResultLen = GetTempPathA(bufferLength, path);
+
+ if (dwResultLen != expectedResultLength)
+ {
+ Fail("GetTempPathA(%d, %s) expected to return %d but returned %d.\n",
+ bufferLength, tmpDirPath?tmpDirPath:"NULL", expectedResultLength, dwResultLen);
+ }
+}
+
+int __cdecl main(int argc, char *argv[])
+{
+ if (0 != PAL_Initialize(argc,argv))
+ {
+ return FAIL;
+ }
+
+ SetAndCompare("/tmp", "/tmp/");
+ SetAndCompare("/tmp/", "/tmp/");
+ SetAndCompare("", "/tmp/");
+ SetAndCompare(NULL, "/tmp/");
+ SetAndCompare("/", "/");
+ SetAndCompare("/var/tmp", "/var/tmp/");
+ SetAndCompare("/var/tmp/", "/var/tmp/");
+ SetAndCompare("~", "~/");
+ SetAndCompare("~/", "~/");
+ SetAndCompare(".tmp", ".tmp/");
+ SetAndCompare("./tmp", "./tmp/");
+ SetAndCompare("/home/someuser/sometempdir", "/home/someuser/sometempdir/");
+ SetAndCompare(NULL, "/tmp/");
+
+ DWORD dwResultLen = GetTempPathA(0, NULL);
+ if (dwResultLen != 0 || GetLastError() != ERROR_INVALID_PARAMETER)
+ {
+ Fail("GetTempPath(NULL, ...) returned %d with error code %d but "
+ "should have failed with ERROR_INVALID_PARAMETER (%d).\n",
+ dwResultLen, GetLastError(), ERROR_INVALID_PARAMETER);
+ }
+
+ SetAndCheckLength("abc/", 5, 4);
+ SetAndCheckLength("abcd", 5, 6);
+ SetAndCheckLength("abcde", 5, 7);
+ SetAndCheckLength("abcdef/", 5, 9);
+ SetAndCheckLength(NULL, 5, 6);
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/file_io/gettemppatha/test1/testinfo.dat b/src/pal/tests/palsuite/file_io/gettemppatha/test1/testinfo.dat
new file mode 100644
index 0000000000..71f8bef651
--- /dev/null
+++ b/src/pal/tests/palsuite/file_io/gettemppatha/test1/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = file_io
+Function = GetTempPathA
+Name = Test for GetTempPathA (test 1)
+Type = DEFAULT
+EXE1 = gettemppatha
+Description
+= Calls GetTempPathA and verifies by passing the returned
+= value to CreateDirectoryA. If the returned path exists,
+= CreateDirectoryA will fail.
+
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/CMakeLists.txt
new file mode 100644
index 0000000000..3fc399fe59
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/CMakeLists.txt
@@ -0,0 +1,28 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(CreateFileMappingA)
+add_subdirectory(CreateFileMappingW)
+add_subdirectory(FreeLibrary)
+add_subdirectory(FreeLibraryAndExitThread)
+add_subdirectory(GetModuleFileNameA)
+add_subdirectory(GetModuleFileNameW)
+add_subdirectory(GetProcAddress)
+add_subdirectory(GetProcessHeap)
+add_subdirectory(HeapAlloc)
+add_subdirectory(HeapFree)
+add_subdirectory(HeapReAlloc)
+add_subdirectory(LocalAlloc)
+add_subdirectory(LocalFree)
+add_subdirectory(LockFile)
+add_subdirectory(MapViewOfFile)
+add_subdirectory(OpenFileMappingA)
+add_subdirectory(OpenFileMappingW)
+add_subdirectory(ReadProcessMemory)
+add_subdirectory(RtlMoveMemory)
+add_subdirectory(UnlockFile)
+add_subdirectory(UnmapViewOfFile)
+add_subdirectory(VirtualAlloc)
+add_subdirectory(VirtualFree)
+add_subdirectory(VirtualProtect)
+add_subdirectory(VirtualQuery)
+
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/CMakeLists.txt
new file mode 100644
index 0000000000..0223c4d9b5
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/CMakeLists.txt
@@ -0,0 +1,11 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test3)
+add_subdirectory(test4)
+add_subdirectory(test5)
+add_subdirectory(test6)
+add_subdirectory(test7)
+add_subdirectory(test8)
+add_subdirectory(test9)
+
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test1/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test1/CMakeLists.txt
new file mode 100644
index 0000000000..36084bf446
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ CreateFileMapping.c
+)
+
+add_executable(paltest_createfilemappinga_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_createfilemappinga_test1 coreclrpal)
+
+target_link_libraries(paltest_createfilemappinga_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test1/CreateFileMapping.c b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test1/CreateFileMapping.c
new file mode 100644
index 0000000000..91640bfd04
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test1/CreateFileMapping.c
@@ -0,0 +1,173 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: createfilemapping.c (test 1)
+**
+** Purpose: Positive test the CreateFileMapping API.
+** Call CreateFileMapping with access PAGE_READONLY.
+**
+**
+**============================================================*/
+#include <palsuite.h>
+
+const int MAPPINGSIZE = 2048;
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ HANDLE hFile;
+ char buf[] = "this is a test string";
+ char ch[2048];
+ char lpFileName[] = "test.tmp";
+ DWORD dwBytesWritten;
+ BOOL err;
+ int RetVal = PASS;
+
+ HANDLE hFileMapping;
+ LPVOID lpMapViewAddress;
+
+ /* Initialize the PAL environment.
+ */
+ if(0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ /* Create a file handle with CreateFile.
+ */
+ hFile = CreateFile( lpFileName,
+ GENERIC_WRITE|GENERIC_READ,
+ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ NULL,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if (hFile == INVALID_HANDLE_VALUE)
+ {
+ Fail("ERROR: %u :unable to create file \"%s\".\n",
+ GetLastError(),
+ lpFileName);
+ }
+
+ /* Initialize the buffers.
+ */
+ memset(ch, 0, MAPPINGSIZE);
+
+ /* Write to the File handle.
+ */
+ err = WriteFile(hFile,
+ buf,
+ strlen(buf),
+ &dwBytesWritten,
+ NULL);
+
+ if (err == FALSE)
+ {
+ Trace("ERROR: %u :unable to write to file handle "
+ "hFile=0x%lx\n",
+ GetLastError(),
+ hFile);
+ RetVal = FAIL;
+ goto CleanUpOne;
+ }
+
+ /* Flush to the hard-drive.
+ */
+ FlushFileBuffers(hFile);
+
+ /* Create a unnamed file-mapping object with file handle FileHandle
+ * and with PAGE_READWRITE protection.
+ */
+ hFileMapping = CreateFileMapping(
+ hFile,
+ NULL, /*not inherited*/
+ PAGE_READONLY, /*read and wite*/
+ 0, /*high-order size*/
+ 0, /*low-order size*/
+ NULL); /*unnamed object*/
+
+ if(NULL == hFileMapping)
+ {
+ Trace("ERROR:%u: Failed to create File Mapping.\n",
+ GetLastError());
+ RetVal = FAIL;
+ goto CleanUpOne;
+ }
+
+ /* maps a view of a file into the address space of the calling process.
+ */
+ lpMapViewAddress = MapViewOfFile(
+ hFileMapping,
+ FILE_MAP_READ, /* access code */
+ 0, /*high order offset*/
+ 0, /*low order offset*/
+ 0); /* number of bytes for map */
+
+ if(NULL == lpMapViewAddress)
+ {
+ Trace("ERROR:%u: Failed to call MapViewOfFile "
+ "API to map a view of file!\n",
+ GetLastError());
+ RetVal = FAIL;
+ goto CleanUpTwo;
+ }
+
+ /* Copy the MapViewOfFile to buffer, so we can
+ * compare with value read from file directly.
+ */
+ memcpy(ch, (LPCSTR)lpMapViewAddress, MAPPINGSIZE);
+ if (memcmp(ch, buf, strlen(buf))!= 0)
+ {
+ Trace("ERROR: MapViewOfFile not equal to file contents "
+ "retrieved \"%s\", expected \"%s\".\n",
+ ch, buf);
+ RetVal = FAIL;
+ goto CleanUpThree;
+ }
+
+CleanUpThree:
+
+ /* Unmap the view of file.
+ */
+ if ( UnmapViewOfFile(lpMapViewAddress) == FALSE )
+ {
+ Trace("ERROR:%u: Failed to UnmapViewOfFile of \"%0x%lx\".\n",
+ GetLastError(),
+ lpMapViewAddress);
+ RetVal = FAIL;
+ }
+
+CleanUpTwo:
+
+ /* Close Handle to opend file mapping.
+ */
+ if ( CloseHandle(hFileMapping) == FALSE )
+ {
+ Trace("ERROR:%u: Failed to CloseHandle \"0x%lx\".\n",
+ GetLastError(),
+ hFileMapping);
+ RetVal = FAIL;
+ }
+
+CleanUpOne:
+
+ /* Close Handle to create file mapping.
+ */
+ if ( CloseHandle(hFile) == FALSE )
+ {
+ Trace("ERROR:%u: Failed to CloseHandle \"0x%lx\".\n",
+ GetLastError(),
+ hFile);
+ RetVal = FAIL;
+ }
+
+ /* Terminate the PAL.
+ */
+ PAL_TerminateEx(RetVal);
+ return RetVal;
+}
+
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test1/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test1/testinfo.dat
new file mode 100644
index 0000000000..36ff3238c7
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = CreateFileMapping
+Name = CreateFileMappingA with PAGE_READONLY
+TYPE = DEFAULT
+EXE1 = createfilemapping
+Description
+=Test the CreateFileMapping to create a named file-mapping object
+=and with PAGE_READONLY protection
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test3/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test3/CMakeLists.txt
new file mode 100644
index 0000000000..374f8f0946
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test3/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ CreateFileMapping.c
+)
+
+add_executable(paltest_createfilemappinga_test3
+ ${SOURCES}
+)
+
+add_dependencies(paltest_createfilemappinga_test3 coreclrpal)
+
+target_link_libraries(paltest_createfilemappinga_test3
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test3/CreateFileMapping.c b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test3/CreateFileMapping.c
new file mode 100644
index 0000000000..2a849d86b8
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test3/CreateFileMapping.c
@@ -0,0 +1,155 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: createfilemapping.c (test 3)
+**
+** Purpose: Positive test the CreateFileMapping API.
+** Call CreateFileMapping with access PAGE_READWRITE.
+**
+**
+**============================================================*/
+#include <palsuite.h>
+
+const int MAPPINGSIZE = 2048;
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ HANDLE hFile;
+ char buf[] = "this is a test string";
+ char ch[2048];
+ char lpFileName[] = "test.tmp";
+ HANDLE hFileMapping;
+ LPVOID lpMapViewAddress;
+ int RetVal = PASS;
+
+ /* Initialize the PAL environment.
+ */
+ if(0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ /* Create a file handle with CreateFile.
+ */
+ hFile = CreateFile( lpFileName,
+ GENERIC_WRITE|GENERIC_READ,
+ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ NULL,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if (hFile == INVALID_HANDLE_VALUE)
+ {
+ Fail("ERROR: %u :unable to create file \"%s\".\n",
+ GetLastError(),
+ lpFileName);
+ }
+
+ /* Initialize the buffers.
+ */
+ memset(ch, 0, MAPPINGSIZE);
+
+ /* Create a unnamed file-mapping object with file handle FileHandle
+ * and with PAGE_READWRITE protection.
+ */
+ hFileMapping = CreateFileMapping(
+ hFile,
+ NULL, /*not inherited*/
+ PAGE_READWRITE, /*read and wite*/
+ 0, /*high-order size*/
+ MAPPINGSIZE, /*low-order size*/
+ NULL); /*unnamed object*/
+
+ if(NULL == hFileMapping)
+ {
+ Trace("ERROR:%u: Failed to create File Mapping.\n",
+ GetLastError());
+ RetVal = FAIL;
+ goto CleanUpOne;
+ }
+
+ /* maps a view of a file into the address space of the calling process.
+ */
+ lpMapViewAddress = MapViewOfFile(
+ hFileMapping,
+ FILE_MAP_ALL_ACCESS, /* access code */
+ 0, /*high order offset*/
+ 0, /*low order offset*/
+ MAPPINGSIZE); /* number of bytes for map */
+
+ if(NULL == lpMapViewAddress)
+ {
+ Trace("ERROR:%u: Failed to call MapViewOfFile "
+ "API to map a view of file!\n",
+ GetLastError());
+ RetVal = FAIL;
+ goto CleanUpTwo;
+ }
+
+ /* Write to the Map view.
+ */
+ memcpy(lpMapViewAddress, buf, strlen(buf));
+
+ /* Read from the Map view.
+ */
+ memcpy(ch, (LPCSTR)lpMapViewAddress, MAPPINGSIZE);
+
+ /* Copy the MapViewOfFile to buffer, so we can
+ * compare with value read from file directly.
+ */
+ if (memcmp(ch, buf, strlen(buf))!= 0)
+ {
+ Trace("ERROR: MapViewOfFile not equal to file contents "
+ "retrieved \"%s\", expected \"%s\".\n",
+ ch, buf);
+ RetVal = FAIL;
+ goto CleanUpThree;
+ }
+
+CleanUpThree:
+
+ /* Unmap the view of file.
+ */
+ if ( UnmapViewOfFile(lpMapViewAddress) == FALSE )
+ {
+ Trace("ERROR:%u: Failed to UnmapViewOfFile of \"%0x%lx\".\n",
+ GetLastError(),
+ lpMapViewAddress);
+ RetVal = FAIL;
+ }
+
+CleanUpTwo:
+
+ /* Close Handle to opend file mapping.
+ */
+ if ( CloseHandle(hFileMapping) == FALSE )
+ {
+ Trace("ERROR:%u: Failed to CloseHandle \"0x%lx\".\n",
+ GetLastError(),
+ hFileMapping);
+ RetVal = FAIL;
+ }
+
+CleanUpOne:
+
+ /* Close Handle to create file mapping.
+ */
+ if ( CloseHandle(hFile) == FALSE )
+ {
+ Trace("ERROR:%u: Failed to CloseHandle \"0x%lx\".\n",
+ GetLastError(),
+ hFile);
+ RetVal = FAIL;
+ }
+
+ /* Terminate the PAL.
+ */
+ PAL_TerminateEx(RetVal);
+ return RetVal;
+}
+
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test3/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test3/testinfo.dat
new file mode 100644
index 0000000000..4689ee6a08
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test3/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = CreateFileMapping
+Name = CreateFileMappingA with PAGE_READWRITE
+TYPE = DEFAULT
+EXE1 = createfilemapping
+Description
+=Test the CreateFileMapping to create a unnamed file-mapping object
+=and with PAGE_READWRITE protection
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test4/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test4/CMakeLists.txt
new file mode 100644
index 0000000000..665b10a3f0
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test4/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ CreateFileMapping.c
+)
+
+add_executable(paltest_createfilemappinga_test4
+ ${SOURCES}
+)
+
+add_dependencies(paltest_createfilemappinga_test4 coreclrpal)
+
+target_link_libraries(paltest_createfilemappinga_test4
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test4/CreateFileMapping.c b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test4/CreateFileMapping.c
new file mode 100644
index 0000000000..64caa88ca0
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test4/CreateFileMapping.c
@@ -0,0 +1,181 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: createfilemapping.c (test 4)
+**
+** Purpose: Positive test the CreateFileMapping API.
+** Call CreateFileMapping with access PAGE_WRITECOPY.
+**
+**
+**============================================================*/
+#include <palsuite.h>
+
+const int MAPPINGSIZE = 2048;
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ HANDLE hFile;
+ char buf[] = "this is a test string";
+ char ch[2048];
+ char lpFileName[] = "test.tmp";
+ HANDLE hFileMapping;
+ LPVOID lpMapViewAddress;
+ int RetVal = PASS;
+ int err;
+ DWORD dwBytesWritten;
+
+
+ /* Initialize the PAL environment.
+ */
+ if(0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ /* Create a file handle with CreateFile.
+ */
+ hFile = CreateFile( lpFileName,
+ GENERIC_WRITE|GENERIC_READ,
+ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ NULL,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if (hFile == INVALID_HANDLE_VALUE)
+ {
+ Fail("ERROR: %u :unable to create file \"%s\".\n",
+ GetLastError(),
+ lpFileName);
+ }
+
+ /* Write to the File handle.
+ */
+ err = WriteFile(hFile,
+ buf,
+ strlen(buf),
+ &dwBytesWritten,
+ NULL);
+
+ if (err == FALSE)
+ {
+ Trace("ERROR: %u :unable to write to file handle "
+ "hFile=0x%lx\n",
+ GetLastError(),
+ hFile);
+ RetVal = FAIL;
+ goto CleanUpOne;
+ }
+
+ /* Flush to the hard-drive.
+ */
+ FlushFileBuffers(hFile);
+
+ /* Initialize the buffers.
+ */
+ memset(ch, 0, MAPPINGSIZE);
+
+ /* Create a unnamed file-mapping object with file handle FileHandle
+ * and with PAGE_WRITECOPY protection.
+ */
+ hFileMapping = CreateFileMapping(
+ hFile,
+ NULL, /*not inherited*/
+ PAGE_WRITECOPY, /*write copy*/
+ 0, /*high-order size*/
+ 0, /*low-order size*/
+ NULL); /*unnamed object*/
+
+ if(NULL == hFileMapping)
+ {
+ Trace("ERROR:%u: Failed to create File Mapping.\n",
+ GetLastError());
+ RetVal = FAIL;
+ goto CleanUpOne;
+ }
+
+ /* maps a view of a file into the address space of the calling process.
+ */
+ lpMapViewAddress = MapViewOfFile(
+ hFileMapping,
+ FILE_MAP_COPY, /* access code */
+ 0, /* high order offset*/
+ 0, /* low order offset*/
+ 0); /* number of bytes for map */
+
+ if(NULL == lpMapViewAddress)
+ {
+ Trace("ERROR:%u: Failed to call MapViewOfFile "
+ "API to map a view of file!\n",
+ GetLastError());
+ RetVal = FAIL;
+ goto CleanUpTwo;
+ }
+
+ /* Write to the Map view.3
+ */
+ memcpy(lpMapViewAddress, buf, strlen(buf));
+
+ /* Read from the Map view.
+ */
+ memcpy(ch, (LPCSTR)lpMapViewAddress, MAPPINGSIZE);
+
+ /* Copy the MapViewOfFile to buffer, so we can
+ * compare with value read from file directly.
+ */
+ if (memcmp(ch, buf, strlen(buf))!= 0)
+ {
+ Trace("ERROR: MapViewOfFile not equal to file contents "
+ "retrieved \"%s\", expected \"%s\".\n",
+ ch, buf);
+ RetVal = FAIL;
+ goto CleanUpThree;
+ }
+
+CleanUpThree:
+
+ /* Unmap the view of file.
+ */
+ if ( UnmapViewOfFile(lpMapViewAddress) == FALSE )
+ {
+ Trace("ERROR:%u: Failed to UnmapViewOfFile of \"%0x%lx\".\n",
+ GetLastError(),
+ lpMapViewAddress);
+ RetVal = FAIL;
+ }
+
+CleanUpTwo:
+
+ /* Close Handle to opend file mapping.
+ */
+ if ( CloseHandle(hFileMapping) == FALSE )
+ {
+ Trace("ERROR:%u: Failed to CloseHandle \"0x%lx\".\n",
+ GetLastError(),
+ hFileMapping);
+ RetVal = FAIL;
+ }
+
+CleanUpOne:
+
+ /* Close Handle to create file mapping.
+ */
+ if ( CloseHandle(hFile) == FALSE )
+ {
+ Trace("ERROR:%u: Failed to CloseHandle \"0x%lx\".\n",
+ GetLastError(),
+ hFile);
+ RetVal = FAIL;
+ }
+
+ /* Terminate the PAL.
+ */
+ PAL_TerminateEx(RetVal);
+ return RetVal;
+}
+
+
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test4/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test4/testinfo.dat
new file mode 100644
index 0000000000..7d9dda1a96
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test4/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = CreateFileMapping
+Name = CreateFileMappingA with PAGE_WRITECOPY.
+TYPE = DEFAULT
+EXE1 = createfilemapping
+Description
+= Positive test the CreateFileMapping API.
+= Call CreateFileMapping with access PAGE_WRITECOPY.
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test5/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test5/CMakeLists.txt
new file mode 100644
index 0000000000..6f7f3c3635
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test5/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ CreateFileMapping.c
+)
+
+add_executable(paltest_createfilemappinga_test5
+ ${SOURCES}
+)
+
+add_dependencies(paltest_createfilemappinga_test5 coreclrpal)
+
+target_link_libraries(paltest_createfilemappinga_test5
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test5/CreateFileMapping.c b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test5/CreateFileMapping.c
new file mode 100644
index 0000000000..c7f9918b08
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test5/CreateFileMapping.c
@@ -0,0 +1,193 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: createfilemapping.c (test 5)
+**
+** Purpose: Positive test the CreateFileMapping API.
+** Test CreateFileMapping to a "swap" handle with
+** access PAGE_READONLY.
+**
+**
+**============================================================*/
+#include <palsuite.h>
+
+const int MAPPINGSIZE = 2048;
+HANDLE SWAP_HANDLE = ((VOID *)(-1));
+
+int __cdecl main(int argc, char *argv[])
+{
+ char testString[] = "this is a test string";
+ char lpObjectName[] = "myMappingObject";
+ int RetVal = FAIL;
+ char results[2048];
+
+ HANDLE hFileMapRO;
+ HANDLE hFileMapRW;
+ LPVOID lpMapViewRO;
+ LPVOID lpMapViewRW;
+
+ /* Initialize the PAL environment.
+ */
+ if(0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ /* Initialize the buffers.
+ */
+ memset(results, 0, MAPPINGSIZE);
+
+ /* Create a named file-mapping object with file handle FileHandle
+ * and with PAGE_READWRITE protection.
+ */
+ hFileMapRW = CreateFileMapping(
+ SWAP_HANDLE,
+ NULL, /*not inherited*/
+ PAGE_READWRITE, /*read only*/
+ 0, /*high-order size*/
+ MAPPINGSIZE, /*low-order size*/
+ lpObjectName); /*named object*/
+
+ if(NULL == hFileMapRW)
+ {
+ Fail("ERROR:%u: Failed to create File Mapping.\n",
+ GetLastError());
+ }
+
+ /* maps a view of a file into the address space of the calling process.
+ */
+ lpMapViewRW = MapViewOfFile(
+ hFileMapRW,
+ FILE_MAP_ALL_ACCESS, /* access code */
+ 0, /* high order offset*/
+ 0, /* low order offset*/
+ MAPPINGSIZE); /* number of bytes for map */
+
+ if(NULL == lpMapViewRW)
+ {
+ Trace("ERROR:%u: Failed to call MapViewOfFile "
+ "API to map a view of file!\n",
+ GetLastError());
+ RetVal = FAIL;
+ goto CleanUpOne;
+ }
+
+
+ hFileMapRO = CreateFileMapping(
+ SWAP_HANDLE,
+ NULL, /*not inherited*/
+ PAGE_READONLY, /*read and write*/
+ 0, /*high-order size*/
+ MAPPINGSIZE, /*low-order size*/
+ lpObjectName); /*named object*/
+
+ if(NULL == hFileMapRO)
+ {
+ Trace("ERROR:%u: Failed to create File Mapping.\n",
+ GetLastError());
+ RetVal = FAIL;
+ goto CleanUpTwo;
+ }
+
+ /* maps a view of a file into the address space of the calling process.
+ */
+ lpMapViewRO = MapViewOfFile(
+ hFileMapRO,
+ FILE_MAP_READ, /* access code */
+ 0, /* high order offset*/
+ 0, /* low order offset*/
+ MAPPINGSIZE); /* number of bytes for map */
+
+ if(NULL == lpMapViewRO)
+ {
+ Trace("ERROR:%u: Failed to call MapViewOfFile "
+ "API to map a view of file!\n",
+ GetLastError());
+ RetVal = FAIL;
+ goto CleanUpThree;
+ }
+
+ /* Write the test string to the Map view.
+ */
+ memcpy(lpMapViewRW, testString, strlen(testString));
+
+ /* Read from the second Map view.
+ */
+ memcpy(results, (LPCSTR)lpMapViewRO, MAPPINGSIZE);
+
+ /* Verify the contents of the file mapping,
+ * by comparing what was written to what was read.
+ */
+ if (memcmp(results, testString, strlen(testString))!= 0)
+ {
+ Trace("ERROR: MapViewOfFile not equal to file contents "
+ "retrieved \"%s\", expected \"%s\".\n",
+ results,
+ testString);
+ RetVal = FAIL;
+ goto CleanUpFour;
+ }
+
+ /* Test was successful.
+ */
+ RetVal = PASS;
+
+CleanUpFour:
+
+ /* Unmap the view of file.
+ */
+ if ( UnmapViewOfFile(lpMapViewRO) == FALSE )
+ {
+ Trace("ERROR:%u: Failed to UnmapViewOfFile of \"%0x%lx\".\n",
+ GetLastError(),
+ lpMapViewRO);
+ RetVal = FAIL;
+ }
+
+CleanUpThree:
+
+ /* Close Handle to opend file mapping.
+ */
+ if ( CloseHandle(hFileMapRO) == FALSE )
+ {
+ Trace("ERROR:%u: Failed to CloseHandle \"0x%lx\".\n",
+ GetLastError(),
+ hFileMapRO);
+ RetVal = FAIL;
+ }
+
+
+CleanUpTwo:
+ /* Unmap the view of file.
+ */
+ if ( UnmapViewOfFile(lpMapViewRW) == FALSE )
+ {
+ Trace("ERROR:%u: Failed to UnmapViewOfFile of \"%0x%lx\".\n",
+ GetLastError(),
+ lpMapViewRW);
+ RetVal = FAIL;
+ }
+
+
+CleanUpOne:
+
+ /* Close Handle to opend file mapping.
+ */
+ if ( CloseHandle(hFileMapRW) == FALSE )
+ {
+ Trace("ERROR:%u: Failed to CloseHandle \"0x%lx\".\n",
+ GetLastError(),
+ hFileMapRW);
+ RetVal = FAIL;
+ }
+
+
+ /* Terminate the PAL.
+ */
+ PAL_TerminateEx(RetVal);
+ return RetVal;
+}
+
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test5/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test5/testinfo.dat
new file mode 100644
index 0000000000..137db9d82b
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test5/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = CreateFileMapping
+Name = CreateFileMappingA - with PAGE_READWRITE and INVALID_HANDLE_VALUE file handle
+TYPE = DEFAULT
+EXE1 = createfilemapping
+Description
+=Test the CreateFileMapping to create a unnamed file-mapping object
+=and with PAGE_READWRITE protection by passing INVALID_HANDLE_VALUE
+=file handle
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test6/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test6/CMakeLists.txt
new file mode 100644
index 0000000000..2f5d98b5e6
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test6/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ CreateFileMapping.c
+)
+
+add_executable(paltest_createfilemappinga_test6
+ ${SOURCES}
+)
+
+add_dependencies(paltest_createfilemappinga_test6 coreclrpal)
+
+target_link_libraries(paltest_createfilemappinga_test6
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test6/CreateFileMapping.c b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test6/CreateFileMapping.c
new file mode 100644
index 0000000000..6445295de8
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test6/CreateFileMapping.c
@@ -0,0 +1,164 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: createfilemapping.c (test 6)
+**
+** Purpose: Positive test the CreateFileMapping API.
+** Test CreateFileMapping to a "swap" handle with
+** access PAGE_READWRITE.
+**
+**
+**============================================================*/
+#include <palsuite.h>
+
+const int MAPPINGSIZE = 2048;
+HANDLE SWAP_HANDLE = ((VOID *)(-1));
+
+int __cdecl main(int argc, char *argv[])
+{
+ char testString[] = "this is a test string";
+ char lpObjectName[] = "myMappingObject";
+ char results[2048];
+ int RetVal = PASS;
+
+ HANDLE hFileMapRW;
+ LPVOID lpMapViewRW;
+ LPVOID lpMapViewRW2;
+
+ /* Initialize the PAL environment.
+ */
+ if(0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ /* Initialize the buffers.
+ */
+ memset(results, 0, MAPPINGSIZE);
+
+ /* Create a named file-mapping object with file handle FileHandle
+ * and with PAGE_READWRITE protection.
+ */
+ hFileMapRW = CreateFileMapping(
+ SWAP_HANDLE,
+ NULL, /*not inherited*/
+ PAGE_READWRITE, /*read write*/
+ 0, /*high-order size*/
+ MAPPINGSIZE, /*low-order size*/
+ lpObjectName); /*unnamed object*/
+
+ if(NULL == hFileMapRW)
+ {
+ Fail("ERROR:%u: Failed to create File Mapping.\n",
+ GetLastError());
+ }
+
+ /* Create a map view of the READWRITE file mapping.
+ */
+ lpMapViewRW = MapViewOfFile(
+ hFileMapRW,
+ FILE_MAP_ALL_ACCESS,/* access code */
+ 0, /* high order offset*/
+ 0, /* low order offset*/
+ MAPPINGSIZE); /* number of bytes for map */
+
+ if(NULL == lpMapViewRW)
+ {
+ Trace("ERROR:%u: Failed to call MapViewOfFile "
+ "API to map a view of file!\n",
+ GetLastError());
+ RetVal = FAIL;
+ goto CleanUpOne;
+ }
+
+
+ /* maps a view of a file into the address space of the calling process.
+ */
+ lpMapViewRW2 = MapViewOfFile(
+ hFileMapRW,
+ FILE_MAP_ALL_ACCESS, /* access code */
+ 0, /* high order offset*/
+ 0, /* low order offset*/
+ MAPPINGSIZE); /* number of bytes for map */
+
+ if(NULL == lpMapViewRW2)
+ {
+ Trace("ERROR:%u: Failed to call MapViewOfFile "
+ "API to map a view of file!\n",
+ GetLastError());
+ RetVal = FAIL;
+ goto CleanUpTwo;
+ }
+
+ /* Write the test string to the Map view.
+ */
+ memcpy(lpMapViewRW, testString, strlen(testString));
+
+ /* Read from the second Map view.
+ */
+ memcpy(results, (LPCSTR)lpMapViewRW2, MAPPINGSIZE);
+
+ /* Verify the contents of the file mapping,
+ * by comparing what was written to what was read.
+ */
+ if (memcmp(results, testString, strlen(testString))!= 0)
+ {
+ Trace("ERROR: MapViewOfFile not equal to file contents "
+ "retrieved \"%s\", expected \"%s\".\n",
+ results,
+ testString);
+ RetVal = FAIL;
+ goto CleanUpThree;
+ }
+
+ /* Test successful.
+ */
+ RetVal = PASS;
+
+CleanUpThree:
+
+ /* Unmap the view of file.
+ */
+ if ( UnmapViewOfFile(lpMapViewRW2) == FALSE )
+ {
+ Trace("ERROR:%u: Failed to UnmapViewOfFile of \"%0x%lx\".\n",
+ GetLastError(),
+ lpMapViewRW2);
+ RetVal = FAIL;
+ }
+
+CleanUpTwo:
+
+ /* Unmap the view of file.
+ */
+ if ( UnmapViewOfFile(lpMapViewRW) == FALSE )
+ {
+ Trace("ERROR:%u: Failed to UnmapViewOfFile of \"%0x%lx\".\n",
+ GetLastError(),
+ lpMapViewRW);
+ RetVal = FAIL;
+ }
+
+
+CleanUpOne:
+
+ /* Close Handle to create file mapping.
+ */
+ if ( CloseHandle(hFileMapRW) == FALSE )
+ {
+ Trace("ERROR:%u: Failed to CloseHandle \"0x%lx\".\n",
+ GetLastError(),
+ hFileMapRW);
+ RetVal = FAIL;
+ }
+
+
+ /* Terminate the PAL.
+ */
+ PAL_TerminateEx(RetVal);
+ return RetVal;
+}
+
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test6/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test6/testinfo.dat
new file mode 100644
index 0000000000..d088c5d562
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test6/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = CreateFileMapping
+Name = CreateFileMappingA - with PAGE_READONLY
+TYPE = DEFAULT
+EXE1 = createfilemapping
+Description
+=Test the CreateFileMapping to create a named file-mapping object
+=and with PAGE_READONLY protection
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test7/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test7/CMakeLists.txt
new file mode 100644
index 0000000000..4fd24a63a1
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test7/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ createfilemapping.c
+)
+
+add_executable(paltest_createfilemappinga_test7
+ ${SOURCES}
+)
+
+add_dependencies(paltest_createfilemappinga_test7 coreclrpal)
+
+target_link_libraries(paltest_createfilemappinga_test7
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test7/createfilemapping.c b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test7/createfilemapping.c
new file mode 100644
index 0000000000..7cef9ddcdc
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test7/createfilemapping.c
@@ -0,0 +1,164 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: createfilemapping.c (test 7)
+**
+** Purpose: Positive test the CreateFileMapping API.
+** Test CreateFileMapping to a "swap" handle with
+** access PAGE_READWRITE.
+**
+**
+**============================================================*/
+#include <palsuite.h>
+
+const int MAPPINGSIZE = 2048;
+HANDLE SWAP_HANDLE = ((VOID *)(-1));
+
+int __cdecl main(int argc, char *argv[])
+{
+ char testString[] = "this is a test string";
+ char lpObjectName[] = "myMappingObject";
+ char results[2048];
+ int RetVal = PASS;
+
+ HANDLE hFileMapRW;
+ LPVOID lpMapViewRW;
+ LPVOID lpMapViewRO;
+
+ /* Initialize the PAL environment.
+ */
+ if(0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ /* Initialize the buffers.
+ */
+ memset(results, 0, MAPPINGSIZE);
+
+ /* Create a named file-mapping object with file handle FileHandle
+ * and with PAGE_READWRITE protection.
+ */
+ hFileMapRW = CreateFileMapping(
+ SWAP_HANDLE,
+ NULL, /*not inherited*/
+ PAGE_READWRITE, /*read write*/
+ 0, /*high-order size*/
+ MAPPINGSIZE, /*low-order size*/
+ lpObjectName); /*unnamed object*/
+
+ if(NULL == hFileMapRW)
+ {
+ Fail("ERROR:%u: Failed to create File Mapping.\n",
+ GetLastError());
+ }
+
+ /* Create a map view to the READWRITE file mapping.
+ */
+ lpMapViewRW = MapViewOfFile(
+ hFileMapRW,
+ FILE_MAP_ALL_ACCESS,/* access code */
+ 0, /* high order offset*/
+ 0, /* low order offset*/
+ MAPPINGSIZE); /* number of bytes for map */
+
+ if(NULL == lpMapViewRW)
+ {
+ Trace("ERROR:%u: Failed to call MapViewOfFile "
+ "API to map a view of file!\n",
+ GetLastError());
+ RetVal = FAIL;
+ goto CleanUpOne;
+ }
+
+
+ /* Create a map view to the READWRITE file mapping.
+ */
+ lpMapViewRO = MapViewOfFile(
+ hFileMapRW,
+ FILE_MAP_READ, /* access code */
+ 0, /* high order offset*/
+ 0, /* low order offset*/
+ MAPPINGSIZE); /* number of bytes for map */
+
+ if(NULL == lpMapViewRO)
+ {
+ Trace("ERROR:%u: Failed to call MapViewOfFile "
+ "API to map a view of file!\n",
+ GetLastError());
+ RetVal = FAIL;
+ goto CleanUpTwo;
+ }
+
+ /* Write the test string to the Map view.
+ */
+ memcpy(lpMapViewRW, testString, strlen(testString));
+
+ /* Read from the second Map view.
+ */
+ memcpy(results, (LPCSTR)lpMapViewRO, MAPPINGSIZE);
+
+ /* Verify the contents of the file mapping,
+ * by comparing what was written to what was read.
+ */
+ if (memcmp(results, testString, strlen(testString))!= 0)
+ {
+ Trace("ERROR: MapViewOfFile not equal to file contents "
+ "retrieved \"%s\", expected \"%s\".\n",
+ results,
+ testString);
+ RetVal = FAIL;
+ goto CleanUpThree;
+ }
+
+ /* Test successful.
+ */
+ RetVal = PASS;
+
+CleanUpThree:
+
+ /* Unmap the view of file.
+ */
+ if ( UnmapViewOfFile(lpMapViewRO) == FALSE )
+ {
+ Trace("ERROR:%u: Failed to UnmapViewOfFile of \"%0x%lx\".\n",
+ GetLastError(),
+ lpMapViewRO);
+ RetVal = FAIL;
+ }
+
+CleanUpTwo:
+
+ /* Unmap the view of file.
+ */
+ if ( UnmapViewOfFile(lpMapViewRW) == FALSE )
+ {
+ Trace("ERROR:%u: Failed to UnmapViewOfFile of \"%0x%lx\".\n",
+ GetLastError(),
+ lpMapViewRW);
+ RetVal = FAIL;
+ }
+
+
+CleanUpOne:
+
+ /* Close Handle to create file mapping.
+ */
+ if ( CloseHandle(hFileMapRW) == FALSE )
+ {
+ Trace("ERROR:%u: Failed to CloseHandle \"0x%lx\".\n",
+ GetLastError(),
+ hFileMapRW);
+ RetVal = FAIL;
+ }
+
+
+ /* Terminate the PAL.
+ */
+ PAL_TerminateEx(RetVal);
+ return RetVal;
+}
+
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test7/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test7/testinfo.dat
new file mode 100644
index 0000000000..c03d98a91c
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test7/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = CreateFileMapping
+Name = CreateFileMappingA - with PAGE_COPYWRITE
+TYPE = DEFAULT
+EXE1 = createfilemapping
+Description
+=Test the CreateFileMapping to create a named file-mapping object
+=and with PAGE_READONLY protection
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test8/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test8/CMakeLists.txt
new file mode 100644
index 0000000000..ae3ee8ddf6
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test8/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ createfilemapping.c
+)
+
+add_executable(paltest_createfilemappinga_test8
+ ${SOURCES}
+)
+
+add_dependencies(paltest_createfilemappinga_test8 coreclrpal)
+
+target_link_libraries(paltest_createfilemappinga_test8
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test8/createfilemapping.c b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test8/createfilemapping.c
new file mode 100644
index 0000000000..02b2fb5e61
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test8/createfilemapping.c
@@ -0,0 +1,79 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: createfilemapping.c (test 8)
+**
+** Purpose: Positive test the CreateFileMapping API.
+** Test the un-verifiable parameter combinations.
+**
+**
+**============================================================*/
+#include <palsuite.h>
+
+const int MAPPINGSIZE = 2048;
+HANDLE SWAP_HANDLE = ((VOID *)(-1));
+
+int __cdecl main(int argc, char *argv[])
+{
+ HANDLE hFileMap;
+
+ /* Initialize the PAL environment.
+ */
+ if(0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ /* Create a READONLY, "swap", un-named file mapping.
+ * This test is unverifiable since there is no hook back to the file map
+ * because it is un-named. As well, since it resides in "swap", and is
+ * initialized to zero, there is nothing to read.
+ */
+ hFileMap = CreateFileMapping(
+ SWAP_HANDLE,
+ NULL, /*not inherited*/
+ PAGE_READONLY, /*read only*/
+ 0, /*high-order size*/
+ MAPPINGSIZE, /*low-order size*/
+ NULL); /*un-named object*/
+
+ if(NULL == hFileMap)
+ {
+ Fail("ERROR:%u: Failed to create File Mapping.\n",
+ GetLastError());
+ }
+
+
+ /* Create a COPYWRITE, "swap", un-named file mapping.
+ * This test is unverifiable, here is a quote from MSDN:
+ *
+ * Copy on write access. If you create the map with PAGE_WRITECOPY and
+ * the view with FILE_MAP_COPY, you will receive a view to file. If you
+ * write to it, the pages are automatically swappable and the modifications
+ * you make will not go to the original data file.
+ *
+ */
+ hFileMap = CreateFileMapping(
+ SWAP_HANDLE,
+ NULL, /*not inherited*/
+ PAGE_WRITECOPY, /*read only*/
+ 0, /*high-order size*/
+ MAPPINGSIZE, /*low-order size*/
+ NULL); /*unnamed object*/
+
+ if(NULL == hFileMap)
+ {
+ Fail("ERROR:%u: Failed to create File Mapping.\n",
+ GetLastError());
+ }
+
+
+ /* Terminate the PAL.
+ */
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test8/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test8/testinfo.dat
new file mode 100644
index 0000000000..ebe138f659
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test8/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = CreateFileMapping
+Name = CreateFileMappingA - unnamed swap, READWRITE.
+TYPE = DEFAULT
+EXE1 = createfilemapping
+Description
+= Positive test the CreateFileMapping API.
+= Test an unnamed File Mapping to a "swap"
+= handle with access PAGE_READWRITE.
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test9/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test9/CMakeLists.txt
new file mode 100644
index 0000000000..a377632bed
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test9/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ createfilemapping.c
+)
+
+add_executable(paltest_createfilemappinga_test9
+ ${SOURCES}
+)
+
+add_dependencies(paltest_createfilemappinga_test9 coreclrpal)
+
+target_link_libraries(paltest_createfilemappinga_test9
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test9/createfilemapping.c b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test9/createfilemapping.c
new file mode 100644
index 0000000000..9224c22b4b
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test9/createfilemapping.c
@@ -0,0 +1,150 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: createfilemapping.c (test 9)
+**
+** Purpose: Negative test the CreateFileMapping API.
+**
+**
+**============================================================*/
+#include <palsuite.h>
+
+const int MAPPINGSIZE = 2048;
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ HANDLE hFile;
+ char lpFileName[] = "test.tmp";
+
+ HANDLE hFileMapping;
+
+ /* Initialize the PAL environment.
+ */
+ if(0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ /* Create a file handle with CreateFile, as READONLY
+ */
+ hFile = CreateFile( lpFileName,
+ GENERIC_READ,
+ FILE_SHARE_READ,
+ NULL,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if (hFile == INVALID_HANDLE_VALUE)
+ {
+ Fail("ERROR: %u :unable to create file \"%s\".\n",
+ GetLastError(),
+ lpFileName);
+ }
+
+ /* Attempt to create a unnamed file-mapping object to a READONLY file
+ * as READWRITE access.
+ */
+ hFileMapping = CreateFileMapping(
+ hFile,
+ NULL, /*not inherited*/
+ PAGE_READWRITE, /*read and write*/
+ 0, /*high-order size*/
+ MAPPINGSIZE, /*low-order size*/
+ NULL); /*unnamed object*/
+
+ if(NULL != hFileMapping)
+ {
+ Trace("ERROR: Able to create READWRITE mapping to a "
+ "READONLY file.\n" );
+ if( 0 == CloseHandle(hFile) )
+ {
+ Trace("Unexpected Error: Unable to close file handle\n");
+ }
+ Fail("");
+ }
+
+ /* Attempt to create a unnamed file-mapping object to a zero lenght
+ * file.
+ */
+ hFileMapping = CreateFileMapping(
+ hFile,
+ NULL, /*not inherited*/
+ PAGE_READWRITE, /*read and write*/
+ 0, /*high-order size*/
+ 0, /*low-order size*/
+ NULL); /*unnamed object*/
+
+ if( NULL != hFileMapping )
+ {
+ Trace("ERROR: Able to create READWRITE mapping to a "
+ "READONLY file.\n" );
+ if( 0 == CloseHandle(hFile) )
+ {
+ Trace("Unexpected Error: Unable to close file handle\n");
+ }
+ Fail("");
+ }
+ if(GetLastError() != ERROR_ACCESS_DENIED)
+ {
+ Trace("ERROR: Expected GetLastError() to return "
+ "ERROR_FILE_INVALID (%d), it returned %u.\n",
+ ERROR_FILE_INVALID,
+ GetLastError());
+ if( 0 == CloseHandle(hFile) )
+ {
+ Trace("Unexpected Error: Unable to close file handle\n");
+ }
+ Fail("");
+ }
+
+ /* Attempt to create a file mapping that is larger than
+ * the file.
+ */
+ hFileMapping = CreateFileMapping(
+ hFile,
+ NULL, /*not inherited*/
+ PAGE_READONLY, /*read only*/
+ 0, /*high-order size*/
+ MAPPINGSIZE, /*low-order size*/
+ NULL); /*unnamed object*/
+ if(NULL != hFileMapping)
+ {
+ Trace("ERROR: Able to create file mapping of size %d to "
+ "file of size 0.\n",
+ MAPPINGSIZE);
+ if( 0 == CloseHandle(hFile) )
+ {
+ Trace("Unexpected Error: Unable to close file handle\n");
+ }
+ Fail("");
+ }
+
+ if(GetLastError() != ERROR_NOT_ENOUGH_MEMORY )
+ {
+ Trace("ERROR: Expected GetLastError() to return "
+ "ERROR_NOT_ENOUGH_MEMORY (%d), it returned %u.\n",
+ ERROR_NOT_ENOUGH_MEMORY,
+ GetLastError());
+ if( 0 == CloseHandle(hFile) )
+ {
+ Trace("Unexpected Error: Unable to close file handle\n");
+ }
+ Fail("");
+ }
+
+ if( 0 == CloseHandle(hFile) )
+ {
+ Fail("Unexpected Error: Unable to close file handle\n");
+ }
+
+ /* Terminate the PAL.
+ */
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test9/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test9/testinfo.dat
new file mode 100644
index 0000000000..11cbedc8c5
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingA/test9/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = CreateFileMapping
+Name = CreateFileMappingA negative testing
+TYPE = DEFAULT
+EXE1 = createfilemapping
+Description
+= Negative test the CreateFileMapping API.
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/CMakeLists.txt
new file mode 100644
index 0000000000..85f5c90e2c
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/CMakeLists.txt
@@ -0,0 +1,16 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(CreateFileMapping_neg1)
+add_subdirectory(test1)
+
+# TODO: make this test compile
+# add_subdirectory(test2)
+
+add_subdirectory(test3)
+add_subdirectory(test4)
+add_subdirectory(test5)
+add_subdirectory(test6)
+add_subdirectory(test7)
+add_subdirectory(test8)
+add_subdirectory(test9)
+
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/CreateFileMapping_neg1/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/CreateFileMapping_neg1/CMakeLists.txt
new file mode 100644
index 0000000000..a4ad343ea0
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/CreateFileMapping_neg1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ CreateFileMapping_neg.c
+)
+
+add_executable(paltest_createfilemappingw_createfilemapping_neg1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_createfilemappingw_createfilemapping_neg1 coreclrpal)
+
+target_link_libraries(paltest_createfilemappingw_createfilemapping_neg1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/CreateFileMapping_neg1/CreateFileMapping_neg.c b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/CreateFileMapping_neg1/CreateFileMapping_neg.c
new file mode 100644
index 0000000000..8cf79b3c57
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/CreateFileMapping_neg1/CreateFileMapping_neg.c
@@ -0,0 +1,93 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: createfilemapping_neg.c
+**
+** Purpose: Negative test the CreateFileMapping API.
+** Call CreateFileMapping to create a unnamed
+** file-mapping object with PAGE_READONLY
+** protection and try to map a zero length file
+** in UNICODE
+**
+**
+**============================================================*/
+#define UNICODE
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ HANDLE FileHandle;
+ HANDLE FileMappingHandle;
+ int err;
+ WCHAR *lpFileName = NULL;
+
+ //Initialize the PAL environment
+ err = PAL_Initialize(argc, argv);
+ if(0 != err)
+ {
+ ExitProcess(FAIL);
+ }
+
+ //conver string to a unicode one
+ lpFileName = convert("temp.txt");
+
+
+ //create a file and return the file handle
+ FileHandle = CreateFile(lpFileName,
+ GENERIC_READ,
+ FILE_SHARE_READ,
+ NULL,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_ARCHIVE,
+ NULL);
+
+ //free this memory
+ free(lpFileName);
+
+ if(INVALID_HANDLE_VALUE == FileHandle)
+ {
+ Fail("Failed to call CreateFile to create a file\n");
+ }
+
+ //create a unnamed file-mapping object with file handle FileHandle
+ //and with PAGE_READONLY protection
+ //try to map a file which is zero length.
+ FileMappingHandle = CreateFileMapping(
+ FileHandle, //File Handle
+ NULL, //not inherited
+ PAGE_READONLY, //access protection
+ 0, //high-order of object size
+ 0, //low-orger of object size
+ NULL); //unnamed object
+
+
+ if(NULL != FileMappingHandle || ERROR_FILE_INVALID != GetLastError())
+ {//no error occurred
+ Trace("\nFailed to call CreateFileMapping API for a negative test!\n");
+ err = CloseHandle(FileHandle);
+ if(0 == err)
+ {
+ Fail("\nFailed to call CloseHandle API\n");
+ }
+ err = CloseHandle(FileMappingHandle);
+ if(0 == err)
+ {
+ Fail("\nFailed to call CloseHandle API\n");
+ }
+ Fail("");
+ }
+
+ //close the file handle
+ err = CloseHandle(FileHandle);
+ if(0 == err)
+ {
+ Fail("\nFailed to call CloseHandle API\n");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/CreateFileMapping_neg1/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/CreateFileMapping_neg1/testinfo.dat
new file mode 100644
index 0000000000..a09487d4b9
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/CreateFileMapping_neg1/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = CreateFileMapping
+Name = Negative test for CreateFileMappingW - with a zero length file
+TYPE = DEFAULT
+EXE1 = createfilemapping_neg
+Description
+=Test the CreateFileMapping to try to map a zero length file
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test1/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test1/CMakeLists.txt
new file mode 100644
index 0000000000..0c569ec9b6
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ CreateFileMappingW.c
+)
+
+add_executable(paltest_createfilemappingw_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_createfilemappingw_test1 coreclrpal)
+
+target_link_libraries(paltest_createfilemappingw_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test1/CreateFileMappingW.c b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test1/CreateFileMappingW.c
new file mode 100644
index 0000000000..4263a3ad29
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test1/CreateFileMappingW.c
@@ -0,0 +1,174 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: createfilemappingw.c (test 1)
+**
+** Purpose: Positive test the CreateFileMappingW API.
+** Call CreateFileMappingW with access PAGE_READONLY.
+**
+**
+**============================================================*/
+#define UNICODE
+#include <palsuite.h>
+
+const int MAPPINGSIZE = 2048;
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ HANDLE hFile;
+ char buf[] = "this is a test string";
+ char ch[2048];
+ WCHAR lpFileName[] = {'t','e','s','t','.','t','m','p','\0'};
+ DWORD dwBytesWritten;
+ BOOL err;
+ int RetVal = PASS;
+
+ HANDLE hFileMapping;
+ LPVOID lpMapViewAddress;
+
+ /* Initialize the PAL environment.
+ */
+ if(0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ /* Create a file handle with CreateFile.
+ */
+ hFile = CreateFile( lpFileName,
+ GENERIC_WRITE|GENERIC_READ,
+ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ NULL,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if (hFile == INVALID_HANDLE_VALUE)
+ {
+ Fail("ERROR: %u :unable to create file \"%s\".\n",
+ GetLastError(),
+ lpFileName);
+ }
+
+ /* Initialize the buffers.
+ */
+ memset(ch, 0, MAPPINGSIZE);
+
+ /* Write to the File handle.
+ */
+ err = WriteFile(hFile,
+ buf,
+ strlen(buf),
+ &dwBytesWritten,
+ NULL);
+
+ if (err == FALSE)
+ {
+ Trace("ERROR: %u :unable to write to file handle "
+ "hFile=0x%lx\n",
+ GetLastError(),
+ hFile);
+ RetVal = FAIL;
+ goto CleanUpOne;
+ }
+
+ /* Flush to the hard-drive.
+ */
+ FlushFileBuffers(hFile);
+
+ /* Create a unnamed file-mapping object with file handle FileHandle
+ * and with PAGE_READWRITE protection.
+ */
+ hFileMapping = CreateFileMapping(
+ hFile,
+ NULL, /*not inherited*/
+ PAGE_READONLY, /*read and wite*/
+ 0, /*high-order size*/
+ 0, /*low-order size*/
+ NULL); /*unnamed object*/
+
+ if(NULL == hFileMapping)
+ {
+ Trace("ERROR:%u: Failed to create File Mapping.\n",
+ GetLastError());
+ RetVal = FAIL;
+ goto CleanUpOne;
+ }
+
+ /* maps a view of a file into the address space of the calling process.
+ */
+ lpMapViewAddress = MapViewOfFile(
+ hFileMapping,
+ FILE_MAP_READ, /* access code */
+ 0, /*high order offset*/
+ 0, /*low order offset*/
+ 0); /* number of bytes for map */
+
+ if(NULL == lpMapViewAddress)
+ {
+ Trace("ERROR:%u: Failed to call MapViewOfFile "
+ "API to map a view of file!\n",
+ GetLastError());
+ RetVal = FAIL;
+ goto CleanUpTwo;
+ }
+
+ /* Copy the MapViewOfFile to buffer, so we can
+ * compare with value read from file directly.
+ */
+ memcpy(ch, (LPCSTR)lpMapViewAddress, MAPPINGSIZE);
+ if (memcmp(ch, buf, strlen(buf))!= 0)
+ {
+ Trace("ERROR: MapViewOfFile not equal to file contents "
+ "retrieved \"%s\", expected \"%s\".\n",
+ ch, buf);
+ RetVal = FAIL;
+ goto CleanUpThree;
+ }
+
+CleanUpThree:
+
+ /* Unmap the view of file.
+ */
+ if ( UnmapViewOfFile(lpMapViewAddress) == FALSE )
+ {
+ Trace("ERROR:%u: Failed to UnmapViewOfFile of \"%0x%lx\".\n",
+ GetLastError(),
+ lpMapViewAddress);
+ RetVal = FAIL;
+ }
+
+CleanUpTwo:
+
+ /* Close Handle to opend file mapping.
+ */
+ if ( CloseHandle(hFileMapping) == FALSE )
+ {
+ Trace("ERROR:%u: Failed to CloseHandle \"0x%lx\".\n",
+ GetLastError(),
+ hFileMapping);
+ RetVal = FAIL;
+ }
+
+CleanUpOne:
+
+ /* Close Handle to create file mapping.
+ */
+ if ( CloseHandle(hFile) == FALSE )
+ {
+ Trace("ERROR:%u: Failed to CloseHandle \"0x%lx\".\n",
+ GetLastError(),
+ hFile);
+ RetVal = FAIL;
+ }
+
+ /* Terminate the PAL.
+ */
+ PAL_TerminateEx(RetVal);
+ return RetVal;
+}
+
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test1/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test1/testinfo.dat
new file mode 100644
index 0000000000..464679a456
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = CreateFileMappingW
+Name = CreateFileMappingW with PAGE_READONLY
+TYPE = DEFAULT
+EXE1 = createfilemappingw
+Description
+=Test the CreateFileMappingW to create a unnamed file-mapping object
+=and with PAGE_READONLY protection
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test2/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test2/CMakeLists.txt
new file mode 100644
index 0000000000..992645f48c
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ CreateFileMappingW.c
+)
+
+add_executable(paltest_createfilemappingw_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_createfilemappingw_test2 coreclrpal)
+
+target_link_libraries(paltest_createfilemappingw_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test2/CreateFileMappingW.c b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test2/CreateFileMappingW.c
new file mode 100644
index 0000000000..11ff967dfd
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test2/CreateFileMappingW.c
@@ -0,0 +1,124 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: createfilemappingw.c
+**
+** Purpose: Positive test the CreateFileMapping API.
+** Call CreateFileMapping to create a unnamed
+** file-mapping object with PAGE_READONLY
+** protection and SEC_IMAGE attribute in UNICODE
+**
+**
+**============================================================*/
+#define UNICODE
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ HANDLE FileHandle;
+ HANDLE FileMappingHandle;
+ int err;
+ WCHAR *wpFileName = NULL;
+ char executableFileName[256]="";
+
+
+ //Initialize the PAL environment
+ err = PAL_Initialize(argc, argv);
+ if(0 != err)
+ {
+ ExitProcess(FAIL);
+ }
+
+#if WIN32
+ sprintf(executableFileName,"%s","executable.exe");
+#else
+ sprintf(executableFileName,"%s","executable");
+#endif
+
+ //conver string to a unicode one
+ wpFileName = convert(executableFileName);
+
+
+ //create a file and return the file handle
+ FileHandle = CreateFile(wpFileName,
+ GENERIC_READ,
+ FILE_SHARE_READ,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_ARCHIVE,
+ NULL);
+
+ //free this memory
+ free(wpFileName);
+
+ if(INVALID_HANDLE_VALUE == FileHandle)
+ {
+ Fail("Failed to call CreateFile to create a file\n");
+ }
+
+ //create a unnamed file-mapping object with file handle FileHandle
+ //and with PAGE_READONLY protection
+ FileMappingHandle = CreateFileMapping(
+ FileHandle, //File Handle
+ NULL, //not inherited
+ PAGE_READONLY|SEC_IMAGE, //access protection and section attribute
+ 0, //high-order of object size
+ 0, //low-orger of object size
+ NULL); //unnamed object
+
+
+ if(NULL == FileMappingHandle)
+ {
+ Trace("\nFailed to call CreateFileMapping to create a mapping object!\n");
+ err = CloseHandle(FileHandle);
+ if(0 == err)
+ {
+ Fail("\nFailed to call CloseHandle API\n");
+ }
+ Fail("");
+ }
+ if(GetLastError() == ERROR_ALREADY_EXISTS)
+ {
+ Trace("\nFile mapping object already exists!\n");
+ err = CloseHandle(FileHandle);
+ if(0 == err)
+ {
+ Trace("\nFailed to call CloseHandle API to close a file handle\n");
+ err = CloseHandle(FileMappingHandle);
+ if(0 == err)
+ {
+ Fail("\nFailed to call CloseHandle API to close a mapping object handle\n");
+ }
+ Fail("");
+ }
+ err = CloseHandle(FileMappingHandle);
+ if(0 == err)
+ {
+ Fail("\nFailed to call CloseHandle API to close a mapping object handle\n");
+ }
+ Fail("");
+ }
+ err = CloseHandle(FileMappingHandle);
+ if(0 == err)
+ {
+ Trace("\nFailed to call CloseHandle API to close a mapping object handle\n");
+ err = CloseHandle(FileHandle);
+ if(0 == err)
+ {
+ Fail("\nFailed to call CloseHandle API to close a file handle\n");
+ }
+ Fail("");
+ }
+ err = CloseHandle(FileHandle);
+ if(0 == err)
+ {
+ Fail("\nFailed to call CloseHandle API to close a file handle\n");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test3/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test3/CMakeLists.txt
new file mode 100644
index 0000000000..87832ffd9b
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test3/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ CreateFileMappingW.c
+)
+
+add_executable(paltest_createfilemappingw_test3
+ ${SOURCES}
+)
+
+add_dependencies(paltest_createfilemappingw_test3 coreclrpal)
+
+target_link_libraries(paltest_createfilemappingw_test3
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test3/CreateFileMappingW.c b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test3/CreateFileMappingW.c
new file mode 100644
index 0000000000..1cbeff94a7
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test3/CreateFileMappingW.c
@@ -0,0 +1,156 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: createfilemappingw.c (test 3)
+**
+** Purpose: Positive test the CreateFileMappingW API.
+** Call CreateFileMapping with access PAGE_READWRITE.
+**
+**
+**============================================================*/
+#define UNICODE
+#include <palsuite.h>
+
+const int MAPPINGSIZE = 2048;
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ HANDLE hFile;
+ char buf[] = "this is a test string";
+ char ch[2048];
+ WCHAR lpFileName[] = {'t','e','s','t','.','t','m','p','\0'};
+ HANDLE hFileMapping;
+ LPVOID lpMapViewAddress;
+ int RetVal = PASS;
+
+ /* Initialize the PAL environment.
+ */
+ if(0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ /* Create a file handle with CreateFile.
+ */
+ hFile = CreateFile( lpFileName,
+ GENERIC_WRITE|GENERIC_READ,
+ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ NULL,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if (hFile == INVALID_HANDLE_VALUE)
+ {
+ Fail("ERROR: %u :unable to create file \"%s\".\n",
+ GetLastError(),
+ lpFileName);
+ }
+
+ /* Initialize the buffers.
+ */
+ memset(ch, 0, MAPPINGSIZE);
+
+ /* Create a unnamed file-mapping object with file handle FileHandle
+ * and with PAGE_READWRITE protection.
+ */
+ hFileMapping = CreateFileMapping(
+ hFile,
+ NULL, /*not inherited*/
+ PAGE_READWRITE, /*read and wite*/
+ 0, /*high-order size*/
+ MAPPINGSIZE, /*low-order size*/
+ NULL); /*unnamed object*/
+
+ if(NULL == hFileMapping)
+ {
+ Trace("ERROR:%u: Failed to create File Mapping.\n",
+ GetLastError());
+ RetVal = FAIL;
+ goto CleanUpOne;
+ }
+
+ /* maps a view of a file into the address space of the calling process.
+ */
+ lpMapViewAddress = MapViewOfFile(
+ hFileMapping,
+ FILE_MAP_ALL_ACCESS, /* access code */
+ 0, /*high order offset*/
+ 0, /*low order offset*/
+ MAPPINGSIZE); /* number of bytes for map */
+
+ if(NULL == lpMapViewAddress)
+ {
+ Trace("ERROR:%u: Failed to call MapViewOfFile "
+ "API to map a view of file!\n",
+ GetLastError());
+ RetVal = FAIL;
+ goto CleanUpTwo;
+ }
+
+ /* Write to the Map view.
+ */
+ memcpy(lpMapViewAddress, buf, strlen(buf));
+
+ /* Read from the Map view.
+ */
+ memcpy(ch, (LPCSTR)lpMapViewAddress, MAPPINGSIZE);
+
+ /* Copy the MapViewOfFile to buffer, so we can
+ * compare with value read from file directly.
+ */
+ if (memcmp(ch, buf, strlen(buf))!= 0)
+ {
+ Trace("ERROR: MapViewOfFile not equal to file contents "
+ "retrieved \"%s\", expected \"%s\".\n",
+ ch, buf);
+ RetVal = FAIL;
+ goto CleanUpThree;
+ }
+
+CleanUpThree:
+
+ /* Unmap the view of file.
+ */
+ if ( UnmapViewOfFile(lpMapViewAddress) == FALSE )
+ {
+ Trace("ERROR:%u: Failed to UnmapViewOfFile of \"%0x%lx\".\n",
+ GetLastError(),
+ lpMapViewAddress);
+ RetVal = FAIL;
+ }
+
+CleanUpTwo:
+
+ /* Close Handle to opend file mapping.
+ */
+ if ( CloseHandle(hFileMapping) == FALSE )
+ {
+ Trace("ERROR:%u: Failed to CloseHandle \"0x%lx\".\n",
+ GetLastError(),
+ hFileMapping);
+ RetVal = FAIL;
+ }
+
+CleanUpOne:
+
+ /* Close Handle to create file mapping.
+ */
+ if ( CloseHandle(hFile) == FALSE )
+ {
+ Trace("ERROR:%u: Failed to CloseHandle \"0x%lx\".\n",
+ GetLastError(),
+ hFile);
+ RetVal = FAIL;
+ }
+
+ /* Terminate the PAL.
+ */
+ PAL_TerminateEx(RetVal);
+ return RetVal;
+}
+
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test3/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test3/testinfo.dat
new file mode 100644
index 0000000000..1077316618
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test3/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = CreateFileMappingW
+Name = CreateFileMappingW with PAGE_READWRITE
+TYPE = DEFAULT
+EXE1 = createfilemappingw
+Description
+=Test the CreateFileMappingW to create a unnamed file-mapping object
+=and with PAGE_READWRITE protection
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test4/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test4/CMakeLists.txt
new file mode 100644
index 0000000000..f8a5c9041f
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test4/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ CreateFileMappingW.c
+)
+
+add_executable(paltest_createfilemappingw_test4
+ ${SOURCES}
+)
+
+add_dependencies(paltest_createfilemappingw_test4 coreclrpal)
+
+target_link_libraries(paltest_createfilemappingw_test4
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test4/CreateFileMappingW.c b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test4/CreateFileMappingW.c
new file mode 100644
index 0000000000..265a317b2f
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test4/CreateFileMappingW.c
@@ -0,0 +1,182 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: createfilemappingw.c (test 4)
+**
+** Purpose: Positive test the CreateFileMappingW API.
+** Call CreateFileMappingW with access PAGE_WRITECOPY.
+**
+**
+**============================================================*/
+#define UNICODE
+#include <palsuite.h>
+
+const int MAPPINGSIZE = 2048;
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ HANDLE hFile;
+ char buf[] = "this is a test string";
+ char ch[2048];
+ WCHAR lpFileName[] = {'t','e','s','t','.','t','m','p','\0'};
+ HANDLE hFileMapping;
+ LPVOID lpMapViewAddress;
+ int RetVal = PASS;
+ int err;
+ DWORD dwBytesWritten;
+
+
+ /* Initialize the PAL environment.
+ */
+ if(0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ /* Create a file handle with CreateFile.
+ */
+ hFile = CreateFile( lpFileName,
+ GENERIC_WRITE|GENERIC_READ,
+ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ NULL,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if (hFile == INVALID_HANDLE_VALUE)
+ {
+ Fail("ERROR: %u :unable to create file \"%s\".\n",
+ GetLastError(),
+ lpFileName);
+ }
+
+ /* Write to the File handle.
+ */
+ err = WriteFile(hFile,
+ buf,
+ strlen(buf),
+ &dwBytesWritten,
+ NULL);
+
+ if (err == FALSE)
+ {
+ Trace("ERROR: %u :unable to write to file handle "
+ "hFile=0x%lx\n",
+ GetLastError(),
+ hFile);
+ RetVal = FAIL;
+ goto CleanUpOne;
+ }
+
+ /* Flush to the hard-drive.
+ */
+ FlushFileBuffers(hFile);
+
+ /* Initialize the buffers.
+ */
+ memset(ch, 0, MAPPINGSIZE);
+
+ /* Create a unnamed file-mapping object with file handle FileHandle
+ * and with PAGE_WRITECOPY protection.
+ */
+ hFileMapping = CreateFileMapping(
+ hFile,
+ NULL, /*not inherited*/
+ PAGE_WRITECOPY, /*write copy*/
+ 0, /*high-order size*/
+ 0, /*low-order size*/
+ NULL); /*unnamed object*/
+
+ if(NULL == hFileMapping)
+ {
+ Trace("ERROR:%u: Failed to create File Mapping.\n",
+ GetLastError());
+ RetVal = FAIL;
+ goto CleanUpOne;
+ }
+
+ /* maps a view of a file into the address space of the calling process.
+ */
+ lpMapViewAddress = MapViewOfFile(
+ hFileMapping,
+ FILE_MAP_COPY, /* access code */
+ 0, /* high order offset*/
+ 0, /* low order offset*/
+ 0); /* number of bytes for map */
+
+ if(NULL == lpMapViewAddress)
+ {
+ Trace("ERROR:%u: Failed to call MapViewOfFile "
+ "API to map a view of file!\n",
+ GetLastError());
+ RetVal = FAIL;
+ goto CleanUpTwo;
+ }
+
+ /* Write to the Map view.3
+ */
+ memcpy(lpMapViewAddress, buf, strlen(buf));
+
+ /* Read from the Map view.
+ */
+ memcpy(ch, (LPCSTR)lpMapViewAddress, MAPPINGSIZE);
+
+ /* Copy the MapViewOfFile to buffer, so we can
+ * compare with value read from file directly.
+ */
+ if (memcmp(ch, buf, strlen(buf))!= 0)
+ {
+ Trace("ERROR: MapViewOfFile not equal to file contents "
+ "retrieved \"%s\", expected \"%s\".\n",
+ ch, buf);
+ RetVal = FAIL;
+ goto CleanUpThree;
+ }
+
+CleanUpThree:
+
+ /* Unmap the view of file.
+ */
+ if ( UnmapViewOfFile(lpMapViewAddress) == FALSE )
+ {
+ Trace("ERROR:%u: Failed to UnmapViewOfFile of \"%0x%lx\".\n",
+ GetLastError(),
+ lpMapViewAddress);
+ RetVal = FAIL;
+ }
+
+CleanUpTwo:
+
+ /* Close Handle to opend file mapping.
+ */
+ if ( CloseHandle(hFileMapping) == FALSE )
+ {
+ Trace("ERROR:%u: Failed to CloseHandle \"0x%lx\".\n",
+ GetLastError(),
+ hFileMapping);
+ RetVal = FAIL;
+ }
+
+CleanUpOne:
+
+ /* Close Handle to create file mapping.
+ */
+ if ( CloseHandle(hFile) == FALSE )
+ {
+ Trace("ERROR:%u: Failed to CloseHandle \"0x%lx\".\n",
+ GetLastError(),
+ hFile);
+ RetVal = FAIL;
+ }
+
+ /* Terminate the PAL.
+ */
+ PAL_TerminateEx(RetVal);
+ return RetVal;
+}
+
+
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test4/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test4/testinfo.dat
new file mode 100644
index 0000000000..472b857eff
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test4/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = CreateFileMappingW
+Name = CreateFileMappingW with PAGE_WRITECOPY.
+TYPE = DEFAULT
+EXE1 = createfilemappingw
+Description
+=Test the CreateFileMapping to create a unnamed file-mapping object
+=and with PAGE_WRITE protection
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test5/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test5/CMakeLists.txt
new file mode 100644
index 0000000000..8391fbd721
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test5/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ CreateFileMappingW.c
+)
+
+add_executable(paltest_createfilemappingw_test5
+ ${SOURCES}
+)
+
+add_dependencies(paltest_createfilemappingw_test5 coreclrpal)
+
+target_link_libraries(paltest_createfilemappingw_test5
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test5/CreateFileMappingW.c b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test5/CreateFileMappingW.c
new file mode 100644
index 0000000000..21bf7c6d76
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test5/CreateFileMappingW.c
@@ -0,0 +1,194 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: createfilemappingw.c (test 5)
+**
+** Purpose: Positive test the CreateFileMappingW API.
+** Test CreateFileMappingW to a "swap" handle with
+** access PAGE_READONLY.
+**
+**
+**============================================================*/
+#define UNICODE
+#include <palsuite.h>
+
+const int MAPPINGSIZE = 2048;
+HANDLE SWAP_HANDLE = ((VOID *)(-1));
+
+int __cdecl main(int argc, char *argv[])
+{
+ char testString[] = "this is a test string";
+ WCHAR lpObjectName[] = {'m','y','O','b','j','e','c','t','\0'};
+ int RetVal = FAIL;
+ char results[2048];
+
+ HANDLE hFileMapRO;
+ HANDLE hFileMapRW;
+ LPVOID lpMapViewRO;
+ LPVOID lpMapViewRW;
+
+ /* Initialize the PAL environment.
+ */
+ if(0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ /* Initialize the buffers.
+ */
+ memset(results, 0, MAPPINGSIZE);
+
+ /* Create a named file-mapping object with file handle FileHandle
+ * and with PAGE_READWRITE protection.
+ */
+ hFileMapRW = CreateFileMapping(
+ SWAP_HANDLE,
+ NULL, /*not inherited*/
+ PAGE_READWRITE, /*read only*/
+ 0, /*high-order size*/
+ MAPPINGSIZE, /*low-order size*/
+ lpObjectName); /*named object*/
+
+ if(NULL == hFileMapRW)
+ {
+ Fail("ERROR:%u: Failed to create File Mapping.\n",
+ GetLastError());
+ }
+
+ /* maps a view of a file into the address space of the calling process.
+ */
+ lpMapViewRW = MapViewOfFile(
+ hFileMapRW,
+ FILE_MAP_ALL_ACCESS, /* access code */
+ 0, /* high order offset*/
+ 0, /* low order offset*/
+ MAPPINGSIZE); /* number of bytes for map */
+
+ if(NULL == lpMapViewRW)
+ {
+ Trace("ERROR:%u: Failed to call MapViewOfFile "
+ "API to map a view of file!\n",
+ GetLastError());
+ RetVal = FAIL;
+ goto CleanUpOne;
+ }
+
+
+ hFileMapRO = CreateFileMapping(
+ SWAP_HANDLE,
+ NULL, /*not inherited*/
+ PAGE_READONLY, /*read and write*/
+ 0, /*high-order size*/
+ MAPPINGSIZE, /*low-order size*/
+ lpObjectName); /*named object*/
+
+ if(NULL == hFileMapRO)
+ {
+ Trace("ERROR:%u: Failed to create File Mapping.\n",
+ GetLastError());
+ RetVal = FAIL;
+ goto CleanUpTwo;
+ }
+
+ /* maps a view of a file into the address space of the calling process.
+ */
+ lpMapViewRO = MapViewOfFile(
+ hFileMapRO,
+ FILE_MAP_READ, /* access code */
+ 0, /* high order offset*/
+ 0, /* low order offset*/
+ MAPPINGSIZE); /* number of bytes for map */
+
+ if(NULL == lpMapViewRO)
+ {
+ Trace("ERROR:%u: Failed to call MapViewOfFile "
+ "API to map a view of file!\n",
+ GetLastError());
+ RetVal = FAIL;
+ goto CleanUpThree;
+ }
+
+ /* Write the test string to the Map view.
+ */
+ memcpy(lpMapViewRW, testString, strlen(testString));
+
+ /* Read from the second Map view.
+ */
+ memcpy(results, (LPCSTR)lpMapViewRO, MAPPINGSIZE);
+
+ /* Verify the contents of the file mapping,
+ * by comparing what was written to what was read.
+ */
+ if (memcmp(results, testString, strlen(testString))!= 0)
+ {
+ Trace("ERROR: MapViewOfFile not equal to file contents "
+ "retrieved \"%s\", expected \"%s\".\n",
+ results,
+ testString);
+ RetVal = FAIL;
+ goto CleanUpFour;
+ }
+
+ /* Test was successful.
+ */
+ RetVal = PASS;
+
+CleanUpFour:
+
+ /* Unmap the view of file.
+ */
+ if ( UnmapViewOfFile(lpMapViewRO) == FALSE )
+ {
+ Trace("ERROR:%u: Failed to UnmapViewOfFile of \"%0x%lx\".\n",
+ GetLastError(),
+ lpMapViewRO);
+ RetVal = FAIL;
+ }
+
+CleanUpThree:
+
+ /* Close Handle to opend file mapping.
+ */
+ if ( CloseHandle(hFileMapRO) == FALSE )
+ {
+ Trace("ERROR:%u: Failed to CloseHandle \"0x%lx\".\n",
+ GetLastError(),
+ hFileMapRO);
+ RetVal = FAIL;
+ }
+
+
+CleanUpTwo:
+ /* Unmap the view of file.
+ */
+ if ( UnmapViewOfFile(lpMapViewRW) == FALSE )
+ {
+ Trace("ERROR:%u: Failed to UnmapViewOfFile of \"%0x%lx\".\n",
+ GetLastError(),
+ lpMapViewRW);
+ RetVal = FAIL;
+ }
+
+
+CleanUpOne:
+
+ /* Close Handle to opend file mapping.
+ */
+ if ( CloseHandle(hFileMapRW) == FALSE )
+ {
+ Trace("ERROR:%u: Failed to CloseHandle \"0x%lx\".\n",
+ GetLastError(),
+ hFileMapRW);
+ RetVal = FAIL;
+ }
+
+
+ /* Terminate the PAL.
+ */
+ PAL_TerminateEx(RetVal);
+ return RetVal;
+}
+
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test5/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test5/testinfo.dat
new file mode 100644
index 0000000000..87e16d3d79
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test5/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = CreateFileMappingW
+Name = CreateFileMappingW - PAGE_READWRITE
+TYPE = DEFAULT
+EXE1 = createfilemappingw
+Description
+= Positive test the CreateFileMappingW API.
+= Test CreateFileMappingW to create a named
+= "swap" handle with access PAGE_READONLY.
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test6/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test6/CMakeLists.txt
new file mode 100644
index 0000000000..abb62ad950
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test6/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ CreateFileMappingW.c
+)
+
+add_executable(paltest_createfilemappingw_test6
+ ${SOURCES}
+)
+
+add_dependencies(paltest_createfilemappingw_test6 coreclrpal)
+
+target_link_libraries(paltest_createfilemappingw_test6
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test6/CreateFileMappingW.c b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test6/CreateFileMappingW.c
new file mode 100644
index 0000000000..acf3ac6dff
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test6/CreateFileMappingW.c
@@ -0,0 +1,165 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: createfilemappingw.c (test 6)
+**
+** Purpose: Positive test the CreateFileMappingW API.
+** Test CreateFileMappingW to a "swap" handle with
+** access PAGE_READWRITE.
+**
+**
+**============================================================*/
+#define UNICODE
+#include <palsuite.h>
+
+const int MAPPINGSIZE = 2048;
+HANDLE SWAP_HANDLE = ((VOID *)(-1));
+
+int __cdecl main(int argc, char *argv[])
+{
+ char testString[] = "this is a test string";
+ WCHAR lpObjectName[] = {'m','y','O','b','j','e','c','t','\0'};
+ char results[2048];
+ int RetVal = PASS;
+
+ HANDLE hFileMapRW;
+ LPVOID lpMapViewRW;
+ LPVOID lpMapViewRW2;
+
+ /* Initialize the PAL environment.
+ */
+ if(0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ /* Initialize the buffers.
+ */
+ memset(results, 0, MAPPINGSIZE);
+
+ /* Create a named file-mapping object with file handle FileHandle
+ * and with PAGE_READWRITE protection.
+ */
+ hFileMapRW = CreateFileMapping(
+ SWAP_HANDLE,
+ NULL, /*not inherited*/
+ PAGE_READWRITE, /*read write*/
+ 0, /*high-order size*/
+ MAPPINGSIZE, /*low-order size*/
+ lpObjectName); /*named object*/
+
+ if(NULL == hFileMapRW)
+ {
+ Fail("ERROR:%u: Failed to create File Mapping.\n",
+ GetLastError());
+ }
+
+ /* Create a map view of the READWRITE file mapping.
+ */
+ lpMapViewRW = MapViewOfFile(
+ hFileMapRW,
+ FILE_MAP_ALL_ACCESS,/* access code */
+ 0, /* high order offset*/
+ 0, /* low order offset*/
+ MAPPINGSIZE); /* number of bytes for map */
+
+ if(NULL == lpMapViewRW)
+ {
+ Trace("ERROR:%u: Failed to call MapViewOfFile "
+ "API to map a view of file!\n",
+ GetLastError());
+ RetVal = FAIL;
+ goto CleanUpOne;
+ }
+
+
+ /* maps a view of a file into the address space of the calling process.
+ */
+ lpMapViewRW2 = MapViewOfFile(
+ hFileMapRW,
+ FILE_MAP_ALL_ACCESS, /* access code */
+ 0, /* high order offset*/
+ 0, /* low order offset*/
+ MAPPINGSIZE); /* number of bytes for map */
+
+ if(NULL == lpMapViewRW2)
+ {
+ Trace("ERROR:%u: Failed to call MapViewOfFile "
+ "API to map a view of file!\n",
+ GetLastError());
+ RetVal = FAIL;
+ goto CleanUpTwo;
+ }
+
+ /* Write the test string to the Map view.
+ */
+ memcpy(lpMapViewRW, testString, strlen(testString));
+
+ /* Read from the second Map view.
+ */
+ memcpy(results, (LPCSTR)lpMapViewRW2, MAPPINGSIZE);
+
+ /* Verify the contents of the file mapping,
+ * by comparing what was written to what was read.
+ */
+ if (memcmp(results, testString, strlen(testString))!= 0)
+ {
+ Trace("ERROR: MapViewOfFile not equal to file contents "
+ "retrieved \"%s\", expected \"%s\".\n",
+ results,
+ testString);
+ RetVal = FAIL;
+ goto CleanUpThree;
+ }
+
+ /* Test successful.
+ */
+ RetVal = PASS;
+
+CleanUpThree:
+
+ /* Unmap the view of file.
+ */
+ if ( UnmapViewOfFile(lpMapViewRW2) == FALSE )
+ {
+ Trace("ERROR:%u: Failed to UnmapViewOfFile of \"%0x%lx\".\n",
+ GetLastError(),
+ lpMapViewRW2);
+ RetVal = FAIL;
+ }
+
+CleanUpTwo:
+
+ /* Unmap the view of file.
+ */
+ if ( UnmapViewOfFile(lpMapViewRW) == FALSE )
+ {
+ Trace("ERROR:%u: Failed to UnmapViewOfFile of \"%0x%lx\".\n",
+ GetLastError(),
+ lpMapViewRW);
+ RetVal = FAIL;
+ }
+
+
+CleanUpOne:
+
+ /* Close Handle to create file mapping.
+ */
+ if ( CloseHandle(hFileMapRW) == FALSE )
+ {
+ Trace("ERROR:%u: Failed to CloseHandle \"0x%lx\".\n",
+ GetLastError(),
+ hFileMapRW);
+ RetVal = FAIL;
+ }
+
+
+ /* Terminate the PAL.
+ */
+ PAL_TerminateEx(RetVal);
+ return RetVal;
+}
+
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test6/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test6/testinfo.dat
new file mode 100644
index 0000000000..7afae68f16
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test6/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = CreateFileMapping
+Name = CreateFileMappingA - with PAGE_READONLY
+TYPE = DEFAULT
+EXE1 = createfilemappingw
+Description
+= Positive test the CreateFileMappingW API.
+= Test CreateFileMappingW to create a named
+= "swap" handle with access PAGE_READWRITE.
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test7/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test7/CMakeLists.txt
new file mode 100644
index 0000000000..b40cfeae96
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test7/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ createfilemapping.c
+)
+
+add_executable(paltest_createfilemappingw_test7
+ ${SOURCES}
+)
+
+add_dependencies(paltest_createfilemappingw_test7 coreclrpal)
+
+target_link_libraries(paltest_createfilemappingw_test7
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test7/createfilemapping.c b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test7/createfilemapping.c
new file mode 100644
index 0000000000..e49b9f688d
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test7/createfilemapping.c
@@ -0,0 +1,165 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: createfilemappingw.c (test 7)
+**
+** Purpose: Positive test the CreateFileMappingW API.
+** Test CreateFileMappingW to a "swap" handle with
+** access PAGE_READWRITE.
+**
+**
+**============================================================*/
+#define UNICODE
+#include <palsuite.h>
+
+const int MAPPINGSIZE = 2048;
+HANDLE SWAP_HANDLE = ((VOID *)(-1));
+
+int __cdecl main(int argc, char *argv[])
+{
+ char testString[] = "this is a test string";
+ WCHAR lpObjectName[] = {'m','y','O','b','j','e','c','t','\0'};
+ char results[2048];
+ int RetVal = PASS;
+
+ HANDLE hFileMapRW;
+ LPVOID lpMapViewRW;
+ LPVOID lpMapViewRO;
+
+ /* Initialize the PAL environment.
+ */
+ if(0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ /* Initialize the buffers.
+ */
+ memset(results, 0, MAPPINGSIZE);
+
+ /* Create a named file-mapping object with file handle FileHandle
+ * and with PAGE_READWRITE protection.
+ */
+ hFileMapRW = CreateFileMapping(
+ SWAP_HANDLE,
+ NULL, /*not inherited*/
+ PAGE_READWRITE, /*read write*/
+ 0, /*high-order size*/
+ MAPPINGSIZE, /*low-order size*/
+ lpObjectName); /*unnamed object*/
+
+ if(NULL == hFileMapRW)
+ {
+ Fail("ERROR:%u: Failed to create File Mapping.\n",
+ GetLastError());
+ }
+
+ /* Create a map view to the READWRITE file mapping.
+ */
+ lpMapViewRW = MapViewOfFile(
+ hFileMapRW,
+ FILE_MAP_ALL_ACCESS,/* access code */
+ 0, /* high order offset*/
+ 0, /* low order offset*/
+ MAPPINGSIZE); /* number of bytes for map */
+
+ if(NULL == lpMapViewRW)
+ {
+ Trace("ERROR:%u: Failed to call MapViewOfFile "
+ "API to map a view of file!\n",
+ GetLastError());
+ RetVal = FAIL;
+ goto CleanUpOne;
+ }
+
+
+ /* Create a map view to the READWRITE file mapping.
+ */
+ lpMapViewRO = MapViewOfFile(
+ hFileMapRW,
+ FILE_MAP_READ, /* access code */
+ 0, /* high order offset*/
+ 0, /* low order offset*/
+ MAPPINGSIZE); /* number of bytes for map */
+
+ if(NULL == lpMapViewRO)
+ {
+ Trace("ERROR:%u: Failed to call MapViewOfFile "
+ "API to map a view of file!\n",
+ GetLastError());
+ RetVal = FAIL;
+ goto CleanUpTwo;
+ }
+
+ /* Write the test string to the Map view.
+ */
+ memcpy(lpMapViewRW, testString, strlen(testString));
+
+ /* Read from the second Map view.
+ */
+ memcpy(results, (LPCSTR)lpMapViewRO, MAPPINGSIZE);
+
+ /* Verify the contents of the file mapping,
+ * by comparing what was written to what was read.
+ */
+ if (memcmp(results, testString, strlen(testString))!= 0)
+ {
+ Trace("ERROR: MapViewOfFile not equal to file contents "
+ "retrieved \"%s\", expected \"%s\".\n",
+ results,
+ testString);
+ RetVal = FAIL;
+ goto CleanUpThree;
+ }
+
+ /* Test successful.
+ */
+ RetVal = PASS;
+
+CleanUpThree:
+
+ /* Unmap the view of file.
+ */
+ if ( UnmapViewOfFile(lpMapViewRO) == FALSE )
+ {
+ Trace("ERROR:%u: Failed to UnmapViewOfFile of \"%0x%lx\".\n",
+ GetLastError(),
+ lpMapViewRO);
+ RetVal = FAIL;
+ }
+
+CleanUpTwo:
+
+ /* Unmap the view of file.
+ */
+ if ( UnmapViewOfFile(lpMapViewRW) == FALSE )
+ {
+ Trace("ERROR:%u: Failed to UnmapViewOfFile of \"%0x%lx\".\n",
+ GetLastError(),
+ lpMapViewRW);
+ RetVal = FAIL;
+ }
+
+
+CleanUpOne:
+
+ /* Close Handle to create file mapping.
+ */
+ if ( CloseHandle(hFileMapRW) == FALSE )
+ {
+ Trace("ERROR:%u: Failed to CloseHandle \"0x%lx\".\n",
+ GetLastError(),
+ hFileMapRW);
+ RetVal = FAIL;
+ }
+
+
+ /* Terminate the PAL.
+ */
+ PAL_TerminateEx(RetVal);
+ return RetVal;
+}
+
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test7/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test7/testinfo.dat
new file mode 100644
index 0000000000..a68a665d74
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test7/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = CreateFileMappingW
+Name = CreateFileMappingW - PAGE_COPYWRITE
+TYPE = DEFAULT
+EXE1 = createfilemapping
+Description
+= Positive test the CreateFileMappingW API.
+= Test CreateFileMappingW to create a named
+= "swap" handle with access PAGE_READWRITE
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test8/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test8/CMakeLists.txt
new file mode 100644
index 0000000000..96658c163a
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test8/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ createfilemapping.c
+)
+
+add_executable(paltest_createfilemappingw_test8
+ ${SOURCES}
+)
+
+add_dependencies(paltest_createfilemappingw_test8 coreclrpal)
+
+target_link_libraries(paltest_createfilemappingw_test8
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test8/createfilemapping.c b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test8/createfilemapping.c
new file mode 100644
index 0000000000..1ff137d8d3
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test8/createfilemapping.c
@@ -0,0 +1,82 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: createfilemappingw.c (test 8)
+**
+** Purpose: Positive test the CreateFileMappingW API.
+** Test the un-verifiable parameter combinations.
+**
+**
+**============================================================*/
+#define UNICODE
+#include <palsuite.h>
+
+const int MAPPINGSIZE = 2048;
+HANDLE SWAP_HANDLE = ((VOID *)(-1));
+
+int __cdecl main(int argc, char *argv[])
+{
+ WCHAR lpObjectName[] = {'m','y','O','b','j','e','c','t','\0'};
+
+ HANDLE hFileMap;
+
+ /* Initialize the PAL environment.
+ */
+ if(0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ /* Create a READONLY, "swap", un-named file mapping.
+ * This test is unverifiable since there is no hook back to the file map
+ * because it is un-named. As well, since it resides in "swap", and is
+ * initialized to zero, there is nothing to read.
+ */
+ hFileMap = CreateFileMapping(
+ SWAP_HANDLE,
+ NULL, /*not inherited*/
+ PAGE_READONLY, /*read only*/
+ 0, /*high-order size*/
+ MAPPINGSIZE, /*low-order size*/
+ NULL); /*un-named object*/
+
+ if(NULL == hFileMap)
+ {
+ Fail("ERROR:%u: Failed to create File Mapping.\n",
+ GetLastError());
+ }
+
+
+ /* Create a COPYWRITE, "swap", un-named file mapping.
+ * This test is unverifiable, here is a quote from MSDN:
+ *
+ * Copy on write access. If you create the map with PAGE_WRITECOPY and
+ * the view with FILE_MAP_COPY, you will receive a view to file. If you
+ * write to it, the pages are automatically swappable and the modifications
+ * you make will not go to the original data file.
+ *
+ */
+ hFileMap = CreateFileMapping(
+ SWAP_HANDLE,
+ NULL, /*not inherited*/
+ PAGE_WRITECOPY, /*write copy*/
+ 0, /*high-order size*/
+ MAPPINGSIZE, /*low-order size*/
+ NULL); /*unnamed object*/
+
+ if(NULL == hFileMap)
+ {
+ Fail("ERROR:%u: Failed to create File Mapping.\n",
+ GetLastError());
+ }
+
+
+ /* Terminate the PAL.
+ */
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test8/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test8/testinfo.dat
new file mode 100644
index 0000000000..475d827af4
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test8/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = CreateFileMappingW - Special cases
+Name = CreateFileMappingW
+TYPE = DEFAULT
+EXE1 = createfilemapping
+Description
+= Positive test the CreateFileMappingW API.
+= Test the un-verifiable parameter combinations.
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test9/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test9/CMakeLists.txt
new file mode 100644
index 0000000000..5a55e27b33
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test9/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ createfilemapping.c
+)
+
+add_executable(paltest_createfilemappingw_test9
+ ${SOURCES}
+)
+
+add_dependencies(paltest_createfilemappingw_test9 coreclrpal)
+
+target_link_libraries(paltest_createfilemappingw_test9
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test9/createfilemapping.c b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test9/createfilemapping.c
new file mode 100644
index 0000000000..16ae74c126
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test9/createfilemapping.c
@@ -0,0 +1,151 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: createfilemapping.c (test 9)
+**
+** Purpose: Negative test the CreateFileMappingW API.
+**
+**
+**============================================================*/
+#define UNICODE
+#include <palsuite.h>
+
+const int MAPPINGSIZE = 2048;
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ HANDLE hFile;
+ WCHAR lpFileName[] = {'t','e','s','t','.','t','m','p','\0'};
+
+ HANDLE hFileMapping;
+
+ /* Initialize the PAL environment.
+ */
+ if(0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ /* Create a file handle with CreateFile, as READONLY
+ */
+ hFile = CreateFile( lpFileName,
+ GENERIC_READ,
+ FILE_SHARE_READ,
+ NULL,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if (hFile == INVALID_HANDLE_VALUE)
+ {
+ Fail("ERROR: %u :unable to create file \"%s\".\n",
+ GetLastError(),
+ lpFileName);
+ }
+
+ /* Attempt to create a unnamed file-mapping object to a READONLY file
+ * as READWRITE access.
+ */
+ hFileMapping = CreateFileMapping(
+ hFile,
+ NULL, /*not inherited*/
+ PAGE_READWRITE, /*read and write*/
+ 0, /*high-order size*/
+ MAPPINGSIZE, /*low-order size*/
+ NULL); /*unnamed object*/
+
+ if(NULL != hFileMapping)
+ {
+ Trace("ERROR: Able to create READWRITE mapping to a "
+ "READONLY file.\n" );
+ if( 0 == CloseHandle(hFile) )
+ {
+ Trace("Unexpected Error: Unable to close file handle\n");
+ }
+ Fail("");
+ }
+
+ /* Attempt to create a unnamed file-mapping object to a zero lenght
+ * file.
+ */
+ hFileMapping = CreateFileMapping(
+ hFile,
+ NULL, /*not inherited*/
+ PAGE_READWRITE, /*read and write*/
+ 0, /*high-order size*/
+ 0, /*low-order size*/
+ NULL); /*unnamed object*/
+
+ if( NULL != hFileMapping )
+ {
+ Trace("ERROR: Able to create READWRITE mapping to a "
+ "READONLY file.\n" );
+ if( 0 == CloseHandle(hFile) )
+ {
+ Trace("Unexpected Error: Unable to close file handle\n");
+ }
+ Fail("");
+ }
+ if(GetLastError() != ERROR_ACCESS_DENIED)
+ {
+ Trace("ERROR: Expected GetLastError() to return "
+ "ERROR_FILE_INVALID (%d), it returned %u.\n",
+ ERROR_FILE_INVALID,
+ GetLastError());
+ if( 0 == CloseHandle(hFile) )
+ {
+ Trace("Unexpected Error: Unable to close file handle\n");
+ }
+ Fail("");
+ }
+
+ /* Attempt to create a file mapping that is larger than
+ * the file.
+ */
+ hFileMapping = CreateFileMapping(
+ hFile,
+ NULL, /*not inherited*/
+ PAGE_READONLY, /*read only*/
+ 0, /*high-order size*/
+ MAPPINGSIZE, /*low-order size*/
+ NULL); /*unnamed object*/
+ if(NULL != hFileMapping)
+ {
+ Trace("ERROR: Able to create file mapping of size %d to "
+ "file of size 0.\n",
+ MAPPINGSIZE);
+ if( 0 == CloseHandle(hFile) )
+ {
+ Trace("Unexpected Error: Unable to close file handle\n");
+ }
+ Fail("");
+ }
+
+ if(GetLastError() != ERROR_NOT_ENOUGH_MEMORY )
+ {
+ Trace("ERROR: Expected GetLastError() to return "
+ "ERROR_NOT_ENOUGH_MEMORY (%d), it returned %u.\n",
+ ERROR_NOT_ENOUGH_MEMORY,
+ GetLastError());
+ if( 0 == CloseHandle(hFile) )
+ {
+ Trace("Unexpected Error: Unable to close file handle\n");
+ }
+ Fail("");
+ }
+
+ if( 0 == CloseHandle(hFile) )
+ {
+ Fail("Unexpected Error: Unable to close file handle\n");
+ }
+
+ /* Terminate the PAL.
+ */
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test9/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test9/testinfo.dat
new file mode 100644
index 0000000000..2a7ecdbab7
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/CreateFileMappingW/test9/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = CreateFileMappingW
+Name = CreateFileMappingW negative testing
+TYPE = DEFAULT
+EXE1 = createfilemapping
+Description
+= Negative test the CreateFileMapping API.
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/FreeLibrary/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/FreeLibrary/CMakeLists.txt
new file mode 100644
index 0000000000..ef14ea5352
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/FreeLibrary/CMakeLists.txt
@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/FreeLibrary/test1/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/FreeLibrary/test1/CMakeLists.txt
new file mode 100644
index 0000000000..3807621e3f
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/FreeLibrary/test1/CMakeLists.txt
@@ -0,0 +1,20 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ dlltest.c
+ FreeLibrary.c
+)
+
+add_executable(paltest_freelibrary_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_freelibrary_test1 coreclrpal)
+
+target_link_libraries(paltest_freelibrary_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/FreeLibrary/test1/FreeLibrary.c b/src/pal/tests/palsuite/filemapping_memmgt/FreeLibrary/test1/FreeLibrary.c
new file mode 100644
index 0000000000..a06a231586
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/FreeLibrary/test1/FreeLibrary.c
@@ -0,0 +1,128 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source:
+**
+** Purpose: Positive test the FreeLibrary API.
+**
+**
+**============================================================*/
+#include <palsuite.h>
+
+/*char LibraryName[] = "dlltest";*/
+/* SHLEXT is defined only for Unix variants */
+
+#if defined(SHLEXT)
+#define LibraryName "dlltest"SHLEXT
+#else
+#define LibraryName "dlltest"
+#endif
+
+
+
+
+BOOL PALAPI TestDll(HMODULE, int);
+
+int __cdecl main(int argc, char *argv[])
+{
+ HANDLE hLib;
+
+ /* Initialize the PAL. */
+ if ((PAL_Initialize(argc, argv)) != 0)
+ {
+ return (FAIL);
+ }
+
+ /*Load library (DLL). */
+ hLib = LoadLibrary(LibraryName);
+
+ if(hLib == NULL)
+ {
+ Fail("ERROR:%u:Unable to load library %s\n",
+ GetLastError(),
+ LibraryName);
+ }
+
+ /* Test access to DLL. */
+ if(!TestDll(hLib, PASS))
+ {
+ Trace("ERROR: TestDll function returned FALSE "
+ "expected TRUE\n.");
+ FreeLibrary(hLib);
+ Fail("");
+ }
+
+ /* Call the FreeLibrary API. */
+ if (!FreeLibrary(hLib))
+ {
+ Fail("ERROR:%u: Unable to free library \"%s\"\n",
+ GetLastError(),
+ LibraryName);
+ }
+
+ /* Test access to the free'd DLL. */
+ if(!TestDll(hLib, FAIL))
+ {
+ Fail("ERROR: TestDll function returned FALSE "
+ "expected TRUE\n.");
+ }
+
+ PAL_Terminate();
+ return PASS;
+
+}
+
+
+BOOL PALAPI TestDll(HMODULE hLib, int testResult)
+{
+ int RetVal;
+#if WIN32
+ char FunctName[] = "_DllTest@0";
+#else
+ char FunctName[] = "DllTest";
+#endif
+ FARPROC DllAddr;
+
+ /* Attempt to grab the proc address of the dll function.
+ * This one should succeed.*/
+ if(testResult == PASS)
+ {
+ DllAddr = GetProcAddress(hLib, FunctName);
+ if(DllAddr == NULL)
+ {
+ Trace("ERROR: Unable to load function \"%s\" library \"%s\"\n",
+ FunctName,
+ LibraryName);
+ return (FALSE);
+ }
+ /* Run the function in the DLL,
+ * to ensure that the DLL was loaded properly.*/
+ RetVal = DllAddr();
+ if (RetVal != 1)
+ {
+ Trace("ERROR: Unable to receive correct information from DLL! "
+ ":expected \"1\", returned \"%d\"\n",
+ RetVal);
+ return (FALSE);
+ }
+ }
+
+ /* Attempt to grab the proc address of the dll function.
+ * This one should fail.*/
+ if(testResult == FAIL)
+ {
+ DllAddr = GetProcAddress(hLib, FunctName);
+ if(DllAddr != NULL)
+ {
+ Trace("ERROR: Able to load function \"%s\" from free'd"
+ " library \"%s\"\n",
+ FunctName,
+ LibraryName);
+ return (FALSE);
+ }
+ }
+ return (TRUE);
+}
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/FreeLibrary/test1/dlltest.c b/src/pal/tests/palsuite/filemapping_memmgt/FreeLibrary/test1/dlltest.c
new file mode 100644
index 0000000000..44f1b5a903
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/FreeLibrary/test1/dlltest.c
@@ -0,0 +1,32 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: dlltest.c (FreeLibrary test dll)
+**
+** Purpose: This file will be used to create the shared library
+** that will be used in the FreeLibraryAndExitThread
+** test. A very simple shared library, with one function
+** "DllTest" which merely returns 1.
+**
+**
+**===================================================================*/
+#include "pal.h"
+
+#if WIN32
+__declspec(dllexport)
+#endif
+
+int __stdcall DllTest()
+{
+ return 1;
+}
+
+#ifdef WIN32
+int __stdcall _DllMainCRTStartup(void *hinstDLL, int reason, void * lpvReserved)
+{
+ return 1;
+}
+#endif
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/FreeLibrary/test1/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/FreeLibrary/test1/testinfo.dat
new file mode 100644
index 0000000000..a09d21428f
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/FreeLibrary/test1/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = FreeLibrary
+Name = Positive test for FreeLibrary API
+TYPE = DEFAULT
+EXE1 = freelibrary
+LIB1 = dlltest
+Description
+=Test the FreeLibrary to decrement the reference
+=count of the loaded DLL
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/FreeLibrary/test2/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/FreeLibrary/test2/CMakeLists.txt
new file mode 100644
index 0000000000..00b1eca8e3
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/FreeLibrary/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test2.c
+)
+
+add_executable(paltest_freelibrary_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_freelibrary_test2 coreclrpal)
+
+target_link_libraries(paltest_freelibrary_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/FreeLibrary/test2/test2.c b/src/pal/tests/palsuite/filemapping_memmgt/FreeLibrary/test2/test2.c
new file mode 100644
index 0000000000..b43f74d6bc
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/FreeLibrary/test2/test2.c
@@ -0,0 +1,52 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test2.c (FreeLibrary)
+**
+** Purpose: Tests the PAL implementation of the FreeLibrary function.
+** This is a negative test that will pass an invalid and a
+** null handle to FreeLibrary.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char* argv[])
+{
+ HANDLE hLib;
+
+ /* Initialize the PAL.
+ */
+ if ((PAL_Initialize(argc, argv)) != 0)
+ {
+ return (FAIL);
+ }
+
+ /* Attempt to pass FreeLibrary an invalid handle.
+ */
+ hLib = INVALID_HANDLE_VALUE;
+ if (FreeLibrary(hLib))
+ {
+ Fail("ERROR: Able to free library handle = \"0x%lx\".\n",
+ hLib);
+ }
+
+ /* Attempt to pass FreeLibrary a NULL handle.
+ */
+ hLib = NULL;
+ if (FreeLibrary(hLib))
+ {
+ Fail("ERROR: Able to free library handle = \"NULL\".\n");
+ }
+
+
+ /* Terminate the PAL.
+ */
+ PAL_Terminate();
+ return PASS;
+
+}
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/FreeLibrary/test2/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/FreeLibrary/test2/testinfo.dat
new file mode 100644
index 0000000000..521fa6eaea
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/FreeLibrary/test2/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = FreeLibrary
+Name = Negative test for FreeLibrary
+TYPE = DEFAULT
+EXE1 = test2
+Description
+= Tests the PAL implementation of the FreeLibrary function.
+= This is a negative test that will pass an invalid and a
+= null handle to FreeLibrary.
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/FreeLibraryAndExitThread/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/FreeLibraryAndExitThread/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/FreeLibraryAndExitThread/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/FreeLibraryAndExitThread/test1/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/FreeLibraryAndExitThread/test1/CMakeLists.txt
new file mode 100644
index 0000000000..cec083583a
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/FreeLibraryAndExitThread/test1/CMakeLists.txt
@@ -0,0 +1,20 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ dlltest.c
+ test1.c
+)
+
+add_executable(paltest_freelibraryandexitthread_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_freelibraryandexitthread_test1 coreclrpal)
+
+target_link_libraries(paltest_freelibraryandexitthread_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/FreeLibraryAndExitThread/test1/dlltest.c b/src/pal/tests/palsuite/filemapping_memmgt/FreeLibraryAndExitThread/test1/dlltest.c
new file mode 100644
index 0000000000..954c624d19
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/FreeLibraryAndExitThread/test1/dlltest.c
@@ -0,0 +1,32 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: dlltest.c (FreeLibraryAndExitThread test dll)
+**
+** Purpose: This file will be used to create the shared library
+** that will be used in the FreeLibraryAndExitThread
+** test. A very simple shared library, with one function
+** "DllTest" which merely returns 1.
+**
+**
+**===================================================================*/
+#include "pal.h"
+
+#if WIN32
+__declspec(dllexport)
+#endif
+
+int _stdcall DllTest()
+{
+ return 1;
+}
+
+#if WIN32
+int __stdcall _DllMainCRTStartup(void *hinstDLL, int reason, void * lpvReserved)
+{
+ return 1;
+}
+#endif
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/FreeLibraryAndExitThread/test1/test1.c b/src/pal/tests/palsuite/filemapping_memmgt/FreeLibraryAndExitThread/test1/test1.c
new file mode 100644
index 0000000000..6aacfc83b4
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/FreeLibraryAndExitThread/test1/test1.c
@@ -0,0 +1,183 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test1.c (FreeLibraryAndExitThread)
+**
+** Purpose: Tests the PAL implementation of the FreeLibraryAndExitThread
+** function. FreeLibraryAndExitThread when run will exit the
+** process that it is called within, therefore we create a
+** thread to run the API. Then test for the existance of the
+** thread and access to the library.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+/*Define platform specific information*/
+
+/* SHLEXT is defined only for Unix variants */
+#if defined(SHLEXT)
+#define LibraryName "dlltest"SHLEXT
+#else
+#define LibraryName "dlltest"
+#endif
+
+#define TIMEOUT 60000
+
+BOOL PALAPI StartThreadTest();
+DWORD PALAPI CreateTestThread(LPVOID);
+BOOL PALAPI TestDll(HMODULE, int);
+
+int __cdecl main(int argc, char* argv[])
+{
+ /*Initialize the PAL*/
+ if ((PAL_Initialize(argc, argv)) != 0)
+ {
+ return (FAIL);
+ }
+
+ if (!StartThreadTest())
+ {
+ Fail("ERROR: FreeLibraryAndExitThread test failed.\n");
+ }
+
+ /*Terminate the PAL*/
+ PAL_Terminate();
+ return PASS;
+
+}
+
+
+BOOL PALAPI StartThreadTest()
+{
+ HMODULE hLib;
+ HANDLE hThread;
+ DWORD dwThreadId;
+ LPTHREAD_START_ROUTINE lpStartAddress = &CreateTestThread;
+ LPVOID lpParameter = lpStartAddress;
+ DWORD rc = -1;
+ /*Load library (DLL).*/
+ hLib = LoadLibrary(LibraryName);
+ if(hLib == NULL)
+ {
+ Trace("ERROR: Unable to load library %s\n", LibraryName);
+
+ return (FALSE);
+ }
+
+ /*Start the test thread*/
+ hThread = CreateThread(NULL,
+ (DWORD)0,
+ lpParameter,
+ hLib,
+ (DWORD)NULL,
+ &dwThreadId);
+ if(hThread == NULL)
+ {
+ Trace("ERROR:%u: Unable to create thread.\n",
+ GetLastError());
+
+ FreeLibrary(hLib);
+ return (FALSE);
+ }
+
+ /*Wait on thread.*/
+ rc = WaitForSingleObject(hThread, TIMEOUT);
+ if( rc != WAIT_OBJECT_0 )
+ {
+ Trace("ERROR:%u: hThread=0x%4.4lx not exited by "
+ "FreeLibraryAndExitThread, RC[%d]\n",
+ GetLastError(),
+ hThread, rc);
+
+// There is a possibility that the other thread might
+// still be using the library VSW:337893
+// FreeLibrary(hLib);
+ CloseHandle(hThread);
+ return (FALSE);
+ }
+
+ /*Test access to DLL.*/
+ if(!TestDll(hLib, 0))
+ {
+ Trace("ERROR: TestDll function returned FALSE "
+ "expected TRUE\n.");
+
+ CloseHandle(hThread);
+ return (FALSE);
+ }
+
+ FreeLibrary(hLib);
+ /*Clean-up thread.*/
+ CloseHandle(hThread);
+
+ return (TRUE);
+}
+
+BOOL PALAPI TestDll(HMODULE hLib, int testResult)
+{
+ int RetVal;
+ char FunctName[] = "DllTest";
+ FARPROC DllAddr;
+
+ /* Attempt to grab the proc address of the dll function.
+ * This one should succeed.*/
+ if(testResult == 1)
+ {
+ DllAddr = GetProcAddress(hLib, FunctName);
+ if(DllAddr == NULL)
+ {
+ Trace("ERROR: Unable to load function \"%s\" library \"%s\"\n",
+ FunctName,
+ LibraryName);
+ return (FALSE);
+ }
+ /* Run the function in the DLL,
+ * to ensure that the DLL was loaded properly.*/
+ RetVal = DllAddr();
+ if (RetVal != 1)
+ {
+ Trace("ERROR: Unable to receive correct information from DLL! "
+ ":expected \"1\", returned \"%d\"\n",
+ RetVal);
+ return (FALSE);
+ }
+ }
+
+ /* Attempt to grab the proc address of the dll function.
+ * This one should fail.*/
+ if(testResult == 0)
+ {
+ DllAddr = GetProcAddress(hLib, FunctName);
+ if(DllAddr != NULL)
+ {
+ Trace("ERROR: Able to load function \"%s\" from free'd"
+ " library \"%s\"\n",
+ FunctName,
+ LibraryName);
+ return (FALSE);
+ }
+ }
+ return (TRUE);
+}
+
+DWORD PALAPI CreateTestThread(LPVOID lpParam)
+{
+ /* Test access to DLL.*/
+ TestDll(lpParam, 1);
+
+ /*Free library and exit thread.*/
+ FreeLibraryAndExitThread(lpParam, (DWORD)0);
+
+ /* NOT REACHED */
+
+ /*Infinite loop, we should not get here.*/
+ while(1);
+
+ return (DWORD)0;
+}
+
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/FreeLibraryAndExitThread/test1/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/FreeLibraryAndExitThread/test1/testinfo.dat
new file mode 100644
index 0000000000..455829c0d5
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/FreeLibraryAndExitThread/test1/testinfo.dat
@@ -0,0 +1,17 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = FreeLibraryAndExitThread
+Name = Positive test for FreeLibraryAndExitThread
+TYPE = DEFAULT
+EXE1 = test1
+LIB1 = dlltest
+Description
+= Tests the PAL implementation of the FreeLibraryAndExitThread
+= function. When run, FreeLibraryAndExitThread will exit the
+= process that it is called within, therefore we create a
+= thread to run the API. Then we test for the existance of the
+= thread and access to the library.
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/GetModuleFileNameA/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/GetModuleFileNameA/CMakeLists.txt
new file mode 100644
index 0000000000..ef14ea5352
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/GetModuleFileNameA/CMakeLists.txt
@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/GetModuleFileNameA/test1/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/GetModuleFileNameA/test1/CMakeLists.txt
new file mode 100644
index 0000000000..a1128c62b8
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/GetModuleFileNameA/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ GetModuleFileNameA.c
+)
+
+add_executable(paltest_getmodulefilenamea_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getmodulefilenamea_test1 coreclrpal)
+
+target_link_libraries(paltest_getmodulefilenamea_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/GetModuleFileNameA/test1/GetModuleFileNameA.c b/src/pal/tests/palsuite/filemapping_memmgt/GetModuleFileNameA/test1/GetModuleFileNameA.c
new file mode 100644
index 0000000000..d05f0ac6a9
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/GetModuleFileNameA/test1/GetModuleFileNameA.c
@@ -0,0 +1,92 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: getmodulefilenamea.c
+**
+** Purpose: Positive test the GetModuleFileName API.
+** Call GetModuleFileName to retrieve the specified
+** module full path and file name
+**
+**
+**============================================================*/
+
+#include <palsuite.h>
+
+#define MODULENAMEBUFFERSIZE 1024
+
+/* SHLEXT is defined only for Unix variants */
+
+#if defined(SHLEXT)
+#define ModuleName "librotor_pal"SHLEXT
+#define Delimiter "/"
+#else
+#define ModuleName "rotor_pal.dll"
+#define Delimiter "\\"
+#endif
+
+int __cdecl main(int argc, char *argv[])
+{
+ HMODULE ModuleHandle;
+ int err;
+ DWORD ModuleNameLength;
+ char ModuleFileNameBuf[MODULENAMEBUFFERSIZE]="";
+ char* TempBuf = NULL;
+ char* LastBuf = NULL;
+
+ //Initialize the PAL environment
+ err = PAL_Initialize(argc, argv);
+ if(0 != err)
+ {
+ ExitProcess(FAIL);
+ }
+
+
+ //load a module
+ ModuleHandle = LoadLibrary(ModuleName);
+ if(!ModuleHandle)
+ {
+ Fail("Failed to call LoadLibrary API!\n");
+ }
+
+
+ //retrieve the specified module full path and file name
+ ModuleNameLength = GetModuleFileName(
+ ModuleHandle,//specified module handle
+ ModuleFileNameBuf,//buffer for module file name
+ MODULENAMEBUFFERSIZE);
+
+ //strip out all full path
+ TempBuf = strtok(ModuleFileNameBuf,Delimiter);
+ LastBuf = TempBuf;
+ while(NULL != TempBuf)
+ {
+ LastBuf = TempBuf;
+ TempBuf = strtok(NULL,Delimiter);
+ }
+
+
+ if(0 == ModuleNameLength || strcmp(ModuleName,LastBuf))
+ {
+ Trace("\nFailed to all GetModuleFileName API!\n");
+ err = FreeLibrary(ModuleHandle);
+ if(0 == err)
+ {
+ Fail("\nFailed to all FreeLibrary API!\n");
+ }
+ Fail("");
+ }
+
+ //decrement the reference count of the loaded dll
+ err = FreeLibrary(ModuleHandle);
+ if(0 == err)
+ {
+ Fail("\nFailed to all FreeLibrary API!\n");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/GetModuleFileNameA/test1/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/GetModuleFileNameA/test1/testinfo.dat
new file mode 100644
index 0000000000..8075e840ce
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/GetModuleFileNameA/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = GetModuleFileNameA
+Name = Positive test for GetModuleFileNameA API
+TYPE = DEFAULT
+EXE1 = getmodulefilenamea
+Description
+=Test the GetModuleFileNameA to retrieve the specified module
+=full path and file name
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/GetModuleFileNameA/test2/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/GetModuleFileNameA/test2/CMakeLists.txt
new file mode 100644
index 0000000000..c35e9acc5e
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/GetModuleFileNameA/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ GetModuleFileNameA.c
+)
+
+add_executable(paltest_getmodulefilenamea_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getmodulefilenamea_test2 coreclrpal)
+
+target_link_libraries(paltest_getmodulefilenamea_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/GetModuleFileNameA/test2/GetModuleFileNameA.c b/src/pal/tests/palsuite/filemapping_memmgt/GetModuleFileNameA/test2/GetModuleFileNameA.c
new file mode 100644
index 0000000000..e8aed6d30e
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/GetModuleFileNameA/test2/GetModuleFileNameA.c
@@ -0,0 +1,49 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: getmodulefilenamea.c
+**
+** Purpose: Positive test the GetModuleFileNameA API.
+** Call GetModuleFileName to retrieve current process
+** full path and file name by passing a NULL module handle
+**
+**
+**============================================================*/
+#include <palsuite.h>
+
+
+#define MODULENAMEBUFFERSIZE 1024
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ DWORD ModuleNameLength;
+ char ModuleFileNameBuf[MODULENAMEBUFFERSIZE]="";
+ int err;
+
+ //Initialize the PAL environment
+ err = PAL_Initialize(argc, argv);
+ if(0 != err)
+ {
+ ExitProcess(FAIL);
+ }
+
+
+ //retrieve the current process full path and file name
+ //by passing a NULL module handle
+ ModuleNameLength = GetModuleFileName(
+ NULL, //a NULL handle
+ ModuleFileNameBuf,//buffer for module file name
+ MODULENAMEBUFFERSIZE);
+
+ if(0 == ModuleNameLength)
+ {
+ Fail("\nFailed to all GetModuleFileName API!\n");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/GetModuleFileNameA/test2/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/GetModuleFileNameA/test2/testinfo.dat
new file mode 100644
index 0000000000..45fdca6ae7
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/GetModuleFileNameA/test2/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = GetModuleFileNameA
+Name = Positive test for GetModuleFileNameA API
+TYPE = DEFAULT
+EXE1 = getmodulefilenamea
+Description
+=Test the GetModuleFileNameA to retrieve current process full
+=full path and file name by passing a NULL module handle
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/GetModuleFileNameW/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/GetModuleFileNameW/CMakeLists.txt
new file mode 100644
index 0000000000..ef14ea5352
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/GetModuleFileNameW/CMakeLists.txt
@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/GetModuleFileNameW/test1/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/GetModuleFileNameW/test1/CMakeLists.txt
new file mode 100644
index 0000000000..c702d07908
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/GetModuleFileNameW/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ GetModuleFileNameW.c
+)
+
+add_executable(paltest_getmodulefilenamew_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getmodulefilenamew_test1 coreclrpal)
+
+target_link_libraries(paltest_getmodulefilenamew_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/GetModuleFileNameW/test1/GetModuleFileNameW.c b/src/pal/tests/palsuite/filemapping_memmgt/GetModuleFileNameW/test1/GetModuleFileNameW.c
new file mode 100644
index 0000000000..4c1c3b00ab
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/GetModuleFileNameW/test1/GetModuleFileNameW.c
@@ -0,0 +1,112 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: getmodulefilenamew.c
+**
+** Purpose: Test the GetModuleFileNameW to retrieve the specified module
+** full path and file name in UNICODE.
+**
+**
+**============================================================*/
+#define UNICODE
+#include <palsuite.h>
+
+#define MODULENAMEBUFFERSIZE 1024
+
+/* SHLEXT is defined only for Unix variants */
+
+#if defined(SHLEXT)
+#define ModuleName "librotor_pal"SHLEXT
+#define Delimiter "/"
+#else
+#define ModuleName "rotor_pal.dll"
+#define Delimiter "\\"
+#endif
+
+int __cdecl main(int argc, char *argv[])
+{
+ HMODULE ModuleHandle;
+ int err;
+ WCHAR *lpModuleName;
+ DWORD ModuleNameLength;
+ WCHAR *ModuleFileNameBuf;
+ char* TempBuf = NULL;
+ char* LastBuf = NULL;
+ char NewModuleFileNameBuf[MODULENAMEBUFFERSIZE+200] = "";
+
+
+ //Initialize the PAL environment
+ err = PAL_Initialize(argc, argv);
+ if(0 != err)
+ {
+ ExitProcess(FAIL);
+ }
+
+ ModuleFileNameBuf = malloc(MODULENAMEBUFFERSIZE*sizeof(WCHAR));
+
+ //convert a normal string to a wide one
+ lpModuleName = convert(ModuleName);
+
+ //load a module
+ ModuleHandle = LoadLibrary(lpModuleName);
+
+ //free the memory
+ free(lpModuleName);
+
+ if(!ModuleHandle)
+ {
+ Fail("Failed to call LoadLibrary API!\n");
+ }
+
+
+ //retrieve the specified module full path and file name
+ ModuleNameLength = GetModuleFileName(
+ ModuleHandle,//specified module handle
+ ModuleFileNameBuf,//buffer for module file name
+ MODULENAMEBUFFERSIZE);
+
+
+
+ //convert a wide full path name to a normal one
+ strcpy(NewModuleFileNameBuf,convertC(ModuleFileNameBuf));
+
+ //strip out all full path
+ TempBuf = strtok(NewModuleFileNameBuf,Delimiter);
+ LastBuf = TempBuf;
+ while(NULL != TempBuf)
+ {
+ LastBuf = TempBuf;
+ TempBuf = strtok(NULL,Delimiter);
+ }
+
+
+ //free the memory
+ free(ModuleFileNameBuf);
+
+ if(0 == ModuleNameLength || strcmp(ModuleName,LastBuf))
+ {
+ Trace("\nFailed to all GetModuleFileName API!\n");
+ err = FreeLibrary(ModuleHandle);
+ if(0 == err)
+ {
+ Fail("\nFailed to all FreeLibrary API!\n");
+ }
+ Fail("");
+ }
+
+
+
+ //decrement the reference count of the loaded dll
+ err = FreeLibrary(ModuleHandle);
+ if(0 == err)
+ {
+ Fail("\nFailed to all FreeLibrary API!\n");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/GetModuleFileNameW/test1/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/GetModuleFileNameW/test1/testinfo.dat
new file mode 100644
index 0000000000..c8d94b73b4
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/GetModuleFileNameW/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = GetModuleFileNameW
+Name = Positive test for GetModuleFileNameW API
+TYPE = DEFAULT
+EXE1 = getmodulefilenamew
+Description
+=Test the GetModuleFileNameW to retrieve the specified module
+=full path and file name in UNICODE
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/GetModuleFileNameW/test2/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/GetModuleFileNameW/test2/CMakeLists.txt
new file mode 100644
index 0000000000..857feb330d
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/GetModuleFileNameW/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ GetModuleFileNameW.c
+)
+
+add_executable(paltest_getmodulefilenamew_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getmodulefilenamew_test2 coreclrpal)
+
+target_link_libraries(paltest_getmodulefilenamew_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/GetModuleFileNameW/test2/GetModuleFileNameW.c b/src/pal/tests/palsuite/filemapping_memmgt/GetModuleFileNameW/test2/GetModuleFileNameW.c
new file mode 100644
index 0000000000..6009a9d298
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/GetModuleFileNameW/test2/GetModuleFileNameW.c
@@ -0,0 +1,57 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: getmodulefilenamew.c
+**
+** Purpose: Positive test the GetModuleFileName API.
+** Call GetModuleFileName to retrieve current process
+** full path and file name by passing a NULL module handle
+** in UNICODE
+**
+**
+**============================================================*/
+#define UNICODE
+#include <palsuite.h>
+
+#define MODULENAMEBUFFERSIZE 1024
+
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ DWORD ModuleNameLength;
+ WCHAR *ModuleFileNameBuf;
+ int err;
+
+
+ //Initialize the PAL environment
+ err = PAL_Initialize(argc, argv);
+ if(0 != err)
+ {
+ ExitProcess(FAIL);
+ }
+
+ ModuleFileNameBuf = malloc(MODULENAMEBUFFERSIZE*sizeof(WCHAR));
+
+ //retrieve the current process full path and file name
+ //by passing a NULL module handle
+ ModuleNameLength = GetModuleFileName(
+ NULL, //a NULL handle
+ ModuleFileNameBuf,//buffer for module file name
+ MODULENAMEBUFFERSIZE);
+
+ //free the memory
+ free(ModuleFileNameBuf);
+
+ if(0 == ModuleNameLength)
+ {
+ Fail("\nFailed to all GetModuleFileName API!\n");
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/GetModuleFileNameW/test2/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/GetModuleFileNameW/test2/testinfo.dat
new file mode 100644
index 0000000000..8b8740149c
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/GetModuleFileNameW/test2/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = GetModuleFileNameW
+Name = Positive test for GetModuleFileNameW API
+TYPE = DEFAULT
+EXE1 = getmodulefilenamew
+Description
+=Test the GetModuleFileNameW to retrieve current process full
+=full path and file name by passing a NULL module handle in UNICODE
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/GetProcAddress/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/GetProcAddress/CMakeLists.txt
new file mode 100644
index 0000000000..ef14ea5352
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/GetProcAddress/CMakeLists.txt
@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/GetProcAddress/test1/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/GetProcAddress/test1/CMakeLists.txt
new file mode 100644
index 0000000000..541ef8b98e
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/GetProcAddress/test1/CMakeLists.txt
@@ -0,0 +1,20 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+ testlib.c
+)
+
+add_executable(paltest_getprocaddress_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getprocaddress_test1 coreclrpal)
+
+target_link_libraries(paltest_getprocaddress_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/GetProcAddress/test1/test1.c b/src/pal/tests/palsuite/filemapping_memmgt/GetProcAddress/test1/test1.c
new file mode 100644
index 0000000000..f0b76c615f
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/GetProcAddress/test1/test1.c
@@ -0,0 +1,111 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================================
+**
+** Source: test1.c (filemapping_memmgt\getprocaddress\test1)
+**
+** Purpose: Positive test the GetProcAddress API.
+** The first test calls GetProcAddress to retrieve the
+** address of SimpleFunction inside testlib by its name,
+** then calls the function and checks that it worked.
+**
+**
+**===========================================================================*/
+#include <palsuite.h>
+
+typedef int (__stdcall *SIMPLEFUNCTION)(int);
+
+/* SHLEXT is defined only for Unix variants */
+#if defined(SHLEXT)
+#define lpModuleName "testlib"SHLEXT
+#else
+#define lpModuleName "testlib.dll"
+#endif
+
+int __cdecl main(int argc, char *argv[])
+{
+ int err;
+ HMODULE hModule;
+ SIMPLEFUNCTION procAddressByName;
+
+#if WIN32
+ const char *FunctionName = "_SimpleFunction@4";
+#else
+ const char *FunctionName = "SimpleFunction";
+#endif
+
+ /* Initialize the PAL environment. */
+ if(0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ /* load a module */
+ hModule = LoadLibrary(lpModuleName);
+ if(!hModule)
+ {
+ Fail("Unexpected error: "
+ "LoadLibrary(%s) failed.\n",
+ lpModuleName);
+ }
+
+ /*
+ * Test 1
+ *
+ * Get the address of a function
+ */
+ procAddressByName = (SIMPLEFUNCTION) GetProcAddress(hModule,FunctionName);
+ if(!procAddressByName)
+ {
+ Trace("ERROR: Unable to get address of SimpleFunction by its name. "
+ "GetProcAddress returned NULL with error %d\n",
+ GetLastError());
+
+ /* Cleanup */
+ err = FreeLibrary(hModule);
+ if(0 == err)
+ {
+ Fail("Unexpected error: Failed to FreeLibrary %s\n",
+ lpModuleName);
+ }
+ Fail("");
+ }
+
+ /* Call the function to see that it really worked */
+ /* Simple function adds 1 to the argument passed */
+ if( 2 != ((procAddressByName)(1)))
+ {
+ Trace("ERROR: Problem calling the function by its address.\n");
+
+ /* Cleanup */
+ err = FreeLibrary(hModule);
+ if(0 == err)
+ {
+ Fail("Unexpected error: Failed to FreeLibrary %s\n",
+ lpModuleName);
+ }
+ Fail("");
+ }
+
+ /* Cleanup */
+ err = FreeLibrary(hModule);
+ if(0 == err)
+ {
+ Fail("Unexpected error: Failed to FreeLibrary %s\n",
+ lpModuleName);
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
+
+
+
+
+
+
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/GetProcAddress/test1/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/GetProcAddress/test1/testinfo.dat
new file mode 100644
index 0000000000..31b262e31e
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/GetProcAddress/test1/testinfo.dat
@@ -0,0 +1,19 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = filemapping_memmgt
+Function = getprocaddress
+Name = Positive test for GetProcAddress API
+TYPE = DEFAULT
+EXE1 = test1
+LIB1 = testlib
+Description
+=Positive test the GetProcAddress API.
+=The first test calls GetProcAddress to retrieve the
+=address of strcpy by its name, then calls the function and
+=checks that it worked. The second part of the test
+=calls GetProcAddress to retrieve the address of
+=strcpy by its ordinal, then calls the function and
+=checks that it worked.
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/GetProcAddress/test1/testlib.c b/src/pal/tests/palsuite/filemapping_memmgt/GetProcAddress/test1/testlib.c
new file mode 100644
index 0000000000..e8fe48e05d
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/GetProcAddress/test1/testlib.c
@@ -0,0 +1,33 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================================
+**
+** Source: testlib.c (filemapping_memmgt\getprocaddress\test1)
+**
+** Purpose: Create a simple library containing one function
+** to test GetProcAddress
+**
+**
+**===========================================================================*/
+#include "pal.h"
+
+#if WIN32
+__declspec(dllexport)
+#endif
+
+/**
+ * Simple function that returns i+1
+ */
+int __stdcall SimpleFunction(int i)
+{
+ return i+1;
+}
+
+#if WIN32
+int __stdcall _DllMainCRTStartup(void *hinstDLL, int reason, void *lpvReserved)
+{
+ return 1;
+}
+#endif
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/GetProcAddress/test2/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/GetProcAddress/test2/CMakeLists.txt
new file mode 100644
index 0000000000..60a5ba1a6e
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/GetProcAddress/test2/CMakeLists.txt
@@ -0,0 +1,20 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test2.c
+ testlib.c
+)
+
+add_executable(paltest_getprocaddress_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getprocaddress_test2 coreclrpal)
+
+target_link_libraries(paltest_getprocaddress_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/GetProcAddress/test2/test2.c b/src/pal/tests/palsuite/filemapping_memmgt/GetProcAddress/test2/test2.c
new file mode 100644
index 0000000000..9107728423
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/GetProcAddress/test2/test2.c
@@ -0,0 +1,152 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================================
+**
+** Source: test2.c (filemapping_memmgt\getprocaddress\test2)
+**
+** Purpose: This test tries to call GetProcAddress with
+** a NULL handle, with a NULL function name, with an empty
+** function name, with an invalid name and with an
+** invalid ordinal value.
+**
+**
+**===========================================================================*/
+#include <palsuite.h>
+
+
+/* SHLEXT is defined only for Unix variants */
+#if defined(SHLEXT)
+#define lpModuleName "testlib"SHLEXT
+#else
+#define lpModuleName "testlib.dll"
+#endif
+
+
+/**
+ * main
+ */
+int __cdecl main(int argc, char *argv[])
+{
+ int err;
+ HMODULE hModule;
+ FARPROC procAddress;
+
+ /* Initialize the PAL environment. */
+ if(0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ /* load a module */
+ hModule = LoadLibrary(lpModuleName);
+ if(!hModule)
+ {
+ Fail("Unexpected error: "
+ "LoadLibrary(%s) failed.\n",
+ lpModuleName);
+ }
+
+ /*
+ * Test 1
+ *
+ * Call GetProcAddress with a NULL handle
+ */
+ procAddress = GetProcAddress(NULL,"SimpleFunction");
+ if(procAddress != NULL)
+ {
+ Trace("ERROR: GetProcAddress with a NULL handle "
+ "returned a non-NULL value when it should have "
+ "returned a NULL value with an error\n");
+
+ /* Cleanup */
+ err = FreeLibrary(hModule);
+ if(0 == err)
+ {
+ Fail("Unexpected error: Failed to FreeLibrary %s\n",
+ lpModuleName);
+ }
+ Fail("");
+ }
+
+ /**
+ * Test 2
+ *
+ * Call GetProcAddress with a NULL function name
+ */
+
+ procAddress = GetProcAddress(hModule,NULL);
+ if(procAddress != NULL)
+ {
+ Trace("ERROR: GetProcAddress with a NULL function name "
+ "returned a non-NULL value when it should have "
+ "returned a NULL value with an error\n");
+
+ /* Cleanup */
+ err = FreeLibrary(hModule);
+ if(0 == err)
+ {
+ Fail("Unexpected error: Failed to FreeLibrary %s\n",
+ lpModuleName);
+ }
+ Fail("");
+ }
+
+ /**
+ * Test 3
+ *
+ * Call GetProcAddress with an empty function name string
+ */
+
+ procAddress = GetProcAddress(hModule,"");
+ if(procAddress != NULL)
+ {
+ Trace("ERROR: GetProcAddress with an empty function name "
+ "returned a non-NULL value when it should have "
+ "returned a NULL value with an error\n");
+
+ /* Cleanup */
+ err = FreeLibrary(hModule);
+ if(0 == err)
+ {
+ Fail("Unexpected error: Failed to FreeLibrary %s\n",
+ lpModuleName);
+ }
+ Fail("");
+ }
+
+ /**
+ * Test 4
+ *
+ * Call GetProcAddress with an invalid name
+ */
+
+ procAddress = GetProcAddress(hModule,"Simple Function");
+ if(procAddress != NULL)
+ {
+ Trace("ERROR: GetProcAddress with an invalid function name "
+ "returned a non-NULL value when it should have "
+ "returned a NULL value with an error\n");
+
+ /* Cleanup */
+ err = FreeLibrary(hModule);
+ if(0 == err)
+ {
+ Fail("Unexpected error: Failed to FreeLibrary %s\n",
+ lpModuleName);
+ }
+ Fail("");
+ }
+
+ /* cleanup */
+ err = FreeLibrary(hModule);
+ if(0 == err)
+ {
+ Fail("Unexpected error: Failed to FreeLibrary %s\n",
+ lpModuleName);
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/GetProcAddress/test2/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/GetProcAddress/test2/testinfo.dat
new file mode 100644
index 0000000000..8bf50ad812
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/GetProcAddress/test2/testinfo.dat
@@ -0,0 +1,18 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = filemapping_memmgt
+Function = getprocaddress
+Name = Negative test for GetProcAddress API
+TYPE = DEFAULT
+EXE1 = test2
+LIB1 = testlib
+Description
+=This test tries to call GetProcAddress with
+=a NULL handle, with a NULL function name, with an empty
+=function name, with an invalid name and with an
+=nvalid ordinal value.
+
+
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/GetProcAddress/test2/testlib.c b/src/pal/tests/palsuite/filemapping_memmgt/GetProcAddress/test2/testlib.c
new file mode 100644
index 0000000000..23e58e871e
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/GetProcAddress/test2/testlib.c
@@ -0,0 +1,33 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================================
+**
+** Source: testlib.c (filemapping_memmgt\getprocaddress\test2)
+**
+** Purpose: Create a simple library containing one function
+** to test GetProcAddress
+**
+**
+**===========================================================================*/
+#include "pal.h"
+
+#if WIN32
+__declspec(dllexport)
+#endif
+
+/**
+ * Simple function that returns i+1
+ */
+int __stdcall SimpleFunction(int i)
+{
+ return i+1;
+}
+
+#if WIN32
+int __stdcall _DllMainCRTStartup(void *hinstDLL, int reason, void *lpvReserved)
+{
+ return 1;
+}
+#endif
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/GetProcessHeap/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/GetProcessHeap/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/GetProcessHeap/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/GetProcessHeap/test1/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/GetProcessHeap/test1/CMakeLists.txt
new file mode 100644
index 0000000000..18871abf00
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/GetProcessHeap/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ GetProcessHeap.c
+)
+
+add_executable(paltest_getprocessheap_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getprocessheap_test1 coreclrpal)
+
+target_link_libraries(paltest_getprocessheap_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/GetProcessHeap/test1/GetProcessHeap.c b/src/pal/tests/palsuite/filemapping_memmgt/GetProcessHeap/test1/GetProcessHeap.c
new file mode 100644
index 0000000000..bec6b5c616
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/GetProcessHeap/test1/GetProcessHeap.c
@@ -0,0 +1,39 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: getprocheap.c
+**
+** Purpose: Positive test the GetProcessHeap API.
+** Call GetProcessHeap to retrieve the handle of
+** calling process heap
+**
+**
+**============================================================*/
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ int err;
+ HANDLE ProcessHeapHandle;
+
+ //Initialize the PAL environment
+ err = PAL_Initialize(argc, argv);
+ if(0 != err)
+ {
+ ExitProcess(FAIL);
+ }
+
+ //Retrieve the calling process heap handle
+ ProcessHeapHandle = GetProcessHeap();
+
+ if(!ProcessHeapHandle)
+ {
+ Fail("\nFailed to call GetProcessHeap API!\n");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/GetProcessHeap/test1/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/GetProcessHeap/test1/testinfo.dat
new file mode 100644
index 0000000000..cec3dd12d7
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/GetProcessHeap/test1/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = GetProcessHeap
+Name = Positive test for GetProcessHeap API retrieve the handle of calling process heap
+TYPE = DEFAULT
+EXE1 = getprocessheap
+Description
+=Test the GetProcessHeap to retrieve the handle of the calling process heap
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/HeapAlloc/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/HeapAlloc/CMakeLists.txt
new file mode 100644
index 0000000000..1962ade358
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/HeapAlloc/CMakeLists.txt
@@ -0,0 +1,6 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+add_subdirectory(test3)
+
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/HeapAlloc/test1/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/HeapAlloc/test1/CMakeLists.txt
new file mode 100644
index 0000000000..3a64a0c58a
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/HeapAlloc/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ HeapAlloc.c
+)
+
+add_executable(paltest_heapalloc_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_heapalloc_test1 coreclrpal)
+
+target_link_libraries(paltest_heapalloc_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/HeapAlloc/test1/HeapAlloc.c b/src/pal/tests/palsuite/filemapping_memmgt/HeapAlloc/test1/HeapAlloc.c
new file mode 100644
index 0000000000..04de274e80
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/HeapAlloc/test1/HeapAlloc.c
@@ -0,0 +1,100 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: heapalloc.c
+**
+** Purpose: Positive test the HeapAlloc API.
+** Call HeapAlloc by pssing zero as control flag
+** Call HeapAlloc by passing HEAP_ZERO_MEMORY as control flag
+** Call HeapAlloc to allocate one byte heap memory
+** Call HeapAlloc to allocate maximum available heap memory
+**
+**
+**============================================================*/
+#include <palsuite.h>
+
+#define HEAPSIZE 64
+
+int __cdecl main(int argc, char *argv[])
+{
+ int err;
+ HANDLE ProcessHeapHandle;
+ LPVOID lpHeap;
+
+ /* Initialize the PAL environment */
+ err = PAL_Initialize(argc, argv);
+ if(0 != 0)
+ {
+ ExitProcess(FAIL);
+ }
+
+ /* Retrieve the calling process heap handle */
+ ProcessHeapHandle = GetProcessHeap();
+
+ if(!ProcessHeapHandle)
+ {
+ Fail("\nFailed to call GetProcessHeap API!\n");
+ }
+
+ /* allocate a heap memory in specified size */
+ lpHeap = HeapAlloc(ProcessHeapHandle, /* HeapHandle */
+ 0, /* control flag */
+ HEAPSIZE); /* /specify the heap size */
+ if(NULL == lpHeap)
+ {
+ Fail("Failed to call HeapAlloc API!\n");
+ }
+
+ /* free the heap memory */
+ err = HeapFree(ProcessHeapHandle,
+ 0,
+ lpHeap);
+ if(0 == err)
+ {
+ Fail("Failed to call HeapFree API!\n");
+ }
+
+
+ /* allocate a heap memory in 1 byte size */
+ lpHeap = HeapAlloc(ProcessHeapHandle, /* HeapHandle */
+ 0, /* control flag */
+ 1); /* specify the heap size*/
+ if(NULL == lpHeap)
+ {
+ Fail("Failed to call HeapAlloc API to allocate one byte heap memory!\n");
+ }
+
+ /* free the heap memory */
+ err = HeapFree(ProcessHeapHandle,
+ 0,
+ lpHeap);
+ if(0 == err)
+ {
+ Fail("Failed to call HeapFree API!\n");
+ }
+
+ /* allocate a heap memory and initialize it to zero */
+ lpHeap = HeapAlloc(ProcessHeapHandle,/* HeapHandle */
+ HEAP_ZERO_MEMORY,/* control flag */
+ HEAPSIZE); /* specify the heap size */
+ if(NULL == lpHeap)
+ {
+ Fail("Failed to call HeapAlloc API with HEAP_ZERO_MEMORY control flag!\n");
+ }
+
+ /* free the heap memory */
+ err = HeapFree(ProcessHeapHandle,
+ 0,
+ lpHeap);
+ if(0 == err)
+ {
+ Fail("Failed to call HeapFree API!\n");
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/HeapAlloc/test1/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/HeapAlloc/test1/testinfo.dat
new file mode 100644
index 0000000000..9b6064349d
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/HeapAlloc/test1/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = HeapAlloc
+Name = Positive test for HeapAlloc API
+TYPE = DEFAULT
+EXE1 = heapalloc
+Description
+=Test the HeapAlloc by passing zero as the control flag
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/HeapAlloc/test2/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/HeapAlloc/test2/CMakeLists.txt
new file mode 100644
index 0000000000..5253110d8d
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/HeapAlloc/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ HeapAlloc.c
+)
+
+add_executable(paltest_heapalloc_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_heapalloc_test2 coreclrpal)
+
+target_link_libraries(paltest_heapalloc_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/HeapAlloc/test2/HeapAlloc.c b/src/pal/tests/palsuite/filemapping_memmgt/HeapAlloc/test2/HeapAlloc.c
new file mode 100644
index 0000000000..5f4ff90498
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/HeapAlloc/test2/HeapAlloc.c
@@ -0,0 +1,59 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: heapalloc.c
+**
+** Purpose: Positive test the HeapAlloc API.
+** Call HeapAlloc with HEAP_ZERO_MEMORY control flag
+**
+**
+**============================================================*/
+#include <palsuite.h>
+
+#define HEAPSIZE 64
+
+int __cdecl main(int argc, char *argv[])
+{
+ int err;
+ HANDLE ProcessHeapHandle;
+ LPVOID lpHeap;
+
+
+ //Initialize the PAL environment
+ err = PAL_Initialize(argc, argv);
+ if(0 != err)
+ {
+ ExitProcess(FAIL);
+ }
+
+ //Retrieve the calling process heap handle
+ ProcessHeapHandle = GetProcessHeap();
+
+ if(!ProcessHeapHandle)
+ {
+ Fail("\nFailed to call GetProcessHeap API!\n");
+ }
+
+ lpHeap = HeapAlloc(ProcessHeapHandle,//HeapHandle
+ HEAP_ZERO_MEMORY,//control flag
+ HEAPSIZE); //specify the heap size
+ if(NULL == lpHeap)
+ {
+ Fail("Failed to call HeapAlloc API!\n");
+ }
+
+ //free the heap memory
+ err = HeapFree(ProcessHeapHandle,
+ 0,
+ lpHeap);
+ if(0 == err)
+ {
+ Fail("Failed to call HeapFree API!\n");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/HeapAlloc/test2/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/HeapAlloc/test2/testinfo.dat
new file mode 100644
index 0000000000..5c6e77d2cc
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/HeapAlloc/test2/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = HeapAlloc
+Name = Positive test for HeapAlloc API
+TYPE = DEFAULT
+EXE1 = heapalloc
+Description
+=Test the HeapAlloc with HEAP_ZERO_MEMORY control flag
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/HeapAlloc/test3/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/HeapAlloc/test3/CMakeLists.txt
new file mode 100644
index 0000000000..f0b89461d2
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/HeapAlloc/test3/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ HeapAlloc.c
+)
+
+add_executable(paltest_heapalloc_test3
+ ${SOURCES}
+)
+
+add_dependencies(paltest_heapalloc_test3 coreclrpal)
+
+target_link_libraries(paltest_heapalloc_test3
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/HeapAlloc/test3/HeapAlloc.c b/src/pal/tests/palsuite/filemapping_memmgt/HeapAlloc/test3/HeapAlloc.c
new file mode 100644
index 0000000000..4a74fe8194
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/HeapAlloc/test3/HeapAlloc.c
@@ -0,0 +1,62 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: heapalloc.c
+**
+** Purpose: Positive test the HeapAlloc API.
+** Call HeapAlloc asking for zero bytes
+** with HEAP_ZERO_MEMORY control flag
+**
+**
+**============================================================*/
+#include <palsuite.h>
+
+#define HEAPSIZE 0
+
+int __cdecl main(int argc, char *argv[])
+{
+ int err;
+ HANDLE ProcessHeapHandle;
+ LPVOID lpHeap;
+
+
+ //Initialize the PAL environment
+ err = PAL_Initialize(argc, argv);
+ if(0 != err)
+ {
+ ExitProcess(FAIL);
+ }
+
+ //Retrieve the calling process heap handle
+ ProcessHeapHandle = GetProcessHeap();
+
+ if(!ProcessHeapHandle)
+ {
+ Fail("\nFailed to call GetProcessHeap API!\n");
+ }
+
+ lpHeap = HeapAlloc(ProcessHeapHandle,//HeapHandle
+ HEAP_ZERO_MEMORY,//control flag
+ HEAPSIZE); //specify the heap size
+
+ //lpHeap should be non-NULL pointer
+ if(NULL == lpHeap)
+ {
+ Fail("Failed to call HeapAlloc API, when number of bytes to be allocated is zero!\n");
+ }
+
+ //free the heap memory
+ err = HeapFree(ProcessHeapHandle,
+ 0,
+ lpHeap);
+ if(0 == err)
+ {
+ Fail("Failed to call HeapFree API!\n");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/HeapAlloc/test3/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/HeapAlloc/test3/testinfo.dat
new file mode 100644
index 0000000000..c7d67d3b4f
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/HeapAlloc/test3/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = HeapAlloc
+Name = Positive test for HeapAlloc API
+TYPE = DEFAULT
+EXE1 = heapalloc
+Description
+=Test the HeapAlloc asking for zero bytes with HEAP_ZERO_MEMORY control flag
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/HeapFree/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/HeapFree/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/HeapFree/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/HeapFree/test1/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/HeapFree/test1/CMakeLists.txt
new file mode 100644
index 0000000000..898047a9ad
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/HeapFree/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ HeapFree.c
+)
+
+add_executable(paltest_heapfree_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_heapfree_test1 coreclrpal)
+
+target_link_libraries(paltest_heapfree_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/HeapFree/test1/HeapFree.c b/src/pal/tests/palsuite/filemapping_memmgt/HeapFree/test1/HeapFree.c
new file mode 100644
index 0000000000..37b6b3bf60
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/HeapFree/test1/HeapFree.c
@@ -0,0 +1,62 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: heapfree.c
+**
+** Purpose: Positive test the HeapFree API.
+** Call HeapFree to free a memory block
+** and try to free an invalid memory block
+**
+**
+**============================================================*/
+#include <palsuite.h>
+
+#define HEAPSIZE 64
+
+int __cdecl main(int argc, char *argv[])
+{
+ int err;
+ HANDLE ProcessHeapHandle;
+ LPVOID lpHeap;
+
+
+ /* Initialize the PAL environment */
+ if(0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ /* Retrieve the calling process heap handle */
+ ProcessHeapHandle = GetProcessHeap();
+
+ if(!ProcessHeapHandle)
+ {
+ Fail("\nFailed to call GetProcessHeap API!\n");
+ }
+
+
+ lpHeap = HeapAlloc(ProcessHeapHandle,/* HeapHandle */
+ HEAP_ZERO_MEMORY,/* control flag */
+ HEAPSIZE); /* specify the heap size */
+ if(NULL == lpHeap)
+ {
+ Fail("Failed to call HeapAlloc API!\n");
+ }
+
+
+ /* free a allocate heap memory */
+ err = HeapFree(ProcessHeapHandle,
+ 0,
+ lpHeap);
+
+ if(0 == err)
+ {
+ Fail("Failed to call HeapFree API!\n");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/HeapFree/test1/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/HeapFree/test1/testinfo.dat
new file mode 100644
index 0000000000..c6f18167e3
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/HeapFree/test1/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = HeapFree
+Name = Positive test for HeapFree API to free an allocated heap block
+TYPE = DEFAULT
+EXE1 = heapfree
+Description
+=Test the HeapFree to free a memory block
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/HeapReAlloc/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/HeapReAlloc/CMakeLists.txt
new file mode 100644
index 0000000000..8083faf655
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/HeapReAlloc/CMakeLists.txt
@@ -0,0 +1,8 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+add_subdirectory(test3)
+add_subdirectory(test4)
+add_subdirectory(test5)
+
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/HeapReAlloc/test1/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/HeapReAlloc/test1/CMakeLists.txt
new file mode 100644
index 0000000000..1decb02c73
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/HeapReAlloc/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_heaprealloc_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_heaprealloc_test1 coreclrpal)
+
+target_link_libraries(paltest_heaprealloc_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/HeapReAlloc/test1/test1.c b/src/pal/tests/palsuite/filemapping_memmgt/HeapReAlloc/test1/test1.c
new file mode 100644
index 0000000000..497d208eca
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/HeapReAlloc/test1/test1.c
@@ -0,0 +1,72 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: test1.c
+**
+** Purpose: Allocate some memory. Then reallocate that memory. Ensure the
+** return values are correct, and also that data placed in the allocated
+** memory carries over to the reallocated block.
+**
+**
+**============================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ HANDLE TheHeap;
+ char* TheMemory;
+ char* ReAllocMemory;
+ int i;
+
+ if(PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+ TheHeap = GetProcessHeap();
+
+ if(TheHeap == NULL)
+ {
+ Fail("ERROR: GetProcessHeap() returned NULL when it was called. "
+ "GetLastError() returned %d.",GetLastError());
+ }
+
+ /* Allocate 100 bytes on the heap */
+ if((TheMemory = HeapAlloc(TheHeap, 0, 100)) == NULL)
+ {
+ Fail("ERROR: HeapAlloc returned NULL when it was called. "
+ "GetLastError() returned %d.",GetLastError());
+ }
+
+ /* Set each byte of that memory block to 'x' */
+ memset(TheMemory, 'X', 100);
+
+ /* Reallocate the memory */
+ ReAllocMemory = HeapReAlloc(TheHeap, 0, TheMemory, 100);
+
+ if(ReAllocMemory == NULL)
+ {
+ Fail("ERROR: HeapReAlloc failed to reallocate the 100 bytes of "
+ "heap memory. GetLastError returns %d.",GetLastError());
+ }
+
+ /* Check that each byte of the memory Reallocated is 'x' */
+
+ for(i=0; i<100; ++i)
+ {
+ if(ReAllocMemory[i] != 'X')
+ {
+ Fail("ERROR: Byte number %d of the reallocated memory block "
+ "is not set to 'X' as it should be.",i);
+ }
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/HeapReAlloc/test1/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/HeapReAlloc/test1/testinfo.dat
new file mode 100644
index 0000000000..ad3a3ffc73
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/HeapReAlloc/test1/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = HeapReAlloc
+Name = Positive test for HeapReAlloc to check normal behaviour
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Allocate some memory. Then reallocate that memory. Ensure the
+= return values are correct, and also that data placed in the allocated
+= memory carries over to the reallocated block.
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/HeapReAlloc/test2/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/HeapReAlloc/test2/CMakeLists.txt
new file mode 100644
index 0000000000..6f5510387a
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/HeapReAlloc/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test2.c
+)
+
+add_executable(paltest_heaprealloc_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_heaprealloc_test2 coreclrpal)
+
+target_link_libraries(paltest_heaprealloc_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/HeapReAlloc/test2/test2.c b/src/pal/tests/palsuite/filemapping_memmgt/HeapReAlloc/test2/test2.c
new file mode 100644
index 0000000000..13e789f901
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/HeapReAlloc/test2/test2.c
@@ -0,0 +1,79 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: test2.c
+**
+** Purpose: Allocate some memory. Then reallocate that memory into less
+** space than the original amount. Ensure the
+** return values are correct, and also that data placed in the allocated
+** memory carries over to the reallocated block.
+**
+**
+**============================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ HANDLE TheHeap;
+ char* TheMemory;
+ char* ReAllocMemory;
+ int i;
+
+ if(PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+ TheHeap = GetProcessHeap();
+
+ if(TheHeap == NULL)
+ {
+ Fail("ERROR: GetProcessHeap() returned NULL when it was called. "
+ "GetLastError() returned %d.",GetLastError());
+ }
+
+ /* Allocate 200 bytes on the heap */
+ if((TheMemory = HeapAlloc(TheHeap, 0, 200)) == NULL)
+ {
+ Fail("ERROR: HeapAlloc returned NULL when it was called. "
+ "GetLastError() returned %d.",GetLastError());
+ }
+
+ /* Set the first 100 bytes to 'X' */
+ memset(TheMemory, 'X', 100);
+
+ /* Set the second 100 bytes to 'Z' */
+ memset(TheMemory+100, 'Z', 100);
+
+ /* Reallocate the memory to 100 bytes */
+ ReAllocMemory = HeapReAlloc(TheHeap, 0, TheMemory, 100);
+
+ if(ReAllocMemory == NULL)
+ {
+ Fail("ERROR: HeapReAlloc failed to reallocate the 100 bytes of "
+ "heap memory. GetLastError returns %d.",GetLastError());
+ }
+
+ /* Check that each of the first 100 bytes hasn't lost any data.
+ Anything beyond the first 100 might still be valid, but we can't
+ gaurentee it.
+ */
+
+ for(i=0; i<100; ++i)
+ {
+ /* Note: Cast to char* so the function knows the size is 1 */
+ if(ReAllocMemory[i] != 'X')
+ {
+ Fail("ERROR: Byte number %d of the reallocated memory block "
+ "is not set to 'X' as it should be.",i);
+ }
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/HeapReAlloc/test2/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/HeapReAlloc/test2/testinfo.dat
new file mode 100644
index 0000000000..95a12aafd5
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/HeapReAlloc/test2/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = HeapReAlloc
+Name = Positive test for HeapReAlloc to reallocate into a smaller space
+TYPE = DEFAULT
+EXE1 = test2
+Description
+= Allocate some memory. Then reallocate that memory into less
+= space than the origional amount. Ensure the
+= return values are correct, and also that data placed in the allocated
+= memory carries over to the reallocated block.
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/HeapReAlloc/test3/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/HeapReAlloc/test3/CMakeLists.txt
new file mode 100644
index 0000000000..7ad836706a
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/HeapReAlloc/test3/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test3.c
+)
+
+add_executable(paltest_heaprealloc_test3
+ ${SOURCES}
+)
+
+add_dependencies(paltest_heaprealloc_test3 coreclrpal)
+
+target_link_libraries(paltest_heaprealloc_test3
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/HeapReAlloc/test3/test3.c b/src/pal/tests/palsuite/filemapping_memmgt/HeapReAlloc/test3/test3.c
new file mode 100644
index 0000000000..dea9de348d
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/HeapReAlloc/test3/test3.c
@@ -0,0 +1,78 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: test3.c
+**
+** Purpose: Allocate some memory. Then reallocate that memory into a
+** bigger space on the heap. Check that the first portion of the data is
+** unchanged. Then set the new portion to a value, to ensure that it is
+** properly writable memory.
+**
+**
+**============================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ HANDLE TheHeap;
+ char* TheMemory;
+ char* ReAllocMemory;
+ int i;
+
+ if(PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+ TheHeap = GetProcessHeap();
+
+ if(TheHeap == NULL)
+ {
+ Fail("ERROR: GetProcessHeap() returned NULL when it was called. "
+ "GetLastError() returned %d.",GetLastError());
+ }
+
+ /* Allocate 100 bytes on the heap */
+ if((TheMemory = HeapAlloc(TheHeap, 0, 100)) == NULL)
+ {
+ Fail("ERROR: HeapAlloc returned NULL when it was called. "
+ "GetLastError() returned %d.",GetLastError());
+ }
+
+ /* Set the first 100 bytes to 'X' */
+ memset(TheMemory, 'X', 100);
+
+ /* Reallocate the memory to 200 bytes */
+ ReAllocMemory = HeapReAlloc(TheHeap, 0, TheMemory, 200);
+
+ if(ReAllocMemory == NULL)
+ {
+ Fail("ERROR: HeapReAlloc failed to reallocate the 100 bytes of "
+ "heap memory. GetLastError returns %d.",GetLastError());
+ }
+
+ /* Check that each of the first 100 bytes hasn't lost any data. */
+ for(i=0; i<100; ++i)
+ {
+
+ if(ReAllocMemory[i] != 'X')
+ {
+ Fail("ERROR: Byte number %d of the reallocated memory block "
+ "is not set to 'X' as it should be.",i);
+ }
+ }
+
+ /* Beyond the first 100 bytes is valid free memory. We'll set all this
+ memory to a value -- though, even if HeapReAlloc didn't work, it might
+ still be possible to memset this memory without raising an exception.
+ */
+ memset(ReAllocMemory+100, 'Z', 100);
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/HeapReAlloc/test3/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/HeapReAlloc/test3/testinfo.dat
new file mode 100644
index 0000000000..ed6da87c33
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/HeapReAlloc/test3/testinfo.dat
@@ -0,0 +1,16 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = HeapReAlloc
+Name = Positive test for HeapReAlloc to reallocate into a larger space
+TYPE = DEFAULT
+EXE1 = test3
+Description
+= Allocate some memory. Then reallocate that memory into a
+= bigger space on the heap. Check that the first portion of the data is
+= unchanged. Then set the new portion to a value, to ensure that it is
+= properly writable memory.
+
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/HeapReAlloc/test4/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/HeapReAlloc/test4/CMakeLists.txt
new file mode 100644
index 0000000000..024a4ef840
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/HeapReAlloc/test4/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test4.c
+)
+
+add_executable(paltest_heaprealloc_test4
+ ${SOURCES}
+)
+
+add_dependencies(paltest_heaprealloc_test4 coreclrpal)
+
+target_link_libraries(paltest_heaprealloc_test4
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/HeapReAlloc/test4/test4.c b/src/pal/tests/palsuite/filemapping_memmgt/HeapReAlloc/test4/test4.c
new file mode 100644
index 0000000000..cebf904501
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/HeapReAlloc/test4/test4.c
@@ -0,0 +1,80 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: test4.c
+**
+** Purpose: Call HeapReAlloc with a NULL pointer to memory. It should
+** return NULL.
+**
+**
+**============================================================*/
+
+/* Note: When attempted with a NULL Handle, this test crashes under win32.
+ As such, the behaviour isn't tested here.
+*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ HANDLE TheHeap;
+ LPVOID TheMemory = NULL;
+
+ if(PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+ TheHeap = GetProcessHeap();
+
+ if(TheHeap == NULL)
+ {
+ Fail("ERROR: GetProcessHeap() returned NULL when it was called. "
+ "GetLastError() returned %d.",GetLastError());
+ }
+
+ /* Allocate 100 bytes on the heap */
+ if(HeapAlloc(TheHeap, 0, 100) == NULL)
+ {
+ Fail("ERROR: HeapAlloc returned NULL when it was called. "
+ "GetLastError() returned %d.",GetLastError());
+ }
+
+ /* Call HeapReAlloc with a NULL memory pointer. It should fail */
+
+ if(HeapReAlloc(TheHeap, 0, TheMemory, 100) != NULL)
+ {
+ Fail("ERROR: HeapReAlloc was passed an invalid memory pointer. "
+ "It should have failed and returned NULL upon failure.");
+ }
+
+ if(GetLastError() != 0)
+ {
+ Fail("ERROR: GetLastError should be zero after passing a NULL "
+ "memory pointer to HeapReAlloc.\n");
+ }
+
+ /* Call HeapReAlloc with a size of 0 bytes on a NULL memory pointer.
+ It should still fail.
+ */
+
+ if(HeapReAlloc(TheHeap, 0, TheMemory, 0) != NULL)
+ {
+ Fail("ERROR: HeapReAlloc was passed an invalid memory pointer and "
+ "the amount of memory to reallocate was 0. "
+ "It should have failed and returned NULL upon failure.");
+ }
+
+ if(GetLastError() != 0)
+ {
+ Fail("ERROR: GetLastError should be zero after passing a NULL "
+ "memory pointer to HeapReAlloc.\n");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/HeapReAlloc/test4/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/HeapReAlloc/test4/testinfo.dat
new file mode 100644
index 0000000000..cfa5f5ceed
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/HeapReAlloc/test4/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = HeapReAlloc
+Name = Negative test for HeapReAlloc
+TYPE = DEFAULT
+EXE1 = test4
+Description
+= Call HeapReAlloc with a NULL pointer to memory. It should
+= return NULL.
+
+
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/HeapReAlloc/test5/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/HeapReAlloc/test5/CMakeLists.txt
new file mode 100644
index 0000000000..3ab3ec16e8
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/HeapReAlloc/test5/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test5.c
+)
+
+add_executable(paltest_heaprealloc_test5
+ ${SOURCES}
+)
+
+add_dependencies(paltest_heaprealloc_test5 coreclrpal)
+
+target_link_libraries(paltest_heaprealloc_test5
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/HeapReAlloc/test5/test5.c b/src/pal/tests/palsuite/filemapping_memmgt/HeapReAlloc/test5/test5.c
new file mode 100644
index 0000000000..230e65e492
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/HeapReAlloc/test5/test5.c
@@ -0,0 +1,69 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: test5.c
+**
+** Purpose: Allocate some memory. Then call HeapRealloc with 0 as the
+** amount of memory to reallocate. This should work, essentially freeing
+** the memory (though we can't verfiy this)
+**
+**
+**============================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ HANDLE TheHeap;
+ char* TheMemory;
+ char* ReAllocMemory;
+ char* ReAllocMemory2;
+
+ if(PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+ TheHeap = GetProcessHeap();
+
+ if(TheHeap == NULL)
+ {
+ Fail("ERROR: GetProcessHeap() returned NULL when it was called. "
+ "GetLastError() returned %d.",GetLastError());
+ }
+
+ /* Allocate 100 bytes on the heap */
+ if((TheMemory = HeapAlloc(TheHeap, 0, 100)) == NULL)
+ {
+ Fail("ERROR: HeapAlloc returned NULL when it was called. "
+ "GetLastError() returned %d.",GetLastError());
+ }
+
+ /* Set each byte of that memory block to 'x' */
+ memset(TheMemory, 'X', 100);
+
+ /* Reallocate the memory into 0 bytes */
+ ReAllocMemory = HeapReAlloc(TheHeap, 0, TheMemory, 0);
+
+ if(ReAllocMemory == NULL)
+ {
+ Fail("ERROR: HeapReAlloc failed to reallocate the 100 bytes of "
+ "heap memory. GetLastError returns %d.",GetLastError());
+ }
+
+ /* Reallocate the memory we just put into 0 bytes, into 100 bytes. */
+ ReAllocMemory2 = HeapReAlloc(TheHeap, 0, ReAllocMemory, 100);
+
+ if(ReAllocMemory2 == NULL)
+ {
+ Fail("ERROR: HeapReAlloc failed to reallocate the 0 bytes of "
+ "heap memory into 100. GetLastError returns %d.",GetLastError());
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/HeapReAlloc/test5/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/HeapReAlloc/test5/testinfo.dat
new file mode 100644
index 0000000000..e36b9035c5
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/HeapReAlloc/test5/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = HeapReAlloc
+Name = Positive test for HeapReAlloc to check behaviour with byte size 0
+TYPE = DEFAULT
+EXE1 = test5
+Description
+= Allocate some memory. Then call HeapRealloc with 0 as the
+= amount of memory to reallocate. This should work, essentially freeing
+= the memory (though we can't verfiy this)
+
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/LocalAlloc/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/LocalAlloc/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/LocalAlloc/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/LocalAlloc/test1/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/LocalAlloc/test1/CMakeLists.txt
new file mode 100644
index 0000000000..c96e00a170
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/LocalAlloc/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ LocalAlloc.c
+)
+
+add_executable(paltest_localalloc_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_localalloc_test1 coreclrpal)
+
+target_link_libraries(paltest_localalloc_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/LocalAlloc/test1/LocalAlloc.c b/src/pal/tests/palsuite/filemapping_memmgt/LocalAlloc/test1/LocalAlloc.c
new file mode 100644
index 0000000000..17afbc6020
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/LocalAlloc/test1/LocalAlloc.c
@@ -0,0 +1,49 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: LocalAlloc.c
+**
+** Purpose: Positive test the LocalAlloc API.
+** Call LocalAlloc with zero as the allocation attribute
+**
+**
+**============================================================*/
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ HLOCAL LocalHeap;
+ HLOCAL FreeHeap;
+ int err;
+ const SIZE_T heapSize = 64;
+
+ /*Initialize the PAL environment*/
+ err = PAL_Initialize(argc, argv);
+ if(0 != err)
+ {
+ return FAIL;
+ }
+
+ /*Allocate the specified number of bytes from the heap*/
+ /*with allocation attribute: zero which is required by PAL Doc*/
+ LocalHeap = LocalAlloc(0, heapSize);
+ if(!LocalHeap)
+ {
+ Fail("\nFailed to call LocalAlloc API, "
+ "error code=%u\n", GetLastError());
+ }
+
+ /*Free the allocated local heap memory*/
+ FreeHeap = LocalFree(LocalHeap);
+ if(FreeHeap)
+ {
+ Fail("Failed to call LocalFree API, "
+ "error code=%u\n", GetLastError());
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/LocalAlloc/test1/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/LocalAlloc/test1/testinfo.dat
new file mode 100644
index 0000000000..056d9ceb21
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/LocalAlloc/test1/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = LocalAlloc
+Name = Positive test LocalAlloc API to Allocate the specified number of bytes from the heap
+TYPE = DEFAULT
+EXE1 = localalloc
+Description
+=Test the LocalAlloc with zero ad allocation attribute
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/LocalFree/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/LocalFree/CMakeLists.txt
new file mode 100644
index 0000000000..ef14ea5352
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/LocalFree/CMakeLists.txt
@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/LocalFree/test1/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/LocalFree/test1/CMakeLists.txt
new file mode 100644
index 0000000000..47ad76ebe6
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/LocalFree/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ LocalFree.c
+)
+
+add_executable(paltest_localfree_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_localfree_test1 coreclrpal)
+
+target_link_libraries(paltest_localfree_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/LocalFree/test1/LocalFree.c b/src/pal/tests/palsuite/filemapping_memmgt/LocalFree/test1/LocalFree.c
new file mode 100644
index 0000000000..d9c062e761
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/LocalFree/test1/LocalFree.c
@@ -0,0 +1,49 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: LocalFree.c
+**
+** Purpose: Positive test the LocalFree API.
+** Call LocalFree to free a specified local memory object
+**
+**
+**============================================================*/
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ HLOCAL LocalHeap;
+ HLOCAL FreeHeap;
+ int err;
+ const SIZE_T heapSize = 64;
+
+ /*Initialize the PAL environment*/
+ err = PAL_Initialize(argc, argv);
+ if(0 != err)
+ {
+ return FAIL;
+ }
+
+ /*Allocate the specified number of bytes from the heap*/
+ /*with zero ad the allocation attribute*/
+ LocalHeap = LocalAlloc(0, heapSize);
+ if(!LocalHeap)
+ {
+ Fail("\nFailed to call LocalAlloc API, "
+ "error code=%u\n", GetLastError());
+ }
+
+ /*Free the allocated local heap memory*/
+ FreeHeap = LocalFree(LocalHeap);
+ if(FreeHeap)
+ {
+ Fail("Failed to call LocalFree API, "
+ "error code=%u\n", GetLastError());
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/LocalFree/test1/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/LocalFree/test1/testinfo.dat
new file mode 100644
index 0000000000..2c0611bdec
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/LocalFree/test1/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = LocalFree
+Name = Positive test LocalFree API to free a specified local memory object
+TYPE = DEFAULT
+EXE1 = localfree
+Description
+=Test the LocalFree to free a specified local memory object
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/LocalFree/test2/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/LocalFree/test2/CMakeLists.txt
new file mode 100644
index 0000000000..ac7a11a05f
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/LocalFree/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ LocalFree.c
+)
+
+add_executable(paltest_localfree_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_localfree_test2 coreclrpal)
+
+target_link_libraries(paltest_localfree_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/LocalFree/test2/LocalFree.c b/src/pal/tests/palsuite/filemapping_memmgt/LocalFree/test2/LocalFree.c
new file mode 100644
index 0000000000..4d4567dc3f
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/LocalFree/test2/LocalFree.c
@@ -0,0 +1,39 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: LocalFree.c
+**
+** Purpose: Positive test the LocalFree API.
+** call LocalFree by passing NULL as local memory
+** object handle
+**
+**
+**============================================================*/
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ HLOCAL FreeHeap;
+ int err;
+
+ /*Initialize the PAL environment*/
+ err = PAL_Initialize(argc, argv);
+ if(0 != err)
+ {
+ return FAIL;
+ }
+
+ /*call LocalFree by passing NULL as local memory object handle*/
+ FreeHeap = LocalFree(NULL);
+ if(FreeHeap)
+ {
+ Fail("Failed to call LocalFree API, "
+ "error code=%u\n", GetLastError());
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/LocalFree/test2/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/LocalFree/test2/testinfo.dat
new file mode 100644
index 0000000000..1455fe93b7
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/LocalFree/test2/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = LocalFree
+Name = Positive test LocalFree API by passing NULL as local memory object handle
+TYPE = DEFAULT
+EXE1 = localfree
+Description
+=Test the LocalFree by passing NULL
+=as a local memory object handle
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/LockFile/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/LockFile/CMakeLists.txt
new file mode 100644
index 0000000000..19ee487a6a
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/LockFile/CMakeLists.txt
@@ -0,0 +1,10 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+add_subdirectory(test3)
+add_subdirectory(test4)
+add_subdirectory(test5)
+add_subdirectory(test6)
+add_subdirectory(test7)
+
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/LockFile/LockFile.h b/src/pal/tests/palsuite/filemapping_memmgt/LockFile/LockFile.h
new file mode 100644
index 0000000000..2862b6c524
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/LockFile/LockFile.h
@@ -0,0 +1,152 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: LockFile.h
+**
+** Purpose: This header file has a RunHelper method which will be used to
+** start a child proccess in many LockFile testcases. The CreateAndLockFile
+** method Creates a file and calls LockFile upon it. And the two Signal
+** methods are used for IPC.
+**
+**
+**============================================================*/
+
+#include <palsuite.h>
+
+int RunHelper(char* Helper)
+{
+ STARTUPINFO si;
+ PROCESS_INFORMATION pi;
+ DWORD RetCode;
+
+ ZeroMemory( &si, sizeof(si) );
+ si.cb = sizeof(si);
+ ZeroMemory( &pi, sizeof(pi) );
+
+ if(!CreateProcess( NULL,Helper,NULL,NULL,FALSE,0,NULL,NULL,&si,&pi))
+ {
+ Fail("ERROR: CreateProcess failed to load executable '%s'.",Helper);
+ }
+
+ if(WaitForSingleObject( pi.hProcess, INFINITE ) == WAIT_FAILED)
+ {
+ Fail("ERROR: WaitForSingleObject returned WAIT_FAILED when it was "
+ "called.");
+ }
+
+ /* Get the return value from the helper process */
+ if (GetExitCodeProcess(pi.hProcess, &RetCode) == 0)
+ {
+ Fail("ERROR: GetExitCodeProccess failed when attempting to retrieve "
+ "the exit code of the child process.");
+ }
+
+ if(CloseHandle( pi.hProcess ) == 0)
+ {
+ Fail("ERROR: CloseHandle failed to close the process.");
+ }
+
+ if(CloseHandle( pi.hThread ) == 0)
+ {
+ Fail("ERROR: CloseHandle failed to close the thread.");
+ }
+
+ return RetCode;
+}
+
+HANDLE CreateAndLockFile(HANDLE TheFile, char* FileName, char* WriteBuffer,
+ DWORD LockStart, DWORD LockLength)
+{
+ DWORD BytesWritten;
+
+ TheFile = CreateFile(FileName,
+ GENERIC_READ|GENERIC_WRITE,
+ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ NULL,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if (TheFile == INVALID_HANDLE_VALUE)
+ {
+ Fail("ERROR: Could not open file '%s' with CreateFile. "
+ "GetLastError() returned %d.",FileName,GetLastError());
+ }
+
+ if(WriteFile(TheFile, WriteBuffer,
+ strlen(WriteBuffer),&BytesWritten, NULL) == 0)
+ {
+ Fail("ERROR: WriteFile has failed. It returned 0 when we "
+ "attempted to write to the file '%s'. GetLastError() "
+ "returned %d.",FileName,GetLastError());
+ }
+
+ if(FlushFileBuffers(TheFile) == 0)
+ {
+ Fail("ERROR: FlushFileBuffers returned failure. GetLastError() "
+ "returned %d.",GetLastError());
+ }
+
+ if(LockFile(TheFile, LockStart, 0, LockLength, 0) == 0)
+ {
+ Fail("ERROR: LockFile failed. GetLastError returns %d.",
+ GetLastError());
+ }
+
+ return TheFile;
+}
+
+void SignalAndBusyWait(HANDLE TheFile)
+{
+ int size;
+ DWORD BytesWritten;
+
+ size = GetFileSize(TheFile,NULL)+1;
+
+ if(SetFilePointer(TheFile, 0, NULL, FILE_END) == INVALID_SET_FILE_POINTER)
+ {
+ Fail("ERROR: SetFilePointer was unable to set the pointer to the "
+ "end of the file. GetLastError() returned %d.",GetLastError());
+ }
+
+ if(WriteFile(TheFile, "x", 1,&BytesWritten, NULL) == 0)
+ {
+ Fail("ERROR: WriteFile was unable to write to the WaitFile. "
+ "GetLastError() returned %d.",GetLastError());
+ }
+
+ if(FlushFileBuffers(TheFile) == 0)
+ {
+ Fail("ERROR: FlushFileBuffers failed when flushing the WaitFile. "
+ "GetLastError() returned %d.");
+ }
+
+ while(GetFileSize(TheFile,NULL) == size) { Sleep(100); }
+}
+
+void SignalFinish(HANDLE TheFile)
+{
+ DWORD BytesWritten;
+
+ if(SetFilePointer(TheFile, 0, NULL, FILE_END) == INVALID_SET_FILE_POINTER)
+ {
+ Fail("ERROR: SetFilePointer was unable to set the pointer to the "
+ "end of the WaitFile. GetLastError() returned %d.",
+ GetLastError());
+ }
+
+ if(WriteFile(TheFile, "x", 1,&BytesWritten, NULL) == 0)
+ {
+ Fail("ERROR: WriteFile was unable to write to the WaitFile. "
+ "GetLastError returned %d.",GetLastError());
+ }
+
+ if(FlushFileBuffers(TheFile) == 0)
+ {
+ Fail("ERROR: FlushFileBuffers failed when flushing the WaitFile. "
+ "GetLastError() returned %d.");
+ }
+}
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/LockFile/test1/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/LockFile/test1/CMakeLists.txt
new file mode 100644
index 0000000000..0af09480ef
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/LockFile/test1/CMakeLists.txt
@@ -0,0 +1,36 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(TESTSOURCES
+ test1.c
+)
+
+add_executable(paltest_lockfile_test1
+ ${TESTSOURCES}
+)
+
+add_dependencies(paltest_lockfile_test1 coreclrpal)
+
+target_link_libraries(paltest_lockfile_test1
+ pthread
+ m
+ coreclrpal
+)
+
+
+set(HELPERSOURCES
+ helper.c
+)
+
+add_executable(paltest_lockfile_test1_helper
+ ${HELPERSOURCES}
+)
+
+add_dependencies(paltest_lockfile_test1_helper coreclrpal)
+
+target_link_libraries(paltest_lockfile_test1_helper
+ pthread
+ m
+ coreclrpal
+) \ No newline at end of file
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/LockFile/test1/helper.c b/src/pal/tests/palsuite/filemapping_memmgt/LockFile/test1/helper.c
new file mode 100644
index 0000000000..05b4b8451a
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/LockFile/test1/helper.c
@@ -0,0 +1,86 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: helper.c
+**
+** Purpose: A child process which will attempt to read and write to files
+** which were locked in the parent.
+**
+**
+**============================================================*/
+
+#include <palsuite.h>
+
+#define BUF_SIZE 128
+
+int __cdecl main(int argc, char *argv[])
+{
+ HANDLE TheFile;
+ int result = 0;
+ char DataBuffer[BUF_SIZE];
+ DWORD BytesRead, BytesWritten;
+ char fileName[] = "testfile.tmp";
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /* Open the same file that the parent has opened and locked */
+ TheFile = CreateFile(fileName,
+ GENERIC_READ|GENERIC_WRITE,
+ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if (TheFile == INVALID_HANDLE_VALUE)
+ {
+ Fail("ERROR: Could not open file '%s' with CreateFile.",fileName);
+ }
+
+ /* Attempt to Read 5 bytes from this file. Since it is locked, this
+ should fail.
+ */
+
+ if(ReadFile(TheFile, DataBuffer, 5, &BytesRead, NULL) != 0)
+ {
+ Trace("ERROR: ReadFile should have failed! It was called on "
+ "a locked file. But, it returned non-zero indicating success.");
+ result = 1;
+ }
+
+ /* Attempt to Write 5 bytes to this file. Since it is locked this should
+ fail.
+ */
+
+ memset(DataBuffer,'X',BUF_SIZE);
+
+ if(WriteFile(TheFile, DataBuffer, 5,&BytesWritten, NULL) != 0)
+ {
+ Trace("ERROR: WriteFile should have failed! It was called on "
+ "a locked file. But, it returned non-zero indicating success.");
+ result = 1;
+ }
+
+ /* Check to ensure that the number of Bytes read/written is still 0,
+ since nothing should have been read or written.
+ */
+
+ if(BytesRead != 0 || BytesWritten !=0)
+ {
+ Trace("ERROR: The number of bytes read is %d and written is %d. "
+ "These should both be 0, as the file was locked.",
+ BytesRead,BytesWritten);
+ result = 1;
+ }
+
+ PAL_TerminateEx(result);
+ return result;
+}
+
+
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/LockFile/test1/test1.c b/src/pal/tests/palsuite/filemapping_memmgt/LockFile/test1/test1.c
new file mode 100644
index 0000000000..cee223ef81
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/LockFile/test1/test1.c
@@ -0,0 +1,140 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: test1.c
+**
+** Purpose: Open a file, and lock it from start to EOF. Then create a
+** new process, which will attempt to Read and Write from the file. Check
+** to ensure both of these operations fail.
+**
+**
+**============================================================*/
+
+#include <palsuite.h>
+#include "../LockFile.h"
+
+#define HELPER "helper"
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ HANDLE TheFile;
+ DWORD FileStart = 0;
+ DWORD FileEnd = 0;
+ const char lpBuffer[] = "This is a test file.";
+ DWORD bytesWritten;
+ BOOL bRc = TRUE;
+ char fileName[] = "testfile.tmp";
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /* Important to have sharing enabled, or there is no need for the lock. */
+ TheFile = CreateFile(fileName,
+ GENERIC_READ|GENERIC_WRITE,
+ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ NULL,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if (TheFile == INVALID_HANDLE_VALUE)
+ {
+ Fail("ERROR: Could not open file '%s' with CreateFile.",fileName);
+ }
+
+ bRc = WriteFile(TheFile,
+ lpBuffer,
+ (DWORD)sizeof(lpBuffer),
+ &bytesWritten,
+ NULL);
+
+ if(!bRc)
+ {
+ if(CloseHandle(TheFile) == 0)
+ {
+ Fail("ERROR: CloseHandle failed to close the file.");
+ }
+
+ Fail("ERROR: Could not write to file '%s' with WriteFile.",fileName);
+ }
+ else if(bytesWritten != (DWORD)sizeof(lpBuffer))
+ {
+ if(CloseHandle(TheFile) == 0)
+ {
+ Fail("ERROR: CloseHandle failed to close the file.");
+ }
+
+ Fail("ERROR: Could not write the correct number of bytes to the "
+ "file '%s' with WriteFile.",fileName);
+ }
+
+ /* Find the value for the End of the file */
+ FileEnd = SetFilePointer(TheFile,0,NULL,FILE_END);
+
+ if(FileEnd == INVALID_SET_FILE_POINTER)
+ {
+ if(CloseHandle(TheFile) == 0)
+ {
+ Fail("ERROR: CloseHandle failed to close the file.");
+ }
+
+ Fail("ERROR: Could not set the file pointer to the end of the file "
+ "using SetFilePointer. It returned INVALID_SET_FILE_POINTER.");
+ }
+
+ /* Lock the file from Start to EOF */
+
+ if(LockFile(TheFile, FileStart, 0, FileEnd, 0) == 0)
+ {
+ Trace("ERROR: LockFile failed. GetLastError returns %d.",
+ GetLastError());
+ if(CloseHandle(TheFile) == 0)
+ {
+ Fail("ERROR: CloseHandle failed to close the file.");
+ }
+ Fail("");
+ }
+
+ /* Launch another process, which will attempt to read and write from
+ the locked file.
+
+ If the helper program returns 1, then the test fails. More
+ specific errors are given by the Helper file itself.
+ */
+ if(RunHelper(HELPER))
+ {
+ if(CloseHandle(TheFile) == 0)
+ {
+ Fail("ERROR: CloseHandle failed to close the file.");
+ }
+
+ Fail("ERROR: The Helper program determined that the file was not "
+ "locked properly by LockFile.");
+ }
+
+ if(UnlockFile(TheFile, FileStart, 0, FileEnd, 0) == 0)
+ {
+ Trace("ERROR: UnlockFile failed. GetLastError returns %d.",
+ GetLastError());
+ if(CloseHandle(TheFile) == 0)
+ {
+ Fail("ERROR: CloseHandle failed to close the file.");
+ }
+ Fail("");
+ }
+
+ if(CloseHandle(TheFile) == 0)
+ {
+ Fail("ERROR: CloseHandle failed to close the file.");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/LockFile/test1/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/LockFile/test1/testinfo.dat
new file mode 100644
index 0000000000..cbe4d94d40
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/LockFile/test1/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = LockFile
+Name = Positive test for LockFile API
+TYPE = DEFAULT
+EXE1 = test1
+EXE2 = helper
+Description
+= Open a file, and lock it from start to EOF. Then create a
+= new process, which will attempt to Read and Write from the file. Check
+= to ensure both of these operations fail.
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/LockFile/test2/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/LockFile/test2/CMakeLists.txt
new file mode 100644
index 0000000000..157c517e62
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/LockFile/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test2.c
+)
+
+add_executable(paltest_lockfile_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_lockfile_test2 coreclrpal)
+
+target_link_libraries(paltest_lockfile_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/LockFile/test2/test2.c b/src/pal/tests/palsuite/filemapping_memmgt/LockFile/test2/test2.c
new file mode 100644
index 0000000000..8aef130ef4
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/LockFile/test2/test2.c
@@ -0,0 +1,94 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: test2.c
+**
+** Purpose: Open a file, and lock it from start to EOF. Check to ensure
+** the current process can still read and write from/to the file.
+**
+**
+**============================================================*/
+
+#include <palsuite.h>
+#include "../LockFile.h"
+
+#define FILENAME "testfile.txt"
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ HANDLE TheFile = NULL;
+ DWORD FileStart = 0;
+ DWORD FileEnd = 0;
+ DWORD BytesWritten = 0;
+ DWORD BytesRead = 0;
+ char WriteBuffer[] = "This is some test data.";
+ char DataBuffer[128];
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /* Call the helper function to Create a file, write 'WriteBuffer' to
+ the file, and lock the file.
+ */
+
+ FileEnd = strlen(WriteBuffer);
+ TheFile = CreateAndLockFile(TheFile, FILENAME, WriteBuffer,
+ FileStart, FileEnd);
+
+ /* Move the file pointer to the start of the file */
+ if(SetFilePointer(TheFile, 0, NULL, FILE_BEGIN) != 0)
+ {
+ Fail("ERROR: SetFilePointer failed to move the file pointer back "
+ "to the start of the file.");
+ }
+
+ /* Attempt to Read 5 bytes from this file. Since the lock does not
+ affect the calling process, this should succeed.
+ */
+
+ if(ReadFile(TheFile, DataBuffer, 5, &BytesRead, NULL) == 0)
+ {
+ Fail("ERROR: ReadFile has failed. Attempted to read in 5 bytes from "
+ "the file '%s' after it had LockFile called upon it, but within "
+ "the same process.",FILENAME);
+ }
+
+ if(strncmp(DataBuffer, WriteBuffer, 5) != 0)
+ {
+ Fail("ERROR: The data read in from ReadFile is not what should have "
+ "been written in the file. '%s' ",DataBuffer);
+ }
+
+ /* Attempt to Write 5 bytes to this file. Since the lock does not affect
+ the calling process, this should succeed.
+ */
+
+ memset(WriteBuffer, 'X', strlen(WriteBuffer));
+
+ if(WriteFile(TheFile, WriteBuffer, 5,&BytesWritten, NULL) == 0)
+ {
+ Fail("ERROR: WriteFile has failed. Attempted to write 5 bytes to "
+ "the file '%s' after it had LockFile called upon it, but within "
+ "the same process.",FILENAME);
+ }
+
+ if(UnlockFile(TheFile, FileStart, 0, FileEnd, 0) == 0)
+ {
+ Fail("ERROR: UnlockFile failed. GetLastError returns %d.",
+ GetLastError());
+ }
+
+ if(CloseHandle(TheFile) == 0)
+ {
+ Fail("ERROR: CloseHandle failed to close the file.");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/LockFile/test2/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/LockFile/test2/testinfo.dat
new file mode 100644
index 0000000000..c84e7c0a0a
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/LockFile/test2/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = LockFile
+Name = Positive test for LockFile API
+TYPE = DEFAULT
+EXE1 = test2
+Description
+= Open a file, and lock it from start to EOF. Check to ensure
+= the current process can still read and write from/to the file.
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/LockFile/test3/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/LockFile/test3/CMakeLists.txt
new file mode 100644
index 0000000000..69516de69b
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/LockFile/test3/CMakeLists.txt
@@ -0,0 +1,36 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(TESTSOURCES
+ test3.c
+)
+
+add_executable(paltest_lockfile_test3
+ ${TESTSOURCES}
+)
+
+add_dependencies(paltest_lockfile_test3 coreclrpal)
+
+target_link_libraries(paltest_lockfile_test3
+ pthread
+ m
+ coreclrpal
+)
+
+
+set(HELPERSOURCES
+ helper.c
+)
+
+add_executable(paltest_lockfile_test3_helper
+ ${HELPERSOURCES}
+)
+
+add_dependencies(paltest_lockfile_test3_helper coreclrpal)
+
+target_link_libraries(paltest_lockfile_test3_helper
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/LockFile/test3/helper.c b/src/pal/tests/palsuite/filemapping_memmgt/LockFile/test3/helper.c
new file mode 100644
index 0000000000..079417fce8
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/LockFile/test3/helper.c
@@ -0,0 +1,102 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: helper.c
+**
+** Purpose: A child process which will attempt to read and write to files
+** which were locked in the parent.
+**
+**
+**============================================================*/
+
+#include <palsuite.h>
+
+#define FILENAME "testfile.txt"
+#define BUF_SIZE 128
+
+int __cdecl main(int argc, char *argv[])
+{
+ HANDLE TheFile;
+ int result = 0;
+ char DataBuffer[BUF_SIZE];
+ DWORD BytesRead, BytesWritten;
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /* Open the same file that the parent has opened and locked */
+ TheFile = CreateFile(FILENAME,
+ GENERIC_READ|GENERIC_WRITE,
+ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if (TheFile == INVALID_HANDLE_VALUE)
+ {
+ Fail("ERROR: Could not open file '%s' with CreateFile. "
+ "GetLastError() returns %d.",FILENAME,GetLastError());
+ }
+
+ /* Attempt to Read the first 3 bytes from this file.
+ Since it is unlocked, this should work properly.
+ */
+
+ if(ReadFile(TheFile, DataBuffer, 3, &BytesRead, NULL) == 0)
+ {
+ Trace("ERROR: ReadFile should have succeeded in reading the first "
+ "three bytes of the file, as these bytes were not locked. "
+ "GetLastError() returned %d.",GetLastError());
+ result = 1;
+ }
+
+ /* Now, read the next 10 bytes, which should be locked. Ensure that
+ ReadFile fails.
+ */
+
+ if(ReadFile(TheFile, DataBuffer,10, &BytesRead, NULL) != 0)
+ {
+ Trace("ERROR: ReadFile should have failed when attempting to read in "
+ "bytes between StartOfFile+3 and EndOfFile-3.");
+ result = 1;
+ }
+
+ /* Attempt to Write 10 bytes to this file. Since it is locked this should
+ fail.
+ */
+
+ memset(DataBuffer,'X',BUF_SIZE);
+
+ if(WriteFile(TheFile, DataBuffer, 10,&BytesWritten, NULL) != 0)
+ {
+ Trace("ERROR: WriteFile should have failed when attempting to write "
+ "bytes between StartOfFile+3 and EOF-3.");
+ result = 1;
+ }
+
+
+ /* Move the FilePointer to the EOF-3, where the lock ends */
+ if(SetFilePointer(TheFile,-3,NULL,FILE_END) == INVALID_SET_FILE_POINTER)
+ {
+ Fail("ERROR: Could not set the file pointer to the EOF-3 "
+ "using SetFilePointer. It returned INVALID_SET_FILE_POINTER.");
+ }
+
+ /* Attempt to write to those 3 unlocked bytes on the end of the file */
+ if(WriteFile(TheFile, DataBuffer, 3,&BytesWritten, NULL) == 0)
+ {
+ Trace("ERROR: WriteFile should have succeeded when attempting "
+ "to write the last three bytes of the file, as they were not "
+ "locked. GetLastError() returned %d.",GetLastError());
+ result = 1;
+ }
+
+ PAL_TerminateEx(result);
+ return result;
+}
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/LockFile/test3/test3.c b/src/pal/tests/palsuite/filemapping_memmgt/LockFile/test3/test3.c
new file mode 100644
index 0000000000..78662c5685
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/LockFile/test3/test3.c
@@ -0,0 +1,71 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: test3.c
+**
+** Purpose: Open a file, lock a region in the middle. Create a new process
+** and attempt to read and write directly before and after that region, which
+** should succeed. Also, check to see that reading/writing in the locked
+** region fails.
+**
+**
+**============================================================*/
+
+#include <palsuite.h>
+#include "../LockFile.h"
+
+#define HELPER "helper"
+#define FILENAME "testfile.txt"
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ HANDLE TheFile = NULL;
+ DWORD FileStart = 0;
+ DWORD FileEnd = 0;
+ char* WriteBuffer = "12345678901234567890123456";
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /* Call the helper function to Create a file, write 'WriteBuffer' to
+ the file, and lock the file.
+ */
+
+ FileEnd = strlen(WriteBuffer);
+ TheFile = CreateAndLockFile(TheFile,FILENAME, WriteBuffer,
+ FileStart+3, FileEnd-6);
+
+
+ /* Launch another process, which will attempt to read and write from
+ the locked file.
+
+ If the helper program returns 1, then the test fails. More
+ specific errors are given by the Helper file itself.
+ */
+ if(RunHelper(HELPER))
+ {
+ Fail("ERROR: The Helper program determined that the file was not "
+ "locked properly by LockFile.");
+ }
+
+ if(UnlockFile(TheFile, FileStart+3, 0, FileEnd-6, 0) == 0)
+ {
+ Fail("ERROR: UnlockFile failed. GetLastError returns %d.",
+ GetLastError());
+ }
+
+ if(CloseHandle(TheFile) == 0)
+ {
+ Fail("ERROR: CloseHandle failed to close the file. "
+ "GetLastError() returned %d.",GetLastError());
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/LockFile/test3/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/LockFile/test3/testinfo.dat
new file mode 100644
index 0000000000..b64ec5ed03
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/LockFile/test3/testinfo.dat
@@ -0,0 +1,16 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = LockFile
+Name = Positive test for LockFile API
+TYPE = DEFAULT
+EXE1 = test3
+EXE2 = helper
+Description
+= Open a file, lock a region in the middle. Create a new process
+= and attempt to read and write directly before and after that region, which
+= should succeed. Also, check to see that reading/writing in the locked
+= region fails.
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/LockFile/test4/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/LockFile/test4/CMakeLists.txt
new file mode 100644
index 0000000000..fb8f6745d4
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/LockFile/test4/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test4.c
+)
+
+add_executable(paltest_lockfile_test4
+ ${SOURCES}
+)
+
+add_dependencies(paltest_lockfile_test4 coreclrpal)
+
+target_link_libraries(paltest_lockfile_test4
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/LockFile/test4/test4.c b/src/pal/tests/palsuite/filemapping_memmgt/LockFile/test4/test4.c
new file mode 100644
index 0000000000..f5cd359fb5
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/LockFile/test4/test4.c
@@ -0,0 +1,231 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: test4.c
+**
+** Purpose:
+** - Attempt to call LockFile on a file without GENERIC_READ or
+** GENERIC_WRITE (this should fail)
+** - Attempt to overlap two locks, this should fail.
+**
+**
+**============================================================*/
+
+#include <palsuite.h>
+
+char fileName[] = "testfile.tmp";
+
+void OverlapTest()
+{
+ HANDLE TheFile = NULL;
+ DWORD FileStart = 0;
+ const char lpBuffer[] = "This is a test file.";
+ DWORD bytesWritten;
+ BOOL bRc = TRUE;
+
+ TheFile = CreateFile(fileName,
+ GENERIC_READ|GENERIC_WRITE,
+ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ NULL,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if (TheFile == INVALID_HANDLE_VALUE)
+ {
+ Fail("ERROR: Could not open file '%s' with CreateFile. "
+ "GetLastError() returned %d.",fileName,GetLastError());
+ }
+
+ bRc = WriteFile(TheFile,
+ lpBuffer,
+ (DWORD)sizeof(lpBuffer),
+ &bytesWritten,
+ NULL);
+
+ if(!bRc)
+ {
+ Trace("ERROR: Could not write to file '%s' with WriteFile.",fileName);
+
+ if(CloseHandle(TheFile) == 0)
+ {
+ Fail("ERROR: CloseHandle failed to close the file.");
+ }
+ Fail("");
+
+ }
+ else if(bytesWritten != (DWORD)sizeof(lpBuffer))
+ {
+ Trace("ERROR: Could not write the correct number of bytes to the "
+ "file '%s' with WriteFile.",fileName);
+
+ if(CloseHandle(TheFile) == 0)
+ {
+ Fail("ERROR: CloseHandle failed to close the file.");
+ }
+ Fail("");
+ }
+
+ /* Lock the First 5 bytes of the File */
+
+ if(LockFile(TheFile, FileStart, 0, 5, 0) == 0)
+ {
+ Trace("ERROR: LockFile failed in Overlap test. "
+ "GetLastError returns %d.",
+ GetLastError());
+
+ if(CloseHandle(TheFile) == 0)
+ {
+ Fail("ERROR: CloseHandle failed to close the file.");
+ }
+ Fail("");
+ }
+
+ /* Lock from Byte 2 until 7 -- this overlaps and should return failure. */
+ if(LockFile(TheFile,FileStart+2, 0, 5, 0) != 0)
+ {
+ Trace("ERROR: LockFile returned success when it was overlapped on "
+ "an already locked region of the file.");
+
+ if(CloseHandle(TheFile) == 0)
+ {
+ Fail("ERROR: CloseHandle failed to close the file.");
+ }
+ Fail("");
+ }
+
+ /* Unlock the file */
+ if(UnlockFile(TheFile, FileStart, 0, 5, 0) == 0)
+ {
+ Trace("ERROR: UnlockFile failed in Overlap test. GetLastError "
+ "returns %d.",GetLastError());
+
+ if(CloseHandle(TheFile) == 0)
+ {
+ Fail("ERROR: CloseHandle failed to close the file.");
+ }
+ Fail("");
+ }
+
+ /* Close the File */
+ if(CloseHandle(TheFile) == 0)
+ {
+ Fail("ERROR: CloseHandle failed to close the file in the Overlap "
+ "test. GetLastError() returned %d.",GetLastError());
+ }
+}
+
+void FlagsTest(DWORD TheFlags, int ExpectedResult)
+{
+ HANDLE TheFile = NULL;
+ DWORD FileStart = 0;
+ int result;
+
+ TheFile = CreateFile(fileName,
+ TheFlags,
+ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if (TheFile == INVALID_HANDLE_VALUE)
+ {
+ Fail("ERROR: Could not open file '%s' with CreateFile. "
+ "GetLastError() returned %d.",fileName,GetLastError());
+ }
+
+ /* Lock the First 5 bytes of the File. The result of this depends
+ upon which flags were set with the CreateFile.
+ */
+
+ result = LockFile(TheFile, FileStart, 0, 5, 0);
+
+ /* If the expected result is 1, check to ensure the result is non-zero,
+ as non-zero is returned on success
+ */
+ if(ExpectedResult == 1)
+ {
+ if(result == 0)
+ {
+ Trace("ERROR: LockFile returned zero when the expected result "
+ "was non-zero. It was passed the flag value %d.",
+ TheFlags);
+
+ if(CloseHandle(TheFile) == 0)
+ {
+ Fail("ERROR: CloseHandle failed to close the file.");
+ }
+ Fail("");
+ }
+ }
+ /* If the expected result is 0, check to ensure the result is 0 */
+ else
+ {
+ if(result != 0)
+ {
+ Trace("ERROR: LockFile returned %d when the expected result "
+ "was zero. It was passed the flag value %d.",
+ result, TheFlags);
+
+ if(CloseHandle(TheFile) == 0)
+ {
+ Fail("ERROR: CloseHandle failed to close the file.");
+ }
+ Fail("");
+ }
+ }
+
+ /* Only unlock the file if we expect it to be successfully locked */
+ if(ExpectedResult)
+ {
+ if(UnlockFile(TheFile,FileStart,0, 5, 0) == 0)
+ {
+ Fail("ERROR: UnlockFile failed in the Flags Test. GetLastError() "
+ "returned %d.",GetLastError());
+
+ if(CloseHandle(TheFile) == 0)
+ {
+ Fail("ERROR: CloseHandle failed to close the file.");
+ }
+ Fail("");
+ }
+ }
+
+ /* Close the File */
+ if(CloseHandle(TheFile) == 0)
+ {
+ Fail("ERROR: CloseHandle failed to close the file in the Flags "
+ "test. GetLastError() returned %d.",GetLastError());
+ }
+}
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /* This test opens a file, then calls lock twice, overlapping the
+ regions and checking to ensure that this causes an error.
+ */
+ OverlapTest();
+
+ /* Test that LockFile fails if no flags are set */
+ FlagsTest(0,0);
+
+ /* Test that LockFile passes if only GENERIC_READ is set */
+ FlagsTest(GENERIC_READ,1);
+
+ /* Test that LockFile passes if only GENERIC_WRITE is set */
+ FlagsTest(GENERIC_WRITE,1);
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/LockFile/test4/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/LockFile/test4/testinfo.dat
new file mode 100644
index 0000000000..0600260d82
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/LockFile/test4/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = LockFile
+Name = Negative test for LockFile API
+TYPE = DEFAULT
+EXE1 = test4
+Description
+= - Attempt to call LockFile on a file without GENERIC_READ or
+= GENERIC_WRITE (this should fail)
+= - Attempt to overlap two locks, this should fail.
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/LockFile/test5/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/LockFile/test5/CMakeLists.txt
new file mode 100644
index 0000000000..cc4548a6f0
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/LockFile/test5/CMakeLists.txt
@@ -0,0 +1,36 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(TESTSOURCES
+ test5.c
+)
+
+add_executable(paltest_lockfile_test5
+ ${TESTSOURCES}
+)
+
+add_dependencies(paltest_lockfile_test5 coreclrpal)
+
+target_link_libraries(paltest_lockfile_test5
+ pthread
+ m
+ coreclrpal
+)
+
+
+set(HELPERSOURCES
+ helper.c
+)
+
+add_executable(paltest_lockfile_test5_helper
+ ${HELPERSOURCES}
+)
+
+add_dependencies(paltest_lockfile_test5_helper coreclrpal)
+
+target_link_libraries(paltest_lockfile_test5_helper
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/LockFile/test5/helper.c b/src/pal/tests/palsuite/filemapping_memmgt/LockFile/test5/helper.c
new file mode 100644
index 0000000000..1fc9b1a9a5
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/LockFile/test5/helper.c
@@ -0,0 +1,122 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: helper.c
+**
+** Purpose: A child process which will attempt to read and write to files
+** which were locked in the parent. It will also lock another region of the
+** same file.
+**
+**
+**============================================================*/
+
+#include <palsuite.h>
+#include "../LockFile.h"
+
+#define FILENAME "testfile.txt"
+#define WAITFILENAME "waitfile"
+#define BUF_SIZE 128
+
+int __cdecl main(int argc, char *argv[])
+{
+ HANDLE TheFile, WaitFile;
+ int result = 0;
+ char DataBuffer[BUF_SIZE];
+ DWORD BytesRead;
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /* Open the same file that the parent has opened and locked */
+ TheFile = CreateFile(FILENAME,
+ GENERIC_READ|GENERIC_WRITE,
+ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if (TheFile == INVALID_HANDLE_VALUE)
+ {
+ Trace("ERROR: Could not open file '%s' with CreateFile.",FILENAME);
+ result = 1;
+ }
+
+ /* Open up the WaitFile that we're using for IPC */
+ WaitFile = CreateFile(WAITFILENAME,
+ GENERIC_READ|GENERIC_WRITE,
+ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ NULL,
+ OPEN_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if (WaitFile == INVALID_HANDLE_VALUE)
+ {
+ Trace("ERROR: Could not open file '%s' with CreateFile. "
+ "GetLastError() returned %d.",WAITFILENAME,GetLastError());
+ result = 1;
+ }
+
+ /* Lock the same file that the parent process locked, but the child
+ locks bytes 11 through 20
+ */
+
+ if(LockFile(TheFile, 11, 0, 10, 0) == 0)
+ {
+ Trace("ERROR: LockFile failed in the child proccess. "
+ "GetLastError returns %d.",
+ GetLastError());
+ result = 1;
+ }
+
+ /* Check to ensure the parent lock is respected */
+ if(ReadFile(TheFile, DataBuffer, 10, &BytesRead, NULL) != 0)
+ {
+ Trace("ERROR: ReadFile returned success when it should "
+ "have failed. Attempted to read the first 10 bytes "
+ "of a file which was locked by the parent process.");
+ result = 1;
+ }
+
+ /* Check to ensure the lock put on by this proccess doesn't restrict
+ access
+ */
+
+ if(SetFilePointer(TheFile, 11, 0, FILE_BEGIN) == INVALID_SET_FILE_POINTER)
+ {
+ Trace("ERROR: SetFilePointer was unable to move the file pointer to "
+ "the 11th byte in the file, within the child proccess. "
+ "GetLastError() returned %d.",GetLastError());
+ result = 1;
+ }
+
+ if(ReadFile(TheFile, DataBuffer, 10, &BytesRead, NULL) == 0)
+ {
+ Trace("ERROR: ReadFile failed when attempting to read a section of "
+ "the file which was locked by the current process. It should "
+ "have been able to read this. GetLastError() returned %d.",
+ GetLastError());
+ result = 1;
+ }
+
+ // Sleep for a bit to give the parent a chance to block before we do.
+ Sleep(1000);
+
+ /* Switch back to the parent, so it can check the child's locks */
+ SignalAndBusyWait(WaitFile);
+
+ if(UnlockFile(TheFile, 11, 0, 10, 0) == 0)
+ {
+ Fail("ERROR: Failed to Unlock bytes 11-20 in the file. "
+ "GetLastError returned %d.",GetLastError());
+ }
+
+ PAL_TerminateEx(result);
+ return result;
+}
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/LockFile/test5/test5.c b/src/pal/tests/palsuite/filemapping_memmgt/LockFile/test5/test5.c
new file mode 100644
index 0000000000..a02a3c5a49
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/LockFile/test5/test5.c
@@ -0,0 +1,161 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: test5.c
+**
+** Purpose:
+** Have two processes obtain a lock on a single file, but in different
+** regions of the file. Use Read/Write to ensure the locks are respected.
+** This requires some IPC, which is done here with a crude busy wait on a
+** file (waiting for the file size to change) to avoid too many more
+** dependencies.
+**
+**
+**============================================================*/
+
+#include <palsuite.h>
+#include "../LockFile.h"
+
+#define HELPER "helper"
+#define FILENAME "testfile.txt"
+#define WAITFILENAME "waitfile"
+#define BUF_SIZE 128
+
+int RunTest(char* Helper, HANDLE TheFile, HANDLE WaitFile)
+{
+ STARTUPINFO si;
+ PROCESS_INFORMATION pi;
+ DWORD ChildRetCode = 0;
+ DWORD ParentRetCode = 0;
+ DWORD BytesRead;
+ char DataBuffer[BUF_SIZE];
+
+
+ ZeroMemory( &si, sizeof(si) );
+ si.cb = sizeof(si);
+ ZeroMemory( &pi, sizeof(pi) );
+
+ /* Load up the helper Process, and then Wait until it signals that it
+ is finished locking.
+ */
+ if(!CreateProcess( NULL,Helper,NULL,NULL,FALSE,0,NULL,NULL,&si,&pi))
+ {
+ Fail("ERROR: CreateProcess failed to load executable '%s'.",Helper);
+ }
+
+ SignalAndBusyWait(WaitFile);
+
+ /* Now the child proccess has locked another section of the file, from
+ bytes 11 through 20. Let's check that the parent lock is still ignored
+ by the parent proccess and that the child's lock is respected.
+ */
+
+ if(ReadFile(TheFile, DataBuffer, 10, &BytesRead, NULL) == 0)
+ {
+ Trace("ERROR: ReadFile failed when attempting to read a section of "
+ "the file which was locked by the current process. It should "
+ "have been able to read this. GetLastError() returned %d.",
+ GetLastError());
+ ParentRetCode = 1;
+ }
+
+ SetFilePointer(TheFile, 11, 0, FILE_BEGIN);
+
+ if(ReadFile(TheFile, DataBuffer, 10, &BytesRead, NULL) != 0)
+ {
+ Trace("ERROR: ReadFile returned success when it should "
+ "have failed. Attempted to read 10 bytes of the file which "
+ "were locked by the child.");
+ ParentRetCode = 1;
+ }
+
+ /* We're finished testing. Let the child proccess know so it can clean
+ up, and the parent will wait until it is done.
+ */
+ SignalFinish(WaitFile);
+ WaitForSingleObject(pi.hProcess,INFINITE);
+
+ /* Get the return value from the helper process */
+ if (GetExitCodeProcess(pi.hProcess, &ChildRetCode) == 0)
+ {
+ Fail("ERROR: GetExitCodeProccess failed when attempting to retrieve "
+ "the exit code of the child process.");
+ }
+
+ if(CloseHandle( pi.hProcess ) == 0)
+ {
+ Fail("ERROR: CloseHandle failed to close the process.");
+ }
+
+ if(CloseHandle( pi.hThread ) == 0)
+ {
+ Fail("ERROR: CloseHandle failed to close the thread.");
+ }
+
+ return (ChildRetCode || ParentRetCode);
+}
+
+int __cdecl main(int argc, char *argv[])
+{
+ HANDLE TheFile = NULL;
+ HANDLE WaitFile = NULL;
+ char* WriteBuffer = "12345678901234567890123456";
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /* Open up the file we'll be using for some crude IPC */
+ WaitFile = CreateFile(WAITFILENAME,
+ GENERIC_READ|GENERIC_WRITE,
+ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ NULL,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if (WaitFile == INVALID_HANDLE_VALUE)
+ {
+ Fail("ERROR: Could not open file '%s' with CreateFile. "
+ "GetLastError() returned %d.",WAITFILENAME,GetLastError());
+ }
+
+ /* Call the helper function to Create a file, write 'WriteBuffer' to
+ the file, and lock the file from bytes 0 to 10.
+ */
+ TheFile = CreateAndLockFile(TheFile, FILENAME, WriteBuffer,
+ 0, 10);
+
+ /* Run the test. Better errors are displayed by Trace throughout. */
+ if(RunTest(HELPER, TheFile, WaitFile))
+ {
+ Fail("ERROR: Attempting to have two processes lock different "
+ "sections of the same file has failed.");
+ }
+
+ /* Unlock the first 10 bytes which were locked by the parent proccess */
+ if(UnlockFile(TheFile, 0, 0, 10, 0) == 0)
+ {
+ Fail("ERROR: Failed to Unlock the first 10 bytes of the file. "
+ "GetLastError returned %d.",GetLastError());
+ }
+
+ if(CloseHandle(TheFile) == 0)
+ {
+ Fail("ERROR: CloseHandle failed to close the file used for "
+ "testing the locks. GetLastError() returns %d.",GetLastError());
+ }
+
+ if(CloseHandle(WaitFile) == 0)
+ {
+ Fail("ERROR: CloseHandle failed to close the wait file. "
+ "GetLastError() returns %d.",GetLastError());
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/LockFile/test5/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/LockFile/test5/testinfo.dat
new file mode 100644
index 0000000000..f020933cd9
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/LockFile/test5/testinfo.dat
@@ -0,0 +1,17 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = LockFile
+Name = Positive test for LockFile API
+TYPE = DEFAULT
+EXE1 = test5
+EXE2 = helper
+Description
+= Have two processes obtain a lock on a single file, but in different
+= regions of the file. Use Read/Write to ensure the locks are respected.
+= This requires some IPC, which is done here with a crude busy wait on a
+= file (waiting for the file size to change) to avoid too many more
+= dependencies.
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/LockFile/test6/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/LockFile/test6/CMakeLists.txt
new file mode 100644
index 0000000000..5049977582
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/LockFile/test6/CMakeLists.txt
@@ -0,0 +1,36 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(TESTSOURCES
+ test6.c
+)
+
+add_executable(paltest_lockfile_test6
+ ${TESTSOURCES}
+)
+
+add_dependencies(paltest_lockfile_test6 coreclrpal)
+
+target_link_libraries(paltest_lockfile_test6
+ pthread
+ m
+ coreclrpal
+)
+
+
+set(HELPERSOURCES
+ helper.c
+)
+
+add_executable(paltest_lockfile_test6_helper
+ ${HELPERSOURCES}
+)
+
+add_dependencies(paltest_lockfile_test6_helper coreclrpal)
+
+target_link_libraries(paltest_lockfile_test6_helper
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/LockFile/test6/helper.c b/src/pal/tests/palsuite/filemapping_memmgt/LockFile/test6/helper.c
new file mode 100644
index 0000000000..98112fc4a5
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/LockFile/test6/helper.c
@@ -0,0 +1,71 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: helper.c
+**
+** Purpose: A child process which will attempt to append to the end of
+** a locked file.
+**
+**
+**============================================================*/
+
+#include <palsuite.h>
+
+#define FILENAME "testfile.txt"
+#define BUF_SIZE 128
+
+int __cdecl main(int argc, char *argv[])
+{
+ HANDLE TheFile;
+ int result = 0;
+ char DataBuffer[BUF_SIZE];
+ DWORD BytesWritten;
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /* Open the same file that the parent has opened and locked */
+ TheFile = CreateFile(FILENAME,
+ GENERIC_READ|GENERIC_WRITE,
+ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if (TheFile == INVALID_HANDLE_VALUE)
+ {
+ Trace("ERROR: Could not open file '%s' with CreateFile. "
+ "GetLastError() returns %d.",FILENAME,GetLastError());
+ result = -1;
+ }
+
+
+ /* Move the FilePointer to the EOF */
+ if(SetFilePointer(TheFile,0,NULL,FILE_END) == INVALID_SET_FILE_POINTER)
+ {
+ Trace("ERROR: Could not set the file pointer to the EOF "
+ "using SetFilePointer. It returned INVALID_SET_FILE_POINTER.");
+ result = -1;
+ }
+
+ memset(DataBuffer, 'X', BUF_SIZE);
+
+ /* Return the result of WriteFile -- we want to check in the parent that
+ this was successful. Note: WriteFile doesn't get run if something
+ failed during the setup, in that case -1 is returned.
+ */
+
+ if(result != -1)
+ {
+ result = WriteFile(TheFile, DataBuffer, 3,&BytesWritten, NULL);
+ }
+
+ PAL_TerminateEx(result);
+ return result;
+}
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/LockFile/test6/test6.c b/src/pal/tests/palsuite/filemapping_memmgt/LockFile/test6/test6.c
new file mode 100644
index 0000000000..ba01b9710a
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/LockFile/test6/test6.c
@@ -0,0 +1,146 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: test6.c
+**
+** Purpose:
+** Append to a file which is locked until the end of the file, and
+** append to a file which is locked past the end of the file. (The first
+** should succeed, while the second should fail)
+**
+**
+**============================================================*/
+
+#include <palsuite.h>
+#include "../LockFile.h"
+
+#define HELPER "helper"
+#define FILENAME "testfile.txt"
+
+/* This test checks that you can append to a file which is locked from Start
+ to EOF.
+*/
+void Test1()
+{
+ HANDLE TheFile = NULL;
+ DWORD FileStart = 0;
+ DWORD FileEnd = 0;
+ int result;
+ char* WriteBuffer = "12345678901234567890123456";
+
+ /* Call the helper function to Create a file, write 'WriteBuffer' to
+ the file, and lock the file.
+ */
+
+ FileEnd = strlen(WriteBuffer);
+ TheFile = CreateAndLockFile(TheFile,FILENAME, WriteBuffer,
+ FileStart, FileEnd);
+
+
+ /*
+ Launch another proccess which will attempt to append to the
+ end of the file. Note: This returns -1 if the setup failed in some way.
+ */
+
+ result = RunHelper(HELPER);
+
+ if(result == -1)
+ {
+ Fail("ERROR: The Helper program failed in setting up the "
+ "test, so it could never be run.");
+ }
+ else if(result == 0)
+ {
+ Fail("ERROR: Failed to append to the file which was Locked from "
+ "start until EOF. Should have been able to append to this "
+ "file still. GetLastError() is %d.",GetLastError());
+ }
+
+ if(UnlockFile(TheFile, FileStart, 0, FileEnd, 0) == 0)
+ {
+ Fail("ERROR: UnlockFile failed. GetLastError returns %d.",
+ GetLastError());
+ }
+
+ if(CloseHandle(TheFile) == 0)
+ {
+ Fail("ERROR: CloseHandle failed to close the file. "
+ "GetLastError() returned %d.",GetLastError());
+ }
+
+}
+
+/* This test checks that you can't append to a file which is locked beyond
+ EOF.
+*/
+void Test2()
+{
+ HANDLE TheFile = NULL;
+ DWORD FileStart = 0;
+ DWORD FileEnd = 0;
+ int result;
+ char* WriteBuffer = "12345678901234567890123456";
+
+ /* Call the helper function to Create a file, write 'WriteBuffer' to
+ the file, and lock the file.
+ */
+
+ FileEnd = strlen(WriteBuffer);
+ TheFile = CreateAndLockFile(TheFile,FILENAME, WriteBuffer,
+ FileStart, FileEnd+20);
+
+
+ /*
+ Launch another proccess which will attempt to append to the
+ end of the file.
+ */
+
+ result = RunHelper(HELPER);
+
+ if(result == -1)
+ {
+ Fail("ERROR: The Helper program failed in setting up the "
+ "test, so it could never be run.");
+ }
+ else if(result > 0)
+ {
+ Fail("ERROR: The Helper program successfully appended to the "
+ "end of the file, even though it was locked beyond EOF. This "
+ "should have failed.");
+ }
+
+ if(UnlockFile(TheFile, FileStart, 0, FileEnd+20, 0) == 0)
+ {
+ Fail("ERROR: UnlockFile failed. GetLastError returns %d.",
+ GetLastError());
+ }
+
+ if(CloseHandle(TheFile) == 0)
+ {
+ Fail("ERROR: CloseHandle failed to close the file. "
+ "GetLastError() returned %d.",GetLastError());
+ }
+
+}
+
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /* Test a file which is locked until EOF to see if you can append */
+ Test1();
+
+ /* Test a file which is locked past EOF to ensure you can't append */
+ Test2();
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/LockFile/test6/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/LockFile/test6/testinfo.dat
new file mode 100644
index 0000000000..871a9a2756
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/LockFile/test6/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = LockFile
+Name = Positive test for LockFile API
+TYPE = DEFAULT
+EXE1 = test6
+EXE2 = helper
+Description
+= Append to a file which is locked until the end of the file, and
+= append to a file which is locked past the end of the file. (The first
+= should succeed, while the second should fail)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/LockFile/test7/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/LockFile/test7/CMakeLists.txt
new file mode 100644
index 0000000000..e8434cc787
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/LockFile/test7/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test7.c
+)
+
+add_executable(paltest_lockfile_test7
+ ${SOURCES}
+)
+
+add_dependencies(paltest_lockfile_test7 coreclrpal)
+
+target_link_libraries(paltest_lockfile_test7
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/LockFile/test7/test7.c b/src/pal/tests/palsuite/filemapping_memmgt/LockFile/test7/test7.c
new file mode 100644
index 0000000000..c572a6e653
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/LockFile/test7/test7.c
@@ -0,0 +1,135 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: test7.c
+**
+** Purpose: Try locking an invalid HANDLE and a NULL Handle.
+**
+**
+**============================================================*/
+
+#include <palsuite.h>
+#include "../LockFile.h"
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ HANDLE TheFile = NULL;
+ DWORD FileEnd = 0;
+ const char lpBuffer[] = "This is a test file.";
+ DWORD bytesWritten;
+ BOOL bRc = TRUE;
+ char fileName[] = "testfile.tmp";
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ TheFile = CreateFile(fileName,
+ GENERIC_READ|GENERIC_WRITE,
+ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ NULL,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if (TheFile == INVALID_HANDLE_VALUE)
+ {
+ Fail("ERROR: Could not open file '%s' with CreateFile. "
+ "GetLastError() returned %d.",fileName,GetLastError());
+ }
+
+ bRc = WriteFile(
+ TheFile, // handle to file
+ lpBuffer, // data buffer
+ (DWORD)sizeof(lpBuffer), // number of bytes to write
+ &bytesWritten, // number of bytes written
+ NULL // overlapped buffer
+ );
+
+ if(!bRc)
+ {
+ Trace("ERROR: Could not write to file '%s' with WriteFile.",fileName);
+
+ if(CloseHandle(TheFile) == 0)
+ {
+ Fail("ERROR: CloseHandle failed to close the file.");
+ }
+ Fail("");
+
+ }
+ else if(bytesWritten != (DWORD)sizeof(lpBuffer))
+ {
+ Trace("ERROR: Could not write the correct number of bytes to the "
+ "file '%s' with WriteFile.",fileName);
+
+ if(CloseHandle(TheFile) == 0)
+ {
+ Fail("ERROR: CloseHandle failed to close the file.");
+ }
+ Fail("");
+ }
+
+ /* Attempt to lock a region of this file beyond EOF, to ensure this
+ doesn't cause an error.
+ */
+ FileEnd = SetFilePointer(TheFile, 0, NULL, FILE_END);
+
+ if(LockFile(TheFile, FileEnd+10, 0, 10, 0) == 0)
+ {
+ Trace("ERROR: LockFile failed when attempting to lock a region "
+ "beyond the EOF. GetLastError() returned %d.",GetLastError());
+
+ if(CloseHandle(TheFile) == 0)
+ {
+ Fail("ERROR: CloseHandle failed to close the file.");
+ }
+ Fail("");
+ }
+
+ if(UnlockFile(TheFile, FileEnd+10, 0, 10, 0) == 0)
+ {
+ Trace("ERROR: UnlockFile failed when attempting to unlock the region "
+ "which was locked beyond the EOF. GetLastError returned %d.",
+ GetLastError());
+
+ if(CloseHandle(TheFile) == 0)
+ {
+ Fail("ERROR: CloseHandle failed to close the file.");
+ }
+ Fail("");
+ }
+
+ if(CloseHandle(TheFile) == 0)
+ {
+ Fail("ERROR: Failed to call CloseHandle. GetLastError "
+ "returned %d.",GetLastError());
+ }
+
+ /* Attempt to call Lockfile on an HANDLE which has been closed. This
+ should fail.
+ */
+ if(LockFile(TheFile, 0, 0, 5, 0) != 0)
+ {
+ Fail("ERROR: Attempted to Lock an invalid handle and the function "
+ "returned success.");
+ }
+
+ /* Attempt to call Lockfile by passing it NULL for a handle. This should
+ fail.
+ */
+
+ if(LockFile(NULL, 0, 0, 5, 0) != 0)
+ {
+ Fail("ERROR: Attempted to Lock a NULL handle and the function "
+ "returned success.");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/LockFile/test7/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/LockFile/test7/testinfo.dat
new file mode 100644
index 0000000000..74e7f00306
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/LockFile/test7/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = LockFile
+Name = Positive test for LockFile API
+TYPE = DEFAULT
+EXE1 = test7
+Description
+= Ensure that LockFile succeeds when the lock begins beyond
+= EOF. Try locking an invalid HANDLE and a NULL Handle.
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/MapViewOfFile/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/MapViewOfFile/CMakeLists.txt
new file mode 100644
index 0000000000..7c20179353
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/MapViewOfFile/CMakeLists.txt
@@ -0,0 +1,9 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+add_subdirectory(test3)
+add_subdirectory(test4)
+add_subdirectory(test5)
+add_subdirectory(test6)
+
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/MapViewOfFile/test1/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/MapViewOfFile/test1/CMakeLists.txt
new file mode 100644
index 0000000000..ef9838d41e
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/MapViewOfFile/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ MapViewOfFile.c
+)
+
+add_executable(paltest_mapviewoffile_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_mapviewoffile_test1 coreclrpal)
+
+target_link_libraries(paltest_mapviewoffile_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/MapViewOfFile/test1/MapViewOfFile.c b/src/pal/tests/palsuite/filemapping_memmgt/MapViewOfFile/test1/MapViewOfFile.c
new file mode 100644
index 0000000000..6177e0decf
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/MapViewOfFile/test1/MapViewOfFile.c
@@ -0,0 +1,226 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: MapViewOfFile.c
+**
+**
+** Purpose: Positive test the MapViewOfFile API.
+** Call MapViewOfFile with access FILE_MAP_READ.
+**
+**
+**============================================================*/
+#include <palsuite.h>
+#define MAPPINGSIZE 8192
+int __cdecl main(int argc, char *argv[])
+{
+
+ HANDLE hFile = INVALID_HANDLE_VALUE;
+ LPSTR buf = NULL;
+ CHAR ch[MAPPINGSIZE];
+ CHAR lpFileName[] = "test.tmp";
+ DWORD dwBytesWritten = 0;
+ DWORD dwInitialSize = 0;
+ DWORD dwFinalSize = 0;
+ BOOL bRetVal = FALSE;
+
+ HANDLE hFileMapping = 0;
+ LPVOID lpMapViewAddress = NULL;
+
+ /* Initialize the PAL environment.
+ */
+ if( 0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ /* Create a file handle with CreateFile.
+ */
+ hFile = CreateFile( lpFileName,
+ GENERIC_WRITE|GENERIC_READ,
+ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ NULL,
+ OPEN_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING,
+ NULL);
+
+ if (hFile == INVALID_HANDLE_VALUE)
+ {
+ Fail( "ERROR: %u :unable to create file \"%s\".\n",
+ GetLastError(), lpFileName);
+ }
+
+ /* Get the initial size of file, for latter tests.
+ */
+ dwInitialSize = GetFileSize (hFile, NULL);
+ if ( INVALID_FILE_SIZE == dwInitialSize )
+ {
+ Fail("ERROR:%u: The created file \"%s\" has an invalid "
+ "file size.\n",GetLastError(),lpFileName);
+ }
+
+ /*
+ * An application must meet certain requirements when working
+ * with files opened with FILE_FLAG_NO_BUFFERING:
+ * File access must begin at byte offsets within the file that
+ * are integer multiples of the volume's sector size. To determine a
+ * volume's sector size, call the GetDiskFreeSpace function.
+ *
+ * File access must be for numbers of bytes that are integer
+ * multiples of the volume's sector size. For example, if the
+ * sector size is 512 bytes, an application can request reads and
+ * writes of 512, 1024, or 2048 bytes, but not of 335, 981, or 7171 bytes.
+ *
+ * Buffer addresses for read and write operations must be sector
+ * aligned (aligned on addresses in memory that are integer multiples
+ * of the volume's sector size). One way to sector align buffers is to use the
+ * VirtualAlloc function to allocate the buffers. This function allocates memory
+ * that is aligned on addresses that are integer multiples of the system's page size.
+ * Because both page and volume sector sizes are powers of 2, memory aligned by multiples
+ * of the system's page size is also aligned by multiples of the volume's sector size.
+ */
+ buf = (LPSTR)VirtualAlloc( NULL, /* Let the system decide the location. */
+ MAPPINGSIZE / 2, /* One page, the smallest you can request */
+ MEM_COMMIT, /* Reserve and commit in one pass */
+ PAGE_READWRITE ); /* Allow reading and writting. */
+
+ if ( NULL == buf )
+ {
+ Trace( "VirtualAlloc failed! LastError=%d\n", GetLastError() );
+ CloseHandle( hFile );
+ Fail("");
+ }
+
+
+ /*
+ * Write to the File handle.
+ * The reminder will be padded with zeros.
+ */
+ strncpy( buf,
+ "thats not a test string....THIS is a test string",
+ MAPPINGSIZE / 2 );
+
+ bRetVal = WriteFile(hFile,
+ buf,
+ MAPPINGSIZE / 2,
+ &dwBytesWritten,
+ NULL);
+
+ if ( FALSE == bRetVal )
+ {
+ Trace( "ERROR: %u :unable to write to file handle hFile=0x%lx\n",
+ GetLastError(), hFile);
+ CloseHandle(hFile);
+ VirtualFree( buf, 0, MEM_RELEASE );
+ Fail("");
+ }
+
+ /* Create a unnamed file-mapping object with file handle FileHandle
+ * and with PAGE_READWRITE protection.
+ */
+ hFileMapping = CreateFileMapping( hFile,
+ NULL, /*not inherited*/
+ PAGE_READWRITE, /*read and wite*/
+ 0, /*high-order of object size*/
+ MAPPINGSIZE, /*low-orger of object size*/
+ NULL); /*unnamed object*/
+
+ if( NULL == hFileMapping )
+ {
+ Trace("ERROR:%u: Failed to create File Mapping.\n", GetLastError());
+ CloseHandle(hFile);
+ VirtualFree( buf, 0, MEM_RELEASE );
+ Fail("");
+ }
+
+ /* maps a view of a file into the address space of the calling process.
+ */
+ lpMapViewAddress = MapViewOfFile( hFileMapping,
+ FILE_MAP_READ, /* access code */
+ 0, /*high order offset*/
+ 0, /*low order offset*/
+ MAPPINGSIZE); /* number of bytes for map */
+
+ if( NULL == lpMapViewAddress )
+ {
+ Trace( "ERROR:%u: Failed to call MapViewOfFile API to map"
+ " a view of file!\n", GetLastError());
+ CloseHandle(hFile);
+ CloseHandle(hFileMapping);
+ VirtualFree( buf, 0, MEM_RELEASE );
+ Fail("");
+ }
+
+ /* Verify that the size of the file has increased to
+ * accomidate the MapView.
+ */
+ dwFinalSize = GetFileSize (hFile, NULL);
+ if ( (dwFinalSize <= dwInitialSize) && (dwFinalSize != MAPPINGSIZE))
+ {
+
+ CloseHandle(hFile);
+ CloseHandle(hFileMapping);
+ VirtualFree( buf, 0, MEM_RELEASE );
+ UnmapViewOfFile(lpMapViewAddress);
+
+ Fail( "ERROR: Size of the file was expected to "
+ "increase from \"%d\", to \"%d\".\n ",
+ dwInitialSize,
+ dwFinalSize);
+ }
+
+ /* Copy the MapViewOfFile to buffer, so we can
+ * compare with value read from file directly.
+ */
+ memcpy(ch, (LPCSTR)lpMapViewAddress, MAPPINGSIZE);
+ if (memcmp(ch, buf, strlen(buf)) != 0)
+ {
+ CloseHandle(hFile);
+ CloseHandle(hFileMapping);
+ UnmapViewOfFile(lpMapViewAddress) ;
+ VirtualFree( buf, 0, MEM_RELEASE );
+
+ Fail( "ERROR: MapViewOfFile not equal to file contents "
+ "retrieved \"%s\", expected \"%s\".\n",
+ ch,
+ buf);
+ }
+
+ /* Unmap the view of file.
+ */
+ if( FALSE == UnmapViewOfFile(lpMapViewAddress) )
+ {
+ Trace( "\nFailed to call UnmapViewOfFile API to unmap the "
+ "view of a file, error code=%u\n", GetLastError());
+ CloseHandle(hFile);
+ CloseHandle(hFileMapping);
+ VirtualFree( buf, 0, MEM_RELEASE );
+ Fail("");
+ }
+
+ /* Close handle to create file.
+ */
+ if( FALSE == CloseHandle(hFile) )
+ {
+ Trace( "ERROR:%u:Failed to call CloseHandle API to close a file handle.",
+ GetLastError());
+ CloseHandle(hFileMapping);
+ VirtualFree( buf, 0, MEM_RELEASE );
+ Fail("");
+ }
+
+ if( FALSE == CloseHandle(hFileMapping) )
+ {
+ Trace( "ERROR:%u:Failed to call CloseHandle API to close a "
+ "filemapping handle.",GetLastError());
+ VirtualFree( buf, 0, MEM_RELEASE );
+ Fail("");
+ }
+
+ VirtualFree( buf, 0, MEM_RELEASE );
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/MapViewOfFile/test1/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/MapViewOfFile/test1/testinfo.dat
new file mode 100644
index 0000000000..f1d8451efb
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/MapViewOfFile/test1/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = MapViewOfFile
+Name = Positive test MapViewOfFile API with access FILE_MAP_READ
+TYPE = DEFAULT
+EXE1 = mapviewoffile
+Description
+=Test the MapViewOfFile with access FILE_MAP_READ
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/MapViewOfFile/test2/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/MapViewOfFile/test2/CMakeLists.txt
new file mode 100644
index 0000000000..18a9d105b1
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/MapViewOfFile/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ MapViewOfFile.c
+)
+
+add_executable(paltest_mapviewoffile_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_mapviewoffile_test2 coreclrpal)
+
+target_link_libraries(paltest_mapviewoffile_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/MapViewOfFile/test2/MapViewOfFile.c b/src/pal/tests/palsuite/filemapping_memmgt/MapViewOfFile/test2/MapViewOfFile.c
new file mode 100644
index 0000000000..c08f585c0e
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/MapViewOfFile/test2/MapViewOfFile.c
@@ -0,0 +1,203 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: MapViewOfFile.c
+**
+** Purpose: Positive test the MapViewOfFile API.
+** Call MapViewOfFile with access FILE_MAP_WRITE.
+**
+** Depends: CreateFile,
+** GetFileSize,
+** memset,
+** CreateFileMapping,
+** CloseHandle,
+** memcpy,
+** ReadFile,
+** memcmp,
+** UnMapViewOfFile.
+**
+**
+**============================================================*/
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ HANDLE hFile;
+ HANDLE hFileMapping;
+ LPVOID lpMapViewAddress;
+ char buf[] = "this is a test string";
+ const int MAPPINGSIZE = 2048;
+ char ch[2048];
+ char readString[2048];
+ char lpFileName[] = "test.tmp";
+ DWORD dwBytesRead;
+ DWORD dwInitialSize = 0;
+ DWORD dwFinalSize = 0;
+ BOOL bRetVal;
+
+ /* Initialize the PAL environment.
+ */
+ if(0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ /* Create a file handle with CreateFile.
+ */
+ hFile = CreateFile( lpFileName,
+ GENERIC_WRITE|GENERIC_READ,
+ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ NULL,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+ if (hFile == INVALID_HANDLE_VALUE)
+ {
+ Fail("ERROR: %u :unable to create file \"%s\".\n",
+ GetLastError(),
+ lpFileName);
+ }
+
+ /* Get the initial size of file, for latter tests.
+ */
+ dwInitialSize = GetFileSize (hFile, NULL);
+ if ( dwInitialSize == INVALID_FILE_SIZE )
+ {
+ Fail("ERROR:%u: The created file \"%s\" has an invalid "
+ "file size.\n",
+ GetLastError(),
+ lpFileName);
+ }
+
+ /* Initialize the buffers.
+ */
+ memset(ch, 0, MAPPINGSIZE);
+ memset(readString, 0, MAPPINGSIZE);
+
+ /* Create a unnamed file-mapping object with file handle FileHandle
+ * and with PAGE_READWRITE protection.
+ */
+ hFileMapping = CreateFileMapping(
+ hFile,
+ NULL, /*not inherited*/
+ PAGE_READWRITE, /*read and wite*/
+ 0, /*high-order of object size*/
+ MAPPINGSIZE, /*low-orger of object size*/
+ NULL); /*unnamed object*/
+
+ if(NULL == hFileMapping)
+ {
+ Trace("ERROR:%u: Failed to create File Mapping.\n",
+ GetLastError());
+ CloseHandle(hFile);
+ Fail("");
+ }
+
+ /* maps a view of a file into the address space of the calling process.
+ */
+ lpMapViewAddress = MapViewOfFile(
+ hFileMapping,
+ FILE_MAP_WRITE, /* access code */
+ 0, /*high order offset*/
+ 0, /*low order offset*/
+ MAPPINGSIZE); /* number of bytes for map */
+
+ if(NULL == lpMapViewAddress)
+ {
+ Trace("ERROR:%u: Failed to call MapViewOfFile API to map a view"
+ " of file!\n",
+ GetLastError());
+ CloseHandle(hFile);
+ CloseHandle(hFileMapping);
+ Fail("");
+ }
+
+ /* Verify that the size of the file has increased to
+ * accomidate the MapView.
+ */
+ dwFinalSize = GetFileSize (hFile, NULL);
+ if ( (dwFinalSize <= dwInitialSize) && (dwFinalSize != MAPPINGSIZE))
+ {
+ CloseHandle(hFile);
+ CloseHandle(hFileMapping);
+ Fail("ERROR: Size of the file was expected to "
+ "increase from \"%d\", to \"%d\".\n ",
+ dwInitialSize,
+ MAPPINGSIZE);
+ }
+
+ /* Write to the MapView and copy the MapViewOfFile
+ * to buffer, so we can compare with value read from
+ * file directly.
+ */
+ memcpy(lpMapViewAddress, buf, strlen(buf));
+
+ /* Read from the File handle.
+ */
+ bRetVal = ReadFile(hFile,
+ readString,
+ strlen(buf),
+ &dwBytesRead,
+ NULL);
+
+ if (bRetVal == FALSE)
+ {
+ Trace("ERROR: %u :unable to read from file handle "
+ "hFile=0x%lx\n",
+ GetLastError(),
+ hFile);
+ CloseHandle(hFile);
+ CloseHandle(hFileMapping);
+ Fail("");
+ }
+
+ if (memcmp(buf, readString, strlen(readString)) != 0)
+ {
+ CloseHandle(hFile);
+ CloseHandle(hFileMapping);
+ Fail("ERROR: Read string from file \"%s\", is "
+ "not equal to string written through MapView "
+ "\"%s\".\n",
+ readString,
+ ch);
+ }
+
+ /* Unmap the view of file.
+ */
+ if(UnmapViewOfFile(lpMapViewAddress) == FALSE)
+ {
+ Trace("ERROR: Failed to call UnmapViewOfFile API to"
+ " unmap the view of a file, error code=%u\n",
+ GetLastError());
+ CloseHandle(hFile);
+ CloseHandle(hFileMapping);
+ Fail("");
+ }
+
+ /* Close handle to create file.
+ */
+ if(CloseHandle(hFile) == FALSE)
+ {
+ Trace("ERROR:%u:Failed to call CloseHandle API "
+ "to close a file handle.",
+ GetLastError());
+ CloseHandle(hFileMapping);
+ Fail("");
+ }
+
+ if(CloseHandle(hFileMapping) == FALSE)
+ {
+ Fail("ERROR:%u:Failed to call CloseHandle API "
+ "to close a file mapping handle.",
+ GetLastError());
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/MapViewOfFile/test2/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/MapViewOfFile/test2/testinfo.dat
new file mode 100644
index 0000000000..13b3f52cf1
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/MapViewOfFile/test2/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = MapViewOfFile
+Name = Positive test for MapViewOfFile API with access FILE_MAP_WRITE
+TYPE = DEFAULT
+EXE1 = mapviewoffile
+Description
+=Test the MapViewOfFile with access FILE_MAP_WRITE
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/MapViewOfFile/test3/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/MapViewOfFile/test3/CMakeLists.txt
new file mode 100644
index 0000000000..76bd3276a4
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/MapViewOfFile/test3/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ MapViewOfFile.c
+)
+
+add_executable(paltest_mapviewoffile_test3
+ ${SOURCES}
+)
+
+add_dependencies(paltest_mapviewoffile_test3 coreclrpal)
+
+target_link_libraries(paltest_mapviewoffile_test3
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/MapViewOfFile/test3/MapViewOfFile.c b/src/pal/tests/palsuite/filemapping_memmgt/MapViewOfFile/test3/MapViewOfFile.c
new file mode 100644
index 0000000000..63bee768f9
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/MapViewOfFile/test3/MapViewOfFile.c
@@ -0,0 +1,209 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: MapViewOfFile.c
+**
+** Purpose: Positive test the MapViewOfFile API.
+** Call MapViewOfFile with access FILE_MAP_ALL_ACCESS.
+**
+** Depends: CreateFile,
+** GetFileSize,
+** memset,
+** memcpy,
+** memcmp,
+** ReadFile,
+** UnMapViewOfFile,
+** CreateFileMapping,
+** CloseHandle.
+**
+**
+**============================================================*/
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ HANDLE hFile;
+ HANDLE hFileMapping;
+ LPVOID lpMapViewAddress;
+ char buf[] = "this is a test string";
+ const int MAPPINGSIZE = 2048;
+ char ch[2048];
+ char readString[2048];
+ char lpFileName[] = "test.tmp";
+ DWORD dwBytesRead;
+ DWORD dwInitialSize = 0;
+ DWORD dwFinalSize = 0;
+ BOOL bRetVal;
+
+ /* Initialize the PAL environment.
+ */
+ if(0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ /* Create a file handle with CreateFile.
+ */
+ hFile = CreateFile( lpFileName,
+ GENERIC_WRITE|GENERIC_READ,
+ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ NULL,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+ if (hFile == INVALID_HANDLE_VALUE)
+ {
+ Fail("ERROR: %u :unable to create file \"%s\".\n",
+ GetLastError(),
+ lpFileName);
+ }
+
+ /* Get the initial size of file, for latter tests.
+ */
+ dwInitialSize = GetFileSize (hFile, NULL);
+ if ( dwInitialSize == INVALID_FILE_SIZE )
+ {
+ Trace("ERROR:%u: The created file \"%s\" has an invalid "
+ "file size.\n",
+ GetLastError(),
+ lpFileName);
+ CloseHandle(hFile);
+ Fail("");
+ }
+
+ /* Initialize the buffers.
+ */
+ memset(ch, 0, MAPPINGSIZE);
+ memset(readString, 0, MAPPINGSIZE);
+
+ /* Create a unnamed file-mapping object with file handle FileHandle
+ * and with PAGE_READWRITE protection.
+ */
+ hFileMapping = CreateFileMapping(
+ hFile,
+ NULL, /*not inherited*/
+ PAGE_READWRITE, /*read and wite*/
+ 0, /*high-order of object size*/
+ MAPPINGSIZE, /*low-orger of object size*/
+ NULL); /*unnamed object*/
+
+ if(NULL == hFileMapping)
+ {
+ Trace("ERROR:%u: Failed to create File Mapping.\n",
+ GetLastError());
+ CloseHandle(hFile);
+ Fail("");
+ }
+
+ /* maps a view of a file into the address space of the calling process.
+ */
+ lpMapViewAddress = MapViewOfFile(
+ hFileMapping,
+ FILE_MAP_ALL_ACCESS, /*access code*/
+ 0, /*high order offset*/
+ 0, /*low order offset*/
+ MAPPINGSIZE); /* number of bytes for map */
+
+ if(NULL == lpMapViewAddress)
+ {
+ Trace("ERROR:%u: Failed to call MapViewOfFile API to map a view"
+ " of file!\n",
+ GetLastError());
+ CloseHandle(hFile);
+ CloseHandle(hFileMapping);
+ Fail("");
+ }
+
+ /* Verify that the size of the file has increased to
+ * accomidate the MapView.
+ */
+ dwFinalSize = GetFileSize (hFile, NULL);
+ if ( (dwFinalSize <= dwInitialSize) && (dwFinalSize != MAPPINGSIZE))
+ {
+ CloseHandle(hFile);
+ CloseHandle(hFileMapping);
+ Fail("ERROR: Size of the file was expected to "
+ "increase from \"%d\", to \"%d\".\n ",
+ dwInitialSize,
+ MAPPINGSIZE);
+ }
+
+ /* Write to the MapView and copy the MapViewOfFile
+ * to buffer, so we can compare with value read from
+ * file directly.
+ */
+
+ memcpy(lpMapViewAddress, buf, strlen(buf));
+ memcpy(ch, (LPCSTR)lpMapViewAddress, MAPPINGSIZE);
+
+ /* Read from the File handle.
+ */
+ bRetVal = ReadFile(hFile,
+ readString,
+ strlen(buf),
+ &dwBytesRead,
+ NULL);
+
+ if (bRetVal == FALSE)
+ {
+ Trace("ERROR: %u :unable to read from file handle "
+ "hFile=0x%lx\n",
+ GetLastError(),
+ hFile);
+ CloseHandle(hFile);
+ CloseHandle(hFileMapping);
+ Fail("");
+ }
+
+ if (memcmp(ch, readString, strlen(readString)) != 0)
+ {
+ CloseHandle(hFile);
+ CloseHandle(hFileMapping);
+ Fail("ERROR: Read string from file \"%s\", is "
+ "not equal to string written through MapView "
+ "\"%s\".\n",
+ readString,
+ ch);
+ }
+
+ /* Unmap the view of file.
+ */
+ if(UnmapViewOfFile(lpMapViewAddress) == FALSE)
+ {
+ Trace("ERROR: Failed to call UnmapViewOfFile API to"
+ " unmap the view of a file, error code=%u\n",
+ GetLastError());
+ CloseHandle(hFile);
+ CloseHandle(hFileMapping);
+ Fail("");
+ }
+
+ /* Close handle to create file.
+ */
+ if(CloseHandle(hFile) == FALSE)
+ {
+ Trace("ERROR:%u:Failed to call CloseHandle API "
+ "to close a file handle.",
+ GetLastError());
+ CloseHandle(hFileMapping);
+ Fail("");
+ }
+
+ /* Close handle to file mapping.
+ */
+ if(CloseHandle(hFileMapping) == FALSE)
+ {
+ Fail("ERROR:%u:Failed to call CloseHandle API "
+ "to close a file handle.",
+ GetLastError());
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/MapViewOfFile/test3/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/MapViewOfFile/test3/testinfo.dat
new file mode 100644
index 0000000000..f76333e7ea
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/MapViewOfFile/test3/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = MapViewOfFile
+Name = Positive test MapViewOfFile API with access FILE_MAP_ALL_ACCESS
+TYPE = DEFAULT
+EXE1 = mapviewoffile
+Description
+=Test the MapViewOfFile with access FILE_MAP_ALL_ACCESS
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/MapViewOfFile/test4/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/MapViewOfFile/test4/CMakeLists.txt
new file mode 100644
index 0000000000..52381c510f
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/MapViewOfFile/test4/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ mapviewoffile.c
+)
+
+add_executable(paltest_mapviewoffile_test4
+ ${SOURCES}
+)
+
+add_dependencies(paltest_mapviewoffile_test4 coreclrpal)
+
+target_link_libraries(paltest_mapviewoffile_test4
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/MapViewOfFile/test4/mapviewoffile.c b/src/pal/tests/palsuite/filemapping_memmgt/MapViewOfFile/test4/mapviewoffile.c
new file mode 100644
index 0000000000..7f3252144b
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/MapViewOfFile/test4/mapviewoffile.c
@@ -0,0 +1,166 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: MapViewOfFile.c
+**
+** Purpose: Negative test the MapViewOfFile API.
+** Call MapViewOfFile with all access modes, except
+** read-only, on a read only map.
+**
+** Depends: CreateFile,
+** CreateFileMapping,
+** CloseHandle,
+** UnMapViewOfFile.
+**
+
+**
+**============================================================*/
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ HANDLE hFile;
+ BOOL err;
+ HANDLE hFileMapping;
+ LPVOID lpMapViewAddress;
+ DWORD dwBytesWritten;
+ const int MAPPINGSIZE = 2048;
+ char buf[] = "this is a test string";
+ char lpFileName[] = "test.tmp";
+
+ /* Initialize the PAL environment.
+ */
+ if(0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ /* Create a file handle with CreateFile.
+ */
+ hFile = CreateFile( lpFileName,
+ GENERIC_WRITE|GENERIC_READ,
+ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ NULL,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+ if (hFile == INVALID_HANDLE_VALUE)
+ {
+ Fail("ERROR: %u :unable to create file \"%s\".\n",
+ GetLastError(),
+ lpFileName);
+ }
+
+ /* Write to the File handle.
+ */
+ err = WriteFile(hFile,
+ buf,
+ strlen(buf),
+ &dwBytesWritten,
+ NULL);
+
+ if ( !FlushFileBuffers( hFile ) )
+ {
+ CloseHandle(hFile);
+ Fail("ERROR: Unable to flush the buffers\n");
+ }
+
+ if (err == FALSE)
+ {
+ Trace("ERROR: %u :unable to write to file handle "
+ "hFile=0x%lx\n",
+ GetLastError(),
+ hFile);
+ CloseHandle(hFile);
+ Fail("");
+ }
+
+ /* Create a unnamed file-mapping object with file handle FileHandle
+ * and with PAGE_READWRITE protection.
+ */
+ hFileMapping = CreateFileMapping(
+ hFile,
+ NULL, /*not inherited*/
+ PAGE_READONLY, /*read and wite*/
+ 0, /*high-order of object size*/
+ 0, /*low-orger of object size*/
+ NULL); /*unnamed object*/
+
+ if(NULL == hFileMapping)
+ {
+ Trace("ERROR:%u: Failed to create File Mapping.\n",
+ GetLastError());
+ CloseHandle(hFile);
+ Fail("");
+ }
+
+ /* map a writeable view of a file to a read-only file map.
+ */
+ lpMapViewAddress = MapViewOfFile(
+ hFileMapping,
+ FILE_MAP_WRITE, /* access code */
+ 0, /* high order offset */
+ 0, /* low order offset */
+ MAPPINGSIZE); /* number of bytes for map */
+
+ if(NULL != lpMapViewAddress)
+ {
+ Trace("ERROR:%u: Able to create a writeable MapViewOfFile"
+ " to a read-only file.\n",
+ GetLastError());
+ CloseHandle(hFile);
+ CloseHandle(hFileMapping);
+ UnmapViewOfFile(lpMapViewAddress);
+ Fail("");
+ }
+
+ /* map an all access view of a file to a read-only file map.
+ */
+ lpMapViewAddress = MapViewOfFile(
+ hFileMapping,
+ FILE_MAP_ALL_ACCESS, /* access code */
+ 0, /* high order offset */
+ 0, /* low order offset */
+ MAPPINGSIZE); /* number of bytes for map */
+
+ if(NULL != lpMapViewAddress)
+ {
+ Trace("ERROR:%u: Able to create an all access MapViewOfFile"
+ " to a read-only file.\n",
+ GetLastError());
+ CloseHandle(hFile);
+ CloseHandle(hFileMapping);
+ UnmapViewOfFile(lpMapViewAddress);
+ Fail("");
+ }
+
+ /* map an copy view of a file to a read-only file map.
+ */
+ lpMapViewAddress = MapViewOfFile(
+ hFileMapping,
+ FILE_MAP_COPY, /* access code */
+ 0, /* high order offset */
+ 0, /* low order offset */
+ MAPPINGSIZE); /* number of bytes for map */
+
+ if(NULL != lpMapViewAddress)
+ {
+ Trace("ERROR:%u: Able to create a copy access MapViewOfFile "
+ "to a read-only file.\n",
+ GetLastError());
+ CloseHandle(hFile);
+ CloseHandle(hFileMapping);
+ Fail("");
+ }
+
+ /* Clean-up and Teminate. */
+ CloseHandle(hFile);
+ CloseHandle(hFileMapping);
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/MapViewOfFile/test4/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/MapViewOfFile/test4/testinfo.dat
new file mode 100644
index 0000000000..37655eda5b
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/MapViewOfFile/test4/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = MapViewOfFile
+Name = Negative test MapViewOfFile API
+TYPE = DEFAULT
+EXE1 = mapviewoffile
+Description
+= Negative test the MapViewOfFile API.
+= Call MapViewOfFile with all access modes,
+= except read-only, on a read only map.
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/MapViewOfFile/test5/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/MapViewOfFile/test5/CMakeLists.txt
new file mode 100644
index 0000000000..f98a4b7779
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/MapViewOfFile/test5/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ mapviewoffile.c
+)
+
+add_executable(paltest_mapviewoffile_test5
+ ${SOURCES}
+)
+
+add_dependencies(paltest_mapviewoffile_test5 coreclrpal)
+
+target_link_libraries(paltest_mapviewoffile_test5
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/MapViewOfFile/test5/mapviewoffile.c b/src/pal/tests/palsuite/filemapping_memmgt/MapViewOfFile/test5/mapviewoffile.c
new file mode 100644
index 0000000000..219b3fa12a
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/MapViewOfFile/test5/mapviewoffile.c
@@ -0,0 +1,131 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: MapViewOfFile.c
+**
+** Purpose: Negative test the MapViewOfFile API.
+** Passing invalid values for the hFileMappingObject.
+**
+** Depends: CreatePipe,
+** CreateFile,
+** CreateFileMapping,
+** CloseHandle.
+**
+
+**
+**============================================================*/
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ const int MAPPINGSIZE = 2048;
+ HANDLE hFileMapping;
+ LPVOID lpMapViewAddress;
+ HANDLE hReadPipe = NULL;
+ HANDLE hWritePipe = NULL;
+ BOOL bRetVal;
+
+ SECURITY_ATTRIBUTES lpPipeAttributes;
+
+ /* Initialize the PAL environment.
+ */
+ if(0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ /* Attempt to create a MapViewOfFile with a NULL handle.
+ */
+ hFileMapping = NULL;
+
+ lpMapViewAddress = MapViewOfFile(
+ hFileMapping,
+ FILE_MAP_WRITE, /* access code */
+ 0, /* high order offset */
+ 0, /* low order offset */
+ MAPPINGSIZE); /* number of bytes for map */
+
+ if((NULL != lpMapViewAddress) &&
+ (GetLastError() != ERROR_INVALID_HANDLE))
+ {
+ Trace("ERROR:%u: Able to create a MapViewOfFile with "
+ "hFileMapping=0x%lx.\n",
+ GetLastError());
+ UnmapViewOfFile(lpMapViewAddress);
+ Fail("");
+ }
+
+ /* Attempt to create a MapViewOfFile with an invalid handle.
+ */
+ hFileMapping = INVALID_HANDLE_VALUE;
+
+ lpMapViewAddress = MapViewOfFile(
+ hFileMapping,
+ FILE_MAP_WRITE, /* access code */
+ 0, /* high order offset */
+ 0, /* low order offset */
+ MAPPINGSIZE); /* number of bytes for map */
+
+ if((NULL != lpMapViewAddress) &&
+ (GetLastError() != ERROR_INVALID_HANDLE))
+ {
+ Trace("ERROR:%u: Able to create a MapViewOfFile with "
+ "hFileMapping=0x%lx.\n",
+ GetLastError());
+ UnmapViewOfFile(lpMapViewAddress);
+ Fail("");
+ }
+
+ /* Setup SECURITY_ATTRIBUTES structure for CreatePipe.
+ */
+ lpPipeAttributes.nLength = sizeof(lpPipeAttributes);
+ lpPipeAttributes.lpSecurityDescriptor = NULL;
+ lpPipeAttributes.bInheritHandle = TRUE;
+
+ /* Create a Pipe.
+ */
+ bRetVal = CreatePipe(&hReadPipe, /* read handle*/
+ &hWritePipe, /* write handle */
+ &lpPipeAttributes,/* security attributes*/
+ 0); /* pipe size*/
+ if (bRetVal == FALSE)
+ {
+ Fail("ERROR: %ld :Unable to create pipe\n",
+ GetLastError());
+ }
+
+ /* Attempt creating a MapViewOfFile with a Pipe Handle.
+ */
+ lpMapViewAddress = MapViewOfFile(
+ hReadPipe,
+ FILE_MAP_WRITE, /* access code */
+ 0, /* high order offset */
+ 0, /* low order offset */
+ MAPPINGSIZE); /* number of bytes for map */
+
+ if((NULL != lpMapViewAddress) &&
+ (GetLastError() != ERROR_INVALID_HANDLE))
+ {
+ Trace("ERROR:%u: Able to create a MapViewOfFile with "
+ "hFileMapping=0x%lx.\n",
+ GetLastError());
+ CloseHandle(hReadPipe);
+ CloseHandle(hWritePipe);
+ UnmapViewOfFile(lpMapViewAddress);
+ Fail("");
+ }
+
+ /* Clean-up and Terminate the PAL.
+ */
+ CloseHandle(hReadPipe);
+ CloseHandle(hWritePipe);
+ PAL_Terminate();
+ return PASS;
+}
+
+
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/MapViewOfFile/test5/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/MapViewOfFile/test5/testinfo.dat
new file mode 100644
index 0000000000..e3ecb32772
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/MapViewOfFile/test5/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = MapViewOfFile
+Name = Negative test for MapViewOfFile API.
+TYPE = DEFAULT
+EXE1 = mapviewoffile
+Description
+= Negative test the MapViewOfFile API.
+= Passing invalid values for the hFileMappingObject.
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/MapViewOfFile/test6/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/MapViewOfFile/test6/CMakeLists.txt
new file mode 100644
index 0000000000..dad03aaf80
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/MapViewOfFile/test6/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ mapviewoffile.c
+)
+
+add_executable(paltest_mapviewoffile_test6
+ ${SOURCES}
+)
+
+add_dependencies(paltest_mapviewoffile_test6 coreclrpal)
+
+target_link_libraries(paltest_mapviewoffile_test6
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/MapViewOfFile/test6/mapviewoffile.c b/src/pal/tests/palsuite/filemapping_memmgt/MapViewOfFile/test6/mapviewoffile.c
new file mode 100644
index 0000000000..f7d7302a4c
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/MapViewOfFile/test6/mapviewoffile.c
@@ -0,0 +1,85 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: MapViewOfFile.c
+**
+** Purpose: Positivve test the MapViewOfFile API.
+** Mapping a pagefile allocation into memory
+**
+** Depends: CreateFileMappingW,
+** UnmapViewOfFile
+** CloseHandle.
+**
+
+**
+**============================================================*/
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ const int MAPPINGSIZE = 2048;
+ HANDLE hFileMapping;
+ LPVOID lpMapViewAddress;
+ char *p;
+ int i;
+
+ /* Initialize the PAL environment.
+ */
+ if(0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ hFileMapping = CreateFileMappingW(INVALID_HANDLE_VALUE,
+ NULL,
+ PAGE_READWRITE,
+ 0,
+ MAPPINGSIZE,
+ NULL);
+
+ if (hFileMapping == NULL) {
+ Trace("ERROR:%u: CreateFileMappingW() failed\n", GetLastError());
+ Fail("");
+ }
+
+
+ lpMapViewAddress = MapViewOfFile(
+ hFileMapping,
+ FILE_MAP_WRITE, /* access code */
+ 0, /* high order offset */
+ 0, /* low order offset */
+ MAPPINGSIZE); /* number of bytes for map */
+
+ if(NULL == lpMapViewAddress)
+ {
+ Trace("ERROR:%u: MapViewOfFile() failed.\n",
+ GetLastError());
+ CloseHandle(hFileMapping);
+ Fail("");
+ }
+
+ p = (char *)lpMapViewAddress;
+ for (i=0; i<MAPPINGSIZE; ++i) {
+ /* Confirm that the memory is zero-initialized */
+ if (p[i] != 0)
+ {
+ Fail("MapViewOfFile() of pagefile didn't return 0-filled data "
+ "(Offset %d has value 0x%x)\n", i, p[i]);
+ }
+ /* Confirm that it is writable */
+ *(char *)lpMapViewAddress = 0xcc;
+ }
+
+ /* Clean-up and Terminate the PAL.
+ */
+ CloseHandle(hFileMapping);
+ UnmapViewOfFile(lpMapViewAddress);
+ PAL_Terminate();
+ return PASS;
+}
+
+
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/MapViewOfFile/test6/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/MapViewOfFile/test6/testinfo.dat
new file mode 100644
index 0000000000..020827d2fe
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/MapViewOfFile/test6/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = MapViewOfFile
+Name = Positive test for MapViewOfFile API.
+TYPE = DEFAULT
+EXE1 = mapviewoffile
+Description
+= Positive test the MapViewOfFile API.
+= Mapping in a section of anonymous pagefile
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingA/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingA/CMakeLists.txt
new file mode 100644
index 0000000000..1962ade358
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingA/CMakeLists.txt
@@ -0,0 +1,6 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+add_subdirectory(test3)
+
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingA/test1/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingA/test1/CMakeLists.txt
new file mode 100644
index 0000000000..b286924864
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingA/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ OpenFileMappingA.c
+)
+
+add_executable(paltest_openfilemappinga_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_openfilemappinga_test1 coreclrpal)
+
+target_link_libraries(paltest_openfilemappinga_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingA/test1/OpenFileMappingA.c b/src/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingA/test1/OpenFileMappingA.c
new file mode 100644
index 0000000000..9087285112
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingA/test1/OpenFileMappingA.c
@@ -0,0 +1,157 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: openfilemappinga.c (test 1)
+**
+** Purpose: Positive test the OpenFileMapping API.
+** Call OpenFileMapping to open a named file-mapping
+** object with FILE_MAP_ALL_ACCESS access
+**
+**
+**============================================================*/
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ HANDLE FileMappingHandle;
+ HANDLE OpenFileMappingHandle;
+ HANDLE lpMapViewAddress;
+ const int LOWORDERSIZE = 1024;
+ char buf[] = "this is a test";
+ char MapObject[] = "myMappingObject";
+ char ch[1024];
+ int err;
+ int RetVal = PASS;
+
+ /* Initialize the PAL environment.
+ */
+ err = PAL_Initialize(argc, argv);
+ if(0 != err)
+ {
+ return FAIL;
+ }
+
+
+ /* Create a named file-mapping object with
+ * file handle FileHandle.
+ */
+ FileMappingHandle = CreateFileMapping(
+ INVALID_HANDLE_VALUE,
+ NULL, /* not inherited */
+ PAGE_READWRITE, /* read and write */
+ 0, /* high-order size */
+ LOWORDERSIZE, /* low-order size */
+ MapObject); /* named object */
+
+ if(NULL == FileMappingHandle)
+ {
+ Fail("ERROR:%u:Failed to call CreateFileMapping to "
+ "create a mapping object.\n",
+ GetLastError());
+ }
+ if(GetLastError() == ERROR_ALREADY_EXISTS)
+ {
+ Trace("ERROR:File mapping object already exists\n");
+ RetVal = FAIL;
+ goto CleanUpOne;
+ }
+
+ /* Open a named file-mapping object with
+ * FILE_MAP_ALL_ACCESS access.
+ */
+ OpenFileMappingHandle = OpenFileMapping(
+ FILE_MAP_ALL_ACCESS,
+ TRUE,
+ MapObject );
+
+ if(NULL == OpenFileMappingHandle)
+ {
+ Trace("ERROR:%u:Failed to Call OpenFileMapping API!\n",
+ GetLastError());
+ RetVal = FAIL;
+ goto CleanUpOne;
+ }
+
+ /* Test the opened map view.
+ */
+ lpMapViewAddress = MapViewOfFile(
+ OpenFileMappingHandle,
+ FILE_MAP_ALL_ACCESS, /* access code */
+ 0, /* high order offset */
+ 0, /* low order offset */
+ LOWORDERSIZE); /* number of bytes for map */
+
+ if(NULL == lpMapViewAddress)
+ {
+ Trace("ERROR:%u: Failed to call MapViewOfFile "
+ "API to map a view of file!\n",
+ GetLastError());
+ RetVal = FAIL;
+ goto CleanUpTwo;
+ }
+
+ /* Write to the Map View.
+ */
+ memcpy(lpMapViewAddress, buf, strlen(buf));
+
+ /* Read from the Map View.
+ */
+ memcpy(ch, (LPCSTR)lpMapViewAddress, LOWORDERSIZE);
+
+ /* Compare what was written to the Map View,
+ * to what was read.
+ */
+ if (memcmp(ch, buf, strlen(buf))!= 0)
+ {
+ Trace("ERROR: MapViewOfFile not equal to file contents "
+ "retrieved \"%s\", expected \"%s\".\n",
+ ch, buf);
+ RetVal = FAIL;
+ goto CleanUpThree;
+
+ }
+
+CleanUpThree:
+
+ /* Unmap the view of file.
+ */
+ if ( UnmapViewOfFile(lpMapViewAddress) == FALSE )
+ {
+ Trace("ERROR:%u: Failed to UnmapViewOfFile of \"%0x%lx\".\n",
+ GetLastError(),
+ lpMapViewAddress);
+ RetVal = FAIL;
+ }
+
+CleanUpTwo:
+
+ /* Close Handle to opend file mapping.
+ */
+ if ( CloseHandle(OpenFileMappingHandle) == 0 )
+ {
+ Trace("ERROR:%u: Failed to CloseHandle \"0x%lx\".\n",
+ GetLastError(),
+ OpenFileMappingHandle);
+ RetVal = FAIL;
+ }
+
+CleanUpOne:
+
+ /* Close Handle to create file mapping.
+ */
+ if ( CloseHandle(FileMappingHandle) == 0 )
+ {
+ Trace("ERROR:%u: Failed to CloseHandle \"0x%lx\".\n",
+ GetLastError(),
+ FileMappingHandle);
+ RetVal = FAIL;
+ }
+
+
+ /* Terminat the PAL.*/
+ PAL_TerminateEx(RetVal);
+ return RetVal;
+}
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingA/test1/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingA/test1/testinfo.dat
new file mode 100644
index 0000000000..010f2fe279
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingA/test1/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = OpenFileMappingA
+Name = Positive test for OpenFileMappingA API with FILE_MAP_ALL_ACCESS access
+TYPE = DEFAULT
+EXE1 = openfilemappinga
+Description
+=Test the OpenFileMappingA with FILE_MAP_ALL_ACCESS access
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingA/test2/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingA/test2/CMakeLists.txt
new file mode 100644
index 0000000000..3a0eff04a7
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingA/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ OpenFileMappingA.c
+)
+
+add_executable(paltest_openfilemappinga_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_openfilemappinga_test2 coreclrpal)
+
+target_link_libraries(paltest_openfilemappinga_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingA/test2/OpenFileMappingA.c b/src/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingA/test2/OpenFileMappingA.c
new file mode 100644
index 0000000000..5e41a92024
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingA/test2/OpenFileMappingA.c
@@ -0,0 +1,214 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: openfilemappinga.c (test 2)
+**
+** Purpose: Positive test the OpenFileMapping API.
+** Call OpenFileMapping to open a named file-mapping
+** object with FILE_MAP_WRITE access
+**
+**
+**============================================================*/
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ HANDLE FileMappingHandle;
+ HANDLE OpenFileMappingHandle;
+ HANDLE lpMapViewAddress;
+ HANDLE OpenFileMappingHandle2;
+ HANDLE lpMapViewAddress2;
+ const int LOWORDERSIZE = 1024;
+ char MapObject[] = "myMappingObject";
+ char buf[] = "this is a test";
+ char ch[1024];
+ int RetVal = PASS;
+
+
+ /* Initialize the PAL environment.
+ */
+ if(0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ /* Create a named file-mapping object with file handle FileHandle.
+ */
+ FileMappingHandle = CreateFileMapping(
+ INVALID_HANDLE_VALUE,
+ NULL, /* not inherited */
+ PAGE_READWRITE, /* read and write */
+ 0, /* high-order size */
+ LOWORDERSIZE, /* low-order size */
+ MapObject); /* named object */
+
+
+ if(NULL == FileMappingHandle)
+ {
+ Fail("\nFailed to call CreateFileMapping to create "
+ "a mapping object!\n");
+ }
+ if(GetLastError() == ERROR_ALREADY_EXISTS)
+ {
+ Trace("\nFile mapping object already exists!\n");
+ RetVal = FAIL;
+ goto CleanUpOne;
+ }
+
+ /* Open a named file-mapping object with FILE_MAP_WRITE access.
+ */
+ OpenFileMappingHandle = OpenFileMapping(
+ FILE_MAP_WRITE,
+ FALSE,
+ MapObject);
+
+ if(NULL == OpenFileMappingHandle)
+ {
+ Trace("\nFailed to Call OpenFileMapping API!\n");
+ RetVal = FAIL;
+ goto CleanUpOne;
+ }
+
+ /* Open a named file-mapping object with
+ * FILE_MAP_ALL_ACCESS access, to verify
+ * the FILE_MAP_WRITE access map.
+ */
+ OpenFileMappingHandle2 = OpenFileMapping(
+ FILE_MAP_ALL_ACCESS,
+ FALSE,
+ MapObject);
+
+ if(NULL == OpenFileMappingHandle2)
+ {
+ Trace("\nFailed to Call OpenFileMapping API!\n");
+ RetVal = FAIL;
+ goto CleanUpTwo;
+ }
+
+ /* Create map view of the open mapping that has
+ * FILE_MAP_WRITE access.
+ */
+ lpMapViewAddress = MapViewOfFile(
+ OpenFileMappingHandle,
+ FILE_MAP_WRITE, /* access code */
+ 0, /* high order offset */
+ 0, /* low order offset */
+ LOWORDERSIZE); /* number of bytes for map */
+
+ if(NULL == lpMapViewAddress)
+ {
+ Trace("ERROR:%u: Failed to call MapViewOfFile "
+ "API to map a view of file!\n",
+ GetLastError());
+ RetVal = FAIL;
+ goto CleanUpThree;
+ }
+
+ /* Create map view of the open mapping that has
+ * FILE_MAP_ALL_ACCESS access.
+ */
+ lpMapViewAddress2 = MapViewOfFile(
+ OpenFileMappingHandle2,
+ FILE_MAP_ALL_ACCESS, /* access code */
+ 0, /* high order offset */
+ 0, /* low order offset */
+ LOWORDERSIZE); /* number of bytes for map */
+
+ if(NULL == lpMapViewAddress2)
+ {
+ Trace("ERROR:%u: Failed to call MapViewOfFile "
+ "API to map a view of file!\n",
+ GetLastError());
+ RetVal = FAIL;
+ goto CleanUpFour;
+ }
+
+ /* Write to the Map View.
+ */
+ memcpy(lpMapViewAddress, buf, strlen(buf));
+
+ /* Read from the Map View.
+ */
+ memcpy(ch, (LPCSTR)lpMapViewAddress, LOWORDERSIZE);
+
+ /* Compare what was written to the Map View,
+ * to what was read.
+ */
+ if (memcmp(ch, buf, strlen(buf))!= 0)
+ {
+ Fail("ERROR: MapViewOfFile not equal to file contents "
+ "retrieved \"%s\", expected \"%s\".\n",
+ ch, buf);
+ RetVal = FAIL;
+ goto CleanUpFive;
+ }
+
+CleanUpFive:
+
+ /* Unmap the view of file.
+ */
+ if ( UnmapViewOfFile(lpMapViewAddress2) == FALSE )
+ {
+ Trace("ERROR:%u: Failed to UnmapViewOfFile of \"%0x%lx\".\n",
+ GetLastError(),
+ lpMapViewAddress2);
+ RetVal = FAIL;
+ }
+
+CleanUpFour:
+
+ /* Unmap the view of file.
+ */
+ if ( UnmapViewOfFile(lpMapViewAddress) == FALSE )
+ {
+ Trace("ERROR:%u: Failed to UnmapViewOfFile of \"%0x%lx\".\n",
+ GetLastError(),
+ lpMapViewAddress);
+ RetVal = FAIL;
+ }
+
+CleanUpThree:
+
+ /* Close Handle to opened file mapping.
+ */
+ if ( CloseHandle(OpenFileMappingHandle2) == 0 )
+ {
+ Trace("ERROR:%u: Failed to CloseHandle \"0x%lx\".\n",
+ GetLastError(),
+ OpenFileMappingHandle2);
+ RetVal = FAIL;
+ }
+
+CleanUpTwo:
+
+ /* Close Handle to opened file mapping.
+ */
+ if ( CloseHandle(OpenFileMappingHandle) == 0 )
+ {
+ Trace("ERROR:%u: Failed to CloseHandle \"0x%lx\".\n",
+ GetLastError(),
+ OpenFileMappingHandle);
+ RetVal = FAIL;
+ }
+
+CleanUpOne:
+
+ /* Close Handle to create file mapping.
+ */
+ if ( CloseHandle(FileMappingHandle) == 0 )
+ {
+ Trace("ERROR:%u: Failed to CloseHandle \"0x%lx\".\n",
+ GetLastError(),
+ FileMappingHandle);
+ RetVal = FAIL;
+ }
+
+
+ /* Terminate the PAL.
+ */
+ PAL_TerminateEx(RetVal);
+ return RetVal;
+}
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingA/test2/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingA/test2/testinfo.dat
new file mode 100644
index 0000000000..2a02128b68
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingA/test2/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = OpenFileMappingA
+Name = Positive test for OpenFileMappingA API with FILE_MAP_WRITE access
+TYPE = DEFAULT
+EXE1 = openfilemappinga
+Description
+=Test the OpenFileMappingA with FILE_MAP_WRITE access
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingA/test3/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingA/test3/CMakeLists.txt
new file mode 100644
index 0000000000..599a09ffc7
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingA/test3/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ OpenFileMappingA.c
+)
+
+add_executable(paltest_openfilemappinga_test3
+ ${SOURCES}
+)
+
+add_dependencies(paltest_openfilemappinga_test3 coreclrpal)
+
+target_link_libraries(paltest_openfilemappinga_test3
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingA/test3/OpenFileMappingA.c b/src/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingA/test3/OpenFileMappingA.c
new file mode 100644
index 0000000000..b01a3e8c0b
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingA/test3/OpenFileMappingA.c
@@ -0,0 +1,217 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: openfilemappinga.c
+**
+** Purpose: Positive test the OpenFileMapping API.
+** Call OpenFileMapping to open a named file-mapping
+** object with FILE_MAP_READ access
+**
+**
+**============================================================*/
+#include <palsuite.h>
+
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ HANDLE FileMappingHandle;
+ HANDLE OpenFileMappingHandle;
+ HANDLE OpenFileMappingHandle2;
+ HANDLE lpMapViewAddress;
+ HANDLE lpMapViewAddress2;
+ const int LOWORDERSIZE = 1024;
+ char buf[] = "this is a test";
+ char MapObject[] = "myMappingObject";
+ char ch[1024];
+ int RetVal = PASS;
+
+ /* Initialize the PAL environment.
+ */
+ if(0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ /* Create a named file-mapping object with file handle FileHandle.
+ */
+ FileMappingHandle = CreateFileMapping(
+ INVALID_HANDLE_VALUE,
+ NULL, /* Not inherited */
+ PAGE_READWRITE, /* Read only */
+ 0, /* High-order size */
+ LOWORDERSIZE, /* Must be none 0 */
+ MapObject); /* Named object */
+
+
+ if(NULL == FileMappingHandle)
+ {
+ Fail("ERROR:%u:Failed to call CreateFileMapping to create "
+ "mapping object = \"%s\".\n",
+ GetLastError(),
+ MapObject);
+ }
+ if(GetLastError() == ERROR_ALREADY_EXISTS)
+ {
+ Trace("ERROR:File mapping object \"%s\" already exists!\n",
+ MapObject);
+ RetVal = FAIL;
+ goto CleanUpOne;
+ }
+
+ /* Open a named file-mapping object with
+ * FILE_MAP_READ access.
+ */
+ OpenFileMappingHandle = OpenFileMapping(
+ FILE_MAP_READ,
+ 0,
+ MapObject);
+
+ if(NULL == OpenFileMappingHandle)
+ {
+ Trace("ERROR:%u: Failed to Call OpenFileMapping API.\n");
+ RetVal = FAIL;
+ goto CleanUpOne;
+ }
+
+ /* Open a named file-mapping object with
+ * FILE_MAP_ALL_ACCESS access, to verify the
+ * READ-ONLY Map view.
+ */
+ OpenFileMappingHandle2 = OpenFileMapping(
+ FILE_MAP_ALL_ACCESS,
+ 0,
+ MapObject);
+
+ if(NULL == OpenFileMappingHandle2)
+ {
+ Trace("Failed to Call OpenFileMapping API!\n");
+ RetVal = FAIL;
+ goto CleanUpTwo;
+ }
+
+ /* Test the opened map view.
+ */
+ lpMapViewAddress = MapViewOfFile(
+ OpenFileMappingHandle,
+ FILE_MAP_READ, /* access code */
+ 0, /* high order offset */
+ 0, /* low order offset */
+ LOWORDERSIZE); /* number of bytes for map */
+
+ if(NULL == lpMapViewAddress)
+ {
+ Trace("ERROR:%u: Failed to call MapViewOfFile "
+ "API to map a view of file!\n",
+ GetLastError());
+ RetVal = FAIL;
+ goto CleanUpThree;
+ }
+
+ /* Open the second Map view to verify the writing
+ * of the READ-ONLY Map view.
+ */
+ lpMapViewAddress2 = MapViewOfFile(
+ OpenFileMappingHandle2,
+ FILE_MAP_ALL_ACCESS, /* access code */
+ 0, /* high order offset */
+ 0, /* low order offset */
+ LOWORDERSIZE); /* number of bytes for map */
+
+ if(NULL == lpMapViewAddress2)
+ {
+ Trace("ERROR:%u: Failed to call MapViewOfFile "
+ "API to map a view of file!\n",
+ GetLastError());
+ RetVal = FAIL;
+ goto CleanUpFour;
+ }
+
+ /* Write to the ALL_ACCESS Map View.
+ */
+ memcpy(lpMapViewAddress2, buf, strlen(buf));
+
+ /* Read from the READ-ONLY Map View.
+ */
+ memcpy(ch, (LPCSTR)lpMapViewAddress, LOWORDERSIZE);
+
+ /* Compare what was written to the Map View,
+ * to what was read.
+ */
+ if (memcmp(ch, buf, strlen(buf))!= 0)
+ {
+ Trace("ERROR: MapViewOfFile not equal to file contents "
+ "retrieved \"%s\", expected \"%s\".\n",
+ ch, buf);
+ RetVal = FAIL;
+ goto CleanUpFive;
+ }
+
+CleanUpFive:
+
+ /* Unmap the view of file.
+ */
+ if ( UnmapViewOfFile(lpMapViewAddress2) == FALSE )
+ {
+ Trace("ERROR:%u: Failed to UnmapViewOfFile of \"%0x%lx\".\n",
+ GetLastError(),
+ lpMapViewAddress2);
+ RetVal = FAIL;
+ }
+
+CleanUpFour:
+
+ /* Unmap the view of file.
+ */
+ if ( UnmapViewOfFile(lpMapViewAddress) == FALSE )
+ {
+ Trace("ERROR:%u: Failed to UnmapViewOfFile of \"%0x%lx\".\n",
+ GetLastError(),
+ lpMapViewAddress);
+ RetVal = FAIL;
+ }
+
+CleanUpThree:
+
+ /* Close Handle to opened file mapping.
+ */
+ if ( CloseHandle(OpenFileMappingHandle2) == 0 )
+ {
+ Trace("ERROR:%u: Failed to CloseHandle \"0x%lx\".\n",
+ GetLastError(),
+ OpenFileMappingHandle2);
+ RetVal = FAIL;
+ }
+
+CleanUpTwo:
+
+ /* Close Handle to opened file mapping.
+ */
+ if ( CloseHandle(OpenFileMappingHandle) == 0 )
+ {
+ Trace("ERROR:%u: Failed to CloseHandle \"0x%lx\".\n",
+ GetLastError(),
+ OpenFileMappingHandle);
+ RetVal = FAIL;
+ }
+
+CleanUpOne:
+
+ /* Close Handle to create file mapping.
+ */
+ if ( CloseHandle(FileMappingHandle) == 0 )
+ {
+ Trace("ERROR:%u: Failed to CloseHandle \"0x%lx\".\n",
+ GetLastError(),
+ FileMappingHandle);
+ RetVal = FAIL;
+ }
+
+ /* Terminate the PAL.
+ */
+ PAL_TerminateEx(RetVal);
+ return RetVal;
+}
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingA/test3/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingA/test3/testinfo.dat
new file mode 100644
index 0000000000..4aff853f91
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingA/test3/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = OpenFileMappingA
+Name = Positive test for OpenFileMappingA API with FILE_MAP_READ access
+TYPE = DEFAULT
+EXE1 = openfilemappinga
+Description
+=Test the OpenFileMappingA with FILE_MAP_READ access
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingW/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingW/CMakeLists.txt
new file mode 100644
index 0000000000..1962ade358
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingW/CMakeLists.txt
@@ -0,0 +1,6 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+add_subdirectory(test3)
+
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingW/test1/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingW/test1/CMakeLists.txt
new file mode 100644
index 0000000000..04e9e47ef0
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingW/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ OpenFileMappingW.c
+)
+
+add_executable(paltest_openfilemappingw_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_openfilemappingw_test1 coreclrpal)
+
+target_link_libraries(paltest_openfilemappingw_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingW/test1/OpenFileMappingW.c b/src/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingW/test1/OpenFileMappingW.c
new file mode 100644
index 0000000000..079af4a5c0
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingW/test1/OpenFileMappingW.c
@@ -0,0 +1,155 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: openfilemappingw.c (test 1)
+**
+** Purpose: Positive test the OpenFileMapping API.
+** Call OpenFileMapping to open a named file-mapping
+** object with FILE_MAP_ALL_ACCESS access
+**
+**
+**============================================================*/
+
+#define UNICODE
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ HANDLE lpMapViewAddress;
+ char buf[] = "this is a test";
+ char ch[1024];
+
+ HANDLE FileMappingHandle;
+ HANDLE OpenFileMappingHandle;
+ const int LOWORDERSIZE = 1024;
+ int RetVal = PASS;
+ WCHAR wpMappingFileObject[] = {'m','y','O','b','j','e','c','t','\0'};
+
+ /* Initialize the PAL environment.
+ */
+ if(0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ /* Create a unnamed file-mapping object with file handle FileHandle.
+ */
+ FileMappingHandle = CreateFileMapping(
+ INVALID_HANDLE_VALUE,
+ NULL, /* Not inherited*/
+ PAGE_READWRITE, /* Read and write*/
+ 0, /* High-order size*/
+ LOWORDERSIZE, /* Low-order size*/
+ wpMappingFileObject);/* Named object*/
+
+
+ if(NULL == FileMappingHandle)
+ {
+ Fail("\nFailed to call CreateFileMapping to create a "
+ "mapping object!\n");
+ }
+ if(GetLastError() == ERROR_ALREADY_EXISTS)
+ {
+ Trace("\nFile mapping object already exists!\n");
+ RetVal = FAIL;
+ goto CleanUpOne;
+ }
+
+ /* Open a named file-mapping object with FILE_MAP_ALL_ACCESS access.
+ */
+ OpenFileMappingHandle = OpenFileMapping(
+ FILE_MAP_ALL_ACCESS,
+ FALSE,
+ wpMappingFileObject);
+
+ if(NULL == OpenFileMappingHandle)
+ {
+ Trace("\nFailed to Call OpenFileMapping API!\n");
+ RetVal = FAIL;
+ goto CleanUpOne;
+ }
+
+ /* Test the opened map view.
+ */
+ lpMapViewAddress = MapViewOfFile(
+ OpenFileMappingHandle,
+ FILE_MAP_ALL_ACCESS, /* access code */
+ 0, /* high order offset */
+ 0, /* low order offset */
+ LOWORDERSIZE); /* number of bytes for map */
+
+ if(NULL == lpMapViewAddress)
+ {
+ Trace("ERROR:%u: Failed to call MapViewOfFile "
+ "API to map a view of file!\n",
+ GetLastError());
+ RetVal = FAIL;
+ goto CleanUpTwo;
+ }
+
+ /* Write to the Map View.
+ */
+ memcpy(lpMapViewAddress, buf, strlen(buf));
+
+ /* Read from the Map View.
+ */
+ memcpy(ch, (LPCSTR)lpMapViewAddress, LOWORDERSIZE);
+
+ /* Compare what was written to the Map View,
+ * to what was read.
+ */
+ if (memcmp(ch, buf, strlen(buf))!= 0)
+ {
+ Trace("ERROR: MapViewOfFile not equal to file contents "
+ "retrieved \"%s\", expected \"%s\".\n",
+ ch, buf);
+ RetVal = FAIL;
+ goto CleanUpThree;
+ }
+
+CleanUpThree:
+
+ /* Unmap the view of file.
+ */
+ if ( UnmapViewOfFile(lpMapViewAddress) == FALSE )
+ {
+ Trace("ERROR:%u: Failed to UnmapViewOfFile of \"%0x%lx\".\n",
+ GetLastError(),
+ lpMapViewAddress);
+ RetVal = FAIL;
+ }
+
+CleanUpTwo:
+
+ /* Close Handle to opend file mapping.
+ */
+ if ( CloseHandle(OpenFileMappingHandle) == 0 )
+ {
+ Trace("ERROR:%u: Failed to CloseHandle \"0x%lx\".\n",
+ GetLastError(),
+ OpenFileMappingHandle);
+ RetVal = FAIL;
+ }
+
+CleanUpOne:
+
+ /* Close Handle to create file mapping.
+ */
+ if ( CloseHandle(FileMappingHandle) == 0 )
+ {
+ Trace("ERROR:%u: Failed to CloseHandle \"0x%lx\".\n",
+ GetLastError(),
+ FileMappingHandle);
+ RetVal = FAIL;
+ }
+
+ /* Terminate the PAL.
+ */
+ PAL_TerminateEx(RetVal);
+ return RetVal;
+}
+
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingW/test1/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingW/test1/testinfo.dat
new file mode 100644
index 0000000000..e67f4775f4
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingW/test1/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = OpenFileMappingW
+Name = Positive test for OpenFileMappingW API
+TYPE = DEFAULT
+EXE1 = openfilemappingw
+Description
+=Test the OpenFileMappingW with FILE_MAP_ALL_ACCESS access
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingW/test2/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingW/test2/CMakeLists.txt
new file mode 100644
index 0000000000..22e960b788
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingW/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ OpenFileMappingW.c
+)
+
+add_executable(paltest_openfilemappingw_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_openfilemappingw_test2 coreclrpal)
+
+target_link_libraries(paltest_openfilemappingw_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingW/test2/OpenFileMappingW.c b/src/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingW/test2/OpenFileMappingW.c
new file mode 100644
index 0000000000..e6a69651fa
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingW/test2/OpenFileMappingW.c
@@ -0,0 +1,217 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: openfilemappingw.c (test 2)
+**
+** Purpose: Positive test the OpenFileMapping API.
+** Call OpenFileMapping to open a named file-mapping
+** object with FILE_MAP_WRITE access
+**
+**
+**============================================================*/
+#define UNICODE
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ HANDLE FileMappingHandle;
+ HANDLE OpenFileMappingHandle;
+ HANDLE lpMapViewAddress;
+ HANDLE OpenFileMappingHandle2;
+ HANDLE lpMapViewAddress2;
+ const int LOWORDERSIZE = 1024;
+ WCHAR MapObject[] = {'m','y','O','b','j','e','c','t','\0'};
+ char buf[] = "this is a test";
+ char ch[1024];
+ int RetVal = PASS;
+
+
+ /* Initialize the PAL environment.
+ */
+ if(0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ /* Create a named file-mapping object with file handle FileHandle.
+ */
+ FileMappingHandle = CreateFileMapping(
+ INVALID_HANDLE_VALUE,
+ NULL, /* not inherited */
+ PAGE_READWRITE, /* read and wite */
+ 0, /* high-order size */
+ LOWORDERSIZE, /* low-order size */
+ MapObject); /* named object */
+
+ if(NULL == FileMappingHandle)
+ {
+ Fail("\nFailed to call CreateFileMapping to "
+ "create a mapping object!\n");
+ }
+ if(GetLastError() == ERROR_ALREADY_EXISTS)
+ {
+ Trace("\nFile mapping object already exists!\n");
+ RetVal = FAIL;
+ goto CleanUpOne;
+ }
+
+ /* Open a named file-mapping object with FILE_MAP_WRITE access.
+ */
+ OpenFileMappingHandle = OpenFileMapping(
+ FILE_MAP_WRITE,
+ FALSE,
+ MapObject);
+
+ if(NULL == OpenFileMappingHandle)
+ {
+ Trace("\nFailed to Call OpenFileMappingW API!\n");
+ RetVal = FAIL;
+ goto CleanUpOne;
+ }
+
+ /* Open a named file-mapping object with
+ * FILE_MAP_ALL_ACCESS access, to verify
+ * the FILE_MAP_WRITE access map.
+ */
+ OpenFileMappingHandle2 = OpenFileMapping(
+ FILE_MAP_ALL_ACCESS,
+ FALSE,
+ MapObject);
+
+ if(NULL == OpenFileMappingHandle2)
+ {
+ Trace("\nFailed to Call OpenFileMappingW API!\n");
+ RetVal = FAIL;
+ goto CleanUpTwo;
+ }
+
+ /* Create map view of the open mapping that has
+ * FILE_MAP_WRITE access.
+ */
+ lpMapViewAddress = MapViewOfFile(
+ OpenFileMappingHandle,
+ FILE_MAP_WRITE, /* access code */
+ 0, /* high order offset */
+ 0, /* low order offset */
+ LOWORDERSIZE); /* number of bytes for map */
+
+ if(NULL == lpMapViewAddress)
+ {
+ Trace("ERROR:%u: Failed to call MapViewOfFile "
+ "API to map a view of file!\n",
+ GetLastError());
+ RetVal = FAIL;
+ goto CleanUpThree;
+ }
+
+ /* Create map view of the open mapping that has
+ * FILE_MAP_ALL_ACCESS access.
+ */
+
+ lpMapViewAddress2 = MapViewOfFile(
+ OpenFileMappingHandle2,
+ FILE_MAP_ALL_ACCESS, /* access code */
+ 0, /* high order offset */
+ 0, /* low order offset */
+ LOWORDERSIZE); /* number of bytes for map */
+
+ if(NULL == lpMapViewAddress2)
+ {
+ Trace("ERROR:%u: Failed to call MapViewOfFile "
+ "API to map a view of file!\n",
+ GetLastError());
+ RetVal = FAIL;
+ goto CleanUpFour;
+ }
+
+ /* Write to the Map View.
+ */
+ memcpy(lpMapViewAddress, buf, strlen(buf));
+
+ /* Read from the Map View.
+ */
+ memcpy(ch, (LPCSTR)lpMapViewAddress, LOWORDERSIZE);
+
+ /* Compare what was written to the Map View,
+ * to what was read.
+ */
+ if (memcmp(ch, buf, strlen(buf))!= 0)
+ {
+
+ Trace("ERROR: MapViewOfFile not equal to file contents "
+ "retrieved \"%s\", expected \"%s\".\n",
+ ch, buf);
+ RetVal = FAIL;
+ goto CleanUpFive;
+ }
+
+
+CleanUpFive:
+
+ /* Unmap the view of file.
+ */
+ if ( UnmapViewOfFile(lpMapViewAddress2) == FALSE )
+ {
+ Trace("ERROR:%u: Failed to UnmapViewOfFile of \"%0x%lx\".\n",
+ GetLastError(),
+ lpMapViewAddress2);
+ RetVal = FAIL;
+ }
+
+CleanUpFour:
+
+ /* Unmap the view of file.
+ */
+ if ( UnmapViewOfFile(lpMapViewAddress) == FALSE )
+ {
+ Trace("ERROR:%u: Failed to UnmapViewOfFile of \"%0x%lx\".\n",
+ GetLastError(),
+ lpMapViewAddress);
+ RetVal = FAIL;
+ }
+
+CleanUpThree:
+
+ /* Close Handle to opened file mapping.
+ */
+ if ( CloseHandle(OpenFileMappingHandle2) == 0 )
+ {
+ Trace("ERROR:%u: Failed to CloseHandle \"0x%lx\".\n",
+ GetLastError(),
+ OpenFileMappingHandle2);
+ RetVal = FAIL;
+ }
+
+CleanUpTwo:
+
+ /* Close Handle to opened file mapping.
+ */
+ if ( CloseHandle(OpenFileMappingHandle) == 0 )
+ {
+ Trace("ERROR:%u: Failed to CloseHandle \"0x%lx\".\n",
+ GetLastError(),
+ OpenFileMappingHandle);
+ RetVal = FAIL;
+ }
+
+CleanUpOne:
+
+ /* Close Handle to create file mapping.
+ */
+ if ( CloseHandle(FileMappingHandle) == 0 )
+ {
+ Trace("ERROR:%u: Failed to CloseHandle \"0x%lx\".\n",
+ GetLastError(),
+ FileMappingHandle);
+ RetVal = FAIL;
+ }
+
+ /* Terminate the PAL.
+ */
+ PAL_TerminateEx(RetVal);
+ return RetVal;
+}
+
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingW/test2/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingW/test2/testinfo.dat
new file mode 100644
index 0000000000..d481560a0d
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingW/test2/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = OpenFileMappingW
+Name = Positive test for OpenFileMappingW API
+TYPE = DEFAULT
+EXE1 = openfilemappingw
+Description
+=Test the OpenFileMappingW with FILE_MAP_WRITE access
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingW/test3/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingW/test3/CMakeLists.txt
new file mode 100644
index 0000000000..5a54368110
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingW/test3/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ OpenFileMappingW.c
+)
+
+add_executable(paltest_openfilemappingw_test3
+ ${SOURCES}
+)
+
+add_dependencies(paltest_openfilemappingw_test3 coreclrpal)
+
+target_link_libraries(paltest_openfilemappingw_test3
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingW/test3/OpenFileMappingW.c b/src/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingW/test3/OpenFileMappingW.c
new file mode 100644
index 0000000000..9c83491f6b
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingW/test3/OpenFileMappingW.c
@@ -0,0 +1,210 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: openfilemappingw.c (test 3)
+**
+** Purpose: Positive test the OpenFileMappingW API.
+** Call OpenFileMappingW to open a named file-mapping
+** object with FILE_MAP_READ access
+**
+**
+**============================================================*/
+#define UNICODE
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ char buf[] = "this is a test";
+ char ch[1024];
+ HANDLE FileMappingHandle;
+ HANDLE OpenFileMappingHandle;
+ HANDLE OpenFileMappingHandle2;
+ HANDLE lpMapViewAddress;
+ HANDLE lpMapViewAddress2;
+ const int LOWORDERSIZE = 1024;
+ int RetVal = PASS;
+ WCHAR wpMappingFileObject[] = {'m','y','O','b','j','e','c','t','\0'};
+
+
+ /* Initialize the PAL environment.
+ */
+ if(0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ /* Create a unnamed file-mapping object with file handle FileHandle.
+ */
+ FileMappingHandle = CreateFileMapping(
+ INVALID_HANDLE_VALUE,
+ NULL, /* not inherited */
+ PAGE_READWRITE, /* read and wite */
+ 0, /* high-order size */
+ LOWORDERSIZE, /* must be non-zero */
+ wpMappingFileObject);/* named object */
+
+ if(NULL == FileMappingHandle)
+ {
+ Fail("\nFailed to call CreateFileMapping to create mapping object!\n");
+ }
+ if(GetLastError() == ERROR_ALREADY_EXISTS)
+ {
+ Trace("\nFile mapping object already exists!\n");
+ RetVal = FAIL;
+ goto CleanUpOne;
+ }
+
+ /* Open a named file-mapping object with FILE_MAP_ALL_ACCESS access.
+ */
+ OpenFileMappingHandle = OpenFileMapping(
+ FILE_MAP_READ,
+ FALSE,
+ wpMappingFileObject);
+
+ if(NULL == OpenFileMappingHandle)
+ {
+ Trace("\nFailed to Call OpenFileMapping API!\n");
+ RetVal = FAIL;
+ goto CleanUpOne;
+ }
+
+ /* Open a file mapping with FILE_MAP_ALL_ACCESS access,
+ * to verify the FILE_MAP_READ.
+ */
+ OpenFileMappingHandle2 = OpenFileMapping(
+ FILE_MAP_ALL_ACCESS,
+ FALSE,
+ wpMappingFileObject);
+
+ if(NULL == OpenFileMappingHandle2)
+ {
+ Trace("\nFailed to Call OpenFileMapping API!\n");
+ RetVal = FAIL;
+ goto CleanUpTwo;
+ }
+
+ /* Test the opened map view.
+ */
+ lpMapViewAddress = MapViewOfFile(
+ OpenFileMappingHandle,
+ FILE_MAP_READ, /* access code */
+ 0, /* high order offset */
+ 0, /* low order offset */
+ LOWORDERSIZE); /* number of bytes for map */
+
+ if(NULL == lpMapViewAddress)
+ {
+ Trace("ERROR:%u: Failed to call MapViewOfFile "
+ "API to map a view of file!\n",
+ GetLastError());
+ RetVal = FAIL;
+ goto CleanUpThree;
+ }
+
+ /* Open a map view with FILE_MAP_ALL_ACCESS to verify,
+ * the FILE_MAP_READ view.
+ */
+ lpMapViewAddress2 = MapViewOfFile(
+ OpenFileMappingHandle2,
+ FILE_MAP_ALL_ACCESS, /* access code */
+ 0, /* high order offset */
+ 0, /* low order offset */
+ LOWORDERSIZE); /* number of bytes for map */
+
+ if(NULL == lpMapViewAddress2)
+ {
+ Trace("2ERROR:%u: Failed to call MapViewOfFile "
+ "API to map a view of file!\n",
+ GetLastError());
+ RetVal = FAIL;
+ goto CleanUpFour;
+ }
+
+ /* Write to the Map View.
+ */
+ memcpy(lpMapViewAddress2, buf, strlen(buf));
+ /* Read from the Map View.
+ */
+ memcpy(ch, (LPCSTR)lpMapViewAddress, LOWORDERSIZE);
+
+ /* Compare what was written to the Map View,
+ * to what was read.
+ */
+ if (memcmp(ch, buf, strlen(buf))!= 0)
+ {
+ Trace("ERROR: MapViewOfFile not equal to file contents "
+ "retrieved \"%s\", expected \"%s\".\n",
+ ch,
+ buf);
+ RetVal = FAIL;
+ goto CleanUpFive;
+ }
+
+CleanUpFive:
+
+ /* Unmap the view of file.
+ */
+ if ( UnmapViewOfFile(lpMapViewAddress2) == FALSE )
+ {
+ Trace("ERROR:%u: Failed to UnmapViewOfFile of \"%0x%lx\".\n",
+ GetLastError(),
+ lpMapViewAddress2);
+ RetVal = FAIL;
+ }
+
+CleanUpFour:
+
+ /* Unmap the view of file.
+ */
+ if ( UnmapViewOfFile(lpMapViewAddress) == FALSE )
+ {
+ Trace("ERROR:%u: Failed to UnmapViewOfFile of \"%0x%lx\".\n",
+ GetLastError(),
+ lpMapViewAddress);
+ RetVal = FAIL;
+ }
+
+CleanUpThree:
+
+ /* Close Handle to opened file mapping.
+ */
+ if ( CloseHandle(OpenFileMappingHandle2) == 0 )
+ {
+ Trace("ERROR:%u: Failed to CloseHandle \"0x%lx\".\n",
+ GetLastError(),
+ OpenFileMappingHandle2);
+ RetVal = FAIL;
+ }
+
+CleanUpTwo:
+
+ /* Close Handle to opened file mapping.
+ */
+ if ( CloseHandle(OpenFileMappingHandle) == 0 )
+ {
+ Trace("ERROR:%u: Failed to CloseHandle \"0x%lx\".\n",
+ GetLastError(),
+ OpenFileMappingHandle);
+ RetVal = FAIL;
+ }
+
+CleanUpOne:
+
+ /* Close Handle to create file mapping.
+ */
+ if ( CloseHandle(FileMappingHandle) == 0 )
+ {
+ Trace("ERROR:%u: Failed to CloseHandle \"0x%lx\".\n",
+ GetLastError(),
+ FileMappingHandle);
+ RetVal = FAIL;
+ }
+
+ /* Terminate the PAL.
+ */
+ PAL_TerminateEx(RetVal);
+ return RetVal;
+}
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingW/test3/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingW/test3/testinfo.dat
new file mode 100644
index 0000000000..b4ac69ec36
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/OpenFileMappingW/test3/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = OpenFileMappingW
+Name = Positive test for OpenFileMappingW API with FILE_MAP_READ access
+TYPE = DEFAULT
+EXE1 = openfilemappingw
+Description
+=Test the OpenFileMappingW with FILE_MAP_READ access
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/ReadProcessMemory/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/ReadProcessMemory/CMakeLists.txt
new file mode 100644
index 0000000000..d2ae61f923
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/ReadProcessMemory/CMakeLists.txt
@@ -0,0 +1,6 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(ReadProcessMemory_neg1)
+add_subdirectory(test1)
+add_subdirectory(test2)
+
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/ReadProcessMemory/ReadProcessMemory_neg1/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/ReadProcessMemory/ReadProcessMemory_neg1/CMakeLists.txt
new file mode 100644
index 0000000000..400c9219f6
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/ReadProcessMemory/ReadProcessMemory_neg1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ ReadProcessMemory_neg.c
+)
+
+add_executable(paltest_readprocessmemory_readprocessmemory_neg1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_readprocessmemory_readprocessmemory_neg1 coreclrpal)
+
+target_link_libraries(paltest_readprocessmemory_readprocessmemory_neg1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/ReadProcessMemory/ReadProcessMemory_neg1/ReadProcessMemory_neg.c b/src/pal/tests/palsuite/filemapping_memmgt/ReadProcessMemory/ReadProcessMemory_neg1/ReadProcessMemory_neg.c
new file mode 100644
index 0000000000..aecd5ad576
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/ReadProcessMemory/ReadProcessMemory_neg1/ReadProcessMemory_neg.c
@@ -0,0 +1,127 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: ReadProcessMemory_neg.c
+**
+** Purpose: Negative test the ReadProcessMemory API.
+** Call ReadProcessMemory to read unreadabel memory area
+**
+**
+**============================================================*/
+#include <palsuite.h>
+
+#define REGIONSIZE 1024
+
+int __cdecl main(int argc, char *argv[])
+{
+ int err;
+ BOOL bResult;
+ HANDLE ProcessHandle;
+ DWORD ProcessID;
+ LPVOID lpProcessAddress = NULL;
+ char ProcessBuffer[REGIONSIZE];
+ ULONG_PTR size = 0;
+
+
+ /*Initialize the PAL environment*/
+ err = PAL_Initialize(argc, argv);
+ if(0 != err)
+ {
+ return FAIL;
+ }
+
+ /*retrieve the current process ID*/
+ ProcessID = GetCurrentProcessId();
+
+ /*retrieve the current process handle*/
+ ProcessHandle = OpenProcess(
+ PROCESS_ALL_ACCESS,
+ FALSE, /*not inherited*/
+ ProcessID);
+
+ if(NULL == ProcessHandle)
+ {
+ Fail("\nFailed to call OpenProcess API to retrieve "
+ "current process handle error code=%u\n",
+ GetLastError());
+ }
+
+
+
+ /*allocate the virtual memory*/
+ lpProcessAddress = VirtualAlloc(
+ NULL, /*system determine where to allocate the region*/
+ REGIONSIZE, /*specify the size*/
+ MEM_RESERVE, /*allocation type*/
+ PAGE_READONLY); /*access protection*/
+
+ if(NULL == lpProcessAddress)
+ {
+ Fail("\nFailed to call VirtualAlloc API to allocate "
+ "virtual memory, error code=%u\n", GetLastError());
+ }
+
+ /*zero the memory*/
+ memset(ProcessBuffer, 0, REGIONSIZE);
+ /*try to retrieve the unreadable memory area*/
+ bResult = ReadProcessMemory(
+ ProcessHandle, /*current process handle*/
+ lpProcessAddress, /*base of memory area*/
+ (LPVOID)ProcessBuffer,
+ REGIONSIZE, /*buffer length in bytes*/
+ &size);
+
+
+ /*check the return value*/
+ if(0 != bResult)
+ {
+ Trace("\nFailed to call ReadProcessMemory API for a negative test, "
+ "Try to read an unreadable memory area will cause fail "
+ "but it successes\n");
+
+ err = CloseHandle(ProcessHandle);
+ if(0 == err)
+ {
+ Trace("\nFailed to call CloseHandle API, error code=%u\n",
+ GetLastError());
+ }
+
+ /*decommit the specified region*/
+ err = VirtualFree(lpProcessAddress, REGIONSIZE, MEM_DECOMMIT);
+ if(0 == err)
+ {
+ Trace("\nFailed to call VirtualFree API, error code=%u\n",
+ GetLastError());
+ }
+ Fail("");
+ }
+
+ err = CloseHandle(ProcessHandle);
+ if(0 == err)
+ {
+ Trace("\nFailed to call CloseHandle API, error code = %u\n",
+ GetLastError());
+
+ err = VirtualFree(lpProcessAddress, REGIONSIZE, MEM_DECOMMIT);
+ if(0 == err)
+ {
+ Trace("\nFailed to call VirtualFree API, error code=%u\n",
+ GetLastError());
+ }
+
+ Fail("");
+ }
+ /*decommit the specified region*/
+ err = VirtualFree(lpProcessAddress, REGIONSIZE, MEM_DECOMMIT);
+ if(0 == err)
+ {
+ Fail("\nFailed to call VirtualFree API, error code=%u\n",
+ GetLastError());
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/ReadProcessMemory/ReadProcessMemory_neg1/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/ReadProcessMemory/ReadProcessMemory_neg1/testinfo.dat
new file mode 100644
index 0000000000..08c8f3291d
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/ReadProcessMemory/ReadProcessMemory_neg1/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = ReadProcessMemory
+Name = Negative test ReadProcessMemory API to read unreadable memory area
+TYPE = DEFAULT
+EXE1 = readprocessmemory_neg
+Description
+=Test the ReadProcessMemory to read unreadable memory area
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/ReadProcessMemory/test1/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/ReadProcessMemory/test1/CMakeLists.txt
new file mode 100644
index 0000000000..8c21f01562
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/ReadProcessMemory/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ ReadProcessMemory.c
+)
+
+add_executable(paltest_readprocessmemory_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_readprocessmemory_test1 coreclrpal)
+
+target_link_libraries(paltest_readprocessmemory_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/ReadProcessMemory/test1/ReadProcessMemory.c b/src/pal/tests/palsuite/filemapping_memmgt/ReadProcessMemory/test1/ReadProcessMemory.c
new file mode 100644
index 0000000000..c9475f13f1
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/ReadProcessMemory/test1/ReadProcessMemory.c
@@ -0,0 +1,126 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: ReadProcessMemory.c
+**
+** Purpose: Positive test the ReadProcessMemory API.
+** Call ReadProcessMemory to read memory contents
+** inside current process.
+**
+**
+**============================================================*/
+#include <palsuite.h>
+
+#define REGIONSIZE 1024
+
+int __cdecl main(int argc, char *argv[])
+{
+ int err;
+ BOOL bResult;
+ HANDLE ProcessHandle;
+ DWORD ProcessID;
+ LPVOID lpProcessAddress = NULL;
+ char ProcessBuffer[REGIONSIZE];
+ ULONG_PTR size = 0;
+
+
+ /*Initialize the PAL environment*/
+ err = PAL_Initialize(argc, argv);
+ if(0 != err)
+ {
+ return FAIL;
+ }
+
+ /*retrieve the current process ID*/
+ ProcessID = GetCurrentProcessId();
+
+ /*retrieve the current process handle*/
+ ProcessHandle = OpenProcess(
+ PROCESS_VM_READ,/*access flag*/
+ FALSE, /*not inherited*/
+ ProcessID);
+
+ if(NULL == ProcessHandle)
+ {
+ Fail("\nFailed to call OpenProcess API to retrieve "
+ "current process handle error code=%u\n",
+ GetLastError());
+ }
+
+ /*allocate the virtual memory*/
+ lpProcessAddress = VirtualAlloc(
+ NULL, /*system determine where to allocate the region*/
+ REGIONSIZE, /*specify the size*/
+ MEM_COMMIT, /*allocation type*/
+ PAGE_READONLY); /*access protection*/
+
+ if(NULL == lpProcessAddress)
+ {
+ Fail("\nFailed to call VirtualAlloc API to allocate "
+ "virtual memory, error code=%u!\n", GetLastError());
+ }
+
+ /*zero the memory*/
+ memset(ProcessBuffer, 0, REGIONSIZE);
+
+ /*retrieve the memory contents*/
+ bResult = ReadProcessMemory(
+ ProcessHandle, /*current process handle*/
+ lpProcessAddress, /*base of memory area*/
+ (LPVOID)ProcessBuffer,
+ REGIONSIZE, /*buffer length in bytes*/
+ &size);
+
+ if(!bResult || REGIONSIZE != size)
+ {
+ Trace("\nFailed to call ReadProcessMemory API "
+ "to retrieve the memory contents, error code=%u\n",
+ GetLastError());
+
+ err = CloseHandle(ProcessHandle);
+ if(0 == err)
+ {
+ Trace("\nFailed to call CloseHandle API, error code=%u\n",
+ GetLastError());
+ }
+
+ /*decommit the specified region*/
+ err = VirtualFree(lpProcessAddress, REGIONSIZE, MEM_DECOMMIT);
+ if(0 == err)
+ {
+ Trace("\nFailed to call VirtualFree API, error code=%u\n",
+ GetLastError());
+ }
+ Fail("");
+ }
+
+ err = CloseHandle(ProcessHandle);
+ if(0 == err)
+ {
+ Trace("\nFailed to call CloseHandle API, error code = %u\n",
+ GetLastError());
+
+ err = VirtualFree(lpProcessAddress, REGIONSIZE, MEM_DECOMMIT);
+ if(0 == err)
+ {
+ Trace("\nFailed to call VirtualFree API, error code=%u\n",
+ GetLastError());
+ }
+
+ Fail("");
+ }
+
+ /*decommit the specified region*/
+ err = VirtualFree(lpProcessAddress, REGIONSIZE, MEM_DECOMMIT);
+ if(0 == err)
+ {
+ Fail("\nFailed to call VirtualFree API, error code=%u\n",
+ GetLastError());
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/ReadProcessMemory/test1/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/ReadProcessMemory/test1/testinfo.dat
new file mode 100644
index 0000000000..c56920d206
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/ReadProcessMemory/test1/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = ReadProcessMemory
+Name = Positive test for ReadProcessMemory API to read memory contents
+TYPE = DEFAULT
+EXE1 = readprocessmemory
+Description
+=Test the ReadProcessMemory to read the memory contents
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/ReadProcessMemory/test2/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/ReadProcessMemory/test2/CMakeLists.txt
new file mode 100644
index 0000000000..9e0de95a0a
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/ReadProcessMemory/test2/CMakeLists.txt
@@ -0,0 +1,36 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(TESTSOURCES
+ test2.c
+)
+
+add_executable(paltest_readprocessmemory_test2
+ ${TESTSOURCES}
+)
+
+add_dependencies(paltest_readprocessmemory_test2 coreclrpal)
+
+target_link_libraries(paltest_readprocessmemory_test2
+ pthread
+ m
+ coreclrpal
+)
+
+
+set(HELPERSOURCES
+ helper.c
+)
+
+add_executable(paltest_readprocessmemory_test2_helper
+ ${HELPERSOURCES}
+)
+
+add_dependencies(paltest_readprocessmemory_test2_helper coreclrpal)
+
+target_link_libraries(paltest_readprocessmemory_test2_helper
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/ReadProcessMemory/test2/commonconsts.h b/src/pal/tests/palsuite/filemapping_memmgt/ReadProcessMemory/test2/commonconsts.h
new file mode 100644
index 0000000000..433d820f0f
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/ReadProcessMemory/test2/commonconsts.h
@@ -0,0 +1,48 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: commonconsts.h
+**
+**
+**============================================================*/
+
+#ifndef _COMMONCONSTS_H_
+#define _COMMONCONSTS_H_
+
+#include <pal.h>
+#define REGIONSIZE 1024
+
+const int TIMEOUT = 40000;
+
+const WCHAR szcToHelperEvName[] = { 'T', 'o', '\0' };
+const WCHAR szcFromHelperEvName[] = { 'F', 'r', 'o', 'm', '\0' };
+
+const char initialValue = '-';
+const char nextValue = '|';
+const char guardValue = '*';
+const char *commsFileName = "AddrNLen.dat";
+
+
+/* PEDANTIC and PEDANTIC0 is a helper macro that just grumps about any
+ * zero return codes in a generic way. with little typing */
+#define PEDANTIC(function, parameters) \
+{ \
+ if (! (function parameters) ) \
+ { \
+ Trace("%s: NonFatal failure of %s%s for reasons %u and %u\n", \
+ __FILE__, #function, #parameters, GetLastError(), errno); \
+ } \
+}
+#define PEDANTIC1(function, parameters) \
+{ \
+ if ( (function parameters) ) \
+ { \
+ Trace("%s: NonFatal failure of %s%s for reasons %u and %u\n", \
+ __FILE__, #function, #parameters, GetLastError(), errno); \
+ } \
+}
+
+#endif
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/ReadProcessMemory/test2/helper.c b/src/pal/tests/palsuite/filemapping_memmgt/ReadProcessMemory/test2/helper.c
new file mode 100644
index 0000000000..59e882fc1f
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/ReadProcessMemory/test2/helper.c
@@ -0,0 +1,249 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: helper.c
+**
+** Purpose: This helper process sets up a several blocks of memory,
+** then uses a file to tell its parent process where that memory is
+** So it can do a WriteProcessMemory on it. When the parent process is done
+** we check here that it was written properly.
+**
+**
+**============================================================*/
+
+#include "commonconsts.h"
+
+#include <palsuite.h>
+
+#if defined(BIT64) && defined(PLATFORM_UNIX)
+#define LLFORMAT "%I64u"
+#else
+#define LLFORMAT "%u"
+#endif
+
+struct allhandles_t
+{
+ HANDLE hEvToHelper;
+ HANDLE hEvFromHelper;
+ char *valuesFileName;
+};
+
+
+/* function: wpmDoIt
+ *
+ * This is a general WriteProcessMemory testing function that sets up
+ * the RAM pointed to and tells the companion process on the other end
+ * of the handles in 'Comms' to attempt to alter 'lenDest' bytes at
+ * '*pDest'.
+ *
+ * '*pBuffer'[0..'lenBuffer'] is expected to be a guard region
+ * surrounding the '*pDest'[0..'lenDest'] region so that this function
+ * can verify that only the proper bytes were altered.
+ */
+
+int wpmDoIt(struct allhandles_t Comms,
+ char * pBuffer, unsigned int lenBuffer,
+ char * pDest, unsigned int lenDest,
+ const char* storageDescription)
+{
+ char *pCurr;
+ FILE *commsFile;
+ DWORD dwRet;
+
+ if (pBuffer > pDest || lenDest > lenBuffer)
+ {
+ Trace("WriteProcessMemory::DoIt() test implementation: "
+ "(pBuffer > pDest || lenDest > lenBuffer)\n");
+ return FALSE;
+ }
+
+ /* set up the storage */
+ memset(pBuffer, guardValue, lenBuffer);
+ memset(pDest, initialValue, lenDest);
+
+ /* tell the parent what RAM to adjust */
+ if(!(commsFile = fopen(Comms.valuesFileName, "w")))
+ {
+ Trace("WriteProcessMemory: fopen of '%S' failed (%u). \n",
+ Comms.valuesFileName, GetLastError());
+ return FALSE;
+ }
+ if (!fprintf(commsFile, LLFORMAT " " LLFORMAT " '%s'\n",
+ pDest, lenDest, storageDescription))
+ {
+ Trace("WriteProcessMemory: fprintf to '%S' failed (%u). \n",
+ Comms.valuesFileName, GetLastError());
+ return FALSE;
+ }
+ PEDANTIC1(fclose, (commsFile));
+
+ /* Tell the parent the data is ready for it to adjust */
+ PEDANTIC(ResetEvent, (Comms.hEvToHelper));
+ PEDANTIC(SetEvent, (Comms.hEvFromHelper));
+
+ dwRet = WaitForSingleObject(Comms.hEvToHelper, TIMEOUT); /* parent is done */
+ if (dwRet != WAIT_OBJECT_0)
+ {
+ Trace("helper WaitForSingleObjectTest: WaitForSingleObject "
+ "failed (%u)\n", GetLastError());
+ return FALSE;
+ }
+
+ /* check the stuff that SHOULD have changed */
+ for (pCurr = pDest; pCurr < (pDest + lenDest); pCurr++)
+ {
+ if ( *pCurr != nextValue)
+ {
+ Trace("When testing '%s': alteration test failed "
+ "at " LLFORMAT " offset " LLFORMAT " Found '%c' instead of '%c'\n.",
+ storageDescription, pDest, pCurr - pDest, *pCurr, nextValue);
+ Trace(" 'Altered' string: '%.*s'\n",lenBuffer, pBuffer);
+ return FALSE;
+ }
+ }
+ /* check the stuff that should NOT have changed */
+ for (pCurr = pBuffer; pCurr < pDest; pCurr++ )
+ {
+ if ( *pCurr != guardValue)
+ {
+ Trace("When testing '%s': leading guard zone test failed "
+ "at " LLFORMAT " offset " LLFORMAT ". Found '%c' instead of '%c'\n.",
+ storageDescription, pDest, pCurr - pBuffer, *pCurr, guardValue);
+ Trace(" 'Altered' string: '%.*s'\n",lenBuffer, pBuffer);
+ return FALSE;
+ }
+ }
+ for (pCurr = pDest + lenDest; pCurr < (pBuffer + lenBuffer); pCurr++ )
+ {
+ if ( *pCurr != guardValue)
+ {
+ Trace("When testing '%s': trailing guard zone test failed "
+ "at " LLFORMAT " offset " LLFORMAT ". Found '%c' instead of '%c'\n.",
+ storageDescription, pDest + lenDest, pCurr - pBuffer, *pCurr, guardValue);
+ Trace(" 'Altered' string: '%.*s'\n",lenBuffer, pBuffer);
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ BOOL success = TRUE; /* assume success */
+ struct allhandles_t Comms = {0,0,0} ;
+
+ /* variables to track storage to alter */
+ char *pTarget = NULL;
+ unsigned int sizeTarget;
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /* hook up with the events created by the parent */
+ Comms.hEvToHelper = OpenEventW(EVENT_ALL_ACCESS, 0, szcToHelperEvName);
+ if (!Comms.hEvToHelper)
+ {
+ Fail("WriteProcessMemory: OpenEvent of '%S' failed (%u). "
+ "(the event should already exist!)\n",
+ szcToHelperEvName, GetLastError());
+ }
+ Comms.hEvFromHelper = OpenEventW(EVENT_ALL_ACCESS, 0, szcFromHelperEvName);
+ if (!Comms.hEvToHelper)
+ {
+ Trace("WriteProcessMemory: OpenEvent of '%S' failed (%u). "
+ "(the event should already exist!)\n",
+ szcFromHelperEvName, GetLastError());
+ success = FALSE;
+ goto EXIT;
+ }
+ Comms.valuesFileName = argv[1];
+
+ {
+ char autoAllocatedOnStack[51];
+
+ /* Get the parent process to write to the local stack */
+ success &= wpmDoIt(Comms, autoAllocatedOnStack,
+ sizeof(autoAllocatedOnStack),
+ autoAllocatedOnStack + sizeof(int),
+ sizeof(autoAllocatedOnStack) - 2 * sizeof(int),
+ "const size array on stack with int sized guards");
+ }
+
+ /* Get the parent process to write to stuff on the heap */
+ sizeTarget = 2 * sizeof(int) + 23 ; /* 23 is just a random prime > 16 */
+ if (!(pTarget = malloc(sizeTarget)))
+ {
+ Trace("WriteProcessMemory helper: unable to allocate '%s'->%d bytes of memory"
+ "(%u).\n",
+ argv[3], sizeTarget, GetLastError());
+ success = FALSE;
+ goto EXIT;
+
+ }
+ success &= wpmDoIt(Comms, pTarget, sizeTarget,
+ pTarget + sizeof(int),
+ sizeTarget - 2 * sizeof(int),
+ "array on heap with int sized guards");
+
+ /* just to be nice try something 16 - 2 * sizeof(int) bytes long */
+ {
+ char autoAllocatedOnStack[16];
+
+ /* Get the parent process to write to the local stack */
+ success &= wpmDoIt(Comms, autoAllocatedOnStack,
+ sizeof(autoAllocatedOnStack),
+ autoAllocatedOnStack + sizeof(int),
+ sizeof(autoAllocatedOnStack) - 2 * sizeof(int),
+ "another 16 byte array on stack with int sized guards inside");
+ }
+
+ /* NOTE: Don't try 0 bytes long. Win32 WriteProcessMemory claims
+ * it writes 8 bytes in that case! */
+
+ /* and 1 byte long... */
+ {
+ char autoAllocatedOnStack[1+ 2 * sizeof(int)];
+
+ /* Get the parent process to write to the local stack */
+ success &= wpmDoIt(Comms, autoAllocatedOnStack,
+ sizeof(autoAllocatedOnStack),
+ autoAllocatedOnStack + sizeof(int),
+ 1,
+ "no bytes with int sized guards outside on stack");
+ }
+
+
+EXIT:
+ /* Tell the parent that we are done */
+ if (!DeleteFile(Comms.valuesFileName))
+ {
+ Trace("helper: DeleteFile failed so parent (test1) is unlikely "
+ "to exit cleanly\n");
+ }
+ PEDANTIC(ResetEvent, (Comms.hEvToHelper));
+ if (!SetEvent(Comms.hEvFromHelper))
+ {
+ Trace("helper: SetEvent failed so parent (test1) is unlikely "
+ "to exit cleanly\n");
+ }
+
+ free(pTarget);
+ PEDANTIC(CloseHandle, (Comms.hEvToHelper));
+ PEDANTIC(CloseHandle, (Comms.hEvFromHelper));
+
+ if (!success)
+ {
+ Fail("");
+ }
+
+ PAL_Terminate();
+
+ return success ? PASS : FAIL;
+}
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/ReadProcessMemory/test2/test2.c b/src/pal/tests/palsuite/filemapping_memmgt/ReadProcessMemory/test2/test2.c
new file mode 100644
index 0000000000..eda40599ce
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/ReadProcessMemory/test2/test2.c
@@ -0,0 +1,258 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: test2.c
+**
+** Purpose: Create a child process and some events for communications with it.
+** When the child gets back to us with a memory location and a length,
+** Call WriteProcessMemory on this location and check to see that it
+** writes successfully. Then call ReadProcessMemory to check if the
+** contents read are same as those written
+**
+**
+**============================================================*/
+
+#define UNICODE
+
+#include "commonconsts.h"
+
+#include <palsuite.h>
+
+#if defined(BIT64) && defined(PLATFORM_UNIX)
+#define LLFORMAT "%I64u"
+#else
+#define LLFORMAT "%u"
+#endif
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ PROCESS_INFORMATION pi;
+ STARTUPINFO si;
+ HANDLE hEvToHelper;
+ HANDLE hEvFromHelper;
+ DWORD dwExitCode;
+
+ DWORD dwRet;
+ char cmdComposeBuf[MAX_PATH];
+ PWCHAR uniString;
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /* Create the signals we need for cross process communication */
+ hEvToHelper = CreateEvent(NULL, TRUE, FALSE, szcToHelperEvName);
+ if (!hEvToHelper)
+ {
+ Fail("WriteProcessMemory: CreateEvent of '%S' failed. "
+ "GetLastError() returned %d.\n", szcToHelperEvName,
+ GetLastError());
+ }
+ if (GetLastError() == ERROR_ALREADY_EXISTS)
+ {
+ Fail("WriteProcessMemory: CreateEvent of '%S' failed. "
+ "(already exists!)\n", szcToHelperEvName);
+ }
+ hEvFromHelper = CreateEvent(NULL, TRUE, FALSE, szcFromHelperEvName);
+ if (!hEvToHelper)
+ {
+ Fail("WriteProcessMemory: CreateEvent of '%S' failed. "
+ "GetLastError() returned %d.\n", szcFromHelperEvName,
+ GetLastError());
+ }
+ if (GetLastError() == ERROR_ALREADY_EXISTS)
+ {
+ Fail("WriteProcessMemory: CreateEvent of '%S' failed. "
+ "(already exists!)\n", szcFromHelperEvName);
+ }
+ ResetEvent(hEvFromHelper);
+ ResetEvent(hEvToHelper);
+
+ if (!sprintf(cmdComposeBuf, "helper %s", commsFileName))
+ {
+ Fail("Could not convert command line\n");
+ }
+ uniString = convert(cmdComposeBuf);
+
+ ZeroMemory( &si, sizeof(si) );
+ si.cb = sizeof(si);
+ ZeroMemory( &pi, sizeof(pi) );
+
+ /* Create a new process. This is the process that will ask for
+ * memory munging */
+ if(!CreateProcess( NULL, uniString, NULL, NULL,
+ FALSE, 0, NULL, NULL, &si, &pi))
+ {
+ Trace("ERROR: CreateProcess failed to load executable '%S'. "
+ "GetLastError() returned %u.\n",
+ uniString, GetLastError());
+ free(uniString);
+ Fail("");
+ }
+ free(uniString);
+
+
+ while(1)
+ {
+ FILE *commsFile;
+ char* pSrcMemory;
+ char* pDestMemory;
+ SIZE_T Count;
+ SIZE_T wpmCount;
+ char incomingCMDBuffer[MAX_PATH + 1];
+
+ int err;
+ HANDLE readProcessHandle;
+ DWORD readProcessID;
+ char readProcessBuffer[REGIONSIZE]; // size 1024
+ BOOL bResult;
+ size_t size = 0;
+
+ readProcessID = pi.dwProcessId;
+
+ /* wait until the helper tells us that it has given us
+ * something to do */
+ dwRet = WaitForSingleObject(hEvFromHelper, TIMEOUT);
+ if (dwRet != WAIT_OBJECT_0)
+ {
+ Trace("test1 WaitForSingleObjectTest: WaitForSingleObject "
+ "failed (%u)\n", GetLastError());
+ break; /* no more work incoming */
+ }
+
+ /* get the parameters to test WriteProcessMemory with */
+ if (!(commsFile = fopen(commsFileName, "r")))
+ {
+ /* no file means there is no more work */
+ break;
+ }
+ if ( NULL == fgets(incomingCMDBuffer, MAX_PATH, commsFile))
+ {
+ Fail ("unable to read from communication file %s "
+ "for reasons %u & %u\n",
+ errno, GetLastError());
+ }
+ PEDANTIC1(fclose,(commsFile));
+ sscanf(incomingCMDBuffer, LLFORMAT " " LLFORMAT, &pDestMemory, &Count);
+ if (argc > 1)
+ {
+ Trace("Preparing to write to " LLFORMAT " bytes @ " LLFORMAT "('%s')\n",
+ Count, pDestMemory, incomingCMDBuffer);
+ }
+
+ /* compose some data to write to the client process */
+ if (!(pSrcMemory = malloc(Count)))
+ {
+ Trace("could not dynamically allocate memory to copy from "
+ "for reasons %u & %u\n",
+ errno, GetLastError());
+ goto doneIteration;
+ }
+ memset(pSrcMemory, nextValue, Count);
+ Trace("Preparing to write to " LLFORMAT " bytes @ " LLFORMAT " ('%s')[%u]\n",
+ Count, pDestMemory, incomingCMDBuffer, pSrcMemory);
+
+ /* do the work */
+ dwRet = WriteProcessMemory(pi.hProcess,
+ pDestMemory,
+ pSrcMemory,
+ Count,
+ &wpmCount);
+
+ if (!dwRet)
+ {
+ Trace("%s: Problem: on a write to "LLFORMAT " bytes @ " LLFORMAT " ('%s')\n",
+ argv[0], Count, pDestMemory, incomingCMDBuffer);
+ Trace("test1 WriteProcessMemory returned a (!=0) (GLE=%u)\n",
+ GetLastError());
+ }
+ if(Count != wpmCount)
+ {
+ Trace("%s: Problem: on a write to " LLFORMAT " bytes @ " LLFORMAT " ('%s')\n",
+ argv[0], Count, pDestMemory, incomingCMDBuffer);
+ Trace("The number of bytes written should have been "
+ LLFORMAT ", but was reported as " LLFORMAT " \n", Count, wpmCount);
+ }
+
+ readProcessHandle = OpenProcess(
+ PROCESS_VM_READ,
+ FALSE,
+ readProcessID);
+
+ if(NULL == readProcessHandle)
+ {
+ Fail("\nFailed to call OpenProcess API to retrieve "
+ "current process handle error code=%u\n",
+ GetLastError());
+ }
+
+ /*zero the memory*/
+ memset(readProcessBuffer, 0, size);
+
+ /*retrieve the memory contents*/
+ bResult = ReadProcessMemory(
+ readProcessHandle, /*current process handle*/
+ pDestMemory, /*base of memory area*/
+ (LPVOID)readProcessBuffer,
+ Count, /*buffer length in bytes*/
+ &size);
+
+
+ if( !bResult || (Count != size) )
+ {
+ Trace("\nFailed to call ReadProcessMemory API "
+ "to retrieve the memory contents, error code=%u; Bresult[%u] Count[" LLFORMAT "], Size[%d]\n",
+ GetLastError(), bResult, Count, size);
+
+ err = CloseHandle(readProcessHandle);
+
+ if(0 == err)
+ {
+ Trace("\nFailed to call CloseHandle API, error code=%u\n",
+ GetLastError());
+ }
+ dwExitCode = FAIL;
+ }
+
+ if( !memcmp (pDestMemory, readProcessBuffer, Count ) )
+ {
+ Trace("Difference in memory contents, expected [%s], but received [%s]\n", pDestMemory, readProcessBuffer);
+ dwExitCode = FAIL;
+ }
+
+ Trace("ReadProcessBuffer contains [%s]\n", readProcessBuffer);
+ err = CloseHandle(readProcessHandle);
+
+ free(pSrcMemory);
+
+ doneIteration:
+ PEDANTIC(ResetEvent, (hEvFromHelper));
+ PEDANTIC(SetEvent, (hEvToHelper));
+ }
+
+ /* wait for the child process to complete */
+ WaitForSingleObject ( pi.hProcess, TIMEOUT );
+ /* this may return a failure code on a success path */
+
+ /* check the exit code from the process */
+ if( ! GetExitCodeProcess( pi.hProcess, &dwExitCode ) )
+ {
+ Trace( "GetExitCodeProcess call failed with error code %u\n",
+ GetLastError() );
+ dwExitCode = FAIL;
+ }
+
+
+ PEDANTIC(CloseHandle, (hEvToHelper));
+ PEDANTIC(CloseHandle, (hEvFromHelper));
+ PEDANTIC(CloseHandle, (pi.hThread));
+ PEDANTIC(CloseHandle, (pi.hProcess));
+
+ PAL_TerminateEx(dwExitCode);
+ return dwExitCode;
+}
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/ReadProcessMemory/test2/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/ReadProcessMemory/test2/testinfo.dat
new file mode 100644
index 0000000000..58a9935a08
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/ReadProcessMemory/test2/testinfo.dat
@@ -0,0 +1,18 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Debug
+Function = ReadProcessMemory
+Name = Check that writing/reading text to/from process memory succeeds.
+TYPE = DEFAULT
+EXE1 = test2
+EXE2 = helper
+Description
+= Create a child process and attempt to write to its memory
+= at the places and lengths it specifies via a data file.
+= the child verifies that all the specified memory was altered
+= with no overruns. Parent then tries to read memory from child
+= and does memory compare to ensure it read memory contents
+= correctly
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/RtlMoveMemory/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/RtlMoveMemory/CMakeLists.txt
new file mode 100644
index 0000000000..393074b4ee
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/RtlMoveMemory/CMakeLists.txt
@@ -0,0 +1,7 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test3)
+add_subdirectory(test4)
+add_subdirectory(test5)
+
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/RtlMoveMemory/test1/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/RtlMoveMemory/test1/CMakeLists.txt
new file mode 100644
index 0000000000..987c413d03
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/RtlMoveMemory/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_rtlmovememory_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_rtlmovememory_test1 coreclrpal)
+
+target_link_libraries(paltest_rtlmovememory_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/RtlMoveMemory/test1/test1.c b/src/pal/tests/palsuite/filemapping_memmgt/RtlMoveMemory/test1/test1.c
new file mode 100644
index 0000000000..7fc56510d8
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/RtlMoveMemory/test1/test1.c
@@ -0,0 +1,56 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: test1.c
+**
+** Purpose: Simple test -- have two 128 blocks of memory allocated. Then
+** move one block to the other and check to see that the data was not
+** corrupted.
+**
+**
+**============================================================*/
+
+#include <palsuite.h>
+
+enum Memory
+{
+ MEMORY_AMOUNT = 128
+};
+
+int __cdecl main(int argc, char *argv[])
+{
+ char NewAddress[MEMORY_AMOUNT];
+ char OldAddress[MEMORY_AMOUNT];
+ int i;
+ char temp;
+
+ if(PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ /* Put some data into the block we'll be moving */
+ memset(OldAddress, 'X', MEMORY_AMOUNT);
+
+ /* Move the block to the NewAddress */
+ RtlMoveMemory(NewAddress, OldAddress, MEMORY_AMOUNT);
+
+ /* Check to ensure the data didn't get corrupted */
+ for(i=0; i<MEMORY_AMOUNT; ++i)
+ {
+ if(NewAddress[i] != 'X')
+ {
+ temp = NewAddress[i];
+ Fail("ERROR: When the memory was moved to a new location, the "
+ "data which was stored in it was somehow corrupted. "
+ "Character %d should have been 'X' but instead is %c.\n",
+ i, temp);
+ }
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/RtlMoveMemory/test1/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/RtlMoveMemory/test1/testinfo.dat
new file mode 100644
index 0000000000..645d46c968
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/RtlMoveMemory/test1/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = RtlMoveMemory
+Name = Positive test for RtlMoveMemory API
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Simple test -- have two 128 blocks of memory allocated. Then
+= move one block to the other and check to see that the data was not
+= corrupted.
+
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/RtlMoveMemory/test3/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/RtlMoveMemory/test3/CMakeLists.txt
new file mode 100644
index 0000000000..14098a8dc1
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/RtlMoveMemory/test3/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test3.c
+)
+
+add_executable(paltest_rtlmovememory_test3
+ ${SOURCES}
+)
+
+add_dependencies(paltest_rtlmovememory_test3 coreclrpal)
+
+target_link_libraries(paltest_rtlmovememory_test3
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/RtlMoveMemory/test3/test3.c b/src/pal/tests/palsuite/filemapping_memmgt/RtlMoveMemory/test3/test3.c
new file mode 100644
index 0000000000..279c0c1199
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/RtlMoveMemory/test3/test3.c
@@ -0,0 +1,72 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: test3.c
+**
+** Purpose: Allocate 128 bytes of memory and store data in it. Move 10
+** other bytes of memory to that location. Check that the first 10 bytes
+** carried over their data and that the other 118 were unchanged.
+**
+**
+**============================================================*/
+
+#include <palsuite.h>
+
+enum Memory
+{
+ NEW_MEMORY_AMOUNT = 128,
+ OLD_MEMORY_AMOUNT = 10
+};
+
+int __cdecl main(int argc, char *argv[])
+{
+ char NewAddress[NEW_MEMORY_AMOUNT];
+ char OldAddress[OLD_MEMORY_AMOUNT];
+ int i;
+
+
+ if(PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ /* Put some data into the block we'll be moving */
+ memset(OldAddress, 'X', OLD_MEMORY_AMOUNT);
+
+ /* Put some data into the block we're moving to */
+ memset(NewAddress, 'Z', NEW_MEMORY_AMOUNT);
+
+ /* Move the block to the NewAddress */
+ RtlMoveMemory(NewAddress, OldAddress, OLD_MEMORY_AMOUNT);
+
+ /* Check to ensure the moved data didn't get corrupted */
+ for(i=0; i<OLD_MEMORY_AMOUNT; ++i)
+ {
+ if(NewAddress[i] != 'X')
+ {
+ Fail("ERROR: When the memory was moved to a new location, the "
+ "data which was stored in it was somehow corrupted. "
+ "Character %d should have been 'X' but instead is %c.\n",
+ i, NewAddress[i]);
+ }
+ }
+
+ /* Check to ensure the memory which didn't move didn't get corrupted */
+ for(i=OLD_MEMORY_AMOUNT; i<NEW_MEMORY_AMOUNT; ++i)
+ {
+ if(NewAddress[i] != 'Z')
+ {
+ Fail("ERROR: When the memory was moved to a new location, the "
+ "data which was stored in it was somehow corrupted. "
+ "Character %d should have been 'Z' but instead is %c.\n",
+ i, NewAddress[i]);
+ }
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/RtlMoveMemory/test3/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/RtlMoveMemory/test3/testinfo.dat
new file mode 100644
index 0000000000..fb56f2e985
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/RtlMoveMemory/test3/testinfo.dat
@@ -0,0 +1,17 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = RtlMoveMemory
+Name = Positive test for RtlMoveMemory API, move a small block to large
+TYPE = DEFAULT
+EXE1 = test3
+Description
+= Allocate 128 bytes of memory and store data in it. Move 10
+= other bytes of memory to that location. Check that the first 10 bytes
+= carried over their data and that the other 118 were unchanged.
+
+
+
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/RtlMoveMemory/test4/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/RtlMoveMemory/test4/CMakeLists.txt
new file mode 100644
index 0000000000..00aec7e8f7
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/RtlMoveMemory/test4/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test4.c
+)
+
+add_executable(paltest_rtlmovememory_test4
+ ${SOURCES}
+)
+
+add_dependencies(paltest_rtlmovememory_test4 coreclrpal)
+
+target_link_libraries(paltest_rtlmovememory_test4
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/RtlMoveMemory/test4/test4.c b/src/pal/tests/palsuite/filemapping_memmgt/RtlMoveMemory/test4/test4.c
new file mode 100644
index 0000000000..b6e1ecd6f7
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/RtlMoveMemory/test4/test4.c
@@ -0,0 +1,76 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: test4.c
+**
+** Purpose: Test simple overlapping. Move the first 50 bytes of a
+** piece of memory to the latter 50 bytes. ie i -> i+50 Check to make sure
+** no data is lost.
+**
+**
+**============================================================*/
+
+#include <palsuite.h>
+
+enum Memory
+{
+ MEMORY_AMOUNT = 128
+};
+
+int __cdecl main(int argc, char *argv[])
+{
+ char* NewAddress;
+ char OldAddress[MEMORY_AMOUNT];
+ int i;
+
+ if(PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ NewAddress = OldAddress+50;
+
+ /* Put some data into the block we'll be moving
+ The first 50 byes will be 'X' and the rest set to 'Z'
+ */
+ memset(OldAddress, 'X', 50);
+ memset(NewAddress, 'Z', MEMORY_AMOUNT-50);
+
+ /* Move the first 50 bytes of OldAddress to OldAddress+50. This
+ is to test that the source and destination addresses can overlap.
+ */
+ RtlMoveMemory(NewAddress, OldAddress, 50);
+
+ /* Check to ensure the moved data didn't get corrupted
+ The first 50 bytes should be 'X'
+ */
+ for(i=0; i<50; ++i)
+ {
+ if(NewAddress[i] != 'X')
+ {
+ Fail("ERROR: When the memory was moved to a new location, the "
+ "data which was stored in it was somehow corrupted. "
+ "Character %d should have been 'X' but instead is %c.\n",
+ i, NewAddress[i]);
+ }
+ }
+
+ /* The rest of the memory should be 'Z' */
+ for(i=50; i<MEMORY_AMOUNT-50; ++i)
+ {
+ if(NewAddress[i] != 'Z')
+ {
+
+ Fail("ERROR: When the memory was moved to a new location, the "
+ "data which was stored in it was somehow corrupted. "
+ "Character %d should have been 'Z' but instead is %c.\n",
+ i, NewAddress[i]);
+ }
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/RtlMoveMemory/test4/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/RtlMoveMemory/test4/testinfo.dat
new file mode 100644
index 0000000000..56b82f2083
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/RtlMoveMemory/test4/testinfo.dat
@@ -0,0 +1,18 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = RtlMoveMemory
+Name = Positive test for RtlMoveMemory API, test that overlapping works
+TYPE = DEFAULT
+EXE1 = test4
+Description
+= Test simple overlapping. Move the first 50 bytes of a
+= piece of memory to the latter 50 bytes. ie i -> i+50 Check to make sure
+= no data is lost.
+
+
+
+
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/RtlMoveMemory/test5/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/RtlMoveMemory/test5/CMakeLists.txt
new file mode 100644
index 0000000000..f2de78216e
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/RtlMoveMemory/test5/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test5.c
+)
+
+add_executable(paltest_rtlmovememory_test5
+ ${SOURCES}
+)
+
+add_dependencies(paltest_rtlmovememory_test5 coreclrpal)
+
+target_link_libraries(paltest_rtlmovememory_test5
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/RtlMoveMemory/test5/test5.c b/src/pal/tests/palsuite/filemapping_memmgt/RtlMoveMemory/test5/test5.c
new file mode 100644
index 0000000000..affcb0abc9
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/RtlMoveMemory/test5/test5.c
@@ -0,0 +1,63 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: test5.c
+**
+** Purpose: Do more complex overlapping. Move a section of memory back so
+** that it actually ends up overlapping itself.
+**
+**
+**============================================================*/
+
+#include <palsuite.h>
+
+enum Memory
+{
+ MEMORY_AMOUNT = 128
+};
+
+int __cdecl main(int argc, char *argv[])
+{
+ char* NewAddress;
+ char* SectionToMove;
+ char TheMemory[MEMORY_AMOUNT];
+ int i;
+
+ if(PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ NewAddress = TheMemory;
+ SectionToMove = TheMemory+50;
+
+ /* Put some data into the first 50 bytes */
+ memset(TheMemory, 'X', 50);
+
+ /* Put some data into the rest of the memory */
+ memset(SectionToMove, 'Z', MEMORY_AMOUNT-50);
+
+ /* Move the section in the middle of TheMemory back to the start of
+ TheMemory -- but have it also overlap itself. (ie. the section
+ to be move is overlapping itself)
+ */
+ RtlMoveMemory(NewAddress, SectionToMove, MEMORY_AMOUNT-50);
+
+ /* Check to ensure the moved data didn't get corrupted */
+ for(i=0; i<MEMORY_AMOUNT-50; ++i)
+ {
+ if(NewAddress[i] != 'Z')
+ {
+ Fail("ERROR: When the memory was moved to a new location, the "
+ "data which was stored in it was somehow corrupted. "
+ "Character %d should have been 'Z' but instead is %c.\n",
+ i, NewAddress[i]);
+ }
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/RtlMoveMemory/test5/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/RtlMoveMemory/test5/testinfo.dat
new file mode 100644
index 0000000000..a4ba99a29d
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/RtlMoveMemory/test5/testinfo.dat
@@ -0,0 +1,18 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = RtlMoveMemory
+Name = Positive test for RtlMoveMemory API, test that overlapping works
+TYPE = DEFAULT
+EXE1 = test5
+Description
+= Do more complex overlapping. Move a section of memory back so
+= that it actually ends up overlapping itself.
+
+
+
+
+
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/UnlockFile/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/UnlockFile/CMakeLists.txt
new file mode 100644
index 0000000000..a3847f8ca9
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/UnlockFile/CMakeLists.txt
@@ -0,0 +1,7 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+add_subdirectory(test3)
+add_subdirectory(test4)
+
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/UnlockFile/UnlockFile.h b/src/pal/tests/palsuite/filemapping_memmgt/UnlockFile/UnlockFile.h
new file mode 100644
index 0000000000..8fce2695a7
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/UnlockFile/UnlockFile.h
@@ -0,0 +1,112 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: UnLockFile.h
+**
+** Purpose: This header file has a RunHelper method which will be used to
+** start a child proccess in many LockFile testcases. The CreateAndLockFile
+** method Creates a file and calls LockFile upon it. And the two Signal
+** methods are used for IPC.
+**
+**
+**============================================================*/
+
+#include <palsuite.h>
+
+HANDLE CreateAndLockFile(HANDLE TheFile, char* FileName, char* WriteBuffer,
+ DWORD LockStart, DWORD LockLength)
+{
+ DWORD BytesWritten;
+
+ TheFile = CreateFile(FileName,
+ GENERIC_READ|GENERIC_WRITE,
+ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ NULL,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if (TheFile == INVALID_HANDLE_VALUE)
+ {
+ Fail("ERROR: Could not open file '%s' with CreateFile. "
+ "GetLastError() returned %d.\n",FileName,GetLastError());
+ }
+
+ if(WriteFile(TheFile, WriteBuffer,
+ strlen(WriteBuffer),&BytesWritten, NULL) == 0)
+ {
+ Fail("ERROR: WriteFile has failed. It returned 0 when we "
+ "attempted to write to the file '%s'. GetLastError() "
+ "returned %d.\n",FileName,GetLastError());
+ }
+
+ if(FlushFileBuffers(TheFile) == 0)
+ {
+ Fail("ERROR: FlushFileBuffers returned failure. GetLastError() "
+ "returned %d.\n",GetLastError());
+ }
+
+ if(LockFile(TheFile, LockStart, 0, LockLength, 0) == 0)
+ {
+ Fail("ERROR: LockFile failed. GetLastError returns %d.\n",
+ GetLastError());
+ }
+
+ return TheFile;
+}
+
+void SignalAndBusyWait(HANDLE TheFile)
+{
+ int size;
+ DWORD BytesWritten;
+
+ size = GetFileSize(TheFile,NULL)+1;
+
+ if(SetFilePointer(TheFile, 0, NULL, FILE_END) == INVALID_SET_FILE_POINTER)
+ {
+ Fail("ERROR: SetFilePointer was unable to set the pointer to the "
+ "end of the file. GetLastError() returned %d.\n",GetLastError());
+ }
+
+ if(WriteFile(TheFile, "x", 1,&BytesWritten, NULL) == 0)
+ {
+ Fail("ERROR: WriteFile was unable to write to the WaitFile. "
+ "GetLastError() returned %d.\n",GetLastError());
+ }
+
+ if(FlushFileBuffers(TheFile) == 0)
+ {
+ Fail("ERROR: FlushFileBuffers failed when flushing the WaitFile. "
+ "GetLastError() returned %d.\n");
+ }
+
+ while(GetFileSize(TheFile,NULL) == size) {}
+}
+
+void SignalFinish(HANDLE TheFile)
+{
+ DWORD BytesWritten;
+
+ if(SetFilePointer(TheFile, 0, NULL, FILE_END) == INVALID_SET_FILE_POINTER)
+ {
+ Fail("ERROR: SetFilePointer was unable to set the pointer to the "
+ "end of the WaitFile. GetLastError() returned %d.\n",
+ GetLastError());
+ }
+
+ if(WriteFile(TheFile, "x", 1,&BytesWritten, NULL) == 0)
+ {
+ Fail("ERROR: WriteFile was unable to write to the WaitFile. "
+ "GetLastError returned %d.\n",GetLastError());
+ }
+
+ if(FlushFileBuffers(TheFile) == 0)
+ {
+ Fail("ERROR: FlushFileBuffers failed when flushing the WaitFile. "
+ "GetLastError() returned %d.\n");
+ }
+
+}
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/UnlockFile/test1/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/UnlockFile/test1/CMakeLists.txt
new file mode 100644
index 0000000000..0e6d6fef4c
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/UnlockFile/test1/CMakeLists.txt
@@ -0,0 +1,36 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(TESTSOURCES
+ test1.c
+)
+
+add_executable(paltest_unlockfile_test1
+ ${TESTSOURCES}
+)
+
+add_dependencies(paltest_unlockfile_test1 coreclrpal)
+
+target_link_libraries(paltest_unlockfile_test1
+ pthread
+ m
+ coreclrpal
+)
+
+
+set(HELPERSOURCES
+ helper.c
+)
+
+add_executable(paltest_unlockfile_test1_helper
+ ${HELPERSOURCES}
+)
+
+add_dependencies(paltest_unlockfile_test1_helper coreclrpal)
+
+target_link_libraries(paltest_unlockfile_test1_helper
+ pthread
+ m
+ coreclrpal
+) \ No newline at end of file
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/UnlockFile/test1/helper.c b/src/pal/tests/palsuite/filemapping_memmgt/UnlockFile/test1/helper.c
new file mode 100644
index 0000000000..c2ef5a6736
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/UnlockFile/test1/helper.c
@@ -0,0 +1,92 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: helper.c
+**
+** Purpose: A child process which will attempt to read from the
+** locked file to ensure it is locked. After it has been unlocked, it
+** will then read again to check that Unlock worked.
+**
+**
+**============================================================*/
+
+#include <palsuite.h>
+#include "../UnlockFile.h"
+
+#define FILENAME "testfile.txt"
+#define WAITFILENAME "waitfile"
+#define BUF_SIZE 128
+
+int __cdecl main(int argc, char *argv[])
+{
+ HANDLE TheFile, WaitFile;
+ int result = 0;
+ char DataBuffer[BUF_SIZE];
+ DWORD BytesRead;
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /* Open the same file that the parent has opened and locked */
+ TheFile = CreateFile(FILENAME,
+ GENERIC_READ|GENERIC_WRITE,
+ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if (TheFile == INVALID_HANDLE_VALUE)
+ {
+ Trace("ERROR: Could not open file '%s' with CreateFile.\n",FILENAME);
+ result = 1;
+ }
+
+ /* Open up the WaitFile that we're using for IPC */
+ WaitFile = CreateFile(WAITFILENAME,
+ GENERIC_READ|GENERIC_WRITE,
+ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ NULL,
+ OPEN_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if (WaitFile == INVALID_HANDLE_VALUE)
+ {
+ Trace("ERROR: Could not open file '%s' with CreateFile. "
+ "GetLastError() returned %d.\n",WAITFILENAME,GetLastError());
+ result = 1;
+ }
+
+
+ /* Check to ensure the parent lock is respected */
+ if(ReadFile(TheFile, DataBuffer, 10, &BytesRead, NULL) != 0)
+ {
+ Trace("ERROR: ReadFile returned success when it should "
+ "have failed. Attempted to read the first 10 bytes "
+ "of a file which was locked by the parent process.\n");
+ result = 1;
+ }
+
+ // Sleep for a bit to give the parent a chance to block before we do.
+ Sleep(1000);
+
+ /* Switch back to the parent, so it can unlock the file */
+ SignalAndBusyWait(WaitFile);
+
+ if(ReadFile(TheFile, DataBuffer, 10, &BytesRead, NULL) == 0)
+ {
+ Trace("ERROR: ReadFile was unable to read from the file after it "
+ "had been unlocked. Attempted to read 10 bytes and ReadFile "
+ "returned 0. GetLastError() returned %d.\n",GetLastError());
+ result = 1;
+ }
+
+ PAL_TerminateEx(result);
+ return result;
+}
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/UnlockFile/test1/test1.c b/src/pal/tests/palsuite/filemapping_memmgt/UnlockFile/test1/test1.c
new file mode 100644
index 0000000000..14634c7f7a
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/UnlockFile/test1/test1.c
@@ -0,0 +1,154 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: test1.c
+**
+** Purpose:
+** Have the parent Lock a file, then have the child check the lock, then
+** have the parent unlock the file, and the child check again.
+** This requires some IPC, which is done here with a crude busy wait on a
+** file (waiting for the file size to change) to avoid too many more
+** dependencies.
+**
+**
+**============================================================*/
+
+#include <palsuite.h>
+#include "../UnlockFile.h"
+
+#define HELPER "helper"
+#define FILENAME "testfile.txt"
+#define WAITFILENAME "waitfile"
+#define BUF_SIZE 128
+
+int RunTest(char* Helper, HANDLE TheFile, HANDLE WaitFile)
+{
+ STARTUPINFO si;
+ PROCESS_INFORMATION pi;
+ DWORD ChildRetCode = 0;
+ DWORD ParentRetCode = 0;
+ DWORD FileEnd;
+
+ ZeroMemory( &si, sizeof(si) );
+ si.cb = sizeof(si);
+ ZeroMemory( &pi, sizeof(pi) );
+
+ /* Load up the helper Process, and then Wait until it signals that it
+ is finished locking.
+ */
+ if(!CreateProcess( NULL, Helper, NULL,
+ NULL, FALSE, 0,
+ NULL, NULL, &si, &pi))
+ {
+ Fail("ERROR: CreateProcess failed to load executable '%s'.\n",Helper);
+ }
+
+ SignalAndBusyWait(WaitFile);
+
+ /* When the child proccess is finished verifying the lock, find the end
+ of the file and unlock the file.
+ */
+
+ FileEnd = SetFilePointer(TheFile, 0, NULL, FILE_END);
+
+ if(FileEnd == INVALID_SET_FILE_POINTER)
+ {
+ Trace("ERROR: SetFilePointer failed to set the file pointer to the "
+ "end of the file. GetLastError() returned %d.\n",
+ GetLastError());
+ ParentRetCode = 1;
+ }
+
+ if(UnlockFile(TheFile, 0, 0, FileEnd, 0) == 0)
+ {
+ Trace("ERROR: The call to UnlockFile returned 0 when attempting to "
+ "unlock the file within the parent. This should have "
+ "succeeded. GetLastError returned %d.\n",GetLastError());
+ ParentRetCode = 1;
+ }
+
+ /* Switch back to the child so that it can ensure the unlock worked
+ properly.
+ */
+
+ SignalFinish(WaitFile);
+ WaitForSingleObject(pi.hProcess,INFINITE);
+
+ /* Get the return value from the helper process */
+ if (GetExitCodeProcess(pi.hProcess, &ChildRetCode) == 0)
+ {
+ Fail("ERROR: GetExitCodeProccess failed when attempting to retrieve "
+ "the exit code of the child process.\n");
+ }
+
+ if(CloseHandle( pi.hProcess ) == 0)
+ {
+ Fail("ERROR: CloseHandle failed to close the process.\n");
+ }
+
+ if(CloseHandle( pi.hThread ) == 0)
+ {
+ Fail("ERROR: CloseHandle failed to close the thread.\n");
+ }
+
+ return (ChildRetCode || ParentRetCode);
+}
+
+int __cdecl main(int argc, char *argv[])
+{
+ HANDLE TheFile = NULL;
+ HANDLE WaitFile = NULL;
+ char* WriteBuffer = "12345678901234567890123456";
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /* Open up the file we'll be using for some crude IPC */
+ WaitFile = CreateFile(WAITFILENAME,
+ GENERIC_READ|GENERIC_WRITE,
+ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ NULL,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if (WaitFile == INVALID_HANDLE_VALUE)
+ {
+ Fail("ERROR: Could not open file '%s' with CreateFile. "
+ "GetLastError() returned %d.\n",WAITFILENAME,GetLastError());
+ }
+
+ /* Call the helper function to Create a file, write 'WriteBuffer' to
+ the file, and lock the file from start to end.
+ */
+ TheFile = CreateAndLockFile(TheFile, FILENAME, WriteBuffer,
+ 0, strlen(WriteBuffer));
+
+ /* Run the test. Better errors are displayed by Trace throughout. */
+ if(RunTest(HELPER, TheFile, WaitFile))
+ {
+ Fail("ERROR: Checking to ensure that Unlock successfully unlocked "
+ "a file failed.\n");
+ }
+
+ if(CloseHandle(TheFile) == 0)
+ {
+ Fail("ERROR: CloseHandle failed to close the file used for "
+ "testing the locks. GetLastError() returns %d.\n",
+ GetLastError());
+ }
+
+ if(CloseHandle(WaitFile) == 0)
+ {
+ Fail("ERROR: CloseHandle failed to close the wait file. "
+ "GetLastError() returns %d.\n",GetLastError());
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/UnlockFile/test1/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/UnlockFile/test1/testinfo.dat
new file mode 100644
index 0000000000..4d0ad6afc9
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/UnlockFile/test1/testinfo.dat
@@ -0,0 +1,17 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = UnlockFile
+Name = Positive test for UnlockFile API
+TYPE = DEFAULT
+EXE1 = test1
+EXE2 = helper
+Description
+= Have the parent Lock a file, then have the child check the lock, then
+= have the parent unlock the file, and the child check again.
+= This requires some IPC, which is done here with a crude busy wait on a
+= file (waiting for the file size to change) to avoid too many more
+= dependencies.
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/UnlockFile/test2/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/UnlockFile/test2/CMakeLists.txt
new file mode 100644
index 0000000000..142b2763cb
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/UnlockFile/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test2.c
+)
+
+add_executable(paltest_unlockfile_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_unlockfile_test2 coreclrpal)
+
+target_link_libraries(paltest_unlockfile_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/UnlockFile/test2/test2.c b/src/pal/tests/palsuite/filemapping_memmgt/UnlockFile/test2/test2.c
new file mode 100644
index 0000000000..22c2cce2fb
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/UnlockFile/test2/test2.c
@@ -0,0 +1,154 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: test2.c
+**
+** Purpose: Open a file, and call Unlock on the file, even though it has yet
+** to be locked. Then lock a portion of the file, and attempt to call unlock
+** on a larger portion of the file. Also, try to unlock a smaller portion
+** than was locked.
+**
+**
+**============================================================*/
+
+#include <palsuite.h>
+#include "../UnlockFile.h"
+
+int __cdecl main(int argc, char *argv[])
+{
+ HANDLE TheFile = NULL;
+ const char lpBuffer[] = "This is a test file.";
+ DWORD bytesWritten;
+ BOOL bRc = TRUE;
+ char fileName[] = "testfile.tmp";
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /* Open a file which is in the directory */
+ TheFile = CreateFile(fileName,
+ GENERIC_READ|GENERIC_WRITE,
+ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ NULL,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if (TheFile == INVALID_HANDLE_VALUE)
+ {
+ Fail("ERROR: Could not open file '%s' with CreateFile. "
+ "GetLastError() returned %d.\n",fileName,GetLastError());
+ }
+
+ bRc = WriteFile(
+ TheFile, // handle to file
+ lpBuffer, // data buffer
+ (DWORD)sizeof(lpBuffer), // number of bytes to write
+ &bytesWritten, // number of bytes written
+ NULL // overlapped buffer
+ );
+
+ if(!bRc)
+ {
+ Trace("ERROR: Could not write to file '%s' with WriteFile.",fileName);
+
+ if(CloseHandle(TheFile) == 0)
+ {
+ Fail("ERROR: CloseHandle failed to close the file.");
+ }
+ Fail("");
+
+ }
+ else if(bytesWritten != (DWORD)sizeof(lpBuffer))
+ {
+ Trace("ERROR: Could not write the correct number of bytes to the "
+ "file '%s' with WriteFile.",fileName);
+
+ if(CloseHandle(TheFile) == 0)
+ {
+ Fail("ERROR: CloseHandle failed to close the file.");
+ }
+ Fail("");
+ }
+
+ /* Call unlock file on an unlocked file, this should return 0 */
+ if(UnlockFile(TheFile, 0, 0, 5, 0) != 0)
+ {
+ Trace("ERROR: Attempted to unlock a file which was not locked and "
+ "the UnlockFile call was successful.\n");
+
+ if(CloseHandle(TheFile) == 0)
+ {
+ Fail("ERROR: CloseHandle failed to close the file.");
+ }
+ Fail("");
+ }
+
+ /* Lock the file */
+ if(LockFile(TheFile, 0, 0, 5, 0) == 0)
+ {
+ Trace("ERROR: Failed to call LockFile on a valid file handle. "
+ "GetLastError returned %d.\n",GetLastError());
+
+ if(CloseHandle(TheFile) == 0)
+ {
+ Fail("ERROR: CloseHandle failed to close the file.");
+ }
+ Fail("");
+ }
+
+ /* Try to unlock more of the file than was locked by LockFile */
+ if(UnlockFile(TheFile, 0, 0, 10, 0) != 0)
+ {
+ Trace("ERROR: Attempted to unlock bytes 0 to 9, but only bytes "
+ "0 to 4 are locked. But, UnlockFile was successful, when it "
+ "should have failed.\n");
+
+ if(CloseHandle(TheFile) == 0)
+ {
+ Fail("ERROR: CloseHandle failed to close the file.");
+ }
+ Fail("");
+ }
+
+ /* Try to unlock less of the file than was locked by LockFile */
+ if(UnlockFile(TheFile, 0, 0, 3, 0) != 0)
+ {
+ Trace("ERROR: Attempted to unlock bytes 0 to 2, but the bytes 0 to "
+ "4 were locked by LockFile. Unlockfile should have failed "
+ "when attempting this operation.\n");
+
+ if(CloseHandle(TheFile) == 0)
+ {
+ Fail("ERROR: CloseHandle failed to close the file.");
+ }
+ Fail("");
+ }
+
+ /* Properly unlock the file */
+ if(UnlockFile(TheFile, 0, 0, 5, 0) == 0)
+ {
+ Trace("ERROR: UnlockFile failed to unlock bytes 0 to 4 of the file. "
+ "GetLastError returned %d.\n",GetLastError());
+
+ if(CloseHandle(TheFile) == 0)
+ {
+ Fail("ERROR: CloseHandle failed to close the file.");
+ }
+ Fail("");
+ }
+
+ if(CloseHandle(TheFile) == 0)
+ {
+ Fail("ERROR: CloseHandle failed to close the file.\n");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/UnlockFile/test2/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/UnlockFile/test2/testinfo.dat
new file mode 100644
index 0000000000..932a4a2b8a
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/UnlockFile/test2/testinfo.dat
@@ -0,0 +1,16 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = UnlockFile
+Name = Positive test for UnlockFile API
+TYPE = DEFAULT
+EXE1 = test2
+Description
+= Open a file, and call Unlock on the file, even though it has yet
+= to be locked. Then lock a portion of the file, and attempt to call unlock
+= on a larger portion of the file. Also, try to unlock a smaller portion
+= than was locked.
+
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/UnlockFile/test3/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/UnlockFile/test3/CMakeLists.txt
new file mode 100644
index 0000000000..b4ec37c88c
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/UnlockFile/test3/CMakeLists.txt
@@ -0,0 +1,36 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(TESTSOURCES
+ test3.c
+)
+
+add_executable(paltest_unlockfile_test3
+ ${TESTSOURCES}
+)
+
+add_dependencies(paltest_unlockfile_test3 coreclrpal)
+
+target_link_libraries(paltest_unlockfile_test3
+ pthread
+ m
+ coreclrpal
+)
+
+
+set(HELPERSOURCES
+ helper.c
+)
+
+add_executable(paltest_unlockfile_test3_helper
+ ${HELPERSOURCES}
+)
+
+add_dependencies(paltest_unlockfile_test3_helper coreclrpal)
+
+target_link_libraries(paltest_unlockfile_test3_helper
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/UnlockFile/test3/helper.c b/src/pal/tests/palsuite/filemapping_memmgt/UnlockFile/test3/helper.c
new file mode 100644
index 0000000000..650abf49ad
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/UnlockFile/test3/helper.c
@@ -0,0 +1,103 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: helper.c
+**
+** Purpose: A child process which will lock a portion of the file,
+** then try to unlock a portion of the file which was locked by the parent.
+**
+**
+**============================================================*/
+
+#include <palsuite.h>
+#include "../UnlockFile.h"
+
+#define FILENAME "testfile.txt"
+#define WAITFILENAME "waitfile"
+#define BUF_SIZE 128
+
+int __cdecl main(int argc, char *argv[])
+{
+ HANDLE TheFile, WaitFile;
+ int result = 0;
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /* Open the same file that the parent has opened and locked */
+ TheFile = CreateFile(FILENAME,
+ GENERIC_READ|GENERIC_WRITE,
+ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if (TheFile == INVALID_HANDLE_VALUE)
+ {
+ Trace("ERROR: Could not open file '%s' with CreateFile.\n",FILENAME);
+ result = 1;
+ }
+
+ /* Open up the WaitFile that we're using for IPC */
+ WaitFile = CreateFile(WAITFILENAME,
+ GENERIC_READ|GENERIC_WRITE,
+ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ NULL,
+ OPEN_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if (WaitFile == INVALID_HANDLE_VALUE)
+ {
+ Trace("ERROR: Could not open file '%s' with CreateFile. "
+ "GetLastError() returned %d.\n",WAITFILENAME,GetLastError());
+ result = 1;
+ }
+
+ /* Lock a section of the file different from which was locked in the
+ parent proccess
+ */
+ if(LockFile(TheFile, 10, 0, 10, 0) == 0)
+ {
+ Trace("ERROR: The LockFile call within the child failed to lock "
+ "the file. GetLastError() returned %d.\n",GetLastError());
+ result = 1;
+ }
+
+ /* Attempt to unlock the portion of the file which was locked within the
+ parent process.
+ */
+ if(UnlockFile(TheFile, 0, 0, 10, 0) != 0)
+ {
+ Trace("ERROR: The UnlockFile call within the child succeeded in "
+ "calling UnlockFile on the portion of the file which was "
+ "locked by the parent.\n");
+ result = 1;
+ }
+
+ // Sleep for a bit to give the parent a chance to block before we do.
+ Sleep(1000);
+
+ /* Switch back to the parent, so it can check the child lock */
+ SignalAndBusyWait(WaitFile);
+
+ /* Finally, clean up the lock which was done within this proccess and
+ exit.
+ */
+ if(UnlockFile(TheFile, 10, 0, 10, 0) == 0)
+ {
+ Trace("ERROR: The UnlockFile call within the child failed to unlock "
+ "the portion of the file which was locked by the child. "
+ "GetLastError() returned %d.\n", GetLastError());
+ result = 1;
+ }
+
+ PAL_TerminateEx(result);
+ return result;
+}
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/UnlockFile/test3/test3.c b/src/pal/tests/palsuite/filemapping_memmgt/UnlockFile/test3/test3.c
new file mode 100644
index 0000000000..cf27aba0a3
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/UnlockFile/test3/test3.c
@@ -0,0 +1,142 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: test3.c
+**
+** Purpose:
+** Lock a portion of the file with the parent. Then have the child lock
+** another portion. Have the child attempt to call Unlock on the parent's
+** locked data, and the parent do the same to the child. Ensure that the
+** locks are respected.
+**
+**
+**============================================================*/
+
+#include <palsuite.h>
+#include "../UnlockFile.h"
+
+#define HELPER "helper"
+#define FILENAME "testfile.txt"
+#define WAITFILENAME "waitfile"
+#define BUF_SIZE 128
+
+int RunTest(char* Helper, HANDLE TheFile, HANDLE WaitFile)
+{
+ STARTUPINFO si;
+ PROCESS_INFORMATION pi;
+ DWORD ChildRetCode = 0;
+ DWORD ParentRetCode = 0;
+
+ ZeroMemory( &si, sizeof(si) );
+ si.cb = sizeof(si);
+ ZeroMemory( &pi, sizeof(pi) );
+
+ /* Load up the helper Process, and then Wait until it signals that it
+ is finished locking.
+ */
+ if(!CreateProcess( NULL, Helper, NULL,
+ NULL, FALSE, 0,
+ NULL, NULL, &si, &pi))
+ {
+ Fail("ERROR: CreateProcess failed to load executable '%s'.\n",Helper);
+ }
+
+ SignalAndBusyWait(WaitFile);
+
+ /* When the child proccess is finished setting its lock and testing the
+ parent lock, then the parent can test the child's lock.
+ */
+
+ if(UnlockFile(TheFile, 10, 0, 10, 0) != 0)
+ {
+ Trace("ERROR: The parent proccess called Unlock on the child "
+ "proccesses lock, and the function returned non-zero, when "
+ "it should have failed.\n");
+ ParentRetCode = 1;
+ }
+
+ /* Switch back to the child so that it can unlock its portion and
+ cleanup.
+ */
+
+ SignalFinish(WaitFile);
+ WaitForSingleObject(pi.hProcess,INFINITE);
+
+ /* Get the return value from the helper process */
+ if (GetExitCodeProcess(pi.hProcess, &ChildRetCode) == 0)
+ {
+ Fail("ERROR: GetExitCodeProccess failed when attempting to retrieve "
+ "the exit code of the child process.\n");
+ }
+
+ if(CloseHandle( pi.hProcess ) == 0)
+ {
+ Fail("ERROR: CloseHandle failed to close the process.\n");
+ }
+
+ if(CloseHandle( pi.hThread ) == 0)
+ {
+ Fail("ERROR: CloseHandle failed to close the thread.\n");
+ }
+
+ return (ChildRetCode || ParentRetCode);
+}
+
+int __cdecl main(int argc, char *argv[])
+{
+ HANDLE TheFile = NULL;
+ HANDLE WaitFile = NULL;
+ char* WriteBuffer = "12345678901234567890123456";
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /* Open up the file we'll be using for some crude IPC */
+ WaitFile = CreateFile(WAITFILENAME,
+ GENERIC_READ|GENERIC_WRITE,
+ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ NULL,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if (WaitFile == INVALID_HANDLE_VALUE)
+ {
+ Fail("ERROR: Could not open file '%s' with CreateFile. "
+ "GetLastError() returned %d.\n",WAITFILENAME,GetLastError());
+ }
+
+ /* Call the helper function to Create a file, write 'WriteBuffer' to
+ the file, and lock the file from bytes 0-9.
+ */
+ TheFile = CreateAndLockFile(TheFile, FILENAME, WriteBuffer,
+ 0, 10);
+
+ /* Run the test. Better errors are displayed by Trace throughout. */
+ if(RunTest(HELPER, TheFile, WaitFile))
+ {
+ Fail("ERROR: The test to check that the Unlock will not work on "
+ "on locks set by other proccesses failed.\n");
+ }
+
+ if(CloseHandle(TheFile) == 0)
+ {
+ Fail("ERROR: CloseHandle failed to close the file used for "
+ "testing the locks. GetLastError() returns %d.\n",
+ GetLastError());
+ }
+
+ if(CloseHandle(WaitFile) == 0)
+ {
+ Fail("ERROR: CloseHandle failed to close the wait file. "
+ "GetLastError() returns %d.\n",GetLastError());
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/UnlockFile/test3/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/UnlockFile/test3/testinfo.dat
new file mode 100644
index 0000000000..bf7ec5f809
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/UnlockFile/test3/testinfo.dat
@@ -0,0 +1,17 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = UnlockFile
+Name = Positive test for UnlockFile API
+TYPE = DEFAULT
+EXE1 = test3
+EXE2 = helper
+Description
+= Lock a portion of the file with the parent. Then have the child lock
+= another portion. Have the child attempt to call Unlock on the parent's
+= locked data, and the parent do the same to the child. Ensure that the
+= locks are respected.
+
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/UnlockFile/test4/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/UnlockFile/test4/CMakeLists.txt
new file mode 100644
index 0000000000..d6bee307c2
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/UnlockFile/test4/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test4.c
+)
+
+add_executable(paltest_unlockfile_test4
+ ${SOURCES}
+)
+
+add_dependencies(paltest_unlockfile_test4 coreclrpal)
+
+target_link_libraries(paltest_unlockfile_test4
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/UnlockFile/test4/test4.c b/src/pal/tests/palsuite/filemapping_memmgt/UnlockFile/test4/test4.c
new file mode 100644
index 0000000000..55abcd24bc
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/UnlockFile/test4/test4.c
@@ -0,0 +1,187 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: test4.c
+**
+** Purpose: Pass an invalid handle to UnlockFile. Pass a null handle to
+** UnlockFile. Create a file and lock two consecuative regions and call
+** UnlockFile on the whole region (this should fail, see msdn)
+**
+**
+**============================================================*/
+
+#include <palsuite.h>
+#include "../UnlockFile.h"
+
+int __cdecl main(int argc, char *argv[])
+{
+ HANDLE TheFile = NULL;
+ const char lpBuffer[] = "This is a test file.";
+ DWORD bytesWritten;
+ BOOL bRc = TRUE;
+ char fileName[] = "testfile.tmp";
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /* Open a file which is in the directory */
+ TheFile = CreateFile(fileName,
+ GENERIC_READ|GENERIC_WRITE,
+ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ NULL,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if (TheFile == INVALID_HANDLE_VALUE)
+ {
+ Fail("ERROR: Could not open file '%s' with CreateFile. "
+ "GetLastError() returned %d.\n",fileName,GetLastError());
+ }
+
+ bRc = WriteFile(
+ TheFile, // handle to file
+ lpBuffer, // data buffer
+ (DWORD)sizeof(lpBuffer), // number of bytes to write
+ &bytesWritten, // number of bytes written
+ NULL // overlapped buffer
+ );
+
+ if(!bRc)
+ {
+ Trace("ERROR: Could not write to file '%s' with WriteFile.",fileName);
+
+ if(CloseHandle(TheFile) == 0)
+ {
+ Fail("ERROR: CloseHandle failed to close the file.");
+ }
+ Fail("");
+
+ }
+ else if(bytesWritten != (DWORD)sizeof(lpBuffer))
+ {
+ Trace("ERROR: Could not write the correct number of bytes to the "
+ "file '%s' with WriteFile.",fileName);
+
+ if(CloseHandle(TheFile) == 0)
+ {
+ Fail("ERROR: CloseHandle failed to close the file.");
+ }
+ Fail("");
+ }
+
+ if(CloseHandle(TheFile) == 0)
+ {
+ Fail("ERROR: CloseHandle failed to close the file.\n");
+ }
+
+
+ /* Test an invalid handle and a NULL handle */
+ if(UnlockFile(TheFile, 0, 0, 0, 0) != 0)
+ {
+ Fail("ERROR: Called UnlockFile on an invalid HANDLE and it "
+ "returned a success value.\n");
+ }
+
+ if(UnlockFile(NULL, 0, 0, 0, 0) != 0)
+ {
+ Fail("ERROR: Called UnlockFile with NULL passed for the HANDLE and "
+ "it returned a success value.\n");
+ }
+
+ /* Re-open the file */
+ TheFile = CreateFile(fileName,
+ GENERIC_READ|GENERIC_WRITE,
+ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ NULL,
+ OPEN_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if (TheFile == INVALID_HANDLE_VALUE)
+ {
+ Fail("ERROR: Could not open file '%s' with CreateFile. "
+ "GetLastError() returned %d.\n",fileName,GetLastError());
+ }
+
+ /* Lock two consecuative regions of this file */
+ if(LockFile(TheFile, 0, 0, 5, 0) == 0)
+ {
+ Trace("ERROR: LockFile failed attempting to lock bytes 0-4. "
+ "GetLastError() returned %d.\n",GetLastError());
+
+ if(CloseHandle(TheFile) == 0)
+ {
+ Fail("ERROR: CloseHandle failed to close the file.");
+ }
+ Fail("");
+ }
+
+ if(LockFile(TheFile, 5, 0, 5, 0) == 0)
+ {
+ Fail("ERROR: LockFile failed attempting to lock bytes 5-9. "
+ "GetLastError() returned %d.\n",GetLastError());
+
+ if(CloseHandle(TheFile) == 0)
+ {
+ Fail("ERROR: CloseHandle failed to close the file.");
+ }
+ Fail("");
+ }
+
+ /* Attempt to unlock the entire region which was locked with one
+ call to UnlockFile. This should fail.
+ */
+ if(UnlockFile(TheFile, 0, 0, 10, 0) != 0)
+ {
+ Fail("ERROR: Called UnlockFile on bytes 0-9 which were locked with "
+ "two seperate LockFile calls. This should have failed. "
+ "UnlockFile will not unlock consecuative locked regions.\n");
+
+ if(CloseHandle(TheFile) == 0)
+ {
+ Fail("ERROR: CloseHandle failed to close the file.");
+ }
+ Fail("");
+ }
+
+
+ /* Now, unlock the regions one at a time. */
+ if(UnlockFile(TheFile, 0, 0, 5, 0) == 0)
+ {
+ Fail("ERROR: UnlockFile failed when attempting to unlock bytes "
+ "0-4 of the file. GetLastError() returned %d.\n",GetLastError());
+
+ if(CloseHandle(TheFile) == 0)
+ {
+ Fail("ERROR: CloseHandle failed to close the file.");
+ }
+ Fail("");
+ }
+
+ if(UnlockFile(TheFile, 5, 0, 5, 0) == 0)
+ {
+ Fail("ERROR: UnlockFile failed when attempting to unlock bytes "
+ "5-9 of the file. GetLastError() returned %d.\n",GetLastError());
+
+ if(CloseHandle(TheFile) == 0)
+ {
+ Fail("ERROR: CloseHandle failed to close the file.");
+ }
+ Fail("");
+ }
+
+ if(CloseHandle(TheFile) == 0)
+ {
+ Fail("ERROR: CloseHandle failed to close the file.\n");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/UnlockFile/test4/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/UnlockFile/test4/testinfo.dat
new file mode 100644
index 0000000000..4f3885b978
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/UnlockFile/test4/testinfo.dat
@@ -0,0 +1,16 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = UnlockFile
+Name = Positive test for UnlockFile API
+TYPE = DEFAULT
+EXE1 = test4
+Description
+= Pass an invalid handle to UnlockFile. Pass a null handle to
+= UnlockFile. Create a file and lock two consecuative regions and call
+= UnlockFile on the whole region (this should fail, see msdn)
+
+
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/UnmapViewOfFile/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/UnmapViewOfFile/CMakeLists.txt
new file mode 100644
index 0000000000..ef14ea5352
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/UnmapViewOfFile/CMakeLists.txt
@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/UnmapViewOfFile/test1/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/UnmapViewOfFile/test1/CMakeLists.txt
new file mode 100644
index 0000000000..5ebda77ba6
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/UnmapViewOfFile/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ UnmapViewOfFile.c
+)
+
+add_executable(paltest_unmapviewoffile_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_unmapviewoffile_test1 coreclrpal)
+
+target_link_libraries(paltest_unmapviewoffile_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/UnmapViewOfFile/test1/UnmapViewOfFile.c b/src/pal/tests/palsuite/filemapping_memmgt/UnmapViewOfFile/test1/UnmapViewOfFile.c
new file mode 100644
index 0000000000..a970ccc3b5
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/UnmapViewOfFile/test1/UnmapViewOfFile.c
@@ -0,0 +1,184 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: UnMapViewOfFile.c
+**
+** Purpose: Positive test the MapViewOfFile API.
+** Call MapViewOfFile with access FILE_MAP_ALL_ACCESS.
+**
+** Depends: CreateFile,
+** GetFileSize,
+** memset,
+** memcpy,
+** memcmp,
+** ReadFile,
+** UnMapViewOfFile,
+** CreateFileMapping,
+** CloseHandle.
+
+**
+**============================================================*/
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ const int MappingSize = 2048;
+ HANDLE hFile;
+ HANDLE hFileMapping;
+ LPVOID lpMapViewAddress;
+ char buf[] = "this is a test string";
+ char ch[2048];
+ char readString[2048];
+ char lpFileName[] = "test.tmp";
+ DWORD dwBytesRead;
+ BOOL bRetVal;
+
+ /* Initialize the PAL environment.
+ */
+ if(0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ /* Create a file handle with CreateFile.
+ */
+ hFile = CreateFile( lpFileName,
+ GENERIC_WRITE|GENERIC_READ,
+ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ NULL,
+ OPEN_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+ if (hFile == INVALID_HANDLE_VALUE)
+ {
+ Fail("ERROR: %u :unable to create file \"%s\".\n",
+ GetLastError(),
+ lpFileName);
+ }
+
+ /* Initialize the buffers.
+ */
+ memset(ch, 0, MappingSize);
+ memset(readString, 0, MappingSize);
+
+ /* Create a unnamed file-mapping object with file handle FileHandle
+ * and with PAGE_READWRITE protection.
+ */
+ hFileMapping = CreateFileMapping(
+ hFile,
+ NULL, /*not inherited*/
+ PAGE_READWRITE, /*read and wite*/
+ 0, /*high-order of object size*/
+ MappingSize, /*low-orger of object size*/
+ NULL); /*unnamed object*/
+
+ if(NULL == hFileMapping)
+ {
+ Trace("ERROR:%u: Failed to create File Mapping.\n",
+ GetLastError());
+ CloseHandle(hFile);
+ Fail("");
+ }
+
+ /* maps a view of a file into the address space of the calling process.
+ */
+ lpMapViewAddress = MapViewOfFile(
+ hFileMapping,
+ FILE_MAP_ALL_ACCESS, /* access code */
+ 0, /* high order offset */
+ 0, /* low order offset */
+ MappingSize); /* number of bytes for map */
+
+ if(NULL == lpMapViewAddress)
+ {
+ Trace("ERROR:%u: Failed to call MapViewOfFile API to map a view"
+ " of file!\n",
+ GetLastError());
+ CloseHandle(hFile);
+ CloseHandle(hFileMapping);
+ Fail("");
+ }
+
+ /* Write to the MapView and copy the MapViewOfFile
+ * to buffer, so we can compare with value read from
+ * file directly.
+ */
+
+ memcpy(lpMapViewAddress, buf, strlen(buf));
+ memcpy(ch, (LPCSTR)lpMapViewAddress, MappingSize);
+
+ /* Read from the File handle.
+ */
+ bRetVal = ReadFile(hFile,
+ readString,
+ strlen(buf),
+ &dwBytesRead,
+ NULL);
+
+ if (bRetVal == FALSE)
+ {
+ Trace("ERROR: %u :unable to read from file handle "
+ "hFile=0x%lx\n",
+ GetLastError(),
+ hFile);
+ CloseHandle(hFile);
+ CloseHandle(hFileMapping);
+ Fail("");
+ }
+
+ if (memcmp(ch, readString, strlen(readString)) != 0)
+ {
+ Trace("ERROR: Read string from file \"%s\", is "
+ "not equal to string written through MapView "
+ "\"%s\".\n",
+ readString,
+ ch);
+ CloseHandle(hFile);
+ CloseHandle(hFileMapping);
+ Fail("");
+ }
+
+ /* Unmap the view of file.
+ */
+ if(UnmapViewOfFile(lpMapViewAddress) == FALSE)
+ {
+ Trace("ERROR: Failed to call UnmapViewOfFile API to"
+ " unmap the view of a file, error code=%u\n",
+ GetLastError());
+ CloseHandle(hFile);
+ CloseHandle(hFileMapping);
+ Fail("");
+ }
+
+ /* Re-initialize the buffer.
+ */
+ memset(ch, 0, MappingSize);
+
+ /* Close handle to created file mapping.
+ */
+ if(CloseHandle(hFileMapping) == FALSE)
+ {
+ Trace("ERROR:%u:Failed to call CloseHandle API "
+ "to close a file mapping handle.",
+ GetLastError());
+ CloseHandle(hFile);
+ Fail("");
+ }
+
+ /* Close handle to create file.
+ */
+ if(CloseHandle(hFile) == FALSE)
+ {
+ Fail("ERROR:%u:Failed to call CloseHandle API "
+ "to close a file handle.",
+ GetLastError());
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/UnmapViewOfFile/test1/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/UnmapViewOfFile/test1/testinfo.dat
new file mode 100644
index 0000000000..8418015360
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/UnmapViewOfFile/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = UnmapViewOfFile
+Name = Positive test UnmapViewOfFile API to unmap a view of file
+TYPE = DEFAULT
+EXE1 = unmapviewoffile
+LANG = cpp
+Description
+= Test the UnmapViewOfFile to unmap a view of file.
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/UnmapViewOfFile/test2/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/UnmapViewOfFile/test2/CMakeLists.txt
new file mode 100644
index 0000000000..5c12cf9825
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/UnmapViewOfFile/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ unmapviewoffile.c
+)
+
+add_executable(paltest_unmapviewoffile_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_unmapviewoffile_test2 coreclrpal)
+
+target_link_libraries(paltest_unmapviewoffile_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/UnmapViewOfFile/test2/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/UnmapViewOfFile/test2/testinfo.dat
new file mode 100644
index 0000000000..29e847a82f
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/UnmapViewOfFile/test2/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = UnmapViewOfFile
+Name = Negative test UnmapViewOfFile API to unmap a view of file
+TYPE = DEFAULT
+EXE1 = unmapviewoffile
+Description
+= Test the UnmapViewOfFile to unmap a view of file
+= negative test by passing a NULL mapping address.
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/UnmapViewOfFile/test2/unmapviewoffile.c b/src/pal/tests/palsuite/filemapping_memmgt/UnmapViewOfFile/test2/unmapviewoffile.c
new file mode 100644
index 0000000000..2ca185d234
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/UnmapViewOfFile/test2/unmapviewoffile.c
@@ -0,0 +1,42 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: UnmapViewOfFile.c (test 2)
+**
+** Purpose: Negative test the UnmapViewOfFile API.
+** Call UnmapViewOfFile to unmap a view of
+** NULL.
+**
+**
+**============================================================*/
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ int err;
+
+ /*Initialize the PAL environment*/
+ err = PAL_Initialize(argc, argv);
+ if(0 != err)
+ {
+ return FAIL;
+ }
+
+ /* Negative test the UnmapViewOfFile by passing a NULL*/
+ /* mapping address handle*/
+ err = UnmapViewOfFile(NULL);
+ if(0 != err)
+ {
+ Fail("ERROR: Able to call UnmapViewOfFile API "
+ "by passing a NULL mapping address.\n" );
+
+ }
+
+ /* Terminate the PAL.
+ */
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/CMakeLists.txt
new file mode 100644
index 0000000000..eafaa66856
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/CMakeLists.txt
@@ -0,0 +1,24 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test10)
+add_subdirectory(test11)
+add_subdirectory(test12)
+add_subdirectory(test13)
+add_subdirectory(test14)
+add_subdirectory(test15)
+add_subdirectory(test16)
+add_subdirectory(test17)
+add_subdirectory(test18)
+add_subdirectory(test19)
+add_subdirectory(test2)
+add_subdirectory(test20)
+add_subdirectory(test21)
+add_subdirectory(test3)
+add_subdirectory(test4)
+add_subdirectory(test5)
+add_subdirectory(test6)
+add_subdirectory(test7)
+add_subdirectory(test8)
+add_subdirectory(test9)
+
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test1/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test1/CMakeLists.txt
new file mode 100644
index 0000000000..90ba41bd79
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ VirtualAlloc.c
+)
+
+add_executable(paltest_virtualalloc_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_virtualalloc_test1 coreclrpal)
+
+target_link_libraries(paltest_virtualalloc_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test1/VirtualAlloc.c b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test1/VirtualAlloc.c
new file mode 100644
index 0000000000..26ee942ba1
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test1/VirtualAlloc.c
@@ -0,0 +1,50 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: virtualalloc.c
+**
+** Purpose: Positive test the VirtualAlloc API.
+** Call VirtualAlloc with MEM_COMMIT allocation type
+** and PAGE_READONLY access protection
+
+**
+**============================================================*/
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ int err;
+ LPVOID lpVirtualAddress;
+
+
+ //Initialize the PAL environment
+ err = PAL_Initialize(argc, argv);
+ if(0 != err)
+ {
+ ExitProcess(FAIL);
+ }
+
+ //Allocate the physical storage in memory or in the paging file on disk
+ lpVirtualAddress = VirtualAlloc(NULL,//system determine where to allocate the region
+ 1024, //specify the size
+ MEM_COMMIT, //allocation type
+ PAGE_READONLY); //access protection
+ if(NULL == lpVirtualAddress)
+ {
+ Fail("\nFailed to call VirtualAlloc API!\n");
+ }
+
+ //decommit the specified region
+ err = VirtualFree(lpVirtualAddress,1024,MEM_DECOMMIT);
+ if(0 == err)
+ {
+ Fail("\nFailed to call VirtualFree API!\n");
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test1/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test1/testinfo.dat
new file mode 100644
index 0000000000..5b8311a05d
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = VirtualAlloc
+Name = Positive test for VirtualAlloc API
+TYPE = DEFAULT
+EXE1 = virtualalloc
+Description
+=Test the VirtualAlloc with MEM_COMMIT allocation type
+=and PAGE_READONLY access protection
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test10/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test10/CMakeLists.txt
new file mode 100644
index 0000000000..51b0e1d92e
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test10/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ VirtualAlloc.c
+)
+
+add_executable(paltest_virtualalloc_test10
+ ${SOURCES}
+)
+
+add_dependencies(paltest_virtualalloc_test10 coreclrpal)
+
+target_link_libraries(paltest_virtualalloc_test10
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test10/VirtualAlloc.c b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test10/VirtualAlloc.c
new file mode 100644
index 0000000000..ac06b9b5c8
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test10/VirtualAlloc.c
@@ -0,0 +1,48 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: virtualalloc.c
+**
+** Purpose: Positive test the VirtualAlloc API.
+** Call VirtualAlloc with MEM_RESERVE allocation type
+** and PAGE_EXECUTE_READ access protection
+
+**
+**============================================================*/
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ int err;
+ LPVOID lpVirtualAddress;
+
+ //Initialize the PAL environment
+ err = PAL_Initialize(argc, argv);
+ if(0 != err)
+ {
+ ExitProcess(FAIL);
+ }
+
+ //Allocate the physical storage in memory or in the paging file on disk
+ lpVirtualAddress = VirtualAlloc(NULL,//system determine where to allocate the region
+ 1024, //specify the size
+ MEM_RESERVE, //allocation type
+ PAGE_EXECUTE_READ); //access protection
+ if(NULL == lpVirtualAddress)
+ {
+ Fail("\nFailed to call VirtualAlloc API!\n");
+ }
+
+ //decommit the specified region
+ err = VirtualFree(lpVirtualAddress,1024,MEM_DECOMMIT);
+ if(0 == err)
+ {
+ Fail("\nFailed to call VirtualFree API!\n");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test10/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test10/testinfo.dat
new file mode 100644
index 0000000000..960f2265d5
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test10/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = VirtualAlloc
+Name = Positive test for VirtualAlloc API
+TYPE = DEFAULT
+EXE1 = virtualalloc
+Description
+=Test the VirtualAlloc with MEM_RESERVE allocation type
+=and PAGE_EXECUTE_READ access protection
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test11/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test11/CMakeLists.txt
new file mode 100644
index 0000000000..adff47087b
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test11/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ VirtualAlloc.c
+)
+
+add_executable(paltest_virtualalloc_test11
+ ${SOURCES}
+)
+
+add_dependencies(paltest_virtualalloc_test11 coreclrpal)
+
+target_link_libraries(paltest_virtualalloc_test11
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test11/VirtualAlloc.c b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test11/VirtualAlloc.c
new file mode 100644
index 0000000000..a3df39b634
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test11/VirtualAlloc.c
@@ -0,0 +1,49 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: virtualalloc.c
+**
+** Purpose: Positive test the VirtualAlloc API.
+** Call VirtualAlloc with MEM_RESERVE allocation type
+** and PAGE_READONLY access protection
+**
+
+**
+**============================================================*/
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ int err;
+ LPVOID lpVirtualAddress;
+
+
+ //Initialize the PAL environment
+ err = PAL_Initialize(argc, argv);
+ if(0 != err)
+ {
+ ExitProcess(FAIL);
+ }
+ //Allocate the physical storage in memory or in the paging file on disk
+ lpVirtualAddress = VirtualAlloc(NULL,//system determine where to allocate the region
+ 1024, //specify the size
+ MEM_RESERVE, //allocation type
+ PAGE_EXECUTE_READWRITE); //access protection
+ if(NULL == lpVirtualAddress)
+ {
+ Fail("\nFailed to call VirtualAlloc API!\n");
+ }
+
+ //decommit the specified region
+ err = VirtualFree(lpVirtualAddress,1024,MEM_DECOMMIT);
+ if(0 == err)
+ {
+ Fail("\nFailed to call VirtualFree API!\n");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test11/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test11/testinfo.dat
new file mode 100644
index 0000000000..5d9f0ad880
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test11/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = VirtualAlloc
+Name = Positive test for VirtualAlloc API
+TYPE = DEFAULT
+EXE1 = virtualalloc
+Description
+=Test the VirtualAlloc with MEM_RESERVE allocation type
+=and PAGE_EXECUTE_READWRITE access protection
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test12/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test12/CMakeLists.txt
new file mode 100644
index 0000000000..26f303573e
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test12/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ VirtualAlloc.c
+)
+
+add_executable(paltest_virtualalloc_test12
+ ${SOURCES}
+)
+
+add_dependencies(paltest_virtualalloc_test12 coreclrpal)
+
+target_link_libraries(paltest_virtualalloc_test12
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test12/VirtualAlloc.c b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test12/VirtualAlloc.c
new file mode 100644
index 0000000000..8b3508635f
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test12/VirtualAlloc.c
@@ -0,0 +1,48 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: virtualalloc.c
+**
+** Purpose: Positive test the VirtualAlloc API.
+** Call VirtualAlloc with MEM_RESERVE allocation type
+** and PAGE_NOACCESS access protection
+
+**
+**============================================================*/
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ int err;
+ LPVOID lpVirtualAddress;
+
+ //Initialize the PAL environment
+ err = PAL_Initialize(argc, argv);
+ if(0 != err)
+ {
+ ExitProcess(FAIL);
+ }
+
+ //Allocate the physical storage in memory or in the paging file on disk
+ lpVirtualAddress = VirtualAlloc(NULL,//system determine where to allocate the region
+ 1024, //specify the size
+ MEM_RESERVE, //allocation type
+ PAGE_NOACCESS); //access protection
+ if(NULL == lpVirtualAddress)
+ {
+ Fail("\nFailed to call VirtualAlloc API!\n");
+ }
+
+ //decommit the specified region
+ err = VirtualFree(lpVirtualAddress,1024,MEM_DECOMMIT);
+ if(0 == err)
+ {
+ Fail("\nFailed to call VirtualFree API!\n");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test12/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test12/testinfo.dat
new file mode 100644
index 0000000000..ac2b91c0dc
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test12/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = VirtualAlloc
+Name = Positive test for VirtualAlloc API
+TYPE = DEFAULT
+EXE1 = virtualalloc
+Description
+=Test the VirtualAlloc with MEM_COMMIT allocation type
+=and PAGE_NOACCESS access protection
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test13/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test13/CMakeLists.txt
new file mode 100644
index 0000000000..f85cbdc694
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test13/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ VirtualAlloc.c
+)
+
+add_executable(paltest_virtualalloc_test13
+ ${SOURCES}
+)
+
+add_dependencies(paltest_virtualalloc_test13 coreclrpal)
+
+target_link_libraries(paltest_virtualalloc_test13
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test13/VirtualAlloc.c b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test13/VirtualAlloc.c
new file mode 100644
index 0000000000..d2109c0339
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test13/VirtualAlloc.c
@@ -0,0 +1,48 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: virtualalloc.c
+**
+** Purpose: Positive test the VirtualAlloc API.
+** Call VirtualAlloc with MEM_COMMIT|MEM_TOP_DOWN allocation type
+** and PAGE_READONLY access protection
+
+**
+**============================================================*/
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ int err;
+ LPVOID lpVirtualAddress;
+
+ //Initialize the PAL environment
+ err = PAL_Initialize(argc, argv);
+ if(0 != err)
+ {
+ ExitProcess(FAIL);
+ }
+
+ //Allocate the physical storage in memory or in the paging file on disk
+ lpVirtualAddress = VirtualAlloc(NULL,//system determine where to allocate the region
+ 1024, //specify the size
+ MEM_COMMIT|MEM_TOP_DOWN, //allocation type
+ PAGE_READONLY); //access protection
+ if(NULL == lpVirtualAddress)
+ {
+ Fail("\nFailed to call VirtualAlloc API!\n");
+ }
+
+ //decommit the specified region
+ err = VirtualFree(lpVirtualAddress,1024,MEM_DECOMMIT);
+ if(0 == err)
+ {
+ Fail("\nFailed to call VirtualFree API!\n");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test13/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test13/testinfo.dat
new file mode 100644
index 0000000000..a571e9f8d2
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test13/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = VirtualAlloc
+Name = Positive test for VirtualAlloc API
+TYPE = DEFAULT
+EXE1 = virtualalloc
+Description
+=Test the VirtualAlloc with MEM_COMMIT|MEM_TOP_DOWN allocation type
+=and PAGE_READONLY access protection
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test14/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test14/CMakeLists.txt
new file mode 100644
index 0000000000..41ed0ca208
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test14/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ VirtualAlloc.c
+)
+
+add_executable(paltest_virtualalloc_test14
+ ${SOURCES}
+)
+
+add_dependencies(paltest_virtualalloc_test14 coreclrpal)
+
+target_link_libraries(paltest_virtualalloc_test14
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test14/VirtualAlloc.c b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test14/VirtualAlloc.c
new file mode 100644
index 0000000000..49bd21875e
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test14/VirtualAlloc.c
@@ -0,0 +1,48 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: virtualalloc.c
+**
+** Purpose: Positive test the VirtualAlloc API.
+** Call VirtualAlloc with MEM_COMMIT|MEM_TOP_DOWN allocation type
+** and PAGE_READWRITE access protection
+
+**
+**============================================================*/
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ int err;
+ LPVOID lpVirtualAddress;
+
+ //Initialize the PAL environment
+ err = PAL_Initialize(argc, argv);
+ if(0 != err)
+ {
+ ExitProcess(FAIL);
+ }
+
+ //Allocate the physical storage in memory or in the paging file on disk
+ lpVirtualAddress = VirtualAlloc(NULL,//system determine where to allocate the region
+ 1024, //specify the size
+ MEM_COMMIT|MEM_TOP_DOWN, //allocation type
+ PAGE_READWRITE); //access protection
+ if(NULL == lpVirtualAddress)
+ {
+ Fail("\nFailed to call VirtualAlloc API!\n");
+ }
+
+ //decommit the specified region
+ err = VirtualFree(lpVirtualAddress,1024,MEM_DECOMMIT);
+ if(0 == err)
+ {
+ Fail("\nFailed to call VirtualFree API!\n");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test14/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test14/testinfo.dat
new file mode 100644
index 0000000000..60decb8461
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test14/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = VirtualAlloc
+Name = Positive test for VirtualAlloc API
+TYPE = DEFAULT
+EXE1 = virtualalloc
+Description
+=Test the VirtualAlloc with MEM_COMMIT|MEM_TOP_DOWN allocation type
+=and PAGE_READWRITE access protection
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test15/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test15/CMakeLists.txt
new file mode 100644
index 0000000000..87b29108b2
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test15/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ VirtualAlloc.c
+)
+
+add_executable(paltest_virtualalloc_test15
+ ${SOURCES}
+)
+
+add_dependencies(paltest_virtualalloc_test15 coreclrpal)
+
+target_link_libraries(paltest_virtualalloc_test15
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test15/VirtualAlloc.c b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test15/VirtualAlloc.c
new file mode 100644
index 0000000000..3cf1502f26
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test15/VirtualAlloc.c
@@ -0,0 +1,48 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: virtualalloc.c
+**
+** Purpose: Positive test the VirtualAlloc API.
+** Call VirtualAlloc with MEM_COMMIT|MEM_TOP_DOWN allocation type
+** and PAGE_EXECUTE access protection
+
+**
+**============================================================*/
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ int err;
+ LPVOID lpVirtualAddress;
+
+ //Initialize the PAL environment
+ err = PAL_Initialize(argc, argv);
+ if(0 != err)
+ {
+ ExitProcess(FAIL);
+ }
+
+ //Allocate the physical storage in memory or in the paging file on disk
+ lpVirtualAddress = VirtualAlloc(NULL,//system determine where to allocate the region
+ 1024, //specify the size
+ MEM_COMMIT|MEM_TOP_DOWN, //allocation type
+ PAGE_EXECUTE); //access protection
+ if(NULL == lpVirtualAddress)
+ {
+ Fail("\nFailed to call VirtualAlloc API!\n");
+ }
+
+ //decommit the specified region
+ err = VirtualFree(lpVirtualAddress,1024,MEM_DECOMMIT);
+ if(0 == err)
+ {
+ Fail("\nFailed to call VirtualFree API!\n");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test15/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test15/testinfo.dat
new file mode 100644
index 0000000000..2d9845ded6
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test15/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = VirtualAlloc
+Name = Positive test for VirtualAlloc API
+TYPE = DEFAULT
+EXE1 = virtualalloc
+Description
+=Test the VirtualAlloc with MEM_COMMIT|MEM_TOP_DOWN allocation type
+=and PAGE_EXECUTE access protection
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test16/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test16/CMakeLists.txt
new file mode 100644
index 0000000000..90e3f3bdb2
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test16/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ VirtualAlloc.c
+)
+
+add_executable(paltest_virtualalloc_test16
+ ${SOURCES}
+)
+
+add_dependencies(paltest_virtualalloc_test16 coreclrpal)
+
+target_link_libraries(paltest_virtualalloc_test16
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test16/VirtualAlloc.c b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test16/VirtualAlloc.c
new file mode 100644
index 0000000000..ce61b9aa39
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test16/VirtualAlloc.c
@@ -0,0 +1,48 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: virtualalloc.c
+**
+** Purpose: Positive test the VirtualAlloc API.
+** Call VirtualAlloc with MEM_COMMIT|MEM_TOP_DOWN allocation type
+** and PAGE_EXECUTE_READ access protection
+
+**
+**============================================================*/
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ int err;
+ LPVOID lpVirtualAddress;
+
+ //Initialize the PAL environment
+ err = PAL_Initialize(argc, argv);
+ if(0 != err)
+ {
+ ExitProcess(FAIL);
+ }
+
+ //Allocate the physical storage in memory or in the paging file on disk
+ lpVirtualAddress = VirtualAlloc(NULL,//system determine where to allocate the region
+ 1024, //specify the size
+ MEM_COMMIT|MEM_TOP_DOWN, //allocation type
+ PAGE_EXECUTE_READ); //access protection
+ if(NULL == lpVirtualAddress)
+ {
+ Fail("\nFailed to call VirtualAlloc API!\n");
+ }
+
+ //decommit the specified region
+ err = VirtualFree(lpVirtualAddress,1024,MEM_DECOMMIT);
+ if(0 == err)
+ {
+ Fail("\nFailed to call VirtualFree API!\n");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test16/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test16/testinfo.dat
new file mode 100644
index 0000000000..1389f1f92e
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test16/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = VirtualAlloc
+Name = Positive test for VirtualAlloc API
+TYPE = DEFAULT
+EXE1 = virtualalloc
+Description
+=Test the VirtualAlloc with MEM_COMMIT|MEM_TOP_DOWN allocation type
+=and PAGE_EXECUTE_READ access protection
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test17/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test17/CMakeLists.txt
new file mode 100644
index 0000000000..461b48ccc0
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test17/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ VirtualAlloc.c
+)
+
+add_executable(paltest_virtualalloc_test17
+ ${SOURCES}
+)
+
+add_dependencies(paltest_virtualalloc_test17 coreclrpal)
+
+target_link_libraries(paltest_virtualalloc_test17
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test17/VirtualAlloc.c b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test17/VirtualAlloc.c
new file mode 100644
index 0000000000..eb609f14e4
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test17/VirtualAlloc.c
@@ -0,0 +1,49 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: virtualalloc.c
+**
+** Purpose: Positive test the VirtualAlloc API.
+** Call VirtualAlloc with MEM_COMMIT|MEM_TOP_DOWN allocation type
+** and PAGE_READONLY access protection
+**
+
+**
+**============================================================*/
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ int err;
+ LPVOID lpVirtualAddress;
+
+ //Initialize the PAL environment
+ err = PAL_Initialize(argc, argv);
+ if(0 != err)
+ {
+ ExitProcess(FAIL);
+ }
+
+ //Allocate the physical storage in memory or in the paging file on disk
+ lpVirtualAddress = VirtualAlloc(NULL,//system determine where to allocate the region
+ 1024, //specify the size
+ MEM_COMMIT|MEM_TOP_DOWN, //allocation type
+ PAGE_EXECUTE_READWRITE); //access protection
+ if(NULL == lpVirtualAddress)
+ {
+ Fail("\nFailed to call VirtualAlloc API!\n");
+ }
+
+ //decommit the specified region
+ err = VirtualFree(lpVirtualAddress,1024,MEM_DECOMMIT);
+ if(0 == err)
+ {
+ Fail("\nFailed to call VirtualFree API!\n");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test17/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test17/testinfo.dat
new file mode 100644
index 0000000000..49ced63836
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test17/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = VirtualAlloc
+Name = Positive test for VirtualAlloc API
+TYPE = DEFAULT
+EXE1 = virtualalloc
+Description
+=Test the VirtualAlloc with MEM_COMMIT|MEM_TOP_DOWN allocation type
+=and PAGE_EXECUTE_READWRITE access protection
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test18/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test18/CMakeLists.txt
new file mode 100644
index 0000000000..69823be14b
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test18/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ VirtualAlloc.c
+)
+
+add_executable(paltest_virtualalloc_test18
+ ${SOURCES}
+)
+
+add_dependencies(paltest_virtualalloc_test18 coreclrpal)
+
+target_link_libraries(paltest_virtualalloc_test18
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test18/VirtualAlloc.c b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test18/VirtualAlloc.c
new file mode 100644
index 0000000000..e46da851db
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test18/VirtualAlloc.c
@@ -0,0 +1,49 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: virtualalloc.c
+**
+** Purpose: Positive test the VirtualAlloc API.
+** Call VirtualAlloc with MEM_COMMIT|MEM_TOP_DOWN allocation type
+** and PAGE_NOACCESS access protection
+
+**
+**============================================================*/
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ int err;
+ LPVOID lpVirtualAddress;
+
+ //Initialize the PAL environment
+ err = PAL_Initialize(argc, argv);
+ if(0 != err)
+ {
+ ExitProcess(FAIL);
+ }
+
+
+ //Allocate the physical storage in memory or in the paging file on disk
+ lpVirtualAddress = VirtualAlloc(NULL,//system determine where to allocate the region
+ 1024, //specify the size
+ MEM_COMMIT|MEM_TOP_DOWN, //allocation type
+ PAGE_NOACCESS); //access protection
+ if(NULL == lpVirtualAddress)
+ {
+ Fail("\nFailed to call VirtualAlloc API!\n");
+ }
+
+ //decommit the specified region
+ err = VirtualFree(lpVirtualAddress,1024,MEM_DECOMMIT);
+ if(0 == err)
+ {
+ Fail("\nFailed to call VirtualFree API!\n");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test18/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test18/testinfo.dat
new file mode 100644
index 0000000000..1fd4ac6f14
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test18/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = VirtualAlloc
+Name = Positive test for VirtualAlloc API
+TYPE = DEFAULT
+EXE1 = virtualalloc
+Description
+=Test the VirtualAlloc with MEM_COMMIT|MEM_TOP_DOWN allocation type
+=and PAGE_NOACCESS access protection
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test19/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test19/CMakeLists.txt
new file mode 100644
index 0000000000..fa65b4fa46
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test19/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ VirtualAlloc.c
+)
+
+add_executable(paltest_virtualalloc_test19
+ ${SOURCES}
+)
+
+add_dependencies(paltest_virtualalloc_test19 coreclrpal)
+
+target_link_libraries(paltest_virtualalloc_test19
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test19/VirtualAlloc.c b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test19/VirtualAlloc.c
new file mode 100644
index 0000000000..5cbe48b15e
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test19/VirtualAlloc.c
@@ -0,0 +1,51 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: virtualalloc.c
+**
+** Purpose: Positive test the VirtualAlloc API.
+** Call VirtualAlloc to reserve and commit
+** simultaneously with MEM_COMMIT|MEM_RESERVE|MEM_TOP_DOWN
+** allocation type and PAGE_READONLY access
+** protection
+**
+**
+**============================================================*/
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ int err;
+ LPVOID lpVirtualAddress;
+
+ //Initialize the PAL environment
+ err = PAL_Initialize(argc, argv);
+ if(0 != err)
+ {
+ ExitProcess(FAIL);
+ }
+
+ //reserve and commit simultaneously by using MEM_COMMIT|MEM_RESERVE
+ lpVirtualAddress = VirtualAlloc(NULL,//system determine where to allocate the region
+ 1024, //specify the size
+ MEM_COMMIT|MEM_RESERVE|MEM_TOP_DOWN, //allocation type
+ PAGE_READONLY); //access protection
+ if(NULL == lpVirtualAddress)
+ {
+ Fail("\nFailed to call VirtualAlloc API!\n");
+ }
+
+ //decommit the specified region
+ err = VirtualFree(lpVirtualAddress,1024,MEM_DECOMMIT);
+ if(0 == err)
+ {
+ Fail("\nFailed to call VirtualFree API!\n");
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test19/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test19/testinfo.dat
new file mode 100644
index 0000000000..6e427da15a
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test19/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = VirtualAlloc
+Name = Positive test for VirtualAlloc API
+TYPE = DEFAULT
+EXE1 = virtualalloc
+Description
+=Test the VirtualAlloc to reserve and commit
+=simultaneously by using MEM_COMMIT|MEM_RESERVE|MEM_TOP_DOWN
+=allocation type and PAGE_READONLY access protection
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test2/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test2/CMakeLists.txt
new file mode 100644
index 0000000000..1753b1edc5
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ VirtualAlloc.c
+)
+
+add_executable(paltest_virtualalloc_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_virtualalloc_test2 coreclrpal)
+
+target_link_libraries(paltest_virtualalloc_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test2/VirtualAlloc.c b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test2/VirtualAlloc.c
new file mode 100644
index 0000000000..99cf76a523
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test2/VirtualAlloc.c
@@ -0,0 +1,49 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: virtualalloc.c
+**
+** Purpose: Positive test the VirtualAlloc API.
+** Call VirtualAlloc with MEM_COMMIT allocation type
+** and PAGE_READWRITE access protection
+
+**
+**============================================================*/
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ int err;
+ LPVOID lpVirtualAddress;
+
+ //Initialize the PAL environment
+ err = PAL_Initialize(argc, argv);
+ if(0 != err)
+ {
+ ExitProcess(FAIL);
+ }
+
+ //Allocate the physical storage in memory or in the paging file on disk
+ lpVirtualAddress = VirtualAlloc(NULL,//system determine where to allocate the region
+ 1024, //specify the size
+ MEM_COMMIT, //allocation type
+ PAGE_READWRITE); //access protection
+ if(NULL == lpVirtualAddress)
+ {
+ Fail("\nFailed to call VirtualAlloc API!\n");
+ }
+
+ //decommit the specified region
+ err = VirtualFree(lpVirtualAddress,1024,MEM_DECOMMIT);
+ if(0 == err)
+ {
+ Fail("\nFailed to call VirtualFree API!\n");
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test2/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test2/testinfo.dat
new file mode 100644
index 0000000000..c7d8b6783d
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test2/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = VirtualAlloc
+Name = Positive test for VirtualAlloc API
+TYPE = DEFAULT
+EXE1 = virtualalloc
+Description
+=Test the VirtualAlloc with MEM_COMMIT allocation type
+=and PAGE_READWRITE access protection
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test20/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test20/CMakeLists.txt
new file mode 100644
index 0000000000..2c55071149
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test20/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ virtualalloc.c
+)
+
+add_executable(paltest_virtualalloc_test20
+ ${SOURCES}
+)
+
+add_dependencies(paltest_virtualalloc_test20 coreclrpal)
+
+target_link_libraries(paltest_virtualalloc_test20
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test20/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test20/testinfo.dat
new file mode 100644
index 0000000000..6010a18c8a
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test20/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = VirtualAlloc
+Name = Positive test for VirtualAlloc API
+TYPE = DEFAULT
+EXE1 = virtualalloc
+Description
+=Test VirtualAlloc to ensure that re-committed memory is not changed.
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test20/virtualalloc.c b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test20/virtualalloc.c
new file mode 100644
index 0000000000..7aec3c7f55
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test20/virtualalloc.c
@@ -0,0 +1,50 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: virtualalloc.c
+**
+** Purpose: Positive test the VirtualAlloc API.
+** Ensure that memory re-committed through VirtualAlloc
+** is not changed.
+**
+**
+**============================================================*/
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ int err;
+ int *ptr;
+
+ //Initialize the PAL environment
+ err = PAL_Initialize(argc, argv);
+ if(0 != err)
+ {
+ ExitProcess(FAIL);
+ }
+
+ ptr = (int *) VirtualAlloc(NULL, 4096, MEM_COMMIT | MEM_RESERVE,
+ PAGE_READWRITE);
+ if (ptr == NULL)
+ {
+ Fail("First VirtualAlloc failed!\n");
+ }
+
+ *ptr = 123;
+
+ ptr = (int *) VirtualAlloc(ptr, 4096, MEM_COMMIT, PAGE_READWRITE);
+ if (ptr == NULL)
+ {
+ Fail("Second VirtualAlloc failed!\n");
+ }
+ if (*ptr != 123)
+ {
+ Fail("VirtualAlloc modified (probably zeroed) re-committed memory!\n");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test21/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test21/CMakeLists.txt
new file mode 100644
index 0000000000..f97c32af75
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test21/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ virtualalloc.c
+)
+
+add_executable(paltest_virtualalloc_test21
+ ${SOURCES}
+)
+
+add_dependencies(paltest_virtualalloc_test21 coreclrpal)
+
+target_link_libraries(paltest_virtualalloc_test21
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test21/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test21/testinfo.dat
new file mode 100644
index 0000000000..c32d352d19
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test21/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = VirtualAlloc
+Name = Positive test for VirtualAlloc API
+TYPE = DEFAULT
+EXE1 = virtualalloc
+Description
+=Test VirtualAlloc to ensure that freed memory that is committed again is zeroed.
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test21/virtualalloc.c b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test21/virtualalloc.c
new file mode 100644
index 0000000000..065a2ff5c8
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test21/virtualalloc.c
@@ -0,0 +1,54 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: virtualalloc.c
+**
+** Purpose: Positive test the VirtualAlloc API.
+** Ensure that memory committed through VirtualAlloc,
+** then freed, then committed again is zeroed.
+**
+**
+**============================================================*/
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ int err;
+ int *ptr;
+
+ //Initialize the PAL environment
+ err = PAL_Initialize(argc, argv);
+ if(0 != err)
+ {
+ ExitProcess(FAIL);
+ }
+
+ ptr = (int *) VirtualAlloc(NULL, 4096, MEM_COMMIT | MEM_RESERVE,
+ PAGE_READWRITE);
+ if (ptr == NULL)
+ {
+ Fail("First VirtualAlloc failed!\n");
+ }
+ *ptr = 123;
+
+ if (!VirtualFree(ptr, 4096, MEM_DECOMMIT))
+ {
+ Fail("VirtualFree failed!\n");
+ }
+
+ ptr = (int *) VirtualAlloc(ptr, 4096, MEM_COMMIT, PAGE_READWRITE);
+ if (ptr == NULL)
+ {
+ Fail("Second VirtualAlloc failed!\n");
+ }
+ if (*ptr != 0)
+ {
+ Fail("VirtualAlloc failed to zero its memory!\n");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test3/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test3/CMakeLists.txt
new file mode 100644
index 0000000000..035594bd79
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test3/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ VirtualAlloc.c
+)
+
+add_executable(paltest_virtualalloc_test3
+ ${SOURCES}
+)
+
+add_dependencies(paltest_virtualalloc_test3 coreclrpal)
+
+target_link_libraries(paltest_virtualalloc_test3
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test3/VirtualAlloc.c b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test3/VirtualAlloc.c
new file mode 100644
index 0000000000..5c57ec337f
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test3/VirtualAlloc.c
@@ -0,0 +1,48 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: virtualalloc.c
+**
+** Purpose: Positive test the VirtualAlloc API.
+** Call VirtualAlloc with MEM_COMMIT allocation type
+** and PAGE_EXECUTE access protection
+
+**
+**============================================================*/
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ int err;
+ LPVOID lpVirtualAddress;
+
+ //Initialize the PAL environment
+ err = PAL_Initialize(argc, argv);
+ if(0 != err)
+ {
+ ExitProcess(FAIL);
+ }
+
+ //Allocate the physical storage in memory or in the paging file on disk
+ lpVirtualAddress = VirtualAlloc(NULL,//system determine where to allocate the region
+ 1024, //specify the size
+ MEM_COMMIT, //allocation type
+ PAGE_EXECUTE); //access protection
+ if(NULL == lpVirtualAddress)
+ {
+ Fail("\nFailed to call VirtualAlloc API!\n");
+ }
+
+ //decommit the specified region
+ err = VirtualFree(lpVirtualAddress,1024,MEM_DECOMMIT);
+ if(0 == err)
+ {
+ Fail("\nFailed to call VirtualFree API!\n");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test3/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test3/testinfo.dat
new file mode 100644
index 0000000000..a3d5401493
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test3/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = VirtualAlloc
+Name = Positive test for VirtualAlloc API
+TYPE = DEFAULT
+EXE1 = virtualalloc
+Description
+=Test the VirtualAlloc with MEM_COMMIT allocation type
+=and PAGE_EXECUTE access protection
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test4/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test4/CMakeLists.txt
new file mode 100644
index 0000000000..5ce80bf52f
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test4/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ VirtualAlloc.c
+)
+
+add_executable(paltest_virtualalloc_test4
+ ${SOURCES}
+)
+
+add_dependencies(paltest_virtualalloc_test4 coreclrpal)
+
+target_link_libraries(paltest_virtualalloc_test4
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test4/VirtualAlloc.c b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test4/VirtualAlloc.c
new file mode 100644
index 0000000000..c134a14eb1
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test4/VirtualAlloc.c
@@ -0,0 +1,49 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: virtualalloc.c
+**
+** Purpose: Positive test the VirtualAlloc API.
+** Call VirtualAlloc with MEM_COMMIT allocation type
+** and PAGE_EXECUTE_READ access protection
+
+**
+**============================================================*/
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ int err;
+ LPVOID lpVirtualAddress;
+
+ //Initialize the PAL environment
+ err = PAL_Initialize(argc, argv);
+ if(0 != err)
+ {
+ ExitProcess(FAIL);
+ }
+
+ //Allocate the physical storage in memory or in the paging file on disk
+ lpVirtualAddress = VirtualAlloc(NULL,//system determine where to allocate the region
+ 1024, //specify the size
+ MEM_COMMIT, //allocation type
+ PAGE_EXECUTE_READ); //access protection
+ if(NULL == lpVirtualAddress)
+ {
+ Fail("\nFailed to call VirtualAlloc API!\n");
+ }
+
+ //decommit the specified region
+ err = VirtualFree(lpVirtualAddress,1024,MEM_DECOMMIT);
+ if(0 == err)
+ {
+ Fail("\nFailed to call VirtualFree API!\n");
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test4/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test4/testinfo.dat
new file mode 100644
index 0000000000..0e84e7a3ba
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test4/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = VirtualAlloc
+Name = Positive test for VirtualAlloc API
+TYPE = DEFAULT
+EXE1 = virtualalloc
+Description
+=Test the VirtualAlloc with MEM_COMMIT allocation type
+=and PAGE_EXECUTE_READ access protection
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test5/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test5/CMakeLists.txt
new file mode 100644
index 0000000000..138d9c9727
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test5/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ VirtualAlloc.c
+)
+
+add_executable(paltest_virtualalloc_test5
+ ${SOURCES}
+)
+
+add_dependencies(paltest_virtualalloc_test5 coreclrpal)
+
+target_link_libraries(paltest_virtualalloc_test5
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test5/VirtualAlloc.c b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test5/VirtualAlloc.c
new file mode 100644
index 0000000000..8c4f9dcdb6
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test5/VirtualAlloc.c
@@ -0,0 +1,50 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: virtualalloc.c
+**
+** Purpose: Positive test the VirtualAlloc API.
+** Call VirtualAlloc with MEM_COMMIT allocation type
+** and PAGE_READONLY access protection
+**
+
+**
+**============================================================*/
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ int err;
+ LPVOID lpVirtualAddress;
+
+ //Initialize the PAL environment
+ err = PAL_Initialize(argc, argv);
+ if(0 != err)
+ {
+ ExitProcess(FAIL);
+ }
+
+ //Allocate the physical storage in memory or in the paging file on disk
+ lpVirtualAddress = VirtualAlloc(NULL,//system determine where to allocate the region
+ 1024, //specify the size
+ MEM_COMMIT, //allocation type
+ PAGE_EXECUTE_READWRITE); //access protection
+ if(NULL == lpVirtualAddress)
+ {
+ Fail("\nFailed to call VirtualAlloc API!\n");
+ }
+
+ //decommit the specified region
+ err = VirtualFree(lpVirtualAddress,1024,MEM_DECOMMIT);
+ if(0 == err)
+ {
+ Fail("\nFailed to call VirtualFree API!\n");
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test5/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test5/testinfo.dat
new file mode 100644
index 0000000000..332b88b071
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test5/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = VirtualAlloc
+Name = Positive test for VirtualAlloc API
+TYPE = DEFAULT
+EXE1 = virtualalloc
+Description
+=Test the VirtualAlloc with MEM_COMMIT allocation type
+=and PAGE_EXECUTE_READWRITE access protection
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test6/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test6/CMakeLists.txt
new file mode 100644
index 0000000000..c61add9db4
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test6/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ VirtualAlloc.c
+)
+
+add_executable(paltest_virtualalloc_test6
+ ${SOURCES}
+)
+
+add_dependencies(paltest_virtualalloc_test6 coreclrpal)
+
+target_link_libraries(paltest_virtualalloc_test6
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test6/VirtualAlloc.c b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test6/VirtualAlloc.c
new file mode 100644
index 0000000000..e9c33d86df
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test6/VirtualAlloc.c
@@ -0,0 +1,48 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: virtualalloc.c
+**
+** Purpose: Positive test the VirtualAlloc API.
+** Call VirtualAlloc with MEM_COMMIT allocation type
+** and PAGE_NOACCESS access protection
+
+**
+**============================================================*/
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ int err;
+ LPVOID lpVirtualAddress;
+
+ //Initialize the PAL environment
+ err = PAL_Initialize(argc, argv);
+ if(0 != err)
+ {
+ ExitProcess(FAIL);
+ }
+
+ //Allocate the physical storage in memory or in the paging file on disk
+ lpVirtualAddress = VirtualAlloc(NULL,//system determine where to allocate the region
+ 1024, //specify the size
+ MEM_COMMIT, //allocation type
+ PAGE_NOACCESS); //access protection
+ if(NULL == lpVirtualAddress)
+ {
+ Fail("\nFailed to call VirtualAlloc API!\n");
+ }
+
+ //decommit the specified region
+ err = VirtualFree(lpVirtualAddress,1024,MEM_DECOMMIT);
+ if(0 == err)
+ {
+ Fail("\nFailed to call VirtualFree API!\n");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test6/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test6/testinfo.dat
new file mode 100644
index 0000000000..ac2b91c0dc
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test6/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = VirtualAlloc
+Name = Positive test for VirtualAlloc API
+TYPE = DEFAULT
+EXE1 = virtualalloc
+Description
+=Test the VirtualAlloc with MEM_COMMIT allocation type
+=and PAGE_NOACCESS access protection
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test7/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test7/CMakeLists.txt
new file mode 100644
index 0000000000..b5452a0c48
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test7/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ VirtualAlloc.c
+)
+
+add_executable(paltest_virtualalloc_test7
+ ${SOURCES}
+)
+
+add_dependencies(paltest_virtualalloc_test7 coreclrpal)
+
+target_link_libraries(paltest_virtualalloc_test7
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test7/VirtualAlloc.c b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test7/VirtualAlloc.c
new file mode 100644
index 0000000000..bee2735c9f
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test7/VirtualAlloc.c
@@ -0,0 +1,53 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: virtualalloc.c
+**
+** Purpose: Positive test the VirtualAlloc API.
+** Call VirtualAlloc with MEM_RESERVE allocation type
+** and PAGE_READONLY access protection
+
+**
+**============================================================*/
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ int err;
+ LPVOID lpVirtualAddress;
+
+ //Initialize the PAL environment
+ err = PAL_Initialize(argc, argv);
+ if(0 != err)
+ {
+ ExitProcess(FAIL);
+ }
+
+ //Allocate the physical storage in memory or in the paging file on disk
+ lpVirtualAddress = VirtualAlloc(NULL,//system determine where to allocate the region
+ 1024, //specify the size
+ MEM_RESERVE, //allocation type
+ PAGE_READONLY); //access protection
+ if(NULL == lpVirtualAddress)
+ {
+ Fail("\nFailed to call VirtualAlloc API!\n");
+ PAL_Terminate();
+ return 1;
+ }
+
+ //decommit the specified region
+ err = VirtualFree(lpVirtualAddress,1024,MEM_DECOMMIT);
+ if(0 == err)
+ {
+ Fail("\nFailed to call VirtualFree API!\n");
+ PAL_Terminate();
+ return 1;
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test7/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test7/testinfo.dat
new file mode 100644
index 0000000000..2edcb56d3b
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test7/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = VirtualAlloc
+Name = Positive test for VirtualAlloc API
+TYPE = DEFAULT
+EXE1 = virtualalloc
+Description
+=Test the VirtualAlloc with MEM_RESERVE allocation type
+=and PAGE_READONLY access protection
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test8/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test8/CMakeLists.txt
new file mode 100644
index 0000000000..584a0c505a
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test8/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ VirtualAlloc.c
+)
+
+add_executable(paltest_virtualalloc_test8
+ ${SOURCES}
+)
+
+add_dependencies(paltest_virtualalloc_test8 coreclrpal)
+
+target_link_libraries(paltest_virtualalloc_test8
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test8/VirtualAlloc.c b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test8/VirtualAlloc.c
new file mode 100644
index 0000000000..d548e0c8db
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test8/VirtualAlloc.c
@@ -0,0 +1,48 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: virtualalloc.c
+**
+** Purpose: Positive test the VirtualAlloc API.
+** Call VirtualAlloc with MEM_RESERVE allocation type
+** and PAGE_READWRITE access protection
+
+**
+**============================================================*/
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ int err;
+ LPVOID lpVirtualAddress;
+
+ //Initialize the PAL environment
+ err = PAL_Initialize(argc, argv);
+ if(0 != err)
+ {
+ ExitProcess(FAIL);
+ }
+
+ //Allocate the physical storage in memory or in the paging file on disk
+ lpVirtualAddress = VirtualAlloc(NULL,//system determine where to allocate the region
+ 1024, //specify the size
+ MEM_RESERVE, //allocation type
+ PAGE_READWRITE); //access protection
+ if(NULL == lpVirtualAddress)
+ {
+ Fail("\nFailed to call VirtualAlloc API!\n");
+ }
+
+ //decommit the specified region
+ err = VirtualFree(lpVirtualAddress,1024,MEM_DECOMMIT);
+ if(0 == err)
+ {
+ Fail("\nFailed to call VirtualFree API!\n");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test8/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test8/testinfo.dat
new file mode 100644
index 0000000000..c0ee6b6a69
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test8/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = VirtualAlloc
+Name = Positive test for VirtualAlloc API
+TYPE = DEFAULT
+EXE1 = virtualalloc
+Description
+=Test the VirtualAlloc with MEM_RESERVE allocation type
+=and PAGE_READWRITE access protection
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test9/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test9/CMakeLists.txt
new file mode 100644
index 0000000000..aee950b2e4
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test9/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ VirtualAlloc.c
+)
+
+add_executable(paltest_virtualalloc_test9
+ ${SOURCES}
+)
+
+add_dependencies(paltest_virtualalloc_test9 coreclrpal)
+
+target_link_libraries(paltest_virtualalloc_test9
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test9/VirtualAlloc.c b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test9/VirtualAlloc.c
new file mode 100644
index 0000000000..2711addacc
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test9/VirtualAlloc.c
@@ -0,0 +1,48 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: virtualalloc.c
+**
+** Purpose: Positive test the VirtualAlloc API.
+** Call VirtualAlloc with MEM_RESERVE allocation type
+** and PAGE_EXECUTE access protection
+
+**
+**============================================================*/
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ int err;
+ LPVOID lpVirtualAddress;
+
+ //Initialize the PAL environment
+ err = PAL_Initialize(argc, argv);
+ if(0 != err)
+ {
+ ExitProcess(FAIL);
+ }
+
+ //Allocate the physical storage in memory or in the paging file on disk
+ lpVirtualAddress = VirtualAlloc(NULL,//system determine where to allocate the region
+ 1024, //specify the size
+ MEM_RESERVE, //allocation type
+ PAGE_EXECUTE); //access protection
+ if(NULL == lpVirtualAddress)
+ {
+ Fail("\nFailed to call VirtualAlloc API!\n");
+ }
+
+ //decommit the specified region
+ err = VirtualFree(lpVirtualAddress,1024,MEM_DECOMMIT);
+ if(0 == err)
+ {
+ Fail("\nFailed to call VirtualFree API!\n");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test9/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test9/testinfo.dat
new file mode 100644
index 0000000000..1e83744bba
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualAlloc/test9/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = VirtualAlloc
+Name = Positive test for VirtualAlloc API
+TYPE = DEFAULT
+EXE1 = virtualalloc
+Description
+=Test the VirtualAlloc with MEM_RESERVE allocation type
+=and PAGE_EXECUTE access protection
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualFree/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/VirtualFree/CMakeLists.txt
new file mode 100644
index 0000000000..1962ade358
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualFree/CMakeLists.txt
@@ -0,0 +1,6 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+add_subdirectory(test3)
+
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualFree/test1/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/VirtualFree/test1/CMakeLists.txt
new file mode 100644
index 0000000000..1914f76fe6
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualFree/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ VirtualFree.c
+)
+
+add_executable(paltest_virtualfree_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_virtualfree_test1 coreclrpal)
+
+target_link_libraries(paltest_virtualfree_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualFree/test1/VirtualFree.c b/src/pal/tests/palsuite/filemapping_memmgt/VirtualFree/test1/VirtualFree.c
new file mode 100644
index 0000000000..0f4f144aa5
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualFree/test1/VirtualFree.c
@@ -0,0 +1,48 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: virtualfree.c
+**
+** Purpose: Positive test the VirtualFree API.
+** Call VirtualFree with MEM_DECOMMIT
+** free operation type
+**
+**
+**============================================================*/
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ int err;
+ LPVOID lpVirtualAddress;
+
+ //Initialize the PAL environment
+ err = PAL_Initialize(argc, argv);
+ if(0 != err)
+ {
+ ExitProcess(FAIL);
+ }
+
+ //Allocate the physical storage in memory or in the paging file on disk
+ lpVirtualAddress = VirtualAlloc(NULL,//system determine where to allocate the region
+ 1024, //specify the size
+ MEM_COMMIT, //allocation type
+ PAGE_READONLY); //access protection
+ if(NULL == lpVirtualAddress)
+ {
+ Fail("\nFailed to call VirtualAlloc API!\n");
+ }
+
+ //decommit the specified region
+ err = VirtualFree(lpVirtualAddress,1024,MEM_DECOMMIT);
+ if(0 == err)
+ {
+ Fail("\nFailed to call VirtualFree API!\n");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualFree/test1/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/VirtualFree/test1/testinfo.dat
new file mode 100644
index 0000000000..2848635681
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualFree/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = VirtualFree
+Name = Positive test for VirtualFree API
+TYPE = DEFAULT
+EXE1 = virtualfree
+Description
+=Test the VirtualFree with MEM_DECOMMIT free
+=operation type
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualFree/test2/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/VirtualFree/test2/CMakeLists.txt
new file mode 100644
index 0000000000..a288b37154
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualFree/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ VirtualFree.c
+)
+
+add_executable(paltest_virtualfree_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_virtualfree_test2 coreclrpal)
+
+target_link_libraries(paltest_virtualfree_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualFree/test2/VirtualFree.c b/src/pal/tests/palsuite/filemapping_memmgt/VirtualFree/test2/VirtualFree.c
new file mode 100644
index 0000000000..70064a3bf9
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualFree/test2/VirtualFree.c
@@ -0,0 +1,54 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: virtualfree.c
+**
+** Purpose: Positive test the VirtualFree API.
+** Call VirtualFree with MEM_RELEASE
+** free operation type
+**
+**
+**============================================================*/
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ int err;
+ LPVOID lpVirtualAddress;
+
+ //Initialize the PAL environment
+ err = PAL_Initialize(argc, argv);
+ if(0 != err)
+ {
+ ExitProcess(FAIL);
+ }
+
+ //Allocate the physical storage in memory or in the paging file on disk
+ lpVirtualAddress = VirtualAlloc(NULL,//system determine where to allocate the region
+ 1024, //specify the size
+ MEM_COMMIT, //allocation type
+ PAGE_READONLY); //access protection
+ if(NULL == lpVirtualAddress)
+ {
+ Fail("\nFailed to call VirtualAlloc API!\n");
+ PAL_Terminate();
+ return 1;
+ }
+
+ //decommit the specified region
+ err = VirtualFree(lpVirtualAddress,//base address
+ 0, //must be zero with MEM_RELEASE
+ MEM_RELEASE);//free operation
+ if(0 == err)
+ {
+ Fail("\nFailed to call VirtualFree API!\n");
+ PAL_Terminate();
+ return 1;
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualFree/test2/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/VirtualFree/test2/testinfo.dat
new file mode 100644
index 0000000000..ea380c3676
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualFree/test2/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = VirtualFree
+Name = Positive test for VirtualFree API
+TYPE = DEFAULT
+EXE1 = virtualfree
+Description
+=Test the VirtualFree with MEM_RELEASE free
+=operation type
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualFree/test3/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/VirtualFree/test3/CMakeLists.txt
new file mode 100644
index 0000000000..993189c1aa
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualFree/test3/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ VirtualFree.c
+)
+
+add_executable(paltest_virtualfree_test3
+ ${SOURCES}
+)
+
+add_dependencies(paltest_virtualfree_test3 coreclrpal)
+
+target_link_libraries(paltest_virtualfree_test3
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualFree/test3/VirtualFree.c b/src/pal/tests/palsuite/filemapping_memmgt/VirtualFree/test3/VirtualFree.c
new file mode 100644
index 0000000000..27f1936be7
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualFree/test3/VirtualFree.c
@@ -0,0 +1,53 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: virtualfree.c
+**
+** Purpose: Positive test the VirtualFree API.
+** Call VirtualFree with MEM_RELEASE
+** and MEM_DECOMMIT free operation type
+**
+**
+**============================================================*/
+#include <palsuite.h>
+
+#define VIRTUALSIZE 1024
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ int err;
+ LPVOID lpVirtualAddress;
+
+ //Initialize the PAL environment
+ err = PAL_Initialize(argc, argv);
+ if(0 != err)
+ {
+ ExitProcess(FAIL);
+ }
+
+ //Allocate the physical storage in memory or in the paging file on disk
+ lpVirtualAddress = VirtualAlloc(NULL,//system determine where to allocate the region
+ VIRTUALSIZE, //specify the size
+ MEM_RESERVE, //allocation type
+ PAGE_NOACCESS); //access protection
+ if(NULL == lpVirtualAddress)
+ {
+ Fail("\nFailed to call VirtualAlloc API!\n");
+ }
+
+ //decommit and release the specified region
+ err = VirtualFree(lpVirtualAddress, //base address
+ VIRTUALSIZE, //decommited size
+ MEM_DECOMMIT|MEM_RELEASE);//free operation
+ if(0 != err)
+ {
+ Fail("\nFailed to call VirtualFree API!\n");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualFree/test3/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/VirtualFree/test3/testinfo.dat
new file mode 100644
index 0000000000..c27b7ad3e5
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualFree/test3/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = VirtualFree
+Name = Positive test for VirtualFree API
+TYPE = DEFAULT
+EXE1 = virtualfree
+Description
+=Test the VirtualFree with MEM_DECOMMIT|MEM_RELEASE free
+=operation type
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualProtect/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/VirtualProtect/CMakeLists.txt
new file mode 100644
index 0000000000..cac5452ec9
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualProtect/CMakeLists.txt
@@ -0,0 +1,9 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+add_subdirectory(test3)
+add_subdirectory(test4)
+add_subdirectory(test6)
+add_subdirectory(test7)
+
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualProtect/test1/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/VirtualProtect/test1/CMakeLists.txt
new file mode 100644
index 0000000000..214cf460ae
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualProtect/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ VirtualProtect.c
+)
+
+add_executable(paltest_virtualprotect_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_virtualprotect_test1 coreclrpal)
+
+target_link_libraries(paltest_virtualprotect_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualProtect/test1/VirtualProtect.c b/src/pal/tests/palsuite/filemapping_memmgt/VirtualProtect/test1/VirtualProtect.c
new file mode 100644
index 0000000000..1a28bd156d
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualProtect/test1/VirtualProtect.c
@@ -0,0 +1,69 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: virtualprotect.c
+**
+** Purpose: Positive test the VirtualProtect API.
+** Call VirtualProtect to set new protect as
+** PAGE_READWRITE
+**
+**
+**============================================================*/
+#include <palsuite.h>
+
+#define REGIONSIZE 1024
+
+int __cdecl main(int argc, char *argv[])
+{
+ int err;
+ LPVOID lpVirtualAddress;
+ DWORD OldProtect;
+
+ //Initialize the PAL environment
+ err = PAL_Initialize(argc, argv);
+ if(0 != err)
+ {
+ ExitProcess(FAIL);
+ }
+
+ //Allocate the physical storage in memory or in the paging file on disk
+ lpVirtualAddress = VirtualAlloc(NULL,//system determine where to allocate the region
+ REGIONSIZE, //specify the size
+ MEM_COMMIT, //allocation type
+ PAGE_READONLY); //access protection
+ if(NULL == lpVirtualAddress)
+ {
+ Fail("\nFailed to call VirtualAlloc API!\n");
+ }
+
+ OldProtect = PAGE_READONLY;
+ //Set new access protection
+ err = VirtualProtect(lpVirtualAddress,
+ REGIONSIZE, //specify the region size
+ PAGE_READWRITE,//desied access protection
+ &OldProtect);//old access protection
+ if(0 == err)
+ {
+ Trace("\nFailed to call VirtualProtect API!\n");
+ err = VirtualFree(lpVirtualAddress,REGIONSIZE,MEM_DECOMMIT);
+ if(0 == err)
+ {
+ Fail("\nFailed to call VirtualFree API!\n");
+ }
+ Fail("");
+ }
+
+
+ //decommit the specified region
+ err = VirtualFree(lpVirtualAddress,REGIONSIZE,MEM_DECOMMIT);
+ if(0 == err)
+ {
+ Fail("\nFailed to call VirtualFree API!\n");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualProtect/test1/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/VirtualProtect/test1/testinfo.dat
new file mode 100644
index 0000000000..6b78c079e7
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualProtect/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = VirtualProtect
+Name = Positive test for VirtualProtect - with PAGE_READWRITE
+TYPE = DEFAULT
+EXE1 = virtualprotect
+Description
+=Test the VirtualProtect to set new access protection
+=as PAGE_READWRITE
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualProtect/test2/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/VirtualProtect/test2/CMakeLists.txt
new file mode 100644
index 0000000000..27f43477ea
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualProtect/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ VirtualProtect.c
+)
+
+add_executable(paltest_virtualprotect_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_virtualprotect_test2 coreclrpal)
+
+target_link_libraries(paltest_virtualprotect_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualProtect/test2/VirtualProtect.c b/src/pal/tests/palsuite/filemapping_memmgt/VirtualProtect/test2/VirtualProtect.c
new file mode 100644
index 0000000000..64a08d7885
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualProtect/test2/VirtualProtect.c
@@ -0,0 +1,69 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: virtualprotect.c
+**
+** Purpose: Positive test the VirtualProtect API.
+** Call VirtualProtect to set new protect as
+** PAGE_EXECUTE
+**
+**
+**============================================================*/
+#include <palsuite.h>
+
+#define REGIONSIZE 1024
+
+int __cdecl main(int argc, char *argv[])
+{
+ int err;
+ LPVOID lpVirtualAddress;
+ DWORD OldProtect;
+
+ //Initialize the PAL environment
+ err = PAL_Initialize(argc, argv);
+ if(0 != err)
+ {
+ ExitProcess(FAIL);
+ }
+
+ //Allocate the physical storage in memory or in the paging file on disk
+ lpVirtualAddress = VirtualAlloc(NULL,//determine where to allocate the region
+ REGIONSIZE, //specify the size
+ MEM_COMMIT, //allocation type
+ PAGE_READONLY); //access protection
+ if(NULL == lpVirtualAddress)
+ {
+ Fail("\nFailed to call VirtualAlloc API!\n");
+ }
+
+ OldProtect = PAGE_READONLY;
+ //Set new access protection
+ err = VirtualProtect(lpVirtualAddress,
+ REGIONSIZE, //specify the region size
+ PAGE_EXECUTE,//desied access protection
+ &OldProtect);//old access protection
+ if(0 == err)
+ {
+ Trace("\nFailed to call VirtualProtect API!\n");
+ err = VirtualFree(lpVirtualAddress,REGIONSIZE,MEM_DECOMMIT);
+ if(0 == err)
+ {
+ Fail("\nFailed to call VirtualFree API!\n");
+ }
+ Fail("");
+ }
+
+
+ //decommit the specified region
+ err = VirtualFree(lpVirtualAddress,REGIONSIZE,MEM_DECOMMIT);
+ if(0 == err)
+ {
+ Fail("\nFailed to call VirtualFree API!\n");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualProtect/test2/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/VirtualProtect/test2/testinfo.dat
new file mode 100644
index 0000000000..d5fa0cfbc2
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualProtect/test2/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = VirtualProtect
+Name = Positive test for VirtualProtect - with PAGE_EXECUTE
+TYPE = DEFAULT
+EXE1 = virtualprotect
+Description
+=Test the VirtualProtect to set new access protection
+=as PAGE_EXECUTE
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualProtect/test3/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/VirtualProtect/test3/CMakeLists.txt
new file mode 100644
index 0000000000..994d4e2f41
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualProtect/test3/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ VirtualProtect.c
+)
+
+add_executable(paltest_virtualprotect_test3
+ ${SOURCES}
+)
+
+add_dependencies(paltest_virtualprotect_test3 coreclrpal)
+
+target_link_libraries(paltest_virtualprotect_test3
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualProtect/test3/VirtualProtect.c b/src/pal/tests/palsuite/filemapping_memmgt/VirtualProtect/test3/VirtualProtect.c
new file mode 100644
index 0000000000..0f738630ee
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualProtect/test3/VirtualProtect.c
@@ -0,0 +1,69 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: virtualprotect.c
+**
+** Purpose: Positive test the VirtualProtect API.
+** Call VirtualProtect to set new protect as
+** PAGE_EXECUTE_READ
+**
+**
+**============================================================*/
+#include <palsuite.h>
+
+#define REGIONSIZE 1024
+
+int __cdecl main(int argc, char *argv[])
+{
+ int err;
+ LPVOID lpVirtualAddress;
+ DWORD OldProtect;
+
+ //Initialize the PAL environment
+ err = PAL_Initialize(argc, argv);
+ if(0 != err)
+ {
+ ExitProcess(FAIL);
+ }
+
+ //Allocate the physical storage in memory or in the paging file on disk
+ lpVirtualAddress = VirtualAlloc(NULL,//determine where to allocate the region
+ REGIONSIZE, //specify the size
+ MEM_COMMIT, //allocation type
+ PAGE_READONLY); //access protection
+ if(NULL == lpVirtualAddress)
+ {
+ Fail("\nFailed to call VirtualAlloc API!\n");
+ }
+
+ OldProtect = PAGE_READONLY;
+ //Set new access protection
+ err = VirtualProtect(lpVirtualAddress,
+ REGIONSIZE, //specify the region size
+ PAGE_EXECUTE_READ,//desied access protection
+ &OldProtect);//old access protection
+ if(0 == err)
+ {
+ Trace("\nFailed to call VirtualProtect API!\n");
+ err = VirtualFree(lpVirtualAddress,REGIONSIZE,MEM_DECOMMIT);
+ if(0 == err)
+ {
+ Fail("\nFailed to call VirtualFree API!\n");
+ }
+ Fail("");
+ }
+
+
+ //decommit the specified region
+ err = VirtualFree(lpVirtualAddress,REGIONSIZE,MEM_DECOMMIT);
+ if(0 == err)
+ {
+ Fail("\nFailed to call VirtualFree API!\n");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualProtect/test3/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/VirtualProtect/test3/testinfo.dat
new file mode 100644
index 0000000000..7c64c3092e
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualProtect/test3/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = VirtualProtect
+Name = Positive test for VirtualProtect - with PAGE_EXECUTE_READ
+TYPE = DEFAULT
+EXE1 = virtualprotect
+Description
+=Test the VirtualProtect to set new access protection
+=as PAGE_EXECUTE_READ
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualProtect/test4/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/VirtualProtect/test4/CMakeLists.txt
new file mode 100644
index 0000000000..2e0fba50bb
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualProtect/test4/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ VirtualProtect.c
+)
+
+add_executable(paltest_virtualprotect_test4
+ ${SOURCES}
+)
+
+add_dependencies(paltest_virtualprotect_test4 coreclrpal)
+
+target_link_libraries(paltest_virtualprotect_test4
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualProtect/test4/VirtualProtect.c b/src/pal/tests/palsuite/filemapping_memmgt/VirtualProtect/test4/VirtualProtect.c
new file mode 100644
index 0000000000..926d501d0d
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualProtect/test4/VirtualProtect.c
@@ -0,0 +1,68 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: virtualprotect.c
+**
+** Purpose: Positive test the VirtualProtect API.
+** Call VirtualProtect to set new protect as
+** PAGE_EXECUTE_READWRITE
+**
+**
+**============================================================*/
+#include <palsuite.h>
+
+#define REGIONSIZE 1024
+
+int __cdecl main(int argc, char *argv[])
+{
+ int err;
+ LPVOID lpVirtualAddress;
+ DWORD OldProtect;
+
+ //Initialize the PAL environment
+ err = PAL_Initialize(argc, argv);
+ if(0 != err)
+ {
+ ExitProcess(FAIL);
+ }
+
+ //Allocate the physical storage in memory or in the paging file on disk
+ lpVirtualAddress = VirtualAlloc(NULL,//determine where to allocate the region
+ REGIONSIZE, //specify the size
+ MEM_COMMIT, //allocation type
+ PAGE_READONLY); //access protection
+ if(NULL == lpVirtualAddress)
+ {
+ Fail("\nFailed to call VirtualAlloc API!\n");
+ }
+
+ OldProtect = PAGE_READONLY;
+ //Set new access protection
+ err = VirtualProtect(lpVirtualAddress,
+ REGIONSIZE, //specify the region size
+ PAGE_EXECUTE_READWRITE,//desied access protection
+ &OldProtect);//old access protection
+ if(0 == err)
+ {
+ Trace("\nFailed to call VirtualProtect API!\n");
+ err = VirtualFree(lpVirtualAddress,REGIONSIZE,MEM_DECOMMIT);
+ if(0 == err)
+ {
+ Fail("\nFailed to call VirtualFree API!\n");
+ }
+ Fail("");
+ }
+
+ //decommit the specified region
+ err = VirtualFree(lpVirtualAddress,REGIONSIZE,MEM_DECOMMIT);
+ if(0 == err)
+ {
+ Fail("\nFailed to call VirtualFree API!\n");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualProtect/test4/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/VirtualProtect/test4/testinfo.dat
new file mode 100644
index 0000000000..c344073113
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualProtect/test4/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = VirtualProtect
+Name = Positive test for VirtualProtect - with PAGE_EXECUTE_READWRITE
+TYPE = DEFAULT
+EXE1 = virtualprotect
+Description
+=Test the VirtualProtect to set new access protection
+=as PAGE_EXECUTE_READWRITE
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualProtect/test6/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/VirtualProtect/test6/CMakeLists.txt
new file mode 100644
index 0000000000..6d6fd07df8
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualProtect/test6/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ VirtualProtect.c
+)
+
+add_executable(paltest_virtualprotect_test6
+ ${SOURCES}
+)
+
+add_dependencies(paltest_virtualprotect_test6 coreclrpal)
+
+target_link_libraries(paltest_virtualprotect_test6
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualProtect/test6/VirtualProtect.c b/src/pal/tests/palsuite/filemapping_memmgt/VirtualProtect/test6/VirtualProtect.c
new file mode 100644
index 0000000000..d60b323ec6
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualProtect/test6/VirtualProtect.c
@@ -0,0 +1,68 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: virtualprotect.c
+**
+** Purpose: Positive test the VirtualProtect API.
+** Call VirtualProtect to set new protect as
+** PAGE_NOACCESS
+**
+**
+**============================================================*/
+#include <palsuite.h>
+
+#define REGIONSIZE 1024
+
+int __cdecl main(int argc, char *argv[])
+{
+ int err;
+ LPVOID lpVirtualAddress;
+ DWORD OldProtect;
+
+ //Initialize the PAL environment
+ err = PAL_Initialize(argc, argv);
+ if(0 != err)
+ {
+ ExitProcess(FAIL);
+ }
+ //Allocate the physical storage in memory or in the paging file on disk
+ lpVirtualAddress = VirtualAlloc(NULL,//determine where to allocate the region
+ REGIONSIZE, //specify the size
+ MEM_COMMIT, //allocation type
+ PAGE_READONLY); //access protection
+ if(NULL == lpVirtualAddress)
+ {
+ Fail("\nFailed to call VirtualAlloc API!\n");
+ }
+
+ OldProtect = PAGE_READONLY;
+ //Set new access protection
+ err = VirtualProtect(lpVirtualAddress,
+ REGIONSIZE, //specify the region size
+ PAGE_NOACCESS,//desied access protection
+ &OldProtect);//old access protection
+ if(0 == err)
+ {
+ Trace("\nFailed to call VirtualProtect API!\n");
+ err = VirtualFree(lpVirtualAddress,REGIONSIZE,MEM_DECOMMIT);
+ if(0 == err)
+ {
+ Fail("\nFailed to call VirtualFree API!\n");
+ }
+ Fail("");
+ }
+
+
+ //decommit the specified region
+ err = VirtualFree(lpVirtualAddress,REGIONSIZE,MEM_DECOMMIT);
+ if(0 == err)
+ {
+ Fail("\nFailed to call VirtualFree API!\n");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualProtect/test6/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/VirtualProtect/test6/testinfo.dat
new file mode 100644
index 0000000000..71ccad5639
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualProtect/test6/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = VirtualProtect
+Name = Positive test for VirtualProtect - with PAGE_NOACCESS
+TYPE = DEFAULT
+EXE1 = virtualprotect
+Description
+=Test the VirtualProtect to set new access protection
+=as PAGE_NOACCESS
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualProtect/test7/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/VirtualProtect/test7/CMakeLists.txt
new file mode 100644
index 0000000000..06af860559
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualProtect/test7/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ VirtualProtect.c
+)
+
+add_executable(paltest_virtualprotect_test7
+ ${SOURCES}
+)
+
+add_dependencies(paltest_virtualprotect_test7 coreclrpal)
+
+target_link_libraries(paltest_virtualprotect_test7
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualProtect/test7/VirtualProtect.c b/src/pal/tests/palsuite/filemapping_memmgt/VirtualProtect/test7/VirtualProtect.c
new file mode 100644
index 0000000000..edc37711f4
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualProtect/test7/VirtualProtect.c
@@ -0,0 +1,69 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: virtualprotect.c
+**
+** Purpose: Positive test the VirtualProtect API.
+** Call VirtualProtect to set new protect as
+** PAGE_READONLY
+**
+**
+**============================================================*/
+#include <palsuite.h>
+
+#define REGIONSIZE 1024
+
+int __cdecl main(int argc, char *argv[])
+{
+ int err;
+ LPVOID lpVirtualAddress;
+ DWORD OldProtect;
+
+ //Initialize the PAL environment
+ err = PAL_Initialize(argc, argv);
+ if(0 != err)
+ {
+ ExitProcess(FAIL);
+ }
+
+ //Allocate the physical storage in memory or in the paging file on disk
+ lpVirtualAddress = VirtualAlloc(NULL,//determine where to allocate the region
+ REGIONSIZE, //specify the size
+ MEM_COMMIT, //allocation type
+ PAGE_READWRITE); //access protection
+ if(NULL == lpVirtualAddress)
+ {
+ Fail("\nFailed to call VirtualAlloc API!\n");
+ }
+
+ OldProtect = PAGE_READONLY;
+ //Set new access protection
+ err = VirtualProtect(lpVirtualAddress,
+ REGIONSIZE, //specify the region size
+ PAGE_READONLY,//desied access protection
+ &OldProtect);//old access protection
+ if(0 == err)
+ {
+ Trace("\nFailed to call VirtualProtect API!\n");
+ err = VirtualFree(lpVirtualAddress,REGIONSIZE,MEM_DECOMMIT);
+ if(0 == err)
+ {
+ Fail("\nFailed to call VirtualFree API!\n");
+ }
+ Fail("");
+ }
+
+
+ //decommit the specified region
+ err = VirtualFree(lpVirtualAddress,REGIONSIZE,MEM_DECOMMIT);
+ if(0 == err)
+ {
+ Fail("\nFailed to call VirtualFree API!\n");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualProtect/test7/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/VirtualProtect/test7/testinfo.dat
new file mode 100644
index 0000000000..6b6eb58b34
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualProtect/test7/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = VirtualProtect
+Name = Positive test for VirtualProtect - with PAGE_READONLY
+TYPE = DEFAULT
+EXE1 = virtualprotect
+Description
+=Test the VirtualProtect to set new access protection
+=as PAGE_READONLY
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualQuery/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/VirtualQuery/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualQuery/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualQuery/test1/CMakeLists.txt b/src/pal/tests/palsuite/filemapping_memmgt/VirtualQuery/test1/CMakeLists.txt
new file mode 100644
index 0000000000..4f4e4bc5f0
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualQuery/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ VirtualQuery.c
+)
+
+add_executable(paltest_virtualquery_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_virtualquery_test1 coreclrpal)
+
+target_link_libraries(paltest_virtualquery_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualQuery/test1/VirtualQuery.c b/src/pal/tests/palsuite/filemapping_memmgt/VirtualQuery/test1/VirtualQuery.c
new file mode 100644
index 0000000000..44216ae563
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualQuery/test1/VirtualQuery.c
@@ -0,0 +1,68 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: virtualquery.c
+**
+** Purpose: Positive test the VirtualQuery API.
+** Call VirtualQuery to get the virtual
+** page info
+**
+**
+**============================================================*/
+#include <palsuite.h>
+
+#define VIRTUALMEMORYSIZE 1024
+
+int __cdecl main(int argc, char *argv[])
+{
+ int err;
+ LPVOID lpVirtualAddress;
+ MEMORY_BASIC_INFORMATION PageInfo;
+ DWORD dwBufferSize;
+
+ //Initialize the PAL environment
+ err = PAL_Initialize(argc, argv);
+ if(0 != err)
+ {
+ ExitProcess(FAIL);
+ }
+
+ //Allocate the physical storage in memory or in the paging file on disk
+ lpVirtualAddress = VirtualAlloc(NULL,//determine where to allocate the region
+ VIRTUALMEMORYSIZE, //specify the size
+ MEM_COMMIT, //allocation type
+ PAGE_READONLY); //access protection
+ if(NULL == lpVirtualAddress)
+ {
+ Fail("\nFailed to call VirtualAlloc API!\n");
+ }
+
+ //get the virtual page info
+ dwBufferSize =
+ VirtualQuery(lpVirtualAddress,&PageInfo,sizeof(MEMORY_BASIC_INFORMATION));
+
+ if(dwBufferSize <= 0 ||
+ PageInfo.RegionSize <=0 ||
+ PAGE_READONLY != PageInfo.AllocationProtect ||
+ MEM_COMMIT != PageInfo.State)
+ {
+ Fail("\nFailed to call VirtualQuery API!\n");
+ }
+
+
+
+ //decommit the specified region
+ err = VirtualFree(lpVirtualAddress, //virtual page base address
+ VIRTUALMEMORYSIZE,//specify the size
+ MEM_DECOMMIT);//free operation
+ if(0 == err)
+ {
+ Fail("\nFailed to call VirtualFree API!\n");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/filemapping_memmgt/VirtualQuery/test1/testinfo.dat b/src/pal/tests/palsuite/filemapping_memmgt/VirtualQuery/test1/testinfo.dat
new file mode 100644
index 0000000000..b3462cd2f7
--- /dev/null
+++ b/src/pal/tests/palsuite/filemapping_memmgt/VirtualQuery/test1/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Filemapping_memmgt
+Function = VirtualQuery
+Name = Positive test for VirtualQuery API
+TYPE = DEFAULT
+EXE1 = virtualquery
+Description
+=Test the VirtualQuery to get the virtual page info
diff --git a/src/pal/tests/palsuite/loader/CMakeLists.txt b/src/pal/tests/palsuite/loader/CMakeLists.txt
new file mode 100644
index 0000000000..2c213b8426
--- /dev/null
+++ b/src/pal/tests/palsuite/loader/CMakeLists.txt
@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(LoadLibraryA)
+add_subdirectory(LoadLibraryW)
+
diff --git a/src/pal/tests/palsuite/loader/LoadLibraryA/CMakeLists.txt b/src/pal/tests/palsuite/loader/LoadLibraryA/CMakeLists.txt
new file mode 100644
index 0000000000..ff4c550d38
--- /dev/null
+++ b/src/pal/tests/palsuite/loader/LoadLibraryA/CMakeLists.txt
@@ -0,0 +1,8 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+add_subdirectory(test3)
+add_subdirectory(test5)
+add_subdirectory(test7)
+
diff --git a/src/pal/tests/palsuite/loader/LoadLibraryA/test1/CMakeLists.txt b/src/pal/tests/palsuite/loader/LoadLibraryA/test1/CMakeLists.txt
new file mode 100644
index 0000000000..542f8d3277
--- /dev/null
+++ b/src/pal/tests/palsuite/loader/LoadLibraryA/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ LoadLibraryA.c
+)
+
+add_executable(paltest_loadlibrarya_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_loadlibrarya_test1 coreclrpal)
+
+target_link_libraries(paltest_loadlibrarya_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/loader/LoadLibraryA/test1/LoadLibraryA.c b/src/pal/tests/palsuite/loader/LoadLibraryA/test1/LoadLibraryA.c
new file mode 100644
index 0000000000..b4a8de1367
--- /dev/null
+++ b/src/pal/tests/palsuite/loader/LoadLibraryA/test1/LoadLibraryA.c
@@ -0,0 +1,53 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: loadlibrarya.c
+**
+** Purpose: Positive test the LoadLibrary API.
+** Call LoadLibrary to map a module into the calling
+** process address space(DLL file)
+**
+**
+**============================================================*/
+#include <palsuite.h>
+
+/* SHLEXT is defined only for Unix variants */
+
+#if defined(SHLEXT)
+#define ModuleName "librotor_pal"SHLEXT
+#else
+#define ModuleName "rotor_pal.dll"
+#endif
+
+int __cdecl main(int argc, char *argv[])
+{
+ HMODULE ModuleHandle;
+ int err;
+
+ /* Initialize the PAL environment */
+ err = PAL_Initialize(argc, argv);
+ if(0 != err)
+ {
+ ExitProcess(FAIL);
+ }
+
+ /* load a module */
+ ModuleHandle = LoadLibrary(ModuleName);
+ if(!ModuleHandle)
+ {
+ Fail("Failed to call LoadLibrary API!\n");
+ }
+
+ /* decrement the reference count of the loaded dll */
+ err = FreeLibrary(ModuleHandle);
+ if(0 == err)
+ {
+ Fail("\nFailed to all FreeLibrary API!\n");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/loader/LoadLibraryA/test1/testinfo.dat b/src/pal/tests/palsuite/loader/LoadLibraryA/test1/testinfo.dat
new file mode 100644
index 0000000000..096aab958b
--- /dev/null
+++ b/src/pal/tests/palsuite/loader/LoadLibraryA/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Loader
+Function = LoadLibraryA
+Name = Positive test for LoadLibraryA API to load Dynamic library module
+TYPE = DEFAULT
+EXE1 = loadlibrarya
+Description
+=Test the LoadLibraryA to map module into calling process address space
+
diff --git a/src/pal/tests/palsuite/loader/LoadLibraryA/test2/CMakeLists.txt b/src/pal/tests/palsuite/loader/LoadLibraryA/test2/CMakeLists.txt
new file mode 100644
index 0000000000..63cfb22545
--- /dev/null
+++ b/src/pal/tests/palsuite/loader/LoadLibraryA/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ LoadLibraryA.c
+)
+
+add_executable(paltest_loadlibrarya_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_loadlibrarya_test2 coreclrpal)
+
+target_link_libraries(paltest_loadlibrarya_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/loader/LoadLibraryA/test2/LoadLibraryA.c b/src/pal/tests/palsuite/loader/LoadLibraryA/test2/LoadLibraryA.c
new file mode 100644
index 0000000000..d7cd9cb875
--- /dev/null
+++ b/src/pal/tests/palsuite/loader/LoadLibraryA/test2/LoadLibraryA.c
@@ -0,0 +1,52 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: loadlibrarya.c
+**
+** Purpose: Negative test the LoadLibraryA API.
+** Call LoadLibraryA with a not exist module Name
+**
+**
+**============================================================*/
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ HMODULE ModuleHandle;
+ int err;
+ const char *pModuleName = "Not-exist-module-name";
+
+ /* Initialize the PAL environment */
+ err = PAL_Initialize(argc, argv);
+ if(0 != err)
+ {
+ return FAIL;
+ }
+
+ /*try to load a not exist module */
+ ModuleHandle = LoadLibraryA(pModuleName);
+ if(NULL != ModuleHandle)
+ {
+ Trace("Failed to call LoadLibraryA with a not exist mudule name, "
+ "a NULL module handle is expected, but no NULL module handle "
+ "is returned, error code=%u\n", GetLastError());
+
+ /* decrement the reference count of the loaded module */
+ err = FreeLibrary(ModuleHandle);
+ if(0 == err)
+ {
+ Trace("\nFailed to all FreeLibrary API to decrement "
+ "the reference count of the loaded module, "
+ "error code = %u\n", GetLastError());
+
+ }
+
+ Fail("");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/loader/LoadLibraryA/test2/MyModule.c b/src/pal/tests/palsuite/loader/LoadLibraryA/test2/MyModule.c
new file mode 100644
index 0000000000..883b3fbc4a
--- /dev/null
+++ b/src/pal/tests/palsuite/loader/LoadLibraryA/test2/MyModule.c
@@ -0,0 +1,19 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: mymoduale.c
+**
+** Purpose: Positive test the LoadLibrary API.
+**
+
+**
+**============================================================*/
+
+int __cdecl main(int argc, char *argv[])
+{
+ //only for testing LoadLibrary
+ return 0;
+}
diff --git a/src/pal/tests/palsuite/loader/LoadLibraryA/test2/testinfo.dat b/src/pal/tests/palsuite/loader/LoadLibraryA/test2/testinfo.dat
new file mode 100644
index 0000000000..97b7222b9e
--- /dev/null
+++ b/src/pal/tests/palsuite/loader/LoadLibraryA/test2/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Loader
+Function = LoadLibraryA
+Name = Negative test LoadLibraryA API to load a not exist module
+TYPE = DEFAULT
+EXE1 = loadlibrarya
+Description
+=Test the LoadLibraryA to load a not exist module
+
diff --git a/src/pal/tests/palsuite/loader/LoadLibraryA/test3/CMakeLists.txt b/src/pal/tests/palsuite/loader/LoadLibraryA/test3/CMakeLists.txt
new file mode 100644
index 0000000000..143d0ec096
--- /dev/null
+++ b/src/pal/tests/palsuite/loader/LoadLibraryA/test3/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ loadlibrarya.c
+)
+
+add_executable(paltest_loadlibrarya_test3
+ ${SOURCES}
+)
+
+add_dependencies(paltest_loadlibrarya_test3 coreclrpal)
+
+target_link_libraries(paltest_loadlibrarya_test3
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/loader/LoadLibraryA/test3/loadlibrarya.c b/src/pal/tests/palsuite/loader/LoadLibraryA/test3/loadlibrarya.c
new file mode 100644
index 0000000000..da38f98d04
--- /dev/null
+++ b/src/pal/tests/palsuite/loader/LoadLibraryA/test3/loadlibrarya.c
@@ -0,0 +1,40 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: loadlibrarya.c
+**
+** Purpose: Negative test the LoadLibrary API with NULL module
+** name.
+**
+**
+**============================================================*/
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ HMODULE ModuleHandle;
+ int err;
+
+ /*Initialize the PAL environment*/
+ err = PAL_Initialize(argc, argv);
+ if(0 != err)
+ {
+ return FAIL;
+ }
+
+ /*load a module by passing a NULL module name*/
+ ModuleHandle = LoadLibraryA(NULL);
+ if(NULL != ModuleHandle)
+ {
+ Fail("\nFailed to call loadlibrarya API for a negative test, "
+ "call loadibrarya with NULL moudle name, a NULL module "
+ "handle is expected, but no NULL module handle is returned, "
+ "error code =%u\n", GetLastError());
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/loader/LoadLibraryA/test3/testinfo.dat b/src/pal/tests/palsuite/loader/LoadLibraryA/test3/testinfo.dat
new file mode 100644
index 0000000000..c27c8e0eea
--- /dev/null
+++ b/src/pal/tests/palsuite/loader/LoadLibraryA/test3/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Loader
+Function = LoadLibraryA
+Name = Negative test LoadLibraryA API with a NULL module name
+TYPE = DEFAULT
+EXE1 = loadlibrarya
+Description
+=Test the LoadLibraryA to map NULL module into calling
+=process address space
+
diff --git a/src/pal/tests/palsuite/loader/LoadLibraryA/test5/CMakeLists.txt b/src/pal/tests/palsuite/loader/LoadLibraryA/test5/CMakeLists.txt
new file mode 100644
index 0000000000..a9d791c916
--- /dev/null
+++ b/src/pal/tests/palsuite/loader/LoadLibraryA/test5/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ loadlibrarya.c
+)
+
+add_executable(paltest_loadlibrarya_test5
+ ${SOURCES}
+)
+
+add_dependencies(paltest_loadlibrarya_test5 coreclrpal)
+
+target_link_libraries(paltest_loadlibrarya_test5
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/loader/LoadLibraryA/test5/loadlibrarya.c b/src/pal/tests/palsuite/loader/LoadLibraryA/test5/loadlibrarya.c
new file mode 100644
index 0000000000..d1e6b6d1dc
--- /dev/null
+++ b/src/pal/tests/palsuite/loader/LoadLibraryA/test5/loadlibrarya.c
@@ -0,0 +1,67 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: loadlibrarya.c
+**
+** Purpose: Negative test the LoadLibraryA API.
+** Call LoadLibraryA by passing a module name
+** without extension but with a trailing dot.
+**
+**
+**============================================================*/
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ HMODULE ModuleHandle;
+ char ModuleName[_MAX_FNAME];
+ int err;
+
+ /* Initialize the PAL environment */
+ err = PAL_Initialize(argc, argv);
+ if(0 != err)
+ {
+ return FAIL;
+ }
+
+ memset(ModuleName, 0, _MAX_FNAME);
+
+ /*Module name without extension but with a trailing dot*/
+#if WIN32
+ sprintf(ModuleName, "%s", "rotor_pal.");
+#else
+ /* Under FreeBSD */
+ sprintf(ModuleName, "%s", "librotor_pal.");
+#endif
+
+ /* load a module which does not have the file extension,
+ * but has a trailing dot
+ */
+ ModuleHandle = LoadLibraryA(ModuleName);
+ if(NULL != ModuleHandle)
+ {
+ Trace("Failed to call LoadLibraryA API for a negative test "
+ "call LoadLibraryA with module name which does not have "
+ "extension except a trailing dot, a NULL module handle is"
+ "expected, but no NULL module handle is returned, "
+ "error code = %u\n", GetLastError());
+
+
+ /* decrement the reference count of the loaded dll */
+ err = FreeLibrary(ModuleHandle);
+ if(0 == err)
+ {
+ Trace("\nFailed to call FreeLibrary API, "
+ "error code = %u\n", GetLastError());
+ }
+
+ Fail("");
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/loader/LoadLibraryA/test5/testinfo.dat b/src/pal/tests/palsuite/loader/LoadLibraryA/test5/testinfo.dat
new file mode 100644
index 0000000000..e2cd16c6f1
--- /dev/null
+++ b/src/pal/tests/palsuite/loader/LoadLibraryA/test5/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Loader
+Function = LoadLibraryA
+Name = Negative test for LoadLibraryA API by passing a module name without extension but with a trailing dot.
+TYPE = DEFAULT
+EXE1 = loadlibrarya
+Description
+=Test the LoadLibraryA by passing a module name without extension
+=but with a trailing dot.
+
diff --git a/src/pal/tests/palsuite/loader/LoadLibraryA/test6/CMakeLists.txt b/src/pal/tests/palsuite/loader/LoadLibraryA/test6/CMakeLists.txt
new file mode 100644
index 0000000000..bb66adef77
--- /dev/null
+++ b/src/pal/tests/palsuite/loader/LoadLibraryA/test6/CMakeLists.txt
@@ -0,0 +1,36 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(TESTSOURCES
+ loadlibrarya.c
+)
+
+add_executable(paltest_loadlibrarya_test6
+ ${TESTSOURCES}
+)
+
+add_dependencies(paltest_loadlibrarya_test6 coreclrpal)
+
+target_link_libraries(paltest_loadlibrarya_test6
+ pthread
+ m
+ coreclrpal
+)
+
+
+set(HELPERSOURCES
+ dlltest.c
+)
+
+add_executable(paltest_loadlibrarya_test6_dlltest
+ ${HELPERSOURCES}
+)
+
+add_dependencies(paltest_loadlibrarya_test6_dlltest coreclrpal)
+
+target_link_libraries(paltest_loadlibrarya_test6_dlltest
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/loader/LoadLibraryA/test6/dlltest.c b/src/pal/tests/palsuite/loader/LoadLibraryA/test6/dlltest.c
new file mode 100644
index 0000000000..72380eebb5
--- /dev/null
+++ b/src/pal/tests/palsuite/loader/LoadLibraryA/test6/dlltest.c
@@ -0,0 +1,72 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================================
+**
+** Source: dllmain.c
+**
+** Purpose: Test to ensure DllMain() is called with DLL_THREAD_DETACH
+** only the initial time that the library is loaded.
+**
+** Depends: None
+**
+
+**
+**===========================================================================*/
+
+#include <palsuite.h>
+
+/* count of the number of times DllMain()
+ * was called with THREAD_ATTACH.
+ */
+static int g_attachCount = 0;
+
+/* standard DllMain() */
+BOOL __stdcall DllMain(HINSTANCE hinstDLL, DWORD reason, LPVOID lpvReserved)
+{
+ switch( reason )
+ {
+ case DLL_PROCESS_ATTACH:
+ {
+ g_attachCount++;
+ break;
+ }
+
+ case DLL_PROCESS_DETACH:
+ {
+ break;
+ }
+
+ case DLL_THREAD_ATTACH:
+ {
+ break;
+ }
+
+ case DLL_THREAD_DETACH:
+ {
+ break;
+ }
+ }
+
+ return TRUE;
+}
+
+#if _WIN32
+BOOL __stdcall _DllMainCRTStartup(HINSTANCE hinstDLL, DWORD reason, LPVOID lpvReserved)
+{
+ return DllMain(hinstDLL, reason, lpvReserved);
+}
+#endif
+
+
+
+/* function to return the current attach count */
+#if _WIN32
+__declspec(dllexport)
+#endif
+int PALAPI GetAttachCount( void )
+{
+ return g_attachCount;
+}
+
diff --git a/src/pal/tests/palsuite/loader/LoadLibraryA/test6/loadlibrarya.c b/src/pal/tests/palsuite/loader/LoadLibraryA/test6/loadlibrarya.c
new file mode 100644
index 0000000000..ee825e6439
--- /dev/null
+++ b/src/pal/tests/palsuite/loader/LoadLibraryA/test6/loadlibrarya.c
@@ -0,0 +1,172 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: loadlibrary.c (test 6)
+**
+** Purpose: Positive test the LoadLibrary API. Test will verify
+** that it is unable to load the library twice. Once by
+** using the full path name and secondly by using the
+** short name.
+**
+
+**
+**============================================================*/
+#include <palsuite.h>
+
+/*Define platform specific information*/
+#if defined(SHLEXT)
+#define LibraryName "dlltest"SHLEXT
+#define GETATTACHCOUNTNAME "GetAttachCount"
+#else
+typedef int (*dllfunct)();
+#define LibraryName "dlltest.dll"
+#define GETATTACHCOUNTNAME "_GetAttachCount@0"
+#endif
+
+
+/* Helper function to test the loaded library.
+ */
+BOOL PALAPI TestDll(HMODULE hLib)
+{
+ int RetVal;
+ char FunctName[] = GETATTACHCOUNTNAME;
+ FARPROC DllFunc;
+
+ /* Access a function from the loaded library.
+ */
+ DllFunc = GetProcAddress(hLib, FunctName);
+ if(DllFunc == NULL)
+ {
+ Trace("ERROR: Unable to load function \"%s\" from library \"%s\"\n",
+ FunctName,
+ LibraryName);
+ return (FALSE);
+ }
+
+ /* Verify that the DLL_PROCESS_ATTACH is only
+ * accessed once.*/
+ RetVal = DllFunc();
+ if (RetVal != 1)
+ {
+ Trace("ERROR: Unable to receive correct information from DLL! "
+ ":expected \"1\", returned \"%d\"\n",
+ RetVal);
+ return (FALSE);
+ }
+
+ return (TRUE);
+}
+
+int __cdecl main(int argc, char *argv[])
+{
+ HANDLE hFullLib;
+ HANDLE hShortLib;
+ int iRetVal = FAIL;
+ char fullPath[_MAX_DIR];
+ char drive[_MAX_DRIVE];
+ char dir[_MAX_DIR];
+ char fname[_MAX_FNAME];
+ char ext[_MAX_EXT];
+
+
+
+ /* Initialize the PAL. */
+ if ((PAL_Initialize(argc, argv)) != 0)
+ {
+ return (FAIL);
+ }
+
+ /* Initalize the buffer.
+ */
+ memset(fullPath, 0, _MAX_DIR);
+
+ /* Get the full path to the library (DLL).
+ */
+
+ if (NULL != _fullpath(fullPath,argv[0],_MAX_DIR)) {
+
+ _splitpath(fullPath,drive,dir,fname,ext);
+ _makepath(fullPath,drive,dir,LibraryName,"");
+
+
+ } else {
+ Fail("ERROR: conversion from relative path \" %s \" to absolute path failed. _fullpath returned NULL\n",argv[0]);
+ }
+
+ /* Call Load library with the short name of
+ * the dll.
+ */
+ hShortLib = LoadLibrary(LibraryName);
+ if(hShortLib == NULL)
+ {
+ Fail("ERROR:%u:Unable to load library %s\n",
+ GetLastError(),
+ LibraryName);
+ }
+
+ /* Test the loaded library.
+ */
+ if (!TestDll(hShortLib))
+ {
+ iRetVal = FAIL;
+ goto cleanUpOne;
+ }
+
+ /* Call Load library with the full name of
+ * the dll.
+ */
+ hFullLib = LoadLibrary(fullPath);
+ if(hFullLib == NULL)
+ {
+ Trace("ERROR:%u:Unable to load library %s\n",
+ GetLastError(),
+ fullPath);
+ iRetVal = FAIL;
+ goto cleanUpTwo;
+ }
+
+ /* Test the loaded library.
+ */
+ if (!TestDll(hFullLib))
+ {
+ iRetVal = FAIL;
+ goto cleanUpTwo;
+ }
+
+ /* Test Succeeded.
+ */
+ iRetVal = PASS;
+
+cleanUpTwo:
+
+ /* Call the FreeLibrary API.
+ */
+ if (!FreeLibrary(hFullLib))
+ {
+ Trace("ERROR:%u: Unable to free library \"%s\"\n",
+ GetLastError(),
+ fullPath);
+ iRetVal = FAIL;
+ }
+
+cleanUpOne:
+
+ /* Call the FreeLibrary API.
+ */
+ if (!FreeLibrary(hShortLib))
+ {
+ Trace("ERROR:%u: Unable to free library \"%s\"\n",
+ GetLastError(),
+ LibraryName);
+ iRetVal = FAIL;
+ }
+
+ /* Terminate the PAL.
+ */
+ PAL_Terminate();
+ return iRetVal;
+
+}
diff --git a/src/pal/tests/palsuite/loader/LoadLibraryA/test6/testinfo.dat b/src/pal/tests/palsuite/loader/LoadLibraryA/test6/testinfo.dat
new file mode 100644
index 0000000000..4be93b8092
--- /dev/null
+++ b/src/pal/tests/palsuite/loader/LoadLibraryA/test6/testinfo.dat
@@ -0,0 +1,17 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Loader
+Function = LoadLibraryA
+Name = Positive test for LoadLibrary API
+TYPE = DEFAULT
+EXE1 = loadlibrarya
+LIB1 = dlltest
+Description
+= Positive test the LoadLibrary API. Test will verify
+= that it is unable to load the library twice. Once by
+= using the full path name and secondly by using the
+= short name.
+
diff --git a/src/pal/tests/palsuite/loader/LoadLibraryA/test7/CMakeLists.txt b/src/pal/tests/palsuite/loader/LoadLibraryA/test7/CMakeLists.txt
new file mode 100644
index 0000000000..6c0d174600
--- /dev/null
+++ b/src/pal/tests/palsuite/loader/LoadLibraryA/test7/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ LoadLibraryA.c
+)
+
+add_executable(paltest_loadlibrarya_test7
+ ${SOURCES}
+)
+
+add_dependencies(paltest_loadlibrarya_test7 coreclrpal)
+
+target_link_libraries(paltest_loadlibrarya_test7
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/loader/LoadLibraryA/test7/LoadLibraryA.c b/src/pal/tests/palsuite/loader/LoadLibraryA/test7/LoadLibraryA.c
new file mode 100644
index 0000000000..5e6db8bb68
--- /dev/null
+++ b/src/pal/tests/palsuite/loader/LoadLibraryA/test7/LoadLibraryA.c
@@ -0,0 +1,83 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: loadlibrarya.c
+**
+** Purpose: Positive test the LoadLibrary API by calling it multiple times.
+** Call LoadLibrary to map a module into the calling
+** process address space(DLL file)
+**
+**
+**============================================================*/
+#include <palsuite.h>
+
+/* SHLEXT is defined only for Unix variants */
+
+#if defined(SHLEXT)
+#define ModuleName "librotor_pal"SHLEXT
+#else
+#define ModuleName "rotor_pal.dll"
+#endif
+
+int __cdecl main(int argc, char *argv[])
+{
+ HMODULE ModuleHandle;
+ HMODULE ReturnHandle;
+ int err;
+
+ /* Initialize the PAL environment */
+ err = PAL_Initialize(argc, argv);
+ if(0 != err)
+ {
+ ExitProcess(FAIL);
+ }
+
+ /* load a module */
+ ModuleHandle = LoadLibrary(ModuleName);
+ if(!ModuleHandle)
+ {
+ Fail("Error[%u]:Failed to call LoadLibrary API!\n", GetLastError());
+ }
+
+ /* Call LoadLibrary again, should return same handle as returned for first time */
+ ReturnHandle = LoadLibrary(ModuleName);
+ if(!ReturnHandle)
+ {
+ Fail("Error[%u]:Failed to call LoadLibrary API second time!\n", GetLastError());
+ }
+
+ if(ModuleHandle != ReturnHandle)
+ {
+ Fail("Error[%u]:Failed to return the same handle while calling LoadLibrary API twice!\n", GetLastError());
+ }
+
+ Trace("Value of handle ModuleHandle[%x], ReturnHandle[%x]\n", ModuleHandle, ReturnHandle);
+ /* decrement the reference count of the loaded dll */
+ err = FreeLibrary(ModuleHandle);
+
+ if(0 == err)
+ {
+ Fail("Error[%u]:Failed to FreeLibrary API!\n", GetLastError());
+ }
+
+ /* Try Freeing a library again, should not fail */
+ err = FreeLibrary(ReturnHandle);
+
+ if(0 == err)
+ {
+ Fail("Error[%u][%d]: Was not successful in freeing a Library twice using FreeLibrary!\n", GetLastError(), err);
+ }
+
+ /* Try Freeing a library again, should fail */
+ err = FreeLibrary(ReturnHandle);
+
+ if(1 != err)
+ {
+ Fail("Error[%u][%d]: Was successful in freeing a Library thrice using FreeLibrary!\n", GetLastError(), err);
+ }
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/loader/LoadLibraryA/test7/testinfo.dat b/src/pal/tests/palsuite/loader/LoadLibraryA/test7/testinfo.dat
new file mode 100644
index 0000000000..416caf34fb
--- /dev/null
+++ b/src/pal/tests/palsuite/loader/LoadLibraryA/test7/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Loader
+Function = LoadLibraryA
+Name = Positive and Negative test for LoadLibraryA API to load Dynamic library module
+TYPE = DEFAULT
+EXE1 = loadlibrarya
+Description
+=Test the LoadLibraryA to load multiple times and call unload more times than load
+
diff --git a/src/pal/tests/palsuite/loader/LoadLibraryA/test8/CMakeLists.txt b/src/pal/tests/palsuite/loader/LoadLibraryA/test8/CMakeLists.txt
new file mode 100644
index 0000000000..b663a7b5bc
--- /dev/null
+++ b/src/pal/tests/palsuite/loader/LoadLibraryA/test8/CMakeLists.txt
@@ -0,0 +1,36 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(TESTSOURCES
+ loadlibrarya.c
+)
+
+add_executable(paltest_loadlibrarya_test8
+ ${TESTSOURCES}
+)
+
+add_dependencies(paltest_loadlibrarya_test8 coreclrpal)
+
+target_link_libraries(paltest_loadlibrarya_test8
+ pthread
+ m
+ coreclrpal
+)
+
+
+set(HELPERSOURCES
+ dlltest.c
+)
+
+add_executable(paltest_loadlibrarya_test8_dlltest
+ ${HELPERSOURCES}
+)
+
+add_dependencies(paltest_loadlibrarya_test8_dlltest coreclrpal)
+
+target_link_libraries(paltest_loadlibrarya_test8_dlltest
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/loader/LoadLibraryA/test8/dlltest.c b/src/pal/tests/palsuite/loader/LoadLibraryA/test8/dlltest.c
new file mode 100644
index 0000000000..72380eebb5
--- /dev/null
+++ b/src/pal/tests/palsuite/loader/LoadLibraryA/test8/dlltest.c
@@ -0,0 +1,72 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================================
+**
+** Source: dllmain.c
+**
+** Purpose: Test to ensure DllMain() is called with DLL_THREAD_DETACH
+** only the initial time that the library is loaded.
+**
+** Depends: None
+**
+
+**
+**===========================================================================*/
+
+#include <palsuite.h>
+
+/* count of the number of times DllMain()
+ * was called with THREAD_ATTACH.
+ */
+static int g_attachCount = 0;
+
+/* standard DllMain() */
+BOOL __stdcall DllMain(HINSTANCE hinstDLL, DWORD reason, LPVOID lpvReserved)
+{
+ switch( reason )
+ {
+ case DLL_PROCESS_ATTACH:
+ {
+ g_attachCount++;
+ break;
+ }
+
+ case DLL_PROCESS_DETACH:
+ {
+ break;
+ }
+
+ case DLL_THREAD_ATTACH:
+ {
+ break;
+ }
+
+ case DLL_THREAD_DETACH:
+ {
+ break;
+ }
+ }
+
+ return TRUE;
+}
+
+#if _WIN32
+BOOL __stdcall _DllMainCRTStartup(HINSTANCE hinstDLL, DWORD reason, LPVOID lpvReserved)
+{
+ return DllMain(hinstDLL, reason, lpvReserved);
+}
+#endif
+
+
+
+/* function to return the current attach count */
+#if _WIN32
+__declspec(dllexport)
+#endif
+int PALAPI GetAttachCount( void )
+{
+ return g_attachCount;
+}
+
diff --git a/src/pal/tests/palsuite/loader/LoadLibraryA/test8/loadlibrarya.c b/src/pal/tests/palsuite/loader/LoadLibraryA/test8/loadlibrarya.c
new file mode 100644
index 0000000000..6556e9c896
--- /dev/null
+++ b/src/pal/tests/palsuite/loader/LoadLibraryA/test8/loadlibrarya.c
@@ -0,0 +1,235 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: loadlibrary.c (test 8)
+**
+** Purpose: Positive test the LoadLibrary API. Test will verify
+** that it is unable to load the library twice. Once by
+** using the full path name and secondly by using the
+** short name.
+**
+
+**
+**============================================================*/
+#include <palsuite.h>
+
+/*Define platform specific information*/
+#if defined(SHLEXT)
+#define LibraryName "dlltest"SHLEXT
+#define GETATTACHCOUNTNAME "GetAttachCount"
+#else
+typedef int (*dllfunct)();
+#define LibraryName "dlltest.dll"
+#define GETATTACHCOUNTNAME "_GetAttachCount@0"
+#endif
+
+
+/* Helper function to test the loaded library.
+ */
+BOOL PALAPI TestDll(HMODULE hLib)
+{
+ int RetVal;
+ char FunctName[] = GETATTACHCOUNTNAME;
+ FARPROC DllFunc;
+
+ /* Access a function from the loaded library.
+ */
+ DllFunc = GetProcAddress(hLib, FunctName);
+ if(DllFunc == NULL)
+ {
+ Trace("ERROR: Unable to load function \"%s\" from library \"%s\"\n",
+ FunctName,
+ LibraryName);
+ return (FALSE);
+ }
+
+ /* Verify that the DLL_PROCESS_ATTACH is only
+ * accessed once.*/
+ RetVal = DllFunc();
+ if (RetVal != 1)
+ {
+ Trace("ERROR: Unable to receive correct information from DLL! "
+ ":expected \"1\", returned \"%d\"\n",
+ RetVal);
+ return (FALSE);
+ }
+
+ return (TRUE);
+}
+
+int __cdecl main(int argc, char *argv[])
+{
+ HANDLE hFullLib;
+ HANDLE hShortLib;
+ HANDLE hRelLib;
+
+ int iRetVal = FAIL;
+ char fullPath[_MAX_DIR];
+ char drive[_MAX_DRIVE];
+ char dir[_MAX_DIR];
+ char relTestDir[_MAX_DIR];
+ char fname[_MAX_FNAME];
+ char ext[_MAX_EXT];
+
+ BOOL bRc = FALSE;
+ char relLibPath[_MAX_DIR];
+
+
+ /* Initialize the PAL. */
+ if ((PAL_Initialize(argc, argv)) != 0)
+ {
+ return (FAIL);
+ }
+
+ /* Initalize the buffer.
+ */
+ memset(fullPath, 0, _MAX_DIR);
+
+ /* Get the full path to the library (DLL).
+ */
+
+ if (NULL != _fullpath(fullPath,argv[0],_MAX_DIR)) {
+
+ _splitpath(fullPath,drive,dir,fname,ext);
+ _makepath(fullPath,drive,dir,LibraryName,"");
+
+
+ } else {
+ Fail("ERROR: conversion from relative path \" %s \" to absolute path failed. _fullpath returned NULL\n",argv[0]);
+ }
+
+ /* Get relative path to the library
+ */
+ _splitpath(argv[0], drive, relTestDir, fname, ext);
+ _makepath(relLibPath,drive,relTestDir,LibraryName,"");
+
+
+ /* Call Load library with the short name of
+ * the dll.
+ */
+ hShortLib = LoadLibrary(LibraryName);
+ if(hShortLib == NULL)
+ {
+ Fail("ERROR:%u:Short:Unable to load library %s\n",
+ GetLastError(),
+ LibraryName);
+ }
+
+ /* Test the loaded library.
+ */
+ if (!TestDll(hShortLib))
+ {
+ iRetVal = FAIL;
+ goto cleanUpOne;
+ }
+
+ /* Call Load library with the full name of
+ * the dll.
+ */
+ hFullLib = LoadLibrary(fullPath);
+ if(hFullLib == NULL)
+ {
+ Trace("ERROR:%u:Full:Unable to load library %s\n",
+ GetLastError(),
+ fullPath);
+ iRetVal = FAIL;
+ goto cleanUpTwo;
+ }
+
+ /* Test the loaded library.
+ */
+ if (!TestDll(hFullLib))
+ {
+ iRetVal = FAIL;
+ goto cleanUpTwo;
+ }
+
+ /*
+ ** Call the load library with the relative path
+ ** wrt to the directory ./testloadlibrary/..
+ ** since we don't want to make any assumptions
+ ** regarding the type of build
+ */
+ hRelLib = LoadLibrary(relLibPath);
+ if(hRelLib == NULL)
+ {
+ Trace("ERROR:%u:Rel:Unable to load library at %s\n",
+ GetLastError(), relLibPath);
+ iRetVal = FAIL;
+ goto cleanUpTwo;
+ }
+
+ /* Test the loaded library.
+ */
+ if (!TestDll(hRelLib))
+ {
+ iRetVal = FAIL;
+ goto cleanUpThree;
+ }
+
+ if( hRelLib != hFullLib )
+ {
+ Trace("Relative and Absolute Paths to libraries don't have same handle\n");
+ iRetVal = FAIL;
+ goto cleanUpThree;
+ }
+
+ if( hRelLib != hShortLib )
+ {
+ Trace("Relative and Short Paths to libraries don't have same handle\n");
+ iRetVal = FAIL;
+ goto cleanUpThree;
+ }
+
+
+ /* Test Succeeded.
+ */
+ iRetVal = PASS;
+
+cleanUpThree:
+
+ /* Call the FreeLibrary API.
+ */
+
+ if (!FreeLibrary(hRelLib))
+ {
+ Trace("ERROR:%u: Unable to free library \"%s\"\n",
+ GetLastError(),
+ relLibPath);
+ iRetVal = FAIL;
+ }
+
+cleanUpTwo:
+
+ /* Call the FreeLibrary API.
+ */
+ if (!FreeLibrary(hFullLib))
+ {
+ Trace("ERROR:%u: Unable to free library \"%s\"\n",
+ GetLastError(),
+ fullPath);
+ iRetVal = FAIL;
+ }
+
+cleanUpOne:
+
+ /* Call the FreeLibrary API.
+ */
+ if (!FreeLibrary(hShortLib))
+ {
+ Trace("ERROR:%u: Unable to free library \"%s\"\n",
+ GetLastError(),
+ LibraryName);
+ iRetVal = FAIL;
+ }
+
+
+ /* Terminate the PAL.
+ */
+ PAL_TerminateEx(iRetVal);
+ return iRetVal;
+
+}
diff --git a/src/pal/tests/palsuite/loader/LoadLibraryA/test8/testinfo.dat b/src/pal/tests/palsuite/loader/LoadLibraryA/test8/testinfo.dat
new file mode 100644
index 0000000000..b552b72082
--- /dev/null
+++ b/src/pal/tests/palsuite/loader/LoadLibraryA/test8/testinfo.dat
@@ -0,0 +1,17 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Loader
+Function = LoadLibraryA
+Name = Positive test for LoadLibrary API
+TYPE = DEFAULT
+EXE1 = loadlibrarya
+LIB1 = dlltest
+Description
+= Positive test the LoadLibrary API. Test will verify
+= that it is able to load the library thrice. Once by
+= using the full path name, second by using the
+= short name and third by using relative paths
+
diff --git a/src/pal/tests/palsuite/loader/LoadLibraryW/CMakeLists.txt b/src/pal/tests/palsuite/loader/LoadLibraryW/CMakeLists.txt
new file mode 100644
index 0000000000..37abc032af
--- /dev/null
+++ b/src/pal/tests/palsuite/loader/LoadLibraryW/CMakeLists.txt
@@ -0,0 +1,7 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+add_subdirectory(test3)
+add_subdirectory(test5)
+
diff --git a/src/pal/tests/palsuite/loader/LoadLibraryW/test1/CMakeLists.txt b/src/pal/tests/palsuite/loader/LoadLibraryW/test1/CMakeLists.txt
new file mode 100644
index 0000000000..87038012b7
--- /dev/null
+++ b/src/pal/tests/palsuite/loader/LoadLibraryW/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ LoadLibraryW.c
+)
+
+add_executable(paltest_loadlibraryw_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_loadlibraryw_test1 coreclrpal)
+
+target_link_libraries(paltest_loadlibraryw_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/loader/LoadLibraryW/test1/LoadLibraryW.c b/src/pal/tests/palsuite/loader/LoadLibraryW/test1/LoadLibraryW.c
new file mode 100644
index 0000000000..4c1a551de1
--- /dev/null
+++ b/src/pal/tests/palsuite/loader/LoadLibraryW/test1/LoadLibraryW.c
@@ -0,0 +1,62 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: loadlibraryw.c
+**
+** Purpose: Positive test the LoadLibrary API.
+** Call LoadLibrary to map a module into the calling
+** process address space(DLL file)
+**
+**
+**============================================================*/
+#define UNICODE
+#include <palsuite.h>
+/* SHLEXT is defined only for Unix variants */
+
+#if defined(SHLEXT)
+#define ModuleName "librotor_pal"SHLEXT
+#else
+#define ModuleName "rotor_pal.dll"
+#endif
+
+int __cdecl main(int argc, char *argv[])
+{
+ HMODULE ModuleHandle;
+ int err;
+ WCHAR *lpModuleName;
+
+ /* Initialize the PAL environment */
+ err = PAL_Initialize(argc, argv);
+ if(0 != err)
+ {
+ ExitProcess(FAIL);
+ }
+
+ /* convert a normal string to a wide one */
+ lpModuleName = convert(ModuleName);
+
+ /* load a module */
+ ModuleHandle = LoadLibrary(lpModuleName);
+
+ /* free the memory */
+ free(lpModuleName);
+
+ if(!ModuleHandle)
+ {
+ Fail("Failed to call LoadLibrary API!\n");
+ }
+
+
+ /* decrement the reference count of the loaded dll */
+ err = FreeLibrary(ModuleHandle);
+ if(0 == err)
+ {
+ Fail("\nFailed to all FreeLibrary API!\n");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/loader/LoadLibraryW/test1/testinfo.dat b/src/pal/tests/palsuite/loader/LoadLibraryW/test1/testinfo.dat
new file mode 100644
index 0000000000..c5c4adc75a
--- /dev/null
+++ b/src/pal/tests/palsuite/loader/LoadLibraryW/test1/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Loader
+Function = LoadLibraryW
+Name = Positive test for LoadLibraryW API to load a dynamic library module
+TYPE = DEFAULT
+EXE1 = loadlibraryw
+Description
+=Test the LoadLibraryW to map module into calling process address space
diff --git a/src/pal/tests/palsuite/loader/LoadLibraryW/test2/CMakeLists.txt b/src/pal/tests/palsuite/loader/LoadLibraryW/test2/CMakeLists.txt
new file mode 100644
index 0000000000..5e8486d23b
--- /dev/null
+++ b/src/pal/tests/palsuite/loader/LoadLibraryW/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ loadlibraryw.c
+)
+
+add_executable(paltest_loadlibraryw_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_loadlibraryw_test2 coreclrpal)
+
+target_link_libraries(paltest_loadlibraryw_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/loader/LoadLibraryW/test2/loadlibraryw.c b/src/pal/tests/palsuite/loader/LoadLibraryW/test2/loadlibraryw.c
new file mode 100644
index 0000000000..e8aebf77e9
--- /dev/null
+++ b/src/pal/tests/palsuite/loader/LoadLibraryW/test2/loadlibraryw.c
@@ -0,0 +1,62 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: loadlibraryw.c
+**
+** Purpose: Negative test the LoadLibraryW API.
+** Call LoadLibraryW with a not exist module Name
+**
+**
+**============================================================*/
+#define UNICODE
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ HMODULE ModuleHandle;
+ int err;
+ WCHAR *pwModuleName;
+ const char *pModuleName = "Not-exist-module-name";
+
+ /* Initialize the PAL environment */
+ err = PAL_Initialize(argc, argv);
+ if(0 != err)
+ {
+ return FAIL;
+ }
+
+ /* convert a normal string to a wide one */
+ pwModuleName = convert((char *)pModuleName);
+
+
+ /*try to load a not exist module */
+ ModuleHandle = LoadLibraryW(pwModuleName);
+
+ /* free the memory */
+ free(pwModuleName);
+
+ if(NULL != ModuleHandle)
+ {
+ Trace("Failed to call LoadLibraryW with a not exist mudule name, "
+ "a NULL module handle is expected, but no NULL module handle "
+ "is returned, error code=%u\n", GetLastError());
+
+ /* decrement the reference count of the loaded module */
+ err = FreeLibrary(ModuleHandle);
+ if(0 == err)
+ {
+ Trace("\nFailed to all FreeLibrary API to decrement "
+ "the reference count of the loaded module, "
+ "error code = %u\n", GetLastError());
+
+ }
+
+ Fail("");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/loader/LoadLibraryW/test2/testinfo.dat b/src/pal/tests/palsuite/loader/LoadLibraryW/test2/testinfo.dat
new file mode 100644
index 0000000000..bc107f0069
--- /dev/null
+++ b/src/pal/tests/palsuite/loader/LoadLibraryW/test2/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Loader
+Function = LoadLibraryW
+Name = Negative test LoadLibraryW API to load a not exist module
+TYPE = DEFAULT
+EXE1 = loadlibraryw
+Description
+=Test the LoadLibraryW to load a not exist module
+
diff --git a/src/pal/tests/palsuite/loader/LoadLibraryW/test3/CMakeLists.txt b/src/pal/tests/palsuite/loader/LoadLibraryW/test3/CMakeLists.txt
new file mode 100644
index 0000000000..2c96fa23da
--- /dev/null
+++ b/src/pal/tests/palsuite/loader/LoadLibraryW/test3/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ loadlibraryw.c
+)
+
+add_executable(paltest_loadlibraryw_test3
+ ${SOURCES}
+)
+
+add_dependencies(paltest_loadlibraryw_test3 coreclrpal)
+
+target_link_libraries(paltest_loadlibraryw_test3
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/loader/LoadLibraryW/test3/loadlibraryw.c b/src/pal/tests/palsuite/loader/LoadLibraryW/test3/loadlibraryw.c
new file mode 100644
index 0000000000..c722edaf13
--- /dev/null
+++ b/src/pal/tests/palsuite/loader/LoadLibraryW/test3/loadlibraryw.c
@@ -0,0 +1,41 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: loadlibraryw.c
+**
+** Purpose: Negative test the loadlibraryw API.
+** Call loadlibraryw with NULL module name
+**
+**
+**============================================================*/
+#define UNICODE
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ HMODULE ModuleHandle;
+ int err;
+
+ /* Initialize the PAL environment */
+ err = PAL_Initialize(argc, argv);
+ if(0 != err)
+ {
+ return FAIL;
+ }
+
+ /* load a module with a NULL module name */
+ ModuleHandle = LoadLibraryW(NULL);
+ if(NULL != ModuleHandle)
+ {
+ Fail("\nFailed to call loadlibraryw API for a negative test, "
+ "call loadibraryw with NULL moudle name, a NULL module "
+ "handle is expected, but no NULL module handle is returned, "
+ "error code =%u\n", GetLastError());
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/loader/LoadLibraryW/test3/testinfo.dat b/src/pal/tests/palsuite/loader/LoadLibraryW/test3/testinfo.dat
new file mode 100644
index 0000000000..bd20aaf995
--- /dev/null
+++ b/src/pal/tests/palsuite/loader/LoadLibraryW/test3/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Loader
+Function = LoadLibraryW
+Name = Negative test loadlibraryw API with a NULL module name
+TYPE = DEFAULT
+EXE1 = loadlibraryw
+Description
+=Test the LoadLibraryW with a NULL module name
diff --git a/src/pal/tests/palsuite/loader/LoadLibraryW/test5/CMakeLists.txt b/src/pal/tests/palsuite/loader/LoadLibraryW/test5/CMakeLists.txt
new file mode 100644
index 0000000000..7b8931a961
--- /dev/null
+++ b/src/pal/tests/palsuite/loader/LoadLibraryW/test5/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ loadlibraryw.c
+)
+
+add_executable(paltest_loadlibraryw_test5
+ ${SOURCES}
+)
+
+add_dependencies(paltest_loadlibraryw_test5 coreclrpal)
+
+target_link_libraries(paltest_loadlibraryw_test5
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/loader/LoadLibraryW/test5/loadlibraryw.c b/src/pal/tests/palsuite/loader/LoadLibraryW/test5/loadlibraryw.c
new file mode 100644
index 0000000000..acaa200a06
--- /dev/null
+++ b/src/pal/tests/palsuite/loader/LoadLibraryW/test5/loadlibraryw.c
@@ -0,0 +1,71 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: loadlibraryw.c
+**
+** Purpose: Negative test the LoadLibraryW API.
+** Call LoadLibraryW by passing a module name
+** without extension but with a trailing dot.
+**
+**
+**============================================================*/
+#define UNICODE
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ HMODULE ModuleHandle;
+ int err;
+ WCHAR *lpModuleName;
+ char ModuleName[_MAX_FNAME];
+
+ /* Initialize the PAL environment */
+ err = PAL_Initialize(argc, argv);
+ if(0 != err)
+ {
+ return FAIL;
+ }
+
+ memset(ModuleName, 0, _MAX_FNAME);
+
+ /*Module name without extension but with a trailing dot*/
+#if WIN32
+ sprintf(ModuleName,"%s","rotor_pal.");
+#else
+ sprintf(ModuleName,"%s","librotor_pal.");
+#endif
+
+ /* convert a normal string to a wide one */
+ lpModuleName = convert(ModuleName);
+
+ /* load a module */
+ ModuleHandle = LoadLibraryW(lpModuleName);
+
+ /* free the memory */
+ free(lpModuleName);
+
+ if(NULL != ModuleHandle)
+ {
+ Trace("Failed to call LoadLibraryW API for a negative test "
+ "call LoadLibraryW with module name which does not have "
+ "extension except a trailing dot, a NULL module handle is"
+ "expected, but no NULL module handle is returned, "
+ "error code = %u\n", GetLastError());
+
+ /* decrement the reference count of the loaded dll */
+ err = FreeLibrary(ModuleHandle);
+ if(0 == err)
+ {
+ Trace("\nFailed to call FreeLibrary API, "
+ "error code = %u\n", GetLastError());
+ }
+
+ Fail("");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/loader/LoadLibraryW/test5/testinfo.dat b/src/pal/tests/palsuite/loader/LoadLibraryW/test5/testinfo.dat
new file mode 100644
index 0000000000..8275f41644
--- /dev/null
+++ b/src/pal/tests/palsuite/loader/LoadLibraryW/test5/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Loader
+Function = LoadLibraryw
+Name = Negative test for LoadLibraryW API by passing a module name without extension but with a trailing dot.
+TYPE = DEFAULT
+EXE1 = loadlibraryw
+Description
+=Test the LoadLibraryW by passing a module name without extension
+=but with a trailing dot.
+
diff --git a/src/pal/tests/palsuite/locale_info/CMakeLists.txt b/src/pal/tests/palsuite/locale_info/CMakeLists.txt
new file mode 100644
index 0000000000..52482daa41
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/CMakeLists.txt
@@ -0,0 +1,26 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+# TODO: make the following tests compile if they are needed
+# add_subdirectory(CompareStringA)
+# add_subdirectory(CompareStringW)
+# add_subdirectory(GetLocaleInfoW)
+# add_subdirectory(GetStringTypeExW)
+# add_subdirectory(GetSystemDefaultLangID)
+# add_subdirectory(GetThreadLocale)
+# add_subdirectory(GetTimeZoneInformation)
+# add_subdirectory(GetUserDefaultLangID)
+# add_subdirectory(GetUserDefaultLCID)
+# add_subdirectory(IsValidLocale)
+# add_subdirectory(SetThreadLocale)
+
+add_subdirectory(GetACP)
+add_subdirectory(GetCPInfo)
+add_subdirectory(IsDBCSLeadByte)
+add_subdirectory(IsDBCSLeadByteEx)
+add_subdirectory(IsValidCodePage)
+add_subdirectory(MultiByteToWideChar)
+add_subdirectory(WideCharToMultiByte)
+
+
+
+
diff --git a/src/pal/tests/palsuite/locale_info/CompareStringA/CMakeLists.txt b/src/pal/tests/palsuite/locale_info/CompareStringA/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/CompareStringA/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/locale_info/CompareStringA/test1/CMakeLists.txt b/src/pal/tests/palsuite/locale_info/CompareStringA/test1/CMakeLists.txt
new file mode 100644
index 0000000000..96ee18d857
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/CompareStringA/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_comparestringa_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_comparestringa_test1 coreclrpal)
+
+target_link_libraries(paltest_comparestringa_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/locale_info/CompareStringA/test1/test1.c b/src/pal/tests/palsuite/locale_info/CompareStringA/test1/test1.c
new file mode 100644
index 0000000000..98c147af48
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/CompareStringA/test1/test1.c
@@ -0,0 +1,99 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Tests that CompareStringA returns the correct value and can handle
+** invalid parameters.
+**
+**
+**==========================================================================*/
+
+#define CSTR_LESS_THAN 1
+#define CSTR_EQUAL 2
+#define CSTR_GREATER_THAN 3
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ char str1[] = {'f','o','o',0};
+ char str2[] = {'f','o','o','x',0};
+ char str3[] = {'f','O','o',0};
+ int flags = NORM_IGNORECASE | NORM_IGNOREWIDTH;
+ int ret;
+
+ if (0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ ret = CompareStringA(0x0409, flags, str1, -1, str2, -1);
+ if (ret != CSTR_LESS_THAN)
+ {
+ Fail("CompareStringA with \"%S\" (%d) and \"%S\" (%d) did not return "
+ "CSTR_LESS_THAN!\n", str1, -1, str2, -1);
+ }
+
+ ret = CompareStringA(0x0409, flags, str1, -1, str2, 3);
+ if (ret != CSTR_EQUAL)
+ {
+ Fail("CompareStringA with \"%S\" (%d) and \"%S\" (%d) did not return "
+ "CSTR_EQUAL!\n", str1, -1, str2, 3);
+ }
+
+ ret = CompareStringA(0x0409, flags, str2, -1, str1, -1);
+ if (ret != CSTR_GREATER_THAN)
+ {
+ Fail("CompareStringA with \"%S\" (%d) and \"%S\" (%d) did not return "
+ "CSTR_GREATER_THAN!\n", str2, -1, str1, -1);
+ }
+
+ ret = CompareStringA(0x0409, flags, str1, -1, str3, -1);
+ if (ret != CSTR_EQUAL)
+ {
+ Fail("CompareStringA with \"%S\" (%d) and \"%S\" (%d) did not return "
+ "CSTR_EQUAL!\n", str1, -1, str3, -1);
+ }
+
+ ret = CompareStringA(0x0409, flags, str3, -1, str1, -1);
+ if (ret != CSTR_EQUAL)
+ {
+ Fail("CompareStringA with \"%S\" (%d) and \"%S\" (%d) did not return "
+ "CSTR_EQUAL!\n", str3, -1, str1, -1);
+ }
+
+ ret = CompareStringA(0x0409, flags, str3, -1, str1, -1);
+ if (ret != CSTR_EQUAL)
+ {
+ Fail("CompareStringA with \"%S\" (%d) and \"%S\" (%d) did not return "
+ "CSTR_EQUAL!\n", str3, -1, str1, -1);
+ }
+
+ ret = CompareStringA(0x0409, flags, str1, 0, str3, -1);
+ if (ret != CSTR_LESS_THAN)
+ {
+ Fail("CompareStringA with \"%S\" (%d) and \"%S\" (%d) did not return "
+ "CSTR_GREATER_THAN!\n", str1, 0, str3, -1);
+ }
+
+
+ ret = CompareStringA(0x0409, flags, NULL, -1, str3, -1);
+ if (ret != 0)
+ {
+ Fail("CompareStringA should have returned 0, got %d!\n", ret);
+ }
+ if (GetLastError() != ERROR_INVALID_PARAMETER)
+ {
+ Fail("CompareStringA should have set the last error to "
+ "ERROR_INVALID_PARAMETER!\n");
+ }
+
+ PAL_Terminate();
+
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/locale_info/CompareStringA/test1/testinfo.dat b/src/pal/tests/palsuite/locale_info/CompareStringA/test1/testinfo.dat
new file mode 100644
index 0000000000..e934b13763
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/CompareStringA/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Locale Information
+Function = CompareStringA
+Name = Test #1 for CompareStringA
+TYPE = DEFAULT
+EXE1 = test1
+Description
+=Tests that CompareStringA returns the correct value and can handle
+=invalid parameters.
diff --git a/src/pal/tests/palsuite/locale_info/CompareStringW/CMakeLists.txt b/src/pal/tests/palsuite/locale_info/CompareStringW/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/CompareStringW/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/locale_info/CompareStringW/test1/CMakeLists.txt b/src/pal/tests/palsuite/locale_info/CompareStringW/test1/CMakeLists.txt
new file mode 100644
index 0000000000..8652977387
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/CompareStringW/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_comparestringw_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_comparestringw_test1 coreclrpal)
+
+target_link_libraries(paltest_comparestringw_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/locale_info/CompareStringW/test1/test1.c b/src/pal/tests/palsuite/locale_info/CompareStringW/test1/test1.c
new file mode 100644
index 0000000000..bdf2c3dcf3
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/CompareStringW/test1/test1.c
@@ -0,0 +1,99 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Tests that CompareStringW returns the correct value and can handle
+** invalid parameters.
+**
+**
+**==========================================================================*/
+
+#define CSTR_LESS_THAN 1
+#define CSTR_EQUAL 2
+#define CSTR_GREATER_THAN 3
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ WCHAR str1[] = {'f','o','o',0};
+ WCHAR str2[] = {'f','o','o','x',0};
+ WCHAR str3[] = {'f','O','o',0};
+ int flags = NORM_IGNORECASE | NORM_IGNOREWIDTH;
+ int ret;
+
+ if (0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ ret = CompareStringW(0x0409, flags, str1, -1, str2, -1);
+ if (ret != CSTR_LESS_THAN)
+ {
+ Fail("CompareStringW with \"%S\" (%d) and \"%S\" (%d) did not return "
+ "CSTR_LESS_THAN!\n", str1, -1, str2, -1);
+ }
+
+ ret = CompareStringW(0x0409, flags, str1, -1, str2, 3);
+ if (ret != CSTR_EQUAL)
+ {
+ Fail("CompareStringW with \"%S\" (%d) and \"%S\" (%d) did not return "
+ "CSTR_EQUAL!\n", str1, -1, str2, 3);
+ }
+
+ ret = CompareStringW(0x0409, flags, str2, -1, str1, -1);
+ if (ret != CSTR_GREATER_THAN)
+ {
+ Fail("CompareStringW with \"%S\" (%d) and \"%S\" (%d) did not return "
+ "CSTR_GREATER_THAN!\n", str2, -1, str1, -1);
+ }
+
+ ret = CompareStringW(0x0409, flags, str1, -1, str3, -1);
+ if (ret != CSTR_EQUAL)
+ {
+ Fail("CompareStringW with \"%S\" (%d) and \"%S\" (%d) did not return "
+ "CSTR_EQUAL!\n", str1, -1, str3, -1);
+ }
+
+ ret = CompareStringW(0x0409, flags, str3, -1, str1, -1);
+ if (ret != CSTR_EQUAL)
+ {
+ Fail("CompareStringW with \"%S\" (%d) and \"%S\" (%d) did not return "
+ "CSTR_EQUAL!\n", str3, -1, str1, -1);
+ }
+
+ ret = CompareStringW(0x0409, flags, str3, -1, str1, -1);
+ if (ret != CSTR_EQUAL)
+ {
+ Fail("CompareStringW with \"%S\" (%d) and \"%S\" (%d) did not return "
+ "CSTR_EQUAL!\n", str3, -1, str1, -1);
+ }
+
+ ret = CompareStringW(0x0409, flags, str1, 0, str3, -1);
+ if (ret != CSTR_LESS_THAN)
+ {
+ Fail("CompareStringW with \"%S\" (%d) and \"%S\" (%d) did not return "
+ "CSTR_GREATER_THAN!\n", str1, 0, str3, -1);
+ }
+
+
+ ret = CompareStringW(0x0409, flags, NULL, -1, str3, -1);
+ if (ret != 0)
+ {
+ Fail("CompareStringW should have returned 0, got %d!\n", ret);
+ }
+ if (GetLastError() != ERROR_INVALID_PARAMETER)
+ {
+ Fail("CompareStringW should have set the last error to "
+ "ERROR_INVALID_PARAMETER!\n");
+ }
+
+ PAL_Terminate();
+
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/locale_info/CompareStringW/test1/testinfo.dat b/src/pal/tests/palsuite/locale_info/CompareStringW/test1/testinfo.dat
new file mode 100644
index 0000000000..d41de3ee68
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/CompareStringW/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Locale Information
+Function = CompareStringW
+Name = Test #1 for CompareStringW
+TYPE = DEFAULT
+EXE1 = test1
+Description
+=Tests that CompareStringW returns the correct value and can handle
+=invalid parameters.
diff --git a/src/pal/tests/palsuite/locale_info/GetACP/CMakeLists.txt b/src/pal/tests/palsuite/locale_info/GetACP/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/GetACP/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/locale_info/GetACP/test1/CMakeLists.txt b/src/pal/tests/palsuite/locale_info/GetACP/test1/CMakeLists.txt
new file mode 100644
index 0000000000..c5513da2c1
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/GetACP/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_getacp_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getacp_test1 coreclrpal)
+
+target_link_libraries(paltest_getacp_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/locale_info/GetACP/test1/test1.c b/src/pal/tests/palsuite/locale_info/GetACP/test1/test1.c
new file mode 100644
index 0000000000..8ea078ee69
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/GetACP/test1/test1.c
@@ -0,0 +1,42 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Tests that GetACP returns the expected default code page.
+**
+**
+**==========================================================================*/
+
+
+#include <palsuite.h>
+
+/*
+ * NOTE: We only support code page 65001 (UTF-8).
+ */
+
+#define EXPECTED_CP 65001
+
+int __cdecl main(int argc, char *argv[])
+{
+ int ret;
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ ret = GetACP();
+ if (ret != EXPECTED_CP)
+ {
+ Fail("ERROR: got incorrect result for current ANSI code page!\n"
+ "Expected %d, got %d\n", EXPECTED_CP, ret);
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/locale_info/GetACP/test1/testinfo.dat b/src/pal/tests/palsuite/locale_info/GetACP/test1/testinfo.dat
new file mode 100644
index 0000000000..63a58f681b
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/GetACP/test1/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Locale Information
+Function = GetACP
+Name = Test #1 for GetACP
+TYPE = DEFAULT
+EXE1 = test1
+Description
+=Tests that GetACP returns code-page 1252.
diff --git a/src/pal/tests/palsuite/locale_info/GetCPInfo/CMakeLists.txt b/src/pal/tests/palsuite/locale_info/GetCPInfo/CMakeLists.txt
new file mode 100644
index 0000000000..1962ade358
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/GetCPInfo/CMakeLists.txt
@@ -0,0 +1,6 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+add_subdirectory(test3)
+
diff --git a/src/pal/tests/palsuite/locale_info/GetCPInfo/test1/CMakeLists.txt b/src/pal/tests/palsuite/locale_info/GetCPInfo/test1/CMakeLists.txt
new file mode 100644
index 0000000000..c209b121b2
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/GetCPInfo/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_getcpinfo_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getcpinfo_test1 coreclrpal)
+
+target_link_libraries(paltest_getcpinfo_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/locale_info/GetCPInfo/test1/test1.c b/src/pal/tests/palsuite/locale_info/GetCPInfo/test1/test1.c
new file mode 100644
index 0000000000..ed9bbf93fc
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/GetCPInfo/test1/test1.c
@@ -0,0 +1,54 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Tests that GetCPInfo works for CP_ACP and 0x4E4 (default codepage)
+** Also makes sure it correctly handles an invalid code page.
+**
+**
+**==========================================================================*/
+
+
+#include <palsuite.h>
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ CPINFO cpinfo;
+
+ if (0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ if (!GetCPInfo(CP_ACP, &cpinfo))
+ {
+ Fail("GetCPInfo() unable to get info for CP_ACP\n");
+ }
+
+ if (!GetCPInfo(65001, &cpinfo))
+ {
+ Fail("GetCPInfo() unable to get info for code page 65001 (utf8)\n");
+ }
+
+ if (GetCPInfo(-1, &cpinfo))
+ {
+ Fail("GetCPInfo() did not error on invalid code page!\n");
+ }
+
+ if (GetLastError() != ERROR_INVALID_PARAMETER)
+ {
+ Fail("GetCPInfo() failed to set the last error to"
+ " ERROR_INVALID_PARAMETER!\n");
+ }
+
+
+ PAL_Terminate();
+
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/locale_info/GetCPInfo/test1/testinfo.dat b/src/pal/tests/palsuite/locale_info/GetCPInfo/test1/testinfo.dat
new file mode 100644
index 0000000000..31be1d5536
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/GetCPInfo/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Locale Information
+Function = GetCPInfo
+Name = Test #1 for GetCPInfo
+TYPE = DEFAULT
+EXE1 = test1
+Description
+=Tests that GetCPInfo works for CP_ACP and 0x4E4 (default codepage)
+=Also makes sure it correctly handles an invalid code page.
diff --git a/src/pal/tests/palsuite/locale_info/GetCPInfo/test2/CMakeLists.txt b/src/pal/tests/palsuite/locale_info/GetCPInfo/test2/CMakeLists.txt
new file mode 100644
index 0000000000..6132e9b3fa
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/GetCPInfo/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test2.c
+)
+
+add_executable(paltest_getcpinfo_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getcpinfo_test2 coreclrpal)
+
+target_link_libraries(paltest_getcpinfo_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/locale_info/GetCPInfo/test2/test2.c b/src/pal/tests/palsuite/locale_info/GetCPInfo/test2/test2.c
new file mode 100644
index 0000000000..f52320f167
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/GetCPInfo/test2/test2.c
@@ -0,0 +1,60 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test2.c
+**
+** Purpose: Tests that GetCPInfo gives the correct information for codepage 0x4E4
+** (the default).
+**
+**
+**==========================================================================*/
+
+
+#include <palsuite.h>
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ CPINFO cpinfo;
+ int codepage;
+ unsigned int i;
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ /*
+ * codepage 1252 (0x4E4): Windows 3.1 Latin 1 (U.S., Western Europe)
+ */
+ codepage = 1252;
+
+ if (!GetCPInfo(codepage, &cpinfo))
+ {
+ Fail("GetCPInfo() failed on default ansi code page!\n");
+ }
+ if (cpinfo.MaxCharSize != 1)
+ {
+ Fail("GetCPInfo() returned incorrect MaxCharSize information!\n");
+ }
+ if (cpinfo.DefaultChar[0] != '?' || cpinfo.DefaultChar[1] != 0)
+ {
+ Fail("GetCPInfo() returned incorrect DefaultChar information");
+ }
+
+ for (i = 0; i<MAX_LEADBYTES; i++)
+ {
+ if (cpinfo.LeadByte[i] != 0)
+ {
+ Fail("GetCPInfo() returned incorrect LeadByte information");
+ }
+ }
+
+ PAL_Terminate();
+
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/locale_info/GetCPInfo/test2/testinfo.dat b/src/pal/tests/palsuite/locale_info/GetCPInfo/test2/testinfo.dat
new file mode 100644
index 0000000000..fee6849858
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/GetCPInfo/test2/testinfo.dat
@@ -0,0 +1,9 @@
+Version = 1.0
+Section = Locale Information
+Function = GetCPInfo
+Name = Test #2 for GetCPInfo
+TYPE = DEFAULT
+EXE1 = test2
+Description
+=Tests that GetCPInfo gives the correct information for codepage 0x4E4
+=(the default).
diff --git a/src/pal/tests/palsuite/locale_info/GetCPInfo/test3/CMakeLists.txt b/src/pal/tests/palsuite/locale_info/GetCPInfo/test3/CMakeLists.txt
new file mode 100644
index 0000000000..3e4a09b51d
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/GetCPInfo/test3/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test3.c
+)
+
+add_executable(paltest_getcpinfo_test3
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getcpinfo_test3 coreclrpal)
+
+target_link_libraries(paltest_getcpinfo_test3
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/locale_info/GetCPInfo/test3/test3.c b/src/pal/tests/palsuite/locale_info/GetCPInfo/test3/test3.c
new file mode 100644
index 0000000000..aa9df935b8
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/GetCPInfo/test3/test3.c
@@ -0,0 +1,41 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test3.c
+**
+** Purpose: Test that passes CP_ACP to GetCPInfo, verifying the results.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+
+/* Currently only one CodePage "CP_ACP" is supported by the PAL */
+
+int __cdecl main(int argc, char *argv[])
+{
+ CPINFO cpinfo;
+
+ /* Initialize the PAL.
+ */
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ /* Test GetCPInfo with CP_ACP.
+ */
+ if (!GetCPInfo(CP_ACP, &cpinfo))
+ {
+ Fail("GetCPInfo() unable to get info for code page %d!\n", CP_ACP);
+ }
+
+ /* Terminate the PAL.
+ */
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/locale_info/GetCPInfo/test3/testinfo.dat b/src/pal/tests/palsuite/locale_info/GetCPInfo/test3/testinfo.dat
new file mode 100644
index 0000000000..13f7a29262
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/GetCPInfo/test3/testinfo.dat
@@ -0,0 +1,8 @@
+Version = 1.0
+Section = Locale Information
+Function = GetCPInfo
+Name = Test #3 for GetCPInfo
+TYPE = DEFAULT
+EXE1 = test3
+Description
+=Tests that GetCPInfo passes for all valid code pages
diff --git a/src/pal/tests/palsuite/locale_info/GetLocaleInfoW/CMakeLists.txt b/src/pal/tests/palsuite/locale_info/GetLocaleInfoW/CMakeLists.txt
new file mode 100644
index 0000000000..ef14ea5352
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/GetLocaleInfoW/CMakeLists.txt
@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+
diff --git a/src/pal/tests/palsuite/locale_info/GetLocaleInfoW/test1/CMakeLists.txt b/src/pal/tests/palsuite/locale_info/GetLocaleInfoW/test1/CMakeLists.txt
new file mode 100644
index 0000000000..f373b98f7c
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/GetLocaleInfoW/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_getlocaleinfow_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getlocaleinfow_test1 coreclrpal)
+
+target_link_libraries(paltest_getlocaleinfow_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/locale_info/GetLocaleInfoW/test1/test1.c b/src/pal/tests/palsuite/locale_info/GetLocaleInfoW/test1/test1.c
new file mode 100644
index 0000000000..0994940a57
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/GetLocaleInfoW/test1/test1.c
@@ -0,0 +1,89 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Tests that GetLocaleInfoW gives the correction information for
+** LOCALE_NEUTRAL.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+
+
+int Types[] = { LOCALE_SDECIMAL, LOCALE_STHOUSAND, LOCALE_ILZERO,
+ LOCALE_SCURRENCY, LOCALE_SMONDECIMALSEP, LOCALE_SMONTHOUSANDSEP };
+
+char *TypeStrings[] = { "LOCALE_SDECIMAL", "LOCALE_STHOUSAND", "LOCALE_ILZERO",
+ "LOCALE_SCURRENCY", "LOCALE_SMONDECIMALSEP", "LOCALE_SMONTHOUSANDSEP" };
+
+#define NUM_TYPES (sizeof(Types) / sizeof(Types[0]))
+
+typedef WCHAR InfoStrings[NUM_TYPES][4];
+
+typedef struct
+{
+ LCID lcid;
+ InfoStrings Strings;
+} LocalInfoType;
+
+LocalInfoType Locales[] =
+{
+ {LOCALE_NEUTRAL,
+ {{'.',0}, {',',0}, {'1',0}, {'$',0}, {'.',0}, {',',0}}},
+};
+
+int NumLocales = sizeof(Locales) / sizeof(Locales[0]);
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ WCHAR buffer[256] = { 0 };
+ int ret;
+ int i,j;
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ for (i=0; i<NumLocales; i++)
+ {
+ for (j=0; j<NUM_TYPES; j++)
+ {
+ ret = GetLocaleInfoW(Locales[i].lcid, Types[j], buffer, 256);
+
+ if (ret == 0)
+ {
+ Fail("GetLocaleInfoW returned an unexpected error!\n");
+ }
+
+
+ if (wcscmp(buffer, Locales[i].Strings[j]) != 0)
+ {
+
+ Fail("GetLocaleInfoW gave incorrect result for %s, "
+ "locale %#x:\nExpected \"%S\", got \"%S\"!\n", TypeStrings[j],
+ Locales[i].lcid, Locales[i].Strings[j], buffer);
+
+ }
+
+ if (ret != wcslen(Locales[i].Strings[j]) + 1)
+ {
+ Fail("GetLocaleInfoW returned incorrect value for %s, "
+ "locale %#x:\nExpected %d, got %d!\n", TypeStrings[j],
+ Locales[i].lcid, wcslen(Locales[i].Strings[j])+1, ret);
+ }
+ }
+ }
+
+
+ PAL_Terminate();
+
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/locale_info/GetLocaleInfoW/test1/testinfo.dat b/src/pal/tests/palsuite/locale_info/GetLocaleInfoW/test1/testinfo.dat
new file mode 100644
index 0000000000..00d974a71c
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/GetLocaleInfoW/test1/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Locale Information
+Function = GetLocaleInfoW
+Name = Test #1 for GetLocaleInfoW
+TYPE = DEFAULT
+EXE1 = test1
+Description
+=Tests that GetLocaleInfoW gives the correction information for LOCALE_NEUTRAL
diff --git a/src/pal/tests/palsuite/locale_info/GetLocaleInfoW/test2/CMakeLists.txt b/src/pal/tests/palsuite/locale_info/GetLocaleInfoW/test2/CMakeLists.txt
new file mode 100644
index 0000000000..dd5b82ef61
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/GetLocaleInfoW/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test2.c
+)
+
+add_executable(paltest_getlocaleinfow_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getlocaleinfow_test2 coreclrpal)
+
+target_link_libraries(paltest_getlocaleinfow_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/locale_info/GetLocaleInfoW/test2/test2.c b/src/pal/tests/palsuite/locale_info/GetLocaleInfoW/test2/test2.c
new file mode 100644
index 0000000000..f00fa79c59
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/GetLocaleInfoW/test2/test2.c
@@ -0,0 +1,51 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test2.c
+**
+** Purpose: Tests that GetLocaleInfoW will correctly return the amount of
+** buffer space required. Also tests that it correctly handles a
+** buffer of insufficient space.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ WCHAR buffer[256] = { 0 };
+ int ret;
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ ret = GetLocaleInfoW(LOCALE_NEUTRAL, LOCALE_SDECIMAL, buffer, 0);
+ if (ret != 2)
+ {
+ Fail("GetLocaleInfoW gave incorrect desired length for buffer.\n"
+ "Expected 2, got %d.\n", ret);
+ }
+
+ ret = GetLocaleInfoW(LOCALE_NEUTRAL, LOCALE_SDECIMAL, buffer, 1);
+ if (ret != 0)
+ {
+ Fail("GetLocaleInfoW expected to return 0, returned %d", ret);
+ }
+
+ if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
+ {
+ Fail("GetLocaleInfoW failed to set last error to "
+ "ERROR_INSUFFICIENT_BUFFER!\n");
+ }
+
+ PAL_Terminate();
+
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/locale_info/GetLocaleInfoW/test2/testinfo.dat b/src/pal/tests/palsuite/locale_info/GetLocaleInfoW/test2/testinfo.dat
new file mode 100644
index 0000000000..b9fc4886ee
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/GetLocaleInfoW/test2/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Locale Information
+Function = GetLocaleInfoW
+Name = Test #2 for GetLocaleInfoW
+TYPE = DEFAULT
+EXE1 = test2
+Description
+=Tests that GetLocaleInfoW will correctly return the amount of
+=buffer space required. Also tests that it correctly handles a
+=buffer of insufficient space.
diff --git a/src/pal/tests/palsuite/locale_info/GetStringTypeExW/CMakeLists.txt b/src/pal/tests/palsuite/locale_info/GetStringTypeExW/CMakeLists.txt
new file mode 100644
index 0000000000..ef14ea5352
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/GetStringTypeExW/CMakeLists.txt
@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+
diff --git a/src/pal/tests/palsuite/locale_info/GetStringTypeExW/test1/CMakeLists.txt b/src/pal/tests/palsuite/locale_info/GetStringTypeExW/test1/CMakeLists.txt
new file mode 100644
index 0000000000..5bb7b8c8b5
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/GetStringTypeExW/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_getstringtypeexw_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getstringtypeexw_test1 coreclrpal)
+
+target_link_libraries(paltest_getstringtypeexw_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/locale_info/GetStringTypeExW/test1/test1.c b/src/pal/tests/palsuite/locale_info/GetStringTypeExW/test1/test1.c
new file mode 100644
index 0000000000..e15c3d66cd
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/GetStringTypeExW/test1/test1.c
@@ -0,0 +1,54 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Tests GetStringTypeExW with values that will ensure all possible
+** flags get set once.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ WCHAR wideStr[] = {'9',' '};
+ WORD values1[] = { C1_DIGIT, C1_SPACE };
+ int len = 2;
+ WORD Info[256];
+ BOOL ret;
+ int i;
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ for (i=0; i<len; i++)
+ {
+ ret = GetStringTypeExW(LOCALE_USER_DEFAULT, CT_CTYPE1, &wideStr[i], 1, &Info[i]);
+ if (!ret)
+ {
+ Fail("GetStringTypeExW failed!\n");
+ }
+
+ if ((Info[i] & values1[i])!= values1[i])
+ {
+
+ Fail("GetStringTypeExW returned wrong type info for %c (%d)\n"
+ "Expected %#x, got %#x\n", wideStr[i], wideStr[i],
+ values1[i], Info[i]);
+
+ }
+ }
+
+ PAL_Terminate();
+
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/locale_info/GetStringTypeExW/test1/testinfo.dat b/src/pal/tests/palsuite/locale_info/GetStringTypeExW/test1/testinfo.dat
new file mode 100644
index 0000000000..b0fbea4c05
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/GetStringTypeExW/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Locale Information
+Function = GetStringTypeExW
+Name = Test #1 for GetStringTypeExW
+TYPE = DEFAULT
+EXE1 = test1
+Description
+=Tests GetStringTypeExW with values that will ensure all possible
+=flags get set once.
diff --git a/src/pal/tests/palsuite/locale_info/GetStringTypeExW/test2/CMakeLists.txt b/src/pal/tests/palsuite/locale_info/GetStringTypeExW/test2/CMakeLists.txt
new file mode 100644
index 0000000000..4a8fab243e
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/GetStringTypeExW/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test2.c
+)
+
+add_executable(paltest_getstringtypeexw_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getstringtypeexw_test2 coreclrpal)
+
+target_link_libraries(paltest_getstringtypeexw_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/locale_info/GetStringTypeExW/test2/test2.c b/src/pal/tests/palsuite/locale_info/GetStringTypeExW/test2/test2.c
new file mode 100644
index 0000000000..6dca7e8ac5
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/GetStringTypeExW/test2/test2.c
@@ -0,0 +1,78 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test2.c
+**
+** Purpose: Tests GetStringTypeExW with values from every possible unicode
+** category.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+
+
+/*
+ * A random selection of unicode characters, each representing a distinct
+ * unicode category
+ */
+WCHAR TestStr[] =
+{
+ 0x05D0, /* 4, HEBREW LETTER ALEF */
+ 0x0488, /* 7, COMBINING CYRILLIC HUNDRED THOUSANDS SIGN */
+ 0x0030, /* 8, DIGIT ZERO */
+ 0x0020, /* 22, SPACE */
+};
+
+#define TEST_LEN (sizeof(TestStr) / sizeof(WCHAR))
+
+WORD TestFlags[TEST_LEN] =
+{
+ C1_ALPHA,
+ 0,
+ C1_DIGIT,
+ C1_BLANK|C1_SPACE
+};
+
+int __cdecl main(int argc, char *argv[])
+{
+ WORD Info;
+ BOOL ret;
+ int i;
+
+ /* check only the bits listed in rotor_pal.doc */
+ const WORD PAL_VALID_C1_BITS = C1_DIGIT | C1_SPACE;
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ for (i=0; i <TEST_LEN; i++)
+ {
+ ret = GetStringTypeExW(LOCALE_USER_DEFAULT, CT_CTYPE1, &TestStr[i], 1, &Info);
+
+ if (!ret)
+ {
+ Fail("GetStringTypeExW failed!\n");
+ }
+
+ if ((Info & PAL_VALID_C1_BITS) != (TestFlags[i] & PAL_VALID_C1_BITS))
+ {
+
+ Fail("GetStringTypeExW (test #%i) returned wrong type info for %c (%d)\n"
+ "Expected %#x, got %#x\n", i, TestStr[i], TestStr[i],
+ TestFlags[i], Info);
+
+ }
+ }
+
+ PAL_Terminate();
+
+ return PASS;
+}
+
+
diff --git a/src/pal/tests/palsuite/locale_info/GetStringTypeExW/test2/testinfo.dat b/src/pal/tests/palsuite/locale_info/GetStringTypeExW/test2/testinfo.dat
new file mode 100644
index 0000000000..361d29b450
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/GetStringTypeExW/test2/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Locale Information
+Function = GetStringTypeExW
+Name = Test #2 for GetStringTypeExW
+TYPE = DEFAULT
+EXE1 = test2
+Description
+=Tests GetStringTypeExW with values from every possible unicode category.
diff --git a/src/pal/tests/palsuite/locale_info/GetSystemDefaultLangID/CMakeLists.txt b/src/pal/tests/palsuite/locale_info/GetSystemDefaultLangID/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/GetSystemDefaultLangID/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/locale_info/GetSystemDefaultLangID/test1/CMakeLists.txt b/src/pal/tests/palsuite/locale_info/GetSystemDefaultLangID/test1/CMakeLists.txt
new file mode 100644
index 0000000000..ef87b5f87f
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/GetSystemDefaultLangID/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_getsystemdefaultlangid_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getsystemdefaultlangid_test1 coreclrpal)
+
+target_link_libraries(paltest_getsystemdefaultlangid_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/locale_info/GetSystemDefaultLangID/test1/test1.c b/src/pal/tests/palsuite/locale_info/GetSystemDefaultLangID/test1/test1.c
new file mode 100644
index 0000000000..1bc5120815
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/GetSystemDefaultLangID/test1/test1.c
@@ -0,0 +1,59 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Checks that GetSystemDefaultLangID can be used to make a valid
+** locale, and that it is consistent with LOCALE_USER_DEFAULT.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ LCID lcid;
+ LANGID LangID;
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ LangID = GetSystemDefaultLangID();
+ if (LangID == 0)
+ {
+ Fail("GetSystemDefaultLangID failed!\n");
+ }
+
+ /* Try using the langid (with default sort) as a locale */
+ if (!SetThreadLocale(MAKELCID(LangID, SORT_DEFAULT)))
+ {
+ Fail("Unable to use GetSystemDefaultLangID as a locale!\n");
+ }
+ lcid = GetThreadLocale();
+ if (!IsValidLocale(lcid, LCID_INSTALLED))
+ {
+ Fail("Unable to use GetSystemDefaultLangID as a locale!\n");
+ }
+
+ /* Make sure results consistent with using LOCALE_USER_DEFAULT */
+ if (!SetThreadLocale(LOCALE_USER_DEFAULT))
+ {
+ Fail("Unexpected error testing GetSystemDefaultLangID!\n");
+ }
+ if (GetThreadLocale() != lcid)
+ {
+ Fail("Results from GetSystemDefaultLangID inconsistent with "
+ "LOCALE_USER_DEFAULT!\n");
+ }
+
+ PAL_Terminate();
+
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/locale_info/GetSystemDefaultLangID/test1/testinfo.dat b/src/pal/tests/palsuite/locale_info/GetSystemDefaultLangID/test1/testinfo.dat
new file mode 100644
index 0000000000..e37ce45a44
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/GetSystemDefaultLangID/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Locale Information
+Function = GetSystemDefaultLangID
+Name = Test #1 for GetSystemDefaultLangID
+TYPE = DEFAULT
+EXE1 = test1
+Description
+=Checks that GetSystemDefaultLangID can be used to make a valid
+=locale, and that it is consistent with LOCALE_USER_DEFAULT.
diff --git a/src/pal/tests/palsuite/locale_info/GetThreadLocale/CMakeLists.txt b/src/pal/tests/palsuite/locale_info/GetThreadLocale/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/GetThreadLocale/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/locale_info/GetThreadLocale/test1/CMakeLists.txt b/src/pal/tests/palsuite/locale_info/GetThreadLocale/test1/CMakeLists.txt
new file mode 100644
index 0000000000..8cec9d8306
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/GetThreadLocale/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_getthreadlocale_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getthreadlocale_test1 coreclrpal)
+
+target_link_libraries(paltest_getthreadlocale_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/locale_info/GetThreadLocale/test1/test1.c b/src/pal/tests/palsuite/locale_info/GetThreadLocale/test1/test1.c
new file mode 100644
index 0000000000..8eb7252e37
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/GetThreadLocale/test1/test1.c
@@ -0,0 +1,36 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Tests that GetThreadLocale returns a valid locale.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ LCID lcid;
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ lcid = GetThreadLocale();
+
+ if (!IsValidLocale(lcid, LCID_INSTALLED))
+ {
+ Fail("GetThreadLocale returned a locale that is not installed!\n");
+ }
+
+ PAL_Terminate();
+
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/locale_info/GetThreadLocale/test1/testinfo.dat b/src/pal/tests/palsuite/locale_info/GetThreadLocale/test1/testinfo.dat
new file mode 100644
index 0000000000..a58782a38c
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/GetThreadLocale/test1/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Locale Information
+Function = GetThreadLocale
+Name = Test #1 for GetThreadLocale
+TYPE = DEFAULT
+EXE1 = test1
+Description
+=Tests that GetThreadLocale returns a valid locale
diff --git a/src/pal/tests/palsuite/locale_info/GetTimeZoneInformation/CMakeLists.txt b/src/pal/tests/palsuite/locale_info/GetTimeZoneInformation/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/GetTimeZoneInformation/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/locale_info/GetTimeZoneInformation/test1/CMakeLists.txt b/src/pal/tests/palsuite/locale_info/GetTimeZoneInformation/test1/CMakeLists.txt
new file mode 100644
index 0000000000..281f3bf9c3
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/GetTimeZoneInformation/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_gettimezoneinformation_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_gettimezoneinformation_test1 coreclrpal)
+
+target_link_libraries(paltest_gettimezoneinformation_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/locale_info/GetTimeZoneInformation/test1/test1.c b/src/pal/tests/palsuite/locale_info/GetTimeZoneInformation/test1/test1.c
new file mode 100644
index 0000000000..bb83ade231
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/GetTimeZoneInformation/test1/test1.c
@@ -0,0 +1,73 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Tests that GetTimeZoneInformation gives reasonable values.
+**
+**
+**==========================================================================*/
+
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ TIME_ZONE_INFORMATION tzi;
+ DWORD ret;
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ ret = GetTimeZoneInformation(&tzi);
+ if (ret == TIME_ZONE_ID_UNKNOWN)
+ {
+ /* Occurs in time zones that do not use daylight savings time. */
+ if (tzi.StandardBias != 0)
+ {
+ Fail("GetTimeZoneInformation() gave invalid data!\n"
+ "Returned TIME_ZONE_ID_UNKNOWN but StandardBias != 0!\n");
+ }
+ if (tzi.DaylightBias != 0)
+ {
+ Fail("GetTimeZoneInformation() gave invalid data!\n"
+ "Returned TIME_ZONE_ID_UNKNOWN but DaylightBias != 0!\n");
+ }
+ }
+ else if (ret == TIME_ZONE_ID_STANDARD)
+ {
+ if (tzi.StandardBias != 0)
+ {
+ Fail("GetTimeZoneInformation() gave invalid data!\n"
+ "StandardBias is %d, should be 0!\n", tzi.StandardBias);
+ }
+ }
+ else if (ret == TIME_ZONE_ID_DAYLIGHT)
+ {
+ if (tzi.DaylightBias != -60 && tzi.DaylightBias != 0)
+ {
+ Fail("GetTimeZoneInformation() gave invalid data!\n"
+ "DaylightBias is %d, should be 0 or -60!\n", tzi.DaylightBias);
+ }
+ }
+ else
+ {
+ Fail("GetTimeZoneInformation() returned an invalid value!\n");
+ }
+
+ if (tzi.Bias % 30 != 0)
+ {
+ Fail("GetTimeZoneInformation() gave an invalid bias of %d!\n",
+ tzi.Bias);
+ }
+
+ PAL_Terminate();
+
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/locale_info/GetTimeZoneInformation/test1/testinfo.dat b/src/pal/tests/palsuite/locale_info/GetTimeZoneInformation/test1/testinfo.dat
new file mode 100644
index 0000000000..382b8d5351
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/GetTimeZoneInformation/test1/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Locale Information
+Function = GetTimeZoneInformation
+Name = Test #1 for GetTimeZoneInformation
+TYPE = DEFAULT
+EXE1 = test1
+Description
+=Tests that GetTimeZoneInformation gives reasonable values.
diff --git a/src/pal/tests/palsuite/locale_info/GetUserDefaultLCID/CMakeLists.txt b/src/pal/tests/palsuite/locale_info/GetUserDefaultLCID/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/GetUserDefaultLCID/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/locale_info/GetUserDefaultLCID/test1/CMakeLists.txt b/src/pal/tests/palsuite/locale_info/GetUserDefaultLCID/test1/CMakeLists.txt
new file mode 100644
index 0000000000..e039d46ccd
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/GetUserDefaultLCID/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_getuserdefaultlcid_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getuserdefaultlcid_test1 coreclrpal)
+
+target_link_libraries(paltest_getuserdefaultlcid_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/locale_info/GetUserDefaultLCID/test1/test1.c b/src/pal/tests/palsuite/locale_info/GetUserDefaultLCID/test1/test1.c
new file mode 100644
index 0000000000..4a336f9bb7
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/GetUserDefaultLCID/test1/test1.c
@@ -0,0 +1,52 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Tests that GetUserDefaultLCID returns a valid locale that is
+** consistent with LOCALE_USER_DEFAULT.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ LCID lcid;
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ lcid = GetUserDefaultLCID();
+ if (lcid == 0)
+ {
+ Fail("GetUserDefaultLCID failed!\n");
+ }
+
+ if (!IsValidLocale(lcid, LCID_INSTALLED))
+ {
+ Fail("GetUserDefaultLCID gave an invalid locale!\n");
+ }
+
+ /* Make sure results consistent with using LOCALE_USER_DEFAULT */
+ if (!SetThreadLocale(LOCALE_USER_DEFAULT))
+ {
+ Fail("Unexpected error testing GetUserDefaultLCID!\n");
+ }
+ if (GetThreadLocale() != lcid)
+ {
+ Fail("Results from GetUserDefaultLCID inconsistent with "
+ "LOCALE_USER_DEFAULT!\n");
+ }
+
+ PAL_Terminate();
+
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/locale_info/GetUserDefaultLCID/test1/testinfo.dat b/src/pal/tests/palsuite/locale_info/GetUserDefaultLCID/test1/testinfo.dat
new file mode 100644
index 0000000000..73565b03c5
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/GetUserDefaultLCID/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Locale Information
+Function = GetUserDefaultLCID
+Name = Test #1 for GetUserDefaultLCID
+TYPE = DEFAULT
+EXE1 = test1
+Description
+=Tests that GetUserDefaultLCID returns a valid locale that is
+=consistent with LOCALE_USER_DEFAULT.
diff --git a/src/pal/tests/palsuite/locale_info/GetUserDefaultLangID/CMakeLists.txt b/src/pal/tests/palsuite/locale_info/GetUserDefaultLangID/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/GetUserDefaultLangID/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/locale_info/GetUserDefaultLangID/test1/CMakeLists.txt b/src/pal/tests/palsuite/locale_info/GetUserDefaultLangID/test1/CMakeLists.txt
new file mode 100644
index 0000000000..71fa0464bb
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/GetUserDefaultLangID/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_getuserdefaultlangid_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getuserdefaultlangid_test1 coreclrpal)
+
+target_link_libraries(paltest_getuserdefaultlangid_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/locale_info/GetUserDefaultLangID/test1/test1.c b/src/pal/tests/palsuite/locale_info/GetUserDefaultLangID/test1/test1.c
new file mode 100644
index 0000000000..51c5678086
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/GetUserDefaultLangID/test1/test1.c
@@ -0,0 +1,60 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Checks that GetUserDefaultLangID can be used to make a valid
+** locale, and that it is consistent with LOCALE_USER_DEFAULT.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ LCID lcid;
+ LANGID LangID;
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ LangID = GetUserDefaultLangID();
+ if (LangID == 0)
+ {
+ Fail("GetUserDefaultLangID failed!\n");
+ }
+
+ /* Try using the langid (with default sort) as a locale */
+ if (!SetThreadLocale(MAKELCID(LangID, SORT_DEFAULT)))
+ {
+ Fail("Unable to use GetUserDefaultLangID as a locale!\n");
+ }
+ lcid = GetThreadLocale();
+ if (!IsValidLocale(lcid, LCID_INSTALLED))
+ {
+ Fail("Unable to use GetUserDefaultLangID as a locale!\n");
+ }
+
+ /* Make sure results consistent with using LOCALE_USER_DEFAULT */
+ if (!SetThreadLocale(LOCALE_USER_DEFAULT))
+ {
+ Fail("Unexpected error testing GetUserDefaultLangID!\n");
+ }
+ if (GetThreadLocale() != lcid)
+ {
+ Fail("Results from GetUserDefaultLangID inconsistent with "
+ "LOCALE_USER_DEFAULT!\n");
+ }
+
+ PAL_Terminate();
+
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/locale_info/GetUserDefaultLangID/test1/testinfo.dat b/src/pal/tests/palsuite/locale_info/GetUserDefaultLangID/test1/testinfo.dat
new file mode 100644
index 0000000000..a46125757e
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/GetUserDefaultLangID/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Locale Information
+Function = GetUserDefaultLangID
+Name = Test #1 for GetUserDefaultLangID
+TYPE = DEFAULT
+EXE1 = test1
+Description
+=Checks that GetUserDefaultLangID can be used to make a valid
+=locale, and that it is consistent with LOCALE_USER_DEFAULT.
diff --git a/src/pal/tests/palsuite/locale_info/IsDBCSLeadByte/CMakeLists.txt b/src/pal/tests/palsuite/locale_info/IsDBCSLeadByte/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/IsDBCSLeadByte/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/locale_info/IsDBCSLeadByte/test1/CMakeLists.txt b/src/pal/tests/palsuite/locale_info/IsDBCSLeadByte/test1/CMakeLists.txt
new file mode 100644
index 0000000000..ad5ad7508d
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/IsDBCSLeadByte/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_isdbcsleadbyte_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_isdbcsleadbyte_test1 coreclrpal)
+
+target_link_libraries(paltest_isdbcsleadbyte_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/locale_info/IsDBCSLeadByte/test1/test1.c b/src/pal/tests/palsuite/locale_info/IsDBCSLeadByte/test1/test1.c
new file mode 100644
index 0000000000..ad326be084
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/IsDBCSLeadByte/test1/test1.c
@@ -0,0 +1,64 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Tests that IsDBCSLeadByte does not find any lead-bytes in the
+** current ansi code page
+**
+**
+** TODO: Test for positive, i.e., if it is potentially isdbcsleadbyte
+**==========================================================================*/
+
+
+#include <palsuite.h>
+
+void DoTest()
+{
+ int value;
+ int ret;
+ int i;
+
+
+ for (i=0; i<256; i++)
+ {
+ value = IsDBCSLeadByte(i);
+
+ ret = GetLastError();
+ if (ret == ERROR_INVALID_PARAMETER)
+ {
+ Fail("IsDBCSLeadByte unexpectedly errored with ERROR_INVALID_PARAMETER for %d!\n", i);
+ }
+ else if (ret != 0)
+ {
+ Fail("IsDBCSLeadByte had an unexpected error [%d] for %d!\n", ret, i);
+ }
+ else if (value)
+ {
+ Fail("IsDBCSLeadByte incorrectly found a lead byte in value [%d] for"
+ " %d\n", value, i);
+ }
+
+ }
+}
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ if (0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ DoTest();
+
+ PAL_Terminate();
+
+// setlocale( "japan", );
+
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/locale_info/IsDBCSLeadByte/test1/testinfo.dat b/src/pal/tests/palsuite/locale_info/IsDBCSLeadByte/test1/testinfo.dat
new file mode 100644
index 0000000000..43cd2aebb6
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/IsDBCSLeadByte/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Locale Information
+Function = IsDBCSLeadByte
+Name = Test #1 for IsDBCSLeadByte
+TYPE = DEFAULT
+EXE1 = test1
+Description
+=Tests that IsDBCSLeadByte does not find any lead-bytes in the
+=current ansi code page
diff --git a/src/pal/tests/palsuite/locale_info/IsDBCSLeadByteEx/CMakeLists.txt b/src/pal/tests/palsuite/locale_info/IsDBCSLeadByteEx/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/IsDBCSLeadByteEx/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/locale_info/IsDBCSLeadByteEx/test1/CMakeLists.txt b/src/pal/tests/palsuite/locale_info/IsDBCSLeadByteEx/test1/CMakeLists.txt
new file mode 100644
index 0000000000..9d53ee9b3b
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/IsDBCSLeadByteEx/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_isdbcsleadbyteex_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_isdbcsleadbyteex_test1 coreclrpal)
+
+target_link_libraries(paltest_isdbcsleadbyteex_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/locale_info/IsDBCSLeadByteEx/test1/test1.c b/src/pal/tests/palsuite/locale_info/IsDBCSLeadByteEx/test1/test1.c
new file mode 100644
index 0000000000..9466f4817f
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/IsDBCSLeadByteEx/test1/test1.c
@@ -0,0 +1,72 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Tests that IsDBCSLeadByteEx does not find any lead-bytes in the
+** current ansi code page or the default code page. Also tests that
+** it correctly handles an invalid codepage.
+**
+**
+**==========================================================================*/
+
+
+#include <palsuite.h>
+
+void DoTest(int codepage)
+{
+ int value;
+ int ret;
+ int i;
+
+
+ for (i=0; i<256; i++)
+ {
+ value = IsDBCSLeadByteEx(codepage, i);
+
+ ret = GetLastError();
+ if (ret == ERROR_INVALID_PARAMETER)
+ {
+ Fail("IsDBCSLeadByteEx unexpectedly errored with ERROR_INVALID_PARAMETER!\n");
+ }
+ else if (ret != 0)
+ {
+ Fail("IsDBCSLeadByteEx had an unexpected error!\n");
+ }
+ else if (value)
+ {
+ Fail("IsDBCSLeadByteEx incorrectly found a lead byte in code "
+ "page %d\n", codepage);
+ }
+
+ }
+}
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ if (0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ if (IsDBCSLeadByteEx(-1, 0))
+ {
+ Fail("IsDBCSLeadByteEx did not error on an invalid code page!\n");
+ }
+
+ /* Clear the last error. */
+ SetLastError(0);
+
+
+ DoTest(0);
+ DoTest(CP_ACP);
+
+ PAL_Terminate();
+
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/locale_info/IsDBCSLeadByteEx/test1/testinfo.dat b/src/pal/tests/palsuite/locale_info/IsDBCSLeadByteEx/test1/testinfo.dat
new file mode 100644
index 0000000000..b85e387272
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/IsDBCSLeadByteEx/test1/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Locale Information
+Function = IsDBCSLeadByteEx
+Name = Test #1 for IsDBCSLeadByteEx
+TYPE = DEFAULT
+EXE1 = test1
+Description
+=Tests that IsDBCSLeadByteEx does not find any lead-bytes in the
+=current ansi code page or the default code page. Also tests that
+=it correctly handles an invalid codepage.
diff --git a/src/pal/tests/palsuite/locale_info/IsValidCodePage/CMakeLists.txt b/src/pal/tests/palsuite/locale_info/IsValidCodePage/CMakeLists.txt
new file mode 100644
index 0000000000..ef14ea5352
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/IsValidCodePage/CMakeLists.txt
@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+
diff --git a/src/pal/tests/palsuite/locale_info/IsValidCodePage/test1/CMakeLists.txt b/src/pal/tests/palsuite/locale_info/IsValidCodePage/test1/CMakeLists.txt
new file mode 100644
index 0000000000..d87e8c0d6b
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/IsValidCodePage/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_isvalidcodepage_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_isvalidcodepage_test1 coreclrpal)
+
+target_link_libraries(paltest_isvalidcodepage_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/locale_info/IsValidCodePage/test1/test1.c b/src/pal/tests/palsuite/locale_info/IsValidCodePage/test1/test1.c
new file mode 100644
index 0000000000..deb6a7ae72
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/IsValidCodePage/test1/test1.c
@@ -0,0 +1,50 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Tests IsValidCodePage with a collection of valid and invalid
+** code pages.
+**
+**
+**==========================================================================*/
+
+
+#include <palsuite.h>
+
+
+UINT InvalidCodePages[] =
+{
+ 0, 0x1, 0x2, 0x3, 0xfff
+};
+
+int NumInvalidPages = sizeof(InvalidCodePages) / sizeof(InvalidCodePages[0]);
+
+int __cdecl main(int argc, char *argv[])
+{
+ int i;
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+
+ for (i=0; i<NumInvalidPages; i++)
+ {
+ if (IsValidCodePage(InvalidCodePages[i]))
+ {
+ Fail("IsValidCodePage() found code page %#x valid!\n",
+ InvalidCodePages[i]);
+ }
+ }
+
+ PAL_Terminate();
+
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/locale_info/IsValidCodePage/test1/testinfo.dat b/src/pal/tests/palsuite/locale_info/IsValidCodePage/test1/testinfo.dat
new file mode 100644
index 0000000000..f3b0fb8cb3
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/IsValidCodePage/test1/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Locale Information
+Function = IsValidCodePage
+Name = Test #1 for IsValidCodePage
+TYPE = DEFAULT
+EXE1 = test1
+Description
+=Tests IsValidCodePage with a collection of valid and invalid code pages.
diff --git a/src/pal/tests/palsuite/locale_info/IsValidCodePage/test2/CMakeLists.txt b/src/pal/tests/palsuite/locale_info/IsValidCodePage/test2/CMakeLists.txt
new file mode 100644
index 0000000000..adcae86ff9
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/IsValidCodePage/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test2.c
+)
+
+add_executable(paltest_isvalidcodepage_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_isvalidcodepage_test2 coreclrpal)
+
+target_link_libraries(paltest_isvalidcodepage_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/locale_info/IsValidCodePage/test2/test2.c b/src/pal/tests/palsuite/locale_info/IsValidCodePage/test2/test2.c
new file mode 100644
index 0000000000..d9362cfd96
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/IsValidCodePage/test2/test2.c
@@ -0,0 +1,51 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test2.c
+**
+** Purpose: Tests IsValidCodePage with all the code pages valid on W2K.
+**
+**
+**==========================================================================*/
+
+
+
+#include <palsuite.h>
+
+UINT ValidCodePages[] =
+{
+ 0x25, 0x1b5, 0x1f4, 0x352, 0x35c, 0x35d, 0x35f, 0x361,
+ 0x36a, 0x3a4, 0x3a8, 0x3b5, 0x3b6, 0x4e2, 0x4e3, 0x4e4, 0x4e5, 0x4e6,
+ 0x4e7, 0x4e8, 0x4e9, 0x4ea, 0x2710, 0x275f, 0x4e9f, 0x4f25, 0x5182, 0x6faf,
+ 0x6fb0, 0x6fbd, 0xfde8, 0xfde9
+};
+
+
+int NumValidPages = sizeof(ValidCodePages) / sizeof(ValidCodePages[0]);
+int __cdecl main(int argc, char *argv[])
+{
+ int i;
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ for (i=0; i<NumValidPages; i++)
+ {
+ if (!IsValidCodePage(ValidCodePages[i]))
+ {
+ Fail("IsValidCodePage() found code page %#x invalid!\n",
+ ValidCodePages[i]);
+ }
+ }
+
+
+ PAL_Terminate();
+
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/locale_info/IsValidCodePage/test2/testinfo.dat b/src/pal/tests/palsuite/locale_info/IsValidCodePage/test2/testinfo.dat
new file mode 100644
index 0000000000..f4507b411e
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/IsValidCodePage/test2/testinfo.dat
@@ -0,0 +1,8 @@
+Version = 1.0
+Section = Locale Information
+Function = IsValidCodePage
+Name = Test #2 for IsValidCodePage
+TYPE = DEFAULT
+EXE1 = test2
+Description
+=Tests IsValidCodePage with all the code pages valid on W2K.
diff --git a/src/pal/tests/palsuite/locale_info/IsValidLocale/CMakeLists.txt b/src/pal/tests/palsuite/locale_info/IsValidLocale/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/IsValidLocale/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/locale_info/IsValidLocale/test1/CMakeLists.txt b/src/pal/tests/palsuite/locale_info/IsValidLocale/test1/CMakeLists.txt
new file mode 100644
index 0000000000..8fc7604a49
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/IsValidLocale/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_isvalidlocale_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_isvalidlocale_test1 coreclrpal)
+
+target_link_libraries(paltest_isvalidlocale_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/locale_info/IsValidLocale/test1/test1.c b/src/pal/tests/palsuite/locale_info/IsValidLocale/test1/test1.c
new file mode 100644
index 0000000000..4dd63653f5
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/IsValidLocale/test1/test1.c
@@ -0,0 +1,76 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Tests IsValidLocale with the current locale, -1, and
+** LOCALE_USER_DEFAULT (which actually isn't valid).
+**
+**
+**==========================================================================*/
+
+
+#include <palsuite.h>
+
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ LCID lcid;
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ /*
+ * Passing LOCALE_USER_DEFAULT to IsValidLocale will fail, so instead
+ * the current thread localed is changed to it, and that lcid is passed
+ * to IsValidLocale (which should always pass)
+ */
+ if (!SetThreadLocale(LOCALE_USER_DEFAULT))
+ {
+ Fail("Unable to set locale to LOCALE_USER_DEFAULT!\n");
+ }
+
+ lcid = GetThreadLocale();
+
+ if (!IsValidLocale(lcid, LCID_SUPPORTED))
+ {
+ Fail("IsValidLocale found the default user locale unsupported!\n");
+ }
+ if (!IsValidLocale(lcid, LCID_INSTALLED))
+ {
+ Fail("IsValidLocale found the default user locale uninstalled!\n");
+ }
+
+ /*
+ * Test out bad parameters
+ */
+ if (IsValidLocale(-1, LCID_SUPPORTED))
+ {
+ Fail("IsValideLocale passed with an invalid LCID!\n");
+ }
+ if (IsValidLocale(-1, LCID_INSTALLED))
+ {
+ Fail("IsValideLocale passed with an invalid LCID!\n");
+ }
+
+ if (IsValidLocale(LOCALE_USER_DEFAULT, LCID_SUPPORTED))
+ {
+ Fail("IsValidLocale passed with LOCALE_USER_DEFAULT!\n");
+ }
+ if (IsValidLocale(LOCALE_USER_DEFAULT, LCID_INSTALLED))
+ {
+ Fail("IsValidLocale passed with LOCALE_USER_DEFAULT!\n");
+ }
+
+ PAL_Terminate();
+
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/locale_info/IsValidLocale/test1/testinfo.dat b/src/pal/tests/palsuite/locale_info/IsValidLocale/test1/testinfo.dat
new file mode 100644
index 0000000000..e9fcc18cf3
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/IsValidLocale/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Locale Information
+Function = IsValidLocale
+Name = Test #1 for IsValidLocale
+TYPE = DEFAULT
+EXE1 = test1
+Description
+=Tests IsValidLocale with the current locale, -1, and LOCALE_USER_DEFAULT
+=(which actually isn't valid).
diff --git a/src/pal/tests/palsuite/locale_info/MultiByteToWideChar/CMakeLists.txt b/src/pal/tests/palsuite/locale_info/MultiByteToWideChar/CMakeLists.txt
new file mode 100644
index 0000000000..0b8ae6062e
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/MultiByteToWideChar/CMakeLists.txt
@@ -0,0 +1,6 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+add_subdirectory(test3)
+add_subdirectory(test4)
diff --git a/src/pal/tests/palsuite/locale_info/MultiByteToWideChar/test1/CMakeLists.txt b/src/pal/tests/palsuite/locale_info/MultiByteToWideChar/test1/CMakeLists.txt
new file mode 100644
index 0000000000..044c47712b
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/MultiByteToWideChar/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_multibytetowidechar_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_multibytetowidechar_test1 coreclrpal)
+
+target_link_libraries(paltest_multibytetowidechar_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/locale_info/MultiByteToWideChar/test1/test1.c b/src/pal/tests/palsuite/locale_info/MultiByteToWideChar/test1/test1.c
new file mode 100644
index 0000000000..81f58a532c
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/MultiByteToWideChar/test1/test1.c
@@ -0,0 +1,81 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Tests MultiByteToWideChar with all the ASCII characters (0-127).
+** Also tests that WideCharToMultiByte handles different buffer
+** lengths correctly (0, -1, and a valid length)
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+
+/*
+ * For now, it is assumed that MultiByteToWideChar will only be used in the PAL
+ * with CP_ACP, and that dwFlags will be 0.
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ char mbStr[128];
+ WCHAR wideStr[128];
+ int ret;
+ int i;
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ for (i=0; i<128; i++)
+ {
+ mbStr[i] = 127 - i;
+ wideStr[i] = 0;
+ }
+
+
+ ret = MultiByteToWideChar(CP_ACP, 0, mbStr, -1, wideStr, 0);
+ if (ret != 128)
+ {
+ Fail("MultiByteToWideChar did not return correct string length!\n"
+ "Got %d, expected %d\n", ret, 128);
+ }
+
+ /* Make sure the ASCII set (0-127) gets translated correctly */
+ ret = MultiByteToWideChar(CP_ACP, 0, mbStr, -1, wideStr, 128);
+ if (ret != 128)
+ {
+ Fail("MultiByteToWideChar did not return correct string length!\n"
+ "Got %d, expected %d\n", ret, 128);
+ }
+
+ for (i=0; i<128; i++)
+ {
+ if (wideStr[i] != (WCHAR)(127 - i))
+ {
+ Fail("MultiByteToWideChar failed to translate correctly!\n"
+ "Expected character %d to be %c (%x), got %c (%x)\n",
+ i, 127 - i, 127 - i,wideStr[i], wideStr[i]);
+ }
+ }
+
+
+ /* try a 0 length string */
+ mbStr[0] = 0;
+ ret = MultiByteToWideChar(CP_ACP, 0, mbStr, -1, wideStr, 0);
+ if (ret != 1)
+ {
+ Fail("MultiByteToWideChar did not return correct string length!\n"
+ "Got %d, expected %d\n", ret, 1);
+ }
+
+ PAL_Terminate();
+
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/locale_info/MultiByteToWideChar/test1/testinfo.dat b/src/pal/tests/palsuite/locale_info/MultiByteToWideChar/test1/testinfo.dat
new file mode 100644
index 0000000000..0e4591d247
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/MultiByteToWideChar/test1/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Locale Information
+Function = MultiByteToWideChar
+Name = Test #1 for MultiByteToWideChar
+TYPE = DEFAULT
+EXE1 = test1
+Description
+=Tests MultiByteToWideChar with all the ASCII characters (0-127).
+=Also tests that WideCharToMultiByte handles different buffer
+=lengths correctly (0, -1, and a valid length)
diff --git a/src/pal/tests/palsuite/locale_info/MultiByteToWideChar/test2/CMakeLists.txt b/src/pal/tests/palsuite/locale_info/MultiByteToWideChar/test2/CMakeLists.txt
new file mode 100644
index 0000000000..0367d53938
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/MultiByteToWideChar/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test2.c
+)
+
+add_executable(paltest_multibytetowidechar_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_multibytetowidechar_test2 coreclrpal)
+
+target_link_libraries(paltest_multibytetowidechar_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/locale_info/MultiByteToWideChar/test2/test2.c b/src/pal/tests/palsuite/locale_info/MultiByteToWideChar/test2/test2.c
new file mode 100644
index 0000000000..1370dba894
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/MultiByteToWideChar/test2/test2.c
@@ -0,0 +1,68 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test2.c
+**
+** Purpose: Tests that MultiByteToWideChar respects the length of the wide
+** character string.
+
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+
+/*
+ * For now, it is assumed that MultiByteToWideChar will only be used in the PAL
+ * with CP_ACP, and that dwFlags will be 0.
+ */
+
+int __cdecl main(int argc, char *argv[])
+{
+ char mbStr[128];
+ WCHAR wideStr[128];
+ int ret;
+ int i;
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ for (i=0; i<128; i++)
+ {
+ mbStr[i] = 'a';
+ wideStr[i] = 0;
+ }
+
+ mbStr[127] = 0;
+
+
+ ret = MultiByteToWideChar(CP_ACP, 0, mbStr, 10, wideStr, 0);
+ if (ret != 10)
+ {
+ Fail("MultiByteToWideChar did not return correct string length!\n"
+ "Got %d, expected %d\n", ret, 10);
+ }
+
+ wideStr[10] = (WCHAR) 'b';
+
+ ret = MultiByteToWideChar(CP_ACP, 0, mbStr, 10, wideStr, 128);
+ if (ret != 10)
+ {
+ Fail("MultiByteToWideChar did not return correct string length!\n"
+ "Got %d, expected %d\n", ret, 10);
+ }
+
+ if (wideStr[10] != 'b')
+ {
+ Fail("WideCharToMultiByte overflowed the destination buffer!\n");
+ }
+
+ PAL_Terminate();
+
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/locale_info/MultiByteToWideChar/test2/testinfo.dat b/src/pal/tests/palsuite/locale_info/MultiByteToWideChar/test2/testinfo.dat
new file mode 100644
index 0000000000..5211db1256
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/MultiByteToWideChar/test2/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Locale Information
+Function = MultiByteToWideChar
+Name = Test #2 for MultiByteToWideChar
+TYPE = DEFAULT
+EXE1 = test2
+Description
+=Tests that MultiByteToWideChar respects the length of the wide
+=character string.
diff --git a/src/pal/tests/palsuite/locale_info/MultiByteToWideChar/test3/CMakeLists.txt b/src/pal/tests/palsuite/locale_info/MultiByteToWideChar/test3/CMakeLists.txt
new file mode 100644
index 0000000000..57e3d66faf
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/MultiByteToWideChar/test3/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test3.c
+)
+
+add_executable(paltest_multibytetowidechar_test3
+ ${SOURCES}
+)
+
+add_dependencies(paltest_multibytetowidechar_test3 coreclrpal)
+
+target_link_libraries(paltest_multibytetowidechar_test3
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/locale_info/MultiByteToWideChar/test3/test3.c b/src/pal/tests/palsuite/locale_info/MultiByteToWideChar/test3/test3.c
new file mode 100644
index 0000000000..1b3a4bd4f5
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/MultiByteToWideChar/test3/test3.c
@@ -0,0 +1,73 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test3.c
+**
+** Purpose: Tests that MultiByteToWideChar correctly handles the following
+** error conditions: insufficient buffer space, invalid code pages,
+** and invalid flags.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ char mbStr[128];
+ WCHAR wideStr[128];
+ int ret;
+ int i;
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ for (i=0; i<128; i++)
+ {
+ mbStr[i] = 'a';
+ wideStr[i] = 0;
+ }
+
+ mbStr[127] = 0;
+
+ /* try with insufficient buffer space */
+ ret = MultiByteToWideChar(CP_ACP, 0, mbStr, -1, wideStr, 10);
+ if (ret != 0)
+ {
+ Fail("MultiByteToWideChar did not return an error!\n"
+ "Expected return of 0, got %d", ret);
+ }
+
+ ret = GetLastError();
+ if (ret != ERROR_INSUFFICIENT_BUFFER)
+ {
+ Fail("MultiByteToWideChar did not set the last error to "
+ "ERROR_INSUFFICIENT_BUFFER!\n");
+ }
+
+ /* try with a wacky code page */
+ ret = MultiByteToWideChar(-1, 0, mbStr, -1, wideStr, 128);
+ if (ret != 0)
+ {
+ Fail("MultiByteToWideChar did not return an error!\n"
+ "Expected return of 0, got %d", ret);
+ }
+
+ ret = GetLastError();
+ if (ret != ERROR_INVALID_PARAMETER)
+ {
+ Fail("MultiByteToWideChar did not set the last error to "
+ "ERROR_INVALID_PARAMETER!\n");
+ }
+
+ PAL_Terminate();
+
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/locale_info/MultiByteToWideChar/test3/testinfo.dat b/src/pal/tests/palsuite/locale_info/MultiByteToWideChar/test3/testinfo.dat
new file mode 100644
index 0000000000..c59f285dca
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/MultiByteToWideChar/test3/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Locale Information
+Function = MultiByteToWideChar
+Name = Test #3 for MultiByteToWideChar
+TYPE = DEFAULT
+EXE1 = test3
+Description
+=Tests that MultiByteToWideChar correctly handles the following
+=error conditions: insufficient buffer space, invalid code pages,
+=and invalid flags.
+
diff --git a/src/pal/tests/palsuite/locale_info/MultiByteToWideChar/test4/CMakeLists.txt b/src/pal/tests/palsuite/locale_info/MultiByteToWideChar/test4/CMakeLists.txt
new file mode 100644
index 0000000000..3d167dff7c
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/MultiByteToWideChar/test4/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test4.c
+)
+
+add_executable(paltest_multibytetowidechar_test4
+ ${SOURCES}
+)
+
+add_dependencies(paltest_multibytetowidechar_test4 coreclrpal)
+
+target_link_libraries(paltest_multibytetowidechar_test4
+ pthread
+ m
+ coreclrpal
+) \ No newline at end of file
diff --git a/src/pal/tests/palsuite/locale_info/MultiByteToWideChar/test4/test4.c b/src/pal/tests/palsuite/locale_info/MultiByteToWideChar/test4/test4.c
new file mode 100644
index 0000000000..2ba606cf35
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/MultiByteToWideChar/test4/test4.c
@@ -0,0 +1,230 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test4.c
+**
+** Purpose: Tests MultiByteToWideChar with a UTF-8 encoding
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ int ret;
+ int ret2;
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ const char * const utf8Strings[] =
+ {
+ // Correct strings
+
+ // Empty string
+ "",
+ // 1 byte encoded 1 character long string
+ "A",
+ // 2 byte encoded 1 character long string
+ "\xC2\x80",
+ // 3 byte encoded 1 character long string
+ "\xE0\xA0\x80",
+ // 1 byte encoded characters only
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
+ // valid 2 byte encoded characters only
+ "\xC2\x80\xC3\xBF\xC7\x81\xDF\xBF",
+ // valid 3 byte encoded characters only
+ "\xE0\xA0\x80\xE1\xB6\x88\xE1\x80\x80\xEF\xBF\xBF",
+ // 1 byte and 2 byte encoded characters interleaved 1:1 starting and ending with 1 byte char
+ "\x41\xC2\x80\x42\xC3\xBF\x43\xC7\x81\x44\xDF\xBF\x45",
+ // 1 byte and 2 byte encoded characters interleaved 1:1 starting with 1 byte char, ending with 2 byte one
+ "\x41\xC2\x80\x42\xC3\xBF\x43\xC7\x81\x44\xDF\xBF",
+ // 1 byte and 2 byte encoded characters interleaved 1:1 starting with 2 byte char, ending with 1 byte one
+ "\xC2\x80\x42\xC3\xBF\x43\xC7\x81\x44\xDF\xBF\x45",
+ // 1 byte and 2 byte encoded characters interleaved 1:1 starting and ending with 2 byte char
+ "\xC2\x80\x42\xC3\xBF\x43\xC7\x81\x44\xDF\xBF",
+ // 1 byte and 2 byte encoded characters interleaved 2:2 starting and ending with 1 byte char
+ "\x41\x42\xC2\x80\xC3\xBF\x43\x44\xC7\x81\xDF\xBF\x45\x46",
+ // 1 byte and 2 byte encoded characters interleaved 2:2 starting with 1 byte char, ending with 2 byte one
+ "\x41\x42\xC2\x80\xC3\xBF\x43\x44\xC7\x81\xDF\xBF",
+ // 1 byte and 2 byte encoded characters interleaved 2:2 starting with 2 byte char, ending with 1 byte one
+ "\xC2\x80\xC3\xBF\x43\x44\xC7\x81\xDF\xBF\x45\x46",
+ // 1 byte and 2 byte encoded characters interleaved 2:2 starting and ending with 2 byte char
+ "\xC2\x80\xC3\xBF\x43\x44\xC7\x81\xDF\xBF",
+ // surrogates
+ "\xF0\x90\x80\x80\xF0\x90\x89\x80\xF3\x80\x8E\xB0\xF4\x8F\xBF\xBF",
+
+ // Strings with errors
+ // Incomplete 2 byte encoded character 1 byte missing standalone
+ "\xC2",
+ // Incomplete 3 byte encoded character 1 byte missing standalone
+ "\xE0\xA0",
+ // Incomplete 3 byte encoded character 2 bytes missing standalone
+ "\xE0",
+ // Incomplete surrogate character 1 byte missing standalone
+ "\xF0\x90\x80",
+ // Incomplete surrogate character 2 bytes missing standalone
+ "\xF0\x90",
+ // Incomplete surrogate character 3 bytes missing standalone
+ "\xF0",
+ // Trailing byte with no lead byte standalone
+ "\x80",
+ // Incomplete 2 byte encoded character 1 byte missing between 1 byte chars
+ "\x41\xC2\x42",
+ // Incomplete 3 byte encoded character 1 byte missing between 1 byte chars
+ "\x41\xE0\xA0\x42",
+ // Incomplete 3 byte encoded character 2 bytes missing between 1 byte chars
+ "\x41\xE0\x42",
+ // Trailing byte with no lead byte between 1 byte chars
+ "\x41\x80\x42",
+ // Incomplete 2 byte encoded character 1 byte missing before 1 byte char
+ "\xC2\x42",
+ // Incomplete 3 byte encoded character 1 byte missing before 1 byte char
+ "\xE0\xA0\x42",
+ // Incomplete 3 byte encoded character 2 bytes missing before 1 byte char
+ "\xE0\x42",
+ // Trailing byte with no lead byte before 1 byte char
+ "\x80\x42",
+ // Incomplete 2 byte encoded character 1 byte missing after 1 byte char
+ "\x41\xC2",
+ // Incomplete 3 byte encoded character 1 byte missing after 1 byte char
+ "\x41\xE0\xA0",
+ // Incomplete 3 byte encoded character 2 bytes missing after 1 byte char
+ "\x41\xE0",
+ // Trailing byte with no lead byte after 1 byte char
+ "\x41\x80",
+ // Incomplete 2 byte encoded character 1 byte missing between 2 byte chars
+ "\xC2\x80\xC2\xC3\xBF",
+ // Incomplete 3 byte encoded character 1 byte missing between 2 byte chars
+ "\xC2\x80\xE0\xA0\xC3\xBF",
+ // Incomplete 3 byte encoded character 2 bytes missing between 2 byte chars
+ "\xC2\x80\xE0\xC3\xBF",
+ // Trailing byte with no lead byte between 2 byte chars
+ "\xC2\x80\x80\xC3\xBF",
+ // 2 byte encoded character in non-shortest form encodings (these are not allowed)
+ "\xC0\x80",
+ // 3 byte encoded character in non-shortest form encodings (these are not allowed)
+ "\xE0\x80\x80",
+ // 4 byte encoded character in non-shortest form encodings (these are not allowed)
+ "\xF0\x80\x80\x80",
+ };
+
+ const WCHAR * const unicodeStrings[] =
+ {
+ // Empty string
+ W(""),
+ // 1 byte encoded 1 character long string
+ W("A"),
+ // 2 byte encoded 1 character long string
+ W("\x0080"),
+ // 3 byte encoded 1 character long string
+ W("\x0800"),
+ // 1 byte encoded characters only
+ W("ABCDEFGHIJKLMNOPQRSTUVWXYZ"),
+ // 2 byte encoded characters only
+ W("\x0080\x00FF\x01C1\x07FF"),
+ // valid 3 byte encoded characters only
+ W("\x0800\x1D88\x1000\xFFFF"),
+ // 1 byte and 2 byte encoded characters interleaved 1:1 starting and ending with 1 byte char
+ W("\x0041\x0080\x0042\x00FF\x0043\x01C1\x0044\x07FF\x0045"),
+ // 1 byte and 2 byte encoded characters interleaved 1:1 starting with 1 byte char, ending with 2 byte one
+ W("\x0041\x0080\x0042\x00FF\x0043\x01C1\x0044\x07FF"),
+ // 1 byte and 2 byte encoded characters interleaved 1:1 starting with 2 byte char, ending with 1 byte one
+ W("\x0080\x0042\x00FF\x0043\x01C1\x0044\x07FF\x0045"),
+ // 1 byte and 2 byte encoded characters interleaved 1:1 starting and ending with 2 byte char
+ W("\x0080\x0042\x00FF\x0043\x01C1\x0044\x07FF"),
+ // 1 byte and 2 byte encoded characters interleaved 2:2 starting and ending with 1 byte char
+ W("\x0041\x0042\x0080\x00FF\x0043\x0044\x01C1\x07FF\x0045\x0046"),
+ // 1 byte and 2 byte encoded characters interleaved 2:2 starting with 1 byte char, ending with 2 byte one
+ W("\x0041\x0042\x0080\x00FF\x0043\x0044\x01C1\x07FF"),
+ // 1 byte and 2 byte encoded characters interleaved 2:2 starting with 2 byte char, ending with 1 byte one
+ W("\x0080\x00FF\x0043\x0044\x01C1\x07FF\x0045\x0046"),
+ // 1 byte and 2 byte encoded characters interleaved 2:2 starting and ending with 2 byte char
+ W("\x0080\x00FF\x0043\x0044\x01C1\x07FF"),
+ // surrogates
+ W("\xD800\xDC00\xD800\xDE40\xDAC0\xDFB0\xDBFF\xDFFF"),
+
+ // Strings with errors
+ // Incomplete 2 byte encoded character standalone
+ W(""),
+ // Incomplete 3 byte encoded character 1 byte missing standalone
+ W(""),
+ // Incomplete 3 byte encoded character 2 bytes missing standalone
+ W(""),
+ // Incomplete surrogate character 1 byte missing standalone
+ W(""),
+ // Incomplete surrogate character 2 bytes missing standalone
+ W(""),
+ // Incomplete surrogate character 3 bytes missing standalone
+ W(""),
+ // Trailing byte with no lead byte standalone
+ W(""),
+ // Incomplete 2 byte encoded character 1 byte missing between 1 byte chars
+ W("\x0041\x0042"),
+ // Incomplete 3 byte encoded character 1 byte missing between 1 byte chars
+ W("\x0041\x0042"),
+ // Incomplete 3 byte encoded character 2 bytes missing between 1 byte chars
+ W("\x0041\x0042"),
+ // Trailing byte with no lead byte between 1 byte chars
+ W("\x0041\x0042"),
+ // Incomplete 2 byte encoded character 1 byte missing before 1 byte char
+ W("\x0042"),
+ // Incomplete 3 byte encoded character 1 byte missing before 1 byte char
+ W("\x0042"),
+ // Incomplete 3 byte encoded character 2 bytes missing before 1 byte char
+ W("\x0042"),
+ // Trailing byte with no lead byte before 1 byte char
+ W("\x0042"),
+ // Incomplete 2 byte encoded character 1 byte missing after 1 byte char
+ W("\x0041"),
+ // Incomplete 3 byte encoded character 1 byte missing after 1 byte char
+ W("\x0041"),
+ // Incomplete 3 byte encoded character 2 bytes missing after 1 byte char
+ W("\x0041"),
+ // Trailing byte with no lead byte after 1 byte char
+ W("\x0041"),
+ // Incomplete 2 byte encoded character 1 byte missing between 2 byte chars
+ W("\x0080\x00FF"),
+ // Incomplete 3 byte encoded character 1 byte missing between 2 byte chars
+ W("\x0080\x00FF"),
+ // Incomplete 3 byte encoded character 2 bytes missing between 2 byte chars
+ W("\x0080\x00FF"),
+ // Trailing byte with no lead byte between 2 byte chars
+ W("\x0080\x00FF"),
+ // 2 byte encoded character in non-shortest form encodings (these are not allowed)
+ W(""),
+ // 3 byte encoded character in non-shortest form encodings (these are not allowed)
+ W(""),
+ // 4 byte encoded character in non-shortest form encodings (these are not allowed)
+ W(""),
+ };
+
+ for (int i = 0; i < (sizeof(utf8Strings) / sizeof(utf8Strings[0])); i++)
+ {
+ ret = MultiByteToWideChar(CP_UTF8, 0, utf8Strings[i], -1, NULL, 0);
+ WCHAR* wideBuffer = malloc(ret * sizeof(WCHAR));
+ ret2 = MultiByteToWideChar(CP_UTF8, 0, utf8Strings[i], -1, wideBuffer, ret);
+ if (ret != ret2)
+ {
+ Fail("MultiByteToWideChar string %d: returned different string length for empty and real dest buffers!\n"
+ "Got %d for the empty one, %d for real one.\n", i, ret2, ret);
+ }
+
+ if (wcscmp(wideBuffer, unicodeStrings[i]) != 0)
+ {
+ Fail("MultiByteToWideChar string %d: the resulting string doesn't match the expected one!\n", i);
+ }
+
+ free(wideBuffer);
+ }
+
+ PAL_Terminate();
+
+ return PASS;
+} \ No newline at end of file
diff --git a/src/pal/tests/palsuite/locale_info/MultiByteToWideChar/test4/testinfo.dat b/src/pal/tests/palsuite/locale_info/MultiByteToWideChar/test4/testinfo.dat
new file mode 100644
index 0000000000..e95f413904
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/MultiByteToWideChar/test4/testinfo.dat
@@ -0,0 +1,13 @@
+#
+# Copyright (c) Microsoft Corporation. All rights reserved.
+#
+
+Version = 1.0
+Section = Locale Information
+Function = MultiByteToWideChar
+Name = Test #4 for MultiByteToWideChar
+TYPE = DEFAULT
+EXE1 = test4
+Description
+=Tests MultiByteToWideChar with UTF-8 encoded strings
+=containing various corner cases \ No newline at end of file
diff --git a/src/pal/tests/palsuite/locale_info/SetThreadLocale/CMakeLists.txt b/src/pal/tests/palsuite/locale_info/SetThreadLocale/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/SetThreadLocale/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/locale_info/SetThreadLocale/test1/CMakeLists.txt b/src/pal/tests/palsuite/locale_info/SetThreadLocale/test1/CMakeLists.txt
new file mode 100644
index 0000000000..85824dd836
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/SetThreadLocale/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_setthreadlocale_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_setthreadlocale_test1 coreclrpal)
+
+target_link_libraries(paltest_setthreadlocale_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/locale_info/SetThreadLocale/test1/test1.c b/src/pal/tests/palsuite/locale_info/SetThreadLocale/test1/test1.c
new file mode 100644
index 0000000000..794093cf4c
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/SetThreadLocale/test1/test1.c
@@ -0,0 +1,50 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Tests SetThreadLocale with every valid locale to see that it passes
+** and that it actually sets the locale.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ int i;
+
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ /* Try all possible locale's */
+ for (i=0; i<0x000fffff; i++)
+ {
+ if (!IsValidLocale(i, LCID_INSTALLED))
+ {
+ continue;
+ }
+
+ if (!SetThreadLocale(i))
+ {
+ Fail("SetThreadLocale failed for an installed locale!\n");
+ }
+
+ if (GetThreadLocale() != i)
+ {
+ Fail("SetThreadLocale didn't actually change to LCID %#x!\n", i);
+ }
+ }
+
+ PAL_Terminate();
+
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/locale_info/SetThreadLocale/test1/testinfo.dat b/src/pal/tests/palsuite/locale_info/SetThreadLocale/test1/testinfo.dat
new file mode 100644
index 0000000000..ba0f5b7eeb
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/SetThreadLocale/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Locale Information
+Function = SetThreadLocale
+Name = Test #1 for SetThreadLocale
+TYPE = DEFAULT
+EXE1 = test1
+Description
+=Tests SetThreadLocale with every valid locale to see that it passes
+=and that it actually sets the locale.
diff --git a/src/pal/tests/palsuite/locale_info/WideCharToMultiByte/CMakeLists.txt b/src/pal/tests/palsuite/locale_info/WideCharToMultiByte/CMakeLists.txt
new file mode 100644
index 0000000000..dc5d5131ec
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/WideCharToMultiByte/CMakeLists.txt
@@ -0,0 +1,7 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+add_subdirectory(test3)
+add_subdirectory(test4)
+add_subdirectory(test5)
diff --git a/src/pal/tests/palsuite/locale_info/WideCharToMultiByte/test1/CMakeLists.txt b/src/pal/tests/palsuite/locale_info/WideCharToMultiByte/test1/CMakeLists.txt
new file mode 100644
index 0000000000..0d1d12b41e
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/WideCharToMultiByte/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_widechartomultibyte_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_widechartomultibyte_test1 coreclrpal)
+
+target_link_libraries(paltest_widechartomultibyte_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/locale_info/WideCharToMultiByte/test1/test1.c b/src/pal/tests/palsuite/locale_info/WideCharToMultiByte/test1/test1.c
new file mode 100644
index 0000000000..cd763f33be
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/WideCharToMultiByte/test1/test1.c
@@ -0,0 +1,102 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Tests WideCharToMultiByte with all the ASCII characters (0-127).
+** Also tests that WideCharToMultiByte handles different buffer
+** lengths correctly (0, -1, and a valid length)
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ char mbStr[128];
+ WCHAR wideStr[128];
+ int ret;
+ int i;
+ int k;
+ BOOL bRet=TRUE;
+
+ /* These codepages are currently supported by the PAL */
+ int codePages[] ={
+ CP_ACP,
+ CP_UTF8
+ };
+
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ /* Go through all of the code pages */
+ for(i=0; i<(sizeof(codePages)/sizeof(int)); i++)
+ {
+
+ for (k=0; k<128; k++)
+ {
+ wideStr[k] = 127 - k;
+ mbStr[k] = 0;
+ }
+
+ /* Convert with buffer size of 0 */
+ ret = WideCharToMultiByte(codePages[i], 0, wideStr, -1,
+ mbStr, 0, NULL, NULL);
+ if (ret != 128)
+ {
+ Trace("WideCharToMultiByte did not return correct string length!\n"
+ "Got %d, expected %d for code page %d with error %u.\n",
+ ret, 128,codePages[i],GetLastError());
+ bRet=FALSE;
+ }
+
+ /* Make sure the ASCII set (0-127) gets translated correctly */
+ ret = WideCharToMultiByte(codePages[i], 0, wideStr, -1,
+ mbStr, 128, NULL, NULL);
+ if (ret != 128)
+ {
+ Trace("WideCharToMultiByte did not return correct string length!\n"
+ "Got %d, expected %d for code page %d with error %u.\n",
+ ret, 128,codePages[i],GetLastError());
+ bRet=FALSE;
+ }
+
+ for (k=0; k<128; k++)
+ {
+ if (mbStr[k] != 127 - k)
+ {
+ Trace("WideCharToMultiByte failed to translate correctly!\n"
+ "Expected character %d to be %c (%x), got %c (%x) for "
+ "code page %d\n",k, 127 - k, 127 - k,mbStr[k], mbStr[k],
+ codePages[i]);
+ bRet=FALSE;
+ }
+ }
+
+
+ /* try a 0 length string ("") */
+ wideStr[0] = '\0';
+ ret = WideCharToMultiByte(codePages[i], 0, wideStr, -1,
+ mbStr, 0, NULL, NULL);
+ if (ret != 1)
+ {
+ Trace("WideCharToMultiByte did not return correct string length!\n"
+ "Got %d, expected %d for code page %d with error %u.\n",
+ ret, 1,codePages[i],GetLastError());
+ bRet=FALSE;
+ }
+ }
+
+ int result = bRet ? PASS : FAIL;
+ PAL_TerminateEx(result);
+ return result;
+}
+
diff --git a/src/pal/tests/palsuite/locale_info/WideCharToMultiByte/test1/testinfo.dat b/src/pal/tests/palsuite/locale_info/WideCharToMultiByte/test1/testinfo.dat
new file mode 100644
index 0000000000..9fb5f0f032
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/WideCharToMultiByte/test1/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Locale Information
+Function = WideCharToMultiByte
+Name = Test #1 for WideCharToMultiByte
+TYPE = DEFAULT
+EXE1 = test1
+Description
+=Tests WideCharToMultiByte with all the ASCII characters (0-127).
+=Also tests that WideCharToMultiByte handles different buffer
+=lengths correctly (0, -1, and a valid length)
diff --git a/src/pal/tests/palsuite/locale_info/WideCharToMultiByte/test2/CMakeLists.txt b/src/pal/tests/palsuite/locale_info/WideCharToMultiByte/test2/CMakeLists.txt
new file mode 100644
index 0000000000..bbfad2ca9f
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/WideCharToMultiByte/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test2.c
+)
+
+add_executable(paltest_widechartomultibyte_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_widechartomultibyte_test2 coreclrpal)
+
+target_link_libraries(paltest_widechartomultibyte_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/locale_info/WideCharToMultiByte/test2/test2.c b/src/pal/tests/palsuite/locale_info/WideCharToMultiByte/test2/test2.c
new file mode 100644
index 0000000000..f5d40ae903
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/WideCharToMultiByte/test2/test2.c
@@ -0,0 +1,88 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test2.c
+**
+** Purpose: Tests that WideCharToMultiByte respects the length of the wide
+** character string.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ char mbStr[128];
+ WCHAR wideStr[128];
+ int ret;
+ int i;
+ int k;
+ BOOL bRet=TRUE;
+
+ /* These codepages are currently supported by the PAL */
+ int codePages[] ={
+ CP_ACP,
+ CP_UTF8
+ };
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ /* Go through all of the code pages */
+ for(i=0; i<(sizeof(codePages)/sizeof(int)); i++)
+ {
+
+ /* Filling the arrays */
+ for (k=0; k<128; k++)
+ {
+ wideStr[k] = 'a';
+ mbStr[i] = 0;
+ }
+
+ wideStr[127] = 0;
+
+ /* Passing a buffer that is too small */
+ ret = WideCharToMultiByte(codePages[i], 0, wideStr, 10,
+ mbStr, 0, NULL, NULL);
+ if (ret != 10)
+ {
+ Trace("WideCharToMultiByte did not return correct string length!\n"
+ "Got %d, expected %d for %d with error %u.\n", ret, 10,
+ codePages[i], GetLastError());
+ bRet = FALSE;
+ }
+
+ /* Passing a sufficiently large buffer */
+ mbStr[10] = 'b';
+ ret = WideCharToMultiByte(codePages[i], 0, wideStr, 10,
+ mbStr, 128, NULL, NULL);
+ if (ret != 10)
+ {
+ Trace("WideCharToMultiByte did not return correct string length!\n"
+ "Got %d, expected %d for code page %d with error %u.\n",
+ ret, 10, codePages[i], GetLastError());
+ bRet = FALSE;
+ }
+
+ /* Verifying overflow of the destination string did not occur */
+ if (mbStr[10] != 'b')
+ {
+ Trace("WideCharToMultiByte overflowed the destination buffer for "
+ "code page %d.\n", codePages[i]);
+ bRet = FALSE;
+ }
+
+ }
+
+ int result = bRet ? PASS : FAIL;
+ PAL_TerminateEx(result);
+ return result;
+}
+
diff --git a/src/pal/tests/palsuite/locale_info/WideCharToMultiByte/test2/testinfo.dat b/src/pal/tests/palsuite/locale_info/WideCharToMultiByte/test2/testinfo.dat
new file mode 100644
index 0000000000..e5b50b8143
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/WideCharToMultiByte/test2/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Locale Information
+Function = WideCharToMultiByte
+Name = Test #2 for WideCharToMultiByte
+TYPE = DEFAULT
+EXE1 = test2
+Description
+=Tests that WideCharToMultiByte respects the length of the wide
+=character string.
diff --git a/src/pal/tests/palsuite/locale_info/WideCharToMultiByte/test3/CMakeLists.txt b/src/pal/tests/palsuite/locale_info/WideCharToMultiByte/test3/CMakeLists.txt
new file mode 100644
index 0000000000..0edfd73931
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/WideCharToMultiByte/test3/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test3.c
+)
+
+add_executable(paltest_widechartomultibyte_test3
+ ${SOURCES}
+)
+
+add_dependencies(paltest_widechartomultibyte_test3 coreclrpal)
+
+target_link_libraries(paltest_widechartomultibyte_test3
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/locale_info/WideCharToMultiByte/test3/test3.c b/src/pal/tests/palsuite/locale_info/WideCharToMultiByte/test3/test3.c
new file mode 100644
index 0000000000..ecd26addb4
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/WideCharToMultiByte/test3/test3.c
@@ -0,0 +1,100 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test3.c
+**
+** Purpose: Tests that WideCharToMultiByte correctly handles the following
+** error conditions: insufficient buffer space, invalid code pages,
+** and invalid flags.
+**
+**
+**==========================================================================*/
+
+
+#include <palsuite.h>
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ char mbStr[128];
+ WCHAR wideStr[128];
+ int ret;
+ int i;
+ int k;
+ BOOL bRet=TRUE;
+
+ /* These codepages are currently supported by the PAL */
+ int codePages[] ={
+ CP_ACP,
+ CP_UTF8
+ };
+
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ /* Go through all of the code pages */
+ for(i=0; i<(sizeof(codePages)/sizeof(int)); i++)
+ {
+
+ for (k=0; k<128; k++)
+ {
+ wideStr[k] = 'a';
+ mbStr[k] = 0;
+ }
+
+ wideStr[127] = 0;
+
+ /* try with insufficient buffer space */
+ ret = WideCharToMultiByte(codePages[i], 0, wideStr, -1,
+ mbStr, 10, NULL, NULL);
+ if (ret != 0)
+ {
+ Trace("WideCharToMultiByte did not return an error!\n"
+ "Expected return of 0, got %d for code page %d.\n", ret,
+ codePages[i]);
+ bRet = FALSE;
+ }
+
+ ret = GetLastError();
+ if (ret != ERROR_INSUFFICIENT_BUFFER)
+ {
+ Fail("WideCharToMultiByte set the last error to %u instead of "
+ "ERROR_INSUFFICIENT_BUFFER for code page %d.\n",
+ GetLastError(),codePages[i]);
+ bRet = FALSE;
+ }
+ }
+
+ /* Return failure if any of the code pages returned the wrong results */
+ if(!bRet)
+ {
+ return FAIL;
+ }
+
+ /* try with a wacky code page */
+ ret = WideCharToMultiByte(-1, 0, wideStr, -1, mbStr, 128, NULL, NULL);
+ if (ret != 0)
+ {
+ Fail("WideCharToMultiByte did not return an error!\n"
+ "Expected return of 0, got %d for invalid code page.\n", ret);
+ }
+
+ ret = GetLastError();
+ if (ret != ERROR_INVALID_PARAMETER)
+ {
+ Fail("WideCharToMultiByte set the last error to %u instead of "
+ "ERROR_INVALID_PARAMETER for invalid code page -1.\n",
+ GetLastError());
+ }
+
+ PAL_Terminate();
+
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/locale_info/WideCharToMultiByte/test3/testinfo.dat b/src/pal/tests/palsuite/locale_info/WideCharToMultiByte/test3/testinfo.dat
new file mode 100644
index 0000000000..b737686c39
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/WideCharToMultiByte/test3/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Locale Information
+Function = WideCharToMultiByte
+Name = Test #3 for WideCharToMultiByte
+TYPE = DEFAULT
+EXE1 = test3
+Description
+=Tests that WideCharToMultiByte correctly handles the following
+=error conditions: insufficient buffer space and invalid code pages.
+
diff --git a/src/pal/tests/palsuite/locale_info/WideCharToMultiByte/test4/CMakeLists.txt b/src/pal/tests/palsuite/locale_info/WideCharToMultiByte/test4/CMakeLists.txt
new file mode 100644
index 0000000000..f0ffd84ee9
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/WideCharToMultiByte/test4/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test4.c
+)
+
+add_executable(paltest_widechartomultibyte_test4
+ ${SOURCES}
+)
+
+add_dependencies(paltest_widechartomultibyte_test4 coreclrpal)
+
+target_link_libraries(paltest_widechartomultibyte_test4
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/locale_info/WideCharToMultiByte/test4/test4.c b/src/pal/tests/palsuite/locale_info/WideCharToMultiByte/test4/test4.c
new file mode 100644
index 0000000000..8ab5fe90af
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/WideCharToMultiByte/test4/test4.c
@@ -0,0 +1,131 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test4.c
+**
+** Purpose: Tests that WideCharToMultiByte correctly handles WC_NO_BEST_FIT_CHARS
+**
+**
+**==========================================================================*/
+
+
+#include <palsuite.h>
+
+/* C with a circumflex */
+wchar_t ustr[2] = { 0x108, 0 };
+
+/* expected conversion when best fit is allowed on Windows */
+char* lpBestFitRes = "C";
+
+/* expected conversion when no default character is specified */
+char* lpResStr1 = "?";
+
+/* expected conversion when the default character is 'k' */
+char myDefaultChar = 'k';
+char* lpResStr2 = "k";
+
+int
+TestWideCharToMultiByte(
+ IN UINT CodePage,
+ IN DWORD dwFlags,
+ IN LPCSTR lpDefaultChar,
+ IN LPSTR lpResStr)
+{
+ char mbstr[30];
+ int ret;
+ int testStatus = PASS;
+ BOOL usedDefaultChar = FALSE;
+
+ printf("WideCharToMultiByte (CodePage=%d, dwFlags=%#x, default=%c)\n",
+ CodePage, dwFlags, lpDefaultChar?*lpDefaultChar:' ');
+ ret = WideCharToMultiByte(CodePage, dwFlags, ustr, -1, mbstr, sizeof(mbstr),
+ lpDefaultChar, &usedDefaultChar);
+ if (ret != 0) {
+ printf(" converted C with circumflex to in Unicode to multibyte: "
+ "\"%s\"\n", mbstr);
+ printf(" used default character?: %d\n", usedDefaultChar);
+ if (strcmp(mbstr, lpResStr) != 0 || usedDefaultChar != TRUE)
+ {
+ printf("!!!! failed conversion !!!!\n");
+ testStatus = FAIL;
+ }
+ }
+ else {
+ printf("!!!! failed conversion !!!!\n");
+ testStatus = FAIL;
+ }
+ return testStatus;
+}
+
+int __cdecl main(int argc, char *argv[])
+{
+ int testStatus = PASS;
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ /* Use WideCharToMultiByte to convert the string in code page CP_ACP.
+ * Note that the resulting string will be different on Windows PAL and
+ * Unix PAL. On Windows, the default best fit behavior will map C with
+ * circumflex to C.
+ *
+ * testStatus |= TestWideCharToMultiByte(CP_ACP, 0, NULL, lpBestFitRes);
+ *
+ * On Unix, where there is no support for finding best fit, it will be
+ * mapped to a '?'. In addition, it will trigger an ASSERT in the dbg/chk
+ * builds.
+ *
+ * testStatus |= TestWideCharToMultiByte(CP_ACP, 0, NULL, lpResStr1);
+ */
+
+ /* Use WideCharToMultiByte with WC_NO_BEST_FIR_CHARS to convert the string
+ * in CP_ACP (1252 by default). This will prevent it from mapping the C
+ * with circumflex to its closest match in the ANSI code page: C
+ */
+ testStatus |= TestWideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, NULL, lpResStr1);
+
+
+ /* Use WideCharToMultiByte with WC_NO_BEST_FIR_CHARS and a default character
+ * to convert the string. This will prevent it from mapping the C with
+ * circumflex to its closest match in the ANSI code page: C. It will be
+ * replaced with the specified default character.
+ */
+ testStatus |= TestWideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, &myDefaultChar, lpResStr2);
+
+ /* Use WideCharToMultiByte to convert the string in code page 1253
+ * Note that the resulting string will be different on Windows PAL and
+ * Unix PAL. On Windows, the default best fit behavior will map C with
+ * circumflex to C.
+ *
+ * testStatus |= TestWideCharToMultiByte(1253, 0, NULL, lpBestFitRes);
+ *
+ * On Unix, where there is no support for finding best fit, it will be
+ * mapped to a '?'. In addition, it will trigger an ASSERT in the dbg/chk
+ * builds.
+ *
+ * testStatus |= TestWideCharToMultiByte(1253, 0, NULL, lpResStr1);
+ */
+
+ /* Use WideCharToMultiByte with WC_NO_BEST_FIR_CHARS to convert the string
+ * in 1253. This will prevent it from mapping the C
+ * with circumflex to its closest match in the ANSI code page: C
+ */
+ testStatus |= TestWideCharToMultiByte(1253, WC_NO_BEST_FIT_CHARS, NULL, lpResStr1);
+
+ /* Use WideCharToMultiByte with WC_NO_BEST_FIR_CHARS and a default
+ * character to convert the string in 1253. This will prevent it from
+ * mapping the C with circumflex to its closest match in the ANSI code
+ * page: C. It will be replaced with the specified default character.
+ */
+ testStatus |= TestWideCharToMultiByte(1253, WC_NO_BEST_FIT_CHARS, &myDefaultChar, lpResStr2);
+
+ PAL_TerminateEx(testStatus);
+
+ return testStatus;
+}
+
diff --git a/src/pal/tests/palsuite/locale_info/WideCharToMultiByte/test4/testinfo.dat b/src/pal/tests/palsuite/locale_info/WideCharToMultiByte/test4/testinfo.dat
new file mode 100644
index 0000000000..03b00d3548
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/WideCharToMultiByte/test4/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Locale Information
+Function = WideCharToMultiByte
+Name = Test #4 for WideCharToMultiByte
+TYPE = DEFAULT
+EXE1 = test4
+Description
+=Tests that WideCharToMultiByte correctly handles WC_NO_BEST_FIT_CHARS
diff --git a/src/pal/tests/palsuite/locale_info/WideCharToMultiByte/test5/CMakeLists.txt b/src/pal/tests/palsuite/locale_info/WideCharToMultiByte/test5/CMakeLists.txt
new file mode 100644
index 0000000000..6ca2a628bf
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/WideCharToMultiByte/test5/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test5.c
+)
+
+add_executable(paltest_widechartomultibyte_test5
+ ${SOURCES}
+)
+
+add_dependencies(paltest_widechartomultibyte_test5 coreclrpal)
+
+target_link_libraries(paltest_widechartomultibyte_test5
+ pthread
+ m
+ coreclrpal
+) \ No newline at end of file
diff --git a/src/pal/tests/palsuite/locale_info/WideCharToMultiByte/test5/test5.c b/src/pal/tests/palsuite/locale_info/WideCharToMultiByte/test5/test5.c
new file mode 100644
index 0000000000..3ca0d90d0f
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/WideCharToMultiByte/test5/test5.c
@@ -0,0 +1,154 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test4.c
+**
+** Purpose: Tests WideCharMultiByte with UTF-8 encoding
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ int ret;
+ int ret2;
+
+ if (PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ const WCHAR * const unicodeStrings[] =
+ {
+ // Correct strings
+
+ // Empty string
+ W(""),
+ // 1 byte encoded 1 character long string
+ W("A"),
+ // 2 byte encoded 1 character long string
+ W("\x0080"),
+ // 3 byte encoded 1 character long string
+ W("\x0800"),
+ // 1 byte encoded characters only
+ W("ABCDEFGHIJKLMNOPQRSTUVWXYZ"),
+ // 2 byte encoded characters only
+ W("\x0080\x00FF\x01C1\x07FF"),
+ // valid 3 byte encoded characters only
+ W("\x0800\x1D88\x1000\xFFFF"),
+ // 1 byte and 2 byte encoded characters interleaved 1:1 starting and ending with 1 byte char
+ W("\x0041\x0080\x0042\x00FF\x0043\x01C1\x0044\x07FF\x0045"),
+ // 1 byte and 2 byte encoded characters interleaved 1:1 starting with 1 byte char, ending with 2 byte one
+ W("\x0041\x0080\x0042\x00FF\x0043\x01C1\x0044\x07FF"),
+ // 1 byte and 2 byte encoded characters interleaved 1:1 starting with 2 byte char, ending with 1 byte one
+ W("\x0080\x0042\x00FF\x0043\x01C1\x0044\x07FF\x0045"),
+ // 1 byte and 2 byte encoded characters interleaved 1:1 starting and ending with 2 byte char
+ W("\x0080\x0042\x00FF\x0043\x01C1\x0044\x07FF"),
+ // 1 byte and 2 byte encoded characters interleaved 2:2 starting and ending with 1 byte char
+ W("\x0041\x0042\x0080\x00FF\x0043\x0044\x01C1\x07FF\x0045\x0046"),
+ // 1 byte and 2 byte encoded characters interleaved 2:2 starting with 1 byte char, ending with 2 byte one
+ W("\x0041\x0042\x0080\x00FF\x0043\x0044\x01C1\x07FF"),
+ // 1 byte and 2 byte encoded characters interleaved 2:2 starting with 2 byte char, ending with 1 byte one
+ W("\x0080\x00FF\x0043\x0044\x01C1\x07FF\x0045\x0046"),
+ // 1 byte and 2 byte encoded characters interleaved 2:2 starting and ending with 2 byte char
+ W("\x0080\x00FF\x0043\x0044\x01C1\x07FF"),
+ // Surrogates
+ W("\xD800\xDC00\xD800\xDE40\xDAC0\xDFB0\xDBFF\xDFFF"),
+
+ // Strings with errors
+
+ // Single high surrogate
+ W("\xD800"),
+ // Single low surrogate
+ W("\xDC00"),
+ // Character followed by single high surrogate
+ W("\x0041\xD800"),
+ // Character followed by single low surrogate
+ W("\x0041\xDC00"),
+ // Single high surrogate between two characters
+ W("\x0041\xD800\x0042"),
+ // Single low surrogate between two characters
+ W("\x0041\xDC00\x0042"),
+ };
+
+ const char * const utf8Strings[] =
+ {
+ // Correct strings
+
+ // Empty string
+ "",
+ // 1 byte encoded 1 character long string
+ "A",
+ // 2 byte encoded 1 character long string
+ "\xC2\x80",
+ // 3 byte encoded 1 character long string
+ "\xE0\xA0\x80",
+ // 1 byte encoded characters only
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
+ // valid 2 byte encoded characters only
+ "\xC2\x80\xC3\xBF\xC7\x81\xDF\xBF",
+ // valid 3 byte encoded characters only
+ "\xE0\xA0\x80\xE1\xB6\x88\xE1\x80\x80\xEF\xBF\xBF",
+ // 1 byte and 2 byte encoded characters interleaved 1:1 starting and ending with 1 byte char
+ "\x41\xC2\x80\x42\xC3\xBF\x43\xC7\x81\x44\xDF\xBF\x45",
+ // 1 byte and 2 byte encoded characters interleaved 1:1 starting with 1 byte char, ending with 2 byte one
+ "\x41\xC2\x80\x42\xC3\xBF\x43\xC7\x81\x44\xDF\xBF",
+ // 1 byte and 2 byte encoded characters interleaved 1:1 starting with 2 byte char, ending with 1 byte one
+ "\xC2\x80\x42\xC3\xBF\x43\xC7\x81\x44\xDF\xBF\x45",
+ // 1 byte and 2 byte encoded characters interleaved 1:1 starting and ending with 2 byte char
+ "\xC2\x80\x42\xC3\xBF\x43\xC7\x81\x44\xDF\xBF",
+ // 1 byte and 2 byte encoded characters interleaved 2:2 starting and ending with 1 byte char
+ "\x41\x42\xC2\x80\xC3\xBF\x43\x44\xC7\x81\xDF\xBF\x45\x46",
+ // 1 byte and 2 byte encoded characters interleaved 2:2 starting with 1 byte char, ending with 2 byte one
+ "\x41\x42\xC2\x80\xC3\xBF\x43\x44\xC7\x81\xDF\xBF",
+ // 1 byte and 2 byte encoded characters interleaved 2:2 starting with 2 byte char, ending with 1 byte one
+ "\xC2\x80\xC3\xBF\x43\x44\xC7\x81\xDF\xBF\x45\x46",
+ // 1 byte and 2 byte encoded characters interleaved 2:2 starting and ending with 2 byte char
+ "\xC2\x80\xC3\xBF\x43\x44\xC7\x81\xDF\xBF",
+ // Surrogates
+ "\xF0\x90\x80\x80\xF0\x90\x89\x80\xF3\x80\x8E\xB0\xF4\x8F\xBF\xBF",
+
+ // Strings with errors
+
+ // Single high surrogate
+ "\xEF\xBF\xBD",
+ // Single low surrogate
+ "\xEF\xBF\xBD",
+ // Character followed by single high surrogate
+ "\x41\xEF\xBF\xBD",
+ // Character followed by single low surrogate
+ "\x41\xEF\xBF\xBD",
+ // Single high surrogate between two characters
+ "\x41\xEF\xBF\xBD\x42",
+ // Single low surrogate between two characters
+ "\x41\xEF\xBF\xBD\x42",
+ };
+
+ for (int i = 0; i < (sizeof(unicodeStrings) / sizeof(unicodeStrings[0])); i++)
+ {
+ ret = WideCharToMultiByte(CP_UTF8, 0, unicodeStrings[i], -1, NULL, 0, NULL, NULL);
+ CHAR* utf8Buffer = malloc(ret * sizeof(CHAR));
+ ret2 = WideCharToMultiByte(CP_UTF8, 0, unicodeStrings[i], -1, utf8Buffer, ret, NULL, NULL);
+ if (ret != ret2)
+ {
+ Fail("WideCharToMultiByte string %d: returned different string length for empty and real dest buffers!\n"
+ "Got %d for the empty one, %d for real one.\n", i, ret2, ret);
+ }
+
+ if (strcmp(utf8Buffer, utf8Strings[i]) != 0)
+ {
+ Fail("WideCharToMultiByte string %d: the resulting string doesn't match the expected one!\n", i);
+ }
+
+ free(utf8Buffer);
+ }
+
+ PAL_Terminate();
+
+ return PASS;
+} \ No newline at end of file
diff --git a/src/pal/tests/palsuite/locale_info/WideCharToMultiByte/test5/testinfo.dat b/src/pal/tests/palsuite/locale_info/WideCharToMultiByte/test5/testinfo.dat
new file mode 100644
index 0000000000..485d9401e5
--- /dev/null
+++ b/src/pal/tests/palsuite/locale_info/WideCharToMultiByte/test5/testinfo.dat
@@ -0,0 +1,13 @@
+#
+# Copyright (c) Microsoft Corporation. All rights reserved.
+#
+
+Version = 1.0
+Section = Locale Information
+Function = WideCharToMultiByte
+Name = Test #5 for WideCharToMultiByte
+TYPE = DEFAULT
+EXE1 = test5
+Description
+=Tests WideCharToMultiByte conversion to UTF-8
+=containing various corner cases \ No newline at end of file
diff --git a/src/pal/tests/palsuite/manual-inspect.dat b/src/pal/tests/palsuite/manual-inspect.dat
new file mode 100644
index 0000000000..c541b2ff85
--- /dev/null
+++ b/src/pal/tests/palsuite/manual-inspect.dat
@@ -0,0 +1,17 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+# Automatable to detect gross errors; also manually inspect for proper behaviour
+miscellaneous/messageboxw/test1,1
+# Automatable to detect gross errors; also manually inspect for proper behaviour
+# Env var PAL_DISABLE_MESSAGEBOX=1 disables msg boxes for automation on Windows
+miscellaneous/messageboxw/test2,1
+# Automatable to detect gross errors; also manually inspect for proper behaviour
+pal_specific/pal_get_stderr/test1,1
+pal_specific/pal_get_stdout/test1,1
+# The tests for the sleep api may fail depending upon what other
+# processes are running and their relative priority.
+threading/sleep/test1,1
+threading/sleepex/test1,1
+
diff --git a/src/pal/tests/palsuite/manual-unautomatable.dat b/src/pal/tests/palsuite/manual-unautomatable.dat
new file mode 100644
index 0000000000..0a9a7a1b63
--- /dev/null
+++ b/src/pal/tests/palsuite/manual-unautomatable.dat
@@ -0,0 +1,35 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+#This test is negative and will exit with exit(1).
+#Therefore, the harness would record it as a failure
+c_runtime/exit/test2,1
+# A successful DebugBreak test run dumps core or throws up an ASSERT
+# dialog box (or...) and returns an exit code != 0
+debug_api/debugbreak/test1,1
+# debug_api/outputdebugstringa/test1 attempts to send "Foo!" to the debugger
+# The PAL behaviour is implementation dependant and can include an interactive
+# dialog
+debug_api/outputdebugstringw/test1,1
+debug_api/outputdebugstringa/test1,1
+# The return code on success is NOT the usual 0, instead it's 3
+exception_handling/setunhandledexceptionfilter/test1,1
+# These tests require user intervention and cannot be automated
+pal_specific/pal_get_stdin/test1,1
+threading/setconsolectrlhandler/test1,1
+threading/setconsolectrlhandler/test4,1
+# These tests take several minutes to run and time out when run with the harness
+file_io/gettempfilenamea/test2,1
+file_io/gettempfilenamew/test2,1
+# getstdhandle fails under Windows if the output is redirected so
+# it must be run from the command line
+file_io/getstdhandle/test1,1
+# This test runs calculations in a nested loop to occupy the processor.
+# This causes the test harness to time out on some machines.
+threading/threadpriority/test1,1
+# This test runs for 96 minutes and will time out with the harness.
+threading/sleep/test2,1
+# This test runs forever by design.
+threading/waitformultipleobjects/test2,1
+
diff --git a/src/pal/tests/palsuite/miscellaneous/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/CMakeLists.txt
new file mode 100644
index 0000000000..86f194198b
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/CMakeLists.txt
@@ -0,0 +1,44 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(CharNextA)
+add_subdirectory(CharNextExA)
+add_subdirectory(CloseHandle)
+add_subdirectory(CreatePipe)
+add_subdirectory(FlushInstructionCache)
+add_subdirectory(FormatMessageW)
+add_subdirectory(FreeEnvironmentStringsW)
+add_subdirectory(GetCommandLineW)
+add_subdirectory(GetComputerNameW)
+add_subdirectory(GetEnvironmentStringsW)
+add_subdirectory(GetEnvironmentVariableA)
+add_subdirectory(GetEnvironmentVariableW)
+add_subdirectory(GetLastError)
+add_subdirectory(GetSystemInfo)
+add_subdirectory(GetTickCount)
+add_subdirectory(InterlockedBit)
+add_subdirectory(InterlockedCompareExchange)
+add_subdirectory(InterlockedCompareExchange64)
+add_subdirectory(InterlockedCompareExchangePointer)
+add_subdirectory(InterlockedDecrement)
+add_subdirectory(InterlockedDecrement64)
+add_subdirectory(InterlockedExchange)
+add_subdirectory(InterlockedExchange64)
+add_subdirectory(InterLockedExchangeAdd)
+add_subdirectory(InterlockedExchangePointer)
+add_subdirectory(InterlockedIncrement)
+add_subdirectory(InterlockedIncrement64)
+add_subdirectory(lstrcatW)
+add_subdirectory(lstrcpynW)
+add_subdirectory(lstrcpyW)
+add_subdirectory(lstrlenA)
+add_subdirectory(lstrlenW)
+add_subdirectory(queryperformancecounter)
+add_subdirectory(queryperformancefrequency)
+add_subdirectory(SetEnvironmentVariableA)
+add_subdirectory(SetEnvironmentVariableW)
+add_subdirectory(SetLastError)
+add_subdirectory(wsprintfA)
+add_subdirectory(wsprintfW)
+add_subdirectory(_i64tow)
+add_subdirectory(_ui64tow)
+
diff --git a/src/pal/tests/palsuite/miscellaneous/CharNextA/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/CharNextA/CMakeLists.txt
new file mode 100644
index 0000000000..ef14ea5352
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/CharNextA/CMakeLists.txt
@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+
diff --git a/src/pal/tests/palsuite/miscellaneous/CharNextA/test1/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/CharNextA/test1/CMakeLists.txt
new file mode 100644
index 0000000000..8506d86737
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/CharNextA/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.c
+)
+
+add_executable(paltest_charnexta_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_charnexta_test1 coreclrpal)
+
+target_link_libraries(paltest_charnexta_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/CharNextA/test1/test.c b/src/pal/tests/palsuite/miscellaneous/CharNextA/test1/test.c
new file mode 100644
index 0000000000..d2a3db31d5
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/CharNextA/test1/test.c
@@ -0,0 +1,62 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: test.c
+**
+** Purpose: Test for CharNextA, ensures it returns the proper char for an
+** entire string
+**
+**
+**=========================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc,char *argv[])
+{
+
+ char * AnExampleString = "this is the string";
+ char * StringPointer = AnExampleString;
+ int count = 0;
+
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /* Use CharNext to move through an entire string. Ensure the pointer that
+ is returned points to the correct character, by comparing it with
+ 'StringPointer' which isn't touched by CharNext.
+ */
+
+ while(*AnExampleString != '\0')
+ {
+
+ /* Fail if any characters are different. This is comparing the
+ * addresses of both characters, not the characters themselves.
+ */
+
+ if(AnExampleString != &StringPointer[count])
+ {
+ Fail("ERROR: %#x and %#x are different. These should be the same "
+ " address.\n",AnExampleString,&StringPointer[count]);
+
+
+ }
+
+ AnExampleString = CharNextA(AnExampleString);
+ ++count;
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/CharNextA/test1/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/CharNextA/test1/testinfo.dat
new file mode 100644
index 0000000000..e2b5e501d7
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/CharNextA/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = CharNextA
+Name = Positive Test for CharNextA
+TYPE = DEFAULT
+EXE1 = test
+Description
+= Test to see if CharNextA works properly
+= when calling it repeatedly on a single string.
diff --git a/src/pal/tests/palsuite/miscellaneous/CharNextA/test2/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/CharNextA/test2/CMakeLists.txt
new file mode 100644
index 0000000000..04f4679630
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/CharNextA/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.c
+)
+
+add_executable(paltest_charnexta_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_charnexta_test2 coreclrpal)
+
+target_link_libraries(paltest_charnexta_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/CharNextA/test2/test.c b/src/pal/tests/palsuite/miscellaneous/CharNextA/test2/test.c
new file mode 100644
index 0000000000..7261959021
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/CharNextA/test2/test.c
@@ -0,0 +1,67 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: test.c
+**
+** Purpose: Test for CharNextA, ensures it returns an LPTSTR
+**
+**
+**=========================================================*/
+
+/* Depends on strcmp() */
+
+#include <palsuite.h>
+
+void testString(LPSTR input, LPSTR expected)
+{
+
+ LPTSTR pReturned = NULL;
+
+ pReturned = CharNextA(input);
+
+ /* Compare the Returned String to what it should be */
+ if(strcmp(expected,pReturned) != 0)
+ {
+ Fail("ERROR: CharNextA Failed: [%s] and [%s] are not equal, "
+ "they should be after calling CharNextA.\n",
+ pReturned,expected);
+ }
+
+
+}
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /* test several Strings */
+ testString("this is the string", "his is the string");
+ testString("t", "");
+ testString("", "");
+ testString("a\t", "\t");
+ testString("a\a", "\a");
+ testString("a\b", "\b");
+ testString("a\"", "\"");
+ testString("a\\", "\\");
+ testString("\\", "");
+ testString("\f", "");
+ testString("\b", "");
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/CharNextA/test2/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/CharNextA/test2/testinfo.dat
new file mode 100644
index 0000000000..4b663851b3
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/CharNextA/test2/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = CharNextA
+Name = Positive Test for CharNextA
+TYPE = DEFAULT
+EXE1 = test
+Description
+= Test to ensure it returns an LPTSTR when called on a string
diff --git a/src/pal/tests/palsuite/miscellaneous/CharNextExA/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/CharNextExA/CMakeLists.txt
new file mode 100644
index 0000000000..ef14ea5352
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/CharNextExA/CMakeLists.txt
@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+
diff --git a/src/pal/tests/palsuite/miscellaneous/CharNextExA/test1/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/CharNextExA/test1/CMakeLists.txt
new file mode 100644
index 0000000000..bfa12b5526
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/CharNextExA/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.c
+)
+
+add_executable(paltest_charnextexa_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_charnextexa_test1 coreclrpal)
+
+target_link_libraries(paltest_charnextexa_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/CharNextExA/test1/test.c b/src/pal/tests/palsuite/miscellaneous/CharNextExA/test1/test.c
new file mode 100644
index 0000000000..9671ca86b8
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/CharNextExA/test1/test.c
@@ -0,0 +1,63 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: test.c
+**
+** Purpose: Test for CharNextExA function
+**
+**
+**=========================================================*/
+
+/*
+ This test is FINISHED. This function is the same as CharNextA it seems,
+ since the only fields that differ are always 0.
+*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ char * AnExampleString = "this is the string";
+ char * StringPointer = AnExampleString;
+ int count = 0;
+
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /* Use CharNext to move through an entire string. Ensure the pointer
+ * that is returned points to the correct character, by comparing it with
+ * 'stringPointer' which isn't touched by CharNext.
+ */
+
+ while(*AnExampleString != 0)
+ {
+ /* Fail if any characters are different. This is comparing the
+ * addresses of both characters, not the characters themselves.
+ */
+
+ if(AnExampleString != &StringPointer[count])
+ {
+ Fail("ERROR: %#x and %#x are different. These should be the "
+ "same address.\n",AnExampleString,&StringPointer[count]);
+ }
+
+ AnExampleString = CharNextExA(0,AnExampleString,0);
+ ++count;
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/CharNextExA/test1/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/CharNextExA/test1/testinfo.dat
new file mode 100644
index 0000000000..ea36fa61e0
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/CharNextExA/test1/testinfo.dat
@@ -0,0 +1,16 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = CharNextA
+Name = Positive Test for CharNextExA
+TYPE = DEFAULT
+EXE1 = test
+Description
+= Test to see if CharNextExA works properly
+= when calling it repeatedly on a single string.
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/CharNextExA/test2/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/CharNextExA/test2/CMakeLists.txt
new file mode 100644
index 0000000000..556043abcd
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/CharNextExA/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.c
+)
+
+add_executable(paltest_charnextexa_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_charnextexa_test2 coreclrpal)
+
+target_link_libraries(paltest_charnextexa_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/CharNextExA/test2/test.c b/src/pal/tests/palsuite/miscellaneous/CharNextExA/test2/test.c
new file mode 100644
index 0000000000..ffc153f5e6
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/CharNextExA/test2/test.c
@@ -0,0 +1,66 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: test.c
+**
+** Purpose: Test for CharNextExA, ensures it returns an LPTSTR
+**
+**
+**=========================================================*/
+
+/* Depends on strcmp() */
+
+#include <palsuite.h>
+
+void testString(LPSTR input, LPSTR expected)
+{
+
+ LPTSTR pReturned = NULL;
+
+ pReturned = CharNextExA(0,input,0);
+
+ /* Compare the Returned String to what it should be */
+ if(strcmp(expected,pReturned) != 0)
+ {
+ Fail("ERROR: CharNextExA Failed: [%s] and [%s] are not equal, "
+ "they should be after calling CharNextExA.\n",
+ pReturned,expected);
+ }
+
+
+}
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /* test several Strings */
+ testString("this is the string", "his is the string");
+ testString("t", "");
+ testString("", "");
+ testString("a\t", "\t");
+ testString("a\a", "\a");
+ testString("a\b", "\b");
+ testString("a\"", "\"");
+ testString("a\\", "\\");
+ testString("\\", "");
+ testString("\f", "");
+ testString("\bx", "x");
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/CharNextExA/test2/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/CharNextExA/test2/testinfo.dat
new file mode 100644
index 0000000000..adc110769b
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/CharNextExA/test2/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = CharNextExA
+Name = Return Value test for CharNextExA
+TYPE = DEFAULT
+EXE1 = test
+Description
+= Test to ensure it returns an LPTSTR when called on a string
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/CloseHandle/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/CloseHandle/CMakeLists.txt
new file mode 100644
index 0000000000..ef14ea5352
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/CloseHandle/CMakeLists.txt
@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+
diff --git a/src/pal/tests/palsuite/miscellaneous/CloseHandle/test1/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/CloseHandle/test1/CMakeLists.txt
new file mode 100644
index 0000000000..bbe37ddd19
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/CloseHandle/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.c
+)
+
+add_executable(paltest_closehandle_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_closehandle_test1 coreclrpal)
+
+target_link_libraries(paltest_closehandle_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/CloseHandle/test1/test.c b/src/pal/tests/palsuite/miscellaneous/CloseHandle/test1/test.c
new file mode 100644
index 0000000000..8e42229c29
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/CloseHandle/test1/test.c
@@ -0,0 +1,64 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: test.c
+**
+** Purpose: Test for CloseHandle function
+**
+**
+**=========================================================*/
+
+/* Depends on: CreateFile and WriteFile */
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ HANDLE FileHandle = NULL;
+ LPDWORD WriteBuffer; /* Used with WriteFile */
+
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ WriteBuffer = malloc(sizeof(WORD));
+
+ if ( WriteBuffer == NULL )
+ {
+ Fail("ERROR: Failed to allocate memory for WriteBuffer pointer. "
+ "Can't properly exec test case without this.\n");
+ }
+
+
+ /* Create a file, since this returns to us a HANDLE we can use */
+ FileHandle = CreateFile("testfile",
+ GENERIC_READ | GENERIC_WRITE,0,NULL,CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ /* Should be able to close this handle */
+ if(CloseHandle(FileHandle) == 0)
+ {
+ free(WriteBuffer);
+ Fail("ERROR: (Test 1) Attempted to close a HANDLE on a file, but the "
+ "return value was <=0, indicating failure.\n");
+ }
+
+ free(WriteBuffer);
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/CloseHandle/test1/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/CloseHandle/test1/testinfo.dat
new file mode 100644
index 0000000000..891e1dfcfc
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/CloseHandle/test1/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = CloseHandle
+Name = Positive Test for CloseHandle
+TYPE = DEFAULT
+EXE1 = test
+Description
+= Open a file to get a handle, and then close the file using CloseHandle
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/CloseHandle/test2/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/CloseHandle/test2/CMakeLists.txt
new file mode 100644
index 0000000000..75de513be7
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/CloseHandle/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.c
+)
+
+add_executable(paltest_closehandle_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_closehandle_test2 coreclrpal)
+
+target_link_libraries(paltest_closehandle_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/CloseHandle/test2/test.c b/src/pal/tests/palsuite/miscellaneous/CloseHandle/test2/test.c
new file mode 100644
index 0000000000..c1eea44070
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/CloseHandle/test2/test.c
@@ -0,0 +1,46 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: test.c
+**
+** Purpose: Test for CloseHandle function, try to close an unopened HANDLE
+**
+**
+**=========================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ HANDLE SomeHandle = NULL;
+
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /* If the handle is already closed and you can close it again,
+ * something is wrong.
+ */
+
+ if(CloseHandle(SomeHandle) != 0)
+ {
+ Fail("ERROR: Called CloseHandle on an already closed Handle "
+ "and it still returned as a success.\n");
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/CloseHandle/test2/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/CloseHandle/test2/testinfo.dat
new file mode 100644
index 0000000000..6917e8586a
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/CloseHandle/test2/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = CloseHandle
+Name = Positive Test for CloseHandle
+TYPE = DEFAULT
+EXE1 = test
+Description
+= Attempt to close an unintialized HANDLE, should be unable to do this.
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/CreatePipe/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/CreatePipe/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/CreatePipe/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/miscellaneous/CreatePipe/test1/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/CreatePipe/test1/CMakeLists.txt
new file mode 100644
index 0000000000..af878cb873
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/CreatePipe/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_createpipe_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_createpipe_test1 coreclrpal)
+
+target_link_libraries(paltest_createpipe_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/CreatePipe/test1/test1.c b/src/pal/tests/palsuite/miscellaneous/CreatePipe/test1/test1.c
new file mode 100644
index 0000000000..3930183b60
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/CreatePipe/test1/test1.c
@@ -0,0 +1,113 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test1.c (CreatePipe)
+**
+** Purpose: Tests the PAL implementation of the CreatePipe function.
+** This test will create two pipes, a read and a write. Once
+** the pipes have been created, they will be tested by writing
+** and then reading, then comparing the results.
+**
+** Depends: WriteFile
+** ReadFile
+** memcmp
+** CloseHandle
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+const char* cTestString = "one fish, two fish, red fish, blue fish.";
+
+int __cdecl main(int argc, char **argv)
+{
+ HANDLE hReadPipe = NULL;
+ HANDLE hWritePipe = NULL;
+ BOOL bRetVal = FALSE;
+ DWORD dwBytesWritten;
+ DWORD dwBytesRead;
+ char buffer[256];
+
+ SECURITY_ATTRIBUTES lpPipeAttributes;
+
+ /*Initialize the PAL*/
+ if ((PAL_Initialize(argc, argv)) != 0)
+ {
+ return (FAIL);
+ }
+
+ /*Setup SECURITY_ATTRIBUTES structure for CreatePipe*/
+ lpPipeAttributes.nLength = sizeof(lpPipeAttributes);
+ lpPipeAttributes.lpSecurityDescriptor = NULL;
+ lpPipeAttributes.bInheritHandle = TRUE;
+
+ /*Create a Pipe*/
+ bRetVal = CreatePipe(&hReadPipe, /* read handle*/
+ &hWritePipe, /* write handle */
+ &lpPipeAttributes, /* security attributes*/
+ 0); /* pipe size*/
+ if (bRetVal == FALSE)
+ {
+ Fail("ERROR: %ld :Unable to create pipe\n", GetLastError());
+ }
+
+ /*Write to the write pipe handle*/
+ bRetVal = WriteFile(hWritePipe, /* handle to write pipe*/
+ cTestString, /* buffer to write*/
+ strlen(cTestString),/* number of bytes to write*/
+ &dwBytesWritten, /* number of bytes written*/
+ NULL); /* overlapped buffer*/
+ if (bRetVal == FALSE)
+ {
+ Fail("ERROR: %ld :unable to write to write pipe handle "
+ "hWritePipe=0x%lx\n", GetLastError(), hWritePipe);
+ }
+
+ /*Read, 256 bytes, more bytes then actually written.
+ This will give allow us to use the value that ReadFile
+ returns for comparision.*/
+ bRetVal = ReadFile(hReadPipe, /* handle to read pipe*/
+ buffer, /* buffer to write to*/
+ 256, /* number of bytes to read*/
+ &dwBytesRead, /* number of bytes read*/
+ NULL); /* overlapped buffer*/
+ if (bRetVal == FALSE)
+ {
+ Fail("ERROR: %ld : unable read hWritePipe=0x%lx\n",
+ GetLastError(), hWritePipe);
+ }
+
+ /*Compare what was read with what was written.*/
+ if ((memcmp(cTestString, buffer, dwBytesRead)) != 0)
+ {
+ Fail("ERROR: read \"%s\" expected \"%s\" \n", buffer, cTestString);
+ }
+
+ /*Compare values returned from WriteFile and ReadFile.*/
+ if (dwBytesWritten != dwBytesRead)
+ {
+ Fail("ERROR: WriteFile wrote \"%d\", but ReadFile read \"%d\","
+ " these should be the same\n", buffer, cTestString);
+ }
+
+ /*Close write pipe handle*/
+ if (CloseHandle(hWritePipe) == 0)
+ {
+ Fail("ERROR: %ld : Unable to close write pipe handle "
+ "hWritePipe=0x%lx\n",GetLastError(), hWritePipe);
+ }
+
+ /*Close Read pipe handle*/
+ if (CloseHandle(hReadPipe) == 0)
+ {
+ Fail("ERROR: %ld : Unable to close read pipe handle "
+ "hReadPipe=0x%lx\n", GetLastError(), hReadPipe);
+ }
+
+ PAL_Terminate();
+ return (PASS);
+}
diff --git a/src/pal/tests/palsuite/miscellaneous/CreatePipe/test1/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/CreatePipe/test1/testinfo.dat
new file mode 100644
index 0000000000..b9422b0627
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/CreatePipe/test1/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = CreatePipe
+Name = Test for CreatePipe
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Tests the PAL implementation of the CreatePipe function.
+= This test will create two pipes, a read and a write. Once
+= the pipes have been created, they will be tested by writing
+= and then reading, then comparing the results.
diff --git a/src/pal/tests/palsuite/miscellaneous/FlushInstructionCache/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/FlushInstructionCache/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/FlushInstructionCache/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/miscellaneous/FlushInstructionCache/test1/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/FlushInstructionCache/test1/CMakeLists.txt
new file mode 100644
index 0000000000..fbd8b0f87d
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/FlushInstructionCache/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_flushinstructioncache_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_flushinstructioncache_test1 coreclrpal)
+
+target_link_libraries(paltest_flushinstructioncache_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/FlushInstructionCache/test1/test1.c b/src/pal/tests/palsuite/miscellaneous/FlushInstructionCache/test1/test1.c
new file mode 100644
index 0000000000..cdbefd01cc
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/FlushInstructionCache/test1/test1.c
@@ -0,0 +1,66 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: test1.c
+**
+** Purpose: Tests that FlushInstructionCache returns the correct value for a
+** number of different inputs.
+**
+**
+** Note :
+** For this function, what constitutes "invalid parameters" will depend entirely
+** on the platform; because of this we can't simply test values on Windows and
+** then ask for the same results everywhere. Because of this, this test can
+** ensure that the function succeeds for some "obviously" valid values, but
+** can't make sure that it fails for invalid values.
+**
+**=========================================================*/
+
+#include <palsuite.h>
+
+void DoTest(void *Buffer, int Size, int Expected)
+{
+ int ret;
+
+ SetLastError(0);
+ ret = FlushInstructionCache(GetCurrentProcess(), Buffer, Size);
+ if (!ret && Expected)
+ {
+ Fail("Expected FlushInstructionCache to return non-zero, got zero!\n"
+ "region: %p, size: %d, GetLastError: %d\n", Buffer, Size,
+ GetLastError());
+ }
+ else if (ret && !Expected)
+ {
+ Fail("Expected FlushInstructionCache to return zero, got non-zero!\n"
+ "region: %p, size: %d, GetLastError: %d\n", Buffer, Size,
+ GetLastError());
+ }
+
+ if (!Expected && ERROR_NOACCESS != GetLastError())
+ {
+ Fail("FlushInstructionCache failed to set the last error to "
+ "ERROR_NOACCESS!\n");
+ }
+
+}
+
+int __cdecl main(int argc,char *argv[])
+{
+ char ValidPtr[256];
+
+ if(PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ /* with valid pointer, zero-size and valid size must succeed */
+ DoTest(ValidPtr, 0, 1);
+ DoTest(ValidPtr, 42, 1);
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/miscellaneous/FlushInstructionCache/test1/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/FlushInstructionCache/test1/testinfo.dat
new file mode 100644
index 0000000000..78ab5f77ff
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/FlushInstructionCache/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = FlushInstructionCache
+Name = Positive Test #1 for FlushInstructionCache
+TYPE = DEFAULT
+EXE1 = test1
+Description
+=Tests that FlushInstructionCache returns the correct value for a
+=number of different inputs.
diff --git a/src/pal/tests/palsuite/miscellaneous/FormatMessageW/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/FormatMessageW/CMakeLists.txt
new file mode 100644
index 0000000000..7c20179353
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/FormatMessageW/CMakeLists.txt
@@ -0,0 +1,9 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+add_subdirectory(test3)
+add_subdirectory(test4)
+add_subdirectory(test5)
+add_subdirectory(test6)
+
diff --git a/src/pal/tests/palsuite/miscellaneous/FormatMessageW/test1/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/FormatMessageW/test1/CMakeLists.txt
new file mode 100644
index 0000000000..0f242e9b30
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/FormatMessageW/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.c
+)
+
+add_executable(paltest_formatmessagew_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_formatmessagew_test1 coreclrpal)
+
+target_link_libraries(paltest_formatmessagew_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/FormatMessageW/test1/test.c b/src/pal/tests/palsuite/miscellaneous/FormatMessageW/test1/test.c
new file mode 100644
index 0000000000..0cc4c43432
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/FormatMessageW/test1/test.c
@@ -0,0 +1,63 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source : test.c
+**
+** Purpose: Test for FormatMessageW() function
+**
+**
+**=========================================================*/
+
+#define UNICODE
+#include <palsuite.h>
+
+
+int __cdecl main(int argc, char *argv[]) {
+
+ WCHAR TheString[] = {'P','a','l',' ','T','e','s','t','\0'};
+ WCHAR OutBuffer[128];
+ int ReturnResult;
+
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+
+ ReturnResult = FormatMessage(
+ FORMAT_MESSAGE_FROM_STRING, /* source and processing options */
+ TheString, /* message source */
+ 0, /* message identifier */
+ 0, /* language identifier */
+ OutBuffer, /* message buffer */
+ 1024, /* maximum size of message buffer */
+ NULL /* array of message inserts */
+ );
+
+
+ if(ReturnResult == 0)
+ {
+ Fail("ERROR: The return value was 0, which indicates failure. "
+ "The function failed when trying to Format a simple string"
+ ", with no formatters in it.");
+ }
+
+ if(memcmp(OutBuffer,TheString,wcslen(OutBuffer)*2+2) != 0)
+ {
+ Fail("ERROR: The formatted string should be %s but is really %s.",
+ convertC(TheString),
+ convertC(OutBuffer));
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/FormatMessageW/test1/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/FormatMessageW/test1/testinfo.dat
new file mode 100644
index 0000000000..5bd46bf604
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/FormatMessageW/test1/testinfo.dat
@@ -0,0 +1,16 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = FormatMessageW
+Name = Positive test of FormatMessageW
+TYPE = DEFAULT
+EXE1 = test
+Description
+= Test a very simple case -- basically just copy a string into a buffer,
+= no formatting.
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/FormatMessageW/test2/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/FormatMessageW/test2/CMakeLists.txt
new file mode 100644
index 0000000000..26092ac300
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/FormatMessageW/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.c
+)
+
+add_executable(paltest_formatmessagew_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_formatmessagew_test2 coreclrpal)
+
+target_link_libraries(paltest_formatmessagew_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/FormatMessageW/test2/test.c b/src/pal/tests/palsuite/miscellaneous/FormatMessageW/test2/test.c
new file mode 100644
index 0000000000..6c2d80b3f4
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/FormatMessageW/test2/test.c
@@ -0,0 +1,581 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source : test.c
+**
+** Purpose: Test for FormatMessageW() function
+**
+**
+**=========================================================*/
+
+#define UNICODE
+#include <palsuite.h>
+
+WCHAR OutBuffer[1024];
+
+/* Pass this test the string "INSERT" and it will succeed */
+
+int test1(int num, ...)
+{
+
+ WCHAR * TheString = convert("Pal %1!s! Testing");
+ int ReturnResult;
+ va_list TheList;
+ va_start(TheList,num);
+ memset( OutBuffer, 0, 1024 );
+
+ ReturnResult = FormatMessage(
+ FORMAT_MESSAGE_FROM_STRING, /* source and processing options */
+ TheString, /* message source */
+ 0, /* message identifier */
+ 0, /* language identifier */
+ OutBuffer, /* message buffer */
+ 1024, /* maximum size of message buffer */
+ &TheList /* array of message inserts */
+ );
+
+ va_end(TheList);
+
+ if(ReturnResult == 0)
+ {
+ Fail("ERROR: The return value was 0, which indicates failure. "
+ "The function failed when trying to Format a simple string,"
+ " with the 's' formatter.");
+
+ }
+
+ if(memcmp(OutBuffer, convert("Pal INSERT Testing"),
+ wcslen(OutBuffer)*2+2) != 0)
+ {
+ Fail("ERROR: The formated string should have been 'Pal INSERT "
+ "Testing' but '%s' was returned.",
+ convertC(OutBuffer));
+ }
+
+
+ return PASS;
+}
+
+/* Pass this test the int 40 and it will succeed */
+
+int test2(int num, ...)
+{
+
+ WCHAR * TheString = convert("Pal %1!i! Testing");
+ int ReturnResult;
+ va_list TheList;
+ va_start(TheList,num);
+
+ memset( OutBuffer, 0, 1024 );
+
+ ReturnResult = FormatMessage(
+ FORMAT_MESSAGE_FROM_STRING, /* source and processing options */
+ TheString, /* message source */
+ 0, /* message identifier */
+ 0, /* language identifier */
+ OutBuffer, /* message buffer */
+ 1024, /* maximum size of message buffer */
+ &TheList /* array of message inserts */
+ );
+
+ va_end(TheList);
+
+ if(ReturnResult == 0)
+ {
+ Fail("ERROR: The return value was 0, which indicates failure. "
+ "The function failed when trying to Format a simple string,"
+ " with the 'i' formatter.");
+ }
+
+ if(memcmp(OutBuffer, convert("Pal 40 Testing"),wcslen(OutBuffer)*2+2) != 0)
+ {
+ Fail("ERROR: The formated string should have been 'Pal 40 Testing' "
+ "but '%s' was returned.", convertC(OutBuffer));
+ }
+ return PASS;
+}
+
+/* Pass this test the character 'a' and it will succeed */
+
+int test3(int num, ...) {
+
+ WCHAR * TheString = convert("Pal %1!c! Testing");
+ int ReturnResult;
+ va_list TheList;
+ va_start(TheList,num);
+ memset( OutBuffer, 0, 1024 );
+ ReturnResult = FormatMessage(
+ FORMAT_MESSAGE_FROM_STRING, /* source and processing options */
+ TheString, /* message source */
+ 0, /* message identifier */
+ 0, /* language identifier */
+ OutBuffer, /* message buffer */
+ 1024, /* maximum size of message buffer */
+ &TheList /* array of message inserts */
+ );
+
+ va_end(TheList);
+
+ if(ReturnResult == 0)
+ {
+ Fail("ERROR: The return value was 0, which indicates failure. "
+ "The function failed when trying to Format a simple string,"
+ " with the 'c' formatter.");
+ }
+
+ if(memcmp(OutBuffer, convert("Pal a Testing"),wcslen(OutBuffer)*2+2) != 0)
+ {
+ Fail("ERROR: The formated string should have been 'Pal a Testing' "
+ "but '%s' was returned.", convertC(OutBuffer));
+
+ }
+
+ return PASS;
+}
+
+/* Pass this test the character 'a' and it will succeed */
+
+int test4(int num, ...) {
+
+ WCHAR * TheString = convert("Pal %1!C! Testing");
+ int ReturnResult;
+ va_list TheList;
+ va_start(TheList,num);
+ memset( OutBuffer, 0, 1024 );
+ ReturnResult = FormatMessage(
+ FORMAT_MESSAGE_FROM_STRING, /* source and processing options */
+ TheString, /* message source */
+ 0, /* message identifier */
+ 0, /* language identifier */
+ OutBuffer, /* message buffer */
+ 1024, /* maximum size of message buffer */
+ &TheList /* array of message inserts */
+ );
+
+ va_end(TheList);
+
+ if(ReturnResult == 0)
+ {
+ Fail("ERROR: The return value was 0, which indicates failure. "
+ "The function failed when trying to Format a simple string,"
+ " with the 'C' formatter.");
+ }
+
+ if(memcmp(OutBuffer, convert("Pal a Testing"),wcslen(OutBuffer)*2+2) != 0)
+ {
+ Fail("ERROR: The formated string should have been 'Pal a Testing' "
+ "but '%s' was returned.",convertC(OutBuffer));
+ }
+
+ return PASS;
+}
+
+/* Pass this test the number 57 and it will succeed */
+
+int test5(int num, ...)
+{
+
+ WCHAR * TheString = convert("Pal %1!d! Testing");
+ int ReturnResult;
+ va_list TheList;
+ va_start(TheList,num);
+ memset( OutBuffer, 0, 1024 );
+
+ ReturnResult = FormatMessage(
+ FORMAT_MESSAGE_FROM_STRING, /* source and processing options */
+ TheString, /* message source */
+ 0, /* message identifier */
+ 0, /* language identifier */
+ OutBuffer, /* message buffer */
+ 1024, /* maximum size of message buffer */
+ &TheList /* array of message inserts */
+ );
+
+ va_end(TheList);
+
+ if(ReturnResult == 0)
+ {
+ Fail("ERROR: The return value was 0, which indicates failure. "
+ "The function failed when trying to Format a simple string, "
+ "with the 'd' formatter.");
+
+ }
+
+ if(memcmp(OutBuffer, convert("Pal 57 Testing"),wcslen(OutBuffer)*2+2) != 0)
+ {
+ Fail("ERROR: The formated string should have been 'Pal 57 Testing' "
+ "but '%s' was returned.",convertC(OutBuffer));
+
+ }
+
+ return PASS;
+}
+
+/* Pass this test the characters 'a' and 'b' and it will succeed. */
+
+int test6(int num, ...) {
+
+ WCHAR * TheString = convert("Pal %1!hc! and %2!hC! Testing");
+ int ReturnResult;
+ va_list TheList;
+ va_start(TheList,num);
+ memset( OutBuffer, 0, 1024 );
+
+ ReturnResult = FormatMessage(
+ FORMAT_MESSAGE_FROM_STRING, /* source and processing options */
+ TheString, /* message source */
+ 0, /* message identifier */
+ 0, /* language identifier */
+ OutBuffer, /* message buffer */
+ 1024, /* maximum size of message buffer */
+ &TheList /* array of message inserts */
+ );
+
+ va_end(TheList);
+
+ if(ReturnResult == 0)
+ {
+ Fail("ERROR: The return value was 0, which indicates failure. "
+ "The function failed when trying to Format a simple string, "
+ "with the 'hc' and 'hC' formatters.");
+
+ }
+
+ if(memcmp(OutBuffer, convert("Pal a and b Testing"),
+ wcslen(OutBuffer)*2+2) != 0)
+ {
+ Fail("ERROR: The formated string should have been 'Pal a and b "
+ "Testing' but '%s' was returned.", convertC(OutBuffer));
+
+ }
+
+ return PASS;
+}
+
+/* Pass this test 90, the string 'foo' and the string 'bar' to succeed */
+
+int test7(int num, ...)
+{
+
+ WCHAR * TheString = convert("Pal %1!hd! and %2!hs! and %3!hS! Testing");
+ int ReturnResult;
+ va_list TheList;
+ va_start(TheList,num);
+ memset( OutBuffer, 0, 1024 );
+
+ ReturnResult = FormatMessage(
+ FORMAT_MESSAGE_FROM_STRING, /* source and processing options */
+ TheString, /* message source */
+ 0, /* message identifier */
+ 0, /* language identifier */
+ OutBuffer, /* message buffer */
+ 1024, /* maximum size of message buffer */
+ &TheList /* array of message inserts */
+ );
+
+ va_end(TheList);
+
+ if(ReturnResult == 0)
+ {
+ Fail("ERROR: The return value was 0, which indicates failure. "
+ "The function failed when trying to Format a simple string, "
+ "with the 'hd', 'hs' and 'hS' formatters.");
+
+ }
+
+ if(memcmp(OutBuffer,
+ convert("Pal 90 and foo and bar Testing"),
+ wcslen(OutBuffer)*2+2) != 0)
+ {
+ Fail("ERROR: The formated string should have been 'Pal 90 and foo "
+ "and bar Testing' but '%s' was returned.",convertC(OutBuffer));
+ }
+
+ return PASS;
+}
+
+/* Pass this test the characters 'a', 'b' and the numbers 50 and 100 */
+
+int test8(int num, ...)
+{
+
+ WCHAR * TheString =
+ convert("Pal %1!lc! and %2!lC! and %3!ld! and %4!li! Testing");
+ int ReturnResult;
+ va_list TheList;
+ va_start(TheList,num);
+ memset( OutBuffer, 0, 1024 );
+
+ ReturnResult = FormatMessage(
+ FORMAT_MESSAGE_FROM_STRING, /* source and processing options */
+ TheString, /* message source */
+ 0, /* message identifier */
+ 0, /* language identifier */
+ OutBuffer, /* message buffer */
+ 1024, /* maximum size of message buffer */
+ &TheList /* array of message inserts */
+ );
+
+ va_end(TheList);
+
+ if(ReturnResult == 0)
+ {
+ Fail("ERROR: The return value was 0, which indicates failure. "
+ "The function failed when trying to Format a simple string, "
+ "with the 'lc', 'lC', 'ld' and 'li' formatters.");
+
+ }
+
+ if(memcmp(OutBuffer,
+ convert("Pal a and b and 50 and 100 Testing"),
+ wcslen(OutBuffer)*2+2) != 0)
+ {
+ Fail("ERROR: The formated string should have been 'Pal a and b and 50"
+ " and 100 Testing' but '%s' was returned.",convertC(OutBuffer));
+
+ }
+
+ return PASS;
+}
+
+/* Pass this test the wide string 'foo' and 'bar' and the unsigned
+ int 56 to pass
+*/
+
+int test9(int num, ...) {
+
+ WCHAR * TheString = convert("Pal %1!ls! and %2!ls! and %3!lu! Testing");
+ int ReturnResult;
+ va_list TheList;
+ va_start(TheList,num);
+ memset( OutBuffer, 0, 1024 );
+ ReturnResult = FormatMessage(
+ FORMAT_MESSAGE_FROM_STRING, /* source and processing options */
+ TheString, /* message source */
+ 0, /* message identifier */
+ 0, /* language identifier */
+ OutBuffer, /* message buffer */
+ 1024, /* maximum size of message buffer */
+ &TheList /* array of message inserts */
+ );
+
+ va_end(TheList);
+
+ if(ReturnResult == 0)
+ {
+ Fail("ERROR: The return value was 0, which indicates failure. "
+ "The function failed when trying to Format a simple string,"
+ " with the 'ls', 'lS' and 'lu' formatters.");
+
+ }
+
+ if(memcmp(OutBuffer,
+ convert("Pal foo and bar and 56 Testing"),
+ wcslen(OutBuffer)*2+2) != 0)
+ {
+ Fail("ERROR: The formated string should have been 'Pal foo and bar "
+ "and 56 Testing' but '%s' was returned.",convertC(OutBuffer));
+
+ }
+
+ return PASS;
+}
+
+/* Pass this test the hex values 0x123ab and 0x123cd */
+
+int test10(int num, ...)
+{
+
+ WCHAR * TheString = convert("Pal %1!lx! and %2!lX! Testing");
+ int ReturnResult;
+ va_list TheList;
+ va_start(TheList,num);
+ memset( OutBuffer, 0, 1024 );
+ ReturnResult = FormatMessage(
+ FORMAT_MESSAGE_FROM_STRING, /* source and processing options */
+ TheString, /* message source */
+ 0, /* message identifier */
+ 0, /* language identifier */
+ OutBuffer, /* message buffer */
+ 1024, /* maximum size of message buffer */
+ &TheList /* array of message inserts */
+ );
+
+ va_end(TheList);
+
+ if(ReturnResult == 0)
+ {
+ Fail("ERROR: The return value was 0, which indicates failure. "
+ "The function failed when trying to Format a simple string, "
+ "with the 'lx' and 'lX' formatters.");
+
+ }
+
+ if(memcmp(OutBuffer,
+ convert("Pal 123ab and 123CD Testing"),
+ wcslen(OutBuffer)*2+2) != 0)
+ {
+ Fail("ERROR: The formated string should have been 'Pal 123ab and "
+ "123CD Testing' but '%s' was returned.", convertC(OutBuffer));
+
+ }
+
+ return PASS;
+}
+
+/* Pass this test a pointer to 0x123ab and the string 'foo' to pass */
+
+int test11(int num, ...)
+{
+
+ WCHAR * TheString = convert("Pal %1!p! and %2!S! Testing");
+ int ReturnResult;
+ va_list TheList;
+ va_start(TheList,num);
+ memset( OutBuffer, 0, 1024 );
+
+ ReturnResult = FormatMessage(
+ FORMAT_MESSAGE_FROM_STRING, /* source and processing options */
+ TheString, /* message source */
+ 0, /* message identifier */
+ 0, /* language identifier */
+ OutBuffer, /* message buffer */
+ 1024, /* maximum size of message buffer */
+ &TheList /* array of message inserts */
+ );
+
+ va_end(TheList);
+
+ if(ReturnResult == 0)
+ {
+ Fail("ERROR: The return value was 0, which indicates failure. "
+ "The function failed when trying to Format a simple string, "
+ "with the 'p' and 'S' formatters.");
+
+ }
+
+/*
+** Run only on 64 bit platforms
+*/
+#if defined(BIT64) && defined(PLATFORM_UNIX)
+ Trace("Testing for 64 Bit Platforms \n");
+ if(memcmp(OutBuffer,
+ convert("Pal 00000000000123AB and foo Testing"),
+ wcslen(OutBuffer)*2+2) != 0 &&
+ /* BSD style */
+ memcmp( OutBuffer,
+ convert( "Pal 0x123ab and foo Testing" ),
+ wcslen(OutBuffer)*2+2 ) != 0 )
+ {
+ Fail("ERROR: The formated string should have been 'Pal 000123AB and "
+ "foo Testing' but '%s' was returned.",convertC(OutBuffer));
+
+ }
+
+#else
+ Trace("Testing for Non 64 Bit Platforms \n");
+ if(memcmp(OutBuffer,
+ convert("Pal 000123AB and foo Testing"),
+ wcslen(OutBuffer)*2+2) != 0 &&
+ /* BSD style */
+ memcmp( OutBuffer,
+ convert( "Pal 0x123ab and foo Testing" ),
+ wcslen(OutBuffer)*2+2 ) != 0 )
+ {
+ Fail("ERROR: The formated string should have been 'Pal 000123AB and "
+ "foo Testing' but '%s' was returned.",convertC(OutBuffer));
+
+ }
+
+#endif
+
+ return PASS;
+}
+
+/* Pass this test the unsigned int 100 and the hex values 0x123ab and 0x123cd
+to succeed */
+
+int test12(int num, ...)
+{
+
+ WCHAR * TheString = convert("Pal %1!u! and %2!x! and %3!X! Testing");
+ int ReturnResult;
+ va_list TheList;
+ va_start(TheList,num);
+ memset( OutBuffer, 0, 1024 );
+
+ ReturnResult = FormatMessage(
+ FORMAT_MESSAGE_FROM_STRING, /* source and processing options */
+ TheString, /* message source */
+ 0, /* message identifier */
+ 0, /* language identifier */
+ OutBuffer, /* message buffer */
+ 1024, /* maximum size of message buffer */
+ &TheList /* array of message inserts */
+ );
+
+ va_end(TheList);
+
+ if(ReturnResult == 0)
+ {
+ Fail("ERROR: The return value was 0, which indicates failure. "
+ "The function failed when trying to Format a simple string, "
+ "with the 'u', 'x' and 'X' formatters.");
+
+ }
+
+ if(memcmp(OutBuffer,
+ convert("Pal 100 and 123ab and 123CD Testing"),
+ wcslen(OutBuffer)*2+2) != 0)
+ {
+ Fail("ERROR: The formated string should have been 'Pal 100 and "
+ "123ab and 123CD Testing' but '%s' was returned.",
+ convertC(OutBuffer));
+
+ }
+
+ return PASS;
+}
+
+int __cdecl main(int argc, char *argv[])
+{
+ WCHAR szwInsert[] = {'I','N','S','E','R','T','\0'};
+ WCHAR szwFoo[] = {'f','o','o','\0'};
+ WCHAR szwBar[] = {'b','a','r','\0'};
+
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ if(test1(0,szwInsert) || /* Test %s */
+ test2(0,40) || /* Test %i */
+ test3(0,'a') || /* Test %c */
+ test4(0,'a') || /* Test %C */
+ test5(0,57) || /* Test %d */
+ test6(0,'a','b') || /* Test %hc, %hC */
+ test7(0,90,"foo","bar") || /* Test %hd,hs,hS */
+ test8(0,'a','b',50,100) || /* Test %lc, lC, ld, li */
+ test9(0,szwFoo,szwBar,56) || /* Test %ls,lS,lu */
+ test10(0,0x123ab,0x123cd) || /* Test %lx, %lX */
+ test11(0,(void *)0x123ab,"foo") || /* Test %p, %S */
+ test12(0,100,0x123ab,0x123cd)) /* Test %u,x,X */
+ {
+
+
+ }
+
+ PAL_Terminate();
+ return PASS;
+
+}
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/FormatMessageW/test2/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/FormatMessageW/test2/testinfo.dat
new file mode 100644
index 0000000000..5e4a35428e
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/FormatMessageW/test2/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = FormatMessageW
+Name = Positive test of FormatMessageW
+TYPE = DEFAULT
+EXE1 = test
+Description
+= A collection of tests to check and make sure all the standard formatters work.
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/FormatMessageW/test3/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/FormatMessageW/test3/CMakeLists.txt
new file mode 100644
index 0000000000..b430511c4c
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/FormatMessageW/test3/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.c
+)
+
+add_executable(paltest_formatmessagew_test3
+ ${SOURCES}
+)
+
+add_dependencies(paltest_formatmessagew_test3 coreclrpal)
+
+target_link_libraries(paltest_formatmessagew_test3
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/FormatMessageW/test3/test.c b/src/pal/tests/palsuite/miscellaneous/FormatMessageW/test3/test.c
new file mode 100644
index 0000000000..a390c00fea
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/FormatMessageW/test3/test.c
@@ -0,0 +1,85 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source : test.c
+**
+** Purpose: Test for FormatMessageW() function
+**
+**
+**=========================================================*/
+
+#define UNICODE
+#include <palsuite.h>
+
+WCHAR OutBuffer[1024];
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ WCHAR * TheString;
+ WCHAR * CorrectString;
+ int ReturnResult;
+
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ TheString = convert("Pal %1!u! %2!i! %3!s! Testing");
+
+ /* The resulting value in the buffer shouldn't be formatted at all,
+ because the inserts are being ignored.
+ */
+
+ ReturnResult = FormatMessage(
+ FORMAT_MESSAGE_FROM_STRING |
+ FORMAT_MESSAGE_IGNORE_INSERTS, /* source and processing options */
+ TheString, /* message source */
+ 0, /* message identifier */
+ 0, /* language identifier */
+ OutBuffer, /* message buffer */
+ 1024, /* maximum size of message buffer */
+ NULL /* array of message inserts */
+ );
+
+
+
+ if(ReturnResult == 0)
+ {
+ free(TheString);
+ Fail("ERROR: The return value was 0, which indicates failure. "
+ "The function failed when trying to Format a simple string, "
+ "using the IGNORE_INSERTS flag.\n");
+ }
+
+
+ /* Note: Since 's' is the default insert, when this function is called
+ with ignore inserts, it strips %3!s! down to just %3 -- as they're
+ equal.
+ */
+ if(memcmp(OutBuffer,
+ (CorrectString = convert("Pal %1!u! %2!i! %3 Testing")),
+ wcslen(OutBuffer)*2+2) != 0)
+ {
+ free(TheString);
+ free(CorrectString);
+ Fail("ERROR: Since the IGNORE_INSERTS flag was set, the result "
+ "should have been 'Pal %%1!u! %%2!i! %%3 Testing' but was "
+ "really '%S'.\n",OutBuffer);
+ }
+
+ free(TheString);
+ free(CorrectString);
+ PAL_Terminate();
+ return PASS;
+
+}
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/FormatMessageW/test3/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/FormatMessageW/test3/testinfo.dat
new file mode 100644
index 0000000000..cad1f63817
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/FormatMessageW/test3/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = FormatMessageW
+Name = Positive test of FormatMessageW
+TYPE = DEFAULT
+EXE1 = test
+Description
+= Test to ensure the IGNORE_INSERTS flag works properly.
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/FormatMessageW/test4/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/FormatMessageW/test4/CMakeLists.txt
new file mode 100644
index 0000000000..cae8ff149c
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/FormatMessageW/test4/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.c
+)
+
+add_executable(paltest_formatmessagew_test4
+ ${SOURCES}
+)
+
+add_dependencies(paltest_formatmessagew_test4 coreclrpal)
+
+target_link_libraries(paltest_formatmessagew_test4
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/FormatMessageW/test4/test.c b/src/pal/tests/palsuite/miscellaneous/FormatMessageW/test4/test.c
new file mode 100644
index 0000000000..4f865efe7e
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/FormatMessageW/test4/test.c
@@ -0,0 +1,77 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source : test.c
+**
+** Purpose: Test for FormatMessageW() function
+**
+**
+**=========================================================*/
+
+#define UNICODE
+#include <palsuite.h>
+
+WCHAR OutBuffer[1024];
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ WCHAR * TheString;
+ WCHAR* TheArray[3];
+ int ReturnResult;
+
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ TheString = convert("Pal %1 %2 %3 Testing");
+ TheArray[0] = convert("Foo");
+ TheArray[1] = convert("Bar");
+ TheArray[2] = convert("FooBar");
+
+ /* This should just use the 3 strings in the array to replace
+ inserts in the given string.
+ */
+
+ ReturnResult = FormatMessage(
+ FORMAT_MESSAGE_FROM_STRING |
+ FORMAT_MESSAGE_ARGUMENT_ARRAY, /* source and processing options */
+ TheString, /* message source */
+ 0, /* message identifier */
+ 0, /* language identifier */
+ OutBuffer, /* message buffer */
+ 1024, /* maximum size of message buffer */
+ (va_list *) TheArray /* array of message inserts */
+ );
+
+ if(ReturnResult == 0)
+ {
+ Fail("ERROR: The return value was 0, which indicates failure. "
+ "The function failed when trying to Format a simple string, "
+ "usin gthe ARGUMENT_ARRAY flag.");
+ }
+
+ if(memcmp(OutBuffer,
+ convert("Pal Foo Bar FooBar Testing"),
+ wcslen(OutBuffer)*2+2) != 0)
+ {
+ Fail("ERROR: Since the FORMAT_MESSAGE_ARGUMENT_ARRAY flag was set, "
+ "the result should have been 'Pal Foo Bar FooBar Testing' but was"
+ " really '%s'.",convertC(OutBuffer));
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+
+}
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/FormatMessageW/test4/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/FormatMessageW/test4/testinfo.dat
new file mode 100644
index 0000000000..33e0cfa827
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/FormatMessageW/test4/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = FormatMessageW
+Name = Positive test of FormatMessageW
+TYPE = DEFAULT
+EXE1 = test
+Description
+= Test to ensure the FORMAT_MESSAGE_ARGUMENT_ARRAY flag works properly.
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/FormatMessageW/test5/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/FormatMessageW/test5/CMakeLists.txt
new file mode 100644
index 0000000000..6779f94ff9
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/FormatMessageW/test5/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.c
+)
+
+add_executable(paltest_formatmessagew_test5
+ ${SOURCES}
+)
+
+add_dependencies(paltest_formatmessagew_test5 coreclrpal)
+
+target_link_libraries(paltest_formatmessagew_test5
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/FormatMessageW/test5/test.c b/src/pal/tests/palsuite/miscellaneous/FormatMessageW/test5/test.c
new file mode 100644
index 0000000000..148c2ff236
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/FormatMessageW/test5/test.c
@@ -0,0 +1,76 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source : test.c
+**
+** Purpose: Test for FormatMessageW() function
+**
+**
+**=========================================================*/
+
+
+#define UNICODE
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[]) {
+
+ WCHAR * TheString;
+ LPWSTR OutBuffer;
+ WCHAR* TheArray[3];
+ int ReturnResult;
+
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ TheString = convert("Pal %1 %2 %3 Testing");
+ TheArray[0] = convert("Foo");
+ TheArray[1] = convert("Bar");
+ TheArray[2] = convert("FooBar");
+
+ /* OutBuffer will be allocated in the function, if the flag
+ is working properly.
+ */
+
+ ReturnResult = FormatMessage(
+ FORMAT_MESSAGE_FROM_STRING |
+ FORMAT_MESSAGE_ARGUMENT_ARRAY |
+ FORMAT_MESSAGE_ALLOCATE_BUFFER, /* source and processing options */
+ TheString, /* message source */
+ 0, /* message identifier */
+ 0, /* language identifier */
+ (LPWSTR)&OutBuffer, /* message buffer */
+ 0, /* maximum size of message buffer */
+ (va_list *) TheArray /* array of message inserts */
+ );
+
+ if(ReturnResult == 0)
+ {
+ Fail("ERROR: The return value was 0, which indicates failure. "
+ "The function failed when trying to Format a simple string, "
+ "using the ALLOCATE_BUFFER flag.");
+ }
+
+ if(memcmp(OutBuffer,
+ convert("Pal Foo Bar FooBar Testing"),
+ wcslen(OutBuffer)*2+2) != 0)
+ {
+ Fail("ERROR: Since the FORMAT_MESSAGE_ALLOCATE_BUFFER flag was set, "
+ "the result should have been 'Pal Foo Bar FooBar Testing' but "
+ "was really '%s'.",convertC(OutBuffer));
+ }
+
+ PAL_Terminate();
+ return PASS;
+
+}
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/FormatMessageW/test5/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/FormatMessageW/test5/testinfo.dat
new file mode 100644
index 0000000000..6f497c23cc
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/FormatMessageW/test5/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = FormatMessageW
+Name = Positive test of FormatMessageW
+TYPE = DEFAULT
+EXE1 = test
+Description
+= Test to ensure the FORMAT_MESSAGE_ALLOCATE_BUFFER flag works properly.
diff --git a/src/pal/tests/palsuite/miscellaneous/FormatMessageW/test6/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/FormatMessageW/test6/CMakeLists.txt
new file mode 100644
index 0000000000..450b2b808b
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/FormatMessageW/test6/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.c
+)
+
+add_executable(paltest_formatmessagew_test6
+ ${SOURCES}
+)
+
+add_dependencies(paltest_formatmessagew_test6 coreclrpal)
+
+target_link_libraries(paltest_formatmessagew_test6
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/FormatMessageW/test6/test.c b/src/pal/tests/palsuite/miscellaneous/FormatMessageW/test6/test.c
new file mode 100644
index 0000000000..48f5e3e93d
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/FormatMessageW/test6/test.c
@@ -0,0 +1,78 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source : test.c
+**
+** Purpose: Test for FormatMessageW() function
+**
+**
+**=========================================================*/
+
+
+#define UNICODE
+#include <palsuite.h>
+
+
+int __cdecl main(int argc, char *argv[]) {
+
+
+ LPWSTR OutBuffer;
+ int ReturnResult;
+
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+
+ /* This is testing the use of FROM_SYSTEM. We can't check to ensure
+ the error message it extracts is correct, only that it does place some
+ information into the buffer when it is called.
+ */
+
+ /*
+
+ ERROR_SUCCESS (0L) is normally returned by GetLastError,
+ But, the ERROR_SUCCESS is removed from messages for Unix based Systems
+ To ensure that we have some information into the buffer we are using the message
+ identifier value 2L (ERROR_FILE_NOT_FOUND)
+ */
+ ReturnResult = FormatMessage(
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_ALLOCATE_BUFFER, /* source and processing options */
+ NULL, /* message source */
+ 2L, /* message identifier */
+ 0, /* language identifier */
+ (LPWSTR)&OutBuffer, /* message buffer */
+ 0, /* maximum size of message buffer */
+ NULL /* array of message inserts */
+ );
+
+ if(ReturnResult == 0)
+ {
+ Fail("ERROR: The return value was 0, which indicates failure. The "
+ "function failed when trying to Format a FROM_SYSTEM message.");
+ }
+
+ if(wcslen(OutBuffer) <= 0)
+ {
+ Fail("ERROR: There are no characters in the buffer, and when the "
+ "FORMAT_MESSAGE_FROM_SYSTEM flag is used with ERROR_FILE_NOT_FOUND error, "
+ "something should be put into the buffer.");
+ }
+
+ LocalFree(OutBuffer);
+
+ PAL_Terminate();
+ return PASS;
+
+}
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/FormatMessageW/test6/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/FormatMessageW/test6/testinfo.dat
new file mode 100644
index 0000000000..7eda505271
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/FormatMessageW/test6/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = FormatMessageW
+Name = Positive test of FormatMessageW
+TYPE = DEFAULT
+EXE1 = test
+Description
+= Test to ensure the FORMAT_SYSTEM_MESSAGE flag works properly.
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/FreeEnvironmentStringsW/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/FreeEnvironmentStringsW/CMakeLists.txt
new file mode 100644
index 0000000000..ef14ea5352
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/FreeEnvironmentStringsW/CMakeLists.txt
@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+
diff --git a/src/pal/tests/palsuite/miscellaneous/FreeEnvironmentStringsW/test1/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/FreeEnvironmentStringsW/test1/CMakeLists.txt
new file mode 100644
index 0000000000..be39b63ec9
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/FreeEnvironmentStringsW/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.c
+)
+
+add_executable(paltest_freeenvironmentstringsw_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_freeenvironmentstringsw_test1 coreclrpal)
+
+target_link_libraries(paltest_freeenvironmentstringsw_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/FreeEnvironmentStringsW/test1/test.c b/src/pal/tests/palsuite/miscellaneous/FreeEnvironmentStringsW/test1/test.c
new file mode 100644
index 0000000000..56010039d7
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/FreeEnvironmentStringsW/test1/test.c
@@ -0,0 +1,53 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: test.c
+**
+** Purpose: Test for FreeEnvironmentStringsW() function
+**
+**
+**=========================================================*/
+
+#define UNICODE
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ LPWSTR CapturedEnvironment = NULL;
+ BOOL TheResult = 0;
+
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ CapturedEnvironment = GetEnvironmentStrings();
+
+ /* If it's pointing to NULL, it failed. This checks the dependency */
+ if(CapturedEnvironment == NULL) {
+ Fail("The function GetEnvironmentStrings() failed, and the "
+ "FreeEnvironmentStrings() tests is dependant on it.\n");
+ }
+
+ /* This should return 1, if it succeeds, otherwise, test fails */
+ TheResult = FreeEnvironmentStrings(CapturedEnvironment);
+ if(TheResult != 1) {
+ Fail("The function returned %d which indicates failure to Free the "
+ "Environment Strings.\n",TheResult);
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/FreeEnvironmentStringsW/test1/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/FreeEnvironmentStringsW/test1/testinfo.dat
new file mode 100644
index 0000000000..f653bf5dc2
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/FreeEnvironmentStringsW/test1/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = FreeEnvironmentStringsW
+Name = Return value test for FreeEnvironmentStringsW
+TYPE = DEFAULT
+EXE1 = test
+Description
+= Get a set of strings and then free it to see if function returns success
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/FreeEnvironmentStringsW/test2/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/FreeEnvironmentStringsW/test2/CMakeLists.txt
new file mode 100644
index 0000000000..a3688dd24a
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/FreeEnvironmentStringsW/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.c
+)
+
+add_executable(paltest_freeenvironmentstringsw_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_freeenvironmentstringsw_test2 coreclrpal)
+
+target_link_libraries(paltest_freeenvironmentstringsw_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/FreeEnvironmentStringsW/test2/test.c b/src/pal/tests/palsuite/miscellaneous/FreeEnvironmentStringsW/test2/test.c
new file mode 100644
index 0000000000..1bb05cdb12
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/FreeEnvironmentStringsW/test2/test.c
@@ -0,0 +1,71 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: test.c
+**
+** Purpose: Test for FreeEnvironmentStringsW() function
+**
+**
+**=========================================================*/
+
+#define UNICODE
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ WCHAR CapturedEnvironment[] = {'T','E','S','T','\0'};
+ BOOL TheResult = 0;
+ LPWSTR lpCapturedEnvironment = NULL;
+
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ lpCapturedEnvironment = (LPWSTR)malloc( sizeof(CapturedEnvironment) /
+ sizeof(CapturedEnvironment[0]) );
+
+ if ( lpCapturedEnvironment )
+ {
+ memcpy( lpCapturedEnvironment, CapturedEnvironment,
+ sizeof(CapturedEnvironment) / sizeof(CapturedEnvironment[0]) );
+ }
+ else
+ {
+ Fail( "malloc() failed to allocate memory.\n" );
+ }
+ /* Even if this is not a valid Environment block, the function will
+ still return success
+ */
+
+ TheResult = FreeEnvironmentStrings( lpCapturedEnvironment );
+ if(TheResult == 0)
+ {
+ Fail("The function should still return a success value even if it is "
+ "passed a LPWSTR which is not an environment block properly "
+ "aquired from GetEnvironmentStrings\n");
+ }
+
+ /* Even passing this function NULL, should still return a success value */
+ TheResult = FreeEnvironmentStrings(NULL);
+ if(TheResult == 0)
+ {
+ Fail("The function should still return a success value even if pass "
+ "NULL.\n");
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/FreeEnvironmentStringsW/test2/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/FreeEnvironmentStringsW/test2/testinfo.dat
new file mode 100644
index 0000000000..c426a7ccbd
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/FreeEnvironmentStringsW/test2/testinfo.dat
@@ -0,0 +1,16 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = FreeEnvironmentStringsW
+Name = Positive Return value test for FreeEnvironmentStringsW
+TYPE = DEFAULT
+EXE1 = test
+Description
+= Ensure that FreeEnvironmentStringsW returns success when passed pointers
+= that don't point to an environment block.
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/GetCalendarInfoW/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/GetCalendarInfoW/CMakeLists.txt
new file mode 100644
index 0000000000..ef14ea5352
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetCalendarInfoW/CMakeLists.txt
@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+
diff --git a/src/pal/tests/palsuite/miscellaneous/GetCalendarInfoW/test1/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/GetCalendarInfoW/test1/CMakeLists.txt
new file mode 100644
index 0000000000..e3acf4061a
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetCalendarInfoW/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ GetCalendarInfoW.c
+)
+
+add_executable(paltest_getcalendarinfow_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getcalendarinfow_test1 coreclrpal)
+
+target_link_libraries(paltest_getcalendarinfow_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/GetCalendarInfoW/test1/GetCalendarInfoW.c b/src/pal/tests/palsuite/miscellaneous/GetCalendarInfoW/test1/GetCalendarInfoW.c
new file mode 100644
index 0000000000..4876fe180f
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetCalendarInfoW/test1/GetCalendarInfoW.c
@@ -0,0 +1,57 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: GetCalendarInfoW.c
+**
+** Purpose: Positive test the GetCalendarInfoW API.
+** Call GetCalendarInfoW to retrieve the information of a
+** calendar
+**
+**
+**============================================================*/
+#define UNICODE
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ int err;
+ LCID Locale = LOCALE_USER_DEFAULT;
+ CALTYPE CalType = CAL_ITWODIGITYEARMAX|CAL_RETURN_NUMBER;
+ DWORD dwValue;
+
+ /*Initialize the PAL environment*/
+ err = PAL_Initialize(argc, argv);
+ if(0 != err)
+ {
+ return FAIL;
+ }
+
+ err = GetCalendarInfoW(Locale,/*locale idendifier*/
+ CAL_GREGORIAN, /*calendar identifier*/
+ CalType, /*calendar tyope*/
+ NULL, /*buffer to store the retrieve info*/
+ 0, /*alwayse zero*/
+ &dwValue);/*to store the requrest data*/
+ if (0 == err)
+ {
+ Fail("GetCalendarInfoW failed for CAL_GREGORIAN!\n");
+ }
+
+ err = GetCalendarInfoW(Locale,/*locale idendifier*/
+ CAL_GREGORIAN_US, /*calendar identifier*/
+ CalType, /*calendar tyope*/
+ NULL, /*buffer to store the retreive info*/
+ 0, /*alwayse zero*/
+ &dwValue);/*to store the requrest data*/
+ if (0 == err)
+ {
+ Fail("GetCalendarInfoW failed for CAL_GREGORIAN_US!\n");
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/miscellaneous/GetCalendarInfoW/test1/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/GetCalendarInfoW/test1/testinfo.dat
new file mode 100644
index 0000000000..59c806c22a
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetCalendarInfoW/test1/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = miscellaneous
+Function = GetCalendarInfoW
+Name = Positive test for GetCalendarInfoW API to retrieve the info of a calendar
+TYPE = DEFAULT
+EXE1 = getcalendarinfow
+Description
+= Test the GetCalendarInfoW to retrieve the information of a calendar
+= This test for US English
+
diff --git a/src/pal/tests/palsuite/miscellaneous/GetCalendarInfoW/test2/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/GetCalendarInfoW/test2/CMakeLists.txt
new file mode 100644
index 0000000000..cbfd1aa5db
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetCalendarInfoW/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ GetCalendarInfoW.c
+)
+
+add_executable(paltest_getcalendarinfow_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getcalendarinfow_test2 coreclrpal)
+
+target_link_libraries(paltest_getcalendarinfow_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/GetCalendarInfoW/test2/GetCalendarInfoW.c b/src/pal/tests/palsuite/miscellaneous/GetCalendarInfoW/test2/GetCalendarInfoW.c
new file mode 100644
index 0000000000..d8a59a0fc0
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetCalendarInfoW/test2/GetCalendarInfoW.c
@@ -0,0 +1,79 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: GetCalendarInfoW.c
+**
+** Purpose: Positive test the GetCalendarInfoW API.
+** Call GetCalendarInfoW to retrieve the information of all
+** calendars
+**
+**
+**============================================================*/
+#define UNICODE
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ int err;
+ int index = 0;
+ LCID Locale = LOCALE_USER_DEFAULT;
+ CALID Calendar;
+ CALTYPE CalType = CAL_ITWODIGITYEARMAX|CAL_RETURN_NUMBER;
+ DWORD dwValue;
+ char *CalendarID[]={"CAL_GREGORIAN",
+ "CAL_GREGORIAN_US",
+ "CAL_JAPAN",
+ "CAL_TAIWAN",
+ "CAL_KOREA",
+ "CAL_HIJRI",
+ "CAL_THAI",
+ "CAL_HEBREW",
+ "CAL_GREGORIAN_ME_FRENCH",
+ "CAL_GREGORIAN_ARABIC",
+ "CAL_GREGORIAN_XLIT_ENGLISH",
+ "CAL_GREGORIAN_XLIT_FRENCH",
+ "CAL_JULIAN"};
+
+ char errBuffer[1024];
+
+
+ /*Initialize the PAL environment*/
+ err = PAL_Initialize(argc, argv);
+ if(0 != err)
+ {
+ return FAIL;
+ }
+
+ memset(errBuffer, 0, 1024);
+
+ for(index=0; index<13; index++)
+ {
+ Calendar = index + 1;
+ /*retrieve the specified calendar info*/
+ err = GetCalendarInfoW(Locale,/*locale idendifier*/
+ Calendar, /*calendar identifier*/
+ CalType, /*calendar tyope*/
+ NULL, /*buffer to store the retreive info*/
+ 0, /*alwayse zero*/
+ &dwValue);/*to store the requrest data*/
+ if(0 == err)
+ {
+ strcat(errBuffer, CalendarID[index]);
+ strcat(errBuffer, ", ");
+ }
+ }
+
+
+ if(strlen(errBuffer) > 0)
+ {
+ Fail("\nFailed to call GetCalendarInfoW API by passing %s"
+ " Calendar identifier(s)\n",errBuffer);
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/miscellaneous/GetCalendarInfoW/test2/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/GetCalendarInfoW/test2/testinfo.dat
new file mode 100644
index 0000000000..ea85e99a30
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetCalendarInfoW/test2/testinfo.dat
@@ -0,0 +1,11 @@
+Version = 1.0
+Section = miscellaneous
+Function = GetCalendarInfoW
+Name = Positive test #2 for GetCalendarInfoW API to retrieve the info of a
+calendar
+TYPE = DEFAULT
+EXE1 = getcalendarinfow
+Description
+= Test the GetCalendarInfoW to retrieve the information of all calendars
+= but US English
+
diff --git a/src/pal/tests/palsuite/miscellaneous/GetCommandLineW/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/GetCommandLineW/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetCommandLineW/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/miscellaneous/GetCommandLineW/test1/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/GetCommandLineW/test1/CMakeLists.txt
new file mode 100644
index 0000000000..491fdca9b5
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetCommandLineW/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.c
+)
+
+add_executable(paltest_getcommandlinew_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getcommandlinew_test1 coreclrpal)
+
+target_link_libraries(paltest_getcommandlinew_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/GetCommandLineW/test1/test.c b/src/pal/tests/palsuite/miscellaneous/GetCommandLineW/test1/test.c
new file mode 100644
index 0000000000..d8a81746b6
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetCommandLineW/test1/test.c
@@ -0,0 +1,71 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source : test.c
+**
+** Purpose: Test for GetCommandLineW() function
+**
+**
+**=========================================================*/
+
+#define UNICODE
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ LPWSTR TheResult = NULL;
+ WCHAR *CommandLine;
+ int i;
+ WCHAR * p;
+
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ CommandLine = malloc(1024);
+ wcscpy(CommandLine,convert(argv[0]));
+
+ for(i=1;i<argc;++i)
+ {
+ wcscat(CommandLine,convert(" "));
+ wcscat(CommandLine,convert(argv[i]));
+ }
+
+ TheResult = GetCommandLine();
+
+ /* If it is NULL, it failed. */
+ if(TheResult == NULL)
+ {
+ Fail("ERROR: The command line returned was NULL -- but should be "
+ "a LPWSTR.");
+ }
+
+ // It's ok that if there is trailing white spaces in "TheResult"
+ // Let's trim them.
+ p = TheResult + wcslen(TheResult) - 1;
+ while (* p == L' ' || * p == L'\t') { printf("%c\n", *p); * p-- = 0 ; }
+
+ if(memcmp(TheResult,CommandLine,wcslen(TheResult)*2+2) != 0)
+ {
+ Fail("ERROR: The command line returned was %s instead of %s "
+ "which was the command.\n",
+ convertC(TheResult), convertC(CommandLine));
+ }
+
+ free(CommandLine);
+
+ PAL_Terminate();
+ return PASS;
+
+}
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/GetCommandLineW/test1/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/GetCommandLineW/test1/testinfo.dat
new file mode 100644
index 0000000000..668cb7d249
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetCommandLineW/test1/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = GetCommandLineW
+Name = Positive test for GetCommandLineW
+TYPE = DEFAULT
+EXE1 = test
+Description
+= Ensure that this function returns the correct CommandLine
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/GetComputerNameW/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/GetComputerNameW/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetComputerNameW/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/miscellaneous/GetComputerNameW/test1/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/GetComputerNameW/test1/CMakeLists.txt
new file mode 100644
index 0000000000..980dae88ae
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetComputerNameW/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.c
+)
+
+add_executable(paltest_getcomputernamew_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getcomputernamew_test1 coreclrpal)
+
+target_link_libraries(paltest_getcomputernamew_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/GetComputerNameW/test1/test.c b/src/pal/tests/palsuite/miscellaneous/GetComputerNameW/test1/test.c
new file mode 100644
index 0000000000..7a00cad598
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetComputerNameW/test1/test.c
@@ -0,0 +1,53 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source : test.c
+**
+** Purpose: Positive Test for GetComputerName() function
+**
+**
+**=========================================================*/
+
+#define UNICODE
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ int HOST_NAME_MAX = 255;
+ WCHAR wzComputerName[HOST_NAME_MAX+1];
+ DWORD dwSize = sizeof(wzComputerName)/sizeof(wzComputerName[0]);
+
+ // Initialize the PAL and return FAILURE if this fails
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ Fail ("ERROR: PAL_Initialize() call failed!\n");
+ }
+
+ if (0 == GetComputerName(wzComputerName, &dwSize))
+ {
+ Fail("ERROR: GetComputerName failed with %d!\n", GetLastError());
+ }
+
+ // dwSize is the length of wzComputerName without NULL
+ if (dwSize < 0 || dwSize > (sizeof(wzComputerName)/sizeof(wzComputerName[0]) - 1))
+ {
+ Fail("ERROR: GetComputerName returned %S with dwSize = %u whereas the passed in buffer size is %d!\n",
+ wzComputerName, dwSize, sizeof(wzComputerName)/sizeof(wzComputerName[0]));
+ }
+
+ // dwSize is the length of wzComputerName without NULL
+ if (dwSize != wcslen(wzComputerName))
+ {
+ Fail("ERROR: GetComputerName returned %S of length %d which is not equal to dwSize = %u!\n",
+ wzComputerName, wcslen(wzComputerName), dwSize);
+ }
+
+ printf ("GetComputerName returned %S of length %u\n", wzComputerName, dwSize);
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/miscellaneous/GetComputerNameW/test1/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/GetComputerNameW/test1/testinfo.dat
new file mode 100644
index 0000000000..d45bca1c25
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetComputerNameW/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = GetComputerNameW
+Name = Test for GetComputerNameW
+TYPE = DEFAULT
+EXE1 = test
+Description
+= Check to ensure that GetComputerNameW returnes a decent value.
+
diff --git a/src/pal/tests/palsuite/miscellaneous/GetDateFormatW/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/GetDateFormatW/CMakeLists.txt
new file mode 100644
index 0000000000..80b6a0d41d
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetDateFormatW/CMakeLists.txt
@@ -0,0 +1,6 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(GetDateFormatW_neg1)
+add_subdirectory(GetDateFormatW_neg2)
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/miscellaneous/GetDateFormatW/GetDateFormatW_neg1/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/GetDateFormatW/GetDateFormatW_neg1/CMakeLists.txt
new file mode 100644
index 0000000000..5a340c6cfb
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetDateFormatW/GetDateFormatW_neg1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ GetDateFormatW_neg.c
+)
+
+add_executable(paltest_getdateformatw_getdateformatw_neg1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getdateformatw_getdateformatw_neg1 coreclrpal)
+
+target_link_libraries(paltest_getdateformatw_getdateformatw_neg1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/GetDateFormatW/GetDateFormatW_neg1/GetDateFormatW_neg.c b/src/pal/tests/palsuite/miscellaneous/GetDateFormatW/GetDateFormatW_neg1/GetDateFormatW_neg.c
new file mode 100644
index 0000000000..c64dc74cb6
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetDateFormatW/GetDateFormatW_neg1/GetDateFormatW_neg.c
@@ -0,0 +1,85 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: GetDateFormatW_neg.c
+**
+** Purpose: Negative test the GetDateFormatW API.
+** Call GetDateFormatW by passing an invalid parameter
+**
+**
+**============================================================*/
+#define UNICODE
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ int err;
+ WCHAR *wpFormat;
+ LPCSTR lpString = "gg";
+ CONST SYSTEMTIME *lpDate = NULL;
+ LCID DefaultLocale;
+ DWORD dwFlags;
+ int DateSize;
+ WCHAR *wpBuffer = NULL;
+
+ /*Initialize the PAL environment*/
+ err = PAL_Initialize(argc, argv);
+ if(0 != err)
+ {
+ return FAIL;
+ }
+
+ /*convert to a wide character string*/
+ wpFormat = convert((char *)lpString);
+
+ dwFlags = DATE_USE_ALT_CALENDAR; /*set the flags*/
+
+
+ DateSize = 0;
+
+ /*retrieve the buffer size*/
+ DateSize = GetDateFormatW(
+ DefaultLocale, /*system default locale*/
+ dwFlags, /*function option*/
+ (SYSTEMTIME *)lpDate, /*always is NULL*/
+ wpFormat, /*pointer to a picture string*/
+ wpBuffer, /*out buffer*/
+ DateSize); /*buffer size*/
+
+ if(DateSize <= 0)
+ {
+ free(wpFormat);
+ Fail("\nRetrieved an invalid buffer size\n");
+ }
+
+ wpBuffer = malloc((DateSize + 1)*sizeof(WCHAR));
+ if(NULL == wpBuffer)
+ {
+ free(wpFormat);
+ Fail("\nFailed to allocate memory to store the formatted string\n");
+ }
+
+ /*format a date by passing an invalid locale indentifier*/
+ err = GetDateFormatW(
+ -1, /*invalid locale identifier*/
+ dwFlags, /*function option*/
+ (SYSTEMTIME *)lpDate, /*always is NULL, or use system date*/
+ wpFormat, /*pointer to a picture string*/
+ wpBuffer, /*out buffer*/
+ DateSize); /*buffer size*/
+
+ free(wpBuffer);
+ free(wpFormat);
+
+ if(0 != err || GetLastError() != ERROR_INVALID_PARAMETER)
+ {
+ Fail("\nFailed to call GetDateFormatW for a negative test by "
+ "passing an invalid parameter, error code=%d\n", GetLastError());
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/miscellaneous/GetDateFormatW/GetDateFormatW_neg1/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/GetDateFormatW/GetDateFormatW_neg1/testinfo.dat
new file mode 100644
index 0000000000..f02271650c
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetDateFormatW/GetDateFormatW_neg1/testinfo.dat
@@ -0,0 +1,8 @@
+Version = 1.0
+Section = miscellaneous
+Function = GetDateFormatW
+Name = Negative test for GetDateFormatW by passing an invlid locale identifier
+TYPE = DEFAULT
+EXE1 = getdateformatw_neg
+Description
+=negative test GetDateFormatW by passing an invalid locale identifier
diff --git a/src/pal/tests/palsuite/miscellaneous/GetDateFormatW/GetDateFormatW_neg2/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/GetDateFormatW/GetDateFormatW_neg2/CMakeLists.txt
new file mode 100644
index 0000000000..646de9160b
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetDateFormatW/GetDateFormatW_neg2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ GetDateFormatW_neg.c
+)
+
+add_executable(paltest_getdateformatw_getdateformatw_neg2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getdateformatw_getdateformatw_neg2 coreclrpal)
+
+target_link_libraries(paltest_getdateformatw_getdateformatw_neg2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/GetDateFormatW/GetDateFormatW_neg2/GetDateFormatW_neg.c b/src/pal/tests/palsuite/miscellaneous/GetDateFormatW/GetDateFormatW_neg2/GetDateFormatW_neg.c
new file mode 100644
index 0000000000..676038f03a
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetDateFormatW/GetDateFormatW_neg2/GetDateFormatW_neg.c
@@ -0,0 +1,98 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: GetDateFormatW_neg.c
+**
+** Purpose: Negative test the GetDateFormatW API.
+** Call GetDateFormatW by passing an invalid flag
+**
+**
+**============================================================*/
+#define UNICODE
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ int err;
+ WCHAR *wpFormat;
+ LPCSTR lpString = "gg";
+ CONST SYSTEMTIME *lpDate = NULL;
+ LCID DefaultLocale;
+ DWORD dwFlags;
+ int DateSize;
+ WCHAR *wpBuffer = NULL;
+
+ /*Initialize the PAL environment*/
+ err = PAL_Initialize(argc, argv);
+ if(0 != err)
+ {
+ return FAIL;
+ }
+
+ /*convert to a wide character string*/
+ wpFormat = convert((char *)lpString);
+
+ /*
+ DefaultLocale = GetSystemDefaultLCID() which is not defined in PAL;
+
+ LOCALE_SYSTEM_DEFAULT = MAKELCID(LANG_SYSTEM_DEFAULT, SORT_DEFAULT)
+
+ LANG_SYSTEM_DEFAULT = MAKELANGID(LANG_NEUTRAL,SUBLANG_SYS_DEFAULT);
+ SUBLANG_SYS_DEFAULT is not defined in PAL, here use hardcoding,
+ the value is from winnt.h
+ */
+
+ DefaultLocale = MAKELCID(MAKELANGID(LANG_NEUTRAL, 0x02), SORT_DEFAULT);
+
+ dwFlags = DATE_USE_ALT_CALENDAR; /*set the flags*/
+
+
+ DateSize = 0;
+
+ /*retrieve the buffer size*/
+ DateSize = GetDateFormatW(
+ DefaultLocale, /*system default locale*/
+ dwFlags, /*function option*/
+ (SYSTEMTIME *)lpDate, /*always is NULL*/
+ wpFormat, /*pointer to a picture string*/
+ wpBuffer, /*out buffer*/
+ DateSize); /*buffer size*/
+
+ if(DateSize <= 0)
+ {
+ free(wpFormat);
+ Fail("\nRetrieved an invalid buffer size\n");
+ }
+
+ wpBuffer = malloc((DateSize + 1)*sizeof(WCHAR));
+ if(NULL == wpBuffer)
+ {
+ free(wpFormat);
+ Fail("\nFailed to allocate memory to store the formatted string\n");
+ }
+
+ err = GetDateFormatW(
+ DefaultLocale, /*system default locale*/
+ 0x00000001|0x00000008,/*DATE_SHORTDATE|DATE_YEARMONTH */
+ /*an invalid flag*/
+ (SYSTEMTIME *)lpDate, /*always is NULL, or use system date*/
+ wpFormat, /*pointer to a picture string*/
+ wpBuffer, /*out buffer*/
+ DateSize); /*buffer size*/
+
+ free(wpBuffer);
+ free(wpFormat);
+
+ if(0 != err || GetLastError() != ERROR_INVALID_FLAGS)
+ {
+ Fail("\nFailed to call GetDateFormatW for a negative test by "
+ "passing an invalid flag, error code=%d\n", GetLastError());
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/miscellaneous/GetDateFormatW/GetDateFormatW_neg2/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/GetDateFormatW/GetDateFormatW_neg2/testinfo.dat
new file mode 100644
index 0000000000..fe5bc9b06e
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetDateFormatW/GetDateFormatW_neg2/testinfo.dat
@@ -0,0 +1,9 @@
+Version = 1.0
+Section = miscellaneous
+Function = GetDateFormatW
+Name = Negative test for GetDateFormatW by passing an invalid flag
+TYPE = DEFAULT
+EXE1 = getdateformatw_neg
+Description
+=test for GetDateFormatW by passing an invalid flag which is not
+=supported
diff --git a/src/pal/tests/palsuite/miscellaneous/GetDateFormatW/test1/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/GetDateFormatW/test1/CMakeLists.txt
new file mode 100644
index 0000000000..8c1e4b024e
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetDateFormatW/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ GetDateFormatW.c
+)
+
+add_executable(paltest_getdateformatw_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getdateformatw_test1 coreclrpal)
+
+target_link_libraries(paltest_getdateformatw_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/GetDateFormatW/test1/GetDateFormatW.c b/src/pal/tests/palsuite/miscellaneous/GetDateFormatW/test1/GetDateFormatW.c
new file mode 100644
index 0000000000..264e397a49
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetDateFormatW/test1/GetDateFormatW.c
@@ -0,0 +1,100 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: GetDateFormatW.c
+**
+** Purpose: Positive test the GetDateFormatW API.
+** Call GetDateFormatW to format a date string for
+** a specified locale
+**
+**
+**============================================================*/
+#define UNICODE
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ int err;
+ WCHAR *wpFormat;
+ LPCSTR lpString = "gg";
+ CONST SYSTEMTIME *lpDate = NULL;
+ LCID DefaultLocale;
+ DWORD dwFlags;
+ int DateSize;
+ WCHAR *wpBuffer = NULL;
+
+ /*Initialize the PAL environment*/
+ err = PAL_Initialize(argc, argv);
+ if(0 != err)
+ {
+ return FAIL;
+ }
+
+ /*convert to a wide character string*/
+ wpFormat = convert((char *)lpString);
+
+ /*
+ DefaultLocale = GetSystemDefaultLCID() which is not defined in PAL;
+
+ LOCALE_SYSTEM_DEFAULT = MAKELCID(LANG_SYSTEM_DEFAULT, SORT_DEFAULT)
+
+ LANG_SYSTEM_DEFAULT = MAKELANGID(LANG_NEUTRAL,SUBLANG_SYS_DEFAULT);
+ SUBLANG_SYS_DEFAULT is not defined in PAL, here use hardcoding,
+ the value is from winnt.h
+ */
+ DefaultLocale = MAKELCID(MAKELANGID(LANG_NEUTRAL, 0x02), SORT_DEFAULT);
+
+ dwFlags = DATE_USE_ALT_CALENDAR; /*set the flags*/
+
+
+ DateSize = 0;
+
+ /*retrieve the buffer size*/
+ DateSize = GetDateFormatW(
+ DefaultLocale, /*system default locale*/
+ dwFlags, /*function option*/
+ (SYSTEMTIME *)lpDate, /*always is NULL*/
+ wpFormat, /*pointer to a picture string*/
+ wpBuffer, /*out buffer*/
+ DateSize); /*buffer size*/
+
+ if(DateSize <= 0)
+ {
+ free(wpFormat);
+ Fail("\nRetrieved an invalid buffer size\n");
+ }
+
+
+ wpBuffer = malloc((DateSize+1)*sizeof(WCHAR));
+ if(NULL == wpBuffer)
+ {
+ free(wpFormat);
+ Fail("\nFailed to allocate memory to store a formatted string\n");
+ }
+
+ /*retrieve the formatted string for a specified locale*/
+ err = GetDateFormatW(
+ DefaultLocale, /*system default locale*/
+ dwFlags, /*function option*/
+ (SYSTEMTIME *)lpDate, /*always is NULL*/
+ wpFormat, /*pointer to a picture string*/
+ wpBuffer, /*out buffer*/
+ DateSize); /*buffer size*/
+
+ if(0 == err)
+ {
+ free(wpBuffer);
+ free(wpFormat);
+ Fail("\nFailed to call GetDateFormatW to format a system data "
+ "as a data string for system default locale!\n");
+ }
+
+ free(wpBuffer);
+ free(wpFormat);
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/miscellaneous/GetDateFormatW/test1/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/GetDateFormatW/test1/testinfo.dat
new file mode 100644
index 0000000000..6ed9ee7cef
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetDateFormatW/test1/testinfo.dat
@@ -0,0 +1,9 @@
+Version = 1.0
+Section = miscellaneous
+Function = GetDateFormatW
+Name = Positive test for GetDateFormatW to format a date as a date string
+TYPE = DEFAULT
+EXE1 = getdateformatw
+Description
+=test for GetDateFormatW to format a date as a date string
+=for a specified locale
diff --git a/src/pal/tests/palsuite/miscellaneous/GetEnvironmentStringsW/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/GetEnvironmentStringsW/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetEnvironmentStringsW/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/miscellaneous/GetEnvironmentStringsW/test1/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/GetEnvironmentStringsW/test1/CMakeLists.txt
new file mode 100644
index 0000000000..306400e558
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetEnvironmentStringsW/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.c
+)
+
+add_executable(paltest_getenvironmentstringsw_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getenvironmentstringsw_test1 coreclrpal)
+
+target_link_libraries(paltest_getenvironmentstringsw_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/GetEnvironmentStringsW/test1/test.c b/src/pal/tests/palsuite/miscellaneous/GetEnvironmentStringsW/test1/test.c
new file mode 100644
index 0000000000..2bd9153e59
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetEnvironmentStringsW/test1/test.c
@@ -0,0 +1,81 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source : test.c
+**
+** Purpose: Test for GetEnvironmentStringsW() function
+**
+**
+**=========================================================*/
+
+/* Depends on SetEnvironmentVariable(), wcsstr() and wcslen() */
+
+#define UNICODE
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[]) {
+
+ LPWSTR CapturedEnvironmentStrings = NULL;
+ LPWSTR EnviroStringReturned = NULL;
+ WCHAR EnvironmentVariableBuffer[] =
+ {'P','A','L','T','E','S','T','I','N','G','\0'};
+ WCHAR EnvironmentValueBuffer[] = {'T','e','s','t','i','n','g','\0'};
+
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /* This test depends on SetEnvironmentVariableW working.
+ We need to set a variable so we can test and ensure it's there
+ when we get them back
+ */
+
+ SetEnvironmentVariable(EnvironmentVariableBuffer,EnvironmentValueBuffer);
+
+ CapturedEnvironmentStrings = GetEnvironmentStrings();
+
+ /* If it's pointing to NULL, it failed. */
+ if(CapturedEnvironmentStrings == NULL) {
+ Fail("The function returned a pointer to NULL, which it shouldn't do. "
+ "It should point to a block of Environment Strings.\n");
+ }
+
+ /* Now that we've grabbed the list of envrionment strings, go through
+ each one, and check for a match to 'PALTESTING'. If this is missing
+ it's not pointing at the environment block.
+ */
+
+ while(*CapturedEnvironmentStrings != 0)
+ {
+ EnviroStringReturned = wcsstr(CapturedEnvironmentStrings,
+ EnvironmentVariableBuffer);
+ CapturedEnvironmentStrings += wcslen(CapturedEnvironmentStrings)+1;
+ if(EnviroStringReturned != NULL)
+ {
+ break;
+ }
+ }
+
+ if(EnviroStringReturned == NULL)
+ {
+ Fail("The memory block returned was searched, but nothing was found to "
+ "prove this was really the environment block. Either this "
+ "function, SetEnvironmentVariable or wcsstr() is broken.\n");
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/GetEnvironmentStringsW/test1/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/GetEnvironmentStringsW/test1/testinfo.dat
new file mode 100644
index 0000000000..fa712ab823
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetEnvironmentStringsW/test1/testinfo.dat
@@ -0,0 +1,16 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = GetEnvironmentStringsW
+Name = Test for correct return of GetEnvironmentStringsW
+TYPE = DEFAULT
+EXE1 = test
+Description
+= Get a set of strings, and check to make sure it contains a predetermined
+= string that was placed there.
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableA/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableA/CMakeLists.txt
new file mode 100644
index 0000000000..7c20179353
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableA/CMakeLists.txt
@@ -0,0 +1,9 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+add_subdirectory(test3)
+add_subdirectory(test4)
+add_subdirectory(test5)
+add_subdirectory(test6)
+
diff --git a/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableA/test1/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableA/test1/CMakeLists.txt
new file mode 100644
index 0000000000..184a6ef1f0
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableA/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.c
+)
+
+add_executable(paltest_getenvironmentvariablea_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getenvironmentvariablea_test1 coreclrpal)
+
+target_link_libraries(paltest_getenvironmentvariablea_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableA/test1/test.c b/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableA/test1/test.c
new file mode 100644
index 0000000000..8862e823bc
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableA/test1/test.c
@@ -0,0 +1,84 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source : test.c
+**
+** Purpose: Test for GetEnvironmentVariable() function
+** Assign a properly sized buffer and get an environment
+** variable, check to ensure it returns the correct values.
+**
+**
+**=========================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[]) {
+
+ /* Define some buffers needed for the function */
+ char * pResultBuffer = NULL;
+ int size = 0;
+
+ /* A place to stash the returned values */
+ int ReturnValueForLargeBuffer = 0;
+
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /* Recieve and allocate the correct amount of memory for the buffer */
+ size = ReturnValueForLargeBuffer = GetEnvironmentVariable("PATH",
+ pResultBuffer,
+ 0);
+ pResultBuffer = malloc(size);
+ if ( pResultBuffer == NULL )
+ {
+ Fail("ERROR: Failed to allocate memory for pResultBuffer pointer. "
+ "Can't properly exec test case without this.\n");
+ }
+
+
+ /* Normal case, PATH should fit into this buffer */
+ ReturnValueForLargeBuffer = GetEnvironmentVariable("PATH",
+ pResultBuffer,
+ size);
+
+ /* Ensure that it returned a positive value */
+ if(ReturnValueForLargeBuffer <= 0)
+ {
+ free(pResultBuffer);
+
+ Fail("The return was %d, which indicates that the function failed.\n",
+ ReturnValueForLargeBuffer);
+ }
+
+ /* Ensure that it succeeded and copied the correct number of characters.
+ If this is true, then the return value should be one less of the size of
+ the buffer. (Doesn't include that NULL byte)
+ */
+
+ if(ReturnValueForLargeBuffer != size-1)
+ {
+ free(pResultBuffer);
+
+ Fail("The value returned was %d when it should have been %d. "
+ "This should be the number of characters copied, minus the "
+ "NULL byte.\n",ReturnValueForLargeBuffer, size-1);
+ }
+
+
+ free(pResultBuffer);
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableA/test1/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableA/test1/testinfo.dat
new file mode 100644
index 0000000000..ee81e2ec3b
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableA/test1/testinfo.dat
@@ -0,0 +1,16 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = GetEnvironmentVariableA
+Name = Return value test for GetEnvironmentVariableA
+TYPE = DEFAULT
+EXE1 = test
+Description
+= Assign a properly sized buffer and get an environment variable, check to
+= ensure it returns the correct values.
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableA/test2/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableA/test2/CMakeLists.txt
new file mode 100644
index 0000000000..abfd73f458
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableA/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.c
+)
+
+add_executable(paltest_getenvironmentvariablea_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getenvironmentvariablea_test2 coreclrpal)
+
+target_link_libraries(paltest_getenvironmentvariablea_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableA/test2/test.c b/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableA/test2/test.c
new file mode 100644
index 0000000000..d26588e907
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableA/test2/test.c
@@ -0,0 +1,56 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source : test.c
+**
+** Purpose: Test for GetEnvironmentVariable() function
+** Pass a small buffer to GetEnvironmentVariableA to ensure
+** it returns the size it requires.
+**
+**
+**=========================================================*/
+
+#include <palsuite.h>
+
+#define SMALL_BUFFER_SIZE 1
+
+int __cdecl main(int argc, char *argv[]) {
+
+ /* A place to stash the returned values */
+ int ReturnValueForSmallBuffer = 0;
+
+ char pSmallBuffer[SMALL_BUFFER_SIZE];
+
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /* PATH won't fit in this buffer, it should return how many
+ characters it needs
+ */
+
+ ReturnValueForSmallBuffer = GetEnvironmentVariable("PATH",
+ pSmallBuffer,
+ SMALL_BUFFER_SIZE);
+ if(ReturnValueForSmallBuffer <= 0)
+ {
+ Fail("The return value was %d when it should have been greater "
+ "than 0. "
+ "This should return the number of characters needed to contained "
+ "the contents of PATH in a buffer.\n",ReturnValueForSmallBuffer);
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableA/test2/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableA/test2/testinfo.dat
new file mode 100644
index 0000000000..990649fad9
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableA/test2/testinfo.dat
@@ -0,0 +1,16 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = GetEnvironmentVariableA
+Name = Return value test on GetEnvironmentVariableA
+TYPE = DEFAULT
+EXE1 = test
+Description
+= Pass a small buffer to GetEnvironmentVariableA
+= to ensure it returns the size it requires.
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableA/test3/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableA/test3/CMakeLists.txt
new file mode 100644
index 0000000000..a63c11b1a3
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableA/test3/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.c
+)
+
+add_executable(paltest_getenvironmentvariablea_test3
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getenvironmentvariablea_test3 coreclrpal)
+
+target_link_libraries(paltest_getenvironmentvariablea_test3
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableA/test3/test.c b/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableA/test3/test.c
new file mode 100644
index 0000000000..b51e139c95
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableA/test3/test.c
@@ -0,0 +1,67 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source : test.c
+**
+** Purpose: Test for GetEnvironmentVariable() function
+** Pass a nonexisting environment variable and a null to
+** the function to check return values.
+**
+**
+**=========================================================*/
+
+#include <palsuite.h>
+
+#define BUFFER_SIZE 5000
+#define SMALL_BUFFER_SIZE 5
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ int ReturnValueForNonExisting = 0;
+ int ReturnValueForNull = 0;
+
+ char pResultBuffer[BUFFER_SIZE];
+ char pSmallBuffer[SMALL_BUFFER_SIZE];
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /* This variable doesn't exist, it should return 0 */
+ ReturnValueForNonExisting = GetEnvironmentVariable("NonExistingVariable",
+ pSmallBuffer,
+ SMALL_BUFFER_SIZE);
+
+ if(ReturnValueForNonExisting != 0)
+ {
+ Fail("ERROR: The return should have been 0, but it was %d. "
+ "The function attempted to get an Environment Variable that "
+ "doesn't exist and should return 0 as a result.\n",
+ ReturnValueForNonExisting);
+ }
+
+
+ /* Passing a NULL string should return 0 */
+ ReturnValueForNull = GetEnvironmentVariable(NULL,
+ pResultBuffer,
+ BUFFER_SIZE);
+
+ if(ReturnValueForNull != 0)
+ {
+ Fail("ERROR: The return should have been 0, but it was %d. "
+ "The function attempted to get a NULL pointer and should return "
+ "0 as a result.\n",ReturnValueForNull);
+
+ }
+
+ PAL_Terminate();
+ return PASS;
+ }
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableA/test3/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableA/test3/testinfo.dat
new file mode 100644
index 0000000000..afaa04b8fa
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableA/test3/testinfo.dat
@@ -0,0 +1,16 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = GetEnvironmentVariableA
+Name = Return value test for GetEnvironmentVariableA
+TYPE = DEFAULT
+EXE1 = test
+Description
+= Pass a nonexisting environment variable and a null to the function
+= to check return values.
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableA/test4/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableA/test4/CMakeLists.txt
new file mode 100644
index 0000000000..76cfdb6d49
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableA/test4/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.c
+)
+
+add_executable(paltest_getenvironmentvariablea_test4
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getenvironmentvariablea_test4 coreclrpal)
+
+target_link_libraries(paltest_getenvironmentvariablea_test4
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableA/test4/test.c b/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableA/test4/test.c
new file mode 100644
index 0000000000..1fea5719b4
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableA/test4/test.c
@@ -0,0 +1,75 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source : test.c
+**
+** Purpose: Test for GetEnvironmentVariable() function
+** Set an Environment Variable, then use GetEnvironmentVariable to
+** retrieve it -- ensure that it retrieves properly.
+**
+**
+**=========================================================*/
+
+/* Depends on SetEnvironmentVariableW (because we're implmenting
+ the wide version) and strcmp()
+*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[]) {
+
+ /* Define some buffers needed for the function */
+ char * pResultBuffer = NULL;
+ WCHAR SomeEnvironmentVariable[] = {'P','A','L','T','E','S','T','\0'};
+ WCHAR TheEnvironmentValue[] = {'T','E','S','T','\0'};
+ int size = 0;
+
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ SetEnvironmentVariableW(SomeEnvironmentVariable,
+ TheEnvironmentValue);
+
+
+ /* Normal case, PATH should fit into this buffer */
+ size = GetEnvironmentVariable("PALTEST", // Variable Name
+ pResultBuffer, // Buffer for Value
+ 0); // Buffer size
+
+ pResultBuffer = malloc(size);
+ if ( pResultBuffer == NULL )
+ {
+ Fail("ERROR: Failed to allocate memory for pResultBuffer pointer. "
+ "Can't properly exec test case without this.\n");
+ }
+
+
+ GetEnvironmentVariable("PALTEST",
+ pResultBuffer,
+ size);
+
+ if(strcmp(pResultBuffer,"TEST") != 0)
+ {
+ free(pResultBuffer);
+ Fail("ERROR: The value in the buffer should have been 'TEST' but "
+ "was really '%s'.\n",pResultBuffer);
+
+ }
+
+ free(pResultBuffer);
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableA/test4/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableA/test4/testinfo.dat
new file mode 100644
index 0000000000..8fb16c778c
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableA/test4/testinfo.dat
@@ -0,0 +1,16 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = GetEnvironmentVariableA
+Name = Positive Test for GetEnvironmentVariableA
+TYPE = DEFAULT
+EXE1 = test
+Description
+= Set an Environment Variable, then use GetEnvironmentVariable
+= to retrieve it ensure that it retrieves properly.
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableA/test5/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableA/test5/CMakeLists.txt
new file mode 100644
index 0000000000..548d86bb03
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableA/test5/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test5.c
+)
+
+add_executable(paltest_getenvironmentvariablea_test5
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getenvironmentvariablea_test5 coreclrpal)
+
+target_link_libraries(paltest_getenvironmentvariablea_test5
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableA/test5/test5.c b/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableA/test5/test5.c
new file mode 100644
index 0000000000..8d63a1aecb
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableA/test5/test5.c
@@ -0,0 +1,145 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+** Source : test5.c
+**
+** Purpose: Test for GetEnvironmentVariableA() function
+** Create environment variables that differ only
+** in case and verify that they return the appropriate
+** value on the BSD environment.
+**
+**
+===========================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+
+#if WIN32
+
+ return PASS;
+
+#else
+
+ /* Define some buffers needed for the function */
+ char * pResultBuffer = NULL;
+
+ char FirstEnvironmentVariable[] = {"PALTEST"};
+ char FirstEnvironmentValue[] = {"FIRST"};
+
+ char SecondEnvironmentVariable[] = {"paltest"};
+ char SecondEnvironmentValue[] = {"SECOND"};
+
+ DWORD size = 0;
+ BOOL bRc = TRUE;
+
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /* Set the first environment variable */
+ bRc = SetEnvironmentVariableA(FirstEnvironmentVariable,
+ FirstEnvironmentValue);
+
+ if(!bRc)
+ {
+ Fail("ERROR: SetEnvironmentVariable failed to set a "
+ "proper environment variable with error %u.\n", GetLastError());
+ }
+
+
+ /* Normal case, PATH should fit into this buffer */
+ size = GetEnvironmentVariableA(FirstEnvironmentVariable,
+ pResultBuffer,
+ 0);
+
+ /* To account for the null character at the end of the string */
+ size = size + 1;
+
+ pResultBuffer = malloc(sizeof(char)*size);
+ if ( pResultBuffer == NULL )
+ {
+ Fail("ERROR: Failed to allocate memory for pResultBuffer pointer\n.");
+ }
+
+ /* Try to retrieve the value of the first environment variable */
+ GetEnvironmentVariableA(FirstEnvironmentVariable,
+ pResultBuffer,
+ size);
+
+ if ( pResultBuffer == NULL )
+ {
+ free(pResultBuffer);
+ Fail("ERROR: GetEnvironmentVariable failed to return a value "
+ "from a proper environment variable with error %u.\n",
+ GetLastError());
+ }
+
+ /* Compare the strings to see that the correct variable was returned */
+ if(strcmp(pResultBuffer,FirstEnvironmentValue) != 0)
+ {
+ free(pResultBuffer);
+ Fail("ERROR: The value in the buffer should have been '%s' but "
+ "was really '%s'.\n",FirstEnvironmentValue, pResultBuffer);
+ }
+
+ free(pResultBuffer);
+
+ /* Set the second environment Variable */
+ bRc = SetEnvironmentVariableA(SecondEnvironmentVariable,
+ SecondEnvironmentValue);
+
+ if(!bRc)
+ {
+ Fail("ERROR: SetEnvironmentVariable failed to set a "
+ "proper environment variable with error %u.\n",
+ GetLastError());
+ }
+
+ /* Reallocate the memory for the string */
+ pResultBuffer = malloc(sizeof(char)*size);
+ if ( pResultBuffer == NULL )
+ {
+ Fail("ERROR: Failed to allocate memory for pResultBuffer pointer.");
+ }
+
+ /* Try retrieving the value of the first variable, even though the
+ second variable has the same spelling and only differs in case */
+ GetEnvironmentVariableA(FirstEnvironmentVariable,
+ pResultBuffer,
+ size);
+
+ if ( pResultBuffer == NULL )
+ {
+ free(pResultBuffer);
+ Fail("ERROR: GetEnvironmentVariable failed to return a value "
+ "from a proper environment variable with error %u.\n",
+ GetLastError());
+ }
+
+ /* Compare the two strings to confirm that the right value is returned */
+ if(strcmp(pResultBuffer,FirstEnvironmentValue) != 0)
+ {
+ free(pResultBuffer);
+ Fail("ERROR: The value in the buffer should have been '%s' but "
+ "was really '%s'.\n",FirstEnvironmentValue,pResultBuffer);
+ }
+
+ free(pResultBuffer);
+
+ PAL_Terminate();
+ return PASS;
+
+#endif
+}
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableA/test5/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableA/test5/testinfo.dat
new file mode 100644
index 0000000000..0bcec5973b
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableA/test5/testinfo.dat
@@ -0,0 +1,17 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = GetEnvironmentVariableA
+Name = Positive Test for GetEnvironmentVariableA
+TYPE = DEFAULT
+EXE1 = test5
+Description
+= Set environment variables that differ only in case
+= and verify that on BSD they return two different
+= values.
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableA/test6/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableA/test6/CMakeLists.txt
new file mode 100644
index 0000000000..a0873bb7e7
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableA/test6/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test6.c
+)
+
+add_executable(paltest_getenvironmentvariablea_test6
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getenvironmentvariablea_test6 coreclrpal)
+
+target_link_libraries(paltest_getenvironmentvariablea_test6
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableA/test6/test6.c b/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableA/test6/test6.c
new file mode 100644
index 0000000000..8ef7571f59
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableA/test6/test6.c
@@ -0,0 +1,99 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+** Source : test6.c
+**
+** Purpose: Test for GetEnvironmentVariableA() function
+** Create environment variables that differ only
+** in case and verify that they return the appropriate
+** value on the BSD environment.
+**
+
+**
+===========================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+
+#if WIN32
+
+ /* Define some buffers needed for the function */
+ char * pResultBuffer = NULL;
+
+ char FirstEnvironmentVariable[] = {"PALTEST"};
+ char FirstEnvironmentValue[] = {"FIRST"};
+ char ModifiedEnvVar[] = {"paltest"};
+
+ DWORD size = 0;
+ BOOL bRc = TRUE;
+
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /* Set the first environment variable */
+ bRc = SetEnvironmentVariableA(FirstEnvironmentVariable,
+ FirstEnvironmentValue);
+
+ if(!bRc)
+ {
+ Fail("ERROR: SetEnvironmentVariable failed to set a "
+ "proper environment variable with error %u.\n",
+ GetLastError());
+ }
+
+ /* Normal case, PATH should fit into this buffer */
+ size = GetEnvironmentVariableA(ModifiedEnvVar,
+ pResultBuffer,
+ 0);
+
+ /* To account for the nul character at the end of the string */
+ size = size + 1;
+
+ pResultBuffer = malloc(sizeof(char)*size);
+ if ( pResultBuffer == NULL )
+ {
+ Fail("ERROR: Failed to allocate memory for pResultBuffer pointer.\n");
+ }
+
+ /* Try to retrieve the value of the first environment variable */
+ GetEnvironmentVariableA(ModifiedEnvVar,
+ pResultBuffer,
+ size);
+
+ if ( pResultBuffer == NULL )
+ {
+ free(pResultBuffer);
+ Fail("ERROR: GetEnvironmentVariable failed to return a value "
+ "from a proper environment variable with error %u.\n",
+ GetLastError());
+ }
+
+ /* Compare the strings to see that the correct variable was returned */
+ if(strcmp(pResultBuffer,FirstEnvironmentValue) != 0)
+ {
+ free(pResultBuffer);
+ Fail("ERROR: The value in the buffer should have been '%s' but "
+ "was really '%s'.\n",FirstEnvironmentValue, pResultBuffer);
+ }
+
+ free(pResultBuffer);
+
+ PAL_Terminate();
+ return PASS;
+
+
+#else
+
+ return PASS;
+#endif
+}
diff --git a/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableA/test6/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableA/test6/testinfo.dat
new file mode 100644
index 0000000000..5de219a959
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableA/test6/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = GetEnvironmentVariableA
+Name = Positive Test for GetEnvironmentVariableA
+TYPE = DEFAULT
+EXE1 = test6
+Description
+= Set an Environment Variable, then use GetEnvironmentVariable
+= to retrieve the Variable, using a name that differs only in
+= Case. In Windows this should not affect the return value
+= of the function.
diff --git a/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableW/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableW/CMakeLists.txt
new file mode 100644
index 0000000000..7c20179353
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableW/CMakeLists.txt
@@ -0,0 +1,9 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+add_subdirectory(test3)
+add_subdirectory(test4)
+add_subdirectory(test5)
+add_subdirectory(test6)
+
diff --git a/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableW/test1/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableW/test1/CMakeLists.txt
new file mode 100644
index 0000000000..567c992461
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableW/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.c
+)
+
+add_executable(paltest_getenvironmentvariablew_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getenvironmentvariablew_test1 coreclrpal)
+
+target_link_libraries(paltest_getenvironmentvariablew_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableW/test1/test.c b/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableW/test1/test.c
new file mode 100644
index 0000000000..6c764509d0
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableW/test1/test.c
@@ -0,0 +1,79 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source : test.c
+**
+** Purpose: Test for GetEnvironmentVariable() function
+**
+**
+**=========================================================*/
+
+#define UNICODE
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ /* Define some buffers needed for the function */
+ WCHAR * pResultBuffer = NULL;
+ int size = 0;
+
+ /* A place to stash the returned values */
+ int ReturnValueForLargeBuffer = 0;
+
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /* Recieve and allocate the correct amount of memory for the buffer */
+ size = ReturnValueForLargeBuffer =
+ GetEnvironmentVariable(convert("PATH"),
+ pResultBuffer,
+ 0);
+
+ pResultBuffer = malloc(size*sizeof(WCHAR));
+ if ( pResultBuffer == NULL )
+ {
+ Fail("ERROR: Failed to allocate memory for pResultBuffer pointer. "
+ "Can't properly exec test case without this.\n");
+ }
+
+
+ /* Normal case, PATH should fit into this buffer */
+ ReturnValueForLargeBuffer = GetEnvironmentVariable(convert("PATH"),
+ pResultBuffer,
+ size);
+ free(pResultBuffer);
+
+ /* Ensure that it returned a positive value */
+ if(ReturnValueForLargeBuffer <= 0)
+ {
+ Fail("The return was %d, which indicates that the function failed.\n",
+ ReturnValueForLargeBuffer);
+ }
+
+ /* Ensure that it succeeded and copied the correct number of characters.
+ If this is true, then the return value should be one less of the
+ size of the buffer. (Doesn't include that NULL byte)
+ */
+ if(ReturnValueForLargeBuffer != size-1)
+ {
+ Fail("The value returned was %d when it should have been %d. This "
+ "should be the number of characters copied, "
+ "minus the NULL byte.\n", ReturnValueForLargeBuffer, size-1);
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableW/test1/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableW/test1/testinfo.dat
new file mode 100644
index 0000000000..467f2b7b94
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableW/test1/testinfo.dat
@@ -0,0 +1,16 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = GetEnvironmentVariableW
+Name = Return value test for GetEnvironmentVariableW
+TYPE = DEFAULT
+EXE1 = test
+Description
+= Assign a properly sized buffer and get an environment variable,
+= check to ensure it returns the correct values.
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableW/test2/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableW/test2/CMakeLists.txt
new file mode 100644
index 0000000000..7234f61ed3
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableW/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.c
+)
+
+add_executable(paltest_getenvironmentvariablew_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getenvironmentvariablew_test2 coreclrpal)
+
+target_link_libraries(paltest_getenvironmentvariablew_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableW/test2/test.c b/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableW/test2/test.c
new file mode 100644
index 0000000000..6fa753c8d3
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableW/test2/test.c
@@ -0,0 +1,56 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source : test.c
+**
+** Purpose: Test for GetEnvironmentVariable() function
+**
+**
+**=========================================================*/
+
+#define UNICODE
+
+#include <palsuite.h>
+
+#define SMALL_BUFFER_SIZE 1
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ WCHAR pSmallBuffer[SMALL_BUFFER_SIZE];
+
+ /* A place to stash the returned values */
+ int ReturnValueForSmallBuffer;
+
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /* PATH won't fit in this buffer, it should return how many characters
+ it needs
+ */
+
+ ReturnValueForSmallBuffer = GetEnvironmentVariable(convert("PATH"),
+ pSmallBuffer,
+ SMALL_BUFFER_SIZE);
+
+ if(ReturnValueForSmallBuffer <= 0)
+ {
+ Fail("The return value was %d when it should have been greater "
+ "than 0. This should return the number of characters needed "
+ "to contained the contents of PATH in a buffer.\n",
+ ReturnValueForSmallBuffer);
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableW/test2/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableW/test2/testinfo.dat
new file mode 100644
index 0000000000..372f5af316
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableW/test2/testinfo.dat
@@ -0,0 +1,16 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = GetEnvironmentVariableW
+Name = Return value test on GetEnvironmentVariableW
+TYPE = DEFAULT
+EXE1 = test
+Description
+= Pass a small buffer to GetEnvironmentVariableW
+= to ensure it returns the size it requires.
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableW/test3/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableW/test3/CMakeLists.txt
new file mode 100644
index 0000000000..bafd75e52e
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableW/test3/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.c
+)
+
+add_executable(paltest_getenvironmentvariablew_test3
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getenvironmentvariablew_test3 coreclrpal)
+
+target_link_libraries(paltest_getenvironmentvariablew_test3
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableW/test3/test.c b/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableW/test3/test.c
new file mode 100644
index 0000000000..03781e723f
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableW/test3/test.c
@@ -0,0 +1,71 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source : test.c
+**
+** Purpose: Test for GetEnvironmentVariable() function
+**
+**
+**=========================================================*/
+
+#define UNICODE
+#include <palsuite.h>
+
+#define BUFFER_SIZE 5000
+#define SMALL_BUFFER_SIZE 5
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ /* Define some buffers needed for the function */
+ WCHAR pResultBuffer[BUFFER_SIZE];
+ WCHAR pSmallBuffer[SMALL_BUFFER_SIZE];
+
+ /* A place to stash the returned values */
+ int ReturnValueForNonExisting, ReturnValueForNull;
+
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /* This variable doesn't exist, it should return 0 */
+ ReturnValueForNonExisting =
+ GetEnvironmentVariable(convert("NonExistingVariable"),
+ pSmallBuffer,
+ SMALL_BUFFER_SIZE);
+
+ if(ReturnValueForNonExisting != 0)
+ {
+ Fail("ERROR: The return should have been 0, but it was %d. The "
+ "function attempted to get an Environment Variable that doesn't "
+ "exist and should return 0 as a result.\n",
+ ReturnValueForNonExisting);
+ }
+
+
+ /* Passing a NULL string should return 0 */
+ ReturnValueForNull = GetEnvironmentVariable(NULL,
+ pResultBuffer,
+ BUFFER_SIZE);
+
+ if(ReturnValueForNull != 0)
+ {
+ Fail("ERROR: The return should have been 0, but it was %d. The "
+ "function attempted to get a NULL pointer and should return 0 "
+ "as a result.\n",ReturnValueForNull);
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableW/test3/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableW/test3/testinfo.dat
new file mode 100644
index 0000000000..d41c19c908
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableW/test3/testinfo.dat
@@ -0,0 +1,16 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = GetEnvironmentVariableW
+Name = Return value test for GetEnvironmentVariableW
+TYPE = DEFAULT
+EXE1 = test
+Description
+= Pass a nonexisting environment variable and a null to the function
+= to check return values.
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableW/test4/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableW/test4/CMakeLists.txt
new file mode 100644
index 0000000000..f870bd6b22
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableW/test4/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.c
+)
+
+add_executable(paltest_getenvironmentvariablew_test4
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getenvironmentvariablew_test4 coreclrpal)
+
+target_link_libraries(paltest_getenvironmentvariablew_test4
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableW/test4/test.c b/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableW/test4/test.c
new file mode 100644
index 0000000000..b5894efc6e
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableW/test4/test.c
@@ -0,0 +1,63 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source : test.c
+**
+** Purpose: Test for GetEnvironmentVariable() function
+**
+**
+**=========================================================*/
+
+/* Depends on SetEnvironmentVariableW (because we're implmenting the wide
+ version) and strcmp() */
+
+#define UNICODE
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[]) {
+
+ /* Define some buffers needed for the function */
+ WCHAR * pResultBuffer = NULL;
+ WCHAR SomeEnvironmentVariable[] = {'P','A','L','T','E','S','T','\0'};
+ WCHAR TheEnvironmentValue[] = {'T','E','S','T','\0'};
+ int size;
+
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ SetEnvironmentVariable(SomeEnvironmentVariable,
+ TheEnvironmentValue);
+
+
+ /* Normal case, PATH should fit into this buffer */
+ size = GetEnvironmentVariable(convert("PALTEST"), // Variable Name
+ pResultBuffer, // Buffer for Value
+ 0); // Buffer size
+
+ pResultBuffer = malloc(size*sizeof(WCHAR));
+
+ GetEnvironmentVariable(convert("PALTEST"),
+ pResultBuffer,
+ size);
+
+ if(wcsncmp(pResultBuffer,convert("TEST"),wcslen(pResultBuffer) * 2) != 0)
+ {
+ Fail("ERROR: The value in the buffer should have been 'TEST' but was "
+ "really '%s'.",convertC(pResultBuffer));
+ }
+
+ free(pResultBuffer);
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableW/test4/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableW/test4/testinfo.dat
new file mode 100644
index 0000000000..64204fa698
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableW/test4/testinfo.dat
@@ -0,0 +1,16 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = GetEnvironmentVariableW
+Name = Positive Test for GetEnvironmentVariableW
+TYPE = DEFAULT
+EXE1 = test
+Description
+= Set an Environment Variable, then use GetEnvironmentVariable
+= to retrieve it -- ensure that it retrieves properly.
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableW/test5/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableW/test5/CMakeLists.txt
new file mode 100644
index 0000000000..ab44781279
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableW/test5/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test5.c
+)
+
+add_executable(paltest_getenvironmentvariablew_test5
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getenvironmentvariablew_test5 coreclrpal)
+
+target_link_libraries(paltest_getenvironmentvariablew_test5
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableW/test5/test5.c b/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableW/test5/test5.c
new file mode 100644
index 0000000000..58eba3a380
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableW/test5/test5.c
@@ -0,0 +1,144 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+** Source : test5.c
+**
+** Purpose: Test for GetEnvironmentVariableW() function
+** Create environment variables that differ only
+** in case and verify that they return the appropriate
+** value on the BSD environment.
+**
+**
+===========================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+
+#if WIN32
+
+ return PASS;
+
+#else
+
+ /* Define some buffers needed for the function */
+ WCHAR * pResultBuffer = NULL;
+
+ WCHAR FirstEnvironmentVariable[] = {'P','A','L','T','E','S','T','\0'};
+ WCHAR FirstEnvironmentValue[] = {'F','I','R','S','T','\0'};
+
+ WCHAR SecondEnvironmentVariable[] = {'p','a','l','t','e','s','t','\0'};
+ WCHAR SecondEnvironmentValue[] = {'S','E','C','O','N','D','\0'};
+
+ DWORD size = 0;
+ BOOL bRc = TRUE;
+
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /* Set the first environment variable */
+ bRc = SetEnvironmentVariableW(FirstEnvironmentVariable,
+ FirstEnvironmentValue);
+
+ if(!bRc)
+ {
+ Fail("ERROR: SetEnvironmentVariable failed to set a "
+ "proper environment variable with error %u.\n", GetLastError());
+ }
+
+ /* Normal case, PATH should fit into this buffer */
+ size = GetEnvironmentVariableW(FirstEnvironmentVariable,
+ pResultBuffer,
+ 0);
+
+ /* To account for the nul character at the end of the string */
+ size = size + 1;
+
+ pResultBuffer = malloc(sizeof(WCHAR)*size);
+ if ( pResultBuffer == NULL )
+ {
+ Fail("ERROR: Failed to allocate memory for pResultBuffer pointer.\n");
+ }
+
+ /* Try to retrieve the value of the first environment variable */
+ GetEnvironmentVariableW(FirstEnvironmentVariable,
+ pResultBuffer,
+ size);
+
+ if ( pResultBuffer == NULL )
+ {
+ free(pResultBuffer);
+ Fail("ERROR: GetEnvironmentVariable failed to return a value "
+ "from a proper environment variable with error %u.\n",
+ GetLastError());
+ }
+
+ /* Compare the strings to see that the correct variable was returned */
+ if(wcsncmp(pResultBuffer,FirstEnvironmentValue,wcslen(pResultBuffer)) != 0)
+ {
+ free(pResultBuffer);
+ Fail("ERROR: The value in the buffer should have been '%S' but "
+ "was really '%S'.\n",FirstEnvironmentValue, pResultBuffer);
+ }
+
+ free(pResultBuffer);
+
+ /* Set the second environment Variable */
+ bRc = SetEnvironmentVariableW(SecondEnvironmentVariable,
+ SecondEnvironmentValue);
+
+ if(!bRc)
+ {
+ Fail("ERROR: SetEnvironmentVariable failed to set a "
+ "proper environment variable with error %u.\n",
+ GetLastError());
+ }
+
+ /* Reallocate the memory for the string */
+ pResultBuffer = malloc(sizeof(WCHAR)*size);
+ if ( pResultBuffer == NULL )
+ {
+ Fail("ERROR: Failed to allocate memory for pResultBuffer pointer.\n");
+ }
+
+ /* Try retrieving the value of the first variable, even though the
+ second variable has the same spelling and only differs in case */
+ GetEnvironmentVariableW(FirstEnvironmentVariable,
+ pResultBuffer,
+ size);
+
+ if ( pResultBuffer == NULL )
+ {
+ free(pResultBuffer);
+ Fail("ERROR: GetEnvironmentVariable failed to return a value "
+ "from a proper environment variable with error %u.\n",
+ GetLastError());
+ }
+
+ /* Compare the two strings to confirm that the right value is returned */
+ if(wcsncmp(pResultBuffer,FirstEnvironmentValue,wcslen(pResultBuffer)) != 0)
+ {
+ free(pResultBuffer);
+ Fail("ERROR: The value in the buffer should have been '%S' but "
+ "was really '%S'.\n",FirstEnvironmentValue,pResultBuffer);
+ }
+
+ free(pResultBuffer);
+
+ PAL_Terminate();
+ return PASS;
+
+#endif
+}
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableW/test5/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableW/test5/testinfo.dat
new file mode 100644
index 0000000000..cbc214e8ca
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableW/test5/testinfo.dat
@@ -0,0 +1,17 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = GetEnvironmentVariableW
+Name = Positive Test for GetEnvironmentVariableW
+TYPE = DEFAULT
+EXE1 = test5
+Description
+= Set an Environment Variable, then use GetEnvironmentVariable
+= to retrieve it. Then set another environment variable that differs
+= from the original variable only by case and verify that
+= GetEnvironmnetVariable returns the correct value.
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableW/test6/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableW/test6/CMakeLists.txt
new file mode 100644
index 0000000000..e504c8323a
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableW/test6/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test6.c
+)
+
+add_executable(paltest_getenvironmentvariablew_test6
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getenvironmentvariablew_test6 coreclrpal)
+
+target_link_libraries(paltest_getenvironmentvariablew_test6
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableW/test6/test6.c b/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableW/test6/test6.c
new file mode 100644
index 0000000000..85f31be9c2
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableW/test6/test6.c
@@ -0,0 +1,99 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+** Source : test6.c
+**
+** Purpose: Test for GetEnvironmentVariableW() function
+** Create environment variables that differ only
+** in case and verify that they return the appropriate
+** value on the BSD environment.
+**
+**
+===========================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+
+#if WIN32
+
+ /* Define some buffers needed for the function */
+ WCHAR * pResultBuffer = NULL;
+
+ WCHAR FirstEnvironmentVariable[] = {'P','A','L','T','E','S','T','\0'};
+ WCHAR FirstEnvironmentValue[] = {'F','I','R','S','T','\0'};
+
+ WCHAR ModifiedEnvironmentVariable[] = {'p','a','l','t','e','s','t','\0'};
+
+ DWORD size = 0;
+ BOOL bRc = TRUE;
+
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /* Set the first environment variable */
+ bRc = SetEnvironmentVariableW(FirstEnvironmentVariable,
+ FirstEnvironmentValue);
+
+ if(!bRc)
+ {
+ Fail("ERROR: SetEnvironmentVariable failed to set a "
+ "proper environment variable with error %u.\n",
+ GetLastError());
+ }
+
+ /* Normal case, PATH should fit into this buffer */
+ size = GetEnvironmentVariableW(ModifiedEnvironmentVariable,
+ pResultBuffer,
+ 0);
+
+ /* To account for the nul character at the end of the string */
+ size = size + 1;
+
+ pResultBuffer = malloc(sizeof(WCHAR)*size);
+ if ( pResultBuffer == NULL )
+ {
+ Fail("ERROR: Failed to allocate memory for pResultBuffer pointer.\n");
+ }
+
+ /* Try to retrieve the value of the first environment variable */
+ GetEnvironmentVariableW(ModifiedEnvironmentVariable,
+ pResultBuffer,
+ size);
+
+ if ( pResultBuffer == NULL )
+ {
+ free(pResultBuffer);
+ Fail("ERROR: GetEnvironmentVariable failed to return a value "
+ "from a proper environment variable with error %u.\n",
+ GetLastError());
+ }
+
+ /* Compare the strings to see that the correct variable was returned */
+ if(wcsncmp(pResultBuffer,FirstEnvironmentValue,wcslen(pResultBuffer)) != 0)
+ {
+ free(pResultBuffer);
+ Fail("ERROR: The value in the buffer should have been '%S' but "
+ "was really '%S'.\n",FirstEnvironmentValue, pResultBuffer);
+ }
+
+ free(pResultBuffer);
+
+ PAL_Terminate();
+ return PASS;
+
+
+#else
+
+ return PASS;
+#endif
+}
diff --git a/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableW/test6/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableW/test6/testinfo.dat
new file mode 100644
index 0000000000..fad1ad69a6
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetEnvironmentVariableW/test6/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = GetEnvironmentVariableW
+Name = Positive Test for GetEnvironmentVariableW
+TYPE = DEFAULT
+EXE1 = test6
+Description
+= Set an Environment Variable, then use GetEnvironmentVariable
+= to retrieve the Variable, using a name that differs only in
+= Case. In Windows this should not affect the return value
+= of the function.
diff --git a/src/pal/tests/palsuite/miscellaneous/GetLastError/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/GetLastError/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetLastError/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/miscellaneous/GetLastError/test1/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/GetLastError/test1/CMakeLists.txt
new file mode 100644
index 0000000000..09e650c924
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetLastError/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.c
+)
+
+add_executable(paltest_getlasterror_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getlasterror_test1 coreclrpal)
+
+target_link_libraries(paltest_getlasterror_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/GetLastError/test1/test.c b/src/pal/tests/palsuite/miscellaneous/GetLastError/test1/test.c
new file mode 100644
index 0000000000..65f56e595f
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetLastError/test1/test.c
@@ -0,0 +1,63 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source : test.c
+**
+** Purpose: Test for GetLastError() function
+**
+**
+**=========================================================*/
+
+/* Depends on SetLastError() */
+
+#include <palsuite.h>
+
+/**
+ * Helper functions that does the actual test
+ */
+static void test(DWORD error )
+{
+ DWORD TheResult;
+
+ /* Set error */
+ SetLastError(error);
+
+ /* Check to make sure it returns the error value we just set */
+ TheResult = GetLastError();
+ if(TheResult!= error)
+ {
+ Fail("ERROR: The last error should have been %u, but when "
+ "GetLastError was called, it returned %u.\n",error,TheResult);
+ }
+
+}
+
+int __cdecl main(int argc, char *argv[]) {
+
+
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /* test setting and getting some values */
+ test(5);
+ test(0xffffffff);
+ test(0xEEEEEEEE);
+ test(0xAAAAAAAA);
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/GetLastError/test1/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/GetLastError/test1/testinfo.dat
new file mode 100644
index 0000000000..be41f52c63
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetLastError/test1/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = GetLastError
+Name = Positive Test for GetLastError
+TYPE = DEFAULT
+EXE1 = test
+Description
+= Ensure GetLastError returns the error message which was set.
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/GetSystemInfo/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/GetSystemInfo/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetSystemInfo/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/miscellaneous/GetSystemInfo/test1/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/GetSystemInfo/test1/CMakeLists.txt
new file mode 100644
index 0000000000..960291fe79
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetSystemInfo/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.c
+)
+
+add_executable(paltest_getsysteminfo_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getsysteminfo_test1 coreclrpal)
+
+target_link_libraries(paltest_getsysteminfo_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/GetSystemInfo/test1/test.c b/src/pal/tests/palsuite/miscellaneous/GetSystemInfo/test1/test.c
new file mode 100644
index 0000000000..5f3608fb70
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetSystemInfo/test1/test.c
@@ -0,0 +1,70 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source : test.c
+**
+** Purpose: Test for GetSystemInfo() function
+**
+**
+**=========================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[]) {
+
+ SYSTEM_INFO TheSystemInfo;
+ SYSTEM_INFO* pSystemInfo = &TheSystemInfo;
+
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ GetSystemInfo(pSystemInfo);
+
+ /* Ensure both valules are > than 0 */
+ if(pSystemInfo->dwNumberOfProcessors < 1)
+ {
+ Fail("ERROR: The dwNumberofProcessors values should be > 0.");
+ }
+
+ if(pSystemInfo->dwPageSize < 1)
+ {
+ Fail("ERROR: The dwPageSize should be greater than 0.");
+ }
+
+ /* If this isn't WIN32, ensure all the other variables are 0 */
+
+#if UNIX
+ if(pSystemInfo->dwOemId != 0 ||
+ pSystemInfo->wProcessorArchitecture != 0 ||
+ pSystemInfo->wReserved != 0 ||
+ pSystemInfo->lpMinimumApplicationAddress != 0 ||
+ pSystemInfo->lpMaximumApplicationAddress != 0 ||
+ pSystemInfo->dwActiveProcessorMask != 0 ||
+ pSystemInfo->dwProcessorType !=0 ||
+ pSystemInfo->dwAllocationGranularity !=0 ||
+ pSystemInfo->wProcessorLevel != 0 ||
+ pSystemInfo->wProcessorRevision != 0) {
+ Fail("ERROR: Under FreeBSD, OemId, ProcessorArchitecture, Reserved, "
+ "MinimumApplicationAddress, MaximumApplicationAddress, "
+ "ActiveProcessorMask, ProcessorType, AllocationGranularity, "
+ "ProcessorLevel and ProcessorRevision should be equal to 0.");
+
+
+ }
+#endif
+
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/GetSystemInfo/test1/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/GetSystemInfo/test1/testinfo.dat
new file mode 100644
index 0000000000..7f03c6355c
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetSystemInfo/test1/testinfo.dat
@@ -0,0 +1,16 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = GetSystemInfo
+Name = Positive Test for GetSystemInfo
+TYPE = DEFAULT
+EXE1 = test
+Description
+= Ensures the two required System Info fields can be aquired,
+= and the others are all 0.
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/GetTickCount/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/GetTickCount/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetTickCount/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/miscellaneous/GetTickCount/test1/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/GetTickCount/test1/CMakeLists.txt
new file mode 100644
index 0000000000..5c6ea26a41
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetTickCount/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.c
+)
+
+add_executable(paltest_gettickcount_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_gettickcount_test1 coreclrpal)
+
+target_link_libraries(paltest_gettickcount_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/GetTickCount/test1/test.c b/src/pal/tests/palsuite/miscellaneous/GetTickCount/test1/test.c
new file mode 100644
index 0000000000..ad71ba5d6c
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetTickCount/test1/test.c
@@ -0,0 +1,58 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source:
+**
+** Source : test1.c
+**
+** Purpose: Test for GetTickCount() function
+**
+**
+**=========================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[]) {
+
+ DWORD FirstCount = 0;
+ DWORD SecondCount = 0;
+
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /* Grab a FirstCount, then loop for a bit to make the clock increase */
+ FirstCount = GetTickCount();
+
+ /* Make sure some time passes */
+ Sleep(60); //Since the get tick count is accurate within 55 milliseconds.
+
+ /* Get a second count */
+ SecondCount = GetTickCount();
+
+ /* Make sure the second one is bigger than the first.
+ This isn't the best test, but it at least shows that it's returning a
+ DWORD which is increasing.
+ */
+
+ if(FirstCount >= SecondCount)
+ {
+ Fail("ERROR: The first time (%d) was greater/equal than the second time "
+ " (%d). The tick count should have increased.\n",
+ FirstCount,SecondCount);
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/GetTickCount/test1/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/GetTickCount/test1/testinfo.dat
new file mode 100644
index 0000000000..78888abd53
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetTickCount/test1/testinfo.dat
@@ -0,0 +1,16 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = GetTickCount
+Name = Positive Test for GetTickCount
+TYPE = DEFAULT
+EXE1 = test
+Description
+= Grab two Tick Counts with this function, and ensure that
+= the second is larger to show that the tick count is increasing.
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/GetUserNameW/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/GetUserNameW/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetUserNameW/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/miscellaneous/GetUserNameW/test1/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/GetUserNameW/test1/CMakeLists.txt
new file mode 100644
index 0000000000..a1d5ab21b8
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetUserNameW/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.c
+)
+
+add_executable(paltest_getusernamew_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getusernamew_test1 coreclrpal)
+
+target_link_libraries(paltest_getusernamew_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/GetUserNameW/test1/test.c b/src/pal/tests/palsuite/miscellaneous/GetUserNameW/test1/test.c
new file mode 100644
index 0000000000..809f14c12d
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetUserNameW/test1/test.c
@@ -0,0 +1,52 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source : test.c
+**
+** Purpose: Positive Test for GetUserName() function
+**
+**
+**=========================================================*/
+
+#define UNICODE
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ WCHAR wzUserName[UNLEN+1];
+ DWORD dwSize = sizeof(wzUserName)/sizeof(wzUserName[0]);
+
+ // Initialize the PAL and return FAILURE if this fails
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ Fail ("ERROR: PAL_Initialize() call failed!\n");
+ }
+
+ if (0 == GetUserName(wzUserName, &dwSize))
+ {
+ Fail("ERROR: GetUserName failed with %d!\n", GetLastError());
+ }
+
+ // dwSize is the length of wzUserName with NULL
+ if (dwSize <= 0 || dwSize > (sizeof(wzUserName)/sizeof(wzUserName[0])))
+ {
+ Fail("ERROR: GetUserName returned %S with dwSize = %u whereas the passed in buffer size is %d!\n",
+ wzUserName, dwSize, sizeof(wzUserName)/sizeof(wzUserName[0]));
+ }
+
+ // dwSize is the length of wzUserName with NULL
+ if (dwSize != wcslen(wzUserName)+1)
+ {
+ Fail("ERROR: GetUserName returned %S of length %d which is not equal to dwSize-1 = %u!\n",
+ wzUserName, wcslen(wzUserName), dwSize-1);
+ }
+
+ printf ("GetUserName returned %S of length %u\n", wzUserName, dwSize-1);
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/miscellaneous/GetUserNameW/test1/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/GetUserNameW/test1/testinfo.dat
new file mode 100644
index 0000000000..3e0aa48bd0
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetUserNameW/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = GetUserNameW
+Name = Test for GetUserNameW
+TYPE = DEFAULT
+EXE1 = test
+Description
+= Check to ensure that GetUserNameW returnes a decent value.
+
diff --git a/src/pal/tests/palsuite/miscellaneous/GetVersionExA/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/GetVersionExA/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetVersionExA/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/miscellaneous/GetVersionExA/test1/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/GetVersionExA/test1/CMakeLists.txt
new file mode 100644
index 0000000000..b9dd711d36
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetVersionExA/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.c
+)
+
+add_executable(paltest_getversionexa_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getversionexa_test1 coreclrpal)
+
+target_link_libraries(paltest_getversionexa_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/GetVersionExA/test1/test.c b/src/pal/tests/palsuite/miscellaneous/GetVersionExA/test1/test.c
new file mode 100644
index 0000000000..5dd20c6576
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetVersionExA/test1/test.c
@@ -0,0 +1,83 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source : test.c
+**
+** Purpose: Test for GetVersionExA() function
+**
+**
+**=========================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[]) {
+
+ OSVERSIONINFO TheVersionInfo;
+ OSVERSIONINFO* pVersionInfo = &TheVersionInfo;
+
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+
+ /* This needs to be done before using GetVersionEx */
+ pVersionInfo->dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+
+ /* If GetVersionEx fails, then the test fails */
+ if(GetVersionEx(pVersionInfo) == 0)
+ {
+ Fail("ERROR: The GetVersionEx function returned 0, which indicates "
+ "failure.");
+ }
+
+ /* These values are fixed, ensure they're set properly */
+ if(pVersionInfo->dwMajorVersion != 5)
+ {
+ Fail("ERROR: The fixed value of dwMajorVersion shoud be 5, "
+ "but is really %d.",pVersionInfo->dwMajorVersion);
+ }
+
+ /* The minor version values for Win2k and XP are different
+ for Win2k minor version equals 0 and for XP minor version
+ equals 1. Both values are excepted here. */
+ if((pVersionInfo->dwMinorVersion != 0) &&
+ (pVersionInfo->dwMinorVersion != 1))
+ {
+ Fail("ERROR: The fixed value of dwMinorVersion shoud be 0 or 1, "
+ "but is really %d.",pVersionInfo->dwMinorVersion);
+ }
+ if(pVersionInfo->dwBuildNumber_PAL_Undefined < 0)
+ {
+ Fail("ERROR: The value of dwBuildNumber shoud be at least 0, but "
+ "is really %d.",pVersionInfo->dwBuildNumber_PAL_Undefined);
+ }
+
+#if !WIN32
+ /* Under BSD, the PlatformID should be UNIX and the Service Pack
+ version should be set to "".
+ */
+
+ if(pVersionInfo->dwPlatformId != VER_PLATFORM_UNIX ||
+ pVersionInfo->szCSDVersion_PAL_Undefined[0] != 0)
+ {
+ Fail("ERROR: The dwPlatformId should be %d but is really %d. And the "
+ "szCSDVerion should be NULL.",
+ VER_PLATFORM_UNIX,pVersionInfo->dwPlatformId);
+ }
+#endif
+
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/GetVersionExA/test1/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/GetVersionExA/test1/testinfo.dat
new file mode 100644
index 0000000000..1e9c570c60
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetVersionExA/test1/testinfo.dat
@@ -0,0 +1,16 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = GetVersionExA
+Name = Positive Test for GetVersionExA
+TYPE = DEFAULT
+EXE1 = test
+Description
+= Test that all the values in the OSVERSION structure are set properly
+= for the current environment.
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/GetVersionExW/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/GetVersionExW/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetVersionExW/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/miscellaneous/GetVersionExW/test1/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/GetVersionExW/test1/CMakeLists.txt
new file mode 100644
index 0000000000..d7eb683343
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetVersionExW/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.c
+)
+
+add_executable(paltest_getversionexw_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getversionexw_test1 coreclrpal)
+
+target_link_libraries(paltest_getversionexw_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/GetVersionExW/test1/test.c b/src/pal/tests/palsuite/miscellaneous/GetVersionExW/test1/test.c
new file mode 100644
index 0000000000..69aae54bcf
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetVersionExW/test1/test.c
@@ -0,0 +1,88 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source : test.c
+**
+** Purpose: Test for GetVersionExW() function
+**
+**
+**=========================================================*/
+
+#define UNICODE
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ OSVERSIONINFO TheVersionInfo;
+ OSVERSIONINFO* pVersionInfo = &TheVersionInfo;
+
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /* This needs to be done before using GetVersionEx */
+ pVersionInfo->dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+
+ /* If GetVersionEx fails, then the test fails */
+ if(GetVersionEx(pVersionInfo) == 0)
+ {
+ Fail("ERROR: The GetVersionEx function returned 0, which indicates "
+ "failure.");
+ }
+
+ /* These values are fixed, ensure they're set properly */
+ if(pVersionInfo->dwMajorVersion != 5)
+ {
+ Fail("ERROR: The fixed value of dwMajorVersion shoud be 5, but is "
+ " really %d.",pVersionInfo->dwMajorVersion);
+ }
+
+ /* The minor version values for Win2k and XP are different
+ for Win2k minor version equals 0 and for XP minor version
+ equals 1. Both values are excepted here. */
+ if((pVersionInfo->dwMinorVersion != 0) &&
+ (pVersionInfo->dwMinorVersion != 1))
+ {
+ Fail("ERROR: The fixed value of dwMinorVersion shoud be 0 or 1, "
+ "but is really %d.",pVersionInfo->dwMinorVersion);
+ }
+
+ if(pVersionInfo->dwBuildNumber_PAL_Undefined < 0)
+ {
+ Fail("ERROR: The value of dwBuildNumber shoud be at least 0, but is "
+ "really %d.",pVersionInfo->dwBuildNumber_PAL_Undefined);
+ }
+
+#if !WIN32
+
+
+ /* Under BSD, the PlatformID should be UNIX and the Service Pack
+ version should be set to "".
+ */
+
+ if(pVersionInfo->dwPlatformId != VER_PLATFORM_UNIX ||
+ pVersionInfo->szCSDVersion_PAL_Undefined[0] != 0)
+ {
+ Fail("ERROR: The dwPlatformId should be %d but is really %d. And the "
+ "szCSDVerion should be NULL.",VER_PLATFORM_UNIX,
+ pVersionInfo->dwPlatformId);
+ }
+#endif
+
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/GetVersionExW/test1/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/GetVersionExW/test1/testinfo.dat
new file mode 100644
index 0000000000..7773245b3f
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/GetVersionExW/test1/testinfo.dat
@@ -0,0 +1,16 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = GetVersionExW
+Name = Positive Test for GetVersionExW
+TYPE = DEFAULT
+EXE1 = test
+Description
+= Test that all the values in the OSVERSION structure are set properly
+= for the current environment.
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/InterLockedExchangeAdd/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/InterLockedExchangeAdd/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/InterLockedExchangeAdd/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/miscellaneous/InterLockedExchangeAdd/test1/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/InterLockedExchangeAdd/test1/CMakeLists.txt
new file mode 100644
index 0000000000..e5ba709c11
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/InterLockedExchangeAdd/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.cpp
+)
+
+add_executable(paltest_interlockedexchangeadd_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_interlockedexchangeadd_test1 coreclrpal)
+
+target_link_libraries(paltest_interlockedexchangeadd_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/InterLockedExchangeAdd/test1/test.cpp b/src/pal/tests/palsuite/miscellaneous/InterLockedExchangeAdd/test1/test.cpp
new file mode 100644
index 0000000000..ca9e5bb5bf
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/InterLockedExchangeAdd/test1/test.cpp
@@ -0,0 +1,102 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source : test.c
+**
+** Purpose: InterlockedExchangeAdd() function
+**
+**
+**=========================================================*/
+
+/*
+** The InterlockedExchangeAdd function performs an atomic addition of Value
+** to the value pointed to by Addend.
+** The result is stored in the address specified by Addend.
+** The initial value of the variable pointed to by Addend is returned as the function value.
+*/
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ LONG TheReturn;
+
+ LONG *ptrValue = NULL;
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+
+
+#if defined(BIT64) && defined(PLATFORM_UNIX)
+ ptrValue = (LONG *) malloc(sizeof(LONG));
+
+ if(ptrValue == NULL)
+ {
+ Fail("Error:%d:Malloc failed for ptrValue\n", GetLastError());
+ }
+
+ *ptrValue = (LONG) 0;
+
+ TheReturn = InterlockedExchangeAdd( ptrValue, (LONG) 5);
+
+
+ /* Added, it should be 5 now */
+ if(*ptrValue != 5)
+ {
+
+ Trace("ERROR: After an add operation, the value should be 5, "
+ "but it is really %d.", *ptrValue);
+ free(ptrValue);
+ Fail("");
+ }
+
+ /* Check to make sure the function returns the original value (5 in this case) */
+ if(TheReturn != 0)
+ {
+ Trace("ERROR: The function should have returned the new value of %d "
+ "but instead returned %d.", *ptrValue, TheReturn);
+ free(ptrValue);
+ Fail("");
+ }
+
+ TheReturn = InterlockedExchangeAdd( ptrValue, (LONG) 1);
+
+
+ /* Added twice, it should be 6 now */
+ if(*ptrValue != 6)
+ {
+
+ Trace("ERROR: After having two add operations, the value should be 6, "
+ "but it is really %d.", *ptrValue);
+ free(ptrValue);
+ Fail("");
+ }
+
+ /* Check to make sure the function returns the original value (5 in this case) */
+ if(TheReturn != 5)
+ {
+ Trace("ERROR: The function should have returned the new value of %d "
+ "but instead returned %d.", *ptrValue, TheReturn);
+ free(ptrValue);
+ Fail("");
+ }
+
+ free(ptrValue);
+#endif
+ PAL_Terminate();
+ return PASS;
+}
+
+
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/InterlockedBit/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/InterlockedBit/CMakeLists.txt
new file mode 100644
index 0000000000..ef14ea5352
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/InterlockedBit/CMakeLists.txt
@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+
diff --git a/src/pal/tests/palsuite/miscellaneous/InterlockedBit/test1/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/InterlockedBit/test1/CMakeLists.txt
new file mode 100644
index 0000000000..a70802ea2d
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/InterlockedBit/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.cpp
+)
+
+add_executable(paltest_interlockedbit_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_interlockedbit_test1 coreclrpal)
+
+target_link_libraries(paltest_interlockedbit_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/InterlockedBit/test1/test.cpp b/src/pal/tests/palsuite/miscellaneous/InterlockedBit/test1/test.cpp
new file mode 100644
index 0000000000..1f7c43cddb
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/InterlockedBit/test1/test.cpp
@@ -0,0 +1,77 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source : test.c
+**
+** Purpose: Test for InterlockedBitTestAndReset() function
+**
+**
+**=========================================================*/
+
+#include <palsuite.h>
+
+typedef struct tag_TEST_DATA
+{
+ LONG baseValue;
+ UINT bitPosition;
+ LONG expectedValue;
+ UCHAR expectedReturnValue;
+} TEST_DATA;
+
+TEST_DATA test_data[] =
+{
+ { (LONG)0x00000000, 3, (LONG)0x00000000, 0 },
+ { (LONG)0x12341234, 2, (LONG)0x12341230, 1 },
+ { (LONG)0x12341234, 3, (LONG)0x12341234, 0 },
+ { (LONG)0x12341234, 31, (LONG)0x12341234, 0 },
+ { (LONG)0x12341234, 28, (LONG)0x02341234, 1 },
+ { (LONG)0xffffffff, 28, (LONG)0xefffffff, 1 }
+};
+
+int __cdecl main(int argc, char *argv[]) {
+
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ for (int i = 0; i < sizeof (test_data) / sizeof (TEST_DATA); i++)
+ {
+ LONG baseVal = test_data[i].baseValue;
+ LONG bitPosition = test_data[i].bitPosition;
+
+ UCHAR ret = InterlockedBitTestAndReset(
+ &baseVal, /* Variable to manipulate */
+ bitPosition);
+
+ if (ret != test_data[i].expectedReturnValue)
+ {
+ Fail("ERROR: InterlockedBitTestAndReset(%d): Expected return value is %d,"
+ "Actual return value is %d.",
+ i,
+ test_data[i].expectedReturnValue,
+ ret);
+ }
+
+ if (baseVal != test_data[i].expectedValue)
+ {
+ Fail("ERROR: InterlockedBitTestAndReset(%d): Expected value is %x,"
+ "Actual value is %x.",
+ i,
+ test_data[i].expectedValue,
+ baseVal);
+ }
+
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/miscellaneous/InterlockedBit/test1/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/InterlockedBit/test1/testinfo.dat
new file mode 100644
index 0000000000..677999906f
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/InterlockedBit/test1/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = InterlockedBitTestAndReset
+Name = Test for InterlockedBitTestAndReset
+TYPE = DEFAULT
+EXE1 = test
+Description
+Test validates that function InterlockedBitTestAndReset work as intended.
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/InterlockedBit/test2/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/InterlockedBit/test2/CMakeLists.txt
new file mode 100644
index 0000000000..6b50a755fe
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/InterlockedBit/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.cpp
+)
+
+add_executable(paltest_interlockedbit_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_interlockedbit_test2 coreclrpal)
+
+target_link_libraries(paltest_interlockedbit_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/InterlockedBit/test2/test.cpp b/src/pal/tests/palsuite/miscellaneous/InterlockedBit/test2/test.cpp
new file mode 100644
index 0000000000..4230c8a805
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/InterlockedBit/test2/test.cpp
@@ -0,0 +1,77 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source : test.c
+**
+** Purpose: Test for InterlockedBitTestAndSet() function
+**
+**
+**=========================================================*/
+
+#include <palsuite.h>
+
+typedef struct tag_TEST_DATA
+{
+ LONG baseValue;
+ UINT bitPosition;
+ LONG expectedValue;
+ UCHAR expectedReturnValue;
+} TEST_DATA;
+
+TEST_DATA test_data[] =
+{
+ { (LONG)0x00000000, 2, (LONG)0x00000004, 0 },
+ { (LONG)0x12341234, 2, (LONG)0x12341234, 1 },
+ { (LONG)0x12341234, 3, (LONG)0x1234123c, 0 },
+ { (LONG)0x12341234, 31, (LONG)0x92341234, 0 },
+ { (LONG)0x12341234, 28, (LONG)0x12341234, 1 },
+ { (LONG)0xffffffff, 28, (LONG)0xffffffff, 1 }
+};
+
+int __cdecl main(int argc, char *argv[]) {
+
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ for (int i = 0; i < sizeof (test_data) / sizeof (TEST_DATA); i++)
+ {
+ LONG baseVal = test_data[i].baseValue;
+ LONG bitPosition = test_data[i].bitPosition;
+
+ UCHAR ret = InterlockedBitTestAndSet(
+ &baseVal, /* Variable to manipulate */
+ bitPosition);
+
+ if (ret != test_data[i].expectedReturnValue)
+ {
+ Fail("ERROR: InterlockedBitTestAndSet(%d): Expected return value is %d,"
+ "Actual return value is %d.",
+ i,
+ test_data[i].expectedReturnValue,
+ ret);
+ }
+
+ if (baseVal != test_data[i].expectedValue)
+ {
+ Fail("ERROR: InterlockedBitTestAndSet(%d): Expected value is %x,"
+ "Actual value is %x.",
+ i,
+ test_data[i].expectedValue,
+ baseVal);
+ }
+
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/miscellaneous/InterlockedBit/test2/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/InterlockedBit/test2/testinfo.dat
new file mode 100644
index 0000000000..3ad431701a
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/InterlockedBit/test2/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = InterlockedBitTestAndSet
+Name = Test for InterlockedBitTestAndSet
+TYPE = DEFAULT
+EXE1 = test
+Description
+Test validates that function InterlockedBitTestAndSet work as intended.
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/InterlockedCompareExchange/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/InterlockedCompareExchange/CMakeLists.txt
new file mode 100644
index 0000000000..ef14ea5352
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/InterlockedCompareExchange/CMakeLists.txt
@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+
diff --git a/src/pal/tests/palsuite/miscellaneous/InterlockedCompareExchange/test1/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/InterlockedCompareExchange/test1/CMakeLists.txt
new file mode 100644
index 0000000000..d9e867256a
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/InterlockedCompareExchange/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.cpp
+)
+
+add_executable(paltest_interlockedcompareexchange_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_interlockedcompareexchange_test1 coreclrpal)
+
+target_link_libraries(paltest_interlockedcompareexchange_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/InterlockedCompareExchange/test1/test.cpp b/src/pal/tests/palsuite/miscellaneous/InterlockedCompareExchange/test1/test.cpp
new file mode 100644
index 0000000000..77f2c4c449
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/InterlockedCompareExchange/test1/test.cpp
@@ -0,0 +1,100 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source : test.c
+**
+** Purpose: Test for InterlockedCompareExchange() function
+**
+**
+**=========================================================*/
+
+/* This test is FINISHED. Note: The biggest feature of this function is that
+ it locks the value before it increments it -- in order to make it so only
+ one thread can access it. But, I really don't have a great test to make
+ sure it's thread safe. Any ideas?
+*/
+
+#include <palsuite.h>
+
+#define START_VALUE 0
+#define SECOND_VALUE 5
+#define THIRD_VALUE 10
+
+int __cdecl main(int argc, char *argv[]) {
+
+ int BaseVariableToManipulate = START_VALUE;
+ int ValueToExchange = SECOND_VALUE;
+ int TempValue;
+ int TheReturn;
+
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /* Compare START_VALUE with BaseVariableToManipulate, they're equal,
+ so exchange
+ */
+
+ TheReturn = InterlockedCompareExchange(
+ &BaseVariableToManipulate, /* Destination */
+ ValueToExchange, /* Exchange value */
+ START_VALUE); /* Compare value */
+
+ /* Exchanged, these should be equal now */
+ if(BaseVariableToManipulate != ValueToExchange)
+ {
+ Fail("ERROR: A successful compare and exchange should have occurred, "
+ "making the variable have the value of %d, as opposed to the "
+ "current value of %d.",
+ ValueToExchange,BaseVariableToManipulate);
+ }
+
+ /* Check to make sure it returns the original number which
+ 'BaseVariableToManipulate' was set to.
+ */
+ if(TheReturn != START_VALUE)
+ {
+ Fail("ERROR: The return value after the first exchange should be the "
+ "former value of the variable, which was %d, but it is now %d.",
+ START_VALUE,TheReturn);
+ }
+
+
+
+ ValueToExchange = THIRD_VALUE; /* Give this a new value */
+ TempValue = BaseVariableToManipulate; /* Note value of Base */
+
+ /*
+ Do an exchange where 'BaseVariableToManipulate' doesn't
+ match -- therefore the exchange shouldn't happen.
+ So, it should end up the same as the 'TempValue' we saved.
+ */
+
+ InterlockedCompareExchange(&BaseVariableToManipulate,
+ ValueToExchange,
+ START_VALUE);
+
+ if(BaseVariableToManipulate != TempValue)
+ {
+ Fail("ERROR: An attempted exchange should have failed due to "
+ "the compare failing. But, it seems to have succeeded. The "
+ "value should be %d but is %d in this case.",
+ TempValue,BaseVariableToManipulate);
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/InterlockedCompareExchange/test1/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/InterlockedCompareExchange/test1/testinfo.dat
new file mode 100644
index 0000000000..04b1dfe783
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/InterlockedCompareExchange/test1/testinfo.dat
@@ -0,0 +1,16 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = InterlockedCompareExchange
+Name = Positive test of InterlockedCompareExchange
+TYPE = DEFAULT
+EXE1 = test
+Description
+= Test to see if both successful and unsuccessful compare exchanges workp
+= roperly -- ie. Exchange and don't exchange.
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/InterlockedCompareExchange/test2/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/InterlockedCompareExchange/test2/CMakeLists.txt
new file mode 100644
index 0000000000..038d375273
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/InterlockedCompareExchange/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.cpp
+)
+
+add_executable(paltest_interlockedcompareexchange_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_interlockedcompareexchange_test2 coreclrpal)
+
+target_link_libraries(paltest_interlockedcompareexchange_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/InterlockedCompareExchange/test2/test.cpp b/src/pal/tests/palsuite/miscellaneous/InterlockedCompareExchange/test2/test.cpp
new file mode 100644
index 0000000000..902f626d47
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/InterlockedCompareExchange/test2/test.cpp
@@ -0,0 +1,168 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source : test.c
+**
+** Purpose: Test for InterlockedCompareExchange() function using multiple threads
+**
+**
+**=========================================================*/
+
+
+
+#include <palsuite.h>
+
+#define MAX_THREADS 10
+#define REPEAT_COUNT 10
+
+//Global Variable Declaration
+LONG g_Total = 0;
+LONG Lock=0;
+
+
+void ModifyGlobalResource(void);
+void AcquireLock(PLONG pLock);
+void ReleaseLock(PLONG pLock);
+
+
+
+//Main entry point of the program
+int __cdecl main(int argc, char *argv[]) {
+
+ int i = 0;
+ DWORD dwThreadID=0;
+ LONG totalOperations = 0;
+
+ HANDLE hThread[MAX_THREADS];
+
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+
+ totalOperations = MAX_THREADS * REPEAT_COUNT;
+
+
+ //Create MAX_THREADS threads that will operate on the global counter
+ for (i=0;i<MAX_THREADS;i++)
+ {
+ hThread[i] = CreateThread(
+ NULL, // default security attributes
+ 0, // use default stack size
+ (LPTHREAD_START_ROUTINE) ModifyGlobalResource, // thread function
+ NULL, // argument to thread function
+ 0, // use default creation flags
+ &dwThreadID); // returns the thread identifier
+
+ // Check the return value for success.
+
+ if (hThread[i] == NULL)
+ {
+ Fail("ERROR: Was not able to create thread\n"
+ "GetLastError returned %d\n", GetLastError());
+ }
+
+ }
+
+
+ //Wait for all threads to finish
+ for (i=0;i<MAX_THREADS;i++)
+ {
+
+ if (WAIT_OBJECT_0 != WaitForSingleObject (hThread[i], INFINITE))
+ {
+ Fail ("Main: Wait for Single Object failed. Failing test.\n"
+ "GetLastError returned %d\n", GetLastError());
+ }
+
+ }
+
+
+ if (0!= g_Total)
+ {
+ Fail("Test Failed \n");
+ }
+
+ Trace("Global Counter Value at the end of the test %d \n", g_Total);
+
+ /*
+ * Terminate PAL
+ */
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
+void ModifyGlobalResource(void)
+{
+
+ int i =0;
+
+ for (i=0;i<REPEAT_COUNT;i++)
+ {
+
+ /*
+ Acquire Lock Provides Synchronization Around g_Total global variable
+ */
+
+ AcquireLock(&Lock);
+
+ /*
+ The following set of operations is gauranteed to be atomic by virtue of the fact
+ that InterLockedCompareExchange was able to gaurantee that the compare
+ and exchange operation on pLock was thread safe. If the same set of code was
+ executed without using InterlockedCompareExchange the code would fail most of
+ time.
+
+ */
+ g_Total++;
+ Sleep(100);
+ g_Total--;
+ if (0!=g_Total)
+ {
+ Fail("Test Failed beacuse g_Total was not protected \n");
+ }
+
+
+ /*
+ Acquire Lock releases the lock around g_Total Global variable
+ */
+
+ ReleaseLock(&Lock);
+ }
+
+
+}
+
+
+void AcquireLock(PLONG pLock)
+{
+ //Spin Lock implemented with the help of InterlockedCompareExchange
+
+
+ while(1)
+ {
+ if (InterlockedCompareExchange(pLock,1,0)==0)
+ break;
+ }
+
+}
+
+
+void ReleaseLock(PLONG pLock)
+{
+
+
+ MemoryBarrier();
+ *pLock = 0;
+}
+
diff --git a/src/pal/tests/palsuite/miscellaneous/InterlockedCompareExchange64/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/InterlockedCompareExchange64/CMakeLists.txt
new file mode 100644
index 0000000000..ef14ea5352
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/InterlockedCompareExchange64/CMakeLists.txt
@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+
diff --git a/src/pal/tests/palsuite/miscellaneous/InterlockedCompareExchange64/test1/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/InterlockedCompareExchange64/test1/CMakeLists.txt
new file mode 100644
index 0000000000..722603eb4a
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/InterlockedCompareExchange64/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.cpp
+)
+
+add_executable(paltest_interlockedcompareexchange64_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_interlockedcompareexchange64_test1 coreclrpal)
+
+target_link_libraries(paltest_interlockedcompareexchange64_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/InterlockedCompareExchange64/test1/test.cpp b/src/pal/tests/palsuite/miscellaneous/InterlockedCompareExchange64/test1/test.cpp
new file mode 100644
index 0000000000..56430e60cf
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/InterlockedCompareExchange64/test1/test.cpp
@@ -0,0 +1,122 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source : test.c
+**
+** Purpose: Test for InterlockedCompareExchange() function
+**
+**
+**=========================================================*/
+
+/* This test is FINISHED. Note: The biggest feature of this function is that
+ it locks the value before it increments it -- in order to make it so only
+ one thread can access it. But, I really don't have a great test to make
+ sure it's thread safe. Any ideas?
+*/
+
+#include <palsuite.h>
+
+#define START_VALUE 0
+#define SECOND_VALUE 5
+#define THIRD_VALUE 10
+
+int __cdecl main(int argc, char *argv[]) {
+
+ LONGLONG BaseVariableToManipulate = START_VALUE;
+ LONGLONG ValueToExchange = SECOND_VALUE;
+ LONGLONG TempValue;
+ LONGLONG TheReturn;
+
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+/*
+** Run only on 64 bit platforms
+*/
+#if defined(BIT64) && defined(PLATFORM_UNIX)
+ /* Compare START_VALUE with BaseVariableToManipulate, they're equal,
+ so exchange
+ */
+
+ TheReturn = InterlockedCompareExchange64(
+ &BaseVariableToManipulate, /* Destination */
+ ValueToExchange, /* Exchange value */
+ START_VALUE); /* Compare value */
+
+ /* Exchanged, these should be equal now */
+ if(BaseVariableToManipulate != ValueToExchange)
+ {
+#ifdef PLATFORM_UNIX
+ Fail("ERROR: A successful compare and exchange should have occurred, "
+ "making the variable have the value of %ll, as opposed to the "
+ "current value of %ll.",
+ ValueToExchange,BaseVariableToManipulate);
+#else
+ Fail("ERROR: A successful compare and exchange should have occurred, "
+ "making the variable have the value of %I64, as opposed to the "
+ "current value of %d.",
+ ValueToExchange,BaseVariableToManipulate);
+
+#endif
+ }
+
+ /* Check to make sure it returns the original number which
+ 'BaseVariableToManipulate' was set to.
+ */
+ if(TheReturn != START_VALUE)
+ {
+#ifdef PLATFORM_UNIX
+ Fail("ERROR: The return value after the first exchange should be the "
+ "former value of the variable, which was %ll, but it is now %ll.",
+ START_VALUE,TheReturn);
+#else
+ Fail("ERROR: The return value after the first exchange should be the "
+ "former value of the variable, which was %I64, but it is now %I64.",
+ START_VALUE,TheReturn);
+#endif
+
+ }
+
+
+
+ ValueToExchange = THIRD_VALUE; /* Give this a new value */
+ TempValue = BaseVariableToManipulate; /* Note value of Base */
+
+ /*
+ Do an exchange where 'BaseVariableToManipulate' doesn't
+ match -- therefore the exchange shouldn't happen.
+ So, it should end up the same as the 'TempValue' we saved.
+ */
+
+ InterlockedCompareExchange64(&BaseVariableToManipulate,
+ ValueToExchange,
+ START_VALUE);
+
+ if(BaseVariableToManipulate != TempValue)
+ {
+#ifdef PLATFORM_UNIX
+ Fail("ERROR: An attempted exchange should have failed due to "
+ "the compare failing. But, it seems to have succeeded. The "
+ "value should be %ll but is %ll in this case.",
+ TempValue,BaseVariableToManipulate);
+#else
+ Fail("ERROR: An attempted exchange should have failed due to "
+ "the compare failing. But, it seems to have succeeded. The "
+ "value should be %I64 but is %I64 in this case.",
+ TempValue,BaseVariableToManipulate);
+#endif
+ }
+
+#endif //if defined(BIT64) && defined(PLATFORM_UNIX)
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/miscellaneous/InterlockedCompareExchange64/test1/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/InterlockedCompareExchange64/test1/testinfo.dat
new file mode 100644
index 0000000000..1849277347
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/InterlockedCompareExchange64/test1/testinfo.dat
@@ -0,0 +1,16 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = InterlockedCompareExchange64
+Name = Positive test of InterlockedCompareExchange64
+TYPE = DEFAULT
+EXE1 = test
+Description
+= Test to see if both successful and unsuccessful compare exchanges workp
+= roperly -- ie. Exchange and don't exchange.
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/InterlockedCompareExchange64/test2/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/InterlockedCompareExchange64/test2/CMakeLists.txt
new file mode 100644
index 0000000000..f052ca0b27
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/InterlockedCompareExchange64/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.cpp
+)
+
+add_executable(paltest_interlockedcompareexchange64_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_interlockedcompareexchange64_test2 coreclrpal)
+
+target_link_libraries(paltest_interlockedcompareexchange64_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/InterlockedCompareExchange64/test2/test.cpp b/src/pal/tests/palsuite/miscellaneous/InterlockedCompareExchange64/test2/test.cpp
new file mode 100644
index 0000000000..2440543631
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/InterlockedCompareExchange64/test2/test.cpp
@@ -0,0 +1,104 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source : test.c
+**
+** Purpose: InterlockedIncrement64() function
+**
+** The test case spawns MAX_THREADS Threads, and each thread call InterlockedDecrement Function to decrement a
+** global counter REPEAT_COUNT Times. The Test case sets the global counter to Zero at the begining of the test.
+** The test cases passes if at the end the test the value of the global counter is MAX_THREADS * REPEAT_COUNT.
+**
+**
+**=========================================================*/
+
+#include <palsuite.h>
+#define MAX_THREADS 64
+#define REPEAT_COUNT 10000
+
+LONG GlobalCounter = 0;
+void IncrementCounter(void);
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ LONG TotalOperations=0;
+ int i=0;
+ DWORD dwThreadID = 0;
+
+ HANDLE hThread[MAX_THREADS];
+
+ TotalOperations = MAX_THREADS * REPEAT_COUNT;
+
+ GlobalCounter = 0;
+
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /*
+ ** Run only on 64 bit platforms
+ */
+ #if defined(BIT64) && defined(PLATFORM_UNIX)
+
+ //Create MAX_THREADS threads that will operate on the global counter
+ for (i=0;i<MAX_THREADS;i++)
+ {
+ hThread[i] = CreateThread(
+ NULL, // default security attributes
+ 0, // use default stack size
+ (LPTHREAD_START_ROUTINE) IncrementCounter, // thread function
+ NULL, // argument to thread function
+ 0, // use default creation flags
+ &dwThreadID); // returns the thread identifier
+
+ // Check the return value for success.
+ if (hThread[i] == NULL)
+ {
+ Fail("ERROR: Was not able to create thread\n"
+ "GetLastError returned %d\n", GetLastError());
+ }
+ }
+ //Wait for all threads to finish
+ for (i=0;i<MAX_THREADS;i++)
+ {
+ if (WAIT_OBJECT_0 != WaitForSingleObject (hThread[i], INFINITE))
+ {
+ Fail ("Main: Wait for Single Object failed. Failing test.\n"
+ "GetLastError returned %d\n", GetLastError());
+ }
+ }
+
+ /* Compare the value of global counter with zero.
+ */
+ if (TotalOperations!=GlobalCounter)
+ {
+ Fail("Test Case Failed: InterlockedDecrement \n");
+ }
+
+ #endif //defined(BIT64) && defined(PLATFORM_UNIX)
+
+ PAL_Terminate();
+ return PASS;
+}
+
+void IncrementCounter(void)
+{
+ int i=0;
+
+ for (i=0; i<REPEAT_COUNT;i++)
+ {
+ InterlockedIncrement(&GlobalCounter);
+ }
+}
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/InterlockedCompareExchangePointer/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/InterlockedCompareExchangePointer/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/InterlockedCompareExchangePointer/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/miscellaneous/InterlockedCompareExchangePointer/test1/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/InterlockedCompareExchangePointer/test1/CMakeLists.txt
new file mode 100644
index 0000000000..0c48c4e296
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/InterlockedCompareExchangePointer/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.cpp
+)
+
+add_executable(paltest_interlockedcompareexchangepointer_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_interlockedcompareexchangepointer_test1 coreclrpal)
+
+target_link_libraries(paltest_interlockedcompareexchangepointer_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/InterlockedCompareExchangePointer/test1/test.cpp b/src/pal/tests/palsuite/miscellaneous/InterlockedCompareExchangePointer/test1/test.cpp
new file mode 100644
index 0000000000..c263a6cdc4
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/InterlockedCompareExchangePointer/test1/test.cpp
@@ -0,0 +1,80 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: test.c
+**
+** Purpose: Test for InterlockedCompareExchangePointer() function
+**
+**
+**=========================================================*/
+
+/* This test is FINISHED. Note: The biggest feature of this function is that
+ it locks the value before it increments it -- in order to make it so only
+ one thread can access it. But, I really don't have a great test to
+ make sure it's thread safe. Any ideas?
+*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ long StartValue = 5;
+ long NewValue = 10;
+ PVOID ReturnValue = NULL;
+
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ ReturnValue = InterlockedCompareExchangePointer((PVOID)&StartValue,
+ (PVOID)NewValue,
+ (PVOID)StartValue);
+
+ /* StartValue and NewValue should be equal now */
+ if(StartValue != NewValue)
+ {
+ Fail("ERROR: These values should be equal after the exchange. "
+ "They should both be %d, however the value that should have "
+ "been exchanged is %d.\n",NewValue,StartValue);
+ }
+
+ /* Returnvalue should have been set to what 'StartValue' was
+ (5 in this case)
+ */
+
+ if((int)(size_t)ReturnValue != 5)
+ {
+ Fail("ERROR: The return value should be the value of the "
+ "variable before the exchange took place, which was 5. "
+ "But, the return value was %d.\n",ReturnValue);
+ }
+
+ /* This is a mismatch, so no exchange should happen */
+ InterlockedCompareExchangePointer((PVOID)&StartValue,
+ ReturnValue,
+ ReturnValue);
+ if(StartValue != NewValue)
+ {
+ Fail("ERROR: The compare should have failed and no exchange should "
+ "have been made, but it seems the exchange still happened.\n");
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
+
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/InterlockedCompareExchangePointer/test1/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/InterlockedCompareExchangePointer/test1/testinfo.dat
new file mode 100644
index 0000000000..d78515e7cc
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/InterlockedCompareExchangePointer/test1/testinfo.dat
@@ -0,0 +1,16 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = InterlockedCompareExchangePointer
+Name = Positive test of InterlockedCompareExchangePointer
+TYPE = DEFAULT
+EXE1 = test
+Description
+= Test to see if both successful and unsuccessful compare exchanges work
+= properly -- ie. Exchange and don't exchange.
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/InterlockedDecrement/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/InterlockedDecrement/CMakeLists.txt
new file mode 100644
index 0000000000..ef14ea5352
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/InterlockedDecrement/CMakeLists.txt
@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+
diff --git a/src/pal/tests/palsuite/miscellaneous/InterlockedDecrement/test1/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/InterlockedDecrement/test1/CMakeLists.txt
new file mode 100644
index 0000000000..6cd307d2e8
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/InterlockedDecrement/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.cpp
+)
+
+add_executable(paltest_interlockeddecrement_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_interlockeddecrement_test1 coreclrpal)
+
+target_link_libraries(paltest_interlockeddecrement_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/InterlockedDecrement/test1/test.cpp b/src/pal/tests/palsuite/miscellaneous/InterlockedDecrement/test1/test.cpp
new file mode 100644
index 0000000000..9c9a50c73e
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/InterlockedDecrement/test1/test.cpp
@@ -0,0 +1,60 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source : test.c
+**
+** Purpose: InterlockedDecrement() function
+**
+**
+**=========================================================*/
+
+/* This test is FINISHED. Note: The biggest feature of this function is that
+ it locks the value before it increments it -- in order to make it so only
+ one thread can access it. But, I really don't have a great test to make
+ sure it's thread safe. Any ideas?
+*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ int TheValue = 0;
+ int TheReturn;
+
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ InterlockedDecrement(&TheValue);
+ TheReturn = InterlockedDecrement(&TheValue);
+
+ /* Decremented twice, it should be -2 now */
+ if(TheValue != -2)
+ {
+ Fail("ERROR: After being decremented twice, the value should be -2, "
+ "but it is really %d.",TheValue);
+ }
+
+ /* Check to make sure it returns itself */
+ if(TheReturn != TheValue)
+ {
+ Fail("ERROR: The function should have returned the new value of %d "
+ "but instead returned %d.",TheValue,TheReturn);
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/InterlockedDecrement/test1/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/InterlockedDecrement/test1/testinfo.dat
new file mode 100644
index 0000000000..57ee3835cd
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/InterlockedDecrement/test1/testinfo.dat
@@ -0,0 +1,16 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = InterlockedDecrement
+Name = Positive test of InterlockedDecrement
+TYPE = DEFAULT
+EXE1 = test
+Description
+= Test to see if this decrements the variable correctly and
+= has the correct return value.
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/InterlockedDecrement/test2/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/InterlockedDecrement/test2/CMakeLists.txt
new file mode 100644
index 0000000000..331d89d5d6
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/InterlockedDecrement/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.cpp
+)
+
+add_executable(paltest_interlockeddecrement_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_interlockeddecrement_test2 coreclrpal)
+
+target_link_libraries(paltest_interlockeddecrement_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/InterlockedDecrement/test2/test.cpp b/src/pal/tests/palsuite/miscellaneous/InterlockedDecrement/test2/test.cpp
new file mode 100644
index 0000000000..2f214e29e5
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/InterlockedDecrement/test2/test.cpp
@@ -0,0 +1,94 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source : test.c
+**
+** Purpose: InterlockedDecrement() function
+**
+** The test case spawns MAX_THREADS Threads, and each thread call InterlockedDecrement Function to decrement a
+** global counter REPEAT_COUNT Times. The Test case sets the global counter to MAX_THREADS * REPEAT_COUNT
+** at the begining of the test. The test cases passes if at the end the test the value of the global counter is Zero.
+**
+**
+**=========================================================*/
+
+#include <palsuite.h>
+#define MAX_THREADS 64
+#define REPEAT_COUNT 10000
+
+LONG GlobalCounter = 0;
+void DecrementCounter(void);
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ LONG TotalOperations=0;
+ int i=0;
+ DWORD dwThreadID = 0;
+ HANDLE hThread[MAX_THREADS];
+ TotalOperations = MAX_THREADS * REPEAT_COUNT;
+ GlobalCounter = TotalOperations;
+
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ //Create MAX_THREADS threads that will operate on the global counter
+ for (i=0;i<MAX_THREADS;i++)
+ {
+ hThread[i] = CreateThread(
+ NULL, // default security attributes
+ 0, // use default stack size
+ (LPTHREAD_START_ROUTINE) DecrementCounter, // thread function
+ NULL, // argument to thread function
+ 0, // use default creation flags
+ &dwThreadID); // returns the thread identifier
+
+ // Check the return value for success.
+
+ if (hThread[i] == NULL)
+ {
+ Fail("ERROR: Was not able to create thread\n"
+ "GetLastError returned %d\n", GetLastError());
+ }
+ }
+
+ //Wait for all threads to finish
+ for (i=0;i<MAX_THREADS;i++)
+ {
+ if (WAIT_OBJECT_0 != WaitForSingleObject (hThread[i], INFINITE))
+ {
+ Fail ("Main: Wait for Single Object failed. Failing test.\n"
+ "GetLastError returned %d\n", GetLastError());
+ }
+ }
+
+ /* Compare the value of global counter with zero.
+ */
+ if (0!=GlobalCounter)
+ {
+ Fail("Test Case Failed: InterlockedDecrement \n");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
+void DecrementCounter(void)
+{
+ int i=0;
+ for (i=0; i<REPEAT_COUNT;i++)
+ {
+ InterlockedDecrement(&GlobalCounter);
+ }
+}
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/InterlockedDecrement64/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/InterlockedDecrement64/CMakeLists.txt
new file mode 100644
index 0000000000..ef14ea5352
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/InterlockedDecrement64/CMakeLists.txt
@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+
diff --git a/src/pal/tests/palsuite/miscellaneous/InterlockedDecrement64/test1/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/InterlockedDecrement64/test1/CMakeLists.txt
new file mode 100644
index 0000000000..727a328d07
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/InterlockedDecrement64/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.cpp
+)
+
+add_executable(paltest_interlockeddecrement64_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_interlockeddecrement64_test1 coreclrpal)
+
+target_link_libraries(paltest_interlockeddecrement64_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/InterlockedDecrement64/test1/test.cpp b/src/pal/tests/palsuite/miscellaneous/InterlockedDecrement64/test1/test.cpp
new file mode 100644
index 0000000000..326587d9a1
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/InterlockedDecrement64/test1/test.cpp
@@ -0,0 +1,77 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source : test.c
+**
+** Purpose: InterlockedDecrement64() function
+**
+**
+**=========================================================*/
+
+/* This test is FINISHED. Note: The biggest feature of this function is that
+ it locks the value before it increments it -- in order to make it so only
+ one thread can access it. But, I really don't have a great test to make
+ sure it's thread safe. Any ideas?
+*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ LONGLONG TheValue = 0;
+ LONGLONG TheReturn;
+
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+/*
+** Run only on 64 bit platforms
+*/
+#if defined(BIT64) && defined(PLATFORM_UNIX)
+ /* Compare START_VALUE with BaseVariableToManipulate, they're equal,
+ so exchange
+ */
+ InterlockedDecrement64(&TheValue);
+ TheReturn = InterlockedDecrement64(&TheValue);
+
+ /* Decremented twice, it should be -2 now */
+ if(TheValue != -2)
+ {
+#ifdef PLATFORM_UNIX
+ Fail("ERROR: After being decremented twice, the value should be -2, "
+ "but it is really %ll.",TheValue);
+#else
+ Fail("ERROR: After being decremented twice, the value should be -2, "
+ "but it is really %I64.",TheValue);
+#endif
+ }
+
+ /* Check to make sure it returns itself */
+ if(TheReturn != TheValue)
+ {
+#ifdef PLATFORM_UNIX
+ Fail("ERROR: The function should have returned the new value of %d "
+ "but instead returned %ll.",TheValue,TheReturn);
+#else
+ Fail("ERROR: After being decremented twice, the value should be -2, "
+ "but it is really %I64.",TheValue);
+#endif
+ }
+#endif //defined(BIT64) && defined(PLATFORM_UNIX)
+ PAL_Terminate();
+ return PASS;
+}
+
+
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/InterlockedDecrement64/test1/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/InterlockedDecrement64/test1/testinfo.dat
new file mode 100644
index 0000000000..8c5b1f087c
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/InterlockedDecrement64/test1/testinfo.dat
@@ -0,0 +1,16 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = InterlockedDecrement64
+Name = Positive test of InterlockedDecrement64
+TYPE = DEFAULT
+EXE1 = test
+Description
+= Test to see if this decrements the variable correctly and
+= has the correct return value.
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/InterlockedDecrement64/test2/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/InterlockedDecrement64/test2/CMakeLists.txt
new file mode 100644
index 0000000000..ecea6399a7
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/InterlockedDecrement64/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.cpp
+)
+
+add_executable(paltest_interlockeddecrement64_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_interlockeddecrement64_test2 coreclrpal)
+
+target_link_libraries(paltest_interlockeddecrement64_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/InterlockedDecrement64/test2/test.cpp b/src/pal/tests/palsuite/miscellaneous/InterlockedDecrement64/test2/test.cpp
new file mode 100644
index 0000000000..fa748d538d
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/InterlockedDecrement64/test2/test.cpp
@@ -0,0 +1,99 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source : test.c
+**
+** Purpose: InterlockedDecrement64() function
+**
+** The test case spawns MAX_THREADS Threads, and each thread call InterlockedDecrement Function to decrement a
+** global counter REPEAT_COUNT Times. The Test case sets the global counter to MAX_THREADS * REPEAT_COUNT
+** at the begining of the test. The test cases passes if at the end the test the value of the global counter is Zero.
+**
+**
+**=========================================================*/
+
+#include <palsuite.h>
+#define MAX_THREADS 64
+#define REPEAT_COUNT 10000
+
+LONG GlobalCounter = 0;
+void DecrementCounter(void);
+
+int __cdecl main(int argc, char *argv[])
+{
+ LONG TotalOperations=0;
+ int i=0;
+ DWORD dwThreadID = 0;
+ HANDLE hThread[MAX_THREADS];
+ TotalOperations = MAX_THREADS * REPEAT_COUNT;
+ GlobalCounter = TotalOperations;
+
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ #if defined(BIT64) && defined(PLATFORM_UNIX)
+
+ //Create MAX_THREADS threads that will operate on the global counter
+ for (i=0;i<MAX_THREADS;i++)
+ {
+ hThread[i] = CreateThread(
+ NULL, // default security attributes
+ 0, // use default stack size
+ (LPTHREAD_START_ROUTINE) DecrementCounter, // thread function
+ NULL, // argument to thread function
+ 0, // use default creation flags
+ &dwThreadID); // returns the thread identifier
+
+ // Check the return value for success.
+ if (hThread[i] == NULL)
+ {
+ Fail("ERROR: Was not able to create thread\n"
+ "GetLastError returned %d\n", GetLastError());
+ }
+ }
+
+ //Wait for all threads to finish
+ for (i=0;i<MAX_THREADS;i++)
+ {
+
+ if (WAIT_OBJECT_0 != WaitForSingleObject (hThread[i], INFINITE))
+ {
+ Fail ("Main: Wait for Single Object failed. Failing test.\n"
+ "GetLastError returned %d\n", GetLastError());
+ }
+ }
+
+ /* Compare the value of global counter with zero.
+ */
+ if (0!=GlobalCounter)
+ {
+ Fail("Test Case Failed: InterlockedDecrement \n");
+ }
+
+#endif //defined(BIT64) && defined(PLATFORM_UNIX)
+
+ PAL_Terminate();
+ return PASS;
+}
+
+void DecrementCounter(void)
+{
+ int i=0;
+
+ for (i=0; i<REPEAT_COUNT;i++)
+ {
+ InterlockedDecrement(&GlobalCounter);
+ }
+}
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/InterlockedExchange/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/InterlockedExchange/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/InterlockedExchange/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/miscellaneous/InterlockedExchange/test1/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/InterlockedExchange/test1/CMakeLists.txt
new file mode 100644
index 0000000000..a1a7f862ed
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/InterlockedExchange/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.cpp
+)
+
+add_executable(paltest_interlockedexchange_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_interlockedexchange_test1 coreclrpal)
+
+target_link_libraries(paltest_interlockedexchange_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/InterlockedExchange/test1/test.cpp b/src/pal/tests/palsuite/miscellaneous/InterlockedExchange/test1/test.cpp
new file mode 100644
index 0000000000..517fca1792
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/InterlockedExchange/test1/test.cpp
@@ -0,0 +1,69 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: test.c
+**
+** Purpose: InterlockedExchange() function
+**
+**
+**=========================================================*/
+
+/* This test is FINISHED. Note: The biggest feature of this function is that
+ it locks the value before it increments it -- in order to make it so only
+ one thread can access it. But, I really don't have a great test to make
+ sure it's thread safe. Any ideas?
+*/
+
+#include <palsuite.h>
+
+#define START_VALUE 0
+
+int __cdecl main(int argc, char *argv[]) {
+
+ int TheValue = START_VALUE;
+ int NewValue = 5;
+ int TheReturn;
+
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ TheReturn = InterlockedExchange(&TheValue,NewValue);
+
+ /* Compare the exchanged value with the value we exchanged it with. Should
+ be the same.
+ */
+ if(TheValue != NewValue)
+ {
+ Fail("ERROR: The value which was exchanged should now be %d, but "
+ "instead it is %d.",NewValue,TheValue);
+ }
+
+ /* Check to make sure it returns the origional number which 'TheValue' was
+ set to.
+ */
+
+ if(TheReturn != START_VALUE)
+ {
+ Fail("ERROR: The value returned should be the value before the "
+ "exchange happened, which was %d, but %d was returned.",
+ START_VALUE,TheReturn);
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/InterlockedExchange/test1/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/InterlockedExchange/test1/testinfo.dat
new file mode 100644
index 0000000000..4b7c20a423
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/InterlockedExchange/test1/testinfo.dat
@@ -0,0 +1,16 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = InterlockedExchange
+Name = Positive test of InterlockedExchange
+TYPE = DEFAULT
+EXE1 = test
+Description
+= Test to see if this exchanges the variables correctly and
+= has the correct return value.
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/InterlockedExchange64/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/InterlockedExchange64/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/InterlockedExchange64/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/miscellaneous/InterlockedExchange64/test1/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/InterlockedExchange64/test1/CMakeLists.txt
new file mode 100644
index 0000000000..3f4cd5e058
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/InterlockedExchange64/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.cpp
+)
+
+add_executable(paltest_interlockedexchange64_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_interlockedexchange64_test1 coreclrpal)
+
+target_link_libraries(paltest_interlockedexchange64_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/InterlockedExchange64/test1/test.cpp b/src/pal/tests/palsuite/miscellaneous/InterlockedExchange64/test1/test.cpp
new file mode 100644
index 0000000000..12e8b50580
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/InterlockedExchange64/test1/test.cpp
@@ -0,0 +1,85 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: test.c
+**
+** Purpose: InterlockedExchange64() function
+**
+**
+**=========================================================*/
+
+/* This test is FINISHED. Note: The biggest feature of this function is that
+ it locks the value before it increments it -- in order to make it so only
+ one thread can access it. But, I really don't have a great test to make
+ sure it's thread safe. Any ideas?
+*/
+
+#include <palsuite.h>
+
+#define START_VALUE 0
+
+int __cdecl main(int argc, char *argv[]) {
+
+ LONGLONG TheValue = START_VALUE;
+ LONGLONG NewValue = 5;
+ LONGLONG TheReturn;
+
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+/*
+** Run only on 64 bit platforms
+*/
+#if defined(BIT64) && defined(PLATFORM_UNIX)
+
+ TheReturn = InterlockedExchange64(&TheValue,NewValue);
+
+ /* Compare the exchanged value with the value we exchanged it with. Should
+ be the same.
+ */
+ if(TheValue != NewValue)
+ {
+#ifdef PLATFORM_UNIX
+ Fail("ERROR: The value which was exchanged should now be %ll, but "
+ "instead it is %ll.",NewValue,TheValue);
+#else
+ Fail("ERROR: The value which was exchanged should now be %I64, but "
+ "instead it is %I64.",NewValue,TheValue);
+#endif
+ }
+
+ /* Check to make sure it returns the origional number which 'TheValue' was
+ set to.
+ */
+
+ if(TheReturn != START_VALUE)
+ {
+#ifdef PLATFORM_UNIX
+ Fail("ERROR: The value returned should be the value before the "
+ "exchange happened, which was %ll, but %ll was returned.",
+ START_VALUE,TheReturn);
+#else
+ Fail("ERROR: The value returned should be the value before the "
+ "exchange happened, which was %I64, but %I64 was returned.",
+ START_VALUE,TheReturn);
+#endif
+ }
+
+#endif //defined(BIT64) && defined(_IA64_)
+ PAL_Terminate();
+ return PASS;
+}
+
+
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/InterlockedExchange64/test1/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/InterlockedExchange64/test1/testinfo.dat
new file mode 100644
index 0000000000..3669e99614
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/InterlockedExchange64/test1/testinfo.dat
@@ -0,0 +1,16 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = InterlockedExchange64
+Name = Positive test of InterlockedExchange64
+TYPE = DEFAULT
+EXE1 = test
+Description
+= Test to see if this exchanges the variables correctly and
+= has the correct return value.
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/InterlockedExchangePointer/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/InterlockedExchangePointer/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/InterlockedExchangePointer/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/miscellaneous/InterlockedExchangePointer/test1/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/InterlockedExchangePointer/test1/CMakeLists.txt
new file mode 100644
index 0000000000..b0858963a0
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/InterlockedExchangePointer/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ InterlockedExchangePointer.cpp
+)
+
+add_executable(paltest_interlockedexchangepointer_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_interlockedexchangepointer_test1 coreclrpal)
+
+target_link_libraries(paltest_interlockedexchangepointer_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/InterlockedExchangePointer/test1/InterlockedExchangePointer.cpp b/src/pal/tests/palsuite/miscellaneous/InterlockedExchangePointer/test1/InterlockedExchangePointer.cpp
new file mode 100644
index 0000000000..d36c96724f
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/InterlockedExchangePointer/test1/InterlockedExchangePointer.cpp
@@ -0,0 +1,64 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: InterlockedExchangePointer
+**
+** Purpose: Positive test the InterlockedExchangePointer API.
+** Call InterlockedExchangePointer to exchange a pair of
+** value
+**
+**
+**
+**============================================================*/
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ int err;
+ int i1 = 10;
+ int i2 = 20;
+ int *pOldValue = &i1;
+ int *pNewValue = &i2;
+ PVOID pReturnValue;
+
+ /*Initialize the PAL environment*/
+ err = PAL_Initialize(argc, argv);
+ if(0 != err)
+ {
+ return FAIL;
+ }
+
+
+
+ /*
+ Testing
+ =======
+ */
+
+ pReturnValue = InterlockedExchangePointer((PVOID)&pOldValue,
+ (PVOID)pNewValue);
+ /*check the returned value*/
+ if(*(int *)pReturnValue != i1)
+ {
+ Fail("\nFailed to call InterlockedExchangePointer API, "
+ "return pointer does not point to the origional value\n");
+ }
+
+ /*check the exchanged value*/
+ if(*pOldValue != *pNewValue)
+ {
+ Fail("\nFailed to call InterlockedExchangePointer API, "
+ "exchanged value is not right\n");
+ }
+
+
+
+ /*
+ Clean Up
+ */
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/miscellaneous/InterlockedExchangePointer/test1/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/InterlockedExchangePointer/test1/testinfo.dat
new file mode 100644
index 0000000000..5e0a36627a
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/InterlockedExchangePointer/test1/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = miscellaneous
+Function = InterlockedExchangePointer
+Name = Pos test for InterlockedExchangePointer API to excnage a pair of value
+TYPE = DEFAULT
+EXE1 = interlockedexchangepointer
+Description
+=Test the InterlockedExchangePointer to exchange a pair of value
diff --git a/src/pal/tests/palsuite/miscellaneous/InterlockedIncrement/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/InterlockedIncrement/CMakeLists.txt
new file mode 100644
index 0000000000..ef14ea5352
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/InterlockedIncrement/CMakeLists.txt
@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+
diff --git a/src/pal/tests/palsuite/miscellaneous/InterlockedIncrement/test1/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/InterlockedIncrement/test1/CMakeLists.txt
new file mode 100644
index 0000000000..f87dc72281
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/InterlockedIncrement/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.cpp
+)
+
+add_executable(paltest_interlockedincrement_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_interlockedincrement_test1 coreclrpal)
+
+target_link_libraries(paltest_interlockedincrement_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/InterlockedIncrement/test1/test.cpp b/src/pal/tests/palsuite/miscellaneous/InterlockedIncrement/test1/test.cpp
new file mode 100644
index 0000000000..8b4b3e9148
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/InterlockedIncrement/test1/test.cpp
@@ -0,0 +1,62 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: test.c
+**
+** Purpose: InterlockedIncrement() function
+**
+**
+**=========================================================*/
+
+/* This test is FINISHED. Note: The biggest feature of this function is that
+ it locks the value before it increments it -- in order to make it so only
+ one thread can access it. But, I really don't have a great test to make
+ sure it's thread safe. Any ideas? Nothing I've tried has worked.
+*/
+
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ int TheValue = 0;
+ int TheReturn;
+
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ InterlockedIncrement(&TheValue);
+ TheReturn = InterlockedIncrement(&TheValue);
+
+ /* Incremented twice, it should be 2 now */
+ if(TheValue != 2)
+ {
+ Fail("ERROR: The value was incremented twice and shoud now be 2, "
+ "but it is really %d",TheValue);
+ }
+
+ /* Check to make sure it returns itself */
+ if(TheReturn != TheValue)
+ {
+ Fail("ERROR: The function should return the new value, which shoud "
+ "have been %d, but it returned %d.",TheValue,TheReturn);
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/InterlockedIncrement/test1/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/InterlockedIncrement/test1/testinfo.dat
new file mode 100644
index 0000000000..c304960030
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/InterlockedIncrement/test1/testinfo.dat
@@ -0,0 +1,16 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = InterlockedIncreement
+Name = Positive test of InterlockedIncrement
+TYPE = DEFAULT
+EXE1 = test
+Description
+= Test to see if this increments the variable correctly and
+= has the correct return value.
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/InterlockedIncrement/test2/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/InterlockedIncrement/test2/CMakeLists.txt
new file mode 100644
index 0000000000..e8c5278cbc
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/InterlockedIncrement/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.cpp
+)
+
+add_executable(paltest_interlockedincrement_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_interlockedincrement_test2 coreclrpal)
+
+target_link_libraries(paltest_interlockedincrement_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/InterlockedIncrement/test2/test.cpp b/src/pal/tests/palsuite/miscellaneous/InterlockedIncrement/test2/test.cpp
new file mode 100644
index 0000000000..280a2ea709
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/InterlockedIncrement/test2/test.cpp
@@ -0,0 +1,95 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source : test.c
+**
+** Purpose: InterlockedIncrement() function
+**
+** The test case spawns MAX_THREADS Threads, and each thread call InterlockedDecrement Function to decrement a
+** global counter REPEAT_COUNT Times. The Test case sets the global counter to Zero at the begining of the test.
+** The test cases passes if at the end the test the value of the global counter is MAX_THREADS * REPEAT_COUNT.
+**
+**
+**=========================================================*/
+
+#include <palsuite.h>
+#define MAX_THREADS 64
+#define REPEAT_COUNT 10000
+
+LONG GlobalCounter = 0;
+
+void IncrementCounter(void);
+
+
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ LONG TotalOperations=0;
+ int i=0;
+ DWORD dwThreadID = 0;
+ HANDLE hThread[MAX_THREADS];
+ TotalOperations = MAX_THREADS * REPEAT_COUNT;
+ GlobalCounter = 0;
+
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ //Create MAX_THREADS threads that will operate on the global counter
+ for (i=0;i<MAX_THREADS;i++)
+ {
+ hThread[i] = CreateThread(
+ NULL, // default security attributes
+ 0, // use default stack size
+ (LPTHREAD_START_ROUTINE) IncrementCounter, // thread function
+ NULL, // argument to thread function
+ 0, // use default creation flags
+ &dwThreadID); // returns the thread identifier
+
+ // Check the return value for success.
+
+ if (hThread[i] == NULL)
+ {
+ Fail("ERROR: Was not able to create thread\n"
+ "GetLastError returned %d\n", GetLastError());
+ }
+ }
+
+ //Wait for all threads to finish
+ for (i=0;i<MAX_THREADS;i++)
+ {
+ if (WAIT_OBJECT_0 != WaitForSingleObject (hThread[i], INFINITE))
+ {
+ Fail ("Main: Wait for Single Object failed. Failing test.\n"
+ "GetLastError returned %d\n", GetLastError());
+ }
+ }
+
+ /* Compare the value of global counter with zero.
+ */
+
+ if (TotalOperations!=GlobalCounter)
+ {
+ Fail("Test Case Failed: InterlockedDecrement \n");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
+void IncrementCounter(void)
+{
+ int i=0;
+ for (i=0; i<REPEAT_COUNT;i++)
+ {
+ InterlockedIncrement(&GlobalCounter);
+ }
+}
diff --git a/src/pal/tests/palsuite/miscellaneous/InterlockedIncrement64/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/InterlockedIncrement64/CMakeLists.txt
new file mode 100644
index 0000000000..ef14ea5352
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/InterlockedIncrement64/CMakeLists.txt
@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+
diff --git a/src/pal/tests/palsuite/miscellaneous/InterlockedIncrement64/test1/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/InterlockedIncrement64/test1/CMakeLists.txt
new file mode 100644
index 0000000000..d7bec46d4e
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/InterlockedIncrement64/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.cpp
+)
+
+add_executable(paltest_interlockedincrement64_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_interlockedincrement64_test1 coreclrpal)
+
+target_link_libraries(paltest_interlockedincrement64_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/InterlockedIncrement64/test1/test.cpp b/src/pal/tests/palsuite/miscellaneous/InterlockedIncrement64/test1/test.cpp
new file mode 100644
index 0000000000..c02886f5c6
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/InterlockedIncrement64/test1/test.cpp
@@ -0,0 +1,77 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: test.c
+**
+** Purpose: InterlockedIncrement64() function
+**
+**
+**=========================================================*/
+
+/* This test is FINISHED. Note: The biggest feature of this function is that
+ it locks the value before it increments it -- in order to make it so only
+ one thread can access it. But, I really don't have a great test to make
+ sure it's thread safe. Any ideas? Nothing I've tried has worked.
+*/
+
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ LONGLONG TheValue = 0;
+ LONGLONG TheReturn;
+
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+/*
+** Run only on 64 bit platforms
+*/
+#if defined(BIT64) && defined(PLATFORM_UNIX)
+
+ InterlockedIncrement64(&TheValue);
+ TheReturn = InterlockedIncrement64(&TheValue);
+
+ /* Incremented twice, it should be 2 now */
+ if(TheValue != 2)
+ {
+#ifdef PLATFORM_UNIX
+ Fail("ERROR: The value was incremented twice and shoud now be 2, "
+ "but it is really %ll",TheValue);
+#else
+ Fail("ERROR: The value was incremented twice and shoud now be 2, "
+ "but it is really %I64",TheValue);
+#endif
+ }
+
+ /* Check to make sure it returns itself */
+ if(TheReturn != TheValue)
+ {
+#ifdef PLATFORM_UNIX
+ Fail("ERROR: The function should return the new value, which shoud "
+ "have been %d, but it returned %ll.",TheValue,TheReturn);
+#else
+ Fail("ERROR: The function should return the new value, which shoud "
+ "have been %d, but it returned %I64.",TheValue,TheReturn);
+#endif
+ }
+
+#endif //defined(BIT64) && defined(PLATFORM_UNIX)
+ PAL_Terminate();
+ return PASS;
+}
+
+
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/InterlockedIncrement64/test1/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/InterlockedIncrement64/test1/testinfo.dat
new file mode 100644
index 0000000000..fff0c701c6
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/InterlockedIncrement64/test1/testinfo.dat
@@ -0,0 +1,16 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = InterlockedIncrement64
+Name = Positive test of InterlockedIncrement64
+TYPE = DEFAULT
+EXE1 = test
+Description
+= Test to see if this increments the variable correctly and
+= has the correct return value.
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/InterlockedIncrement64/test2/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/InterlockedIncrement64/test2/CMakeLists.txt
new file mode 100644
index 0000000000..be571a535b
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/InterlockedIncrement64/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.cpp
+)
+
+add_executable(paltest_interlockedincrement64_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_interlockedincrement64_test2 coreclrpal)
+
+target_link_libraries(paltest_interlockedincrement64_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/InterlockedIncrement64/test2/test.cpp b/src/pal/tests/palsuite/miscellaneous/InterlockedIncrement64/test2/test.cpp
new file mode 100644
index 0000000000..1d579fe325
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/InterlockedIncrement64/test2/test.cpp
@@ -0,0 +1,101 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source : test.c
+**
+** Purpose: InterlockedIncrement64() function
+**
+** The test case spawns MAX_THREADS Threads, and each thread call InterlockedDecrement Function to decrement a
+** global counter REPEAT_COUNT Times. The Test case sets the global counter to Zero at the begining of the test.
+** The test cases passes if at the end the test the value of the global counter is MAX_THREADS * REPEAT_COUNT.
+**
+**
+**=========================================================*/
+
+#include <palsuite.h>
+#define MAX_THREADS 64
+#define REPEAT_COUNT 10000
+
+LONG GlobalCounter = 0;
+void IncrementCounter(void);
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ LONG TotalOperations=0;
+ int i=0;
+ DWORD dwThreadID = 0;
+ HANDLE hThread[MAX_THREADS];
+ TotalOperations = MAX_THREADS * REPEAT_COUNT;
+ GlobalCounter = 0;
+
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /*
+ ** Run only on 64 bit platforms
+ */
+ #if defined(BIT64) && defined(PLATFORM_UNIX)
+
+ //Create MAX_THREADS threads that will operate on the global counter
+ for (i=0;i<MAX_THREADS;i++)
+ {
+ hThread[i] = CreateThread(
+ NULL, // default security attributes
+ 0, // use default stack size
+ (LPTHREAD_START_ROUTINE) IncrementCounter, // thread function
+ NULL, // argument to thread function
+ 0, // use default creation flags
+ &dwThreadID); // returns the thread identifier
+
+ // Check the return value for success.
+ if (hThread[i] == NULL)
+ {
+ Fail("ERROR: Was not able to create thread\n"
+ "GetLastError returned %d\n", GetLastError());
+ }
+ }
+
+
+ //Wait for all threads to finish
+ for (i=0;i<MAX_THREADS;i++)
+ {
+ if (WAIT_OBJECT_0 != WaitForSingleObject (hThread[i], INFINITE))
+ {
+ Fail ("Main: Wait for Single Object failed. Failing test.\n"
+ "GetLastError returned %d\n", GetLastError());
+ }
+ }
+
+ /* Compare the value of global counter with zero.
+ */
+ if (TotalOperations!=GlobalCounter)
+ {
+ Fail("Test Case Failed: InterlockedDecrement \n");
+ }
+ #endif //defined(BIT64) && defined(PLATFORM_UNIX)
+
+ PAL_Terminate();
+ return PASS;
+}
+
+void IncrementCounter(void)
+{
+ int i=0;
+
+ for (i=0; i<REPEAT_COUNT;i++)
+ {
+ InterlockedIncrement(&GlobalCounter);
+ }
+}
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/IsBadCodePtr/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/IsBadCodePtr/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/IsBadCodePtr/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/miscellaneous/IsBadCodePtr/test1/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/IsBadCodePtr/test1/CMakeLists.txt
new file mode 100644
index 0000000000..d41e6bc5ab
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/IsBadCodePtr/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_isbadcodeptr_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_isbadcodeptr_test1 coreclrpal)
+
+target_link_libraries(paltest_isbadcodeptr_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/IsBadCodePtr/test1/test1.c b/src/pal/tests/palsuite/miscellaneous/IsBadCodePtr/test1/test1.c
new file mode 100644
index 0000000000..4b2763d457
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/IsBadCodePtr/test1/test1.c
@@ -0,0 +1,60 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Test to ensure that IsBadCodePtr return 0 when
+** it can read memory or non zero when it can't.
+**
+** Dependencies: PAL_Initialize
+** PAL_Terminate
+** Fail
+**
+
+**
+**===========================================================================*/
+
+#include <palsuite.h>
+
+/**
+ * main
+ *
+ * executable entry point
+ */
+INT __cdecl main(INT argc, CHAR **argv)
+{
+ BOOL ResultValue = 0;
+
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /* This should be readable, and return 0 */
+ ResultValue = IsBadCodePtr((FARPROC)main);
+ if(ResultValue != 0)
+ {
+ Fail("ERROR: IsBadCodePtr returned %d instead of 0, when pointing "
+ "at readable memory.\n",ResultValue);
+ }
+
+ /* 0x00 is usually unreadable memory so the function should
+ return non zero */
+ ResultValue = IsBadCodePtr((FARPROC)0x00);
+
+ if(ResultValue == 0)
+ {
+ Fail("ERROR: IsBadCodePtr returned %d instead of non zero "
+ "when checking on unreadable memory.\n",ResultValue);
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/miscellaneous/IsBadCodePtr/test1/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/IsBadCodePtr/test1/testinfo.dat
new file mode 100644
index 0000000000..8b73c0dfca
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/IsBadCodePtr/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = C Runtime
+Function = IsBadCodePtr
+Name = Positive Test for IsBadCodePtr
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= ensure that IsBadCodePtr return 0 when
+= it can read memory or non zero when it can't.
diff --git a/src/pal/tests/palsuite/miscellaneous/IsBadReadPtr/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/IsBadReadPtr/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/IsBadReadPtr/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/miscellaneous/IsBadReadPtr/test1/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/IsBadReadPtr/test1/CMakeLists.txt
new file mode 100644
index 0000000000..f1e84d73b8
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/IsBadReadPtr/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.c
+)
+
+add_executable(paltest_isbadreadptr_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_isbadreadptr_test1 coreclrpal)
+
+target_link_libraries(paltest_isbadreadptr_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/IsBadReadPtr/test1/test.c b/src/pal/tests/palsuite/miscellaneous/IsBadReadPtr/test1/test.c
new file mode 100644
index 0000000000..24b7ceb7e6
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/IsBadReadPtr/test1/test.c
@@ -0,0 +1,138 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: test.c
+**
+** Purpose: IsBadReadPtr() function
+**
+**
+**=========================================================*/
+
+#include <palsuite.h>
+
+#define MEMORY_AMOUNT 16
+
+int __cdecl main(int argc, char *argv[])
+{
+ LPVOID TestingPointer = NULL;
+ BOOL ResultValue = 0;
+
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ TestingPointer = malloc(MEMORY_AMOUNT);
+ if ( TestingPointer == NULL )
+ {
+ Fail("ERROR: Failed to allocate memory for TestingPointer pointer. "
+ "Can't properly exec test case without this.\n");
+ }
+
+
+ /* This should be readable, and return 0 */
+ ResultValue = IsBadReadPtr(TestingPointer,MEMORY_AMOUNT);
+ if(ResultValue != 0)
+ {
+ free(TestingPointer);
+
+ Fail("ERROR: The function returned %d instead of 0, when pointing "
+ "at readable memory.\n",ResultValue);
+ }
+
+ /* If we pass 0, the result should be 0 as well */
+ ResultValue = IsBadReadPtr(TestingPointer,0);
+ if(ResultValue != 0)
+ {
+ free(TestingPointer);
+
+ Fail("ERROR: The function returned %d instead of 0, when the "
+ "function was passed a range of 0 bytes.\n",ResultValue);
+ }
+ free(TestingPointer); /* we are done with this */
+
+ /* create a READABLE address */
+ TestingPointer = VirtualAlloc(
+ NULL, /* system selects address */
+ 80, /* size of allocation*/
+ MEM_COMMIT, /* commit */
+ PAGE_READONLY); /* protection = read only */
+
+ if (TestingPointer == NULL )
+ {
+ Fail("ERROR: call to VirtualAlloc failed\n");
+ }
+
+ ResultValue = IsBadReadPtr(TestingPointer,16);
+ if(ResultValue != 0) /* if no access */
+ {
+ if(!VirtualFree(TestingPointer, 0, MEM_RELEASE))
+ {
+ Trace("ERROR: Call to VirtualFree failed with error"
+ " code[ %u ]\n",GetLastError());
+ }
+
+ Fail("ERROR: The function returned %d instead of 1 when checking "
+ "on unreadable memory.\n",ResultValue);
+ }
+
+ if(!VirtualFree(TestingPointer,0, MEM_RELEASE))
+ {
+ Fail("ERROR: Call to VirtualFree failed with error"
+ " code[ %u ]\n",GetLastError());
+ }
+
+ /* create an unreadable address */
+ TestingPointer = VirtualAlloc(
+ NULL, /* system selects address */
+ 80, /* size of allocation */
+ MEM_COMMIT, /* commit */
+ PAGE_NOACCESS); /* protection = no access */
+
+ if (TestingPointer == NULL )
+ {
+ Fail("ERROR: call to VirtualAlloc failed\n");
+ }
+
+ ResultValue = IsBadReadPtr(TestingPointer,16);
+
+ if(ResultValue == 0) /* if access */
+ {
+ if(!VirtualFree(TestingPointer, 0, MEM_RELEASE))
+ {
+ Trace("ERROR: Call to VirtualFree failed with error"
+ " code[ %u ]\n",GetLastError());
+ }
+
+ Fail("ERROR: The function returned %d instead of 1 when checking "
+ "on unreadable memory.\n",ResultValue);
+ }
+
+ if(!VirtualFree(TestingPointer,0, MEM_RELEASE))
+ {
+ Fail("ERROR: Call to VirtualFree failed with error"
+ " code[ %u ]\n",GetLastError());
+ }
+
+
+ /* This should be unreadable and return 1 */
+ ResultValue = IsBadReadPtr(NULL,16);
+ if(ResultValue != 1)
+ {
+ Fail("ERROR: The function returned %d instead of 1 when checking "
+ "to see if NULL was readable.\n",ResultValue);
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/IsBadReadPtr/test1/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/IsBadReadPtr/test1/testinfo.dat
new file mode 100644
index 0000000000..27668b66c7
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/IsBadReadPtr/test1/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = IsBadReadPtr
+Name = Return value tests for IsBadReadPtr
+TYPE = DEFAULT
+EXE1 = test
+Description
+= Ensure that this returns true and false when it is supposed to.
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/IsBadWritePtr/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/IsBadWritePtr/CMakeLists.txt
new file mode 100644
index 0000000000..1962ade358
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/IsBadWritePtr/CMakeLists.txt
@@ -0,0 +1,6 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+add_subdirectory(test3)
+
diff --git a/src/pal/tests/palsuite/miscellaneous/IsBadWritePtr/test1/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/IsBadWritePtr/test1/CMakeLists.txt
new file mode 100644
index 0000000000..2b2e6aae2e
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/IsBadWritePtr/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.c
+)
+
+add_executable(paltest_isbadwriteptr_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_isbadwriteptr_test1 coreclrpal)
+
+target_link_libraries(paltest_isbadwriteptr_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/IsBadWritePtr/test1/test.c b/src/pal/tests/palsuite/miscellaneous/IsBadWritePtr/test1/test.c
new file mode 100644
index 0000000000..018d7beae0
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/IsBadWritePtr/test1/test.c
@@ -0,0 +1,81 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: test.c
+**
+** Purpose: IsBadWritePtr() function
+**
+**
+**=========================================================*/
+
+#include <palsuite.h>
+
+#define MEMORY_AMOUNT 16
+
+int __cdecl main(int argc, char *argv[]) {
+
+ void * TestingPointer = NULL;
+ BOOL ResultValue = 0;
+
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ TestingPointer = malloc(MEMORY_AMOUNT);
+ if ( TestingPointer == NULL )
+ {
+ Fail("ERROR: Failed to allocate memory for TestingPointer pointer. "
+ "Can't properly exec test case without this.\n");
+ }
+
+
+ /* This should be writeable, return 0 */
+ ResultValue = IsBadWritePtr(TestingPointer,MEMORY_AMOUNT);
+
+ if(ResultValue != 0)
+ {
+ free(TestingPointer);
+
+ Fail("ERROR: Returned %d when 0 should have been returned, checking "
+ "to see if writable memory is unwriteable.\n",ResultValue);
+ }
+
+ free(TestingPointer);
+
+ /* This should be !writeable, return nonezero */
+ TestingPointer = (void*)0x08; /* non writeable address */
+ ResultValue = IsBadWritePtr(TestingPointer,sizeof(int));
+
+ if(ResultValue == 0)
+ {
+ Fail("ERROR: Returned %d when nonezero should have been returned, "
+ "checking to see if unwriteable memory is writeable.\n",
+ ResultValue);
+ }
+
+ /* This should be !writeable, return Nonezero */
+ ResultValue = IsBadWritePtr(NULL,MEMORY_AMOUNT);
+
+ if(ResultValue == 0)
+ {
+ Fail("ERROR: Returned %d when nonezero should have been "
+ "returned,checking "
+ "to see if a NULL pointer is writeable.\n",
+ ResultValue);
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/IsBadWritePtr/test1/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/IsBadWritePtr/test1/testinfo.dat
new file mode 100644
index 0000000000..ba4e97ebbc
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/IsBadWritePtr/test1/testinfo.dat
@@ -0,0 +1,16 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = IsBadWritePtr
+Name = Return Value test IsBadWritePtr
+TYPE = DEFAULT
+EXE1 = test
+Description
+= Test to ensure that the function returns true and
+= false when it is supposed to.
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/IsBadWritePtr/test2/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/IsBadWritePtr/test2/CMakeLists.txt
new file mode 100644
index 0000000000..c033f8054f
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/IsBadWritePtr/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test2.c
+)
+
+add_executable(paltest_isbadwriteptr_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_isbadwriteptr_test2 coreclrpal)
+
+target_link_libraries(paltest_isbadwriteptr_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/IsBadWritePtr/test2/test2.c b/src/pal/tests/palsuite/miscellaneous/IsBadWritePtr/test2/test2.c
new file mode 100644
index 0000000000..2d4d53e3b7
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/IsBadWritePtr/test2/test2.c
@@ -0,0 +1,128 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: test2.c
+**
+** Purpose:
+** Create three consecuative pages, NOACCES, READWRITE and
+** NOACCESS. Check to ensure that the READWRITE page returns 0, to
+** ensure that IsBadWritePtr isn't overflowing. Also check the other two
+** pages to see that they return non-zero.
+**
+**
+**=========================================================*/
+
+#include <palsuite.h>
+#define PAGE_SIZE 4096
+
+int __cdecl main(int argc, char *argv[]) {
+
+ LPVOID PageOne, PageTwo, PageThree;
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /* Reserve enough space for four pages. We'll commit this memory
+ and set the correct access for each page below.
+ */
+
+ PageOne = VirtualAlloc(NULL,
+ PAGE_SIZE*4,
+ MEM_RESERVE,
+ PAGE_NOACCESS);
+
+ if(PageOne == NULL)
+ {
+ Fail("ERROR: VirtualAlloc failed to reserve the required memory.\n");
+ }
+
+ /* Set the first Page to PAGE_NOACCESS */
+
+ PageOne = VirtualAlloc(PageOne,
+ PAGE_SIZE,
+ MEM_COMMIT,
+ PAGE_NOACCESS);
+
+ if(PageOne == NULL)
+ {
+ VirtualFree(PageOne,0,MEM_RELEASE);
+
+ Fail("ERROR: VirtualAlloc failed to commit the required memory "
+ "for the first page.\n");
+ }
+
+ /* Set the second Page to PAGE_READWRITE */
+
+ PageTwo = VirtualAlloc(((BYTE*)PageOne)+PAGE_SIZE,
+ PAGE_SIZE,
+ MEM_COMMIT,
+ PAGE_READWRITE);
+ if(PageTwo == NULL)
+ {
+ VirtualFree(PageOne,0,MEM_RELEASE);
+
+ Fail("ERROR: VirtualAlloc failed to allocate the required memory "
+ "for the second page. %d\n",GetLastError());
+ }
+
+ /* Set the third Page to PAGE_NOACCESS */
+
+ PageThree = VirtualAlloc(((BYTE*)PageTwo) + (2 * PAGE_SIZE),
+ PAGE_SIZE,
+ MEM_COMMIT,
+ PAGE_NOACCESS);
+
+ if(PageThree == NULL)
+ {
+ VirtualFree(PageOne,0,MEM_RELEASE);
+
+ Fail("ERROR: VirtualAlloc failed to allocate the required memory. "
+ "For the third page.\n");
+ }
+
+
+/* Check that calling IsBadWritePtr on the first page returns non-zero */
+
+ if(IsBadWritePtr(PageThree,PAGE_SIZE) == 0)
+ {
+ VirtualFree(PageOne,0,MEM_RELEASE);
+
+ Fail("ERROR: Called IsBadWritePtr on a page which was set NOACCESS "
+ "but the return value was 0, indicating that the memory is "
+ "writable.\n");
+ }
+
+ /* Check that calling IsBadWritePtr on the middle page returns 0 */
+
+ if(IsBadWritePtr(PageTwo,PAGE_SIZE) != 0)
+ {
+ VirtualFree(PageOne,0,MEM_RELEASE);
+
+ Fail("ERROR: IsBadWritePtr didn't return 0 when called on a "
+ "page which should have been writable.\n");
+ }
+
+ /* Check that calling IsBadWritePtr on the third page returns non-zero */
+
+ if(IsBadWritePtr(PageThree,PAGE_SIZE) == 0)
+ {
+ VirtualFree(PageOne,0,MEM_RELEASE);
+
+ Fail("ERROR: Called IsBadWritePtr on a page which was set NOACCESS "
+ "but the return value was 0, indicating that the memory is "
+ "writable.\n");
+ }
+ VirtualFree(PageOne,0,MEM_RELEASE);
+ PAL_Terminate();
+ return PASS;
+}
+
+
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/IsBadWritePtr/test2/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/IsBadWritePtr/test2/testinfo.dat
new file mode 100644
index 0000000000..ad0a5fe90e
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/IsBadWritePtr/test2/testinfo.dat
@@ -0,0 +1,19 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = IsBadWritePtr
+Name = Return Value test IsBadWritePtr
+TYPE = DEFAULT
+EXE1 = test2
+Description
+= Create three consecuative pages, NOACCES, READWRITE and
+= NOACCESS. Check to ensure that the READWRITE page returns 0, to
+= ensure that IsBadWritePtr isn't overflowing. Also check the other two
+= pages to see that they return non-zero.
+
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/IsBadWritePtr/test3/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/IsBadWritePtr/test3/CMakeLists.txt
new file mode 100644
index 0000000000..32cb901e8d
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/IsBadWritePtr/test3/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test3.c
+)
+
+add_executable(paltest_isbadwriteptr_test3
+ ${SOURCES}
+)
+
+add_dependencies(paltest_isbadwriteptr_test3 coreclrpal)
+
+target_link_libraries(paltest_isbadwriteptr_test3
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/IsBadWritePtr/test3/test3.c b/src/pal/tests/palsuite/miscellaneous/IsBadWritePtr/test3/test3.c
new file mode 100644
index 0000000000..4c058a8987
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/IsBadWritePtr/test3/test3.c
@@ -0,0 +1,58 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: test3.c
+**
+** Purpose:
+** Check that IsBadWritePtr returns non-zero on Read-only memory.
+**
+**
+**=========================================================*/
+
+#include <palsuite.h>
+
+#define PAGE_SIZE 4096
+
+int __cdecl main(int argc, char *argv[]) {
+
+ LPVOID PageOne;
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /* Reserve enough space for four pages. We'll commit this memory
+ and set the correct access for each page below.
+ */
+
+ PageOne = VirtualAlloc(NULL,
+ PAGE_SIZE,
+ MEM_COMMIT,
+ PAGE_READONLY);
+
+ if(PageOne == NULL)
+ {
+ Fail("ERROR: VirtualAlloc failed to commit the required memory.\n");
+ }
+
+ if(IsBadWritePtr(PageOne,PAGE_SIZE) == 0)
+ {
+ VirtualFree(PageOne,0,MEM_RELEASE);
+
+ Fail("ERROR: IsBadWritePtr returned 0 when checking a section of "
+ "read-only memory. It should be non-zero.\n");
+ }
+
+ VirtualFree(PageOne,0,MEM_RELEASE);
+ PAL_Terminate();
+ return PASS;
+}
+
+
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/IsBadWritePtr/test3/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/IsBadWritePtr/test3/testinfo.dat
new file mode 100644
index 0000000000..18851d2fde
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/IsBadWritePtr/test3/testinfo.dat
@@ -0,0 +1,17 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = IsBadWritePtr
+Name = Return Value test IsBadWritePtr
+TYPE = DEFAULT
+EXE1 = test3
+Description
+= Check that IsBadWritePtr returns non-zero on Read-only memory.
+
+
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/MessageBoxW/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/MessageBoxW/CMakeLists.txt
new file mode 100644
index 0000000000..ef14ea5352
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/MessageBoxW/CMakeLists.txt
@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+
diff --git a/src/pal/tests/palsuite/miscellaneous/MessageBoxW/test1/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/MessageBoxW/test1/CMakeLists.txt
new file mode 100644
index 0000000000..5e77e8ba98
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/MessageBoxW/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.c
+)
+
+add_executable(paltest_messageboxw_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_messageboxw_test1 coreclrpal)
+
+target_link_libraries(paltest_messageboxw_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/MessageBoxW/test1/test.c b/src/pal/tests/palsuite/miscellaneous/MessageBoxW/test1/test.c
new file mode 100644
index 0000000000..8eb8c0eb7e
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/MessageBoxW/test1/test.c
@@ -0,0 +1,81 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: test.c
+**
+** Purpose: Test for MessageBoxW() function
+**
+**
+**=========================================================*/
+
+#define UNICODE
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ /* Declare Variables to use with convert()*/
+ WCHAR * PalTitle = NULL;
+ WCHAR * OkTesting = NULL;
+ WCHAR * AbortTesting = NULL;
+ WCHAR * YesTesting = NULL;
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ PalTitle = convert("Pal Testing");
+ OkTesting = convert("Click OK Please!");
+
+ /* Handle, text, title, style */
+ if(MessageBox(NULL, OkTesting,
+ PalTitle,
+ MB_OK) != IDOK)
+ {
+ free(OkTesting);
+ free(PalTitle);
+ Fail("ERROR: The MB_OK style should return IDOK.");
+ }
+
+ free(OkTesting);
+ AbortTesting = convert("Click Abort Please!");
+ if(MessageBox(NULL,
+ AbortTesting,
+ PalTitle,
+ MB_ABORTRETRYIGNORE) != IDABORT)
+ {
+ free(AbortTesting);
+ free(PalTitle);
+ Fail("ERROR: The MB_ABORTRETRYIGNORE style should "
+ "return IDABORT.");
+ }
+
+ free(AbortTesting);
+ YesTesting = convert("Click No Please!");
+
+ if(MessageBox(NULL,
+ YesTesting,
+ PalTitle,
+ MB_YESNO) != IDNO)
+ {
+ free(PalTitle);
+ free(YesTesting);
+ Fail("ERROR: The MB_YESNO style should return IDNO.");
+ }
+
+ free(YesTesting);
+ free(PalTitle);
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/MessageBoxW/test1/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/MessageBoxW/test1/testinfo.dat
new file mode 100644
index 0000000000..e4d46c986b
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/MessageBoxW/test1/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = MessageBoxW
+Name = Positive test of MessageBoxW
+TYPE = DEFAULT
+EXE1 = test
+Description
+= Ensure that the return values are correct for each type of Message Style.
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/MessageBoxW/test2/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/MessageBoxW/test2/CMakeLists.txt
new file mode 100644
index 0000000000..4b0af2e77e
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/MessageBoxW/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.c
+)
+
+add_executable(paltest_messageboxw_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_messageboxw_test2 coreclrpal)
+
+target_link_libraries(paltest_messageboxw_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/MessageBoxW/test2/test.c b/src/pal/tests/palsuite/miscellaneous/MessageBoxW/test2/test.c
new file mode 100644
index 0000000000..e2ff0cf6d6
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/MessageBoxW/test2/test.c
@@ -0,0 +1,76 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: test.c
+**
+** Purpose: Test for MessageBoxW() function
+**
+**
+**=========================================================*/
+
+#define UNICODE
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[]) {
+
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /* Check to make sure there are no problems accepting all the ICON
+ styles and FLAG styles. These don't change anything, unless
+ they don't work at all.
+ */
+
+ if(MessageBox(NULL,
+ convert("Pal Testing"),
+ convert("Pal Title"),
+ MB_OK |MB_ICONEXCLAMATION|MB_TASKMODAL) != IDOK)
+ {
+ Fail("ERROR: The MB_OK style should always return IDOK.");
+ }
+
+ if(MessageBox(NULL,
+ convert("Pal Testing"),
+ convert("Pal Title"),
+ MB_OK |MB_ICONINFORMATION|MB_SYSTEMMODAL) != IDOK)
+ {
+ Fail("ERROR: The MB_OK style should always return IDOK.");
+ }
+
+ /* MB_SERVICE_NOTIFICATION doesn't seem to be available under windows?
+ It claims it exists and it should be supported under FreeBSD.
+ */
+
+#if UNIX
+ if(MessageBox(NULL,
+ convert("Pal Testing"),
+ convert("Pal Title"),
+ MB_OK |MB_ICONSTOP|MB_SERVICE_NOTIFICATION) != IDOK)
+ {
+ Fail("ERROR: The MB_OK style should always return IDOK.");
+ }
+#endif
+
+ if(MessageBox(NULL,
+ convert("Pal Testing"),
+ convert("Pal Title"),
+ MB_OK |MB_ICONQUESTION) != IDOK)
+ {
+ Fail("ERROR: The MB_OK style should always return IDOK.");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/MessageBoxW/test2/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/MessageBoxW/test2/testinfo.dat
new file mode 100644
index 0000000000..e4d46c986b
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/MessageBoxW/test2/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = MessageBoxW
+Name = Positive test of MessageBoxW
+TYPE = DEFAULT
+EXE1 = test
+Description
+= Ensure that the return values are correct for each type of Message Style.
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableA/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableA/CMakeLists.txt
new file mode 100644
index 0000000000..a3847f8ca9
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableA/CMakeLists.txt
@@ -0,0 +1,7 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+add_subdirectory(test3)
+add_subdirectory(test4)
+
diff --git a/src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableA/test1/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableA/test1/CMakeLists.txt
new file mode 100644
index 0000000000..b66248522b
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableA/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_setenvironmentvariablea_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_setenvironmentvariablea_test1 coreclrpal)
+
+target_link_libraries(paltest_setenvironmentvariablea_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableA/test1/test1.c b/src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableA/test1/test1.c
new file mode 100644
index 0000000000..86a44218f1
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableA/test1/test1.c
@@ -0,0 +1,168 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: test1.c
+**
+** Purpose: Test for SetEnvironmentVariableA() function. Set an
+** environment variable and check to ensure success was returned. Then
+** get the environment variable and compare to the correct value. Also, check
+** that calling the function again, resets the variable properly. And that
+** calling with NULL deletes the variable.
+**
+** Depends:
+** GetEnvironmentVariable
+** memcmp
+** memset
+** strlen
+**
+**
+**=========================================================*/
+
+#include <palsuite.h>
+#define BUF_SIZE 128
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ /* Define some buffers needed for the function */
+ char* VariableBuffer = "PALTEST";
+ char* ValueBuffer = "Testing";
+ char* SecondValueBuffer = "SecondTest";
+ char NewValue[BUF_SIZE];
+ int SetResult = 0;
+
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+
+
+ /*
+ Test #1
+ =======
+ */
+
+ SetResult = SetEnvironmentVariable(VariableBuffer,
+ ValueBuffer);
+
+ /* If result is 0, the SetEnviron function failed */
+ if(SetResult == 0)
+ {
+ Fail("ERROR: SetEnvironmentVariable returned 0, which indicates that "
+ "it failed, even though it should have succeeded in setting the "
+ "variable PALTEST.\n");
+ }
+
+ memset(NewValue,0,BUF_SIZE);
+
+ /* Grab the Environment variable we just set */
+ if(GetEnvironmentVariable(VariableBuffer,NewValue,BUF_SIZE) <= 0)
+ {
+ Fail("ERROR: GetEnvironmentVariable returned 0 or less, which "
+ "indicates that no value was read in from the given variable.");
+ }
+
+ /* Make sure that the value put into NewValue was indeed the environment
+ variable we set.
+ */
+
+ if(memcmp(NewValue,ValueBuffer,strlen(ValueBuffer)+1) != 0)
+ {
+ Fail("ERROR: When retrieving the variable that was just set, a "
+ "difference was found. Instead of the value being '%s' it "
+ "was instead '%s'.\n",ValueBuffer,NewValue);
+ }
+
+
+
+ /*
+ Test #2
+ =======
+ */
+
+ /* If we set the same environment variable with a different value, the
+ old value should be replaced.
+ */
+
+ SetResult = SetEnvironmentVariable(VariableBuffer,
+ SecondValueBuffer);
+
+ /* If result is 0, the SetEnviron function failed */
+ if(SetResult == 0)
+ {
+ Fail("ERROR: SetEnvironmentVariable returned 0, which indicates that "
+ "it failed, even though it should have succeeded in re-setting "
+ "the variable PALTEST.\n");
+ }
+
+ memset(NewValue,0,BUF_SIZE);
+
+ /* Grab the Environment variable we just set */
+ if(GetEnvironmentVariable(VariableBuffer,NewValue,BUF_SIZE) <= 0)
+ {
+ Fail("ERROR: GetEnvironmentVariable returned 0 or less, which "
+ "indicates that no value was read in from the given variable.");
+ }
+
+ /* Make sure that the value put into NewValue was indeed the environment
+ variable we set.
+ */
+
+ if(memcmp(NewValue,SecondValueBuffer,strlen(SecondValueBuffer)+1) != 0)
+ {
+ Fail("ERROR: When retrieving the variable that was just set, a "
+ "difference was found. Instead of the value being '%s' it "
+ "was instead '%s'.\n",SecondValueBuffer,NewValue);
+ }
+
+
+
+ /*
+ Test #3
+ =======
+ */
+
+ /* Finally, set this variable with NULL, which should delete it from the
+ current environment.
+ */
+
+ SetResult = SetEnvironmentVariable(VariableBuffer, NULL);
+
+ /* If result is 0, the SetEnviron function failed */
+ if(SetResult == 0)
+ {
+ Fail("ERROR: SetEnvironmentVariable returned 0, which indicates that "
+ "it failed, even though it should have succeeded in deleting "
+ "the variable PALTEST.\n");
+ }
+
+ memset(NewValue,0,BUF_SIZE);
+
+ /* Grab the Environment variable we just set, ensure that it's
+ empty now.
+ */
+ if(GetEnvironmentVariable(VariableBuffer,NewValue,BUF_SIZE) != 0)
+ {
+ Fail("ERROR: GetEnvironmentVariable returned a non-zero value, "
+ "even though the environment variable which was checked should "
+ "have been empty.");
+ }
+
+
+ /*
+ Clean Up
+ */
+ PAL_Terminate();
+ return PASS;
+}
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableA/test1/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableA/test1/testinfo.dat
new file mode 100644
index 0000000000..561cd943fc
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableA/test1/testinfo.dat
@@ -0,0 +1,19 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = SetEnvironmentVariableA
+Name = Positive test of SetEnvironmentVariableA
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Set an environment variable and check to ensure success was returned. Then
+= get the environment variable and compare to the correct value. Also, check
+= that calling the function again, resets the variable properly. And that
+= calling with NULL deletes the variable.
+
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableA/test2/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableA/test2/CMakeLists.txt
new file mode 100644
index 0000000000..c062c6df65
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableA/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test2.c
+)
+
+add_executable(paltest_setenvironmentvariablea_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_setenvironmentvariablea_test2 coreclrpal)
+
+target_link_libraries(paltest_setenvironmentvariablea_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableA/test2/test2.c b/src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableA/test2/test2.c
new file mode 100644
index 0000000000..984007e6f1
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableA/test2/test2.c
@@ -0,0 +1,85 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: test2.c
+**
+** Purpose: Test for SetEnvironmentVariableA() function
+** Test to see that passing NULL to the first param fails.
+** Test that passing NULL to both params fails.
+** Set an environment variable, then pass NULL to the second param
+** to delete it. Then make the same call again, to check that it fails.
+**
+**
+**=========================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ /* Define some buffers needed for the function */
+ char* VariableBuffer = "PALTEST";
+ char* ValueBuffer = "testing";
+ int SetResult;
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /* Check that it fails if the first param is NULL */
+
+ SetResult = SetEnvironmentVariable(NULL,ValueBuffer);
+
+ if(SetResult != 0)
+ {
+ Fail("ERROR: SetEnvironmentVariable returned a success value, "
+ "even though it was passed NULL as the first parameter and "
+ "should have failed.\n");
+ }
+
+ /* Check that it fails when both params are NULL */
+ SetResult = SetEnvironmentVariable(NULL,NULL);
+ if(SetResult != 0)
+ {
+ Fail("ERROR: SetEnvironmentVariable returned a success value, even "
+ "though it was passed NULL as the first and second parameter and "
+ "should have failed.\n");
+ }
+
+
+ /* First, set the variable, which should be ok. Then call the
+ function with the second parameter NULL twice -- the first call should
+ pass, the second should fail.
+ */
+
+ SetResult = SetEnvironmentVariable(VariableBuffer,ValueBuffer);
+ if(SetResult == 0)
+ {
+ Fail("ERROR: SetEnvironmentVariable returned failure, when "
+ "attempting to set a valid variable.\n");
+ }
+
+ SetResult = SetEnvironmentVariable(VariableBuffer,NULL);
+ if(SetResult == 0)
+ {
+ Fail("ERROR: SetEnvironmentVariable returned failure, when "
+ "attempting to delete a variable.\n");
+ }
+
+ SetResult = SetEnvironmentVariable(VariableBuffer,NULL);
+ if(SetResult != 0)
+ {
+ Fail("ERROR: SetEnvironmentVariable returned success, when "
+ "attempting to delete a variable which doesn't exist.\n");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableA/test2/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableA/test2/testinfo.dat
new file mode 100644
index 0000000000..446e301500
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableA/test2/testinfo.dat
@@ -0,0 +1,19 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = SetEnvironmentVariableA
+Name = Return value test of SetEnvironmentVariableA
+TYPE = DEFAULT
+EXE1 = test2
+Description
+= Test to see that passing NULL to the first param fails.
+= Test that passing NULL to both params fails.
+= Set an environment variable, then pass NULL to the second param
+= to delete it. Then make the same call again, to check that it fails.
+
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableA/test3/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableA/test3/CMakeLists.txt
new file mode 100644
index 0000000000..159f574abe
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableA/test3/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test3.c
+)
+
+add_executable(paltest_setenvironmentvariablea_test3
+ ${SOURCES}
+)
+
+add_dependencies(paltest_setenvironmentvariablea_test3 coreclrpal)
+
+target_link_libraries(paltest_setenvironmentvariablea_test3
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableA/test3/test3.c b/src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableA/test3/test3.c
new file mode 100644
index 0000000000..fa24275da7
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableA/test3/test3.c
@@ -0,0 +1,144 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+** Source : test3.c
+**
+** Purpose: Test for SetEnvironmentVariableA() function
+** Create environment variables that differ only
+** in case and verify that they return the appropriate
+** value on the BSD environment.
+**
+**
+===========================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+
+#if WIN32
+
+ return PASS;
+
+#else
+
+ /* Define some buffers needed for the function */
+ char * pResultBuffer = NULL;
+
+ char FirstEnvironmentVariable[] = {"PALTEST"};
+ char FirstEnvironmentValue[] = {"FIRST"};
+
+ char SecondEnvironmentVariable[] = {"paltest"};
+ char SecondEnvironmentValue[] = {"SECOND"};
+
+ DWORD size = 0;
+ BOOL bRc = TRUE;
+
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /* Set the first environment variable */
+ bRc = SetEnvironmentVariableA(FirstEnvironmentVariable,
+ FirstEnvironmentValue);
+
+ if(!bRc)
+ {
+ Fail("ERROR: SetEnvironmentVariable failed to set a "
+ "proper environment variable with error %u.\n",
+ GetLastError());
+ }
+
+ /* Set the second environment Variable */
+ bRc = SetEnvironmentVariableA(SecondEnvironmentVariable,
+ SecondEnvironmentValue);
+
+ if(!bRc)
+ {
+ Fail("ERROR: SetEnvironmentVariable failed to set a "
+ "proper environment variable with error %u.\n",
+ GetLastError());
+ }
+
+
+ /* Normal case, PATH should fit into this buffer */
+ size = GetEnvironmentVariableA(FirstEnvironmentVariable,
+ pResultBuffer,
+ 0);
+
+ /* increase size to account for the null char at the end */
+ size = size + 1;
+
+ pResultBuffer = malloc(sizeof(char)*size);
+ if ( pResultBuffer == NULL )
+ {
+ Fail("ERROR: Failed to allocate memory for pResultBuffer pointer.\n");
+ }
+
+ /* Try to retrieve the value of the first environment variable */
+ GetEnvironmentVariable(FirstEnvironmentVariable,
+ pResultBuffer,
+ size);
+
+ if ( pResultBuffer == NULL )
+ {
+ free(pResultBuffer);
+ Fail("ERROR: GetEnvironmentVariable failed to return a value "
+ "from a proper environment variable with error %u.\n",
+ GetLastError());
+ }
+
+ /* Compare the strings to see that the correct variable was returned */
+ if(strcmp(pResultBuffer,FirstEnvironmentValue) != 0)
+ {
+ Trace("ERROR: The value in the buffer should have been '%s' but "
+ "was really '%s'.\n",FirstEnvironmentValue, pResultBuffer);
+ free(pResultBuffer);
+ Fail("");
+ }
+
+ free(pResultBuffer);
+
+ /* Reallocate the memory for the string */
+ pResultBuffer = malloc(sizeof(char)*size);
+ if ( pResultBuffer == NULL )
+ {
+ Fail("ERROR: Failed to allocate memory for pResultBuffer pointer.\n");
+ }
+
+ /* Try retrieving the value of the first variable, even though the
+ second variable has the same spelling and only differs in case */
+ GetEnvironmentVariable(SecondEnvironmentVariable,
+ pResultBuffer,
+ size);
+
+ if ( pResultBuffer == NULL )
+ {
+ Fail("ERROR: GetEnvironmentVariable failed to return a value "
+ "from a proper environment variable with error %u.\n",
+ GetLastError());
+ }
+
+ /* Compare the two strings to confirm that the right value is returned */
+ if(strcmp(pResultBuffer,SecondEnvironmentValue) != 0)
+ {
+ Trace("ERROR: The value in the buffer should have been '%s' but "
+ "was really '%s'.\n",SecondEnvironmentValue,pResultBuffer);
+ free(pResultBuffer);
+ Fail("");
+ }
+
+ free(pResultBuffer);
+
+ PAL_Terminate();
+ return PASS;
+
+#endif
+}
diff --git a/src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableA/test3/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableA/test3/testinfo.dat
new file mode 100644
index 0000000000..05076bb376
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableA/test3/testinfo.dat
@@ -0,0 +1,18 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = SetEnvironmentVariableA
+Name = Return value test of SetEnvironmentVariableA
+TYPE = DEFAULT
+EXE1 = test3
+Description
+= Test creating environment variables that differ only
+= by case and check that they are treated as separate
+= variables in the BSD operating system.
+
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableA/test4/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableA/test4/CMakeLists.txt
new file mode 100644
index 0000000000..29cca8d7b4
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableA/test4/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test4.c
+)
+
+add_executable(paltest_setenvironmentvariablea_test4
+ ${SOURCES}
+)
+
+add_dependencies(paltest_setenvironmentvariablea_test4 coreclrpal)
+
+target_link_libraries(paltest_setenvironmentvariablea_test4
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableA/test4/test4.c b/src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableA/test4/test4.c
new file mode 100644
index 0000000000..557cef74c9
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableA/test4/test4.c
@@ -0,0 +1,100 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+** Source : test4.c
+**
+** Purpose: Test for SetEnvironmentVariableA() function
+** Create environment variables that differ only
+** in case and verify that they return the appropriate
+** value in the WIN32 Environment
+**
+
+**
+===========================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+
+#if WIN32
+
+ /* Define some buffers needed for the function */
+ char * pResultBuffer = NULL;
+
+ char FirstEnvironmentVariable[] = {"PALTEST"};
+ char FirstEnvironmentValue[] = {"FIRST"};
+ char ModifiedEnvVar[] = {"paltest"};
+
+ DWORD size = 0;
+ BOOL bRc = TRUE;
+
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /* Set the first environment variable */
+ bRc = SetEnvironmentVariableA(FirstEnvironmentVariable,
+ FirstEnvironmentValue);
+
+ if(!bRc)
+ {
+ Fail("ERROR: SetEnvironmentVariable failed to set a "
+ "proper environment variable with error %u.\n",
+ GetLastError());
+ }
+
+ /* Normal case, PATH should fit into this buffer */
+ size = GetEnvironmentVariableA(ModifiedEnvVar,
+ pResultBuffer,
+ 0);
+
+ /* To account for the null character at the end of the string */
+ size = size + 1;
+
+ pResultBuffer = malloc(sizeof(char)*size);
+ if ( pResultBuffer == NULL )
+ {
+ Fail("ERROR: Failed to allocate memory for pResultBuffer pointer.\n");
+ }
+
+ /* Try to retrieve the value of the first environment variable */
+ GetEnvironmentVariableA(ModifiedEnvVar,
+ pResultBuffer,
+ size);
+
+ if ( pResultBuffer == NULL )
+ {
+ free(pResultBuffer);
+ Fail("ERROR: GetEnvironmentVariable failed to return a value "
+ "from a proper environment variable with error %u.\n",
+ GetLastError());
+ }
+
+ /* Compare the strings to see that the correct variable was returned */
+ if(strcmp(pResultBuffer,FirstEnvironmentValue) != 0)
+ {
+ Trace("ERROR: The value in the buffer should have been '%s' but "
+ "was really '%s'.\n",FirstEnvironmentValue, pResultBuffer);
+ free(pResultBuffer);
+ Fail("");
+ }
+
+ free(pResultBuffer);
+
+ PAL_Terminate();
+ return PASS;
+
+
+#else
+
+ return PASS;
+#endif
+}
diff --git a/src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableA/test4/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableA/test4/testinfo.dat
new file mode 100644
index 0000000000..925a917871
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableA/test4/testinfo.dat
@@ -0,0 +1,18 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = SetEnvironmentVariableA
+Name = Return value test of SetEnvironmentVariableA
+TYPE = DEFAULT
+EXE1 = test4
+Description
+= Test that creating an environment variable and trying
+= to attain the value of the environment variable using
+= a name with different case works in the Windows
+= Environment.
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableW/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableW/CMakeLists.txt
new file mode 100644
index 0000000000..a3847f8ca9
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableW/CMakeLists.txt
@@ -0,0 +1,7 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+add_subdirectory(test3)
+add_subdirectory(test4)
+
diff --git a/src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableW/test1/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableW/test1/CMakeLists.txt
new file mode 100644
index 0000000000..247dceefd9
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableW/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.c
+)
+
+add_executable(paltest_setenvironmentvariablew_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_setenvironmentvariablew_test1 coreclrpal)
+
+target_link_libraries(paltest_setenvironmentvariablew_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableW/test1/test.c b/src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableW/test1/test.c
new file mode 100644
index 0000000000..bddbba7940
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableW/test1/test.c
@@ -0,0 +1,142 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: test.c
+**
+** Purpose:
+** Set an environment variable and check to ensure success was returned. Then
+** get the environment variable and compare to the correct value. Also, check
+** that calling the function again, resets the variable properly. And that
+** calling with NULL deletes the variable.
+**
+**
+**=========================================================*/
+
+#define UNICODE
+#define BUF_SIZE 128
+
+#include <palsuite.h>
+
+/* Depends on GetEnvironmentVariable */
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ /* Define some buffers needed for the function */
+ WCHAR VariableBuffer[] = {'P','A','L','T','E','S','T','\0'};
+ WCHAR ValueBuffer[] = {'T','e','s','t','i','n','g','\0'};
+ WCHAR SecondValueBuffer[] = {'S','e','c','o','n','d','T','e','s','t','\0'};
+ WCHAR NewValue[BUF_SIZE];
+ int SetResult = 0;
+
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ SetResult = SetEnvironmentVariable(VariableBuffer,
+ ValueBuffer);
+
+ /* If result is 0, the SetEnviron function failed */
+ if(SetResult == 0)
+ {
+ Fail("ERROR: SetEnvironmentVariable returned 0, which indicates that "
+ "it failed, even though it should have succeeded in setting the "
+ "variable PALTEST.\n");
+ }
+
+
+ /* Grab the Environment variable we just set */
+ if(GetEnvironmentVariable(VariableBuffer,NewValue,BUF_SIZE) <= 0)
+ {
+ Fail("ERROR: GetEnvironmentVariable returned 0 or less, which "
+ "indicates that no value was read in from the given variable.");
+ }
+
+ /* Make sure that the value put into NewValue was indeed the environment
+ variable we set.
+ */
+
+ if(memcmp(NewValue,ValueBuffer,wcslen(ValueBuffer)*sizeof(WCHAR)+2) != 0)
+ {
+ Fail("ERROR: When retrieving the variable that was just set, a "
+ "difference was found. Instead of the value being '%s' it "
+ "was instead '%s'.\n",convertC(ValueBuffer),convertC(NewValue));
+ }
+
+ /* If we set the same environment variable with a different value, the
+ old value should be replaced.
+ */
+
+ SetResult = SetEnvironmentVariable(VariableBuffer,
+ SecondValueBuffer);
+
+ /* If result is 0, the SetEnviron function failed */
+ if(SetResult == 0)
+ {
+ Fail("ERROR: SetEnvironmentVariable returned 0, which indicates that "
+ "it failed, even though it should have succeeded in re-setting "
+ "the variable PALTEST.\n");
+ }
+
+ memset(NewValue,0,BUF_SIZE);
+
+ /* Grab the Environment variable we just set */
+ if(GetEnvironmentVariable(VariableBuffer,NewValue,BUF_SIZE) <= 0)
+ {
+ Fail("ERROR: GetEnvironmentVariable returned 0 or less, which "
+ "indicates that no value was read in from the given variable.");
+ }
+
+ /* Make sure that the value put into NewValue was indeed the environment
+ variable we set.
+ */
+
+ if(memcmp(NewValue,SecondValueBuffer,
+ wcslen(SecondValueBuffer)*sizeof(WCHAR)+2) != 0)
+ {
+ Fail("ERROR: When retrieving the variable that was just set, a "
+ "difference was found. Instead of the value being '%s' it "
+ "was instead '%s'.\n",
+ convertC(SecondValueBuffer),convertC(NewValue));
+ }
+
+ /* Finally, set this variable with NULL, which should delete it from the
+ current environment.
+ */
+
+ SetResult = SetEnvironmentVariable(VariableBuffer, NULL);
+
+ /* If result is 0, the SetEnviron function failed */
+ if(SetResult == 0)
+ {
+ Fail("ERROR: SetEnvironmentVariable returned 0, which indicates that "
+ "it failed, even though it should have succeeded in deleting "
+ "the variable PALTEST.\n");
+ }
+
+ memset(NewValue,0,BUF_SIZE);
+
+ /* Grab the Environment variable we just set, ensure that it's
+ empty now.
+ */
+ if(GetEnvironmentVariable(VariableBuffer,NewValue,BUF_SIZE) != 0)
+ {
+ Fail("ERROR: GetEnvironmentVariable returned a non-zero value, "
+ "even though the environment variable which was checked should "
+ "have been empty.");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableW/test1/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableW/test1/testinfo.dat
new file mode 100644
index 0000000000..a44f4674cf
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableW/test1/testinfo.dat
@@ -0,0 +1,18 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = SetEnvironmentVariableW
+Name = Positive test of SetEnvironmentVariableW
+TYPE = DEFAULT
+EXE1 = test
+Description
+= Set an environment variable and check to ensure success was returned. Then
+= get the environment variable and compare to the correct value. Also, check
+= that calling the function again, resets the variable properly. And that
+= calling with NULL deletes the variable.
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableW/test2/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableW/test2/CMakeLists.txt
new file mode 100644
index 0000000000..a69343ccd5
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableW/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.c
+)
+
+add_executable(paltest_setenvironmentvariablew_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_setenvironmentvariablew_test2 coreclrpal)
+
+target_link_libraries(paltest_setenvironmentvariablew_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableW/test2/test.c b/src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableW/test2/test.c
new file mode 100644
index 0000000000..12f4887b6d
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableW/test2/test.c
@@ -0,0 +1,88 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: test.c
+**
+** Purpose: Test for SetEnvironmentVariableW() function
+** Test to see that passing NULL to the first param fails.
+** Test that passing NULL to both params fails.
+** Set an environment variable, then pass NULL to the second param
+** to delete it. Then make the same call again, to check that it fails.
+**
+**
+**=========================================================*/
+
+#define UNICODE
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ /* Define some buffers needed for the function */
+ WCHAR VariableBuffer[] = {'P','A','L','T','E','S','T','\0'};
+ WCHAR ValueBuffer[] = {'T','e','s','t','i','n','g','\0'};
+ int SetResult;
+
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ SetResult = SetEnvironmentVariable(NULL,ValueBuffer);
+
+ /* Check that it fails if the first param is NULL */
+ if(SetResult != 0)
+ {
+ Fail("ERROR: SetEnvironmentVariable returned a success value, "
+ "even though it was passed NULL as the first parameter and "
+ "should have failed.\n");
+ }
+
+ /* Check that it fails when both params are NULL */
+ SetResult = SetEnvironmentVariable(NULL,NULL);
+ if(SetResult != 0)
+ {
+ Fail("ERROR: SetEnvironmentVariable returned a success value, even "
+ "though it was passed NULL as the first and second parameter and "
+ "should have failed.\n");
+ }
+
+ /* First, set the variable, which should be ok. Then call the
+ function with the second parameter NULL twice -- the first call should
+ pass, the second should fail.
+ */
+ SetResult = SetEnvironmentVariable(VariableBuffer,ValueBuffer);
+ if(SetResult == 0)
+ {
+ Fail("ERROR: SetEnvironmentVariable returned failure, when "
+ "attempting to set a valid variable.\n");
+ }
+
+ SetResult = SetEnvironmentVariable(VariableBuffer,NULL);
+ if(SetResult == 0)
+ {
+ Fail("ERROR: SetEnvironmentVariable returned failure, when "
+ "attempting to delete a variable.\n");
+ }
+
+ SetResult = SetEnvironmentVariable(VariableBuffer,NULL);
+ if(SetResult != 0)
+ {
+ Fail("ERROR: SetEnvironmentVariable returned success, when "
+ "attempting to delete a variable which doesn't exist.\n");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableW/test2/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableW/test2/testinfo.dat
new file mode 100644
index 0000000000..4df82daade
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableW/test2/testinfo.dat
@@ -0,0 +1,18 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = SetEnvironmentVariableW
+Name = Return value test of SetEnvironmentVariableW
+TYPE = DEFAULT
+EXE1 = test
+Description
+= Test to see that passing NULL to the first param fails.
+= Test that passing NULL to both params fails.
+= Set an environment variable, then pass NULL to the second param
+= to delete it. Then make the same call again, to check that it fails.
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableW/test3/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableW/test3/CMakeLists.txt
new file mode 100644
index 0000000000..e9072c7143
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableW/test3/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test3.c
+)
+
+add_executable(paltest_setenvironmentvariablew_test3
+ ${SOURCES}
+)
+
+add_dependencies(paltest_setenvironmentvariablew_test3 coreclrpal)
+
+target_link_libraries(paltest_setenvironmentvariablew_test3
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableW/test3/test3.c b/src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableW/test3/test3.c
new file mode 100644
index 0000000000..02d0a2d6d9
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableW/test3/test3.c
@@ -0,0 +1,143 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+** Source : test3.c
+**
+** Purpose: Test for SetEnvironmentVariableW() function
+** Create environment variables that differ only
+** in case and verify that they return the appropriate
+** value on the BSD environment.
+**
+**
+===========================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+
+#if WIN32
+
+ return PASS;
+
+#else
+
+ /* Define some buffers needed for the function */
+ WCHAR * pResultBuffer = NULL;
+
+ WCHAR FirstEnvironmentVariable[] = {'P','A','L','T','E','S','T','\0'};
+ WCHAR FirstEnvironmentValue[] = {'F','I','R','S','T','\0'};
+
+ WCHAR SecondEnvironmentVariable[] = {'p','a','l','t','e','s','t','\0'};
+ WCHAR SecondEnvironmentValue[] = {'S','E','C','O','N','D','\0'};
+
+ DWORD size = 0;
+ BOOL bRc = TRUE;
+
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /* Set the first environment variable */
+ bRc = SetEnvironmentVariableW(FirstEnvironmentVariable,
+ FirstEnvironmentValue);
+
+ if(!bRc)
+ {
+ Fail("ERROR: SetEnvironmentVariable failed to set a "
+ "proper environment variable with error %u.\n",
+ GetLastError());
+ }
+
+ /* Set the second environment Variable */
+ bRc = SetEnvironmentVariableW(SecondEnvironmentVariable,
+ SecondEnvironmentValue);
+
+ if(!bRc)
+ {
+ Fail("ERROR: SetEnvironmentVariable failed to set a "
+ "proper environment variable with error %u.\n",
+ GetLastError());
+ }
+
+
+ /* Normal case, PATH should fit into this buffer */
+ size = GetEnvironmentVariableW(FirstEnvironmentVariable,
+ pResultBuffer,
+ 0);
+
+ /* Increase size to account for the null char at the end */
+ size = size + 1;
+
+ pResultBuffer = malloc(sizeof(WCHAR)*size);
+ if ( pResultBuffer == NULL )
+ {
+ Fail("ERROR: Failed to allocate memory for pResultBuffer pointer.\n");
+ }
+
+ /* Try to retrieve the value of the first environment variable */
+ GetEnvironmentVariableW(FirstEnvironmentVariable,
+ pResultBuffer,
+ size);
+
+ if ( pResultBuffer == NULL )
+ {
+ Fail("ERROR: GetEnvironmentVariable failed to return a value "
+ "from a proper environment variable with error %u.\n",
+ GetLastError());
+ }
+
+ /* Compare the strings to see that the correct variable was returned */
+ if(wcscmp(pResultBuffer,FirstEnvironmentValue) != 0)
+ {
+ Trace("ERROR: The value in the buffer should have been '%S' but "
+ "was really '%S'.\n",FirstEnvironmentValue, pResultBuffer);
+ free(pResultBuffer);
+ Fail("");
+ }
+
+ free(pResultBuffer);
+
+ /* Reallocate the memory for the string */
+ pResultBuffer = malloc(sizeof(WCHAR)*size);
+ if ( pResultBuffer == NULL )
+ {
+ Fail("ERROR: Failed to allocate memory for pResultBuffer pointer.\n");
+ }
+
+ /* Try retrieving the value of the first variable, even though the
+ second variable has the same spelling and only differs in case */
+ GetEnvironmentVariableW(SecondEnvironmentVariable,
+ pResultBuffer,
+ size);
+
+ if ( pResultBuffer == NULL )
+ {
+ Fail("ERROR: GetEnvironmentVariable failed to return a value "
+ "from a proper environment variable with error %u.\n",
+ GetLastError());
+ }
+
+ /* Compare the two strings to confirm that the right value is returned */
+ if(wcscmp(pResultBuffer,SecondEnvironmentValue) != 0)
+ {
+ Trace("ERROR: The value in the buffer should have been '%S' but "
+ "was really '%S'.\n",SecondEnvironmentValue,pResultBuffer);
+ free(pResultBuffer);
+ Fail("");
+ }
+
+ free(pResultBuffer);
+
+ PAL_Terminate();
+ return PASS;
+
+#endif
+}
diff --git a/src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableW/test3/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableW/test3/testinfo.dat
new file mode 100644
index 0000000000..43a457a76a
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableW/test3/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = SetEnvironmentVariableW
+Name = Return value test of SetEnvironmentVariableW
+TYPE = DEFAULT
+EXE1 = test3
+Description
+= Create environment variables that differ only by case
+= and verify that they are treated distinctly in the
+= BSD Operating System.
diff --git a/src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableW/test4/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableW/test4/CMakeLists.txt
new file mode 100644
index 0000000000..f5f48bab33
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableW/test4/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test4.c
+)
+
+add_executable(paltest_setenvironmentvariablew_test4
+ ${SOURCES}
+)
+
+add_dependencies(paltest_setenvironmentvariablew_test4 coreclrpal)
+
+target_link_libraries(paltest_setenvironmentvariablew_test4
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableW/test4/test4.c b/src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableW/test4/test4.c
new file mode 100644
index 0000000000..b8f7734de4
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableW/test4/test4.c
@@ -0,0 +1,99 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+** Source : test4.c
+**
+** Purpose: Test for SetEnvironmentVariableW() function
+** Create environment variables that differ only
+** in case and verify that they return the appropriate
+** value on the BSD environment.
+**
+**
+===========================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+
+#if WIN32
+
+ /* Define some buffers needed for the function */
+ WCHAR * pResultBuffer = NULL;
+
+ WCHAR FirstEnvironmentVariable[] = {'P','A','L','T','E','S','T','\0'};
+ WCHAR FirstEnvironmentValue[] = {'F','I','R','S','T','\0'};
+
+ WCHAR ModifiedEnvironmentVariable[] = {'p','a','l','t','e','s','t','\0'};
+
+ DWORD size = 0;
+ BOOL bRc = TRUE;
+
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /* Set the first environment variable */
+ bRc = SetEnvironmentVariableW(FirstEnvironmentVariable,
+ FirstEnvironmentValue);
+
+ if(!bRc)
+ {
+ Fail("ERROR: SetEnvironmentVariable failed to set a "
+ "proper environment variable with error %u.\n",
+ GetLastError());
+ }
+
+ /* Normal case, PATH should fit into this buffer */
+ size = GetEnvironmentVariableW(ModifiedEnvironmentVariable,
+ pResultBuffer,
+ 0);
+
+ /* To account for the nul character at the end of the string */
+ size = size + 1;
+
+ pResultBuffer = malloc(sizeof(WCHAR)*size);
+ if ( pResultBuffer == NULL )
+ {
+ Fail("ERROR: Failed to allocate memory for pResultBuffer pointer.\n");
+ }
+
+ /* Try to retrieve the value of the first environment variable */
+ GetEnvironmentVariableW(ModifiedEnvironmentVariable,
+ pResultBuffer,
+ size);
+
+ if ( pResultBuffer == NULL )
+ {
+ Fail("ERROR: GetEnvironmentVariable failed to return a value "
+ "from a proper environment variable with error %u.\n",
+ GetLastError());
+ }
+
+ /* Compare the strings to see that the correct variable was returned */
+ if(wcsncmp(pResultBuffer,FirstEnvironmentValue,wcslen(pResultBuffer)) != 0)
+ {
+ Trace("ERROR: The value in the buffer should have been '%S' but "
+ "was really '%S'.\n",FirstEnvironmentValue, pResultBuffer);
+ free(pResultBuffer);
+ Fail("");
+ }
+
+ free(pResultBuffer);
+
+ PAL_Terminate();
+ return PASS;
+
+
+#else
+
+ return PASS;
+#endif
+}
diff --git a/src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableW/test4/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableW/test4/testinfo.dat
new file mode 100644
index 0000000000..ac3c4325e0
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/SetEnvironmentVariableW/test4/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = SetEnvironmentVariableW
+Name = Return value test of SetEnvironmentVariableW
+TYPE = DEFAULT
+EXE1 = test4
+Description
+= Create environment variable and try to retreive
+= the value of the variable by using a variable name
+= that differs in case. This should not affect the
+= return value in the Windows Operating System.
diff --git a/src/pal/tests/palsuite/miscellaneous/SetLastError/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/SetLastError/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/SetLastError/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/miscellaneous/SetLastError/test1/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/SetLastError/test1/CMakeLists.txt
new file mode 100644
index 0000000000..5248d6ce97
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/SetLastError/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.c
+)
+
+add_executable(paltest_setlasterror_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_setlasterror_test1 coreclrpal)
+
+target_link_libraries(paltest_setlasterror_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/SetLastError/test1/test.c b/src/pal/tests/palsuite/miscellaneous/SetLastError/test1/test.c
new file mode 100644
index 0000000000..d414626dd2
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/SetLastError/test1/test.c
@@ -0,0 +1,59 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: test.c
+**
+** Purpose: Test for SetLastError() function
+**
+**
+**=========================================================*/
+/* Depends on GetLastError() */
+
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[]) {
+
+ /* Error value that we can set to test */
+ const unsigned int FAKE_ERROR = 5;
+ const int NEGATIVE_ERROR = -1;
+
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /* Set error */
+ SetLastError(FAKE_ERROR);
+
+ /* Check to make sure it returns the error value we just set */
+ if(GetLastError() != FAKE_ERROR)
+ {
+ Fail("ERROR: The last error should have been '%d' but the error "
+ "returned was '%d'\n",FAKE_ERROR,GetLastError());
+ }
+
+ /* Set the error to a negative */
+ SetLastError(NEGATIVE_ERROR);
+
+ /* Check to make sure it returns the error value we just set */
+ if((signed)GetLastError() != NEGATIVE_ERROR)
+ {
+ Fail("ERROR: The last error should have been '%d' but the error "
+ "returned was '%d'\n",NEGATIVE_ERROR,GetLastError());
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/SetLastError/test1/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/SetLastError/test1/testinfo.dat
new file mode 100644
index 0000000000..5333a4bb36
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/SetLastError/test1/testinfo.dat
@@ -0,0 +1,16 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = SetLastError
+Name = Positive test of SetLastError
+TYPE = DEFAULT
+EXE1 = test
+Description
+= Set the Last Error and then use GetLastError to make sure
+= it was set properly. Assumes GetLastError is working.
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/_i64tow/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/_i64tow/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/_i64tow/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/miscellaneous/_i64tow/test1/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/_i64tow/test1/CMakeLists.txt
new file mode 100644
index 0000000000..6876d1b24e
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/_i64tow/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_i64tow_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_i64tow_test1 coreclrpal)
+
+target_link_libraries(paltest_i64tow_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/_i64tow/test1/test1.c b/src/pal/tests/palsuite/miscellaneous/_i64tow/test1/test1.c
new file mode 100644
index 0000000000..9a87328b0d
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/_i64tow/test1/test1.c
@@ -0,0 +1,76 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: test1.c
+**
+** Purpose: Tests _i64tow with normal values and different radices, negative
+** values, as well as the highest and lowest values.
+**
+**
+**============================================================*/
+
+#include <palsuite.h>
+
+typedef struct
+{
+ INT64 value;
+ int radix;
+ char *result;
+} testCase;
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ WCHAR buffer[256];
+ WCHAR *testStr;
+ WCHAR *ret;
+ int i;
+ testCase testCases[] =
+ {
+ {42, 10, "42"},
+ {42, 2, "101010"},
+ {29, 32, "t"},
+ {-1, 10, "-1"},
+ {-1, 8, "1777777777777777777777"},
+ {-1, 32, "fvvvvvvvvvvvv"},
+ {I64(0x7FFFFFFFFFFFFFFF), 10, "9223372036854775807"},
+ {I64(0x8000000000000000), 10, "-9223372036854775808"},
+ {0,2,"0"},
+ {0,16,"0"},
+ {3,16,"3"},
+ {15,16,"f"},
+ {16,16,"10"},
+
+ };
+
+
+ if (0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ for (i=0; i<sizeof(testCases) / sizeof(testCase); i++)
+ {
+ ret = _i64tow(testCases[i].value, buffer, testCases[i].radix);
+ if (ret != buffer)
+ {
+ Fail("_i64tow did not return a pointer to the string.\n"
+ "Expected %p, got %p\n", buffer, ret);
+ }
+
+ testStr = convert(testCases[i].result);
+ if (wcscmp(testStr, buffer) != 0)
+ {
+ Fail("_i64tow did not give the correct string.\n"
+ "Expected %S, got %S\n", testStr, buffer);
+ }
+ free(testStr);
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/miscellaneous/_i64tow/test1/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/_i64tow/test1/testinfo.dat
new file mode 100644
index 0000000000..a3979e60da
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/_i64tow/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = miscellaneous
+Function = _i64tow
+Name = Test #1 for _i64tow
+TYPE = DEFAULT
+EXE1 = test1
+Description
+=Tests _i64tow with normal values and different radices, negative
+=values, as well as the highest and lowest values.
diff --git a/src/pal/tests/palsuite/miscellaneous/_ui64tow/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/_ui64tow/CMakeLists.txt
new file mode 100644
index 0000000000..ef14ea5352
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/_ui64tow/CMakeLists.txt
@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+
diff --git a/src/pal/tests/palsuite/miscellaneous/_ui64tow/test1/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/_ui64tow/test1/CMakeLists.txt
new file mode 100644
index 0000000000..f920c4bded
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/_ui64tow/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ _ui64tow.c
+)
+
+add_executable(paltest_ui64tow_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_ui64tow_test1 coreclrpal)
+
+target_link_libraries(paltest_ui64tow_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/_ui64tow/test1/_ui64tow.c b/src/pal/tests/palsuite/miscellaneous/_ui64tow/test1/_ui64tow.c
new file mode 100644
index 0000000000..fb94f2509f
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/_ui64tow/test1/_ui64tow.c
@@ -0,0 +1,101 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: _ui64tow.c
+**
+** Purpose: Positive test the _ui64tow API.
+** convert an integer to a wide character string
+**
+**
+**============================================================*/
+#define UNICODE
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ int err;
+ WCHAR *wpBuffer = NULL;
+ char *pChar = NULL;
+ unsigned long ul = 1234567890UL;
+ char *pChar10 = "1234567890";
+ char *pChar2 = "1001001100101100000001011010010";
+ char *pChar16 = "499602d2";
+
+ /*Initialize the PAL environment*/
+ err = PAL_Initialize(argc, argv);
+ if(0 != err)
+ {
+ return FAIL;
+ }
+
+ wpBuffer = malloc(64 * sizeof(WCHAR));
+ if(NULL == wpBuffer)
+ {
+ Fail("\nFail to allocate the buffer to save a converted "
+ "wide character string, error code=%d!\n",
+ GetLastError());
+ }
+
+ /*convert to a 10 base string*/
+ _ui64tow(ul, wpBuffer, 10);
+ pChar = convertC(wpBuffer);
+ if(strcmp(pChar10, pChar))
+ {
+ free(wpBuffer);
+ free(pChar);
+ Fail("\nFailed to call _ui64tow API to convert an interger "
+ "to a 10 base wide character string, error code=%d\n",
+ GetLastError());
+ }
+ free(pChar);
+ free(wpBuffer);
+
+ wpBuffer = malloc(64 * sizeof(WCHAR));
+ if(NULL == wpBuffer)
+ {
+ Fail("\nFail to allocate the buffer to save a converted "
+ "wide character string, error code=%d!\n",
+ GetLastError());
+ }
+
+ /*convert to a 16 base string*/
+ _ui64tow(ul, wpBuffer, 16);
+ pChar = convertC(wpBuffer);
+ if(strcmp(pChar16, pChar))
+ {
+ free(wpBuffer);
+ free(pChar);
+ Fail("\nFailed to call _ui64tow API to convert an interger "
+ "to a 16 base wide character string, error code = %d\n",
+ GetLastError());
+ }
+ free(pChar);
+ free(wpBuffer);
+
+ wpBuffer = malloc(64 * sizeof(WCHAR));
+ if(NULL == wpBuffer)
+ {
+ Fail("\nFail to allocate the buffer to save a converted "
+ "wide character string, error code=%d!\n",
+ GetLastError());
+ }
+ /*convert to a 2 base string*/
+ _ui64tow(ul, wpBuffer, 2);
+ pChar = convertC(wpBuffer);
+ if(strcmp(pChar2, pChar))
+ {
+ free(wpBuffer);
+ free(pChar);
+ Fail("\nFailed to call _ui64tow API to convert an interger "
+ "to a 2 base wide character string, error code=%d\n",
+ GetLastError());
+ }
+ free(pChar);
+ free(wpBuffer);
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/miscellaneous/_ui64tow/test1/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/_ui64tow/test1/testinfo.dat
new file mode 100644
index 0000000000..a60f27a14a
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/_ui64tow/test1/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = miscellaneous
+Function = _ui64tow
+Name = Positive test _ui64tow to convert an integer to a wide character string
+TYPE = DEFAULT
+EXE1 = _ui64tow
+Description
+=Test the _ui64tow API to convert an integer to a wide character string
diff --git a/src/pal/tests/palsuite/miscellaneous/_ui64tow/test2/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/_ui64tow/test2/CMakeLists.txt
new file mode 100644
index 0000000000..b4feb4b8fd
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/_ui64tow/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ _ui64tow.c
+)
+
+add_executable(paltest_ui64tow_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_ui64tow_test2 coreclrpal)
+
+target_link_libraries(paltest_ui64tow_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/_ui64tow/test2/_ui64tow.c b/src/pal/tests/palsuite/miscellaneous/_ui64tow/test2/_ui64tow.c
new file mode 100644
index 0000000000..f13250578c
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/_ui64tow/test2/_ui64tow.c
@@ -0,0 +1,88 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: _ui64tow.c
+**
+** Purpose: Tests _ui64tow with normal values and different
+** radices,highest and lowest values.
+**
+**
+**============================================================*/
+
+#include <palsuite.h>
+
+typedef struct
+{
+ unsigned __int64 value;
+ int radix;
+ char* result;
+} testCase;
+
+
+int __cdecl main(int argc, char *argv[])
+{
+ WCHAR buffer[256];
+ WCHAR *testStr;
+ WCHAR *ret;
+ int i;
+ testCase testCases[] =
+ {
+ /* test limits */
+ {UI64(0xFFFFFFFFFFFFFFFF), 2,
+ "1111111111111111111111111111111111111111111111111111111111111111"},
+ {UI64(0xFFFFFFFFFFFFFFFF), 8, "1777777777777777777777"},
+ {UI64(0xFFFFFFFFFFFFFFFF), 10, "18446744073709551615"},
+ {UI64(0xFFFFFFFFFFFFFFFF), 16, "ffffffffffffffff"},
+ {47, 2, "101111"},
+ {47, 8, "57"},
+ {47, 10, "47"},
+ {47, 16, "2f"},
+ {12, 2, "1100"},
+ {12, 8, "14"},
+ {12, 10, "12"},
+ {12, 16, "c"},
+
+ /* test with 0. */
+ {0, 2, "0"},
+ {0, 8, "0"},
+ {0, 10, "0"},
+ {0, 16, "0"}
+ };
+
+ if (0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ for (i=0; i<sizeof(testCases) / sizeof(testCase); i++)
+ {
+ ret = _ui64tow(testCases[i].value, buffer, testCases[i].radix);
+
+ if (ret != buffer)
+ {
+ Fail("Failed to call _ui64tow API: did not return a pointer "
+ "to string. Expected %p, got %p\n", buffer, ret);
+ }
+
+ testStr = convert(testCases[i].result);
+
+ if (wcscmp(testStr, buffer) != 0)
+ {
+ Trace("ERROR: _ui64tow test#%d. Expected <%S>, got <%S>.\n",
+ i,testStr, buffer);
+ free(testStr);
+ Fail("");
+ }
+
+ free(testStr);
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/_ui64tow/test2/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/_ui64tow/test2/testinfo.dat
new file mode 100644
index 0000000000..0abbca2d11
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/_ui64tow/test2/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = miscellaneous
+Function = _ui64tow
+Name = Positive test _ui64tow to convert an integer to a wide character string
+TYPE = DEFAULT
+EXE1 = _ui64tow
+Description
+=Test the _ui64tow API to convert an integer to a wide character string
+=Test the limits. and 0.
diff --git a/src/pal/tests/palsuite/miscellaneous/lstrcatW/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/lstrcatW/CMakeLists.txt
new file mode 100644
index 0000000000..a3847f8ca9
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/lstrcatW/CMakeLists.txt
@@ -0,0 +1,7 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+add_subdirectory(test3)
+add_subdirectory(test4)
+
diff --git a/src/pal/tests/palsuite/miscellaneous/lstrcatW/test1/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/lstrcatW/test1/CMakeLists.txt
new file mode 100644
index 0000000000..aa5b0c2646
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/lstrcatW/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.c
+)
+
+add_executable(paltest_lstrcatw_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_lstrcatw_test1 coreclrpal)
+
+target_link_libraries(paltest_lstrcatw_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/lstrcatW/test1/test.c b/src/pal/tests/palsuite/miscellaneous/lstrcatW/test1/test.c
new file mode 100644
index 0000000000..ad1095e014
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/lstrcatW/test1/test.c
@@ -0,0 +1,59 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: test.c
+**
+** Purpose: Test for lstrcatW() function
+**
+**
+**=========================================================*/
+
+#define UNICODE
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[]) {
+
+ WCHAR FirstString[10] = {'T','E','S','T','\0'};
+ const WCHAR SecondString[] = {'P','A','L','!','\0'};
+ WCHAR CorrectString[] = {'T','E','S','T','P','A','L','!','\0'};
+ WCHAR* ReturnedPointer = NULL;
+
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ ReturnedPointer = lstrcat(FirstString,SecondString);
+
+ /* Check to see if the pointer returned points to the concat string */
+ if(ReturnedPointer != &FirstString[0])
+ {
+ Fail("ERROR: The function was supposed to return a pointer to "
+ "the concatentated string, but it did not.\n");
+ }
+
+ /* Check to make sure the Concat string is the same as the predetermined
+ 'CorrectString' */
+ if(memcmp(FirstString,CorrectString,
+ wcslen(FirstString)*sizeof(WCHAR)) != 0)
+ {
+ Fail("ERROR: The concatenated string should be %s but %s was the "
+ "result.\n",
+ convertC(CorrectString),
+ convertC(FirstString));
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/lstrcatW/test1/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/lstrcatW/test1/testinfo.dat
new file mode 100644
index 0000000000..006e83b882
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/lstrcatW/test1/testinfo.dat
@@ -0,0 +1,16 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = lstrcatW
+Name = Positive test of lstrcatW
+TYPE = DEFAULT
+EXE1 = test
+Description
+= Test to see that concatenating two strings works,
+= and also check return values in successful and failing situations.
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/lstrcatW/test2/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/lstrcatW/test2/CMakeLists.txt
new file mode 100644
index 0000000000..8a11c8f154
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/lstrcatW/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test2.c
+)
+
+add_executable(paltest_lstrcatw_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_lstrcatw_test2 coreclrpal)
+
+target_link_libraries(paltest_lstrcatw_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/lstrcatW/test2/test2.c b/src/pal/tests/palsuite/miscellaneous/lstrcatW/test2/test2.c
new file mode 100644
index 0000000000..6c66bc8976
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/lstrcatW/test2/test2.c
@@ -0,0 +1,53 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: test2.c
+**
+** Purpose: Negative test for lstrcatW() function
+**
+**
+**=========================================================*/
+
+#define UNICODE
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[]) {
+
+ WCHAR FirstString[10] = {'T','E','S','T','\0'};
+ const WCHAR SecondString[] = {'P','A','L','!','\0'};
+
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /* If either of these is NULL, function should fail and return NULL. */
+ if(lstrcat(NULL,SecondString) != NULL)
+ {
+ Fail("ERROR: When NULL was passed to the first parameter of the "
+ "function, it should have returned "
+ "NULL as a result, but did not.\n");
+ }
+
+ if(lstrcat(FirstString,NULL) != NULL)
+ {
+ Fail("ERROR: When NULL was passed to the second parameter of the "
+ "function, it should have returned "
+ "NULL as a result, but did not.\n");
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/lstrcatW/test2/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/lstrcatW/test2/testinfo.dat
new file mode 100644
index 0000000000..cc1ee644dc
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/lstrcatW/test2/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = lstrcatW
+Name = Negtive test of lstrcatW
+TYPE = DEFAULT
+EXE1 = test2
+Description
+= Test to see lstrcat reports error with failing situations.
diff --git a/src/pal/tests/palsuite/miscellaneous/lstrcatW/test3/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/lstrcatW/test3/CMakeLists.txt
new file mode 100644
index 0000000000..1cdecedf1a
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/lstrcatW/test3/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test3.c
+)
+
+add_executable(paltest_lstrcatw_test3
+ ${SOURCES}
+)
+
+add_dependencies(paltest_lstrcatw_test3 coreclrpal)
+
+target_link_libraries(paltest_lstrcatw_test3
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/lstrcatW/test3/test3.c b/src/pal/tests/palsuite/miscellaneous/lstrcatW/test3/test3.c
new file mode 100644
index 0000000000..49a9c57555
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/lstrcatW/test3/test3.c
@@ -0,0 +1,46 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: test3.c
+**
+** Purpose: Testing lstrcatw with two NULL strings passed on
+**
+**
+**=========================================================*/
+
+#define UNICODE
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+
+
+
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+
+ /* testing the behaviour of lstrcatW with two NULL strings */
+ if( lstrcat(NULL,NULL) != NULL)
+ {
+
+ Fail("lstrcat:ERROR: the function should returned NULL\n");
+
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/lstrcatW/test3/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/lstrcatW/test3/testinfo.dat
new file mode 100644
index 0000000000..794bcdbff7
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/lstrcatW/test3/testinfo.dat
@@ -0,0 +1,26 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+
+Section = Miscellaneous
+
+Function = lstrcatW
+
+Name = Negative testing for lstrcatW
+
+TYPE = DEFAULT
+
+EXE1 = test3
+
+Description
+
+= Testing the behaviour after sending two strings contained NULL
+
+
+
+
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/lstrcatW/test4/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/lstrcatW/test4/CMakeLists.txt
new file mode 100644
index 0000000000..640c224f83
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/lstrcatW/test4/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test4.c
+)
+
+add_executable(paltest_lstrcatw_test4
+ ${SOURCES}
+)
+
+add_dependencies(paltest_lstrcatw_test4 coreclrpal)
+
+target_link_libraries(paltest_lstrcatw_test4
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/lstrcatW/test4/test4.c b/src/pal/tests/palsuite/miscellaneous/lstrcatW/test4/test4.c
new file mode 100644
index 0000000000..abc9021518
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/lstrcatW/test4/test4.c
@@ -0,0 +1,101 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: test4.c
+**
+** Purpose: Testing the behaviour of lstrcatw when string2 contains
+** special characters, this test case depends on:
+** memcmp
+** wcslen
+** lstrcpyn
+**
+**
+**=========================================================*/
+
+#define UNICODE
+
+#include <palsuite.h>
+
+struct testCase
+{
+ WCHAR SecondString[5];
+ WCHAR CorrectString[10];
+};
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ WCHAR FirstString[10] = {'T','E','S','T','\0'};
+ WCHAR TestString[10] = {'T','E','S','T','\0'};
+ int i = 0;
+
+ /*
+ * this structure includes several strings to be tested with
+ * lstrcatW function and the expected results
+ */
+
+ struct testCase testCases[]=
+ {
+ {{'\t','T','A','B','\0'},
+ {'T','E','S','T','\t','T','A','B','\0'}},
+ {{'2','T','\?','B','\0'},
+ {'T','E','S','T','2','T','\?','B','\0'}},
+ {{'\v','T','E','\v','\0'},
+ {'T','E','S','T','\v','T','E','\v','\0'}},
+ {{'T','\a','E','\a','\0'},
+ {'T','E','S','T','T','\a','E','\a','\0'}},
+ {{'0','\f','Z','\f','\0'},
+ {'T','E','S','T','0','\f','Z','\f','\0'}},
+ {{'\r','H','I','\r','\0'},
+ {'T','E','S','T','\r','H','I','\r','\0'}},
+ {{'H','I','\"','\"','\0'},
+ {'T','E','S','T','H','I','\"','\"','\0'}},
+ {{'H','\b','I','\b','\0'},
+ {'T','E','S','T','H','\b','I','\b','\0'}},
+ {{'H','\n','I','\n','\0'},
+ {'T','E','S','T','H','\n','I','\n','\0'}}
+ };
+
+
+
+
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+
+ /* Loop through the struct and validate the resulted string */
+ for( i = 0; i < sizeof(testCases)/sizeof(struct testCase); i++)
+ {
+
+ lstrcat(FirstString, testCases[i].SecondString);
+
+ if(memcmp(FirstString,testCases[i].CorrectString,
+ wcslen(FirstString)*sizeof(WCHAR)))
+ {
+
+ Fail("ERROR: the function failed with a special character.\n");
+ }
+
+ /* reinitialize the first string */
+ lstrcpyn(FirstString,TestString,10);
+
+ }
+
+
+
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/lstrcatW/test4/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/lstrcatW/test4/testinfo.dat
new file mode 100644
index 0000000000..96235fb257
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/lstrcatW/test4/testinfo.dat
@@ -0,0 +1,28 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+
+Section = Miscellaneous
+
+Function = lstrcatW
+
+Name = Positive testing for lstrcatW
+
+TYPE = DEFAULT
+
+EXE1 = test4
+
+Description
+
+= Testing the behaviour of lstrcatw when string2 contains
+
+= special characters and validate the resulted string
+
+
+
+
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/lstrcpyW/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/lstrcpyW/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/lstrcpyW/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/miscellaneous/lstrcpyW/test1/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/lstrcpyW/test1/CMakeLists.txt
new file mode 100644
index 0000000000..e39c9a6098
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/lstrcpyW/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.c
+)
+
+add_executable(paltest_lstrcpyw_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_lstrcpyw_test1 coreclrpal)
+
+target_link_libraries(paltest_lstrcpyw_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/lstrcpyW/test1/test.c b/src/pal/tests/palsuite/miscellaneous/lstrcpyW/test1/test.c
new file mode 100644
index 0000000000..881ba033e8
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/lstrcpyW/test1/test.c
@@ -0,0 +1,66 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: test.c
+**
+** Purpose: Test for lstrcpyW() function
+**
+**
+**=========================================================*/
+
+#define UNICODE
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ WCHAR FirstString[5] = {'T','E','S','T','\0'};
+ WCHAR ResultBuffer[5];
+ WCHAR* ResultPointer = NULL;
+
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ ResultPointer = lstrcpy(ResultBuffer,FirstString);
+
+ /* Check the return value */
+ if(ResultPointer != &ResultBuffer[0])
+ {
+ Fail("ERROR: The function did not return a pointer to the Result "
+ "Buffer after being called.\n");
+ }
+
+ /* A straight copy, the values should be equal. */
+ if(memcmp(ResultBuffer,FirstString,wcslen(ResultBuffer)*2+2) != 0)
+ {
+ Fail("ERROR: The result of the copy was '%s' when it should have "
+ "been '%s'.\n",convertC(ResultBuffer),convertC(FirstString));
+ }
+
+ /* If either param is NULL, it should return NULL. */
+ if(lstrcpy(ResultBuffer,NULL) != NULL)
+ {
+ Fail("ERROR: The second parameter was NULL, so the function should "
+ "fail and return NULL.\n");
+ }
+ if(lstrcpy(NULL,FirstString) != NULL)
+ {
+ Fail("ERROR: The first parameter was NULL, so the function should "
+ "fail and return NULL.\n");
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/lstrcpyW/test1/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/lstrcpyW/test1/testinfo.dat
new file mode 100644
index 0000000000..37c9835236
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/lstrcpyW/test1/testinfo.dat
@@ -0,0 +1,16 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = lstrcpyW
+Name = Positive test of lstrcpyW
+TYPE = DEFAULT
+EXE1 = test
+Description
+= Ensure that a copy of a string works, and that the return values
+= are correct for success and failure.
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/lstrcpynW/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/lstrcpynW/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/lstrcpynW/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/miscellaneous/lstrcpynW/test1/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/lstrcpynW/test1/CMakeLists.txt
new file mode 100644
index 0000000000..4344b89402
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/lstrcpynW/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.c
+)
+
+add_executable(paltest_lstrcpynw_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_lstrcpynw_test1 coreclrpal)
+
+target_link_libraries(paltest_lstrcpynw_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/lstrcpynW/test1/test.c b/src/pal/tests/palsuite/miscellaneous/lstrcpynW/test1/test.c
new file mode 100644
index 0000000000..1ae0c51474
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/lstrcpynW/test1/test.c
@@ -0,0 +1,73 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: test.c
+**
+** Purpose: Test for lstrcpynW() function
+**
+**
+**=========================================================*/
+
+#define UNICODE
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[]) {
+
+ WCHAR FirstString[5] = {'T','E','S','T','\0'};
+ WCHAR CorrectBuffer[3] = {'T','E','\0'};
+ WCHAR ResultBuffer[5];
+ WCHAR* ResultPointer = NULL;
+
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /* A straight copy, the values should be equal. */
+ ResultPointer = lstrcpyn(ResultBuffer,FirstString,3);
+
+ /* Make sure the returned pointer is to the result buffer */
+ if(ResultPointer != &ResultBuffer[0])
+ {
+ Fail("ERROR: The function didn't return a pointer which points to the "
+ "location of the buffer which was copied into.\n");
+ }
+
+ /* Check to see that values are equal */
+ if(memcmp(ResultBuffer,
+ CorrectBuffer,
+ wcslen(ResultBuffer)*sizeof(WCHAR)) != 0)
+ {
+ Fail("ERROR: '%s' was the result and it should have been '%s' when "
+ "this copy was performed.\n",
+ convertC(ResultBuffer),convertC(CorrectBuffer));
+ }
+
+ /* Null values should get Null results */
+ if(lstrcpyn(ResultBuffer,NULL,3) != NULL)
+ {
+ Fail("ERROR: When the second parameter was set to NULL, the return "
+ "value should have been NULL, but it was not.\n");
+ }
+
+ if(lstrcpyn(NULL,FirstString,3) != NULL)
+ {
+ Fail("ERROR: When the first parameter was set to NULL, the return "
+ "value should have been NULL, but it was not.\n");
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/lstrcpynW/test1/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/lstrcpynW/test1/testinfo.dat
new file mode 100644
index 0000000000..111a57928a
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/lstrcpynW/test1/testinfo.dat
@@ -0,0 +1,16 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = lstrcpynW
+Name = Positive test of lstrcpynW
+TYPE = DEFAULT
+EXE1 = test
+Description
+= Ensure that a copy of a string works, and that the return values
+= are correct for success and failure.
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/lstrlenA/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/lstrlenA/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/lstrlenA/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/miscellaneous/lstrlenA/test1/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/lstrlenA/test1/CMakeLists.txt
new file mode 100644
index 0000000000..807a5d83b9
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/lstrlenA/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.c
+)
+
+add_executable(paltest_lstrlena_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_lstrlena_test1 coreclrpal)
+
+target_link_libraries(paltest_lstrlena_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/lstrlenA/test1/test.c b/src/pal/tests/palsuite/miscellaneous/lstrlenA/test1/test.c
new file mode 100644
index 0000000000..13e935ba50
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/lstrlenA/test1/test.c
@@ -0,0 +1,49 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: test.c
+**
+** Purpose: Test for lstrlenA() function
+**
+**
+**=========================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[]) {
+
+ char * FirstString = "Pal Testing"; /* 11 characters */
+
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /* The string size should be 11 */
+ if(lstrlen(FirstString) != 11)
+ {
+ Fail("ERROR: The string size returned was %d but it should have "
+ "been 11 in this test.\n",lstrlen(FirstString));
+ }
+
+ /* A NULL pointer should return 0 length */
+ if(lstrlen(NULL) != 0)
+ {
+ Fail("ERROR: Checking the length of NULL pointer should return "
+ "a value of 0, but %d was returned.\n",lstrlen(NULL));
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/lstrlenA/test1/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/lstrlenA/test1/testinfo.dat
new file mode 100644
index 0000000000..2c8b795f64
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/lstrlenA/test1/testinfo.dat
@@ -0,0 +1,16 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = lstrlenA
+Name = Positive test of lstrlenA
+TYPE = DEFAULT
+EXE1 = test
+Description
+= Test a standard NULL terminated string and a NULL pointer
+= to ensure values are correct.
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/lstrlenW/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/lstrlenW/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/lstrlenW/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/miscellaneous/lstrlenW/test1/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/lstrlenW/test1/CMakeLists.txt
new file mode 100644
index 0000000000..fe6fc9691b
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/lstrlenW/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.c
+)
+
+add_executable(paltest_lstrlenw_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_lstrlenw_test1 coreclrpal)
+
+target_link_libraries(paltest_lstrlenw_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/lstrlenW/test1/test.c b/src/pal/tests/palsuite/miscellaneous/lstrlenW/test1/test.c
new file mode 100644
index 0000000000..49bc6d8f67
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/lstrlenW/test1/test.c
@@ -0,0 +1,51 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: test.c
+**
+** Purpose: Test for lstrlenW() function
+**
+**
+**=========================================================*/
+
+#define UNICODE
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[]) {
+
+ WCHAR FirstString[] = {'T','E','S','T','\0'}; /* 4 characters */
+
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /* The string size should be 4, as noted just above */
+ if(lstrlen(FirstString) != 4)
+ {
+ Fail("ERROR: The return value was %d when it should have shown the "
+ "size to be 4 characters.\n",lstrlen(FirstString));
+ }
+
+ /* A NULL pointer should return 0 length */
+ if(lstrlen(NULL) != 0)
+ {
+ Fail("ERROR: The return value was %d when it should have been 0, the "
+ "length of a NULL pointer.\n",lstrlen(NULL));
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/lstrlenW/test1/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/lstrlenW/test1/testinfo.dat
new file mode 100644
index 0000000000..4e9a4eb2b7
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/lstrlenW/test1/testinfo.dat
@@ -0,0 +1,16 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = lstrlenW
+Name = Positive test of lstrlenW
+TYPE = DEFAULT
+EXE1 = test
+Description
+= Test a standard NULL terminated string and
+= a NULL pointer to ensure values are correct.
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/queryperformancecounter/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/queryperformancecounter/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/queryperformancecounter/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/miscellaneous/queryperformancecounter/test1/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/queryperformancecounter/test1/CMakeLists.txt
new file mode 100644
index 0000000000..d76467aeab
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/queryperformancecounter/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_queryperformancecounter_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_queryperformancecounter_test1 coreclrpal)
+
+target_link_libraries(paltest_queryperformancecounter_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/queryperformancecounter/test1/test1.c b/src/pal/tests/palsuite/miscellaneous/queryperformancecounter/test1/test1.c
new file mode 100644
index 0000000000..55b173add7
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/queryperformancecounter/test1/test1.c
@@ -0,0 +1,107 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: test1.c
+**
+** Purpose: Test for QueryPerformanceCounter function
+**
+**
+**=========================================================*/
+
+/* Depends on: QueryPerformanceFrequency. */
+
+#include <palsuite.h>
+
+/* Milliseconds of error which are acceptable Function execution time, etc.
+ FreeBSD has a "standard" resolution of 50ms for waiting operations, so we
+ must take that into account as well */
+DWORD AcceptableTimeError = 15;
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ int i;
+ int NumIterations = 100;
+ DWORD AvgTimeDiff;
+ DWORD TimeDiff[100];
+ DWORD TotalTimeDiff = 0;
+ DWORD SleepInterval = 50;
+ LARGE_INTEGER StartTime;
+ LARGE_INTEGER EndTime;
+ LARGE_INTEGER Freq;
+
+ /* Initialize the PAL.
+ */
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /* Get the frequency of the High-Performance Counter,
+ * in order to convert counter time to milliseconds.
+ */
+ if (!QueryPerformanceFrequency(&Freq))
+ {
+ Fail("ERROR:%u:Unable to retrieve the frequency of the "
+ "high-resolution performance counter.\n",
+ GetLastError());
+ }
+
+ /* Perform this set of sleep timings a number of times.
+ */
+ for(i=0; i < NumIterations; i++)
+ {
+
+ /* Get the current counter value.
+ */
+ if (!QueryPerformanceCounter(&StartTime))
+ {
+ Fail("ERROR:%u:Unable to retrieve the current value of the "
+ "high-resolution performance counter.\n",
+ GetLastError());
+ }
+
+ /* Sleep a predetermined interval.
+ */
+ Sleep(SleepInterval);
+
+ /* Get the new current counter value.
+ */
+ if (!QueryPerformanceCounter(&EndTime))
+ {
+ Fail("ERROR:%u:Unable to retrieve the current value of the "
+ "high-resolution performance counter.\n",
+ GetLastError());
+ }
+
+ /* Determine elapsed time, in milliseconds. Compare the elapsed time
+ * with the sleep interval, and add to counter.
+ */
+ TimeDiff[i] = (DWORD)(((EndTime.QuadPart - StartTime.QuadPart)*1000)/
+ (Freq.QuadPart));
+ TotalTimeDiff += TimeDiff[i] - SleepInterval;
+
+ }
+
+ /* Verify that the average of the difference between the performance
+ * counter and the sleep interval is within our acceptable range.
+ */
+ AvgTimeDiff = TotalTimeDiff / NumIterations;
+ if (AvgTimeDiff > AcceptableTimeError)
+ {
+ Fail("ERROR: average diff %u acceptable %u.\n",
+ AvgTimeDiff,
+ AcceptableTimeError);
+ }
+
+ /* Terminate the PAL.
+ */
+ PAL_Terminate();
+ return PASS;
+}
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/queryperformancecounter/test1/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/queryperformancecounter/test1/testinfo.dat
new file mode 100644
index 0000000000..56f11fc91b
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/queryperformancecounter/test1/testinfo.dat
@@ -0,0 +1,11 @@
+Version = 1.0
+Section = Miscellaneous
+Function = QueryPerformanceCounter
+Name = Positive Test for QueryPerformanceCounter
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= This test will verify with QueryPerformanceCounter
+= and QueryPerformanceFrequency that an API call of Sleep
+= of 100 milliseconds takes 100 milliseconds, taking into
+= account the error tolerance.
diff --git a/src/pal/tests/palsuite/miscellaneous/queryperformancefrequency/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/queryperformancefrequency/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/queryperformancefrequency/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/miscellaneous/queryperformancefrequency/test1/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/queryperformancefrequency/test1/CMakeLists.txt
new file mode 100644
index 0000000000..352e51342d
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/queryperformancefrequency/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_queryperformancefrequency_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_queryperformancefrequency_test1 coreclrpal)
+
+target_link_libraries(paltest_queryperformancefrequency_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/queryperformancefrequency/test1/test1.c b/src/pal/tests/palsuite/miscellaneous/queryperformancefrequency/test1/test1.c
new file mode 100644
index 0000000000..de08063a74
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/queryperformancefrequency/test1/test1.c
@@ -0,0 +1,59 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: test1.c
+**
+** Purpose: Test for QueryPerformanceFrequency function
+**
+**
+**=========================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ LARGE_INTEGER Freq;
+
+ /* Initialize the PAL.
+ */
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /* Check the return value of the performance
+ * frequency, a value of zero indicates that
+ * either the call has failed or the
+ * high-resolution performance counter is not
+ * installed.
+ */
+ if (!QueryPerformanceFrequency(&Freq))
+ {
+
+ Fail("ERROR:%u:Unable to retrieve the frequency of the "
+ "high-resolution performance counter.\n",
+ GetLastError());
+ }
+
+
+ /* Check the return value the frequency the
+ * value should be non-zero.
+ */
+ if (Freq.QuadPart == 0)
+ {
+
+ Fail("ERROR: The frequency has been determined to be 0 "
+ "the frequency should be non-zero.\n");
+
+ }
+
+ /* Terminate the PAL.
+ */
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/miscellaneous/queryperformancefrequency/test1/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/queryperformancefrequency/test1/testinfo.dat
new file mode 100644
index 0000000000..ea561422c1
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/queryperformancefrequency/test1/testinfo.dat
@@ -0,0 +1,12 @@
+Version = 1.0
+Section = Miscellaneous
+Function = QueryPerformanceFrequency
+Name = Positive Test for QueryPerformanceFrequency
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= This test will verify that QueryPerformanceFrequency
+= returns a valid return value.
+= The value of the count is processor dependent. On
+= some processors, for example, the count might be the
+= cycle rate of the processor clock.
diff --git a/src/pal/tests/palsuite/miscellaneous/wsprintfA/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/wsprintfA/CMakeLists.txt
new file mode 100644
index 0000000000..f40d4151d6
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/wsprintfA/CMakeLists.txt
@@ -0,0 +1,13 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test11)
+add_subdirectory(test12)
+add_subdirectory(test13)
+add_subdirectory(test2)
+add_subdirectory(test3)
+add_subdirectory(test6)
+add_subdirectory(test7)
+add_subdirectory(test8)
+add_subdirectory(test9)
+
diff --git a/src/pal/tests/palsuite/miscellaneous/wsprintfA/test1/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/wsprintfA/test1/CMakeLists.txt
new file mode 100644
index 0000000000..ef589329f0
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/wsprintfA/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.c
+)
+
+add_executable(paltest_wsprintfa_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_wsprintfa_test1 coreclrpal)
+
+target_link_libraries(paltest_wsprintfa_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/wsprintfA/test1/test.c b/src/pal/tests/palsuite/miscellaneous/wsprintfA/test1/test.c
new file mode 100644
index 0000000000..722270965d
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/wsprintfA/test1/test.c
@@ -0,0 +1,58 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: test.c
+**
+** Purpose: Test for wsprintfA() function
+**
+**
+**=========================================================*/
+
+#include <palsuite.h>
+
+ char * ErrorMessage;
+ char buf[256];
+
+/* memcmp is used to verify the results, so this test is dependent on it. */
+/* ditto with strlen */
+
+int test1()
+{
+ char checkstr[] = "hello world";
+
+ wsprintf(buf, "hello world");
+
+ /* Error message */
+ ErrorMessage = "ERROR: (Test 1) Failed on 'hello world' test. The "
+ "correct string is 'hello world' and the result returned was ";
+
+ return (memcmp(checkstr, buf, strlen(checkstr)+1) != 0);
+}
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ if(test1())
+ {
+ Fail("%s '%s'\n",ErrorMessage,buf);
+ }
+
+ PAL_Terminate();
+ return PASS;
+
+}
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/wsprintfA/test1/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/wsprintfA/test1/testinfo.dat
new file mode 100644
index 0000000000..c06f4c01aa
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/wsprintfA/test1/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = wsprintfA
+Name = Positive test of wsprintfA
+TYPE = DEFAULT
+EXE1 = test
+Description
+= Test the very basic functionality of wsprintf.
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/wsprintfA/test11/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/wsprintfA/test11/CMakeLists.txt
new file mode 100644
index 0000000000..92c44b9341
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/wsprintfA/test11/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.c
+)
+
+add_executable(paltest_wsprintfa_test11
+ ${SOURCES}
+)
+
+add_dependencies(paltest_wsprintfa_test11 coreclrpal)
+
+target_link_libraries(paltest_wsprintfa_test11
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/wsprintfA/test11/test.c b/src/pal/tests/palsuite/miscellaneous/wsprintfA/test11/test.c
new file mode 100644
index 0000000000..b43299a045
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/wsprintfA/test11/test.c
@@ -0,0 +1,128 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: test.c
+**
+** Purpose: Test for wsprintfA() function
+**
+**
+**=========================================================*/
+
+#include <palsuite.h>
+
+/* memcmp is used to verify the results, so this test is dependent on it. */
+/* ditto with strlen */
+
+char * ErrorMessage;
+char buf[256];
+
+BOOL test1()
+{
+ int pos = 42;
+
+
+ /* Test 1 */
+ wsprintf(buf, "foo %u", pos);
+ if (memcmp(buf, "foo 42", strlen(buf) + 1) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 1) Failed. The correct string is "
+ "'foo 42' and the result returned was ";
+ return FAIL;
+ }
+
+ /* Test 2 */
+ wsprintf(buf, "foo %lu", 0xFFFF);
+ if (memcmp(buf, "foo 65535", strlen(buf) + 1) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 2) Failed. The correct string is "
+ "'foo 65535' and the result returned was ";
+ return FAIL;
+ }
+
+ /* Test 3 */
+ wsprintf(buf, "foo %hu", 0xFFFF);
+ if (memcmp(buf, "foo 65535", strlen(buf) + 1) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 3) Failed. The correct string is "
+ "'foo 65535' and the result returned was ";
+ return FAIL;
+ }
+
+ /* Test 4 */
+ wsprintf(buf, "foo %3u", pos);
+ if (memcmp(buf, "foo 42", strlen(buf) + 1) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 4) Failed. The correct string is "
+ "'foo 42' and the result returned was ";
+ return FAIL;
+ }
+
+ /* Test 5 */
+ wsprintf(buf, "foo %-3u", pos);
+ if (memcmp(buf, "foo 42 ", strlen(buf) + 1) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 5) Failed. The correct string is "
+ "'foo 42' and the result returned was ";
+ return FAIL;
+ }
+
+ /* Test 6 */
+ wsprintf(buf, "foo %.1u", pos);
+ if (memcmp(buf, "foo 42", strlen(buf) + 1) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 6) Failed. The correct string is "
+ "'foo 42' and the result returned was ";
+ return FAIL;
+ }
+
+ /* Test 7 */
+ wsprintf(buf, "foo %.3u", pos);
+ if (memcmp(buf, "foo 042", strlen(buf) + 1) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 7) Failed. The correct string is "
+ "'foo 042' and the result returned was ";
+ return FAIL;
+ }
+
+ /* Test 8 */
+ wsprintf(buf, "foo %03u", pos);
+ if (memcmp(buf, "foo 042", strlen(buf) + 1) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 8) Failed. The correct string is "
+ "'foo 042' and the result returned was ";
+ return FAIL;
+ }
+
+ /* Test 9 */
+ wsprintf(buf, "foo %#u", pos);
+ if (memcmp(buf, "foo 42", strlen(buf) + 1) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 9) Failed. The correct string is "
+ "'foo 42' and the result returned was ";
+ return FAIL;
+ }
+ return PASS;
+}
+
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ if(test1())
+ {
+ Fail("%s'%s'\n",ErrorMessage,buf);
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/wsprintfA/test11/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/wsprintfA/test11/testinfo.dat
new file mode 100644
index 0000000000..c5f1ec1975
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/wsprintfA/test11/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = wsprintfA
+Name = Positive test of wsprintfA
+TYPE = DEFAULT
+EXE1 = test
+Description
+= Test the %u formatter.
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/wsprintfA/test12/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/wsprintfA/test12/CMakeLists.txt
new file mode 100644
index 0000000000..e4013ad9e3
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/wsprintfA/test12/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.c
+)
+
+add_executable(paltest_wsprintfa_test12
+ ${SOURCES}
+)
+
+add_dependencies(paltest_wsprintfa_test12 coreclrpal)
+
+target_link_libraries(paltest_wsprintfa_test12
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/wsprintfA/test12/test.c b/src/pal/tests/palsuite/miscellaneous/wsprintfA/test12/test.c
new file mode 100644
index 0000000000..dcc61019d4
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/wsprintfA/test12/test.c
@@ -0,0 +1,119 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: test.c
+**
+** Purpose: Test for wsprintfA() function
+**
+**
+**=========================================================*/
+
+#include <palsuite.h>
+
+/* memcmp is used to verify the results, so this test is dependent on it. */
+/* ditto with strlen */
+
+char * ErrorMessage;
+char buf[256];
+
+BOOL test1()
+{
+ int pos = 0x1234ab;
+
+ /* Test 1 */
+ wsprintf(buf, "foo %x", pos);
+ if (memcmp(buf, "foo 1234ab", strlen(buf) + 1) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 1) Failed. The correct "
+ "string is 'foo 1234ab' and the result returned was ";
+ return FAIL;
+ }
+
+ /* Test 2 */
+ wsprintf(buf, "foo %lx", pos);
+ if (memcmp(buf, "foo 1234ab", strlen(buf) + 1) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 2) Failed. The correct "
+ "string is 'foo 1234ab' and the result returned was ";
+ return FAIL;
+ }
+
+
+ /* Test 3 */
+ wsprintf(buf, "foo %7x", pos);
+ if (memcmp(buf, "foo 1234ab", strlen(buf) + 1) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 3) Failed. The correct string is "
+ "'foo 1234ab' and the result returned was ";
+ return FAIL;
+ }
+
+ /* Test 4 */
+ wsprintf(buf, "foo %-7x", pos);
+ if (memcmp(buf, "foo 1234ab ", strlen(buf) + 1) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 4) Failed. The correct string is "
+ "'foo 1234ab' and the result returned was ";
+ return FAIL;
+ }
+
+ /* Test 5 */
+ wsprintf(buf, "foo %.1x", pos);
+ if (memcmp(buf, "foo 1234ab", strlen(buf) + 1) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 5) Failed. The correct string is "
+ "'foo 1234ab' and the result returned was ";
+ return FAIL;
+ }
+
+ /* Test 6 */
+ wsprintf(buf, "foo %.7x", pos);
+ if (memcmp(buf, "foo 01234ab", strlen(buf) + 1) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 6) Failed. The correct string is "
+ "'foo 01234ab' and the result returned was ";
+ return FAIL;
+ }
+
+ /* Test 7 */
+ wsprintf(buf, "foo %07x", pos);
+ if (memcmp(buf, "foo 01234ab", strlen(buf) + 1) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 7) Failed. The correct string is "
+ "'foo 01234ab' and the result returned was ";
+ return FAIL;
+ }
+
+ /* Test 8 */
+ wsprintf(buf, "foo %#x", pos);
+ if (memcmp(buf, "foo 0x1234ab", strlen(buf) + 1) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 8) Failed. The correct string is "
+ "'foo 0x1234ab' and the result returned was ";
+ return FAIL;
+ }
+
+ return PASS;
+}
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ if(test1())
+ {
+ Fail("%s '%s'\n",ErrorMessage,buf);
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/wsprintfA/test12/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/wsprintfA/test12/testinfo.dat
new file mode 100644
index 0000000000..71c8386f27
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/wsprintfA/test12/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = wsprintfA
+Name = Positive test of wsprintfA
+TYPE = DEFAULT
+EXE1 = test
+Description
+= Test the %x formatter.
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/wsprintfA/test13/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/wsprintfA/test13/CMakeLists.txt
new file mode 100644
index 0000000000..423b05d8d9
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/wsprintfA/test13/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.c
+)
+
+add_executable(paltest_wsprintfa_test13
+ ${SOURCES}
+)
+
+add_dependencies(paltest_wsprintfa_test13 coreclrpal)
+
+target_link_libraries(paltest_wsprintfa_test13
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/wsprintfA/test13/test.c b/src/pal/tests/palsuite/miscellaneous/wsprintfA/test13/test.c
new file mode 100644
index 0000000000..e1f7d80a0f
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/wsprintfA/test13/test.c
@@ -0,0 +1,120 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: test.c
+**
+** Purpose: Test for wsprintfA() function
+**
+**
+**=========================================================*/
+
+#include <palsuite.h>
+
+/* memcmp is used to verify the results, so this test is dependent on it. */
+/* ditto with strlen */
+
+char * ErrorMessage;
+char buf[256];
+
+BOOL test1()
+{
+ int pos = 0x1234ab;
+
+ /* Test 1 */
+ wsprintf(buf, "foo %X", pos);
+ if (memcmp(buf, "foo 1234AB", strlen(buf) + 1) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 1) Failed. The correct string is "
+ " 'foo 1234AB' and the result returned was ";
+ return FAIL;
+ }
+
+ /* Test 2 */
+ wsprintf(buf, "foo %lX", pos);
+ if (memcmp(buf, "foo 1234AB", strlen(buf) + 1) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 2) Failed. The correct string is "
+ "'foo 1234AB' and the result returned was ";
+ return FAIL;
+ }
+
+
+ /* Test 3 */
+ wsprintf(buf, "foo %7X", pos);
+ if (memcmp(buf, "foo 1234AB", strlen(buf) + 1) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 3) Failed. The correct string is "
+ "'foo 1234AB' and the result returned was ";
+ return FAIL;
+ }
+
+ /* Test 4 */
+ wsprintf(buf, "foo %-7X", pos);
+ if (memcmp(buf, "foo 1234AB ", strlen(buf) + 1) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 4) Failed. The correct string is "
+ "'foo 1234AB' and the result returned was ";
+ return FAIL;
+ }
+
+ /* Test 5 */
+ wsprintf(buf, "foo %.1X", pos);
+ if (memcmp(buf, "foo 1234AB", strlen(buf) + 1) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 5) Failed. The correct string is "
+ "'foo 1234AB' and the result returned was ";
+ return FAIL;
+ }
+
+ /* Test 6 */
+ wsprintf(buf, "foo %.7X", pos);
+ if (memcmp(buf, "foo 01234AB", strlen(buf) + 1) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 6) Failed. The correct string is "
+ "'foo 01234AB' and the result returned was ";
+ return FAIL;
+ }
+
+ /* Test 7 */
+ wsprintf(buf, "foo %07X", pos);
+ if (memcmp(buf, "foo 01234AB", strlen(buf) + 1) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 7) Failed. The correct string is "
+ "'foo 01234AB' and the result returned was ";
+ return FAIL;
+ }
+
+ /* Test 8 */
+ wsprintf(buf, "foo %#X", pos);
+ if (memcmp(buf, "foo 0X1234AB", strlen(buf) + 1) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 8) Failed. The correct string is "
+ "'foo 0X1234AB' and the result returned was ";
+ return FAIL;
+ }
+
+ return PASS;
+}
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ if(test1())
+ {
+ Fail("%s '%s'\n",ErrorMessage,buf);
+ }
+
+ PAL_Terminate();
+ return PASS;
+
+}
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/wsprintfA/test13/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/wsprintfA/test13/testinfo.dat
new file mode 100644
index 0000000000..0e0d1b4633
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/wsprintfA/test13/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = wsprintfA
+Name = Positive test of wsprintfA
+TYPE = DEFAULT
+EXE1 = test
+Description
+= Test the %X formatter.
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/wsprintfA/test2/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/wsprintfA/test2/CMakeLists.txt
new file mode 100644
index 0000000000..546a1daa38
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/wsprintfA/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.c
+)
+
+add_executable(paltest_wsprintfa_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_wsprintfa_test2 coreclrpal)
+
+target_link_libraries(paltest_wsprintfa_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/wsprintfA/test2/test.c b/src/pal/tests/palsuite/miscellaneous/wsprintfA/test2/test.c
new file mode 100644
index 0000000000..b879e54043
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/wsprintfA/test2/test.c
@@ -0,0 +1,123 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: test.c
+**
+** Purpose: Test for wsprintfA() function
+**
+**
+**=========================================================*/
+
+#include <palsuite.h>
+
+/* memcmp is used to verify the results, so this test is dependent on it. */
+/* ditto with strlen */
+
+char * ErrorMessage;
+char * BadResult;
+char buf[256];
+
+BOOL test1()
+{
+
+
+ /* Test 1 */
+ wsprintf(buf, "foo %s", "bar");
+ if (memcmp(buf, "foo bar", strlen(buf) + 1) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 1) Failed. The correct string is "
+ "'foo bar' and the result returned was ";
+ BadResult = buf;
+ return FAIL;
+ }
+
+ /* Test 2 */
+ wsprintf(buf, "foo %hs", "bar");
+ if (memcmp(buf, "foo bar", strlen(buf) + 1) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 2) Failed. The correct string is "
+ "'foo bar' and the result returned was ";
+ BadResult = buf;
+ return FAIL;
+ }
+
+
+ /* Test 3 */
+ wsprintf(buf, "foo %5s", "bar");
+ if (memcmp(buf, "foo bar", strlen(buf) + 1) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 3) Failed. The correct string is "
+ "'foo bar' and the result returned was ";
+ BadResult = buf;
+ return FAIL;
+ }
+
+ /* Test 4 */
+ wsprintf(buf, "foo %.2s", "bar");
+ if (memcmp(buf, "foo ba", strlen(buf) + 1) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 4) Failed. The correct string is "
+ "'foo ba' and the result returned was ";
+ BadResult = buf;
+ return FAIL;
+ }
+
+ /* Test 5 */
+ wsprintf(buf, "foo %5.2s", "bar");
+ if (memcmp(buf, "foo ba", strlen(buf) + 1) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 5) Failed. The correct string is "
+ "'foo ba' and the result returned was ";
+ BadResult = buf;
+ return FAIL;
+ }
+
+ /* Test 6 */
+ wsprintf(buf, "foo %-5s", "bar");
+ if (memcmp(buf, "foo bar ", strlen(buf) + 1) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 6) Failed. The correct string is "
+ "'foo bar' and the result returned was ";
+ BadResult = buf;
+ return FAIL;
+ }
+
+ /* Test 7 */
+ wsprintf(buf, "foo %05s", "bar");
+ if (memcmp(buf, "foo 00bar", strlen(buf) + 1) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 7) Failed. The correct string is "
+ "'foo 00bar' and the result returned was ";
+ BadResult = buf;
+ return FAIL;
+ }
+ return PASS;
+}
+
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ if(test1())
+ {
+ Fail("%s '%s'\n",ErrorMessage,BadResult);
+ }
+
+ PAL_Terminate();
+ return PASS;
+
+}
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/wsprintfA/test2/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/wsprintfA/test2/testinfo.dat
new file mode 100644
index 0000000000..32e51df28b
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/wsprintfA/test2/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = wsprintfA
+Name = Positive test of wsprintfA
+TYPE = DEFAULT
+EXE1 = test
+Description
+= Test the %s and %ls formatters with various flags.
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/wsprintfA/test3/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/wsprintfA/test3/CMakeLists.txt
new file mode 100644
index 0000000000..8043ccd60b
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/wsprintfA/test3/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.c
+)
+
+add_executable(paltest_wsprintfa_test3
+ ${SOURCES}
+)
+
+add_dependencies(paltest_wsprintfa_test3 coreclrpal)
+
+target_link_libraries(paltest_wsprintfa_test3
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/wsprintfA/test3/test.c b/src/pal/tests/palsuite/miscellaneous/wsprintfA/test3/test.c
new file mode 100644
index 0000000000..bb598d9d63
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/wsprintfA/test3/test.c
@@ -0,0 +1,121 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: test.c
+**
+** Purpose: Test for wsprintfA() function
+**
+**
+**=========================================================*/
+
+#include <palsuite.h>
+
+/* memcmp is used to verify the results, so this test is dependent on it. */
+/* ditto with strlen */
+
+char * ErrorMessage;
+char buf[256];
+
+BOOL test1()
+{
+
+ /* Test 1 */
+ wsprintf(buf, "foo %S", convert("bar"));
+ if (memcmp(buf, "foo bar", strlen(buf) + 1) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 1) Failed. The correct string is "
+ "'foo bar' and the result returned was ";
+ return FAIL;
+ }
+
+ /* Test 2 */
+ wsprintf(buf, "foo %hS", "bar");
+ if (memcmp(buf, "foo bar", strlen(buf) + 1) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 2) Failed. The correct string is "
+ "'foo bar' and the result returned was ";
+ return FAIL;
+ }
+
+ /* Test 3 */
+ wsprintf(buf, "foo %lS", convert("bar"));
+ if (memcmp(buf, "foo bar", strlen(buf) + 1) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 3) Failed. The correct string is '"
+ "foo bar' and the result returned was ";
+ return FAIL;
+ }
+
+
+ /* Test 4 */
+ wsprintf(buf, "foo %5S", convert("bar"));
+ if (memcmp(buf, "foo bar", strlen(buf) + 1) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 4) Failed. The correct string is "
+ "'foo bar' and the result returned was ";
+ return FAIL;
+ }
+
+ /* Test 5 */
+ wsprintf(buf, "foo %.2S", convert("bar"));
+ if (memcmp(buf, "foo ba", strlen(buf) + 1) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 5) Failed. The correct string is "
+ "'foo ba' and the result returned was ";
+ return FAIL;
+ }
+
+ /* Test 6 */
+ wsprintf(buf, "foo %5.2S", convert("bar"));
+ if (memcmp(buf, "foo ba", strlen(buf) + 1) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 6) Failed. The correct string is "
+ "'foo ba' and the result returned was ";
+ return FAIL;
+ }
+
+ /* Test 7 */
+ wsprintf(buf, "foo %-5S", convert("bar"));
+ if (memcmp(buf, "foo bar ", strlen(buf) + 1) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 7) Failed. The correct string is "
+ "'foo bar ' and the result returned was ";
+ return FAIL;
+ }
+
+ /* Test 8 */
+ wsprintf(buf, "foo %05S", convert("bar"));
+ if (memcmp(buf, "foo 00bar", strlen(buf) + 1) != 0) {
+ ErrorMessage = "ERROR: (Test 8) Failed. The correct string is "
+ "'foo 00bar' and the result returned was ";
+ return FAIL;
+ }
+ return PASS;
+}
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ if(test1()) {
+ Fail("%s '%s'\n",ErrorMessage,buf);
+
+ }
+
+ PAL_Terminate();
+ return PASS;
+
+}
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/wsprintfA/test3/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/wsprintfA/test3/testinfo.dat
new file mode 100644
index 0000000000..0660aa17a3
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/wsprintfA/test3/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = wsprintfA
+Name = Positive test of wsprintfA
+TYPE = DEFAULT
+EXE1 = test
+Description
+= Test the %S and wide characters in general.
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/wsprintfA/test6/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/wsprintfA/test6/CMakeLists.txt
new file mode 100644
index 0000000000..6a5caf95c2
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/wsprintfA/test6/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.c
+)
+
+add_executable(paltest_wsprintfa_test6
+ ${SOURCES}
+)
+
+add_dependencies(paltest_wsprintfa_test6 coreclrpal)
+
+target_link_libraries(paltest_wsprintfa_test6
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/wsprintfA/test6/test.c b/src/pal/tests/palsuite/miscellaneous/wsprintfA/test6/test.c
new file mode 100644
index 0000000000..08d97f467a
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/wsprintfA/test6/test.c
@@ -0,0 +1,114 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: test.c
+**
+** Purpose: Test for wsprintfA() function
+**
+**
+**=========================================================*/
+
+#include <palsuite.h>
+
+/* memcmp is used to verify the results, so this test is dependent on it. */
+/* ditto with strlen */
+
+char * ErrorMessage;
+char buf[256];
+
+BOOL test1()
+{
+ WCHAR wc = 'c';
+
+ /* Test 1 */
+ wsprintf(buf, "foo %c", 'b');
+ if (memcmp(buf, "foo b", strlen(buf) + 1) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 1) Failed. The correct string is "
+ "'foo b' and the result returned was ";
+ return FAIL;
+ }
+
+ /* Test 2 */
+ wsprintf(buf, "foo %hc", 'b');
+ if (memcmp(buf, "foo b", strlen(buf) + 1) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 2) Failed. The correct string is "
+ "'foo b' and the result returned was ";
+ return FAIL;
+ }
+
+ /* Test 3 */
+ wsprintf(buf, "foo %lc", wc);
+ if (memcmp(buf, "foo c", strlen(buf) + 1) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 3) Failed. The correct string is "
+ "'foo c' and the result returned was ";
+ return FAIL;
+ }
+
+
+ /* Test 4 */
+ wsprintf(buf, "foo %5c", 'b');
+ if (memcmp(buf, "foo b", strlen(buf) + 1) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 4) Failed. The correct string is "
+ "'foo bar' and the result returned was ";
+ return FAIL;
+ }
+
+ /* Test 5 */
+ wsprintf(buf, "foo %-5c", 'b');
+ if (memcmp(buf, "foo b ", strlen(buf) + 1) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 5) Failed. The correct string is "
+ "'foo b ' and the result returned was ";
+ return FAIL;
+ }
+
+ /* Test 6 */
+ wsprintf(buf, "foo %05c", 'b');
+ if (memcmp(buf, "foo 0000b", strlen(buf) + 1) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 6) Failed. The correct string is "
+ "'foo 0000b' and the result returned was ";
+ return FAIL;
+ }
+
+ /* Test 7 */
+ wsprintf(buf, "foo %#c", 'b');
+ if (memcmp(buf, "foo b", strlen(buf) + 1) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 7) Failed. The correct string is "
+ "'foo b' and the result returned was ";
+ return FAIL;
+ }
+ return PASS;
+}
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ if(test1())
+ {
+ Fail("%s '%s'\n",ErrorMessage,buf);
+ }
+
+ PAL_Terminate();
+ return PASS;
+
+}
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/wsprintfA/test6/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/wsprintfA/test6/testinfo.dat
new file mode 100644
index 0000000000..31b0f667b6
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/wsprintfA/test6/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = wsprintfA
+Name = Positive test of wsprintfA
+TYPE = DEFAULT
+EXE1 = test
+Description
+= Test the %c formatter.
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/wsprintfA/test7/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/wsprintfA/test7/CMakeLists.txt
new file mode 100644
index 0000000000..0885f0f21e
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/wsprintfA/test7/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.c
+)
+
+add_executable(paltest_wsprintfa_test7
+ ${SOURCES}
+)
+
+add_dependencies(paltest_wsprintfa_test7 coreclrpal)
+
+target_link_libraries(paltest_wsprintfa_test7
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/wsprintfA/test7/test.c b/src/pal/tests/palsuite/miscellaneous/wsprintfA/test7/test.c
new file mode 100644
index 0000000000..6d380efaa9
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/wsprintfA/test7/test.c
@@ -0,0 +1,112 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: test.c
+**
+** Purpose: Test for wsprintfA() function
+**
+**
+**=========================================================*/
+
+#include <palsuite.h>
+
+/* memcmp is used to verify the results, so this test is dependent on it. */
+/* ditto with strlen */
+
+char * ErrorMessage;
+char buf[256];
+
+BOOL test1()
+{
+ WCHAR wb = 'b';
+
+ /* Test 1 */
+ wsprintf(buf, "foo %C", wb);
+ if (memcmp(buf, "foo b", strlen(buf) + 1) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 1) Failed. The correct string is "
+ "'foo b' and the result returned was ";
+ return FAIL;
+ }
+
+ /* Test 2 */
+ wsprintf(buf, "foo %hC", wb);
+ if (memcmp(buf, "foo b", strlen(buf) + 1) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 2) Failed. The correct string is "
+ "'foo b' and the result returned was ";
+ return FAIL;
+ }
+
+ /* Test 3 */
+ wsprintf(buf, "foo %lC", 'c');
+ if (memcmp(buf, "foo c", strlen(buf) + 1) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 3) Failed. The correct string is "
+ "'foo c' and the result returned was ";
+ return FAIL;
+ }
+
+
+ /* Test 4 */
+ wsprintf(buf, "foo %5C", wb);
+ if (memcmp(buf, "foo b", strlen(buf) + 1) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 4) Failed. The correct string is "
+ "'foo b' and the result returned was ";
+ return FAIL;
+ }
+
+ /* Test 5 */
+ wsprintf(buf, "foo %-5C", wb);
+ if (memcmp(buf, "foo b ", strlen(buf) + 1) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 5) Failed. The correct string is "
+ "'foo b ' and the result returned was ";
+ return FAIL;
+ }
+
+ /* Test 6 */
+ wsprintf(buf, "foo %05C", wb);
+ if (memcmp(buf, "foo 0000b", strlen(buf) + 1) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 6) Failed. The correct string is "
+ "'foo 0000b' and the result returned was ";
+ return FAIL;
+ }
+
+ /* Test 7 */
+ wsprintf(buf, "foo %#C", wb);
+ if (memcmp(buf, "foo b", strlen(buf) + 1) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 7) Failed. The correct string is "
+ "'foo b' and the result returned was ";
+ return FAIL;
+ }
+ return PASS;
+}
+
+int __cdecl main(int argc, char *argv[])
+{
+
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ if(test1())
+ {
+ Fail("%s '%s'\n",ErrorMessage,buf);
+
+ }
+
+ PAL_Terminate();
+ return PASS;
+
+}
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/wsprintfA/test7/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/wsprintfA/test7/testinfo.dat
new file mode 100644
index 0000000000..31b0f667b6
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/wsprintfA/test7/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = wsprintfA
+Name = Positive test of wsprintfA
+TYPE = DEFAULT
+EXE1 = test
+Description
+= Test the %c formatter.
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/wsprintfA/test8/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/wsprintfA/test8/CMakeLists.txt
new file mode 100644
index 0000000000..3c4b5ed36e
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/wsprintfA/test8/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.c
+)
+
+add_executable(paltest_wsprintfa_test8
+ ${SOURCES}
+)
+
+add_dependencies(paltest_wsprintfa_test8 coreclrpal)
+
+target_link_libraries(paltest_wsprintfa_test8
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/wsprintfA/test8/test.c b/src/pal/tests/palsuite/miscellaneous/wsprintfA/test8/test.c
new file mode 100644
index 0000000000..7367461544
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/wsprintfA/test8/test.c
@@ -0,0 +1,120 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: test.c
+**
+** Purpose: Test for wsprintfA() function
+**
+**
+**=========================================================*/
+
+#include <palsuite.h>
+
+/* memcmp is used to verify the results, so this test is dependent on it. */
+/* ditto with strlen */
+
+char * ErrorMessage;
+char buf[256];
+
+BOOL test1()
+{
+ int pos = 42;
+
+ /* Test 1 */
+ wsprintf(buf, "foo %d", pos);
+ if (memcmp(buf, "foo 42", strlen(buf) + 1) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 1) Failed. The correct string is "
+ "'foo 42' and the result returned was ";
+ return FAIL;
+ }
+
+ /* Test 2 */
+ wsprintf(buf, "foo %ld", 0xFFFF);
+ if (memcmp(buf, "foo 65535", strlen(buf) + 1) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 2) Failed. The correct string is "
+ "'foo 65535' and the result returned was ";
+ return FAIL;
+ }
+
+ /* Test 3 */
+ wsprintf(buf, "foo %3d", pos);
+ if (memcmp(buf, "foo 42", strlen(buf) + 1) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 3) Failed. The correct string is "
+ "'foo 42' and the result returned was ";
+ return FAIL;
+ }
+
+ /* Test 4 */
+ wsprintf(buf, "foo %-3d", pos);
+ if (memcmp(buf, "foo 42 ", strlen(buf) + 1) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 4) Failed. The correct string is "
+ "'foo 42 ' and the result returned was ";
+ return FAIL;
+ }
+
+ /* Test 5 */
+ wsprintf(buf, "foo %.1d", pos);
+ if (memcmp(buf, "foo 42", strlen(buf) + 1) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 5) Failed. The correct string is "
+ "'foo 42' and the result returned was ";
+ return FAIL;
+ }
+
+ /* Test 6 */
+ wsprintf(buf, "foo %.3d", pos);
+ if (memcmp(buf, "foo 042", strlen(buf) + 1) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 6) Failed. The correct string is "
+ "'foo 042' and the result returned was ";
+ return FAIL;
+ }
+
+ /* Test 7 */
+ wsprintf(buf, "foo %03d", pos);
+ if (memcmp(buf, "foo 042", strlen(buf) + 1) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 7) Failed. The correct string is "
+ "'foo 042' and the result returned was ";
+ return FAIL;
+ }
+
+ /* Test 8 */
+ wsprintf(buf, "foo %#d", pos);
+ if (memcmp(buf, "foo 42", strlen(buf) + 1) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 8) Failed. The correct string is "
+ "'foo 42' and the result returned was ";
+ return FAIL;
+ }
+ return PASS;
+}
+
+int __cdecl main(int argc, char *argv[])
+{
+
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ if(test1())
+ {
+ Fail("%s '%s'\n",ErrorMessage,buf);
+ }
+
+ PAL_Terminate();
+ return PASS;
+
+}
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/wsprintfA/test8/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/wsprintfA/test8/testinfo.dat
new file mode 100644
index 0000000000..75f4fbf121
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/wsprintfA/test8/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = wsprintfA
+Name = Positive test of wsprintfA
+TYPE = DEFAULT
+EXE1 = test
+Description
+= Test the %d formatter.
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/wsprintfA/test9/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/wsprintfA/test9/CMakeLists.txt
new file mode 100644
index 0000000000..dcbb22ebb5
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/wsprintfA/test9/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.c
+)
+
+add_executable(paltest_wsprintfa_test9
+ ${SOURCES}
+)
+
+add_dependencies(paltest_wsprintfa_test9 coreclrpal)
+
+target_link_libraries(paltest_wsprintfa_test9
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/wsprintfA/test9/test.c b/src/pal/tests/palsuite/miscellaneous/wsprintfA/test9/test.c
new file mode 100644
index 0000000000..9f123bcc6d
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/wsprintfA/test9/test.c
@@ -0,0 +1,122 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: test.c
+**
+** Purpose: Test for wsprintfA() function
+**
+**
+**=========================================================*/
+
+#include <palsuite.h>
+
+/* memcmp is used to verify the results, so this test is dependent on it. */
+/* ditto with strlen */
+
+char * ErrorMessage;
+char buf[256];
+
+BOOL test1()
+{
+
+ int pos = 42;
+
+
+ /* Test 1 */
+ wsprintf(buf, "foo %i", pos);
+ if (memcmp(buf, "foo 42", strlen(buf) + 1) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 1) Failed. The correct string is "
+ "'foo 42' and the result returned was ";
+ return FAIL;
+ }
+
+ /* Test 2 */
+ wsprintf(buf, "foo %li", 0xFFFF);
+ if (memcmp(buf, "foo 65535", strlen(buf) + 1) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 2) Failed. The correct string is "
+ "'foo 65535' and the result returned was ";
+ return FAIL;
+ }
+
+
+ /* Test 3 */
+ wsprintf(buf, "foo %3i", pos);
+ if (memcmp(buf, "foo 42", strlen(buf) + 1) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 3) Failed. The correct string is "
+ "'foo 42' and the result returned was ";
+ return FAIL;
+ }
+
+ /* Test 4 */
+ wsprintf(buf, "foo %-3i", pos);
+ if (memcmp(buf, "foo 42 ", strlen(buf) + 1) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 4) Failed. The correct string is "
+ "'foo 42 ' and the result returned was ";
+ return FAIL;
+ }
+
+ /* Test 5 */
+ wsprintf(buf, "foo %.1i", pos);
+ if (memcmp(buf, "foo 42", strlen(buf) + 1) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 5) Failed. The correct string is "
+ "'foo 42' and the result returned was ";
+ return FAIL;
+ }
+
+ /* Test 6 */
+ wsprintf(buf, "foo %.3i", pos);
+ if (memcmp(buf, "foo 042", strlen(buf) + 1) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 6) Failed. The correct string is "
+ "'foo 042' and the result returned was ";
+ return FAIL;
+ }
+
+ /* Test 7 */
+ wsprintf(buf, "foo %03i", pos);
+ if (memcmp(buf, "foo 042", strlen(buf) + 1) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 7) Failed. The correct string is "
+ "'foo 042' and the result returned was ";
+ return FAIL;
+ }
+
+ /* Test 8 */
+ wsprintf(buf, "foo %#i", pos);
+ if (memcmp(buf, "foo 42", strlen(buf) + 1) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 8) Failed. The correct string is "
+ "'foo 42' and the result returned was ";
+ return FAIL;
+ }
+
+ return PASS;
+}
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ if(test1())
+ {
+ Fail("%s '%s'\n",ErrorMessage,buf);
+ }
+
+ PAL_Terminate();
+ return PASS;
+
+}
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/wsprintfA/test9/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/wsprintfA/test9/testinfo.dat
new file mode 100644
index 0000000000..2a3689e4dd
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/wsprintfA/test9/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = wsprintfA
+Name = Positive test of wsprintfA
+TYPE = DEFAULT
+EXE1 = test
+Description
+= Test the %i formatter.
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/wsprintfW/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/wsprintfW/CMakeLists.txt
new file mode 100644
index 0000000000..f40d4151d6
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/wsprintfW/CMakeLists.txt
@@ -0,0 +1,13 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test11)
+add_subdirectory(test12)
+add_subdirectory(test13)
+add_subdirectory(test2)
+add_subdirectory(test3)
+add_subdirectory(test6)
+add_subdirectory(test7)
+add_subdirectory(test8)
+add_subdirectory(test9)
+
diff --git a/src/pal/tests/palsuite/miscellaneous/wsprintfW/test1/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/wsprintfW/test1/CMakeLists.txt
new file mode 100644
index 0000000000..b1c0fb3d0b
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/wsprintfW/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.c
+)
+
+add_executable(paltest_wsprintfw_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_wsprintfw_test1 coreclrpal)
+
+target_link_libraries(paltest_wsprintfw_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/wsprintfW/test1/test.c b/src/pal/tests/palsuite/miscellaneous/wsprintfW/test1/test.c
new file mode 100644
index 0000000000..700cb134bd
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/wsprintfW/test1/test.c
@@ -0,0 +1,64 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: test.c
+**
+** Purpose: Test for wsprintfW() function
+**
+**
+**=========================================================*/
+
+#define UNICODE
+#include <palsuite.h>
+
+
+char * ErrorMessage = NULL;
+WCHAR * BadResult = NULL;
+
+/* memcmp is used to verify the results, so this test is dependent on it. */
+/* ditto with strlen */
+
+
+BOOL test1()
+{
+ char checkstr[] = "hello world";
+
+ WCHAR buf[256];
+
+ /* Test a simple string */
+ wsprintf(buf, convert("hello world"));
+
+ /* Error message */
+ ErrorMessage = "ERROR: (Test 1) Failed on 'hello world' test. "
+ "The correct string is 'hello world' and the result returned was ";
+ BadResult = buf;
+
+ return (memcmp(convert(checkstr), buf, wcslen(buf)*2+2) != 0);
+}
+
+int __cdecl main(int argc, char *argv[]) {
+
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ if(test1()) {
+ Fail("%s '%s'\n",ErrorMessage,convertC(BadResult));
+
+ }
+
+ PAL_Terminate();
+ return PASS;
+
+}
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/wsprintfW/test1/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/wsprintfW/test1/testinfo.dat
new file mode 100644
index 0000000000..f36aced027
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/wsprintfW/test1/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = wsprintfW
+Name = Positive test of wsprintfW
+TYPE = DEFAULT
+EXE1 = test
+Description
+= Test the very basic functionality of wsprintfW.
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/wsprintfW/test11/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/wsprintfW/test11/CMakeLists.txt
new file mode 100644
index 0000000000..a5d73ed413
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/wsprintfW/test11/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.c
+)
+
+add_executable(paltest_wsprintfw_test11
+ ${SOURCES}
+)
+
+add_dependencies(paltest_wsprintfw_test11 coreclrpal)
+
+target_link_libraries(paltest_wsprintfw_test11
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/wsprintfW/test11/test.c b/src/pal/tests/palsuite/miscellaneous/wsprintfW/test11/test.c
new file mode 100644
index 0000000000..dc1e7a7758
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/wsprintfW/test11/test.c
@@ -0,0 +1,139 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: test.c
+**
+** Purpose: Test for wsprintfW() function
+**
+**
+**=========================================================*/
+
+#define UNICODE
+#include <palsuite.h>
+
+
+
+char * ErrorMessage = NULL;
+WCHAR * BadResult = NULL;
+WCHAR buf[256];
+
+/* memcmp is used to verify the results, so this test is dependent on it. */
+/* ditto with strlen */
+
+
+BOOL test1()
+{
+
+ int pos = 42;
+
+ wsprintf(buf, convert("foo %u"), pos);
+ if (memcmp(buf, convert("foo 42"), wcslen(buf)*2 + 2) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 1) Failed. The correct string is"
+ " 'foo 42' and the result returned was ";
+ BadResult = buf;
+ return FAIL;
+ }
+
+ wsprintf(buf, convert("foo %lu"), 0xFFFF);
+ if (memcmp(buf, convert("foo 65535"), wcslen(buf)*2 + 2) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 2) Failed. The correct string is"
+ " 'foo 65535' and the result returned was ";
+ BadResult = buf;
+ return FAIL;
+ }
+
+ wsprintf(buf, convert("foo %hu"), 0xFFFF);
+ if (memcmp(buf, convert("foo 65535"), wcslen(buf)*2 + 2) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 3) Failed. The correct string is"
+ " 'foo 65535' and the result returned was ";
+ BadResult = buf;
+ return FAIL;
+ }
+
+ wsprintf(buf, convert("foo %3u"), pos);
+ if (memcmp(buf, convert("foo 42"), wcslen(buf)*2 + 2) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 4) Failed. The correct string is"
+ " 'foo 42' and the result returned was ";
+ BadResult = buf;
+ return FAIL;
+ }
+
+ wsprintf(buf, convert("foo %-3u"), pos);
+ if (memcmp(buf, convert("foo 42 "), wcslen(buf)*2 + 2) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 5) Failed. The correct string is"
+ " 'foo 42 ' and the result returned was ";
+ BadResult = buf;
+ return FAIL;
+ }
+
+ wsprintf(buf, convert("foo %.1u"), pos);
+ if (memcmp(buf, convert("foo 42"), wcslen(buf)*2 + 2) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 6) Failed. The correct string is"
+ " 'foo 42' and the result returned was ";
+ BadResult = buf;
+ return FAIL;
+ }
+
+ wsprintf(buf, convert("foo %.3u"), pos);
+ if (memcmp(buf, convert("foo 042"), wcslen(buf)*2 + 2) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 7) Failed. The correct string is"
+ " 'foo 042' and the result returned was ";
+ BadResult = buf;
+ return FAIL;
+ }
+
+ wsprintf(buf, convert("foo %03u"), pos);
+ if (memcmp(buf, convert("foo 042"), wcslen(buf)*2 + 2) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 8) Failed. The correct string is"
+ " 'foo 042' and the result returned was ";
+ BadResult = buf;
+ return FAIL;
+ }
+
+ wsprintf(buf, convert("foo %#u"), pos);
+ if (memcmp(buf, convert("foo 42"), wcslen(buf)*2 + 2) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 9) Failed. The correct string is"
+ " 'foo 42' and the result returned was ";
+ BadResult = buf;
+ return FAIL;
+ }
+
+ return PASS;
+}
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ if(test1())
+ {
+ Fail("%s '%s'\n",ErrorMessage,convertC(BadResult));
+
+ }
+
+ PAL_Terminate();
+ return PASS;
+
+}
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/wsprintfW/test11/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/wsprintfW/test11/testinfo.dat
new file mode 100644
index 0000000000..bb85d63f1b
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/wsprintfW/test11/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = wsprintfW
+Name = Positive test of wsprintfW
+TYPE = DEFAULT
+EXE1 = test
+Description
+= Test %u formatter with wsprintfW.
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/wsprintfW/test12/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/wsprintfW/test12/CMakeLists.txt
new file mode 100644
index 0000000000..3811fb07c9
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/wsprintfW/test12/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.c
+)
+
+add_executable(paltest_wsprintfw_test12
+ ${SOURCES}
+)
+
+add_dependencies(paltest_wsprintfw_test12 coreclrpal)
+
+target_link_libraries(paltest_wsprintfw_test12
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/wsprintfW/test12/test.c b/src/pal/tests/palsuite/miscellaneous/wsprintfW/test12/test.c
new file mode 100644
index 0000000000..6ba456b3bc
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/wsprintfW/test12/test.c
@@ -0,0 +1,128 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: test.c
+**
+** Purpose: Test for wsprintfW() function
+**
+**
+**=========================================================*/
+
+#define UNICODE
+#include <palsuite.h>
+
+
+char * ErrorMessage = NULL;
+WCHAR * BadResult = NULL;
+WCHAR buf[256];
+
+/* memcmp is used to verify the results, so this test is dependent on it. */
+/* ditto with strlen */
+
+BOOL test1()
+{
+ int pos = 0x1234ab;
+
+ wsprintf(buf, convert("foo %x"), pos);
+ if (memcmp(buf, convert("foo 1234ab"), wcslen(buf)*2 + 2) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 1) Failed. The correct string is"
+ " 'foo 1234ab' and the result returned was ";
+ BadResult = buf;
+ return FAIL;
+ }
+
+ wsprintf(buf, convert("foo %lx"), pos);
+ if (memcmp(buf, convert("foo 1234ab"), wcslen(buf)*2 + 2) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 2) Failed. The correct string is"
+ " 'foo 1234ab' and the result returned was ";
+ BadResult = buf;
+ return FAIL;
+ }
+
+ wsprintf(buf, convert("foo %7x"), pos);
+ if (memcmp(buf, convert("foo 1234ab"), wcslen(buf)*2 + 2) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 3) Failed. The correct string is"
+ " 'foo 1234ab' and the result returned was ";
+ BadResult = buf;
+ return FAIL;
+ }
+
+ wsprintf(buf, convert("foo %-7x"), pos);
+ if (memcmp(buf, convert("foo 1234ab "), wcslen(buf)*2 + 2) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 4) Failed. The correct string is"
+ " 'foo 1234ab ' and the result returned was ";
+ BadResult = buf;
+ return FAIL;
+ }
+
+ wsprintf(buf, convert("foo %.1x"), pos);
+ if (memcmp(buf, convert("foo 1234ab"), wcslen(buf)*2 + 2) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 5) Failed. The correct string is"
+ " 'foo 1234ab' and the result returned was ";
+ BadResult = buf;
+ return FAIL;
+ }
+
+ wsprintf(buf, convert("foo %.7x"), pos);
+ if (memcmp(buf, convert("foo 01234ab"), wcslen(buf)*2 + 2) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 6) Failed. The correct string is"
+ " 'foo 01234ab' and the result returned was ";
+ BadResult = buf;
+ return FAIL;
+ }
+
+ wsprintf(buf, convert("foo %07x"), pos);
+ if (memcmp(buf, convert("foo 01234ab"), wcslen(buf)*2 + 2) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 7) Failed. The correct string is"
+ " 'foo 01234ab' and the result returned was ";
+ BadResult = buf;
+ return FAIL;
+ }
+
+ wsprintf(buf, convert("foo %#x"), pos);
+ if (memcmp(buf, convert("foo 0x1234ab"), wcslen(buf)*2 + 2) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 8) Failed. The correct string is"
+ " 'foo 0x1234ab' and the result returned was ";
+ BadResult = buf;
+ return FAIL;
+ }
+
+ return PASS;
+}
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ if(test1())
+ {
+ Fail("%s '%s'\n",ErrorMessage,convertC(BadResult));
+
+ }
+
+ PAL_Terminate();
+ return PASS;
+
+}
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/wsprintfW/test12/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/wsprintfW/test12/testinfo.dat
new file mode 100644
index 0000000000..0d38a20bcc
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/wsprintfW/test12/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = wsprintfW
+Name = Positive test of wsprintfW
+TYPE = DEFAULT
+EXE1 = test
+Description
+= Test %x formatter with wsprintfW.
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/wsprintfW/test13/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/wsprintfW/test13/CMakeLists.txt
new file mode 100644
index 0000000000..617abb854c
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/wsprintfW/test13/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.c
+)
+
+add_executable(paltest_wsprintfw_test13
+ ${SOURCES}
+)
+
+add_dependencies(paltest_wsprintfw_test13 coreclrpal)
+
+target_link_libraries(paltest_wsprintfw_test13
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/wsprintfW/test13/test.c b/src/pal/tests/palsuite/miscellaneous/wsprintfW/test13/test.c
new file mode 100644
index 0000000000..dd0daae0a0
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/wsprintfW/test13/test.c
@@ -0,0 +1,126 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: test.c
+**
+** Purpose: Test for wsprintfW() function
+**
+**
+**=========================================================*/
+
+#define UNICODE
+#include <palsuite.h>
+
+char * ErrorMessage = NULL;
+WCHAR * BadResult = NULL;
+WCHAR buf[256];
+
+/* memcmp is used to verify the results, so this test is dependent on it. */
+/* ditto with strlen */
+
+BOOL test1()
+{
+ int pos = 0x1234ab;
+
+ wsprintf(buf, convert("foo %X"), pos);
+ if (memcmp(buf, convert("foo 1234AB"), wcslen(buf)*2 + 2) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 1) Failed. The correct string is"
+ " 'foo 1234AB' and the result returned was ";
+ BadResult = buf;
+ return FAIL;
+ }
+
+ wsprintf(buf, convert("foo %lX"), pos);
+ if (memcmp(buf, convert("foo 1234AB"), wcslen(buf)*2 + 2) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 2) Failed. The correct string is"
+ " 'foo 1234AB' and the result returned was ";
+ BadResult = buf;
+ return FAIL;
+ }
+
+ wsprintf(buf, convert("foo %7X"), pos);
+ if (memcmp(buf, convert("foo 1234AB"), wcslen(buf)*2 + 2) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 3) Failed. The correct string is"
+ " 'foo 1234AB' and the result returned was ";
+ BadResult = buf;
+ return FAIL;
+ }
+
+ wsprintf(buf, convert("foo %-7X"), pos);
+ if (memcmp(buf, convert("foo 1234AB "), wcslen(buf)*2 + 2) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 4) Failed. The correct string is"
+ " 'foo 1234AB ' and the result returned was ";
+ BadResult = buf;
+ return FAIL;
+ }
+
+ wsprintf(buf, convert("foo %.1X"), pos);
+ if (memcmp(buf, convert("foo 1234AB"), wcslen(buf)*2 + 2) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 5) Failed. The correct string is"
+ " 'foo 1234AB' and the result returned was ";
+ BadResult = buf;
+ return FAIL;
+ }
+
+ wsprintf(buf, convert("foo %.7X"), pos);
+ if (memcmp(buf, convert("foo 01234AB"), wcslen(buf)*2 + 2) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 6) Failed. The correct string is"
+ " 'foo 01234AB' and the result returned was ";
+ BadResult = buf;
+ return FAIL;
+ }
+
+ wsprintf(buf, convert("foo %07X"), pos);
+ if (memcmp(buf, convert("foo 01234AB"), wcslen(buf)*2 + 2) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 7) Failed. The correct string is"
+ " 'foo 01234AB' and the result returned was ";
+ BadResult = buf;
+ return FAIL;
+ }
+
+ wsprintf(buf, convert("foo %#X"), pos);
+ if (memcmp(buf, convert("foo 0X1234AB"), wcslen(buf)*2 + 2) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 8) Failed. The correct string is"
+ " 'foo 0X1234AB' and the result returned was ";
+ BadResult = buf;
+ return FAIL;
+ }
+
+ return PASS;
+}
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ if(test1())
+ {
+ Fail("%s '%s'\n",ErrorMessage,convertC(BadResult));
+
+ }
+
+ PAL_Terminate();
+ return PASS;
+
+}
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/wsprintfW/test13/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/wsprintfW/test13/testinfo.dat
new file mode 100644
index 0000000000..c16a43f7b7
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/wsprintfW/test13/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = wsprintfW
+Name = Positive test of wsprintfW
+TYPE = DEFAULT
+EXE1 = test
+Description
+= Test %X formatter with wsprintfW.
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/wsprintfW/test2/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/wsprintfW/test2/CMakeLists.txt
new file mode 100644
index 0000000000..00b26da2e6
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/wsprintfW/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.c
+)
+
+add_executable(paltest_wsprintfw_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_wsprintfw_test2 coreclrpal)
+
+target_link_libraries(paltest_wsprintfw_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/wsprintfW/test2/test.c b/src/pal/tests/palsuite/miscellaneous/wsprintfW/test2/test.c
new file mode 100644
index 0000000000..f25ab6c2f4
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/wsprintfW/test2/test.c
@@ -0,0 +1,108 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: test.c
+**
+** Purpose: Test for wsprintfW() function
+**
+**
+**=========================================================*/
+#define UNICODE
+#include <palsuite.h>
+
+
+char * ErrorMessage = NULL;
+WCHAR * BadResult = NULL;
+WCHAR buf[256];
+
+/* memcmp is used to verify the results, so this test is dependent on it. */
+/* ditto with strlen */
+
+
+BOOL test1()
+{
+
+ wsprintf(buf, convert("foo %s"), convert("bar"));
+ if (memcmp(buf, convert("foo bar"), wcslen(buf)*2+2) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 1) Failed. The correct string is 'foo bar'"
+ " and the result returned was ";
+ BadResult = buf;
+ return FAIL;
+ }
+
+ wsprintf(buf, convert("foo %ls"), convert("bar"));
+ if (memcmp(buf, convert("foo bar"), wcslen(buf)*2 + 2) != 0){
+ ErrorMessage = "ERROR: (Test 2) Failed. The correct string is 'foo bar'"
+ " and the result returned was ";
+ BadResult = buf;
+ return FAIL;
+ }
+
+ wsprintf(buf, convert("foo %5s"), convert("bar"));
+ if (memcmp(buf, convert("foo bar"), wcslen(buf)*2 + 2) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 3) Failed. The correct string is"
+ " 'foo bar' and the result returned was ";
+ BadResult = buf;
+ return FAIL;
+ }
+ wsprintf(buf, convert("foo %.2s"), convert("bar"));
+ if (memcmp(buf, convert("foo ba"), wcslen(buf)*2 + 2) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 4) Failed. The correct string is 'foo ba'"
+ " and the result returned was ";
+ BadResult = buf;
+ return FAIL;
+ }
+ wsprintf(buf, convert("foo %5.2s"), convert("bar"));
+ if (memcmp(buf, convert("foo ba"), wcslen(buf)*2 + 2) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 5) Failed. The correct string is"
+ " 'foo ba' and the result returned was ";
+ BadResult = buf;
+ return FAIL;
+ }
+ wsprintf(buf, convert("foo %-5s"), convert("bar"));
+ if (memcmp(buf, convert("foo bar "), wcslen(buf)*2 + 2) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 6) Failed. The correct string is"
+ " 'foo bar ' and the result returned was ";
+ BadResult = buf;
+ return FAIL;
+ }
+ wsprintf(buf, convert("foo %05s"), convert("bar"));
+ if (memcmp(buf, convert("foo 00bar"), wcslen(buf)*2 + 2) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 7) Failed. The correct string is"
+ " 'foo 00bar' and the result returned was ";
+ BadResult = buf;
+ return FAIL;
+ }
+
+ return PASS;
+}
+
+int __cdecl main(int argc, char *argv[])
+{
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ if(test1())
+ {
+ Fail("%s '%s'\n",ErrorMessage,convertC(BadResult));
+ }
+
+ PAL_Terminate();
+ return PASS;
+
+}
diff --git a/src/pal/tests/palsuite/miscellaneous/wsprintfW/test2/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/wsprintfW/test2/testinfo.dat
new file mode 100644
index 0000000000..a2a7bb2d39
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/wsprintfW/test2/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = wsprintfW
+Name = Positive test of wsprintfW
+TYPE = DEFAULT
+EXE1 = test
+Description
+= Test %s formatter with wsprintfW.
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/wsprintfW/test3/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/wsprintfW/test3/CMakeLists.txt
new file mode 100644
index 0000000000..25c6185d12
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/wsprintfW/test3/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.c
+)
+
+add_executable(paltest_wsprintfw_test3
+ ${SOURCES}
+)
+
+add_dependencies(paltest_wsprintfw_test3 coreclrpal)
+
+target_link_libraries(paltest_wsprintfw_test3
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/wsprintfW/test3/test.c b/src/pal/tests/palsuite/miscellaneous/wsprintfW/test3/test.c
new file mode 100644
index 0000000000..a52d617e47
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/wsprintfW/test3/test.c
@@ -0,0 +1,127 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: test.c
+**
+** Purpose: Test for wsprintfW() function
+**
+**
+**=========================================================*/
+#define UNICODE
+#include <palsuite.h>
+
+
+
+char * ErrorMessage = NULL;
+WCHAR * BadResult = NULL;
+WCHAR buf[256];
+
+/* memcmp is used to verify the results, so this test is dependent on it. */
+/* ditto with strlen */
+
+
+BOOL test1()
+{
+
+ wsprintf(buf, convert("foo %S"), "bar");
+ if (memcmp(buf, convert("foo bar"), wcslen(buf)*2 + 2) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 1) Failed. The correct string is"
+ " 'foo bar' and the result returned was ";
+ BadResult = buf;
+ return FAIL;
+ }
+
+ wsprintf(buf, convert("foo %hS"), "bar");
+ if (memcmp(buf, convert("foo bar"), wcslen(buf)*2 + 2) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 2) Failed. The correct string is"
+ " 'foo bar' and the result returned was ";
+ BadResult = buf;
+ return FAIL;
+ }
+
+ wsprintf(buf, convert("foo %lS"), convert("bar"));
+ if (memcmp(buf, convert("foo bar"), wcslen(buf)*2 + 2) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 3) Failed. The correct string is"
+ " 'foo bar' and the result returned was ";
+ BadResult = buf;
+ return FAIL;
+ }
+
+ wsprintf(buf, convert("foo %5S"), "bar");
+ if (memcmp(buf, convert("foo bar"), wcslen(buf)*2 + 2) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 4) Failed. The correct string is"
+ " 'foo bar' and the result returned was ";
+ BadResult = buf;
+ return FAIL;
+ }
+
+ wsprintf(buf, convert("foo %.2S"), "bar");
+ if (memcmp(buf, convert("foo ba"), wcslen(buf)*2 + 2) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 5) Failed. The correct string is"
+ " 'foo ba' and the result returned was ";
+ BadResult = buf;
+ return FAIL;
+ }
+
+ wsprintf(buf, convert("foo %5.2S"), "bar");
+ if (memcmp(buf, convert("foo ba"), wcslen(buf)*2 + 2) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 6) Failed. The correct string is"
+ " 'foo ba' and the result returned was ";
+ BadResult = buf;
+ return FAIL;
+ }
+
+ wsprintf(buf, convert("foo %-5S"), "bar");
+ if (memcmp(buf, convert("foo bar "), wcslen(buf)*2 + 2) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 7) Failed. The correct string is"
+ " 'foo bar ' and the result returned was ";
+ BadResult = buf;
+ return FAIL;
+ }
+
+ wsprintf(buf, convert("foo %05S"), "bar");
+ if (memcmp(buf, convert("foo 00bar"), wcslen(buf)*2 + 2) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 8) Failed. The correct string is"
+ " 'foo 00bar' and the result returned was ";
+ BadResult = buf;
+ return FAIL;
+ }
+
+ return PASS;
+}
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ if(test1())
+ {
+ Fail("%s '%s'\n",ErrorMessage,convertC(BadResult));
+
+ }
+
+ PAL_Terminate();
+ return PASS;
+
+}
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/wsprintfW/test3/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/wsprintfW/test3/testinfo.dat
new file mode 100644
index 0000000000..46b7b7459d
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/wsprintfW/test3/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = wsprintfW
+Name = Positive test of wsprintfW
+TYPE = DEFAULT
+EXE1 = test
+Description
+= Test %S formatter with wsprintfW.
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/wsprintfW/test6/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/wsprintfW/test6/CMakeLists.txt
new file mode 100644
index 0000000000..c63a4d5c82
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/wsprintfW/test6/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.c
+)
+
+add_executable(paltest_wsprintfw_test6
+ ${SOURCES}
+)
+
+add_dependencies(paltest_wsprintfw_test6 coreclrpal)
+
+target_link_libraries(paltest_wsprintfw_test6
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/wsprintfW/test6/test.c b/src/pal/tests/palsuite/miscellaneous/wsprintfW/test6/test.c
new file mode 100644
index 0000000000..513f1f7941
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/wsprintfW/test6/test.c
@@ -0,0 +1,115 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: test.c
+**
+** Purpose: Test for wsprintfW() function
+**
+**
+**=========================================================*/
+#define UNICODE
+#include <palsuite.h>
+
+
+char * ErrorMessage = NULL;
+WCHAR * BadResult = NULL;
+WCHAR buf[256];
+
+/* memcmp is used to verify the results, so this test is dependent on it. */
+/* ditto with strlen */
+
+BOOL test1()
+{
+ WCHAR wc = 'b';
+
+ wsprintf(buf, convert("foo %c"), wc);
+ if (memcmp(buf, convert("foo b"), wcslen(buf)*2 + 2) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 1) Failed. The correct string is"
+ " 'foo b' and the result returned was ";
+ BadResult = buf;
+ return FAIL;
+ }
+
+ wsprintf(buf, convert("foo %hc"), wc);
+ if (memcmp(buf, convert("foo b"), wcslen(buf)*2 + 2) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 2) Failed. The correct string is 'foo b'"
+ " and the result returned was ";
+ BadResult = buf;
+ return FAIL;
+ }
+
+ wsprintf(buf, convert("foo %lc"), wc);
+ if (memcmp(buf, convert("foo b"), wcslen(buf)*2 + 2) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 3) Failed. The correct string is 'foo b'"
+ " and the result returned was ";
+ BadResult = buf;
+ return FAIL;
+ }
+
+ wsprintf(buf, convert("foo %5c"), wc);
+ if (memcmp(buf, convert("foo b"), wcslen(buf)*2 + 2) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 4) Failed. The correct string is"
+ " 'foo b' and the result returned was ";
+ BadResult = buf;
+ return FAIL;
+ }
+
+ wsprintf(buf, convert("foo %-5c"), wc);
+ if (memcmp(buf, convert("foo b "), wcslen(buf)*2 + 2) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 5) Failed. The correct string is"
+ " 'foo b ' and the result returned was ";
+ BadResult = buf;
+ return FAIL;
+ }
+
+ wsprintf(buf, convert("foo %05c"), wc);
+ if (memcmp(buf, convert("foo 0000b"), wcslen(buf)*2 + 2) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 6) Failed. The correct string is"
+ " 'foo 0000b' and the result returned was ";
+ BadResult = buf;
+ return FAIL;
+ }
+
+ wsprintf(buf, convert("foo %#c"), wc);
+ if (memcmp(buf, convert("foo b"), wcslen(buf)*2 + 2) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 7) Failed. The correct string is 'foo b'"
+ " and the result returned was ";
+ BadResult = buf;
+ return FAIL;
+ }
+ return PASS;
+}
+int __cdecl main(int argc, char *argv[])
+{
+
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ if(test1())
+ {
+ Fail("%s '%s'\n",ErrorMessage,convertC(BadResult));
+
+ }
+
+ PAL_Terminate();
+ return PASS;
+
+}
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/wsprintfW/test6/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/wsprintfW/test6/testinfo.dat
new file mode 100644
index 0000000000..627b76f602
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/wsprintfW/test6/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = wsprintfW
+Name = Positive test of wsprintfW
+TYPE = DEFAULT
+EXE1 = test
+Description
+= Test %c formatter with wsprintfW.
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/wsprintfW/test7/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/wsprintfW/test7/CMakeLists.txt
new file mode 100644
index 0000000000..25e43107ff
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/wsprintfW/test7/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.c
+)
+
+add_executable(paltest_wsprintfw_test7
+ ${SOURCES}
+)
+
+add_dependencies(paltest_wsprintfw_test7 coreclrpal)
+
+target_link_libraries(paltest_wsprintfw_test7
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/wsprintfW/test7/test.c b/src/pal/tests/palsuite/miscellaneous/wsprintfW/test7/test.c
new file mode 100644
index 0000000000..99e73b13ce
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/wsprintfW/test7/test.c
@@ -0,0 +1,117 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: test.c
+**
+** Purpose: Test for wsprintfW() function
+**
+**
+**=========================================================*/
+#define UNICODE
+#include <palsuite.h>
+
+
+
+char * ErrorMessage = NULL;
+WCHAR * BadResult = NULL;
+WCHAR buf[256];
+
+/* memcmp is used to verify the results, so this test is dependent on it. */
+/* ditto with strlen */
+
+
+BOOL test1()
+{
+ WCHAR wb = 'b';
+
+ wsprintf(buf, convert("foo %C"), 'b');
+ if (memcmp(buf, convert("foo b"), wcslen(buf)*2 + 2) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 1) Failed. The correct string is"
+ " 'foo b' and the result returned was ";
+ BadResult = buf;
+ return FAIL;
+ }
+
+ wsprintf(buf, convert("foo %hC"), 'b');
+ if (memcmp(buf, convert("foo b"), wcslen(buf)*2 + 2) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 2) Failed. The correct string is"
+ " 'foo b' and the result returned was ";
+ BadResult = buf;
+ return FAIL;
+ }
+
+ wsprintf(buf, convert("foo %lC"), wb);
+ if (memcmp(buf, convert("foo b"), wcslen(buf)*2 + 2) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 3) Failed. The correct string is"
+ " 'foo b' and the result returned was ";
+ BadResult = buf;
+ return FAIL;
+ }
+
+ wsprintf(buf, convert("foo %5C"), 'b');
+ if (memcmp(buf, convert("foo b"), wcslen(buf)*2 + 2) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 4) Failed. The correct string is"
+ " 'foo b' and the result returned was ";
+ BadResult = buf;
+ return FAIL;
+ }
+
+ wsprintf(buf, convert("foo %-5C"), 'b');
+ if (memcmp(buf, convert("foo b "), wcslen(buf)*2 + 2) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 5) Failed. The correct string is"
+ " 'foo b ' and the result returned was ";
+ BadResult = buf;
+ return FAIL;
+ }
+
+ wsprintf(buf, convert("foo %05C"), 'b');
+ if (memcmp(buf, convert("foo 0000b"), wcslen(buf)*2 + 2) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 6) Failed. The correct string is"
+ " 'foo 0000b' and the result returned was ";
+ BadResult = buf;
+ return FAIL;
+ }
+
+ wsprintf(buf, convert("foo %#C"), 'b');
+ if (memcmp(buf, convert("foo b"), wcslen(buf)*2 + 2) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 7) Failed. The correct string is"
+ " 'foo b' and the result returned was ";
+ BadResult = buf;
+ return FAIL;
+ }
+ return PASS;
+}
+int __cdecl main(int argc, char *argv[])
+{
+
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ if(test1())
+ {
+ Fail("%s '%s'\n",ErrorMessage,convertC(BadResult));
+
+ }
+
+ PAL_Terminate();
+ return PASS;
+
+}
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/wsprintfW/test7/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/wsprintfW/test7/testinfo.dat
new file mode 100644
index 0000000000..ffcb47a37f
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/wsprintfW/test7/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = wsprintfW
+Name = Positive test of wsprintfW
+TYPE = DEFAULT
+EXE1 = test
+Description
+= Test %C formatter with wsprintfW.
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/wsprintfW/test8/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/wsprintfW/test8/CMakeLists.txt
new file mode 100644
index 0000000000..a6478a2af0
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/wsprintfW/test8/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.c
+)
+
+add_executable(paltest_wsprintfw_test8
+ ${SOURCES}
+)
+
+add_dependencies(paltest_wsprintfw_test8 coreclrpal)
+
+target_link_libraries(paltest_wsprintfw_test8
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/wsprintfW/test8/test.c b/src/pal/tests/palsuite/miscellaneous/wsprintfW/test8/test.c
new file mode 100644
index 0000000000..63c296eb22
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/wsprintfW/test8/test.c
@@ -0,0 +1,128 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: test.c
+**
+** Purpose: Test for wsprintfW() function
+**
+**
+**=========================================================*/
+#define UNICODE
+#include <palsuite.h>
+
+
+
+char * ErrorMessage = NULL;
+WCHAR * BadResult = NULL;
+WCHAR buf[256];
+
+/* memcmp is used to verify the results, so this test is dependent on it. */
+/* ditto with strlen */
+
+
+BOOL test1()
+{
+ int pos = 42;
+
+ wsprintf(buf, convert("foo %d"), pos);
+ if (memcmp(buf, convert("foo 42"), wcslen(buf)*2 + 2) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 1) Failed. The correct string is"
+ " 'foo 42' and the result returned was ";
+ BadResult = buf;
+ return FAIL;
+ }
+
+ wsprintf(buf, convert("foo %ld"), 0xFFFF);
+ if (memcmp(buf, convert("foo 65535"), wcslen(buf)*2 + 2) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 2) Failed. The correct string is"
+ " 'foo 65535' and the result returned was ";
+ BadResult = buf;
+ return FAIL;
+ }
+
+ wsprintf(buf, convert("foo %3d"), pos);
+ if (memcmp(buf, convert("foo 42"), wcslen(buf)*2 + 2) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 3) Failed. The correct string is"
+ " 'foo 42' and the result returned was ";
+ BadResult = buf;
+ return FAIL;
+ }
+
+ wsprintf(buf, convert("foo %-3d"), pos);
+ if (memcmp(buf, convert("foo 42 "), wcslen(buf)*2 + 2) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 4) Failed. The correct string is"
+ " 'foo 42 ' and the result returned was ";
+ BadResult = buf;
+ return FAIL;
+ }
+
+ wsprintf(buf, convert("foo %.1d"), pos);
+ if (memcmp(buf, convert("foo 42"), wcslen(buf)*2 + 2) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 5) Failed. The correct string is"
+ " 'foo 42' and the result returned was ";
+ BadResult = buf;
+ return FAIL;
+ }
+
+ wsprintf(buf, convert("foo %.3d"), pos);
+ if (memcmp(buf, convert("foo 042"), wcslen(buf)*2 + 2) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 6) Failed. The correct string is"
+ " 'foo 042' and the result returned was ";
+ BadResult = buf;
+ return FAIL;
+ }
+
+ wsprintf(buf, convert("foo %03d"), pos);
+ if (memcmp(buf, convert("foo 042"), wcslen(buf)*2 + 2) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 7) Failed. The correct string is"
+ " 'foo 042' and the result returned was ";
+ BadResult = buf;
+ return FAIL;
+ }
+
+ wsprintf(buf, convert("foo %#d"), pos);
+ if (memcmp(buf, convert("foo 42"), wcslen(buf)*2 + 2) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 8) Failed. The correct string is"
+ " 'foo 42' and the result returned was ";
+ BadResult = buf;
+ return FAIL;
+ }
+
+ return PASS;
+}
+int __cdecl main(int argc, char *argv[])
+{
+
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ if(test1())
+ {
+ Fail("%s '%s'\n",ErrorMessage,convertC(BadResult));
+
+ }
+
+ PAL_Terminate();
+ return PASS;
+
+}
+
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/wsprintfW/test8/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/wsprintfW/test8/testinfo.dat
new file mode 100644
index 0000000000..4238671918
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/wsprintfW/test8/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = wsprintfW
+Name = Positive test of wsprintfW
+TYPE = DEFAULT
+EXE1 = test
+Description
+= Test %d formatter with wsprintfW.
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/wsprintfW/test9/CMakeLists.txt b/src/pal/tests/palsuite/miscellaneous/wsprintfW/test9/CMakeLists.txt
new file mode 100644
index 0000000000..e09867b1a7
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/wsprintfW/test9/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.c
+)
+
+add_executable(paltest_wsprintfw_test9
+ ${SOURCES}
+)
+
+add_dependencies(paltest_wsprintfw_test9 coreclrpal)
+
+target_link_libraries(paltest_wsprintfw_test9
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/miscellaneous/wsprintfW/test9/test.c b/src/pal/tests/palsuite/miscellaneous/wsprintfW/test9/test.c
new file mode 100644
index 0000000000..0a49d9c2c5
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/wsprintfW/test9/test.c
@@ -0,0 +1,128 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: test.c
+**
+** Purpose: Test for wsprintfW() function
+**
+**
+**=========================================================*/
+
+#define UNICODE
+#include <palsuite.h>
+
+
+char * ErrorMessage = NULL;
+WCHAR * BadResult = NULL;
+WCHAR buf[256];
+
+/* memcmp is used to verify the results, so this test is dependent on it. */
+/* ditto with strlen */
+
+
+BOOL test1()
+{
+ int pos = 42;
+
+ wsprintf(buf, convert("foo %i"), pos);
+ if (memcmp(buf, convert("foo 42"), wcslen(buf)*2 + 2) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 1) Failed. The correct string is"
+ " 'foo 42' and the result returned was ";
+ BadResult = buf;
+ return FAIL;
+ }
+
+ wsprintf(buf, convert("foo %li"), 0xFFFF);
+ if (memcmp(buf, convert("foo 65535"), wcslen(buf)*2 + 2) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 2) Failed. The correct string is"
+ " 'foo 65535' and the result returned was ";
+ BadResult = buf;
+ return FAIL;
+ }
+
+ wsprintf(buf, convert("foo %3i"), pos);
+ if (memcmp(buf, convert("foo 42"), wcslen(buf)*2 + 2) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 3) Failed. The correct string is"
+ " 'foo 42' and the result returned was ";
+ BadResult = buf;
+ return FAIL;
+ }
+
+ wsprintf(buf, convert("foo %-3i"), pos);
+ if (memcmp(buf, convert("foo 42 "), wcslen(buf)*2 + 2) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 4) Failed. The correct string is"
+ " 'foo 42 ' and the result returned was ";
+ BadResult = buf;
+ return FAIL;
+ }
+
+ wsprintf(buf, convert("foo %.1i"), pos);
+ if (memcmp(buf, convert("foo 42"), wcslen(buf)*2 + 2) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 5) Failed. The correct string is"
+ " 'foo 42' and the result returned was ";
+ BadResult = buf;
+ return FAIL;
+ }
+
+ wsprintf(buf, convert("foo %.3i"), pos);
+ if (memcmp(buf, convert("foo 042"), wcslen(buf)*2 + 2) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 6) Failed. The correct string is"
+ " 'foo 042' and the result returned was ";
+ BadResult = buf;
+ return FAIL;
+ }
+
+ wsprintf(buf, convert("foo %03i"), pos);
+ if (memcmp(buf, convert("foo 042"), wcslen(buf)*2 + 2) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 7) Failed. The correct string is"
+ " 'foo 042' and the result returned was ";
+ BadResult = buf;
+ return FAIL;
+ }
+
+ wsprintf(buf, convert("foo %#i"), pos);
+ if (memcmp(buf, convert("foo 42"), wcslen(buf)*2 + 2) != 0)
+ {
+ ErrorMessage = "ERROR: (Test 8) Failed. The correct string is"
+ " 'foo 42' and the result returned was ";
+ BadResult = buf;
+ return FAIL;
+ }
+
+ return PASS;
+}
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ if(test1())
+ {
+ Fail("%s '%s'\n",ErrorMessage,convertC(BadResult));
+
+ }
+
+ PAL_Terminate();
+ return PASS;
+
+}
+
+
diff --git a/src/pal/tests/palsuite/miscellaneous/wsprintfW/test9/testinfo.dat b/src/pal/tests/palsuite/miscellaneous/wsprintfW/test9/testinfo.dat
new file mode 100644
index 0000000000..3006aa87bc
--- /dev/null
+++ b/src/pal/tests/palsuite/miscellaneous/wsprintfW/test9/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Miscellaneous
+Function = wsprintfW
+Name = Positive test of wsprintfW
+TYPE = DEFAULT
+EXE1 = test
+Description
+= Test %i formatter with wsprintfW.
+
+
diff --git a/src/pal/tests/palsuite/pal_specific/CMakeLists.txt b/src/pal/tests/palsuite/pal_specific/CMakeLists.txt
new file mode 100644
index 0000000000..aaf1f27182
--- /dev/null
+++ b/src/pal/tests/palsuite/pal_specific/CMakeLists.txt
@@ -0,0 +1,13 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+# TODO: make these tests compile
+# add_subdirectory(PAL_get_stderr)
+# add_subdirectory(PAL_get_stdin)
+# add_subdirectory(PAL_get_stdout)
+
+add_subdirectory(pal_entrypoint)
+add_subdirectory(PAL_errno)
+add_subdirectory(PAL_GetPALDirectoryW)
+add_subdirectory(pal_initializedebug)
+add_subdirectory(PAL_Initialize_Terminate)
+
diff --git a/src/pal/tests/palsuite/pal_specific/PAL_GetPALDirectoryW/CMakeLists.txt b/src/pal/tests/palsuite/pal_specific/PAL_GetPALDirectoryW/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/pal_specific/PAL_GetPALDirectoryW/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/pal_specific/PAL_GetPALDirectoryW/test1/CMakeLists.txt b/src/pal/tests/palsuite/pal_specific/PAL_GetPALDirectoryW/test1/CMakeLists.txt
new file mode 100644
index 0000000000..bf1d3a91e7
--- /dev/null
+++ b/src/pal/tests/palsuite/pal_specific/PAL_GetPALDirectoryW/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ PAL_GetPALDirectoryW.c
+)
+
+add_executable(paltest_pal_getpaldirectoryw_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_pal_getpaldirectoryw_test1 coreclrpal)
+
+target_link_libraries(paltest_pal_getpaldirectoryw_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/pal_specific/PAL_GetPALDirectoryW/test1/PAL_GetPALDirectoryW.c b/src/pal/tests/palsuite/pal_specific/PAL_GetPALDirectoryW/test1/PAL_GetPALDirectoryW.c
new file mode 100644
index 0000000000..2c67aa4954
--- /dev/null
+++ b/src/pal/tests/palsuite/pal_specific/PAL_GetPALDirectoryW/test1/PAL_GetPALDirectoryW.c
@@ -0,0 +1,78 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: pal_getpaldirectoryw.c
+**
+** Purpose: Positive test the PAL_GetPALDirectoryW API.
+** Call this API to retrieve a fully-qualified
+** directory name where the PAL DLL is loaded from.
+**
+**
+**============================================================*/
+#define UNICODE
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ int err;
+ BOOL bValue;
+ DWORD dwFileAttribute;
+ WCHAR *wpDirectoryName = NULL;
+ char *pDirectoryName = NULL;
+
+ /*Initialize the PAL environment*/
+ err = PAL_Initialize(argc, argv);
+ if(0 != err)
+ {
+ return FAIL;
+ }
+
+ /*allocate momory to store the directory name*/
+ wpDirectoryName = malloc(MAX_PATH*sizeof(WCHAR));
+ if(NULL == wpDirectoryName)
+ {
+ Fail("\nFailed to allocate memory for storing directory name!\n");
+ }
+
+ UINT size = MAX_PATH;
+ /*retrieve the machine configuration directory*/
+ bValue = PAL_GetPALDirectoryW(wpDirectoryName, &size);
+ if(FALSE == bValue)
+ {
+ free(wpDirectoryName);
+ Fail("Failed to call PAL_GetPALDirectoryW API, "
+ "error code =%u\n", GetLastError());
+ }
+
+
+ /*convert wide char string to a standard one*/
+ pDirectoryName = convertC(wpDirectoryName);
+ if(0 == strlen(pDirectoryName))
+ {
+ free(wpDirectoryName);
+ free(pDirectoryName);
+ Fail("The retrieved directory name string is empty!\n");
+ }
+
+ /*free the memory*/
+ free(pDirectoryName);
+
+ /*retrieve the attribute of a file or directory*/
+ dwFileAttribute = GetFileAttributesW(wpDirectoryName);
+
+ /*free the memory*/
+ free(wpDirectoryName);
+
+ /*check if the attribute indicates a directory*/
+ if(FILE_ATTRIBUTE_DIRECTORY !=
+ (dwFileAttribute & FILE_ATTRIBUTE_DIRECTORY))
+ {
+ Fail("The retrieved directory name is not a valid directory!\n");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/pal_specific/PAL_GetPALDirectoryW/test1/testinfo.dat b/src/pal/tests/palsuite/pal_specific/PAL_GetPALDirectoryW/test1/testinfo.dat
new file mode 100644
index 0000000000..dca92b0462
--- /dev/null
+++ b/src/pal/tests/palsuite/pal_specific/PAL_GetPALDirectoryW/test1/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = PAL_Specific
+Function = PAL_GetPALDirectoryW
+Name = Positive test for PAL_GetPALDirectoryW to retrieve fully-qualified directory name.
+TYPE = DEFAULT
+EXE1 = pal_getpaldirectoryw
+Description
+=Retrieve the fully-qualified directory name where the PAL DLL is loaded from
diff --git a/src/pal/tests/palsuite/pal_specific/PAL_GetUserTempDirectoryW/CMakeLists.txt b/src/pal/tests/palsuite/pal_specific/PAL_GetUserTempDirectoryW/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/pal_specific/PAL_GetUserTempDirectoryW/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/pal_specific/PAL_GetUserTempDirectoryW/test1/CMakeLists.txt b/src/pal/tests/palsuite/pal_specific/PAL_GetUserTempDirectoryW/test1/CMakeLists.txt
new file mode 100644
index 0000000000..e8d3c40565
--- /dev/null
+++ b/src/pal/tests/palsuite/pal_specific/PAL_GetUserTempDirectoryW/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ PAL_GetUserTempDirectoryW.c
+)
+
+add_executable(paltest_pal_getusertempdirectoryw_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_pal_getusertempdirectoryw_test1 coreclrpal)
+
+target_link_libraries(paltest_pal_getusertempdirectoryw_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/pal_specific/PAL_GetUserTempDirectoryW/test1/PAL_GetUserTempDirectoryW.c b/src/pal/tests/palsuite/pal_specific/PAL_GetUserTempDirectoryW/test1/PAL_GetUserTempDirectoryW.c
new file mode 100644
index 0000000000..65cc426c74
--- /dev/null
+++ b/src/pal/tests/palsuite/pal_specific/PAL_GetUserTempDirectoryW/test1/PAL_GetUserTempDirectoryW.c
@@ -0,0 +1,58 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: pal_getusertempdirectoryw.c
+**
+** Purpose: Positive test the PAL_GetUserTempDirectoryW API.
+** Call PAL_GetUserTempDirectoryW to retrieve the user
+** temp directory.
+**
+**
+**============================================================*/
+#define UNICODE
+#include <palsuite.h>
+
+#define DIRECTORYLENGTH 1024
+
+int __cdecl main(int argc, char *argv[])
+{
+ int err;
+ DWORD dwFileAttribute;
+ DWORD cch = DIRECTORYLENGTH;
+ WCHAR wDirectoryName[DIRECTORYLENGTH];
+
+ //Initialize the PAL environment
+ err = PAL_Initialize(argc, argv);
+ if(0 != err)
+ {
+ ExitProcess(FAIL);
+ }
+
+ //retrieve the user temp directory
+ err = PAL_GetUserTempDirectory(ddtInstallationDependentDirectory, wDirectoryName, &cch);
+
+ if(0 == err || 0 == strlen(convertC(wDirectoryName)))
+ {
+ Fail("Failed to call PAL_GetUserTempDirectoryW API!\n");
+ }
+
+
+ //retrieve the attributes of a file or directory
+ dwFileAttribute = GetFileAttributesW(wDirectoryName);
+
+
+ //check if the retrieved attribute indicates a directory
+ if( FILE_ATTRIBUTE_DIRECTORY != (FILE_ATTRIBUTE_DIRECTORY & dwFileAttribute))
+ {
+ Fail("PAL_GetUserTempDirectoryW API returned a non-directory name!\n");
+ }
+
+ printf ("PAL_GetUserTempDirectoryW returns %S\n", wDirectoryName);
+
+ PAL_Terminate();
+ return PASS;
+
+}
diff --git a/src/pal/tests/palsuite/pal_specific/PAL_GetUserTempDirectoryW/test1/testinfo.dat b/src/pal/tests/palsuite/pal_specific/PAL_GetUserTempDirectoryW/test1/testinfo.dat
new file mode 100644
index 0000000000..d530ca5fc7
--- /dev/null
+++ b/src/pal/tests/palsuite/pal_specific/PAL_GetUserTempDirectoryW/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = pal_specific
+Function = PAL_GetUserTempDirectoryW
+Name = Positive test for PAL_GetUserTempDirectoryW API
+TYPE = DEFAULT
+EXE1 = pal_getusertempdirectoryw
+Description
+=Test the PAL_GetUserTempDirectoryW to retrieve the user temp
+=directory name
diff --git a/src/pal/tests/palsuite/pal_specific/PAL_Initialize_Terminate/CMakeLists.txt b/src/pal/tests/palsuite/pal_specific/PAL_Initialize_Terminate/CMakeLists.txt
new file mode 100644
index 0000000000..ef14ea5352
--- /dev/null
+++ b/src/pal/tests/palsuite/pal_specific/PAL_Initialize_Terminate/CMakeLists.txt
@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+
diff --git a/src/pal/tests/palsuite/pal_specific/PAL_Initialize_Terminate/test1/CMakeLists.txt b/src/pal/tests/palsuite/pal_specific/PAL_Initialize_Terminate/test1/CMakeLists.txt
new file mode 100644
index 0000000000..416439d650
--- /dev/null
+++ b/src/pal/tests/palsuite/pal_specific/PAL_Initialize_Terminate/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ PAL_Initialize_Terminate.c
+)
+
+add_executable(paltest_pal_initialize_terminate_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_pal_initialize_terminate_test1 coreclrpal)
+
+target_link_libraries(paltest_pal_initialize_terminate_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/pal_specific/PAL_Initialize_Terminate/test1/PAL_Initialize_Terminate.c b/src/pal/tests/palsuite/pal_specific/PAL_Initialize_Terminate/test1/PAL_Initialize_Terminate.c
new file mode 100644
index 0000000000..29bb2c3b4f
--- /dev/null
+++ b/src/pal/tests/palsuite/pal_specific/PAL_Initialize_Terminate/test1/PAL_Initialize_Terminate.c
@@ -0,0 +1,33 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: pal_initialize_terminate.c
+**
+** Purpose: Positive test the PAL_Initialize and PAL_Terminate API.
+** Call PAL_Initialize to initialize the PAL
+** environment and call PAL_Terminate to clean up the PAL
+** environment.
+**
+
+**
+**============================================================*/
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ int err;
+
+ /* Initialize the PAL environment */
+ err = PAL_Initialize(argc, argv);
+
+ if(0 != err)
+ {
+ ExitProcess(1);
+ }
+
+ PAL_Terminate();
+ return 0;
+}
diff --git a/src/pal/tests/palsuite/pal_specific/PAL_Initialize_Terminate/test1/testinfo.dat b/src/pal/tests/palsuite/pal_specific/PAL_Initialize_Terminate/test1/testinfo.dat
new file mode 100644
index 0000000000..8ffe3bb7c7
--- /dev/null
+++ b/src/pal/tests/palsuite/pal_specific/PAL_Initialize_Terminate/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = PAL_Specific
+Function = PAL_Initialize and PAL_Terminate
+Name = Positive test for PAL_Initialize and PAL_Terminate
+TYPE = DEFAULT
+EXE1 = pal_initialize_terminate
+Description
+=Test the PAL_Initialize to initialize the PAL environment
+=Test the PAL_Terminate to clean up the PAL environment
diff --git a/src/pal/tests/palsuite/pal_specific/PAL_Initialize_Terminate/test2/CMakeLists.txt b/src/pal/tests/palsuite/pal_specific/PAL_Initialize_Terminate/test2/CMakeLists.txt
new file mode 100644
index 0000000000..b7661fd240
--- /dev/null
+++ b/src/pal/tests/palsuite/pal_specific/PAL_Initialize_Terminate/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ pal_initialize_twice.c
+)
+
+add_executable(paltest_pal_initialize_terminate_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_pal_initialize_terminate_test2 coreclrpal)
+
+target_link_libraries(paltest_pal_initialize_terminate_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/pal_specific/PAL_Initialize_Terminate/test2/pal_initialize_twice.c b/src/pal/tests/palsuite/pal_specific/PAL_Initialize_Terminate/test2/pal_initialize_twice.c
new file mode 100644
index 0000000000..fc460bc1ad
--- /dev/null
+++ b/src/pal/tests/palsuite/pal_specific/PAL_Initialize_Terminate/test2/pal_initialize_twice.c
@@ -0,0 +1,41 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: pal_initialize_twice.c
+**
+** Purpose: Positive test of PAL_Initialize and PAL_Terminate APIs.
+** Calls PAL_Initialize twice to ensure that doing so
+** will not cause unexpected failures in the PAL.
+** Calls PAL_Terminate twice to clean up the PAL.
+**
+
+**
+**============================================================*/
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ /* Initialize the PAL environment */
+ if (0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /* Try calling PAL_Initialize again - should just increment the init_count. */
+ if (0 != (PAL_Initialize(argc, argv)))
+ {
+ // Call terminate due to the first PAL initialization.
+ PAL_TerminateEx(FAIL);
+ return FAIL;
+ }
+
+ /* If both calls to PAL_Initialize succeed, then PAL_Terminate must be
+ called twice. The first call just decrements the init_count to 1. */
+
+ PAL_Terminate();
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/pal_specific/PAL_Initialize_Terminate/test2/testinfo.dat b/src/pal/tests/palsuite/pal_specific/PAL_Initialize_Terminate/test2/testinfo.dat
new file mode 100644
index 0000000000..31ceaf054d
--- /dev/null
+++ b/src/pal/tests/palsuite/pal_specific/PAL_Initialize_Terminate/test2/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = PAL_Specific
+Function = PAL_Initialize and PAL_Terminate
+Name = Positive test for calling PAL_Initialize twice
+TYPE = DEFAULT
+EXE1 = pal_initialize_twice
+Description
+=Test calling PAL_Initialize twice to initialize the PAL environment
+=and increment the init_count.
+=Test calling PAL_Terminate twice to decrement the init_count
+=and then clean up the PAL environment.
diff --git a/src/pal/tests/palsuite/pal_specific/PAL_RegisterLibraryW_UnregisterLibraryW/CMakeLists.txt b/src/pal/tests/palsuite/pal_specific/PAL_RegisterLibraryW_UnregisterLibraryW/CMakeLists.txt
new file mode 100644
index 0000000000..37b29c0d6d
--- /dev/null
+++ b/src/pal/tests/palsuite/pal_specific/PAL_RegisterLibraryW_UnregisterLibraryW/CMakeLists.txt
@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2_neg)
+
diff --git a/src/pal/tests/palsuite/pal_specific/PAL_RegisterLibraryW_UnregisterLibraryW/test1/CMakeLists.txt b/src/pal/tests/palsuite/pal_specific/PAL_RegisterLibraryW_UnregisterLibraryW/test1/CMakeLists.txt
new file mode 100644
index 0000000000..2379694b24
--- /dev/null
+++ b/src/pal/tests/palsuite/pal_specific/PAL_RegisterLibraryW_UnregisterLibraryW/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ PAL_RegisterLibraryW_UnregisterLibraryW.c
+)
+
+add_executable(paltest_pal_registerlibraryw_unregisterlibraryw_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_pal_registerlibraryw_unregisterlibraryw_test1 coreclrpal)
+
+target_link_libraries(paltest_pal_registerlibraryw_unregisterlibraryw_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/pal_specific/PAL_RegisterLibraryW_UnregisterLibraryW/test1/PAL_RegisterLibraryW_UnregisterLibraryW.c b/src/pal/tests/palsuite/pal_specific/PAL_RegisterLibraryW_UnregisterLibraryW/test1/PAL_RegisterLibraryW_UnregisterLibraryW.c
new file mode 100644
index 0000000000..ff0d33879c
--- /dev/null
+++ b/src/pal/tests/palsuite/pal_specific/PAL_RegisterLibraryW_UnregisterLibraryW/test1/PAL_RegisterLibraryW_UnregisterLibraryW.c
@@ -0,0 +1,64 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: pal_registerlibrary_unregisterlibrary
+**
+** Purpose: Positive test the PAL_RegisterLibrary API and
+** PAL_UnRegisterLibrary.
+** Call PAL_RegisterLibrary to map a module into the calling
+** process address space and call PAL_UnRegisterLibrary
+** to unmap this module.
+**
+**
+**============================================================*/
+#define UNICODE
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ HMODULE ModuleHandle;
+ char ModuleName[64];
+ WCHAR *wpModuleName = NULL;
+ int err;
+
+ /*Initialize the PAL environment*/
+ err = PAL_Initialize(argc, argv);
+ if(0 != err)
+ {
+ return FAIL;
+ }
+
+ /*zero the buffer*/
+ memset(ModuleName,0,64);
+ sprintf(ModuleName, "%s", "rotor_pal");
+
+ /*convert a normal string to a wide one*/
+ wpModuleName = convert(ModuleName);
+
+ /*load a module*/
+ ModuleHandle = PAL_RegisterLibrary(wpModuleName);
+
+ /*free the memory*/
+ free(wpModuleName);
+
+ if(!ModuleHandle)
+ {
+ Fail("Failed to call PAL_RegisterLibrary API to map a module "
+ "into calling process, error code=%u!\n", GetLastError());
+ }
+
+ /*decrement the reference count of the loaded DLL*/
+ err = PAL_UnregisterLibrary(ModuleHandle);
+ if(0 == err)
+ {
+ Fail("\nFailed to call PAL_UnregisterLibrary API to "
+ "decrement the count of the loaded DLL module, "
+ "error code=%u!\n", GetLastError());
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/pal_specific/PAL_RegisterLibraryW_UnregisterLibraryW/test1/testinfo.dat b/src/pal/tests/palsuite/pal_specific/PAL_RegisterLibraryW_UnregisterLibraryW/test1/testinfo.dat
new file mode 100644
index 0000000000..abbd28c238
--- /dev/null
+++ b/src/pal/tests/palsuite/pal_specific/PAL_RegisterLibraryW_UnregisterLibraryW/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = pal_specific
+Function = PAL_RegisterLibraryW and PAL_UnregisterLibraryW API
+Name = Positive test PAL_RegisterLibraryW and PAL_UnregisterLibaryW API
+TYPE = DEFAULT
+EXE1 = pal_registerlibraryw_unregisterlibraryw
+Description
+=Test the PAL_RegisterLibraryW and PAL_UnregisterLibraryW to map an executable
+=module into calling process address space and unmap this module
diff --git a/src/pal/tests/palsuite/pal_specific/PAL_RegisterLibraryW_UnregisterLibraryW/test2_neg/CMakeLists.txt b/src/pal/tests/palsuite/pal_specific/PAL_RegisterLibraryW_UnregisterLibraryW/test2_neg/CMakeLists.txt
new file mode 100644
index 0000000000..bbcb35933e
--- /dev/null
+++ b/src/pal/tests/palsuite/pal_specific/PAL_RegisterLibraryW_UnregisterLibraryW/test2_neg/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ reg_unreg_libraryw_neg.c
+)
+
+add_executable(paltest_reg_unreg_libraryw_neg
+ ${SOURCES}
+)
+
+add_dependencies(paltest_reg_unreg_libraryw_neg coreclrpal)
+
+target_link_libraries(paltest_reg_unreg_libraryw_neg
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/pal_specific/PAL_RegisterLibraryW_UnregisterLibraryW/test2_neg/reg_unreg_libraryw_neg.c b/src/pal/tests/palsuite/pal_specific/PAL_RegisterLibraryW_UnregisterLibraryW/test2_neg/reg_unreg_libraryw_neg.c
new file mode 100644
index 0000000000..a15ff5745b
--- /dev/null
+++ b/src/pal/tests/palsuite/pal_specific/PAL_RegisterLibraryW_UnregisterLibraryW/test2_neg/reg_unreg_libraryw_neg.c
@@ -0,0 +1,62 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: pal_registerlibraryw_unregisterlibraryw_neg.c
+**
+** Purpose: Negative test the PAL_RegisterLibrary API.
+** Call PAL_RegisterLibrary to map a non-existant module
+** into the calling process address space.
+**
+**
+**============================================================*/
+#define UNICODE
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ HMODULE ModuleHandle;
+ char ModuleName[64];
+ WCHAR *wpModuleName = NULL;
+ int err;
+
+ /*Initialize the PAL environment*/
+ err = PAL_Initialize(argc, argv);
+ if(0 != err)
+ {
+ return FAIL;
+ }
+
+ memset(ModuleName, 0, 64);
+ sprintf(ModuleName, "%s", "not_exist_module_name");
+
+ /*convert a normal string to a wide one*/
+ wpModuleName = convert(ModuleName);
+
+ /*load a not exist module*/
+ ModuleHandle = PAL_RegisterLibrary(wpModuleName);
+
+ /*free the memory*/
+ free(wpModuleName);
+
+ if(NULL != ModuleHandle)
+ {
+ Trace("ERROR: PAL_RegisterLibrary successfully mapped "
+ "a module that does not exist into the calling process\n");
+
+ /*decrement the reference count of the loaded DLL*/
+ err = PAL_UnregisterLibrary(ModuleHandle);
+ if(0 == err)
+ {
+ Trace("\nFailed to call PAL_UnregisterLibrary API to decrement the "
+ "count of the loaded DLL module!\n");
+ }
+ Fail("");
+
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/pal_specific/PAL_RegisterLibraryW_UnregisterLibraryW/test2_neg/testinfo.dat b/src/pal/tests/palsuite/pal_specific/PAL_RegisterLibraryW_UnregisterLibraryW/test2_neg/testinfo.dat
new file mode 100644
index 0000000000..3322633291
--- /dev/null
+++ b/src/pal/tests/palsuite/pal_specific/PAL_RegisterLibraryW_UnregisterLibraryW/test2_neg/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = pal_specific
+Function = PAL_RegisterLibraryW and PAL_UnregisterLibraryW API
+Name = Negative test for PAL_RegisterLibraryW and PAL_UnregisterLibaryW API to map and unmap a non-existant module
+TYPE = DEFAULT
+EXE1 = pal_registerlibraryw_unregisterlibraryw_neg
+Description
+=Test the PAL_RegisterLibraryW and PAL_UnregisterLibraryW to map a non-existant
+=module into calling process address space
+
diff --git a/src/pal/tests/palsuite/pal_specific/PAL_errno/CMakeLists.txt b/src/pal/tests/palsuite/pal_specific/PAL_errno/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/pal_specific/PAL_errno/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/pal_specific/PAL_errno/test1/CMakeLists.txt b/src/pal/tests/palsuite/pal_specific/PAL_errno/test1/CMakeLists.txt
new file mode 100644
index 0000000000..59922b194b
--- /dev/null
+++ b/src/pal/tests/palsuite/pal_specific/PAL_errno/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ PAL_errno.c
+)
+
+add_executable(paltest_pal_errno_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_pal_errno_test1 coreclrpal)
+
+target_link_libraries(paltest_pal_errno_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/pal_specific/PAL_errno/test1/PAL_errno.c b/src/pal/tests/palsuite/pal_specific/PAL_errno/test1/PAL_errno.c
new file mode 100644
index 0000000000..32e8487d07
--- /dev/null
+++ b/src/pal/tests/palsuite/pal_specific/PAL_errno/test1/PAL_errno.c
@@ -0,0 +1,53 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: pal_errno.c
+**
+** Purpose: Positive test the PAL_errno API.
+** call PAL_errno to retrieve the pointer to
+** the per-thread errno value.
+**
+**
+**============================================================*/
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ int err;
+ FILE *pFile = NULL;
+
+ /*Initialize the PAL environment*/
+ err = PAL_Initialize(argc, argv);
+ if( 0 != err)
+ {
+ return FAIL;
+ }
+
+ /*Try to open a not-exist file to read to generate an error*/
+ pFile = fopen( "no_exist_file_name", "r" );
+
+ if( NULL != pFile )
+ {
+ Trace("\nFailed to call fopen to open a not exist for reading, "
+ "an error is expected, but no error occurred\n");
+
+ if( EOF == fclose( pFile ) )
+ {
+ Trace("\nFailed to call fclose to close a file stream\n");
+ }
+ Fail( "Test failed! fopen() Should not have worked!" );
+ }
+
+ /*retrieve the per-thread error value pointer*/
+ if( 2 != errno )
+ {
+ Fail("\nFailed to call PAL_errno API, this value is not correct."
+ " The correct value is ENOENT[2] ( No such file or directory.).\n");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/pal_specific/PAL_errno/test1/testinfo.dat b/src/pal/tests/palsuite/pal_specific/PAL_errno/test1/testinfo.dat
new file mode 100644
index 0000000000..a35e1d23fc
--- /dev/null
+++ b/src/pal/tests/palsuite/pal_specific/PAL_errno/test1/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = PAL_Specific
+Function = PAL_errno
+Name = Positive test PAL_errno API to retrieve the pre-thread errno value
+TYPE = DEFAULT
+EXE1 = pal_errno
+Description
+=Test the PAL_errno to retrieve a pointer to per-thread errno value
diff --git a/src/pal/tests/palsuite/pal_specific/PAL_get_stderr/CMakeLists.txt b/src/pal/tests/palsuite/pal_specific/PAL_get_stderr/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/pal_specific/PAL_get_stderr/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/pal_specific/PAL_get_stderr/test1/CMakeLists.txt b/src/pal/tests/palsuite/pal_specific/PAL_get_stderr/test1/CMakeLists.txt
new file mode 100644
index 0000000000..3436a2dfdb
--- /dev/null
+++ b/src/pal/tests/palsuite/pal_specific/PAL_get_stderr/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ PAL_get_stderr.c
+)
+
+add_executable(paltest_pal_get_stderr_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_pal_get_stderr_test1 coreclrpal)
+
+target_link_libraries(paltest_pal_get_stderr_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/pal_specific/PAL_get_stderr/test1/PAL_get_stderr.c b/src/pal/tests/palsuite/pal_specific/PAL_get_stderr/test1/PAL_get_stderr.c
new file mode 100644
index 0000000000..da53460101
--- /dev/null
+++ b/src/pal/tests/palsuite/pal_specific/PAL_get_stderr/test1/PAL_get_stderr.c
@@ -0,0 +1,52 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: pal_get_stderr.c
+**
+** Purpose: Positive test the PAL_get_stderr API.
+** Call PAL_get_stderr to retrieve the PAL standard error
+** output stream pointer.
+** This test case should be run manually and automatically.
+**
+
+**
+**============================================================*/
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ int err;
+ FILE *pPAL_stderr = NULL;
+ const char *pMsg = "\nThis is a PAL_get_stderr test message, "
+ "not an error message!\n";
+
+ /*Initialize the PAL environment*/
+ err = PAL_Initialize(argc, argv);
+ if(0 != err)
+ {
+ return FAIL;
+ }
+
+ /*retrieve the PAL standard error output stream pointer*/
+ pPAL_stderr = PAL_get_stderr();
+
+ if(NULL == pPAL_stderr)
+ {
+ Fail("\nFailed to call PAL_get_stderr API, error code = %u\n",
+ GetLastError());
+ }
+
+ /*output a test message through PAL standard error stream*/
+ err = fputs(pMsg, pPAL_stderr);
+ if(EOF == err)
+ {
+ Fail("\nFailed to call fputs to output message to PAL stdandard "
+ "error stream, error code=%u\n", GetLastError());
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/pal_specific/PAL_get_stderr/test1/testinfo.dat b/src/pal/tests/palsuite/pal_specific/PAL_get_stderr/test1/testinfo.dat
new file mode 100644
index 0000000000..a633c68e34
--- /dev/null
+++ b/src/pal/tests/palsuite/pal_specific/PAL_get_stderr/test1/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = PAL_Specific
+Function = PAL_get_stderr
+Name = Positive test PAL_get_stderr to retrieve the PAL standard error stream pointer
+TYPE = DEFAULT
+EXE1 = pal_get_stderr
+Description
+=Test the PAL_get_stderr to retrieve the PAL standard error output stream pointer and
+=output a test message to this error stream
+=this test case will be run both manually and automatically
diff --git a/src/pal/tests/palsuite/pal_specific/PAL_get_stdin/CMakeLists.txt b/src/pal/tests/palsuite/pal_specific/PAL_get_stdin/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/pal_specific/PAL_get_stdin/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/pal_specific/PAL_get_stdin/test1/CMakeLists.txt b/src/pal/tests/palsuite/pal_specific/PAL_get_stdin/test1/CMakeLists.txt
new file mode 100644
index 0000000000..592895b18c
--- /dev/null
+++ b/src/pal/tests/palsuite/pal_specific/PAL_get_stdin/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ PAL_get_stdin.c
+)
+
+add_executable(paltest_pal_get_stdin_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_pal_get_stdin_test1 coreclrpal)
+
+target_link_libraries(paltest_pal_get_stdin_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/pal_specific/PAL_get_stdin/test1/PAL_get_stdin.c b/src/pal/tests/palsuite/pal_specific/PAL_get_stdin/test1/PAL_get_stdin.c
new file mode 100644
index 0000000000..5d1fd23f92
--- /dev/null
+++ b/src/pal/tests/palsuite/pal_specific/PAL_get_stdin/test1/PAL_get_stdin.c
@@ -0,0 +1,68 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: pal_get_stdin.c
+**
+** Purpose: Positive test the PAL_get_stdout API.
+** Call PAL_get_stdin to retrieve the PAL standard input
+** stream pointer.
+** This test case should be run manually.
+**
+
+**
+**============================================================*/
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ int err;
+ FILE *pPAL_stdin = NULL;
+ char Buffer[256];
+
+ /*Initialize the PAL environment*/
+ err = PAL_Initialize(argc, argv);
+ if(0 != err)
+ {
+ return FAIL;
+ }
+
+ /*retrieve the PAL standard input stream pointer*/
+ pPAL_stdin = PAL_get_stdin();
+ if(NULL == pPAL_stdin)
+ {
+ Fail("\nFailed to call PAL_get_stdin API to retrieve the "
+ "PAL standard input stream pointer, "
+ "error code = %u\n", GetLastError());
+ }
+
+ /*zero the buffer*/
+ memset(Buffer, 0, 256);
+
+ printf("\nPlease input some words: (less than 255 characters)\n");
+
+ /*further test the input stream*/
+ /*read message from the PAL standard input stream*/
+ if(NULL == fgets(Buffer, 255, pPAL_stdin))
+ {
+ Fail( "Failed to call fgets to get a string from PAL standard "
+ "input stream, error code=%u\n", GetLastError());
+ }
+ else
+ {
+ if(1 == strlen(Buffer) && Buffer[0] == '\n')
+ {
+ printf("\nEmpty input!\n");
+ }
+ else
+ {
+ printf("\nYour input words are:\n%s\n", Buffer);
+ }
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/pal_specific/PAL_get_stdin/test1/testinfo.dat b/src/pal/tests/palsuite/pal_specific/PAL_get_stdin/test1/testinfo.dat
new file mode 100644
index 0000000000..d1c5723236
--- /dev/null
+++ b/src/pal/tests/palsuite/pal_specific/PAL_get_stdin/test1/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = PAL_Specific
+Function = PAL_get_stdin
+Name = Positive test PAL_get_stdin to retrieve the PAL standard stdin stream pointer
+TYPE = DEFAULT
+EXE1 = pal_get_stdin
+Description
+=Test the PAL_get_stdin to retrieve the PAL standard input stream pointer
+=if success, display the input string to screen
+=this test case should be run manually
diff --git a/src/pal/tests/palsuite/pal_specific/PAL_get_stdout/CMakeLists.txt b/src/pal/tests/palsuite/pal_specific/PAL_get_stdout/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/pal_specific/PAL_get_stdout/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/pal_specific/PAL_get_stdout/test1/CMakeLists.txt b/src/pal/tests/palsuite/pal_specific/PAL_get_stdout/test1/CMakeLists.txt
new file mode 100644
index 0000000000..865dd52f16
--- /dev/null
+++ b/src/pal/tests/palsuite/pal_specific/PAL_get_stdout/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ PAL_get_stdout.c
+)
+
+add_executable(paltest_pal_get_stdout_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_pal_get_stdout_test1 coreclrpal)
+
+target_link_libraries(paltest_pal_get_stdout_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/pal_specific/PAL_get_stdout/test1/PAL_get_stdout.c b/src/pal/tests/palsuite/pal_specific/PAL_get_stdout/test1/PAL_get_stdout.c
new file mode 100644
index 0000000000..ebfee47ae9
--- /dev/null
+++ b/src/pal/tests/palsuite/pal_specific/PAL_get_stdout/test1/PAL_get_stdout.c
@@ -0,0 +1,52 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: pal_get_stdout.c
+**
+** Purpose: Positive test the PAL_get_stdout API.
+** Call PAL_get_stdout to retrieve the PAL standard output
+** stream pointer.
+** This test case should be run manually and automatically.
+**
+
+**
+**============================================================*/
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ int err;
+ FILE *pPAL_stdout = NULL;
+ const char *pMsg = "\nThis is a PAL_get_stdout test output message, "
+ "not an error message!\n";
+
+ /*Initialize the PAL environment*/
+ err = PAL_Initialize(argc, argv);
+ if(0 != err)
+ {
+ return FAIL;
+ }
+
+ /*retrieve the PAL output stream pointer*/
+ pPAL_stdout = PAL_get_stdout();
+ if(NULL == pPAL_stdout)
+ {
+ Fail("\nFailed to call PAL_get_stdout API to retrieve the "
+ "standard PAL output stream pointer, error code=%u\n",
+ GetLastError());
+ }
+
+ /*output a test message through PAL standard output stream*/
+ err = fputs(pMsg, pPAL_stdout);
+ if(EOF == err)
+ {
+ Fail("\nFailed to call fputs to output message to PAL stdandard "
+ "output stream, error code=%u\n", GetLastError());
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/pal_specific/PAL_get_stdout/test1/testinfo.dat b/src/pal/tests/palsuite/pal_specific/PAL_get_stdout/test1/testinfo.dat
new file mode 100644
index 0000000000..ed370981aa
--- /dev/null
+++ b/src/pal/tests/palsuite/pal_specific/PAL_get_stdout/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = PAL_Specific
+Function = PAL_get_stdout
+Name = Positive test PAL_get_stdout to retrieve PAL standard output stream pointer
+TYPE = DEFAULT
+EXE1 = pal_get_stdout
+Description
+=Test the PAL_get_stdout to retrieve the PAL standard output stream pointer
+=This test case will be run both manually and automatically
diff --git a/src/pal/tests/palsuite/pal_specific/pal_entrypoint/CMakeLists.txt b/src/pal/tests/palsuite/pal_specific/pal_entrypoint/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/pal_specific/pal_entrypoint/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/pal_specific/pal_entrypoint/test1/CMakeLists.txt b/src/pal/tests/palsuite/pal_specific/pal_entrypoint/test1/CMakeLists.txt
new file mode 100644
index 0000000000..cd18b76958
--- /dev/null
+++ b/src/pal/tests/palsuite/pal_specific/pal_entrypoint/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ pal_entrypoint.c
+)
+
+add_executable(paltest_pal_entrypoint_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_pal_entrypoint_test1 coreclrpal)
+
+target_link_libraries(paltest_pal_entrypoint_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/pal_specific/pal_entrypoint/test1/pal_entrypoint.c b/src/pal/tests/palsuite/pal_specific/pal_entrypoint/test1/pal_entrypoint.c
new file mode 100644
index 0000000000..c1b66944aa
--- /dev/null
+++ b/src/pal/tests/palsuite/pal_specific/pal_entrypoint/test1/pal_entrypoint.c
@@ -0,0 +1,54 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: pal_entrypoint.c
+**
+** Purpose: Positive test the PAL_EntryPoint API.
+**
+** Test the PAL_EntryPoint, Call a PAL function, and let main return
+** as expected..
+**
+
+**
+**============================================================*/
+
+#include "palstartup.h"
+
+/* Test case copied and stream lined from isalpha\test1*/
+struct testCase
+{
+ int CorrectResult;
+ int character;
+};
+
+int __cdecl main(int argc, char *argv[])
+{
+ int result;
+ int i;
+
+ struct testCase testCases[] =
+ {
+ {1, 'a'}
+ };
+
+
+ i = 0;
+ result = isalpha(testCases[i].character);
+ /* The return value is 'non-zero' for success. This if condition
+ * will still work if that non-zero isn't just 1
+ */
+ if ( ((testCases[i].CorrectResult == 1) && (result == 0)) ||
+ ( (testCases[i].CorrectResult == 0) && (result != 0) ))
+ {
+ Fail("ERROR: isalpha returned %i instead of %i for character "
+ "%c.\n",
+ result,
+ testCases[i].CorrectResult,
+ testCases[i].character);
+ }
+
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/pal_specific/pal_entrypoint/test1/palstartup.h b/src/pal/tests/palsuite/pal_specific/pal_entrypoint/test1/palstartup.h
new file mode 100644
index 0000000000..862870be99
--- /dev/null
+++ b/src/pal/tests/palsuite/pal_specific/pal_entrypoint/test1/palstartup.h
@@ -0,0 +1,49 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+// ===========================================================================
+// File: palstartup.h
+//
+// An implementation of startup code for Rotor's Unix PAL. This file should
+// be included by any file in a PAL application that defines main.
+// we have added palsuite.h to include test related macros etc...
+// ===========================================================================
+
+#ifndef __PALSTARTUP_H__
+#define __PALSTARTUP_H__
+
+#include <palsuite.h>
+
+int __cdecl PAL_startup_main(int argc, char **argv);
+
+struct _mainargs
+{
+ int argc;
+ char ** argv;
+};
+
+static DWORD PALAPI run_main(struct _mainargs *args)
+{
+ return (DWORD) PAL_startup_main(args->argc, args->argv);
+}
+
+int __cdecl main(int argc, char **argv) {
+ struct _mainargs mainargs;
+
+ if (PAL_Initialize(argc, argv)) {
+ return FAIL;;
+ }
+
+ // PAL_Terminate is a stdcall function, but it takes no parameters
+ // so the difference doesn't matter.
+ atexit((void (__cdecl *)(void)) PAL_Terminate);
+
+ mainargs.argc = argc;
+ mainargs.argv = argv;
+ exit((int)PAL_EntryPoint((PTHREAD_START_ROUTINE)run_main, &mainargs));
+ return 0; // Quiet a compiler warning
+}
+
+#define main PAL_startup_main
+
+#endif // __PALSTARTUP_H__
diff --git a/src/pal/tests/palsuite/pal_specific/pal_entrypoint/test1/testinfo.dat b/src/pal/tests/palsuite/pal_specific/pal_entrypoint/test1/testinfo.dat
new file mode 100644
index 0000000000..01ac3d6f9f
--- /dev/null
+++ b/src/pal/tests/palsuite/pal_specific/pal_entrypoint/test1/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = PAL_Specific
+Function = PAL_entrypoint
+Name = Positive test entrypoint API
+TYPE = DEFAULT
+EXE1 = pal_errno
+Description
+=Test the PAL_entrypoint to call a PAL api
diff --git a/src/pal/tests/palsuite/pal_specific/pal_initializedebug/CMakeLists.txt b/src/pal/tests/palsuite/pal_specific/pal_initializedebug/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/pal_specific/pal_initializedebug/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/pal_specific/pal_initializedebug/test1/CMakeLists.txt b/src/pal/tests/palsuite/pal_specific/pal_initializedebug/test1/CMakeLists.txt
new file mode 100644
index 0000000000..f6e243d0c4
--- /dev/null
+++ b/src/pal/tests/palsuite/pal_specific/pal_initializedebug/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ pal_initializedebug.c
+)
+
+add_executable(paltest_pal_initializedebug_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_pal_initializedebug_test1 coreclrpal)
+
+target_link_libraries(paltest_pal_initializedebug_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/pal_specific/pal_initializedebug/test1/pal_initializedebug.c b/src/pal/tests/palsuite/pal_specific/pal_initializedebug/test1/pal_initializedebug.c
new file mode 100644
index 0000000000..d14c316013
--- /dev/null
+++ b/src/pal/tests/palsuite/pal_specific/pal_initializedebug/test1/pal_initializedebug.c
@@ -0,0 +1,36 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: pal_initializedebug.c
+**
+** Purpose: Positive test the PAL_InitializeDebug API.
+**
+** Test the PAL_InitializeDebug, it will be NOPs for all
+** platforms other than Mac. There is no other way of testing it
+** currently
+**
+
+**
+**============================================================*/
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[])
+{
+ int err;
+
+ /* Initialize the PAL environment */
+ err = PAL_Initialize(argc, argv);
+
+ if(0 != err)
+ {
+ return FAIL;
+ }
+
+ PAL_InitializeDebug();
+
+ PAL_Terminate();
+ return 0;
+}
diff --git a/src/pal/tests/palsuite/pal_specific/pal_initializedebug/test1/testinfo.dat b/src/pal/tests/palsuite/pal_specific/pal_initializedebug/test1/testinfo.dat
new file mode 100644
index 0000000000..45c40e50d2
--- /dev/null
+++ b/src/pal/tests/palsuite/pal_specific/pal_initializedebug/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = PAL_Specific
+Function = PAL_InitializeDebug
+Name = Positive test for PAL_InitializeDebug
+TYPE = DEFAULT
+EXE1 = pal_initializedebug
+Description
+=Test the PAL_InitializeDebug, it will be NOPs for all
+=platforms other than Mac
diff --git a/src/pal/tests/palsuite/paltestlist.txt b/src/pal/tests/palsuite/paltestlist.txt
new file mode 100644
index 0000000000..d0a76e9573
--- /dev/null
+++ b/src/pal/tests/palsuite/paltestlist.txt
@@ -0,0 +1,808 @@
+c_runtime/abs/test1/paltest_abs_test1
+c_runtime/acos/test1/paltest_acos_test1
+c_runtime/asin/test1/paltest_asin_test1
+c_runtime/atan/test1/paltest_atan_test1
+c_runtime/atan2/test1/paltest_atan2_test1
+c_runtime/atof/test1/paltest_atof_test1
+c_runtime/atoi/test1/paltest_atoi_test1
+c_runtime/atol/test1/paltest_atol_test1
+c_runtime/bsearch/test1/paltest_bsearch_test1
+c_runtime/bsearch/test2/paltest_bsearch_test2
+c_runtime/ceil/test1/paltest_ceil_test1
+c_runtime/cos/test1/paltest_cos_test1
+c_runtime/cosh/test1/paltest_cosh_test1
+c_runtime/errno/test1/paltest_errno_test1
+c_runtime/errno/test2/paltest_errno_test2
+c_runtime/exit/test1/paltest_exit_test1
+c_runtime/exp/test1/paltest_exp_test1
+c_runtime/fabs/test1/paltest_fabs_test1
+c_runtime/fabsf/test1/paltest_fabsf_test1
+c_runtime/fclose/test1/paltest_fclose_test1
+c_runtime/fclose/test2/paltest_fclose_test2
+c_runtime/fflush/test1/paltest_fflush_test1
+c_runtime/fgets/test1/paltest_fgets_test1
+c_runtime/fgets/test2/paltest_fgets_test2
+c_runtime/fgets/test3/paltest_fgets_test3
+c_runtime/floor/test1/paltest_floor_test1
+c_runtime/fmod/test1/paltest_fmod_test1
+c_runtime/fmodf/test1/paltest_fmodf_test1
+c_runtime/fopen/test1/paltest_fopen_test1
+c_runtime/fopen/test2/paltest_fopen_test2
+c_runtime/fopen/test3/paltest_fopen_test3
+c_runtime/fopen/test4/paltest_fopen_test4
+c_runtime/fopen/test5/paltest_fopen_test5
+c_runtime/fopen/test6/paltest_fopen_test6
+c_runtime/fopen/test7/paltest_fopen_test7
+c_runtime/fprintf/test1/paltest_fprintf_test1
+c_runtime/fprintf/test10/paltest_fprintf_test10
+c_runtime/fprintf/test11/paltest_fprintf_test11
+c_runtime/fprintf/test12/paltest_fprintf_test12
+c_runtime/fprintf/test13/paltest_fprintf_test13
+c_runtime/fprintf/test14/paltest_fprintf_test14
+c_runtime/fprintf/test15/paltest_fprintf_test15
+c_runtime/fprintf/test16/paltest_fprintf_test16
+c_runtime/fprintf/test17/paltest_fprintf_test17
+c_runtime/fprintf/test18/paltest_fprintf_test18
+c_runtime/fprintf/test19/paltest_fprintf_test19
+c_runtime/fprintf/test2/paltest_fprintf_test2
+c_runtime/fprintf/test3/paltest_fprintf_test3
+c_runtime/fprintf/test4/paltest_fprintf_test4
+c_runtime/fprintf/test5/paltest_fprintf_test5
+c_runtime/fprintf/test6/paltest_fprintf_test6
+c_runtime/fprintf/test7/paltest_fprintf_test7
+c_runtime/fprintf/test8/paltest_fprintf_test8
+c_runtime/fprintf/test9/paltest_fprintf_test9
+c_runtime/fputs/test1/paltest_fputs_test1
+c_runtime/free/test1/paltest_free_test1
+c_runtime/fseek/test1/paltest_fseek_test1
+c_runtime/fwprintf/test1/paltest_fwprintf_test1
+c_runtime/fwprintf/test10/paltest_fwprintf_test10
+c_runtime/fwprintf/test11/paltest_fwprintf_test11
+c_runtime/fwprintf/test12/paltest_fwprintf_test12
+c_runtime/fwprintf/test13/paltest_fwprintf_test13
+c_runtime/fwprintf/test14/paltest_fwprintf_test14
+c_runtime/fwprintf/test15/paltest_fwprintf_test15
+c_runtime/fwprintf/test16/paltest_fwprintf_test16
+c_runtime/fwprintf/test17/paltest_fwprintf_test17
+c_runtime/fwprintf/test18/paltest_fwprintf_test18
+c_runtime/fwprintf/test3/paltest_fwprintf_test3
+c_runtime/fwprintf/test4/paltest_fwprintf_test4
+c_runtime/fwprintf/test5/paltest_fwprintf_test5
+c_runtime/fwprintf/test6/paltest_fwprintf_test6
+c_runtime/fwprintf/test8/paltest_fwprintf_test8
+c_runtime/fwprintf/test9/paltest_fwprintf_test9
+c_runtime/fwrite/test1/paltest_fwrite_test1
+c_runtime/getc/test1/paltest_getc_test1
+c_runtime/getenv/test1/paltest_getenv_test1
+c_runtime/getenv/test2/paltest_getenv_test2
+c_runtime/getenv/test3/paltest_getenv_test3
+c_runtime/isalnum/test1/paltest_isalnum_test1
+c_runtime/isalpha/test1/paltest_isalpha_test1
+c_runtime/isdigit/test1/paltest_isdigit_test1
+c_runtime/islower/test1/paltest_islower_test1
+c_runtime/isprint/test1/paltest_isprint_test1
+c_runtime/isprint/test2/paltest_isprint_test2
+c_runtime/isspace/test1/paltest_isspace_test1
+c_runtime/isupper/test1/paltest_isupper_test1
+c_runtime/iswdigit/test1/paltest_iswdigit_test1
+c_runtime/iswspace/test1/paltest_iswspace_test1
+c_runtime/iswupper/test1/paltest_iswupper_test1
+c_runtime/iswxdigit/test1/paltest_iswxdigit_test1
+c_runtime/isxdigit/test1/paltest_isxdigit_test1
+c_runtime/labs/test1/paltest_labs_test1
+c_runtime/llabs/test1/paltest_llabs_test1
+c_runtime/localtime/test1/paltest_localtime_test1
+c_runtime/log/test1/paltest_log_test1
+c_runtime/log10/test1/paltest_log10_test1
+c_runtime/malloc/test1/paltest_malloc_test1
+c_runtime/malloc/test2/paltest_malloc_test2
+c_runtime/memchr/test1/paltest_memchr_test1
+c_runtime/memcmp/test1/paltest_memcmp_test1
+c_runtime/memcpy/test1/paltest_memcpy_test1
+c_runtime/memmove/test1/paltest_memmove_test1
+c_runtime/memset/test1/paltest_memset_test1
+c_runtime/modf/test1/paltest_modf_test1
+c_runtime/modff/test1/paltest_modff_test1
+c_runtime/pow/test1/paltest_pow_test1
+c_runtime/printf/test1/paltest_printf_test1
+c_runtime/printf/test10/paltest_printf_test10
+c_runtime/printf/test11/paltest_printf_test11
+c_runtime/printf/test12/paltest_printf_test12
+c_runtime/printf/test13/paltest_printf_test13
+c_runtime/printf/test14/paltest_printf_test14
+c_runtime/printf/test15/paltest_printf_test15
+c_runtime/printf/test16/paltest_printf_test16
+c_runtime/printf/test17/paltest_printf_test17
+c_runtime/printf/test18/paltest_printf_test18
+c_runtime/printf/test19/paltest_printf_test19
+c_runtime/printf/test2/paltest_printf_test2
+c_runtime/printf/test3/paltest_printf_test3
+c_runtime/printf/test4/paltest_printf_test4
+c_runtime/printf/test5/paltest_printf_test5
+c_runtime/printf/test6/paltest_printf_test6
+c_runtime/printf/test7/paltest_printf_test7
+c_runtime/printf/test8/paltest_printf_test8
+c_runtime/printf/test9/paltest_printf_test9
+c_runtime/qsort/test1/paltest_qsort_test1
+c_runtime/qsort/test2/paltest_qsort_test2
+c_runtime/rand_srand/test1/paltest_rand_srand_test1
+c_runtime/realloc/test1/paltest_realloc_test1
+c_runtime/sin/test1/paltest_sin_test1
+c_runtime/sinh/test1/paltest_sinh_test1
+c_runtime/sprintf/test1/paltest_sprintf_test1
+c_runtime/sprintf/test10/paltest_sprintf_test10
+c_runtime/sprintf/test11/paltest_sprintf_test11
+c_runtime/sprintf/test12/paltest_sprintf_test12
+c_runtime/sprintf/test13/paltest_sprintf_test13
+c_runtime/sprintf/test14/paltest_sprintf_test14
+c_runtime/sprintf/test15/paltest_sprintf_test15
+c_runtime/sprintf/test16/paltest_sprintf_test16
+c_runtime/sprintf/test17/paltest_sprintf_test17
+c_runtime/sprintf/test18/paltest_sprintf_test18
+c_runtime/sprintf/test19/paltest_sprintf_test19
+c_runtime/sprintf/test2/paltest_sprintf_test2
+c_runtime/sprintf/test3/paltest_sprintf_test3
+c_runtime/sprintf/test4/paltest_sprintf_test4
+c_runtime/sprintf/test5/paltest_sprintf_test5
+c_runtime/sprintf/test6/paltest_sprintf_test6
+c_runtime/sprintf/test7/paltest_sprintf_test7
+c_runtime/sprintf/test8/paltest_sprintf_test8
+c_runtime/sprintf/test9/paltest_sprintf_test9
+c_runtime/sqrt/test1/paltest_sqrt_test1
+c_runtime/sscanf/test1/paltest_sscanf_test1
+c_runtime/sscanf/test10/paltest_sscanf_test10
+c_runtime/sscanf/test11/paltest_sscanf_test11
+c_runtime/sscanf/test12/paltest_sscanf_test12
+c_runtime/sscanf/test13/paltest_sscanf_test13
+c_runtime/sscanf/test14/paltest_sscanf_test14
+c_runtime/sscanf/test15/paltest_sscanf_test15
+c_runtime/sscanf/test16/paltest_sscanf_test16
+c_runtime/sscanf/test17/paltest_sscanf_test17
+c_runtime/sscanf/test2/paltest_sscanf_test2
+c_runtime/sscanf/test3/paltest_sscanf_test3
+c_runtime/sscanf/test4/paltest_sscanf_test4
+c_runtime/sscanf/test5/paltest_sscanf_test5
+c_runtime/sscanf/test6/paltest_sscanf_test6
+c_runtime/sscanf/test7/paltest_sscanf_test7
+c_runtime/sscanf/test8/paltest_sscanf_test8
+c_runtime/sscanf/test9/paltest_sscanf_test9
+c_runtime/strcat/test1/paltest_strcat_test1
+c_runtime/strchr/test1/paltest_strchr_test1
+c_runtime/strcmp/test1/paltest_strcmp_test1
+c_runtime/strcpy/test1/paltest_strcpy_test1
+c_runtime/strcspn/test1/paltest_strcspn_test1
+c_runtime/strlen/test1/paltest_strlen_test1
+c_runtime/strncat/test1/paltest_strncat_test1
+c_runtime/strncmp/test1/paltest_strncmp_test1
+c_runtime/strncpy/test1/paltest_strncpy_test1
+c_runtime/strpbrk/test1/paltest_strpbrk_test1
+c_runtime/strrchr/test1/paltest_strrchr_test1
+c_runtime/strspn/test1/paltest_strspn_test1
+c_runtime/strstr/test1/paltest_strstr_test1
+c_runtime/strtod/test1/paltest_strtod_test1
+c_runtime/strtod/test2/paltest_strtod_test2
+c_runtime/strtok/test1/paltest_strtok_test1
+c_runtime/strtoul/test1/paltest_strtoul_test1
+c_runtime/swprintf/test1/paltest_swprintf_test1
+c_runtime/swprintf/test10/paltest_swprintf_test10
+c_runtime/swprintf/test11/paltest_swprintf_test11
+c_runtime/swprintf/test12/paltest_swprintf_test12
+c_runtime/swprintf/test13/paltest_swprintf_test13
+c_runtime/swprintf/test14/paltest_swprintf_test14
+c_runtime/swprintf/test15/paltest_swprintf_test15
+c_runtime/swprintf/test16/paltest_swprintf_test16
+c_runtime/swprintf/test17/paltest_swprintf_test17
+c_runtime/swprintf/test18/paltest_swprintf_test18
+c_runtime/swprintf/test19/paltest_swprintf_test19
+c_runtime/swprintf/test3/paltest_swprintf_test3
+c_runtime/swprintf/test4/paltest_swprintf_test4
+c_runtime/swprintf/test5/paltest_swprintf_test5
+c_runtime/swprintf/test6/paltest_swprintf_test6
+c_runtime/swprintf/test8/paltest_swprintf_test8
+c_runtime/swprintf/test9/paltest_swprintf_test9
+c_runtime/swscanf/test1/paltest_swscanf_test1
+c_runtime/swscanf/test10/paltest_swscanf_test10
+c_runtime/swscanf/test11/paltest_swscanf_test11
+c_runtime/swscanf/test12/paltest_swscanf_test12
+c_runtime/swscanf/test13/paltest_swscanf_test13
+c_runtime/swscanf/test14/paltest_swscanf_test14
+c_runtime/swscanf/test15/paltest_swscanf_test15
+c_runtime/swscanf/test16/paltest_swscanf_test16
+c_runtime/swscanf/test17/paltest_swscanf_test17
+c_runtime/swscanf/test2/paltest_swscanf_test2
+c_runtime/swscanf/test3/paltest_swscanf_test3
+c_runtime/swscanf/test4/paltest_swscanf_test4
+c_runtime/swscanf/test5/paltest_swscanf_test5
+c_runtime/swscanf/test6/paltest_swscanf_test6
+c_runtime/swscanf/test7/paltest_swscanf_test7
+c_runtime/swscanf/test8/paltest_swscanf_test8
+c_runtime/swscanf/test9/paltest_swscanf_test9
+c_runtime/tan/test1/paltest_tan_test1
+c_runtime/tanh/test1/paltest_tanh_test1
+c_runtime/time/test1/paltest_time_test1
+c_runtime/tolower/test1/paltest_tolower_test1
+c_runtime/toupper/test1/paltest_toupper_test1
+c_runtime/towlower/test1/paltest_towlower_test1
+c_runtime/towupper/test1/paltest_towupper_test1
+c_runtime/ungetc/test1/paltest_ungetc_test1
+c_runtime/vfprintf/test1/paltest_vfprintf_test1
+c_runtime/vfprintf/test10/paltest_vfprintf_test10
+c_runtime/vfprintf/test11/paltest_vfprintf_test11
+c_runtime/vfprintf/test12/paltest_vfprintf_test12
+c_runtime/vfprintf/test13/paltest_vfprintf_test13
+c_runtime/vfprintf/test14/paltest_vfprintf_test14
+c_runtime/vfprintf/test15/paltest_vfprintf_test15
+c_runtime/vfprintf/test16/paltest_vfprintf_test16
+c_runtime/vfprintf/test17/paltest_vfprintf_test17
+c_runtime/vfprintf/test18/paltest_vfprintf_test18
+c_runtime/vfprintf/test19/paltest_vfprintf_test19
+c_runtime/vfprintf/test2/paltest_vfprintf_test2
+c_runtime/vfprintf/test3/paltest_vfprintf_test3
+c_runtime/vfprintf/test4/paltest_vfprintf_test4
+c_runtime/vfprintf/test5/paltest_vfprintf_test5
+c_runtime/vfprintf/test6/paltest_vfprintf_test6
+c_runtime/vfprintf/test7/paltest_vfprintf_test7
+c_runtime/vfprintf/test8/paltest_vfprintf_test8
+c_runtime/vfprintf/test9/paltest_vfprintf_test9
+c_runtime/vprintf/test10/paltest_vprintf_test10
+c_runtime/vprintf/test11/paltest_vprintf_test11
+c_runtime/vprintf/test12/paltest_vprintf_test12
+c_runtime/vprintf/test13/paltest_vprintf_test13
+c_runtime/vprintf/test14/paltest_vprintf_test14
+c_runtime/vprintf/test15/paltest_vprintf_test15
+c_runtime/vprintf/test16/paltest_vprintf_test16
+c_runtime/vprintf/test17/paltest_vprintf_test17
+c_runtime/vprintf/test18/paltest_vprintf_test18
+c_runtime/vprintf/test19/paltest_vprintf_test19
+c_runtime/vprintf/test2/paltest_vprintf_test2
+c_runtime/vprintf/test3/paltest_vprintf_test3
+c_runtime/vprintf/test4/paltest_vprintf_test4
+c_runtime/vprintf/test5/paltest_vprintf_test5
+c_runtime/vprintf/test6/paltest_vprintf_test6
+c_runtime/vprintf/test7/paltest_vprintf_test7
+c_runtime/vprintf/test8/paltest_vprintf_test8
+c_runtime/vprintf/test9/paltest_vprintf_test9
+c_runtime/vsprintf/test1/paltest_vsprintf_test1
+c_runtime/vsprintf/test10/paltest_vsprintf_test10
+c_runtime/vsprintf/test11/paltest_vsprintf_test11
+c_runtime/vsprintf/test12/paltest_vsprintf_test12
+c_runtime/vsprintf/test13/paltest_vsprintf_test13
+c_runtime/vsprintf/test14/paltest_vsprintf_test14
+c_runtime/vsprintf/test15/paltest_vsprintf_test15
+c_runtime/vsprintf/test16/paltest_vsprintf_test16
+c_runtime/vsprintf/test17/paltest_vsprintf_test17
+c_runtime/vsprintf/test18/paltest_vsprintf_test18
+c_runtime/vsprintf/test19/paltest_vsprintf_test19
+c_runtime/vsprintf/test2/paltest_vsprintf_test2
+c_runtime/vsprintf/test3/paltest_vsprintf_test3
+c_runtime/vsprintf/test4/paltest_vsprintf_test4
+c_runtime/vsprintf/test5/paltest_vsprintf_test5
+c_runtime/vsprintf/test6/paltest_vsprintf_test6
+c_runtime/vsprintf/test7/paltest_vsprintf_test7
+c_runtime/vsprintf/test8/paltest_vsprintf_test8
+c_runtime/vsprintf/test9/paltest_vsprintf_test9
+c_runtime/vswprintf/test1/paltest_vswprintf_test1
+c_runtime/vswprintf/test10/paltest_vswprintf_test10
+c_runtime/vswprintf/test11/paltest_vswprintf_test11
+c_runtime/vswprintf/test12/paltest_vswprintf_test12
+c_runtime/vswprintf/test13/paltest_vswprintf_test13
+c_runtime/vswprintf/test14/paltest_vswprintf_test14
+c_runtime/vswprintf/test15/paltest_vswprintf_test15
+c_runtime/vswprintf/test16/paltest_vswprintf_test16
+c_runtime/vswprintf/test17/paltest_vswprintf_test17
+c_runtime/vswprintf/test18/paltest_vswprintf_test18
+c_runtime/vswprintf/test19/paltest_vswprintf_test19
+c_runtime/vswprintf/test3/paltest_vswprintf_test3
+c_runtime/vswprintf/test4/paltest_vswprintf_test4
+c_runtime/vswprintf/test5/paltest_vswprintf_test5
+c_runtime/vswprintf/test6/paltest_vswprintf_test6
+c_runtime/vswprintf/test8/paltest_vswprintf_test8
+c_runtime/vswprintf/test9/paltest_vswprintf_test9
+c_runtime/wcscat/test1/paltest_wcscat_test1
+c_runtime/wcschr/test1/paltest_wcschr_test1
+c_runtime/wcscmp/test1/paltest_wcscmp_test1
+c_runtime/wcscpy/test1/paltest_wcscpy_test1
+c_runtime/wcslen/test1/paltest_wcslen_test1
+c_runtime/wcsncat/test1/paltest_wcsncat_test1
+c_runtime/wcsncmp/test1/paltest_wcsncmp_test1
+c_runtime/wcsncpy/test1/paltest_wcsncpy_test1
+c_runtime/wcspbrk/test1/paltest_wcspbrk_test1
+c_runtime/wcsrchr/test1/paltest_wcsrchr_test1
+c_runtime/wcsstr/test1/paltest_wcsstr_test1
+c_runtime/wcstod/test1/paltest_wcstod_test1
+c_runtime/wcstod/test2/paltest_wcstod_test2
+c_runtime/wcstok/test1/paltest_wcstok_test1
+c_runtime/wcstol/test1/paltest_wcstol_test1
+c_runtime/wcstol/test2/paltest_wcstol_test2
+c_runtime/wcstol/test3/paltest_wcstol_test3
+c_runtime/wcstol/test4/paltest_wcstol_test4
+c_runtime/wcstol/test5/paltest_wcstol_test5
+c_runtime/wcstol/test6/paltest_wcstol_test6
+c_runtime/wcstoul/test1/paltest_wcstoul_test1
+c_runtime/wcstoul/test2/paltest_wcstoul_test2
+c_runtime/wcstoul/test3/paltest_wcstoul_test3
+c_runtime/wcstoul/test4/paltest_wcstoul_test4
+c_runtime/wcstoul/test5/paltest_wcstoul_test5
+c_runtime/wcstoul/test6/paltest_wcstoul_test6
+c_runtime/wprintf/test1/paltest_wprintf_test1
+c_runtime/_alloca/test1/paltest_alloca_test1
+c_runtime/_fdopen/test1/paltest_fdopen_test1
+c_runtime/_finite/test1/paltest_finite_test1
+c_runtime/_fullpath/test1/paltest_fullpath_test1
+c_runtime/_isnan/test1/paltest_isnan_test1
+c_runtime/_itow/test1/paltest_itow_test1
+c_runtime/_makepath/test1/paltest_makepath_test1
+c_runtime/_mbsdec/test1/paltest_mbsdec_test1
+c_runtime/_mbsinc/test1/paltest_mbsinc_test1
+c_runtime/_mbslen/test1/paltest_mbslen_test1
+c_runtime/_mbsninc/test1/paltest_mbsninc_test1
+c_runtime/_open_osfhandle/test1/paltest_open_osfhandle_test1
+c_runtime/_open_osfhandle/test2/paltest_open_osfhandle_test2
+c_runtime/_putenv/test1/paltest_putenv_test1
+c_runtime/_putenv/test2/paltest_putenv_test2
+c_runtime/_putenv/test3/paltest_putenv_test3
+c_runtime/_putenv/test4/paltest_putenv_test4
+c_runtime/_putw/test1/paltest_putw_test1
+c_runtime/_rotl/test1/paltest_rotl_test1
+c_runtime/_rotr/test1/paltest_rotr_test1
+c_runtime/_snprintf/test1/paltest_snprintf_test1
+c_runtime/_snprintf/test10/paltest_snprintf_test10
+c_runtime/_snprintf/test11/paltest_snprintf_test11
+c_runtime/_snprintf/test12/paltest_snprintf_test12
+c_runtime/_snprintf/test13/paltest_snprintf_test13
+c_runtime/_snprintf/test14/paltest_snprintf_test14
+c_runtime/_snprintf/test15/paltest_snprintf_test15
+c_runtime/_snprintf/test16/paltest_snprintf_test16
+c_runtime/_snprintf/test17/paltest_snprintf_test17
+c_runtime/_snprintf/test18/paltest_snprintf_test18
+c_runtime/_snprintf/test19/paltest_snprintf_test19
+c_runtime/_snprintf/test2/paltest_snprintf_test2
+c_runtime/_snprintf/test3/paltest_snprintf_test3
+c_runtime/_snprintf/test4/paltest_snprintf_test4
+c_runtime/_snprintf/test5/paltest_snprintf_test5
+c_runtime/_snprintf/test6/paltest_snprintf_test6
+c_runtime/_snprintf/test7/paltest_snprintf_test7
+c_runtime/_snprintf/test8/paltest_snprintf_test8
+c_runtime/_snprintf/test9/paltest_snprintf_test9
+c_runtime/_snwprintf/test1/paltest_snwprintf_test1
+c_runtime/_snwprintf/test10/paltest_snwprintf_test10
+c_runtime/_snwprintf/test11/paltest_snwprintf_test11
+c_runtime/_snwprintf/test12/paltest_snwprintf_test12
+c_runtime/_snwprintf/test13/paltest_snwprintf_test13
+c_runtime/_snwprintf/test14/paltest_snwprintf_test14
+c_runtime/_snwprintf/test15/paltest_snwprintf_test15
+c_runtime/_snwprintf/test16/paltest_snwprintf_test16
+c_runtime/_snwprintf/test17/paltest_snwprintf_test17
+c_runtime/_snwprintf/test18/paltest_snwprintf_test18
+c_runtime/_snwprintf/test19/paltest_snwprintf_test19
+c_runtime/_snwprintf/test3/paltest_snwprintf_test3
+c_runtime/_snwprintf/test4/paltest_snwprintf_test4
+c_runtime/_snwprintf/test5/paltest_snwprintf_test5
+c_runtime/_snwprintf/test6/paltest_snwprintf_test6
+c_runtime/_snwprintf/test8/paltest_snwprintf_test8
+c_runtime/_snwprintf/test9/paltest_snwprintf_test9
+c_runtime/_splitpath/test1/paltest_splitpath_test1
+c_runtime/_stricmp/test1/paltest_stricmp_test1
+c_runtime/_strlwr/test1/paltest_strlwr_test1
+c_runtime/_strnicmp/test1/paltest_strnicmp_test1
+c_runtime/_swab/test1/paltest_swab_test1
+c_runtime/_vsnprintf/test1/paltest_vsnprintf_test1
+c_runtime/_vsnprintf/test10/paltest_vsnprintf_test10
+c_runtime/_vsnprintf/test11/paltest_vsnprintf_test11
+c_runtime/_vsnprintf/test12/paltest_vsnprintf_test12
+c_runtime/_vsnprintf/test13/paltest_vsnprintf_test13
+c_runtime/_vsnprintf/test14/paltest_vsnprintf_test14
+c_runtime/_vsnprintf/test15/paltest_vsnprintf_test15
+c_runtime/_vsnprintf/test16/paltest_vsnprintf_test16
+c_runtime/_vsnprintf/test17/paltest_vsnprintf_test17
+c_runtime/_vsnprintf/test18/paltest_vsnprintf_test18
+c_runtime/_vsnprintf/test19/paltest_vsnprintf_test19
+c_runtime/_vsnprintf/test2/paltest_vsnprintf_test2
+c_runtime/_vsnprintf/test3/paltest_vsnprintf_test3
+c_runtime/_vsnprintf/test4/paltest_vsnprintf_test4
+c_runtime/_vsnprintf/test5/paltest_vsnprintf_test5
+c_runtime/_vsnprintf/test6/paltest_vsnprintf_test6
+c_runtime/_vsnprintf/test7/paltest_vsnprintf_test7
+c_runtime/_vsnprintf/test8/paltest_vsnprintf_test8
+c_runtime/_vsnprintf/test9/paltest_vsnprintf_test9
+c_runtime/_vsnwprintf/test1/paltest_vsnwprintf_test1
+c_runtime/_vsnwprintf/test10/paltest_vsnwprintf_test10
+c_runtime/_vsnwprintf/test11/paltest_vsnwprintf_test11
+c_runtime/_vsnwprintf/test12/paltest_vsnwprintf_test12
+c_runtime/_vsnwprintf/test13/paltest_vsnwprintf_test13
+c_runtime/_vsnwprintf/test14/paltest_vsnwprintf_test14
+c_runtime/_vsnwprintf/test15/paltest_vsnwprintf_test15
+c_runtime/_vsnwprintf/test16/paltest_vsnwprintf_test16
+c_runtime/_vsnwprintf/test17/paltest_vsnwprintf_test17
+c_runtime/_vsnwprintf/test18/paltest_vsnwprintf_test18
+c_runtime/_vsnwprintf/test19/paltest_vsnwprintf_test19
+c_runtime/_vsnwprintf/test3/paltest_vsnwprintf_test3
+c_runtime/_vsnwprintf/test4/paltest_vsnwprintf_test4
+c_runtime/_vsnwprintf/test5/paltest_vsnwprintf_test5
+c_runtime/_vsnwprintf/test6/paltest_vsnwprintf_test6
+c_runtime/_vsnwprintf/test8/paltest_vsnwprintf_test8
+c_runtime/_vsnwprintf/test9/paltest_vsnwprintf_test9
+c_runtime/_wcsicmp/test1/paltest_wcsicmp_test1
+c_runtime/_wcslwr/test1/paltest_wcslwr_test1
+c_runtime/_wcsnicmp/test1/paltest_wcsnicmp_test1
+c_runtime/_wfopen/test1/paltest_wfopen_test1
+c_runtime/_wfopen/test2/paltest_wfopen_test2
+c_runtime/_wfopen/test3/paltest_wfopen_test3
+c_runtime/_wfopen/test4/paltest_wfopen_test4
+c_runtime/_wfopen/test5/paltest_wfopen_test5
+c_runtime/_wfopen/test6/paltest_wfopen_test6
+c_runtime/_wfopen/test7/paltest_wfopen_test7
+c_runtime/_wsplitpath/test1/paltest_wsplitpath_test1
+c_runtime/_wtoi/test1/paltest_wtoi_test1
+c_runtime/__iscsym/test1/paltest_iscsym_test1
+debug_api/OutputDebugStringW/test1/paltest_outputdebugstringw_test1
+exception_handling/RaiseException/test1/paltest_raiseexception_test1
+exception_handling/RaiseException/test2/paltest_raiseexception_test2
+exception_handling/RaiseException/test3/paltest_raiseexception_test3
+exception_handling/pal_sxs/test1/paltest_pal_sxs_test1
+filemapping_memmgt/CreateFileMappingA/test1/paltest_createfilemappinga_test1
+filemapping_memmgt/CreateFileMappingA/test3/paltest_createfilemappinga_test3
+filemapping_memmgt/CreateFileMappingA/test4/paltest_createfilemappinga_test4
+filemapping_memmgt/CreateFileMappingA/test8/paltest_createfilemappinga_test8
+filemapping_memmgt/CreateFileMappingA/test9/paltest_createfilemappinga_test9
+filemapping_memmgt/CreateFileMappingW/test1/paltest_createfilemappingw_test1
+filemapping_memmgt/CreateFileMappingW/test3/paltest_createfilemappingw_test3
+filemapping_memmgt/CreateFileMappingW/test4/paltest_createfilemappingw_test4
+filemapping_memmgt/CreateFileMappingW/test8/paltest_createfilemappingw_test8
+filemapping_memmgt/CreateFileMappingW/test9/paltest_createfilemappingw_test9
+filemapping_memmgt/FreeLibrary/test2/paltest_freelibrary_test2
+filemapping_memmgt/GetModuleFileNameA/test2/paltest_getmodulefilenamea_test2
+filemapping_memmgt/GetModuleFileNameW/test2/paltest_getmodulefilenamew_test2
+filemapping_memmgt/GetProcessHeap/test1/paltest_getprocessheap_test1
+filemapping_memmgt/HeapAlloc/test1/paltest_heapalloc_test1
+filemapping_memmgt/HeapAlloc/test2/paltest_heapalloc_test2
+filemapping_memmgt/HeapAlloc/test3/paltest_heapalloc_test3
+filemapping_memmgt/HeapFree/test1/paltest_heapfree_test1
+filemapping_memmgt/HeapReAlloc/test1/paltest_heaprealloc_test1
+filemapping_memmgt/HeapReAlloc/test2/paltest_heaprealloc_test2
+filemapping_memmgt/HeapReAlloc/test3/paltest_heaprealloc_test3
+filemapping_memmgt/HeapReAlloc/test4/paltest_heaprealloc_test4
+filemapping_memmgt/HeapReAlloc/test5/paltest_heaprealloc_test5
+filemapping_memmgt/LocalAlloc/test1/paltest_localalloc_test1
+filemapping_memmgt/LocalFree/test1/paltest_localfree_test1
+filemapping_memmgt/LocalFree/test2/paltest_localfree_test2
+filemapping_memmgt/LockFile/test2/paltest_lockfile_test2
+filemapping_memmgt/LockFile/test7/paltest_lockfile_test7
+filemapping_memmgt/MapViewOfFile/test2/paltest_mapviewoffile_test2
+filemapping_memmgt/MapViewOfFile/test3/paltest_mapviewoffile_test3
+filemapping_memmgt/MapViewOfFile/test4/paltest_mapviewoffile_test4
+filemapping_memmgt/MapViewOfFile/test5/paltest_mapviewoffile_test5
+filemapping_memmgt/MapViewOfFile/test6/paltest_mapviewoffile_test6
+filemapping_memmgt/RtlMoveMemory/test1/paltest_rtlmovememory_test1
+filemapping_memmgt/RtlMoveMemory/test3/paltest_rtlmovememory_test3
+filemapping_memmgt/RtlMoveMemory/test4/paltest_rtlmovememory_test4
+filemapping_memmgt/RtlMoveMemory/test5/paltest_rtlmovememory_test5
+filemapping_memmgt/UnlockFile/test2/paltest_unlockfile_test2
+filemapping_memmgt/UnlockFile/test4/paltest_unlockfile_test4
+filemapping_memmgt/UnmapViewOfFile/test1/paltest_unmapviewoffile_test1
+filemapping_memmgt/UnmapViewOfFile/test2/paltest_unmapviewoffile_test2
+filemapping_memmgt/VirtualAlloc/test1/paltest_virtualalloc_test1
+filemapping_memmgt/VirtualAlloc/test10/paltest_virtualalloc_test10
+filemapping_memmgt/VirtualAlloc/test11/paltest_virtualalloc_test11
+filemapping_memmgt/VirtualAlloc/test12/paltest_virtualalloc_test12
+filemapping_memmgt/VirtualAlloc/test13/paltest_virtualalloc_test13
+filemapping_memmgt/VirtualAlloc/test14/paltest_virtualalloc_test14
+filemapping_memmgt/VirtualAlloc/test15/paltest_virtualalloc_test15
+filemapping_memmgt/VirtualAlloc/test16/paltest_virtualalloc_test16
+filemapping_memmgt/VirtualAlloc/test17/paltest_virtualalloc_test17
+filemapping_memmgt/VirtualAlloc/test18/paltest_virtualalloc_test18
+filemapping_memmgt/VirtualAlloc/test19/paltest_virtualalloc_test19
+filemapping_memmgt/VirtualAlloc/test2/paltest_virtualalloc_test2
+filemapping_memmgt/VirtualAlloc/test20/paltest_virtualalloc_test20
+filemapping_memmgt/VirtualAlloc/test21/paltest_virtualalloc_test21
+filemapping_memmgt/VirtualAlloc/test3/paltest_virtualalloc_test3
+filemapping_memmgt/VirtualAlloc/test4/paltest_virtualalloc_test4
+filemapping_memmgt/VirtualAlloc/test5/paltest_virtualalloc_test5
+filemapping_memmgt/VirtualAlloc/test6/paltest_virtualalloc_test6
+filemapping_memmgt/VirtualAlloc/test7/paltest_virtualalloc_test7
+filemapping_memmgt/VirtualAlloc/test8/paltest_virtualalloc_test8
+filemapping_memmgt/VirtualAlloc/test9/paltest_virtualalloc_test9
+filemapping_memmgt/VirtualFree/test1/paltest_virtualfree_test1
+filemapping_memmgt/VirtualFree/test2/paltest_virtualfree_test2
+filemapping_memmgt/VirtualFree/test3/paltest_virtualfree_test3
+filemapping_memmgt/VirtualProtect/test1/paltest_virtualprotect_test1
+filemapping_memmgt/VirtualProtect/test2/paltest_virtualprotect_test2
+filemapping_memmgt/VirtualProtect/test3/paltest_virtualprotect_test3
+filemapping_memmgt/VirtualProtect/test4/paltest_virtualprotect_test4
+filemapping_memmgt/VirtualProtect/test6/paltest_virtualprotect_test6
+filemapping_memmgt/VirtualProtect/test7/paltest_virtualprotect_test7
+filemapping_memmgt/VirtualQuery/test1/paltest_virtualquery_test1
+file_io/AreFileApisANSI/test1/paltest_arefileapisansi_test1
+file_io/CompareFileTime/test1/paltest_comparefiletime_test1
+file_io/CopyFileA/test1/paltest_copyfilea_test1
+file_io/CopyFileA/test2/paltest_copyfilea_test2
+file_io/CopyFileA/test3/paltest_copyfilea_test3
+file_io/CopyFileA/test4/paltest_copyfilea_test4
+file_io/CopyFileW/test2/paltest_copyfilew_test2
+file_io/CopyFileW/test3/paltest_copyfilew_test3
+file_io/CreateDirectoryA/test1/paltest_createdirectorya_test1
+file_io/CreateDirectoryW/test1/paltest_createdirectoryw_test1
+file_io/DeleteFileA/test1/paltest_deletefilea_test1
+file_io/DeleteFileW/test1/paltest_deletefilew_test1
+file_io/errorpathnotfound/test2/paltest_errorpathnotfound_test2
+file_io/errorpathnotfound/test3/paltest_errorpathnotfound_test3
+file_io/FILECanonicalizePath/paltest_filecanonicalizepath_test1
+file_io/FileTimeToDosDateTime/test1/paltest_filetimetodosdatetime_test1
+file_io/FindClose/test1/paltest_findclose_test1
+file_io/FindFirstFileA/test1/paltest_findfirstfilea_test1
+file_io/FindFirstFileW/test1/paltest_findfirstfilew_test1
+file_io/FindNextFileA/test1/paltest_findnextfilea_test1
+file_io/FindNextFileA/test2/paltest_findnextfilea_test2
+file_io/FindNextFileW/test1/paltest_findnextfilew_test1
+file_io/FindNextFileW/test2/paltest_findnextfilew_test2
+file_io/FlushFileBuffers/test1/paltest_flushfilebuffers_test1
+file_io/GetConsoleCP/test1/paltest_getconsolecp_test1
+file_io/GetConsoleOutputCP/test1/paltest_getconsoleoutputcp_test1
+file_io/GetCurrentDirectoryA/test1/paltest_getcurrentdirectorya_test1
+file_io/GetCurrentDirectoryW/test1/paltest_getcurrentdirectoryw_test1
+file_io/GetDiskFreeSpaceW/test1/paltest_getdiskfreespacew_test1
+file_io/GetDiskFreeSpaceW/test2/paltest_getdiskfreespacew_test2
+file_io/GetFileAttributesA/test1/paltest_getfileattributesa_test1
+file_io/GetFileAttributesExW/test2/paltest_getfileattributesexw_test2
+file_io/GetFileAttributesW/test1/paltest_getfileattributesw_test1
+file_io/GetFileSize/test1/paltest_getfilesize_test1
+file_io/GetFileSizeEx/test1/paltest_getfilesizeex_test1
+file_io/GetFileTime/test1/paltest_getfiletime_test1
+file_io/GetFileTime/test2/paltest_getfiletime_test2
+file_io/GetFileTime/test3/paltest_getfiletime_test3
+file_io/GetFileTime/test4/paltest_getfiletime_test4
+file_io/GetFileTime/test5/paltest_getfiletime_test5
+file_io/GetFileTime/test6/paltest_getfiletime_test6
+file_io/GetFileTime/test7/paltest_getfiletime_test7
+file_io/GetFileType/test1/paltest_getfiletype_test1
+file_io/GetFileType/test2/paltest_getfiletype_test2
+file_io/GetFileType/test3/paltest_getfiletype_test3
+file_io/GetFullPathNameA/test1/paltest_getfullpathnamea_test1
+file_io/GetFullPathNameA/test3/paltest_getfullpathnamea_test3
+file_io/GetFullPathNameA/test4/paltest_getfullpathnamea_test4
+file_io/GetFullPathNameW/test1/paltest_getfullpathnamew_test1
+file_io/GetFullPathNameW/test3/paltest_getfullpathnamew_test3
+file_io/GetFullPathNameW/test4/paltest_getfullpathnamew_test4
+file_io/GetLongPathNameW/test1/paltest_getlongpathnamew_test1
+file_io/GetLongPathNameW/test2/paltest_getlongpathnamew_test2
+file_io/GetStdHandle/test2/paltest_getstdhandle_test2
+file_io/GetSystemTime/test1/paltest_getsystemtime_test1
+file_io/GetSystemTimeAsFileTime/test1/paltest_getsystemtimeasfiletime_test1
+file_io/GetTempFileNameA/test1/paltest_gettempfilenamea_test1
+file_io/GetTempFileNameA/test2/paltest_gettempfilenamea_test2
+file_io/GetTempFileNameA/test3/paltest_gettempfilenamea_test3
+file_io/GetTempFileNameW/test3/paltest_gettempfilenamew_test3
+file_io/gettemppatha/test1/paltest_gettemppatha_test1
+file_io/GetTempPathW/test1/paltest_gettemppathw_test1
+file_io/ReadFile/test2/paltest_readfile_test2
+file_io/ReadFile/test3/paltest_readfile_test3
+file_io/ReadFile/test4/paltest_readfile_test4
+file_io/RemoveDirectoryA/test1/paltest_removedirectorya_test1
+file_io/RemoveDirectoryW/test1/paltest_removedirectoryw_test1
+file_io/SearchPathA/test1/paltest_searchpatha_test1
+file_io/SearchPathW/test1/paltest_searchpathw_test1
+file_io/SetCurrentDirectoryA/test1/paltest_setcurrentdirectorya_test1
+file_io/SetCurrentDirectoryA/test2/paltest_setcurrentdirectorya_test2
+file_io/SetCurrentDirectoryA/test3/paltest_setcurrentdirectorya_test3
+file_io/SetCurrentDirectoryW/test1/paltest_setcurrentdirectoryw_test1
+file_io/SetCurrentDirectoryW/test2/paltest_setcurrentdirectoryw_test2
+file_io/SetCurrentDirectoryW/test3/paltest_setcurrentdirectoryw_test3
+file_io/SetEndOfFile/test1/paltest_setendoffile_test1
+file_io/SetEndOfFile/test2/paltest_setendoffile_test2
+file_io/SetEndOfFile/test3/paltest_setendoffile_test3
+file_io/SetEndOfFile/test4/paltest_setendoffile_test4
+file_io/SetEndOfFile/test5/paltest_setendoffile_test5
+file_io/SetFileAttributesA/test2/paltest_setfileattributesa_test2
+file_io/SetFileAttributesA/test3/paltest_setfileattributesa_test3
+file_io/SetFileAttributesW/test2/paltest_setfileattributesw_test2
+file_io/SetFileAttributesW/test3/paltest_setfileattributesw_test3
+file_io/SetFilePointer/test1/paltest_setfilepointer_test1
+file_io/SetFilePointer/test2/paltest_setfilepointer_test2
+file_io/SetFilePointer/test3/paltest_setfilepointer_test3
+file_io/SetFilePointer/test4/paltest_setfilepointer_test4
+file_io/SetFilePointer/test5/paltest_setfilepointer_test5
+file_io/SetFilePointer/test6/paltest_setfilepointer_test6
+file_io/SetFilePointer/test7/paltest_setfilepointer_test7
+file_io/SetFileTime/test1/paltest_setfiletime_test1
+file_io/SetFileTime/test2/paltest_setfiletime_test2
+file_io/SetFileTime/test3/paltest_setfiletime_test3
+file_io/SetFileTime/test4/paltest_setfiletime_test4
+file_io/WriteFile/test1/paltest_writefile_test1
+file_io/WriteFile/test3/paltest_writefile_test3
+file_io/WriteFile/test4/paltest_writefile_test4
+file_io/WriteFile/test5/paltest_writefile_test5
+loader/LoadLibraryA/test2/paltest_loadlibrarya_test2
+loader/LoadLibraryA/test3/paltest_loadlibrarya_test3
+loader/LoadLibraryA/test5/paltest_loadlibrarya_test5
+loader/LoadLibraryW/test2/paltest_loadlibraryw_test2
+loader/LoadLibraryW/test3/paltest_loadlibraryw_test3
+loader/LoadLibraryW/test5/paltest_loadlibraryw_test5
+locale_info/GetACP/test1/paltest_getacp_test1
+locale_info/GetCPInfo/test1/paltest_getcpinfo_test1
+locale_info/GetCPInfo/test3/paltest_getcpinfo_test3
+locale_info/IsDBCSLeadByte/test1/paltest_isdbcsleadbyte_test1
+locale_info/IsDBCSLeadByteEx/test1/paltest_isdbcsleadbyteex_test1
+locale_info/IsValidCodePage/test1/paltest_isvalidcodepage_test1
+locale_info/MultiByteToWideChar/test1/paltest_multibytetowidechar_test1
+locale_info/MultiByteToWideChar/test2/paltest_multibytetowidechar_test2
+locale_info/MultiByteToWideChar/test3/paltest_multibytetowidechar_test3
+locale_info/MultiByteToWideChar/test4/paltest_multibytetowidechar_test4
+locale_info/WideCharToMultiByte/test1/paltest_widechartomultibyte_test1
+locale_info/WideCharToMultiByte/test2/paltest_widechartomultibyte_test2
+locale_info/WideCharToMultiByte/test3/paltest_widechartomultibyte_test3
+locale_info/WideCharToMultiByte/test5/paltest_widechartomultibyte_test5
+miscellaneous/CharNextA/test1/paltest_charnexta_test1
+miscellaneous/CharNextA/test2/paltest_charnexta_test2
+miscellaneous/CharNextExA/test1/paltest_charnextexa_test1
+miscellaneous/CharNextExA/test2/paltest_charnextexa_test2
+miscellaneous/CloseHandle/test1/paltest_closehandle_test1
+miscellaneous/CloseHandle/test2/paltest_closehandle_test2
+miscellaneous/CreatePipe/test1/paltest_createpipe_test1
+miscellaneous/FlushInstructionCache/test1/paltest_flushinstructioncache_test1
+miscellaneous/FormatMessageW/test1/paltest_formatmessagew_test1
+miscellaneous/FormatMessageW/test2/paltest_formatmessagew_test2
+miscellaneous/FormatMessageW/test3/paltest_formatmessagew_test3
+miscellaneous/FreeEnvironmentStringsW/test1/paltest_freeenvironmentstringsw_test1
+miscellaneous/FreeEnvironmentStringsW/test2/paltest_freeenvironmentstringsw_test2
+miscellaneous/GetCommandLineW/test1/paltest_getcommandlinew_test1
+miscellaneous/GetComputerNameW/test1/paltest_getcomputernamew_test1
+miscellaneous/GetEnvironmentStringsW/test1/paltest_getenvironmentstringsw_test1
+miscellaneous/GetEnvironmentVariableA/test1/paltest_getenvironmentvariablea_test1
+miscellaneous/GetEnvironmentVariableA/test2/paltest_getenvironmentvariablea_test2
+miscellaneous/GetEnvironmentVariableA/test3/paltest_getenvironmentvariablea_test3
+miscellaneous/GetEnvironmentVariableA/test4/paltest_getenvironmentvariablea_test4
+miscellaneous/GetEnvironmentVariableA/test5/paltest_getenvironmentvariablea_test5
+miscellaneous/GetEnvironmentVariableA/test6/paltest_getenvironmentvariablea_test6
+miscellaneous/GetEnvironmentVariableW/test1/paltest_getenvironmentvariablew_test1
+miscellaneous/GetEnvironmentVariableW/test2/paltest_getenvironmentvariablew_test2
+miscellaneous/GetEnvironmentVariableW/test3/paltest_getenvironmentvariablew_test3
+miscellaneous/GetEnvironmentVariableW/test4/paltest_getenvironmentvariablew_test4
+miscellaneous/GetEnvironmentVariableW/test5/paltest_getenvironmentvariablew_test5
+miscellaneous/GetEnvironmentVariableW/test6/paltest_getenvironmentvariablew_test6
+miscellaneous/GetLastError/test1/paltest_getlasterror_test1
+miscellaneous/GetSystemInfo/test1/paltest_getsysteminfo_test1
+miscellaneous/GetTickCount/test1/paltest_gettickcount_test1
+miscellaneous/InterlockedCompareExchange/test1/paltest_interlockedcompareexchange_test1
+miscellaneous/InterlockedCompareExchange/test2/paltest_interlockedcompareexchange_test2
+miscellaneous/InterlockedCompareExchange64/test1/paltest_interlockedcompareexchange64_test1
+miscellaneous/InterlockedCompareExchange64/test2/paltest_interlockedcompareexchange64_test2
+miscellaneous/InterlockedCompareExchangePointer/test1/paltest_interlockedcompareexchangepointer_test1
+miscellaneous/InterlockedDecrement/test1/paltest_interlockeddecrement_test1
+miscellaneous/InterlockedDecrement/test2/paltest_interlockeddecrement_test2
+miscellaneous/InterlockedDecrement64/test1/paltest_interlockeddecrement64_test1
+miscellaneous/InterlockedDecrement64/test2/paltest_interlockeddecrement64_test2
+miscellaneous/InterlockedExchange/test1/paltest_interlockedexchange_test1
+miscellaneous/InterlockedExchange64/test1/paltest_interlockedexchange64_test1
+miscellaneous/InterlockedExchangePointer/test1/paltest_interlockedexchangepointer_test1
+miscellaneous/InterlockedIncrement/test1/paltest_interlockedincrement_test1
+miscellaneous/InterlockedIncrement/test2/paltest_interlockedincrement_test2
+miscellaneous/InterlockedIncrement64/test1/paltest_interlockedincrement64_test1
+miscellaneous/InterlockedIncrement64/test2/paltest_interlockedincrement64_test2
+miscellaneous/lstrcatW/test1/paltest_lstrcatw_test1
+miscellaneous/lstrcatW/test2/paltest_lstrcatw_test2
+miscellaneous/lstrcatW/test3/paltest_lstrcatw_test3
+miscellaneous/lstrcatW/test4/paltest_lstrcatw_test4
+miscellaneous/lstrcpynW/test1/paltest_lstrcpynw_test1
+miscellaneous/lstrcpyW/test1/paltest_lstrcpyw_test1
+miscellaneous/lstrlenA/test1/paltest_lstrlena_test1
+miscellaneous/lstrlenW/test1/paltest_lstrlenw_test1
+miscellaneous/queryperformancecounter/test1/paltest_queryperformancecounter_test1
+miscellaneous/queryperformancefrequency/test1/paltest_queryperformancefrequency_test1
+miscellaneous/SetEnvironmentVariableA/test1/paltest_setenvironmentvariablea_test1
+miscellaneous/SetEnvironmentVariableA/test2/paltest_setenvironmentvariablea_test2
+miscellaneous/SetEnvironmentVariableA/test3/paltest_setenvironmentvariablea_test3
+miscellaneous/SetEnvironmentVariableA/test4/paltest_setenvironmentvariablea_test4
+miscellaneous/SetEnvironmentVariableW/test1/paltest_setenvironmentvariablew_test1
+miscellaneous/SetEnvironmentVariableW/test2/paltest_setenvironmentvariablew_test2
+miscellaneous/SetEnvironmentVariableW/test3/paltest_setenvironmentvariablew_test3
+miscellaneous/SetEnvironmentVariableW/test4/paltest_setenvironmentvariablew_test4
+miscellaneous/SetLastError/test1/paltest_setlasterror_test1
+miscellaneous/wsprintfA/test1/paltest_wsprintfa_test1
+miscellaneous/wsprintfA/test11/paltest_wsprintfa_test11
+miscellaneous/wsprintfA/test12/paltest_wsprintfa_test12
+miscellaneous/wsprintfA/test13/paltest_wsprintfa_test13
+miscellaneous/wsprintfA/test2/paltest_wsprintfa_test2
+miscellaneous/wsprintfA/test3/paltest_wsprintfa_test3
+miscellaneous/wsprintfA/test6/paltest_wsprintfa_test6
+miscellaneous/wsprintfA/test7/paltest_wsprintfa_test7
+miscellaneous/wsprintfA/test8/paltest_wsprintfa_test8
+miscellaneous/wsprintfA/test9/paltest_wsprintfa_test9
+miscellaneous/wsprintfW/test1/paltest_wsprintfw_test1
+miscellaneous/wsprintfW/test11/paltest_wsprintfw_test11
+miscellaneous/wsprintfW/test12/paltest_wsprintfw_test12
+miscellaneous/wsprintfW/test13/paltest_wsprintfw_test13
+miscellaneous/wsprintfW/test3/paltest_wsprintfw_test3
+miscellaneous/wsprintfW/test6/paltest_wsprintfw_test6
+miscellaneous/wsprintfW/test8/paltest_wsprintfw_test8
+miscellaneous/wsprintfW/test9/paltest_wsprintfw_test9
+miscellaneous/_i64tow/test1/paltest_i64tow_test1
+miscellaneous/_ui64tow/test1/paltest_ui64tow_test1
+miscellaneous/_ui64tow/test2/paltest_ui64tow_test2
+pal_specific/pal_entrypoint/test1/paltest_pal_entrypoint_test1
+pal_specific/PAL_errno/test1/paltest_pal_errno_test1
+pal_specific/pal_initializedebug/test1/paltest_pal_initializedebug_test1
+pal_specific/PAL_Initialize_Terminate/test1/paltest_pal_initialize_terminate_test1
+pal_specific/PAL_Initialize_Terminate/test2/paltest_pal_initialize_terminate_test2
+samples/test1/paltest_samples_test1
+threading/CreateEventA/test1/paltest_createeventa_test1
+threading/CreateEventA/test2/paltest_createeventa_test2
+threading/CreateEventW/test1/paltest_createeventw_test1
+threading/CreateEventW/test2/paltest_createeventw_test2
+threading/CreateMutexA_ReleaseMutex/test1/paltest_createmutexa_releasemutex_test1
+threading/CreateMutexW_ReleaseMutex/test1/paltest_createmutexw_releasemutex_test1
+threading/CreateProcessA/test1/paltest_createprocessa_test1
+threading/CreateProcessA/test2/paltest_createprocessa_test2
+threading/CreateProcessW/test1/paltest_createprocessw_test1
+threading/CreateProcessW/test2/paltest_createprocessw_test2
+threading/CreateSemaphoreA_ReleaseSemaphore/test1/paltest_createsemaphorea_releasesemaphore_test1
+threading/CreateSemaphoreA_ReleaseSemaphore/test2/paltest_createsemaphorea_releasesemaphore_test2
+threading/CreateSemaphoreW_ReleaseSemaphore/test1/paltest_createsemaphorew_releasesemaphore_test1
+threading/CreateSemaphoreW_ReleaseSemaphore/test2/paltest_createsemaphorew_releasesemaphore_test2
+threading/CreateThread/test1/paltest_createthread_test1
+threading/CreateThread/test3/paltest_createthread_test3
+threading/CriticalSectionFunctions/test1/paltest_criticalsectionfunctions_test1
+threading/CriticalSectionFunctions/test2/paltest_criticalsectionfunctions_test2
+threading/CriticalSectionFunctions/test3/paltest_criticalsectionfunctions_test3
+threading/CriticalSectionFunctions/test4/paltest_criticalsectionfunctions_test4
+threading/CriticalSectionFunctions/test7/paltest_criticalsectionfunctions_test7
+threading/CriticalSectionFunctions/test8/paltest_criticalsectionfunctions_test8
+threading/DuplicateHandle/test10/paltest_duplicatehandle_test10
+threading/DuplicateHandle/test2/paltest_duplicatehandle_test2
+threading/DuplicateHandle/test4/paltest_duplicatehandle_test4
+threading/DuplicateHandle/test5/paltest_duplicatehandle_test5
+threading/DuplicateHandle/test6/paltest_duplicatehandle_test6
+threading/DuplicateHandle/test7/paltest_duplicatehandle_test7
+threading/DuplicateHandle/test8/paltest_duplicatehandle_test8
+threading/ExitProcess/test1/paltest_exitprocess_test1
+threading/ExitProcess/test2/paltest_exitprocess_test2
+threading/ExitProcess/test3/paltest_exitprocess_test3
+threading/ExitThread/test1/paltest_exitthread_test1
+threading/GetCurrentProcessId/test1/paltest_getcurrentprocessid_test1
+threading/GetCurrentThread/test1/paltest_getcurrentthread_test1
+threading/GetCurrentThread/test2/paltest_getcurrentthread_test2
+threading/GetProcessTimes/test2/paltest_getprocesstimes_test2
+threading/GetThreadTimes/test1/paltest_getthreadtimes_test1
+threading/NamedMutex/test1/paltest_namedmutex_test1
+threading/QueryThreadCycleTime/test1/paltest_querythreadcycletime_test1
+threading/QueueUserAPC/test2/paltest_queueuserapc_test2
+threading/QueueUserAPC/test3/paltest_queueuserapc_test3
+threading/QueueUserAPC/test4/paltest_queueuserapc_test4
+threading/QueueUserAPC/test5/paltest_queueuserapc_test5
+threading/QueueUserAPC/test6/paltest_queueuserapc_test6
+threading/QueueUserAPC/test7/paltest_queueuserapc_test7
+threading/ReleaseMutex/test3/paltest_releasemutex_test3
+threading/releasesemaphore/test1/paltest_releasesemaphore_test1
+threading/ResetEvent/test1/paltest_resetevent_test1
+threading/ResetEvent/test2/paltest_resetevent_test2
+threading/ResetEvent/test3/paltest_resetevent_test3
+threading/ResetEvent/test4/paltest_resetevent_test4
+threading/ResumeThread/test1/paltest_resumethread_test1
+threading/SetErrorMode/test1/paltest_seterrormode_test1
+threading/SetEvent/test1/paltest_setevent_test1
+threading/SetEvent/test2/paltest_setevent_test2
+threading/SetEvent/test3/paltest_setevent_test3
+threading/SetEvent/test4/paltest_setevent_test4
+threading/Sleep/test1/paltest_sleep_test1
+threading/SleepEx/test1/paltest_sleepex_test1
+threading/SleepEx/test2/paltest_sleepex_test2
+threading/SwitchToThread/test1/paltest_switchtothread_test1
+threading/ThreadPriority/test1/paltest_threadpriority_test1
+threading/TLS/test1/paltest_tls_test1
+threading/TLS/test2/paltest_tls_test2
+threading/TLS/test3/paltest_tls_test3
+threading/TLS/test4/paltest_tls_test4
+threading/TLS/test5/paltest_tls_test5
+threading/WaitForMultipleObjects/test1/paltest_waitformultipleobjects_test1
+threading/WaitForMultipleObjectsEx/test1/paltest_waitformultipleobjectsex_test1
+threading/WaitForMultipleObjectsEx/test2/paltest_waitformultipleobjectsex_test2
+threading/WaitForMultipleObjectsEx/test3/paltest_waitformultipleobjectsex_test3
+threading/WaitForMultipleObjectsEx/test4/paltest_waitformultipleobjectsex_test4
+threading/WaitForSingleObject/test1/paltest_waitforsingleobject_test1
+threading/WaitForSingleObject/WFSOExMutexTest/paltest_waitforsingleobject_wfsoexmutextest
+threading/WaitForSingleObject/WFSOExSemaphoreTest/paltest_waitforsingleobject_wfsoexsemaphoretest
+threading/WaitForSingleObject/WFSOExThreadTest/paltest_waitforsingleobject_wfsoexthreadtest
+threading/WaitForSingleObject/WFSOMutexTest/paltest_waitforsingleobject_wfsomutextest
+threading/WaitForSingleObject/WFSOSemaphoreTest/paltest_waitforsingleobject_wfsosemaphoretest
+threading/WaitForSingleObject/WFSOThreadTest/paltest_waitforsingleobject_wfsothreadtest
+threading/YieldProcessor/test1/paltest_yieldprocessor_test1
+eventprovider/eventprovidertest
diff --git a/src/pal/tests/palsuite/paltestlist_to_be_reviewed.txt b/src/pal/tests/palsuite/paltestlist_to_be_reviewed.txt
new file mode 100644
index 0000000000..ac0a2ee4eb
--- /dev/null
+++ b/src/pal/tests/palsuite/paltestlist_to_be_reviewed.txt
@@ -0,0 +1,201 @@
+This is a list of failing PAL tests that need to be reviewed because.
+They should either be fixed or deleted if they are no longer applicable.
+
+c_runtime/ctime/test1/paltest_ctime_test1
+c_runtime/exit/test2/paltest_exit_test2
+c_runtime/feof/test1/paltest_feof_test1
+c_runtime/ferror/test1/paltest_ferror_test1
+c_runtime/ferror/test2/paltest_ferror_test2
+c_runtime/fputs/test2/paltest_fputs_test2
+c_runtime/fread/test1/paltest_fread_test1
+c_runtime/fread/test2/paltest_fread_test2
+c_runtime/fread/test3/paltest_fread_test3
+c_runtime/ftell/test1/paltest_ftell_test1
+c_runtime/fwprintf/test19/paltest_fwprintf_test19
+c_runtime/fwprintf/test2/paltest_fwprintf_test2
+c_runtime/fwprintf/test7/paltest_fwprintf_test7
+c_runtime/iswprint/test1/paltest_iswprint_test1
+c_runtime/swprintf/test2/paltest_swprintf_test2
+c_runtime/swprintf/test7/paltest_swprintf_test7
+c_runtime/ungetc/test2/paltest_ungetc_test2
+c_runtime/vprintf/test1/paltest_vprintf_test1
+c_runtime/vswprintf/test2/paltest_vswprintf_test2
+c_runtime/vswprintf/test7/paltest_vswprintf_test7
+c_runtime/wprintf/test2/paltest_wprintf_test2
+c_runtime/_ecvt/test1/paltest_ecvt_test1
+c_runtime/_gcvt/test1/paltest_gcvt_test1
+c_runtime/_gcvt/test2/paltest_gcvt_test2
+c_runtime/_getw/test1/paltest_getw_test1
+c_runtime/_snwprintf/test2/paltest_snwprintf_test2
+c_runtime/_snwprintf/test7/paltest_snwprintf_test7
+c_runtime/_vsnwprintf/test2/paltest_vsnwprintf_test2
+c_runtime/_vsnwprintf/test7/paltest_vsnwprintf_test7
+c_runtime/_wmakepath/test1/paltest_wmakepath_test1
+debug_api/DebugBreak/test1/paltest_debugbreak_test1
+debug_api/OutputDebugStringA/test1/paltest_outputdebugstringa_test1
+debug_api/WriteProcessMemory/test1/paltest_writeprocessmemory_test1
+debug_api/WriteProcessMemory/test3/paltest_writeprocessmemory_test3
+debug_api/WriteProcessMemory/test4/paltest_writeprocessmemory_test4
+exception_handling/pal_except/test1/paltest_pal_except_test1
+exception_handling/pal_except/test2/paltest_pal_except_test2
+exception_handling/pal_except/test3/paltest_pal_except_test3
+exception_handling/pal_except/test4/paltest_pal_except_test4
+exception_handling/pal_except/test5/paltest_pal_except_test5
+exception_handling/pal_except/test6/paltest_pal_except_test6
+exception_handling/pal_except/test7/paltest_pal_except_test7
+exception_handling/PAL_EXCEPT_FILTER/test1/paltest_pal_except_filter_test1
+exception_handling/PAL_EXCEPT_FILTER/test2/paltest_pal_except_filter_test2
+exception_handling/PAL_EXCEPT_FILTER/test3/paltest_pal_except_filter_test3
+exception_handling/PAL_EXCEPT_FILTER_EX/test1/paltest_pal_except_filter_ex_test1
+exception_handling/PAL_EXCEPT_FILTER_EX/test2/paltest_pal_except_filter_ex_test2
+exception_handling/PAL_EXCEPT_FILTER_EX/test3/paltest_pal_except_filter_ex_test3
+exception_handling/pal_finally/test1/paltest_pal_finally_test1
+exception_handling/PAL_GetBottommostRegistration/test1/paltest_pal_getbottommostregistration_test1
+exception_handling/PAL_GetBottommostRegistration/test2/paltest_pal_getbottommostregistration_test2
+exception_handling/PAL_TRY_EXCEPT/test1/paltest_pal_try_except_test1
+exception_handling/PAL_TRY_EXCEPT/test2/paltest_pal_try_except_test2
+exception_handling/PAL_TRY_EXCEPT_EX/test1/paltest_pal_try_except_ex_test1
+exception_handling/PAL_TRY_EXCEPT_EX/test2/paltest_pal_try_except_ex_test2
+exception_handling/PAL_TRY_EXCEPT_EX/test3/paltest_pal_try_except_ex_test3
+exception_handling/PAL_TRY_LEAVE_FINALLY/test1/paltest_pal_try_leave_finally_test1
+exception_handling/SetUnhandledExceptionFilter/test1/paltest_setunhandledexceptionfilter_test1
+filemapping_memmgt/CreateFileMappingA/test5/paltest_createfilemappinga_test5
+filemapping_memmgt/CreateFileMappingA/test6/paltest_createfilemappinga_test6
+filemapping_memmgt/CreateFileMappingA/test7/paltest_createfilemappinga_test7
+filemapping_memmgt/CreateFileMappingW/CreateFileMapping_neg1/paltest_createfilemappingw_createfilemapping_neg1
+filemapping_memmgt/CreateFileMappingW/test2/paltest_createfilemappingw_test2
+filemapping_memmgt/CreateFileMappingW/test5/paltest_createfilemappingw_test5
+filemapping_memmgt/CreateFileMappingW/test6/paltest_createfilemappingw_test6
+filemapping_memmgt/CreateFileMappingW/test7/paltest_createfilemappingw_test7
+filemapping_memmgt/FreeLibrary/test1/paltest_freelibrary_test1
+filemapping_memmgt/FreeLibraryAndExitThread/test1/paltest_freelibraryandexitthread_test1
+filemapping_memmgt/GetModuleFileNameA/test1/paltest_getmodulefilenamea_test1
+filemapping_memmgt/GetModuleFileNameW/test1/paltest_getmodulefilenamew_test1
+filemapping_memmgt/GetProcAddress/test1/paltest_getprocaddress_test1
+filemapping_memmgt/GetProcAddress/test2/paltest_getprocaddress_test2
+filemapping_memmgt/LockFile/test1/paltest_lockfile_test1
+filemapping_memmgt/LockFile/test3/paltest_lockfile_test3
+filemapping_memmgt/LockFile/test4/paltest_lockfile_test4
+filemapping_memmgt/LockFile/test5/paltest_lockfile_test5
+filemapping_memmgt/LockFile/test6/paltest_lockfile_test6
+filemapping_memmgt/OpenFileMappingA/test1/paltest_openfilemappinga_test1
+filemapping_memmgt/OpenFileMappingA/test2/paltest_openfilemappinga_test2
+filemapping_memmgt/OpenFileMappingA/test3/paltest_openfilemappinga_test3
+filemapping_memmgt/OpenFileMappingW/test1/paltest_openfilemappingw_test1
+filemapping_memmgt/OpenFileMappingW/test2/paltest_openfilemappingw_test2
+filemapping_memmgt/OpenFileMappingW/test3/paltest_openfilemappingw_test3
+filemapping_memmgt/ReadProcessMemory/ReadProcessMemory_neg1/paltest_readprocessmemory_readprocessmemory_neg1
+filemapping_memmgt/ReadProcessMemory/test1/paltest_readprocessmemory_test1
+filemapping_memmgt/ReadProcessMemory/test2/paltest_readprocessmemory_test2
+filemapping_memmgt/UnlockFile/test1/paltest_unlockfile_test1
+filemapping_memmgt/UnlockFile/test3/paltest_unlockfile_test3
+file_io/CopyFileW/test1/paltest_copyfilew_test1
+file_io/CreateDirectoryA/test2/paltest_createdirectorya_test2
+file_io/CreateDirectoryW/test2/paltest_createdirectoryw_test2
+file_io/CreateFileA/test1/paltest_createfilea_test1
+file_io/CreateFileW/test1/paltest_createfilew_test1
+file_io/errorpathnotfound/test1/paltest_errorpathnotfound_test1
+file_io/errorpathnotfound/test4/paltest_errorpathnotfound_test4
+file_io/GetFileAttributesExW/test1/paltest_getfileattributesexw_test1
+file_io/GetFullPathNameA/test2/paltest_getfullpathnamea_test2
+file_io/GetFullPathNameW/test2/paltest_getfullpathnamew_test2
+file_io/GetStdHandle/test1/paltest_getstdhandle_test1
+file_io/GetTempFileNameW/test1/paltest_gettempfilenamew_test1
+file_io/GetTempFileNameW/test2/paltest_gettempfilenamew_test2
+file_io/gettemppatha/test1/paltest_gettemppatha_test1
+file_io/GetTempPathW/test1/paltest_gettemppathw_test1
+file_io/MoveFileA/test1/paltest_movefilea_test1
+file_io/MoveFileExA/test1/paltest_movefileexa_test1
+file_io/MoveFileExW/test1/paltest_movefileexw_test1
+file_io/MoveFileW/test1/paltest_movefilew_test1
+file_io/ReadFile/test1/paltest_readfile_test1
+file_io/SetFileAttributesA/test1/paltest_setfileattributesa_test1
+file_io/SetFileAttributesA/test4/paltest_setfileattributesa_test4
+file_io/SetFileAttributesW/test1/paltest_setfileattributesw_test1
+file_io/SetFileAttributesW/test4/paltest_setfileattributesw_test4
+file_io/WriteFile/test2/paltest_writefile_test2
+loader/LoadLibraryA/test1/paltest_loadlibrarya_test1
+loader/LoadLibraryA/test6/paltest_loadlibrarya_test6
+loader/LoadLibraryA/test7/paltest_loadlibrarya_test7
+loader/LoadLibraryA/test8/paltest_loadlibrarya_test8
+loader/LoadLibraryW/test1/paltest_loadlibraryw_test1
+locale_info/CompareStringA/test1/paltest_comparestringa_test1
+locale_info/CompareStringW/test1/paltest_comparestringw_test1
+locale_info/GetCPInfo/test2/paltest_getcpinfo_test2
+locale_info/GetLocaleInfoW/test1/paltest_getlocaleinfow_test1
+locale_info/GetLocaleInfoW/test2/paltest_getlocaleinfow_test2
+locale_info/GetStringTypeExW/test1/paltest_getstringtypeexw_test1
+locale_info/GetStringTypeExW/test2/paltest_getstringtypeexw_test2
+locale_info/GetSystemDefaultLangID/test1/paltest_getsystemdefaultlangid_test1
+locale_info/GetThreadLocale/test1/paltest_getthreadlocale_test1
+locale_info/GetTimeZoneInformation/test1/paltest_gettimezoneinformation_test1
+locale_info/GetUserDefaultLangID/test1/paltest_getuserdefaultlangid_test1
+locale_info/GetUserDefaultLCID/test1/paltest_getuserdefaultlcid_test1
+locale_info/IsValidCodePage/test2/paltest_isvalidcodepage_test2
+locale_info/IsValidLocale/test1/paltest_isvalidlocale_test1
+locale_info/SetThreadLocale/test1/paltest_setthreadlocale_test1
+locale_info/WideCharToMultiByte/test4/paltest_widechartomultibyte_test4
+miscellaneous/FormatMessageW/test4/paltest_formatmessagew_test4
+miscellaneous/FormatMessageW/test5/paltest_formatmessagew_test5
+miscellaneous/FormatMessageW/test6/paltest_formatmessagew_test6
+miscellaneous/GetCalendarInfoW/test1/paltest_getcalendarinfow_test1
+miscellaneous/GetCalendarInfoW/test2/paltest_getcalendarinfow_test2
+miscellaneous/GetComputerNameW/test1/paltest_getcomputernamew_test1
+miscellaneous/GetDateFormatW/GetDateFormatW_neg1/paltest_getdateformatw_getdateformatw_neg1
+miscellaneous/GetDateFormatW/GetDateFormatW_neg2/paltest_getdateformatw_getdateformatw_neg2
+miscellaneous/GetDateFormatW/test1/paltest_getdateformatw_test1
+miscellaneous/GetUserNameW/test1/paltest_getusernamew_test1
+miscellaneous/GetVersionExA/test1/paltest_getversionexa_test1
+miscellaneous/GetVersionExW/test1/paltest_getversionexw_test1
+miscellaneous/InterLockedExchangeAdd/test1/paltest_interlockedexchangeadd_test1
+miscellaneous/IsBadCodePtr/test1/paltest_isbadcodeptr_test1
+miscellaneous/IsBadReadPtr/test1/paltest_isbadreadptr_test1
+miscellaneous/IsBadWritePtr/test1/paltest_isbadwriteptr_test1
+miscellaneous/IsBadWritePtr/test2/paltest_isbadwriteptr_test2
+miscellaneous/IsBadWritePtr/test3/paltest_isbadwriteptr_test3
+miscellaneous/MessageBoxW/test1/paltest_messageboxw_test1
+miscellaneous/MessageBoxW/test2/paltest_messageboxw_test2
+miscellaneous/wsprintfW/test2/paltest_wsprintfw_test2
+miscellaneous/wsprintfW/test7/paltest_wsprintfw_test7
+pal_specific/PAL_GetMachineConfigurationDirectoryW/test1/paltest_pal_getmachineconfigurationdirectoryw_test1
+pal_specific/PAL_GetPALDirectoryW/test1/paltest_pal_getpaldirectoryw_test1
+pal_specific/PAL_GetUserConfigurationDirectoryW/test1/paltest_pal_getuserconfigurationdirectoryw_test1
+pal_specific/PAL_GetUserTempDirectoryW/test1/paltest_pal_getusertempdirectoryw_test1
+pal_specific/PAL_get_stderr/test1/paltest_pal_get_stderr_test1
+pal_specific/PAL_get_stdin/test1/paltest_pal_get_stdin_test1
+pal_specific/PAL_get_stdout/test1/paltest_pal_get_stdout_test1
+pal_specific/PAL_RegisterLibraryW_UnregisterLibraryW/test1/paltest_pal_registerlibraryw_unregisterlibraryw_test1
+samples/test2/paltest_samples_test2
+threading/CreateEventA/test3/paltest_createeventa_test3
+threading/CreateEventW/test3/paltest_createeventw_test3
+threading/CreateMutexA_ReleaseMutex/test2/paltest_createmutexa_releasemutex_test2
+threading/CreateMutexW_ReleaseMutex/test2/paltest_createmutexw_releasemutex_test2
+threading/CreateSemaphoreA_ReleaseSemaphore/test3/paltest_createsemaphorea_releasesemaphore_test3
+threading/CreateSemaphoreW_ReleaseSemaphore/test3/paltest_createsemaphorew_releasesemaphore_test3
+threading/CreateThread/test2/paltest_createthread_test2
+threading/CriticalSectionFunctions/test5/paltest_criticalsectionfunctions_test5
+threading/CriticalSectionFunctions/test6/paltest_criticalsectionfunctions_test6
+threading/DuplicateHandle/test1/paltest_duplicatehandle_test1
+threading/DuplicateHandle/test11/paltest_duplicatehandle_test11
+threading/DuplicateHandle/test12/paltest_duplicatehandle_test12
+threading/DuplicateHandle/test3/paltest_duplicatehandle_test3
+threading/DuplicateHandle/test9/paltest_duplicatehandle_test9
+threading/ExitThread/test2/paltest_exitthread_test2
+threading/GetCurrentProcess/test1/paltest_getcurrentprocess_test1
+threading/GetCurrentThreadId/test1/paltest_getcurrentthreadid_test1
+threading/GetExitCodeProcess/test1/paltest_getexitcodeprocess_test1
+threading/OpenEventW/test1/paltest_openeventw_test1
+threading/OpenEventW/test2/paltest_openeventw_test2
+threading/OpenEventW/test3/paltest_openeventw_test3
+threading/OpenEventW/test4/paltest_openeventw_test4
+threading/OpenEventW/test5/paltest_openeventw_test5
+threading/OpenProcess/test1/paltest_openprocess_test1
+threading/QueueUserAPC/test1/paltest_queueuserapc_test1
+threading/setthreadcontext/test1/paltest_setthreadcontext_test1
+threading/SuspendThread/test2/paltest_suspendthread_test2
+threading/SuspendThread/test3/paltest_suspendthread_test3
+threading/TerminateProcess/test1/paltest_terminateprocess_test1
+threading/TLS/test6_optimizedtls/paltest_tls_test6_optimizedtls
+threading/WaitForMultipleObjectsEx/test5/paltest_waitformultipleobjectsex_test5
+threading/WaitForMultipleObjectsEx/test6/paltest_waitformultipleobjectsex_test6
+threading/WaitForSingleObject/WFSOProcessTest/paltest_waitforsingleobject_wfsoprocesstest
diff --git a/src/pal/tests/palsuite/palverify.dat b/src/pal/tests/palsuite/palverify.dat
new file mode 100644
index 0000000000..36b48d66e8
--- /dev/null
+++ b/src/pal/tests/palsuite/palverify.dat
@@ -0,0 +1,889 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+c_runtime/__iscsym/test1,1
+c_runtime/_alloca/test1,1
+c_runtime/_ecvt/test1,1
+c_runtime/_fdopen/test1,1
+c_runtime/_finite/test1,1
+c_runtime/_fullpath/test1,1
+c_runtime/_gcvt/test1,1
+c_runtime/_gcvt/test2,1
+c_runtime/_getw/test1,1
+c_runtime/_isnan/test1,1
+c_runtime/_itow/test1,1
+c_runtime/_makepath/test1,1
+c_runtime/_mbsdec/test1,1
+c_runtime/_mbsinc/test1,1
+c_runtime/_mbslen/test1,1
+c_runtime/_mbsninc/test1,1
+c_runtime/_open_osfhandle/test1,1
+c_runtime/_open_osfhandle/test2,1
+c_runtime/_putenv/test1,1
+c_runtime/_putenv/test2,1
+c_runtime/_putenv/test3,1
+c_runtime/_putenv/test4,1
+c_runtime/_putw/test1,1
+c_runtime/_rotl/test1,1
+c_runtime/_rotr/test1,1
+c_runtime/_snprintf/test1,1
+c_runtime/_snprintf/test2,1
+c_runtime/_snprintf/test3,1
+c_runtime/_snprintf/test4,1
+c_runtime/_snprintf/test5,1
+c_runtime/_snprintf/test6,1
+c_runtime/_snprintf/test7,1
+c_runtime/_snprintf/test8,1
+c_runtime/_snprintf/test9,1
+c_runtime/_snprintf/test10,1
+c_runtime/_snprintf/test11,1
+c_runtime/_snprintf/test12,1
+c_runtime/_snprintf/test13,1
+c_runtime/_snprintf/test14,1
+c_runtime/_snprintf/test15,1
+c_runtime/_snprintf/test16,1
+c_runtime/_snprintf/test17,1
+c_runtime/_snprintf/test18,1
+c_runtime/_snprintf/test19,1
+c_runtime/_snwprintf/test1,1
+c_runtime/_snwprintf/test2,1
+c_runtime/_snwprintf/test3,1
+c_runtime/_snwprintf/test4,1
+c_runtime/_snwprintf/test5,1
+c_runtime/_snwprintf/test6,1
+c_runtime/_snwprintf/test7,1
+c_runtime/_snwprintf/test8,1
+c_runtime/_snwprintf/test9,1
+c_runtime/_snwprintf/test10,1
+c_runtime/_snwprintf/test11,1
+c_runtime/_snwprintf/test12,1
+c_runtime/_snwprintf/test13,1
+c_runtime/_snwprintf/test14,1
+c_runtime/_snwprintf/test15,1
+c_runtime/_snwprintf/test16,1
+c_runtime/_snwprintf/test17,1
+c_runtime/_snwprintf/test18,1
+c_runtime/_snwprintf/test19,1
+c_runtime/_splitpath/test1,1
+c_runtime/_stricmp/test1,1
+c_runtime/_strlwr/test1,1
+c_runtime/_strnicmp/test1,1
+c_runtime/_swab/test1,1
+c_runtime/_vsnprintf/test1,1
+c_runtime/_vsnprintf/test2,1
+c_runtime/_vsnprintf/test3,1
+c_runtime/_vsnprintf/test4,1
+c_runtime/_vsnprintf/test5,1
+c_runtime/_vsnprintf/test6,1
+c_runtime/_vsnprintf/test7,1
+c_runtime/_vsnprintf/test8,1
+c_runtime/_vsnprintf/test9,1
+c_runtime/_vsnprintf/test10,1
+c_runtime/_vsnprintf/test11,1
+c_runtime/_vsnprintf/test12,1
+c_runtime/_vsnprintf/test13,1
+c_runtime/_vsnprintf/test14,1
+c_runtime/_vsnprintf/test15,1
+c_runtime/_vsnprintf/test16,1
+c_runtime/_vsnprintf/test17,1
+c_runtime/_vsnprintf/test18,1
+c_runtime/_vsnprintf/test19,1
+c_runtime/_vsnwprintf/test1,1
+c_runtime/_vsnwprintf/test2,1
+c_runtime/_vsnwprintf/test3,1
+c_runtime/_vsnwprintf/test4,1
+c_runtime/_vsnwprintf/test5,1
+c_runtime/_vsnwprintf/test6,1
+c_runtime/_vsnwprintf/test7,1
+c_runtime/_vsnwprintf/test8,1
+c_runtime/_vsnwprintf/test9,1
+c_runtime/_vsnwprintf/test10,1
+c_runtime/_vsnwprintf/test11,1
+c_runtime/_vsnwprintf/test12,1
+c_runtime/_vsnwprintf/test13,1
+c_runtime/_vsnwprintf/test14,1
+c_runtime/_vsnwprintf/test15,1
+c_runtime/_vsnwprintf/test16,1
+c_runtime/_vsnwprintf/test17,1
+c_runtime/_vsnwprintf/test18,1
+c_runtime/_vsnwprintf/test19,1
+c_runtime/_wcsicmp/test1,1
+c_runtime/_wcslwr/test1,1
+c_runtime/_wcsnicmp/test1,1
+c_runtime/_wfopen/test1,1
+c_runtime/_wfopen/test2,1
+c_runtime/_wfopen/test3,1
+c_runtime/_wfopen/test4,1
+c_runtime/_wfopen/test5,1
+c_runtime/_wfopen/test6,1
+c_runtime/_wfopen/test7,1
+c_runtime/_wmakepath/test1,1
+c_runtime/_wsplitpath/test1,1
+c_runtime/_wtoi/test1,1
+c_runtime/abs/test1,1
+c_runtime/acos/test1,1
+c_runtime/asin/test1,1
+c_runtime/atan/test1,1
+c_runtime/atan2/test1,1
+c_runtime/atof/test1,1
+c_runtime/atoi/test1,1
+c_runtime/atol/test1,1
+c_runtime/bsearch/test1,1
+c_runtime/bsearch/test2,1
+c_runtime/ceil/test1,1
+c_runtime/cos/test1,1
+c_runtime/cosh/test1,1
+c_runtime/ctime/test1,1
+c_runtime/errno/test1,1
+c_runtime/errno/test2,1
+c_runtime/exit/test1,1
+c_runtime/exp/test1,1
+c_runtime/fabs/test1,1
+c_runtime/fabsf/test1,1
+c_runtime/fclose/test1,1
+c_runtime/fclose/test2,1
+c_runtime/feof/test1,1
+c_runtime/ferror/test1,1
+c_runtime/ferror/test2,1
+c_runtime/fflush/test1,1
+c_runtime/fgets/test1,1
+c_runtime/fgets/test2,1
+c_runtime/fgets/test3,1
+c_runtime/floor/test1,1
+c_runtime/fmod/test1,1
+c_runtime/fmodf/test1,1
+c_runtime/fopen/test1,1
+c_runtime/fopen/test2,1
+c_runtime/fopen/test3,1
+c_runtime/fopen/test4,1
+c_runtime/fopen/test5,1
+c_runtime/fopen/test6,1
+c_runtime/fopen/test7,1
+c_runtime/fprintf/test1,1
+c_runtime/fprintf/test2,1
+c_runtime/fprintf/test3,1
+c_runtime/fprintf/test4,1
+c_runtime/fprintf/test5,1
+c_runtime/fprintf/test6,1
+c_runtime/fprintf/test7,1
+c_runtime/fprintf/test8,1
+c_runtime/fprintf/test9,1
+c_runtime/fprintf/test10,1
+c_runtime/fprintf/test11,1
+c_runtime/fprintf/test12,1
+c_runtime/fprintf/test13,1
+c_runtime/fprintf/test14,1
+c_runtime/fprintf/test15,1
+c_runtime/fprintf/test16,1
+c_runtime/fprintf/test17,1
+c_runtime/fprintf/test18,1
+c_runtime/fprintf/test19,1
+c_runtime/fputs/test1,1
+c_runtime/fputs/test2,1
+c_runtime/fread/test1,1
+c_runtime/fread/test2,1
+c_runtime/fread/test3,1
+c_runtime/free/test1,1
+c_runtime/fseek/test1,1
+c_runtime/ftell/test1,1
+c_runtime/fwprintf/test1,1
+c_runtime/fwprintf/test2,1
+c_runtime/fwprintf/test3,1
+c_runtime/fwprintf/test4,1
+c_runtime/fwprintf/test5,1
+c_runtime/fwprintf/test6,1
+c_runtime/fwprintf/test7,1
+c_runtime/fwprintf/test8,1
+c_runtime/fwprintf/test9,1
+c_runtime/fwprintf/test10,1
+c_runtime/fwprintf/test11,1
+c_runtime/fwprintf/test12,1
+c_runtime/fwprintf/test13,1
+c_runtime/fwprintf/test14,1
+c_runtime/fwprintf/test15,1
+c_runtime/fwprintf/test16,1
+c_runtime/fwprintf/test17,1
+c_runtime/fwprintf/test18,1
+c_runtime/fwprintf/test19,1
+c_runtime/fwrite/test1,1
+c_runtime/getc/test1,1
+c_runtime/getenv/test1,0
+c_runtime/getenv/test2,1
+c_runtime/getenv/test3,1
+c_runtime/isalnum/test1,1
+c_runtime/isalpha/test1,1
+c_runtime/isdigit/test1,1
+c_runtime/islower/test1,1
+c_runtime/isprint/test1,1
+c_runtime/isprint/test2,1
+c_runtime/isspace/test1,1
+c_runtime/isupper/test1,1
+c_runtime/iswdigit/test1,1
+c_runtime/iswprint/test1,1
+c_runtime/iswspace/test1,1
+c_runtime/iswupper/test1,1
+c_runtime/iswxdigit/test1,1
+c_runtime/isxdigit/test1,1
+c_runtime/labs/test1,1
+c_runtime/llabs/test1,1
+c_runtime/localtime/test1,1
+c_runtime/log/test1,1
+c_runtime/log10/test1,1
+c_runtime/malloc/test1,1
+c_runtime/memchr/test1,1
+c_runtime/memcmp/test1,1
+c_runtime/memcpy/test1,1
+c_runtime/memmove/test1,1
+c_runtime/memset/test1,1
+c_runtime/modf/test1,1
+c_runtime/pow/test1,1
+c_runtime/printf/test1,1
+c_runtime/printf/test2,1
+c_runtime/printf/test3,1
+c_runtime/printf/test4,1
+c_runtime/printf/test5,1
+c_runtime/printf/test6,1
+c_runtime/printf/test7,1
+c_runtime/printf/test8,1
+c_runtime/printf/test9,1
+c_runtime/printf/test10,1
+c_runtime/printf/test11,1
+c_runtime/printf/test12,1
+c_runtime/printf/test13,1
+c_runtime/printf/test14,1
+c_runtime/printf/test15,1
+c_runtime/printf/test16,1
+c_runtime/printf/test17,1
+c_runtime/printf/test18,1
+c_runtime/printf/test19,1
+c_runtime/qsort/test1,1
+c_runtime/qsort/test2,1
+c_runtime/rand_srand/test1,1
+c_runtime/realloc/test1,1
+c_runtime/sin/test1,1
+c_runtime/sinh/test1,1
+c_runtime/sprintf/test1,1
+c_runtime/sprintf/test2,1
+c_runtime/sprintf/test3,1
+c_runtime/sprintf/test4,1
+c_runtime/sprintf/test5,1
+c_runtime/sprintf/test6,1
+c_runtime/sprintf/test7,1
+c_runtime/sprintf/test8,1
+c_runtime/sprintf/test9,1
+c_runtime/sprintf/test10,1
+c_runtime/sprintf/test11,1
+c_runtime/sprintf/test12,1
+c_runtime/sprintf/test13,1
+c_runtime/sprintf/test14,1
+c_runtime/sprintf/test15,1
+c_runtime/sprintf/test16,1
+c_runtime/sprintf/test17,1
+c_runtime/sprintf/test18,1
+c_runtime/sprintf/test19,1
+c_runtime/sqrt/test1,1
+c_runtime/sscanf/test1,1
+c_runtime/sscanf/test2,1
+c_runtime/sscanf/test3,1
+c_runtime/sscanf/test4,1
+c_runtime/sscanf/test5,1
+c_runtime/sscanf/test6,1
+c_runtime/sscanf/test7,1
+c_runtime/sscanf/test8,1
+c_runtime/sscanf/test9,1
+c_runtime/sscanf/test10,1
+c_runtime/sscanf/test11,1
+c_runtime/sscanf/test12,1
+c_runtime/sscanf/test13,1
+c_runtime/sscanf/test14,1
+c_runtime/sscanf/test15,1
+c_runtime/sscanf/test16,1
+c_runtime/sscanf/test17,1
+c_runtime/strcat/test1,1
+c_runtime/strchr/test1,1
+c_runtime/strcmp/test1,1
+c_runtime/strcpy/test1,1
+c_runtime/strcspn/test1,1
+c_runtime/strlen/test1,1
+c_runtime/strncat/test1,1
+c_runtime/strncmp/test1,1
+c_runtime/strncpy/test1,1
+c_runtime/strpbrk/test1,1
+c_runtime/strrchr/test1,1
+c_runtime/strspn/test1,1
+c_runtime/strstr/test1,1
+c_runtime/strtod/test1,1
+c_runtime/strtod/test2,1
+c_runtime/strtok/test1,1
+c_runtime/strtoul/test1,1
+c_runtime/swprintf/test1,1
+c_runtime/swprintf/test2,1
+c_runtime/swprintf/test3,1
+c_runtime/swprintf/test4,1
+c_runtime/swprintf/test5,1
+c_runtime/swprintf/test6,1
+c_runtime/swprintf/test7,1
+c_runtime/swprintf/test8,1
+c_runtime/swprintf/test9,1
+c_runtime/swprintf/test10,1
+c_runtime/swprintf/test11,1
+c_runtime/swprintf/test12,1
+c_runtime/swprintf/test13,1
+c_runtime/swprintf/test14,1
+c_runtime/swprintf/test15,1
+c_runtime/swprintf/test16,1
+c_runtime/swprintf/test17,1
+c_runtime/swprintf/test18,1
+c_runtime/swprintf/test19,1
+c_runtime/swscanf/test1,1
+c_runtime/swscanf/test2,1
+c_runtime/swscanf/test3,1
+c_runtime/swscanf/test4,1
+c_runtime/swscanf/test5,1
+c_runtime/swscanf/test6,1
+c_runtime/swscanf/test7,1
+c_runtime/swscanf/test8,1
+c_runtime/swscanf/test9,1
+c_runtime/swscanf/test10,1
+c_runtime/swscanf/test11,1
+c_runtime/swscanf/test12,1
+c_runtime/swscanf/test13,1
+c_runtime/swscanf/test14,1
+c_runtime/swscanf/test15,1
+c_runtime/swscanf/test16,1
+c_runtime/swscanf/test17,1
+c_runtime/tan/test1,1
+c_runtime/tanh/test1,1
+c_runtime/time/test1,1
+c_runtime/tolower/test1,1
+c_runtime/toupper/test1,1
+c_runtime/towlower/test1,1
+c_runtime/towupper/test1,1
+c_runtime/ungetc/test1,1
+c_runtime/vfprintf/test1,1
+c_runtime/vfprintf/test2,1
+c_runtime/vfprintf/test3,1
+c_runtime/vfprintf/test4,1
+c_runtime/vfprintf/test5,1
+c_runtime/vfprintf/test6,1
+c_runtime/vfprintf/test7,1
+c_runtime/vfprintf/test8,1
+c_runtime/vfprintf/test9,1
+c_runtime/vfprintf/test10,1
+c_runtime/vfprintf/test11,1
+c_runtime/vfprintf/test12,1
+c_runtime/vfprintf/test13,1
+c_runtime/vfprintf/test14,1
+c_runtime/vfprintf/test15,1
+c_runtime/vfprintf/test16,1
+c_runtime/vfprintf/test17,1
+c_runtime/vfprintf/test18,1
+c_runtime/vfprintf/test19,1
+c_runtime/vprintf/test1,1
+c_runtime/vprintf/test2,1
+c_runtime/vprintf/test3,1
+c_runtime/vprintf/test4,1
+c_runtime/vprintf/test5,1
+c_runtime/vprintf/test6,1
+c_runtime/vprintf/test7,1
+c_runtime/vprintf/test8,1
+c_runtime/vprintf/test9,1
+c_runtime/vprintf/test10,1
+c_runtime/vprintf/test11,1
+c_runtime/vprintf/test12,1
+c_runtime/vprintf/test13,1
+c_runtime/vprintf/test14,1
+c_runtime/vprintf/test15,1
+c_runtime/vprintf/test16,1
+c_runtime/vprintf/test17,1
+c_runtime/vprintf/test18,1
+c_runtime/vprintf/test19,1
+c_runtime/vsprintf/test1,1
+c_runtime/vsprintf/test2,1
+c_runtime/vsprintf/test3,1
+c_runtime/vsprintf/test4,1
+c_runtime/vsprintf/test5,1
+c_runtime/vsprintf/test6,1
+c_runtime/vsprintf/test7,1
+c_runtime/vsprintf/test8,1
+c_runtime/vsprintf/test9,1
+c_runtime/vsprintf/test10,1
+c_runtime/vsprintf/test11,1
+c_runtime/vsprintf/test12,1
+c_runtime/vsprintf/test13,1
+c_runtime/vsprintf/test14,1
+c_runtime/vsprintf/test15,1
+c_runtime/vsprintf/test16,1
+c_runtime/vsprintf/test17,1
+c_runtime/vsprintf/test18,1
+c_runtime/vsprintf/test19,1
+c_runtime/vswprintf/test1,1
+c_runtime/vswprintf/test2,1
+c_runtime/vswprintf/test3,1
+c_runtime/vswprintf/test4,1
+c_runtime/vswprintf/test5,1
+c_runtime/vswprintf/test6,1
+c_runtime/vswprintf/test7,1
+c_runtime/vswprintf/test8,1
+c_runtime/vswprintf/test9,1
+c_runtime/vswprintf/test10,1
+c_runtime/vswprintf/test11,1
+c_runtime/vswprintf/test12,1
+c_runtime/vswprintf/test13,1
+c_runtime/vswprintf/test14,1
+c_runtime/vswprintf/test15,1
+c_runtime/vswprintf/test16,1
+c_runtime/vswprintf/test17,1
+c_runtime/vswprintf/test18,1
+c_runtime/vswprintf/test19,1
+c_runtime/wcscat/test1,1
+c_runtime/wcschr/test1,1
+c_runtime/wcscmp/test1,1
+c_runtime/wcscpy/test1,1
+c_runtime/wcslen/test1,1
+c_runtime/wcsncat/test1,1
+c_runtime/wcsncmp/test1,1
+c_runtime/wcsncpy/test1,1
+c_runtime/wcspbrk/test1,1
+c_runtime/wcsrchr/test1,1
+c_runtime/wcsstr/test1,1
+c_runtime/wcstod/test1,1
+c_runtime/wcstod/test2,1
+c_runtime/wcstok/test1,1
+c_runtime/wcstol/test1,1
+c_runtime/wcstol/test2,1
+c_runtime/wcstol/test3,1
+c_runtime/wcstol/test4,1
+c_runtime/wcstol/test5,1
+c_runtime/wcstol/test6,1
+c_runtime/wcstoul/test1,1
+c_runtime/wcstoul/test2,1
+c_runtime/wcstoul/test3,1
+c_runtime/wcstoul/test4,1
+c_runtime/wcstoul/test5,1
+c_runtime/wcstoul/test6,1
+debug_api/writeprocessmemory/test1,1
+exception_handling/pal_except/test1,1
+exception_handling/pal_except/test2,1
+exception_handling/pal_except/test3,1
+exception_handling/pal_except/test4,1
+exception_handling/pal_except/test5,1
+exception_handling/pal_except/test6,1
+exception_handling/pal_except/test7,1
+exception_handling/pal_except_filter/test1,1
+exception_handling/pal_except_filter/test2,1
+exception_handling/pal_except_filter/test3,1
+exception_handling/pal_except_filter_ex/test1,1
+exception_handling/pal_except_filter_ex/test2,1
+exception_handling/pal_except_filter_ex/test3,1
+exception_handling/pal_getbottommostregistration/test1,1
+exception_handling/pal_getbottommostregistration/test2,1
+exception_handling/pal_finally/test1,1
+exception_handling/pal_try_except/test1,1
+exception_handling/pal_try_except/test2,1
+exception_handling/pal_try_except_ex/test1,1
+exception_handling/pal_try_except_ex/test2,1
+exception_handling/pal_try_except_ex/test3,1
+exception_handling/pal_try_leave_finally/test1,1
+exception_handling/raiseexception/test1,1
+exception_handling/raiseexception/test2,1
+exception_handling/raiseexception/test3,1
+file_io/arefileapisansi/test1,1
+file_io/comparefiletime/test1,1
+file_io/copyfilea/test1,1
+file_io/copyfilea/test2,1
+file_io/copyfilea/test3,1
+file_io/copyfilea/test4,1
+file_io/copyfilew/test1,1
+file_io/copyfilew/test2,1
+file_io/createdirectorya/test1,1
+file_io/createdirectoryw/test1,1
+file_io/createfilea/test1,1
+file_io/createfilew/test1,1
+file_io/deletefilea/test1,1
+file_io/deletefilew/test1,1
+file_io/errorpathnotfound/test1,1
+file_io/errorpathnotfound/test2,1
+file_io/errorpathnotfound/test3,1
+#file_io/errorpathnotfound/test4,1
+file_io/filetimetodosdatetime/test1,1
+file_io/findclose/test1,1
+file_io/findfirstfilea/test1,1
+#file_io/findfirstfilew/test1,1
+file_io/findnextfilea/test1,1
+file_io/findnextfilew/test1,1
+file_io/flushfilebuffers/test1,1
+file_io/getconsolecp/test1,1
+file_io/getconsoleoutputcp/test1,1
+file_io/getcurrentdirectorya/test1,1
+file_io/getcurrentdirectoryw/test1,1
+file_io/getdiskfreespacew/test1,1
+#file_io/getfileattributesa/test1,1
+#file_io/getfileattributesexw/test1,1
+file_io/getfileattributesexw/test2,1
+#file_io/getfileattributesw/test1,1
+file_io/getfiletime/test1,1
+file_io/getfiletime/test2,1
+file_io/getfiletime/test3,1
+file_io/getfiletime/test4,1
+file_io/getfiletime/test6,1
+file_io/getfiletime/test7,1
+file_io/getfiletype/test1,1
+file_io/getfiletype/test2,1
+file_io/getfiletype/test3,1
+file_io/getfullpathnamea/test1,1
+file_io/getfullpathnamea/test2,1
+file_io/getfullpathnamea/test3,1
+file_io/getfullpathnamea/test4,1
+file_io/getfullpathnamew/test1,1
+file_io/getfullpathnamew/test2,1
+#file_io/getfullpathnamew/test3,1
+#file_io/getfullpathnamew/test4,1
+file_io/getlongpathnamew/test1,1
+file_io/getlongpathnamew/test2,1
+file_io/getsystemtime/test1,1
+file_io/getsystemtimeasfiletime/test1,1
+file_io/gettempfilenamea/test1,1
+file_io/gettempfilenamea/test3,1
+file_io/gettempfilenamew/test1,1
+file_io/gettempfilenamew/test3,1
+file_io/gettemppatha/test1,1
+file_io/gettemppathw/test1,1
+file_io/movefileexw/test1,1
+file_io/movefilew/test1,1
+#file_io/readfile/test1,1
+file_io/readfile/test2,1
+file_io/readfile/test3,1
+file_io/readfile/test4,1
+file_io/removedirectoryw/test1,1
+file_io/setcurrentdirectorya/test1,1
+file_io/setcurrentdirectorya/test2,1
+file_io/setcurrentdirectorya/test3,1
+file_io/setcurrentdirectoryw/test1,1
+file_io/setcurrentdirectoryw/test2,1
+#file_io/setcurrentdirectoryw/test3,1
+file_io/setendoffile/test1,1
+file_io/setendoffile/test2,1
+file_io/setendoffile/test3,1
+file_io/setendoffile/test4,1
+file_io/setendoffile/test5,1
+file_io/setfileattributesa/test2,1
+file_io/setfileattributesa/test3,1
+file_io/setfileattributesw/test2,1
+file_io/setfileattributesw/test3,1
+file_io/setfilepointer/test1,1
+file_io/setfilepointer/test2,1
+file_io/setfilepointer/test3,1
+file_io/setfilepointer/test4,1
+file_io/setfiletime/test1,1
+file_io/setfiletime/test2,1
+file_io/setfiletime/test3,1
+file_io/setfiletime/test4,1
+file_io/writefile/test1,1
+file_io/writefile/test2,1
+file_io/writefile/test3,1
+file_io/writefile/test4,1
+file_io/writefile/test5,1
+filemapping_memmgt/createfilemappinga/test1,1
+filemapping_memmgt/createfilemappinga/test3,1
+filemapping_memmgt/createfilemappinga/test4,1
+filemapping_memmgt/createfilemappinga/test5,1
+filemapping_memmgt/createfilemappinga/test6,1
+filemapping_memmgt/createfilemappinga/test7,1
+filemapping_memmgt/createfilemappinga/test8,1
+filemapping_memmgt/createfilemappinga/test9,1
+filemapping_memmgt/createfilemappingw/test1,1
+filemapping_memmgt/createfilemappingw/test3,1
+filemapping_memmgt/createfilemappingw/test4,1
+filemapping_memmgt/createfilemappingw/test5,1
+filemapping_memmgt/createfilemappingw/test6,1
+filemapping_memmgt/createfilemappingw/test7,1
+filemapping_memmgt/createfilemappingw/test8,1
+filemapping_memmgt/createfilemappingw/test9,1
+filemapping_memmgt/freelibrary/test1,1
+filemapping_memmgt/freelibrary/test2,1
+filemapping_memmgt/freelibraryandexitthread/test1,1
+filemapping_memmgt/getmodulefilenamea/test1,1
+filemapping_memmgt/getmodulefilenamea/test2,1
+filemapping_memmgt/getmodulefilenamew/test1,1
+filemapping_memmgt/getmodulefilenamew/test2,1
+filemapping_memmgt/getprocaddress/test1,1
+filemapping_memmgt/getprocaddress/test2,1
+filemapping_memmgt/getprocessheap/test1,1
+filemapping_memmgt/heapalloc/test1,1
+filemapping_memmgt/heapalloc/test2,1
+filemapping_memmgt/heapfree/test1,1
+filemapping_memmgt/heaprealloc/test1,1
+filemapping_memmgt/heaprealloc/test2,1
+filemapping_memmgt/heaprealloc/test3,1
+filemapping_memmgt/heaprealloc/test4,1
+filemapping_memmgt/heaprealloc/test5,1
+filemapping_memmgt/localalloc/test1,1
+filemapping_memmgt/localfree/test1,1
+filemapping_memmgt/localfree/test2,1
+filemapping_memmgt/lockfile/test1,1
+filemapping_memmgt/lockfile/test2,1
+filemapping_memmgt/lockfile/test3,1
+filemapping_memmgt/lockfile/test4,1
+filemapping_memmgt/lockfile/test5,1
+filemapping_memmgt/lockfile/test6,1
+filemapping_memmgt/lockfile/test7,1
+filemapping_memmgt/mapviewoffile/test1,1
+filemapping_memmgt/mapviewoffile/test2,1
+filemapping_memmgt/mapviewoffile/test3,1
+filemapping_memmgt/mapviewoffile/test4,1
+filemapping_memmgt/mapviewoffile/test5,1
+filemapping_memmgt/mapviewoffile/test6,1
+filemapping_memmgt/openfilemappinga/test1,1
+filemapping_memmgt/openfilemappinga/test2,1
+filemapping_memmgt/openfilemappinga/test3,1
+filemapping_memmgt/openfilemappingw/test1,1
+filemapping_memmgt/openfilemappingw/test2,1
+filemapping_memmgt/openfilemappingw/test3,1
+filemapping_memmgt/readprocessmemory/readprocessmemory_neg1,1
+filemapping_memmgt/readprocessmemory/test1,1
+filemapping_memmgt/rtlmovememory/test1,1
+filemapping_memmgt/rtlmovememory/test3,1
+filemapping_memmgt/rtlmovememory/test4,1
+filemapping_memmgt/rtlmovememory/test5,1
+filemapping_memmgt/unlockfile/test1,1
+filemapping_memmgt/unlockfile/test2,1
+filemapping_memmgt/unlockfile/test3,1
+filemapping_memmgt/unlockfile/test4,1
+filemapping_memmgt/unmapviewoffile/test1,1
+filemapping_memmgt/virtualalloc/test1,1
+filemapping_memmgt/virtualalloc/test2,1
+filemapping_memmgt/virtualalloc/test3,1
+filemapping_memmgt/virtualalloc/test4,1
+filemapping_memmgt/virtualalloc/test5,1
+filemapping_memmgt/virtualalloc/test6,1
+filemapping_memmgt/virtualalloc/test7,1
+filemapping_memmgt/virtualalloc/test8,1
+filemapping_memmgt/virtualalloc/test9,1
+filemapping_memmgt/virtualalloc/test10,1
+filemapping_memmgt/virtualalloc/test11,1
+filemapping_memmgt/virtualalloc/test12,1
+filemapping_memmgt/virtualalloc/test13,1
+filemapping_memmgt/virtualalloc/test14,1
+filemapping_memmgt/virtualalloc/test15,1
+filemapping_memmgt/virtualalloc/test16,1
+filemapping_memmgt/virtualalloc/test17,1
+filemapping_memmgt/virtualalloc/test18,1
+filemapping_memmgt/virtualalloc/test19,1
+filemapping_memmgt/virtualalloc/test20,1
+filemapping_memmgt/virtualalloc/test21,1
+filemapping_memmgt/virtualfree/test1,1
+filemapping_memmgt/virtualfree/test2,1
+filemapping_memmgt/virtualfree/test3,1
+filemapping_memmgt/virtualprotect/test1,1
+filemapping_memmgt/virtualprotect/test2,1
+filemapping_memmgt/virtualprotect/test3,1
+filemapping_memmgt/virtualprotect/test4,1
+filemapping_memmgt/virtualprotect/test6,1
+filemapping_memmgt/virtualprotect/test7,1
+filemapping_memmgt/virtualquery/test1,1
+loader/loadlibrarya/test1,1
+loader/loadlibrarya/test2,1
+loader/loadlibrarya/test3,0
+loader/loadlibrarya/test5,1
+loader/loadlibrarya/test6,1
+loader/loadlibraryw/test1,1
+loader/loadlibraryw/test2,1
+loader/loadlibraryw/test3,1
+loader/loadlibraryw/test5,1
+locale_info/comparestringw/test1,1
+locale_info/getacp/test1,1
+locale_info/getcpinfo/test1,1
+locale_info/getlocaleinfow/test1,1
+locale_info/getlocaleinfow/test2,1
+locale_info/getstringtypeexw/test1,1
+locale_info/getstringtypeexw/test2,0
+locale_info/getsystemdefaultlangid/test1,1
+locale_info/getthreadlocale/test1,1
+locale_info/gettimezoneinformation/test1,1
+locale_info/getuserdefaultlangid/test1,1
+locale_info/getuserdefaultlcid/test1,1
+locale_info/isdbcsleadbyteex/test1,1
+locale_info/isvalidcodepage/test1,1
+locale_info/isvalidlocale/test1,1
+locale_info/multibytetowidechar/test1,1
+locale_info/multibytetowidechar/test2,1
+locale_info/multibytetowidechar/test3,1
+locale_info/setthreadlocale/test1,1
+locale_info/widechartomultibyte/test1,1
+locale_info/widechartomultibyte/test2,1
+locale_info/widechartomultibyte/test3,1
+miscellaneous/_i64tow/test1,1
+miscellaneous/_ui64tow/test1,1
+miscellaneous/_ui64tow/test2,1
+miscellaneous/charnexta/test1,1
+miscellaneous/charnexta/test2,1
+miscellaneous/charnextexa/test1,1
+miscellaneous/charnextexa/test2,1
+miscellaneous/closehandle/test1,1
+miscellaneous/closehandle/test2,1
+miscellaneous/createpipe/test1,1
+miscellaneous/flushinstructioncache/test1,1
+miscellaneous/formatmessagew/test1,1
+miscellaneous/formatmessagew/test2,1
+miscellaneous/formatmessagew/test3,1
+miscellaneous/formatmessagew/test4,1
+miscellaneous/formatmessagew/test5,1
+miscellaneous/formatmessagew/test6,1
+miscellaneous/freeenvironmentstringsw/test1,1
+miscellaneous/freeenvironmentstringsw/test2,1
+miscellaneous/getcalendarinfow/test1,1
+miscellaneous/getcommandlinew/test1,1
+miscellaneous/getenvironmentstringsw/test1,1
+miscellaneous/getenvironmentvariablea/test1,1
+miscellaneous/getenvironmentvariablea/test2,1
+miscellaneous/getenvironmentvariablea/test3,1
+miscellaneous/getenvironmentvariablea/test4,1
+miscellaneous/getenvironmentvariablew/test1,1
+miscellaneous/getenvironmentvariablew/test2,1
+miscellaneous/getenvironmentvariablew/test3,1
+miscellaneous/getenvironmentvariablew/test4,1
+miscellaneous/getlasterror/test1,1
+miscellaneous/getsysteminfo/test1,1
+miscellaneous/gettickcount/test1,1
+miscellaneous/getversionexa/test1,1
+miscellaneous/getversionexw/test1,1
+miscellaneous/interlockedcompareexchange/test1,1
+miscellaneous/interlockedcompareexchangepointer/test1,1
+miscellaneous/interlockeddecrement/test1,1
+miscellaneous/interlockedexchange/test1,1
+miscellaneous/interlockedexchangepointer/test1,1
+miscellaneous/interlockedincrement/test1,1
+miscellaneous/isbadcodeptr/test1,1
+miscellaneous/isbadreadptr/test1,1
+miscellaneous/isbadwriteptr/test1,1
+miscellaneous/isbadwriteptr/test2,1
+miscellaneous/isbadwriteptr/test3,1
+miscellaneous/lstrcatw/test1,1
+miscellaneous/lstrcatw/test2,1
+miscellaneous/lstrcatw/test3,1
+miscellaneous/lstrcatw/test4,1
+miscellaneous/lstrcpynw/test1,1
+miscellaneous/lstrcpyw/test1,1
+miscellaneous/lstrlena/test1,1
+miscellaneous/lstrlenw/test1,1
+miscellaneous/queryperformancecounter/test1,1
+miscellaneous/queryperformancefrequency/test1,1
+miscellaneous/setenvironmentvariablea/test1,1
+miscellaneous/setenvironmentvariablea/test2,1
+miscellaneous/setenvironmentvariablew/test1,1
+miscellaneous/setenvironmentvariablew/test2,1
+miscellaneous/setlasterror/test1,1
+miscellaneous/wsprintfa/test1,1
+miscellaneous/wsprintfa/test2,1
+miscellaneous/wsprintfa/test3,1
+miscellaneous/wsprintfa/test6,1
+miscellaneous/wsprintfa/test7,1
+miscellaneous/wsprintfa/test8,1
+miscellaneous/wsprintfa/test9,1
+miscellaneous/wsprintfa/test11,1
+miscellaneous/wsprintfa/test12,1
+miscellaneous/wsprintfa/test13,1
+miscellaneous/wsprintfw/test1,1
+miscellaneous/wsprintfw/test2,1
+miscellaneous/wsprintfw/test3,1
+miscellaneous/wsprintfw/test6,1
+miscellaneous/wsprintfw/test7,1
+miscellaneous/wsprintfw/test8,1
+miscellaneous/wsprintfw/test9,1
+miscellaneous/wsprintfw/test11,1
+miscellaneous/wsprintfw/test12,1
+miscellaneous/wsprintfw/test13,1
+pal_specific/pal_errno/test1,1
+pal_specific/pal_getpaldirectoryw/test1,1
+pal_specific/pal_getuserconfigurationdirectoryw/test1,1
+pal_specific/pal_initialize_terminate/test1,1
+threading/createeventa/test1,1
+threading/createeventa/test2,1
+threading/createeventa/test3,1
+threading/createeventw/test1,1
+threading/createeventw/test2,1
+threading/createeventw/test3,1
+threading/createmutexw_releasemutex/test1,1
+threading/createmutexw_releasemutex/test2,1
+threading/createprocessa/test1,1
+threading/createprocessa/test2,1
+threading/createprocessw/test1,1
+threading/createprocessw/test2,1
+threading/createsemaphorea_releasesemaphore/test1,1
+threading/createsemaphorea_releasesemaphore/test2,1
+threading/createsemaphorea_releasesemaphore/test3,1
+threading/createsemaphorew_releasesemaphore/test1,1
+threading/createsemaphorew_releasesemaphore/test2,1
+threading/createsemaphorew_releasesemaphore/test3,1
+threading/createthread/test1,1
+threading/createthread/test2,1
+threading/createthread/test3,1
+threading/criticalsectionfunctions/test1,1
+threading/criticalsectionfunctions/test2,1
+threading/criticalsectionfunctions/test3,1
+threading/criticalsectionfunctions/test4,1
+threading/criticalsectionfunctions/test5,1
+threading/criticalsectionfunctions/test6,1
+threading/criticalsectionfunctions/test7,1
+threading/disablethreadlibrarycalls/test1,1
+threading/disablethreadlibrarycalls/test2,1
+threading/duplicatehandle/test1,1
+threading/duplicatehandle/test2,1
+threading/duplicatehandle/test3,1
+threading/duplicatehandle/test4,1
+threading/duplicatehandle/test5,1
+threading/duplicatehandle/test6,1
+threading/duplicatehandle/test7,1
+threading/duplicatehandle/test8,1
+threading/duplicatehandle/test9,1
+threading/duplicatehandle/test10,1
+threading/duplicatehandle/test11,1
+threading/exitprocess/test1,1
+threading/exitthread/test1,1
+#threading/exitthread/test2,1
+threading/exitthread/test3,1
+threading/getcurrentprocess/test1,1
+threading/getcurrentprocessid/test1,1
+threading/getcurrentthread/test1,1
+threading/getcurrentthread/test2,1
+threading/getcurrentthreadid/test1,1
+threading/getexitcodeprocess/test1,1
+threading/getprocesstimes/test2,1
+threading/openeventw/test1,1
+threading/openeventw/test2,1
+threading/openeventw/test3,1
+threading/openeventw/test4,1
+threading/openeventw/test5,1
+threading/openprocess/test1,1
+threading/queueuserapc/test1,1
+threading/queueuserapc/test2,1
+threading/queueuserapc/test3,1
+threading/queueuserapc/test4,1
+threading/queueuserapc/test5,0
+threading/queueuserapc/test6,0
+threading/queueuserapc/test7,1
+threading/releasemutex/test3,1
+threading/releasesemaphore/test1,1
+threading/resetevent/test1,1
+threading/resumethread/test1,1
+threading/seterrormode/test1,1
+threading/setevent/test1,1
+threading/setthreadcontext/test1,1
+threading/sleepex/test2,1
+threading/suspendthread/test1,1
+threading/terminateprocess/test1,1
+threading/tls/test1,1
+threading/tls/test2,1
+threading/tls/test3,1
+threading/tls/test4,1
+threading/tls/test5,1
+threading/waitformultipleobjects/test1,1
+threading/waitformultipleobjectsex/test1,1
+threading/waitformultipleobjectsex/test2,1
+threading/waitformultipleobjectsex/test3,1
+threading/waitformultipleobjectsex/test4,1
+threading/waitformultipleobjectsex/test5,1
+
+
diff --git a/src/pal/tests/palsuite/runpaltests.sh b/src/pal/tests/palsuite/runpaltests.sh
new file mode 100755
index 0000000000..cc8ffd6b91
--- /dev/null
+++ b/src/pal/tests/palsuite/runpaltests.sh
@@ -0,0 +1,213 @@
+#!/usr/bin/env bash
+#
+# This script executes PAL tests from the specified build location.
+#
+
+if [ $# -lt 1 -o $# -gt 3 ]
+then
+ echo "Usage..."
+ echo "runpaltests.sh <path to root build directory> [<path to temp folder for PAL tests>]"
+ echo
+ echo "For example:"
+ echo "runpaltests.sh /projectk/build/debug"
+ echo
+ exit 1
+fi
+
+echo
+echo "***** Testing PAL *****"
+echo
+
+# Store the location of the root of build directory
+BUILD_ROOD_DIR=$1
+# Create path to the compiled PAL tets in the build directory
+PAL_TEST_BUILD=$BUILD_ROOD_DIR/src/pal/tests/palsuite
+echo Running PAL tests from $PAL_TEST_BUILD
+
+# Create absolute path to the file that contains a list of PAL tests to execute.
+# This file is located next to this script in the source tree
+RELATIVE_PATH_TO_PAL_TESTS=$0
+# Remove the name of this script from the path
+RELATIVE_PATH_TO_PAL_TESTS=${RELATIVE_PATH_TO_PAL_TESTS%/*.*}
+# Change current directory to the location of this script
+cd $RELATIVE_PATH_TO_PAL_TESTS
+# Environment variable PWD contains absolute path to the current folder
+# so use it to create absolute path to the file with a list of tests.
+PAL_TEST_LIST=$PWD/paltestlist.txt
+# Change current directory back to the original location
+cd $OLDPWD
+echo The list of PAL tests to run will be read from $PAL_TEST_LIST
+
+# Create the test output root directory
+mkdir -p /tmp/PalTestOutput
+if [ ! -d /tmp/PalTestOutput ]; then
+ rm -f -r /tmp/PalTestOutput
+ mkdir -p /tmp/PalTestOutput
+fi
+
+# Determine the folder to use for PAL test output during the run, and the folder where output files were requested to be copied.
+# First check if the output folder was passed as a parameter to the script. It is supposed be the second parameter so check if
+# we have more than 1 argument.
+PAL_TEST_OUTPUT_DIR=/tmp/PalTestOutput/default
+if [ $# -gt 1 ]
+then
+ COPY_TO_TEST_OUTPUT_DIR=$2
+else
+ COPY_TO_TEST_OUTPUT_DIR=$PAL_TEST_OUTPUT_DIR
+fi
+
+# Determine the folder to use for PAL test output during the run
+if [ "$COPY_TO_TEST_OUTPUT_DIR" != "$PAL_TEST_OUTPUT_DIR" ]; then
+ # Output files were requested to be copied to a specific folder. In this mode, we need to support parallel runs of PAL tests
+ # on the same machine. Make a unique temp folder for working output inside /tmp/PalTestOutput.
+ PAL_TEST_OUTPUT_DIR=$(mktemp -d /tmp/PalTestOutput/tmp.XXXXXXXX)
+fi
+
+echo PAL tests will store their temporary files and output in $PAL_TEST_OUTPUT_DIR.
+if [ "$COPY_TO_TEST_OUTPUT_DIR" != "$PAL_TEST_OUTPUT_DIR" ]; then
+ echo Output files will be copied to $COPY_TO_TEST_OUTPUT_DIR at the end.
+fi
+
+# Path to a file that will contains a list PAL tests that failed during the test run.
+PAL_FAILED_TEST_LIST=$PAL_TEST_OUTPUT_DIR/palfailedtests.txt
+
+# Path to a file that will contain the XUnit style test result for Jenkins
+# We use a temp file as at the end we have to prepend with the number of tests
+# and failures
+PAL_XUNIT_TEST_LIST_TMP=$PAL_TEST_OUTPUT_DIR/pal_tests.xml.tmp
+PAL_XUNIT_TEST_LIST=$PAL_TEST_OUTPUT_DIR/pal_tests.xml
+
+# Capturing stdout and stderr
+PAL_OUT_FILE=$PAL_TEST_OUTPUT_DIR/pal_test_out
+
+# Remove and recreate the temporary test output directory, and the directory where output files were requested to be copied.
+if [ "$COPY_TO_TEST_OUTPUT_DIR" == "$PAL_TEST_OUTPUT_DIR" ]; then
+ if [ -e $PAL_TEST_OUTPUT_DIR ]; then
+ rm -f -r $PAL_TEST_OUTPUT_DIR
+ fi
+ mkdir -p $PAL_TEST_OUTPUT_DIR
+else
+ # No need to recreate the temp output directory, as mktemp would have created a unique empty directory
+ if [ -e $COPY_TO_TEST_OUTPUT_DIR ]; then
+ rm -f -r $COPY_TO_TEST_OUTPUT_DIR
+ fi
+ mkdir -p $COPY_TO_TEST_OUTPUT_DIR
+ if [ ! -d $COPY_TO_TEST_OUTPUT_DIR ]; then
+ echo Failed to create $COPY_TO_TEST_OUTPUT_DIR.
+ COPY_TO_TEST_OUTPUT_DIR=$PAL_TEST_OUTPUT_DIR
+ fi
+fi
+cd $PAL_TEST_OUTPUT_DIR
+
+echo
+echo "Running tests..."
+echo
+
+NUMBER_OF_PASSED_TESTS=0
+NUMBER_OF_FAILED_TESTS=0
+
+# Read PAL tests names from the $PAL_TEST_LIST file and run them one by one.
+while read TEST_NAME
+do
+ # Remove stdout/stderr file if it exists
+ rm -f $PAL_OUT_FILE
+
+ # Create a folder with the test name, and use that as the working directory for the test. Many PAL tests don't clean up after
+ # themselves and may leave files/directories around, but even to handle test failures that result in a dirty state, run each
+ # test in its own folder.
+ TEST_WORKING_DIR=$(basename $TEST_NAME)
+ if [ -e $TEST_WORKING_DIR ]; then
+ rm -f -r $TEST_WORKING_DIR
+ fi
+ mkdir $TEST_WORKING_DIR
+ cd $TEST_WORKING_DIR
+
+ # Create path to a test executable to run
+ TEST_COMMAND="$PAL_TEST_BUILD/$TEST_NAME"
+ echo -n .
+ # Redirect to temp file
+ $TEST_COMMAND 2>&1 | tee ${PAL_OUT_FILE} ; ( exit ${PIPESTATUS[0]} )
+
+ # Get exit code of the test process.
+ TEST_EXIT_CODE=$?
+
+ # Change back to the output directory, and remove the test's working directory if it's empty
+ cd $PAL_TEST_OUTPUT_DIR
+ rmdir $TEST_WORKING_DIR 2>/dev/null
+
+ TEST_XUNIT_NAME=$(dirname $TEST_NAME)
+ TEST_XUNIT_CLASSNAME=$(dirname $TEST_XUNIT_NAME)
+ TEST_XUNIT_NAME=${TEST_XUNIT_NAME#*/}
+ TEST_XUNIT_NAME=${TEST_XUNIT_NAME#*/}
+
+ TEST_XUNIT_NAME=$(echo $TEST_XUNIT_NAME | tr / .)
+ TEST_XUNIT_CLASSNAME=$(echo $TEST_XUNIT_CLASSNAME | tr / .)
+
+ echo -n "<test name=\"$TEST_XUNIT_CLASSNAME.$TEST_XUNIT_NAME\" type=\"$TEST_XUNIT_CLASSNAME\" method=\"$TEST_XUNIT_NAME\" result=\"" >> $PAL_XUNIT_TEST_LIST_TMP
+
+ # If the exit code is 0 then the test passed, otherwise record a failure.
+ if [ "$TEST_EXIT_CODE" -eq "0" ]; then
+ NUMBER_OF_PASSED_TESTS=$(($NUMBER_OF_PASSED_TESTS + 1))
+ echo "Pass\" />" >> $PAL_XUNIT_TEST_LIST_TMP
+ else
+ echo "Fail\" >" >> $PAL_XUNIT_TEST_LIST_TMP
+ echo "<failure exception-type=\"Exit code: $TEST_EXIT_CODE\">" >> $PAL_XUNIT_TEST_LIST_TMP
+ echo "<message><![CDATA[$(cat $PAL_OUT_FILE)]]></message>" >> $PAL_XUNIT_TEST_LIST_TMP
+ echo "</failure>" >> $PAL_XUNIT_TEST_LIST_TMP
+ echo "</test>" >> $PAL_XUNIT_TEST_LIST_TMP
+ FAILED_TEST="$TEST_NAME. Exit code: $TEST_EXIT_CODE"
+ echo
+ echo FAILED: $FAILED_TEST
+ echo
+
+ # Store the name of the failed test in the list of failed tests.
+ echo $FAILED_TEST >> $PAL_FAILED_TEST_LIST
+
+ NUMBER_OF_FAILED_TESTS=$(($NUMBER_OF_FAILED_TESTS + 1))
+ fi
+done < $PAL_TEST_LIST
+
+# We are done running tests.
+echo
+echo Finished running PAL tests.
+echo
+
+# Finish XUnit file, output to finished file with the number of failures, tests etc
+NUMBER_OF_TESTS=$(($NUMBER_OF_PASSED_TESTS + $NUMBER_OF_FAILED_TESTS))
+
+XUNIT_SUFFIX="</collection>\n"
+XUNIT_SUFFIX+="</assembly>\n"
+XUNIT_SUFFIX+="</assemblies>"
+
+XUNIT_PREFIX="<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
+XUNIT_PREFIX+="<assemblies>\n"
+XUNIT_PREFIX+="<assembly name=\"PAL\" total=\"$NUMBER_OF_TESTS\" passed=\"$NUMBER_OF_PASSED_TESTS\" failed=\"$NUMBER_OF_FAILED_TESTS\" skipped=\"0\">\n"
+XUNIT_PREFIX+="<collection total=\"$NUMBER_OF_TESTS\" passed=\"$NUMBER_OF_PASSED_TESTS\" failed=\"$NUMBER_OF_FAILED_TESTS\" skipped=\"0\" name=\"palsuite\">"
+
+printf "$XUNIT_SUFFIX" >> $PAL_XUNIT_TEST_LIST_TMP
+printf "$XUNIT_PREFIX" | cat - $PAL_XUNIT_TEST_LIST_TMP > $PAL_XUNIT_TEST_LIST
+
+# If there were tests failures then print the list of failed tests
+if [ $NUMBER_OF_FAILED_TESTS -gt "0" ]; then
+ echo "The following test(s) failed:"
+ while read FAILED_TEST_NAME
+ do
+ echo $FAILED_TEST_NAME
+ done < $PAL_FAILED_TEST_LIST
+ echo
+fi
+
+echo PAL Test Results:
+echo " Passed: $NUMBER_OF_PASSED_TESTS"
+echo " Failed: $NUMBER_OF_FAILED_TESTS"
+echo
+
+if [ "$COPY_TO_TEST_OUTPUT_DIR" != "$PAL_TEST_OUTPUT_DIR" ]; then
+ mv -f $PAL_TEST_OUTPUT_DIR/* $COPY_TO_TEST_OUTPUT_DIR/
+ rm -f -r $PAL_TEST_OUTPUT_DIR
+ echo Copied PAL test output files to $COPY_TO_TEST_OUTPUT_DIR.
+fi
+
+# Set exit code to be equal to the number PAL tests that have failed.
+# Exit code 0 indicates success.
+exit $NUMBER_OF_FAILED_TESTS
diff --git a/src/pal/tests/palsuite/samples/CMakeLists.txt b/src/pal/tests/palsuite/samples/CMakeLists.txt
new file mode 100644
index 0000000000..ef14ea5352
--- /dev/null
+++ b/src/pal/tests/palsuite/samples/CMakeLists.txt
@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+
diff --git a/src/pal/tests/palsuite/samples/test1/CMakeLists.txt b/src/pal/tests/palsuite/samples/test1/CMakeLists.txt
new file mode 100644
index 0000000000..da5892cfa6
--- /dev/null
+++ b/src/pal/tests/palsuite/samples/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.c
+)
+
+add_executable(paltest_samples_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_samples_test1 coreclrpal)
+
+target_link_libraries(paltest_samples_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/samples/test1/test.c b/src/pal/tests/palsuite/samples/test1/test.c
new file mode 100644
index 0000000000..2eed6f6f44
--- /dev/null
+++ b/src/pal/tests/palsuite/samples/test1/test.c
@@ -0,0 +1,41 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test.c
+**
+** Purpose: This test is an example of the basic structure of a PAL test
+** suite test case.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char **argv)
+{
+ /* Initialize the PAL.
+ */
+ if(0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+ Trace("\nTest #1...\n");
+
+#ifdef WIN32
+ Trace("\nWe are testing under Win32 environment.\n");
+#else
+ Trace("\nWe are testing under Non-Win32 environment.\n");
+#endif
+
+ Trace("\nThis test has passed.\n");
+
+ /* Shutdown the PAL.
+ */
+ PAL_Terminate();
+
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/samples/test1/testinfo.dat b/src/pal/tests/palsuite/samples/test1/testinfo.dat
new file mode 100644
index 0000000000..0459d24d63
--- /dev/null
+++ b/src/pal/tests/palsuite/samples/test1/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Samples
+Function = sample
+Name = Sample Test #1
+TYPE = DEFAULT
+EXE1 = test
+Description
+=This is a sample test case. It will always pass.
+
+
diff --git a/src/pal/tests/palsuite/samples/test2/CMakeLists.txt b/src/pal/tests/palsuite/samples/test2/CMakeLists.txt
new file mode 100644
index 0000000000..fdef2aac6b
--- /dev/null
+++ b/src/pal/tests/palsuite/samples/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.c
+)
+
+add_executable(paltest_samples_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_samples_test2 coreclrpal)
+
+target_link_libraries(paltest_samples_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/samples/test2/test.c b/src/pal/tests/palsuite/samples/test2/test.c
new file mode 100644
index 0000000000..53d4158b9d
--- /dev/null
+++ b/src/pal/tests/palsuite/samples/test2/test.c
@@ -0,0 +1,48 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test.c
+**
+** Purpose: A sample to show how to structure a test case.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char **argv)
+{
+ int exampleInt = 9;
+
+ /* Initialize the PAL.
+ */
+ if(0 != PAL_Initialize(argc, argv))
+ {
+ return FAIL;
+ }
+
+
+ Trace("\nTest #2...\n");
+
+#ifdef WIN32
+ Trace("\nWe are testing under Win32 environment.\n");
+#else
+ Trace("\nWe are testing under Non-Win32 environment.\n");
+#endif
+
+ if (exampleInt == 9)
+ {
+ Fail("This is an example to how to code a failure. "
+ "This failure was caused by exampleInt equalling %d\n",
+ exampleInt);
+ }
+
+ /* Shutdown the PAL.
+ */
+ PAL_Terminate();
+
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/samples/test2/testinfo.dat b/src/pal/tests/palsuite/samples/test2/testinfo.dat
new file mode 100644
index 0000000000..eb6e38db87
--- /dev/null
+++ b/src/pal/tests/palsuite/samples/test2/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Samples
+Function = sample
+Name = Sample Test #2
+TYPE = DEFAULT
+EXE1 = test
+Description
+=This is a sample test case. It will always fail.
+
diff --git a/src/pal/tests/palsuite/smoketest.script b/src/pal/tests/palsuite/smoketest.script
new file mode 100644
index 0000000000..19bb8cd6dc
--- /dev/null
+++ b/src/pal/tests/palsuite/smoketest.script
@@ -0,0 +1,100 @@
+#!/bin/csh
+
+# Smoketest v1.1
+#
+# This smoketest is intended to stress briefly every part of PAL,
+# and is to be run before submitting or approving a patch, to ensure
+# that it is not breaking the PAL. It should run in about 30 seconds
+#
+# Installation:
+# smoketest.dat and this script should be placed in xxx/xport/tests/palsuite.
+# Execute smoketest with the location of rotor as a commandline arg
+# with no trailing
+#
+# Be sure that xrun and testharness are built. (in xport/tests/harness,
+# cd test_harness, gmake, cd ../xrun, gmake)
+#
+if ($#argv != 1) then
+ echo smoketest v1.1
+ echo " "
+ echo Usage: smoketest location-of-xport
+ echo " "
+ echo "where location-of-xport is the location of your xport checkout"
+ echo "ie. xxxx/xport (with NO TRAILING /)"
+ echo " (For example: smoketest ~/xport)"
+ exit
+endif
+
+setenv ROTOR_DIR $argv[1]
+setenv TH_BIN $argv[1]/tests/harness/test_harness/testharness
+setenv TH_CONFIG $argv[1]/tests/palsuite/smoketest.dat
+setenv TH_RESULTS $argv[1]/tests/palsuite/smoketest.log
+setenv TH_DIR $argv[1]/tests/palsuite
+setenv TH_XRUN $argv[1]/tests/harness/xrun/xrun
+setenv PAL_DBG_CHANNELS ""
+
+
+# Let's check to make sure that the developer has built xrun
+# and testharness for us and/or that the variables above were set
+# properly
+if ((-e $TH_BIN) != 1) then
+ echo $TH_BIN was not found.
+ echo Did you forget to build the test harness\?
+ exit
+endif
+
+if ((-e $TH_XRUN) != 1) then
+ echo $TH_XRUN was not found.
+ echo Did you forget to build Xrun\?
+ exit
+endif
+
+
+$TH_BIN 2>&1 /dev/null
+
+
+set FAILING = `grep EXEC,FAIL $TH_RESULTS | wc -l`
+set PASSING = `grep EXEC,PASS $TH_RESULTS | wc -l`
+set DISABLED = `grep EXEC,DISABLED $TH_RESULTS | wc -l`
+set TOTAL_TESTS = `grep BUILD $TH_RESULTS | wc -l`
+set OTHERS = $TOTAL_TESTS
+@ OTHERS = ((($OTHERS - $FAILING) - $PASSING ) - $DISABLED)
+
+clear
+echo Summary:
+echo ========
+echo Total Number of Tests: $TOTAL_TESTS
+echo Total Passing: $PASSING / $TOTAL_TESTS
+echo Total Failing: $FAILING / $TOTAL_TESTS
+echo Total Disabled: $DISABLED / $TOTAL_TESTS
+echo Other Problems: $OTHERS / $TOTAL_TESTS
+
+if ($FAILING > 0) then
+ echo " "
+ echo "*******************************************"
+ echo "*******************************************"
+ echo "*******************************************"
+ echo "*******************************************"
+ echo "WARNING WARNING WARNING WARNING WARNING"
+ echo " "
+
+ if ($FAILING > 1) then
+ echo There are now $FAILING tests failing.
+ else
+ echo There is now 1 test failing.
+ endif
+
+ echo Please run:
+ echo " "
+ echo grep \"EXEC,FAIL\" $TH_RESULTS
+ echo " "
+ echo to figure out what is going wrong.
+ echo "*******************************************"
+ echo "*******************************************"
+ echo "*******************************************"
+ echo "*******************************************"
+else
+ echo " "
+ echo "Smoketest executed OK."
+ rm $TH_RESULTS
+endif
diff --git a/src/pal/tests/palsuite/tests-manual.dat b/src/pal/tests/palsuite/tests-manual.dat
new file mode 100644
index 0000000000..402e819cea
--- /dev/null
+++ b/src/pal/tests/palsuite/tests-manual.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+c_runtime/exit/test2,1
+pal_specific/pal_get_stderr/test1,1
+pal_specific/pal_get_stdin/test1,1
+pal_specific/pal_get_stdout/test1,1
+threading/setconsolectrlhandler/test1,1
+threading/setconsolectrlhandler/test2,1
+threading/setconsolectrlhandler/test3,1
+threading/setconsolectrlhandler/test4,1
diff --git a/src/pal/tests/palsuite/threading/CMakeLists.txt b/src/pal/tests/palsuite/threading/CMakeLists.txt
new file mode 100644
index 0000000000..bd31d17579
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CMakeLists.txt
@@ -0,0 +1,44 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(CreateEventA)
+add_subdirectory(CreateEventW)
+add_subdirectory(CreateMutexA_ReleaseMutex)
+add_subdirectory(CreateMutexW_ReleaseMutex)
+add_subdirectory(CreateProcessA)
+add_subdirectory(CreateProcessW)
+add_subdirectory(CreateSemaphoreA_ReleaseSemaphore)
+add_subdirectory(CreateSemaphoreW_ReleaseSemaphore)
+add_subdirectory(CreateThread)
+add_subdirectory(CriticalSectionFunctions)
+add_subdirectory(DuplicateHandle)
+add_subdirectory(ExitProcess)
+add_subdirectory(ExitThread)
+add_subdirectory(GetCurrentProcess)
+add_subdirectory(GetCurrentProcessId)
+add_subdirectory(GetCurrentThread)
+add_subdirectory(GetCurrentThreadId)
+add_subdirectory(GetExitCodeProcess)
+add_subdirectory(GetProcessTimes)
+add_subdirectory(GetThreadTimes)
+add_subdirectory(NamedMutex)
+add_subdirectory(OpenEventW)
+add_subdirectory(OpenProcess)
+add_subdirectory(QueryThreadCycleTime)
+add_subdirectory(QueueUserAPC)
+add_subdirectory(ReleaseMutex)
+add_subdirectory(releasesemaphore)
+add_subdirectory(ResetEvent)
+add_subdirectory(ResumeThread)
+add_subdirectory(SetErrorMode)
+add_subdirectory(SetEvent)
+add_subdirectory(Sleep)
+add_subdirectory(SleepEx)
+add_subdirectory(SwitchToThread)
+add_subdirectory(TerminateProcess)
+add_subdirectory(ThreadPriority)
+add_subdirectory(TLS)
+add_subdirectory(WaitForMultipleObjects)
+add_subdirectory(WaitForMultipleObjectsEx)
+add_subdirectory(WaitForSingleObject)
+add_subdirectory(YieldProcessor)
+
diff --git a/src/pal/tests/palsuite/threading/CreateEventA/CMakeLists.txt b/src/pal/tests/palsuite/threading/CreateEventA/CMakeLists.txt
new file mode 100644
index 0000000000..1962ade358
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CreateEventA/CMakeLists.txt
@@ -0,0 +1,6 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+add_subdirectory(test3)
+
diff --git a/src/pal/tests/palsuite/threading/CreateEventA/test1/CMakeLists.txt b/src/pal/tests/palsuite/threading/CreateEventA/test1/CMakeLists.txt
new file mode 100644
index 0000000000..da1232eea4
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CreateEventA/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_createeventa_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_createeventa_test1 coreclrpal)
+
+target_link_libraries(paltest_createeventa_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/CreateEventA/test1/test1.c b/src/pal/tests/palsuite/threading/CreateEventA/test1/test1.c
new file mode 100644
index 0000000000..d8ef0f58a3
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CreateEventA/test1/test1.c
@@ -0,0 +1,95 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: test1.c
+**
+** Purpose: Test for CreateEvent. Create an event, ensure the
+** HANDLE is valid. Then check to ensure that the object is in the
+** signaled state. Close the HANDLE and done.
+**
+**
+**=========================================================*/
+
+/*
+ Note: From the rotor_pal documentation:
+
+ lpEventAttributes will always be NULL, bManualReset can be either
+ TRUE or FALSE, bInitialState can be either TRUE or FALSE, the lpName
+ may be non-NULL
+
+*/
+
+
+#include <palsuite.h>
+
+BOOL CreateEventTest()
+{
+ BOOL bRet = FALSE;
+ DWORD dwRet = 0;
+
+ LPSECURITY_ATTRIBUTES lpEventAttributes = NULL;
+ BOOL bManualReset = TRUE;
+ BOOL bInitialState = TRUE;
+
+ /* Call CreateEvent, and check to ensure the returned HANDLE is a
+ valid event HANDLE
+ */
+
+ HANDLE hEvent = CreateEvent( lpEventAttributes,
+ bManualReset,
+ bInitialState,
+ NULL);
+
+ if (hEvent != NULL)
+ {
+ /* Wait for the Object (for 0 time) and ensure that it returns
+ the value indicating that the event is signaled.
+ */
+ dwRet = WaitForSingleObject(hEvent,0);
+
+ if (dwRet != WAIT_OBJECT_0)
+ {
+ Trace("CreateEventTest:WaitForSingleObject failed (%x)\n", GetLastError());
+ }
+ else
+ {
+ /* If we make it here, and CloseHandle succeeds, then the
+ entire test has passed. Otherwise bRet will still show
+ failure
+ */
+ bRet = CloseHandle(hEvent);
+
+ if (!bRet)
+ {
+ Trace("CreateEventTest:CloseHandle failed (%x)\n", GetLastError());
+ }
+ }
+ }
+ else
+ {
+ Trace("CreateEventTest:CreateEvent failed (%x)\n", GetLastError());
+ }
+
+ return bRet;
+}
+
+int __cdecl main(int argc, char **argv)
+{
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return ( FAIL );
+ }
+
+ if(!CreateEventTest())
+ {
+ Fail ("Test failed\n");
+ }
+
+ PAL_Terminate();
+ return ( PASS );
+
+}
diff --git a/src/pal/tests/palsuite/threading/CreateEventA/test1/testinfo.dat b/src/pal/tests/palsuite/threading/CreateEventA/test1/testinfo.dat
new file mode 100644
index 0000000000..c0d169ccdc
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CreateEventA/test1/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = CreateEvent
+Name = Positive Test for CreateEvent
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Test for CreateEvent. Create an event, ensure the
+= HANDLE is valid. Then check to ensure that the object is in the
+= signaled state. Close the HANDLE and done.
diff --git a/src/pal/tests/palsuite/threading/CreateEventA/test2/CMakeLists.txt b/src/pal/tests/palsuite/threading/CreateEventA/test2/CMakeLists.txt
new file mode 100644
index 0000000000..f87e5bea87
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CreateEventA/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test2.c
+)
+
+add_executable(paltest_createeventa_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_createeventa_test2 coreclrpal)
+
+target_link_libraries(paltest_createeventa_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/CreateEventA/test2/test2.c b/src/pal/tests/palsuite/threading/CreateEventA/test2/test2.c
new file mode 100644
index 0000000000..a24d20eeea
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CreateEventA/test2/test2.c
@@ -0,0 +1,84 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: test2.c
+**
+** Purpose: Test for CreateEvent. Create the event with the
+** initial state being not signaled. Check to ensure that it
+** times out when the event is triggered.
+**
+**
+**=========================================================*/
+
+#include <palsuite.h>
+
+BOOL CreateEventTest()
+{
+ BOOL bRet = FALSE;
+ DWORD dwRet = 0;
+
+ LPSECURITY_ATTRIBUTES lpEventAttributes = 0;
+ BOOL bManualReset = TRUE;
+ BOOL bInitialState = FALSE;
+
+ /* Create an event with the Initial State set to FALSE */
+
+ HANDLE hEvent = CreateEvent( lpEventAttributes,
+ bManualReset,
+ bInitialState,
+ NULL);
+
+ if (hEvent != NULL)
+ {
+ /* This should ensure that the object is reset, or
+ non-signaled.
+ */
+
+ dwRet = WaitForSingleObject(hEvent,0);
+
+ if (dwRet != WAIT_TIMEOUT)
+ {
+ Trace("CloseEventTest:WaitForSingleObject failed (%x)\n", GetLastError());
+ }
+ else
+ {
+ /* At this point, we've tested the function with success.
+ So long as the HANDLE can be closed, this test should
+ pass.
+ */
+
+ bRet = CloseHandle(hEvent);
+
+ if (!bRet)
+ {
+ Trace("CloseEventTest:CloseHandle failed (%x)\n", GetLastError());
+ }
+ }
+ }
+ else
+ {
+ Trace("CloseEventTest:CreateEvent failed (%x)\n", GetLastError());
+ }
+
+ return bRet;
+}
+
+int __cdecl main(int argc, char **argv)
+{
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return ( FAIL );
+ }
+
+ if(!CreateEventTest())
+ {
+ Fail ("Test failed\n");
+ }
+
+ PAL_Terminate();
+ return ( PASS );
+
+}
diff --git a/src/pal/tests/palsuite/threading/CreateEventA/test2/testinfo.dat b/src/pal/tests/palsuite/threading/CreateEventA/test2/testinfo.dat
new file mode 100644
index 0000000000..4af65f18d8
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CreateEventA/test2/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = CreateEvent
+Name = Positive Test for CreateEvent
+TYPE = DEFAULT
+EXE1 = test2
+Description
+= Test for CreateEvent. Create the event with the
+= initial state being not signaled. Check to ensure that it
+= times out when the event is triggered.
diff --git a/src/pal/tests/palsuite/threading/CreateEventA/test3/CMakeLists.txt b/src/pal/tests/palsuite/threading/CreateEventA/test3/CMakeLists.txt
new file mode 100644
index 0000000000..e33c404a79
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CreateEventA/test3/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test3.c
+)
+
+add_executable(paltest_createeventa_test3
+ ${SOURCES}
+)
+
+add_dependencies(paltest_createeventa_test3 coreclrpal)
+
+target_link_libraries(paltest_createeventa_test3
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/CreateEventA/test3/test3.c b/src/pal/tests/palsuite/threading/CreateEventA/test3/test3.c
new file mode 100644
index 0000000000..56d107b22d
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CreateEventA/test3/test3.c
@@ -0,0 +1,219 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: test3.c
+**
+** Purpose: Tests for CreateEventA. Create an event with an empty name,
+** create an event with the same name as an already created event
+** object.
+**
+**
+**=========================================================*/
+
+#include <palsuite.h>
+
+#define SWAPPTR ((VOID *)(-1))
+
+struct testCase
+{
+ LPSECURITY_ATTRIBUTES lpEventAttributes;
+ BOOL bManualReset;
+ BOOL bInitialState;
+ char lpName[MAX_PATH + 2];
+ DWORD dwNameLen;
+ DWORD lastError;
+ BOOL bResult;
+};
+
+struct testCase testCases[]=
+{
+ {0, TRUE, FALSE, "", 0, ERROR_SUCCESS, PASS},
+ {0, TRUE, FALSE, "", 5, ERROR_SUCCESS, PASS},
+ {0, TRUE, FALSE, "", 5, ERROR_ALREADY_EXISTS, PASS},
+ {0, TRUE, FALSE, "", 6, ERROR_INVALID_HANDLE, PASS},
+ {0, TRUE, FALSE, "", MAX_PATH - 1 - 60, ERROR_SUCCESS, PASS},
+ {0, TRUE, FALSE, "", MAX_PATH + 1, ERROR_FILENAME_EXCED_RANGE, PASS}
+};
+
+static HANDLE hEvent[sizeof(testCases)/sizeof(struct testCase)];
+
+DWORD result[sizeof(testCases)/sizeof(struct testCase)];
+
+int __cdecl main(int argc, char **argv)
+{
+
+ BOOL bRet = TRUE;
+ const char *nonEventName = "aaaaaa";
+ HANDLE hUnnamedEvent;
+ HANDLE hFMap;
+ DWORD dwRet;
+ int i;
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return ( FAIL );
+ }
+
+ hUnnamedEvent = CreateEventA(0, TRUE, FALSE, NULL);
+
+ if ( NULL == hUnnamedEvent )
+ {
+ bRet = FALSE;
+ Trace ( "PALSUITE ERROR: CreateEventA (%d, %d, %d, NULL) call "
+ "returned NULL.\nGetLastError returned %u.\n", 0, TRUE, FALSE,
+ GetLastError());
+ }
+
+ if (!CloseHandle(hUnnamedEvent))
+ {
+ bRet = FALSE;
+ Trace("PALSUITE ERROR: CreateEventA: CloseHandle(%lp); call "
+ "failed\nGetLastError returned '%u'.\n", hUnnamedEvent,
+ GetLastError());
+ }
+
+ /* Create non-event with the same name as one of the testCases */
+ hFMap = CreateFileMappingA( SWAPPTR, NULL, PAGE_READONLY, 0, 1,
+ nonEventName );
+
+ if ( NULL == hFMap )
+ {
+ bRet = FALSE;
+ Trace ( "PALSUITE ERROR: CreateFileMapping (%p, %p, %d, %d, %d, %s)"
+ " call returned NULL.\nGetLastError returned %u.\n",
+ SWAPPTR, NULL, PAGE_READONLY, 0, 0, nonEventName,
+ GetLastError());
+ goto done;
+ }
+
+ /* Create Events */
+ for (i = 0; i < sizeof(testCases)/sizeof(struct testCase); i++)
+ {
+ /* create name */
+ memset (testCases[i].lpName, '\0', (MAX_PATH + 2));
+ memset (testCases[i].lpName, 'a', testCases[i].dwNameLen );
+
+ SetLastError(ERROR_SUCCESS);
+
+ hEvent[i] = CreateEventA( testCases[i].lpEventAttributes,
+ testCases[i].bManualReset,
+ testCases[i].bInitialState,
+ testCases[i].lpName);
+
+ if (hEvent[i] != INVALID_HANDLE_VALUE)
+ {
+ DWORD dwError = GetLastError();
+
+ if (dwError != testCases[i].lastError)
+ {
+ bRet = FALSE;
+ Trace ("PALSUITE ERROR:\nCreateEventA(%lp, %d, %d, %s)"
+ "\nGetLastError returned '%u', it should have returned"
+ "'%d' at index '%d'.\n", testCases[i].lpEventAttributes,
+ testCases[i].bManualReset, testCases[i].bInitialState,
+ testCases[i].lpName, dwError,
+ testCases[i].lastError, i);
+ }
+ if ( ERROR_FILENAME_EXCED_RANGE == testCases[i].lastError )
+ {
+ result [i] = 1;
+ }
+ if ( ERROR_INVALID_HANDLE == testCases[i].lastError )
+ {
+ result [i] = 1;
+ }
+ /*
+ * If we expected the testcase to FAIL and it passed,
+ * report an error.
+ */
+ if (testCases[i].bResult == FAIL)
+ {
+ bRet = FALSE;
+ Trace ("PALSUITE ERROR:\nCreateEventA(%lp, %d, %d, %s)"
+ "\nShould have returned INVALID_HANDLE_VALUE but "
+ "didn't at index '%d'.\n",
+ testCases[i].lpEventAttributes,
+ testCases[i].bManualReset,
+ testCases[i].bInitialState,
+ testCases[i].lpName, i);
+ }
+ /*
+ * If result hasn't been set already set it to 0 so all the
+ * resources will be freed.
+ */
+ if (!result[i] )
+ {
+ result[i] = 0;
+ }
+ }
+ else
+ {
+ /*
+ * If we get an INVALID_HANDLE_VALUE and we expected the
+ * test case to pass, report an error.
+ */
+ result[i] = 1;
+
+ if (testCases[i].bResult == PASS)
+ {
+ bRet = FALSE;
+ Trace ("PALSUITE ERROR:\nCreateEventA(%lp, %d, %d, %s);"
+ "\nReturned INVALID_HANDLE_VALUE at index '%d'.\n",
+ testCases[i].lpEventAttributes,
+ testCases[i].bManualReset, testCases[i].bInitialState,
+ testCases[i].lpName, i);
+ }
+ }
+ }
+
+ /* cleanup */
+ for (i = 0; i < sizeof(testCases)/sizeof(struct testCase); i++)
+ {
+ if (result[i])
+ {
+ continue;
+ }
+ dwRet = WaitForSingleObject ( hEvent[i], 0 );
+
+ if (dwRet != WAIT_TIMEOUT)
+ {
+ bRet = FALSE;
+ Trace("PALSUITE ERROR: CreateEventA:\nWaitForSingleObject (%lp, "
+ "%d) call failed at index %d .\nGetLastError returned "
+ "'%u'.\n", hEvent[i], 0, i, GetLastError());
+ }
+
+ if (!CloseHandle(hEvent[i]))
+ {
+ bRet = FALSE;
+ Trace("PALSUITE ERROR: CreateEventA: CloseHandle(%lp) call "
+ "failed at index %d\nGetLastError returned '%u'.\n",
+ hEvent[i], i, GetLastError());
+ }
+ }
+
+done:
+ if (!CloseHandle(hFMap))
+ {
+ bRet = FALSE;
+ Trace("PALSUITE ERROR: CreateEventW: CloseHandle(%p) call "
+ "failed\nGetLastError returned '%u'.\n", hFMap,
+ GetLastError());
+ }
+
+ if (FALSE == bRet)
+ {
+ bRet = FAIL;
+ }
+ else
+ {
+ bRet = PASS;
+ }
+
+ PAL_TerminateEx(bRet);
+
+ return(bRet);
+}
diff --git a/src/pal/tests/palsuite/threading/CreateEventA/test3/testinfo.dat b/src/pal/tests/palsuite/threading/CreateEventA/test3/testinfo.dat
new file mode 100644
index 0000000000..c3a344a2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CreateEventA/test3/testinfo.dat
@@ -0,0 +1,16 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = CreateEventA
+Name = Positive Test for CreateEventA
+TYPE = DEFAULT
+EXE1 = test3
+Description
+= Tests for CreateEventA. Create an unnamed event, create
+= an event with an empty name, create an event with a name longer than
+= MAX_PATH, MAX_PATH + 1, create an event with a name already taken
+= by a non-event object, create an event with a name already taken
+= by an event object.
diff --git a/src/pal/tests/palsuite/threading/CreateEventW/CMakeLists.txt b/src/pal/tests/palsuite/threading/CreateEventW/CMakeLists.txt
new file mode 100644
index 0000000000..1962ade358
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CreateEventW/CMakeLists.txt
@@ -0,0 +1,6 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+add_subdirectory(test3)
+
diff --git a/src/pal/tests/palsuite/threading/CreateEventW/test1/CMakeLists.txt b/src/pal/tests/palsuite/threading/CreateEventW/test1/CMakeLists.txt
new file mode 100644
index 0000000000..0e8ba5bc2a
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CreateEventW/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_createeventw_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_createeventw_test1 coreclrpal)
+
+target_link_libraries(paltest_createeventw_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/CreateEventW/test1/test1.c b/src/pal/tests/palsuite/threading/CreateEventW/test1/test1.c
new file mode 100644
index 0000000000..8d99e41934
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CreateEventW/test1/test1.c
@@ -0,0 +1,93 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: test1.c
+**
+** Purpose: Test for CreateEventW
+**
+**
+**=========================================================*/
+
+/*
+ * Note: From the rotor_pal documentation: lpEventAttributes will
+ * always be NULL, bManualReset can be either TRUE or FALSE,
+ * bInitialState can be either TRUE or FALSE, the lpName may be
+ * non-NULL.
+*/
+#define UNICODE
+#include <palsuite.h>
+
+BOOL CreateEventTest()
+{
+ BOOL bRet = FALSE;
+ DWORD dwRet = 0;
+
+ LPSECURITY_ATTRIBUTES lpEventAttributes = NULL;
+ BOOL bManualReset = TRUE;
+ BOOL bInitialState = TRUE;
+
+ /*
+ * Call CreateEvent, and check to ensure the returned HANDLE is a
+ * valid event HANDLE
+ */
+
+ HANDLE hEvent = CreateEventW(lpEventAttributes,
+ bManualReset,
+ bInitialState,
+ NULL);
+
+ if (hEvent != NULL)
+ {
+ /*
+ * Wait for the Object (for 0 time) and ensure that it returns
+ * the value indicating that the event is signaled.
+ */
+ dwRet = WaitForSingleObject(hEvent,0);
+
+ if (dwRet != WAIT_OBJECT_0)
+ {
+ Trace("CreateEventTest:WaitForSingleObject failed (%x)\n", GetLastError());
+ }
+ else
+ {
+ /*
+ * If we make it here, and CloseHandle succeeds, then the
+ * entire test has passed. Otherwise bRet will still show
+ * failure
+ */
+ bRet = CloseHandle(hEvent);
+
+ if (!bRet)
+ {
+ Trace("CreateEventTest:CloseHandle failed (%x)\n", GetLastError());
+ }
+ }
+ }
+ else
+ {
+ Trace("CreateEventTest:CreateEvent failed (%x)\n", GetLastError());
+ }
+
+ return bRet;
+}
+
+int __cdecl main(int argc, char **argv)
+{
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return ( FAIL );
+ }
+
+ if(!CreateEventTest())
+ {
+ Fail ("Test failed\n");
+ }
+
+ PAL_Terminate();
+ return ( PASS );
+
+}
diff --git a/src/pal/tests/palsuite/threading/CreateEventW/test1/testinfo.dat b/src/pal/tests/palsuite/threading/CreateEventW/test1/testinfo.dat
new file mode 100644
index 0000000000..204ad1f4d4
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CreateEventW/test1/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = CreateEventW
+Name = Positive Test for CreateEventW
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Test for CreateEventW. Create an event, ensure the
+= HANDLE is valid. Then check to ensure that the object is in the
+= signaled state. Close the HANDLE and done.
diff --git a/src/pal/tests/palsuite/threading/CreateEventW/test2/CMakeLists.txt b/src/pal/tests/palsuite/threading/CreateEventW/test2/CMakeLists.txt
new file mode 100644
index 0000000000..f624377474
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CreateEventW/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test2.c
+)
+
+add_executable(paltest_createeventw_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_createeventw_test2 coreclrpal)
+
+target_link_libraries(paltest_createeventw_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/CreateEventW/test2/test2.c b/src/pal/tests/palsuite/threading/CreateEventW/test2/test2.c
new file mode 100644
index 0000000000..4df218995a
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CreateEventW/test2/test2.c
@@ -0,0 +1,85 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: test2.c
+**
+** Purpose: Test for CreateEventW. Create the event with the
+** initial state being not signaled. Check to ensure that it
+** times out when the event is triggered.
+**
+**
+**=========================================================*/
+#define UNICODE
+#include <palsuite.h>
+
+BOOL CreateEventTest()
+{
+ BOOL bRet = FALSE;
+ DWORD dwRet = 0;
+
+ LPSECURITY_ATTRIBUTES lpEventAttributes = 0;
+ BOOL bManualReset = TRUE;
+ BOOL bInitialState = FALSE;
+
+
+ /* Create an event with the Initial State set to FALSE */
+
+ HANDLE hEvent = CreateEventW(lpEventAttributes,
+ bManualReset,
+ bInitialState,
+ NULL);
+
+ if (hEvent != NULL)
+ {
+ /* This should ensure that the object is reset, or
+ non-signaled.
+ */
+
+ dwRet = WaitForSingleObject(hEvent,0);
+
+ if (dwRet != WAIT_TIMEOUT)
+ {
+ Trace("CloseEventTest:WaitForSingleObject failed (%x)\n", GetLastError());
+ }
+ else
+ {
+ /* At this point, we've tested the function with success.
+ So long as the HANDLE can be closed, this test should
+ pass.
+ */
+
+ bRet = CloseHandle(hEvent);
+
+ if (!bRet)
+ {
+ Trace("CloseEventTest:CloseHandle failed (%x)\n", GetLastError());
+ }
+ }
+ }
+ else
+ {
+ Trace("CloseEventTest:CreateEvent failed (%x)\n", GetLastError());
+ }
+
+ return bRet;
+}
+
+int __cdecl main(int argc, char **argv)
+{
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return ( FAIL );
+ }
+
+ if(!CreateEventTest())
+ {
+ Fail ("Test failed\n");
+ }
+
+ PAL_Terminate();
+ return ( PASS );
+
+}
diff --git a/src/pal/tests/palsuite/threading/CreateEventW/test2/testinfo.dat b/src/pal/tests/palsuite/threading/CreateEventW/test2/testinfo.dat
new file mode 100644
index 0000000000..01f7519ae3
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CreateEventW/test2/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = CreateEventW
+Name = Positive Test for CreateEventW
+TYPE = DEFAULT
+EXE1 = test2
+Description
+= Test for CreateEvent. Create the event with the
+= initial state being not signaled. Check to ensure that it
+= times out when the event is triggered.
diff --git a/src/pal/tests/palsuite/threading/CreateEventW/test3/CMakeLists.txt b/src/pal/tests/palsuite/threading/CreateEventW/test3/CMakeLists.txt
new file mode 100644
index 0000000000..4493ba3872
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CreateEventW/test3/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test3.c
+)
+
+add_executable(paltest_createeventw_test3
+ ${SOURCES}
+)
+
+add_dependencies(paltest_createeventw_test3 coreclrpal)
+
+target_link_libraries(paltest_createeventw_test3
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/CreateEventW/test3/test3.c b/src/pal/tests/palsuite/threading/CreateEventW/test3/test3.c
new file mode 100644
index 0000000000..22f0fcfc49
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CreateEventW/test3/test3.c
@@ -0,0 +1,233 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: test3.c
+**
+** Purpose: Tests for CreateEvent. Create an unnamed event, create
+** an event with an empty name, create an event with a name longer than
+** MAX_PATH, MAX_PATH + 1, create an event with a name already taken
+** by a non-event object, create an event with a name already taken
+** by an event object.
+**
+**
+**=========================================================*/
+#include <palsuite.h>
+
+#define SWAPPTR ((VOID *) (-1))
+
+struct testCase
+{
+ LPSECURITY_ATTRIBUTES lpEventAttributes;
+ BOOL bManualReset;
+ BOOL bInitialState;
+ WCHAR lpName[MAX_PATH + 2];
+ DWORD dwNameLen;
+ DWORD lastError;
+ BOOL bResult;
+};
+
+struct testCase testCases[]=
+{
+ {0, TRUE, FALSE, {'\0'}, 0, ERROR_SUCCESS, PASS},
+ {0, TRUE, FALSE, {'\0'}, 5, ERROR_SUCCESS, PASS},
+ {0, TRUE, FALSE, {'\0'}, 5, ERROR_ALREADY_EXISTS, PASS},
+ {0, TRUE, FALSE, {'\0'}, 6, ERROR_INVALID_HANDLE, PASS},
+ {0, TRUE, FALSE, {'\0'}, MAX_PATH - 1 - 60, ERROR_SUCCESS, PASS},
+ {0, TRUE, FALSE, {'\0'}, MAX_PATH - 60, ERROR_SUCCESS, PASS},
+};
+
+static HANDLE hEvent[sizeof(testCases)/sizeof(struct testCase)];
+
+DWORD result[sizeof(testCases)/sizeof(struct testCase)];
+
+int __cdecl main(int argc, char **argv)
+{
+
+ BOOL bRet = TRUE;
+ WCHAR nonEventName[] = {'a','a','a','a','a','a','\0'};
+ char name[MAX_PATH + 2];
+ WCHAR *wName;
+ HANDLE hFMap = NULL;
+ HANDLE hUnnamedEvent;
+ DWORD dwRet;
+ int i;
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return ( FAIL );
+ }
+
+ hUnnamedEvent = CreateEventW(0, TRUE, FALSE, NULL);
+
+ if ( NULL == hUnnamedEvent )
+ {
+ bRet = FALSE;
+ Trace ( "PALSUITE ERROR: CreateEventW (%d, %d, %d, NULL) call "
+ "returned NULL.\nGetLastError returned %u.\n", 0, TRUE, FALSE,
+ GetLastError());
+ goto done;
+ }
+
+ if (!CloseHandle(hUnnamedEvent))
+ {
+ bRet = FALSE;
+ Trace("PALSUITE ERROR: CreateEventW: CloseHandle(%lp); call "
+ "failed\nGetLastError returned '%u'.\n", hUnnamedEvent,
+ GetLastError());
+ }
+
+ /* Create non-event with the same name as one of the testCases */
+ hFMap = CreateFileMappingW( SWAPPTR, NULL, PAGE_READONLY, 0, 1,
+ nonEventName );
+
+ if ( NULL == hFMap )
+ {
+ bRet = FALSE;
+ Trace ( "PALSUITE ERROR: CreateFileMapping (%p, %p, %d, %d, %d, %S)"
+ " call returned NULL.\nGetLastError returned %u\n",
+ SWAPPTR, NULL, PAGE_READONLY, 0, 0, nonEventName,
+ GetLastError());
+ }
+
+ /* Create Events */
+ for (i = 0; i < sizeof(testCases)/sizeof(struct testCase); i++)
+ {
+ /* create name */
+ memset (name, '\0', MAX_PATH + 2);
+ memset (name, 'a', testCases[i].dwNameLen );
+
+ wName = convert(name);
+
+ wcsncpy(testCases[i].lpName, wName,
+ testCases[i].dwNameLen);
+
+ free(wName);
+
+ SetLastError(ERROR_SUCCESS);
+
+ hEvent[i] = CreateEventW( testCases[i].lpEventAttributes,
+ testCases[i].bManualReset,
+ testCases[i].bInitialState,
+ testCases[i].lpName);
+
+ if (hEvent[i] != INVALID_HANDLE_VALUE)
+ {
+ DWORD dwError = GetLastError();
+
+ if (dwError != testCases[i].lastError)
+ {
+ bRet = FALSE;
+ Trace ("PALSUITE ERROR:\nCreateEvent(%lp, %d, %d, %S)"
+ "\nGetLastError returned '%u', it should have returned"
+ "'%d' at index '%d'.\n", testCases[i].lpEventAttributes,
+ testCases[i].bManualReset, testCases[i].bInitialState,
+ testCases[i].lpName, dwError,
+ testCases[i].lastError, i);
+ }
+ if ( ERROR_FILENAME_EXCED_RANGE == testCases[i].lastError )
+ {
+ result [i] = 1;
+ }
+ if ( ERROR_INVALID_HANDLE == testCases[i].lastError )
+ {
+ result [i] = 1;
+ }
+ /*
+ * If we expected the testcase to FAIL and it passed,
+ * report an error.
+ */
+ if (testCases[i].bResult == FAIL)
+ {
+ bRet = FALSE;
+ Trace ("PALSUITE ERROR:\nCreateEvent(%lp, %d, %d, %S)"
+ "\nShould have returned INVALID_HANDLE_VALUE but "
+ "didn't at index '%d'.\n",
+ testCases[i].lpEventAttributes,
+ testCases[i].bManualReset,
+ testCases[i].bInitialState,
+ testCases[i].lpName, i);
+ }
+ /*
+ * If result hasn't been set already set it to 0 so all the
+ * resources will be freed.
+ */
+ if (!result[i])
+ {
+ result[i] = 0;
+ }
+ }
+ else
+ {
+ /*
+ * If we get an INVALID_HANDLE_VALUE and we expected the
+ * test case to pass, report an error.
+ */
+ result[i] = 1;
+
+ if (testCases[i].bResult == PASS)
+ {
+ bRet = FALSE;
+ Trace ("PALSUITE ERROR:\nCreateEvent(%lp, %d, %d, %S);"
+ "\nReturned INVALID_HANDLE_VALUE at index '%d'.\n",
+ testCases[i].lpEventAttributes,
+ testCases[i].bManualReset, testCases[i].bInitialState,
+ testCases[i].lpName, i);
+ }
+ }
+ }
+
+ /* cleanup */
+ for (i = 0; i < sizeof(testCases)/sizeof(struct testCase); i++)
+ {
+ if (result[i])
+ {
+ continue;
+ }
+ dwRet = WaitForSingleObject ( hEvent[i], 0 );
+
+ if (dwRet != WAIT_TIMEOUT)
+ {
+ bRet = FALSE;
+ Trace("PALSUITE ERROR: CreateEventW:\nWaitForSingleObject (%lp, "
+ "%d) call failed at index %d .\nGetLastError returned "
+ "'%u'.\n", hEvent[i], 0, i, GetLastError());
+ }
+
+ if (!CloseHandle(hEvent[i]))
+ {
+ bRet = FALSE;
+ Trace("PALSUITE ERROR: CreateEventW: CloseHandle(%lp) call "
+ "failed at index %d\nGetLastError returned '%u'.\n",
+ hEvent[i], i, GetLastError());
+ }
+ }
+
+done:
+ if (hFMap != NULL && !CloseHandle(hFMap))
+ {
+ bRet = FALSE;
+ Trace("PALSUITE ERROR: CreateEventW: CloseHandle(%p) call "
+ "failed\nGetLastError returned '%u'.\n", hFMap,
+ GetLastError());
+ }
+
+ if (FALSE == bRet)
+ {
+ bRet = FAIL;
+ }
+ else
+ {
+ bRet = PASS;
+ }
+
+ PAL_TerminateEx(bRet);
+
+ return(bRet);
+
+}
+
+
+
diff --git a/src/pal/tests/palsuite/threading/CreateEventW/test3/testinfo.dat b/src/pal/tests/palsuite/threading/CreateEventW/test3/testinfo.dat
new file mode 100644
index 0000000000..4776ed239f
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CreateEventW/test3/testinfo.dat
@@ -0,0 +1,16 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = CreateEventW
+Name = Positive Test for CreateEventW
+TYPE = DEFAULT
+EXE1 = test3
+Description
+= Tests for CreateEventW. Create an unnamed event, create
+= an event with an empty name, create an event with a name longer than
+= MAX_PATH, MAX_PATH + 1, create an event with a name already taken
+= by a non-event object, create an event with a name already taken
+= by an event object.
diff --git a/src/pal/tests/palsuite/threading/CreateMutexA_ReleaseMutex/CMakeLists.txt b/src/pal/tests/palsuite/threading/CreateMutexA_ReleaseMutex/CMakeLists.txt
new file mode 100644
index 0000000000..ef14ea5352
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CreateMutexA_ReleaseMutex/CMakeLists.txt
@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+
diff --git a/src/pal/tests/palsuite/threading/CreateMutexA_ReleaseMutex/test1/CMakeLists.txt b/src/pal/tests/palsuite/threading/CreateMutexA_ReleaseMutex/test1/CMakeLists.txt
new file mode 100644
index 0000000000..ffdf13228e
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CreateMutexA_ReleaseMutex/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ CreateMutexA.c
+)
+
+add_executable(paltest_createmutexa_releasemutex_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_createmutexa_releasemutex_test1 coreclrpal)
+
+target_link_libraries(paltest_createmutexa_releasemutex_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/CreateMutexA_ReleaseMutex/test1/CreateMutexA.c b/src/pal/tests/palsuite/threading/CreateMutexA_ReleaseMutex/test1/CreateMutexA.c
new file mode 100644
index 0000000000..52bab351fb
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CreateMutexA_ReleaseMutex/test1/CreateMutexA.c
@@ -0,0 +1,345 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: CreateMutexA_ReleaseMutex/test1/CreateMutexA.c
+**
+** Purpose: This test case tests whether a Mutex object created
+** with CreateMutex really works by mutually excluding
+** threads from accessing a data structure at the same
+** time. Here we have a buffer that can be filled or
+** emptied, we use a Mutex object to ensure that one
+** operation cannot be started until the other is
+** finished. If one operation detects that the other
+** has not finished, it fails. There is a Producer
+** thread which will try to fill the buffer 25 times,
+** and a consumer thread which try to empty the buffer
+** 25 times. If either the fill or empty operations
+** fails because the Mutex failed to mutually exclude
+** them, the corresponding thread will set an error
+** flag and return. This will cause the test case to
+** fail.
+**
+** To increase the probability of identifying problems,
+** the Fill opeartion has been slowed down with a call
+** to Sleep. This ensures that one operation will try
+** to access the shared buffer while the other is in
+** progress.
+**
+** NOTE: this test case also serves as a test case for
+** WaitForSingleObject.
+**
+**
+** Dependencies: CreateThread
+** ReleaseMutex
+** WaitForSingleObject
+** WaitForMultipleObjects
+** Sleep
+** memset
+**
+
+**
+**=========================================================*/
+
+#define UNICODE
+#include <palsuite.h>
+
+/* Define some values that we will using many times */
+#define MAIN_BUF_SIZE 40
+#define NUM_OF_CYCLES 40
+
+/* Buffer Operation return codes */
+#define OP_OK 0
+#define OP_ERR 1
+#define OP_NONE 2
+
+
+HANDLE hMutex; /* handle to mutex */
+
+BOOL bProdErr; /* Producer error Flag */
+BOOL bConErr; /* Consumer error Flag */
+
+/* Test Buffer */
+char Buffer[MAIN_BUF_SIZE];
+
+/*
+ * EmptyBuffer implements the empty operation for test buffer.
+ */
+int
+EmptyBuffer()
+{
+ int i;
+
+ if ( WaitForSingleObject(hMutex, INFINITE) == WAIT_FAILED)
+ {
+ Fail("ERROR: WaitForSingleObject failed.\n");
+ }
+
+ /* Check to see if the buffer is already completely empty */
+ for (i=0; i<MAIN_BUF_SIZE && Buffer[i] == 0; i++);
+ if (i == MAIN_BUF_SIZE)
+ {
+ /* Its empty so just return */
+ if (ReleaseMutex(hMutex) == FALSE)
+ {
+ Fail("ERROR: ReleaseMutex Failed.\n");
+ }
+ return OP_NONE;
+ }
+
+ /* Its not empty so we must empty it. */
+ for (i=0; i<MAIN_BUF_SIZE; i++)
+ {
+ /* Check for empty slots if we find one then the */
+ /* fill operation did no finish. return an error */
+ if (Buffer[i] == 0)
+ {
+ if (ReleaseMutex(hMutex) == FALSE)
+ {
+ Fail("ERROR: ReleaseMutex Failed.\n");
+ }
+ return OP_ERR;
+ }
+
+ Buffer[i] = 0;
+ }
+
+ if (ReleaseMutex(hMutex) == FALSE)
+ {
+ Fail("ERROR: ReleaseMutex Failed.\n");
+ }
+ return OP_OK;
+}
+
+/*
+ * FillBuffer implements the fill operation for test buffer.
+ */
+int
+FillBuffer()
+{
+ int i;
+
+ if ( WaitForSingleObject(hMutex, INFINITE) == WAIT_FAILED)
+ {
+ Fail("ERROR: WaitForSingleObject failed.\n");
+ }
+
+ /* Check to see if the buffer is already completely full */
+ for (i=0; i<MAIN_BUF_SIZE && Buffer[i] != 0; i++);
+ if (i == MAIN_BUF_SIZE)
+ {
+ /* Its full so just return */
+ if (ReleaseMutex(hMutex) == FALSE)
+ {
+ Fail("ERROR: ReleaseMutex Failed.\n");
+ }
+ return OP_NONE;
+ }
+
+ /* Its not full so we must fill it. */
+ for (i=0; i<MAIN_BUF_SIZE; i++)
+ {
+ /* Check for filled slots if we find one then the */
+ /* empty operation did not finish. return an error */
+ if (Buffer[i] == 1)
+ {
+ if (ReleaseMutex(hMutex) == FALSE)
+ {
+ Fail("ERROR: ReleaseMutex Failed.\n");
+ }
+ return OP_ERR;
+ }
+
+ Buffer[i] = 1;
+ Sleep(10);
+ }
+
+ if (ReleaseMutex(hMutex) == FALSE)
+ {
+ Fail("ERROR: ReleaseMutex Failed.\n");
+ }
+ return OP_OK;
+}
+
+
+
+
+/*
+ * Producer thread function.
+ */
+DWORD
+Producer(LPVOID lpParam)
+{
+ int n = 0;
+ int ret;
+
+ while (n < NUM_OF_CYCLES)
+ {
+ if (bConErr == TRUE)
+ {
+ /* The consumer ran into an error so we'll stop */
+ return 0;
+ }
+
+ ret = FillBuffer();
+
+ if (ret == OP_OK)
+ {
+ n++;
+ }
+ else if (ret == OP_ERR)
+ {
+ bProdErr = TRUE;
+ return 0;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Consumer thread function.
+ */
+DWORD Consumer( LPVOID lpParam )
+{
+ int n = 0;
+ int ret;
+
+ while (n < NUM_OF_CYCLES)
+ {
+ if (bProdErr == TRUE)
+ {
+ /* The consumer ran into an error so we'll stop */
+ return 0;
+ }
+
+ ret = EmptyBuffer();
+
+ if (ret == OP_OK)
+ {
+ n++;
+ }
+ else if (ret == OP_ERR)
+ {
+ bConErr = TRUE;
+ return 0;
+ }
+ }
+
+ return 0;
+}
+
+
+int __cdecl main (int argc, char **argv)
+{
+ DWORD dwThreadId;
+ DWORD dwWaitRet;
+
+ HANDLE hThread1; /* handle to consumer thread */
+ HANDLE hThread2; /* handle to producer thread */
+ HANDLE handleArray[2];
+
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return ( FAIL );
+ }
+
+ /* Initialize our error flags */
+ bProdErr = FALSE;
+ bConErr = FALSE;
+
+ /*
+ * Initialize the Buffer to be empty
+ */
+ memset(Buffer, 0, MAIN_BUF_SIZE);
+
+ /*
+ * Create Mutex
+ */
+ hMutex = CreateMutexA (NULL, FALSE, NULL);
+
+ if (NULL == hMutex)
+ {
+ Fail("hMutex = CreateMutexA() - returned NULL\n"
+ "Failing Test.\nGetLastError returned %u\n", GetLastError());
+ }
+
+
+ /*
+ * Create the Producer thread
+ */
+ hThread1 = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)Producer,
+ 0, 0, &dwThreadId);
+
+ if ( NULL == hThread1 )
+ {
+ CloseHandle(hMutex);
+
+ Fail("CreateThread() returned NULL. Failing test.\n"
+ "GetLastError returned %u\n", GetLastError());
+ }
+
+ /*
+ * Create the Consumer thread
+ */
+ hThread2 = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)Consumer,
+ 0, 0, &dwThreadId);
+
+ if ( NULL == hThread2 )
+ {
+ CloseHandle(hMutex);
+
+ /* Set the error flag and give thread1 some time to exit */
+ bConErr = FALSE;
+ Sleep(250);
+
+ Fail("CreateThread() returned NULL. Failing test.\n"
+ "GetLastError returned %u\n", GetLastError());
+ }
+
+ /*
+ * Wait for both threads to complete (Max 45 Seconds)
+ */
+ handleArray[0] = hThread1;
+ handleArray[1] = hThread2;
+ dwWaitRet = WaitForMultipleObjects (2, handleArray, TRUE, 450000);
+ if (dwWaitRet == WAIT_FAILED)
+ {
+ Fail("ERROR: WaitForMultipleObjects failed.\n");
+ }
+ else if (dwWaitRet == WAIT_TIMEOUT)
+ {
+ /* Set the error flags and give the threads some time to exit */
+ bProdErr = FALSE;
+ bConErr = FALSE;
+ Sleep(250);
+
+ Fail("ERROR: Timeout interval exceeded.\n");
+ }
+
+ /*
+ * Clean up
+ */
+ if (CloseHandle(hThread1) == FALSE ||
+ CloseHandle(hThread2) == FALSE ||
+ CloseHandle(hMutex) == FALSE)
+ {
+ Fail("ERROR: CloseHandle failed.\n");
+ }
+
+
+ /*
+ * Check our error flags
+ */
+ if (bProdErr == TRUE || bConErr == TRUE)
+ {
+ Fail("ERROR: A collision occurred, so the mutex failed.\n");
+ }
+
+ PAL_Terminate();
+ return ( PASS );
+
+}
diff --git a/src/pal/tests/palsuite/threading/CreateMutexA_ReleaseMutex/test1/testinfo.dat b/src/pal/tests/palsuite/threading/CreateMutexA_ReleaseMutex/test1/testinfo.dat
new file mode 100644
index 0000000000..829b7159ac
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CreateMutexA_ReleaseMutex/test1/testinfo.dat
@@ -0,0 +1,33 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = CreateMutexA / ReleaseMutex
+Name = Positive Test for CreateMutexA and ReleaseMutex
+TYPE = DEFAULT
+EXE1 = createmutexa
+Description
+= This test cases test whether a Mutex object created
+= with CreateMutexA really works by mutually excluding
+= threads from accessing a data structure at the same
+= time. Here we have a buffer that can be filled or
+= emptied, we use a Mutex object to ensure that one
+= operation cannot be started until the other is
+= finished. If one operation detects that the other
+= has not finished, it fails. There is a Producer
+= thread which will try to fill the buffer 25 times,
+= and a consumer thread which try to empty the buffer
+= 25 times. If either the fill or empty operations
+= fails because the Mutex failed to mutually exclude
+= then, the corresponding thread will set an error
+= flag and return. This will cause the test case to
+= fail.
+= To increase the probability of identifying problems,
+= the Fill opeartion has been slowed dowm with a call
+= to Sleep. This ensures that one operation will try
+= to access the shared buffer while the other is in
+= progress.
+= NOTE: this test case also serves as a test case for
+= WaitForSingleObject.
diff --git a/src/pal/tests/palsuite/threading/CreateMutexA_ReleaseMutex/test2/CMakeLists.txt b/src/pal/tests/palsuite/threading/CreateMutexA_ReleaseMutex/test2/CMakeLists.txt
new file mode 100644
index 0000000000..925c5d41f6
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CreateMutexA_ReleaseMutex/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ CreateMutexA.c
+)
+
+add_executable(paltest_createmutexa_releasemutex_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_createmutexa_releasemutex_test2 coreclrpal)
+
+target_link_libraries(paltest_createmutexa_releasemutex_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/CreateMutexA_ReleaseMutex/test2/CreateMutexA.c b/src/pal/tests/palsuite/threading/CreateMutexA_ReleaseMutex/test2/CreateMutexA.c
new file mode 100644
index 0000000000..3b83ba9674
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CreateMutexA_ReleaseMutex/test2/CreateMutexA.c
@@ -0,0 +1,331 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: CreateMutexA_ReleaseMutex/test2/CreateMutexA.c
+**
+** Purpose: This test case tests the following things
+** - Creation of named Mutexes
+** - Creating multiple handles to a single named Mutex
+** - Ensuring that these handles work interchangeably
+** - Setting bInitialOwnerFlag to TRUE will cause the
+** initial call to a Wait function on the same Mutex
+** to actually wait.
+** - Waiting on a Mutex that a thread already owns does
+** not block.
+** - Create Named mutex with empty string ("")
+** - Create Named mutex with string of MAX_LONGPATH length
+** - Calling RelaseMutex with invalid Mutex handles and
+** valid but unowned Mutexes.
+**
+** Dependencies: CreateThread
+** ReleaseMutex
+** WaitForSingleObject
+** CloseHandle
+** Sleep
+** memset
+**
+
+**
+**=========================================================*/
+
+#define UNICODE
+#include <palsuite.h>
+
+const char *szMutex = "MyMutex";
+const char *szEmpty = "";
+
+/* Function Prototypes */
+BOOL TestNamedMutex(const char *szMutexName);
+DWORD NamedMutexThread(LPVOID lpParam);
+BOOL NegativeReleaseMutexTests();
+
+struct ThreadData
+{
+ HANDLE hMutex;
+ BOOL bReturnCode;
+};
+typedef struct ThreadData THREADDATA;
+
+
+int __cdecl main (int argc, char **argv)
+{
+ BOOL bFailures = FALSE;
+ char *szMaxPath;
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return ( FAIL );
+ }
+
+
+ /*
+ * Test named Mutexes with ordinary string
+ */
+
+ if (!TestNamedMutex(szMutex))
+ {
+ bFailures = TRUE;
+ }
+
+
+ /*
+ * Test named Mutexes with empty ("") string
+ */
+
+ if (!TestNamedMutex(szEmpty))
+ {
+ bFailures = TRUE;
+ }
+
+
+ /*
+ * Test named Mutexes with string of length MAX_LONGPATHPATH
+ */
+
+ szMaxPath = (char *)malloc(MAX_LONGPATH+2);
+ memset(szMaxPath, 'A', MAX_LONGPATH-60);
+ szMaxPath[MAX_LONGPATH-60] = 0;
+
+ if (!TestNamedMutex(szMaxPath))
+ {
+ bFailures = TRUE;
+ }
+
+ free(szMaxPath);
+
+
+ /*
+ * Run some negative tests on ReleaseMutex
+ */
+
+ if (!NegativeReleaseMutexTests())
+ {
+ bFailures = TRUE;
+ }
+
+
+ /*
+ * If there were any failures, then abort with a call to Fail
+ */
+
+ if (bFailures == TRUE)
+ {
+ Fail("ERROR: There some failures in the Mutex tests.\n");
+ }
+
+ PAL_Terminate();
+ return ( PASS );
+}
+
+
+/*
+ * Testing Function
+ *
+ * Try to get multiple handles to a named Mutex and test
+ * to make sure they actually refer to same Mutex object.
+ */
+BOOL TestNamedMutex(const char *szMutexName)
+{
+ DWORD dwData;
+ HANDLE hMutex1;
+ HANDLE hMutex2;
+ HANDLE hThread;
+ THREADDATA threadData;
+
+ /* Create a mutex and take ownership immediately */
+ hMutex1 = CreateMutexA (NULL, TRUE, szMutexName);
+
+ if (NULL == hMutex1)
+ {
+ Trace("ERROR: CreateMutexA #1 failed. GetLastError returned %u\n",
+ GetLastError());
+ return FALSE;
+ }
+
+ /* Try to wait on the Mutex we just created. We should not block. */
+ if (WaitForSingleObject(hMutex1, 1000) == WAIT_TIMEOUT)
+ {
+ Trace("WaitForSingleObject blocked on a Mutex that we owned.\n");
+ return FALSE;
+ }
+ /* We have to call ReleaseMutex here because of the Wait */
+ if (ReleaseMutex(hMutex1) == FALSE)
+ {
+ Trace("ReleaseMutex Failed.\n");
+ return FALSE;
+ }
+
+ /* Get a second handle to the same mutex */
+ hMutex2 = CreateMutexA (NULL, FALSE, szMutexName);
+
+ if (NULL == hMutex2)
+ {
+ Trace("ERROR: CreateMutex #2 failed. GetLastError returned %u\n",
+ GetLastError());
+ free(szMutexName);
+ return FALSE;
+ }
+
+ /*
+ * Create a thread that will Wait on the second handle.
+ */
+ threadData.hMutex = hMutex2;
+ hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)NamedMutexThread,
+ (LPVOID)&threadData, 0, &dwData);
+
+ if (NULL == hThread)
+ {
+ Trace("ERROR: CreateThread failed. GetLastError returned %u\n",
+ GetLastError());
+ return FALSE;
+ }
+
+ /* Give the thread a little time to execute & wait*/
+ Sleep(500);
+
+ /* Signal the the first handle */
+ if (ReleaseMutex(hMutex1) == FALSE)
+ {
+ Trace("ReleaseMutex Failed.\n");
+ return FALSE;
+ }
+
+ /* Give the thread some time to finish */
+ Sleep(2000);
+
+ /* Clean Up */
+ if (CloseHandle(hMutex1) == FALSE ||
+ CloseHandle(hMutex2) == FALSE ||
+ CloseHandle(hThread) == FALSE)
+ {
+ Trace("ERROR: CloseHandle failed.\n");
+ return FALSE;
+ }
+
+ /* Check the return code to see if signalling the first */
+ /* Mutex handle woke up the thread which was Waiting on */
+ /* the second handle. */
+ if (threadData.bReturnCode != FALSE)
+ {
+ Trace("ERROR: The handles did not refer to the same Mutex object.\n");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+/*
+ * Thread function used with above testing function.
+ */
+DWORD NamedMutexThread(LPVOID lpParam)
+{
+ BOOL bTimedOut = FALSE;
+ THREADDATA *lpThreadData = (THREADDATA *)lpParam;
+
+ /* Wait on the Mutex that was passed to us */
+ if (WaitForSingleObject(lpThreadData->hMutex, 10000) == WAIT_TIMEOUT)
+ {
+ /* The Mutex was not signaled in the allotted time */
+ bTimedOut = TRUE;
+ }
+ if (ReleaseMutex(lpThreadData->hMutex) == FALSE)
+ {
+ Trace("ERROR: ReleaseMutex failed.\n");
+ lpThreadData->bReturnCode = FALSE;
+ return 0;
+ }
+
+ /* Indicate whether we timed out Waiting on the Mutex */
+ lpThreadData->bReturnCode = bTimedOut;
+
+ return 0;
+}
+
+
+/*
+ * Testing Function
+ *
+ * Try some negative tests on ReleaseMutex
+ */
+BOOL NegativeReleaseMutexTests()
+{
+ HANDLE hMutex;
+ BOOL bRet;
+ BOOL bResults = TRUE;
+
+
+ /*
+ * Try calling ReleaseMutex on a null handle
+ */
+ hMutex = 0;
+ bRet = ReleaseMutex(hMutex);
+
+ if (bRet != 0)
+ {
+ Trace("Error: ReleaseMutex accepted null handle.\n");
+ bResults = FALSE;
+ }
+
+
+ /*
+ * Try calling ReleaseMutex on an handle that we don't own
+ */
+ hMutex = CreateMutexA (NULL, TRUE, NULL);
+ if (hMutex == 0)
+ {
+ Trace("Error: CreateMutex failed.\n");
+ bResults = FALSE;
+ }
+
+ bRet = ReleaseMutex(hMutex);
+ bRet = ReleaseMutex(hMutex);
+
+ if (bRet != FALSE)
+ {
+ Trace("Error: ReleaseMutex accepted unowned handle.\n");
+ bResults = FALSE;
+ }
+
+ if (CloseHandle(hMutex) == FALSE)
+ {
+ Trace("Error: CloseHandle failed.\n");
+ bResults = FALSE;
+ }
+
+
+
+ /*
+ * Try calling ReleaseMutex on an handle that has been closed
+ */
+ hMutex = CreateMutexA (NULL, TRUE, NULL);
+ if (hMutex == 0)
+ {
+ Trace("Error: CreateMutex failed.\n");
+ bResults = FALSE;
+ }
+
+ if (ReleaseMutex(hMutex) == FALSE)
+ {
+ Trace("Error: ReleaseMutex failed.\n");
+ bResults = FALSE;
+ }
+ if (CloseHandle(hMutex) == FALSE)
+ {
+ Trace("Error: CloseHandle failed.\n");
+ bResults = FALSE;
+ }
+
+ bRet = ReleaseMutex(hMutex);
+
+ if (bRet != FALSE)
+ {
+ Trace("Error: ReleaseMutex accepted invalid handle.\n");
+ bResults = FALSE;
+ }
+
+ return bResults;
+}
diff --git a/src/pal/tests/palsuite/threading/CreateMutexA_ReleaseMutex/test2/testinfo.dat b/src/pal/tests/palsuite/threading/CreateMutexA_ReleaseMutex/test2/testinfo.dat
new file mode 100644
index 0000000000..7e37528c15
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CreateMutexA_ReleaseMutex/test2/testinfo.dat
@@ -0,0 +1,24 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = CreateMutexA / ReleaseMutex
+Name = Basic validity Tests for CreateMutexA / ReleaseMutex
+TYPE = DEFAULT
+EXE1 = createmutexa
+Description
+= This test case tests the following things
+= - Creation of named Mutexes
+= - Creating multiple handles to a single named Mutex
+= - Ensuring that these handles work interchangeably
+= - Setting bInitialOwnerFlag to TRUE will cause the
+= initial call to a Wait function on the same Mutex
+= to actually wait.
+= - Waiting on a Mutex that a thread already owns should
+= not block.
+= - Create Named mutex with empty string ("")
+= - Create Named mutex with string of MAX_PATH length
+= - Calling RelaseMutex with invalid Mutex handles and
+= valid but unowned Mutexes.
diff --git a/src/pal/tests/palsuite/threading/CreateMutexW_ReleaseMutex/CMakeLists.txt b/src/pal/tests/palsuite/threading/CreateMutexW_ReleaseMutex/CMakeLists.txt
new file mode 100644
index 0000000000..ef14ea5352
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CreateMutexW_ReleaseMutex/CMakeLists.txt
@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+
diff --git a/src/pal/tests/palsuite/threading/CreateMutexW_ReleaseMutex/test1/CMakeLists.txt b/src/pal/tests/palsuite/threading/CreateMutexW_ReleaseMutex/test1/CMakeLists.txt
new file mode 100644
index 0000000000..a73ee045a3
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CreateMutexW_ReleaseMutex/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ CreateMutexW.c
+)
+
+add_executable(paltest_createmutexw_releasemutex_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_createmutexw_releasemutex_test1 coreclrpal)
+
+target_link_libraries(paltest_createmutexw_releasemutex_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/CreateMutexW_ReleaseMutex/test1/CreateMutexW.c b/src/pal/tests/palsuite/threading/CreateMutexW_ReleaseMutex/test1/CreateMutexW.c
new file mode 100644
index 0000000000..c21bfb6a50
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CreateMutexW_ReleaseMutex/test1/CreateMutexW.c
@@ -0,0 +1,345 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: CreateMutexW_ReleaseMutex/test1/CreateMutexW.c
+**
+** Purpose: This test case tests whether a Mutex object created
+** with CreateMutex really works by mutually excluding
+** threads from accessing a data structure at the same
+** time. Here we have a buffer that can be filled or
+** emptied, we use a Mutex object to ensure that one
+** operation cannot be started until the other is
+** finished. If one operation detects that the other
+** has not finished, it fails. There is a Producer
+** thread which will try to fill the buffer 25 times,
+** and a consumer thread which try to empty the buffer
+** 25 times. If either the fill or empty operations
+** fails because the Mutex failed to mutually exclude
+** them, the corresponding thread will set an error
+** flag and return. This will cause the test case to
+** fail.
+**
+** To increase the probability of identifying problems,
+** the Fill opeartion has been slowed dowm with a call
+** to Sleep. This ensures that one operation will try
+** to access the shared buffer while the other is in
+** progress.
+**
+** NOTE: this test case also serves as a test case for
+** WaitForSingleObject.
+**
+**
+** Dependencies: CreateThread
+** ReleaseMutex
+** WaitForSingleObject
+** WaitForMultipleObjects
+** Sleep
+** memset
+**
+
+**
+**=========================================================*/
+
+#define UNICODE
+#include <palsuite.h>
+
+/* Define some values that we will using many times */
+#define MAIN_BUF_SIZE 40
+#define NUM_OF_CYCLES 40
+
+/* Buffer Operation return codes */
+#define OP_OK 0
+#define OP_ERR 1
+#define OP_NONE 2
+
+
+HANDLE hMutex; /* handle to mutex */
+
+BOOL bProdErr; /* Producer error Flag */
+BOOL bConErr; /* Consumer error Flag */
+
+/* Test Buffer */
+char Buffer[MAIN_BUF_SIZE];
+
+/*
+ * EmptyBuffer implements the empty operation for test buffer.
+ */
+int
+EmptyBuffer()
+{
+ int i;
+
+ if ( WaitForSingleObject(hMutex, INFINITE) == WAIT_FAILED)
+ {
+ Fail("ERROR: WaitForSingleObject failed.\n");
+ }
+
+ /* Check to see if the buffer is already completely empty */
+ for (i=0; i<MAIN_BUF_SIZE && Buffer[i] == 0; i++);
+ if (i == MAIN_BUF_SIZE)
+ {
+ /* Its empty so just return */
+ if (ReleaseMutex(hMutex) == FALSE)
+ {
+ Fail("ERROR: ReleaseMutex Failed.\n");
+ }
+ return OP_NONE;
+ }
+
+ /* Its not empty so we must empty it. */
+ for (i=0; i<MAIN_BUF_SIZE; i++)
+ {
+ /* Check for empty slots if we find one then the */
+ /* fill operation did no finish. return an error */
+ if (Buffer[i] == 0)
+ {
+ if (ReleaseMutex(hMutex) == FALSE)
+ {
+ Fail("ERROR: ReleaseMutex Failed.\n");
+ }
+ return OP_ERR;
+ }
+
+ Buffer[i] = 0;
+ }
+
+ if (ReleaseMutex(hMutex) == FALSE)
+ {
+ Fail("ERROR: ReleaseMutex Failed.\n");
+ }
+ return OP_OK;
+}
+
+/*
+ * FillBuffer implements the fill operation for test buffer.
+ */
+int
+FillBuffer()
+{
+ int i;
+
+ if ( WaitForSingleObject(hMutex, INFINITE) == WAIT_FAILED)
+ {
+ Fail("ERROR: WaitForSingleObject failed.\n");
+ }
+
+ /* Check to see if the buffer is already completely full */
+ for (i=0; i<MAIN_BUF_SIZE && Buffer[i] != 0; i++);
+ if (i == MAIN_BUF_SIZE)
+ {
+ /* Its full so just return */
+ if (ReleaseMutex(hMutex) == FALSE)
+ {
+ Fail("ERROR: ReleaseMutex Failed.\n");
+ }
+ return OP_NONE;
+ }
+
+ /* Its not full so we must fill it. */
+ for (i=0; i<MAIN_BUF_SIZE; i++)
+ {
+ /* Check for filled slots if we find one then the */
+ /* empty operation did not finish. return an error */
+ if (Buffer[i] == 1)
+ {
+ if (ReleaseMutex(hMutex) == FALSE)
+ {
+ Fail("ERROR: ReleaseMutex Failed.\n");
+ }
+ return OP_ERR;
+ }
+
+ Buffer[i] = 1;
+ Sleep(10);
+ }
+
+ if (ReleaseMutex(hMutex) == FALSE)
+ {
+ Fail("ERROR: ReleaseMutex Failed.\n");
+ }
+ return OP_OK;
+}
+
+
+
+
+/*
+ * Producer thread function.
+ */
+DWORD
+Producer(LPVOID lpParam)
+{
+ int n = 0;
+ int ret;
+
+ while (n < NUM_OF_CYCLES)
+ {
+ if (bConErr == TRUE)
+ {
+ /* The consumer ran into an error so we'll stop */
+ return 0;
+ }
+
+ ret = FillBuffer();
+
+ if (ret == OP_OK)
+ {
+ n++;
+ }
+ else if (ret == OP_ERR)
+ {
+ bProdErr = TRUE;
+ return 0;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Consumer thread function.
+ */
+DWORD Consumer( LPVOID lpParam )
+{
+ int n = 0;
+ int ret;
+
+ while (n < NUM_OF_CYCLES)
+ {
+ if (bProdErr == TRUE)
+ {
+ /* The consumer ran into an error so we'll stop */
+ return 0;
+ }
+
+ ret = EmptyBuffer();
+
+ if (ret == OP_OK)
+ {
+ n++;
+ }
+ else if (ret == OP_ERR)
+ {
+ bConErr = TRUE;
+ return 0;
+ }
+ }
+
+ return 0;
+}
+
+
+int __cdecl main (int argc, char **argv)
+{
+ DWORD dwThreadId;
+ DWORD dwWaitRet;
+
+ HANDLE hThread1; /* handle to consumer thread */
+ HANDLE hThread2; /* handle to producer thread */
+ HANDLE handleArray[2];
+
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return ( FAIL );
+ }
+
+ /* Initialize our error flags */
+ bProdErr = FALSE;
+ bConErr = FALSE;
+
+ /*
+ * Initialize the Buffer to be empty
+ */
+ memset(Buffer, 0, MAIN_BUF_SIZE);
+
+ /*
+ * Create Mutex
+ */
+ hMutex = CreateMutexW (NULL, FALSE, NULL);
+
+ if (NULL == hMutex)
+ {
+ Fail("hMutex = CreateMutexW() - returned NULL\n"
+ "Failing Test.\nGetLastError returned %u\n", GetLastError());
+ }
+
+
+ /*
+ * Create the Producer thread
+ */
+ hThread1 = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)Producer,
+ 0, 0, &dwThreadId);
+
+ if ( NULL == hThread1 )
+ {
+ CloseHandle(hMutex);
+
+ Fail("CreateThread() returned NULL. Failing test.\n"
+ "GetLastError returned %u\n", GetLastError());
+ }
+
+ /*
+ * Create the Consumer thread
+ */
+ hThread2 = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)Consumer,
+ 0, 0, &dwThreadId);
+
+ if ( NULL == hThread2 )
+ {
+ CloseHandle(hMutex);
+
+ /* Set the error flag and give thread1 some time to exit */
+ bConErr = FALSE;
+ Sleep(250);
+
+ Fail("CreateThread() returned NULL. Failing test.\n"
+ "GetLastError returned %u\n", GetLastError());
+ }
+
+ /*
+ * Wait for both threads to complete (Max 45 Seconds)
+ */
+ handleArray[0] = hThread1;
+ handleArray[1] = hThread2;
+ dwWaitRet = WaitForMultipleObjects (2, handleArray, TRUE, 450000);
+ if (dwWaitRet == WAIT_FAILED)
+ {
+ Fail("ERROR: WaitForMultipleObjects failed.\n");
+ }
+ else if (dwWaitRet == WAIT_TIMEOUT)
+ {
+ /* Set the error flags and give the threads some time to exit */
+ bProdErr = FALSE;
+ bConErr = FALSE;
+ Sleep(250);
+
+ Fail("ERROR: Timeout interval exceeded.\n");
+ }
+
+ /*
+ * Clean up
+ */
+ if (CloseHandle(hThread1) == FALSE ||
+ CloseHandle(hThread2) == FALSE ||
+ CloseHandle(hMutex) == FALSE)
+ {
+ Fail("ERROR: CloseHandle failed.\n");
+ }
+
+
+ /*
+ * Check our error flags
+ */
+ if (bProdErr == TRUE || bConErr == TRUE)
+ {
+ Fail("ERROR: A collision occurred, so the mutex failed.\n");
+ }
+
+ PAL_Terminate();
+ return ( PASS );
+
+}
diff --git a/src/pal/tests/palsuite/threading/CreateMutexW_ReleaseMutex/test1/testinfo.dat b/src/pal/tests/palsuite/threading/CreateMutexW_ReleaseMutex/test1/testinfo.dat
new file mode 100644
index 0000000000..19ea934dff
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CreateMutexW_ReleaseMutex/test1/testinfo.dat
@@ -0,0 +1,33 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = CreateMutexW / ReleaseMutex
+Name = Positive Test for CreateMutexW and ReleaseMutex
+TYPE = DEFAULT
+EXE1 = createmutexw
+Description
+= This test cases test whether a Mutex object created
+= with CreateMutexW really works by mutually excluding
+= threads from accessing a data structure at the same
+= time. Here we have a buffer that can be filled or
+= emptied, we use a Mutex object to ensure that one
+= operation cannot be started until the other is
+= finished. If one operation detects that the other
+= has not finished, it fails. There is a Producer
+= thread which will try to fill the buffer 25 times,
+= and a consumer thread which try to empty the buffer
+= 25 times. If either the fill or empty operations
+= fails because the Mutex failed to mutually exclude
+= then, the corresponding thread will set an error
+= flag and return. This will cause the test case to
+= fail.
+= To increase the probability of identifying problems,
+= the Fill opeartion has been slowed dowm with a call
+= to Sleep. This ensures that one operation will try
+= to access the shared buffer while the other is in
+= progress.
+= NOTE: this test case also serves as a test case for
+= WaitForSingleObject.
diff --git a/src/pal/tests/palsuite/threading/CreateMutexW_ReleaseMutex/test2/CMakeLists.txt b/src/pal/tests/palsuite/threading/CreateMutexW_ReleaseMutex/test2/CMakeLists.txt
new file mode 100644
index 0000000000..b40569b3f5
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CreateMutexW_ReleaseMutex/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ CreateMutexW.c
+)
+
+add_executable(paltest_createmutexw_releasemutex_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_createmutexw_releasemutex_test2 coreclrpal)
+
+target_link_libraries(paltest_createmutexw_releasemutex_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/CreateMutexW_ReleaseMutex/test2/CreateMutexW.c b/src/pal/tests/palsuite/threading/CreateMutexW_ReleaseMutex/test2/CreateMutexW.c
new file mode 100644
index 0000000000..41b7798a6e
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CreateMutexW_ReleaseMutex/test2/CreateMutexW.c
@@ -0,0 +1,340 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: CreateMutexW_ReleaseMutex/test2/CreateMutexW.c
+**
+** Purpose: This test case tests the following things
+** - Creation of named Mutexes
+** - Creating multiple handles to a single named Mutex
+** - Ensuring that these handles work interchangeably
+** - Setting bInitialOwnerFlag to TRUE will cause the
+** initial call to a Wait function on the same Mutex
+** to actually wait.
+** - Waiting on a Mutex that a thread already owns does
+** not block.
+** - Create Named mutex with empty string ("")
+** - Create Named mutex with string of MAX_LONGPATH length
+** - Calling RelaseMutex with invalid Mutex handles and
+** valid but unowned Mutexes.
+**
+** Dependencies: CreateThread
+** ReleaseMutex
+** WaitForSingleObject
+** CloseHandle
+** Sleep
+** memset
+**
+
+**
+**=========================================================*/
+
+#define UNICODE
+#include <palsuite.h>
+
+const char *szMutex = "MyMutex";
+const char *szEmpty = "";
+
+/* Function Prototypes */
+BOOL TestNamedMutex(const char *szMutexName);
+DWORD NamedMutexThread(LPVOID lpParam);
+BOOL NegativeReleaseMutexTests();
+
+struct ThreadData
+{
+ HANDLE hMutex;
+ BOOL bReturnCode;
+};
+typedef struct ThreadData THREADDATA;
+
+
+int __cdecl main (int argc, char **argv)
+{
+ BOOL bFailures = FALSE;
+ char *szMaxPath;
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return ( FAIL );
+ }
+
+
+ /*
+ * Test named Mutexes with ordinary string
+ */
+
+ if (!TestNamedMutex(szMutex))
+ {
+ bFailures = TRUE;
+ }
+
+
+ /*
+ * Test named Mutexes with empty ("") string
+ */
+
+ if (!TestNamedMutex(szEmpty))
+ {
+ bFailures = TRUE;
+ }
+
+
+ /*
+ * Test named Mutexes with string of length MAX_LONGPATH
+ */
+
+ szMaxPath = (char *)malloc(MAX_LONGPATH+2);
+ memset(szMaxPath, 'A', MAX_LONGPATH-60);
+ szMaxPath[MAX_LONGPATH-60] = 0;
+
+ if (!TestNamedMutex(szMaxPath))
+ {
+ bFailures = TRUE;
+ }
+
+ free(szMaxPath);
+
+
+ /*
+ * Run some negative tests on ReleaseMutex
+ */
+
+ if (!NegativeReleaseMutexTests())
+ {
+ bFailures = TRUE;
+ }
+
+
+ /*
+ * If there were any failures, then abort with a call to Fail
+ */
+
+ if (bFailures == TRUE)
+ {
+ Fail("ERROR: There some failures in the Mutex tests.\n");
+ }
+
+ PAL_Terminate();
+ return ( PASS );
+}
+
+
+/*
+ * Testing Function
+ *
+ * Try to get multiple handles to a named Mutex and test
+ * to make sure they actually refer to same Mutex object.
+ */
+BOOL TestNamedMutex(const char *szMutexName)
+{
+ DWORD dwData;
+ HANDLE hMutex1;
+ HANDLE hMutex2;
+ HANDLE hThread;
+ WCHAR *swzMutexName;
+ THREADDATA threadData;
+
+ /* Convert the Mutex name to wide characters */
+ swzMutexName = convert((char *)szMutexName);
+
+ /* Create a mutex and take ownership immediately */
+ hMutex1 = CreateMutexW (NULL, TRUE, swzMutexName);
+
+ if (NULL == hMutex1)
+ {
+ Trace("ERROR: CreateMutex #1 failed. GetLastError returned %u\n",
+ GetLastError());
+ free(swzMutexName);
+ return FALSE;
+ }
+
+ /* Try to wait on the Mutex we just created. We should not block. */
+ if (WaitForSingleObject(hMutex1, 1000) == WAIT_TIMEOUT)
+ {
+ Trace("WaitForSingleObject blocked on a Mutex that we owned.\n");
+ free(swzMutexName);
+ return FALSE;
+ }
+ /* We have to call ReleaseMutex here because of the Wait */
+ if (ReleaseMutex(hMutex1) == FALSE)
+ {
+ Trace("ReleaseMutex Failed.\n");
+ return FALSE;
+ }
+
+ /* Get a second handle to the same mutex */
+ hMutex2 = CreateMutexW (NULL, FALSE, swzMutexName);
+
+ if (NULL == hMutex2)
+ {
+ Trace("ERROR: CreateMutex #2 failed. GetLastError returned %u\n",
+ GetLastError());
+ free(swzMutexName);
+ return FALSE;
+ }
+
+ /* Get rid of the wide character string */
+ free(swzMutexName);
+
+ /*
+ * Create a thread that will Wait on the second handle.
+ */
+ threadData.hMutex = hMutex2;
+ hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)NamedMutexThread,
+ (LPVOID)&threadData, 0, &dwData);
+
+ if (NULL == hThread)
+ {
+ Trace("ERROR: CreateThread failed. GetLastError returned %u\n",
+ GetLastError());
+ return FALSE;
+ }
+
+ /* Give the thread a little time to execute & wait*/
+ Sleep(500);
+
+ /* Signal the the first handle */
+ if (ReleaseMutex(hMutex1) == FALSE)
+ {
+ Trace("ReleaseMutex Failed.\n");
+ return FALSE;
+ }
+
+ /* Give the thread some time to finish */
+ Sleep(2000);
+
+ /* Clean Up */
+ if (CloseHandle(hMutex1) == FALSE ||
+ CloseHandle(hMutex2) == FALSE ||
+ CloseHandle(hThread) == FALSE)
+ {
+ Trace("ERROR: CloseHandle failed.\n");
+ return FALSE;
+ }
+
+ /* Check the return code to see if signalling the first */
+ /* Mutex handle woke up the thread which was Waiting on */
+ /* the second handle. */
+ if (threadData.bReturnCode != FALSE)
+ {
+ Trace("ERROR: The handles did not refer to the same Mutex object.\n");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+/*
+ * Thread function used with above testing function.
+ */
+DWORD NamedMutexThread(LPVOID lpParam)
+{
+ BOOL bTimedOut = FALSE;
+ THREADDATA *lpThreadData = (THREADDATA *)lpParam;
+
+ /* Wait on the Mutex that was passed to us */
+ if (WaitForSingleObject(lpThreadData->hMutex, 10000) == WAIT_TIMEOUT)
+ {
+ /* The Mutex was not signaled in the allotted time */
+ bTimedOut = TRUE;
+ }
+ if (ReleaseMutex(lpThreadData->hMutex) == FALSE)
+ {
+ Trace("ERROR: ReleaseMutex failed.\n");
+ lpThreadData->bReturnCode = FALSE;
+ return 0;
+ }
+
+ /* Indicate whether we timed out Waiting on the Mutex */
+ lpThreadData->bReturnCode = bTimedOut;
+
+ return 0;
+}
+
+
+/*
+ * Testing Function
+ *
+ * Try some negative tests on ReleaseMutex
+ */
+BOOL NegativeReleaseMutexTests()
+{
+ HANDLE hMutex;
+ BOOL bRet;
+ BOOL bResults = TRUE;
+
+
+ /*
+ * Try calling ReleaseMutex on a null handle
+ */
+ hMutex = 0;
+ bRet = ReleaseMutex(hMutex);
+
+ if (bRet != 0)
+ {
+ Trace("Error: ReleaseMutex accepted null handle.\n");
+ bResults = FALSE;
+ }
+
+
+ /*
+ * Try calling ReleaseMutex on an handle that we don't own
+ */
+ hMutex = CreateMutexW (NULL, TRUE, NULL);
+ if (hMutex == 0)
+ {
+ Trace("Error: CreateMutex failed.\n");
+ bResults = FALSE;
+ }
+
+ bRet = ReleaseMutex(hMutex);
+ bRet = ReleaseMutex(hMutex);
+
+ if (bRet != FALSE)
+ {
+ Trace("Error: ReleaseMutex accepted unowned handle.\n");
+ bResults = FALSE;
+ }
+
+ if (CloseHandle(hMutex) == FALSE)
+ {
+ Trace("Error: CloseHandle failed.\n");
+ bResults = FALSE;
+ }
+
+
+
+ /*
+ * Try calling ReleaseMutex on an handle that has been closed
+ */
+ hMutex = CreateMutexW (NULL, TRUE, NULL);
+ if (hMutex == 0)
+ {
+ Trace("Error: CreateMutex failed.\n");
+ bResults = FALSE;
+ }
+
+ if (ReleaseMutex(hMutex) == FALSE)
+ {
+ Trace("Error: ReleaseMutex failed.\n");
+ bResults = FALSE;
+ }
+ if (CloseHandle(hMutex) == FALSE)
+ {
+ Trace("Error: CloseHandle failed.\n");
+ bResults = FALSE;
+ }
+
+ bRet = ReleaseMutex(hMutex);
+
+ if (bRet != FALSE)
+ {
+ Trace("Error: ReleaseMutex accepted invalid handle.\n");
+ bResults = FALSE;
+ }
+
+ return bResults;
+}
diff --git a/src/pal/tests/palsuite/threading/CreateMutexW_ReleaseMutex/test2/testinfo.dat b/src/pal/tests/palsuite/threading/CreateMutexW_ReleaseMutex/test2/testinfo.dat
new file mode 100644
index 0000000000..c5769e3ad3
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CreateMutexW_ReleaseMutex/test2/testinfo.dat
@@ -0,0 +1,24 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = CreateMutexW / ReleaseMutex
+Name = Basic validity Tests for CreateMutexW / ReleaseMutex
+TYPE = DEFAULT
+EXE1 = createmutexw
+Description
+= This test case tests the following things
+= - Creation of named Mutexes
+= - Creating multiple handles to a single named Mutex
+= - Ensuring that these handles work interchangeably
+= - Setting bInitialOwnerFlag to TRUE will cause the
+= initial call to a Wait function on the same Mutex
+= to actually wait.
+= - Waiting on a Mutex that a thread already owns should
+= not block.
+= - Create Named mutex with empty string ("")
+= - Create Named mutex with string of MAX_PATH length
+= - Calling RelaseMutex with invalid Mutex handles and
+= valid but unowned Mutexes.
diff --git a/src/pal/tests/palsuite/threading/CreateProcessA/CMakeLists.txt b/src/pal/tests/palsuite/threading/CreateProcessA/CMakeLists.txt
new file mode 100644
index 0000000000..ef14ea5352
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CreateProcessA/CMakeLists.txt
@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+
diff --git a/src/pal/tests/palsuite/threading/CreateProcessA/test1/CMakeLists.txt b/src/pal/tests/palsuite/threading/CreateProcessA/test1/CMakeLists.txt
new file mode 100644
index 0000000000..67e53edccd
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CreateProcessA/test1/CMakeLists.txt
@@ -0,0 +1,36 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(TESTSOURCES
+ parentProcess.c
+)
+
+add_executable(paltest_createprocessa_test1
+ ${TESTSOURCES}
+)
+
+add_dependencies(paltest_createprocessa_test1 coreclrpal)
+
+target_link_libraries(paltest_createprocessa_test1
+ pthread
+ m
+ coreclrpal
+)
+
+
+set(HELPERSOURCES
+ childProcess.c
+)
+
+add_executable(paltest_createprocessa_test1_child
+ ${HELPERSOURCES}
+)
+
+add_dependencies(paltest_createprocessa_test1_child coreclrpal)
+
+target_link_libraries(paltest_createprocessa_test1_child
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/CreateProcessA/test1/childProcess.c b/src/pal/tests/palsuite/threading/CreateProcessA/test1/childProcess.c
new file mode 100644
index 0000000000..ccbb050c04
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CreateProcessA/test1/childProcess.c
@@ -0,0 +1,131 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: CreateProcessA/test1/childprocess.c
+**
+** Purpose: Test to ensure CreateProcessA starts a new process. This test
+** launches a child process, and examines a file written by the child.
+** This code is the child code.
+**
+** Dependencies: GetCurrentDirectory
+** strlen
+** fopen
+** fclose
+** fprintf
+**
+
+**
+**=========================================================*/
+
+#include <palsuite.h>
+
+const char *szCommonFileA = "childdata.tmp";
+
+const char *szPathDelimA = "\\";
+
+const char *szCommonStringA = "058d2d057111a313aa82401c2e856002\0";
+
+/*
+ * Take two wide strings representing file and directory names
+ * (dirName, fileName), join the strings with the appropriate path
+ * delimiter and populate a wide character buffer (absPathName) with
+ * the resulting string.
+ *
+ * Returns: The number of wide characters in the resulting string.
+ * 0 is returned on Error.
+ */
+int
+mkAbsoluteFilenameA (
+ LPSTR dirName,
+ DWORD dwDirLength,
+ LPCSTR fileName,
+ DWORD dwFileLength,
+ LPSTR absPathName )
+{
+ extern const char *szPathDelimA;
+
+ DWORD sizeDN, sizeFN, sizeAPN;
+
+ sizeDN = strlen( dirName );
+ sizeFN = strlen( fileName );
+ sizeAPN = (sizeDN + 1 + sizeFN + 1);
+
+ /* insure ((dirName + DELIM + fileName + \0) =< _MAX_PATH ) */
+ if ( sizeAPN > _MAX_PATH )
+ {
+ return ( 0 );
+ }
+
+ strncpy(absPathName, dirName, dwDirLength +1);
+ strncpy(absPathName, szPathDelimA, 2);
+ strncpy(absPathName, fileName, dwFileLength +1);
+
+ return (sizeAPN);
+
+}
+
+int __cdecl main( int argc, char **argv )
+{
+
+ static FILE * fp;
+
+ DWORD dwFileLength;
+ DWORD dwDirLength;
+ DWORD dwSize;
+
+ char szDirNameA[_MAX_DIR];
+ char szAbsPathNameA[_MAX_PATH];
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return ( FAIL );
+ }
+
+ dwDirLength = GetCurrentDirectory( _MAX_PATH, szDirNameA );
+
+ if (0 == dwDirLength)
+ {
+ Fail ("GetCurrentDirectory call failed. Could not get "
+ "current working directory\n. Exiting.\n");
+ }
+
+ dwFileLength = strlen( szCommonFileA );
+
+ dwSize = mkAbsoluteFilenameA( szDirNameA, dwDirLength, szCommonFileA,
+ dwFileLength, szAbsPathNameA );
+
+ if (0 == dwSize)
+ {
+ Fail ("Palsuite Code: mkAbsoluteFilename() call failed. Could "
+ "not build absolute path name to file\n. Exiting.\n");
+ }
+
+ if ( NULL == ( fp = fopen ( szAbsPathNameA , "w+" ) ) )
+ {
+ /*
+ * A return value of NULL indicates an error condition or an
+ * EOF condition
+ */
+ Fail ("%s unable to open %s for writing. Exiting.\n", argv[0]
+ , szAbsPathNameA );
+ }
+
+ if ( 0 >= ( fprintf ( fp, "%s", szCommonStringA )))
+ {
+ Fail("%s unable to write to %s. Exiting.\n", argv[0]
+ , szAbsPathNameA );
+ }
+
+ if (0 != (fclose ( fp )))
+ {
+ Fail ("%s unable to close file %s. Pid may not be "
+ "written to file. Exiting.\n", argv[0], szAbsPathNameA );
+ }
+
+ PAL_Terminate();
+ return ( PASS );
+
+}
diff --git a/src/pal/tests/palsuite/threading/CreateProcessA/test1/parentProcess.c b/src/pal/tests/palsuite/threading/CreateProcessA/test1/parentProcess.c
new file mode 100644
index 0000000000..b0c5808a7e
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CreateProcessA/test1/parentProcess.c
@@ -0,0 +1,201 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: CreateProcessA/test1/parentprocess.c
+**
+** Purpose: Test to ensure CreateProcessA starts a new process. This test
+** launches a child process, and examines a file written by the child.
+** This process (the parent process) reads the file created by the child and
+** compares the value the child wrote to the file. (a const char *)
+**
+** Dependencies: GetCurrentDirectory
+** strlen
+** WaitForSingleObject
+** fopen
+** fclose
+** Fail
+**
+
+**
+**=========================================================*/
+
+#include <palsuite.h>
+
+const char *szCommonFileA = "childdata.tmp";
+
+const char *szChildFileA = "paltest_createprocessa_test1_child";
+
+const char *szPathDelimA = "\\";
+
+const char *szCommonStringA = "058d2d057111a313aa82401c2e856002\0";
+
+/*
+ * Take two wide strings representing file and directory names
+ * (dirName, fileName), join the strings with the appropriate path
+ * delimiter and populate a wide character buffer (absPathName) with
+ * the resulting string.
+ *
+ * Returns: The number of wide characters in the resulting string.
+ * 0 is returned on Error.
+ */
+int
+mkAbsoluteFilenameA (
+ LPSTR dirName,
+ DWORD dwDirLength,
+ LPCSTR fileName,
+ DWORD dwFileLength,
+ LPSTR absPathName )
+{
+ extern const char *szPathDelimA;
+
+ DWORD sizeDN, sizeFN, sizeAPN;
+
+ sizeDN = strlen( dirName );
+ sizeFN = strlen( fileName );
+ sizeAPN = (sizeDN + 1 + sizeFN + 1);
+
+ /* insure ((dirName + DELIM + fileName + \0) =< _MAX_PATH ) */
+ if ( sizeAPN > _MAX_PATH )
+ {
+ return ( 0 );
+ }
+
+ strncpy(absPathName, dirName, dwDirLength +1);
+ strncpy(absPathName, szPathDelimA, 2);
+ strncpy(absPathName, fileName, dwFileLength +1);
+
+ return (sizeAPN);
+
+}
+
+int __cdecl main( int argc, char **argv )
+
+{
+
+ STARTUPINFO si;
+ PROCESS_INFORMATION pi;
+
+ static FILE * fp;
+
+ DWORD dwFileLength;
+ DWORD dwDirLength;
+ DWORD dwSize;
+
+ size_t cslen;
+
+ char szReadStringA[256];
+
+ char szDirNameA[_MAX_DIR];
+ char absPathBuf[_MAX_PATH];
+ char *szAbsPathNameA;
+
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return ( FAIL );
+ }
+
+ ZeroMemory ( &si, sizeof(si) );
+ si.cb = sizeof(si);
+ ZeroMemory ( &pi, sizeof(pi) );
+
+ szAbsPathNameA=&absPathBuf[0];
+ dwFileLength = strlen( szChildFileA );
+
+ dwDirLength = GetCurrentDirectory(_MAX_PATH, szDirNameA);
+
+ if (0 == dwDirLength)
+ {
+ Fail ("GetCurrentDirectory call failed. Could not get "
+ "current working directory\n. Exiting.\n");
+ }
+
+ dwSize = mkAbsoluteFilenameA( szDirNameA, dwDirLength, szChildFileA,
+ dwFileLength, szAbsPathNameA );
+
+ if (0 == dwSize)
+ {
+ Fail ("Palsuite Code: mkAbsoluteFilename() call failed. Could "
+ "not build absolute path name to file\n. Exiting.\n");
+ }
+
+ if ( !CreateProcessA ( NULL,
+ szAbsPathNameA,
+ NULL,
+ NULL,
+ FALSE,
+ CREATE_NEW_CONSOLE,
+ NULL,
+ NULL,
+ &si,
+ &pi )
+ )
+ {
+ Fail ( "CreateProcess call failed. GetLastError returned %d\n",
+ GetLastError() );
+ }
+
+ WaitForSingleObject ( pi.hProcess, INFINITE );
+
+ szAbsPathNameA=&absPathBuf[0];
+
+ dwFileLength = strlen( szCommonFileA );
+
+ dwSize = mkAbsoluteFilenameA( szDirNameA, dwDirLength, szCommonFileA,
+ dwFileLength, szAbsPathNameA );
+
+ /* set the string length for the open call*/
+
+ if (0 == dwSize)
+ {
+ Fail ("Palsuite Code: mkAbsoluteFilename() call failed. Could "
+ "not build absolute path name to file\n. Exiting.\n");
+ }
+
+ if ( NULL == ( fp = fopen ( szAbsPathNameA , "r" ) ) )
+ {
+ Fail ("%s\nunable to open %s\nfor reading. Exiting.\n", argv[0],
+ szAbsPathNameA );
+ }
+
+ cslen = strlen ( szCommonStringA );
+
+ if ( NULL == fgets( szReadStringA, (cslen + 1), fp ))
+ {
+ /*
+ * A return value of NULL indicates an error condition or an
+ * EOF condition
+ */
+ Fail ("%s\nunable to read file\n%s\nszReadStringA is %s\n"
+ "Exiting.\n", argv[0], szAbsPathNameA,
+ szReadStringA );
+
+ }
+ if ( 0 != strncmp( szReadStringA, szCommonStringA, cslen ))
+ {
+ Fail ("string comparison failed.\n szReadStringA is %s and\n"
+ "szCommonStringA is %s\n", szReadStringA,
+ szCommonStringA );
+ }
+ else
+ {
+ Trace ("string comparison passed.\n");
+ }
+
+ if (0 != (fclose ( fp )))
+ {
+ Trace ("%s unable to close file %s. This may cause a file pointer "
+ "leak. Continuing.\n", argv[0], szAbsPathNameA );
+ }
+
+ /* Close process and thread handle */
+ CloseHandle ( pi.hProcess );
+ CloseHandle ( pi.hThread );
+
+ PAL_Terminate();
+ return ( PASS );
+
+}
diff --git a/src/pal/tests/palsuite/threading/CreateProcessA/test1/testinfo.dat b/src/pal/tests/palsuite/threading/CreateProcessA/test1/testinfo.dat
new file mode 100644
index 0000000000..02c25444fe
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CreateProcessA/test1/testinfo.dat
@@ -0,0 +1,17 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = CreateProcessA
+Name = Positive Test for CreateProcessA
+TYPE = DEFAULT
+EXE1 = parentprocess
+EXE2 = childprocess
+Description
+= Test the CreateProcessA function. The test executes the childprocess
+= program. The childprocess program launches and writes a const char string
+= to a file childdata. The parent waits for the completion of childprocess
+= and then reads the string from the childdata file. If the string in the
+= file matches it's copy of the const char string, then the test succeeds.
diff --git a/src/pal/tests/palsuite/threading/CreateProcessA/test2/CMakeLists.txt b/src/pal/tests/palsuite/threading/CreateProcessA/test2/CMakeLists.txt
new file mode 100644
index 0000000000..b81ea2e978
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CreateProcessA/test2/CMakeLists.txt
@@ -0,0 +1,36 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(TESTSOURCES
+ parentprocess.c
+)
+
+add_executable(paltest_createprocessa_test2
+ ${TESTSOURCES}
+)
+
+add_dependencies(paltest_createprocessa_test2 coreclrpal)
+
+target_link_libraries(paltest_createprocessa_test2
+ pthread
+ m
+ coreclrpal
+)
+
+
+set(HELPERSOURCES
+ childprocess.c
+)
+
+add_executable(paltest_createprocessa_test2_child
+ ${HELPERSOURCES}
+)
+
+add_dependencies(paltest_createprocessa_test2_child coreclrpal)
+
+target_link_libraries(paltest_createprocessa_test2_child
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/CreateProcessA/test2/childprocess.c b/src/pal/tests/palsuite/threading/CreateProcessA/test2/childprocess.c
new file mode 100644
index 0000000000..baa20c2d3c
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CreateProcessA/test2/childprocess.c
@@ -0,0 +1,69 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: createprocessa/test2/childprocess.c
+**
+** Purpose: This child process reads a string from stdin
+** and writes it out to stdout & stderr
+**
+** Dependencies: memset
+** fgets
+** gputs
+**
+
+**
+**=========================================================*/
+
+#include <palsuite.h>
+#include "test2.h"
+
+
+
+int __cdecl main( int argc, char **argv )
+{
+ int iRetCode = EXIT_OK_CODE; /* preset exit code to OK */
+ char szBuf[BUF_LEN];
+
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ if (argc != 4)
+ {
+ return EXIT_ERR_CODE3;
+ }
+
+ if (strcmp(argv[1], szArg1) != 0
+ || strcmp(argv[2], szArg2) != 0
+ || strcmp(argv[3], szArg3) != 0)
+ {
+ return EXIT_ERR_CODE4;
+ }
+
+
+ memset(szBuf, 0, BUF_LEN);
+
+ /* Read the string that was written by the parent */
+ if (fgets(szBuf, BUF_LEN, stdin) == NULL)
+ {
+ return EXIT_ERR_CODE1;
+ }
+
+ /* Write the string out to the stdout & stderr pipes */
+ if (fputs(szBuf, stdout) == EOF
+ || fputs(szBuf, stderr) == EOF)
+ {
+ return EXIT_ERR_CODE2;
+ }
+
+ /* The exit code will indicate success or failure */
+ PAL_TerminateEx(iRetCode);
+
+ /* Return special exit code to indicate success or failure */
+ return iRetCode;
+}
diff --git a/src/pal/tests/palsuite/threading/CreateProcessA/test2/parentprocess.c b/src/pal/tests/palsuite/threading/CreateProcessA/test2/parentprocess.c
new file mode 100644
index 0000000000..ef3340c5d9
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CreateProcessA/test2/parentprocess.c
@@ -0,0 +1,243 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: createprocessa/test2/parentprocess.c
+**
+** Purpose: Test the following features of CreateProcessA:
+** - Check to see if hProcess & hThread are set in
+** return PROCESS_INFORMATION structure
+** - Check to see if stdin, stdout, & stderr handles
+** are used when STARTF_USESTDHANDLES is specified
+** in STARUPINFO flags and bInheritHandles = TRUE
+** - Check to see that proper arguments are passed to
+** child process
+**
+** Dependencies: CreatePipe
+** strcpy, strlen, strncmp, memset
+** WaitForSingleObject
+** WriteFile, ReadFile
+** GetExitCodeProcess
+**
+
+**
+**=========================================================*/
+
+#include <palsuite.h>
+#include "test2.h"
+
+
+
+int __cdecl main( int argc, char **argv )
+{
+
+ /*******************************************
+ * Declarations
+ *******************************************/
+ STARTUPINFO si;
+ PROCESS_INFORMATION pi;
+
+ HANDLE hTestStdInR = NULL;
+ HANDLE hTestStdInW = NULL;
+ HANDLE hTestStdOutR = NULL;
+ HANDLE hTestStdOutW = NULL;
+ HANDLE hTestStdErrR = NULL;
+ HANDLE hTestStdErrW = NULL;
+
+ BOOL bRetVal = FALSE;
+ DWORD dwBytesWritten = 0;
+ DWORD dwBytesRead = 0;
+ DWORD dwExitCode = 0;
+
+ SECURITY_ATTRIBUTES pipeAttributes;
+
+ char szStdOutBuf[BUF_LEN];
+ char szStdErrBuf[BUF_LEN];
+ char szFullPathNameA[_MAX_PATH];
+
+
+ /*******************************************
+ * Initialization
+ *******************************************/
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return ( FAIL );
+ }
+
+ /*Setup SECURITY_ATTRIBUTES structure for CreatePipe*/
+ pipeAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);
+ pipeAttributes.lpSecurityDescriptor = NULL;
+ pipeAttributes.bInheritHandle = TRUE;
+
+
+ /*Create a StdIn pipe for child*/
+ bRetVal = CreatePipe(&hTestStdInR, /* read handle*/
+ &hTestStdInW, /* write handle */
+ &pipeAttributes, /* security attributes*/
+ 1024); /* pipe size*/
+
+ if (bRetVal == FALSE)
+ {
+ Fail("ERROR: %ld :Unable to create stdin pipe\n", GetLastError());
+ }
+
+
+ /*Create a StdOut pipe for child*/
+ bRetVal = CreatePipe(&hTestStdOutR, /* read handle*/
+ &hTestStdOutW, /* write handle */
+ &pipeAttributes, /* security attributes*/
+ 0); /* pipe size*/
+
+ if (bRetVal == FALSE)
+ {
+ Fail("ERROR: %ld :Unable to create stdout pipe\n", GetLastError());
+ }
+
+
+ /*Create a StdErr pipe for child*/
+ bRetVal = CreatePipe(&hTestStdErrR, /* read handle*/
+ &hTestStdErrW, /* write handle */
+ &pipeAttributes, /* security attributes*/
+ 0); /* pipe size*/
+
+ if (bRetVal == FALSE)
+ {
+ Fail("ERROR: %ld :Unable to create stderr pipe\n", GetLastError());
+ }
+
+ /* Zero the data structure space */
+ ZeroMemory ( &pi, sizeof(pi) );
+ ZeroMemory ( &si, sizeof(si) );
+
+ /* Set the process flags and standard io handles */
+ si.cb = sizeof(si);
+ si.dwFlags = STARTF_USESTDHANDLES;
+ si.hStdInput = hTestStdInR;
+ si.hStdOutput = hTestStdOutW;
+ si.hStdError = hTestStdErrW;
+
+ strcpy(szFullPathNameA, szChildFileA);
+ strcat(szFullPathNameA, szArgs);
+
+ /*******************************************
+ * Start Testing
+ *******************************************/
+
+ /* Launch the child */
+ if ( !CreateProcessA (NULL, szFullPathNameA, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi ))
+ {
+ Fail("ERROR: CreateProcess call failed. GetLastError returned %d\n",
+ GetLastError() );
+ }
+
+ /* Check the returned process information for validity */
+ if (pi.hProcess == 0 || pi.hThread == 0)
+ {
+ Fail("ERROR: CreateProcess Error: Process Handle = %u, Thread Handle = %u\n",
+ pi.hProcess, pi.hThread);
+ }
+
+ /* Write the Constructed string to stdin pipe for the child process */
+ if (WriteFile(hTestStdInW, szTestString, strlen(szTestString), &dwBytesWritten, NULL) == FALSE
+ || WriteFile(hTestStdInW, "\n", strlen("\n"), &dwBytesWritten, NULL) == FALSE)
+ {
+ Fail("ERROR: %ld :unable to write to write pipe handle "
+ "hTestStdInW=0x%lx\n", GetLastError(), hTestStdInW);
+ }
+
+ /* Wait for the child to finish, Max 20 seconds */
+ dwExitCode = WaitForSingleObject(pi.hProcess, 20000);
+
+ /* If the child failed then whole thing fails */
+ if (dwExitCode != WAIT_OBJECT_0)
+ {
+ TerminateProcess(pi.hProcess, 0);
+ Fail("ERROR: The child failed to run properly.\n");
+ }
+
+ /* Check for problems in the child process */
+ if (GetExitCodeProcess(pi.hProcess, &dwExitCode) == FALSE)
+ {
+ Fail("ERROR: Call to GetExitCodeProcess failed.\n");
+ }
+ else if (dwExitCode == EXIT_ERR_CODE1)
+ {
+ Fail("ERROR: The Child process could not reead the string "
+ "written to the stdin pipe.\n");
+ }
+ else if (dwExitCode == EXIT_ERR_CODE2)
+ {
+ Fail("ERROR: The Child process could not write the string "
+ "the stdout pipe or stderr pipe.\n");
+ }
+ else if (dwExitCode == EXIT_ERR_CODE3)
+ {
+ Fail("ERROR: The Child received the wrong number of "
+ "command line arguments.\n");
+ }
+ else if (dwExitCode == EXIT_ERR_CODE4)
+ {
+ Fail("ERROR: The Child received the wrong "
+ "command line arguments.\n");
+ }
+ else if (dwExitCode != EXIT_OK_CODE)
+ {
+ Fail("ERROR: Unexpected exit code returned: %u. Child process "
+ "did not complete its part of the test.\n", dwExitCode);
+ }
+
+
+ /* The child ran ok, so check to see if we received the proper */
+ /* strings through the pipes. */
+
+ /* clear our buffers */
+ memset(szStdOutBuf, 0, BUF_LEN);
+ memset(szStdErrBuf, 0, BUF_LEN);
+
+ /* Read the data back from the child process stdout */
+ bRetVal = ReadFile(hTestStdOutR, /* handle to read pipe*/
+ szStdOutBuf, /* buffer to write to*/
+ BUF_LEN, /* number of bytes to read*/
+ &dwBytesRead, /* number of bytes read*/
+ NULL); /* overlapped buffer*/
+
+ /*Read the data back from the child process stderr */
+ bRetVal = ReadFile(hTestStdErrR, /* handle to read pipe*/
+ szStdErrBuf, /* buffer to write to*/
+ BUF_LEN, /* number of bytes to read*/
+ &dwBytesRead, /* number of bytes read*/
+ NULL); /* overlapped buffer*/
+
+
+ /* Confirm that we recieved the same string that we originally */
+ /* wrote to the child and was received on both stdout & stderr.*/
+ if (strncmp(szTestString, szStdOutBuf, strlen(szTestString)) != 0
+ || strncmp(szTestString, szStdErrBuf, strlen(szTestString)) != 0)
+ {
+ Fail("ERROR: The data read back from child does not match "
+ "what was written. STDOUT: %s STDERR: %s\n",
+ szStdOutBuf, szStdErrBuf);
+ }
+
+
+ /*******************************************
+ * Clean Up
+ *******************************************/
+
+ /* Close process and thread handle */
+ CloseHandle ( pi.hProcess );
+ CloseHandle ( pi.hThread );
+
+ CloseHandle(hTestStdInR);
+ CloseHandle(hTestStdInW);
+ CloseHandle(hTestStdOutR);
+ CloseHandle(hTestStdOutW);
+ CloseHandle(hTestStdErrR);
+ CloseHandle(hTestStdErrW);
+
+ PAL_Terminate();
+ return ( PASS );
+}
diff --git a/src/pal/tests/palsuite/threading/CreateProcessA/test2/test2.h b/src/pal/tests/palsuite/threading/CreateProcessA/test2/test2.h
new file mode 100644
index 0000000000..8cdff3b939
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CreateProcessA/test2/test2.h
@@ -0,0 +1,72 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: test2.h
+**
+
+**
+**===========================================================*/
+
+
+const char *szChildFileA = "paltest_createprocessa_test2_child";
+const char *szArgs = " A B C";
+const char *szArg1 = "A";
+const char *szArg2 = "B";
+const char *szArg3 = "C";
+
+const char *szPathDelimA = "\\";
+
+const char *szTestString = "Copyright (c) Microsoft";
+
+const DWORD EXIT_OK_CODE = 100;
+const DWORD EXIT_ERR_CODE1 = 101;
+const DWORD EXIT_ERR_CODE2 = 102;
+const DWORD EXIT_ERR_CODE3 = 103;
+const DWORD EXIT_ERR_CODE4 = 104;
+const DWORD EXIT_ERR_CODE5 = 105;
+
+#define BUF_LEN 64
+
+/*
+ * Take two wide strings representing file and directory names
+ * (dirName, fileName), join the strings with the appropriate path
+ * delimiter and populate a wide character buffer (absPathName) with
+ * the resulting string.
+ *
+ * Returns: The number of wide characters in the resulting string.
+ * 0 is returned on Error.
+ */
+int
+mkAbsoluteFilenameA (
+ LPSTR dirName,
+ DWORD dwDirLength,
+ LPCSTR fileName,
+ DWORD dwFileLength,
+ LPSTR absPathName )
+{
+ extern const char *szPathDelimA;
+
+ DWORD sizeDN;
+ DWORD sizeFN;
+ DWORD sizeAPN;
+
+ sizeDN = strlen( dirName );
+ sizeFN = strlen( fileName );
+ sizeAPN = (sizeDN + 1 + sizeFN + 1);
+
+ /* insure ((dirName + DELIM + fileName + \0) =< _MAX_PATH ) */
+ if ( sizeAPN > _MAX_PATH )
+ {
+ return ( 0 );
+ }
+
+ strncpy(absPathName, dirName, dwDirLength +1);
+ strcat(absPathName, szPathDelimA);
+ strcat(absPathName, fileName);
+
+ return (sizeAPN);
+
+}
diff --git a/src/pal/tests/palsuite/threading/CreateProcessA/test2/testinfo.dat b/src/pal/tests/palsuite/threading/CreateProcessA/test2/testinfo.dat
new file mode 100644
index 0000000000..23fcdf93ae
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CreateProcessA/test2/testinfo.dat
@@ -0,0 +1,20 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = CreateProcessA
+Name = PROCESS_INFORMATION and HANDLE Inheritance
+TYPE = DEFAULT
+EXE1 = parentprocess
+EXE2 = childprocess
+Description
+= Test the following features of CreateProcessA:
+= - Check to see if hProcess & hThread are set in
+= return PROCESS_INFORMATION structure
+= - Check to see if stdin, stdout, & stderr handles
+= are used when STARTF_USESTDHANDLES is specified
+= in STARUPINFO flags and bInheritHandles = TRUE
+= - Check to see that proper arguments are passed to
+= child process
diff --git a/src/pal/tests/palsuite/threading/CreateProcessW/CMakeLists.txt b/src/pal/tests/palsuite/threading/CreateProcessW/CMakeLists.txt
new file mode 100644
index 0000000000..ef14ea5352
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CreateProcessW/CMakeLists.txt
@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+
diff --git a/src/pal/tests/palsuite/threading/CreateProcessW/test1/CMakeLists.txt b/src/pal/tests/palsuite/threading/CreateProcessW/test1/CMakeLists.txt
new file mode 100644
index 0000000000..394b124526
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CreateProcessW/test1/CMakeLists.txt
@@ -0,0 +1,36 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(TESTSOURCES
+ parentProcess.c
+)
+
+add_executable(paltest_createprocessw_test1
+ ${TESTSOURCES}
+)
+
+add_dependencies(paltest_createprocessw_test1 coreclrpal)
+
+target_link_libraries(paltest_createprocessw_test1
+ pthread
+ m
+ coreclrpal
+)
+
+
+set(HELPERSOURCES
+ childProcess.c
+)
+
+add_executable(paltest_createprocessw_test1_child
+ ${HELPERSOURCES}
+)
+
+add_dependencies(paltest_createprocessw_test1_child coreclrpal)
+
+target_link_libraries(paltest_createprocessw_test1_child
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/CreateProcessW/test1/childProcess.c b/src/pal/tests/palsuite/threading/CreateProcessW/test1/childProcess.c
new file mode 100644
index 0000000000..c71f967b65
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CreateProcessW/test1/childProcess.c
@@ -0,0 +1,150 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: CreateProcessW/test1/childprocess.c
+**
+** Purpose: Test to ensure CreateProcessW starts a new process. This test
+** launches a child process, and examines a file written by the child.
+** This code is the child code.
+**
+** Dependencies: GetCurrentDirectory
+** MultiByteToWideChar
+** wcslen
+** strlen
+** WideCharToMultiByte
+** fopen
+** fclose
+** fprintf
+**
+
+**
+**=========================================================*/
+
+#define UNICODE
+#include <palsuite.h>
+
+const WCHAR szCommonFileW[] =
+ {'c','h','i','l','d','d','a','t','a','.','t','m','p','\0'};
+
+const WCHAR szPathDelimW[] = {'\\','\0'};
+
+const char *szCommonStringA = "058d2d057111a313aa82401c2e856002\0";
+
+/*
+ * Take two wide strings representing file and directory names
+ * (dirName, fileName), join the strings with the appropriate path
+ * delimiter and populate a wide character buffer (absPathName) with
+ * the resulting string.
+ *
+ * Returns: The number of wide characters in the resulting string.
+ * 0 is returned on Error.
+ */
+int
+mkAbsoluteFilenameW (
+ LPWSTR dirName,
+ DWORD dwDirLength,
+ LPCWSTR fileName,
+ DWORD dwFileLength,
+ LPWSTR absPathName )
+{
+ extern const WCHAR szPathDelimW[];
+
+ DWORD sizeDN, sizeFN, sizeAPN;
+
+ sizeDN = wcslen( dirName );
+ sizeFN = wcslen( fileName );
+ sizeAPN = (sizeDN + 1 + sizeFN + 1);
+
+ /* insure ((dirName + DELIM + fileName + \0) =< _MAX_PATH ) */
+ if ( sizeAPN > _MAX_PATH )
+ {
+ return ( 0 );
+ }
+
+ wcsncpy(absPathName, dirName, dwDirLength +1);
+ wcsncpy(absPathName, szPathDelimW, 2);
+ wcsncpy(absPathName, fileName, dwFileLength +1);
+
+ return (sizeAPN);
+
+}
+
+int __cdecl main( int argc, char **argv )
+{
+
+ static FILE * fp;
+
+ DWORD dwFileLength;
+ DWORD dwDirLength;
+ DWORD dwSize;
+
+ char *szAbsPathNameA;
+ WCHAR szDirNameW[_MAX_DIR];
+ WCHAR szAbsPathNameW[_MAX_PATH];
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return ( FAIL );
+ }
+
+ dwDirLength = GetCurrentDirectory( _MAX_PATH, szDirNameW );
+
+ if (0 == dwDirLength)
+ {
+ Fail ("GetCurrentDirectory call failed. Could not get "
+ "current working directory\n. Exiting.\n");
+ }
+
+ dwFileLength = wcslen( szCommonFileW );
+
+ dwSize = mkAbsoluteFilenameW( szDirNameW, dwDirLength, szCommonFileW,
+ dwFileLength, szAbsPathNameW );
+
+ if (0 == dwSize)
+ {
+ Fail ("Palsuite Code: mkAbsoluteFilename() call failed. Could "
+ "not build absolute path name to file\n. Exiting.\n");
+ }
+
+ /* set the string length for the open call */
+ szAbsPathNameA = malloc (dwSize +1);
+
+ if (NULL == szAbsPathNameA)
+ {
+ Fail ("Unable to malloc (%d) bytes. Exiting\n", (dwSize +1) );
+ }
+
+ WideCharToMultiByte (CP_ACP, 0, szAbsPathNameW, -1, szAbsPathNameA,
+ (dwSize + 1), NULL, NULL);
+
+ if ( NULL == ( fp = fopen ( szAbsPathNameA , "w+" ) ) )
+ {
+ /*
+ * A return value of NULL indicates an error condition or an
+ * EOF condition
+ */
+ Fail ("%s unable to open %s for writing. Exiting.\n", argv[0]
+ , szAbsPathNameA );
+ }
+
+ free (szAbsPathNameA);
+
+ if ( 0 >= ( fprintf ( fp, "%s", szCommonStringA )))
+ {
+ Fail("%s unable to write to %s. Exiting.\n", argv[0]
+ , szAbsPathNameA );
+ }
+
+ if (0 != (fclose ( fp )))
+ {
+ Fail ("%s unable to close file %s. Pid may not be "
+ "written to file. Exiting.\n", argv[0], szAbsPathNameA );
+ }
+
+ PAL_Terminate();
+ return ( PASS );
+
+}
diff --git a/src/pal/tests/palsuite/threading/CreateProcessW/test1/parentProcess.c b/src/pal/tests/palsuite/threading/CreateProcessW/test1/parentProcess.c
new file mode 100644
index 0000000000..db1fb6356d
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CreateProcessW/test1/parentProcess.c
@@ -0,0 +1,210 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: CreateProcessW/test1/parentprocess.c
+**
+** Purpose: Test to ensure CreateProcessW starts a new process. This test
+** launches a child process, and examines a file written by the child.
+** This process (the parent process) reads the file created by the child and
+** compares the value the child wrote to the file. (a const char *)
+**
+** Dependencies: GetCurrentDirectory
+** MultiByteToWideChar
+** wcslen
+** strlen
+** WideCharToMultiByte
+** WaitForSingleObject
+** fopen
+** fclose
+** Fail
+**
+
+**
+**=========================================================*/
+
+#define UNICODE
+#include <palsuite.h>
+
+const WCHAR szCommonFileW[] =
+ {'c','h','i','l','d','d','a','t','a','.','t','m','p','\0'};
+
+const WCHAR szChildFileW[] = u"paltest_createprocessw_test1_child";
+
+const WCHAR szPathDelimW[] = {'\\','\0'};
+
+const char *szCommonStringA = "058d2d057111a313aa82401c2e856002\0";
+
+/*
+ * Take two wide strings representing file and directory names
+ * (dirName, fileName), join the strings with the appropriate path
+ * delimiter and populate a wide character buffer (absPathName) with
+ * the resulting string.
+ *
+ * Returns: The number of wide characters in the resulting string.
+ * 0 is returned on Error.
+ */
+int
+mkAbsoluteFilenameW (
+ LPWSTR dirName,
+ DWORD dwDirLength,
+ LPCWSTR fileName,
+ DWORD dwFileLength,
+ LPWSTR absPathName )
+{
+ extern const WCHAR szPathDelimW[];
+
+ DWORD sizeDN, sizeFN, sizeAPN;
+
+ sizeDN = wcslen( dirName );
+ sizeFN = wcslen( fileName );
+ sizeAPN = (sizeDN + 1 + sizeFN + 1);
+
+ /* insure ((dirName + DELIM + fileName + \0) =< _MAX_PATH ) */
+ if ( sizeAPN > _MAX_PATH )
+ {
+ return ( 0 );
+ }
+
+ wcsncpy(absPathName, dirName, dwDirLength +1);
+ wcsncpy(absPathName, szPathDelimW, 2);
+ wcsncpy(absPathName, fileName, dwFileLength +1);
+
+ return (sizeAPN);
+
+}
+
+int __cdecl main( int argc, char **argv )
+
+{
+
+ STARTUPINFOW si;
+ PROCESS_INFORMATION pi;
+
+ static FILE * fp;
+
+ DWORD dwFileLength;
+ DWORD dwDirLength;
+ DWORD dwSize;
+
+ size_t cslen;
+
+ char szReadStringA[256];
+
+ char szAbsPathNameA[_MAX_PATH];
+ WCHAR szDirNameW[_MAX_DIR];
+ WCHAR absPathBuf[_MAX_PATH];
+ WCHAR *szAbsPathNameW;
+
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return ( FAIL );
+ }
+
+ ZeroMemory ( &si, sizeof(si) );
+ si.cb = sizeof(si);
+ ZeroMemory ( &pi, sizeof(pi) );
+
+ szAbsPathNameW=&absPathBuf[0];
+ dwFileLength = wcslen( szChildFileW );
+
+ dwDirLength = GetCurrentDirectory(_MAX_PATH, szDirNameW);
+
+ if (0 == dwDirLength)
+ {
+ Fail ("GetCurrentDirectory call failed. Could not get "
+ "current working directory\n. Exiting.\n");
+ }
+
+ dwSize = mkAbsoluteFilenameW( szDirNameW, dwDirLength, szChildFileW,
+ dwFileLength, szAbsPathNameW );
+
+ if (0 == dwSize)
+ {
+ Fail ("Palsuite Code: mkAbsoluteFilename() call failed. Could "
+ "not build absolute path name to file\n. Exiting.\n");
+ }
+
+ if ( !CreateProcessW ( NULL,
+ szAbsPathNameW,
+ NULL,
+ NULL,
+ FALSE,
+ CREATE_NEW_CONSOLE,
+ NULL,
+ NULL,
+ &si,
+ &pi )
+ )
+ {
+ Fail ( "CreateProcess call failed. GetLastError returned %d\n",
+ GetLastError() );
+ }
+
+ WaitForSingleObject ( pi.hProcess, INFINITE );
+
+ szAbsPathNameW=&absPathBuf[0];
+
+ dwFileLength = wcslen( szCommonFileW );
+
+ dwSize = mkAbsoluteFilenameW( szDirNameW, dwDirLength, szCommonFileW,
+ dwFileLength, szAbsPathNameW );
+
+ /* set the string length for the open call*/
+
+ if (0 == dwSize)
+ {
+ Fail ("Palsuite Code: mkAbsoluteFilename() call failed. Could "
+ "not build absolute path name to file\n. Exiting.\n");
+ }
+
+ WideCharToMultiByte (CP_ACP, 0, szAbsPathNameW, -1, szAbsPathNameA,
+ (dwSize + 1), NULL, NULL);
+
+ if ( NULL == ( fp = fopen ( szAbsPathNameA , "r" ) ) )
+ {
+ Fail ("%s\nunable to open %s\nfor reading. Exiting.\n", argv[0],
+ szAbsPathNameA );
+ }
+
+ cslen = strlen ( szCommonStringA );
+
+ if ( NULL == fgets( szReadStringA, (cslen + 1), fp ))
+ {
+ /*
+ * A return value of NULL indicates an error condition or an
+ * EOF condition
+ */
+ Fail ("%s\nunable to read file\n%s\nszReadStringA is %s\n"
+ "Exiting.\n", argv[0], szAbsPathNameA,
+ szReadStringA );
+ }
+
+ if ( 0 != strncmp( szReadStringA, szCommonStringA, cslen ))
+ {
+ Fail ("string comparison failed.\n szReadStringA is %s and\n"
+ "szCommonStringA is %s\n", szReadStringA,
+ szCommonStringA );
+ }
+ else
+ {
+ Trace ("string comparison passed.\n");
+ }
+
+ if (0 != (fclose ( fp )))
+ {
+ Trace ("%s unable to close file %s. This may cause a file pointer "
+ "leak. Continuing.\n", argv[0], szAbsPathNameA );
+ }
+
+ /* Close process and thread handle */
+ CloseHandle ( pi.hProcess );
+ CloseHandle ( pi.hThread );
+
+ PAL_Terminate();
+ return ( PASS );
+
+}
diff --git a/src/pal/tests/palsuite/threading/CreateProcessW/test1/testinfo.dat b/src/pal/tests/palsuite/threading/CreateProcessW/test1/testinfo.dat
new file mode 100644
index 0000000000..2acf2c9289
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CreateProcessW/test1/testinfo.dat
@@ -0,0 +1,17 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = CreateProcessW
+Name = Positive Test for CreateProcessW
+TYPE = DEFAULT
+EXE1 = parentprocess
+EXE2 = childprocess
+Description
+= Test the CreateProcessW function. The test executes the childprocess
+= program. The childprocess program launches and writes a const char string
+= to a file childdata. The parent waits for the completion of childprocess
+= and then reads the string from the childdata file. If the string in the
+= file matches it's copy of the const char string, then the test succeeds.
diff --git a/src/pal/tests/palsuite/threading/CreateProcessW/test2/CMakeLists.txt b/src/pal/tests/palsuite/threading/CreateProcessW/test2/CMakeLists.txt
new file mode 100644
index 0000000000..3feef213c4
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CreateProcessW/test2/CMakeLists.txt
@@ -0,0 +1,36 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(TESTSOURCES
+ parentprocess.c
+)
+
+add_executable(paltest_createprocessw_test2
+ ${TESTSOURCES}
+)
+
+add_dependencies(paltest_createprocessw_test2 coreclrpal)
+
+target_link_libraries(paltest_createprocessw_test2
+ pthread
+ m
+ coreclrpal
+)
+
+
+set(HELPERSOURCES
+ childprocess.c
+)
+
+add_executable(paltest_createprocessw_test2_child
+ ${HELPERSOURCES}
+)
+
+add_dependencies(paltest_createprocessw_test2_child coreclrpal)
+
+target_link_libraries(paltest_createprocessw_test2_child
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/CreateProcessW/test2/childprocess.c b/src/pal/tests/palsuite/threading/CreateProcessW/test2/childprocess.c
new file mode 100644
index 0000000000..b4ab9366d9
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CreateProcessW/test2/childprocess.c
@@ -0,0 +1,78 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: createprocessw/test2/childprocess.c
+**
+** Purpose: This child process reads a string from stdin
+** and writes it out to stdout & stderr
+**
+** Dependencies: memset
+** fgets
+** gputs
+**
+
+**
+**=========================================================*/
+
+#define UNICODE
+#include <palsuite.h>
+#include "test2.h"
+
+
+int __cdecl main( int argc, char **argv )
+{
+ int iRetCode = EXIT_OK_CODE; /* preset exit code to OK */
+ char szBuf[BUF_LEN];
+
+ WCHAR *swzParam1, *swzParam2, *swzParam3 = NULL;
+
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+ if (argc != 4)
+ {
+ return EXIT_ERR_CODE3;
+ }
+
+ swzParam1 = convert(argv[1]);
+ swzParam2 = convert(argv[2]);
+ swzParam3 = convert(argv[3]);
+
+ if (wcscmp(swzParam1, szArg1) != 0
+ || wcscmp(swzParam2, szArg2) != 0
+ || wcscmp(swzParam3, szArg3) != 0)
+ {
+ return EXIT_ERR_CODE4;
+ }
+
+ free(swzParam1);
+ free(swzParam2);
+ free(swzParam3);
+
+ memset(szBuf, 0, BUF_LEN);
+
+ /* Read the string that was written by the parent */
+ if (fgets(szBuf, BUF_LEN, stdin) == NULL)
+ {
+ return EXIT_ERR_CODE1;
+ }
+
+
+ /* Write the string out to the stdout & stderr pipes */
+ if (fputs(szBuf, stdout) == EOF
+ || fputs(szBuf, stderr) == EOF)
+ {
+ return EXIT_ERR_CODE2;
+ }
+
+ /* The exit code will indicate success or failure */
+ PAL_TerminateEx(iRetCode);
+
+ /* Return special exit code to indicate success or failure */
+ return iRetCode;
+}
diff --git a/src/pal/tests/palsuite/threading/CreateProcessW/test2/parentprocess.c b/src/pal/tests/palsuite/threading/CreateProcessW/test2/parentprocess.c
new file mode 100644
index 0000000000..439b7b5eef
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CreateProcessW/test2/parentprocess.c
@@ -0,0 +1,245 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: createprocessw/test2/parentprocess.c
+**
+** Purpose: Test the following features of CreateProcessW:
+** - Check to see if hProcess & hThread are set in
+** return PROCESS_INFORMATION structure
+** - Check to see if stdin, stdout, & stderr handles
+** are used when STARTF_USESTDHANDLES is specified
+** in STARUPINFO flags and bInheritHandles = TRUE
+** - Check to see that proper arguments are passed to
+** child process
+**
+** Dependencies: CreatePipe
+** strcpy, strlen, strncmp, memset
+** WaitForSingleObject
+** WriteFile, ReadFile
+** GetExitCodeProcess
+**
+
+**
+**=========================================================*/
+
+#define UNICODE
+#include <palsuite.h>
+#include "test2.h"
+
+
+
+int __cdecl main( int argc, char **argv )
+{
+
+ /*******************************************
+ * Declarations
+ *******************************************/
+ STARTUPINFO si;
+ PROCESS_INFORMATION pi;
+
+ HANDLE hTestStdInR = NULL;
+ HANDLE hTestStdInW = NULL;
+ HANDLE hTestStdOutR = NULL;
+ HANDLE hTestStdOutW = NULL;
+ HANDLE hTestStdErrR = NULL;
+ HANDLE hTestStdErrW = NULL;
+
+ BOOL bRetVal = FALSE;
+ DWORD dwBytesWritten = 0;
+ DWORD dwBytesRead = 0;
+ DWORD dwExitCode = 0;
+
+ SECURITY_ATTRIBUTES pipeAttributes;
+
+ char szStdOutBuf[BUF_LEN];
+ char szStdErrBuf[BUF_LEN];
+ WCHAR szFullPathNameW[_MAX_PATH];
+
+
+ /*******************************************
+ * Initialization
+ *******************************************/
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return ( FAIL );
+ }
+
+ /*Setup SECURITY_ATTRIBUTES structure for CreatePipe*/
+ pipeAttributes.nLength = sizeof(SECURITY_ATTRIBUTES);
+ pipeAttributes.lpSecurityDescriptor = NULL;
+ pipeAttributes.bInheritHandle = TRUE;
+
+
+ /*Create a StdIn pipe for child*/
+ bRetVal = CreatePipe(&hTestStdInR, /* read handle*/
+ &hTestStdInW, /* write handle */
+ &pipeAttributes, /* security attributes*/
+ 1024); /* pipe size*/
+
+ if (bRetVal == FALSE)
+ {
+ Fail("ERROR: %ld :Unable to create stdin pipe\n", GetLastError());
+ }
+
+
+ /*Create a StdOut pipe for child*/
+ bRetVal = CreatePipe(&hTestStdOutR, /* read handle*/
+ &hTestStdOutW, /* write handle */
+ &pipeAttributes, /* security attributes*/
+ 0); /* pipe size*/
+
+ if (bRetVal == FALSE)
+ {
+ Fail("ERROR: %ld :Unable to create stdout pipe\n", GetLastError());
+ }
+
+
+ /*Create a StdErr pipe for child*/
+ bRetVal = CreatePipe(&hTestStdErrR, /* read handle*/
+ &hTestStdErrW, /* write handle */
+ &pipeAttributes, /* security attributes*/
+ 0); /* pipe size*/
+
+ if (bRetVal == FALSE)
+ {
+ Fail("ERROR: %ld :Unable to create stderr pipe\n", GetLastError());
+ }
+
+ /* Zero the data structure space */
+ ZeroMemory ( &pi, sizeof(pi) );
+ ZeroMemory ( &si, sizeof(si) );
+
+ /* Set the process flags and standard io handles */
+ si.cb = sizeof(si);
+ si.dwFlags = STARTF_USESTDHANDLES;
+ si.hStdInput = hTestStdInR;
+ si.hStdOutput = hTestStdOutW;
+ si.hStdError = hTestStdErrW;
+
+ wcscpy(szFullPathNameW, szChildFileW);
+ wcscat(szFullPathNameW, szArgs);
+
+ /*******************************************
+ * Start Testing
+ *******************************************/
+
+ /* Launch the child */
+ if ( !CreateProcess (NULL, szFullPathNameW, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi ))
+ {
+ Fail("ERROR: CreateProcess call failed. GetLastError returned %d\n",
+ GetLastError() );
+ }
+
+ /* Check the returned process information for validity */
+ if (pi.hProcess == 0 || pi.hThread == 0)
+ {
+ Fail("ERROR: CreateProcess Error: Process Handle = %u, Thread Handle = %u\n",
+ pi.hProcess, pi.hThread);
+ }
+
+
+ /* Write the Constructed string to stdin pipe for the child process */
+ if (WriteFile(hTestStdInW, szTestString, strlen(szTestString), &dwBytesWritten, NULL) == FALSE
+ || WriteFile(hTestStdInW, "\n", strlen("\n"), &dwBytesWritten, NULL) == FALSE)
+ {
+ Fail("ERROR: %ld :unable to write to write pipe handle "
+ "hTestStdInW=0x%lx\n", GetLastError(), hTestStdInW);
+ }
+
+ /* Wait for the child to finish, Max 20 seconds */
+ dwExitCode = WaitForSingleObject(pi.hProcess, 20000);
+
+ /* If the child failed then whole thing fails */
+ if (dwExitCode != WAIT_OBJECT_0)
+ {
+ TerminateProcess(pi.hProcess, 0);
+ Fail("ERROR: The child failed to run properly.\n");
+ }
+
+ /* Check for problems in the child process */
+ if (GetExitCodeProcess(pi.hProcess, &dwExitCode) == FALSE)
+ {
+ Fail("ERROR: Call to GetExitCodeProcess failed.\n");
+ }
+ else if (dwExitCode == EXIT_ERR_CODE1)
+ {
+ Fail("ERROR: The Child process could not reead the string "
+ "written to the stdin pipe.\n");
+ }
+ else if (dwExitCode == EXIT_ERR_CODE2)
+ {
+ Fail("ERROR: The Child process could not write the string "
+ "the stdout pipe or stderr pipe.\n");
+ }
+ else if (dwExitCode == EXIT_ERR_CODE3)
+ {
+ Fail("ERROR: The Child received the wrong number of "
+ "command line arguments.\n");
+ }
+ else if (dwExitCode == EXIT_ERR_CODE4)
+ {
+ Fail("ERROR: The Child received the wrong "
+ "command line arguments.\n");
+ }
+ else if (dwExitCode != EXIT_OK_CODE)
+ {
+ Fail("ERROR: Unexpected exit code returned: %u. Child process "
+ "did not complete its part of the test.\n", dwExitCode);
+ }
+
+
+ /* The child ran ok, so check to see if we received the proper */
+ /* strings through the pipes. */
+
+ /* clear our buffers */
+ memset(szStdOutBuf, 0, BUF_LEN);
+ memset(szStdErrBuf, 0, BUF_LEN);
+
+ /* Read the data back from the child process stdout */
+ bRetVal = ReadFile(hTestStdOutR, /* handle to read pipe*/
+ szStdOutBuf, /* buffer to write to*/
+ BUF_LEN, /* number of bytes to read*/
+ &dwBytesRead, /* number of bytes read*/
+ NULL); /* overlapped buffer*/
+
+ /*Read the data back from the child process stderr */
+ bRetVal = ReadFile(hTestStdErrR, /* handle to read pipe*/
+ szStdErrBuf, /* buffer to write to*/
+ BUF_LEN, /* number of bytes to read*/
+ &dwBytesRead, /* number of bytes read*/
+ NULL); /* overlapped buffer*/
+
+
+ /* Confirm that we recieved the same string that we originally */
+ /* wrote to the child and was received on both stdout & stderr.*/
+ if (strncmp(szTestString, szStdOutBuf, strlen(szTestString)) != 0
+ || strncmp(szTestString, szStdErrBuf, strlen(szTestString)) != 0)
+ {
+ Fail("ERROR: The data read back from child does not match "
+ "what was written. STDOUT: %s STDERR: %s\n",
+ szStdOutBuf, szStdErrBuf);
+ }
+
+
+ /*******************************************
+ * Clean Up
+ *******************************************/
+
+ /* Close process and thread handle */
+ CloseHandle ( pi.hProcess );
+ CloseHandle ( pi.hThread );
+
+ CloseHandle(hTestStdInR);
+ CloseHandle(hTestStdInW);
+ CloseHandle(hTestStdOutR);
+ CloseHandle(hTestStdOutW);
+ CloseHandle(hTestStdErrR);
+ CloseHandle(hTestStdErrW);
+
+ PAL_Terminate();
+ return ( PASS );
+}
diff --git a/src/pal/tests/palsuite/threading/CreateProcessW/test2/test2.h b/src/pal/tests/palsuite/threading/CreateProcessW/test2/test2.h
new file mode 100644
index 0000000000..07d40b8942
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CreateProcessW/test2/test2.h
@@ -0,0 +1,31 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: test2.h
+**
+**
+
+**
+**=========================================================*/
+
+
+const WCHAR szChildFileW[] = u"paltest_createprocessw_test2_child";
+const WCHAR szArgs[] = {' ',0x41,' ','B',' ','C','\0'};
+const WCHAR szArg1[] = {0x41,'\0'};
+const WCHAR szArg2[] = {'B','\0'};
+const WCHAR szArg3[] = {'C','\0'};
+
+const char *szTestString = "An uninteresting test string (it works though)";
+
+const DWORD EXIT_OK_CODE = 100;
+const DWORD EXIT_ERR_CODE1 = 101;
+const DWORD EXIT_ERR_CODE2 = 102;
+const DWORD EXIT_ERR_CODE3 = 103;
+const DWORD EXIT_ERR_CODE4 = 104;
+const DWORD EXIT_ERR_CODE5 = 105;
+
+#define BUF_LEN 128
+
diff --git a/src/pal/tests/palsuite/threading/CreateProcessW/test2/testinfo.dat b/src/pal/tests/palsuite/threading/CreateProcessW/test2/testinfo.dat
new file mode 100644
index 0000000000..d16ae593f2
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CreateProcessW/test2/testinfo.dat
@@ -0,0 +1,20 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = CreateProcessW
+Name = PROCESS_INFORMATION and HANDLE Inheritance
+TYPE = DEFAULT
+EXE1 = parentprocess
+EXE2 = childprocess
+Description
+= Test the following features of CreateProcessW:
+= - Check to see if hProcess & hThread are set in
+= return PROCESS_INFORMATION structure
+= - Check to see if stdin, stdout, & stderr handles
+= are used when STARTF_USESTDHANDLES is specified
+= in STARUPINFO flags and bInheritHandles = TRUE
+= - Check to see that proper arguments are passed to
+= child process
diff --git a/src/pal/tests/palsuite/threading/CreateSemaphoreA_ReleaseSemaphore/CMakeLists.txt b/src/pal/tests/palsuite/threading/CreateSemaphoreA_ReleaseSemaphore/CMakeLists.txt
new file mode 100644
index 0000000000..1962ade358
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CreateSemaphoreA_ReleaseSemaphore/CMakeLists.txt
@@ -0,0 +1,6 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+add_subdirectory(test3)
+
diff --git a/src/pal/tests/palsuite/threading/CreateSemaphoreA_ReleaseSemaphore/test1/CMakeLists.txt b/src/pal/tests/palsuite/threading/CreateSemaphoreA_ReleaseSemaphore/test1/CMakeLists.txt
new file mode 100644
index 0000000000..f89e150a32
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CreateSemaphoreA_ReleaseSemaphore/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ CreateSemaphore.c
+)
+
+add_executable(paltest_createsemaphorea_releasesemaphore_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_createsemaphorea_releasesemaphore_test1 coreclrpal)
+
+target_link_libraries(paltest_createsemaphorea_releasesemaphore_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/CreateSemaphoreA_ReleaseSemaphore/test1/CreateSemaphore.c b/src/pal/tests/palsuite/threading/CreateSemaphoreA_ReleaseSemaphore/test1/CreateSemaphore.c
new file mode 100644
index 0000000000..342b15ec29
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CreateSemaphoreA_ReleaseSemaphore/test1/CreateSemaphore.c
@@ -0,0 +1,322 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: createsemaphorea_releasesemaphore/test1/createsemaphore.c
+**
+** Purpose: Test Semaphore operation using classic IPC problem:
+** "Producer-Consumer Problem".
+**
+** Dependencies: CreateThread
+** ReleaseSemaphore
+** WaitForSingleObject
+** Sleep
+** fflush
+**
+
+**
+**=========================================================*/
+
+#include <palsuite.h>
+
+#define PRODUCTION_TOTAL 26
+
+#define _BUF_SIZE 10
+
+DWORD dwThreadId; /* consumer thread identifier */
+
+HANDLE hThread; /* handle to consumer thread */
+
+HANDLE hSemaphoreM; /* handle to mutual exclusion semaphore */
+
+HANDLE hSemaphoreE; /* handle to semaphore that counts empty buffer slots */
+
+HANDLE hSemaphoreF; /* handle to semaphore that counts full buffer slots */
+
+typedef struct Buffer
+{
+ short readIndex;
+ short writeIndex;
+ CHAR message[_BUF_SIZE];
+
+} BufferStructure;
+
+CHAR producerItems[PRODUCTION_TOTAL + 1];
+
+CHAR consumerItems[PRODUCTION_TOTAL + 1];
+
+/*
+ * Read next message from the Buffer into provided pointer.
+ * Returns: 0 on failure, 1 on success.
+ */
+int
+readBuf(BufferStructure *Buffer, char *c)
+{
+ if( Buffer -> writeIndex == Buffer -> readIndex )
+ {
+ return 0;
+ }
+ *c = Buffer -> message[Buffer -> readIndex++];
+ Buffer -> readIndex %= _BUF_SIZE;
+ return 1;
+}
+
+/*
+ * Write message generated by the producer to Buffer.
+ * Returns: 0 on failure, 1 on success.
+ */
+int
+writeBuf(BufferStructure *Buffer, CHAR c)
+{
+ if( ( ((Buffer -> writeIndex) + 1) % _BUF_SIZE) ==
+ (Buffer -> readIndex) )
+ {
+ return 0;
+ }
+ Buffer -> message[Buffer -> writeIndex++] = c;
+ Buffer -> writeIndex %= _BUF_SIZE;
+ return 1;
+}
+
+/*
+ * Atomic decrement of semaphore value.
+ */
+VOID
+down(HANDLE hSemaphore)
+{
+ switch ( (WaitForSingleObject (
+ hSemaphore,
+ 10000))) /* Wait 10 seconds */
+ {
+ case WAIT_OBJECT_0: /*
+ * Semaphore was signaled. OK to access
+ * semaphore.
+ */
+ break;
+ case WAIT_ABANDONED: /*
+ * Object was mutex object whose owning
+ * thread has terminated. Shouldn't occur.
+ */
+ Fail("WaitForSingleObject call returned 'WAIT_ABANDONED'.\n"
+ "Failing Test.\n");
+ break;
+ case WAIT_FAILED: /* WaitForSingleObject function failed */
+ Fail("WaitForSingleObject call returned 'WAIT_FAILED'.\n"
+ "GetLastError returned %d\nFailing Test.\n",GetLastError());
+ break;
+ default:
+ Fail("WaitForSingleObject call returned an unexpected value.\n"
+ "Failing Test.\n");
+ break;
+ }
+
+}
+
+/*
+ * Atomic increment of semaphore value.
+ */
+VOID
+up(HANDLE hSemaphore)
+{
+ if (!ReleaseSemaphore (
+ hSemaphore,
+ 1,
+ NULL)
+ )
+ {
+ Fail("ReleaseSemaphore call failed. GetLastError returned %d\n",
+ GetLastError());
+ }
+}
+
+/*
+ * Sleep 500 milleseconds.
+ */
+VOID
+consumerSleep(VOID)
+{
+ Sleep(500);
+}
+
+/*
+ * Sleep between 10 milleseconds.
+ */
+VOID
+producerSleep(VOID)
+{
+ Sleep(10);
+}
+
+/*
+ * Produce a message and write the message to Buffer.
+ */
+VOID
+producer(BufferStructure *Buffer)
+{
+
+ int n = 0;
+ char c;
+
+ while (n < PRODUCTION_TOTAL)
+ {
+ c = 'A' + n ; /* Produce Item */
+
+ down(hSemaphoreE);
+ down(hSemaphoreM);
+
+ if (writeBuf(Buffer, c))
+ {
+ Trace("Producer produces %c.\n", c);
+ fflush(stdout);
+ producerItems[n++] = c;
+ }
+
+ up(hSemaphoreM);
+ up(hSemaphoreF);
+
+ producerSleep();
+ }
+
+ return;
+}
+
+/*
+ * Read and "Consume" the messages in Buffer.
+ */
+DWORD
+PALAPI
+consumer( LPVOID lpParam )
+{
+ int n = 0;
+ char c;
+
+ consumerSleep();
+
+ while (n < PRODUCTION_TOTAL)
+ {
+
+ down(hSemaphoreF);
+ down(hSemaphoreM);
+
+ if (readBuf((BufferStructure*)lpParam, &c))
+ {
+ Trace("\tConsumer consumes %c.\n", c);
+ fflush(stdout);
+ consumerItems[n++] = c;
+ }
+
+ up(hSemaphoreM);
+ up(hSemaphoreE);
+
+ consumerSleep();
+ }
+
+ return 0;
+}
+
+int __cdecl main (int argc, char **argv)
+{
+
+ BufferStructure Buffer, *pBuffer;
+
+ pBuffer = &Buffer;
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return ( FAIL );
+ }
+
+ /*
+ * Create Semaphores
+ */
+ hSemaphoreM = CreateSemaphoreA (
+ NULL,
+ 1,
+ 1,
+ NULL);
+
+ if ( NULL == hSemaphoreM )
+ {
+ Fail ( "hSemaphoreM = CreateSemaphoreA () - returned NULL\n"
+ "Failing Test.\nGetLastError returned %d\n", GetLastError());
+ }
+
+
+ hSemaphoreE = CreateSemaphoreA (
+ NULL,
+ _BUF_SIZE ,
+ _BUF_SIZE ,
+ NULL);
+
+ if ( NULL == hSemaphoreE )
+ {
+ Fail ( "hSemaphoreE = CreateSemaphoreA () - returned NULL\n"
+ "Failing Test.\nGetLastError returned %d\n", GetLastError());
+ }
+
+ hSemaphoreF = CreateSemaphoreA (
+ NULL,
+ 0,
+ _BUF_SIZE ,
+ NULL);
+
+ if ( NULL == hSemaphoreF )
+ {
+ Fail ( "hSemaphoreF = CreateSemaphoreA () - returned NULL\n"
+ "Failing Test.\nGetLastError returned %d\n", GetLastError());
+ }
+
+
+ /*
+ * Initialize Buffer
+ */
+ pBuffer->writeIndex = pBuffer->readIndex = 0;
+
+ /*
+ * Create Consumer
+ */
+ hThread = CreateThread(
+ NULL,
+ 0,
+ consumer,
+ &Buffer,
+ 0,
+ &dwThreadId);
+
+ if ( NULL == hThread )
+ {
+ Fail ( "CreateThread() returned NULL. Failing test.\n"
+ "GetLastError returned %d\n", GetLastError());
+ }
+
+ /*
+ * Start producing
+ */
+ producer(pBuffer);
+
+ /*
+ * Wait for consumer to complete
+ */
+ WaitForSingleObject (hThread, INFINITE);
+
+ /*
+ * Compare items produced vs. items consumed
+ */
+ if ( 0 != strncmp (producerItems, consumerItems, PRODUCTION_TOTAL) )
+ {
+ Fail("The producerItems string %s\n and the consumerItems string "
+ "%s\ndo not match. This could be a problem with the strncmp()"
+ " function\n FailingTest\nGetLastError() returned %d\n",
+ producerItems, consumerItems, GetLastError());
+ }
+
+ Trace ("producerItems and consumerItems arrays match. All %d\nitems "
+ "were produced and consumed in order.\nTest passed.\n",
+ PRODUCTION_TOTAL);
+
+ PAL_Terminate();
+ return ( PASS );
+
+}
diff --git a/src/pal/tests/palsuite/threading/CreateSemaphoreA_ReleaseSemaphore/test1/testinfo.dat b/src/pal/tests/palsuite/threading/CreateSemaphoreA_ReleaseSemaphore/test1/testinfo.dat
new file mode 100644
index 0000000000..880746e43e
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CreateSemaphoreA_ReleaseSemaphore/test1/testinfo.dat
@@ -0,0 +1,18 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = CreateSemaphoreA / ReleaseSemaphore
+Name = Positive Test for CreateSemaphoreA and ReleaseSemaphore
+TYPE = DEFAULT
+EXE1 = createsemaphore
+Description
+= Implementation of Producer / Consumer IPC problem using CreateSemaphoreA
+= and ReleaseSemaphore functions. This test case exercises CreateSemaphoreA
+= , ReleaseSemaphore, CreateThread and WaitForSingleObject functions.
+= Since there is no way to currently create "pseudo" random events in the
+= pal, this example does not behave as classic bounded buffers would. This
+= test case is designed to starve the consumer and have the producer fill
+= the buffer.
diff --git a/src/pal/tests/palsuite/threading/CreateSemaphoreA_ReleaseSemaphore/test2/CMakeLists.txt b/src/pal/tests/palsuite/threading/CreateSemaphoreA_ReleaseSemaphore/test2/CMakeLists.txt
new file mode 100644
index 0000000000..f3e01749b8
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CreateSemaphoreA_ReleaseSemaphore/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ CreateSemaphore.c
+)
+
+add_executable(paltest_createsemaphorea_releasesemaphore_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_createsemaphorea_releasesemaphore_test2 coreclrpal)
+
+target_link_libraries(paltest_createsemaphorea_releasesemaphore_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/CreateSemaphoreA_ReleaseSemaphore/test2/CreateSemaphore.c b/src/pal/tests/palsuite/threading/CreateSemaphoreA_ReleaseSemaphore/test2/CreateSemaphore.c
new file mode 100644
index 0000000000..bff5b51c33
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CreateSemaphoreA_ReleaseSemaphore/test2/CreateSemaphore.c
@@ -0,0 +1,313 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: CreateSemaphoreA_ReleaseSemaphore/test2/createsemaphore.c
+**
+** Purpose: Test Semaphore operation using classic IPC problem:
+** "Producer-Consumer Problem".
+**
+** Dependencies: CreateThread
+** ReleaseSemaphore
+** WaitForSingleObject
+** Sleep
+** fflush
+**
+
+**
+**=========================================================*/
+
+#include <palsuite.h>
+
+#define PRODUCTION_TOTAL 26
+
+#define _BUF_SIZE 10
+
+DWORD dwThreadId; /* consumer thread identifier */
+
+HANDLE hThread; /* handle to consumer thread */
+
+HANDLE hSemaphoreM; /* handle to mutual exclusion semaphore */
+
+HANDLE hSemaphoreE; /* handle to semaphore that counts empty buffer slots */
+
+HANDLE hSemaphoreF; /* handle to semaphore that counts full buffer slots */
+
+typedef struct Buffer
+{
+ short readIndex;
+ short writeIndex;
+ CHAR message[_BUF_SIZE];
+
+} BufferStructure;
+
+CHAR producerItems[PRODUCTION_TOTAL + 1];
+
+CHAR consumerItems[PRODUCTION_TOTAL + 1];
+
+/*
+ * Read next message from the Buffer into provided pointer.
+ * Returns: 0 on failure, 1 on success.
+ */
+int
+readBuf(BufferStructure *Buffer, char *c)
+{
+ if( Buffer -> writeIndex == Buffer -> readIndex )
+ {
+ return 0;
+ }
+ *c = Buffer -> message[Buffer -> readIndex++];
+ Buffer -> readIndex %= _BUF_SIZE;
+ return 1;
+}
+
+/*
+ * Write message generated by the producer to Buffer.
+ * Returns: 0 on failure, 1 on success.
+ */
+int
+writeBuf(BufferStructure *Buffer, CHAR c)
+{
+ if( ( ((Buffer -> writeIndex) + 1) % _BUF_SIZE) ==
+ (Buffer -> readIndex) )
+ {
+ return 0;
+ }
+ Buffer -> message[Buffer -> writeIndex++] = c;
+ Buffer -> writeIndex %= _BUF_SIZE;
+ return 1;
+}
+
+/*
+ * Atomic decrement of semaphore value.
+ */
+VOID
+down(HANDLE hSemaphore)
+{
+ switch ( (WaitForSingleObject (
+ hSemaphore,
+ 10000)))
+ {
+ case WAIT_OBJECT_0: /*
+ * Semaphore was signaled. OK to access semaphore.
+ */
+ break;
+ case WAIT_ABANDONED: /*
+ * Object was mutex object whose owning
+ * thread has terminated. Shouldn't occur.
+ */
+ Fail("WaitForSingleObject call returned 'WAIT_ABANDONED'.\n"
+ "Failing Test.\n");
+ break;
+ case WAIT_FAILED: /* WaitForSingleObject function failed */
+ Fail("WaitForSingleObject call returned 'WAIT_FAILED'.\n"
+ "GetLastError returned %d\nFailing Test.\n",GetLastError());
+ break;
+ default:
+ Fail("WaitForSingleObject call returned an unexpected value.\n"
+ "Failing Test.\n");
+ break;
+ }
+
+}
+
+/*
+ * Atomic increment of semaphore value.
+ */
+VOID
+up(HANDLE hSemaphore)
+{
+ if (!ReleaseSemaphore (
+ hSemaphore,
+ 1,
+ NULL)
+ )
+ {
+ Fail("ReleaseSemaphore call failed. GetLastError returned %d\n",
+ GetLastError());
+ }
+}
+
+/*
+ * Sleep 10 milleseconds.
+ */
+VOID
+consumerSleep(VOID)
+{
+ Sleep(10);
+}
+
+/*
+ * Sleep 500 milleseconds.
+ */
+VOID
+producerSleep(VOID)
+{
+ Sleep(500);
+}
+
+/*
+ * Produce a message and write the message to Buffer.
+ */
+VOID
+producer(BufferStructure *Buffer)
+{
+
+ int n = 0;
+ char c;
+
+ while (n < PRODUCTION_TOTAL)
+ {
+ c = 'A' + n ; /* Produce Item */
+
+ down(hSemaphoreE);
+ down(hSemaphoreM);
+
+ if (writeBuf(Buffer, c))
+ {
+ Trace("Producer produces %c.\n", c);
+ fflush(stdout);
+ producerItems[n++] = c;
+ }
+
+ up(hSemaphoreM);
+ up(hSemaphoreF);
+
+ producerSleep();
+ }
+ return;
+}
+
+/*
+ * Read and "Consume" the messages in Buffer.
+ */
+DWORD
+PALAPI
+consumer( LPVOID lpParam )
+{
+ int n = 0;
+ char c;
+
+ consumerSleep();
+
+ while (n < PRODUCTION_TOTAL)
+ {
+
+ down(hSemaphoreF);
+ down(hSemaphoreM);
+
+ if (readBuf((BufferStructure*)lpParam, &c))
+ {
+ Trace("\tConsumer consumes %c.\n", c);
+ fflush(stdout);
+ consumerItems[n++] = c;
+ }
+
+ up(hSemaphoreM);
+ up(hSemaphoreE);
+
+ consumerSleep();
+ }
+ return 0;
+}
+
+int __cdecl main (int argc, char **argv)
+{
+
+ BufferStructure Buffer, *pBuffer;
+
+ pBuffer = &Buffer;
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return (FAIL);
+ }
+
+ /*
+ * Create Semaphores
+ */
+ hSemaphoreM = CreateSemaphoreA (
+ NULL,
+ 1,
+ 1,
+ NULL);
+
+ if ( NULL == hSemaphoreM )
+ {
+ Fail ( "hSemaphoreM = CreateSemaphoreA () - returned NULL\n"
+ "Failing Test.\n");
+ }
+
+ hSemaphoreE = CreateSemaphoreA (
+ NULL,
+ _BUF_SIZE ,
+ _BUF_SIZE ,
+ NULL);
+
+ if ( NULL == hSemaphoreE )
+ {
+ Fail ( "hSemaphoreE = CreateSemaphoreA () - returned NULL\n"
+ "Failing Test.\n");
+ }
+
+ hSemaphoreF = CreateSemaphoreA (
+ NULL,
+ 0,
+ _BUF_SIZE ,
+ NULL);
+
+ if ( NULL == hSemaphoreF )
+ {
+ Fail ( "hSemaphoreF = CreateSemaphoreA () - returned NULL\n"
+ "Failing Test.\n");
+ }
+
+ /*
+ * Initialize Buffer
+ */
+ pBuffer->writeIndex = pBuffer->readIndex = 0;
+
+ /*
+ * Create Consumer
+ */
+ hThread = CreateThread(
+ NULL,
+ 0,
+ consumer,
+ &Buffer,
+ 0,
+ &dwThreadId);
+
+ if ( NULL == hThread )
+ {
+ Fail ( "CreateThread() returned NULL. Failing test.\n");
+ }
+
+ /*
+ * Start producing
+ */
+ producer(pBuffer);
+
+ /*
+ * Wait for consumer to complete
+ */
+ WaitForSingleObject (hThread, INFINITE);
+
+ if ( 0 != strncmp (producerItems, consumerItems, PRODUCTION_TOTAL) )
+ {
+ Fail("The producerItems string %s\n and the consumerItems string "
+ "%s\ndo not match. This could be a problem with the strncmp()"
+ " function\n FailingTest\nGetLastError() returned %d\n",
+ producerItems, consumerItems, GetLastError());
+ }
+
+ Trace ("producerItems and consumerItems arrays match. All %d\nitems "
+ "were produced and consumed in order.\nTest passed.\n",
+ PRODUCTION_TOTAL);
+
+ PAL_Terminate();
+ return ( PASS );
+
+}
diff --git a/src/pal/tests/palsuite/threading/CreateSemaphoreA_ReleaseSemaphore/test2/testinfo.dat b/src/pal/tests/palsuite/threading/CreateSemaphoreA_ReleaseSemaphore/test2/testinfo.dat
new file mode 100644
index 0000000000..5a6c2e7909
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CreateSemaphoreA_ReleaseSemaphore/test2/testinfo.dat
@@ -0,0 +1,18 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = CreateSemaphoreA / ReleaseSemaphore
+Name = Positive Test for CreateSemaphoreA and ReleaseSemaphore
+TYPE = DEFAULT
+EXE1 = createsemaphore
+Description
+= Implementation of Producer / Consumer IPC problem using CreateSemaphoreA
+= and ReleaseSemaphore functions. This test case exercises CreateSemaphoreA
+= , ReleaseSemaphore, CreateThread and WaitForSingleObject functions.
+= Since there is no way to currently create "pseudo" random events in the
+= pal, this example does not behave as classic bounded buffers would. This
+= test case is designed to starve the producer and have the consumer fill
+= the buffer.
diff --git a/src/pal/tests/palsuite/threading/CreateSemaphoreA_ReleaseSemaphore/test3/CMakeLists.txt b/src/pal/tests/palsuite/threading/CreateSemaphoreA_ReleaseSemaphore/test3/CMakeLists.txt
new file mode 100644
index 0000000000..0c604d6ced
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CreateSemaphoreA_ReleaseSemaphore/test3/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ createsemaphore.c
+)
+
+add_executable(paltest_createsemaphorea_releasesemaphore_test3
+ ${SOURCES}
+)
+
+add_dependencies(paltest_createsemaphorea_releasesemaphore_test3 coreclrpal)
+
+target_link_libraries(paltest_createsemaphorea_releasesemaphore_test3
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/CreateSemaphoreA_ReleaseSemaphore/test3/createsemaphore.c b/src/pal/tests/palsuite/threading/CreateSemaphoreA_ReleaseSemaphore/test3/createsemaphore.c
new file mode 100644
index 0000000000..7c6db6b055
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CreateSemaphoreA_ReleaseSemaphore/test3/createsemaphore.c
@@ -0,0 +1,200 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: createsemaphorea_releasesemaphore/test3/createsemaphore.c
+**
+** Purpose: Test attributes of CreateSemaphoreA and ReleaseSemaphore.
+** Insure for CreateSemaphore that lInitialCount and lMaximumCount
+** constraints are respected. Validate that CreateSemaphore rejects
+** conditions where initial count and / or maximum count are negative
+** and conditions where the initial count is greater than the maximum
+** count. For ReleaseSemaphore validate that lpPreviousCount gets set
+** to the previous semaphore count and lpPreviousCount can be NULL.
+** Also establish ReleaseSemaphore fails when called in a semaphore
+** with count equal to lMaximumCount.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+
+struct testcase
+{
+ LPSECURITY_ATTRIBUTES lpSemaphoreAttributes;
+ LONG lInitialCount;
+ LONG lMaximumCount;
+ LPCTSTR lpName;
+ BOOL bNegativeTest;
+};
+
+struct testcase testCases[] =
+{
+ {NULL, -1, 1, NULL, TRUE},
+ {NULL, 1, -1, NULL, TRUE},
+ {NULL, -1, -1, NULL, TRUE},
+ {NULL, 2, 1, NULL, TRUE},
+ {NULL, 1, 2, NULL, FALSE},
+ {NULL, 0, 10, NULL, FALSE},
+ {NULL, INT_MAX - 1, INT_MAX, NULL, FALSE},
+ {NULL, INT_MAX, INT_MAX, NULL, FALSE}
+};
+
+HANDLE hSemaphore[sizeof(testCases)/sizeof(struct testcase)];
+
+BOOL cleanup(int index)
+{
+ int i;
+ BOOL bRet = TRUE;
+ for (i = 0; i < index; i++)
+ {
+ if (!CloseHandle(hSemaphore[i]))
+ {
+ bRet = FALSE;
+ Trace("PALSUITE ERROR: CloseHandle(%p) call failed for index %d\n",
+ hSemaphore[i], i);
+ }
+ }
+ return(bRet);
+}
+
+int __cdecl main (int argc, char **argv)
+{
+ int i;
+ int j;
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return (FAIL);
+ }
+ /* create semaphores */
+ for (i = 0; i < sizeof(testCases)/sizeof(struct testcase); i++)
+ {
+ hSemaphore[i] = CreateSemaphoreA (testCases[i].lpSemaphoreAttributes,
+ testCases[i].lInitialCount,
+ testCases[i].lMaximumCount,
+ testCases[i].lpName);
+
+ if (NULL == hSemaphore[i])
+ {
+ if (!testCases[i].bNegativeTest)
+ {
+ Trace("PALSUITE ERROR: CreateSemaphoreA('%p' '%ld' '%ld' "
+ "'%p') returned NULL at index %d.\nGetLastError "
+ "returned %d.\n", testCases[i].lpSemaphoreAttributes,
+ testCases[i].lInitialCount, testCases[i].lMaximumCount,
+ testCases[i].lpName, i, GetLastError());
+ if (i > 0)
+ {
+ cleanup(i - 1);
+ }
+ Fail("");
+ }
+ else
+ {
+ continue;
+ }
+ }
+
+ /* increment semaphore count to lMaximumCount */
+ for (j = testCases[i].lInitialCount; (ULONG)j <= (ULONG)testCases[i].lMaximumCount;
+ j++)
+ {
+ if (testCases[i].lMaximumCount == j)
+ {
+ /* Call ReleaseSemaphore once more to ensure ReleaseSemaphore
+ fails */
+ if(ReleaseSemaphore(hSemaphore[i], 1, NULL))
+ {
+ Trace("PALSUITE ERROR: ReleaseSemaphore('%p' '%ld' '%p') "
+ "call returned %d\nwhen it should have returned "
+ "%d.\nThe semaphore's count was %d.\nGetLastError "
+ "returned %d.\n", hSemaphore[i], 1, NULL, TRUE,
+ FALSE, j, GetLastError());
+ cleanup(i);
+ Fail("");
+ }
+ }
+ else
+ {
+ int previous;
+ BOOL bRet = ReleaseSemaphore(hSemaphore[i], 1, &previous);
+ DWORD dwError = GetLastError();
+
+ if(!bRet)
+ {
+ Trace("PALSUITE ERROR: ReleaseSemaphore('%p' '%ld' '%p') "
+ "call returned %d\nwhen it should have returned "
+ "%d.\nThe semaphore count was %d and it's "
+ "lMaxCount was %d.\nGetLastError returned %d.\n",
+ hSemaphore[i], 1, &previous, bRet, TRUE, j,
+ testCases[i].lMaximumCount, dwError);
+ cleanup(i);
+ Fail("");
+ }
+ if (previous != j)
+ {
+ Trace("PALSUITE ERROR: ReleaseSemaphore('%p' '%ld' '%p') "
+ "call set %p to %d instead of %d.\n The semaphore "
+ "count was %d and GetLastError returned %d.\n",
+ hSemaphore[i], 1, &previous, &previous, previous,
+ j, j, dwError);
+ cleanup(i);
+ Fail("");
+ }
+ }
+ }
+
+ // Skip exhaustive decrement tests for too large an initial count
+ if(testCases[i].lInitialCount >= INT_MAX - 1)
+ {
+ continue;
+ }
+
+ /* decrement semaphore count to 0 */
+ for (j = testCases[i].lMaximumCount; j >= 0; j--)
+ {
+ DWORD dwRet = WaitForSingleObject(hSemaphore[i], 0);
+ DWORD dwError = GetLastError();
+
+ if (0 == j)
+ {
+ /* WaitForSingleObject should report that the
+ semaphore is nonsignaled */
+ if (WAIT_TIMEOUT != dwRet)
+ {
+ Trace("PALSUITE ERROR: WaitForSingleObject('%p' '%u') "
+ "call returned %d\nwhen it should have returned "
+ "%d.\nThe semaphore's count was %d.\nGetLastError "
+ "returned %d.\n", hSemaphore[i], 0, dwRet,
+ WAIT_TIMEOUT, j, dwError);
+ cleanup(i);
+ Fail("");
+ }
+ }
+ else
+ {
+ /* WaitForSingleObject should report that the
+ semaphore is signaled */
+ if (WAIT_OBJECT_0 != dwRet)
+ {
+ Trace("PALSUITE ERROR: WaitForSingleObject('%p' '%u') "
+ "call returned %d\nwhen it should have returned "
+ "%d.\nThe semaphore's count was %d.\nGetLastError "
+ "returned %d.\n", hSemaphore[i], 0, dwRet,
+ WAIT_OBJECT_0, j, dwError);
+ cleanup(i);
+ Fail("");
+ }
+ }
+ }
+ }
+ PAL_Terminate();
+ return (PASS);
+}
+
+
+
+
diff --git a/src/pal/tests/palsuite/threading/CreateSemaphoreA_ReleaseSemaphore/test3/testinfo.dat b/src/pal/tests/palsuite/threading/CreateSemaphoreA_ReleaseSemaphore/test3/testinfo.dat
new file mode 100644
index 0000000000..d8cd590923
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CreateSemaphoreA_ReleaseSemaphore/test3/testinfo.dat
@@ -0,0 +1,20 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = CreateSemaphoreA / ReleaseSemaphore
+Name = Positive Test for CreateSemaphoreA and ReleaseSemaphore
+TYPE = DEFAULT
+EXE1 = createsemaphore
+Description
+= Test attributes of CreateSemaphoreA and ReleaseSemaphore.
+= Insure for CreateSemaphore that lInitialCount and lMaximumCount
+= constraints are respected. Validate that CreateSemaphore rejects
+= conditions where, initial count and / or maximum count are negative
+= and conditions where the initial count is greater than the maximum
+= count. For ReleaseSemaphore validate that lpPreviousCount gets set
+= to the previous semaphore count and lpPreviousCount can be NULL.
+= Also establish ReleaseSemaphore fails when called in a semaphore
+= with count equal to lMaximumCount.
diff --git a/src/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/CMakeLists.txt b/src/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/CMakeLists.txt
new file mode 100644
index 0000000000..1962ade358
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/CMakeLists.txt
@@ -0,0 +1,6 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+add_subdirectory(test3)
+
diff --git a/src/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/test1/CMakeLists.txt b/src/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/test1/CMakeLists.txt
new file mode 100644
index 0000000000..b40f2695bc
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ CreateSemaphore.c
+)
+
+add_executable(paltest_createsemaphorew_releasesemaphore_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_createsemaphorew_releasesemaphore_test1 coreclrpal)
+
+target_link_libraries(paltest_createsemaphorew_releasesemaphore_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/test1/CreateSemaphore.c b/src/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/test1/CreateSemaphore.c
new file mode 100644
index 0000000000..854d16d0ef
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/test1/CreateSemaphore.c
@@ -0,0 +1,323 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: CreateSemaphoreW_ReleaseSemaphore/test1/CreateSemaphore.c
+**
+** Purpose: Test Semaphore operation using classic IPC problem:
+** "Producer-Consumer Problem".
+**
+** Dependencies: CreateThread
+** ReleaseSemaphore
+** WaitForSingleObject
+** Sleep
+** fflush
+**
+
+**
+**=========================================================*/
+
+#define UNICODE
+#include <palsuite.h>
+
+#define PRODUCTION_TOTAL 26
+
+#define _BUF_SIZE 10
+
+DWORD dwThreadId; /* consumer thread identifier */
+
+HANDLE hThread; /* handle to consumer thread */
+
+HANDLE hSemaphoreM; /* handle to mutual exclusion semaphore */
+
+HANDLE hSemaphoreE; /* handle to semaphore that counts empty buffer slots */
+
+HANDLE hSemaphoreF; /* handle to semaphore that counts full buffer slots */
+
+typedef struct Buffer
+{
+ short readIndex;
+ short writeIndex;
+ CHAR message[_BUF_SIZE];
+
+} BufferStructure;
+
+CHAR producerItems[PRODUCTION_TOTAL + 1];
+
+CHAR consumerItems[PRODUCTION_TOTAL + 1];
+
+/*
+ * Read next message from the Buffer into provided pointer.
+ * Returns: 0 on failure, 1 on success.
+ */
+int
+readBuf(BufferStructure *Buffer, char *c)
+{
+ if( Buffer -> writeIndex == Buffer -> readIndex )
+ {
+ return 0;
+ }
+ *c = Buffer -> message[Buffer -> readIndex++];
+ Buffer -> readIndex %= _BUF_SIZE;
+ return 1;
+}
+
+/*
+ * Write message generated by the producer to Buffer.
+ * Returns: 0 on failure, 1 on success.
+ */
+int
+writeBuf(BufferStructure *Buffer, CHAR c)
+{
+ if( ( ((Buffer -> writeIndex) + 1) % _BUF_SIZE) ==
+ (Buffer -> readIndex) )
+ {
+ return 0;
+ }
+ Buffer -> message[Buffer -> writeIndex++] = c;
+ Buffer -> writeIndex %= _BUF_SIZE;
+ return 1;
+}
+
+/*
+ * Atomic decrement of semaphore value.
+ */
+VOID
+down(HANDLE hSemaphore)
+{
+ switch ( (WaitForSingleObject (
+ hSemaphore,
+ 10000))) /* Wait 10 seconds */
+ {
+ case WAIT_OBJECT_0: /*
+ * Semaphore was signaled. OK to access
+ * semaphore.
+ */
+ break;
+ case WAIT_ABANDONED: /*
+ * Object was mutex object whose owning
+ * thread has terminated. Shouldn't occur.
+ */
+ Fail("WaitForSingleObject call returned 'WAIT_ABANDONED'.\n"
+ "Failing Test.\n");
+ break;
+ case WAIT_FAILED: /* WaitForSingleObject function failed */
+ Fail("WaitForSingleObject call returned 'WAIT_FAILED'.\n"
+ "GetLastError returned %d\nFailing Test.\n",GetLastError());
+ break;
+ default:
+ Fail("WaitForSingleObject call returned an unexpected value.\n"
+ "Failing Test.\n");
+ break;
+ }
+
+}
+
+/*
+ * Atomic increment of semaphore value.
+ */
+VOID
+up(HANDLE hSemaphore)
+{
+ if (!ReleaseSemaphore (
+ hSemaphore,
+ 1,
+ NULL)
+ )
+ {
+ Fail("ReleaseSemaphore call failed. GetLastError returned %d\n",
+ GetLastError());
+ }
+}
+
+/*
+ * Sleep 500 milleseconds.
+ */
+VOID
+consumerSleep(VOID)
+{
+ Sleep(500);
+}
+
+/*
+ * Sleep between 10 milleseconds.
+ */
+VOID
+producerSleep(VOID)
+{
+ Sleep(10);
+}
+
+/*
+ * Produce a message and write the message to Buffer.
+ */
+VOID
+producer(BufferStructure *Buffer)
+{
+
+ int n = 0;
+ char c;
+
+ while (n < PRODUCTION_TOTAL)
+ {
+ c = 'A' + n ; /* Produce Item */
+
+ down(hSemaphoreE);
+ down(hSemaphoreM);
+
+ if (writeBuf(Buffer, c))
+ {
+ Trace("Producer produces %c.\n", c);
+ fflush(stdout);
+ producerItems[n++] = c;
+ }
+
+ up(hSemaphoreM);
+ up(hSemaphoreF);
+
+ producerSleep();
+ }
+
+ return;
+}
+
+/*
+ * Read and "Consume" the messages in Buffer.
+ */
+DWORD
+PALAPI
+consumer( LPVOID lpParam )
+{
+ int n = 0;
+ char c;
+
+ consumerSleep();
+
+ while (n < PRODUCTION_TOTAL)
+ {
+
+ down(hSemaphoreF);
+ down(hSemaphoreM);
+
+ if (readBuf((BufferStructure*)lpParam, &c))
+ {
+ Trace("\tConsumer consumes %c.\n", c);
+ fflush(stdout);
+ consumerItems[n++] = c;
+ }
+
+ up(hSemaphoreM);
+ up(hSemaphoreE);
+
+ consumerSleep();
+ }
+
+ return 0;
+}
+
+int __cdecl main (int argc, char **argv)
+{
+
+ BufferStructure Buffer, *pBuffer;
+
+ pBuffer = &Buffer;
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return ( FAIL );
+ }
+
+ /*
+ * Create Semaphores
+ */
+ hSemaphoreM = CreateSemaphoreW (
+ NULL,
+ 1,
+ 1,
+ NULL);
+
+ if ( NULL == hSemaphoreM )
+ {
+ Fail ( "hSemaphoreM = CreateSemaphoreW () - returned NULL\n"
+ "Failing Test.\nGetLastError returned %d\n", GetLastError());
+ }
+
+
+ hSemaphoreE = CreateSemaphoreW (
+ NULL,
+ _BUF_SIZE ,
+ _BUF_SIZE ,
+ NULL);
+
+ if ( NULL == hSemaphoreE )
+ {
+ Fail ( "hSemaphoreE = CreateSemaphoreW () - returned NULL\n"
+ "Failing Test.\nGetLastError returned %d\n", GetLastError());
+ }
+
+ hSemaphoreF = CreateSemaphoreW (
+ NULL,
+ 0,
+ _BUF_SIZE ,
+ NULL);
+
+ if ( NULL == hSemaphoreF )
+ {
+ Fail ( "hSemaphoreF = CreateSemaphoreW () - returned NULL\n"
+ "Failing Test.\nGetLastError returned %d\n", GetLastError());
+ }
+
+
+ /*
+ * Initialize Buffer
+ */
+ pBuffer->writeIndex = pBuffer->readIndex = 0;
+
+ /*
+ * Create Consumer
+ */
+ hThread = CreateThread(
+ NULL,
+ 0,
+ consumer,
+ &Buffer,
+ 0,
+ &dwThreadId);
+
+ if ( NULL == hThread )
+ {
+ Fail ( "CreateThread() returned NULL. Failing test.\n"
+ "GetLastError returned %d\n", GetLastError());
+ }
+
+ /*
+ * Start producing
+ */
+ producer(pBuffer);
+
+ /*
+ * Wait for consumer to complete
+ */
+ WaitForSingleObject (hThread, INFINITE);
+
+ /*
+ * Compare items produced vs. items consumed
+ */
+ if ( 0 != strncmp (producerItems, consumerItems, PRODUCTION_TOTAL) )
+ {
+ Fail("The producerItems string %s\n and the consumerItems string "
+ "%s\ndo not match. This could be a problem with the strncmp()"
+ " function\n FailingTest\nGetLastError() returned %d\n",
+ producerItems, consumerItems, GetLastError());
+ }
+
+ Trace ("producerItems and consumerItems arrays match. All %d\nitems "
+ "were produced and consumed in order.\nTest passed.\n",
+ PRODUCTION_TOTAL);
+
+ PAL_Terminate();
+ return ( PASS );
+
+}
diff --git a/src/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/test1/testinfo.dat b/src/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/test1/testinfo.dat
new file mode 100644
index 0000000000..9127589333
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/test1/testinfo.dat
@@ -0,0 +1,18 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = CreateSemaphoreW / ReleaseSemaphore
+Name = Positive Test for CreateSemaphoreW and ReleaseSemaphore
+TYPE = DEFAULT
+EXE1 = createsemaphore
+Description
+= Implementation of Producer / Consumer IPC problem using CreateSemaphoreW
+= and ReleaseSemaphore functions. This test case exercises CreateSemaphoreW
+= , ReleaseSemaphore, CreateThread and WaitForSingleObject functions.
+= Since there is no way to currently create "pseudo" random events in the
+= pal, this example does not behave as classic bounded buffers would. This
+= test case is designed to starve the consumer and have the producer fill
+= the buffer.
diff --git a/src/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/test2/CMakeLists.txt b/src/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/test2/CMakeLists.txt
new file mode 100644
index 0000000000..b14284d08f
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ CreateSemaphore.c
+)
+
+add_executable(paltest_createsemaphorew_releasesemaphore_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_createsemaphorew_releasesemaphore_test2 coreclrpal)
+
+target_link_libraries(paltest_createsemaphorew_releasesemaphore_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/test2/CreateSemaphore.c b/src/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/test2/CreateSemaphore.c
new file mode 100644
index 0000000000..62532737ac
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/test2/CreateSemaphore.c
@@ -0,0 +1,314 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: CreateSemaphoreW_ReleaseSemaphore/test1/CreateSemaphore.c
+**
+** Purpose: Test Semaphore operation using classic IPC problem:
+** "Producer-Consumer Problem".
+**
+** Dependencies: CreateThread
+** ReleaseSemaphore
+** WaitForSingleObject
+** Sleep
+** fflush
+**
+
+**
+**=========================================================*/
+
+#define UNICODE
+#include <palsuite.h>
+
+#define PRODUCTION_TOTAL 26
+
+#define _BUF_SIZE 10
+
+DWORD dwThreadId; /* consumer thread identifier */
+
+HANDLE hThread; /* handle to consumer thread */
+
+HANDLE hSemaphoreM; /* handle to mutual exclusion semaphore */
+
+HANDLE hSemaphoreE; /* handle to semaphore that counts empty buffer slots */
+
+HANDLE hSemaphoreF; /* handle to semaphore that counts full buffer slots */
+
+typedef struct Buffer
+{
+ short readIndex;
+ short writeIndex;
+ CHAR message[_BUF_SIZE];
+
+} BufferStructure;
+
+CHAR producerItems[PRODUCTION_TOTAL + 1];
+
+CHAR consumerItems[PRODUCTION_TOTAL + 1];
+
+/*
+ * Read next message from the Buffer into provided pointer.
+ * Returns: 0 on failure, 1 on success.
+ */
+int
+readBuf(BufferStructure *Buffer, char *c)
+{
+ if( Buffer -> writeIndex == Buffer -> readIndex )
+ {
+ return 0;
+ }
+ *c = Buffer -> message[Buffer -> readIndex++];
+ Buffer -> readIndex %= _BUF_SIZE;
+ return 1;
+}
+
+/*
+ * Write message generated by the producer to Buffer.
+ * Returns: 0 on failure, 1 on success.
+ */
+int
+writeBuf(BufferStructure *Buffer, CHAR c)
+{
+ if( ( ((Buffer -> writeIndex) + 1) % _BUF_SIZE) ==
+ (Buffer -> readIndex) )
+ {
+ return 0;
+ }
+ Buffer -> message[Buffer -> writeIndex++] = c;
+ Buffer -> writeIndex %= _BUF_SIZE;
+ return 1;
+}
+
+/*
+ * Atomic decrement of semaphore value.
+ */
+VOID
+down(HANDLE hSemaphore)
+{
+ switch ( (WaitForSingleObject (
+ hSemaphore,
+ 10000)))
+ {
+ case WAIT_OBJECT_0: /*
+ * Semaphore was signaled. OK to access semaphore.
+ */
+ break;
+ case WAIT_ABANDONED: /*
+ * Object was mutex object whose owning
+ * thread has terminated. Shouldn't occur.
+ */
+ Fail("WaitForSingleObject call returned 'WAIT_ABANDONED'.\n"
+ "Failing Test.\n");
+ break;
+ case WAIT_FAILED: /* WaitForSingleObject function failed */
+ Fail("WaitForSingleObject call returned 'WAIT_FAILED'.\n"
+ "GetLastError returned %d\nFailing Test.\n",GetLastError());
+ break;
+ default:
+ Fail("WaitForSingleObject call returned an unexpected value.\n"
+ "Failing Test.\n");
+ break;
+ }
+
+}
+
+/*
+ * Atomic increment of semaphore value.
+ */
+VOID
+up(HANDLE hSemaphore)
+{
+ if (!ReleaseSemaphore (
+ hSemaphore,
+ 1,
+ NULL)
+ )
+ {
+ Fail("ReleaseSemaphore call failed. GetLastError returned %d\n",
+ GetLastError());
+ }
+}
+
+/*
+ * Sleep 10 milleseconds.
+ */
+VOID
+consumerSleep(VOID)
+{
+ Sleep(10);
+}
+
+/*
+ * Sleep 500 milleseconds.
+ */
+VOID
+producerSleep(VOID)
+{
+ Sleep(500);
+}
+
+/*
+ * Produce a message and write the message to Buffer.
+ */
+VOID
+producer(BufferStructure *Buffer)
+{
+
+ int n = 0;
+ char c;
+
+ while (n < PRODUCTION_TOTAL)
+ {
+ c = 'A' + n ; /* Produce Item */
+
+ down(hSemaphoreE);
+ down(hSemaphoreM);
+
+ if (writeBuf(Buffer, c))
+ {
+ Trace("Producer produces %c.\n", c);
+ fflush(stdout);
+ producerItems[n++] = c;
+ }
+
+ up(hSemaphoreM);
+ up(hSemaphoreF);
+
+ producerSleep();
+ }
+ return;
+}
+
+/*
+ * Read and "Consume" the messages in Buffer.
+ */
+DWORD
+PALAPI
+consumer( LPVOID lpParam )
+{
+ int n = 0;
+ char c;
+
+ consumerSleep();
+
+ while (n < PRODUCTION_TOTAL)
+ {
+
+ down(hSemaphoreF);
+ down(hSemaphoreM);
+
+ if (readBuf((BufferStructure*)lpParam, &c))
+ {
+ Trace("\tConsumer consumes %c.\n", c);
+ fflush(stdout);
+ consumerItems[n++] = c;
+ }
+
+ up(hSemaphoreM);
+ up(hSemaphoreE);
+
+ consumerSleep();
+ }
+ return 0;
+}
+
+int __cdecl main (int argc, char **argv)
+{
+
+ BufferStructure Buffer, *pBuffer;
+
+ pBuffer = &Buffer;
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return (FAIL);
+ }
+
+ /*
+ * Create Semaphores
+ */
+ hSemaphoreM = CreateSemaphoreW (
+ NULL,
+ 1,
+ 1,
+ NULL);
+
+ if ( NULL == hSemaphoreM )
+ {
+ Fail ( "hSemaphoreM = CreateSemaphoreW () - returned NULL\n"
+ "Failing Test.\n");
+ }
+
+ hSemaphoreE = CreateSemaphoreW (
+ NULL,
+ _BUF_SIZE ,
+ _BUF_SIZE ,
+ NULL);
+
+ if ( NULL == hSemaphoreE )
+ {
+ Fail ( "hSemaphoreE = CreateSemaphoreW () - returned NULL\n"
+ "Failing Test.\n");
+ }
+
+ hSemaphoreF = CreateSemaphoreW (
+ NULL,
+ 0,
+ _BUF_SIZE ,
+ NULL);
+
+ if ( NULL == hSemaphoreF )
+ {
+ Fail ( "hSemaphoreF = CreateSemaphoreW () - returned NULL\n"
+ "Failing Test.\n");
+ }
+
+ /*
+ * Initialize Buffer
+ */
+ pBuffer->writeIndex = pBuffer->readIndex = 0;
+
+ /*
+ * Create Consumer
+ */
+ hThread = CreateThread(
+ NULL,
+ 0,
+ consumer,
+ &Buffer,
+ 0,
+ &dwThreadId);
+
+ if ( NULL == hThread )
+ {
+ Fail ( "CreateThread() returned NULL. Failing test.\n");
+ }
+
+ /*
+ * Start producing
+ */
+ producer(pBuffer);
+
+ /*
+ * Wait for consumer to complete
+ */
+ WaitForSingleObject (hThread, INFINITE);
+
+ if ( 0 != strncmp (producerItems, consumerItems, PRODUCTION_TOTAL) )
+ {
+ Fail("The producerItems string %s\n and the consumerItems string "
+ "%s\ndo not match. This could be a problem with the strncmp()"
+ " function\n FailingTest\nGetLastError() returned %d\n",
+ producerItems, consumerItems, GetLastError());
+ }
+
+ Trace ("producerItems and consumerItems arrays match. All %d\nitems "
+ "were produced and consumed in order.\nTest passed.\n",
+ PRODUCTION_TOTAL);
+
+ PAL_Terminate();
+ return ( PASS );
+
+}
diff --git a/src/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/test2/testinfo.dat b/src/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/test2/testinfo.dat
new file mode 100644
index 0000000000..32b107fd9e
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/test2/testinfo.dat
@@ -0,0 +1,18 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = CreateSemaphoreW / ReleaseSemaphore
+Name = Positive Test for CreateSemaphoreW and ReleaseSemaphore
+TYPE = DEFAULT
+EXE1 = createsemaphore
+Description
+= Implementation of Producer / Consumer IPC problem using CreateSemaphoreW
+= and ReleaseSemaphore functions. This test case exercises CreateSemaphoreW
+= , ReleaseSemaphore, CreateThread and WaitForSingleObject functions.
+= Since there is no way to currently create "pseudo" random events in the
+= pal, this example does not behave as classic bounded buffers would. This
+= test case is designed to starve the producer and have the consumer fill
+= the buffer.
diff --git a/src/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/test3/CMakeLists.txt b/src/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/test3/CMakeLists.txt
new file mode 100644
index 0000000000..f7f0905761
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/test3/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ createsemaphore.c
+)
+
+add_executable(paltest_createsemaphorew_releasesemaphore_test3
+ ${SOURCES}
+)
+
+add_dependencies(paltest_createsemaphorew_releasesemaphore_test3 coreclrpal)
+
+target_link_libraries(paltest_createsemaphorew_releasesemaphore_test3
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/test3/createsemaphore.c b/src/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/test3/createsemaphore.c
new file mode 100644
index 0000000000..ea0a5e0846
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/test3/createsemaphore.c
@@ -0,0 +1,201 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: createsemaphorew_releasesemaphore/test3/createsemaphore.c
+**
+** Purpose: Test attributes of CreateSemaphoreW and ReleaseSemaphore.
+** Insure for CreateSemaphore that lInitialCount and lMaximumCount
+** constraints are respected. Validate that CreateSemaphore rejects
+** conditions where initial count and / or maximum count are negative
+** and conditions where the initial count is greater than the maximum
+** count. For ReleaseSemaphore validate that lpPreviousCount gets set
+** to the previous semaphore count and lpPreviousCount can be NULL.
+** Also establish ReleaseSemaphore fails when called in a semaphore
+** with count equal to lMaximumCount.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+
+struct testcase
+{
+ LPSECURITY_ATTRIBUTES lpSemaphoreAttributes;
+ LONG lInitialCount;
+ LONG lMaximumCount;
+ LPCWSTR lpName;
+ BOOL bNegativeTest;
+};
+
+struct testcase testCases[] =
+{
+ {NULL, -1, 1, NULL, TRUE},
+ {NULL, 1, -1, NULL, TRUE},
+ {NULL, -1, -1, NULL, TRUE},
+ {NULL, 2, 1, NULL, TRUE},
+ {NULL, 1, 2, NULL, FALSE},
+ {NULL, 0, 10, NULL, FALSE},
+ {NULL, INT_MAX - 1, INT_MAX, NULL, FALSE},
+ {NULL, INT_MAX, INT_MAX, NULL, FALSE}
+};
+
+HANDLE hSemaphore[sizeof(testCases)/sizeof(struct testcase)];
+
+BOOL cleanup(int index)
+{
+ int i;
+ BOOL bRet = TRUE;
+ for (i = 0; i < index; i++)
+ {
+ if (!CloseHandle(hSemaphore[i]))
+ {
+ bRet = FALSE;
+ Trace("PALSUITE ERROR: CloseHandle(%p) call failed for index %d\n",
+ hSemaphore[i], i);
+ }
+ }
+ return(bRet);
+}
+
+int __cdecl main (int argc, char **argv)
+{
+ int i;
+ int j;
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return (FAIL);
+ }
+ /* create semaphores */
+ for (i = 0; i < sizeof(testCases)/sizeof(struct testcase); i++)
+ {
+ hSemaphore[i] = CreateSemaphoreW (testCases[i].lpSemaphoreAttributes,
+ testCases[i].lInitialCount,
+ testCases[i].lMaximumCount,
+ testCases[i].lpName);
+
+ if (NULL == hSemaphore[i])
+ {
+ if (!testCases[i].bNegativeTest)
+ {
+ Trace("PALSUITE ERROR: CreateSemaphoreW('%p' '%ld' '%ld' "
+ "'%p') returned NULL at index %d.\nGetLastError "
+ "returned %d.\n", testCases[i].lpSemaphoreAttributes,
+ testCases[i].lInitialCount, testCases[i].lMaximumCount,
+ testCases[i].lpName, i, GetLastError());
+ if (i > 0)
+ {
+ cleanup(i - 1);
+ }
+ Fail("");
+ }
+ else
+ {
+ continue;
+ }
+ }
+
+ /* increment semaphore count to lMaximumCount */
+ for (j = testCases[i].lInitialCount; (ULONG)j <= (ULONG)testCases[i].lMaximumCount;
+ j++)
+ {
+ if (testCases[i].lMaximumCount == j)
+ {
+ /* Call ReleaseSemaphore once more to ensure ReleaseSemaphore
+ fails */
+ if(ReleaseSemaphore(hSemaphore[i], 1, NULL))
+ {
+ Trace("PALSUITE ERROR: ReleaseSemaphore('%p' '%ld' '%p') "
+ "call returned %d\nwhen it should have returned "
+ "%d.\nThe semaphore's count was %d.\nGetLastError "
+ "returned %d.\n", hSemaphore[i], 1, NULL, TRUE,
+ FALSE, j, GetLastError());
+ cleanup(i);
+ Fail("");
+ }
+ }
+ else
+ {
+ int previous;
+ BOOL bRet = ReleaseSemaphore(hSemaphore[i], 1, &previous);
+ DWORD dwError = GetLastError();
+
+ if(!bRet)
+ {
+ Trace("PALSUITE ERROR: ReleaseSemaphore('%p' '%ld' '%p') "
+ "call returned %d\nwhen it should have returned "
+ "%d.\nThe semaphore count was %d and it's "
+ "lMaxCount was %d.\nGetLastError returned %d.\n",
+ hSemaphore[i], 1, &previous, bRet, TRUE, j,
+ testCases[i].lMaximumCount, dwError);
+ cleanup(i);
+ Fail("");
+ }
+ if (previous != j)
+ {
+ Trace("PALSUITE ERROR: ReleaseSemaphore('%p' '%ld' '%p') "
+ "call set %p to %d instead of %d.\n The semaphore "
+ "count was %d and GetLastError returned %d.\n",
+ hSemaphore[i], 1, &previous, &previous, previous,
+ j, j, dwError);
+ cleanup(i);
+ Fail("");
+ }
+ }
+ }
+
+ // Skip exhaustive decrement tests for too large an initial count
+ if(testCases[i].lInitialCount >= INT_MAX - 1)
+ {
+ continue;
+ }
+
+ /* decrement semaphore count to 0 */
+ for (j = testCases[i].lMaximumCount; j >= 0; j--)
+ {
+ DWORD dwRet = WaitForSingleObject(hSemaphore[i], 0);
+ DWORD dwError = GetLastError();
+
+ if (0 == j)
+ {
+ /* WaitForSingleObject should report that the
+ semaphore is nonsignaled */
+ if (WAIT_TIMEOUT != dwRet)
+ {
+ Trace("PALSUITE ERROR: WaitForSingleObject('%p' '%u') "
+ "call returned %d\nwhen it should have returned "
+ "%d.\nThe semaphore's count was %d.\nGetLastError "
+ "returned %d.\n", hSemaphore[i], 0, dwRet,
+ WAIT_TIMEOUT, j, dwError);
+ cleanup(i);
+ Fail("");
+ }
+ }
+ else
+ {
+ /* WaitForSingleObject should report that the
+ semaphore is signaled */
+ if (WAIT_OBJECT_0 != dwRet)
+ {
+ Trace("PALSUITE ERROR: WaitForSingleObject('%p' '%u') "
+ "call returned %d\nwhen it should have returned "
+ "%d.\nThe semaphore's count was %d.\nGetLastError "
+ "returned %d.\n", hSemaphore[i], 0, dwRet,
+ WAIT_OBJECT_0, j, dwError);
+ cleanup(i);
+ Fail("");
+ }
+ }
+ }
+ }
+ PAL_Terminate();
+ return (PASS);
+}
+
+
+
+
+
diff --git a/src/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/test3/testinfo.dat b/src/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/test3/testinfo.dat
new file mode 100644
index 0000000000..beaac95f97
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CreateSemaphoreW_ReleaseSemaphore/test3/testinfo.dat
@@ -0,0 +1,20 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = CreateSemaphoreW / ReleaseSemaphore
+Name = Positive Test for CreateSemaphoreW and ReleaseSemaphore
+TYPE = DEFAULT
+EXE1 = createsemaphore
+Description
+= Test attributes of CreateSemaphoreW and ReleaseSemaphore.
+= Insure for CreateSemaphore that lInitialCount and lMaximumCount
+= constraints are respected. Validate that CreateSemaphore rejects
+= conditions where, initial count and / or maximum count are negative
+= and conditions where the initial count is greater than the maximum
+= count. For ReleaseSemaphore validate that lpPreviousCount gets set
+= to the previous semaphore count and lpPreviousCount can be NULL.
+= Also establish ReleaseSemaphore fails when called in a semaphore
+= with count equal to lMaximumCount.
diff --git a/src/pal/tests/palsuite/threading/CreateThread/CMakeLists.txt b/src/pal/tests/palsuite/threading/CreateThread/CMakeLists.txt
new file mode 100644
index 0000000000..1962ade358
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CreateThread/CMakeLists.txt
@@ -0,0 +1,6 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+add_subdirectory(test3)
+
diff --git a/src/pal/tests/palsuite/threading/CreateThread/test1/CMakeLists.txt b/src/pal/tests/palsuite/threading/CreateThread/test1/CMakeLists.txt
new file mode 100644
index 0000000000..d3921c4409
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CreateThread/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_createthread_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_createthread_test1 coreclrpal)
+
+target_link_libraries(paltest_createthread_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/CreateThread/test1/test1.c b/src/pal/tests/palsuite/threading/CreateThread/test1/test1.c
new file mode 100644
index 0000000000..2dd2f6acb6
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CreateThread/test1/test1.c
@@ -0,0 +1,119 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: test1.c
+**
+** Purpose: Test for CreateThread. Call CreateThread and ensure
+** that it succeeds. Also check to ensure the paramater is passed
+** properly.
+**
+**
+**=========================================================*/
+
+#include <palsuite.h>
+
+#ifndef PLATFORM_UNIX
+#define LLFORMAT "%I64u"
+#else
+#define LLFORMAT "%llu"
+#endif
+
+ULONGLONG dwCreateThreadTestParameter = 0;
+
+DWORD PALAPI CreateThreadTestThread( LPVOID lpParameter)
+{
+ DWORD dwRet = 0;
+
+ /* save parameter for test */
+ dwCreateThreadTestParameter = (ULONGLONG)lpParameter;
+
+ return dwRet;
+}
+
+BOOL CreateThreadTest()
+{
+ BOOL bRet = FALSE;
+ DWORD dwRet = 0;
+
+ LPSECURITY_ATTRIBUTES lpThreadAttributes = NULL;
+ DWORD dwStackSize = 0;
+ LPTHREAD_START_ROUTINE lpStartAddress = &CreateThreadTestThread;
+ LPVOID lpParameter = lpStartAddress;
+ DWORD dwCreationFlags = 0; /* run immediately */
+ DWORD dwThreadId = 0;
+
+ HANDLE hThread = 0;
+
+ dwCreateThreadTestParameter = 0;
+
+ /* Create a thread, passing the appropriate paramaters as declared
+ above.
+ */
+
+ hThread = CreateThread( lpThreadAttributes,
+ dwStackSize,
+ lpStartAddress,
+ lpParameter,
+ dwCreationFlags,
+ &dwThreadId );
+
+ /* Ensure that the HANDLE is not invalid! */
+ if (hThread != INVALID_HANDLE_VALUE)
+ {
+ dwRet = WaitForSingleObject(hThread,INFINITE);
+
+ if (dwRet != WAIT_OBJECT_0)
+ {
+ Trace("CreateThreadTest:WaitForSingleObject "
+ "failed (%x)\n",GetLastError());
+ }
+ else
+ {
+ /* Check to ensure that the parameter passed to the thread
+ function is the same in the function as what we passed.
+ */
+
+ if (dwCreateThreadTestParameter != (ULONGLONG)lpParameter)
+ {
+ Trace("CreateThreadTest:parameter error. The "
+ "parameter passed should have been " LLFORMAT " but when "
+ "passed to the Thread function it was " LLFORMAT " . GetLastError[%x]\n",
+ dwCreateThreadTestParameter,lpParameter, GetLastError());
+ }
+ else
+ {
+ bRet = TRUE;
+ }
+
+ }
+ CloseHandle(hThread);
+ }
+ else
+ {
+ Trace("CreateThreadTest:CreateThread failed (%x)\n",GetLastError());
+ }
+
+ return bRet;
+}
+
+
+int __cdecl main(int argc, char **argv)
+{
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return ( FAIL );
+ }
+
+ if(!CreateThreadTest())
+ {
+ Fail ("Test failed\n");
+ }
+
+ Trace("Test Passed\n");
+ PAL_Terminate();
+ return ( PASS );
+
+}
diff --git a/src/pal/tests/palsuite/threading/CreateThread/test1/testinfo.dat b/src/pal/tests/palsuite/threading/CreateThread/test1/testinfo.dat
new file mode 100644
index 0000000000..3ae70625c2
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CreateThread/test1/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = CreateThread
+Name = Positive Test for CreateThread
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Test for CreateThread. Call CreateThread and ensure
+= that it succeeds. Also check to ensure the paramater is passed
+= properly.
diff --git a/src/pal/tests/palsuite/threading/CreateThread/test2/CMakeLists.txt b/src/pal/tests/palsuite/threading/CreateThread/test2/CMakeLists.txt
new file mode 100644
index 0000000000..350cf66e9b
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CreateThread/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test2.c
+)
+
+add_executable(paltest_createthread_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_createthread_test2 coreclrpal)
+
+target_link_libraries(paltest_createthread_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/CreateThread/test2/test2.c b/src/pal/tests/palsuite/threading/CreateThread/test2/test2.c
new file mode 100644
index 0000000000..f64c32ea87
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CreateThread/test2/test2.c
@@ -0,0 +1,184 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*===========================================================
+**
+** Source: test2.c
+**
+** Purpose: Test that lpThreadId is assigned the correct
+** threadId value and that lpThreadId can be NULL.
+**
+**
+**=========================================================*/
+
+#include <palsuite.h>
+
+#define NUM_TESTS 3
+
+HANDLE hThread[NUM_TESTS];
+DWORD dwThreadId[NUM_TESTS];
+volatile BOOL bResult[NUM_TESTS];
+volatile DWORD dwThreadId1[NUM_TESTS];
+
+DWORD PALAPI Thread( LPVOID lpParameter)
+{
+ dwThreadId1[(DWORD) lpParameter] = GetCurrentThreadId();
+ bResult[(DWORD) lpParameter] = TRUE;
+ return (DWORD) lpParameter;
+}
+
+struct testCase
+{
+ LPSECURITY_ATTRIBUTES lpThreadAttributes;
+ DWORD dwStackSize;
+ LPTHREAD_START_ROUTINE lpStartAddress;
+ DWORD dwCreationFlags;
+ LPVOID lpThreadId;
+};
+
+struct testCase testCases[]=
+{
+ {NULL, 0, &Thread, 0, NULL},
+ {NULL, 0, &Thread, CREATE_SUSPENDED, NULL},
+ {NULL, 0, &Thread, 0, (LPVOID) 1}
+};
+
+/*
+ * close handles
+ */
+BOOL cleanup(int index)
+{
+ int i;
+ BOOL bRet = TRUE;
+
+ for (i = 0; i < index; i++)
+ {
+ if (!CloseHandle(hThread[i]))
+ {
+ bRet = FALSE;
+ Trace("PALSUITE ERROR: CloseHandle(%p) call failed for index %d\n",
+ hThread[i], i);
+ }
+ }
+
+ return(bRet);
+}
+
+int __cdecl main(int argc, char **argv)
+{
+ SIZE_T i;
+ DWORD dwRetWFSO;
+ DWORD dwRetRT;
+ BOOL bRet = TRUE;
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return (FAIL);
+ }
+
+ /* set results array to FALSE */
+ for (i = 0; i < NUM_TESTS; i++)
+ {
+ bResult[i]=FALSE;
+ dwThreadId[i]=0;
+ }
+
+ for (i = 0; i < NUM_TESTS; i++)
+ {
+ if (NULL != testCases[i].lpThreadId)
+ {
+ testCases[i].lpThreadId = &dwThreadId[i];
+ }
+ /* pass the index as the thread argument */
+ hThread[i] = CreateThread( testCases[i].lpThreadAttributes,
+ testCases[i].dwStackSize,
+ testCases[i].lpStartAddress,
+ (LPVOID) i,
+ testCases[i].dwCreationFlags,
+ testCases[i].lpThreadId);
+ if (hThread[i] == NULL)
+ {
+ Trace("PALSUITE ERROR: CreateThread('%p' '%d' '%p' '%p' '%d' "
+ "'%p') call failed.\nGetLastError returned '%u'.\n",
+ testCases[i].lpThreadAttributes, testCases[i].dwStackSize,
+ testCases[i].lpStartAddress, (LPVOID) i,
+ testCases[i].dwCreationFlags,
+ testCases[i].lpThreadId, GetLastError());
+ cleanup(i - 1);
+ Fail("");
+ }
+
+ /* Resume suspended threads */
+ if (testCases[i].dwCreationFlags == CREATE_SUSPENDED)
+ {
+ dwRetRT = ResumeThread (hThread[i]);
+ if (dwRetRT != 1)
+ {
+ Trace ("PALSUITE ERROR: ResumeThread(%p) "
+ "call returned %d it should have returned %d.\n"
+ "GetLastError returned %u.\n", hThread[i], dwRetRT,
+ 1, GetLastError());
+ cleanup(i);
+ Fail("");
+ }
+ }
+ }
+
+ /* cleanup */
+ for (i = 0; i < NUM_TESTS; i++)
+ {
+ dwRetWFSO = WaitForSingleObject(hThread[i], 10000);
+ if (dwRetWFSO != WAIT_OBJECT_0)
+ {
+ Trace ("PALSUITE ERROR: WaitForSingleObject('%p' '%d') "
+ "call returned %d instead of WAIT_OBJECT_0 ('%d').\n"
+ "GetLastError returned %u.\n", hThread[i], 10000,
+ dwRetWFSO, WAIT_OBJECT_0, GetLastError());
+ cleanup(i);
+ Fail("");
+ }
+ }
+ if(!cleanup(NUM_TESTS))
+ {
+ Fail("");
+ }
+
+ for (i = 0; i < NUM_TESTS; i++)
+ {
+ /*
+ * check to see that all threads were created and were passed
+ * the array index as an argument.
+ */
+ if (FALSE == bResult[i])
+ {
+ bRet = FALSE;
+ Trace("PALSUITE ERROR: result[%d]=%d. It should be %d\n", i,
+ FALSE, TRUE);
+ }
+ /*
+ * check to see that lpThreadId received the correct value.
+ */
+ if (0 != dwThreadId[i])
+ {
+ if (dwThreadId[i] != dwThreadId1[i])
+ {
+ bRet = FALSE;
+ Trace("PALSUITE ERROR: dwThreadId[%d]=%p and dwThreadId1[%d]"
+ "=%p\nThese values should be identical.\n", i,
+ dwThreadId[i], i, dwThreadId1[i]);
+ }
+ }
+ }
+ if (!bRet)
+ {
+ cleanup(NUM_TESTS);
+ Fail("");
+ }
+
+ PAL_Terminate();
+ return (PASS);
+}
+
+
+
diff --git a/src/pal/tests/palsuite/threading/CreateThread/test2/testinfo.dat b/src/pal/tests/palsuite/threading/CreateThread/test2/testinfo.dat
new file mode 100644
index 0000000000..0333beb360
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CreateThread/test2/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = CreateThread
+Name = Positive Test for CreateThread
+TYPE = DEFAULT
+EXE1 = test2
+Description
+= Test that lpThreadId is assigned the correct threadId value and
+= that lpThreadId can be NULL.
diff --git a/src/pal/tests/palsuite/threading/CreateThread/test3/CMakeLists.txt b/src/pal/tests/palsuite/threading/CreateThread/test3/CMakeLists.txt
new file mode 100644
index 0000000000..923d7a72ab
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CreateThread/test3/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test3.c
+)
+
+add_executable(paltest_createthread_test3
+ ${SOURCES}
+)
+
+add_dependencies(paltest_createthread_test3 coreclrpal)
+
+target_link_libraries(paltest_createthread_test3
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/CreateThread/test3/test3.c b/src/pal/tests/palsuite/threading/CreateThread/test3/test3.c
new file mode 100644
index 0000000000..0c44d1fdd0
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CreateThread/test3/test3.c
@@ -0,0 +1,101 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*===========================================================
+**
+** Source: test3.c
+**
+** Purpose: Check to see that the handle CreateThread returns
+** can be closed while the thread is still running.
+**
+**
+**=========================================================*/
+
+#include <palsuite.h>
+
+HANDLE hThread;
+HANDLE hEvent;
+
+DWORD PALAPI Thread( LPVOID lpParameter)
+{
+ DWORD dwRet;
+ dwRet = WaitForSingleObject(hEvent, INFINITE);
+ /* if this thread continues beyond here, fail */
+ Fail("");
+
+ return 0;
+}
+
+int __cdecl main(int argc, char **argv)
+{
+ DWORD dwThreadId;
+ DWORD dwRet;
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return (FAIL);
+ }
+
+ hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
+
+ if (hEvent == NULL)
+ {
+ Fail("PALSUITE ERROR: CreateEvent call #0 failed. GetLastError "
+ "returned %u.\n", GetLastError());
+ }
+
+ /* pass the index as the thread argument */
+ hThread = CreateThread( NULL,
+ 0,
+ &Thread,
+ (LPVOID) 0,
+ 0,
+ &dwThreadId);
+ if (hThread == NULL)
+ {
+ Trace("PALSUITE ERROR: CreateThread('%p' '%d' '%p' '%p' '%d' '%p') "
+ "call failed.\nGetLastError returned '%u'.\n", NULL,
+ 0, &Thread, (LPVOID) 0, 0, &dwThreadId, GetLastError());
+ if (0 == CloseHandle(hEvent))
+ {
+ Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) during "
+ "clean up.\nGetLastError returned '%u'.\n", hEvent);
+ }
+ Fail("");
+ }
+
+ dwRet = WaitForSingleObject(hThread, 10000);
+ if (dwRet != WAIT_TIMEOUT)
+ {
+ Trace ("PALSUITE ERROR: WaitForSingleObject('%p' '%d') "
+ "call returned %d instead of WAIT_TIMEOUT ('%d').\n"
+ "GetLastError returned '%u'.\n", hThread, 10000,
+ dwRet, WAIT_TIMEOUT, GetLastError());
+ Fail("");
+ }
+
+ if (0 == CloseHandle(hThread))
+ {
+ Trace("PALSUITE ERROR: Unable to CloseHandle(%p) on a running thread."
+ "\nGetLastError returned '%u'.\n", hThread, GetLastError());
+ if (0 == CloseHandle(hEvent))
+ {
+ Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) during "
+ "cleanup.\nGetLastError returned '%u'.\n", hEvent,
+ GetLastError());
+ }
+ Fail("");
+ }
+ if (0 == CloseHandle(hEvent))
+ {
+ Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) during "
+ "cleanup.\nGetLastError returned '%u'.\n", hEvent,
+ GetLastError());
+ Fail("");
+ }
+
+ PAL_Terminate();
+ return (PASS);
+}
+
diff --git a/src/pal/tests/palsuite/threading/CreateThread/test3/testinfo.dat b/src/pal/tests/palsuite/threading/CreateThread/test3/testinfo.dat
new file mode 100644
index 0000000000..712c3a6652
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CreateThread/test3/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = CreateThread
+Name = Positive Test for CreateThread
+TYPE = DEFAULT
+EXE1 = test3
+Description
+= Check to see that the handle CreateThread returns can be closed while
+= the thread is still running.
+
diff --git a/src/pal/tests/palsuite/threading/CriticalSectionFunctions/CMakeLists.txt b/src/pal/tests/palsuite/threading/CriticalSectionFunctions/CMakeLists.txt
new file mode 100644
index 0000000000..b7c6e394b0
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CriticalSectionFunctions/CMakeLists.txt
@@ -0,0 +1,11 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+add_subdirectory(test3)
+add_subdirectory(test4)
+add_subdirectory(test5)
+add_subdirectory(test6)
+add_subdirectory(test7)
+add_subdirectory(test8)
+
diff --git a/src/pal/tests/palsuite/threading/CriticalSectionFunctions/test1/CMakeLists.txt b/src/pal/tests/palsuite/threading/CriticalSectionFunctions/test1/CMakeLists.txt
new file mode 100644
index 0000000000..5ba04fd801
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CriticalSectionFunctions/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ InitializeCriticalSection.c
+)
+
+add_executable(paltest_criticalsectionfunctions_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_criticalsectionfunctions_test1 coreclrpal)
+
+target_link_libraries(paltest_criticalsectionfunctions_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/CriticalSectionFunctions/test1/InitializeCriticalSection.c b/src/pal/tests/palsuite/threading/CriticalSectionFunctions/test1/InitializeCriticalSection.c
new file mode 100644
index 0000000000..f294cea472
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CriticalSectionFunctions/test1/InitializeCriticalSection.c
@@ -0,0 +1,235 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: criticalsectionfunctions/test1/initializecriticalsection.c
+**
+** Purpose: Test Semaphore operation using classic IPC problem:
+** "Producer-Consumer Problem".
+**
+** Dependencies: CreateThread
+** InitializeCriticalSection
+** EnterCriticalSection
+** LeaveCriticalSection
+** DeleteCriticalSection
+** WaitForSingleObject
+** Sleep
+**
+
+**
+**=========================================================*/
+
+#include <palsuite.h>
+
+#define PRODUCTION_TOTAL 26
+
+#define _BUF_SIZE 10
+
+DWORD dwThreadId; /* consumer thread identifier */
+
+HANDLE hThread; /* handle to consumer thread */
+
+CRITICAL_SECTION CriticalSectionM; /* Critical Section Object (used as mutex) */
+
+typedef struct Buffer
+{
+ short readIndex;
+ short writeIndex;
+ CHAR message[_BUF_SIZE];
+
+} BufferStructure;
+
+CHAR producerItems[PRODUCTION_TOTAL + 1];
+
+CHAR consumerItems[PRODUCTION_TOTAL + 1];
+
+/*
+ * Read next message from the Buffer into provided pointer.
+ * Returns: 0 on failure, 1 on success.
+ */
+int
+readBuf(BufferStructure *Buffer, char *c)
+{
+ if( Buffer -> writeIndex == Buffer -> readIndex )
+ {
+ return 0;
+ }
+ *c = Buffer -> message[Buffer -> readIndex++];
+ Buffer -> readIndex %= _BUF_SIZE;
+ return 1;
+}
+
+/*
+ * Write message generated by the producer to Buffer.
+ * Returns: 0 on failure, 1 on success.
+ */
+int
+writeBuf(BufferStructure *Buffer, CHAR c)
+{
+ if( ( ((Buffer -> writeIndex) + 1) % _BUF_SIZE) ==
+ (Buffer -> readIndex) )
+ {
+ return 0;
+ }
+ Buffer -> message[Buffer -> writeIndex++] = c;
+ Buffer -> writeIndex %= _BUF_SIZE;
+ return 1;
+}
+
+/*
+ * Sleep 500 milleseconds.
+ */
+VOID
+consumerSleep(VOID)
+{
+ Sleep(500);
+}
+
+/*
+ * Sleep between 10 milleseconds.
+ */
+VOID
+producerSleep(VOID)
+{
+ Sleep(10);
+}
+
+/*
+ * Produce a message and write the message to Buffer.
+ */
+VOID
+producer(BufferStructure *Buffer)
+{
+
+ int n = 0;
+ char c;
+
+ while (n < PRODUCTION_TOTAL)
+ {
+ c = 'A' + n ; /* Produce Item */
+
+ EnterCriticalSection(&CriticalSectionM);
+
+ if (writeBuf(Buffer, c))
+ {
+ printf("Producer produces %c.\n", c);
+ producerItems[n++] = c;
+ }
+
+ LeaveCriticalSection(&CriticalSectionM);
+
+ producerSleep();
+ }
+
+ return;
+}
+
+/*
+ * Read and "Consume" the messages in Buffer.
+ */
+DWORD
+PALAPI
+consumer( LPVOID lpParam )
+{
+ int n = 0;
+ char c;
+
+ consumerSleep();
+
+ while (n < PRODUCTION_TOTAL)
+ {
+
+ EnterCriticalSection(&CriticalSectionM);
+
+ if (readBuf((BufferStructure*)lpParam, &c))
+ {
+ printf("\tConsumer consumes %c.\n", c);
+ consumerItems[n++] = c;
+ }
+
+ LeaveCriticalSection(&CriticalSectionM);
+
+ consumerSleep();
+ }
+
+ return 0;
+}
+
+int __cdecl main (int argc, char **argv)
+{
+
+ BufferStructure Buffer, *pBuffer;
+
+ pBuffer = &Buffer;
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /*
+ * Create mutual exclusion mechanisms
+ */
+
+ InitializeCriticalSection ( &CriticalSectionM );
+
+ /*
+ * Initialize Buffer
+ */
+ pBuffer->writeIndex = pBuffer->readIndex = 0;
+
+
+
+ /*
+ * Create Consumer
+ */
+ hThread = CreateThread(
+ NULL,
+ 0,
+ consumer,
+ &Buffer,
+ 0,
+ &dwThreadId);
+
+ if ( NULL == hThread )
+ {
+ Fail ( "CreateThread() returned NULL. Failing test.\n"
+ "GetLastError returned %d\n", GetLastError());
+ }
+
+ /*
+ * Start producing
+ */
+ producer(pBuffer);
+
+ /*
+ * Wait for consumer to complete
+ */
+ WaitForSingleObject (hThread, INFINITE);
+
+ /*
+ * Compare items produced vs. items consumed
+ */
+ if ( 0 != strncmp (producerItems, consumerItems, PRODUCTION_TOTAL) )
+ {
+ Fail("The producerItems string %s\n and the consumerItems string "
+ "%s\ndo not match. This could be a problem with the strncmp()"
+ " function\n FailingTest\nGetLastError() returned %d\n",
+ producerItems, consumerItems, GetLastError());
+ }
+
+ /*
+ * Clean up Critical Section object
+ */
+ DeleteCriticalSection(&CriticalSectionM);
+
+ Trace("producerItems and consumerItems arrays match. All %d\nitems "
+ "were produced and consumed in order.\nTest passed.\n",
+ PRODUCTION_TOTAL);
+
+ PAL_Terminate();
+ return (PASS);
+
+}
diff --git a/src/pal/tests/palsuite/threading/CriticalSectionFunctions/test1/testinfo.dat b/src/pal/tests/palsuite/threading/CriticalSectionFunctions/test1/testinfo.dat
new file mode 100644
index 0000000000..494b899b90
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CriticalSectionFunctions/test1/testinfo.dat
@@ -0,0 +1,21 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = InitializeCriticalSection / EnterCriticalSection / LeaveCriticalSection / DeleteCriticalSection
+Name = Positive Test for InitializeCriticalSection, EnterCriticalSection, LeaveCriticalSection and DeleteCriticalSection
+TYPE = DEFAULT
+EXE1 = initializecriticalsection
+Description
+= Implementation of Producer / Consumer IPC problem using the
+= "CriticalSection" functions to provide a mutual exclusion mechanism.
+= This test case exercises InitializeCriticalSection, EnterCriticalSection,
+= LeaveCriticalSection, DeleteCriticalSection, and WaitForSingleObject
+= functions.
+= This case doesn't work with more than one producer and one consumer.
+= The producer thread and consumer thread each take turns blocking on
+= the CriticalSection object and do not have any other synchronization
+= mechanisms. This prevents adding producers or consumers as there are
+= no mechanisms to block them once the buffer is full.
diff --git a/src/pal/tests/palsuite/threading/CriticalSectionFunctions/test2/CMakeLists.txt b/src/pal/tests/palsuite/threading/CriticalSectionFunctions/test2/CMakeLists.txt
new file mode 100644
index 0000000000..d26658cf5d
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CriticalSectionFunctions/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test2.c
+)
+
+add_executable(paltest_criticalsectionfunctions_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_criticalsectionfunctions_test2 coreclrpal)
+
+target_link_libraries(paltest_criticalsectionfunctions_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/CriticalSectionFunctions/test2/test2.c b/src/pal/tests/palsuite/threading/CriticalSectionFunctions/test2/test2.c
new file mode 100644
index 0000000000..47659a1c18
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CriticalSectionFunctions/test2/test2.c
@@ -0,0 +1,226 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: CriticalSectionFunctions/test2/test2.c
+**
+** Purpose: Test that we are able to nest critical section calls.
+** The initial thread makes a call to EnterCriticalSection once,
+** blocking on a CRITICAL_SECTION object and creates a new thread.
+** The newly created thread blocks on the same CRITICAL_SECTION object.
+** The first thread now makes a call to LeaveCriticalSection.
+** Test to see that the new thread doesn't get unblocked.
+**
+** Dependencies: CreateThread
+** InitializeCriticalSection
+** EnterCriticalSection
+** LeaveCriticalSection
+** DeleteCriticalSection
+** WaitForSingleObject
+**
+
+**
+**=========================================================*/
+
+#include <palsuite.h>
+
+CRITICAL_SECTION CriticalSection;
+
+volatile BOOL t0_tflag = FAIL; /* thread 0 timeout flag */
+volatile BOOL t1_aflag = FAIL; /* thread 1 access flag */
+volatile BOOL t1_cflag = FAIL; /* thread 1 critical section flag */
+volatile BOOL bTestResult = FAIL;
+
+DWORD PALAPI Thread(LPVOID lpParam)
+{
+ t1_aflag = PASS;
+ EnterCriticalSection(&CriticalSection);
+ t1_cflag = PASS;
+ LeaveCriticalSection(&CriticalSection);
+ return 0;
+}
+
+int __cdecl main (int argc, char **argv)
+{
+ HANDLE hThread;
+ DWORD dwThreadId;
+ DWORD dwRet;
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return (bTestResult);
+ }
+
+ /*
+ * Create critical section object and enter it
+ */
+ InitializeCriticalSection ( &CriticalSection );
+ EnterCriticalSection(&CriticalSection);
+
+ /*
+ * Create a suspended thread
+ */
+ hThread = CreateThread(NULL,
+ 0,
+ &Thread,
+ (LPVOID) NULL,
+ CREATE_SUSPENDED,
+ &dwThreadId);
+
+ if (hThread == NULL)
+ {
+ Trace("PALSUITE ERROR: CreateThread call failed. GetLastError "
+ "returned %d.\n", GetLastError());
+ LeaveCriticalSection(&CriticalSection);
+ DeleteCriticalSection(&CriticalSection);
+ Fail("");
+ }
+
+ EnterCriticalSection(&CriticalSection);
+ /*
+ * Set priority of the thread to greater than that of the currently
+ * running thread so it is guaranteed to run.
+ */
+ dwRet = (DWORD) SetThreadPriority(hThread, THREAD_PRIORITY_ABOVE_NORMAL);
+
+ if (0 == dwRet)
+ {
+ Trace("PALSUITE ERROR: SetThreadPriority (%p, %d) call failed.\n"
+ "GetLastError returned %d.\n", hThread,
+ THREAD_PRIORITY_NORMAL, GetLastError());
+ LeaveCriticalSection(&CriticalSection);
+ CloseHandle(hThread);
+ DeleteCriticalSection(&CriticalSection);
+ Fail("");
+ }
+
+ dwRet = ResumeThread(hThread);
+
+ if (-1 == dwRet)
+ {
+ Trace("PALSUITE ERROR: ResumeThread(%p) call failed.\nGetLastError "
+ "returned %d.\n", hThread, GetLastError());
+ LeaveCriticalSection(&CriticalSection);
+ CloseHandle(hThread);
+ DeleteCriticalSection(&CriticalSection);
+ Fail("");
+ }
+ /*
+ * Sleep until we know the thread has been invoked. This sleep in
+ * combination with the higher priority of the other thread should
+ * guarantee both threads block on the critical section.
+ */
+ while (t1_aflag == FAIL)
+ {
+ Sleep(1);
+ }
+
+ LeaveCriticalSection(&CriticalSection);
+
+ switch ((WaitForSingleObject(
+ hThread,
+ 10000))) /* Wait 10 seconds */
+ {
+ case WAIT_OBJECT_0:
+ /* Object (thread) is signaled */
+ LeaveCriticalSection(&CriticalSection);
+ CloseHandle(hThread);
+ DeleteCriticalSection(&CriticalSection);
+ Fail("PALSUITE ERROR: WaitForSingleObject(%p,%d) should have "
+ "returned\nWAIT_TIMEOUT ('%d'), instead it returned "
+ "WAIT_OBJECT_0 ('%d').\nA nested LeaveCriticalSection(%p) "
+ "call released both threads that were waiting on it!\n",
+ hThread, 10000, WAIT_TIMEOUT, WAIT_OBJECT_0, &CriticalSection);
+ break;
+ case WAIT_ABANDONED:
+ /*
+ * Object was mutex object whose owning
+ * thread has terminated. Shouldn't occur.
+ */
+ Trace("PALSUITE ERROR: WaitForSingleObject(%p,%d) should have "
+ "returned\nWAIT_TIMEOUT ('%d'), instead it returned "
+ "WAIT_ABANDONED ('%d').\nGetLastError returned '%d'\n",
+ hThread, 10000, WAIT_TIMEOUT, WAIT_ABANDONED, GetLastError());
+ LeaveCriticalSection(&CriticalSection);
+ CloseHandle(hThread);
+ DeleteCriticalSection(&CriticalSection);
+ Fail("");
+ break;
+ case WAIT_FAILED: /* WaitForSingleObject function failed */
+ Trace("PALSUITE ERROR: WaitForSingleObject(%p,%d) should have "
+ "returned\nWAIT_TIMEOUT ('%d'), instead it returned "
+ "WAIT_FAILED ('%d').\nGetLastError returned '%d'\n",
+ hThread, 10000, WAIT_TIMEOUT, WAIT_FAILED, GetLastError());
+ LeaveCriticalSection(&CriticalSection);
+ CloseHandle(hThread);
+ DeleteCriticalSection(&CriticalSection);
+ Fail("");
+ break;
+ case WAIT_TIMEOUT:
+ /*
+ * We expect this thread to timeout waiting for the
+ * critical section object to become available.
+ */
+ t0_tflag = PASS;
+ break;
+ }
+
+ LeaveCriticalSection(&CriticalSection);
+
+ if (WAIT_OBJECT_0 != WaitForSingleObject (hThread, 10000))
+ {
+ if (0 == CloseHandle(hThread))
+ {
+ Trace("PALSUITE ERROR: CloseHandle(%p) call failed.\n"
+ "WaitForSingleObject(%p,%d) should have returned "
+ "WAIT_OBJECT_0 ('%d').\nBoth calls failed. "
+ "Deleted CRITICAL_SECTION object which likely means\n"
+ "thread %p is now in an undefined state. GetLastError "
+ "returned '%d'.\n", hThread, hThread, 10000, WAIT_OBJECT_0,
+ hThread, GetLastError());
+ DeleteCriticalSection(&CriticalSection);
+ Fail("");
+ }
+ else
+ {
+ Trace("PALSUITE ERROR: WaitForSingleObject(%p,%d) should have "
+ "returned WAIT_OBJECT_0 ('%d').\n GetLastError returned "
+ "'%d'.\n", hThread, hThread, 10000, WAIT_OBJECT_0,
+ hThread, GetLastError());
+ DeleteCriticalSection(&CriticalSection);
+ Fail("");
+ }
+ }
+
+ if (0 == CloseHandle(hThread))
+ {
+ Trace("PALSUITE ERROR: CloseHandle(%p) call failed.\n"
+ "Deleted CRITICAL_SECTION object which likely means\n"
+ "thread %p is now in an undefined state. GetLastError "
+ "returned '%d'.\n", hThread, hThread, GetLastError());
+ DeleteCriticalSection(&CriticalSection);
+ Fail("");
+
+ }
+ DeleteCriticalSection(&CriticalSection);
+ /*
+ * Ensure both thread 0 experienced a wait timeout and thread 1
+ * accessed the critical section or fail the test, otherwise pass it.
+ */
+ if ((t0_tflag == FAIL) || (t1_cflag == FAIL))
+ {
+ Trace("PALSUITE ERROR: Thread 0 returned %d when %d was expected.\n"
+ "Thread 1 returned %d when %d was expected.\n", t0_tflag,
+ PASS, t1_cflag, PASS);
+ bTestResult=FAIL;
+ }
+ else
+ {
+ bTestResult=PASS;
+ }
+
+ PAL_TerminateEx(bTestResult);
+ return (bTestResult);
+}
diff --git a/src/pal/tests/palsuite/threading/CriticalSectionFunctions/test2/testinfo.dat b/src/pal/tests/palsuite/threading/CriticalSectionFunctions/test2/testinfo.dat
new file mode 100644
index 0000000000..06842124b9
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CriticalSectionFunctions/test2/testinfo.dat
@@ -0,0 +1,18 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = CriticalSectionFunctions
+Name = Positive test to ensure CRITICAL_SECTION objects can be nested
+TYPE = DEFAULT
+EXE1 = test2
+Description
+= Test that we are able to nest critical section calls.
+= The initial thread makes a call to EnterCriticalSection once,
+= blocking on a CRITICAL_SECTION object and creates a new thread.
+= The newly created thread blocks on the same CRITICAL_SECTION object.
+= The first thread now makes a call to LeaveCriticalSection.
+= Test to see that the new thread doesn't get unblocked.
+
diff --git a/src/pal/tests/palsuite/threading/CriticalSectionFunctions/test3/CMakeLists.txt b/src/pal/tests/palsuite/threading/CriticalSectionFunctions/test3/CMakeLists.txt
new file mode 100644
index 0000000000..8bd2a72878
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CriticalSectionFunctions/test3/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test3.c
+)
+
+add_executable(paltest_criticalsectionfunctions_test3
+ ${SOURCES}
+)
+
+add_dependencies(paltest_criticalsectionfunctions_test3 coreclrpal)
+
+target_link_libraries(paltest_criticalsectionfunctions_test3
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/CriticalSectionFunctions/test3/test3.c b/src/pal/tests/palsuite/threading/CriticalSectionFunctions/test3/test3.c
new file mode 100644
index 0000000000..d5911267b2
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CriticalSectionFunctions/test3/test3.c
@@ -0,0 +1,376 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: CriticalSectionFunctions/test3/test3.c
+**
+** Purpose: Create two threads to exercise TryEnterCriticalSection
+** and EnterCriticalSection. TryEnterCriticalSection acquires
+** and holds a CRITICAL_SECTION object. Another call to
+** TryEnterCriticalSection is made from a different thread, at
+** this time, to establish a call to TryEnterCriticalSection
+** will return immediatly and to establish
+** TryEnterCriticalSection returns the proper value when it
+** attempts to lock a CRITICAL_SECTION that is already owned
+** by another thread. The CRITICAL_SECTION object is then
+** released and held by a call to EnterCriticalSection. A new
+** thread is invoked and attempts to acquire the held
+** CRITICAL_SECTION with a call to TryEnterCriticalSection.
+** TryEnterCriticalSection returns immediatly and returns
+** with the value that states the CRITICAL_SECTION object is
+** held by another thread. This establishes
+** TryEnterCriticalSection behaves the same way with
+** CriticalSections locked by TryEnterCriticalSection and
+** EnterCriticalSection.
+**
+**
+**===================================================================*/
+#include <palsuite.h>
+
+#define NUM_THREADS 2
+
+HANDLE hThread[NUM_THREADS];
+HANDLE hEvent[NUM_THREADS];
+CRITICAL_SECTION CriticalSection;
+BOOL bRet = FAIL;
+
+DWORD PALAPI Thread(LPVOID lpParam)
+{
+ DWORD dwRet;
+
+ if (0 == TryEnterCriticalSection(&CriticalSection))
+ {
+ dwRet = WaitForMultipleObjects(NUM_THREADS, hEvent, TRUE, 10000);
+ if ((WAIT_OBJECT_0 > dwRet) ||
+ ((WAIT_OBJECT_0 + NUM_THREADS - 1) < dwRet))
+ {
+#if 0
+ if (0 == CloseHandle(hThread[1]))
+ {
+ Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) "
+ "during clean up.\nGetLastError returned '%d'.\n",
+ hThread[1], GetLastError());
+ }
+#endif
+ Trace("PALSUITE ERROR: WaitForMultipleObjects(%d, %p, %d, %d) call"
+ "returned an unexpected value, '%d'.\nGetLastError returned "
+ "%d.\n", NUM_THREADS, hEvent, TRUE, 10000, dwRet,
+ GetLastError());
+ }
+ else
+ {
+ bRet = PASS;
+ }
+ }
+ else
+ {
+ /* signal thread 0 */
+ if (0 == SetEvent(hEvent[0]))
+ {
+ Trace("PALSUITE ERROR: Unable to execute SetEvent(%p) during "
+ "clean up.\nGetLastError returned '%d'.\n", hEvent[0],
+ GetLastError());
+ LeaveCriticalSection(&CriticalSection);
+ if (0 == CloseHandle(hThread[0]))
+ {
+ Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) "
+ "during clean up\nGetLastError returned '%d'.\n",
+ hThread[0], GetLastError());
+ }
+ if (0 == CloseHandle(hEvent[0]))
+ {
+ Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) "
+ "during clean up\nGetLastError returned '%d'.\n",
+ hEvent[0], GetLastError());
+ }
+ if (0 == CloseHandle(hEvent[1]))
+ {
+ Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) "
+ "during clean up\nGetLastError returned '%d'.\n",
+ hEvent[1], GetLastError());
+ }
+ DeleteCriticalSection(&CriticalSection);
+ Fail("");
+ }
+
+ /* wait to be signaled */
+ dwRet = WaitForSingleObject(hEvent[1], 10000);
+ if (WAIT_OBJECT_0 != dwRet)
+ {
+ Trace("PALSUITE ERROR: WaitForSingleObject(%p,%d) should have "
+ "returned\nWAIT_OBJECT_0 ('%d'), instead it returned "
+ "('%d').\nGetLastError returned '%d'.\n",
+ hEvent[0], 10000, WAIT_OBJECT_0, dwRet, GetLastError());
+ if (0 == CloseHandle(hThread[0]))
+ {
+ Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) "
+ "during clean up.\nGetLastError returned '%d'.\n",
+ hThread[0], GetLastError());
+ }
+ if (0 == CloseHandle(hEvent[0]))
+ {
+ Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) "
+ "during clean up.\nGetLastError returned '%d'.\n",
+ hEvent[0], GetLastError());
+ }
+ if (0 == CloseHandle(hEvent[1]))
+ {
+ Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) "
+ "during clean up.\nGetLastError returned '%d.'\n",
+ hEvent[1], GetLastError());
+ }
+ DeleteCriticalSection(&CriticalSection);
+ Fail("");
+ }
+ LeaveCriticalSection(&CriticalSection);
+ }
+ return FAIL;
+}
+
+int __cdecl main(int argc, char **argv)
+{
+ HANDLE hThread[NUM_THREADS];
+ DWORD dwThreadId[NUM_THREADS];
+ DWORD dwRet;
+
+ if ((PAL_Initialize(argc,argv)) != 0)
+ {
+ return(bRet);
+ }
+
+ /* thread 0 event */
+ hEvent[0] = CreateEvent(NULL, TRUE, FALSE, NULL);
+
+ if (hEvent[0] == NULL)
+ {
+ Fail("PALSUITE ERROR: CreateEvent call #0 failed. GetLastError "
+ "returned %d.\n", GetLastError());
+ }
+
+ /* thread 1 event */
+ hEvent[1] = CreateEvent(NULL, TRUE, FALSE, NULL);
+
+ if (hEvent[1] == NULL)
+ {
+ Trace("PALSUITE ERROR: CreateEvent call #1 failed. GetLastError "
+ "returned %d.\n", GetLastError());
+ if (0 == CloseHandle(hEvent[0]))
+ {
+ Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) during "
+ "clean up.\nGetLastError returned '%d'.\n", hEvent[0]);
+ }
+ Fail("");
+ }
+
+ InitializeCriticalSection ( &CriticalSection );
+
+ hThread[0] = CreateThread(NULL,
+ 0,
+ &Thread,
+ (LPVOID) NULL,
+ 0,
+ &dwThreadId[0]);
+
+ if (hThread[0] == NULL)
+ {
+ Trace("PALSUITE ERROR: CreateThread call #0 failed. GetLastError "
+ "returned %d.\n", GetLastError());
+ if (0 == CloseHandle(hEvent[0]))
+ {
+ Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) during "
+ "clean up.\nGetLastError returned '%d'.\n", hEvent[0],
+ GetLastError());
+ }
+ if (0 == CloseHandle(hEvent[1]))
+ {
+ Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) during "
+ "clean up.\nGetLastError returned '%d'.\n", hEvent[1],
+ GetLastError());
+ }
+ DeleteCriticalSection(&CriticalSection);
+ Fail("");
+ }
+
+
+ /* wait for thread 0 to be signaled */
+ dwRet = WaitForSingleObject(hEvent[0], 10000);
+ if (WAIT_OBJECT_0 != dwRet)
+ {
+ Trace("PALSUITE ERROR: WaitForSingleObject(%p,%d) should have "
+ "returned\nWAIT_OBJECT_0 ('%d'), instead it returned "
+ "('%d').\nGetLastError returned '%d'.\n", hEvent[0], 10000,
+ WAIT_OBJECT_0, dwRet, GetLastError());
+ if (0 == CloseHandle(hThread[0]))
+ {
+ Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) during "
+ "clean up.\nGetLastError returned '%d'.\n", hThread[0],
+ GetLastError());
+ }
+ if (0 == CloseHandle(hEvent[0]))
+ {
+ Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) during "
+ "clean up.\nGetLastError returned '%d'.\n", hEvent[0],
+ GetLastError());
+ }
+ if (0 == CloseHandle(hEvent[1]))
+ {
+ Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) during "
+ "clean up.\nGetLastError returned '%d'.\n", hEvent[1],
+ GetLastError());
+ }
+ Fail("");
+ }
+
+ /*
+ * Attempting to enter CRITICAL_SECTION object owned by the
+ * created thread and locked with TryEnterCriticalSection
+ */
+ if (0 == TryEnterCriticalSection(&CriticalSection))
+ {
+ /* signal thread 1 */
+ if (0 == SetEvent(hEvent[1]))
+ {
+ Trace("PALSUITE ERROR: Unable to execute SetEvent(%p) call.\n"
+ "GetLastError returned '%d'.\n", hEvent[1],
+ GetLastError());
+ goto done;
+ }
+ }
+ else
+ {
+ Trace("PALSUITE_ERROR: TryEnterCriticalSection was able to grab a"
+ " CRITICAL_SECTION object\nwhich was already owned.\n");
+ LeaveCriticalSection(&CriticalSection);
+ if (0 == CloseHandle(hThread[0]))
+ {
+ Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) during "
+ "clean up.\nGetLastError returned '%d'.\n", hThread[0],
+ GetLastError());
+ }
+ if (0 == CloseHandle(hEvent[0]))
+ {
+ Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) during "
+ "clean up.\nGetLastError returned '%d'.\n", hEvent[0],
+ GetLastError());
+ }
+ if (0 == CloseHandle(hEvent[1]))
+ {
+ Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) during "
+ "clean up.\nGetLastError returned '%d'.\n", hEvent[1],
+ GetLastError());
+ }
+ DeleteCriticalSection(&CriticalSection);
+ Fail("");
+ }
+ /*
+ * Enter the CRITICAL_SECTION and launch another thread to attempt
+ * to access the CRITICAL_SECTION with a call to TryEnterCriticalSection.
+ */
+ EnterCriticalSection(&CriticalSection);
+
+ hThread[1] = CreateThread(NULL,
+ 0,
+ &Thread,
+ (LPVOID) NULL,
+ 0,
+ &dwThreadId[1]);
+
+ if (hThread[1] == NULL)
+ {
+ Trace("PALSUITE ERROR: CreateThread call #1 failed. GetLastError "
+ "returned %d.\n", GetLastError());
+ LeaveCriticalSection(&CriticalSection);
+ if (0 == CloseHandle(hThread[0]))
+ {
+ Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) during "
+ "clean up.\nGetLastError returned '%d'.\n", hThread[0],
+ GetLastError());
+ }
+ if (0 == CloseHandle(hEvent[0]))
+ {
+ Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) during "
+ "clean up.\nGetLastError returned '%d'.\n", hEvent[0],
+ GetLastError());
+ }
+ if (0 == CloseHandle(hEvent[1]))
+ {
+ Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) during "
+ "clean up.\nGetLastError returned '%d'.\n", hEvent[1],
+ GetLastError());
+ }
+ DeleteCriticalSection(&CriticalSection);
+ Fail("");
+ }
+
+ dwRet = WaitForMultipleObjects(NUM_THREADS, hThread, TRUE, 10000);
+ if ((WAIT_OBJECT_0 > dwRet) ||
+ ((WAIT_OBJECT_0 + NUM_THREADS - 1) < dwRet))
+ {
+ Trace("PALSUITE ERROR: WaitForMultipleObjects(%d, %p, %d, %d) call "
+ "returned an unexpected value, '%d'.\nGetLastError returned "
+ "%d.\n", NUM_THREADS, hThread, TRUE, 10000, dwRet,
+ GetLastError());
+ LeaveCriticalSection(&CriticalSection);
+ if (0 == CloseHandle(hThread[0]))
+ {
+ Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) during "
+ "clean up.\nGetLastError returned '%d'.\n", hThread[0],
+ GetLastError());
+ }
+ if (0 == CloseHandle(hThread[1]))
+ {
+ Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) during "
+ "clean up.\nGetLastError returned '%d'.\n", hThread[1],
+ GetLastError());
+ }
+ if (0 == CloseHandle(hEvent[0]))
+ {
+ Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) during "
+ "clean up.\nGetLastError returned '%d'.\n", hEvent[0],
+ GetLastError());
+ }
+ if (0 == CloseHandle(hEvent[1]))
+ {
+ Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) during "
+ "clean up.\nGetLastError returned '%d'.\n", hEvent[1],
+ GetLastError());
+ }
+ DeleteCriticalSection(&CriticalSection);
+ Fail("");
+ }
+
+ LeaveCriticalSection(&CriticalSection);
+ if (0 == CloseHandle(hThread[1]))
+ {
+ Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) during "
+ "clean up.\nGetLastError returned '%d'.\n", hThread[1],
+ GetLastError());
+ }
+done:
+ if (0 == CloseHandle(hThread[0]))
+ {
+ Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) during "
+ "clean up.\nGetLastError returned '%d'.\n", hThread[0],
+ GetLastError());
+ }
+ if (0 == CloseHandle(hEvent[0]))
+ {
+ Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) during "
+ "clean up.\nGetLastError returned '%d'.\n", hEvent[0],
+ GetLastError());
+ }
+ if (0 == CloseHandle(hEvent[1]))
+ {
+ Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) during "
+ "clean up.\nGetLastError returned '%d'.\n", hEvent[1],
+ GetLastError());
+ }
+ DeleteCriticalSection(&CriticalSection);
+
+ PAL_TerminateEx(bRet);
+
+ return (bRet);
+}
+
diff --git a/src/pal/tests/palsuite/threading/CriticalSectionFunctions/test3/testinfo.dat b/src/pal/tests/palsuite/threading/CriticalSectionFunctions/test3/testinfo.dat
new file mode 100644
index 0000000000..818b4870a2
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CriticalSectionFunctions/test3/testinfo.dat
@@ -0,0 +1,29 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = CriticalSectionFunctions
+Name = Positive Test for TryEnterCriticalSection
+TYPE = DEFAULT
+EXE1 = test3
+Description
+= Create two threads to exercise TryEnterCriticalSection
+= and EnterCriticalSection. TryEnterCriticalSection acquires
+= and holds a CRITICAL_SECTION object. Another call to
+= TryEnterCriticalSection is made from a different thread, at
+= this time, to establish a call to TryEnterCriticalSection
+= will return immediatly and to establish
+= TryEnterCriticalSection returns the proper value when it
+= attempts to lock a CRITICAL_SECTION that is already owned
+= by another thread. The CRITICAL_SECTION object is then
+= released and held by a call to EnterCriticalSection. A new
+= thread is invoked and attempts to acquire the held
+= CRITICAL_SECTION with a call to TryEnterCriticalSection.
+= TryEnterCriticalSection returns immediatly and returns
+= with the value that states the CRITICAL_SECTION object is
+= held by another thread. This establishes
+= TryEnterCriticalSection behaves the same way with
+= CriticalSections locked by TryEnterCriticalSection and
+= EnterCriticalSection.
diff --git a/src/pal/tests/palsuite/threading/CriticalSectionFunctions/test4/CMakeLists.txt b/src/pal/tests/palsuite/threading/CriticalSectionFunctions/test4/CMakeLists.txt
new file mode 100644
index 0000000000..0626631640
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CriticalSectionFunctions/test4/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test4.c
+)
+
+add_executable(paltest_criticalsectionfunctions_test4
+ ${SOURCES}
+)
+
+add_dependencies(paltest_criticalsectionfunctions_test4 coreclrpal)
+
+target_link_libraries(paltest_criticalsectionfunctions_test4
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/CriticalSectionFunctions/test4/test4.c b/src/pal/tests/palsuite/threading/CriticalSectionFunctions/test4/test4.c
new file mode 100644
index 0000000000..8a245a4776
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CriticalSectionFunctions/test4/test4.c
@@ -0,0 +1,241 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: criticalsectionfunctions/test4/test4.c
+**
+** Purpose: Test to see if threads blocked on a CRITICAL_SECTION object will
+** be released in an orderly manner. This case looks at the following
+** scenario. If one thread owns a CRITICAL_SECTION object and two threads
+** block in EnterCriticalSection, trying to hold the already owned
+** CRITICAL_SECTION object, when the first thread releases the CRITICAL_SECTION
+** object, will one and only one of the waiters get unblocked?
+**
+** Dependencies: CreateThread
+** InitializeCriticalSection
+** EnterCriticalSection
+** LeaveCriticalSection
+** DeleteCriticalSection
+** Sleep
+** WaitForSingleObject
+**
+
+**
+**=========================================================*/
+
+#include <palsuite.h>
+
+#define NUM_BLOCKING_THREADS 2
+
+BOOL bTestResult;
+CRITICAL_SECTION CriticalSection;
+HANDLE hThread[NUM_BLOCKING_THREADS];
+HANDLE hEvent;
+DWORD dwThreadId[NUM_BLOCKING_THREADS];
+volatile int flags[NUM_BLOCKING_THREADS] = {0,0};
+
+DWORD PALAPI ThreadTest1(LPVOID lpParam)
+{
+
+ EnterCriticalSection ( &CriticalSection );
+
+ flags[0] = 1;
+
+ return 0;
+
+}
+
+DWORD PALAPI ThreadTest2(LPVOID lpParam)
+{
+
+ EnterCriticalSection ( &CriticalSection );
+
+ flags[1] = 1;
+
+ return 0;
+
+}
+
+int __cdecl main(int argc, char **argv)
+{
+
+ DWORD dwRet;
+ DWORD dwRet1;
+ bTestResult = FAIL;
+
+ if ((PAL_Initialize(argc,argv)) != 0)
+ {
+ return(bTestResult);
+ }
+
+ /*
+ * Create Critical Section Object
+ */
+ InitializeCriticalSection ( &CriticalSection );
+
+ EnterCriticalSection ( &CriticalSection );
+
+ hThread[0] = CreateThread(NULL,
+ 0,
+ &ThreadTest1,
+ (LPVOID) 0,
+ CREATE_SUSPENDED,
+ &dwThreadId[0]);
+ if (hThread[0] == NULL)
+ {
+ Trace("PALSUITE ERROR: CreateThread(%p, %d, %p, %p, %d, %p) call "
+ "failed.\nGetLastError returned %d.\n", NULL, 0, &ThreadTest1,
+ (LPVOID) 0, CREATE_SUSPENDED, &dwThreadId[0], GetLastError());
+ LeaveCriticalSection(&CriticalSection);
+ DeleteCriticalSection ( &CriticalSection );
+ Fail("");
+ }
+
+ hThread[1] = CreateThread(NULL,
+ 0,
+ &ThreadTest2,
+ (LPVOID) 0,
+ CREATE_SUSPENDED,
+ &dwThreadId[1]);
+ if (hThread[1] == NULL)
+ {
+ Trace("PALSUITE ERROR: CreateThread(%p, %d, %p, %p, %d, %p) call "
+ "failed.\nGetLastError returned %d.\n", NULL, 0, &ThreadTest2,
+ (LPVOID) 0, CREATE_SUSPENDED, &dwThreadId[1], GetLastError());
+ LeaveCriticalSection(&CriticalSection);
+
+ dwRet = ResumeThread(hThread[0]);
+ if (-1 == dwRet)
+ {
+ Trace("PALSUITE ERROR: ResumeThread(%p) call failed.\n"
+ "GetLastError returned '%d'.\n", hThread[0],
+ GetLastError());
+ }
+
+ dwRet = WaitForSingleObject(hThread[0], 10000);
+ if (WAIT_OBJECT_0 == dwRet)
+ {
+ Trace("PALSUITE ERROR: WaitForSingleObject(%p, %d) call "
+ "failed. '%d' was returned instead of the expected '%d'.\n"
+ "GetLastError returned '%d'.\n", hThread[0], 10000, dwRet,
+ WAIT_OBJECT_0, GetLastError());
+ }
+
+ if (0 == CloseHandle(hThread[0]))
+ {
+ Trace("PALSUITE NOTIFICATION: CloseHandle(%p) call failed.\n"
+ "GetLastError returned %d. Not failing tests.\n",
+ hThread[0], GetLastError());
+ }
+
+ DeleteCriticalSection(&CriticalSection);
+ Fail("");
+ }
+
+ /*
+ * Set other thread priorities to be higher than ours & Sleep to ensure
+ * we give up the processor.
+ */
+ dwRet = (DWORD) SetThreadPriority(hThread[0],
+ THREAD_PRIORITY_ABOVE_NORMAL);
+ if (0 == dwRet)
+ {
+ Trace("PALSUITE ERROR: SetThreadPriority(%p, %d) call failed.\n"
+ "GetLastError returned %d", hThread[0],
+ THREAD_PRIORITY_ABOVE_NORMAL, GetLastError());
+ }
+
+ dwRet = (DWORD) SetThreadPriority(hThread[1],
+ THREAD_PRIORITY_ABOVE_NORMAL);
+ if (0 == dwRet)
+ {
+ Trace("PALSUITE ERROR: SetThreadPriority(%p, %d) call failed.\n"
+ "GetLastError returned %d", hThread[1],
+ THREAD_PRIORITY_ABOVE_NORMAL, GetLastError());
+ }
+
+ dwRet = ResumeThread(hThread[0]);
+ if (-1 == dwRet)
+ {
+ Trace("PALSUITE ERROR: ResumeThread(%p, %d) call failed.\n"
+ "GetLastError returned %d", hThread[0],
+ GetLastError() );
+ }
+
+ dwRet = ResumeThread(hThread[1]);
+ if (-1 == dwRet)
+ {
+ Trace("PALSUITE ERROR: ResumeThread(%p, %d) call failed.\n"
+ "GetLastError returned %d", hThread[0],
+ GetLastError());
+ }
+
+ Sleep (0);
+
+ LeaveCriticalSection (&CriticalSection);
+
+ dwRet = WaitForSingleObject(hThread[0], 10000);
+ dwRet1 = WaitForSingleObject(hThread[1], 10000);
+
+ if ((WAIT_OBJECT_0 == dwRet) ||
+ (WAIT_OBJECT_0 == dwRet1))
+ {
+ if ((1 == flags[0] && 0 == flags[1]) ||
+ (0 == flags[0] && 1 == flags[1]))
+ {
+ bTestResult = PASS;
+ }
+ else
+ {
+ bTestResult = FAIL;
+ Trace ("PALSUITE ERROR: flags[%d] = {%d,%d}. These values are"
+ "inconsistent.\nCriticalSection test failed.\n",
+ NUM_BLOCKING_THREADS, flags[0], flags[1]);
+ }
+
+ /* Fail the test if both threads returned WAIT_OBJECT_0 */
+ if ((WAIT_OBJECT_0 == dwRet) && (WAIT_OBJECT_0 == dwRet1))
+ {
+ bTestResult = FAIL;
+ Trace ("PALSUITE ERROR: WaitForSingleObject(%p, %d) and "
+ "WaitForSingleObject(%p, %d)\nboth returned dwRet = '%d'\n"
+ "One should have returned WAIT_TIMEOUT ('%d').\n",
+ hThread[0], 10000, hThread[1], 10000, dwRet, WAIT_TIMEOUT);
+ }
+ }
+ else
+ {
+ bTestResult = FAIL;
+ Trace ("PALSUITE ERROR: WaitForSingleObject(%p, %d) and "
+ "WaitForSingleObject(%p, %d)\nReturned dwRet = '%d' and\n"
+ "dwRet1 = '%d' respectively.\n", hThread[0], 10000, hThread[1],
+ 10000, dwRet, dwRet1);
+ }
+
+ if (WAIT_OBJECT_0 == dwRet)
+ {
+ if (0 == CloseHandle(hThread[0]))
+ {
+ Trace("PALSUITE NOTIFICATION: CloseHandle(%p) call failed.\n"
+ "GetLastError returned %d. Not failing tests.\n",
+ hThread[0], GetLastError());
+ }
+ }
+ if (WAIT_OBJECT_0 == dwRet1)
+ {
+ if (0 == CloseHandle(hThread[1]))
+ {
+ Trace("PALSUITE NOTIFICATION: CloseHandle(%p) call failed.\n"
+ "GetLastError returned %d. Not failing tests.\n",
+ hThread[1], GetLastError());
+ }
+ }
+
+ /* Leaking the CS on purpose, since there is still a thread
+ waiting on it */
+
+ PAL_TerminateEx(bTestResult);
+ return (bTestResult);
+}
diff --git a/src/pal/tests/palsuite/threading/CriticalSectionFunctions/test4/testinfo.dat b/src/pal/tests/palsuite/threading/CriticalSectionFunctions/test4/testinfo.dat
new file mode 100644
index 0000000000..9c07c24113
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CriticalSectionFunctions/test4/testinfo.dat
@@ -0,0 +1,17 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = LeaveCriticalSection
+Name = Positive test to ensure CRITICAL_SECTION objects are released properly
+TYPE = DEFAULT
+EXE1 = test4
+Description
+= Test to see if threads blocked on a CRITICAL_SECTION object will
+= be released in an orderly manner. This case looks at the following
+= scenario. If one thread owns a CRITICAL_SECTION object and two threads
+= block in EnterCriticalSection, trying to hold the already owned
+= CRITICAL_SECTION object, when the first thread releases the CRITICAL_SECTION
+= object, will one and only one of the waiters get unblocked?
diff --git a/src/pal/tests/palsuite/threading/CriticalSectionFunctions/test5/CMakeLists.txt b/src/pal/tests/palsuite/threading/CriticalSectionFunctions/test5/CMakeLists.txt
new file mode 100644
index 0000000000..37d709f121
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CriticalSectionFunctions/test5/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test5.c
+)
+
+add_executable(paltest_criticalsectionfunctions_test5
+ ${SOURCES}
+)
+
+add_dependencies(paltest_criticalsectionfunctions_test5 coreclrpal)
+
+target_link_libraries(paltest_criticalsectionfunctions_test5
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/CriticalSectionFunctions/test5/test5.c b/src/pal/tests/palsuite/threading/CriticalSectionFunctions/test5/test5.c
new file mode 100644
index 0000000000..8dfa4f5f3d
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CriticalSectionFunctions/test5/test5.c
@@ -0,0 +1,187 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: CriticalSectionFunctions/test5/test5.c
+**
+** Purpose: Attempt to delete a critical section owned by another
+** thread.
+**
+**
+**===================================================================*/
+#include <palsuite.h>
+
+/*
+ * Tokens 0 and 1 are events. Token 2 is the thread.
+ */
+#define NUM_TOKENS 3
+
+HANDLE hToken[NUM_TOKENS];
+CRITICAL_SECTION CriticalSection;
+
+BOOL CleanupHelper (HANDLE *hArray, DWORD dwIndex)
+{
+ BOOL bCHRet;
+
+ bCHRet = CloseHandle(hArray[dwIndex]);
+ if (!bCHRet)
+ {
+ Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) during "
+ "clean up.\nGetLastError returned '%u'.\n", hArray[dwIndex],
+ GetLastError());
+ }
+
+ return (bCHRet);
+}
+
+BOOL Cleanup(HANDLE *hArray, DWORD dwIndex)
+{
+ BOOL bCRet;
+ BOOL bCHRet = FALSE;
+
+ while (--dwIndex > 0)
+ {
+ bCHRet = CleanupHelper(&hArray[0], dwIndex);
+ }
+
+ bCRet = CloseHandle(hArray[0]);
+ if (!bCRet)
+ {
+ Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) during "
+ "clean up.\nGetLastError returned '%u'.\n", hArray[dwIndex],
+ GetLastError());
+ }
+
+ return (bCRet&&bCHRet);
+}
+
+DWORD PALAPI Thread(LPVOID lpParam)
+{
+ DWORD dwTRet;
+
+ EnterCriticalSection(&CriticalSection);
+
+ /* signal thread 0 */
+ if (0 == SetEvent(hToken[0]))
+ {
+ Trace("PALSUITE ERROR: Unable to execute SetEvent(%p) during "
+ "clean up.\nGetLastError returned '%u'.\n", hToken[0],
+ GetLastError());
+ LeaveCriticalSection(&CriticalSection);
+ Cleanup (&hToken[0], NUM_TOKENS);
+ DeleteCriticalSection(&CriticalSection);
+ Fail("");
+ }
+
+ /* wait to be signaled */
+ dwTRet = WaitForSingleObject(hToken[1], 10000);
+ if (WAIT_OBJECT_0 != dwTRet)
+
+ {
+ Trace("PALSUITE ERROR: WaitForSingleObject(%p,%d) should have "
+ "returned\nWAIT_OBJECT_0 ('%d'), instead it returned "
+ "('%d').\nGetLastError returned '%u'.\n",
+ hToken[1], 10000, WAIT_OBJECT_0, dwTRet, GetLastError());
+ LeaveCriticalSection(&CriticalSection);
+ Cleanup (&hToken[0], NUM_TOKENS);
+ DeleteCriticalSection(&CriticalSection);
+ Fail("");
+ }
+
+ LeaveCriticalSection(&CriticalSection);
+ return 0;
+}
+
+int __cdecl main(int argc, char **argv)
+{
+ DWORD dwThreadId;
+ DWORD dwMRet;
+
+ if ((PAL_Initialize(argc,argv)) != 0)
+ {
+ return(FAIL);
+ }
+
+ /* thread 0 event */
+ hToken[0] = CreateEvent(NULL, TRUE, FALSE, NULL);
+ if (NULL == hToken[0])
+ {
+ Fail("PALSUITE ERROR: CreateEvent call #0 failed. GetLastError "
+ "returned %u.\n", GetLastError());
+ }
+
+ /* thread 1 event */
+ hToken[1] = CreateEvent(NULL, TRUE, FALSE, NULL);
+ if (NULL == hToken[1])
+ {
+ Trace("PALSUITE ERROR: CreateEvent call #1 failed. GetLastError "
+ "returned %u.\n", GetLastError());
+ Cleanup(&hToken[0], (NUM_TOKENS - 2));
+ Fail("");
+ }
+
+ InitializeCriticalSection(&CriticalSection);
+
+ hToken[2] = CreateThread(NULL,
+ 0,
+ &Thread,
+ (LPVOID) NULL,
+ 0,
+ &dwThreadId);
+ if (hToken[2] == NULL)
+ {
+ Trace("PALSUITE ERROR: CreateThread call #0 failed. GetLastError "
+ "returned %u.\n", GetLastError());
+ Cleanup(&hToken[0], (NUM_TOKENS - 1));
+ DeleteCriticalSection(&CriticalSection);
+ Fail("");
+ }
+
+ /* wait for thread 0 to be signaled */
+ dwMRet = WaitForSingleObject(hToken[0], 10000);
+ if (WAIT_OBJECT_0 != dwMRet)
+ {
+ Trace("PALSUITE ERROR: WaitForSingleObject(%p,%d) should have "
+ "returned\nWAIT_OBJECT_0 ('%d'), instead it returned "
+ "('%d').\nGetLastError returned '%u'.\n", hToken[0], 10000,
+ WAIT_OBJECT_0, dwMRet, GetLastError());
+ Cleanup(&hToken[0], NUM_TOKENS);
+ Fail("");
+ }
+
+ /*
+ * Attempt to do delete CriticalSection object owned by other thread
+ */
+ DeleteCriticalSection(&CriticalSection);
+
+ /* signal thread 1 */
+ if (0 == SetEvent(hToken[1]))
+ {
+ Trace("PALSUITE ERROR: Unable to execute SetEvent(%p) call.\n"
+ "GetLastError returned '%u'.\n", hToken[1],
+ GetLastError());
+ Cleanup(&hToken[0], NUM_TOKENS);
+ Fail("");
+ }
+
+ dwMRet = WaitForSingleObject(hToken[2], 10000);
+ if (WAIT_OBJECT_0 != dwMRet)
+ {
+ Trace("PALSUITE ERROR: WaitForSingleObject(%p, %d) call "
+ "returned an unexpected value '%d'.\nGetLastError returned "
+ "%u.\n", hToken[2], 10000, dwMRet, GetLastError());
+ Cleanup(&hToken[0], NUM_TOKENS);
+ Fail("");
+ }
+
+ if (!Cleanup(&hToken[0], NUM_TOKENS))
+ {
+ Fail("");
+ }
+
+ PAL_Terminate();
+
+ return (PASS);
+}
diff --git a/src/pal/tests/palsuite/threading/CriticalSectionFunctions/test5/testinfo.dat b/src/pal/tests/palsuite/threading/CriticalSectionFunctions/test5/testinfo.dat
new file mode 100644
index 0000000000..aa1124925b
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CriticalSectionFunctions/test5/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = CriticalSectionFunctions
+Name = Positive test for DeleteCriticalSection
+TYPE = DEFAULT
+EXE1 = test5
+Description
+= Attempt to delete a critical section owned by another thread.
diff --git a/src/pal/tests/palsuite/threading/CriticalSectionFunctions/test6/CMakeLists.txt b/src/pal/tests/palsuite/threading/CriticalSectionFunctions/test6/CMakeLists.txt
new file mode 100644
index 0000000000..c580fdbd6b
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CriticalSectionFunctions/test6/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test6.c
+)
+
+add_executable(paltest_criticalsectionfunctions_test6
+ ${SOURCES}
+)
+
+add_dependencies(paltest_criticalsectionfunctions_test6 coreclrpal)
+
+target_link_libraries(paltest_criticalsectionfunctions_test6
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/CriticalSectionFunctions/test6/test6.c b/src/pal/tests/palsuite/threading/CriticalSectionFunctions/test6/test6.c
new file mode 100644
index 0000000000..c27db86e5b
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CriticalSectionFunctions/test6/test6.c
@@ -0,0 +1,190 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: CriticalSectionFunctions/test6/test6.c
+**
+** Purpose: Attempt to leave a critical section which is owned by
+** another thread.
+**
+**
+**===================================================================*/
+#include <palsuite.h>
+
+/*
+ * Tokens 0 and 1 are events. Token 2 is the thread.
+ */
+#define NUM_TOKENS 3
+
+HANDLE hToken[NUM_TOKENS];
+CRITICAL_SECTION CriticalSection;
+
+BOOL CleanupHelper (HANDLE *hArray, DWORD dwIndex)
+{
+ BOOL bCHRet;
+
+ bCHRet = CloseHandle(hArray[dwIndex]);
+ if (!bCHRet)
+ {
+ Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) during "
+ "clean up.\nGetLastError returned '%u'.\n", hArray[dwIndex],
+ GetLastError());
+ }
+
+ return (bCHRet);
+}
+
+BOOL Cleanup(HANDLE *hArray, DWORD dwIndex)
+{
+ BOOL bCRet;
+ BOOL bCHRet;
+
+ while (--dwIndex > 0)
+ {
+ bCHRet = CleanupHelper(&hArray[0], dwIndex);
+ }
+
+ bCRet = CloseHandle(hArray[0]);
+ if (!bCRet)
+ {
+ Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) during "
+ "clean up.\nGetLastError returned '%u'.\n", hArray[dwIndex],
+ GetLastError());
+ }
+
+ return (bCRet&&bCHRet);
+}
+
+DWORD PALAPI Thread(LPVOID lpParam)
+{
+ DWORD dwTRet;
+
+ EnterCriticalSection(&CriticalSection);
+
+ /* signal thread 0 */
+ if (0 == SetEvent(hToken[0]))
+ {
+ Trace("PALSUITE ERROR: Unable to execute SetEvent(%p) during "
+ "clean up.\nGetLastError returned '%u'.\n", hToken[0],
+ GetLastError());
+ LeaveCriticalSection(&CriticalSection);
+ Cleanup (&hToken[0], NUM_TOKENS);
+ DeleteCriticalSection(&CriticalSection);
+ Fail("");
+ }
+
+ /* wait to be signaled */
+ dwTRet = WaitForSingleObject(hToken[1], 10000);
+ if (WAIT_OBJECT_0 != dwTRet)
+ {
+ Trace("PALSUITE ERROR: WaitForSingleObject(%p,%d) should have "
+ "returned\nWAIT_OBJECT_0 ('%d'), instead it returned "
+ "('%d').\nGetLastError returned '%u'.\n",
+ hToken[1], 10000, WAIT_OBJECT_0, dwTRet, GetLastError());
+ LeaveCriticalSection(&CriticalSection);
+ Cleanup (&hToken[0], NUM_TOKENS);
+ DeleteCriticalSection(&CriticalSection);
+ Fail("");
+ }
+
+ LeaveCriticalSection(&CriticalSection);
+
+ return 0;
+}
+
+int __cdecl main(int argc, char **argv)
+{
+ DWORD dwThreadId;
+ DWORD dwMRet;
+
+ if ((PAL_Initialize(argc,argv)) != 0)
+ {
+ return(FAIL);
+ }
+
+ /* thread 0 event */
+ hToken[0] = CreateEvent(NULL, TRUE, FALSE, NULL);
+
+ if (hToken[0] == NULL)
+ {
+ Fail("PALSUITE ERROR: CreateEvent call #0 failed. GetLastError "
+ "returned %u.\n", GetLastError());
+ }
+
+ /* thread 1 event */
+ hToken[1] = CreateEvent(NULL, TRUE, FALSE, NULL);
+
+ if (hToken[1] == NULL)
+ {
+ Trace("PALSUITE ERROR: CreateEvent call #1 failed. GetLastError "
+ "returned %u.\n", GetLastError());
+ Cleanup(&hToken[0], (NUM_TOKENS - 2));
+ Fail("");
+ }
+
+ InitializeCriticalSection(&CriticalSection);
+
+ hToken[2] = CreateThread(NULL,
+ 0,
+ &Thread,
+ (LPVOID) NULL,
+ 0,
+ &dwThreadId);
+
+ if (hToken[2] == NULL)
+ {
+ Trace("PALSUITE ERROR: CreateThread call #0 failed. GetLastError "
+ "returned %u.\n", GetLastError());
+ Cleanup(&hToken[0], (NUM_TOKENS - 1));
+ DeleteCriticalSection(&CriticalSection);
+ Fail("");
+ }
+
+ /* wait for thread 0 to be signaled */
+ dwMRet = WaitForSingleObject(hToken[0], 10000);
+ if (WAIT_OBJECT_0 != dwMRet)
+ {
+ Trace("PALSUITE ERROR: WaitForSingleObject(%p,%d) should have "
+ "returned\nWAIT_OBJECT_0 ('%d'), instead it returned "
+ "('%d').\nGetLastError returned '%u'.\n", hToken[0], 10000,
+ WAIT_OBJECT_0, dwMRet, GetLastError());
+ Cleanup(&hToken[0], NUM_TOKENS);
+ Fail("");
+ }
+
+ /*
+ * Attempt to leave critical section which is owned by the other thread.
+ */
+ LeaveCriticalSection(&CriticalSection);
+
+ /* signal thread 1 */
+ if (0 == SetEvent(hToken[1]))
+ {
+ Trace("PALSUITE ERROR: Unable to execute SetEvent(%p) call.\n"
+ "GetLastError returned '%u'.\n", hToken[1],
+ GetLastError());
+ Cleanup(&hToken[0], NUM_TOKENS);
+ Fail("");
+ }
+
+ dwMRet = WaitForSingleObject(hToken[2], 10000);
+ if (WAIT_OBJECT_0 != dwMRet)
+ {
+ Trace("PALSUITE ERROR: WaitForSingleObject(%p, %d) call "
+ "returned an unexpected value '%d'.\nGetLastError returned "
+ "%u.\n", hToken[2], 10000, dwMRet, GetLastError());
+ Cleanup(&hToken[0], NUM_TOKENS);
+ Fail("");
+ }
+
+ if (!Cleanup(&hToken[0], NUM_TOKENS))
+ {
+ Fail("");
+ }
+
+ PAL_Terminate();
+
+ return(PASS);
+}
diff --git a/src/pal/tests/palsuite/threading/CriticalSectionFunctions/test6/testinfo.dat b/src/pal/tests/palsuite/threading/CriticalSectionFunctions/test6/testinfo.dat
new file mode 100644
index 0000000000..151e1ed4d0
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CriticalSectionFunctions/test6/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = CriticalSectionFunctions
+Name = Positive Test for LeaveCriticalSection
+TYPE = DEFAULT
+EXE1 = test6
+Description
+= Attempt to leave a critical section which is owned by another thread.
diff --git a/src/pal/tests/palsuite/threading/CriticalSectionFunctions/test7/CMakeLists.txt b/src/pal/tests/palsuite/threading/CriticalSectionFunctions/test7/CMakeLists.txt
new file mode 100644
index 0000000000..0a12bfe3ef
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CriticalSectionFunctions/test7/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test7.c
+)
+
+add_executable(paltest_criticalsectionfunctions_test7
+ ${SOURCES}
+)
+
+add_dependencies(paltest_criticalsectionfunctions_test7 coreclrpal)
+
+target_link_libraries(paltest_criticalsectionfunctions_test7
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/CriticalSectionFunctions/test7/test7.c b/src/pal/tests/palsuite/threading/CriticalSectionFunctions/test7/test7.c
new file mode 100644
index 0000000000..1c030d3c03
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CriticalSectionFunctions/test7/test7.c
@@ -0,0 +1,188 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: CriticalSectionFunctions/test7/test7.c
+**
+** Purpose: Attempt to delete a critical section owned by the current
+** thread.
+**
+**
+**===================================================================*/
+#include <palsuite.h>
+
+/*
+ * Tokens 0 and 1 are events. Token 2 is the thread.
+ */
+#define NUM_TOKENS 3
+
+HANDLE hToken[NUM_TOKENS];
+CRITICAL_SECTION CriticalSection;
+
+BOOL CleanupHelper (HANDLE *hArray, DWORD dwIndex)
+{
+ BOOL bCHRet;
+
+ bCHRet = CloseHandle(hArray[dwIndex]);
+ if (!bCHRet)
+ {
+ Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) during "
+ "clean up.\nGetLastError returned '%u'.\n", hArray[dwIndex],
+ GetLastError());
+ }
+
+ return (bCHRet);
+}
+
+BOOL Cleanup(HANDLE *hArray, DWORD dwIndex)
+{
+ BOOL bCRet;
+ BOOL bCHRet = 0;
+
+ while (--dwIndex > 0)
+ {
+ bCHRet = CleanupHelper(&hArray[0], dwIndex);
+ }
+
+ bCRet = CloseHandle(hArray[0]);
+ if (!bCRet)
+ {
+ Trace("PALSUITE ERROR: Unable to execute CloseHandle(%p) during "
+ "clean up.\nGetLastError returned '%u'.\n", hArray[dwIndex],
+ GetLastError());
+ }
+
+ return (bCRet&&bCHRet);
+}
+
+DWORD PALAPI Thread(LPVOID lpParam)
+{
+ DWORD dwTRet;
+
+ EnterCriticalSection(&CriticalSection);
+
+ /* signal thread 0 */
+ if (0 == SetEvent(hToken[0]))
+ {
+ Trace("PALSUITE ERROR: Unable to execute SetEvent(%p) during "
+ "clean up.\nGetLastError returned '%u'.\n", hToken[0],
+ GetLastError());
+ LeaveCriticalSection(&CriticalSection);
+ Cleanup (&hToken[0], NUM_TOKENS);
+ DeleteCriticalSection(&CriticalSection);
+ Fail("");
+ }
+
+ /* wait to be signaled */
+ dwTRet = WaitForSingleObject(hToken[1], 10000);
+ if (WAIT_OBJECT_0 != dwTRet)
+ {
+ Trace("PALSUITE ERROR: WaitForSingleObject(%p,%d) should have "
+ "returned\nWAIT_OBJECT_0 ('%d'), instead it returned "
+ "('%d').\nGetLastError returned '%u'.\n",
+ hToken[0], 10000, WAIT_OBJECT_0, dwTRet, GetLastError());
+ LeaveCriticalSection(&CriticalSection);
+ Cleanup (&hToken[0], NUM_TOKENS);
+ DeleteCriticalSection(&CriticalSection);
+ Fail("");
+ }
+
+ DeleteCriticalSection(&CriticalSection);
+
+ return 0;
+}
+
+int __cdecl main(int argc, char **argv)
+{
+ DWORD dwThreadId;
+ DWORD dwMRet;
+
+ if ((PAL_Initialize(argc,argv)) != 0)
+ {
+ return(FAIL);
+ }
+
+ /* thread 0 event */
+ hToken[0] = CreateEvent(NULL, TRUE, FALSE, NULL);
+
+ if (hToken[0] == NULL)
+ {
+ Fail("PALSUITE ERROR: CreateEvent call #0 failed. GetLastError "
+ "returned %u.\n", GetLastError());
+ }
+
+ /* thread 1 event */
+ hToken[1] = CreateEvent(NULL, TRUE, FALSE, NULL);
+
+ if (hToken[1] == NULL)
+ {
+ Trace("PALSUITE ERROR: CreateEvent call #1 failed. GetLastError "
+ "returned %u.\n", GetLastError());
+ Cleanup (&hToken[0], (NUM_TOKENS - 2));
+ Fail("");
+ }
+
+ InitializeCriticalSection(&CriticalSection);
+
+ hToken[2] = CreateThread(NULL,
+ 0,
+ &Thread,
+ (LPVOID) NULL,
+ 0,
+ &dwThreadId);
+
+ if (hToken[2] == NULL)
+ {
+ Trace("PALSUITE ERROR: CreateThread call #0 failed. GetLastError "
+ "returned %u.\n", GetLastError());
+ Cleanup (&hToken[0], (NUM_TOKENS - 1));
+ DeleteCriticalSection(&CriticalSection);
+ Fail("");
+ }
+
+ /* wait for thread 0 to be signaled */
+ dwMRet = WaitForSingleObject(hToken[0], 10000);
+ if (WAIT_OBJECT_0 != dwMRet)
+ {
+ Trace("PALSUITE ERROR: WaitForSingleObject(%p,%d) should have "
+ "returned\nWAIT_OBJECT_0 ('%d'), instead it returned "
+ "('%d').\nGetLastError returned '%u'.\n", hToken[0], 10000,
+ WAIT_OBJECT_0, dwMRet, GetLastError());
+ Cleanup (&hToken[0], NUM_TOKENS);
+ Fail("");
+ }
+
+ /* signal thread 1 */
+ if (0 == SetEvent(hToken[1]))
+ {
+ Trace("PALSUITE ERROR: Unable to execute SetEvent(%p) call.\n"
+ "GetLastError returned '%u'.\n", hToken[1],
+ GetLastError());
+ Cleanup (&hToken[0], NUM_TOKENS);
+ Fail("");
+ }
+
+ dwMRet = WaitForSingleObject(hToken[2], 10000);
+ if (WAIT_OBJECT_0 != dwMRet)
+ {
+ Trace("PALSUITE ERROR: WaitForSingleObject(%p, %d) call "
+ "returned an unexpected value '%d'.\nGetLastError returned "
+ "%u.\n", hToken[2], 10000, dwMRet, GetLastError());
+ Cleanup (&hToken[0], NUM_TOKENS);
+ Fail("");
+ }
+
+ if (!Cleanup(&hToken[0], NUM_TOKENS))
+ {
+ Fail("");
+ }
+
+ PAL_Terminate();
+
+ return (PASS);
+}
+
+
+
diff --git a/src/pal/tests/palsuite/threading/CriticalSectionFunctions/test7/testinfo.dat b/src/pal/tests/palsuite/threading/CriticalSectionFunctions/test7/testinfo.dat
new file mode 100644
index 0000000000..5cf5809622
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CriticalSectionFunctions/test7/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = CriticalSectionFunctions
+Name = Positive test for DeleteCriticalSection
+TYPE = DEFAULT
+EXE1 = test7
+Description
+= Attempt to delete a critical section owned by the current thread.
diff --git a/src/pal/tests/palsuite/threading/CriticalSectionFunctions/test8/CMakeLists.txt b/src/pal/tests/palsuite/threading/CriticalSectionFunctions/test8/CMakeLists.txt
new file mode 100644
index 0000000000..0d95a95410
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CriticalSectionFunctions/test8/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test8.c
+)
+
+add_executable(paltest_criticalsectionfunctions_test8
+ ${SOURCES}
+)
+
+add_dependencies(paltest_criticalsectionfunctions_test8 coreclrpal)
+
+target_link_libraries(paltest_criticalsectionfunctions_test8
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/CriticalSectionFunctions/test8/test8.c b/src/pal/tests/palsuite/threading/CriticalSectionFunctions/test8/test8.c
new file mode 100644
index 0000000000..7f0c58cd26
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CriticalSectionFunctions/test8/test8.c
@@ -0,0 +1,217 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: CriticalSectionFunctions/test8/test8.c
+**
+** Pyrpose: Ensure critical section functionality is working by
+** having multiple threads racing on a CS under different
+** scenarios
+**
+**
+**===================================================================*/
+#include <palsuite.h>
+
+#define MAX_THREAD_COUNT 128
+#define DEFAULT_THREAD_COUNT 10
+#define DEFAULT_LOOP_COUNT 1000
+
+#ifndef MIN
+#define MIN(a,b) (((a)<(b)) ? (a) : (b))
+#endif
+
+int g_iThreadCount = DEFAULT_THREAD_COUNT;
+int g_iLoopCount = DEFAULT_LOOP_COUNT;
+volatile LONG g_lCriticalCount = 0;
+HANDLE g_hEvStart = NULL;
+
+CRITICAL_SECTION g_cs;
+DWORD PALAPI Thread(LPVOID lpParam)
+{
+ int i, j, iLpCnt;
+ DWORD dwRet = 0;
+ DWORD dwTid = GetCurrentThreadId();
+ LONG lRet;
+ BOOL bSleepInside;
+ BOOL bSleepOutside;
+
+ Trace("[tid=%u] Thread starting\n", dwTid);
+
+ dwRet = WaitForSingleObject(g_hEvStart, INFINITE);
+ if (WAIT_OBJECT_0 != dwRet)
+ {
+ Fail("WaitForSingleObject returned unexpected %u [GetLastError()=%u]\n",
+ dwRet, GetLastError());
+ }
+
+ for (j=0;j<8;j++)
+ {
+ bSleepInside = 2 & j;
+ bSleepOutside = 4 & j;
+
+ iLpCnt = g_iLoopCount;
+ if (bSleepInside || bSleepOutside)
+ {
+ iLpCnt /= 10;
+ }
+
+ for (i=0;i<iLpCnt;i++)
+ {
+ EnterCriticalSection(&g_cs);
+ if (1 & i)
+ {
+ // Simple increment on odd iterations
+ lRet = (g_lCriticalCount += 1);
+ }
+ else
+ {
+ // Interlocked increment on even iterations
+ lRet = InterlockedIncrement(&g_lCriticalCount);
+ }
+
+ if (1 != lRet || 1 != g_lCriticalCount)
+ {
+ Fail("Detected %d threads in area protected by critical section "
+ "[expected: 1 thread]\n", g_lCriticalCount);
+ }
+ if (bSleepInside)
+ {
+ Sleep(rand()%10);
+ }
+ if (1 != g_lCriticalCount)
+ {
+ Fail("Detected %d threads inside area protected by critical section "
+ "[expected: 1 thread]\n", (int)g_lCriticalCount);
+ }
+
+ if (1 & i)
+ {
+ // Simple decrement on odd iterations
+ lRet = (g_lCriticalCount -= 1);
+ }
+ else
+ {
+ // Interlocked decrement on even iterations
+ lRet = InterlockedDecrement(&g_lCriticalCount);
+ }
+ LeaveCriticalSection(&g_cs);
+
+ if (bSleepOutside)
+ {
+ Sleep(rand()%10);
+ }
+ }
+ }
+
+ Trace("[tid=%u] Thread done\n", dwTid);
+
+ return 0;
+}
+
+int __cdecl main(int argc, char **argv)
+{
+ DWORD dwThreadId;
+ DWORD dwRet;
+ HANDLE hThreads[MAX_THREAD_COUNT] = { 0 };
+ int iThreadCount = 0;
+ int i, iVal;
+
+ if ((PAL_Initialize(argc,argv)) != 0)
+ {
+ return(FAIL);
+ }
+
+ srand(time(NULL));
+
+ for (i=1; i<argc; i++)
+ {
+ if ('-' == *argv[i])
+ {
+ switch(*(argv[i]+1))
+ {
+ case 'n':
+ if (i < argc-1)
+ {
+ i += 1;
+ iVal = atoi(argv[i]);
+ if (0 < iVal)
+ {
+ g_iLoopCount = iVal;
+ }
+ }
+ break;
+ case 't':
+ if (i < argc-1)
+ {
+ i += 1;
+ iVal = atoi(argv[i]);
+ if (0 < iVal && MAX_THREAD_COUNT >= iVal)
+ {
+ g_iThreadCount = iVal;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ Trace ("Iterations:\t%d\n", g_iLoopCount);
+ Trace ("Threads:\t%d\n", g_iThreadCount);
+
+ g_hEvStart = CreateEvent(NULL, TRUE, FALSE, NULL);
+
+ if (g_hEvStart == NULL)
+ {
+ Fail("CreateEvent call failed. GetLastError "
+ "returned %u.\n", GetLastError());
+ }
+
+ InitializeCriticalSection(&g_cs);
+
+ for (i=0;i<g_iThreadCount;i++)
+ {
+ hThreads[iThreadCount] = CreateThread(NULL,
+ 0,
+ &Thread,
+ (LPVOID) NULL,
+ 0,
+ &dwThreadId);
+ if (NULL != hThreads[iThreadCount])
+ {
+ iThreadCount++;
+ }
+ }
+
+ Sleep(100);
+
+ Trace("Created %d client threads\n", g_iThreadCount);
+
+ if (2 > iThreadCount)
+ {
+ Fail("Failed to create minimum number if threads, i.e. 2\n");
+ }
+
+ if (!SetEvent(g_hEvStart))
+ {
+ Fail("SetEvent failed [GetLastError()=%u]\n", GetLastError());
+ }
+
+ for (i=0; i<iThreadCount; i+=64)
+ {
+ dwRet = WaitForMultipleObjects(MIN(iThreadCount-i,64),
+ hThreads+i,
+ TRUE,
+ INFINITE);
+ if (WAIT_OBJECT_0 != dwRet)
+ {
+ Fail("Wait for all threads failed\n");
+ }
+ }
+
+ PAL_Terminate();
+ return (PASS);
+}
diff --git a/src/pal/tests/palsuite/threading/CriticalSectionFunctions/test8/thistest.dat b/src/pal/tests/palsuite/threading/CriticalSectionFunctions/test8/thistest.dat
new file mode 100644
index 0000000000..1057eca5c5
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/CriticalSectionFunctions/test8/thistest.dat
@@ -0,0 +1,2 @@
+
+PAL,threading,palsuite\threading\criticalsectionfunctions\test8,Test8forCriticalSectionFunctionalities=test8.c,
diff --git a/src/pal/tests/palsuite/threading/DisableThreadLibraryCalls/test1/test1.c b/src/pal/tests/palsuite/threading/DisableThreadLibraryCalls/test1/test1.c
new file mode 100644
index 0000000000..b64fd0c7d2
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/DisableThreadLibraryCalls/test1/test1.c
@@ -0,0 +1,145 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test1.c
+**
+** Purpose: Tests that DisableThreadLibraryCalls actually stops thread
+** attach/detach notifications to a library. Also tests how it
+** handles an invalid module handle.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+
+/* SHLEXT is defined only for Unix variants */
+
+#if defined(SHLEXT)
+#define LibName "testlib"SHLEXT
+#define GETCALLCOUNT "GetCallCount"
+#else
+#define LibName "testlib"
+#define GETCALLCOUNT "_GetCallCount@0"
+#endif
+
+DWORD __stdcall ThreadFunc(LPVOID lpParam);
+int RunTest(int DisableThreadCalls);
+
+int __cdecl main(int argc, char **argv)
+{
+ int ret;
+
+ if ((PAL_Initialize(argc,argv)) != 0)
+ {
+ return (FAIL);
+ }
+
+
+ /*
+ * Although MSDN says that DisableThreadLibraryCalls will fail if passed
+ * an invalid handle, it actually returns success!
+ */
+ ret = DisableThreadLibraryCalls(NULL);
+ if (!ret)
+ {
+ Fail("DisableThreadLibraryCalls failed on an invalid module "
+ "handle (it actually should pass)!\n");
+ }
+
+
+ /*
+ * Test once without calling DisableThreadLibraryCalls and make sure we
+ * get expected results.
+ */
+ ret = RunTest(0);
+ if (ret != 2)
+ {
+ Fail("Expected to get 2 thread library calls, got %d!\n", ret);
+ }
+
+
+ /*
+ * Test again, this time calling DisableThreadLibraryCalls.
+ */
+ ret = RunTest(1);
+ if (ret != 0)
+ {
+ Fail("Expected to get 0 thread library calls, got %d!\n", ret);
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
+/*
+ * Thread entry point. Doesn't do anything.
+ */
+DWORD __stdcall ThreadFunc(LPVOID lpParam)
+{
+ return 0;
+}
+
+
+int RunTest(int DisableThreadCalls)
+{
+ HMODULE LibMod;
+ HANDLE hThread;
+ DWORD threadID;
+ DWORD WaitRet;
+ int (*GetCallCount)();
+ int count;
+
+ LibMod = LoadLibrary(LibName);
+ if (LibMod == NULL)
+ {
+ Fail("Unable to load test library!\nGetLastError returned %d\n",
+ GetLastError());
+ }
+
+ GetCallCount = (int(*)())GetProcAddress(LibMod, GETCALLCOUNT);
+ if (GetCallCount == NULL)
+ {
+ Fail("Unable to get function GetCallCount from library!\n"
+ "GetLastError returned %d\n", GetLastError());
+ }
+
+ if (DisableThreadCalls)
+ {
+ if (!DisableThreadLibraryCalls(LibMod))
+ {
+ Fail("DisabledThreadLibraryCalls failed!\n"
+ "GetLastError returned %d!\n", GetLastError());
+ }
+ }
+
+ hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) ThreadFunc,
+ NULL, 0, &threadID);
+
+ if (hThread == NULL)
+ {
+ Fail("Unable to create a thread!\n");
+ }
+
+ WaitRet = WaitForSingleObject(hThread, INFINITE);
+ if (WaitRet == WAIT_FAILED)
+ {
+ Fail("Unable to wait on thread!\nGetLastError returned %d\n",
+ GetLastError());
+ }
+
+ count = GetCallCount();
+
+ CloseHandle(hThread);
+
+ if (!FreeLibrary(LibMod))
+ {
+ Fail("Failed freeing library!\nGetLastError returned %d\n",
+ GetLastError());
+ }
+
+ return count;
+}
diff --git a/src/pal/tests/palsuite/threading/DisableThreadLibraryCalls/test1/testinfo.dat b/src/pal/tests/palsuite/threading/DisableThreadLibraryCalls/test1/testinfo.dat
new file mode 100644
index 0000000000..6d32f3591a
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/DisableThreadLibraryCalls/test1/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Threading
+Function = DisableThreadLibraryCalls
+Name = Positive Test #1 for DisableThreadLibraryCalls
+TYPE = DEFAULT
+EXE1 = test1
+LIB1 = testlib
+Description
+=Tests that DisableThreadLibraryCalls actually stops thread
+=attach/detach notifications to a library. Also tests how it
+=handles an invalid module handle.
diff --git a/src/pal/tests/palsuite/threading/DisableThreadLibraryCalls/test1/testlib.c b/src/pal/tests/palsuite/threading/DisableThreadLibraryCalls/test1/testlib.c
new file mode 100644
index 0000000000..53b66d1357
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/DisableThreadLibraryCalls/test1/testlib.c
@@ -0,0 +1,47 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: testlib.c
+**
+** Purpose: Simple library that counts thread attach/detach notifications
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+static int Count;
+
+BOOL __stdcall DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
+{
+
+ if (fdwReason == DLL_PROCESS_ATTACH)
+ {
+ Count = 0;
+ }
+ else if (fdwReason == DLL_THREAD_ATTACH ||
+ fdwReason == DLL_THREAD_DETACH)
+ {
+ Count++;
+ }
+
+ return TRUE;
+}
+
+#ifdef WIN32
+BOOL __stdcall _DllMainCRTStartup(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
+{
+ return DllMain(hinstDLL, fdwReason, lpvReserved);
+}
+#endif
+
+#ifdef WIN32
+__declspec(dllexport)
+#endif
+int __stdcall GetCallCount()
+{
+ return Count;
+}
diff --git a/src/pal/tests/palsuite/threading/DisableThreadLibraryCalls/test2/dllmain1.c b/src/pal/tests/palsuite/threading/DisableThreadLibraryCalls/test2/dllmain1.c
new file mode 100644
index 0000000000..5010a27665
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/DisableThreadLibraryCalls/test2/dllmain1.c
@@ -0,0 +1,66 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================================
+**
+** Source: dllmain1.c
+**
+** Purpose: Test to ensure DllMain() is called with THREAD_ATTACH
+** when a thread in the application is started.
+**
+** Dependencies: none
+**
+**
+**===========================================================================*/
+
+#include <palsuite.h>
+
+/* count of the number of times DllMain() was called with THREAD_DETACH */
+static int g_attachCount = 0;
+
+
+/* standard DllMain() */
+BOOL PALAPI DllMain(HINSTANCE hinstDLL, DWORD reason, LPVOID lpvReserved)
+{
+ BOOL bResult = TRUE;
+
+ switch( reason )
+ {
+ case DLL_PROCESS_ATTACH:
+ {
+ break;
+ }
+
+ case DLL_PROCESS_DETACH:
+ {
+ break;
+ }
+
+ case DLL_THREAD_ATTACH:
+ /* increment g_attachCount */
+ g_attachCount++;
+ break;
+
+ case DLL_THREAD_DETACH:
+ break;
+ }
+ return bResult;
+}
+
+
+#ifdef WIN32
+BOOL __stdcall _DllMainCRTStartup(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
+{
+ return DllMain(hinstDLL, fdwReason, lpvReserved);
+}
+#endif
+
+/* function to return the current attach count */
+#ifdef WIN32
+__declspec(dllexport)
+#endif
+int PALAPI GetAttachCount( void )
+{
+ return g_attachCount;
+}
diff --git a/src/pal/tests/palsuite/threading/DisableThreadLibraryCalls/test2/dllmain2.c b/src/pal/tests/palsuite/threading/DisableThreadLibraryCalls/test2/dllmain2.c
new file mode 100644
index 0000000000..4e3f8862a4
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/DisableThreadLibraryCalls/test2/dllmain2.c
@@ -0,0 +1,66 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================================
+**
+** Source: dllmain2.c
+**
+** Purpose: Test to ensure DllMain() is called with THREAD_ATTACH
+** when a thread in the application is started.
+**
+** Dependencies: none
+**
+**
+**===========================================================================*/
+
+#include <palsuite.h>
+
+/* count of the number of times DllMain() was called with THREAD_DETACH */
+static int g_attachCount = 0;
+
+
+/* standard DllMain() */
+BOOL PALAPI DllMain(HINSTANCE hinstDLL, DWORD reason, LPVOID lpvReserved)
+{
+ BOOL bResult = TRUE;
+
+ switch( reason )
+ {
+ case DLL_PROCESS_ATTACH:
+ {
+ break;
+ }
+
+ case DLL_PROCESS_DETACH:
+ {
+ break;
+ }
+
+ case DLL_THREAD_ATTACH:
+ /* increment g_attachCount */
+ g_attachCount++;
+ break;
+
+ case DLL_THREAD_DETACH:
+ break;
+ }
+ return bResult;
+}
+
+
+#ifdef WIN32
+BOOL __stdcall _DllMainCRTStartup(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
+{
+ return DllMain(hinstDLL, fdwReason, lpvReserved);
+}
+#endif
+
+/* function to return the current attach count */
+#ifdef WIN32
+__declspec(dllexport)
+#endif
+int PALAPI GetAttachCount( void )
+{
+ return g_attachCount;
+}
diff --git a/src/pal/tests/palsuite/threading/DisableThreadLibraryCalls/test2/test2.c b/src/pal/tests/palsuite/threading/DisableThreadLibraryCalls/test2/test2.c
new file mode 100644
index 0000000000..5fb694ea14
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/DisableThreadLibraryCalls/test2/test2.c
@@ -0,0 +1,237 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================================
+**
+** Source: test2.c
+**
+** Purpose: Test to ensure DisableThreadLibraryCalls() called for one
+** library will not disrupt THREAD_ATTACH notifications etc. by
+** other loaded modules.
+**
+** Dependencies: PAL_Initialize
+** PAL_Terminate
+** Fail
+** CreateThread
+** ResumeThread
+** LoadLibrary
+** FreeLibrary
+** GetProcAddress
+** WaitForSingleObject
+** GetLastError
+**
+**
+**===========================================================================*/
+#include <palsuite.h>
+
+/* SHLEXT is defined only for Unix variants */
+
+#if defined(SHLEXT)
+#define rgchLibraryFile1 "dllmain1"SHLEXT
+#define rgchLibraryFile2 "dllmain2"SHLEXT
+#define szFunction "GetAttachCount"
+#else
+#define rgchLibraryFile1 "dllmain1"
+#define rgchLibraryFile2 "dllmain2"
+#define szFunction "_GetAttachCount@0"
+#endif
+
+/* define our test function type */
+typedef int ( PALAPI *LPTESTFUNC )( void );
+
+
+
+/**
+ * ThreadFunc
+ *
+ * Dummy thread function for causing DLL thread notifications.
+ */
+DWORD PALAPI ThreadFunc( LPVOID param )
+{
+ /* simulate some brief "work" */
+ int i;
+ for( i=0; i<100000; i++ )
+ {
+ }
+
+ return 0;
+}
+
+
+/* main program entry point */
+int __cdecl main( int argc, char **argv )
+
+{
+ /* local variables */
+
+ HANDLE hLib1 = NULL;
+ HANDLE hLib2 = NULL;
+ LPTESTFUNC pFunc1;
+ LPTESTFUNC pFunc2;
+ int attachCount1a = 0;
+ int attachCount1b = 0;
+ int attachCount2a = 0;
+ int attachCount2b = 0;
+
+ HANDLE hThread = NULL;
+ DWORD IDThread;
+ DWORD dwRet;
+
+ BOOL bResult = FAIL;
+
+ /* initialize the PAL */
+ if( PAL_Initialize(argc, argv) != 0 )
+ {
+ return( FAIL );
+ }
+
+ /* Load the first test library */
+ hLib1 = LoadLibrary( rgchLibraryFile1 );
+ if(hLib1 == NULL)
+ {
+ Fail( "ERROR:%lu:LoadLibrary() call failed for %s\n",
+ GetLastError(),
+ rgchLibraryFile1 );
+ }
+
+ /* Load the second test library */
+ hLib2 = LoadLibrary( rgchLibraryFile2 );
+ if(hLib2 == NULL)
+ {
+ Trace( "ERROR:%lu:LoadLibrary() call failed for %s\n",
+ GetLastError(),
+ rgchLibraryFile2 );
+ if( ! FreeLibrary( hLib1 ) )
+ {
+ Trace( "ERROR:%lu:FreeLibrary() call failed\n", GetLastError() );
+ }
+ Fail( "test failed\n" );
+ }
+
+
+ /* Get the addresses of our test functions in the dlls */
+ pFunc1 = (LPTESTFUNC)GetProcAddress( hLib1, szFunction );
+ if( pFunc1 == NULL )
+ {
+ Trace( "ERROR:%lu%:Unable to find \"%s\" in library \"%s\"\n",
+ GetLastError(),
+ szFunction,
+ rgchLibraryFile1 );
+ goto cleanup;
+ }
+
+ pFunc2 = (LPTESTFUNC)GetProcAddress( hLib2, szFunction );
+ if( pFunc1 == NULL )
+ {
+ Trace( "ERROR:%lu%:Unable to find \"%s\" in library \"%s\"\n",
+ GetLastError(),
+ szFunction,
+ rgchLibraryFile2 );
+ goto cleanup;
+ }
+
+ /* disable thread library calls for the first library */
+ if( ! DisableThreadLibraryCalls( (HMODULE)hLib1 ) )
+ {
+ Trace( "ERROR:%lu:DisableThreadLibraryCalls() call failed\n",
+ GetLastError() );
+ goto cleanup;
+ }
+
+ /* Execute the test function to get the attach count */
+ attachCount1a = pFunc1();
+ attachCount2a = pFunc2();
+
+ /* run another dummy thread to cause notification of the libraries */
+ hThread = CreateThread( NULL, /* no security attributes */
+ 0, /* use default stack size */
+ (LPTHREAD_START_ROUTINE) ThreadFunc, /* thread function */
+ (LPVOID) NULL, /* pass thread index as */
+ /* function argument */
+ CREATE_SUSPENDED, /* create suspended */
+ &IDThread ); /* returns thread id */
+
+ /* Check the return value for success. */
+ if( hThread == NULL )
+ {
+ /* error creating thread */
+ Trace( "ERROR:%lu:CreateThread() call failed\n",
+ GetLastError() );
+ goto cleanup;
+ }
+
+ /* Resume the suspended thread */
+ if( ResumeThread( hThread ) == -1 )
+ {
+ Trace( "ERROR:%lu:ResumeThread() call failed\n", GetLastError() );
+ goto cleanup;
+ }
+
+
+ /* wait for the thread to complete */
+ dwRet = WaitForSingleObject( hThread, INFINITE );
+ if( dwRet != WAIT_OBJECT_0 )
+ {
+ Trace( "ERROR: WaitForSingleObject returned %lu, "
+ "expected WAIT_OBJECT_0\n",
+ dwRet );
+ goto cleanup;
+ }
+
+
+ /* Execute the test function to get the new detach count */
+ attachCount1b = pFunc1();
+ attachCount2b = pFunc2();
+
+ /* validate the result */
+ if( attachCount1b != attachCount1a )
+ {
+ Trace( "FAIL: unexpected DLL attach count %d, expected %d\n",
+ attachCount1b,
+ attachCount1a );
+ goto cleanup;
+ }
+
+ /* validate the result */
+ if( attachCount2b != (attachCount2a + 1) )
+ {
+ Trace( "FAIL: unexpected DLL attach count %d, expected %d\n",
+ attachCount2b,
+ (attachCount2a + 1) );
+ goto cleanup;
+ }
+
+ bResult = PASS;
+
+cleanup:
+ /* Unload the test libraries */
+ if( !FreeLibrary( hLib1 ) )
+ {
+ Trace( "ERROR:%u:FreeLibrary() failed on library \"%s\"\n",
+ GetLastError(),
+ rgchLibraryFile1 );
+ bResult = FAIL;
+ }
+
+ if( !FreeLibrary( hLib2 ) )
+ {
+ Trace( "ERROR:%u:FreeLibrary() failed on library \"%s\"\n",
+ GetLastError(),
+ rgchLibraryFile2 );
+ bResult = FAIL;
+ }
+
+ /* check for failure */
+ if( bResult == FAIL )
+ {
+ Fail( "test failed\n" );
+ }
+
+ /* terminate the PAL */
+ PAL_Terminate();
+
+ /* return success */
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/threading/DisableThreadLibraryCalls/test2/testinfo.dat b/src/pal/tests/palsuite/threading/DisableThreadLibraryCalls/test2/testinfo.dat
new file mode 100644
index 0000000000..6d28595628
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/DisableThreadLibraryCalls/test2/testinfo.dat
@@ -0,0 +1,18 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = DisableThreadLibraryCalls
+Name = Test for DisableThreadLibraryCalls
+TYPE = DEFAULT
+EXE1 = test2
+LIB1 = dllmain1
+LIB2 = dllmain2
+Description
+= Test to ensure proper operation of the DisableThreadLibraryCalls()
+= API. This tests to make sure the DisableThreadLibraryCalls() called
+= for one DLL loaded by a process takes effect *only* for that DLL
+= and not for any others, by checking the THREAD_ATTACH notifications
+= in each.
diff --git a/src/pal/tests/palsuite/threading/DuplicateHandle/CMakeLists.txt b/src/pal/tests/palsuite/threading/DuplicateHandle/CMakeLists.txt
new file mode 100644
index 0000000000..b908c1246b
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/DuplicateHandle/CMakeLists.txt
@@ -0,0 +1,15 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test10)
+add_subdirectory(test11)
+add_subdirectory(test12)
+add_subdirectory(test2)
+add_subdirectory(test3)
+add_subdirectory(test4)
+add_subdirectory(test5)
+add_subdirectory(test6)
+add_subdirectory(test7)
+add_subdirectory(test8)
+add_subdirectory(test9)
+
diff --git a/src/pal/tests/palsuite/threading/DuplicateHandle/test1/CMakeLists.txt b/src/pal/tests/palsuite/threading/DuplicateHandle/test1/CMakeLists.txt
new file mode 100644
index 0000000000..04588b75fe
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/DuplicateHandle/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_duplicatehandle_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_duplicatehandle_test1 coreclrpal)
+
+target_link_libraries(paltest_duplicatehandle_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/DuplicateHandle/test1/test1.c b/src/pal/tests/palsuite/threading/DuplicateHandle/test1/test1.c
new file mode 100644
index 0000000000..e080e98ae8
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/DuplicateHandle/test1/test1.c
@@ -0,0 +1,152 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test1.c (DuplicateHandle)
+**
+** Purpose: Tests the PAL implementation of the DuplicateHandle function.
+** This test will create two handles to file, one to write and
+** one to read what was written. Test on a closed handle and a
+** NULL handle, both should fail.
+**
+**
+**===================================================================*/
+#include <palsuite.h>
+
+int __cdecl main(int argc, char **argv)
+{
+ HANDLE hFile;
+ HANDLE hDupFile;
+ char buf[256];
+ char teststr[] = "A uNiQuE tEsT sTrInG";
+ char lpFileName[] = "testfile.txt";
+ DWORD dwBytesWritten;
+ DWORD dwBytesRead;
+ BOOL bRetVal;
+
+ /*Initalize the PAL*/
+ if ((PAL_Initialize(argc,argv)) != 0)
+ {
+ return (FAIL);
+ }
+
+ /*Create a file handle with CreateFile*/
+ hFile = CreateFile(lpFileName,
+ GENERIC_WRITE|GENERIC_READ,
+ FILE_SHARE_WRITE|FILE_SHARE_READ,
+ NULL,
+ OPEN_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+ if (hFile == INVALID_HANDLE_VALUE)
+ {
+ Fail("ERROR: %u :unable to create file \"%s\".\n",
+ GetLastError(),
+ lpFileName);
+ }
+
+ /*Write test string to the file.*/
+ bRetVal = WriteFile(hFile, // handle to file
+ teststr, // data buffer
+ strlen(teststr), // number of bytes to write
+ &dwBytesWritten, // number of bytes written
+ NULL); // overlapped buffer
+
+ if (bRetVal == FALSE)
+ {
+ Trace("ERROR: %u : unable to write to file handle "
+ "hFile=0x%lx\n",
+ GetLastError(),
+ hFile);
+ CloseHandle(hFile);
+ Fail("");
+ }
+
+ /*Create a duplicate handle with DuplicateHandle.*/
+ if (!(DuplicateHandle(
+ GetCurrentProcess(),
+ hFile,
+ GetCurrentProcess(),
+ &hDupFile,
+ GENERIC_READ|GENERIC_WRITE,
+ FALSE,
+ DUPLICATE_SAME_ACCESS)))
+ {
+ Trace("ERROR: %u : Fail to create the duplicate handle"
+ " to hFile=0x%lx\n",
+ GetLastError(),
+ hFile);
+ CloseHandle(hFile);
+ Fail("");
+ }
+
+ memset(buf, 0, 256);
+
+ /*Read from the Duplicated handle.*/
+ bRetVal = ReadFile(hDupFile,
+ buf,
+ 256,
+ &dwBytesRead,
+ NULL);
+ if (bRetVal == FALSE)
+ {
+ Trace("ERROR: %u :unable to read from file handle "
+ "hFile=0x%lx\n",
+ GetLastError(),
+ hFile);
+ CloseHandle(hFile);
+ CloseHandle(hDupFile);
+ Fail("");
+ }
+
+ /*Compare what was written to what was read.*/
+ if (memcmp(teststr, buf, dwBytesRead) != 0)
+ {
+ Trace("ERROR: expected %s, got %s\n", teststr, buf);
+ CloseHandle(hFile);
+ CloseHandle(hDupFile);
+ Fail("");
+ }
+
+ /*Close the handles*/
+ CloseHandle(hFile);
+ CloseHandle(hDupFile);
+
+ /*Failure test: Create DuplicateHandle to a closed handle*/
+ if ((DuplicateHandle(
+ GetCurrentProcess(),
+ hFile,
+ GetCurrentProcess(),
+ &hDupFile,
+ GENERIC_READ|GENERIC_WRITE,
+ FALSE,
+ DUPLICATE_SAME_ACCESS)))
+ {
+ Fail("ERROR: %u :Created a duplicate handle to"
+ " a closed handle hFile=0x%lx\n",
+ GetLastError(),
+ hFile);
+ }
+
+ /*Failure test: Create DuplicateHandle to a NULL handle*/
+ hFile = NULL;
+ if ((DuplicateHandle(
+ GetCurrentProcess(),
+ hFile,
+ GetCurrentProcess(),
+ &hDupFile,
+ GENERIC_READ|GENERIC_WRITE,
+ FALSE,
+ DUPLICATE_SAME_ACCESS)))
+ {
+ Fail("ERROR: %u :Created a duplicate handle to "
+ " a NULL handle hFile=0x%lx\n",
+ GetLastError(),
+ hFile);
+ }
+
+ PAL_Terminate();
+ return (PASS);
+}
diff --git a/src/pal/tests/palsuite/threading/DuplicateHandle/test1/testinfo.dat b/src/pal/tests/palsuite/threading/DuplicateHandle/test1/testinfo.dat
new file mode 100644
index 0000000000..e22b0bea6a
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/DuplicateHandle/test1/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Threading
+Function = DuplicateHandle
+Name = Positive Test for DuplicateHandle
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Tests the PAL implementation of the DuplicateHandle function.
+= This test will create two handles to file, one to write and
+= one to read what was written. Test on a closed handle and a
+= NULL handle, both should fail.
diff --git a/src/pal/tests/palsuite/threading/DuplicateHandle/test10/CMakeLists.txt b/src/pal/tests/palsuite/threading/DuplicateHandle/test10/CMakeLists.txt
new file mode 100644
index 0000000000..ba16252cb4
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/DuplicateHandle/test10/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test10.c
+)
+
+add_executable(paltest_duplicatehandle_test10
+ ${SOURCES}
+)
+
+add_dependencies(paltest_duplicatehandle_test10 coreclrpal)
+
+target_link_libraries(paltest_duplicatehandle_test10
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/DuplicateHandle/test10/test10.c b/src/pal/tests/palsuite/threading/DuplicateHandle/test10/test10.c
new file mode 100644
index 0000000000..108d748de6
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/DuplicateHandle/test10/test10.c
@@ -0,0 +1,239 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test10.c (DuplicateHandle)
+**
+** Purpose: Tests the PAL implementation of the DuplicateHandle function.
+** This tests the operation of a duplicated Semaphore handle
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+enum wait_results
+{
+ WR_WAITING,
+ WR_GOT_MUTEX,
+ WR_TIMED_OUT,
+ WR_RELEASED
+};
+
+
+volatile int t1_result=WR_WAITING;
+volatile int t2_result=WR_WAITING;
+
+
+DWORD PALAPI ThreadTest1(LPVOID lpParam)
+{
+ DWORD dwWait;
+
+ dwWait = WaitForSingleObject((HANDLE)lpParam, 0);
+ if (dwWait == WAIT_OBJECT_0)
+ {
+ /* tell the main thread we got the mutex */
+ t1_result=WR_GOT_MUTEX;
+
+ /* wait for main thread to tell us to release the mutex */
+ while(WR_GOT_MUTEX == t1_result)
+ Sleep(1);
+ ReleaseSemaphore((HANDLE)lpParam, 1, NULL);
+
+ /* tell the main thread we released the mutex */
+ t1_result = WR_RELEASED;
+ }
+ else
+ {
+ t1_result = WR_TIMED_OUT;
+ }
+ return 0;
+}
+
+DWORD PALAPI ThreadTest2(LPVOID lpParam)
+{
+ DWORD dwWait;
+
+ dwWait = WaitForSingleObject((HANDLE)lpParam, 0 );
+ if (dwWait == WAIT_OBJECT_0)
+ {
+ ReleaseSemaphore((HANDLE)lpParam, 1, NULL);
+ t2_result = WR_GOT_MUTEX;
+ }
+ else
+ {
+ t2_result = WR_TIMED_OUT;
+ }
+
+ return 0;
+}
+
+
+int __cdecl main(int argc, char **argv)
+{
+
+ HANDLE hDupSemaphore;
+ HANDLE hSemaphore;
+ HANDLE hThread;
+ HANDLE hThread2;
+ BOOL bDupHandle=FALSE;
+ DWORD dwThreadId = 0;
+
+ if ((PAL_Initialize(argc,argv)) != 0)
+ {
+ return(FAIL);
+ }
+
+ hSemaphore = CreateSemaphoreW( NULL,
+ 1,
+ 1,
+ NULL);
+ if (hSemaphore == NULL)
+ {
+ Fail("PALSUITE ERROR:%u: Unable to create mutex\n",
+ GetLastError());
+ }
+
+ /*Create Duplicate of the Semaphore above*/
+ bDupHandle = DuplicateHandle(GetCurrentProcess(),
+ hSemaphore,
+ GetCurrentProcess(),
+ &hDupSemaphore,
+ GENERIC_READ|GENERIC_WRITE,
+ FALSE,
+ DUPLICATE_SAME_ACCESS);
+ if (!bDupHandle)
+ {
+ Trace("PALSUITE ERROR:%u: Created the duplicate handle to "
+ "closed event handle hSemaphore=0x%lx\n",
+ GetLastError(),
+ hSemaphore);
+ CloseHandle(hSemaphore);
+ Fail("");
+ }
+
+ /*Create a thread to test the Semaphore*/
+ hThread = CreateThread(NULL,
+ 0,
+ &ThreadTest1,
+ hSemaphore,
+ 0,
+ &dwThreadId);
+ if (hThread == NULL)
+ {
+ Trace("PALSUITE ERROR:%u: unable to create thread\n",
+ GetLastError());
+ CloseHandle(hSemaphore);
+ CloseHandle(hDupSemaphore);
+ Fail("");
+ }
+
+ /* wait until thread has taken the mutex */
+ while (WR_WAITING == t1_result)
+ Sleep(1);
+
+ if(WR_TIMED_OUT == t1_result)
+ {
+ Trace("PALSUITE ERROR: %u: thread couldn't acquire the semaphore\n",
+ GetLastError());
+ CloseHandle(hSemaphore);
+ CloseHandle(hDupSemaphore);
+ CloseHandle(hThread);
+ Fail("");
+ }
+
+ /*Create a second thread to use the Semaphore's duplicate handle*/
+ /*This thread should block since the Semaphore is owned by another
+ thread*/
+ hThread2 = CreateThread(NULL,
+ 0,
+ &ThreadTest2,
+ hDupSemaphore,
+ 0,
+ &dwThreadId);
+
+ if (hThread2 == NULL)
+ {
+ Trace("PALSUITE ERROR:%u: unable to create thread\n",
+ GetLastError());
+ CloseHandle(hSemaphore);
+ CloseHandle(hDupSemaphore);
+ CloseHandle(hThread);
+ Fail("");
+ }
+
+ /* wait until thread has tried to take the mutex */
+ while (WR_WAITING == t2_result)
+ Sleep(1);
+
+ if (WR_TIMED_OUT != t2_result )
+ {
+ Trace("PALSUITE ERROR:%u: Able to take mutex %#x while its "
+ "duplicate %#x is held\n", GetLastError(), hDupSemaphore,
+ hSemaphore);
+ CloseHandle(hSemaphore);
+ CloseHandle(hDupSemaphore);
+ CloseHandle(hThread);
+ CloseHandle(hThread2);
+ Fail("");
+ }
+
+ /* reset second thread status */
+ t2_result = WR_WAITING;
+
+ /* tell thread 1 to release the mutex */
+ t1_result = WR_WAITING;
+
+ /* wait for thread 1 to release the mutex */
+ while (WR_WAITING == t1_result)
+ Sleep(1);
+
+ CloseHandle(hThread2);
+
+ /*Re-Create the second thread to reuse the duplicated Semaphore*/
+ /*Since the Semaphore has since been released, the thread should
+ put WR_GOT_MUTEX into t2_result */
+ hThread2 = CreateThread(NULL,
+ 0,
+ &ThreadTest2,
+ hDupSemaphore,
+ 0,
+ &dwThreadId);
+
+ if (hThread2 == NULL)
+ {
+ Trace("PALSUITE ERROR:%u: unable to create thread\n",
+ GetLastError());
+ CloseHandle(hSemaphore);
+ CloseHandle(hDupSemaphore);
+ CloseHandle(hThread);
+ Fail("");
+ }
+
+ /* wait until thread has taken the semaphore */
+ while (WR_WAITING == t2_result)
+ Sleep(1);
+
+ if (WR_GOT_MUTEX != t2_result )
+ {
+ Trace("PALSUITE ERROR:%u: Unable to take semaphore %#x after its"
+ " duplicate %#x was released\n", GetLastError(), hDupSemaphore,
+ hSemaphore);
+ CloseHandle(hSemaphore);
+ CloseHandle(hDupSemaphore);
+ CloseHandle(hThread);
+ CloseHandle(hThread2);
+ Fail("");
+ }
+
+ /*Cleanup.*/
+ CloseHandle(hSemaphore);
+ CloseHandle(hDupSemaphore);
+ CloseHandle(hThread);
+ CloseHandle(hThread2);
+
+ PAL_Terminate();
+ return (PASS);
+}
diff --git a/src/pal/tests/palsuite/threading/DuplicateHandle/test10/testinfo.dat b/src/pal/tests/palsuite/threading/DuplicateHandle/test10/testinfo.dat
new file mode 100644
index 0000000000..674c71c2b3
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/DuplicateHandle/test10/testinfo.dat
@@ -0,0 +1,17 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Threading
+Function = DuplicateHandle
+Name = Test for DuplicateHandle (CreateSemaphore)
+TYPE = DEFAULT
+EXE1 = test10
+Description
+= Tests the PAL implementation of the DuplicateHandle function.
+= This test duplication of a Semaphore handle. The test will
+= create a Semaphore and duplicate a handle to it.
+= Then two subthreads will be used to verify that they can selectively
+= block each other with different handles that refer to the
+= same Semaphore
diff --git a/src/pal/tests/palsuite/threading/DuplicateHandle/test11/CMakeLists.txt b/src/pal/tests/palsuite/threading/DuplicateHandle/test11/CMakeLists.txt
new file mode 100644
index 0000000000..68ce7b23fb
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/DuplicateHandle/test11/CMakeLists.txt
@@ -0,0 +1,36 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(TESTSOURCES
+ test11.c
+)
+
+add_executable(paltest_duplicatehandle_test11
+ ${TESTSOURCES}
+)
+
+add_dependencies(paltest_duplicatehandle_test11 coreclrpal)
+
+target_link_libraries(paltest_duplicatehandle_test11
+ pthread
+ m
+ coreclrpal
+)
+
+
+set(HELPERSOURCES
+ childprocess.c
+)
+
+add_executable(paltest_duplicatehandle_test11_child
+ ${HELPERSOURCES}
+)
+
+add_dependencies(paltest_duplicatehandle_test11_child coreclrpal)
+
+target_link_libraries(paltest_duplicatehandle_test11_child
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/DuplicateHandle/test11/childprocess.c b/src/pal/tests/palsuite/threading/DuplicateHandle/test11/childprocess.c
new file mode 100644
index 0000000000..d5b310e46c
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/DuplicateHandle/test11/childprocess.c
@@ -0,0 +1,74 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: childprocess.c
+**
+** Purpose: Test to ensure DuplicateHandle works properly.
+**
+** Dependencies: PAL_Initialize
+** PAL_Terminate
+** CreateMutexW
+** WaitForSingleObject
+** CloseHandle
+**
+**
+**=========================================================*/
+
+#include <palsuite.h>
+#include "myexitcode.h"
+
+
+int __cdecl main( int argc, char **argv )
+{
+ HANDLE hMutex;
+ WCHAR wszMutexName[] = { 'T','E','S','T','1','1','\0' };
+ DWORD dwRet;
+ int i;
+
+ /* initialize the PAL */
+ if( PAL_Initialize(argc, argv) != 0 )
+ {
+ return( FAIL );
+ }
+
+ /* open a mutex to synchronize with the parent process */
+ hMutex = CreateMutexW( NULL, FALSE, wszMutexName );
+ if( hMutex == NULL )
+ {
+ Fail( "ERROR:%lu:CreateMutex() call failed\r\n", GetLastError() );
+ }
+
+ /* acquire the mutex lock */
+ dwRet = WaitForSingleObject( hMutex, 10000 );
+ if( dwRet != WAIT_OBJECT_0 )
+ {
+ Trace( "ERROR:WaitForSingleObject() returned %lu, "
+ "expected WAIT_OBJECT_0",
+ dwRet );
+ if( ! CloseHandle( hMutex ) )
+ {
+ Trace( "ERROR:%lu:CloseHandle() call failed\n", GetLastError() );
+ }
+ Fail( "test failed\n" );
+ }
+
+
+ /* simulate some activity */
+ for( i=0; i<50000; i++ )
+ ;
+
+ /* close our mutex handle */
+ if( ! CloseHandle( hMutex ) )
+ {
+ Fail( "ERROR:%lu:CloseHandle() call failed\n", GetLastError() );
+ }
+
+ /* terminate the PAL */
+ PAL_Terminate();
+
+ /* return the predefined exit code */
+ return TEST_EXIT_CODE;
+}
diff --git a/src/pal/tests/palsuite/threading/DuplicateHandle/test11/myexitcode.h b/src/pal/tests/palsuite/threading/DuplicateHandle/test11/myexitcode.h
new file mode 100644
index 0000000000..84801cbb54
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/DuplicateHandle/test11/myexitcode.h
@@ -0,0 +1,13 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: duplicatehandle/test11/myexitcode.h
+**
+** Purpose: Define an exit code constant.
+**
+**
+**=========================================================*/
+#define TEST_EXIT_CODE 31
diff --git a/src/pal/tests/palsuite/threading/DuplicateHandle/test11/test11.c b/src/pal/tests/palsuite/threading/DuplicateHandle/test11/test11.c
new file mode 100644
index 0000000000..b05244c4b8
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/DuplicateHandle/test11/test11.c
@@ -0,0 +1,364 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================================
+**
+** Source: test11.c
+**
+** Purpose:
+**
+** Test to ensure proper operation of the DuplicateHandle API.
+** The test launches a trivial child process, then opens
+** a handle to it using OpenProcess. It then duplicates that
+** handle and uses it to wait for the child process to terminate,
+** and then checks the exit code of the child process in order to
+** verify that it was in fact a handle to the correct
+** process. The test tries to duplicate the handle again after
+** the process has been closed, to verify that failure ensues.
+**
+** Dependencies: PAL_Initialize
+** PAL_Terminate
+** Fail
+** ZeroMemory
+** GetCurrentDirectoryW
+** CreateProcessW
+** WaitForSingleObject
+** CreateMutexW
+** ReleaseMutex
+** CloseHandle
+** GetLastError
+** strlen
+** strncpy
+**
+**
+**===========================================================================*/
+#include <palsuite.h>
+#include "myexitcode.h"
+
+
+static const char* rgchPathDelim = "\\";
+
+
+int
+mkAbsoluteFilename( LPSTR dirName,
+ DWORD dwDirLength,
+ LPCSTR fileName,
+ DWORD dwFileLength,
+ LPSTR absPathName )
+{
+ DWORD sizeDN, sizeFN, sizeAPN;
+
+ sizeDN = strlen( dirName );
+ sizeFN = strlen( fileName );
+ sizeAPN = (sizeDN + 1 + sizeFN + 1);
+
+ /* ensure ((dirName + DELIM + fileName + \0) =< _MAX_PATH ) */
+ if( sizeAPN > _MAX_PATH )
+ {
+ return ( 0 );
+ }
+
+ strncpy( absPathName, dirName, dwDirLength +1 );
+ strncpy( absPathName, rgchPathDelim, 2 );
+ strncpy( absPathName, fileName, dwFileLength +1 );
+
+ return (sizeAPN);
+
+}
+
+
+int __cdecl main( int argc, char **argv )
+
+{
+ const char* rgchChildFile = "childprocess";
+
+ STARTUPINFO si;
+ PROCESS_INFORMATION pi;
+
+ DWORD dwError;
+ DWORD dwExitCode;
+ DWORD dwFileLength;
+ DWORD dwDirLength;
+ DWORD dwSize;
+ DWORD dwRet;
+
+ HANDLE hMutex;
+ HANDLE hChildProcess;
+ HANDLE hDupChildProcess;
+
+ char rgchDirName[_MAX_DIR];
+ char absPathBuf[_MAX_PATH];
+ char* rgchAbsPathName;
+
+ BOOL ret = FAIL;
+ BOOL bChildDone = FALSE;
+ WCHAR wszMutexName[] = { 'T','E','S','T','1','1','\0' };
+
+ /* initialize the PAL */
+ if( PAL_Initialize(argc, argv) != 0 )
+ {
+ return( FAIL );
+ }
+
+ /* create a mutex to synchronize with the child process */
+ hMutex = CreateMutexW( NULL, TRUE, wszMutexName );
+ if( hMutex == NULL )
+ {
+ Fail( "ERROR:%lu:CreateMutex() call failed\r\n", GetLastError() );
+ }
+
+ /* zero our process and startup info structures */
+ ZeroMemory( &si, sizeof(si) );
+ si.cb = sizeof( si );
+ ZeroMemory( &pi, sizeof(pi) );
+
+ /* build the absolute path to the child process */
+ rgchAbsPathName = &absPathBuf[0];
+ dwFileLength = strlen( rgchChildFile );
+
+ dwDirLength = GetCurrentDirectory( _MAX_PATH, rgchDirName );
+ if( dwDirLength == 0 )
+ {
+ dwError = GetLastError();
+ if( ReleaseMutex( hMutex ) == 0 )
+ {
+ Trace( "ERROR:%lu:ReleaseMutex() call failed\n", GetLastError() );
+ }
+ if( CloseHandle( hMutex ) == 0 )
+ {
+ Trace( "ERROR:%lu:CloseHandle() call failed\n", GetLastError() );
+ }
+ Fail( "GetCurrentDirectory call failed with error code %d\n",
+ dwError );
+ }
+
+ dwSize = mkAbsoluteFilename( rgchDirName,
+ dwDirLength,
+ rgchChildFile,
+ dwFileLength,
+ rgchAbsPathName );
+ if( dwSize == 0 )
+ {
+ if( ReleaseMutex( hMutex ) == 0 )
+ {
+ Trace( "ERROR:%lu:ReleaseMutex() call failed\n", GetLastError() );
+ }
+ if( CloseHandle( hMutex ) == 0 )
+ {
+ Trace( "ERROR:%lu:CloseHandle() call failed\n", GetLastError() );
+ }
+ Fail( "Palsuite Code: mkAbsoluteFilename() call failed. Could ",
+ "not build absolute path name to file\n. Exiting.\n" );
+ }
+
+ /* launch the child process */
+ if( !CreateProcess( NULL, /* module name to execute */
+ rgchAbsPathName, /* command line */
+ NULL, /* process handle not */
+ /* inheritable */
+ NULL, /* thread handle not */
+ /*inheritable */
+ FALSE, /* handle inheritance */
+ CREATE_NEW_CONSOLE, /* dwCreationFlags */
+ NULL, /* use parent's environment */
+ NULL, /* use parent's starting */
+ /* directory */
+ &si, /* startup info struct */
+ &pi ) /* process info struct */
+ )
+ {
+ dwError = GetLastError();
+ if( ReleaseMutex( hMutex ) == 0 )
+ {
+ Trace( "ERROR:%lu:ReleaseMutex() call failed\n", GetLastError() );
+ }
+ if( CloseHandle( hMutex ) == 0 )
+ {
+ Trace( "ERROR:%lu:CloseHandle() call failed\n", GetLastError() );
+ }
+ Fail( "CreateProcess call failed with error code %d\n",
+ dwError );
+ }
+
+ /* open another handle to the child process */
+ hChildProcess = OpenProcess( PROCESS_ALL_ACCESS, /* access */
+ FALSE, /* inheritable */
+ pi.dwProcessId /* process id */
+ );
+ if( hChildProcess == NULL )
+ {
+ dwError = GetLastError();
+ if( ReleaseMutex( hMutex ) == 0 )
+ {
+ Trace( "ERROR:%lu:ReleaseMutex() call failed\n", GetLastError() );
+ }
+ Trace( "ERROR:%lu:OpenProcess call failed\n", dwError );
+ goto cleanup3;
+ }
+
+ /* duplicate the child process handle */
+ if( ! DuplicateHandle( GetCurrentProcess(),
+ hChildProcess,
+ GetCurrentProcess(),
+ &hDupChildProcess,
+ GENERIC_READ|GENERIC_WRITE,
+ FALSE,
+ DUPLICATE_SAME_ACCESS) )
+ {
+ Trace( "ERROR:%lu:DuplicateHandle() call failed\n", GetLastError() );
+ if( ReleaseMutex( hMutex ) == 0 )
+ {
+ Trace( "ERROR:%lu:ReleaseMutex() call failed\n", GetLastError() );
+ }
+ goto cleanup2;
+ }
+
+ /* release the mutex so the child can proceed */
+ if( ReleaseMutex( hMutex ) == 0 )
+ {
+ Trace( "ERROR:%lu:ReleaseMutex() call failed\n", GetLastError() );
+ goto cleanup1;
+ }
+
+ /* wait for the child process to complete, using the new handle */
+ dwRet = WaitForSingleObject( hDupChildProcess, 10000 );
+ if( dwRet != WAIT_OBJECT_0 )
+ {
+ Trace( "ERROR:WaitForSingleObject call returned %lu, "
+ "expected WAIT_OBJECT_0",
+ dwRet );
+ goto cleanup1;
+ }
+
+ /* remember that we waited until the child was finished */
+ bChildDone = TRUE;
+
+ /* check the exit code from the process -- this is a bit of an */
+ /* extra verification that we opened the correct process handle */
+ if( ! GetExitCodeProcess( hDupChildProcess, &dwExitCode ) )
+ {
+ Trace( "ERROR:%lu:GetExitCodeProcess call failed\n", GetLastError() );
+ goto cleanup1;
+ }
+
+ /* verification */
+ if( (dwExitCode & 0xFF) != (TEST_EXIT_CODE & 0xFF) )
+ {
+ Trace( "GetExitCodeProcess returned an incorrect exit code %d, "
+ "expected value is %d\n",
+ (dwExitCode & 0xFF),
+ (TEST_EXIT_CODE & 0xFF));
+ goto cleanup1;
+ }
+
+ /* close the duplicate handle */
+ if( ! CloseHandle( hDupChildProcess ) )
+ {
+ Trace( "ERROR:%lu:CloseHandle call failed\n", GetLastError() );
+ goto cleanup2;
+ }
+
+ /* close the child process handle */
+ if( ! CloseHandle ( hChildProcess ) )
+ {
+ Trace( "ERROR:%lu:CloseHandle() call failed\n", GetLastError() );
+ goto cleanup3;
+ }
+
+ /* try to call duplicate handle on the closed child process handle */
+ if( DuplicateHandle( GetCurrentProcess(),
+ hChildProcess,
+ GetCurrentProcess(),
+ &hDupChildProcess,
+ GENERIC_READ|GENERIC_WRITE,
+ FALSE,
+ DUPLICATE_SAME_ACCESS) )
+ {
+ Trace( "ERROR:%lu:DuplicateHandle call succeeded on "
+ "a closed process handle, expected ERROR_INVALID_HANDLE\n" );
+ if( ! CloseHandle( hDupChildProcess ) )
+ {
+ Trace( "ERROR:%lu:CloseHandle call failed\n", GetLastError() );
+ }
+ goto cleanup3;
+ }
+
+ /* verify that the last error was ERROR_INVALID_HANDLE */
+ dwRet = GetLastError();
+ if( dwRet != ERROR_INVALID_HANDLE )
+ {
+ Trace( "ERROR:DuplicateHandle returned %lu, "
+ "expected ERROR_INVALID_HANDLE\n",
+ dwRet );
+ goto cleanup3;
+ }
+
+
+ /* success if we get here */
+ ret = PASS;
+
+ /* skip the cleanup stuff that's already done */
+ goto cleanup3;
+
+
+cleanup1:
+ /* close our duplicate handle */
+ if( ! CloseHandle( hDupChildProcess ) )
+ {
+ Trace( "ERROR:%lu:CloseHandle call failed\n", GetLastError() );
+ ret = FAIL;
+ }
+
+cleanup2:
+ /* wait on the child process to complete if necessary */
+ if( ! bChildDone )
+ {
+ dwRet = WaitForSingleObject( hChildProcess, 10000 );
+ if( dwRet != WAIT_OBJECT_0 )
+ {
+ Trace( "ERROR:WaitForSingleObject call returned %lu, "
+ "expected WAIT_OBJECT_0",
+ dwRet );
+ ret = FAIL;
+ }
+ }
+
+ /* close our child process handle */
+ if( CloseHandle ( hChildProcess ) == 0 )
+ {
+ Trace( "ERROR:%lu:CloseHandle() call failed\n", GetLastError() );
+ ret = FAIL;
+ }
+
+cleanup3:
+ /* close all our other handles */
+ if( CloseHandle ( pi.hProcess ) == 0 )
+ {
+ Trace( "ERROR:%lu:CloseHandle() call failed\n", GetLastError() );
+ ret = FAIL;
+ }
+ if( CloseHandle ( pi.hThread ) == 0 )
+ {
+ Trace( "ERROR:%lu:CloseHandle() call failed\n", GetLastError() );
+ ret = FAIL;
+ }
+ if( CloseHandle( hMutex ) == 0 )
+ {
+ Trace( "ERROR:%lu:CloseHandle() call failed\n", GetLastError() );
+ ret = FAIL;
+ }
+
+ if( ret == FAIL )
+ {
+ Fail( "test failed\n" );
+ }
+
+
+
+ /* terminate the PAL */
+ PAL_Terminate();
+
+ /* return success */
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/threading/DuplicateHandle/test11/testinfo.dat b/src/pal/tests/palsuite/threading/DuplicateHandle/test11/testinfo.dat
new file mode 100644
index 0000000000..1937877880
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/DuplicateHandle/test11/testinfo.dat
@@ -0,0 +1,19 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = DuplicateHandle
+Name = Test for DuplicateHandle
+TYPE = DEFAULT
+EXE1 = test11
+EXE2 = childprocess
+Description
+= Test to ensure proper operation of the DuplicateHandle API.
+= The test launches a trivial child process, then opens
+= a handle to it using OpenProcess. It then duplicates that
+= handle and uses it to wait for the child process to terminate,
+= and then checks the exit code of the child process in order to
+= verify that it was in fact a handle to the correct= process. The test tries to duplicate the handle again after
+= the process has been closed, to verify that failure ensues.
diff --git a/src/pal/tests/palsuite/threading/DuplicateHandle/test12/CMakeLists.txt b/src/pal/tests/palsuite/threading/DuplicateHandle/test12/CMakeLists.txt
new file mode 100644
index 0000000000..961a9c64e6
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/DuplicateHandle/test12/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test12.c
+)
+
+add_executable(paltest_duplicatehandle_test12
+ ${SOURCES}
+)
+
+add_dependencies(paltest_duplicatehandle_test12 coreclrpal)
+
+target_link_libraries(paltest_duplicatehandle_test12
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/DuplicateHandle/test12/test12.c b/src/pal/tests/palsuite/threading/DuplicateHandle/test12/test12.c
new file mode 100644
index 0000000000..519194bc3a
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/DuplicateHandle/test12/test12.c
@@ -0,0 +1,129 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test12.c (DuplicateHandle)
+**
+** Purpose: Tests the PAL implementation of the DuplicateHandle function.
+** This test will create handle to file (to write) and close it,
+** then call duplicate handle to read what was written.
+**
+**
+**===================================================================*/
+#include <palsuite.h>
+
+int __cdecl main(int argc, char **argv)
+{
+ HANDLE hFile;
+ HANDLE hDupFile;
+ char buf[256];
+ char teststr[] = "A uNiQuE tEsT sTrInG";
+ char lpFileName[] = "testfile.txt";
+ DWORD dwBytesWritten;
+ DWORD dwBytesRead;
+ BOOL bRetVal;
+
+ /*Initalize the PAL*/
+ if ((PAL_Initialize(argc,argv)) != 0)
+ {
+ return (FAIL);
+ }
+
+ /*Create a file handle with CreateFile*/
+ hFile = CreateFile(lpFileName,
+ GENERIC_WRITE|GENERIC_READ,
+ FILE_SHARE_WRITE|FILE_SHARE_READ,
+ NULL,
+ OPEN_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+ if (hFile == INVALID_HANDLE_VALUE)
+ {
+ Fail("ERROR: %u :unable to create file \"%s\".\n",
+ GetLastError(),
+ lpFileName);
+ }
+
+ /*Write test string to the file.*/
+ bRetVal = WriteFile(hFile, // handle to file
+ teststr, // data buffer
+ strlen(teststr), // number of bytes to write
+ &dwBytesWritten, // number of bytes written
+ NULL); // overlapped buffer
+
+ if (bRetVal == FALSE)
+ {
+ Trace("ERROR: %u : unable to write to file handle "
+ "hFile=0x%lx\n",
+ GetLastError(),
+ hFile);
+ CloseHandle(hFile);
+ Fail("");
+ }
+
+ /*Create a duplicate handle with DuplicateHandle.*/
+ if (!(DuplicateHandle(
+ GetCurrentProcess(),
+ hFile,
+ GetCurrentProcess(),
+ &hDupFile,
+ GENERIC_READ|GENERIC_WRITE,
+ FALSE,
+ DUPLICATE_SAME_ACCESS)))
+ {
+ Trace("ERROR: %u : Fail to create the duplicate handle"
+ " to hFile=0x%lx\n",
+ GetLastError(),
+ hFile);
+ CloseHandle(hFile);
+ Fail("");
+ }
+
+ if( !CloseHandle(hFile) )
+ {
+ Fail("Duplicate Handle:Unable to close original file: Error[%u]\n", GetLastError());
+ }
+
+ memset(buf, 0, 256);
+
+ /*Read from the Duplicated handle.*/
+ bRetVal = ReadFile(hDupFile,
+ buf,
+ 256,
+ &dwBytesRead,
+ NULL);
+ if (bRetVal == FALSE)
+ {
+ Trace("ERROR: %u :unable to read from file handle "
+ "hFile=0x%lx\n",
+ GetLastError(),
+ hDupFile);
+ CloseHandle(hDupFile);
+ Fail("");
+ }
+
+ /*Compare what was written to what was read.*/
+ if (memcmp(teststr, buf, dwBytesRead) != 0)
+ {
+ Trace("ERROR: expected %s, got %s\n", teststr, buf);
+ CloseHandle(hDupFile);
+ Fail("");
+ }
+
+ /*Close the handles*/
+ CloseHandle(hDupFile);
+
+ bRetVal = DeleteFileA(lpFileName);
+ if (bRetVal != TRUE)
+ {
+ Trace("Error:%u: DuplicateHandle, DeleteFileA: Couldn't delete DeleteFileA's"
+ " %s\n", GetLastError(), lpFileName);
+ Fail("");
+ }
+
+
+ PAL_Terminate();
+ return (PASS);
+}
diff --git a/src/pal/tests/palsuite/threading/DuplicateHandle/test12/testinfo.dat b/src/pal/tests/palsuite/threading/DuplicateHandle/test12/testinfo.dat
new file mode 100644
index 0000000000..3d73362eb3
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/DuplicateHandle/test12/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Threading
+Function = DuplicateHandle
+Name = Positive Test for DuplicateHandle
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Tests the PAL implementation of the DuplicateHandle function.
+= This test will create handle to file (to write),
+= then call duplicate handle, and close the original handle
+= and then use duplicated handle to read what was written.
diff --git a/src/pal/tests/palsuite/threading/DuplicateHandle/test2/CMakeLists.txt b/src/pal/tests/palsuite/threading/DuplicateHandle/test2/CMakeLists.txt
new file mode 100644
index 0000000000..06529a6204
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/DuplicateHandle/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test2.c
+)
+
+add_executable(paltest_duplicatehandle_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_duplicatehandle_test2 coreclrpal)
+
+target_link_libraries(paltest_duplicatehandle_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/DuplicateHandle/test2/test2.c b/src/pal/tests/palsuite/threading/DuplicateHandle/test2/test2.c
new file mode 100644
index 0000000000..d1411e62d9
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/DuplicateHandle/test2/test2.c
@@ -0,0 +1,96 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test2.c (DuplicateHandle)
+**
+** Purpose: Tests the PAL implementation of the DuplicateHandle function.
+** This will test duplication of an CreateEvent handle. Test an
+** event in a signaled state to wait, and then set the duplicate
+** to nonsignaled state and perform the wait again. The wait on
+** the event should fail. Test the duplication of closed and NULL
+** events, these should fail.
+**
+**
+**===================================================================*/
+#include <palsuite.h>
+
+int __cdecl main(int argc, char **argv)
+{
+ HANDLE hEvent;
+ HANDLE hDupEvent;
+
+ /*Initalize the PAL.*/
+ if ((PAL_Initialize(argc,argv)) != 0)
+ {
+ return (FAIL);
+ }
+
+ /*Create an Event, and set it in the signaled state.*/
+ hEvent = CreateEvent(0, TRUE, TRUE, 0);
+ if (hEvent == NULL)
+ {
+ Fail("ERROR: %u :unable to create event\n",
+ GetLastError());
+ }
+
+ /*Create a duplicate Event handle.*/
+ if (!(DuplicateHandle(GetCurrentProcess(),
+ hEvent,GetCurrentProcess(),
+ &hDupEvent,
+ GENERIC_READ|GENERIC_WRITE,
+ FALSE, DUPLICATE_SAME_ACCESS)))
+ {
+ Trace("ERROR: %u :Fail to create the duplicate handle"
+ " to hEvent=0x%lx\n",
+ GetLastError(),
+ hEvent);
+ CloseHandle(hEvent);
+ Fail("");
+ }
+
+ /*Perform wait on Event that is in signaled state.*/
+ if ((WaitForSingleObject(hEvent, 1000)) != WAIT_OBJECT_0)
+ {
+ Trace("ERROR: %u :WaitForSignalObject on Event=0x%lx set to "
+ " signaled state failed",
+ GetLastError(),
+ hEvent);
+ CloseHandle(hEvent);
+ CloseHandle(hDupEvent);
+ Fail("");
+ }
+
+ /*Set the Duplicate Event handle to nonsignaled state.*/
+ if ((ResetEvent(hDupEvent)) == 0)
+ {
+ Trace("ERROR: %u :unable to reset dup event\n",
+ GetLastError());
+ CloseHandle(hEvent);
+ CloseHandle(hDupEvent);
+ Fail("");
+ }
+
+ /*Perform wait on Event that is in signaled state.*/
+ if ((WaitForSingleObject(hEvent, 1000)) == WAIT_OBJECT_0)
+ {
+ Trace("ERROR: %u: WaitForSignalObject succeeded on Event=0x%lx "
+ " when Duplicate Event=0x%lx set to nonsignaled state"
+ " succeeded\n",
+ GetLastError(),
+ hEvent,
+ hDupEvent);
+ CloseHandle(hEvent);
+ CloseHandle(hDupEvent);
+ Fail("");
+ }
+
+ /*Close handles to events.*/
+ CloseHandle(hEvent);
+ CloseHandle(hDupEvent);
+
+ PAL_Terminate();
+ return (PASS);
+}
diff --git a/src/pal/tests/palsuite/threading/DuplicateHandle/test2/testinfo.dat b/src/pal/tests/palsuite/threading/DuplicateHandle/test2/testinfo.dat
new file mode 100644
index 0000000000..273440804e
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/DuplicateHandle/test2/testinfo.dat
@@ -0,0 +1,17 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Threading
+Function = DuplicateHandle
+Name = Test for DuplicateHandle
+TYPE = DEFAULT
+EXE1 = test2
+Description
+= Tests the PAL implementation of the DuplicateHandle function.
+= This will test duplication of an CreateEvent handle. Test an
+= event in a signaled state to wait, and then set the duplicate
+= to nonsignaled state and perform the wait again. The wait on
+= the event should fail. Test the duplication of closed and NULL
+= events, these should fail.
diff --git a/src/pal/tests/palsuite/threading/DuplicateHandle/test3/CMakeLists.txt b/src/pal/tests/palsuite/threading/DuplicateHandle/test3/CMakeLists.txt
new file mode 100644
index 0000000000..7f961c2213
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/DuplicateHandle/test3/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test3.c
+)
+
+add_executable(paltest_duplicatehandle_test3
+ ${SOURCES}
+)
+
+add_dependencies(paltest_duplicatehandle_test3 coreclrpal)
+
+target_link_libraries(paltest_duplicatehandle_test3
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/DuplicateHandle/test3/test3.c b/src/pal/tests/palsuite/threading/DuplicateHandle/test3/test3.c
new file mode 100644
index 0000000000..fc91b5ec22
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/DuplicateHandle/test3/test3.c
@@ -0,0 +1,123 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test3.c (DuplicateHandle)
+**
+** Purpose: Tests the PAL implementation of the DuplicateHandle function.
+** This will test duplication of an OpenEvent handle. Test an
+** event in a signaled state to wait, and then set the duplicate
+** to nonsignaled state and perform the wait again. The wait on
+** the event should fail. Test the duplication of closed and NULL
+** events, these should fail.
+**
+**
+**===================================================================*/
+#include <palsuite.h>
+
+int __cdecl main(int argc, char **argv)
+{
+ HANDLE hCreateEvent;
+ HANDLE hOpenEvent;
+ HANDLE hDupEvent;
+ WCHAR lpEventName[]={'E','v','e','n','t','\0'};
+
+ /*Initialize the PAL.*/
+ if ((PAL_Initialize(argc,argv)) != 0)
+ {
+ return (FAIL);
+ }
+
+ /*Create an Event, and set it in the signaled state.*/
+ hCreateEvent = CreateEventW(0,
+ TRUE,
+ TRUE,
+ lpEventName);
+ if (hCreateEvent == NULL)
+ {
+ Fail("ERROR: %u :unable to create event %s\n",
+ GetLastError(),
+ lpEventName);
+ }
+
+ /*Open another handle to hCreateHandle with OpenEvent*/
+ hOpenEvent = OpenEventW(EVENT_ALL_ACCESS,
+ TRUE,
+ lpEventName);
+ if (hOpenEvent == NULL)
+ {
+ Trace("ERROR: %u :unable to create handle with OpenEvent to %s\n",
+ GetLastError(),
+ lpEventName);
+ CloseHandle(hCreateEvent);
+ Fail("");
+ }
+
+ /*Create a duplicate Event handle*/
+ if (!(DuplicateHandle(GetCurrentProcess(),
+ hOpenEvent,
+ GetCurrentProcess(),
+ &hDupEvent,
+ GENERIC_READ|GENERIC_WRITE,
+ FALSE,
+ DUPLICATE_SAME_ACCESS)))
+ {
+ Trace("ERROR: %u :Fail to create the duplicate handle"
+ " to hCreateEvent=0x%lx\n",
+ GetLastError(),
+ hCreateEvent);
+ CloseHandle(hCreateEvent);
+ CloseHandle(hOpenEvent);
+ Fail("");
+ }
+
+ /*Perform wait on Event that is in signaled state*/
+ if ((WaitForSingleObject(hOpenEvent, 1000)) != WAIT_OBJECT_0)
+ {
+ Trace("ERROR: %u :WaitForSignalObject on hOpenEvent=0x%lx set to "
+ " signaled state failed\n",
+ GetLastError(),
+ hOpenEvent);
+ CloseHandle(hCreateEvent);
+ CloseHandle(hOpenEvent);
+ CloseHandle(hDupEvent);
+ Fail("");
+ }
+
+ /*Set the Duplicate Event handle to nonsignaled state*/
+ if ((ResetEvent(hDupEvent)) == 0)
+ {
+ Trace("ERROR: %u: unable to reset hDupEvent=0x%lx\n",
+ GetLastError(),
+ hDupEvent);
+ CloseHandle(hCreateEvent);
+ CloseHandle(hOpenEvent);
+ CloseHandle(hDupEvent);
+ Fail("");
+ }
+
+ /*Perform wait on Event that is in signaled state*/
+ if ((WaitForSingleObject(hOpenEvent, 1000)) == WAIT_OBJECT_0)
+ {
+ Trace("ERROR: %u :WaitForSignalObject succeeded on hOpenEvent=0x%lx "
+ " when Duplicate hDupEvent=0x%lx set to nonsignaled state"
+ " succeeded\n",
+ GetLastError(),
+ hOpenEvent,
+ hDupEvent);
+ CloseHandle(hCreateEvent);
+ CloseHandle(hOpenEvent);
+ CloseHandle(hDupEvent);
+ Fail("");
+ }
+
+ /*Close handles the events*/
+ CloseHandle(hCreateEvent);
+ CloseHandle(hOpenEvent);
+ CloseHandle(hDupEvent);
+
+ PAL_Terminate();
+ return (PASS);
+}
diff --git a/src/pal/tests/palsuite/threading/DuplicateHandle/test3/testinfo.dat b/src/pal/tests/palsuite/threading/DuplicateHandle/test3/testinfo.dat
new file mode 100644
index 0000000000..a10adb9a8e
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/DuplicateHandle/test3/testinfo.dat
@@ -0,0 +1,17 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Threading
+Function = DuplicateHandle
+Name = Test for DuplicateHandle
+TYPE = DEFAULT
+EXE1 = test3
+Description
+= Tests the PAL implementation of the DuplicateHandle function.
+= This will test duplication of an OpenEvent handle. Test an
+= event in a signaled state to wait, and then set the duplicate
+= to nonsignaled state and perform the wait again. The wait on
+= the event should fail. Test the duplication of closed and NULL
+= events, these should fail.
diff --git a/src/pal/tests/palsuite/threading/DuplicateHandle/test4/CMakeLists.txt b/src/pal/tests/palsuite/threading/DuplicateHandle/test4/CMakeLists.txt
new file mode 100644
index 0000000000..c3040d09ec
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/DuplicateHandle/test4/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test4.c
+)
+
+add_executable(paltest_duplicatehandle_test4
+ ${SOURCES}
+)
+
+add_dependencies(paltest_duplicatehandle_test4 coreclrpal)
+
+target_link_libraries(paltest_duplicatehandle_test4
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/DuplicateHandle/test4/test4.c b/src/pal/tests/palsuite/threading/DuplicateHandle/test4/test4.c
new file mode 100644
index 0000000000..14a72db461
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/DuplicateHandle/test4/test4.c
@@ -0,0 +1,239 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test4.c (DuplicateHandle)
+**
+** Purpose: Tests the PAL implementation of the DuplicateHandle function.
+** This test duplication of a Mutex handle. The test will comprise
+** of creating a Mutex and its duplicate and create a thread that
+** will get ownership. Another thread will be create that will
+** attempt to get ownership of the duplicate Mutex, this will
+** fail, since the Mutex is owned by another thread. The Mutex
+** will be released and then the thread will attempt to get
+** ownership of the duplicate Mutex, this will succeed.
+**
+**
+**===================================================================*/
+#include <palsuite.h>
+
+enum wait_results
+{
+ WR_WAITING,
+ WR_GOT_MUTEX,
+ WR_TIMED_OUT,
+ WR_RELEASED
+};
+
+
+volatile int t1_result=WR_WAITING;
+volatile int t2_result=WR_WAITING;
+
+
+DWORD PALAPI ThreadTest1(LPVOID lpParam)
+{
+ DWORD dwWait;
+
+ dwWait = WaitForSingleObject((HANDLE)lpParam, 0);
+ if (dwWait == WAIT_OBJECT_0)
+ {
+ /* tell the main thread we got the mutex */
+ t1_result=WR_GOT_MUTEX;
+
+ /* wait for main thread to tell us to release the mutex */
+ while(WR_GOT_MUTEX == t1_result)
+ Sleep(1);
+ ReleaseMutex((HANDLE)lpParam);
+
+ /* tell the main thread we released the mutex */
+ t1_result = WR_RELEASED;
+ }
+ else
+ {
+ t1_result = WR_TIMED_OUT;
+ }
+ return 0;
+}
+
+DWORD PALAPI ThreadTest2(LPVOID lpParam)
+{
+ DWORD dwWait;
+
+ dwWait = WaitForSingleObject((HANDLE)lpParam, 0 );
+ if (dwWait == WAIT_OBJECT_0)
+ {
+ ReleaseMutex((HANDLE)lpParam);
+ t2_result = WR_GOT_MUTEX;
+ }
+ else
+ {
+ t2_result = WR_TIMED_OUT;
+ }
+
+ return 0;
+}
+
+
+int __cdecl main(int argc, char **argv)
+{
+
+ HANDLE hDupMutex;
+ HANDLE hMutex;
+ HANDLE hThread;
+ HANDLE hThread2;
+ BOOL bDupHandle=FALSE;
+ DWORD dwThreadId = 0;
+
+ if ((PAL_Initialize(argc,argv)) != 0)
+ {
+ return(FAIL);
+ }
+
+ /*Create Mutex without ownership*/
+ hMutex = CreateMutexW(NULL, // no security attributes
+ FALSE, // initially not owned
+ NULL); // name of mutex
+ if (hMutex == NULL)
+ {
+ Fail("ERROR:%u: Unable to create mutex\n",
+ GetLastError());
+ }
+
+ /*Create Duplicate of the Mutex above*/
+ bDupHandle = DuplicateHandle(GetCurrentProcess(),
+ hMutex,
+ GetCurrentProcess(),
+ &hDupMutex,
+ GENERIC_READ|GENERIC_WRITE,
+ FALSE,
+ DUPLICATE_SAME_ACCESS);
+ if (!bDupHandle)
+ {
+ Trace("ERROR:%u: Created the duplicate handle to "
+ "closed event handle hMutex=0x%lx\n",
+ GetLastError(),
+ hMutex);
+ CloseHandle(hMutex);
+ Fail("");
+ }
+
+ /*Create a thread to test the Mutex*/
+ hThread = CreateThread(NULL,
+ 0,
+ &ThreadTest1,
+ hMutex,
+ 0,
+ &dwThreadId);
+ if (hThread == NULL)
+ {
+ Trace("ERROR:%u: unable to create thread\n",
+ GetLastError());
+ CloseHandle(hMutex);
+ CloseHandle(hDupMutex);
+ Fail("");
+ }
+
+ /* wait until thread has taken the mutex */
+ while (WR_WAITING == t1_result)
+ Sleep(1);
+
+ if(WR_TIMED_OUT == t1_result)
+ {
+ Trace("ERROR: %u: thread 1 couldn't acquire the mutex\n");
+ CloseHandle(hMutex);
+ CloseHandle(hDupMutex);
+ CloseHandle(hThread);
+ Fail("");
+ }
+
+ /*Create a second thread to use the duplicate Mutex*/
+ /*This should fail since the Mutex is owned hThread*/
+ hThread2 = CreateThread(NULL,
+ 0,
+ &ThreadTest2,
+ hDupMutex,
+ 0,
+ &dwThreadId);
+
+ if (hThread2 == NULL)
+ {
+ Trace("ERROR:%u: unable to create thread\n",
+ GetLastError());
+ CloseHandle(hMutex);
+ CloseHandle(hDupMutex);
+ CloseHandle(hThread);
+ Fail("");
+ }
+
+ /* wait until thread has tried to take the mutex */
+ while (WR_WAITING == t2_result)
+ Sleep(1);
+
+ if (WR_TIMED_OUT != t2_result )
+ {
+ Trace("ERROR:%u: Able to take mutex %#x while its duplicate %#x is "
+ "held\n", hDupMutex, hMutex);
+ CloseHandle(hMutex);
+ CloseHandle(hDupMutex);
+ CloseHandle(hThread);
+ CloseHandle(hThread2);
+ Fail("");
+ }
+
+ /* reset second thread status */
+ t2_result = WR_WAITING;
+
+ /* tell thread 1 to release the mutex */
+ t1_result = WR_WAITING;
+
+ /* wait for thread 1 to release the mutex */
+ while (WR_WAITING == t1_result)
+ Sleep(1);
+
+ CloseHandle(hThread2);
+
+ /*Re-Create the second thread to reuse the duplicated Mutex*/
+ /*This test should pass, the Mutex has since been released*/
+ hThread2 = CreateThread(NULL,
+ 0,
+ &ThreadTest2,
+ hDupMutex,
+ 0,
+ &dwThreadId);
+
+ if (hThread2 == NULL)
+ {
+ Trace("ERROR:%u: unable to create thread\n",
+ GetLastError());
+ CloseHandle(hMutex);
+ CloseHandle(hDupMutex);
+ CloseHandle(hThread);
+ Fail("");
+ }
+
+ /* wait until thread has taken the mutex */
+ while (WR_WAITING == t2_result)
+ Sleep(1);
+
+ if (WR_GOT_MUTEX != t2_result )
+ {
+ Trace("ERROR:%u: Unable to take mutex %#x after its duplicate %#x was "
+ "released\n", hDupMutex, hMutex);
+ CloseHandle(hMutex);
+ CloseHandle(hDupMutex);
+ CloseHandle(hThread);
+ CloseHandle(hThread2);
+ Fail("");
+ }
+
+ /*Cleanup.*/
+ CloseHandle(hMutex);
+ CloseHandle(hDupMutex);
+ CloseHandle(hThread);
+ CloseHandle(hThread2);
+
+ PAL_Terminate();
+ return (PASS);
+}
diff --git a/src/pal/tests/palsuite/threading/DuplicateHandle/test4/testinfo.dat b/src/pal/tests/palsuite/threading/DuplicateHandle/test4/testinfo.dat
new file mode 100644
index 0000000000..64842f8713
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/DuplicateHandle/test4/testinfo.dat
@@ -0,0 +1,19 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Threading
+Function = DuplicateHandle
+Name = Test for DuplicateHandle (CreateMutex)
+TYPE = DEFAULT
+EXE1 = test4
+Description
+= Tests the PAL implementation of the DuplicateHandle function.
+= This test duplication of a Mutex handle. The test will comprise
+= of creating a Mutex and its duplicate and create a thread that will
+= get ownership. Another thread will be create that will attempt to
+= get ownership of the duplicate Mutex, this will fail, since the
+= Mutex is owned by another thread. The Mutex will be released and
+= then the thread will attempt to get ownership of the duplicate
+= Mutex, this will succeed.
diff --git a/src/pal/tests/palsuite/threading/DuplicateHandle/test5/CMakeLists.txt b/src/pal/tests/palsuite/threading/DuplicateHandle/test5/CMakeLists.txt
new file mode 100644
index 0000000000..bc468a4a75
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/DuplicateHandle/test5/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test5.c
+)
+
+add_executable(paltest_duplicatehandle_test5
+ ${SOURCES}
+)
+
+add_dependencies(paltest_duplicatehandle_test5 coreclrpal)
+
+target_link_libraries(paltest_duplicatehandle_test5
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/DuplicateHandle/test5/test5.c b/src/pal/tests/palsuite/threading/DuplicateHandle/test5/test5.c
new file mode 100644
index 0000000000..a588928f00
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/DuplicateHandle/test5/test5.c
@@ -0,0 +1,145 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test5.c (DuplicateHandle)
+**
+** Purpose: Tests the PAL implementation of the DuplicateHandle function,
+** with CreatePipe. This test will create a pipe and write to it,
+** the duplicate the read handle and read what was written.
+**
+** Depends: WriteFile
+** ReadFile
+** memcmp
+** CloseHandle
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+const char* cTestString = "one fish, two fish, red fish, blue fish.";
+
+int __cdecl main(int argc, char **argv)
+{
+ HANDLE hReadPipe = NULL;
+ HANDLE hWritePipe = NULL;
+ HANDLE hDupPipe = NULL;
+ BOOL bRetVal = FALSE;
+ DWORD dwBytesWritten;
+ DWORD dwBytesRead;
+ char buffer[256];
+
+ SECURITY_ATTRIBUTES lpPipeAttributes;
+
+ /*Initialize the PAL*/
+ if ((PAL_Initialize(argc, argv)) != 0)
+ {
+ return (FAIL);
+ }
+
+ /*Setup SECURITY_ATTRIBUTES structure for CreatePipe*/
+ lpPipeAttributes.nLength = sizeof(lpPipeAttributes);
+ lpPipeAttributes.lpSecurityDescriptor = NULL;
+ lpPipeAttributes.bInheritHandle = TRUE;
+
+ /*Create a Pipe*/
+ bRetVal = CreatePipe(&hReadPipe, /* read handle*/
+ &hWritePipe, /* write handle */
+ &lpPipeAttributes,/* security attributes*/
+ 0); /* pipe size*/
+ if (bRetVal == FALSE)
+ {
+ Fail("ERROR:%u:Unable to create pipe\n", GetLastError());
+ }
+
+ /*Write to the write pipe handle*/
+ bRetVal = WriteFile(hWritePipe, /* handle to write pipe*/
+ cTestString, /* buffer to write*/
+ strlen(cTestString),/* number of bytes to write*/
+ &dwBytesWritten, /* number of bytes written*/
+ NULL); /* overlapped buffer*/
+ if (bRetVal == FALSE)
+ {
+ Trace("ERROR:%u:unable to write to write pipe handle "
+ "hWritePipe=0x%lx\n", GetLastError(), hWritePipe);
+ CloseHandle(hReadPipe);
+ CloseHandle(hWritePipe);
+ Fail("");
+ }
+
+ /*Duplicate the pipe handle*/
+ if (!(DuplicateHandle(GetCurrentProcess(), /* source handle process*/
+ hReadPipe, /* handle to duplicate*/
+ GetCurrentProcess(), /* target process handle*/
+ &hDupPipe, /* duplicate handle*/
+ GENERIC_READ|GENERIC_WRITE,/* requested access*/
+ FALSE, /* handle inheritance*/
+ DUPLICATE_SAME_ACCESS))) /* optional actions*/
+ {
+ Trace("ERROR:%u:Fail to create the duplicate handle"
+ " to hReadPipe=0x%lx",
+ GetLastError(),
+ hReadPipe);
+ CloseHandle(hReadPipe);
+ CloseHandle(hWritePipe);
+ Fail("");
+ }
+
+ /*Read from the duplicated handle, 256 bytes, more bytes
+ than actually written. This will allow us to use the
+ value that ReadFile returns for comparision.*/
+ bRetVal = ReadFile(hDupPipe, /* handle to read pipe*/
+ buffer, /* buffer to write to*/
+ 256, /* number of bytes to read*/
+ &dwBytesRead, /* number of bytes read*/
+ NULL); /* overlapped buffer*/
+ if (bRetVal == FALSE)
+ {
+ Trace("ERROR:%u:unable read from the duplicated pipe "
+ "hDupPipe=0x%lx\n",
+ GetLastError(),
+ hDupPipe);
+ CloseHandle(hReadPipe);
+ CloseHandle(hWritePipe);
+ CloseHandle(hDupPipe);
+ Fail("");
+ }
+
+ /*Compare what was read with what was written.*/
+ if ((memcmp(cTestString, buffer, dwBytesRead)) != 0)
+ {
+ Trace("ERROR:%u: read \"%s\" expected \"%s\" \n",
+ GetLastError(),
+ buffer,
+ cTestString);
+ CloseHandle(hReadPipe);
+ CloseHandle(hWritePipe);
+ CloseHandle(hDupPipe);
+ Fail("");
+ }
+
+ /*Compare values returned from WriteFile and ReadFile.*/
+ if (dwBytesWritten != dwBytesRead)
+ {
+ Trace("ERROR:%u: WriteFile wrote \"%s\", but ReadFile read \"%s\","
+ " these should be the same\n",
+ GetLastError(),
+ buffer,
+ cTestString);
+ CloseHandle(hReadPipe);
+ CloseHandle(hWritePipe);
+ CloseHandle(hDupPipe);
+ Fail("");
+ }
+
+ /*Cleanup.*/
+ CloseHandle(hWritePipe);
+ CloseHandle(hReadPipe);
+ CloseHandle(hDupPipe);
+
+ PAL_Terminate();
+ return (PASS);
+}
diff --git a/src/pal/tests/palsuite/threading/DuplicateHandle/test5/testinfo.dat b/src/pal/tests/palsuite/threading/DuplicateHandle/test5/testinfo.dat
new file mode 100644
index 0000000000..97e42a9787
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/DuplicateHandle/test5/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Threading
+Function = DuplicateHandle
+Name = Test for DuplicateHandle (CreatePipe)
+TYPE = DEFAULT
+EXE1 = test5
+Description
+= Tests the PAL implementation of the DuplicateHandle function,
+= with CreatePipe. This test will create a pipe and write to it,
+= then duplicate the read handle and read what was written.
diff --git a/src/pal/tests/palsuite/threading/DuplicateHandle/test6/CMakeLists.txt b/src/pal/tests/palsuite/threading/DuplicateHandle/test6/CMakeLists.txt
new file mode 100644
index 0000000000..20f7822b1e
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/DuplicateHandle/test6/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test6.c
+)
+
+add_executable(paltest_duplicatehandle_test6
+ ${SOURCES}
+)
+
+add_dependencies(paltest_duplicatehandle_test6 coreclrpal)
+
+target_link_libraries(paltest_duplicatehandle_test6
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/DuplicateHandle/test6/test6.c b/src/pal/tests/palsuite/threading/DuplicateHandle/test6/test6.c
new file mode 100644
index 0000000000..026f315a44
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/DuplicateHandle/test6/test6.c
@@ -0,0 +1,146 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test6.c (DuplicateHandle)
+**
+** Purpose: Tests the PAL implementation of the DuplicateHandle function,
+** with CreatePipe. This test will create a pipe, then duplicate
+** the write handle, write to the handle, and use the read to
+** verify.
+**
+** Depends: WriteFile
+** ReadFile
+** memcmp
+** CloseHandle
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+const char* cTestString = "one fish, two fish, red fish, blue fish.";
+
+int __cdecl main(int argc, char **argv)
+{
+ HANDLE hReadPipe = NULL;
+ HANDLE hWritePipe = NULL;
+ HANDLE hDupPipe = NULL;
+ BOOL bRetVal = FALSE;
+ DWORD dwBytesWritten;
+ DWORD dwBytesRead;
+ char buffer[256];
+
+ SECURITY_ATTRIBUTES lpPipeAttributes;
+
+ /*Initialize the PAL*/
+ if ((PAL_Initialize(argc, argv)) != 0)
+ {
+ return (FAIL);
+ }
+
+ /*Setup SECURITY_ATTRIBUTES structure for CreatePipe*/
+ lpPipeAttributes.nLength = sizeof(lpPipeAttributes);
+ lpPipeAttributes.lpSecurityDescriptor = NULL;
+ lpPipeAttributes.bInheritHandle = TRUE;
+
+ /*Create a Pipe*/
+ bRetVal = CreatePipe(&hReadPipe, /* read handle*/
+ &hWritePipe, /* write handle */
+ &lpPipeAttributes,/* security attributes*/
+ 0); /* pipe size*/
+ if (bRetVal == FALSE)
+ {
+ Fail("ERROR: %ld :Unable to create pipe\n", GetLastError());
+ }
+
+ /*Duplicate the pipe handle*/
+ if (!(DuplicateHandle(GetCurrentProcess(), /* source handle process*/
+ hWritePipe, /* handle to duplicate*/
+ GetCurrentProcess(), /* target process handle*/
+ &hDupPipe, /* duplicate handle*/
+ GENERIC_READ|GENERIC_WRITE,/* requested access*/
+ FALSE, /* handle inheritance*/
+ DUPLICATE_SAME_ACCESS))) /* optional actions*/
+ {
+ Trace("ERROR: %ld :Fail to create the duplicate handle"
+ " to hWritePipe=0x%lx",
+ GetLastError(),
+ hWritePipe);
+ CloseHandle(hReadPipe);
+ CloseHandle(hWritePipe);
+ Fail("");
+ }
+
+ /*Write to the duplicate write pipe handle*/
+ bRetVal = WriteFile(hDupPipe, /* handle to write pipe*/
+ cTestString, /* buffer to write*/
+ strlen(cTestString),/* number of bytes to write*/
+ &dwBytesWritten, /* number of bytes written*/
+ NULL); /* overlapped buffer*/
+ if (bRetVal == FALSE)
+ {
+ Trace("ERROR: %ld :unable to write to duplicate write pipe handle "
+ "hDupPipe=0x%lx\n",
+ GetLastError(),
+ hDupPipe);
+ CloseHandle(hReadPipe);
+ CloseHandle(hWritePipe);
+ CloseHandle(hDupPipe);
+ Fail("");
+ }
+
+ /*Read from the read handle, 256 bytes, more bytes
+ then actually written. This will give allow us to use
+ the value that ReadFile returns for comparision.*/
+ bRetVal = ReadFile(hReadPipe, /* handle to read pipe*/
+ buffer, /* buffer to write to*/
+ 256, /* number of bytes to read*/
+ &dwBytesRead, /* number of bytes read*/
+ NULL); /* overlapped buffer*/
+ if (bRetVal == FALSE)
+ {
+ Trace("ERROR: %ld : unable read hReadPipe=0x%lx\n",
+ GetLastError(), hReadPipe);
+ CloseHandle(hReadPipe);
+ CloseHandle(hWritePipe);
+ CloseHandle(hDupPipe);
+ Fail("");
+ }
+
+ /*Compare what was read with what was written.*/
+ if ((memcmp(cTestString, buffer, dwBytesRead)) != 0)
+ {
+ Trace("ERROR: read \"%s\" expected \"%s\" \n",
+ buffer,
+ cTestString);
+ CloseHandle(hReadPipe);
+ CloseHandle(hWritePipe);
+ CloseHandle(hDupPipe);
+ Fail("");
+ }
+
+ /*Compare values returned from WriteFile and ReadFile.*/
+ if (dwBytesWritten != dwBytesRead)
+ {
+ Trace("ERROR: WriteFile wrote \"%s\", but ReadFile read \"%s\","
+ " these should be the same\n",
+ buffer,
+ cTestString);
+ CloseHandle(hReadPipe);
+ CloseHandle(hWritePipe);
+ CloseHandle(hDupPipe);
+ Fail("");
+ }
+
+ /*Cleanup.*/
+ CloseHandle(hReadPipe);
+ CloseHandle(hWritePipe);
+ CloseHandle(hDupPipe);
+
+
+ PAL_Terminate();
+ return (PASS);
+}
diff --git a/src/pal/tests/palsuite/threading/DuplicateHandle/test6/testinfo.dat b/src/pal/tests/palsuite/threading/DuplicateHandle/test6/testinfo.dat
new file mode 100644
index 0000000000..6c49d64f89
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/DuplicateHandle/test6/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Threading
+Function = DuplicateHandle
+Name = Test for DuplicateHandle (CreatePipe)
+TYPE = DEFAULT
+EXE1 = test6
+Description
+= Tests the PAL implementation of the DuplicateHandle function,
+= with CreatePipe. This test will create a pipe, then duplicate
+= the write handle, write to the handle, and use the read to
+= verify.
diff --git a/src/pal/tests/palsuite/threading/DuplicateHandle/test7/CMakeLists.txt b/src/pal/tests/palsuite/threading/DuplicateHandle/test7/CMakeLists.txt
new file mode 100644
index 0000000000..df3fdf9ae0
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/DuplicateHandle/test7/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test7.c
+)
+
+add_executable(paltest_duplicatehandle_test7
+ ${SOURCES}
+)
+
+add_dependencies(paltest_duplicatehandle_test7 coreclrpal)
+
+target_link_libraries(paltest_duplicatehandle_test7
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/DuplicateHandle/test7/test7.c b/src/pal/tests/palsuite/threading/DuplicateHandle/test7/test7.c
new file mode 100644
index 0000000000..0477291922
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/DuplicateHandle/test7/test7.c
@@ -0,0 +1,149 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test7.c (DuplicateHandle)
+**
+** Purpose: Tests the PAL implementation of the DuplicateHandle function,
+** with a handle from CreateThread. The test will create a thread
+** handle and its duplicate. Then get the priorities of the threads,
+** set the priority of one and the change should be seen in the
+** other.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+DWORD PALAPI CreateTestThread(LPVOID lpParam);
+
+int __cdecl main(int argc, char* argv[])
+{
+ HANDLE hThread;
+ HANDLE hDupThread;
+ DWORD dwThreadId = 0;
+ LPTHREAD_START_ROUTINE lpStartAddress = &CreateTestThread;
+
+ int threadPriority;
+ int duplicatePriority;
+ int finalPriority;
+
+ /* Initialize the PAL.*/
+ if ((PAL_Initialize(argc, argv)) != 0)
+ {
+ return (FAIL);
+ }
+
+ /* Create a thread.*/
+ hThread = CreateThread(NULL, /* SD*/
+ (DWORD)0, /* initial stack size*/
+ lpStartAddress, /* thread function*/
+ NULL, /* thread argument*/
+ (DWORD)0, /* creation option*/
+ &dwThreadId); /* thread identifier*/
+ if (hThread == NULL)
+ {
+ Fail("ERROR:%u: Unable to create thread.\n",
+ GetLastError());
+ }
+
+ /* Duplicate the thread handle.*/
+ if (!(DuplicateHandle(GetCurrentProcess(), /* source handle process*/
+ hThread, /* handle to duplicate*/
+ GetCurrentProcess(), /* target process handle*/
+ &hDupThread, /* duplicate handle*/
+ (DWORD)0, /* requested access*/
+ FALSE, /* handle inheritance*/
+ DUPLICATE_SAME_ACCESS))) /* optional actions*/
+ {
+ Trace("ERROR: %ld :Fail to create the duplicate handle"
+ " to hThread=0x%lx",
+ GetLastError(),
+ hThread);
+ CloseHandle(hThread);
+ Fail("");
+ }
+
+ /* Get the priority of the thread.*/
+ threadPriority = GetThreadPriority(hThread);
+ if(threadPriority != 0)
+ {
+ Trace("ERROR: Thread priority of hThread=0x%lx should be "
+ "set to normal THREAD_PRIORITY_NORMAL=%d\n",
+ hThread,
+ THREAD_PRIORITY_NORMAL);
+ CloseHandle(hThread);
+ CloseHandle(hDupThread);
+ Fail("");
+ }
+
+ /* Get the priority of the duplicated handle, and compare it to
+ * the priority of the original thread. Should be the same.*/
+ duplicatePriority = GetThreadPriority(hThread);
+ if(duplicatePriority != threadPriority)
+ {
+ Trace("ERROR: Expected priority of hThread=0x%lx and hDupThread=0x%lx"
+ " to be the same. Priorities:hThread=\"%d\":hDupThread=\"%d\"\n",
+ hThread,
+ hDupThread,
+ threadPriority,
+ duplicatePriority);
+ CloseHandle(hThread);
+ CloseHandle(hDupThread);
+ Fail("");
+ }
+
+ /* Set the priority of the duplicate thread.*/
+ if(!SetThreadPriority (hDupThread,THREAD_PRIORITY_HIGHEST))
+ {
+ Trace("ERROR:%u: SetThreadPriority failed on hThread=0x%lx\n",
+ GetLastError(),
+ hDupThread);
+ CloseHandle(hThread);
+ CloseHandle(hDupThread);
+ Fail("");
+ }
+
+ /* Get the priority of the origianl thread, and
+ * compare it to what the duplicate was set to.*/
+ finalPriority = GetThreadPriority(hThread);
+ if (finalPriority != THREAD_PRIORITY_HIGHEST)
+ {
+ Trace("ERROR: Expected priority of hThread=0x%lw and "
+ "hDupThread=0x%lw to be set the same. Priorities:"
+ "hThread=\"%d\":hDupThread=\"%d\".\n",
+ hThread,
+ hDupThread,
+ threadPriority,
+ duplicatePriority);
+ CloseHandle(hThread);
+ CloseHandle(hDupThread);
+ Fail("");
+ }
+
+ /* Wait on the original thread.*/
+ if((WaitForSingleObject(hThread, 100)) != WAIT_OBJECT_0)
+ {
+ Trace("ERROR:%u: hThread=0x%lx is in a non-signalled "
+ "mode, yet created signalled.\n",
+ GetLastError(),
+ hThread);
+ CloseHandle(hThread);
+ CloseHandle(hDupThread);
+ Fail("");
+ }
+
+ /* Clean-up thread and Terminate the PAL.*/
+ CloseHandle(hThread);
+ CloseHandle(hDupThread);
+ PAL_Terminate();
+ return PASS;
+}
+
+/*Thread testing function, only return '0'*/
+DWORD PALAPI CreateTestThread(LPVOID lpParam)
+{
+ return (DWORD)0;
+}
diff --git a/src/pal/tests/palsuite/threading/DuplicateHandle/test7/testinfo.dat b/src/pal/tests/palsuite/threading/DuplicateHandle/test7/testinfo.dat
new file mode 100644
index 0000000000..b8092d6152
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/DuplicateHandle/test7/testinfo.dat
@@ -0,0 +1,16 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Threading
+Function = DuplicateHandle
+Name = Test for DuplicateHandle (CreateThread)
+TYPE = DEFAULT
+EXE1 = test7
+Description
+= Tests the PAL implementation of the DuplicateHandle function,
+= with a handle from CreateThread. The test will create a thread
+= handle and its duplicate. Then get the priorities of the threads,
+= set the priority of one and the change should be seen in the
+= other.
diff --git a/src/pal/tests/palsuite/threading/DuplicateHandle/test8/CMakeLists.txt b/src/pal/tests/palsuite/threading/DuplicateHandle/test8/CMakeLists.txt
new file mode 100644
index 0000000000..15ec23d272
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/DuplicateHandle/test8/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test8.c
+)
+
+add_executable(paltest_duplicatehandle_test8
+ ${SOURCES}
+)
+
+add_dependencies(paltest_duplicatehandle_test8 coreclrpal)
+
+target_link_libraries(paltest_duplicatehandle_test8
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/DuplicateHandle/test8/test8.c b/src/pal/tests/palsuite/threading/DuplicateHandle/test8/test8.c
new file mode 100644
index 0000000000..6748c5dffd
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/DuplicateHandle/test8/test8.c
@@ -0,0 +1,164 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test8.c (DuplicateHandle)
+**
+** Purpose: Tests the PAL implementation of the DuplicateHandle function,
+** with a handle from GetCurrentThread. The test will create a thread
+** handle, get the current thread and its duplicate. Then get the
+** priorities of the threads, set the priority of one and the change
+** should be seen in the other.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+DWORD PALAPI CreateTestThread(LPVOID lpParam);
+
+int __cdecl main(int argc, char* argv[])
+{
+ HANDLE hThread;
+ HANDLE hCurrentThread;
+ HANDLE hDupThread;
+ DWORD dwThreadId = 0;
+ LPTHREAD_START_ROUTINE lpStartAddress = &CreateTestThread;
+
+ int threadPriority;
+ int duplicatePriority;
+ int finalPriority;
+
+ /* Initialize the PAL.*/
+ if ((PAL_Initialize(argc, argv)) != 0)
+ {
+ return (FAIL);
+ }
+
+#if !HAVE_SCHED_OTHER_ASSIGNABLE
+ /* Defining thread priority for SCHED_OTHER is implementation defined.
+ Some platforms like NetBSD cannot reassign it as they are dynamic.
+ */
+ printf("paltest_duplicatehandle_test8 has been disabled on this platform\n");
+#else
+
+ /* Create a thread.*/
+ hThread = CreateThread(NULL, /* SD*/
+ (DWORD)0, /* initial stack size*/
+ lpStartAddress, /* thread function*/
+ NULL, /* thread argument*/
+ (DWORD)0, /* creation option*/
+ &dwThreadId); /* thread identifier*/
+ if (hThread == NULL)
+ {
+ Fail("ERROR:%u: Unable to create thread.\n",
+ GetLastError());
+ }
+
+ /*Get a psuedo handle to the current thread.*/
+ hCurrentThread = GetCurrentThread();
+
+ /* Duplicate the psuedo thread handle.*/
+ if (!(DuplicateHandle(GetCurrentProcess(), /* source handle process*/
+ hCurrentThread, /* handle to duplicate*/
+ GetCurrentProcess(), /* target process handle*/
+ &hDupThread, /* duplicate handle*/
+ (DWORD)0, /* requested access*/
+ FALSE, /* handle inheritance*/
+ DUPLICATE_SAME_ACCESS))) /* optional actions*/
+ {
+ Trace("ERROR: %ld :Fail to create the duplicate handle"
+ " to hThread=0x%lx",
+ GetLastError(),
+ hThread);
+ CloseHandle(hThread);
+ Fail("");
+ }
+
+ /* Get the priority of the thread.*/
+ threadPriority = GetThreadPriority(hCurrentThread);
+ if(threadPriority != 0)
+ {
+ Trace("ERROR: Thread priority of hCurrentThread=0x%lx should be "
+ "set to normal THREAD_PRIORITY_NORMAL=%d\n",
+ hCurrentThread,
+ THREAD_PRIORITY_NORMAL);
+ CloseHandle(hThread);
+ CloseHandle(hDupThread);
+ Fail("");
+ }
+
+ /* Get the priority of the duplicated handle, and compare it to
+ * the priority of the original thread. Should be the same.*/
+ duplicatePriority = GetThreadPriority(hCurrentThread);
+ if(duplicatePriority != threadPriority)
+ {
+ Trace("ERROR: Expected priority of hCurrentThread=0x%lx and "
+ "hDupThread=0x%lx to be the same. Priorities:hThread="
+ "\"%d\":hDupThread=\"%d\"\n",
+ hCurrentThread,
+ hDupThread,
+ threadPriority,
+ duplicatePriority);
+ CloseHandle(hThread);
+ CloseHandle(hDupThread);
+ Fail("");
+ }
+
+ /* Set the priority of the original thread.*/
+ if(!SetThreadPriority (hCurrentThread,THREAD_PRIORITY_HIGHEST))
+ {
+ Trace("ERROR:%u: SetThreadPriority failed on hCurrentThread=0x%lx\n",
+ GetLastError(),
+ hCurrentThread);
+ CloseHandle(hThread);
+ CloseHandle(hDupThread);
+ Fail("");
+ }
+
+ /* Get the priority of the duplicate thread, and
+ * compare it to what the original was set to.*/
+ finalPriority = GetThreadPriority(hDupThread);
+ if (finalPriority != THREAD_PRIORITY_HIGHEST)
+ {
+ Trace("ERROR: Expected priority of hCurrentThread=0x%lw and "
+ "hDupThread=0x%lw to be set the same. Priorities:"
+ "hCurrentThread=\"%d\":hDupThread=\"%d\".\n",
+ hCurrentThread,
+ hDupThread,
+ threadPriority,
+ duplicatePriority);
+ CloseHandle(hThread);
+ CloseHandle(hDupThread);
+ Fail("");
+ }
+
+ /* Wait on the original thread.*/
+ if((WaitForSingleObject(hThread, 100)) != WAIT_OBJECT_0)
+ {
+ Trace("ERROR:%u: hCurrentThread=0x%lx is in a non-signalled "
+ "mode, yet created signalled.\n",
+ GetLastError(),
+ hThread);
+ CloseHandle(hThread);
+ CloseHandle(hDupThread);
+ Fail("");
+ }
+
+ /* Clean-up thread and Terminate the PAL.*/
+ CloseHandle(hThread);
+ CloseHandle(hDupThread);
+
+#endif
+
+ PAL_Terminate();
+ return PASS;
+}
+
+/*Thread testing function, only return '0'*/
+DWORD PALAPI CreateTestThread(LPVOID lpParam)
+{
+ return (DWORD)0;
+}
diff --git a/src/pal/tests/palsuite/threading/DuplicateHandle/test8/testinfo.dat b/src/pal/tests/palsuite/threading/DuplicateHandle/test8/testinfo.dat
new file mode 100644
index 0000000000..ae1353af18
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/DuplicateHandle/test8/testinfo.dat
@@ -0,0 +1,16 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Threading
+Function = DuplicateHandle
+Name = Test for DuplicateHandle (GetCurrentThread)
+TYPE = DEFAULT
+EXE1 = test8
+Description
+=Tests the PAL implementation of the DuplicateHandle function,
+=with a handle from GetCurrentThread. The test will create a thread
+=handle, get the current thread and its duplicate. Then get the
+=priorities of the threads, set the priority of one and the change
+=should be seen in the other.
diff --git a/src/pal/tests/palsuite/threading/DuplicateHandle/test9/CMakeLists.txt b/src/pal/tests/palsuite/threading/DuplicateHandle/test9/CMakeLists.txt
new file mode 100644
index 0000000000..e4442e327c
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/DuplicateHandle/test9/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test9.c
+)
+
+add_executable(paltest_duplicatehandle_test9
+ ${SOURCES}
+)
+
+add_dependencies(paltest_duplicatehandle_test9 coreclrpal)
+
+target_link_libraries(paltest_duplicatehandle_test9
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/DuplicateHandle/test9/test9.c b/src/pal/tests/palsuite/threading/DuplicateHandle/test9/test9.c
new file mode 100644
index 0000000000..f15871c57d
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/DuplicateHandle/test9/test9.c
@@ -0,0 +1,127 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test9.c (DuplicateHandle)
+**
+** Purpose: Tests the PAL implementation of the DuplicateHandle function,
+** with a handle from GetCurrentProcess. The test will create a
+** process, duplicate it, then using ReadProcessMemory will
+** read from the memory location of the CreateProcess process
+** memory and the DuplicateHandle process memory. If the
+** duplication is correct the memory will be the same for both.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char* argv[])
+{
+ HANDLE hProcess;
+ HANDLE hDupProcess;
+ char lpBuffer[64];
+ char lpDupBuffer[64];
+ SIZE_T lpNumberOfBytesRead;
+ SIZE_T lpDupNumberOfBytesRead;
+ char lpTestBuffer[] = "abcdefghijklmnopqrstuvwxyz";
+
+ /* Initalize the PAL.
+ */
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /* Initalize the buffers.
+ */
+ ZeroMemory( &lpBuffer, sizeof(lpBuffer) );
+ ZeroMemory( &lpDupBuffer, sizeof(lpDupBuffer) );
+
+ /* Get current proces, this will be duplicated.
+ */
+ hProcess = GetCurrentProcess();
+ if(hProcess == NULL)
+ {
+ Fail("ERROR: Unable to get the current process\n");
+ }
+
+ /* Duplicate the current process handle.
+ */
+ if (!(DuplicateHandle(GetCurrentProcess(), /* source handle process*/
+ hProcess, /* handle to duplicate*/
+ GetCurrentProcess(), /* target process handle*/
+ &hDupProcess, /* duplicate handle*/
+ (DWORD)0, /* requested access*/
+ FALSE, /* handle inheritance*/
+ DUPLICATE_SAME_ACCESS))) /* optional actions*/
+ {
+ Trace("ERROR:%u: Failed to create the duplicate handle"
+ " to hProcess=0x%lx",
+ GetLastError(),
+ hProcess);
+ CloseHandle(hProcess);
+ Fail("");
+ }
+
+ /* Get memory read of the current process.
+ */
+ if ((ReadProcessMemory(hDupProcess, &lpTestBuffer,
+ lpDupBuffer, sizeof(lpDupBuffer), &lpDupNumberOfBytesRead)) == 0)
+ {
+ Trace("ERROR:%u: Unable to read the process memory of "
+ "hDupProcess=0x%lx.\n",
+ GetLastError(),
+ hDupProcess);
+ CloseHandle(hProcess);
+ CloseHandle(hDupProcess);
+ Fail("");
+ }
+
+ /* Get read memory of the created process.
+ */
+ if ((ReadProcessMemory(hProcess, &lpTestBuffer,
+ lpBuffer, sizeof(lpBuffer), &lpNumberOfBytesRead)) == 0)
+ {
+ Trace("ERROR:%u: Unable to read the process memory of "
+ "hProcess=0x%lx.\n",
+ GetLastError(),
+ hProcess);
+ CloseHandle(hProcess);
+ CloseHandle(hDupProcess);
+ Fail("");
+ }
+
+ /* Compare the number of bytes that were read by each
+ * ReadProcessMemory.*/
+ if (lpDupNumberOfBytesRead != lpNumberOfBytesRead)
+ {
+ Trace("ERROR: ReadProcessMemory read different numbers of bytes "
+ "from duplicate process handles.\n");
+ CloseHandle(hProcess);
+ CloseHandle(hDupProcess);
+ Fail("");
+ }
+
+ /* Compare the two buffers to make sure they are equal.
+ */
+ if ((strcmp(lpBuffer, lpDupBuffer)) != 0)
+ {
+ Trace("ERROR: ReadProcessMemory read different numbers of bytes "
+ "from duplicate process handles. hProcess read \"%s\" and "
+ "hDupProcess read \"%s\"\n",
+ lpBuffer,
+ lpDupBuffer);
+ CloseHandle(hProcess);
+ CloseHandle(hDupProcess);
+ Fail("");
+ }
+
+ /* Clean-up thread and Terminate the PAL.*/
+ CloseHandle(hProcess);
+ CloseHandle(hDupProcess);
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/threading/DuplicateHandle/test9/testinfo.dat b/src/pal/tests/palsuite/threading/DuplicateHandle/test9/testinfo.dat
new file mode 100644
index 0000000000..c7122908fd
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/DuplicateHandle/test9/testinfo.dat
@@ -0,0 +1,17 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Threading
+Function = DuplicateHandle
+Name = Test for DuplicateHandle (GetCurrentProcess)
+TYPE = DEFAULT
+EXE1 = test9
+Description
+= Tests the PAL implementation of the DuplicateHandle function,
+= with a handle from GetCurrentProcess. The test will create a
+= process, duplicate it, then using ReadProcessMemory will
+= read from the memory location of the CreateProcess process
+= memory and the DuplicateHandle process memory. If the
+= duplication is correct the memory will be the same for both.
diff --git a/src/pal/tests/palsuite/threading/ExitProcess/CMakeLists.txt b/src/pal/tests/palsuite/threading/ExitProcess/CMakeLists.txt
new file mode 100644
index 0000000000..1962ade358
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/ExitProcess/CMakeLists.txt
@@ -0,0 +1,6 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+add_subdirectory(test3)
+
diff --git a/src/pal/tests/palsuite/threading/ExitProcess/test1/CMakeLists.txt b/src/pal/tests/palsuite/threading/ExitProcess/test1/CMakeLists.txt
new file mode 100644
index 0000000000..decddb8512
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/ExitProcess/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ ExitProcess.c
+)
+
+add_executable(paltest_exitprocess_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_exitprocess_test1 coreclrpal)
+
+target_link_libraries(paltest_exitprocess_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/ExitProcess/test1/ExitProcess.c b/src/pal/tests/palsuite/threading/ExitProcess/test1/ExitProcess.c
new file mode 100644
index 0000000000..2b089a0b83
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/ExitProcess/test1/ExitProcess.c
@@ -0,0 +1,32 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: exitprocess/test1/exitprocess.c
+**
+** Purpose: Test to ensure ExitProcess returns the argument given
+** to it.
+**
+**
+**=========================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main( int argc, char **argv )
+
+{
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return ( FAIL );
+ }
+
+ ExitProcess(PASS);
+
+ Fail ("ExitProcess(0) failed to exit.\n Test Failed.\n");
+
+ return ( FAIL);
+
+}
diff --git a/src/pal/tests/palsuite/threading/ExitProcess/test1/testinfo.dat b/src/pal/tests/palsuite/threading/ExitProcess/test1/testinfo.dat
new file mode 100644
index 0000000000..d8b85abad6
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/ExitProcess/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = ExitProcess
+Name = Positive Test for ExitProcess
+TYPE = DEFAULT
+EXE1 = exitprocess
+Description
+= Test the ExitProcess function. The test runs the ExitProcess function
+= with the TEST_RETURN enumeration value PASS
diff --git a/src/pal/tests/palsuite/threading/ExitProcess/test2/CMakeLists.txt b/src/pal/tests/palsuite/threading/ExitProcess/test2/CMakeLists.txt
new file mode 100644
index 0000000000..881c7d0eee
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/ExitProcess/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test2.c
+)
+
+add_executable(paltest_exitprocess_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_exitprocess_test2 coreclrpal)
+
+target_link_libraries(paltest_exitprocess_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/ExitProcess/test2/test2.c b/src/pal/tests/palsuite/threading/ExitProcess/test2/test2.c
new file mode 100644
index 0000000000..8023ad7bab
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/ExitProcess/test2/test2.c
@@ -0,0 +1,30 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================================
+**
+** Source: test2.c
+**
+** Purpose: Positive test for ExitProcess.
+**
+** Dependencies: none
+**
+
+**
+**===========================================================================*/
+#include <palsuite.h>
+
+
+
+int __cdecl main( int argc, char **argv )
+
+{
+ /* call ExitProcess() -- should work without PAL_Initialize() */
+ ExitProcess(PASS);
+
+
+ /* return failure if we reach here -- note no attempt at */
+ /* meaningful output because we never called PAL_Initialize(). */
+ return FAIL;
+}
diff --git a/src/pal/tests/palsuite/threading/ExitProcess/test2/testinfo.dat b/src/pal/tests/palsuite/threading/ExitProcess/test2/testinfo.dat
new file mode 100644
index 0000000000..0aa07eb15a
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/ExitProcess/test2/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = ExitProcess
+Name = Positive test for ExitProcess
+TYPE = DEFAULT
+EXE1 = test2
+Description
+= Test to ensure proper operation of the ExitProcess()
+= API by ensuring it works before PAL_Initialize() is
+= called.
diff --git a/src/pal/tests/palsuite/threading/ExitProcess/test3/CMakeLists.txt b/src/pal/tests/palsuite/threading/ExitProcess/test3/CMakeLists.txt
new file mode 100644
index 0000000000..638408e986
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/ExitProcess/test3/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test3.c
+)
+
+add_executable(paltest_exitprocess_test3
+ ${SOURCES}
+)
+
+add_dependencies(paltest_exitprocess_test3 coreclrpal)
+
+target_link_libraries(paltest_exitprocess_test3
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/ExitProcess/test3/test3.c b/src/pal/tests/palsuite/threading/ExitProcess/test3/test3.c
new file mode 100644
index 0000000000..aea485e5e3
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/ExitProcess/test3/test3.c
@@ -0,0 +1,40 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================================
+**
+** Source: test3.c
+**
+** Purpose: Positive test for ExitProcess.
+**
+** Dependencies: PAL_Initialize
+** PAL_Terminate
+**
+
+**
+**===========================================================================*/
+#include <palsuite.h>
+
+
+
+int __cdecl main( int argc, char **argv )
+
+{
+ /* initialize the PAL */
+ if( PAL_Initialize(argc, argv) != 0 )
+ {
+ return( FAIL );
+ }
+
+ /* terminate the PAL */
+ PAL_Terminate();
+
+ /* call ExitProcess() -- should work after PAL_Terminate() */
+ ExitProcess( PASS );
+
+
+ /* return failure if we reach here -- note no attempt at */
+ /* meaningful output because we've called PAL_Terminte(). */
+ return FAIL;
+}
diff --git a/src/pal/tests/palsuite/threading/ExitProcess/test3/testinfo.dat b/src/pal/tests/palsuite/threading/ExitProcess/test3/testinfo.dat
new file mode 100644
index 0000000000..c857d885cc
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/ExitProcess/test3/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = ExitProcess
+Name = Positive test for ExitProcess
+TYPE = DEFAULT
+EXE1 = test3
+Description
+= Test to ensure proper operation of the ExitProcess()
+= API by ensuring it works after PAL_Terminate() is
+= called.
diff --git a/src/pal/tests/palsuite/threading/ExitThread/CMakeLists.txt b/src/pal/tests/palsuite/threading/ExitThread/CMakeLists.txt
new file mode 100644
index 0000000000..ef14ea5352
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/ExitThread/CMakeLists.txt
@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+
diff --git a/src/pal/tests/palsuite/threading/ExitThread/test1/CMakeLists.txt b/src/pal/tests/palsuite/threading/ExitThread/test1/CMakeLists.txt
new file mode 100644
index 0000000000..15e0c1b62d
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/ExitThread/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_exitthread_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_exitthread_test1 coreclrpal)
+
+target_link_libraries(paltest_exitthread_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/ExitThread/test1/test1.c b/src/pal/tests/palsuite/threading/ExitThread/test1/test1.c
new file mode 100644
index 0000000000..2963745bef
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/ExitThread/test1/test1.c
@@ -0,0 +1,114 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: test1.c
+**
+** Purpose: Test for ExitThread. Create a thread and then call
+** exit thread within the threading function. Ensure that it exits
+** immediatly.
+**
+**
+**=========================================================*/
+
+#include <palsuite.h>
+
+DWORD dwExitThreadTestParameter = 0;
+
+DWORD PALAPI ExitThreadTestThread( LPVOID lpParameter)
+{
+ DWORD dwRet = 0;
+
+ /* Save parameter for test */
+ dwExitThreadTestParameter = (DWORD)lpParameter;
+
+ /* Call the ExitThread function */
+ ExitThread(dwRet);
+
+ /* If we didn't exit, get caught in this loop. But, the
+ program will exit.
+ */
+ while (!dwRet)
+ {
+ Fail("ERROR: Entered an infinite loop because ExitThread "
+ "failed to exit from the thread. Forcing exit from "
+ "the test now.");
+ }
+
+ return dwRet;
+}
+
+BOOL ExitThreadTest()
+{
+ BOOL bRet = FALSE;
+ DWORD dwRet = 0;
+
+ LPSECURITY_ATTRIBUTES lpThreadAttributes = NULL;
+ DWORD dwStackSize = 0;
+ LPTHREAD_START_ROUTINE lpStartAddress = &ExitThreadTestThread;
+ LPVOID lpParameter = lpStartAddress;
+ DWORD dwCreationFlags = 0; //run immediately
+ DWORD dwThreadId = 0;
+
+ HANDLE hThread = 0;
+
+ dwExitThreadTestParameter = 0;
+
+ /* Create a Thread. We'll need this to test that we're able
+ to exit the thread.
+ */
+ hThread = CreateThread( lpThreadAttributes,
+ dwStackSize, lpStartAddress, lpParameter,
+ dwCreationFlags, &dwThreadId );
+
+ if (hThread != INVALID_HANDLE_VALUE)
+ {
+ dwRet = WaitForSingleObject(hThread,INFINITE);
+
+ if (dwRet != WAIT_OBJECT_0)
+ {
+ Trace("ExitThreadTest:WaitForSingleObject failed "
+ "(%x)\n",GetLastError());
+ }
+ else
+ {
+ /* Check to ensure that the parameter set in the Thread
+ function is correct.
+ */
+ if (dwExitThreadTestParameter != (DWORD)lpParameter)
+ {
+ Trace("ERROR: The paramater passed should have been "
+ "%d but turned up as %d.",
+ dwExitThreadTestParameter, lpParameter);
+ }
+ else
+ {
+ bRet = TRUE;
+ }
+ }
+ }
+ else
+ {
+ Trace("ExitThreadTest:CreateThread failed (%x)\n",GetLastError());
+ }
+
+ return bRet;
+}
+
+int __cdecl main(int argc, char **argv)
+{
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return ( FAIL );
+ }
+
+ if(!ExitThreadTest())
+ {
+ Fail ("Test failed\n");
+ }
+
+ PAL_Terminate();
+ return ( PASS );
+}
diff --git a/src/pal/tests/palsuite/threading/ExitThread/test1/testinfo.dat b/src/pal/tests/palsuite/threading/ExitThread/test1/testinfo.dat
new file mode 100644
index 0000000000..a526f8e127
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/ExitThread/test1/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = ExitThread
+Name = Positive Test for ExitThread
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Test for ExitThread. Create a thread and then call
+= exit thread within the threading function. Ensure that it exits
+= immediatly.
diff --git a/src/pal/tests/palsuite/threading/ExitThread/test2/CMakeLists.txt b/src/pal/tests/palsuite/threading/ExitThread/test2/CMakeLists.txt
new file mode 100644
index 0000000000..aa05382feb
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/ExitThread/test2/CMakeLists.txt
@@ -0,0 +1,36 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(TESTSOURCES
+ test2.c
+)
+
+add_executable(paltest_exitthread_test2
+ ${TESTSOURCES}
+)
+
+add_dependencies(paltest_exitthread_test2 coreclrpal)
+
+target_link_libraries(paltest_exitthread_test2
+ pthread
+ m
+ coreclrpal
+)
+
+
+set(HELPERSOURCES
+ childprocess.c
+)
+
+add_executable(paltest_exitthread_test2_child
+ ${HELPERSOURCES}
+)
+
+add_dependencies(paltest_exitthread_test2_child coreclrpal)
+
+target_link_libraries(paltest_exitthread_test2_child
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/ExitThread/test2/childprocess.c b/src/pal/tests/palsuite/threading/ExitThread/test2/childprocess.c
new file mode 100644
index 0000000000..7fbe208f91
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/ExitThread/test2/childprocess.c
@@ -0,0 +1,41 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: childprocess.c
+**
+** Purpose: Test to ensure ExitThread returns the right
+** value when shutting down the last thread of a process.
+** All this program does is call ExitThread() with a predefined
+** value.
+**
+** Dependencies: none
+**
+
+**
+**=========================================================*/
+
+#include <palsuite.h>
+#include "myexitcode.h"
+
+int __cdecl main( int argc, char **argv )
+{
+ /* initialize the PAL */
+ if( PAL_Initialize(argc, argv) != 0 )
+ {
+ return( FAIL );
+ }
+
+ /* exit the current thread with a magic test value -- it should */
+ /* terminate the process and return that test value from this */
+ /* program. */
+ ExitThread( TEST_EXIT_CODE );
+
+ /* technically we should never get here */
+ PAL_Terminate();
+
+ /* return failure */
+ return FAIL;
+}
diff --git a/src/pal/tests/palsuite/threading/ExitThread/test2/myexitcode.h b/src/pal/tests/palsuite/threading/ExitThread/test2/myexitcode.h
new file mode 100644
index 0000000000..566becb9a0
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/ExitThread/test2/myexitcode.h
@@ -0,0 +1,14 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: myexitcode.h
+**
+** Purpose: Define an exit code.
+**
+**
+**==========================================================================*/
+
+#define TEST_EXIT_CODE 316
diff --git a/src/pal/tests/palsuite/threading/ExitThread/test2/test2.c b/src/pal/tests/palsuite/threading/ExitThread/test2/test2.c
new file mode 100644
index 0000000000..c31af8a079
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/ExitThread/test2/test2.c
@@ -0,0 +1,168 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================================
+**
+** Source: test2.c
+**
+** Purpose: Test to ensure ExitThread() called from the last thread of
+** a process shuts down that process and returns the proper
+** exit code as specified in the ExitThread() call.
+**
+** Dependencies: PAL_Initialize
+** PAL_Terminate
+** Fail
+** ZeroMemory
+** GetCurrentDirectoryW
+** CreateProcessW
+** WaitForSingleObject
+** GetLastError
+** strlen
+** strncpy
+**
+
+**
+**===========================================================================*/
+#include <palsuite.h>
+#include "myexitcode.h"
+
+
+static const char* rgchPathDelim = "\\";
+
+
+int
+mkAbsoluteFilename( LPSTR dirName,
+ DWORD dwDirLength,
+ LPCSTR fileName,
+ DWORD dwFileLength,
+ LPSTR absPathName )
+{
+ DWORD sizeDN, sizeFN, sizeAPN;
+
+ sizeDN = strlen( dirName );
+ sizeFN = strlen( fileName );
+ sizeAPN = (sizeDN + 1 + sizeFN + 1);
+
+ /* ensure ((dirName + DELIM + fileName + \0) =< _MAX_PATH ) */
+ if( sizeAPN > _MAX_PATH )
+ {
+ return ( 0 );
+ }
+
+ strncpy( absPathName, dirName, dwDirLength +1 );
+ strncpy( absPathName, rgchPathDelim, 2 );
+ strncpy( absPathName, fileName, dwFileLength +1 );
+
+ return (sizeAPN);
+
+}
+
+
+int __cdecl main( int argc, char **argv )
+
+{
+ const char* rgchChildFile = "childprocess";
+
+ STARTUPINFO si;
+ PROCESS_INFORMATION pi;
+
+ DWORD dwError;
+ DWORD dwExitCode;
+ DWORD dwFileLength;
+ DWORD dwDirLength;
+ DWORD dwSize;
+ DWORD dwExpected = TEST_EXIT_CODE;
+
+ char rgchDirName[_MAX_DIR];
+ char absPathBuf[_MAX_PATH];
+ char* rgchAbsPathName;
+
+ /* initialize the PAL */
+ if( PAL_Initialize(argc, argv) != 0 )
+ {
+ return( FAIL );
+ }
+
+ /* zero our process and startup info structures */
+ ZeroMemory( &si, sizeof(si) );
+ si.cb = sizeof( si );
+ ZeroMemory( &pi, sizeof(pi) );
+
+ /* build the absolute path to the child process */
+ rgchAbsPathName = &absPathBuf[0];
+ dwFileLength = strlen( rgchChildFile );
+
+ dwDirLength = GetCurrentDirectory( _MAX_PATH, rgchDirName );
+ if( dwDirLength == 0 )
+ {
+ dwError = GetLastError();
+ Fail( "GetCurrentDirectory call failed with error code %d\n",
+ dwError );
+ }
+
+ dwSize = mkAbsoluteFilename( rgchDirName,
+ dwDirLength,
+ rgchChildFile,
+ dwFileLength,
+ rgchAbsPathName );
+ if( dwSize == 0 )
+ {
+ Fail( "Palsuite Code: mkAbsoluteFilename() call failed. Could ",
+ "not build absolute path name to file\n. Exiting.\n" );
+ }
+
+ /* launch the child process */
+ if( !CreateProcess( NULL, /* module name to execute */
+ rgchAbsPathName, /* command line */
+ NULL, /* process handle not */
+ /* inheritable */
+ NULL, /* thread handle not */
+ /* inheritable */
+ FALSE, /* handle inheritance */
+ CREATE_NEW_CONSOLE, /* dwCreationFlags */
+ NULL, /* use parent's environment */
+ NULL, /* use parent's starting */
+ /* directory */
+ &si, /* startup info struct */
+ &pi ) /* process info struct */
+ )
+ {
+ dwError = GetLastError();
+ Fail( "CreateProcess call failed with error code %d\n",
+ dwError );
+ }
+
+ /* wait for the child process to complete */
+ WaitForSingleObject ( pi.hProcess, INFINITE );
+
+ /* check the exit code from the process */
+ if( ! GetExitCodeProcess( pi.hProcess, &dwExitCode ) )
+ {
+ dwError = GetLastError();
+ CloseHandle ( pi.hProcess );
+ CloseHandle ( pi.hThread );
+ Fail( "GetExitCodeProcess call failed with error code %d\n",
+ dwError );
+ }
+
+ /* close process and thread handle */
+ CloseHandle ( pi.hProcess );
+ CloseHandle ( pi.hThread );
+
+ /* check for the expected exit code */
+ /* exit code for some systems is as small as a char, so that's all */
+ /* we'll compare for checking success */
+ if( LOBYTE(LOWORD(dwExitCode)) != LOBYTE(LOWORD(dwExpected)) )
+ {
+ Fail( "GetExitCodeProcess returned an incorrect exit code %d, "
+ "expected value is %d\n",
+ LOWORD(dwExitCode), dwExpected );
+ }
+
+ /* terminate the PAL */
+ PAL_Terminate();
+
+ /* return success */
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/threading/ExitThread/test2/testinfo.dat b/src/pal/tests/palsuite/threading/ExitThread/test2/testinfo.dat
new file mode 100644
index 0000000000..4b5bdc2ac6
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/ExitThread/test2/testinfo.dat
@@ -0,0 +1,19 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = ExitThread
+Name = Test for ExitThread
+TYPE = DEFAULT
+EXE1 = test2
+EXE2 = childprocess
+Description
+= Test to ensure proper operation of the ExitThread
+= API. This test launches a simple child process that exits
+= by calling ExitThread() with a known value, and checks
+= that the correct value is returned to the parent process.
+= This verifies that when the last thread of a process exits
+= via ExitThread, the process exits with the proper return
+= code.
diff --git a/src/pal/tests/palsuite/threading/ExitThread/test3/dllmain.c b/src/pal/tests/palsuite/threading/ExitThread/test3/dllmain.c
new file mode 100644
index 0000000000..923650d1d3
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/ExitThread/test3/dllmain.c
@@ -0,0 +1,65 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================================
+**
+** Source: dllmain.c
+**
+** Purpose: Test to ensure DllMain() is called with THREAD_DETACH
+** when a thread in the application calls ExitThread().
+**
+** Dependencies: none
+**
+
+**
+**===========================================================================*/
+
+#include <palsuite.h>
+
+/* count of the number of times DllMain() was called with THREAD_DETACH */
+static int g_detachCount = 0;
+
+
+/* standard DllMain() */
+BOOL PALAPI DllMain(HINSTANCE hinstDLL, DWORD reason, LPVOID lpvReserved)
+{
+ switch( reason )
+ {
+ case DLL_PROCESS_ATTACH:
+ {
+ break;
+ }
+
+ case DLL_PROCESS_DETACH:
+ {
+ break;
+ }
+
+ case DLL_THREAD_ATTACH:
+ break;
+
+ case DLL_THREAD_DETACH:
+ /* increment g_detachCount */
+ g_detachCount++;
+ break;
+ }
+ return TRUE;
+}
+
+#ifdef WIN32
+BOOL __stdcall _DllMainCRTStartup(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
+{
+ return DllMain(hinstDLL, fdwReason, lpvReserved);
+}
+#endif
+
+
+/* function to return the current detach count */
+#ifdef WIN32
+__declspec(dllexport)
+#endif
+int PALAPI GetDetachCount( void )
+{
+ return g_detachCount;
+}
diff --git a/src/pal/tests/palsuite/threading/ExitThread/test3/test3.c b/src/pal/tests/palsuite/threading/ExitThread/test3/test3.c
new file mode 100644
index 0000000000..8a71c7cc99
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/ExitThread/test3/test3.c
@@ -0,0 +1,162 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================================
+**
+** Source: test3.c
+**
+** Purpose: Test to ensure ExitThread() results in any loaded dynamic
+** libraries having their entry point called with a THREAD_DETACH
+** notification.
+**
+** Dependencies: PAL_Initialize
+** PAL_Terminate
+** Fail
+** GetCurrentDirectoryW
+** CreateThread
+** ResumeThread
+** LoadLibrary
+** FreeLibrary
+** GetProcAddress
+** WaitForSingleObject
+** GetLastError
+** strlen
+** strncpy
+**
+
+**
+**===========================================================================*/
+#include <palsuite.h>
+
+/* SHLEXT is defined only for Unix variants */
+
+#if defined(SHLEXT)
+#define rgchLibraryFile "dllmain"SHLEXT
+#define szFunction "GetDetachCount"
+#else
+#define rgchLibraryFile "dllmain"
+#define szFunction "_GetDetachCount@0"
+#endif
+
+/* define our test function type */
+typedef int ( PALAPI *LPTESTFUNC )( void );
+
+
+/**
+ * ThreadFunc
+ *
+ * Dummy thread function for causing DLL thread notifications.
+ */
+DWORD PALAPI ThreadFunc( LPVOID param )
+{
+ /* simulate some brief "work" */
+ int i;
+ for( i=0; i<100000; i++ )
+ ;
+
+ ExitThread( 0 );
+ return (0);
+}
+
+
+/* main program entry point */
+int __cdecl main( int argc, char **argv )
+
+{
+ /* local variables */
+
+ HANDLE hLib = NULL;
+ LPTESTFUNC pFunc;
+ int detachCount1 = 0;
+ int detachCount2 = 0;
+
+ HANDLE hThread = NULL;
+ DWORD IDThread;
+
+ /* initialize the PAL */
+ if( PAL_Initialize(argc, argv) != 0 )
+ {
+ return( FAIL );
+ }
+
+ /* Load the test library */
+ hLib = LoadLibrary( rgchLibraryFile );
+ if(hLib == NULL)
+ {
+ Fail("ERROR: Unable to load library %s\n", rgchLibraryFile );
+ }
+
+
+ /* Get the address of our test function in the dll */
+ pFunc = (LPTESTFUNC)GetProcAddress( hLib, szFunction );
+ if( pFunc == NULL )
+ {
+ Trace( "ERROR:%lu%:Unable to load function \"%s\" library \"%s\"\n",
+ GetLastError(),
+ szFunction,
+ rgchLibraryFile );
+ if( ! FreeLibrary( hLib ) ) {
+ Trace( "FreeLibrary() failed with error code %lu\n",
+ GetLastError() );
+ }
+ Fail( "Exiting\n" );
+ }
+
+ /* Execute the test function to get the detach count */
+ detachCount1 = pFunc();
+
+ /* run another dummy thread to cause notification of the library */
+ hThread = CreateThread( NULL, /* no security attributes */
+ 0, /* use default stack size */
+ (LPTHREAD_START_ROUTINE) ThreadFunc, /* thread function */
+ (LPVOID) NULL, /* pass thread index as */
+ /* function argument */
+ CREATE_SUSPENDED, /* create suspended */
+ &IDThread ); /* returns thread id */
+
+ /* Check the return value for success. */
+ if( hThread == NULL )
+ {
+ /* error creating thread */
+ Trace( "Unexpected CreateThread error %d\n",
+ GetLastError() );
+ if( ! FreeLibrary( hLib ) ) {
+ Trace( "FreeLibrary() failed with error code %lu\n",
+ GetLastError() );
+ }
+ Fail( "Exiting\n" );
+ }
+
+ /* Resume the suspended thread */
+ ResumeThread( hThread );
+
+ /* wait for the thread to complete */
+ WaitForSingleObject( hThread, INFINITE );
+
+ /* Execute the test function to get the new detach count */
+ detachCount2 = pFunc();
+
+ /* Unload the test library */
+ if( !FreeLibrary( hLib ) )
+ {
+ Fail( "ERROR:%u: Unable to free library \"%s\"\n",
+ GetLastError(),
+ rgchLibraryFile );
+ }
+
+ /* validate the result */
+ if( detachCount2 != (detachCount1 + 1) )
+ {
+ Fail( "FAIL: unexpected DLL detach count %d, expected %d\n",
+ detachCount2,
+ (detachCount1 + 1) );
+ }
+
+
+ /* terminate the PAL */
+ PAL_Terminate();
+
+ /* return success */
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/threading/ExitThread/test3/testinfo.dat b/src/pal/tests/palsuite/threading/ExitThread/test3/testinfo.dat
new file mode 100644
index 0000000000..1c9e8c7567
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/ExitThread/test3/testinfo.dat
@@ -0,0 +1,16 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = ExitThread
+Name = Test for ExitThread
+TYPE = DEFAULT
+EXE1 = test3
+LIB1 = dllmain
+Description
+= Test to ensure proper operation of the ExitThread
+= API. This tests to make sure ExitThread() results
+= in any loaded dynamic libraries having their entry
+= point called with a THREAD_DETACH notification.
diff --git a/src/pal/tests/palsuite/threading/GetCurrentProcess/CMakeLists.txt b/src/pal/tests/palsuite/threading/GetCurrentProcess/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/GetCurrentProcess/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/threading/GetCurrentProcess/test1/CMakeLists.txt b/src/pal/tests/palsuite/threading/GetCurrentProcess/test1/CMakeLists.txt
new file mode 100644
index 0000000000..44105348be
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/GetCurrentProcess/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ process.c
+)
+
+add_executable(paltest_getcurrentprocess_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getcurrentprocess_test1 coreclrpal)
+
+target_link_libraries(paltest_getcurrentprocess_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/GetCurrentProcess/test1/process.c b/src/pal/tests/palsuite/threading/GetCurrentProcess/test1/process.c
new file mode 100644
index 0000000000..17d9af6282
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/GetCurrentProcess/test1/process.c
@@ -0,0 +1,40 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: GetCurrentProcess/test1/process.c
+**
+** Purpose: Test for to see if the process GetCurrentProcess
+** returns a handle to the current process or not.
+**
+** Dependencies: TerminateProcess
+**
+**
+**=========================================================*/
+
+#include <palsuite.h>
+
+INT __cdecl main( int argc, char **argv )
+{
+
+ HANDLE hProcess;
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return ( FAIL );
+ }
+
+ hProcess = GetCurrentProcess();
+ Trace ("Testing the handle returned by GetCurrentProcess\n");
+ if ( 0 == ( TerminateProcess ( hProcess, PASS ) ) )
+ {
+ Fail ("Testing GetCurrentProcess, the TerminateProcess function "
+ "failed.\n");
+ }
+
+ PAL_Terminate();
+ return ( PASS );
+
+}
diff --git a/src/pal/tests/palsuite/threading/GetCurrentProcess/test1/testinfo.dat b/src/pal/tests/palsuite/threading/GetCurrentProcess/test1/testinfo.dat
new file mode 100644
index 0000000000..8eb2759fb9
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/GetCurrentProcess/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = GetCurrentProcess
+Name = Positive Test for GetCurrentProcess
+TYPE = DEFAULT
+EXE1 = process
+Description
+= Test to see if the function GetCurrentProcess returns a handle to the
+= current process or not.
diff --git a/src/pal/tests/palsuite/threading/GetCurrentProcessId/CMakeLists.txt b/src/pal/tests/palsuite/threading/GetCurrentProcessId/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/GetCurrentProcessId/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/threading/GetCurrentProcessId/test1/CMakeLists.txt b/src/pal/tests/palsuite/threading/GetCurrentProcessId/test1/CMakeLists.txt
new file mode 100644
index 0000000000..e5c31e6af2
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/GetCurrentProcessId/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ processId.c
+)
+
+add_executable(paltest_getcurrentprocessid_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getcurrentprocessid_test1 coreclrpal)
+
+target_link_libraries(paltest_getcurrentprocessid_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/GetCurrentProcessId/test1/processId.c b/src/pal/tests/palsuite/threading/GetCurrentProcessId/test1/processId.c
new file mode 100644
index 0000000000..cc689b3f8b
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/GetCurrentProcessId/test1/processId.c
@@ -0,0 +1,41 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: getcurrentprocessid/test1/processid.c
+**
+** Purpose: Test to ensure GetCurrentProcessId returns the current
+** process id number. This test compares the result of
+** GetCurrentProcessId to getpid.
+**
+**
+**=========================================================*/
+
+#include <palsuite.h>
+
+INT __cdecl main( int argc, char **argv )
+{
+
+ DWORD dwProcessId;
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return ( FAIL );
+ }
+
+ dwProcessId = GetCurrentProcessId();
+
+ if ( 0 >= dwProcessId )
+ {
+ Fail ("%s has dwProcessId has id value %d\n", argv[0],
+ dwProcessId );
+ }
+ Trace ("%s has dwProcessId %d\nPassing test as dwProcessId is > 0\n"
+ , argv[0], dwProcessId);
+
+ PAL_Terminate();
+ return ( PASS );
+
+}
diff --git a/src/pal/tests/palsuite/threading/GetCurrentProcessId/test1/testinfo.dat b/src/pal/tests/palsuite/threading/GetCurrentProcessId/test1/testinfo.dat
new file mode 100644
index 0000000000..db615c0bf9
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/GetCurrentProcessId/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = GetCurrentProcessId
+Name = Positive Test for GetCurrentProcessId
+TYPE = DEFAULT
+EXE1 = processid
+Description
+= Test to ensure GetCurrentProcessId returns the current process id number.
+= This test compares the result of GetCurrentProcessId to getpid.
diff --git a/src/pal/tests/palsuite/threading/GetCurrentThread/CMakeLists.txt b/src/pal/tests/palsuite/threading/GetCurrentThread/CMakeLists.txt
new file mode 100644
index 0000000000..ef14ea5352
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/GetCurrentThread/CMakeLists.txt
@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+
diff --git a/src/pal/tests/palsuite/threading/GetCurrentThread/test1/CMakeLists.txt b/src/pal/tests/palsuite/threading/GetCurrentThread/test1/CMakeLists.txt
new file mode 100644
index 0000000000..84cbccbca0
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/GetCurrentThread/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ thread.c
+)
+
+add_executable(paltest_getcurrentthread_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getcurrentthread_test1 coreclrpal)
+
+target_link_libraries(paltest_getcurrentthread_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/GetCurrentThread/test1/testinfo.dat b/src/pal/tests/palsuite/threading/GetCurrentThread/test1/testinfo.dat
new file mode 100644
index 0000000000..29c9767ed0
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/GetCurrentThread/test1/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = GetCurrentThread
+Name = Positive Test for GetCurrentThread
+TYPE = DEFAULT
+EXE1 = thread
+Description
+= Test to ensure GetCurrentThread returns a handle to the current thread.
diff --git a/src/pal/tests/palsuite/threading/GetCurrentThread/test1/thread.c b/src/pal/tests/palsuite/threading/GetCurrentThread/test1/thread.c
new file mode 100644
index 0000000000..b2bb97fd67
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/GetCurrentThread/test1/thread.c
@@ -0,0 +1,93 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: GetCurrentThread/test1/thread.c
+**
+** Purpose: Test to ensure GetCurrentThread returns a handle to
+** the current thread.
+**
+** Dependencies: GetThreadPriority
+** SetThreadPriority
+** Fail
+** Trace
+**
+
+**
+**=========================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main( int argc, char **argv )
+{
+
+ HANDLE hThread;
+ int nPriority;
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return ( FAIL );
+ }
+
+#if !HAVE_SCHED_OTHER_ASSIGNABLE
+ /* Defining thread priority for SCHED_OTHER is implementation defined.
+ Some platforms like NetBSD cannot reassign it as they are dynamic.
+ */
+ printf("paltest_getcurrentthread_test1 has been disabled on this platform\n");
+#else
+ hThread = GetCurrentThread();
+
+ nPriority = GetThreadPriority(hThread);
+
+ if ( THREAD_PRIORITY_NORMAL != nPriority )
+ {
+ if ( THREAD_PRIORITY_ERROR_RETURN == nPriority )
+ {
+ Fail ("GetThreadPriority function call failed for %s\n"
+ "GetLastError returned %d\n", argv[0], GetLastError());
+ }
+ else
+ {
+ Fail ("GetThreadPriority function call failed for %s\n"
+ "The priority returned was %d\n", argv[0], nPriority);
+ }
+ }
+ else
+ {
+ nPriority = 0;
+
+ if (0 == SetThreadPriority(hThread, THREAD_PRIORITY_HIGHEST))
+ {
+ Fail ("Unable to set thread priority. Either handle doesn't"
+ " point to current thread \nor SetThreadPriority "
+ "function failed. Failing test.\n");
+ }
+
+ nPriority = GetThreadPriority(hThread);
+
+ if ( THREAD_PRIORITY_ERROR_RETURN == nPriority )
+ {
+ Fail ("GetThreadPriority function call failed for %s\n"
+ "GetLastError returned %d\n", argv[0], GetLastError());
+ }
+ else if ( THREAD_PRIORITY_HIGHEST == nPriority )
+ {
+ Trace ("GetCurrentThread returns handle to the current "
+ "thread.\n");
+ exit ( PASS );
+ }
+ else
+ {
+ Fail ("Unable to set thread priority. Either handle doesn't"
+ " point to current thread \nor SetThreadPriority "
+ "function failed. Failing test.\n");
+ }
+ }
+#endif
+
+ PAL_Terminate();
+ return ( PASS );
+
+}
diff --git a/src/pal/tests/palsuite/threading/GetCurrentThread/test2/CMakeLists.txt b/src/pal/tests/palsuite/threading/GetCurrentThread/test2/CMakeLists.txt
new file mode 100644
index 0000000000..3fc3c3e7c6
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/GetCurrentThread/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test2.c
+)
+
+add_executable(paltest_getcurrentthread_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getcurrentthread_test2 coreclrpal)
+
+target_link_libraries(paltest_getcurrentthread_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/GetCurrentThread/test2/test2.c b/src/pal/tests/palsuite/threading/GetCurrentThread/test2/test2.c
new file mode 100644
index 0000000000..beeb5ec241
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/GetCurrentThread/test2/test2.c
@@ -0,0 +1,144 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================================
+**
+** Source: test2.c
+**
+** Dependencies: PAL_Initialize
+** PAL_Terminate
+** Fail
+** CreateThread
+** SetThreadPriority
+** GetThreadPriority
+** ResumeThread
+** WaitForSingleObject
+** GetLastError
+**
+** Purpose:
+**
+** Test to ensure proper operation of the GetCurrentThread()
+** API. The test launches a thread in suspended mode, and sets
+** its priority to a non-default value using the handle returned
+** by CreateThread(). The new thread calls GetCurrentThred() to
+** retrieve a handle to itself, and calls GetThreadPriority()
+** to verify that its priority matches what it was set to on
+** the main execution thread.
+**
+
+**
+**===========================================================================*/
+#include <palsuite.h>
+
+
+/* we store the return code from the child thread here because */
+/* we're missing the GetExitCodeThread() API */
+
+static int g_priority = 0;
+
+/**
+ * ThreadFunc
+ *
+ * Thread function that calls GetCurrentThread() to get a pseudo-handle
+ * to itself, then checks its priority and exits with that value.
+ */
+DWORD PALAPI ThreadFunc( LPVOID param )
+{
+ int priority;
+ HANDLE hThread;
+
+ /* call GetCurrentThread() to get a pseudo-handle to */
+ /* the current thread */
+ hThread = GetCurrentThread();
+ if( hThread == NULL )
+ {
+ Fail( "GetCurrentThread() call failed\n" );
+ }
+
+
+ /* get the current thread priority */
+ priority = GetThreadPriority( hThread );
+ if( priority == THREAD_PRIORITY_ERROR_RETURN )
+ {
+ /* GetThreadPriority call failed */
+ Fail( "ERROR:%lu:GetThreadPriority() call failed\n", GetLastError() );
+ }
+
+ /* store this globally because we don't have GetExitCodeThread() */
+ g_priority = priority;
+ return (DWORD)priority;
+}
+
+
+/**
+ * main
+ *
+ * executable entry point
+ */
+INT __cdecl main( INT argc, CHAR **argv )
+{
+ HANDLE hThread = NULL;
+ DWORD IDThread;
+ DWORD dwRet;
+
+ SIZE_T i = 0;
+
+ /* PAL initialization */
+ if( (PAL_Initialize(argc, argv)) != 0 )
+ {
+ return( FAIL );
+ }
+
+#if !HAVE_SCHED_OTHER_ASSIGNABLE
+ /* Defining thread priority for SCHED_OTHER is implementation defined.
+ Some platforms like NetBSD cannot reassign it as they are dynamic.
+ */
+ printf("paltest_getcurrentthread_test2 has been disabled on this platform\n");
+#else
+ /* Create multiple threads. */
+ hThread = CreateThread( NULL, /* no security attributes */
+ 0, /* use default stack size */
+ (LPTHREAD_START_ROUTINE) ThreadFunc, /* thread function */
+ (LPVOID) i, /* pass thread index as */
+ /* function argument */
+ CREATE_SUSPENDED, /* create suspended */
+ &IDThread ); /* returns thread identifier */
+
+ /* Check the return value for success. */
+ if( hThread == NULL )
+ {
+ /* ERROR */
+ Fail( "ERROR:%lu:CreateThread failed\n", GetLastError() );
+ }
+
+ /* set the thread priority of the new thread to the highest value */
+ if( ! SetThreadPriority( hThread, THREAD_PRIORITY_TIME_CRITICAL) )
+ {
+ Fail( "ERROR:%lu:SetThreadPriority() call failed\n", GetLastError() );
+ }
+
+ /* let the child thread run now */
+ ResumeThread( hThread );
+
+
+ /* wait for the thread to finish */
+ dwRet = WaitForSingleObject( hThread, INFINITE );
+ if( dwRet == WAIT_FAILED )
+ {
+ /* ERROR */
+ Fail( "ERROR:%lu:WaitForSingleObject call failed\n", GetLastError() );
+ }
+
+ /* validate the thread's exit code */
+ if( g_priority != THREAD_PRIORITY_TIME_CRITICAL )
+ {
+ /* ERROR */
+ Fail( "FAIL:Unexpected thread priority %d returned, expected %d\n",
+ g_priority, THREAD_PRIORITY_TIME_CRITICAL );
+ }
+#endif
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/threading/GetCurrentThread/test2/testinfo.dat b/src/pal/tests/palsuite/threading/GetCurrentThread/test2/testinfo.dat
new file mode 100644
index 0000000000..96a6d403bb
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/GetCurrentThread/test2/testinfo.dat
@@ -0,0 +1,18 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = GetCurrentThread
+Name = Test for GetCurrentThread
+TYPE = DEFAULT
+EXE1 = test2
+Description
+= Test to ensure proper operation of the GetCurrentThread()
+= API. The test launches a thread in suspended mode, and sets
+= its priority to a non-default value using the handle returned
+= by CreateThread(). The new thread calls GetCurrentThred() to
+= retrieve a handle to itself, and calls GetThreadPriority()
+= to verify that its priority matches what it was set to on
+= the main execution thread.
diff --git a/src/pal/tests/palsuite/threading/GetCurrentThreadId/CMakeLists.txt b/src/pal/tests/palsuite/threading/GetCurrentThreadId/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/GetCurrentThreadId/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/threading/GetCurrentThreadId/test1/CMakeLists.txt b/src/pal/tests/palsuite/threading/GetCurrentThreadId/test1/CMakeLists.txt
new file mode 100644
index 0000000000..490bff8f5f
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/GetCurrentThreadId/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ threadId.c
+)
+
+add_executable(paltest_getcurrentthreadid_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getcurrentthreadid_test1 coreclrpal)
+
+target_link_libraries(paltest_getcurrentthreadid_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/GetCurrentThreadId/test1/testinfo.dat b/src/pal/tests/palsuite/threading/GetCurrentThreadId/test1/testinfo.dat
new file mode 100644
index 0000000000..4d1e056b71
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/GetCurrentThreadId/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = GetCurrentThreadId
+Name = Positive Test for GetCurrentThreadId
+TYPE = DEFAULT
+EXE1 = threadid
+Description
+= Test to ensure GetCurrentThreadId returns the threadId of the current
+= thread.
diff --git a/src/pal/tests/palsuite/threading/GetCurrentThreadId/test1/threadId.c b/src/pal/tests/palsuite/threading/GetCurrentThreadId/test1/threadId.c
new file mode 100644
index 0000000000..acbb1ff373
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/GetCurrentThreadId/test1/threadId.c
@@ -0,0 +1,82 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: getcurrentthreadid/test1/threadid.c
+**
+** Purpose: Test to ensure GetCurrentThreadId returns the threadId of the
+** current thread.
+**
+** Dependencies: CloseHandle
+** WaitForSingleObject
+** CreateThread
+**
+
+**
+**=========================================================*/
+
+
+#include <palsuite.h>
+
+DWORD dwThreadIdTF;
+
+DWORD PALAPI ThreadFunction ( LPVOID lpParam )
+{
+ Trace ("thread code executed\n");
+ dwThreadIdTF = GetCurrentThreadId();
+ return 0;
+}
+
+int __cdecl main( int argc, char **argv )
+{
+ extern DWORD dwThreadIdTF;
+ DWORD dwThreadIdCT;
+ HANDLE hThread;
+ DWORD dwThreadParam = 1;
+ DWORD dwThreadWait;
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return ( FAIL );
+ }
+
+ hThread = CreateThread(
+ NULL,
+ 0,
+ ThreadFunction,
+ &dwThreadParam,
+ 0,
+ &dwThreadIdCT);
+
+ if ( NULL == hThread )
+ {
+ Fail ( "CreateThread() call failed - returned NULL");
+ }
+ else
+ {
+ dwThreadWait = WaitForSingleObject( hThread, INFINITE );
+
+ Trace ("dwThreadWait returned %d\n", dwThreadWait );
+
+ if ( dwThreadIdCT == dwThreadIdTF )
+ {
+ Trace ( "ThreadId numbers match - GetCurrentThreadId"
+ " works. dwThreadIdCT == dwThreadIdTF == %d\n",
+ dwThreadIdTF );
+ PAL_Terminate();
+ return ( PASS );
+ }
+ else
+ {
+ Fail ( "ThreadId numbers don't match - "
+ "GetCurrentThreadId fails dwThreadIdCT = %d "
+ "and dwThreadIdTF = %d\n", dwThreadIdCT, dwThreadIdTF);
+ }
+ }
+
+ PAL_TerminateEx(FAIL);
+ return (FAIL);
+
+}
diff --git a/src/pal/tests/palsuite/threading/GetExitCodeProcess/CMakeLists.txt b/src/pal/tests/palsuite/threading/GetExitCodeProcess/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/GetExitCodeProcess/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/threading/GetExitCodeProcess/test1/CMakeLists.txt b/src/pal/tests/palsuite/threading/GetExitCodeProcess/test1/CMakeLists.txt
new file mode 100644
index 0000000000..adddd97e6d
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/GetExitCodeProcess/test1/CMakeLists.txt
@@ -0,0 +1,36 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(TESTSOURCES
+ test1.c
+)
+
+add_executable(paltest_getexitcodeprocess_test1
+ ${TESTSOURCES}
+)
+
+add_dependencies(paltest_getexitcodeprocess_test1 coreclrpal)
+
+target_link_libraries(paltest_getexitcodeprocess_test1
+ pthread
+ m
+ coreclrpal
+)
+
+
+set(HELPERSOURCES
+ childProcess.c
+)
+
+add_executable(paltest_getexitcodeprocess_test1_child
+ ${HELPERSOURCES}
+)
+
+add_dependencies(paltest_getexitcodeprocess_test1_child coreclrpal)
+
+target_link_libraries(paltest_getexitcodeprocess_test1_child
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/GetExitCodeProcess/test1/childProcess.c b/src/pal/tests/palsuite/threading/GetExitCodeProcess/test1/childProcess.c
new file mode 100644
index 0000000000..fe1b38fb31
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/GetExitCodeProcess/test1/childProcess.c
@@ -0,0 +1,31 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: childprocess.c
+**
+** Purpose: Test to ensure GetExitCodeProcess returns the right
+** value. All this program does is return a predefined value.
+**
+** Dependencies: none
+**
+
+**
+**=========================================================*/
+
+#include <pal.h>
+#include "myexitcode.h"
+
+int __cdecl main( int argc, char **argv )
+{
+ int i;
+
+ // simulate some activity
+ for( i=0; i<10000; i++ )
+ ;
+
+ // return the predefined exit code
+ return TEST_EXIT_CODE;
+}
diff --git a/src/pal/tests/palsuite/threading/GetExitCodeProcess/test1/myexitcode.h b/src/pal/tests/palsuite/threading/GetExitCodeProcess/test1/myexitcode.h
new file mode 100644
index 0000000000..60a140d1f3
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/GetExitCodeProcess/test1/myexitcode.h
@@ -0,0 +1,14 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: myexitcode.h
+**
+** Purpose: Define an exit code.
+**
+**
+**==========================================================================*/
+
+#define TEST_EXIT_CODE 104
diff --git a/src/pal/tests/palsuite/threading/GetExitCodeProcess/test1/test1.c b/src/pal/tests/palsuite/threading/GetExitCodeProcess/test1/test1.c
new file mode 100644
index 0000000000..0f98cf8f57
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/GetExitCodeProcess/test1/test1.c
@@ -0,0 +1,163 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Test to ensure GetExitCodeProcess works properly.
+**
+** Dependencies: PAL_Initialize
+** PAL_Terminate
+** Fail
+** ZeroMemory
+** GetCurrentDirectoryW
+** CreateProcessW
+** WaitForSingleObject
+** GetLastError
+** strlen
+** strncpy
+**
+
+**
+**===========================================================================*/
+#include <palsuite.h>
+#include "myexitcode.h"
+
+
+static const char* rgchPathDelim = "\\";
+
+
+int
+mkAbsoluteFilename( LPSTR dirName,
+ DWORD dwDirLength,
+ LPCSTR fileName,
+ DWORD dwFileLength,
+ LPSTR absPathName )
+{
+ DWORD sizeDN, sizeFN, sizeAPN;
+
+ sizeDN = strlen( dirName );
+ sizeFN = strlen( fileName );
+ sizeAPN = (sizeDN + 1 + sizeFN + 1);
+
+ /* ensure ((dirName + DELIM + fileName + \0) =< _MAX_PATH ) */
+ if( sizeAPN > _MAX_PATH )
+ {
+ return ( 0 );
+ }
+
+ strncpy( absPathName, dirName, dwDirLength +1 );
+ strncpy( absPathName, rgchPathDelim, 2 );
+ strncpy( absPathName, fileName, dwFileLength +1 );
+
+ return (sizeAPN);
+
+}
+
+
+int __cdecl main( int argc, char **argv )
+
+{
+ const char* rgchChildFile = "childprocess";
+
+ STARTUPINFO si;
+ PROCESS_INFORMATION pi;
+
+ DWORD dwError;
+ DWORD dwExitCode;
+ DWORD dwFileLength;
+ DWORD dwDirLength;
+ DWORD dwSize;
+
+ char rgchDirName[_MAX_DIR];
+ char absPathBuf[_MAX_PATH];
+ char* rgchAbsPathName;
+
+ /* initialize the PAL */
+ if( PAL_Initialize(argc, argv) != 0 )
+ {
+ return( FAIL );
+ }
+
+ /* zero our process and startup info structures */
+ ZeroMemory( &si, sizeof(si) );
+ si.cb = sizeof( si );
+ ZeroMemory( &pi, sizeof(pi) );
+
+ /* build the absolute path to the child process */
+ rgchAbsPathName = &absPathBuf[0];
+ dwFileLength = strlen( rgchChildFile );
+
+ dwDirLength = GetCurrentDirectory( _MAX_PATH, rgchDirName );
+ if( dwDirLength == 0 )
+ {
+ dwError = GetLastError();
+ Fail( "GetCurrentDirectory call failed with error code %d\n",
+ dwError );
+ }
+
+ dwSize = mkAbsoluteFilename( rgchDirName,
+ dwDirLength,
+ rgchChildFile,
+ dwFileLength,
+ rgchAbsPathName );
+ if( dwSize == 0 )
+ {
+ Fail( "Palsuite Code: mkAbsoluteFilename() call failed. Could ",
+ "not build absolute path name to file\n. Exiting.\n" );
+ }
+
+ /* launch the child process */
+ if( !CreateProcess( NULL, /* module name to execute */
+ rgchAbsPathName, /* command line */
+ NULL, /* process handle not */
+ /* inheritable */
+ NULL, /* thread handle not */
+ /* inheritable */
+ FALSE, /* handle inheritance */
+ CREATE_NEW_CONSOLE, /* dwCreationFlags */
+ NULL, /* use parent's environment */
+ NULL, /* use parent's starting */
+ /* directory */
+ &si, /* startup info struct */
+ &pi ) /* process info struct */
+ )
+ {
+ dwError = GetLastError();
+ Fail( "CreateProcess call failed with error code %d\n",
+ dwError );
+ }
+
+ /* wait for the child process to complete */
+ WaitForSingleObject ( pi.hProcess, INFINITE );
+
+ /* check the exit code from the process */
+ if( ! GetExitCodeProcess( pi.hProcess, &dwExitCode ) )
+ {
+ dwError = GetLastError();
+ CloseHandle ( pi.hProcess );
+ CloseHandle ( pi.hThread );
+ Fail( "GetExitCodeProcess call failed with error code %d\n",
+ dwError );
+ }
+
+ /* close process and thread handle */
+ CloseHandle ( pi.hProcess );
+ CloseHandle ( pi.hThread );
+
+ /* check for the expected exit code */
+ if( dwExitCode != TEST_EXIT_CODE )
+ {
+ Fail( "GetExitCodeProcess returned an incorrect exit code %d, "
+ "expected value is %d\n",
+ dwExitCode, TEST_EXIT_CODE );
+ }
+
+ /* terminate the PAL */
+ PAL_Terminate();
+
+ /* return success */
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/threading/GetExitCodeProcess/test1/testinfo.dat b/src/pal/tests/palsuite/threading/GetExitCodeProcess/test1/testinfo.dat
new file mode 100644
index 0000000000..d06719f0b0
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/GetExitCodeProcess/test1/testinfo.dat
@@ -0,0 +1,16 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = GetExitCodeProcess
+Name = Test for GetExitCodeProcess
+TYPE = DEFAULT
+EXE1 = test1
+EXE2 = childprocess
+Description
+= Test to ensure proper operation of the GetExitCodeProcess
+= API. This test launches a simple child process that exits
+= with a known value, and checks that the correct value is
+= returned by the function.
diff --git a/src/pal/tests/palsuite/threading/GetProcessTimes/CMakeLists.txt b/src/pal/tests/palsuite/threading/GetProcessTimes/CMakeLists.txt
new file mode 100644
index 0000000000..f4796dc1d3
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/GetProcessTimes/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test2)
+
diff --git a/src/pal/tests/palsuite/threading/GetProcessTimes/test2/CMakeLists.txt b/src/pal/tests/palsuite/threading/GetProcessTimes/test2/CMakeLists.txt
new file mode 100644
index 0000000000..0ef7260204
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/GetProcessTimes/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test2.c
+)
+
+add_executable(paltest_getprocesstimes_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getprocesstimes_test2 coreclrpal)
+
+target_link_libraries(paltest_getprocesstimes_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/GetProcessTimes/test2/test2.c b/src/pal/tests/palsuite/threading/GetProcessTimes/test2/test2.c
new file mode 100644
index 0000000000..687facc584
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/GetProcessTimes/test2/test2.c
@@ -0,0 +1,122 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================================
+**
+** Source: test2.c
+**
+** Purpose: Test to ensure GetProcessTimes works properly.
+**
+** Dependencies: PAL_Initialize
+** PAL_Terminate
+** Fail
+** ZeroMemory
+** CompareFileTime
+** GetLastError
+**
+
+**
+**===========================================================================*/
+#include <palsuite.h>
+
+
+int __cdecl main( int argc, char **argv )
+
+{
+ int i, j, k;
+ int *total;
+
+ HANDLE hProcess;
+ FILETIME createTime;
+ FILETIME exitTime;
+ FILETIME kernelTime1;
+ FILETIME userTime1;
+ FILETIME kernelTime2;
+ FILETIME userTime2;
+
+ DWORD dwError;
+
+ /* initialize the PAL */
+ if( PAL_Initialize(argc, argv) != 0 )
+ {
+ return( FAIL );
+ }
+
+ /* get our own process handle */
+ hProcess = GetCurrentProcess();
+ if( hProcess == NULL )
+ {
+ Fail( "GetCurrentProcess() returned a NULL handle.\n" );
+ }
+
+ /* zero our time structures */
+ ZeroMemory( &createTime, sizeof(createTime) );
+ ZeroMemory( &exitTime, sizeof(exitTime) );
+ ZeroMemory( &kernelTime1, sizeof(kernelTime1) );
+ ZeroMemory( &userTime1, sizeof(userTime1) );
+ ZeroMemory( &kernelTime2, sizeof(kernelTime2) );
+ ZeroMemory( &userTime2, sizeof(userTime2) );
+
+ /* check the process times for the child process */
+ if( ! GetProcessTimes( hProcess,
+ &createTime,
+ &exitTime,
+ &kernelTime1,
+ &userTime1 ) )
+ {
+ dwError = GetLastError();
+ Fail( "GetProcessTimes() call failed with error code %d\n",
+ dwError );
+ }
+
+
+ /* simulate some activity */
+ for( i=0; i<1000; i++ )
+ {
+ for( j=0; j<1000; j++ )
+ {
+ /* do kernel work to increase system usage counters */
+ total = malloc(1024 * 1024);
+
+ *total = j * i;
+ for( k=0; k<1000; k++ )
+ {
+ *total += k + i;
+ }
+
+ free(total);
+ }
+ }
+
+ /* check the process times for the child process */
+ if( ! GetProcessTimes( hProcess,
+ &createTime,
+ &exitTime,
+ &kernelTime2,
+ &userTime2 ) )
+ {
+ dwError = GetLastError();
+ Fail( "GetProcessTimes() call failed with error code %d\n",
+ dwError );
+ }
+
+
+ /* very simple logical checking of the results */
+ if( CompareFileTime( &kernelTime1, &kernelTime2 ) > 0 )
+ {
+ Fail( "Unexpected kernel time value reported.\n" );
+ }
+
+ if( CompareFileTime( &userTime1, &userTime2 ) > 0 )
+ {
+ Fail( "Unexpected user time value reported.\n" );
+ }
+
+
+ /* terminate the PAL */
+ PAL_Terminate();
+
+ /* return success */
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/threading/GetProcessTimes/test2/testinfo.dat b/src/pal/tests/palsuite/threading/GetProcessTimes/test2/testinfo.dat
new file mode 100644
index 0000000000..d0d3b75f06
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/GetProcessTimes/test2/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = GetProcessTimes
+Name = Test for GetProcessTimes
+TYPE = DEFAULT
+EXE1 = test2
+Description
+= Test to ensure proper operation of the GetProcessTimes()
+= API. This test simply checks the kernel/user times for the
+= the current process, which is the only thing supported
+= for this function under the PAL.
diff --git a/src/pal/tests/palsuite/threading/GetThreadTimes/CMakeLists.txt b/src/pal/tests/palsuite/threading/GetThreadTimes/CMakeLists.txt
new file mode 100644
index 0000000000..5e1ef7f28b
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/GetThreadTimes/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
diff --git a/src/pal/tests/palsuite/threading/GetThreadTimes/test1/CMakeLists.txt b/src/pal/tests/palsuite/threading/GetThreadTimes/test1/CMakeLists.txt
new file mode 100644
index 0000000000..d7e2eb2a88
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/GetThreadTimes/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_getthreadtimes_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_getthreadtimes_test1 coreclrpal)
+
+target_link_libraries(paltest_getthreadtimes_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/GetThreadTimes/test1/test1.c b/src/pal/tests/palsuite/threading/GetThreadTimes/test1/test1.c
new file mode 100644
index 0000000000..6b62c05ec7
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/GetThreadTimes/test1/test1.c
@@ -0,0 +1,102 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source:
+**
+** Source : test1.c
+**
+** Purpose: Test for GetThreadTimes() function
+**
+**
+**=========================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[]) {
+ int ret = FAIL;
+
+ //Test is failing unreliably, so for now we always return pass.
+ if (TRUE){
+ ret = PASS;
+ goto EXIT;
+ }
+
+ FILETIME kernelTime1, userTime1, kernelTime2, userTime2;
+ /* Delta = .01 sec */
+ LONG64 Actual, Expected, Delta = 850000000;
+ Actual = 0;
+ Expected = 0;
+ const ULONG64 MSEC_TO_NSEC = 1000000;
+
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ HANDLE cThread = GetCurrentThread();
+
+ int i;
+ /* Take 2000 tiny measurements */
+ for (i = 0; i < 2000; i++){
+ ULONG64 Time1, Time2;
+
+ Sleep(1);
+
+ /* Grab a FirstCount, then loop for a bit to make the clock increase */
+ if (!GetThreadTimes(cThread, NULL, NULL, &kernelTime1, &userTime1))
+ {
+ Fail("ERROR: GetThreadTimes returned failure.\n");
+ }
+ LONG64 x, Init;
+ /* Init is in milliseconds, so we will convert later */
+ Init = (ULONG64)GetTickCount();
+ /* Spin for < 1 Quantum so we don't get interrupted */
+ x = Init + 3;
+ volatile int counter;
+ do {
+ for (counter = 0; counter < 100000; counter++)
+ {
+ // spin to consume CPU time
+ }
+
+ } while (x > GetTickCount());
+ Expected += (GetTickCount() - Init) * MSEC_TO_NSEC;
+ /* Get a second count */
+ if (!GetThreadTimes(cThread, NULL, NULL, &kernelTime2, &userTime2))
+ {
+ Fail("ERROR: GetThreadTimes returned failure.\n");
+ }
+
+ Time1 = ((ULONG64)kernelTime1.dwHighDateTime << 32);
+ Time1 += (ULONG64)kernelTime1.dwLowDateTime;
+ Time1 += ((ULONG64)userTime1.dwHighDateTime << 32);
+ Time1 += (ULONG64)userTime1.dwLowDateTime;
+
+ Time2 = ((ULONG64)kernelTime2.dwHighDateTime << 32);
+ Time2 += (ULONG64)kernelTime2.dwLowDateTime;
+ Time2 += ((ULONG64)userTime2.dwHighDateTime << 32);
+ Time2 += (ULONG64)userTime2.dwLowDateTime;
+
+ Actual += (Time2 - Time1) * 100;
+ }
+
+ if(labs(Expected - Actual) > Delta)
+ {
+ Fail("ERROR: The measured time (%llu millisecs) was not within Delta %llu "
+ "of the expected time (%llu millisecs).\n",
+ (Actual / MSEC_TO_NSEC), (Delta / MSEC_TO_NSEC), (Expected / MSEC_TO_NSEC));
+ }
+ //printf("%llu, %llu\n", Expected, Actual);
+ PAL_Terminate();
+ ret = PASS;
+
+EXIT:
+ return ret;
+}
diff --git a/src/pal/tests/palsuite/threading/NamedMutex/CMakeLists.txt b/src/pal/tests/palsuite/threading/NamedMutex/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/NamedMutex/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/threading/NamedMutex/test1/CMakeLists.txt b/src/pal/tests/palsuite/threading/NamedMutex/test1/CMakeLists.txt
new file mode 100644
index 0000000000..315144e1e8
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/NamedMutex/test1/CMakeLists.txt
@@ -0,0 +1,20 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ namedmutex.cpp
+ nopal.cpp
+)
+
+add_executable(paltest_namedmutex_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_namedmutex_test1 coreclrpal)
+
+target_link_libraries(paltest_namedmutex_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/NamedMutex/test1/namedmutex.cpp b/src/pal/tests/palsuite/threading/NamedMutex/test1/namedmutex.cpp
new file mode 100644
index 0000000000..3726214701
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/NamedMutex/test1/namedmutex.cpp
@@ -0,0 +1,1058 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+// These test cases test named mutexes, including positive
+// and negative cases, cross - thread and cross - process, mutual
+// exclusion, abandon detection, etc.
+
+#include <palsuite.h>
+
+#ifndef _countof
+#define _countof(a) (sizeof(a) / sizeof(a[0]))
+#endif // !_countof
+
+const char *const SessionPrefix = "Local\\";
+const char *const GlobalPrefix = "Global\\";
+
+const char *const NamePrefix = "paltest_namedmutex_test1_";
+const char *const TempNamePrefix = "paltest_namedmutex_test1_temp_";
+const char *const InvalidNamePrefix0 = "paltest\\namedmutex_";
+const char *const InvalidNamePrefix1 = "paltest/namedmutex_";
+const char *const ParentEventNamePrefix0 = "paltest_namedmutex_test1_pe0_";
+const char *const ParentEventNamePrefix1 = "paltest_namedmutex_test1_pe1_";
+const char *const ChildEventNamePrefix0 = "paltest_namedmutex_test1_ce0_";
+const char *const ChildEventNamePrefix1 = "paltest_namedmutex_test1_ce1_";
+const char *const ChildRunningEventNamePrefix = "paltest_namedmutex_test1_cr_";
+
+const char *const GlobalShmFilePathPrefix = "/tmp/.dotnet/shm/global/";
+
+#define MaxPathSize (200)
+const DWORD PollLoopSleepMilliseconds = 100;
+const DWORD FailTimeoutMilliseconds = 30000;
+DWORD g_expectedTimeoutMilliseconds = 500;
+
+bool g_isParent = true;
+bool g_isStress = false;
+char g_processPath[4096], g_processCommandLinePath[4096];
+DWORD g_parentPid = static_cast<DWORD>(-1);
+
+extern char *(*test_strcpy)(char *dest, const char *src);
+extern int (*test_strcmp)(const char *s1, const char *s2);
+extern size_t (*test_strlen)(const char *s);
+extern int (*test_sprintf)(char *str, const char *format, ...);
+extern int (*test_sscanf)(const char *str, const char *format, ...);
+extern int(*test_close)(int fd);
+extern int (*test_unlink)(const char *pathname);
+extern unsigned int test_getpid();
+extern int test_kill(unsigned int pid);
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// Test helpers
+
+extern bool TestFileExists(const char *path);
+extern bool WriteHeaderInfo(const char *path, char sharedMemoryType, char version, int *fdRef);
+
+#define TestAssert(expression) \
+ do \
+ { \
+ if (!(expression)) \
+ { \
+ if (!g_isParent) \
+ { \
+ Trace("Child process: "); \
+ } \
+ Trace("'paltest_namedmutex_test1' failed at line %u. Expression: " #expression "\n", __LINE__); \
+ fflush(stdout); \
+ return false; \
+ } \
+ } while(false)
+
+char *BuildName(const char *testName, char *buffer, const char *prefix0, const char *prefix1 = nullptr)
+{
+ size_t nameLength = 0;
+ const char *prefixes[] = {prefix0, prefix1};
+ for (int i = 0; i < 2; ++i)
+ {
+ const char *prefix = prefixes[i];
+ if (prefix == nullptr)
+ {
+ break;
+ }
+ test_strcpy(&buffer[nameLength], prefix);
+ nameLength += test_strlen(prefix);
+ }
+
+ if (g_isStress)
+ {
+ // Append the test name so that tests can run in parallel
+ nameLength += test_sprintf(&buffer[nameLength], "%s", testName);
+ buffer[nameLength++] = '_';
+ }
+
+ nameLength += test_sprintf(&buffer[nameLength], "%u", g_parentPid);
+ return buffer;
+}
+
+char *BuildGlobalShmFilePath(const char *testName, char *buffer, const char *namePrefix)
+{
+ size_t pathLength = 0;
+ test_strcpy(&buffer[pathLength], GlobalShmFilePathPrefix);
+ pathLength += test_strlen(GlobalShmFilePathPrefix);
+ test_strcpy(&buffer[pathLength], namePrefix);
+ pathLength += test_strlen(namePrefix);
+
+ if (g_isStress)
+ {
+ // Append the test name so that tests can run in parallel
+ pathLength += test_sprintf(&buffer[pathLength], "%s", testName);
+ buffer[pathLength++] = '_';
+ }
+
+ pathLength += test_sprintf(&buffer[pathLength], "%u", g_parentPid);
+ return buffer;
+}
+
+class AutoCloseMutexHandle
+{
+private:
+ HANDLE m_handle;
+
+public:
+ AutoCloseMutexHandle(HANDLE handle = nullptr) : m_handle(handle)
+ {
+ }
+
+ ~AutoCloseMutexHandle()
+ {
+ Close();
+ }
+
+public:
+ HANDLE GetHandle() const
+ {
+ return m_handle;
+ }
+
+ bool Release()
+ {
+ return !!ReleaseMutex(m_handle);
+ }
+
+ void Close()
+ {
+ if (m_handle != nullptr)
+ {
+ CloseHandle(m_handle);
+ m_handle = nullptr;
+ }
+ }
+
+ void Abandon()
+ {
+ // Don't close the handle
+ m_handle = nullptr;
+ }
+
+ AutoCloseMutexHandle &operator =(HANDLE handle)
+ {
+ Close();
+ m_handle = handle;
+ return *this;
+ }
+
+ operator HANDLE() const
+ {
+ return m_handle;
+ }
+
+private:
+ AutoCloseMutexHandle(const AutoCloseMutexHandle &other);
+ AutoCloseMutexHandle(AutoCloseMutexHandle &&other);
+ AutoCloseMutexHandle &operator =(const AutoCloseMutexHandle &other);
+};
+
+void TestCreateMutex(AutoCloseMutexHandle &m, const char *name, bool initiallyOwned = false)
+{
+ m.Close();
+ m = CreateMutexA(nullptr, initiallyOwned, name);
+}
+
+HANDLE TestOpenMutex(const char *name)
+{
+ return OpenMutexA(SYNCHRONIZE, false, name);
+}
+
+bool StartProcess(const char *funcName)
+{
+ // Command line format: <processPath> <parentPid> <testFunctionName> [stress]
+
+ size_t processCommandLinePathLength = 0;
+ g_processCommandLinePath[processCommandLinePathLength++] = '\"';
+ test_strcpy(&g_processCommandLinePath[processCommandLinePathLength], g_processPath);
+ processCommandLinePathLength += test_strlen(g_processPath);
+ g_processCommandLinePath[processCommandLinePathLength++] = '\"';
+ g_processCommandLinePath[processCommandLinePathLength++] = ' ';
+ processCommandLinePathLength += test_sprintf(&g_processCommandLinePath[processCommandLinePathLength], "%u", g_parentPid);
+ g_processCommandLinePath[processCommandLinePathLength++] = ' ';
+ test_strcpy(&g_processCommandLinePath[processCommandLinePathLength], funcName);
+ processCommandLinePathLength += test_strlen(funcName);
+
+ if (g_isStress)
+ {
+ test_strcpy(&g_processCommandLinePath[processCommandLinePathLength], " stress");
+ processCommandLinePathLength += _countof("stress") - 1;
+ }
+
+ STARTUPINFO si;
+ memset(&si, 0, sizeof(si));
+ si.cb = sizeof(si);
+ PROCESS_INFORMATION pi;
+ memset(&pi, 0, sizeof(pi));
+ if (!CreateProcessA(nullptr, g_processCommandLinePath, nullptr, nullptr, false, 0, nullptr, nullptr, &si, &pi))
+ {
+ return false;
+ }
+ CloseHandle(pi.hProcess);
+ CloseHandle(pi.hThread);
+ return true;
+}
+
+bool StartThread(LPTHREAD_START_ROUTINE func, void *arg = nullptr, HANDLE *threadHandleRef = nullptr)
+{
+ DWORD threadId;
+ HANDLE handle = CreateThread(nullptr, 0, func, arg, 0, &threadId);
+ if (handle != nullptr)
+ {
+ if (threadHandleRef == nullptr)
+ {
+ CloseHandle(handle);
+ }
+ else
+ {
+ *threadHandleRef = handle;
+ }
+ return true;
+ }
+ return false;
+}
+
+bool WaitForMutexToBeCreated(const char *testName, AutoCloseMutexHandle &m, const char *eventNamePrefix)
+{
+ char eventName[MaxPathSize];
+ BuildName(testName, eventName, GlobalPrefix, eventNamePrefix);
+ DWORD startTime = GetTickCount();
+ while (true)
+ {
+ m = TestOpenMutex(eventName);
+ if (m != nullptr)
+ {
+ return true;
+ }
+ if (GetTickCount() - startTime >= FailTimeoutMilliseconds)
+ {
+ return false;
+ }
+ Sleep(PollLoopSleepMilliseconds);
+ }
+}
+
+// The following functions are used for parent/child tests, where the child runs in a separate thread or process. The tests are
+// organized such that one the parent or child is ever running code, and they yield control and wait for the other. Since the
+// named mutex is the only type of cross-process sync object available, they are used as events to synchronize. The parent and
+// child have a pair of event mutexes each, which they own initially. To release the other waiting thread/process, the
+// thread/process releases one of its mutexes, which the other thread/process would be waiting on. To wait, the thread/process
+// waits on one of the other thread/process' mutexes. All the while, they ping-pong between the two mutexes. YieldToChild() and
+// YieldToParent() below control the releasing, waiting, and ping-ponging, to help create a deterministic path through the
+// parent and child tests while both are running concurrently.
+
+bool AcquireChildRunningEvent(const char *testName, AutoCloseMutexHandle &childRunningEvent)
+{
+ char name[MaxPathSize];
+ TestCreateMutex(childRunningEvent, BuildName(testName, name, GlobalPrefix, ChildRunningEventNamePrefix));
+ TestAssert(WaitForSingleObject(childRunningEvent, FailTimeoutMilliseconds) == WAIT_OBJECT_0);
+ return true;
+}
+
+bool InitializeParent(const char *testName, AutoCloseMutexHandle parentEvents[2], AutoCloseMutexHandle childEvents[2])
+{
+ // Create parent events
+ char name[MaxPathSize];
+ for (int i = 0; i < 2; ++i)
+ {
+ TestCreateMutex(
+ parentEvents[i],
+ BuildName(testName, name, GlobalPrefix, i == 0 ? ParentEventNamePrefix0 : ParentEventNamePrefix1),
+ true);
+ TestAssert(parentEvents[i] != nullptr);
+ TestAssert(GetLastError() != ERROR_ALREADY_EXISTS);
+ }
+
+ // Wait for the child to create and acquire locks on its events so that the parent can wait on them
+ TestAssert(WaitForMutexToBeCreated(testName, childEvents[0], ChildEventNamePrefix0));
+ TestAssert(WaitForMutexToBeCreated(testName, childEvents[1], ChildEventNamePrefix1));
+ return true;
+}
+
+bool UninitializeParent(const char *testName, AutoCloseMutexHandle parentEvents[2], bool releaseParentEvents = true)
+{
+ if (releaseParentEvents)
+ {
+ TestAssert(parentEvents[0].Release());
+ TestAssert(parentEvents[1].Release());
+ }
+
+ // Wait for the child to finish its test. Child tests will release and close 'childEvents' before releasing
+ // 'childRunningEvent', so after this wait, the parent process can freely start another child that will deterministically
+ // recreate the 'childEvents', which the next parent test will wait on, upon its initialization.
+ AutoCloseMutexHandle childRunningEvent;
+ TestAssert(AcquireChildRunningEvent(testName, childRunningEvent));
+ TestAssert(childRunningEvent.Release());
+ return true;
+}
+
+bool InitializeChild(
+ const char *testName,
+ AutoCloseMutexHandle &childRunningEvent,
+ AutoCloseMutexHandle parentEvents[2],
+ AutoCloseMutexHandle childEvents[2])
+{
+ TestAssert(AcquireChildRunningEvent(testName, childRunningEvent));
+
+ // Create child events
+ char name[MaxPathSize];
+ for (int i = 0; i < 2; ++i)
+ {
+ TestCreateMutex(
+ childEvents[i],
+ BuildName(testName, name, GlobalPrefix, i == 0 ? ChildEventNamePrefix0 : ChildEventNamePrefix1),
+ true);
+ TestAssert(childEvents[i] != nullptr);
+ TestAssert(GetLastError() != ERROR_ALREADY_EXISTS);
+ }
+
+ // Wait for the parent to create and acquire locks on its events so that the child can wait on them
+ TestAssert(WaitForMutexToBeCreated(testName, parentEvents[0], ParentEventNamePrefix0));
+ TestAssert(WaitForMutexToBeCreated(testName, parentEvents[1], ParentEventNamePrefix1));
+
+ // Parent/child tests start with the parent, so after initialization, wait for the parent to tell the child test to start
+ TestAssert(WaitForSingleObject(parentEvents[0], FailTimeoutMilliseconds) == WAIT_OBJECT_0);
+ TestAssert(parentEvents[0].Release());
+ return true;
+}
+
+bool UninitializeChild(
+ AutoCloseMutexHandle &childRunningEvent,
+ AutoCloseMutexHandle parentEvents[2],
+ AutoCloseMutexHandle childEvents[2])
+{
+ // Release and close 'parentEvents' and 'childEvents' before releasing 'childRunningEvent' to avoid races, see
+ // UnitializeParent() for more info
+ TestAssert(childEvents[0].Release());
+ TestAssert(childEvents[1].Release());
+ childEvents[0].Close();
+ childEvents[1].Close();
+ parentEvents[0].Close();
+ parentEvents[1].Close();
+ TestAssert(childRunningEvent.Release());
+ return true;
+}
+
+bool YieldToChild(AutoCloseMutexHandle parentEvents[2], AutoCloseMutexHandle childEvents[2], int &ei)
+{
+ TestAssert(parentEvents[ei].Release());
+ TestAssert(WaitForSingleObject(childEvents[ei], FailTimeoutMilliseconds) == WAIT_OBJECT_0);
+ TestAssert(childEvents[ei].Release());
+ TestAssert(WaitForSingleObject(parentEvents[ei], 0) == WAIT_OBJECT_0);
+ ei = 1 - ei;
+ return true;
+}
+
+bool YieldToParent(AutoCloseMutexHandle parentEvents[2], AutoCloseMutexHandle childEvents[2], int &ei)
+{
+ TestAssert(childEvents[ei].Release());
+ ei = 1 - ei;
+ TestAssert(WaitForSingleObject(parentEvents[ei], FailTimeoutMilliseconds) == WAIT_OBJECT_0);
+ TestAssert(parentEvents[ei].Release());
+ TestAssert(WaitForSingleObject(childEvents[1 - ei], 0) == WAIT_OBJECT_0);
+ return true;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// Tests
+
+bool NameTests()
+{
+ const char *testName = "NameTests";
+
+ AutoCloseMutexHandle m;
+ char name[MaxPathSize];
+
+ // Empty name
+ TestCreateMutex(m, "");
+ TestAssert(m != nullptr);
+
+ // Normal name
+ TestCreateMutex(m, BuildName(testName, name, NamePrefix));
+ TestAssert(m != nullptr);
+ TestAssert(AutoCloseMutexHandle(TestOpenMutex(BuildName(testName, name, NamePrefix))) != nullptr);
+ TestCreateMutex(m, BuildName(testName, name, SessionPrefix, NamePrefix));
+ TestAssert(m != nullptr);
+ TestAssert(AutoCloseMutexHandle(TestOpenMutex(BuildName(testName, name, SessionPrefix, NamePrefix))) != nullptr);
+ TestCreateMutex(m, BuildName(testName, name, GlobalPrefix, NamePrefix));
+ TestAssert(m != nullptr);
+ TestAssert(AutoCloseMutexHandle(TestOpenMutex(BuildName(testName, name, GlobalPrefix, NamePrefix))) != nullptr);
+
+ // Name too long. The maximum allowed length depends on the file system, so we're not checking for that.
+ {
+ char name[257];
+ memset(name, 'a', _countof(name) - 1);
+ name[_countof(name) - 1] = '\0';
+ TestCreateMutex(m, name);
+ TestAssert(m == nullptr);
+ TestAssert(GetLastError() == ERROR_FILENAME_EXCED_RANGE);
+ TestAssert(AutoCloseMutexHandle(TestOpenMutex(name)) == nullptr);
+ TestAssert(GetLastError() == ERROR_FILENAME_EXCED_RANGE);
+ }
+
+ // Invalid characters in name
+ TestCreateMutex(m, BuildName(testName, name, InvalidNamePrefix0));
+ TestAssert(m == nullptr);
+ TestAssert(GetLastError() == ERROR_INVALID_NAME);
+ TestAssert(AutoCloseMutexHandle(TestOpenMutex(BuildName(testName, name, InvalidNamePrefix0))) == nullptr);
+ TestAssert(GetLastError() == ERROR_INVALID_NAME);
+ TestCreateMutex(m, BuildName(testName, name, InvalidNamePrefix1));
+ TestAssert(m == nullptr);
+ TestAssert(GetLastError() == ERROR_INVALID_NAME);
+ TestAssert(AutoCloseMutexHandle(TestOpenMutex(BuildName(testName, name, InvalidNamePrefix1))) == nullptr);
+ TestAssert(GetLastError() == ERROR_INVALID_NAME);
+ TestCreateMutex(m, BuildName(testName, name, SessionPrefix, InvalidNamePrefix0));
+ TestAssert(m == nullptr);
+ TestAssert(GetLastError() == ERROR_INVALID_NAME);
+ TestAssert(AutoCloseMutexHandle(TestOpenMutex(BuildName(testName, name, SessionPrefix, InvalidNamePrefix0))) == nullptr);
+ TestAssert(GetLastError() == ERROR_INVALID_NAME);
+ TestCreateMutex(m, BuildName(testName, name, GlobalPrefix, InvalidNamePrefix1));
+ TestAssert(m == nullptr);
+ TestAssert(GetLastError() == ERROR_INVALID_NAME);
+ TestAssert(AutoCloseMutexHandle(TestOpenMutex(BuildName(testName, name, GlobalPrefix, InvalidNamePrefix1))) == nullptr);
+ TestAssert(GetLastError() == ERROR_INVALID_NAME);
+
+ // Creating a second reference to the same named mutex yields an error indicating that it was opened, not created
+ {
+ TestCreateMutex(m, BuildName(testName, name, NamePrefix));
+ TestAssert(m != nullptr);
+ AutoCloseMutexHandle m2;
+ TestCreateMutex(m2, BuildName(testName, name, NamePrefix));
+ TestAssert(m2 != nullptr);
+ TestAssert(GetLastError() == ERROR_ALREADY_EXISTS);
+ }
+
+ return true;
+}
+
+bool HeaderMismatchTests()
+{
+ const char *testName = "HeaderMismatchTests";
+
+ AutoCloseMutexHandle m, m2;
+ char name[MaxPathSize];
+ int fd;
+
+ // Create and hold onto a mutex during this test to create the shared memory directory
+ TestCreateMutex(m2, BuildName(testName, name, GlobalPrefix, TempNamePrefix));
+ TestAssert(m2 != nullptr);
+
+ // Unknown shared memory type
+ TestAssert(WriteHeaderInfo(BuildGlobalShmFilePath(testName, name, NamePrefix), -1, 1, &fd));
+ TestCreateMutex(m, BuildName(testName, name, GlobalPrefix, NamePrefix));
+ TestAssert(m == nullptr);
+ TestAssert(GetLastError() == ERROR_INVALID_HANDLE);
+ TestAssert(test_close(fd) == 0);
+ TestAssert(test_unlink(BuildGlobalShmFilePath(testName, name, NamePrefix)) == 0);
+
+ // Mismatched version
+ TestAssert(WriteHeaderInfo(BuildGlobalShmFilePath(testName, name, NamePrefix), 0, -1, &fd));
+ TestCreateMutex(m, BuildName(testName, name, GlobalPrefix, NamePrefix));
+ TestAssert(m == nullptr);
+ TestAssert(GetLastError() == ERROR_INVALID_HANDLE);
+ TestAssert(test_close(fd) == 0);
+ TestAssert(test_unlink(BuildGlobalShmFilePath(testName, name, NamePrefix)) == 0);
+
+ return true;
+}
+
+bool MutualExclusionTests_Parent()
+{
+ const char *testName = "MutualExclusionTests";
+
+ AutoCloseMutexHandle parentEvents[2], childEvents[2];
+ TestAssert(InitializeParent(testName, parentEvents, childEvents));
+ int ei = 0;
+ char name[MaxPathSize];
+ AutoCloseMutexHandle m;
+
+ TestCreateMutex(m, BuildName(testName, name, GlobalPrefix, NamePrefix));
+ TestAssert(m != nullptr);
+
+ // Recursive locking with various timeouts
+ TestAssert(WaitForSingleObject(m, 0) == WAIT_OBJECT_0);
+ TestAssert(WaitForSingleObject(m, FailTimeoutMilliseconds) == WAIT_OBJECT_0);
+ TestAssert(WaitForSingleObject(m, static_cast<DWORD>(-1)) == WAIT_OBJECT_0);
+ TestAssert(m.Release());
+ TestAssert(m.Release());
+ TestAssert(m.Release());
+ TestAssert(!m.Release()); // try to release the lock while nobody owns it, and verify recursive lock counting
+ TestAssert(GetLastError() == ERROR_NOT_OWNER);
+
+ TestAssert(YieldToChild(parentEvents, childEvents, ei)); // child takes the lock
+
+ TestAssert(WaitForSingleObject(m, 0) == WAIT_TIMEOUT); // try to lock the mutex without waiting
+ TestAssert(WaitForSingleObject(m, g_expectedTimeoutMilliseconds) == WAIT_TIMEOUT); // try to lock the mutex with a timeout
+ TestAssert(!m.Release()); // try to release the lock while another thread owns it
+ TestAssert(GetLastError() == ERROR_NOT_OWNER);
+
+ TestAssert(YieldToChild(parentEvents, childEvents, ei)); // child releases the lock
+
+ TestAssert(WaitForSingleObject(m, static_cast<DWORD>(-1)) == WAIT_OBJECT_0); // lock the mutex with no timeout and release
+ TestAssert(m.Release());
+
+ UninitializeParent(testName, parentEvents);
+ return true;
+}
+
+DWORD MutualExclusionTests_Child(void *arg = nullptr)
+{
+ const char *testName = "MutualExclusionTests";
+
+ AutoCloseMutexHandle childRunningEvent, parentEvents[2], childEvents[2];
+ TestAssert(InitializeChild(testName, childRunningEvent, parentEvents, childEvents));
+ int ei = 0;
+
+ {
+ char name[MaxPathSize];
+ AutoCloseMutexHandle m;
+
+ TestCreateMutex(m, BuildName(testName, name, GlobalPrefix, NamePrefix));
+ TestAssert(m != nullptr);
+ TestAssert(WaitForSingleObject(m, 0) == WAIT_OBJECT_0); // lock the mutex
+ YieldToParent(parentEvents, childEvents, ei); // parent attempts to lock/release, and fails
+ TestAssert(m.Release()); // release the lock
+ }
+
+ UninitializeChild(childRunningEvent, parentEvents, childEvents);
+ return 0;
+}
+
+bool MutualExclusionTests()
+{
+ const char *testName = "MutualExclusionTests";
+
+ {
+ AutoCloseMutexHandle m;
+ char name[MaxPathSize];
+
+ // Releasing a lock that is not owned by any thread fails
+ TestCreateMutex(m, BuildName(testName, name, NamePrefix));
+ TestAssert(m != nullptr);
+ TestAssert(!m.Release());
+ TestAssert(GetLastError() == ERROR_NOT_OWNER);
+
+ // Acquire a lock during upon creation, and release
+ TestCreateMutex(m, BuildName(testName, name, NamePrefix), true);
+ TestAssert(m != nullptr);
+ TestAssert(m.Release());
+
+ // Multi-waits including a named mutex are not supported
+ AutoCloseMutexHandle m2;
+ TestCreateMutex(m2, nullptr);
+ TestAssert(m2 != nullptr);
+ HANDLE waitHandles[] = {m2.GetHandle(), m.GetHandle()};
+ TestAssert(
+ WaitForMultipleObjects(
+ _countof(waitHandles),
+ waitHandles,
+ false /* waitAll */,
+ FailTimeoutMilliseconds) ==
+ WAIT_FAILED);
+ TestAssert(GetLastError() == ERROR_NOT_SUPPORTED);
+ TestAssert(
+ WaitForMultipleObjects(
+ _countof(waitHandles),
+ waitHandles,
+ true /* waitAll */,
+ FailTimeoutMilliseconds) ==
+ WAIT_FAILED);
+ TestAssert(GetLastError() == ERROR_NOT_SUPPORTED);
+ }
+
+ // When another thread or process owns the lock, this process should not be able to acquire a lock, and the converse
+ TestAssert(StartThread(MutualExclusionTests_Child));
+ TestAssert(MutualExclusionTests_Parent());
+ TestAssert(StartProcess("MutualExclusionTests_Child"));
+ TestAssert(MutualExclusionTests_Parent());
+
+ return true;
+}
+
+bool LifetimeTests_Parent()
+{
+ const char *testName = "LifetimeTests";
+
+ AutoCloseMutexHandle parentEvents[2], childEvents[2];
+ TestAssert(InitializeParent(testName, parentEvents, childEvents));
+ int ei = 0;
+ char name[MaxPathSize];
+ AutoCloseMutexHandle m;
+
+ TestCreateMutex(m, BuildName(testName, name, GlobalPrefix, NamePrefix)); // create first reference to mutex
+ TestAssert(m != nullptr);
+ TestAssert(TestFileExists(BuildGlobalShmFilePath(testName, name, NamePrefix)));
+ TestAssert(YieldToChild(parentEvents, childEvents, ei)); // child creates second reference to mutex using CreateMutex
+ m.Close(); // close first reference
+ TestAssert(TestFileExists(BuildGlobalShmFilePath(testName, name, NamePrefix)));
+ TestAssert(YieldToChild(parentEvents, childEvents, ei)); // child closes second reference
+ TestAssert(!TestFileExists(BuildGlobalShmFilePath(testName, name, NamePrefix)));
+
+ TestCreateMutex(m, BuildName(testName, name, GlobalPrefix, NamePrefix)); // create first reference to mutex
+ TestAssert(m != nullptr);
+ TestAssert(TestFileExists(BuildGlobalShmFilePath(testName, name, NamePrefix)));
+ TestAssert(YieldToChild(parentEvents, childEvents, ei)); // child creates second reference to mutex using OpenMutex
+ m.Close(); // close first reference
+ TestAssert(TestFileExists(BuildGlobalShmFilePath(testName, name, NamePrefix)));
+ TestAssert(YieldToChild(parentEvents, childEvents, ei)); // child closes second reference
+ TestAssert(!TestFileExists(BuildGlobalShmFilePath(testName, name, NamePrefix)));
+
+ UninitializeParent(testName, parentEvents);
+ return true;
+}
+
+DWORD LifetimeTests_Child(void *arg = nullptr)
+{
+ const char *testName = "LifetimeTests";
+
+ AutoCloseMutexHandle childRunningEvent, parentEvents[2], childEvents[2];
+ TestAssert(InitializeChild(testName, childRunningEvent, parentEvents, childEvents));
+ int ei = 0;
+
+ {
+ char name[MaxPathSize];
+ AutoCloseMutexHandle m;
+
+ // ... parent creates first reference to mutex
+ TestCreateMutex(m, BuildName(testName, name, GlobalPrefix, NamePrefix)); // create second reference to mutex using CreateMutex
+ TestAssert(m != nullptr);
+ TestAssert(YieldToParent(parentEvents, childEvents, ei)); // parent closes first reference
+ m.Close(); // close second reference
+
+ TestAssert(YieldToParent(parentEvents, childEvents, ei)); // parent verifies, and creates first reference to mutex again
+ m = TestOpenMutex(BuildName(testName, name, GlobalPrefix, NamePrefix)); // create second reference to mutex using OpenMutex
+ TestAssert(m != nullptr);
+ TestAssert(YieldToParent(parentEvents, childEvents, ei)); // parent closes first reference
+ m.Close(); // close second reference
+
+ TestAssert(YieldToParent(parentEvents, childEvents, ei)); // parent verifies
+ }
+
+ UninitializeChild(childRunningEvent, parentEvents, childEvents);
+ return 0;
+}
+
+bool LifetimeTests()
+{
+ const char *testName = "LifetimeTests";
+
+ {
+ AutoCloseMutexHandle m;
+ char name[MaxPathSize];
+
+ // Shm file should be created and deleted
+ TestCreateMutex(m, BuildName(testName, name, GlobalPrefix, NamePrefix));
+ TestAssert(m != nullptr);
+ TestAssert(TestFileExists(BuildGlobalShmFilePath(testName, name, NamePrefix)));
+ m.Close();
+ TestAssert(!TestFileExists(BuildGlobalShmFilePath(testName, name, NamePrefix)));
+ }
+
+ // Shm file should not be deleted until last reference is released
+ TestAssert(StartThread(LifetimeTests_Child));
+ TestAssert(LifetimeTests_Parent());
+ TestAssert(StartProcess("LifetimeTests_Child"));
+ TestAssert(LifetimeTests_Parent());
+
+ return true;
+}
+
+DWORD AbandonTests_Child_TryLock(void *arg = nullptr);
+
+bool AbandonTests_Parent()
+{
+ const char *testName = "AbandonTests";
+
+ char name[MaxPathSize];
+ AutoCloseMutexHandle m;
+ {
+ AutoCloseMutexHandle parentEvents[2], childEvents[2];
+ TestAssert(InitializeParent(testName, parentEvents, childEvents));
+ int ei = 0;
+
+ TestCreateMutex(m, BuildName(testName, name, GlobalPrefix, NamePrefix));
+ TestAssert(m != nullptr);
+ TestAssert(YieldToChild(parentEvents, childEvents, ei)); // child locks mutex
+ TestAssert(parentEvents[0].Release());
+ TestAssert(parentEvents[1].Release()); // child sleeps for short duration and abandons the mutex
+ TestAssert(WaitForSingleObject(m, FailTimeoutMilliseconds) == WAIT_ABANDONED_0); // attempt to lock and see abandoned mutex
+
+ UninitializeParent(testName, parentEvents, false /* releaseParentEvents */); // parent events are released above
+ }
+
+ // Verify that the mutex lock is owned by this thread, by starting a new thread and trying to lock it
+ StartThread(AbandonTests_Child_TryLock);
+ {
+ AutoCloseMutexHandle parentEvents[2], childEvents[2];
+ TestAssert(InitializeParent(testName, parentEvents, childEvents));
+ int ei = 0;
+
+ TestAssert(YieldToChild(parentEvents, childEvents, ei)); // child tries to lock mutex
+
+ UninitializeParent(testName, parentEvents);
+ }
+
+ // Verify that the mutex lock is owned by this thread, by starting a new process and trying to lock it
+ StartProcess("AbandonTests_Child_TryLock");
+ AutoCloseMutexHandle parentEvents[2], childEvents[2];
+ TestAssert(InitializeParent(testName, parentEvents, childEvents));
+ int ei = 0;
+
+ TestAssert(YieldToChild(parentEvents, childEvents, ei)); // child tries to lock mutex
+
+ // Continue verification
+ TestAssert(m.Release());
+ TestAssert(WaitForSingleObject(m, FailTimeoutMilliseconds) == WAIT_OBJECT_0); // lock again to see it's not abandoned anymore
+ TestAssert(m.Release());
+
+ UninitializeParent(testName, parentEvents, false /* releaseParentEvents */); // parent events are released above
+
+ // Since the child abandons the mutex, and a child process may not release the file lock on the shared memory file before
+ // indicating completion to the parent, make sure to delete the shared memory file by repeatedly opening/closing the mutex
+ // until the parent process becomes the last process to reference the mutex and closing it deletes the file.
+ DWORD startTime = GetTickCount();
+ while (true)
+ {
+ m.Close();
+ if (!TestFileExists(BuildGlobalShmFilePath(testName, name, NamePrefix)))
+ {
+ break;
+ }
+
+ TestAssert(GetTickCount() - startTime < FailTimeoutMilliseconds);
+ m = TestOpenMutex(BuildName(testName, name, GlobalPrefix, NamePrefix));
+ }
+
+ return true;
+}
+
+DWORD AbandonTests_Child_GracefulExit_Close(void *arg = nullptr)
+{
+ const char *testName = "AbandonTests";
+
+ AutoCloseMutexHandle childRunningEvent, parentEvents[2], childEvents[2];
+ TestAssert(InitializeChild(testName, childRunningEvent, parentEvents, childEvents));
+ int ei = 0;
+
+ {
+ char name[MaxPathSize];
+ AutoCloseMutexHandle m;
+
+ // ... parent waits for child to lock mutex
+ TestCreateMutex(m, BuildName(testName, name, GlobalPrefix, NamePrefix));
+ TestAssert(m != nullptr);
+ TestAssert(WaitForSingleObject(m, 0) == WAIT_OBJECT_0);
+ TestAssert(YieldToParent(parentEvents, childEvents, ei)); // parent waits on mutex
+ Sleep(g_expectedTimeoutMilliseconds); // wait for parent to wait on mutex
+ m.Close(); // close mutex without releasing lock
+ }
+
+ UninitializeChild(childRunningEvent, parentEvents, childEvents);
+ return 0;
+}
+
+DWORD AbandonTests_Child_GracefulExit_NoClose(void *arg = nullptr)
+{
+ const char *testName = "AbandonTests";
+
+ // This test needs to run in a separate process because it does not close the mutex handle. Running it in a separate thread
+ // causes the mutex object to retain a reference until the process terminates.
+ TestAssert(test_getpid() != g_parentPid);
+
+ AutoCloseMutexHandle childRunningEvent, parentEvents[2], childEvents[2];
+ TestAssert(InitializeChild(testName, childRunningEvent, parentEvents, childEvents));
+ int ei = 0;
+
+ {
+ char name[MaxPathSize];
+ AutoCloseMutexHandle m;
+
+ // ... parent waits for child to lock mutex
+ TestCreateMutex(m, BuildName(testName, name, GlobalPrefix, NamePrefix));
+ TestAssert(m != nullptr);
+ TestAssert(WaitForSingleObject(m, 0) == WAIT_OBJECT_0);
+ TestAssert(YieldToParent(parentEvents, childEvents, ei)); // parent waits on mutex
+ Sleep(g_expectedTimeoutMilliseconds); // wait for parent to wait on mutex
+ m.Abandon(); // don't close the mutex
+ }
+
+ UninitializeChild(childRunningEvent, parentEvents, childEvents);
+ return 0;
+}
+
+DWORD AbandonTests_Child_AbruptExit(void *arg = nullptr)
+{
+ const char *testName = "AbandonTests";
+
+ DWORD currentPid = test_getpid();
+ TestAssert(currentPid != g_parentPid); // this test needs to run in a separate process
+
+ {
+ AutoCloseMutexHandle childRunningEvent, parentEvents[2], childEvents[2];
+ TestAssert(InitializeChild(testName, childRunningEvent, parentEvents, childEvents));
+ int ei = 0;
+
+ {
+ char name[MaxPathSize];
+ AutoCloseMutexHandle m;
+
+ // ... parent waits for child to lock mutex
+ TestCreateMutex(m, BuildName(testName, name, GlobalPrefix, NamePrefix));
+ TestAssert(m != nullptr);
+ TestAssert(WaitForSingleObject(m, 0) == WAIT_OBJECT_0);
+ TestAssert(YieldToParent(parentEvents, childEvents, ei)); // parent waits on mutex
+ Sleep(g_expectedTimeoutMilliseconds); // wait for parent to wait on mutex
+ m.Abandon(); // don't close the mutex
+ }
+
+ UninitializeChild(childRunningEvent, parentEvents, childEvents);
+ }
+
+ TestAssert(test_kill(currentPid) == 0); // abandon the mutex abruptly
+ return 0;
+}
+
+DWORD AbandonTests_Child_TryLock(void *arg)
+{
+ const char *testName = "AbandonTests";
+
+ AutoCloseMutexHandle childRunningEvent, parentEvents[2], childEvents[2];
+ TestAssert(InitializeChild(testName, childRunningEvent, parentEvents, childEvents));
+ int ei = 0;
+
+ {
+ char name[MaxPathSize];
+ AutoCloseMutexHandle m;
+
+ // ... parent waits for child to lock mutex
+ TestCreateMutex(m, BuildName(testName, name, GlobalPrefix, NamePrefix));
+ TestAssert(m != nullptr);
+ TestAssert(WaitForSingleObject(m, 0) == WAIT_TIMEOUT); // try to lock the mutex while the parent holds the lock
+ TestAssert(WaitForSingleObject(m, g_expectedTimeoutMilliseconds) == WAIT_TIMEOUT);
+ }
+
+ UninitializeChild(childRunningEvent, parentEvents, childEvents);
+ return 0;
+}
+
+bool AbandonTests()
+{
+ const char *testName = "AbandonTests";
+
+ // Abandon by graceful exit where the lock owner closes the mutex before releasing it, unblocks a waiter
+ TestAssert(StartThread(AbandonTests_Child_GracefulExit_Close));
+ TestAssert(AbandonTests_Parent());
+ TestAssert(StartProcess("AbandonTests_Child_GracefulExit_Close"));
+ TestAssert(AbandonTests_Parent());
+
+ // Abandon by graceful exit without closing the mutex unblocks a waiter
+ TestAssert(StartProcess("AbandonTests_Child_GracefulExit_NoClose"));
+ TestAssert(AbandonTests_Parent());
+
+ // Abandon by abrupt exit unblocks a waiter
+ TestAssert(StartProcess("AbandonTests_Child_AbruptExit"));
+ TestAssert(AbandonTests_Parent());
+
+ return true;
+}
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// Test harness
+
+bool (*const (TestList[]))() =
+{
+ NameTests,
+ HeaderMismatchTests,
+ MutualExclusionTests,
+ LifetimeTests,
+ AbandonTests
+};
+
+bool RunTests()
+{
+ bool allPassed = true;
+ for (SIZE_T i = 0; i < _countof(TestList); ++i)
+ {
+ if (!TestList[i]())
+ {
+ allPassed = false;
+ }
+ }
+ return allPassed;
+}
+
+DWORD g_stressDurationMilliseconds = 0;
+LONG g_stressTestCounts[_countof(TestList)] = {0};
+LONG g_stressResult = true;
+
+DWORD StressTest(void *arg)
+{
+ // Run the specified test continuously for the stress duration
+ SIZE_T testIndex = reinterpret_cast<SIZE_T>(arg);
+ DWORD startTime = GetTickCount();
+ do
+ {
+ ++g_stressTestCounts[testIndex];
+ if (!TestList[testIndex]())
+ {
+ InterlockedExchange(&g_stressResult, false);
+ break;
+ }
+ } while (
+ InterlockedCompareExchange(&g_stressResult, false, false) == true &&
+ GetTickCount() - startTime < g_stressDurationMilliseconds);
+ return 0;
+}
+
+bool StressTests(DWORD durationMinutes)
+{
+ g_isStress = true;
+ g_expectedTimeoutMilliseconds = 1;
+ g_stressDurationMilliseconds = durationMinutes * (60 * 1000);
+
+ // Start a thread for each test
+ HANDLE threadHandles[_countof(TestList)];
+ for (SIZE_T i = 0; i < _countof(threadHandles); ++i)
+ {
+ TestAssert(StartThread(StressTest, reinterpret_cast<void *>(i), &threadHandles[i]));
+ }
+
+ while (true)
+ {
+ DWORD waitResult =
+ WaitForMultipleObjects(_countof(threadHandles), threadHandles, true /* bWaitAll */, 10 * 1000 /* dwMilliseconds */);
+ TestAssert(waitResult == WAIT_OBJECT_0 || waitResult == WAIT_TIMEOUT);
+ if (waitResult == WAIT_OBJECT_0)
+ {
+ break;
+ }
+
+ Trace("'paltest_namedmutex_test1' stress test counts: ");
+ for (SIZE_T i = 0; i < _countof(g_stressTestCounts); ++i)
+ {
+ if (i != 0)
+ {
+ Trace(", ");
+ }
+ Trace("%u", g_stressTestCounts[i]);
+ }
+ Trace("\n");
+ fflush(stdout);
+ }
+
+ for (SIZE_T i = 0; i < _countof(threadHandles); ++i)
+ {
+ CloseHandle(threadHandles[i]);
+ }
+ return static_cast<bool>(g_stressResult);
+}
+
+int __cdecl main(int argc, char **argv)
+{
+ if (argc < 1 || argc > 4)
+ {
+ return FAIL;
+ }
+
+ if (PAL_Initialize(argc, argv) != 0)
+ {
+ return FAIL;
+ }
+
+ test_strcpy(g_processPath, argv[0]);
+
+ if (argc == 1)
+ {
+ // Unit test arguments: <processPath>
+
+ g_parentPid = test_getpid();
+ int result = RunTests() ? PASS : FAIL;
+ ExitProcess(result);
+ return result;
+ }
+
+ if (test_strcmp(argv[1], "stress") == 0)
+ {
+ // Stress test arguments: <processPath> stress [durationMinutes]
+
+ DWORD durationMinutes = 1;
+ if (argc >= 3 && test_sscanf(argv[2], "%u", &durationMinutes) != 1)
+ {
+ ExitProcess(FAIL);
+ return FAIL;
+ }
+
+ g_parentPid = test_getpid();
+ int result = StressTests(durationMinutes) ? PASS : FAIL;
+ ExitProcess(result);
+ return result;
+ }
+
+ // Child test process arguments: <processPath> <parentPid> <testFunctionName> [stress]
+
+ g_isParent = false;
+
+ // Get parent process' ID from argument
+ if (test_sscanf(argv[1], "%u", &g_parentPid) != 1)
+ {
+ ExitProcess(FAIL);
+ return FAIL;
+ }
+
+ if (argc >= 4 && test_strcmp(argv[3], "stress") == 0)
+ {
+ g_isStress = true;
+ }
+
+ if (test_strcmp(argv[2], "MutualExclusionTests_Child") == 0)
+ {
+ MutualExclusionTests_Child();
+ }
+ else if (test_strcmp(argv[2], "LifetimeTests_Child") == 0)
+ {
+ LifetimeTests_Child();
+ }
+ else if (test_strcmp(argv[2], "AbandonTests_Child_GracefulExit_Close") == 0)
+ {
+ AbandonTests_Child_GracefulExit_Close();
+ }
+ else if (test_strcmp(argv[2], "AbandonTests_Child_GracefulExit_NoClose") == 0)
+ {
+ AbandonTests_Child_GracefulExit_NoClose();
+ }
+ else if (test_strcmp(argv[2], "AbandonTests_Child_AbruptExit") == 0)
+ {
+ AbandonTests_Child_AbruptExit();
+ }
+ else if (test_strcmp(argv[2], "AbandonTests_Child_TryLock") == 0)
+ {
+ AbandonTests_Child_TryLock();
+ }
+ ExitProcess(PASS);
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/threading/NamedMutex/test1/nopal.cpp b/src/pal/tests/palsuite/threading/NamedMutex/test1/nopal.cpp
new file mode 100644
index 0000000000..46a5d87341
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/NamedMutex/test1/nopal.cpp
@@ -0,0 +1,65 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+// Contains wrappers for functions whose required headers conflict with the PAL
+
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <fcntl.h>
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#define _countof(a) (sizeof(a) / sizeof(a[0]))
+
+#define PAGE_SIZE (4096)
+
+auto test_strcpy = strcpy;
+auto test_strcmp = strcmp;
+auto test_strlen = strlen;
+auto test_sprintf = sprintf;
+auto test_sscanf = sscanf;
+auto test_close = close;
+auto test_unlink = unlink;
+
+unsigned int test_getpid()
+{
+ return getpid();
+}
+
+int test_kill(unsigned int pid)
+{
+ return kill(pid, SIGKILL);
+}
+
+bool TestFileExists(const char *path)
+{
+ int fd = open(path, O_RDWR);
+ if (fd == -1)
+ return false;
+ close(fd);
+ return true;
+}
+
+bool WriteHeaderInfo(const char *path, char sharedMemoryType, char version, int *fdRef)
+{
+ int fd = open(path, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
+ if (fd == -1)
+ return false;
+ *fdRef = fd;
+ if (ftruncate(fd, PAGE_SIZE) != 0)
+ return false;
+ if (lseek(fd, 0, SEEK_SET) != 0)
+ return false;
+
+ // See SharedMemorySharedDataHeader for format
+ char buffer[] = {sharedMemoryType, version};
+ if (write(fd, buffer, _countof(buffer)) != _countof(buffer))
+ return false;
+
+ return flock(fd, LOCK_SH | LOCK_NB) == 0;
+}
diff --git a/src/pal/tests/palsuite/threading/NamedMutex/test1/testinfo.dat b/src/pal/tests/palsuite/threading/NamedMutex/test1/testinfo.dat
new file mode 100644
index 0000000000..e3090093ea
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/NamedMutex/test1/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = Named mutex
+Name = Tests for named mutexes
+TYPE = DEFAULT
+EXE1 = namedmutex
+Description
+= These test cases test named mutexes, including positive
+= and negative cases, cross-thread and cross-process, mutual
+= exclusion, abandon detection, etc.
diff --git a/src/pal/tests/palsuite/threading/OpenEventW/CMakeLists.txt b/src/pal/tests/palsuite/threading/OpenEventW/CMakeLists.txt
new file mode 100644
index 0000000000..8083faf655
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/OpenEventW/CMakeLists.txt
@@ -0,0 +1,8 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+add_subdirectory(test3)
+add_subdirectory(test4)
+add_subdirectory(test5)
+
diff --git a/src/pal/tests/palsuite/threading/OpenEventW/test1/CMakeLists.txt b/src/pal/tests/palsuite/threading/OpenEventW/test1/CMakeLists.txt
new file mode 100644
index 0000000000..2bb61e3044
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/OpenEventW/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_openeventw_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_openeventw_test1 coreclrpal)
+
+target_link_libraries(paltest_openeventw_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/OpenEventW/test1/test1.c b/src/pal/tests/palsuite/threading/OpenEventW/test1/test1.c
new file mode 100644
index 0000000000..9dcb3a4a68
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/OpenEventW/test1/test1.c
@@ -0,0 +1,134 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Test for OpenEventW. This test creates an event,
+** opens a handle to the same event, then waits on both handles
+** in both a signalled and non-signalled state to verify they're.
+** pointing to the same event object.
+**
+**
+**==========================================================================*/
+#include <palsuite.h>
+
+int __cdecl main(int argc, char **argv)
+{
+ BOOL bRet = FAIL;
+ DWORD dwRet;
+ HANDLE hEvent;
+ HANDLE hOpenEvent;
+ WCHAR theName[] = {'E','v','e','n','t','\0'};
+ LPCWSTR lpName = theName;
+
+ /* PAL initialization */
+ if( (PAL_Initialize(argc, argv)) != 0 )
+ {
+ return( FAIL );
+ }
+
+ /* Create an event (with a 0 intial state!) and ensure that the
+ HANDLE is valid
+ */
+ hEvent = CreateEventW( NULL, TRUE, FALSE, lpName );
+ if( hEvent == NULL )
+ {
+ Fail( "ERROR:%lu:CreateEvent call failed\n", GetLastError() );
+ }
+
+
+ /* Call OpenEventW to get another HANDLE on
+ this event. Ensure the HANDLE is valid.
+ */
+ hOpenEvent = OpenEventW( EVENT_ALL_ACCESS, TRUE, lpName );
+ if( hOpenEvent == NULL )
+ {
+ Trace( "ERROR:%lu:OpenEventW call failed\n", GetLastError() );
+ goto cleanup2;
+ }
+
+ /* wait on the original event to verify that it's not signalled */
+ dwRet = WaitForSingleObject( hEvent, 0 );
+ if( dwRet != WAIT_TIMEOUT )
+ {
+ Trace( "ERROR:WaitForSingleObject returned %lu, "
+ "expected WAIT_TIMEOUT\n",
+ dwRet );
+ goto cleanup;
+ }
+
+ /* wait on the opened event to verify that it's not signalled either */
+ dwRet = WaitForSingleObject( hOpenEvent, 0 );
+ if( dwRet != WAIT_TIMEOUT )
+ {
+ Trace( "ERROR:WaitForSingleObject returned %lu, "
+ "expected WAIT_TIMEOUT\n",
+ dwRet );
+ goto cleanup;
+ }
+
+
+ /* Set this opened HANDLE */
+ if( ! SetEvent( hOpenEvent ) )
+ {
+ Trace( "ERROR:%lu:SetEvent call failed\n", GetLastError() );
+ goto cleanup;
+ }
+
+ /* wait on the original event to verify that it's signalled */
+ dwRet = WaitForSingleObject( hEvent, 0 );
+ if( dwRet != WAIT_OBJECT_0 )
+ {
+ Trace( "ERROR:WaitForSingleObject returned %lu, "
+ "expected WAIT_OBJECT_0\n",
+ dwRet );
+ goto cleanup;
+ }
+
+ /* wait on the opened event to verify that it's signalled too */
+ dwRet = WaitForSingleObject( hOpenEvent, 0 );
+ if( dwRet != WAIT_OBJECT_0 )
+ {
+ Trace( "ERROR:WaitForSingleObject returned %lu, "
+ "expected WAIT_OBJECT_0\n",
+ dwRet );
+ goto cleanup;
+ }
+
+ /* success if we get here */
+ bRet = PASS;
+
+cleanup:
+ /* close the opened handle */
+ if( ! CloseHandle( hOpenEvent ) )
+ {
+ Trace( "ERROR:%lu:CloseHandle call failed\n", GetLastError() );
+ bRet = FAIL;
+ }
+
+cleanup2:
+ /* close the original event handle */
+ if( ! CloseHandle( hEvent ) )
+ {
+ Trace( "ERROR:%lu:CloseHandle call failed\n", GetLastError() );
+ bRet = FAIL;
+ }
+
+ /* check for failure */
+ if( bRet == FAIL )
+ {
+ Fail( "test failed\n" );
+ }
+
+
+ /* terminate the PAL */
+ PAL_Terminate();
+
+ /* return success */
+ return ( PASS );
+
+}
+
diff --git a/src/pal/tests/palsuite/threading/OpenEventW/test1/testinfo.dat b/src/pal/tests/palsuite/threading/OpenEventW/test1/testinfo.dat
new file mode 100644
index 0000000000..cc9be71042
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/OpenEventW/test1/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = OpenEventW
+Name = Positive Test for OpenEventW
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Purpose: Test for OpenEventW. This test creates an event,
+= opens a handle to the same event, then waits on both handles
+= in both a signalled and non-signalled state to verify they're
+= pointing to the same event object.
diff --git a/src/pal/tests/palsuite/threading/OpenEventW/test2/CMakeLists.txt b/src/pal/tests/palsuite/threading/OpenEventW/test2/CMakeLists.txt
new file mode 100644
index 0000000000..48fa1f2c4b
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/OpenEventW/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test2.c
+)
+
+add_executable(paltest_openeventw_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_openeventw_test2 coreclrpal)
+
+target_link_libraries(paltest_openeventw_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/OpenEventW/test2/test2.c b/src/pal/tests/palsuite/threading/OpenEventW/test2/test2.c
new file mode 100644
index 0000000000..9cbf872b95
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/OpenEventW/test2/test2.c
@@ -0,0 +1,194 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================================
+**
+** Source: test2.c
+**
+** Purpose: Positive test for OpenEventW.
+**
+** Dependencies: PAL_Initialize
+** PAL_Terminate
+** CreateEvent
+** CloseHandle
+** WaitForSingleObject
+**
+** Purpose:
+**
+** Test to ensure proper operation of the OpenEventW()
+** API by creating a new named event and verifying that
+** it can be used interchangeably by setting the event
+** with the original handle and waiting on it with the
+** new one, then resetting it with the new one and waiting
+** on it with the original one.
+**
+**
+**===========================================================================*/
+#include <palsuite.h>
+
+
+
+int __cdecl main( int argc, char **argv )
+
+{
+ /* local variables */
+ BOOL ret = FAIL;
+ DWORD dwRet = 0;
+ HANDLE hEvent = NULL;
+ HANDLE hTestEvent = NULL;
+ LPSECURITY_ATTRIBUTES lpEventAttributes = NULL;
+ BOOL bManualReset = TRUE;
+ BOOL bInitialState = FALSE;
+ WCHAR wcName[] = {'W','o','o','B','a','b','y','\0'};
+ LPWSTR lpName = wcName;
+
+
+ /* PAL initialization */
+ if( (PAL_Initialize(argc, argv)) != 0 )
+ {
+ return( FAIL );
+ }
+
+
+ /* create an event which we can use with SetEvent */
+ hEvent = CreateEventW( lpEventAttributes,
+ bManualReset,
+ bInitialState,
+ lpName );
+
+ if( hEvent == NULL )
+ {
+ /* ERROR */
+ Fail( "ERROR:%lu:CreateEvent() call failed\n", GetLastError() );
+ }
+
+ /* open a new handle to our event */
+ hTestEvent = OpenEventW(EVENT_ALL_ACCESS, /* we want all rights */
+ FALSE, /* no inherit */
+ lpName );
+
+ if( hTestEvent == NULL )
+ {
+ /* ERROR */
+ Trace( "ERROR:%lu:OpenEventW() call failed\n", GetLastError() );
+ goto cleanup;
+ }
+
+ /* verify that the event isn't signalled yet by waiting on both */
+ /* handles to the event object */
+ dwRet = WaitForSingleObject( hEvent, 0 );
+ if( dwRet != WAIT_TIMEOUT )
+ {
+ /* ERROR */
+ Trace( "ERROR:WaitForSingleObject() call returned %lu, "
+ "expected WAIT_TIMEOUT\n",
+ dwRet );
+ goto cleanup;
+ }
+
+ dwRet = WaitForSingleObject( hTestEvent, 0 );
+ if( dwRet != WAIT_TIMEOUT )
+ {
+ /* ERROR */
+ Trace( "ERROR:WaitForSingleObject() call returned %lu, "
+ "expected WAIT_TIMEOUT\n",
+ dwRet );
+ goto cleanup;
+ }
+
+
+ /* set the event using the original handle */
+ if( ! SetEvent( hEvent ) )
+ {
+ /* ERROR */
+ Trace( "ERROR:%lu:SetEvent() call failed\n", GetLastError() );
+ goto cleanup;
+ }
+
+ /* verify that the event is signalled by waiting on both handles */
+ dwRet = WaitForSingleObject( hEvent, 0 );
+ if( dwRet != WAIT_OBJECT_0 )
+ {
+ /* ERROR */
+ Trace( "ERROR:WaitForSingleObject() call returned %lu, "
+ "expected WAIT_OBJECT_0\n",
+ dwRet );
+ goto cleanup;
+ }
+
+ dwRet = WaitForSingleObject( hTestEvent, 0 );
+ if( dwRet != WAIT_OBJECT_0 )
+ {
+ /* ERROR */
+ Trace( "ERROR:WaitForSingleObject() call returned %lu, "
+ "expected WAIT_OBJECT_0\n",
+ dwRet );
+ goto cleanup;
+ }
+
+ /* reset the event using the new handle */
+ if( ! ResetEvent( hTestEvent ) )
+ {
+ /* ERROR */
+ Trace( "ERROR:%lu:ResetEvent() call failed\n", GetLastError() );
+ goto cleanup;
+ }
+
+ /* verify that the event isn't signalled by waiting on both handles */
+ dwRet = WaitForSingleObject( hEvent, 0 );
+ if( dwRet != WAIT_TIMEOUT )
+ {
+ /* ERROR */
+ Trace( "ERROR:WaitForSingleObject() call returned %lu, "
+ "expected WAIT_TIMEOUT\n",
+ dwRet );
+ goto cleanup;
+ }
+
+ dwRet = WaitForSingleObject( hTestEvent, 0 );
+ if( dwRet != WAIT_TIMEOUT )
+ {
+ /* ERROR */
+ Trace( "ERROR:WaitForSingleObject() call returned %lu, "
+ "expected WAIT_TIMEOUT\n",
+ dwRet );
+ goto cleanup;
+ }
+
+
+ /* test was successful */
+ ret = PASS;
+
+
+cleanup:
+ /* close the new event handle */
+ if( hTestEvent != NULL )
+ {
+ if( ! CloseHandle( hTestEvent ) )
+ {
+ ret = FAIL;
+ Trace( "ERROR:%lu:CloseHandle() call failed\n", GetLastError() );
+ }
+ }
+
+ /* close the original event handle */
+ if( ! CloseHandle( hEvent ) )
+ {
+ ret = FAIL;
+ Trace( "ERROR:%lu:CloseHandle() call failed\n", GetLastError() );
+ }
+
+ /* failure message */
+ if( ret != PASS )
+ {
+ Fail( "Test failed\n" );
+ }
+
+
+ /* PAL termination */
+ PAL_Terminate();
+
+ /* return success or failure */
+ return ret;
+}
diff --git a/src/pal/tests/palsuite/threading/OpenEventW/test2/testinfo.dat b/src/pal/tests/palsuite/threading/OpenEventW/test2/testinfo.dat
new file mode 100644
index 0000000000..ad3f22eea0
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/OpenEventW/test2/testinfo.dat
@@ -0,0 +1,17 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = OpenEventW
+Name = Positive test for OpenEventW
+TYPE = DEFAULT
+EXE1 = test2
+Description
+= Test to ensure proper operation of the OpenEventW()
+= API by creating a new named event and verifying that
+= it can be used interchangeably by setting the event
+= with the original handle and waiting on it with the
+= new one, then resetting it with the new one and waiting
+= on it with the original one.
diff --git a/src/pal/tests/palsuite/threading/OpenEventW/test3/CMakeLists.txt b/src/pal/tests/palsuite/threading/OpenEventW/test3/CMakeLists.txt
new file mode 100644
index 0000000000..433a3a255c
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/OpenEventW/test3/CMakeLists.txt
@@ -0,0 +1,36 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(TESTSOURCES
+ test3.c
+)
+
+add_executable(paltest_openeventw_test3
+ ${TESTSOURCES}
+)
+
+add_dependencies(paltest_openeventw_test3 coreclrpal)
+
+target_link_libraries(paltest_openeventw_test3
+ pthread
+ m
+ coreclrpal
+)
+
+
+set(HELPERSOURCES
+ childprocess.c
+)
+
+add_executable(paltest_openeventw_test3_child
+ ${HELPERSOURCES}
+)
+
+add_dependencies(paltest_openeventw_test3_child coreclrpal)
+
+target_link_libraries(paltest_openeventw_test3_child
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/OpenEventW/test3/childprocess.c b/src/pal/tests/palsuite/threading/OpenEventW/test3/childprocess.c
new file mode 100644
index 0000000000..b5149e006f
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/OpenEventW/test3/childprocess.c
@@ -0,0 +1,81 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: childprocess.c
+**
+** Purpose: Test to ensure that OpenEventW() works when
+** opening an event created by another process. The test
+** program launches this program as a child, which creates
+** a named, initially-unset event. The child waits up to
+** 10 seconds for the parent process to open that event
+** and set it, and returns PASS if the event was set or FAIL
+** otherwise. The parent process checks the return value
+** from the child to verify that the opened event was
+** properly used across processes.
+**
+** Dependencies: PAL_Initialize
+** PAL_Terminate
+** CreateEventW
+** WaitForSingleObject
+** CloseHandle
+**
+**
+**=========================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main( int argc, char **argv )
+{
+ /* local variables */
+ HANDLE hEvent = NULL;
+ WCHAR wcName[] = {'P','A','L','R','o','c','k','s','\0'};
+ LPWSTR lpName = wcName;
+
+ int result = PASS;
+
+ /* initialize the PAL */
+ if( PAL_Initialize(argc, argv) != 0 )
+ {
+ return( FAIL );
+ }
+
+
+ /* open a handle to the event created in the child process */
+ hEvent = OpenEventW( EVENT_ALL_ACCESS, /* we want all rights */
+ FALSE, /* no inherit */
+ lpName );
+
+ if( hEvent == NULL )
+ {
+ /* ERROR */
+ Trace( "ERROR:%lu:OpenEventW() call failed\n", GetLastError() );
+ result = FAIL;
+ goto parentwait;
+ }
+
+ /* set the event -- should take effect in the child process */
+ if( ! SetEvent( hEvent ) )
+ {
+ /* ERROR */
+ Trace( "ERROR:%lu:SetEvent() call failed\n", GetLastError() );
+ result = FAIL;
+ }
+
+parentwait:
+ /* close the event handle */
+ if( ! CloseHandle( hEvent ) )
+ {
+ /* ERROR */
+ Fail( "ERROR:%lu:CloseHandle() call failed in child\n",
+ GetLastError());
+ }
+
+ /* terminate the PAL */
+ PAL_TerminateEx(result);
+
+ /* return success or failure */
+ return result;
+}
diff --git a/src/pal/tests/palsuite/threading/OpenEventW/test3/test3.c b/src/pal/tests/palsuite/threading/OpenEventW/test3/test3.c
new file mode 100644
index 0000000000..10a678a107
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/OpenEventW/test3/test3.c
@@ -0,0 +1,187 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================================
+**
+** Source: test3.c
+**
+** Purpose: Test to ensure that OpenEventW() works when
+** opening an event created by another process. This test
+** program launches a child process which creates a
+** named, initially-unset event. The child waits up to
+** 10 seconds for the parent process to open that event
+** and set it, and returns PASS if the event was set or FAIL
+** otherwise. The parent process checks the return value
+** from the child to verify that the opened event was
+** properly used across processes.
+**
+** Dependencies: PAL_Initialize
+** PAL_Terminate
+** Fail
+** ZeroMemory
+** GetCurrentDirectoryW
+** CreateProcessW
+** WaitForSingleObject
+** GetExitCodeProcess
+** GetLastError
+** strlen
+** strncpy
+**
+**
+**===========================================================================*/
+#include <palsuite.h>
+
+#define TIMEOUT 60000
+
+int __cdecl main( int argc, char **argv )
+{
+ BOOL ret = FAIL;
+ LPSECURITY_ATTRIBUTES lpEventAttributes = NULL;
+
+ STARTUPINFO si;
+ PROCESS_INFORMATION pi;
+
+ DWORD dwExitCode;
+
+ DWORD dwRet = 0;
+ HANDLE hEvent = NULL;
+ WCHAR wcName[] = {'P','A','L','R','o','c','k','s','\0'};
+ LPWSTR lpName = wcName;
+ char lpCommandLine[MAX_PATH] = "";
+
+ /* initialize the PAL */
+ if( PAL_Initialize(argc, argv) != 0 )
+ {
+ return( FAIL );
+ }
+
+ /* zero our process and startup info structures */
+ ZeroMemory( &si, sizeof(si) );
+ si.cb = sizeof( si );
+ ZeroMemory( &pi, sizeof(pi) );
+
+ /* create an event which we can use with SetEvent */
+ hEvent = CreateEventW( lpEventAttributes,
+ TRUE, /* manual reset */
+ FALSE, /* unsignalled */
+ lpName );
+
+ if( hEvent == NULL )
+ {
+ /* ERROR */
+ Fail( "ERROR:%lu:CreateEventW() call failed in child\n",
+ GetLastError());
+ }
+
+ ZeroMemory( lpCommandLine, MAX_PATH );
+ if ( _snprintf( lpCommandLine, MAX_PATH-1, "childprocess ") < 0 )
+ {
+ Fail ("Error: Insufficient lpCommandline for\n");
+ }
+
+ /* launch the child process */
+ if( !CreateProcess( NULL, /* module name to execute */
+ lpCommandLine, /* command line */
+ NULL, /* process handle not */
+ /* inheritable */
+ NULL, /* thread handle not */
+ /* inheritable */
+ FALSE, /* handle inheritance */
+ CREATE_NEW_CONSOLE, /* dwCreationFlags */
+ NULL, /* use parent's environment */
+ NULL, /* use parent's starting */
+ /* directory */
+ &si, /* startup info struct */
+ &pi ) /* process info struct */
+ )
+ {
+ Fail( "ERROR:%lu:CreateProcess call failed\n",
+ GetLastError() );
+ }
+
+ /* verify that the event is signalled by the child process */
+ dwRet = WaitForSingleObject( hEvent, TIMEOUT );
+ if( dwRet != WAIT_OBJECT_0 )
+ {
+ ret = FAIL;
+ /* ERROR */
+ Trace( "ERROR:WaitForSingleObject() call returned %lu, "
+ "expected WAIT_TIMEOUT\n",
+ "expected WAIT_OBJECT_0\n",
+ dwRet );
+
+ goto cleanup;
+
+ if( !CloseHandle( hEvent ) )
+ {
+ Trace( "ERROR:%lu:CloseHandle() call failed in child\n",
+ GetLastError());
+ }
+ goto cleanup;
+ }
+
+ /* wait for the child process to complete */
+ dwRet = WaitForSingleObject ( pi.hProcess, TIMEOUT );
+ if( dwRet != WAIT_OBJECT_0 )
+ {
+ ret = FAIL;
+ Trace( "ERROR:WaitForSingleObject() returned %lu, "
+ "expected %lu\n",
+ dwRet,
+ WAIT_OBJECT_0 );
+ goto cleanup;
+ }
+
+ /* check the exit code from the process */
+ if( ! GetExitCodeProcess( pi.hProcess, &dwExitCode ) )
+ {
+ ret = FAIL;
+ Trace( "ERROR:%lu:GetExitCodeProcess call failed\n",
+ GetLastError() );
+ goto cleanup;
+ }
+
+ /* check for success */
+ ret = (dwExitCode == PASS) ? PASS : FAIL;
+
+cleanup:
+ if( hEvent != NULL )
+ {
+ if( ! CloseHandle ( hEvent ) )
+ {
+ Trace( "ERROR:%lu:CloseHandle call failed on event handle\n",
+ GetLastError() );
+ ret = FAIL;
+ }
+ }
+
+
+ /* close process and thread handle */
+ if( ! CloseHandle ( pi.hProcess ) )
+ {
+ Trace( "ERROR:%lu:CloseHandle call failed on process handle\n",
+ GetLastError() );
+ ret = FAIL;
+ }
+
+ if( ! CloseHandle ( pi.hThread ) )
+ {
+ Trace( "ERROR:%lu:CloseHandle call failed on thread handle\n",
+ GetLastError() );
+ ret = FAIL;
+ }
+
+ /* output a convenient error message and exit if we failed */
+ if( ret == FAIL )
+ {
+ Fail( "test failed\n" );
+ }
+
+
+ /* terminate the PAL */
+ PAL_Terminate();
+
+ /* return success */
+ return ret;
+}
diff --git a/src/pal/tests/palsuite/threading/OpenEventW/test3/testinfo.dat b/src/pal/tests/palsuite/threading/OpenEventW/test3/testinfo.dat
new file mode 100644
index 0000000000..96b2c06644
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/OpenEventW/test3/testinfo.dat
@@ -0,0 +1,21 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = OpenEventW
+Name = Test for OpenEventW
+TYPE = DEFAULT
+EXE1 = test3
+EXE2 = childprocess
+Description
+= Purpose: Test to ensure that OpenEventW() works when
+= opening an event created by another process. This test
+= program launches a child process which creates a
+= named, initially-unset event. The child waits up to
+= 10 seconds for the parent process to open that event
+= and set it, and returns PASS if the event was set or FAIL
+= otherwise. The parent process checks the return value
+= from the child to verify that the opened event was
+= properly used across processes.
diff --git a/src/pal/tests/palsuite/threading/OpenEventW/test4/CMakeLists.txt b/src/pal/tests/palsuite/threading/OpenEventW/test4/CMakeLists.txt
new file mode 100644
index 0000000000..ff17fea23b
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/OpenEventW/test4/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test4.c
+)
+
+add_executable(paltest_openeventw_test4
+ ${SOURCES}
+)
+
+add_dependencies(paltest_openeventw_test4 coreclrpal)
+
+target_link_libraries(paltest_openeventw_test4
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/OpenEventW/test4/test4.c b/src/pal/tests/palsuite/threading/OpenEventW/test4/test4.c
new file mode 100644
index 0000000000..ae657a0511
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/OpenEventW/test4/test4.c
@@ -0,0 +1,112 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================================
+**
+** Source: test4.c
+**
+** Purpose: Positive test for OpenEventW.
+**
+** Dependencies: PAL_Initialize
+** PAL_Terminate
+** CreateEvent
+** CloseHandle
+** WaitForSingleObject
+**
+** Purpose:
+**
+** Test to ensure proper operation of the OpenEventW()
+** API by trying to open an event with a name that is
+** already taken by a non-event object.
+**
+**
+**===========================================================================*/
+#include <palsuite.h>
+
+
+
+int __cdecl main( int argc, char **argv )
+
+{
+ /* local variables */
+ BOOL bRet = PASS;
+ DWORD dwLastError = 0;
+ HANDLE hMutex = NULL;
+ HANDLE hTestEvent = NULL;
+ LPSECURITY_ATTRIBUTES lpSecurityAttributes = NULL;
+ BOOL bInitialState = TRUE;
+ WCHAR wcName[] = {'I','m','A','M','u','t','e','x','\0'};
+ LPWSTR lpName = wcName;
+
+
+ /* PAL initialization */
+ if( (PAL_Initialize(argc, argv)) != 0 )
+ {
+ return( FAIL );
+ }
+
+ /* create a mutex object */
+ hMutex = CreateMutexW( lpSecurityAttributes,
+ bInitialState,
+ lpName );
+
+ if( hMutex == NULL )
+ {
+ /* ERROR */
+ Fail( "ERROR:%lu:CreateMutexW() call failed\n", GetLastError() );
+ }
+
+ /* open a new handle to our event */
+ hTestEvent = OpenEventW(EVENT_ALL_ACCESS, /* we want all rights */
+ FALSE, /* no inherit */
+ lpName );
+
+ if( hTestEvent != NULL )
+ {
+ /* ERROR */
+ Trace( "ERROR:OpenEventW() call succeeded against a named "
+ "mutex, should have returned NULL\n" );
+ if( ! CloseHandle( hTestEvent ) )
+ {
+ Trace( "ERROR:%lu:CloseHandle() call failed \n", GetLastError() );
+ }
+ bRet = FAIL;
+ }
+ else
+ {
+ dwLastError = GetLastError();
+ if( dwLastError != ERROR_INVALID_HANDLE )
+ {
+ /* ERROR */
+ Trace( "ERROR:OpenEventW() call failed against a named "
+ "mutex, but returned an unexpected result: %lu\n",
+ dwLastError );
+ bRet = FAIL;
+ }
+ }
+
+
+ /* close the mutex handle */
+ if( ! CloseHandle( hMutex ) )
+ {
+ Trace( "ERROR:%lu:CloseHandle() call failed \n", GetLastError() );
+ bRet = FAIL;
+ }
+
+
+ /* fail here if we weren't successful */
+ if( bRet == FAIL )
+ {
+ Fail( "" );
+ }
+
+
+ /* PAL termination */
+ PAL_Terminate();
+
+ /* return success or failure */
+ return PASS;
+}
+
+
diff --git a/src/pal/tests/palsuite/threading/OpenEventW/test4/testinfo.dat b/src/pal/tests/palsuite/threading/OpenEventW/test4/testinfo.dat
new file mode 100644
index 0000000000..1b3f2d83c6
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/OpenEventW/test4/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = OpenEventW
+Name = Negative test for OpenEventW
+TYPE = DEFAULT
+EXE1 = test4
+Description
+= Test to ensure proper operation of the OpenEventW()
+= API by trying to open an event with a name that is
+= already taken by a non-event object.
diff --git a/src/pal/tests/palsuite/threading/OpenEventW/test5/CMakeLists.txt b/src/pal/tests/palsuite/threading/OpenEventW/test5/CMakeLists.txt
new file mode 100644
index 0000000000..b78d7fbfc0
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/OpenEventW/test5/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test5.c
+)
+
+add_executable(paltest_openeventw_test5
+ ${SOURCES}
+)
+
+add_dependencies(paltest_openeventw_test5 coreclrpal)
+
+target_link_libraries(paltest_openeventw_test5
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/OpenEventW/test5/test5.c b/src/pal/tests/palsuite/threading/OpenEventW/test5/test5.c
new file mode 100644
index 0000000000..43b585765c
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/OpenEventW/test5/test5.c
@@ -0,0 +1,197 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================================
+**
+** Source: test5.c
+**
+** Purpose: Positive test for OpenEventW.
+**
+** Dependencies: PAL_Initialize
+** PAL_Terminate
+** CreateEvent
+** CloseHandle
+** WaitForSingleObject
+**
+** Purpose:
+**
+** Test to ensure proper operation of the OpenEventW()
+** API by creating a new named event with CreateEventA()
+** and verifying that it can be opened with OpenEventW().
+** It should be possible to use the event handles
+** interchangeably, we test by setting the event with the
+** original handle and waiting on it with the new one,
+** then resetting it with the new one and waiting
+** on it with the original one.
+**
+**
+**===========================================================================*/
+#include <palsuite.h>
+
+
+
+int __cdecl main( int argc, char **argv )
+
+{
+ /* local variables */
+ BOOL ret = FAIL;
+ DWORD dwRet = 0;
+ HANDLE hEvent = NULL;
+ HANDLE hTestEvent = NULL;
+ LPSECURITY_ATTRIBUTES lpEventAttributes = NULL;
+ BOOL bManualReset = TRUE;
+ BOOL bInitialState = FALSE;
+ LPSTR lpNameA = "ShakeIt";
+ WCHAR wcName[] = {'S','h','a','k','e','I','t','\0'};
+ LPWSTR lpNameW = wcName;
+
+
+ /* PAL initialization */
+ if( (PAL_Initialize(argc, argv)) != 0 )
+ {
+ return( FAIL );
+ }
+
+
+ /* create an event which we can use with SetEvent */
+ hEvent = CreateEventA( lpEventAttributes,
+ bManualReset,
+ bInitialState,
+ lpNameA );
+
+ if( hEvent == NULL )
+ {
+ /* ERROR */
+ Fail( "ERROR:%lu:CreateEvent() call failed\n", GetLastError() );
+ }
+
+ /* open a new handle to our event */
+ hTestEvent = OpenEventW(EVENT_ALL_ACCESS, /* we want all rights */
+ FALSE, /* no inherit */
+ lpNameW );
+
+ if( hTestEvent == NULL )
+ {
+ /* ERROR */
+ Trace( "ERROR:%lu:OpenEventW() call failed\n", GetLastError() );
+ goto cleanup;
+ }
+
+ /* verify that the event isn't signalled yet by waiting on both */
+ /* handles to the event object */
+ dwRet = WaitForSingleObject( hEvent, 0 );
+ if( dwRet != WAIT_TIMEOUT )
+ {
+ /* ERROR */
+ Trace( "ERROR:WaitForSingleObject() call returned %lu, "
+ "expected WAIT_TIMEOUT\n",
+ dwRet );
+ goto cleanup;
+ }
+
+ dwRet = WaitForSingleObject( hTestEvent, 0 );
+ if( dwRet != WAIT_TIMEOUT )
+ {
+ /* ERROR */
+ Trace( "ERROR:WaitForSingleObject() call returned %lu, "
+ "expected WAIT_TIMEOUT\n",
+ dwRet );
+ goto cleanup;
+ }
+
+
+ /* set the event using the original handle */
+ if( ! SetEvent( hEvent ) )
+ {
+ /* ERROR */
+ Trace( "ERROR:%lu:SetEvent() call failed\n", GetLastError() );
+ goto cleanup;
+ }
+
+ /* verify that the event is signalled by waiting on both handles */
+ dwRet = WaitForSingleObject( hEvent, 0 );
+ if( dwRet != WAIT_OBJECT_0 )
+ {
+ /* ERROR */
+ Trace( "ERROR:WaitForSingleObject() call returned %lu, "
+ "expected WAIT_OBJECT_0\n",
+ dwRet );
+ goto cleanup;
+ }
+
+ dwRet = WaitForSingleObject( hTestEvent, 0 );
+ if( dwRet != WAIT_OBJECT_0 )
+ {
+ /* ERROR */
+ Trace( "ERROR:WaitForSingleObject() call returned %lu, "
+ "expected WAIT_OBJECT_0\n",
+ dwRet );
+ goto cleanup;
+ }
+
+ /* reset the event using the new handle */
+ if( ! ResetEvent( hTestEvent ) )
+ {
+ /* ERROR */
+ Trace( "ERROR:%lu:ResetEvent() call failed\n", GetLastError() );
+ goto cleanup;
+ }
+
+ /* verify that the event isn't signalled by waiting on both handles */
+ dwRet = WaitForSingleObject( hEvent, 0 );
+ if( dwRet != WAIT_TIMEOUT )
+ {
+ /* ERROR */
+ Trace( "ERROR:WaitForSingleObject() call returned %lu, "
+ "expected WAIT_TIMEOUT\n",
+ dwRet );
+ goto cleanup;
+ }
+
+ dwRet = WaitForSingleObject( hTestEvent, 0 );
+ if( dwRet != WAIT_TIMEOUT )
+ {
+ /* ERROR */
+ Trace( "ERROR:WaitForSingleObject() call returned %lu, "
+ "expected WAIT_TIMEOUT\n",
+ dwRet );
+ goto cleanup;
+ }
+
+
+ /* test was successful */
+ ret = PASS;
+
+
+cleanup:
+ /* close the new event handle */
+ if( hTestEvent != NULL )
+ {
+ if( ! CloseHandle( hTestEvent ) )
+ {
+ ret = FAIL;
+ Trace( "ERROR:%lu:CloseHandle() call failed\n", GetLastError() );
+ }
+ }
+
+ /* close the original event handle */
+ if( ! CloseHandle( hEvent ) )
+ {
+ ret = FAIL;
+ Trace( "ERROR:%lu:CloseHandle() call failed\n", GetLastError() );
+ }
+
+ /* failure message */
+ if( ret != PASS )
+ {
+ Fail( "Test failed\n" );
+ }
+
+
+ /* PAL termination */
+ PAL_Terminate();
+
+ /* return success or failure */
+ return ret;
+}
diff --git a/src/pal/tests/palsuite/threading/OpenEventW/test5/testinfo.dat b/src/pal/tests/palsuite/threading/OpenEventW/test5/testinfo.dat
new file mode 100644
index 0000000000..f5af943a7c
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/OpenEventW/test5/testinfo.dat
@@ -0,0 +1,19 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = OpenEventW
+Name = Positive test for OpenEventW
+TYPE = DEFAULT
+EXE1 = test5
+Description
+= Test to ensure proper operation of the OpenEventW()
+= API by creating a new named event with CreateEventA()
+= and verifying that it can be opened with OpenEventW().
+= It should be possible to use the event handles
+= interchangeably, we test by setting the event with the
+= original handle and waiting on it with the new one,
+= then resetting it with the new one and waiting
+= on it with the original one.
diff --git a/src/pal/tests/palsuite/threading/OpenProcess/CMakeLists.txt b/src/pal/tests/palsuite/threading/OpenProcess/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/OpenProcess/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/threading/OpenProcess/test1/CMakeLists.txt b/src/pal/tests/palsuite/threading/OpenProcess/test1/CMakeLists.txt
new file mode 100644
index 0000000000..26d30547a9
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/OpenProcess/test1/CMakeLists.txt
@@ -0,0 +1,36 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(TESTSOURCES
+ test1.c
+)
+
+add_executable(paltest_openprocess_test1
+ ${TESTSOURCES}
+)
+
+add_dependencies(paltest_openprocess_test1 coreclrpal)
+
+target_link_libraries(paltest_openprocess_test1
+ pthread
+ m
+ coreclrpal
+)
+
+
+set(HELPERSOURCES
+ childProcess.c
+)
+
+add_executable(paltest_openprocess_test1_child
+ ${HELPERSOURCES}
+)
+
+add_dependencies(paltest_openprocess_test1_child coreclrpal)
+
+target_link_libraries(paltest_openprocess_test1_child
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/OpenProcess/test1/childProcess.c b/src/pal/tests/palsuite/threading/OpenProcess/test1/childProcess.c
new file mode 100644
index 0000000000..9ef07433fd
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/OpenProcess/test1/childProcess.c
@@ -0,0 +1,75 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: childprocess.c
+**
+** Purpose: Test to ensure OpenProcess works properly.
+** All this program does is return a predefined value.
+**
+** Dependencies: PAL_Initialize
+** PAL_Terminate
+** CreateMutexW
+** WaitForSingleObject
+** CloseHandle
+**
+**
+**=========================================================*/
+
+#include <palsuite.h>
+#include "myexitcode.h"
+
+
+int __cdecl main( int argc, char **argv )
+{
+ HANDLE hMutex;
+ WCHAR wszMutexName[] = { 'T','E','S','T','1','\0' };
+ DWORD dwRet;
+ int i;
+
+ /* initialize the PAL */
+ if( PAL_Initialize(argc, argv) != 0 )
+ {
+ return( FAIL );
+ }
+
+ /* open a mutex to synchronize with the parent process */
+ hMutex = CreateMutexW( NULL, FALSE, wszMutexName );
+ if( hMutex == NULL )
+ {
+ Fail( "ERROR:%lu:CreateMutex() call failed\r\n", GetLastError() );
+ }
+
+ /* acquire the mutex lock */
+ dwRet = WaitForSingleObject( hMutex, 10000 );
+ if( dwRet != WAIT_OBJECT_0 )
+ {
+ Trace( "ERROR:WaitForSingleObject() returned %lu, "
+ "expected WAIT_OBJECT_0",
+ dwRet );
+ if( ! CloseHandle( hMutex ) )
+ {
+ Trace( "ERROR:%lu:CloseHandle() call failed\n", GetLastError() );
+ }
+ Fail( "test failed\n" );
+ }
+
+
+ /* simulate some activity */
+ for( i=0; i<50000; i++ )
+ ;
+
+ /* close our mutex handle */
+ if( ! CloseHandle( hMutex ) )
+ {
+ Fail( "ERROR:%lu:CloseHandle() call failed\n", GetLastError() );
+ }
+
+ /* terminate the PAL */
+ PAL_Terminate();
+
+ /* return the predefined exit code */
+ return TEST_EXIT_CODE;
+}
diff --git a/src/pal/tests/palsuite/threading/OpenProcess/test1/myexitcode.h b/src/pal/tests/palsuite/threading/OpenProcess/test1/myexitcode.h
new file mode 100644
index 0000000000..66b8f43a97
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/OpenProcess/test1/myexitcode.h
@@ -0,0 +1,14 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: myexitcode.h
+**
+** Purpose: Define an exit code.
+**
+**
+**==========================================================================*/
+
+#define TEST_EXIT_CODE 317
diff --git a/src/pal/tests/palsuite/threading/OpenProcess/test1/test1.c b/src/pal/tests/palsuite/threading/OpenProcess/test1/test1.c
new file mode 100644
index 0000000000..d0f9019646
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/OpenProcess/test1/test1.c
@@ -0,0 +1,282 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Test to ensure OpenProcess works properly.
+**
+** Dependencies: PAL_Initialize
+** PAL_Terminate
+** Fail
+** ZeroMemory
+** GetCurrentDirectoryW
+** CreateProcessW
+** WaitForSingleObject
+** CreateMutexW
+** ReleaseMutex
+** CloseHandle
+** GetLastError
+** strlen
+** strncpy
+**
+**
+**===========================================================================*/
+#include <palsuite.h>
+#include "myexitcode.h"
+
+
+static const char* rgchPathDelim = "\\";
+
+
+int
+mkAbsoluteFilename( LPSTR dirName,
+ DWORD dwDirLength,
+ LPCSTR fileName,
+ DWORD dwFileLength,
+ LPSTR absPathName )
+{
+ DWORD sizeDN, sizeFN, sizeAPN;
+
+ sizeDN = strlen( dirName );
+ sizeFN = strlen( fileName );
+ sizeAPN = (sizeDN + 1 + sizeFN + 1);
+
+ /* ensure ((dirName + DELIM + fileName + \0) =< _MAX_PATH ) */
+ if( sizeAPN > _MAX_PATH )
+ {
+ return ( 0 );
+ }
+
+ strncpy( absPathName, dirName, dwDirLength +1 );
+ strncpy( absPathName, rgchPathDelim, 2 );
+ strncpy( absPathName, fileName, dwFileLength +1 );
+
+ return (sizeAPN);
+
+}
+
+
+int __cdecl main( int argc, char **argv )
+
+{
+ const char* rgchChildFile = "childprocess";
+
+ STARTUPINFO si;
+ PROCESS_INFORMATION pi;
+
+ DWORD dwError;
+ DWORD dwExitCode;
+ DWORD dwFileLength;
+ DWORD dwDirLength;
+ DWORD dwSize;
+ DWORD dwRet;
+
+ HANDLE hMutex;
+ HANDLE hChildProcess;
+
+ char rgchDirName[_MAX_DIR];
+ char absPathBuf[_MAX_PATH];
+ char* rgchAbsPathName;
+
+ BOOL ret = FAIL;
+ BOOL bChildDone = FALSE;
+ WCHAR wszMutexName[] = { 'T','E','S','T','1','\0' };
+
+ /* initialize the PAL */
+ if( PAL_Initialize(argc, argv) != 0 )
+ {
+ return( FAIL );
+ }
+
+ /* create a mutex to synchronize with the child process */
+ hMutex = CreateMutexW( NULL, TRUE, wszMutexName );
+ if( hMutex == NULL )
+ {
+ Fail( "ERROR:%lu:CreateMutex() call failed\r\n", GetLastError() );
+ }
+
+ /* zero our process and startup info structures */
+ ZeroMemory( &si, sizeof(si) );
+ si.cb = sizeof( si );
+ ZeroMemory( &pi, sizeof(pi) );
+
+ /* build the absolute path to the child process */
+ rgchAbsPathName = &absPathBuf[0];
+ dwFileLength = strlen( rgchChildFile );
+
+ dwDirLength = GetCurrentDirectory( _MAX_PATH, rgchDirName );
+ if( dwDirLength == 0 )
+ {
+ dwError = GetLastError();
+ if( ReleaseMutex( hMutex ) == 0 )
+ {
+ Trace( "ERROR:%lu:ReleaseMutex() call failed\n", GetLastError() );
+ }
+ if( CloseHandle( hMutex ) == 0 )
+ {
+ Trace( "ERROR:%lu:CloseHandle() call failed\n", GetLastError() );
+ }
+ Fail( "GetCurrentDirectory call failed with error code %d\n",
+ dwError );
+ }
+
+ dwSize = mkAbsoluteFilename( rgchDirName,
+ dwDirLength,
+ rgchChildFile,
+ dwFileLength,
+ rgchAbsPathName );
+ if( dwSize == 0 )
+ {
+ if( ReleaseMutex( hMutex ) == 0 )
+ {
+ Trace( "ERROR:%lu:ReleaseMutex() call failed\n", GetLastError() );
+ }
+ if( CloseHandle( hMutex ) == 0 )
+ {
+ Trace( "ERROR:%lu:CloseHandle() call failed\n", GetLastError() );
+ }
+ Fail( "Palsuite Code: mkAbsoluteFilename() call failed. Could ",
+ "not build absolute path name to file\n. Exiting.\n" );
+ }
+
+ /* launch the child process */
+ if( !CreateProcess( NULL, /* module name to execute */
+ rgchAbsPathName, /* command line */
+ NULL, /* process handle not */
+ /* inheritable */
+ NULL, /* thread handle not */
+ /*inheritable */
+ FALSE, /* handle inheritance */
+ CREATE_NEW_CONSOLE, /* dwCreationFlags */
+ NULL, /* use parent's environment */
+ NULL, /* use parent's starting */
+ /* directory */
+ &si, /* startup info struct */
+ &pi ) /* process info struct */
+ )
+ {
+ dwError = GetLastError();
+ if( ReleaseMutex( hMutex ) == 0 )
+ {
+ Trace( "ERROR:%lu:ReleaseMutex() call failed\n", GetLastError() );
+ }
+ if( CloseHandle( hMutex ) == 0 )
+ {
+ Trace( "ERROR:%lu:CloseHandle() call failed\n", GetLastError() );
+ }
+ Fail( "CreateProcess call failed with error code %d\n",
+ dwError );
+ }
+
+ /* open another handle to the child process */
+ hChildProcess = OpenProcess( PROCESS_ALL_ACCESS, /* access */
+ FALSE, /* inheritable */
+ pi.dwProcessId /* process id */
+ );
+ if( hChildProcess == NULL )
+ {
+ dwError = GetLastError();
+ if( ReleaseMutex( hMutex ) == 0 )
+ {
+ Trace( "ERROR:%lu:ReleaseMutex() call failed\n", GetLastError() );
+ }
+ Trace( "ERROR:%lu:OpenProcess call failed\n", dwError );
+ goto cleanup2;
+ }
+
+ /* release the mutex so the child can proceed */
+ if( ReleaseMutex( hMutex ) == 0 )
+ {
+ Trace( "ERROR:%lu:ReleaseMutex() call failed\n", GetLastError() );
+ goto cleanup;
+ }
+
+ /* wait for the child process to complete, using the new handle */
+ dwRet = WaitForSingleObject( hChildProcess, 10000 );
+ if( dwRet != WAIT_OBJECT_0 )
+ {
+ Trace( "ERROR:WaitForSingleObject call returned %lu, "
+ "expected WAIT_OBJECT_0",
+ dwRet );
+ goto cleanup;
+ }
+
+ /* remember that we waited until the child was finished */
+ bChildDone = TRUE;
+
+ /* check the exit code from the process -- this is a bit of an */
+ /* extra verification that we opened the correct process handle */
+ if( ! GetExitCodeProcess( hChildProcess, &dwExitCode ) )
+ {
+ Trace( "ERROR:%lu:GetExitCodeProcess call failed\n", GetLastError() );
+ goto cleanup;
+ }
+
+ /* verification */
+ if( (dwExitCode & 0xFF) != (TEST_EXIT_CODE & 0xFF) )
+ {
+ Trace( "GetExitCodeProcess returned an incorrect exit code %d, "
+ "expected value is %d\n",
+ (dwExitCode & 0xFF),
+ (TEST_EXIT_CODE & 0xFF));
+ goto cleanup;
+ }
+
+ /* success if we get here */
+ ret = PASS;
+
+
+cleanup:
+ /* wait on the child process to complete if necessary */
+ if( ! bChildDone )
+ {
+ dwRet = WaitForSingleObject( hChildProcess, 10000 );
+ if( dwRet != WAIT_OBJECT_0 )
+ {
+ Trace( "ERROR:WaitForSingleObject call returned %lu, "
+ "expected WAIT_OBJECT_0",
+ dwRet );
+ ret = FAIL;
+ }
+ }
+
+ /* close all our handles */
+ if( CloseHandle ( hChildProcess ) == 0 )
+ {
+ Trace( "ERROR:%lu:CloseHandle() call failed\n", GetLastError() );
+ ret = FAIL;
+ }
+
+cleanup2:
+ if( CloseHandle ( pi.hProcess ) == 0 )
+ {
+ Trace( "ERROR:%lu:CloseHandle() call failed\n", GetLastError() );
+ ret = FAIL;
+ }
+ if( CloseHandle ( pi.hThread ) == 0 )
+ {
+ Trace( "ERROR:%lu:CloseHandle() call failed\n", GetLastError() );
+ ret = FAIL;
+ }
+ if( CloseHandle( hMutex ) == 0 )
+ {
+ Trace( "ERROR:%lu:CloseHandle() call failed\n", GetLastError() );
+ ret = FAIL;
+ }
+
+ if( ret == FAIL )
+ {
+ Fail( "test failed\n" );
+ }
+
+
+
+ /* terminate the PAL */
+ PAL_Terminate();
+
+ /* return success */
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/threading/OpenProcess/test1/testinfo.dat b/src/pal/tests/palsuite/threading/OpenProcess/test1/testinfo.dat
new file mode 100644
index 0000000000..dd6b2c0ffe
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/OpenProcess/test1/testinfo.dat
@@ -0,0 +1,19 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = OpenProcess
+Name = Test for OpenProcess
+TYPE = DEFAULT
+EXE1 = test1
+EXE2 = childprocess
+Description
+= Test to ensure proper operation of the OpenProcess API.
+= The test launches a trivial child process, then opens
+= a handle to it using OpenProcess. It uses that handle
+= to wait for the child process to terminate, and then
+= checks the exit code of the child process in order to
+= verify that it was in fact a handle to the correct
+= process.
diff --git a/src/pal/tests/palsuite/threading/QueryThreadCycleTime/CMakeLists.txt b/src/pal/tests/palsuite/threading/QueryThreadCycleTime/CMakeLists.txt
new file mode 100644
index 0000000000..5e1ef7f28b
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/QueryThreadCycleTime/CMakeLists.txt
@@ -0,0 +1,3 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
diff --git a/src/pal/tests/palsuite/threading/QueryThreadCycleTime/test1/CMakeLists.txt b/src/pal/tests/palsuite/threading/QueryThreadCycleTime/test1/CMakeLists.txt
new file mode 100644
index 0000000000..ad3eec1a45
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/QueryThreadCycleTime/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_querythreadcycletime_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_querythreadcycletime_test1 coreclrpal)
+
+target_link_libraries(paltest_querythreadcycletime_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/QueryThreadCycleTime/test1/test1.c b/src/pal/tests/palsuite/threading/QueryThreadCycleTime/test1/test1.c
new file mode 100644
index 0000000000..54f0116bd0
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/QueryThreadCycleTime/test1/test1.c
@@ -0,0 +1,98 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source:
+**
+** Source : test1.c
+**
+** Purpose: Test for QueryThreadCycleTime() function
+**
+**
+**=========================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char *argv[]) {
+ int ret = FAIL;
+
+ //Test is failing unreliably, so for now we always return pass.
+ if (TRUE){
+ ret = PASS;
+ goto EXIT;
+ }
+
+ LONG64 Actual, Expected, Delta = 850000000;
+ Actual = 0;
+ Expected = 0;
+ const LONG64 MSEC_TO_NSEC = 1000000;
+
+ /*
+ * Initialize the PAL and return FAILURE if this fails
+ */
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ HANDLE cThread = GetCurrentThread();
+
+ int i;
+ /* Take 2000 tiny measurements */
+ for (i = 0; i < 2000; i++){
+ ULONG64 FirstCount, SecondCount;
+ LONG64 Init;
+
+ Sleep(1);
+
+ /* Grab a FirstCount, then loop for a bit to make the clock increase */
+ if (!QueryThreadCycleTime(cThread, (PULONG64)&FirstCount))
+ {
+ Fail("ERROR: QueryThreadCycleTime returned failure.\n");
+ }
+
+ LONG64 x;
+ /* Init is in milliseconds, so we will convert later */
+ Init = (LONG64)GetTickCount();
+ x = Init + 3;
+ volatile int counter;
+ do {
+ for (counter = 0; counter < 100000; counter++)
+ {
+ // spin to consume CPU time
+ }
+
+ } while (x > GetTickCount());
+ Expected += (GetTickCount() - Init) * MSEC_TO_NSEC;
+ /* Get a second count */
+ if (!QueryThreadCycleTime(cThread, (PULONG64)&SecondCount))
+ {
+ Fail("ERROR: QueryThreadCycleTime returned failure.\n");
+ }
+
+ LONG64 trial = (LONG64)SecondCount - (LONG64)FirstCount;
+ if (trial < 0){
+ printf("Negative value %llu measured", trial);
+ }
+ Actual += (trial);
+
+ }
+
+
+
+ if(labs(Expected - Actual) > Delta)
+ {
+ Fail("ERROR: The measured time (%llu millisecs) was not within Delta %llu "
+ "of the expected time (%llu millisecs).\n",
+ (Actual / MSEC_TO_NSEC), (Delta / MSEC_TO_NSEC), (Expected / MSEC_TO_NSEC));
+ }
+ //printf("%llu, %llu\n", Expected, Actual);
+ PAL_Terminate();
+ ret = PASS;
+
+EXIT:
+ return ret;
+}
diff --git a/src/pal/tests/palsuite/threading/QueueUserAPC/CMakeLists.txt b/src/pal/tests/palsuite/threading/QueueUserAPC/CMakeLists.txt
new file mode 100644
index 0000000000..19ee487a6a
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/QueueUserAPC/CMakeLists.txt
@@ -0,0 +1,10 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+add_subdirectory(test3)
+add_subdirectory(test4)
+add_subdirectory(test5)
+add_subdirectory(test6)
+add_subdirectory(test7)
+
diff --git a/src/pal/tests/palsuite/threading/QueueUserAPC/test1/CMakeLists.txt b/src/pal/tests/palsuite/threading/QueueUserAPC/test1/CMakeLists.txt
new file mode 100644
index 0000000000..54a4d03719
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/QueueUserAPC/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_queueuserapc_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_queueuserapc_test1 coreclrpal)
+
+target_link_libraries(paltest_queueuserapc_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/QueueUserAPC/test1/test1.c b/src/pal/tests/palsuite/threading/QueueUserAPC/test1/test1.c
new file mode 100644
index 0000000000..3637897ba7
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/QueueUserAPC/test1/test1.c
@@ -0,0 +1,313 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test1.c
+**
+** Purpose: Tests that APCs sent to a thread in an alertable state via
+** QueueUserAPC are executed in FIFO order. Also tests that the APC
+** function is executed within the context of the correct thread and
+** that the dwData parameter gets sent correctly.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+const int ChildThreadSleepTime = 2000;
+const int InterruptTime = 1000;
+
+VOID PALAPI APCFuncA(ULONG_PTR dwParam);
+VOID PALAPI APCFuncB(ULONG_PTR dwParam);
+VOID PALAPI APCFuncC(ULONG_PTR dwParam);
+VOID PALAPI APCFuncD(ULONG_PTR dwParam);
+DWORD PALAPI SleeperProc(LPVOID lpParameter);
+
+const char *ExpectedResults = "A0B0C0D0A1B1C1D1A2B2C2D2A3B3C3D3";
+char ResultBuffer[256];
+char *ResultPtr;
+DWORD ChildThread;
+
+/* synchronization events */
+static HANDLE hSyncEvent1 = NULL;
+static HANDLE hSyncEvent2 = NULL;
+
+/* thread result because we have no GetExitCodeThread() API */
+BOOL bThreadResult = FAIL;
+
+int __cdecl main (int argc, char **argv)
+{
+ HANDLE hThread = NULL;
+ int ret;
+ int i,j;
+ BOOL bResult = FAIL;
+
+ PAPCFUNC APCFuncs[] =
+ {
+ APCFuncA,
+ APCFuncB,
+ APCFuncC,
+ APCFuncD,
+ };
+
+ /* initialize the PAL */
+ if (0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ ResultPtr = ResultBuffer;
+
+ /* create a pair of synchronization events to coordinate our threads */
+ hSyncEvent1 = CreateEvent( NULL, FALSE, FALSE, NULL );
+ if( hSyncEvent1 == NULL )
+ {
+ Trace( "ERROR:%lu:CreateEvent() call failed\n", GetLastError() );
+ goto cleanup;
+ }
+
+ hSyncEvent2 = CreateEvent( NULL, FALSE, FALSE, NULL );
+ if( hSyncEvent2 == NULL )
+ {
+ Trace( "ERROR:%lu:CreateEvent() call failed\n", GetLastError() );
+ goto cleanup;
+ }
+
+ /* create a child thread which will call SleepEx */
+ hThread = CreateThread( NULL,
+ 0,
+ (LPTHREAD_START_ROUTINE)SleeperProc,
+ 0,
+ 0,
+ &ChildThread);
+
+ if( hThread == NULL )
+ {
+ Trace( "ERROR:%lu:CreateThread() call failed\n",
+ GetLastError());
+ goto cleanup;
+ }
+
+
+ /* wait on our synchronization event to ensure the thread is running */
+ ret = WaitForSingleObject( hSyncEvent1, 20000 );
+ if( ret != WAIT_OBJECT_0 )
+ {
+ Trace( "ERROR:WaitForSingleObject() returned %lu, "
+ "expected WAIT_OBJECT_0\n",
+ ret );
+ goto cleanup;
+ }
+
+
+ /* queue our user APC functions on the thread */
+ for (i=0; i<4; i++)
+ {
+ for (j=0; j<sizeof(APCFuncs)/sizeof(APCFuncs[0]); j++)
+ {
+ ret = QueueUserAPC(APCFuncs[j], hThread, '0' + i);
+ if (ret == 0)
+ {
+ Trace( "ERROR:%lu:QueueUserAPC() call failed\n",
+ GetLastError());
+ goto cleanup;
+ }
+ }
+ }
+
+ /* signal the child thread to continue */
+ if( ! SetEvent( hSyncEvent2 ) )
+ {
+ Trace( "ERROR:%lu:SetEvent() call failed\n", GetLastError() );
+ goto cleanup;
+ }
+
+
+ /* wait on our synchronization event to ensure the other thread is done */
+ ret = WaitForSingleObject( hSyncEvent1, 20000 );
+ if( ret != WAIT_OBJECT_0 )
+ {
+ Trace( "ERROR:WaitForSingleObject() returned %lu, "
+ "expected WAIT_OBJECT_0\n",
+ ret );
+ goto cleanup;
+ }
+
+
+ /* check that the thread executed successfully */
+ if( bThreadResult == FAIL )
+ {
+ goto cleanup;
+ }
+
+
+ /* check the result buffer */
+ if (strcmp(ExpectedResults, ResultBuffer) != 0)
+ {
+ Trace( "FAIL:Expected the APC function calls to produce a result of "
+ " \"%s\", got \"%s\"\n",
+ ExpectedResults,
+ ResultBuffer );
+ goto cleanup;
+ }
+
+ /* success if we get here */
+ bResult = PASS;
+
+cleanup:
+ /* wait for the other thread to finish */
+ if( hThread != NULL )
+ {
+ ret = WaitForSingleObject( hThread, INFINITE );
+ if (ret == WAIT_FAILED)
+ {
+ Trace( "ERROR:%lu:WaitForSingleObject() returned %lu, "
+ "expected WAIT_OBJECT_0\n",
+ ret );
+ bResult = FAIL;
+ }
+ }
+
+ /* close our synchronization handles */
+ if( hSyncEvent1 != NULL )
+ {
+ if( ! CloseHandle( hSyncEvent1 ) )
+ {
+ Trace( "ERROR:%lu:CloseHandle() call failed\n", GetLastError() );
+ bResult = FAIL;
+ }
+ }
+
+ if( hSyncEvent2 != NULL )
+ {
+ if( ! CloseHandle( hSyncEvent2 ) )
+ {
+ Trace( "ERROR:%lu:CloseHandle() call failed\n", GetLastError() );
+ bResult = FAIL;
+ }
+ }
+
+ if( bResult == FAIL )
+ {
+ Fail( "test failed\n" );
+ }
+
+ /* terminate the PAL */
+ PAL_Terminate();
+
+ /* return success */
+ return PASS;
+}
+
+VOID PALAPI APCFuncA(ULONG_PTR dwParam)
+{
+ char val = (int) dwParam;
+
+ if (GetCurrentThreadId() != ChildThread)
+ {
+ Fail("Executing APC in thread %d, should be in %d!\n",
+ GetCurrentThreadId(), ChildThread);
+ }
+
+ *ResultPtr++ = 'A';
+ *ResultPtr++ = val;
+ *ResultPtr = 0;
+}
+
+VOID PALAPI APCFuncB(ULONG_PTR dwParam)
+{
+ char val = (int) dwParam;
+
+ if (GetCurrentThreadId() != ChildThread)
+ {
+ Fail("Executing APC in thread %d, should be in %d!\n",
+ GetCurrentThreadId(), ChildThread);
+ }
+
+ *ResultPtr++ = 'B';
+ *ResultPtr++ = val;
+ *ResultPtr = 0;
+}
+
+VOID PALAPI APCFuncC(ULONG_PTR dwParam)
+{
+ char val = (int) dwParam;
+
+ if (GetCurrentThreadId() != ChildThread)
+ {
+ Fail("Executing APC in thread %d, should be in %d!\n",
+ GetCurrentThreadId(), ChildThread);
+ }
+
+ *ResultPtr++ = 'C';
+ *ResultPtr++ = val;
+ *ResultPtr = 0;
+}
+
+VOID PALAPI APCFuncD(ULONG_PTR dwParam)
+{
+ char val = (int) dwParam;
+
+ if (GetCurrentThreadId() != ChildThread)
+ {
+ Fail("Executing APC in thread %d, should be in %d!\n",
+ GetCurrentThreadId(), ChildThread);
+ }
+
+ *ResultPtr++ = 'D';
+ *ResultPtr++ = val;
+ *ResultPtr = 0;
+}
+
+/* Entry Point for child thread. All it does is call SleepEx. */
+DWORD PALAPI SleeperProc(LPVOID lpParameter)
+{
+ DWORD ret;
+
+ /* signal the main thread that we're ready to proceed */
+ if( ! SetEvent( hSyncEvent1 ) )
+ {
+ Trace( "ERROR:%lu:SetEvent() call failed\n", GetLastError() );
+ bThreadResult = FAIL;
+ goto done;
+ }
+
+ /* wait for notification from the main thread */
+ ret = WaitForSingleObject( hSyncEvent2, 20000 );
+ if( ret != WAIT_OBJECT_0 )
+ {
+ Trace( "ERROR:WaitForSingleObject() returned %lu, "
+ "expected WAIT_OBJECT_0\n",
+ ret );
+ bThreadResult = FAIL;
+ goto done;
+ }
+
+ /* call SleepEx to activate any queued APCs */
+ ret = SleepEx(ChildThreadSleepTime, TRUE);
+ if (ret != WAIT_IO_COMPLETION)
+ {
+ Trace( "ERROR:SleepEx() call returned %lu, "
+ "expected WAIT_IO_COMPLETION\n",
+ ret );
+ bThreadResult = FAIL;
+ goto done;
+ }
+
+ /* everything passed here */
+ bThreadResult = PASS;
+
+
+done:
+ /* signal the main thread that we're finished */
+ if( ! SetEvent( hSyncEvent1 ) )
+ {
+ Trace( "ERROR:%lu:SetEvent() call failed\n", GetLastError() );
+ bThreadResult = FAIL;
+ }
+
+ /* return success or failure */
+ return bThreadResult;
+}
diff --git a/src/pal/tests/palsuite/threading/QueueUserAPC/test1/testinfo.dat b/src/pal/tests/palsuite/threading/QueueUserAPC/test1/testinfo.dat
new file mode 100644
index 0000000000..fbe8343d81
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/QueueUserAPC/test1/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = QueueUserAPC
+Name = Test #1 for QueueUserAPC
+TYPE = DEFAULT
+EXE1 = test1
+Description
+=Tests that APCs sent to a thread in an alertable state via
+=QueueUserAPC are executed in FIFO order. Also tests that the APC
+=function is executed within the context of the correct thread and
+=that the dwData parameter gets sent correctly.
diff --git a/src/pal/tests/palsuite/threading/QueueUserAPC/test2/CMakeLists.txt b/src/pal/tests/palsuite/threading/QueueUserAPC/test2/CMakeLists.txt
new file mode 100644
index 0000000000..88cda5f7b1
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/QueueUserAPC/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test2.c
+)
+
+add_executable(paltest_queueuserapc_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_queueuserapc_test2 coreclrpal)
+
+target_link_libraries(paltest_queueuserapc_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/QueueUserAPC/test2/test2.c b/src/pal/tests/palsuite/threading/QueueUserAPC/test2/test2.c
new file mode 100644
index 0000000000..dc2bfdb173
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/QueueUserAPC/test2/test2.c
@@ -0,0 +1,224 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test2.c
+**
+** Purpose: Tests that APCs are not executed if a thread never enters an
+** alertable state after they are queued.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+const int ChildThreadSleepTime = 2000;
+const int InterruptTime = 1000;
+
+DWORD ChildThread;
+BOOL InAPC;
+
+/* synchronization events */
+static HANDLE hSyncEvent1 = NULL;
+static HANDLE hSyncEvent2 = NULL;
+
+/* thread result because we have no GetExitCodeThread() API */
+static BOOL bThreadResult = FAIL;
+
+
+VOID PALAPI APCFunc(ULONG_PTR dwParam)
+{
+ InAPC = TRUE;
+}
+
+DWORD PALAPI SleeperProc(LPVOID lpParameter)
+{
+ DWORD ret;
+
+ /* signal the main thread that we're ready to proceed */
+ if( ! SetEvent( hSyncEvent1 ) )
+ {
+ Trace( "ERROR:%lu:SetEvent() call failed\n", GetLastError() );
+ bThreadResult = FAIL;
+ goto done;
+ }
+
+ /* wait for notification from the main thread */
+ ret = WaitForSingleObject( hSyncEvent2, 20000 );
+ if( ret != WAIT_OBJECT_0 )
+ {
+ Trace( "ERROR:WaitForSingleObject() returned %lu, "
+ "expected WAIT_OBJECT_0\n",
+ ret );
+ bThreadResult = FAIL;
+ goto done;
+ }
+
+ /* call our sleep function */
+ Sleep( ChildThreadSleepTime );
+
+ /* success if we reach here */
+ bThreadResult = PASS;
+
+
+done:
+
+ /* signal the main thread that we're finished */
+ if( ! SetEvent( hSyncEvent1 ) )
+ {
+ Trace( "ERROR:%lu:SetEvent() call failed\n", GetLastError() );
+ bThreadResult = FAIL;
+ }
+
+ /* return success or failure */
+ return bThreadResult;
+}
+
+
+int __cdecl main (int argc, char **argv)
+{
+ /* local variables */
+ HANDLE hThread = 0;
+ int ret;
+ BOOL bResult = FAIL;
+
+ /* initialize the PAL */
+ if (0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ InAPC = FALSE;
+
+ /* create a pair of synchronization events to coordinate our threads */
+ hSyncEvent1 = CreateEvent( NULL, FALSE, FALSE, NULL );
+ if( hSyncEvent1 == NULL )
+ {
+ Trace( "ERROR:%lu:CreateEvent() call failed\n", GetLastError() );
+ goto cleanup;
+ }
+
+ hSyncEvent2 = CreateEvent( NULL, FALSE, FALSE, NULL );
+ if( hSyncEvent2 == NULL )
+ {
+ Trace( "ERROR:%lu:CreateEvent() call failed\n", GetLastError() );
+ goto cleanup;
+ }
+
+ /* create a child thread */
+ hThread = CreateThread( NULL,
+ 0,
+ (LPTHREAD_START_ROUTINE)SleeperProc,
+ 0,
+ 0,
+ &ChildThread);
+
+ if (hThread == NULL)
+ {
+ Trace( "ERROR:%lu:CreateThread() call failed\n",
+ GetLastError());
+ goto cleanup;
+ }
+
+
+ /* wait on our synchronization event to ensure the thread is running */
+ ret = WaitForSingleObject( hSyncEvent1, 20000 );
+ if( ret != WAIT_OBJECT_0 )
+ {
+ Trace( "ERROR:WaitForSingleObject() returned %lu, "
+ "expected WAIT_OBJECT_0\n",
+ ret );
+ goto cleanup;
+ }
+
+ /* queue a user APC on the child thread */
+ ret = QueueUserAPC(APCFunc, hThread, 0);
+ if (ret == 0)
+ {
+ Trace( "ERROR:%lu:QueueUserAPC() call failed\n",
+ GetLastError());
+ goto cleanup;
+ }
+
+ /* signal the child thread to continue */
+ if( ! SetEvent( hSyncEvent2 ) )
+ {
+ Trace( "ERROR:%lu:SetEvent() call failed\n", GetLastError() );
+ goto cleanup;
+ }
+
+ /* wait on our synchronization event to ensure the other thread is done */
+ ret = WaitForSingleObject( hSyncEvent1, 20000 );
+ if( ret != WAIT_OBJECT_0 )
+ {
+ Trace( "ERROR:WaitForSingleObject() returned %lu, "
+ "expected WAIT_OBJECT_0\n",
+ ret );
+ goto cleanup;
+ }
+
+ /* check that the thread executed successfully */
+ if( bThreadResult == FAIL )
+ {
+ goto cleanup;
+ }
+
+
+ /* check whether the APC function was executed */
+ if( InAPC )
+ {
+ Trace( "FAIL:APC function was executed but shouldn't have been\n" );
+ goto cleanup;
+ }
+
+ /* success if we reach here */
+ bResult = PASS;
+
+
+cleanup:
+ /* wait for the other thread to finish */
+ if( hThread != NULL )
+ {
+ ret = WaitForSingleObject( hThread, INFINITE );
+ if (ret == WAIT_FAILED)
+ {
+ Trace( "ERROR:%lu:WaitForSingleObject() returned %lu, "
+ "expected WAIT_OBJECT_0\n",
+ ret );
+ bResult = FAIL;
+ }
+ }
+
+ /* close our synchronization handles */
+ if( hSyncEvent1 != NULL )
+ {
+ if( ! CloseHandle( hSyncEvent1 ) )
+ {
+ Trace( "ERROR:%lu:CloseHandle() call failed\n", GetLastError() );
+ bResult = FAIL;
+ }
+ }
+
+ if( hSyncEvent2 != NULL )
+ {
+ if( ! CloseHandle( hSyncEvent2 ) )
+ {
+ Trace( "ERROR:%lu:CloseHandle() call failed\n", GetLastError() );
+ bResult = FAIL;
+ }
+ }
+
+ if( bResult == FAIL )
+ {
+ Fail( "test failed\n" );
+ }
+
+
+ /* terminate the PAL */
+ PAL_Terminate();
+
+ /* return success */
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/threading/QueueUserAPC/test2/testinfo.dat b/src/pal/tests/palsuite/threading/QueueUserAPC/test2/testinfo.dat
new file mode 100644
index 0000000000..42d942df36
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/QueueUserAPC/test2/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = QueueUserAPC
+Name = Test #2 for QueueUserAPC
+TYPE = DEFAULT
+EXE1 = test2
+Description
+=Tests that APCs are not executed if a thread never enters an
+=alertable state after they are queued.
diff --git a/src/pal/tests/palsuite/threading/QueueUserAPC/test3/CMakeLists.txt b/src/pal/tests/palsuite/threading/QueueUserAPC/test3/CMakeLists.txt
new file mode 100644
index 0000000000..8475dcb03e
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/QueueUserAPC/test3/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test3.c
+)
+
+add_executable(paltest_queueuserapc_test3
+ ${SOURCES}
+)
+
+add_dependencies(paltest_queueuserapc_test3 coreclrpal)
+
+target_link_libraries(paltest_queueuserapc_test3
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/QueueUserAPC/test3/test3.c b/src/pal/tests/palsuite/threading/QueueUserAPC/test3/test3.c
new file mode 100644
index 0000000000..933f41a5b4
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/QueueUserAPC/test3/test3.c
@@ -0,0 +1,33 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test3.c
+**
+** Purpose: Tests how QueueUserAPC handles an invalid thread.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main (int argc, char **argv)
+{
+ int ret;
+
+ if (0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ ret = QueueUserAPC(NULL, NULL, 0);
+ if (ret != 0)
+ {
+ Fail("QueueUserAPC passed with an invalid thread!\n");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/threading/QueueUserAPC/test3/testinfo.dat b/src/pal/tests/palsuite/threading/QueueUserAPC/test3/testinfo.dat
new file mode 100644
index 0000000000..0b96349f15
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/QueueUserAPC/test3/testinfo.dat
@@ -0,0 +1,12 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = QueueUserAPC
+Name = Test #3 for QueueUserAPC
+TYPE = DEFAULT
+EXE1 = test3
+Description
+=Tests how QueueUserAPC handles an invalid thread.
diff --git a/src/pal/tests/palsuite/threading/QueueUserAPC/test4/CMakeLists.txt b/src/pal/tests/palsuite/threading/QueueUserAPC/test4/CMakeLists.txt
new file mode 100644
index 0000000000..2552738b50
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/QueueUserAPC/test4/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test4.c
+)
+
+add_executable(paltest_queueuserapc_test4
+ ${SOURCES}
+)
+
+add_dependencies(paltest_queueuserapc_test4 coreclrpal)
+
+target_link_libraries(paltest_queueuserapc_test4
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/QueueUserAPC/test4/test4.c b/src/pal/tests/palsuite/threading/QueueUserAPC/test4/test4.c
new file mode 100644
index 0000000000..c28709db81
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/QueueUserAPC/test4/test4.c
@@ -0,0 +1,72 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================================
+**
+** Source: test4.c
+**
+** Dependencies: PAL_Initialize
+** PAL_Terminate
+** GetCurrentThread
+** SleepEx
+**
+** Purpose:
+**
+** Test to ensure proper operation of the QueueUserAPC()
+** API by trying to queue APC functions on the current
+** thread.
+**
+**
+**===========================================================================*/
+#include <palsuite.h>
+
+
+static BOOL bAPCExecuted = FALSE;
+
+VOID PALAPI APCFunc( ULONG_PTR dwParam )
+{
+ bAPCExecuted = TRUE;
+}
+
+int __cdecl main( int argc, char **argv )
+
+{
+ /* local variables */
+ HANDLE hThread = NULL;
+ DWORD ret;
+
+ /* PAL initialization */
+ if( (PAL_Initialize(argc, argv)) != 0 )
+ {
+ return( FAIL );
+ }
+
+ /* get the current thread */
+ hThread = GetCurrentThread();
+ ret = QueueUserAPC( APCFunc, hThread, 0 );
+ if( ret == 0 )
+ {
+ Fail( "ERROR:%lu:QueueUserAPC call failed\n", GetLastError() );
+ }
+
+ /* call SleepEx() to put the thread in an alertable state */
+ ret = SleepEx( 2000, TRUE );
+ if( ret != WAIT_IO_COMPLETION )
+ {
+ Fail( "ERROR:Expected sleep to return WAIT_IO_COMPLETION, got %lu\n",
+ ret );
+ }
+
+ /* check that the APC function was executed */
+ if( bAPCExecuted == FALSE )
+ {
+ Fail( "ERROR:APC function was not executed\n" );
+ }
+
+ /* PAL termination */
+ PAL_Terminate();
+
+ /* return success */
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/threading/QueueUserAPC/test4/testinfo.dat b/src/pal/tests/palsuite/threading/QueueUserAPC/test4/testinfo.dat
new file mode 100644
index 0000000000..cd7b7c2f21
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/QueueUserAPC/test4/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = QueueUserAPC
+Name = Positive test for QueueUserAPC
+TYPE = DEFAULT
+EXE1 = test4
+Description
+= Test to ensure proper operation of the QueueUserAPC()
+= API by trying to queue APC functions on the current
+= thread.
diff --git a/src/pal/tests/palsuite/threading/QueueUserAPC/test5/CMakeLists.txt b/src/pal/tests/palsuite/threading/QueueUserAPC/test5/CMakeLists.txt
new file mode 100644
index 0000000000..c2fa10de12
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/QueueUserAPC/test5/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test5.c
+)
+
+add_executable(paltest_queueuserapc_test5
+ ${SOURCES}
+)
+
+add_dependencies(paltest_queueuserapc_test5 coreclrpal)
+
+target_link_libraries(paltest_queueuserapc_test5
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/QueueUserAPC/test5/test5.c b/src/pal/tests/palsuite/threading/QueueUserAPC/test5/test5.c
new file mode 100644
index 0000000000..3d26a55f59
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/QueueUserAPC/test5/test5.c
@@ -0,0 +1,200 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================================
+**
+** Source: test5.c
+**
+** Dependencies: PAL_Initialize
+** PAL_Terminate
+** CreateEvent
+** SetEvent
+** CreateThread
+** ResumeThread
+** WaitForSingleObject
+** CloseHandle
+**
+** Purpose:
+**
+** Test to ensure proper operation of the QueueUserAPC()
+** API by trying to queue and activate APC functions on
+** a thread that was created suspended, prior to resuming
+** it. We're verifying the following behavior:
+**
+** "If an application queues an APC before the thread begins
+** running, the thread begins by calling the APC function.
+** After the thread calls an APC function, it calls the APC
+** functions for all APCs in its APC queue."
+**
+**
+**===========================================================================*/
+#include <palsuite.h>
+
+
+static HANDLE hEvent = NULL;
+static BOOL bAPCExecuted = FALSE;
+
+VOID PALAPI APCFunc( ULONG_PTR dwParam )
+{
+ bAPCExecuted = TRUE;
+}
+
+/**
+ * ThreadFunc
+ *
+ * Dummy thread function for APC queuing.
+ */
+DWORD PALAPI ThreadFunc( LPVOID param )
+{
+ DWORD ret = 0;
+
+ /* alertable wait until the global event is signalled */
+ ret = WaitForSingleObject( hEvent, INFINITE );
+ if( ret != WAIT_OBJECT_0 )
+ {
+ Fail( "ERROR:WaitForSingleObject() returned %lu, "
+ "expected WAIT_OBJECT_0\n",
+ ret );
+ }
+
+ return 0;
+}
+
+
+int __cdecl main( int argc, char **argv )
+
+{
+ /* local variables */
+ HANDLE hThread = NULL;
+ DWORD IDThread;
+ DWORD ret;
+ BOOL bResult = FALSE;
+
+ /* PAL initialization */
+ if( (PAL_Initialize(argc, argv)) != 0 )
+ {
+ return( FAIL );
+ }
+
+ /* create an event for the other thread to wait on */
+ hEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
+ if( hEvent == NULL )
+ {
+ Fail( "ERROR:%lu:CreateEvent() call failed\n", GetLastError() );
+ }
+
+ /* run another dummy thread to cause notification of the library */
+ hThread = CreateThread( NULL, /* no security attributes */
+ 0, /* use default stack size */
+ (LPTHREAD_START_ROUTINE) ThreadFunc, /* thread function */
+ (LPVOID) NULL, /* pass thread index as */
+ /* function argument */
+ CREATE_SUSPENDED, /* create suspended */
+ &IDThread ); /* returns thread id */
+
+ /* Check the return value for success. */
+ if( hThread == NULL )
+ {
+ /* error creating thread */
+ Trace( "ERROR:%lu:CreateThread call failed\n", GetLastError() );
+ if( ! CloseHandle( hEvent ) )
+ {
+ Trace( "ERROR:%lu:CloseHandle() call failed\n", GetLastError() );
+ }
+ Fail( "test failed\n" );
+ }
+
+ /* queue our APC on the suspended thread */
+ ret = QueueUserAPC( APCFunc, hThread, 0 );
+ if( ret == 0 )
+ {
+ Fail( "ERROR:%lu:QueueUserAPC call failed\n", GetLastError() );
+ }
+
+ /* wait on the suspended thread */
+ ret = WaitForSingleObject( hThread, 2000 );
+ if( ret != WAIT_TIMEOUT )
+ {
+ Trace( "ERROR:WaitForSingleObject() returned %lu, "
+ "expected WAIT_TIMEOUT\n",
+ ret );
+ goto cleanup;
+ }
+
+ /* verify that the APC function was not executed */
+ if( bAPCExecuted == TRUE )
+ {
+ Trace( "ERROR:APC function was executed for a suspended thread\n" );
+ goto cleanup;
+ }
+
+ /* Resume the suspended thread */
+ ResumeThread( hThread );
+
+ /* do another wait on the resumed thread */
+ ret = WaitForSingleObject( hThread, 2000 );
+
+ /* verify that we got a WAIT_TIMEOUT result */
+ if( ret != WAIT_TIMEOUT )
+ {
+ Trace( "ERROR:WaitForSingleObject() returned %lu, "
+ "expected WAIT_TIMEOUT\n",
+ ret );
+ goto cleanup;
+ }
+
+ /* check that the APC function was actually executed */
+ if( bAPCExecuted == FALSE )
+ {
+ Trace( "ERROR:APC function was not executed\n" );
+ goto cleanup;
+ }
+
+ /* set the success flag */
+ bResult = PASS;
+
+cleanup:
+ /* signal the event so the other thread will exit */
+ if( ! SetEvent( hEvent ) )
+ {
+ Trace( "ERROR:%lu:SetEvent() call failed\n", GetLastError() );
+ bResult = FAIL;
+ }
+
+ /* close the global event handle */
+ if( ! CloseHandle( hEvent ) )
+ {
+ Trace( "ERROR:%lu:CloseHandle() call failed\n", GetLastError() );
+ bResult = FAIL;
+ }
+
+ /* wait on the other thread to complete */
+ ret = WaitForSingleObject( hThread, 2000 );
+ if( ret != WAIT_OBJECT_0 )
+ {
+ Trace( "ERROR:WaitForSingleObject() returned %lu, "
+ "expected WAIT_OBJECT_0\n",
+ ret );
+ bResult = FAIL;
+ }
+
+ /* close the thread handle */
+ if( ! CloseHandle( hThread ) )
+ {
+ Trace( "ERROR:%lu:CloseHandle() call failed\n", GetLastError() );
+ bResult = FAIL;
+ }
+
+ /* output final failure result for failure case */
+ if( bResult == FAIL )
+ {
+ Fail( "test failed\n" );
+ }
+
+ /* PAL termination */
+ PAL_Terminate();
+
+ /* return success */
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/threading/QueueUserAPC/test5/testinfo.dat b/src/pal/tests/palsuite/threading/QueueUserAPC/test5/testinfo.dat
new file mode 100644
index 0000000000..f1775aabe8
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/QueueUserAPC/test5/testinfo.dat
@@ -0,0 +1,20 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = QueueUserAPC
+Name = Positive test for QueueUserAPC
+TYPE = DEFAULT
+EXE1 = test5
+Description
+= Test to ensure proper operation of the QueueUserAPC()
+= API by trying to queue and activate APC functions on
+= a thread that was created suspended, prior to resuming
+= it. We're verifying the following behavior:
+=
+= "If an application queues an APC before the thread begins
+= running, the thread begins by calling the APC function.
+= After the thread calls an APC function, it calls the APC
+= functions for all APCs in its APC queue."
diff --git a/src/pal/tests/palsuite/threading/QueueUserAPC/test6/CMakeLists.txt b/src/pal/tests/palsuite/threading/QueueUserAPC/test6/CMakeLists.txt
new file mode 100644
index 0000000000..3fd1b1a08e
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/QueueUserAPC/test6/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test6.c
+)
+
+add_executable(paltest_queueuserapc_test6
+ ${SOURCES}
+)
+
+add_dependencies(paltest_queueuserapc_test6 coreclrpal)
+
+target_link_libraries(paltest_queueuserapc_test6
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/QueueUserAPC/test6/test6.c b/src/pal/tests/palsuite/threading/QueueUserAPC/test6/test6.c
new file mode 100644
index 0000000000..e2e2464726
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/QueueUserAPC/test6/test6.c
@@ -0,0 +1,129 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================================
+**
+** Source: test6.c
+**
+** Dependencies: PAL_Initialize
+** PAL_Terminate
+** CreateEvent
+** SetEvent
+** CreateThread
+** ResumeThread
+** WaitForMultipleObjectsEx
+** CloseHandle
+**
+** Purpose:
+**
+** Test to ensure proper operation of the QueueUserAPC()
+** API by trying to queue APC functions on a thread that
+** has already terminated.
+**
+**
+**===========================================================================*/
+#include <palsuite.h>
+
+
+static BOOL bAPCExecuted = FALSE;
+
+VOID PALAPI APCFunc( ULONG_PTR dwParam )
+{
+ bAPCExecuted = TRUE;
+}
+
+/**
+ * ThreadFunc
+ *
+ * Dummy thread function for APC queuing.
+ */
+DWORD PALAPI ThreadFunc( LPVOID param )
+{
+ int i;
+
+ /* simulate some activity */
+ for( i=0; i<250000; i++ )
+ ;
+
+ return 0;
+}
+
+
+int __cdecl main( int argc, char **argv )
+
+{
+ /* local variables */
+ HANDLE hThread = NULL;
+ DWORD IDThread;
+ DWORD ret;
+
+ /* PAL initialization */
+ if( (PAL_Initialize(argc, argv)) != 0 )
+ {
+ return( FAIL );
+ }
+
+ /* run another dummy thread to cause notification of the library */
+ hThread = CreateThread( NULL, /* no security attributes */
+ 0, /* use default stack size */
+ (LPTHREAD_START_ROUTINE) ThreadFunc, /* thread function */
+ (LPVOID) NULL, /* pass thread index as */
+ /* function argument */
+ CREATE_SUSPENDED, /* create suspended */
+ &IDThread ); /* returns thread id */
+
+ /* Check the return value for success. */
+ if( hThread == NULL )
+ {
+ /* error creating thread */
+ Fail( "ERROR:%lu:CreateThread call failed\n", GetLastError() );
+ }
+
+ /* Resume the suspended thread */
+ ResumeThread( hThread );
+
+ /* wait on the other thread to complete */
+ ret = WaitForSingleObject( hThread, INFINITE );
+ if( ret != WAIT_OBJECT_0 )
+ {
+ Trace( "ERROR:WaitForSingleObject() returned %lu, "
+ "expected WAIT_OBJECT_0\n",
+ ret );
+ if( ! CloseHandle( hThread ) )
+ {
+ Trace( "ERROR:%lu:CloseHandle() call failed\n", GetLastError() );
+ }
+ Fail( "test failed\n" );
+ }
+
+ /* queue our APC on the finished thread */
+ ret = QueueUserAPC( APCFunc, hThread, 0 );
+ if( ret != 0 )
+ {
+ Trace( "ERROR:QueueUserAPC call succeeded on a terminated thread\n" );
+ if( ! CloseHandle( hThread ) )
+ {
+ Trace( "ERROR:%lu:CloseHandle() call failed\n", GetLastError() );
+ }
+ Fail( "test failed\n" );
+ }
+
+ if( ! CloseHandle( hThread ) )
+ {
+ Fail( "ERROR:%lu:CloseHandle() call failed\n", GetLastError() );
+ }
+
+ /* dummy check that the APC function wasn't actually executed */
+ if( bAPCExecuted != FALSE )
+ {
+ Fail( "ERROR:APC function was executed\n" );
+ }
+
+
+ /* PAL termination */
+ PAL_Terminate();
+
+ /* return success */
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/threading/QueueUserAPC/test6/testinfo.dat b/src/pal/tests/palsuite/threading/QueueUserAPC/test6/testinfo.dat
new file mode 100644
index 0000000000..4d806184ee
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/QueueUserAPC/test6/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = QueueUserAPC
+Name = Negative test for QueueUserAPC
+TYPE = DEFAULT
+EXE1 = test6
+Description
+= Test to ensure proper operation of the QueueUserAPC()
+= API by trying to queue APC functions on a thread that
+= has already terminated.
diff --git a/src/pal/tests/palsuite/threading/QueueUserAPC/test7/CMakeLists.txt b/src/pal/tests/palsuite/threading/QueueUserAPC/test7/CMakeLists.txt
new file mode 100644
index 0000000000..751f3894f4
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/QueueUserAPC/test7/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test7.c
+)
+
+add_executable(paltest_queueuserapc_test7
+ ${SOURCES}
+)
+
+add_dependencies(paltest_queueuserapc_test7 coreclrpal)
+
+target_link_libraries(paltest_queueuserapc_test7
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/QueueUserAPC/test7/test7.c b/src/pal/tests/palsuite/threading/QueueUserAPC/test7/test7.c
new file mode 100644
index 0000000000..54a63982fe
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/QueueUserAPC/test7/test7.c
@@ -0,0 +1,253 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================================
+**
+** Source: test7.c
+**
+** Dependencies: PAL_Initialize
+** PAL_Terminate
+** CreateEvent
+** SetEvent
+** CreateThread
+** ResumeThread
+** WaitForMultipleObjectsEx
+** CloseHandle
+**
+** Purpose:
+**
+** Test to ensure proper operation of the QueueUserAPC()
+** API by trying to queue an APC function on a thread and
+** activating it with WaitForMultipleObjectsEx.
+**
+**
+**===========================================================================*/
+#include <palsuite.h>
+
+
+static HANDLE hSyncEvent = NULL;
+static HANDLE hTestEvent = NULL;
+static int nAPCExecuted = 0;
+static BOOL bThreadResult = FALSE;
+
+VOID PALAPI APCFunc( ULONG_PTR dwParam )
+{
+ ++nAPCExecuted;
+}
+
+/**
+ * ThreadFunc
+ *
+ * Dummy thread function for APC queuing.
+ */
+DWORD PALAPI ThreadFunc( LPVOID param )
+{
+ DWORD ret = 0;
+
+ /* pessimism */
+ bThreadResult = FALSE;
+
+ /* set the sync event to notify the main thread */
+ if( ! SetEvent( hSyncEvent ) )
+ {
+ Trace( "ERROR:%lu:SetEvent() call failed\n", GetLastError() );
+ goto done;
+ }
+
+ /* wait until the test event is signalled */
+ ret = WaitForSingleObject( hTestEvent, INFINITE );
+ if( ret != WAIT_OBJECT_0 )
+ {
+ Trace( "ERROR:WaitForSingleObject() returned %lu, "
+ "expected WAIT_OBJECT_0\n",
+ ret );
+ goto done;
+ }
+
+ /* now do an alertable wait on the same event, which is now
+ in an unsignalled state */
+ ret = WaitForMultipleObjectsEx( 1, &hTestEvent, TRUE, 2000, TRUE );
+
+ /* verify that we got a WAIT_IO_COMPLETION result */
+ if( ret != WAIT_IO_COMPLETION )
+ {
+ Trace( "ERROR:WaitForMultipleObjectsEx returned %lu, "
+ "expected WAIT_IO_COMPLETION\n",
+ ret );
+ goto done;
+ }
+
+ /* set the event again */
+ if( ! SetEvent( hTestEvent ) )
+ {
+ Trace( "ERROR:%lu:SetEvent() call failed\n", GetLastError() );
+ goto done;
+ }
+
+ /* do a non-alertable wait on the same event */
+ ret = WaitForMultipleObjectsEx( 1, &hTestEvent, TRUE, INFINITE, FALSE );
+
+ /* verify that we got a WAIT_OBJECT_0 result */
+ if( ret != WAIT_OBJECT_0 )
+ {
+ Trace( "ERROR:WaitForMultipleObjectsEx returned %lu, "
+ "expected WAIT_OBJECT_0\n",
+ ret );
+ goto done;
+ }
+
+ /* success at this point */
+ bThreadResult = TRUE;
+
+
+done:
+ return bThreadResult;
+}
+
+
+int __cdecl main( int argc, char **argv )
+
+{
+ /* local variables */
+ HANDLE hThread = NULL;
+ DWORD IDThread;
+ DWORD ret;
+ BOOL bResult = FALSE;
+
+ /* PAL initialization */
+ if( (PAL_Initialize(argc, argv)) != 0 )
+ {
+ return( FAIL );
+ }
+
+ /* create an auto-reset event for the other thread to wait on */
+ hTestEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
+ if( hTestEvent == NULL )
+ {
+ Fail( "ERROR:%lu:CreateEvent() call failed\n", GetLastError() );
+ }
+
+ /* create an auto-reset event for synchronization */
+ hSyncEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
+ if( hSyncEvent == NULL )
+ {
+ Trace( "ERROR:%lu:CreateEvent() call failed\n", GetLastError() );
+ if( ! CloseHandle( hTestEvent ) )
+ {
+ Trace( "ERROR:%lu:CreateEvent() call failed\n", GetLastError() );
+ }
+ Fail( "test failed\n" );
+ }
+
+ /* run another dummy thread to cause notification of the library */
+ hThread = CreateThread( NULL, /* no security attributes */
+ 0, /* use default stack size */
+ (LPTHREAD_START_ROUTINE) ThreadFunc, /* thread function */
+ (LPVOID) NULL, /* pass thread index as */
+ /* function argument */
+ CREATE_SUSPENDED, /* create suspended */
+ &IDThread ); /* returns thread id */
+
+ /* Check the return value for success. */
+ if( hThread == NULL )
+ {
+ /* error creating thread */
+ Trace( "ERROR:%lu:CreateThread call failed\n", GetLastError() );
+ if( ! CloseHandle( hTestEvent ) )
+ {
+ Trace( "ERROR:%lu:CloseHandle() call failed\n", GetLastError() );
+ }
+ Fail( "test failed\n" );
+ }
+
+ /* Resume the suspended thread */
+ ResumeThread( hThread );
+
+ /* wait until the other thread is ready to proceed */
+ ret = WaitForSingleObject( hSyncEvent, 10000 );
+ if( ret != WAIT_OBJECT_0 )
+ {
+ Trace( "ERROR:WaitForSingleObject returned %lu, "
+ "expected WAIT_OBJECT_0\n",
+ ret );
+ goto cleanup;
+ }
+
+
+ /* now queue our APC on the test thread */
+ ret = QueueUserAPC( APCFunc, hThread, 0 );
+ if( ret == 0 )
+ {
+ Trace( "ERROR:%lu:QueueUserAPC call failed\n", GetLastError() );
+ goto cleanup;
+ }
+
+ /* signal the test event so the other thread will proceed */
+ if( ! SetEvent( hTestEvent ) )
+ {
+ Trace( "ERROR:%lu:SetEvent() call failed\n", GetLastError() );
+ goto cleanup;
+ }
+
+ /* wait on the other thread to complete */
+ ret = WaitForSingleObject( hThread, INFINITE );
+ if( ret != WAIT_OBJECT_0 )
+ {
+ Trace( "ERROR:WaitForSingleObject() returned %lu, "
+ "expected WAIT_OBJECT_0\n",
+ ret );
+ goto cleanup;
+ }
+
+ /* check the result of the other thread */
+ if( bThreadResult == FALSE )
+ {
+ goto cleanup;
+ }
+
+ /* check that the APC function was actually executed exactly one time */
+ if( nAPCExecuted != 1 )
+ {
+ Trace( "ERROR:APC function was executed %d times, "
+ "expected once\n", nAPCExecuted );
+ goto cleanup;
+ }
+
+ /* set the success flag */
+ bResult = PASS;
+
+
+cleanup:
+ /* close the global event handles */
+ if( ! CloseHandle( hTestEvent ) )
+ {
+ Trace( "ERROR:%lu:CloseHandle() call failed\n", GetLastError() );
+ bResult = FAIL;
+ }
+
+ if( ! CloseHandle( hSyncEvent ) )
+ {
+ Trace( "ERROR:%lu:CloseHandle() call failed\n", GetLastError() );
+ bResult = FAIL;
+ }
+
+ /* close the thread handle */
+ if( ! CloseHandle( hThread ) )
+ {
+ Trace( "ERROR:%lu:CloseHandle() call failed\n", GetLastError() );
+ bResult = FAIL;
+ }
+
+ /* output final failure result for failure case */
+ if( bResult == FAIL )
+ {
+ Fail( "test failed\n" );
+ }
+
+ /* PAL termination */
+ PAL_Terminate();
+
+ /* return success */
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/threading/QueueUserAPC/test7/testinfo.dat b/src/pal/tests/palsuite/threading/QueueUserAPC/test7/testinfo.dat
new file mode 100644
index 0000000000..d92d9496d7
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/QueueUserAPC/test7/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = QueueUserAPC
+Name = Positive test for QueueUserAPC
+TYPE = DEFAULT
+EXE1 = test7
+Description
+= Test to ensure proper operation of the QueueUserAPC()
+= API by trying to queue an APC function on a thread and
+= activating it with WaitForMultipleObjectsEx.
diff --git a/src/pal/tests/palsuite/threading/ReleaseMutex/CMakeLists.txt b/src/pal/tests/palsuite/threading/ReleaseMutex/CMakeLists.txt
new file mode 100644
index 0000000000..f9524196e0
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/ReleaseMutex/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test3)
+
diff --git a/src/pal/tests/palsuite/threading/ReleaseMutex/test3/CMakeLists.txt b/src/pal/tests/palsuite/threading/ReleaseMutex/test3/CMakeLists.txt
new file mode 100644
index 0000000000..8e64c28242
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/ReleaseMutex/test3/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ ReleaseMutex.c
+)
+
+add_executable(paltest_releasemutex_test3
+ ${SOURCES}
+)
+
+add_dependencies(paltest_releasemutex_test3 coreclrpal)
+
+target_link_libraries(paltest_releasemutex_test3
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/ReleaseMutex/test3/ReleaseMutex.c b/src/pal/tests/palsuite/threading/ReleaseMutex/test3/ReleaseMutex.c
new file mode 100644
index 0000000000..5f6adb0419
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/ReleaseMutex/test3/ReleaseMutex.c
@@ -0,0 +1,103 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: ReleaseMutex/test3/ReleaseMutex.c
+**
+** Purpose: Test failure code for ReleaseMutex.
+**
+** Dependencies: CreateMutex
+** ReleaseMutex
+** CreateThread
+**
+
+**
+**=========================================================*/
+
+#include <palsuite.h>
+
+DWORD dwTestResult; /* global for test result */
+
+DWORD dwThreadId; /* consumer thread identifier */
+
+HANDLE hMutex; /* handle to mutex */
+
+HANDLE hThread; /* handle to thread */
+
+/*
+ * Thread function.
+ */
+DWORD
+PALAPI
+ThreadFunction( LPVOID lpNoArg )
+{
+
+ dwTestResult = ReleaseMutex(hMutex);
+
+ return 0;
+}
+
+int __cdecl main (int argc, char **argv)
+{
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return (FAIL);
+ }
+
+ /*
+ * set dwTestResult so test fails even if ReleaseMutex is not called
+ */
+ dwTestResult = 1;
+
+ /*
+ * Create mutex
+ */
+ hMutex = CreateMutexW (
+ NULL,
+ TRUE,
+ NULL);
+
+ if ( NULL == hMutex )
+ {
+ Fail ( "hMutex = CreateMutex () - returned NULL\n"
+ "Failing Test.\nGetLastError returned %d\n", GetLastError());
+ }
+
+ /*
+ * Create ThreadFunction
+ */
+ hThread = CreateThread(
+ NULL,
+ 0,
+ ThreadFunction,
+ NULL,
+ 0,
+ &dwThreadId);
+
+ if ( NULL == hThread )
+ {
+
+ Fail ( "CreateThread() returned NULL. Failing test.\n"
+ "GetLastError returned %d\n", GetLastError());
+ }
+
+ /*
+ * Wait for ThreadFunction to complete
+ */
+ WaitForSingleObject (hThread, INFINITE);
+
+ if (dwTestResult)
+ {
+ Fail ("ReleaseMutex() test was expected to return 0.\n"
+ "It returned %d. Failing test.\n", dwTestResult );
+ }
+
+ Trace ("ReleaseMutex() test returned 0.\nTest passed.\n");
+
+ PAL_Terminate();
+ return ( PASS );
+
+}
diff --git a/src/pal/tests/palsuite/threading/ReleaseMutex/test3/testinfo.dat b/src/pal/tests/palsuite/threading/ReleaseMutex/test3/testinfo.dat
new file mode 100644
index 0000000000..3f06757eb6
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/ReleaseMutex/test3/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = ReleaseMutex
+Name = Positive Test for ReleaseMutex
+TYPE = DEFAULT
+EXE1 = releasemutex
+Description
+= Calls ReleaseMutex from a thread which should not have ownership of the
+= mutex. If ReleaseMutex fails correctly this test will succeed.
diff --git a/src/pal/tests/palsuite/threading/ResetEvent/CMakeLists.txt b/src/pal/tests/palsuite/threading/ResetEvent/CMakeLists.txt
new file mode 100644
index 0000000000..a3847f8ca9
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/ResetEvent/CMakeLists.txt
@@ -0,0 +1,7 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+add_subdirectory(test3)
+add_subdirectory(test4)
+
diff --git a/src/pal/tests/palsuite/threading/ResetEvent/test1/CMakeLists.txt b/src/pal/tests/palsuite/threading/ResetEvent/test1/CMakeLists.txt
new file mode 100644
index 0000000000..78e84da2b9
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/ResetEvent/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_resetevent_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_resetevent_test1 coreclrpal)
+
+target_link_libraries(paltest_resetevent_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/ResetEvent/test1/test1.c b/src/pal/tests/palsuite/threading/ResetEvent/test1/test1.c
new file mode 100644
index 0000000000..20a0d5dffa
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/ResetEvent/test1/test1.c
@@ -0,0 +1,99 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: test1.c
+**
+** Purpose: Test for ResetEvent. Create an event with an intial
+** state signaled. Then reset that signal, and check to see that
+** the event is now not signaled.
+**
+**
+**=========================================================*/
+
+#include <palsuite.h>
+
+BOOL ResetEventTest()
+{
+ BOOL bRet = FALSE;
+ DWORD dwRet = 0;
+
+ LPSECURITY_ATTRIBUTES lpEventAttributes = 0;
+ BOOL bManualReset = TRUE;
+ BOOL bInitialState = TRUE;
+
+ /* Create an Event, ensure it is valid */
+ HANDLE hEvent = CreateEvent( lpEventAttributes,
+ bManualReset, bInitialState, NULL);
+
+ if (hEvent != INVALID_HANDLE_VALUE)
+ {
+ /* Check that WaitFor returns WAIT_OBJECT_0, indicating that
+ the event is signaled.
+ */
+
+ dwRet = WaitForSingleObject(hEvent,0);
+
+ if (dwRet != WAIT_OBJECT_0)
+ {
+ Fail("ResetEventTest:WaitForSingleObject failed (%x)\n", GetLastError());
+ }
+ else
+ {
+ /* Call ResetEvent, which will reset the signal */
+ bRet = ResetEvent(hEvent);
+
+ if (!bRet)
+ {
+ Fail("ResetEventTest:ResetEvent failed (%x)\n", GetLastError());
+ }
+ else
+ {
+ /* Call WaitFor again, and since it has been reset,
+ the return value should now be WAIT_TIMEOUT
+ */
+ dwRet = WaitForSingleObject(hEvent,0);
+
+ if (dwRet != WAIT_TIMEOUT)
+ {
+ Fail("ResetEventTest:WaitForSingleObject %s failed (%x)\n", GetLastError());
+ }
+ else
+ {
+ bRet = CloseHandle(hEvent);
+
+ if (!bRet)
+ {
+ Fail("ResetEventTest:CloseHandle failed (%x)\n", GetLastError());
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ Fail("ResetEventTest:CreateEvent failed (%x)\n", GetLastError());
+ }
+
+ return bRet;
+}
+
+int __cdecl main(int argc, char **argv)
+{
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return ( FAIL );
+ }
+
+ if(!ResetEventTest())
+ {
+ Fail ("Test failed\n");
+ }
+
+ PAL_Terminate();
+ return ( PASS );
+
+}
diff --git a/src/pal/tests/palsuite/threading/ResetEvent/test1/testinfo.dat b/src/pal/tests/palsuite/threading/ResetEvent/test1/testinfo.dat
new file mode 100644
index 0000000000..ed27f13dba
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/ResetEvent/test1/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = ResetEvent
+Name = Positive Test for ResetEvent
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Test for ResetEvent. Create an event with an intial
+= state signaled. Then reset that signal, and check to see that
+= the event is now not signaled.
diff --git a/src/pal/tests/palsuite/threading/ResetEvent/test2/CMakeLists.txt b/src/pal/tests/palsuite/threading/ResetEvent/test2/CMakeLists.txt
new file mode 100644
index 0000000000..ad0fe9b4a1
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/ResetEvent/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test2.c
+)
+
+add_executable(paltest_resetevent_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_resetevent_test2 coreclrpal)
+
+target_link_libraries(paltest_resetevent_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/ResetEvent/test2/test2.c b/src/pal/tests/palsuite/threading/ResetEvent/test2/test2.c
new file mode 100644
index 0000000000..8117f44353
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/ResetEvent/test2/test2.c
@@ -0,0 +1,89 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================================
+**
+** Source: test2.c
+**
+** Dependencies: PAL_Initialize
+** PAL_Terminate
+** CreateEvent
+** CloseHandle
+** WaitForSingleObject
+**
+** Purpose: Test to ensure proper operation of the ResetEvent()
+** API by calling it on an event handle that's already
+** unsignalled.
+**
+
+**
+**===========================================================================*/
+#include <palsuite.h>
+
+
+
+int __cdecl main( int argc, char **argv )
+
+{
+ /* local variables */
+ DWORD dwRet = 0;
+ HANDLE hEvent = NULL;
+ LPSECURITY_ATTRIBUTES lpEventAttributes = NULL;
+ BOOL bManualReset = TRUE;
+ BOOL bInitialState = FALSE;
+
+
+ /* PAL initialization */
+ if( (PAL_Initialize(argc, argv)) != 0 )
+ {
+ return( FAIL );
+ }
+
+
+ /* create an unsignalled event which we can use with ResetEvent */
+ hEvent = CreateEvent( lpEventAttributes,
+ bManualReset,
+ bInitialState,
+ NULL );
+
+ if( hEvent == INVALID_HANDLE_VALUE )
+ {
+ /* ERROR */
+ Fail( "ERROR:%lu:CreateEvent() call failed\n", GetLastError() );
+ }
+
+ /* verify that the event isn't signalled yet */
+ dwRet = WaitForSingleObject( hEvent, 0 );
+ if( dwRet != WAIT_TIMEOUT )
+ {
+ /* ERROR */
+ Trace( "ERROR:WaitForSingleObject() call returned %lu, "
+ "expected WAIT_TIMEOUT\n",
+ dwRet );
+ CloseHandle( hEvent );
+ Fail( "Test failed\n" );
+ }
+
+ /* try to reset the event */
+ if( ! ResetEvent( hEvent ) )
+ {
+ /* ERROR */
+ Trace( "FAIL:%lu:ResetEvent() call failed\n", GetLastError() );
+ CloseHandle( hEvent );
+ Fail( "Test failed\n" );
+ }
+
+ /* close the event handle */
+ if( ! CloseHandle( hEvent ) )
+ {
+ Fail( "ERROR:%lu:CloseHandle() call failed\n", GetLastError() );
+ }
+
+
+ /* PAL termination */
+ PAL_Terminate();
+
+ /* return success */
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/threading/ResetEvent/test2/testinfo.dat b/src/pal/tests/palsuite/threading/ResetEvent/test2/testinfo.dat
new file mode 100644
index 0000000000..4af1769cd4
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/ResetEvent/test2/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = ResetEvent
+Name = Positive test for ResetEvent
+TYPE = DEFAULT
+EXE1 = test2
+Description
+= Test to ensure proper operation of the ResetEvent()
+= API by calling it on an event handle that's already
+= unsignalled.
diff --git a/src/pal/tests/palsuite/threading/ResetEvent/test3/CMakeLists.txt b/src/pal/tests/palsuite/threading/ResetEvent/test3/CMakeLists.txt
new file mode 100644
index 0000000000..3c4ea1f249
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/ResetEvent/test3/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test3.c
+)
+
+add_executable(paltest_resetevent_test3
+ ${SOURCES}
+)
+
+add_dependencies(paltest_resetevent_test3 coreclrpal)
+
+target_link_libraries(paltest_resetevent_test3
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/ResetEvent/test3/test3.c b/src/pal/tests/palsuite/threading/ResetEvent/test3/test3.c
new file mode 100644
index 0000000000..9bc068ea72
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/ResetEvent/test3/test3.c
@@ -0,0 +1,86 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================================
+**
+** Source: test3.c
+**
+** Dependencies: PAL_Initialize
+** PAL_Terminate
+** CreateEvent
+** CloseHandle
+**
+** Purpose:
+**
+** Test to ensure proper operation of the ResetEvent()
+** API by calling it on an event handle that's been
+** closed. We expect it to return an appropriate error
+** result.
+**
+**
+
+**
+**===========================================================================*/
+#include <palsuite.h>
+
+
+
+int __cdecl main( int argc, char **argv )
+
+{
+ /* local variables */
+ HANDLE hEvent = NULL;
+ LPSECURITY_ATTRIBUTES lpEventAttributes = NULL;
+ BOOL bManualReset = TRUE;
+ BOOL bInitialState = FALSE;
+
+
+ /* PAL initialization */
+ if( (PAL_Initialize(argc, argv)) != 0 )
+ {
+ return( FAIL );
+ }
+
+
+ /* create an event which we can use with ResetEvent */
+ hEvent = CreateEvent( lpEventAttributes,
+ bManualReset,
+ bInitialState,
+ NULL );
+
+ if( hEvent == INVALID_HANDLE_VALUE )
+ {
+ /* ERROR */
+ Fail( "ERROR:%lu:CreateEvent() call failed\n", GetLastError() );
+ }
+
+ /* close the event handle */
+ if( ! CloseHandle( hEvent ) )
+ {
+ Fail( "ERROR:%lu:CloseHandle() call failed\n", GetLastError() );
+ }
+
+ /* try to reset the event */
+ if( ResetEvent( hEvent ) )
+ {
+ /* ERROR */
+ Fail( "FAIL:ResetEvent() call succeeded on a closed event handle\n" );
+ }
+
+ /* verify the result of GetLastError() */
+ if( GetLastError() != ERROR_INVALID_HANDLE )
+ {
+ /* ERROR */
+ Fail( "FAIL:ResetEvent() call failed on a closed event handle "
+ "but returned an unexpected error result %lu\n" );
+ }
+
+
+
+ /* PAL termination */
+ PAL_Terminate();
+
+ /* return success */
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/threading/ResetEvent/test3/testinfo.dat b/src/pal/tests/palsuite/threading/ResetEvent/test3/testinfo.dat
new file mode 100644
index 0000000000..4abeeded00
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/ResetEvent/test3/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = ResetEvent
+Name = Negative test for ResetEvent
+TYPE = DEFAULT
+EXE1 = test3
+Description
+= Test to ensure proper operation of the ResetEvent()
+= API by calling it on an event handle that's been
+= closed. We expect it to return an appropriate error
+= result.
diff --git a/src/pal/tests/palsuite/threading/ResetEvent/test4/CMakeLists.txt b/src/pal/tests/palsuite/threading/ResetEvent/test4/CMakeLists.txt
new file mode 100644
index 0000000000..68ee20bc95
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/ResetEvent/test4/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test4.c
+)
+
+add_executable(paltest_resetevent_test4
+ ${SOURCES}
+)
+
+add_dependencies(paltest_resetevent_test4 coreclrpal)
+
+target_link_libraries(paltest_resetevent_test4
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/ResetEvent/test4/test4.c b/src/pal/tests/palsuite/threading/ResetEvent/test4/test4.c
new file mode 100644
index 0000000000..0cc68fd9aa
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/ResetEvent/test4/test4.c
@@ -0,0 +1,161 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================================
+**
+** Source: test4.c
+**
+** Dependencies: PAL_Initialize
+** PAL_Terminate
+** CreateEvent
+** CloseHandle
+** WaitForSingleObject
+** DuplicateHandle
+** GetCurrentProcess
+**
+** Purpose:
+**
+** Test to ensure proper operation of the ResetEvent()
+** API by calling it on an event handle that's the
+** result of a DuplicateHandle() call on another event
+** handle.
+**
+
+**
+**===========================================================================*/
+#include <palsuite.h>
+
+
+
+int __cdecl main( int argc, char **argv )
+
+{
+ /* local variables */
+ DWORD dwRet = 0;
+ HANDLE hEvent = NULL;
+ HANDLE hDupEvent = NULL;
+ LPSECURITY_ATTRIBUTES lpEventAttributes = NULL;
+ BOOL bManualReset = TRUE;
+ BOOL bInitialState = TRUE;
+
+
+ /* PAL initialization */
+ if( (PAL_Initialize(argc, argv)) != 0 )
+ {
+ return( FAIL );
+ }
+
+
+ /* create an event which we can use with ResetEvent */
+ hEvent = CreateEvent( lpEventAttributes,
+ bManualReset,
+ bInitialState,
+ NULL );
+
+ if( hEvent == INVALID_HANDLE_VALUE )
+ {
+ /* ERROR */
+ Fail( "ERROR:%lu:CreateEvent() call failed\n", GetLastError() );
+ }
+
+ /* verify that the event is signalled already */
+ dwRet = WaitForSingleObject( hEvent, 0 );
+ if( dwRet != WAIT_OBJECT_0 )
+ {
+ /* ERROR */
+ Trace( "ERROR:WaitForSingleObject() call returned %lu, "
+ "expected WAIT_OBJECT_0\n",
+ dwRet );
+ CloseHandle( hEvent );
+ Fail( "Test failed\n" );
+ }
+
+
+ /* duplicate the event handle */
+ if( ! (DuplicateHandle(
+ GetCurrentProcess(),
+ hEvent,
+ GetCurrentProcess(),
+ &hDupEvent,
+ GENERIC_READ|GENERIC_WRITE, /* ignored in PAL */
+ FALSE,
+ DUPLICATE_SAME_ACCESS ) ) )
+ {
+ Trace("ERROR:%u:DuplicateHandle() call failed\n",
+ GetLastError() );
+ CloseHandle( hEvent );
+ Fail("Test failed\n");
+ }
+
+ /* verify that the event is signalled with the duplicate handle */
+ dwRet = WaitForSingleObject( hDupEvent, 0 );
+ if( dwRet != WAIT_OBJECT_0 )
+ {
+ /* ERROR */
+ Trace( "ERROR:WaitForSingleObject() call returned %lu, "
+ "expected WAIT_OBJECT_0\n",
+ dwRet );
+ CloseHandle( hEvent );
+ CloseHandle( hDupEvent );
+ Fail( "Test failed\n" );
+ }
+
+
+ /* reset the event using the duplicate handle */
+ if( ! ResetEvent( hDupEvent ) )
+ {
+ /* ERROR */
+ Trace( "ERROR:%lu:ResetEvent() call failed\n", GetLastError() );
+ CloseHandle( hEvent );
+ CloseHandle( hDupEvent );
+ Fail( "Test failed\n" );
+ }
+
+ /* verify that the event isn't signalled using the duplicate handle*/
+ dwRet = WaitForSingleObject( hDupEvent, 0 );
+ if( dwRet != WAIT_TIMEOUT )
+ {
+ /* ERROR */
+ Trace( "ERROR:WaitForSingleObject() call returned %lu, "
+ "expected WAIT_TIMEOUT\n",
+ dwRet );
+ CloseHandle( hEvent );
+ Fail( "Test failed\n" );
+ }
+
+ /* check that the event isn't signalled using the original event handle */
+ dwRet = WaitForSingleObject( hEvent, 0 );
+ if( dwRet != WAIT_TIMEOUT )
+ {
+ /* ERROR */
+ Trace( "ERROR:WaitForSingleObject() call returned %lu, "
+ "expected WAIT_TIMEOUT\n",
+ dwRet );
+ CloseHandle( hEvent );
+ Fail( "Test failed\n" );
+ }
+
+
+ /* close the duplicate event handle */
+ if( ! CloseHandle( hDupEvent ) )
+ {
+ Fail( "ERROR:%lu:CloseHandle() call failed for duplicate handle\n",
+ GetLastError() );
+ }
+
+
+ /* close the event handle */
+ if( ! CloseHandle( hEvent ) )
+ {
+ Fail( "ERROR:%lu:CloseHandle() call failed for original handle\n",
+ GetLastError() );
+ }
+
+
+ /* PAL termination */
+ PAL_Terminate();
+
+ /* return success */
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/threading/ResetEvent/test4/testinfo.dat b/src/pal/tests/palsuite/threading/ResetEvent/test4/testinfo.dat
new file mode 100644
index 0000000000..0223246c6f
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/ResetEvent/test4/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = ResetEvent
+Name = Positive test for ResetEvent
+TYPE = DEFAULT
+EXE1 = test4
+Description
+= Test to ensure proper operation of the ResetEvent()
+= API by calling it on an event handle that's the
+= result of a DuplicateHandle() call on another event
+= handle.
diff --git a/src/pal/tests/palsuite/threading/ResumeThread/CMakeLists.txt b/src/pal/tests/palsuite/threading/ResumeThread/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/ResumeThread/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/threading/ResumeThread/test1/CMakeLists.txt b/src/pal/tests/palsuite/threading/ResumeThread/test1/CMakeLists.txt
new file mode 100644
index 0000000000..2c83dfd3d5
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/ResumeThread/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_resumethread_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_resumethread_test1 coreclrpal)
+
+target_link_libraries(paltest_resumethread_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/ResumeThread/test1/test1.c b/src/pal/tests/palsuite/threading/ResumeThread/test1/test1.c
new file mode 100644
index 0000000000..037f79f7a3
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/ResumeThread/test1/test1.c
@@ -0,0 +1,141 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: test1.c
+**
+** Purpose: Test for ResumeThread. Create a suspended Thread.
+** First, ensure that it is indeed suspended. Then call resumethread
+** and check to ensure that the function has now run.
+**
+**
+**=========================================================*/
+
+#include <palsuite.h>
+
+DWORD dwResumeThreadTestParameter = 0;
+
+DWORD PALAPI ResumeThreadTestThread( LPVOID lpParameter)
+{
+ DWORD dwRet = 0;
+
+ /* Save parameter so we can check and ensure this function ran
+ properly.
+ */
+
+ dwResumeThreadTestParameter = (DWORD)lpParameter;
+
+ return dwRet;
+}
+
+BOOL ResumeThreadTest()
+{
+ BOOL bRet = FALSE;
+ DWORD dwRet = 0;
+
+ LPSECURITY_ATTRIBUTES lpThreadAttributes = NULL;
+ DWORD dwStackSize = 0;
+ LPTHREAD_START_ROUTINE lpStartAddress = &ResumeThreadTestThread;
+ LPVOID lpParameter = lpStartAddress;
+ DWORD dwCreationFlags = CREATE_SUSPENDED;
+ DWORD dwThreadId = 0;
+
+ HANDLE hThread = 0;
+
+ dwResumeThreadTestParameter = 0;
+
+ /* Create a thread, with CREATE_SUSPENDED, so we can resume it! */
+
+ hThread = CreateThread( lpThreadAttributes,
+ dwStackSize, lpStartAddress, lpParameter,
+ dwCreationFlags, &dwThreadId );
+
+ if (hThread != INVALID_HANDLE_VALUE)
+ {
+ /* Wait for one second. This should return WAIT_TIMEOUT */
+ dwRet = WaitForSingleObject(hThread,1000);
+
+ if (dwRet != WAIT_TIMEOUT)
+ {
+ Trace("ResumeThreadTest:WaitForSingleObject "
+ "failed (%x)\n",GetLastError());
+ }
+ else
+ {
+ /* Check to ensure the parameter hasn't changed. The
+ function shouldn't have occurred yet.
+ */
+ if (dwResumeThreadTestParameter != 0)
+ {
+ Trace("ResumeThreadTest:parameter error\n");
+ }
+ else
+ {
+ /* Call ResumeThread and ensure the return value is
+ correct.
+ */
+
+ dwRet = ResumeThread(hThread);
+
+ if (dwRet != 1)
+ {
+ Trace("ResumeThreadTest:ResumeThread "
+ "failed (%x)\n",GetLastError());
+ }
+ else
+ {
+ /* Wait again, now that the thread has been
+ resumed, and the return should be WAIT_OBJECT_0
+ */
+ dwRet = WaitForSingleObject(hThread,INFINITE);
+
+ if (dwRet != WAIT_OBJECT_0)
+ {
+ Trace("ResumeThreadTest:WaitForSingleObject "
+ "failed (%x)\n",GetLastError());
+ }
+ else
+ {
+ /* Check the param now and it should have been
+ set.
+ */
+ if (dwResumeThreadTestParameter != (DWORD)lpParameter)
+ {
+ Trace("ResumeThreadTest:parameter error\n");
+ }
+ else
+ {
+ bRet = TRUE;
+ }
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ Trace("ResumeThreadTest:CreateThread failed (%x)\n",GetLastError());
+ }
+
+ return bRet;
+}
+
+int __cdecl main(int argc, char **argv)
+{
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return ( FAIL );
+ }
+
+ if(!ResumeThreadTest())
+ {
+ Fail("Test Failed\n");
+ }
+
+ PAL_Terminate();
+ return (PASS);
+
+}
diff --git a/src/pal/tests/palsuite/threading/ResumeThread/test1/testinfo.dat b/src/pal/tests/palsuite/threading/ResumeThread/test1/testinfo.dat
new file mode 100644
index 0000000000..8472165d5d
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/ResumeThread/test1/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = ResumeThread
+Name = Positive Test for ResumeThread
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Test for ResumeThread. Create a suspended Thread.
+= First, ensure that it is indeed suspended. Then call resumethread
+= and check to ensure that the function has now run.
diff --git a/src/pal/tests/palsuite/threading/SetErrorMode/CMakeLists.txt b/src/pal/tests/palsuite/threading/SetErrorMode/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/SetErrorMode/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/threading/SetErrorMode/test1/CMakeLists.txt b/src/pal/tests/palsuite/threading/SetErrorMode/test1/CMakeLists.txt
new file mode 100644
index 0000000000..cfdeb31950
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/SetErrorMode/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_seterrormode_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_seterrormode_test1 coreclrpal)
+
+target_link_libraries(paltest_seterrormode_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/SetErrorMode/test1/test1.c b/src/pal/tests/palsuite/threading/SetErrorMode/test1/test1.c
new file mode 100644
index 0000000000..238cec4421
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/SetErrorMode/test1/test1.c
@@ -0,0 +1,50 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test1.c (SetErrorMode)
+**
+** Purpose: Tests the PAL implementation of the SetErrorMode function.
+** This test will set the error mode and then read the error
+** set with GetLastError().
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char **argv)
+{
+ DWORD dErrorReturn;
+ UINT dErrorModes[] = {SEM_NOOPENFILEERRORBOX, SEM_FAILCRITICALERRORS, 0};
+ int i;
+
+ /*
+ * Initialize the Pal
+ */
+ if ((PAL_Initialize(argc,argv)) != 0)
+ {
+ return (FAIL);
+ }
+
+ /*
+ * Loop through the supported Error Modes and verify
+ * that GetLastError() returns the correct Error Mode
+ */
+ for (i=0; i < (sizeof(dErrorModes) / sizeof(UINT)); i++)
+ {
+ SetLastError(dErrorModes[i]);
+ if ((dErrorReturn = GetLastError()) != dErrorModes[i])
+ {
+ Fail("ERROR: SetLastError was set to 0x%4.4x but,"
+ " GetLastError returned 0x%4.4x\n",
+ dErrorModes[i],
+ dErrorReturn);
+ }
+ }
+
+ PAL_Terminate();
+ return (PASS);
+}
diff --git a/src/pal/tests/palsuite/threading/SetErrorMode/test1/testinfo.dat b/src/pal/tests/palsuite/threading/SetErrorMode/test1/testinfo.dat
new file mode 100644
index 0000000000..875ac2a223
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/SetErrorMode/test1/testinfo.dat
@@ -0,0 +1,16 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = Threading
+Function = SetErrorMode
+Name = Positive Test for SetErrorMode
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Tests the PAL implementation of the SetErrorMode function.
+= This test will set the error mode and then read the error
+= set with GetLastError().
+
+
diff --git a/src/pal/tests/palsuite/threading/SetEvent/CMakeLists.txt b/src/pal/tests/palsuite/threading/SetEvent/CMakeLists.txt
new file mode 100644
index 0000000000..a3847f8ca9
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/SetEvent/CMakeLists.txt
@@ -0,0 +1,7 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+add_subdirectory(test3)
+add_subdirectory(test4)
+
diff --git a/src/pal/tests/palsuite/threading/SetEvent/test1/CMakeLists.txt b/src/pal/tests/palsuite/threading/SetEvent/test1/CMakeLists.txt
new file mode 100644
index 0000000000..9be8d5a421
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/SetEvent/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_setevent_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_setevent_test1 coreclrpal)
+
+target_link_libraries(paltest_setevent_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/SetEvent/test1/test1.c b/src/pal/tests/palsuite/threading/SetEvent/test1/test1.c
new file mode 100644
index 0000000000..d5a29ce3f3
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/SetEvent/test1/test1.c
@@ -0,0 +1,94 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: test1.c
+**
+** Purpose: Test for SetEvent. Create an Event and then set
+** this event, checking the return value. Ensure that it returns
+** positive.
+**
+**
+**=========================================================*/
+
+#include <palsuite.h>
+
+BOOL SetEventTest()
+{
+ int bRet = 0;
+ DWORD dwRet = 0;
+
+ LPSECURITY_ATTRIBUTES lpEventAttributes = 0;
+ BOOL bManualReset = TRUE;
+ BOOL bInitialState = FALSE;
+
+ /* Create an event which we can use with SetEvent */
+ HANDLE hEvent = CreateEvent( lpEventAttributes,
+ bManualReset, bInitialState, NULL);
+
+ if (hEvent != INVALID_HANDLE_VALUE)
+ {
+ dwRet = WaitForSingleObject(hEvent,0);
+
+ if (dwRet != WAIT_TIMEOUT)
+ {
+ Trace("SetEventTest:WaitForSingleObject failed (%x)\n", GetLastError());
+ }
+ else
+ {
+ /* Set the event to the previously created event and check
+ the return value.
+ */
+ bRet = SetEvent(hEvent);
+
+ if (!bRet)
+ {
+ Trace("SetEventTest:SetEvent failed (%x)\n", GetLastError());
+ }
+ else
+ {
+ dwRet = WaitForSingleObject(hEvent,0);
+
+ if (dwRet != WAIT_OBJECT_0)
+ {
+ Trace("SetEventTest:WaitForSingleObject failed (%x)\n", GetLastError());
+ }
+ else
+ {
+ dwRet = CloseHandle(hEvent);
+
+ if (!dwRet)
+ {
+ Trace("SetEventTest:CloseHandle failed (%x)\n", GetLastError());
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ Trace("SetEventTest:CreateEvent failed (%x)\n", GetLastError());
+ }
+
+ return bRet;
+}
+
+
+int __cdecl main(int argc, char **argv)
+{
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return ( FAIL );
+ }
+
+ if(SetEventTest() == 0)
+ {
+ Fail ("Test failed\n");
+ }
+
+ PAL_Terminate();
+ return ( PASS );
+
+}
diff --git a/src/pal/tests/palsuite/threading/SetEvent/test1/testinfo.dat b/src/pal/tests/palsuite/threading/SetEvent/test1/testinfo.dat
new file mode 100644
index 0000000000..9bfd80829c
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/SetEvent/test1/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = SetEvent
+Name = Positive Test for SetEvent
+TYPE = DEFAULT
+EXE1 = test1
+Description
+=Test for SetEvent. Create an Event and then set
+=this event, checking the return value. Ensure that it returns
+=positive.
diff --git a/src/pal/tests/palsuite/threading/SetEvent/test2/CMakeLists.txt b/src/pal/tests/palsuite/threading/SetEvent/test2/CMakeLists.txt
new file mode 100644
index 0000000000..87522b3ffc
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/SetEvent/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test2.c
+)
+
+add_executable(paltest_setevent_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_setevent_test2 coreclrpal)
+
+target_link_libraries(paltest_setevent_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/SetEvent/test2/test2.c b/src/pal/tests/palsuite/threading/SetEvent/test2/test2.c
new file mode 100644
index 0000000000..5fd2833957
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/SetEvent/test2/test2.c
@@ -0,0 +1,125 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================================
+**
+** Source: test2.c
+**
+** Dependencies: PAL_Initialize
+** PAL_Terminate
+** CreateEvent
+** CloseHandle
+** WaitForSingleObject
+**
+** Purpose:
+**
+** Test to ensure proper operation of the SetEvent()
+** API by calling it on an event handle that's already set.
+**
+
+**
+**===========================================================================*/
+#include <palsuite.h>
+
+
+
+int __cdecl main( int argc, char **argv )
+
+{
+ /* local variables */
+ DWORD dwRet = 0;
+ HANDLE hEvent = NULL;
+ LPSECURITY_ATTRIBUTES lpEventAttributes = NULL;
+ BOOL bManualReset = TRUE;
+ BOOL bInitialState = FALSE;
+
+
+ /* PAL initialization */
+ if( (PAL_Initialize(argc, argv)) != 0 )
+ {
+ return( FAIL );
+ }
+
+
+ /* create an event which we can use with SetEvent */
+ hEvent = CreateEvent( lpEventAttributes,
+ bManualReset,
+ bInitialState,
+ NULL );
+
+ if( hEvent == INVALID_HANDLE_VALUE )
+ {
+ /* ERROR */
+ Fail( "ERROR:%lu:CreateEvent() call failed\n", GetLastError() );
+ }
+
+ /* verify that the event isn't signalled yet */
+ dwRet = WaitForSingleObject( hEvent, 0 );
+ if( dwRet != WAIT_TIMEOUT )
+ {
+ /* ERROR */
+ Trace( "ERROR:WaitForSingleObject() call returned %lu, "
+ "expected WAIT_TIMEOUT\n",
+ dwRet );
+ CloseHandle( hEvent );
+ Fail( "Test failed\n" );
+ }
+
+ /* set the event */
+ if( ! SetEvent( hEvent ) )
+ {
+ /* ERROR */
+ Trace( "ERROR:%lu:SetEvent() call failed\n", GetLastError() );
+ CloseHandle( hEvent );
+ Fail( "Test failed\n" );
+ }
+
+ /* verify that the event is signalled */
+ dwRet = WaitForSingleObject( hEvent, 0 );
+ if( dwRet != WAIT_OBJECT_0 )
+ {
+ /* ERROR */
+ Trace( "ERROR:WaitForSingleObject() call returned %lu, "
+ "expected WAIT_OBJECT_0\n",
+ dwRet );
+ CloseHandle( hEvent );
+ Fail( "Test failed\n" );
+ }
+
+ /* try to set the event again */
+ if( ! SetEvent( hEvent ) )
+ {
+ /* ERROR */
+ Trace( "FAIL:%lu:SetEvent() call failed on signalled event\n",
+ GetLastError() );
+ CloseHandle( hEvent );
+ Fail( "Test failed\n" );
+ }
+
+ /* verify that the event is still signalled */
+ dwRet = WaitForSingleObject( hEvent, 0 );
+ if( dwRet != WAIT_OBJECT_0 )
+ {
+ /* ERROR */
+ Trace( "ERROR:WaitForSingleObject() call returned %lu, "
+ "expected WAIT_OBJECT_0\n",
+ dwRet );
+ CloseHandle( hEvent );
+ Fail( "Test failed\n" );
+ }
+
+
+ /* close the event handle */
+ if( ! CloseHandle( hEvent ) )
+ {
+ Fail( "ERROR:%lu:CloseHandle() call failed\n", GetLastError() );
+ }
+
+
+ /* PAL termination */
+ PAL_Terminate();
+
+ /* return success */
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/threading/SetEvent/test2/testinfo.dat b/src/pal/tests/palsuite/threading/SetEvent/test2/testinfo.dat
new file mode 100644
index 0000000000..f2153052bb
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/SetEvent/test2/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = SetEvent
+Name = Positive test for SetEvent
+TYPE = DEFAULT
+EXE1 = test2
+Description
+= Test to ensure proper operation of the SetEvent()
+= API by calling it on an event handle that's already set.
diff --git a/src/pal/tests/palsuite/threading/SetEvent/test3/CMakeLists.txt b/src/pal/tests/palsuite/threading/SetEvent/test3/CMakeLists.txt
new file mode 100644
index 0000000000..d09239b3e4
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/SetEvent/test3/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test3.c
+)
+
+add_executable(paltest_setevent_test3
+ ${SOURCES}
+)
+
+add_dependencies(paltest_setevent_test3 coreclrpal)
+
+target_link_libraries(paltest_setevent_test3
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/SetEvent/test3/test3.c b/src/pal/tests/palsuite/threading/SetEvent/test3/test3.c
new file mode 100644
index 0000000000..21601f00b8
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/SetEvent/test3/test3.c
@@ -0,0 +1,85 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================================
+**
+** Source: test3.c
+**
+** Dependencies: PAL_Initialize
+** PAL_Terminate
+** CreateEvent
+** CloseHandle
+**
+** Purpose:
+**
+** Test to ensure proper operation of the SetEvent()
+** API by calling it on an event handle that's been
+** closed. We expect it to return an appropriate error
+** result.
+**
+
+**
+**===========================================================================*/
+#include <palsuite.h>
+
+
+
+int __cdecl main( int argc, char **argv )
+
+{
+ /* local variables */
+ HANDLE hEvent = NULL;
+ LPSECURITY_ATTRIBUTES lpEventAttributes = NULL;
+ BOOL bManualReset = TRUE;
+ BOOL bInitialState = FALSE;
+
+
+ /* PAL initialization */
+ if( (PAL_Initialize(argc, argv)) != 0 )
+ {
+ return( FAIL );
+ }
+
+
+ /* create an event which we can use with SetEvent */
+ hEvent = CreateEvent( lpEventAttributes,
+ bManualReset,
+ bInitialState,
+ NULL );
+
+ if( hEvent == INVALID_HANDLE_VALUE )
+ {
+ /* ERROR */
+ Fail( "ERROR:%lu:CreateEvent() call failed\n", GetLastError() );
+ }
+
+ /* close the event handle */
+ if( ! CloseHandle( hEvent ) )
+ {
+ Fail( "ERROR:%lu:CloseHandle() call failed\n", GetLastError() );
+ }
+
+ /* try to set the event */
+ if( SetEvent( hEvent ) )
+ {
+ /* ERROR */
+ Fail( "FAIL:SetEvent() call succeeded on a closed event handle\n" );
+ }
+
+ /* verify the result of GetLastError() */
+ if( GetLastError() != ERROR_INVALID_HANDLE )
+ {
+ /* ERROR */
+ Fail( "FAIL:SetEvent() call failed on a closed event handle"
+ "but returned an unexpected error result %lu\n" );
+ }
+
+
+
+ /* PAL termination */
+ PAL_Terminate();
+
+ /* return success */
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/threading/SetEvent/test3/testinfo.dat b/src/pal/tests/palsuite/threading/SetEvent/test3/testinfo.dat
new file mode 100644
index 0000000000..7b8f43013a
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/SetEvent/test3/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = SetEvent
+Name = Negative test for SetEvent
+TYPE = DEFAULT
+EXE1 = test3
+Description
+= Test to ensure proper operation of the SetEvent()
+= API by calling it on an event handle that's been
+= closed. We expect it to return an appropriate error
+= result.
diff --git a/src/pal/tests/palsuite/threading/SetEvent/test4/CMakeLists.txt b/src/pal/tests/palsuite/threading/SetEvent/test4/CMakeLists.txt
new file mode 100644
index 0000000000..3f1d344292
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/SetEvent/test4/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test4.c
+)
+
+add_executable(paltest_setevent_test4
+ ${SOURCES}
+)
+
+add_dependencies(paltest_setevent_test4 coreclrpal)
+
+target_link_libraries(paltest_setevent_test4
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/SetEvent/test4/test4.c b/src/pal/tests/palsuite/threading/SetEvent/test4/test4.c
new file mode 100644
index 0000000000..7a79a9d708
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/SetEvent/test4/test4.c
@@ -0,0 +1,161 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================================
+**
+** Source: test4.c
+**
+** Dependencies: PAL_Initialize
+** PAL_Terminate
+** CreateEvent
+** CloseHandle
+** WaitForSingleObject
+** DuplicateHandle
+** GetCurrentProcess
+**
+** Purpose:
+**
+** Test to ensure proper operation of the SetEvent()
+** API by calling it on an event handle that's the
+** result of a DuplicateHandle() call on another event
+** handle.
+**
+
+**
+**===========================================================================*/
+#include <palsuite.h>
+
+
+
+int __cdecl main( int argc, char **argv )
+
+{
+ /* local variables */
+ DWORD dwRet = 0;
+ HANDLE hEvent = NULL;
+ HANDLE hDupEvent = NULL;
+ LPSECURITY_ATTRIBUTES lpEventAttributes = NULL;
+ BOOL bManualReset = TRUE;
+ BOOL bInitialState = FALSE;
+
+
+ /* PAL initialization */
+ if( (PAL_Initialize(argc, argv)) != 0 )
+ {
+ return( FAIL );
+ }
+
+
+ /* create an event which we can use with SetEvent */
+ hEvent = CreateEvent( lpEventAttributes,
+ bManualReset,
+ bInitialState,
+ NULL );
+
+ if( hEvent == INVALID_HANDLE_VALUE )
+ {
+ /* ERROR */
+ Fail( "ERROR:%lu:CreateEvent() call failed\n", GetLastError() );
+ }
+
+ /* verify that the event isn't signalled yet */
+ dwRet = WaitForSingleObject( hEvent, 0 );
+ if( dwRet != WAIT_TIMEOUT )
+ {
+ /* ERROR */
+ Trace( "ERROR:WaitForSingleObject() call returned %lu, "
+ "expected WAIT_TIMEOUT\n",
+ dwRet );
+ CloseHandle( hEvent );
+ Fail( "Test failed\n" );
+ }
+
+
+ /* duplicate the event handle */
+ if( ! (DuplicateHandle(
+ GetCurrentProcess(),
+ hEvent,
+ GetCurrentProcess(),
+ &hDupEvent,
+ GENERIC_READ|GENERIC_WRITE, /* ignored in PAL */
+ FALSE,
+ DUPLICATE_SAME_ACCESS ) ) )
+ {
+ Trace("ERROR:%u:DuplicateHandle() call failed\n",
+ GetLastError() );
+ CloseHandle( hEvent );
+ Fail("Test failed\n");
+ }
+
+ /* verify that the event isn't signalled yet with the duplicate handle */
+ dwRet = WaitForSingleObject( hDupEvent, 0 );
+ if( dwRet != WAIT_TIMEOUT )
+ {
+ /* ERROR */
+ Trace( "ERROR:WaitForSingleObject() call returned %lu, "
+ "expected WAIT_TIMEOUT\n",
+ dwRet );
+ CloseHandle( hEvent );
+ CloseHandle( hDupEvent );
+ Fail( "Test failed\n" );
+ }
+
+
+ /* set the event using the duplicate handle */
+ if( ! SetEvent( hDupEvent ) )
+ {
+ /* ERROR */
+ Trace( "ERROR:%lu:SetEvent() call failed\n", GetLastError() );
+ CloseHandle( hEvent );
+ CloseHandle( hDupEvent );
+ Fail( "Test failed\n" );
+ }
+
+ /* verify that the event is signalled using the duplicate handle*/
+ dwRet = WaitForSingleObject( hDupEvent, 0 );
+ if( dwRet != WAIT_OBJECT_0 )
+ {
+ /* ERROR */
+ Trace( "ERROR:WaitForSingleObject() call returned %lu, "
+ "expected WAIT_OBJECT_0\n",
+ dwRet );
+ CloseHandle( hEvent );
+ Fail( "Test failed\n" );
+ }
+
+ /* verify that the event is signalled using the original event handle */
+ dwRet = WaitForSingleObject( hEvent, 0 );
+ if( dwRet != WAIT_OBJECT_0 )
+ {
+ /* ERROR */
+ Trace( "ERROR:WaitForSingleObject() call returned %lu, "
+ "expected WAIT_OBJECT_0\n",
+ dwRet );
+ CloseHandle( hEvent );
+ Fail( "Test failed\n" );
+ }
+
+
+ /* close the duplicate event handle */
+ if( ! CloseHandle( hDupEvent ) )
+ {
+ Fail( "ERROR:%lu:CloseHandle() call failed for duplicate handle\n",
+ GetLastError() );
+ }
+
+
+ /* close the event handle */
+ if( ! CloseHandle( hEvent ) )
+ {
+ Fail( "ERROR:%lu:CloseHandle() call failed for original handle\n",
+ GetLastError() );
+ }
+
+
+ /* PAL termination */
+ PAL_Terminate();
+
+ /* return success */
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/threading/SetEvent/test4/testinfo.dat b/src/pal/tests/palsuite/threading/SetEvent/test4/testinfo.dat
new file mode 100644
index 0000000000..9a7f7ddb3b
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/SetEvent/test4/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = SetEvent
+Name = Positive test for SetEvent
+TYPE = DEFAULT
+EXE1 = test4
+Description
+= Test to ensure proper operation of the SetEvent()
+= API by calling it on an event handle that's the
+= result of a DuplicateHandle() call on another event
+= handle.
diff --git a/src/pal/tests/palsuite/threading/Sleep/CMakeLists.txt b/src/pal/tests/palsuite/threading/Sleep/CMakeLists.txt
new file mode 100644
index 0000000000..ef14ea5352
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/Sleep/CMakeLists.txt
@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+
diff --git a/src/pal/tests/palsuite/threading/Sleep/test1/CMakeLists.txt b/src/pal/tests/palsuite/threading/Sleep/test1/CMakeLists.txt
new file mode 100644
index 0000000000..b0d8db28a2
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/Sleep/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ Sleep.c
+)
+
+add_executable(paltest_sleep_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_sleep_test1 coreclrpal)
+
+target_link_libraries(paltest_sleep_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/Sleep/test1/Sleep.c b/src/pal/tests/palsuite/threading/Sleep/test1/Sleep.c
new file mode 100644
index 0000000000..f7f7c91730
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/Sleep/test1/Sleep.c
@@ -0,0 +1,80 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: Sleep.c
+**
+** Purpose: Test to establish whether the Sleep function stops the thread from
+** executing for the specified times.
+**
+** Dependencies: GetSystemTime
+** Fail
+** Trace
+**
+
+**
+**=========================================================*/
+
+#include <palsuite.h>
+
+DWORD SleepTimes[] =
+{
+ 0,
+ 50,
+ 100,
+ 500,
+ 2000
+};
+
+/* Milliseconds of error which are acceptable Function execution time, etc. */
+DWORD AcceptableTimeError = 150;
+
+int __cdecl main( int argc, char **argv )
+{
+ UINT64 OldTimeStamp;
+ UINT64 NewTimeStamp;
+ DWORD MaxDelta;
+ DWORD TimeDelta;
+ DWORD i;
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return ( FAIL );
+ }
+
+ LARGE_INTEGER performanceFrequency;
+ if (!QueryPerformanceFrequency(&performanceFrequency))
+ {
+ return FAIL;
+ }
+
+ for( i = 0; i < sizeof(SleepTimes) / sizeof(DWORD); i++)
+ {
+ OldTimeStamp = GetHighPrecisionTimeStamp(performanceFrequency);
+ Sleep(SleepTimes[i]);
+ NewTimeStamp = GetHighPrecisionTimeStamp(performanceFrequency);
+
+ TimeDelta = NewTimeStamp - OldTimeStamp;
+
+ /* For longer intervals use a 10 percent tolerance */
+ if ((SleepTimes[i] * 0.1) > AcceptableTimeError)
+ {
+ MaxDelta = SleepTimes[i] + (DWORD)(SleepTimes[i] * 0.1);
+ }
+ else
+ {
+ MaxDelta = SleepTimes[i] + AcceptableTimeError;
+ }
+
+ if ( TimeDelta<SleepTimes[i] || TimeDelta>MaxDelta )
+ {
+ Fail("The sleep function slept for %d ms when it should have "
+ "slept for %d ms\n", TimeDelta, SleepTimes[i]);
+ }
+ }
+ PAL_Terminate();
+ return ( PASS );
+
+}
diff --git a/src/pal/tests/palsuite/threading/Sleep/test1/testinfo.dat b/src/pal/tests/palsuite/threading/Sleep/test1/testinfo.dat
new file mode 100644
index 0000000000..433a061f2c
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/Sleep/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = Sleep
+Name = Positive Test for Sleep
+TYPE = DEFAULT
+EXE1 = sleep
+Description
+= Test to see if the Sleep function stops the thread from executing for the
+= specified amount of time.
diff --git a/src/pal/tests/palsuite/threading/Sleep/test2/CMakeLists.txt b/src/pal/tests/palsuite/threading/Sleep/test2/CMakeLists.txt
new file mode 100644
index 0000000000..832e8ab42d
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/Sleep/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ sleep.c
+)
+
+add_executable(paltest_sleep_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_sleep_test2 coreclrpal)
+
+target_link_libraries(paltest_sleep_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/Sleep/test2/sleep.c b/src/pal/tests/palsuite/threading/Sleep/test2/sleep.c
new file mode 100644
index 0000000000..eb30e34f2f
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/Sleep/test2/sleep.c
@@ -0,0 +1,73 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: Sleep.c
+**
+** Purpose: Test to establish whether the Sleep function stops the thread from
+** executing for the specified times.
+**
+** Dependencies: GetTickCount
+**
+
+**
+**=========================================================*/
+
+#include <palsuite.h>
+
+/*
+ * times in 10^(-3) seconds
+ */
+
+DWORD SleepTimes[] =
+{
+ 60000,
+ 300000,
+ 1800000,
+ 3200000
+};
+
+/* Milliseconds of error which are acceptable Function execution time, etc. */
+DWORD AcceptableTimeError = 150;
+
+int __cdecl main( int argc, char **argv )
+{
+ UINT64 OldTimeStamp;
+ UINT64 NewTimeStamp;
+ DWORD MaxDelta;
+ DWORD TimeDelta;
+ DWORD i;
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return ( FAIL );
+ }
+
+ LARGE_INTEGER performanceFrequency;
+ if (!QueryPerformanceFrequency(&performanceFrequency))
+ {
+ return FAIL;
+ }
+
+ for( i = 0; i < sizeof(SleepTimes) / sizeof(DWORD); i++)
+ {
+ OldTimeStamp = GetHighPrecisionTimeStamp(performanceFrequency);
+ Sleep(SleepTimes[i]);
+ NewTimeStamp = GetHighPrecisionTimeStamp(performanceFrequency);
+
+ TimeDelta = NewTimeStamp - OldTimeStamp;
+
+ MaxDelta = SleepTimes[i] + AcceptableTimeError;
+
+ if ( TimeDelta<SleepTimes[i] || TimeDelta>MaxDelta )
+ {
+ Fail("The sleep function slept for %u ms when it should have "
+ "slept for %u ms\n", TimeDelta, SleepTimes[i]);
+ }
+ }
+ PAL_Terminate();
+ return ( PASS );
+
+}
diff --git a/src/pal/tests/palsuite/threading/Sleep/test2/testinfo.dat b/src/pal/tests/palsuite/threading/Sleep/test2/testinfo.dat
new file mode 100644
index 0000000000..433a061f2c
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/Sleep/test2/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = Sleep
+Name = Positive Test for Sleep
+TYPE = DEFAULT
+EXE1 = sleep
+Description
+= Test to see if the Sleep function stops the thread from executing for the
+= specified amount of time.
diff --git a/src/pal/tests/palsuite/threading/SleepEx/CMakeLists.txt b/src/pal/tests/palsuite/threading/SleepEx/CMakeLists.txt
new file mode 100644
index 0000000000..ef14ea5352
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/SleepEx/CMakeLists.txt
@@ -0,0 +1,5 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+
diff --git a/src/pal/tests/palsuite/threading/SleepEx/test1/CMakeLists.txt b/src/pal/tests/palsuite/threading/SleepEx/test1/CMakeLists.txt
new file mode 100644
index 0000000000..de562755fc
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/SleepEx/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_sleepex_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_sleepex_test1 coreclrpal)
+
+target_link_libraries(paltest_sleepex_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/SleepEx/test1/test1.c b/src/pal/tests/palsuite/threading/SleepEx/test1/test1.c
new file mode 100644
index 0000000000..7ccfe0ce87
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/SleepEx/test1/test1.c
@@ -0,0 +1,89 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test1.c
+**
+** Purpose: Tests that SleepEx correctly sleeps for a given amount of time,
+** regardless of the alertable flag.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+typedef struct
+{
+ DWORD SleepTime;
+ BOOL Alertable;
+} testCase;
+
+testCase testCases[] =
+{
+ {0, FALSE},
+ {50, FALSE},
+ {100, FALSE},
+ {500, FALSE},
+ {2000, FALSE},
+
+ {0, TRUE},
+ {50, TRUE},
+ {100, TRUE},
+ {500, TRUE},
+ {2000, TRUE},
+};
+
+/* Milliseconds of error which are acceptable Function execution time, etc. */
+DWORD AcceptableTimeError = 150;
+
+int __cdecl main( int argc, char **argv )
+{
+ UINT64 OldTimeStamp;
+ UINT64 NewTimeStamp;
+ DWORD MaxDelta;
+ DWORD TimeDelta;
+ DWORD i;
+
+ if (0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ LARGE_INTEGER performanceFrequency;
+ if (!QueryPerformanceFrequency(&performanceFrequency))
+ {
+ return FAIL;
+ }
+
+ for (i = 0; i<sizeof(testCases) / sizeof(testCases[0]); i++)
+ {
+ OldTimeStamp = GetHighPrecisionTimeStamp(performanceFrequency);
+
+ SleepEx(testCases[i].SleepTime, testCases[i].Alertable);
+
+ NewTimeStamp = GetHighPrecisionTimeStamp(performanceFrequency);
+
+ TimeDelta = NewTimeStamp - OldTimeStamp;
+
+ /* For longer intervals use a 10 percent tolerance */
+ if ((testCases[i].SleepTime * 0.1) > AcceptableTimeError)
+ {
+ MaxDelta = testCases[i].SleepTime + (DWORD)(testCases[i].SleepTime * 0.1);
+ }
+ else
+ {
+ MaxDelta = testCases[i].SleepTime + AcceptableTimeError;
+ }
+
+ if (TimeDelta < testCases[i].SleepTime || TimeDelta > MaxDelta)
+ {
+ Fail("The sleep function slept for %d ms when it should have "
+ "slept for %d ms\n", TimeDelta, testCases[i].SleepTime);
+ }
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/threading/SleepEx/test1/testinfo.dat b/src/pal/tests/palsuite/threading/SleepEx/test1/testinfo.dat
new file mode 100644
index 0000000000..1242768743
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/SleepEx/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = SleepEx
+Name = Test #1 for SleepEx
+TYPE = DEFAULT
+EXE1 = test1
+Description
+=Tests that SleepEx correctly sleeps for a given amount of time,
+=regardless of the alertable flag.
diff --git a/src/pal/tests/palsuite/threading/SleepEx/test2/CMakeLists.txt b/src/pal/tests/palsuite/threading/SleepEx/test2/CMakeLists.txt
new file mode 100644
index 0000000000..0ea4a44449
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/SleepEx/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test2.c
+)
+
+add_executable(paltest_sleepex_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_sleepex_test2 coreclrpal)
+
+target_link_libraries(paltest_sleepex_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/SleepEx/test2/test2.c b/src/pal/tests/palsuite/threading/SleepEx/test2/test2.c
new file mode 100644
index 0000000000..c2ba4e704d
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/SleepEx/test2/test2.c
@@ -0,0 +1,183 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test2.c
+**
+** Purpose: Tests that a child thread in the middle of a SleepEx call will be
+** interrupted by QueueUserAPC if the alert flag was set.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+const int ChildThreadSleepTime = 2000;
+const int InterruptTime = 1000;
+/* We need to keep in mind that BSD has a timer resolution of 10ms, so
+ we need to adjust our delta to keep that in mind. Besides we need some
+ tolerance to account for different scheduling strategies, heavy load
+ scenarios, etc.
+
+ Real-world data also tells us we can expect a big difference between
+ values when run on real iron vs run in a hypervisor.
+
+ Thread-interruption times when run on bare metal will typically yield
+ around 0ms on Linux and between 0 and 16ms on FreeBSD. However, when run
+ in a hypervisor (like VMWare ESXi) we may get values around an order of
+ magnitude higher, up to 110 ms for some tests.
+*/
+const DWORD AcceptableDelta = 150;
+
+const int Iterations = 5;
+
+void RunTest(BOOL AlertThread);
+VOID PALAPI APCFunc(ULONG_PTR dwParam);
+DWORD PALAPI SleeperProc(LPVOID lpParameter);
+
+DWORD ThreadSleepDelta;
+
+int __cdecl main( int argc, char **argv )
+{
+ int i;
+ DWORD dwAvgDelta;
+
+ if (0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /*
+ On some platforms (e.g. FreeBSD 4.9) the first call to some synch objects
+ (such as conditions) involves some pthread internal initialization that
+ can make the first wait slighty longer, potentially going above the
+ acceptable delta for this test. Let's add a dummy wait to preinitialize
+ internal structures
+ */
+ Sleep(100);
+
+ /*
+ * Check that Queueing an APC in the middle of a sleep does interrupt
+ * it, if it's in an alertable state.
+ */
+ dwAvgDelta = 0;
+ for (i=0;i<Iterations;i++)
+ {
+ RunTest(TRUE);
+ dwAvgDelta += ThreadSleepDelta - InterruptTime;
+ }
+ dwAvgDelta /= Iterations;
+
+ if (dwAvgDelta > AcceptableDelta)
+ {
+ Fail("Expected thread to sleep for %d ms (and get interrupted).\n"
+ "Average delta: %u ms, acceptable delta: %u\n",
+ InterruptTime, dwAvgDelta, AcceptableDelta);
+ }
+
+ /*
+ * Check that Queueing an APC in the middle of a sleep does NOT interrupt
+ * it, if it is not in an alertable state.
+ */
+ dwAvgDelta = 0;
+ for (i=0;i<Iterations;i++)
+ {
+ RunTest(FALSE);
+ dwAvgDelta += ThreadSleepDelta - ChildThreadSleepTime;
+ }
+ dwAvgDelta /= Iterations;
+
+ if (dwAvgDelta > AcceptableDelta)
+ {
+ Fail("Expected thread to sleep for %d ms (and not be interrupted).\n"
+ "Average delta: %u ms, acceptable delta: %u\n",
+ ChildThreadSleepTime, dwAvgDelta, AcceptableDelta);
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
+void RunTest(BOOL AlertThread)
+{
+ HANDLE hThread = 0;
+ DWORD dwThreadId = 0;
+ int ret;
+
+ hThread = CreateThread( NULL,
+ 0,
+ (LPTHREAD_START_ROUTINE)SleeperProc,
+ (LPVOID) AlertThread,
+ 0,
+ &dwThreadId);
+
+ if (hThread == NULL)
+ {
+ Fail("ERROR: Was not able to create the thread to test SleepEx!\n"
+ "GetLastError returned %d\n", GetLastError());
+ }
+
+ if (SleepEx(InterruptTime, FALSE) != 0)
+ {
+ Fail("The creating thread did not sleep!\n");
+ }
+
+ ret = QueueUserAPC(APCFunc, hThread, 0);
+ if (ret == 0)
+ {
+ Fail("QueueUserAPC failed! GetLastError returned %d\n", GetLastError());
+ }
+
+ ret = WaitForSingleObject(hThread, INFINITE);
+ if (ret == WAIT_FAILED)
+ {
+ Fail("Unable to wait on child thread!\nGetLastError returned %d.",
+ GetLastError());
+ }
+}
+
+/* Function doesn't do anything, just needed to interrupt SleepEx */
+VOID PALAPI APCFunc(ULONG_PTR dwParam)
+{
+
+}
+
+/* Entry Point for child thread. */
+DWORD PALAPI SleeperProc(LPVOID lpParameter)
+{
+ UINT64 OldTimeStamp;
+ UINT64 NewTimeStamp;
+ BOOL Alertable;
+ DWORD ret;
+
+ Alertable = (BOOL) lpParameter;
+
+ LARGE_INTEGER performanceFrequency;
+ if (!QueryPerformanceFrequency(&performanceFrequency))
+ {
+ return FAIL;
+ }
+
+ OldTimeStamp = GetHighPrecisionTimeStamp(performanceFrequency);
+
+ ret = SleepEx(ChildThreadSleepTime, Alertable);
+
+ NewTimeStamp = GetHighPrecisionTimeStamp(performanceFrequency);
+
+ if (Alertable && ret != WAIT_IO_COMPLETION)
+ {
+ Fail("Expected the interrupted sleep to return WAIT_IO_COMPLETION.\n"
+ "Got %d\n", ret);
+ }
+ else if (!Alertable && ret != 0)
+ {
+ Fail("Sleep did not timeout. Expected return of 0, got %d.\n", ret);
+ }
+
+
+ ThreadSleepDelta = NewTimeStamp - OldTimeStamp;
+
+ return 0;
+}
diff --git a/src/pal/tests/palsuite/threading/SleepEx/test2/testinfo.dat b/src/pal/tests/palsuite/threading/SleepEx/test2/testinfo.dat
new file mode 100644
index 0000000000..52f3ce0af6
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/SleepEx/test2/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = SleepEx
+Name = Test #2 for SleepEx
+TYPE = DEFAULT
+EXE1 = test2
+Description
+=Tests that a child thread in the middle of a SleepEx call will be
+=interrupted by QueueUserAPC if the alert flag was set.
+
diff --git a/src/pal/tests/palsuite/threading/SwitchToThread/CMakeLists.txt b/src/pal/tests/palsuite/threading/SwitchToThread/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/SwitchToThread/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/threading/SwitchToThread/test1/CMakeLists.txt b/src/pal/tests/palsuite/threading/SwitchToThread/test1/CMakeLists.txt
new file mode 100644
index 0000000000..40ecc910b0
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/SwitchToThread/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_switchtothread_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_switchtothread_test1 coreclrpal)
+
+target_link_libraries(paltest_switchtothread_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/SwitchToThread/test1/test1.c b/src/pal/tests/palsuite/threading/SwitchToThread/test1/test1.c
new file mode 100644
index 0000000000..76ecdd3572
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/SwitchToThread/test1/test1.c
@@ -0,0 +1,97 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Test to ensure SwitchToThread works, without
+** causing test to hang
+**
+** Dependencies: PAL_Initialize
+** Fail
+** SwitchToThread
+** WaitForMultipleObject
+** CreateThread
+** GetLastError
+**
+
+**
+**===========================================================================*/
+
+
+#include <palsuite.h>
+#define THREAD_COUNT 10
+#define REPEAT_COUNT 1000
+#define TIMEOUT 60000
+void PALAPI Run_Thread(LPVOID lpParam);
+
+/**
+ * main
+ *
+ * executable entry point
+ */
+INT __cdecl main( INT argc, CHAR **argv )
+{
+ DWORD dwParam;
+ HANDLE hThread[THREAD_COUNT];
+ DWORD threadId[THREAD_COUNT];
+
+ int i = 0;
+ int returnCode = 0;
+
+ /*PAL initialization */
+ if( (PAL_Initialize(argc, argv)) != 0 )
+ {
+ return FAIL;
+ }
+
+
+ for( i = 0; i < THREAD_COUNT; i++ )
+ {
+ dwParam = (int) i;
+ //Create thread
+ hThread[i] = CreateThread(
+ NULL, /* no security attributes */
+ 0, /* use default stack size */
+ (LPTHREAD_START_ROUTINE)Run_Thread,/* thread function */
+ (LPVOID)dwParam, /* argument to thread function */
+ 0, /* use default creation flags */
+ &threadId[i] /* returns the thread identifier*/
+ );
+
+ if(hThread[i] == NULL)
+ {
+ Fail("Create Thread failed for iteration %d GetLastError value is %d\n", i, GetLastError());
+ }
+
+ }
+
+
+ returnCode = WaitForMultipleObjects(THREAD_COUNT, hThread, TRUE, TIMEOUT);
+ if( WAIT_OBJECT_0 != returnCode )
+ {
+ Trace("Wait for Object(s) returned %d, expected value is %d, and GetLastError value is %d\n", returnCode, WAIT_OBJECT_0, GetLastError());
+ }
+
+ PAL_Terminate();
+ return PASS;
+
+}
+
+void PALAPI Run_Thread (LPVOID lpParam)
+{
+ int i = 0;
+ int Id=(int)lpParam;
+
+ for(i=0; i < REPEAT_COUNT; i++ )
+ {
+ // No Last Error is set..
+ if(!SwitchToThread())
+ {
+ Trace( "The operating system did not switch execution to another thread,"
+ "for thread id[%d], iteration [%d]\n", Id, i );
+ }
+ }
+}
diff --git a/src/pal/tests/palsuite/threading/SwitchToThread/test1/testinfo.dat b/src/pal/tests/palsuite/threading/SwitchToThread/test1/testinfo.dat
new file mode 100644
index 0000000000..15ee8d4d4e
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/SwitchToThread/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = SwitchToThread
+Name = Test for SwitchToThread
+TYPE = DEFAULT
+EXE1 = test
+Description
+= Purpose: Test to ensure SwitchToThread is
+= working properly on supported platforms
diff --git a/src/pal/tests/palsuite/threading/TLS/CMakeLists.txt b/src/pal/tests/palsuite/threading/TLS/CMakeLists.txt
new file mode 100644
index 0000000000..bffdf7f714
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/TLS/CMakeLists.txt
@@ -0,0 +1,9 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+add_subdirectory(test3)
+add_subdirectory(test4)
+add_subdirectory(test5)
+
+
diff --git a/src/pal/tests/palsuite/threading/TLS/test1/CMakeLists.txt b/src/pal/tests/palsuite/threading/TLS/test1/CMakeLists.txt
new file mode 100644
index 0000000000..ff1a866eb9
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/TLS/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ TLS.c
+)
+
+add_executable(paltest_tls_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_tls_test1 coreclrpal)
+
+target_link_libraries(paltest_tls_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/TLS/test1/TLS.c b/src/pal/tests/palsuite/threading/TLS/test1/TLS.c
new file mode 100644
index 0000000000..4300c3f98b
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/TLS/test1/TLS.c
@@ -0,0 +1,182 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================================
+**
+** Source: tls.c
+**
+** Purpose: Test to ensure TlsAlloc, TlsGetValue, TlsSetValue
+** and TlsFree are working properly together.
+**
+** Dependencies: PAL_Initialize
+** Fail
+** Sleep
+** LocalAlloc
+** LocalFree
+** WaitForSingleObject
+** CreateThread
+** GetLastError
+**
+
+**
+**===========================================================================*/
+#include <palsuite.h>
+
+#define NUM_OF_THREADS 10
+
+DWORD dwTlsIndex; /* TLS index */
+
+/**
+ * CommonFunction
+ *
+ * Helper function that calls TlsGetValue
+ */
+VOID CommonFunction(VOID)
+{
+ LPVOID lpvData;
+ DWORD dwError;
+
+ /* Retrieve a data pointer for the current thread. */
+ lpvData = TlsGetValue(dwTlsIndex);
+
+ if ( (lpvData == 0) &&
+ ((dwError = GetLastError()) != NO_ERROR) )
+ {/*ERROR */
+ Fail("TlsGetValue(%d) returned 0 with error %d\n",
+ dwTlsIndex,
+ dwError);
+ }
+
+ Sleep(5000);
+}
+
+/**
+ * ThreadFunc
+ *
+ * Thread function that stores a value in the thread's tls slot
+ * for the predefined tls index
+ */
+DWORD PALAPI ThreadFunc(LPVOID lpThreadParameter)
+{
+ LPVOID lpvData;
+ DWORD dwError;
+
+ /* Initialize the TLS index for this thread.*/
+ lpvData = (LPVOID) LocalAlloc(0, 256);
+
+ if( lpvData == NULL )
+ {/*ERROR */
+ dwError = GetLastError();
+ Fail("Unexpected LocalAlloc(0, 256) failure with error %d\n",
+ dwError);
+ }
+
+
+ if ( TlsSetValue(dwTlsIndex, lpvData) == 0 )
+ {/*ERROR */
+ dwError = GetLastError();
+ Fail("TlsSetValue(%d, %x) returned 0 with error %d\n",
+ dwTlsIndex,
+ lpvData,
+ dwError);
+ }
+
+ CommonFunction();
+
+ /* Release the dynamic memory. */
+ lpvData = TlsGetValue(dwTlsIndex);
+
+ if ( (lpvData == 0) &&
+ ((dwError = GetLastError()) != NO_ERROR) )
+ {/*ERROR */
+ Fail("TlsGetValue(%d) returned 0 with error %d\n",
+ dwTlsIndex,
+ dwError);
+ }
+ else
+ {
+ if( LocalFree((HLOCAL) lpvData) != NULL )
+ {
+ dwError = GetLastError();
+ Fail("Unexpected LocalFree(%x) failure with error %d\n",
+ lpvData,
+ dwError);
+ }
+ }
+
+ return PASS;
+}
+
+/**
+ * main
+ *
+ * executable entry point
+ */
+INT __cdecl main( INT argc, CHAR **argv )
+{
+ DWORD IDThread;
+ HANDLE hThread[NUM_OF_THREADS];
+ int i;
+
+ /*PAL initialization */
+ if( (PAL_Initialize(argc, argv)) != 0 )
+ {
+ return FAIL;
+ }
+
+ /*Allocate a TLS index. */
+ if ((dwTlsIndex = TlsAlloc()) == TLS_OUT_OF_INDEXES)
+ {/*RROR*/
+ DWORD dwError = GetLastError();
+ Fail("TlsAlloc() returned error %d\n",
+ dwError);
+ }
+
+ /*Create multiple threads.*/
+
+ for (i = 0; i < NUM_OF_THREADS; i++)
+ {
+ hThread[i] = CreateThread(NULL, /* no security attributes*/
+ 0, /* use default stack size */
+ ThreadFunc, /* thread function */
+ NULL, /* no thread function argument */
+ 0, /* use default creation flags */
+ &IDThread); /* returns thread identifier */
+
+ /* Check the return value for success. */
+ if (hThread[i] == NULL)
+ {/* ERROR */
+ DWORD dwError = GetLastError();
+ Fail("Unexpected CreateThread error %d\n",
+ dwError);
+ }
+ }
+
+ /* Wait for all threads to finish */
+ for (i = 0; i < NUM_OF_THREADS; i++)
+ {
+ DWORD dwRet;
+
+ dwRet = WaitForSingleObject(hThread[i], INFINITE);
+
+ if( dwRet == WAIT_FAILED )
+ {/* ERROR */
+ DWORD dwError = GetLastError();
+ Fail("Unexpected WaitForSingleObject error %d\n",
+ dwError);
+ }
+ }
+
+ /* Release the TLS index */
+ if( TlsFree( dwTlsIndex ) == 0 )
+ {/* ERROR */
+ DWORD dwError = GetLastError();
+ Fail("TlsFree() returned 0 with error %d\n",
+ dwError);
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/threading/TLS/test1/testinfo.dat b/src/pal/tests/palsuite/threading/TLS/test1/testinfo.dat
new file mode 100644
index 0000000000..544e391266
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/TLS/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = TLS
+Name = Test for TlsAlloc, TlsGetValue, TlsSetValue and TlsFree
+TYPE = DEFAULT
+EXE1 = tls
+Description
+= Test to ensure TlsAlloc, TlsGetValue, TlsSetValue
+= and TlsFree are working properly together.
diff --git a/src/pal/tests/palsuite/threading/TLS/test2/CMakeLists.txt b/src/pal/tests/palsuite/threading/TLS/test2/CMakeLists.txt
new file mode 100644
index 0000000000..5afe82b4a6
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/TLS/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ TLS.c
+)
+
+add_executable(paltest_tls_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_tls_test2 coreclrpal)
+
+target_link_libraries(paltest_tls_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/TLS/test2/TLS.c b/src/pal/tests/palsuite/threading/TLS/test2/TLS.c
new file mode 100644
index 0000000000..96a6011f96
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/TLS/test2/TLS.c
@@ -0,0 +1,66 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================================
+**
+** Source: tls.c
+**
+** Purpose: Test to ensure TlsAlloc and TlsFree are working when we try
+** to allocate the guaranted minimum number of indicies.
+**
+
+**
+**===========================================================================*/
+#include <palsuite.h>
+
+#define NUM_OF_INDEX 64
+/* Minimum guaranteed is at least 64 for all systems.*/
+
+/**
+ * main
+ *
+ * executable entry point
+ */
+INT __cdecl main( INT argc, CHAR **argv )
+{
+ DWORD dwIndexes[NUM_OF_INDEX];
+ int i,j;
+
+ /* PAL initialization */
+ if( (PAL_Initialize(argc, argv)) != 0 )
+ {
+ return FAIL;
+ }
+
+ /* Allocate a bunch of TLS indexes. */
+ for( i = 0; i < NUM_OF_INDEX; i++ )
+ {
+ if( (dwIndexes[i] = TlsAlloc()) == TLS_OUT_OF_INDEXES )
+ {/*ERROR */
+ DWORD dwError = GetLastError();
+ Fail("TlsAlloc() returned -1 with error %d"
+ "when trying to allocate %d index\n",
+ dwError,
+ i);
+ }
+ }
+
+ /* Free the TLS indexes.*/
+ for( j = 0; j < NUM_OF_INDEX; j++ )
+ {
+ if( TlsFree(dwIndexes[j]) == 0 )
+ {/* ERROR */
+ DWORD dwError = GetLastError();
+ Fail("TlsFree() returned 0 with error %d"
+ "when trying to free %d index\n",
+ dwError,
+ i);
+ }
+ }
+
+ PAL_Terminate();
+
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/threading/TLS/test2/testinfo.dat b/src/pal/tests/palsuite/threading/TLS/test2/testinfo.dat
new file mode 100644
index 0000000000..3a672a5f38
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/TLS/test2/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = TLS
+Name = Test for TlsAlloc and TlsFree
+TYPE = DEFAULT
+EXE1 = tls
+Description
+= Test to ensure TlsAlloc and TlsFree are working when we try
+= to allocate the guaranted minimum number of index.
diff --git a/src/pal/tests/palsuite/threading/TLS/test3/CMakeLists.txt b/src/pal/tests/palsuite/threading/TLS/test3/CMakeLists.txt
new file mode 100644
index 0000000000..0964d33d2c
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/TLS/test3/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ TLS.c
+)
+
+add_executable(paltest_tls_test3
+ ${SOURCES}
+)
+
+add_dependencies(paltest_tls_test3 coreclrpal)
+
+target_link_libraries(paltest_tls_test3
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/TLS/test3/TLS.c b/src/pal/tests/palsuite/threading/TLS/test3/TLS.c
new file mode 100644
index 0000000000..4acaef5020
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/TLS/test3/TLS.c
@@ -0,0 +1,90 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================================
+**
+** Source: tls.c
+**
+** Purpose: Test to ensure TlsGetValue, TlsSetValue and TlsFree
+** are not working with an invalid index
+**
+** Dependencies: PAL_Initialize
+** PAL_Terminate
+** LocalAlloc
+** LocalFree
+**
+
+**
+**===========================================================================*/
+#include <palsuite.h>
+
+DWORD dwTlsIndex; /* TLS index */
+
+/**
+ * main
+ *
+ * executable entry point
+ */
+INT __cdecl main( INT argc, CHAR **argv )
+{
+ CHAR lpstrData[256] = "";
+ LPVOID lpvData = NULL;
+ BOOL bRet;
+
+ /* PAL initialization */
+ if( (PAL_Initialize(argc, argv)) != 0 )
+ {
+ return FAIL;
+ }
+
+ /* Invalid TLS index */
+ dwTlsIndex = -1;
+
+ /*
+ * Set some data in the invalid TLS index
+ *Should return 0 and an error
+ */
+ bRet = TlsSetValue(dwTlsIndex, (LPVOID)lpstrData);
+
+ if ( bRet != 0)
+ {/*ERROR */
+ Fail("TlsSetValue(%d, %x) returned %d "
+ "when it should have returned 0 and an error\n",
+ dwTlsIndex,
+ lpvData,
+ bRet);
+ }
+
+ /*
+ * Get the data at the invalid index
+ * Should return 0 and an error
+ */
+ lpvData = TlsGetValue(dwTlsIndex);
+
+ if ( lpvData != 0 )
+ {/* ERROR */
+ Fail("TlsGetValue(%d) returned %d "
+ "when it should have returned 0 and an error\n",
+ dwTlsIndex,
+ lpvData);
+ }
+
+ /*
+ * Release the invalid TLS index
+ * Should return 0 and an error
+ */
+ bRet = TlsFree( dwTlsIndex );
+
+ if( bRet != 0 )
+ {/* ERROR */
+ Fail("TlsFree() returned %d "
+ "when it should have returned 0 and an error\n",
+ bRet);
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
+
diff --git a/src/pal/tests/palsuite/threading/TLS/test3/testinfo.dat b/src/pal/tests/palsuite/threading/TLS/test3/testinfo.dat
new file mode 100644
index 0000000000..63ce59f351
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/TLS/test3/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = TLS
+Name = TlsGetValue, TlsSetValue and TlsFree
+TYPE = DEFAULT
+EXE1 = tls
+Description
+= Test to ensure TlsGetValue, TlsSetValue and TlsFree
+= are not working with an invalid index
diff --git a/src/pal/tests/palsuite/threading/TLS/test4/CMakeLists.txt b/src/pal/tests/palsuite/threading/TLS/test4/CMakeLists.txt
new file mode 100644
index 0000000000..7e7b47786a
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/TLS/test4/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test4.c
+)
+
+add_executable(paltest_tls_test4
+ ${SOURCES}
+)
+
+add_dependencies(paltest_tls_test4 coreclrpal)
+
+target_link_libraries(paltest_tls_test4
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/TLS/test4/test4.c b/src/pal/tests/palsuite/threading/TLS/test4/test4.c
new file mode 100644
index 0000000000..8c3603cdb0
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/TLS/test4/test4.c
@@ -0,0 +1,137 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================================
+**
+** Source: test4.c (threading/tls)
+**
+** Purpose: Test to ensure that upon key creation, the value NULL
+** is associated with the new key in all active threads.
+** Upon thread creation, the value NULL is associated
+** with all defined keys in the new thread.
+**
+** Dependencies: PAL_Initialize
+** PAL_Terminate
+** LocalAlloc
+** LocalFree
+**
+
+**
+**===========================================================================*/
+#include <palsuite.h>
+
+#define NUM_OF_THREADS 10
+
+DWORD dwTlsIndex; /* TLS index */
+
+/**
+ * ThreadFunc
+ *
+ * Thread function that checks that NULL is associated with the tls index
+ */
+DWORD PALAPI ThreadFunc(VOID)
+{
+ LPVOID lpvData;
+ DWORD dwError;
+
+ /* Retrieve a data pointer for the current thread.
+ The return value should be NULL since no data has been
+ set in the index */
+ lpvData = TlsGetValue(dwTlsIndex);
+
+ if ( (lpvData != NULL) &&
+ ((dwError = GetLastError()) == NO_ERROR) )
+ {/*ERROR */
+ Fail("TlsGetValue(%d) returned data "
+ "even if no data was associated with the index\n",
+ dwTlsIndex);
+ }
+
+ return PASS;
+}
+
+/**
+ * main
+ *
+ * executable entry point
+ */
+INT __cdecl main( INT argc, CHAR **argv )
+{
+ DWORD IDThread;
+ LPVOID lpvData;
+ DWORD dwError;
+ HANDLE hThread[NUM_OF_THREADS];
+ int i;
+
+ /*PAL initialization */
+ if( (PAL_Initialize(argc, argv)) != 0 )
+ {
+ return FAIL;
+ }
+
+ /*Allocate a TLS index. */
+ if ((dwTlsIndex = TlsAlloc()) == TLS_OUT_OF_INDEXES)
+ {/*ERROR*/
+ DWORD dwError = GetLastError();
+ Fail("TlsAlloc() returned error %d\n",
+ dwError);
+ }
+
+ /*Check that the value associated with the tls index is NULL*/
+ lpvData = TlsGetValue(dwTlsIndex);
+
+ if ( (lpvData != NULL) &&
+ ((dwError = GetLastError()) == NO_ERROR) )
+ {/*ERROR */
+ Fail("TlsGetValue(%d) returned non-null data "
+ "even if no data was associated with the index\n",
+ dwTlsIndex);
+ }
+
+ /*Create multiple threads.*/
+ for (i = 0; i < NUM_OF_THREADS; i++)
+ {
+ hThread[i] = CreateThread(NULL, /* no security attributes*/
+ 0, /* use default stack size */
+ (LPTHREAD_START_ROUTINE) ThreadFunc, /* thread function */
+ NULL, /* no thread function argument */
+ 0, /* use default creation flags */
+ &IDThread); /* returns thread identifier */
+
+ /* Check the return value for success. */
+ if (hThread[i] == NULL)
+ {/* ERROR */
+ DWORD dwError = GetLastError();
+ Fail("Unexpected CreateThread error %d\n",
+ dwError);
+ }
+ }
+
+ /* Wait for all threads to finish */
+ for (i = 0; i < NUM_OF_THREADS; i++)
+ {
+ DWORD dwRet;
+
+ dwRet = WaitForSingleObject(hThread[i], INFINITE);
+
+ if( dwRet == WAIT_FAILED )
+ {/* ERROR */
+ DWORD dwError = GetLastError();
+ Fail("Unexpected WaitForSingleObject error %d\n",
+ dwError);
+ }
+ }
+
+ /* Release the TLS index */
+ if( TlsFree( dwTlsIndex ) == 0 )
+ {/* ERROR */
+ DWORD dwError = GetLastError();
+ Fail("TlsFree() returned 0 with error %d\n",
+ dwError);
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/threading/TLS/test4/testinfo.dat b/src/pal/tests/palsuite/threading/TLS/test4/testinfo.dat
new file mode 100644
index 0000000000..6001770642
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/TLS/test4/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = TLS
+Name = TlsAlloc, TlsGetValue
+TYPE = DEFAULT
+EXE1 = test4
+Description
+=Test to ensure that upon key creation, the value NULL
+=is associated with the new key in all active threads.
+=Upon thread creation, the value NULL is associated
+=with all defined keys in the new thread.
diff --git a/src/pal/tests/palsuite/threading/TLS/test5/CMakeLists.txt b/src/pal/tests/palsuite/threading/TLS/test5/CMakeLists.txt
new file mode 100644
index 0000000000..5fb5c9ddfd
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/TLS/test5/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test5.c
+)
+
+add_executable(paltest_tls_test5
+ ${SOURCES}
+)
+
+add_dependencies(paltest_tls_test5 coreclrpal)
+
+target_link_libraries(paltest_tls_test5
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/TLS/test5/test5.c b/src/pal/tests/palsuite/threading/TLS/test5/test5.c
new file mode 100644
index 0000000000..c1cd132937
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/TLS/test5/test5.c
@@ -0,0 +1,108 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================================
+**
+** Source: test5.c (threading/tls)
+**
+** Purpose: Test that creates a key, sets its value, deletes the key,
+** creates a new key, and gets its value to make sure its NULL.
+**
+** Dependencies: PAL_Initialize
+** PAL_Terminate
+** LocalAlloc
+** LocalFree
+**
+
+**
+**===========================================================================*/
+#include <palsuite.h>
+
+DWORD dwTlsIndex; /* TLS index */
+
+/**
+ * main
+ *
+ * executable entry point
+ */
+INT __cdecl main( INT argc, CHAR **argv )
+{
+ LPVOID lpvData;
+ DWORD dwError;
+
+ /*PAL initialization */
+ if( (PAL_Initialize(argc, argv)) != 0 )
+ {
+ return FAIL;
+ }
+
+ /**
+ * create a key, set its value, delete the key
+ */
+
+ /*Allocate a TLS index. */
+ if ((dwTlsIndex = TlsAlloc()) == TLS_OUT_OF_INDEXES)
+ {/*ERROR*/
+ DWORD dwError = GetLastError();
+ Fail("TlsAlloc() returned error %d\n",
+ dwError);
+ }
+
+ /* Initialize the TLS index for this thread.*/
+ lpvData = (LPVOID) LocalAlloc(0, 256);
+
+ if( lpvData == NULL )
+ {/*ERROR */
+ dwError = GetLastError();
+ Fail("Unexpected LocalAlloc(0, 256) failure with error %d\n",
+ dwError);
+ }
+
+ if ( TlsSetValue(dwTlsIndex, lpvData) == 0 )
+ {/*ERROR */
+ dwError = GetLastError();
+ Fail("TlsSetValue(%d, %x) returned 0 with error %d\n",
+ dwTlsIndex,
+ lpvData,
+ dwError);
+ }
+
+ /* Release the TLS index */
+ if( TlsFree( dwTlsIndex ) == 0 )
+ {/* ERROR */
+ DWORD dwError = GetLastError();
+ Fail("TlsFree() returned 0 with error %d\n",
+ dwError);
+ }
+
+
+ /**
+ * create a new key, and get its value
+ */
+
+ /*Allocate a TLS index. */
+ if ((dwTlsIndex = TlsAlloc()) == TLS_OUT_OF_INDEXES)
+ {/*ERROR*/
+ DWORD dwError = GetLastError();
+ Fail("TlsAlloc() returned error %d\n",
+ dwError);
+ }
+
+ /* Retrieve a data pointer for the current thread.
+ The return value should be NULL since no data has been
+ set in the index */
+ lpvData = TlsGetValue(dwTlsIndex);
+
+ if ( (lpvData != NULL) &&
+ ((dwError = GetLastError()) == NO_ERROR) )
+ {/*ERROR */
+ Fail("TlsGetValue(%d) returned data "
+ "even if no data was associated with the index\n",
+ dwTlsIndex);
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
diff --git a/src/pal/tests/palsuite/threading/TLS/test5/testinfo.dat b/src/pal/tests/palsuite/threading/TLS/test5/testinfo.dat
new file mode 100644
index 0000000000..4b3e2a64c5
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/TLS/test5/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = TLS
+Name = TlsAlloc and TlsGetValue
+TYPE = DEFAULT
+EXE1 = test5
+Description
+= Test that creates a key, sets its value, deletes the key,
+= creates a new key, and gets its value to make sure its NULL.
diff --git a/src/pal/tests/palsuite/threading/TLS/test6_optimizedtls/CMakeLists.txt b/src/pal/tests/palsuite/threading/TLS/test6_optimizedtls/CMakeLists.txt
new file mode 100644
index 0000000000..8b3a4ed64a
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/TLS/test6_optimizedtls/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.c
+)
+
+add_executable(paltest_tls_test6_optimizedtls
+ ${SOURCES}
+)
+
+add_dependencies(paltest_tls_test6_optimizedtls coreclrpal)
+
+target_link_libraries(paltest_tls_test6_optimizedtls
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/TLS/test6_optimizedtls/test.c b/src/pal/tests/palsuite/threading/TLS/test6_optimizedtls/test.c
new file mode 100644
index 0000000000..02419dc90c
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/TLS/test6_optimizedtls/test.c
@@ -0,0 +1,190 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================================
+**
+** Source: test.c
+**
+** Purpose: Test to ensure TlsAlloc, PAL_MakeOptimizedTlsGetter,
+** PAL_FreeOptimizedTlsGetter and TlsFree are working properly
+** on supported platforms
+**
+** Dependencies: PAL_Initialize
+** Fail
+** Sleep
+** LocalAlloc
+** LocalFree
+** WaitForSingleObject
+** CreateThread
+** GetLastError
+**
+
+**
+**===========================================================================*/
+
+
+#include <palsuite.h>
+#define THREAD_COUNT 5
+DWORD dwTlsIndex; /* TLS index */
+
+void PALAPI Run_Thread(LPVOID lpParam);
+
+/**
+ * main
+ *
+ * executable entry point
+ */
+INT __cdecl main( INT argc, CHAR **argv )
+{
+ DWORD dwParam;
+ DWORD dwError;
+ HANDLE hThread[THREAD_COUNT];
+ DWORD threadId[THREAD_COUNT];
+
+ int i = 0;
+ int returnCode = 0;
+
+ /*PAL initialization */
+ if( (PAL_Initialize(argc, argv)) != 0 )
+ {
+ return FAIL;
+ }
+
+ /*Allocate a TLS index. */
+ if ((dwTlsIndex = TlsAlloc()) == TLS_OUT_OF_INDEXES)
+ {
+ /*ERROR*/
+ dwError = GetLastError();
+ Fail("TlsAlloc() returned error %d\n",
+ dwError);
+ }
+
+
+ for( i = 0; i < THREAD_COUNT; i++ )
+ {
+ dwParam = (int) i;
+ //Create thread
+ hThread[i] = CreateThread(
+ NULL, /* no security attributes */
+ 0, /* use default stack size */
+ (LPTHREAD_START_ROUTINE)Run_Thread,/* thread function */
+ (LPVOID)dwParam, /* argument to thread function */
+ 0, /* use default creation flags */
+ &threadId[i] /* returns the thread identifier*/
+ );
+
+ if(hThread[i] == NULL)
+ {
+ Fail("Create Thread failed for iteration %d GetLastError value is %d\n", i, GetLastError());
+ }
+
+ }
+
+
+ returnCode = WaitForMultipleObjects(THREAD_COUNT, hThread, TRUE, INFINITE);
+ if( WAIT_OBJECT_0 != returnCode )
+ {
+ Trace("Wait for Object(s) returned %d, expected value is %d, and GetLastError value is %d\n", returnCode, WAIT_OBJECT_0, GetLastError());
+ }
+
+ /* Release the TLS index */
+ if( TlsFree( dwTlsIndex ) == 0 )
+ {
+ /* ERROR */
+ dwError = GetLastError();
+ Fail("TlsFree() returned 0 with error %d\n",
+ dwError);
+ }
+
+ PAL_Terminate();
+ return PASS;
+
+}
+
+void PALAPI Run_Thread (LPVOID lpParam)
+{
+ unsigned int i = 0;
+
+ LPVOID lpvData;
+ DWORD dwError;
+ PAL_POPTIMIZEDTLSGETTER ptrOptimizedTlsGetter;
+
+ int Id=(int)lpParam;
+
+
+ lpvData = TlsGetValue(dwTlsIndex);
+ if ( (lpvData != NULL) &&
+ ((dwError = GetLastError()) == NO_ERROR) )
+ {
+ /*ERROR */
+ Fail("Error:%d:TlsGetValue(%d) returned data "
+ "even if data was not associated with the index, for thread id [%d]\n",
+ dwError, dwTlsIndex, Id);
+ }
+
+
+ /* Initialize the TLS index for this thread.*/
+ lpvData = (LPVOID) LocalAlloc(0, 256);
+
+ if( lpvData == NULL )
+ {
+ /*ERROR */
+ dwError = GetLastError();
+ Fail("Unexpected LocalAlloc(0, 256) failure with error %d\n",
+ dwError);
+ }
+
+ if ( TlsSetValue(dwTlsIndex, lpvData) == 0 )
+ {
+ /*ERROR */
+ dwError = GetLastError();
+ Fail("TlsSetValue(%d, %x) returned 0 with error %d\n",
+ dwTlsIndex,
+ lpvData,
+ dwError);
+ }
+
+ ptrOptimizedTlsGetter = PAL_MakeOptimizedTlsGetter(dwTlsIndex);
+ if( ptrOptimizedTlsGetter == NULL )
+ {
+ /* Retrieve a data pointer for the current thread.
+ The return value should be NULL since no data has been
+ set in the index */
+ lpvData = TlsGetValue(dwTlsIndex);
+ Trace("Not Inside the optimizer loop for thread [%d]\n", Id);
+
+ if ( (lpvData == NULL) &&
+ ((dwError = GetLastError()) == NO_ERROR) )
+ {
+ /*ERROR */
+ Fail("Error:%d:TlsGetValue(%d) returned data "
+ "as NULL even if data was associated with the index, for thread id [%d]\n",
+ dwError, dwTlsIndex, Id);
+ }
+ }
+ else
+ {
+ /* Retrieve a data pointer for the current thread.
+ The return value should be NULL since no data has been
+ set in the index */
+ lpvData = ptrOptimizedTlsGetter();
+
+ if ( (lpvData == NULL) &&
+ ((dwError = GetLastError()) == NO_ERROR) )
+ {
+ /*ERROR */
+ Fail(" Error:%d: MakeOptimizedTlsGetter for dwTlsIndex (%d) returned data "
+ "as NULL even if no data was associated with the index, for thread id [%d]\n",
+ dwError, dwTlsIndex, Id);
+ }
+
+ Trace("Inside the optimizer loop for thread [%d]\n", Id);
+ PAL_FreeOptimizedTlsGetter(ptrOptimizedTlsGetter);
+ }
+
+
+
+
+}
+
diff --git a/src/pal/tests/palsuite/threading/TLS/test6_optimizedtls/testinfo.dat b/src/pal/tests/palsuite/threading/TLS/test6_optimizedtls/testinfo.dat
new file mode 100644
index 0000000000..2193edcab3
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/TLS/test6_optimizedtls/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = PAL_MakeOptimizedTlsGetter and PAL_FreeOptimizedTlsGetter
+Name = Test for PAL_MakeOptimizedTlsGetterandPAL_FreeOptimizedTlsGetter
+TYPE = DEFAULT
+EXE1 = test
+Description
+= Purpose: Test to ensure TlsAlloc, PAL_MakeOptimizedTlsGetter,
+= PAL_FreeOptimizedTlsGetter and TlsFree are working properly
+= on supported platforms
diff --git a/src/pal/tests/palsuite/threading/TerminateProcess/CMakeLists.txt b/src/pal/tests/palsuite/threading/TerminateProcess/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/TerminateProcess/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/threading/TerminateProcess/test1/CMakeLists.txt b/src/pal/tests/palsuite/threading/TerminateProcess/test1/CMakeLists.txt
new file mode 100644
index 0000000000..37d575952f
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/TerminateProcess/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ TerminateProcess.c
+)
+
+add_executable(paltest_terminateprocess_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_terminateprocess_test1 coreclrpal)
+
+target_link_libraries(paltest_terminateprocess_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/TerminateProcess/test1/TerminateProcess.c b/src/pal/tests/palsuite/threading/TerminateProcess/test1/TerminateProcess.c
new file mode 100644
index 0000000000..6feedfce76
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/TerminateProcess/test1/TerminateProcess.c
@@ -0,0 +1,41 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: terminateprocess/test1/terminateprocess.c
+**
+** Purpose: Test to see if TerminateProcess will
+** terminate the current process.
+**
+** Dependencies: GetCurrentProcess
+**
+**
+**=========================================================*/
+
+#include <palsuite.h>
+
+INT __cdecl main( int argc, char **argv )
+{
+
+ HANDLE hProcess;
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return (FAIL);
+ }
+
+ hProcess = GetCurrentProcess();
+
+ Trace ("Testing TerminateProcess function.\n");
+
+ if ( 0 == ( TerminateProcess ( hProcess, PASS ) ) )
+ {
+ Fail ("TerminateProcess failed.\n");
+ }
+
+ PAL_TerminateEx(FAIL);
+ return (FAIL);
+
+}
diff --git a/src/pal/tests/palsuite/threading/TerminateProcess/test1/testinfo.dat b/src/pal/tests/palsuite/threading/TerminateProcess/test1/testinfo.dat
new file mode 100644
index 0000000000..7ee69bfa29
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/TerminateProcess/test1/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = TerminateProcess
+Name = Positive Test for TerminateProcess
+TYPE = DEFAULT
+EXE1 = terminateprocess
+Description
+= Test to see if the function TerminateProcess terminates the currently
+= running process and passes the appropriate value through uExitCode.
+
diff --git a/src/pal/tests/palsuite/threading/ThreadPriority/CMakeLists.txt b/src/pal/tests/palsuite/threading/ThreadPriority/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/ThreadPriority/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/threading/ThreadPriority/test1/CMakeLists.txt b/src/pal/tests/palsuite/threading/ThreadPriority/test1/CMakeLists.txt
new file mode 100644
index 0000000000..e341ca7435
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/ThreadPriority/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ ThreadPriority.c
+)
+
+add_executable(paltest_threadpriority_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_threadpriority_test1 coreclrpal)
+
+target_link_libraries(paltest_threadpriority_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/ThreadPriority/test1/ThreadPriority.c b/src/pal/tests/palsuite/threading/ThreadPriority/test1/ThreadPriority.c
new file mode 100644
index 0000000000..95bcdac52a
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/ThreadPriority/test1/ThreadPriority.c
@@ -0,0 +1,83 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================================
+**
+** Source: threadpriority.c
+**
+** Purpose: Test to ensure GetThreadPriority works properly.
+**
+** Dependencies: PAL_Initialize
+** PAL_Terminate
+** Fail
+** CreateThread
+** WaitForSingleObject
+** GetLastError
+** time()
+**
+
+**
+**===========================================================================*/
+#include <palsuite.h>
+
+/**
+ * CheckThreadPriority
+ *
+ * Helper function that checks the current thread priority
+ * against an expected value.
+ */
+static VOID CheckThreadPriority( HANDLE hThread, int expectedPriority )
+{
+ int priority;
+ DWORD dwError = 0;
+
+ /* get the current thread priority */
+ priority = GetThreadPriority( hThread );
+ if( priority == THREAD_PRIORITY_ERROR_RETURN )
+ {
+ /* GetThreadPriority call failed */
+ dwError = GetLastError();
+ Fail( "Unexpected GetThreadPriority() failure "
+ "with error %d\n", dwError );
+ }
+ else if( priority != expectedPriority )
+ {
+ /* unexpected thread priority detected */
+ Fail( "Unexpected initial thread priority value %d reported\n",
+ priority );
+ }
+}
+
+
+/**
+ * main
+ *
+ * executable entry point
+ */
+INT __cdecl main( INT argc, CHAR **argv )
+{
+
+ /* PAL initialization */
+ if( (PAL_Initialize(argc, argv)) != 0 )
+ {
+ return( FAIL );
+ }
+
+ /* set the thread priority of the main to the highest possible value
+ this will give the chance to the main thread to create all the
+ other threads */
+ if(!SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_NORMAL))
+ {
+ DWORD dwError;
+
+ dwError = GetLastError();
+ Fail( "Unexpected SetThreadPriority() failure with error %d\n",
+ dwError );
+ }
+
+ CheckThreadPriority( GetCurrentThread(), THREAD_PRIORITY_NORMAL );
+ //Add verification of timing out here..
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/threading/ThreadPriority/test1/testinfo.dat b/src/pal/tests/palsuite/threading/ThreadPriority/test1/testinfo.dat
new file mode 100644
index 0000000000..0abd9c1e06
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/ThreadPriority/test1/testinfo.dat
@@ -0,0 +1,17 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = ThreadPriority
+Name = Test for GetThreadPriority and SetThreadPriority
+TYPE = DEFAULT
+EXE1 = threadpriority
+Description
+= Test to ensure proper operation of the GetThreadPriority
+= and SetThreadPriority APIs. The test launches several threads
+= of varying priorities, and verifies that the correct priority
+= is reported for each. It also verifies that the processing
+= time for each test thread is consistent with the priority
+= that's set for it.
diff --git a/src/pal/tests/palsuite/threading/WaitForMultipleObjects/CMakeLists.txt b/src/pal/tests/palsuite/threading/WaitForMultipleObjects/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/WaitForMultipleObjects/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/threading/WaitForMultipleObjects/test1/CMakeLists.txt b/src/pal/tests/palsuite/threading/WaitForMultipleObjects/test1/CMakeLists.txt
new file mode 100644
index 0000000000..2b1f946b26
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/WaitForMultipleObjects/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_waitformultipleobjects_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_waitformultipleobjects_test1 coreclrpal)
+
+target_link_libraries(paltest_waitformultipleobjects_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/WaitForMultipleObjects/test1/test1.c b/src/pal/tests/palsuite/threading/WaitForMultipleObjects/test1/test1.c
new file mode 100644
index 0000000000..8249c38d9d
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/WaitForMultipleObjects/test1/test1.c
@@ -0,0 +1,224 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: test1.c
+**
+** Purpose: Test for WaitForMultipleObjects. Call the function
+** on an array of 4 events, and ensure that it returns correct
+** results when we do so.
+**
+**
+**=========================================================*/
+
+#include <palsuite.h>
+
+/* Number of events in array */
+#define MAX_EVENTS 4
+
+BOOL WaitForMultipleObjectsTest()
+{
+ BOOL bRet = TRUE;
+ DWORD dwRet = 0;
+
+ DWORD i = 0, j = 0;
+
+ LPSECURITY_ATTRIBUTES lpEventAttributes = NULL;
+ BOOL bManualReset = TRUE;
+ BOOL bInitialState = TRUE;
+
+ HANDLE hEvent[MAX_EVENTS];
+
+ /* Run through this for loop and create 4 events */
+ for (i = 0; i < MAX_EVENTS; i++)
+ {
+ hEvent[i] = CreateEvent( lpEventAttributes,
+ bManualReset, bInitialState, NULL);
+
+ if (hEvent[i] == INVALID_HANDLE_VALUE)
+ {
+ Trace("WaitForMultipleObjectsTest:CreateEvent %u failed (%x)\n", i, GetLastError());
+ bRet = FALSE;
+ break;
+ }
+
+ /* Set the current event */
+ bRet = SetEvent(hEvent[i]);
+
+ if (!bRet)
+ {
+ Trace("WaitForMultipleObjectsTest:SetEvent %u failed (%x)\n", i, GetLastError());
+ bRet = FALSE;
+ break;
+ }
+
+ /* Ensure that this returns the correct value */
+ dwRet = WaitForSingleObject(hEvent[i],0);
+
+ if (dwRet != WAIT_OBJECT_0)
+ {
+ Trace("WaitForMultipleObjectsTest:WaitForSingleObject %u failed (%x)\n", i, GetLastError());
+ bRet = FALSE;
+ break;
+ }
+
+ /* Reset the event, and again ensure that the return value of
+ WaitForSingle is correct.
+ */
+ bRet = ResetEvent(hEvent[i]);
+
+ if (!bRet)
+ {
+ Trace("WaitForMultipleObjectsTest:ResetEvent %u failed (%x)\n", i, GetLastError());
+ bRet = FALSE;
+ break;
+ }
+
+ dwRet = WaitForSingleObject(hEvent[i],0);
+
+ if (dwRet != WAIT_TIMEOUT)
+ {
+ Trace("WaitForMultipleObjectsTest:WaitForSingleObject %u failed (%x)\n", i, GetLastError());
+ bRet = FALSE;
+ break;
+ }
+ }
+
+ /*
+ * If the first section of the test passed, move on to the
+ * second.
+ */
+
+ if (bRet)
+ {
+ BOOL bWaitAll = TRUE;
+ DWORD nCount = MAX_EVENTS;
+ CONST HANDLE *lpHandles = &hEvent[0];
+
+ /* Call WaitForMultipleOjbects on all the events, the return
+ should be WAIT_TIMEOUT
+ */
+ dwRet = WaitForMultipleObjects( nCount,
+ lpHandles,
+ bWaitAll,
+ 0);
+
+ if (dwRet != WAIT_TIMEOUT)
+ {
+ Trace("WaitForMultipleObjectsTest:WaitForMultipleObjects failed (%x)\n", GetLastError());
+ }
+ else
+ {
+ /* Step through each event and one at a time, set the
+ currect test, while reseting all the other tests
+ */
+
+ for (i = 0; i < MAX_EVENTS; i++)
+ {
+ for (j = 0; j < MAX_EVENTS; j++)
+ {
+ if (j == i)
+ {
+
+ bRet = SetEvent(hEvent[j]);
+
+ if (!bRet)
+ {
+ Trace("WaitForMultipleObjectsTest:SetEvent %u failed (%x)\n", j, GetLastError());
+ break;
+ }
+ }
+ else
+ {
+ bRet = ResetEvent(hEvent[j]);
+
+ if (!bRet)
+ {
+ Trace("WaitForMultipleObjectsTest:ResetEvent %u failed (%x)\n", j, GetLastError());
+ }
+ }
+ }
+
+ bWaitAll = FALSE;
+
+ /* Check that WaitFor returns WAIT_OBJECT + i */
+ dwRet = WaitForMultipleObjects( nCount,
+ lpHandles, bWaitAll, 0);
+
+ if (dwRet != WAIT_OBJECT_0+i)
+ {
+ Trace("WaitForMultipleObjectsTest:WaitForMultipleObjects failed (%x)\n", GetLastError());
+ bRet = FALSE;
+ break;
+ }
+ }
+ }
+
+ for (i = 0; i < MAX_EVENTS; i++)
+ {
+ bRet = CloseHandle(hEvent[i]);
+
+ if (!bRet)
+ {
+ Trace("WaitForMultipleObjectsTest:CloseHandle %u failed (%x)\n", i, GetLastError());
+ }
+ }
+ }
+
+ return bRet;
+}
+
+BOOL WaitMultipleDuplicateHandleTest()
+{
+ BOOL testResult = TRUE;
+ const HANDLE eventHandle = CreateEvent(NULL, TRUE, TRUE, NULL);
+ HANDLE eventHandles[] = {eventHandle, eventHandle};
+
+ // WaitAny - Wait for any of the events (no error expected)
+ DWORD result = WaitForMultipleObjects(sizeof(eventHandles) / sizeof(eventHandles[0]), eventHandles, FALSE, 0);
+ if (result != WAIT_OBJECT_0)
+ {
+ Trace("WaitMultipleDuplicateHandleTest:WaitAny failed (%x)\n", GetLastError());
+ testResult = FALSE;
+ }
+
+ // WaitAll - Wait for all of the events (error expected)
+ result = WaitForMultipleObjects(sizeof(eventHandles) / sizeof(eventHandles[0]), eventHandles, TRUE, 0);
+ if (result != WAIT_FAILED)
+ {
+ Trace("WaitMultipleDuplicateHandleTest:WaitAll failed: call unexpectedly succeeded\n");
+ testResult = FALSE;
+ }
+ else if (GetLastError() != ERROR_INVALID_PARAMETER)
+ {
+ Trace("WaitMultipleDuplicateHandleTest:WaitAll failed: unexpected last error (%x)\n");
+ testResult = FALSE;
+ }
+
+ return testResult;
+}
+
+int __cdecl main(int argc, char **argv)
+{
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return ( FAIL );
+ }
+
+ if(!WaitForMultipleObjectsTest())
+ {
+ Fail ("Test failed\n");
+ }
+
+ if (!WaitMultipleDuplicateHandleTest())
+ {
+ Fail("Test failed\n");
+ }
+
+ PAL_Terminate();
+ return ( PASS );
+
+}
diff --git a/src/pal/tests/palsuite/threading/WaitForMultipleObjects/test1/testinfo.dat b/src/pal/tests/palsuite/threading/WaitForMultipleObjects/test1/testinfo.dat
new file mode 100644
index 0000000000..38bd350d64
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/WaitForMultipleObjects/test1/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = WaitForMultipleObjects
+Name = Positive Test for WaitForMultipleObjects
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Test for WaitForMultipleObjects. Call the function
+= on an array of 4 events, and ensure that it returns correct
+= results when we do so.
diff --git a/src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/CMakeLists.txt b/src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/CMakeLists.txt
new file mode 100644
index 0000000000..7c20179353
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/CMakeLists.txt
@@ -0,0 +1,9 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(test2)
+add_subdirectory(test3)
+add_subdirectory(test4)
+add_subdirectory(test5)
+add_subdirectory(test6)
+
diff --git a/src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test1/CMakeLists.txt b/src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test1/CMakeLists.txt
new file mode 100644
index 0000000000..d035021bb9
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_waitformultipleobjectsex_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_waitformultipleobjectsex_test1 coreclrpal)
+
+target_link_libraries(paltest_waitformultipleobjectsex_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test1/test1.c b/src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test1/test1.c
new file mode 100644
index 0000000000..df3233fa50
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test1/test1.c
@@ -0,0 +1,226 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: test1.c
+**
+** Purpose: Test for WaitForMultipleObjectsEx. Call the function
+** on an array of 4 events, and ensure that it returns correct
+** results when we do so.
+**
+**
+**=========================================================*/
+
+#include <palsuite.h>
+
+/* Originally written as WaitForMultipleObjects/test1 */
+
+
+/* Number of events in array */
+#define MAX_EVENTS 4
+
+BOOL WaitForMultipleObjectsExTest()
+{
+ BOOL bRet = TRUE;
+ DWORD dwRet = 0;
+ DWORD i = 0, j = 0;
+
+ LPSECURITY_ATTRIBUTES lpEventAttributes = NULL;
+ BOOL bManualReset = TRUE;
+ BOOL bInitialState = TRUE;
+
+ HANDLE hEvent[MAX_EVENTS];
+
+ /* Run through this for loop and create 4 events */
+ for (i = 0; i < MAX_EVENTS; i++)
+ {
+ hEvent[i] = CreateEvent( lpEventAttributes,
+ bManualReset, bInitialState, NULL);
+
+ if (hEvent[i] == INVALID_HANDLE_VALUE)
+ {
+ Trace("WaitForMultipleObjectsExTest:CreateEvent %u failed (%x)\n", i, GetLastError());
+ bRet = FALSE;
+ break;
+ }
+
+ /* Set the current event */
+ bRet = SetEvent(hEvent[i]);
+
+ if (!bRet)
+ {
+ Trace("WaitForMultipleObjectsExTest:SetEvent %u failed (%x)\n", i, GetLastError());
+ bRet = FALSE;
+ break;
+ }
+
+ /* Ensure that this returns the correct value */
+ dwRet = WaitForSingleObject(hEvent[i],0);
+
+ if (dwRet != WAIT_OBJECT_0)
+ {
+ Trace("WaitForMultipleObjectsExTest:WaitForSingleObject %u failed (%x)\n", i, GetLastError());
+ bRet = FALSE;
+ break;
+ }
+
+ /* Reset the event, and again ensure that the return value of
+ WaitForSingle is correct.
+ */
+ bRet = ResetEvent(hEvent[i]);
+
+ if (!bRet)
+ {
+ Trace("WaitForMultipleObjectsExTest:ResetEvent %u failed (%x)\n", i, GetLastError());
+ bRet = FALSE;
+ break;
+ }
+
+ dwRet = WaitForSingleObject(hEvent[i],0);
+
+ if (dwRet != WAIT_TIMEOUT)
+ {
+ Trace("WaitForMultipleObjectsExTest:WaitForSingleObject %u failed (%x)\n", i, GetLastError());
+ bRet = FALSE;
+ break;
+ }
+ }
+
+ /*
+ * If the first section of the test passed, move on to the
+ * second.
+ */
+
+ if (bRet)
+ {
+ BOOL bWaitAll = TRUE;
+ DWORD nCount = MAX_EVENTS;
+ CONST HANDLE *lpHandles = &hEvent[0];
+
+ /* Call WaitForMultipleObjectsEx on all the events, the return
+ should be WAIT_TIMEOUT
+ */
+ dwRet = WaitForMultipleObjectsEx(nCount,
+ lpHandles,
+ bWaitAll,
+ 0,
+ FALSE);
+
+ if (dwRet != WAIT_TIMEOUT)
+ {
+ Trace("WaitForMultipleObjectsExTest: WaitForMultipleObjectsEx failed (%x)\n", GetLastError());
+ }
+ else
+ {
+ /* Step through each event and one at a time, set the
+ currect test, while reseting all the other tests
+ */
+
+ for (i = 0; i < MAX_EVENTS; i++)
+ {
+ for (j = 0; j < MAX_EVENTS; j++)
+ {
+ if (j == i)
+ {
+
+ bRet = SetEvent(hEvent[j]);
+
+ if (!bRet)
+ {
+ Trace("WaitForMultipleObjectsExTest:SetEvent %j failed (%x)\n", j, GetLastError());
+ break;
+ }
+ }
+ else
+ {
+ bRet = ResetEvent(hEvent[j]);
+
+ if (!bRet)
+ {
+ Trace("WaitForMultipleObjectsExTest:ResetEvent %u failed (%x)\n", j, GetLastError());
+ }
+ }
+ }
+
+ bWaitAll = FALSE;
+
+ /* Check that WaitFor returns WAIT_OBJECT + i */
+ dwRet = WaitForMultipleObjectsEx( nCount,
+ lpHandles, bWaitAll, 0, FALSE);
+
+ if (dwRet != WAIT_OBJECT_0+i)
+ {
+ Trace("WaitForMultipleObjectsExTest: WaitForMultipleObjectsEx failed (%x)\n", GetLastError());
+ bRet = FALSE;
+ break;
+ }
+ }
+ }
+
+ for (i = 0; i < MAX_EVENTS; i++)
+ {
+ bRet = CloseHandle(hEvent[i]);
+
+ if (!bRet)
+ {
+ Trace("WaitForMultipleObjectsExTest:CloseHandle %u failed (%x)\n", i, GetLastError());
+ }
+ }
+ }
+
+ return bRet;
+}
+
+BOOL WaitMultipleDuplicateHandleTest()
+{
+ BOOL testResult = TRUE;
+ const HANDLE eventHandle = CreateEvent(NULL, TRUE, TRUE, NULL);
+ HANDLE eventHandles[] = {eventHandle, eventHandle};
+
+ // WaitAny - Wait for any of the events (no error expected)
+ DWORD result = WaitForMultipleObjects(sizeof(eventHandles) / sizeof(eventHandles[0]), eventHandles, FALSE, 0);
+ if (result != WAIT_OBJECT_0)
+ {
+ Trace("WaitMultipleDuplicateHandleTest:WaitAny failed (%x)\n", GetLastError());
+ testResult = FALSE;
+ }
+
+ // WaitAll - Wait for all of the events (error expected)
+ result = WaitForMultipleObjects(sizeof(eventHandles) / sizeof(eventHandles[0]), eventHandles, TRUE, 0);
+ if (result != WAIT_FAILED)
+ {
+ Trace("WaitMultipleDuplicateHandleTest:WaitAll failed: call unexpectedly succeeded\n");
+ testResult = FALSE;
+ }
+ else if (GetLastError() != ERROR_INVALID_PARAMETER)
+ {
+ Trace("WaitMultipleDuplicateHandleTest:WaitAll failed: unexpected last error (%x)\n");
+ testResult = FALSE;
+ }
+
+ return testResult;
+}
+
+int __cdecl main(int argc, char **argv)
+{
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return ( FAIL );
+ }
+
+ if(!WaitForMultipleObjectsExTest())
+ {
+ Fail ("Test failed\n");
+ }
+
+ if (!WaitMultipleDuplicateHandleTest())
+ {
+ Fail("Test failed\n");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test1/testinfo.dat b/src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test1/testinfo.dat
new file mode 100644
index 0000000000..596c4bbf32
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test1/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = WaitForMultipleObjectsEx
+Name = Test #1 for WaitForMultipleObjectsEx
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Test for WaitForMultipleObjectsEx. Call the function
+= on an array of 4 events, and ensure that it returns correct
+= results when we do so.
diff --git a/src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test2/CMakeLists.txt b/src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test2/CMakeLists.txt
new file mode 100644
index 0000000000..ab47c6f2e7
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test2/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test2.c
+)
+
+add_executable(paltest_waitformultipleobjectsex_test2
+ ${SOURCES}
+)
+
+add_dependencies(paltest_waitformultipleobjectsex_test2 coreclrpal)
+
+target_link_libraries(paltest_waitformultipleobjectsex_test2
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test2/test2.c b/src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test2/test2.c
new file mode 100644
index 0000000000..b2bc301128
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test2/test2.c
@@ -0,0 +1,188 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test2.c
+**
+** Purpose: Tests that a child thread in the middle of a
+** WaitForMultipleObjectsEx call will be interrupted by QueueUserAPC
+** if the alert flag was set.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+/* Based on SleepEx/test2 */
+
+const unsigned int ChildThreadWaitTime = 1000;
+const unsigned int InterruptTime = 500;
+
+#define TOLERANCE 10
+
+void RunTest(BOOL AlertThread);
+VOID PALAPI APCFunc(ULONG_PTR dwParam);
+DWORD PALAPI WaiterProc(LPVOID lpParameter);
+
+DWORD ThreadWaitDelta;
+
+int __cdecl main( int argc, char **argv )
+{
+
+ DWORD delta = 0;
+
+ if (0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /*
+ On some platforms (e.g. FreeBSD 4.9) the first call to some synch objects
+ (such as conditions) involves some pthread internal initialization that
+ can make the first wait slighty longer, potentially going above the
+ acceptable delta for this test. Let's add a dummy wait to preinitialize
+ internal structures
+ */
+ Sleep(100);
+
+
+ /*
+ * Check that Queueing an APC in the middle of a wait does interrupt
+ * it, if it's in an alertable state.
+ */
+ RunTest(TRUE);
+ // Make sure that the wait returns in time greater than interrupt and less than
+ // wait timeout
+ if (
+ ((ThreadWaitDelta >= ChildThreadWaitTime) && (ThreadWaitDelta - ChildThreadWaitTime) > TOLERANCE)
+ || (( ThreadWaitDelta < InterruptTime) && (ThreadWaitDelta - InterruptTime) > TOLERANCE)
+ )
+ {
+ Fail("Expected thread to wait for %d ms (and get interrupted).\n"
+ "Interrupt Time: %d ms, ThreadWaitDelta %u\n",
+ ChildThreadWaitTime, InterruptTime, ThreadWaitDelta);
+ }
+
+ /*
+ * Check that Queueing an APC in the middle of a wait does NOT interrupt
+ * it, if it is not in an alertable state.
+ */
+ RunTest(FALSE);
+
+ // Make sure that time taken for thread to return from wait is more than interrupt
+ // and also not less than the complete child thread wait time
+
+ delta = ThreadWaitDelta - ChildThreadWaitTime;
+ if( (ThreadWaitDelta < ChildThreadWaitTime) && ( delta > TOLERANCE) )
+ {
+ Fail("Expected thread to wait for %d ms (and not get interrupted).\n"
+ "Interrupt Time: %d ms, ThreadWaitDelta %u\n",
+ ChildThreadWaitTime, InterruptTime, ThreadWaitDelta);
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+}
+
+void RunTest(BOOL AlertThread)
+{
+ HANDLE hThread = 0;
+ DWORD dwThreadId = 0;
+ int ret;
+
+ hThread = CreateThread( NULL,
+ 0,
+ (LPTHREAD_START_ROUTINE)WaiterProc,
+ (LPVOID) AlertThread,
+ 0,
+ &dwThreadId);
+
+ if (hThread == NULL)
+ {
+ Fail("ERROR: Was not able to create the thread to test!\n"
+ "GetLastError returned %d\n", GetLastError());
+ }
+
+ Sleep(InterruptTime);
+
+ ret = QueueUserAPC(APCFunc, hThread, 0);
+ if (ret == 0)
+ {
+ Fail("QueueUserAPC failed! GetLastError returned %d\n",
+ GetLastError());
+ }
+
+ ret = WaitForSingleObject(hThread, INFINITE);
+ if (ret == WAIT_FAILED)
+ {
+ Fail("Unable to wait on child thread!\nGetLastError returned %d.\n",
+ GetLastError());
+ }
+}
+
+/* Function doesn't do anything, just needed to interrupt the wait*/
+VOID PALAPI APCFunc(ULONG_PTR dwParam)
+{
+}
+
+/* Entry Point for child thread. */
+DWORD PALAPI WaiterProc(LPVOID lpParameter)
+{
+ HANDLE Semaphore;
+ UINT64 OldTimeStamp;
+ UINT64 NewTimeStamp;
+ BOOL Alertable;
+ DWORD ret;
+
+ /* Create a semaphore that is not in the signalled state */
+ Semaphore = CreateSemaphoreW(NULL, 0, 1, NULL);
+
+ if (Semaphore == NULL)
+ {
+ Fail("Failed to create semaphore! GetLastError returned %d.\n",
+ GetLastError());
+ }
+
+ Alertable = (BOOL) lpParameter;
+
+ LARGE_INTEGER performanceFrequency;
+ if (!QueryPerformanceFrequency(&performanceFrequency))
+ {
+ Fail("Failed to query performance frequency!");
+ }
+
+ OldTimeStamp = GetHighPrecisionTimeStamp(performanceFrequency);
+
+ ret = WaitForMultipleObjectsEx(1, &Semaphore, FALSE, ChildThreadWaitTime,
+ Alertable);
+
+ NewTimeStamp = GetHighPrecisionTimeStamp(performanceFrequency);
+
+
+ if (Alertable && ret != WAIT_IO_COMPLETION)
+ {
+ Fail("Expected the interrupted wait to return WAIT_IO_COMPLETION.\n"
+ "Got %d\n", ret);
+ }
+ else if (!Alertable && ret != WAIT_TIMEOUT)
+ {
+ Fail("WaitForMultipleObjectsEx did not timeout.\n"
+ "Expected return of WAIT_TIMEOUT, got %d.\n", ret);
+ }
+
+ ThreadWaitDelta = NewTimeStamp - OldTimeStamp;
+
+ ret = CloseHandle(Semaphore);
+ if (!ret)
+ {
+ Fail("Unable to close handle to semaphore!\n"
+ "GetLastError returned %d\n", GetLastError());
+ }
+
+ return 0;
+}
+
+
diff --git a/src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test2/testinfo.dat b/src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test2/testinfo.dat
new file mode 100644
index 0000000000..e8e781a7f2
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test2/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = WaitForMultipleObjectsEx
+Name = Test #2 for WaitForMultipleObjectsEx
+TYPE = DEFAULT
+EXE1 = test2
+Description
+=Tests that a child thread in the middle of a
+=WaitForMultipleObjectsEx call will be interrupted by QueueUserAPC
+=if the alert flag was set.
diff --git a/src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test3/CMakeLists.txt b/src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test3/CMakeLists.txt
new file mode 100644
index 0000000000..645b86719d
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test3/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test3.c
+)
+
+add_executable(paltest_waitformultipleobjectsex_test3
+ ${SOURCES}
+)
+
+add_dependencies(paltest_waitformultipleobjectsex_test3 coreclrpal)
+
+target_link_libraries(paltest_waitformultipleobjectsex_test3
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test3/test3.c b/src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test3/test3.c
new file mode 100644
index 0000000000..b78b0540dc
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test3/test3.c
@@ -0,0 +1,106 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test3.c
+**
+** Purpose: Tests that waiting on an open mutex will a return
+** WAIT_OBJECT_0. Does this by creating a child thread that
+** acquires the mutex, releases it, and exits.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+
+const int ChildThreadWaitTime = 1000;
+const int ParentDelayTime = 2000;
+
+DWORD PALAPI AcquiringProc(LPVOID lpParameter);
+
+int __cdecl main( int argc, char **argv)
+{
+ HANDLE Mutex;
+ HANDLE hThread = 0;
+ DWORD dwThreadId = 0;
+ int ret;
+
+ if (0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ Mutex = CreateMutexW(NULL, FALSE, NULL);
+ if (Mutex == NULL)
+ {
+ Fail("Unable to create the mutex. GetLastError returned %d\n",
+ GetLastError());
+ }
+
+ hThread = CreateThread( NULL,
+ 0,
+ (LPTHREAD_START_ROUTINE)AcquiringProc,
+ (LPVOID) Mutex,
+ 0,
+ &dwThreadId);
+
+ if (hThread == NULL)
+ {
+ Fail("ERROR: Was not able to create the thread to test!\n"
+ "GetLastError returned %d\n", GetLastError());
+ }
+
+ Sleep(ParentDelayTime);
+
+ ret = WaitForMultipleObjectsEx(1, &Mutex, FALSE, INFINITE, FALSE);
+ if (ret != WAIT_OBJECT_0)
+ {
+ Fail("Expected WaitForMultipleObjectsEx to return WAIT_OBJECT_0\n"
+ "Got %d\n", ret);
+ }
+
+ if (!CloseHandle(Mutex))
+ {
+ Fail("CloseHandle on the mutex failed!\n");
+ }
+
+ if (!CloseHandle(hThread))
+ {
+ Fail("CloseHandle on the thread failed!\n");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
+/*
+ * Entry Point for child thread. Acquries a mutex, releases it, and exits.
+ */
+DWORD PALAPI AcquiringProc(LPVOID lpParameter)
+{
+ HANDLE Mutex;
+ DWORD ret;
+
+ Mutex = (HANDLE) lpParameter;
+
+ Sleep(ChildThreadWaitTime);
+
+ ret = WaitForSingleObject(Mutex, 0);
+ if (ret != WAIT_OBJECT_0)
+ {
+ Fail("Expected the WaitForSingleObject call on the mutex to succeed\n"
+ "Expected return of WAIT_OBJECT_0, got %d\n", ret);
+ }
+
+ ret = ReleaseMutex(Mutex);
+ if (!ret)
+ {
+ Fail("Unable to release mutex! GetLastError returned %d\n",
+ GetLastError());
+ }
+
+ return 0;
+}
diff --git a/src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test3/testinfo.dat b/src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test3/testinfo.dat
new file mode 100644
index 0000000000..991b93489d
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test3/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = WaitForMultipleObjectsEx
+Name = Test #3 for WaitForMultipleObjectsEx
+TYPE = DEFAULT
+EXE1 = test3
+Description
+=Tests that waiting on an open mutex will a return
+=WAIT_OBJECT_0. Does this by creating a child thread that
+=acquires the mutex, releases it, and exits.
diff --git a/src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test4/CMakeLists.txt b/src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test4/CMakeLists.txt
new file mode 100644
index 0000000000..3cd7f72b98
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test4/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test4.c
+)
+
+add_executable(paltest_waitformultipleobjectsex_test4
+ ${SOURCES}
+)
+
+add_dependencies(paltest_waitformultipleobjectsex_test4 coreclrpal)
+
+target_link_libraries(paltest_waitformultipleobjectsex_test4
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test4/test4.c b/src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test4/test4.c
new file mode 100644
index 0000000000..15d0a386d1
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test4/test4.c
@@ -0,0 +1,101 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: test4.c
+**
+** Purpose: Tests that waiting on an abandonded mutex will a return
+** WAIT_ABANDONED_0. Does this by creating a child thread that
+** acquires the mutex and exits.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+
+const int ChildThreadWaitTime = 1000;
+const int ParentDelayTime = 2000;
+
+DWORD PALAPI AbandoningProc(LPVOID lpParameter);
+
+int __cdecl main( int argc, char **argv )
+{
+ HANDLE Mutex;
+ HANDLE hThread = 0;
+ DWORD dwThreadId = 0;
+ int ret;
+
+ if (0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ Mutex = CreateMutexW(NULL, FALSE, NULL);
+ if (Mutex == NULL)
+ {
+ Fail("Unable to create the mutex. GetLastError returned %d\n",
+ GetLastError());
+ }
+
+ hThread = CreateThread( NULL,
+ 0,
+ (LPTHREAD_START_ROUTINE)AbandoningProc,
+ (LPVOID) Mutex,
+ 0,
+ &dwThreadId);
+
+ if (hThread == NULL)
+ {
+ Fail("ERROR: Was not able to create the thread to test!\n"
+ "GetLastError returned %d\n", GetLastError());
+ }
+
+ Sleep(ParentDelayTime);
+
+ ret = WaitForMultipleObjectsEx(1, &Mutex, FALSE, INFINITE, FALSE);
+ if (ret != WAIT_ABANDONED_0)
+ {
+ Fail("Expected WaitForMultipleObjectsEx to return WAIT_ABANDONED_0\n"
+ "Got %d\n", ret);
+ }
+
+ ReleaseMutex(Mutex);
+ if (!CloseHandle(Mutex))
+ {
+ Fail("CloseHandle on the mutex failed!\n");
+ }
+
+ if (!CloseHandle(hThread))
+ {
+ Fail("CloseHandle on the thread failed!\n");
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
+/*
+ * Entry Point for child thread. Acquries a mutex and exit's without
+ * releasing it.
+ */
+DWORD PALAPI AbandoningProc(LPVOID lpParameter)
+{
+ HANDLE Mutex;
+ DWORD ret;
+
+ Mutex = (HANDLE) lpParameter;
+
+ Sleep(ChildThreadWaitTime);
+
+ ret = WaitForSingleObject(Mutex, 0);
+ if (ret != WAIT_OBJECT_0)
+ {
+ Fail("Expected the WaitForSingleObject call on the mutex to succeed\n"
+ "Expected return of WAIT_OBJECT_0, got %d\n", ret);
+ }
+
+ return 0;
+}
diff --git a/src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test4/testinfo.dat b/src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test4/testinfo.dat
new file mode 100644
index 0000000000..16f3468ac2
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test4/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = WaitForMultipleObjectsEx
+Name = Test #4 for WaitForMultipleObjectsEx
+TYPE = DEFAULT
+EXE1 = test4
+Description
+=Tests that waiting on an abandonded mutex will a return
+=WAIT_ABANDONED_0. Does this by creating a child thread that
+=acquires the mutex and exits.
diff --git a/src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test5/CMakeLists.txt b/src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test5/CMakeLists.txt
new file mode 100644
index 0000000000..50147e9bf3
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test5/CMakeLists.txt
@@ -0,0 +1,36 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(TESTSOURCES
+ test5.c
+)
+
+add_executable(paltest_waitformultipleobjectsex_test5
+ ${TESTSOURCES}
+)
+
+add_dependencies(paltest_waitformultipleobjectsex_test5 coreclrpal)
+
+target_link_libraries(paltest_waitformultipleobjectsex_test5
+ pthread
+ m
+ coreclrpal
+)
+
+
+set(HELPERSOURCES
+ helper.c
+)
+
+add_executable(paltest_waitformultipleobjectsex_test5_helper
+ ${HELPERSOURCES}
+)
+
+add_dependencies(paltest_waitformultipleobjectsex_test5_helper coreclrpal)
+
+target_link_libraries(paltest_waitformultipleobjectsex_test5_helper
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test5/commonconsts.h b/src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test5/commonconsts.h
new file mode 100644
index 0000000000..b746616b58
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test5/commonconsts.h
@@ -0,0 +1,42 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: commonconsts.h
+**
+**
+**============================================================*/
+
+#ifndef _COMMONCONSTS_H_
+#define _COMMONCONSTS_H_
+
+#include <pal.h>
+
+const int TIMEOUT = 60 * 5 * 1000;
+
+char *szcHelperProcessStartEvName = "start";
+char *szcHelperProcessReadyEvName = "ready";
+char *szcHelperProcessFinishEvName = "finish";
+
+/* PEDANTIC and PEDANTIC0 is a helper macro that just grumps about any
+ * zero return codes in a generic way. with little typing */
+#define PEDANTIC(function, parameters) \
+{ \
+ if (! (function parameters) ) \
+ { \
+ Trace("%s: NonFatal failure of %s%s for reasons %u and %u\n", \
+ __FILE__, #function, #parameters, GetLastError(), errno); \
+ } \
+}
+#define PEDANTIC1(function, parameters) \
+{ \
+ if ( (function parameters) ) \
+ { \
+ Trace("%s: NonFatal failure of %s%s for reasons %u and %u\n", \
+ __FILE__, #function, #parameters, GetLastError(), errno); \
+ } \
+}
+
+#endif
diff --git a/src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test5/helper.c b/src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test5/helper.c
new file mode 100644
index 0000000000..274780a216
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test5/helper.c
@@ -0,0 +1,122 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: helper.c
+**
+** Purpose: This helper process sets up signals to communicate
+** with the test thread in the parent process, and let the test
+** thread signal this process when to exit.
+**
+**
+**============================================================*/
+
+#include "commonconsts.h"
+
+#include <palsuite.h>
+
+HANDLE hProcessStartEvent;
+HANDLE hProcessReadyEvent;
+HANDLE hProcessFinishEvent;
+HANDLE hProcessCleanupEvent;
+
+
+int __cdecl main(int argc, char *argv[])
+{
+
+ BOOL success = TRUE; /* assume success */
+ DWORD dwRet;
+ DWORD dwProcessId;
+ char szEventName[MAX_LONGPATH];
+ PWCHAR uniString;
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /* Open the event to let test thread tell us to get started. */
+ uniString = convert(szcHelperProcessStartEvName);
+ hProcessStartEvent = OpenEventW(EVENT_ALL_ACCESS, 0, uniString);
+ free(uniString);
+ if (!hProcessStartEvent)
+ {
+ Fail("helper.main: OpenEvent of '%S' failed (%u). "
+ "(the event should already exist!)\n",
+ szcHelperProcessStartEvName, GetLastError());
+ }
+
+ /* Wait for signal from test thread. */
+ dwRet = WaitForSingleObject(hProcessStartEvent, TIMEOUT);
+ if (dwRet != WAIT_OBJECT_0)
+ {
+ Fail("helper.main: WaitForSingleObject '%s' failed\n"
+ "LastError:(%u)\n", szcHelperProcessStartEvName, GetLastError());
+ }
+
+ dwProcessId = GetCurrentProcessId();
+
+ if ( 0 >= dwProcessId )
+ {
+ Fail ("helper.main: %s has invalid pid %d\n", argv[0], dwProcessId );
+ }
+
+ /* Open the event to tell test thread we are ready. */
+ if (_snprintf(szEventName, MAX_LONGPATH-1, "%s%d", szcHelperProcessReadyEvName, dwProcessId) < 0)
+ {
+ Fail ("helper.main: Insufficient event name string length for pid=%d\n", dwProcessId);
+ }
+
+ uniString = convert(szEventName);
+
+ hProcessReadyEvent = OpenEventW(EVENT_ALL_ACCESS, 0, uniString);
+ free(uniString);
+ if (!hProcessReadyEvent)
+ {
+ Fail("helper.main: OpenEvent of '%s' failed (%u). "
+ "(the event should already exist!)\n",
+ szEventName, GetLastError());
+ }
+
+ /* Open the event to let test thread tell us to exit. */
+ if (_snprintf(szEventName, MAX_LONGPATH-1, "%s%d", szcHelperProcessFinishEvName, dwProcessId) < 0)
+ {
+ Fail ("helper.main: Insufficient event name string length for pid=%d\n", dwProcessId);
+ }
+
+ uniString = convert(szEventName);
+
+ hProcessFinishEvent = OpenEventW(EVENT_ALL_ACCESS, 0, uniString);
+ free(uniString);
+ if (!hProcessFinishEvent)
+ {
+ Fail("helper.main: OpenEvent of '%s' failed LastError:(%u).\n",
+ szEventName, GetLastError());
+ }
+
+ /* Tell the test thread we are ready. */
+ if (!SetEvent(hProcessReadyEvent))
+ {
+ Fail("helper.main: SetEvent '%s' failed LastError:(%u)\n",
+ hProcessReadyEvent, GetLastError());
+ }
+
+ /* Wait for signal from test thread before exit. */
+ dwRet = WaitForSingleObject(hProcessFinishEvent, TIMEOUT);
+ if (WAIT_OBJECT_0 != dwRet)
+ {
+ Fail("helper.main: WaitForSingleObject '%s' failed pid=%d\n"
+ "LastError:(%u)\n",
+ szcHelperProcessFinishEvName, dwProcessId, GetLastError());
+ }
+
+ PEDANTIC(CloseHandle, (hProcessStartEvent));
+ PEDANTIC(CloseHandle, (hProcessReadyEvent));
+ PEDANTIC(CloseHandle, (hProcessFinishEvent));
+
+ PAL_Terminate();
+
+ return success ? PASS : FAIL;
+}
diff --git a/src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test5/test5.c b/src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test5/test5.c
new file mode 100644
index 0000000000..d19978c103
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test5/test5.c
@@ -0,0 +1,506 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================
+**
+** Source: test5.c
+**
+** Purpose: Test the functionality of simultaneously waiting
+** on multiple processes. Create the same number of helper
+** processes and helper threads.
+** Helper threads wait on helper processes to finish.
+** Helper processes wait on the event signal from test
+** thread before exit.
+** The test thread can wake up one helper
+** thread at a time by signaling the corresponding helper
+** process to finish.
+** The test thread can also wake up all helper threads at once
+** by signaling help process 0 to exit.
+**
+**
+**============================================================*/
+
+#define UNICODE
+
+#include "commonconsts.h"
+
+#include <palsuite.h>
+
+/* The maximum number of objects a thread can wait is MAXIMUM_WAIT_OBJECTS.
+ The last helper thread in this test case will wait on all helper processes
+ plus a thread finish event so the maximum number of helper processes
+ can be created in this test case is (MAXIMUM_WAIT_OBJECTS-1). */
+#define MAX_HELPER_PROCESS (MAXIMUM_WAIT_OBJECTS-1)
+
+int MaxNumHelperProcess = MAX_HELPER_PROCESS;
+
+/* indicate how the test thread wake up helper thread. */
+typedef enum _TestCaseType {
+ WakeUpOneThread, /* wake up one helper thread at a time. */
+ WakeUpAllThread /* wake up all helper threads at once */
+} TestCaseType;
+
+TestCaseType TestCase = WakeUpOneThread;
+
+/* When the test thread wakes up one thread at a time,
+ ThreadIndexOfThreadFinishEvent specifies the index of the thread that
+ should be waked up using hThreadFinishEvent instead of helper process. */
+DWORD ThreadIndexOfThreadFinishEvent = 0;
+
+struct helper_process_t
+{
+ PROCESS_INFORMATION pi;
+ HANDLE hProcessReadyEvent;
+ HANDLE hProcessFinishEvent;
+} helper_process[MAX_HELPER_PROCESS];
+
+HANDLE hProcessStartEvent;
+
+struct helper_thread_t
+{
+ HANDLE hThread;
+ DWORD dwThreadId;
+ HANDLE hThreadReadyEvent;
+ HANDLE hThreadFinishEvent;
+} helper_thread[MAX_HELPER_PROCESS];
+
+/*
+ * Entry Point for helper thread.
+ */
+DWORD PALAPI WaitForProcess(LPVOID lpParameter)
+{
+ DWORD index, i;
+ DWORD dwRet;
+ HANDLE handles[MAX_HELPER_PROCESS+1];
+
+ index = (DWORD) lpParameter;
+
+ /* The helper thread 0 will wait for helper process 0, helper thread 1 will
+ wait for helper process 0 and 1, helper thread 2 will wait for helper
+ process 0, 1, and 2, and so on ..., and the last helper thread will wait
+ on all helper processes.
+ Each helper thread also waits on hThreadFinishEvent so that
+ it can exit without waiting on any process to finish. */
+
+ for (i = 0; i <= index; i++)
+ {
+ handles[i] = helper_process[i].pi.hProcess;
+ }
+
+ handles[index+1] = helper_thread[index].hThreadFinishEvent;
+
+ if(!SetEvent(helper_thread[index].hThreadReadyEvent))
+ {
+ Fail("test5.WaitProcess: SetEvent of hThreadReadyEvent failed for thread %d. "
+ "GetLastError() returned %d.\n", index,
+ GetLastError());
+ }
+
+ dwRet = WaitForMultipleObjectsEx(index+2, &handles[0], FALSE, TIMEOUT, TRUE);
+ if (WakeUpAllThread == TestCase)
+ {
+ /* If the test thread signals helper process 0 to exit, all threads will be waked up,
+ and the return value must be (WAIT_OBJECT_0+0) because the handle of helper process 0
+ is in handle[0]. */
+ if (dwRet != (WAIT_OBJECT_0+0))
+ {
+ Fail("test5.WaitForProcess: invalid return value %d for WakupAllThread from WaitForMultipleObjectsEx for thread %d\n"
+ "LastError:(%u)\n",
+ dwRet, index,
+ GetLastError());
+ }
+ }
+ else if (WakeUpOneThread == TestCase)
+ {
+ /* If the test thread wakes up one helper thread at a time,
+ the return value must be either (WAIT_OBJECT_0+index) if the helper thread
+ wakes up because the corresponding help process exits,
+ or (index+1) if the helper thread wakes up because of hThreadReadyEvent. */
+ if ((index != ThreadIndexOfThreadFinishEvent && dwRet != (WAIT_OBJECT_0+index)) ||
+ (index == ThreadIndexOfThreadFinishEvent && dwRet != (index+1)))
+ {
+ Fail("test5.WaitForProcess: invalid return value %d for WakupOneThread from WaitForMultipleObjectsEx for thread %d\n"
+ "LastError:(%u)\n",
+ dwRet, index,
+ GetLastError());
+ }
+ }
+ else
+ {
+ Fail("Unknown TestCase %d\n", TestCase);
+ }
+ return 0;
+}
+
+/*
+ * Setup the helper processes and helper threads.
+ */
+void
+Setup()
+{
+
+ STARTUPINFO si;
+ DWORD dwRet;
+ int i;
+
+ char szEventName[MAX_PATH];
+ PWCHAR uniStringHelper;
+ PWCHAR uniString;
+
+ /* Create the event to start helper process after it was created. */
+ uniString = convert(szcHelperProcessStartEvName);
+ hProcessStartEvent = CreateEvent(NULL, TRUE, FALSE, uniString);
+ free(uniString);
+ if (!hProcessStartEvent)
+ {
+ Fail("test5.Setup: CreateEvent of '%s' failed. "
+ "GetLastError() returned %d.\n", szcHelperProcessStartEvName,
+ GetLastError());
+ }
+
+ /* Create the helper processes. */
+ ZeroMemory( &si, sizeof(si) );
+ si.cb = sizeof(si);
+ uniStringHelper = convert("helper");
+ for (i = 0; i < MaxNumHelperProcess; i++)
+ {
+ ZeroMemory( &helper_process[i].pi, sizeof(PROCESS_INFORMATION));
+
+ if(!CreateProcess( NULL, uniStringHelper, NULL, NULL,
+ FALSE, 0, NULL, NULL, &si, &helper_process[i].pi))
+ {
+ Fail("test5.Setup: CreateProcess failed to load executable for helper process %d. "
+ "GetLastError() returned %u.\n",
+ i, GetLastError());
+ }
+
+ /* Create the event to let helper process tell us it is ready. */
+ if (_snprintf(szEventName, MAX_PATH-1, "%s%d",
+ szcHelperProcessReadyEvName, helper_process[i].pi.dwProcessId) < 0)
+ {
+ Fail ("test5.Setup: Insufficient event name string length for %s\n", szcHelperProcessReadyEvName);
+ }
+
+ uniString = convert(szEventName);
+
+ helper_process[i].hProcessReadyEvent = CreateEvent(NULL, FALSE, FALSE, uniString);
+ free(uniString);
+ if (!helper_process[i].hProcessReadyEvent)
+ {
+ Fail("test5.Setup: CreateEvent of '%s' failed. "
+ "GetLastError() returned %d.\n", szEventName,
+ GetLastError());
+ }
+
+ /* Create the event to tell helper process to exit. */
+ if (_snprintf(szEventName, MAX_PATH-1, "%s%d",
+ szcHelperProcessFinishEvName, helper_process[i].pi.dwProcessId) < 0)
+ {
+ Fail ("test5.Setup: Insufficient event name string length for %s\n", szcHelperProcessFinishEvName);
+ }
+
+ uniString = convert(szEventName);
+
+ helper_process[i].hProcessFinishEvent = CreateEvent(NULL, TRUE, FALSE, uniString);
+ free(uniString);
+ if (!helper_process[i].hProcessFinishEvent)
+ {
+ Fail("test5.Setup: CreateEvent of '%s' failed. "
+ "GetLastError() returned %d.\n", szEventName,
+ GetLastError());
+ }
+
+ }
+ free(uniStringHelper);
+
+ /* Signal all helper processes to start. */
+ if (!SetEvent(hProcessStartEvent))
+ {
+ Fail("test5.Setup: SetEvent '%s' failed\n",
+ "LastError:(%u)\n",
+ szcHelperProcessStartEvName, GetLastError());
+ }
+
+ /* Wait for ready signals from all helper processes. */
+ for (i = 0; i < MaxNumHelperProcess; i++)
+ {
+ dwRet = WaitForSingleObject(helper_process[i].hProcessReadyEvent, TIMEOUT);
+ if (dwRet != WAIT_OBJECT_0)
+ {
+ Fail("test5.Setup: WaitForSingleObject %s failed for helper process %d\n"
+ "LastError:(%u)\n",
+ szcHelperProcessReadyEvName, i, GetLastError());
+ }
+ }
+
+ /* Create the same number of helper threads as helper processes. */
+ for (i = 0; i < MaxNumHelperProcess; i++)
+ {
+ /* Create the event to let helper thread tell us it is ready. */
+ helper_thread[i].hThreadReadyEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+ if (!helper_thread[i].hThreadReadyEvent)
+ {
+ Fail("test5.Setup: CreateEvent of hThreadReadyEvent failed for thread %d\n"
+ "LastError:(%u)\n", i, GetLastError());
+ }
+
+ /* Create the event to tell helper thread to exit without waiting for helper process. */
+ helper_thread[i].hThreadFinishEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+ if (!helper_thread[i].hThreadFinishEvent)
+ {
+ Fail("test5.Setup: CreateEvent of hThreadFinishEvent failed for thread %d\n"
+ "LastError:(%u)\n", i, GetLastError());
+ }
+
+ /* Create the helper thread. */
+ helper_thread[i].hThread = CreateThread( NULL,
+ 0,
+ (LPTHREAD_START_ROUTINE)WaitForProcess,
+ (LPVOID)i,
+ 0,
+ &helper_thread[i].dwThreadId);
+ if (NULL == helper_thread[i].hThread)
+ {
+ Fail("test5.Setup: Unable to create the helper thread %d\n"
+ "LastError:(%u)\n", i, GetLastError());
+ }
+ }
+
+ /* Wait for ready signals from all helper threads. */
+ for (i = 0; i < MaxNumHelperProcess; i++)
+ {
+ dwRet = WaitForSingleObject(helper_thread[i].hThreadReadyEvent, TIMEOUT);
+ if (dwRet != WAIT_OBJECT_0)
+ {
+ Fail("test5.Setup: WaitForSingleObject hThreadReadyEvent for thread %d\n"
+ "LastError:(%u)\n", i, GetLastError());
+ }
+ }
+}
+
+/*
+ * Cleanup the helper processes and helper threads.
+ */
+DWORD
+Cleanup()
+{
+ DWORD dwExitCode;
+ DWORD dwRet;
+ int i;
+
+ /* Wait for all helper process to finish and close their handles
+ and associated events. */
+ for (i = 0; i < MaxNumHelperProcess; i++)
+ {
+
+ /* wait for the child process to complete */
+ dwRet = WaitForSingleObject ( helper_process[i].pi.hProcess, TIMEOUT );
+ if (WAIT_OBJECT_0 != dwRet)
+ {
+ Fail("test5.Cleanup: WaitForSingleObject hThreadReadyEvent failed for thread %d\n"
+ "LastError:(%u)\n", i, GetLastError());
+ }
+
+ /* check the exit code from the process */
+ if (!GetExitCodeProcess(helper_process[i].pi.hProcess, &dwExitCode))
+ {
+ Trace( "test5.Cleanup: GetExitCodeProcess %d call failed LastError:(%u)\n",
+ i, GetLastError());
+ dwExitCode = FAIL;
+ }
+ PEDANTIC(CloseHandle, (helper_process[i].pi.hThread));
+ PEDANTIC(CloseHandle, (helper_process[i].pi.hProcess));
+ PEDANTIC(CloseHandle, (helper_process[i].hProcessReadyEvent));
+ PEDANTIC(CloseHandle, (helper_process[i].hProcessFinishEvent));
+ }
+
+ /* Close all helper threads' handles */
+ for (i = 0; i < MaxNumHelperProcess; i++)
+ {
+ PEDANTIC(CloseHandle, (helper_thread[i].hThread));
+ PEDANTIC(CloseHandle, (helper_thread[i].hThreadReadyEvent));
+ PEDANTIC(CloseHandle, (helper_thread[i].hThreadFinishEvent));
+ }
+
+ /* Close all process start event. */
+ PEDANTIC(CloseHandle, (hProcessStartEvent));
+
+ return dwExitCode;
+}
+
+/*
+ * In this test case, the test thread will signal one helper
+ * process to exit at a time starting from the last helper
+ * process and then wait for the corresponding helper thread to exit.
+ * The ThreadIndexOfThreadFinishEvent specifies the index of the thread that
+ * should be waked up using hThreadFinishEvent instead of helper process.
+ */
+void
+TestWakeupOneThread()
+{
+ DWORD dwRet;
+ int i;
+
+ TestCase = WakeUpOneThread;
+
+ if (((LONG)ThreadIndexOfThreadFinishEvent) < 0 ||
+ ThreadIndexOfThreadFinishEvent >= MAX_HELPER_PROCESS)
+ Fail("test5.TestWaitOnOneThread: Invalid ThreadIndexOfThreadFinishEvent %d\n", ThreadIndexOfThreadFinishEvent);
+
+ /* Since helper thread 0 waits on helper process 0,
+ thread 1 waits on on process 0, and 1,
+ thread 2 waits on process 0, 1, and 2, and so on ...,
+ and the last helper thread will wait on all helper processes,
+ the helper thread can be waked up one at a time by
+ waking up the help process one at a time starting from the
+ last helper process. */
+ for (i = MaxNumHelperProcess-1; i >= 0; i--)
+ {
+ /* make sure the helper thread has not exited yet. */
+ dwRet = WaitForSingleObject(helper_thread[i].hThread, 0);
+ if (WAIT_TIMEOUT != dwRet)
+ {
+ Fail("test5.TestWaitOnOneThread: helper thread %d already exited %d\n", i);
+ }
+
+ /* Decide how to wakeup the helper thread:
+ using event or using helper process. */
+ if (i == ThreadIndexOfThreadFinishEvent)
+ {
+ if (!SetEvent(helper_thread[i].hThreadFinishEvent))
+ {
+ Fail("test5.TestWaitOnOneThread: SetEvent hThreadFinishEvent failed for thread %d\n",
+ "LastError:(%u)\n", i, GetLastError());
+ }
+ }
+ else
+ {
+ if (!SetEvent(helper_process[i].hProcessFinishEvent))
+ {
+ Fail("test5.TestWaitOnOneThread: SetEvent %s%d failed for helper process %d\n",
+ "LastError:(%u)\n",
+ szcHelperProcessFinishEvName, helper_process[i].pi.dwProcessId, i,
+ GetLastError());
+ }
+ }
+
+ dwRet = WaitForSingleObject(helper_thread[i].hThread, TIMEOUT);
+ if (WAIT_OBJECT_0 != dwRet)
+ {
+ Fail("test5.TestWaitOnOneThread: WaitForSingleObject helper thread %d"
+ "LastError:(%u)\n",
+ i, GetLastError());
+ }
+ }
+
+ /* Finally, need to wake up the helper process which the test thread
+ skips waking up in the last loop. */
+ if (!SetEvent(helper_process[ThreadIndexOfThreadFinishEvent].hProcessFinishEvent))
+ {
+ Fail("test5.TestWaitOnOneThread: SetEvent %s%d failed\n",
+ "LastError:(%u)\n",
+ szcHelperProcessFinishEvName, helper_process[ThreadIndexOfThreadFinishEvent].pi.dwProcessId,
+ GetLastError());
+ }
+}
+
+/*
+ * In this test case, the test thread will signal the helper
+ * process 0 to exit. Since all helper threads wait on process 0,
+ * all helper threads will wake up and exit, and the test thread
+ * will wait for all of them to exit.
+ */
+void
+TestWakeupAllThread()
+{
+ DWORD dwRet;
+ int i;
+
+ TestCase = WakeUpAllThread;
+
+ /* make sure none of the helper thread exits. */
+ for (i = 0; i < MaxNumHelperProcess; i++)
+ {
+ dwRet = WaitForSingleObject(helper_thread[i].hThread, 0);
+ if (WAIT_TIMEOUT != dwRet)
+ {
+ Fail("test5.TestWaitOnAllThread: helper thread %d already exited %d\n", i);
+ }
+ }
+
+ /* Signal helper process 0 to exit. */
+ if (!SetEvent(helper_process[0].hProcessFinishEvent))
+ {
+ Fail("test5.TestWaitOnAllThread: SetEvent %s%d failed\n",
+ "LastError:(%u)\n",
+ szcHelperProcessFinishEvName, helper_process[0].pi.dwProcessId,
+ GetLastError());
+ }
+
+ /* Wait for all helper threads to exit. */
+ for (i = 0; i < MaxNumHelperProcess; i++)
+ {
+
+ dwRet = WaitForSingleObject(helper_thread[i].hThread, TIMEOUT);
+ if (WAIT_OBJECT_0 != dwRet)
+ {
+ Fail("test5.TestWaitOnAllThread: WaitForSingleObject failed for helper thread %d\n"
+ "LastError:(%u)\n",
+ i, GetLastError());
+ }
+ }
+
+ /* Signal the rest of helper processes to exit. */
+ for (i = 1; i < MaxNumHelperProcess; i++)
+ {
+ if (!SetEvent(helper_process[i].hProcessFinishEvent))
+ {
+ Fail("test5.TestWaitOnAllThread: SetEvent %s%d failed\n",
+ "LastError:(%u)\n",
+ szcHelperProcessFinishEvName, helper_process[i].pi.dwProcessId,
+ GetLastError());
+ }
+ }
+}
+
+int __cdecl main(int argc, char *argv[])
+{
+ DWORD dwExitCode;
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ switch (argc)
+ {
+ case 1:
+ MaxNumHelperProcess = MAX_HELPER_PROCESS;
+ break;
+ case 2:
+ MaxNumHelperProcess = atol(argv[1]);
+ break;
+ default:
+ Fail("Invalid number of arguments\n");
+ }
+
+ if (MaxNumHelperProcess < 1 ||
+ MaxNumHelperProcess > MAX_HELPER_PROCESS)
+ Fail("test5.main: Invalid MaxNumHelperProcess %d\n", MaxNumHelperProcess);
+
+ Setup();
+ ThreadIndexOfThreadFinishEvent = 3;
+ TestWakeupOneThread();
+ dwExitCode = Cleanup();
+
+ if (PASS == dwExitCode)
+ {
+ Setup();
+ TestWakeupAllThread();
+ dwExitCode = Cleanup();
+ }
+
+ PAL_TerminateEx(dwExitCode);
+ return dwExitCode;
+}
diff --git a/src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test5/testinfo.dat b/src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test5/testinfo.dat
new file mode 100644
index 0000000000..5efc75f77e
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test5/testinfo.dat
@@ -0,0 +1,18 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = WaitForMultipleObjectsEx
+Name = Check simultaneously waiting on multiple processes.
+TYPE = DEFAULT
+EXE1 = test5
+EXE2 = helper
+Description
+= Create a number of helper processes and helper threads.
+= Helper threads wait on helper processes to finish.
+= Helper processes wait on the event signal from test
+= thread before exit. The test thread then selectively
+= signals helper process to finish and then wait on the
+= selected helper thread to finish.
diff --git a/src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test6/CMakeLists.txt b/src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test6/CMakeLists.txt
new file mode 100644
index 0000000000..ce75cadbff
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test6/CMakeLists.txt
@@ -0,0 +1,36 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(TESTSOURCES
+ test6.c
+)
+
+add_executable(paltest_waitformultipleobjectsex_test6
+ ${TESTSOURCES}
+)
+
+add_dependencies(paltest_waitformultipleobjectsex_test6 coreclrpal)
+
+target_link_libraries(paltest_waitformultipleobjectsex_test6
+ pthread
+ m
+ coreclrpal
+)
+
+
+set(HELPERSOURCES
+ child6.c
+)
+
+add_executable(paltest_waitformultipleobjectsex_test6_child
+ ${HELPERSOURCES}
+)
+
+add_dependencies(paltest_waitformultipleobjectsex_test6_child coreclrpal)
+
+target_link_libraries(paltest_waitformultipleobjectsex_test6_child
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test6/child6.c b/src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test6/child6.c
new file mode 100644
index 0000000000..1a95815ddf
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test6/child6.c
@@ -0,0 +1,211 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: child6.c
+**
+** Purpose: Test for WaitForMultipleObjectsEx in multiple
+** scenarios - child process
+**
+**
+**=========================================================*/
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char **argv)
+{
+ int i, iRet;
+ BOOL bRet;
+ BOOL bNamedEvent = 0;
+ BOOL bMutex = 0;
+ BOOL bMutexAndNamedEvent = 0;
+ BOOL bSemaphore = 0;
+ DWORD dwRet;
+ HANDLE hNamedEvent;
+ HANDLE hMutex;
+ char szTestName[256];
+ WCHAR wszTestName[256] = { 0 };
+ char szEventName[128] = { 0 };
+ char szMutexName[128] = { 0 };
+ char szSemName[128] = { 0 };
+ WCHAR wszEventName[128];
+ WCHAR wszMutexName[128];
+ WCHAR wszSemName[128];
+ DWORD iExitCode = 0;
+ HANDLE hSemaphore;
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return ( FAIL );
+ }
+
+ Trace("[child] Starting\n");
+
+ for (i=1; i<argc; i++)
+ {
+ if (0 == strcmp(argv[i],"-event"))
+ {
+ bNamedEvent = 1;
+ }
+ else if (0 == strcmp(argv[i],"-mutex"))
+ {
+ bMutex = 1;
+ }
+ else if (0 == strcmp(argv[i],"-mutex_and_named_event"))
+ {
+ bMutexAndNamedEvent = 1;
+ }
+ else if (0 == strcmp(argv[i],"-semaphore"))
+ {
+ bSemaphore = 1;
+ }
+ else if (0 == strcmp(argv[i],"-exitcode") && i < argc-1 )
+ {
+ i++;
+ iExitCode = atoi(argv[i]);
+ Trace("[child] My exit code is %d\n", iExitCode);
+ }
+
+ else if ('-' != *argv[i])
+ {
+ strncpy(szTestName, argv[i], 256);
+ szTestName[255] = 0;
+ iRet = MultiByteToWideChar(CP_ACP, 0, szTestName, strlen(szTestName)+1, wszTestName, 256);
+ if (0 == iRet)
+ {
+ Fail("Failed to convert test string\n");
+ }
+ }
+ }
+
+ _snprintf(szEventName, 128, "%s_Event", szTestName);
+ szEventName[127] = 0;
+ _snprintf(szMutexName, 128, "%s_Mutex", szTestName);
+ szMutexName[127] = 0;
+ _snprintf(szSemName, 128, "%s_Semaphore", szTestName);
+ szSemName[127] = 0;
+
+ iRet = MultiByteToWideChar(CP_ACP, 0, szEventName, strlen(szEventName)+1, wszEventName, 128);
+ iRet &= MultiByteToWideChar(CP_ACP, 0, szMutexName, strlen(szMutexName)+1, wszMutexName, 128);
+ iRet &= MultiByteToWideChar(CP_ACP, 0, szSemName, strlen(szSemName)+1, wszSemName, 128);
+ if (0 == iRet)
+ {
+ Fail("[child] Failed to convert strings\n");
+ }
+
+ Trace("[child] TestName=%s Event: %S, Mutex: %S, Semaphore = %S\n",
+ szTestName, wszEventName, wszMutexName, wszSemName);
+
+ hNamedEvent = OpenEventW(0, FALSE, wszEventName);
+ if (NULL == hNamedEvent)
+ {
+ Fail("[child] OpenEventW failed [szEventName=%s GetLastError()=%u]\n",
+ szEventName, GetLastError());
+ }
+ hMutex = OpenMutexW(0, FALSE, wszMutexName);
+ if (NULL == hMutex)
+ {
+ Fail("[child] OpenMutexW failed [GetLastError()=%u]\n",
+ GetLastError());
+ }
+ hSemaphore = CreateSemaphoreW(NULL, 0, 256, wszSemName);
+ if (NULL == hSemaphore)
+ {
+ Fail("[child] CreateSemaphore failed [GetLastError()=%u]\n",
+ GetLastError());
+ }
+
+
+ if (bMutex)
+ {
+ Trace("[child] Going to wait on mutex %s\n", szMutexName);
+ dwRet = WaitForSingleObject(hMutex, INFINITE);
+ if (WAIT_FAILED == dwRet)
+ {
+ Fail("[child] WaitForMultipleObjects failed [GetLastError()=%u]\n",
+ GetLastError());
+ }
+
+ Trace("[child] Setting event %s\n", szEventName);
+ bRet = SetEvent(hNamedEvent);
+ if (FALSE == bRet)
+ {
+ Fail("[child] SetEvent failed [GetLastError()=%u]\n",
+ GetLastError());
+ }
+
+ // mutex will be abandoned
+ }
+ else if (bMutexAndNamedEvent)
+ {
+ dwRet = WaitForSingleObject(hMutex, INFINITE);
+ if (WAIT_FAILED == dwRet)
+ {
+ Fail("[child] WaitForMultipleObjects failed [GetLastError()=%u]\n",
+ GetLastError());
+ }
+
+ Sleep(2000);
+
+ bRet = ReleaseMutex(hMutex);
+ if (FALSE == bRet)
+ {
+ Fail("[child] ReleaseMutex failed [GetLastError()=%u]\n",
+ GetLastError());
+ }
+
+ Sleep(1000);
+
+ bRet = SetEvent(hNamedEvent);
+ if (FALSE == bRet)
+ {
+ Fail("[child] SetEvent failed [GetLastError()=%u]\n",
+ GetLastError());
+ }
+ }
+ else if (bSemaphore)
+ {
+ LONG lPrevCount = 42;
+
+
+ Trace("[child] Going to wait on event %s\n", szEventName);
+ dwRet = WaitForSingleObject(hNamedEvent, INFINITE);
+ if (WAIT_FAILED == dwRet)
+ {
+ Fail("[child] WaitForMultipleObjects failed [GetLastError()=%u]\n",
+ GetLastError());
+ }
+
+ Trace("[child] Releasing semaphore %s\n", szSemName);
+ bRet = ReleaseSemaphore(hSemaphore, 10, &lPrevCount);
+ if (FALSE == bRet)
+ {
+ Fail("ReleaseMutex failed [GetLastError()=%u]\n",
+ GetLastError());
+ }
+ if (0 != lPrevCount)
+ {
+ Fail("Previous count from semaphore=%d, expected 0\n", lPrevCount);
+ }
+ }
+ else if (bNamedEvent)
+ {
+ Sleep(1000);
+
+ bRet = SetEvent(hNamedEvent);
+ if (FALSE == bRet)
+ {
+ Fail("[child] SetEvent failed [GetLastError()=%u]\n",
+ GetLastError());
+ }
+ }
+
+ Sleep(1000);
+
+ Trace("[child] Done\n");
+
+ PAL_TerminateEx(iExitCode);
+ return iExitCode;
+}
diff --git a/src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test6/test6.c b/src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test6/test6.c
new file mode 100644
index 0000000000..399d2c3bff
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test6/test6.c
@@ -0,0 +1,709 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: test6.c
+**
+** Purpose: Test for WaitForMultipleObjectsEx in multiple
+** scenarios
+**
+**
+**=========================================================*/
+
+#include <palsuite.h>
+
+#define MAX_COUNT 10000
+#define MAX_THREADS 256
+
+BOOL g_bMutex = 0;
+BOOL g_bEvent = 0;
+BOOL g_bNamedEvent = 0;
+BOOL g_bSemaphore = 0;
+BOOL g_bProcess = 0;
+BOOL g_bLocalWaitAll = 0;
+BOOL g_bRemoteWaitAll = 0;
+BOOL g_bRandom = 0;
+
+int iCount = 1;
+int iThreads = 1;
+HANDLE hThreads[MAX_THREADS];
+
+#ifndef MIN
+#define MIN(a,b) (((a)<(b)) ? (a) : (b))
+#endif
+
+DWORD PALAPI EventTestThread(PVOID pArg)
+{
+ BOOL bRet;
+ DWORD dwRet;
+ HANDLE hEvent[2];
+ HANDLE (*prgHandles)[] = (HANDLE (*)[])pArg;
+
+ Trace("[EventTestThread] Starting\n");
+
+ bRet = DuplicateHandle(GetCurrentProcess(), (*prgHandles)[0], GetCurrentProcess(),
+ &hEvent[0], 0, FALSE, DUPLICATE_SAME_ACCESS);
+ bRet &= DuplicateHandle(GetCurrentProcess(), (*prgHandles)[1], GetCurrentProcess(),
+ &hEvent[1], 0, FALSE, DUPLICATE_SAME_ACCESS);
+ if (FALSE == bRet)
+ {
+ Fail("[EventTestThread] Failed to duplicate handles\n");
+ }
+
+ Sleep(1000);
+ bRet = SetEvent(hEvent[1]);
+ if (FALSE == bRet)
+ {
+ Fail("SetEvent failed\n");
+ Fail("[EventTestThread] SetEvent failed [GetLastError()=%u]\n",
+ GetLastError());
+ }
+
+ dwRet = WaitForSingleObject(hEvent[1], INFINITE);
+ if (WAIT_FAILED == dwRet)
+ {
+ Fail("[EventTestThread] WaitForMultipleObjects failed [GetLastError()=%u]\n",
+ GetLastError());
+ }
+
+ Sleep(1000);
+ bRet = SetEvent(hEvent[0]);
+ if (FALSE == bRet)
+ {
+ Fail("[EventTestThread] SetEvent failed [GetLastError()=%u]\n",
+ GetLastError());
+ }
+
+ Sleep(1000);
+ bRet = SetEvent(hEvent[1]);
+ if (FALSE == bRet)
+ {
+ Fail("[EventTestThread] SetEvent failed [GetLastError()=%u]\n",
+ GetLastError());
+ }
+
+ CloseHandle(hEvent[0]);
+ CloseHandle(hEvent[1]);
+
+ Trace("[EventTestThread] Done\n");
+ return 0;
+}
+
+DWORD PALAPI MutexTestThread(PVOID pArg)
+{
+ BOOL bRet;
+ DWORD dwRet;
+ HANDLE hMutex;
+
+ Trace("[MutexTestThread] Starting\n");
+
+ bRet = DuplicateHandle(GetCurrentProcess(), (HANDLE)pArg, GetCurrentProcess(), &hMutex,
+ 0, FALSE, DUPLICATE_SAME_ACCESS);
+ if (FALSE == bRet)
+ {
+ Fail("[EventTestThread] DuplicateHandle failed [GetLastError()=%u]\n",
+ GetLastError());
+ }
+
+ dwRet = WaitForSingleObject(hMutex, INFINITE);
+ if (WAIT_FAILED == dwRet)
+ {
+ Fail("[EventTestThread] WaitForMultipleObjects failed [GetLastError()=%u]\n",
+ GetLastError());
+ }
+
+ Sleep(1000);
+ CloseHandle(hMutex);
+
+ Trace("[MutexTestThread] Done\n");
+
+ return 0;
+}
+
+DWORD PALAPI TestThread(PVOID pArg)
+{
+ BOOL bRet;
+ DWORD dwRet;
+ PROCESS_INFORMATION pi;
+ STARTUPINFO si;
+ HANDLE hNamedEvent;
+ HANDLE hEvent[2] = { 0, 0 };
+ HANDLE hMutex = 0;
+ HANDLE hSemaphore = 0;
+ HANDLE hObjs[2];
+ DWORD dwThreadNum;
+ DWORD dwSlaveThreadTid = 0;
+ HANDLE hThread;
+ int i, iCnt, iRet;
+ char szTestName[128];
+ char szCmd[128];
+ char szEventName[128] = { 0 };
+ char szMutexName[128] = { 0 };
+ char szSemName[128] = { 0 };
+ WCHAR wszEventName[128] = { 0 };
+ WCHAR wszMutexName[128] = { 0 };
+ WCHAR wszSemName[128] = { 0 };
+ BOOL bMutex = g_bMutex;
+ BOOL bEvent = g_bEvent;
+ BOOL bNamedEvent = g_bNamedEvent;
+ BOOL bSemaphore = g_bSemaphore;
+ BOOL bProcess = g_bProcess;
+ BOOL bLocalWaitAll = g_bLocalWaitAll;
+ BOOL bRemoteWaitAll = g_bRemoteWaitAll;
+ int iDesiredExitCode;
+
+ dwThreadNum = (DWORD)pArg;
+
+ _snprintf (szTestName, 128, "Test6_%u", dwThreadNum);
+ szTestName[127] = 0;
+
+ _snprintf(szEventName, 128, "%s_Event", szTestName);
+ szEventName[127] = 0;
+ _snprintf(szMutexName, 128, "%s_Mutex", szTestName);
+ szMutexName[127] = 0;
+ _snprintf(szSemName, 128, "%s_Semaphore", szTestName);
+ szSemName[127] = 0;
+
+ iRet = MultiByteToWideChar(CP_ACP, 0, szEventName, strlen(szEventName)+1, wszEventName, 128);
+ iRet &= MultiByteToWideChar(CP_ACP, 0, szMutexName, strlen(szMutexName)+1, wszMutexName, 128);
+ iRet &= MultiByteToWideChar(CP_ACP, 0, szSemName, strlen(szSemName)+1, wszSemName, 128);
+
+ if (0 == iRet)
+ {
+ Fail("[TestThread] Failed to convert strings\n");
+ }
+
+ Trace("[TestThread] TestName=%s Event: %S, Mutex: %S, Semaphore = %S\n",
+ szTestName, wszEventName, wszMutexName, wszSemName);
+
+ hEvent[0] = CreateEventA(NULL, FALSE, FALSE, NULL);
+ hEvent[1] = CreateEventA(NULL, FALSE, FALSE, NULL);
+
+ hNamedEvent = CreateEventW(NULL, FALSE, FALSE, wszEventName);
+ hMutex = CreateMutexW(NULL, FALSE, wszMutexName);
+ hSemaphore = CreateSemaphoreW(NULL, 0, 256, wszSemName);
+
+ if (NULL == hEvent[0] || NULL == hEvent[1] || NULL == hMutex ||
+ NULL == hNamedEvent || NULL == hSemaphore)
+ {
+ Fail("[TestThread] Failed to create objects "
+ "[hNamedEvent=%p hMutex=%p hSemaphore=%p]\n",
+ (VOID*)hNamedEvent, (VOID*)hMutex, (VOID*)hSemaphore);
+ }
+
+ for (iCnt=0; iCnt<iCount; iCnt++)
+ {
+ if (g_bRandom)
+ {
+ int iRnd;
+
+ bMutex = 0;
+ bEvent = 0;
+ bNamedEvent = 0;
+ bSemaphore = 0;
+ bProcess = 0;
+ bLocalWaitAll = 0;
+ bRemoteWaitAll = 0;
+
+ iRnd = rand() % 7;
+ switch(iRnd)
+ {
+ case 0:
+ bMutex = 1;
+ break;
+ case 1:
+ bEvent = 1;
+ break;
+ case 2:
+ bNamedEvent = 1;
+ break;
+ case 3:
+ bSemaphore = 1;
+ break;
+ case 4:
+ bProcess = 1;
+ break;
+ case 5:
+ bLocalWaitAll = 1;
+ break;
+ case 6:
+ bRemoteWaitAll = 1;
+ break;
+ }
+ }
+
+ if (bEvent)
+ {
+ Trace("======================================================================\n");
+ Trace("Local unnamed event test\n");
+ Trace("----------------------------------------\n");
+ hThread = CreateThread(NULL, 0, EventTestThread, (PVOID)hEvent, 0, &dwSlaveThreadTid);
+ if (NULL == hThread)
+ {
+ Fail("Failed to create thread\n");
+ }
+
+ hObjs[0] = hEvent[0];
+ dwRet = WaitForMultipleObjects(1, hObjs, FALSE, INFINITE);
+ if (WAIT_FAILED == dwRet)
+ {
+ Fail("WaitForMultipleObjects failed\n");
+ }
+
+ hObjs[0] = hThread;
+ dwRet = WaitForMultipleObjects(1, hObjs, FALSE, INFINITE);
+ if (WAIT_FAILED == dwRet)
+ {
+ Fail("WaitForMultipleObjects failed\n");
+ }
+
+ CloseHandle(hThread);
+ Trace("Local unnamed event test done \n");
+ Trace("======================================================================\n");
+ }
+
+ if (bMutex)
+ {
+ Trace("======================================================================\n");
+ Trace("Mutex with remote thread awakening test\n");
+ Trace("----------------------------------------\n");
+
+ hThread = CreateThread(NULL, 0, MutexTestThread, (PVOID)hMutex, 0, &dwSlaveThreadTid);
+ if (NULL == hThread)
+ {
+ Fail("Failed to create thread\n");
+ }
+
+ Sleep(1000);
+
+ hObjs[0] = hMutex;
+
+ for (i=0;i<10;i++)
+ {
+ dwRet = WaitForMultipleObjects(1, hObjs, FALSE, INFINITE);
+ if (WAIT_FAILED == dwRet)
+ {
+ Fail("WaitForMultipleObjects failed [dwRet=%x GetLastError()=%d\n",
+ dwRet, GetLastError());
+ }
+ }
+
+ hObjs[0] = hThread;
+ dwRet = WaitForMultipleObjects(1, hObjs, FALSE, INFINITE);
+ if (WAIT_FAILED == dwRet)
+ {
+ Fail("WaitForMultipleObjects failed [GetLastError()=%u]\n",
+ GetLastError());
+ }
+
+ for (i=0;i<10;i++)
+ {
+ bRet = ReleaseMutex(hMutex);
+ if (FALSE == bRet)
+ {
+ Fail("ReleaseMutex failed [GetLastError()=%u]\n",
+ GetLastError());
+ }
+ }
+
+ CloseHandle(hThread);
+ Trace("Mutex with remote thread awakening test done\n");
+ Trace("======================================================================\n");
+ }
+
+ if (bNamedEvent)
+ {
+ Trace("======================================================================\n");
+ Trace("Named event with remote thread awakening test\n");
+ Trace("----------------------------------------\n");
+
+ ZeroMemory ( &si, sizeof(si) );
+ si.cb = sizeof(si);
+ ZeroMemory ( &pi, sizeof(pi) );
+
+ _snprintf (szCmd, 128, "child6 -event %s", szTestName);
+ szCmd[127] = 0;
+
+ bRet = CreateProcessA(NULL, szCmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
+ if (FALSE == bRet)
+ {
+ Fail("CreateProcess failed [GetLastError()=%u]\n",
+ GetLastError());
+ }
+
+ hObjs[0] = pi.hProcess;
+ hObjs[1] = hNamedEvent;
+
+ dwRet = WaitForMultipleObjects(2, hObjs, FALSE, INFINITE);
+ if (1 != dwRet)
+ {
+ Fail("WaitForMultipleObjects failed [dwRet=%u GetLastError()=%u]\n",
+ dwRet, GetLastError());
+ }
+
+ dwRet = WaitForSingleObject(pi.hProcess, INFINITE);
+ if (WAIT_FAILED == dwRet)
+ {
+ Fail("WaitForMultipleObjects failed [GetLastError()=%u]\n",
+ GetLastError());
+ }
+ Trace("Named event with remote thread awakening test done\n");
+ Trace("======================================================================\n");
+ }
+
+ if (bSemaphore)
+ {
+ Trace("======================================================================\n");
+ Trace("Semaphore with remote thread awakening test\n");
+ Trace("----------------------------------------\n");
+
+ ZeroMemory ( &si, sizeof(si) );
+ si.cb = sizeof(si);
+ ZeroMemory ( &pi, sizeof(pi) );
+
+ _snprintf (szCmd, 128, "child6 -semaphore %s", szTestName);
+ szCmd[127] = 0;
+
+ bRet = CreateProcessA(NULL, szCmd, NULL, NULL, FALSE,
+ 0, NULL, NULL, &si, &pi);
+ if (FALSE == bRet)
+ {
+ Fail("CreateProcessA failed [GetLastError()=%u]\n",
+ GetLastError());
+ }
+
+ Trace("Setting event %s\n", szEventName);
+ bRet = SetEvent(hNamedEvent);
+ if (FALSE == bRet)
+ {
+ Fail("[child] SetEvent failed [GetLastError()=%u]\n",
+ GetLastError());
+ }
+
+ Trace("Going to wait on semaphore %s\n", szSemName);
+
+
+ hObjs[0] = pi.hProcess;
+ hObjs[0] = hEvent[0];
+ hObjs[1] = hSemaphore;
+ for (i=0;i<10;i++)
+ {
+ dwRet = WaitForMultipleObjects(2, hObjs, FALSE, INFINITE);
+ if (1 != dwRet)
+ {
+ Trace("WaitForMultipleObjects failed [tid=%u dwRet=%u GetLastError()=%u]\n",
+ GetCurrentThreadId(), dwRet, GetLastError());
+ DebugBreak();
+ }
+ }
+
+ dwRet = WaitForSingleObject(pi.hProcess, INFINITE);
+ if (WAIT_FAILED == dwRet)
+ {
+ Fail("WaitForMultipleObjects failed [GetLastError()=%u]\n",
+ GetLastError());
+ }
+ Trace("Semaphore with remote thread awakening test done\n");
+ Trace("======================================================================\n");
+ }
+
+ if (bProcess)
+ {
+ DWORD dwExitCode;
+
+ Trace("======================================================================\n");
+ Trace("Process wait test\n");
+ Trace("----------------------------------------\n");
+
+ iDesiredExitCode = rand() % 0xFF;
+
+ ZeroMemory ( &si, sizeof(si) );
+ si.cb = sizeof(si);
+ ZeroMemory ( &pi, sizeof(pi) );
+
+ _snprintf (szCmd, 128, "child6 -mutex %s -exitcode %d", szTestName, iDesiredExitCode);
+ szCmd[127] = 0;
+
+ bRet = CreateProcessA(NULL, szCmd, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
+ if (FALSE == bRet)
+ {
+ Fail("CreateProcess failed [GetLastError()=%u]\n",
+ GetLastError());
+ }
+
+ Trace("Going to wait on event %s\n", szEventName);
+ dwRet = WaitForSingleObject(hNamedEvent, INFINITE);
+ if (WAIT_FAILED == dwRet)
+ {
+ Fail("WaitForMultipleObjects failed [GetLastError()=%u]\n",
+ GetLastError());
+ }
+
+ hObjs[0] = hEvent[0]; // dummy, this is a local event
+ hObjs[1] = hMutex;
+
+ dwRet = WaitForMultipleObjects(2, hObjs, FALSE, INFINITE);
+ if (WAIT_FAILED == dwRet)
+ {
+ Fail("WaitForMultipleObjects failed [GetLastError()=%u]\n",
+ GetLastError());
+ }
+ if (1 == dwRet || (1 + WAIT_ABANDONED_0) == dwRet)
+ {
+ bRet = ReleaseMutex(hMutex);
+ if (FALSE == bRet)
+ {
+ Fail("ReleaseMutex failed [GetLastError()=%u]\n",
+ GetLastError());
+ }
+ }
+
+ dwRet = WaitForSingleObject(pi.hProcess, INFINITE);
+ if (WAIT_FAILED == dwRet)
+ {
+ Fail("WaitForMultipleObjects failed [GetLastError()=%u]\n",
+ GetLastError());
+ }
+
+ if (!GetExitCodeProcess(pi.hProcess, &dwExitCode))
+ {
+ Trace("GetExitCodeProcess call failed LastError:(%u)\n",
+ GetLastError());
+ dwExitCode = FAIL;
+ }
+
+ if (iDesiredExitCode != dwExitCode)
+ {
+ Fail("Wrong return code: %u [%d]\n", dwExitCode, iDesiredExitCode);
+ }
+ CloseHandle(pi.hProcess);
+ CloseHandle(pi.hThread);
+ Trace("Process wait test done\n");
+ Trace("======================================================================\n");
+ }
+
+ if (bLocalWaitAll)
+ {
+ Trace("======================================================================\n");
+ Trace("WaitAll with local thread awakening test\n");
+ Trace("----------------------------------------\n");
+
+ hThread = CreateThread(NULL, 0, EventTestThread, (PVOID)hEvent, 0, &dwSlaveThreadTid);
+ if (NULL == hThread)
+ {
+ Fail("CreateThread failed [GetLastError()=%u]\n",
+ GetLastError());
+ }
+
+ dwRet = WaitForMultipleObjects(2, hEvent, TRUE, INFINITE);
+ if (WAIT_FAILED == dwRet)
+ {
+ Fail("WaitForMultipleObjects failed [GetLastError()=%u]\n",
+ GetLastError());
+ }
+
+ hObjs[0] = hThread;
+ dwRet = WaitForMultipleObjects(1, hObjs, FALSE, INFINITE);
+ if (WAIT_FAILED == dwRet)
+ {
+ Fail("WaitForMultipleObjects failed [GetLastError()=%u]\n",
+ GetLastError());
+ }
+
+ CloseHandle(hThread);
+ Trace("WaitAll with local thread awakening test done\n");
+ Trace("======================================================================\n");
+ }
+
+ if (bRemoteWaitAll)
+ {
+ Trace("======================================================================\n");
+ Trace("WaitAll with remote thread awakening test\n");
+ Trace("----------------------------------------\n");
+
+ ZeroMemory ( &si, sizeof(si) );
+ si.cb = sizeof(si);
+ ZeroMemory ( &pi, sizeof(pi) );
+
+ _snprintf (szCmd, 128, "child6 -mutex_and_named_event %s", szTestName);
+ szCmd[127] = 0;
+
+ bRet = CreateProcessA(NULL, szCmd, NULL, NULL, FALSE,
+ 0, NULL, NULL, &si, &pi);
+ if (FALSE == bRet)
+ {
+ Fail("CreateProcess failed [GetLastError()=%u]\n",
+ GetLastError());
+ }
+
+ Sleep(1000);
+
+ hObjs[0] = hMutex;
+ hObjs[1] = hNamedEvent;
+
+ dwRet = WaitForMultipleObjects(2, hObjs, TRUE, INFINITE);
+ if (WAIT_FAILED == dwRet)
+ {
+ Fail("WaitForMultipleObjects failed [GetLastError()=%u]\n",
+ GetLastError());
+ }
+
+ bRet = ReleaseMutex(hMutex);
+ if (FALSE == bRet)
+ {
+ Fail("ReleaseMutex failed [GetLastError()=%u]\n",
+ GetLastError());
+ }
+
+ dwRet = WaitForSingleObject(pi.hProcess, INFINITE);
+ if (WAIT_FAILED == dwRet)
+ {
+ Fail("WaitForMultipleObjects failed [GetLastError()=%u]\n",
+ GetLastError());
+ }
+
+ CloseHandle(pi.hProcess);
+ CloseHandle(pi.hThread);
+ Trace("WaitAll with remote thread awakening test done\n");
+ Trace("======================================================================\n");
+ }
+ }
+
+ return 0;
+}
+
+int __cdecl main(int argc, char **argv)
+{
+ DWORD dwRet;
+ DWORD dwSlaveThreadTid = 0;
+ int i, iCnt;
+
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return ( FAIL );
+ }
+
+ srand(time(NULL) * GetCurrentProcessId());
+
+ if (argc == 1)
+ {
+ g_bMutex = 1;
+ g_bEvent = 1;
+ g_bNamedEvent = 1;
+ g_bSemaphore = 1;
+ g_bProcess = 1;
+ g_bLocalWaitAll = 1;
+ g_bRemoteWaitAll = 1;
+ }
+ else
+ {
+ for (i=1;i<argc;i++)
+ {
+ if (0 == strcmp(argv[i], "-mutex"))
+ {
+ g_bMutex = 1;
+ }
+ else if (0 == strcmp(argv[i], "-event"))
+ {
+ g_bEvent = 1;
+ }
+ else if (0 == strcmp(argv[i], "-namedevent"))
+ {
+ g_bNamedEvent = 1;
+ }
+ else if (0 == strcmp(argv[i], "-semaphore"))
+ {
+ g_bSemaphore = 1;
+ }
+ else if (0 == strcmp(argv[i], "-process"))
+ {
+ g_bProcess = 1;
+ }
+ else if (0 == strcmp(argv[i], "-localwaitall"))
+ {
+ g_bLocalWaitAll = 1;
+ }
+ else if (0 == strcmp(argv[i], "-remotewaitall"))
+ {
+ g_bRemoteWaitAll = 1;
+ }
+ else if (0 == strcmp(argv[i], "-all"))
+ {
+ g_bMutex = 1;
+ g_bEvent = 1;
+ g_bNamedEvent = 1;
+ g_bSemaphore = 1;
+ g_bProcess = 1;
+ g_bLocalWaitAll = 1;
+ g_bRemoteWaitAll = 1;
+ }
+ else if (0 == strcmp(argv[i], "-random"))
+ {
+ g_bRandom = 1;
+ }
+ else if ((0 == strcmp(argv[i], "-count")) && (argc > i+1))
+ {
+ i++;
+ iCnt = atoi(argv[i]);
+ if (iCnt > 0 && iCnt < MAX_COUNT)
+ {
+ iCount = iCnt;
+ }
+ }
+ else if ((0 == strcmp(argv[i], "-threads")) && (argc > i+1))
+ {
+ i++;
+ iCnt = atoi(argv[i]);
+ if (iCnt > 0 && iCnt <= MAX_THREADS)
+ {
+ iThreads = iCnt;
+ }
+ }
+ else
+ {
+ Trace("Unknown option %s ignored\n", argv[i]);
+ }
+ }
+ }
+
+
+ iCnt = 0;
+ for (i=0;i<iThreads;i++)
+ {
+ hThreads[iCnt] = CreateThread(NULL, 0, TestThread, (VOID*)iCnt, 0, &dwSlaveThreadTid);
+ if (NULL == hThreads[iCnt])
+ {
+ Trace("Failed to create thread\n");
+ }
+ else
+ {
+ iCnt++;
+ }
+ }
+
+ if (0 == iCnt)
+ {
+ Fail("Can't create any thread\n");
+ }
+
+ for (i=0; i<iCnt; i+=64)
+ {
+ dwRet = WaitForMultipleObjects(MIN(64, iCnt-i), &hThreads[i], TRUE, INFINITE);
+ if (WAIT_FAILED == dwRet)
+ {
+ Fail("WaitForMultipleObjects failed [dwRet=%u GetLastError()=%u iCnt=%d i=%d]\n",
+ dwRet, GetLastError(), iCnt, i);
+ }
+ }
+
+
+ for (i=0; i<iCnt; i++)
+ {
+ CloseHandle(hThreads[i]);
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
diff --git a/src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test6/thistest.dat b/src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test6/thistest.dat
new file mode 100644
index 0000000000..8d36162752
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/WaitForMultipleObjectsEx/test6/thistest.dat
@@ -0,0 +1,2 @@
+
+PAL,threading,palsuite\threading\waitformultipleobjectsex\test6,Test6forWaitForMultipleObjectsEx=test6.c child6.c,<SUPPORTEXE>
diff --git a/src/pal/tests/palsuite/threading/WaitForSingleObject/CMakeLists.txt b/src/pal/tests/palsuite/threading/WaitForSingleObject/CMakeLists.txt
new file mode 100644
index 0000000000..94bd51caa6
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/WaitForSingleObject/CMakeLists.txt
@@ -0,0 +1,11 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+add_subdirectory(WFSOExMutexTest)
+add_subdirectory(WFSOExSemaphoreTest)
+add_subdirectory(WFSOExThreadTest)
+add_subdirectory(WFSOMutexTest)
+add_subdirectory(WFSOProcessTest)
+add_subdirectory(WFSOSemaphoreTest)
+add_subdirectory(WFSOThreadTest)
+
diff --git a/src/pal/tests/palsuite/threading/WaitForSingleObject/WFSOExMutexTest/CMakeLists.txt b/src/pal/tests/palsuite/threading/WaitForSingleObject/WFSOExMutexTest/CMakeLists.txt
new file mode 100644
index 0000000000..65fa0abe14
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/WaitForSingleObject/WFSOExMutexTest/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ WFSOExMutexTest.c
+)
+
+add_executable(paltest_waitforsingleobject_wfsoexmutextest
+ ${SOURCES}
+)
+
+add_dependencies(paltest_waitforsingleobject_wfsoexmutextest coreclrpal)
+
+target_link_libraries(paltest_waitforsingleobject_wfsoexmutextest
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/WaitForSingleObject/WFSOExMutexTest/WFSOExMutexTest.c b/src/pal/tests/palsuite/threading/WaitForSingleObject/WFSOExMutexTest/WFSOExMutexTest.c
new file mode 100644
index 0000000000..3737f9cc10
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/WaitForSingleObject/WFSOExMutexTest/WFSOExMutexTest.c
@@ -0,0 +1,214 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: WFSOExMutex.c
+**
+** Purpose: Tests a child thread in the middle of a
+** WaitForSingleObjectEx call will be interrupted by QueueUserAPC
+** if the alert flag was set.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+/*Based on SleepEx/test2 */
+
+const int ChildThreadWaitTime = 4000;
+const int InterruptTime = 2000;
+const DWORD AcceptableDelta = 300;
+
+void RunTest(BOOL AlertThread);
+VOID PALAPI APCFunc(ULONG_PTR dwParam);
+DWORD PALAPI WaiterProc(LPVOID lpParameter);
+
+DWORD ThreadWaitDelta;
+HANDLE hMutex;
+
+
+
+int __cdecl main( int argc, char **argv )
+{
+ int ret=0;
+
+ if (0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /*
+ On some platforms (e.g. FreeBSD 4.9) the first call to some synch objects
+ (such as conditions) involves some pthread internal initialization that
+ can make the first wait slighty longer, potentially going above the
+ acceptable delta for this test. Let's add a dummy wait to preinitialize
+ internal structures
+ */
+ Sleep(100);
+
+ /*
+ The state of a mutex object is signaled when it is not owned by any thread.
+ The creating thread can use the bInitialOwner flag to request immediate ownership
+ of the mutex. Otherwise, a thread must use one of the wait functions to request
+ ownership. When the mutex's state is signaled, one waiting thread is granted
+ ownership, the mutex's state changes to nonsignaled, and the wait function returns.
+ Only one thread can own a mutex at any given time. The owning thread uses the
+ ReleaseMutex function to release its ownership.
+ */
+
+ /* Create a mutex that is not in the signalled state */
+ hMutex = CreateMutex(NULL, //No security attributes
+ TRUE, //Iniitally owned
+ NULL); //Name of mutex
+
+ if (hMutex == NULL)
+ {
+ Fail("Failed to create mutex! GetLastError returned %d.\n",
+ GetLastError());
+ }
+ /*
+ * Check that Queueing an APC in the middle of a wait does interrupt
+ * it, if it's in an alertable state.
+ */
+
+ RunTest(TRUE);
+ if ((ThreadWaitDelta - InterruptTime) > AcceptableDelta)
+ {
+ Fail("Expected thread to wait for %d ms (and get interrupted).\n"
+ "Thread waited for %d ms! (Acceptable delta: %d)\n",
+ InterruptTime, ThreadWaitDelta, AcceptableDelta);
+ }
+
+
+ /*
+ * Check that Queueing an APC in the middle of a wait does NOT interrupt
+ * it, if it is not in an alertable state.
+ */
+ RunTest(FALSE);
+ if ((ThreadWaitDelta - ChildThreadWaitTime) > AcceptableDelta)
+ {
+ Fail("Expected thread to wait for %d ms (and not be interrupted).\n"
+ "Thread waited for %d ms! (Acceptable delta: %d)\n",
+ ChildThreadWaitTime, ThreadWaitDelta, AcceptableDelta);
+ }
+
+
+
+ //Release Mutex
+ ret = ReleaseMutex(hMutex);
+ if (0==ret)
+ {
+ Fail("Unable to Release Mutex!\n"
+ "GetLastError returned %d\n", GetLastError());
+ }
+
+ //Close Mutex Handle
+ ret = CloseHandle(hMutex);
+ if (!ret)
+ {
+ Fail("Unable to close handle to Mutex!\n"
+ "GetLastError returned %d\n", GetLastError());
+ }
+
+ PAL_Terminate();
+ return PASS;
+}
+
+void RunTest(BOOL AlertThread)
+{
+
+ HANDLE hThread = 0;
+ DWORD dwThreadId = 0;
+
+ int ret=0;
+
+ hThread = CreateThread( NULL,
+ 0,
+ (LPTHREAD_START_ROUTINE)WaiterProc,
+ (LPVOID) AlertThread,
+ 0,
+ &dwThreadId);
+
+ if (hThread == NULL)
+ {
+ Fail("ERROR: Was not able to create the thread to test!\n"
+ "GetLastError returned %d\n", GetLastError());
+ }
+
+
+
+ Sleep(InterruptTime);
+
+ ret = QueueUserAPC(APCFunc, hThread, 0);
+
+ if (ret == 0)
+ {
+ Fail("QueueUserAPC failed! GetLastError returned %d\n",
+ GetLastError());
+ }
+
+ ret = WaitForSingleObject(hThread, INFINITE);
+
+ if (ret == WAIT_FAILED)
+ {
+ Fail("Unable to wait on child thread!\nGetLastError returned %d.\n",
+ GetLastError());
+ }
+
+
+ if (0==CloseHandle(hThread))
+ {
+ Trace("Could not close Thread handle\n");
+ Fail ( "GetLastError returned %d\n", GetLastError());
+ }
+}
+
+/* Function doesn't do anything, just needed to interrupt the wait*/
+VOID PALAPI APCFunc(ULONG_PTR dwParam)
+{
+}
+
+/* Entry Point for child thread. */
+DWORD PALAPI WaiterProc(LPVOID lpParameter)
+{
+ UINT64 OldTimeStamp;
+ UINT64 NewTimeStamp;
+ BOOL Alertable;
+ DWORD ret;
+
+ Alertable = (BOOL) lpParameter;
+
+ LARGE_INTEGER performanceFrequency;
+ if (!QueryPerformanceFrequency(&performanceFrequency))
+ {
+ Fail("Failed to query performance frequency!");
+ }
+
+ OldTimeStamp = GetHighPrecisionTimeStamp(performanceFrequency);
+
+ ret = WaitForSingleObjectEx( hMutex,
+ ChildThreadWaitTime,
+ Alertable);
+
+ NewTimeStamp = GetHighPrecisionTimeStamp(performanceFrequency);
+
+ if (Alertable && ret != WAIT_IO_COMPLETION)
+ {
+ Fail("Expected the interrupted wait to return WAIT_IO_COMPLETION.\n"
+ "Got %d\n", ret);
+ }
+ else if (!Alertable && ret != WAIT_TIMEOUT)
+ {
+ Fail("WaitForSingleObjectEx did not timeout.\n"
+ "Expected return of WAIT_TIMEOUT, got %d.\n", ret);
+ }
+
+ ThreadWaitDelta = NewTimeStamp - OldTimeStamp;
+
+ return 0;
+}
+
+
+
diff --git a/src/pal/tests/palsuite/threading/WaitForSingleObject/WFSOExSemaphoreTest/CMakeLists.txt b/src/pal/tests/palsuite/threading/WaitForSingleObject/WFSOExSemaphoreTest/CMakeLists.txt
new file mode 100644
index 0000000000..12517e31e0
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/WaitForSingleObject/WFSOExSemaphoreTest/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ WFSOExSemaphoreTest.c
+)
+
+add_executable(paltest_waitforsingleobject_wfsoexsemaphoretest
+ ${SOURCES}
+)
+
+add_dependencies(paltest_waitforsingleobject_wfsoexsemaphoretest coreclrpal)
+
+target_link_libraries(paltest_waitforsingleobject_wfsoexsemaphoretest
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/WaitForSingleObject/WFSOExSemaphoreTest/WFSOExSemaphoreTest.c b/src/pal/tests/palsuite/threading/WaitForSingleObject/WFSOExSemaphoreTest/WFSOExSemaphoreTest.c
new file mode 100644
index 0000000000..793c50995c
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/WaitForSingleObject/WFSOExSemaphoreTest/WFSOExSemaphoreTest.c
@@ -0,0 +1,184 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: WFSOExSemaphore.c
+**
+** Purpose: Tests a child thread in the middle of a
+** WaitForSingleObjectEx call will be interrupted by QueueUserAPC
+** if the alert flag was set.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+/*Based on SleepEx/test2 */
+
+const int ChildThreadWaitTime = 4000;
+const int InterruptTime = 2000;
+const DWORD AcceptableDelta = 300;
+
+void RunTest(BOOL AlertThread);
+VOID PALAPI APCFunc(ULONG_PTR dwParam);
+DWORD PALAPI WaiterProc(LPVOID lpParameter);
+
+DWORD ThreadWaitDelta;
+
+int __cdecl main( int argc, char **argv )
+{
+ if (0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /*
+ On some platforms (e.g. FreeBSD 4.9) the first call to some synch objects
+ (such as conditions) involves some pthread internal initialization that
+ can make the first wait slighty longer, potentially going above the
+ acceptable delta for this test. Let's add a dummy wait to preinitialize
+ internal structures
+ */
+ Sleep(100);
+
+ /*
+ * Check that Queueing an APC in the middle of a wait does interrupt
+ * it, if it's in an alertable state.
+ */
+
+ RunTest(TRUE);
+ if ((ThreadWaitDelta - InterruptTime) > AcceptableDelta)
+ {
+ Fail("Expected thread to wait for %d ms (and get interrupted).\n"
+ "Thread waited for %d ms! (Acceptable delta: %d)\n",
+ InterruptTime, ThreadWaitDelta, AcceptableDelta);
+ }
+
+
+ /*
+ * Check that Queueing an APC in the middle of a wait does NOT interrupt
+ * it, if it is not in an alertable state.
+ */
+ RunTest(FALSE);
+ if ((ThreadWaitDelta - ChildThreadWaitTime) > AcceptableDelta)
+ {
+ Fail("Expected thread to wait for %d ms (and not be interrupted).\n"
+ "Thread waited for %d ms! (Acceptable delta: %d)\n",
+ ChildThreadWaitTime, ThreadWaitDelta, AcceptableDelta);
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+}
+
+void RunTest(BOOL AlertThread)
+{
+ HANDLE hThread = 0;
+ DWORD dwThreadId = 0;
+ int ret;
+
+ hThread = CreateThread( NULL,
+ 0,
+ (LPTHREAD_START_ROUTINE)WaiterProc,
+ (LPVOID) AlertThread,
+ 0,
+ &dwThreadId);
+
+ if (hThread == NULL)
+ {
+ Fail("ERROR: Was not able to create the thread to test!\n"
+ "GetLastError returned %d\n", GetLastError());
+ }
+
+ Sleep(InterruptTime);
+
+ ret = QueueUserAPC(APCFunc, hThread, 0);
+ if (ret == 0)
+ {
+ Fail("QueueUserAPC failed! GetLastError returned %d\n",
+ GetLastError());
+ }
+
+ ret = WaitForSingleObject(hThread, INFINITE);
+ if (ret == WAIT_FAILED)
+ {
+ Fail("Unable to wait on child thread!\nGetLastError returned %d.\n",
+ GetLastError());
+ }
+
+ if (0==CloseHandle(hThread))
+ {
+ Trace("Could not close Thread handle\n");
+ Fail ( "GetLastError returned %d\n", GetLastError());
+ }
+}
+
+/* Function doesn't do anything, just needed to interrupt the wait*/
+VOID PALAPI APCFunc(ULONG_PTR dwParam)
+{
+}
+
+/* Entry Point for child thread. */
+DWORD PALAPI WaiterProc(LPVOID lpParameter)
+{
+ HANDLE hSemaphore;
+ UINT64 OldTimeStamp;
+ UINT64 NewTimeStamp;
+ BOOL Alertable;
+ DWORD ret;
+
+ LARGE_INTEGER performanceFrequency;
+ if (!QueryPerformanceFrequency(&performanceFrequency))
+ {
+ Fail("Failed to query performance frequency!");
+ }
+
+ /* Create a semaphore that is not in the signalled state */
+ hSemaphore = CreateSemaphoreW(NULL, 0, 1, NULL);
+
+ if (hSemaphore == NULL)
+ {
+ Fail("Failed to create semaphore! GetLastError returned %d.\n",
+ GetLastError());
+ }
+
+ Alertable = (BOOL) lpParameter;
+
+ OldTimeStamp = GetHighPrecisionTimeStamp(performanceFrequency);
+
+ ret = WaitForSingleObjectEx( hSemaphore,
+ ChildThreadWaitTime,
+ Alertable);
+
+ NewTimeStamp = GetHighPrecisionTimeStamp(performanceFrequency);
+
+
+ if (Alertable && ret != WAIT_IO_COMPLETION)
+ {
+ Fail("Expected the interrupted wait to return WAIT_IO_COMPLETION.\n"
+ "Got %d\n", ret);
+ }
+ else if (!Alertable && ret != WAIT_TIMEOUT)
+ {
+ Fail("WaitForSingleObjectEx did not timeout.\n"
+ "Expected return of WAIT_TIMEOUT, got %d.\n", ret);
+ }
+
+
+ ThreadWaitDelta = NewTimeStamp - OldTimeStamp;
+
+ ret = CloseHandle(hSemaphore);
+ if (!ret)
+ {
+ Fail("Unable to close handle to semaphore!\n"
+ "GetLastError returned %d\n", GetLastError());
+ }
+
+ return 0;
+}
+
+
+
diff --git a/src/pal/tests/palsuite/threading/WaitForSingleObject/WFSOExThreadTest/CMakeLists.txt b/src/pal/tests/palsuite/threading/WaitForSingleObject/WFSOExThreadTest/CMakeLists.txt
new file mode 100644
index 0000000000..f3d868f082
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/WaitForSingleObject/WFSOExThreadTest/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ WFSOExThreadTest.c
+)
+
+add_executable(paltest_waitforsingleobject_wfsoexthreadtest
+ ${SOURCES}
+)
+
+add_dependencies(paltest_waitforsingleobject_wfsoexthreadtest coreclrpal)
+
+target_link_libraries(paltest_waitforsingleobject_wfsoexthreadtest
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/WaitForSingleObject/WFSOExThreadTest/WFSOExThreadTest.c b/src/pal/tests/palsuite/threading/WaitForSingleObject/WFSOExThreadTest/WFSOExThreadTest.c
new file mode 100644
index 0000000000..894d2804aa
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/WaitForSingleObject/WFSOExThreadTest/WFSOExThreadTest.c
@@ -0,0 +1,204 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=====================================================================
+**
+** Source: WFSOExThreadTest.c
+**
+** Purpose: Tests a child thread in the middle of a
+** WaitForSingleObjectEx call will be interrupted by QueueUserAPC
+** if the alert flag was set.
+**
+**
+**===================================================================*/
+
+#include <palsuite.h>
+
+/*Based on SleepEx/test2 */
+
+const int ChildThreadWaitTime = 4000;
+const int InterruptTime = 2000;
+const DWORD AcceptableDelta = 300;
+
+void RunTest(BOOL AlertThread);
+VOID PALAPI APCFunc(ULONG_PTR dwParam);
+DWORD PALAPI WaiterProc(LPVOID lpParameter);
+void WorkerThread(void);
+
+int ThreadWaitDelta;
+
+int __cdecl main( int argc, char **argv )
+{
+ if (0 != (PAL_Initialize(argc, argv)))
+ {
+ return FAIL;
+ }
+
+ /*
+ On some platforms (e.g. FreeBSD 4.9) the first call to some synch objects
+ (such as conditions) involves some pthread internal initialization that
+ can make the first wait slighty longer, potentially going above the
+ acceptable delta for this test. Let's add a dummy wait to preinitialize
+ internal structures
+ */
+ Sleep(100);
+
+ /*
+ * Check that Queueing an APC in the middle of a wait does interrupt
+ * it, if it's in an alertable state.
+ */
+
+ RunTest(TRUE);
+ if (abs(ThreadWaitDelta - InterruptTime) > AcceptableDelta)
+ {
+ Fail("Expected thread to wait for %d ms (and get interrupted).\n"
+ "Thread waited for %d ms! (Acceptable delta: %d)\n",
+ InterruptTime, ThreadWaitDelta, AcceptableDelta);
+ }
+
+
+ /*
+ * Check that Queueing an APC in the middle of a wait does NOT interrupt
+ * it, if it is not in an alertable state.
+ */
+ RunTest(FALSE);
+ if (abs(ThreadWaitDelta - ChildThreadWaitTime) > AcceptableDelta)
+ {
+ Fail("Expected thread to wait for %d ms (and not be interrupted).\n"
+ "Thread waited for %d ms! (Acceptable delta: %d)\n",
+ ChildThreadWaitTime, ThreadWaitDelta, AcceptableDelta);
+ }
+
+
+ PAL_Terminate();
+ return PASS;
+}
+
+void RunTest(BOOL AlertThread)
+{
+ HANDLE hThread = 0;
+ DWORD dwThreadId = 0;
+ int ret;
+
+ //Create thread
+ hThread = CreateThread( NULL,
+ 0,
+ (LPTHREAD_START_ROUTINE)WaiterProc,
+ (LPVOID) AlertThread,
+ 0,
+ &dwThreadId);
+
+ if (hThread == NULL)
+ {
+ Fail("ERROR: Was not able to create the thread to test!\n"
+ "GetLastError returned %d\n", GetLastError());
+ }
+
+ Sleep(InterruptTime);
+
+ ret = QueueUserAPC(APCFunc, hThread, 0);
+ if (ret == 0)
+ {
+ Fail("QueueUserAPC failed! GetLastError returned %d\n",
+ GetLastError());
+ }
+
+
+ ret = WaitForSingleObject(hThread, INFINITE);
+ if (ret == WAIT_FAILED)
+ {
+ Fail("Unable to wait on child thread!\nGetLastError returned %d.\n",
+ GetLastError());
+ }
+
+ if (0==CloseHandle(hThread))
+ {
+ Trace("Could not close Thread handle\n");
+ Fail ( "GetLastError returned %d\n", GetLastError());
+ }
+}
+
+/* Function doesn't do anything, just needed to interrupt the wait*/
+VOID PALAPI APCFunc(ULONG_PTR dwParam)
+{
+}
+
+/* Entry Point for child thread. */
+DWORD PALAPI WaiterProc(LPVOID lpParameter)
+{
+ HANDLE hWaitThread;
+ UINT64 OldTimeStamp;
+ UINT64 NewTimeStamp;
+ BOOL Alertable;
+ DWORD ret;
+ DWORD dwThreadId = 0;
+
+/*
+When a thread terminates, the thread object attains a signaled state,
+satisfying any threads that were waiting on the object.
+*/
+
+/* Create a thread that does not return immediately to maintain a non signaled test*/
+ hWaitThread = CreateThread( NULL,
+ 0,
+ (LPTHREAD_START_ROUTINE)WorkerThread,
+ NULL,
+ 0,
+ &dwThreadId);
+
+ if (hWaitThread == NULL)
+ {
+ Fail("ERROR: Was not able to create worker thread to wait on!\n"
+ "GetLastError returned %d\n", GetLastError());
+ }
+
+ Alertable = (BOOL) lpParameter;
+
+ LARGE_INTEGER performanceFrequency;
+ if (!QueryPerformanceFrequency(&performanceFrequency))
+ {
+ Fail("Failed to query performance frequency!");
+ }
+
+ OldTimeStamp = GetHighPrecisionTimeStamp(performanceFrequency);
+
+ ret = WaitForSingleObjectEx( hWaitThread,
+ ChildThreadWaitTime,
+ Alertable);
+
+ NewTimeStamp = GetHighPrecisionTimeStamp(performanceFrequency);
+
+
+ if (Alertable && ret != WAIT_IO_COMPLETION)
+ {
+ Fail("Expected the interrupted wait to return WAIT_IO_COMPLETION.\n"
+ "Got %d\n", ret);
+ }
+ else if (!Alertable && ret != WAIT_TIMEOUT)
+ {
+ Fail("WaitForSingleObjectEx did not timeout.\n"
+ "Expected return of WAIT_TIMEOUT, got %d.\n", ret);
+ }
+
+ ThreadWaitDelta = NewTimeStamp - OldTimeStamp;
+
+ ret = CloseHandle(hWaitThread);
+ if (!ret)
+ {
+ Fail("Unable to close handle to Thread!\n"
+ "GetLastError returned %d\n", GetLastError());
+ }
+
+ return 0;
+}
+
+
+void WorkerThread(void)
+{
+
+ //Make the worker thread sleep to test WFSOEx Functionality
+
+ Sleep(2*ChildThreadWaitTime);
+}
+
diff --git a/src/pal/tests/palsuite/threading/WaitForSingleObject/WFSOMutexTest/CMakeLists.txt b/src/pal/tests/palsuite/threading/WaitForSingleObject/WFSOMutexTest/CMakeLists.txt
new file mode 100644
index 0000000000..374880e90f
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/WaitForSingleObject/WFSOMutexTest/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ WFSOMutexTest.c
+)
+
+add_executable(paltest_waitforsingleobject_wfsomutextest
+ ${SOURCES}
+)
+
+add_dependencies(paltest_waitforsingleobject_wfsomutextest coreclrpal)
+
+target_link_libraries(paltest_waitforsingleobject_wfsomutextest
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/WaitForSingleObject/WFSOMutexTest/WFSOMutexTest.c b/src/pal/tests/palsuite/threading/WaitForSingleObject/WFSOMutexTest/WFSOMutexTest.c
new file mode 100644
index 0000000000..5ecf517c2a
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/WaitForSingleObject/WFSOMutexTest/WFSOMutexTest.c
@@ -0,0 +1,184 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: WFSOMutexTest.c
+**
+** Purpose: Test for WaitForSingleObjectTest.
+** Create Mutex Object
+** Create Two Threads, Each Threads does WFSO for the Mutex Object
+** Increments Counter
+** Releases Mutex
+** Test Passes if the above operations are successful
+**
+**
+**
+**=========================================================*/
+
+
+
+#include <palsuite.h>
+
+
+#define NUMBER_OF_WORKER_THREADS 2
+
+//Declaring Variables
+HANDLE hMutex = NULL;
+unsigned int globalcounter =0;
+int testReturnCode = PASS;
+
+//Declaring Function Prototypes
+DWORD WFSOMutexTest(LPVOID params);
+void incrementCounter(void);
+
+
+
+int __cdecl main(int argc, char **argv)
+{
+
+ //Declare local variables
+ int i =0;
+
+ // 2 dimensional array to hold thread handles for each worker thread
+ HANDLE hThread[NUMBER_OF_WORKER_THREADS];
+ DWORD dwThreadId=0;
+ int returnCode = 0;
+
+ //Initialize PAL
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return ( FAIL );
+ }
+
+ //Create Mutex
+ hMutex = CreateMutex(NULL, // no security attributes
+ FALSE, // initially not owned
+ NULL); // name of mutex
+
+ //Check for Mutex Creation
+
+ if (hMutex == NULL)
+ {
+ Fail("Create Mutex Failed, GetLastError: %d\n", GetLastError());
+ }
+
+
+ //Spawn 2 worker threads
+ for (i=0;i<NUMBER_OF_WORKER_THREADS;i++)
+ {
+ //Create Thread
+
+ hThread[i] = CreateThread(
+ NULL,
+ 0,
+ WFSOMutexTest,
+ NULL,
+ 0,
+ &dwThreadId);
+
+ if ( NULL == hThread[i] )
+ {
+ Fail ( "CreateThread() returned NULL. Failing test.\n"
+ "GetLastError returned %d\n", GetLastError());
+ }
+
+ }
+
+ /* Test running */
+ returnCode = WaitForMultipleObjects( NUMBER_OF_WORKER_THREADS, hThread, TRUE, 5000);
+ if( WAIT_OBJECT_0 != returnCode )
+ {
+ Trace("Wait for Object(s) returned %d, and GetLastError value is %d\n", returnCode, GetLastError());
+ testReturnCode = FAIL;
+ }
+
+//Close thread handles
+for (i=0;i<NUMBER_OF_WORKER_THREADS;i++)
+ {
+
+ if (0==CloseHandle(hThread[i]))
+ {
+ Trace("Could not Close thread handle\n");
+ Fail ( "GetLastError returned %d\n", GetLastError());
+ }
+ }
+
+//Close Mutex Handle
+if (0==CloseHandle(hMutex))
+ {
+ Trace("Could not close mutex handle\n");
+ Fail ( "GetLastError returned %d\n", GetLastError());
+ }
+
+
+PAL_TerminateEx(testReturnCode);
+return ( testReturnCode );
+
+}
+
+
+void incrementCounter(void)
+{
+ if (INT_MAX == globalcounter)
+ {
+ globalcounter = 0;
+ }
+
+ globalcounter++;
+ Trace("Global Counter Value: %d \n", globalcounter);
+}
+
+
+DWORD WFSOMutexTest(LPVOID params)
+{
+
+ DWORD dwWaitResult;
+
+ // Request ownership of mutex.
+
+ dwWaitResult = WaitForSingleObject(
+ hMutex, // handle to mutex
+ 5000L); // five-second time-out interval
+
+ switch (dwWaitResult)
+ {
+ // The thread got mutex ownership.
+ case WAIT_OBJECT_0:
+ {
+
+ incrementCounter();
+
+ //Release ownership of the mutex object.
+ if (! ReleaseMutex(hMutex))
+ {
+ Fail ( "ReleaseMutex() returned NULL. Failing test.\n"
+ "GetLastError returned %d\n", GetLastError());
+ }
+
+ break;
+ }
+
+ // Cannot get mutex ownership due to time-out.
+ case WAIT_TIMEOUT:
+ {
+ Fail ( "Cannot get mutex ownership due to time-out. Failing test.\n"
+ "GetLastError returned %d\n", GetLastError());
+ return FALSE;
+ }
+
+ // Got ownership of the abandoned mutex object.
+ case WAIT_ABANDONED:
+ {
+ Fail ( "Got ownership of the abandoned mutex object. Failing test.\n"
+ "GetLastError returned %d\n", GetLastError());
+ return FALSE;
+ }
+ }
+
+ return 1;
+}
+
+
+
diff --git a/src/pal/tests/palsuite/threading/WaitForSingleObject/WFSOProcessTest/CMakeLists.txt b/src/pal/tests/palsuite/threading/WaitForSingleObject/WFSOProcessTest/CMakeLists.txt
new file mode 100644
index 0000000000..a70b101988
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/WaitForSingleObject/WFSOProcessTest/CMakeLists.txt
@@ -0,0 +1,36 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(TESTSOURCES
+ WFSOProcessTest.c
+)
+
+add_executable(paltest_waitforsingleobject_wfsoprocesstest
+ ${TESTSOURCES}
+)
+
+add_dependencies(paltest_waitforsingleobject_wfsoprocesstest coreclrpal)
+
+target_link_libraries(paltest_waitforsingleobject_wfsoprocesstest
+ pthread
+ m
+ coreclrpal
+)
+
+
+set(HELPERSOURCES
+ ChildProcess.c
+)
+
+add_executable(paltest_waitforsingleobject_wfsoprocesstest_child
+ ${HELPERSOURCES}
+)
+
+add_dependencies(paltest_waitforsingleobject_wfsoprocesstest_child coreclrpal)
+
+target_link_libraries(paltest_waitforsingleobject_wfsoprocesstest_child
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/WaitForSingleObject/WFSOProcessTest/ChildProcess.c b/src/pal/tests/palsuite/threading/WaitForSingleObject/WFSOProcessTest/ChildProcess.c
new file mode 100644
index 0000000000..91c24d87bb
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/WaitForSingleObject/WFSOProcessTest/ChildProcess.c
@@ -0,0 +1,50 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: ChildProcess.c
+**
+** Purpose: Dummy Process which does some work on which the Main Test case waits
+**
+**
+
+**
+**=========================================================*/
+
+
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char **argv)
+{
+
+//Declare local variables
+int i =0;
+
+
+
+//Initialize PAL
+if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return ( FAIL );
+ }
+
+//Do some work
+for (i=0; i<100000; i++);
+
+Trace("Counter Value was incremented to %d \n ",i);
+
+PAL_Terminate();
+return ( PASS );
+
+}
+
+
+
+
+
+
+
+
diff --git a/src/pal/tests/palsuite/threading/WaitForSingleObject/WFSOProcessTest/WFSOProcessTest.c b/src/pal/tests/palsuite/threading/WaitForSingleObject/WFSOProcessTest/WFSOProcessTest.c
new file mode 100644
index 0000000000..2711e26c29
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/WaitForSingleObject/WFSOProcessTest/WFSOProcessTest.c
@@ -0,0 +1,119 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: WFSOProcessTest.c
+**
+** Purpose: Test for WaitForSingleObjectTest.
+** Create One Process and do some work
+** Use WFSO For the Process to finish
+**
+** Test Passes if the above operations are successful
+**
+**
+**
+**=========================================================*/
+
+
+
+#include <palsuite.h>
+
+int __cdecl main(int argc, char **argv)
+{
+
+//Declare local variables
+STARTUPINFO si;
+PROCESS_INFORMATION pi;
+
+DWORD dwWaitResult=0;
+
+//Initialize PAL
+if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return ( FAIL );
+ }
+
+
+ZeroMemory( &si, sizeof(si) );
+si.cb = sizeof(si);
+ZeroMemory( &pi, sizeof(pi) );
+
+// Start the child process.
+if( !CreateProcess( NULL, // No module name (use command line).
+ "childprocess", // Command line.
+ NULL, // Process handle not inheritable.
+ NULL, // Thread handle not inheritable.
+ FALSE, // Set handle inheritance to FALSE.
+ 0, // No creation flags.
+ NULL, // Use parent's environment block.
+ NULL, // Use parent's starting directory.
+ &si, // Pointer to STARTUPINFO structure.
+ &pi ) // Pointer to PROCESS_INFORMATION structure.
+)
+
+{
+Fail ( "Create Process Failed. Failing test.\n"
+ "GetLastError returned %d\n", GetLastError());
+}
+
+// Wait until child process exits.
+ dwWaitResult = WaitForSingleObject( pi.hProcess, INFINITE );
+switch (dwWaitResult)
+ {
+ // The Process wait was successful
+ case WAIT_OBJECT_0:
+ {
+
+ Trace("Wait for Process was successful\n");
+ break;
+ }
+
+ // Time-out.
+ case WAIT_TIMEOUT:
+ {
+ Fail ( "Time -out. Failing test.\n"
+ "GetLastError returned %d\n", GetLastError());
+ return FALSE;
+ }
+
+ // Got ownership of the abandoned process object.
+ case WAIT_ABANDONED:
+ {
+ Fail ( "Got ownership of the abandoned Process object. Failing test.\n"
+ "GetLastError returned %d\n", GetLastError());
+ return FALSE;
+ }
+
+ //Error condition
+ case WAIT_FAILED:
+ {
+ Fail ( "Wait for Process Failed. Failing test.\n"
+ "GetLastError returned %d\n", GetLastError());
+ return FALSE;
+ }
+
+}
+
+
+
+// Close process handle
+if (0==CloseHandle(pi.hProcess))
+ {
+ Trace("Could not close process handle\n");
+ Fail ( "GetLastError returned %d\n", GetLastError());
+ }
+
+
+PAL_Terminate();
+return ( PASS );
+
+}
+
+
+
+
+
+
+
diff --git a/src/pal/tests/palsuite/threading/WaitForSingleObject/WFSOSemaphoreTest/CMakeLists.txt b/src/pal/tests/palsuite/threading/WaitForSingleObject/WFSOSemaphoreTest/CMakeLists.txt
new file mode 100644
index 0000000000..171e0583e5
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/WaitForSingleObject/WFSOSemaphoreTest/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ WFSOSemaphoreTest.c
+)
+
+add_executable(paltest_waitforsingleobject_wfsosemaphoretest
+ ${SOURCES}
+)
+
+add_dependencies(paltest_waitforsingleobject_wfsosemaphoretest coreclrpal)
+
+target_link_libraries(paltest_waitforsingleobject_wfsosemaphoretest
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/WaitForSingleObject/WFSOSemaphoreTest/WFSOSemaphoreTest.c b/src/pal/tests/palsuite/threading/WaitForSingleObject/WFSOSemaphoreTest/WFSOSemaphoreTest.c
new file mode 100644
index 0000000000..9902d448cd
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/WaitForSingleObject/WFSOSemaphoreTest/WFSOSemaphoreTest.c
@@ -0,0 +1,183 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: WFSOMutexTest.c
+**
+** Purpose: Test for WaitForSingleObjectTest.
+** Create Semaphore Object
+** Create Two Threads, Each Threads does WFSO for the Semaphore Object
+** Increments Counter
+** Releases Semaphore
+** Test Passes if the above operations are successful
+**
+**
+**
+**=========================================================*/
+
+
+
+#include <palsuite.h>
+
+
+#define NUMBER_OF_WORKER_THREADS 2
+
+
+//Declaring Variables
+HANDLE hSemaphore = NULL;
+unsigned int globalcounter =0;
+int testReturnCode = PASS;
+
+//Declaring Function Prototypes
+DWORD WFSOSemaphoreTest(LPVOID params);
+void incrementCounter(void);
+
+int __cdecl main(int argc, char **argv)
+{
+
+ //Declare local variables
+ int i =0;
+ int cMax = 2;
+
+ int returnCode = 0;
+
+ // 2 dimensional array to hold thread handles for each worker thread
+ HANDLE hThread[NUMBER_OF_WORKER_THREADS];
+ DWORD dwThreadId=0;
+
+ //Initialize PAL
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return ( FAIL );
+ }
+
+ //Create Semaphore
+ hSemaphore = CreateSemaphore(
+ NULL, // no security attributes
+ cMax, // initial count
+ cMax, // maximum count
+ NULL); // unnamed semaphore
+
+ if (hSemaphore == NULL)
+ {
+ // Check for error.
+ Fail("Create Semaphore Failed, GetLastError: %d\n", GetLastError());
+ }
+
+
+
+ //Spawn 2 worker threads
+ for (i=0;i<NUMBER_OF_WORKER_THREADS;i++)
+ {
+ //Create Thread
+
+ hThread[i] = CreateThread(
+ NULL,
+ 0,
+ WFSOSemaphoreTest,
+ NULL,
+ 0,
+ &dwThreadId);
+
+ if ( NULL == hThread[i] )
+ {
+ Fail ( "CreateThread() returned NULL. Failing test.\n"
+ "GetLastError returned %d\n", GetLastError());
+ }
+
+ }
+
+
+ /* Test running */
+ returnCode = WaitForMultipleObjects( NUMBER_OF_WORKER_THREADS, hThread, TRUE, 5000);
+ if( WAIT_OBJECT_0 != returnCode )
+ {
+ Trace("Wait for Object(s) returned %d, and GetLastError value is %d\n", returnCode, GetLastError());
+ testReturnCode = FAIL;
+ }
+
+//Close thread handles
+for (i=0;i<NUMBER_OF_WORKER_THREADS;i++)
+ {
+
+ if (0==CloseHandle(hThread[i]))
+ {
+ Trace("Could not Close thread handle\n");
+ Fail ( "GetLastError returned %d\n", GetLastError());
+ }
+ }
+
+//Close Semaphore Handle
+if (0==CloseHandle(hSemaphore))
+ {
+ Trace("Could not close semaphore handle\n");
+ Fail ( "GetLastError returned %d\n", GetLastError());
+ }
+
+PAL_TerminateEx(testReturnCode);
+return ( testReturnCode );
+
+}
+
+
+void incrementCounter(void)
+{
+ if (INT_MAX == globalcounter)
+ {
+ globalcounter = 0;
+ }
+
+ globalcounter++;
+ Trace("Global Counter Value: %d \n", globalcounter);
+}
+
+
+DWORD WFSOSemaphoreTest(LPVOID params)
+{
+
+ DWORD dwWaitResult;
+
+ // Request ownership of Semaphore
+
+ dwWaitResult = WaitForSingleObject(
+ hSemaphore, // handle to semaphore
+ 0L); // zero-second time-out interval
+
+
+ switch (dwWaitResult)
+ {
+ // The semaphore object was signaled.
+ case WAIT_OBJECT_0:
+ {
+
+ incrementCounter();
+ // Increment the count of the semaphore.
+
+ if (!ReleaseSemaphore(
+ hSemaphore, // handle to semaphore
+ 1, // increase count by one
+ NULL) ) // not interested in previous count
+ {
+ Fail ( "ReleaseSemaphore() returned NULL. Failing test.\n"
+ "GetLastError returned %d\n", GetLastError());
+ }
+
+ break;
+ }
+
+ // Semaphore was nonsignaled, so a time-out occurred.
+ case WAIT_TIMEOUT:
+ {
+ Fail ( "Semaphore was nonsignaled, so a time-out occurred. Failing test.\n"
+ "GetLastError returned %d\n", GetLastError());
+ return FALSE;
+ }
+ }
+
+ return 1;
+}
+
+
+
diff --git a/src/pal/tests/palsuite/threading/WaitForSingleObject/WFSOThreadTest/CMakeLists.txt b/src/pal/tests/palsuite/threading/WaitForSingleObject/WFSOThreadTest/CMakeLists.txt
new file mode 100644
index 0000000000..18701a9da5
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/WaitForSingleObject/WFSOThreadTest/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ WFSOThreadTest.c
+)
+
+add_executable(paltest_waitforsingleobject_wfsothreadtest
+ ${SOURCES}
+)
+
+add_dependencies(paltest_waitforsingleobject_wfsothreadtest coreclrpal)
+
+target_link_libraries(paltest_waitforsingleobject_wfsothreadtest
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/WaitForSingleObject/WFSOThreadTest/WFSOThreadTest.c b/src/pal/tests/palsuite/threading/WaitForSingleObject/WFSOThreadTest/WFSOThreadTest.c
new file mode 100644
index 0000000000..378350671a
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/WaitForSingleObject/WFSOThreadTest/WFSOThreadTest.c
@@ -0,0 +1,179 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: WFSOThreadTest.c
+**
+** Purpose: Test for WaitForSingleObjectTest.
+** Create One Thread and do some work
+** Use WFSO For the Thread to finish
+**
+** Test Passes if the above operations are successful
+**
+**
+**
+**=========================================================*/
+
+
+
+#include <palsuite.h>
+
+
+//Declaring Variables
+HANDLE hThread = NULL;
+HANDLE hEvent = NULL;
+
+unsigned int globalcounter =0;
+
+//Declaring Function Prototypes
+DWORD incrementCounter(LPVOID params);
+
+int __cdecl main(int argc, char **argv)
+{
+
+ //Declare local variables
+ DWORD dwThreadId=0;
+ DWORD dwWaitResult=0;
+
+ //Initialize PAL
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return ( FAIL );
+ }
+
+
+ //Create Event
+ hEvent = CreateEvent(NULL,TRUE,FALSE, NULL);
+ if(hEvent == NULL)
+ {
+ Fail("Create Event Failed\n"
+ "GetLastError returned %d\n", GetLastError());
+ }
+
+
+ //Create Thread
+ hThread = CreateThread(
+ NULL,
+ 0,
+ incrementCounter,
+ NULL,
+ 0,
+ &dwThreadId);
+
+ if ( NULL == hThread )
+ {
+ Fail ( "CreateThread() returned NULL. Failing test.\n"
+ "GetLastError returned %d\n", GetLastError());
+ }
+
+
+ //Wait For Thread to signal start
+ dwWaitResult = WaitForSingleObject(hEvent,INFINITE);
+
+ switch (dwWaitResult)
+ {
+ // The thread wait was successful
+ case WAIT_OBJECT_0:
+ {
+
+ Trace ("Wait for Single Object (hEvent) was successful.\n");
+ break;
+ }
+
+ // Time-out.
+ case WAIT_TIMEOUT:
+ {
+ Fail ( "Time -out. Failing test.\n"
+ "GetLastError returned %d\n", GetLastError());
+ return FALSE;
+ }
+
+ // Got ownership of the abandoned event object.
+ case WAIT_ABANDONED:
+ {
+ Fail ( "Got ownership of the abandoned event object. Failing test.\n"
+ "GetLastError returned %d\n", GetLastError());
+ return FALSE;
+ }
+
+ }
+
+
+ //Wait for Thread to finish
+ dwWaitResult = WaitForSingleObject(
+ hThread, //handle to thread
+ 5000L); //Wait Indefinitely
+
+
+ switch (dwWaitResult)
+ {
+ // The thread wait was successful
+ case WAIT_OBJECT_0:
+ {
+
+ Trace("Wait for thread was successful\n");
+
+ break;
+ }
+
+ // Time-out.
+ case WAIT_TIMEOUT:
+ {
+ Fail ( "Time -out. Failing test.\n"
+ "GetLastError returned %d\n", GetLastError());
+ return FALSE;
+ }
+
+ // Got ownership of the abandoned thread object.
+ case WAIT_ABANDONED:
+ {
+ Fail ( "Got ownership of the abandoned thread object. Failing test.\n"
+ "GetLastError returned %d\n", GetLastError());
+ return FALSE;
+ }
+
+ }
+
+
+//Close Handles
+if (0==CloseHandle(hEvent))
+ {
+ Trace("Could not Close event handle\n");
+ Fail ( "GetLastError returned %d\n", GetLastError());
+ }
+if (0==CloseHandle(hThread))
+ {
+ Trace("Could not Close thread handle\n");
+ Fail ( "GetLastError returned %d\n", GetLastError());
+ }
+
+PAL_Terminate();
+return ( PASS );
+
+}
+
+DWORD incrementCounter(LPVOID params)
+{
+
+ //Signal Event so that main thread can start to wait for thread object
+ if (0==SetEvent(hEvent))
+ {
+ Fail ( "SetEvent returned Zero. Failing test.\n"
+ "GetLastError returned %d\n", GetLastError());
+ }
+
+ for (globalcounter=0;globalcounter<100000;globalcounter++);
+
+ //Sleep(5000);
+
+ Trace("Global Counter Value: %d \n", globalcounter);
+ return 0;
+}
+
+
+
+
+
+
diff --git a/src/pal/tests/palsuite/threading/WaitForSingleObject/test1/CMakeLists.txt b/src/pal/tests/palsuite/threading/WaitForSingleObject/test1/CMakeLists.txt
new file mode 100644
index 0000000000..0a71330ba1
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/WaitForSingleObject/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_waitforsingleobject_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_waitforsingleobject_test1 coreclrpal)
+
+target_link_libraries(paltest_waitforsingleobject_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/WaitForSingleObject/test1/test1.c b/src/pal/tests/palsuite/threading/WaitForSingleObject/test1/test1.c
new file mode 100644
index 0000000000..2af80df677
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/WaitForSingleObject/test1/test1.c
@@ -0,0 +1,121 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================
+**
+** Source: test1.c
+**
+** Purpose: Test for WaitForSingleObjectTest. Create two events, one
+** with a TRUE and one with FALSE intial state. Ensure that WaitForSingle
+** returns correct values for each of these.
+**
+**
+**=========================================================*/
+
+#include <palsuite.h>
+
+BOOL WaitForSingleObjectTest()
+{
+
+ BOOL bRet = FALSE;
+ DWORD dwRet = 0;
+
+ LPSECURITY_ATTRIBUTES lpEventAttributes = 0;
+ BOOL bManualReset = TRUE;
+ BOOL bInitialState = TRUE;
+
+ HANDLE hEvent;
+
+ /* Create an event, and ensure the HANDLE is valid */
+ hEvent = CreateEvent(lpEventAttributes, bManualReset,
+ bInitialState, NULL);
+
+ if (hEvent != INVALID_HANDLE_VALUE)
+ {
+
+ /* Call WaitForSingleObject with 0 time on the event. It
+ should return WAIT_OBJECT_0
+ */
+
+ dwRet = WaitForSingleObject(hEvent,0);
+
+ if (dwRet != WAIT_OBJECT_0)
+ {
+ Trace("WaitForSingleObjectTest:WaitForSingleObject failed (%x)\n", GetLastError());
+ }
+ else
+ {
+ bRet = CloseHandle(hEvent);
+
+ if (!bRet)
+ {
+ Trace("WaitForSingleObjectTest:CloseHandle failed (%x)\n", GetLastError());
+ }
+ }
+ }
+ else
+ {
+ Trace("WaitForSingleObjectTest:CreateEvent failed (%x)\n", GetLastError());
+ }
+
+ /* If the first section passed, Create another event, with the
+ intial state being FALSE this time.
+ */
+
+ if (bRet)
+ {
+ bRet = FALSE;
+
+ bInitialState = FALSE;
+
+ hEvent = CreateEvent( lpEventAttributes,
+ bManualReset, bInitialState, NULL);
+
+ if (hEvent != INVALID_HANDLE_VALUE)
+ {
+
+ /* Test WaitForSingleObject and ensure that it returns
+ WAIT_TIMEOUT in this case.
+ */
+
+ dwRet = WaitForSingleObject(hEvent,0);
+
+ if (dwRet != WAIT_TIMEOUT)
+ {
+ Trace("WaitForSingleObjectTest:WaitForSingleObject failed (%x)\n", GetLastError());
+ }
+ else
+ {
+ bRet = CloseHandle(hEvent);
+
+ if (!bRet)
+ {
+ Trace("WaitForSingleObjectTest:CloseHandle failed (%x)\n", GetLastError());
+ }
+ }
+ }
+ else
+ {
+ Trace("WaitForSingleObjectTest::CreateEvent failed (%x)\n", GetLastError());
+ }
+ }
+ return bRet;
+}
+
+int __cdecl main(int argc, char **argv)
+{
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return ( FAIL );
+ }
+
+ if(!WaitForSingleObjectTest())
+ {
+ Fail ("Test failed\n");
+ }
+
+ PAL_Terminate();
+ return ( PASS );
+
+}
diff --git a/src/pal/tests/palsuite/threading/WaitForSingleObject/test1/testinfo.dat b/src/pal/tests/palsuite/threading/WaitForSingleObject/test1/testinfo.dat
new file mode 100644
index 0000000000..89193d1c20
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/WaitForSingleObject/test1/testinfo.dat
@@ -0,0 +1,14 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = WaitForSingleObject
+Name = Positive Test for WaitForSingleObject
+TYPE = DEFAULT
+EXE1 = test1
+Description
+= Test for WaitForSingleObject. Create two events, one
+= with a TRUE and one with FALSE intial state. Ensure that WaitForSingle
+= returns correct values for each of these.
diff --git a/src/pal/tests/palsuite/threading/YieldProcessor/CMakeLists.txt b/src/pal/tests/palsuite/threading/YieldProcessor/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/YieldProcessor/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/threading/YieldProcessor/test1/CMakeLists.txt b/src/pal/tests/palsuite/threading/YieldProcessor/test1/CMakeLists.txt
new file mode 100644
index 0000000000..5002bf763d
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/YieldProcessor/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test1.c
+)
+
+add_executable(paltest_yieldprocessor_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_yieldprocessor_test1 coreclrpal)
+
+target_link_libraries(paltest_yieldprocessor_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/YieldProcessor/test1/test1.c b/src/pal/tests/palsuite/threading/YieldProcessor/test1/test1.c
new file mode 100644
index 0000000000..6adbe989c2
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/YieldProcessor/test1/test1.c
@@ -0,0 +1,92 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*=============================================================================
+**
+** Source: test1.c
+**
+** Purpose: Test to ensure YieldProcessor works, without
+** causing test to hang
+**
+** Dependencies: PAL_Initialize
+** Fail
+** YieldProcessor
+** WaitForMultipleObject
+** CreateThread
+** GetLastError
+**
+
+**
+**===========================================================================*/
+
+
+#include <palsuite.h>
+#define THREAD_COUNT 10
+#define REPEAT_COUNT 1000
+#define TIMEOUT 60000
+void PALAPI Run_Thread(LPVOID lpParam);
+
+/**
+ * main
+ *
+ * executable entry point
+ */
+INT __cdecl main( INT argc, CHAR **argv )
+{
+ DWORD dwParam;
+ HANDLE hThread[THREAD_COUNT];
+ DWORD threadId[THREAD_COUNT];
+
+ int i = 0;
+ int returnCode = 0;
+
+ /*PAL initialization */
+ if( (PAL_Initialize(argc, argv)) != 0 )
+ {
+ return FAIL;
+ }
+
+
+ for( i = 0; i < THREAD_COUNT; i++ )
+ {
+ dwParam = (int) i;
+ //Create thread
+ hThread[i] = CreateThread(
+ NULL, /* no security attributes */
+ 0, /* use default stack size */
+ (LPTHREAD_START_ROUTINE)Run_Thread,/* thread function */
+ (LPVOID)dwParam, /* argument to thread function */
+ 0, /* use default creation flags */
+ &threadId[i] /* returns the thread identifier*/
+ );
+
+ if(hThread[i] == NULL)
+ {
+ Fail("Create Thread failed for iteration %d GetLastError value is %d\n", i, GetLastError());
+ }
+
+ }
+
+
+ returnCode = WaitForMultipleObjects(THREAD_COUNT, hThread, TRUE, TIMEOUT);
+ if( WAIT_OBJECT_0 != returnCode )
+ {
+ Trace("Wait for Object(s) returned %d, expected value is %d, and GetLastError value is %d\n", returnCode, WAIT_OBJECT_0, GetLastError());
+ }
+
+ PAL_Terminate();
+ return PASS;
+
+}
+
+void PALAPI Run_Thread (LPVOID lpParam)
+{
+ int i = 0;
+
+ for(i=0; i < REPEAT_COUNT; i++ )
+ {
+ // No error code set nor does it have any return code
+ YieldProcessor();
+ }
+}
diff --git a/src/pal/tests/palsuite/threading/YieldProcessor/test1/testinfo.dat b/src/pal/tests/palsuite/threading/YieldProcessor/test1/testinfo.dat
new file mode 100644
index 0000000000..6d12110c34
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/YieldProcessor/test1/testinfo.dat
@@ -0,0 +1,13 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = YieldProcessor
+Name = Test for YieldProcessor
+TYPE = DEFAULT
+EXE1 = test
+Description
+= Purpose: Test to ensure YieldProcessor is
+= working properly on supported platforms
diff --git a/src/pal/tests/palsuite/threading/releasesemaphore/CMakeLists.txt b/src/pal/tests/palsuite/threading/releasesemaphore/CMakeLists.txt
new file mode 100644
index 0000000000..f6aa0cb2d9
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/releasesemaphore/CMakeLists.txt
@@ -0,0 +1,4 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+add_subdirectory(test1)
+
diff --git a/src/pal/tests/palsuite/threading/releasesemaphore/test1/CMakeLists.txt b/src/pal/tests/palsuite/threading/releasesemaphore/test1/CMakeLists.txt
new file mode 100644
index 0000000000..e415f91fb2
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/releasesemaphore/test1/CMakeLists.txt
@@ -0,0 +1,19 @@
+cmake_minimum_required(VERSION 2.8.12.2)
+
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+
+set(SOURCES
+ test.c
+)
+
+add_executable(paltest_releasesemaphore_test1
+ ${SOURCES}
+)
+
+add_dependencies(paltest_releasesemaphore_test1 coreclrpal)
+
+target_link_libraries(paltest_releasesemaphore_test1
+ pthread
+ m
+ coreclrpal
+)
diff --git a/src/pal/tests/palsuite/threading/releasesemaphore/test1/test.c b/src/pal/tests/palsuite/threading/releasesemaphore/test1/test.c
new file mode 100644
index 0000000000..4d736b7d9a
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/releasesemaphore/test1/test.c
@@ -0,0 +1,68 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/*============================================================================
+**
+** Source: releasesemaphore/test1/createsemaphore.c
+**
+** Purpose: Check that ReleaseSemaphore fails when using a semaphore handle
+** which has been closed by a call to CloseHandle. Check that
+** ReleaseSemaphore fails when using a ReleaseCount of zero or less than
+** zero.
+**
+**
+**==========================================================================*/
+
+#include <palsuite.h>
+
+HANDLE hSemaphore;
+
+int __cdecl main (int argc, char **argv)
+{
+ if(0 != (PAL_Initialize(argc, argv)))
+ {
+ return (FAIL);
+ }
+ hSemaphore = CreateSemaphoreA (NULL, 1, 2, NULL);
+
+ if (NULL == hSemaphore)
+ {
+ Fail("PALSUITE ERROR: CreateSemaphoreA ('%p' '%ld' '%ld' "
+ "'%p') returned NULL.\nGetLastError returned %d.\n",
+ NULL, 1, 2, NULL, GetLastError());
+ }
+
+ if(ReleaseSemaphore(hSemaphore, 0, NULL))
+ {
+ Fail("PALSUITE ERROR: ReleaseSemaphore('%p' '%ld' '%p') "
+ "call returned %d\nwhen it should have returned "
+ "%d.\nGetLastError returned %d.\n",
+ hSemaphore, 0, NULL, FALSE, TRUE, GetLastError());
+ }
+
+ if(ReleaseSemaphore(hSemaphore, -1, NULL))
+ {
+ Fail("PALSUITE ERROR: ReleaseSemaphore('%p' '%ld' '%p') "
+ "call returned %d\nwhen it should have returned "
+ "%d.\nGetLastError returned %d.\n",
+ hSemaphore, -1, NULL, TRUE, FALSE, GetLastError());
+ }
+
+ if(!CloseHandle(hSemaphore))
+ {
+ Fail("PALSUITE ERROR: CloseHandle(%p) call failed. GetLastError "
+ "returned %d.\n", hSemaphore, GetLastError());
+ }
+
+ if(ReleaseSemaphore(hSemaphore, 1, NULL))
+ {
+ Fail("PALSUITE ERROR: ReleaseSemaphore('%p' '%ld' '%p') "
+ "call incremented semaphore %p count\nafter the handle "
+ "was closed by a call to CloseHandle.\n GetLastError returned "
+ "%d.\n", hSemaphore, -1, NULL, hSemaphore, GetLastError());
+ }
+
+ PAL_Terminate();
+ return (PASS);
+}
diff --git a/src/pal/tests/palsuite/threading/releasesemaphore/test1/testinfo.dat b/src/pal/tests/palsuite/threading/releasesemaphore/test1/testinfo.dat
new file mode 100644
index 0000000000..b4d647a592
--- /dev/null
+++ b/src/pal/tests/palsuite/threading/releasesemaphore/test1/testinfo.dat
@@ -0,0 +1,15 @@
+# Licensed to the .NET Foundation under one or more agreements.
+# The .NET Foundation licenses this file to you under the MIT license.
+# See the LICENSE file in the project root for more information.
+
+Version = 1.0
+Section = threading
+Function = ReleaseSemaphore
+Name = Positive Test for ReleaseSemaphore
+TYPE = DEFAULT
+EXE1 = test
+Description
+= Check that ReleaseSemaphore fails when using a semaphore handle
+= which has been closed by a call to CloseHandle. Check that
+= ReleaseSemaphore fails when using a ReleaseCount of zero or less than
+= zero.
diff --git a/src/pal/tools/clang-compiler-override.txt b/src/pal/tools/clang-compiler-override.txt
new file mode 100644
index 0000000000..ee1e63b63b
--- /dev/null
+++ b/src/pal/tools/clang-compiler-override.txt
@@ -0,0 +1,20 @@
+SET (CMAKE_C_FLAGS_INIT "-Wall -std=c11")
+SET (CMAKE_C_FLAGS_DEBUG_INIT "-g -O0")
+SET (CLR_C_FLAGS_CHECKED_INIT "-g -O2")
+# Refer to the below instruction to support __thread with -O2/-O3 on Linux/ARM
+# https://github.com/dotnet/coreclr/blob/master/Documentation/building/linux-instructions.md
+SET (CMAKE_C_FLAGS_RELEASE_INIT "-g -O3")
+SET (CMAKE_C_FLAGS_RELWITHDEBINFO_INIT "-g -O2")
+
+SET (CMAKE_CXX_FLAGS_INIT "-Wall -Wno-null-conversion -std=c++11")
+SET (CMAKE_CXX_FLAGS_DEBUG_INIT "-g -O0")
+SET (CLR_CXX_FLAGS_CHECKED_INIT "-g -O2")
+SET (CMAKE_CXX_FLAGS_RELEASE_INIT "-g -O3")
+SET (CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT "-g -O2")
+
+SET (CLR_DEFINES_DEBUG_INIT DEBUG _DEBUG _DBG URTBLDENV_FRIENDLY=Checked BUILDENV_CHECKED=1)
+SET (CLR_DEFINES_CHECKED_INIT DEBUG _DEBUG _DBG URTBLDENV_FRIENDLY=Checked BUILDENV_CHECKED=1)
+SET (CLR_DEFINES_RELEASE_INIT NDEBUG URTBLDENV_FRIENDLY=Retail)
+SET (CLR_DEFINES_RELWITHDEBINFO_INIT NDEBUG URTBLDENV_FRIENDLY=Retail)
+
+SET (CMAKE_INSTALL_PREFIX $ENV{__CMakeBinDir})
diff --git a/src/pal/tools/gen-buildsys-clang.sh b/src/pal/tools/gen-buildsys-clang.sh
new file mode 100755
index 0000000000..b7945f3091
--- /dev/null
+++ b/src/pal/tools/gen-buildsys-clang.sh
@@ -0,0 +1,154 @@
+#!/usr/bin/env bash
+#
+# This file invokes cmake and generates the build system for Clang.
+#
+
+if [ $# -lt 4 -o $# -gt 8 ]
+then
+ echo "Usage..."
+ echo "gen-buildsys-clang.sh <path to top level CMakeLists.txt> <ClangMajorVersion> <ClangMinorVersion> <Architecture> [build flavor] [coverage] [ninja] [cmakeargs]"
+ echo "Specify the path to the top level CMake file - <ProjectK>/src/NDP"
+ echo "Specify the clang version to use, split into major and minor version"
+ echo "Specify the target architecture."
+ echo "Optionally specify the build configuration (flavor.) Defaults to DEBUG."
+ echo "Optionally specify 'coverage' to enable code coverage build."
+ echo "Target ninja instead of make. ninja must be on the PATH."
+ echo "Pass additional arguments to CMake call."
+ exit 1
+fi
+
+# Set up the environment to be used for building with clang.
+if which "clang-$2.$3" > /dev/null 2>&1
+ then
+ export CC="$(which clang-$2.$3)"
+ export CXX="$(which clang++-$2.$3)"
+elif which "clang$2$3" > /dev/null 2>&1
+ then
+ export CC="$(which clang$2$3)"
+ export CXX="$(which clang++$2$3)"
+elif which clang > /dev/null 2>&1
+ then
+ export CC="$(which clang)"
+ export CXX="$(which clang++)"
+else
+ echo "Unable to find Clang Compiler"
+ exit 1
+fi
+
+build_arch="$4"
+buildtype=DEBUG
+code_coverage=OFF
+build_tests=OFF
+generator="Unix Makefiles"
+__UnprocessedCMakeArgs=""
+
+for i in "${@:5}"; do
+ upperI="$(echo $i | awk '{print toupper($0)}')"
+ case $upperI in
+ # Possible build types are DEBUG, CHECKED, RELEASE, RELWITHDEBINFO, MINSIZEREL.
+ DEBUG | CHECKED | RELEASE | RELWITHDEBINFO | MINSIZEREL)
+ buildtype=$upperI
+ ;;
+ COVERAGE)
+ echo "Code coverage is turned on for this build."
+ code_coverage=ON
+ ;;
+ INCLUDE_TESTS)
+ echo "Including tests directory in build."
+ build_tests=ON
+ ;;
+ NINJA)
+ generator=Ninja
+ ;;
+ *)
+ __UnprocessedCMakeArgs="${__UnprocessedCMakeArgs}${__UnprocessedCMakeArgs:+ }$i"
+ esac
+done
+
+OS=`uname`
+
+# Locate llvm
+# This can be a little complicated, because the common use-case of Ubuntu with
+# llvm-3.5 installed uses a rather unusual llvm installation with the version
+# number postfixed (i.e. llvm-ar-3.5), so we check for that first.
+# On FreeBSD the version number is appended without point and dash (i.e.
+# llvm-ar35).
+# Additionally, OSX doesn't use the llvm- prefix.
+if [ $OS = "Linux" -o $OS = "FreeBSD" -o $OS = "OpenBSD" -o $OS = "NetBSD" -o $OS = "SunOS" ]; then
+ llvm_prefix="llvm-"
+elif [ $OS = "Darwin" ]; then
+ llvm_prefix=""
+else
+ echo "Unable to determine build platform"
+ exit 1
+fi
+
+desired_llvm_major_version=$2
+desired_llvm_minor_version=$3
+if [ $OS = "FreeBSD" ]; then
+ desired_llvm_version="$desired_llvm_major_version$desired_llvm_minor_version"
+elif [ $OS = "OpenBSD" ]; then
+ desired_llvm_version=""
+elif [ $OS = "NetBSD" ]; then
+ desired_llvm_version=""
+elif [ $OS = "SunOS" ]; then
+ desired_llvm_version=""
+else
+ desired_llvm_version="-$desired_llvm_major_version.$desired_llvm_minor_version"
+fi
+locate_llvm_exec() {
+ if which "$llvm_prefix$1$desired_llvm_version" > /dev/null 2>&1
+ then
+ echo "$(which $llvm_prefix$1$desired_llvm_version)"
+ elif which "$llvm_prefix$1" > /dev/null 2>&1
+ then
+ echo "$(which $llvm_prefix$1)"
+ else
+ exit 1
+ fi
+}
+
+llvm_ar="$(locate_llvm_exec ar)"
+[[ $? -eq 0 ]] || { echo "Unable to locate llvm-ar"; exit 1; }
+llvm_link="$(locate_llvm_exec link)"
+[[ $? -eq 0 ]] || { echo "Unable to locate llvm-link"; exit 1; }
+llvm_nm="$(locate_llvm_exec nm)"
+[[ $? -eq 0 ]] || { echo "Unable to locate llvm-nm"; exit 1; }
+if [ $OS = "Linux" -o $OS = "FreeBSD" -o $OS = "OpenBSD" -o $OS = "NetBSD" -o $OS = "SunOS" ]; then
+ llvm_objdump="$(locate_llvm_exec objdump)"
+ [[ $? -eq 0 ]] || { echo "Unable to locate llvm-objdump"; exit 1; }
+fi
+
+cmake_extra_defines=
+if [[ -n "$LLDB_LIB_DIR" ]]; then
+ cmake_extra_defines="$cmake_extra_defines -DWITH_LLDB_LIBS=$LLDB_LIB_DIR"
+fi
+if [[ -n "$LLDB_INCLUDE_DIR" ]]; then
+ cmake_extra_defines="$cmake_extra_defines -DWITH_LLDB_INCLUDES=$LLDB_INCLUDE_DIR"
+fi
+if [[ -n "$CROSSCOMPILE" ]]; then
+ if ! [[ -n "$ROOTFS_DIR" ]]; then
+ echo "ROOTFS_DIR not set for crosscompile"
+ exit 1
+ fi
+ cmake_extra_defines="$cmake_extra_defines -C $1/cross/$build_arch/tryrun.cmake"
+ cmake_extra_defines="$cmake_extra_defines -DCMAKE_TOOLCHAIN_FILE=$1/cross/$build_arch/toolchain.cmake"
+fi
+if [ "$build_arch" == "arm-softfp" ]; then
+ cmake_extra_defines="$cmake_extra_defines -DARM_SOFTFP=1"
+fi
+
+cmake \
+ -G "$generator" \
+ "-DCMAKE_USER_MAKE_RULES_OVERRIDE=$1/src/pal/tools/clang-compiler-override.txt" \
+ "-DCMAKE_AR=$llvm_ar" \
+ "-DCMAKE_LINKER=$llvm_link" \
+ "-DCMAKE_NM=$llvm_nm" \
+ "-DCMAKE_OBJDUMP=$llvm_objdump" \
+ "-DCMAKE_BUILD_TYPE=$buildtype" \
+ "-DCMAKE_ENABLE_CODE_COVERAGE=$code_coverage" \
+ "-DCMAKE_EXPORT_COMPILE_COMMANDS=1 " \
+ "-DCLR_CMAKE_BUILD_TESTS=$build_tests" \
+ $cmake_extra_defines \
+ $__UnprocessedCMakeArgs \
+ "$1"
diff --git a/src/pal/tools/gen-buildsys-win.bat b/src/pal/tools/gen-buildsys-win.bat
new file mode 100644
index 0000000000..ab57fb4bb4
--- /dev/null
+++ b/src/pal/tools/gen-buildsys-win.bat
@@ -0,0 +1,54 @@
+@if not defined __echo @echo off
+rem
+rem This file invokes cmake and generates the build system for windows.
+
+set argC=0
+for %%x in (%*) do Set /A argC+=1
+
+if %argC% lss 3 GOTO :USAGE
+if %1=="/?" GOTO :USAGE
+
+setlocal
+set basePath=%~dp0
+:: remove quotes
+set "basePath=%basePath:"=%"
+:: remove trailing slash
+if %basePath:~-1%==\ set "basePath=%basePath:~0,-1%"
+
+set __SourceDir=%1
+set __VSVersion=%2
+set __Arch=%3
+set __CmakeGenerator=Visual Studio
+if /i "%__VSVersion%" == "vs2015" (set __CmakeGenerator=%__CmakeGenerator% 14 2015)
+if /i "%__Arch%" == "x64" (set __CmakeGenerator=%__CmakeGenerator% Win64)
+if /i "%__Arch%" == "arm64" (set __CmakeGenerator=%__CmakeGenerator% Win64)
+if /i "%__Arch%" == "arm" (set __CmakeGenerator=%__CmakeGenerator% ARM)
+
+if /i "%__NMakeMakefiles%" == "1" (set __CmakeGenerator=NMake Makefiles)
+
+:loop
+if [%4] == [] goto end_loop
+set __ExtraCmakeParams=%__ExtraCmakeParams% %4
+shift
+goto loop
+:end_loop
+
+if defined CMakePath goto DoGen
+
+:: Eval the output from probe-win1.ps1
+for /f "delims=" %%a in ('powershell -NoProfile -ExecutionPolicy RemoteSigned "& "%basePath%\probe-win.ps1""') do %%a
+
+:DoGen
+"%CMakePath%" "-DCMAKE_USER_MAKE_RULES_OVERRIDE=%basePath%\windows-compiler-override.txt" "-DCMAKE_INSTALL_PREFIX:PATH=$ENV{__CMakeBinDir}" "-DCLR_CMAKE_HOST_ARCH=%__Arch%" %__ExtraCmakeParams% -G "%__CmakeGenerator%" %__SourceDir%
+endlocal
+GOTO :DONE
+
+:USAGE
+ echo "Usage..."
+ echo "gen-buildsys-win.bat <path to top level CMakeLists.txt> <VSVersion>"
+ echo "Specify the path to the top level CMake file - <ProjectK>/src/NDP"
+ echo "Specify the VSVersion to be used - VS2015"
+ EXIT /B 1
+
+:DONE
+ EXIT /B 0
diff --git a/src/pal/tools/gen-dactable-rva.sh b/src/pal/tools/gen-dactable-rva.sh
new file mode 100644
index 0000000000..dd200068e5
--- /dev/null
+++ b/src/pal/tools/gen-dactable-rva.sh
@@ -0,0 +1 @@
+nm $1 | grep g_dacTable | cut -f 1 -d' ' | head -n 1 | awk '{ print "#define DAC_TABLE_RVA 0x" $1}' > $2
diff --git a/src/pal/tools/preptests.sh b/src/pal/tools/preptests.sh
new file mode 100755
index 0000000000..704f869625
--- /dev/null
+++ b/src/pal/tools/preptests.sh
@@ -0,0 +1,69 @@
+# PrepTests.sh
+# Initializes our test running environment by setting environment variables appropriately. Already set variables
+# are not overwritten. This is intended for use on unix.
+#
+# Created 10/28/2014 - mmitche
+
+ExecPrepTestsCore()
+{
+ unset -f ExecPrepTestsCore
+
+ echo
+ echo Preparing this window to run tests
+ echo Setting up Exernal Environment Variables
+ echo _TGTCPU - Target CPU
+ echo BVT_ROOT - Root of tests to run
+ echo CORE_RUN - Test host
+ echo CORE_ROOT - Root of CLR drop.
+ echo
+
+ # Set $_TGTCPU based on the processor arch. In bash on an x64 linux machine, that will show up as x86_x64.
+ # If so, then set to AMD64. Otherwise I386.
+ if ! test $_TGTCPU
+ then
+ export _TGTCPU=`arch`
+ if test $_TGTCPU = "x86_x64"
+ then
+ export _TGTCPU="AMD64"
+ else
+ export _TGTCPU="i386"
+ fi
+ fi
+
+ # Set $BVT_ROOT based on current directory
+ if ! test $BVT_ROOT
+ then
+ export BVT_ROOT=$PWD
+ fi
+
+ # Set $CORE_RUN based on current directory
+ if ! test $CORE_RUN
+ then
+ if test -e $BVT_ROOT/Hosting/CoreClr/Activation/Host/TestHost.exe
+ then
+ export CORE_RUN=$BVT_ROOT/Hosting/CoreClr/Activation/Host/TestHost.exe
+ else
+ echo !!!ERROR: $BVT_ROOT/Hosting/CoreClr/Activation/Host/TestHost.exe does not exist. CORE_RUN not set.
+ return 1
+ fi
+ fi
+
+ # Set $CORE_ROOT base to $PWD unless otherwise set.
+ if ! test "$CORE_ROOT"
+ then
+ echo Warning. CORE_ROOT is not set at the moment. Setting it to $PWD
+ export CORE_ROOT=$PWD
+ fi
+
+ # Report the current state of the environment
+ echo _TGCPU is set to: $_TGTCPU
+ echo BVT_ROOT is set to: $BVT_ROOT
+ echo CORE_ROOT is set to: $CORE_ROOT
+ echo CORE_RUN is set to $CORE_RUN
+ echo
+
+ return 0
+}
+
+# This is explicitly so that we can RETURN and not exit this script.
+ExecPrepTestsCore $*
diff --git a/src/pal/tools/probe-win.ps1 b/src/pal/tools/probe-win.ps1
new file mode 100644
index 0000000000..783cb6dfe0
--- /dev/null
+++ b/src/pal/tools/probe-win.ps1
@@ -0,0 +1,60 @@
+# This file probes for the prerequisites for the build system, and outputs commands for eval'ing
+# from the cmd scripts to set variables (and exit on error)
+
+function GetCMakeVersions
+{
+ $items = @()
+ $items += @(Get-ChildItem hklm:\SOFTWARE\Wow6432Node\Kitware -ErrorAction SilentlyContinue)
+ $items += @(Get-ChildItem hklm:\SOFTWARE\Kitware -ErrorAction SilentlyContinue)
+ return $items | where { $_.PSChildName.StartsWith("CMake ") }
+}
+
+function GetCMakeInfo($regKey)
+{
+ try {
+ $version = [System.Version] $regKey.PSChildName.Split(' ')[1]
+ }
+ catch {
+ return $null
+ }
+ $cmakeDir = (Get-ItemProperty $regKey.PSPath).'(default)'
+ $cmakePath = [System.IO.Path]::Combine($cmakeDir, "bin\cmake.exe")
+ if (![System.IO.File]::Exists($cmakePath)) {
+ return $null
+ }
+ return @{'version' = $version; 'path' = $cmakePath}
+}
+
+function LocateCMake
+{
+ $errorMsg = "CMake is a pre-requisite to build this repository but it was not found on the path. Please install CMake from http://www.cmake.org/download/ and ensure it is on your path."
+ $inPathPath = (get-command cmake.exe -ErrorAction SilentlyContinue).Path
+ if ($inPathPath -ne $null) {
+ return $inPathPath
+ }
+ # Let us hope that CMake keep using their current version scheme
+ $validVersions = @()
+ foreach ($regKey in GetCMakeVersions) {
+ $info = GetCMakeInfo($regKey)
+ if ($info -ne $null) {
+ $validVersions += @($info)
+ }
+ }
+ $newestCMakePath = ($validVersions |
+ Sort-Object -property @{Expression={$_.version}; Ascending=$false} |
+ select -first 1).path
+ if ($newestCMakePath -eq $null) {
+ Throw $errorMsg
+ }
+ return $newestCMakePath
+}
+
+try {
+ $cmakePath = LocateCMake
+ [System.Console]::WriteLine("set CMakePath=" + $cmakePath)
+
+}
+catch {
+ [System.Console]::Error.WriteLine($_.Exception.Message)
+ [System.Console]::WriteLine("exit /b 1")
+}
diff --git a/src/pal/tools/setup-ubuntuvm.sh b/src/pal/tools/setup-ubuntuvm.sh
new file mode 100755
index 0000000000..89d8ea37b2
--- /dev/null
+++ b/src/pal/tools/setup-ubuntuvm.sh
@@ -0,0 +1,27 @@
+#!/usr/bin/env bash
+
+echo Installing basic Ubuntu \(VM\) XPlat environment
+
+function Install-Packages {
+ echo Installing Packages
+ apt-get install clang -y
+ apt-get install cmake -y
+}
+
+function Enable-Integration-Services {
+ echo Checking for integration services
+ res=$(grep -c "hv_vmbus" /etc/initramfs-tools/modules)
+ if [ $res -eq 0 ]
+ then
+ echo Installing integration services
+ echo hv_vmbus >> /etc/initramfs-tools/modules
+ echo hv_storvsc >> /etc/initramfs-tools/modules
+ echo hv_blkvsc >> /etc/initramfs-tools/modules
+ echo hv_netvsc >> /etc/initramfs-tools/modules
+ else
+ echo Integration Services already installed
+ fi
+}
+
+Install-Packages
+Enable-Integration-Services
diff --git a/src/pal/tools/smarty.sh b/src/pal/tools/smarty.sh
new file mode 100755
index 0000000000..d8b407e72c
--- /dev/null
+++ b/src/pal/tools/smarty.sh
@@ -0,0 +1,26 @@
+if ! test "$_TGTCPU"
+then
+ echo !!!ERROR: _TGTCPU not set. Please run preptests.sh
+fi
+if ! test "$CORE_RUN"
+then
+ echo !!!ERROR: CORE_RUN not set. Please run preptests.sh
+fi
+if ! test "$CORE_ROOT"
+then
+ echo !!!ERROR: CORE_ROOT not set. Please run preptests.sh
+fi
+if ! test "$BVT_ROOT"
+then
+ export BVT_ROOT=$PWD
+fi
+
+if [ -n "$PERL5LIB" ] ; then
+ if [ -z "`expr $PERL5LIB : ".*\($BVT_ROOT/Common/Smarty\)"`" ] ; then
+ export PERL5LIB="$PERL5LIB:$BVT_ROOT/Common/Smarty"
+ fi
+else
+ export PERL5LIB=$BVT_ROOT/Common/Smarty
+fi
+
+perl Common/Smarty/Smarty.pl $*
diff --git a/src/pal/tools/windows-compiler-override.txt b/src/pal/tools/windows-compiler-override.txt
new file mode 100644
index 0000000000..f6cb16856c
--- /dev/null
+++ b/src/pal/tools/windows-compiler-override.txt
@@ -0,0 +1,16 @@
+SET (CMAKE_C_FLAGS_INIT "/Wall /FC")
+SET (CMAKE_C_FLAGS_DEBUG_INIT "/Od /Zi")
+SET (CLR_C_FLAGS_CHECKED_INIT "/O1 /Zi")
+SET (CMAKE_C_FLAGS_RELEASE_INIT "/Ox /Zi")
+SET (CMAKE_C_FLAGS_RELWITHDEBINFO_INIT "/O2 /Zi")
+
+SET (CMAKE_CXX_FLAGS_INIT "/Wall /FC")
+SET (CMAKE_CXX_FLAGS_DEBUG_INIT "/Od /Zi")
+SET (CLR_CXX_FLAGS_CHECKED_INIT "/O1 /Zi")
+SET (CMAKE_CXX_FLAGS_RELEASE_INIT "/Ox /Zi")
+SET (CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT "/O2 /Zi")
+
+SET (CLR_DEFINES_DEBUG_INIT DEBUG _DEBUG _DBG URTBLDENV_FRIENDLY=Checked BUILDENV_CHECKED=1)
+SET (CLR_DEFINES_CHECKED_INIT DEBUG _DEBUG _DBG URTBLDENV_FRIENDLY=Checked BUILDENV_CHECKED=1)
+SET (CLR_DEFINES_RELEASE_INIT NDEBUG URTBLDENV_FRIENDLY=Retail)
+SET (CLR_DEFINES_RELWITHDEBINFO_INIT NDEBUG URTBLDENV_FRIENDLY=Retail) \ No newline at end of file